diff --git a/.cirrus.yml b/.cirrus.yml index 99e5a37c9b..303a1c1bd0 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -2,8 +2,9 @@ freebsd_build_task: freebsd_instance: matrix: - image_family: freebsd-12-1 - image_family: freebsd-11-3-snap + image_family: freebsd-12-3 + image_family: freebsd-13-0 + image_family: freebsd-14-0-snap cpu: 1 memory: 1G diff --git a/.dir-locals.el b/.dir-locals.el new file mode 100644 index 0000000000..90697be3bd --- /dev/null +++ b/.dir-locals.el @@ -0,0 +1,2 @@ +((nil . ((indent-tabs-mode . nil))) + (makefile-mode . ((indent-tabs-mode . t)))) diff --git a/.github/workflows/cl-host.yml b/.github/workflows/cl-host.yml index af60c6b84d..95ff3ec94c 100644 --- a/.github/workflows/cl-host.yml +++ b/.github/workflows/cl-host.yml @@ -7,22 +7,23 @@ jobs: ecl: runs-on: ubuntu-latest + timeout-minutes: 45 steps: - uses: actions/checkout@v1 - uses: actions/cache@v1 - id: ecl-cache + id: ecl-cache3 with: path: /tmp/ecl - key: ecl-cache + key: ecl-cache3 - name: build host ecl - if: steps.ecl-cache.outputs.cache-hit != 'true' + if: steps.ecl-cache3.outputs.cache-hit != 'true' run: | wget -q https://github.com/sbcl/sbcl/releases/download/sbcl-1.4.14/ecl.tgz tar xf ecl.tgz cd ecl - ./configure --prefix=/usr/ + ./configure --prefix=/usr/ --enable-threads make working-directory: /tmp @@ -40,36 +41,32 @@ jobs: clisp: runs-on: ubuntu-latest + timeout-minutes: 45 steps: - uses: actions/checkout@v1 - name: instal host clisp run: | sudo apt-get -qq update | true - sudo apt-get -qq install clisp + sudo apt-get -qq install clisp git-restore-mtime - name: build env: SBCL_MAKE_TARGET_2_OPTIONS: --disable-ldb --disable-debugger - run: ./make.sh --xc-host='clisp -on-error exit' - - abcl: - - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v1 - - name: instal host abcl run: | - wget -q https://github.com/sbcl/sbcl/releases/download/sbcl-1.4.14/abcl.jar - echo '(setf system::*invoke-debugger-hook* (lambda (c fun) (princ c) (top-level::backtrace-command 100) (exit :status 1)))' > ~/.abclrc - - name: build - env: - SBCL_MAKE_TARGET_2_OPTIONS: --disable-ldb --disable-debugger - run: ./make.sh --xc-host='java -jar abcl.jar' + git restore-mtime + ./make.sh --xc-host='clisp -on-error exit' + - name: archive clisp-xc fasls + run: tar --transform 's,^,clisp-host/,' -cf clisp-host-fasls.tgz obj/from-xc/ + - name: upload clisp-xc archive + uses: actions/upload-artifact@v3 + with: + name: xc-host-fasls + path: clisp-host-fasls.tgz ccl: runs-on: ubuntu-latest + timeout-minutes: 45 steps: - uses: actions/checkout@v1 @@ -77,14 +74,26 @@ jobs: run: | wget -q https://github.com/sbcl/sbcl/releases/download/sbcl-1.4.14/ccl-host.tgz tar xf ccl-host.tgz + sudo apt-get -qq update | true + sudo apt-get -qq install git-restore-mtime - name: build env: SBCL_MAKE_TARGET_2_OPTIONS: --disable-ldb --disable-debugger - run: ./make.sh --xc-host='ccl-host/lx86cl64 --batch' + run: | + git restore-mtime + ./make.sh --xc-host='ccl-host/lx86cl64 --batch' + - name: archive ccl-xc fasls + run: tar --transform 's,^,ccl-host/,' -cf ccl-host-fasls.tgz obj/from-xc/ + - name: upload ccl-xc archive + uses: actions/upload-artifact@v3 + with: + name: xc-host-fasls + path: ccl-host-fasls.tgz cmucl: runs-on: ubuntu-latest + timeout-minutes: 45 steps: - uses: actions/checkout@v1 @@ -94,8 +103,68 @@ jobs: cd cmucl wget -q https://github.com/sbcl/sbcl/releases/download/sbcl-1.4.14/cmucl.tar.bz2 tar xf cmucl.tar.bz2 + echo '(setf ext:*gc-verbose* nil)' > ~/.cmucl-init.lisp + sudo apt-get -qq update | true + sudo apt-get -qq install git-restore-mtime working-directory: /tmp/ - name: build env: SBCL_MAKE_TARGET_2_OPTIONS: --disable-ldb --disable-debugger - run: ./make.sh --xc-host='/tmp/cmucl/bin/lisp -batch' + run: | + git restore-mtime + ./make.sh --xc-host='/tmp/cmucl/bin/lisp -batch' + - name: archive cmucl-xc fasls + run: tar --transform 's,^,cmucl-host/,' -cf cmucl-host-fasls.tgz obj/from-xc/ + - name: upload cmucl-xc archive + uses: actions/upload-artifact@v3 + with: + name: xc-host-fasls + path: cmucl-host-fasls.tgz + + sbcl: + + runs-on: ubuntu-latest + timeout-minutes: 45 + + steps: + - uses: actions/checkout@v1 + - name: instal host sbcl + run: | + sudo apt-get -qq update | true + sudo apt-get -qq install sbcl libcapstone-dev git-restore-mtime + - name: build + env: + SBCL_MAKE_TARGET_2_OPTIONS: --disable-ldb --disable-debugger + run: | + git restore-mtime + ./make.sh --xc-host='sbcl --dynamic-space-size 600MB --lose-on-corruption --disable-ldb --disable-debugger' + - name: archive sbcl-xc fasls + run: tar --transform 's,^,sbcl-host/,' -cf sbcl-host-fasls.tgz obj/from-xc/ + - name: upload sbcl-xc archive + uses: actions/upload-artifact@v3 + with: + name: xc-host-fasls + path: sbcl-host-fasls.tgz + + compare-xc-host-fasls: + + runs-on: ubuntu-latest + timeout-minutes: 5 + needs: [ccl, sbcl, cmucl, clisp] + + steps: + - name: download xc-host fasls + uses: actions/download-artifact@v3 + with: + name: xc-host-fasls + - name: extract xc-host fasls + run: | + tar xf ccl-host-fasls.tgz + tar xf sbcl-host-fasls.tgz + tar xf clisp-host-fasls.tgz + tar xf cmucl-host-fasls.tgz + - name: compare xc-host fasls + run: | + diff -ur sbcl-host/ ccl-host/ + diff -ur sbcl-host/ clisp-host/ || true + diff -ur sbcl-host/ cmucl-host/ || true diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 55ac0b59c1..ad3f9d3cb8 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -6,10 +6,16 @@ jobs: build: runs-on: ubuntu-latest + timeout-minutes: 60 strategy: matrix: - options: [--with-sb-thread, --without-sb-thread] + options: [--with-sb-thread, --without-sb-thread, --without-sb-unicode] arch: [x86, x86-64] + subfeatures: [''] + include: + - { arch: x86-64, subfeatures: sse4, options: --with-sb-thread } + - { arch: x86-64, subfeatures: fasteval, options: --with-sb-fasteval --without-sb-eval } + fail-fast: false steps: @@ -21,11 +27,47 @@ jobs: - name: instal host gcc-multilib if: matrix.arch == 'x86' run: sudo apt-get -qq --no-install-recommends install gcc-multilib + + - name: backend-sub-features + if: matrix.subfeatures == 'sse4' + run: echo '(lambda (features) (list* :popcnt :sse4 features))' > customize-backend-subfeatures.lisp + - name: build - env: + env: SBCL_MAKE_TARGET_2_OPTIONS: --disable-ldb --disable-debugger - run: ./make.sh ${{ matrix.options }} --xc-host='sbcl --dynamic-space-size 500MB --lose-on-corruption --disable-ldb --disable-debugger' --arch=${{ matrix.arch }} + run: ./make.sh ${{ matrix.options }} --xc-host='sbcl --dynamic-space-size 600MB --lose-on-corruption --disable-ldb --disable-debugger' --arch=${{ matrix.arch }} - name: test run: cd tests; ./run-tests.sh + - name: test + if: matrix.subfeatures == 'fasteval' + run: cd tests; ./run-tests.sh --evaluator-mode interpret - name: ansi-test run: cd tests; ./ansi-tests.sh + + - name: crossbuild arm + if: matrix.subfeatures == 'sse4' + run: crossbuild-runner/build-all.sh arm + - name: crossbuild arm64 + if: matrix.subfeatures == 'sse4' + run: crossbuild-runner/build-all.sh arm64 + - name: crossbuild mips + if: matrix.subfeatures == 'sse4' + run: crossbuild-runner/build-all.sh mips + - name: crossbuild ppc + if: matrix.subfeatures == 'sse4' + run: crossbuild-runner/build-all.sh ppc + - name: crossbuild ppc64 + if: matrix.subfeatures == 'sse4' + run: crossbuild-runner/build-all.sh ppc64 + - name: crossbuild riscv + if: matrix.subfeatures == 'sse4' + run: crossbuild-runner/build-all.sh riscv + - name: crossbuild sparc + if: matrix.subfeatures == 'sse4' + run: crossbuild-runner/build-all.sh sparc + - name: crossbuild x86 + if: matrix.subfeatures == 'sse4' + run: crossbuild-runner/build-all.sh x86 + - name: crossbuild x86-64 + if: matrix.subfeatures == 'sse4' + run: crossbuild-runner/build-all.sh x86-64 diff --git a/.github/workflows/mac.yml b/.github/workflows/mac.yml index 1666e11ab2..3c0cb56a45 100644 --- a/.github/workflows/mac.yml +++ b/.github/workflows/mac.yml @@ -18,7 +18,22 @@ jobs: - name: build env: SBCL_MAKE_TARGET_2_OPTIONS: --disable-ldb --disable-debugger - run: ./make.sh ${{ matrix.options }} --xc-host='sbcl --dynamic-space-size 500MB --lose-on-corruption --disable-ldb --disable-debugger' + run: ./make.sh ${{ matrix.options }} --xc-host='sbcl --dynamic-space-size 600MB --lose-on-corruption --disable-ldb --disable-debugger' + - name: make binary + run: | + name=sbcl-`cat version.lisp-expr | ./run-sbcl.sh --noinform --noprint --eval '(write-line (read))'`-darwin-x86-64 + mkdir sbcl-mac-binary${{ matrix.options }}; + cd .. + mv sbcl $name + ./$name/binary-distribution.sh $name + bzip2 $name-binary.tar + mv $name sbcl + mv $name-binary.tar.bz2 sbcl/sbcl-mac-binary${{ matrix.options }} + - name: save binary + uses: actions/upload-artifact@v1 + with: + name: sbcl-mac-binary${{ matrix.options }} + path: sbcl-mac-binary${{ matrix.options }} - name: test run: cd tests; ./run-tests.sh - name: ansi-test diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index f57d241c88..409fb7d2ba 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -7,21 +7,31 @@ jobs: runs-on: windows-latest + defaults: + run: + shell: msys2 {0} + steps: - uses: actions/checkout@v1 + - uses: msys2/setup-msys2@v2 + with: + install: mingw-w64-x86_64-gcc make diffutils git + - name: install host sbcl + shell: pwsh run: | cinst sbcl -source tools-for-build - echo "::add-path::/c/Program Files/Steel Bank Common Lisp/1.4.14" - name: build env: SBCL_HOME: "/c/Program Files/Steel Bank Common Lisp/1.4.14" run: | - bash ./make.sh --xc-host='sbcl --dynamic-space-size 500MB --lose-on-corruption --disable-ldb --disable-debugger' + PATH=$PATH:"/c/Program Files/Steel Bank Common Lisp/1.4.14" + export PATH + ./make.sh --xc-host='sbcl --lose-on-corruption --disable-ldb --disable-debugger' - name: make installer run: | - bash ./make-windows-installer.sh - bash -c "mkdir sbcl-windows-installer; mv output/*msi sbcl-windows-installer" + ./make-windows-installer.sh + mkdir sbcl-windows-installer; mv output/*msi sbcl-windows-installer - name: save installer uses: actions/upload-artifact@v1 with: @@ -29,10 +39,10 @@ jobs: path: sbcl-windows-installer - name: tests working-directory: tests - run: bash ./run-tests.sh + run: ./run-tests.sh - name: ansi-tests working-directory: tests - run: bash ./ansi-tests.sh + run: ./ansi-tests.sh diff --git a/.gitignore b/.gitignore index 158add5d2b..c5b80e7d93 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ *.d *.dSYM *.o +*.so *.a *.fasl *.FASL @@ -22,31 +23,30 @@ src/compiler/target src/runtime/Config src/runtime/TAGS src/runtime/genesis +src/runtime/linkage-table-prelink-info.c src/runtime/openbsd-sigcontext.h src/runtime/sbcl src/runtime/sbcl.exe src/runtime/sbcl.h src/runtime/sbcl.mk -src/runtime/sbcl.nm src/runtime/shrinkwrap-sbcl* src/runtime/target-arch-os.h src/runtime/target-arch.h src/runtime/target-lispregs.h src/runtime/target-os.h src/runtime/ppc-linux-mcontext.h -src/runtime/sparc-funcdef.h tests/test-status.lisp-expr tests/test.log tests/*.so tests/run-tests-* tests/last-random-state.lisp-expr +tests/ansi-test/ +tools-for-build/avx2* tools-for-build/determine-endianness tools-for-build/determine-endianness.exe tools-for-build/grovel-headers tools-for-build/grovel-headers.exe tools-for-build/mmap-rwx -tools-for-build/os-provides-putwc-test -tools-for-build/os-provides-putwc-test.exe tools-for-build/where-is-mcontext contrib/*/test-passed contrib/*/test-output diff --git a/HACKING b/HACKING index 71e417012f..13d44a403b 100644 --- a/HACKING +++ b/HACKING @@ -21,9 +21,6 @@ Modifying To change the code at run-time the :SB-DEVEL feature is almost always necessary, otherwise a lot of macros, functions, and variables do not survive in the final image. -"./make-target-2.sh --load-with-sb-devel" can resave the core with -sb-devel without recompiling the whole thing, but probably a better -idea is to put it into customize-target-features.lisp. Patch Submissions ================= @@ -58,7 +55,7 @@ Patches requiring more widespread discussion and feedback should be sent to the sbcl-devel mailing list. If you have any questions, feel free to ask them on sbcl-devel, -or the IRC channel #sbcl@freenode.net. +or the IRC channel #sbcl@irc.libera.chat. Coding Style ============ diff --git a/INSTALL b/INSTALL index a7045a7b9d..81225f8022 100644 --- a/INSTALL +++ b/INSTALL @@ -139,11 +139,11 @@ INSTALLING SBCL To run the regression tests: - $ cd tests && sh run-tests.sh + $ cd ./tests && sh run-tests.sh To build documentation: - $ cd doc/manual && make + $ cd ./doc/manual && make This builds the Info, HTML and PDF documentation from the Texinfo sources. The manual includes documentation string from the build @@ -179,7 +179,7 @@ INSTALLING SBCL :SB-CORE-COMPRESSION (--with-sb-core-compression) - Adds zlib as a build-dependency, and makes SBCL able to save + Adds zstd as a build-dependency, and makes SBCL able to save compressed cores. Not enabled by default. :SB-XREF-FOR-INTERNALS (--with-sb-xref-for-internals) diff --git a/NEWS b/NEWS index 3bcb1cb6af..18ed320b36 100644 --- a/NEWS +++ b/NEWS @@ -1,13 +1,743 @@ ;;;; -*- coding: utf-8; fill-column: 78 -*- +changes in sbcl-2.2.8 relative to sbcl-2.2.7: + * minor incompatible change: support for 32-bit x86/Darwin has been removed. + * bug fix: fix miscompilation related to empty infinite loops preceded by + conditional expressions. (lp#1986810, reported by Artyom Bologov) + * bug fix: fix gc invariant violations. (lp#1983218, reported by Marius + Gerbershagen; lp#1983248, reported by Vasily Postnicov) + * bug fix: use CC to compile SBCL as a shared library. (lp#1976148, + reported by Pierre Neidhardt) + * bug fix: don't crash the system completely if RUN-PROGRAM fails to create + a pipe. (lp#1979841, reported by Thor Kristofferson) + * bug fix: be more disciplined about use of C system includes. (lp#1981799, + reported by Mark Evenson) + * bug fix: STRING/= returning wrong results for some cases when :END1/:END2 + were not compile-time constants. (lp#1983284) + * bug fix: compile-time checking of :START and :END keyword arguments to + FILL is more complete. + * optimization: adjacent type tests on the same value are more compact + (arm64, x86-64). + * optimization: the compiler can inline COPY-STRUCTURE in more cases. + * optimization: type checks for non-simple arrays are shorter. + * optimization: printing strings (as Lisp data) is faster. + +changes in sbcl-2.2.7 relative to sbcl-2.2.6: + * minor incompatible change: the compiler emits full WARNINGs for undefined + references to variables in TYPE and DYNAMIC-EXTENT declarations, and for + SETQ of an undefined variable. (This was the historic behaviour for + everything except the DYNAMIC-EXTENT case, which used to emit a + STYLE-WARNING, but these diagnostics got lost in a refactoring since + sbcl-2.2.2) + * minor incompatible change: literal objects (strings, in particular) + in compiled code may at the discretion of the runtime be placed in + read-only memory. Violations of CLHS 3.7.1 could produce memory faults. + If ":PURIFY NIL" is given to SAVE-LISP-AND-DIE then no read-only memory + will be used. + * enhancement: Unicode support has been updated to support version 10.0.0 of + the Unicode standard, including addition of characters and refinements to + breaking and collation algorithms. + * bug fix: AVX is no longer used for loading simd-pack-256 constants. + (lp#1928097) + * bug fix: fix building the manual when some contribs are blocked or + otherwise disabled. (lp#1979821, thanks to Robert Schiele) + * bug fix: fix type derivation of sequence functions with highly-specific + declared argument types. (lp#1980292, reported by James Kalenius) + * bug fix: internal error when optimizing chains of conditionals in local + functions. (lp#1981607, reported by Pasha K) + * bug fix: fix comparison of negative floats with bignums. + * optimization: faster TRUNCATE with float arguments. + * optimization: EQUALP hashing of large floating point values should + generate less garbage. + +changes in sbcl-2.2.6 relative to sbcl-2.2.5: + * minor incompatible change: support for 32-bit x86 on macOS has been + removed. + * new contrib: sb-simd, to provide a convenient interface for SIMD + programming on x86-64. (Thanks to Marco Heisig and other sb-simd + contributors) + * enhancement: core compression now uses zstd instead of zlib. (lp#1881089) + * enhancement: provide compiler warnings for specialized array type + mismatches in CONCATENATE. + * enhancement: provide compiler warnings for bad sequence bounding index + designator arguments to sequence functions. + * enhancement: The sb-mpfr contrib now allows coercion from MPFR-FLOATs + to CL:RATIONAL. (Thanks to Robert Smith) + * bug fix: fix compilation failure related to declaiming types of constants. + (lp#1977726, reported by Pierre Neidhardt) + * bug fix: fix race condition in CLOS optimized constructors. (lp#1951341) + * bug fix: fix too-eager elision of allocation barriers when initializing + closure and structure objects. + * optimization: fasl files are now usually smaller (up to 10% on default + policy) and may load faster, especially on high debug. + * optimization: faster string comparisons on arm64, x86-64. + * optimization: faster [n]string-down/upcase on arm64, x86-64. + * optimization: faster [n]reverse for 8- and 32-bit element vectors on + arm64, x86-64. + * optimization: faster type tests for (CONS (EQL symbol)) on x86-64. + +changes in sbcl-2.2.5 relative to sbcl-2.2.4: + * minor incompatible change: SB-EXT:*DERIVE-FUNCTION-TYPES* being NIL now + means that function calls will strictly only use type information from + proclaimed ftypes. The previous behavior (still the default) of using + derived type information from the same file is specified with :SAME-FILE. + (lp#1393302) + * minor incompatible change: RENAME-FILE now overwrites the target file on + Windows too, making its behaviour consistent with other platforms. + * minor incompatible change: inlining of local function is inhibited if + policy DEBUG = 3. + * platform support: + ** single-stepping is now supported on 64-bit PowerPC platforms. (thanks + to Thomas Fitzsimmons) + ** the :SB-LINKABLE-RUNTIME feature is now supported on 32-bit and 64-bit + PowerPC platforms. (thanks to Thomas Fitzsimmons) + * optimization: improved type derivation of REDUCE with some known reducing + functions. + * enhancement: debug source locations now work correctly for top level forms + with policy DEBUG = 1, as well as for block compiled files. + * enhancement: TRACE now supports tracing macro functions, compiler-macro + functions, individual methods and local functions. See the user manual for + more details. (lp#375314) + * bug fix: fix integer comparisons on x86-64 and arm64 (lp#1971088, reported + by Guillaume LE VAILLANT) + * bug fix: coverage instrumentation behaves correctly with respect to + non-local exits. + * bug fix: ftype proclamations now take effect immediately during block + compilation. + * bug fix: block compilation of top-level closures now work. (lp#1931730, + reported by Sean Maher) + * bug fix: streams opened from RUN-PROGRAM but left unclosed because of a + non-local exit no longer cause unrelated streams to be closed later. + +changes in sbcl-2.2.4 relative to sbcl-2.2.3: + * enhancement: better constraint propagation in the compiler. Specifically, + the compiler can now derive the type of X in control flow join situations + such as + (LAMBDA (X) (ECASE (1 ...) (2 ...)) X) + or + (LAMBDA (X) (ETYPECASE (INTEGER ...) (SYMBOL ...)) X) + instead of forgetting all information about X after the E(TYPE)CASE. + * optimization: inlined functions enclosed in local macro definitions no + longer save their entire lexical environment, reducing unnecessary + memory retention. + * optimization: faster (< integer fixnum) comparisons (ARM64 and x86-64). + * platform support: + ** RUN-PROGRAM is faster on Linux and FreeBSD if close_range(2) is + available. + * bug fix: block compilation now interacts more correctly with the creation + of new packages. + * bug fix: internal compiler error in array reference + optimizer. (lp#1966624) + +changes in sbcl-2.2.3 relative to sbcl-2.2.2: + * minor incompatible change: SB-THREAD:MUTEX-OWNER may return :THREAD-DEAD + if the apparent owner either exited nearly instantly after releasing the + mutex (and is not now the owner), or died and never released it. + * minor incompatible change: building the system with the simple semi-space + copying collector is no longer supported. + * minor incompatible change: support for PPC/Darwin has been removed. + * platform support: + ** fix regressions in threads on RISC-V. (lp#1962598) + ** threads are now enabled by default on RISC-V. + ** The generational garbage collector is now supported on MIPS. + * optimization: fasls containing standard object literals are now smaller + and load more efficiently. + * optimization: faster arithmetic (*-+) on word-sized integers when the + result is not known to fit into a word (ARM64 and x86-64). + * bug fix: EQness of constants is now always preserved when block compiling. + +changes in sbcl-2.2.2 relative to sbcl-2.2.1: + * platform support: + ** all architectures now share the coverage mark instrumentation + implementation, meaning that performance now equals what had been + implemented only on x86 architectures. + ** fixed a performance regression on x86-64 from changes in AVX2 register + handling. (lp#1960081, reported by Michael Kappert) + ** fixed a garbage collection bug on ppc64 manifesting in occasional + corruption on threaded programs. (lp#1959338, lp#1952973) + ** micro-optimizations in type tests for (SIGNED-BYTE 64). + * enhancement: improved handling of source locations for some classes + of compile time and runtime errors. + * enhancement: better source locations for structure accessors. + * bug fix: SB-COVER now always instruments top level forms correctly. + * bug fix: muffling conditions now works correctly on higher debug settings. + * bug fix: local muffling declarations now scope correctly with respect to + undefined variable warnings. + * optimization: calls to STRING= can now return NIL more quickly on strings + of unequal length. + +changes in sbcl-2.2.1 relative to sbcl-2.2.0: + * incompatible change: DEFINE-ALIEN-CALLBACK, which has never been exported + from a public package, has been deleted. It is superseded by + SB-ALIEN:DEFINE-ALIEN-CALLABLE. + * minor incompatible change: compiler warnings are emitted on more + provably-erroneous code involving sequence functions on specialized + arrays. + * platform support: + ** support getting thread IDs on FreeBSD. (thanks to Felix Lange) + ** faster function call sequence on arm64. + ** the built-in buffer size for file streams is increased to 8KB. + * enhancement: provide a restart for method lambda list mismatches that + fmakunbounds the generic function. + * enhancement: provide a USE-VALUE restart around type errors signalled from + (SETF SLOT-VALUE). + * enhancement: when UPDATE-INSTANCE-FOR-DIFFERENT-CLASS (or -REDEFINED-) + undergoes a non-local exit, restore the instance to its original state. + (thanks to Michał phoe Herda) + * enhancement: the :SYNCHRONIZED keyword argument to MAKE-HASH-TABLE is no + longer experimental. + * bug fix: fix an erroneous compiler tranform for (EXPT SINGLE-FLOAT + INTEGER). (lp#1958061, thanks to Vasily Postnicov) + * bug fix: disassembly of closures is more likely to show the relevant code + if more than one closure closes over the same environment. (lp#1956870, + reported by Michał phoe Herda) + * bug fix: RUN-PROGRAM with :IF-EXISTS :APPEND no longer signals an error if + the output does not exist. (lp#1958569, thanks to Ingo Krabbe) + * optimization: reorder basic blocks to have loop code fall through more + often. (thanks to Hayley Patton) + * optimization: sequences larger than the buffer size are written to streams + without going through a buffering stage. (reported by Philipp Marek) + +changes in sbcl-2.2.0 relative to sbcl-2.1.11: + * platform support: + ** support for FreeBSD on 64-bit arm platforms has been added. + ** the :SB-LINKABLE-RUNTIME build-time feature is now supported on 32-bit + and 64-bit arm platforms, and on the FreeBSD operating system. + ** bug fix: correct encoding for vmovsd. (lp#1953483, reported by Marco + Heisig) + ** bug fix: support ABIv1 callbacks on big-endian ppc64. (lp#1900343, + thanks to Thomas Fitzsimmons) + ** bug fix: don't misuse mprotect() in dynamic space on Windows. + (lp#1955723, reported by 3b) + * enhancement: catch type mismatches for REPLACE, SUBSTITUTE, MAKE-ARRAY + with :INITIAL-CONTENTS. + * optimization: printing symbols is around 10% faster than previously. + * bug fix: don't use the current type of non-returning functions when + redefining them in another file. (lp#1953214, reported by Nicolas Hafner) + * bug fix: eliminate stack cleanups more conservatively. (lp#1954330, + reported by Daniel Kochmański) + * bug fix: check consistently in tests for the existence of VOPs. + (lp#1952896, reported by Sébastien Villemot) + +changes in sbcl-2.1.11 relative to sbcl-2.1.10: + * minor incompatible change: *COMPILE-PRINT* now defaults to NIL. T gives + the old behavior of echoing top level forms. Users who want to see a + report of the phases of compilation can use *COMPILE-PROGRESS* and the + corresponding COMPILE-FILE :PROGRESS argument. + * optimization: The compiler assignment-converts functions much more + aggressively; local or non-entry block-compiled functions + which always return to the same place are automatically converted into the + equivalent loop or goto control structures. + * enhancement: on x86-64 and ppc64 platforms, the system uses inline + instructions rather than page protection to implement a store barrier for + the garbage collector. + * enhancement: improved reporting of code deletion notes. + * platform support: + ** unbound-variable restarts for amd64 are now supported. + ** bug fix: single-floats to foreign functions on 32-bit ARMel. + (lp#1950080, reported by Sebastien Villemot) + ** bug fix: opening files with names containing non-ASCII characters on + Windows works better. (reported by Nikolay) + ** bug fix: use fp_xsave to access the floating point flags and control + word in Haiku signal contexts. (Thanks to Al Hoang) + ** bug fix: complex single-float support on riscv64. + ** optimization: support for accessing elements of &rest args directly on + ppc64, mips, riscv. + ** optimization: parse a /proc file rather than executing uname for + SOFTWARE-VERSION on Linux + * bug fix: fix crash from SB-COVER:RESET-COVERAGE. (lp#1950059, reported by + Gregory Czerniak) + +changes in sbcl-2.1.10 relative to sbcl-2.1.9: + * incompatible change: simd-pack without a specific element-type is no + longer treated as containing integers. A type must be supplied for VOPs to + work on such values. + * minor incompatible change: the list form of the FUNCTION type specifier + does not allow * as any argument type, but does allow * as a placeholder + for wholly unspecified arguments when specifying the value(s) type. + * minor incompatible change: the default (Lisp) toplevel option parser + throws an error if it encounters an option which was intended to be used + and removed by the C runtime. (lp#1945081, reported by Luke Gorrie) + * new feature: there is now a defined interface for defining foreign + callable functions, which can be used for passing callbacks to foreign + functions or for calling Lisp code from the foreign world as a shared + library (preliminary support). See the revised manual section "Calling + into Lisp From C" for more details. + * enhancement: arg-count mismatches in self-calls in defmethod are reported. + (lp#1912436, reported by 3b) + * enhancement: the SB-CLTL2 contrib now returns type information for + generated structure accessors. (lp#1934859, reported by SATO shinichi) + * optimization: code generation is improved for modular arithmetic involving + signed operations. + * platform support: + ** x86-64 machine code emitter crash when attempting to assemble some + vector instructions. (lp#1945975, thanks to Marco Heisig) + ** conditional move instructions are now supported on arm64. + ** a number of new peephole optimizations have been implemented on arm64. + ** arm64 on Darwin now uses gcc-compatible thread-local storage. + * bug fix: compiler notes are no longer emitted when compiling FORMATTER + forms, including when implicitly triggered on a constant string argument + to FORMAT. (lp#1946246, reported by SATO shinichi) + * bug fix: a compiler error when attempting to compile a call to AREF with + too many dimensions. (lp#1902985) + * bug fix: harmonize the behaviour of SLOT-BOUNDP on non-standard-objects + between the various ways in which it can be called. (lp#732229, reported + by Zach Beane) + * bug fix: FTRUNCATE and similar functions are now more careful about + deriving facts about the sign of zero they might return. (lp#1732009, + reported by Paul Dietz) + +changes in sbcl-2.1.9 relative to sbcl-2.1.8: + * minor incompatible change: the experimental DEFCAS macro has been removed. + * minor incompatible change: finalizing classes with slots with duplicate + symbol-names will only emit a warning if either slot name is an exported + symbol. (lp#1943559) + * platform support: + ** the debugger is better able to display SIMD packs. (thanks to Marco + Heisig) + ** fix a bug in zeroing YMM registers. (thanks to Marco Heisig) + ** fix instruction definitions for SSE blend and shuffle vector + instructions. (thanks to Marco Heisig) + ** handle heap corruption exceptions in our exception handler on win64. + ** improve WAIT-UNTIL-FD-USABLE on Windows, reducing busy-looping. + (thanks to Fabio Almeida) + * bug fix: EQUALP hash tables whose keys contain arrays containing floats should + behave correctly. (lp#1942424, reported by Nicolas Neuss) + +changes in sbcl-2.1.8 relative to sbcl-2.1.7: + * minor incompatible change: the experimental DEFINE-CAS-EXPANDER macro has + been removed. + * minor incompatible change: the hooks in *INIT-HOOKS* are called before + starting the finalizer or other non-user threads. (thanks to Sean Whitton) + * platform support: + ** many improvements to code generation on arm64. + ** avoid slow forms of the bit test instructions BT, BTS, BTR on x86-64. + ** fix a bug in loading large core files on the Apple M1/arm64. (thanks + to Mayank Manjrekar) + ** fix a bug in loading core loading on the Apple M1/arm64. (reported by + Eric Timmons) + * enhancement: the block-compiler is more robust to files with intermingled + compile-time and load-time effects. The semantics of the block-compiler + remain not-entirely ANSI compatible. (thanks to Sean Maher) + * enhancement: (CAS SAP-REF-) and CAS on alien integers is implemented on + ppc64 and x86-64, working towards fixing lp#1894057 + * bug fix: fix OPEN-STREAM-P on streams closed by saving a core. + (lp#1938433, reported by Guillaume LE VAILLANT) + * bug fix: remove a spurious warning from COERCE. (lp#1920931, reported by + Andrew Berkley) + * bug fix: remove a warning from inlining SET-EXCLUSIVE-OR. (lp#1936470, + reported by Jerome Abela) + +changes in sbcl-2.1.7 relative to sbcl-2.1.6: + * incompatible change: on certain platforms (currently just x86-64), + dynamic-extent arrays specialized on character and numeric types and + created without either :INITIAL-ELEMENT or :INITIAL-CONTENTS will reflect + previous contents of the stack instead of #\null (or 0) in all elements. + * minor incompatible change: SB-SPROF:START-PROFILING no longer silently + does nothing if the clock is already running. It instead stop and restarts + with the newly provided options, and warns. + * minor incompatible change: the system attempts to refer to the supplied + pathname in compiler diagnostics, if relevant, rather than the truename. + * enhancement: new contrib module sb-graph producing graphical + visualizations of Intermediate Representations of SBCL compilation data + structures. + * platform support: + ** improved code generation for unary minus in modular contexts on arm64. + ** make the disassembler annotations slightly more robust on arm64. + ** release space back to the Operating System on Windows. + ** improve the test for whether pages need to be committed on Windows. + * optimization: the type of (LOOP ... COLLECT ...), and the type of COLLECT + INTO variables, is derived as LIST. (lp#1934577, reported by SATO + shinichi) + +changes in sbcl-2.1.6 relative to sbcl-2.1.5: + * minor incompatible change: COMPILE-FILE does not merge the input file's + pathname-directory into the output path if :OUTPUT-FILE was specified + and has a directory that is not :UNSPECIFIC. + * platform support: + ** improvements to unwind code generation on arm64. + ** on x86-64, accept three operands for vshufpd. (reported by Bela + Pecsek) + ** on x86-64, improvements to use of popcount + ** improve exception handling on 64-bit Windows. (thanks to Luis Borges + de Oliveira) + * bug fix: allow use of macros with improper argument list. (lp#1929623, + thanks to Sean Maher) + * bug fix: COERCE no longer attempts to guess what the user meant if they + provide a type specifier of a union of types other than STRING. + (lp#1929614) + * bug fix: print a single trailing zero after the decimal point for FORMAT + ~E if there are no digits remaining to be printed and the width allows it. + (lp#883520) + +changes in sbcl-2.1.5 relative to sbcl-2.1.4: + * minor incompatible change: on x86-64, the backend instruction encoders for + movzx and for string opcodes have changed their semantics. + * platform support: + ** compatibility: support the latest MinGW on x86. (lp#1923325, thanks to + Alexis Rivera) + ** bug fix: on x86-64, fix instruction encoding for TEST on RIP-relative + addresses. (lp#1925808, reported by Shinmera on #sbcl, thanks also to + 3b) + ** bug fix: on x86-64, loading all-1s into an AVX2 register no longer + causes an error. (lp#1928516, thanks to Marco Heisig) + ** bug fix: on arm64, improve disassembly of ADD with constant 0 as MOV + ** enhancement: on arm64, support debugger commands RETURN-FROM-FRAME and + RESTART-FRAME more efficiently. + ** enhancement: on x86-64, add support for vshuf* AVX2 instructions. + (reported by Bela Pecsek) + ** optimization: faster function calls on arm64. + ** optimization: (SETF SBIT) is faster on x86-64. + * bug fix: INTEGER-DECODE-FLOAT was computing the wrong answer for denormal + double floats. (lp#1926383, reported by Stavros Macrakis) + * bug fix: RANDOM on a floating point argument now does not cons. (reported + by Tito Latini) + * bug fix: fix a compiler crash in type derivation of LOGTEST. (lp#1928243) + * bug fix: fix a compiler failure when a declared function type contains a + literal structure with a valid MAKE-LOAD-FORM method. (lp#1929160, thanks + to Yurii Hryhorenko) + * optimization: FBOUNDP on a constant symbol is now faster. + * optimization: file compilation now produces smaller fasls for files which + reference package literals. + * optimization: derive the type of calls to FLOAT-SIGN. + +changes in sbcl-2.1.4 relative to sbcl-2.1.3: + * platform support: + ** work around address-space randomization causing instability on new + versions of MinGW. (lp#1921141) + * bug fix: RANDOM on floats returns values strictly less than the float + argument. + * bug fix: compiler error on x86-64 resulting from attempting to zero a + memory location with xor. (reported by Eric Marsden) + * optimization: extended loops updating iteration variables with THEN can + perform specialized arithmetic for those updates. + * optimization: in some cases, the jump table resulting from a compilation + of TYPECASE is simpler. + * optimization: on x86-64, IF BOUNDP followed by SYMBOL-VALUE can elide some + memory loads and tests. + +changes in sbcl-2.1.3 relative to sbcl-2.1.2: + * minor incompatible change: support for the :SB-SAFEPOINT-STRICTLY, + :SB-THRUPTION, and :SB-WTIMER build features has been removed + * platform support: + ** support for :SB-CORE-COMPRESSION on Darwin/ARM64 + ** support ARM v8.1 atomic and compare-and-swap instructions + ** x86, x86-64: microoptimizations in multiple type-checking routines + * bug fix: structures and conditions are now TYPEP all classes in the class + precedence list of their class. (reported by Luis Oliveira) + * bug fix: derivation of the result type from subtraction sometimes + erroneously excluded zero. (lp#1916895) + * bug fix: reduce the number of places where the system permissively accepts + the symbol * as a type specifier where it should not be accepted. + (lp#1860919) + * bug fix: the code-walker used by the system's implementation of CLOS can + handle defuns declared inline. (reported by Don Cohen) + * optimization: EQUALP on specialized vectors and arrays is faster. + * optimization: support routines for EQUALP hash tables generate less garbage. + +changes in sbcl-2.1.2 relative to sbcl-2.1.1: + * platform support: + ** support for ARM64 macOS; + ** improvement in coverage mark implementation on non-x86oid backends, + approaching the existing x86oid support; + ** more empirically-robust retrieval of the program counter from illegal + instruction traps on SPARC; + ** retain fewer dead objects when saving cores with precise collectors. + * incompatible change: MAP-ALL-SAMPLES and MAP-TRACE-SAMPLES + are no longer present in the SB-SPROF contrib module. + * minor incompatible change: SB-SPROF:WITH-PROFILING defaults to all + threads. SB-SPROF:START-PROFILING no longer accepts a :SAMPLING keyword. + * enhancement: the sb-introspect contrib now supports finding the lambda + lists of method combinations. (thanks to Didier Verna) + * enhancement: short-form DEFSETF now stores a source-location. + * bug fix: canonical unions of CONS types were being incorrectly computed. + (lp#1912863, reported by James Kalenius) + * bug fix: better understanding of array simplicity (or otherwise) in the + type system. (lp#1903241) + * bug fix: unions of rational and integer types now have a single canonical + form, allowing more correct reasoning about them in the type system. + * bug fix: less likely to overclaim certainty about type equality of union + types. (lp#1916040) + * bug fix: HANDLER-BIND evaluates the forms producing handler functions only + once. (lp#1916302, reported by Christophe Junke) + * optimization: FIND on constant sequences can be compiled into a jump + table, in a similar manner to POSITION + * optimization: the compiler's awareness of numeric contagion rules for + operations on pairs of floating point numbers is improved. (lp#1914094, + thanks to Andrew Berkley) + +changes in sbcl-2.1.1 relative to sbcl-2.1.0: + * platform support: + ** restore non-threaded NetBSD builds; + ** adjust how the finalizer thread is started; (lp#1906571, lp#1907872) + ** fix the encoding of PEXTR on x86-64; + * minor incompatible change: emit warnings for list iteration forms when the + object being iterated over is known not to be a list. (lp#1908819, + reported by Michael Fiano) + * bug fix: detect 2 or 1 as an invalid number of arguments passed to + optimized slot reading or writing effective method respectively. + (lp#1909659, reported by Michal Herda) + * bug fix: division by zero errors were in some cases not being signalled. + (lp#1910098, reported by il71) + * bug fix: erroneous coercions in the type system could lose precision. + (lp#1910294) + * bug fix: literal (read-time evaluated) NaNs in source code no longer cause + compiler crashes. (lp#1909881, reported by Michal Herda) + * bug fix: detect more erroneous syntax in method bodies. (lp#1912362, + reported by Paul M. Rodriguez) + * optimization: the compiler's understanding of EXPT is improved, reducing + the introduction of COMPLEX types. (lp#1908830, reported by Michael Fiano) + * optimization: the compiler is better at computing numeric contagion when + (COMPLEX FLOAT) types are involved. + * micro-optimizations: + ** moving from slightly-bigger-than-fixnum ranges is more efficient on x86-64; + ** encode character comparisons with smaller operands on x86-64; + ** truncating (and related operations) on floats can be inlined in more + cases on 64-bit platforms; + ** rounding can use specialized instructions on ARM64 and on x86-64 when + SSE4 is available; + +changes in sbcl-2.1.0 relative to sbcl-2.0.11: + * minor incompatible change: the MAKE-EA internal function, used in the + assembler, has been removed (affecting some libraries defining their own + Virtual Operations) + * new feature: SB-EXT:PRIMITIVE-OBJECT-SIZE can be used to interrogate the + low-level size in memory of objects. (lp#1636910, reported by anquegi) + * platform support: + ** pass required -std argument to the compiler on Solaris (lp#1885751, + thanks to Jesse Off) + ** better treatment of non-ASCII program arguments on Windows (lp#1907970, + reported by Timofei Shatrov) + ** implement the improved TYPEP with structure types on all other + supported platforms (32-bit PowerPC, ARM, ARM64, MIPS, SPARC, RISC-V) + * enhancement: stream dispatch (to vanilla ANSI / Gray / Simple variants) has + been rewritten and optimized, fixing a number of bugs including: + ** performance of WRITE-SEQUENCE on composite streams (lp#309136) + ** handling of CLOSE on SYNONYM-STREAM (lp#1904257, reported by Richard M + Kreuter) + ** handling of CLOSE on BROADCAST-STREAM with no components (lp#1904722, + reported by Richard M Kreuter) + ** loading SB-SIMPLE-STREAMS breaks functionality of other stream classes + (lp#1908132) + ** some excessive consing in READ-LINE + * enhancements related to RUN-PROGRAM: + ** improved the documentation related to the ARGS argument (lp#806733, + reported by mon_key) + ** added a PRESERVE-FDS argument + * bug fix: ensure that TYPE-OF returns something even on internal instances, + which may become visible in the debugger. (lp#1908261, reported by + Philipp Marek) + * bug fix: iteration variables established by standard forms should always + be considered used by the compiler. (lp#719585, reported by Roman + Marynchak) + * bug fix: don't allow compiler transformations to weaken the requirement + against extended (list-form) function names in FUNCALL and related + operators. (lp#310069) + * bug fix: improve automated version number generation in branches. + (lp#897867, thanks to Martin Cracauer) + * bug fix: add possibly-spurious futex wakes when unwinding from a call to + futex-wait, to avoid deadlocks from interrupted waits. (lp#1038034) + * bug fixes in the compiler: + ** error on malformed DESTRUCTURING-BIND (lp#1738638) + ** error on malformed SPECIAL declaration (lp#1740756) + ** error from use of VALUES type in COERCE (lp#1887712) + ** enforcement of FTYPE types involving &OPTIONAL (lp#1903932) + ** checking for proper-list-ness before applying transforms (lp#1905512) + ** compilation of LAMBDA form including a malformed DEFUN (lp#1906056) + ** memory fault from VALUES-related handling in high DEBUG code + (lp#1906563) + ** transforms handle explicit NIL arguments in :END arguments to SEARCH + (lp#1907924) + * bug fix: return COMPILED-FUNCTION for TYPE-OF on compiled functions. + (lp#1906583) + * some bugs were also closed in this release cycle as obsolete, having been + fixed by the passage of time or other change in the environment: + ** floating point error reporting on OS X (lp#309454) + ** load-shared-library not working from non-main threads on OS X (lp#592425) + * optimization: CONSTANTLY on constant arguments returns a more efficient + function. (lp#1852585) + * optimization: perform fewer Lisp/Alien representation conversions in + callbacks. + * optimization: perform fewer redundant widetag tests when doing type tests + of complicated union types. + * optimization: signed-integer division on machine-word sized operands is + now implemented using multiplication, affecting TRUNCATE, FLOOR, CEILING, + MOD and REM. (This optimization was already performed on unsigned-integer + division) + +changes in sbcl-2.0.11 relative to sbcl-2.0.10: + * minor incompatible change: (ARRAY NIL (*)) is not a subtype of STRING, + as is consistent with a majority of maintained CL implementations. + * minor incompatible change: ARRAY-RANK-LIMIT is decreased from 65529 to 256 + * optimization: TYPEP on structure types is faster and more compact on + x86[-64] and ppc64. + * optimization: LOGCOUNT is faster on arm64. + * optimization: SIGNUM can be inlined if its argument type is known. + (lp#1903533) + * bug fix: compiler crash in tail call handling. (lp#1903938) + * bug fix: crash in traceroot. (lp#1903419, reported by Michal Herda) + * bug fix: DESCRIBE called with a string as second argument no longer mutates + that string. (lp#1903901, reported by Michal Herda) + * bug fix: stack clobbering by 256-bit SIMD packs on x86-64. (lp#1901685, + reported by Marco Heisig) + +changes in sbcl-2.0.10 relative to sbcl-2.0.9: + * minor incompatible change: the funarg given to SB-SPROF:MAP-TRACES + does not receive a wallclock time with each trace. + * minor incompatible change: INTERNAL-TIME-UNITS-PER-SECOND has been + increased to 10^6 on 64-bit architectures. + * minor incompatible change: SIGPIPE is ignored by default again. (lp#1897624) + * minor incompatible change: the system code compiled under the + :LINKAGE-TABLE feature is now unconditionally compiled in, and the + corresponding entry in *FEATURES* has been removed. + * enhancement: style-warnings are issued for variables which have an + assignment but no "for-value reference" (per CLHS glossary entry) + * bug fix: SB-CLTL2:MACROEXPAND-ALL did not expand MULTIPLE-VALUE-BIND + and MULTIPLE-VALUE-SETQ + * bug fix: CPUID-based feature detection had an index/mask confusion + (lp#1899239) + * bug fix: fix a deadlock on Windows (lp#1896802) + * bug fix: eliminate type errors when wall clocks go back (lp#1028026, + lp#1032111) + * bug fix: fix EOF handling in read-char-no-hang on concatenenated streams + (lp#690408, reported by Willem Broekema) + * bug fix: fix MAP-INTO on extended sequences (lp#1855375, thanks to James + Kalenius) + * bug fix: SB-GMP can now raise -1, 0 and 1 to the power of a bignum. + (thanks to Aaron Chen) + * bug fixes in tests: + ** add a C function declaration (lp#1897627, thanks to Bob Felts) + ** parse vmmap output more liberally (lp#1897722, reported by Bob Felts) + +changes in sbcl-2.0.9 relative to sbcl-2.0.8: + * incompatible change: HPPA and DEC Alpha architecture + support has been removed. + * minor incompatible change: the compiler signals a warning at + compile-time when an initform of T, NIL or 0 does not match a + STANDARD-CLASS slot's declared type. + * minor incompatible change: the runtime no longer uses SIGPIPE internally, + so the signal is deliverable to user code as is customary. Ignoring the + signal - in lieu of the OS default of process termination - is obtainable + via (SB-SYS:ENABLE-INTERRUPT SB-UNIX:SIGPIPE :IGNORE). + * platform support: + ** a number of obsolete portability layers (particularly on the Windows + platform) have been removed in favour of direct calling of the native + interfaces. + ** RUN-PROGRAM now accepts a :WINDOW argument to control whether a + subprocess window should be displayed. (Thanks to Luis Borges de + Oliveira) + ** the use of futexes implied by :SB-FUTEX is now implemented on FreeBSD. + * bug fix: SB-SPROF can distinguish between SBCL-internal assembly routines. + * bug fix: SB-SPROF has better output in its reports for anonymous + functions. + * optimization: CALL-NEXT-METHOD with supplied arguments in required + positions is now faster if the supplied arguments are EQL to the original + arguments. -changes relative to sbcl-2.0.4: +changes in sbcl-2.0.8 relative to sbcl-2.0.7: + * platform support: + ** added support for NetBSD/ARM64; + ** threads on Linux now have OS-visible names; + ** removed unnecessary emulation of pthread functions on Windows; + ** work around a sigwait() bug on Mac OS X; + ** allow safepoint build on Mac OS X, though it probably doesn't + work very well (reported by Chris Wagner, lp#1382811) + ** removed stub support for HPUX. + * optimization: SB-THREAD:MAKE-THREAD is faster on most platforms. + * optimization: faster RATIONAL when the result is a RATIO. + * optimization: improved cross-type comparisons (float/ratio/bignum). + * bug fix: EQUALP on pathnames was wrong + * bug fixes: fix compiler issues in: + ** COUNT (lp#1889391) + ** VECTOR-LENGTH (lp#1888919) + ** constant-folding (lp#1888384) + ** FIND and POSITION (lp#1887316) + +changes in sbcl-2.0.7 relative to sbcl-2.0.6: + * minor incompatible change: SB-THREAD:THREAD-OS-TID returns NIL for + a thread which has exited. + * minor incompatible change: OPEN no longer calls TRUENAME implicitly + on a string filespec prior to issuing an open() system call. + * minor incompatible change: PATHNAME is no longer a STRUCTURE-OBJECT. + * documentation: HASH-FUNCTION is a function designator. (lp#1888028, + reported by Jacek Zlydach) + * bug fix: eliminated a potential garbage-collector deadlock + when linking with TCMalloc. + * bug fix: foreign threads (those not made by SB-THREAD:MAKE-THREAD) + can not crash with a "GC_PENDING, but why?" error when returning + back from Lisp into the foreign caller. + * bug fix: sb-fasteval crashed trying to install a JIT-compiled + DEFSTRUCT accessor in a locked package. + * bug fix: removed misuse of putwc() which caused stdio streams + to drop characters. + * bug fix: the "maximum interrupt nesting depth exceeded" error + generated in the C runtime is significantly less likely to occur. + * bug fix: sb-sprof should no longer segfault from calling pthread_kill() + on a nonexistent thread. + * bug fix: a portability issue arising from various build hosts + (lp#1886255, reported by Pierre Neidhardt) + * bug fix: spurious compiler warnings from REDUCE with :INITIAL-VALUE. + (lp#1885515, reported by Michael South) + * bug fix: an inconsistency between class hierarchies and the type system + under some circumstances involving redefinition. (lp#1886397, reported by + Atilla Lendvai) + * bug fix: the USE-VALUE restart for OPEN on non-existent files is more + likely to function as expected. (lp#1886587) + * bug fix: various invalid inputs to ROTATE-BYTE no longer cause compiler + errors. (lp#1887164, lp#1888152) + * optimization: PPC64 on linux uses the __thread annotation on C variables + in preference to pthread_setspecific() and pthread_getspecific(). + +changes in sbcl-2.0.6 relative to sbcl-2.0.5: + * planned incompatible change: the defined symbols in the Metaobject + Protocol, currently accessible from both SB-MOP and SB-PCL packages, will + in a later release be no longer exported from SB-PCL. + * platform support: + ** better support for dynamic-extent on the SPARC architecture. + ** bug fix for loading very large core files. + ** bug fix for logior and logxor on PPC64. + * enhancement: EQUALP on structure instances uses code specialized + to each structure type, inlining comparison of non-pointer slots. + * enhancement: some standard operators, such as WITH-OUTPUT-TO-STRING and + CHANGE-CLASS, have been adapted to use dynamic-extent temporary objects, + and so cons less garbage on the heap. + * enhancement: read tables are more space- and speed efficient + * bug fix: stream conditions with dynamic-extent streams have the stream + replaced by a stub. (reported by Matt Kaufmann) + * bug fix: garbage collections triggered from foreign callbacks crashed. + (lp#1884403, reported by Andrew Kent) + * bug fix: compiler failure in compiling MAKE-LIST. (lp#1881349) + * bug fix: using the debugger from frames with calls to functions with + unsupplied optional arguments is less likely to cause heap corruption. + (lp#1883745) + +changes in sbcl-2.0.5 relative to sbcl-2.0.4: + * platform support: + ** experimental support for ARM32 and ARM64 on OpenBSD + ** better musl libc support. (lp#1768368, thanks to Eric Timmons) + ** more correct use of futexes on 64-bit Linux. (lp#1876825, reported by + Ilya Perminov) + ** restore building on current Solaris. (lp#1881393, thanks to Shawn + Ellis) * enhancement: CMUCL-style START-BLOCK and END-BLOCK declarations are now supported for block compiling forms at a sub-file granularity. + * enhancement: IPv6 support in sb-bsd-sockets is enabled on Windows. * minor change: *compile-print* now makes it more clear what block compilation is actually doing. The default output is now slightly more verbose as a result. + * bug fix: number keys in EQUALP hash tables are correctly hashed. + (lp#1878653, reported by Syll) * bug fix: EQness is better preserved given partial sharing of list contents in the file compiler. (lp#1583753, reported by Denis Budyak) + * bug fix: the peephole pass neglected to preserve jump table labels. + (lp#1876485) + * bug fix: fix compiler crash in block compilation merging of toplevel + lambdas. (lp#1865336, reported by il71) + * bug fix: sb-introspect's function-lambda-arglist is better at extracting + default values of nested macro arguments. (lp#1876194) + * bug fix: RESTART-BIND's body is an implicit progn, and so does not accept + declarations. (lp#1876303, reported by Michal Herda) + * optimization: EQUAL hash tables with keys involving structure-objects will + have fewer systematic collisions. changes in sbcl-2.0.4 relative to sbcl-2.0.3: * platform support: diff --git a/README.static-executable b/README.static-executable new file mode 100644 index 0000000000..ffd12f35fe --- /dev/null +++ b/README.static-executable @@ -0,0 +1,250 @@ +This branch of SBCL is maintained by Eric Timmons (@daewok) and contains a set +of patches necessary to build a completely static executable with SBCL. Such an +executable has all necessary foreign libraries statically linked into the +runtime and has no support for dynamic loading and unloading of +libraries. While the lack of dynamic loading support is certainly constraining, +the benefit of building an executable this way is it requires no libraries to +be installed by the user of the executable. This makes it ideal for archival +purposes, distributing executables to a non-technical audience, distributing an +executable where you must know the exact versions of foreign libraries used at +runtime, or distributing executables that Just Work^TM (like many executables +written in golang). + +While other solutions exist to statically link foreign libraries into the SBCL +runtime, to the best of my knowledge there has been no publicly advertised +method of building SBCL with libc statically linked. The lack of static linking +for libc means that the user of the executable must have a compatible libc +installed. Unfortunately, the most commonly used libc in the Linux world +(glibc) is frequently not backward compatible with itself. For evidence of +this, see the fact that SBCLs built on Debian Buster (like the official +releases since 1.5.6) do not run on Debian Stretch. + +Unfortunately, glibc doesn't even really support static linking at +all. Therefore, I recommend that static SBCL executables be built with musl +libc. Musl is designed with static linking in mind and is broadly compatible +with most libraries that don't do tricksy things with libc. And if you find a +library not compatible with musl libc, it seems most maintainers are welcoming +to patches that add support. + +Alpine Linux is a great OS for building statically linked executables as it +uses musl libc by default. I further recommend using Docker for building static +executables so that you don't need to maintain a separate Alpine install. Plus, +you can use the clfoundation/sbcl:alpine3.13 image as a starting point. + +THEORY + +The biggest issue with creating a static executable is ensuring that foreign +symbols are accessible from the Lisp core. In normal, dynamic use, SBCL uses +dlsym to look up the address of symbols and stores them in a vector in foreign +memory called the "linkage table". The lisp core then maintains a hash table +mapping foreign symbol names to their index in the linkage table. This is +called the linkage info. + +In a static executable, we cannot count on having a working dlsym, even if +libdl is linked into the runtime. When performing static linkage, musl libc +replaces all libdl functions with stubs that simply return errors. Therefore, +we have to use the system linker to resolve the references for us. But in order +to have the linker do that for us, we need to know at link time which foreign +symbols our lisp code will want to use! + +EXTRACTING LINKAGE INFO + +There are two approaches described below to generate a static executable. Both +of them require a file describing the desired linkage info. While you could +generate this by hand, it is easiest to extract it from a core. + +In order to extract the linkage info from a running core, use +tools-for-build/dump-linkage-info.lisp. After loading that into the core, +evaluate (sb-dump-linkage-info:dump-to-file #p"/path/to/output.sexp"). It also +takes an keyword argument :make-undefined, a list of symbol names to make +undefined in the output. This is useful for approach two below. + +The sexp written to the output file is a single list of lists. Each sublist has +three elements. The first is a string naming the symbol. The second is T if the +symbol is entered into the linkage info as data (it is a foreign variable) and +NIL otherwise (it is a foreign function). The third is T if the symbol is +undefined and NIL otherwise. It is critical that undefined symbols be +maintained for approach one below. + +The following two sections describe two approaches on how to generate a static +executable, step-by-step. The demo static executable contains the sb-gmp +contrib and runs its test quite when executed. It requires that the static +libraries for libgmp and libz are installed on your system. There is some +weirdness with how the tests are loaded. This is because the tests do not seem +to work after being dumped: I have not yet figured out why this is. + +BUILDING A STATIC EXECUTABLE - APPROACH ONE + +This approach to building a static executable is preferred if you're you want +to minimize the amount of time compiling C and Lisp code. It takes advantage of +the fact that musl inserts stub functionality for libdl such that it can still +be linked against. + +The general process for this approach is: + +0. Build SBCL with the :sb-prelink-linkage-table feature (:sb-linkable-runtime +is also strongly recommended). + +1. Build a core containing the lisp code you want to package in the static +executable. + +2. Dump the linkage info to a file. + +3. Dump the core to a file (with save-lisp-and-die). + +4. Generate a C file that contains the info needed to build the linkage table. + +5. Relink the runtime. This time statically *and* with the object file +generated from the C file in step 4. + +6. Load the saved core into the new static runtime, dumping again with +:executable t if desired. + +Some notes about this approach: + ++ The build IDs of the dynamic runtime (used to generate the core in step 1) +and the static runtime *must* match. The easiest way to achieve this is to +install SBCL with the feature :sb-linkable-runtime. This installs sbcl.o (the +SBCL runtime in a ingle object file) along with everything else. + ++ No modifications must be made to the linkage info file generated in step 2 +and no symbols can be filtered out of it. + +Here is a step-by-step procedure to build the demo static executable using this +approach. + +Step 0: + + sh make.sh --fancy --with-sb-linkable-runtime --with-sb-prelink-linkage-table + sh install.sh + +Steps 1-3: + + sbcl --non-interactive \ + --no-sysinit --no-userinit \ + --eval '(require :uiop)' \ + --eval '(require :sb-gmp)' \ + --eval '(require :sb-rt)' \ + --eval '(defvar *sb-gmp-tests* (uiop:read-file-string "contrib/sb-gmp/tests.lisp"))' \ + --load tools-for-build/dump-linkage-info.lisp \ + --eval '(sb-dump-linkage-info:dump-to-file "/tmp/linkage-info.sexp")' \ + --eval '(sb-ext:save-lisp-and-die "/tmp/sb-gmp-tester.core")' + +Step 4: + + sbcl --no-sysinit --no-userinit \ + --script tools-for-build/create-linkage-table-prelink-info-override.lisp \ + /tmp/linkage-info.sexp \ + /tmp/linkage-table-prelink-info-override.c + +Step 5: + + # Get all the variables SBCL used to build defined in the current environment. + while read l; do + eval "${l%%=*}=\"${l#*=}\""; + done < /usr/local/lib/sbcl/sbcl.mk + + $CC $CFLAGS -Wno-builtin-declaration-mismatch -o /tmp/linkage-table-prelink-info-override.o -c /tmp/linkage-table-prelink-info-override.c + $CC -no-pie -static $LINKFLAGS -o /tmp/static-sbcl /usr/local/lib/sbcl/$LIBSBCL /tmp/linkage-table-prelink-info-override.o -lgmp $LIBS + +Step 6: + + /tmp/static-sbcl --core /tmp/sb-gmp-tester.core \ + --non-interactive \ + --no-sysinit --no-userinit \ + --eval '(sb-ext:save-lisp-and-die "/tmp/sb-gmp-tester" :executable t :toplevel (lambda () (uiop:load-from-string *sb-gmp-tests*) (sb-rt:do-tests) (exit)) :compression t)' + + +Look at the dumped executable. You should see that it is a static executable. + + ldd /tmp/sb-gmp-tester + +Test that it works! + + /tmp/sb-gmp-tester + +BUILDING A STATIC EXECUTABLE - APPROACH TWO + +This approach results in an executable that is not linked with libdl at +all. This makes it a little bit more "pure" than than the previous approach, +but that comes at the cost of needing to fully recompile both the runtime and +core after the necessary foreign symbols are determined. + +The general process for this approach is: + +1. Build a core containing the lisp code you want to package in the static +executable. + +2. Dump the linkage info to a file. + +3. Recompile SBCL, passing in the linkage info during build. + +4. Rebuild your core with the new runtime and corresponding core. + +5. Dump with :executable t. + +Some notes about this approach: + ++ The libdl symbols must be stripped out of the linkage info file generated in +step 2. The easiest way to do this is pass sb-dump-linkage-info:*libdl-symbols* +as the :make-undefined argument to dump-to-file. + ++ Further modifications can be made to the linkage info file generated in step +2. You can reorder the symbols at will. You can add new symbols. You probably +don't want to remove any (besides libdl functions). + +Steps 1-2: + + sh run-sbcl.sh --non-interactive \ + --no-sysinit --no-userinit \ + --eval '(require :uiop)' \ + --eval '(require :sb-gmp)' \ + --eval '(require :sb-rt)' \ + --eval '(defvar *sb-gmp-tests* (uiop:read-file-string "contrib/sb-gmp/tests.lisp"))' \ + --load tools-for-build/dump-linkage-info.lisp \ + --eval '(sb-dump-linkage-info:dump-to-file "/tmp/linkage-info.sexp" :remove-symbols sb-dump-linkage-info:*libdl-symbols*)' + +Step 3: + + LDLIBS="-lgmp" LINKFLAGS="-no-pie -static" IGNORE_CONTRIB_FAILURES="yes" sh make.sh --extra-linkage-table-entries=/tmp/linkage-info.sexp --without-os-provides-dlopen --without-os-provides-dladdr --fancy + +Steps 4-5: + + sh run-sbcl.sh --non-interactive \ + --no-sysinit --no-userinit \ + --eval '(require :uiop)' \ + --eval '(require :sb-gmp)' \ + --eval '(require :sb-rt)' \ + --eval '(defvar *sb-gmp-tests* (uiop:read-file-string "contrib/sb-gmp/tests.lisp"))' \ + --eval '(sb-ext:save-lisp-and-die "/tmp/sb-gmp-tester" :executable t :toplevel (lambda () (uiop:load-from-string *sb-gmp-tests*) (sb-rt:do-tests) (exit)) :compression t)' + +Look at the dumped executable. You should see that it is a static executable. + + ldd /tmp/sb-gmp-tester + +Test that it works! + + /tmp/sb-gmp-tester + +BUILDING A STATIC EXECUTABLE WITH DOCKER + +See the Dockerfile at tools-for-build/Dockerfile.static-executable-example for +an example of how to build the demo executable using Docker and approach +one. The benefit of Docker is that it is a cheap way to build with musl libc +even if you use glibc locally. + +The following commands will build the demo executable inside docker and extract +it from the image, placing it at /tmp/sb-gmp-tester on your local file +system. The following commands also try to avoid polluting your Docker +namespace by not tagging the image or naming the container used to extract the +executable. + + IMAGE_ID_FILE="$(mktemp)" + CONTAINER_ID_FILE="$(mktemp)" + rm "$CONTAINER_ID_FILE" + docker build --iidfile "$IMAGE_ID_FILE" -f tools-for-build/Dockerfile.static-executable-example . + docker create --cidfile "$CONTAINER_ID_FILE" "$(cat "$IMAGE_ID_FILE")" + docker cp "$(cat "$CONTAINER_ID_FILE"):/tmp/sb-gmp-tester" /tmp/sb-gmp-tester + docker rm "$(cat "$CONTAINER_ID_FILE")" + rm "$IMAGE_ID_FILE" + rm "$CONTAINER_ID_FILE" diff --git a/TODO b/TODO index ecf397395f..1c88ea5e70 100644 --- a/TODO +++ b/TODO @@ -47,11 +47,6 @@ PEEPHOLE OPTIMIZER Have you ever read SBCL disassembly? -DEFGLOBAL - - Global lexical variables. Esp. since with threads special variable - accesses is no speed daemon. - FINISHING EXTERNAL FORMATS Byte order marks. Newline conventions. A way to specify an external @@ -75,11 +70,6 @@ ADVICE/FWRAP latter returns the underlying definition, whereas the first returns the encapsulation. -GENERIC FUNCTION TRACING - - This sucks currently. It would also be good to be able to trace - individual methods. - POLICY MADNESS The interactions between various optimization policies are far from @@ -88,11 +78,6 @@ POLICY MADNESS FAST-SAFE, FAST-UNSAFE) "dominant" policies, and expose the rest as separately declarable optimization toggles. - MAYBE-INLINE is also nice, but it would be good if someone could - figure out how to get rid of it while retaining the semantics it - provides. Inlining recursive functions is also something to think - about. - INHIBIT-WARNINGS really needs to go away. WINDOWS @@ -101,13 +86,10 @@ WINDOWS DARWIN - Needs love, particularly threads and exceptions/signals. slam.sh is - also broken there. + Needs love, particularly threads and exceptions/signals. DRAGONFLY Multithreading does not work. Possibly because of bug in mmap/munmap. - Hint: Comment out call to os_invalidate in perform_thread_post_mortem - and threads will work, but space will not be freed, of course. MISC CLEANUPS @@ -120,13 +102,6 @@ MISC CLEANUPS ** use %COMPILE where COMPILE-TOP-LEVEL used to be used ** remove redundant COMPILE-TOP-LEVEL and FUNCTIONAL-KIND=:TOP-LEVEL stuff from the compiler - * outstanding embarrassments - ** :IGNORE-ERRORS-P cruft in stems-and-flags.lisp-expr. (It's - reasonable to support this as a crutch when initially - bootstrapping from balky xc hosts with their own - idiosyncratic ideas of what merits FAILURE-P, but it's - embarrassing to have to use it when bootstrapping - under SBCL!), * miscellaneous simple refactoring * belated renaming: ** rename %PRIMITIVE to %VOP diff --git a/benchmarks/grab-mutex.lisp b/benchmarks/grab-mutex.lisp new file mode 100644 index 0000000000..9ee82641f4 --- /dev/null +++ b/benchmarks/grab-mutex.lisp @@ -0,0 +1,208 @@ +(in-package sb-thread) + +(sb-ext:defglobal *mutex* (sb-thread:make-mutex)) +(declaim (type mutex *mutex*)) +(sb-ext:defglobal *start-semaphore* nil) +(sb-ext:defglobal *ready-semaphore* nil) + +(defmacro timing (&body body) + `(binding* ((start-real (get-internal-real-time)) + ((thread-start-sec thread-start-nsec) + (sb-unix::clock-gettime sb-unix:clock-thread-cputime-id))) + ,@body + (binding* ((stop-real (get-internal-real-time)) + ((thread-stop-sec thread-stop-nsec) + (sb-unix::clock-gettime sb-unix:clock-thread-cputime-id))) + (values (- stop-real start-real) ; microseconds + (+ (* 1000000 (- thread-stop-sec thread-start-sec)) + (round (- thread-stop-nsec thread-start-nsec) 1000)))))) + +(defmacro timing-test (&body body) + `(let ((m *mutex*) (waste (make-array 100 :element-type 'sb-vm:word))) + (declare (truly-dynamic-extent waste)) + (setq sb-thread::*grab-mutex-calls-performed* 0) + ;; Get all threads to agree on the moment they should start + (sb-thread:signal-semaphore *ready-semaphore*) + (sb-thread:wait-on-semaphore *start-semaphore*) + (macrolet ((do-some-work () + ;; Perform a slightly nontrivial amount of "stuff" + ;; i.e. more than just assigning a variable. + '(dotimes (i (length waste)) + (setf (aref waste i) (logxor (aref waste i) (ash 1 (mod i 64))))))) + (timing ,@body)))) + +;;; Default implementation of WITH-MUTEX +(defun grab-and-release-baseline-nlx-protected (n-iter) + (timing-test + (dotimes (i (the fixnum n-iter)) + (sb-thread:with-mutex (m) + (do-some-work))))) + +;;; Default implementation of grab/release but no interrupt-safety +(defun grab-and-release-baseline-unprotected (n-iter) + (timing-test + (dotimes (i (the fixnum n-iter)) + (sb-thread:grab-mutex m) + (do-some-work) + (sb-thread:release-mutex m)))) + +(defvar *mutexes-held* nil) +(setf (sb-int:info :variable :wired-tls '*mutexes-held*) :always-thread-local + (sb-int:info :variable :always-bound '*mutexes-held*) :always-bound) +(defmacro binding-mutexes-held ((mutex) &body body) + `(dx-let ((*mutexes-held* (cons ,mutex *mutexes-held*))) ,@body)) + +;;; Faster implementation of grab and release +(defun grab-and-release-algo-2 (n-iter) + (timing-test + (dotimes (i (the fixnum n-iter)) + (sb-thread:wait-for-mutex-algorithm-2 m) + (binding-mutexes-held (m) + (do-some-work) + (sb-thread:fast-release-mutex m))))) +;;; Faster implementation, and GRAB- can often avoid a function call +(defun grab-and-release-algo-2+ (n-iter) + (timing-test + (dotimes (i (the fixnum n-iter)) + (sb-thread:wait-for-mutex-2-partial-inline m) + (binding-mutexes-held (m) + (do-some-work) + (sb-thread:fast-release-mutex m))))) +(defun grab-and-release-algo-3 (n-iter) + (timing-test + (dotimes (i (the fixnum n-iter)) + (sb-thread:wait-for-mutex-algorithm-3 m) + (binding-mutexes-held (m) + (do-some-work) + (sb-thread:fast-release-mutex m))))) +(defun grab-and-release-algo-3+ (n-iter) + (timing-test + (dotimes (i (the fixnum n-iter)) + (sb-thread:wait-for-mutex-3-partial-inline m) + (binding-mutexes-held (m) + (do-some-work) + (sb-thread:fast-release-mutex m))))) + +(defun try (n-threads n-iter label testfun) + (let (threads) + (setq *ready-semaphore* (sb-thread:make-semaphore)) + (setq *start-semaphore* (sb-thread:make-semaphore)) + (dotimes (i n-threads) + (push (sb-thread:make-thread testfun :arguments n-iter) + threads)) + ;; Wait until all threads say that they're ready + (sb-thread:wait-on-semaphore *ready-semaphore* :n n-threads) + ;; "Unleash the hounds" + (sb-thread:signal-semaphore *start-semaphore* n-threads) + (let ((sum-real 0) + (sum-cpu 0)) + (dolist (thread threads) + (multiple-value-bind (realtime cputime) + (sb-thread:join-thread thread) + ;;(format t "real: ~5d cpu: ~5d~%" realtime cputime) + (incf sum-real realtime) + (incf sum-cpu cputime))) + (format t "~20a: cpu=(sum=~8d avg=~8d) real=~8d~@[ [~d calls]~]~%" + label + sum-cpu (floor sum-cpu n-threads) + (floor sum-real n-threads) + (let ((c sb-thread::*grab-mutex-calls-performed*)) + (unless (zerop c) c)))))) + +(defun test-n-threads (n) + (try n 100000 "WITH-MUTEX" 'grab-and-release-baseline-nlx-protected) + (try n 100000 "GRAB+RELEASE" 'grab-and-release-baseline-unprotected) + (try n 100000 "ALGO2" 'grab-and-release-algo-2) + (try n 100000 "ALGO2+" 'grab-and-release-algo-2+) + (try n 100000 "ALGO3" 'grab-and-release-algo-3) + (try n 100000 "ALGO3+" 'grab-and-release-algo-3+)) + +#| +* (sb-thread::test-n-threads 5) +WITH-MUTEX : cpu=(sum= 1129410 avg= 225882) real= 251198 +GRAB+RELEASE : cpu=(sum= 1013281 avg= 202656) real= 221599 +ALGO2 : cpu=(sum= 983301 avg= 196660) real= 217599 [480215 calls] +ALGO2+ : cpu=(sum= 906144 avg= 181228) real= 199999 [240760 calls] +ALGO3 : cpu=(sum= 953727 avg= 190745) real= 212000 [482759 calls] +ALGO3+ : cpu=(sum= 893479 avg= 178695) real= 199998 [246538 calls] + +* (sb-thread::test-n-threads 10) +WITH-MUTEX : cpu=(sum= 4744457 avg= 474445) real= 535597 +GRAB+RELEASE : cpu=(sum= 4854507 avg= 485450) real= 544798 +ALGO2 : cpu=(sum= 4168526 avg= 416852) real= 453997 [968121 calls] +ALGO2+ : cpu=(sum= 3720948 avg= 372094) real= 409599 [462061 calls] +ALGO3 : cpu=(sum= 4091659 avg= 409165) real= 444797 [970730 calls] +ALGO3+ : cpu=(sum= 3824551 avg= 382455) real= 418398 [404065 calls] + +* (sb-thread::test-n-threads 15) +WITH-MUTEX : cpu=(sum=12460694 avg= 830712) real= 909595 +GRAB+RELEASE : cpu=(sum=11579420 avg= 771961) real= 835462 +ALGO2 : cpu=(sum= 9343377 avg= 622891) real= 654131 [1463285 calls] +ALGO2+ : cpu=(sum= 8908803 avg= 593920) real= 631996 [571894 calls] +ALGO3 : cpu=(sum= 9262899 avg= 617526) real= 654929 [1458653 calls] +ALGO3+ : cpu=(sum= 8771110 avg= 584740) real= 620264 [539979 calls] + +* (sb-thread::test-n-threads 20) +WITH-MUTEX : cpu=(sum=18373401 avg= 918670) real= 1157394 +GRAB+RELEASE : cpu=(sum=19171438 avg= 958571) real= 1110394 +ALGO2 : cpu=(sum=15958082 avg= 797904) real= 883196 [1947759 calls] +ALGO2+ : cpu=(sum=14531894 avg= 726594) real= 839596 [776184 calls] +ALGO3 : cpu=(sum=16258896 avg= 812944) real= 869995 [1950461 calls] +ALGO3+ : cpu=(sum=15892267 avg= 794613) real= 840197 [719736 calls] + +* (sb-thread::test-n-threads 25) +WITH-MUTEX : cpu=(sum=24908201 avg= 996328) real= 1425273 +GRAB+RELEASE : cpu=(sum=24098405 avg= 963936) real= 1358552 +ALGO2 : cpu=(sum=18334699 avg= 733387) real= 1135194 [2402256 calls] +ALGO2+ : cpu=(sum=18920912 avg= 756836) real= 1095675 [932165 calls] +ALGO3 : cpu=(sum=20350344 avg= 814013) real= 1100794 [2427181 calls] +ALGO3+ : cpu=(sum=19708020 avg= 788320) real= 1051835 [891826 calls] + +* (sb-thread::test-n-threads 30) +WITH-MUTEX : cpu=(sum=29270655 avg= 975688) real= 1725458 +GRAB+RELEASE : cpu=(sum=29194555 avg= 973151) real= 1616391 +ALGO2 : cpu=(sum=25331922 avg= 844397) real= 1331460 [2911750 calls] +ALGO2+ : cpu=(sum=25128049 avg= 837601) real= 1291458 [1111621 calls] +ALGO3 : cpu=(sum=25039192 avg= 834639) real= 1310660 [2912492 calls] +ALGO3+ : cpu=(sum=24520302 avg= 817343) real= 1261327 [1069574 calls] + +* (sb-thread::test-n-threads 35) +WITH-MUTEX : cpu=(sum=35886189 avg= 1025319) real= 1958961 +GRAB+RELEASE : cpu=(sum=32335690 avg= 923876) real= 1894504 +ALGO2 : cpu=(sum=29280055 avg= 836573) real= 1557933 [3395447 calls] +ALGO2+ : cpu=(sum=28854572 avg= 824416) real= 1490965 [1276195 calls] +ALGO3 : cpu=(sum=28764304 avg= 821837) real= 1539534 [3389637 calls] +ALGO3+ : cpu=(sum=27708686 avg= 791676) real= 1467193 [1239603 calls] + +* (sb-thread::test-n-threads 40) +WITH-MUTEX : cpu=(sum=40892193 avg= 1022304) real= 2209987 +GRAB+RELEASE : cpu=(sum=37467476 avg= 936686) real= 2130089 +ALGO2 : cpu=(sum=34310107 avg= 857752) real= 1765091 [3882825 calls] +ALGO2+ : cpu=(sum=33543491 avg= 838587) real= 1711993 [1455625 calls] +ALGO3 : cpu=(sum=32834489 avg= 820862) real= 1724991 [3878370 calls] +ALGO3+ : cpu=(sum=29716033 avg= 742900) real= 1669290 [1378376 calls] + +* (sb-thread::test-n-threads 45) +WITH-MUTEX : cpu=(sum=47760154 avg= 1061336) real= 2463454 +GRAB+RELEASE : cpu=(sum=45402624 avg= 1008947) real= 2385232 +ALGO2 : cpu=(sum=36951436 avg= 821143) real= 1971723 [4363504 calls] +ALGO2+ : cpu=(sum=36382508 avg= 808500) real= 1918567 [1626474 calls] +ALGO3 : cpu=(sum=37765508 avg= 839233) real= 1934301 [4365986 calls] +ALGO3+ : cpu=(sum=37104282 avg= 824539) real= 1842213 [1582110 calls] + +* (sb-thread::test-n-threads 50) +WITH-MUTEX : cpu=(sum=51003010 avg= 1020060) real= 2775826 +GRAB+RELEASE : cpu=(sum=50266070 avg= 1005321) real= 2643187 +ALGO2 : cpu=(sum=42814331 avg= 856286) real= 2179588 [4851758 calls] +ALGO2+ : cpu=(sum=40166972 avg= 803339) real= 2121509 [1795256 calls] +ALGO3 : cpu=(sum=40122437 avg= 802448) real= 2167029 [4843515 calls] +ALGO3+ : cpu=(sum=40284932 avg= 805698) real= 2058550 [1743178 calls] + +* (sb-thread::test-n-threads 55) +WITH-MUTEX : cpu=(sum=55076760 avg= 1001395) real= 3008711 +GRAB+RELEASE : cpu=(sum=56878995 avg= 1034163) real= 2877731 +ALGO2 : cpu=(sum=46343366 avg= 842606) real= 2402168 [5331893 calls] +ALGO2+ : cpu=(sum=43091002 avg= 783472) real= 2330753 [1938588 calls] +ALGO3 : cpu=(sum=45509126 avg= 827438) real= 2342314 [5345695 calls] +ALGO3+ : cpu=(sum=45191331 avg= 821660) real= 2260789 [1909666 calls] +|# diff --git a/benchmarks/threads-compile.lisp b/benchmarks/threads-compile.lisp new file mode 100644 index 0000000000..1c3d9f10f9 --- /dev/null +++ b/benchmarks/threads-compile.lisp @@ -0,0 +1,243 @@ +;;; This is a stress test of multi-thread garbage collection without +;;; introducing contrived factors into the system such as extra debugging +;;; or manually invoked GC. + +#| + +NB: You need to compile with #+sb-devel +so that compiling "src/compiler/srctran" does not fail quickly. + +Legend: One line per statistic, measured in microsec. One column per thread. +The statistics: + 1. worst observed GC wait time per thread + 2. average GC wait time per thread + 3. total CPU time per thread + +./run-sbcl.sh --dynamic-space-size 4GB +* (load "src/cold/chill") +* (load (compile-file "benchmarks/threads-compile")) + +* (benchmark 4 4) ; 4 threads, 4 iterations each +;; worst-case stop-the-world pause = .528 sec + [ 161289 528922 528972 528953] + [ 67780 100901 93856 99925] + [ 4342694 3875017 4088501 3992092] + +* (benchmark 20 6) ; 20 threads, 6 iterations each +;; worst-case stop-the-world pause = .905 sec +;; but I've seen this parameter pair produce as much as 1.38 sec worst-case pause + [ 853493 905262 904932 904812 904660 904480 905302 904205 904040 904363 905253 905290 905231 903957 903644 903827 903432 903272 903607 905291] + [ 95906 98105 96955 96992 100130 98969 99631 96186 98073 96748 97830 97861 94608 94574 97282 95638 97308 96941 97169 95195] + [ 8638099 7620908 8408132 7783041 7411906 7616439 7550742 7881625 8042876 7627665 7090403 7322993 8996690 8231693 7415837 8477329 7745566 8130082 7640412 7891094] + +* (benchmark 30 4) ; 30 threads, 4 iterations each +;; worst-case stop-the-world pause = 1.59 sec + [ 1589254 1589235 1589236 1589246 1589200 1589244 1589293 1589249 1589258 1589260 1589195 1589517 1589541 1589267 1589454 1589577 1589311 1589311 1589420 1589658 1589638 1589322 1589302 1589262 1426929 1589448 1589644 1589307 1589492 1589577] + [ 131124 133234 134216 132862 134032 133074 131811 133394 134221 133830 133337 135129 133034 131109 133957 130416 128010 133089 128650 131075 134138 133200 130342 132036 126419 133778 132877 135274 132027 132272] + [ 6463084 5699894 6391162 5323400 5510025 5425688 6288613 4886611 5456971 5394043 5564274 5639621 5054329 5722550 5208487 5986264 6858847 5267559 7030543 5811645 5656792 5012832 6000738 5682139 7220169 6433044 5468151 5295718 5333045 5908446] +|# + +(defparameter *gcmetrics-condvar* + (sb-sys:find-dynamic-foreign-symbol-address "gcmetrics_condvar")) +(defparameter *gcmetrics-mutex* + (sb-sys:find-dynamic-foreign-symbol-address "gcmetrics_mutex")) + +(define-alien-routine pthread-mutex-lock int (m unsigned)) +(define-alien-routine pthread-mutex-unlock int (m unsigned)) +(define-alien-routine pthread-cond-wait int (cv unsigned) (m unsigned)) +(define-alien-routine pthread-cond-broadcast int (cv unsigned)) + +(defun thread-gcmetrics (thread) + (sb-thread:with-deathlok (thread c-thread) + (if (= c-thread 0) + (values nil nil nil) + (let ((sap + (sb-sys:sap+ (sb-sys:int-sap c-thread) + (+ (sb-alien:extern-alien "dynamic_values_bytes" (sb-alien:unsigned 32)) + (* 8 8))))) ; interrupt context pointers + (values (sb-sys:sap-ref-64 sap 8) ; avg + (sb-sys:sap-ref-64 sap 16) ; worst + (sb-sys:sap-ref-64 sap 0)))))) ; runtime + +;;; Exercise COMPILE-FILE in many threads, which is representative of a +;;; lispy workload. Any suitable workload should do. +;;; It would be better to have each thread doing a different kind of work, +;;; but I took the easy route. +(defun gc-benchmark (n-threads n-iter) + (let (threads + (running (make-array n-threads :initial-element t)) + (avg-gc-wait (make-array n-threads)) + (worst-gc-wait (make-array n-threads)) + (runtime (make-array n-threads))) + (flet ((work (arg) + (with-open-file (*standard-output* + (format nil "/tmp/foo~d.stdout" arg) + :direction :output + :if-exists :supersede + :if-does-not-exist :create) + (let ((*error-output* *standard-output*)) + (dotimes (i n-iter) + (let ((file (format nil "/tmp/foo~d.fasl" arg))) + (compile-file "src/compiler/srctran" + :print nil + :output-file file))))) + (setf (aref running arg) nil) + (pthread-cond-broadcast *gcmetrics-condvar*))) + (dotimes (i n-threads) + (push (sb-thread:make-thread + #'work + :name (format nil "worker~d" i) + :arguments i) + threads))) + (let ((start (get-internal-real-time))) + (assert (= 0 (pthread-mutex-lock *gcmetrics-mutex*))) + (loop + (let ((count (count t running))) + (when (zerop count) (return)) + (assert (= 0 (pthread-cond-wait *gcmetrics-condvar* *gcmetrics-mutex*))) + (let ((i 0)) + (dolist (thread threads) + (multiple-value-bind (avg worst run) (thread-gcmetrics thread) + (when avg + (setf (aref avg-gc-wait i) avg + (aref worst-gc-wait i) worst + (aref runtime i) run))) + (incf i))) + (format t "~D threads:~% [~{~8d~^ ~}]~% [~{~8d~^ ~}]~% [~{~8d~^ ~}]~%" + count + (coerce worst-gc-wait 'list) + (coerce avg-gc-wait 'list) + (coerce runtime 'list)))) + (pthread-mutex-unlock *gcmetrics-mutex*) + (let ((end (get-internal-real-time))) + (format t "~&all done: ~fs~%" + (/ (- end start) internal-time-units-per-second)))))) + +;;; run this with a 16GB dynamic space +(defun allocator-benchmark (n-threads n-iter) + (let (threads (sem (make-semaphore))) + (flet ((work (arg) + (let ((out (format nil "/tmp/out~d.fasl" arg))) + (dotimes (i n-iter) + (compile-file "src/compiler/node" + :print nil :block-compile t :verbose nil + :output-file out) + (signal-semaphore sem)) + (delete-file out)) + (values (sb-vm::current-thread-offset-sap + sb-vm::thread-et-allocator-mutex-acq-slot) + (sb-vm::current-thread-offset-sap + sb-vm::thread-et-find-freeish-page-slot) + (sb-vm::current-thread-offset-sap + sb-vm::thread-et-bzeroing-slot)))) + (dotimes (i n-threads) + (push (make-thread #'work :name (format nil "worker~d" i) :arguments i) + threads) + (sleep .25)) + (setq threads (nreverse threads)) + (macrolet ((intmetric (slot) + `(sap-ref-word sap (ash ,slot sb-vm:word-shift))) + (floatmetric (slot) + `(float (sap-ref-word sap (ash ,slot sb-vm:word-shift))))) + (let ((n-to-go (* n-threads n-iter))) + (loop + ;; Wait for any thread to be done with one COMPILE-FILE + (wait-on-semaphore sem) + (dolist (thread threads) + (with-deathlok (thread c-thread) + (unless (= c-thread 0) + (let* ((sap (int-sap c-thread)) + (divisor (intmetric sb-vm::thread-slow-path-allocs-slot)) + (times + (list (/ (floatmetric sb-vm::thread-et-allocator-mutex-acq-slot) + divisor) + (/ (floatmetric sb-vm::thread-et-find-freeish-page-slot) + divisor) + (/ (floatmetric sb-vm::thread-et-bzeroing-slot) + divisor)))) + (format t "~a: ~a~%" (thread-name thread) times))))) + (terpri) + (when (zerop (decf n-to-go)) (return)))))))) + +#| +typical results: +(ALLOCATOR-BENCHMARK 1 5) + worker0: (330.69366 387.3285 6498.661) + +(ALLOCATOR-BENCHMARK 2 5) + worker0: (330.5141 267.6703 7333.836) + worker1: (228.58601 165.74622 6578.589) + +(ALLOCATOR-BENCHMARK 5 5) + worker0: (690.2581 425.22952 5876.69) + worker1: (710.41406 348.25806 6209.075) + worker2: (839.3615 454.86133 7612.185) + worker3: (885.43054 602.65674 10080.599) + worker4: (610.4866 262.36072 8558.833) + +(ALLOCATOR-BENCHMARK 10 5) + worker0: (1223.6002 430.6594 7850.7573) + worker1: (1330.8501 370.85773 6489.9937) + worker2: (1253.6841 505.19583 5270.5938) + worker3: (1490.959 715.54004 6404.7485) + worker4: (1285.563 418.3966 4903.252) + worker5: (1166.429 367.69632 4751.1025) + worker6: (1516.6385 703.275 5229.6743) + worker7: (1445.5946 435.18625 8682.394) + worker8: (1445.0297 392.44226 6706.816) + worker9: (1356.9069 461.00558 5664.2266) + +(ALLOCATOR-BENCHMARK 20 3) + worker0: (1556.1759 320.41278 7864.225) + worker1: (2484.3042 380.25073 6287.422) + worker2: (2330.8076 518.1103 6229.52) + worker3: (1892.3644 413.4363 6322.3574) + worker4: (2391.721 581.5211 5309.2114) + worker5: (3180.5654 1101.414 5779.844) + worker6: (2621.355 634.3344 4852.1455) + worker7: (2378.809 440.01437 4085.8718) + worker8: (2730.9878 432.23807 3691.8616) + worker9: (2128.9807 376.76605 6020.571) + worker10: (2715.6238 483.9466 7864.9487) + worker11: (2880.8203 445.12094 5770.294) + worker12: (3576.9197 767.5074 6190.4316) + worker13: (3010.8503 437.47897 6542.27) + worker14: (2961.2139 453.69385 6901.6504) + worker15: (3242.9263 513.6723 6050.3047) + worker16: (3760.2107 1017.8271 6511.578) + worker17: (3949.1416 794.4195 5975.102) + worker18: (3443.0042 444.75006 4557.97) + worker19: (3430.517 806.4593 3539.3176) + +(ALLOCATOR-BENCHMARK 30 2) + worker0: (3228.2756 465.13016 8892.34) + worker1: (3792.6448 770.495 7546.6333) + worker2: (3741.0088 856.29407 9156.665) + worker3: (3276.4631 410.84845 8926.436) + worker4: (3618.4817 409.49045 6198.2173) + worker5: (3677.3682 533.64966 6499.718) + worker6: (3326.2502 426.92972 6894.4204) + worker7: (4277.313 497.48938 8042.677) + worker8: (4424.929 515.2159 8480.562) + worker9: (4579.331 646.7453 7944.594) + worker10: (5665.9673 585.96246 9082.217) + worker11: (4093.323 536.14 8263.94) + worker12: (5716.6953 636.16815 6921.578) + worker13: (5787.886 771.44214 4725.5513) + worker14: (7163.328 1685.777 5396.888) + worker15: (5750.1753 584.4418 4869.9063) + worker16: (5826.1787 653.7092 3785.243) + worker17: (6162.1816 760.8072 3882.8232) + worker18: (5333.0513 477.8418 4006.6885) + worker19: (8481.007 597.1158 3250.377) + worker20: (9162.3125 2120.3945 5063.6616) + worker21: (5398.499 643.1221 11578.032) + worker22: (7045.36 1039.0885 5842.894) + worker23: (9666.884 543.9834 4494.3945) + worker24: (9476.041 770.6879 4494.854) + worker25: (4477.0054 348.83954 5587.9424) + worker26: (5616.502 469.45154 5180.7173) + worker27: (10800.295 481.92975 6047.9507) + worker28: (11228.471 606.4268 4192.347) + worker29: (19881.9 996.91534 157.6319) +|# diff --git a/binary-distribution.sh b/binary-distribution.sh index a2e998e218..49988dfe63 100755 --- a/binary-distribution.sh +++ b/binary-distribution.sh @@ -23,9 +23,9 @@ tar -cf $b-binary.tar \ `for contrib in $(cd $b/contrib && echo *); do src_dir=$b/contrib/$contrib cache_dir=$b/obj/asdf-cache/$contrib - if test -d $src_dir && test -f $cache_dir/test-passed.test-report; then + if test -d $src_dir && test -f $cache_dir/build-passed.test-report; then echo $src_dir/Makefile - echo $cache_dir/test-passed.test-report + echo $cache_dir/build-passed.test-report fi done` \ $b/obj/sbcl-home diff --git a/clean.sh b/clean.sh index e157121e11..8997173d91 100755 --- a/clean.sh +++ b/clean.sh @@ -14,7 +14,7 @@ set -e # this script (including "gmake clean" in the src/runtime directory) # several times in a row without failure.. so we leave the output/ # directory in place.) -rm -rf obj/* output/* src/runtime/genesis/ +rm -rf obj/* output/* src/runtime/genesis/ src/runtime/sbcl.mk # Ensure that we know GNUMAKE. . ./find-gnumake.sh @@ -32,7 +32,7 @@ for d in tools-for-build; do $GNUMAKE -I ../src/runtime -s clean cd "$original_pwd" > /dev/null done -( cd ./doc ; sh ./clean.sh ) +( cd ./doc && sh ./clean.sh ) # Within all directories, remove things which don't look like source # files. Some explanations: @@ -95,7 +95,6 @@ find . \( \ -name 'core' -o \ -name '?*.core' -o \ -name '*.map' -o \ - -name '*.nm' -o \ -name '*.host-obj' -o \ -name '*.lisp-obj' -o \ -name '*.target-obj' -o \ @@ -111,11 +110,26 @@ find . \( \ -name 'encodings.texi-temp' -o \ -name 'stack-alignment-offset' -o \ -name 'test-status.lisp-expr' -o \ + -name 'last-random-state.lisp-expr' -o \ + -name 'test.log' -o \ + -name 'whitespace-stamp' -o \ -name 'a.out' -o \ -name 'sbcl' -o \ -name 'sbcl.h' -o \ + -name 'ppc-linux-mcontext.h' -o \ -name 'depend' -o \ -name 'TAGS' -o \ -name 'tags' -o \ -name 'test-passed' -o \ - -name 'local-target-features.lisp-expr' \) -print | xargs rm -fr + -name 'local-target-features.lisp-expr' \) -print | \ + if test -f .cleanignore; then + # Because this file deletes all symlinks, it prevents building + # in a tree of symlinks. Here's a low-tech workaround: have + # whatever tool creates your tree of symlinks enumerate + # relative paths to each one in a file called .cleanignore, + # and this script won't delete them. This .cleanignore file + # doesn't support any wildcards or comments. + awk 'BEGIN{while(getline <".cleanignore"!=0){ign["./" $0]=1}} ign[$0]!=1'; + else + cat; + fi | xargs rm -fr diff --git a/contrib/Makefile b/contrib/Makefile index b2b385e468..5c9fb76693 100644 --- a/contrib/Makefile +++ b/contrib/Makefile @@ -1,9 +1,16 @@ vpath %.fasl ../obj/sbcl-home/contrib/ -all: asdf.fasl sb-posix.fasl sb-bsd-sockets.fasl sb-introspect.fasl sb-cltl2.fasl \ - sb-aclrepl.fasl sb-sprof.fasl sb-capstone.fasl sb-md5.fasl sb-capstone.fasl \ - sb-executable.fasl sb-gmp.fasl sb-mpfr.fasl sb-queue.fasl sb-rotate-byte.fasl \ - sb-simple-streams.fasl sb-concurrency.fasl sb-cover.fasl +contribs = asdf sb-posix sb-bsd-sockets sb-introspect sb-cltl2 sb-aclrepl \ + sb-sprof sb-capstone sb-md5 sb-capstone sb-executable sb-gmp sb-mpfr \ + sb-queue sb-rotate-byte sb-simple-streams sb-concurrency sb-cover \ + sb-graph sb-simd + +active_contribs = $(filter-out $(SBCL_CONTRIB_BLOCKLIST),$(contribs)) + +fasls = $(active_contribs:=.fasl) + +all: $(fasls) + asdf.fasl: sh ./build-contrib $(basename $(@F)) sb-grovel.fasl: asdf.fasl @@ -42,3 +49,7 @@ sb-rotate-byte.fasl: asdf.fasl sh ./build-contrib $(basename $(@F)) sb-simple-streams.fasl: asdf.fasl sb-posix.fasl sb-bsd-sockets.fasl sb-rt.fasl sh ./build-contrib $(basename $(@F)) +sb-graph.fasl: asdf.fasl sb-rt.fasl + sh ./build-contrib $(basename $(@F)) +sb-simd.fasl: asdf.fasl + sh ./build-contrib $(basename $(@F)) diff --git a/contrib/asdf-module.mk b/contrib/asdf-module.mk index 6c1882fac4..97f443fc7e 100644 --- a/contrib/asdf-module.mk +++ b/contrib/asdf-module.mk @@ -6,7 +6,7 @@ # ones as dependencies. UNAME:=$(shell uname -s) -DEST=$(SBCL_PWD)/obj/sbcl-home/contrib/ +DEST=$(SBCL_TOP)/obj/sbcl-home/contrib/ FASL=$(DEST)/$(SYSTEM).fasl ASD=$(DEST)/$(SYSTEM).asd @@ -30,12 +30,16 @@ all: $(FASL) $(ASD) $(FASL):: $(SBCL) --eval '(setf (sb-ext:readtable-base-char-preference *readtable*) :both)' \ + --eval '(declaim (muffle-conditions (and compiler-note (not sb-c::unknown-typep-note))))' \ --load ../asdf-stub.lisp \ --eval '(asdf::build-asdf-contrib "$(SYSTEM)")' $(ASD):: echo "(defsystem :$(SYSTEM) :class require-system)" > $@ +build: $(FASL) $(ASD) + true + test: $(FASL) $(ASD) $(SBCL) --load ../asdf-stub.lisp \ --eval '(asdf::test-asdf-contrib "$(SYSTEM)")' diff --git a/contrib/asdf-stub.lisp b/contrib/asdf-stub.lisp index 1bd8a77e3a..c6da6cc6fe 100644 --- a/contrib/asdf-stub.lisp +++ b/contrib/asdf-stub.lisp @@ -14,9 +14,9 @@ sb-ext::(declaim (unmuffle-conditions sb-kernel:redefinition-warning)) (defun setup-asdf-contrib () ;;(setf *resolve-symlinks* nil) - (let* ((sbcl-pwd (getenv-pathname "SBCL_PWD" :ensure-directory t)) - (src-contrib (subpathname sbcl-pwd "contrib/")) - (asdf-cache (subpathname sbcl-pwd "obj/asdf-cache/")) + (let* ((sbcl-top (merge-pathnames (getenv-pathname "SBCL_TOP" :ensure-directory t))) + (src-contrib (subpathname sbcl-top "contrib/")) + (asdf-cache (subpathname sbcl-top "obj/asdf-cache/")) (source-registry '(:source-registry :ignore-inherited-configuration)) (output-translations `(:output-translations (,(namestring src-contrib) ,(namestring asdf-cache)) @@ -49,9 +49,9 @@ sb-ext::(declaim (unmuffle-conditions sb-kernel:redefinition-warning)) (append '(:sb-building-contrib) sb-impl:+internal-features+ *features*)) (setup-asdf-contrib) (let* ((name (string-downcase system)) - (sbcl-pwd (getenv-pathname "SBCL_PWD" :ensure-directory t)) - (out-contrib (subpathname sbcl-pwd "obj/sbcl-home/contrib/")) - (cache-module (subpathname sbcl-pwd (format nil "obj/asdf-cache/~a/" name))) + (sbcl-top (merge-pathnames (getenv-pathname "SBCL_TOP" :ensure-directory t))) + (out-contrib (subpathname sbcl-top "obj/sbcl-home/contrib/")) + (cache-module (subpathname sbcl-top (format nil "obj/asdf-cache/~a/" name))) (system (find-system name)) (system.fasl (output-file 'compile-bundle-op system)) (module.fasl (subpathname out-contrib (strcat name ".fasl"))) @@ -66,6 +66,8 @@ sb-ext::(declaim (unmuffle-conditions sb-kernel:redefinition-warning)) (format o "(provide :~A)~%~{(require ~(~S~))~%~}" name dependencies)) (compile-file module-setup.lisp :output-file module-setup.fasl) (operate 'compile-bundle-op system) + (let ((s (find-symbol "DUMP/RESTORE-INTERESTING-TYPES" "SB-C"))) + (when s (funcall s 'write))) (concatenate-files input-fasls module.fasl))) (defun test-asdf-contrib (system) diff --git a/contrib/asdf/Makefile b/contrib/asdf/Makefile index 1fd4a3b1b2..c1abd15772 100644 --- a/contrib/asdf/Makefile +++ b/contrib/asdf/Makefile @@ -1,4 +1,4 @@ -DEST=$(SBCL_PWD)/obj/sbcl-home/contrib/ +DEST=$(SBCL_TOP)/obj/sbcl-home/contrib/ ASDF_FASL=$(DEST)/asdf.fasl UIOP_FASL=$(DEST)/uiop.fasl FASL=$(UIOP_FASL) $(ASDF_FASL) @@ -7,16 +7,18 @@ FROB_READTABLE='(setf (sb-ext:readtable-base-char-preference *readtable*) :both) fasl:: $(UIOP_FASL) $(ASDF_FASL) $(UIOP_FASL):: uiop.lisp ../../output/sbcl.core mkdir -p $(DEST) - $(SBCL) --eval $(FROB_READTABLE) --eval '(compile-file #p"SYS:CONTRIB;ASDF;UIOP.LISP" :print nil :output-file (parse-native-namestring "$@"))' &1 && touch ../obj/asdf-cache/$@/test-passed.test-report ; then +if $GNUMAKE -j1 -C $@ build < /dev/null 2>&1 && touch ../obj/asdf-cache/$@/build-passed.test-report ; then : else exit $? diff --git a/contrib/sb-aclrepl/inspect.lisp b/contrib/sb-aclrepl/inspect.lisp index 37cbced7f9..24532ee729 100644 --- a/contrib/sb-aclrepl/inspect.lisp +++ b/contrib/sb-aclrepl/inspect.lisp @@ -757,7 +757,7 @@ cons cells and LIST-TYPE is :normal, :dotted, or :cyclic" (defun inspected-structure-parts (object) (let ((components-list '()) - (info (sb-kernel:layout-info (sb-kernel:layout-of object)))) + (info (sb-kernel:wrapper-info (sb-kernel:wrapper-of object)))) (when (sb-kernel::defstruct-description-p info) (dolist (dd-slot (sb-kernel:dd-slots info) (nreverse components-list)) (push (cons (string (sb-kernel:dsd-name dd-slot)) diff --git a/contrib/sb-aclrepl/sb-aclrepl.asd b/contrib/sb-aclrepl/sb-aclrepl.asd index d22af906be..cb32435b20 100644 --- a/contrib/sb-aclrepl/sb-aclrepl.asd +++ b/contrib/sb-aclrepl/sb-aclrepl.asd @@ -12,13 +12,4 @@ (:file "repl" :depends-on ("toplevel")) (:file "inspect" :depends-on ("repl")) (:file "debug" :depends-on ("repl"))) - :perform (load-op :after (o c) (provide 'sb-aclrepl)) - :in-order-to ((test-op (test-op "sb-aclrepl/tests")))) - -(defsystem "sb-aclrepl/tests" - :depends-on ("sb-rt") - :components ((:file "tests"))) - -(defmethod perform ((o test-op) (c (eql (find-system "sb-aclrepl/tests")))) - (or (funcall (intern "DO-TESTS" (find-package "SB-RT"))) - (error "test-op failed"))) + :perform (load-op :after (o c) (provide 'sb-aclrepl))) diff --git a/contrib/sb-aclrepl/tests.lisp b/contrib/sb-aclrepl/tests.lisp index 5d692ff55f..1a7c17914d 100644 --- a/contrib/sb-aclrepl/tests.lisp +++ b/contrib/sb-aclrepl/tests.lisp @@ -1,16 +1,13 @@ ;; Tests for sb-aclrepl (defpackage #:aclrepl-tests - (:use #:sb-aclrepl #:cl #:sb-rt)) + (:import-from #:test-util #:deftest) + (:use #:sb-aclrepl #:cl)) (in-package #:aclrepl-tests) (declaim (special sb-aclrepl::*skip-address-display* sb-aclrepl::*inspect-unbound-object-marker*)) -(setf sb-rt::*catch-errors* nil) - -(rem-all-tests) - (deftest hook.1 (boundp 'sb-impl::*inspect-fun*) t) (deftest hook.2 (boundp 'sb-int:*repl-prompt-fun*) t) (deftest hook.3 (boundp 'sb-int:*repl-read-form-fun*) t) @@ -58,16 +55,11 @@ '(0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19))) (eval-when (:compile-toplevel :load-toplevel :execute) - (defparameter *circle-list1* '(a)) - (setf (car *circle-list1*) *circle-list1*) - (defparameter *circle-list2* '(b)) - (setf (cdr *circle-list2*) *circle-list2*) - (defparameter *circle-list3* '(a b c)) - (setf (car *circle-list3*) *circle-list3*) - (defparameter *circle-list4* '(a b c)) - (setf (second *circle-list4*) *circle-list4*) - (defparameter *circle-list5* '(a b c)) - (setf (cddr *circle-list5*) *circle-list5*)) + (defparameter *circle-list1* '#1=(#1#)) + (defparameter *circle-list2* '#2=(b . #2#)) + (defparameter *circle-list3* '#3=(#3# b c)) + (defparameter *circle-list4* '#4=(a #4# c)) + (defparameter *circle-list5* '#5=(a b . #5#))) (defun find-position (object id) (nth-value 0 (sb-aclrepl::find-part-id object id))) diff --git a/contrib/sb-bsd-sockets/addrinfo-constants.lisp b/contrib/sb-bsd-sockets/constants-addrinfo.lisp similarity index 98% rename from contrib/sb-bsd-sockets/addrinfo-constants.lisp rename to contrib/sb-bsd-sockets/constants-addrinfo.lisp index a412f443bd..a78175387d 100644 --- a/contrib/sb-bsd-sockets/addrinfo-constants.lisp +++ b/contrib/sb-bsd-sockets/constants-addrinfo.lisp @@ -58,11 +58,12 @@ (:integer EAI-BADFLAGS "EAI_BADFLAGS") (:integer EAI-NONAME "EAI_NONAME") (:integer EAI-SERVICE "EAI_SERVICE") - #-(or freebsd dragonfly) + #-(or freebsd dragonfly win32) (:integer EAI-ADDRFAMILY "EAI_ADDRFAMILY") (:integer EAI-MEMORY "EAI_MEMORY") (:integer EAI-FAIL "EAI_FAIL") (:integer EAI-AGAIN "EAI_AGAIN") + #-win32 (:integer EAI-SYSTEM "EAI_SYSTEM") (:integer NI-NAMEREQD "NI_NAMEREQD")) diff --git a/contrib/sb-bsd-sockets/gethostbyname-constants.lisp b/contrib/sb-bsd-sockets/constants-gethostbyname.lisp similarity index 80% rename from contrib/sb-bsd-sockets/gethostbyname-constants.lisp rename to contrib/sb-bsd-sockets/constants-gethostbyname.lisp index 923bbcf853..7dfe424240 100644 --- a/contrib/sb-bsd-sockets/gethostbyname-constants.lisp +++ b/contrib/sb-bsd-sockets/constants-gethostbyname.lisp @@ -7,12 +7,12 @@ (addr (* t)) (len int) (af int))) - (:integer NETDB-INTERNAL #+hpux "h_NETDB_INTERNAL" #-hpux "NETDB_INTERNAL" "See errno.") - (:integer NETDB-SUCCESS #+hpux "h_NETDB_SUCCESS" #-hpux "NETDB_SUCCESS" "No problem.") + (:integer NETDB-INTERNAL "NETDB_INTERNAL" "See errno.") + (:integer NETDB-SUCCESS "NETDB_SUCCESS" "No problem.") (:integer HOST-NOT-FOUND "HOST_NOT_FOUND" "Authoritative Answer Host not found.") (:integer TRY-AGAIN "TRY_AGAIN" "Non-Authoritative Host not found, or SERVERFAIL.") (:integer NO-RECOVERY "NO_RECOVERY" "Non recoverable errors, FORMERR, REFUSED, NOTIMP.") (:integer NO-DATA "NO_DATA" "Valid name, no data record of requested type.") (:integer NO-ADDRESS "NO_ADDRESS" "No address, look for MX record.") - #-(or hpux sunos) + #-sunos (:function h-strerror ("hstrerror" c-string (errno int)))) diff --git a/contrib/sb-bsd-sockets/constants-unix.lisp b/contrib/sb-bsd-sockets/constants-unix.lisp new file mode 100644 index 0000000000..148f660f83 --- /dev/null +++ b/contrib/sb-bsd-sockets/constants-unix.lisp @@ -0,0 +1,44 @@ +("sys/socket.h" "errno.h" "fcntl.h") + +((:integer af-local + #+(or sunos solaris) "AF_UNIX" + #-(or sunos solaris) "AF_LOCAL" + "Local to host (pipes and file-domain).") + + (:integer ifnamsiz "IFNAMSIZ") + +;; socket shutdown flags + (:integer SHUT_RD "SHUT_RD") + (:integer SHUT_WR "SHUT_WR") + (:integer SHUT_RDWR "SHUT_RDWR") + + (:integer O-NONBLOCK "O_NONBLOCK") + (:integer f-getfl "F_GETFL") + (:integer f-setfl "F_SETFL") + + (:integer msg-trunc "MSG_TRUNC") + (:integer msg-waitall "MSG_WAITALL") + (:integer msg-eor "MSG_EOR") + (:integer msg-dontwait "MSG_DONTWAIT") + #+linux (:integer msg-nosignal "MSG_NOSIGNAL") + #+linux (:integer msg-confirm "MSG_CONFIRM") + #+linux (:integer msg-more "MSG_MORE") + + (:integer EADDRINUSE "EADDRINUSE") + (:integer EAGAIN "EAGAIN") + (:integer EBADF "EBADF") + (:integer ECONNREFUSED "ECONNREFUSED") + (:integer ETIMEDOUT "ETIMEDOUT") + (:integer EINTR "EINTR") + (:integer EINVAL "EINVAL") + (:integer ENOBUFS "ENOBUFS") + (:integer ENOMEM "ENOMEM") + (:integer EOPNOTSUPP "EOPNOTSUPP") + (:integer EPERM "EPERM") + (:integer EPROTONOSUPPORT "EPROTONOSUPPORT") + (:integer ERANGE "ERANGE") + (:integer ESOCKTNOSUPPORT "ESOCKTNOSUPPORT") + (:integer ENETUNREACH "ENETUNREACH") + (:integer ENOTCONN "ENOTCONN") + (:integer EAFNOSUPPORT "EAFNOSUPPORT") + (:integer EINPROGRESS "EINPROGRESS")) diff --git a/contrib/sb-bsd-sockets/constants-win32.lisp b/contrib/sb-bsd-sockets/constants-win32.lisp new file mode 100644 index 0000000000..6a2c925d6d --- /dev/null +++ b/contrib/sb-bsd-sockets/constants-win32.lisp @@ -0,0 +1,60 @@ +;;; -*- Lisp -*- + +;;; This isn't really lisp, but it's definitely a source file. we +;;; name it thus to avoid having to mess with the clc lpn translations + +;;; first, the headers necessary to find definitions of everything +("winsock2.h" "errno.h") + +;;; then the stuff we're looking for +((:function ioctl ("ioctlsocket" int + (socket int) + (cmd int) + (argp (unsigned 32) :in-out))) + + (:function wsa-socket ("WSASocketA" int + (af int) + (type int) + (protocol int) + (lpProtocolInfo (* t)) + (g int) + (flags int))) + + (:structure wsa-data ("struct WSAData" + (integer version "u_int16_t" "wVersion") + (integer high-version "u_int16_t" "wHighVersion") + (c-string description "char" "szDescription") + (c-string system-status "char" "szSystemStatus") + (integer max-sockets "unsigned short" "iMaxSockets") + (integer max-udp-dg "unsigned short" "iMaxUdpDg") + (c-string-pointer vendor-info "char *" "lpVendorInfo"))) + + (:function wsa-startup ("WSAStartup" int + (wVersionRequested (unsigned 16)) + (lpWSAData wsa-data :out))) + + (:function wsa-get-last-error ("WSAGetLastError" int)) + + (:integer FIONBIO "FIONBIO") + + (:integer SHUT_RD "SD_RECEIVE") + (:integer SHUT_WR "SD_SEND") + (:integer SHUT_RDWR "SD_BOTH") + + (:integer EADDRINUSE "WSAEADDRINUSE") + (:integer EAGAIN "WSAEWOULDBLOCK") + (:integer EBADF "WSAEBADF") + (:integer ECONNREFUSED "WSAECONNREFUSED") + (:integer ETIMEDOUT "WSAETIMEDOUT") + (:integer EINTR "WSAEINTR") + (:integer EINVAL "WSAEINVAL") + (:integer ENOBUFS "WSAENOBUFS") + (:integer ENOMEM "WSAENOBUFS") + (:integer EOPNOTSUPP "WSAEOPNOTSUPP") + (:integer EPERM "WSAENETDOWN") + (:integer EPROTONOSUPPORT "WSAEPROTONOSUPPORT") + (:integer ESOCKTNOSUPPORT "WSAESOCKTNOSUPPORT") + (:integer ENETUNREACH "WSAENETUNREACH") + (:integer ENOTCONN "WSAENOTCONN") + (:integer EAFNOSUPPORT "WSAEAFNOSUPPORT") + (:integer EINPROGRESS "WSAEINPROGRESS")) diff --git a/contrib/sb-bsd-sockets/constants.lisp b/contrib/sb-bsd-sockets/constants.lisp index 8fef0fe837..ceaef58504 100644 --- a/contrib/sb-bsd-sockets/constants.lisp +++ b/contrib/sb-bsd-sockets/constants.lisp @@ -4,18 +4,15 @@ ;;; name it thus to avoid having to mess with the clc lpn translations ;;; first, the headers necessary to find definitions of everything -("sys/types.h" "sys/socket.h" "sys/stat.h" "unistd.h" "sys/un.h" +#-win32 ("sys/types.h" "sys/socket.h" "sys/stat.h" "unistd.h" "sys/un.h" "netinet/in.h" "netinet/in_systm.h" "netinet/ip.h" "net/if.h" "arpa/inet.h" ; inet_{ntop,pton} - "netdb.h" "errno.h" "netinet/tcp.h" "fcntl.h" ) + "netdb.h" "errno.h" "netinet/tcp.h" "fcntl.h") +#+win32 ("winsock2.h" "errno.h" "ws2tcpip.h") ;;; then the stuff we're looking for ((:integer af-inet "AF_INET" "IP Protocol family") (:integer af-unspec "AF_UNSPEC" "Unspecified") - (:integer af-local - #+(or sunos solaris hpux) "AF_UNIX" - #-(or sunos solaris hpux) "AF_LOCAL" - "Local to host (pipes and file-domain).") (:integer af-inet6 "AF_INET6" "IP version 6") #+linux (:integer af-route "AF_NETLINK" "Alias to emulate 4.4BSD ") @@ -66,48 +63,10 @@ (:integer tcp-nodelay "TCP_NODELAY") #+linux (:integer so-bindtodevice "SO_BINDTODEVICE") - (:integer ifnamsiz "IFNAMSIZ") - -;; socket shutdown flags -(:integer SHUT_RD "SHUT_RD") -(:integer SHUT_WR "SHUT_WR") -(:integer SHUT_RDWR "SHUT_RDWR") - -;; errors - (:integer EADDRINUSE "EADDRINUSE") - (:integer EAGAIN "EAGAIN") - (:integer EBADF "EBADF") - (:integer ECONNREFUSED "ECONNREFUSED") - (:integer ETIMEDOUT "ETIMEDOUT") - (:integer EINTR "EINTR") - (:integer EINVAL "EINVAL") - (:integer ENOBUFS "ENOBUFS") - (:integer ENOMEM "ENOMEM") - (:integer EOPNOTSUPP "EOPNOTSUPP") - (:integer EPERM "EPERM") - (:integer EPROTONOSUPPORT "EPROTONOSUPPORT") - (:integer ERANGE "ERANGE") - (:integer ESOCKTNOSUPPORT "ESOCKTNOSUPPORT") - (:integer ENETUNREACH "ENETUNREACH") - (:integer ENOTCONN "ENOTCONN") - (:integer EAFNOSUPPORT "EAFNOSUPPORT") - (:integer EINPROGRESS "EINPROGRESS") - - (:integer O-NONBLOCK "O_NONBLOCK") - (:integer f-getfl "F_GETFL") - (:integer f-setfl "F_SETFL") (:integer msg-oob "MSG_OOB") (:integer msg-peek "MSG_PEEK") - (:integer msg-trunc "MSG_TRUNC") - (:integer msg-waitall "MSG_WAITALL") - (:integer msg-eor "MSG_EOR") (:integer msg-dontroute "MSG_DONTROUTE") - (:integer msg-dontwait "MSG_DONTWAIT") - #+linux (:integer msg-nosignal "MSG_NOSIGNAL") - #+linux (:integer msg-confirm "MSG_CONFIRM") - #+linux (:integer msg-more "MSG_MORE") - ;; for socket-receive (:type socklen-t "socklen_t") @@ -177,9 +136,11 @@ ((array (unsigned 8)) flowinfo "u_int32_t" "sin6_flowinfo") ((array (unsigned 8)) addr "struct in_addr6" "sin6_addr") ((array (unsigned 8)) scope-id "u_int32_t" "sin6_scope_id"))) + #-win32 (:structure sockaddr-un ("struct sockaddr_un" (integer family "sa_family_t" "sun_family") (c-string path "char" "sun_path"))) + #-win32 (:structure sockaddr-un-abstract ("struct sockaddr_un" (integer family "sa_family_t" "sun_family") ((array (unsigned 8)) path "char" "sun_path"))) @@ -204,14 +165,7 @@ (integer type "int" "h_addrtype") (integer length "int" "h_length") ((* (* (unsigned 8))) addresses "char **" "h_addr_list"))) - (:structure msghdr ("struct msghdr" - (c-string-pointer name "void *" "msg_name") - (integer namelen "socklen_t" "msg_namelen") - ((* t) iov "struct iovec" "msg_iov") - (integer iovlen "size_t" "msg_iovlen") - ((* t) control "void *" "msg_control") - (integer controllen "socklen_t" "msg_controllen") - (integer flags "int" "msg_flags"))) + (:function socket (#-netbsd "socket" #+netbsd "_socket" int (domain int) (type int) @@ -239,7 +193,7 @@ (socket int) (his-addr (* t)) ; KLUDGE: sockaddr-in or sockaddr-un? (addrlen socklen-t))) - (:function close ("close" int + (:function close (#-win32 "close" #+win32 "closesocket" int (fd int))) (:function shutdown ("shutdown" int (fd int) (how int))) @@ -250,10 +204,7 @@ (flags int) (sockaddr (* t)) ; KLUDGE: sockaddr-in or sockaddr-un? (socklen (* socklen-t)))) - (:function recvmsg ("recvmsg" ssize-t - (socket int) - (msg (* msghdr)) - (flags int))) + (:function send ("send" ssize-t (socket int) (buf (* t)) @@ -266,10 +217,7 @@ (flags int) (sockaddr (* t)) ; KLUDGE: sockaddr-in or sockaddr-un? (socklen socklen-t))) - (:function sendmsg ("sendmsg" int - (socket int) - (msg (* msghdr)) - (flags int))) + ;; Socket options @@ -282,6 +230,7 @@ (:function fcntl ("fcntl" int (fd int) (cmd int) + &optional (arg long))) (:function getsockopt ("getsockopt" int (socket int) diff --git a/contrib/sb-bsd-sockets/inet.lisp b/contrib/sb-bsd-sockets/inet.lisp index d5e8122450..68063f907d 100644 --- a/contrib/sb-bsd-sockets/inet.lisp +++ b/contrib/sb-bsd-sockets/inet.lisp @@ -134,7 +134,7 @@ a list of protocol aliases" (go :error) (return-from getprotobyname (protoent-to-values ent)))))) #+sb-thread - (sb-thread::with-system-mutex (**getprotoby-lock**) + (sb-int:with-system-mutex (**getprotoby-lock**) (get-it)) #-sb-thread (get-it)) diff --git a/contrib/sb-bsd-sockets/inet4.lisp b/contrib/sb-bsd-sockets/inet4.lisp index 56429b5c71..69b405ab2a 100644 --- a/contrib/sb-bsd-sockets/inet4.lisp +++ b/contrib/sb-bsd-sockets/inet4.lisp @@ -92,7 +92,7 @@ Examples: sockaddr)) (defmethod free-sockaddr-for ((socket inet-socket) sockaddr) - (sockint::free-sockaddr-in sockaddr)) + (sb-alien:free-alien sockaddr)) (defmethod size-of-sockaddr ((socket inet-socket)) sockint::size-of-sockaddr-in) diff --git a/contrib/sb-bsd-sockets/inet6.lisp b/contrib/sb-bsd-sockets/inet6.lisp index caa92490ea..f0007498f2 100644 --- a/contrib/sb-bsd-sockets/inet6.lisp +++ b/contrib/sb-bsd-sockets/inet6.lisp @@ -100,7 +100,7 @@ malformed." sockaddr)) (defmethod free-sockaddr-for ((socket inet6-socket) sockaddr) - (sockint::free-sockaddr-in6 sockaddr)) + (sb-alien:free-alien sockaddr)) (defmethod size-of-sockaddr ((socket inet6-socket)) sockint::size-of-sockaddr-in6) diff --git a/contrib/sb-bsd-sockets/local.lisp b/contrib/sb-bsd-sockets/local.lisp index 9d9d5c7b87..aedaf2b54d 100644 --- a/contrib/sb-bsd-sockets/local.lisp +++ b/contrib/sb-bsd-sockets/local.lisp @@ -25,7 +25,7 @@ also known as unix-domain sockets.")) (values sockaddr sockint::size-of-sockaddr-un))) (defmethod free-sockaddr-for ((socket local-socket) sockaddr) - (sockint::free-sockaddr-un sockaddr)) + (sb-alien:free-alien sockaddr)) (defmethod size-of-sockaddr ((socket local-socket)) sockint::size-of-sockaddr-un) @@ -80,7 +80,7 @@ in the abstract namespace.")) (values sockaddr sockint::size-of-sockaddr-un-abstract)))))) (defmethod free-sockaddr-for ((socket local-abstract-socket) sockaddr) - (sockint::free-sockaddr-un-abstract sockaddr)) + (sb-alien:free-alien sockaddr)) (defmethod size-of-sockaddr ((socket local-abstract-socket)) sockint::size-of-sockaddr-un-abstract) diff --git a/contrib/sb-bsd-sockets/name-service.lisp b/contrib/sb-bsd-sockets/name-service.lisp index 2ab8effac6..3982d02ce1 100644 --- a/contrib/sb-bsd-sockets/name-service.lisp +++ b/contrib/sb-bsd-sockets/name-service.lisp @@ -68,14 +68,14 @@ "Returns a HOST-ENT instance for HOST-NAME or signals a NAME-SERVICE-ERROR. HOST-NAME may also be an IP address in dotted quad notation or some other weird stuff - see gethostbyname(3) for the details." - (sb-thread::with-system-mutex (**gethostby-lock** :allow-with-interrupts t) + (sb-int:with-system-mutex (**gethostby-lock** :allow-with-interrupts t) (make-host-ent (sockint::gethostbyname host-name)))) (defun get-host-by-address (address) "Returns a HOST-ENT instance for ADDRESS, which should be a vector of (integer 0 255), or signals a NAME-SERVICE-ERROR. See gethostbyaddr(3) for details." - (sb-thread::with-system-mutex (**gethostby-lock** :allow-with-interrupts t) + (sb-int:with-system-mutex (**gethostby-lock** :allow-with-interrupts t) (sockint::with-in-addr packed-addr () (let ((addr-vector (coerce address 'vector))) (loop for i from 0 below (length addr-vector) @@ -148,7 +148,7 @@ weird stuff - see getaddrinfo(3) for the details." elements in case of an IPv6 address, or signals a NAME-SERVICE-ERROR. See gethostbyaddr(3) for details." (declare (optimize speed)) - (multiple-value-bind (sockaddr sockaddr-free sockaddr-size address-family) + (multiple-value-bind (sockaddr sockaddr-size address-family) (etypecase address ((vector (unsigned-byte 8) 4) (let ((sockaddr (sb-alien:make-alien sockint::sockaddr-in))) @@ -157,7 +157,7 @@ See gethostbyaddr(3) for details." (dotimes (i (length address)) (setf (sb-alien:deref (sockint::sockaddr-in-addr sockaddr) i) (aref address i))) - (values sockaddr #'sockint::free-sockaddr-in + (values sockaddr (sb-alien:alien-size sockint::sockaddr-in :bytes) sockint::af-inet))) #-win32 @@ -167,7 +167,7 @@ See gethostbyaddr(3) for details." (dotimes (i (length address)) (setf (sb-alien:deref (sockint::sockaddr-in6-addr sockaddr) i) (aref address i))) - (values sockaddr #'sockint::free-sockaddr-in6 + (values sockaddr (sb-alien:alien-size sockint::sockaddr-in6 :bytes) sockint::af-inet6)))) (unwind-protect @@ -186,7 +186,7 @@ See gethostbyaddr(3) for details." :type address-family :aliases nil :addresses (list address)))) - (funcall sockaddr-free sockaddr))))) + (sb-alien:free-alien sockaddr))))) ;;; Error handling diff --git a/contrib/sb-bsd-sockets/sb-bsd-sockets.asd b/contrib/sb-bsd-sockets/sb-bsd-sockets.asd index 1d3e60772c..7313d17a13 100644 --- a/contrib/sb-bsd-sockets/sb-bsd-sockets.asd +++ b/contrib/sb-bsd-sockets/sb-bsd-sockets.asd @@ -6,7 +6,7 @@ ;;; 1003.1-2003 defines an alternative API, which is specified in the ;;; RFC to be thread-safe. If it seems to be available, use it. -(when (sb-alien::find-dynamic-foreign-symbol-address "getaddrinfo") +(when (sb-alien::find-foreign-symbol-address "getaddrinfo") (pushnew :sb-bsd-sockets-addrinfo *features*)) (defsystem "sb-bsd-sockets" @@ -14,74 +14,35 @@ :defsystem-depends-on ("sb-grovel") #+sb-building-contrib :pathname #+sb-building-contrib #p"SYS:CONTRIB;SB-BSD-SOCKETS;" + :serial t :components ((:file "defpackage") - - (:sb-grovel-constants-file "constants" :depends-on ("defpackage") - :if-feature (:not :win32) - :package :sockint) - (:file "win32-lib" :if-feature :win32) - (:sb-grovel-constants-file "win32-constants" :depends-on ("defpackage" "win32-lib") - :if-feature :win32 - :package :sockint) - (:sb-grovel-constants-file "addrinfo-constants" :depends-on ("defpackage") - :if-feature :sb-bsd-sockets-addrinfo - :package :sockint) - (:sb-grovel-constants-file "gethostbyname-constants" :depends-on ("defpackage") - :if-feature (:not :sb-bsd-sockets-addrinfo) - :package :sockint) - - (:file "util" :depends-on ("defpackage" "constants")) - (:file "protocol" :depends-on ("defpackage")) - - (:file "win32-sockets" :depends-on ("protocol" "win32-constants") - :if-feature :win32) - (:file "sockets" :depends-on ("util" "constants" "protocol" "win32-sockets")) - (:file "sockopt" :depends-on ("util" "sockets")) - - (:file "inet" :depends-on ("protocol" "sockets")) - (:file "inet4" :depends-on ("protocol" "sockets")) - (:file "inet6" :depends-on ("protocol" "sockets") - :if-feature (:not :win32)) - (:file "local" :depends-on ("protocol" "sockets") - :if-feature (:not :win32)) - - (:file "name-service" :depends-on ("protocol" "sockets")) - (:file "misc" :depends-on ("sockets")) - - ;; FIXME at least NEWS and TODO actually exist in the - ;; filesystem. However, their all-uppercase names are translated to - ;; all-lowercase in logical pathname translation. - ;; (:static-file "NEWS") - ;; (:static-file "INSTALL") - ;; (:static-file "README") - ;; (:static-file "index.html") - ;; (:static-file "TODO") - ) - :perform (load-op :after (o c) (provide 'sb-bsd-sockets)) - :in-order-to ((test-op (test-op "sb-bsd-sockets/tests")))) - -(defsystem "sb-bsd-sockets/tests" - :depends-on ("sb-rt" - "sb-bsd-sockets" - (:feature (:not :win32) "sb-posix")) - :components ((:file "tests")) - :perform (test-op (o c) - (multiple-value-bind (soft strict pending) - (funcall (intern "DO-TESTS" (find-package "SB-RT"))) - (declare (ignorable pending)) - (fresh-line) - (unless strict - #+sb-testing-contrib - ;; We create TEST-PASSED from a shell script if tests passed. But - ;; since the shell script only `touch'es it, we can actually create - ;; it ahead of time -- as long as we're certain that tests truly - ;; passed, hence the check for SOFT. - (when soft - (with-open-file (s #p"SYS:CONTRIB;SB-BSD-SOCKETS;TEST-PASSED.TEST-REPORT" - :direction :output) - (dolist (pend pending) - (format s "Expected failure: ~A~%" pend)))) - (warn "ignoring expected failures in test-op")) - (unless soft - (error "test-op failed with unexpected failures"))))) + (:file "win32-lib" :if-feature :win32) + (:sb-grovel-constants-file "constants" + :package :sockint) + (:sb-grovel-constants-file "constants-unix" + :if-feature (:not :win32) + :package :sockint) + (:sb-grovel-constants-file "constants-win32" + :if-feature :win32 + :package :sockint) + (:sb-grovel-constants-file "constants-addrinfo" + :if-feature :sb-bsd-sockets-addrinfo + :package :sockint) + (:sb-grovel-constants-file "constants-gethostbyname" + :if-feature (:not :sb-bsd-sockets-addrinfo) + :package :sockint) + (:file "util") + (:file "protocol") + (:file "win32-sockets" :if-feature :win32) + (:file "sockets") + (:file "sockopt") + + (:file "inet") + (:file "inet4") + (:file "inet6") + (:file "local" :if-feature (:not :win32)) + + (:file "name-service") + (:file "misc")) + :perform (load-op :after (o c) (provide 'sb-bsd-sockets))) diff --git a/contrib/sb-bsd-sockets/sockets.lisp b/contrib/sb-bsd-sockets/sockets.lisp index bab57a2982..18e94cc561 100644 --- a/contrib/sb-bsd-sockets/sockets.lisp +++ b/contrib/sb-bsd-sockets/sockets.lisp @@ -177,8 +177,8 @@ directly instantiated."))) ((or (eql element-type 'character) (eql element-type 'base-char)) (code-char (sb-alien:deref (sb-alien:deref copy-buffer) i))) (t (sb-alien:deref (sb-alien:deref copy-buffer) i))))) - (apply #'values buffer len (multiple-value-list - (bits-of-sockaddr socket sockaddr)))) + (multiple-value-call #'values buffer len + (bits-of-sockaddr socket sockaddr))) (:interrupted nil))) (sb-alien:free-alien copy-buffer)))))) @@ -236,44 +236,6 @@ directly instantiated."))) (open-stream-p (slot-value socket 'stream)) (/= -1 (socket-file-descriptor socket)))) -(defmethod socket-close ((socket socket) &key abort) - ;; the close(2) manual page has all kinds of warning about not - ;; checking the return value of close, on the grounds that an - ;; earlier write(2) might have returned successfully w/o actually - ;; writing the stuff to disk. It then goes on to define the only - ;; possible error return as EBADF (fd isn't a valid open file - ;; descriptor). Presumably this is an oversight and we could also - ;; get anything that write(2) would have given us. - - ;; note that if you have a socket _and_ a stream on the same fd, - ;; the socket will avoid doing anything to close the fd in case - ;; the stream has done it already - if so, it may have been - ;; reassigned to some other file, and closing it would be bad - (let ((fd (socket-file-descriptor socket))) - (flet ((drop-it (&optional streamp) - (setf (slot-value socket 'file-descriptor) -1) - (if streamp - (slot-makunbound socket 'stream) - (sb-ext:cancel-finalization socket)) - t)) - (cond ((eql fd -1) - ;; already closed - nil) - ((slot-boundp socket 'stream) - (close (slot-value socket 'stream) :abort abort) - ;; Don't do this if there was an error from CLOSE -- the stream is - ;; still live. - (drop-it t)) - (t - (handler-case - (socket-error-case ("close" (sockint::close fd) - result (minusp result))) - (bad-file-descriptor-error () - (drop-it)) - (:no-error (r) - (declare (ignore r)) - (drop-it)))))))) - (defmethod socket-shutdown ((socket socket) &key direction) (let* ((fd (socket-file-descriptor socket)) (how (ecase direction @@ -401,3 +363,44 @@ When supplied, ERRNO should be the UNIX error number associated to the failed call. The default behavior is to use the current value of the errno variable." (error (condition-for-errno errno) :errno errno :syscall where)) + +;;; This wants to refer to the BAD-FILE-DESCRIPTOR-ERROR condition class. +;;; :BLOCK-COMPILE would have handled it correctly, but I don't know how +;;; to pass that flag through our contrib-building steps. +(defmethod socket-close ((socket socket) &key abort) + ;; the close(2) manual page has all kinds of warning about not + ;; checking the return value of close, on the grounds that an + ;; earlier write(2) might have returned successfully w/o actually + ;; writing the stuff to disk. It then goes on to define the only + ;; possible error return as EBADF (fd isn't a valid open file + ;; descriptor). Presumably this is an oversight and we could also + ;; get anything that write(2) would have given us. + + ;; note that if you have a socket _and_ a stream on the same fd, + ;; the socket will avoid doing anything to close the fd in case + ;; the stream has done it already - if so, it may have been + ;; reassigned to some other file, and closing it would be bad + (let ((fd (socket-file-descriptor socket))) + (flet ((drop-it (&optional streamp) + (setf (slot-value socket 'file-descriptor) -1) + (if streamp + (slot-makunbound socket 'stream) + (sb-ext:cancel-finalization socket)) + t)) + (cond ((eql fd -1) + ;; already closed + nil) + ((slot-boundp socket 'stream) + (close (slot-value socket 'stream) :abort abort) + ;; Don't do this if there was an error from CLOSE -- the stream is + ;; still live. + (drop-it t)) + (t + (handler-case + (socket-error-case ("close" (sockint::close fd) + result (minusp result))) + (bad-file-descriptor-error () + (drop-it)) + (:no-error (r) + (declare (ignore r)) + (drop-it)))))))) diff --git a/contrib/sb-bsd-sockets/sockopt.lisp b/contrib/sb-bsd-sockets/sockopt.lisp index a9c1a2736d..f7d54fda41 100644 --- a/contrib/sb-bsd-sockets/sockopt.lisp +++ b/contrib/sb-bsd-sockets/sockopt.lisp @@ -62,8 +62,7 @@ Code for options that not every system has should be conditionalised: (sockint::getsockopt (socket-file-descriptor socket) ,find-level ,number (sb-alien:addr buffer) - #+win32 size - #-win32 (sb-alien:addr size))) + (sb-alien:addr size))) (,mangle-return buffer size)))) `((declare (ignore socket)) (unsupported-socket-option ',lisp-name)))) diff --git a/contrib/sb-bsd-sockets/tests.lisp b/contrib/sb-bsd-sockets/tests.lisp index f24535273b..c2b2eb5084 100644 --- a/contrib/sb-bsd-sockets/tests.lisp +++ b/contrib/sb-bsd-sockets/tests.lisp @@ -1,14 +1,9 @@ (defpackage "SB-BSD-SOCKETS-TEST" - (:use "CL" "SB-BSD-SOCKETS" "SB-RT")) + (:import-from #:test-util #:deftest) + (:use "CL" "SB-BSD-SOCKETS")) (in-package :sb-bsd-sockets-test) -(defmacro deftest* ((name &key fails-on) form &rest results) - `(progn - (when (sb-impl::featurep ',fails-on) - (pushnew ',name sb-rt::*expected-failures*)) - (deftest ,name ,form ,@results))) - ;;; a real address (deftest make-inet-address (equalp (make-inet-address "127.0.0.1") #(127 0 0 1)) @@ -18,13 +13,11 @@ (equalp (make-inet-address "242.1.211.3") #(242 1 211 3)) t) -#-win32 (deftest make-inet6-address.1 (equalp (make-inet6-address "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff") #(255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255)) t) -#-win32 (deftest unparse-inet6-address (string= (sb-bsd-sockets::unparse-inet6-address (make-inet6-address "fe80::abcd:1234")) @@ -52,12 +45,14 @@ nil)) t) -(when (handler-case (make-instance 'inet-socket - :type :stream - :protocol (get-protocol-by-name "tcp")) - (error nil) - (:no-error (x) x)) - (push :ipv4-support *features*)) +(eval-when (:compile-toplevel :execute) + (when (handler-case (make-instance 'inet-socket + :type :stream + :protocol (get-protocol-by-name "tcp")) + (error nil) + (:no-error (x) x)) + (format t "~&Will test IPv4~%") + (push :ipv4-support *features*))) #+ipv4-support (deftest make-inet-socket.smoke @@ -74,7 +69,7 @@ t) #+ipv4-support -(deftest* (make-inet-socket-wrong) +(deftest make-inet-socket-wrong ;; fail to make a socket: check correct error return. There's no nice ;; way to check the condition stuff on its own, which is a shame (handler-case @@ -92,7 +87,7 @@ t) #+ipv4-support -(deftest* (make-inet-socket-keyword-wrong) +(deftest make-inet-socket-keyword-wrong ;; same again with keywords (handler-case (make-instance 'inet-socket :type :stream :protocol :udp) @@ -109,7 +104,6 @@ (:no-error nil)) t) -#-win32 (deftest make-inet6-socket.smoke (handler-case (let ((s (make-instance 'inet6-socket :type :stream :protocol (get-protocol-by-name "tcp")))) @@ -117,7 +111,6 @@ ((or address-family-not-supported protocol-not-supported-error) () t)) t) -#-win32 (deftest make-inet6-socket.keyword (handler-case (let ((s (make-instance 'inet6-socket :type :stream :protocol :tcp))) @@ -126,7 +119,7 @@ t) #+ipv4-support -(deftest* (non-block-socket) +(deftest non-block-socket (let ((s (make-instance 'inet-socket :type :stream :protocol :tcp))) (setf (non-blocking-mode s) t) (non-blocking-mode s)) @@ -153,7 +146,6 @@ (socket-close s2))) t) -#-win32 (deftest inet6-socket-bind (handler-case (let* ((tcp (get-protocol-by-name "tcp")) @@ -183,7 +175,7 @@ t) #+ipv4-support -(deftest* (simple-sockopt-test) +(deftest simple-sockopt-test ;; test we can set SO_REUSEADDR on a socket and retrieve it, and in ;; the process that all the weird macros in sockopt happened right. (let ((s (make-instance 'inet-socket :type :stream :protocol (get-protocol-by-name "tcp")))) @@ -354,6 +346,35 @@ (network-unreachable-error () 'network-unreachable)) t) +#+(and ipv4-support sb-thread) +(deftest sockopt-close-wait-listen-eof + (let ((listen-sock (make-instance 'inet-socket :type :stream :protocol :tcp)) + (client-sock (make-instance 'inet-socket :type :stream :protocol :tcp)) + server-sock + port) + (unwind-protect + (progn + (socket-bind listen-sock #(127 0 0 1) 0) + (setf port (nth-value 1 (socket-name listen-sock))) + (socket-listen listen-sock 1) + + (let ((client-connect-thread + (sb-thread:make-thread + (lambda () + (socket-connect client-sock #(127 0 0 1) port) + (socket-close client-sock))))) + (sb-thread:join-thread client-connect-thread :timeout 20) + (setf server-sock (socket-accept listen-sock))) + + ;; Wait for input. This should return when we get EOF + ;; from the client. It should /not/ hang. + (sb-sys:wait-until-fd-usable (socket-file-descriptor server-sock) :input) + (listen (socket-make-stream server-sock :input t))) + (socket-close listen-sock) + (socket-close client-sock) + (and server-sock (socket-close server-sock)))) + nil) + #+ipv4-support (deftest socket-open-p-true.1 (socket-open-p (make-instance 'inet-socket :type :stream :protocol :tcp)) @@ -396,7 +417,8 @@ #+(and ipv4-support sb-thread) (deftest interrupt-io - (let (result) + (let (result + (sem (sb-thread:make-semaphore))) (labels ((client (port) (setf result @@ -411,11 +433,8 @@ (handler-case (prog1 (catch 'stop - (progn - (read-char stream) - (sleep 0.1) - (sleep 0.1) - (sleep 0.1))) + (sb-thread:signal-semaphore sem) + (read-char stream)) (close stream)) (error (c) c)))))) @@ -434,17 +453,18 @@ (stream (socket-make-stream r :input t :output t - :buffering :none)) - (ok :ok)) + :buffering :none))) (socket-close s) - (sleep 5) + (sb-thread:wait-on-semaphore sem) + (sleep 0.1) (sb-thread:interrupt-thread client - (lambda () (throw 'stop ok))) - (sleep 5) - (setf ok :not-ok) + (lambda () (throw 'stop :ok))) + (unless (sb-ext:wait-for (null (sb-thread::thread-interruptions client)) :timeout 5) + (setf result :timeout)) (write-char #\x stream) (close stream) - (socket-close r)))))) + (socket-close r) + (sb-thread:join-thread client :timeout 5)))))) (server)) result) :ok) diff --git a/contrib/sb-bsd-sockets/win32-constants.lisp b/contrib/sb-bsd-sockets/win32-constants.lisp deleted file mode 100644 index 8fcfa1fa8e..0000000000 --- a/contrib/sb-bsd-sockets/win32-constants.lisp +++ /dev/null @@ -1,232 +0,0 @@ -;;; -*- Lisp -*- - -;;; This isn't really lisp, but it's definitely a source file. we -;;; name it thus to avoid having to mess with the clc lpn translations - -;;; first, the headers necessary to find definitions of everything -("winsock2.h" "errno.h") - -;;; then the stuff we're looking for -((:integer af-inet "AF_INET" "IP Protocol family") - (:integer af-unspec "AF_UNSPEC" "Unspecified") - (:integer sock-stream "SOCK_STREAM" - "Sequenced, reliable, connection-based byte streams.") - (:integer sock-dgram "SOCK_DGRAM" - "Connectionless, unreliable datagrams of fixed maximum length.") - (:integer sock-raw "SOCK_RAW" - "Raw protocol interface.") - (:integer sock-rdm "SOCK_RDM" - "Reliably-delivered messages.") - (:integer sock-seqpacket "SOCK_SEQPACKET" - "Sequenced, reliable, connection-based, datagrams of fixed maximum length.") - - (:integer sol-socket "SOL_SOCKET") - - ;; some of these may be linux-specific - (:integer so-debug "SO_DEBUG" - "Enable debugging in underlying protocol modules") - (:integer so-reuseaddr "SO_REUSEADDR" "Enable local address reuse") - (:integer so-type "SO_TYPE") ;get only - (:integer so-error "SO_ERROR") ;get only (also clears) - (:integer so-dontroute "SO_DONTROUTE" - "Bypass routing facilities: instead send direct to appropriate network interface for the network portion of the destination address") - (:integer so-broadcast "SO_BROADCAST" "Request permission to send broadcast datagrams") - (:integer so-sndbuf "SO_SNDBUF") - (:integer so-rcvbuf "SO_RCVBUF") - (:integer so-keepalive "SO_KEEPALIVE" - "Send periodic keepalives: if peer does not respond, we get SIGPIPE") - (:integer so-oobinline "SO_OOBINLINE" - "Put out-of-band data into the normal input queue when received") - (:integer so-linger "SO_LINGER" - "For reliable streams, pause a while on closing when unsent messages are queued") - (:integer so-sndlowat "SO_SNDLOWAT") - (:integer so-rcvlowat "SO_RCVLOWAT") - (:integer so-sndtimeo "SO_SNDTIMEO") - (:integer so-rcvtimeo "SO_RCVTIMEO") - - (:integer tcp-nodelay "TCP_NODELAY") - - (:integer msg-oob "MSG_OOB") - (:integer msg-peek "MSG_PEEK") - (:integer msg-dontroute "MSG_DONTROUTE") - - ;; socket shutdown flags - (:integer SHUT_RD "SD_RECEIVE") - (:integer SHUT_WR "SD_SEND") - (:integer SHUT_RDWR "SD_BOTH") - - ;; errors - (:integer EADDRINUSE "WSAEADDRINUSE") - (:integer EAGAIN "WSAEWOULDBLOCK") - (:integer EBADF "WSAEBADF") - (:integer ECONNREFUSED "WSAECONNREFUSED") - (:integer ETIMEDOUT "WSAETIMEDOUT") - (:integer EINTR "WSAEINTR") - (:integer EINVAL "WSAEINVAL") - (:integer ENOBUFS "WSAENOBUFS") - (:integer ENOMEM "WSAENOBUFS") - (:integer EOPNOTSUPP "WSAEOPNOTSUPP") - (:integer EPERM "WSAENETDOWN") - (:integer EPROTONOSUPPORT "WSAEPROTONOSUPPORT") - (:integer ESOCKTNOSUPPORT "WSAESOCKTNOSUPPORT") - (:integer ENETUNREACH "WSAENETUNREACH") - (:integer ENOTCONN "WSAENOTCONN") - (:integer EAFNOSUPPORT "EAFNOSUPPORT") - (:integer EINPROGRESS "EINPROGRESS") - - (:integer inaddr-any "INADDR_ANY") - (:integer FIONBIO "FIONBIO") - - - ;; for socket-receive - (:type socklen-t "int") - - (:structure in-addr ("struct in_addr" - ((array (unsigned 8)) addr "u_int32_t" "s_addr"))) - - (:structure sockaddr-in ("struct sockaddr_in" - (integer family "sa_family_t" "sin_family") - ;; These two could be in-port-t and - ;; in-addr-t, but then we'd throw away the - ;; convenience (and byte-order agnosticism) - ;; of the old sb-grovel scheme. - ((array (unsigned 8)) port "u_int16_t" "sin_port") - ((array (unsigned 8)) addr "struct in_addr" "sin_addr"))) - - (:structure hostent ("struct hostent" - (c-string-pointer name "char *" "h_name") - ((* c-string) aliases "char **" "h_aliases") - (integer type "int" "h_addrtype") - (integer length "int" "h_length") - ((* (* (unsigned 8))) addresses "char **" "h_addr_list"))) - - (:structure protoent ("struct protoent" - (c-string-pointer name "char *" "p_name") - ((* (* t)) aliases "char **" "p_aliases") - (integer proto "int" "p_proto"))) - - (:function getprotobyname ("getprotobyname" (* protoent) - (name c-string))) - - (:function getprotobynumber ("getprotobynumber" (* protoent) - (proto int))) - - ;; FIXME: We should probably grovel the windows SOCKET type and use it in - ;; these instead of int... - - (:function bind ("bind" int - (sockfd int) - (my-addr (* t)) ; KLUDGE: sockaddr-in or sockaddr-un? - (addrlen socklen-t))) - - (:function listen ("listen" int - (socket int) - (backlog int))) - - (:function accept ("accept" int - (socket int) - (my-addr (* t)) ; KLUDGE: sockaddr-in or sockaddr-un? - (addrlen int :in-out))) - - (:function getpeername ("getpeername" int - (socket int) - (her-addr (* t)) ; KLUDGE: sockaddr-in or sockaddr-un? - (addrlen socklen-t :in-out))) - - (:function getsockname ("getsockname" int - (socket int) - (my-addr (* t)) ; KLUDGE: sockaddr-in or sockaddr-un? - (addrlen socklen-t :in-out))) - - (:function connect ("connect" int - (socket int) - (his-addr (* t)) ; KLUDGE: sockaddr-in or sockaddr-un? - (addrlen socklen-t))) - - (:function close ("closesocket" int - (fd int))) - - (:function shutdown ("shutdown" int - (socket int) ; KLUDGE: should be SOCKET, not int. - (how int))) - - (:function recvfrom ("recvfrom" int - (socket int) - (buf (* t)) - (len integer) - (flags int) - (sockaddr (* t)) ; KLUDGE: sockaddr-in or sockaddr-un? - (socklen (* socklen-t)))) - - (:function recv ("recv" int - (socket int) - (buf (* t)) - (len integer) - (flags integer))) - - (:function send ("send" int - (socket int) - (buf (* t)) - (len int) - (flags int))) - - (:function sendto ("sendto" int - (socket int) - (buf (* t)) - (len int) - (flags int) - (sockaddr (* t)) ; KLUDGE: sockaddr-in or sockaddr-un? - (socklen socklen-t))) - -;;; FIXME should be using getaddrinfo instead? - - (:function setsockopt ("setsockopt" int - (socket int) - (level int) - (optname int) - (optval (* t)) - (optlen int))) ;;; should be socklen-t! - - (:function getsockopt ("getsockopt" int - (socket int) - (level int) - (optname int) - (optval (* t)) - (optlen int :in-out))) ;;; should be socklen-t! - - (:function ioctl ("ioctlsocket" int - (socket int) - (cmd int) - (argp (unsigned 32) :in-out))) - - -;;; Win32 specific cruft - (:function wsa-socket ("WSASocketA" int - (af int) - (type int) - (protocol int) - (lpProtocolInfo (* t)) - (g int) - (flags int))) - - (:structure wsa-data ("struct WSAData" - (integer version "u_int16_t" "wVersion") - (integer high-version "u_int16_t" "wHighVersion") - (c-string description "char" "szDescription") - (c-string system-status "char" "szSystemStatus") - (integer max-sockets "unsigned short" "iMaxSockets") - (integer max-udp-dg "unsigned short" "iMaxUdpDg") - (c-string-pointer vendor-info "char *" "lpVendorInfo"))) - - (:function wsa-startup ("WSAStartup" int - (wVersionRequested (unsigned 16)) - (lpWSAData wsa-data :out))) - - (:function wsa-get-last-error ("WSAGetLastError" int)) - (:integer IPPROTO_IP "IPPROTO_IP") - (:integer IPPROTO_IPV6 "IPPROTO_IPV6") - (:integer IPPROTO_ICMP "IPPROTO_ICMP") - (:integer IPPROTO_IGMP "IPPROTO_IGMP") - (:integer IPPROTO_TCP "IPPROTO_TCP") - (:integer IPPROTO_UDP "IPPROTO_UDP") - (:integer IPPROTO_RAW "IPPROTO_RAW")) diff --git a/contrib/sb-bsd-sockets/win32-lib.lisp b/contrib/sb-bsd-sockets/win32-lib.lisp index 41aedeca36..c5c47563d8 100644 --- a/contrib/sb-bsd-sockets/win32-lib.lisp +++ b/contrib/sb-bsd-sockets/win32-lib.lisp @@ -1,3 +1,2 @@ -(eval-when (:compile-toplevel :load-toplevel :execute) - (sb-alien:load-shared-object "ws2_32.dll") - (sb-alien:load-shared-object "msvcrt.dll")) +(sb-alien:load-shared-object "ws2_32.dll") +(sb-alien:load-shared-object "msvcrt.dll") diff --git a/contrib/sb-capstone/capstone.lisp b/contrib/sb-capstone/capstone.lisp index d6dbda80f7..f41f60dff4 100644 --- a/contrib/sb-capstone/capstone.lisp +++ b/contrib/sb-capstone/capstone.lisp @@ -285,7 +285,7 @@ (define-alien-type cs-insn (struct nil (insn-id int) - (insn-addr unsigned) + (insn-addr (unsigned 64)) (insn-size short) (insn-bytes (array char 16)) (insn-mnemonic (array char 32)) @@ -310,9 +310,9 @@ ;; The handle returned by cs-open will be represented as being of type unsigned -(define-alien-routine cs-open int (arch int) (mode (integer 64)) (handle unsigned :out)) +(define-alien-routine cs-open int (arch int) (mode unsigned-int) (handle unsigned :out)) -(define-alien-routine cs-version unsigned (major int :out) (minor int :out)) +(define-alien-routine cs-version unsigned-int (major int :out) (minor int :out)) (define-alien-routine cs-close int (handle unsigned :in-out)) diff --git a/contrib/sb-capstone/sb-capstone.asd b/contrib/sb-capstone/sb-capstone.asd index adf9479035..c10c0c3e06 100644 --- a/contrib/sb-capstone/sb-capstone.asd +++ b/contrib/sb-capstone/sb-capstone.asd @@ -7,16 +7,4 @@ :description "Multi-target disassembly for SBCL using Capstone library" :serial t :components ((:file "capstone")) - :perform (load-op :after (o c) (provide 'sb-capstone)) - :in-order-to ((test-op (test-op "sb-capstone/tests")))) - -(defsystem "sb-capstone/tests" - :depends-on ("sb-capstone" "sb-rt") - :version "0.1" - :components ((:file "tests"))) - -(defmethod perform ((o test-op) (c (eql (find-system "sb-capstone/tests")))) - (if (member :sb-capstone *features*) - (or (funcall (intern "DO-TESTS" (find-package "SB-RT"))) - (error "test-op failed")) - (warn "Could not test sb-capstone"))) + :perform (load-op :after (o c) (provide 'sb-capstone))) diff --git a/contrib/sb-capstone/tests.lisp b/contrib/sb-capstone/tests.lisp index aebab57d66..5ded75dcee 100644 --- a/contrib/sb-capstone/tests.lisp +++ b/contrib/sb-capstone/tests.lisp @@ -58,6 +58,10 @@ (every #'(lambda (instruction) (search instruction instructions)) instructions-to-check)))))) +#| +;;; Someone needs to fix these. +;;; See https://groups.google.com/g/sbcl-help-archive/c/FxDjTHaPnik/m/mIFJTe9-AQAJ + (deftest x86-64 (capstone-check '(#x8F #x45 #x08 #x48 #x8B #xF0) '(:x86-64 :little-endian) '("MOV RSI, RAX" @@ -75,3 +79,4 @@ '(:ppc64 :big-endian) '("MFLR R0")) t) +|# diff --git a/contrib/sb-cltl2/compiler-let.lisp b/contrib/sb-cltl2/compiler-let.lisp index 4d7f76f444..9241a2f6ba 100644 --- a/contrib/sb-cltl2/compiler-let.lisp +++ b/contrib/sb-cltl2/compiler-let.lisp @@ -51,7 +51,7 @@ #+sb-fasteval (sb-interpreter::defspecial compiler-let (bindings &body body) :deferred (env) - (funcall (info :function :interpreter 'let) + (funcall (car (sb-interpreter::special-form-handler 'let)) `(,bindings (declare (special ,@(mapcar (lambda (binding) diff --git a/contrib/sb-cltl2/defpackage.lisp b/contrib/sb-cltl2/defpackage.lisp index 765e79472c..baac62c98b 100644 --- a/contrib/sb-cltl2/defpackage.lisp +++ b/contrib/sb-cltl2/defpackage.lisp @@ -1,5 +1,6 @@ (defpackage :sb-cltl2 (:use :cl :sb-c :sb-int :sb-kernel) + (:import-from #:sb-walker #:macroexpand-all) (:export #:compiler-let #:macroexpand-all ;; environment access diff --git a/contrib/sb-cltl2/env.lisp b/contrib/sb-cltl2/env.lisp index 693142c374..1dd2211ad6 100644 --- a/contrib/sb-cltl2/env.lisp +++ b/contrib/sb-cltl2/env.lisp @@ -281,8 +281,10 @@ appear." (:function (setf binding :function localp nil - ftype (when (eq :declared (info :function :where-from name)) - (global-ftype name)) + ftype (if (or (typep (info :function :source-transform name) + '(cons sb-kernel:defstruct-description)) + (eq (info :function :where-from name) :declared)) + (global-ftype name)) inlinep (info :function :inlinep name)))))) (values binding localp @@ -441,7 +443,7 @@ appear." (info :variable :deprecated name)) (extra-pairs :variable name var *lexenv*))))) -;;; Unlike policy-related declarations which the interpeter itself needs +;;; Unlike policy-related declarations which the interpreter itself needs ;;; for correct operation of some macros, muffled conditions are irrelevant, ;;; since warnings are not signaled much, if at all. ;;; This is even more useless than env-package-locks. diff --git a/contrib/sb-cltl2/macroexpand.lisp b/contrib/sb-cltl2/macroexpand.lisp deleted file mode 100644 index 466fc88c1a..0000000000 --- a/contrib/sb-cltl2/macroexpand.lisp +++ /dev/null @@ -1,98 +0,0 @@ -(in-package :sb-cltl2) - -(defun macroexpand-all (form &optional environment) - (let ((sb-walker::*walk-form-expand-macros-p* t)) - (sb-walker:walk-form - form environment - (lambda (subform context env) - (acond ((and (eq context :eval) - (listp subform) - (symbolp (car subform)) - (get (car subform) :partial-macroexpander)) - ;; The partial expander must return T as its second value - ;; if it wants to stop the walk. - (funcall it subform env)) - (t - subform)))))) - -;; Given EXPR, the argument to an invocation of Quasiquote macro, macroexpand -;; evaluable subforms of EXPR using ENV. A subform is evaluable if all -;; preceding occurrences of #\` have been "canceled" by a comma. -;; DEPTH counts the nesting and should not be supplied by external callers. -(defun %quasiquoted-macroexpand-all (expr env &optional (depth 0)) - (flet ((quasiquote-p (x) - (and (listp x) (eq (car x) 'quasiquote) (singleton-p (cdr x)))) - (recurse (x) - (%quasiquoted-macroexpand-all x env depth))) - (if (atom expr) - (cond ((simple-vector-p expr) (map 'vector #'recurse expr)) - ((comma-p expr) - (unquote (if (> depth 1) - (%quasiquoted-macroexpand-all - (comma-expr expr) env (1- depth)) - (macroexpand-all (comma-expr expr) env)) - (comma-kind expr))) - (t expr)) - (if (quasiquote-p expr) - (list 'quasiquote - (%quasiquoted-macroexpand-all (second expr) env (1+ depth))) - (let (result) - (loop - (push (recurse (pop expr)) result) - (when (or (atom expr) (quasiquote-p expr)) - (return (nreconc result (recurse expr)))))))))) - -(setf (get 'quasiquote :partial-macroexpander) - (lambda (form env) - (destructuring-bind (arg) (cdr form) ; sanity-check the shape - (declare (ignore arg)) - (values (%quasiquoted-macroexpand-all form env) t)))) - -#| - -;; Another example that some people might find useful. - -(defun macroexpand-decls+forms (body env) ; a bit of a kludge, but it works - (mapcar (lambda (x) - (if (and (listp x) (eq (car x) 'declare)) - x - (macroexpand-all x env))) - body)) - -(setf (get 'dotimes :partial-macroexpander) - (lambda (form env) - (destructuring-bind ((var count &optional (result nil result-p)) - &body body) (cdr form) - (values `(dotimes (,var ,(macroexpand-all count env) - ,@(if result-p - (list (macroexpand-all result env)))) - ,@(macroexpand-decls+forms body env)) - t)))) - -(macroexpand-all '(macrolet ((hair (x) `(car ,x))) - (dotimes (i (bar)) (foo i (hair baz)) l)))) -=> -(MACROLET ((HAIR (X) - `(CAR ,X))) - (DOTIMES (I (BAR)) (FOO I (CAR BAZ)) L)) - -instead of - -(MACROLET ((HAIR (X) - `(CAR ,X))) - (BLOCK NIL - (LET ((I 0) (#:COUNT699 (BAR))) - (DECLARE (TYPE UNSIGNED-BYTE I) - (TYPE INTEGER #:COUNT699)) - (TAGBODY - (GO #:G701) - #:G700 - (TAGBODY (FOO I (CAR BAZ)) L) - (LET* () - (MULTIPLE-VALUE-BIND (#:NEW702) (1+ I) (PROGN (SETQ I #:NEW702) NIL))) - #:G701 - (IF (>= I #:COUNT699) - NIL - (PROGN (GO #:G700))) - (RETURN-FROM NIL (PROGN NIL)))))) -|# diff --git a/contrib/sb-cltl2/sb-cltl2.asd b/contrib/sb-cltl2/sb-cltl2.asd index 2ebbe5e254..3d3fd4f8c3 100644 --- a/contrib/sb-cltl2/sb-cltl2.asd +++ b/contrib/sb-cltl2/sb-cltl2.asd @@ -8,15 +8,5 @@ #+sb-building-contrib #p"SYS:CONTRIB;SB-CLTL2;" :components ((:file "defpackage") (:file "compiler-let" :depends-on ("defpackage")) - (:file "macroexpand" :depends-on ("defpackage")) (:file "env" :depends-on ("defpackage"))) - :perform (load-op :after (o c) (provide 'sb-cltl2)) - :in-order-to ((test-op (test-op "sb-cltl2/tests")))) - -(defsystem "sb-cltl2/tests" - :depends-on ("sb-rt") - :components ((:file "tests"))) - -(defmethod perform ((o test-op) (c (eql (find-system "sb-cltl2/tests")))) - (or (funcall (find-symbol "DO-TESTS" "SB-RT")) - (error "test-op failed"))) + :perform (load-op :after (o c) (provide 'sb-cltl2))) diff --git a/contrib/sb-cltl2/tests.lisp b/contrib/sb-cltl2/tests.lisp index a57ba39d08..8943aef2e4 100644 --- a/contrib/sb-cltl2/tests.lisp +++ b/contrib/sb-cltl2/tests.lisp @@ -5,16 +5,15 @@ ;;;; absolutely no warranty. See the COPYING and CREDITS files for ;;;; more information. -;; Undo default contribs mufflage so that DECLARATION-INFORMATION tests pass. -sb-ext::(declaim (unmuffle-conditions compiler-note)) +;; These tests pass under sb-interpreter but not sb-eval +#+interpreter (unless (find-package "SB-INTERPRETER") (invoke-restart 'run-tests::skip-file)) (defpackage :sb-cltl2-tests - (:use :sb-cltl2 :cl :sb-rt :sb-ext :sb-kernel :sb-int)) + (:import-from #:test-util #:deftest) + (:use :sb-cltl2 :cl :sb-ext :sb-kernel :sb-int)) (in-package :sb-cltl2-tests) -(rem-all-tests) - (defmacro *x*-value () (declare (special *x*)) *x*) @@ -136,6 +135,16 @@ sb-ext::(declaim (unmuffle-conditions compiler-note)) (equalp (frob (+ x x)) '(+ y y)))) t) +;; MULTIPLE-VALUE-BIND and -SETQ and were failing to macroexpand-all +;; because the walker treated them both as special operators. +(deftest macroexpand-all.mvb + (let ((form '(multiple-value-bind (a b) (something) (use-them a b)))) + (not (equalp form (macroexpand-all form nil)))) + t) +(deftest macroexpand-all.mvs + (let ((form '(multiple-value-setq (a b) (something)))) + (not (equalp form (macroexpand-all form nil)))) + t) ;;;; DECLARATION-INFORMATION (defmacro dinfo (thing &environment env) @@ -441,6 +450,21 @@ sb-ext::(declaim (unmuffle-conditions compiler-note)) t ((ftype function (integer) (values integer &optional))))) +(deftest function-information.ftype-struct-ctor + (fun-info sb-c::make-lvar) + (:function nil + ((ftype function (&optional (or sb-c::node null)) (values sb-c::lvar &optional))))) +(deftest function-information.ftype-struct-accessor + (fun-info (setf sb-c::sset-vector)) + (:function nil + ((ftype function (simple-vector sset) (values simple-vector &optional))))) +(deftest function-information.ftype-struct-predicate + (fun-info sb-c::sset-p) + (:function nil ((ftype function (t) (values boolean &optional))))) +(deftest function-information.ftype-struct-copier + (fun-info sb-c::copy-sset) + (:function nil ((ftype function (sset) (values sset &optional))))) + ;;;;; AUGMENT-ENVIRONMENT (defmacro ct (form &environment env) @@ -518,7 +542,7 @@ sb-ext::(declaim (unmuffle-conditions compiler-note)) (macroexpand '(mac feh) (augment-environment nil - :macro (list (list 'mac #'(lambda (form benv) + :macro (list (list 'mac #'(lambda (form env) (declare (ignore env)) `(quote ,form ,form ,form)))))) (quote (mac feh) (mac feh) (mac feh)) @@ -576,11 +600,11 @@ sb-ext::(declaim (unmuffle-conditions compiler-note)) (declare (ignore ,a ,b)) ,c))) +(define-declaration zaphod (spec env) + (declare (ignore env)) + (values :declare (cons 'zaphod spec))) (deftest define-declaration.declare (progn - (define-declaration zaphod (spec env) - (declare (ignore env)) - (values :declare (cons 'zaphod spec))) (locally (declare (zaphod beblebrox)) (locally (declare (zaphod and ford)) (ct (declaration-information 'zaphod lexenv))))) @@ -589,20 +613,17 @@ sb-ext::(declaim (unmuffle-conditions compiler-note)) (deftest define-declaration.declare2 (progn - (define-declaration zaphod (spec env) - (declare (ignore env)) - (values :declare (cons 'zaphod spec))) (locally (declare (zaphod beblebrox) (special x)) (ct (declaration-information 'zaphod lexenv)))) (zaphod beblebrox)) +(define-declaration vogon (spec env) + (declare (ignore env)) + (values :variable `((,(cadr spec) vogon-key vogon-value)))) (deftest define-declaration.variable (progn - (define-declaration vogon (spec env) - (declare (ignore env)) - (values :variable `((,(cadr spec) vogon-key vogon-value)))) (locally (declare (vogon poetry)) (ct (assoc 'vogon-key @@ -615,9 +636,6 @@ sb-ext::(declaim (unmuffle-conditions compiler-note)) (deftest define-declaration.variable.special (progn - (define-declaration vogon (spec env) - (declare (ignore env)) - (values :variable `((,(cadr spec) vogon-key vogon-value)))) (let (x) (declare (vogon x)) (declare (special x)) @@ -629,9 +647,6 @@ sb-ext::(declaim (unmuffle-conditions compiler-note)) (deftest define-declaration.variable.special2 (progn - (define-declaration vogon (spec env) - (declare (ignore env)) - (values :variable `((,(cadr spec) vogon-key vogon-value)))) (let (x) (declare (special x)) (declare (vogon x)) @@ -643,9 +658,6 @@ sb-ext::(declaim (unmuffle-conditions compiler-note)) (deftest define-declaration.variable.mask (progn - (define-declaration vogon (spec env) - (declare (ignore env)) - (values :variable `((,(cadr spec) vogon-key vogon-value)))) (let (x) (declare (vogon x)) (let (x) @@ -657,9 +669,6 @@ sb-ext::(declaim (unmuffle-conditions compiler-note)) (deftest define-declaration.variable.macromask (progn - (define-declaration vogon (spec env) - (declare (ignore env)) - (values :variable `((,(cadr spec) vogon-key vogon-value)))) (let (x) (declare (vogon x)) (symbol-macrolet ((x 42)) @@ -671,9 +680,6 @@ sb-ext::(declaim (unmuffle-conditions compiler-note)) (deftest define-declaration.variable.macromask2 (progn - (define-declaration vogon (spec env) - (declare (ignore env)) - (values :variable `((,(cadr spec) vogon-key vogon-value)))) (symbol-macrolet ((x 42)) (declare (vogon x)) (list @@ -688,14 +694,15 @@ sb-ext::(declaim (unmuffle-conditions compiler-note)) (third (multiple-value-list (variable-information 'x lexenv)))))))) (nil (vogon-key . vogon-value))) -(deftest define-declaration.variable.mask2 - (progn +(progn (define-declaration vogon-a (spec env) (declare (ignore env)) (values :variable `((,(cadr spec) vogon-key a)))) (define-declaration vogon-b (spec env) (declare (ignore env)) - (values :variable `((,(cadr spec) vogon-key b)))) + (values :variable `((,(cadr spec) vogon-key b))))) +(deftest define-declaration.variable.mask2 + (progn (let (x) (declare (vogon-a x)) (let (x) @@ -722,11 +729,11 @@ sb-ext::(declaim (unmuffle-conditions compiler-note)) +(define-declaration sad (spec env) + (declare (ignore env)) + (values :function `((,(cadr spec) emotional-state sad)))) (deftest define-declaration.function (progn - (define-declaration sad (spec env) - (declare (ignore env)) - (values :function `((,(cadr spec) emotional-state sad)))) (locally (declare (zaphod beblebrox)) (locally (declare (sad robot)) (ct @@ -738,9 +745,6 @@ sb-ext::(declaim (unmuffle-conditions compiler-note)) (deftest define-declaration.function.lexical (progn - (define-declaration sad (spec env) - (declare (ignore env)) - (values :function `((,(cadr spec) emotional-state sad)))) (flet ((robot nil)) (locally (declare (sad robot)) (ct @@ -753,9 +757,6 @@ sb-ext::(declaim (unmuffle-conditions compiler-note)) (deftest define-declaration.function.lexical2 (progn - (define-declaration sad (spec env) - (declare (ignore env)) - (values :function `((,(cadr spec) emotional-state sad)))) (labels ((robot nil)) (declare (sad robot)) (ct @@ -767,9 +768,6 @@ sb-ext::(declaim (unmuffle-conditions compiler-note)) (deftest define-declaration.function.mask (progn - (define-declaration sad (spec env) - (declare (ignore env)) - (values :function `((,(cadr spec) emotional-state sad)))) (labels ((robot nil)) (declare (sad robot)) (labels ((robot nil)) @@ -783,9 +781,6 @@ sb-ext::(declaim (unmuffle-conditions compiler-note)) (deftest define-declaration.function.mask2 (progn - (define-declaration sad (spec env) - (declare (ignore env)) - (values :function `((,(cadr spec) emotional-state sad)))) (locally (declare (sad robot)) (labels ((robot nil)) @@ -796,11 +791,11 @@ sb-ext::(declaim (unmuffle-conditions compiler-note)) lexenv))))))) nil) +(define-declaration happy (spec env) + (declare (ignore env)) + (values :function `((,(cadr spec) emotional-state happy)))) (deftest define-declaration.function2 (progn - (define-declaration happy (spec env) - (declare (ignore env)) - (values :function `((,(cadr spec) emotional-state happy)))) (locally (declare (zaphod beblebrox)) (locally (declare (sad robot)) (locally (declare (happy robot)) diff --git a/contrib/sb-concurrency/sb-concurrency.asd b/contrib/sb-concurrency/sb-concurrency.asd index 185ff6d4e7..b88ccaf9b7 100644 --- a/contrib/sb-concurrency/sb-concurrency.asd +++ b/contrib/sb-concurrency/sb-concurrency.asd @@ -18,38 +18,4 @@ (:file "queue" :depends-on ("package")) (:file "mailbox" :depends-on ("package" "queue")) (:file "gate" :depends-on ("package"))) - :perform (load-op :after (o c) (provide 'sb-concurrency)) - :in-order-to ((test-op (test-op "sb-concurrency/tests")))) - -(defsystem "sb-concurrency/tests" - :depends-on ("sb-concurrency" "sb-rt") - :components - ((:module tests - :components - ((:file "package") - (:file "test-utils" :depends-on ("package")) - (:file "test-frlock" :depends-on ("package" "test-utils")) - (:file "test-queue" :depends-on ("package" "test-utils")) - (:file "test-mailbox" :depends-on ("package" "test-utils")) - (:file "test-gate" :depends-on ("package" "test-utils")))))) - -(defmethod perform ((o test-op) - (c (eql (find-system "sb-concurrency/tests")))) - (multiple-value-bind (soft strict pending) - (funcall (intern "DO-TESTS" (find-package "SB-RT"))) - (declare (ignorable pending)) - (fresh-line) - (unless strict - #+sb-testing-contrib - ;; We create TEST-PASSED from a shell script if tests passed. But - ;; since the shell script only `touch'es it, we can actually create - ;; it ahead of time -- as long as we're certain that tests truly - ;; passed, hence the check for SOFT. - (when soft - (with-open-file (s #p"SYS:CONTRIB;SB-CONCURRENCY;TEST-PASSED" - :direction :output) - (dolist (pend pending) - (format s "Expected failure: ~A~%" pend)))) - (warn "ignoring expected failures in test-op")) - (unless soft - (error "test-op failed with unexpected failures")))) + :perform (load-op :after (o c) (provide 'sb-concurrency))) diff --git a/contrib/sb-concurrency/tests/package.lisp b/contrib/sb-concurrency/tests/package.lisp index 7328fc257e..24f876c9b6 100644 --- a/contrib/sb-concurrency/tests/package.lisp +++ b/contrib/sb-concurrency/tests/package.lisp @@ -2,4 +2,5 @@ (in-package :cl-user) (defpackage :sb-concurrency-test - (:use :cl :sb-thread :sb-concurrency :sb-rt)) + (:import-from #:test-util #:deftest) + (:use :cl :sb-thread :sb-concurrency)) diff --git a/contrib/sb-concurrency/tests/test-frlock.lisp b/contrib/sb-concurrency/tests/test-frlock.lisp index f9dc3ffbf3..479edc9c83 100644 --- a/contrib/sb-concurrency/tests/test-frlock.lisp +++ b/contrib/sb-concurrency/tests/test-frlock.lisp @@ -11,17 +11,12 @@ (in-package :sb-concurrency-test) -(defmacro deftest* ((name &key fails-on) form &rest results) - `(progn - (when (sb-impl::featurep ',fails-on) - (pushnew ',name sb-rt::*expected-failures*)) - (deftest ,name ,form ,@results))) - ;; XXX something like clock_getres(CLOCK_REALTIME, ...) would be better (defvar *minimum-sleep* - #+(or openbsd sunos) 0.01 - #-(or openbsd sunos) 0.0001) + #+(or openbsd netbsd sunos) 0.01 + #-(or openbsd netbsd sunos) 0.0001) +#+sb-thread (defun test-frlocks (&key (reader-count (min (* 12 *cpus*) 200)) (read-count 1000000) (outer-read-pause 0) (inner-read-pause 0) @@ -86,7 +81,7 @@ (values (cdr w-e!) (cdr r-e!)))) #+sb-thread -(deftest* (frlock.1) +(deftest frlock.1 (handler-case (sb-ext:with-timeout 40 (test-frlocks #+win32 :outer-write-pause #+win32 t )) diff --git a/contrib/sb-concurrency/tests/test-gate.lisp b/contrib/sb-concurrency/tests/test-gate.lisp index 5c78884ad3..2bbb0d3f0e 100644 --- a/contrib/sb-concurrency/tests/test-gate.lisp +++ b/contrib/sb-concurrency/tests/test-gate.lisp @@ -36,6 +36,23 @@ :arguments i))) (int-gate (make-gate))) (sleep 1) + ;; Considering that OPEN-GATE = CONDITION-BROADCAST, this action of INTERRUPT-THREAD + ;; with an (OPEN-GATE) call would be expressly forbidden if condition vars were + ;; implemented by native (pthread) primitives. Generally speaking the pthread intrinsics + ;; provide better mutex fairness, and I very much doubt we could use our condition + ;; vars with pthread mutexes. + ;; + ;; Debian docs say: "ASYNC-SIGNAL SAFETY + ;; The condition functions are not async-signal safe, and should not be called from a + ;; signal handler. In particular, calling pthread_cond_signal or pthread_cond_broadcast + ;; from a signal handler may deadlock the calling thread." + ;; https://manpages.debian.org/testing/glibc-doc/pthread_cond_broadcast.3.en.html + ;; + ;; OpenGroup calls out cond_signal but does not say cond_broadcast isn't safe. + ;; I suspect that it means that they both are not safe since they share a doc page: + ;; "It is not safe to use the pthread_cond_signal() function in a signal handler + ;; that is invoked asynchronously." + ;; https://pubs.opengroup.org/onlinepubs/007904975/functions/pthread_cond_broadcast.html (interrupt-thread (car threads) (lambda () (unwind-protect (when (gate-open-p gate) @@ -55,7 +72,6 @@ ;; once the gate is closed. (deftest gate.2 (let* ((gate (make-gate)) - (cont (make-gate)) (marks (make-array (if (> *cpus* 1) 100 50) :initial-element nil)) (threads (loop for i from 0 below (length marks) collect (make-thread (lambda (n) @@ -92,6 +108,7 @@ (block nil (handler-bind ((sb-sys:deadline-timeout #'(lambda (c) + (declare (ignore c)) (return :deadline)))) (sb-sys:with-deadline (:seconds 0.1) (wait-on-gate gate)))))))) diff --git a/contrib/sb-concurrency/tests/test-mailbox.lisp b/contrib/sb-concurrency/tests/test-mailbox.lisp index 14a9dadefb..83b324eb26 100644 --- a/contrib/sb-concurrency/tests/test-mailbox.lisp +++ b/contrib/sb-concurrency/tests/test-mailbox.lisp @@ -215,10 +215,11 @@ ;; receivers (or only senders) are shot ;; dead, there's still one that survives to ;; properly end the test. - (loop repeat 99 - for victim = (nth (random n) threads) + (loop for victim = (nth (random n) threads) + repeat 99 do (kill-thread victim) (sleep (random 0.0001))))) + (declare (ignore errors)) (values ;; We may have killed a receiver before it got to incrementing ;; the counter. diff --git a/contrib/sb-concurrency/tests/test-utils.lisp b/contrib/sb-concurrency/tests/test-utils.lisp index 1afc30d902..57d32ffbfa 100644 --- a/contrib/sb-concurrency/tests/test-utils.lisp +++ b/contrib/sb-concurrency/tests/test-utils.lisp @@ -10,6 +10,7 @@ ;;;; files for more information. (in-package :sb-concurrency-test) +(declaim (sb-ext:muffle-conditions sb-ext:compiler-note)) #+sb-thread (progn diff --git a/contrib/sb-cover/cover.lisp b/contrib/sb-cover/cover.lisp index 24f1a5fbeb..a1000b02cc 100644 --- a/contrib/sb-cover/cover.lisp +++ b/contrib/sb-cover/cover.lisp @@ -20,8 +20,10 @@ (defmacro code-coverage-hashtable () `(car sb-c:*code-coverage-info*)) -;;;; New coverage representation (only for x86-64 as of now). +;;;; New coverage representation. ;;;; One byte per coverage mark is stored in the unboxed constants of the code. +;;;; x86[-64] use a slightly different but not significantly different +;;; representation of the marks from other architectures. (defun %find-coverage-map (code) (declare (type (or sb-kernel:simple-fun sb-kernel:code-component @@ -35,27 +37,30 @@ (sb-kernel:code-component (let ((n (sb-kernel:code-header-words code))) (let ((map (sb-kernel:code-header-ref code (1- n)))) + (when (typep map '(cons (eql sb-c::coverage-map))) + (return-from %find-coverage-map (values (cdr map) code)))) + ;; if code-boxed-words can't be an odd number, try one more slot + #-(or x86 x86-64) + (let ((map (sb-kernel:code-header-ref code (- n 2)))) (when (typep map '(cons (eql sb-c::coverage-map))) (return-from %find-coverage-map (values (cdr map) code)))))))) +#+arm64 +(declaim (ftype (sb-int:sfunction (t) (simple-array (unsigned-byte 8) (*))) code-coverage-marks)) ;;; Coverage marks are in the raw bytes following the jump tables ;;; preceding any other unboxed constants. This way we don't have to store ;;; a pointer to the coverage marks since their location is implicit. (defun code-coverage-marks (code) + #-arm64 (let ((insts (sb-kernel:code-instructions code))) (sb-sys:sap+ insts (ash (sb-kernel:code-jump-table-words code) - sb-vm:word-shift)))) - -;;; Retun just the list of soure paths in CODE that are marked covered. -(defun get-coverage (code) - (multiple-value-bind (map code) (%find-coverage-map code) - (when map - (sb-int:collect ((paths)) - (sb-sys:with-pinned-objects (code) - (let ((sap (code-coverage-marks code))) - (dotimes (i (length map) (paths)) - (unless (zerop (sb-sys:sap-ref-8 sap i)) - (paths (svref map i)))))))))) + sb-vm:word-shift))) + #+arm64 + (let* ((words (sb-kernel:code-header-words code)) + (last (sb-kernel:code-header-ref code (- words 2)))) + (if (vectorp last) + last + (sb-kernel:code-header-ref code (- words 3))))) ;;;; @@ -85,18 +90,55 @@ image." (let ((,var (sb-ext:weak-pointer-value (car cell)))) (if ,var (progn ,@body (setq predecessor cell)) - (rplacd predecessor (cdr cell))))))))) + (rplacd predecessor (cdr cell)))))))) + ;; Using different values here isn't great, but a 1 bit seemed + ;; the natural choice for "marked" which is fine for x86 which can + ;; store any immediate byte. But the architectures which can't + ;; have either a ZERO-TN or NULL-TN, and can store a byte from + ;; that register into the coverage mark. So they expect a 0 + ;; in the low bit and therefore a 1 in the unmarked state. + (empty-mark-word () + #+(or x86-64 x86) 0 + #-(or x86-64 x86) sb-ext:most-positive-word) + (byte-marked-p (byte) + #+(or x86-64 x86) `(/= ,byte 0) + #-(or x86-64 x86) `(/= ,byte #xFF))) + +;;; Retun just the list of soure paths in CODE that are marked covered. +(defun get-coverage (code) + (multiple-value-bind (map code) (%find-coverage-map code) + (when map + (sb-int:collect ((paths)) + #-arm64 + (sb-sys:with-pinned-objects (code) + (let ((sap (code-coverage-marks code))) + (dotimes (i (length map) (paths)) + (when (byte-marked-p (sb-sys:sap-ref-8 sap i)) + (paths (svref map i)))))) + #+arm64 + (let ((marks (code-coverage-marks code))) + (dotimes (i (length map) (paths)) + (when (byte-marked-p (aref marks i)) + (paths (svref map i))))))))) (defun reset-coverage (&optional object) "Reset all coverage data back to the `Not executed` state." (cond (object ; reset only this object - (multiple-value-bind (map code) (%find-coverage-map object) + (multiple-value-bind (map code) + (%find-coverage-map (the sb-kernel:code-component object)) (when map + #-arm64 (sb-sys:with-pinned-objects (code) - (let ((sap (code-coverage-marks code))) - (dotimes (i (ceiling (length map) sb-vm:n-word-bytes)) - (setf (sb-sys:sap-ref-word sap (ash i sb-vm:n-word-bytes)) 0))))))) - (t ; reset everything + (sb-alien:alien-funcall + (sb-alien:extern-alien "memset" + (function sb-alien:void sb-sys:system-area-pointer + sb-alien:int sb-alien:unsigned)) + (code-coverage-marks code) + (logand (empty-mark-word) #xFF) + (length map))) + #+arm64 + (fill (code-coverage-marks code) #xFF)))) + (t ; reset everything (do-instrumented-code (code) (reset-coverage code)) (sb-c:reset-code-coverage)))) @@ -110,7 +152,6 @@ image." ;; NAMESTRING->PATH-TABLES maps a namestring to a hashtable which maps ;; source paths to the legacy coverage record for that path in that file, ;; e.g. (1 4 1) -> ((1 4 1) . SB-C::%CODE-COVERAGE-UNMARKED%) - #+(or x86-64 x86) (let ((namestring->path-tables (make-hash-table :test 'equal)) (coverage-records (code-coverage-hashtable)) (n-marks 0)) @@ -133,10 +174,11 @@ image." (gethash namestring namestring->path-tables) path-lookup-table) (dolist (item legacy-coverage-marks) (setf (gethash (car item) path-lookup-table) item))) + #-arm64 (sb-sys:with-pinned-objects (code) (let ((sap (code-coverage-marks code))) - (dotimes (i (length map)) ; for each recorded mark - (unless (zerop (sb-sys:sap-ref-8 sap i)) + (dotimes (i (length map)) ; for each recorded mark + (when (byte-marked-p (sb-sys:sap-ref-8 sap i)) (incf n-marks) ;; Set the legacy coverage mark for each path it touches (dolist (path (svref map i)) @@ -145,7 +187,16 @@ image." (rplacd found t) #+nil (warn "Missing coverage entry for ~S in ~S" - path namestring)))))))))) + path namestring)))))))) + #+arm64 + (let ((marks (code-coverage-marks code))) + (dotimes (i (length map)) ; for each recorded mark + (when (byte-marked-p (aref marks i)) + (incf n-marks) + (dolist (path (svref map i)) + (let ((found (gethash path path-lookup-table))) + (if found + (rplacd found t))))))))) (values coverage-records n-marks))) ) ; end MACROLET diff --git a/contrib/sb-cover/sb-cover.asd b/contrib/sb-cover/sb-cover.asd index 58efcd0304..14890be38c 100644 --- a/contrib/sb-cover/sb-cover.asd +++ b/contrib/sb-cover/sb-cover.asd @@ -8,11 +8,4 @@ #+sb-building-contrib #p"SYS:CONTRIB;SB-COVER;" :depends-on ("sb-md5") :components ((:file "cover")) - :perform (load-op :after (o c) (provide 'sb-cover)) - :in-order-to ((test-op (test-op "sb-cover/tests")))) - -(defsystem "sb-cover/tests" - #+sb-building-contrib :pathname - #+sb-building-contrib #p"SYS:CONTRIB;SB-COVER;" - :depends-on ("sb-cover" "asdf") - :components ((:file "tests"))) + :perform (load-op :after (o c) (provide 'sb-cover))) diff --git a/contrib/sb-cover/test-data-5.lisp b/contrib/sb-cover/test-data-5.lisp new file mode 100644 index 0000000000..9dd1ccaf39 --- /dev/null +++ b/contrib/sb-cover/test-data-5.lisp @@ -0,0 +1,14 @@ +(declaim (optimize sb-c:store-coverage-data)) + +(defun outer () + (catch 'tag + (inner) + (print "returned from inner"))) + +(defun inner () + (print "inside inner") + (thrower) + (print "after thrower")) + +(defun thrower () + (throw 'tag :good)) diff --git a/contrib/sb-cover/test-data-6.lisp b/contrib/sb-cover/test-data-6.lisp new file mode 100644 index 0000000000..1492809adf --- /dev/null +++ b/contrib/sb-cover/test-data-6.lisp @@ -0,0 +1,8 @@ +(declaim (optimize sb-c:store-coverage-data)) + +(defun nlx-from-flet () + (flet ((foo (x) + (return-from nlx-from-flet x))) + (foo 3) + (print "reached") + (foo 4))) diff --git a/contrib/sb-cover/test-data-branching-forms.lisp b/contrib/sb-cover/test-data-branching-forms.lisp index a519db0c5b..f79d15e15c 100644 --- a/contrib/sb-cover/test-data-branching-forms.lisp +++ b/contrib/sb-cover/test-data-branching-forms.lisp @@ -1,6 +1,6 @@ +;; Total of 14 forms have coverage data (the in-package, defun plus 12 subforms) (in-package sb-cover-test) -;; Total of 13 forms have coverage data (the defun plus 12 subforms) (defun test-branching-forms () ;; The tests forms here need to be a cons to have coverage data ;; instrumentation, but the progn-like clauses should allow for coverage diff --git a/contrib/sb-cover/tests.lisp b/contrib/sb-cover/tests.lisp index eb01a8d1ae..4a813d9d21 100644 --- a/contrib/sb-cover/tests.lisp +++ b/contrib/sb-cover/tests.lisp @@ -1,19 +1,13 @@ -(defpackage sb-cover-test (:use :cl :asdf :uiop)) +(defpackage sb-cover-test (:use :cl)) (in-package sb-cover-test) -(defparameter *source-directory* - (system-source-directory :sb-cover)) -(defparameter *output-directory* - (apply-output-translations *source-directory*)) - -(setf *default-pathname-defaults* (translate-logical-pathname *default-pathname-defaults*)) +(defparameter *source-directory* cl-user::*source-directory*) +(defparameter *output-directory* cl-user::*coverage-report-directory*) (defun compile-load (x) - (flet ((in-dir (dir type) - (translate-logical-pathname (subpathname dir x :type type)))) - (load (compile-file (in-dir *source-directory* "lisp") - :output-file (in-dir *output-directory* "fasl"))))) + (load (compile-file (merge-pathnames (merge-pathnames x ".*lisp") *source-directory*) + :output-file *output-directory*))) (defun report () (handler-case @@ -41,18 +35,19 @@ (catch 'ok (handler-case (sb-cover:report #p"/tmp/foo") - (error () - (throw 'ok nil))) + (error (c) + (when (search "does not designate a directory" (princ-to-string c)) + (throw 'ok nil)))) (error "REPORT with a non-pathname directory did not signal an error.")) (report) -(assert (probe-file (subpathname *output-directory* "cover-index.html"))) +(assert (probe-file (merge-pathnames "cover-index.html" *output-directory*))) -;;; None of the code was executed +;;; Only the top level forms have been executed (assert (zerop (sb-cover::ok-of (getf sb-cover::*counts* :branch)))) (assert (zerop (sb-cover::all-of (getf sb-cover::*counts* :branch)))) -(assert (zerop (sb-cover::ok-of (getf sb-cover::*counts* :expression)))) +(assert (= 2 (sb-cover::ok-of (getf sb-cover::*counts* :expression)))) (assert (plusp (sb-cover::all-of (getf sb-cover::*counts* :expression)))) ;;; Call the function again @@ -116,7 +111,7 @@ (report) ;; Complete expression coverage -(assert (= 13 +(assert (= 14 (sb-cover::ok-of (getf sb-cover::*counts* :expression)) (sb-cover::all-of (getf sb-cover::*counts* :expression)))) @@ -133,6 +128,25 @@ (assert (= (sb-cover::ok-of (getf sb-cover::*counts* :expression)) (sb-cover::all-of (getf sb-cover::*counts* :expression)))) -;; Clean up after the tests -(map nil #'delete-file - (directory (merge-pathnames #p"*.html" *output-directory*))) +;; Make sure we handle non-local exits from function calls correctly. +(sb-cover:clear-coverage) +(compile-load "test-data-5") +(outer) +(report) + +(assert (zerop (sb-cover::ok-of (getf sb-cover::*counts* :branch)))) +(assert (zerop (sb-cover::all-of (getf sb-cover::*counts* :branch)))) +(assert (= 12 (sb-cover::ok-of (getf sb-cover::*counts* :expression)))) +(assert (= 16 (sb-cover::all-of (getf sb-cover::*counts* :expression)))) + +;; And then ensure that non-local exits from local calls are handled +;; correctly as well. +(sb-cover:clear-coverage) +(compile-load "test-data-6") +(nlx-from-flet) +(report) + +(assert (zerop (sb-cover::ok-of (getf sb-cover::*counts* :branch)))) +(assert (zerop (sb-cover::all-of (getf sb-cover::*counts* :branch)))) +(assert (= 7 (sb-cover::ok-of (getf sb-cover::*counts* :expression)))) +(assert (= 11 (sb-cover::all-of (getf sb-cover::*counts* :expression)))) diff --git a/contrib/sb-executable/sb-executable.lisp b/contrib/sb-executable/sb-executable.lisp index 527c8d82d1..a70fda8a0d 100644 --- a/contrib/sb-executable/sb-executable.lisp +++ b/contrib/sb-executable/sb-executable.lisp @@ -60,7 +60,7 @@ exec sbcl --noinform ~{~A ~}--eval \"(with-open-file (i \\\"$0\\\" :element-type (out-name (namestring (translate-logical-pathname output-file))) (prot (elt (multiple-value-list (sb-unix:unix-stat out-name)) 3))) (if prot - (sb-unix::void-syscall ("chmod" c-string int) + (sb-unix:void-syscall ("chmod" c-string int) out-name (logior prot (if (logand prot #o400) #o100) diff --git a/contrib/sb-gmp/gmp.lisp b/contrib/sb-gmp/gmp.lisp index 0ea1989f18..ab20da84a8 100644 --- a/contrib/sb-gmp/gmp.lisp +++ b/contrib/sb-gmp/gmp.lisp @@ -84,6 +84,7 @@ #-(or win32 darwin) '("libgmp.so" "libgmp.so.10" "libgmp.so.3") #+darwin '("libgmp.dylib" "libgmp.10.dylib" "libgmp.3.dylib") #+win32 '("libgmp.dll" "libgmp-10.dll" "libgmp-3.dll")) + (sb-alien::find-foreign-symbol-address "__gmp_version") (warn "GMP not loaded."))) (defvar *gmp-features* nil) @@ -335,13 +336,19 @@ pre-allocated bignum. The allocated bignum-length must be (1+ COUNT)." ;;; Utility macros for GMP mpz variable and result declaration and ;;; incarnation of associated SBCL bignums +(declaim (inline allocate-bignum)) +(defun allocate-bignum (size) + (let ((bignum (%allocate-bignum size))) + (dotimes (i size bignum) + (setf (%bignum-ref bignum i) 0)))) + (defmacro with-mpz-results (pairs &body body) (loop for (gres size) in pairs for res = (gensym "RESULT") collect `(when (> ,size sb-kernel:maximum-bignum-length) (error "Size of result exceeds maxim bignum length")) into checks collect `(,gres (struct gmpint)) into declares - collect `(,res (%allocate-bignum ,size)) + collect `(,res (allocate-bignum ,size)) into resinits collect `(setf (slot ,gres 'mp_alloc) (%bignum-length ,res) (slot ,gres 'mp_size) 0 @@ -400,7 +407,7 @@ pre-allocated bignum. The allocated bignum-length must be (1+ COUNT)." into resinits collect `(when (> ,size (1- sb-kernel:maximum-bignum-length)) (error "Size of result exceeds maxim bignum length")) into checks - collect `(,res (%allocate-bignum (1+ ,size))) + collect `(,res (allocate-bignum (1+ ,size))) into resallocs collect `(setf ,res (if (minusp (slot ,gres 'mp_size)) ; check for negative result (- (gmp-z-to-bignum (slot ,gres 'mp_d) ,res ,size)) @@ -422,6 +429,16 @@ pre-allocated bignum. The allocated bignum-length must be (1+ COUNT)." ,@clears (values ,@results))))))) +(defun mpz->bignum (z) + "Convert a GMP MPZ Z into a Lisp BIGNUM." + (let* ((size (abs (sb-alien:slot z 'mp_size))) + (neg? (minusp (sb-alien:slot z 'mp_size))) + (bigint (allocate-bignum (1+ size)))) + (sb-sys:with-pinned-objects (bigint) + (* (if neg? -1 1) + (gmp-z-to-bignum (slot z 'mp_d) bigint size))))) + + ;;; function definition and foreign function relationships (defmacro defgmpfun (name args &body body) `(progn @@ -760,6 +777,19 @@ pre-allocated bignum. The allocated bignum-length must be (1+ COUNT)." (bignum-data-sap ad)) ,@body)))))) +(defun mpq->rational (q) + "Convert a GMP MPQ into a Lisp RATIONAL." + (sb-kernel:build-ratio (mpz->bignum (slot q 'mp_num)) + (mpz->bignum (slot q 'mp_den)))) + +(declaim (inline __gmpq_init)) +(define-alien-routine __gmpq_init void + (x (* (struct gmprat)))) + +(declaim (inline __gmpq_clear)) +(define-alien-routine __gmpq_clear void + (x (* (struct gmprat)))) + (defmacro defmpqfun (name gmpfun) `(progn (declaim (sb-ext:maybe-inline ,name)) @@ -771,8 +801,8 @@ pre-allocated bignum. The allocated bignum-length must be (1+ COUNT)." (blength (denominator b))) 3))) (with-alien ((r (struct gmprat))) - (let ((num (%allocate-bignum size)) - (den (%allocate-bignum size))) + (let ((num (allocate-bignum size)) + (den (allocate-bignum size))) (sb-sys:with-pinned-objects (num den) (setf (slot (slot r 'mp_num) 'mp_size) 0 (slot (slot r 'mp_num) 'mp_alloc) size @@ -828,13 +858,9 @@ pre-allocated bignum. The allocated bignum-length must be (1+ COUNT)." ;;;; SBCL interface and integration installation (macrolet ((def (name original) - (let ((special (intern (format nil "*~A-FUNCTION*" name)))) - `(progn - (declaim (type function ,special) - (inline ,name)) - (defvar ,special (symbol-function ',original)) - (defun ,name (&rest args) - (apply (load-time-value ,special t) args)))))) + `(progn + (declaim (ftype function ,name)) + (setf (fdefinition ',name) (fdefinition ',original))))) (def orig-mul multiply-bignums) (def orig-truncate bignum-truncate) (def orig-gcd bignum-gcd) @@ -870,7 +896,7 @@ pre-allocated bignum. The allocated bignum-length must be (1+ COUNT)." (mpz-tdiv a b))) (defun gmp-lcm (a b) - (declare (optimize (speed 3) (space 3)) + (declare (optimize (speed 3) (space 3) (sb-c:verify-arg-count 0)) (type integer a b) (inline mpz-lcm)) (if (or (and (typep a 'fixnum) @@ -890,7 +916,7 @@ pre-allocated bignum. The allocated bignum-length must be (1+ COUNT)." ;;; rationals (defun gmp-two-arg-+ (x y) - (declare (optimize (speed 3) (space 3)) + (declare (optimize (speed 3) (space 3) (sb-c:verify-arg-count 0)) (inline mpq-add)) (if (and (or (typep x 'ratio) (typep y 'ratio)) @@ -901,7 +927,7 @@ pre-allocated bignum. The allocated bignum-length must be (1+ COUNT)." (orig-two-arg-+ x y))) (defun gmp-two-arg-- (x y) - (declare (optimize (speed 3) (space 3)) + (declare (optimize (speed 3) (space 3) (sb-c:verify-arg-count 0)) (inline mpq-sub)) (if (and (or (typep x 'ratio) (typep y 'ratio)) @@ -912,7 +938,7 @@ pre-allocated bignum. The allocated bignum-length must be (1+ COUNT)." (orig-two-arg-- x y))) (defun gmp-two-arg-* (x y) - (declare (optimize (speed 3) (space 3)) + (declare (optimize (speed 3) (space 3) (sb-c:verify-arg-count 0)) (inline mpq-mul)) (if (and (or (typep x 'ratio) (typep y 'ratio)) @@ -923,7 +949,7 @@ pre-allocated bignum. The allocated bignum-length must be (1+ COUNT)." (orig-two-arg-* x y))) (defun gmp-two-arg-/ (x y) - (declare (optimize (speed 3) (space 3)) + (declare (optimize (speed 3) (space 3) (sb-c:verify-arg-count 0)) (inline mpq-div)) (if (and (rationalp x) (rationalp y) @@ -934,14 +960,15 @@ pre-allocated bignum. The allocated bignum-length must be (1+ COUNT)." (defun gmp-intexp (base power) (declare (inline mpz-mul-2exp mpz-pow)) - (check-type power (integer #.(1+ most-negative-fixnum) #.most-positive-fixnum)) (cond ((or (and (integerp base) (< (abs power) 1000) (< (blength base) 4)) + (member base '(0 1 -1)) *gmp-disabled*) (orig-intexp base power)) (t + (check-type power (integer #.(1+ most-negative-fixnum) #.most-positive-fixnum)) (cond ((minusp power) (/ (the integer (gmp-intexp base (- power))))) ((eql base 2) @@ -973,8 +1000,7 @@ pre-allocated bignum. The allocated bignum-length must be (1+ COUNT)." (defun uninstall-gmp-funs () (sb-ext:without-package-locks (macrolet ((def (destination source) - `(setf (fdefinition ',destination) - ,(intern (format nil "*~A-FUNCTION*" source))))) + `(setf (fdefinition ',destination) (fdefinition ',source)))) (def multiply-bignums orig-mul) (def bignum-truncate orig-truncate) (def bignum-gcd orig-gcd) diff --git a/contrib/sb-gmp/sb-gmp.asd b/contrib/sb-gmp/sb-gmp.asd index 7e242674a1..ab3ab4c451 100644 --- a/contrib/sb-gmp/sb-gmp.asd +++ b/contrib/sb-gmp/sb-gmp.asd @@ -7,21 +7,5 @@ :description "bignum calculations for SBCL using the GMP library" :serial t :components ((:file "gmp")) - :perform (load-op :after (o c) (provide 'sb-gmp)) - :in-order-to ((test (test-op "sb-gmp/tests")))) + :perform (load-op :after (o c) (provide 'sb-gmp))) -(defsystem "sb-gmp/tests" - :depends-on ("sb-rt" "sb-gmp") - :components ((:file "tests"))) - -(defmethod perform ((o test-op) (c (eql (find-system "sb-gmp/tests")))) - (if (not (member :sb-gmp *features*)) - (warn "unable to test sb-gmp: libgmp unavailable") - (multiple-value-bind (soft strict pending) - (funcall (intern "DO-TESTS" (find-package "SB-RT"))) - (declare (ignorable pending)) - (fresh-line) - (unless strict - (warn "ignoring expected failures in sb-gmp-tests")) - (unless soft - (error "sb-gmp-tests failed with unexpected failures"))))) diff --git a/contrib/sb-gmp/tests.lisp b/contrib/sb-gmp/tests.lisp index 88a4d35ae9..11b28c4c87 100644 --- a/contrib/sb-gmp/tests.lisp +++ b/contrib/sb-gmp/tests.lisp @@ -1,10 +1,13 @@ (defpackage "SB-GMP-TESTS" - (:use "COMMON-LISP" "SB-GMP" "SB-RT")) + (:import-from #:test-util #:deftest) + (:use "COMMON-LISP" "SB-GMP")) (in-package "SB-GMP-TESTS") -(defparameter *state* (make-gmp-rstate)) -(rand-seed *state* 1234) +#+sb-gmp +(progn + (defparameter *state* (make-gmp-rstate)) + (rand-seed *state* 1234)) (defmacro defgenerator (name arguments &body body) `(defun ,name ,arguments @@ -196,6 +199,10 @@ 'mpz-pow -15546163094340153687 11)) +(deftest intexp-1 + (sb-gmp::gmp-intexp 1 (ash 1 127)) + 1) + (deftest remove-1 (multiple-value-list (mpz-remove 28 2)) (7 2)) diff --git a/contrib/sb-graph/Makefile b/contrib/sb-graph/Makefile new file mode 100644 index 0000000000..9cdc69e9bd --- /dev/null +++ b/contrib/sb-graph/Makefile @@ -0,0 +1,2 @@ +SYSTEM=sb-graph +include ../asdf-module.mk diff --git a/contrib/sb-graph/example/testfile.lisp b/contrib/sb-graph/example/testfile.lisp new file mode 100644 index 0000000000..154ca068bd --- /dev/null +++ b/contrib/sb-graph/example/testfile.lisp @@ -0,0 +1,5 @@ +(defun foo (a b) + (+ a b)) + +(defun bar (b c d) + (* (foo b c) d)) diff --git a/contrib/sb-graph/example/trace-1-DEFUNFOO.dot b/contrib/sb-graph/example/trace-1-DEFUNFOO.dot new file mode 100644 index 0000000000..12cb84e510 --- /dev/null +++ b/contrib/sb-graph/example/trace-1-DEFUNFOO.dot @@ -0,0 +1,367 @@ +digraph { +"{0} COMPONENT [NIL]: ''DEFUN FOO''" -> "{1} CBLOCK [3101743450240528196]"[label="head"]; +"{0} COMPONENT [NIL]: ''DEFUN FOO''" -> "{2} CBLOCK [2506100549378885246]"[label="tail"]; +"{1} CBLOCK [3101743450240528196]" -> "{0} COMPONENT [NIL]: ''DEFUN FOO''"[label="component"]; +"{1} CBLOCK [3101743450240528196]" -> "{3} CBLOCK [3432958294353052646]"[label="succ[# 0]"]; +"{1} CBLOCK [3101743450240528196]" -> "{4} CBLOCK [1030293972324225963]"[label="succ[# 1]"]; +"{3} CBLOCK [3432958294353052646]" -> "{0} COMPONENT [NIL]: ''DEFUN FOO''"[label="component"]; +"{3} CBLOCK [3432958294353052646]" -> "{5} CBLOCK [3418937811103477267]"[label="succ[# 0]"]; +"{3} CBLOCK [3432958294353052646]" -> "{4} CBLOCK [1030293972324225963]"[label="pred[# 0]"]; +"{3} CBLOCK [3432958294353052646]" -> "{1} CBLOCK [3101743450240528196]"[label="pred[# 1]"]; +"{3} CBLOCK [3432958294353052646]" -> "{6} BIND [3685440732622309514]"[label="start[ctran: BLOCK-START]"color="blue"]; +"{5} CBLOCK [3418937811103477267]" -> "{0} COMPONENT [NIL]: ''DEFUN FOO''"[label="component"]; +"{5} CBLOCK [3418937811103477267]" -> "{7} CBLOCK [577634977173467407]"[label="succ[# 0]"]; +"{5} CBLOCK [3418937811103477267]" -> "{3} CBLOCK [3432958294353052646]"[label="pred[# 0]"]; +"{5} CBLOCK [3418937811103477267]" -> "{8} ENTRY [1798174669859920552]: +"[label="start[ctran: BLOCK-START]"color="blue"]; +"{7} CBLOCK [577634977173467407]" -> "{0} COMPONENT [NIL]: ''DEFUN FOO''"[label="component"]; +"{7} CBLOCK [577634977173467407]" -> "{2} CBLOCK [2506100549378885246]"[label="succ[# 0]"]; +"{7} CBLOCK [577634977173467407]" -> "{5} CBLOCK [3418937811103477267]"[label="pred[# 0]"]; +"{7} CBLOCK [577634977173467407]" -> "{9} CRETURN [3318805410236664255]: +result-type: #"[label="start[ctran: BLOCK-START]"color="blue"]; +"{2} CBLOCK [2506100549378885246]" -> "{0} COMPONENT [NIL]: ''DEFUN FOO''"[label="component"]; +"{2} CBLOCK [2506100549378885246]" -> "{7} CBLOCK [577634977173467407]"[label="pred[# 0]"]; +"{9} CRETURN [3318805410236664255]: +result-type: #" -> "{A} CLAMBDA [1548640143404685150]: +%debug-name: NIL +source-name: FOO +kind: NIL"[label="lambda"]; +"{9} CRETURN [3318805410236664255]: +result-type: #" -> "{B} LVAR [3332062336230889072]: +%derived-type: NIL +dynamic-extent: NIL"[label="result"]; +"{A} CLAMBDA [1548640143404685150]: +%debug-name: NIL +source-name: FOO +kind: NIL" -> "{A} CLAMBDA [1548640143404685150]: +%debug-name: NIL +source-name: FOO +kind: NIL"[label="home"]; +"{A} CLAMBDA [1548640143404685150]: +%debug-name: NIL +source-name: FOO +kind: NIL" -> "{C} LAMBDA-VAR [427626644569905684]: +arg-info: NIL +flags: 0"[label="vars[# 0]"]; +"{A} CLAMBDA [1548640143404685150]: +%debug-name: NIL +source-name: FOO +kind: NIL" -> "{D} LAMBDA-VAR [2146378094944416105]: +arg-info: NIL +flags: 0"[label="vars[# 1]"]; +"{C} LAMBDA-VAR [427626644569905684]: +arg-info: NIL +flags: 0" -> "{A} CLAMBDA [1548640143404685150]: +%debug-name: NIL +source-name: FOO +kind: NIL"[label="home"]; +"{D} LAMBDA-VAR [2146378094944416105]: +arg-info: NIL +flags: 0" -> "{A} CLAMBDA [1548640143404685150]: +%debug-name: NIL +source-name: FOO +kind: NIL"[label="home"]; +"{B} LVAR [3332062336230889072]: +%derived-type: NIL +dynamic-extent: NIL" -> "{9} CRETURN [3318805410236664255]: +result-type: #"[label="dest"color="brown"]; +"{B} LVAR [3332062336230889072]: +%derived-type: NIL +dynamic-extent: NIL" -> "{E} COMBINATION [4470851417157717636]: +kind: KNOWN +info: #"[label="uses"]; +"{E} COMBINATION [4470851417157717636]: +kind: KNOWN +info: #" -> "{F} LVAR [880522709123618192]: +%derived-type: # +dynamic-extent: NIL"[label="fun"]; +"{E} COMBINATION [4470851417157717636]: +kind: KNOWN +info: #" -> "{10} LVAR [1971775294085688999]: +%derived-type: # +dynamic-extent: NIL"[label="args[# 0]"]; +"{E} COMBINATION [4470851417157717636]: +kind: KNOWN +info: #" -> "{11} LVAR [2437848309170464037]: +%derived-type: # +dynamic-extent: NIL"[label="args[# 1]"]; +"{F} LVAR [880522709123618192]: +%derived-type: # +dynamic-extent: NIL" -> "{E} COMBINATION [4470851417157717636]: +kind: KNOWN +info: #"[label="dest"color="brown"]; +"{F} LVAR [880522709123618192]: +%derived-type: # +dynamic-extent: NIL" -> "{12} REF [2322685304030638494]: +derived-type: #"[label="uses"]; +"{12} REF [2322685304030638494]: +derived-type: #" -> "{13} NOT SUPPORTED YET: + # + :DEFINED-TYPE # + :WHERE-FROM :DECLARED + :KIND :GLOBAL-FUNCTION {1001D90B33}>"[label="leaf"]; +"{12} REF [2322685304030638494]: +derived-type: #" -> "{14} REF [2214161050784690650]: +derived-type: #"[label="next[ctran: INSIDE-BLOCK]"color="blue"]; +"{12} REF [2322685304030638494]: +derived-type: #" -> "{F} LVAR [880522709123618192]: +%derived-type: # +dynamic-extent: NIL"[label="lvar"]; +"{14} REF [2214161050784690650]: +derived-type: #" -> "{C} LAMBDA-VAR [427626644569905684]: +arg-info: NIL +flags: 0"[label="leaf"]; +"{14} REF [2214161050784690650]: +derived-type: #" -> "{15} REF [1478297276934534521]: +derived-type: #"[label="next[ctran: INSIDE-BLOCK]"color="blue"]; +"{14} REF [2214161050784690650]: +derived-type: #" -> "{10} LVAR [1971775294085688999]: +%derived-type: # +dynamic-extent: NIL"[label="lvar"]; +"{15} REF [1478297276934534521]: +derived-type: #" -> "{D} LAMBDA-VAR [2146378094944416105]: +arg-info: NIL +flags: 0"[label="leaf"]; +"{15} REF [1478297276934534521]: +derived-type: #" -> "{E} COMBINATION [4470851417157717636]: +kind: KNOWN +info: #"[label="next[ctran: INSIDE-BLOCK]"color="blue"]; +"{15} REF [1478297276934534521]: +derived-type: #" -> "{11} LVAR [2437848309170464037]: +%derived-type: # +dynamic-extent: NIL"[label="lvar"]; +"{11} LVAR [2437848309170464037]: +%derived-type: # +dynamic-extent: NIL" -> "{E} COMBINATION [4470851417157717636]: +kind: KNOWN +info: #"[label="dest"color="brown"]; +"{11} LVAR [2437848309170464037]: +%derived-type: # +dynamic-extent: NIL" -> "{15} REF [1478297276934534521]: +derived-type: #"[label="uses"]; +"{10} LVAR [1971775294085688999]: +%derived-type: # +dynamic-extent: NIL" -> "{E} COMBINATION [4470851417157717636]: +kind: KNOWN +info: #"[label="dest"color="brown"]; +"{10} LVAR [1971775294085688999]: +%derived-type: # +dynamic-extent: NIL" -> "{14} REF [2214161050784690650]: +derived-type: #"[label="uses"]; +"{8} ENTRY [1798174669859920552]: +" -> "{16} NOT SUPPORTED YET: + # {1001D90A13}>"[label="cleanup"]; +"{8} ENTRY [1798174669859920552]: +" -> "{12} REF [2322685304030638494]: +derived-type: #"[label="next[ctran: INSIDE-BLOCK]"color="blue"]; +"{8} ENTRY [1798174669859920552]: +" -> "{8} ENTRY [1798174669859920552]: +"[label="prev[ctran: BLOCK-START]"color="blue"]; +"{4} CBLOCK [1030293972324225963]" -> "{0} COMPONENT [NIL]: ''DEFUN FOO''"[label="component"]; +"{4} CBLOCK [1030293972324225963]" -> "{3} CBLOCK [3432958294353052646]"[label="succ[# 0]"]; +"{4} CBLOCK [1030293972324225963]" -> "{1} CBLOCK [3101743450240528196]"[label="pred[# 0]"]; +"{4} CBLOCK [1030293972324225963]" -> "{17} BIND [831277122367414297]"[label="start[ctran: BLOCK-START]"color="blue"]; +"{17} BIND [831277122367414297]" -> "{18} CLAMBDA [2262455371626719506]: +%debug-name: (XEP FOO) +source-name: .ANONYMOUS. +kind: EXTERNAL"[label="lambda"]; +"{17} BIND [831277122367414297]" -> "{19} REF [3619795511931107142]: +derived-type: #"[label="next[ctran: INSIDE-BLOCK]"color="green"]; +"{17} BIND [831277122367414297]" -> "{17} BIND [831277122367414297]"[label="prev[ctran: BLOCK-START]"color="red"]; +"{18} CLAMBDA [2262455371626719506]: +%debug-name: (XEP FOO) +source-name: .ANONYMOUS. +kind: EXTERNAL" -> "{18} CLAMBDA [2262455371626719506]: +%debug-name: (XEP FOO) +source-name: .ANONYMOUS. +kind: EXTERNAL"[label="home"]; +"{18} CLAMBDA [2262455371626719506]: +%debug-name: (XEP FOO) +source-name: .ANONYMOUS. +kind: EXTERNAL" -> "{1A} LAMBDA-VAR [1619988245174222653]: +arg-info: NIL +flags: 1"[label="vars[# 0]"]; +"{18} CLAMBDA [2262455371626719506]: +%debug-name: (XEP FOO) +source-name: .ANONYMOUS. +kind: EXTERNAL" -> "{1B} LAMBDA-VAR [1302633028662760541]: +arg-info: NIL +flags: 0"[label="vars[# 1]"]; +"{18} CLAMBDA [2262455371626719506]: +%debug-name: (XEP FOO) +source-name: .ANONYMOUS. +kind: EXTERNAL" -> "{1C} LAMBDA-VAR [4271800902626008186]: +arg-info: NIL +flags: 0"[label="vars[# 2]"]; +"{1A} LAMBDA-VAR [1619988245174222653]: +arg-info: NIL +flags: 1" -> "{18} CLAMBDA [2262455371626719506]: +%debug-name: (XEP FOO) +source-name: .ANONYMOUS. +kind: EXTERNAL"[label="home"]; +"{1B} LAMBDA-VAR [1302633028662760541]: +arg-info: NIL +flags: 0" -> "{18} CLAMBDA [2262455371626719506]: +%debug-name: (XEP FOO) +source-name: .ANONYMOUS. +kind: EXTERNAL"[label="home"]; +"{1C} LAMBDA-VAR [4271800902626008186]: +arg-info: NIL +flags: 0" -> "{18} CLAMBDA [2262455371626719506]: +%debug-name: (XEP FOO) +source-name: .ANONYMOUS. +kind: EXTERNAL"[label="home"]; +"{19} REF [3619795511931107142]: +derived-type: #" -> "{A} CLAMBDA [1548640143404685150]: +%debug-name: NIL +source-name: FOO +kind: NIL"[label="leaf"]; +"{19} REF [3619795511931107142]: +derived-type: #" -> "{1D} REF [255745217795967635]: +derived-type: #"[label="next[ctran: INSIDE-BLOCK]"color="blue"]; +"{19} REF [3619795511931107142]: +derived-type: #" -> "{1E} LVAR [2622378942754528345]: +%derived-type: NIL +dynamic-extent: NIL"[label="lvar"]; +"{1D} REF [255745217795967635]: +derived-type: #" -> "{1B} LAMBDA-VAR [1302633028662760541]: +arg-info: NIL +flags: 0"[label="leaf"]; +"{1D} REF [255745217795967635]: +derived-type: #" -> "{1F} REF [3667387203345186464]: +derived-type: #"[label="next[ctran: INSIDE-BLOCK]"color="blue"]; +"{1D} REF [255745217795967635]: +derived-type: #" -> "{20} LVAR [2092324786633111792]: +%derived-type: # +dynamic-extent: NIL"[label="lvar"]; +"{1F} REF [3667387203345186464]: +derived-type: #" -> "{1C} LAMBDA-VAR [4271800902626008186]: +arg-info: NIL +flags: 0"[label="leaf"]; +"{1F} REF [3667387203345186464]: +derived-type: #" -> "{21} COMBINATION [3204626948301471823]: +kind: LOCAL +info: LOCAL"[label="next[ctran: INSIDE-BLOCK]"color="blue"]; +"{1F} REF [3667387203345186464]: +derived-type: #" -> "{22} LVAR [4442925413727114980]: +%derived-type: # +dynamic-extent: NIL"[label="lvar"]; +"{21} COMBINATION [3204626948301471823]: +kind: LOCAL +info: LOCAL" -> "{1E} LVAR [2622378942754528345]: +%derived-type: NIL +dynamic-extent: NIL"[label="fun"]; +"{21} COMBINATION [3204626948301471823]: +kind: LOCAL +info: LOCAL" -> "{20} LVAR [2092324786633111792]: +%derived-type: # +dynamic-extent: NIL"[label="args[# 0]"]; +"{21} COMBINATION [3204626948301471823]: +kind: LOCAL +info: LOCAL" -> "{22} LVAR [4442925413727114980]: +%derived-type: # +dynamic-extent: NIL"[label="args[# 1]"]; +"{1E} LVAR [2622378942754528345]: +%derived-type: NIL +dynamic-extent: NIL" -> "{21} COMBINATION [3204626948301471823]: +kind: LOCAL +info: LOCAL"[label="dest"color="brown"]; +"{1E} LVAR [2622378942754528345]: +%derived-type: NIL +dynamic-extent: NIL" -> "{19} REF [3619795511931107142]: +derived-type: #"[label="uses"]; +"{20} LVAR [2092324786633111792]: +%derived-type: # +dynamic-extent: NIL" -> "{21} COMBINATION [3204626948301471823]: +kind: LOCAL +info: LOCAL"[label="dest"color="brown"]; +"{20} LVAR [2092324786633111792]: +%derived-type: # +dynamic-extent: NIL" -> "{1D} REF [255745217795967635]: +derived-type: #"[label="uses"]; +"{22} LVAR [4442925413727114980]: +%derived-type: # +dynamic-extent: NIL" -> "{21} COMBINATION [3204626948301471823]: +kind: LOCAL +info: LOCAL"[label="dest"color="brown"]; +"{22} LVAR [4442925413727114980]: +%derived-type: # +dynamic-extent: NIL" -> "{1F} REF [3667387203345186464]: +derived-type: #"[label="uses"]; +"{6} BIND [3685440732622309514]" -> "{A} CLAMBDA [1548640143404685150]: +%debug-name: NIL +source-name: FOO +kind: NIL"[label="lambda"]; +"{6} BIND [3685440732622309514]" -> "{6} BIND [3685440732622309514]"[label="prev[ctran: BLOCK-START]"color="red"]; +} \ No newline at end of file diff --git a/contrib/sb-graph/example/trace-2-toplevelform.dot b/contrib/sb-graph/example/trace-2-toplevelform.dot new file mode 100644 index 0000000000..a3a7bcfa87 --- /dev/null +++ b/contrib/sb-graph/example/trace-2-toplevelform.dot @@ -0,0 +1,128 @@ +digraph { +"{0} COMPONENT [TOPLEVEL]: ''top level form''" -> "{1} CBLOCK [1943264620861609727]"[label="head"]; +"{0} COMPONENT [TOPLEVEL]: ''top level form''" -> "{2} CBLOCK [1731306899775915608]"[label="tail"]; +"{1} CBLOCK [1943264620861609727]" -> "{0} COMPONENT [TOPLEVEL]: ''top level form''"[label="component"]; +"{1} CBLOCK [1943264620861609727]" -> "{3} CBLOCK [3908410932650914907]"[label="succ[# 0]"]; +"{3} CBLOCK [3908410932650914907]" -> "{0} COMPONENT [TOPLEVEL]: ''top level form''"[label="component"]; +"{3} CBLOCK [3908410932650914907]" -> "{2} CBLOCK [1731306899775915608]"[label="succ[# 0]"]; +"{3} CBLOCK [3908410932650914907]" -> "{1} CBLOCK [1943264620861609727]"[label="pred[# 0]"]; +"{3} CBLOCK [3908410932650914907]" -> "{4} BIND [3628153076315219959]"[label="start[ctran: BLOCK-START]"color="blue"]; +"{2} CBLOCK [1731306899775915608]" -> "{0} COMPONENT [TOPLEVEL]: ''top level form''"[label="component"]; +"{2} CBLOCK [1731306899775915608]" -> "{3} CBLOCK [3908410932650914907]"[label="pred[# 0]"]; +"{4} BIND [3628153076315219959]" -> "{5} CLAMBDA [1883614179857431325]: +%debug-name: (TOP-LEVEL-FORM + (%DEFUN 'FOO + (NAMED-LAMBDA FOO + (A B) + (DECLARE (TOP-LEVEL-FORM)) + (BLOCK FOO (+ A B))))) +source-name: .ANONYMOUS. +kind: TOPLEVEL"[label="lambda"]; +"{4} BIND [3628153076315219959]" -> "{6} REF [1814276436352168607]: +derived-type: #"[label="next[ctran: INSIDE-BLOCK]"color="green"]; +"{4} BIND [3628153076315219959]" -> "{4} BIND [3628153076315219959]"[label="prev[ctran: BLOCK-START]"color="red"]; +"{5} CLAMBDA [1883614179857431325]: +%debug-name: (TOP-LEVEL-FORM + (%DEFUN 'FOO + (NAMED-LAMBDA FOO + (A B) + (DECLARE (TOP-LEVEL-FORM)) + (BLOCK FOO (+ A B))))) +source-name: .ANONYMOUS. +kind: TOPLEVEL" -> "{5} CLAMBDA [1883614179857431325]: +%debug-name: (TOP-LEVEL-FORM + (%DEFUN 'FOO + (NAMED-LAMBDA FOO + (A B) + (DECLARE (TOP-LEVEL-FORM)) + (BLOCK FOO (+ A B))))) +source-name: .ANONYMOUS. +kind: TOPLEVEL"[label="home"]; +"{6} REF [1814276436352168607]: +derived-type: #" -> "{7} NOT SUPPORTED YET: + # + :DEFINED-TYPE # + :WHERE-FROM :DEFINED + :KIND :GLOBAL-FUNCTION {1001D6DA43}>"[label="leaf"]; +"{6} REF [1814276436352168607]: +derived-type: #" -> "{8} REF [3898086476392545619]: +derived-type: #"[label="next[ctran: INSIDE-BLOCK]"color="blue"]; +"{6} REF [1814276436352168607]: +derived-type: #" -> "{9} LVAR [4022411708127746323]: +%derived-type: # +dynamic-extent: NIL"[label="lvar"]; +"{8} REF [3898086476392545619]: +derived-type: #" -> "{A} CONSTANT [405874115581245099]: +value: FOO"[label="leaf"]; +"{8} REF [3898086476392545619]: +derived-type: #" -> "{B} NOT SUPPORTED YET: + # + :WHERE-FROM :DEFINED + :VARS (A B) {1001D90353}>) {1001D96AE3}>"[label="next[ctran: INSIDE-BLOCK]"color="blue"]; +"{8} REF [3898086476392545619]: +derived-type: #" -> "{C} LVAR [1186859114169146565]: +%derived-type: # +dynamic-extent: NIL"[label="lvar"]; +"{C} LVAR [1186859114169146565]: +%derived-type: # +dynamic-extent: NIL" -> "{D} COMBINATION [1475360876084922324]: +kind: FULL +info: FULL"[label="dest"color="brown"]; +"{C} LVAR [1186859114169146565]: +%derived-type: # +dynamic-extent: NIL" -> "{8} REF [3898086476392545619]: +derived-type: #"[label="uses"]; +"{D} COMBINATION [1475360876084922324]: +kind: FULL +info: FULL" -> "{9} LVAR [4022411708127746323]: +%derived-type: # +dynamic-extent: NIL"[label="fun"]; +"{D} COMBINATION [1475360876084922324]: +kind: FULL +info: FULL" -> "{C} LVAR [1186859114169146565]: +%derived-type: # +dynamic-extent: NIL"[label="args[# 0]"]; +"{D} COMBINATION [1475360876084922324]: +kind: FULL +info: FULL" -> "{E} LVAR [3728149842014737266]: +%derived-type: # +dynamic-extent: NIL"[label="args[# 1]"]; +"{9} LVAR [4022411708127746323]: +%derived-type: # +dynamic-extent: NIL" -> "{D} COMBINATION [1475360876084922324]: +kind: FULL +info: FULL"[label="dest"color="brown"]; +"{9} LVAR [4022411708127746323]: +%derived-type: # +dynamic-extent: NIL" -> "{6} REF [1814276436352168607]: +derived-type: #"[label="uses"]; +"{E} LVAR [3728149842014737266]: +%derived-type: # +dynamic-extent: NIL" -> "{D} COMBINATION [1475360876084922324]: +kind: FULL +info: FULL"[label="dest"color="brown"]; +"{E} LVAR [3728149842014737266]: +%derived-type: # +dynamic-extent: NIL" -> "{F} REF [4127949218090209127]: +derived-type: #"[label="uses"]; +"{F} REF [4127949218090209127]: +derived-type: #" -> "{10} NOT SUPPORTED YET: + #"[label="leaf"]; +"{F} REF [4127949218090209127]: +derived-type: #" -> "{D} COMBINATION [1475360876084922324]: +kind: FULL +info: FULL"[label="next[ctran: INSIDE-BLOCK]"color="blue"]; +"{F} REF [4127949218090209127]: +derived-type: #" -> "{E} LVAR [3728149842014737266]: +%derived-type: # +dynamic-extent: NIL"[label="lvar"]; +} \ No newline at end of file diff --git a/contrib/sb-graph/example/trace-3-DEFUNBAR.dot b/contrib/sb-graph/example/trace-3-DEFUNBAR.dot new file mode 100644 index 0000000000..d9b87e6270 --- /dev/null +++ b/contrib/sb-graph/example/trace-3-DEFUNBAR.dot @@ -0,0 +1,795 @@ +digraph { +"{0} COMPONENT [NIL]: ''DEFUN BAR''" -> "{1} CBLOCK [1575903357056582106]"[label="head"]; +"{0} COMPONENT [NIL]: ''DEFUN BAR''" -> "{2} CBLOCK [646725814620792949]"[label="tail"]; +"{1} CBLOCK [1575903357056582106]" -> "{0} COMPONENT [NIL]: ''DEFUN BAR''"[label="component"]; +"{1} CBLOCK [1575903357056582106]" -> "{3} CBLOCK [463338187003706333]"[label="succ[# 0]"]; +"{1} CBLOCK [1575903357056582106]" -> "{4} CBLOCK [4485638051092447707]"[label="succ[# 1]"]; +"{3} CBLOCK [463338187003706333]" -> "{0} COMPONENT [NIL]: ''DEFUN BAR''"[label="component"]; +"{3} CBLOCK [463338187003706333]" -> "{5} CBLOCK [4517821492800445034]"[label="succ[# 0]"]; +"{3} CBLOCK [463338187003706333]" -> "{4} CBLOCK [4485638051092447707]"[label="pred[# 0]"]; +"{3} CBLOCK [463338187003706333]" -> "{1} CBLOCK [1575903357056582106]"[label="pred[# 1]"]; +"{3} CBLOCK [463338187003706333]" -> "{6} BIND [2888465489035891844]"[label="start[ctran: BLOCK-START]"color="blue"]; +"{5} CBLOCK [4517821492800445034]" -> "{0} COMPONENT [NIL]: ''DEFUN BAR''"[label="component"]; +"{5} CBLOCK [4517821492800445034]" -> "{7} CBLOCK [560949006574360106]"[label="succ[# 0]"]; +"{5} CBLOCK [4517821492800445034]" -> "{8} CBLOCK [4400914120625574157]"[label="succ[# 1]"]; +"{5} CBLOCK [4517821492800445034]" -> "{3} CBLOCK [463338187003706333]"[label="pred[# 0]"]; +"{5} CBLOCK [4517821492800445034]" -> "{9} ENTRY [3859794357893252955]: +"[label="start[ctran: BLOCK-START]"color="blue"]; +"{7} CBLOCK [560949006574360106]" -> "{0} COMPONENT [NIL]: ''DEFUN BAR''"[label="component"]; +"{7} CBLOCK [560949006574360106]" -> "{2} CBLOCK [646725814620792949]"[label="succ[# 0]"]; +"{7} CBLOCK [560949006574360106]" -> "{5} CBLOCK [4517821492800445034]"[label="pred[# 0]"]; +"{7} CBLOCK [560949006574360106]" -> "{A} REF [970847179709888776]: +derived-type: #"[label="start[ctran: BLOCK-START]"color="blue"]; +"{2} CBLOCK [646725814620792949]" -> "{0} COMPONENT [NIL]: ''DEFUN BAR''"[label="component"]; +"{2} CBLOCK [646725814620792949]" -> "{7} CBLOCK [560949006574360106]"[label="pred[# 0]"]; +"{2} CBLOCK [646725814620792949]" -> "{B} CBLOCK [3753698776976668030]"[label="pred[# 1]"]; +"{B} CBLOCK [3753698776976668030]" -> "{0} COMPONENT [NIL]: ''DEFUN BAR''"[label="component"]; +"{B} CBLOCK [3753698776976668030]" -> "{2} CBLOCK [646725814620792949]"[label="succ[# 0]"]; +"{B} CBLOCK [3753698776976668030]" -> "{8} CBLOCK [4400914120625574157]"[label="pred[# 0]"]; +"{B} CBLOCK [3753698776976668030]" -> "{C} CRETURN [1875721060202815921]: +result-type: #"[label="start[ctran: BLOCK-START]"color="blue"]; +"{8} CBLOCK [4400914120625574157]" -> "{0} COMPONENT [NIL]: ''DEFUN BAR''"[label="component"]; +"{8} CBLOCK [4400914120625574157]" -> "{B} CBLOCK [3753698776976668030]"[label="succ[# 0]"]; +"{8} CBLOCK [4400914120625574157]" -> "{5} CBLOCK [4517821492800445034]"[label="pred[# 0]"]; +"{8} CBLOCK [4400914120625574157]" -> "{D} REF [1142794053290553148]: +derived-type: #"[label="start[ctran: BLOCK-START]"color="blue"]; +"{D} REF [1142794053290553148]: +derived-type: #" -> "{E} CLAMBDA [1583379011298201103]: +%debug-name: (LET ((G5 G4))) +source-name: .ANONYMOUS. +kind: LET"[label="leaf"]; +"{D} REF [1142794053290553148]: +derived-type: #" -> "{F} REF [1091524514451138732]: +derived-type: #"[label="next[ctran: INSIDE-BLOCK]"color="blue"]; +"{D} REF [1142794053290553148]: +derived-type: #" -> "{10} LVAR [1899977882035455531]: +%derived-type: NIL +dynamic-extent: NIL"[label="lvar"]; +"{E} CLAMBDA [1583379011298201103]: +%debug-name: (LET ((G5 G4))) +source-name: .ANONYMOUS. +kind: LET" -> "{11} CLAMBDA [274430610392932488]: +%debug-name: NIL +source-name: BAR +kind: NIL"[label="home"]; +"{E} CLAMBDA [1583379011298201103]: +%debug-name: (LET ((G5 G4))) +source-name: .ANONYMOUS. +kind: LET" -> "{12} LAMBDA-VAR [2194186068469748088]: +arg-info: NIL +flags: 0"[label="vars[# 0]"]; +"{11} CLAMBDA [274430610392932488]: +%debug-name: NIL +source-name: BAR +kind: NIL" -> "{11} CLAMBDA [274430610392932488]: +%debug-name: NIL +source-name: BAR +kind: NIL"[label="home"]; +"{11} CLAMBDA [274430610392932488]: +%debug-name: NIL +source-name: BAR +kind: NIL" -> "{13} LAMBDA-VAR [551267047686253943]: +arg-info: NIL +flags: 0"[label="vars[# 0]"]; +"{11} CLAMBDA [274430610392932488]: +%debug-name: NIL +source-name: BAR +kind: NIL" -> "{14} LAMBDA-VAR [1342701350530444948]: +arg-info: NIL +flags: 0"[label="vars[# 1]"]; +"{11} CLAMBDA [274430610392932488]: +%debug-name: NIL +source-name: BAR +kind: NIL" -> "{15} LAMBDA-VAR [687676610963465975]: +arg-info: NIL +flags: 0"[label="vars[# 2]"]; +"{13} LAMBDA-VAR [551267047686253943]: +arg-info: NIL +flags: 0" -> "{11} CLAMBDA [274430610392932488]: +%debug-name: NIL +source-name: BAR +kind: NIL"[label="home"]; +"{14} LAMBDA-VAR [1342701350530444948]: +arg-info: NIL +flags: 0" -> "{11} CLAMBDA [274430610392932488]: +%debug-name: NIL +source-name: BAR +kind: NIL"[label="home"]; +"{15} LAMBDA-VAR [687676610963465975]: +arg-info: NIL +flags: 0" -> "{11} CLAMBDA [274430610392932488]: +%debug-name: NIL +source-name: BAR +kind: NIL"[label="home"]; +"{12} LAMBDA-VAR [2194186068469748088]: +arg-info: NIL +flags: 0" -> "{E} CLAMBDA [1583379011298201103]: +%debug-name: (LET ((G5 G4))) +source-name: .ANONYMOUS. +kind: LET"[label="home"]; +"{F} REF [1091524514451138732]: +derived-type: #" -> "{16} LAMBDA-VAR [4210063433964233181]: +arg-info: NIL +flags: 0"[label="leaf"]; +"{F} REF [1091524514451138732]: +derived-type: #" -> "{17} COMBINATION [2114537499351968799]: +kind: LOCAL +info: LOCAL"[label="next[ctran: INSIDE-BLOCK]"color="blue"]; +"{F} REF [1091524514451138732]: +derived-type: #" -> "{18} LVAR [1279162088182557763]: +%derived-type: # +dynamic-extent: NIL"[label="lvar"]; +"{16} LAMBDA-VAR [4210063433964233181]: +arg-info: NIL +flags: 0" -> "{19} CLAMBDA [1745095324529044804]: +%debug-name: (LET ((G4 CONSTANT))) +source-name: .ANONYMOUS. +kind: LET"[label="home"]; +"{19} CLAMBDA [1745095324529044804]: +%debug-name: (LET ((G4 CONSTANT))) +source-name: .ANONYMOUS. +kind: LET" -> "{11} CLAMBDA [274430610392932488]: +%debug-name: NIL +source-name: BAR +kind: NIL"[label="home"]; +"{19} CLAMBDA [1745095324529044804]: +%debug-name: (LET ((G4 CONSTANT))) +source-name: .ANONYMOUS. +kind: LET" -> "{16} LAMBDA-VAR [4210063433964233181]: +arg-info: NIL +flags: 0"[label="vars[# 0]"]; +"{17} COMBINATION [2114537499351968799]: +kind: LOCAL +info: LOCAL" -> "{10} LVAR [1899977882035455531]: +%derived-type: NIL +dynamic-extent: NIL"[label="fun"]; +"{17} COMBINATION [2114537499351968799]: +kind: LOCAL +info: LOCAL" -> "{18} LVAR [1279162088182557763]: +%derived-type: # +dynamic-extent: NIL"[label="args[# 0]"]; +"{10} LVAR [1899977882035455531]: +%derived-type: NIL +dynamic-extent: NIL" -> "{17} COMBINATION [2114537499351968799]: +kind: LOCAL +info: LOCAL"[label="dest"color="brown"]; +"{10} LVAR [1899977882035455531]: +%derived-type: NIL +dynamic-extent: NIL" -> "{D} REF [1142794053290553148]: +derived-type: #"[label="uses"]; +"{18} LVAR [1279162088182557763]: +%derived-type: # +dynamic-extent: NIL" -> "{17} COMBINATION [2114537499351968799]: +kind: LOCAL +info: LOCAL"[label="dest"color="brown"]; +"{18} LVAR [1279162088182557763]: +%derived-type: # +dynamic-extent: NIL" -> "{F} REF [1091524514451138732]: +derived-type: #"[label="uses"]; +"{C} CRETURN [1875721060202815921]: +result-type: #" -> "{11} CLAMBDA [274430610392932488]: +%debug-name: NIL +source-name: BAR +kind: NIL"[label="lambda"]; +"{C} CRETURN [1875721060202815921]: +result-type: #" -> "{1A} LVAR [934340460890599439]: +%derived-type: NIL +dynamic-extent: NIL"[label="result"]; +"{1A} LVAR [934340460890599439]: +%derived-type: NIL +dynamic-extent: NIL" -> "{C} CRETURN [1875721060202815921]: +result-type: #"[label="dest"color="brown"]; +"{1A} LVAR [934340460890599439]: +%derived-type: NIL +dynamic-extent: NIL" -> "{1B} COMBINATION [875787350148863859]: +kind: KNOWN +info: #"[label="uses"]; +"{1B} COMBINATION [875787350148863859]: +kind: KNOWN +info: #" -> "{1C} LVAR [880575187628074238]: +%derived-type: # +dynamic-extent: NIL"[label="fun"]; +"{1B} COMBINATION [875787350148863859]: +kind: KNOWN +info: #" -> "{1D} LVAR [2954358970637004122]: +%derived-type: # +dynamic-extent: NIL"[label="args[# 0]"]; +"{1B} COMBINATION [875787350148863859]: +kind: KNOWN +info: #" -> "{1E} LVAR [1183996723568101089]: +%derived-type: # +dynamic-extent: NIL"[label="args[# 1]"]; +"{1C} LVAR [880575187628074238]: +%derived-type: # +dynamic-extent: NIL" -> "{1B} COMBINATION [875787350148863859]: +kind: KNOWN +info: #"[label="dest"color="brown"]; +"{1C} LVAR [880575187628074238]: +%derived-type: # +dynamic-extent: NIL" -> "{1F} REF [1077682984383576289]: +derived-type: #"[label="uses"]; +"{1F} REF [1077682984383576289]: +derived-type: #" -> "{20} NOT SUPPORTED YET: + # + :DEFINED-TYPE # + :WHERE-FROM :DECLARED + :KIND :GLOBAL-FUNCTION {1002A2E013}>"[label="leaf"]; +"{1F} REF [1077682984383576289]: +derived-type: #" -> "{21} REF [3270722447377338959]: +derived-type: #"[label="next[ctran: INSIDE-BLOCK]"color="blue"]; +"{1F} REF [1077682984383576289]: +derived-type: #" -> "{1C} LVAR [880575187628074238]: +%derived-type: # +dynamic-extent: NIL"[label="lvar"]; +"{21} REF [3270722447377338959]: +derived-type: #" -> "{22} NOT SUPPORTED YET: + # + :DEFINED-TYPE # + :WHERE-FROM :DEFINED-HERE + :KIND :GLOBAL-FUNCTION {1002A2E323}>"[label="leaf"]; +"{21} REF [3270722447377338959]: +derived-type: #" -> "{23} REF [3193645899558233143]: +derived-type: #"[label="next[ctran: INSIDE-BLOCK]"color="blue"]; +"{21} REF [3270722447377338959]: +derived-type: #" -> "{24} LVAR [1092023012539887227]: +%derived-type: # +dynamic-extent: NIL"[label="lvar"]; +"{23} REF [3193645899558233143]: +derived-type: #" -> "{13} LAMBDA-VAR [551267047686253943]: +arg-info: NIL +flags: 0"[label="leaf"]; +"{23} REF [3193645899558233143]: +derived-type: #" -> "{25} REF [2658638157906711011]: +derived-type: #"[label="next[ctran: INSIDE-BLOCK]"color="blue"]; +"{23} REF [3193645899558233143]: +derived-type: #" -> "{26} LVAR [1584308892107556128]: +%derived-type: # +dynamic-extent: NIL"[label="lvar"]; +"{25} REF [2658638157906711011]: +derived-type: #" -> "{14} LAMBDA-VAR [1342701350530444948]: +arg-info: NIL +flags: 0"[label="leaf"]; +"{25} REF [2658638157906711011]: +derived-type: #" -> "{27} COMBINATION [4361784411754163848]: +kind: FULL +info: FULL"[label="next[ctran: INSIDE-BLOCK]"color="blue"]; +"{25} REF [2658638157906711011]: +derived-type: #" -> "{28} LVAR [2490411435938110265]: +%derived-type: # +dynamic-extent: NIL"[label="lvar"]; +"{27} COMBINATION [4361784411754163848]: +kind: FULL +info: FULL" -> "{24} LVAR [1092023012539887227]: +%derived-type: # +dynamic-extent: NIL"[label="fun"]; +"{27} COMBINATION [4361784411754163848]: +kind: FULL +info: FULL" -> "{26} LVAR [1584308892107556128]: +%derived-type: # +dynamic-extent: NIL"[label="args[# 0]"]; +"{27} COMBINATION [4361784411754163848]: +kind: FULL +info: FULL" -> "{28} LVAR [2490411435938110265]: +%derived-type: # +dynamic-extent: NIL"[label="args[# 1]"]; +"{24} LVAR [1092023012539887227]: +%derived-type: # +dynamic-extent: NIL" -> "{27} COMBINATION [4361784411754163848]: +kind: FULL +info: FULL"[label="dest"color="brown"]; +"{24} LVAR [1092023012539887227]: +%derived-type: # +dynamic-extent: NIL" -> "{21} REF [3270722447377338959]: +derived-type: #"[label="uses"]; +"{26} LVAR [1584308892107556128]: +%derived-type: # +dynamic-extent: NIL" -> "{27} COMBINATION [4361784411754163848]: +kind: FULL +info: FULL"[label="dest"color="brown"]; +"{26} LVAR [1584308892107556128]: +%derived-type: # +dynamic-extent: NIL" -> "{23} REF [3193645899558233143]: +derived-type: #"[label="uses"]; +"{28} LVAR [2490411435938110265]: +%derived-type: # +dynamic-extent: NIL" -> "{27} COMBINATION [4361784411754163848]: +kind: FULL +info: FULL"[label="dest"color="brown"]; +"{28} LVAR [2490411435938110265]: +%derived-type: # +dynamic-extent: NIL" -> "{25} REF [2658638157906711011]: +derived-type: #"[label="uses"]; +"{1D} LVAR [2954358970637004122]: +%derived-type: # +dynamic-extent: NIL" -> "{1B} COMBINATION [875787350148863859]: +kind: KNOWN +info: #"[label="dest"color="brown"]; +"{1D} LVAR [2954358970637004122]: +%derived-type: # +dynamic-extent: NIL" -> "{29} NOT SUPPORTED YET: + # + :ASSERTED-TYPE # + :TYPE-TO-CHECK # {1002A31703}>"[label="uses"]; +"{1E} LVAR [1183996723568101089]: +%derived-type: # +dynamic-extent: NIL" -> "{1B} COMBINATION [875787350148863859]: +kind: KNOWN +info: #"[label="dest"color="brown"]; +"{1E} LVAR [1183996723568101089]: +%derived-type: # +dynamic-extent: NIL" -> "{2A} REF [3033938375645121583]: +derived-type: #"[label="uses"]; +"{2A} REF [3033938375645121583]: +derived-type: #" -> "{15} LAMBDA-VAR [687676610963465975]: +arg-info: NIL +flags: 0"[label="leaf"]; +"{2A} REF [3033938375645121583]: +derived-type: #" -> "{2B} REF [1791781268393324760]: +derived-type: #"[label="next[ctran: INSIDE-BLOCK]"color="blue"]; +"{2A} REF [3033938375645121583]: +derived-type: #" -> "{1E} LVAR [1183996723568101089]: +%derived-type: # +dynamic-extent: NIL"[label="lvar"]; +"{2B} REF [1791781268393324760]: +derived-type: #" -> "{19} CLAMBDA [1745095324529044804]: +%debug-name: (LET ((G4 CONSTANT))) +source-name: .ANONYMOUS. +kind: LET"[label="leaf"]; +"{2B} REF [1791781268393324760]: +derived-type: #" -> "{2C} COMBINATION [1668396070861299820]: +kind: LOCAL +info: LOCAL"[label="next[ctran: INSIDE-BLOCK]"color="blue"]; +"{2B} REF [1791781268393324760]: +derived-type: #" -> "{2D} LVAR [3615461272610505909]: +%derived-type: NIL +dynamic-extent: NIL"[label="lvar"]; +"{2C} COMBINATION [1668396070861299820]: +kind: LOCAL +info: LOCAL" -> "{2D} LVAR [3615461272610505909]: +%derived-type: NIL +dynamic-extent: NIL"[label="fun"]; +"{2C} COMBINATION [1668396070861299820]: +kind: LOCAL +info: LOCAL" -> "{2E} LVAR [1415646066275954498]: +%derived-type: # +dynamic-extent: NIL"[label="args[# 0]"]; +"{2D} LVAR [3615461272610505909]: +%derived-type: NIL +dynamic-extent: NIL" -> "{2C} COMBINATION [1668396070861299820]: +kind: LOCAL +info: LOCAL"[label="dest"color="brown"]; +"{2D} LVAR [3615461272610505909]: +%derived-type: NIL +dynamic-extent: NIL" -> "{2B} REF [1791781268393324760]: +derived-type: #"[label="uses"]; +"{2E} LVAR [1415646066275954498]: +%derived-type: # +dynamic-extent: NIL" -> "{2C} COMBINATION [1668396070861299820]: +kind: LOCAL +info: LOCAL"[label="dest"color="brown"]; +"{2E} LVAR [1415646066275954498]: +%derived-type: # +dynamic-extent: NIL" -> "{27} COMBINATION [4361784411754163848]: +kind: FULL +info: FULL"[label="uses"]; +"{A} REF [970847179709888776]: +derived-type: #" -> "{2F} NOT SUPPORTED YET: + # + :DEFINED-TYPE # + :WHERE-FROM :DECLARED + :KIND :GLOBAL-FUNCTION {1002A37C83}>"[label="leaf"]; +"{A} REF [970847179709888776]: +derived-type: #" -> "{30} REF [2480652678179831556]: +derived-type: #"[label="next[ctran: INSIDE-BLOCK]"color="blue"]; +"{A} REF [970847179709888776]: +derived-type: #" -> "{31} LVAR [4253175545486229054]: +%derived-type: # +dynamic-extent: NIL"[label="lvar"]; +"{30} REF [2480652678179831556]: +derived-type: #" -> "{16} LAMBDA-VAR [4210063433964233181]: +arg-info: NIL +flags: 0"[label="leaf"]; +"{30} REF [2480652678179831556]: +derived-type: #" -> "{32} REF [4597392725968595806]: +derived-type: #"[label="next[ctran: INSIDE-BLOCK]"color="blue"]; +"{30} REF [2480652678179831556]: +derived-type: #" -> "{33} LVAR [351302786686104344]: +%derived-type: # +dynamic-extent: NIL"[label="lvar"]; +"{32} REF [4597392725968595806]: +derived-type: #" -> "{34} CONSTANT [1034096512296901705]: +value: OBJECT-NOT-NUMBER-ERROR"[label="leaf"]; +"{32} REF [4597392725968595806]: +derived-type: #" -> "{35} REF [4291216069658349752]: +derived-type: #"[label="next[ctran: INSIDE-BLOCK]"color="blue"]; +"{32} REF [4597392725968595806]: +derived-type: #" -> "{36} LVAR [742349938659844719]: +%derived-type: # +dynamic-extent: NIL"[label="lvar"]; +"{35} REF [4291216069658349752]: +derived-type: #" -> "{37} CONSTANT [3166890015804126914]: +value: NIL"[label="leaf"]; +"{35} REF [4291216069658349752]: +derived-type: #" -> "{38} COMBINATION [3837710288170316803]: +kind: KNOWN +info: #"[label="next[ctran: INSIDE-BLOCK]"color="blue"]; +"{35} REF [4291216069658349752]: +derived-type: #" -> "{39} LVAR [919264330689577080]: +%derived-type: # +dynamic-extent: NIL"[label="lvar"]; +"{38} COMBINATION [3837710288170316803]: +kind: KNOWN +info: #" -> "{31} LVAR [4253175545486229054]: +%derived-type: # +dynamic-extent: NIL"[label="fun"]; +"{38} COMBINATION [3837710288170316803]: +kind: KNOWN +info: #" -> "{33} LVAR [351302786686104344]: +%derived-type: # +dynamic-extent: NIL"[label="args[# 0]"]; +"{38} COMBINATION [3837710288170316803]: +kind: KNOWN +info: #" -> "{36} LVAR [742349938659844719]: +%derived-type: # +dynamic-extent: NIL"[label="args[# 1]"]; +"{38} COMBINATION [3837710288170316803]: +kind: KNOWN +info: #" -> "{39} LVAR [919264330689577080]: +%derived-type: # +dynamic-extent: NIL"[label="args[# 2]"]; +"{31} LVAR [4253175545486229054]: +%derived-type: # +dynamic-extent: NIL" -> "{38} COMBINATION [3837710288170316803]: +kind: KNOWN +info: #"[label="dest"color="brown"]; +"{31} LVAR [4253175545486229054]: +%derived-type: # +dynamic-extent: NIL" -> "{A} REF [970847179709888776]: +derived-type: #"[label="uses"]; +"{33} LVAR [351302786686104344]: +%derived-type: # +dynamic-extent: NIL" -> "{38} COMBINATION [3837710288170316803]: +kind: KNOWN +info: #"[label="dest"color="brown"]; +"{33} LVAR [351302786686104344]: +%derived-type: # +dynamic-extent: NIL" -> "{30} REF [2480652678179831556]: +derived-type: #"[label="uses"]; +"{36} LVAR [742349938659844719]: +%derived-type: # +dynamic-extent: NIL" -> "{38} COMBINATION [3837710288170316803]: +kind: KNOWN +info: #"[label="dest"color="brown"]; +"{36} LVAR [742349938659844719]: +%derived-type: # +dynamic-extent: NIL" -> "{32} REF [4597392725968595806]: +derived-type: #"[label="uses"]; +"{39} LVAR [919264330689577080]: +%derived-type: # +dynamic-extent: NIL" -> "{38} COMBINATION [3837710288170316803]: +kind: KNOWN +info: #"[label="dest"color="brown"]; +"{39} LVAR [919264330689577080]: +%derived-type: # +dynamic-extent: NIL" -> "{35} REF [4291216069658349752]: +derived-type: #"[label="uses"]; +"{9} ENTRY [3859794357893252955]: +" -> "{3A} NOT SUPPORTED YET: + # {1002A2DEF3}>"[label="cleanup"]; +"{9} ENTRY [3859794357893252955]: +" -> "{1F} REF [1077682984383576289]: +derived-type: #"[label="next[ctran: INSIDE-BLOCK]"color="blue"]; +"{9} ENTRY [3859794357893252955]: +" -> "{9} ENTRY [3859794357893252955]: +"[label="prev[ctran: BLOCK-START]"color="blue"]; +"{4} CBLOCK [4485638051092447707]" -> "{0} COMPONENT [NIL]: ''DEFUN BAR''"[label="component"]; +"{4} CBLOCK [4485638051092447707]" -> "{3} CBLOCK [463338187003706333]"[label="succ[# 0]"]; +"{4} CBLOCK [4485638051092447707]" -> "{1} CBLOCK [1575903357056582106]"[label="pred[# 0]"]; +"{4} CBLOCK [4485638051092447707]" -> "{3B} BIND [1357533544267766393]"[label="start[ctran: BLOCK-START]"color="blue"]; +"{3B} BIND [1357533544267766393]" -> "{3C} CLAMBDA [2613760754162345450]: +%debug-name: (XEP BAR) +source-name: .ANONYMOUS. +kind: EXTERNAL"[label="lambda"]; +"{3B} BIND [1357533544267766393]" -> "{3D} REF [1764939026324736725]: +derived-type: #"[label="next[ctran: INSIDE-BLOCK]"color="green"]; +"{3B} BIND [1357533544267766393]" -> "{3B} BIND [1357533544267766393]"[label="prev[ctran: BLOCK-START]"color="red"]; +"{3C} CLAMBDA [2613760754162345450]: +%debug-name: (XEP BAR) +source-name: .ANONYMOUS. +kind: EXTERNAL" -> "{3C} CLAMBDA [2613760754162345450]: +%debug-name: (XEP BAR) +source-name: .ANONYMOUS. +kind: EXTERNAL"[label="home"]; +"{3C} CLAMBDA [2613760754162345450]: +%debug-name: (XEP BAR) +source-name: .ANONYMOUS. +kind: EXTERNAL" -> "{3E} LAMBDA-VAR [602304310100471643]: +arg-info: NIL +flags: 1"[label="vars[# 0]"]; +"{3C} CLAMBDA [2613760754162345450]: +%debug-name: (XEP BAR) +source-name: .ANONYMOUS. +kind: EXTERNAL" -> "{3F} LAMBDA-VAR [3684977715938429788]: +arg-info: NIL +flags: 0"[label="vars[# 1]"]; +"{3C} CLAMBDA [2613760754162345450]: +%debug-name: (XEP BAR) +source-name: .ANONYMOUS. +kind: EXTERNAL" -> "{40} LAMBDA-VAR [1054668136212602532]: +arg-info: NIL +flags: 0"[label="vars[# 2]"]; +"{3C} CLAMBDA [2613760754162345450]: +%debug-name: (XEP BAR) +source-name: .ANONYMOUS. +kind: EXTERNAL" -> "{41} LAMBDA-VAR [4315196173549852881]: +arg-info: NIL +flags: 0"[label="vars[# 3]"]; +"{3E} LAMBDA-VAR [602304310100471643]: +arg-info: NIL +flags: 1" -> "{3C} CLAMBDA [2613760754162345450]: +%debug-name: (XEP BAR) +source-name: .ANONYMOUS. +kind: EXTERNAL"[label="home"]; +"{3F} LAMBDA-VAR [3684977715938429788]: +arg-info: NIL +flags: 0" -> "{3C} CLAMBDA [2613760754162345450]: +%debug-name: (XEP BAR) +source-name: .ANONYMOUS. +kind: EXTERNAL"[label="home"]; +"{40} LAMBDA-VAR [1054668136212602532]: +arg-info: NIL +flags: 0" -> "{3C} CLAMBDA [2613760754162345450]: +%debug-name: (XEP BAR) +source-name: .ANONYMOUS. +kind: EXTERNAL"[label="home"]; +"{41} LAMBDA-VAR [4315196173549852881]: +arg-info: NIL +flags: 0" -> "{3C} CLAMBDA [2613760754162345450]: +%debug-name: (XEP BAR) +source-name: .ANONYMOUS. +kind: EXTERNAL"[label="home"]; +"{3D} REF [1764939026324736725]: +derived-type: #" -> "{11} CLAMBDA [274430610392932488]: +%debug-name: NIL +source-name: BAR +kind: NIL"[label="leaf"]; +"{3D} REF [1764939026324736725]: +derived-type: #" -> "{42} REF [842470847812081026]: +derived-type: #"[label="next[ctran: INSIDE-BLOCK]"color="blue"]; +"{3D} REF [1764939026324736725]: +derived-type: #" -> "{43} LVAR [1888062279493340457]: +%derived-type: NIL +dynamic-extent: NIL"[label="lvar"]; +"{42} REF [842470847812081026]: +derived-type: #" -> "{3F} LAMBDA-VAR [3684977715938429788]: +arg-info: NIL +flags: 0"[label="leaf"]; +"{42} REF [842470847812081026]: +derived-type: #" -> "{44} REF [2055375462078303612]: +derived-type: #"[label="next[ctran: INSIDE-BLOCK]"color="blue"]; +"{42} REF [842470847812081026]: +derived-type: #" -> "{45} LVAR [4254170655862804359]: +%derived-type: # +dynamic-extent: NIL"[label="lvar"]; +"{44} REF [2055375462078303612]: +derived-type: #" -> "{40} LAMBDA-VAR [1054668136212602532]: +arg-info: NIL +flags: 0"[label="leaf"]; +"{44} REF [2055375462078303612]: +derived-type: #" -> "{46} REF [4363891311576890011]: +derived-type: #"[label="next[ctran: INSIDE-BLOCK]"color="blue"]; +"{44} REF [2055375462078303612]: +derived-type: #" -> "{47} LVAR [3883248025090896421]: +%derived-type: # +dynamic-extent: NIL"[label="lvar"]; +"{46} REF [4363891311576890011]: +derived-type: #" -> "{41} LAMBDA-VAR [4315196173549852881]: +arg-info: NIL +flags: 0"[label="leaf"]; +"{46} REF [4363891311576890011]: +derived-type: #" -> "{48} COMBINATION [3442268956323344380]: +kind: LOCAL +info: LOCAL"[label="next[ctran: INSIDE-BLOCK]"color="blue"]; +"{46} REF [4363891311576890011]: +derived-type: #" -> "{49} LVAR [571401066792478435]: +%derived-type: # +dynamic-extent: NIL"[label="lvar"]; +"{48} COMBINATION [3442268956323344380]: +kind: LOCAL +info: LOCAL" -> "{43} LVAR [1888062279493340457]: +%derived-type: NIL +dynamic-extent: NIL"[label="fun"]; +"{48} COMBINATION [3442268956323344380]: +kind: LOCAL +info: LOCAL" -> "{45} LVAR [4254170655862804359]: +%derived-type: # +dynamic-extent: NIL"[label="args[# 0]"]; +"{48} COMBINATION [3442268956323344380]: +kind: LOCAL +info: LOCAL" -> "{47} LVAR [3883248025090896421]: +%derived-type: # +dynamic-extent: NIL"[label="args[# 1]"]; +"{48} COMBINATION [3442268956323344380]: +kind: LOCAL +info: LOCAL" -> "{49} LVAR [571401066792478435]: +%derived-type: # +dynamic-extent: NIL"[label="args[# 2]"]; +"{43} LVAR [1888062279493340457]: +%derived-type: NIL +dynamic-extent: NIL" -> "{48} COMBINATION [3442268956323344380]: +kind: LOCAL +info: LOCAL"[label="dest"color="brown"]; +"{43} LVAR [1888062279493340457]: +%derived-type: NIL +dynamic-extent: NIL" -> "{3D} REF [1764939026324736725]: +derived-type: #"[label="uses"]; +"{45} LVAR [4254170655862804359]: +%derived-type: # +dynamic-extent: NIL" -> "{48} COMBINATION [3442268956323344380]: +kind: LOCAL +info: LOCAL"[label="dest"color="brown"]; +"{45} LVAR [4254170655862804359]: +%derived-type: # +dynamic-extent: NIL" -> "{42} REF [842470847812081026]: +derived-type: #"[label="uses"]; +"{47} LVAR [3883248025090896421]: +%derived-type: # +dynamic-extent: NIL" -> "{48} COMBINATION [3442268956323344380]: +kind: LOCAL +info: LOCAL"[label="dest"color="brown"]; +"{47} LVAR [3883248025090896421]: +%derived-type: # +dynamic-extent: NIL" -> "{44} REF [2055375462078303612]: +derived-type: #"[label="uses"]; +"{49} LVAR [571401066792478435]: +%derived-type: # +dynamic-extent: NIL" -> "{48} COMBINATION [3442268956323344380]: +kind: LOCAL +info: LOCAL"[label="dest"color="brown"]; +"{49} LVAR [571401066792478435]: +%derived-type: # +dynamic-extent: NIL" -> "{46} REF [4363891311576890011]: +derived-type: #"[label="uses"]; +"{6} BIND [2888465489035891844]" -> "{11} CLAMBDA [274430610392932488]: +%debug-name: NIL +source-name: BAR +kind: NIL"[label="lambda"]; +"{6} BIND [2888465489035891844]" -> "{6} BIND [2888465489035891844]"[label="prev[ctran: BLOCK-START]"color="red"]; +} \ No newline at end of file diff --git a/contrib/sb-graph/example/trace-4-toplevelform.dot b/contrib/sb-graph/example/trace-4-toplevelform.dot new file mode 100644 index 0000000000..8de4b59bfd --- /dev/null +++ b/contrib/sb-graph/example/trace-4-toplevelform.dot @@ -0,0 +1,128 @@ +digraph { +"{0} COMPONENT [TOPLEVEL]: ''top level form''" -> "{1} CBLOCK [4546777747233824097]"[label="head"]; +"{0} COMPONENT [TOPLEVEL]: ''top level form''" -> "{2} CBLOCK [293033905737092273]"[label="tail"]; +"{1} CBLOCK [4546777747233824097]" -> "{0} COMPONENT [TOPLEVEL]: ''top level form''"[label="component"]; +"{1} CBLOCK [4546777747233824097]" -> "{3} CBLOCK [2374185086335330572]"[label="succ[# 0]"]; +"{3} CBLOCK [2374185086335330572]" -> "{0} COMPONENT [TOPLEVEL]: ''top level form''"[label="component"]; +"{3} CBLOCK [2374185086335330572]" -> "{2} CBLOCK [293033905737092273]"[label="succ[# 0]"]; +"{3} CBLOCK [2374185086335330572]" -> "{1} CBLOCK [4546777747233824097]"[label="pred[# 0]"]; +"{3} CBLOCK [2374185086335330572]" -> "{4} BIND [2124840765505938481]"[label="start[ctran: BLOCK-START]"color="blue"]; +"{2} CBLOCK [293033905737092273]" -> "{0} COMPONENT [TOPLEVEL]: ''top level form''"[label="component"]; +"{2} CBLOCK [293033905737092273]" -> "{3} CBLOCK [2374185086335330572]"[label="pred[# 0]"]; +"{4} BIND [2124840765505938481]" -> "{5} CLAMBDA [3240387953118118454]: +%debug-name: (TOP-LEVEL-FORM + (%DEFUN 'BAR + (NAMED-LAMBDA BAR + (B C D) + (DECLARE (TOP-LEVEL-FORM)) + (BLOCK BAR (* # D))))) +source-name: .ANONYMOUS. +kind: TOPLEVEL"[label="lambda"]; +"{4} BIND [2124840765505938481]" -> "{6} REF [1909866941284971615]: +derived-type: #"[label="next[ctran: INSIDE-BLOCK]"color="green"]; +"{4} BIND [2124840765505938481]" -> "{4} BIND [2124840765505938481]"[label="prev[ctran: BLOCK-START]"color="red"]; +"{5} CLAMBDA [3240387953118118454]: +%debug-name: (TOP-LEVEL-FORM + (%DEFUN 'BAR + (NAMED-LAMBDA BAR + (B C D) + (DECLARE (TOP-LEVEL-FORM)) + (BLOCK BAR (* # D))))) +source-name: .ANONYMOUS. +kind: TOPLEVEL" -> "{5} CLAMBDA [3240387953118118454]: +%debug-name: (TOP-LEVEL-FORM + (%DEFUN 'BAR + (NAMED-LAMBDA BAR + (B C D) + (DECLARE (TOP-LEVEL-FORM)) + (BLOCK BAR (* # D))))) +source-name: .ANONYMOUS. +kind: TOPLEVEL"[label="home"]; +"{6} REF [1909866941284971615]: +derived-type: #" -> "{7} NOT SUPPORTED YET: + # + :DEFINED-TYPE # + :WHERE-FROM :DEFINED + :KIND :GLOBAL-FUNCTION {1001D6DA43}>"[label="leaf"]; +"{6} REF [1909866941284971615]: +derived-type: #" -> "{8} REF [784168789779171862]: +derived-type: #"[label="next[ctran: INSIDE-BLOCK]"color="blue"]; +"{6} REF [1909866941284971615]: +derived-type: #" -> "{9} LVAR [2701418418247132151]: +%derived-type: # +dynamic-extent: NIL"[label="lvar"]; +"{8} REF [784168789779171862]: +derived-type: #" -> "{A} CONSTANT [1255380336112371100]: +value: BAR"[label="leaf"]; +"{8} REF [784168789779171862]: +derived-type: #" -> "{B} NOT SUPPORTED YET: + # + :WHERE-FROM :DEFINED + :VARS (B C D) {1002A2D803}>) {1002A2ED73}>"[label="next[ctran: INSIDE-BLOCK]"color="blue"]; +"{8} REF [784168789779171862]: +derived-type: #" -> "{C} LVAR [2400416095386229337]: +%derived-type: # +dynamic-extent: NIL"[label="lvar"]; +"{C} LVAR [2400416095386229337]: +%derived-type: # +dynamic-extent: NIL" -> "{D} COMBINATION [2858390395914678261]: +kind: FULL +info: FULL"[label="dest"color="brown"]; +"{C} LVAR [2400416095386229337]: +%derived-type: # +dynamic-extent: NIL" -> "{8} REF [784168789779171862]: +derived-type: #"[label="uses"]; +"{D} COMBINATION [2858390395914678261]: +kind: FULL +info: FULL" -> "{9} LVAR [2701418418247132151]: +%derived-type: # +dynamic-extent: NIL"[label="fun"]; +"{D} COMBINATION [2858390395914678261]: +kind: FULL +info: FULL" -> "{C} LVAR [2400416095386229337]: +%derived-type: # +dynamic-extent: NIL"[label="args[# 0]"]; +"{D} COMBINATION [2858390395914678261]: +kind: FULL +info: FULL" -> "{E} LVAR [2458505184304471429]: +%derived-type: # +dynamic-extent: NIL"[label="args[# 1]"]; +"{9} LVAR [2701418418247132151]: +%derived-type: # +dynamic-extent: NIL" -> "{D} COMBINATION [2858390395914678261]: +kind: FULL +info: FULL"[label="dest"color="brown"]; +"{9} LVAR [2701418418247132151]: +%derived-type: # +dynamic-extent: NIL" -> "{6} REF [1909866941284971615]: +derived-type: #"[label="uses"]; +"{E} LVAR [2458505184304471429]: +%derived-type: # +dynamic-extent: NIL" -> "{D} COMBINATION [2858390395914678261]: +kind: FULL +info: FULL"[label="dest"color="brown"]; +"{E} LVAR [2458505184304471429]: +%derived-type: # +dynamic-extent: NIL" -> "{F} REF [4329924708167232172]: +derived-type: #"[label="uses"]; +"{F} REF [4329924708167232172]: +derived-type: #" -> "{10} NOT SUPPORTED YET: + #"[label="leaf"]; +"{F} REF [4329924708167232172]: +derived-type: #" -> "{D} COMBINATION [2858390395914678261]: +kind: FULL +info: FULL"[label="next[ctran: INSIDE-BLOCK]"color="blue"]; +"{F} REF [4329924708167232172]: +derived-type: #" -> "{E} LVAR [2458505184304471429]: +%derived-type: # +dynamic-extent: NIL"[label="lvar"]; +} \ No newline at end of file diff --git a/contrib/sb-graph/readme.org b/contrib/sb-graph/readme.org new file mode 100644 index 0000000000..4522c116c3 --- /dev/null +++ b/contrib/sb-graph/readme.org @@ -0,0 +1,124 @@ +* ir1-grapher + This library graphs SBCL [[https://cmucl.org/docs/internals/html/The-Implicit-Continuation-Representation.html#The-Implicit-Continuation-Representation][ir1]] and outputs graphviz. + + As of now, it is stil unfinished. There are a few tweaks that are + needed to improve useablility, in particular, I think the rendering + could be done a lot better, with subgraphs, to make it a lot more + readable. Also to make it more readable, I'm planning on + implementing rainbow-parens-esque arrow + label color randomization. + +** How do I use it during compiler tracing? + To load the system, you can call ~(asdf:load-system + :ir1-grapher)~ once you have either loaded ~ir1-grapher.asd~ + manually, or placed the folder inside your [[https://common-lisp.net/project/asdf/asdf/Configuring-ASDF-to-find-your-systems.html][ASDF load path]]. + + Because of the way it hooks in the compiler, you shouldn't actually + have to do anything after loading it except turning on trace output + of the compiler (SBCL), and adding ~:sb-graph~ to + ~sb-c::*compile-trace-targets*~. Turning on the tracing can be done + by calling ~(compile-file "file" :trace-file t)~, and adding + ~:sb-graph~ to ~sb-c::*compile-trace-targets*~ can be done however + you want. After compilation is done, alongside the normal trace + file, SBCL is hooked into writing a series of .dot files, which + contain the graphviz DOT representation of all the components + compiled. If you set ~*compile-progress*~ to ~T~, it will print out + progress information, and will tell you when and where it writes + out the graphviz files. + +** How do I use the system interactively? + If you ran into a compiler error, and want to graph the + still-in-memory code interactively, you can do so with the + following functions: + +*** ~(make-and-dfs object distance)~ + This function takes an ir1 object ~object~, and integer + ~distance~, and returns a graph object with every node up to + ~distance~ hops away from ~object~ in its ~dfs-table~. Each object + is tagged with a "codename", visible as a hex digit in braces at + the start of each graph node. + + Then, to operate on the graph interactively, you can use: + +*** ~(interactively-graph graph &optional filename)~ + This function takes a ~graph~ and a ~filename~, and sets the + current working graph to it, and the current output file to the + filename. When calling ~output~ and ~expand~, the graph will be + written to ~filename~. + +*** ~(output)~ + This function outputs the current working graph to a string, and + if ~interactively-graph~ was called with a filename, writes it to + that file. + +*** ~(expand codename)~ + After you've rendered the graph, if you want to add a node to the + ~dfs-table~ (thus expanding the amount of the in-memory objects + rendered), call this function with the codename of the new object + you'd like to add. Example: ~(expand "A")~. + + If you passed a filename to ~interactively-graph~, this function + will then write the render to file automatically. + +*** ~(unexpand codename)~ + Removes the node tied to the codename from the table, meaning that + it won't get its neighbours traversed when graph rendering is done. + +*** ~(get-node codename)~ + Returns the object tied to ~codename~ from the current interactive + graph. + +** And if you don't want to use ~interactively-graph~: +*** ~(render-graph graph)~ + Given a graph with objects in its ~dfs-table~, returns a string of + the rendering of the graph in DOT. + + Does the same thing as ~output~, but without using + ~interactively-graph~. + +*** ~(expand-codename graph codename)~ + Given a graph and codename, put the node tied to ~codename~ into + the ~dfs-table~ of the graph. + + Does the same thing as ~expand~, but without using + ~interactively-graph~. + +*** ~(unexpand-codename graph codename)~ + Does the same thing as ~unexpand~, but without using + ~interactively-graph~. + +*** ~(get-node-from-codename graph codename)~ + Return the node tied to ~codename~ in ~graph~. + + Does the same thing as ~node~, but without using + ~interactively-graph~. + +** What good is ~interactively-graph~ if I need to run ~dot~ every time the graph gets output? + That's where ~render-on-change.sh~ comes in. Run + ~render-on-change.sh~ with two arguments. First is the input DOT + file, and second is the output SVG file. If you want to export to a + different format, just modify the ~-Tsvg~ of the script. + +** Help! It's saying there's a package locking error. + Run ~(sb-ext:unlock-package :sb-c)~ in the REPL, or compile SBCL + with ~--with-sb-devel~ (if you're doing compiler work, you should + probably do this anyways). In ~src/package.lisp~, there's a + ~(sb-ext:unlock-package :sb-c)~ statement, but it seems to not work + as expected. + +** But what if the compiler breaks your library, or I want to muck around with it? + ~hooking.lisp~ contains all the code that is used to hook the + compiler directly, and ~graphing.lisp~ goes from the compiler data + structures to the graphviz DOT format. + + Right now, I'm assuming that the only place that the compiler will + ever call ~sb-c::ir2-convert~ for each component is inside + ~%compile-component~, and only one time. If this becomes no longer + true, then the hooking location/manner will have to be modified. + +** After the ~.dot~ files get output, how do I render them? + ~dot -T input.dot > output~. + For example, ~dot -Tsvg trace-1-DEFUNFOO.dot > out.svg~. + +** Can I see an example? + Yes, look at the ~example/~ folder. It contains the dot output + when running ~(compile-file "testfile" :trace-file t)~. diff --git a/contrib/sb-graph/render-on-change.sh b/contrib/sb-graph/render-on-change.sh new file mode 100755 index 0000000000..ed4fdc3d3e --- /dev/null +++ b/contrib/sb-graph/render-on-change.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +inotifywait -e close_write,moved_to,create -m . | +while read -r directory events filename; do + if [ "$filename" = "$1" ]; then + dot -Tsvg $1 > $2 + fi +done diff --git a/contrib/sb-graph/sb-graph.asd b/contrib/sb-graph/sb-graph.asd new file mode 100644 index 0000000000..54fb7909ef --- /dev/null +++ b/contrib/sb-graph/sb-graph.asd @@ -0,0 +1,17 @@ +;;; -*- Lisp -*- +#-(or sb-testing-contrib sb-building-contrib) +(error "Can't build contribs with ASDF") + +(asdf:defsystem "sb-graph" + :serial t + :components + ((:module src + :serial t + :components + ((:file "package") + (:file "graphing") + (:file "hooking")))) + :perform (load-op :after (o c) (provide 'sb-graph))) + +;;; The tests for sb-graph are under tests/sb-graph.impure.lisp to +;;; take advantage of the sbcl regression tester features. diff --git a/contrib/sb-graph/sb-graph.texinfo b/contrib/sb-graph/sb-graph.texinfo new file mode 100644 index 0000000000..714432134d --- /dev/null +++ b/contrib/sb-graph/sb-graph.texinfo @@ -0,0 +1,120 @@ +@node ICR Graphing +@comment node-name, next, previous, up +@chapter ICR Graphing +@cindex Graph, ICR, IR1 + +The @code{sb-graph} module provides a graphing tool for SBCL ir1. It +outputs graphviz DOT format. + +Its main features are that it can hook compilation so that SBCL can +output .dot files when compiler tracing is enabled, and, given a graph +in memory, provide the facility to interactively graph and interact with +it. + +@menu +* Overview:: +* User Manual:: +* API Description:: +@end menu + +@node Overview +@section Overview + +@node User Manual +@section User Manual + +If all you want to do is output .dot files during compiler tracing, you +shouldn’t actually have to do anything after loading it except turning +on SBCL’s trace output. This can be done by calling (compile-file "file" +:trace-file t). After compilation is done, alongside the normal trace +file, SBCL is transparently hooked into writing a series of .dot files, +which contain the graphviz DOT representation of all the components +compiled. If you set sb-c::*compile-progress* to T, it will print out +progress information, and will tell you when and where it writes out the +graphviz files. + +To use it interactively, call interactively-graph with a graph object +and output filename. After this is done, output, expand, and get-node +can be used to interact with said graph. As you call expand, the graph +will be output to the filename you specified. In the root of the +repository is a shell script render-on-change.sh which can be run with +two arguments: the input DOT file (the one passed to +interactively-graph), as well as an output SVG file that graphviz will +render to every time the file is changed on disk. This uses +inotify-wait, and so inotify-utils must be installed. As far as I know +this only works on Linux. A similar thing could be written for other +operating systems, though. All-in-all, this allows for a very short +expand-render-display loop. + +@node API Description +@section API Description + +@itemize + +@item + +* (make-and-dfs object distance) + +This function takes an ir1 object object, and integer distance, and +returns a graph object with every node up to distance hops away from +object in its dfs-table. Each object is tagged with a “codename”, +visible as a hex digit in braces at the start of each graph node. + +@item + +* (interactively-graph graph &optional filename) + +This function takes a graph and a filename, and sets the current working +graph to it, and the current output file to the filename. When calling +output and expand, the graph will be written to filename. + +@item + +* (output) + +This function outputs the current working graph to a string, and if +interactively-graph was called with a filename, writes it to that file. + +@item + +* (expand codename) + +After you’ve rendered the graph, if you want to add +a node to the dfs-table (thus expanding the amount of the in-memory +objects rendered), call this function with the codename of the new +object you’d like to add. Example: (expand "A"). + +If you passed a filename to interactively-graph, this function will then +write the render to file automatically. + +@item + +* (get-node codename) + +Returns the object tied to codename from the current interactive graph. + +@item + +* (render-graph graph) + +Given a graph with objects in its dfs-table, returns a string of the +rendering of the graph in DOT. + +Does the same thing as output, but without using interactively-graph. + +@item + +* (expand-graph-codename graph codename) + +Given a graph and codename, put the node tied to codename into the +dfs-table of the graph. + +Does the same thing as expand, but without using interactively-graph. + +@item + +* (get-node-from-codename graph codename) + +Return the node tied to codename in graph. + +Does the same thing as node, but without using interactively-graph. diff --git a/contrib/sb-graph/src/graphing.lisp b/contrib/sb-graph/src/graphing.lisp new file mode 100644 index 0000000000..959bf00125 --- /dev/null +++ b/contrib/sb-graph/src/graphing.lisp @@ -0,0 +1,389 @@ +(in-package :sb-graph) + +(defun make-graph () + (make-instance 'graph + :stream (make-string-output-stream) + :dfs-table (make-hash-table :test 'eq :size 63) + :obj-table (make-hash-table :test 'eq :size 63) + :codename-table (make-hash-table :test 'equal :size 63) + :codename-number 0)) + +(defun make-and-dfs (object distance) + (let ((graph (make-graph))) + (dfs-add graph distance object) + graph)) + +(defun save-graph (str filename) + (with-open-file (s filename :direction :output :if-does-not-exist :create :if-exists :supersede) + (write-string str s))) + +;; dfs-table: obj -> T +;; obj-table: obj -> codename +;; codename-table: codename -> obj +(defclass graph () + ((stream :initarg :stream :accessor stream) + (dfs-table :initarg :dfs-table :reader dfs-table) + (obj-table :initarg :obj-table :reader obj-table) + (codename-table :initarg :codename-table :reader codename-table) + (codename-number :initarg :codename-number :accessor codename-number))) + +(defmethod render-graph (graph) + (get-output-stream-string (stream graph)) + (write-string (format nil "digraph {~%") (stream graph)) + (maphash #'(lambda (k v) (declare (ignore v)) (edges graph k)) (dfs-table graph)) + (write-string "}" (stream graph)) + (get-output-stream-string (stream graph))) + +;; RENDER-GRAPH goes through all the nodes in DFS-TABLE, so we add the +;; node corresponding to the given codename to the graph's DFS-TABLE +(defmethod expand-codename (graph codename) + (setf (gethash (gethash codename (codename-table graph)) + (dfs-table graph)) + t)) + +(defmethod unexpand-codename (graph codename) + (remhash (gethash codename (codename-table graph)) + (dfs-table graph))) + +(defun get-node-from-codename (graph codename) + (gethash codename (codename-table graph))) + +;; creates a new codename, ties it to this object, then returns it. +(defun add-to-code-tables (graph object) + (if (nth-value 1 (gethash object (obj-table graph))) + (gethash object (obj-table graph)) + (let ((new-codename (let ((res (format nil "~X" (codename-number graph)))) + (incf (codename-number graph)) + res))) + (setf (gethash object (obj-table graph)) + new-codename + (gethash new-codename (codename-table graph)) + object) + new-codename))) + +(let ((curr-graph nil) + (curr-file nil)) + (defun interactively-graph (graph &optional (filename nil)) + (setf curr-graph graph) + (setf curr-file filename)) + + (defun output () + (if curr-file + (save-graph (render-graph curr-graph) curr-file) + (render-graph curr-graph))) + + (defun expand (codename) + (expand-codename curr-graph codename) + (when curr-file + (output))) + + (defun unexpand (codename) + (unexpand-codename curr-graph codename) + (when curr-file + (output))) + + (defun get-node (codename) + (get-node-from-codename curr-graph codename))) + + +;; modify-str-plist returns a new plist which is identical except the +;; value associated with KEY has been replaced by what is returned by +;; funcalling func on the value +(defun modify-str-plist (plist key func) + (assert (= 0 (mod (length plist) 2))) + (apply #'nconc + (loop with ck = nil + with cv = nil + while (setf ck (car plist) + cv (cadr plist)) + collect (let ((v (if (string= key ck) + (list ck (funcall func cv)) + (list ck cv)))) + (setf plist (cddr plist)) + v)))) + +;; this is because graphviz doesn't allow nodes to have more than 16k +;; of text in them +(defun clamp (str) + (if (< 16300 (length str)) + (subseq str 0 16300) + str)) + +;; This was copied from the common lisp cookbook. +(defun replace-all (string part replacement &key (test #'char=)) + "Returns a new string in which all the occurences of the part +is replaced with replacement." + (with-output-to-string (out) + (loop with part-length = (length part) + for old-pos = 0 then (+ pos part-length) + for pos = (search part string + :start2 old-pos + :test test) + do (write-string string out + :start old-pos + :end (or pos (length string))) + when pos do (write-string replacement out) + while pos))) + +(defmethod edge ((graph graph) from to &rest options) + (assert (= 0 (mod (length options) 2))) + (format (stream graph) "\"{~A} ~A\" -> \"{~A} ~A\"[~A];~%" + (if (gethash from (obj-table graph)) + (gethash from (obj-table graph)) + (add-to-code-tables graph from)) + (replace-all (replace-all (clamp (display from)) "\"" "'") "\\" "\\\\") + (if (gethash to (obj-table graph)) + (gethash to (obj-table graph)) + (add-to-code-tables graph to)) + (replace-all (replace-all (clamp (display to)) "\"" "'") "\\" "\\\\") + (apply #'concatenate + (cons 'string + (loop with ck = nil + with cv = nil + while (setf ck (car options) + cv (cadr options)) + collect (let ((v (format nil "~A=\"~A\"" ck cv))) + (setf options (cddr options)) + v)))))) + +;; this is overriding the edge so that we can not render CTRANs +(defmethod edge ((graph graph) from (to sb-c::ctran) &rest options) + (apply #'edge (nconc (list graph from (sb-c::ctran-next to)) + (modify-str-plist options "label" + (lambda (x) + (concatenate 'string x (format nil "[ctran: ~A]" (sb-c::ctran-kind to))))) + (unless (find-if (lambda (x) (string= x "color")) options) + '("color" "blue"))))) + + +(defmethod edge ((graph graph) from (to list) &rest options) + (let ((counter 0)) + (mapc #'(lambda (x) + (apply #'edge + (nconc (list graph from x) + (modify-str-plist + options "label" + #'(lambda (x) + (let ((res (format nil "~A[# ~A]" + x counter))) + (incf counter) + res)))))) + to))) + +;; display goes from an object to the string representation that'll be +;; inside the graph nodes + +(defmethod display ((c sb-c::component)) + (format nil "COMPONENT: '~S'" + (sb-c::component-name c))) + +;; The sxhash is required to not end up with a single CBLOCK node +(defmethod display ((b sb-c::cblock)) + (format nil "CBLOCK")) + +(defmethod display ((ctran sb-c::ctran)) + (error "Trying to display a CTRAN, this shouldn't happen")) + +(defmethod display ((cl sb-c::clambda)) + (format nil "CLAMBDA:~%%debug-name: ~A~%source-name: ~A~%kind: ~A" + (sb-c::lambda-%debug-name cl) + (sb-c::lambda-%source-name cl) + (sb-c::lambda-kind cl))) + +(defmethod display ((cr sb-c::creturn)) + (format nil "CRETURN:~%result-type: ~A" + (sb-c::return-result-type cr))) + +(defmethod display ((bind sb-c::bind)) + (format nil "BIND")) + +(defmethod display ((ref sb-c::ref)) + (format nil "REF:~%derived-type: ~A" + (sb-c::ref-derived-type ref))) + +(defmethod display ((comb sb-c::combination)) + (format nil "COMBINATION:~%kind: ~A~%info: ~A" + (sb-c::combination-kind comb) + (sb-c::combination-info comb))) + +(defmethod display ((lvar sb-c::lvar)) + (format nil "LVAR:~%%derived-type: ~A~%dynamic-extent: ~A" + (sb-c::lvar-%derived-type lvar) + (sb-c::lvar-dynamic-extent lvar))) + +(defmethod display ((const sb-c::constant)) + (format nil "CONSTANT:~%value: ~A" + (sb-c::constant-value const))) + +(defmethod display ((lamvar sb-c::lambda-var)) + (format nil "LAMBDA-VAR:~%arg-info: ~A~%flags: ~A" + (sb-c::lambda-var-arg-info lamvar) + (sb-c::lambda-var-flags lamvar))) + +(defmethod display ((entry sb-c::entry)) + (format nil "ENTRY")) + +(defmethod display (obj) + (format nil "NOT SUPPORTED YET:~% ~A" obj)) + + +(defmethod edges ((graph graph) (objects list)) + (mapc #'(lambda (o) (edges graph o)) objects)) + +(defmethod edges ((graph graph) (component sb-c::component)) + (edge graph component (sb-c::component-head component) "label" "head") + (edge graph component (sb-c::component-tail component) "label" "tail")) + +(defmethod edges ((graph graph) (cblock sb-c::cblock)) + (edge graph cblock (sb-c::block-component cblock) "label" "component") + (edge graph cblock (sb-c::block-succ cblock) "label" "succ") + (edge graph cblock (sb-c::block-pred cblock) "label" "pred") + (edge graph cblock (sb-c::block-start cblock) "label" "start")) + +;; Unfinished +(defmethod edges ((graph graph) (cl sb-c::clambda)) + (edge graph cl (sb-c::lambda-home cl) "label" "home") + (edge graph cl (sb-c::lambda-vars cl) "label" "vars")) + +(defmethod edges ((graph graph) (cr sb-c::creturn)) + (edge graph cr (sb-c::return-lambda cr) "label" "lambda") + (edge graph cr (sb-c::return-result cr) "label" "result")) + +;; this is just a dummy function to skip the CTRAN +(defmethod edges ((graph graph) (ct sb-c::ctran))) + +(defmethod edges ((graph graph) (ref sb-c::ref)) + (edge graph ref (sb-c::ref-leaf ref) "label" "leaf") + (edge graph ref (sb-c::ref-next ref) "label" "next") + (edge graph ref (sb-c::ref-lvar ref) "label" "lvar")) + +(defmethod edges ((graph graph) (bind sb-c::bind)) + (edge graph bind (sb-c::bind-lambda bind) "label" "lambda") + (edge graph bind (sb-c::bind-next bind) "label" "next" "color" "green") + (edge graph bind (sb-c::bind-prev bind) "label" "prev" "color" "red")) + +(defmethod edges ((graph graph) (comb sb-c::combination)) + (edge graph comb (sb-c::combination-fun comb) "label" "fun") + (edge graph comb (sb-c::combination-args comb) "label" "args")) + +(defmethod edges ((graph graph) (lvar sb-c::lvar)) + (edge graph lvar (sb-c::lvar-dest lvar) "label" "dest" "color" "brown") + (edge graph lvar (sb-c::lvar-uses lvar) "label" "uses")) + +(defmethod edges ((graph graph) (lamvar sb-c::lambda-var)) + (edge graph lamvar (sb-c::lambda-var-home lamvar) "label" "home") + (edge graph lamvar (sb-c::lambda-var-sets lamvar) "label" "sets")) + +(defmethod edges ((graph graph) (entry sb-c::entry)) + (edge graph entry (sb-c::entry-exits entry) "label" "exits") + (edge graph entry (sb-c::entry-cleanup entry) "label" "cleanup") + (edge graph entry (sb-c::entry-next entry) "label" "next") + (edge graph entry (sb-c::entry-prev entry) "label" "prev")) + +(defmethod edges ((graph graph) object)) + +;; the name is a "pun" of the words 'unique' and 'graph' +(defmacro unig ((graph obj) &body body) + (let ((g (gensym)) + (o (gensym))) + `(let ((,g ,graph) + (,o ,obj)) + (unless (nth-value 1 (gethash ,o (dfs-table ,g))) + (setf (gethash ,o (dfs-table ,g)) t) + ,@body)))) + +(defmethod dfs-add ((graph graph) (distance integer) (objects list)) + (mapc #'(lambda (o) (dfs-add graph distance o)) objects)) + +;; a component should be rendered as a subgraph +(defmethod dfs-add ((graph graph) (distance integer) (component sb-c::component)) + (when (> distance 0) + (decf distance) + (unig (graph component) + (dfs-add graph distance (sb-c::component-head component)) + (dfs-add graph distance (sb-c::component-tail component))))) + +(defmethod dfs-add ((graph graph) (distance integer) (cblock sb-c::cblock)) + (when (> distance 0) + (decf distance) + (unig (graph cblock) + (dfs-add graph distance (sb-c::block-component cblock)) + (dfs-add graph distance (sb-c::block-succ cblock)) + (dfs-add graph distance (sb-c::block-pred cblock)) + (dfs-add graph distance (sb-c::block-start cblock))))) + +;; Unfinished +(defmethod dfs-add ((graph graph) (distance integer) (cl sb-c::clambda)) + (when (> distance 0) + (decf distance) + (unig (graph cl) + (dfs-add graph distance (sb-c::lambda-home cl)) + (dfs-add graph distance (sb-c::lambda-vars cl))))) + +(defmethod dfs-add ((graph graph) (distance integer) (cr sb-c::creturn)) + (when (> distance 0) + (decf distance) + (unig (graph cr) + (dfs-add graph distance (sb-c::return-lambda cr)) + (dfs-add graph distance (sb-c::return-result cr))))) + +;; (defmethod dfs-add ((graph graph) (distance integer) (node sb-c::node)) +;; ) + +;; this is just a dummy function to skip the CTRAN. Note that it +;; doesn't decf distance. +(defmethod dfs-add ((graph graph) (distance integer) (ct sb-c::ctran)) + (when (> distance 0) + (unig (graph ct) + (dfs-add graph distance (sb-c::ctran-next ct))))) + +(defmethod dfs-add ((graph graph) (distance integer) (ref sb-c::ref)) + (when (> distance 0) + (decf distance) + (unig (graph ref) + (dfs-add graph distance (sb-c::ref-leaf ref)) + (dfs-add graph distance (sb-c::ref-next ref)) + (dfs-add graph distance (sb-c::ref-lvar ref))))) + +(defmethod dfs-add ((graph graph) (distance integer) (bind sb-c::bind)) + (when (> distance 0) + (decf distance) + (unig (graph bind) + (dfs-add graph distance (sb-c::bind-lambda bind)) + (dfs-add graph distance (sb-c::bind-next bind)) + (dfs-add graph distance (sb-c::bind-prev bind))))) + +(defmethod dfs-add ((graph graph) (distance integer) (comb sb-c::combination)) + (when (> distance 0) + (decf distance) + (unig (graph comb) + (dfs-add graph distance (sb-c::combination-fun comb)) + (dfs-add graph distance (sb-c::combination-args comb))))) + +(defmethod dfs-add ((graph graph) (distance integer) (lvar sb-c::lvar)) + (when (> distance 0) + (decf distance) + (unig (graph lvar) + (dfs-add graph distance (sb-c::lvar-dest lvar)) + (dfs-add graph distance (sb-c::lvar-uses lvar))))) + +(defmethod dfs-add ((graph graph) (distance integer) (lamvar sb-c::lambda-var)) + (when (> distance 0) + (decf distance) + (unig (graph lamvar) + (dfs-add graph distance (sb-c::lambda-var-home lamvar)) + (dfs-add graph distance (sb-c::lambda-var-sets lamvar))))) + +(defmethod dfs-add ((graph graph) (distance integer) (entry sb-c::entry)) + (when (> distance 0) + (decf distance) + (unig (graph entry) + (dfs-add graph distance (sb-c::entry-exits entry)) + (dfs-add graph distance (sb-c::entry-cleanup entry)) + (dfs-add graph distance (sb-c::entry-next entry)) + (dfs-add graph distance (sb-c::entry-prev entry))))) + +(defmethod dfs-add ((graph graph) (distance integer) object) + (when (> distance 0) + (decf distance) + (unig (graph object)))) diff --git a/contrib/sb-graph/src/hooking.lisp b/contrib/sb-graph/src/hooking.lisp new file mode 100644 index 0000000000..e626da5d34 --- /dev/null +++ b/contrib/sb-graph/src/hooking.lisp @@ -0,0 +1,87 @@ +(in-package :sb-graph) + +(eval-when (:compile-toplevel :load-toplevel) + (defvar *hook-enabled* (make-hash-table))) + +(defmacro hook (fun lambda-list &body body) + (let ((ll (gensym)) + (f (gensym)) + (orig (gensym))) + `(let ((,f ',fun)) + (when (nth-value 1 (gethash ',f *hook-enabled*)) + (unhook ,fun)) + (setf (gethash ,f *hook-enabled*) t) + (sb-int::encapsulate ,f 'hook + (lambda (,orig &rest ,ll) + (when (hook-enabled ,fun) + (destructuring-bind ,lambda-list ,ll + (block hook + ,@body))) + (apply ,orig ,ll)))))) +(defmacro disable-hook (fun) + (let ((f (gensym))) + `(let ((,f ',fun)) + (when (nth-value 1 (gethash ,f *hook-enabled*)) + (setf (gethash ',fun *hook-enabled*) nil))))) +(defmacro enable-hook (fun) + (let ((f (gensym))) + `(let ((,f ',fun)) + (when (nth-value 1 (gethash ,f *hook-enabled*)) + (setf (gethash ',fun *hook-enabled*) t))))) +(defmacro unhook (fun) + (let ((f (gensym))) + `(let ((,f ',fun)) + (when (nth-value 1 (gethash ,f *hook-enabled*)) + (sb-int::unencapsulate ,f 'hook) + (remhash ,f *hook-enabled*))))) +(defmacro hook-enabled (fun) + `(gethash ',fun *hook-enabled*)) + +;; (defun test-hook (a b c &rest d) +;; (list (+ a b c) d)) +;; (hook test-hook (a b c &rest d) +;; (format t "This is a hook! ~A ~A ~A ~A~%" a b c d)) +;; (unhook test-hook) +;; (hook sb-c::compile-toplevel (lambdas load-time-value-p) +;; (format t "~%Hooking the compiler. compile-toplevel:~%lambdas: ~A~%load-time-value-p: ~A~%" +;; lambdas load-time-value-p)) +;; (unhook sb-c::compile-toplevel) +;; (eval-when (:compile-toplevel :load-toplevel) +;; (defvar *acc* nil)) +;; (hook sb-c::compile-component (component) +;; (push component *acc*)) + +(eval-when (:compile-toplevel :load-toplevel) + (defvar *trace-number* 0)) + +(hook sb-c::ir2-convert (component) + (disable-hook sb-c::ir2-convert) + (when (and (streamp sb-c::*compiler-trace-output*) + (find :sb-graph sb-c::*compile-trace-targets*)) + (let* ((pn (pathname sb-c::*compiler-trace-output*)) + (out-pn (make-pathname + :host (pathname-host pn) + :directory (pathname-directory pn) + :name + (format nil "trace-~A-~A" (incf *trace-number*) + (coerce (loop for char + across + (let ((cn (sb-c::component-name component))) + (cond + ((symbolp cn) (symbol-name cn)) + ((stringp cn) cn) + ((listp cn) (if (eq (car cn) 'top-level-form) + "TOP-LEVEL-FORM" + (format nil "~{~a~}" cn))) + (t ""))) + when (or (alpha-char-p char) + (digit-char-p char) + (char= char #\-) + (char= char #\_)) + collect char) + 'string)) + :type "dot"))) + (save-graph (render-graph (make-and-dfs component 9999999)) out-pn) + (when sb-c::*compile-progress* + (format *debug-io* "~%; Wrote graphviz of component ~A to ~A.~%" component out-pn)))) + (enable-hook sb-c::ir2-convert)) diff --git a/contrib/sb-graph/src/package.lisp b/contrib/sb-graph/src/package.lisp new file mode 100644 index 0000000000..8e45d2dac3 --- /dev/null +++ b/contrib/sb-graph/src/package.lisp @@ -0,0 +1,10 @@ +(eval-when (:compile-toplevel :load-toplevel) + (sb-ext:unlock-package :sb-c)) + +(defpackage :sb-graph + (:shadow :stream) + (:use :cl :cl-user) + (:export :hook :disable-hook :enable-hook :unhook :hook-enabled + :make-graph :make-and-dfs :save-graph :graph :render-graph + :expand :expand-codename :get-node-from-codename :expand :unexpand :get-node + :interactively-graph :output :dfs-add)) diff --git a/contrib/sb-grovel/def-to-lisp.lisp b/contrib/sb-grovel/def-to-lisp.lisp index 4a416906c3..90ab33ae3f 100644 --- a/contrib/sb-grovel/def-to-lisp.lisp +++ b/contrib/sb-grovel/def-to-lisp.lisp @@ -119,12 +119,12 @@ code: (as-c "#define CAST_SIGNED(x) ((sizeof(x) == 4)? (long long) (long) (x): (x))") #+(and (not win32) x86-64) (as-c "#define CAST_SIGNED(x) ((sizeof(x) == 4)? (long) (int) (x): (x))") - ;; the C compiler on macOS warns that %ld is the wrong format for an int + ;; the C compiler on x86 macOS warns that %ld is the wrong format for an int ;; even though 'long' and 'int' are both 4 bytes. - #+x86 - (as-c "#define CAST_SIGNED(x) ((long) (x))") - #-(or x86 x86-64) + #-(or x86 64-bit) (as-c "#define CAST_SIGNED(x) ((int) (x))") + #+(and (not x86-64) (or x86 64-bit)) + (as-c "#define CAST_SIGNED(x) ((long) (x))") (as-c "int main(int argc, char *argv[]) {") (as-c " FILE *out;") (as-c " if (argc != 2) {") diff --git a/contrib/sb-grovel/foreign-glue.lisp b/contrib/sb-grovel/foreign-glue.lisp index b09023c444..b6d1aa2f99 100644 --- a/contrib/sb-grovel/foreign-glue.lisp +++ b/contrib/sb-grovel/foreign-glue.lisp @@ -356,7 +356,7 @@ deeply nested structures." (defmacro define-c-struct (name size &rest elements) (multiple-value-bind (struct-elements accessors) (let* ((root (make-instance 'struct :name name :children nil :offset 0))) - (loop for e in (sort elements #'< :key #'fourth) + (loop for e in (sort (copy-list elements) #'< :key #'fourth) do (insert-element root (apply 'mk-val e)) finally (return root)) (setf (children root) @@ -370,7 +370,6 @@ deeply nested structures." object c-object index) (let ((with (intern (format nil "WITH-~A" name))) (allocate (intern (format nil "ALLOCATE-~A" name))) - (free (intern (format nil "FREE-~A" name))) (size-of (intern (format nil "SIZE-OF-~A" name)))) `(progn (sb-alien:define-alien-type ,@(first struct-elements)) @@ -390,7 +389,7 @@ deeply nested structures." ,(second ,pair))) ,field-values)) ,@,body) - (,',free ,,var))))) + (sb-alien:free-alien ,,var))))) (defconstant ,size-of ,size) (defun ,allocate () (let* ((,object (sb-alien:make-alien ,name)) @@ -403,9 +402,7 @@ deeply nested structures." ;; optimizations might be possible. (dotimes (,index ,size) (setf (deref ,c-object ,index) 0)) - ,object)) - (defun ,free (,object) - (sb-alien:free-alien ,object))))))) + ,object))))))) ;; FIXME: Nothing in SBCL uses this, but kept it around in case there ;; are third-party sb-grovel clients. It should go away eventually, diff --git a/contrib/sb-introspect/introspect.lisp b/contrib/sb-introspect/introspect.lisp index 4d13b45162..565acd1dd8 100644 --- a/contrib/sb-introspect/introspect.lisp +++ b/contrib/sb-introspect/introspect.lisp @@ -34,6 +34,7 @@ "FUNCTION-ARGLIST" "FUNCTION-LAMBDA-LIST" "FUNCTION-TYPE" + "METHOD-COMBINATION-LAMBDA-LIST" "DEFTYPE-LAMBDA-LIST" "VALID-FUNCTION-NAME-P" "FIND-DEFINITION-SOURCE" @@ -300,11 +301,11 @@ If an unsupported TYPE is requested, the function will return NIL. (eq (car name) 'setf)) (setf name (cadr name))) (let ((expander (info :setf :expander name))) - (when expander - (find-definition-source - (cond ((symbolp expander) (symbol-function expander)) - ((listp expander) (cdr expander)) - (t expander)))))) + (cond ((typep expander '(cons symbol)) + (translate-source-location (cddr expander))) + (expander + (find-definition-source + (if (listp expander) (cdr expander) expander)))))) ((:structure) (let ((class (get-class name))) (if class @@ -353,6 +354,7 @@ If an unsupported TYPE is requested, the function will return NIL. (sb-c:fun-info-ltn-annotate . sb-c:ltn-annotate) (sb-c:fun-info-optimizer . sb-c:optimizer) (sb-c:fun-info-ir2-convert . sb-c:ir2-convert) + (sb-c::fun-info-ir2-hook . sb-c::ir2-hook) (sb-c::fun-info-stack-allocate-result . sb-c::stack-allocate-result) (sb-c::fun-info-constraint-propagate @@ -459,13 +461,14 @@ If an unsupported TYPE is requested, the function will return NIL. (let* ((debug-info (function-debug-info function)) (debug-source (debug-info-source debug-info)) (debug-fun (debug-info-debug-function function debug-info)) - (tlf (sb-c::compiled-debug-info-tlf-number debug-info))) + (tlf (if debug-fun (sb-c::compiled-debug-fun-tlf-number debug-fun)))) (make-definition-source :pathname (when (stringp (debug-source-namestring debug-source)) (parse-namestring (debug-source-namestring debug-source))) :character-offset - (sb-c::compiled-debug-info-char-offset debug-info) + (if tlf + (elt (sb-c::debug-source-start-positions debug-source) tlf)) :form-path (if tlf (list tlf)) :form-number (sb-c::compiled-debug-fun-form-number debug-fun) :file-write-date (debug-source-created debug-source) @@ -492,11 +495,13 @@ If an unsupported TYPE is requested, the function will return NIL. (function-lambda-list function)) (defun function-lambda-list (function) - "Describe the lambda list for the extended function designator FUNCTION. + "Return the lambda list for the extended function designator FUNCTION. Works for special-operators, macros, simple functions, interpreted functions, and generic functions. Signals an error if FUNCTION is not a valid extended -function designator." - ;; FIXME: sink this logic into SB-KERNEL:%FUN-LAMBDA-LIST and just call that? +function designator. + +If the function does not have a lambda list (compiled with debug 0), +then two values are returned: (values nil t)" (cond ((and (symbolp function) (special-operator-p function)) (function-lambda-list (info :function :ir1-convert function))) ((valid-function-name-p function) @@ -506,7 +511,10 @@ function designator." ((typep function 'generic-function) (sb-pcl::generic-function-pretty-arglist function)) (t - (%fun-lambda-list function)))) + (let ((raw-result (%fun-lambda-list function))) + (if (eq raw-result :unknown) + (values nil t) + (values raw-result nil)))))) (defun deftype-lambda-list (typespec-operator) "Returns the lambda list of TYPESPEC-OPERATOR as first return @@ -521,6 +529,18 @@ value." (values (%fun-lambda-list f) t) (values nil nil)))) +(defun method-combination-lambda-list (method-combination) + "Return the lambda-list of METHOD-COMBINATION designator. +METHOD-COMBINATION can be a method combination object, +or a method combination name." + (let* ((name (etypecase method-combination + (symbol method-combination) + (method-combination + (sb-pcl::method-combination-type-name method-combination)))) + (info (or (gethash name sb-pcl::**method-combinations**) + (error "~S: no such method combination." name)))) + (sb-pcl::method-combination-info-lambda-list info))) + (defun function-type (function-designator) "Returns the ftype of FUNCTION-DESIGNATOR, or NIL." (etypecase function-designator @@ -541,7 +561,7 @@ value." ;; because it contains more accurate information e.g. for ;; struct-accessors. (function-type name) - (sb-impl::%fun-type function-designator)))))) + (sb-impl::%fun-ftype function-designator)))))) ;;;; find callers/callees, liberated from Helmut Eller's code in SLIME @@ -597,7 +617,21 @@ value." ;; entry. (setf (definition-source-form-number source-location) xref-form-number) - (push (cons name source-location) result)))) + (let ((name (cond ((sb-c::transform-p name) + (let ((fun-name (%fun-name fun))) + (append (if (consp fun-name) + fun-name + (list fun-name)) + (let* ((type (sb-c::transform-type name)) + (type-spec (type-specifier type))) + (and (sb-kernel:fun-type-p type) + (list (second type-spec))))))) + ((sb-c::vop-info-p name) + (list 'sb-c:define-vop + (sb-c::vop-info-name name))) + (t + name)))) + (push (cons name source-location) result))))) xrefs)))) result)) @@ -718,6 +752,14 @@ Experimental. ;;;; ALLOCATION INTROSPECTION +(eval-when (:compile-toplevel :execute) + (defmacro pinnedp (addr) + `(eql (sb-alien:alien-funcall + (sb-alien:extern-alien "sb_introspect_pinnedp" + (function sb-alien:int sb-alien:unsigned)) + ,addr) + 1))) + (defun allocation-information (object) "Returns information about the allocation of OBJECT. Primary return value indicates the general type of allocation: :IMMEDIATE, :HEAP, :STACK, @@ -784,27 +826,15 @@ Experimental: interface subject to change." ;; bits are packed in the opposite order. And thankfully, ;; this fix seems not to depend on whether the numbering ;; scheme is MSB 0 or LSB 0, afaict. - (let* ((index (sb-vm:find-page-index + (let* ((wp (page-protected-p object)) + (index (sb-vm:find-page-index (get-lisp-obj-address object))) - (flags (sb-alien:slot page 'sb-vm::flags)) - . - ;; The unused WP-CLR is for ease of counting - #+big-endian - ((type (ldb (byte 5 3) flags)) - (wp (logbitp 2 flags)) - (wp-clr (logbitp 1 flags)) - (dontmove (logbitp 0 flags))) - #+little-endian - ((type (ldb (byte 5 0) flags)) - (wp (logbitp 5 flags)) - (wp-clr (logbitp 6 flags)) - (dontmove (logbitp 7 flags)))) - (declare (ignore wp-clr)) + (type (sb-alien:slot page 'sb-vm::flags))) (list :space space :generation (sb-alien:slot page 'sb-vm::gen) :write-protected wp - :boxed (logbitp 0 type) - :pinned dontmove + :boxed (> (logand type #xf) 1) + :pinned (pinnedp (get-lisp-obj-address object)) :large (logbitp 4 type) :page index))) (list :space space)) @@ -854,10 +884,11 @@ Experimental: interface subject to change." (add-to-xset part seen) (funcall fun part)))) (when ext - (let ((table sb-pcl::*eql-specializer-table*)) - (multiple-value-bind (value foundp) - (with-locked-system-table (table) (gethash object table)) - (when foundp (call value))))) + (multiple-value-bind (value foundp) + (let ((table sb-pcl::*eql-specializer-table*)) + (with-system-mutex ((hash-table-lock table)) + (gethash object table))) + (when foundp (call value)))) (sb-vm:do-referenced-object (object call) (cons :extend @@ -1004,7 +1035,7 @@ Experimental: interface subject to change." (= this-bin-size (+ prev-bin-size 2))) this-bin-size)))))))) -(defun largest-objects (&key (threshold #+gencgc sb-vm:gencgc-card-bytes +(defun largest-objects (&key (threshold #+gencgc sb-vm:gencgc-page-bytes #-gencgc sb-c:+backend-page-bytes+) (sort :size)) (declare (type (member :address :size) sort)) diff --git a/contrib/sb-introspect/sb-introspect.asd b/contrib/sb-introspect/sb-introspect.asd index fdee4e024f..aedf883e98 100644 --- a/contrib/sb-introspect/sb-introspect.asd +++ b/contrib/sb-introspect/sb-introspect.asd @@ -16,52 +16,4 @@ :components ((:file "introspect")) #+sb-building-contrib :pathname #+sb-building-contrib #p"SYS:CONTRIB;SB-INTROSPECT;" - :perform (load-op :after (o c) (provide 'sb-introspect)) - :in-order-to ((test-op (test-op "sb-introspect/tests")))) - -(defclass plist-file (cl-source-file) - ((source-plist - :initform nil - :initarg :source-plist - :reader plist-file-source-plist))) - -(defmethod perform ((op compile-op) (com plist-file)) - (with-compilation-unit (:source-plist (plist-file-source-plist com)) - (call-next-method))) - -(defmethod perform ((op load-op) (com plist-file)) - (with-compilation-unit (:source-plist (plist-file-source-plist com)) - (call-next-method))) - -(defsystem "sb-introspect/tests" - :depends-on ("sb-introspect" "sb-rt") - #+sb-building-contrib :pathname - #+sb-building-contrib #p"SYS:CONTRIB;SB-INTROSPECT;" - :components ((:file "xref-test-data") - (:file "xref-test" :depends-on ("xref-test-data")) - (:plist-file "test" :source-plist (:test-outer "OUT") :operation-done-p (compile-op (o c) nil)) - (:file "test-driver" :depends-on ("test"))) - :perform - (test-op (o c) - ;; N.b. At least DEFINITION-SOURCE-PLIST.1 assumes that CWD is the - ;; contrib/sb-introspect directory which is true for when this is - ;; implicitly run via make-target-contribs.sh -- but not when this - ;; is executed manually. - (let ((*default-pathname-defaults* (translate-logical-pathname (system-source-directory c)))) - (multiple-value-bind (soft strict pending) (symbol-call :sb-rt :do-tests) - (declare (ignorable pending)) - (fresh-line) - (unless strict - #+sb-testing-contrib - ;; We create TEST-PASSED from a shell script if tests passed. But - ;; since the shell script only `touch'es it, we can actually create - ;; it ahead of time -- as long as we're certain that tests truly - ;; passed, hence the check for SOFT. - (when soft - (with-open-file (s #p"SYS:CONTRIB;SB-INTROSPECT;TEST-PASSED" - :direction :output) - (dolist (pend pending) - (format s "Expected failure: ~A~%" pend)))) - (warn "ignoring expected failures in test-op")) - (unless soft - (error "test-op failed with unexpected failures")))))) + :perform (load-op :after (o c) (provide 'sb-introspect))) diff --git a/contrib/sb-introspect/test-driver.lisp b/contrib/sb-introspect/test-driver.lisp index 1a1d3ebff1..5c3fd1312d 100644 --- a/contrib/sb-introspect/test-driver.lisp +++ b/contrib/sb-introspect/test-driver.lisp @@ -8,16 +8,11 @@ ;;;; files for more information. (defpackage :sb-introspect-test - (:use "SB-INTROSPECT" "CL" "SB-RT")) + (:import-from #:test-util #:deftest) + (:use "SB-INTROSPECT" "CL")) (in-package :sb-introspect-test) -(defmacro deftest* ((name &key fails-on) form &rest results) - `(progn - (when (sb-impl::featurep ',fails-on) - (pushnew ',name sb-rt::*expected-failures*)) - (deftest ,name ,form ,@results))) - ;; When running the tests which query for a function type, sb-interpreter ;; can return an answer if there were type declarations for the arguments, ;; except that return type is always unknown. The compiler returns a @@ -28,15 +23,23 @@ (deftest function-lambda-list.1 (function-lambda-list 'cl-user::one) - (cl-user::a cl-user::b cl-user::c)) + (cl-user::a cl-user::b cl-user::c) + nil) + +(deftest function-lambda-list.1a + (function-lambda-list 'cl-user::0-debug) + () + t) (deftest function-lambda-list.2 (function-lambda-list 'the) - (sb-c::value-type sb-c::form)) + (sb-c::value-type sb-c::form) + nil) (deftest function-lambda-list.3 (function-lambda-list #'(sb-pcl::slow-method cl-user::j (t))) - (sb-pcl::method-args sb-pcl::next-methods)) + (sb-pcl::method-args sb-pcl::next-methods) + nil) (deftest macro-lambda-list.1 (equal (function-lambda-list (defmacro macro-lambda-list.1-m (x b) @@ -44,6 +47,10 @@ '(x b)) t) +(defmacro interpret (form) + `(let ((sb-ext:*evaluator-mode* :interpret)) + (eval ',form))) + #+sb-eval (deftest macro-lambda-list.2 (equal (function-lambda-list (interpret (defmacro macro-lambda-list.2-m (x) @@ -72,7 +79,9 @@ (let* ((source (find-definition-source #'cl-user::one)) (plist (definition-source-plist source)) (pathname (definition-source-pathname source))) - (values (equalp pathname #p"SYS:CONTRIB;SB-INTROSPECT;TEST.LISP.NEWEST") + (declare (ignore source)) + ;; the full pathname isn't important + (values (equalp (pathname-name pathname) "TEST") (= (definition-source-file-write-date source) (file-write-date pathname)) (or (equal (getf plist :test-outer) @@ -80,18 +89,13 @@ plist))) t t t) -;; Not sure why this fails when interpreted, and don't really care too much. -;; The behavior seems right to me anyway. -#.(if (eq sb-ext:*evaluator-mode* :compile) -'(deftest definition-source-plist.2 +;;; The behavior of :SOURCE-PLIST on nested WITH-COMPILATION-UNIT +;;; is to append. This is documented in source/compiler/main +(test-util:with-test (:name :definition-source-plist.2) (let ((plist (definition-source-plist (find-definition-source #'cl-user::four)))) - (values (or (equal (getf plist :test-outer) "OUT") - plist) - (or (equal (getf plist :test-inner) "IN") - plist))) - t t) -(values)) + (assert (equal (getf plist :test-outer) "OUT")) + (assert (equal (getf plist :test-inner) "IN")))) (defun matchp (object form-number) (let ((ds (sb-introspect:find-definition-source object))) @@ -122,7 +126,7 @@ t) (deftest find-source-stuff.4 - (matchp (car (sb-pcl:generic-function-methods #'cl-user::two)) 4) + (matchp (car (sb-mop:generic-function-methods #'cl-user::two)) 4) t) (deftest find-source-stuff.5 @@ -242,7 +246,7 @@ (matchp-name :function 'cl-user::compile-time-too-fun 28) t) -(load "load-test.lisp") +(load "../contrib/sb-introspect/load-test.lisp") (deftest find-source-stuff.32 (matchp-name :function 'cl-user::loaded-as-source-fun 3) t) @@ -320,6 +324,24 @@ (&optional sb-kernel::element-type sb-kernel::size) t) +;;; Check correctness of METHOD-COMBINATION-LAMBDA-LIST +(deftest method-combination-lambda-list.1 + (method-combination-lambda-list 'standard) + nil) + +(deftest method-combination-lambda-list.2 + (method-combination-lambda-list + (sb-mop:find-method-combination #'documentation 'cl-user::r nil)) + (&optional (sb-pcl::order :most-specific-first))) + +(declaim (sb-ext:muffle-conditions style-warning)) +(define-method-combination long-form-mc (foo &rest args &key bar) ()) + +(deftest method-combination-lambda-list.3 + (method-combination-lambda-list 'long-form-mc) + (foo &rest args &key bar)) + + ;;; Test allocation-information (defun tai (x kind info &key ignore) @@ -358,36 +380,21 @@ (tai 42s0 :immediate nil) t) -;;; -- It appears that this test can also fail due to systematic issues -;;; (possibly with the C compiler used) which we cannot detect based on -;;; *features*. Until this issue has been fixed, I am marking this test -;;; as failing on Windows to allow installation of the contrib on -;;; affected builds, even if the underlying issue is (possibly?) not even -;;; strictly related to windows. C.f. lp1057631. --DFL -;;; -(deftest* (allocation-information.4 +(test-util:with-test (:name :allocation-information.4 ;; Ignored as per the comment above, even though it seems ;; unlikely that this is the right condition. - :fails-on (or :win32 :ppc64 (and :sparc :gencgc))) - #+gencgc + :fails-on (or :ppc64 (and :sparc :gencgc))) (tai (make-list 1) :heap `(:space :dynamic :boxed t :large nil) - :ignore (list :page :pinned :generation :write-protected)) - #-gencgc - (tai :cons :heap - ;; FIXME: Figure out what's the right cheney-result. SPARC at least - ;; has exhibited both :READ-ONLY and :DYNAMIC, which seems wrong. - '() - :ignore '(:space)) - t) + :ignore (list :page :pinned :generation :write-protected))) (setq sb-ext:*evaluator-mode* :compile) (sb-ext:defglobal *large-obj* nil) -#+(and gencgc (or riscv x86 x86-64 ppc) (not win32)) +#+(and gencgc (or riscv x86 x86-64 ppc) (not win32) (not ubsan)) (progn (setq *print-array* nil) - (setq *large-obj* (make-array (* sb-vm:gencgc-card-bytes 4) + (setq *large-obj* (make-array (* sb-vm:gencgc-page-bytes 4) :element-type '(unsigned-byte 8))) (sb-ext:gc :gen 1) ; Array won't move to a large unboxed page until GC'd (deftest allocation-information.5 @@ -414,30 +421,39 @@ (= (getf props :page) page) (= (getf props :generation) gen) (eq (getf props :boxed :missing) boxedp)))) + +(defun alloc-large-code () + ;; large objets have to have to be at least 4 GC pages + (let ((bytes (* 4 sb-vm:gencgc-page-bytes))) + ;; For 32-bit in order to force allocation into a large-object page, the currently + ;; open code region has to be closed. Otherwise the allocation might fit in the region. + #-64-bit + (sb-alien:alien-funcall + (sb-alien:extern-alien "gc_close_region" + (function sb-alien:void sb-alien:unsigned sb-alien:unsigned)) + (+ (* 3 3 sb-vm:n-word-bytes) ; KLUDGE: a region is 3 words, and code_region + ; is the third in the array of regions + (sb-sys:find-dynamic-foreign-symbol-address "gc_alloc_region")) + 7) ; KLUDGE: PAGE_TYPE_CODE + ;; A legal code object needs >= 4 boxed words. Let's use 8 + (let ((object (sb-c:allocate-code-object nil 8 (- bytes (* 8 sb-vm:n-word-bytes))))) + (setq *large-obj* object) + ;; assert that it's large, otherwise the entire test is bogus + (let ((props (nth-value 1 (allocation-information object)))) + (assert (getf props :large))) + object))) +(compile 'alloc-large-code) + #+gencgc -(deftest* (allocation-information.6 :fails-on :sbcl) +(deftest allocation-information.6 ;; Remember, all tests run after all toplevel forms have executed, ;; so if this were (DEFGLOBAL *LARGE-CODE* ... ) or something, ;; the garbage collection explicitly requested for ALLOCATION-INFORMATION.5 ;; would have already happened, and thus affected this test as well. ;; So we need to make the objects within each test, ;; while avoiding use of lexical vars that would cause conservative pinning. - (multiple-value-bind (page gen) - (page-and-gen - (setq *large-obj* - ;; To get a large-object page, a code object has to exceed - ;; LARGE_OBJECT_SIZE and not fit within an open region. - ;; (This is a minor bug, because one should be able to - ;; create regions as large as desired without affecting - ;; determination of whether an object is large. - ;; Practically it means is that a small object region - ;; is limited to at most 3 pages) - ;; 32-bit machines use 64K for code allocation regions, - ;; but the large object size can be as small as 16K. - ;; 16K might fit in the free space of an open region, - ;; and by accident would not go on a large object page. - (sb-c:allocate-code-object nil 0 0 - (max (* 4 sb-vm:gencgc-card-bytes) #-64-bit 65536)))) + (multiple-value-bind (page gen) (page-and-gen (alloc-large-code)) + (declare (ignorable gen)) (declare (notinline format)) (format (make-string-output-stream) "~%") (loop for i from 1 to sb-vm:+highest-normal-generation+ @@ -453,8 +469,8 @@ (deftest allocation-information.7 (locally (declare (notinline format)) - ;; Create a bignum using 4 GC cards - (setq *b* (ash 1 (* sb-vm:gencgc-card-bytes sb-vm:n-byte-bits 4))) + ;; Create a bignum using 4 GC pages + (setq *b* (ash 1 (* sb-vm:gencgc-page-bytes sb-vm:n-byte-bits 4))) (setq *negb* (- *b*)) (and (let ((props (get-small-bignum-allocation-information))) ;; *SMALL-BIGNUM* was created as a large boxed object @@ -526,10 +542,6 @@ (sb-kernel:type= (sb-kernel:values-specifier-type typespec1) (sb-kernel:values-specifier-type typespec2)))) -(defmacro interpret (form) - `(let ((sb-ext:*evaluator-mode* :interpret)) - (eval ',form))) - ;; Functions (declaim (ftype (function (integer &optional string) string) moon)) @@ -565,7 +577,9 @@ (type-equal (function-type #'f) (if (expect-wild-return-type-p #'f) '(function (symbol) *) - '(function (symbol) (values simple-string &optional))))) + '(function (symbol) (values #+sb-unicode simple-string + #-sb-unicode simple-base-string + &optional))))) t) ;; Closures @@ -707,7 +721,7 @@ (predicate (find-definition-source #'cl-user::three-p))) (values (and (equalp copier accessor) (equalp copier predicate)) - (equal "TEST.LISP.NEWEST" + (equal "test.lisp" (file-namestring (definition-source-pathname copier))) (equal '(5) (definition-source-form-path copier)))) @@ -721,7 +735,7 @@ (predicate (car (find-definition-sources-by-name 'cl-user::three-p :function)))) (values (and (equalp copier accessor) (equalp copier predicate)) - (equal "TEST.LISP.NEWEST" + (equal "test.lisp" (file-namestring (definition-source-pathname copier))) (equal '(5) (definition-source-form-path copier)))) @@ -761,24 +775,25 @@ ;;; ASDF. I can't even. (compile 'sb-introspect:map-root) -(defun count-pointees (x simple &aux (n 0)) - (sb-introspect:map-root (lambda (obj) - (declare (ignore obj)) - (incf n)) - x - :simple simple) - n) +(defun list-pointees (x simple) + (sb-int:collect ((result)) + (sb-introspect:map-root (lambda (obj) (result obj)) + x :simple simple) + (result))) +(defun count-pointees (x simple) + (length (list-pointees x simple))) ;;; A closure points to its underlying function, all closed-over values, ;;; and possibly the closure's name. -;;; #'SB-INT:CONSTANTLY-T is a nameless closure over 1 value -(deftest map-root-closure-un (count-pointees #'SB-INT:CONSTANTLY-T nil) 2) -;;; (SYMBOL-FUNCTION 'AND) is a named closure over 1 value +(deftest map-root-closure-unnamed + (count-pointees (funcall (compile nil `(lambda (x) (lambda () x))) t) nil) + 2) +;;; (SYMBOL-FUNCTION 'AND) is a named closure over 1 value. +;;; The closed-over value is AND, and the name of the closure is (:MACRO AND). (deftest map-root-closure-named (count-pointees (symbol-function 'and) nil) 3) -;;; GFs point to their layout, implementation, slots, -;;; and a hash-code, except that 64-bit headers can store the hash code -;;; in the slot vector's high header bytes. +;;; GFs point to their layout, implementation function, and slot vector. +;;; There's also a hash-code which is stored is one of two different ways. ;;; However, in either case we expect only 3 referenced objects, ;;; because due to a strange design choice in MAP-ROOT, ;;; it does not invoke the funarg on fixnums (or characters). diff --git a/contrib/sb-introspect/test.lisp b/contrib/sb-introspect/test.lisp index 7ef4b24207..f33bec8823 100644 --- a/contrib/sb-introspect/test.lisp +++ b/contrib/sb-introspect/test.lisp @@ -93,3 +93,5 @@ (flet ((x ())) (declare (notinline x)) (x))) + +(defun 0-debug (a b c) (declare (optimize (debug 0))) (+ a b c)) diff --git a/contrib/sb-introspect/xref-test-data.lisp b/contrib/sb-introspect/xref-test-data.lisp index 25e692aa36..701944bb64 100644 --- a/contrib/sb-introspect/xref-test-data.lisp +++ b/contrib/sb-introspect/xref-test-data.lisp @@ -8,7 +8,8 @@ ;;;; files for more information. (defpackage :sb-introspect-test/xref - (:use "SB-INTROSPECT" "CL" "SB-RT")) + (:import-from #:test-util #:deftest) + (:use "SB-INTROSPECT" "CL")) (in-package :sb-introspect-test/xref) diff --git a/contrib/sb-md5/md5-tests.lisp b/contrib/sb-md5/md5-tests.lisp index ea9e4c82bc..b58be7f670 100644 --- a/contrib/sb-md5/md5-tests.lisp +++ b/contrib/sb-md5/md5-tests.lisp @@ -1,5 +1,6 @@ (defpackage #:sb-md5-tests - (:use #:sb-md5 #:cl #:sb-rt)) + (:import-from #:test-util #:deftest) + (:use #:sb-md5 #:cl)) (in-package #:sb-md5-tests) (defun byte-array-to-hex-string (bytevec) diff --git a/contrib/sb-md5/md5.lisp b/contrib/sb-md5/md5.lisp index a737b70e86..28da373720 100644 --- a/contrib/sb-md5/md5.lisp +++ b/contrib/sb-md5/md5.lisp @@ -69,6 +69,7 @@ (in-package sb-md5) (eval-when (:compile-toplevel :load-toplevel :execute) + (sb-ext:restrict-compiler-policy 'space 1) ; lp#1988683 (setf (sb-int:system-package-p *package*) t)) #+cmu @@ -132,7 +133,7 @@ where a is the intended low-order byte and d the high-order byte." #-lw-int32 `(aref ,vector ,index)) -;;; Section 3.4: Auxilliary functions +;;; Section 3.4: Auxiliary functions (declaim (inline f g h i) (ftype (function (ub32 ub32 ub32) ub32) f g h i)) @@ -374,7 +375,7 @@ starting from `offset' into the given 16 word MD5 block." block (* vm:vector-data-offset vm:word-bits) (* 64 vm:byte-bits)) #+(and :sbcl :little-endian) - (sb-kernel:ub8-bash-copy buffer offset block 0 64) + (sb-kernel:%byte-blt buffer offset block 0 64) #-(or (and :sbcl :little-endian) (and :cmu :little-endian)) (loop for i of-type (integer 0 16) from 0 for j of-type (integer 0 #.most-positive-fixnum) @@ -394,13 +395,14 @@ starting from `offset' into the given 16 word MD5 block." (type simple-string buffer) (optimize (speed 3) (safety 0) (space 0) (debug 0) #+lw-int32 (float 0) #+lw-int32 (hcl:fixnum-safety 0))) + (declare (ignorable block buffer offset)) #+(and :cmu :little-endian) (kernel:bit-bash-copy buffer (+ (* vm:vector-data-offset vm:word-bits) (* offset vm:byte-bits)) block (* vm:vector-data-offset vm:word-bits) (* 64 vm:byte-bits)) #+(and :sbcl :little-endian) - (sb-kernel:ub8-bash-copy buffer offset block 0 64) + (error "Unexpectedly hit MD5:FILL-BLOCK-CHAR") #-(or (and :sbcl :little-endian) (and :cmu :little-endian)) (loop for i of-type (integer 0 16) from 0 for j of-type (integer 0 #.most-positive-fixnum) @@ -639,10 +641,7 @@ The resulting MD5 message-digest is returned as an array of sixteen "Calculate the MD5 message-digest of data in `sequence', which should be a 1d simple-array with element type (unsigned-byte 8). On CMU CL and SBCL non-simple and non-1d arrays with this element-type are also -supported. Use with strings is DEPRECATED, since this will not work -correctly on implementations with `char-code-limit' > 256 and ignores -character-coding issues. Use md5sum-string instead, or convert to the -required (unsigned-byte 8) format through other means before-hand." +supported." (declare (optimize (speed 3) (safety 3) (space 0) (debug 1)) (type (vector (unsigned-byte 8)) sequence) (type fixnum start)) (locally diff --git a/contrib/sb-md5/sb-md5.asd b/contrib/sb-md5/sb-md5.asd index 6439f83a19..3bebc1b699 100644 --- a/contrib/sb-md5/sb-md5.asd +++ b/contrib/sb-md5/sb-md5.asd @@ -24,14 +24,4 @@ #+sb-building-contrib :pathname #+sb-building-contrib #p"SYS:CONTRIB;SB-MD5;" :components ((:file "md5")) - :perform (load-op :after (o c) (provide 'sb-md5)) - :in-order-to ((test-op (test-op "sb-md5/tests")))) - -(defsystem "sb-md5/tests" - :depends-on ("sb-md5" "sb-rt") - :version "2.0.4" - :components ((:file "md5-tests"))) - -(defmethod perform ((o test-op) (c (eql (find-system "sb-md5/tests")))) - (or (funcall (intern "DO-TESTS" (find-package "SB-RT"))) - (error "test-op failed"))) + :perform (load-op :after (o c) (provide 'sb-md5))) diff --git a/contrib/sb-mpfr/mpfr.lisp b/contrib/sb-mpfr/mpfr.lisp index 5ab5430b6c..499ccfddfd 100644 --- a/contrib/sb-mpfr/mpfr.lisp +++ b/contrib/sb-mpfr/mpfr.lisp @@ -198,10 +198,11 @@ (defun %load-mpfr () (or (some #'try-load-shared-object - #-(or win32 darwin) '("libmpfr.so" "libmpfr.so.4") - #+darwin '("libmpfr.dylib" "libmpfr.4.dylib") + #-(or win32 darwin) '("libmpfr.so" "libmpfr.so.4" "libmpfr.so.6") + #+darwin '("libmpfr.dylib" "libmpfr.4.dylib" "libmpfr.6.dylib") #+win32 '("mpfr.dll")) - (warn "MPFR not loaded."))) + (warn "MPFR was not loaded. This is likely because the shared library ~ + was not found."))) (defun load-mpfr (&key (persistently t)) (setf *mpfr-version* nil @@ -217,8 +218,8 @@ (alien-funcall (extern-alien "mpfr_get_version" (function c-string))))) (cond ((null *mpfr-version*)) - ((string<= *mpfr-version* "3.1") - (warn "SB-MPFR requires at least MPFR version 3.1") + ((string<= *mpfr-version* "4.0.0") + (warn "SB-MPFR requires at least MPFR version 4.0.0") (setf success nil)) (t (setf +mpfr-precision+ @@ -1730,7 +1731,7 @@ ,@defines)))) (define-onearg-no-rnd-mpfr-funs - ((ceil mpfr_ceil) + ((ceiling mpfr_ceil) (floor mpfr_floor) (round mpfr_round) (truncate mpfr_trunc))) @@ -1783,6 +1784,19 @@ (x (* (struct mpfrfloat))) (rnd mpfr_rnd_enum)) +(declaim (inline mpfr_get_q)) +(define-alien-routine mpfr_get_q void + (rop (* (struct sb-gmp::gmprat))) + (op (* (struct mpfrfloat)))) + +(defun mpfrfloat->rational (f) + "Convert a raw MPFRFLOAT F into a CL:RATIONAL." + (with-alien ((q (struct sb-gmp::gmprat))) + (sb-gmp::__gmpq_init (addr q)) + (mpfr_get_q (addr q) f) + (prog1 (sb-gmp::mpq->rational q) + (sb-gmp::__gmpq_clear (addr q))))) + (defun coerce (x type &optional (round *mpfr-rnd*)) (cond ((typep x 'mpfr-float) @@ -1792,6 +1806,9 @@ (mpfr_get_flt x-ref round)) (double-float (mpfr_get_d x-ref round)) + (rational + ;; this will always be exact + (mpfrfloat->rational x-ref)) (mpfr-float (let ((result (make-mpfr-float))) (mpfr_set (mpfr-float-ref result) x-ref round) diff --git a/contrib/sb-mpfr/sb-mpfr.asd b/contrib/sb-mpfr/sb-mpfr.asd index 867722a9de..2689178c07 100644 --- a/contrib/sb-mpfr/sb-mpfr.asd +++ b/contrib/sb-mpfr/sb-mpfr.asd @@ -8,21 +8,5 @@ :serial t :depends-on ("sb-gmp") :components ((:file "mpfr")) - :perform (load-op :after (o c) (provide 'sb-mpfr)) - :in-order-to ((test-op (test-op "sb-mpfr/tests")))) + :perform (load-op :after (o c) (provide 'sb-mpfr))) -(defsystem "sb-mpfr/tests" - :depends-on ("sb-rt" "sb-mpfr") - :components ((:file "tests"))) - -(defmethod perform ((o test-op) (c (eql (find-system "sb-mpfr/tests")))) - (if (not (member :sb-mpfr *features*)) - (warn "unable to test sb-mpfr: libmpfr unavailable") - (multiple-value-bind (soft strict pending) - (funcall (intern "DO-TESTS" (find-package "SB-RT"))) - (declare (ignorable pending)) - (fresh-line) - (unless strict - (warn "ignoring expected failures in sb-mpfr-tests")) - (unless soft - (error "sb-mpfr-tests failed with unexpected failures"))))) diff --git a/contrib/sb-mpfr/tests.lisp b/contrib/sb-mpfr/tests.lisp index 700b996d23..48566475db 100644 --- a/contrib/sb-mpfr/tests.lisp +++ b/contrib/sb-mpfr/tests.lisp @@ -1,7 +1,4 @@ -(defpackage "SB-MPFR-TESTS" - (:use "COMMON-LISP" "SB-RT")) - -(in-package "SB-MPFR-TESTS") +;;; FIXME: how are these testing anything??? (defun sample () (let ((sb-mpfr:*mpfr-rnd* :MPFR_RNDD)) @@ -26,3 +23,34 @@ (defun sample-pi () (sb-mpfr:set-precision 400) (sb-mpfr:const-pi)) + + +;;; Test that (sb-mpfr:coerce * 'rational) works + +(defvar *roundtrip-precision* 100) + +(defun rational-roundtrip (rat) + (sb-mpfr:with-precision *roundtrip-precision* + (let* ((f (sb-mpfr:coerce rat 'sb-mpfr:mpfr-float)) + (frat (sb-mpfr:coerce f 'rational))) + frat))) + +(macrolet ((%write-out-idempotence-tests (&rest rationals) + `(progn + ,@(loop :for rat :in rationals + :collect + `(test-util:with-test + (:name ,(sb-int:keywordicate (format nil "TEST-RATIONALIZE-~A" rat))) + (assert (<= (abs (- ,rat (rational-roundtrip ,rat))) + (expt 2 (- *roundtrip-precision*))))))))) + + (%write-out-idempotence-tests + 1/2 + 1/4 + 1/8 + 1/16 + (+ 1/2 1/4 1/8) + 355/113 + pi + (exp 1) + (sqrt 2))) diff --git a/contrib/sb-posix/interface.lisp b/contrib/sb-posix/interface.lisp index 3c94463cbf..f938064987 100644 --- a/contrib/sb-posix/interface.lisp +++ b/contrib/sb-posix/interface.lisp @@ -128,7 +128,7 @@ (macrolet ((def (x) `(progn (define-call-internally open-with-mode ,x int minusp - (pathname filename) (flags int) (mode mode-t)) + (pathname filename) (flags int) &optional (mode mode-t)) (define-call-internally open-without-mode ,x int minusp (pathname filename) (flags int)) (define-entry-point ,x @@ -245,9 +245,10 @@ (define-call-internally fcntl-without-arg "fcntl" int minusp (fd file-descriptor) (cmd int)) (define-call-internally fcntl-with-int-arg "fcntl" int minusp - (fd file-descriptor) (cmd int) (arg int)) + (fd file-descriptor) (cmd int) &optional (arg int)) (define-call-internally fcntl-with-pointer-arg "fcntl" int minusp (fd file-descriptor) (cmd int) + &optional (arg alien-pointer-to-anything-or-nil)) (define-protocol-class flock alien-flock () ((type :initarg :type :accessor flock-type @@ -340,24 +341,36 @@ "Forks the current process, returning 0 in the new process and the PID of the child process in the parent. Forking while multiple threads are running is not supported." - (tagbody - (let () - #+sb-thread - (sb-impl::finalizer-thread-stop) - (sb-thread::with-all-threads-lock - (when (let ((avltree sb-thread::*all-threads*)) - (or (sb-thread::avlnode-left avltree) - (sb-thread::avlnode-right avltree))) - (go :error)) - (let ((pid (posix-fork))) - #+darwin - (when (= pid 0) - (darwin-reinit)) - #+sb-thread - (setf sb-impl::*finalizer-thread* t) - (return-from fork pid)))) - :error - (error "Cannot fork with multiple threads running."))) + ;; It would be easy enough to to allow fork in multithreaded code - we'd need the new + ;; process to set *ALL-THREADS* to contain only one thread, and unmap other threads' + ;; stack to avoid a memory leak. The tricky part would be adhering the the POSIX caveats. + ;; Linux: + ;; After a fork() in a multithreaded program, the child can safely call only async-signal-safe + ;; functions (see signal-safety(7)) until such time as it calls execve(2). + ;; FreeBSD: + ;; If the process has more than one thread, locks and other resources held by the other + ;; threads are not released and therefore only async-signal-safe functions are guaranteed + ;; to work in the child process until a call to execve(2) or a similar function. + ;; macOS: + ;; To be totally safe you should restrict yourself to only executing async-signal safe + ;; operations until such time as one of the exec functions is called. + #+sb-thread + (when (cdr (sb-int:with-system-mutex (sb-thread::*make-thread-lock*) + (sb-impl::finalizer-thread-stop) + ;; Dead threads aren't pruned from *ALL-THREADS* until the Pthread join. + ;; Do that now so that the forked process has only the main thread + ;; in *ALL-THREADS* and nothing in *JOINABLE-THREADS*. + (sb-thread::%dispose-thread-structs) + ;; Threads are added to ALL-THREADS before they have an OS thread, + ;; but newborn threads are not exposed in SB-THREAD:LIST-ALL-THREADS. + ;; So we need to go lower-level to sense whether any exist. + (sb-thread:avltree-list sb-thread::*all-threads*))) + (sb-impl::finalizer-thread-start) + (error "Cannot fork with multiple threads running.")) + (let ((pid (posix-fork))) + #+darwin (when (= pid 0) (darwin-reinit)) + #+sb-thread (sb-impl::finalizer-thread-start) + pid)) (export 'fork :sb-posix) (define-call "getpgid" pid-t minusp (pid pid-t)) @@ -430,14 +443,12 @@ not supported." (declaim (inline wait)) (defun wait (&optional statusptr) (declare (type (or null (simple-array (signed-byte 32) (1))) statusptr)) - (let* ((ptr (or statusptr (make-array 1 :element-type '(signed-byte 32)))) - (pid (sb-sys:with-pinned-objects (ptr) - (alien-funcall - (extern-alien "wait" (function pid-t (* int))) - (sb-sys:vector-sap ptr))))) - (if (minusp pid) - (syscall-error 'wait) - (values pid (aref ptr 0)))))) + (with-alien ((wait (function pid-t (* int)) :extern "wait") + (status int)) + (let ((pid (alien-funcall wait (addr status)))) + (when (minusp pid) (syscall-error 'wait)) + (when statusptr (setf (aref statusptr 0) status)) + (values pid status))))) #-win32 (progn @@ -447,15 +458,12 @@ not supported." (declare (type (sb-alien:alien pid-t) pid) (type (sb-alien:alien int) options) (type (or null (simple-array (signed-byte 32) (1))) statusptr)) - (let* ((ptr (or statusptr (make-array 1 :element-type '(signed-byte 32)))) - (pid (sb-sys:with-pinned-objects (ptr) - (alien-funcall - (extern-alien "waitpid" (function pid-t - pid-t (* int) int)) - pid (sb-sys:vector-sap ptr) options)))) - (if (minusp pid) - (syscall-error 'waitpid) - (values pid (aref ptr 0))))) + (with-alien ((waitpid (function pid-t pid-t (* int) int) :extern "waitpid") + (status int)) + (let ((pid (alien-funcall waitpid pid (addr status) options))) + (when (minusp pid) (syscall-error 'waitpid)) + (when statusptr (setf (aref statusptr 0) status)) + (values pid status)))) ;; waitpid macros (define-call "wifexited" boolean never-fails (status int)) (define-call "wexitstatus" int never-fails (status int)) @@ -504,11 +512,9 @@ not supported." (define-call "mlockall" int minusp (flags int)) (define-call "munlockall" int minusp) -#-win32 -(define-call "getpagesize" int minusp) -#+win32 -;;; KLUDGE: This could be taken from GetSystemInfo -(export (defun getpagesize () 4096)) +(export 'getpagesize) +(declaim (inline getpagesize)) +(defun getpagesize () (extern-alien "os_reported_page_size" (unsigned 32))) ;;; passwd database ;; The docstrings are copied from the descriptions in SUSv3, @@ -654,16 +660,13 @@ not supported." (declaim (inline pipe)) (defun pipe (&optional filedes2) (declare (type (or null (simple-array (signed-byte 32) (2))) filedes2)) - (unless filedes2 - (setq filedes2 (make-array 2 :element-type '(signed-byte 32)))) - (let ((r (sb-sys:with-pinned-objects (filedes2) - (alien-funcall - ;; FIXME: (* INT)? (ARRAY INT 2) would be better - (extern-alien "pipe" (function int (* int))) - (sb-sys:vector-sap filedes2))))) - (when (minusp r) - (syscall-error 'pipe))) - (values (aref filedes2 0) (aref filedes2 1)))) + (multiple-value-bind (fd0 fd1) + (with-alien ((pipe (function int (array int 2)) :extern "pipe") + (fds (array int 2))) + (let ((r (alien-funcall pipe fds))) + (if (minusp r) (syscall-error 'pipe) (values (deref fds 0) (deref fds 1))))) + (when filedes2 (setf (aref filedes2 0) fd0 (aref filedes2 1) fd1)) + (values fd0 fd1)))) #-win32 (define-protocol-class termios alien-termios () @@ -801,7 +804,8 @@ not supported." (if (minusp value) (syscall-error 'utimes) value))) - (let ((fun (extern-alien "sb_utimes" (function int (c-string :not-null t) + (let ((fun (extern-alien #-netbsd "utimes" #+netbsd "sb_utimes" + (function int (c-string :not-null t) (* (array alien-timeval 2))))) (name (filename filename))) (if (not (and access-time modification-time)) diff --git a/contrib/sb-posix/libc-tests.lisp b/contrib/sb-posix/libc-tests.lisp index b4fa3334a1..19ab8822b5 100644 --- a/contrib/sb-posix/libc-tests.lisp +++ b/contrib/sb-posix/libc-tests.lisp @@ -1,5 +1,4 @@ -(defpackage #:sb-libc-tests (:use #:cl #:sb-rt)) -(in-package "SB-LIBC-TESTS") +(in-package "SB-POSIX-TESTS") (defparameter *tests* ; unicode strings (by default unless #-sb-unicode) #("1.20203" "3.4400" "3240.2205" "10088.92" "12.3" "1000000000e-2" diff --git a/contrib/sb-posix/macros.lisp b/contrib/sb-posix/macros.lisp index f8bdc7c914..82382c4b4e 100644 --- a/contrib/sb-posix/macros.lisp +++ b/contrib/sb-posix/macros.lisp @@ -99,16 +99,18 @@ a FILE-STREAM designating the underlying file-descriptor." (if (sb-sys:find-foreign-symbol-address c-name) `(progn (declaim (inline ,lisp-name)) - (defun ,lisp-name ,(mapcar #'car arguments) + (defun ,lisp-name ,(mapcar #'car (remove '&optional arguments)) (let ((r (alien-funcall (extern-alien ,c-name (function ,return-type ,@(mapcar (lambda (x) - (gethash (cadr x) - *designator-types* - (cadr x))) + (if (eq x '&optional) + x + (gethash (cadr x) + *designator-types* + (cadr x)))) arguments))) ,@(mapcar (lambda (x) (if (nth-value 1 @@ -118,7 +120,7 @@ a FILE-STREAM designating the underlying file-descriptor." :sb-posix) ,(car x)) (car x))) - arguments)))) + (remove '&optional arguments))))) (if (,error-predicate r) (syscall-error ',lisp-name) r)))) `(sb-int:style-warn "Didn't find definition for ~S" ,c-name))) diff --git a/contrib/sb-posix/posix-tests.lisp b/contrib/sb-posix/posix-tests.lisp index 450def9a40..475f54ea5a 100644 --- a/contrib/sb-posix/posix-tests.lisp +++ b/contrib/sb-posix/posix-tests.lisp @@ -1,19 +1,16 @@ (defpackage "SB-POSIX-TESTS" - (:use "COMMON-LISP" "SB-RT")) + (:import-from #:test-util #:deftest) + (:use "COMMON-LISP")) (in-package "SB-POSIX-TESTS") -(defvar *test-directory* - (ensure-directories-exist - (merge-pathnames (make-pathname :directory '(:relative "test-output")) - (make-pathname :directory - (pathname-directory *load-truename*))))) +(defvar *test-directory* test-util:*test-directory*) (defvar *current-directory* *default-pathname-defaults*) (defvar *this-file* *load-truename*) -(eval-when (:compile-toplevel :load-toplevel) +(eval-when (:compile-toplevel :load-toplevel :execute) (defconstant +mode-rwx-all+ (logior sb-posix::s-irusr sb-posix::s-iwusr sb-posix::s-ixusr #-win32 @@ -174,17 +171,11 @@ (sb-posix:syscall-error (c) (typep (sb-posix:syscall-errno c) - '(member - #+(or darwin openbsd) - #.sb-posix:eisdir - #+win32 - #.sb-posix::eacces - #+win32 - #.sb-posix::enotempty - #+sunos - #.sb-posix::einval - #-(or darwin openbsd win32 sunos) - #.sb-posix::ebusy)))) t) + `(member #+(or darwin openbsd freebsd) ,sb-posix:eisdir + #+win32 ,sb-posix::eacces #+win32 ,sb-posix::enotempty + #+sunos ,sb-posix::einval + #-(or darwin openbsd freebsd win32 sunos) ,sb-posix::ebusy)))) + t) (deftest rmdir.error.4 (let* ((dir (ensure-directories-exist @@ -237,13 +228,10 @@ #-(or (and darwin x86) win32) (deftest stat.2 - (let* ((stat (sb-posix:stat "/")) - (mode (sb-posix::stat-mode stat))) - ;; it's logically possible for / to be writeable by others... but - ;; if it is, either someone is playing with strange security - ;; modules or they want to know about it anyway. - (logand mode sb-posix::s-iwoth)) - 0) + (eql + (sb-posix::stat-mode (sb-posix:stat "/")) + (sb-posix::stat-mode (sb-posix:stat (make-pathname :directory '(:absolute :up))))) + t) (deftest stat.3 (let* ((now (get-universal-time)) @@ -256,16 +244,6 @@ (< (- atime unix-now) 10)) t) -#-(or (and darwin x86) win32) -(deftest stat.4 - (let* ((stat (sb-posix:stat (make-pathname :directory '(:absolute :up)))) - (mode (sb-posix::stat-mode stat))) - ;; it's logically possible for / to be writeable by others... but - ;; if it is, either someone is playing with strange security - ;; modules or they want to know about it anyway. - (logand mode sb-posix::s-iwoth)) - 0) - ;; Test that stat can take a second argument. #-win32 (deftest stat.5 @@ -403,6 +381,7 @@ (let ((file (format nil "~A/[foo].txt" (namestring *test-directory*)))) ;; creat() with a string as argument (let ((fd (sb-posix:creat file sb-posix:s-iwrite))) + (declare (ignorable fd)) #+win32 (sb-posix:close fd)) ;; if this test fails, it will probably be with @@ -423,7 +402,6 @@ (ignore-errors (sb-posix:unlink name)))) nil) -#-hpux ; fix: cant handle c-vargs (deftest open.error.1 (handler-case (sb-posix:open *test-directory* sb-posix::o-wronly) (sb-posix:syscall-error (c) @@ -442,14 +420,14 @@ sb-posix::o-nonblock)) t) -#-(or hpux win32 netbsd) ; fix: cant handle c-vargs +#-(or win32 netbsd) ; fix: cant handle c-vargs (deftest fcntl.flock.1 (locally (declare (sb-ext:muffle-conditions sb-ext:compiler-note)) (let ((flock (make-instance 'sb-posix:flock :type sb-posix:f-wrlck :whence sb-posix:seek-set :start 0 :len 10)) - (pathname "fcntl.flock.1") + (pathname (merge-pathnames #P"fcntl.flock.1" *test-directory*)) kid-status) (catch 'test (with-open-file (f pathname :direction :output) @@ -484,7 +462,7 @@ :type sb-posix:f-wrlck :whence sb-posix:seek-set :start 0 :len 10)) - (pathname "fcntl.flock.2") + (pathname (merge-pathnames #P"fcntl.flock.2" *test-directory*)) kid-status) (catch 'test (with-open-file (f pathname :direction :output) @@ -548,27 +526,25 @@ t) #-darwin -(deftest readdir/dirent-name - (let ((dir (sb-posix:opendir *current-directory*))) - (unwind-protect - (equal (sort (loop for entry = (sb-posix:readdir dir) - until (sb-alien:null-alien entry) - collect (sb-posix:dirent-name entry)) - #'string<) - (sort (append '("." "..") - (mapcar (lambda (p) - (let ((string (enough-namestring p *current-directory*))) - (if (pathname-name p) - string - (subseq string 0 (1- (length string)))))) - (directory (make-pathname - :name :wild +(test-util:with-test (:name :readdir/dirent-name) + (let* ((dir (sb-posix:opendir *current-directory*)) + (posix-readdir (loop for entry = (sb-posix:readdir dir) + until (sb-alien:null-alien entry) + collect (sb-posix:dirent-name entry))) + (cl-directory + (append '("." "..") + (mapcar (lambda (p) + (let ((string (enough-namestring p *current-directory*))) + (if (pathname-name p) + string + (subseq string 0 (1- (length string)))))) + (directory (make-pathname :name :wild :type :wild - :defaults *current-directory*)))) - #'string<)) - (sb-posix:closedir dir))) - t) - + :defaults *current-directory*) + :resolve-symlinks nil))))) + (sb-posix:closedir dir) + (assert (equal (sort posix-readdir #'string<) + (sort cl-directory #'string<))))) (deftest write.1 (progn @@ -603,7 +579,7 @@ ;; make sure that we get something sensible, not an error (handler-case (progn (sb-posix:getpwnam "almost-certainly-does-not-exist") nil) - (t (cond) t)) + (t (cond) (declare (ignore cond)) t)) nil) #-(or android win32) @@ -626,7 +602,7 @@ ;; make sure that we get something sensible, not an error (handler-case (progn (sb-posix:getgrnam "almost-certainly-does-not-exist") nil) - (t (cond) t)) + (t (cond) (declare (ignore cond)) t)) nil) #+nil @@ -666,21 +642,24 @@ t) #-(or (and darwin x86) win32) -(deftest utimes.1 - (let ((file (merge-pathnames #p"utimes.1" *test-directory*)) - (atime (random (1- (expt 2 31)))) - (mtime (random (1- (expt 2 31))))) - (with-open-file (stream file - :direction :output - :if-exists :supersede - :if-does-not-exist :create) - (princ "Hello, utimes" stream)) - (sb-posix:utime file atime mtime) - (let* ((stat (sb-posix:stat file))) - (delete-file file) - (list (= (sb-posix:stat-atime stat) atime) - (= (sb-posix:stat-mtime stat) mtime)))) - (t t)) +(macrolet ((test (name posix-fun) + `(deftest ,name + (let ((file (merge-pathnames #p"utimes.1" *test-directory*)) + (atime (random (1- (expt 2 31)))) + (mtime (random (1- (expt 2 31))))) + (with-open-file (stream file + :direction :output + :if-exists :supersede + :if-does-not-exist :create) + (princ "Hello, utimes" stream)) + (,posix-fun file atime mtime) + (let* ((stat (sb-posix:stat file))) + (delete-file file) + (list (= (sb-posix:stat-atime stat) atime) + (= (sb-posix:stat-mtime stat) mtime)))) + (t t)))) + (test utime.1 sb-posix:utime) + (test utimes.1 sb-posix:utimes)) ;; readlink tests. #-win32 @@ -697,7 +676,6 @@ ;; Same thing, but with a very long link target (which doesn't have ;; to exist). This tests the array adjustment in the wrapper, ;; provided that the target's length is long enough. - #-hpux ; arg2 to readlink is 80, and arg0 is larger than that (deftest readlink.2 (let ((target-pathname (make-pathname :name (make-string 255 :initial-element #\a) @@ -711,6 +689,7 @@ #.(concatenate 'string "/" (make-string 255 :initial-element #\a))) ;; The error tests are in the order of exposition from SUSv3. + #-freebsd (deftest readlink.error.1 (let* ((subdir-pathname (merge-pathnames (make-pathname @@ -726,9 +705,9 @@ (sb-posix:syscall-error (c) (sb-posix:syscall-errno c))) (ignore-errors - (sb-posix:chmod subdir-pathname #o777) - (sb-posix:unlink link-pathname) - (sb-posix:rmdir subdir-pathname)))) + (sb-posix:chmod subdir-pathname #o777) + (sb-posix:unlink link-pathname) + (sb-posix:rmdir subdir-pathname)))) #.sb-posix:eacces) (deftest readlink.error.2 (let* ((non-link-pathname (make-pathname :name "readlink.error.2" @@ -836,9 +815,8 @@ (delete-file temp)))) t "mkstemp-1") -;#-(or win32 sunos hpux) ;;;; mkdtemp is unimplemented on at least Solaris 10 -#-(or win32 hpux sunos) +#-(or win32 sunos) ;;; But it is implemented on OpenSolaris 2008.11 (deftest mkdtemp.1 (let ((pathname diff --git a/contrib/sb-posix/sb-posix.asd b/contrib/sb-posix/sb-posix.asd index 6965f7cff2..5910b61690 100644 --- a/contrib/sb-posix/sb-posix.asd +++ b/contrib/sb-posix/sb-posix.asd @@ -14,32 +14,4 @@ (:sb-grovel-constants-file "constants" :package :sb-posix :depends-on ("defpackage")) (:file "interface" :depends-on ("constants" "macros" "designator"))) - :perform (load-op :after (o c) (provide 'sb-posix)) - :in-order-to ((test-op (test-op "sb-posix/tests")))) - -(defsystem "sb-posix/tests" - :depends-on ("sb-rt") - #+sb-building-contrib :pathname - #+sb-building-contrib #p"SYS:CONTRIB;SB-POSIX;" - :components ((:file "libc-tests") - (:file "posix-tests")) - :perform - (test-op (o c) - (funcall (intern "DO-TESTS" (find-package "SB-RT"))) - (let ((failures (funcall (intern "PENDING-TESTS" "SB-RT"))) - (ignored-failures (loop for sym being the symbols of :sb-posix-tests - if (search ".ERROR" (symbol-name sym)) - collect sym))) - (cond - ((null failures) - t) - ((null (set-difference failures ignored-failures)) - (warn "~@") - t) - (t - (error "non-errno tests failed!")))))) + :perform (load-op :after (o c) (provide 'sb-posix))) diff --git a/contrib/sb-posix/strtod.lisp b/contrib/sb-posix/strtod.lisp index 232ce5a3d8..4cf3f885fa 100644 --- a/contrib/sb-posix/strtod.lisp +++ b/contrib/sb-posix/strtod.lisp @@ -28,7 +28,7 @@ and a secondary value, the number of characters consumed." (when (typep string 'base-string) (sb-kernel:with-array-data ((data string) (start) (end) :check-fill-pointer t) (when (eql (locally - (declare (optimize (sb-c::insert-array-bounds-checks 0))) + (declare (optimize (sb-c:insert-array-bounds-checks 0))) (schar data (1+ end))) #\Nul) (return-from strtod (strtod/base-string data start))))) ;; Short simple non-base string, or base-string w/o a null in the right place diff --git a/contrib/sb-rotate-byte/compiler.lisp b/contrib/sb-rotate-byte/compiler.lisp index e0dda24ae0..3391b6896e 100644 --- a/contrib/sb-rotate-byte/compiler.lisp +++ b/contrib/sb-rotate-byte/compiler.lisp @@ -18,21 +18,24 @@ (macrolet (;; see src/compiler/srctran.lisp (with-byte-specifier ((size-var pos-var spec) &body body) - (once-only ((spec `(macroexpand ,spec)) + (once-only ((spec `(handler-case (macroexpand ,spec) + (error () + (return (values nil t))))) (temp '(gensym))) - `(if (and (consp ,spec) - (eq (car ,spec) 'byte) - (= (length ,spec) 3)) - (let ((,size-var (second ,spec)) - (,pos-var (third ,spec))) - ,@body) - (let ((,size-var `(byte-size ,,temp)) - (,pos-var `(byte-position ,,temp))) - `(let ((,,temp ,,spec)) - ,,@body)))))) + `(if (and (consp ,spec) + (eq (car ,spec) 'byte) + (= (length ,spec) 3)) + (let ((,size-var (second ,spec)) + (,pos-var (third ,spec))) + ,@body) + (let ((,size-var `(byte-size ,,temp)) + (,pos-var `(byte-position ,,temp))) + `(let ((,,temp ,,spec)) + ,,@body)))))) (define-source-transform rotate-byte (count spec num) - (with-byte-specifier (size pos spec) - `(%rotate-byte ,count ,size ,pos ,num)))) + (block nil + (with-byte-specifier (size pos spec) + `(%rotate-byte ,count ,size ,pos ,num))))) (defoptimizer (%rotate-byte derive-type) ((count size posn num)) ;; FIXME: this looks fairly unwieldy. I'm sure it can be made @@ -42,7 +45,7 @@ (if (numeric-type-p size) (let ((size-high (numeric-type-high size)) (num-type (sb-c::lvar-type num))) - (if (and size-high + (if (and (typep size-high '(integer 1)) num-type (<= size-high sb-vm:n-word-bits) (csubtypep num-type @@ -84,6 +87,6 @@ ;;; first crack at a zero COUNT, since transforms are currently run ;;; latest-defined first. (deftransform %rotate-byte ((count size pos integer) - ((constant-arg (member 0)) * * *) *) + ((constant-arg (member 0)) t t t) *) "fold identity operation" 'integer) diff --git a/contrib/sb-rotate-byte/sb-rotate-byte.asd b/contrib/sb-rotate-byte/sb-rotate-byte.asd index 60ecfd0c91..fa3080fd9c 100644 --- a/contrib/sb-rotate-byte/sb-rotate-byte.asd +++ b/contrib/sb-rotate-byte/sb-rotate-byte.asd @@ -22,11 +22,4 @@ (:file "ppc-vm" :if-feature :ppc) (:file "ppc64-vm" :if-feature :ppc64))) (:file "rotate-byte" :depends-on ("vm"))) - :perform (load-op :after (o c) (provide 'sb-rotate-byte)) - :in-order-to ((test-op (test-op "sb-rotate-byte/tests")))) - -(defsystem "sb-rotate-byte/tests" - #+sb-building-contrib :pathname - #+sb-building-contrib #p"SYS:CONTRIB;SB-ROTATE-BYTE;" - :depends-on ("sb-rotate-byte") - :components ((:file "rotate-byte-tests"))) + :perform (load-op :after (o c) (provide 'sb-rotate-byte))) diff --git a/contrib/sb-simd/CREDITS b/contrib/sb-simd/CREDITS new file mode 100644 index 0000000000..f6a7a451d5 --- /dev/null +++ b/contrib/sb-simd/CREDITS @@ -0,0 +1,8 @@ +sb-simd was developed by: + +Marco Heisig +Bela Pecsek +Tomas Wain +Stas Boukarev + +The detailed project history is archived at github.com/marcoheisig/sb-simd diff --git a/contrib/sb-simd/Makefile b/contrib/sb-simd/Makefile new file mode 100644 index 0000000000..96ad88feb5 --- /dev/null +++ b/contrib/sb-simd/Makefile @@ -0,0 +1,2 @@ +SYSTEM=sb-simd +include ../asdf-module.mk diff --git a/contrib/sb-simd/code/constants.lisp b/contrib/sb-simd/code/constants.lisp new file mode 100644 index 0000000000..6027fe53e9 --- /dev/null +++ b/contrib/sb-simd/code/constants.lisp @@ -0,0 +1,50 @@ +(in-package #:sb-simd-internals) + +(defconstant most-positive-f32 most-positive-single-float) +(defconstant most-negative-f32 most-negative-single-float) +(defconstant most-positive-f64 most-positive-double-float) +(defconstant most-negative-f64 most-negative-double-float) + +(defconstant most-positive-u1 (1- (expt 2 1))) +(defconstant most-positive-u2 (1- (expt 2 2))) +(defconstant most-positive-u4 (1- (expt 2 4))) +(defconstant most-positive-u8 (1- (expt 2 8))) +(defconstant most-positive-u16 (1- (expt 2 16))) +(defconstant most-positive-u32 (1- (expt 2 32))) +(defconstant most-positive-u64 (1- (expt 2 64))) + +(defconstant +u8-true+ most-positive-u8) +(defconstant +u16-true+ most-positive-u16) +(defconstant +u32-true+ most-positive-u32) +(defconstant +u64-true+ most-positive-u64) + +(defconstant +u8-false+ 0) +(defconstant +u16-false+ 0) +(defconstant +u32-false+ 0) +(defconstant +u64-false+ 0) + +(defconstant most-positive-s8 (1- (expt 2 (1- 8)))) +(defconstant most-positive-s16 (1- (expt 2 (1- 16)))) +(defconstant most-positive-s32 (1- (expt 2 (1- 32)))) +(defconstant most-positive-s64 (1- (expt 2 (1- 64)))) + +(defconstant most-negative-s8 (- (expt 2 (1- 8)))) +(defconstant most-negative-s16 (- (expt 2 (1- 16)))) +(defconstant most-negative-s32 (- (expt 2 (1- 32)))) +(defconstant most-negative-s64 (- (expt 2 (1- 64)))) + +(defconstant +s8-true+ -1) +(defconstant +s16-true+ -1) +(defconstant +s32-true+ -1) +(defconstant +s64-true+ -1) + +(defconstant +s8-false+ 0) +(defconstant +s16-false+ 0) +(defconstant +s32-false+ 0) +(defconstant +s64-false+ 0) + +(defconstant +f32-true+ (sb-kernel:make-single-float +s32-true+)) +(defconstant +f64-true+ (sb-kernel:make-double-float +s32-true+ +u32-true+)) + +(defconstant +f32-false+ (sb-kernel:make-single-float +s32-false+)) +(defconstant +f64-false+ (sb-kernel:make-double-float +s32-false+ +u32-false+)) diff --git a/contrib/sb-simd/code/cpu-identification.lisp b/contrib/sb-simd/code/cpu-identification.lisp new file mode 100644 index 0000000000..2981f29f5e --- /dev/null +++ b/contrib/sb-simd/code/cpu-identification.lisp @@ -0,0 +1,72 @@ +(in-package #:sb-simd-internals) + +#+x86-64 +(progn + (defun cpuid (eax &optional (ecx 0)) + (declare (type (unsigned-byte 32) eax ecx)) + (sb-vm::%cpu-identification eax ecx)) + + (defun sse-supported-p () + (and (>= (cpuid 0) 1) + (logbitp 25 (nth-value 3 (cpuid 1))))) + + (defun sse2-supported-p () + (and (>= (cpuid 0) 1) + (logbitp 26 (nth-value 3 (cpuid 1))))) + + (defun sse3-supported-p () + (and (>= (cpuid 0) 1) + (logbitp 0 (nth-value 2 (cpuid 1))))) + + (defun ssse3-supported-p () + (and (>= (cpuid 0) 1) + (logbitp 9 (nth-value 2 (cpuid 1))))) + + (defun sse4.1-supported-p () + (and (>= (cpuid 0) 1) + (logbitp 19 (nth-value 2 (cpuid 1))))) + + (defun sse4.2-supported-p () + (and (>= (cpuid 0) 1) + (logbitp 20 (nth-value 2 (cpuid 1))))) + + (defun avx-supported-p () + (and (>= (cpuid 0) 1) + (logbitp 28 (nth-value 2 (cpuid 1))))) + + (defun avx2-supported-p () + (and (>= (cpuid 0) 7) + (logbitp 5 (nth-value 1 (cpuid 7))))) + + (defun fma-supported-p () + (and (>= (cpuid 0) 1) + (logbitp 12 (nth-value 2 (cpuid 1)))))) + +#-x86-64 +(progn + (defun sse-supported-p () + nil) + + (defun sse2-supported-p () + nil) + + (defun sse3-supported-p () + nil) + + (defun ssse3-supported-p () + nil) + + (defun sse4.1-supported-p () + nil) + + (defun sse4.2-supported-p () + nil) + + (defun avx-supported-p () + nil) + + (defun avx2-supported-p () + nil) + + (defun fma-supported-p () + nil)) diff --git a/contrib/sb-simd/code/define-arefs.lisp b/contrib/sb-simd/code/define-arefs.lisp new file mode 100644 index 0000000000..4cf42304be --- /dev/null +++ b/contrib/sb-simd/code/define-arefs.lisp @@ -0,0 +1,179 @@ +(in-package #:sb-simd-internals) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; +;;; Auxiliary Functions and Macros + +(declaim (notinline wrong-number-of-subscripts)) +(defun wrong-number-of-subscripts (array number-of-subscripts) + (error "Wrong number of subcripts, ~S, for an array of rank ~S." + number-of-subscripts + (array-rank array))) + +(declaim (notinline invalid-subscript)) +(defun invalid-subscript (subscript array axis limit) + (declare (ignore array)) + (error "Invalid array subscript ~S for axis ~S, ~ + should be a non-negative integer below ~S." + subscript axis limit)) + +;; This function doesn't have to be particularly fast, because all index +;; computations where the number of subscripts is known at compile time are +;; expanded by compiler macros and WITH-ROW-MAJOR-SIMD-INDEX. The only way +;; to reach this function is when an array indexing function is supplied as +;; the first argument to APPLY or FUNCALL. +(defun array-row-major-simd-index (array simd-width &rest subscripts) + (let ((rank (array-rank array)) + (length (length subscripts))) + (unless (= rank length) + (wrong-number-of-subscripts array length)) + (let ((stride 1) + (index 0)) + (declare (index stride index)) + (loop for axis from (1- rank) downto 0 + for subscript = (nth axis subscripts) + for dimension = (array-dimension array axis) + for width = simd-width then 1 do + (unless (<= -1 subscript (- dimension width)) + (invalid-subscript subscript array axis (1+ (- dimension width)))) + (incf index (* stride subscript)) + (setf stride (* stride dimension))) + index))) + +(defmacro with-row-major-simd-index + ((index array simd-width &rest indices) &body body &environment env) + (check-type index symbol) + (check-type array symbol) + (check-type simd-width (integer 1)) + (dolist (index indices) + (check-type index symbol)) + (let* ((length (length indices)) + (rank-binding `(,(gensym "RANK") (array-rank ,array))) + (rank (first rank-binding)) + (dimension-bindings + (loop for axis below length + collect `(,(gensym "DIMENSION") (array-dimension ,array ,axis)))) + (dimensions (mapcar #'first dimension-bindings)) + (stride-bindings + (loop for axis from (- length 2) downto 0 + for old-stride = nil then new-stride + for new-stride = (gensym "STRIDE") + for stride-binding = `(,new-stride ,(nth axis dimensions)) + then `(,new-stride (index* ,(nth axis dimensions) ,old-stride)) + collect stride-binding)) + (strides (reverse (mapcar #'first stride-bindings))) + (index-form + `(index+ + ,@(loop for stride in strides + for index in indices + collect `(index* ,stride ,index)) + ,(first (last indices))))) + `(let (,rank-binding) + (unless (= ,rank ,length) + (wrong-number-of-subscripts ,array ,length)) + (let (,@dimension-bindings) + (declare (ignorable ,@dimensions)) + ,@(when (sb-c:policy env (plusp sb-c::insert-array-bounds-checks)) + (loop for axis from 0 + for dimension in dimensions + for index in indices + for limit = (if (= axis (1- length)) `(- ,dimension ,(1- simd-width)) dimension) + collect `(unless (< -1 ,index ,limit) + (invalid-subscript ,index ,array ,axis ,limit)))) + (let* (,@stride-bindings) + (let ((,index ,index-form)) + ,@body)))))) + +(defun setf-row-major-aref (v a i) + (setf (row-major-aref a i) v)) + +(define-compiler-macro setf-row-major-aref (v a i) + (let* ((v-binding `(,(gensym "VALUE") ,v)) + (v (first v-binding))) + `(let (,v-binding) + (setf (row-major-aref ,a ,i) ,v)))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; +;;; Array Load and Store Instructions + +(macrolet + ((define-aref (load-record-name) + (with-accessors ((load load-record-name) + (aref load-record-aref) + (row-major-aref load-record-row-major-aref) + (value-record load-record-value-record) + (vector-record load-record-vector-record)) + (find-function-record load-record-name) + (let ((simd-width (value-record-simd-width value-record)) + (element-type + (second + (value-record-type vector-record)))) + `(progn + (define-inline ,row-major-aref (array index) + (declare (type (array ,element-type) array) + (index index)) + (,load array index)) + (defun ,aref (array &rest indices) + (declare (type (array ,element-type) array)) + (,load + array + (apply #'array-row-major-simd-index array ,simd-width indices))) + (define-compiler-macro ,aref (array &rest indices) + (let* ((index (gensym "INDEX")) + (array-binding `(,(gensym "ARRAY") ,array)) + (index-bindings + (loop for index-form in indices + collect `(,(gensym "INDEX") ,index-form))) + (array (first array-binding)) + (indices (mapcar #'first index-bindings))) + `(let (,array-binding ,@index-bindings) + (declare (type (array ,',element-type) ,array)) + (with-row-major-simd-index (,index ,array ,',simd-width ,@indices) + (,',load ,array ,index))))))))) + (define-setf-aref (store-record-name) + (with-accessors ((store store-record-name) + (aref store-record-aref) + (row-major-aref store-record-row-major-aref) + (value-record store-record-value-record) + (vector-record store-record-vector-record)) + (find-function-record store-record-name) + (let ((value-type (value-record-name value-record)) + (simd-width (value-record-simd-width value-record)) + (element-type + (second + (value-record-type vector-record)))) + `(progn + (define-inline (setf ,row-major-aref) (value array index) + (declare (type (array ,element-type) array) + (index index)) + (,store (,value-type value) array index)) + (defun (setf ,aref) (value array &rest indices) + (declare (type (array ,element-type) array)) + (,store + (,value-type value) + array + (apply #'array-row-major-simd-index array ,simd-width indices))) + (define-compiler-macro (setf ,aref) (value array &rest indices) + (let* ((value-binding `(,(gensym "VALUE") ,value)) + (array-binding `(,(gensym "ARRAY") ,array)) + (index-bindings + (loop for index-form in indices + collect `(,(gensym "INDEX") ,index-form))) + (indices (mapcar #'first index-bindings)) + (value (first value-binding)) + (array (first array-binding)) + (index (gensym "INDEX"))) + `(let (,value-binding ,array-binding ,@index-bindings) + (declare (type (array ,',element-type) ,array)) + (with-row-major-simd-index (,index ,array ,',simd-width ,@indices) + (,',store (,',value-type ,value) ,array ,index))))))))) + (define-arefs () + `(progn + ,@(loop for load-record in (filter-function-records #'load-record-p) + for name = (load-record-name load-record) + collect `(define-aref ,name)) + ,@(loop for store-record in (filter-function-records #'store-record-p) + for name = (store-record-name store-record) + collect `(define-setf-aref ,name))))) + (define-arefs)) diff --git a/contrib/sb-simd/code/define-associatives.lisp b/contrib/sb-simd/code/define-associatives.lisp new file mode 100644 index 0000000000..48825e8945 --- /dev/null +++ b/contrib/sb-simd/code/define-associatives.lisp @@ -0,0 +1,58 @@ +(in-package #:sb-simd-internals) + +(macrolet + ((define-associative (associative-record-name) + (with-accessors ((name associative-record-name) + (binary-operation associative-record-binary-operation) + (identity-element associative-record-identity-element)) + (find-function-record associative-record-name) + (with-accessors ((binary-operation instruction-record-name) + (result-records instruction-record-result-records) + (argument-records instruction-record-argument-records) + (associative instruction-record-associative)) binary-operation + (assert associative) + (destructuring-bind ((value-record) (arg1-record arg2-record)) + (list result-records argument-records) + (assert (eq value-record arg1-record)) + (assert (eq value-record arg2-record)) + (let ((type (value-record-name value-record))) + (if (not identity-element) + `(progn + (defun ,name (arg &rest more-args) + (let ((result (,type arg))) + (declare (,type result)) + (loop for arg in more-args + do (setf result (,binary-operation result (,type arg)))) + result)) + (define-compiler-macro ,name (&whole whole &rest args) + (let ((n (length args))) + (case n + (0 whole) + (1 `(,',type ,(first args))) + (otherwise + `(,',binary-operation + (,',name ,@(subseq args 0 (floor n 2))) + (,',name ,@(subseq args (floor n 2))))))))) + `(progn + (defun ,name (&rest args) + (if (null args) + (,type ,identity-element) + (let ((result (,type (first args)))) + (declare (,type result)) + (loop for arg in (rest args) + do (setf result (,binary-operation result (,type arg)))) + result))) + (define-compiler-macro ,name (&rest args) + (let ((n (length args))) + (case n + (0 `(,',type ,,identity-element)) + (1 `(,',type ,(first args))) + (otherwise + `(,',binary-operation + (,',name ,@(subseq args 0 (floor n 2))) + (,',name ,@(subseq args (floor n 2))))))))))))))) + (define-associatives () + `(progn + ,@(loop for associative-record in (filter-function-records #'associative-record-p) + collect `(define-associative ,(associative-record-name associative-record)))))) + (define-associatives)) diff --git a/contrib/sb-simd/code/define-comparisons.lisp b/contrib/sb-simd/code/define-comparisons.lisp new file mode 100644 index 0000000000..58b336bc1c --- /dev/null +++ b/contrib/sb-simd/code/define-comparisons.lisp @@ -0,0 +1,47 @@ +(in-package #:sb-simd-internals) + +(macrolet + ((define-comparison (comparision-record-name) + (with-accessors ((name comparison-record-name) + (cmp comparison-record-cmp) + (and comparison-record-and) + (truth comparison-record-truth)) + (find-function-record comparision-record-name) + (with-accessors ((cmp instruction-record-name) + (result-records instruction-record-result-records) + (argument-records instruction-record-argument-records)) cmp + (destructuring-bind ((result-record) (argument-record other-argument-record)) + (list result-records argument-records) + (assert (eq argument-record other-argument-record)) + (let ((and (function-record-name and)) + (result-type (value-record-name result-record)) + (argument-type (value-record-name argument-record))) + `(progn + (defun ,name (arg &rest more-args) + (if (null more-args) + (progn (,argument-type arg) (,result-type ,truth)) + (let* ((a (,argument-type arg)) + (b (,argument-type (first more-args))) + (result (,cmp a b))) + (declare (,argument-type a b) + (,result-type result)) + (loop for elt in (rest more-args) + do (shiftf a b (,argument-type elt)) + do (setf result (,and result (,cmp a b)))) + result))) + (define-compiler-macro ,name (arg &rest more-args) + (if (null more-args) + `(progn (,',argument-type ,arg) (,',result-type ,',truth)) + (let ((bindings + (loop for arg in (list* arg more-args) + collect + (list (gensym "ARG") (list ',argument-type arg))))) + `(let ,bindings + (,',and ,@(loop for ((a nil) (b nil) . rest) on bindings + collect `(,',cmp ,a ,b) + until (null rest))))))))))))) + (define-comparisons () + `(progn + ,@(loop for comparison-record in (filter-function-records #'comparison-record-p) + collect `(define-comparison ,(comparison-record-name comparison-record)))))) + (define-comparisons)) diff --git a/contrib/sb-simd/code/define-custom-vops.lisp b/contrib/sb-simd/code/define-custom-vops.lisp new file mode 100644 index 0000000000..0fd034ebd7 --- /dev/null +++ b/contrib/sb-simd/code/define-custom-vops.lisp @@ -0,0 +1,167 @@ +(in-package #:sb-vm) + +(macrolet + ((define-custom-vop (name &body clauses) + (with-accessors ((name sb-simd-internals:instruction-record-name) + (vop sb-simd-internals:instruction-record-vop) + (argument-records sb-simd-internals:instruction-record-argument-records) + (result-records sb-simd-internals:instruction-record-result-records) + (cost sb-simd-internals:instruction-record-cost) + (encoding sb-simd-internals:instruction-record-encoding)) + (sb-simd-internals:find-function-record name) + (assert (eq encoding :custom)) + (labels ((find-clauses (key) + (remove key clauses :test-not #'eq :key #'first)) + (find-clause (key) + (let ((found (find-clauses key))) + (assert (= 1 (length found))) + (rest (first found))))) + `(sb-c:define-vop (,vop) + (:translate ,vop) + (:policy :fast-safe) + (:arg-types ,@(mapcar #'sb-simd-internals:value-record-primitive-type argument-records)) + (:result-types ,@(mapcar #'sb-simd-internals:value-record-primitive-type result-records)) + (:args + ,@(loop for arg in (find-clause :args) + for argument-record in argument-records + collect `(,@arg :scs ,(sb-simd-internals:value-record-scs argument-record)))) + ,@(find-clauses :info) + ,@(find-clauses :temporary) + (:results + ,@(loop for result in (find-clause :results) + for result-record in result-records + collect `(,@result :scs ,(sb-simd-internals:value-record-scs result-record)))) + (:generator ,cost ,@(find-clause :generator))))))) + ;; SSE + (macrolet ((def (name cmp) + `(define-custom-vop ,name + (:args (a :target tmp) (b)) + (:temporary (:sc single-reg :from (:argument 0)) tmp) + (:results (dst)) + (:generator + (unless (location= a tmp) + (inst xorps tmp tmp) + (inst movss tmp a)) + (inst cmpss ,cmp tmp b) + (inst movq dst tmp))))) + (def sb-simd-sse::two-arg-f32= :eq) + (def sb-simd-sse::two-arg-f32/= :neq) + (def sb-simd-sse::two-arg-f32< :lt) + (def sb-simd-sse::two-arg-f32<= :le) + (def sb-simd-sse::two-arg-f32> :nle) + (def sb-simd-sse::two-arg-f32>= :nlt)) + (define-custom-vop sb-simd-sse::f32-from-s64 + (:args (src)) + (:results (dst)) + (:generator + (inst xorps dst dst) + (inst cvtsi2ss dst src))) + (define-custom-vop sb-simd-sse::f32!-from-p128 + (:args (src :target dst)) + (:temporary (:sc single-sse-reg :from (:argument 0)) tmp) + (:results (dst)) + (:generator + (move tmp src) + (inst xorps dst dst) + (inst movss dst tmp))) + ;; SSE2 + (macrolet ((def (name cmp) + `(define-custom-vop ,name + (:args (a :target tmp) (b)) + (:temporary (:sc single-reg :from (:argument 0)) tmp) + (:results (dst)) + (:generator + (unless (location= a tmp) + (inst xorpd tmp tmp) + (inst movsd tmp a)) + (inst cmpsd ,cmp tmp b) + (inst movq dst tmp))))) + (def sb-simd-sse2::two-arg-f64= :eq) + (def sb-simd-sse2::two-arg-f64/= :neq) + (def sb-simd-sse2::two-arg-f64< :lt) + (def sb-simd-sse2::two-arg-f64<= :le) + (def sb-simd-sse2::two-arg-f64> :nle) + (def sb-simd-sse2::two-arg-f64>= :nlt)) + (define-custom-vop sb-simd-sse2::f64-from-s64 + (:args (src)) + (:results (dst)) + (:generator + (inst xorpd dst dst) + (inst cvtsi2sd dst src))) + (define-custom-vop sb-simd-sse2::f64!-from-p128 + (:args (src :target tmp)) + (:temporary (:sc double-sse-reg :from (:argument 0)) tmp) + (:results (dst)) + (:generator + (move tmp src) + (inst xorpd dst dst) + (inst movsd dst tmp))) + ;; AVX + (macrolet ((def (name cmp) + `(define-custom-vop ,name + (:args (a :target tmp) (b)) + (:temporary (:sc single-reg :from (:argument 0)) tmp) + (:results (dst)) + (:generator + (unless (location= a tmp) + (inst vxorps tmp tmp tmp)) + (inst vcmpss ,cmp tmp a b) + (inst vmovq dst tmp))))) + (def sb-simd-avx::two-arg-f32= :eq) + (def sb-simd-avx::two-arg-f32/= :neq) + (def sb-simd-avx::two-arg-f32< :lt) + (def sb-simd-avx::two-arg-f32<= :le) + (def sb-simd-avx::two-arg-f32> :nle) + (def sb-simd-avx::two-arg-f32>= :nlt)) + (macrolet ((def (name cmp) + `(define-custom-vop ,name + (:args (a :target tmp) (b)) + (:temporary (:sc single-reg :from (:argument 0)) tmp) + (:results (dst)) + (:generator + (unless (location= a tmp) + (inst vxorpd tmp tmp tmp)) + (inst vcmpsd ,cmp tmp a b) + (inst vmovq dst tmp))))) + (def sb-simd-avx::two-arg-f64= :eq) + (def sb-simd-avx::two-arg-f64/= :neq) + (def sb-simd-avx::two-arg-f64< :lt) + (def sb-simd-avx::two-arg-f64<= :le) + (def sb-simd-avx::two-arg-f64> :nle) + (def sb-simd-avx::two-arg-f64>= :nlt)) + (define-custom-vop sb-simd-avx::f32-from-s64 + (:args (src :to :save)) + (:results (dst)) + (:generator + (inst vxorpd dst dst dst) + (inst vcvtsi2ss dst dst src))) + (define-custom-vop sb-simd-avx::f64-from-s64 + (:args (src :to :save)) + (:results (dst)) + (:generator + (inst vxorpd dst dst dst) + (inst vcvtsi2sd dst dst src))) + (define-custom-vop sb-simd-avx::f32!-from-p128 + (:args (src :to :save)) + (:results (dst)) + (:generator + (inst vxorps dst dst dst) + (inst movss dst src))) + (define-custom-vop sb-simd-avx::f32!-from-p256 + (:args (src :to :save)) + (:results (dst)) + (:generator + (inst vxorps dst dst dst) + (inst movss dst src))) + (define-custom-vop sb-simd-avx::f64!-from-p128 + (:args (src :to :save)) + (:results (dst)) + (:generator + (inst vxorpd dst dst dst) + (inst movsd dst src))) + (define-custom-vop sb-simd-avx::f64!-from-p256 + (:args (src :to :save)) + (:results (dst)) + (:generator + (inst vxorpd dst dst dst) + (inst movsd dst src)))) diff --git a/contrib/sb-simd/code/define-fake-vops.lisp b/contrib/sb-simd/code/define-fake-vops.lisp new file mode 100644 index 0000000000..4432791c4d --- /dev/null +++ b/contrib/sb-simd/code/define-fake-vops.lisp @@ -0,0 +1,1718 @@ +(in-package #:sb-simd-internals) + +;;; Primitives with a :NONE encoding do not define a VOP. Instead, we +;;; define a fake VOP - a regular function that has the name of the VOP +;;; that would have been generated if the encoding wasn't :NONE. Fake VOPs +;;; are useful for defining instructions that we would like to have in the +;;; instruction set, and that can be expressed easily in terms of the other +;;; VOPs. + +(defmacro define-fake-vop (name lambda-list &body body) + (with-accessors ((vop instruction-record-vop) + (result-records instruction-record-result-records) + (argument-records instruction-record-argument-records) + (instruction-set instruction-record-instruction-set)) + (find-function-record name) + (assert (= (length lambda-list) + (length argument-records))) + (assert (null (intersection lambda-list lambda-list-keywords))) + (when (instruction-set-available-p instruction-set) + `(define-inline ,vop ,lambda-list + (declare (optimize (safety 0) (debug 0))) + (declare + ,@(loop for argument-record in argument-records + for argument in lambda-list + collect `(type ,(value-record-name argument-record) ,argument))) + (the (values ,@(mapcar #'value-record-name result-records) &optional) + (progn ,@body)))))) + +(defmacro define-trivial-fake-vop (name operator &key key result-key) + (let* ((record (find-function-record name)) + (arity (length (instruction-record-argument-records record))) + (args (prefixed-symbols "ARG" arity))) + (assert (= 1 (length (instruction-record-result-records record)))) + (flet ((wrap (key expr) + (if (null key) expr `(,key ,expr)))) + `(define-fake-vop ,name ,args + ,(wrap result-key `(,operator ,@(loop for arg in args collect (wrap key arg)))))))) + +(in-package #:sb-simd) + +(macrolet ((define-u64-packer (name scalar-record-name) + (with-accessors ((type value-record-name) + (bits value-record-bits)) + (find-value-record scalar-record-name) + (let ((args (prefixed-symbols "ARG" (the integer (/ 64 bits))))) + `(define-fake-vop ,name ,args + (logior + ,@(loop for arg in args + for position from 0 by bits + collect `(dpb ,arg (byte ,bits ,position) 0)))))))) + (define-u64-packer u64-from-u8s u8) + (define-u64-packer u64-from-u16s u16) + (define-u64-packer u64-from-u32s u32) + (define-u64-packer u64-from-s8s s8) + (define-u64-packer u64-from-s16s s16) + (define-u64-packer u64-from-s32s s32) + (define-u64-packer u64-from-s64 s64)) + +(macrolet ((define-u64-unpacker (name scalar-record-name) + (with-accessors ((type value-record-name) + (bits value-record-bits)) + (find-value-record scalar-record-name) + `(define-fake-vop ,name (x) + (values + ,@ (loop repeat (/ 64 bits) + for position from 0 by bits + collect + (if (subtypep type 'unsigned-byte) + `(ldb (byte ,bits ,position) x) + `(- (mod (+ (ldb (byte ,bits ,position) x) + ,(expt 2 (1- bits))) + ,(expt 2 bits)) + ,(expt 2 (1- bits)))))))))) + + (define-u64-unpacker u8s-from-u64 u8) + (define-u64-unpacker u16s-from-u64 u16) + (define-u64-unpacker u32s-from-u64 u32) + (define-u64-unpacker s8s-from-u64 s8) + (define-u64-unpacker s16s-from-u64 s16) + (define-u64-unpacker s32s-from-u64 s32) + (define-u64-unpacker s64-from-u64 s64)) + +(macrolet ((define-deboolifier (name true false) + `(define-inline ,name (expr) (if expr ,true ,false)))) + (define-deboolifier u8-from-boolean +u8-true+ +u8-false+) + (define-deboolifier u16-from-boolean +u16-true+ +u16-false+) + (define-deboolifier u32-from-boolean +u32-true+ +u32-false+) + (define-deboolifier u64-from-boolean +u64-true+ +u64-false+)) + +(defun u16-odd-bits (x) + (declare (type (unsigned-byte 16) x)) + (setf x (logand (ash x -1) #x5555)) + (setf x (logand (logior (ash x -1) x) #x3333)) + (setf x (logand (logior (ash x -2) x) #x0F0F)) + (setf x (logand (logior (ash x -4) x) #x00FF)) + x) + +(defun u32-odd-bits (x) + (declare (type (unsigned-byte 32) x)) + (setf x (logand (ash x -1) #x55555555)) + (setf x (logand (logior (ash x -1) x) #x33333333)) + (setf x (logand (logior (ash x -2) x) #x0F0F0F0F)) + (setf x (logand (logior (ash x -4) x) #x00FF00FF)) + (setf x (logand (logior (ash x -8) x) #x0000FFFF)) + x) + +;;; f32 + +(define-fake-vop f32-if (mask a b) + (if (logbitp 31 mask) a b)) + +(macrolet ((def (name op &rest keywords) `(define-trivial-fake-vop ,name ,op ,@keywords))) + (def two-arg-f32-and logand :key sb-kernel:single-float-bits :result-key sb-kernel:make-single-float) + (def two-arg-f32-or logior :key sb-kernel:single-float-bits :result-key sb-kernel:make-single-float) + (def two-arg-f32-xor logxor :key sb-kernel:single-float-bits :result-key sb-kernel:make-single-float) + (def f32-andc1 logandc1 :key sb-kernel:single-float-bits :result-key sb-kernel:make-single-float) + (def f32-not lognot :key sb-kernel:single-float-bits :result-key sb-kernel:make-single-float) + (def two-arg-f32-min min) + (def two-arg-f32-max max) + (def two-arg-f32+ +) + (def two-arg-f32- -) + (def two-arg-f32* *) + (def two-arg-f32/ /) + #+(or) + (def f32-reciprocal reciprocal) + #+(or) + (def f32-rsqrt rsqrt) + (def f32-sqrt sqrt) + (def two-arg-f32= = :result-key u32-from-boolean) + (def two-arg-f32/= /= :result-key u32-from-boolean) + (def two-arg-f32< < :result-key u32-from-boolean) + (def two-arg-f32<= <= :result-key u32-from-boolean) + (def two-arg-f32> > :result-key u32-from-boolean) + (def two-arg-f32>= >= :result-key u32-from-boolean)) + +;;; f64 + +(define-fake-vop f64-if (mask a b) + (if (logbitp 63 mask) a b)) + +(macrolet ((def (name logical-operation) + (let* ((record (find-function-record name)) + (arity (length (instruction-record-argument-records record))) + (args (prefixed-symbols "ARG" arity))) + `(define-fake-vop ,name ,args + (let ((bits + (,logical-operation + ,@(loop for arg in args + collect `(sb-kernel:double-float-bits ,arg))))) + (sb-kernel:make-double-float + (ash bits -32) + (ldb (byte 32 0) bits))))))) + (def two-arg-f64-and logand) + (def two-arg-f64-or logior) + (def two-arg-f64-xor logxor) + (def f64-andc1 logandc1) + (def f64-not lognot)) + +(macrolet ((def (name op &rest keywords) `(define-trivial-fake-vop ,name ,op ,@keywords))) + (def two-arg-f64-min min) + (def two-arg-f64-max max) + (def two-arg-f64+ +) + (def two-arg-f64- -) + (def two-arg-f64* *) + (def two-arg-f64/ /) + #+(or) + (def f64-reciprocal reciprocal) + #+(or) + (def f64-rsqrt rsqrt) + (def f64-sqrt sqrt) + (def two-arg-f64= = :result-key u64-from-boolean) + (def two-arg-f64/= /= :result-key u64-from-boolean) + (def two-arg-f64< < :result-key u64-from-boolean) + (def two-arg-f64<= <= :result-key u64-from-boolean) + (def two-arg-f64> > :result-key u64-from-boolean) + (def two-arg-f64>= >= :result-key u64-from-boolean)) + +;;; integer operations + +;;; In contrast to the floating-point conditional selection operations, +;;; those for integers always operate with byte granularity. +(macrolet ((def (name maskbits) + `(define-fake-vop ,name (mask a b) + (logior + ,@(loop for offset from 0 by 8 below maskbits + collect + `(if (logbitp ,(+ offset 7) mask) + (mask-field (byte 8 ,offset) a) + (mask-field (byte 8 ,offset) b))))))) + (def u8-if 8) + (def u16-if 16) + (def u32-if 32) + (def u64-if 64)) + +(macrolet ((def (name bits u-if) + `(define-fake-vop ,name (mask a b) + (let ((u (,u-if mask (dpb a (byte ,bits 0) 0) (dpb b (byte ,bits 0) 0)))) + (- (mod (+ (ldb (byte ,bits 0) u) ,(expt 2 (1- bits))) + ,(expt 2 bits)) + ,(expt 2 (1- bits))))))) + (def s8-if 8 %u8-if) + (def s16-if 16 %u16-if) + (def s32-if 32 %u32-if) + (def s64-if 64 %u64-if)) + +(macrolet ((def (name bits) + `(define-inline ,name (integer) + (declare (integer integer)) + (mod integer ,(expt 2 bits))))) + (def u8-wrap 8) + (def u16-wrap 16) + (def u32-wrap 32) + (def u64-wrap 64)) + +(macrolet ((def (name bits) + (let ((offset (expt 2 (1- bits)))) + `(define-inline ,name (integer) + (declare (integer integer)) + (- (mod (+ integer ,offset) ,(expt 2 bits)) + ,offset))))) + (def s8-wrap 8) + (def s16-wrap 16) + (def s32-wrap 32) + (def s64-wrap 64)) + +(macrolet ((def (name op &rest keywords) `(define-trivial-fake-vop ,name ,op ,@keywords))) + ;; u8 + (def two-arg-u8-and logand) + (def two-arg-u8-or logior) + (def two-arg-u8-xor logxor) + (def two-arg-u8-max max) + (def two-arg-u8-min min) + (def two-arg-u8+ + :result-key u8-wrap) + (def two-arg-u8- - :result-key u8-wrap) + (def two-arg-u8= = :result-key u8-from-boolean) + (def two-arg-u8/= /= :result-key u8-from-boolean) + (def two-arg-u8< < :result-key u8-from-boolean) + (def two-arg-u8<= <= :result-key u8-from-boolean) + (def two-arg-u8> > :result-key u8-from-boolean) + (def two-arg-u8>= >= :result-key u8-from-boolean) + (def u8-andc1 logandc1) + (def u8-not lognot :result-key u8-wrap) + ;; u16 + (def two-arg-u16-and logand) + (def two-arg-u16-or logior) + (def two-arg-u16-xor logxor) + (def two-arg-u16-max max) + (def two-arg-u16-min min) + (def two-arg-u16+ + :result-key u16-wrap) + (def two-arg-u16- - :result-key u16-wrap) + (def two-arg-u16= = :result-key u16-from-boolean) + (def two-arg-u16/= /= :result-key u16-from-boolean) + (def two-arg-u16< < :result-key u16-from-boolean) + (def two-arg-u16<= <= :result-key u16-from-boolean) + (def two-arg-u16> > :result-key u16-from-boolean) + (def two-arg-u16>= >= :result-key u16-from-boolean) + (def u16-andc1 logandc1) + (def u16-not lognot :result-key u16-wrap) + ;; u32 + (def two-arg-u32-and logand) + (def two-arg-u32-or logior) + (def two-arg-u32-xor logxor) + (def two-arg-u32-max max) + (def two-arg-u32-min min) + (def two-arg-u32+ + :result-key u32-wrap) + (def two-arg-u32- - :result-key u32-wrap) + (def two-arg-u32= = :result-key u32-from-boolean) + (def two-arg-u32/= /= :result-key u32-from-boolean) + (def two-arg-u32< < :result-key u32-from-boolean) + (def two-arg-u32<= <= :result-key u32-from-boolean) + (def two-arg-u32> > :result-key u32-from-boolean) + (def two-arg-u32>= >= :result-key u32-from-boolean) + (def u32-andc1 logandc1) + (def u32-not lognot :result-key u32-wrap) + ;; u64 + (def two-arg-u64-and logand) + (def two-arg-u64-or logior) + (def two-arg-u64-xor logxor) + (def two-arg-u64-max max) + (def two-arg-u64-min min) + (def two-arg-u64+ + :result-key u64-wrap) + (def two-arg-u64- - :result-key u64-wrap) + (def two-arg-u64= = :result-key u64-from-boolean) + (def two-arg-u64/= /= :result-key u64-from-boolean) + (def two-arg-u64< < :result-key u64-from-boolean) + (def two-arg-u64<= <= :result-key u64-from-boolean) + (def two-arg-u64> > :result-key u64-from-boolean) + (def two-arg-u64>= >= :result-key u64-from-boolean) + (def u64-andc1 logandc1) + (def u64-not lognot :result-key u64-wrap) + ;; s8 + (def two-arg-s8-and logand) + (def two-arg-s8-or logior) + (def two-arg-s8-xor logxor) + (def two-arg-s8-max max) + (def two-arg-s8-min min) + (def two-arg-s8+ + :result-key s8-wrap) + (def two-arg-s8- - :result-key s8-wrap) + (def two-arg-s8= = :result-key u8-from-boolean) + (def two-arg-s8/= /= :result-key u8-from-boolean) + (def two-arg-s8< < :result-key u8-from-boolean) + (def two-arg-s8<= <= :result-key u8-from-boolean) + (def two-arg-s8> > :result-key u8-from-boolean) + (def two-arg-s8>= >= :result-key u8-from-boolean) + (def s8-andc1 logandc1) + (def s8-not lognot :result-key s8-wrap) + ;; s16 + (def two-arg-s16-and logand) + (def two-arg-s16-or logior) + (def two-arg-s16-xor logxor) + (def two-arg-s16-max max) + (def two-arg-s16-min min) + (def two-arg-s16+ + :result-key s16-wrap) + (def two-arg-s16- - :result-key s16-wrap) + (def two-arg-s16= = :result-key u16-from-boolean) + (def two-arg-s16/= /= :result-key u16-from-boolean) + (def two-arg-s16< < :result-key u16-from-boolean) + (def two-arg-s16<= <= :result-key u16-from-boolean) + (def two-arg-s16> > :result-key u16-from-boolean) + (def two-arg-s16>= >= :result-key u16-from-boolean) + (def s16-andc1 logandc1) + (def s16-not lognot :result-key s16-wrap) + ;; s32 + (def two-arg-s32-and logand) + (def two-arg-s32-or logior) + (def two-arg-s32-xor logxor) + (def two-arg-s32-max max) + (def two-arg-s32-min min) + (def two-arg-s32+ + :result-key s32-wrap) + (def two-arg-s32- - :result-key s32-wrap) + (def two-arg-s32= = :result-key u32-from-boolean) + (def two-arg-s32/= /= :result-key u32-from-boolean) + (def two-arg-s32< < :result-key u32-from-boolean) + (def two-arg-s32<= <= :result-key u32-from-boolean) + (def two-arg-s32> > :result-key u32-from-boolean) + (def two-arg-s32>= >= :result-key u32-from-boolean) + (def s32-andc1 logandc1) + (def s32-not lognot :result-key s32-wrap) + ;; s64 + (def two-arg-s64-and logand) + (def two-arg-s64-or logior) + (def two-arg-s64-xor logxor) + (def two-arg-s64-max max) + (def two-arg-s64-min min) + (def two-arg-s64+ + :result-key s64-wrap) + (def two-arg-s64- - :result-key s64-wrap) + (def two-arg-s64= = :result-key u64-from-boolean) + (def two-arg-s64/= /= :result-key u64-from-boolean) + (def two-arg-s64< < :result-key u64-from-boolean) + (def two-arg-s64<= <= :result-key u64-from-boolean) + (def two-arg-s64> > :result-key u64-from-boolean) + (def two-arg-s64>= >= :result-key u64-from-boolean) + (def s64-andc1 logandc1) + (def s64-not lognot :result-key s64-wrap)) + +(in-package #:sb-simd-sse) + +(define-fake-vop f32-not (a) + (%f32-andc1 a +f32-true+)) + +(define-fake-vop make-f32.4 (a b c d) + (%f32.4-unpacklo + (%f32.4-unpacklo + (%f32.4!-from-f32 a) + (%f32.4!-from-f32 c)) + (%f32.4-unpacklo + (%f32.4!-from-f32 b) + (%f32.4!-from-f32 d)))) + +(define-fake-vop f32.4-values (x) + (let* ((zero (sb-ext:%make-simd-pack-single 0f0 0f0 0f0 0f0)) + (a0b0 (%f32.4-unpacklo x zero)) + (c0d0 (%f32.4-unpackhi x zero))) + (values + (%f32!-from-p128 (%f32.4-unpacklo a0b0 zero)) + (%f32!-from-p128 (%f32.4-unpackhi a0b0 zero)) + (%f32!-from-p128 (%f32.4-unpacklo c0d0 zero)) + (%f32!-from-p128 (%f32.4-unpackhi c0d0 zero))))) + +(define-fake-vop f32.4-broadcast (x) + (let ((v (%f32.4!-from-f32 x))) + (%f32.4-shuffle v v 0))) + +(define-fake-vop f32.4-not (a) + (%f32.4-andc1 + a + (%make-f32.4 +f32-true+ +f32-true+ +f32-true+ +f32-true+))) + +(macrolet ((def (name op) + `(define-fake-vop ,name (x) + (let ((y (,op x (%f32.4-shuffle x x #4r2301)))) + (f32! (,op y (%f32.4-shuffle y y #4r1032))))))) + (def f32.4-horizontal-and %two-arg-f32.4-and) + (def f32.4-horizontal-or %two-arg-f32.4-or) + (def f32.4-horizontal-xor %two-arg-f32.4-xor) + (def f32.4-horizontal-max %two-arg-f32.4-max) + (def f32.4-horizontal-min %two-arg-f32.4-min) + (def f32.4-horizontal+ %two-arg-f32.4+) + (def f32.4-horizontal* %two-arg-f32.4*)) + +(in-package #:sb-simd-sse2) + +(define-fake-vop u8!-from-p128 (x) + (logand #xff (%u64!-from-p128 x))) + +(define-fake-vop u16!-from-p128 (x) + (logand #xffff (%u64!-from-p128 x))) + +(define-fake-vop u32!-from-p128 (x) + (logand #xffffffff (%u64!-from-p128 x))) + +(define-fake-vop f64-not (a) + (%f64-andc1 a +f64-true+)) + +(define-fake-vop make-f64.2 (a b) + (%f64.2-unpacklo + (%f64.2!-from-f64 a) + (%f64.2!-from-f64 b))) + +(define-fake-vop f64.2-values (x) + (values + (%f64!-from-p128 x) + (%f64!-from-p128 (%f64.2-shuffle x 1)))) + +(define-fake-vop f64.2-broadcast (x) + (let ((v (%f64.2!-from-f64 x))) + (%f64.2-unpacklo v v))) + +(define-fake-vop f64.2-not (a) + (%f64.2-andc1 + a + (%make-f64.2 +f64-true+ +f64-true+))) + +(macrolet ((def (name op) + `(define-fake-vop ,name (x) + (multiple-value-bind (a b) (%f64.2-values x) + (,op a b))))) + (def f64.2-horizontal-and %two-arg-f64-and) + (def f64.2-horizontal-or %two-arg-f64-or) + (def f64.2-horizontal-xor %two-arg-f64-xor) + (def f64.2-horizontal-max %two-arg-f64-max) + (def f64.2-horizontal-min %two-arg-f64-min) + (def f64.2-horizontal+ %two-arg-f64+) + (def f64.2-horizontal* %two-arg-f64*)) + +(define-fake-vop make-u8.16 (a b c d e f g h i j k l m n o p) + (%u8.16-unpacklo + (%u8.16!-from-p128 (%u64.2!-from-u64 (sb-simd::%u64-from-u8s a c e g i k m o))) + (%u8.16!-from-p128 (%u64.2!-from-u64 (sb-simd::%u64-from-u8s b d f h j l n p))))) + +(define-fake-vop u8.16-values (x) + (multiple-value-call #'values + (sb-simd::%u8s-from-u64 (%u64!-from-p128 x)) + (sb-simd::%u8s-from-u64 (%u64!-from-p128 (%u32.4-shuffle (%u32.4!-from-p128 x) #b00001110))))) + +(define-fake-vop u8.16-broadcast (x) + (let ((v (%u64.2!-from-u64 (sb-simd::%u64-from-u8s x x x x x x x x)))) + (%u8.16!-from-p128 (%u64.2-unpacklo v v)))) + +(define-fake-vop u8.16-not (a) + (let* ((x +u8-true+) + (v (%make-u8.16 x x x x x x x x x x x x x x x x))) + (%u8.16-andc1 a v))) + +(define-fake-vop two-arg-u8.16/= (a b) + (%u8.16-not + (%two-arg-u8.16= a b))) + +(define-fake-vop two-arg-u8.16> (a b) + (let* ((x (expt 2 7)) + (v (%make-u8.16 x x x x x x x x x x x x x x x x))) + (%two-arg-u8.16>~ (%two-arg-u8.16- a v) + (%two-arg-u8.16- b v)))) + +(define-fake-vop two-arg-u8.16< (a b) + (%two-arg-u8.16> b a)) + +(define-fake-vop two-arg-u8.16>= (a b) + (%u8.16-not + (%two-arg-u8.16< a b))) + +(define-fake-vop two-arg-u8.16<= (a b) + (%u8.16-not + (%two-arg-u8.16> a b))) + +(define-fake-vop make-u16.8 (a b c d e f g h) + (%u16.8-unpacklo + (%u16.8!-from-p128 (%u64.2!-from-u64 (sb-simd::%u64-from-u16s a c e g))) + (%u16.8!-from-p128 (%u64.2!-from-u64 (sb-simd::%u64-from-u16s b d f h))))) + +(define-fake-vop u16.8-values (x) + (multiple-value-call #'values + (sb-simd::%u16s-from-u64 (%u64!-from-p128 x)) + (sb-simd::%u16s-from-u64 (%u64!-from-p128 (%u32.4-shuffle (%u32.4!-from-p128 x) #b00001110))))) + +(define-fake-vop u16.8-broadcast (x) + (let ((v (%u64.2!-from-u64 (sb-simd::%u64-from-u16s x x x x)))) + (%u16.8!-from-p128 (%u64.2-unpacklo v v)))) + +(define-fake-vop u16.8-not (a) + (%u16.8-andc1 + a + (%make-u16.8 +u16-true+ +u16-true+ +u16-true+ +u16-true+ + +u16-true+ +u16-true+ +u16-true+ +u16-true+))) + +(define-fake-vop two-arg-u16.8/= (a b) + (%u16.8-not + (%two-arg-u16.8= a b))) + +(define-fake-vop two-arg-u16.8> (a b) + (let* ((x (expt 2 15)) + (v (%make-u16.8 x x x x x x x x))) + (%two-arg-u16.8>~ (%two-arg-u16.8- a v) + (%two-arg-u16.8- b v)))) + +(define-fake-vop two-arg-u16.8< (a b) + (%two-arg-u16.8> b a)) + +(define-fake-vop two-arg-u16.8>= (a b) + (%u16.8-not + (%two-arg-u16.8< a b))) + +(define-fake-vop two-arg-u16.8<= (a b) + (%u16.8-not + (%two-arg-u16.8> a b))) + +(define-fake-vop u16.8-movemask (a) + (u16-odd-bits + (%u8.16-movemask + (%u8.16!-from-p128 a)))) + +(define-fake-vop make-u32.4 (a b c d) + (%u32.4-unpacklo + (%u32.4!-from-p128 (%u64.2!-from-u64 (sb-simd::%u64-from-u32s a c))) + (%u32.4!-from-p128 (%u64.2!-from-u64 (sb-simd::%u64-from-u32s b d))))) + +(define-fake-vop u32.4-values (x) + (multiple-value-call #'values + (sb-simd::%u32s-from-u64 (%u64!-from-p128 x)) + (sb-simd::%u32s-from-u64 (%u64!-from-p128 (%u32.4-shuffle (%u32.4!-from-p128 x) #b00001110))))) + +(define-fake-vop u32.4-broadcast (x) + (let ((v (%u64.2!-from-u64 (sb-simd::%u64-from-u32s x x)))) + (%u32.4!-from-p128 (%u64.2-unpacklo v v)))) + +(define-fake-vop u32.4-not (a) + (%u32.4-andc1 + a + (%make-u32.4 +u32-true+ +u32-true+ +u32-true+ +u32-true+))) + +(define-fake-vop two-arg-u32.4/= (a b) + (%u32.4-not + (%two-arg-u32.4= a b))) + +(define-fake-vop two-arg-u32.4> (a b) + (let* ((x (expt 2 31)) + (v (%make-u32.4 x x x x))) + (%two-arg-u32.4>~ (%two-arg-u32.4- a v) + (%two-arg-u32.4- b v)))) + +(define-fake-vop two-arg-u32.4< (a b) + (%two-arg-u32.4> b a)) + +(define-fake-vop two-arg-u32.4>= (a b) + (%u32.4-not + (%two-arg-u32.4< a b))) + +(define-fake-vop two-arg-u32.4<= (a b) + (%u32.4-not + (%two-arg-u32.4> a b))) + +(define-fake-vop make-u64.2 (a b) + (%u64.2-unpacklo + (%u64.2!-from-u64 a) + (%u64.2!-from-u64 b))) + +(define-fake-vop u64.2-values (x) + (values + (%u64!-from-p128 x) + (%u64!-from-p128 (%u32.4-shuffle (%u32.4!-from-p128 x) #b00001110)))) + +(define-fake-vop u64.2-broadcast (x) + (let ((v (%u64.2!-from-u64 x))) + (%u64.2-unpacklo v v))) + +(define-fake-vop u64.2-not (a) + (%u64.2-andc1 + a + (%make-u64.2 +u64-true+ +u64-true+))) + +(define-fake-vop s8.16!-from-s8 (x) + (%s8.16!-from-p128 (%u64.2!-from-u64 (sb-simd::%u64-from-s8s x 0 0 0 0 0 0 0)))) + +(define-fake-vop make-s8.16 (a b c d e f g h i j k l m n o p) + (%s8.16-unpacklo + (%s8.16!-from-p128 (%u64.2!-from-u64 (sb-simd::%u64-from-s8s a c e g i k m o))) + (%s8.16!-from-p128 (%u64.2!-from-u64 (sb-simd::%u64-from-s8s b d f h j l n p))))) + +(define-fake-vop s8.16-values (x) + (multiple-value-call #'values + (sb-simd::%s8s-from-u64 (%u64!-from-p128 x)) + (sb-simd::%s8s-from-u64 (%u64!-from-p128 (%u32.4-shuffle (%u32.4!-from-p128 x) #b00001110))))) + +(define-fake-vop s8.16-broadcast (x) + (let ((v (%u64.2!-from-u64 (sb-simd::%u64-from-s8s x x x x x x x x)))) + (%s8.16!-from-p128 (%u64.2-unpacklo v v)))) + +(define-fake-vop s8.16-not (a) + (%s8.16-andc1 + a + (%make-s8.16 +s8-true+ +s8-true+ +s8-true+ +s8-true+ + +s8-true+ +s8-true+ +s8-true+ +s8-true+ + +s8-true+ +s8-true+ +s8-true+ +s8-true+ + +s8-true+ +s8-true+ +s8-true+ +s8-true+))) + +(define-fake-vop two-arg-s8.16/= (a b) + (%u8.16-not + (%two-arg-s8.16= a b))) + +(define-fake-vop two-arg-s8.16< (a b) + (%two-arg-s8.16> b a)) + +(define-fake-vop two-arg-s8.16>= (a b) + (%u8.16-not + (%two-arg-s8.16< a b))) + +(define-fake-vop two-arg-s8.16<= (a b) + (%u8.16-not + (%two-arg-s8.16> a b))) + +(define-fake-vop s16.8!-from-s16 (x) + (%s16.8!-from-p128 (%u64.2!-from-u64 (sb-simd::%u64-from-s16s x 0 0 0)))) + +(define-fake-vop make-s16.8 (a b c d e f g h) + (%s16.8-unpacklo + (%s16.8!-from-p128 (%u64.2!-from-u64 (sb-simd::%u64-from-s16s a c e g))) + (%s16.8!-from-p128 (%u64.2!-from-u64 (sb-simd::%u64-from-s16s b d f h))))) + +(define-fake-vop s16.8-values (x) + (multiple-value-call #'values + (sb-simd::%s16s-from-u64 (%u64!-from-p128 x)) + (sb-simd::%s16s-from-u64 (%u64!-from-p128 (%u32.4-shuffle (%u32.4!-from-p128 x) #b00001110))))) + +(define-fake-vop s16.8-broadcast (x) + (let ((v (%u64.2!-from-u64 (sb-simd::%u64-from-s16s x x x x)))) + (%s16.8!-from-p128 (%u64.2-unpacklo v v)))) + +(define-fake-vop s16.8-not (a) + (%s16.8-andc1 + a + (%make-s16.8 +s16-true+ +s16-true+ +s16-true+ +s16-true+ + +s16-true+ +s16-true+ +s16-true+ +s16-true+))) + +(define-fake-vop two-arg-s16.8/= (a b) + (%u16.8-not + (%two-arg-s16.8= a b))) + +(define-fake-vop two-arg-s16.8< (a b) + (%two-arg-s16.8> b a)) + +(define-fake-vop two-arg-s16.8>= (a b) + (%u16.8-not + (%two-arg-s16.8< a b))) + +(define-fake-vop two-arg-s16.8<= (a b) + (%u16.8-not + (%two-arg-s16.8> a b))) + +(define-fake-vop s16.8-movemask (a) + (u16-odd-bits + (%u8.16-movemask + (%u8.16!-from-p128 a)))) + +(define-fake-vop s32.4!-from-s32 (x) + (%s32.4!-from-p128 (%u64.2!-from-u64 (sb-simd::%u64-from-s32s x 0)))) + +(define-fake-vop make-s32.4 (a b c d) + (%s32.4-unpacklo + (%s32.4!-from-p128 (%u64.2!-from-u64 (sb-simd::%u64-from-s32s a c))) + (%s32.4!-from-p128 (%u64.2!-from-u64 (sb-simd::%u64-from-s32s b d))))) + +(define-fake-vop s32.4-values (x) + (multiple-value-call #'values + (sb-simd::%s32s-from-u64 (%u64!-from-p128 x)) + (sb-simd::%s32s-from-u64 (%u64!-from-p128 (%u32.4-shuffle (%u32.4!-from-p128 x) #b00001110))))) + +(define-fake-vop s32.4-broadcast (x) + (let ((v (%u64.2!-from-u64 (sb-simd::%u64-from-s32s x x)))) + (%s32.4!-from-p128 (%u64.2-unpacklo v v)))) + +(define-fake-vop s32.4-not (a) + (%s32.4-andc1 + a + (%make-s32.4 +s32-true+ +s32-true+ +s32-true+ +s32-true+))) + +(define-fake-vop two-arg-s32.4/= (a b) + (%u32.4-not + (%two-arg-s32.4= a b))) + +(define-fake-vop two-arg-s32.4< (a b) + (%two-arg-s32.4> b a)) + +(define-fake-vop two-arg-s32.4>= (a b) + (%u32.4-not + (%two-arg-s32.4< a b))) + +(define-fake-vop two-arg-s32.4<= (a b) + (%u32.4-not + (%two-arg-s32.4> a b))) + +(define-fake-vop s64.2!-from-s64 (x) + (%s64.2!-from-p128 (%u64.2!-from-u64 (sb-simd::%u64-from-s64 x)))) + +(define-fake-vop make-s64.2 (a b) + (%s64.2-unpacklo + (%s64.2!-from-p128 (%u64.2!-from-u64 (sb-simd::%u64-from-s64 a))) + (%s64.2!-from-p128 (%u64.2!-from-u64 (sb-simd::%u64-from-s64 b))))) + +(define-fake-vop s64.2-values (x) + (values + (sb-simd::%s64-from-u64 (%u64!-from-p128 x)) + (sb-simd::%s64-from-u64 (%u64!-from-p128 (%u32.4-shuffle (%u32.4!-from-p128 x) #b00001110))))) + +(define-fake-vop s64.2-broadcast (x) + (let ((v (%u64.2!-from-u64 (sb-simd::%u64-from-s64 x)))) + (%s64.2!-from-p128 (%u64.2-unpacklo v v)))) + +(define-fake-vop s64.2-not (a) + (%s64.2-andc1 + a + (%make-s64.2 +s64-true+ +s64-true+))) + +(in-package #:sb-simd-sse4.1) + +(define-fake-vop two-arg-u64.2/= (a b) + (sb-simd-sse2::%u64.2-not + (%two-arg-u64.2= a b))) + +(define-fake-vop two-arg-s64.2/= (a b) + (sb-simd-sse2::%u64.2-not + (%two-arg-s64.2= a b))) + +(in-package #:sb-simd-sse4.2) + +(define-fake-vop two-arg-u64.2> (a b) + (let* ((x (expt 2 63)) + (v (sb-simd-sse2::%make-u64.2 x x))) + (%two-arg-u64.2>~ (sb-simd-sse2::%two-arg-u64.2- a v) + (sb-simd-sse2::%two-arg-u64.2- b v)))) + +(define-fake-vop two-arg-u64.2< (a b) + (%two-arg-u64.2> b a)) + +(define-fake-vop two-arg-u64.2>= (a b) + (sb-simd-sse2::%u64.2-not + (%two-arg-u64.2< a b))) + +(define-fake-vop two-arg-u64.2<= (a b) + (sb-simd-sse2::%u64.2-not + (%two-arg-u64.2> a b))) + +(define-fake-vop two-arg-s64.2< (a b) + (%two-arg-s64.2> b a)) + +(define-fake-vop two-arg-s64.2>= (a b) + (sb-simd-sse2::%u64.2-not + (%two-arg-s64.2< a b))) + +(define-fake-vop two-arg-s64.2<= (a b) + (sb-simd-sse2::%u64.2-not + (%two-arg-s64.2> a b))) + +(in-package #:sb-simd-avx) + +(define-fake-vop u8!-from-p128 (x) + (logand #xff (%u64!-from-p128 x))) + +(define-fake-vop u8!-from-p256 (x) + (logand #xff (%u64!-from-p256 x))) + +(define-fake-vop u16!-from-p128 (x) + (logand #xffff (%u64!-from-p128 x))) + +(define-fake-vop u16!-from-p256 (x) + (logand #xffff (%u64!-from-p256 x))) + +(define-fake-vop u32!-from-p128 (x) + (logand #xffffffff (%u64!-from-p128 x))) + +(define-fake-vop u32!-from-p256 (x) + (logand #xffffffff (%u64!-from-p256 x))) + +(define-fake-vop f32-not (a) + (%f32-andc1 a +f32-true+)) + +(define-fake-vop f64-not (a) + (%f64-andc1 a +f64-true+)) + +(define-fake-vop make-f32.4 (a b c d) + (%f32.4-unpacklo + (%f32.4-unpacklo + (%f32.4!-from-f32 a) + (%f32.4!-from-f32 c)) + (%f32.4-unpacklo + (%f32.4!-from-f32 b) + (%f32.4!-from-f32 d)))) + +(define-fake-vop f32.4-values (x) + (values + (%f32!-from-p128 x) + (%f32!-from-p128 (%f32.4-permute x 1)) + (%f32!-from-p128 (%f32.4-permute x 2)) + (%f32!-from-p128 (%f32.4-permute x 3)))) + +(define-fake-vop f32.4-not (a) + (%f32.4-andc1 + a + (%make-f32.4 +f32-true+ +f32-true+ +f32-true+ +f32-true+))) + +(macrolet ((def (name op) + `(define-fake-vop ,name (x) + (let ((y (,op x (%f32.4-shuffle x x #4r2301)))) + (f32! (,op y (%f32.4-shuffle y y #4r1032))))))) + (def f32.4-horizontal-and %two-arg-f32.4-and) + (def f32.4-horizontal-or %two-arg-f32.4-or) + (def f32.4-horizontal-xor %two-arg-f32.4-xor) + (def f32.4-horizontal-max %two-arg-f32.4-max) + (def f32.4-horizontal-min %two-arg-f32.4-min) + (def f32.4-horizontal+ %two-arg-f32.4+) + (def f32.4-horizontal* %two-arg-f32.4*)) + +(define-fake-vop make-f64.2 (a b) + (%f64.2-unpacklo + (%f64.2!-from-f64 a) + (%f64.2!-from-f64 b))) + +(define-fake-vop f64.2-values (x) + (values + (%f64!-from-p128 x) + (%f64!-from-p128 (%f64.2-permute x 1)))) + +(define-fake-vop f64.2-not (a) + (%f64.2-andc1 + a + (%make-f64.2 +f64-true+ +f64-true+))) + +(macrolet ((def (name op) + `(define-fake-vop ,name (x) + (multiple-value-bind (a b) (%f64.2-values x) + (,op a b))))) + (def f64.2-horizontal-and %two-arg-f64-and) + (def f64.2-horizontal-or %two-arg-f64-or) + (def f64.2-horizontal-xor %two-arg-f64-xor) + (def f64.2-horizontal-max %two-arg-f64-max) + (def f64.2-horizontal-min %two-arg-f64-min) + (def f64.2-horizontal+ %two-arg-f64+) + (def f64.2-horizontal* %two-arg-f64*)) + +(define-fake-vop make-f32.8 (a b c d e f g h) + (let ((lo (%make-f32.4 a b c d)) + (hi (%make-f32.4 e f g h))) + (%f32.8-insert-f32.4 (%f32.8!-from-p128 lo) hi 1))) + +(define-fake-vop f32.8-values (x) + (multiple-value-call #'values + (%f32.4-values (%f32.4!-from-p256 x)) + (%f32.4-values (%f32.4-from-f32.8 x 1)))) + +(define-fake-vop f32.8-not (a) + (%f32.8-andc1 + a + (%make-f32.8 +f32-true+ +f32-true+ +f32-true+ +f32-true+ + +f32-true+ +f32-true+ +f32-true+ +f32-true+))) + +(macrolet ((def (name op) + `(define-fake-vop ,name (x) + (let* ((x (,op x (%f32.8-dupodd x))) + (x (,op x (%f32.8-permute x #4r0202))) + (x (,op x (%f32.8-permute128 x x #4r01)))) + (%f32!-from-p256 x))))) + (def f32.8-horizontal-and %two-arg-f32.8-and) + (def f32.8-horizontal-or %two-arg-f32.8-or) + (def f32.8-horizontal-xor %two-arg-f32.8-xor) + (def f32.8-horizontal-max %two-arg-f32.8-max) + (def f32.8-horizontal-min %two-arg-f32.8-min) + (def f32.8-horizontal+ %two-arg-f32.8+) + (def f32.8-horizontal* %two-arg-f32.8*)) + +(define-fake-vop make-f64.4 (a b c d) + (let ((lo (%make-f64.2 a b)) + (hi (%make-f64.2 c d))) + (%f64.4-insert-f64.2 (%f64.4!-from-p128 lo) hi 1))) + +(define-fake-vop f64.4-values (x) + (multiple-value-call #'values + (%f64.2-values (%f64.2!-from-p256 x)) + (%f64.2-values (%f64.2-from-f64.4 x 1)))) + +(define-fake-vop f64.4-not (a) + (%f64.4-andc1 + a + (%make-f64.4 +f64-true+ +f64-true+ +f64-true+ +f64-true+))) + +(macrolet ((def (name op ) + `(define-fake-vop ,name (x) + (let* ((y (,op x (%f64.4-permute x #b0101))) + (z (,op y (%f64.4-permute128 y y #4r01)))) + (%f64!-from-p256 z))))) + (def f64.4-horizontal-and %two-arg-f64.4-and) + (def f64.4-horizontal-or %two-arg-f64.4-or) + (def f64.4-horizontal-xor %two-arg-f64.4-xor) + (def f64.4-horizontal-max %two-arg-f64.4-max) + (def f64.4-horizontal-min %two-arg-f64.4-min) + (def f64.4-horizontal+ %two-arg-f64.4+) + (def f64.4-horizontal* %two-arg-f64.4*)) + +(define-fake-vop make-u8.16 (a b c d e f g h i j k l m n o p) + (%u8.16-unpacklo + (%u8.16!-from-p128 (%u64.2!-from-u64 (sb-simd::%u64-from-u8s a c e g i k m o))) + (%u8.16!-from-p128 (%u64.2!-from-u64 (sb-simd::%u64-from-u8s b d f h j l n p))))) + +(define-fake-vop u8.16-values (x) + (multiple-value-call #'values + (sb-simd::%u8s-from-u64 (%u64!-from-p128 x)) + (sb-simd::%u8s-from-u64 (%u64!-from-p128 (%u64.2-permute (%u64.2!-from-p128 x) 1))))) + +(define-fake-vop u8.16-broadcast (x) + (let ((v (%u64.2!-from-u64 (sb-simd::%u64-from-u8s x x x x x x x x)))) + (%u8.16!-from-p128 (%u64.2-unpacklo v v)))) + +(define-fake-vop u8.16-not (a) + (%u8.16-andc1 + a + (%make-u8.16 +u8-true+ +u8-true+ +u8-true+ +u8-true+ + +u8-true+ +u8-true+ +u8-true+ +u8-true+ + +u8-true+ +u8-true+ +u8-true+ +u8-true+ + +u8-true+ +u8-true+ +u8-true+ +u8-true+))) + +(define-fake-vop two-arg-u8.16/= (a b) + (%u8.16-not + (%two-arg-u8.16= a b))) + +(define-fake-vop two-arg-u8.16> (a b) + (let* ((x (expt 2 7)) + (v (%make-u8.16 x x x x x x x x x x x x x x x x))) + (%two-arg-u8.16>~ (%two-arg-u8.16- a v) + (%two-arg-u8.16- b v)))) + +(define-fake-vop two-arg-u8.16< (a b) + (%two-arg-u8.16> b a)) + +(define-fake-vop two-arg-u8.16>= (a b) + (%u8.16-not + (%two-arg-u8.16< a b))) + +(define-fake-vop two-arg-u8.16<= (a b) + (%u8.16-not + (%two-arg-u8.16> a b))) + +(define-fake-vop make-u16.8 (a b c d e f g h) + (%u16.8-unpacklo + (%u16.8!-from-p128 (%u64.2!-from-u64 (sb-simd::%u64-from-u16s a c e g))) + (%u16.8!-from-p128 (%u64.2!-from-u64 (sb-simd::%u64-from-u16s b d f h))))) + +(define-fake-vop u16.8-values (x) + (multiple-value-call #'values + (sb-simd::%u16s-from-u64 (%u64!-from-p128 x)) + (sb-simd::%u16s-from-u64 (%u64!-from-p128 (%u64.2-permute (%u64.2!-from-p128 x) 1))))) + +(define-fake-vop u16.8-broadcast (x) + (let ((v (%u64.2!-from-u64 (sb-simd::%u64-from-u16s x x x x)))) + (%u16.8!-from-p128 (%u64.2-unpacklo v v)))) + +(define-fake-vop u16.8-not (a) + (%u16.8-andc1 + a + (%make-u16.8 +u16-true+ +u16-true+ +u16-true+ +u16-true+ + +u16-true+ +u16-true+ +u16-true+ +u16-true+))) + +(define-fake-vop two-arg-u16.8/= (a b) + (%u16.8-not + (%two-arg-u16.8= a b))) + +(define-fake-vop two-arg-u16.8> (a b) + (let* ((x (expt 2 15)) + (v (%make-u16.8 x x x x x x x x))) + (%two-arg-u16.8>~ (%two-arg-u16.8- a v) + (%two-arg-u16.8- b v)))) + +(define-fake-vop two-arg-u16.8< (a b) + (%two-arg-u16.8> b a)) + +(define-fake-vop two-arg-u16.8>= (a b) + (%u16.8-not + (%two-arg-u16.8< a b))) + +(define-fake-vop two-arg-u16.8<= (a b) + (%u16.8-not + (%two-arg-u16.8> a b))) + +(define-fake-vop u16.8-movemask (a) + (u16-odd-bits + (%u8.16-movemask + (%u8.16!-from-p128 a)))) + +(define-fake-vop make-u32.4 (a b c d) + (%u32.4-unpacklo + (%u32.4!-from-p128 (%u64.2!-from-u64 (sb-simd::%u64-from-u32s a c))) + (%u32.4!-from-p128 (%u64.2!-from-u64 (sb-simd::%u64-from-u32s b d))))) + +(define-fake-vop u32.4-values (x) + (multiple-value-call #'values + (sb-simd::%u32s-from-u64 (%u64!-from-p128 x)) + (sb-simd::%u32s-from-u64 (%u64!-from-p128 (%u64.2-permute (%u64.2!-from-p128 x) 1))))) + +(define-fake-vop u32.4-broadcast (x) + (let ((v (%u64.2!-from-u64 (sb-simd::%u64-from-u32s x x)))) + (%u32.4!-from-p128 (%u64.2-unpacklo v v)))) + +(define-fake-vop u32.4-not (a) + (%u32.4-andc1 + a + (%make-u32.4 +u32-true+ +u32-true+ +u32-true+ +u32-true+))) + +(define-fake-vop two-arg-u32.4/= (a b) + (%u32.4-not + (%two-arg-u32.4= a b))) + +(define-fake-vop two-arg-u32.4> (a b) + (let* ((x (expt 2 31)) + (v (%make-u32.4 x x x x))) + (%two-arg-u32.4>~ (%two-arg-u32.4- a v) + (%two-arg-u32.4- b v)))) + +(define-fake-vop two-arg-u32.4< (a b) + (%two-arg-u32.4> b a)) + +(define-fake-vop two-arg-u32.4>= (a b) + (%u32.4-not + (%two-arg-u32.4< a b))) + +(define-fake-vop two-arg-u32.4<= (a b) + (%u32.4-not + (%two-arg-u32.4> a b))) + +(define-fake-vop make-u64.2 (a b) + (%u64.2-unpacklo + (%u64.2!-from-u64 a) + (%u64.2!-from-u64 b))) + +(define-fake-vop u64.2-values (x) + (multiple-value-call #'values + (%u64!-from-p128 x) + (%u64!-from-p128 (%u64.2-permute (%u64.2!-from-p128 x) 1)))) + +(define-fake-vop u64.2-broadcast (x) + (let ((v (%u64.2!-from-u64 x))) + (%u64.2-unpacklo v v))) + +(define-fake-vop u64.2-not (a) + (%u64.2-andc1 + a + (%make-u64.2 +u64-true+ +u64-true+))) + +(define-fake-vop two-arg-u64.2/= (a b) + (%u64.2-not + (%two-arg-u64.2= a b))) + +(define-fake-vop two-arg-u64.2> (a b) + (let* ((x (expt 2 63)) + (v (%make-u64.2 x x))) + (%two-arg-u64.2>~ (%two-arg-u64.2- a v) + (%two-arg-u64.2- b v)))) + +(define-fake-vop two-arg-u64.2< (a b) + (%two-arg-u64.2> b a)) + +(define-fake-vop two-arg-u64.2>= (a b) + (sb-simd-avx::%u64.2-not + (%two-arg-u64.2< a b))) + +(define-fake-vop two-arg-u64.2<= (a b) + (sb-simd-avx::%u64.2-not + (%two-arg-u64.2> a b))) + +(define-fake-vop make-u8.32 + (u01 u02 u03 u04 u05 u06 u07 u08 u09 u10 u11 u12 u13 u14 u15 u16 u17 u18 u19 u20 u21 u22 u23 u24 u25 u26 u27 u28 u29 u30 u31 u32) + (let ((lo (%make-u8.16 u01 u02 u03 u04 u05 u06 u07 u08 u09 u10 u11 u12 u13 u14 u15 u16)) + (hi (%make-u8.16 u17 u18 u19 u20 u21 u22 u23 u24 u25 u26 u27 u28 u29 u30 u31 u32))) + (%u8.32-insert-u8.16 (%u8.32!-from-p128 lo) hi 1))) + +(define-fake-vop u8.32-values (x) + (multiple-value-call #'values + (%u8.16-values (%u8.16!-from-p256 x)) + (%u8.16-values (%u8.16-from-u8.32 x 1)))) + +(define-fake-vop u8.32-broadcast (x) + (let ((v (%u8.16-broadcast x))) + (%u8.32-insert-u8.16 (%u8.32!-from-p128 v) v 1))) + +(define-fake-vop make-u16.16 (a b c d e f g h i j k l m n o p) + (let ((lo (%make-u16.8 a b c d e f g h)) + (hi (%make-u16.8 i j k l m n o p))) + (%u16.16-insert-u16.8 (%u16.16!-from-p128 lo) hi 1))) + +(define-fake-vop u16.16-values (x) + (multiple-value-call #'values + (%u16.8-values (%u16.8!-from-p256 x)) + (%u16.8-values (%u16.8-from-u16.16 x 1)))) + +(define-fake-vop u16.16-broadcast (x) + (let ((v (%u16.8-broadcast x))) + (%u16.16-insert-u16.8 (%u16.16!-from-p128 v) v 1))) + +(define-fake-vop make-u32.8 (a b c d e f g h) + (let ((lo (%make-u32.4 a b c d)) + (hi (%make-u32.4 e f g h))) + (%u32.8-insert-u32.4 (%u32.8!-from-p128 lo) hi 1))) + +(define-fake-vop u32.8-values (x) + (multiple-value-call #'values + (%u32.4-values (%u32.4!-from-p256 x)) + (%u32.4-values (%u32.4-from-u32.8 x 1)))) + +(define-fake-vop u32.8-broadcast (x) + (let ((v (%u32.4-broadcast x))) + (%u32.8-insert-u32.4 (%u32.8!-from-p128 v) v 1))) + +(define-fake-vop make-u64.4 (a b c d) + (let ((lo (%make-u64.2 a b)) + (hi (%make-u64.2 c d))) + (%u64.4-insert-u64.2 (%u64.4!-from-p128 lo) hi 1))) + +(define-fake-vop u64.4-values (x) + (multiple-value-call #'values + (%u64.2-values (%u64.2!-from-p256 x)) + (%u64.2-values (%u64.2-from-u64.4 x 1)))) + +(define-fake-vop u64.4-broadcast (x) + (let ((v (%u64.2-broadcast x))) + (%u64.4-insert-u64.2 (%u64.4!-from-p128 v) v 1))) + +(define-fake-vop s8.16!-from-s8 (x) + (%s8.16!-from-p128 (%u64.2!-from-u64 (sb-simd::%u64-from-s8s x 0 0 0 0 0 0 0)))) + +(define-fake-vop make-s8.16 (a b c d e f g h i j k l m n o p) + (%s8.16-unpacklo + (%s8.16!-from-p128 (%u64.2!-from-u64 (sb-simd::%u64-from-s8s a c e g i k m o))) + (%s8.16!-from-p128 (%u64.2!-from-u64 (sb-simd::%u64-from-s8s b d f h j l n p))))) + +(define-fake-vop s8.16-values (x) + (multiple-value-call #'values + (sb-simd::%s8s-from-u64 (%u64!-from-p128 x)) + (sb-simd::%s8s-from-u64 (%u64!-from-p128 (%u64.2-permute (%u64.2!-from-p128 x) 1))))) + +(define-fake-vop s8.16-broadcast (x) + (let ((v (%u64.2!-from-u64 (sb-simd::%u64-from-s8s x x x x x x x x)))) + (%s8.16!-from-p128 (%u64.2-unpacklo v v)))) + +(define-fake-vop s8.16-not (a) + (%s8.16-andc1 + a + (%make-s8.16 +s8-true+ +s8-true+ +s8-true+ +s8-true+ + +s8-true+ +s8-true+ +s8-true+ +s8-true+ + +s8-true+ +s8-true+ +s8-true+ +s8-true+ + +s8-true+ +s8-true+ +s8-true+ +s8-true+))) + +(define-fake-vop two-arg-s8.16/= (a b) + (%u8.16-not + (%two-arg-s8.16= a b))) + +(define-fake-vop two-arg-s8.16< (a b) + (%two-arg-s8.16> b a)) + +(define-fake-vop two-arg-s8.16>= (a b) + (%u8.16-not + (%two-arg-s8.16< a b))) + +(define-fake-vop two-arg-s8.16<= (a b) + (%u8.16-not + (%two-arg-s8.16> a b))) + +(define-fake-vop s16.8!-from-s16 (x) + (%s16.8!-from-p128 (%u64.2!-from-u64 (sb-simd::%u64-from-s16s x 0 0 0)))) + +(define-fake-vop make-s16.8 (a b c d e f g h) + (%s16.8-unpacklo + (%s16.8!-from-p128 (%u64.2!-from-u64 (sb-simd::%u64-from-s16s a c e g))) + (%s16.8!-from-p128 (%u64.2!-from-u64 (sb-simd::%u64-from-s16s b d f h))))) + +(define-fake-vop s16.8-values (x) + (multiple-value-call #'values + (sb-simd::%s16s-from-u64 (%u64!-from-p128 x)) + (sb-simd::%s16s-from-u64 (%u64!-from-p128 (%u64.2-permute (%u64.2!-from-p128 x) 1))))) + +(define-fake-vop s16.8-broadcast (x) + (let ((v (%u64.2!-from-u64 (sb-simd::%u64-from-s16s x x x x)))) + (%s16.8!-from-p128 (%u64.2-unpacklo v v)))) + +(define-fake-vop s16.8-not (a) + (%s16.8-andc1 + a + (%make-s16.8 +s16-true+ +s16-true+ +s16-true+ +s16-true+ + +s16-true+ +s16-true+ +s16-true+ +s16-true+))) + +(define-fake-vop two-arg-s16.8/= (a b) + (%u16.8-not + (%two-arg-s16.8= a b))) + +(define-fake-vop two-arg-s16.8< (a b) + (%two-arg-s16.8> b a)) + +(define-fake-vop two-arg-s16.8>= (a b) + (%u16.8-not + (%two-arg-s16.8< a b))) + +(define-fake-vop two-arg-s16.8<= (a b) + (%u16.8-not + (%two-arg-s16.8> a b))) + +(define-fake-vop s16.8-movemask (a) + (u16-odd-bits + (%u8.16-movemask + (%u8.16!-from-p128 a)))) + +(define-fake-vop s32.4!-from-s32 (x) + (%s32.4!-from-p128 (%u64.2!-from-u64 (sb-simd::%u64-from-s32s x 0)))) + +(define-fake-vop make-s32.4 (a b c d) + (%s32.4-unpacklo + (%s32.4!-from-p128 (%u64.2!-from-u64 (sb-simd::%u64-from-s32s a c))) + (%s32.4!-from-p128 (%u64.2!-from-u64 (sb-simd::%u64-from-s32s b d))))) + +(define-fake-vop s32.4-values (x) + (multiple-value-call #'values + (sb-simd::%s32s-from-u64 (%u64!-from-p128 x)) + (sb-simd::%s32s-from-u64 (%u64!-from-p128 (%u64.2-permute (%u64.2!-from-p128 x) 1))))) + +(define-fake-vop s32.4-broadcast (x) + (let ((v (%u64.2!-from-u64 (sb-simd::%u64-from-s32s x x)))) + (%s32.4!-from-p128 (%u64.2-unpacklo v v)))) + +(define-fake-vop s32.4-not (a) + (%s32.4-andc1 + a + (%make-s32.4 +s32-true+ +s32-true+ +s32-true+ +s32-true+))) + +(define-fake-vop two-arg-s32.4/= (a b) + (%u32.4-not + (%two-arg-s32.4= a b))) + +(define-fake-vop two-arg-s32.4< (a b) + (%two-arg-s32.4> b a)) + +(define-fake-vop two-arg-s32.4>= (a b) + (%u32.4-not + (%two-arg-s32.4< a b))) + +(define-fake-vop two-arg-s32.4<= (a b) + (%u32.4-not + (%two-arg-s32.4> a b))) + +(define-fake-vop s64.2!-from-s64 (x) + (%s64.2!-from-p128 (%u64.2!-from-u64 (sb-simd::%u64-from-s64 x)))) + +(define-fake-vop make-s64.2 (a b) + (%s64.2-unpacklo + (%s64.2!-from-p128 (%u64.2!-from-u64 (sb-simd::%u64-from-s64 a))) + (%s64.2!-from-p128 (%u64.2!-from-u64 (sb-simd::%u64-from-s64 b))))) + +(define-fake-vop s64.2-values (x) + (multiple-value-call #'values + (sb-simd::%s64-from-u64 (%u64!-from-p128 x)) + (sb-simd::%s64-from-u64 (%u64!-from-p128 (%u64.2-permute (%u64.2!-from-p128 x) 1))))) + +(define-fake-vop s64.2-broadcast (x) + (let ((v (%u64.2!-from-u64 (sb-simd::%u64-from-s64 x)))) + (%s64.2!-from-p128 (%u64.2-unpacklo v v)))) + +(define-fake-vop s64.2-not (a) + (%s64.2-andc1 + a + (%make-s64.2 +s64-true+ +s64-true+))) + +(define-fake-vop two-arg-s64.2/= (a b) + (%u64.2-not + (%two-arg-s64.2= a b))) + +(define-fake-vop two-arg-s64.2< (a b) + (%two-arg-s64.2> b a)) + +(define-fake-vop two-arg-s64.2>= (a b) + (sb-simd-avx::%u64.2-not + (%two-arg-s64.2< a b))) + +(define-fake-vop two-arg-s64.2<= (a b) + (sb-simd-avx::%u64.2-not + (%two-arg-s64.2> a b))) + +(define-fake-vop s8.32!-from-s8 (x) + (%s8.32!-from-p256 (%u64.4!-from-u64 (sb-simd::%u64-from-s8s x 0 0 0 0 0 0 0)))) + +(define-fake-vop make-s8.32 + (s01 s02 s03 s04 s05 s06 s07 s08 s09 s10 s11 s12 s13 s14 s15 s16 s17 s18 s19 s20 s21 s22 s23 s24 s25 s26 s27 s28 s29 s30 s31 s32) + (let ((lo (%make-s8.16 s01 s02 s03 s04 s05 s06 s07 s08 s09 s10 s11 s12 s13 s14 s15 s16)) + (hi (%make-s8.16 s17 s18 s19 s20 s21 s22 s23 s24 s25 s26 s27 s28 s29 s30 s31 s32))) + (%s8.32-insert-s8.16 (%s8.32!-from-p128 lo) hi 1))) + +(define-fake-vop s8.32-values (x) + (multiple-value-call #'values + (%s8.16-values (%s8.16!-from-p256 x)) + (%s8.16-values (%s8.16-from-s8.32 x 1)))) + +(define-fake-vop s8.32-broadcast (x) + (let ((v (%s8.16-broadcast x))) + (%s8.32-insert-s8.16 (%s8.32!-from-p128 v) v 1))) + +(define-fake-vop s16.16!-from-s16 (x) + (%s16.16!-from-p256 (%u64.4!-from-u64 (sb-simd::%u64-from-s16s x 0 0 0)))) + +(define-fake-vop make-s16.16 (a b c d e f g h i j k l m n o p) + (let ((lo (%make-s16.8 a b c d e f g h)) + (hi (%make-s16.8 i j k l m n o p))) + (%s16.16-insert-s16.8 (%s16.16!-from-p128 lo) hi 1))) + +(define-fake-vop s16.16-values (x) + (multiple-value-call #'values + (%s16.8-values (%s16.8!-from-p256 x)) + (%s16.8-values (%s16.8-from-s16.16 x 1)))) + +(define-fake-vop s16.16-broadcast (x) + (let ((v (%s16.8-broadcast x))) + (%s16.16-insert-s16.8 (%s16.16!-from-p128 v) v 1))) + +(define-fake-vop s32.8!-from-s32 (x) + (%s32.8!-from-p256 (%u64.4!-from-u64 (sb-simd::%u64-from-s32s x 0)))) + +(define-fake-vop make-s32.8 (a b c d e f g h) + (let ((lo (%make-s32.4 a b c d)) + (hi (%make-s32.4 e f g h))) + (%s32.8-insert-s32.4 (%s32.8!-from-p128 lo) hi 1))) + +(define-fake-vop s32.8-values (x) + (multiple-value-call #'values + (%s32.4-values (%s32.4!-from-p256 x)) + (%s32.4-values (%s32.4-from-s32.8 x 1)))) + +(define-fake-vop s32.8-broadcast (x) + (let ((v (%s32.4-broadcast x))) + (%s32.8-insert-s32.4 (%s32.8!-from-p128 v) v 1))) + +(define-fake-vop s64.4!-from-s64 (x) + (%s64.4!-from-p256 (%u64.4!-from-u64 (sb-simd::%u64-from-s64 x)))) + +(define-fake-vop make-s64.4 (a b c d) + (let ((lo (%make-s64.2 a b)) + (hi (%make-s64.2 c d))) + (%s64.4-insert-s64.2 (%s64.4!-from-p128 lo) hi 1))) + +(define-fake-vop s64.4-values (x) + (multiple-value-call #'values + (%s64.2-values (%s64.2!-from-p256 x)) + (%s64.2-values (%s64.2-from-s64.4 x 1)))) + +(define-fake-vop s64.4-broadcast (x) + (let ((v (%s64.2-broadcast x))) + (%s64.4-insert-s64.2 (%s64.4!-from-p128 v) v 1))) + +(in-package #:sb-simd-avx2) + +(define-fake-vop u8.16-broadcast (x) + (%u8.16-broadcastvec (sb-simd-avx::%u8.16!-from-u8 x))) + +(define-fake-vop u16.8-broadcast (x) + (%u16.8-broadcastvec (sb-simd-avx::%u16.8!-from-u16 x))) + +(define-fake-vop u32.4-broadcast (x) + (%u32.4-broadcastvec (sb-simd-avx::%u32.4!-from-u32 x))) + +(define-fake-vop u64.2-broadcast (x) + (%u64.2-broadcastvec (sb-simd-avx::%u64.2!-from-u64 x))) + +(define-fake-vop s8.16-broadcast (x) + (%s8.16-broadcastvec (sb-simd-avx::%s8.16!-from-s8 x))) + +(define-fake-vop s16.8-broadcast (x) + (%s16.8-broadcastvec (sb-simd-avx::%s16.8!-from-s16 x))) + +(define-fake-vop s32.4-broadcast (x) + (%s32.4-broadcastvec (sb-simd-avx::%s32.4!-from-s32 x))) + +(define-fake-vop s64.2-broadcast (x) + (%s64.2-broadcastvec (sb-simd-avx::%s64.2!-from-s64 x))) + +(define-fake-vop make-u8.32 + (u01 u02 u03 u04 u05 u06 u07 u08 u09 u10 u11 u12 u13 u14 u15 u16 u17 u18 u19 u20 u21 u22 u23 u24 u25 u26 u27 u28 u29 u30 u31 u32) + (let ((lo (sb-simd-avx::%make-u8.16 u01 u02 u03 u04 u05 u06 u07 u08 u09 u10 u11 u12 u13 u14 u15 u16)) + (hi (sb-simd-avx::%make-u8.16 u17 u18 u19 u20 u21 u22 u23 u24 u25 u26 u27 u28 u29 u30 u31 u32))) + (%u8.32-insert-u8.16 (sb-simd-avx::%u8.32!-from-p128 lo) hi 1))) + +(define-fake-vop u8.32-values (x) + (multiple-value-call #'values + (sb-simd-avx::%u8.16-values (sb-simd-avx::%u8.16!-from-p256 x)) + (sb-simd-avx::%u8.16-values (%u8.16-from-u8.32 x 1)))) + +(define-fake-vop u8.32-broadcast (x) + (%u8.32-broadcastvec (sb-simd-avx::%u8.32!-from-u8 x))) + +(define-fake-vop u8.32-not (a) + (%u8.32-andc1 + a + (%make-u8.32 +u8-true+ +u8-true+ +u8-true+ +u8-true+ + +u8-true+ +u8-true+ +u8-true+ +u8-true+ + +u8-true+ +u8-true+ +u8-true+ +u8-true+ + +u8-true+ +u8-true+ +u8-true+ +u8-true+ + +u8-true+ +u8-true+ +u8-true+ +u8-true+ + +u8-true+ +u8-true+ +u8-true+ +u8-true+ + +u8-true+ +u8-true+ +u8-true+ +u8-true+ + +u8-true+ +u8-true+ +u8-true+ +u8-true+))) + +(define-fake-vop two-arg-u8.32/= (a b) + (%u8.32-not + (%two-arg-u8.32= a b))) + +(define-fake-vop two-arg-u8.32> (a b) + (let* ((x (expt 2 7)) + (v (%make-u8.32 x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x))) + (%two-arg-u8.32>~ (%two-arg-u8.32- a v) + (%two-arg-u8.32- b v)))) + +(define-fake-vop two-arg-u8.32< (a b) + (%two-arg-u8.32> b a)) + +(define-fake-vop two-arg-u8.32>= (a b) + (%u8.32-not + (%two-arg-u8.32< a b))) + +(define-fake-vop two-arg-u8.32<= (a b) + (%u8.32-not + (%two-arg-u8.32> a b))) + +(define-fake-vop make-u16.16 (a b c d e f g h i j k l m n o p) + (let ((lo (sb-simd-avx::%make-u16.8 a b c d e f g h)) + (hi (sb-simd-avx::%make-u16.8 i j k l m n o p))) + (%u16.16-insert-u16.8 (sb-simd-avx::%u16.16!-from-p128 lo) hi 1))) + +(define-fake-vop u16.16-values (x) + (multiple-value-call #'values + (sb-simd-avx::%u16.8-values (sb-simd-avx::%u16.8!-from-p256 x)) + (sb-simd-avx::%u16.8-values (%u16.8-from-u16.16 x 1)))) + +(define-fake-vop u16.16-broadcast (x) + (%u16.16-broadcastvec (sb-simd-avx::%u16.16!-from-u16 x))) + +(define-fake-vop u16.16-not (a) + (%u16.16-andc1 + a + (%make-u16.16 +u16-true+ +u16-true+ +u16-true+ +u16-true+ + +u16-true+ +u16-true+ +u16-true+ +u16-true+ + +u16-true+ +u16-true+ +u16-true+ +u16-true+ + +u16-true+ +u16-true+ +u16-true+ +u16-true+))) + +(define-fake-vop two-arg-u16.16/= (a b) + (%u16.16-not + (%two-arg-u16.16= a b))) + +(define-fake-vop two-arg-u16.16> (a b) + (let* ((x (expt 2 15)) + (v (%make-u16.16 x x x x x x x x x x x x x x x x))) + (%two-arg-u16.16>~ (%two-arg-u16.16- a v) + (%two-arg-u16.16- b v)))) + +(define-fake-vop two-arg-u16.16< (a b) + (%two-arg-u16.16> b a)) + +(define-fake-vop two-arg-u16.16>= (a b) + (%u16.16-not + (%two-arg-u16.16< a b))) + +(define-fake-vop two-arg-u16.16<= (a b) + (%u16.16-not + (%two-arg-u16.16> a b))) + +(define-fake-vop u16.16-movemask (a) + (u32-odd-bits + (%u8.32-movemask + (sb-simd-avx::%u8.32!-from-p256 a)))) + +(define-fake-vop make-u32.8 (a b c d e f g h) + (let ((lo (sb-simd-avx::%make-u32.4 a b c d)) + (hi (sb-simd-avx::%make-u32.4 e f g h))) + (%u32.8-insert-u32.4 (sb-simd-avx::%u32.8!-from-p128 lo) hi 1))) + +(define-fake-vop u32.8-values (x) + (multiple-value-call #'values + (sb-simd-avx::%u32.4-values (sb-simd-avx::%u32.4!-from-p256 x)) + (sb-simd-avx::%u32.4-values (%u32.4-from-u32.8 x 1)))) + +(define-fake-vop u32.8-broadcast (x) + (%u32.8-broadcastvec (sb-simd-avx::%u32.8!-from-u32 x))) + +(define-fake-vop u32.8-not (a) + (%u32.8-andc1 + a + (%make-u32.8 +u32-true+ +u32-true+ +u32-true+ +u32-true+ + +u32-true+ +u32-true+ +u32-true+ +u32-true+))) + +(define-fake-vop two-arg-u32.8/= (a b) + (%u32.8-not + (%two-arg-u32.8= a b))) + +(define-fake-vop two-arg-u32.8> (a b) + (let* ((x (expt 2 31)) + (v (%make-u32.8 x x x x x x x x))) + (%two-arg-u32.8>~ (%two-arg-u32.8- a v) + (%two-arg-u32.8- b v)))) + +(define-fake-vop two-arg-u32.8< (a b) + (%two-arg-u32.8> b a)) + +(define-fake-vop two-arg-u32.8>= (a b) + (%u32.8-not + (%two-arg-u32.8< a b))) + +(define-fake-vop two-arg-u32.8<= (a b) + (%u32.8-not + (%two-arg-u32.8> a b))) + +(define-fake-vop make-u64.4 (a b c d) + (let ((lo (sb-simd-avx::%make-u64.2 a b)) + (hi (sb-simd-avx::%make-u64.2 c d))) + (%u64.4-insert-u64.2 (sb-simd-avx::%u64.4!-from-p128 lo) hi 1))) + +(define-fake-vop u64.4-values (x) + (multiple-value-call #'values + (sb-simd-avx::%u64.2-values (sb-simd-avx::%u64.2!-from-p256 x)) + (sb-simd-avx::%u64.2-values (%u64.2-from-u64.4 x 1)))) + +(define-fake-vop u64.4-broadcast (x) + (%u64.4-broadcastvec (sb-simd-avx::%u64.4!-from-u64 x))) + +(define-fake-vop u64.4-not (a) + (%u64.4-andc1 + a + (%make-u64.4 +u64-true+ +u64-true+ +u64-true+ +u64-true+))) + +(define-fake-vop two-arg-u64.4/= (a b) + (%u64.4-not + (%two-arg-u64.4= a b))) + +(define-fake-vop two-arg-u64.4> (a b) + (let* ((x (expt 2 63)) + (v (%make-u64.4 x x x x))) + (%two-arg-u64.4>~ (%two-arg-u64.4- a v) + (%two-arg-u64.4- b v)))) + +(define-fake-vop two-arg-u64.4< (a b) + (%two-arg-u64.4> b a)) + +(define-fake-vop two-arg-u64.4>= (a b) + (%u64.4-not + (%two-arg-u64.4< a b))) + +(define-fake-vop two-arg-u64.4<= (a b) + (%u64.4-not + (%two-arg-u64.4> a b))) + +(define-fake-vop make-s8.32 + (s01 s02 s03 s04 s05 s06 s07 s08 s09 s10 s11 s12 s13 s14 s15 s16 s17 s18 s19 s20 s21 s22 s23 s24 s25 s26 s27 s28 s29 s30 s31 s32) + (let ((lo (sb-simd-avx::%make-s8.16 s01 s02 s03 s04 s05 s06 s07 s08 s09 s10 s11 s12 s13 s14 s15 s16)) + (hi (sb-simd-avx::%make-s8.16 s17 s18 s19 s20 s21 s22 s23 s24 s25 s26 s27 s28 s29 s30 s31 s32))) + (%s8.32-insert-s8.16 (sb-simd-avx::%s8.32!-from-p128 lo) hi 1))) + +(define-fake-vop s8.32-values (x) + (multiple-value-call #'values + (sb-simd-avx::%s8.16-values (sb-simd-avx::%s8.16!-from-p256 x)) + (sb-simd-avx::%s8.16-values (%s8.16-from-s8.32 x 1)))) + +(define-fake-vop s8.32-broadcast (x) + (%s8.32-broadcastvec (sb-simd-avx::%s8.32!-from-s8 x))) + +(define-fake-vop s8.32-not (a) + (%s8.32-andc1 + a + (%make-s8.32 +s8-true+ +s8-true+ +s8-true+ +s8-true+ + +s8-true+ +s8-true+ +s8-true+ +s8-true+ + +s8-true+ +s8-true+ +s8-true+ +s8-true+ + +s8-true+ +s8-true+ +s8-true+ +s8-true+ + +s8-true+ +s8-true+ +s8-true+ +s8-true+ + +s8-true+ +s8-true+ +s8-true+ +s8-true+ + +s8-true+ +s8-true+ +s8-true+ +s8-true+ + +s8-true+ +s8-true+ +s8-true+ +s8-true+))) + +(define-fake-vop two-arg-s8.32/= (a b) + (%u8.32-not + (%two-arg-s8.32= a b))) + +(define-fake-vop two-arg-s8.32< (a b) + (%two-arg-s8.32> b a)) + +(define-fake-vop two-arg-s8.32>= (a b) + (%u8.32-not + (%two-arg-s8.32< a b))) + +(define-fake-vop two-arg-s8.32<= (a b) + (%u8.32-not + (%two-arg-s8.32> a b))) + +(define-fake-vop make-s16.16 (a b c d e f g h i j k l m n o p) + (let ((lo (sb-simd-avx::%make-s16.8 a b c d e f g h)) + (hi (sb-simd-avx::%make-s16.8 i j k l m n o p))) + (%s16.16-insert-s16.8 (sb-simd-avx::%s16.16!-from-p128 lo) hi 1))) + +(define-fake-vop s16.16-values (x) + (multiple-value-call #'values + (sb-simd-avx::%s16.8-values (sb-simd-avx::%s16.8!-from-p256 x)) + (sb-simd-avx::%s16.8-values (sb-simd-avx::%s16.8-from-s16.16 x 1)))) + +(define-fake-vop s16.16-broadcast (x) + (%s16.16-broadcastvec (sb-simd-avx::%s16.16!-from-s16 x))) + +(define-fake-vop s16.16-not (a) + (%s16.16-andc1 + a + (%make-s16.16 +s16-true+ +s16-true+ +s16-true+ +s16-true+ + +s16-true+ +s16-true+ +s16-true+ +s16-true+ + +s16-true+ +s16-true+ +s16-true+ +s16-true+ + +s16-true+ +s16-true+ +s16-true+ +s16-true+))) + +(define-fake-vop two-arg-s16.16/= (a b) + (%u16.16-not + (%two-arg-s16.16= a b))) + +(define-fake-vop two-arg-s16.16< (a b) + (%two-arg-s16.16> b a)) + +(define-fake-vop two-arg-s16.16>= (a b) + (%u16.16-not + (%two-arg-s16.16< a b))) + +(define-fake-vop two-arg-s16.16<= (a b) + (%u16.16-not + (%two-arg-s16.16> a b))) + +(define-fake-vop s16.16-movemask (a) + (u32-odd-bits + (%u8.32-movemask + (sb-simd-avx::%u8.32!-from-p256 a)))) + +(define-fake-vop make-s32.8 (a b c d e f g h) + (let ((lo (sb-simd-avx::%make-s32.4 a b c d)) + (hi (sb-simd-avx::%make-s32.4 e f g h))) + (%s32.8-insert-s32.4 (sb-simd-avx::%s32.8!-from-p128 lo) hi 1))) + +(define-fake-vop s32.8-values (x) + (multiple-value-call #'values + (sb-simd-avx::%s32.4-values (sb-simd-avx::%s32.4!-from-p256 x)) + (sb-simd-avx::%s32.4-values (sb-simd-avx::%s32.4-from-s32.8 x 1)))) + +(define-fake-vop s32.8-broadcast (x) + (%s32.8-broadcastvec (sb-simd-avx::%s32.8!-from-s32 x))) + +(define-fake-vop s32.8-not (a) + (%s32.8-andc1 + a + (%make-s32.8 +s32-true+ +s32-true+ +s32-true+ +s32-true+ + +s32-true+ +s32-true+ +s32-true+ +s32-true+))) + +(define-fake-vop two-arg-s32.8/= (a b) + (%u32.8-not + (%two-arg-s32.8= a b))) + +(define-fake-vop two-arg-s32.8< (a b) + (%two-arg-s32.8> b a)) + +(define-fake-vop two-arg-s32.8>= (a b) + (%u32.8-not + (%two-arg-s32.8< a b))) + +(define-fake-vop two-arg-s32.8<= (a b) + (%u32.8-not + (%two-arg-s32.8> a b))) + +(define-fake-vop make-s64.4 (a b c d) + (let ((lo (sb-simd-avx::%make-s64.2 a b)) + (hi (sb-simd-avx::%make-s64.2 c d))) + (%s64.4-insert-s64.2 (sb-simd-avx::%s64.4!-from-p128 lo) hi 1))) + +(define-fake-vop s64.4-values (x) + (multiple-value-call #'values + (sb-simd-avx::%s64.2-values (sb-simd-avx::%s64.2!-from-p256 x)) + (sb-simd-avx::%s64.2-values (%s64.2-from-s64.4 x 1)))) + +(define-fake-vop s64.4-broadcast (x) + (%s64.4-broadcastvec (sb-simd-avx::%s64.4!-from-s64 x))) + +(define-fake-vop s64.4-not (a) + (%s64.4-andc1 + a + (%make-s64.4 +s64-true+ +s64-true+ +s64-true+ +s64-true+))) + +(define-fake-vop two-arg-s64.4/= (a b) + (%u64.4-not + (%two-arg-s64.4= a b))) + +(define-fake-vop two-arg-s64.4< (a b) + (%two-arg-s64.4> b a)) + +(define-fake-vop two-arg-s64.4>= (a b) + (%u64.4-not + (%two-arg-s64.4< a b))) + +(define-fake-vop two-arg-s64.4<= (a b) + (%u64.4-not + (%two-arg-s64.4> a b))) + +(define-fake-vop f64.4-reverse (a) + (%f64.4-permute4x64 a #b00011011)) diff --git a/contrib/sb-simd/code/define-ifs.lisp b/contrib/sb-simd/code/define-ifs.lisp new file mode 100644 index 0000000000..c41e7cb604 --- /dev/null +++ b/contrib/sb-simd/code/define-ifs.lisp @@ -0,0 +1,28 @@ +(in-package #:sb-simd-internals) + +(macrolet + ((define-if (if-record-name) + (with-accessors ((name if-record-name) + (blend if-record-blend)) + (find-function-record if-record-name) + (with-accessors ((blend instruction-record-name) + (result-records instruction-record-result-records) + (argument-records instruction-record-argument-records)) blend + (destructuring-bind (a-record b-record mask-record) argument-records + (assert (eq a-record b-record)) + (assert (= (value-record-bits a-record) + (value-record-bits mask-record))) + (destructuring-bind (result-record) result-records + (assert (eq result-record a-record)) + (let ((value-type (value-record-name a-record)) + (mask-type (value-record-name mask-record))) + `(define-inline ,name (mask a b) + (the ,value-type + (,blend (,value-type b) + (,value-type a) + (,mask-type mask)))))))))) + (define-ifs () + `(progn + ,@(loop for if-record in (filter-function-records #'if-record-p) + collect `(define-if ,(if-record-name if-record)))))) + (define-ifs)) diff --git a/contrib/sb-simd/code/define-instruction-vops.lisp b/contrib/sb-simd/code/define-instruction-vops.lisp new file mode 100644 index 0000000000..03e9ce207d --- /dev/null +++ b/contrib/sb-simd/code/define-instruction-vops.lisp @@ -0,0 +1,181 @@ +(in-package #:sb-vm) + +(macrolet + ((define-instruction-vop (instruction-record-name) + (with-accessors ((name sb-simd-internals:instruction-record-name) + (vop sb-simd-internals:instruction-record-vop) + (mnemonic sb-simd-internals:instruction-record-mnemonic) + (argument-records sb-simd-internals:instruction-record-argument-records) + (result-records sb-simd-internals:instruction-record-result-records) + (cost sb-simd-internals:instruction-record-cost) + (pure sb-simd-internals:instruction-record-pure) + (always-translatable sb-simd-internals:instruction-record-always-translatable) + (associative sb-simd-internals:instruction-record-associative) + (prefix sb-simd-internals:instruction-record-prefix) + (suffix sb-simd-internals:instruction-record-suffix) + (encoding sb-simd-internals:instruction-record-encoding)) + (sb-simd-internals:find-function-record instruction-record-name) + (let* ((asyms (sb-simd-internals:prefixed-symbols "A" (length argument-records))) + (rsyms (sb-simd-internals:prefixed-symbols "R" (length result-records))) + (defknown + `(defknown ,vop + (,@(mapcar #'sb-simd-internals:value-record-name argument-records)) + (values ,@(mapcar #'sb-simd-internals:value-record-name result-records) &optional) + (,@(when (and always-translatable (not (eq encoding :fake-vop))) + '(always-translatable)) + ,@(when pure '(foldable flushable movable))) + :overwrite-fndb-silently t)) + (arg-types + (mapcar #'sb-simd-internals:value-record-primitive-type argument-records)) + (result-types + (mapcar #'sb-simd-internals:value-record-primitive-type result-records)) + (args + (loop for asym in asyms + for argument-record in argument-records + when (symbolp (sb-simd-internals:value-record-primitive-type argument-record)) + collect `(,asym :scs ,(sb-simd-internals:value-record-scs argument-record)))) + (info + (loop for asym in asyms + for argument-record in argument-records + unless (symbolp (sb-simd-internals:value-record-primitive-type argument-record)) + collect asym)) + (results + (loop for rsym in rsyms + for result-record in result-records + collect `(,rsym :scs ,(sb-simd-internals:value-record-scs result-record))))) + (ecase encoding + ((:fake-vop :custom) + `(progn ,defknown)) + (:standard + (assert mnemonic) + `(progn + ,defknown + (define-vop (,vop) + (:translate ,vop) + (:policy :fast-safe) + (:args ,@args) + (:info ,@info) + (:results ,@results) + (:arg-types ,@arg-types) + (:result-types ,@result-types) + (:generator + ,cost + (inst ,mnemonic ,@prefix ,@rsyms ,@asyms ,@suffix))))) + (:move + (assert mnemonic) + (let ((src (first asyms)) + (dst (first rsyms))) + `(progn + ,defknown + (define-vop (,vop) + (:translate ,vop) + (:policy :fast-safe) + (:args (,@(first args) :target ,dst) ,@(rest args)) + (:info ,@info) + (:results ,@results) + (:arg-types ,@arg-types) + (:result-types ,@result-types) + (:generator + ,cost + (unless (location= ,dst ,src) + (inst ,mnemonic ,@prefix ,@rsyms ,@asyms ,@suffix))))))) + (:sse + (assert mnemonic) + (let ((x (first asyms)) + (y (second asyms)) + (rest (rest (rest asyms))) + (r (first rsyms))) + `(progn + ,defknown + (define-vop (,vop) + (:translate ,vop) + (:policy :fast-safe) + (:args (,@(first args) :target ,r) ,@(rest args)) + (:temporary (:sc ,(first (sb-simd-internals:value-record-scs (first argument-records)))) tmp) + (:info ,@info) + (:results ,@results) + (:arg-types ,@arg-types) + (:result-types ,@result-types) + (:generator + ,cost + (cond ((location= ,x ,r) + (inst ,mnemonic ,@prefix ,r ,y ,@rest ,@suffix)) + ((or (not (tn-p ,y)) + (not (location= ,y ,r))) + (move ,r ,x) + (inst ,mnemonic ,@prefix ,r ,y ,@rest ,@suffix)) + (t + (move tmp ,x) + (inst ,mnemonic ,@prefix tmp ,y ,@rest ,@suffix) + (move ,r tmp)))))))) + (:sse+xmm0 + (assert mnemonic) + (let ((x (first asyms)) + (y (second asyms)) + (z (third asyms)) + (r (first rsyms))) + `(progn + ,defknown + (define-vop (,vop) + (:translate ,vop) + (:policy :fast-safe) + (:args (,@(first args) :target ,r) ,(second args) (,@(third args) :target xmm0)) + (:temporary (:sc ,(first (sb-simd-internals:value-record-scs (first argument-records)))) tmp) + (:temporary (:sc ,(first (sb-simd-internals:value-record-scs (second argument-records))) + :from (:argument 0) :to :result :offset 0) xmm0) + (:info ,@info) + (:results ,@results) + (:arg-types ,@arg-types) + (:result-types ,@result-types) + (:generator + ,cost + (move xmm0 ,z) + (cond ((location= ,x ,r) + (inst ,mnemonic ,@prefix ,r ,y xmm0 ,@suffix)) + ((or (not (tn-p ,y)) + (not (location= ,y ,r))) + (move ,r ,x) + (inst ,mnemonic ,@prefix ,r ,y xmm0 ,@suffix)) + (t + (move tmp ,x) + (inst ,mnemonic ,@prefix tmp ,y xmm0 ,@suffix) + (move ,r tmp)))))))) + (:fma + (assert mnemonic) + (let ((x (first asyms)) + (y (second asyms)) + (z (third asyms)) + (rest (rest (rest (rest asyms)))) + (r (first rsyms))) + `(progn + ,defknown + (define-vop (,vop) + (:translate ,vop) + (:policy :fast-safe) + (:args (,@(first args) :target ,r) ,@(rest args)) + (:temporary (:sc ,(first (sb-simd-internals:value-record-scs (first argument-records)))) tmp) + (:info ,@info) + (:results ,@results) + (:arg-types ,@arg-types) + (:result-types ,@result-types) + (:generator + ,cost + (cond ((location= ,x ,r) + (inst ,mnemonic ,@prefix ,r ,y ,z ,@rest ,@suffix)) + ((and (or (not (tn-p ,y)) + (not (location= ,y ,r))) + (or (not (tn-p ,z)) + (not (location= ,z ,r)))) + (move ,r ,x) + (inst ,mnemonic ,@prefix ,r ,y ,z ,@rest ,@suffix)) + (t + (move tmp ,x) + (inst ,mnemonic ,@prefix tmp ,y ,z ,@rest ,@suffix) + (move ,r tmp)))))))))))) + (define-instruction-vops () + `(progn + ,@(loop for instruction-record + in (sb-simd-internals:filter-available-function-records + #'sb-simd-internals:instruction-record-p) + collect `(define-instruction-vop ,(sb-simd-internals:instruction-record-name instruction-record)))))) + (define-instruction-vops)) diff --git a/contrib/sb-simd/code/define-instructions.lisp b/contrib/sb-simd/code/define-instructions.lisp new file mode 100644 index 0000000000..5cb846d791 --- /dev/null +++ b/contrib/sb-simd/code/define-instructions.lisp @@ -0,0 +1,30 @@ +(in-package #:sb-simd-internals) + +(macrolet + ((define-instruction (name) + (with-accessors ((name instruction-record-name) + (vop instruction-record-vop) + (argument-records instruction-record-argument-records) + (encoding instruction-record-encoding) + (instruction-set instruction-record-instruction-set)) + (find-function-record name) + (let ((argument-record-names (mapcar #'record-name argument-records)) + (argument-symbols (prefixed-symbols "ARGUMENT-" (length argument-records)))) + (if (not (instruction-set-available-p instruction-set)) + `(define-missing-instruction ,name + :required-arguments ,argument-symbols) + ;; Define the actual instruction as a wrapper around the VOP + ;; that attempts to cast all arguments to the correct types. + `(define-inline ,name ,argument-symbols + (let ,(loop for argument-symbol in argument-symbols + for type in (mapcar #'value-record-name argument-records) + collect `(,argument-symbol (,type ,argument-symbol))) + (with-primitive-arguments + ,(mapcar #'list argument-symbols argument-record-names) + (,vop ,@argument-symbols)))))))) + (define-instructions () + `(progn + ,@(loop for instruction-record in (filter-function-records #'instruction-record-p) + for name = (instruction-record-name instruction-record) + collect `(define-instruction ,name))))) + (define-instructions)) diff --git a/contrib/sb-simd/code/define-modify-macros.lisp b/contrib/sb-simd/code/define-modify-macros.lisp new file mode 100644 index 0000000000..141a285324 --- /dev/null +++ b/contrib/sb-simd/code/define-modify-macros.lisp @@ -0,0 +1,142 @@ +(in-package #:sb-simd) + +(define-modify-macro f32-incf (&optional (num 1f0)) two-arg-f32+) +(define-modify-macro f32-decf (&optional (num 1f0)) two-arg-f32-) + +(define-modify-macro f64-incf (&optional (num 1d0)) two-arg-f64+) +(define-modify-macro f64-decf (&optional (num 1d0)) two-arg-f64-) + +(define-modify-macro u8-incf (&optional (num 1)) two-arg-u8+) +(define-modify-macro u8-decf (&optional (num 1)) two-arg-u8-) + +(define-modify-macro u16-incf (&optional (num 1)) two-arg-u16+) +(define-modify-macro u16-decf (&optional (num 1)) two-arg-u16-) + +(define-modify-macro u32-incf (&optional (num 1)) two-arg-u32+) +(define-modify-macro u32-decf (&optional (num 1)) two-arg-u32-) + +(define-modify-macro u64-incf (&optional (num 1)) two-arg-u64+) +(define-modify-macro u64-decf (&optional (num 1)) two-arg-u64-) + +(define-modify-macro s8-incf (&optional (num 1)) two-arg-s8+) +(define-modify-macro s8-decf (&optional (num 1)) two-arg-s8-) + +(define-modify-macro s16-incf (&optional (num 1)) two-arg-s16+) +(define-modify-macro s16-decf (&optional (num 1)) two-arg-s16-) + +(define-modify-macro s32-incf (&optional (num 1)) two-arg-s32+) +(define-modify-macro s32-decf (&optional (num 1)) two-arg-s32-) + +(define-modify-macro s64-incf (&optional (num 1)) two-arg-s64+) +(define-modify-macro s64-decf (&optional (num 1)) two-arg-s64-) + +(in-package #:sb-simd-sse) + +(define-modify-macro f32-incf (&optional (num 1f0)) two-arg-f32+) +(define-modify-macro f32-decf (&optional (num 1f0)) two-arg-f32-) + +(define-modify-macro f32.4-incf (&optional (num 1f0)) two-arg-f32.4+) +(define-modify-macro f32.4-decf (&optional (num 1f0)) two-arg-f32.4-) + +(in-package #:sb-simd-sse2) + +(define-modify-macro f64-incf (&optional (num 1d0)) two-arg-f64+) +(define-modify-macro f64-decf (&optional (num 1d0)) two-arg-f64-) + +(define-modify-macro f64.2-incf (&optional (num 1d0)) two-arg-f64.2+) +(define-modify-macro f64.2-decf (&optional (num 1d0)) two-arg-f64.2-) + +(define-modify-macro u8.16-incf (&optional (num 1)) two-arg-u8.16+) +(define-modify-macro u8.16-decf (&optional (num 1)) two-arg-u8.16-) + +(define-modify-macro u16.8-incf (&optional (num 1)) two-arg-u16.8+) +(define-modify-macro u16.8-decf (&optional (num 1)) two-arg-u16.8-) + +(define-modify-macro u32.4-incf (&optional (num 1)) two-arg-u32.4+) +(define-modify-macro u32.4-decf (&optional (num 1)) two-arg-u32.4-) + +(define-modify-macro u64.2-incf (&optional (num 1)) two-arg-u64.2+) +(define-modify-macro u64.2-decf (&optional (num 1)) two-arg-u64.2-) + +(define-modify-macro s8.16-incf (&optional (num 1)) two-arg-s8.16+) +(define-modify-macro s8.16-decf (&optional (num 1)) two-arg-s8.16-) + +(define-modify-macro s16.8-incf (&optional (num 1)) two-arg-s16.8+) +(define-modify-macro s16.8-decf (&optional (num 1)) two-arg-s16.8-) + +(define-modify-macro s32.4-incf (&optional (num 1)) two-arg-s32.4+) +(define-modify-macro s32.4-decf (&optional (num 1)) two-arg-s32.4-) + +(define-modify-macro s64.2-incf (&optional (num 1)) two-arg-s64.2+) +(define-modify-macro s64.2-decf (&optional (num 1)) two-arg-s64.2-) + +(in-package #:sb-simd-avx) + +(define-modify-macro f32-incf (&optional (num 1f0)) two-arg-f32+) +(define-modify-macro f32-decf (&optional (num 1f0)) two-arg-f32-) + +(define-modify-macro f64-incf (&optional (num 1d0)) two-arg-f64+) +(define-modify-macro f64-decf (&optional (num 1d0)) two-arg-f64-) + +(define-modify-macro f32.4-incf (&optional (num 1f0)) two-arg-f32.4+) +(define-modify-macro f32.4-decf (&optional (num 1f0)) two-arg-f32.4-) + +(define-modify-macro f32.8-incf (&optional (num 1f0)) two-arg-f32.8+) +(define-modify-macro f32.8-decf (&optional (num 1f0)) two-arg-f32.8-) + +(define-modify-macro f64.2-incf (&optional (num 1d0)) two-arg-f64.2+) +(define-modify-macro f64.2-decf (&optional (num 1d0)) two-arg-f64.2-) + +(define-modify-macro f64.4-incf (&optional (num 1d0)) two-arg-f64.4+) +(define-modify-macro f64.4-decf (&optional (num 1d0)) two-arg-f64.4-) + +(define-modify-macro u8.16-incf (&optional (num 1)) two-arg-u8.16+) +(define-modify-macro u8.16-decf (&optional (num 1)) two-arg-u8.16-) + +(define-modify-macro u16.8-incf (&optional (num 1)) two-arg-u16.8+) +(define-modify-macro u16.8-decf (&optional (num 1)) two-arg-u16.8-) + +(define-modify-macro u32.4-incf (&optional (num 1)) two-arg-u32.4+) +(define-modify-macro u32.4-decf (&optional (num 1)) two-arg-u32.4-) + +(define-modify-macro u64.2-incf (&optional (num 1)) two-arg-u64.2+) +(define-modify-macro u64.2-decf (&optional (num 1)) two-arg-u64.2-) + +(define-modify-macro s8.16-incf (&optional (num 1)) two-arg-s8.16+) +(define-modify-macro s8.16-decf (&optional (num 1)) two-arg-s8.16-) + +(define-modify-macro s16.8-incf (&optional (num 1)) two-arg-s16.8+) +(define-modify-macro s16.8-decf (&optional (num 1)) two-arg-s16.8-) + +(define-modify-macro s32.4-incf (&optional (num 1)) two-arg-s32.4+) +(define-modify-macro s32.4-decf (&optional (num 1)) two-arg-s32.4-) + +(define-modify-macro s64.2-incf (&optional (num 1)) two-arg-s64.2+) +(define-modify-macro s64.2-decf (&optional (num 1)) two-arg-s64.2-) + +(in-package #:sb-simd-avx2) + +(define-modify-macro u8.32-incf (&optional (num 1)) two-arg-u8.32+) +(define-modify-macro u8.32-decf (&optional (num 1)) two-arg-u8.32-) + +(define-modify-macro u16.16-incf (&optional (num 1)) two-arg-u16.16+) +(define-modify-macro u16.16-decf (&optional (num 1)) two-arg-u16.16-) + +(define-modify-macro u32.8-incf (&optional (num 1)) two-arg-u32.8+) +(define-modify-macro u32.8-decf (&optional (num 1)) two-arg-u32.8-) + +(define-modify-macro u64.4-incf (&optional (num 1)) two-arg-u64.4+) +(define-modify-macro u64.4-decf (&optional (num 1)) two-arg-u64.4-) + +(define-modify-macro s8.32-incf (&optional (num 1)) two-arg-s8.32+) +(define-modify-macro s8.32-decf (&optional (num 1)) two-arg-s8.32-) + +(define-modify-macro s16.16-incf (&optional (num 1)) two-arg-s16.16+) +(define-modify-macro s16.16-decf (&optional (num 1)) two-arg-s16.16-) + +(define-modify-macro s32.8-incf (&optional (num 1)) two-arg-s32.8+) +(define-modify-macro s32.8-decf (&optional (num 1)) two-arg-s32.8-) + +(define-modify-macro s64.4-incf (&optional (num 1)) two-arg-s64.4+) +(define-modify-macro s64.4-decf (&optional (num 1)) two-arg-s64.4-) + diff --git a/contrib/sb-simd/code/define-reducers.lisp b/contrib/sb-simd/code/define-reducers.lisp new file mode 100644 index 0000000000..eeb09bf9d5 --- /dev/null +++ b/contrib/sb-simd/code/define-reducers.lisp @@ -0,0 +1,37 @@ +(in-package #:sb-simd-internals) + +(macrolet + ((define-reducer (reducer-record-name) + (with-accessors ((name reducer-record-name) + (binary-operation reducer-record-binary-operation) + (initial-element reducer-record-initial-element)) + (find-function-record reducer-record-name) + (with-accessors ((binary-operation instruction-record-name) + (result-records instruction-record-result-records) + (argument-records instruction-record-argument-records)) binary-operation + (destructuring-bind ((value-record) (arg1-record arg2-record)) + (list result-records argument-records) + (assert (eq value-record arg1-record)) + (assert (eq value-record arg2-record)) + (let ((type (value-record-name value-record))) + `(progn + (defun ,name (arg &rest more-args) + (if (null more-args) + (,binary-operation (,type ,initial-element) (,type arg)) + (let ((result (,type arg))) + (declare (,type result)) + (loop for arg in more-args + do (setf result (,binary-operation result (,type arg)))) + result))) + (define-compiler-macro ,name (arg &rest more-args) + (cond ((null more-args) + `(,',binary-operation ,',initial-element (,',type ,arg))) + (t (reduce + (lambda (a b) `(,',binary-operation (,',type ,a) (,',type ,b))) + more-args + :initial-value `(,',type ,arg))))))))))) + (define-reducers () + `(progn + ,@(loop for reducer-record in (filter-function-records #'reducer-record-p) + collect `(define-reducer ,(reducer-record-name reducer-record)))))) + (define-reducers)) diff --git a/contrib/sb-simd/code/define-reffers.lisp b/contrib/sb-simd/code/define-reffers.lisp new file mode 100644 index 0000000000..d6261cb062 --- /dev/null +++ b/contrib/sb-simd/code/define-reffers.lisp @@ -0,0 +1,44 @@ +(in-package #:sb-simd-internals) + +;;; In this file, we define reffers for scalars that can be defined in +;;; terms of built-in Common Lisp functions. +(macrolet + ((define-reffers () + `(progn + ,@(loop for record in (filter-function-records + (lambda (function-record) + (eq (symbol-package + (parse-function-name + (function-record-name function-record))) + (find-package "SB-SIMD")))) + for name = (function-record-name record) + for value-record = (first (function-record-result-records record)) + for type = (value-record-name value-record) + when (aref-record-p record) collect + `(progn + (defun ,name (array &rest subscripts) + (declare (type (array ,type) array)) + (apply #'aref array subscripts)) + (define-compiler-macro ,name (array &rest subscripts) + `(aref (the (array ,',type) ,array) ,@subscripts))) + when (setf-aref-record-p record) collect + `(progn + (defun ,name (value array &rest subscripts) + (declare (type ,type value) + (type (array ,type) array)) + (setf (apply #'aref array subscripts) value)) + (define-compiler-macro ,name (value array &rest subscripts) + (let ((v (gensym "VALUE"))) + `(let ((,v ,value)) + (setf (aref (the (array ,',type) ,array) ,@subscripts) + ,v))))) + when (row-major-aref-record-p record) collect + `(define-inline ,name (array index) + (declare (type (array ,type) array)) + (row-major-aref array index)) + when (setf-row-major-aref-record-p record) collect + `(define-inline ,name (value array index) + (declare (type ,type value) + (type (array ,type) array)) + (setf (row-major-aref array index) value)))))) + (define-reffers)) diff --git a/contrib/sb-simd/code/define-rounders.lisp b/contrib/sb-simd/code/define-rounders.lisp new file mode 100644 index 0000000000..48ab85890e --- /dev/null +++ b/contrib/sb-simd/code/define-rounders.lisp @@ -0,0 +1,75 @@ +(in-package #:sb-simd-sse4.1) + +(define-inline f32.4-round (x) + (f32.4-%round x #b00)) + +(define-inline f32.4-floor (x) + (f32.4-%round x #b01)) + +(define-inline f32.4-ceiling (x) + (f32.4-%round x #b10)) + +(define-inline f32.4-truncate (x) + (f32.4-%round x #b11)) + +(define-inline f64.2-round (x) + (f64.2-%round x #b00)) + +(define-inline f64.2-floor (x) + (f64.2-%round x #b01)) + +(define-inline f64.2-ceiling (x) + (f64.2-%round x #b10)) + +(define-inline f64.2-truncate (x) + (f64.2-%round x #b11)) + +(in-package #:sb-simd-avx) + +(define-inline f32.4-round (x) + (f32.4-%round x #b00)) + +(define-inline f32.4-floor (x) + (f32.4-%round x #b01)) + +(define-inline f32.4-ceiling (x) + (f32.4-%round x #b10)) + +(define-inline f32.4-truncate (x) + (f32.4-%round x #b11)) + +(define-inline f64.2-round (x) + (f64.2-%round x #b00)) + +(define-inline f64.2-floor (x) + (f64.2-%round x #b01)) + +(define-inline f64.2-ceiling (x) + (f64.2-%round x #b10)) + +(define-inline f64.2-truncate (x) + (f64.2-%round x #b11)) + +(define-inline f32.8-round (x) + (f32.8-%round x #b00)) + +(define-inline f32.8-floor (x) + (f32.8-%round x #b01)) + +(define-inline f32.8-ceiling (x) + (f32.8-%round x #b10)) + +(define-inline f32.8-truncate (x) + (f32.8-%round x #b11)) + +(define-inline f64.4-round (x) + (f64.4-%round x #b00)) + +(define-inline f64.4-floor (x) + (f64.4-%round x #b01)) + +(define-inline f64.4-ceiling (x) + (f64.4-%round x #b10)) + +(define-inline f64.4-truncate (x) + (f64.4-%round x #b11)) diff --git a/contrib/sb-simd/code/define-scalar-casts.lisp b/contrib/sb-simd/code/define-scalar-casts.lisp new file mode 100644 index 0000000000..45cb30a735 --- /dev/null +++ b/contrib/sb-simd/code/define-scalar-casts.lisp @@ -0,0 +1,78 @@ +(in-package #:sb-simd-internals) + +;;; For each value record we define a function of the same name that will +;;; either suitably convert its argument to that value record's type, or +;;; signal an error. + +(macrolet + ((define-scalar-cast (scalar-cast-record-name) + (with-accessors ((name scalar-cast-record-name)) + (find-function-record scalar-cast-record-name) + (let ((err (mksym (symbol-package name) "CANNOT-CONVERT-TO-" name))) + `(progn + (define-notinline ,err (x) + (error "Cannot convert ~S to ~S." x ',name)) + (sb-c:defknown ,name (t) (values ,name &optional) + (sb-c:foldable) + :overwrite-fndb-silently t) + (sb-c:deftransform ,name ((x) (,name) *) + 'x) + ,@(case name + (sb-simd:f32 + `((sb-c:deftransform ,name ((x) (double-float) *) + '(coerce x 'single-float)))) + (sb-simd:f64 + `((sb-c:deftransform ,name ((x) (single-float) *) + '(coerce x 'double-float)))) + (sb-simd-sse:f32 + `((sb-c:deftransform ,name ((x) (double-float) *) + '(sb-kernel:%single-float x)) + (sb-c:deftransform ,name ((x) ((signed-byte 64)) *) + '(sb-simd-sse::f32-from-s64 x)))) + (sb-simd-sse2:f64 + `((sb-c:deftransform ,name ((x) (single-float) *) + '(sb-simd-sse2::f64-from-f32 x)) + (sb-c:deftransform ,name ((x) ((signed-byte 64)) *) + '(sb-simd-sse2::f64-from-s64 x)))) + (sb-simd-avx:f32 + `((sb-c:deftransform ,name ((x) (double-float) *) + '(sb-simd-avx::f32-from-f64 x)) + (sb-c:deftransform ,name ((x) ((signed-byte 64)) *) + '(sb-simd-avx::f32-from-s64 x)))) + (sb-simd-avx:f64 + `((sb-c:deftransform ,name ((x) (single-float) *) + '(sb-simd-avx::f64-from-f32 x)) + (sb-c:deftransform ,name ((x) ((signed-byte 64)) *) + '(sb-simd-avx::f64-from-s64 x))))) + (defun ,name (x) + (typecase x + (,name x) + ,@(case name + (sb-simd:f32 + `((double-float (coerce x 'single-float)) + (real (coerce x ',name)))) + (sb-simd:f64 + `((sb-simd-sse2:f32 (coerce x 'double-float)) + (real (coerce x ',name)))) + (sb-simd-sse:f32 + `((double-float (sb-kernel:%single-float x)) + (sb-simd-sse:s64 (sb-simd-sse::%f32-from-s64 x)) + (real (coerce x ',name)))) + (sb-simd-sse2:f64 + `((sb-simd-sse2:f32 (sb-simd-sse2::%f64-from-f32 x)) + (sb-simd-sse2:s64 (sb-simd-sse2::%f64-from-s64 x)) + (real (coerce x ',name)))) + (sb-simd-avx:f32 + `((sb-simd-avx:f64 (sb-simd-avx::%f32-from-f64 x)) + (sb-simd-avx:s64 (sb-simd-avx::%f32-from-s64 x)) + (real (coerce x ',name)))) + (sb-simd-avx:f64 + `((sb-simd-avx:f32 (sb-simd-avx::%f64-from-f32 x)) + (sb-simd-avx:s64 (sb-simd-avx::%f64-from-s64 x)) + (real (coerce x ',name))))) + (otherwise (,err x)))))))) + (define-scalar-casts () + `(progn + ,@(loop for scalar-cast-record in (filter-function-records #'scalar-cast-record-p) + collect `(define-scalar-cast ,(function-record-name scalar-cast-record)))))) + (define-scalar-casts)) diff --git a/contrib/sb-simd/code/define-simd-casts.lisp b/contrib/sb-simd/code/define-simd-casts.lisp new file mode 100644 index 0000000000..c1d49e6a69 --- /dev/null +++ b/contrib/sb-simd/code/define-simd-casts.lisp @@ -0,0 +1,92 @@ +(in-package #:sb-simd-internals) + +;;; For each SIMD data type X.Y, define two functions: +;;; +;;; 1. A function named X.Y that ensures that an object is either of the +;;; type X.Y, or a scalar that can be broadcast to the type X.Y. +;;; +;;; 2. A function named X.Y! that reinterprets the bits of another SIMD +;;; pack or suitable scalar as an X.Y. If the supplied argument has +;;; more bits than the target data type, the excess bits are discarded. +;;; If the supplied argument has less bits than the target data types, +;;; the remaining bits are set to zero. + +;;; The pXXX SIMD types are special - we define their 'cast' function +;;; manually. +(define-inline sb-simd-sse:p128 (x) (the sb-simd-sse:p128 x)) +(define-inline sb-simd-avx:p128 (x) (the sb-simd-avx:p128 x)) +(define-inline sb-simd-avx:p256 (x) (the sb-simd-avx:p256 x)) + +(macrolet + (;; We cannot call known functions directly in the definition of a + ;; cast, only their VOPs. The reason is that each known function + ;; definition uses casts to automatically upgrade its arguments, and + ;; we don't want to end up with a circular dependency. + (call-vop (instruction-record-name &rest arguments) + (with-accessors ((instruction-set instruction-record-instruction-set) + (vop instruction-record-vop)) + (find-function-record instruction-record-name) + (if (instruction-set-available-p instruction-set) + `(,vop ,@arguments) + `(progn + (missing-instruction + (load-time-value + (find-function-record ',instruction-record-name))) + (touch ,@arguments))))) + (define-simd-cast (simd-cast-record-name) + (with-accessors ((name simd-cast-record-name) + (instruction-set simd-cast-record-instruction-set) + (broadcast-record simd-cast-record-broadcast)) + (find-function-record simd-cast-record-name) + (let* ((broadcast (function-record-name broadcast-record)) + (simd-record (function-record-result-record broadcast-record)) + (real-record (simd-record-scalar-record simd-record)) + (simd-type (value-record-name simd-record)) + (real-type (value-record-name real-record)) + (package (instruction-set-package instruction-set)) + (err (mksym package "CANNOT-CONVERT-TO-" name))) + `(progn + (define-notinline ,err (x) + (error "Cannot convert ~S to ~S." x ',name)) + (sb-c:defknown ,name (t) (values ,name &optional) + (sb-c:foldable) + :overwrite-fndb-silently t) + (sb-c:deftransform ,name ((x) (,simd-type) *) + 'x) + (sb-c:deftransform ,name ((x) (real) *) + '(,broadcast (,real-type x))) + (defun ,name (x) + (typecase x + (,simd-type x) + (real (call-vop ,broadcast (,real-type x))) + (otherwise (,err x)))))))) + (define-reinterpret-cast (reinterpret-cast-record) + (with-accessors ((name reinterpret-cast-record-name) + (instruction-set reinterpret-cast-record-instruction-set) + (reinterpreters reinterpret-cast-record-reinterpreters)) + (find-function-record reinterpret-cast-record) + (let* ((package (instruction-set-package instruction-set)) + (err (mksym package "CANNOT-REINTERPRET-AS-" name))) + `(progn + (define-notinline ,err (x) + (error "Cannot reinterpret ~S as ~S." x ',name)) + (defun ,name (x) + (typecase x + ,@(loop for reinterpreter in reinterpreters + for argument-record = (first (function-record-required-argument-records reinterpreter)) + collect + `(,(value-record-name argument-record) + (call-vop ,(function-record-name reinterpreter) x))) + (otherwise (,err x)))))))) + (define-simd-casts () + `(progn + ,@(loop for simd-cast-record in (filter-function-records #'simd-cast-record-p) + collect + `(define-simd-cast ,(simd-cast-record-name simd-cast-record))))) + (define-reinterpret-casts () + `(progn + ,@(loop for reinterpret-cast-record in (filter-function-records #'reinterpret-cast-record-p) + collect + `(define-reinterpret-cast ,(reinterpret-cast-record-name reinterpret-cast-record)))))) + (define-simd-casts) + (define-reinterpret-casts)) diff --git a/contrib/sb-simd/code/define-types.lisp b/contrib/sb-simd/code/define-types.lisp new file mode 100644 index 0000000000..4812b86299 --- /dev/null +++ b/contrib/sb-simd/code/define-types.lisp @@ -0,0 +1,10 @@ +(in-package #:sb-simd-internals) + +(macrolet + ((define-types () + `(progn + ,@(loop for value-record being the hash-values of *value-records* + collect + `(deftype ,(value-record-name value-record) () + ',(value-record-type value-record)))))) + (define-types)) diff --git a/contrib/sb-simd/code/define-unequals.lisp b/contrib/sb-simd/code/define-unequals.lisp new file mode 100644 index 0000000000..23a0d9553b --- /dev/null +++ b/contrib/sb-simd/code/define-unequals.lisp @@ -0,0 +1,46 @@ +(in-package #:sb-simd-internals) + +(macrolet + ((define-unequal (unequal-record-name) + (with-accessors ((name unequal-record-name) + (neq unequal-record-neq) + (and unequal-record-and) + (truth unequal-record-truth)) + (find-function-record unequal-record-name) + (with-accessors ((neq instruction-record-name) + (result-records instruction-record-result-records) + (argument-records instruction-record-argument-records)) neq + (destructuring-bind ((result-record) (argument-record other-argument-record)) + (list result-records argument-records) + (assert (eq argument-record other-argument-record)) + (let ((and (function-record-name and)) + (result-type (value-record-name result-record)) + (argument-type (value-record-name argument-record))) + `(progn + (defun ,name (arg &rest more-args) + (let ((args (list* (,argument-type arg) (mapcar #',argument-type more-args))) + (result (,result-type ,truth))) + (declare (,result-type result)) + (loop for (a . rest) on args do + (loop for b in rest do + (setf result (,and result (,neq a b))))) + result)) + (define-compiler-macro ,name (arg &rest more-args) + (if (null more-args) + `(progn (,',argument-type ,arg) (,',result-type ,',truth)) + (let ((bindings + (loop for arg in (list* arg more-args) + collect + (list (gensym "ARG") (list ',argument-type arg))))) + `(let ,bindings + (,',and + ,@(loop for ((a nil) . rest) on bindings + append + (loop for (b nil) in rest + collect `(,',neq ,a ,b)))))))))))))) + (define-unequals () + `(progn + ,@(loop for unequal-record in (filter-function-records #'unequal-record-p) + collect + `(define-unequal ,(unequal-record-name unequal-record)))))) + (define-unequals)) diff --git a/contrib/sb-simd/code/define-vop-functions.lisp b/contrib/sb-simd/code/define-vop-functions.lisp new file mode 100644 index 0000000000..614243bb24 --- /dev/null +++ b/contrib/sb-simd/code/define-vop-functions.lisp @@ -0,0 +1,68 @@ +(in-package #:sb-simd-internals) + +;;; For constant folding, SBCL needs functions of the same name as the VOP. +;;; In this file, we define these functions. Because some VOPs cannot +;;; translate the full range of arguments supported by such a function, +;;; e.g., because one argument is expected to be a constant, we also need +;;; some macrology to have each function dispatch only to calls that can be +;;; translated. + +(defmacro with-primitive-arguments (alist &body body) + ;; Each entry in ALIST is of the form (VARIABLE VALUE-RECORD-NAME). + (if (null alist) + `(progn ,@body) + `(with-primitive-argument ,(first alist) + (with-primitive-arguments ,(rest alist) + ,@body)))) + +(defmacro with-primitive-argument ((symbol value-record) &body body) + (with-accessors ((primitive-type value-record-primitive-type) + (simd-p simd-record-p)) + (find-value-record value-record) + (etypecase primitive-type + ;; Case 1: A symbol denoting a primitive type. + (symbol + (let ((alias (find primitive-type sb-c::*backend-primitive-type-aliases* :key #'car))) + ;; ALIAS is either null or a list of the form (:OR PRIMITIVE-TYPE*) + (if (or (not simd-p) (not alias)) + `(progn ,@body) + `(etypecase ,symbol + ,@(loop for pt in (rest (rest alias)) + for type = (sb-c::primitive-type-specifier (sb-c:primitive-type-or-lose pt)) + collect `(,type ,@body)))))) + ;; Case 2: A list of the form (:CONSTANT TYPE), where TYPE is either + ;; of the form (SIGNED-BYTE N) or (UNSIGNED-BYTE N) for some positive + ;; integer N. + ((cons (eql :constant) (cons type-specifier null)) + (multiple-value-bind (low high) + (integer-type-specifier-inclusive-bounds (second primitive-type)) + `(ecase ,symbol + ,@(loop for value from low to high + collect `(,value (symbol-macrolet ((,symbol ,value)) ,@body))))))))) + +(macrolet + ((define-vop-function (name) + (with-accessors ((name instruction-record-name) + (vop instruction-record-vop) + (argument-records instruction-record-argument-records) + (encoding instruction-record-encoding) + (instruction-set instruction-record-instruction-set)) + (find-function-record name) + (let* ((argument-record-names (mapcar #'record-name argument-records)) + (argument-symbols (prefixed-symbols "ARGUMENT-" (length argument-records)))) + (unless (or (eq encoding :fake-vop) + (not (instruction-set-available-p instruction-set))) + `(defun ,vop (,@argument-symbols) + (declare + ,@(loop for argument-symbol in argument-symbols + for argument-record in argument-records + collect `(type ,(value-record-name argument-record) ,argument-symbol))) + (with-primitive-arguments ,(mapcar #'list argument-symbols argument-record-names) + (,vop ,@argument-symbols))))))) + + (define-vop-functions () + `(progn + ,@(loop for instruction-record in (filter-function-records #'instruction-record-p) + for name = (instruction-record-name instruction-record) + collect `(define-vop-function ,name))))) + (define-vop-functions)) diff --git a/contrib/sb-simd/code/define-vref-vops.lisp b/contrib/sb-simd/code/define-vref-vops.lisp new file mode 100644 index 0000000000..b68cd8f165 --- /dev/null +++ b/contrib/sb-simd/code/define-vref-vops.lisp @@ -0,0 +1,97 @@ +(in-package #:sb-vm) + +;;; Both load- and store VOPs are augmented with an auxiliary last argument +;;; that is a constant addend for the address calculation. This addend is +;;; zero by default, but we can sometimes transform the code for the index +;;; calculation such that we have a nonzero addend. We also generate two +;;; variants of the VOP - one for the general case, and one for the case +;;; where the index is a compile-time constant. + +(macrolet + ((define-vref-vop (vref-record-name) + (with-accessors ((name sb-simd-internals:vref-record-name) + (vop sb-simd-internals:vref-record-vop) + (vop-c sb-simd-internals:vref-record-vop-c) + (mnemonic sb-simd-internals:vref-record-mnemonic) + (value-record sb-simd-internals:vref-record-value-record) + (vector-record sb-simd-internals:vref-record-vector-record) + (store sb-simd-internals:store-record-p)) + (sb-simd-internals:find-function-record vref-record-name) + (let* ((vector-type (sb-simd-internals:value-record-type vector-record)) + (vector-primitive-type (sb-simd-internals:value-record-primitive-type vector-record)) + (value-scs (sb-simd-internals:value-record-scs value-record)) + (value-type (sb-simd-internals:value-record-type value-record)) + (value-primitive-type (sb-simd-internals:value-record-primitive-type value-record)) + (scalar-record + (etypecase value-record + (sb-simd-internals:simd-record (sb-simd-internals:simd-record-scalar-record value-record)) + (sb-simd-internals:value-record value-record))) + (bits-per-element (sb-simd-internals:value-record-bits scalar-record)) + (bytes-per-element (ceiling bits-per-element 8)) + (displacement + (multiple-value-bind (lo hi) + (displacement-bounds other-pointer-lowtag bits-per-element vector-data-offset) + `(integer ,lo ,hi)))) + (multiple-value-bind (index-scs scale) + (if (>= bytes-per-element (ash 1 n-fixnum-tag-bits)) + (values '(any-reg signed-reg unsigned-reg) `(index-scale ,bytes-per-element index)) + (values '(signed-reg unsigned-reg) bytes-per-element)) + `(progn + (defknown ,vop (,@(when store `(,value-type)) ,vector-type index ,displacement) + (values ,value-type &optional) + (always-translatable) + :overwrite-fndb-silently t) + (define-vop (,vop) + (:translate ,vop) + (:policy :fast-safe) + (:args + ,@(when store `((value :scs ,value-scs :target result))) + (vector :scs (descriptor-reg)) + (index :scs ,index-scs)) + (:info addend) + (:arg-types + ,@(when store `(,value-primitive-type)) + ,vector-primitive-type + positive-fixnum + (:constant ,displacement)) + (:results (result :scs ,value-scs)) + (:result-types ,value-primitive-type) + (:generator + 2 + ,@(let ((ea `(ea (+ (* vector-data-offset n-word-bytes) + (* addend ,bytes-per-element) + (- other-pointer-lowtag)) + vector index ,scale))) + (if store + `((inst ,mnemonic ,ea value) + (move result value)) + `((inst ,mnemonic result ,ea)))))) + (define-vop (,vop-c) + (:translate ,vop) + (:policy :fast-safe) + (:args ,@(when store `((value :scs ,value-scs :target result))) + (vector :scs (descriptor-reg))) + (:info index addend) + (:arg-types ,@(when store `(,value-primitive-type)) + ,vector-primitive-type + (:constant low-index) + (:constant ,displacement)) + (:results (result :scs ,value-scs)) + (:result-types ,value-primitive-type) + (:generator + 1 + ,@(let ((ea `(ea (+ (* vector-data-offset n-word-bytes) + (* ,bytes-per-element (+ index addend)) + (- other-pointer-lowtag)) + vector))) + (if store + `((inst ,mnemonic ,ea value) + (move result value)) + `((inst ,mnemonic result ,ea))))))))))) + (define-vref-vops () + `(progn + ,@(loop for vref-record + in (sb-simd-internals:filter-available-function-records + #'sb-simd-internals:vref-record-p) + collect `(define-vref-vop ,(sb-simd-internals:vref-record-name vref-record)))))) + (define-vref-vops)) diff --git a/contrib/sb-simd/code/define-vrefs.lisp b/contrib/sb-simd/code/define-vrefs.lisp new file mode 100644 index 0000000000..7ad8a43081 --- /dev/null +++ b/contrib/sb-simd/code/define-vrefs.lisp @@ -0,0 +1,44 @@ +(in-package #:sb-simd-internals) + +(macrolet + ((define-vref (name kind) + (with-accessors ((name vref-record-name) + (instruction-set vref-record-instruction-set) + (value-record vref-record-value-record) + (vector-record vref-record-vector-record) + (vop vref-record-vop)) + (find-function-record name) + (let* ((simd-width (value-record-simd-width value-record)) + (element-type + (second + (value-record-type vector-record)))) + (ecase kind + (:load + `(define-inline ,name (array index) + (declare (type (array ,element-type) array) + (index index)) + (multiple-value-bind (vector index) + (sb-kernel:%data-vector-and-index + array + (sb-kernel:check-bound array (- (array-total-size array) ,(1- simd-width)) index)) + (declare (type (simple-array ,element-type (*)) vector)) + (,vop vector index 0)))) + (:store + `(define-inline ,name (value array index) + (declare (type (array ,element-type) array) + (index index)) + (multiple-value-bind (vector index) + (sb-kernel:%data-vector-and-index + array + (sb-kernel:check-bound array (- (array-total-size array) ,(1- simd-width)) index)) + (declare (type (simple-array ,element-type (*)) vector)) + (,vop (,(value-record-name value-record) value) vector index 0)))))))) + (define-vrefs () + `(progn + ,@(loop for load-record in (filter-function-records #'load-record-p) + for name = (load-record-name load-record) + collect `(define-vref ,name :load)) + ,@(loop for store-record in (filter-function-records #'store-record-p) + for name = (store-record-name store-record) + collect `(define-vref ,name :store))))) + (define-vrefs)) diff --git a/contrib/sb-simd/code/instruction-set-case.lisp b/contrib/sb-simd/code/instruction-set-case.lisp new file mode 100644 index 0000000000..b2c54d7ad1 --- /dev/null +++ b/contrib/sb-simd/code/instruction-set-case.lisp @@ -0,0 +1,106 @@ +(in-package #:sb-simd-internals) + +;;; Lisp supports an image-based workflow, so it is entirely possible that +;;; a program is transferred from one machine to another one that supports +;;; different instructions. For example, a video game developer might +;;; create a game on a machine supporting x86 instructions up to AVX2, +;;; create an image-based executable, and ship it to a customer whose +;;; machine supports only x86 instructions up to SSE4.1. +;;; +;;; This file defines a macro for conditionally executing code based on the +;;; available instructions. Special care was taken to make this +;;; conditional selection as efficient as possible. On x86, it should +;;; compile to a jump table whose index is computed only at load time and +;;; whenever the image is restarted. + +;;; For each instruction-set-case macro appearing in source code, we +;;; register an IDISPATCH structure that tracks the available clauses, and +;;; the index of the currently active clause. Whenever the Lisp image is +;;; restarted, we traverse all IDISPATCH structures and recompute the index +;;; of the currently active clause. +(defparameter *idispatch-table* + (make-hash-table :weakness :key :synchronized t)) + +(defstruct (idispatch + (:constructor %make-idispatch) + (:predicate idispatchp)) + ;; The clauses supplied to the instruction-set-case macro. + (clauses nil :type list :read-only t) + ;; A list of lists of instruction sets - one for each clause. + (isets nil :type list :read-only t) + ;; The index of the currently active clause. + (index 0 :type (unsigned-byte 8))) + +(defun make-idispatch (isets clauses) + (let ((idispatch (%make-idispatch + :clauses clauses + :isets isets))) + (update-idispatch-index idispatch) + (setf (gethash idispatch *idispatch-table*) t) + idispatch)) + +(defun update-idispatch-index (idispatch) + (loop for index from 0 + for instruction-sets in (idispatch-isets idispatch) + when (every #'instruction-set-available-p instruction-sets) do + (setf (idispatch-index idispatch) index) + (return-from update-idispatch-index) + finally + (warn "None of the idispatch clauses in ~@ + ~{~S~%~}is available on this machine." + (idispatch-clauses idispatch)) + (setf (idispatch-index idispatch) + (length (idispatch-isets idispatch))))) + +(defun update-idispatch-indices () + (loop for idispatch being the hash-keys of *idispatch-table* do + (update-idispatch-index idispatch))) + +(pushnew 'update-idispatch-indices sb-ext:*init-hooks*) + +(defmacro instruction-set-case (&body clauses) + "Execute the first clause whose instruction sets are available at run +time, or signal an error if no clause could be run. + +Each clause has to start with an instruction set name, or a list of +instruction set names, followed by a list of statements. + +Example: + + (instruction-set-case + (:sse2 (foo)) + (:avx (bar)) + ((:avx2 :fma) (baz))) +" + (sb-int:with-unique-names (idispatch) + (multiple-value-bind (isets bodies) + (parse-instruction-set-case-clauses clauses) + `(let ((,idispatch (load-time-value (make-idispatch ',isets ',clauses)))) + (declare (idispatch ,idispatch)) + (case (idispatch-index ,idispatch) + ,@(loop for iset in isets + for body in bodies + for index from 0 + collect `(,index ,@body)) + (,(length clauses) + (idispatch-no-applicable-clause ,idispatch))))))) + +(defun parse-instruction-set-case-clauses (clauses) + (flet ((clause-iset (clause) + (unless (consp clause) + (error "Not a valid instruction-set-case clause: ~S" + clause)) + (let ((head (first clause))) + (if (listp head) + (mapcar #'find-instruction-set head) + (list (find-instruction-set head))))) + (clause-body (clause) + (rest clause))) + (values + (mapcar #'clause-iset clauses) + (mapcar #'clause-body clauses)))) + +(defun idispatch-no-applicable-clause (idispatch) + (error "None of the idispatch clauses in ~@ + ~{~S~%~}is available on this machine." + (idispatch-clauses idispatch))) diff --git a/contrib/sb-simd/code/instruction-set.lisp b/contrib/sb-simd/code/instruction-set.lisp new file mode 100644 index 0000000000..755238eff8 --- /dev/null +++ b/contrib/sb-simd/code/instruction-set.lisp @@ -0,0 +1,152 @@ +(in-package #:sb-simd-internals) + +;;; An instruction set is a description for a set of data types and +;;; functions in a particular package. + +(defclass instruction-set (printable) + (;; The instruction set's name. + (%name + :type keyword + :initarg :name + :initform (required-argument :name) + :reader instruction-set-name) + ;; The package that holds the instruction set's symbols. + (%package + :type package + :initarg :package + :initform (required-argument :package) + :reader instruction-set-package) + ;; A thunk, returning whether the instruction set is currently available. + ;; Such a run time check is needed in the case where an executable is + ;; created on one machine and run on another machine. In that case, some + ;; of the instructions sets available on the former might not be available + ;; on the latter. + (%test + :type function + :initarg :test :initform (required-argument :test) + :reader instruction-set-test) + ;; A list of instruction sets included by this one. + (%includes + :type list + :initarg :includes + :initform '() + :reader instruction-set-includes) + ;; A hash table, mapping from function records of scalar functions to + ;; lists of function records of SIMD functions. + (%vectorizer-table + :type hash-table + :initform (make-hash-table :test #'eq) + :reader instruction-set-vectorizer-table))) + +(defmethod printable-slot-plist append ((instruction-set instruction-set)) + (list :name (instruction-set-name instruction-set) + :package (instruction-set-package instruction-set))) + +(defun instruction-set-p (x) + (typep x 'instruction-set)) + +(defun instruction-set-available-p (instruction-set) + (funcall (instruction-set-test instruction-set))) + +;;; Returns a list containing the name of the supplied instruction set, and +;;; the names of all instruction sets that are directly or indirectly +;;; included by it. +(defun included-instruction-sets (instruction-set) + (let ((result '())) + (labels ((scan (instruction-set) + (with-accessors ((includes instruction-set-includes)) instruction-set + (unless (member instruction-set result) + (push instruction-set result) + (mapcar #'scan includes))))) + (scan instruction-set) + (nreverse result)))) + +(defun register-vectorizer (X-record X.Y-record) + (assert (scalar-function-record-p X-record)) + (assert (simd-function-record-p X.Y-record)) + (with-accessors ((vectorizer-table instruction-set-vectorizer-table)) + (function-record-instruction-set X.Y-record) + (pushnew X.Y-record (gethash X-record vectorizer-table '())))) + +(defun instruction-set-vectorizers (instruction-set X-record) + (loop for instruction-set in (included-instruction-sets instruction-set) + append + (gethash X-record (instruction-set-vectorizer-table instruction-set) '()))) + +;;; A hash table, mapping from instruction set names or packages to +;;; instruction sets. +(defparameter *instruction-sets* (make-hash-table :test #'eq)) + +(defun find-instruction-set (designator &optional (errorp t)) + (or (gethash designator *instruction-sets*) + (when errorp + (typecase designator + (symbol (error "There is no instruction set with the name ~S." designator)) + (package (error "There is not instruction set with the package ~S" designator)) + (otherwise (error "Not a valid instruction set designator: ~S" designator)))))) + +(defmethod make-load-form ((instruction-set instruction-set) &optional env) + (declare (ignore env)) + `(find-instruction-set ',(instruction-set-name instruction-set))) + +(defmethod shared-initialize :after + ((instruction-set instruction-set) slot-names &key &allow-other-keys) + (setf (gethash (instruction-set-name instruction-set) *instruction-sets*) + instruction-set) + (setf (gethash (instruction-set-package instruction-set) *instruction-sets*) + instruction-set) + instruction-set) + +;;; The currently active instruction set. +(defvar *instruction-set*) + +;;; Defining Instruction Sets + +(defparameter *instruction-set-options* + '(:include :test :scalars :simd-packs :simd-casts :reinterpret-casts + :instructions :loads :stores :reffers + :associatives :reducers :comparisons :unequals :ifs)) + +(defgeneric decode-record-definition (record-name expr)) + +(defmacro define-instruction-set (name &body options) + ;; Ensure that only valid options are supplied. + (dolist (option options) + (unless (and (listp option) + (member (first option) *instruction-set-options*)) + (error "Not a valid instruction set option:~% ~S" option))) + (flet ((decode (keyword decoder) + (loop for (key . exprs) in options + when (eq key keyword) + append (mapcar decoder exprs))) + (decode-include (expr) + `(find-instruction-set ',expr)) + (record-decoder (record-name) + (lambda (x) + (decode-record-definition record-name x)))) + ;; The macro expansion of an instruction set is a very large expression + ;; that is evaluated exactly once, so compiling it would be a waste of + ;; resources. Instead, we use SBCL's built-in interpreter. + `(let (#+(or sb-eval sb-fasteval)(sb-ext:*evaluator-mode* :interpret)) + (eval + '(let ((*instruction-set* + (make-instance 'instruction-set + :name ',name + :package ,(if (eq name :sb-simd) + (find-package "SB-SIMD") + (find-package (concatenate 'string "SB-SIMD-" (string name)))) + :test (lambda () (and ,@(decode :test #'identity))) + :includes (list ,@(decode :include #'decode-include))))) + ,@(decode :scalars (record-decoder 'value-record)) + ,@(decode :simd-packs (record-decoder 'simd-record)) + ,@(decode :instructions (record-decoder 'instruction-record)) + ,@(decode :loads (record-decoder 'load-record)) + ,@(decode :stores (record-decoder 'store-record)) + ,@(decode :reffers (record-decoder 'reffer-record)) + ,@(decode :associatives (record-decoder 'associative-record)) + ,@(decode :reducers (record-decoder 'reducer-record)) + ,@(decode :comparisons (record-decoder 'comparison-record)) + ,@(decode :unequals (record-decoder 'unequal-record)) + ,@(decode :ifs (record-decoder 'if-record)) + ,@(decode :simd-casts (record-decoder 'simd-cast-record)) + ,@(decode :reinterpret-casts (record-decoder 'reinterpret-cast-record))))))) diff --git a/contrib/sb-simd/code/instruction-sets/avx.lisp b/contrib/sb-simd/code/instruction-sets/avx.lisp new file mode 100644 index 0000000000..aa422c56ca --- /dev/null +++ b/contrib/sb-simd/code/instruction-sets/avx.lisp @@ -0,0 +1,915 @@ +(in-package #:sb-simd-avx) + +(define-instruction-set :avx + (:test (avx-supported-p)) + (:include :x86-64) + (:scalars + (f32 32 single-float #:single-float (#:single-reg)) + (f64 64 double-float #:double-float (#:double-reg))) + (:simd-packs + (p128 nil 128 #:simd-pack (#:int-sse-reg #:double-sse-reg #:single-sse-reg)) + (f32.4 f32 128 #:simd-pack-single (#:single-sse-reg)) + (f64.2 f64 128 #:simd-pack-double (#:double-sse-reg)) + (u8.16 u8 128 #:simd-pack-ub8 (#:int-sse-reg)) + (u16.8 u16 128 #:simd-pack-ub16 (#:int-sse-reg)) + (u32.4 u32 128 #:simd-pack-ub32 (#:int-sse-reg)) + (u64.2 u64 128 #:simd-pack-ub64 (#:int-sse-reg)) + (s8.16 s8 128 #:simd-pack-sb8 (#:int-sse-reg)) + (s16.8 s16 128 #:simd-pack-sb16 (#:int-sse-reg)) + (s32.4 s32 128 #:simd-pack-sb32 (#:int-sse-reg)) + (s64.2 s64 128 #:simd-pack-sb64 (#:int-sse-reg)) + (p256 nil 256 #:simd-pack-256 (#:int-avx2-reg #:double-avx2-reg #:single-avx2-reg)) + (f32.8 f32 256 #:simd-pack-256-single (#:single-avx2-reg)) + (f64.4 f64 256 #:simd-pack-256-double (#:double-avx2-reg)) + (u8.32 u8 256 #:simd-pack-256-ub8 (#:int-avx2-reg)) + (u16.16 u16 256 #:simd-pack-256-ub16 (#:int-avx2-reg)) + (u32.8 u32 256 #:simd-pack-256-ub32 (#:int-avx2-reg)) + (u64.4 u64 256 #:simd-pack-256-ub64 (#:int-avx2-reg)) + (s8.32 s8 256 #:simd-pack-256-sb8 (#:int-avx2-reg)) + (s16.16 s16 256 #:simd-pack-256-sb16 (#:int-avx2-reg)) + (s32.8 s32 256 #:simd-pack-256-sb32 (#:int-avx2-reg)) + (s64.4 s64 256 #:simd-pack-256-sb64 (#:int-avx2-reg))) + (:simd-casts + (f32.4 f32.4-broadcast) + (f64.2 f64.2-broadcast) + (f32.8 f32.8-broadcast) + (f64.4 f64.4-broadcast) + (u8.16 u8.16-broadcast) + (u16.8 u16.8-broadcast) + (u32.4 u32.4-broadcast) + (u64.2 u64.2-broadcast) + (u8.32 u8.32-broadcast) + (u16.16 u16.16-broadcast) + (u32.8 u32.8-broadcast) + (u64.4 u64.4-broadcast) + (s8.16 s8.16-broadcast) + (s16.8 s16.8-broadcast) + (s32.4 s32.4-broadcast) + (s64.2 s64.2-broadcast) + (s8.32 s8.32-broadcast) + (s16.16 s16.16-broadcast) + (s32.8 s32.8-broadcast) + (s64.4 s64.4-broadcast)) + (:reinterpret-casts + (f32! f32!-from-p128 f32!-from-p256) + (f64! f64!-from-p128 f64!-from-p256) + (u8! u8!-from-p128 u8!-from-p256) + (u16! u16!-from-p128 u16!-from-p256) + (u32! u32!-from-p128 u32!-from-p256) + (u64! u64!-from-p128 u64!-from-p256) + (f32.4! f32.4!-from-f32 f32.4!-from-p256) + (f64.2! f64.2!-from-f64 f64.2!-from-p128) + (f32.8! f32.8!-from-f32 f32.8!-from-p128 f32.8!-from-p256) + (f64.4! f64.4!-from-f64 f64.4!-from-p128 f64.4!-from-p256) + (u8.16! u8.16!-from-u8 u8.16!-from-p128 u8.16!-from-p256) + (u16.8! u16.8!-from-u16 u16.8!-from-p128 u16.8!-from-p256) + (u32.4! u32.4!-from-u32 u32.4!-from-p128 u32.4!-from-p256) + (u64.2! u64.2!-from-u64 u64.2!-from-p128 u64.2!-from-p256) + (u8.32! u8.32!-from-u8 u8.32!-from-p128 u8.32!-from-p256) + (u16.16! u16.16!-from-u16 u16.16!-from-p128 u16.16!-from-p256) + (u32.8! u32.8!-from-u32 u32.8!-from-p128 u32.8!-from-p256) + (u64.4! u64.4!-from-u64 u64.4!-from-p128 u64.4!-from-p256) + (s8.16! s8.16!-from-s8 s8.16!-from-p128 s8.16!-from-p256) + (s16.8! s16.8!-from-s16 s16.8!-from-p128 s16.8!-from-p256) + (s32.4! s32.4!-from-s32 s32.4!-from-p128 s32.4!-from-p256) + (s64.2! s64.2!-from-s64 s64.2!-from-p128 s64.2!-from-p256) + (s8.32! s8.32!-from-s8 s8.32!-from-p128 s8.32!-from-p256) + (s16.16! s16.16!-from-s16 s16.16!-from-p128 s16.16!-from-p256) + (s32.8! s32.8!-from-s32 s32.8!-from-p128 s32.8!-from-p256) + (s64.4! s64.4!-from-s64 s64.4!-from-p128 s64.4!-from-p256)) + (:instructions + (vzeroupper #:vzeroupper () () :cost 1 :pure nil) + (vzeroall #:vzeroall () () :cost 1 :pure nil) + ;; f32 + (f32-from-f64 #:vcvtsd2ss (f32) (f64) :cost 5) + (f32-from-s64 nil (f32) (s64) :cost 5 :encoding :custom) + (f32!-from-p128 nil (f32) (p128) :cost 1 :encoding :custom :always-translatable nil) + (f32!-from-p256 nil (f32) (p256) :cost 1 :encoding :custom :always-translatable nil) + (two-arg-f32-and #:vandps (f32) (f32 f32) :cost 1 :associative t) + (two-arg-f32-or #:vorps (f32) (f32 f32) :cost 1 :associative t) + (two-arg-f32-xor #:vxorps (f32) (f32 f32) :cost 1 :associative t) + (two-arg-f32-max #:vmaxss (f32) (f32 f32) :cost 1 :associative t) + (two-arg-f32-min #:vminss (f32) (f32 f32) :cost 1 :associative t) + (two-arg-f32+ #:vaddss (f32) (f32 f32) :cost 1 :associative t) + (two-arg-f32- #:vsubss (f32) (f32 f32) :cost 2) + (two-arg-f32* #:vmulss (f32) (f32 f32) :cost 2 :associative t) + (two-arg-f32/ #:vdivss (f32) (f32 f32) :cost 8) + (two-arg-f32= #:vcmpss (u32) (f32 f32) :cost 4 :encoding :custom :prefix '(:eq) :associative t) + (two-arg-f32/= #:vcmpss (u32) (f32 f32) :cost 4 :encoding :custom :prefix '(:neq) :associative t) + (two-arg-f32< #:vcmpss (u32) (f32 f32) :cost 4 :encoding :custom :prefix '(:lt)) + (two-arg-f32<= #:vcmpss (u32) (f32 f32) :cost 4 :encoding :custom :prefix '(:le)) + (two-arg-f32> #:vcmpss (u32) (f32 f32) :cost 4 :encoding :custom :prefix '(:nle)) + (two-arg-f32>= #:vcmpss (u32) (f32 f32) :cost 4 :encoding :custom :prefix '(:nlt)) + (f32-andc1 #:vandnps (f32) (f32 f32) :cost 1) + (f32-not nil (f32) (f32) :cost 1 :encoding :fake-vop) + (f32-reciprocal #:vrcpss (f32) (f32) :cost 5) + (f32-rsqrt #:vrsqrtss (f32) (f32) :cost 5) + (f32-sqrt #:vsqrtss (f32) (f32) :cost 15) + ;; f64 + (f64-from-f32 #:vcvtss2sd (f64) (f32) :cost 5) + (f64-from-s64 nil (f64) (s64) :cost 5 :encoding :custom) + (f64!-from-p128 nil (f64) (p128) :cost 1 :encoding :custom :always-translatable nil) + (f64!-from-p256 nil (f64) (p256) :cost 1 :encoding :custom :always-translatable nil) + (two-arg-f64-and #:vandpd (f64) (f64 f64) :cost 1 :associative t) + (two-arg-f64-or #:vorpd (f64) (f64 f64) :cost 1 :associative t) + (two-arg-f64-xor #:vxorpd (f64) (f64 f64) :cost 1 :associative t) + (two-arg-f64-max #:vmaxsd (f64) (f64 f64) :cost 1 :associative t) + (two-arg-f64-min #:vminsd (f64) (f64 f64) :cost 1 :associative t) + (two-arg-f64+ #:vaddsd (f64) (f64 f64) :cost 1 :associative t) + (two-arg-f64- #:vsubsd (f64) (f64 f64) :cost 2) + (two-arg-f64* #:vmulsd (f64) (f64 f64) :cost 2 :associative t) + (two-arg-f64/ #:vdivsd (f64) (f64 f64) :cost 8) + (two-arg-f64= #:vcmpsd (u64) (f64 f64) :cost 4 :encoding :custom :prefix '(:eq) :associative t) + (two-arg-f64/= #:vcmpsd (u64) (f64 f64) :cost 4 :encoding :custom :prefix '(:neq) :associative t) + (two-arg-f64< #:vcmpsd (u64) (f64 f64) :cost 4 :encoding :custom :prefix '(:lt)) + (two-arg-f64<= #:vcmpsd (u64) (f64 f64) :cost 4 :encoding :custom :prefix '(:le)) + (two-arg-f64> #:vcmpsd (u64) (f64 f64) :cost 4 :encoding :custom :prefix '(:nle)) + (two-arg-f64>= #:vcmpsd (u64) (f64 f64) :cost 4 :encoding :custom :prefix '(:nlt)) + (f64-andc1 #:vandnpd (f64) (f64 f64) :cost 1) + (f64-not nil (f64) (f64) :cost 1 :encoding :fake-vop) + (f64-sqrt #:vsqrtsd (f64) (f64) :cost 15) + ;; scalar reinterpret casts + ( u8!-from-p128 nil (u8) (p128) :cost 1 :encoding :fake-vop) + ( u8!-from-p256 nil (u8) (p256) :cost 1 :encoding :fake-vop) + (u16!-from-p128 nil (u16) (p128) :cost 1 :encoding :fake-vop) + (u16!-from-p256 nil (u16) (p256) :cost 1 :encoding :fake-vop) + (u32!-from-p128 nil (u32) (p128) :cost 1 :encoding :fake-vop) + (u32!-from-p256 nil (u32) (p256) :cost 1 :encoding :fake-vop) + (u64!-from-p128 #:movq (u64) (p128) :cost 1 :always-translatable nil) + (u64!-from-p256 #:movq (u64) (p256) :cost 1 :always-translatable nil) + ;; f32.4 + (f32.4-from-s32.4 #:vcvtdq2ps (f32.4) (s32.4) :cost 5) + (f32.4!-from-f32 #:vmovups (f32.4) (f32) :cost 1 :encoding :move) + (f32.4!-from-p128 #:vmovups (f32.4) (p128) :cost 1 :encoding :move :always-translatable nil) + (f32.4!-from-p256 #:vextractf128 (f32.4) (p256) :cost 1 :suffix '(0) :always-translatable nil) + (make-f32.4 nil (f32.4) (f32 f32 f32 f32) :cost 1 :encoding :fake-vop) + (f32.4-values nil (f32 f32 f32 f32) (f32.4) :cost 1 :encoding :fake-vop) + (f32.4-broadcast #:vbroadcastss (f32.4) (f32) :cost 1) + (f32.4-from-f64.4 #:vcvtpd2ps (f32.4) (f64.4) :cost 5) ;; wrong code is generated VCVTPD2PS XMM0, XMM0 + (f32.4-blend #:vblendvps (f32.4) (f32.4 f32.4 u32.4) :cost 1) + (f32.4-blendc #:vblendps (f32.4) (f32.4 f32.4 imm4) :cost 1) + (two-arg-f32.4-and #:vandps (f32.4) (f32.4 f32.4) :cost 1 :associative t) + (two-arg-f32.4-or #:vorps (f32.4) (f32.4 f32.4) :cost 1 :associative t) + (two-arg-f32.4-xor #:vxorps (f32.4) (f32.4 f32.4) :cost 1 :associative t) + (two-arg-f32.4-max #:vmaxps (f32.4) (f32.4 f32.4) :cost 3 :associative t) + (two-arg-f32.4-min #:vminps (f32.4) (f32.4 f32.4) :cost 3 :associative t) + (f32.4-andc1 #:vandnps (f32.4) (f32.4 f32.4) :cost 1) + (f32.4-not nil (f32.4) (f32.4) :cost 1 :encoding :fake-vop) + (two-arg-f32.4+ #:vaddps (f32.4) (f32.4 f32.4) :cost 2 :associative t) + (two-arg-f32.4- #:vsubps (f32.4) (f32.4 f32.4) :cost 2) + (two-arg-f32.4* #:vmulps (f32.4) (f32.4 f32.4) :cost 2 :associative t) + (two-arg-f32.4/ #:vdivps (f32.4) (f32.4 f32.4) :cost 8) + (two-arg-f32.4= #:vcmpps (u32.4) (f32.4 f32.4) :cost 4 :prefix '(:eq) :associative t) + (two-arg-f32.4/= #:vcmpps (u32.4) (f32.4 f32.4) :cost 4 :prefix '(:neq) :associative t) + (two-arg-f32.4< #:vcmpps (u32.4) (f32.4 f32.4) :cost 4 :prefix '(:lt)) + (two-arg-f32.4<= #:vcmpps (u32.4) (f32.4 f32.4) :cost 4 :prefix '(:le)) + (two-arg-f32.4> #:vcmpps (u32.4) (f32.4 f32.4) :cost 4 :prefix '(:gt)) + (two-arg-f32.4>= #:vcmpps (u32.4) (f32.4 f32.4) :cost 4 :prefix '(:ge)) + (f32.4-horizontal-and nil (f32) (f32.4) :cost 5 :encoding :fake-vop) + (f32.4-horizontal-or nil (f32) (f32.4) :cost 5 :encoding :fake-vop) + (f32.4-horizontal-xor nil (f32) (f32.4) :cost 5 :encoding :fake-vop) + (f32.4-horizontal-max nil (f32) (f32.4) :cost 5 :encoding :fake-vop) + (f32.4-horizontal-min nil (f32) (f32.4) :cost 5 :encoding :fake-vop) + (f32.4-horizontal+ nil (f32) (f32.4) :cost 5 :encoding :fake-vop) + (f32.4-horizontal* nil (f32) (f32.4) :cost 5 :encoding :fake-vop) + (f32.4-dupeven #:vmovsldup (f32.4) (f32.4) :cost 1) + (f32.4-dupodd #:vmovshdup (f32.4) (f32.4) :cost 1) + (f32.4-addsub #:vaddsubps (f32.4) (f32.4 f32.4) :cost 3) + (f32.4-hadd #:vhaddps (f32.4) (f32.4 f32.4) :cost 6) + (f32.4-hsub #:vhsubps (f32.4) (f32.4 f32.4) :cost 6) + (f32.4-reciprocal #:vrcpps (f32.4) (f32.4) :cost 5) + (f32.4-rsqrt #:vrsqrtps (f32.4) (f32.4) :cost 5) + (f32.4-sqrt #:vsqrtps (f32.4) (f32.4) :cost 15) + (f32.4-unpackhi #:vunpckhps (f32.4) (f32.4 f32.4) :cost 1) + (f32.4-unpacklo #:vunpcklps (f32.4) (f32.4 f32.4) :cost 1) + (f32.4-movemask #:vmovmskps (u4) (f32.4) :cost 1) + (f32.4-%round #:vroundps (f32.4) (f32.4 imm3) :cost 2) + (f32.4-permute #:vpermilps (f32.4) (f32.4 imm8) :cost 1) + (f32.4-shuffle #:vshufps (f32.4) (f32.4 f32.4 imm8) :cost 1) + (f32.4-movemask #:vmovmskps (u4) (f32.4) :cost 1) + ;; f64.2 + (f64.2!-from-f64 #:vmovupd (f64.2) (f64) :cost 1 :encoding :move) + (f64.2!-from-p128 #:vmovupd (f64.2) (p128) :cost 1 :encoding :move :always-translatable nil) + (f64.2!-from-p256 #:vextractf128 (f64.2) (p256) :cost 1 :suffix '(0) :always-translatable nil) + (make-f64.2 nil (f64.2) (f64 f64) :cost 1 :encoding :fake-vop) + (f64.2-values nil (f64 f64) (f64.2) :cost 1 :encoding :fake-vop) + (f64.2-broadcast #:vmovddup (f64.2) (f64) :cost 1) + (f64.2-blend #:vblendvpd (f64.2) (f64.2 f64.2 u64.2) :cost 1) + (f64.2-blendc #:vblendpd (f64.2) (f64.2 f64.2 imm2) :cost 1) + (two-arg-f64.2-and #:vandpd (f64.2) (f64.2 f64.2) :cost 1 :associative t) + (two-arg-f64.2-or #:vorpd (f64.2) (f64.2 f64.2) :cost 1 :associative t) + (two-arg-f64.2-xor #:vxorpd (f64.2) (f64.2 f64.2) :cost 1 :associative t) + (two-arg-f64.2-max #:vmaxpd (f64.2) (f64.2 f64.2) :cost 3 :associative t) + (two-arg-f64.2-min #:vminpd (f64.2) (f64.2 f64.2) :cost 3 :associative t) + (two-arg-f64.2+ #:vaddpd (f64.2) (f64.2 f64.2) :cost 2 :associative t) + (f64.2-andc1 #:vandnpd (f64.2) (f64.2 f64.2) :cost 1) + (f64.2-not nil (f64.2) (f64.2) :cost 1 :encoding :fake-vop) + (two-arg-f64.2- #:vsubpd (f64.2) (f64.2 f64.2) :cost 2) + (two-arg-f64.2* #:vmulpd (f64.2) (f64.2 f64.2) :cost 2 :associative t) + (two-arg-f64.2/ #:vdivpd (f64.2) (f64.2 f64.2) :cost 8) + (two-arg-f64.2= #:vcmppd (u64.2) (f64.2 f64.2) :cost 4 :prefix '(:eq) :associative t) + (two-arg-f64.2/= #:vcmppd (u64.2) (f64.2 f64.2) :cost 4 :prefix '(:neq) :associative t) + (two-arg-f64.2< #:vcmppd (u64.2) (f64.2 f64.2) :cost 4 :prefix '(:lt)) + (two-arg-f64.2<= #:vcmppd (u64.2) (f64.2 f64.2) :cost 4 :prefix '(:le)) + (two-arg-f64.2> #:vcmppd (u64.2) (f64.2 f64.2) :cost 4 :prefix '(:gt)) + (two-arg-f64.2>= #:vcmppd (u64.2) (f64.2 f64.2) :cost 4 :prefix '(:ge)) + (f64.2-horizontal-and nil (f64) (f64.2) :cost 3 :encoding :fake-vop) + (f64.2-horizontal-or nil (f64) (f64.2) :cost 3 :encoding :fake-vop) + (f64.2-horizontal-xor nil (f64) (f64.2) :cost 3 :encoding :fake-vop) + (f64.2-horizontal-max nil (f64) (f64.2) :cost 3 :encoding :fake-vop) + (f64.2-horizontal-min nil (f64) (f64.2) :cost 3 :encoding :fake-vop) + (f64.2-horizontal+ nil (f64) (f64.2) :cost 3 :encoding :fake-vop) + (f64.2-horizontal* nil (f64) (f64.2) :cost 3 :encoding :fake-vop) + (f64.2-addsub #:vaddsubpd (f64.2) (f64.2 f64.2) :cost 3) + (f64.2-hadd #:vhaddpd (f64.2) (f64.2 f64.2) :cost 6) + (f64.2-hsub #:vhsubpd (f64.2) (f64.2 f64.2) :cost 6) + (f64.2-sqrt #:vsqrtpd (f64.2) (f64.2) :cost 20) + (f64.2-unpackhi #:vunpckhpd (f64.2) (f64.2 f64.2) :cost 1) + (f64.2-unpacklo #:vunpcklpd (f64.2) (f64.2 f64.2) :cost 1) + (f64.2-movemask #:vmovmskpd (u2) (f64.2) :cost 1) + (f64.2-%round #:vroundpd (f64.2) (f64.2 imm3) :cost 2) + (f64.2-permute #:vpermilpd (f64.2) (f64.2 imm2) :cost 1) + (f64.2-shuffle #:vshufpd (f64.2) (f64.2 f64.2 imm1) :cost 1) + (f64.2-movemask #:vmovmskpd (u2) (f64.2) :cost 1) + ;; f32.8 + (f32.8-from-s32.8 #:vcvtdq2ps (f32.8) (s32.8) :cost 5) + (f32.8!-from-f32 #:vmovups (f32.8) (f32) :cost 1 :encoding :move) + (f32.8!-from-p128 #:vmovups (f32.8) (p128) :cost 1 :encoding :move :always-translatable nil) + (f32.8!-from-p256 #:vmovups (f32.8) (p256) :cost 1 :encoding :move :always-translatable nil) + (make-f32.8 nil (f32.8) (f32 f32 f32 f32 f32 f32 f32 f32) :cost 1 :encoding :fake-vop) + (f32.8-values nil (f32 f32 f32 f32 f32 f32 f32 f32) (f32.8) :cost 1 :encoding :fake-vop) + (f32.8-broadcast #:vbroadcastss (f32.8) (f32) :cost 1) + (f32.8-from-u32.8 #:vcvtdq2ps (f32.8) (u32.8) :cost 5) + (f32.8-blend #:vblendvps (f32.8) (f32.8 f32.8 u32.8) :cost 1) + (f32.8-blendc #:vblendps (f32.8) (f32.8 f32.8 imm8) :cost 1) + (two-arg-f32.8-and #:vandps (f32.8) (f32.8 f32.8) :cost 1 :associative t) + (two-arg-f32.8-or #:vorps (f32.8) (f32.8 f32.8) :cost 1 :associative t) + (two-arg-f32.8-xor #:vxorps (f32.8) (f32.8 f32.8) :cost 1 :associative t) + (two-arg-f32.8-max #:vmaxps (f32.8) (f32.8 f32.8) :cost 3 :associative t) + (two-arg-f32.8-min #:vminps (f32.8) (f32.8 f32.8) :cost 3 :associative t) + (f32.8-andc1 #:vandnps (f32.8) (f32.8 f32.8) :cost 1) + (f32.8-not nil (f32.8) (f32.8) :cost 1 :encoding :fake-vop) + (two-arg-f32.8+ #:vaddps (f32.8) (f32.8 f32.8) :cost 2 :associative t) + (two-arg-f32.8- #:vsubps (f32.8) (f32.8 f32.8) :cost 2) + (two-arg-f32.8* #:vmulps (f32.8) (f32.8 f32.8) :cost 2 :associative t) + (two-arg-f32.8/ #:vdivps (f32.8) (f32.8 f32.8) :cost 8) + (two-arg-f32.8= #:vcmpps (u32.8) (f32.8 f32.8) :cost 4 :prefix '(:eq) :associative t) + (two-arg-f32.8/= #:vcmpps (u32.8) (f32.8 f32.8) :cost 4 :prefix '(:neq) :associative t) + (two-arg-f32.8< #:vcmpps (u32.8) (f32.8 f32.8) :cost 4 :prefix '(:lt)) + (two-arg-f32.8<= #:vcmpps (u32.8) (f32.8 f32.8) :cost 4 :prefix '(:le)) + (two-arg-f32.8> #:vcmpps (u32.8) (f32.8 f32.8) :cost 4 :prefix '(:gt)) + (two-arg-f32.8>= #:vcmpps (u32.8) (f32.8 f32.8) :cost 4 :prefix '(:ge)) + (f32.8-horizontal-and nil (f32) (f32.8) :cost 5 :encoding :fake-vop) + (f32.8-horizontal-or nil (f32) (f32.8) :cost 5 :encoding :fake-vop) + (f32.8-horizontal-xor nil (f32) (f32.8) :cost 5 :encoding :fake-vop) + (f32.8-horizontal-max nil (f32) (f32.8) :cost 5 :encoding :fake-vop) + (f32.8-horizontal-min nil (f32) (f32.8) :cost 5 :encoding :fake-vop) + (f32.8-horizontal+ nil (f32) (f32.8) :cost 5 :encoding :fake-vop) + (f32.8-horizontal* nil (f32) (f32.8) :cost 5 :encoding :fake-vop) + (f32.8-dupeven #:vmovsldup (f32.8) (f32.8) :cost 1) + (f32.8-dupodd #:vmovshdup (f32.8) (f32.8) :cost 1) + (f32.8-hadd #:vhaddps (f32.8) (f32.8 f32.8) :cost 6) + (f32.8-hsub #:vhsubps (f32.8) (f32.8 f32.8) :cost 6) + (f32.8-reciprocal #:vrcpps (f32.8) (f32.8) :cost 5) + (f32.8-rsqrt #:vrsqrtps (f32.8) (f32.8) :cost 5) + (f32.8-sqrt #:vsqrtps (f32.8) (f32.8) :cost 15) + (f32.8-unpackhi #:vunpckhps (f32.8) (f32.8 f32.8) :cost 1) + (f32.8-unpacklo #:vunpcklps (f32.8) (f32.8 f32.8) :cost 1) + (f32.8-movemask #:vmovmskps (u8) (f32.8) :cost 1) + (f32.8-%round #:vroundps (f32.8) (f32.8 imm3) :cost 2) + (f32.8-permute #:vpermilps (f32.8) (f32.8 imm8) :cost 1) + (f32.8-permute128 #:vperm2f128 (f32.8) (f32.8 f32.8 imm8) :cost 1) + (f32.8-shuffle #:vshufps (f32.8) (f32.8 f32.8 imm8) :cost 1) + (f32.4-from-f32.8 #:vextractf128 (f32.4) (f32.8 imm1) :cost 1) + (f32.8-insert-f32.4 #:vinsertf128 (f32.8) (f32.8 f32.4 imm1) :cost 1) + (f32.8-movemask #:vmovmskps (u8) (f32.8) :cost 1) + ;; f64.4 + (f64.4!-from-f64 #:vmovupd (f64.4) (f64) :cost 1 :encoding :move) + (f64.4!-from-p128 #:vmovupd (f64.4) (p128) :cost 1 :encoding :move :always-translatable nil) + (f64.4!-from-p256 #:vmovupd (f64.4) (p256) :cost 1 :encoding :move :always-translatable nil) + (make-f64.4 nil (f64.4) (f64 f64 f64 f64) :cost 1 :encoding :fake-vop) + (f64.4-values nil (f64 f64 f64 f64) (f64.4) :cost 1 :encoding :fake-vop) + (f64.4-broadcast #:vbroadcastsd (f64.4) (f64) :cost 1) + (f64.4-from-f32.4 #:vcvtps2pd (f64.4) (f32.4) :cost 5) + (f64.4-from-u32.4 #:vcvtdq2pd (f64.4) (u32.4) :cost 5) + (f64.4-from-s32.4 #:vcvtdq2pd (f64.4) (s32.4) :cost 5) + (f64.4-blend #:vblendvpd (f64.4) (f64.4 f64.4 u64.4) :cost 1) + (f64.4-blendc #:vblendpd (f64.4) (f64.4 f64.4 imm4) :cost 1) + (two-arg-f64.4-and #:vandpd (f64.4) (f64.4 f64.4) :cost 1 :associative t) + (two-arg-f64.4-or #:vorpd (f64.4) (f64.4 f64.4) :cost 1 :associative t) + (two-arg-f64.4-xor #:vxorpd (f64.4) (f64.4 f64.4) :cost 1 :associative t) + (two-arg-f64.4-max #:vmaxpd (f64.4) (f64.4 f64.4) :cost 3 :associative t) + (two-arg-f64.4-min #:vminpd (f64.4) (f64.4 f64.4) :cost 3 :associative t) + (two-arg-f64.4+ #:vaddpd (f64.4) (f64.4 f64.4) :cost 2 :associative t) + (two-arg-f64.4- #:vsubpd (f64.4) (f64.4 f64.4) :cost 2) + (two-arg-f64.4* #:vmulpd (f64.4) (f64.4 f64.4) :cost 2 :associative t) + (two-arg-f64.4/ #:vdivpd (f64.4) (f64.4 f64.4) :cost 8) + (two-arg-f64.4= #:vcmppd (u64.4) (f64.4 f64.4) :cost 4 :prefix '(:eq) :associative t) + (two-arg-f64.4/= #:vcmppd (u64.4) (f64.4 f64.4) :cost 4 :prefix '(:neq) :associative t) + (two-arg-f64.4< #:vcmppd (u64.4) (f64.4 f64.4) :cost 4 :prefix '(:lt)) + (two-arg-f64.4<= #:vcmppd (u64.4) (f64.4 f64.4) :cost 4 :prefix '(:le)) + (two-arg-f64.4> #:vcmppd (u64.4) (f64.4 f64.4) :cost 4 :prefix '(:gt)) + (two-arg-f64.4>= #:vcmppd (u64.4) (f64.4 f64.4) :cost 4 :prefix '(:ge)) + (f64.4-horizontal-and nil (f64) (f64.4) :cost 3 :encoding :fake-vop) + (f64.4-horizontal-or nil (f64) (f64.4) :cost 3 :encoding :fake-vop) + (f64.4-horizontal-xor nil (f64) (f64.4) :cost 3 :encoding :fake-vop) + (f64.4-horizontal-max nil (f64) (f64.4) :cost 3 :encoding :fake-vop) + (f64.4-horizontal-min nil (f64) (f64.4) :cost 3 :encoding :fake-vop) + (f64.4-horizontal+ nil (f64) (f64.4) :cost 3 :encoding :fake-vop) + (f64.4-horizontal* nil (f64) (f64.4) :cost 3 :encoding :fake-vop) + (f64.4-andc1 #:vandnpd (f64.4) (f64.4 f64.4) :cost 1) + (f64.4-not nil (f64.4) (f64.4) :cost 1 :encoding :fake-vop) + (f64.4-dupeven #:vmovddup (f64.4) (f64.4) :cost 1) + (f64.4-hadd #:vhaddpd (f64.4) (f64.4 f64.4) :cost 6) + (f64.4-hsub #:vhsubpd (f64.4) (f64.4 f64.4) :cost 6) + (f64.4-sqrt #:vsqrtpd (f64.4) (f64.4) :cost 20) + (f64.4-unpackhi #:vunpckhpd (f64.4) (f64.4 f64.4) :cost 1) + (f64.4-unpacklo #:vunpcklpd (f64.4) (f64.4 f64.4) :cost 1) + (f64.4-movemask #:vmovmskpd (u4) (f64.4) :cost 1) + (f64.4-%round #:vroundpd (f64.4) (f64.4 imm3) :cost 2) + (f64.4-permute #:vpermilpd (f64.4) (f64.4 imm4) :cost 1) + (f64.4-permute128 #:vperm2f128 (f64.4) (f64.4 f64.4 imm8) :cost 1) + (f64.4-shuffle #:vshufpd (f64.4) (f64.4 f64.4 imm2) :cost 1) + (f64.4-reverse #:vpermilpd (f64.4) (f64.4) :cost 2 :encoding :fake-vop) + (f64.2-from-f64.4 #:vextractf128 (f64.2) (f64.4 imm1) :cost 1) + (f64.4-insert-f64.2 #:vinsertf128 (f64.4) (f64.4 f64.2 imm1) :cost 1) + (f64.4-set128 #:vinsertf128 (f64.4) (f64.2 f64.2 imm1) :cost 1) + (f64.4-movemask #:vmovmskpd (u4) (f64.4) :cost 1) + ;; u8.16 + (u8.16!-from-u8 #:movq (u8.16) (u8) :cost 1) + (u8.16!-from-p128 #:vmovdqu (u8.16) (p128) :cost 1 :encoding :move :always-translatable nil) + (u8.16!-from-p256 #:vextractf128 (u8.16) (p256) :cost 1 :suffix '(0) :always-translatable nil) + (make-u8.16 nil (u8.16) (u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8) :cost 1 :encoding :fake-vop) + (u8.16-values nil (u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8) (u8.16) :cost 1 :encoding :fake-vop) + (u8.16-broadcast nil (u8.16) (u8) :cost 1 :encoding :fake-vop) + (u8.16-blend #:vpblendvb (u8.16) (u8.16 u8.16 u8.16) :cost 1) + (two-arg-u8.16-and #:vpand (u8.16) (u8.16 u8.16) :cost 1 :associative t) + (two-arg-u8.16-or #:vpor (u8.16) (u8.16 u8.16) :cost 1 :associative t) + (two-arg-u8.16-xor #:vpxor (u8.16) (u8.16 u8.16) :cost 1 :associative t) + (u8.16-andc1 #:vpandn (u8.16) (u8.16 u8.16) :cost 1) + (u8.16-not nil (u8.16) (u8.16) :cost 1 :encoding :fake-vop) + (two-arg-u8.16+ #:vpaddb (u8.16) (u8.16 u8.16) :cost 2 :associative t) + (two-arg-u8.16- #:vpsubb (u8.16) (u8.16 u8.16) :cost 2) + (two-arg-u8.16= #:vpcmpeqb (u8.16) (u8.16 u8.16) :cost 1 :associative t) + (two-arg-u8.16/= nil (u8.16) (u8.16 u8.16) :cost 2 :associative t :encoding :fake-vop) + (two-arg-u8.16>~ #:vpcmpgtb (u8.16) (u8.16 u8.16) :cost 1) + (two-arg-u8.16> nil (u8.16) (u8.16 u8.16) :cost 1 :encoding :fake-vop) + (two-arg-u8.16< nil (u8.16) (u8.16 u8.16) :cost 1 :encoding :fake-vop) + (two-arg-u8.16>= nil (u8.16) (u8.16 u8.16) :cost 2 :encoding :fake-vop) + (two-arg-u8.16<= nil (u8.16) (u8.16 u8.16) :cost 2 :encoding :fake-vop) + (u8.16-unpackhi #:vpunpckhbw (u8.16) (u8.16 u8.16) :cost 1) + (u8.16-unpacklo #:vpunpcklbw (u8.16) (u8.16 u8.16) :cost 1) + (u8.16-movemask #:vpmovmskb (u16) (u8.16) :cost 1) + (u8.16-shuffle #:vpshufb (u8.16) (u8.16 u8.16) :cost 1) ;; TODO missing imm + ;; u16.8 + (u16.8!-from-u16 #:movq (u16.8) (u16) :cost 1) + (u16.8!-from-p128 #:vmovdqu (u16.8) (p128) :cost 1 :encoding :move :always-translatable nil) + (u16.8!-from-p256 #:vextractf128 (u16.8) (p256) :cost 1 :suffix '(0) :always-translatable nil) + (make-u16.8 nil (u16.8) (u16 u16 u16 u16 u16 u16 u16 u16) :cost 1 :encoding :fake-vop) + (u16.8-values nil (u16 u16 u16 u16 u16 u16 u16 u16) (u16.8) :cost 1 :encoding :fake-vop) + (u16.8-broadcast nil (u16.8) (u16) :cost 1 :encoding :fake-vop) + (u16.8-blend #:vpblendvb (u16.8) (u16.8 u16.8 u16.8) :cost 1) + (two-arg-u16.8-and #:vpand (u16.8) (u16.8 u16.8) :cost 1 :associative t) + (two-arg-u16.8-or #:vpor (u16.8) (u16.8 u16.8) :cost 1 :associative t) + (two-arg-u16.8-xor #:vpxor (u16.8) (u16.8 u16.8) :cost 1 :associative t) + (u16.8-andc1 #:vpandn (u16.8) (u16.8 u16.8) :cost 1) + (u16.8-not nil (u16.8) (u16.8) :cost 1 :encoding :fake-vop) + (two-arg-u16.8+ #:vpaddw (u16.8) (u16.8 u16.8) :cost 2 :associative t) + (two-arg-u16.8- #:vpsubw (u16.8) (u16.8 u16.8) :cost 2) + (two-arg-u16.8= #:vpcmpeqw (u16.8) (u16.8 u16.8) :cost 1 :associative t) + (two-arg-u16.8/= nil (u16.8) (u16.8 u16.8) :cost 2 :associative t :encoding :fake-vop) + (two-arg-u16.8>~ #:vpcmpgtw (u16.8) (u16.8 u16.8) :cost 1) + (two-arg-u16.8> nil (u16.8) (u16.8 u16.8) :cost 1 :encoding :fake-vop) + (two-arg-u16.8< nil (u16.8) (u16.8 u16.8) :cost 1 :encoding :fake-vop) + (two-arg-u16.8>= nil (u16.8) (u16.8 u16.8) :cost 2 :encoding :fake-vop) + (two-arg-u16.8<= nil (u16.8) (u16.8 u16.8) :cost 2 :encoding :fake-vop) + (u16.8-shiftl #:vpsllw (u16.8) (u16.8 u16.8) :cost 1) + (u16.8-shiftr #:vpsrlw (u16.8) (u16.8 u16.8) :cost 1) + (u16.8-unpackhi #:vpunpckhwd (u16.8) (u16.8 u16.8) :cost 1) + (u16.8-unpacklo #:vpunpcklwd (u16.8) (u16.8 u16.8) :cost 1) + (u16.8-movemask nil (u8) (u16.8) :cost 1 :encoding :fake-vop) + (u16.8-shufflehi #:vpshufhw (u16.8) (u16.8 imm8) :cost 1) + (u16.8-shufflelo #:vpshuflw (u16.8) (u16.8 imm8) :cost 1) + ;; u32.4 + (u32.4!-from-u32 #:movq (u32.4) (u32) :cost 1) + (u32.4!-from-p128 #:vmovdqu (u32.4) (p128) :cost 1 :encoding :move :always-translatable nil) + (u32.4!-from-p256 #:vextractf128 (u32.4) (p256) :cost 1 :suffix '(0) :always-translatable nil) + (make-u32.4 nil (u32.4) (u32 u32 u32 u32) :cost 1 :encoding :fake-vop) + (u32.4-values nil (u32 u32 u32 u32) (u32.4) :cost 1 :encoding :fake-vop) + (u32.4-broadcast nil (u32.4) (u32) :cost 1 :encoding :fake-vop) + (u32.4-blend #:vpblendvb (u32.4) (u32.4 u32.4 u32.4) :cost 1) + (two-arg-u32.4-and #:vpand (u32.4) (u32.4 u32.4) :cost 1 :associative t) + (two-arg-u32.4-or #:vpor (u32.4) (u32.4 u32.4) :cost 1 :associative t) + (two-arg-u32.4-xor #:vpxor (u32.4) (u32.4 u32.4) :cost 1 :associative t) + (u32.4-andc1 #:vpandn (u32.4) (u32.4 u32.4) :cost 1) + (u32.4-not nil (u32.4) (u32.4) :cost 1 :encoding :fake-vop) + (two-arg-u32.4+ #:vpaddd (u32.4) (u32.4 u32.4) :cost 2 :associative t) + (two-arg-u32.4- #:vpsubd (u32.4) (u32.4 u32.4) :cost 2) + (two-arg-u32.4= #:vpcmpeqd (u32.4) (u32.4 u32.4) :cost 1 :associative t) + (two-arg-u32.4/= nil (u32.4) (u32.4 u32.4) :cost 2 :associative t :encoding :fake-vop) + (two-arg-u32.4>~ #:vpcmpgtd (u32.4) (u32.4 u32.4) :cost 1) + (two-arg-u32.4> nil (u32.4) (u32.4 u32.4) :cost 1 :encoding :fake-vop) + (two-arg-u32.4< nil (u32.4) (u32.4 u32.4) :cost 1 :encoding :fake-vop) + (two-arg-u32.4>= nil (u32.4) (u32.4 u32.4) :cost 2 :encoding :fake-vop) + (two-arg-u32.4<= nil (u32.4) (u32.4 u32.4) :cost 2 :encoding :fake-vop) + (u32.4-unpackhi #:vpunpckhdq (u32.4) (u32.4 u32.4) :cost 1) + (u32.4-unpacklo #:vpunpckldq (u32.4) (u32.4 u32.4) :cost 1) + (u32.4-movemask #:vmovmskps (u4) (u32.4) :cost 1) + (u32.4-permute #:vpermilps (u32.4) (u32.4 imm8) :cost 1) + ;; u64.2 + (u64.2!-from-u64 #:movq (u64.2) (u64) :cost 1) + (u64.2!-from-p128 #:vmovdqu (u64.2) (p128) :cost 1 :encoding :move :always-translatable nil) + (u64.2!-from-p256 #:vextractf128 (u64.2) (p256) :cost 1 :suffix '(0) :always-translatable nil) + (make-u64.2 nil (u64.2) (u64 u64) :cost 1 :encoding :fake-vop) + (u64.2-values nil (u64 u64) (u64.2) :cost 1 :encoding :fake-vop) + (u64.2-broadcast nil (u64.2) (u64) :cost 1 :encoding :fake-vop) + (u64.2-from-u64 #:movq (u64.2) (u64) :cost 1) + (u64.2-blend #:vpblendvb (u64.2) (u64.2 u64.2 u64.2) :cost 1) + (two-arg-u64.2-and #:vpand (u64.2) (u64.2 u64.2) :cost 1 :associative t) + (two-arg-u64.2-or #:vpor (u64.2) (u64.2 u64.2) :cost 1 :associative t) + (two-arg-u64.2-xor #:vpxor (u64.2) (u64.2 u64.2) :cost 1 :associative t) + (u64.2-andc1 #:vpandn (u64.2) (u64.2 u64.2) :cost 1) + (u64.2-not nil (u64.2) (u64.2) :cost 1 :encoding :fake-vop) + (two-arg-u64.2+ #:vpaddq (u64.2) (u64.2 u64.2) :cost 2 :associative t) + (two-arg-u64.2- #:vpsubq (u64.2) (u64.2 u64.2) :cost 2) + (two-arg-u64.2= #:vpcmpeqq (u64.2) (u64.2 u64.2) :cost 1 :associative t) + (two-arg-u64.2/= nil (u64.2) (u64.2 u64.2) :cost 2 :associative t :encoding :fake-vop) + (two-arg-u64.2>~ #:vpcmpgtq (u64.2) (u64.2 u64.2) :cost 1) + (two-arg-u64.2> nil (u64.2) (u64.2 u64.2) :cost 1 :encoding :fake-vop) + (two-arg-u64.2< nil (u64.2) (u64.2 u64.2) :cost 1 :encoding :fake-vop) + (two-arg-u64.2>= nil (u64.2) (u64.2 u64.2) :cost 2 :encoding :fake-vop) + (two-arg-u64.2<= nil (u64.2) (u64.2 u64.2) :cost 2 :encoding :fake-vop) + (u64.2-unpackhi #:vpunpckhqdq (u64.2) (u64.2 u64.2) :cost 1) + (u64.2-unpacklo #:vpunpcklqdq (u64.2) (u64.2 u64.2) :cost 1) + (u64.2-movemask #:vmovmskpd (u2) (u64.2) :cost 1) + (u64.2-permute #:vpermilpd (u64.2) (u64.2 imm8) :cost 1) + ;; u8.32 + (u8.32!-from-u8 #:movq (u8.32) (u8) :cost 1) + (u8.32!-from-p128 #:vmovdqu (u8.32) (p128) :cost 1 :encoding :move :always-translatable nil) + (u8.32!-from-p256 #:vmovdqu (u8.32) (p256) :cost 1 :encoding :move :always-translatable nil) + (make-u8.32 nil (u8.32) (u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8) :cost 1 :encoding :fake-vop) + (u8.32-values nil (u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8) (u8.32) :cost 1 :encoding :fake-vop) + (u8.32-broadcast nil (u8.32) (u8) :cost 1 :encoding :fake-vop) + (u8.16-from-u8.32 #:vextractf128 (u8.16) (u8.32 imm1) :cost 1) + (u8.32-insert-u8.16 #:vinsertf128 (u8.32) (u8.32 u8.16 imm1) :cost 1) + ;; u16.16 + (u16.16!-from-u16 #:movq (u16.16) (u16) :cost 1) + (u16.16!-from-p128 #:vmovdqu (u16.16) (p128) :cost 1 :encoding :move :always-translatable nil) + (u16.16!-from-p256 #:vmovdqu (u16.16) (p256) :cost 1 :encoding :move :always-translatable nil) + (make-u16.16 nil (u16.16) (u16 u16 u16 u16 u16 u16 u16 u16 u16 u16 u16 u16 u16 u16 u16 u16) :cost 1 :encoding :fake-vop) + (u16.16-values nil (u16 u16 u16 u16 u16 u16 u16 u16 u16 u16 u16 u16 u16 u16 u16 u16) (u16.16) :cost 1 :encoding :fake-vop) + (u16.16-broadcast nil (u16.16) (u16) :cost 1 :encoding :fake-vop) + (u16.8-from-u16.16 #:vextractf128 (u16.8) (u16.16 imm1) :cost 1) + (u16.16-insert-u16.8 #:vinsertf128 (u16.16) (u16.16 u16.8 imm1) :cost 1) + ;; u32.8 + (u32.8!-from-u32 #:movq (u32.8) (u32) :cost 1) + (u32.8!-from-p128 #:vmovdqu (u32.8) (p128) :cost 1 :encoding :move :always-translatable nil) + (u32.8!-from-p256 #:vmovdqu (u32.8) (p256) :cost 1 :encoding :move :always-translatable nil) + (make-u32.8 nil (u32.8) (u32 u32 u32 u32 u32 u32 u32 u32) :cost 1 :encoding :fake-vop) + (two-arg-u32.8-and #:vandps (u32.8) (u32.8 u32.8) :cost 1 :associative t) + (u32.8-values nil (u32 u32 u32 u32 u32 u32 u32 u32) (u32.8) :cost 1 :encoding :fake-vop) + (u32.8-broadcast nil (u32.8) (u32) :cost 1 :encoding :fake-vop) + (u32.8-permute #:vpermilps (u32.8) (u32.4 imm8) :cost 1) + (u32.4-from-u32.8 #:vextractf128 (u32.4) (u32.8 imm1) :cost 1) + (u32.8-insert-u32.4 #:vinsertf128 (u32.8) (u32.8 u32.4 imm1) :cost 1) + ;; u64.4 + (u64.4!-from-u64 #:movq (u64.4) (u64) :cost 1) + (u64.4!-from-p128 #:vmovdqu (u64.4) (p128) :cost 1 :encoding :move :always-translatable nil) + (u64.4!-from-p256 #:vmovdqu (u64.4) (p256) :cost 1 :encoding :move :always-translatable nil) + (make-u64.4 nil (u64.4) (u64 u64 u64 u64) :cost 1 :encoding :fake-vop) + (two-arg-u64.4-and #:vandpd (u64.4) (u64.4 u64.4) :cost 1 :associative t) + (u64.4-values nil (u64 u64 u64 u64) (u64.4) :cost 1 :encoding :fake-vop) + (u64.4-broadcast nil (u64.4) (u64) :cost 1 :encoding :fake-vop) + (u64.4-permute #:vpermilpd (u64.4) (u64.4 imm8) :cost 1) + (u64.2-from-u64.4 #:vextractf128 (u64.2) (u64.4 imm1) :cost 1) + (u64.4-insert-u64.2 #:vinsertf128 (u64.4) (u64.4 u64.2 imm1) :cost 1) + ;; s8.16 + (s8.16!-from-s8 nil (s8.16) (s8) :cost 1 :encoding :fake-vop) + (s8.16!-from-p128 #:vmovdqu (s8.16) (p128) :cost 1 :encoding :move :always-translatable nil) + (s8.16!-from-p256 #:vextractf128 (s8.16) (p256) :cost 1 :suffix '(0) :always-translatable nil) + (make-s8.16 nil (s8.16) (s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8) :cost 1 :encoding :fake-vop) + (s8.16-values nil (s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8) (s8.16) :cost 1 :encoding :fake-vop) + (s8.16-broadcast nil (s8.16) (s8) :cost 1 :encoding :fake-vop) + (s8.16-blend #:vpblendvb (s8.16) (s8.16 s8.16 u8.16) :cost 1) + (two-arg-s8.16-and #:vpand (s8.16) (s8.16 s8.16) :cost 1 :associative t) + (two-arg-s8.16-or #:vpor (s8.16) (s8.16 s8.16) :cost 1 :associative t) + (two-arg-s8.16-xor #:vpxor (s8.16) (s8.16 s8.16) :cost 1 :associative t) + (s8.16-andc1 #:vpandn (s8.16) (s8.16 s8.16) :cost 1) + (s8.16-not nil (s8.16) (s8.16) :cost 1 :encoding :fake-vop) + (two-arg-s8.16+ #:vpaddb (s8.16) (s8.16 s8.16) :cost 2 :associative t) + (two-arg-s8.16- #:vpsubb (s8.16) (s8.16 s8.16) :cost 2) + (two-arg-s8.16= #:vpcmpeqb (u8.16) (s8.16 s8.16) :cost 1 :associative t) + (two-arg-s8.16/= nil (u8.16) (s8.16 s8.16) :cost 2 :associative t :encoding :fake-vop) + (two-arg-s8.16> #:vpcmpgtb (u8.16) (s8.16 s8.16) :cost 1) + (two-arg-s8.16< nil (u8.16) (s8.16 s8.16) :cost 1 :encoding :fake-vop) + (two-arg-s8.16>= nil (u8.16) (s8.16 s8.16) :cost 2 :encoding :fake-vop) + (two-arg-s8.16<= nil (u8.16) (s8.16 s8.16) :cost 2 :encoding :fake-vop) + (s8.16-unpackhi #:vpunpckhbw (s8.16) (s8.16 s8.16) :cost 1) + (s8.16-unpacklo #:vpunpcklbw (s8.16) (s8.16 s8.16) :cost 1) + (s8.16-movemask #:vpmovmskb (u16) (s8.16) :cost 1) + (s8.16-shuffle #:vpshufb (s8.16) (s8.16 u8.16) :cost 1) + ;; s16.8 + (s16.8!-from-s16 nil (s16.8) (s16) :cost 1 :encoding :fake-vop) + (s16.8!-from-p128 #:vmovdqu (s16.8) (p128) :cost 1 :encoding :move :always-translatable nil) + (s16.8!-from-p256 #:vextractf128 (s16.8) (p256) :cost 1 :suffix '(0) :always-translatable nil) + (make-s16.8 nil (s16.8) (s16 s16 s16 s16 s16 s16 s16 s16) :cost 1 :encoding :fake-vop) + (s16.8-values nil (s16 s16 s16 s16 s16 s16 s16 s16) (s16.8) :cost 1 :encoding :fake-vop) + (s16.8-broadcast nil (s16.8) (s16) :cost 1 :encoding :fake-vop) + (s16.8-blend #:vpblendvb (s16.8) (s16.8 s16.8 u16.8) :cost 1) + (two-arg-s16.8-and #:vpand (s16.8) (s16.8 s16.8) :cost 1 :associative t) + (two-arg-s16.8-or #:vpor (s16.8) (s16.8 s16.8) :cost 1 :associative t) + (two-arg-s16.8-xor #:vpxor (s16.8) (s16.8 s16.8) :cost 1 :associative t) + (s16.8-andc1 #:vpandn (s16.8) (s16.8 s16.8) :cost 1) + (s16.8-not nil (s16.8) (s16.8) :cost 1 :encoding :fake-vop) + (two-arg-s16.8+ #:vpaddw (s16.8) (s16.8 s16.8) :cost 2 :associative t) + (two-arg-s16.8- #:vpsubw (s16.8) (s16.8 s16.8) :cost 2) + (two-arg-s16.8-mullo #:vpmullw (s16.8) (s16.8 s16.8) :cost 2 :associative t) + (s16.8-shiftl #:vpsllq (s16.8) (s16.8 s16.8) :cost 1) + (s16.8-shiftr #:vpsrlq (s16.8) (s16.8 s16.8) :cost 1) + (two-arg-s16.8= #:vpcmpeqw (u16.8) (s16.8 s16.8) :cost 1 :associative t) + (two-arg-s16.8/= nil (u16.8) (s16.8 s16.8) :cost 2 :associative t :encoding :fake-vop) + (two-arg-s16.8> #:vpcmpgtw (u16.8) (s16.8 s16.8) :cost 1) + (two-arg-s16.8< nil (u16.8) (s16.8 s16.8) :cost 1 :encoding :fake-vop) + (two-arg-s16.8>= nil (u16.8) (s16.8 s16.8) :cost 2 :encoding :fake-vop) + (two-arg-s16.8<= nil (u16.8) (s16.8 s16.8) :cost 2 :encoding :fake-vop) + (s16.8-shiftl #:vpsllw (s16.8) (s16.8 s16.8) :cost 1) + (s16.8-shiftr #:vpsrlw (s16.8) (s16.8 s16.8) :cost 1) + (s16.8-unpackhi #:vpunpckhwd (s16.8) (s16.8 s16.8) :cost 1) + (s16.8-unpacklo #:vpunpcklwd (s16.8) (s16.8 s16.8) :cost 1) + (s16.8-movemask nil (u8) (s16.8) :cost 1 :encoding :fake-vop) + (s16.8-shufflehi #:vpshufhw (s16.8) (s16.8 imm8) :cost 1) + (s16.8-shufflelo #:vpshuflw (s16.8) (s16.8 imm8) :cost 1) + (two-arg-s16.8-mullo #:vpmullw (s16.8) (s16.8 s16.8) :cost 2 :associative t) + ;; s32.4 + (s32.4!-from-s32 nil (s32.4) (s32) :cost 1 :encoding :fake-vop) + (s32.4!-from-p128 #:vmovdqu (s32.4) (p128) :cost 1 :encoding :move :always-translatable nil) + (s32.4!-from-p256 #:vextractf128 (s32.4) (p256) :cost 1 :suffix '(0) :always-translatable nil) + (make-s32.4 nil (s32.4) (s32 s32 s32 s32) :cost 1 :encoding :fake-vop) + (s32.4-values nil (s32 s32 s32 s32) (s32.4) :cost 1 :encoding :fake-vop) + (s32.4-broadcast nil (s32.4) (s32) :cost 1 :encoding :fake-vop) + (s32.4-blend #:vpblendvb (s32.4) (s32.4 s32.4 u32.4) :cost 1) + (s32.4-from-f64.4 #:vcvtpd2dq (s32.4) (f64.4) :cost 5) ;; wrong code is generated VCVTPD2DQ XMM0, XMM0. 3rd and 4th elements are 0s + (s32.4-from-f32.4 #:vcvtps2dq (s32.4) (f32.4) :cost 5) + (two-arg-s32.4-and #:vpand (s32.4) (s32.4 s32.4) :cost 1 :associative t) + (two-arg-s32.4-or #:vpor (s32.4) (s32.4 s32.4) :cost 1 :associative t) + (two-arg-s32.4-xor #:vpxor (s32.4) (s32.4 s32.4) :cost 1 :associative t) + (s32.4-andc1 #:vpandn (s32.4) (s32.4 s32.4) :cost 1) + (s32.4-not nil (s32.4) (s32.4) :cost 1 :encoding :fake-vop) + (two-arg-s32.4+ #:vpaddd (s32.4) (s32.4 s32.4) :cost 2 :associative t) + (two-arg-s32.4- #:vpsubd (s32.4) (s32.4 s32.4) :cost 2) + (two-arg-s32.4-mullo #:vpmulld (s32.4) (s32.4 s32.4) :cost 2 :associative t) + (two-arg-s32.4= #:vpcmpeqd (u32.4) (s32.4 s32.4) :cost 1 :associative t) + (two-arg-s32.4/= nil (u32.4) (s32.4 s32.4) :cost 2 :associative t :encoding :fake-vop) + (two-arg-s32.4> #:vpcmpgtd (u32.4) (s32.4 s32.4) :cost 1) + (two-arg-s32.4< nil (u32.4) (s32.4 s32.4) :cost 1 :encoding :fake-vop) + (two-arg-s32.4>= nil (u32.4) (s32.4 s32.4) :cost 2 :encoding :fake-vop) + (two-arg-s32.4<= nil (u32.4) (s32.4 s32.4) :cost 2 :encoding :fake-vop) + (s32.4-unpackhi #:vpunpckhdq (s32.4) (s32.4 s32.4) :cost 1) + (s32.4-unpacklo #:vpunpckldq (s32.4) (s32.4 s32.4) :cost 1) + (s32.4-movemask #:vmovmskps (u4) (s32.4) :cost 1) + (s32.4-permute #:vpermilps (s32.4) (s32.4 imm8) :cost 1) + ;; s64.2 + (s64.2!-from-s64 nil (s64.2) (s64) :cost 1 :encoding :fake-vop) + (s64.2!-from-p128 #:vmovdqu (s64.2) (p128) :cost 1 :encoding :move :always-translatable nil) + (s64.2!-from-p256 #:vextractf128 (s64.2) (p256) :cost 1 :suffix '(0) :always-translatable nil) + (make-s64.2 nil (s64.2) (s64 s64) :cost 1 :encoding :fake-vop) + (s64.2-values nil (s64 s64) (s64.2) :cost 1 :encoding :fake-vop) + (s64.2-broadcast nil (s64.2) (s64) :cost 1 :encoding :fake-vop) + (s64.2-blend #:vpblendvb (s64.2) (s64.2 s64.2 u64.2) :cost 1) + (two-arg-s64.2-and #:vpand (s64.2) (s64.2 s64.2) :cost 1 :associative t) + (two-arg-s64.2-or #:vpor (s64.2) (s64.2 s64.2) :cost 1 :associative t) + (two-arg-s64.2-xor #:vpxor (s64.2) (s64.2 s64.2) :cost 1 :associative t) + (s64.2-andc1 #:vpandn (s64.2) (s64.2 s64.2) :cost 1) + (s64.2-not nil (s64.2) (s64.2) :cost 1 :encoding :fake-vop) + (two-arg-s64.2+ #:vpaddq (s64.2) (s64.2 s64.2) :cost 2 :associative t) + (two-arg-s64.2- #:vpsubq (s64.2) (s64.2 s64.2) :cost 2) + (s64.2-shiftl #:vpsllq (s64.2) (s64.2 s64.2) :cost 1) + (s64.2-shiftr #:vpsrlq (s64.2) (s64.2 s64.2) :cost 1) + (two-arg-s64.2= #:vpcmpeqq (u64.2) (s64.2 s64.2) :cost 1 :associative t) + (two-arg-s64.2/= nil (u64.2) (s64.2 s64.2) :cost 2 :associative t :encoding :fake-vop) + (two-arg-s64.2> #:vpcmpgtq (u64.2) (s64.2 s64.2) :cost 1) + (two-arg-s64.2< nil (u64.2) (s64.2 s64.2) :cost 1 :encoding :fake-vop) + (two-arg-s64.2>= nil (u64.2) (s64.2 s64.2) :cost 2 :encoding :fake-vop) + (two-arg-s64.2<= nil (u64.2) (s64.2 s64.2) :cost 2 :encoding :fake-vop) + (s64.2-unpackhi #:vpunpckhqdq (s64.2) (s64.2 s64.2) :cost 1) + (s64.2-unpacklo #:vpunpcklqdq (s64.2) (s64.2 s64.2) :cost 1) + (s64.2-movemask #:vmovmskpd (u2) (s64.2) :cost 1) + (s64.2-permute #:vpermilpd (s64.2) (s64.2 imm8) :cost 1) + ;; s8.32 + (s8.32!-from-s8 nil (s8.32) (s8) :cost 1 :encoding :fake-vop) + (s8.32!-from-p128 #:vmovdqu (s8.32) (p128) :cost 1 :encoding :move :always-translatable nil) + (s8.32!-from-p256 #:vmovdqu (s8.32) (p256) :cost 1 :encoding :move :always-translatable nil) + (make-s8.32 nil (s8.32) (s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8) :cost 1 :encoding :fake-vop) + (s8.32-values nil (s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8) (s8.32) :cost 1 :encoding :fake-vop) + (s8.32-broadcast nil (s8.32) (s8) :cost 1 :encoding :fake-vop) + (s8.16-from-s8.32 #:vextractf128 (s8.16) (s8.32 imm1) :cost 1) + (s8.32-insert-s8.16 #:vinsertf128 (s8.32) (s8.32 s8.16 imm1) :cost 1) + (s8.32-permute128 #:vperm2f128 (s8.32) (s8.32 s8.32 imm8) :cost 1) + ;; s16.16 + (s16.16!-from-s16 nil (s16.16) (s16) :cost 1 :encoding :fake-vop) + (s16.16!-from-p128 #:vmovdqu (s16.16) (p128) :cost 1 :encoding :move :always-translatable nil) + (s16.16!-from-p256 #:vmovdqu (s16.16) (p256) :cost 1 :encoding :move :always-translatable nil) + (make-s16.16 nil (s16.16) (s16 s16 s16 s16 s16 s16 s16 s16 s16 s16 s16 s16 s16 s16 s16 s16) :cost 1 :encoding :fake-vop) + (s16.16-values nil (s16 s16 s16 s16 s16 s16 s16 s16 s16 s16 s16 s16 s16 s16 s16 s16) (s16.16) :cost 1 :encoding :fake-vop) + (s16.16-broadcast nil (s16.16) (s16) :cost 1 :encoding :fake-vop) + (s16.8-from-s16.16 #:vextractf128 (s16.8) (s16.16 imm1) :cost 1) + (s16.16-insert-s16.8 #:vinsertf128 (s16.16) (s16.16 s16.8 imm1) :cost 1) + (s16.16-permute128 #:vperm2f128 (s16.16) (s16.16 s16.16 imm8) :cost 1) + ;; s32.8 + (s32.8!-from-s32 nil (s32.8) (s32) :cost 1 :encoding :fake-vop) + (s32.8!-from-p128 #:vmovdqu (s32.8) (p128) :cost 1 :encoding :move :always-translatable nil) + (s32.8!-from-p256 #:vmovdqu (s32.8) (p256) :cost 1 :encoding :move :always-translatable nil) + (make-s32.8 nil (s32.8) (s32 s32 s32 s32 s32 s32 s32 s32) :cost 1 :encoding :fake-vop) + (s32.8-values nil (s32 s32 s32 s32 s32 s32 s32 s32) (s32.8) :cost 1 :encoding :fake-vop) + (s32.8-broadcast nil (s32.8) (s32) :cost 1 :encoding :fake-vop) + (s32.8-from-f32.8 #:vcvtps2dq (s32.8) (f32.8) :cost 4) + (s32.8-permute #:vpermilps (s32.8) (s32.4 imm8) :cost 1) + (s32.4-from-s32.8 #:vextractf128 (s32.4) (s32.8 imm1) :cost 1) + (s32.8-insert-s32.4 #:vinsertf128 (s32.8) (s32.8 s32.4 imm1) :cost 1) + (s32.8-permute128 #:vperm2f128 (s32.8) (s32.8 s32.8 imm8) :cost 1) + ;; s64.4 + (s64.4!-from-s64 nil (s64.4) (s64) :cost 1 :encoding :fake-vop) + (s64.4!-from-p128 #:vmovdqu (s64.4) (p128) :cost 1 :encoding :move :always-translatable nil) + (s64.4!-from-p256 #:vmovdqu (s64.4) (p256) :cost 1 :encoding :move :always-translatable nil) + (make-s64.4 nil (s64.4) (s64 s64 s64 s64) :cost 1 :encoding :fake-vop) + (s64.4-values nil (s64 s64 s64 s64) (s64.4) :cost 1 :encoding :fake-vop) + (s64.4-broadcast nil (s64.4) (s64) :cost 1 :encoding :fake-vop) + (s64.4-permute #:vpermilpd (s64.4) (s64.4 imm8) :cost 1) + (s64.2-from-s64.4 #:vextractf128 (s64.2) (s64.4 imm1) :cost 1) + (s64.4-insert-s64.2 #:vinsertf128 (s64.4) (s64.4 s64.2 imm1) :cost 1) + (s64.4-permute128 #:vperm2f128 (s64.4) (s64.4 s64.4 imm8) :cost 1)) + (:loads + #+sb-unicode + (u32.4-load-from-string #:vmovdqu u32.4 charvec char-array u32.4-string-ref u32.4-row-major-string-ref) + #+sb-unicode + (u32.8-load-from-string #:vmovdqu u32.8 charvec char-array u32.8-string-ref u32.8-row-major-string-ref) + (f32-load #:vmovss f32 f32vec f32-array f32-aref f32-row-major-aref) + (f64-load #:vmovsd f64 f64vec f64-array f64-aref f64-row-major-aref) + (f32.4-load #:vmovups f32.4 f32vec f32-array f32.4-aref f32.4-row-major-aref) + (f64.2-load #:vmovupd f64.2 f64vec f64-array f64.2-aref f64.2-row-major-aref) + (f32.8-load #:vmovups f32.8 f32vec f32-array f32.8-aref f32.8-row-major-aref) + (f64.4-load #:vmovupd f64.4 f64vec f64-array f64.4-aref f64.4-row-major-aref) + (u8.16-load #:vmovdqu u8.16 u8vec u8-array u8.16-aref u8.16-row-major-aref) + (u16.8-load #:vmovdqu u16.8 u16vec u16-array u16.8-aref u16.8-row-major-aref) + (u32.4-load #:vmovdqu u32.4 u32vec u32-array u32.4-aref u32.4-row-major-aref) + (u64.2-load #:vmovdqu u64.2 u64vec u64-array u64.2-aref u64.2-row-major-aref) + (u8.32-load #:vmovdqu u8.32 u8vec u8-array u8.32-aref u8.32-row-major-aref) + (u16.16-load #:vmovdqu u16.16 u16vec u16-array u16.16-aref u16.16-row-major-aref) + (u32.8-load #:vmovdqu u32.8 u32vec u32-array u32.8-aref u32.8-row-major-aref) + (u64.4-load #:vmovdqu u64.4 u64vec u64-array u64.4-aref u64.4-row-major-aref) + (s8.16-load #:vmovdqu s8.16 s8vec s8-array s8.16-aref s8.16-row-major-aref) + (s16.8-load #:vmovdqu s16.8 s16vec s16-array s16.8-aref s16.8-row-major-aref) + (s32.4-load #:vmovdqu s32.4 s32vec s32-array s32.4-aref s32.4-row-major-aref) + (s64.2-load #:vmovdqu s64.2 s64vec s64-array s64.2-aref s64.2-row-major-aref) + (s8.32-load #:vmovdqu s8.32 s8vec s8-array s8.32-aref s8.32-row-major-aref) + (s16.16-load #:vmovdqu s16.16 s16vec s16-array s16.16-aref s16.16-row-major-aref) + (s32.8-load #:vmovdqu s32.8 s32vec s32-array s32.8-aref s32.8-row-major-aref) + (s64.4-load #:vmovdqu s64.4 s64vec s64-array s64.4-aref s64.4-row-major-aref)) + (:stores + #+sb-unicode + (u32.4-store-into-string #:vmovdqu u32.4 charvec char-array u32.4-string-ref u32.4-row-major-string-ref) + #+sb-unicode + (u32.8-store-into-string #:vmovdqu u32.8 charvec char-array u32.8-string-ref u32.8-row-major-string-ref) + (f32-store #:vmovss f32 f32vec f32-array f32-aref f32-row-major-aref) + (f64-store #:vmovsd f64 f64vec f64-array f64-aref f64-row-major-aref) + (f32.4-store #:vmovups f32.4 f32vec f32-array f32.4-aref f32.4-row-major-aref) + (f64.2-store #:vmovupd f64.2 f64vec f64-array f64.2-aref f64.2-row-major-aref) + (f32.8-store #:vmovups f32.8 f32vec f32-array f32.8-aref f32.8-row-major-aref) + (f64.4-store #:vmovupd f64.4 f64vec f64-array f64.4-aref f64.4-row-major-aref) + (u8.16-store #:vmovdqu u8.16 u8vec u8-array u8.16-aref u8.16-row-major-aref) + (u16.8-store #:vmovdqu u16.8 u16vec u16-array u16.8-aref u16.8-row-major-aref) + (u32.4-store #:vmovdqu u32.4 u32vec u32-array u32.4-aref u32.4-row-major-aref) + (u64.2-store #:vmovdqu u64.2 u64vec u64-array u64.2-aref u64.2-row-major-aref) + (s8.16-store #:vmovdqu s8.16 s8vec s8-array s8.16-aref s8.16-row-major-aref) + (s16.8-store #:vmovdqu s16.8 s16vec s16-array s16.8-aref s16.8-row-major-aref) + (s32.4-store #:vmovdqu s32.4 s32vec s32-array s32.4-aref s32.4-row-major-aref) + (s64.2-store #:vmovdqu s64.2 s64vec s64-array s64.2-aref s64.2-row-major-aref) + (u8.32-store #:vmovdqu u8.32 u8vec u8-array u8.32-aref u8.32-row-major-aref) + (u16.16-store #:vmovdqu u16.16 u16vec u16-array u16.16-aref u16.16-row-major-aref) + (u32.8-store #:vmovdqu u32.8 u32vec u32-array u32.8-aref u32.8-row-major-aref) + (u64.4-store #:vmovdqu u64.4 u64vec u64-array u64.4-aref u64.4-row-major-aref) + (s8.32-store #:vmovdqu s8.32 s8vec s8-array s8.32-aref s8.32-row-major-aref) + (s16.16-store #:vmovdqu s16.16 s16vec s16-array s16.16-aref s16.16-row-major-aref) + (s32.8-store #:vmovdqu s32.8 s32vec s32-array s32.8-aref s32.8-row-major-aref) + (s64.4-store #:vmovdqu s64.4 s64vec s64-array s64.4-aref s64.4-row-major-aref) + (f32.4-ntstore #:vmovntps f32.4 f32vec f32-array f32.4-non-temporal-aref f32.4-non-temporal-row-major-aref) + (f64.2-ntstore #:vmovntpd f64.2 f64vec f64-array f64.2-non-temporal-aref f64.2-non-temporal-row-major-aref) + (f32.8-ntstore #:vmovntps f32.8 f32vec f32-array f32.8-non-temporal-aref f32.8-non-temporal-row-major-aref) + (f64.4-ntstore #:vmovntpd f64.4 f64vec f64-array f64.4-non-temporal-aref f64.4-non-temporal-row-major-aref) + (u8.16-ntstore #:vmovntdq u8.16 u8vec u8-array u8.16-non-temporal-aref u8.16-non-temporal-row-major-aref) + (u16.8-ntstore #:vmovntdq u16.8 u16vec u16-array u16.8-non-temporal-aref u16.8-non-temporal-row-major-aref) + (u32.4-ntstore #:vmovntdq u32.4 u32vec u32-array u32.4-non-temporal-aref u32.4-non-temporal-row-major-aref) + (u64.2-ntstore #:vmovntdq u64.2 u64vec u64-array u64.2-non-temporal-aref u64.2-non-temporal-row-major-aref) + (s8.16-ntstore #:vmovntdq s8.16 s8vec s8-array s8.16-non-temporal-aref s8.16-non-temporal-row-major-aref) + (s16.8-ntstore #:vmovntdq s16.8 s16vec s16-array s16.8-non-temporal-aref s16.8-non-temporal-row-major-aref) + (s32.4-ntstore #:vmovntdq s32.4 s32vec s32-array s32.4-non-temporal-aref s32.4-non-temporal-row-major-aref) + (s64.2-ntstore #:vmovntdq s64.2 s64vec s64-array s64.2-non-temporal-aref s64.2-non-temporal-row-major-aref) + (u8.32-ntstore #:vmovntdq u8.32 u8vec u8-array u8.32-non-temporal-aref u8.32-non-temporal-row-major-aref) + (u16.16-ntstore #:vmovntdq u16.16 u16vec u16-array u16.16-non-temporal-aref u16.16-non-temporal-row-major-aref) + (u32.8-ntstore #:vmovntdq u32.8 u32vec u32-array u32.8-non-temporal-aref u32.8-non-temporal-row-major-aref) + (u64.4-ntstore #:vmovntdq u64.4 u64vec u64-array u64.4-non-temporal-aref u64.4-non-temporal-row-major-aref) + (s8.32-ntstore #:vmovntdq s8.32 s8vec s8-array s8.32-non-temporal-aref s8.32-non-temporal-row-major-aref) + (s16.16-ntstore #:vmovntdq s16.16 s16vec s16-array s16.16-non-temporal-aref s16.16-non-temporal-row-major-aref) + (s32.8-ntstore #:vmovntdq s32.8 s32vec s32-array s32.8-non-temporal-aref s32.8-non-temporal-row-major-aref) + (s64.4-ntstore #:vmovntdq s64.4 s64vec s64-array s64.4-non-temporal-aref s64.4-non-temporal-row-major-aref)) + (:associatives + (f32-and two-arg-f32-and +f32-true+) + (f32-or two-arg-f32-or +f32-false+) + (f32-xor two-arg-f32-xor +f32-false+) + (f32-max two-arg-f32-max nil) + (f32-min two-arg-f32-min nil) + (f32+ two-arg-f32+ 0f0) + (f32* two-arg-f32* 1f0) + (f64-and two-arg-f64-and +f64-true+) + (f64-or two-arg-f64-or +f64-false+) + (f64-xor two-arg-f64-xor +f64-false+) + (f64-max two-arg-f64-max nil) + (f64-min two-arg-f64-min nil) + (f64+ two-arg-f64+ 0d0) + (f64* two-arg-f64* 1d0) + (f32.4-and two-arg-f32.4-and +f32-true+) + (f32.4-or two-arg-f32.4-or +f32-false+) + (f32.4-xor two-arg-f32.4-xor +f32-false+) + (f32.4-max two-arg-f32.4-max nil) + (f32.4-min two-arg-f32.4-min nil) + (f32.4+ two-arg-f32.4+ 0f0) + (f32.4* two-arg-f32.4* 1f0) + (f64.2-and two-arg-f64.2-and +f64-true+) + (f64.2-or two-arg-f64.2-or +f64-false+) + (f64.2-xor two-arg-f64.2-xor +f64-false+) + (f64.2-max two-arg-f64.2-max nil) + (f64.2-min two-arg-f64.2-min nil) + (f64.2+ two-arg-f64.2+ 0d0) + (f64.2* two-arg-f64.2* 1d0) + (f32.8-and two-arg-f32.8-and +f32-true+) + (f32.8-or two-arg-f32.8-or +f32-false+) + (f32.8-xor two-arg-f32.8-xor +f32-false+) + (f32.8-max two-arg-f32.8-max nil) + (f32.8-min two-arg-f32.8-min nil) + (f32.8+ two-arg-f32.8+ 0f0) + (f32.8* two-arg-f32.8* 1f0) + (f64.4-and two-arg-f64.4-and +f64-true+) + (f64.4-or two-arg-f64.4-or +f64-false+) + (f64.4-xor two-arg-f64.4-xor +f64-false+) + (f64.4-max two-arg-f64.4-max nil) + (f64.4-min two-arg-f64.4-min nil) + (f64.4+ two-arg-f64.4+ 0d0) + (f64.4* two-arg-f64.4* 1d0) + (u8.16-and two-arg-u8.16-and +u8-true+) + (u8.16-or two-arg-u8.16-or +u8-false+) + (u8.16-xor two-arg-u8.16-xor +u8-false+) + (u8.16+ two-arg-u8.16+ 0) + (u16.8-and two-arg-u16.8-and +u16-true+) + (u16.8-or two-arg-u16.8-or +u16-false+) + (u16.8-xor two-arg-u16.8-xor +u16-false+) + (u16.8+ two-arg-u16.8+ 0) + (u32.4-and two-arg-u32.4-and +u32-true+) + (u32.4-or two-arg-u32.4-or +u32-false+) + (u32.4-xor two-arg-u32.4-xor +u32-false+) + (u32.4+ two-arg-u32.4+ 0) + (u64.2-and two-arg-u64.2-and +u64-true+) + (u64.2-or two-arg-u64.2-or +u64-false+) + (u64.2-xor two-arg-u64.2-xor +u64-false+) + (u64.2+ two-arg-u64.2+ 0) + (s8.16-and two-arg-s8.16-and +s8-true+) + (s8.16-or two-arg-s8.16-or +s8-false+) + (s8.16-xor two-arg-s8.16-xor +s8-false+) + (s8.16+ two-arg-s8.16+ 0) + (s16.8-and two-arg-s16.8-and +s16-true+) + (s16.8-or two-arg-s16.8-or +s16-false+) + (s16.8-xor two-arg-s16.8-xor +s16-false+) + (s16.8+ two-arg-s16.8+ 0) + (s16.8-mullo two-arg-s16.8-mullo 1) + (s32.4-and two-arg-s32.4-and +s32-true+) + (s32.4-or two-arg-s32.4-or +s32-false+) + (s32.4-xor two-arg-s32.4-xor +s32-false+) + (s32.4+ two-arg-s32.4+ 0) + (s32.4-mullo two-arg-s32.4-mullo 1) + (s64.2-and two-arg-s64.2-and +s64-true+) + (s64.2-or two-arg-s64.2-or +s64-false+) + (s64.2-xor two-arg-s64.2-xor +s64-false+) + (s64.2+ two-arg-s64.2+ 0) + ;; The next two functions are only required for implementing + ;; floating-point comparisons and unequals. + (u32.8-and two-arg-u32.8-and +u32-true+) + (u64.4-and two-arg-u64.4-and +u64-true+)) + (:comparisons + (f32= two-arg-f32= u32-and +u32-true+) + (f32< two-arg-f32< u32-and +u32-true+) + (f32<= two-arg-f32<= u32-and +u32-true+) + (f32> two-arg-f32> u32-and +u32-true+) + (f32>= two-arg-f32>= u32-and +u32-true+) + (f64= two-arg-f64= u64-and +u64-true+) + (f64< two-arg-f64< u64-and +u64-true+) + (f64<= two-arg-f64<= u64-and +u64-true+) + (f64> two-arg-f64> u64-and +u64-true+) + (f64>= two-arg-f64>= u64-and +u64-true+) + (f32.4= two-arg-f32.4= u32.4-and +u32-true+) + (f32.4< two-arg-f32.4< u32.4-and +u32-true+) + (f32.4<= two-arg-f32.4<= u32.4-and +u32-true+) + (f32.4> two-arg-f32.4> u32.4-and +u32-true+) + (f32.4>= two-arg-f32.4>= u32.4-and +u32-true+) + (f64.2= two-arg-f64.2= u64.2-and +u64-true+) + (f64.2< two-arg-f64.2< u64.2-and +u64-true+) + (f64.2<= two-arg-f64.2<= u64.2-and +u64-true+) + (f64.2> two-arg-f64.2> u64.2-and +u64-true+) + (f64.2>= two-arg-f64.2>= u64.2-and +u64-true+) + (f32.8= two-arg-f32.8= u32.8-and +u32-true+) + (f32.8< two-arg-f32.8< u32.8-and +u32-true+) + (f32.8<= two-arg-f32.8<= u32.8-and +u32-true+) + (f32.8> two-arg-f32.8> u32.8-and +u32-true+) + (f32.8>= two-arg-f32.8>= u32.8-and +u32-true+) + (f64.4= two-arg-f64.4= u64.4-and +u64-true+) + (f64.4< two-arg-f64.4< u64.4-and +u64-true+) + (f64.4<= two-arg-f64.4<= u64.4-and +u64-true+) + (f64.4> two-arg-f64.4> u64.4-and +u64-true+) + (f64.4>= two-arg-f64.4>= u64.4-and +u64-true+) + (u8.16= two-arg-u8.16= u8.16-and +u8-true+) + (u8.16< two-arg-u8.16< u8.16-and +u8-true+) + (u8.16<= two-arg-u8.16<= u8.16-and +u8-true+) + (u8.16> two-arg-u8.16> u8.16-and +u8-true+) + (u8.16>= two-arg-u8.16>= u8.16-and +u8-true+) + (u16.8= two-arg-u16.8= u16.8-and +u16-true+) + (u16.8< two-arg-u16.8< u16.8-and +u16-true+) + (u16.8<= two-arg-u16.8<= u16.8-and +u16-true+) + (u16.8> two-arg-u16.8> u16.8-and +u16-true+) + (u16.8>= two-arg-u16.8>= u16.8-and +u16-true+) + (u32.4= two-arg-u32.4= u32.4-and +u32-true+) + (u32.4< two-arg-u32.4< u32.4-and +u32-true+) + (u32.4<= two-arg-u32.4<= u32.4-and +u32-true+) + (u32.4> two-arg-u32.4> u32.4-and +u32-true+) + (u32.4>= two-arg-u32.4>= u32.4-and +u32-true+) + (u64.2= two-arg-u64.2= u64.2-and +u64-true+) + (u64.2< two-arg-u64.2< u64.2-and +u64-true+) + (u64.2<= two-arg-u64.2<= u64.2-and +u64-true+) + (u64.2> two-arg-u64.2> u64.2-and +u64-true+) + (u64.2>= two-arg-u64.2>= u64.2-and +u64-true+) + (s8.16= two-arg-s8.16= u8.16-and +u8-true+) + (s8.16< two-arg-s8.16< u8.16-and +u8-true+) + (s8.16<= two-arg-s8.16<= u8.16-and +u8-true+) + (s8.16> two-arg-s8.16> u8.16-and +u8-true+) + (s8.16>= two-arg-s8.16>= u8.16-and +u8-true+) + (s16.8= two-arg-s16.8= u16.8-and +u16-true+) + (s16.8< two-arg-s16.8< u16.8-and +u16-true+) + (s16.8<= two-arg-s16.8<= u16.8-and +u16-true+) + (s16.8> two-arg-s16.8> u16.8-and +u16-true+) + (s16.8>= two-arg-s16.8>= u16.8-and +u16-true+) + (s32.4= two-arg-s32.4= u32.4-and +u32-true+) + (s32.4< two-arg-s32.4< u32.4-and +u32-true+) + (s32.4<= two-arg-s32.4<= u32.4-and +u32-true+) + (s32.4> two-arg-s32.4> u32.4-and +u32-true+) + (s32.4>= two-arg-s32.4>= u32.4-and +u32-true+) + (s64.2= two-arg-s64.2= u64.2-and +u64-true+) + (s64.2< two-arg-s64.2< u64.2-and +u64-true+) + (s64.2<= two-arg-s64.2<= u64.2-and +u64-true+) + (s64.2> two-arg-s64.2> u64.2-and +u64-true+) + (s64.2>= two-arg-s64.2>= u64.2-and +u64-true+)) + (:ifs + (f32.4-if f32.4-blend) + (f32.8-if f32.8-blend) + (f64.2-if f64.2-blend) + (f64.4-if f64.4-blend) + (u8.16-if u8.16-blend) + (u16.8-if u16.8-blend) + (u32.4-if u32.4-blend) + (u64.2-if u64.2-blend) + (s8.16-if s8.16-blend) + (s16.8-if s16.8-blend) + (s32.4-if s32.4-blend) + (s64.2-if s64.2-blend)) + (:reducers + (f32- two-arg-f32- 0f0) + (f32/ two-arg-f32/ 1f0) + (f64- two-arg-f64- 0d0) + (f64/ two-arg-f64/ 1d0) + (f32.4- two-arg-f32.4- 0f0) + (f32.4/ two-arg-f32.4/ 1f0) + (f64.2- two-arg-f64.2- 0d0) + (f64.2/ two-arg-f64.2/ 1d0) + (f32.8- two-arg-f32.8- 0f0) + (f32.8/ two-arg-f32.8/ 1f0) + (f64.4- two-arg-f64.4- 0d0) + (f64.4/ two-arg-f64.4/ 1d0) + (u8.16- two-arg-u8.16- 0) + (u16.8- two-arg-u16.8- 0) + (u32.4- two-arg-u32.4- 0) + (u64.2- two-arg-u64.2- 0) + (s8.16- two-arg-s8.16- 0) + (s16.8- two-arg-s16.8- 0) + (s32.4- two-arg-s32.4- 0) + (s64.2- two-arg-s64.2- 0)) + (:unequals + (f32/= two-arg-f32/= u32-and +u32-true+) + (f64/= two-arg-f64/= u64-and +u64-true+) + (f32.4/= two-arg-f32.4/= u32.4-and +u32-true+) + (f64.2/= two-arg-f64.2/= u64.2-and +u64-true+) + (f32.8/= two-arg-f32.8/= u32.8-and +u32-true+) + (f64.4/= two-arg-f64.4/= u64.4-and +u64-true+) + (u8.16/= two-arg-u8.16/= u8.16-and +u8-true+) + (u16.8/= two-arg-u16.8/= u16.8-and +u16-true+) + (u32.4/= two-arg-u32.4/= u32.4-and +u32-true+) + (u64.2/= two-arg-u64.2/= u64.2-and +u64-true+) + (s8.16/= two-arg-s8.16/= u8.16-and +u8-true+) + (s16.8/= two-arg-s16.8/= u16.8-and +u16-true+) + (s32.4/= two-arg-s32.4/= u32.4-and +u32-true+) + (s64.2/= two-arg-s64.2/= u64.2-and +u64-true+))) diff --git a/contrib/sb-simd/code/instruction-sets/avx2.lisp b/contrib/sb-simd/code/instruction-sets/avx2.lisp new file mode 100644 index 0000000000..a0f50c2ea6 --- /dev/null +++ b/contrib/sb-simd/code/instruction-sets/avx2.lisp @@ -0,0 +1,523 @@ +(in-package #:sb-simd-avx2) + +(define-instruction-set :avx2 + (:include :avx) + (:test (avx2-supported-p)) + (:simd-packs + ;; You may wonder why we define these SIMD packs twice both for AVX and + ;; AVX2. The reason is that each of these instruction sets provides its + ;; own version of the constructor for integer SIMD packs. And since the + ;; constructor has the same name as the pack, AVX2 cannot inherit them + ;; from AVX. Luckily, defining SIMD records is cheap, so we can simply + ;; define them again with a different name (or rather, with the same + ;; name but in a different package). + (u8.32 u8 256 #:simd-pack-256-ub8 (#:int-avx2-reg)) + (u16.16 u16 256 #:simd-pack-256-ub16 (#:int-avx2-reg)) + (u32.8 u32 256 #:simd-pack-256-ub32 (#:int-avx2-reg)) + (u64.4 u64 256 #:simd-pack-256-ub64 (#:int-avx2-reg)) + (s8.32 s8 256 #:simd-pack-256-sb8 (#:int-avx2-reg)) + (s16.16 s16 256 #:simd-pack-256-sb16 (#:int-avx2-reg)) + (s32.8 s32 256 #:simd-pack-256-sb32 (#:int-avx2-reg)) + (s64.4 s64 256 #:simd-pack-256-sb64 (#:int-avx2-reg))) + (:simd-casts + (u8.32 u8.32-broadcast) + (u16.16 u16.16-broadcast) + (u32.8 u32.8-broadcast) + (u64.4 u64.4-broadcast) + (s8.32 s8.32-broadcast) + (s16.16 s16.16-broadcast) + (s32.8 s32.8-broadcast) + (s64.4 s64.4-broadcast)) + (:reinterpret-casts + (u8.16! sb-simd-avx::u8.16!-from-u8 sb-simd-avx::u8.16!-from-p128 u8.16!-from-p256) + (u16.8! sb-simd-avx::u16.8!-from-u16 sb-simd-avx::u16.8!-from-p128 u16.8!-from-p256) + (u32.4! sb-simd-avx::u32.4!-from-u32 sb-simd-avx::u32.4!-from-p128 u32.4!-from-p256) + (u64.2! sb-simd-avx::u64.2!-from-u64 sb-simd-avx::u64.2!-from-p128 u64.2!-from-p256) + (s8.16! sb-simd-avx::s8.16!-from-s8 sb-simd-avx::s8.16!-from-p128 s8.16!-from-p256) + (s16.8! sb-simd-avx::s16.8!-from-s16 sb-simd-avx::s16.8!-from-p128 s16.8!-from-p256) + (s32.4! sb-simd-avx::s32.4!-from-s32 sb-simd-avx::s32.4!-from-p128 s32.4!-from-p256) + (s64.2! sb-simd-avx::s64.2!-from-s64 sb-simd-avx::s64.2!-from-p128 s64.2!-from-p256)) + (:instructions + ;; f64.4 + (f64.4-permute4x64 #:vpermpd (f64.4) (f64.4 imm8) :cost 1) + (f64.4-reverse nil (f64.4) (f64.4) :cost 2 :encoding :fake-vop) + ;; u8.16 + (u8.16!-from-p256 #:vextracti128 (u8.16) (p256) :cost 1 :suffix '(0) :always-translatable nil) + (u8.16-broadcast nil (u8.16) (u8) :cost 1 :encoding :fake-vop) + (u8.16-broadcastvec #:vpbroadcastb (u8.16) (u8.16) :cost 1) + ;; u16.8 + (u16.8!-from-p256 #:vextracti128 (u16.8) (p256) :cost 1 :suffix '(0) :always-translatable nil) + (u16.8-broadcast nil (u16.16) (u16) :cost 1 :encoding :fake-vop) + (u16.8-broadcastvec #:vpbroadcastw (u16.16) (u16.8) :cost 1) + ;; u32.4 + (u32.4!-from-p256 #:vextracti128 (u32.4) (p256) :cost 1 :suffix '(0) :always-translatable nil) + (u32.4-broadcast nil (u32.4) (u32) :cost 1 :encoding :fake-vop) + (u32.4-broadcastvec #:vpbroadcastd (u32.4) (u32.4) :cost 1) + (u32.4-shiftl #:vpsllvd (u32.4) (u32.4 u32.4) :cost 1) + (u32.4-shiftr #:vpsrlvd (u32.4) (u32.4 u32.4) :cost 1) + ;; u64.2 + (u64.2!-from-p256 #:vextracti128 (u64.2) (p256) :cost 1 :suffix '(0) :always-translatable nil) + (u64.2-broadcast nil (u64.2) (u64) :cost 1 :encoding :fake-vop) + (u64.2-broadcastvec #:vpbroadcastq (u64.2) (u64.2) :cost 1) + (u64.2-shiftl #:vpsllvd (u64.2) (u64.2 u64.2) :cost 1) + (u64.2-shiftr #:vpsrlvd (u64.2) (u64.2 u64.2) :cost 1) + ;; s8.16 + (s8.16!-from-p256 #:vextracti128 (s8.16) (p256) :cost 1 :suffix '(0) :always-translatable nil) + (s8.16-broadcast nil (s8.16) (s8) :cost 1 :encoding :fake-vop) + (s8.16-broadcastvec #:vpbroadcastb (s8.16) (s8.16) :cost 1) + ;; s16.8 + (s16.8!-from-p256 #:vextracti128 (s16.8) (p256) :cost 1 :suffix '(1) :always-translatable nil) + (s16.8-broadcast nil (s16.16) (s16) :cost 1 :encoding :fake-vop) + (s16.8-broadcastvec #:vpbroadcastw (s16.16) (s16.8) :cost 1) + ;; s32.4 + (s32.4!-from-p256 #:vextracti128 (s32.4) (p256) :cost 1 :suffix '(0) :always-translatable nil) + (s32.4-broadcast nil (s32.4) (s32) :cost 1 :encoding :fake-vop) + (s32.4-broadcastvec #:vpbroadcastd (s32.4) (s32.4) :cost 1) + (s32.4-shiftl #:vpsllvq (s32.4) (s32.4 s32.4) :cost 1) + (s32.4-shiftr #:vpsrlvq (s32.4) (s32.4 s32.4) :cost 1) + ;; s64.2 + (s64.2!-from-p256 #:vextracti128 (s64.2) (p256) :cost 1 :suffix '(0) :always-translatable nil) + (s64.2-broadcast nil (s64.2) (s64) :cost 1 :encoding :fake-vop) + (s64.2-broadcastvec #:vpbroadcastq (s64.2) (s64.2) :cost 1) + (s64.2-shiftl #:vpsllvq (s64.2) (s64.2 s64.2) :cost 1) + (s64.2-shiftr #:vpsrlvq (s64.2) (s64.2 s64.2) :cost 1) + ;; u8.32 + (make-u8.32 nil (u8.32) (u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8) :cost 1 :encoding :fake-vop) + (u8.32-values nil (u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8) (u8.32) :cost 1 :encoding :fake-vop) + (u8.32-broadcast nil (u8.32) (u8) :cost 1 :encoding :fake-vop) + (u8.32-broadcastvec #:vpbroadcastb (u8.32) (u8.32) :cost 1) + (u8.32-blend #:vpblendvb (u8.32) (u8.32 u8.32 u8.32) :cost 1) + (two-arg-u8.32-and #:vpand (u8.32) (u8.32 u8.32) :cost 1 :associative t) + (two-arg-u8.32-or #:vpor (u8.32) (u8.32 u8.32) :cost 1 :associative t) + (two-arg-u8.32-xor #:vpxor (u8.32) (u8.32 u8.32) :cost 1 :associative t) + (u8.32-andc1 #:vpandn (u8.32) (u8.32 u8.32) :cost 1) + (u8.32-not nil (u8.32) (u8.32) :cost 1 :encoding :fake-vop) + (two-arg-u8.32-max #:vpmaxub (u8.32) (u8.32 u8.32) :cost 2 :associative t) + (two-arg-u8.32-min #:vpminub (u8.32) (u8.32 u8.32) :cost 2 :associative t) + (two-arg-u8.32+ #:vpaddb (u8.32) (u8.32 u8.32) :cost 2 :associative t) + (two-arg-u8.32- #:vpsubb (u8.32) (u8.32 u8.32) :cost 2) + (two-arg-u8.32= #:vpcmpeqb (u8.32) (u8.32 u8.32) :cost 1 :associative t) + (two-arg-u8.32/= nil (u8.32) (u8.32 u8.32) :cost 2 :associative t :encoding :fake-vop) + (two-arg-u8.32>~ #:vpcmpgtb (u8.32) (u8.32 u8.32) :cost 1) + (two-arg-u8.32> nil (u8.32) (u8.32 u8.32) :cost 1 :encoding :fake-vop) + (two-arg-u8.32< nil (u8.32) (u8.32 u8.32) :cost 1 :encoding :fake-vop) + (two-arg-u8.32>= nil (u8.32) (u8.32 u8.32) :cost 2 :encoding :fake-vop) + (two-arg-u8.32<= nil (u8.32) (u8.32 u8.32) :cost 2 :encoding :fake-vop) + (u8.32-avg #:vpavgb (u8.32) (u8.32 u8.32) :cost 2) + (u8.32-packus #:vpackuswb (u8.32) (u16.16 u16.16) :cost 2) + (u8.32-unpackhi #:vpunpckhbw (u8.32) (u8.32 u8.32) :cost 1) + (u8.32-unpacklo #:vpunpcklbw (u8.32) (u8.32 u8.32) :cost 1) + (u8.32-movemask #:vpmovmskb (u32) (u8.32) :cost 1) + (u8.32-shuffle #:vpshufb (u8.32) (u8.32 u8.32) :cost 1) + (u8.32-insert-u8.16 #:vinserti128 (u8.32) (u8.32 u8.16 imm8) :cost 1) + (u8.16-from-u8.32 #:vextracti128 (u8.16) (u8.32 imm1) :cost 1) + (u8.32-permute128 #:vperm2i128 (u8.32) (u8.32 u8.32 imm8) :cost 1) + ;; u16.16 + (make-u16.16 nil (u16.16) (u16 u16 u16 u16 u16 u16 u16 u16 u16 u16 u16 u16 u16 u16 u16 u16) :cost 1 :encoding :fake-vop) + (u16.16-values nil (u16 u16 u16 u16 u16 u16 u16 u16 u16 u16 u16 u16 u16 u16 u16 u16) (u16.16) :cost 1 :encoding :fake-vop) + (u16.16-broadcast nil (u16.16) (u16) :cost 1 :encoding :fake-vop) + (u16.16-broadcastvec #:vpbroadcastw (u16.16) (u16.16) :cost 1) + (u16.16-blend #:vpblendvb (u16.16) (u16.16 u16.16 u16.16) :cost 1) + (u16.16-from-u8.16 #:vpmovzxbw (u16.16) (u8.16) :cost 5) + (two-arg-u16.16-and #:vpand (u16.16) (u16.16 u16.16) :cost 1 :associative t) + (two-arg-u16.16-or #:vpor (u16.16) (u16.16 u16.16) :cost 1 :associative t) + (two-arg-u16.16-xor #:vpxor (u16.16) (u16.16 u16.16) :cost 1 :associative t) + (u16.16-andc1 #:vpandn (u16.16) (u16.16 u16.16) :cost 1) + (u16.16-not nil (u16.16) (u16.16) :cost 1 :encoding :fake-vop) + (two-arg-u16.16-max #:vpmaxuw (u16.16) (u16.16 u16.16) :cost 2 :associative t) + (two-arg-u16.16-min #:vpminuw (u16.16) (u16.16 u16.16) :cost 2 :associative t) + (two-arg-u16.16+ #:vpaddw (u16.16) (u16.16 u16.16) :cost 2 :associative t) + (two-arg-u16.16- #:vpsubw (u16.16) (u16.16 u16.16) :cost 2) + (two-arg-u16.16= #:vpcmpeqw (u16.16) (u16.16 u16.16) :cost 1 :associative t) + (two-arg-u16.16/= nil (u16.16) (u16.16 u16.16) :cost 2 :associative t :encoding :fake-vop) + (two-arg-u16.16>~ #:vpcmpgtw (u16.16) (u16.16 u16.16) :cost 1) + (two-arg-u16.16> nil (u16.16) (u16.16 u16.16) :cost 1 :encoding :fake-vop) + (two-arg-u16.16< nil (u16.16) (u16.16 u16.16) :cost 1 :encoding :fake-vop) + (two-arg-u16.16>= nil (u16.16) (u16.16 u16.16) :cost 2 :encoding :fake-vop) + (two-arg-u16.16<= nil (u16.16) (u16.16 u16.16) :cost 2 :encoding :fake-vop) + (u16.16-shiftl #:vpsllw (u16.16) (u16.16 u16.8) :cost 2) + (u16.16-shiftr #:vpsrlw (u16.16) (u16.16 u16.8) :cost 2) + (u16.16-avg #:vpavgw (u16.16) (u16.16 u16.16) :cost 1) + (u16.16-packus #:vpackusdw (u16.16) (u32.8 u32.8) :cost 1) + (u16.16-unpackhi #:vpunpckhwd (u16.16) (u16.16 u16.16) :cost 1) + (u16.16-unpacklo #:vpunpcklwd (u16.16) (u16.16 u16.16) :cost 1) + (u16.16-movemask nil (u16) (u16.16) :cost 1 :encoding :fake-vop) + (u16.16-shufflehi #:vpshufhw (u16.16) (u16.16 imm8) :cost 1) + (u16.16-shufflelo #:vpshuflw (u16.16) (u16.16 imm8) :cost 1) + (u16.8-from-u16.16 #:vextracti128 (u16.8) (u16.16 imm1) :cost 1) + (u16.16-insert-u16.8 #:vinserti128 (u16.16) (u16.16 u16.8 imm1) :cost 1) + (u16.16-permute128 #:vperm2i128 (u16.16) (u16.16 u16.16 imm8) :cost 1) + ;; u32.8 + (make-u32.8 nil (u32.8) (u32 u32 u32 u32 u32 u32 u32 u32) :cost 1 :encoding :fake-vop) + (u32.8-values nil (u32 u32 u32 u32 u32 u32 u32 u32) (u32.8) :cost 1 :encoding :fake-vop) + (u32.8-broadcast nil (u32.8) (u32) :cost 1 :encoding :fake-vop) + (u32.8-broadcastvec #:vpbroadcastd (u32.8) (u32.8) :cost 1) + (u32.8-blend #:vpblendvb (u32.8) (u32.8 u32.8 u32.8) :cost 1) + (u32.8-from-u16.8 #:vpmovzxwd (u32.8) (u16.8) :cost 5) + (u32.8-from-u8.16 #:vpmovzxbd (u32.8) (u8.16) :cost 5) + (two-arg-u32.8-and #:vpand (u32.8) (u32.8 u32.8) :cost 1 :associative t) + (two-arg-u32.8-or #:vpor (u32.8) (u32.8 u32.8) :cost 1 :associative t) + (two-arg-u32.8-xor #:vpxor (u32.8) (u32.8 u32.8) :cost 1 :associative t) + (u32.8-andc1 #:vpandn (u32.8) (u32.8 u32.8) :cost 1) + (u32.8-not nil (u32.8) (u32.8) :cost 1 :encoding :fake-vop) + (two-arg-u32.8-max #:vpmaxud (u32.8) (u32.8 u32.8) :cost 2 :associative t) + (two-arg-u32.8-min #:vpminud (u32.8) (u32.8 u32.8) :cost 2 :associative t) + (two-arg-u32.8+ #:vpaddd (u32.8) (u32.8 u32.8) :cost 2 :associative t) + (two-arg-u32.8- #:vpsubd (u32.8) (u32.8 u32.8) :cost 2) + (two-arg-u32.8= #:vpcmpeqd (u32.8) (u32.8 u32.8) :cost 1 :associative t) + (two-arg-u32.8/= nil (u32.8) (u32.8 u32.8) :cost 2 :associative t :encoding :fake-vop) + (two-arg-u32.8>~ #:vpcmpgtd (u32.8) (u32.8 u32.8) :cost 1) + (two-arg-u32.8> nil (u32.8) (u32.8 u32.8) :cost 1 :encoding :fake-vop) + (two-arg-u32.8< nil (u32.8) (u32.8 u32.8) :cost 1 :encoding :fake-vop) + (two-arg-u32.8>= nil (u32.8) (u32.8 u32.8) :cost 2 :encoding :fake-vop) + (two-arg-u32.8<= nil (u32.8) (u32.8 u32.8) :cost 2 :encoding :fake-vop) + (u32.8-shiftl #:vpsllvd (u32.8) (u32.8 u32.8) :cost 1) + (u32.8-shiftr #:vpsrlvd (u32.8) (u32.8 u32.8) :cost 1) + (u32.8-unpackhi #:vpunpckhdq (u32.8) (u32.8 u32.8) :cost 1) + (u32.8-unpacklo #:vpunpckldq (u32.8) (u32.8 u32.8) :cost 1) + (u32.8-movemask #:vmovmskps (u8) (u32.8) :cost 1) + (u32.4-from-u32.8 #:vextracti128 (u32.4) (u32.8 imm1) :cost 1) + (u32.8-insert-u32.4 #:vinserti128 (u32.8) (u32.8 u32.4 imm1) :cost 1) + (u32.8-permute128 #:vperm2i128 (u32.8) (u32.8 u32.8 imm8) :cost 1) + ;; u64.4 + (make-u64.4 nil (u64.4) (u64 u64 u64 u64) :cost 1 :encoding :fake-vop) + (u64.4-values nil (u64 u64 u64 u64) (u64.4) :cost 1 :encoding :fake-vop) + (u64.4-broadcast nil (u64.4) (u64) :cost 1 :encoding :fake-vop) + (u64.4-broadcastvec #:vpbroadcastq (u64.4) (u64.4) :cost 1) + (u64.4-blend #:vpblendvb (u64.4) (u64.4 u64.4 u64.4) :cost 1) + (u64.4-from-u16.8 #:vpmovzxwq (u64.4) (u16.8) :cost 5) + (u64.4-from-u32.4 #:vpmovzxdq (u64.4) (u32.4) :cost 5) + (u64.4-from-u8.16 #:vpmovzxbq (u64.4) (u8.16) :cost 5) + (two-arg-u64.4-and #:vpand (u64.4) (u64.4 u64.4) :cost 1 :associative t) + (two-arg-u64.4-or #:vpor (u64.4) (u64.4 u64.4) :cost 1 :associative t) + (two-arg-u64.4-xor #:vpxor (u64.4) (u64.4 u64.4) :cost 1 :associative t) + (u64.4-andc1 #:vpandn (u64.4) (u64.4 u64.4) :cost 1) + (u64.4-not nil (u64.4) (u64.4) :cost 1 :encoding :fake-vop) + (two-arg-u64.4+ #:vpaddq (u64.4) (u64.4 u64.4) :cost 2 :associative t) + (two-arg-u64.4- #:vpsubq (u64.4) (u64.4 u64.4) :cost 2) + (two-arg-u64.4-mul #:vpmuludq (u64.4) (u64.4 u64.4) :cost 1 :associative t) + (two-arg-u64.4= #:vpcmpeqq (u64.4) (u64.4 u64.4) :cost 1 :associative t) + (two-arg-u64.4/= nil (u64.4) (u64.4 u64.4) :cost 2 :associative t :encoding :fake-vop) + (two-arg-u64.4>~ #:vpcmpgtq (u64.4) (u64.4 u64.4) :cost 1) + (two-arg-u64.4> nil (u64.4) (u64.4 u64.4) :cost 1 :encoding :fake-vop) + (two-arg-u64.4< nil (u64.4) (u64.4 u64.4) :cost 1 :encoding :fake-vop) + (two-arg-u64.4>= nil (u64.4) (u64.4 u64.4) :cost 2 :encoding :fake-vop) + (two-arg-u64.4<= nil (u64.4) (u64.4 u64.4) :cost 2 :encoding :fake-vop) + (u64.4-shiftl #:vpsllvq (u64.4) (u64.4 u64.4) :cost 1) + (u64.4-shiftr #:vpsrlvq (u64.4) (u64.4 u64.4) :cost 1) + (u64.4-unpackhi #:vpunpckhqdq (u64.4) (u64.4 u64.4) :cost 1) + (u64.4-unpacklo #:vpunpcklqdq (u64.4) (u64.4 u64.4) :cost 1) + (u64.4-movemask #:vmovmskpd (u4) (u64.4) :cost 1) + (u64.2-from-u64.4 #:vextracti128 (u64.2) (u64.4 imm1) :cost 1) + (u64.4-insert-u64.2 #:vinserti128 (u64.4) (u64.4 u64.2 imm1) :cost 1) + (u64.4-permute128 #:vperm2i128 (u64.4) (u64.4 u64.4 imm8) :cost 1) + ;; s8.32 + (make-s8.32 nil (s8.32) (s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8) :cost 1 :encoding :fake-vop) + (s8.32-values nil (s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8) (s8.32) :cost 1 :encoding :fake-vop) + (s8.32-broadcast nil (s8.32) (s8) :cost 1 :encoding :fake-vop) + (s8.32-broadcastvec #:vpbroadcastb (s8.32) (s8.32) :cost 1) + (s8.32-blend #:vpblendvb (s8.32) (s8.32 s8.32 u8.32) :cost 1) + (two-arg-s8.32-and #:vpand (s8.32) (s8.32 s8.32) :cost 1 :associative t) + (two-arg-s8.32-or #:vpor (s8.32) (s8.32 s8.32) :cost 1 :associative t) + (two-arg-s8.32-xor #:vpxor (s8.32) (s8.32 s8.32) :cost 1 :associative t) + (s8.32-andc1 #:vpandn (s8.32) (s8.32 s8.32) :cost 1) + (s8.32-not nil (s8.32) (s8.32) :cost 1 :encoding :fake-vop) + (two-arg-s8.32-max #:vpmaxsb (s8.32) (s8.32 s8.32) :cost 2 :associative t) + (two-arg-s8.32-min #:vpminsb (s8.32) (s8.32 s8.32) :cost 2 :associative t) + (two-arg-s8.32+ #:vpaddb (s8.32) (s8.32 s8.32) :cost 2 :associative t) + (two-arg-s8.32- #:vpsubb (s8.32) (s8.32 s8.32) :cost 2) + (two-arg-s8.32= #:vpcmpeqb (u8.32) (s8.32 s8.32) :cost 1 :associative t) + (two-arg-s8.32/= nil (u8.32) (s8.32 s8.32) :cost 2 :associative t :encoding :fake-vop) + (two-arg-s8.32> #:vpcmpgtb (u8.32) (s8.32 s8.32) :cost 1) + (two-arg-s8.32< nil (u8.32) (s8.32 s8.32) :cost 1 :encoding :fake-vop) + (two-arg-s8.32>= nil (u8.32) (s8.32 s8.32) :cost 2 :encoding :fake-vop) + (two-arg-s8.32<= nil (u8.32) (s8.32 s8.32) :cost 2 :encoding :fake-vop) + (s8.32-abs #:vpabsb (s8.32) (s8.32) :cost 2) + (s8.32-packs #:vpacksswb (s8.32) (s16.16 s16.16) :cost 2) + (s8.32-unpackhi #:vpunpckhbw (s8.32) (s8.32 s8.32) :cost 1) + (s8.32-unpacklo #:vpunpcklbw (s8.32) (s8.32 s8.32) :cost 1) + (s8.32-movemask #:vpmovmskb (u32) (s8.32) :cost 1) + (s8.32-shuffle #:vpshufb (s8.32) (s8.32 u8.32) :cost 1) + (s8.32-sign #:vpsignb (s8.32) (s8.32 s8.32) :cost 1) + (s8.32-broadcastvec #:vpbroadcastb (s8.32) (s8.32) :cost 1) + (s8.16-from-s8.32 #:vextracti128 (s8.16) (s8.32 imm1) :cost 1) + (s8.32-insert-s8.16 #:vinserti128 (s8.32) (s8.32 s8.16 imm1) :cost 1) + (s8.32-permute128 #:vperm2i128 (s8.32) (s8.32 s8.32 imm8) :cost 1) + ;; s16.16 + (make-s16.16 nil (s16.16) (s16 s16 s16 s16 s16 s16 s16 s16 s16 s16 s16 s16 s16 s16 s16 s16) :cost 1 :encoding :fake-vop) + (s16.16-values nil (s16 s16 s16 s16 s16 s16 s16 s16 s16 s16 s16 s16 s16 s16 s16 s16) (s16.16) :cost 1 :encoding :fake-vop) + (s16.16-broadcast nil (s16.16) (s16) :cost 1 :encoding :fake-vop) + (s16.16-broadcastvec #:vpbroadcastw (s16.16) (s16.16) :cost 1) + (s16.16-blend #:vpblendvb (s16.16) (s16.16 s16.16 u16.16) :cost 1) + (s16.16-from-s8.16 #:vpmovsxbw (s16.16) (s8.16) :cost 5) + (s16.16-from-u8.16 #:vpmovsxbw (s16.16) (u8.16) :cost 5) + (two-arg-s16.16-and #:vpand (s16.16) (s16.16 s16.16) :cost 1 :associative t) + (two-arg-s16.16-or #:vpor (s16.16) (s16.16 s16.16) :cost 1 :associative t) + (two-arg-s16.16-xor #:vpxor (s16.16) (s16.16 s16.16) :cost 1 :associative t) + (s16.16-andc1 #:vpandn (s16.16) (s16.16 s16.16) :cost 1) + (s16.16-not nil (s16.16) (s16.16) :cost 1 :encoding :fake-vop) + (two-arg-s16.16-max #:vpmaxsw (s16.16) (s16.16 s16.16) :cost 2 :associative t) + (two-arg-s16.16-min #:vpminsw (s16.16) (s16.16 s16.16) :cost 2 :associative t) + (two-arg-s16.16+ #:vpaddw (s16.16) (s16.16 s16.16) :cost 2 :associative t) + (two-arg-s16.16- #:vpsubw (s16.16) (s16.16 s16.16) :cost 2) + (two-arg-s16.16-mulhi #:vpmulhw (s16.16) (s16.16 s16.16) :cost 1 :associative t) + (two-arg-s16.16-mullo #:vpmullw (s16.16) (s16.16 s16.16) :cost 1 :associative t) + (two-arg-s16.16-mulhrs #:vpmulhrsw (s16.16) (s16.16 s16.16) :cost 1 :associative t) + (two-arg-s16.16= #:vpcmpeqw (u16.16) (s16.16 s16.16) :cost 1 :associative t) + (two-arg-s16.16/= nil (u16.16) (s16.16 s16.16) :cost 2 :associative t :encoding :fake-vop) + (two-arg-s16.16> #:vpcmpgtw (u16.16) (s16.16 s16.16) :cost 1) + (two-arg-s16.16< nil (u16.16) (s16.16 s16.16) :cost 1 :encoding :fake-vop) + (two-arg-s16.16>= nil (u16.16) (s16.16 s16.16) :cost 2 :encoding :fake-vop) + (two-arg-s16.16<= nil (u16.16) (s16.16 s16.16) :cost 2 :encoding :fake-vop) + (s16.16-abs #:vpabsw (s16.16) (s16.16) :cost 2) + (s16.16-hadd #:vphaddw (s16.16) (s16.16 s16.16) :cost 2) + (s16.16-hadds #:vphaddsw (s16.16) (s16.16 s16.16) :cost 2) + (s16.16-madd #:vpmaddwd (s16.16) (s16.16 s16.16) :cost 2) + (s16.16-maddubs #:vpmaddubsw (s16.16) (u8.32 s8.32) :cost 2) + (s16.16-hsub #:vphsubw (s16.16) (s16.16 s16.16) :cost 2) + (s16.16-hsubs #:vphsubsw (s16.16) (s16.16 s16.16) :cost 2) + (s16.16-packs #:vpackssdw (s16.16) (s32.8 s32.8) :cost 1) + (s16.16-unpackhi #:vpunpckhwd (s16.16) (s16.16 s16.16) :cost 1) + (s16.16-unpacklo #:vpunpcklwd (s16.16) (s16.16 s16.16) :cost 1) + (s16.16-movemask nil (u16) (s16.16) :cost 1 :encoding :fake-vop) + (s16.16-shufflehi #:vpshufhw (s16.16) (s16.16 imm8) :cost 1) + (s16.16-shufflelo #:vpshuflw (s16.16) (s16.16 imm8) :cost 1) + (s16.16-shiftl #:vpsllw (s16.16) (s16.16 s16.8) :cost 2) + (s16.16-shiftr #:vpsrlw (s16.16) (s16.16 s16.8) :cost 2) + (s16.16-sign #:vpsignw (s16.16) (s16.16 s16.16) :cost 2) + (s16.8-from-s16.16 #:vextracti128 (s16.8) (s16.16 imm1) :cost 1) + (s16.16-insert-s16.8 #:vinserti128 (s16.16) (s16.16 s16.8 imm1) :cost 1) + (s16.16-permute128 #:vperm2i128 (s16.16) (s16.16 s16.16 imm8) :cost 1) + ;; s32.8 + (make-s32.8 nil (s32.8) (s32 s32 s32 s32 s32 s32 s32 s32) :cost 1 :encoding :fake-vop) + (s32.8-values nil (s32 s32 s32 s32 s32 s32 s32 s32) (s32.8) :cost 1 :encoding :fake-vop) + (s32.8-broadcast nil (s32.8) (s32) :cost 1 :encoding :fake-vop) + (s32.8-broadcastvec #:vpbroadcastd (s32.8) (s32.8) :cost 1) + (s32.8-blend #:vpblendvb (s32.8) (s32.8 s32.8 u32.8) :cost 1) + (s32.8-from-s16.8 #:vpmovsxwd (s32.8) (s16.8) :cost 5) + (s32.8-from-u16.8 #:vpmovsxwd (s32.8) (u16.8) :cost 5) + (s32.8-from-s8.16 #:vpmovsxbd (s32.8) (s8.16) :cost 5) + (s32.8-from-u8.16 #:vpmovsxbd (s32.8) (u8.16) :cost 5) + (two-arg-s32.8-and #:vpand (s32.8) (s32.8 s32.8) :cost 1 :associative t) + (two-arg-s32.8-or #:vpor (s32.8) (s32.8 s32.8) :cost 1 :associative t) + (two-arg-s32.8-xor #:vpxor (s32.8) (s32.8 s32.8) :cost 1 :associative t) + (s32.8-andc1 #:vpandn (s32.8) (s32.8 s32.8) :cost 1) + (s32.8-not nil (s32.8) (s32.8) :cost 1 :encoding :fake-vop) + (two-arg-s32.8-max #:vpmaxsd (s32.8) (s32.8 s32.8) :cost 2 :associative t) + (two-arg-s32.8-min #:vpminsd (s32.8) (s32.8 s32.8) :cost 2 :associative t) + (two-arg-s32.8+ #:vpaddd (s32.8) (s32.8 s32.8) :cost 2 :associative t) + (two-arg-s32.8- #:vpsubd (s32.8) (s32.8 s32.8) :cost 2) + (two-arg-s32.8-mullo #:vpmulld (s32.8) (s32.8 s32.8) :cost 2 :associative t) + (two-arg-s32.8= #:vpcmpeqd (u32.8) (s32.8 s32.8) :cost 1 :associative t) + (two-arg-s32.8/= nil (u32.8) (s32.8 s32.8) :cost 2 :associative t :encoding :fake-vop) + (two-arg-s32.8> #:vpcmpgtd (u32.8) (s32.8 s32.8) :cost 1) + (two-arg-s32.8< nil (u32.8) (s32.8 s32.8) :cost 1 :encoding :fake-vop) + (two-arg-s32.8>= nil (u32.8) (s32.8 s32.8) :cost 2 :encoding :fake-vop) + (two-arg-s32.8<= nil (u32.8) (s32.8 s32.8) :cost 2 :encoding :fake-vop) + (s32.8-abs #:vpabsd (s32.8) (s32.8) :cost 2) + (s32.8-hadd #:vphaddd (s32.8) (s32.8 s32.8) :cost 1) + (s32.8-hsub #:vphsubd (s32.8) (s32.8 s32.8) :cost 1) + (s32.8-shiftl #:vpsllvd (s32.8) (s32.8 s32.8) :cost 1) + (s32.8-shiftr #:vpsrlvd (s32.8) (s32.8 s32.8) :cost 1) + (s32.8-unpackhi #:vpunpckhdq (s32.8) (s32.8 s32.8) :cost 1) + (s32.8-unpacklo #:vpunpckldq (s32.8) (s32.8 s32.8) :cost 1) + (s32.8-movemask #:vmovmskps (u8) (s32.8) :cost 1) + (s32.8-sign #:vpsignd (s32.8) (s32.8 s32.8) :cost 1) + (s32.4-from-s32.8 #:vextracti128 (s32.4) (s32.8 imm1) :cost 1) + (s32.8-insert-s32.4 #:vinserti128 (s32.8) (s32.8 s32.4 imm1) :cost 1) + (s32.8-permute128 #:vperm2i128 (s32.8) (s32.8 s32.8 imm8) :cost 1) + ;; s64.4 + (make-s64.4 nil (s64.4) (s64 s64 s64 s64) :cost 1 :encoding :fake-vop) + (s64.4-values nil (s64 s64 s64 s64) (s64.4) :cost 1 :encoding :fake-vop) + (s64.4-broadcast nil (s64.4) (s64) :cost 1 :encoding :fake-vop) + (s64.4-broadcastvec #:vpbroadcastq (s64.4) (s64.4) :cost 1) + (s64.4-blend #:vpblendvb (s64.4) (s64.4 s64.4 u64.4) :cost 1) + (s64.4-from-s16.8 #:vpmovsxwq (s64.4) (s16.8) :cost 5) + (s64.4-from-u16.8 #:vpmovsxwq (s64.4) (u16.8) :cost 5) + (s64.4-from-s32.4 #:vpmovsxdq (s64.4) (s32.4) :cost 5) + (s64.4-from-u32.4 #:vpmovsxdq (s64.4) (u32.4) :cost 5) + (s64.4-from-s8.16 #:vpmovsxbq (s64.4) (s8.16) :cost 5) + (s64.4-from-u8.16 #:vpmovsxbq (s64.4) (u8.16) :cost 5) + (two-arg-s64.4-and #:vpand (s64.4) (s64.4 s64.4) :cost 1 :associative t) + (two-arg-s64.4-or #:vpor (s64.4) (s64.4 s64.4) :cost 1 :associative t) + (two-arg-s64.4-xor #:vpxor (s64.4) (s64.4 s64.4) :cost 1 :associative t) + (s64.4-andc1 #:vandnpd (s64.4) (s64.4 s64.4) :cost 1) + (s64.4-not nil (s64.4) (s64.4) :cost 1 :encoding :fake-vop) + (two-arg-s64.4+ #:vpaddq (s64.4) (s64.4 s64.4) :cost 1 :associative t) + (two-arg-s64.4- #:vpsubq (s64.4) (s64.4 s64.4) :cost 1) + (two-arg-s64.4-mul #:vpmuldq (s64.4) (s64.4 s64.4) :cost 1 :associative t) + (two-arg-s64.4= #:vpcmpeqq (u64.4) (s64.4 s64.4) :cost 1 :associative t) + (two-arg-s64.4/= nil (u64.4) (s64.4 s64.4) :cost 2 :associative t :encoding :fake-vop) + (two-arg-s64.4> #:vpcmpgtq (u64.4) (s64.4 s64.4) :cost 1) + (two-arg-s64.4< nil (u64.4) (s64.4 s64.4) :cost 1 :encoding :fake-vop) + (two-arg-s64.4>= nil (u64.4) (s64.4 s64.4) :cost 2 :encoding :fake-vop) + (two-arg-s64.4<= nil (u64.4) (s64.4 s64.4) :cost 2 :encoding :fake-vop) + (s64.4-shiftl #:vpsllvq (s64.4) (s64.4 s64.4) :cost 1) + (s64.4-shiftr #:vpsrlvq (s64.4) (s64.4 s64.4) :cost 1) + (s64.4-unpackhi #:vpunpckhqdq (s64.4) (s64.4 s64.4) :cost 1) + (s64.4-unpacklo #:vpunpcklqdq (s64.4) (s64.4 s64.4) :cost 1) + (s64.4-movemask #:vmovmskpd (u4) (s64.4) :cost 1) + (s64.2-from-s64.4 #:vextracti128 (s64.2) (s64.4 imm1) :cost 1) + (s64.4-insert-s64.2 #:vinserti128 (s64.4) (s64.4 s64.2 imm1) :cost 1) + (s64.4-permute128 #:vperm2i128 (s64.4) (s64.4 s64.4 imm8) :cost 1)) + (:loads + (f32.4-ntload #:vmovntdqa f32.4 f32vec f32-array f32.4-non-temporal-aref f32.4-non-temporal-row-major-aref) + (f64.2-ntload #:vmovntdqa f64.2 f64vec f64-array f64.2-non-temporal-aref f64.2-non-temporal-row-major-aref) + (f32.8-ntload #:vmovntdqa f32.8 f32vec f32-array f32.8-non-temporal-aref f32.8-non-temporal-row-major-aref) + (f64.4-ntload #:vmovntdqa f64.4 f64vec f64-array f64.4-non-temporal-aref f64.4-non-temporal-row-major-aref) + (u8.16-ntload #:vmovntdqa u8.16 u8vec u8-array u8.16-non-temporal-aref u8.16-non-temporal-row-major-aref) + (u16.8-ntload #:vmovntdqa u16.8 u16vec u16-array u16.8-non-temporal-aref u16.8-non-temporal-row-major-aref) + (u32.4-ntload #:vmovntdqa u32.4 u32vec u32-array u32.4-non-temporal-aref u32.4-non-temporal-row-major-aref) + (u64.2-ntload #:vmovntdqa u64.2 u64vec u64-array u64.2-non-temporal-aref u64.2-non-temporal-row-major-aref) + (s8.16-ntload #:vmovntdqa s8.16 s8vec s8-array s8.16-non-temporal-aref s8.16-non-temporal-row-major-aref) + (s16.8-ntload #:vmovntdqa s16.8 s16vec s16-array s16.8-non-temporal-aref s16.8-non-temporal-row-major-aref) + (s32.4-ntload #:vmovntdqa s32.4 s32vec s32-array s32.4-non-temporal-aref s32.4-non-temporal-row-major-aref) + (s64.2-ntload #:vmovntdqa s64.2 s64vec s64-array s64.2-non-temporal-aref s64.2-non-temporal-row-major-aref) + (u8.32-ntload #:vmovntdqa u8.32 u8vec u8-array u8.32-non-temporal-aref u8.32-non-temporal-row-major-aref) + (u16.16-ntload #:vmovntdqa u16.16 u16vec u16-array u16.16-non-temporal-aref u16.16-non-temporal-row-major-aref) + (u32.8-ntload #:vmovntdqa u32.8 u32vec u32-array u32.8-non-temporal-aref u32.8-non-temporal-row-major-aref) + (u64.4-ntload #:vmovntdqa u64.4 u64vec u64-array u64.4-non-temporal-aref u64.4-non-temporal-row-major-aref) + (s8.32-ntload #:vmovntdqa s8.32 s8vec s8-array s8.32-non-temporal-aref s8.32-non-temporal-row-major-aref) + (s16.16-ntload #:vmovntdqa s16.16 s16vec s16-array s16.16-non-temporal-aref s16.16-non-temporal-row-major-aref) + (s32.8-ntload #:vmovntdqa s32.8 s32vec s32-array s32.8-non-temporal-aref s32.8-non-temporal-row-major-aref) + (s64.4-ntload #:vmovntdqa s64.4 s64vec s64-array s64.4-non-temporal-aref s64.4-non-temporal-row-major-aref)) + (:stores + (f32.4-ntstore #:vmovntps f32.4 f32vec f32-array f32.4-non-temporal-aref f32.4-non-temporal-row-major-aref) + (f64.2-ntstore #:vmovntpd f64.2 f64vec f64-array f64.2-non-temporal-aref f64.2-non-temporal-row-major-aref) + (f32.8-ntstore #:vmovntps f32.8 f32vec f32-array f32.8-non-temporal-aref f32.8-non-temporal-row-major-aref) + (f64.4-ntstore #:vmovntpd f64.4 f64vec f64-array f64.4-non-temporal-aref f64.4-non-temporal-row-major-aref) + (u8.16-ntstore #:vmovntdq u8.16 u8vec u8-array u8.16-non-temporal-aref u8.16-non-temporal-row-major-aref) + (u16.8-ntstore #:vmovntdq u16.8 u16vec u16-array u16.8-non-temporal-aref u16.8-non-temporal-row-major-aref) + (u32.4-ntstore #:vmovntdq u32.4 u32vec u32-array u32.4-non-temporal-aref u32.4-non-temporal-row-major-aref) + (u64.2-ntstore #:vmovntdq u64.2 u64vec u64-array u64.2-non-temporal-aref u64.2-non-temporal-row-major-aref) + (s8.16-ntstore #:vmovntdq s8.16 s8vec s8-array s8.16-non-temporal-aref s8.16-non-temporal-row-major-aref) + (s16.8-ntstore #:vmovntdq s16.8 s16vec s16-array s16.8-non-temporal-aref s16.8-non-temporal-row-major-aref) + (s32.4-ntstore #:vmovntdq s32.4 s32vec s32-array s32.4-non-temporal-aref s32.4-non-temporal-row-major-aref) + (s64.2-ntstore #:vmovntdq s64.2 s64vec s64-array s64.2-non-temporal-aref s64.2-non-temporal-row-major-aref) + (u8.32-ntstore #:vmovntdq u8.32 u8vec u8-array u8.32-non-temporal-aref u8.32-non-temporal-row-major-aref) + (u16.16-ntstore #:vmovntdq u16.16 u16vec u16-array u16.16-non-temporal-aref u16.16-non-temporal-row-major-aref) + (u32.8-ntstore #:vmovntdq u32.8 u32vec u32-array u32.8-non-temporal-aref u32.8-non-temporal-row-major-aref) + (u64.4-ntstore #:vmovntdq u64.4 u64vec u64-array u64.4-non-temporal-aref u64.4-non-temporal-row-major-aref) + (s8.32-ntstore #:vmovntdq s8.32 s8vec s8-array s8.32-non-temporal-aref s8.32-non-temporal-row-major-aref) + (s16.16-ntstore #:vmovntdq s16.16 s16vec s16-array s16.16-non-temporal-aref s16.16-non-temporal-row-major-aref) + (s32.8-ntstore #:vmovntdq s32.8 s32vec s32-array s32.8-non-temporal-aref s32.8-non-temporal-row-major-aref) + (s64.4-ntstore #:vmovntdq s64.4 s64vec s64-array s64.4-non-temporal-aref s64.4-non-temporal-row-major-aref)) + (:associatives + (u8.32-and two-arg-u8.32-and +u8-true+) + (u8.32-or two-arg-u8.32-or +u8-false+) + (u8.32-xor two-arg-u8.32-xor +u8-false+) + (u8.32-max two-arg-u8.32-max nil) + (u8.32-min two-arg-u8.32-min nil) + (u8.32+ two-arg-u8.32+ 0) + (u16.16-and two-arg-u16.16-and +u16-true+) + (u16.16-or two-arg-u16.16-or +u16-false+) + (u16.16-xor two-arg-u16.16-xor +u16-false+) + (u16.16-max two-arg-u16.16-max nil) + (u16.16-min two-arg-u16.16-min nil) + (u16.16+ two-arg-u16.16+ 0) + (u32.8-and two-arg-u32.8-and +u32-true+) + (u32.8-or two-arg-u32.8-or +u32-false+) + (u32.8-xor two-arg-u32.8-xor +u32-false+) + (u32.8-max two-arg-u32.8-max nil) + (u32.8-min two-arg-u32.8-min nil) + (u32.8+ two-arg-u32.8+ 0) + (u64.4-and two-arg-u64.4-and +u64-true+) + (u64.4-or two-arg-u64.4-or +u64-false+) + (u64.4-xor two-arg-u64.4-xor +u64-false+) + (u64.4+ two-arg-u64.4+ 0) + (u64.4-mul two-arg-u64.4-mul 1) + (s8.32-and two-arg-s8.32-and +s8-true+) + (s8.32-or two-arg-s8.32-or +s8-false+) + (s8.32-xor two-arg-s8.32-xor +s8-false+) + (s8.32-max two-arg-s8.32-max nil) + (s8.32-min two-arg-s8.32-min nil) + (s8.32+ two-arg-s8.32+ 0) + (s16.16-and two-arg-s16.16-and +s16-true+) + (s16.16-or two-arg-s16.16-or +s16-false+) + (s16.16-xor two-arg-s16.16-xor +s16-false+) + (s16.16-max two-arg-s16.16-max nil) + (s16.16-min two-arg-s16.16-min nil) + (s16.16+ two-arg-s16.16+ 0) + (s16.16-mulhi two-arg-s16.16-mulhi 1) + (s16.16-mullo two-arg-s16.16-mullo 1) + (s16.16-mulhrs two-arg-s16.16-mulhrs 1) + (s32.8-and two-arg-s32.8-and +s32-true+) + (s32.8-or two-arg-s32.8-or +s32-false+) + (s32.8-xor two-arg-s32.8-xor +s32-false+) + (s32.8-max two-arg-s32.8-max nil) + (s32.8-min two-arg-s32.8-min nil) + (s32.8+ two-arg-s32.8+ 0) + (s32.8-mullo two-arg-s32.8-mullo 1) + (s64.4-and two-arg-s64.4-and +s64-true+) + (s64.4-or two-arg-s64.4-or +s64-false+) + (s64.4-xor two-arg-s64.4-xor +s64-false+) + (s64.4+ two-arg-s64.4+ 0) + (s64.4-mul two-arg-s64.4-mul 1)) + (:comparisons + (u8.32= two-arg-u8.32= u8.32-and +u8-true+) + (u8.32< two-arg-u8.32< u8.32-and +u8-true+) + (u8.32<= two-arg-u8.32<= u8.32-and +u8-true+) + (u8.32> two-arg-u8.32> u8.32-and +u8-true+) + (u8.32>= two-arg-u8.32>= u8.32-and +u8-true+) + (u16.16= two-arg-u16.16= u16.16-and +u16-true+) + (u16.16< two-arg-u16.16< u16.16-and +u16-true+) + (u16.16<= two-arg-u16.16<= u16.16-and +u16-true+) + (u16.16> two-arg-u16.16> u16.16-and +u16-true+) + (u16.16>= two-arg-u16.16>= u16.16-and +u16-true+) + (u32.8= two-arg-u32.8= u32.8-and +u32-true+) + (u32.8< two-arg-u32.8< u32.8-and +u32-true+) + (u32.8<= two-arg-u32.8<= u32.8-and +u32-true+) + (u32.8> two-arg-u32.8> u32.8-and +u32-true+) + (u32.8>= two-arg-u32.8>= u32.8-and +u32-true+) + (u64.4= two-arg-u64.4= u64.4-and +u64-true+) + (u64.4< two-arg-u64.4< u64.4-and +u64-true+) + (u64.4<= two-arg-u64.4<= u64.4-and +u64-true+) + (u64.4> two-arg-u64.4> u64.4-and +u64-true+) + (u64.4>= two-arg-u64.4>= u64.4-and +u64-true+) + (s8.32= two-arg-s8.32= u8.32-and +u8-true+) + (s8.32< two-arg-s8.32< u8.32-and +u8-true+) + (s8.32<= two-arg-s8.32<= u8.32-and +u8-true+) + (s8.32> two-arg-s8.32> u8.32-and +u8-true+) + (s8.32>= two-arg-s8.32>= u8.32-and +u8-true+) + (s16.16= two-arg-s16.16= u16.16-and +u16-true+) + (s16.16< two-arg-s16.16< u16.16-and +u16-true+) + (s16.16<= two-arg-s16.16<= u16.16-and +u16-true+) + (s16.16> two-arg-s16.16> u16.16-and +u16-true+) + (s16.16>= two-arg-s16.16>= u16.16-and +u16-true+) + (s32.8= two-arg-s32.8= u32.8-and +u32-true+) + (s32.8< two-arg-s32.8< u32.8-and +u32-true+) + (s32.8<= two-arg-s32.8<= u32.8-and +u32-true+) + (s32.8> two-arg-s32.8> u32.8-and +u32-true+) + (s32.8>= two-arg-s32.8>= u32.8-and +u32-true+) + (s64.4= two-arg-s64.4= u64.4-and +u64-true+) + (s64.4< two-arg-s64.4< u64.4-and +u64-true+) + (s64.4<= two-arg-s64.4<= u64.4-and +u64-true+) + (s64.4> two-arg-s64.4> u64.4-and +u64-true+) + (s64.4>= two-arg-s64.4>= u64.4-and +u64-true+)) + (:ifs + (u8.32-if u8.32-blend) + (u16.16-if u16.16-blend) + (u32.8-if u32.8-blend) + (u64.4-if u64.4-blend) + (s8.32-if s8.32-blend) + (s16.16-if s16.16-blend) + (s32.8-if s32.8-blend) + (s64.4-if s64.4-blend)) + (:reducers + (u8.32- two-arg-u8.32- 0) + (u16.16- two-arg-u16.16- 0) + (u32.8- two-arg-u32.8- 0) + (u64.4- two-arg-u64.4- 0) + (s8.32- two-arg-s8.32- 0) + (s16.16- two-arg-s16.16- 0) + (s32.8- two-arg-s32.8- 0) + (s64.4- two-arg-s64.4- 0)) + (:unequals + (u8.32/= two-arg-u8.32/= u8.32-and +u8-true+) + (u16.16/= two-arg-u16.16/= u16.16-and +u16-true+) + (u32.8/= two-arg-u32.8/= u32.8-and +u32-true+) + (u64.4/= two-arg-u64.4/= u64.4-and +u64-true+) + (s8.32/= two-arg-s8.32/= u8.32-and +u8-true+) + (s16.16/= two-arg-s16.16/= u16.16-and +u16-true+) + (s32.8/= two-arg-s32.8/= u32.8-and +u32-true+) + (s64.4/= two-arg-s64.4/= u64.4-and +u64-true+))) diff --git a/contrib/sb-simd/code/instruction-sets/fma.lisp b/contrib/sb-simd/code/instruction-sets/fma.lisp new file mode 100644 index 0000000000..cbeeaed24c --- /dev/null +++ b/contrib/sb-simd/code/instruction-sets/fma.lisp @@ -0,0 +1,38 @@ +(in-package #:sb-simd-fma) + +(define-instruction-set :fma + (:test (fma-supported-p)) + (:include :avx2) + (:instructions + ;; f32 + (f32-fmadd #:vfmadd213ss (f32) (f32 f32 f32) :cost 1 :encoding :fma) + (f32-fnmadd #:vfnmadd213ss (f32) (f32 f32 f32) :cost 1 :encoding :fma) + (f32-fmsub #:vfmsub213ss (f32) (f32 f32 f32) :cost 1 :encoding :fma) + ;; f64 + (f64-fmadd #:vfmadd213sd (f64) (f64 f64 f64) :cost 1 :encoding :fma) + (f64-fnmadd #:vfnmadd213sd (f64) (f64 f64 f64) :cost 1 :encoding :fma) + (f64-fmsub #:vfmsub213sd (f64) (f64 f64 f64) :cost 1 :encoding :fma) + ;; f32.4 + (f32.4-fmadd #:vfmadd213ps (f32.4) (f32.4 f32.4 f32.4) :cost 1 :encoding :fma) + (f32.4-fnmadd #:vfnmadd213ps (f32.4) (f32.4 f32.4 f32.4) :cost 1 :encoding :fma) + (f32.4-fmsub #:vfmsub213ps (f32.4) (f32.4 f32.4 f32.4) :cost 1 :encoding :fma) + (f32.4-fmaddsub #:vfmaddsub213ps (f32.4) (f32.4 f32.4 f32.4) :cost 1 :encoding :fma) + (f32.4-fmsubadd #:vfmsubadd213ps (f32.4) (f32.4 f32.4 f32.4) :cost 1 :encoding :fma) + ;; f32.8 + (f32.8-fmadd #:vfmadd213ps (f32.8) (f32.8 f32.8 f32.8) :cost 1 :encoding :fma) + (f32.8-fnmadd #:vfnmadd213ps (f32.8) (f32.8 f32.8 f32.8) :cost 1 :encoding :fma) + (f32.8-fmsub #:vfmsub213ps (f32.8) (f32.8 f32.8 f32.8) :cost 1 :encoding :fma) + (f32.8-fmaddsub #:vfmaddsub213ps (f32.8) (f32.8 f32.8 f32.8) :cost 1 :encoding :fma) + (f32.8-fmsubadd #:vfmsubadd213ps (f32.8) (f32.8 f32.8 f32.8) :cost 1 :encoding :fma) + ;; f64.2 + (f64.2-fmadd #:vfmadd213pd (f64.2) (f64.2 f64.2 f64.2) :cost 1 :encoding :fma) + (f64.2-fnmadd #:vfnmadd213pd (f64.2) (f64.2 f64.2 f64.2) :cost 1 :encoding :fma) + (f64.2-fmsub #:vfmsub213pd (f64.2) (f64.2 f64.2 f64.2) :cost 1 :encoding :fma) + (f64.2-fmaddsub #:vfmaddsub213pd (f64.2) (f64.2 f64.2 f64.2) :cost 1 :encoding :fma) + (f64.2-fmsubadd #:vfmsubadd213pd (f64.2) (f64.2 f64.2 f64.2) :cost 1 :encoding :fma) + ;; f64.4 + (f64.4-fmadd #:vfmadd213pd (f64.4) (f64.4 f64.4 f64.4) :cost 1 :encoding :fma) + (f64.4-fnmadd #:vfnmadd213pd (f64.4) (f64.4 f64.4 f64.4) :cost 1 :encoding :fma) + (f64.4-fmsub #:vfmsub213pd (f64.4) (f64.4 f64.4 f64.4) :cost 1 :encoding :fma) + (f64.4-fmaddsub #:vfmaddsub213pd (f64.4) (f64.4 f64.4 f64.4) :cost 1 :encoding :fma) + (f64.4-fmsubadd #:vfmsubadd213pd (f64.4) (f64.4 f64.4 f64.4) :cost 1 :encoding :fma))) diff --git a/contrib/sb-simd/code/instruction-sets/sb-simd.lisp b/contrib/sb-simd/code/instruction-sets/sb-simd.lisp new file mode 100644 index 0000000000..2743243e8e --- /dev/null +++ b/contrib/sb-simd/code/instruction-sets/sb-simd.lisp @@ -0,0 +1,392 @@ +(in-package #:sb-simd) + +(define-instruction-set :sb-simd + (:scalars + (any 64 t #:t) + ;; Numbers + (index 64 sb-simd-internals::index #:signed-num (#:signed-reg)) + (u1 1 (unsigned-byte 1) #:unsigned-num (#:unsigned-reg)) + (u2 2 (unsigned-byte 2) #:unsigned-num (#:unsigned-reg)) + (u4 4 (unsigned-byte 4) #:unsigned-num (#:unsigned-reg)) + (u8 8 (unsigned-byte 8) #:unsigned-num (#:unsigned-reg)) + (u16 16 (unsigned-byte 16) #:unsigned-num (#:unsigned-reg)) + (u32 32 (unsigned-byte 32) #:unsigned-num (#:unsigned-reg)) + (u64 64 (unsigned-byte 64) #:unsigned-num (#:unsigned-reg)) + (s8 8 (signed-byte 8) #:signed-num (#:signed-reg)) + (s16 16 (signed-byte 16) #:signed-num (#:signed-reg)) + (s32 32 (signed-byte 32) #:signed-num (#:signed-reg)) + (s64 64 (signed-byte 64) #:signed-num (#:signed-reg)) + (f32 32 single-float #:single-float (#:single-reg)) + (f64 64 double-float #:double-float (#:double-reg)) + ;; Vectors + #+sb-unicode + (charvec 64 (simple-array character (*)) #:simple-character-string) + ( u8vec 64 (simple-array (unsigned-byte 8) (*)) #:simple-array-unsigned-byte-8) + (u16vec 64 (simple-array (unsigned-byte 16) (*)) #:simple-array-unsigned-byte-16) + (u32vec 64 (simple-array (unsigned-byte 32) (*)) #:simple-array-unsigned-byte-32) + (u64vec 64 (simple-array (unsigned-byte 64) (*)) #:simple-array-unsigned-byte-64) + ( s8vec 64 (simple-array (signed-byte 8) (*)) #:simple-array-signed-byte-8) + (s16vec 64 (simple-array (signed-byte 16) (*)) #:simple-array-signed-byte-16) + (s32vec 64 (simple-array (signed-byte 32) (*)) #:simple-array-signed-byte-32) + (s64vec 64 (simple-array (signed-byte 64) (*)) #:simple-array-signed-byte-64) + (f32vec 64 (simple-array single-float (*)) #:simple-array-single-float) + (f64vec 64 (simple-array double-float (*)) #:simple-array-double-float) + ;; Arrays + (char-array 64 (array character)) + ( u8-array 64 (array (unsigned-byte 8))) + (u16-array 64 (array (unsigned-byte 16))) + (u32-array 64 (array (unsigned-byte 32))) + (u64-array 64 (array (unsigned-byte 64))) + ( s8-array 64 (array (signed-byte 8))) + (s16-array 64 (array (signed-byte 16))) + (s32-array 64 (array (signed-byte 32))) + (s64-array 64 (array (signed-byte 64))) + (f32-array 64 (array single-float)) + (f64-array 64 (array double-float))) + (:instructions + ;; ub64 packers and unpackers + (u64-from-f32 nil (u64) (f32 f32) :encoding :fake-vop) + (u64-from-f64 nil (u64) (f64) :encoding :fake-vop) + (u64-from-u8s nil (u64) (u8 u8 u8 u8 u8 u8 u8 u8) :encoding :fake-vop) + (u64-from-u16s nil (u64) (u16 u16 u16 u16) :encoding :fake-vop) + (u64-from-u32s nil (u64) (u32 u32) :encoding :fake-vop) + (u64-from-s8s nil (u64) (s8 s8 s8 s8 s8 s8 s8 s8) :encoding :fake-vop) + (u64-from-s16s nil (u64) (s16 s16 s16 s16) :encoding :fake-vop) + (u64-from-s32s nil (u64) (s32 s32) :encoding :fake-vop) + (u64-from-s64 nil (u64) (s64) :encoding :fake-vop) + ( u8s-from-u64 nil (u8 u8 u8 u8 u8 u8 u8 u8) (u64) :encoding :fake-vop) + (u16s-from-u64 nil (u16 u16 u16 u16) (u64) :encoding :fake-vop) + (u32s-from-u64 nil (u32 u32) (u64) :encoding :fake-vop) + ( s8s-from-u64 nil (s8 s8 s8 s8 s8 s8 s8 s8) (u64) :encoding :fake-vop) + (s16s-from-u64 nil (s16 s16 s16 s16) (u64) :encoding :fake-vop) + (s32s-from-u64 nil (s32 s32) (u64) :encoding :fake-vop) + ( s64-from-u64 nil (s64) (u64) :encoding :fake-vop) + ;; f32 + (f32-if nil (f32) (u32 f32 f32) :encoding :fake-vop) + (two-arg-f32-and nil (f32) (f32 f32) :encoding :fake-vop :associative t) + (two-arg-f32-or nil (f32) (f32 f32) :encoding :fake-vop :associative t) + (two-arg-f32-xor nil (f32) (f32 f32) :encoding :fake-vop :associative t) + (two-arg-f32-max nil (f32) (f32 f32) :encoding :fake-vop :associative t) + (two-arg-f32-min nil (f32) (f32 f32) :encoding :fake-vop :associative t) + (two-arg-f32+ nil (f32) (f32 f32) :encoding :fake-vop :associative t) + (two-arg-f32- nil (f32) (f32 f32) :encoding :fake-vop) + (two-arg-f32* nil (f32) (f32 f32) :encoding :fake-vop :associative t) + (two-arg-f32/ nil (f32) (f32 f32) :encoding :fake-vop) + (two-arg-f32= nil (u32) (f32 f32) :encoding :fake-vop :associative t) + (two-arg-f32/= nil (u32) (f32 f32) :encoding :fake-vop :associative t) + (two-arg-f32< nil (u32) (f32 f32) :encoding :fake-vop) + (two-arg-f32<= nil (u32) (f32 f32) :encoding :fake-vop) + (two-arg-f32> nil (u32) (f32 f32) :encoding :fake-vop) + (two-arg-f32>= nil (u32) (f32 f32) :encoding :fake-vop) + (f32-andc1 nil (f32) (f32 f32) :encoding :fake-vop) + (f32-not nil (f32) (f32) :encoding :fake-vop) + (f32-reciprocal nil (f32) (f32) :encoding :fake-vop) + (f32-rsqrt nil (f32) (f32) :encoding :fake-vop) + (f32-sqrt nil (f32) (f32) :encoding :fake-vop) + ;; f64 + (f64-if nil (f64) (u64 f64 f64) :encoding :fake-vop) + (two-arg-f64-and nil (f64) (f64 f64) :encoding :fake-vop :associative t) + (two-arg-f64-or nil (f64) (f64 f64) :encoding :fake-vop :associative t) + (two-arg-f64-xor nil (f64) (f64 f64) :encoding :fake-vop :associative t) + (two-arg-f64-max nil (f64) (f64 f64) :encoding :fake-vop :associative t) + (two-arg-f64-min nil (f64) (f64 f64) :encoding :fake-vop :associative t) + (two-arg-f64+ nil (f64) (f64 f64) :encoding :fake-vop :associative t) + (two-arg-f64- nil (f64) (f64 f64) :encoding :fake-vop) + (two-arg-f64* nil (f64) (f64 f64) :encoding :fake-vop :associative t) + (two-arg-f64/ nil (f64) (f64 f64) :encoding :fake-vop) + (two-arg-f64= nil (u64) (f64 f64) :encoding :fake-vop :associative t) + (two-arg-f64/= nil (u64) (f64 f64) :encoding :fake-vop :associative t) + (two-arg-f64< nil (u64) (f64 f64) :encoding :fake-vop) + (two-arg-f64<= nil (u64) (f64 f64) :encoding :fake-vop) + (two-arg-f64> nil (u64) (f64 f64) :encoding :fake-vop) + (two-arg-f64>= nil (u64) (f64 f64) :encoding :fake-vop) + (f64-andc1 nil (f64) (f64 f64) :encoding :fake-vop) + (f64-not nil (f64) (f64) :encoding :fake-vop) + (f64-reciprocal nil (f64) (f64) :encoding :fake-vop) + (f64-rsqrt nil (f64) (f64) :encoding :fake-vop) + (f64-sqrt nil (f64) (f64) :encoding :fake-vop) + ;; u8 + (u8-if nil (u8) (u8 u8 u8) :encoding :fake-vop) + (two-arg-u8-and nil (u8) (u8 u8) :encoding :fake-vop :associative t) + (two-arg-u8-or nil (u8) (u8 u8) :encoding :fake-vop :associative t) + (two-arg-u8-xor nil (u8) (u8 u8) :encoding :fake-vop :associative t) + (two-arg-u8-max nil (u8) (u8 u8) :encoding :fake-vop :associative t) + (two-arg-u8-min nil (u8) (u8 u8) :encoding :fake-vop :associative t) + (two-arg-u8+ nil (u8) (u8 u8) :encoding :fake-vop :associative t) + (two-arg-u8- nil (u8) (u8 u8) :encoding :fake-vop) + (two-arg-u8= nil (u8) (u8 u8) :encoding :fake-vop :associative t) + (two-arg-u8/= nil (u8) (u8 u8) :encoding :fake-vop :associative t) + (two-arg-u8< nil (u8) (u8 u8) :encoding :fake-vop) + (two-arg-u8<= nil (u8) (u8 u8) :encoding :fake-vop) + (two-arg-u8> nil (u8) (u8 u8) :encoding :fake-vop) + (two-arg-u8>= nil (u8) (u8 u8) :encoding :fake-vop) + (u8-andc1 nil (u8) (u8 u8) :encoding :fake-vop) + (u8-not nil (u8) (u8) :encoding :fake-vop) + ;; u16 + (u16-if nil (u16) (u16 u16 u16) :encoding :fake-vop) + (two-arg-u16-and nil (u16) (u16 u16) :encoding :fake-vop :associative t) + (two-arg-u16-or nil (u16) (u16 u16) :encoding :fake-vop :associative t) + (two-arg-u16-xor nil (u16) (u16 u16) :encoding :fake-vop :associative t) + (two-arg-u16-max nil (u16) (u16 u16) :encoding :fake-vop :associative t) + (two-arg-u16-min nil (u16) (u16 u16) :encoding :fake-vop :associative t) + (two-arg-u16+ nil (u16) (u16 u16) :encoding :fake-vop :associative t) + (two-arg-u16- nil (u16) (u16 u16) :encoding :fake-vop) + (two-arg-u16= nil (u16) (u16 u16) :encoding :fake-vop :associative t) + (two-arg-u16/= nil (u16) (u16 u16) :encoding :fake-vop :associative t) + (two-arg-u16< nil (u16) (u16 u16) :encoding :fake-vop) + (two-arg-u16<= nil (u16) (u16 u16) :encoding :fake-vop) + (two-arg-u16> nil (u16) (u16 u16) :encoding :fake-vop) + (two-arg-u16>= nil (u16) (u16 u16) :encoding :fake-vop) + (u16-andc1 nil (u16) (u16 u16) :encoding :fake-vop) + (u16-not nil (u16) (u16) :encoding :fake-vop) + ;; u32 + (u32-if nil (u32) (u32 u32 u32) :encoding :fake-vop) + (two-arg-u32-and nil (u32) (u32 u32) :encoding :fake-vop :associative t) + (two-arg-u32-or nil (u32) (u32 u32) :encoding :fake-vop :associative t) + (two-arg-u32-xor nil (u32) (u32 u32) :encoding :fake-vop :associative t) + (two-arg-u32-max nil (u32) (u32 u32) :encoding :fake-vop :associative t) + (two-arg-u32-min nil (u32) (u32 u32) :encoding :fake-vop :associative t) + (two-arg-u32+ nil (u32) (u32 u32) :encoding :fake-vop :associative t) + (two-arg-u32- nil (u32) (u32 u32) :encoding :fake-vop) + (two-arg-u32= nil (u32) (u32 u32) :encoding :fake-vop :associative t) + (two-arg-u32/= nil (u32) (u32 u32) :encoding :fake-vop :associative t) + (two-arg-u32< nil (u32) (u32 u32) :encoding :fake-vop) + (two-arg-u32<= nil (u32) (u32 u32) :encoding :fake-vop) + (two-arg-u32> nil (u32) (u32 u32) :encoding :fake-vop) + (two-arg-u32>= nil (u32) (u32 u32) :encoding :fake-vop) + (u32-andc1 nil (u32) (u32 u32) :encoding :fake-vop) + (u32-not nil (u32) (u32) :encoding :fake-vop) + ;; u64 + (u64-if nil (u64) (u64 u64 u64) :encoding :fake-vop) + (two-arg-u64-and nil (u64) (u64 u64) :encoding :fake-vop :associative t) + (two-arg-u64-or nil (u64) (u64 u64) :encoding :fake-vop :associative t) + (two-arg-u64-xor nil (u64) (u64 u64) :encoding :fake-vop :associative t) + (two-arg-u64-max nil (u64) (u64 u64) :encoding :fake-vop :associative t) + (two-arg-u64-min nil (u64) (u64 u64) :encoding :fake-vop :associative t) + (two-arg-u64+ nil (u64) (u64 u64) :encoding :fake-vop :associative t) + (two-arg-u64- nil (u64) (u64 u64) :encoding :fake-vop) + (two-arg-u64= nil (u64) (u64 u64) :encoding :fake-vop :associative t) + (two-arg-u64/= nil (u64) (u64 u64) :encoding :fake-vop :associative t) + (two-arg-u64< nil (u64) (u64 u64) :encoding :fake-vop) + (two-arg-u64<= nil (u64) (u64 u64) :encoding :fake-vop) + (two-arg-u64> nil (u64) (u64 u64) :encoding :fake-vop) + (two-arg-u64>= nil (u64) (u64 u64) :encoding :fake-vop) + (u64-andc1 nil (u64) (u64 u64) :encoding :fake-vop) + (u64-not nil (u64) (u64) :encoding :fake-vop) + ;; s8 + (s8-if nil (s8) (u8 s8 s8) :encoding :fake-vop) + (two-arg-s8-and nil (s8) (s8 s8) :encoding :fake-vop :associative t) + (two-arg-s8-or nil (s8) (s8 s8) :encoding :fake-vop :associative t) + (two-arg-s8-xor nil (s8) (s8 s8) :encoding :fake-vop :associative t) + (two-arg-s8-max nil (s8) (s8 s8) :encoding :fake-vop :associative t) + (two-arg-s8-min nil (s8) (s8 s8) :encoding :fake-vop :associative t) + (two-arg-s8+ nil (s8) (s8 s8) :encoding :fake-vop :associative t) + (two-arg-s8- nil (s8) (s8 s8) :encoding :fake-vop) + (two-arg-s8= nil (u8) (s8 s8) :encoding :fake-vop :associative t) + (two-arg-s8/= nil (u8) (s8 s8) :encoding :fake-vop :associative t) + (two-arg-s8< nil (u8) (s8 s8) :encoding :fake-vop) + (two-arg-s8<= nil (u8) (s8 s8) :encoding :fake-vop) + (two-arg-s8> nil (u8) (s8 s8) :encoding :fake-vop) + (two-arg-s8>= nil (u8) (s8 s8) :encoding :fake-vop) + (s8-andc1 nil (s8) (s8 s8) :encoding :fake-vop) + (s8-not nil (s8) (s8) :encoding :fake-vop) + ;; s16 + (s16-if nil (s16) (u16 s16 s16) :encoding :fake-vop) + (two-arg-s16-and nil (s16) (s16 s16) :encoding :fake-vop :associative t) + (two-arg-s16-or nil (s16) (s16 s16) :encoding :fake-vop :associative t) + (two-arg-s16-xor nil (s16) (s16 s16) :encoding :fake-vop :associative t) + (two-arg-s16-max nil (s16) (s16 s16) :encoding :fake-vop :associative t) + (two-arg-s16-min nil (s16) (s16 s16) :encoding :fake-vop :associative t) + (two-arg-s16+ nil (s16) (s16 s16) :encoding :fake-vop :associative t) + (two-arg-s16- nil (s16) (s16 s16) :encoding :fake-vop) + (two-arg-s16= nil (u16) (s16 s16) :encoding :fake-vop :associative t) + (two-arg-s16/= nil (u16) (s16 s16) :encoding :fake-vop :associative t) + (two-arg-s16< nil (u16) (s16 s16) :encoding :fake-vop) + (two-arg-s16<= nil (u16) (s16 s16) :encoding :fake-vop) + (two-arg-s16> nil (u16) (s16 s16) :encoding :fake-vop) + (two-arg-s16>= nil (u16) (s16 s16) :encoding :fake-vop) + (s16-andc1 nil (s16) (s16 s16) :encoding :fake-vop) + (s16-not nil (s16) (s16) :encoding :fake-vop) + ;; s32 + (s32-if nil (s32) (u32 s32 s32) :encoding :fake-vop) + (two-arg-s32-and nil (s32) (s32 s32) :encoding :fake-vop :associative t) + (two-arg-s32-or nil (s32) (s32 s32) :encoding :fake-vop :associative t) + (two-arg-s32-xor nil (s32) (s32 s32) :encoding :fake-vop :associative t) + (two-arg-s32-max nil (s32) (s32 s32) :encoding :fake-vop :associative t) + (two-arg-s32-min nil (s32) (s32 s32) :encoding :fake-vop :associative t) + (two-arg-s32+ nil (s32) (s32 s32) :encoding :fake-vop :associative t) + (two-arg-s32- nil (s32) (s32 s32) :encoding :fake-vop) + (two-arg-s32= nil (u32) (s32 s32) :encoding :fake-vop :associative t) + (two-arg-s32/= nil (u32) (s32 s32) :encoding :fake-vop :associative t) + (two-arg-s32< nil (u32) (s32 s32) :encoding :fake-vop) + (two-arg-s32<= nil (u32) (s32 s32) :encoding :fake-vop) + (two-arg-s32> nil (u32) (s32 s32) :encoding :fake-vop) + (two-arg-s32>= nil (u32) (s32 s32) :encoding :fake-vop) + (s32-andc1 nil (s32) (s32 s32) :encoding :fake-vop) + (s32-not nil (s32) (s32) :encoding :fake-vop) + ;; s64 + (s64-if nil (s64) (u64 s64 s64) :encoding :fake-vop) + (two-arg-s64-and nil (s64) (s64 s64) :encoding :fake-vop :associative t) + (two-arg-s64-or nil (s64) (s64 s64) :encoding :fake-vop :associative t) + (two-arg-s64-xor nil (s64) (s64 s64) :encoding :fake-vop :associative t) + (two-arg-s64-max nil (s64) (s64 s64) :encoding :fake-vop :associative t) + (two-arg-s64-min nil (s64) (s64 s64) :encoding :fake-vop :associative t) + (two-arg-s64+ nil (s64) (s64 s64) :encoding :fake-vop :associative t) + (two-arg-s64- nil (s64) (s64 s64) :encoding :fake-vop) + (two-arg-s64= nil (u64) (s64 s64) :encoding :fake-vop :associative t) + (two-arg-s64/= nil (u64) (s64 s64) :encoding :fake-vop :associative t) + (two-arg-s64< nil (u64) (s64 s64) :encoding :fake-vop) + (two-arg-s64<= nil (u64) (s64 s64) :encoding :fake-vop) + (two-arg-s64> nil (u64) (s64 s64) :encoding :fake-vop) + (two-arg-s64>= nil (u64) (s64 s64) :encoding :fake-vop) + (s64-andc1 nil (s64) (s64 s64) :encoding :fake-vop) + (s64-not nil (s64) (s64) :encoding :fake-vop)) + (:reffers + (f32 f32-array f32-aref f32-row-major-aref) + (f64 f64-array f64-aref f64-row-major-aref) + ( u8 u8-array u8-aref u8-row-major-aref) + (u16 u16-array u16-aref u16-row-major-aref) + (u32 u32-array u32-aref u32-row-major-aref) + (u64 u64-array u64-aref u64-row-major-aref) + ( s8 s8-array s8-aref s8-row-major-aref) + (s16 s16-array s16-aref s16-row-major-aref) + (s32 s32-array s32-aref s32-row-major-aref) + (s64 s64-array s64-aref s64-row-major-aref)) + (:associatives + (f32-and two-arg-f32-and +f32-true+) + (f32-or two-arg-f32-or +f32-false+) + (f32-xor two-arg-f32-xor +f32-false+) + (f32-max two-arg-f32-max nil) + (f32-min two-arg-f32-min nil) + (f32+ two-arg-f32+ 0f0) + (f32* two-arg-f32* 1f0) + (f64-and two-arg-f64-and +f64-true+) + (f64-or two-arg-f64-or +f64-false+) + (f64-xor two-arg-f64-xor +f64-false+) + (f64-max two-arg-f64-max nil) + (f64-min two-arg-f64-min nil) + (f64+ two-arg-f64+ 0d0) + (f64* two-arg-f64* 1d0) + ( u8-and two-arg-u8-and +u8-true+) + ( u8-or two-arg-u8-or +u8-false+) + ( u8-xor two-arg-u8-xor +u8-false+) + ( u8-max two-arg-u8-max nil) + ( u8-min two-arg-u8-min nil) + ( u8+ two-arg-u8+ 0) + (u16-and two-arg-u16-and +u16-true+) + (u16-or two-arg-u16-or +u16-false+) + (u16-xor two-arg-u16-xor +u16-false+) + (u16-max two-arg-u16-max nil) + (u16-min two-arg-u16-min nil) + (u16+ two-arg-u16+ 0) + (u32-and two-arg-u32-and +u32-true+) + (u32-or two-arg-u32-or +u32-false+) + (u32-xor two-arg-u32-xor +u32-false+) + (u32-max two-arg-u32-max nil) + (u32-min two-arg-u32-min nil) + (u32+ two-arg-u32+ 0) + (u64-and two-arg-u64-and +u64-true+) + (u64-or two-arg-u64-or +u64-false+) + (u64-xor two-arg-u64-xor +u64-false+) + (u64-max two-arg-u64-max nil) + (u64-min two-arg-u64-min nil) + (u64+ two-arg-u64+ 0) + ( s8-and two-arg-s8-and +s8-true+) + ( s8-or two-arg-s8-or +s8-false+) + ( s8-xor two-arg-s8-xor +s8-false+) + ( s8-max two-arg-s8-max nil) + ( s8-min two-arg-s8-min nil) + ( s8+ two-arg-s8+ 0) + (s16-and two-arg-s16-and +s16-true+) + (s16-or two-arg-s16-or +s16-false+) + (s16-xor two-arg-s16-xor +s16-false+) + (s16-max two-arg-s16-max nil) + (s16-min two-arg-s16-min nil) + (s16+ two-arg-s16+ 0) + (s32-and two-arg-s32-and +s32-true+) + (s32-or two-arg-s32-or +s32-false+) + (s32-xor two-arg-s32-xor +s32-false+) + (s32-max two-arg-s32-max nil) + (s32-min two-arg-s32-min nil) + (s32+ two-arg-s32+ 0) + (s64-and two-arg-s64-and +s64-true+) + (s64-or two-arg-s64-or +s64-false+) + (s64-xor two-arg-s64-xor +s64-false+) + (s64-max two-arg-s64-max nil) + (s64-min two-arg-s64-min nil) + (s64+ two-arg-s64+ 0)) + (:comparisons + (f32= two-arg-f32= u32-and +u32-true+) + (f32< two-arg-f32< u32-and +u32-true+) + (f32<= two-arg-f32<= u32-and +u32-true+) + (f32> two-arg-f32> u32-and +u32-true+) + (f32>= two-arg-f32>= u32-and +u32-true+) + (f64= two-arg-f64= u64-and +u64-true+) + (f64< two-arg-f64< u64-and +u64-true+) + (f64<= two-arg-f64<= u64-and +u64-true+) + (f64> two-arg-f64> u64-and +u64-true+) + (f64>= two-arg-f64>= u64-and +u64-true+) + (u8= two-arg-u8= u8-and +u8-true+) + (u8< two-arg-u8< u8-and +u8-true+) + (u8<= two-arg-u8<= u8-and +u8-true+) + (u8> two-arg-u8> u8-and +u8-true+) + (u8>= two-arg-u8>= u8-and +u8-true+) + (u16= two-arg-u16= u16-and +u16-true+) + (u16< two-arg-u16< u16-and +u16-true+) + (u16<= two-arg-u16<= u16-and +u16-true+) + (u16> two-arg-u16> u16-and +u16-true+) + (u16>= two-arg-u16>= u16-and +u16-true+) + (u32= two-arg-u32= u32-and +u32-true+) + (u32< two-arg-u32< u32-and +u32-true+) + (u32<= two-arg-u32<= u32-and +u32-true+) + (u32> two-arg-u32> u32-and +u32-true+) + (u32>= two-arg-u32>= u32-and +u32-true+) + (u64= two-arg-u64= u64-and +u64-true+) + (u64< two-arg-u64< u64-and +u64-true+) + (u64<= two-arg-u64<= u64-and +u64-true+) + (u64> two-arg-u64> u64-and +u64-true+) + (u64>= two-arg-u64>= u64-and +u64-true+) + (s8= two-arg-s8= u8-and +u8-true+) + (s8< two-arg-s8< u8-and +u8-true+) + (s8<= two-arg-s8<= u8-and +u8-true+) + (s8> two-arg-s8> u8-and +u8-true+) + (s8>= two-arg-s8>= u8-and +u8-true+) + (s16= two-arg-s16= u16-and +u16-true+) + (s16< two-arg-s16< u16-and +u16-true+) + (s16<= two-arg-s16<= u16-and +u16-true+) + (s16> two-arg-s16> u16-and +u16-true+) + (s16>= two-arg-s16>= u16-and +u16-true+) + (s32= two-arg-s32= u32-and +u32-true+) + (s32< two-arg-s32< u32-and +u32-true+) + (s32<= two-arg-s32<= u32-and +u32-true+) + (s32> two-arg-s32> u32-and +u32-true+) + (s32>= two-arg-s32>= u32-and +u32-true+) + (s64= two-arg-s64= u64-and +u64-true+) + (s64< two-arg-s64< u64-and +u64-true+) + (s64<= two-arg-s64<= u64-and +u64-true+) + (s64> two-arg-s64> u64-and +u64-true+) + (s64>= two-arg-s64>= u64-and +u64-true+)) + (:reducers + (f32- two-arg-f32- 0f0) + (f32/ two-arg-f32/ 1f0) + (f64- two-arg-f64- 0d0) + (f64/ two-arg-f64/ 1d0) + (u8- two-arg-u8- 0) + (u16- two-arg-u16- 0) + (u32- two-arg-u32- 0) + (u64- two-arg-u64- 0) + (s8- two-arg-s8- 0) + (s16- two-arg-s16- 0) + (s32- two-arg-s32- 0) + (s64- two-arg-s64- 0)) + (:unequals + (f32/= two-arg-f32/= u32-and +u32-true+) + (f64/= two-arg-f64/= u64-and +u64-true+) + (u8/= two-arg-u8/= u8-and +u8-true+) + (u16/= two-arg-u16/= u16-and +u16-true+) + (u32/= two-arg-u32/= u32-and +u32-true+) + (u64/= two-arg-u64/= u64-and +u64-true+) + (s8/= two-arg-s8/= u8-and +u8-true+) + (s16/= two-arg-s16/= u16-and +u16-true+) + (s32/= two-arg-s32/= u32-and +u32-true+) + (s64/= two-arg-s64/= u64-and +u64-true+))) diff --git a/contrib/sb-simd/code/instruction-sets/sse.lisp b/contrib/sb-simd/code/instruction-sets/sse.lisp new file mode 100644 index 0000000000..01914ed505 --- /dev/null +++ b/contrib/sb-simd/code/instruction-sets/sse.lisp @@ -0,0 +1,105 @@ +(in-package #:sb-simd-sse) + +(define-instruction-set :sse + (:test (sse-supported-p)) + (:include :x86-64) + (:scalars + (f32 32 single-float #:single-float (#:single-reg))) + (:simd-packs + (p128 nil 128 #:simd-pack (#:int-sse-reg #:double-sse-reg #:single-sse-reg)) + (f32.4 f32 128 #:simd-pack-single (#:single-sse-reg))) + (:simd-casts + (f32.4 f32.4-broadcast)) + (:reinterpret-casts + (f32! f32!-from-p128) + (f32.4! f32.4!-from-f32)) + (:instructions + ;; f32 + (f32-from-s64 nil (f32) (s64) :cost 5 :encoding :custom) + (f32!-from-p128 nil (f32) (p128) :cost 1 :encoding :custom :always-translatable nil) + (two-arg-f32-and #:andps (f32) (f32 f32) :cost 1 :encoding :sse :associative t) + (two-arg-f32-or #:orps (f32) (f32 f32) :cost 1 :encoding :sse :associative t) + (two-arg-f32-xor #:xorps (f32) (f32 f32) :cost 1 :encoding :sse :associative t) + (two-arg-f32-max #:maxss (f32) (f32 f32) :cost 1 :encoding :sse :associative t) + (two-arg-f32-min #:minss (f32) (f32 f32) :cost 1 :encoding :sse :associative t) + (two-arg-f32+ #:addss (f32) (f32 f32) :cost 1 :encoding :sse :associative t) + (two-arg-f32- #:subss (f32) (f32 f32) :cost 2 :encoding :sse) + (two-arg-f32* #:mulss (f32) (f32 f32) :cost 2 :encoding :sse :associative t) + (two-arg-f32/ #:divss (f32) (f32 f32) :cost 8 :encoding :sse) + (two-arg-f32= #:cmpss (u32) (f32 f32) :cost 4 :encoding :custom :prefix '(:eq) :associative t) + (two-arg-f32/= #:cmpss (u32) (f32 f32) :cost 4 :encoding :custom :prefix '(:neq) :associative t) + (two-arg-f32< #:cmpss (u32) (f32 f32) :cost 4 :encoding :custom :prefix '(:lt)) + (two-arg-f32<= #:cmpss (u32) (f32 f32) :cost 4 :encoding :custom :prefix '(:le)) + (two-arg-f32> #:cmpss (u32) (f32 f32) :cost 4 :encoding :custom :prefix '(:nle)) + (two-arg-f32>= #:cmpss (u32) (f32 f32) :cost 4 :encoding :custom :prefix '(:nlt)) + (f32-andc1 #:andnps (f32) (f32 f32) :cost 1 :encoding :sse) + (f32-not nil (f32) (f32) :cost 1 :encoding :fake-vop) + (f32-reciprocal #:rcpss (f32) (f32) :cost 5) + (f32-rsqrt #:rsqrtss (f32) (f32) :cost 5) + (f32-sqrt #:sqrtss (f32) (f32) :cost 15) + ;; f32.4 + (f32.4!-from-f32 #:movups (f32.4) (f32) :cost 1 :encoding :move) + (make-f32.4 nil (f32.4) (f32 f32 f32 f32) :cost 1 :encoding :fake-vop) + (f32.4-values nil (f32 f32 f32 f32) (f32.4) :cost 1 :encoding :fake-vop) + (f32.4-broadcast nil (f32.4) (f32) :cost 1 :encoding :fake-vop) + (two-arg-f32.4-and #:andps (f32.4) (f32.4 f32.4) :cost 1 :encoding :sse :associative t) + (two-arg-f32.4-or #:orps (f32.4) (f32.4 f32.4) :cost 1 :encoding :sse :associative t) + (two-arg-f32.4-xor #:xorps (f32.4) (f32.4 f32.4) :cost 1 :encoding :sse :associative t) + (two-arg-f32.4-max #:maxps (f32.4) (f32.4 f32.4) :cost 3 :encoding :sse :associative t) + (two-arg-f32.4-min #:minps (f32.4) (f32.4 f32.4) :cost 3 :encoding :sse :associative t) + (two-arg-f32.4+ #:addps (f32.4) (f32.4 f32.4) :cost 2 :encoding :sse :associative t) + (two-arg-f32.4- #:subps (f32.4) (f32.4 f32.4) :cost 2 :encoding :sse) + (two-arg-f32.4* #:mulps (f32.4) (f32.4 f32.4) :cost 2 :encoding :sse :associative t) + (two-arg-f32.4/ #:divps (f32.4) (f32.4 f32.4) :cost 8 :encoding :sse) + (f32.4-horizontal-and nil (f32) (f32.4) :cost 5 :encoding :fake-vop) + (f32.4-horizontal-or nil (f32) (f32.4) :cost 5 :encoding :fake-vop) + (f32.4-horizontal-xor nil (f32) (f32.4) :cost 5 :encoding :fake-vop) + (f32.4-horizontal-max nil (f32) (f32.4) :cost 5 :encoding :fake-vop) + (f32.4-horizontal-min nil (f32) (f32.4) :cost 5 :encoding :fake-vop) + (f32.4-horizontal+ nil (f32) (f32.4) :cost 5 :encoding :fake-vop) + (f32.4-horizontal* nil (f32) (f32.4) :cost 5 :encoding :fake-vop) + (f32.4-andc1 #:andnps (f32.4) (f32.4 f32.4) :cost 1 :encoding :sse) + (f32.4-not nil (f32.4) (f32.4) :cost 1 :encoding :fake-vop) + (f32.4-reciprocal #:rcpps (f32.4) (f32.4) :cost 5) + (f32.4-rsqrt #:rsqrtps (f32.4) (f32.4) :cost 5) + (f32.4-sqrt #:sqrtps (f32.4) (f32.4) :cost 15) + (f32.4-shuffle #:shufps (f32.4) (f32.4 f32.4 sb-simd-x86-64::imm8) :cost 1 :encoding :sse) + (f32.4-unpacklo #:unpcklps (f32.4) (f32.4 f32.4) :cost 1 :encoding :sse) + (f32.4-unpackhi #:unpckhps (f32.4) (f32.4 f32.4) :cost 1 :encoding :sse) + (f32.4-movemask #:movmskps (u4) (f32.4) :cost 1)) + (:loads + (f32-load #:movss f32 f32vec f32-array f32-aref f32-row-major-aref) + (f32.4-load #:movups f32.4 f32vec f32-array f32.4-aref f32.4-row-major-aref)) + (:stores + (f32-store #:movss f32 f32vec f32-array f32-aref f32-row-major-aref) + (f32.4-store #:movups f32.4 f32vec f32-array f32.4-aref f32.4-row-major-aref) + (f32.4-ntstore #:movntps f32.4 f32vec f32-array f32.4-non-temporal-aref f32.4-non-temporal-row-major-aref)) + (:associatives + (f32-and two-arg-f32-and +f32-true+) + (f32-or two-arg-f32-or +f32-false+) + (f32-xor two-arg-f32-xor +f32-false+) + (f32-max two-arg-f32-max nil) + (f32-min two-arg-f32-min nil) + (f32+ two-arg-f32+ 0f0) + (f32* two-arg-f32* 1f0) + (f32.4-and two-arg-f32.4-and +f32-true+) + (f32.4-or two-arg-f32.4-or +f32-false+) + (f32.4-xor two-arg-f32.4-xor +f32-false+) + (f32.4-max two-arg-f32.4-max nil) + (f32.4-min two-arg-f32.4-min nil) + (f32.4+ two-arg-f32.4+ 0f0) + (f32.4* two-arg-f32.4* 1f0)) + (:comparisons + (f32= two-arg-f32= u32-and +u32-true+) + (f32< two-arg-f32< u32-and +u32-true+) + (f32<= two-arg-f32<= u32-and +u32-true+) + (f32> two-arg-f32> u32-and +u32-true+) + (f32>= two-arg-f32>= u32-and +u32-true+)) + (:reducers + (f32- two-arg-f32- 0f0) + (f32/ two-arg-f32/ 1f0) + (f32.4- two-arg-f32.4- 0f0) + (f32.4/ two-arg-f32.4/ 1f0)) + (:unequals + (f32/= two-arg-f32/= u32-and +u32-true+))) + diff --git a/contrib/sb-simd/code/instruction-sets/sse2.lisp b/contrib/sb-simd/code/instruction-sets/sse2.lisp new file mode 100644 index 0000000000..3984ec3d45 --- /dev/null +++ b/contrib/sb-simd/code/instruction-sets/sse2.lisp @@ -0,0 +1,461 @@ +(in-package #:sb-simd-sse2) + +(define-instruction-set :sse2 + (:include :sse) + (:test (sse2-supported-p)) + (:scalars + (f64 64 double-float #:double-float (#:double-reg))) + (:simd-packs + (f64.2 f64 128 #:simd-pack-double (#:double-sse-reg)) + (u8.16 u8 128 #:simd-pack-ub8 (#:int-sse-reg)) + (u16.8 u16 128 #:simd-pack-ub16 (#:int-sse-reg)) + (u32.4 u32 128 #:simd-pack-ub32 (#:int-sse-reg)) + (u64.2 u64 128 #:simd-pack-ub64 (#:int-sse-reg)) + (s8.16 s8 128 #:simd-pack-sb8 (#:int-sse-reg)) + (s16.8 s16 128 #:simd-pack-sb16 (#:int-sse-reg)) + (s32.4 s32 128 #:simd-pack-sb32 (#:int-sse-reg)) + (s64.2 s64 128 #:simd-pack-sb64 (#:int-sse-reg))) + (:simd-casts + (f64.2 f64.2-broadcast) + (u8.16 u8.16-broadcast) + (u16.8 u16.8-broadcast) + (u32.4 u32.4-broadcast) + (u64.2 u64.2-broadcast) + (s8.16 s8.16-broadcast) + (s16.8 s16.8-broadcast) + (s32.4 s32.4-broadcast) + (s64.2 s64.2-broadcast)) + (:reinterpret-casts + (f64! f64!-from-p128) + (u8! u8!-from-p128) + (u16! u16!-from-p128) + (u32! u32!-from-p128) + (u64! u64!-from-p128) + (f64.2! f64.2!-from-f64 f64.2!-from-p128) + (u8.16! u8.16!-from-u8 u8.16!-from-p128) + (u16.8! u16.8!-from-u16 u16.8!-from-p128) + (u32.4! u32.4!-from-u32 u32.4!-from-p128) + (u64.2! u64.2!-from-u64 u64.2!-from-p128) + (s8.16! s8.16!-from-s8 s8.16!-from-p128) + (s16.8! s16.8!-from-s16 s16.8!-from-p128) + (s32.4! s32.4!-from-s32 s32.4!-from-p128) + (s64.2! s64.2!-from-s64 s64.2!-from-p128)) + (:instructions + ;; f32 + (f32-from-f64 #:cvtsd2ss (f32) (f64) :cost 5) + ;; f64 + (f64-from-f32 #:cvtss2sd (f64) (f32) :cost 5) + (f64-from-s64 nil (f64) (s64) :cost 5 :encoding :custom) + (f64!-from-p128 nil (f64) (p128) :cost 1 :encoding :custom :always-translatable nil) + (two-arg-f64-and #:andpd (f64) (f64 f64) :cost 1 :encoding :sse :associative t) + (two-arg-f64-or #:orpd (f64) (f64 f64) :cost 1 :encoding :sse :associative t) + (two-arg-f64-xor #:xorpd (f64) (f64 f64) :cost 1 :encoding :sse :associative t) + (two-arg-f64-max #:maxsd (f64) (f64 f64) :cost 1 :encoding :sse :associative t) + (two-arg-f64-min #:minsd (f64) (f64 f64) :cost 1 :encoding :sse :associative t) + (two-arg-f64+ #:addsd (f64) (f64 f64) :cost 1 :encoding :sse :associative t) + (two-arg-f64- #:subsd (f64) (f64 f64) :cost 2 :encoding :sse) + (two-arg-f64* #:mulsd (f64) (f64 f64) :cost 2 :encoding :sse :associative t) + (two-arg-f64/ #:divsd (f64) (f64 f64) :cost 8 :encoding :sse) + (two-arg-f64= #:cmpsd (u64) (f64 f64) :cost 4 :encoding :custom :prefix '(:eq) :associative t) + (two-arg-f64/= #:cmpsd (u64) (f64 f64) :cost 4 :encoding :custom :prefix '(:neq) :associative t) + (two-arg-f64< #:cmpsd (u64) (f64 f64) :cost 4 :encoding :custom :prefix '(:lt)) + (two-arg-f64<= #:cmpsd (u64) (f64 f64) :cost 4 :encoding :custom :prefix '(:le)) + (two-arg-f64> #:cmpsd (u64) (f64 f64) :cost 4 :encoding :custom :prefix '(:nle)) + (two-arg-f64>= #:cmpsd (u64) (f64 f64) :cost 4 :encoding :custom :prefix '(:nlt)) + (f64-andc1 #:andnpd (f64) (f64 f64) :cost 1 :encoding :sse) + (f64-not nil (f64) (f64) :cost 1 :encoding :fake-vop) + (f64.2-hsum nil (f64) (f64.2) :cost 3 :encoding :fake-vop) + (f64.2-hprod nil (f64) (f64.2) :cost 3 :encoding :fake-vop) + (f64-sqrt #:sqrtsd (f64) (f64) :cost 15) + ;; scalar reinterpret casts + ( u8!-from-p128 nil (u8) (p128) :cost 1 :encoding :fake-vop) + (u16!-from-p128 nil (u16) (p128) :cost 1 :encoding :fake-vop) + (u32!-from-p128 nil (u32) (p128) :cost 1 :encoding :fake-vop) + (u64!-from-p128 #:movq (u64) (p128) :cost 1 :always-translatable nil) + ;; f32.4 + (f32.4-from-s32.4 #:cvtdq2ps (f32.4) (s32.4) :cost 5) + (f32.4!-from-p128 #:movups (f32.4) (p128) :cost 1 :encoding :move :always-translatable nil) + (two-arg-f32.4= #:cmpps (u32.4) (f32.4 f32.4) :cost 4 :encoding :sse :prefix '(:eq) :associative t) + (two-arg-f32.4/= #:cmpps (u32.4) (f32.4 f32.4) :cost 4 :encoding :sse :prefix '(:neq) :associative t) + (two-arg-f32.4< #:cmpps (u32.4) (f32.4 f32.4) :cost 4 :encoding :sse :prefix '(:lt)) + (two-arg-f32.4<= #:cmpps (u32.4) (f32.4 f32.4) :cost 4 :encoding :sse :prefix '(:le)) + (two-arg-f32.4> #:cmpps (u32.4) (f32.4 f32.4) :cost 4 :encoding :sse :prefix '(:nle)) + (two-arg-f32.4>= #:cmpps (u32.4) (f32.4 f32.4) :cost 4 :encoding :sse :prefix '(:nlt)) + ;; f64.2 + (f64.2!-from-f64 #:movupd (f64.2) (f64) :cost 1 :encoding :move) + (f64.2!-from-p128 #:movupd (f64.2) (p128) :cost 1 :encoding :move :always-translatable nil) + (make-f64.2 nil (f64.2) (f64 f64) :cost 1 :encoding :fake-vop) + (f64.2-values nil (f64 f64) (f64.2) :cost 1 :encoding :fake-vop) + (f64.2-broadcast nil (f64.2) (f64) :cost 1 :encoding :fake-vop) + (two-arg-f64.2-and #:andpd (f64.2) (f64.2 f64.2) :cost 1 :encoding :sse :associative t) + (two-arg-f64.2-or #:orpd (f64.2) (f64.2 f64.2) :cost 1 :encoding :sse :associative t) + (two-arg-f64.2-xor #:xorpd (f64.2) (f64.2 f64.2) :cost 1 :encoding :sse :associative t) + (two-arg-f64.2-max #:maxpd (f64.2) (f64.2 f64.2) :cost 3 :encoding :sse :associative t) + (two-arg-f64.2-min #:minpd (f64.2) (f64.2 f64.2) :cost 3 :encoding :sse :associative t) + (two-arg-f64.2+ #:addpd (f64.2) (f64.2 f64.2) :cost 2 :encoding :sse :associative t) + (two-arg-f64.2- #:subpd (f64.2) (f64.2 f64.2) :cost 2 :encoding :sse) + (two-arg-f64.2* #:mulpd (f64.2) (f64.2 f64.2) :cost 2 :encoding :sse :associative t) + (two-arg-f64.2/ #:divpd (f64.2) (f64.2 f64.2) :cost 8 :encoding :sse) + (two-arg-f64.2= #:cmppd (u64.2) (f64.2 f64.2) :cost 4 :encoding :sse :prefix '(:eq) :associative t) + (two-arg-f64.2/= #:cmppd (u64.2) (f64.2 f64.2) :cost 4 :encoding :sse :prefix '(:neq) :associative t) + (two-arg-f64.2< #:cmppd (u64.2) (f64.2 f64.2) :cost 4 :encoding :sse :prefix '(:lt)) + (two-arg-f64.2<= #:cmppd (u64.2) (f64.2 f64.2) :cost 4 :encoding :sse :prefix '(:le)) + (two-arg-f64.2> #:cmppd (u64.2) (f64.2 f64.2) :cost 4 :encoding :sse :prefix '(:nle)) + (two-arg-f64.2>= #:cmppd (u64.2) (f64.2 f64.2) :cost 4 :encoding :sse :prefix '(:nlt)) + (f64.2-horizontal-and nil (f64) (f64.2) :cost 3 :encoding :fake-vop) + (f64.2-horizontal-or nil (f64) (f64.2) :cost 3 :encoding :fake-vop) + (f64.2-horizontal-xor nil (f64) (f64.2) :cost 3 :encoding :fake-vop) + (f64.2-horizontal-max nil (f64) (f64.2) :cost 3 :encoding :fake-vop) + (f64.2-horizontal-min nil (f64) (f64.2) :cost 3 :encoding :fake-vop) + (f64.2-horizontal+ nil (f64) (f64.2) :cost 3 :encoding :fake-vop) + (f64.2-horizontal* nil (f64) (f64.2) :cost 3 :encoding :fake-vop) + (f64.2-andc1 #:andnpd (f64.2) (f64.2 f64.2) :cost 1 :encoding :sse) + (f64.2-not nil (f64.2) (f64.2) :cost 1 :encoding :fake-vop) + (f64.2-sqrt #:sqrtpd (f64.2) (f64.2) :cost 20) + (f64.2-unpackhi #:unpckhpd (f64.2) (f64.2 f64.2) :cost 1 :encoding :sse) + (f64.2-unpacklo #:unpcklpd (f64.2) (f64.2 f64.2) :cost 1 :encoding :sse) + (f64.2-shuffle #:shufpd (f64.2) (f64.2 imm2) :cost 1) + (f64.2-movemask #:movmskpd (u2) (f64.2) :cost 1) + ;; u8.16 + (u8.16!-from-u8 #:movq (u8.16) (u8) :cost 1) + (u8.16!-from-p128 #:movdqu (u8.16) (p128) :cost 1 :encoding :move :always-translatable nil) + (make-u8.16 nil (u8.16) (u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8) :cost 1 :encoding :fake-vop) + (u8.16-values nil (u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8 u8) (u8.16) :cost 1 :encoding :fake-vop) + (u8.16-broadcast nil (u8.16) (u8) :cost 1 :encoding :fake-vop) + (two-arg-u8.16-and #:pand (u8.16) (u8.16 u8.16) :cost 1 :encoding :sse :associative t) + (two-arg-u8.16-or #:por (u8.16) (u8.16 u8.16) :cost 1 :encoding :sse :associative t) + (two-arg-u8.16-xor #:pxor (u8.16) (u8.16 u8.16) :cost 1 :encoding :sse :associative t) + (u8.16-andc1 #:pandn (u8.16) (u8.16 u8.16) :cost 1 :encoding :sse) + (u8.16-not nil (u8.16) (u8.16) :cost 1 :encoding :fake-vop) + (two-arg-u8.16+ #:paddb (u8.16) (u8.16 u8.16) :cost 2 :encoding :sse :associative t) + (two-arg-u8.16- #:psubb (u8.16) (u8.16 u8.16) :cost 2 :encoding :sse) + (two-arg-u8.16= #:pcmpeqb (u8.16) (u8.16 u8.16) :cost 1 :encoding :sse) + (two-arg-u8.16/= nil (u8.16) (u8.16 u8.16) :cost 2 :associative t :encoding :fake-vop) + (two-arg-u8.16>~ #:pcmpgtb (u8.16) (u8.16 u8.16) :cost 1 :encoding :sse) + (two-arg-u8.16> nil (u8.16) (u8.16 u8.16) :cost 1 :encoding :fake-vop) + (two-arg-u8.16< nil (u8.16) (u8.16 u8.16) :cost 1 :encoding :fake-vop) + (two-arg-u8.16>= nil (u8.16) (u8.16 u8.16) :cost 2 :encoding :fake-vop) + (two-arg-u8.16<= nil (u8.16) (u8.16 u8.16) :cost 2 :encoding :fake-vop) + (u8.16-average #:pavgw (u8.16) (u8.16 u8.16) :cost 1 :encoding :sse) + (u8.16-unpackhi #:punpckhbw (u8.16) (u8.16 u8.16) :cost 1 :encoding :sse) + (u8.16-unpacklo #:punpcklbw (u8.16) (u8.16 u8.16) :cost 1 :encoding :sse) + (u8.16-movemask #:pmovmskb (u16) (u8.16) :cost 1) + ;; u16.8 + (u16.8!-from-u16 #:movq (u16.8) (u16) :cost 1) + (u16.8!-from-p128 #:movdqu (u16.8) (p128) :cost 1 :encoding :move :always-translatable nil) + (make-u16.8 nil (u16.8) (u16 u16 u16 u16 u16 u16 u16 u16) :cost 1 :encoding :fake-vop) + (u16.8-values nil (u16 u16 u16 u16 u16 u16 u16 u16) (u16.8) :cost 1 :encoding :fake-vop) + (u16.8-broadcast nil (u16.8) (u16) :cost 1 :encoding :fake-vop) + (two-arg-u16.8-and #:pand (u16.8) (u16.8 u16.8) :cost 1 :encoding :sse :associative t) + (two-arg-u16.8-or #:por (u16.8) (u16.8 u16.8) :cost 1 :encoding :sse :associative t) + (two-arg-u16.8-xor #:pxor (u16.8) (u16.8 u16.8) :cost 1 :encoding :sse :associative t) + (u16.8-andc1 #:pandn (u16.8) (u16.8 u16.8) :cost 1 :encoding :sse) + (u16.8-not nil (u16.8) (u16.8) :cost 1 :encoding :fake-vop) + (two-arg-u16.8+ #:paddw (u16.8) (u16.8 u16.8) :cost 2 :encoding :sse :associative t) + (two-arg-u16.8- #:psubw (u16.8) (u16.8 u16.8) :cost 2 :encoding :sse) + (two-arg-u16.8= #:pcmpeqw (u16.8) (u16.8 u16.8) :cost 1 :encoding :sse) + (two-arg-u16.8/= nil (u16.8) (u16.8 u16.8) :cost 2 :associative t :encoding :fake-vop) + (two-arg-u16.8>~ #:pcmpgtw (u16.8) (u16.8 u16.8) :cost 1 :encoding :sse) + (two-arg-u16.8> nil (u16.8) (u16.8 u16.8) :cost 1 :encoding :fake-vop) + (two-arg-u16.8< nil (u16.8) (u16.8 u16.8) :cost 1 :encoding :fake-vop) + (two-arg-u16.8>= nil (u16.8) (u16.8 u16.8) :cost 2 :encoding :fake-vop) + (two-arg-u16.8<= nil (u16.8) (u16.8 u16.8) :cost 2 :encoding :fake-vop) + (u16.8-average #:pavgb (u16.8) (u16.8 u16.8) :cost 1 :encoding :sse) + (u16.8-unpackhi #:punpckhwd (u16.8) (u16.8 u16.8) :cost 1 :encoding :sse) + (u16.8-unpacklo #:punpcklwd (u16.8) (u16.8 u16.8) :cost 1 :encoding :sse) + (u16.8-movemask nil (u8) (u16.8) :cost 1 :encoding :fake-vop) + (u16.8-elt #:pextrw (u16) (u16.8 imm3) :cost 1) + (u16.8-shufflehi #:pshufhw (u16.8) (u16.8 imm8) :cost 1) + (u16.8-shufflelo #:pshuflw (u16.8) (u16.8 imm8) :cost 1) + (u16.8-shiftl #:psllw-imm (u16.8) (u16.8 imm4) :cost 1 :encoding :sse) + (u16.8-shiftr #:psrlw-imm (u16.8) (u16.8 imm4) :cost 1 :encoding :sse) + ;; u32.4 + (u32.4!-from-u32 #:movq (u32.4) (u16) :cost 1) + (u32.4!-from-p128 #:movdqu (u32.4) (p128) :cost 1 :encoding :move :always-translatable nil) + (make-u32.4 nil (u32.4) (u32 u32 u32 u32) :cost 1 :encoding :fake-vop) + (u32.4-values nil (u32 u32 u32 u32) (u32.4) :cost 1 :encoding :fake-vop) + (u32.4-broadcast nil (u32.4) (u32) :cost 1 :encoding :fake-vop) + (two-arg-u32.4-and #:pand (u32.4) (u32.4 u32.4) :cost 1 :encoding :sse :associative t) + (two-arg-u32.4-or #:por (u32.4) (u32.4 u32.4) :cost 1 :encoding :sse :associative t) + (two-arg-u32.4-xor #:pxor (u32.4) (u32.4 u32.4) :cost 1 :encoding :sse :associative t) + (u32.4-andc1 #:pandn (u32.4) (u32.4 u32.4) :cost 1 :encoding :sse) + (u32.4-not nil (u32.4) (u32.4) :cost 1 :encoding :fake-vop) + (two-arg-u32.4+ #:paddd (u32.4) (u32.4 u32.4) :cost 2 :encoding :sse :associative t) + (two-arg-u32.4- #:psubd (u32.4) (u32.4 u32.4) :cost 2 :encoding :sse) + (two-arg-u32.4= #:pcmpeqd (u32.4) (u32.4 u32.4) :cost 1 :encoding :sse) + (two-arg-u32.4/= nil (u32.4) (u32.4 u32.4) :cost 2 :associative t :encoding :fake-vop) + (two-arg-u32.4>~ #:pcmpgtd (u32.4) (u32.4 u32.4) :cost 1 :encoding :sse) + (two-arg-u32.4> nil (u32.4) (u32.4 u32.4) :cost 1 :encoding :fake-vop) + (two-arg-u32.4< nil (u32.4) (u32.4 u32.4) :cost 1 :encoding :fake-vop) + (two-arg-u32.4>= nil (u32.4) (u32.4 u32.4) :cost 2 :encoding :fake-vop) + (two-arg-u32.4<= nil (u32.4) (u32.4 u32.4) :cost 2 :encoding :fake-vop) + (u32.4-unpackhi #:punpckhdq (u32.4) (u32.4 u32.4) :cost 1 :encoding :sse) + (u32.4-unpacklo #:punpckldq (u32.4) (u32.4 u32.4) :cost 1 :encoding :sse) + (u32.4-movemask #:movmskps (u4) (u32.4) :cost 1) + (u32.4-shuffle #:pshufd (u32.4) (u32.4 imm8) :cost 1) + (u32.4-shiftl #:pslld-imm (u32.4) (u32.4 imm5) :cost 1 :encoding :sse) + (u32.4-shiftr #:psrld-imm (u32.4) (u32.4 imm5) :cost 1 :encoding :sse) + ;; u64.2 + (u64.2!-from-u64 #:movq (u64.2) (u64) :cost 1) + (u64.2!-from-p128 #:movdqu (u64.2) (p128) :cost 1 :encoding :move :always-translatable nil) + (make-u64.2 nil (u64.2) (u64 u64) :cost 1 :encoding :fake-vop) + (u64.2-values nil (u64 u64) (u64.2) :cost 1 :encoding :fake-vop) + (u64.2-broadcast nil (u64.2) (u64) :cost 1 :encoding :fake-vop) + (two-arg-u64.2-and #:pand (u64.2) (u64.2 u64.2) :cost 1 :encoding :sse :associative t) + (two-arg-u64.2-or #:por (u64.2) (u64.2 u64.2) :cost 1 :encoding :sse :associative t) + (two-arg-u64.2-xor #:pxor (u64.2) (u64.2 u64.2) :cost 1 :encoding :sse :associative t) + (u64.2-andc1 #:pandn (u64.2) (u64.2 u64.2) :cost 1 :encoding :sse) + (u64.2-not nil (u64.2) (u64.2) :cost 1 :encoding :fake-vop) + (two-arg-u64.2+ #:paddq (u64.2) (u64.2 u64.2) :cost 2 :encoding :sse :associative t) + (two-arg-u64.2- #:psubq (u64.2) (u64.2 u64.2) :cost 2 :encoding :sse) + (u64.2-unpackhi #:punpckhqdq (u64.2) (u64.2 u64.2) :cost 1 :encoding :sse) + (u64.2-unpacklo #:punpcklqdq (u64.2) (u64.2 u64.2) :cost 1 :encoding :sse) + (u64.2-movemask #:movmskpd (u2) (u64.2) :cost 1) + (u64.2-shiftl #:psllq-imm (u64.2) (u64.2 imm6) :cost 1 :encoding :sse) + (u64.2-shiftr #:psrlq-imm (u64.2) (u64.2 imm6) :cost 1 :encoding :sse) + ;; s8.16 + (s8.16!-from-s8 nil (s8.16) (s8) :cost 1 :encoding :fake-vop) + (s8.16!-from-p128 #:movdqu (s8.16) (p128) :cost 1 :encoding :move :always-translatable nil) + (make-s8.16 nil (s8.16) (s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8) :cost 1 :encoding :fake-vop) + (s8.16-values nil (s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8 s8) (s8.16) :cost 1 :encoding :fake-vop) + (s8.16-broadcast nil (s8.16) (s8) :cost 1 :encoding :fake-vop) + (two-arg-s8.16-and #:pand (s8.16) (s8.16 s8.16) :cost 1 :encoding :sse :associative t) + (two-arg-s8.16-or #:por (s8.16) (s8.16 s8.16) :cost 1 :encoding :sse :associative t) + (two-arg-s8.16-xor #:pxor (s8.16) (s8.16 s8.16) :cost 1 :encoding :sse :associative t) + (s8.16-andc1 #:pandn (s8.16) (s8.16 s8.16) :cost 1 :encoding :sse) + (s8.16-not nil (s8.16) (s8.16) :cost 1 :encoding :fake-vop) + (two-arg-s8.16+ #:paddb (s8.16) (s8.16 s8.16) :cost 2 :encoding :sse :associative t) + (two-arg-s8.16- #:psubb (s8.16) (s8.16 s8.16) :cost 2 :encoding :sse) + (two-arg-s8.16= #:pcmpeqb (u8.16) (s8.16 s8.16) :cost 1 :encoding :sse) + (two-arg-s8.16/= nil (u8.16) (s8.16 s8.16) :cost 2 :associative t :encoding :fake-vop) + (two-arg-s8.16> #:pcmpgtb (u8.16) (s8.16 s8.16) :cost 1 :encoding :sse) + (two-arg-s8.16< nil (u8.16) (s8.16 s8.16) :cost 1 :encoding :fake-vop) + (two-arg-s8.16>= nil (u8.16) (s8.16 s8.16) :cost 2 :encoding :fake-vop) + (two-arg-s8.16<= nil (u8.16) (s8.16 s8.16) :cost 2 :encoding :fake-vop) + (s8.16-unpackhi #:punpckhbw (s8.16) (s8.16 s8.16) :cost 1 :encoding :sse) + (s8.16-unpacklo #:punpcklbw (s8.16) (s8.16 s8.16) :cost 1 :encoding :sse) + (s8.16-movemask #:pmovmskb (u16) (s8.16) :cost 1) + ;; s16.8 + (s16.8!-from-s16 nil (s16.8) (s16) :cost 1 :encoding :fake-vop) + (s16.8!-from-p128 #:movdqu (s16.8) (p128) :cost 1 :encoding :move :always-translatable nil) + (make-s16.8 nil (s16.8) (s16 s16 s16 s16 s16 s16 s16 s16) :cost 1 :encoding :fake-vop) + (s16.8-values nil (s16 s16 s16 s16 s16 s16 s16 s16) (s16.8) :cost 1 :encoding :fake-vop) + (s16.8-broadcast nil (s16.8) (s16) :cost 1 :encoding :fake-vop) + (two-arg-s16.8-and #:pand (s16.8) (s16.8 s16.8) :cost 1 :encoding :sse :associative t) + (two-arg-s16.8-or #:por (s16.8) (s16.8 s16.8) :cost 1 :encoding :sse :associative t) + (two-arg-s16.8-xor #:pxor (s16.8) (s16.8 s16.8) :cost 1 :encoding :sse :associative t) + (s16.8-andc1 #:pandn (s16.8) (s16.8 s16.8) :cost 1 :encoding :sse) + (s16.8-not nil (s16.8) (s16.8) :cost 1 :encoding :fake-vop) + (two-arg-s16.8+ #:paddw (s16.8) (s16.8 s16.8) :cost 2 :encoding :sse :associative t) + (two-arg-s16.8- #:psubw (s16.8) (s16.8 s16.8) :cost 2 :encoding :sse) + (two-arg-s16.8= #:pcmpeqw (u16.8) (s16.8 s16.8) :cost 1 :encoding :sse) + (two-arg-s16.8/= nil (u16.8) (s16.8 s16.8) :cost 2 :associative t :encoding :fake-vop) + (two-arg-s16.8> #:pcmpgtw (u16.8) (s16.8 s16.8) :cost 1 :encoding :sse) + (two-arg-s16.8< nil (u16.8) (s16.8 s16.8) :cost 1 :encoding :fake-vop) + (two-arg-s16.8>= nil (u16.8) (s16.8 s16.8) :cost 2 :encoding :fake-vop) + (two-arg-s16.8<= nil (u16.8) (s16.8 s16.8) :cost 2 :encoding :fake-vop) + (s16.8-unpackhi #:punpckhwd (s16.8) (s16.8 s16.8) :cost 1 :encoding :sse) + (s16.8-unpacklo #:punpcklwd (s16.8) (s16.8 s16.8) :cost 1 :encoding :sse) + (s16.8-movemask nil (u8) (s16.8) :cost 1 :encoding :fake-vop) + (s16.8-mullo #:pmullw (s16.8) (s16.8 s16.8) :cost 1 :encoding :sse) + (s16.8-elt #:pextrw (s16) (s16.8 imm3) :cost 1) + (s16.8-shufflehi #:pshufhw (s16.8) (s16.8 imm8) :cost 1) + (s16.8-shufflelo #:pshuflw (s16.8) (s16.8 imm8) :cost 1) + (s16.8-shiftl #:psllw-imm (s16.8) (s16.8 imm4) :cost 1 :encoding :sse) + (s16.8-shiftr #:psrlw-imm (s16.8) (s16.8 imm4) :cost 1 :encoding :sse) + ;; s32.4 + (s32.4!-from-s32 nil (s32.4) (s32) :cost 1 :encoding :fake-vop) + (s32.4!-from-p128 #:movdqu (s32.4) (p128) :cost 1 :encoding :move :always-translatable nil) + (make-s32.4 nil (s32.4) (s32 s32 s32 s32) :cost 1 :encoding :fake-vop) + (s32.4-values nil (s32 s32 s32 s32) (s32.4) :cost 1 :encoding :fake-vop) + (s32.4-broadcast nil (s32.4) (s32) :cost 1 :encoding :fake-vop) + (s32.4-from-f32.4 #:cvtps2dq (s32.4) (f32.4) :cost 5) + (s32.4-from-f64.2 #:cvtpd2dq (s32.4) (f64.2) :cost 1) + (two-arg-s32.4-and #:pand (s32.4) (s32.4 s32.4) :cost 1 :encoding :sse :associative t) + (two-arg-s32.4-or #:por (s32.4) (s32.4 s32.4) :cost 1 :encoding :sse :associative t) + (two-arg-s32.4-xor #:pxor (s32.4) (s32.4 s32.4) :cost 1 :encoding :sse :associative t) + (s32.4-andc1 #:pandn (s32.4) (s32.4 s32.4) :cost 1 :encoding :sse) + (s32.4-not nil (s32.4) (s32.4) :cost 1 :encoding :fake-vop) + (two-arg-s32.4+ #:paddd (s32.4) (s32.4 s32.4) :cost 2 :encoding :sse :associative t) + (two-arg-s32.4- #:psubd (s32.4) (s32.4 s32.4) :cost 2 :encoding :sse) + (two-arg-s32.4= #:pcmpeqd (u32.4) (s32.4 s32.4) :cost 1 :encoding :sse) + (two-arg-s32.4/= nil (u32.4) (s32.4 s32.4) :cost 2 :associative t :encoding :fake-vop) + (two-arg-s32.4> #:pcmpgtd (u32.4) (s32.4 s32.4) :cost 1 :encoding :sse) + (two-arg-s32.4< nil (u32.4) (s32.4 s32.4) :cost 1 :encoding :fake-vop) + (two-arg-s32.4>= nil (u32.4) (s32.4 s32.4) :cost 2 :encoding :fake-vop) + (two-arg-s32.4<= nil (u32.4) (s32.4 s32.4) :cost 2 :encoding :fake-vop) + (s32.4-unpackhi #:punpckhdq (s32.4) (s32.4 s32.4) :cost 1 :encoding :sse) + (s32.4-unpacklo #:punpckldq (s32.4) (s32.4 s32.4) :cost 1 :encoding :sse) + (s32.4-movemask #:movmskps (u4) (s32.4) :cost 1) + (s32.4-shuffle #:pshufd (s32.4) (s32.4 imm8) :cost 1) + (s32.4-shiftl #:pslld-imm (s32.4) (s32.4 imm5) :cost 1 :encoding :sse) + (s32.4-shiftr #:psrld-imm (s32.4) (s32.4 imm5) :cost 1 :encoding :sse) + ;; s64.2 + (s64.2!-from-s64 nil (s64.2) (s64) :cost 1 :encoding :fake-vop) + (s64.2!-from-p128 #:movdqu (s64.2) (p128) :cost 1 :encoding :move :always-translatable nil) + (make-s64.2 nil (s64.2) (s64 s64) :cost 1 :encoding :fake-vop) + (s64.2-values nil (s64 s64) (s64.2) :cost 1 :encoding :fake-vop) + (s64.2-broadcast nil (s64.2) (s64) :cost 1 :encoding :fake-vop) + (two-arg-s64.2-and #:pand (s64.2) (s64.2 s64.2) :cost 1 :encoding :sse :associative t) + (two-arg-s64.2-or #:por (s64.2) (s64.2 s64.2) :cost 1 :encoding :sse :associative t) + (two-arg-s64.2-xor #:pxor (s64.2) (s64.2 s64.2) :cost 1 :encoding :sse :associative t) + (s64.2-andc1 #:pandn (s64.2) (s64.2 s64.2) :cost 1 :encoding :sse) + (s64.2-not nil (s64.2) (s64.2) :cost 1 :encoding :fake-vop) + (two-arg-s64.2+ #:paddq (s64.2) (s64.2 s64.2) :cost 2 :encoding :sse :associative t) + (two-arg-s64.2- #:psubq (s64.2) (s64.2 s64.2) :cost 2 :encoding :sse) + (s64.2-unpackhi #:punpckhqdq (s64.2) (s64.2 s64.2) :cost 1 :encoding :sse) + (s64.2-unpacklo #:punpcklqdq (s64.2) (s64.2 s64.2) :cost 1 :encoding :sse) + (s64.2-movemask #:movmskpd (u2) (s64.2) :cost 1) + (s64.2-shiftl #:psllq-imm (s64.2) (s64.2 imm6) :cost 1 :encoding :sse) + (s64.2-shiftr #:psrlq-imm (s64.2) (s64.2 imm6) :cost 1 :encoding :sse)) + (:loads + #+sb-unicode + (u32.4-load-from-string #:movdqu u32.4 charvec char-array u32.4-string-ref u32.4-row-major-string-ref) + (f64-load #:movsd f64 f64vec f64-array f64-aref f64-row-major-aref) + (f64.2-load #:movupd f64.2 f64vec f64-array f64.2-aref f64.2-row-major-aref) + (u8.16-load #:movdqu u8.16 u8vec u8-array u8.16-aref u8.16-row-major-aref) + (u16.8-load #:movdqu u16.8 u16vec u16-array u16.8-aref u16.8-row-major-aref) + (u32.4-load #:movdqu u32.4 u32vec u32-array u32.4-aref u32.4-row-major-aref) + (u64.2-load #:movdqu u64.2 u64vec u64-array u64.2-aref u64.2-row-major-aref) + (s8.16-load #:movdqu s8.16 s8vec s8-array s8.16-aref s8.16-row-major-aref) + (s16.8-load #:movdqu s16.8 s16vec s16-array s16.8-aref s16.8-row-major-aref) + (s32.4-load #:movdqu s32.4 s32vec s32-array s32.4-aref s32.4-row-major-aref) + (s64.2-load #:movdqu s64.2 s64vec s64-array s64.2-aref s64.2-row-major-aref)) + (:stores + #+sb-unicode + (u32.4-store-into-string #:movdqu u32.4 charvec char-array u32.4-string-ref u32.4-row-major-string-ref) + (f64-store #:movsd f64 f64vec f64-array f64-aref f64-row-major-aref) + (f64.2-store #:movupd f64.2 f64vec f64-array f64.2-aref f64.2-row-major-aref) + (u8.16-store #:movdqu u8.16 u8vec u8-array u8.16-aref u8.16-row-major-aref) + (u16.8-store #:movdqu u16.8 u16vec u16-array u16.8-aref u16.8-row-major-aref) + (u32.4-store #:movdqu u32.4 u32vec u32-array u32.4-aref u32.4-row-major-aref) + (u64.2-store #:movdqu u64.2 u64vec u64-array u64.2-aref u64.2-row-major-aref) + (s8.16-store #:movdqu s8.16 s8vec s8-array s8.16-aref s8.16-row-major-aref) + (s16.8-store #:movdqu s16.8 s16vec s16-array s16.8-aref s16.8-row-major-aref) + (s32.4-store #:movdqu s32.4 s32vec s32-array s32.4-aref s32.4-row-major-aref) + (s64.2-store #:movdqu s64.2 s64vec s64-array s64.2-aref s64.2-row-major-aref) + (f64.2-ntstore #:movntpd f64.2 f64vec f64-array f64.2-non-temporal-aref f64.2-non-temporal-row-major-aref) + (u8.16-ntstore #:movntdq u8.16 u8vec u8-array u8.16-non-temporal-aref u8.16-non-temporal-row-major-aref) + (u16.8-ntstore #:movntdq u16.8 u16vec u16-array u16.8-non-temporal-aref u16.8-non-temporal-row-major-aref) + (u32.4-ntstore #:movntdq u32.4 u32vec u32-array u32.4-non-temporal-aref u32.4-non-temporal-row-major-aref) + (u64.2-ntstore #:movntdq u64.2 u64vec u64-array u64.2-non-temporal-aref u64.2-non-temporal-row-major-aref) + (s8.16-ntstore #:movntdq s8.16 s8vec s8-array s8.16-non-temporal-aref s8.16-non-temporal-row-major-aref) + (s16.8-ntstore #:movntdq s16.8 s16vec s16-array s16.8-non-temporal-aref s16.8-non-temporal-row-major-aref) + (s32.4-ntstore #:movntdq s32.4 s32vec s32-array s32.4-non-temporal-aref s32.4-non-temporal-row-major-aref) + (s64.2-ntstore #:movntdq s64.2 s64vec s64-array s64.2-non-temporal-aref s64.2-non-temporal-row-major-aref)) + (:associatives + (f64-and two-arg-f64-and +f64-true+) + (f64-or two-arg-f64-or +f64-false+) + (f64-xor two-arg-f64-xor +f64-false+) + (f64-max two-arg-f64-max nil) + (f64-min two-arg-f64-min nil) + (f64+ two-arg-f64+ 0d0) + (f64* two-arg-f64* 1d0) + (f64.2-and two-arg-f64.2-and +f64-true+) + (f64.2-or two-arg-f64.2-or +f64-false+) + (f64.2-xor two-arg-f64.2-xor +f64-false+) + (f64.2-max two-arg-f64.2-max nil) + (f64.2-min two-arg-f64.2-min nil) + (f64.2+ two-arg-f64.2+ 0d0) + (f64.2* two-arg-f64.2* 1d0) + (u8.16-and two-arg-u8.16-and +u8-true+) + (u8.16-or two-arg-u8.16-or +u8-false+) + (u8.16-xor two-arg-u8.16-xor +u8-false+) + (u8.16+ two-arg-u8.16+ 0) + (u16.8-and two-arg-u16.8-and +u16-true+) + (u16.8-or two-arg-u16.8-or +u16-false+) + (u16.8-xor two-arg-u16.8-xor +u16-false+) + (u16.8+ two-arg-u16.8+ 0) + (u32.4-and two-arg-u32.4-and +u32-true+) + (u32.4-or two-arg-u32.4-or +u32-false+) + (u32.4-xor two-arg-u32.4-xor +u32-false+) + (u32.4+ two-arg-u32.4+ 0) + (u64.2-and two-arg-u64.2-and +u64-true+) + (u64.2-or two-arg-u64.2-or +u64-false+) + (u64.2-xor two-arg-u64.2-xor +u64-false+) + (u64.2+ two-arg-u64.2+ 0) + (s8.16-and two-arg-s8.16-and +s8-true+) + (s8.16-or two-arg-s8.16-or +s8-false+) + (s8.16-xor two-arg-s8.16-xor +s8-false+) + (s8.16+ two-arg-s8.16+ 0) + (s16.8-and two-arg-s16.8-and +s16-true+) + (s16.8-or two-arg-s16.8-or +s16-false+) + (s16.8-xor two-arg-s16.8-xor +s16-false+) + (s16.8+ two-arg-s16.8+ 0) + (s32.4-and two-arg-s32.4-and +s32-true+) + (s32.4-or two-arg-s32.4-or +s32-false+) + (s32.4-xor two-arg-s32.4-xor +s32-false+) + (s32.4+ two-arg-s32.4+ 0) + (s64.2-and two-arg-s64.2-and +s64-true+) + (s64.2-or two-arg-s64.2-or +s64-false+) + (s64.2-xor two-arg-s64.2-xor +s64-false+) + (s64.2+ two-arg-s64.2+ 0)) + (:comparisons + (f64= two-arg-f64= u64-and +u64-true+) + (f64< two-arg-f64< u64-and +u64-true+) + (f64<= two-arg-f64<= u64-and +u64-true+) + (f64> two-arg-f64> u64-and +u64-true+) + (f64>= two-arg-f64>= u64-and +u64-true+) + (f32.4= two-arg-f32.4= u32.4-and +u32-true+) + (f32.4< two-arg-f32.4< u32.4-and +u32-true+) + (f32.4<= two-arg-f32.4<= u32.4-and +u32-true+) + (f32.4> two-arg-f32.4> u32.4-and +u32-true+) + (f32.4>= two-arg-f32.4>= u32.4-and +u32-true+) + (f64.2= two-arg-f64.2= u64.2-and +u64-true+) + (f64.2< two-arg-f64.2< u64.2-and +u64-true+) + (f64.2<= two-arg-f64.2<= u64.2-and +u64-true+) + (f64.2> two-arg-f64.2> u64.2-and +u64-true+) + (f64.2>= two-arg-f64.2>= u64.2-and +u64-true+) + (u8.16= two-arg-u8.16= u8.16-and +u8-true+) + (u8.16< two-arg-u8.16< u8.16-and +u8-true+) + (u8.16<= two-arg-u8.16<= u8.16-and +u8-true+) + (u8.16> two-arg-u8.16> u8.16-and +u8-true+) + (u8.16>= two-arg-u8.16>= u8.16-and +u8-true+) + (u16.8= two-arg-u16.8= u16.8-and +u16-true+) + (u16.8< two-arg-u16.8< u16.8-and +u16-true+) + (u16.8<= two-arg-u16.8<= u16.8-and +u16-true+) + (u16.8> two-arg-u16.8> u16.8-and +u16-true+) + (u16.8>= two-arg-u16.8>= u16.8-and +u16-true+) + (u32.4= two-arg-u32.4= u32.4-and +u32-true+) + (u32.4< two-arg-u32.4< u32.4-and +u32-true+) + (u32.4<= two-arg-u32.4<= u32.4-and +u32-true+) + (u32.4> two-arg-u32.4> u32.4-and +u32-true+) + (u32.4>= two-arg-u32.4>= u32.4-and +u32-true+) + (s8.16= two-arg-s8.16= u8.16-and +u8-true+) + (s8.16< two-arg-s8.16< u8.16-and +u8-true+) + (s8.16<= two-arg-s8.16<= u8.16-and +u8-true+) + (s8.16> two-arg-s8.16> u8.16-and +u8-true+) + (s8.16>= two-arg-s8.16>= u8.16-and +u8-true+) + (s16.8= two-arg-s16.8= u16.8-and +u16-true+) + (s16.8< two-arg-s16.8< u16.8-and +u16-true+) + (s16.8<= two-arg-s16.8<= u16.8-and +u16-true+) + (s16.8> two-arg-s16.8> u16.8-and +u16-true+) + (s16.8>= two-arg-s16.8>= u16.8-and +u16-true+) + (s32.4= two-arg-s32.4= u32.4-and +u32-true+) + (s32.4< two-arg-s32.4< u32.4-and +u32-true+) + (s32.4<= two-arg-s32.4<= u32.4-and +u32-true+) + (s32.4> two-arg-s32.4> u32.4-and +u32-true+) + (s32.4>= two-arg-s32.4>= u32.4-and +u32-true+)) + (:reducers + (f64- two-arg-f64- 0d0) + (f64/ two-arg-f64/ 1d0) + (f64.2- two-arg-f64.2- 0d0) + (f64.2/ two-arg-f64.2/ 1d0) + (u8.16- two-arg-u8.16- 0) + (u16.8- two-arg-u16.8- 0) + (u32.4- two-arg-u32.4- 0) + (u64.2- two-arg-u64.2- 0) + (s8.16- two-arg-s8.16- 0) + (s16.8- two-arg-s16.8- 0) + (s32.4- two-arg-s32.4- 0) + (s64.2- two-arg-s64.2- 0)) + (:unequals + (f64/= two-arg-f64/= u64-and +u64-true+) + (f32.4/= two-arg-f32.4/= sb-simd-sse2:u32.4-and +u32-true+) + (f64.2/= two-arg-f64.2/= u64.2-and +u64-true+) + (u8.16/= two-arg-u8.16/= u8.16-and +u8-true+) + (u16.8/= two-arg-u16.8/= u16.8-and +u16-true+) + (u32.4/= two-arg-u32.4/= u32.4-and +u32-true+) + (s8.16/= two-arg-s8.16/= u8.16-and +u8-true+) + (s16.8/= two-arg-s16.8/= u16.8-and +u16-true+) + (s32.4/= two-arg-s32.4/= u32.4-and +u32-true+))) diff --git a/contrib/sb-simd/code/instruction-sets/sse3.lisp b/contrib/sb-simd/code/instruction-sets/sse3.lisp new file mode 100644 index 0000000000..4ac046c5a7 --- /dev/null +++ b/contrib/sb-simd/code/instruction-sets/sse3.lisp @@ -0,0 +1,11 @@ +(in-package #:sb-simd-sse3) + +(define-instruction-set :sse3 + (:include :sse2) + (:test (sse3-supported-p)) + (:instructions + (f32.4-hadd #:haddps (f32.4) (f32.4 f32.4) :cost 1 :encoding :sse) + (f32.4-hdup #:movshdup (f32.4) (f32.4) :cost 1) + (f32.4-ldup #:movsldup (f32.4) (f32.4) :cost 1) + (f64.2-hadd #:haddpd (f64.2) (f64.2 f64.2) :cost 1 :encoding :sse))) + diff --git a/contrib/sb-simd/code/instruction-sets/sse4-1.lisp b/contrib/sb-simd/code/instruction-sets/sse4-1.lisp new file mode 100644 index 0000000000..ee82bfdae7 --- /dev/null +++ b/contrib/sb-simd/code/instruction-sets/sse4-1.lisp @@ -0,0 +1,125 @@ +(in-package #:sb-simd-sse4.1) + +(define-instruction-set :sse4.1 + (:include :ssse3) + (:test (sse4.1-supported-p)) + (:instructions + ;; f32.4 + (f32.4-blend #:blendvps (f32.4) (f32.4 f32.4 u32.4) :cost 1 :encoding :sse+xmm0) + (f32.4-blendc #:blendps (f32.4) (f32.4 f32.4 imm4) :cost 1 :encoding :sse) + (f32.4-%round #:roundps (f32.4) (f32.4 imm3) :cost 2) + #+(or) ;; TODO: Broken in SBCL + (f32.4-elt #:extractps (f32) (f32.4 imm2) :cost 1) + (f32.4-insert #:insertps (f32.4) (f32.4 f32.4 imm8) :cost 1 :encoding :sse) + ;; f64.2 + (f64.2-blend #:blendvpd (f64.2) (f64.2 f64.2 u64.2) :cost 1 :encoding :sse+xmm0) + (f64.2-blendc #:blendpd (f64.2) (f64.2 f64.2 imm2) :cost 1 :encoding :sse) + (f64.2-%round #:roundpd (f64.2) (f64.2 imm3) :cost 2) + ;; u8.16 + (u8.16-blend #:pblendvb (u8.16) (u8.16 u8.16 u8.16) :cost 1 :encoding :sse+xmm0) + (u8.16-elt #:pextrb (u8) (u8.16 imm4) :cost 1) + (u8.16-insert #:pinsrb (u8.16) (u8.16 u8 imm4) :cost 1 :encoding :sse) + ;; u16.8 + (u16.8-blend #:pblendvb (u16.8) (u16.8 u16.8 u16.8) :cost 1 :encoding :sse+xmm0) + (two-arg-u16.8-max #:pmaxuw (u16.8) (u16.8 u16.8) :cost 2 :encoding :sse :associative t) + (two-arg-u16.8-min #:pminuw (u16.8) (u16.8 u16.8) :cost 2 :encoding :sse :associative t) + (u16.8-minpos #:pminuw (u16.8) (u16.8) :cost 5) + ;; u32.4 + (u32.4-blend #:pblendvb (u32.4) (u32.4 u32.4 u32.4) :cost 1 :encoding :sse+xmm0) + (two-arg-u32.4-max #:pmaxud (u32.4) (u32.4 u32.4) :cost 2 :encoding :sse :associative t) + (two-arg-u32.4-min #:pminud (u32.4) (u32.4 u32.4) :cost 2 :encoding :sse :associative t) + (u32.4-elt #:pextrd (u32) (u32.4 imm2) :cost 1) + (u32.4-insert #:pinsrd (u32.4) (u32.4 u32 imm2) :cost 1 :encoding :sse) + ;; u64.2 + (u64.2-blend #:pblendvb (u64.2) (u64.2 u64.2 u64.2) :cost 1 :encoding :sse+xmm0) + (two-arg-u64.2= #:pcmpeqq (u64.2) (u64.2 u64.2) :cost 1 :encoding :sse :associative t) + (two-arg-u64.2/= nil (u64.2) (u64.2 u64.2) :cost 2 :encoding :fake-vop :associative t) + (u64.2-elt #:pextrq (u64) (u64.2 imm1) :cost 1) + #+(or) ;; TODO: PINSRQ is currently missing in SBCL. + (u64.2-insert #:pinsrq (u64.2) (u64.2 u64 imm1) :cost 1 :encoding :sse) + ;; s8.16 + (s8.16-blend #:pblendvb (s8.16) (s8.16 s8.16 u8.16) :cost 1 :encoding :sse+xmm0) + (two-arg-s8.16-max #:pmaxsb (s8.16) (s8.16 s8.16) :cost 2 :encoding :sse :associative t) + (two-arg-s8.16-min #:pminsb (s8.16) (s8.16 s8.16) :cost 2 :encoding :sse :associative t) + (s8.16-elt #:pextrb (s8) (s8.16 imm4) :cost 1) + (s8.16-insert #:pinsrb (s8.16) (s8.16 s8 imm4) :cost 1 :encoding :sse) + ;; s16.8 + (s16.8-blend #:pblendvb (s16.8) (s16.8 s16.8 u16.8) :cost 1 :encoding :sse+xmm0) + (s16.8-from-u8.16 #:pmovsxbw (s16.8) (u8.16) :cost 5) + (s16.8-from-s8.16 #:pmovsxbw (s16.8) (s8.16) :cost 5) + (s16.8-pack #:packusdw (s16.8) (s32.4 s32.4) :cost 1 :encoding :sse) + ;; s32.4 + (s32.4-blend #:pblendvb (s32.4) (s32.4 s32.4 u32.4) :cost 1 :encoding :sse+xmm0) + (two-arg-s32.4-max #:pmaxsd (s32.4) (s32.4 s32.4) :cost 2 :encoding :sse :associative t) + (two-arg-s32.4-min #:pminsd (s32.4) (s32.4 s32.4) :cost 2 :encoding :sse :associative t) + (s32.4-from-u8.16 #:pmovsxbd (s32.4) (u8.16) :cost 5) + (s32.4-from-s8.16 #:pmovsxbd (s32.4) (s8.16) :cost 5) + (s32.4-from-u16.8 #:pmovsxwd (s32.4) (u16.8) :cost 5) + (s32.4-from-s16.8 #:pmovsxwd (s32.4) (s16.8) :cost 5) + (two-arg-s32.4-mullo #:pmulld (s32.4) (s32.4 s32.4) :cost 1 :encoding :sse :associative t) + (s32.4-elt #:pextrd (s32) (s32.4 imm2) :cost 1) + (s32.4-insert #:pinsrd (s32.4) (s32.4 s32 imm2) :cost 1 :encoding :sse) + ;; s64.2 + (s64.2-blend #:pblendvb (s64.2) (s64.2 s64.2 u64.2) :cost 1 :encoding :sse+xmm0) + (s64.2-from-u8.16 #:pmovsxbq (s64.2) (u8.16) :cost 5) + (s64.2-from-s8.16 #:pmovsxbq (s64.2) (s8.16) :cost 5) + (s64.2-from-u16.8 #:pmovsxwq (s64.2) (u16.8) :cost 5) + (s64.2-from-s16.8 #:pmovsxwq (s64.2) (s16.8) :cost 5) + (s64.2-from-u32.4 #:pmovsxdq (s64.2) (u32.4) :cost 5) + (s64.2-from-s32.4 #:pmovsxdq (s64.2) (s32.4) :cost 5) + (two-arg-s64.2-mul #:pmuldq (s64.2) (s64.2 s64.2) :cost 2 :encoding :sse :associative t) + (two-arg-s64.2= #:pcmpeqq (u64.2) (s64.2 s64.2) :cost 1 :encoding :sse :associative t) + (two-arg-s64.2/= nil (u64.2) (s64.2 s64.2) :cost 2 :encoding :fake-vop :associative t) + (s64.2-elt #:pextrq (s64) (s64.2 imm1) :cost 1) + #+(or) ;; TODO: PINSRQ is currently missing in SBCL. + (s64.2-insert #:pinsrq (s64.2) (s64.2 s64 imm1) :cost 1 :encoding :sse)) + (:loads + (f32.4-ntload #:movntdqa f32.4 f32vec f32-array f32.4-non-temporal-aref f32.4-non-temporal-row-major-aref) + (f64.2-ntload #:movntdqa f64.2 f64vec f64-array f64.2-non-temporal-aref f64.2-non-temporal-row-major-aref) + (u8.16-ntload #:movntdqa u8.16 u8vec u8-array u8.16-non-temporal-aref u8.16-non-temporal-row-major-aref) + (u16.8-ntload #:movntdqa u16.8 u16vec u16-array u16.8-non-temporal-aref u16.8-non-temporal-row-major-aref) + (u32.4-ntload #:movntdqa u32.4 u32vec u32-array u32.4-non-temporal-aref u32.4-non-temporal-row-major-aref) + (u64.2-ntload #:movntdqa u64.2 u64vec u64-array u64.2-non-temporal-aref u64.2-non-temporal-row-major-aref) + (s8.16-ntload #:movntdqa s8.16 s8vec s8-array s8.16-non-temporal-aref s8.16-non-temporal-row-major-aref) + (s16.8-ntload #:movntdqa s16.8 s16vec s16-array s16.8-non-temporal-aref s16.8-non-temporal-row-major-aref) + (s32.4-ntload #:movntdqa s32.4 s32vec s32-array s32.4-non-temporal-aref s32.4-non-temporal-row-major-aref) + (s64.2-ntload #:movntdqa s64.2 s64vec s64-array s64.2-non-temporal-aref s64.2-non-temporal-row-major-aref)) + (:stores + (f32.4-ntstore #:movntps f32.4 f32vec f32-array f32.4-non-temporal-aref f32.4-non-temporal-row-major-aref) + (f64.2-ntstore #:movntpd f64.2 f64vec f64-array f64.2-non-temporal-aref f64.2-non-temporal-row-major-aref) + (u8.16-ntstore #:movntdq u8.16 u8vec u8-array u8.16-non-temporal-aref u8.16-non-temporal-row-major-aref) + (u16.8-ntstore #:movntdq u16.8 u16vec u16-array u16.8-non-temporal-aref u16.8-non-temporal-row-major-aref) + (u32.4-ntstore #:movntdq u32.4 u32vec u32-array u32.4-non-temporal-aref u32.4-non-temporal-row-major-aref) + (u64.2-ntstore #:movntdq u64.2 u64vec u64-array u64.2-non-temporal-aref u64.2-non-temporal-row-major-aref) + (s8.16-ntstore #:movntdq s8.16 s8vec s8-array s8.16-non-temporal-aref s8.16-non-temporal-row-major-aref) + (s16.8-ntstore #:movntdq s16.8 s16vec s16-array s16.8-non-temporal-aref s16.8-non-temporal-row-major-aref) + (s32.4-ntstore #:movntdq s32.4 s32vec s32-array s32.4-non-temporal-aref s32.4-non-temporal-row-major-aref) + (s64.2-ntstore #:movntdq s64.2 s64vec s64-array s64.2-non-temporal-aref s64.2-non-temporal-row-major-aref)) + (:associatives + (u16.8-max two-arg-u16.8-max nil) + (u16.8-min two-arg-u16.8-min nil) + (u32.4-max two-arg-u32.4-max nil) + (u32.4-min two-arg-u32.4-min nil) + (s8.16-max two-arg-s8.16-max nil) + (s8.16-min two-arg-s8.16-min nil) + (s32.4-max two-arg-s32.4-max nil) + (s32.4-min two-arg-s32.4-min nil) + (s32.4-mullo two-arg-s32.4-mullo 1) + (s64.2-mul two-arg-s64.2-mul 1)) + (:comparisons + (u64.2= two-arg-u64.2= u64.2-and +u64-true+) + (s64.2= two-arg-s64.2= u64.2-and +u64-true+)) + (:ifs + (f32.4-if f32.4-blend) + (f64.2-if f64.2-blend) + (u8.16-if u8.16-blend) + (u16.8-if u16.8-blend) + (u32.4-if u32.4-blend) + (u64.2-if u64.2-blend) + (s8.16-if s8.16-blend) + (s16.8-if s16.8-blend) + (s32.4-if s32.4-blend) + (s64.2-if s64.2-blend)) + (:unequals + (u64.2/= two-arg-u64.2/= u64.2-and +u64-true+) + (s64.2/= two-arg-s64.2/= u64.2-and +u64-true+))) diff --git a/contrib/sb-simd/code/instruction-sets/sse4-2.lisp b/contrib/sb-simd/code/instruction-sets/sse4-2.lisp new file mode 100644 index 0000000000..9eb83ca8b9 --- /dev/null +++ b/contrib/sb-simd/code/instruction-sets/sse4-2.lisp @@ -0,0 +1,26 @@ +(in-package #:sb-simd-sse4.2) + +(define-instruction-set :sse4.2 + (:include :sse4.1) + (:test (sse4.2-supported-p)) + (:instructions + ;; u64.2 + (two-arg-u64.2>~ #:pcmpgtq (u64.2) (u64.2 u64.2) :cost 3 :encoding :sse) + (two-arg-u64.2> nil (u64.2) (u64.2 u64.2) :cost 3 :encoding :fake-vop) + (two-arg-u64.2>= nil (u64.2) (u64.2 u64.2) :cost 4 :encoding :fake-vop) + (two-arg-u64.2< nil (u64.2) (u64.2 u64.2) :cost 3 :encoding :fake-vop) + (two-arg-u64.2<= nil (u64.2) (u64.2 u64.2) :cost 4 :encoding :fake-vop) + ;; s64.2 + (two-arg-s64.2> #:pcmpgtq (u64.2) (s64.2 s64.2) :cost 3 :encoding :sse) + (two-arg-s64.2>= nil (u64.2) (s64.2 s64.2) :cost 4 :encoding :fake-vop) + (two-arg-s64.2< nil (u64.2) (s64.2 s64.2) :cost 3 :encoding :fake-vop) + (two-arg-s64.2<= nil (u64.2) (s64.2 s64.2) :cost 4 :encoding :fake-vop)) + (:comparisons + (u64.2< two-arg-u64.2< u64.2-and +u64-true+) + (u64.2<= two-arg-u64.2<= u64.2-and +u64-true+) + (u64.2> two-arg-u64.2> u64.2-and +u64-true+) + (u64.2>= two-arg-u64.2>= u64.2-and +u64-true+) + (s64.2< two-arg-s64.2< u64.2-and +u64-true+) + (s64.2<= two-arg-s64.2<= u64.2-and +u64-true+) + (s64.2> two-arg-s64.2> u64.2-and +u64-true+) + (s64.2>= two-arg-s64.2>= u64.2-and +u64-true+))) diff --git a/contrib/sb-simd/code/instruction-sets/ssse3.lisp b/contrib/sb-simd/code/instruction-sets/ssse3.lisp new file mode 100644 index 0000000000..9dbc932f1e --- /dev/null +++ b/contrib/sb-simd/code/instruction-sets/ssse3.lisp @@ -0,0 +1,31 @@ +(in-package #:sb-simd-ssse3) + +(define-instruction-set :ssse3 + (:include :sse3) + (:test (ssse3-supported-p)) + (:instructions + ;; u16.8 + (u16.8-hadd #:phaddw (u16.8) (u16.8 u16.8) :cost 3 :encoding :sse) + (u16.8-hsub #:phsubw (u16.8) (u16.8 u16.8) :cost 3 :encoding :sse) + ;; u32.4 + (u32.4-hadd #:phaddd (u32.4) (u32.4 u32.4) :cost 3 :encoding :sse) + (u32.4-hsub #:phsubd (u32.4) (u32.4 u32.4) :cost 3 :encoding :sse) + ;; s8.16 + (s8.16-shuffle #:pshufb (s8.16) (s8.16 s8.16) :cost 1 :encoding :sse) + (s8.16-abs #:pabsb (s8.16) (s8.16) :cost 2) + (s8.16-sign #:psignb (s8.16) (s8.16 s8.16) :cost 1 :encoding :sse) + ;; s16.8 + (two-arg-s16.8-mulhrs #:pmulhrsw (s16.8) (s16.8 s16.8) :cost 1 :encoding :sse :associative t) + (s16.8-abs #:pabsw (s16.8) (s16.8) :cost 2) + (s16.8-maddubs #:pmaddubsw (s16.8) (u16.8 s16.8) :cost 2 :encoding :sse) + (s16.8-sign #:psignw (s16.8) (s16.8 s16.8) :cost 2 :encoding :sse) + ;; s16.8 + (s16.8-hadd #:phaddw (s16.8) (s16.8 s16.8) :cost 3 :encoding :sse) + (s16.8-hsub #:phsubw (s16.8) (s16.8 s16.8) :cost 3 :encoding :sse) + ;; s32.4 + (s32.4-abs #:pabsd (s32.4) (s32.4) :cost 2) + (s32.4-sign #:psignd (s32.4) (s32.4 s32.4) :cost 3 :encoding :sse) + (s32.4-hadd #:phaddd (s32.4) (s32.4 s32.4) :cost 3 :encoding :sse) + (s32.4-hsub #:phsubd (s32.4) (s32.4 s32.4) :cost 3 :encoding :sse)) + (:associatives + (s16.8-mulhrs two-arg-s16.8-mulhrs 1))) diff --git a/contrib/sb-simd/code/instruction-sets/x86-64.lisp b/contrib/sb-simd/code/instruction-sets/x86-64.lisp new file mode 100644 index 0000000000..5ddbdf2f25 --- /dev/null +++ b/contrib/sb-simd/code/instruction-sets/x86-64.lisp @@ -0,0 +1,13 @@ +(in-package #:sb-simd-x86-64) + +(define-instruction-set :x86-64 + (:include :sb-simd) + (:scalars + (imm1 1 (unsigned-byte 1) (:constant (unsigned-byte 1))) + (imm2 2 (unsigned-byte 2) (:constant (unsigned-byte 2))) + (imm3 3 (unsigned-byte 3) (:constant (unsigned-byte 3))) + (imm4 4 (unsigned-byte 4) (:constant (unsigned-byte 4))) + (imm5 5 (unsigned-byte 5) (:constant (unsigned-byte 5))) + (imm6 6 (unsigned-byte 6) (:constant (unsigned-byte 6))) + (imm7 7 (unsigned-byte 7) (:constant (unsigned-byte 7))) + (imm8 8 (unsigned-byte 8) (:constant (unsigned-byte 8))))) diff --git a/contrib/sb-simd/code/missing-instruction.lisp b/contrib/sb-simd/code/missing-instruction.lisp new file mode 100644 index 0000000000..85acff491c --- /dev/null +++ b/contrib/sb-simd/code/missing-instruction.lisp @@ -0,0 +1,35 @@ +(in-package #:sb-simd-internals) + +;;; Our library always defines all instruction sets and instructions, but +;;; usually, only a subset of them are actually available. All the +;;; remaining instructions are replaced by functions that signal a suitable +;;; error message. + +(define-condition missing-instruction (error) + ((%record + :initarg :record + :reader missing-instruction-record)) + (:report + (lambda (c s) + (with-accessors ((instruction-set instruction-record-instruction-set) + (instruction-name instruction-record-name)) + (missing-instruction-record c) + (format s "Missing ~S instruction ~S." + (instruction-set-name instruction-set) + instruction-name))))) + +(defun missing-instruction (instruction-record) + (error 'missing-instruction :record instruction-record)) + +(defmacro define-missing-instruction + (name &key (required-arguments '()) (optional-arguments '()) (rest-argument nil)) + (assert (find-function-record name)) + `(defun ,name (,@required-arguments + ,@optional-arguments + ,@(when rest-argument `(&rest ,rest-argument))) + (declare (ignore ,@required-arguments + ,@optional-arguments + ,@(when rest-argument `(,rest-argument)))) + (missing-instruction + (load-time-value + (find-function-record ',name))))) diff --git a/contrib/sb-simd/code/packages.lisp b/contrib/sb-simd/code/packages.lisp new file mode 100644 index 0000000000..a3dea97699 --- /dev/null +++ b/contrib/sb-simd/code/packages.lisp @@ -0,0 +1,1995 @@ +(in-package #:cl-user) + +(defpackage #:sb-simd-internals + (:use #:common-lisp) + (:export + ;; constants.lisp + #:most-positive-f32 + #:most-negative-f32 + #:most-positive-f64 + #:most-negative-f64 + #:most-positive-u1 + #:most-positive-u2 + #:most-positive-u4 + #:most-positive-u8 + #:most-positive-u16 + #:most-positive-u32 + #:most-positive-u64 + #:most-positive-s8 + #:most-negative-s8 + #:most-positive-s16 + #:most-negative-s16 + #:most-positive-s32 + #:most-negative-s32 + #:most-positive-s64 + #:most-negative-s64 + #:+u8-true+ + #:+u16-true+ + #:+u32-true+ + #:+u64-true+ + #:+u8-false+ + #:+u16-false+ + #:+u32-false+ + #:+u64-false+ + #:+s8-true+ + #:+s16-true+ + #:+s32-true+ + #:+s64-true+ + #:+s8-false+ + #:+s16-false+ + #:+s32-false+ + #:+s64-false+ + #:+f32-true+ + #:+f64-true+ + #:+f32-false+ + #:+f64-false+ + ;; utilities.lisp + #:type-specifier + #:non-nil-symbol + #:function-name + #:index+ + #:index- + #:index* + #:ensure-package + #:mksym + #:prefixed-symbols + #:touch + #:required-argument + #:macroexpand-all + #:ensure-list + #:lambda-expression-p + #:parse-function-name + #:define-inline + #:define-notinline + ;; printable.lisp + #:printable + #:printable-slot-plist + ;; instruction-set.lisp + #:*instruction-sets* + #:instruction-set + #:instruction-set-p + #:instruction-set-name + #:instruction-set-package + #:instruction-set-includes + #:instruction-set-available-p + #:find-instruction-set + #:included-instruction-sets + #:define-instruction-set + #:instruction-set-vectorizers + ;; record.lisp + #:record + #:record-p + #:record-name + #:record-instruction-set + #:value-record + #:value-record-p + #:value-record-name + #:value-record-instruction-set + #:value-record-type + #:value-record-primitive-type + #:value-record-bits + #:value-record-scs + #:value-record-simd-width + #:value-record-cast-record + #:find-value-record + #:filter-value-records + #:simd-record + #:simd-record-p + #:scalar-record-p + #:simd-record-name + #:simd-record-instruction-set + #:simd-record-type + #:simd-record-primitive-type + #:simd-record-bits + #:simd-record-scs + #:simd-record-scalar-record + #:function-record + #:function-record-p + #:function-record-name + #:function-record-instruction-set + #:function-record-result-records + #:function-record-result-record + #:function-record-required-argument-records + #:function-record-rest-argument-record + #:function-record-simd-width + #:function-record-scalar-variant + #:find-function-record + #:filter-function-records + #:filter-available-function-records + #:scalar-function-record-p + #:simd-function-record-p + #:aref-record + #:aref-record-p + #:setf-aref-record + #:setf-aref-record-p + #:row-major-aref-record + #:row-major-aref-record-p + #:setf-row-major-aref-record + #:setf-row-major-aref-record-p + #:instruction-record + #:instruction-record-p + #:instruction-record-name + #:instruction-record-instruction-set + #:instruction-record-vop + #:instruction-record-mnemonic + #:instruction-record-result-records + #:instruction-record-argument-records + #:instruction-record-cost + #:instruction-record-pure + #:instruction-record-always-translatable + #:instruction-record-associative + #:instruction-record-encoding + #:instruction-record-prefix + #:instruction-record-suffix + #:vref-record + #:vref-record-p + #:vref-record-name + #:vref-record-instruction-set + #:vref-record-vop + #:vref-record-vop-c + #:vref-record-mnemonic + #:vref-record-value-record + #:vref-record-vector-record + #:vref-record-aref + #:vref-record-row-major-aref + #:load-record + #:load-record-p + #:load-record-name + #:load-record-instruction-set + #:load-record-vop + #:load-record-vop-c + #:load-record-mnemonic + #:load-record-value-record + #:load-record-vector-record + #:load-record-aref + #:load-record-row-major-aref + #:store-record + #:store-record-p + #:store-record-name + #:store-record-instruction-set + #:store-record-vop + #:store-record-vop-c + #:store-record-mnemonic + #:store-record-value-record + #:store-record-vector-record + #:store-record-aref + #:store-record-row-major-aref + #:reffer-record + #:reffer-record-p + #:reffer-record-name + #:reffer-record-instruction-set + #:reffer-record-array-record + #:reffer-record-primitive + #:associative-record + #:associative-record-p + #:associative-record-name + #:associative-record-instruction-set + #:associative-record-binary-operation + #:associative-record-identity-element + #:reducer-record + #:reducer-record-p + #:reducer-record-name + #:reducer-record-instruction-set + #:reducer-record-binary-operation + #:reducer-record-initial-element + #:comparison-record + #:comparison-record-p + #:comparison-record-name + #:comparison-record-instruction-set + #:comparison-record-cmp + #:comparison-record-and + #:comparison-record-truth + #:unequal-record + #:unequal-record-p + #:unequal-record-name + #:unequal-record-instruction-set + #:unequal-record-neq + #:unequal-record-and + #:unequal-record-truth + #:if-record + #:if-record-p + #:if-record-name + #:if-record-instruction-set + #:if-record-blend + #:cast-record + #:cast-record-p + #:cast-record-name + #:cast-record-instruction-set + #:scalar-cast-record + #:scalar-cast-record-p + #:scalar-cast-record-name + #:scalar-cast-record-instruction-set + #:simd-cast-record + #:simd-cast-record-p + #:simd-cast-record-name + #:simd-cast-record-instruction-set + #:simd-cast-record-broadcast + #:reinterpret-cast-record + #:reinterpret-cast-record-p + #:reinterpret-cast-record-name + #:reinterpret-cast-record-instruction-set + #:reinterpret-cast-record-reinterpreters + ;; Macros + #:define-fake-vop + #:define-trivial-fake-vop + #:with-primitive-arguments + #:with-primitive-argument + #:instruction-set-case + ;; CPU Identification + #:sse-supported-p + #:sse2-supported-p + #:sse3-supported-p + #:ssse3-supported-p + #:sse4.1-supported-p + #:sse4.2-supported-p + #:avx-supported-p + #:avx2-supported-p + #:fma-supported-p)) + +(progn + (defpackage #:sb-simd + (:use #:common-lisp #:sb-simd-internals) + #0= + (:export + ;; Re-exports from sb-simd-internals. + #:most-positive-f32 + #:most-negative-f32 + #:most-positive-f64 + #:most-negative-f64 + #:most-positive-u1 + #:most-positive-u2 + #:most-positive-u4 + #:most-positive-u8 + #:most-positive-u16 + #:most-positive-u32 + #:most-positive-u64 + #:most-positive-s8 + #:most-negative-s8 + #:most-positive-s16 + #:most-negative-s16 + #:most-positive-s32 + #:most-negative-s32 + #:most-positive-s64 + #:most-negative-s64 + #:+u8-true+ + #:+u16-true+ + #:+u32-true+ + #:+u64-true+ + #:+u8-false+ + #:+u16-false+ + #:+u32-false+ + #:+u64-false+ + #:+s8-true+ + #:+s16-true+ + #:+s32-true+ + #:+s64-true+ + #:+s8-false+ + #:+s16-false+ + #:+s32-false+ + #:+s64-false+ + #:+f32-true+ + #:+f64-true+ + #:+f32-false+ + #:+f64-false+ + #:index + #:index+ + #:index- + #:index* + ;; Macros + #:define-inline + #:instruction-set-case + ;; f32 + #:f32 + #:f32vec + #:f32-array + #:f32-if + #:f32-and + #:f32-or + #:f32-xor + #:f32-andc1 + #:f32-not + #:f32-max + #:f32-min + #:f32+ + #:f32- + #:f32* + #:f32/ + #:f32= + #:f32/= + #:f32< + #:f32<= + #:f32> + #:f32>= + #:f32-incf + #:f32-decf + #:f32-aref + #:f32-row-major-aref + ;; f64 + #:f64 + #:f64vec + #:f64-array + #:f64-if + #:f64-and + #:f64-or + #:f64-xor + #:f64-andc1 + #:f64-not + #:f64-max + #:f64-min + #:f64+ + #:f64- + #:f64* + #:f64/ + #:f64= + #:f64/= + #:f64< + #:f64<= + #:f64> + #:f64>= + #:f64-incf + #:f64-decf + #:f64-aref + #:f64-row-major-aref + ;; u1 + #:u1 + ;; u2 + #:u2 + ;; u4 + #:u4 + ;; u8 + #:u8 + #:u8vec + #:u8-array + #:u8-if + #:u8-and + #:u8-or + #:u8-xor + #:u8-andc1 + #:u8-not + #:u8-max + #:u8-min + #:u8+ + #:u8- + #:u8= + #:u8/= + #:u8< + #:u8<= + #:u8> + #:u8>= + #:u8-incf + #:u8-decf + #:u8-aref + #:u8-row-major-aref + ;; u16 + #:u16 + #:u16vec + #:u16-array + #:u16-if + #:u16-and + #:u16-or + #:u16-xor + #:u16-andc1 + #:u16-not + #:u16-max + #:u16-min + #:u16+ + #:u16- + #:u16= + #:u16/= + #:u16< + #:u16<= + #:u16> + #:u16>= + #:u16-incf + #:u16-decf + #:u16-aref + #:u16-row-major-aref + ;; u32 + #:u32 + #:u32vec + #:u32-array + #:u32-if + #:u32-and + #:u32-or + #:u32-xor + #:u32-andc1 + #:u32-not + #:u32-max + #:u32-min + #:u32+ + #:u32- + #:u32= + #:u32/= + #:u32< + #:u32<= + #:u32> + #:u32>= + #:u32-incf + #:u32-decf + #:u32-aref + #:u32-row-major-aref + ;; u64 + #:u64 + #:u64vec + #:u64-array + #:u64-if + #:u64-and + #:u64-or + #:u64-xor + #:u64-andc1 + #:u64-not + #:u64-max + #:u64-min + #:u64+ + #:u64- + #:u64= + #:u64/= + #:u64< + #:u64<= + #:u64> + #:u64>= + #:u64-incf + #:u64-decf + #:u64-aref + #:u64-row-major-aref + ;; s8 + #:s8 + #:s8vec + #:s8-array + #:s8-if + #:s8-and + #:s8-or + #:s8-xor + #:s8-andc1 + #:s8-not + #:s8-max + #:s8-min + #:s8+ + #:s8- + #:s8= + #:s8/= + #:s8< + #:s8<= + #:s8> + #:s8>= + #:s8-incf + #:s8-decf + #:s8-aref + #:s8-row-major-aref + ;; s16 + #:s16 + #:s16vec + #:s16-array + #:s16-if + #:s16-and + #:s16-or + #:s16-xor + #:s16-andc1 + #:s16-not + #:s16-max + #:s16-min + #:s16+ + #:s16- + #:s16= + #:s16/= + #:s16< + #:s16<= + #:s16> + #:s16>= + #:s16-incf + #:s16-decf + #:s16-aref + #:s16-row-major-aref + ;; s32 + #:s32 + #:s32vec + #:s32-array + #:s32-if + #:s32-and + #:s32-or + #:s32-xor + #:s32-andc1 + #:s32-not + #:s32-max + #:s32-min + #:s32+ + #:s32- + #:s32= + #:s32/= + #:s32< + #:s32<= + #:s32> + #:s32>= + #:s32-incf + #:s32-decf + #:s32-aref + #:s32-row-major-aref + ;; s64 + #:s64 + #:s64vec + #:s64-array + #:s64-if + #:s64-and + #:s64-or + #:s64-xor + #:s64-andc1 + #:s64-not + #:s64-max + #:s64-min + #:s64+ + #:s64- + #:s64= + #:s64/= + #:s64< + #:s64<= + #:s64> + #:s64>= + #:s64-incf + #:s64-decf + #:s64-aref + #:s64-row-major-aref + ;; Simple Strings + #+sb-unicode + #:charvec + #:char-array + ;; Integer Packers + #:u64-from-u8s + #:u64-from-u16s + #:u64-from-u32s + #:u64-from-s8s + #:u64-from-s16s + #:u64-from-s32s + #:u64-from-s64 + ;; Integer Unpackers + #:u8s-from-u64 + #:u16s-from-u64 + #:u32s-from-u64 + #:s8s-from-u64 + #:s16s-from-u64 + #:s32s-from-u64 + #:s64-from-u64 + ;; Boolean Conversion + #:u8-from-boolean + #:u16-from-boolean + #:u32-from-boolean + #:u64-from-boolean + ;; Odd Bits + #:u16-odd-bits + #:u32-odd-bits)) + + (defpackage #:sb-simd-x86-64 + (:use #:common-lisp #:sb-simd-internals #:sb-simd) + #0# + #1= + (:export #:imm1 #:imm2 #:imm3 #:imm4 #:imm5 #:imm6 #:imm7 #:imm8)) + + (defpackage #:sb-simd-sse + (:use #:common-lisp #:sb-simd-internals #:sb-simd-x86-64) + (:shadow + ;; f32 + #:f32 + #:f32-and + #:f32-or + #:f32-xor + #:f32-andc1 + #:f32-not + #:f32-max + #:f32-min + #:f32+ + #:f32- + #:f32* + #:f32/ + #:f32= + #:f32/= + #:f32< + #:f32<= + #:f32> + #:f32>= + #:f32-incf + #:f32-decf + #:f32-aref + #:f32-row-major-aref) + #0# + #1# + #2= + (:export + #:f32! + #:p128 + ;; f32.4 + #:make-f32.4 + #:f32.4 + #:f32.4! + #:f32.4-values + #:f32.4-broadcast + #:f32.4!-from-f32 + #:f32.4-and + #:f32.4-or + #:f32.4-xor + #:f32.4-max + #:f32.4-min + #:f32.4+ + #:f32.4- + #:f32.4* + #:f32.4/ + #:f32.4-horizontal-and + #:f32.4-horizontal-or + #:f32.4-horizontal-xor + #:f32.4-horizontal-max + #:f32.4-horizontal-min + #:f32.4-horizontal+ + #:f32.4-horizontal* + #:f32.4-andc1 + #:f32.4-not + #:f32.4-reciprocal + #:f32.4-rsqrt + #:f32.4-sqrt + #:f32.4-movemask + #:f32.4-shuffle + #:f32.4-incf + #:f32.4-decf + #:f32.4-aref #:f32.4-row-major-aref + #:f32.4-non-temporal-aref #:f32.4-non-temporal-row-major-aref)) + + (defpackage #:sb-simd-sse2 + (:use #:common-lisp #:sb-simd-internals #:sb-simd-sse) + (:shadow + ;; f64 + #:f64 + #:f64-and + #:f64-or + #:f64-xor + #:f64-andc1 + #:f64-not + #:f64-max + #:f64-min + #:f64+ + #:f64- + #:f64* + #:f64/ + #:f64= + #:f64/= + #:f64< + #:f64<= + #:f64> + #:f64>= + #:f64-incf + #:f64-decf + #:f64-aref + #:f64-row-major-aref) + #0# + #1# + #2# + #3= + (:export + #:f64! + #:u8! + #:u16! + #:u32! + #:u64! + ;; f32.4 + #:f32.4= + #:f32.4/= + #:f32.4< + #:f32.4<= + #:f32.4> + #:f32.4>= + ;; f64.2 + #:make-f64.2 + #:f64.2 + #:f64.2! + #:f64.2-values + #:f64.2-broadcast + #:f64.2-and + #:f64.2-or + #:f64.2-xor + #:f64.2-max + #:f64.2-min + #:f64.2+ + #:f64.2- + #:f64.2* + #:f64.2/ + #:f64.2= + #:f64.2/= + #:f64.2< + #:f64.2<= + #:f64.2> + #:f64.2>= + #:f64.2-horizontal-and + #:f64.2-horizontal-or + #:f64.2-horizontal-xor + #:f64.2-horizontal-max + #:f64.2-horizontal-min + #:f64.2-horizontal+ + #:f64.2-horizontal* + #:f64.2-andc1 + #:f64.2-not + #:f64.2-sqrt + #:f64.2-shuffle + #:f64.2-unpackhi + #:f64.2-unpacklo + #:f64.2-movemask + #:f64.2-incf + #:f64.2-decf + #:f64.2-aref #:f64.2-row-major-aref + #:f64.2-non-temporal-aref #:f64.2-non-temporal-row-major-aref + ;; u8.16 + #:make-u8.16 + #:u8.16 + #:u8.16! + #:u8.16-values + #:u8.16-broadcast + #:u8.16-and + #:u8.16-or + #:u8.16-xor + #:u8.16-andc1 + #:u8.16-not + #:u8.16+ + #:u8.16- + #:u8.16= + #:u8.16-unpackhi + #:u8.16-unpacklo + #:u8.16-movemask + #:u8.16-average + ;; TODO Having 8-bit shifts would be nice, but there is no instruction + ;; for that. But they could be implemented as a fake VOP. + ;; #:u8.16-shiftl + ;; #:u8.16-shiftr + #:u8.16-incf + #:u8.16-decf + #:u8.16-aref #:u8.16-row-major-aref + #:u8.16-non-temporal-aref #:u8.16-non-temporal-row-major-aref + ;; u16.8 + #:make-u16.8 + #:u16.8 + #:u16.8! + #:u16.8-values + #:u16.8-broadcast + #:u16.8-and + #:u16.8-or + #:u16.8-xor + #:u16.8-andc1 + #:u16.8-not + #:u16.8+ + #:u16.8- + #:u16.8= + #:u16.8-unpackhi + #:u16.8-unpacklo + #:u16.8-movemask + #:u16.8-average + #:u16.8-shiftl + #:u16.8-shiftr + #:u16.8-incf + #:u16.8-decf + #:u16.8-aref #:u16.8-row-major-aref + #:u16.8-non-temporal-aref #:u16.8-non-temporal-row-major-aref + ;; u32.4 + #:make-u32.4 + #:u32.4 + #:u32.4! + #:u32.4-values + #:u32.4-broadcast + #:u32.4-and + #:u32.4-or + #:u32.4-xor + #:u32.4-andc1 + #:u32.4-not + #:u32.4+ + #:u32.4- + #:u32.4= + #:u32.4-unpackhi + #:u32.4-unpacklo + #:u32.4-movemask + #:u32.4-shuffle + #:u32.4-shiftl + #:u32.4-shiftr + #:u32.4-incf + #:u32.4-decf + #:u32.4-aref #:u32.4-row-major-aref + #:u32.4-non-temporal-aref #:u32.4-non-temporal-row-major-aref + #+sb-unicode + #:u32.4-string-ref + #+sb-unicode + #:u32.4-row-major-string-ref + ;; u64.2 + #:make-u64.2 + #:u64.2 + #:u64.2! + #:u64.2-values + #:u64.2-broadcast + #:u64.2-and + #:u64.2-or + #:u64.2-xor + #:u64.2-andc1 + #:u64.2-not + #:u64.2+ + #:u64.2- + #:u64.2-unpackhi + #:u64.2-unpacklo + #:u64.2-movemask + #:u64.2-shiftl + #:u64.2-shiftr + #:u64.2-incf + #:u64.2-decf + #:u64.2-aref #:u64.2-row-major-aref + #:u64.2-non-temporal-aref #:u64.2-non-temporal-row-major-aref + ;; s8.16 + #:make-s8.16 + #:s8.16 + #:s8.16! + #:s8.16-values + #:s8.16-broadcast + #:s8.16-and + #:s8.16-or + #:s8.16-xor + #:s8.16-andc1 + #:s8.16-not + #:s8.16+ + #:s8.16- + #:s8.16= + #:s8.16-unpackhi + #:s8.16-unpacklo + #:s8.16-movemask + #:s8.16-aref #:s8.16-row-major-aref + #:s8.16-non-temporal-aref #:s8.16-non-temporal-row-major-aref + ;; s16.8 + #:make-s16.8 + #:s16.8 + #:s16.8! + #:s16.8-values + #:s16.8-broadcast + #:s16.8-and + #:s16.8-or + #:s16.8-xor + #:s16.8-andc1 + #:s16.8-not + #:s16.8+ + #:s16.8- + #:s16.8= + #:s16.8-unpackhi + #:s16.8-unpacklo + #:s16.8-movemask + #:s16.8-mullo + #:s16.8-elt + #:s16.8-shufflehi + #:s16.8-shufflelo + #:s16.8-shiftl + #:s16.8-shiftr + #:s16.8-aref #:s16.8-row-major-aref + #:s16.8-non-temporal-aref #:s16.8-non-temporal-row-major-aref + ;; s32.4 + #:make-s32.4 + #:s32.4 + #:s32.4! + #:s32.4-values + #:s32.4-broadcast + #:s32.4-and + #:s32.4-or + #:s32.4-xor + #:s32.4-andc1 + #:s32.4-not + #:s32.4+ + #:s32.4- + #:s32.4= + #:s32.4-unpackhi + #:s32.4-unpacklo + #:s32.4-movemask + #:s32.4-shuffle + #:s32.4-shiftl + #:s32.4-shiftr + #:s32.4-aref #:s32.4-row-major-aref + #:s32.4-non-temporal-aref #:s32.4-non-temporal-row-major-aref + ;; s64.2 + #:make-s64.2 + #:s64.2 + #:s64.2! + #:s64.2-values + #:s64.2-broadcast + #:s64.2-and + #:s64.2-or + #:s64.2-xor + #:s64.2-andc1 + #:s64.2-not + #:s64.2+ + #:s64.2- + #:s64.2-unpackhi + #:s64.2-unpacklo + #:s64.2-movemask + #:s64.2-shiftl + #:s64.2-shiftr + #:s64.2-aref #:s64.2-row-major-aref + #:s64.2-non-temporal-aref #:s64.2-non-temporal-row-major-aref)) + + (defpackage #:sb-simd-sse3 + (:use #:common-lisp #:sb-simd-internals #:sb-simd-sse2) + #0# + #1# + #2# + #3# + #4= + (:export + #:f32.4-hadd + #:f32.4-hdup + #:f32.4-ldup)) + + (defpackage #:sb-simd-ssse3 + (:use #:common-lisp #:sb-simd-internals #:sb-simd-sse3) + #0# + #1# + #2# + #3# + #4# + #5= + (:export + #:s16.8-mulhrs + #:u16.8-hadd + #:u32.4-hadd + #:u16.8-hsub + #:u32.4-hsub + #:s8.16-shuffle + #:s8.16-abs + #:s8.16-sign + #:s16.8-abs + #:s16.8-maddubs + #:s16.8-sign + #:s16.8-hadd + #:s16.8-hsub + #:s32.4-abs + #:s32.4-sign + #:s32.4-hadd + #:s32.4-hsub)) + + (defpackage #:sb-simd-sse4.1 + (:use #:common-lisp #:sb-simd-internals #:sb-simd-ssse3) + (:shadow + #:f32.4-non-temporal-aref #:f32.4-non-temporal-row-major-aref + #:f64.2-non-temporal-aref #:f64.2-non-temporal-row-major-aref + #:u8.16-non-temporal-aref #:u8.16-non-temporal-row-major-aref + #:u16.8-non-temporal-aref #:u16.8-non-temporal-row-major-aref + #:u32.4-non-temporal-aref #:u32.4-non-temporal-row-major-aref + #:u64.2-non-temporal-aref #:u64.2-non-temporal-row-major-aref + #:s8.16-non-temporal-aref #:s8.16-non-temporal-row-major-aref + #:s16.8-non-temporal-aref #:s16.8-non-temporal-row-major-aref + #:s32.4-non-temporal-aref #:s32.4-non-temporal-row-major-aref + #:s64.2-non-temporal-aref #:s64.2-non-temporal-row-major-aref) + #0# + #1# + #2# + #3# + #4# + #5# + #6= + (:export + #:f32.4-if + #:f32.4-round + #:f32.4-floor + #:f32.4-ceiling + #:f32.4-truncate + ;; #:f32.4-elt ;; TODO + #:f32.4-insert + #:f64.2-if + #:f64.2-round + #:f64.2-floor + #:f64.2-ceiling + #:f64.2-truncate + #:u8.16-if + #:u8.16-elt + #:u8.16-insert + #:u16.8-if + #:u16.8-max + #:u16.8-min + #:u16.8-minpos + #:u32.4-if + #:u32.4-max + #:u32.4-min + #:u32.4-elt + #:u32.4-insert + #:u64.2-if + #:u64.2= + #:u64.2/= + #:u64.2-elt + #:s8.16-if + #:s8.16-max + #:s8.16-min + #:s8.16-elt + #:s8.16-insert + #:s16.8-if + #:s16.8-from-u8.16 + #:s16.8-from-s8.16 + #:s16.8-pack + #:s32.4-if + #:s32.4-max + #:s32.4-min + #:s32.4-from-u8.16 + #:s32.4-from-s8.16 + #:s32.4-from-u16.8 + #:s32.4-from-s16.8 + #:s32.4-mullo + #:s32.4-elt + #:s32.4-insert + #:s64.2-if + #:s64.2-from-u8.16 + #:s64.2-from-s8.16 + #:s64.2-from-u16.8 + #:s64.2-from-s16.8 + #:s64.2-from-u32.4 + #:s64.2-from-s32.4 + #:s64.2= + #:s64.2/= + #:s64.2-elt)) + + (defpackage #:sb-simd-sse4.2 + (:use #:common-lisp #:sb-simd-internals #:sb-simd-sse4.1) + #0# + #1# + #2# + #3# + #4# + #5# + #6# + #7= + (:export + #:u64.2> + #:u64.2>= + #:u64.2< + #:u64.2<=)) + + (defpackage #:sb-simd-avx + (:use #:common-lisp #:sb-simd-internals #:sb-simd-x86-64) + #0# + #1# + (:shadow + ;; f32 + #:f32 + #:f32-and + #:f32-or + #:f32-xor + #:f32-andc1 + #:f32-not + #:f32-max + #:f32-min + #:f32+ + #:f32- + #:f32* + #:f32/ + #:f32= + #:f32/= + #:f32< + #:f32<= + #:f32> + #:f32>= + #:f32-incf + #:f32-decf + #:f32-aref + #:f32-row-major-aref + ;; f64 + #:f64 + #:f64-and + #:f64-or + #:f64-xor + #:f64-andc1 + #:f64-not + #:f64-max + #:f64-min + #:f64+ + #:f64- + #:f64* + #:f64/ + #:f64= + #:f64/= + #:f64< + #:f64<= + #:f64> + #:f64>= + #:f64-incf + #:f64-decf + #:f64-aref + #:f64-row-major-aref) + #8= + (:export + #:p128 + #:p256 + #:vzeroupper + #:vzeroall + ;; f32.4 + #:make-f32.4 + #:f32.4 + #:f32.4! + #:f32.4-values + #:f32.4-broadcast + #:f32.4-if + #:f32.4-from-f64.4 + #:f32.4-and + #:f32.4-or + #:f32.4-xor + #:f32.4-andc1 + #:f32.4-not + #:f32.4-max + #:f32.4-min + #:f32.4+ + #:f32.4- + #:f32.4* + #:f32.4/ + #:f32.4-horizontal-and + #:f32.4-horizontal-or + #:f32.4-horizontal-xor + #:f32.4-horizontal-max + #:f32.4-horizontal-min + #:f32.4-horizontal+ + #:f32.4-horizontal* + #:f32.4= + #:f32.4/= + #:f32.4< + #:f32.4<= + #:f32.4> + #:f32.4>= + #:f32.4-addsub + #:f32.4-hadd + #:f32.4-hsub + #:f32.4-reciprocal + #:f32.4-rsqrt + #:f32.4-sqrt + #:f32.4-unpackhi + #:f32.4-unpacklo + #:f32.4-round + #:f32.4-floor + #:f32.4-ceiling + #:f32.4-truncate + #:f32.4-permute + #:f32.4-shuffle + #:f32.4-movemask + #:f32.4-incf + #:f32.4-decf + #:f32.4-aref #:f32.4-row-major-aref + #:f32.4-non-temporal-aref #:f32.4-non-temporal-row-major-aref + ;; f64.2 + #:make-f64.2 + #:f64.2 + #:f64.2! + #:f64.2-values + #:f64.2-broadcast + #:f64.2-if + #:f64.2-and + #:f64.2-or + #:f64.2-xor + #:f64.2-andc1 + #:f64.2-not + #:f64.2-max + #:f64.2-min + #:f64.2+ + #:f64.2- + #:f64.2* + #:f64.2/ + #:f64.2-horizontal-and + #:f64.2-horizontal-or + #:f64.2-horizontal-xor + #:f64.2-horizontal-max + #:f64.2-horizontal-min + #:f64.2-horizontal+ + #:f64.2-horizontal* + #:f64.2= + #:f64.2/= + #:f64.2< + #:f64.2<= + #:f64.2> + #:f64.2>= + #:f64.2-addsub + #:f64.2-hadd + #:f64.2-hsub + #:f64.2-sqrt + #:f64.2-unpackhi + #:f64.2-unpacklo + #:f64.2-round + #:f64.2-floor + #:f64.2-ceiling + #:f64.2-truncate + #:f64.2-permute + #:f64.2-shuffle + #:f64.2-movemask + #:f64.2-incf + #:f64.2-decf + #:f64.2-aref #:f64.2-row-major-aref + #:f64.2-non-temporal-aref #:f64.2-non-temporal-row-major-aref + ;; f32.8 + #:make-f32.8 + #:f32.8 + #:f32.8! + #:f32.8-values + #:f32.8-broadcast + #:f32.8-if + #:f32.8-from-u32.8 + #:f32.8-and + #:f32.8-or + #:f32.8-xor + #:f32.8-andc1 + #:f32.8-not + #:f32.8-max + #:f32.8-min + #:f32.8+ + #:f32.8- + #:f32.8* + #:f32.8/ + #:f32.8-horizontal-and + #:f32.8-horizontal-or + #:f32.8-horizontal-xor + #:f32.8-horizontal-max + #:f32.8-horizontal-min + #:f32.8-horizontal+ + #:f32.8-horizontal* + #:f32.8= + #:f32.8/= + #:f32.8< + #:f32.8<= + #:f32.8> + #:f32.8>= + #:f32.8-dupeven + #:f32.8-dupodd + #:f32.8-hadd + #:f32.8-hsub + #:f32.8-reciprocal + #:f32.8-rsqrt + #:f32.8-sqrt + #:f32.8-unpackhi + #:f32.8-unpacklo + #:f32.8-round + #:f32.8-floor + #:f32.8-ceiling + #:f32.8-truncate + #:f32.8-permute + #:f32.8-permute128 + #:f32.8-shuffle + #:f32.8-movemask + #:f32.4-from-f32.8 + #:f32.8-insert-f32.4 + #:f32.8-round + #:f32.8-incf + #:f32.8-decf + #:f32.8-aref #:f32.8-row-major-aref + #:f32.8-non-temporal-aref #:f32.8-non-temporal-row-major-aref + ;; f64.4 + #:make-f64.4 + #:f64.4 + #:f64.4! + #:f64.4-values + #:f64.4-broadcast + #:f64.4-if + #:f64.4-from-f32.4 + #:f64.4-from-u32.4 + #:f64.4-from-s32.4 + #:f64.4-and + #:f64.4-or + #:f64.4-xor + #:f64.4-andc1 + #:f64.4-not + #:f64.4-max + #:f64.4-min + #:f64.4+ + #:f64.4- + #:f64.4* + #:f64.4/ + #:f64.4-horizontal-and + #:f64.4-horizontal-or + #:f64.4-horizontal-xor + #:f64.4-horizontal-max + #:f64.4-horizontal-min + #:f64.4-horizontal+ + #:f64.4-horizontal* + #:f64.4= + #:f64.4/= + #:f64.4< + #:f64.4<= + #:f64.4> + #:f64.4>= + #:f64.4-dupeven + #:f64.4-hadd + #:f64.4-hsub + #:f64.4-sqrt + #:f64.4-unpackhi + #:f64.4-unpacklo + #:f64.4-ceiling + #:f64.4-permute + #:f64.4-permute128 + #:f64.4-shuffle + #:f64.4-movemask + #:f64.4-reverse + #:f64.2-from-f64.4 + #:f64.4-insert-f64.2 + #:f64.4-set128 + #:f64.4-round + #:f64.4-incf + #:f64.4-decf + #:f64.4-aref #:f64.4-row-major-aref + #:f64.4-non-temporal-aref #:f64.4-non-temporal-row-major-aref + ;; u8.16 + #:make-u8.16 + #:u8.16 + #:u8.16! + #:u8.16-values + #:u8.16-broadcast + #:u8.16-if + #:u8.16-and + #:u8.16-or + #:u8.16-xor + #:u8.16-andc1 + #:u8.16-not + #:u8.16+ + #:u8.16- + #:u8.16= + #:u8.16/= + #:u8.16> + #:u8.16< + #:u8.16>= + #:u8.16<= + #:u8.16-unpackhi + #:u8.16-unpacklo + #:u8.16-movemask + #:u8.16-aref #:u8.16-row-major-aref + #:u8.16-non-temporal-aref #:u8.16-non-temporal-row-major-aref + ;; u16.8 + #:make-u16.8 + #:u16.8 + #:u16.8! + #:u16.8-values + #:u16.8-broadcast + #:u16.8-if + #:u16.8-and + #:u16.8-or + #:u16.8-xor + #:u16.8-andc1 + #:u16.8-not + #:u16.8+ + #:u16.8- + #:u16.8= + #:u16.8/= + #:u16.8> + #:u16.8< + #:u16.8>= + #:u16.8<= + #:u16.8-shiftl + #:u16.8-shiftr + #:u16.8-unpackhi + #:u16.8-unpacklo + #:u16.8-movemask + #:u16.8-aref #:u16.8-row-major-aref + #:u16.8-non-temporal-aref #:u16.8-non-temporal-row-major-aref + ;; u32.4 + #:make-u32.4 + #:u32.4 + #:u32.4! + #:u32.4-values + #:u32.4-broadcast + #:u32.4-if + #:u32.4-and + #:u32.4-or + #:u32.4-xor + #:u32.4-andc1 + #:u32.4-not + #:u32.4+ + #:u32.4- + #:u32.4= + #:u32.4/= + #:u32.4> + #:u32.4< + #:u32.4>= + #:u32.4<= + #:u32.4-unpackhi + #:u32.4-unpacklo + #:u32.4-movemask + #:u32.4-permute + #:u32.4-aref #:u32.4-row-major-aref + #:u32.4-non-temporal-aref #:u32.4-non-temporal-row-major-aref + #+sb-unicode + #:u32.4-string-ref + #+sb-unicode + #:u32.4-row-major-string-ref + ;; u64.2 + #:make-u64.2 + #:u64.2 + #:u64.2! + #:u64.2-values + #:u64.2-broadcast + #:u64.2-if + #:u64.2-and + #:u64.2-or + #:u64.2-xor + #:u64.2-andc1 + #:u64.2-not + #:u64.2+ + #:u64.2- + #:u64.2= + #:u64.2/= + #:u64.2> + #:u64.2< + #:u64.2>= + #:u64.2<= + #:u64.2-unpackhi + #:u64.2-unpacklo + #:u64.2-movemask + #:u64.2-permute + #:u64.2-aref #:u64.2-row-major-aref + #:u64.2-non-temporal-aref #:u64.2-non-temporal-row-major-aref + ;; u8.32 + #:make-u8.32 + #:u8.32 + #:u8.32! + #:u8.32-values + #:u8.32-broadcast + #:u8.16-from-u8.32 + #:u8.32-insert-u8.16 + #:u8.32-aref #:u8.32-row-major-aref + #:u8.32-non-temporal-aref #:u8.32-non-temporal-row-major-aref + ;; u16.16 + #:make-u16.16 + #:u16.16 + #:u16.16! + #:u16.16-values + #:u16.16-broadcast + #:u16.8-from-u16.16 + #:u16.16-insert-u16.8 + #:u16.16-aref #:u16.16-row-major-aref + #:u16.16-non-temporal-aref #:u16.16-non-temporal-row-major-aref + ;; u32.8 + #:make-u32.8 + #:u32.8 + #:u32.8! + #:u32.8-values + #:u32.8-broadcast + #:u32.8-permute + #:u32.8-insert-u32.4 + #:u32.8-aref #:u32.8-row-major-aref + #:u32.8-non-temporal-aref #:u32.8-non-temporal-row-major-aref + #+sb-unicode + #:u32.8-string-ref + #+sb-unicode + #:u32.8-row-major-string-ref + ;; u64.4 + #:make-u64.4 + #:u64.4 + #:u64.4! + #:u64.4-values + #:u64.4-broadcast + #:u64.4-permute + #:u64.2-from-u64.4 + #:u64.4-insert-u64.2 + #:u64.4-aref #:u64.4-row-major-aref + #:u64.4-non-temporal-aref #:u64.4-non-temporal-row-major-aref + ;; s8.16 + #:make-s8.16 + #:s8.16 + #:s8.16! + #:s8.16-values + #:s8.16-broadcast + #:s8.16-if + #:s8.16-and + #:s8.16-or + #:s8.16-xor + #:s8.16-andc1 + #:s8.16-not + #:s8.16+ + #:s8.16- + #:s8.16= + #:s8.16/= + #:s8.16> + #:s8.16< + #:s8.16>= + #:s8.16<= + #:s8.16-unpackhi + #:s8.16-unpacklo + #:s8.16-movemask + #:s8.16-aref #:s8.16-row-major-aref + #:s8.16-non-temporal-aref #:s8.16-non-temporal-row-major-aref + ;; s16.8 + #:make-s16.8 + #:s16.8 + #:s16.8! + #:s16.8-values + #:s16.8-broadcast + #:s16.8-if + #:s16.8-and + #:s16.8-or + #:s16.8-xor + #:s16.8-andc1 + #:s16.8-not + #:s16.8+ + #:s16.8- + #:s16.8-mullo + #:s16.8= + #:s16.8/= + #:s16.8> + #:s16.8< + #:s16.8>= + #:s16.8<= + #:s16.8-mullo + #:s16.8-shiftl + #:s16.8-shiftr + #:s16.8-unpackhi + #:s16.8-unpacklo + #:s16.8-movemask + #:s16.8-aref #:s16.8-row-major-aref + #:s16.8-non-temporal-aref #:s16.8-non-temporal-row-major-aref + ;; s32.4 + #:make-s32.4 + #:s32.4 + #:s32.4! + #:s32.4-values + #:s32.4-broadcast + #:s32.4-if + #:s32.4-from-f64.4 + #:s32.4-and + #:s32.4-or + #:s32.4-xor + #:s32.4-andc1 + #:s32.4-not + #:s32.4+ + #:s32.4- + #:s32.4-mullo + #:s32.4= + #:s32.4/= + #:s32.4> + #:s32.4< + #:s32.4>= + #:s32.4<= + #:s32.4-mullo + #:s32.4-unpackhi + #:s32.4-unpacklo + #:s32.4-movemask + #:s32.4-permute + #:s32.4-aref #:s32.4-row-major-aref + #:s32.4-non-temporal-aref #:s32.4-non-temporal-row-major-aref + ;; s64.2 + #:s64.2 + #:make-s64.2 + #:s64.2 + #:s64.2! + #:s64.2-values + #:s64.2-broadcast + #:s64.2-if + #:s64.2-and + #:s64.2-or + #:s64.2-xor + #:s64.2-andc1 + #:s64.2-not + #:s64.2+ + #:s64.2- + #:s64.2= + #:s64.2/= + #:s64.2> + #:s64.2< + #:s64.2>= + #:s64.2<= + #:s64.2-shiftl + #:s64.2-shiftr + #:s64.2-unpackhi + #:s64.2-unpacklo + #:s64.2-movemask + #:s64.2-permute + #:s64.2-aref #:s64.2-row-major-aref + #:s64.2-non-temporal-aref #:s64.2-non-temporal-row-major-aref + ;; s8.32 + #:make-s8.32 + #:s8.32 + #:s8.32! + #:s8.32-values + #:s8.32-broadcast + #:s8.16-from-s8.32 + #:s8.32-insert-s8.16 + #:s8.32-permute128 + #:s8.32-aref #:s8.32-row-major-aref + #:s8.32-non-temporal-aref #:s8.32-non-temporal-row-major-aref + ;; s16.16 + #:make-s16.16 + #:s16.16 + #:s16.16! + #:s16.16-values + #:s16.16-broadcast + #:s16.8-from-s16.16 + #:s16.16-insert-s16.8 + #:s16.16-permute128 + #:s16.16-aref #:s16.16-row-major-aref + #:s16.16-non-temporal-aref #:s16.16-non-temporal-row-major-aref + ;; s32.8 + #:make-s32.8 + #:s32.8 + #:s32.8! + #:s32.8-values + #:s32.8-broadcast + #:s32.4-from-s32.8 + #:s32.8-insert-s32.4 + #:s32.8-permute128 + #:s32.8-aref #:s32.8-row-major-aref + #:s32.8-non-temporal-aref #:s32.8-non-temporal-row-major-aref + ;; s64.4 + #:make-s64.4 + #:s64.4 + #:s64.4! + #:s64.4-values + #:s64.4-broadcast + #:s64.2-from-s64.4 + #:s64.4-insert-s64.2 + #:s64.4-permute + #:s64.4-permute128 + #:s64.4-aref #:s64.4-row-major-aref + #:s64.4-non-temporal-aref #:s64.4-non-temporal-row-major-aref)) + + (defpackage #:sb-simd-avx2 + (:use #:common-lisp #:sb-simd-internals #:sb-simd-avx) + (:shadow + #:u8.16!-from-p256 #:u16.8!-from-p256 #:u32.4!-from-p256 #:u64.2!-from-p256 + #:s8.16!-from-p256 #:s16.8!-from-p256 #:s32.4!-from-p256 #:s64.2!-from-p256 + #:u8.16! #:u16.8! #:u32.4! #:u64.2! + #:s8.16! #:s16.8! #:s32.4! #:s64.2! + #:make-u8.32 #:make-u16.16 #:make-u32.8 #:make-u64.4 + #:make-s8.32 #:make-s16.16 #:make-s32.8 #:make-s64.4 + #:u8.32 #:u16.16 #:u32.8 #:u64.4 + #:s8.32 #:s16.16 #:s32.8 #:s64.4 + #:u8.32-values #:u16.16-values #:u32.8-values #:u64.4-values + #:s8.32-values #:s16.16-values #:s32.8-values #:s64.4-values + #:u8.16-from-u8.32 #:u16.8-from-u16.16 #:u32.4-from-u32.8 #:u64.2-from-u64.4 + #:s8.16-from-s8.32 #:s16.8-from-s16.16 #:s32.4-from-s32.8 #:s64.2-from-s64.4 + #:u8.32-insert-u8.16 #:u16.16-insert-u16.8 #:u32.8-insert-u32.4 #:u64.4-insert-u64.2 + #:s8.32-insert-s8.16 #:s16.16-insert-s16.8 #:s32.8-insert-s32.4 #:s64.4-insert-s64.2 + #:u8.16-broadcast #:u16.8-broadcast #:u32.4-broadcast #:u64.2-broadcast + #:s8.16-broadcast #:s16.8-broadcast #:s32.4-broadcast #:s64.2-broadcast + #:u8.32-broadcast #:u16.16-broadcast #:u32.8-broadcast #:u64.4-broadcast + #:s8.32-broadcast #:s16.16-broadcast #:s32.8-broadcast #:s64.4-broadcast + #:u8.32-permute128 #:s8.32-permute128 + #:u32.8-permute128 #:s32.8-permute128 + #:s16.16-permute128 + #:s64.4-permute128 + #:f64.4-reverse + #:s64.2-shiftl + #:s64.2-shiftr + #:f32.4-non-temporal-aref #:f32.4-non-temporal-row-major-aref + #:f64.2-non-temporal-aref #:f64.2-non-temporal-row-major-aref + #:f32.8-non-temporal-aref #:f32.8-non-temporal-row-major-aref + #:f64.4-non-temporal-aref #:f64.4-non-temporal-row-major-aref + #:u8.16-non-temporal-aref #:u8.16-non-temporal-row-major-aref + #:u16.8-non-temporal-aref #:u16.8-non-temporal-row-major-aref + #:u32.4-non-temporal-aref #:u32.4-non-temporal-row-major-aref + #:u64.2-non-temporal-aref #:u64.2-non-temporal-row-major-aref + #:s8.16-non-temporal-aref #:s8.16-non-temporal-row-major-aref + #:s16.8-non-temporal-aref #:s16.8-non-temporal-row-major-aref + #:s32.4-non-temporal-aref #:s32.4-non-temporal-row-major-aref + #:s64.2-non-temporal-aref #:s64.2-non-temporal-row-major-aref + #:u8.32-non-temporal-aref #:u8.32-non-temporal-row-major-aref + #:u16.16-non-temporal-aref #:u16.16-non-temporal-row-major-aref + #:u32.8-non-temporal-aref #:u32.8-non-temporal-row-major-aref + #:u64.4-non-temporal-aref #:u64.4-non-temporal-row-major-aref + #:s8.32-non-temporal-aref #:s8.32-non-temporal-row-major-aref + #:s16.16-non-temporal-aref #:s16.16-non-temporal-row-major-aref + #:s32.8-non-temporal-aref #:s32.8-non-temporal-row-major-aref + #:s64.4-non-temporal-aref #:s64.4-non-temporal-row-major-aref) + #0# + #1# + #8# + #9= + (:export + ;; f32.8 + ;; f64.4 + #:f64.4-reverse + ;; u8.16 + ;; u16.8 + ;; u32.4 + #:u32.4-shiftl + #:u32.4-shiftr + ;; u64.2 + #:u64.2-shiftl + #:u64.2-shiftr + ;; s8.16 + ;; s16.8 + ;; s32.4 + #:s32.4-shiftl + #:s32.4-shiftr + ;; s64.2 + #:s64.2-shiftl + #:s64.2-shiftr + ;; u8.32 + #:u8.32-if + #:u8.32-and + #:u8.32-or + #:u8.32-xor + #:u8.32-andc1 + #:u8.32-not + #:u8.32-max + #:u8.32-min + #:u8.32+ + #:u8.32- + #:u8.32= + #:u8.32/= + #:u8.32> + #:u8.32< + #:u8.32>= + #:u8.32<= + #:u8.32-avg + #:u8.32-packus + #:u8.32-unpackhi + #:u8.32-unpacklo + #:u8.32-movemask + #:u8.32-permute128 + #:u8.16-from-u8.32 + #:u8.32-insert-u8.16 + ;; u16.16 + #:u16.16-from-u8.16 + #:u16.16-if + #:u16.16-and + #:u16.16-or + #:u16.16-xor + #:u16.16-andc1 + #:u16.16-not + #:u16.16-max + #:u16.16-min + #:u16.16+ + #:u16.16- + #:s16.16-mulhi + #:u16.16= + #:u16.16/= + #:u16.16> + #:u16.16< + #:u16.16>= + #:u16.16<= + #:u16.16-shiftl + #:u16.16-shiftr + #:u16.16-avg + #:u16.16-packus + #:u16.16-unpacklo + #:u16.16-unpackhi + #:u16.16-movemask + #:u16.8-from-u16.16 + #:u16.16-insert-u16.8 + #:u16.16-permute128 + ;; u32.8 + #:u32.8-from-u16.8 + #:u32.8-from-u8.16 + #:u32.8-if + #:u32.8-and + #:u32.8-or + #:u32.8-xor + #:u32.8-andc1 + #:u32.8-not + #:u32.8-max + #:u32.8-min + #:u32.8+ + #:u32.8- + #:u32.8= + #:u32.8/= + #:u32.8> + #:u32.8< + #:u32.8>= + #:u32.8<= + #:u32.8-shiftl + #:u32.8-shiftr + #:u32.8-unpacklo + #:u32.8-unpackhi + #:u32.8-movemask + #:u32.4-from-u32.8 + #:u32.8-insert-u32.4 + #:u32.8-permute128 + #:u32.8-incf + #:u32.8-decf + ;; u64.4 + #:u64.4-from-u16.8 + #:u64.4-from-u32.4 + #:u64.4-from-u8.16 + #:u64.4-if + #:u64.4-and + #:u64.4-or + #:u64.4-xor + #:u64.4-andc1 + #:u64.4-not + #:u64.4+ + #:u64.4- + #:u64.4-mul + #:u64.4= + #:u64.4/= + #:u64.4> + #:u64.4< + #:u64.4>= + #:u64.4<= + #:u64.4-shiftl + #:u64.4-shiftr + #:u64.4-unpacklo + #:u64.4-unpackhi + #:u64.4-movemask + #:u64.2-from-u64.4 + #:u64.4-insert-u64.2 + #:u64.4-permute128 + #:u64.4-incf + #:u64.4-decf + ;; s8.32 + #:s8.32-if + #:s8.32-and + #:s8.32-or + #:s8.32-xor + #:s8.32-andc1 + #:s8.32-not + #:s8.32-max + #:s8.32-max + #:s8.32+ + #:s8.32- + #:s32.8-mullo + #:s8.32= + #:s8.32/= + #:s8.32> + #:s8.32< + #:s8.32>= + #:s8.32<= + #:s8.32-abs + #:s8.32-packs + #:s8.32-unpacklo + #:s8.32-unpackhi + #:s8.32-movemask + #:s8.32-shuffle + #:s8.32-sign + #:s8.16-from-s8.32 + #:s8.32-insert-s8.16 + #:s8.32-permute128 + ;; s16.16 + #:s16.16-from-s8.16 + #:s16.16-from-u8.16 + #:s16.16-if + #:s16.16-and + #:s16.16-or + #:s16.16-xor + #:s16.16-andc1 + #:s16.16-not + #:s16.16-max + #:s16.16-min + #:s16.16+ + #:s16.16- + #:s16.16-mulhi + #:s16.16-mullo + #:s16.16-mulhrs + #:s16.16= + #:s16.16/= + #:s16.16> + #:s16.16< + #:s16.16>= + #:s16.16<= + #:s16.16-abs + #:s16.16-hadd + #:s16.16-hadds + #:s16.16-madd + #:s16.16-maddubs + #:s16.16-hsub + #:s16.16-hsubs + #:s16.16-packs + #:s16.16-unpackhi + #:s16.16-unpacklo + #:s16.16-movemask + #:s16.16-shiftl + #:s16.16-shiftr + #:s16.16-sign + #:s16.8-from-s16.16 + #:s16.16-insert-s16.8 + #:s16.16-permute128 + ;; s32.8 + #:s32.8-from-s16.8 + #:s32.8-from-u16.8 + #:s32.8-from-s8.16 + #:s32.8-from-u8.16 + #:s32.8-if + #:s32.8-and + #:s32.8-or + #:s32.8-xor + #:s32.8-andc1 + #:s32.8-not + #:s32.8-max + #:s32.8-min + #:s32.8+ + #:s32.8- + #:s32.8-mullo + #:s32.8= + #:s32.8/= + #:s32.8> + #:s32.8< + #:s32.8>= + #:s32.8<= + #:s32.8-abs + #:s32.8-hadd + #:s32.8-hsub + #:s32.8-shiftl + #:s32.8-shiftr + #:s32.8-sign + #:s32.8-unpacklo + #:s32.8-unpackhi + #:s32.8-movemask + #:s32.4-from-s32.8 + #:s32.8-insert-s32.4 + #:s32.8-permute128 + #:s32.8-incf + #:s32.8-decf + ;; s64.4 + #:s64.4-from-s16.8 + #:s64.4-from-u16.8 + #:s64.4-from-s32.4 + #:s64.4-from-u32.4 + #:s64.4-from-s8.16 + #:s64.4-from-u8.16 + #:s64.4-if + #:s64.4-and + #:s64.4-or + #:s64.4-xor + #:s64.4-andc1 + #:s64.4-not + #:s64.4+ + #:s64.4- + #:s64.4= + #:s64.4/= + #:s64.4> + #:s64.4< + #:s64.4>= + #:s64.4<= + #:s64.4-shiftl + #:s64.4-shiftr + #:s64.4-unpackhi + #:s64.4-unpacklo + #:s64.4-movemask + #:s64.2-from-s64.4 + #:s64.4-insert-s64.2 + #:s64.4-permute128 + #:s64.4-incf + #:s64.4-decf)) + + (defpackage #:sb-simd-fma + (:use #:common-lisp #:sb-simd-internals #:sb-simd-avx2) + #0# + #1# + #8# + #9# + #10= + (:export + ;; f32 + #:f32-fmadd + #:f32-fnmadd + #:f32-fmsub + #:f32-fmaddsub + #:f32-fmsubadd + ;; f64 + #:f64-fmadd + #:f64-fnmadd + #:f64-fmsub + #:f64-fmaddsub + #:f64-fmsubadd + ;; f32.4 + #:f32.4-fmadd + #:f32.4-fnmadd + #:f32.4-fmsub + #:f32.4-fmaddsub + #:f32.4-fmsubadd + ;; f32.8 + #:f32.8-fmadd + #:f32.8-fnmadd + #:f32.8-fmsub + #:f32.8-fmaddsub + #:f32.8-fmsubadd + ;; f64.2 + #:f64.2-fmadd + #:f64.2-fnmadd + #:f64.2-fmsub + #:f64.2-fmaddsub + #:f64.2-fmsubadd + ;; f64.4 + #:f64.4-fmadd + #:f64.4-fnmadd + #:f64.4-fmsub + #:f64.4-fmaddsub + #:f64.4-fmsubadd))) diff --git a/contrib/sb-simd/code/printable.lisp b/contrib/sb-simd/code/printable.lisp new file mode 100644 index 0000000000..dfed99d81b --- /dev/null +++ b/contrib/sb-simd/code/printable.lisp @@ -0,0 +1,24 @@ +(in-package #:sb-simd-internals) + +(defclass printable () ()) + +;;; Gather a plist of all class slots. We use this plist to conveniently +;;; define PRINT-OBJECT. +(defgeneric printable-slot-plist (printable) + (:method-combination append :most-specific-last)) + +(defmethod printable-slot-plist append (printable) + '()) + +(defmethod print-object ((printable printable) stream) + (print-unreadable-object (printable stream :type t) + (pprint-logical-block (stream (printable-slot-plist printable)) + (loop + (pprint-exit-if-list-exhausted) + (write (pprint-pop) :stream stream) + (pprint-exit-if-list-exhausted) + (write-char #\space stream) + (write (pprint-pop) :stream stream) + (pprint-exit-if-list-exhausted) + (write-char #\space stream) + (pprint-newline :linear stream))))) diff --git a/contrib/sb-simd/code/record.lisp b/contrib/sb-simd/code/record.lisp new file mode 100644 index 0000000000..02160e38aa --- /dev/null +++ b/contrib/sb-simd/code/record.lisp @@ -0,0 +1,1025 @@ +(in-package #:sb-simd-internals) + +;;; A record describes a particular function or data type. Macros later +;;; use the information stored in these records to generate most of the +;;; code of this library. + +(defclass record (printable) + ((%name + :type (or non-nil-symbol function-name) + :initarg :name + :initform (required-argument :name) + :reader record-name) + (%instruction-set + :type instruction-set + :initarg :instruction-set + :initform *instruction-set* + :reader record-instruction-set))) + +(defun record-p (x) + (typep x 'record)) + +;;; Ensure that the home package of the name of the record is the same as +;;; the package of its instruction set. +(defmethod shared-initialize :after + ((record record) slot-names &key &allow-other-keys) + (with-accessors ((name record-name) + (instruction-set record-instruction-set)) record + (let ((package (etypecase name + (symbol (symbol-package name)) + (function-name (symbol-package (second name)))))) + (unless (eq package (instruction-set-package instruction-set)) + (error "Wrong home package ~S for ~S record ~S." + (package-name package) + (instruction-set-name instruction-set) + name))))) + +(defmethod printable-slot-plist append ((record record)) + (list :name (record-name record) + :instruction-set (record-instruction-set record))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; +;;; Value Record +;;; +;;; A value record describes a specialized set of Common Lisp objects. +;;; Each value record consists of a Common Lisp type specifier, a +;;; corresponding primitive type specifier used by SBCL's VM, the number of +;;; bits required to represent all such objects, and a list of storage +;;; classes in which such objects can be stored. + +(defclass value-record (record) + (;; Define aliases for inherited slots. + (%name :reader value-record-name) + (%instruction-set :reader value-record-instruction-set) + ;; The Common Lisp type of this value. + (%type + :type type-specifier + :initarg :type + :initform (required-argument :type) + :reader value-record-type) + ;; The primitive type of this value as used by SBCL's VM. + (%primitive-type + :type type-specifier + :initarg :primitive-type + :initform (required-argument :primitive-type) + :reader value-record-primitive-type) + ;; The number of bits that are necessary to represent this value in + ;; memory. + (%bits + :type unsigned-byte + :initarg :bits + :initform (required-argument :bits) + :reader value-record-bits) + ;; A list of storage classes where this value can be placed. + (%scs + :type list + :initarg :scs + :initform (required-argument :scs) + :reader value-record-scs))) + +(defun value-record-p (x) + (typep x 'value-record)) + +(defmethod printable-slot-plist append ((value-record value-record)) + (list :type (value-record-type value-record) + :primitive-type (value-record-primitive-type value-record) + :bits (value-record-bits value-record) + :scs (value-record-scs value-record))) + +;;; A hash table, mapping from value record names to value records. +(declaim (hash-table *value-records*)) +(defparameter *value-records* (make-hash-table :test #'eq)) + +(defun find-value-record (name &optional (errorp t)) + (or (gethash name *value-records*) + (when errorp + (error "There is no value record with the name ~S." + name)))) + +(defmethod make-load-form ((value-record value-record) &optional env) + (declare (ignore env)) + `(find-value-record ',(value-record-name value-record))) + +(defun filter-value-records (predicate) + (loop for value-record being the hash-values of *value-records* + when (funcall predicate value-record) + collect value-record)) + +;;; Ensure that each value record is registered in the *VALUE-RECORDS* hash +;;; table. +(defmethod shared-initialize :after + ((value-record value-record) slot-names &key &allow-other-keys) + (setf (gethash (value-record-name value-record) *value-records*) + value-record)) + +;; Interns a string designator into the SB-VM package, while gracefully +;; handling the case where the symbol is not present. +(defun find-sc (sc) + (or (find-symbol (string sc) "SB-VM") + 'sb-vm::descriptor-reg)) + +;; Intern all symbols and strings in EXPR that have no home package in the +;; SB-VM package. +(defun find-primitive-type (expr) + (etypecase expr + (string (find-symbol expr "SB-VM")) + (symbol (if (null (symbol-package expr)) + (find-primitive-type (symbol-name expr)) + expr)) + (integer expr) + (list (mapcar #'find-primitive-type expr)))) + +(defmethod decode-record-definition ((_ (eql 'value-record)) expr) + (destructuring-bind (name bits type &optional (primitive-type 't) (scs '(#:descriptor-reg))) expr + `(let ((.value-record. + (make-instance 'value-record + :name ',name + :bits ,bits + :type ',type + :primitive-type ',(find-primitive-type primitive-type) + :scs ',(mapcar #'find-sc scs)))) + (make-instance 'scalar-cast-record + :name ',name + :result-record .value-record.)))) + +(defgeneric value-record-simd-width (value-record) + (:method ((value-record value-record)) 1)) + +(defgeneric value-record-cast-record (value-record) + (:method ((value-record value-record)) + (find-function-record (value-record-name value-record)))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; +;;; SIMD Record + +(defclass simd-record (value-record) + (;; Define aliases for inherited slots. + (%name :reader simd-record-name) + (%instruction-set :reader simd-record-instruction-set) + (%type :reader simd-record-type) + (%primitive-type :reader simd-record-primitive-type) + (%bits :reader simd-record-bits) + (%scs :reader simd-record-scs) + ;; The scalar record of the elements of this SIMD pack. + (%scalar-record + :type value-record + :initarg :scalar-record + :initform (required-argument :scalar-record) + :reader simd-record-scalar-record) + ;; The number of scalar elements in this SIMD pack. + (%width + :type unsigned-byte + :initarg :width + :initform (required-argument :width) + :reader value-record-simd-width))) + +(defun simd-record-p (x) + (typep x 'simd-record)) + +(defun scalar-record-p (x) + (typep x '(and value-record (not simd-record)))) + +(defmethod decode-record-definition ((_ (eql 'simd-record)) expr):w + (destructuring-bind (name scalar-record-name bits primitive-type scs) expr + (let ((simd-pack-type + (let ((base-type + (ecase bits + (128 (find-symbol "SIMD-PACK" "SB-EXT")) + (256 (find-symbol "SIMD-PACK-256" "SB-EXT"))))) + (cond ((not base-type) 't) + ((not scalar-record-name) base-type) + (t `(,base-type ,scalar-record-name)))))) + `(let ((.scalar-record. (find-value-record ',(or scalar-record-name (find-symbol "U64"))))) + (make-instance 'simd-record + :name ',name + :scalar-record .scalar-record. + :bits ',bits + :width (the unsigned-byte (/ ,bits (value-record-bits .scalar-record.))) + :type ',simd-pack-type + :primitive-type ',(find-primitive-type primitive-type) + :scs ',(mapcar #'find-sc scs)))))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; +;;; Function Record +;;; +;;; A function record describes one or more Common Lisp functions. +;;; Depending on its attributes, the function record will later be used to +;;; define zero or more VOPs, defknowns, deftransforms, defuns and compiler +;;; macros. + +(defclass function-record (record) + (;; Define aliases for inherited slots. + (%name :reader function-record-name) + (%instruction-set :reader function-record-instruction-set) + ;; The scalar function that is applied element-wise by the SIMD function + ;; denoted by this record, or NIL if the record doesn't denote such a + ;; SIMD function. + (%scalar-variant + :type (or function-record null) + :initarg :scalar-variant + :initform nil + :reader function-record-scalar-variant))) + +(defun function-record-p (x) + (typep x 'function-record)) + +(defgeneric function-record-result-records (function-record)) + +(defgeneric function-record-required-argument-records (function-record)) + +(defgeneric function-record-rest-argument-record (function-record) + (:method ((function-record function-record)) + nil)) + +(defgeneric function-record-result-record (function-record) + (:method ((function-record function-record)) + (let ((result-records (function-record-result-records function-record))) + (when (null result-records) + (error "Attempt to access the result record of a function that produces zero values.")) + (first result-records)))) + +(defun function-record-simd-width (function-record) + (value-record-simd-width + (function-record-result-record function-record))) + +(defmethod printable-slot-plist append ((function-record function-record)) + (list :argument-types + (let ((mandatory (function-record-required-argument-records function-record)) + (rest (function-record-rest-argument-record function-record))) + (if (not rest) + (mapcar #'value-record-name mandatory) + `(,@(mapcar #'value-record-name mandatory) &rest (value-record-name rest)))) + :result-records (function-record-result-records function-record))) + +(defun scalar-function-record-p (x) + (and (function-record-p x) + (not (null (function-record-result-records x))) + (notany #'simd-record-p (function-record-result-records x)))) + +(defun simd-function-record-p (x) + (and (function-record-p x) + (not (null (function-record-result-records x))) + (every #'simd-record-p (function-record-result-records x)))) + +;;; Automatically derive the :SCALAR-VARIANT keyword. +(defmethod shared-initialize :around + ((function-record function-record) slot-names &rest rest &key name &allow-other-keys) + (flet ((give-up () + (return-from shared-initialize (call-next-method)))) + (multiple-value-bind (symbol setf-p) (parse-function-name name) + (let* ((string (symbol-name symbol)) + (package (symbol-package symbol)) + (prefix-end (or (position #\. string) (give-up))) + (suffix-end (length string)) + (suffix-start (or (position-if-not #'digit-char-p string :start (1+ prefix-end)) suffix-end)) + (prefix (subseq string 0 prefix-end)) + (suffix (subseq string suffix-start suffix-end)) + (symbol (or (find-symbol (concatenate 'string prefix suffix) package) (give-up))) + (function-name (if setf-p `(setf ,symbol) symbol)) + (scalar-variant-record (or (find-function-record function-name nil) (give-up)))) + (apply #'call-next-method function-record slot-names + :scalar-variant scalar-variant-record + rest))))) + +;;; A hash table, mapping from instruction names to instruction records. +(declaim (hash-table *function-records*)) +(defparameter *function-records* (make-hash-table :test #'equal)) + +(defun find-function-record (name &optional (errorp t)) + (or (gethash name *function-records*) + (when errorp + (error "There is no function with the name ~S." + name)))) + +(defmethod make-load-form ((function-record function-record) &optional env) + (declare (ignore env)) + `(find-function-record ',(function-record-name function-record))) + +;;; Ensure that each function record is registered in *FUNCTION-RECORDS*, +;;; and that vectorizing functions are registered in their instruction set. +(defmethod shared-initialize :after + ((function-record function-record) slot-names &key &allow-other-keys) + (let ((scalar-variant (function-record-scalar-variant function-record))) + (unless (null scalar-variant) + (register-vectorizer scalar-variant function-record))) + (setf (gethash (function-record-name function-record) *function-records*) + function-record)) + +(defun filter-function-records (predicate) + (loop for function-record being the hash-values of *function-records* + when (funcall predicate function-record) + collect function-record)) + +(defun filter-available-function-records (predicate) + (filter-function-records + (lambda (function-record) + (and (instruction-set-available-p (function-record-instruction-set function-record)) + (funcall predicate function-record))))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; +;;; Reffer Records + +(defclass reffer-record (function-record) + ((%name :reader reffer-record-name) + (%instruction-set :reader reffer-record-instruction-set) + ;; A value record, describing which kinds of objects are loaded or stored. + (%result-records + :type list + :initarg :result-records + :initform (required-argument :result-records) + :reader function-record-result-records) + ;; A value record, describing what kind of array is being referenced. + (%array-record + :type value-record + :initarg :array-record + :initform (required-argument :array-record) + :reader reffer-record-array-record) + ;; A function record, denoting the underlying primitive load or store + ;; operation of that record. This primitive always accepts a + ;; one-dimensional array and a single row-major index as arguments. + (%primitive + :type (or function-record null) + :initarg :primitive + :initform nil + :reader reffer-record-primitive))) + +(defun reffer-record-p (x) + (typep x 'reffer-record)) + +(defmethod printable-slot-plist append ((reffer-record reffer-record)) + (list :array-record (reffer-record-array-record reffer-record))) + +(defclass aref-record (reffer-record) + (;; Define aliases for inherited slots. + (%name :reader aref-record-name) + (%instruction-set :reader aref-record-instruction-set))) + +(defun aref-record-p (x) + (typep x 'aref-record)) + +(defmethod function-record-required-argument-records + ((aref-record aref-record)) + (list (reffer-record-array-record aref-record))) + +(defmethod function-record-rest-argument-record + ((aref-record aref-record)) + (find-value-record 'sb-simd:index)) + +(defclass row-major-aref-record (reffer-record) + (;; Define aliases for inherited slots. + (%name :reader row-major-aref-record-name) + (%instruction-set :reader row-major-aref-record-instruction-set))) + +(defun row-major-aref-record-p (x) + (typep x 'row-major-aref-record)) + +(defmethod function-record-required-argument-records + ((row-major-aref-record row-major-aref-record)) + (list (reffer-record-array-record row-major-aref-record) + (find-value-record 'sb-simd:index))) + +(defclass setf-aref-record (reffer-record) + (;; Define aliases for inherited slots. + (%name :reader setf-aref-record-name) + (%instruction-set :reader setf-aref-record-instruction-set))) + +(defun setf-aref-record-p (x) + (typep x 'setf-aref-record)) + +(defmethod function-record-required-argument-records + ((setf-aref-record setf-aref-record)) + (list (function-record-result-record setf-aref-record) + (reffer-record-array-record setf-aref-record))) + +(defmethod function-record-rest-argument-record + ((setf-aref-record setf-aref-record)) + (find-value-record 'sb-simd:index)) + +(defclass setf-row-major-aref-record (reffer-record) + (;; Define aliases for inherited slots. + (%name :reader setf-row-major-aref-record-name) + (%instruction-set :reader setf-row-major-aref-record-instruction-set))) + +(defun setf-row-major-aref-record-p (x) + (typep x 'setf-row-major-aref-record)) + +(defmethod function-record-required-argument-records + ((setf-row-major-aref-record setf-row-major-aref-record)) + (list (function-record-result-record setf-row-major-aref-record) + (reffer-record-array-record setf-row-major-aref-record) + (find-value-record 'sb-simd:index))) + +(defmethod decode-record-definition ((_ (eql 'reffer-record)) expr) + (destructuring-bind (type array-type aref row-major-aref) expr + `(let ((.value-record. (find-value-record ',type)) + (.array-record. (find-value-record ',array-type))) + (let ((.primitive. (make-instance 'row-major-aref-record + :name ',row-major-aref + :array-record .array-record. + :result-records (list .value-record.)))) + (make-instance 'aref-record + :name ',aref + :array-record .array-record. + :primitive .primitive. + :result-records (list .value-record.))) + (let ((.primitive. (make-instance 'setf-row-major-aref-record + :name '(setf ,row-major-aref) + :array-record .array-record. + :result-records (list .value-record.)))) + (make-instance 'setf-aref-record + :name '(setf ,aref) + :array-record .array-record. + :primitive .primitive. + :result-records (list .value-record.)))))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; +;;; Instruction Record +;;; +;;; An instruction record describes a function that can more or less +;;; directly be expressed as a single assembler instruction. + +(defclass instruction-record (function-record) + (;; Define aliases for inherited slots. + (%name :reader instruction-record-name) + (%instruction-set :reader instruction-record-instruction-set) + ;; The name of the VOP that translates this instruction. + (%vop + :type non-nil-symbol + :initarg :vop + :initform (required-argument :vop) + :reader instruction-record-vop) + ;; The mnemonic that is used within the VOP to emit this instruction. + (%mnemonic + :type symbol + :initarg :mnemonic + :initform (required-argument :mnemonic) + :reader instruction-record-mnemonic) + ;; A list of value records - one for each result. + (%result-records + :type list + :initarg :result-records + :initform (required-argument :result-records) + :reader instruction-record-result-records + :reader function-record-result-records) + ;; A list of value records - one for each argument. + (%argument-records + :type list + :initarg :argument-records + :initform (required-argument :argument-records) + :reader function-record-required-argument-records + :reader instruction-record-argument-records) + ;; A rough estimate of the cost of executing that instruction. + (%cost + :type unsigned-byte + :initarg :cost + :initform 1 + :reader instruction-record-cost) + ;; Whether this instruction satisfies (INST a b) = (INST b a). + (%associative + :type boolean + :initarg :associative + :initform nil + :reader instruction-record-associative) + ;; Whether this instruction is free of side-effects. + (%pure + :type boolean + :initarg :pure + :initform t + :reader instruction-record-pure) + ;; Whether this instruction can always be translated into a VOP. + (%always-translatable + :type boolean + :initarg :always-translatable + :initform t + :reader instruction-record-always-translatable) + ;; How the instruction is turned into a VOP. + (%encoding + :type (member :standard :sse :sse+xmm0 :custom :fake-vop :move :fma) + :initarg :encoding + :initform :standard + :reader instruction-record-encoding) + ;; A list that, if provided, supplies the first arguments to the + ;; mnemonic. + (%prefix + :type list + :initarg :prefix + :initform '() + :reader instruction-record-prefix) + ;; A list that, if provided, supplies the last arguments to the + ;; mnemonic. + (%suffix + :type list + :initarg :suffix + :initform '() + :reader instruction-record-suffix))) + +(defun instruction-record-p (x) + (typep x 'instruction-record)) + +(defmethod printable-slot-plist append ((instruction-record instruction-record)) + (list :vop (instruction-record-vop instruction-record) + :mnemonic (instruction-record-mnemonic instruction-record) + :pure (instruction-record-pure instruction-record) + :always-translatable (instruction-record-always-translatable instruction-record) + :encoding (instruction-record-encoding instruction-record) + :prefix (instruction-record-prefix instruction-record) + :suffix (instruction-record-suffix instruction-record))) + +(defmethod decode-record-definition ((_ (eql 'instruction-record)) expr) + (destructuring-bind (name mnemonic result-record-names argument-record-names &rest rest) expr + `(make-instance 'instruction-record + :name ',name + :vop ',(mksym (symbol-package name) "%" name) + :mnemonic ',(find-symbol (string mnemonic) sb-assem::*backend-instruction-set-package*) + :result-records (mapcar #'find-value-record ',result-record-names) + :argument-records (mapcar #'find-value-record ',argument-record-names) + ,@rest))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; +;;; Vref Record +;;; +;;; A vref record describes either a load or store instruction. + +(defclass vref-record (function-record) + (;; Define aliases for inherited slots. + (%name :reader vref-record-name) + (%instruction-set :reader vref-record-instruction-set) + ;; The name of the VOP that translates this instruction. + (%vop + :type non-nil-symbol + :initarg :vop + :initform (required-argument :vop) + :reader vref-record-vop) + ;; The name of the VOP that translates this instruction when the + ;; supplied index is a constant. + (%vop-c + :type non-nil-symbol + :initarg :vop-c + :initform (required-argument :vop-c) + :reader vref-record-vop-c) + ;; The mnemonic that is used within the VOP to emit this instruction. + (%mnemonic + :type symbol + :initarg :mnemonic + :initform (required-argument :mnemonic) + :reader vref-record-mnemonic) + ;; A value record, describing which kinds of objects are loaded or stored. + (%value-record + :type value-record + :initarg :value-record + :initform (required-argument :value-record) + :reader vref-record-value-record) + ;; A value record, describing the vector being read from or written to. + (%vector-record + :type value-record + :initarg :vector-record + :initform (required-argument :vector-record) + :reader vref-record-vector-record) + ;; The name of the n-dimensional accessor to be generated. + (%aref + :type function-name + :initarg :aref + :initform (required-argument :aref) + :reader vref-record-aref) + ;; The name of the vector accessor to be generated. + (%row-major-aref + :type function-name + :initarg :row-major-aref + :initform (required-argument :row-major-aref) + :reader vref-record-row-major-aref))) + +(defun vref-record-p (x) + (typep x 'vref-record)) + +(defmethod printable-slot-plist append ((vref-record vref-record)) + (list :vop (vref-record-vop vref-record) + :vop-c (vref-record-vop-c vref-record) + :mnemonic (vref-record-mnemonic vref-record) + :vector-record (vref-record-vector-record vref-record) + :aref (vref-record-aref vref-record) + :row-major-aref (vref-record-row-major-aref vref-record))) + +(defmethod function-record-result-records ((vref-record vref-record)) + (list + (vref-record-value-record vref-record))) + +(defun decode-vref-record-definition (expr instance) + (destructuring-bind (name mnemonic value-type vector-type array-type aref row-major-aref &rest rest) expr + `(let* ((.value-record. (find-value-record ',value-type)) + (.vector-record. (find-value-record ',vector-type)) + (.array-record. (find-value-record ',array-type)) + (.primitive. + (make-instance ',instance + :name ',name + :vop ',(mksym (symbol-package name) "%" name) + :vop-c ',(mksym (symbol-package name) "%" name "-C") + :mnemonic ',(find-symbol (string mnemonic) sb-assem::*backend-instruction-set-package*) + :value-record .value-record. + :vector-record .vector-record. + :aref ',aref + :row-major-aref ',row-major-aref + ,@rest))) + ,(if (eq instance 'load-record) + `(make-instance 'row-major-aref-record + :name ',row-major-aref + :array-record .array-record. + :primitive .primitive. + :result-records (list .value-record.)) + `(make-instance 'setf-row-major-aref-record + :name '(setf ,row-major-aref) + :array-record .array-record. + :primitive .primitive. + :result-records (list .value-record.))) + ,(if (eq instance 'load-record) + `(make-instance 'aref-record + :name ',aref + :array-record .array-record. + :primitive .primitive. + :result-records (list .value-record.)) + `(make-instance 'setf-aref-record + :name '(setf ,aref) + :array-record .array-record. + :primitive .primitive. + :result-records (list .value-record.)))))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; +;;; Load Record + +(defclass load-record (vref-record) + (;; Define aliases for inherited slots. + (%name :reader load-record-name) + (%instruction-set :reader load-record-instruction-set) + (%vop :reader load-record-vop) + (%vop-c :reader load-record-vop-c) + (%mnemonic :reader load-record-mnemonic) + (%value-record :reader load-record-value-record) + (%vector-record :reader load-record-vector-record) + (%aref :reader load-record-aref) + (%row-major-aref :reader load-record-row-major-aref))) + +(defun load-record-p (x) + (typep x 'load-record)) + +(defmethod function-record-required-argument-records ((load-record load-record)) + (list (load-record-vector-record load-record) + (find-value-record 'sb-simd:index))) + +(defmethod decode-record-definition ((_ (eql 'load-record)) expr) + (decode-vref-record-definition expr 'load-record)) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; +;;; Store Record + +(defclass store-record (vref-record) + (;; Define aliases for inherited slots. + (%name :reader store-record-name) + (%instruction-set :reader store-record-instruction-set) + (%vop :reader store-record-vop) + (%vop-c :reader store-record-vop-c) + (%mnemonic :reader store-record-mnemonic) + (%value-record :reader store-record-value-record) + (%vector-record :reader store-record-vector-record) + (%aref :reader store-record-aref) + (%row-major-aref :reader store-record-row-major-aref))) + +(defun store-record-p (x) + (typep x 'store-record)) + +(defmethod function-record-required-argument-records ((store-record store-record)) + (list (store-record-value-record store-record) + (store-record-vector-record store-record) + (find-value-record 'sb-simd:index))) + +(defmethod decode-record-definition ((_ (eql 'store-record)) expr) + (decode-vref-record-definition expr 'store-record)) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; +;;; Associative Record + +(defclass associative-record (function-record) + (;; Define aliases for inherited slots. + (%name :reader associative-record-name) + (%instruction-set :reader associative-record-instruction-set) + ;; The binary operation used to combine the arguments. + (%binary-operation + :initarg :binary-operation + :initform (required-argument :binary-operation) + :reader associative-record-binary-operation) + ;; The identity for that operation, or NIL if there is none. + (%identity-element + :initarg :identity-element + :initform (required-argument :identity-element) + :reader associative-record-identity-element))) + +(defun associative-record-p (x) + (typep x 'associative-record)) + +(defmethod function-record-result-records ((associative-record associative-record)) + (function-record-result-records + (associative-record-binary-operation associative-record))) + +(defmethod function-record-required-argument-records ((associative-record associative-record)) + (if (not (associative-record-identity-element associative-record)) + (list (function-record-rest-argument-record associative-record)) + (list))) + +(defmethod function-record-rest-argument-record ((associative-record associative-record)) + (first (function-record-required-argument-records + (associative-record-binary-operation associative-record)))) + +(defmethod decode-record-definition ((_ (eql 'associative-record)) expr) + (destructuring-bind (name binary-operation identity-element &rest rest) expr + `(let* ((.binary-operation. (find-function-record ',binary-operation)) + (.value-record. (function-record-result-record .binary-operation.))) + (make-instance 'associative-record + :name ',name + :binary-operation .binary-operation. + ;; We can safely use NIL to denote the case where no identity + ;; element is supplied, because our associative functions operate on + ;; numbers only. + :identity-element ,identity-element + ,@rest)))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; +;;; Reducer Record + +(defclass reducer-record (function-record) + (;; Define aliases for inherited slots. + (%name :reader reducer-record-name) + (%instruction-set :reader reducer-record-instruction-set) + ;; The binary operation used to reduce the arguments. + (%binary-operation + :initarg :binary-operation + :initform (required-argument :binary-operation) + :reader reducer-record-binary-operation) + ;; The initial element for the reduction. + (%initial-element + :initarg :initial-element + :initform (required-argument :initial-element) + :reader reducer-record-initial-element))) + +(defun reducer-record-p (x) + (typep x 'reducer-record)) + +(defmethod function-record-result-records ((reducer-record reducer-record)) + (function-record-result-records + (reducer-record-binary-operation reducer-record))) + +(defmethod function-record-required-argument-records ((reducer-record reducer-record)) + (list (function-record-rest-argument-record reducer-record))) + +(defmethod function-record-rest-argument-record ((reducer-record reducer-record)) + (first (function-record-required-argument-records + (reducer-record-binary-operation reducer-record)))) + +(defmethod decode-record-definition ((_ (eql 'reducer-record)) expr) + (destructuring-bind (name binary-operation initial-element &rest rest) expr + `(make-instance 'reducer-record + :name ',name + :binary-operation (find-function-record ',binary-operation) + :initial-element ,initial-element + ,@rest))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; +;;; Comparison Record + +(defclass comparison-record (function-record) + (;; Define aliases for inherited slots. + (%name :reader comparison-record-name) + (%instruction-set :reader comparison-record-instruction-set) + ;; The binary comparison function. + (%cmp + :type instruction-record + :initarg :cmp + :initform (required-argument :cmp) + :reader comparison-record-cmp) + ;; The function for combining the results of some comparisons. + (%and + :type function-record + :initarg :and + :initform (required-argument :and) + :reader comparison-record-and) + ;; The truth value returned for an empty comparison. + (%truth + :initarg :truth + :initform (required-argument :truth) + :reader comparison-record-truth))) + +(defun comparison-record-p (x) + (typep x 'comparison-record)) + +(defmethod function-record-result-records ((comparison-record comparison-record)) + (function-record-result-records + (comparison-record-and comparison-record))) + +(defmethod function-record-required-argument-records ((comparison-record comparison-record)) + (list (function-record-rest-argument-record comparison-record))) + +(defmethod function-record-rest-argument-record ((comparison-record comparison-record)) + (first (function-record-required-argument-records (comparison-record-cmp comparison-record)))) + +(defmethod decode-record-definition ((_ (eql 'comparison-record)) expr) + (destructuring-bind (name cmp and truth &rest rest) expr + `(make-instance 'comparison-record + :name ',name + :cmp (find-function-record ',cmp) + :and (find-function-record ',and) + :truth ,truth + ,@rest))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; +;;; Unequal Record + +(defclass unequal-record (function-record) + (;; Define aliases for inherited slots. + (%name :reader unequal-record-name) + (%instruction-set :reader unequal-record-instruction-set) + ;; The binary unequal function. + (%neq + :type instruction-record + :initarg :neq + :initform (required-argument :neq) + :reader unequal-record-neq) + ;; The function for combining the results of some unequals. + (%and + :type function-record + :initarg :and + :initform (required-argument :and) + :reader unequal-record-and) + ;; The truth value returned for an empty unequal. + (%truth + :initarg :truth + :initform (required-argument :truth) + :reader unequal-record-truth))) + +(defun unequal-record-p (x) + (typep x 'unequal-record)) + +(defmethod function-record-result-records ((unequal-record unequal-record)) + (function-record-result-records + (unequal-record-and unequal-record))) + +(defmethod function-record-required-argument-records ((unequal-record unequal-record)) + (list (function-record-rest-argument-record unequal-record))) + +(defmethod function-record-rest-argument-record ((unequal-record unequal-record)) + (first (function-record-required-argument-records (unequal-record-neq unequal-record)))) + +(defmethod decode-record-definition ((_ (eql 'unequal-record)) expr) + (destructuring-bind (name neq and truth &rest rest) expr + `(make-instance 'unequal-record + :name ',name + :neq (find-function-record ',neq) + :and (find-function-record ',and) + :truth ,truth + ,@rest))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; +;;; If Record + +(defclass if-record (function-record) + (;; Define aliases for inherited slots. + (%name :reader if-record-name) + (%instruction-set :reader if-record-instruction-set) + ;; The blend instruction used to implement this function + (%blend + :type instruction-record + :initarg :blend + :initform (required-argument :blend) + :reader if-record-blend))) + +(defun if-record-p (x) + (typep x 'if-record)) + +(defmethod function-record-result-records ((if-record if-record)) + (function-record-result-records + (if-record-blend if-record))) + +(defmethod function-record-required-argument-records ((if-record if-record)) + (destructuring-bind (a b mask) + (function-record-required-argument-records (if-record-blend if-record)) + (list mask a b))) + +(defmethod decode-record-definition ((_ (eql 'if-record)) expr) + (destructuring-bind (name blend &rest rest) expr + `(make-instance 'if-record + :name ',name + :blend (find-function-record ',blend) + ,@rest))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; +;;; Cast Record + +(defclass cast-record (function-record) + (;; Define aliases for inherited slots. + (%name :reader cast-record-name) + (%instruction-set :reader cast-record-instruction-set) + ;; A value record describing the result of the cast. + (%result-record + :type value-record + :initarg :result-record + :initform (required-argument :result-record) + :reader cast-record-result-record + :reader function-record-result-record))) + +(defun cast-record-p (x) + (typep x 'cast-record)) + +(defmethod function-record-result-records ((cast-record cast-record)) + (list (cast-record-result-record cast-record))) + +(defmethod function-record-required-argument-records ((cast-record cast-record)) + (list (find-value-record 'sb-simd::any))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; +;;; Scalar Cast Record + +(defclass scalar-cast-record (cast-record) + (;; Define aliases for inherited slots. + (%name :reader scalar-cast-record-name) + (%instruction-set :reader scalar-cast-record-instruction-set))) + +(defun scalar-cast-record-p (x) + (typep x 'scalar-cast-record)) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; +;;; SIMD Cast Record + +(defclass simd-cast-record (cast-record) + (;; Define aliases for inherited slots. + (%name :reader simd-cast-record-name) + (%instruction-set :reader simd-cast-record-instruction-set) + ;; The broadcast instruction used to implement this function + (%broadcast + :type instruction-record + :initarg :broadcast + :initform (required-argument :broadcast) + :reader simd-cast-record-broadcast))) + +(defun simd-cast-record-p (x) + (typep x 'simd-cast-record)) + +(defmethod function-record-result-records ((simd-cast-record simd-cast-record)) + (function-record-result-records + (simd-cast-record-broadcast simd-cast-record))) + +(defmethod function-record-required-argument-records ((simd-cast-record simd-cast-record)) + (list (find-value-record 'sb-simd::any))) + +(defmethod decode-record-definition ((_ (eql 'simd-cast-record)) expr) + (destructuring-bind (name broadcast) expr + `(let ((.broadcast. (find-function-record ',broadcast))) + (make-instance 'simd-cast-record + :name ',name + :result-record (function-record-result-record .broadcast.) + :broadcast .broadcast.)))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; +;;; Reinterpret Cast Record + +(defclass reinterpret-cast-record (function-record) + (;; Define aliases for inherited slots. + (%name :reader reinterpret-cast-record-name) + (%instruction-set :reader reinterpret-cast-record-instruction-set) + (%reinterpreters + :type list + :initarg :reinterpreters + :initform (required-argument :reinterpreters) + :reader reinterpret-cast-record-reinterpreters))) + +(defun reinterpret-cast-record-p (x) + (typep x 'reinterpret-cast-record)) + +(defmethod function-record-result-records ((reinterpret-cast-record reinterpret-cast-record)) + (function-record-result-records + (first + (reinterpret-cast-record-reinterpreters reinterpret-cast-record)))) + +(defmethod function-record-required-argument-records ((reinterpret-cast-record reinterpret-cast-record)) + (list (find-value-record 'sb-simd::any))) + +(defmethod decode-record-definition ((_ (eql 'reinterpret-cast-record)) expr) + (destructuring-bind (name &rest reinterpreters) expr + `(make-instance 'reinterpret-cast-record + :name ',name + :reinterpreters + (list + ,@(loop for reinterpreter in reinterpreters + collect `(find-function-record ',reinterpreter)))))) diff --git a/contrib/sb-simd/code/sb-simd.asd b/contrib/sb-simd/code/sb-simd.asd new file mode 100644 index 0000000000..e0c1a085ee --- /dev/null +++ b/contrib/sb-simd/code/sb-simd.asd @@ -0,0 +1,48 @@ +(defsystem #:sb-simd + :description "A convenient SIMD interface for SBCL." + :author "Marco Heisig " + :license "MIT" + + :serial t + :components + ((:file "packages") + (:file "constants") + (:file "utilities") + (:file "printable") + (:file "cpu-identification") + (:file "instruction-set") + (:file "instruction-set-case") + (:file "record") + (:file "missing-instruction") + (:module "instruction-sets" + :components + ((:file "sb-simd") + (:file "x86-64") + (:file "sse") + (:file "sse2") + (:file "sse3") + (:file "ssse3") + (:file "sse4-1") + (:file "sse4-2") + (:file "avx") + (:file "avx2") + (:file "fma"))) + (:file "define-types") + (:file "define-instruction-vops") + (:file "define-vref-vops") + (:file "define-custom-vops") + (:file "define-vop-functions") + (:file "define-scalar-casts") + (:file "define-fake-vops") + (:file "define-simd-casts") + (:file "define-instructions") + (:file "define-vrefs") + (:file "define-reffers") + (:file "define-arefs") + (:file "define-ifs") + (:file "define-associatives") + (:file "define-reducers") + (:file "define-comparisons") + (:file "define-unequals") + (:file "define-rounders") + (:file "define-modify-macros"))) diff --git a/contrib/sb-simd/code/utilities.lisp b/contrib/sb-simd/code/utilities.lisp new file mode 100644 index 0000000000..bec5a53310 --- /dev/null +++ b/contrib/sb-simd/code/utilities.lisp @@ -0,0 +1,106 @@ +(in-package #:sb-simd-internals) + +;;; Types + +(deftype type-specifier () + '(or symbol cons)) + +(deftype non-nil-symbol () + '(and symbol (not null))) + +(deftype function-name () + '(or non-nil-symbol (cons (eql setf) (cons non-nil-symbol null)))) + +(deftype index () + '(integer + (#.(- (1- array-total-size-limit))) + (#.(1- array-total-size-limit)))) + +;;; Functions + +(defun index+ (&rest indices) + (the index (apply #'+ indices))) + +(define-compiler-macro index+ (&rest indices) + `(the index (+ ,@(loop for index in indices collect `(the index ,index))))) + +(defun index- (index &rest more-indices) + (the index (apply #'- index more-indices))) + +(define-compiler-macro index- (index &rest more-indices) + `(the index (- (the index ,index) ,@(loop for index in more-indices collect `(the index ,index))))) + +(defun index* (&rest indices) + (the index (apply #'* indices))) + +(define-compiler-macro index* (&rest indices) + `(the index (* ,@(loop for index in indices collect `(the index ,index))))) + +(defun ensure-package (name) + (or (find-package name) + (make-package name))) + +(defun mksym (package &rest string-designators) + (intern + (apply #'concatenate 'string (mapcar #'string string-designators)) + package)) + +(defun prefixed-symbols (prefix n &optional (package *package*)) + (loop for index below n + collect + (mksym package prefix (format nil "~D" index)))) + +(declaim (notinline touch)) +(defun touch (&rest arguments &aux value) + (declare (ignore arguments)) + (declare (special value)) + (values-list (loop repeat (random 100) collect value))) + +(defun required-argument (initarg) + (error "Required argument: ~S" initarg)) + +(defun macroexpand-all (form &optional env) + (let ((sb-walker::*walk-form-expand-macros-p* t)) + (sb-walker:walk-form form env))) + +(defun ensure-list (x) + (if (listp x) + x + (list x))) + +(defun lambda-expression-p (x) + (and (listp x) + (> (list-length x) 1) + (eq (first x) 'lambda) + (listp (second x)))) + +(defun parse-function-name (function-name) + (typecase function-name + (non-nil-symbol + (values function-name nil)) + ((cons (eql setf) (cons non-nil-symbol null)) + (values (second function-name) t)) + (otherwise + (error "Not a valid function name: ~S" function-name)))) + +;;; Macros + +(defmacro define-inline (name lambda-list &body body) + `(progn + (declaim (inline ,name)) + (defun ,name ,lambda-list ,@body))) + +(defmacro define-notinline (name lambda-list &body body) + `(progn + (declaim (notinline ,name)) + (defun ,name ,lambda-list ,@body))) + +(defun integer-type-specifier-inclusive-bounds (type-specifier) + (assert (= 2 (length type-specifier))) + (let ((bits (the (integer 1) (second type-specifier)))) + (ecase (first type-specifier) + (unsigned-byte + (values 0 (1- (expt 2 bits)))) + (signed-byte + (values (- (expt 2 (1- bits))) + (1- (expt 2 (1- bits)))))))) diff --git a/contrib/sb-simd/examples/benchmarks.lisp b/contrib/sb-simd/examples/benchmarks.lisp new file mode 100755 index 0000000000..6859206ef9 --- /dev/null +++ b/contrib/sb-simd/examples/benchmarks.lisp @@ -0,0 +1,281 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Benchmarking code +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +(asdf:load-system :sb-simd) +(ql:quickload :alexandria :silent t) +(use-package :sb-simd-avx) + +(defmacro time-total (n &body body) + "N-average the execution time of BODY in seconds" + (declare (optimize (speed 0))) + (alexandria:with-gensyms (start end) + `(let (,start ,end) + (sb-ext:gc :full t) + (setf ,start (get-internal-real-time)) + (loop for i below ,n + do ,@body) + (setf ,end (get-internal-real-time)) + (coerce (/ (- ,end ,start) internal-time-units-per-second) + 'float)))) + +(defun simd-sum (array &aux (n (array-total-size array))) + (declare (type f64vec array) + (optimize speed (safety 0))) + (do ((index 0 (the (integer 0 #.(- array-total-size-limit 16)) (+ index 16))) + (acc1 (f64.4 0) (f64.4+ acc1 (f64.4-aref array (+ index 0)))) + (acc2 (f64.4 0) (f64.4+ acc2 (f64.4-aref array (+ index 4)))) + (acc3 (f64.4 0) (f64.4+ acc3 (f64.4-aref array (+ index 8)))) + (acc4 (f64.4 0) (f64.4+ acc4 (f64.4-aref array (+ index 12))))) + ((> index (- n 16)) + (do ((result (multiple-value-call #'+ (f64.4-values (f64.4+ acc1 acc2 acc3 acc4))) + (+ result (row-major-aref array index))) + (index index (1+ index))) + ((>= index n) result))))) + +(defun simd-vdot (array1 array2 &aux (n (min (array-total-size array1) (array-total-size array2)))) + (declare (type f64vec array1 array2) + (optimize speed (safety 0))) + (do ((index 0 (the (integer 0 #.(- array-total-size-limit 16)) (+ index 16))) + (acc1 (f64.4 0) (f64.4-incf acc1 (f64.4* (f64.4-aref array1 (+ index 0)) + (f64.4-aref array2 (+ index 0))))) + (acc2 (f64.4 0) (f64.4-incf acc2 (f64.4* (f64.4-aref array1 (+ index 4)) + (f64.4-aref array2 (+ index 4))))) + (acc3 (f64.4 0) (f64.4-incf acc3 (f64.4* (f64.4-aref array1 (+ index 8)) + (f64.4-aref array2 (+ index 8))))) + (acc4 (f64.4 0) (f64.4-incf acc4 (f64.4* (f64.4-aref array1 (+ index 12)) + (f64.4-aref array2 (+ index 12)))))) + ((> index (- n 16)) + (do ((result (multiple-value-call #'+ (f64.4-values (f64.4+ acc1 acc2 acc3 acc4))) + (+ result (* (row-major-aref array1 index) + (row-major-aref array2 index)))) + (index index (1+ index))) + ((>= index n) result))))) + +;; For some reasons it floating-point-overflows +(defun fma-vdot (array1 array2 &aux (n (min (array-total-size array1) (array-total-size array2)))) + (declare (type f64vec array1 array2) + (optimize speed (safety 0))) + (do ((index 0 (the (integer 0 #.(- array-total-size-limit 16)) (+ index 16))) + (acc1 (f64.4 0) (setf acc1 (sb-simd-avx2:f64.4-fmadd acc1 (f64.4-aref array1 (+ index 0)) + (f64.4-aref array2 (+ index 0))))) + (acc2 (f64.4 0) (setf acc2 (sb-simd-avx2:f64.4-fmadd acc2 (f64.4-aref array1 (+ index 4)) + (f64.4-aref array2 (+ index 4))))) + (acc3 (f64.4 0) (setf acc3 (sb-simd-avx2:f64.4-fmadd acc3 (f64.4-aref array1 (+ index 8)) + (f64.4-aref array2 (+ index 8))))) + (acc4 (f64.4 0) (setf acc4 (sb-simd-avx2:f64.4-fmadd acc4 (f64.4-aref array1 (+ index 12)) + (f64.4-aref array2 (+ index 12)))))) + ((> index (- n 16)) + (do ((result (f64.4-hsum (f64.4+ acc1 acc2 acc3 acc4)) + (+ result (* (row-major-aref array1 index) + (row-major-aref array2 index)))) + (index index (1+ index))) + ((>= index n) result))))) + +(declaim (inline f64.4-fma-vdot)) +(defun f64.4-fma-vdot (array1 array2 &aux (n (min (array-total-size array1) + (array-total-size array2)))) + (declare (optimize (speed 3) (safety 0) (debug 0)) + (type f64vec array1 array2)) + (let ((n0 (- n (mod n 16)))) + (+ (loop with acc1 of-type f64.4 = (f64.4 0) + with acc2 of-type f64.4 = (f64.4 0) + with acc3 of-type f64.4 = (f64.4 0) + with acc4 of-type f64.4 = (f64.4 0) + for i of-type fixnum below n0 by 16 + do (let ((array1-i0 (f64.4-aref array1 (+ i 0))) + (array1-i4 (f64.4-aref array1 (+ i 4))) + (array1-i8 (f64.4-aref array1 (+ i 8))) + (array1-i12 (f64.4-aref array1 (+ i 12)))) + (setf acc1 (sb-simd-avx2:f64.4-fmadd acc1 array1-i0 + (f64.4-aref array2 (+ i 0))) + acc2 (sb-simd-avx2:f64.4-fmadd acc2 array1-i4 + (f64.4-aref array2 (+ i 4))) + acc3 (sb-simd-avx2:f64.4-fmadd acc3 array1-i8 + (f64.4-aref array2 (+ i 8))) + acc4 (sb-simd-avx2:f64.4-fmadd acc4 array1-i12 + (f64.4-aref array2 (+ i 12))))) + finally (return (f64.4-hsum (f64.4+ acc1 acc2 acc3 acc4)))) + (loop for i of-type fixnum from n0 below n + summing (* (aref array1 i) (aref array2 i)) + into sum of-type double-float + finally (return sum))))) + +(defun benchmark-f64.4-vdot-double (&rest v-lengths) + (declare (optimize (speed 3) (safety 0) (debug 0)) + (notinline sb-simd-avx2:f64.4-vdot)) + (loop for len in v-lengths + do (format t "Doing dot product of two ~A long double float vectors 1e6 times~%" len) + collect (let ((u (make-array len :element-type 'double-float + :initial-contents + (mapcar (lambda (i) (+ i 0.1d0)) + (alexandria:iota len)))) + (v (make-array len :element-type 'double-float + :initial-contents + (mapcar (lambda (i) (+ i 0.2d0)) + (alexandria:iota len))))) + (declare (type f64vec u v)) + (time-total 1e6 (sb-simd-avx2::f64.4-vdot u v))))) + +(defun benchmark-f64.4-vdot2-double (&rest v-lengths) + (declare (optimize (speed 3) (safety 0) (debug 0)) + (notinline sb-simd-avx2:f64.4-vdot2)) + (loop for len in v-lengths + do (format t "Doing dot product of two ~A long double float vectors 1e6 times~%" len) + collect (let ((u (make-array len :element-type 'double-float + :initial-contents + (mapcar (lambda (i) (+ i 0.1d0)) + (alexandria:iota len)))) + (v (make-array len :element-type 'double-float + :initial-contents + (mapcar (lambda (i) (+ i 0.2d0)) + (alexandria:iota len))))) + (declare (type f64vec u v)) + (time-total 1e6 (sb-simd-avx2::f64.4-vdot2 u v))))) + +(defun benchmark-f64.4-fma-vdot-double (&rest v-lengths) + (declare (optimize (speed 3) (safety 0) (debug 0)) + (notinline f64.4-fma-vdot)) + (loop for len in v-lengths + do (format t "Doing dot product of two ~A long double float vectors 1e6 times~%" len) + collect (let ((u (make-array len :element-type 'double-float + :initial-contents + (mapcar (lambda (i) (+ i 0.1d0)) + (alexandria:iota len)))) + (v (make-array len :element-type 'double-float + :initial-contents + (mapcar (lambda (i) (+ i 0.2d0)) + (alexandria:iota len))))) + (declare (type f64vec u v)) + (time-total 1e6 (f64.4-fma-vdot u v))))) + +(defun benchmark-simd-vdot-double (&rest v-lengths) + (declare (optimize (speed 3) (safety 0) (debug 0)) + (notinline f64.4-vdot)) + (loop for len in v-lengths + do (format t "Doing dot product of two ~A long double float vectors 1e6 times~%" len) + collect (let ((u (make-array len :element-type 'double-float + :initial-contents + (mapcar (lambda (i) (+ i 0.1d0)) + (alexandria:iota len)))) + (v (make-array len :element-type 'double-float + :initial-contents + (mapcar (lambda (i) (+ i 0.2d0)) + (alexandria:iota len))))) + (declare (type f64vec u v)) + (time-total 1e6 (simd-vdot u v))))) + +(defun benchmark-fma-vdot-double (&rest v-lengths) + (declare (optimize (speed 3) (safety 0) (debug 0)) + (notinline fma-vdot)) + (loop for len in v-lengths + do (format t "Doing dot product of two ~A long double float vectors 1e6 times~%" len) + collect (let ((u (make-array len :element-type 'double-float + :initial-contents + (mapcar (lambda (i) (+ i 0.1d0)) + (alexandria:iota len)))) + (v (make-array len :element-type 'double-float + :initial-contents + (mapcar (lambda (i) (+ i 0.2d0)) + (alexandria:iota len))))) + (declare (type f64vec u v)) + (time-total 1e6 (fma-vdot u v))))) + +(defun benchmark-avx-single (&rest v-lengths) + (declare (optimize (speed 3) (safety 0) (debug 0)) + (notinline f32.8-vdot)) + (loop for len in v-lengths + do (format t "Doing dot product of two ~A long single float vectors 1e6 times~%" len) + collect (let ((u (make-array len :element-type 'single-float + :initial-contents + (mapcar (lambda (i) (+ i 0.1f0)) + (alexandria:iota len)))) + (v (make-array len :element-type 'single-float + :initial-contents + (mapcar (lambda (i) (+ i 0.2f0)) + (alexandria:iota len))))) + (declare (type f32vec u v)) + (time-total 1e6 (f32.8-vdot u v))))) + +(defun benchmark-sse-double (&rest v-lengths) + (declare (optimize (speed 3) (safety 0) (debug 0)) + (notinline f64.2-vdot)) + (loop for len in v-lengths + do (format t "Doing dot product of two ~A long double float vectors 1e6 times~%" len) + collect (let ((u (make-array len :element-type 'double-float + :initial-contents + (mapcar (lambda (i) (+ i 0.1d0)) + (alexandria:iota len)))) + (v (make-array len :element-type 'double-float + :initial-contents + (mapcar (lambda (i) (+ i 0.2d0)) + (alexandria:iota len))))) + (declare (type f32vec u v)) + (time-total 1e6 (f64.2-vdot u v))))) + +(defun benchmark-sse-single (&rest v-lengths) + (declare (optimize (speed 3) (safety 0) (debug 0)) + (notinline f32.4-vdot)) + (loop for len in v-lengths + do (format t "Doing dot product of two ~A long single float vectors 1e6 times~%" len) + collect (let ((u (make-array len :element-type 'single-float + :initial-contents + (mapcar (lambda (i) (+ i 0.1f0)) + (alexandria:iota len)))) + (v (make-array len :element-type 'single-float + :initial-contents + (mapcar (lambda (i) (+ i 0.2f0)) + (alexandria:iota len))))) + (declare (type f32vec u v)) + (time-total 1e6 (f32.4-vdot u v))))) + +(defun benchmark-vsum-double (&rest v-lengths) + (declare (optimize (speed 3) (safety 0) (debug 0)) + (notinline f64.4-vsum)) + (loop for len in v-lengths + do (format t "Doing sum of a ~A long double float vector 1e6 times~%" len) + collect (let ((u (make-array len :element-type 'double-float + :initial-contents + (mapcar (lambda (i) (+ i 0.1d0)) + (alexandria:iota len))))) + (declare (type f64vec u)) + (time-total 1e6 (f64.4-vsum u))))) + +(defun benchmark-simd-sum-double (&rest v-lengths) + (declare (optimize (speed 3) (safety 0) (debug 0)) + (notinline simd-sum)) + (loop for len in v-lengths + do (format t "Doing sum of a ~A long double float vector 1e6 times~%" len) + collect (let ((u (make-array len :element-type 'double-float + :initial-contents + (mapcar (lambda (i) (+ i 0.1d0)) + (alexandria:iota len))))) + (declare (type f64vec u)) + (time-total 1e6 (simd-sum u))))) + +(defun benchmark-vsum-single (&rest v-lengths) + (declare (optimize (speed 3) (safety 0) (debug 0)) + (notinline f32.8-vsum)) + (loop for len in v-lengths + do (format t "Doing sum of a ~A long single float vector 1e6 x~%" len) + collect (let ((u (make-array len :element-type 'single-float + :initial-contents + (mapcar (lambda (i) (+ i 0.1f0)) + (alexandria:iota len))))) + (declare (type f32vec u)) + (time-total 1e6 (f32.8-vsum u))))) +#+(or) +(benchmark-f64.4-vdot-double 10 100 200 400 800 1200 2400 4800 9600) +#+(or) +(benchmark-f64.4-vdot2-double 10 100 200 400 800 1200 2400 4800 9600) +#+(or) +(benchmark-avx-single 10 100 200 400 800 1200 2400 4800 9600) +#+(or) +(benchmark-sse-double 10 100 200 400 800 1200 2400 4800 9600) +#+(or) +(benchmark-sse-single 10 100 200 400 800 1200 2400 4800 9600) +#+(or) +(benchmark-vsum-double 10 100 200 400 800 1200 2400 4800 9600) +#+(or) +(benchmark-vsum-single 10 100 200 400 800 1200 2400 4800 9600) +#+(or) +(apply 'benchmark-avx-double (loop for i from 1 to 10 collect (* 1000 i))) diff --git a/contrib/sb-simd/examples/simd-dot.lisp b/contrib/sb-simd/examples/simd-dot.lisp new file mode 100644 index 0000000000..7664aadada --- /dev/null +++ b/contrib/sb-simd/examples/simd-dot.lisp @@ -0,0 +1,20 @@ +(in-package :sb-simd-avx) + +(defun simd-dot (array1 array2 &aux (n (min (array-total-size array1) (array-total-size array2)))) + (declare (type (simple-array double-float 1) array1 array2) + (optimize speed (safety 0))) + (do ((index 0 (the (integer 0 #.(- array-total-size-limit 16)) (+ index 16))) + (acc1 (f64.4 0) (f64.4+ acc1 (f64.4* (f64.4-row-major-aref array1 (+ index 0)) + (f64.4-row-major-aref array2 (+ index 0))))) + (acc2 (f64.4 0) (f64.4+ acc2 (f64.4* (f64.4-row-major-aref array1 (+ index 4)) + (f64.4-row-major-aref array2 (+ index 4))))) + (acc3 (f64.4 0) (f64.4+ acc3 (f64.4* (f64.4-row-major-aref array1 (+ index 8)) + (f64.4-row-major-aref array2 (+ index 8))))) + (acc4 (f64.4 0) (f64.4+ acc4 (f64.4* (f64.4-row-major-aref array1 (+ index 12)) + (f64.4-row-major-aref array2 (+ index 12)))))) + ((>= index (- n 16)) + (do ((result (f64.4-horizontal+ (f64.4+ acc1 acc2 acc3 acc4)) + (+ result (* (row-major-aref array1 index) + (row-major-aref array2 index)))) + (index index (1+ index))) + ((>= index n) result))))) diff --git a/contrib/sb-simd/examples/simd-sum.lisp b/contrib/sb-simd/examples/simd-sum.lisp new file mode 100755 index 0000000000..1a197185d6 --- /dev/null +++ b/contrib/sb-simd/examples/simd-sum.lisp @@ -0,0 +1,15 @@ +(in-package :sb-simd-avx) + +(defun simd-sum (array &aux (n (array-total-size array))) + (declare (type (simple-array double-float (*)) array) + (optimize speed (safety 0))) + (do ((index 0 (the (integer 0 #.(- array-total-size-limit 16)) (+ index 16))) + (acc1 (f64.4 0) (f64.4+ acc1 (f64.4-aref array (+ index 0)))) + (acc2 (f64.4 0) (f64.4+ acc2 (f64.4-aref array (+ index 4)))) + (acc3 (f64.4 0) (f64.4+ acc3 (f64.4-aref array (+ index 8)))) + (acc4 (f64.4 0) (f64.4+ acc4 (f64.4-aref array (+ index 12))))) + ((>= index (- n 16)) + (do ((result (f64.4-horizontal+ (f64.4+ acc1 acc2 acc3 acc4)) + (+ result (row-major-aref array index))) + (index index (1+ index))) + ((>= index n) result))))) diff --git a/contrib/sb-simd/sb-simd.texinfo b/contrib/sb-simd/sb-simd.texinfo new file mode 100644 index 0000000000..2e7acb83e6 --- /dev/null +++ b/contrib/sb-simd/sb-simd.texinfo @@ -0,0 +1,230 @@ +@node sb-simd +@section sb-simd +@cindex SIMD + +The @code{sb-simd} module provides a convenient interface for SIMD +programming in SBCL. It provides one package per SIMD instruction set, +plus functions and macros for querying whether an instruction set is +available and what functions and data types it exports. + +@subsection Data Types + +The central data type in @code{sb-simd} is the SIMD pack. A SIMD pack +is very similar to a specialized vector, except that its length must be +a particular power of two that depends on its element type and the +underlying hardware. The set of element types that are supported for +SIMD packs is similar to that of SBCL's specialized array element types, +except that there is currently no support for SIMD packs of complex +numbers or characters. + +The supported scalar types are @code{f32}, @code{f64}, @code{sN}, and +@code{uN}, where @code{N} is either 8, 16, 32, or 64. These scalar +types are abbreviations for the Common Lisp types @code{single-float}, +@code{double-float}, @code{signed-byte}, and @code{unsigned-byte}, +respectively. For each scalar data type @code{X}, there exists one or +more SIMD data type @code{X.Y} with @code{Y} elements. For example, in +AVX there are two supported SIMD data types with element type +@code{f64}, namely @code{f64.2} (128 bit) and @code{f64.4} (256 bit). + +SIMD packs are regular Common Lisp objects that have a type, a class, +and can be passed as function arguments. The price for this is that +SIMD packs have both a boxed and an unboxed representation. The unboxed +representation of a SIMD pack has zero overhead and fits into a CPU +register, but can only be used within a function and when the compiler +can statically determine the SIMD pack's type. Otherwise, the SIMD pack +is boxed, i.e., spilled to the heap together with its type information. +In practice, boxing of SIMD packs can usually be avoided via inlining, +or by loading and storing them to specialized arrays instead of passing +them around as function arguments. + +@subsection Casts + +For each scalar data type @code{X}, there is a function named @code{X} +that is equivalent to @code{(lambda (v) (coerce v 'X))}. For each SIMD +data type @code{X.Y}, there is a function named @code{X.Y} that ensures +that its argument is of type @code{X.Y}, or, if the argument is a number, +calls the cast function of @code{X} and broadcasts the result. + +All functions provided by @code{sb-simd} (apart from the casts +themselves) implicitly cast each argument to its expected type. So to +add the number five to each single float in a SIMD pack @code{x} of type +@code{f32.8}, it is sufficient to write @code{(f32.8+ x 5)}. We don't +mention this implicit conversion explicitly in the following sections, +so if any function description states that an argument must be of type +@code{X.Y}, the argument can actually be of any type that is a suitable +argument of the cast function named @code{X.Y}. + +@subsection Constructors + +For each SIMD data type @code{X.Y}, there is a constructor named +@code{make-X.Y} that takes @code{Y} arguments of type @code{X} and +returns a SIMD pack whose elements are the supplied values. + +@subsection Unpackers + +For each SIMD data type @code{X.Y}, there is a function named +@code{X.Y-values} that returns, as @code{Y} multiple values, the +elements of the supplied SIMD pack of type @code{X.Y}. + +@subsection Reinterpret Casts + +For each SIMD data type @code{X.Y}, there is a function named +@code{X.Y!} that takes any SIMD pack or scalar datum and interprets its +bits as a SIMD pack of type @code{X.Y}. If the supplied datum has more +bits than the resulting value, the excess bits are discarded. If the +supplied datum has less bits than the resulting value, the missing bits are +assumed to be zero. + +@subsection Associatives + +For each associative binary function, e.g., @code{two-arg-X.Y-OP}, there +is a function @code{X.Y-OP} that takes any number of arguments and +combines them with this binary function in a tree-like fashion. If the +binary function has an identity element, it is possible to call the +function with zero arguments, in which case the identity element is +returned. If there is no identity element, the function must receive at +least one argument. + +Examples of associative functions are @code{f32.8+}, for summing any +number of 256 bit packs of single floats, and @code{u8.32-max}, for +computing the element-wise maximum of one or more 256 bit packs of 8 bit +integers. + +@subsection Reducers + +For binary functions @code{two-arg-X.Y-OP} that are not associative, but +that have a neutral element, there are functions @code{X.Y-OP} that take +any positive number of arguments and return the reduction of all +arguments with the binary function. In the special case of a single +supplied argument, the binary function is invoked on the neutral element +and that argument. Reducers have been introduced to generate Lisp-style +subtraction and division functions. + +Examples of reducers are @code{f32.8/}, for successively dividing a pack +of 32 bit single floats by all further supplied packs of 32 bit single +floats, or @code{u32.8-} for subtracting any number of supplied packs of +32 bit unsigned integers from the first supplied one, except in the case +of a single argument, where @code{u32.8-} simply negates all values in +the pack. + +@subsection Rounding + +For each floating-point SIMD data type @code{X.Y} there are several +functions that round the values of a supplied SIMD pack to nearby +floating-point values whose fractional digits are all zero. Those +functions are @code{X.Y-round}, @code{X.Y-floor}, @code{X.Y-ceiling}, +and @code{X.Y-truncate}, and they have the same semantics as the one +argument versions of @code{cl:round}, @code{cl:floor}, +@code{cl:ceiling}, and @code{cl:truncate}, respectively. + +@subsection Comparisons + +For each SIMD data type @code{X.Y}, there exist conversion functions +@code{X.Y<}, @code{X.Y<=}, @code{X.Y>}, @code{X.Y>=}, and +@code{X.Y=} that check whether the supplied arguments are strictly +monotonically increasing, monotonically increasing, strictly monotonically +decreasing, monotonically decreasing, equal, or nowhere equal, +respectively. In contrast to the Common Lisp functions @code{<}, +@code{<=}, @code{>}, @code{>=}, @code{=}, and @code{/=} the SIMD +comparison functions don't return a generalized boolean, but a SIMD pack of +unsigned integers with @code{Y} elements. The bits of each unsigned +integer are either all one, if the values of the arguments at that position +satisfy the test, or all zero, if they don't. We call a SIMD packs of such +unsigned integers a mask. + +@subsection Conditionals + +The SIMD paradigm is inherently incompatible with fine-grained control +flow. A piece of code containing an @code{if} special form cannot be +vectorized in a straightforward way, because doing so would require as +many instruction pointers and processor states as there are values in +the desired SIMD data type. Instead, most SIMD instruction sets provide +an operator for selecting values from one of two supplied SIMD packs +based on a mask. The mask is a SIMD pack with as many elements as the +other two arguments, but whose elements are unsigned integers whose bits +must be either all zeros or all ones. This selection mechanism can be +used to emulate the effect of an @code{if} special form, at the price +that both operands have to be computed each time. + +In @code{sb-simd}, all conditional operations and comparisons emit +suitable mask fields, and there is a @code{X.Y-if} function for each +SIMD data type with element type @code{X} and number of elements +@code{Y} whose first arguments must be a suitable mask, whose second and +third argument must be objects that can be converted to the SIMD data +type @code{X.Y}, and that returns a value of type @code{X.Y} where each +element is from the second operand if the corresponding mask bits are +set, and from the third operand if the corresponding mask bits are not +set. + +@subsection Loads and Stores + +In practice, a SIMD pack @code{X.Y} is usually not constructed by +calling its constructor, but by loading @code{Y} consecutive elements +from a specialized array with element type @code{X}. The functions for +doing so are called @code{X.Y-aref} and @code{X.Y-row-major-aref}, and +have similar semantics as Common Lisp's @code{aref} and +@code{row-major-aref}. In addition to that, some instruction sets +provide the functions @code{X.Y-non-temporal-aref} and +@code{X.Y-non-temporal-row-major-aref}, for accessing a memory location +without loading the referenced values into the CPU's cache. + +For each function @code{X.Y-foo} for loading SIMD packs from an array, +there also exists a corresponding function @code{(setf X.Y-foo)} for +storing a SIMD pack in the specified memory location. An exception to +this rule is that some instruction sets (e.g., SSE) only provide +functions for non-temporal stores, but not for the corresponding +non-temporal loads. + +One difficulty when treating the data of a Common Lisp array as a SIMD +pack is that some hardware instructions require a particular alignment +of the address being referenced. Luckily, most architectures provide +instructions for unaligned loads and stores that are, at least on modern +CPUs, not slower than their aligned equivalents. So by default we +translate all array references as unaligned loads and stores. An +exception are the instructions for non-temporal loads and stores, that +always require a certain alignment. We do not handle this case +specially, so without special handling by the user, non-temporal loads +and stores will only work on certain array indices that depend on the +actual placement of that array in memory. + +@subsection Specialized Scalar Operations + +Finally, for each SIMD function @code{X.Y-OP} that applies a certain +operation @code{OP} element-wise to the @code{Y} elements of type +@code{X}, there exists also a functions @code{X-OP} for applying that +operation only to a single element. For example, the SIMD function +@code{f64.4+} has a corresponding function @code{f64+} that differs from +@code{cl:+} in that it only accepts arguments of type double float, and +that it adds its supplied arguments in a fixed order that is the same as +the one used by @code{f64.4}. + +There are good reasons for exporting scalar functions from a SIMD +library, too. The most obvious one is that they obey the same naming +convention and hence make it easier to locate the correct functions. +Another benefit is that the semantics of each scalar operation is +precisely the same as that of the corresponding SIMD function, so they +can be used to write reference implementations for testing. A final +reason is that these scalar functions can be used to simplify the life +of tools for automatic vectorization. + +@subsection Instruction Set Dispatch + +One challenge that is unique to image-based programming systems such as +Lisp is that a program can run on one machine, be dumped as an image, +and then resumed on another machine. While nobody expects this feature +to work across machines with different architectures, it is quite likely +that the machine where the image is dumped and the one where execution +is resumed provide different instruction set extensions. + +As a practical example, consider a game developer that develops software +on an x86-64 machine with all SIMD extensions up to AVX2, but then dumps +it as an image and ships it to a customer whose machine only supports +SIMD extensions up to SSE2. Ideally, the image should contain multiple +optimized versions of all crucial functions, and dynamically select the +most appropriate version based on the instruction set extensions that +are actually available. + +This kind of run time instruction set dispatch is explicitly supported +by means of the @code{instruction-set-case} macro. The code resulting +from an invocation of this macro compiles to an efficient jump table +whose index is recomputed on each startup of the Lisp image. diff --git a/contrib/sb-simd/test-suite/numbers.lisp b/contrib/sb-simd/test-suite/numbers.lisp new file mode 100644 index 0000000000..93dabca7ee --- /dev/null +++ b/contrib/sb-simd/test-suite/numbers.lisp @@ -0,0 +1,28 @@ +(in-package #:sb-simd-test-suite) + +(defparameter *numbers* + (remove-duplicates + `(,most-positive-double-float + ,most-negative-double-float + ,least-positive-normalized-double-float + ,least-negative-normalized-double-float + ,least-positive-double-float + ,least-negative-double-float + ,most-positive-single-float + ,most-negative-single-float + ,least-positive-normalized-single-float + ,least-negative-normalized-single-float + ,least-positive-single-float + ,least-negative-single-float + ,@(loop for type in '(single-float double-float integer) + append (loop for i from 0 to 64 + for n = (expt 2 i) + collect (coerce n type) + collect (coerce (- n) type) + collect (coerce (1- n) type) + collect (coerce (1+ n) type) + collect (coerce (1- (- n)) type) + collect (coerce (1+ (- n)) type)))))) + +(defun numbers-of-type (type) + (remove-if-not (lambda (x) (typep x type)) *numbers*)) diff --git a/contrib/sb-simd/test-suite/packages.lisp b/contrib/sb-simd/test-suite/packages.lisp new file mode 100644 index 0000000000..e589ebd8f3 --- /dev/null +++ b/contrib/sb-simd/test-suite/packages.lisp @@ -0,0 +1,15 @@ +(cl:in-package #:common-lisp-user) + +(defpackage #:sb-simd-test-suite + (:use #:common-lisp #:sb-simd-internals) + (:export + #:run-test-suite + #:define-test + #:is + #:signals + #:all-tests + #:check-package + #:run-tests + #:define-simple-simd-test + #:define-horizontal-test + #:define-aref-test)) diff --git a/contrib/sb-simd/test-suite/test-arefs.lisp b/contrib/sb-simd/test-suite/test-arefs.lisp new file mode 100644 index 0000000000..7f1926997b --- /dev/null +++ b/contrib/sb-simd/test-suite/test-arefs.lisp @@ -0,0 +1,92 @@ +(in-package #:sb-simd-test-suite) + +(defmacro define-aref-test (aref element-type simd-width &optional (unpacker 'identity)) + (let ((value-symbols (prefixed-symbols "V" simd-width)) + (zero (coerce 0 element-type)) + (one (coerce 1 element-type))) + `(define-test ,aref + ;; Create an array of zeros and successively replace zeros with + ;; ones. After each replacement, check whether a load still + ;; produces the expected result. + (let ((array (make-array '(,simd-width) + :element-type ',element-type + :initial-element ,zero))) + (multiple-value-bind ,value-symbols (,unpacker (,aref array 0)) + ,@(loop for value-symbol in value-symbols + collect `(is (= ,value-symbol ,zero)))) + (loop for index below ,simd-width do + (setf (aref array index) ,one) + (loop for number in (multiple-value-list (,unpacker (,aref array 0))) + for position from 0 + do (if (<= position index) + (is (= number ,one)) + (is (= number ,zero)))))) + ;; Create an array with twice as many elements as the width of the + ;; SIMD data type, and whose lower half consists of all zeros and + ;; whose upper half consists of all ones. Check that all valid + ;; loads from this array have the expected state. + (let ((array (make-array '(,(* 2 simd-width)) + :element-type ',element-type + :initial-contents + (append (make-list ,simd-width :initial-element ,zero) + (make-list ,simd-width :initial-element ,one))))) + (loop for index below ,simd-width do + (multiple-value-bind ,value-symbols + (,unpacker (,aref array index)) + ,@(loop for value-symbol in value-symbols + for position from 0 + collect `(if (< (+ ,position index) ,simd-width) + (is (= ,value-symbol ,zero)) + (is (= ,value-symbol ,one)))))))))) + +(in-package #:sb-simd) + +(sb-simd-test-suite:define-aref-test u8-aref (unsigned-byte 8) 1) +(sb-simd-test-suite:define-aref-test u16-aref (unsigned-byte 16) 1) +(sb-simd-test-suite:define-aref-test u32-aref (unsigned-byte 32) 1) +(sb-simd-test-suite:define-aref-test u64-aref (unsigned-byte 64) 1) +(sb-simd-test-suite:define-aref-test s8-aref (signed-byte 8) 1) +(sb-simd-test-suite:define-aref-test s16-aref (signed-byte 16) 1) +(sb-simd-test-suite:define-aref-test s32-aref (signed-byte 32) 1) +(sb-simd-test-suite:define-aref-test s64-aref (signed-byte 64) 1) +(sb-simd-test-suite:define-aref-test f32-aref single-float 1) +(sb-simd-test-suite:define-aref-test f64-aref double-float 1) + +(in-package #:sb-simd-sse) + +(sb-simd-test-suite:define-aref-test f32.4-aref single-float 4 f32.4-values) + +(in-package #:sb-simd-sse2) + +(sb-simd-test-suite:define-aref-test f64.2-aref double-float 2 f64.2-values) +(sb-simd-test-suite:define-aref-test u8.16-aref (unsigned-byte 8) 16 u8.16-values) +(sb-simd-test-suite:define-aref-test u16.8-aref (unsigned-byte 16) 8 u16.8-values) +(sb-simd-test-suite:define-aref-test u32.4-aref (unsigned-byte 32) 4 u32.4-values) +(sb-simd-test-suite:define-aref-test u64.2-aref (unsigned-byte 64) 2 u64.2-values) +(sb-simd-test-suite:define-aref-test s8.16-aref (signed-byte 8) 16 s8.16-values) +(sb-simd-test-suite:define-aref-test s16.8-aref (signed-byte 16) 8 s16.8-values) +(sb-simd-test-suite:define-aref-test s32.4-aref (signed-byte 32) 4 s32.4-values) +(sb-simd-test-suite:define-aref-test s64.2-aref (signed-byte 64) 2 s64.2-values) + +(in-package #:sb-simd-avx) + +(sb-simd-test-suite:define-aref-test f32.4-aref single-float 4 f32.4-values) +(sb-simd-test-suite:define-aref-test f32.8-aref single-float 8 f32.8-values) +(sb-simd-test-suite:define-aref-test f64.2-aref double-float 2 f64.2-values) +(sb-simd-test-suite:define-aref-test f64.4-aref double-float 4 f64.4-values) +(sb-simd-test-suite:define-aref-test u8.16-aref (unsigned-byte 8) 16 u8.16-values) +(sb-simd-test-suite:define-aref-test u16.8-aref (unsigned-byte 16) 8 u16.8-values) +(sb-simd-test-suite:define-aref-test u32.4-aref (unsigned-byte 32) 4 u32.4-values) +(sb-simd-test-suite:define-aref-test u64.2-aref (unsigned-byte 64) 2 u64.2-values) +(sb-simd-test-suite:define-aref-test s8.16-aref (signed-byte 8) 16 s8.16-values) +(sb-simd-test-suite:define-aref-test s16.8-aref (signed-byte 16) 8 s16.8-values) +(sb-simd-test-suite:define-aref-test s32.4-aref (signed-byte 32) 4 s32.4-values) +(sb-simd-test-suite:define-aref-test s64.2-aref (signed-byte 64) 2 s64.2-values) +(sb-simd-test-suite:define-aref-test u8.32-aref (unsigned-byte 8) 32 u8.32-values) +(sb-simd-test-suite:define-aref-test u16.16-aref (unsigned-byte 16) 16 u16.16-values) +(sb-simd-test-suite:define-aref-test u32.8-aref (unsigned-byte 32) 8 u32.8-values) +(sb-simd-test-suite:define-aref-test u64.4-aref (unsigned-byte 64) 4 u64.4-values) +(sb-simd-test-suite:define-aref-test s8.32-aref (signed-byte 8) 32 s8.32-values) +(sb-simd-test-suite:define-aref-test s16.16-aref (signed-byte 16) 16 s16.16-values) +(sb-simd-test-suite:define-aref-test s32.8-aref (signed-byte 32) 8 s32.8-values) +(sb-simd-test-suite:define-aref-test s64.4-aref (signed-byte 64) 4 s64.4-values) diff --git a/contrib/sb-simd/test-suite/test-hairy-simd-functions.lisp b/contrib/sb-simd/test-suite/test-hairy-simd-functions.lisp new file mode 100644 index 0000000000..24e36c71b7 --- /dev/null +++ b/contrib/sb-simd/test-suite/test-hairy-simd-functions.lisp @@ -0,0 +1,9 @@ +(in-package #:sb-simd-test-suite) + +(in-package #:sb-simd-sse) + +(in-package #:sb-simd-sse2) + +(in-package #:sb-simd-avx) + +(in-package #:sb-simd-avx2) diff --git a/contrib/sb-simd/test-suite/test-horizontal-functions.lisp b/contrib/sb-simd/test-suite/test-horizontal-functions.lisp new file mode 100644 index 0000000000..3557e38d06 --- /dev/null +++ b/contrib/sb-simd/test-suite/test-horizontal-functions.lisp @@ -0,0 +1,76 @@ +(in-package #:sb-simd-test-suite) + +(defmacro define-horizontal-test (horizontal-fn scalar-fn) + (let* ((horizontal-record (find-function-record horizontal-fn)) + (scalar-record (find-function-record scalar-fn)) + (argument-record (first (function-record-required-argument-records horizontal-record))) + (result-record (function-record-result-record horizontal-record)) + (width (value-record-simd-width argument-record)) + (args (loop repeat width collect (gensym))) + (pack (third (simd-info (value-record-name argument-record))))) + (assert (eq (function-record-result-record scalar-record) result-record)) + `(define-test ,horizontal-fn + (let ((generator (find-generator ',(value-record-name result-record)))) + (loop repeat 99 do + (let ,(loop for arg in args collect `(,arg (funcall generator))) + (handler-case + (assert (bitwise= (,horizontal-fn (,pack ,@args)) + (,scalar-fn ,@args))) + (floating-point-overflow ()) + (floating-point-overflow ())))))))) + +(in-package #:sb-simd-sse) + +(sb-simd-test-suite:define-horizontal-test f32.4-horizontal-and f32-and) +(sb-simd-test-suite:define-horizontal-test f32.4-horizontal-or f32-or) +(sb-simd-test-suite:define-horizontal-test f32.4-horizontal-xor f32-xor) +(sb-simd-test-suite:define-horizontal-test f32.4-horizontal-max f32-max) +(sb-simd-test-suite:define-horizontal-test f32.4-horizontal-min f32-min) +(sb-simd-test-suite:define-horizontal-test f32.4-horizontal+ f32+) +(sb-simd-test-suite:define-horizontal-test f32.4-horizontal* f32*) + +(in-package #:sb-simd-sse2) + +(sb-simd-test-suite:define-horizontal-test f64.2-horizontal-and f64-and) +(sb-simd-test-suite:define-horizontal-test f64.2-horizontal-or f64-or) +(sb-simd-test-suite:define-horizontal-test f64.2-horizontal-xor f64-xor) +(sb-simd-test-suite:define-horizontal-test f64.2-horizontal-max f64-max) +(sb-simd-test-suite:define-horizontal-test f64.2-horizontal-min f64-min) +(sb-simd-test-suite:define-horizontal-test f64.2-horizontal+ f64+) +(sb-simd-test-suite:define-horizontal-test f64.2-horizontal* f64*) + +(in-package #:sb-simd-avx) + +(sb-simd-test-suite:define-horizontal-test f32.4-horizontal-and f32-and) +(sb-simd-test-suite:define-horizontal-test f32.4-horizontal-or f32-or) +(sb-simd-test-suite:define-horizontal-test f32.4-horizontal-xor f32-xor) +(sb-simd-test-suite:define-horizontal-test f32.4-horizontal-max f32-max) +(sb-simd-test-suite:define-horizontal-test f32.4-horizontal-min f32-min) +(sb-simd-test-suite:define-horizontal-test f32.4-horizontal+ f32+) +(sb-simd-test-suite:define-horizontal-test f32.4-horizontal* f32*) + +(sb-simd-test-suite:define-horizontal-test f64.2-horizontal-and f64-and) +(sb-simd-test-suite:define-horizontal-test f64.2-horizontal-or f64-or) +(sb-simd-test-suite:define-horizontal-test f64.2-horizontal-xor f64-xor) +(sb-simd-test-suite:define-horizontal-test f64.2-horizontal-max f64-max) +(sb-simd-test-suite:define-horizontal-test f64.2-horizontal-min f64-min) +(sb-simd-test-suite:define-horizontal-test f64.2-horizontal+ f64+) +(sb-simd-test-suite:define-horizontal-test f64.2-horizontal* f64*) + +(sb-simd-test-suite:define-horizontal-test f32.8-horizontal-and f32-and) +(sb-simd-test-suite:define-horizontal-test f32.8-horizontal-or f32-or) +(sb-simd-test-suite:define-horizontal-test f32.8-horizontal-xor f32-xor) +(sb-simd-test-suite:define-horizontal-test f32.8-horizontal-max f32-max) +(sb-simd-test-suite:define-horizontal-test f32.8-horizontal-min f32-min) +(sb-simd-test-suite:define-horizontal-test f32.8-horizontal+ f32+) +(sb-simd-test-suite:define-horizontal-test f32.8-horizontal* f32*) + +(sb-simd-test-suite:define-horizontal-test f64.4-horizontal-and f64-and) +(sb-simd-test-suite:define-horizontal-test f64.4-horizontal-or f64-or) +(sb-simd-test-suite:define-horizontal-test f64.4-horizontal-xor f64-xor) +(sb-simd-test-suite:define-horizontal-test f64.4-horizontal-max f64-max) +(sb-simd-test-suite:define-horizontal-test f64.4-horizontal-min f64-min) +(sb-simd-test-suite:define-horizontal-test f64.4-horizontal+ f64+) +(sb-simd-test-suite:define-horizontal-test f64.4-horizontal* f64*) + +(in-package #:sb-simd-avx2) diff --git a/contrib/sb-simd/test-suite/test-packages.lisp b/contrib/sb-simd/test-suite/test-packages.lisp new file mode 100644 index 0000000000..13f475db9e --- /dev/null +++ b/contrib/sb-simd/test-suite/test-packages.lisp @@ -0,0 +1,16 @@ +(in-package #:sb-simd-test-suite) + +(define-test packages) + +(define-test packages + (check-package '#:sb-simd-internals) + (check-package '#:sb-simd) + (check-package '#:sb-simd-x86-64) + (check-package '#:sb-simd-sse) + (check-package '#:sb-simd-sse2) + (check-package '#:sb-simd-sse3) + (check-package '#:sb-simd-ssse3) + (check-package '#:sb-simd-sse4.1) + (check-package '#:sb-simd-sse4.2) + (check-package '#:sb-simd-avx) + (check-package '#:sb-simd-avx2)) diff --git a/contrib/sb-simd/test-suite/test-simple-simd-functions.lisp b/contrib/sb-simd/test-suite/test-simple-simd-functions.lisp new file mode 100644 index 0000000000..9cbbd5b032 --- /dev/null +++ b/contrib/sb-simd/test-suite/test-simple-simd-functions.lisp @@ -0,0 +1,543 @@ +(in-package #:sb-simd-test-suite) + +(defmacro define-simple-simd-test (simd-foo result-types argtypes foo) + `(define-test ,simd-foo + ,@(loop for argtype-variant in (argtypes-variants argtypes) + collect `(test-simple-simd-function ,simd-foo ,result-types ,argtype-variant ,foo)))) + +(defmacro test-simple-simd-function (simd-foo result-types simplified-argtypes foo) + (let* ((result-infos (mapcar #'simd-info result-types)) + (argument-infos (mapcar #'simd-info simplified-argtypes)) + (argument-symbols (prefixed-symbols "ARGUMENT-" (length argument-infos))) + (result-symbols (prefixed-symbols "RESULT-" (length result-infos))) + (output-symbols (prefixed-symbols "OUTPUT-" (length result-infos))) + (simd-width (the integer (second (first result-infos))))) + (assert (apply #'= (append (mapcar #'second result-infos) (mapcar #'second argument-infos)))) + `(loop repeat ,(min (expt 99 (length argument-infos)) 10000) do + (multiple-value-bind (inputs outputs) + (find-valid-simd-call + (lambda ,argument-symbols + (declare ,@(loop for argument-symbol in argument-symbols + for argument-type in (mapcar #'first argument-infos) + collect `(type ,argument-type ,argument-symbol))) + (,foo ,@argument-symbols)) + ',(mapcar #'find-generator (mapcar #'first argument-infos)) + ,simd-width + ',(mapcar #'third argument-infos) + ',(mapcar #'third result-infos)) + (destructuring-bind ,argument-symbols inputs + (destructuring-bind ,output-symbols outputs + (multiple-value-bind ,result-symbols (,simd-foo ,@argument-symbols) + ,@(loop for result-type in result-types + for result-symbol in result-symbols + for output-symbol in output-symbols + collect + `(is (simd= ,result-symbol ,output-symbol)))))))))) + +(in-package #:sb-simd-sse) + +(sb-simd-test-suite:define-simple-simd-test f32.4-and (f32.4) (&rest f32.4) f32-and) +(sb-simd-test-suite:define-simple-simd-test f32.4-or (f32.4) (&rest f32.4) f32-or) +(sb-simd-test-suite:define-simple-simd-test f32.4-xor (f32.4) (&rest f32.4) f32-xor) +(sb-simd-test-suite:define-simple-simd-test f32.4-andc1 (f32.4) (f32.4 f32.4) f32-andc1) +(sb-simd-test-suite:define-simple-simd-test f32.4-not (f32.4) (f32.4) f32-not) +(sb-simd-test-suite:define-simple-simd-test f32.4-max (f32.4) (f32.4 &rest f32.4) f32-max) +(sb-simd-test-suite:define-simple-simd-test f32.4-min (f32.4) (f32.4 &rest f32.4) f32-min) +(sb-simd-test-suite:define-simple-simd-test f32.4+ (f32.4) (&rest f32.4) f32+) +(sb-simd-test-suite:define-simple-simd-test f32.4- (f32.4) (f32.4 &rest f32.4) f32-) +(sb-simd-test-suite:define-simple-simd-test f32.4* (f32.4) (&rest f32.4) f32*) +(sb-simd-test-suite:define-simple-simd-test f32.4/ (f32.4) (f32.4 &rest f32.4) f32/) + +(in-package #:sb-simd-sse2) + +(sb-simd-test-suite:define-simple-simd-test f32.4= (u32.4) (f32.4 &rest f32.4) f32=) +(sb-simd-test-suite:define-simple-simd-test f32.4/= (u32.4) (f32.4 &rest f32.4) f32/=) +(sb-simd-test-suite:define-simple-simd-test f32.4< (u32.4) (f32.4 &rest f32.4) f32<) +(sb-simd-test-suite:define-simple-simd-test f32.4<= (u32.4) (f32.4 &rest f32.4) f32<=) +(sb-simd-test-suite:define-simple-simd-test f32.4> (u32.4) (f32.4 &rest f32.4) f32>) +(sb-simd-test-suite:define-simple-simd-test f32.4>= (u32.4) (f32.4 &rest f32.4) f32>=) + +(sb-simd-test-suite:define-simple-simd-test f64.2-and (f64.2) (&rest f64.2) f64-and) +(sb-simd-test-suite:define-simple-simd-test f64.2-or (f64.2) (&rest f64.2) f64-or) +(sb-simd-test-suite:define-simple-simd-test f64.2-xor (f64.2) (&rest f64.2) f64-xor) +(sb-simd-test-suite:define-simple-simd-test f64.2-andc1 (f64.2) (f64.2 f64.2) f64-andc1) +(sb-simd-test-suite:define-simple-simd-test f64.2-not (f64.2) (f64.2) f64-not) +(sb-simd-test-suite:define-simple-simd-test f64.2-max (f64.2) (f64.2 &rest f64.2) f64-max) +(sb-simd-test-suite:define-simple-simd-test f64.2-min (f64.2) (f64.2 &rest f64.2) f64-min) +(sb-simd-test-suite:define-simple-simd-test f64.2+ (f64.2) (&rest f64.2) f64+) +(sb-simd-test-suite:define-simple-simd-test f64.2- (f64.2) (f64.2 &rest f64.2) f64-) +(sb-simd-test-suite:define-simple-simd-test f64.2* (f64.2) (&rest f64.2) f64*) +(sb-simd-test-suite:define-simple-simd-test f64.2/ (f64.2) (f64.2 &rest f64.2) f64/) +(sb-simd-test-suite:define-simple-simd-test f64.2= (u64.2) (f64.2 &rest f64.2) f64=) +(sb-simd-test-suite:define-simple-simd-test f64.2/= (u64.2) (f64.2 &rest f64.2) f64/=) +(sb-simd-test-suite:define-simple-simd-test f64.2< (u64.2) (f64.2 &rest f64.2) f64<) +(sb-simd-test-suite:define-simple-simd-test f64.2<= (u64.2) (f64.2 &rest f64.2) f64<=) +(sb-simd-test-suite:define-simple-simd-test f64.2> (u64.2) (f64.2 &rest f64.2) f64>) +(sb-simd-test-suite:define-simple-simd-test f64.2>= (u64.2) (f64.2 &rest f64.2) f64>=) + +(sb-simd-test-suite:define-simple-simd-test u8.16-and (u8.16) (&rest u8.16) u8-and) +(sb-simd-test-suite:define-simple-simd-test u8.16-or (u8.16) (&rest u8.16) u8-or) +(sb-simd-test-suite:define-simple-simd-test u8.16-xor (u8.16) (&rest u8.16) u8-xor) +(sb-simd-test-suite:define-simple-simd-test u8.16-andc1 (u8.16) (u8.16 u8.16) u8-andc1) +(sb-simd-test-suite:define-simple-simd-test u8.16-not (u8.16) (u8.16) u8-not) +(sb-simd-test-suite:define-simple-simd-test u8.16+ (u8.16) (&rest u8.16) u8+) +(sb-simd-test-suite:define-simple-simd-test u8.16- (u8.16) (u8.16 &rest u8.16) u8-) +(sb-simd-test-suite:define-simple-simd-test u8.16= (u8.16) (u8.16 &rest u8.16) u8=) +(sb-simd-test-suite:define-simple-simd-test u8.16/= (u8.16) (u8.16 &rest u8.16) u8/=) +(sb-simd-test-suite:define-simple-simd-test u8.16< (u8.16) (u8.16 &rest u8.16) u8<) +(sb-simd-test-suite:define-simple-simd-test u8.16<= (u8.16) (u8.16 &rest u8.16) u8<=) +(sb-simd-test-suite:define-simple-simd-test u8.16> (u8.16) (u8.16 &rest u8.16) u8>) +(sb-simd-test-suite:define-simple-simd-test u8.16>= (u8.16) (u8.16 &rest u8.16) u8>=) + +(sb-simd-test-suite:define-simple-simd-test u16.8-and (u16.8) (&rest u16.8) u16-and) +(sb-simd-test-suite:define-simple-simd-test u16.8-or (u16.8) (&rest u16.8) u16-or) +(sb-simd-test-suite:define-simple-simd-test u16.8-xor (u16.8) (&rest u16.8) u16-xor) +(sb-simd-test-suite:define-simple-simd-test u16.8-andc1 (u16.8) (u16.8 u16.8) u16-andc1) +(sb-simd-test-suite:define-simple-simd-test u16.8-not (u16.8) (u16.8) u16-not) +(sb-simd-test-suite:define-simple-simd-test u16.8+ (u16.8) (&rest u16.8) u16+) +(sb-simd-test-suite:define-simple-simd-test u16.8- (u16.8) (u16.8 &rest u16.8) u16-) +(sb-simd-test-suite:define-simple-simd-test u16.8= (u16.8) (u16.8 &rest u16.8) u16=) +(sb-simd-test-suite:define-simple-simd-test u16.8/= (u16.8) (u16.8 &rest u16.8) u16/=) +(sb-simd-test-suite:define-simple-simd-test u16.8< (u16.8) (u16.8 &rest u16.8) u16<) +(sb-simd-test-suite:define-simple-simd-test u16.8<= (u16.8) (u16.8 &rest u16.8) u16<=) +(sb-simd-test-suite:define-simple-simd-test u16.8> (u16.8) (u16.8 &rest u16.8) u16>) +(sb-simd-test-suite:define-simple-simd-test u16.8>= (u16.8) (u16.8 &rest u16.8) u16>=) + +(sb-simd-test-suite:define-simple-simd-test u32.4-and (u32.4) (&rest u32.4) u32-and) +(sb-simd-test-suite:define-simple-simd-test u32.4-or (u32.4) (&rest u32.4) u32-or) +(sb-simd-test-suite:define-simple-simd-test u32.4-xor (u32.4) (&rest u32.4) u32-xor) +(sb-simd-test-suite:define-simple-simd-test u32.4-andc1 (u32.4) (u32.4 u32.4) u32-andc1) +(sb-simd-test-suite:define-simple-simd-test u32.4-not (u32.4) (u32.4) u32-not) +(sb-simd-test-suite:define-simple-simd-test u32.4+ (u32.4) (&rest u32.4) u32+) +(sb-simd-test-suite:define-simple-simd-test u32.4- (u32.4) (u32.4 &rest u32.4) u32-) +(sb-simd-test-suite:define-simple-simd-test u32.4= (u32.4) (u32.4 &rest u32.4) u32=) +(sb-simd-test-suite:define-simple-simd-test u32.4/= (u32.4) (u32.4 &rest u32.4) u32/=) +(sb-simd-test-suite:define-simple-simd-test u32.4< (u32.4) (u32.4 &rest u32.4) u32<) +(sb-simd-test-suite:define-simple-simd-test u32.4<= (u32.4) (u32.4 &rest u32.4) u32<=) +(sb-simd-test-suite:define-simple-simd-test u32.4> (u32.4) (u32.4 &rest u32.4) u32>) +(sb-simd-test-suite:define-simple-simd-test u32.4>= (u32.4) (u32.4 &rest u32.4) u32>=) + +(sb-simd-test-suite:define-simple-simd-test u64.2-and (u64.2) (&rest u64.2) u64-and) +(sb-simd-test-suite:define-simple-simd-test u64.2-or (u64.2) (&rest u64.2) u64-or) +(sb-simd-test-suite:define-simple-simd-test u64.2-xor (u64.2) (&rest u64.2) u64-xor) +(sb-simd-test-suite:define-simple-simd-test u64.2-andc1 (u64.2) (u64.2 u64.2) u64-andc1) +(sb-simd-test-suite:define-simple-simd-test u64.2-not (u64.2) (u64.2) u64-not) +(sb-simd-test-suite:define-simple-simd-test u64.2+ (u64.2) (&rest u64.2) u64+) +(sb-simd-test-suite:define-simple-simd-test u64.2- (u64.2) (u64.2 &rest u64.2) u64-) + +(sb-simd-test-suite:define-simple-simd-test s8.16-and (s8.16) (&rest s8.16) s8-and) +(sb-simd-test-suite:define-simple-simd-test s8.16-or (s8.16) (&rest s8.16) s8-or) +(sb-simd-test-suite:define-simple-simd-test s8.16-xor (s8.16) (&rest s8.16) s8-xor) +(sb-simd-test-suite:define-simple-simd-test s8.16-andc1 (s8.16) (s8.16 s8.16) s8-andc1) +(sb-simd-test-suite:define-simple-simd-test s8.16-not (s8.16) (s8.16) s8-not) +(sb-simd-test-suite:define-simple-simd-test s8.16+ (s8.16) (&rest s8.16) s8+) +(sb-simd-test-suite:define-simple-simd-test s8.16- (s8.16) (s8.16 &rest s8.16) s8-) +(sb-simd-test-suite:define-simple-simd-test s8.16= (u8.16) (s8.16 &rest s8.16) s8=) +(sb-simd-test-suite:define-simple-simd-test s8.16/= (u8.16) (s8.16 &rest s8.16) s8/=) +(sb-simd-test-suite:define-simple-simd-test s8.16< (u8.16) (s8.16 &rest s8.16) s8<) +(sb-simd-test-suite:define-simple-simd-test s8.16<= (u8.16) (s8.16 &rest s8.16) s8<=) +(sb-simd-test-suite:define-simple-simd-test s8.16> (u8.16) (s8.16 &rest s8.16) s8>) +(sb-simd-test-suite:define-simple-simd-test s8.16>= (u8.16) (s8.16 &rest s8.16) s8>=) + +(sb-simd-test-suite:define-simple-simd-test s16.8-and (s16.8) (&rest s16.8) s16-and) +(sb-simd-test-suite:define-simple-simd-test s16.8-or (s16.8) (&rest s16.8) s16-or) +(sb-simd-test-suite:define-simple-simd-test s16.8-xor (s16.8) (&rest s16.8) s16-xor) +(sb-simd-test-suite:define-simple-simd-test s16.8-andc1 (s16.8) (s16.8 s16.8) s16-andc1) +(sb-simd-test-suite:define-simple-simd-test s16.8-not (s16.8) (s16.8) s16-not) +(sb-simd-test-suite:define-simple-simd-test s16.8+ (s16.8) (&rest s16.8) s16+) +(sb-simd-test-suite:define-simple-simd-test s16.8- (s16.8) (s16.8 &rest s16.8) s16-) +(sb-simd-test-suite:define-simple-simd-test s16.8= (u16.8) (s16.8 &rest s16.8) s16=) +(sb-simd-test-suite:define-simple-simd-test s16.8/= (u16.8) (s16.8 &rest s16.8) s16/=) +(sb-simd-test-suite:define-simple-simd-test s16.8< (u16.8) (s16.8 &rest s16.8) s16<) +(sb-simd-test-suite:define-simple-simd-test s16.8<= (u16.8) (s16.8 &rest s16.8) s16<=) +(sb-simd-test-suite:define-simple-simd-test s16.8> (u16.8) (s16.8 &rest s16.8) s16>) +(sb-simd-test-suite:define-simple-simd-test s16.8>= (u16.8) (s16.8 &rest s16.8) s16>=) + +(sb-simd-test-suite:define-simple-simd-test s32.4-and (s32.4) (&rest s32.4) s32-and) +(sb-simd-test-suite:define-simple-simd-test s32.4-or (s32.4) (&rest s32.4) s32-or) +(sb-simd-test-suite:define-simple-simd-test s32.4-xor (s32.4) (&rest s32.4) s32-xor) +(sb-simd-test-suite:define-simple-simd-test s32.4-andc1 (s32.4) (s32.4 s32.4) s32-andc1) +(sb-simd-test-suite:define-simple-simd-test s32.4-not (s32.4) (s32.4) s32-not) +(sb-simd-test-suite:define-simple-simd-test s32.4+ (s32.4) (&rest s32.4) s32+) +(sb-simd-test-suite:define-simple-simd-test s32.4- (s32.4) (s32.4 &rest s32.4) s32-) +(sb-simd-test-suite:define-simple-simd-test s32.4= (u32.4) (s32.4 &rest s32.4) s32=) +(sb-simd-test-suite:define-simple-simd-test s32.4/= (u32.4) (s32.4 &rest s32.4) s32/=) +(sb-simd-test-suite:define-simple-simd-test s32.4< (u32.4) (s32.4 &rest s32.4) s32<) +(sb-simd-test-suite:define-simple-simd-test s32.4<= (u32.4) (s32.4 &rest s32.4) s32<=) +(sb-simd-test-suite:define-simple-simd-test s32.4> (u32.4) (s32.4 &rest s32.4) s32>) +(sb-simd-test-suite:define-simple-simd-test s32.4>= (u32.4) (s32.4 &rest s32.4) s32>=) + +(sb-simd-test-suite:define-simple-simd-test s64.2-and (s64.2) (&rest s64.2) s64-and) +(sb-simd-test-suite:define-simple-simd-test s64.2-or (s64.2) (&rest s64.2) s64-or) +(sb-simd-test-suite:define-simple-simd-test s64.2-xor (s64.2) (&rest s64.2) s64-xor) +(sb-simd-test-suite:define-simple-simd-test s64.2-andc1 (s64.2) (s64.2 s64.2) s64-andc1) +(sb-simd-test-suite:define-simple-simd-test s64.2-not (s64.2) (s64.2) s64-not) +(sb-simd-test-suite:define-simple-simd-test s64.2+ (s64.2) (&rest s64.2) s64+) +(sb-simd-test-suite:define-simple-simd-test s64.2- (s64.2) (s64.2 &rest s64.2) s64-) + +(in-package #:sb-simd-sse4.1) + +(sb-simd-test-suite:define-simple-simd-test f32.4-if (f32.4) (u32.4 f32.4 f32.4) f32-if) +(sb-simd-test-suite:define-simple-simd-test f64.2-if (f64.2) (u64.2 f64.2 f64.2) f64-if) +(sb-simd-test-suite:define-simple-simd-test u8.16-if (u8.16) (u8.16 u8.16 u8.16) u8-if) +(sb-simd-test-suite:define-simple-simd-test u16.8-if (u16.8) (u16.8 u16.8 u16.8) u16-if) +(sb-simd-test-suite:define-simple-simd-test u32.4-if (u32.4) (u32.4 u32.4 u32.4) u32-if) +(sb-simd-test-suite:define-simple-simd-test u64.2-if (u64.2) (u64.2 u64.2 u64.2) u64-if) +(sb-simd-test-suite:define-simple-simd-test s8.16-if (s8.16) (u8.16 s8.16 s8.16) s8-if) +(sb-simd-test-suite:define-simple-simd-test s16.8-if (s16.8) (u16.8 s16.8 s16.8) s16-if) +(sb-simd-test-suite:define-simple-simd-test s32.4-if (s32.4) (u32.4 s32.4 s32.4) s32-if) +(sb-simd-test-suite:define-simple-simd-test s64.2-if (s64.2) (u64.2 s64.2 s64.2) s64-if) + +(sb-simd-test-suite:define-simple-simd-test u64.2= (u64.2) (u64.2 &rest u64.2) u64=) +(sb-simd-test-suite:define-simple-simd-test u64.2/= (u64.2) (u64.2 &rest u64.2) u64/=) + +(sb-simd-test-suite:define-simple-simd-test s64.2= (u64.2) (s64.2 &rest s64.2) s64=) +(sb-simd-test-suite:define-simple-simd-test s64.2/= (u64.2) (s64.2 &rest s64.2) s64/=) + +(in-package #:sb-simd-sse4.2) + +(sb-simd-test-suite:define-simple-simd-test u64.2< (u64.2) (u64.2 &rest u64.2) u64<) +(sb-simd-test-suite:define-simple-simd-test u64.2<= (u64.2) (u64.2 &rest u64.2) u64<=) +(sb-simd-test-suite:define-simple-simd-test u64.2> (u64.2) (u64.2 &rest u64.2) u64>) +(sb-simd-test-suite:define-simple-simd-test u64.2>= (u64.2) (u64.2 &rest u64.2) u64>=) + +(sb-simd-test-suite:define-simple-simd-test s64.2< (u64.2) (s64.2 &rest s64.2) s64<) +(sb-simd-test-suite:define-simple-simd-test s64.2<= (u64.2) (s64.2 &rest s64.2) s64<=) +(sb-simd-test-suite:define-simple-simd-test s64.2> (u64.2) (s64.2 &rest s64.2) s64>) +(sb-simd-test-suite:define-simple-simd-test s64.2>= (u64.2) (s64.2 &rest s64.2) s64>=) + +(in-package #:sb-simd-avx) + +(sb-simd-test-suite:define-simple-simd-test f32.4-if (f32.4) (u32.4 f32.4 f32.4) f32-if) +(sb-simd-test-suite:define-simple-simd-test f32.4-and (f32.4) (&rest f32.4) f32-and) +(sb-simd-test-suite:define-simple-simd-test f32.4-or (f32.4) (&rest f32.4) f32-or) +(sb-simd-test-suite:define-simple-simd-test f32.4-xor (f32.4) (&rest f32.4) f32-xor) +(sb-simd-test-suite:define-simple-simd-test f32.4-andc1 (f32.4) (f32.4 f32.4) f32-andc1) +(sb-simd-test-suite:define-simple-simd-test f32.4-not (f32.4) (f32.4) f32-not) +(sb-simd-test-suite:define-simple-simd-test f32.4-max (f32.4) (f32.4 &rest f32.4) f32-max) +(sb-simd-test-suite:define-simple-simd-test f32.4-min (f32.4) (f32.4 &rest f32.4) f32-min) +(sb-simd-test-suite:define-simple-simd-test f32.4+ (f32.4) (&rest f32.4) f32+) +(sb-simd-test-suite:define-simple-simd-test f32.4- (f32.4) (f32.4 &rest f32.4) f32-) +(sb-simd-test-suite:define-simple-simd-test f32.4* (f32.4) (&rest f32.4) f32*) +(sb-simd-test-suite:define-simple-simd-test f32.4/ (f32.4) (f32.4 &rest f32.4) f32/) +(sb-simd-test-suite:define-simple-simd-test f32.4= (u32.4) (f32.4 &rest f32.4) f32=) +(sb-simd-test-suite:define-simple-simd-test f32.4/= (u32.4) (f32.4 &rest f32.4) f32/=) +(sb-simd-test-suite:define-simple-simd-test f32.4< (u32.4) (f32.4 &rest f32.4) f32<) +(sb-simd-test-suite:define-simple-simd-test f32.4<= (u32.4) (f32.4 &rest f32.4) f32<=) +(sb-simd-test-suite:define-simple-simd-test f32.4> (u32.4) (f32.4 &rest f32.4) f32>) +(sb-simd-test-suite:define-simple-simd-test f32.4>= (u32.4) (f32.4 &rest f32.4) f32>=) + +(sb-simd-test-suite:define-simple-simd-test f32.8-if (f32.8) (u32.8 f32.8 f32.8) f32-if) +(sb-simd-test-suite:define-simple-simd-test f32.8-and (f32.8) (&rest f32.8) f32-and) +(sb-simd-test-suite:define-simple-simd-test f32.8-or (f32.8) (&rest f32.8) f32-or) +(sb-simd-test-suite:define-simple-simd-test f32.8-xor (f32.8) (&rest f32.8) f32-xor) +(sb-simd-test-suite:define-simple-simd-test f32.8-andc1 (f32.8) (f32.8 f32.8) f32-andc1) +(sb-simd-test-suite:define-simple-simd-test f32.8-not (f32.8) (f32.8) f32-not) +(sb-simd-test-suite:define-simple-simd-test f32.8-max (f32.8) (f32.8 &rest f32.8) f32-max) +(sb-simd-test-suite:define-simple-simd-test f32.8-min (f32.8) (f32.8 &rest f32.8) f32-min) +(sb-simd-test-suite:define-simple-simd-test f32.8+ (f32.8) (&rest f32.8) f32+) +(sb-simd-test-suite:define-simple-simd-test f32.8- (f32.8) (f32.8 &rest f32.8) f32-) +(sb-simd-test-suite:define-simple-simd-test f32.8* (f32.8) (&rest f32.8) f32*) +(sb-simd-test-suite:define-simple-simd-test f32.8/ (f32.8) (f32.8 &rest f32.8) f32/) +(sb-simd-test-suite:define-simple-simd-test f32.8= (u32.8) (f32.8 &rest f32.8) f32=) +(sb-simd-test-suite:define-simple-simd-test f32.8/= (u32.8) (f32.8 &rest f32.8) f32/=) +(sb-simd-test-suite:define-simple-simd-test f32.8< (u32.8) (f32.8 &rest f32.8) f32<) +(sb-simd-test-suite:define-simple-simd-test f32.8<= (u32.8) (f32.8 &rest f32.8) f32<=) +(sb-simd-test-suite:define-simple-simd-test f32.8> (u32.8) (f32.8 &rest f32.8) f32>) +(sb-simd-test-suite:define-simple-simd-test f32.8>= (u32.8) (f32.8 &rest f32.8) f32>=) + +(sb-simd-test-suite:define-simple-simd-test f64.2-if (f64.2) (u64.2 f64.2 f64.2) f64-if) +(sb-simd-test-suite:define-simple-simd-test f64.2-and (f64.2) (&rest f64.2) f64-and) +(sb-simd-test-suite:define-simple-simd-test f64.2-or (f64.2) (&rest f64.2) f64-or) +(sb-simd-test-suite:define-simple-simd-test f64.2-xor (f64.2) (&rest f64.2) f64-xor) +(sb-simd-test-suite:define-simple-simd-test f64.2-andc1 (f64.2) (f64.2 f64.2) f64-andc1) +(sb-simd-test-suite:define-simple-simd-test f64.2-not (f64.2) (f64.2) f64-not) +(sb-simd-test-suite:define-simple-simd-test f64.2-max (f64.2) (f64.2 &rest f64.2) f64-max) +(sb-simd-test-suite:define-simple-simd-test f64.2-min (f64.2) (f64.2 &rest f64.2) f64-min) +(sb-simd-test-suite:define-simple-simd-test f64.2+ (f64.2) (&rest f64.2) f64+) +(sb-simd-test-suite:define-simple-simd-test f64.2- (f64.2) (f64.2 &rest f64.2) f64-) +(sb-simd-test-suite:define-simple-simd-test f64.2* (f64.2) (&rest f64.2) f64*) +(sb-simd-test-suite:define-simple-simd-test f64.2/ (f64.2) (f64.2 &rest f64.2) f64/) +(sb-simd-test-suite:define-simple-simd-test f64.2= (u64.2) (f64.2 &rest f64.2) f64=) +(sb-simd-test-suite:define-simple-simd-test f64.2/= (u64.2) (f64.2 &rest f64.2) f64/=) +(sb-simd-test-suite:define-simple-simd-test f64.2< (u64.2) (f64.2 &rest f64.2) f64<) +(sb-simd-test-suite:define-simple-simd-test f64.2<= (u64.2) (f64.2 &rest f64.2) f64<=) +(sb-simd-test-suite:define-simple-simd-test f64.2> (u64.2) (f64.2 &rest f64.2) f64>) +(sb-simd-test-suite:define-simple-simd-test f64.2>= (u64.2) (f64.2 &rest f64.2) f64>=) + +(sb-simd-test-suite:define-simple-simd-test f64.4-if (f64.4) (u64.4 f64.4 f64.4) f64-if) +(sb-simd-test-suite:define-simple-simd-test f64.4-and (f64.4) (&rest f64.4) f64-and) +(sb-simd-test-suite:define-simple-simd-test f64.4-or (f64.4) (&rest f64.4) f64-or) +(sb-simd-test-suite:define-simple-simd-test f64.4-xor (f64.4) (&rest f64.4) f64-xor) +(sb-simd-test-suite:define-simple-simd-test f64.4-andc1 (f64.4) (f64.4 f64.4) f64-andc1) +(sb-simd-test-suite:define-simple-simd-test f64.4-not (f64.4) (f64.4) f64-not) +(sb-simd-test-suite:define-simple-simd-test f64.4-max (f64.4) (f64.4 &rest f64.4) f64-max) +(sb-simd-test-suite:define-simple-simd-test f64.4-min (f64.4) (f64.4 &rest f64.4) f64-min) +(sb-simd-test-suite:define-simple-simd-test f64.4+ (f64.4) (&rest f64.4) f64+) +(sb-simd-test-suite:define-simple-simd-test f64.4- (f64.4) (f64.4 &rest f64.4) f64-) +(sb-simd-test-suite:define-simple-simd-test f64.4* (f64.4) (&rest f64.4) f64*) +(sb-simd-test-suite:define-simple-simd-test f64.4/ (f64.4) (f64.4 &rest f64.4) f64/) +(sb-simd-test-suite:define-simple-simd-test f64.4= (u64.4) (f64.4 &rest f64.4) f64=) +(sb-simd-test-suite:define-simple-simd-test f64.4/= (u64.4) (f64.4 &rest f64.4) f64/=) +(sb-simd-test-suite:define-simple-simd-test f64.4< (u64.4) (f64.4 &rest f64.4) f64<) +(sb-simd-test-suite:define-simple-simd-test f64.4<= (u64.4) (f64.4 &rest f64.4) f64<=) +(sb-simd-test-suite:define-simple-simd-test f64.4> (u64.4) (f64.4 &rest f64.4) f64>) +(sb-simd-test-suite:define-simple-simd-test f64.4>= (u64.4) (f64.4 &rest f64.4) f64>=) + +(sb-simd-test-suite:define-simple-simd-test u8.16-if (u8.16) (u8.16 u8.16 u8.16) u8-if) +(sb-simd-test-suite:define-simple-simd-test u8.16-and (u8.16) (&rest u8.16) u8-and) +(sb-simd-test-suite:define-simple-simd-test u8.16-or (u8.16) (&rest u8.16) u8-or) +(sb-simd-test-suite:define-simple-simd-test u8.16-xor (u8.16) (&rest u8.16) u8-xor) +(sb-simd-test-suite:define-simple-simd-test u8.16-andc1 (u8.16) (u8.16 u8.16) u8-andc1) +(sb-simd-test-suite:define-simple-simd-test u8.16-not (u8.16) (u8.16) u8-not) +(sb-simd-test-suite:define-simple-simd-test u8.16+ (u8.16) (&rest u8.16) u8+) +(sb-simd-test-suite:define-simple-simd-test u8.16- (u8.16) (u8.16 &rest u8.16) u8-) +(sb-simd-test-suite:define-simple-simd-test u8.16= (u8.16) (u8.16 &rest u8.16) u8=) +(sb-simd-test-suite:define-simple-simd-test u8.16/= (u8.16) (u8.16 &rest u8.16) u8/=) +(sb-simd-test-suite:define-simple-simd-test u8.16< (u8.16) (u8.16 &rest u8.16) u8<) +(sb-simd-test-suite:define-simple-simd-test u8.16<= (u8.16) (u8.16 &rest u8.16) u8<=) +(sb-simd-test-suite:define-simple-simd-test u8.16> (u8.16) (u8.16 &rest u8.16) u8>) +(sb-simd-test-suite:define-simple-simd-test u8.16>= (u8.16) (u8.16 &rest u8.16) u8>=) + +(sb-simd-test-suite:define-simple-simd-test u16.8-if (u16.8) (u16.8 u16.8 u16.8) u16-if) +(sb-simd-test-suite:define-simple-simd-test u16.8-and (u16.8) (&rest u16.8) u16-and) +(sb-simd-test-suite:define-simple-simd-test u16.8-or (u16.8) (&rest u16.8) u16-or) +(sb-simd-test-suite:define-simple-simd-test u16.8-xor (u16.8) (&rest u16.8) u16-xor) +(sb-simd-test-suite:define-simple-simd-test u16.8-andc1 (u16.8) (u16.8 u16.8) u16-andc1) +(sb-simd-test-suite:define-simple-simd-test u16.8-not (u16.8) (u16.8) u16-not) +(sb-simd-test-suite:define-simple-simd-test u16.8+ (u16.8) (&rest u16.8) u16+) +(sb-simd-test-suite:define-simple-simd-test u16.8- (u16.8) (u16.8 &rest u16.8) u16-) +(sb-simd-test-suite:define-simple-simd-test u16.8= (u16.8) (u16.8 &rest u16.8) u16=) +(sb-simd-test-suite:define-simple-simd-test u16.8/= (u16.8) (u16.8 &rest u16.8) u16/=) +(sb-simd-test-suite:define-simple-simd-test u16.8< (u16.8) (u16.8 &rest u16.8) u16<) +(sb-simd-test-suite:define-simple-simd-test u16.8<= (u16.8) (u16.8 &rest u16.8) u16<=) +(sb-simd-test-suite:define-simple-simd-test u16.8> (u16.8) (u16.8 &rest u16.8) u16>) +(sb-simd-test-suite:define-simple-simd-test u16.8>= (u16.8) (u16.8 &rest u16.8) u16>=) + +(sb-simd-test-suite:define-simple-simd-test u32.4-if (u32.4) (u32.4 u32.4 u32.4) u32-if) +(sb-simd-test-suite:define-simple-simd-test u32.4-and (u32.4) (&rest u32.4) u32-and) +(sb-simd-test-suite:define-simple-simd-test u32.4-or (u32.4) (&rest u32.4) u32-or) +(sb-simd-test-suite:define-simple-simd-test u32.4-xor (u32.4) (&rest u32.4) u32-xor) +(sb-simd-test-suite:define-simple-simd-test u32.4-andc1 (u32.4) (u32.4 u32.4) u32-andc1) +(sb-simd-test-suite:define-simple-simd-test u32.4-not (u32.4) (u32.4) u32-not) +(sb-simd-test-suite:define-simple-simd-test u32.4+ (u32.4) (&rest u32.4) u32+) +(sb-simd-test-suite:define-simple-simd-test u32.4- (u32.4) (u32.4 &rest u32.4) u32-) +(sb-simd-test-suite:define-simple-simd-test u32.4= (u32.4) (u32.4 &rest u32.4) u32=) +(sb-simd-test-suite:define-simple-simd-test u32.4/= (u32.4) (u32.4 &rest u32.4) u32/=) +(sb-simd-test-suite:define-simple-simd-test u32.4< (u32.4) (u32.4 &rest u32.4) u32<) +(sb-simd-test-suite:define-simple-simd-test u32.4<= (u32.4) (u32.4 &rest u32.4) u32<=) +(sb-simd-test-suite:define-simple-simd-test u32.4> (u32.4) (u32.4 &rest u32.4) u32>) +(sb-simd-test-suite:define-simple-simd-test u32.4>= (u32.4) (u32.4 &rest u32.4) u32>=) + +(sb-simd-test-suite:define-simple-simd-test u64.2-if (u64.2) (u64.2 u64.2 u64.2) u64-if) +(sb-simd-test-suite:define-simple-simd-test u64.2-and (u64.2) (&rest u64.2) u64-and) +(sb-simd-test-suite:define-simple-simd-test u64.2-or (u64.2) (&rest u64.2) u64-or) +(sb-simd-test-suite:define-simple-simd-test u64.2-xor (u64.2) (&rest u64.2) u64-xor) +(sb-simd-test-suite:define-simple-simd-test u64.2-andc1 (u64.2) (u64.2 u64.2) u64-andc1) +(sb-simd-test-suite:define-simple-simd-test u64.2-not (u64.2) (u64.2) u64-not) +(sb-simd-test-suite:define-simple-simd-test u64.2+ (u64.2) (&rest u64.2) u64+) +(sb-simd-test-suite:define-simple-simd-test u64.2- (u64.2) (u64.2 &rest u64.2) u64-) +(sb-simd-test-suite:define-simple-simd-test u64.2= (u64.2) (u64.2 &rest u64.2) u64=) +(sb-simd-test-suite:define-simple-simd-test u64.2/= (u64.2) (u64.2 &rest u64.2) u64/=) +(sb-simd-test-suite:define-simple-simd-test u64.2< (u64.2) (u64.2 &rest u64.2) u64<) +(sb-simd-test-suite:define-simple-simd-test u64.2<= (u64.2) (u64.2 &rest u64.2) u64<=) +(sb-simd-test-suite:define-simple-simd-test u64.2> (u64.2) (u64.2 &rest u64.2) u64>) +(sb-simd-test-suite:define-simple-simd-test u64.2>= (u64.2) (u64.2 &rest u64.2) u64>=) + +(sb-simd-test-suite:define-simple-simd-test s8.16-if (s8.16) (u8.16 s8.16 s8.16) s8-if) +(sb-simd-test-suite:define-simple-simd-test s8.16-and (s8.16) (&rest s8.16) s8-and) +(sb-simd-test-suite:define-simple-simd-test s8.16-or (s8.16) (&rest s8.16) s8-or) +(sb-simd-test-suite:define-simple-simd-test s8.16-xor (s8.16) (&rest s8.16) s8-xor) +(sb-simd-test-suite:define-simple-simd-test s8.16-andc1 (s8.16) (s8.16 s8.16) s8-andc1) +(sb-simd-test-suite:define-simple-simd-test s8.16-not (s8.16) (s8.16) s8-not) +(sb-simd-test-suite:define-simple-simd-test s8.16+ (s8.16) (&rest s8.16) s8+) +(sb-simd-test-suite:define-simple-simd-test s8.16- (s8.16) (s8.16 &rest s8.16) s8-) +(sb-simd-test-suite:define-simple-simd-test s8.16= (u8.16) (s8.16 &rest s8.16) s8=) +(sb-simd-test-suite:define-simple-simd-test s8.16/= (u8.16) (s8.16 &rest s8.16) s8/=) +(sb-simd-test-suite:define-simple-simd-test s8.16< (u8.16) (s8.16 &rest s8.16) s8<) +(sb-simd-test-suite:define-simple-simd-test s8.16<= (u8.16) (s8.16 &rest s8.16) s8<=) +(sb-simd-test-suite:define-simple-simd-test s8.16> (u8.16) (s8.16 &rest s8.16) s8>) +(sb-simd-test-suite:define-simple-simd-test s8.16>= (u8.16) (s8.16 &rest s8.16) s8>=) + +(sb-simd-test-suite:define-simple-simd-test s16.8-if (s16.8) (u16.8 s16.8 s16.8) s16-if) +(sb-simd-test-suite:define-simple-simd-test s16.8-and (s16.8) (&rest s16.8) s16-and) +(sb-simd-test-suite:define-simple-simd-test s16.8-or (s16.8) (&rest s16.8) s16-or) +(sb-simd-test-suite:define-simple-simd-test s16.8-xor (s16.8) (&rest s16.8) s16-xor) +(sb-simd-test-suite:define-simple-simd-test s16.8-andc1 (s16.8) (s16.8 s16.8) s16-andc1) +(sb-simd-test-suite:define-simple-simd-test s16.8-not (s16.8) (s16.8) s16-not) +(sb-simd-test-suite:define-simple-simd-test s16.8+ (s16.8) (&rest s16.8) s16+) +(sb-simd-test-suite:define-simple-simd-test s16.8- (s16.8) (s16.8 &rest s16.8) s16-) +(sb-simd-test-suite:define-simple-simd-test s16.8= (u16.8) (s16.8 &rest s16.8) s16=) +(sb-simd-test-suite:define-simple-simd-test s16.8/= (u16.8) (s16.8 &rest s16.8) s16/=) +(sb-simd-test-suite:define-simple-simd-test s16.8< (u16.8) (s16.8 &rest s16.8) s16<) +(sb-simd-test-suite:define-simple-simd-test s16.8<= (u16.8) (s16.8 &rest s16.8) s16<=) +(sb-simd-test-suite:define-simple-simd-test s16.8> (u16.8) (s16.8 &rest s16.8) s16>) +(sb-simd-test-suite:define-simple-simd-test s16.8>= (u16.8) (s16.8 &rest s16.8) s16>=) + +(sb-simd-test-suite:define-simple-simd-test s32.4-if (s32.4) (u32.4 s32.4 s32.4) s32-if) +(sb-simd-test-suite:define-simple-simd-test s32.4-and (s32.4) (&rest s32.4) s32-and) +(sb-simd-test-suite:define-simple-simd-test s32.4-or (s32.4) (&rest s32.4) s32-or) +(sb-simd-test-suite:define-simple-simd-test s32.4-xor (s32.4) (&rest s32.4) s32-xor) +(sb-simd-test-suite:define-simple-simd-test s32.4-andc1 (s32.4) (s32.4 s32.4) s32-andc1) +(sb-simd-test-suite:define-simple-simd-test s32.4-not (s32.4) (s32.4) s32-not) +(sb-simd-test-suite:define-simple-simd-test s32.4+ (s32.4) (&rest s32.4) s32+) +(sb-simd-test-suite:define-simple-simd-test s32.4- (s32.4) (s32.4 &rest s32.4) s32-) +(sb-simd-test-suite:define-simple-simd-test s32.4= (u32.4) (s32.4 &rest s32.4) s32=) +(sb-simd-test-suite:define-simple-simd-test s32.4/= (u32.4) (s32.4 &rest s32.4) s32/=) +(sb-simd-test-suite:define-simple-simd-test s32.4< (u32.4) (s32.4 &rest s32.4) s32<) +(sb-simd-test-suite:define-simple-simd-test s32.4<= (u32.4) (s32.4 &rest s32.4) s32<=) +(sb-simd-test-suite:define-simple-simd-test s32.4> (u32.4) (s32.4 &rest s32.4) s32>) +(sb-simd-test-suite:define-simple-simd-test s32.4>= (u32.4) (s32.4 &rest s32.4) s32>=) + +(sb-simd-test-suite:define-simple-simd-test s64.2-if (s64.2) (u64.2 s64.2 s64.2) s64-if) +(sb-simd-test-suite:define-simple-simd-test s64.2-and (s64.2) (&rest s64.2) s64-and) +(sb-simd-test-suite:define-simple-simd-test s64.2-or (s64.2) (&rest s64.2) s64-or) +(sb-simd-test-suite:define-simple-simd-test s64.2-xor (s64.2) (&rest s64.2) s64-xor) +(sb-simd-test-suite:define-simple-simd-test s64.2-andc1 (s64.2) (s64.2 s64.2) s64-andc1) +(sb-simd-test-suite:define-simple-simd-test s64.2-not (s64.2) (s64.2) s64-not) +(sb-simd-test-suite:define-simple-simd-test s64.2+ (s64.2) (&rest s64.2) s64+) +(sb-simd-test-suite:define-simple-simd-test s64.2- (s64.2) (s64.2 &rest s64.2) s64-) +(sb-simd-test-suite:define-simple-simd-test s64.2= (u64.2) (s64.2 &rest s64.2) s64=) +(sb-simd-test-suite:define-simple-simd-test s64.2< (u64.2) (s64.2 &rest s64.2) s64<) +(sb-simd-test-suite:define-simple-simd-test s64.2<= (u64.2) (s64.2 &rest s64.2) s64<=) +(sb-simd-test-suite:define-simple-simd-test s64.2> (u64.2) (s64.2 &rest s64.2) s64>) +(sb-simd-test-suite:define-simple-simd-test s64.2>= (u64.2) (s64.2 &rest s64.2) s64>=) + +(in-package #:sb-simd-avx2) + +(sb-simd-test-suite:define-simple-simd-test u8.32-if (u8.32) (u8.32 u8.32 u8.32) u8-if) +(sb-simd-test-suite:define-simple-simd-test u8.32-and (u8.32) (&rest u8.32) u8-and) +(sb-simd-test-suite:define-simple-simd-test u8.32-or (u8.32) (&rest u8.32) u8-or) +(sb-simd-test-suite:define-simple-simd-test u8.32-xor (u8.32) (&rest u8.32) u8-xor) +(sb-simd-test-suite:define-simple-simd-test u8.32-andc1 (u8.32) (u8.32 u8.32) u8-andc1) +(sb-simd-test-suite:define-simple-simd-test u8.32-not (u8.32) (u8.32) u8-not) +(sb-simd-test-suite:define-simple-simd-test u8.32+ (u8.32) (&rest u8.32) u8+) +(sb-simd-test-suite:define-simple-simd-test u8.32- (u8.32) (u8.32 &rest u8.32) u8-) +(sb-simd-test-suite:define-simple-simd-test u8.32= (u8.32) (u8.32 &rest u8.32) u8=) +(sb-simd-test-suite:define-simple-simd-test u8.32/= (u8.32) (u8.32 &rest u8.32) u8/=) +(sb-simd-test-suite:define-simple-simd-test u8.32< (u8.32) (u8.32 &rest u8.32) u8<) +(sb-simd-test-suite:define-simple-simd-test u8.32<= (u8.32) (u8.32 &rest u8.32) u8<=) +(sb-simd-test-suite:define-simple-simd-test u8.32> (u8.32) (u8.32 &rest u8.32) u8>) +(sb-simd-test-suite:define-simple-simd-test u8.32>= (u8.32) (u8.32 &rest u8.32) u8>=) + +(sb-simd-test-suite:define-simple-simd-test u16.16-if (u16.16) (u16.16 u16.16 u16.16) u16-if) +(sb-simd-test-suite:define-simple-simd-test u16.16-and (u16.16) (&rest u16.16) u16-and) +(sb-simd-test-suite:define-simple-simd-test u16.16-or (u16.16) (&rest u16.16) u16-or) +(sb-simd-test-suite:define-simple-simd-test u16.16-xor (u16.16) (&rest u16.16) u16-xor) +(sb-simd-test-suite:define-simple-simd-test u16.16-andc1 (u16.16) (u16.16 u16.16) u16-andc1) +(sb-simd-test-suite:define-simple-simd-test u16.16-not (u16.16) (u16.16) u16-not) +(sb-simd-test-suite:define-simple-simd-test u16.16+ (u16.16) (&rest u16.16) u16+) +(sb-simd-test-suite:define-simple-simd-test u16.16- (u16.16) (u16.16 &rest u16.16) u16-) +(sb-simd-test-suite:define-simple-simd-test u16.16= (u16.16) (u16.16 &rest u16.16) u16=) +(sb-simd-test-suite:define-simple-simd-test u16.16/= (u16.16) (u16.16 &rest u16.16) u16/=) +(sb-simd-test-suite:define-simple-simd-test u16.16< (u16.16) (u16.16 &rest u16.16) u16<) +(sb-simd-test-suite:define-simple-simd-test u16.16<= (u16.16) (u16.16 &rest u16.16) u16<=) +(sb-simd-test-suite:define-simple-simd-test u16.16> (u16.16) (u16.16 &rest u16.16) u16>) +(sb-simd-test-suite:define-simple-simd-test u16.16>= (u16.16) (u16.16 &rest u16.16) u16>=) + +(sb-simd-test-suite:define-simple-simd-test u32.8-if (u32.8) (u32.8 u32.8 u32.8) u32-if) +(sb-simd-test-suite:define-simple-simd-test u32.8-and (u32.8) (&rest u32.8) u32-and) +(sb-simd-test-suite:define-simple-simd-test u32.8-or (u32.8) (&rest u32.8) u32-or) +(sb-simd-test-suite:define-simple-simd-test u32.8-xor (u32.8) (&rest u32.8) u32-xor) +(sb-simd-test-suite:define-simple-simd-test u32.8-andc1 (u32.8) (u32.8 u32.8) u32-andc1) +(sb-simd-test-suite:define-simple-simd-test u32.8-not (u32.8) (u32.8) u32-not) +(sb-simd-test-suite:define-simple-simd-test u32.8+ (u32.8) (&rest u32.8) u32+) +(sb-simd-test-suite:define-simple-simd-test u32.8- (u32.8) (u32.8 &rest u32.8) u32-) +(sb-simd-test-suite:define-simple-simd-test u32.8= (u32.8) (u32.8 &rest u32.8) u32=) +(sb-simd-test-suite:define-simple-simd-test u32.8/= (u32.8) (u32.8 &rest u32.8) u32/=) +(sb-simd-test-suite:define-simple-simd-test u32.8< (u32.8) (u32.8 &rest u32.8) u32<) +(sb-simd-test-suite:define-simple-simd-test u32.8<= (u32.8) (u32.8 &rest u32.8) u32<=) +(sb-simd-test-suite:define-simple-simd-test u32.8> (u32.8) (u32.8 &rest u32.8) u32>) +(sb-simd-test-suite:define-simple-simd-test u32.8>= (u32.8) (u32.8 &rest u32.8) u32>=) + +(sb-simd-test-suite:define-simple-simd-test u64.4-if (u64.4) (u64.4 u64.4 u64.4) u64-if) +(sb-simd-test-suite:define-simple-simd-test u64.4-and (u64.4) (&rest u64.4) u64-and) +(sb-simd-test-suite:define-simple-simd-test u64.4-or (u64.4) (&rest u64.4) u64-or) +(sb-simd-test-suite:define-simple-simd-test u64.4-xor (u64.4) (&rest u64.4) u64-xor) +(sb-simd-test-suite:define-simple-simd-test u64.4-andc1 (u64.4) (u64.4 u64.4) u64-andc1) +(sb-simd-test-suite:define-simple-simd-test u64.4-not (u64.4) (u64.4) u64-not) +(sb-simd-test-suite:define-simple-simd-test u64.4+ (u64.4) (&rest u64.4) u64+) +(sb-simd-test-suite:define-simple-simd-test u64.4- (u64.4) (u64.4 &rest u64.4) u64-) +(sb-simd-test-suite:define-simple-simd-test u64.4= (u64.4) (u64.4 &rest u64.4) u64=) +(sb-simd-test-suite:define-simple-simd-test u64.4/= (u64.4) (u64.4 &rest u64.4) u64/=) +(sb-simd-test-suite:define-simple-simd-test u64.4< (u64.4) (u64.4 &rest u64.4) u64<) +(sb-simd-test-suite:define-simple-simd-test u64.4<= (u64.4) (u64.4 &rest u64.4) u64<=) +(sb-simd-test-suite:define-simple-simd-test u64.4> (u64.4) (u64.4 &rest u64.4) u64>) +(sb-simd-test-suite:define-simple-simd-test u64.4>= (u64.4) (u64.4 &rest u64.4) u64>=) + +(sb-simd-test-suite:define-simple-simd-test s8.32-if (s8.32) (u8.32 s8.32 s8.32) s8-if) +(sb-simd-test-suite:define-simple-simd-test s8.32-and (s8.32) (&rest s8.32) s8-and) +(sb-simd-test-suite:define-simple-simd-test s8.32-or (s8.32) (&rest s8.32) s8-or) +(sb-simd-test-suite:define-simple-simd-test s8.32-xor (s8.32) (&rest s8.32) s8-xor) +(sb-simd-test-suite:define-simple-simd-test s8.32-andc1 (s8.32) (s8.32 s8.32) s8-andc1) +(sb-simd-test-suite:define-simple-simd-test s8.32-not (s8.32) (s8.32) s8-not) +(sb-simd-test-suite:define-simple-simd-test s8.32+ (s8.32) (&rest s8.32) s8+) +(sb-simd-test-suite:define-simple-simd-test s8.32- (s8.32) (s8.32 &rest s8.32) s8-) +(sb-simd-test-suite:define-simple-simd-test s8.32= (u8.32) (s8.32 &rest s8.32) s8=) +(sb-simd-test-suite:define-simple-simd-test s8.32/= (u8.32) (s8.32 &rest s8.32) s8/=) +(sb-simd-test-suite:define-simple-simd-test s8.32< (u8.32) (s8.32 &rest s8.32) s8<) +(sb-simd-test-suite:define-simple-simd-test s8.32<= (u8.32) (s8.32 &rest s8.32) s8<=) +(sb-simd-test-suite:define-simple-simd-test s8.32> (u8.32) (s8.32 &rest s8.32) s8>) +(sb-simd-test-suite:define-simple-simd-test s8.32>= (u8.32) (s8.32 &rest s8.32) s8>=) + +(sb-simd-test-suite:define-simple-simd-test s16.16-if (s16.16) (u16.16 s16.16 s16.16) s16-if) +(sb-simd-test-suite:define-simple-simd-test s16.16-and (s16.16) (&rest s16.16) s16-and) +(sb-simd-test-suite:define-simple-simd-test s16.16-or (s16.16) (&rest s16.16) s16-or) +(sb-simd-test-suite:define-simple-simd-test s16.16-xor (s16.16) (&rest s16.16) s16-xor) +(sb-simd-test-suite:define-simple-simd-test s16.16-andc1 (s16.16) (s16.16 s16.16) s16-andc1) +(sb-simd-test-suite:define-simple-simd-test s16.16-not (s16.16) (s16.16) s16-not) +(sb-simd-test-suite:define-simple-simd-test s16.16+ (s16.16) (&rest s16.16) s16+) +(sb-simd-test-suite:define-simple-simd-test s16.16- (s16.16) (s16.16 &rest s16.16) s16-) +(sb-simd-test-suite:define-simple-simd-test s16.16= (u16.16) (s16.16 &rest s16.16) s16=) +(sb-simd-test-suite:define-simple-simd-test s16.16/= (u16.16) (s16.16 &rest s16.16) s16/=) +(sb-simd-test-suite:define-simple-simd-test s16.16< (u16.16) (s16.16 &rest s16.16) s16<) +(sb-simd-test-suite:define-simple-simd-test s16.16<= (u16.16) (s16.16 &rest s16.16) s16<=) +(sb-simd-test-suite:define-simple-simd-test s16.16> (u16.16) (s16.16 &rest s16.16) s16>) +(sb-simd-test-suite:define-simple-simd-test s16.16>= (u16.16) (s16.16 &rest s16.16) s16>=) + +(sb-simd-test-suite:define-simple-simd-test s32.8-if (s32.8) (u32.8 s32.8 s32.8) s32-if) +(sb-simd-test-suite:define-simple-simd-test s32.8-and (s32.8) (&rest s32.8) s32-and) +(sb-simd-test-suite:define-simple-simd-test s32.8-or (s32.8) (&rest s32.8) s32-or) +(sb-simd-test-suite:define-simple-simd-test s32.8-xor (s32.8) (&rest s32.8) s32-xor) +(sb-simd-test-suite:define-simple-simd-test s32.8-andc1 (s32.8) (s32.8 s32.8) s32-andc1) +(sb-simd-test-suite:define-simple-simd-test s32.8-not (s32.8) (s32.8) s32-not) +(sb-simd-test-suite:define-simple-simd-test s32.8+ (s32.8) (&rest s32.8) s32+) +(sb-simd-test-suite:define-simple-simd-test s32.8- (s32.8) (s32.8 &rest s32.8) s32-) +(sb-simd-test-suite:define-simple-simd-test s32.8= (u32.8) (s32.8 &rest s32.8) s32=) +(sb-simd-test-suite:define-simple-simd-test s32.8/= (u32.8) (s32.8 &rest s32.8) s32/=) +(sb-simd-test-suite:define-simple-simd-test s32.8< (u32.8) (s32.8 &rest s32.8) s32<) +(sb-simd-test-suite:define-simple-simd-test s32.8<= (u32.8) (s32.8 &rest s32.8) s32<=) +(sb-simd-test-suite:define-simple-simd-test s32.8> (u32.8) (s32.8 &rest s32.8) s32>) +(sb-simd-test-suite:define-simple-simd-test s32.8>= (u32.8) (s32.8 &rest s32.8) s32>=) + +(sb-simd-test-suite:define-simple-simd-test s64.4-if (s64.4) (u64.4 s64.4 s64.4) s64-if) +(sb-simd-test-suite:define-simple-simd-test s64.4-and (s64.4) (&rest s64.4) s64-and) +(sb-simd-test-suite:define-simple-simd-test s64.4-or (s64.4) (&rest s64.4) s64-or) +(sb-simd-test-suite:define-simple-simd-test s64.4-xor (s64.4) (&rest s64.4) s64-xor) +(sb-simd-test-suite:define-simple-simd-test s64.4-andc1 (s64.4) (s64.4 s64.4) s64-andc1) +(sb-simd-test-suite:define-simple-simd-test s64.4-not (s64.4) (s64.4) s64-not) +(sb-simd-test-suite:define-simple-simd-test s64.4+ (s64.4) (&rest s64.4) s64+) +(sb-simd-test-suite:define-simple-simd-test s64.4- (s64.4) (s64.4 &rest s64.4) s64-) +(sb-simd-test-suite:define-simple-simd-test s64.4= (u64.4) (s64.4 &rest s64.4) s64=) +(sb-simd-test-suite:define-simple-simd-test s64.4< (u64.4) (s64.4 &rest s64.4) s64<) +(sb-simd-test-suite:define-simple-simd-test s64.4<= (u64.4) (s64.4 &rest s64.4) s64<=) +(sb-simd-test-suite:define-simple-simd-test s64.4> (u64.4) (s64.4 &rest s64.4) s64>) +(sb-simd-test-suite:define-simple-simd-test s64.4>= (u64.4) (s64.4 &rest s64.4) s64>=) + +(in-package #:sb-simd-fma) + +(sb-simd-test-suite:define-simple-simd-test f32.4-fmadd (f32.4) (f32.4 f32.4 f32.4) f32-fmadd) +(sb-simd-test-suite:define-simple-simd-test f32.4-fnmadd (f32.4) (f32.4 f32.4 f32.4) f32-fnmadd) +(sb-simd-test-suite:define-simple-simd-test f32.4-fmsub (f32.4) (f32.4 f32.4 f32.4) f32-fmsub) + +(sb-simd-test-suite:define-simple-simd-test f32.8-fmadd (f32.8) (f32.8 f32.8 f32.8) f32-fmadd) +(sb-simd-test-suite:define-simple-simd-test f32.8-fnmadd (f32.8) (f32.8 f32.8 f32.8) f32-fnmadd) +(sb-simd-test-suite:define-simple-simd-test f32.8-fmsub (f32.8) (f32.8 f32.8 f32.8) f32-fmsub) + +(sb-simd-test-suite:define-simple-simd-test f64.2-fmadd (f64.2) (f64.2 f64.2 f64.2) f64-fmadd) +(sb-simd-test-suite:define-simple-simd-test f64.2-fnmadd (f64.2) (f64.2 f64.2 f64.2) f64-fnmadd) +(sb-simd-test-suite:define-simple-simd-test f64.2-fmsub (f64.2) (f64.2 f64.2 f64.2) f64-fmsub) + +(sb-simd-test-suite:define-simple-simd-test f64.4-fmadd (f64.4) (f64.4 f64.4 f64.4) f64-fmadd) +(sb-simd-test-suite:define-simple-simd-test f64.4-fnmadd (f64.4) (f64.4 f64.4 f64.4) f64-fnmadd) +(sb-simd-test-suite:define-simple-simd-test f64.4-fmsub (f64.4) (f64.4 f64.4 f64.4) f64-fmsub) diff --git a/contrib/sb-simd/test-suite/test-suite.lisp b/contrib/sb-simd/test-suite/test-suite.lisp new file mode 100644 index 0000000000..79fba2e9f9 --- /dev/null +++ b/contrib/sb-simd/test-suite/test-suite.lisp @@ -0,0 +1,157 @@ +(in-package #:sb-simd-test-suite) + +;; A list of the names of all tests defined with the TEST macro. +(defparameter *tests* '()) + +;; The value of *RANDOM-STATE* when the test suite encountered the most +;; recent error, or NIL, if there have been no recent errors. +(defvar *failed-random-state* nil) + +;; The number of tests that have been run so far. +(defvar *test-count*) + +;; The number of successful checks that have been performed so far. +(defvar *pass-count*) + +;; The number of checks that have been performed in the current test. +(defvar *check-count* 0) + +(defun call-with-random-state (thunk) + (let ((*random-state* + (if (not *failed-random-state*) + (load-time-value (make-random-state t)) + *failed-random-state*))) + (setf *failed-random-state* (make-random-state *random-state*)) + (multiple-value-prog1 (funcall thunk) + (setf *failed-random-state* nil)))) + +(defmacro with-random-state (&body body) + `(call-with-random-state (lambda () ,@body))) + +(defun call-with-test-harness (thunk) + (if (and (boundp '*test-count*) + (boundp '*pass-count*)) + (funcall thunk) + (let* ((*test-count* 0) + (*pass-count* 0)) + (with-random-state (funcall thunk)) + (report *test-count* *pass-count*)))) + +(defmacro with-test-harness (&body body) + `(call-with-test-harness (lambda () ,@body))) + +(defun report (test-count pass-count) + (format t "~&Success: ~s test~:p, ~s check~:p.~%" test-count pass-count) + (finish-output)) + +;;; Ensure that DEFINE-TEST never overwrites function names in other +;;; packages. +(defun intern-test-name (test-name) + (let ((test-suite-package #.*package*) + (name (symbol-name test-name)) + (package (symbol-package test-name))) + (cond ((eq package test-suite-package) + test-name) + ((eq (nth-value 1 (find-symbol name package)) :external) + (intern (format nil "~A:~A" (package-name package) name) test-suite-package)) + (t + (intern (format nil "~A:~A" (package-name package) name) test-suite-package))))) + +(defmacro define-test (test-name &body body) + "Define a test function and add it to *TESTS*." + (let ((name (intern-test-name test-name))) + `(prog1 ',name + (defun ,name () + (declare (optimize (debug 3) (safety 3))) + (with-test-harness + (enter-test ',name) + ,@body)) + (pushnew ',name *tests*)))) + +(defun enter-test (test-name) + (incf *test-count*) + (setf *check-count* 0) + (format t "~&~A" (string test-name)) + (finish-output)) + +(defun pass () + (incf *pass-count*) + (when (zerop (logand *check-count* (incf *check-count*))) + (write-char #\.)) + (values)) + +(defmacro is (test-form) + "Assert that TEST-FORM evaluates to true." + `(progn + (assert ,test-form) + (pass))) + +(defun expect-condition (expected thunk) + (block nil + (flet ((handler (condition) + (cond ((typep condition expected) + (pass) + (return)) + (t (error "Expected to signal ~s, but got ~s:~%~a" + expected (type-of condition) condition))))) + (handler-bind ((condition #'handler)) + (funcall thunk))) + (error "Expected to signal ~s, but got nothing." expected))) + +(defmacro signals (condition &body body) + "Assert that `body' signals a condition of type `condition'." + `(expect-condition ',condition (lambda () ,@body))) + +(defun all-tests () + *tests*) + +;;; This function catches particularly hideous bugs - exported symbols with +;;; no attached definition. In case some exported symbols are +;;; intentionally without definition, they can be excluded via the SKIP +;;; argument. +(defun check-package (package &key skip) + (let ((skip (loop for name in skip collect (intern (string name) package)))) + (do-external-symbols (symbol package) + (unless (member symbol skip) + (unless (symbol-defined-p symbol) + (error "~@" + (package-name package) + (symbol-name symbol)))))) + (pass)) + +(defun symbol-defined-p (symbol) + (or (find-class symbol nil) + (boundp symbol) + (fboundp symbol) + (fboundp `(setf ,symbol)) + (macro-function symbol) + (special-operator-p symbol) + (type-specifier-p symbol))) + +(defun type-specifier-p (object) + (ignore-errors (typep 42 object) t)) + +(defun run-tests (&rest tests) + (with-test-harness (mapc #'funcall (shuffle tests))) + (values)) + +(defun run-test-suite () + (format t "== Testing SB-SIMD ==~%") + (format t "The library exports ~D functions." + (length (all-exported-functions))) + (apply #'run-tests (all-tests))) + +(defun all-instruction-sets () + (remove-duplicates + (loop for iset being the hash-values of sb-simd-internals:*instruction-sets* + collect iset))) + +(defun all-exported-functions () + (remove-duplicates + (loop for iset in (all-instruction-sets) + for package = (instruction-set-package iset) + append + (loop for symbol being the external-symbols of package + when (fboundp symbol) + collect symbol)))) diff --git a/contrib/sb-simd/test-suite/utilities.lisp b/contrib/sb-simd/test-suite/utilities.lisp new file mode 100644 index 0000000000..7e77ef3ea7 --- /dev/null +++ b/contrib/sb-simd/test-suite/utilities.lisp @@ -0,0 +1,174 @@ +(in-package #:sb-simd-test-suite) + +(defun shuffle (list) + (let ((result (copy-seq list))) + (loop for tail on result + for tail-length from (length result) downto 2 + do (rotatef (first tail) + (nth (random tail-length) tail))) + result)) + +(defun simd-info (name) + "Returns, as list: + + 1. The element type of the SIMD pack. + + 2. The number of elements of the SIMD pack. + + 3. The name of the function for creating the SIMD pack from individual + elements. + + 4. The name of the function for returning the elements of the SIMD pack as + multiple values." + (with-accessors ((scalar-record simd-record-scalar-record) + (width value-record-simd-width)) + (find-value-record name) + (list + (value-record-name scalar-record) + width + (or (find-symbol (format nil "MAKE-~A" (symbol-name name)) + (symbol-package name)) + (error "No constructor found for ~S." name)) + (or (find-symbol (format nil "~A-VALUES" (symbol-name name)) + (symbol-package name)) + (error "No unpacker found for ~S." name))))) + +(defun simd= (a b) + (typecase a + (sb-ext:simd-pack + (when (sb-ext:simd-pack-p b) + (multiple-value-bind (a0 a1) (sb-ext:%simd-pack-ub64s a) + (multiple-value-bind (b0 b1) (sb-ext:%simd-pack-ub64s b) + (and (= a0 b0) (= a1 b1)))))) + (sb-ext:simd-pack-256 + (when (sb-ext:simd-pack-256-p b) + (multiple-value-bind (a0 a1 a2 a3) (sb-ext:%simd-pack-256-ub64s a) + (multiple-value-bind (b0 b1 b2 b3) (sb-ext:%simd-pack-256-ub64s b) + (and (= a0 b0) (= a1 b1) (= a2 b2) (= a3 b3)))))) + (otherwise nil))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; +;;; Argument Type Specifications + +(defun parse-argtypes (argtypes) + "Returns, as multiple values: + + 1. The list of mandatory argtypes. + + 2. The list of optional argtypes. + + 3. The argtype of the rest argument, or NIL if there is no &rest argtype." + (labels ((fail () + (error "Malformed argtypes list: ~S" argtypes)) + (process-mandatory (argtypes mandatory) + (if (null argtypes) + (values (reverse mandatory) '() nil) + (case (first argtypes) + ((&optional) + (process-optional (rest argtypes) mandatory '())) + ((&rest) + (process-rest (rest argtypes) mandatory '())) + (#.(set-difference lambda-list-keywords '(&optional &rest)) + (fail)) + (otherwise + (process-mandatory (rest argtypes) (cons (first argtypes) mandatory)))))) + (process-optional (argtypes mandatory optional) + (if (null argtypes) + (values (reverse mandatory) (reverse optional) nil) + (case (first argtypes) + ((&rest) + (process-rest (rest argtypes) mandatory optional)) + (#.(set-difference lambda-list-keywords '(&rest)) + (fail)) + (otherwise + (process-optional (rest argtypes) mandatory (cons (first argtypes) optional)))))) + (process-rest (argtypes mandatory optional) + (if (or (endp argtypes) + (not (endp (rest argtypes)))) + (fail) + (values (reverse mandatory) (reverse optional) (first argtypes))))) + (process-mandatory argtypes '()))) + +(defun argtypes-variants (argtypes) + "Returns a list of lists of type specifiers such that each list of type +specifiers satisfies the argument type specification given by ARGTYPES." + (multiple-value-bind (mandatory optional rest) + (parse-argtypes argtypes) + (let ((result '())) + (loop for n-optional to (length optional) do + (loop for n-rest from 0 to (if (not rest) 0 3) do + (push (append mandatory + (subseq optional 0 n-optional) + (make-list n-rest :initial-element rest)) + result))) + (reverse result)))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; +;;; Generators + +(defun find-generator (type) + (intern (format nil "RANDOM-~A" (symbol-name type)) + #.*package*)) + +(macrolet ((define-generators () + `(progn + ,@(loop for (type name) + in '((sb-simd:f32 random-f32) + (sb-simd:f64 random-f64) + (sb-simd:u8 random-u8) + (sb-simd:u16 random-u16) + (sb-simd:u32 random-u32) + (sb-simd:u64 random-u64) + (sb-simd:s8 random-s8) + (sb-simd:s16 random-s16) + (sb-simd:s32 random-s32) + (sb-simd:s64 random-s64)) + collect + (let ((numbers (numbers-of-type type))) + `(defun ,name () + (aref ,(coerce numbers `(simple-array ,type (*))) + (random ,(length numbers))))))))) + (define-generators)) + +(defun find-valid-simd-call (scalar-function input-generators simd-width + input-constructors output-constructors) + (let ((inputs-list '()) + (outputs-list '())) + (loop repeat simd-width do + (multiple-value-bind (inputs outputs) + (find-valid-scalar-call scalar-function input-generators) + (push inputs inputs-list) + (push outputs outputs-list))) + (values + (apply #'mapcar #'funcall input-constructors inputs-list) + (apply #'mapcar #'funcall output-constructors outputs-list)))) + +(defun find-valid-scalar-call (scalar-function input-generators) + (let ((attempts 0)) + (loop + (let ((inputs (mapcar #'funcall input-generators))) + (handler-case (return (values inputs (multiple-value-list (apply scalar-function inputs)))) + (condition () + (incf attempts) + (when (> attempts 1000) + (error "Failed to find a valid call to ~S." scalar-function)))))))) + +(defun bitwise= (a b) + (etypecase a + (rational + (when (rationalp b) + (= a b))) + (single-float + (when (typep b 'single-float) + (= (sb-kernel:single-float-bits a) + (sb-kernel:single-float-bits b)))) + (double-float + (when (typep b 'double-float) + (= (sb-kernel:double-float-bits a) + (sb-kernel:double-float-bits b)))) + (complex + (when (typep b 'complex) + (bitwise= (realpart a) (realpart b)) + (bitwise= (imagpart a) (imagpart b)))))) diff --git a/contrib/sb-simple-streams/classes.lisp b/contrib/sb-simple-streams/classes.lisp index 2343db32c1..27bc1bf800 100644 --- a/contrib/sb-simple-streams/classes.lisp +++ b/contrib/sb-simple-streams/classes.lisp @@ -118,6 +118,8 @@ (pending :initform nil :type list) (handler :initform nil :type (or null sb-impl::handler)))) +(setq sb-pcl::*simple-stream-root-classoid* (sb-kernel:find-classoid 'simple-stream)) + (def-stream-class single-channel-simple-stream (simple-stream) (;; the "dirty" flag -- if this is > 0, write out buffer contents ;; before changing position; see flush-buffer diff --git a/contrib/sb-simple-streams/impl.lisp b/contrib/sb-simple-streams/impl.lisp index 167ce372e2..e8905c0804 100644 --- a/contrib/sb-simple-streams/impl.lisp +++ b/contrib/sb-simple-streams/impl.lisp @@ -12,6 +12,7 @@ (eval-when (:compile-toplevel) (defun optional+key-style-warning-p (condition) (and (typep condition '(and simple-condition style-warning)) + (stringp (simple-condition-format-control condition)) (search "&OPTIONAL and &KEY found" (simple-condition-format-control condition)))) (proclaim '(sb-ext:muffle-conditions (satisfies optional+key-style-warning-p)))) @@ -56,7 +57,7 @@ (defmethod close ((stream simple-stream) &key abort) (device-close stream abort)) -(defun %file-position (stream position) +(defun sb-impl::s-%file-position (stream position) (declare (type simple-stream stream) (type (or (integer 0 *) (member nil :start :end)) position)) (with-stream-class (simple-stream stream) @@ -107,7 +108,7 @@ nil))) posn)))) -(defun %file-length (stream) +(defun sb-impl::s-%file-length (stream) (declare (type simple-stream stream)) (%check stream :open) (device-file-length stream)) @@ -138,7 +139,7 @@ nil)) -(defun %file-string-length (stream object) +(defun sb-impl::s-%file-string-length (stream object) (declare (type simple-stream stream)) (with-stream-class (simple-stream stream) (%check stream :output) @@ -160,19 +161,18 @@ count))) -(defun %read-line (stream eof-error-p eof-value recursive-p) +(defun sb-impl::s-%read-line (stream eof-error-p eof-value) (declare (optimize (speed 3) (space 1) (safety 0) (debug 0)) - (type simple-stream stream) - (ignore recursive-p)) + (type simple-stream stream)) (with-stream-class (simple-stream stream) (%check stream :input) (when (any-stream-instance-flags stream :eof) - (return-from %read-line + (return-from sb-impl::s-%read-line (sb-impl::eof-or-lose stream eof-error-p eof-value))) ;; for interactive streams, finish output first to force prompt (when (and (any-stream-instance-flags stream :output) (any-stream-instance-flags stream :interactive)) - (%finish-output stream)) + (sb-impl::s-%finish-output stream)) (let* ((encap (sm melded-stream stream)) ; encapsulating stream (cbuf (make-string 80)) ; current buffer (bufs (list cbuf)) ; list of buffers @@ -227,23 +227,22 @@ (setf (cdr tail) (cons cbuf nil)) (setf tail (cdr tail)))))))) -(defun %read-char (stream eof-error-p eof-value recursive-p blocking-p) - (declare (type simple-stream stream) - (ignore recursive-p)) +(defun sb-impl::s-%read-char (stream eof-error-p eof-value blocking-p) + (declare (type simple-stream stream)) (with-stream-class (simple-stream stream) (%check stream :input) (when (any-stream-instance-flags stream :eof) - (return-from %read-char + (return-from sb-impl::s-%read-char (sb-impl::eof-or-lose stream eof-error-p eof-value))) ;; for interactive streams, finish output first to force prompt (when (and (any-stream-instance-flags stream :output) (any-stream-instance-flags stream :interactive)) - (%finish-output stream)) + (sb-impl::s-%finish-output stream)) (funcall-stm-handler j-read-char (sm melded-stream stream) eof-error-p eof-value blocking-p))) -(defun %unread-char (stream character) +(defun sb-impl::s-%unread-char (stream character) (declare (type simple-stream stream) (ignore character)) (with-stream-class (simple-stream stream) (%check stream :input) @@ -255,13 +254,12 @@ (setf (sm last-char-read-size stream) 0))))) -(defun %peek-char (stream peek-type eof-error-p eof-value recursive-p) - (declare (type simple-stream stream) - (ignore recursive-p)) +(defun sb-impl::s-%peek-char (stream peek-type eof-error-p eof-value) + (declare (type simple-stream stream)) (with-stream-class (simple-stream stream) (%check stream :input) (when (any-stream-instance-flags stream :eof) - (return-from %peek-char + (return-from sb-impl::s-%peek-char (sb-impl::eof-or-lose stream eof-error-p eof-value))) (let* ((encap (sm melded-stream stream)) (char (funcall-stm-handler j-read-char encap @@ -319,7 +317,7 @@ (device-clear-input stream buffer-only)) -(defun %read-byte (stream eof-error-p eof-value) +(defun sb-impl::s-%read-byte (stream eof-error-p eof-value) (declare (type simple-stream stream)) (with-stream-class (simple-stream stream) (%check stream :input) @@ -345,14 +343,14 @@ (sm encapsulated-char-read-size stream) 0))))))))) -(defun %write-char (stream character) +(defun sb-impl::s-%write-char (stream character) (declare (type simple-stream stream)) (with-stream-class (simple-stream stream) (%check stream :output) (funcall-stm-handler-2 j-write-char character (sm melded-stream stream)))) -(defun %fresh-line (stream) +(defun sb-impl::s-%fresh-line (stream) (declare (type simple-stream stream)) (with-stream-class (simple-stream stream) (%check stream :output) @@ -361,7 +359,7 @@ t))) -(defun %write-string (stream string start end) +(defun sb-impl::s-%write-string (stream string start end) (declare (type simple-stream stream)) (with-stream-class (simple-stream stream) (%check stream :output) @@ -369,14 +367,14 @@ start end))) -(defun %line-length (stream) +(defun sb-impl::s-%line-length (stream) (declare (type simple-stream stream)) (%check stream :output) ;; implement me nil) -(defun %finish-output (stream) +(defun sb-impl::s-%finish-output (stream) (declare (type simple-stream stream)) (with-stream-class (simple-stream stream) (%check stream :output) @@ -401,7 +399,7 @@ nil) -(defun %force-output (stream) +(defun sb-impl::s-%force-output (stream) (declare (type simple-stream stream)) (with-stream-class (simple-stream stream) (%check stream :output) @@ -422,7 +420,7 @@ nil) -(defun %clear-output (stream) +(defun sb-impl::%clear-output (stream) (declare (type simple-stream stream)) (with-stream-class (simple-stream stream) (%check stream :output) @@ -443,7 +441,7 @@ (device-clear-output stream))) -(defun %write-byte (stream integer) +(defun sb-impl::s-%write-byte (stream integer) (declare (type simple-stream stream)) (with-stream-class (simple-stream stream) (%check stream :output) @@ -510,7 +508,7 @@ ;; extend to work on other sequences: repeated read-byte ))) -(defun %write-sequence (stream seq start end) +(defun sb-impl::s-%write-sequence (stream seq start end) (declare (type simple-stream stream) (type sequence seq) (type sb-int:index start end)) @@ -528,32 +526,36 @@ (single-channel-simple-stream (with-stream-class (single-channel-simple-stream stream) (loop with max-ptr fixnum = (sm buf-len stream) - for src-pos fixnum = start then (+ src-pos count) + with src-pos fixnum = start for src-rest fixnum = (- end src-pos) - while (> src-rest 0) ; FIXME: this is non-ANSI - for ptr fixnum = (let ((ptr (sm buffpos stream))) - (if (>= ptr max-ptr) - (flush-buffer stream t) - ptr)) - for buf-rest fixnum = (- max-ptr ptr) - for count fixnum = (min buf-rest src-rest) - do (progn (setf (sm mode stream) 1) - (setf (sm buffpos stream) (+ ptr count)) - (buffer-copy seq src-pos (sm buffer stream) ptr count))))) + while (> src-rest 0) + do (let* ((ptr (let ((ptr (sm buffpos stream))) + (if (>= ptr max-ptr) + (flush-buffer stream t) + ptr))) + (buf-rest (- max-ptr ptr)) + (count (min buf-rest src-rest))) + (declare (type fixnum ptr buf-rest count)) + (setf (sm mode stream) 1) + (setf (sm buffpos stream) (+ ptr count)) + (buffer-copy seq src-pos (sm buffer stream) ptr count) + (incf src-pos count))))) (dual-channel-simple-stream (with-stream-class (dual-channel-simple-stream stream) (loop with max-ptr fixnum = (sm max-out-pos stream) - for src-pos fixnum = start then (+ src-pos count) + with src-pos fixnum = start for src-rest fixnum = (- end src-pos) - while (> src-rest 0) ; FIXME: this is non-ANSI - for ptr fixnum = (let ((ptr (sm outpos stream))) - (if (>= ptr max-ptr) - (flush-out-buffer stream t) - ptr)) - for buf-rest fixnum = (- max-ptr ptr) - for count fixnum = (min buf-rest src-rest) - do (progn (setf (sm outpos stream) (+ ptr count)) - (buffer-copy seq src-pos (sm out-buffer stream) ptr count))))) + while (> src-rest 0) + do (let* ((ptr (let ((ptr (sm outpos stream))) + (if (>= ptr max-ptr) + (flush-out-buffer stream t) + ptr))) + (buf-rest (- max-ptr ptr)) + (count (min buf-rest src-rest))) + (declare (type fixnum ptr buf-rest count)) + (setf (sm outpos stream) (+ ptr count)) + (buffer-copy seq src-pos (sm out-buffer stream) ptr count) + (incf src-pos count))))) (string-simple-stream (error 'simple-type-error :datum stream @@ -565,46 +567,6 @@ )) seq) - -(defun read-vector (vector stream &key (start 0) end (endian-swap :byte-8)) - (declare (type (sb-kernel:simple-unboxed-array (*)) vector) - (type stream stream)) - ;; START and END are octet offsets, not vector indices! [Except for strings] - ;; Return value is index of next octet to be read into (i.e., start+count) - (etypecase stream - (simple-stream - (with-stream-class (simple-stream stream) - (cond ((stringp vector) - (let* ((start (or start 0)) - (end (or end (length vector))) - (encap (sm melded-stream stream)) - (char (funcall-stm-handler j-read-char encap nil nil t))) - (when char - (setf (schar vector start) char) - (incf start) - (+ start (funcall-stm-handler j-read-chars encap vector nil - start end nil))))) - ((any-stream-instance-flags stream :string) - (error "Can't READ-BYTE on string streams.")) - (t - (do* ((encap (sm melded-stream stream)) - (index (or start 0) (1+ index)) - (end (or end (* (length vector) (vector-elt-width vector)))) - (endian-swap (endian-swap-value vector endian-swap)) - (flag t nil)) - ((>= index end) index) - (let ((byte (read-byte-internal encap nil nil flag))) - (unless byte - (return index)) - (setf (bref vector (logxor index endian-swap)) byte))))))) - ((or ansi-stream fundamental-stream) - (unless (typep vector '(or string - (simple-array (signed-byte 8) (*)) - (simple-array (unsigned-byte 8) (*)))) - (error "Wrong vector type for read-vector on stream not of type simple-stream.")) - (read-sequence vector stream :start (or start 0) :end end)))) - - ;;; ;;; USER-LEVEL FUNCTIONS ;;; @@ -621,54 +583,20 @@ (defmethod stream-element-type ((stream simple-stream)) '(unsigned-byte 8)) -(defun interactive-stream-p (stream) - "Return true if Stream does I/O on a terminal or other interactive device." - (etypecase stream - (simple-stream +(defmethod interactive-stream-p ((stream simple-stream)) (%check stream :open) (any-stream-instance-flags stream :interactive)) - (ansi-stream - (funcall (sb-kernel:ansi-stream-misc stream) stream :interactive-p)) - (fundamental-stream - nil))) -(defun (setf interactive-stream-p) (flag stream) - (typecase stream - (simple-stream +(defmethod (setf interactive-stream-p) (flag (stream simple-stream)) (%check stream :open) (if flag (add-stream-instance-flags stream :interactive) (remove-stream-instance-flags stream :interactive))) - (t - (error 'simple-type-error - :datum stream - :expected-type 'simple-stream - :format-control "Can't set interactive flag on ~S." - :format-arguments (list stream))))) - -(defun file-string-length (stream object) - (declare (type (or string character) object) (type stream stream)) - "Return the delta in STREAM's FILE-POSITION that would be caused by writing - OBJECT to STREAM. Non-trivial only in implementations that support - international character sets." - (typecase stream - (simple-stream (%file-string-length stream object)) - (t - (etypecase object - (character 1) - (string (length object)))))) - -(defun stream-external-format (stream) - "Returns Stream's external-format." - (etypecase stream - (simple-stream + +(defun sb-impl::s-%stream-external-format (stream) (with-stream-class (simple-stream) (%check stream :open) (sm external-format stream))) - (ansi-stream - :default) - (fundamental-stream - :default))) (defun open (filename &rest options &key (direction :input) @@ -725,58 +653,7 @@ (symbol (find-class class t)) (class class))))))) - -;; These are not normally inlined. -;; READ-CHAR is 1K of code, etc. This was probably either a brute-force -;; way to optimize IN-SYNONYM-OF and/or optimize for known sub-hierarchy -;; at compile-time, but how likely is that to help? -(declaim (inline read-byte read-char read-char-no-hang unread-char)) - -(defun read-byte (stream &optional (eof-error-p t) eof-value) - "Returns the next byte of the Stream." - (declare (sb-int:explicit-check)) - (let ((stream (in-stream-from-designator stream))) - (etypecase stream - (simple-stream - (let ((byte (%read-byte stream eof-error-p eof-value))) - (if (eq byte eof-value) - byte - (the integer byte)))) - (ansi-stream - (sb-impl::ansi-stream-read-byte stream eof-error-p eof-value nil)) - (fundamental-stream - (let ((byte (sb-gray:stream-read-byte stream))) - (if (eq byte :eof) - (sb-impl::eof-or-lose stream eof-error-p eof-value) - (the integer byte))))))) - -(defun read-char (&optional (stream *standard-input*) (eof-error-p t) - eof-value recursive-p) - "Inputs a character from Stream and returns it." - (declare (sb-int:explicit-check)) - (let ((stream (in-stream-from-designator stream))) - (etypecase stream - (simple-stream - (let ((char (%read-char stream eof-error-p eof-value recursive-p t))) - (if (eq char eof-value) - char - (the character char)))) - (ansi-stream - (sb-impl::ansi-stream-read-char stream eof-error-p eof-value - recursive-p)) - (fundamental-stream - (let ((char (sb-gray:stream-read-char stream))) - (if (eq char :eof) - (sb-impl::eof-or-lose stream eof-error-p eof-value) - (the character char))))))) - -(defun read-char-no-hang (&optional (stream *standard-input*) (eof-error-p t) - eof-value recursive-p) - "Returns the next character from the Stream if one is availible, or nil." - (declare (sb-int:explicit-check)) - (let ((stream (in-stream-from-designator stream))) - (etypecase stream - (simple-stream +(defun sb-impl::s-%read-char-no-hang (stream eof-error-p eof-value) (%check stream :input) (let ((char (with-stream-class (simple-stream) @@ -784,72 +661,6 @@ (if (or (eq char eof-value) (not char)) char (the character char)))) - (ansi-stream - (sb-impl::ansi-stream-read-char-no-hang stream eof-error-p eof-value - recursive-p)) - (fundamental-stream - (let ((char (sb-gray:stream-read-char-no-hang stream))) - (if (eq char :eof) - (sb-impl::eof-or-lose stream eof-error-p eof-value) - (the (or character null) char))))))) - -(defun unread-char (character &optional (stream *standard-input*)) - "Puts the Character back on the front of the input Stream." - (declare (sb-int:explicit-check)) - (let ((stream (in-stream-from-designator stream))) - (etypecase stream - (simple-stream - (%unread-char stream character)) - (ansi-stream - (sb-impl::ansi-stream-unread-char character stream)) - (fundamental-stream - (sb-gray:stream-unread-char stream character)))) - nil) - -(declaim (notinline read-byte read-char read-char-no-hang unread-char)) - -(defun peek-char (&optional (peek-type nil) (stream *standard-input*) - (eof-error-p t) eof-value recursive-p) - "Peeks at the next character in the input Stream. See manual for details." - (declare (sb-int:explicit-check)) - (let ((stream (in-stream-from-designator stream))) - (etypecase stream - (simple-stream - (let ((char - (%peek-char stream peek-type eof-error-p eof-value recursive-p))) - (if (eq char eof-value) - char - (the character char)))) - ;; FIXME: Broken on ECHO-STREAM (cf internal implementation?) -- - ;; CSR, 2004-01-19 - (ansi-stream - (sb-impl::ansi-stream-peek-char peek-type stream eof-error-p eof-value - recursive-p)) - (fundamental-stream - ;; This seems to duplicate all the code of GENERALIZED-PEEKING-MECHANISM - (cond ((characterp peek-type) - (do ((char (sb-gray:stream-read-char stream) - (sb-gray:stream-read-char stream))) - ((or (eq char :eof) (char= char peek-type)) - (cond ((eq char :eof) - (sb-impl::eof-or-lose stream eof-error-p eof-value)) - (t - (sb-gray:stream-unread-char stream char) - char))))) - ((eq peek-type t) - (do ((char (sb-gray:stream-read-char stream) - (sb-gray:stream-read-char stream))) - ((or (eq char :eof) (not (sb-impl::whitespace[2]p char))) - (cond ((eq char :eof) - (sb-impl::eof-or-lose stream eof-error-p eof-value)) - (t - (sb-gray:stream-unread-char stream char) - char))))) - (t - (let ((char (sb-gray:stream-peek-char stream))) - (if (eq char :eof) - (sb-impl::eof-or-lose stream eof-error-p eof-value) - (the character char))))))))) (defun listen (&optional (stream *standard-input*) (width 1)) "Returns T if WIDTH octets are available on STREAM. If WIDTH is @@ -867,25 +678,6 @@ is supported only on simple-streams." (fundamental-stream (sb-gray:stream-listen stream))))) - -(defun read-line (&optional (stream *standard-input*) (eof-error-p t) - eof-value recursive-p) - "Returns a line of text read from the Stream as a string, discarding the - newline character." - (declare (sb-int:explicit-check)) - (let ((stream (in-stream-from-designator stream))) - (etypecase stream - (simple-stream - (%read-line stream eof-error-p eof-value recursive-p)) - (ansi-stream - (sb-impl::ansi-stream-read-line stream eof-error-p eof-value - recursive-p)) - (fundamental-stream - (multiple-value-bind (string eof) (sb-gray:stream-read-line stream) - (if (and eof (zerop (length string))) - (values (sb-impl::eof-or-lose stream eof-error-p eof-value) t) - (values string eof))))))) - (defun read-sequence (seq stream &key (start 0) (end nil) partial-fill) "Destructively modify SEQ by reading elements from STREAM. SEQ is bounded by START and END. SEQ is destructively modified by @@ -917,198 +709,22 @@ is supported only on simple-streams." (sb-gray:stream-clear-input stream)))) nil) -(defun write-byte (integer stream) - "Outputs an octet to the Stream." - (declare (sb-int:explicit-check)) - (let ((stream (out-stream-from-designator stream))) - (etypecase stream - (simple-stream - (%write-byte stream integer)) - (ansi-stream - (funcall (sb-kernel:ansi-stream-bout stream) stream integer)) - (fundamental-stream - (sb-gray:stream-write-byte stream integer)))) - integer) - -(defun write-char (character &optional (stream *standard-output*)) - "Outputs the Character to the Stream." - (declare (sb-int:explicit-check)) - (let ((stream (out-stream-from-designator stream))) - (etypecase stream - (simple-stream - (%write-char stream character)) - (ansi-stream - (funcall (sb-kernel:ansi-stream-out stream) stream character)) - (fundamental-stream - (sb-gray:stream-write-char stream character)))) - character) - -(defun write-string (string &optional (stream *standard-output*) - &key (start 0) (end nil)) - "Outputs the String to the given Stream." - (declare (sb-int:explicit-check)) - (let ((stream (out-stream-from-designator stream)) - (end (sb-impl::%check-vector-sequence-bounds string start end))) - (etypecase stream - (simple-stream - (%write-string stream string start end) - string) - (ansi-stream - (sb-impl::ansi-stream-write-string string stream start end)) - (fundamental-stream - (sb-gray:stream-write-string stream string start end))))) - -(defun write-line (string &optional (stream *standard-output*) - &key (start 0) end) - (declare (type string string)) - (declare (sb-int:explicit-check)) - (let ((stream (out-stream-from-designator stream)) - (end (sb-impl::%check-vector-sequence-bounds string start end))) - (etypecase stream - (simple-stream +(defun sb-impl::s-%write-line (stream string start end) + (declare (type simple-stream stream)) (%check stream :output) (with-stream-class (simple-stream stream) (funcall-stm-handler-2 j-write-chars string stream start end) (funcall-stm-handler-2 j-write-char #\Newline stream))) - (ansi-stream - (sb-impl::ansi-stream-write-string string stream start end) - (funcall (sb-kernel:ansi-stream-out stream) stream #\Newline)) - (fundamental-stream - (sb-gray:stream-write-string stream string start end) - (sb-gray:stream-terpri stream)))) - string) -(defun write-sequence (seq stream &key (start 0) (end nil)) - "Write the elements of SEQ bounded by START and END to STREAM." - (let ((stream (out-stream-from-designator stream)) - (end (or end (length seq)))) - (etypecase stream - (simple-stream - (%write-sequence stream seq start end)) - (ansi-stream - (sb-impl::ansi-stream-write-sequence seq stream start end)) - (fundamental-stream - (sb-gray:stream-write-sequence stream seq start end))))) - -(defun terpri (&optional (stream *standard-output*)) - "Outputs a new line to the Stream." - (declare (sb-int:explicit-check)) - (let ((stream (out-stream-from-designator stream))) - (etypecase stream - (simple-stream +(defun sb-impl::s-%terpri (stream) (%check stream :output) (with-stream-class (simple-stream stream) (funcall-stm-handler-2 j-write-char #\Newline stream))) - (ansi-stream - (funcall (sb-kernel:ansi-stream-out stream) stream #\Newline)) - (fundamental-stream - (sb-gray:stream-terpri stream)))) - nil) - -(defun fresh-line (&optional (stream *standard-output*)) - "Outputs a new line to the Stream if it is not positioned at the beginning of - a line. Returns T if it output a new line, nil otherwise." - (declare (sb-int:explicit-check)) - (let ((stream (out-stream-from-designator stream))) - (etypecase stream - (simple-stream - (%fresh-line stream)) - (ansi-stream - (sb-impl::ansi-stream-fresh-line stream)) - (fundamental-stream - (sb-gray:stream-fresh-line stream))))) -(defun finish-output (&optional (stream *standard-output*)) - "Attempts to ensure that all output sent to the Stream has reached its - destination, and only then returns." - (declare (sb-int:explicit-check)) - (let ((stream (out-stream-from-designator stream))) - (etypecase stream - (simple-stream - (%finish-output stream)) - (ansi-stream - (funcall (sb-kernel:ansi-stream-misc stream) stream :finish-output)) - (fundamental-stream - (sb-gray:stream-finish-output stream)))) - nil) - -(defun force-output (&optional (stream *standard-output*)) - "Attempts to force any buffered output to be sent." - (declare (sb-int:explicit-check)) - (let ((stream (out-stream-from-designator stream))) - (etypecase stream - (simple-stream - (%force-output stream)) - (ansi-stream - (funcall (sb-kernel:ansi-stream-misc stream) stream :force-output)) - (fundamental-stream - (sb-gray:stream-force-output stream)))) - nil) - -(defun clear-output (&optional (stream *standard-output*)) - "Clears the given output Stream." - (declare (sb-int:explicit-check)) - (let ((stream (out-stream-from-designator stream))) - (etypecase stream - (simple-stream - (%clear-output stream)) - (ansi-stream - (funcall (sb-kernel:ansi-stream-misc stream) stream :clear-output)) - (fundamental-stream - (sb-gray:stream-clear-output stream)))) - nil) - - -(defun file-position (stream &optional position) - "With one argument returns the current position within the file - File-Stream is open to. If the second argument is supplied, then - this becomes the new file position. The second argument may also - be :start or :end for the start and end of the file, respectively." - (declare (type (or sb-int:index (member nil :start :end)) position)) - (etypecase stream - (simple-stream - (%file-position stream position)) - (ansi-stream - (sb-kernel:ansi-stream-file-position stream position)))) - -(defun file-length (stream) - "This function returns the length of the file that File-Stream is open to." - (etypecase stream - (simple-stream - (%file-length stream)) - (ansi-stream - (sb-impl::stream-file-stream-or-lose stream) - (funcall (sb-kernel:ansi-stream-misc stream) stream :file-length)))) - -(defun charpos (&optional (stream *standard-output*)) - "Returns the number of characters on the current line of output of the given - Stream, or Nil if that information is not availible." - (let ((stream (out-stream-from-designator stream))) - (etypecase stream - (simple-stream +(defun sb-impl::s-%charpos (stream) (with-stream-class (simple-stream stream) (%check stream :open) (sm charpos stream))) - (ansi-stream - (funcall (sb-kernel:ansi-stream-misc stream) stream :charpos)) - (fundamental-stream - (sb-gray:stream-line-column stream))))) - -(defun line-length (&optional (stream *standard-output*)) - "Returns the number of characters in a line of output of the given - Stream, or Nil if that information is not availible." - (let ((stream (out-stream-from-designator stream))) - (etypecase stream - (simple-stream - (%check stream :output) - ;; TODO (sat 2003-04-02): a way to specify a line length would - ;; be good, I suppose. Returning nil here means - ;; sb-pretty::default-line-length is used. - nil) - (ansi-stream - (funcall (sb-kernel:ansi-stream-misc stream) stream :line-length)) - (fundamental-stream - (sb-gray:stream-line-length stream))))) (defun wait-for-input-available (stream &optional timeout) "Waits for input to become available on the Stream and returns T. If @@ -1133,19 +749,9 @@ is supported only on simple-streams." (wait-for-input-available (sb-sys:fd-stream-fd stream) timeout)))))) ;; Make PATHNAME and NAMESTRING work -(defun sb-int:file-name (stream &optional new-name) - (typecase stream - (file-simple-stream +(defun sb-impl::s-%file-name (stream new-name) (with-stream-class (file-simple-stream stream) (cond (new-name (%file-rename stream new-name)) (t (%file-name stream))))) - (sb-sys:fd-stream - (cond (new-name - (setf (sb-impl::fd-stream-pathname stream) new-name) - (setf (sb-impl::fd-stream-file stream) - (%file-namestring new-name)) - t) - (t - (sb-impl::fd-stream-pathname stream)))))) diff --git a/contrib/sb-simple-streams/internal.lisp b/contrib/sb-simple-streams/internal.lisp index 13d4639484..15dcf37bad 100644 --- a/contrib/sb-simple-streams/internal.lisp +++ b/contrib/sb-simple-streams/internal.lisp @@ -249,6 +249,7 @@ (pos -1) (count 0) (state nil)) + (declare (ignorable count)) (flet ((input () (aref octets (incf ptr))) (unput (n) diff --git a/contrib/sb-simple-streams/package.lisp b/contrib/sb-simple-streams/package.lisp index c15c1c2463..c9c38bca3d 100644 --- a/contrib/sb-simple-streams/package.lisp +++ b/contrib/sb-simple-streams/package.lisp @@ -14,7 +14,7 @@ (:import-from #:sb-impl #:in-stream-from-designator #:out-stream-from-designator) ;; FIXME: Using deffoo! or equivalent might be nicer. - (:implement #:common-lisp #:sb-kernel #:sb-int) + (:implement #:common-lisp #:sb-impl) (:export ;; Stream classes #:STREAM #:SIMPLE-STREAM diff --git a/contrib/sb-simple-streams/sb-simple-streams.asd b/contrib/sb-simple-streams/sb-simple-streams.asd index 4854978d4f..9dbbf5fad6 100644 --- a/contrib/sb-simple-streams/sb-simple-streams.asd +++ b/contrib/sb-simple-streams/sb-simple-streams.asd @@ -14,21 +14,14 @@ ;;(:file "ext-format" :depends-on ("package")) (:file "classes" :depends-on ("iodefs")) (:file "internal" :depends-on ("classes")) - (:file "strategy" :depends-on ("internal")) + (:file "strategy" :depends-on ("string")) (:file "impl" :depends-on ("internal" "fndb" "file" "string")) (:file "file" :depends-on ("strategy")) (:file "direct" :depends-on ("strategy")) (:file "null" :depends-on ("strategy")) (:file "socket" :depends-on ("strategy")) - (:file "string" :depends-on ("strategy")) + (:file "string" :depends-on ("internal")) (:file "terminal" :depends-on ("strategy")) ;;(:file "gray-compat" :depends-on ("package")) ) - :perform (load-op :after (o c) (provide 'sb-simple-streams)) - :in-order-to ((test-op (test-op "sb-simple-streams/tests")))) - -(defsystem "sb-simple-streams/tests" - :depends-on ("sb-rt" "sb-simple-streams") - #+sb-building-contrib :pathname - #+sb-building-contrib #p"SYS:CONTRIB;SB-SIMPLE-STREAMS;" - :components ((:file "simple-stream-tests"))) + :perform (load-op :after (o c) (provide 'sb-simple-streams))) diff --git a/contrib/sb-simple-streams/simple-stream-tests.lisp b/contrib/sb-simple-streams/simple-stream-tests.lisp index 20c5a8efc9..2fb5100439 100644 --- a/contrib/sb-simple-streams/simple-stream-tests.lisp +++ b/contrib/sb-simple-streams/simple-stream-tests.lisp @@ -1,7 +1,8 @@ ;;;; -*- lisp -*- (defpackage sb-simple-streams-test - (:use #:common-lisp #:sb-simple-streams #:sb-rt)) + (:import-from #:test-util #:deftest) + (:use #:common-lisp #:sb-simple-streams)) (in-package #:sb-simple-streams-test) @@ -60,6 +61,7 @@ (progn ,@body)) ,(when delete-afterwards `(ignore-errors (delete-file ,file)))))) +#+nil ; fails (deftest non-existent-class (handler-case (with-test-file (s *test-file* :class 'non-existent-stream) @@ -84,6 +86,7 @@ :direction :output :if-exists :overwrite :if-does-not-exist :create)) + (fresh-line s) (string= (write-string *dumb-string* s) *dumb-string*)) (delete-file *test-file*)) t) @@ -501,6 +504,7 @@ Nothing to see here, move along.") (read-char s))) #\A) +#+nil ; fails (deftest synonym-stream-6 ;; WRITE-STRING (with-sc-test-stream (*synonym*) @@ -542,8 +546,8 @@ Nothing to see here, move along.") (deftest synonym-stream-11 ;; STREAM-ELEMENT-TYPE (via STREAM-MISC-DISPATCH) (with-sc-test-stream (*synonym*) - (eql (stream-element-type (make-synonym-stream '*synonym*)) - (stream-element-type *synonym*))) + (equal (stream-element-type (make-synonym-stream '*synonym*)) + (stream-element-type *synonym*))) T) (deftest synonym-stream-12 @@ -603,6 +607,7 @@ Nothing to see here, move along.") (read-char synonym)) #\A) +#+nil ; fails (deftest broadcast-stream-6 ;; WRITE-STRING (with-sc-test-stream (synonym) @@ -705,6 +710,7 @@ Nothing to see here, move along.") (read-char synonym)) #\A) +#+nil ; fails (deftest two-way-stream-6 ;; WRITE-STRING (with-sc-test-stream (synonym) @@ -889,8 +895,8 @@ Nothing to see here, move along.") (deftest concatenated-stream-11 ;; STREAM-ELEMENT-TYPE (via STREAM-MISC-DISPATCH) (with-sc-test-stream (*synonym*) - (eql (stream-element-type (make-concatenated-stream *synonym*)) - (stream-element-type *synonym*))) + (equal (stream-element-type (make-concatenated-stream *synonym*)) + (stream-element-type *synonym*))) T) (deftest concatenated-stream-12 @@ -949,6 +955,7 @@ Nothing to see here, move along.") ;; launchpad bug #491087 +#+nil ; fails (deftest lp491087 (labels ((read-big-int (stream) (let ((b (make-array 1 :element-type '(signed-byte 32) diff --git a/contrib/sb-simple-streams/strategy.lisp b/contrib/sb-simple-streams/strategy.lisp index 628b80ba66..9e890683ca 100644 --- a/contrib/sb-simple-streams/strategy.lisp +++ b/contrib/sb-simple-streams/strategy.lisp @@ -109,6 +109,7 @@ (buffpos (sm buffpos stream)) (cnt 0) (char nil)) + (declare (ignorable cnt)) (unwind-protect (flet ((input () (when (>= buffpos (sm buffer-ptr stream)) diff --git a/contrib/sb-sprof/design-notes.txt b/contrib/sb-sprof/design-notes.txt new file mode 100644 index 0000000000..967de1d501 --- /dev/null +++ b/contrib/sb-sprof/design-notes.txt @@ -0,0 +1,50 @@ +New data recorder: + +* Each thread gets its own trace buffer. + +* There are almost no mutexes involved nor any WITHOUT-GCING + nor synchronized hash-table. + +* Trace buffers store the program counter locations as code serial# + and displacement so that they are stable across GC. + +* For gencgc only, code on a pseudo-static page will store absolute PCs + which avoids looking for the object base address while sampling. + Therefore profiling a saved core is far more efficient. + +* Traces are hashed so that multiple hits at the same call stack + will entail only an increment of a counter for that trace. + This optimization makes :ALLOC mode collect far fewer traces + since many allocations have the same call stack. + +Known limitations: + +* A code object that gets GC'd after it has been recorded as serial# + displacement + may show up as an unknown function in the report. We could be slightly better + here by marking code objects as ineligible for GC if they appear in a profile buffer, + or we could have GC scan the profile buffers (which would defeat + the point of the stable representation), or we could just make all code ineligible + for GC if any profile buffers exist. + +* The code serial# field wraps around at 32 bits for 64-bit machines + (and 18 bits for 32-bit machines), which is a theoretical problem, but unlikely + to be a problem in practice. We could create a recycle list for serial# + assignment if it were ever a problem in practice. + The be on the safe side, the logic which assigs the number should refuse to + allocate new numbers after it hits the limit. Subsequently allocated code objects + would all get the number 0. + +* Non-x86 can still not walk more than one stack frame back. + This seems to have to do with the fact that it is unreliable (i.e. crash-prone) + to try to walk the stack when interrupted at an arbitrary instruction, because + our frame establishing instructions are not atomic. + This is contrary to most machine-native ABIs where the specification + is that frame creation be be atomic. e.g. on ppc it's a store-with-update. + +* The "missing frames" marker probably probably needs better treatment + if it occurs in a graph-based report so that the generator does not think + than all "missing frames" pseudo-functions are the same function. + +* The graphing routine does not currently take advantage of the compressed + representation of traces with multiple hits, so it takes more time than + should be required to preprocess the graph. diff --git a/contrib/sb-sprof/disassemble.lisp b/contrib/sb-sprof/disassemble.lisp index da5df6121f..4802428096 100644 --- a/contrib/sb-sprof/disassemble.lisp +++ b/contrib/sb-sprof/disassemble.lisp @@ -8,7 +8,7 @@ (defun sample-counts-by-pc (samples) (let* ((unique-pc-count-guess (isqrt (truncate (samples-index samples) 2))) (sample-counts-by-pc (make-hash-table :size unique-pc-count-guess))) - (map-all-samples (lambda (info pc-or-offset) + (map-all-pc-locs (lambda (info pc-or-offset) (let ((pc (sample-pc info pc-or-offset))) (incf (gethash pc sample-counts-by-pc 0)))) samples) @@ -46,16 +46,15 @@ (defun add-disassembly-profile-note (chunk stream dstate) (declare (ignore chunk stream)) - (when *samples* - (let* ((samples *samples*) - (counts (ensure-sample-counts samples)) - (location (sb-disassem:dstate-cur-addr dstate)) - (count (pc-sample-count location counts))) + (binding* ((samples *samples* :exit-if-null) + (counts (ensure-sample-counts samples)) + (location (sb-disassem:dstate-cur-addr dstate)) + (count (pc-sample-count location counts))) (unless (zerop count) (let* ((total-count (samples-trace-count samples)) (width (length (write-to-string total-count :base 10)))) (sb-disassem::note (format nil "~VD/~VD samples" width count width total-count) - dstate)))))) + dstate))))) (pushnew 'add-disassembly-profile-note sb-disassem::*default-dstate-hooks*) diff --git a/contrib/sb-sprof/graph.lisp b/contrib/sb-sprof/graph.lisp index 680eff90d1..db8f4afa55 100644 --- a/contrib/sb-sprof/graph.lisp +++ b/contrib/sb-sprof/graph.lisp @@ -14,10 +14,10 @@ (root nil :type (or null vertex)) (dfn 0 :type fixnum) (edges () :type list) - (scc-vertices () :type list)) + (scc-vertices () :type list :read-only t)) (defstruct edge - (vertex (sb-impl::missing-arg) :type vertex)) + (vertex (sb-int:missing-arg) :type vertex)) (defstruct graph (vertices () :type list)) @@ -86,13 +86,14 @@ (unless (in-component w) (setf (vertex-root v) (min-root v w)))) (if (eq v (vertex-root v)) - (loop while (and stack (vertex-> (car stack) v)) - as w = (pop stack) - collect w into this-component - do (setf (in-component w) t) - finally - (setf (in-component v) t) - (push (cons v this-component) components)) + (loop for w = (car stack) + while (and stack (vertex-> (car stack) v)) + do (pop stack) + collect w into this-component + do (setf (in-component w) t) + finally + (setf (in-component v) t) + (push (cons v this-component) components)) (push v stack)))) (map-vertices #'visit vertices) components))) @@ -147,15 +148,16 @@ (:constructor %make-call-graph)) ;; the value of *SAMPLE-INTERVAL* or *ALLOC-INTERVAL* at the time ;; the graph was created (depending on the current allocation mode) - (sample-interval (sb-impl::missing-arg) :type (real (0))) + (sample-interval (sb-int:missing-arg) :type (real (0)) :read-only t) ;; the sampling-mode that was used for the profiling run - (sampling-mode (sb-impl::missing-arg) :type sampling-mode) + (sampling-mode (sb-int:missing-arg) :type sampling-mode :read-only t) ;; number of samples taken - (nsamples (sb-impl::missing-arg) :type sb-int:index) + (nsamples (sb-int:missing-arg) :type sb-int:index :read-only t) + (unique-trace-count (sb-int:missing-arg) :type sb-int:index :read-only t) ;; threads that have been sampled - (sampled-threads '() :type list) + (sampled-threads '() :type list :read-only t) ;; sample count for samples not in any function - (elsewhere-count (sb-impl::missing-arg) :type sb-int:index)) + (elsewhere-count (sb-int:missing-arg) :type sb-int:index :read-only t)) (defmethod print-object ((call-graph call-graph) stream) (print-unreadable-object (call-graph stream :type t :identity t) @@ -181,13 +183,13 @@ (start-pc-or-offset 0 :type address) (end-pc-or-offset 0 :type address) ;; the name of the function - (name nil :type t) + (name nil :type t :read-only t) ;; sample count for this function (count 0 :type fixnum) ;; count including time spent in functions called from this one (accrued-count 0 :type fixnum) ;; the debug-info that this node was created from - (debug-info nil :type t) + (debug-info nil :type t :read-only t) ;; list of NODEs for functions calling this one (callers () :type list) ;; the call count for the function that corresponds to this node (or NIL @@ -253,7 +255,11 @@ ;;; Make a NODE for debug-info INFO. (defun make-node (info) - (flet ((clean-name (name) + (flet ((code-bounds (code) + (let* ((start (sb-kernel:code-instructions code)) + (end (sap+ start (sb-kernel:%code-text-size code)))) + (values (sap-int start) (sap-int end)))) + (clean-name (name) (if (and (consp name) (member (first name) '(sb-c::xep sb-c::tl-xep sb-c::&more-processor @@ -262,12 +268,11 @@ (second name) name))) (typecase info - (sb-kernel::code-component + (sb-kernel:code-component (multiple-value-bind (start end) (code-bounds info) (values - (%make-node :name (or (sb-disassem::find-assembler-routine start) - (format nil "~a" info)) + (%make-node :name (format nil "~a" info) :debug-info info :start-pc-or-offset start :end-pc-or-offset end) @@ -277,12 +282,11 @@ (cdf (sb-di::compiled-debug-fun-compiler-debug-fun info)) (start-offset (sb-c::compiled-debug-fun-start-pc cdf)) (end-offset (sb-c::compiled-debug-fun-elsewhere-pc cdf)) - (component (sb-di::compiled-debug-fun-component info)) - (start-pc (code-start component))) + (component (sb-di::compiled-debug-fun-component info))) ;; Call graphs are mostly useless unless we somehow ;; distinguish a gazillion different (LAMBDA ())'s. (when (equal name '(lambda ())) - (setf name (format nil "Unknown component: #x~x" start-pc))) + (setf name (format nil "~a in ~a" name component))) (values (%make-node :name (clean-name name) :debug-info info :start-pc-or-offset start-offset @@ -291,6 +295,9 @@ (sb-di::debug-fun (%make-node :name (clean-name (sb-di::debug-fun-name info)) :debug-info info)) + (symbol + (%make-node :name (string info) + :debug-info sb-fasl:*assembler-routines*)) (t (%make-node :name (coerce info 'string) :debug-info info))))) @@ -334,17 +341,17 @@ collect node)) ;;; Value is a CALL-GRAPH for the current contents of *SAMPLES*. -(defun make-call-graph-1 (max-depth) +(defun make-call-graph-1 (samples max-depth) (let ((elsewhere-count 0)) (with-lookup-tables () (map-traces - (lambda (thread time trace) - (declare (ignore thread time)) + (lambda (thread trace) + (declare (ignore thread)) (let ((visited-nodes '()) (depth 0) (caller nil)) (block calls - (map-trace-samples + (map-trace-pc-locs (lambda (debug-info pc-offset) (declare (ignore pc-offset)) (when (> depth max-depth) @@ -372,17 +379,17 @@ (incf (node-accrued-count caller))) (t (incf elsewhere-count))))) - *samples*) + samples) (let ((sorted-nodes (sort (collect-nodes) #'> :key #'node-count))) (loop for node in sorted-nodes and i from 1 do (setf (node-index node) i)) - (%make-call-graph :nsamples (samples-trace-count *samples*) - :sample-interval (if (eq (samples-mode *samples*) - :alloc) - (samples-alloc-interval *samples*) - (samples-sample-interval *samples*)) - :sampling-mode (samples-mode *samples*) - :sampled-threads (samples-sampled-threads *samples*) + (%make-call-graph :nsamples (samples-trace-count samples) + :unique-trace-count (samples-unique-trace-count samples) + :sample-interval (if (eq (samples-mode samples) :alloc) + 1 + (samples-sample-interval samples)) + :sampling-mode (samples-mode samples) + :sampled-threads (samples-sampled-threads samples) :elsewhere-count elsewhere-count :vertices sorted-nodes))))) @@ -417,10 +424,19 @@ ;;; *SAMPLES*. The result contain a list of nodes sorted by self-time ;;; in the FLAT-NODES slot, and a dag in VERTICES, with call cycles ;;; reduced to CYCLE structures. -(defun make-call-graph (max-depth) +(defun make-call-graph (samples max-depth) (stop-profiling) - (show-progress "~&Computing call graph ") - (let ((call-graph (without-gcing (make-call-graph-1 max-depth)))) + (when (zerop (length (samples-vector samples))) + (show-progress "~&Aggregating raw data") + (setf (values (samples-vector samples) + (samples-unique-trace-count samples) + (samples-sampled-threads samples)) + (convert-raw-data))) + (show-progress "~&Computing call graph") + ;; I _think_ the reason for pinning all code is that the graph logic + ;; compares absolute PC locations. Wonderfully commented, it is. + (let ((call-graph (with-code-pages-pinned (:dynamic) + (make-call-graph-1 samples max-depth)))) (show-progress "~&Finding cycles") #+nil (reduce-call-graph call-graph) diff --git a/contrib/sb-sprof/interface.lisp b/contrib/sb-sprof/interface.lisp index 0040582a98..34e4cca608 100644 --- a/contrib/sb-sprof/interface.lisp +++ b/contrib/sb-sprof/interface.lisp @@ -9,14 +9,8 @@ "Default number of seconds between samples.") (declaim (type (real (0)) *sample-interval*)) -(defvar *alloc-interval* 4 - "Default number of allocation region openings between samples.") -(declaim (type (integer (0)) *alloc-interval*)) - (defvar *max-samples* 50000 - "Default number of traces taken. This variable is somewhat misnamed: -each trace may actually consist of an arbitrary number of samples, depending -on the depth of the call stack.") + "Default maximum number of stack traces collected.") (declaim (type sb-int:index *max-samples*)) (defvar *sampling-mode* :cpu @@ -25,57 +19,44 @@ profiling, and :TIME for wallclock profiling.") (declaim (type sampling-mode *sampling-mode*)) (defmacro with-profiling ((&key (sample-interval '*sample-interval*) - (alloc-interval '*alloc-interval*) + alloc-interval (max-samples '*max-samples*) (reset nil) (mode '*sampling-mode*) (loop nil) - (max-depth most-positive-fixnum) + max-depth show-progress - (threads '(list sb-thread:*current-thread*)) + (threads :all) (report nil report-p)) &body body) "Evaluate BODY with statistical profiling turned on. If LOOP is true, loop around the BODY until a sufficient number of samples has been collected. Returns the values from the last evaluation of BODY. -In multithreaded operation, only the thread in which WITH-PROFILING was -evaluated will be profiled by default. If you want to profile multiple -threads, invoke the profiler with START-PROFILING. - The following keyword args are recognized: :SAMPLE-INTERVAL Take a sample every seconds. Default is *SAMPLE-INTERVAL*. - :ALLOC-INTERVAL - Take a sample every time allocation regions (approximately - 8kB) have been allocated since the last sample. Default is - *ALLOC-INTERVAL*. - :MODE If :CPU, run the profiler in CPU profiling mode. If :ALLOC, run the profiler in allocation profiling mode. If :TIME, run the profiler in wallclock profiling mode. :MAX-SAMPLES - Repeat evaluating body until samples are taken. + If :LOOP is NIL (the default), collect no more than samples. + If :LOOP is T, repeat evaluating body until samples are taken. Default is *MAX-SAMPLES*. - :MAX-DEPTH - Maximum call stack depth that the profiler should consider. Only - has an effect on x86 and x86-64. - :REPORT If specified, call REPORT with :TYPE at the end. :RESET - It true, call RESET at the beginning. + If true, call RESET at the beginning. :THREADS Form that evaluates to the list threads to profile, or :ALL to indicate - that all threads should be profiled. Defaults to the current - thread. (Note: START-PROFILING defaults to all threads.) + that all threads should be profiled. Defaults to all threads. :THREADS has no effect on call-counting at the moment. @@ -90,80 +71,67 @@ The following keyword args are recognized: evaluate BODY." (declare (type report-type report)) (check-type loop boolean) - (with-unique-names (values last-index oops) - `(let* ((*sample-interval* ,sample-interval) - (*alloc-interval* ,alloc-interval) - (*sampling* nil) - (*sampling-mode* ,mode) - (*max-samples* ,max-samples)) - ,@(when reset '((reset))) - (flet ((,oops () - (warn "~@"))) + #-sb-thread (unless (eq threads :all) (warn ":THREADS is ignored")) + (when alloc-interval (warn "ALLOC-INTERVAL is ignored")) + (when max-depth (warn "MAX-DEPTH is ignored")) + (let ((message "~@")) + (with-unique-names (values last-index) + `(let ((*show-progress* ,show-progress)) + ,@(when reset '((reset))) (unwind-protect (progn - (start-profiling :max-depth ,max-depth :threads ,threads) + (start-profiling :mode ,mode :max-samples ,max-samples + :sample-interval ,sample-interval + :threads ,threads) ,(if loop `(let (,values) - (loop - (when (>= (samples-trace-count *samples*) - (samples-max-samples *samples*)) + (loop ; Uh, shouldn't this be a trailing test, not a leading test? + (when (>= trace-count trace-limit) (return)) - ,@(when show-progress - `((format t "~&===> ~d of ~d samples taken.~%" - (samples-trace-count *samples*) - (samples-max-samples *samples*)))) - (let ((,last-index (samples-index *samples*))) + (show-progress "~&===> ~d of ~d samples taken.~%" + trace-count trace-limit) + (let ((,last-index trace-count)) (setf ,values (multiple-value-list (progn ,@body))) - (when (= ,last-index (samples-index *samples*)) - (,oops) + (when (= ,last-index trace-count) + (warn ,message) (return)))) (values-list ,values)) - `(let ((,last-index (samples-index *samples*))) + `(let ((,last-index trace-count)) (multiple-value-prog1 (progn ,@body) - (when (= ,last-index (samples-index *samples*)) - (,oops)))))) - (stop-profiling))) - ,@(when report-p `((report :type ,report)))))) + (when (= ,last-index trace-count) + (warn ,message)))))) + (stop-profiling)) + ,@(when report-p `((report :type ,report))))))) -(defvar *timer* nil) +;;; In wallclock mode, *TIMER* is an instance of either SB-THREAD:THREAD +;;; or SB-EXT:TIMER depending on whether thread support exists. +(defglobal *timer* nil) #-win32 (defun start-profiling (&key (max-samples *max-samples*) (mode *sampling-mode*) (sample-interval *sample-interval*) - (alloc-interval *alloc-interval*) - (max-depth most-positive-fixnum) - (threads :all) - (sampling t)) + alloc-interval + max-depth + (threads :all)) "Start profiling statistically in the current thread if not already profiling. The following keyword args are recognized: :SAMPLE-INTERVAL Take a sample every seconds. Default is *SAMPLE-INTERVAL*. - :ALLOC-INTERVAL - Take a sample every time allocation regions (approximately - 8kB) have been allocated since the last sample. Default is - *ALLOC-INTERVAL*. - :MODE If :CPU, run the profiler in CPU profiling mode. If :ALLOC, run the profiler in allocation profiling mode. If :TIME, run the profiler in wallclock profiling mode. :MAX-SAMPLES - Maximum number of samples. Default is *MAX-SAMPLES*. - - :MAX-DEPTH - Maximum call stack depth that the profiler should consider. Only - has an effect on x86 and x86-64. + Maximum number of stack traces to collect. Default is *MAX-SAMPLES*. :THREADS List threads to profile, or :ALL to indicate that all threads should be - profiled. Defaults to :ALL. (Note: WITH-PROFILING defaults to the current - thread.) + profiled. Defaults to :ALL. :THREADS has no effect on call-counting at the moment. @@ -171,94 +139,116 @@ The following keyword args are recognized: not properly delivered to threads in proportion to their CPU usage when doing :CPU profiling. If you see empty call graphs, or are obviously missing several samples from certain threads, you may be falling afoul - of this. - - :SAMPLING - If true, the default, start sampling right away. - If false, START-SAMPLING can be used to turn sampling on." + of this." + ;; Starting the clock with an interval of zero or negative is meaningless. + ;; If, by 0, you mean STOP-PROFILING then you should use STOP-PROFILING. + (declare (type (real (0)) sample-interval)) + (when alloc-interval (warn "ALLOC-INTERVAL is ignored")) + (when max-depth (warn "MAX-DEPTH is ignored")) #-gencgc (when (eq mode :alloc) (error "Allocation profiling is only supported for builds using the generational garbage collector.")) - (unless *profiling* - (multiple-value-bind (secs usecs) - (multiple-value-bind (secs rest) - (truncate sample-interval) - (values secs (truncate (* rest 1000000)))) - (setf *sampling* sampling - *samples* (make-samples :start-time (get-internal-real-time) - :max-depth max-depth - :max-samples max-samples - :sample-interval sample-interval - :alloc-interval alloc-interval - :mode mode)) - (enable-call-counting) - (setf *profiled-threads* threads) - (sb-sys:enable-interrupt sb-unix:sigprof - #'sigprof-handler - :synchronous t) - (ecase mode - (:alloc - (let ((alloc-signal (1- alloc-interval))) - #+sb-thread - (progn - (when (eq :all threads) - ;; Set the value new threads inherit. - (sb-thread::with-all-threads-lock - (setf sb-thread::*default-alloc-signal* alloc-signal))) - ;; Turn on allocation profiling in existing threads. - (dolist (thread (profiled-threads)) - (sb-thread::%set-symbol-value-in-thread 'sb-vm::*alloc-signal* thread alloc-signal))) - #-sb-thread - (setf sb-vm:*alloc-signal* alloc-signal))) - (:cpu - (unix-setitimer :profile secs usecs secs usecs)) - (:time - #+sb-thread - (let ((setup (sb-thread:make-semaphore :name "Timer thread setup semaphore"))) - (setf *timer-thread* - (sb-thread:make-thread (lambda () - (sb-thread:wait-on-semaphore setup) - (loop while (eq sb-thread:*current-thread* *timer-thread*) - do (sleep 1.0))) - :name "SB-SPROF wallclock timer thread")) - (sb-thread:signal-semaphore setup)) - #-sb-thread - (setf *timer-thread* nil) - (setf *timer* (make-timer #'thread-distribution-handler :name "SB-PROF wallclock timer" - :thread *timer-thread*)) - (schedule-timer *timer* sample-interval :repeat-interval sample-interval))) - (setq *profiling* mode))) - (values)) + #-sb-thread (unless (eq threads :all) (warn ":THREADS is ignored")) + (when *profiling* + (warn "START-PROFILING will STOP-PROFILING first before applying new parameters") + (stop-profiling)) + ;; I'm 99% sure that unconditionally assigning *SAMPLES* is a bug, + ;; because doing it makes the RESET function (and the :RESET keyword + ;; to WITH-PROFILING) meaningless - what's the difference between + ;; resetting and not resetting if either way causes all previously + ;; acquired traces to disappear? My intuition would have been that + ;; start/stop/start/stop should leave *SAMPLES* holding a union of all + ;; traces captured by both "on" periods, whereas with a RESET in between + ;; it would not. But they behave identically, because this is a reset. + (setf *samples* (make-samples mode sample-interval)) + (setf trace-limit max-samples trace-count 0) + (enable-call-counting) + #+sb-thread (setf sb-thread::*profiled-threads* threads) + ;; Each existing threads' sprof-enable slot needs to reflect the desired set. + (sb-thread::avltree-filter + (lambda (node &aux (thread (sb-thread::avlnode-data node))) + (if (or (eq threads :all) (memq thread threads)) + (start-sampling thread) + (stop-sampling thread))) + sb-thread::*all-threads*) + ;; The signal handler is entirely in C now. install_handler() uses the argument + ;; as a boolean flag. -1 means "install", 0 means "uninstall" which we don't do. + ;; Statistical allocation profiling is not signal-based- instead, whenever a C call + ;; occurs to handle thread-local allocation region overflow, a trace is recorded. + (unless (eq mode :alloc) + (with-alien ((%sigaction (function void int signed) :extern "install_handler")) + (alien-funcall %sigaction sb-unix:sigprof -1))) + ;; Keep all code live no matter if apparently unreferenced + (setf (extern-alien "sb_sprof_enabled" int) 1) + (ecase mode + (:alloc + (setq enable-alloc-profiler 1)) + (:cpu + (multiple-value-bind (secs usecs) + (multiple-value-bind (secs rest) (truncate sample-interval) + (values secs (truncate (* rest 1000000)))) + (unix-setitimer :profile secs usecs secs usecs))) + (:time + #+sb-thread + (flet ((map-threads (function &aux (threads sb-thread::*profiled-threads*)) + (if (listp threads) + (mapc function threads) + (named-let visit ((node sb-thread::*all-threads*)) + (awhen (sb-thread::avlnode-left node) (visit it)) + (awhen (sb-thread::avlnode-right node) (visit it)) + (let ((thread (sb-thread::avlnode-data node))) + (when (and (= (sb-thread::thread-%visible thread) 1) + (neq thread *timer*)) + (funcall function thread))))))) + (sb-thread::start-thread + (setf *timer* (sb-thread::%make-thread "SPROF timer" nil (sb-thread:make-semaphore))) + (lambda () + (loop (unless *timer* (return)) + (sleep sample-interval) + (map-threads + (lambda (thread) + (sb-thread:with-deathlok (thread c-thread) + (unless (= c-thread 0) + (sb-unix:pthread-kill (sb-thread::thread-os-thread thread) + sb-unix:sigprof))))))) + nil)) + #-sb-thread + (schedule-timer (setf *timer* (make-timer (lambda () (unix-kill 0 sb-unix:sigprof)) + :name "SPROF timer")) + sample-interval :repeat-interval sample-interval))) + (setq *profiling* mode)) (defun stop-profiling () "Stop profiling if profiling." (let ((profiling *profiling*)) (when profiling ;; Even with the timers shut down we cannot be sure that there is no - ;; undelivered sigprof. The handler is also responsible for turning the - ;; *ALLOC-SIGNAL* off in individual threads. + ;; undelivered sigprof. (ecase profiling (:alloc - #+sb-thread - (setf sb-thread::*default-alloc-signal* nil) - #-sb-thread - (setf sb-vm:*alloc-signal* nil)) + (setq enable-alloc-profiler 0)) (:cpu (unix-setitimer :profile 0 0 0 0)) (:time - (unschedule-timer *timer*) - (setf *timer* nil - *timer-thread* nil))) + (let ((timer *timer*)) + ;; after this assignment, the timer thread will raise the + ;; profiling signal at most once more, and then stop. + (setf *timer* nil) + #-sb-thread (unschedule-timer timer) + #+sb-thread (sb-thread:join-thread timer)))) (disable-call-counting) - (setf *profiling* nil - *sampling* nil - *profiled-threads* nil) - (setf (samples-end-time *samples*) (get-internal-real-time)))) + ;; New threads should not mask SIGPROF by default + #+sb-thread (setf sb-thread::*profiled-threads* :all) + (let ((samples *samples*)) + (aver samples) + (setf (samples-trace-count samples) trace-count)) + (setf *profiling* nil))) (values)) (defun reset () "Reset the profiler." (stop-profiling) - (setq *sampling* nil) (setq *samples* nil) + (setf trace-count 0) + (call-with-each-profile-buffer (lambda (x y z) (declare (ignore x y z)))) (values)) diff --git a/contrib/sb-sprof/package.lisp b/contrib/sb-sprof/package.lisp index a0c6262d1b..3ce83e71e8 100644 --- a/contrib/sb-sprof/package.lisp +++ b/contrib/sb-sprof/package.lisp @@ -8,7 +8,7 @@ (:export ;; Recording #:start-sampling #:stop-sampling #:with-sampling - #:map-traces #:map-trace-samples #:map-all-samples + #:map-traces #:sample-pc ;; Call counting @@ -19,7 +19,7 @@ #:report ;; Interface - #:*sample-interval* #:*max-samples* #:*alloc-interval* + #:*sample-interval* #:*max-samples* #:start-profiling #:stop-profiling #:with-profiling #:reset)) (eval-when (:compile-toplevel :load-toplevel :execute) diff --git a/contrib/sb-sprof/record.lisp b/contrib/sb-sprof/record.lisp index 09a781e617..86524373d7 100644 --- a/contrib/sb-sprof/record.lisp +++ b/contrib/sb-sprof/record.lisp @@ -5,270 +5,193 @@ (in-package #:sb-sprof) - -;;; Append-only sample vector - (deftype sampling-mode () '(member :cpu :alloc :time)) ;;; 0 code-component-ish ;;; 1 an offset relative to the start of the code-component or an ;;; absolute address -(defconstant +elements-per-sample+ 2) +(defconstant +elements-per-pc-loc+ 2) ;;; 0 the trace start marker (trace-start . END-INDEX) ;;; 1 the current thread, an SB-THREAD:THREAD instance -;;; 2 the current internal real time -(defconstant +elements-per-trace-start+ 3) - -(declaim (inline make-sample-vector)) -(defun make-sample-vector (max-samples) - (make-array (* max-samples - ;; Arbitrary guess at how many samples we'll be - ;; taking for each trace. The exact amount doesn't - ;; matter, this is just to decrease the amount of - ;; re-allocation that will need to be done. - 10 - ;; Each sample takes two cells in the vector - +elements-per-sample+))) +(defconstant +elements-per-trace-start+ 2) ;;; Encapsulate all the information about a sampling run -(defstruct (samples - (:constructor - make-samples (&key start-time - mode sample-interval alloc-interval - max-depth max-samples - &aux (vector (make-sample-vector max-samples))))) - ;; When this vector fills up, we allocate a new one and copy over - ;; the old contents. - (vector nil :type simple-vector) - (index 0 :type sb-int:index) - ;; Only used while recording a trace. Stores a cell that is - ;; - ;; (start-trace . nil) (start-trace is the marker symbol - ;; SB-SPROF:START-TRACE) - ;; - ;; when starting to record a trace and - ;; - ;; (start-trace . END-INDEX-OF-THE-TRACE) - ;; - ;; after finishing recording the trace. This allows MAP-TRACES to - ;; jump from one trace to the next in O(1) instead of O(N) time. - (trace-start '(nil . nil) :type cons) +(defstruct (samples (:constructor make-samples (mode sample-interval))) + (vector #() :type simple-vector) + ;; The trace count is updated only when profiling is stopped. (trace-count 0 :type sb-int:index) - + (unique-trace-count nil) (sampled-threads nil :type list) - ;; Metadata - (start-time (sb-int:missing-arg) :type sb-kernel:internal-time :read-only t) - (end-time nil :type (or null sb-kernel:internal-time)) - (mode nil :type sampling-mode :read-only t) - (sample-interval (sb-int:missing-arg) :type (real (0)) :read-only t) - (alloc-interval (sb-int:missing-arg) :type (integer (0)) :read-only t) - (max-depth most-positive-fixnum :type (and fixnum (integer (0))) :read-only t) - (max-samples (sb-int:missing-arg) :type sb-int:index :read-only t)) + (sample-interval (sb-int:missing-arg) :type (real (0)) :read-only t)) + +(defun samples-index (x) (length (samples-vector x))) + +(define-alien-variable ("gencgc_alloc_profiler" enable-alloc-profiler) (signed 32)) +(define-alien-variable ("sb_sprof_trace_ct" trace-count) (signed 32)) +(define-alien-variable ("sb_sprof_trace_ct_max" trace-limit) (signed 32)) (defmethod print-object ((samples samples) stream) (let ((*print-array* nil)) (call-next-method))) - -(defun note-sample-vector-full (samples) - (format *trace-output* "Profiler sample vector full (~:D trace~:P / ~ - approximately ~:D sample~:P), doubling the ~ - size~%" - (samples-trace-count samples) - (truncate (samples-index samples) +elements-per-sample+))) - -(declaim (inline ensure-samples-vector)) -(defun ensure-samples-vector (samples) - (declare (optimize (speed 3))) - (let ((vector (samples-vector samples)) - (index (samples-index samples))) - ;; Allocate a new sample vector if the current one is too small to - ;; accommodate the largest chunk of elements that we could - ;; potentially store in one go (currently 3 elements, stored by - ;; RECORD-TRACE-START). - (values (if (< (length vector) (+ index (max +elements-per-sample+ - +elements-per-trace-start+))) - (let ((new-vector (make-array (* 2 index)))) - (note-sample-vector-full samples) - (replace new-vector vector) - (setf (samples-vector samples) new-vector)) - vector) - index))) - -(defun record-trace-start (samples) - ;; Mark the start of the trace. - (multiple-value-bind (vector index) (ensure-samples-vector samples) - (let ((trace-start (cons 'trace-start nil))) - (setf (aref vector index) trace-start - (aref vector (+ index 1)) sb-thread:*current-thread* - (aref vector (+ index 2)) (get-internal-real-time)) - (setf (samples-index samples) (+ index +elements-per-trace-start+) - (samples-trace-start samples) trace-start)))) - -(defun record-trace-end (samples) - (setf (cdr (samples-trace-start samples)) (samples-index samples))) - -(declaim (inline record-sample)) -(defun record-sample (samples info pc-or-offset) - (multiple-value-bind (vector index) (ensure-samples-vector samples) - ;; For each sample, store the debug-info and the PC/offset into - ;; adjacent cells. - (setf (aref vector index) info - (aref vector (1+ index)) pc-or-offset) - (setf (samples-index samples) (+ index +elements-per-sample+)))) ;;; Trace and sample and access functions (defun map-traces (function samples) "Call FUNCTION on each trace in SAMPLES -The lambda list of FUNCTION has to be compatible to - - (thread time trace) +The signature of FUNCTION must be compatible with (thread trace). -. FUNCTION is called once for each trace such that THREAD is the -SB-THREAD:TREAD instance that was sampled to produce TRACE, TIME is -the internal real time at which TRACE was produced and TRACE is an -opaque object whose only purpose is being used as the second argument -to MAP-TRACE-SAMPLES. +FUNCTION is called once for each trace where THREAD is the SB-THREAD:TREAD +instance which was sampled to produce TRACE, and TRACE is an opaque object +to be passed to MAP-TRACE-PC-LOCS. EXPERIMENTAL: Interface subject to change." (let ((function (sb-kernel:%coerce-callable-to-fun function)) (vector (samples-vector samples)) - (index (samples-index samples)) - (start-time (samples-start-time samples))) + (index (samples-index samples))) (when (plusp index) (sb-int:aver (typep (aref vector 0) '(cons (eql trace-start) index))) (loop for start = 0 then end - while (< start index) for end = (cdr (aref vector start)) for thread = (aref vector (+ start 1)) - for time = (/ (- (aref vector (+ start 2)) start-time) - internal-time-units-per-second) do (let ((trace (list vector start end))) - (funcall function thread time trace)))))) - -(defun map-trace-samples (function trace) - "Call FUNCTION on each sample in TRACE. - -The lambda list of FUNCTION has to be compatible to - - (info pc-or-offset) - -. + (funcall function thread trace)) + while (< end index))))) -TRACE is an object as received by a function passed to MAP-TRACES. - -EXPERIMENTAL: Interface subject to change." +;;; Call FUNCTION on each PC location in TRACE. +;;; The signature of FUNCTION must be compatible with (info pc-or-offset). +;;; TRACE is an object as received by the function passed to MAP-TRACES. +(defun map-trace-pc-locs (function trace) (let ((function (sb-kernel:%coerce-callable-to-fun function))) (destructuring-bind (samples start end) trace - (loop for i from (- end +elements-per-sample+) + (loop for i from (- end +elements-per-pc-loc+) downto (+ start +elements-per-trace-start+ -1) - by +elements-per-sample+ + by +elements-per-pc-loc+ for info = (aref samples i) for pc-or-offset = (aref samples (1+ i)) do (funcall function info pc-or-offset))))) -(declaim (special *samples*)) -(defun map-all-samples (function &optional (samples *samples*)) - "Call FUNCTION on each sample in SAMPLES. - -The lambda list of FUNCTION has to be compatible to - - (info pc-or-offset) - -. - -SAMPLES is usually the value of *SAMPLES* after a profiling run. - -EXPERIMENTAL: Interface subject to change." - (sb-int:dx-flet ((do-trace (thread time trace) - (declare (ignore thread time)) - (map-trace-samples function trace))) +;;; One "sample" is a trace, usually. But also it means an instance of SAMPLES, +;;; but also it means a PC location expressed as code + offset. +;;; So when is a sample not a sample? When it's a PC location. +(declaim (type (or null samples) *samples*)) +(defglobal *samples* nil) + +;;; Call FUNCTION on each PC location in SAMPLES which is usually +;;; the value of *SAMPLES* after a profiling run. +;;; The signature of FUNCTION must be compatible with (info pc-or-offset). +(defun map-all-pc-locs (function &optional (samples *samples*)) + (sb-int:dx-flet ((do-trace (thread trace) + (declare (ignore thread)) + (map-trace-pc-locs function trace))) (map-traces #'do-trace samples))) (defun sample-pc (info pc-or-offset) "Extract and return program counter from INFO and PC-OR-OFFSET. -Can be applied to the arguments passed by MAP-TRACE-SAMPLES and -MAP-ALL-SAMPLES. +Can be applied to the arguments passed by MAP-TRACE-PC-LOCS and +MAP-ALL-PC-LOCS. EXPERIMENTAL: Interface subject to change." (etypecase info ;; Assembly routines or foreign functions don't move around, so ;; we've stored a raw PC - ((or null sb-kernel:code-component string) + ((or null sb-kernel:code-component string symbol) pc-or-offset) ;; Lisp functions might move, so we've stored a offset from the ;; start of the code component. (sb-di::compiled-debug-fun - (let* ((component (sb-di::compiled-debug-fun-component info)) - (start-pc (code-start component))) - (+ start-pc pc-or-offset))))) + (let ((component (sb-di::compiled-debug-fun-component info))) + (sap-int (sap+ (sb-kernel:code-instructions component) pc-or-offset)))))) ;;; Sampling -(defvar *samples* nil) -(declaim (type (or null samples) *samples*)) - +;;; *PROFILING* is both the global enabling flag, and the operational mode. (defvar *profiling* nil) (declaim (type (or (eql nil) sampling-mode) *profiling*)) -(defvar *sampling* nil) -(declaim (type boolean *sampling*)) (defvar *show-progress* nil) -(defvar *old-sampling* nil) - ;; Call count encapsulation information (defvar *encapsulations* (make-hash-table :test 'equal)) -(defun turn-off-sampling () - (setq *old-sampling* *sampling*) - (setq *sampling* nil)) - -(defun turn-on-sampling () - (setq *sampling* *old-sampling*)) - (defun show-progress (format-string &rest args) (when *show-progress* (apply #'format t format-string args) (finish-output))) -(defun start-sampling () - "Switch on statistical sampling." - (setq *sampling* t)) - -(defun stop-sampling () - "Switch off statistical sampling." - (setq *sampling* nil)) +(define-alien-routine "sb_toggle_sigprof" int (context system-area-pointer) (state int)) +(eval-when (:compile-toplevel) + ;; current-thread-offset-sap has no slot setter, let alone for other threads, + ;; nor for sub-fields of a word, so ... + (defmacro sprof-enable-byte () ; see 'thread.h' + (+ (ash sb-vm:thread-state-word-slot sb-vm:word-shift) 1))) + +;;; If a thread wants sampling but had previously blocked SIGPROF, +;;; it will have to unblock the signal. We can use %INTERRUPT-THREAD +;;; to tell it to do that. +(defun start-sampling (&optional (thread sb-thread:*current-thread*)) + "Unblock SIGPROF in the specified thread" + (if (eq thread sb-thread:*current-thread*) + (when (zerop (sap-ref-8 (sb-thread:current-thread-sap) (sprof-enable-byte))) + (setf (sap-ref-8 (sb-thread:current-thread-sap) (sprof-enable-byte)) 1) + (sb-toggle-sigprof (if (boundp 'sb-kernel:*current-internal-error-context*) + sb-kernel:*current-internal-error-context* + (sb-sys:int-sap 0)) + 0)) + ;; %INTERRUPT-THREAD requires that the interruptions lock be held by the caller. + (sb-thread:with-deathlok (thread c-thread) + (when (and (/= c-thread 0) + (zerop (sap-ref-8 (int-sap c-thread) (sprof-enable-byte)))) + (sb-thread::%interrupt-thread thread #'start-sampling)))) + nil) + +(defun stop-sampling (&optional (thread sb-thread:*current-thread*)) + "Block SIGPROF in the specified thread" + (sb-thread:with-deathlok (thread c-thread) + (when (and (/= c-thread 0) + (not (zerop (sap-ref-8 (int-sap c-thread) (sprof-enable-byte))))) + (setf (sap-ref-8 (int-sap c-thread) (sprof-enable-byte)) 0) + ;; Blocking the signal is done lazily in threads other than the current one. + (when (eq thread sb-thread:*current-thread*) + (sb-toggle-sigprof (sb-sys:int-sap 0) 1)))) ; 1 = mask it + nil) + +(defun call-with-sampling (enable thunk) + (declare (dynamic-extent thunk)) + (if (= (sap-ref-8 (sb-thread:current-thread-sap) (sprof-enable-byte)) + (if enable 1 0)) + ;; Already in the correct state + (funcall thunk) + ;; Invert state, call thunk, invert again + (progn (if enable (start-sampling) (stop-sampling)) + (unwind-protect (funcall thunk) + (if enable (stop-sampling) (start-sampling)))))) (defmacro with-sampling ((&optional (on t)) &body body) - "Evaluate body with statistical sampling turned on or off." - `(let ((*sampling* ,on) - (sb-vm:*alloc-signal* sb-vm:*alloc-signal*)) - ,@body)) + "Evaluate body with statistical sampling turned on or off in the current thread." + `(call-with-sampling (if ,on t nil) (lambda () ,@body))) ;;; Return something serving as debug info for address PC. -(declaim (inline debug-info)) -(defun debug-info (pc) +(defun debug-info (pc code) (declare (type system-area-pointer pc) (muffle-conditions compiler-note)) - (let ((code (sb-di::code-header-from-pc pc))) + (let ((pc-int (sap-int pc))) (cond ((not code) (let ((name (sap-foreign-symbol pc))) (if name (values (format nil "foreign function ~a" name) - (sap-int pc) - :foreign) - (values nil (sap-int pc) :foreign)))) + pc-int :foreign) + (values nil pc-int :foreign)))) + ((eq code sb-fasl:*assembler-routines*) + (values (sb-disassem::find-assembler-routine pc-int) + pc-int :asm-routine)) (t - (let* ((code-header-len (* (sb-kernel:code-header-words code) - sb-vm:n-word-bytes)) - ;; Give up if we land in the 2 or 3 instructions of a + (let* (;; Give up if we land in the 2 or 3 instructions of a ;; code component sans simple-fun that is not an asm routine. ;; While it's conceivable that this could be improved, ;; the problem will be different or nonexistent after @@ -277,192 +200,232 @@ EXPERIMENTAL: Interface subject to change." (di (unless (typep (sb-kernel:%code-debug-info code) 'sb-c::compiled-debug-info) (return-from debug-info - (values code (sap-int pc))))) - (pc-offset (- (sap-int pc) - (- (sb-kernel:get-lisp-obj-address code) - sb-vm:other-pointer-lowtag) - code-header-len)) + (values code pc-int nil)))) + (pc-offset (sap- (int-sap pc-int) (sb-kernel:code-instructions code))) (df (sb-di::debug-fun-from-pc code pc-offset))) #+immobile-code (declare (ignorable di)) (cond ((typep df 'sb-di::bogus-debug-fun) - (values code (sap-int pc) nil)) + (values code pc-int nil)) (df ;; The code component might be moved by the GC. Store - ;; a PC offset, and reconstruct the data in - ;; SAMPLE-PC-FROM-PC-OR-OFFSET. + ;; a PC offset, and reconstruct the data in SAMPLE-PC (values df pc-offset nil)) (t (values nil 0 nil)))))))) -(declaim (inline record)) -(defun record (samples pc) - (declare (type system-area-pointer pc)) - (multiple-value-bind (info pc-or-offset foreign) (debug-info pc) - (record-sample samples info pc-or-offset) - foreign)) - -;;; List of thread currently profiled, or :ALL for all threads. -(defvar *profiled-threads* nil) -(declaim (type (or list (member :all)) *profiled-threads*)) - -;;; Thread which runs the wallclock timers, if any. -(defvar *timer-thread* nil) - -(defun profiled-threads () - (let ((profiled-threads *profiled-threads*)) - (remove *timer-thread* - (if (eq :all profiled-threads) - (sb-thread:list-all-threads) - profiled-threads)))) - -(defun profiled-thread-p (thread) - (let ((profiled-threads *profiled-threads*)) - (or (and (eq :all profiled-threads) - (not (eq *timer-thread* thread))) - (member thread profiled-threads :test #'eq)))) - -#+(and (or x86 x86-64) (not win32)) -(progn - ;; Ensure that only one thread at a time will be doing profiling stuff. - (defvar *profiler-lock* (sb-thread:make-mutex :name "Statistical Profiler")) - (defvar *distribution-lock* (sb-thread:make-mutex :name "Wallclock profiling lock")) - - #+sb-thread - (declaim (inline pthread-kill)) - #+sb-thread - (define-alien-routine pthread-kill int (os-thread unsigned-long) (signal int)) - - ;;; A random thread will call this in response to either a timer firing, - ;;; This in turn will distribute the notice to those threads we are - ;;; interested using SIGPROF. - (defun thread-distribution-handler () - (declare (optimize speed (space 0))) - #+sb-thread - (let ((lock *distribution-lock*)) - ;; Don't flood the system with more interrupts if the last - ;; set is still being delivered. - (unless (sb-thread:mutex-value lock) - (sb-thread::with-system-mutex (lock) - (dolist (thread (profiled-threads)) - ;; This may occasionally fail to deliver the signal, but that - ;; seems better then using kill_thread_safely with it's 1 - ;; second backoff. - (let ((os-thread (sb-thread::thread-os-thread thread))) - (when os-thread - (pthread-kill os-thread sb-unix:sigprof))))))) - #-sb-thread - (unix-kill 0 sb-unix:sigprof)) - - (defun sigprof-handler (signal code scp) - (declare (ignore signal code) (optimize speed (space 0)) - (disable-package-locks sb-di::x86-call-context) - (muffle-conditions compiler-note) - (type system-area-pointer scp)) - (let ((self sb-thread:*current-thread*) - (profiling *profiling*)) - ;; Turn off allocation counter when it is not needed. Doing this in the - ;; signal handler means we don't have to worry about racing with the runtime - (unless (eq :alloc profiling) - (setf sb-vm::*alloc-signal* nil)) - (when (and *sampling* - ;; Normal SIGPROF gets practically speaking delivered to threads - ;; depending on the run time they use, so we need to filter - ;; out those we don't care about. For :ALLOC and :TIME profiling - ;; only the interesting threads get SIGPROF in the first place. - ;; - ;; ...except that Darwin at least doesn't seem to work like we - ;; would want it to, which makes multithreaded :CPU profiling pretty - ;; pointless there -- though it may be that our mach magic is - ;; partially to blame? - (or (not (eq :cpu profiling)) (profiled-thread-p self))) - (sb-thread::with-system-mutex (*profiler-lock* :without-gcing t) - (let ((samples *samples*) - ;; Don't touch the circularity hash-table - *print-circle*) - (when (and samples - (< (samples-trace-count samples) - (samples-max-samples samples))) - (with-alien ((scp (* os-context-t) :local scp)) - (let* ((pc-ptr (sb-vm:context-pc scp)) - (fp (sb-vm::context-register scp #.sb-vm::ebp-offset))) - ;; foreign code might not have a useful frame - ;; pointer in ebp/rbp, so make sure it looks - ;; reasonable before walking the stack - (unless (sb-di::control-stack-pointer-valid-p (sb-sys:int-sap fp)) - (return-from sigprof-handler nil)) - (incf (samples-trace-count samples)) - (pushnew self (samples-sampled-threads samples)) - (let ((fp (int-sap fp)) - (ok t)) - (declare (type system-area-pointer fp pc-ptr)) - ;; FIXME: How annoying. The XC doesn't store enough - ;; type information about SB-DI::X86-CALL-CONTEXT, - ;; even if we declaim the ftype explicitly in - ;; src/code/debug-int. And for some reason that type - ;; information is needed for the inlined version to - ;; be compiled without boxing the returned saps. So - ;; we declare the correct ftype here manually, even - ;; if the compiler should be able to deduce this - ;; exact same information. - (declare (ftype (function (system-area-pointer) - (values (member nil t) - system-area-pointer - system-area-pointer)) - sb-di::x86-call-context)) - (record-trace-start samples) - (dotimes (i (samples-max-depth samples)) - (record samples pc-ptr) - (setf (values ok pc-ptr fp) - (sb-di::x86-call-context fp)) - (unless ok - ;; If we fail to walk the stack beyond the - ;; initial frame, there is likely something - ;; wrong. Undo the trace start marker and the - ;; one sample we already recorded. - (when (zerop i) - (decf (samples-index samples) - (+ +elements-per-trace-start+ - (* +elements-per-sample+ (1+ i))))) - (return))) - (record-trace-end samples)))) - ;; Reset thread-local allocation counter before interrupts - ;; are enabled. - (when (eq t sb-vm::*alloc-signal*) - (setf sb-vm:*alloc-signal* (1- (samples-alloc-interval samples))))))))) - nil)) - -;; FIXME: On non-x86 platforms we don't yet walk the call stack deeper -;; than one level. -#-(or x86 x86-64) -(defun sigprof-handler (signal code scp) - (declare (ignore signal code)) - (sb-sys:without-interrupts - (let ((samples *samples*)) - (when (and *sampling* - samples - (< (samples-trace-count samples) - (samples-max-samples samples))) - (sb-sys:without-gcing - (with-alien ((scp (* os-context-t) :local scp)) - (locally (declare (optimize (inhibit-warnings 2))) - (incf (samples-trace-count samples)) - (record-trace-start samples) - (let ((pc-ptr (sb-vm:context-pc scp)) - (fp (sb-vm::context-register scp #.sb-vm::cfp-offset))) - (unless (eq (record samples pc-ptr) :foreign) - (record samples (sap-ref-sap - (int-sap fp) - (* sb-vm::lra-save-offset sb-vm::n-word-bytes))))) - (record-trace-end samples)))))))) - -;;; Return the start address of CODE. -(defun code-start (code) - (declare (type sb-kernel:code-component code)) - (sap-int (sb-kernel:code-instructions code))) - -;;; Return start and end address of CODE as multiple values. -(defun code-bounds (code) - (declare (type sb-kernel:code-component code)) - (let* ((start (code-start code)) - (end (+ start (sb-kernel:%code-text-size code)))) - (values start end))) +(defun sprof-data-header (sap) + (values (sap-ref-sap sap 0) ; bucket pointer + (sap-ref-32 sap 8) ; free pointer + (sap-ref-32 sap 12))) ; capacity +(defconstant n-buckets #x10000) +(defconstant element-size 8) +(defun sprof-data-trace (data trace-index) (sap+ data (* trace-index element-size))) +(defun trace-multiplicity (trace) (sap-ref-32 trace 4)) +(defun trace-len (trace) + #+64-bit (logand (sap-ref-64 trace 8) #xffffffff) + #-64-bit (sap-ref-32 trace 8)) + +;;; Pseudo-functions for marking questionable parts of the stack trace +(defun unavailable-frames ()) +(defun unknown-function ()) + +(defun build-serialno-to-code-map () + ;; Allocate a hash-table for serial# -> code object + ;; Identifying code-containing pages is quick (except on cheneygc), so + ;; two passes over the heap is cheaper than sizing up the table repeatedly. + (let ((ht (make-hash-table + :size (let ((n 0)) + (sb-vm:map-code-objects (lambda (x) (declare (ignore x)) (incf n))) + n)))) + ;; Collect the objects + (sb-vm:map-code-objects + (lambda (x) + (let ((serial (sb-kernel:%code-serialno x))) + (unless (eql serial 0) + (setf (gethash serial ht) x))))) + ht)) + +(defun extract-traces (sap serialno-to-code) + (macrolet ((absolute-pc (pc) + ;; Foreign function or immovable code + `(let ((sap (int-sap ,pc))) + (debug-info sap (sb-di::code-header-from-pc sap)))) + (relative-pc (serialno offset) + ;; Convert serial# + base-address-relative pc-offset + ;; to tagged code object + CODE-INSTRUCTIONS-relative pc-offset. + ;; This can fail only if the code was GCed in the meantime. + `(let* ((id ,serialno) + (code (gethash id serialno-to-code)) + (rel-pc ,offset)) + (when (and (not code) (/= id 0)) + ;; If the serial# could not be found, something has gone wrong in GC. + ;; This really should not happen. If it does, simulate a random code blob + ;; named with that serial#. + (setf code (sb-kernel:fun-code-header + (compile nil `(named-lambda ,(format nil "Unknown fn ~d" id) ()))) + (gethash id serialno-to-code) code + rel-pc 0)) + (if code + (with-pinned-objects (code) + (debug-info (sap+ (int-sap (logandc2 (sb-kernel:get-lisp-obj-address code) + sb-vm:lowtag-mask)) + rel-pc) + code)) + (let ((code (sb-kernel:fun-code-header #'unknown-function))) + (debug-info (sb-kernel:code-instructions code) code))))) + (elision-marker () + `(let ((code (sb-kernel:fun-code-header #'unavailable-frames))) + (debug-info (sb-kernel:code-instructions code) code)))) + (do ((free-ptr (nth-value 1 (sprof-data-header sap))) + (trace-ptr 2) + (result)) + ((>= trace-ptr free-ptr) + (aver (= trace-ptr free-ptr)) + result) + (let* ((trace (sprof-data-trace sap trace-ptr)) + (len (trace-len trace)) + ;; byte offset into the trace at which the locs[] array begins + (element-offset 16) + (locs)) + (dotimes (i len (push (cons (nreverse (coerce locs 'vector)) + (trace-multiplicity trace)) + result)) + (multiple-value-bind (info pc-or-offset) + #-64-bit + (let ((word0 (sap-ref-word trace element-offset)) + (word1 (sap-ref-word trace (+ element-offset 4)))) + (cond ((not (zerop word1)) (relative-pc word0 word1)) ; serial# + offset + ((eql word0 sb-ext:most-positive-word) (elision-marker)) + (t (absolute-pc word0)))) + #+64-bit + (let ((bits (sap-ref-word trace element-offset))) + (cond ((eql bits sb-ext:most-positive-word) (elision-marker)) + ((logbitp 63 bits) + (relative-pc (ldb (byte 32 0) bits) (ldb (byte 31 32) bits))) + (t (absolute-pc bits)))) + (setf locs (list* pc-or-offset info locs)) + (incf element-offset element-size))) + (incf trace-ptr (+ 2 len)))))) + +;;; Call FUNCTION with each thread's sampled data, and deallocate the data. +(defun call-with-each-profile-buffer (function) + (with-alien ((acquire-data (function system-area-pointer unsigned) :extern "acquire_sprof_data")) + (flet ((process (sap thread) + (multiple-value-bind (buckets free-ptr capacity) (sprof-data-header sap) + (let ((buckets-used 0)) + (dotimes (bucket-index n-buckets) + ;; bucket values are uint32_t + (when (plusp (sap-ref-32 buckets (ash bucket-index 2))) (incf buckets-used))) + (funcall function sap thread + (list (* free-ptr element-size) + (* capacity element-size) + buckets-used))) + (sb-sys:deallocate-system-memory buckets (* n-buckets 4)) + (sb-sys:deallocate-system-memory sap (* capacity element-size))))) + (let ((all-threads sb-thread::*all-threads*) + (processed-threads)) + ;; Scan exited threads. Careful not to lose elements if a thread receives a + ;; profiling signal after the timer gets stopped, exits, and pushes data into + ;; the list. i.e. concurrent access to sb-thread::*sprof-data* is possible. + #+sb-thread + (loop + (let ((data (atomic-pop sb-thread::*sprof-data*))) + (unless data (return)) + (destructuring-bind (sap . thread) data + ;; Avoid double-free of the foreign memory, in case two threads try to + ;; reset the profiler at the same time (which constitutes user error) + (when (and sap (eq (cas (car data) sap nil) sap)) + (process sap thread) + (push thread processed-threads))))) + ;; Scan running threads + (sb-thread::avltree-filter + (lambda (node &aux (thread (sb-thread::avlnode-data node))) + (unless (memq thread processed-threads) + ;; Ensure that the thread can't exit (which ensures that it can't free the sprof_sem + ;; that might be needed by the C routine, depending on things), and also ensure + ;; mutual exclusivity with other callers of this. + (sb-thread:with-deathlok (thread c-thread) + (unless (zerop c-thread) + (let ((sap (alien-funcall acquire-data c-thread))) + (unless (= (sap-int sap) 0) + (process sap thread)))))) + nil) + all-threads))))) + +(defun convert-raw-data () + (let ((ht (build-serialno-to-code-map)) + (threads) + ;; traces are not de-deduplicated across threads, + ;; so this number is only approximate. + (n-unique-traces 0) + (aggregate-data)) + ;; Mask SIGPROF in this thread in case of pending signal + ;; and funky scheduling by the OS. + (let ((saved-sigprof-mask (sb-toggle-sigprof (int-sap 0) 1))) + (call-with-each-profile-buffer + (lambda (sap thread memusage) + (push (cons thread memusage) threads) + (push (cons (extract-traces sap ht) thread) aggregate-data))) + (setf (extern-alien "sb_sprof_enabled" int) 0) + (sb-toggle-sigprof (int-sap 0) saved-sigprof-mask)) + ;; Precompute the length of the new SAMPLES-VECTOR + (let ((vector + (make-array + (let ((total-length 0)) + (dolist (subsample aggregate-data total-length) + (loop for (trace . multiplicity) in (car subsample) + do (incf total-length (* (+ (length trace) +elements-per-trace-start+) + multiplicity))))))) + (index 0)) + ;; Now fill in the vector to match the old data format. + ;; This is of needlessly inefficient for :ALLOC mode, since the entire point + ;; of the new format is to speed up callgraph construction. + (dolist (subsample aggregate-data) + (loop with thread = (cdr subsample) + for (trace . multiplicity) in (car subsample) + do (incf n-unique-traces) + (dotimes (i multiplicity) + (let* ((len (+ (length trace) +elements-per-trace-start+)) + (end (+ index len))) + (setf (aref vector index) `(trace-start . ,end) + (aref vector (1+ index)) thread) + (replace vector trace :start1 (+ index 2)) + (setq index end))))) + (aver (= index (length vector))) + (values vector n-unique-traces threads)))) + +#+nil +(defun dump-hash-buckets (sap-or-thread) + (binding* ((sap (if (typep sap-or-thread 'sb-thread::thread) + (sap-ref-sap (int-sap (sb-thread::thread-primitive-thread sap-or-thread)) + (ash sb-vm:thread-sprof-data-slot sb-vm:word-shift)) + sap-or-thread)) + ((buckets free-ptr) (sprof-data-header sap)) + (buckets-used 0) + (trace-ptr 2) + (n-traces 0) + (n-unique 0)) + (dotimes (bucket-index n-buckets) + (let ((n (do ((entry (sap-ref-32 buckets (ash bucket-index 2)) + (sap-ref-32 (sprof-data-trace sap entry) 0)) + (chainlen 0 (1+ chainlen))) + ((= entry 0) chainlen)))) + (when (plusp n) + (incf buckets-used) + (format t "~5d ~d~%" bucket-index n)))) + (loop while (< trace-ptr free-ptr) + do (let ((trace (sprof-data-trace sap trace-ptr))) + (incf n-unique) + (incf n-traces (trace-multiplicity trace)) + (incf trace-ptr (+ 2 (trace-len trace))))) + (aver (= trace-ptr free-ptr)) + (format t "~d buckets in use, ~D unique traces, ~D total~%" buckets-used n-unique n-traces))) + +#+nil +(defun code-summary-by-gc-generation () + (let ((gens (make-array 7 :initial-element 0))) + (dolist (code (sb-vm:list-allocated-objects :all :type sb-vm:code-header-widetag)) + (let ((gen (sb-kernel:generation-of code))) + (when (<= 0 gen 6) + (incf (aref gens gen))))) + gens)) diff --git a/contrib/sb-sprof/report.lisp b/contrib/sb-sprof/report.lisp index a6f394a938..4a67a4b188 100644 --- a/contrib/sb-sprof/report.lisp +++ b/contrib/sb-sprof/report.lisp @@ -7,9 +7,9 @@ (defconstant +alloc-region-size+ #-gencgc - (get-page-size) + sb-c:+backend-page-bytes+ #+gencgc - (max sb-vm:gencgc-alloc-granularity sb-vm:gencgc-card-bytes)) + (max sb-vm:gencgc-alloc-granularity sb-vm:gencgc-page-bytes)) (deftype report-type () '(member nil :flat :graph)) @@ -38,27 +38,28 @@ count (scc-p v)))) (if (eq (call-graph-sampling-mode call-graph) :alloc) (format t "~2&Number of samples: ~d~%~ + Unique traces: ~d~%~ Alloc interval: ~a regions (approximately ~a kB)~%~ - Total sampling amount: ~a regions (approximately ~a kB)~%~ - Number of cycles: ~d~%~ - Sampled threads:~{~% ~S~}~2%" + Total sampling amount: ~a regions (approximately ~a kB)" nsamples + (call-graph-unique-trace-count call-graph) interval (truncate (* interval +alloc-region-size+) 1024) (* nsamples interval) - (truncate (* nsamples interval +alloc-region-size+) 1024) - ncycles - (call-graph-sampled-threads call-graph)) + (truncate (* nsamples interval +alloc-region-size+) 1024)) (format t "~2&Number of samples: ~d~%~ Sample interval: ~f seconds~%~ - Total sampling time: ~f seconds~%~ - Number of cycles: ~d~%~ - Sampled threads:~{~% ~S~}~2%" + Total sampling time: ~f seconds" nsamples interval - (* nsamples interval) - ncycles - (call-graph-sampled-threads call-graph))))) + (* nsamples interval))) + (format t "~%Graph cycles: ~d~%~ + Sampled threads:~%" ncycles) + (loop for (thread bytes-used bytes-reserved buckets-used) + in (call-graph-sampled-threads call-graph) + do (format t " ~a (~d/~d bytes, ~d hash buckets)~%" + thread bytes-used bytes-reserved buckets-used)) + (terpri))) (declaim (type report-sort-key *report-sort-by*)) (defvar *report-sort-by* :samples @@ -121,7 +122,7 @@ (accrued-percent (samples-percent call-graph accrued-count))) (incf total-count count) (incf total-percent percent) - (format t "~&~4d ~6d ~5,1f ~6d ~5,1f ~6d ~5,1f ~8@a ~s~%" + (format t "~&~4d ~6d ~5,1f ~6d ~5,1f ~6d ~5,1f ~8@a " (incf i) count percent @@ -129,8 +130,10 @@ accrued-percent total-count total-percent - (or (node-call-count node) "-") - (node-name node)) + (or (node-call-count node) "-")) + (if (stringp (node-name node)) + (format t "~a~%" (node-name node)) + (format t "~s~%" (node-name node))) (finish-output))) (print-separator) (format t "~& ~6d ~5,1f~36a elsewhere~%" @@ -145,8 +148,12 @@ (do-vertices (node call-graph) (when (cycle-p node) (flet ((print-info (indent index count percent name) - (format t "~&~6d ~5,1f ~11@t ~V@t ~s [~d]~%" - count percent indent name index))) + (format t "~&~6d ~5,1f ~11@t ~V@t " + count percent indent) + (if (stringp name) + (format t "~a" name) + (format t "~s" name)) + (format t " [~d]~%" index))) (print-separator) (format t "~&~6d ~5,1f ~a...~%" (node-count node) @@ -168,8 +175,12 @@ (flet ((find-call (from to) (find to (node-edges from) :key #'call-vertex)) (print-info (indent index count percent name) - (format t "~&~6d ~5,1f ~11@t ~V@t ~s [~d]~%" - count percent indent name index))) + (format t "~&~6d ~5,1f ~11@t ~V@t " + count percent indent) + (if (stringp name) + (format t "~a" name) + (format t "~s" name)) + (format t " [~d]~%" index))) (format t "~& Callers~%") (format t "~& Total. Function~%") (format t "~& Count % Count % Callees~%") @@ -185,13 +196,15 @@ (samples-percent call-graph (call-count call)) (node-name caller)))) ;; Print the node itself. - (format t "~&~6d ~5,1f ~6d ~5,1f ~s [~d]~%" + (format t "~&~6d ~5,1f ~6d ~5,1f " (node-count node) (samples-percent call-graph (node-count node)) (node-accrued-count node) - (samples-percent call-graph (node-accrued-count node)) - (node-name node) - (node-index node)) + (samples-percent call-graph (node-accrued-count node))) + (if (stringp (node-name node)) + (format t "~a" (node-name node)) + (format t "~s" (node-name node))) + (format t " [~d]~%" (node-index node)) ;; Print callees. (do-edges (call called node) (print-info 4 (node-index called) @@ -248,8 +261,8 @@ resulting call-graph, or NIL if there are no samples (eg. right after calling RESET.) Profiling is stopped before the call graph is generated." - (cond (*samples* - (let ((graph (or call-graph (make-call-graph most-positive-fixnum)))) + (acond (*samples* + (let ((graph (or call-graph (make-call-graph it most-positive-fixnum)))) (ecase type (:flat (print-flat graph :stream stream :max max :min-percent min-percent)) @@ -257,6 +270,6 @@ Profiling is stopped before the call graph is generated." (print-graph graph :stream stream :max max :min-percent min-percent)) ((nil))) graph)) - (t - (format stream "~&; No samples to report.~%") - nil))) + (t + (format stream "~&; No samples to report.~%") + nil))) diff --git a/contrib/sb-sprof/sb-sprof.asd b/contrib/sb-sprof/sb-sprof.asd index 0bd4f6b326..b04b677963 100644 --- a/contrib/sb-sprof/sb-sprof.asd +++ b/contrib/sb-sprof/sb-sprof.asd @@ -13,13 +13,4 @@ (:file "report") (:file "interface") (:file "disassemble")) - :perform (load-op :after (o c) (provide 'sb-sprof)) - :in-order-to ((test-op (test-op "sb-sprof/tests")))) - -(defsystem "sb-sprof/tests" - :depends-on ("sb-sprof") - :components ((:file "test")) - :perform (test-op (o c) - #-(or win32 darwin) ;not yet - (or (funcall (find-symbol "RUN-TESTS" "SB-SPROF-TEST")) - (error "test-op failed")))) + :perform (load-op :after (o c) (provide 'sb-sprof))) diff --git a/contrib/sb-sprof/sb-sprof.texinfo b/contrib/sb-sprof/sb-sprof.texinfo index 59717fcd6b..2fec2ebaca 100644 --- a/contrib/sb-sprof/sb-sprof.texinfo +++ b/contrib/sb-sprof/sb-sprof.texinfo @@ -118,12 +118,6 @@ runs. @subsection Platform support -This module is known not to work consistently on the Alpha platform, -for technical reasons related to the implementation of a machine -language idiom for marking sections of code to be treated as atomic by -the garbage collector; However, it should work on other platforms, -and the deficiency on the Alpha will eventually be rectified. - Allocation profiling is only supported on SBCL builds that use the generational garbage collector. Tracking of call stacks at a depth of more than two levels is only supported on x86 and x86-64. @@ -137,10 +131,6 @@ depth of more than two levels is only supported on x86 and x86-64. @include fun-sb-sprof-map-traces.texinfo -@include fun-sb-sprof-map-trace-samples.texinfo - -@include fun-sb-sprof-map-all-samples.texinfo - @include fun-sb-sprof-sample-pc.texinfo @include fun-sb-sprof-report.texinfo diff --git a/contrib/sb-sprof/test.lisp b/contrib/sb-sprof/test.lisp index e9cdc463d9..cb3fbef484 100644 --- a/contrib/sb-sprof/test.lisp +++ b/contrib/sb-sprof/test.lisp @@ -43,13 +43,52 @@ while (< (get-universal-time) target) do (consalot)))) +;; This has been failing on Sparc/SunOS for a while, +;; having nothing to do with the rewrite of sprof's +;; data collector into C. Maybe it works on Linux +;; but the less fuss about Sparc, the better. +#+sparc (defun run-tests () t) + +(defvar *compiler-input* "../contrib/sb-sprof/graph.lisp") +(defvar *compiler-output* "./foo.fasl") +(defvar *sprof-loop-test-max-samples* 50) + +#-sparc (defun run-tests () + (proclaim '(sb-ext:muffle-conditions style-warning)) + (sb-sprof:with-profiling (:max-samples *sprof-loop-test-max-samples* + :report :flat :loop t :show-progress t) + ;; Notice that "./foo.fasl" writes into this directory, whereas simply "foo.fasl" + ;; would write into "../../src/code/" + ;; Notice also that our file I/O routines are so crappy that 15% of the test + ;; is spent in lseek, and 12% in write. Just wow! + ;; Self Total Cumul + ;; Nr Count % Count % Count % Calls Function + ;; ------------------------------------------------------------------------ + ;; 1 15 15.0 15 15.0 15 15.0 - foreign function __lseek + ;; 2 12 12.0 12 12.0 27 27.0 - foreign function write + ;; 3 7 7.0 7 7.0 34 34.0 - foreign function __pthread_sigmask + + ;; + (compile-file *compiler-input* :output-file *compiler-output* :print nil)) + (delete-file *compiler-output*) (let ((*standard-output* (make-broadcast-stream))) (test) - (consing-test))) - -;; For debugging purposes, print output for visual inspection to see if -;; the allocation sequence gets hit in the right places (i.e. not at all -;; in traditional builds, and everywhere if SB-SAFEPOINT-STRICTLY is -;; enabled.) -#+nil (disassemble #'consalot) + (consing-test) + ;; This test shows that STOP-SAMPLING and START-SAMPLING on a thread do something. + ;; Based on rev b6bf65d9 it would seem that the API got broken a little. + ;; The thread doesn't do a whole lot, which is fine for what it is. + #+sb-thread + (let* ((sem (sb-thread:make-semaphore)) + (some-thread (sb-thread:make-thread #'sb-thread:wait-on-semaphore :arguments sem + :name "donothing"))) + (sb-sprof:stop-sampling some-thread) + (sb-sprof:start-sampling some-thread) + (sb-thread:signal-semaphore sem) + ;; Join because when run by run-tests.sh, it's an error to have random leftover threads + (sb-thread:join-thread some-thread)) + ;; For debugging purposes, print output for visual inspection to see where + ;; the allocation sequence gets hit. + ;; It can be interrupted even inside pseudo-atomic now. + (disassemble #'consalot :stream *error-output*)) + t) diff --git a/cross-make.sh b/cross-make.sh index 09b21e4fcf..48d754b6a6 100755 --- a/cross-make.sh +++ b/cross-make.sh @@ -50,7 +50,9 @@ mv build-id.inc output # make-host-1 and copy the generated C headers to the target machine sh make-host-1.sh -tar cf - src/runtime/genesis | ssh $ssh_port_opt $host cd $root \; tar xf - +# workaround small amounts of clock skew by using --touch on the extraction +# You'll probably have to remove the --touch when building for SunOS +tar cf - src/runtime/genesis | ssh $ssh_port_opt $host cd $root \; tar xf - --touch # make-target-1 and copy back the artifacts ssh $ssh_port_opt $host cd $root \; $ENV sh make-target-1.sh diff --git a/crossbuild-runner/Makefile b/crossbuild-runner/Makefile new file mode 100644 index 0000000000..2a2fcb42ee --- /dev/null +++ b/crossbuild-runner/Makefile @@ -0,0 +1,53 @@ +all: output/arm.core output/arm64.core output/mips.core output/ppc.core output/ppc64.core \ + output/riscv.core output/sparc.core output/x86.core output/x86-64.core + +SBCL=src/runtime/sbcl +ARGS=--core output/sbcl.core --noinform --disable-debugger --noprint --no-userinit --no-sysinit +SCRIPT1=crossbuild-runner/pass-1.lisp +SCRIPT2=crossbuild-runner/pass-2.lisp +DEPS1=crossbuild-runner/pass-1.lisp src/cold/build-order.lisp-expr # FIXME: and all the sources, of course + +obj/xbuild/arm/xc.core: $(DEPS1) + $(SBCL) $(ARGS) arm < $(SCRIPT1) +output/arm.core: obj/xbuild/arm/xc.core + $(SBCL) $(ARGS) arm < $(SCRIPT2) + +obj/xbuild/arm64/xc.core: $(DEPS1) + $(SBCL) $(ARGS) arm64 < $(SCRIPT1) +output/arm64.core: obj/xbuild/arm64/xc.core + $(SBCL) $(ARGS) arm64 < $(SCRIPT2) + +obj/xbuild/mips/xc.core: $(DEPS1) + $(SBCL) $(ARGS) mips < $(SCRIPT1) +output/mips.core: obj/xbuild/mips/xc.core + $(SBCL) $(ARGS) mips < $(SCRIPT2) + +obj/xbuild/ppc/xc.core: $(DEPS1) + $(SBCL) $(ARGS) ppc < $(SCRIPT1) +output/ppc.core: obj/xbuild/ppc/xc.core + $(SBCL) $(ARGS) ppc < $(SCRIPT2) + +obj/xbuild/ppc64/xc.core: $(DEPS1) + $(SBCL) $(ARGS) ppc64 < $(SCRIPT1) +output/ppc64.core: obj/xbuild/ppc64/xc.core + $(SBCL) $(ARGS) ppc64 < $(SCRIPT2) + +obj/xbuild/riscv/xc.core: $(DEPS1) + $(SBCL) $(ARGS) riscv < $(SCRIPT1) +output/riscv.core: obj/xbuild/riscv/xc.core + $(SBCL) $(ARGS) riscv < $(SCRIPT2) + +obj/xbuild/sparc/xc.core: $(DEPS1) + $(SBCL) $(ARGS) sparc < $(SCRIPT1) +output/sparc.core: obj/xbuild/sparc/xc.core + $(SBCL) $(ARGS) sparc < $(SCRIPT2) + +obj/xbuild/x86/xc.core: $(DEPS1) + $(SBCL) $(ARGS) x86 < $(SCRIPT1) +output/x86.core: obj/xbuild/x86/xc.core + $(SBCL) $(ARGS) x86 < $(SCRIPT2) + +obj/xbuild/x86-64/xc.core: $(DEPS1) + $(SBCL) $(ARGS) x86-64 < $(SCRIPT1) +output/x86-64.core: obj/xbuild/x86-64/xc.core + $(SBCL) $(ARGS) x86-64 < $(SCRIPT2) diff --git a/crossbuild-runner/backends/alpha/local-target-features b/crossbuild-runner/backends/alpha/local-target-features deleted file mode 100644 index be10fec468..0000000000 --- a/crossbuild-runner/backends/alpha/local-target-features +++ /dev/null @@ -1 +0,0 @@ -:alpha :unix :elf :linux :cheneygc :64-bit-registers :stack-allocatable-closures :stack-allocatable-lists :stack-allocatable-fixed-objects :little-endian diff --git a/crossbuild-runner/backends/alpha/stuff-groveled-from-headers.lisp b/crossbuild-runner/backends/alpha/stuff-groveled-from-headers.lisp deleted file mode 100644 index a9b090bf21..0000000000 --- a/crossbuild-runner/backends/alpha/stuff-groveled-from-headers.lisp +++ /dev/null @@ -1,145 +0,0 @@ -;;;; This is an automatically generated file, please do not hand-edit it. -;;;; See the program "grovel-headers.c". - -(in-package "SB-ALIEN") - -;;;flags for dlopen() -(defconstant rtld-lazy 1) ; #x1 -(defconstant rtld-now 2) ; #x2 -(defconstant rtld-global 256) ; #x100 -(in-package "SB-UNIX") - -;;; select() -(defconstant fd-setsize 1024) ; #x400 -;;; poll() -(defconstant pollin 1) ; #x1 -(defconstant pollout 4) ; #x4 -(defconstant pollpri 2) ; #x2 -(defconstant pollhup 16) ; #x10 -(defconstant pollnval 32) ; #x20 -(defconstant pollerr 8) ; #x8 -(define-alien-type nfds-t (unsigned 64)) -;;; langinfo -(defconstant codeset 14) ; #xe -;;; types, types, types -(define-alien-type clock-t (signed 64)) -(define-alien-type dev-t (unsigned 64)) -(define-alien-type gid-t (unsigned 32)) -(define-alien-type ino-t (unsigned 32)) -(define-alien-type mode-t (unsigned 32)) -(define-alien-type nlink-t (unsigned 32)) -(define-alien-type off-t (signed 64)) -(define-alien-type size-t (unsigned 64)) -(define-alien-type time-t (signed 64)) -(define-alien-type suseconds-t (signed 64)) -(define-alien-type uid-t (unsigned 32)) -;; Types in src/runtime/wrap.h. See that file for explantion. -;; Don't use these types for anything other than the stat wrapper. -(define-alien-type wst-ino-t (unsigned 32)) -(define-alien-type wst-dev-t (unsigned 32)) -(define-alien-type wst-off-t (unsigned 32)) -(define-alien-type wst-blksize-t (unsigned 64)) -(define-alien-type wst-blkcnt-t (unsigned 64)) -(define-alien-type wst-nlink-t (unsigned 32)) -(define-alien-type wst-uid-t (unsigned 32)) -(define-alien-type wst-gid-t (unsigned 32)) - -;;; fcntl.h (or unistd.h on OpenBSD and NetBSD) -(defconstant r_ok 4) ; #x4 -(defconstant w_ok 2) ; #x2 -(defconstant x_ok 1) ; #x1 -(defconstant f_ok 0) ; #x0 - -;;; fcntlbits.h -(defconstant o_rdonly 0) ; #x0 -(defconstant o_wronly 1) ; #x1 -(defconstant o_rdwr 2) ; #x2 -(defconstant o_accmode 3) ; #x3 -(defconstant o_creat 512) ; #x200 -(defconstant o_excl 2048) ; #x800 -(defconstant o_noctty 4096) ; #x1000 -(defconstant o_trunc 1024) ; #x400 -(defconstant o_append 8) ; #x8 -;;; -(defconstant s-ifmt 61440) ; #xf000 -(defconstant s-ififo 4096) ; #x1000 -(defconstant s-ifchr 8192) ; #x2000 -(defconstant s-ifdir 16384) ; #x4000 -(defconstant s-ifblk 24576) ; #x6000 -(defconstant s-ifreg 32768) ; #x8000 - -(defconstant s-iflnk 40960) ; #xa000 -(defconstant s-ifsock 49152) ; #xc000 - -;;; error numbers -(defconstant ebadf 9) ; #x9 -(defconstant enoent 2) ; #x2 -(defconstant eintr 4) ; #x4 -(defconstant eagain 35) ; #x23 -(defconstant eio 5) ; #x5 -(defconstant eexist 17) ; #x11 -(defconstant eloop 62) ; #x3e -(defconstant espipe 29) ; #x1d -(defconstant epipe 32) ; #x20 -(defconstant ewouldblock 35) ; #x23 - -;;; for waitpid() in run-program.lisp -(defconstant wnohang 1) ; #x1 -(defconstant wuntraced 2) ; #x2 - -;;; various ioctl(2) flags -(defconstant tiocgpgrp 1074033783) ; #x40047477 - -;;; signals -(defconstant sigalrm 14) ; #xe -(defconstant sigbus 10) ; #xa -(defconstant sigchld 20) ; #x14 -(defconstant sigcont 19) ; #x13 -(defconstant sigemt 7) ; #x7 -(defconstant sigfpe 8) ; #x8 -(defconstant sighup 1) ; #x1 -(defconstant sigill 4) ; #x4 -(defconstant sigint 2) ; #x2 -(defconstant sigio 23) ; #x17 -(defconstant sigkill 9) ; #x9 -(defconstant sigpipe 13) ; #xd -(defconstant sigprof 27) ; #x1b -(defconstant sigquit 3) ; #x3 -(defconstant sigsegv 11) ; #xb -(defconstant sigstop 17) ; #x11 -(defconstant sigsys 12) ; #xc -(defconstant sigterm 15) ; #xf -(defconstant sigtrap 5) ; #x5 -(defconstant sigtstp 18) ; #x12 -(defconstant sigttin 21) ; #x15 -(defconstant sigttou 22) ; #x16 -(defconstant sigurg 16) ; #x10 -(defconstant sigusr1 30) ; #x1e -(defconstant sigusr2 31) ; #x1f -(defconstant sigvtalrm 26) ; #x1a -(defconstant sigwinch 28) ; #x1c -(defconstant sigxcpu 24) ; #x18 -(defconstant sigxfsz 25) ; #x19 -(defconstant fpe-intovf 2) ; #x2 -(defconstant fpe-intdiv 1) ; #x1 -(defconstant fpe-fltdiv 3) ; #x3 -(defconstant fpe-fltovf 4) ; #x4 -(defconstant fpe-fltund 5) ; #x5 -(defconstant fpe-fltres 6) ; #x6 -(defconstant fpe-fltinv 7) ; #x7 -(defconstant fpe-fltsub 8) ; #x8 - -;;; structures -(define-alien-type nil - (struct timeval - (tv-sec (signed 64)) - (tv-usec (signed 64)))) -(define-alien-type nil - (struct timespec - (tv-sec (signed 64)) - (tv-nsec (signed 64)))) - -(in-package "SB-KERNEL") - -;;; Our runtime types -(define-alien-type os-vm-size-t (unsigned 64)) diff --git a/crossbuild-runner/backends/arm/features b/crossbuild-runner/backends/arm/features new file mode 100644 index 0000000000..b3f2c53976 --- /dev/null +++ b/crossbuild-runner/backends/arm/features @@ -0,0 +1,6 @@ +:gencgc :alien-callbacks +; As opposed to soft-float or FPA, we support VFP only (and +; possibly VFPv2 and higher only), but we'll leave the obvious +; hooks in for someone to add the support later. +:arm-vfp :arm-vfpv2 +:fp-and-pc-standard-save diff --git a/crossbuild-runner/backends/arm/local-target-features b/crossbuild-runner/backends/arm/local-target-features index a31aadeebd..83d8430266 100644 --- a/crossbuild-runner/backends/arm/local-target-features +++ b/crossbuild-runner/backends/arm/local-target-features @@ -1 +1 @@ -:arm :unix :elf :linux :largefile :gencgc :linkage-table :alien-callbacks :arm-vfp :arm-vfpv2 :stack-allocatable-lists :stack-allocatable-fixed-objects :stack-allocatable-vectors :stack-allocatable-closures :unwind-to-frame-and-call-vop :fp-and-pc-standard-save :little-endian :arm-softfp +:little-endian :gencgc :largefile diff --git a/crossbuild-runner/backends/arm/stuff-groveled-from-headers.lisp b/crossbuild-runner/backends/arm/stuff-groveled-from-headers.lisp index 4d4e007b4b..b620791895 100644 --- a/crossbuild-runner/backends/arm/stuff-groveled-from-headers.lisp +++ b/crossbuild-runner/backends/arm/stuff-groveled-from-headers.lisp @@ -7,6 +7,7 @@ (defconstant rtld-lazy 1) ; #x1 (defconstant rtld-now 2) ; #x2 (defconstant rtld-global 256) ; #x100 + (in-package "SB-UNIX") ;;; select() @@ -19,8 +20,6 @@ (defconstant pollnval 32) ; #x20 (defconstant pollerr 8) ; #x8 (define-alien-type nfds-t (unsigned 32)) -;;; langinfo -(defconstant codeset 14) ; #xe ;;; types, types, types (define-alien-type clock-t (signed 32)) (define-alien-type dev-t (unsigned 64)) @@ -30,6 +29,7 @@ (define-alien-type nlink-t (unsigned 32)) (define-alien-type off-t (signed 64)) (define-alien-type size-t (unsigned 32)) +(define-alien-type ssize-t (signed 32)) (define-alien-type time-t (signed 32)) (define-alien-type suseconds-t (signed 32)) (define-alien-type uid-t (unsigned 32)) @@ -80,11 +80,13 @@ (defconstant eio 5) ; #x5 (defconstant eexist 17) ; #x11 (defconstant eloop 40) ; #x28 -(defconstant espipe 29) ; #x1d (defconstant epipe 32) ; #x20 +(defconstant espipe 29) ; #x1d (defconstant ewouldblock 11) ; #xb +(defconstant sc-nprocessors-onln 84) ; #x54 ;;; for waitpid() in run-program.lisp +(defconstant wcontinued 8) ; #x8 (defconstant wnohang 1) ; #x1 (defconstant wuntraced 2) ; #x2 @@ -92,6 +94,10 @@ (defconstant tiocgpgrp 21519) ; #x540f ;;; signals +(defconstant sizeof-sigset_t 128) ; #x80 +(defconstant sig_block 0) ; #x0 +(defconstant sig_unblock 1) ; #x1 +(defconstant sig_setmask 2) ; #x2 (defconstant sigalrm 14) ; #xe (defconstant sigbus 7) ; #x7 (defconstant sigchld 17) ; #x11 @@ -130,6 +136,16 @@ (defconstant fpe-fltinv 7) ; #x7 (defconstant fpe-fltsub 8) ; #x8 +(defconstant clock-realtime 0) ; #x0 +(defconstant clock-monotonic 1) ; #x1 +(defconstant clock-process-cputime-id 2) ; #x2 +(defconstant clock-realtime-alarm 8) ; #x8 +(defconstant clock-realtime-coarse 5) ; #x5 +(defconstant clock-monotonic-coarse 6) ; #x6 +(defconstant clock-monotonic-raw 4) ; #x4 +(defconstant clock-boottime 7) ; #x7 +(defconstant clock-boottime-alarn 9) ; #x9 +(defconstant clock-thread-cputime-id 3) ; #x3 ;;; structures (define-alien-type nil (struct timeval diff --git a/crossbuild-runner/backends/arm64/features b/crossbuild-runner/backends/arm64/features new file mode 100644 index 0000000000..b88d81ae94 --- /dev/null +++ b/crossbuild-runner/backends/arm64/features @@ -0,0 +1,8 @@ +:64-bit :gencgc :fp-and-pc-standard-save +:use-cons-region +:alien-callbacks +:unbind-in-unwind +:compare-and-swap-vops :undefined-fun-restarts +:unwind-to-frame-and-call-vop +:call-symbol +:no-continue-unwind diff --git a/crossbuild-runner/backends/arm64/local-target-features b/crossbuild-runner/backends/arm64/local-target-features index 944c378ce1..93ce7690c1 100644 --- a/crossbuild-runner/backends/arm64/local-target-features +++ b/crossbuild-runner/backends/arm64/local-target-features @@ -1 +1 @@ -:arm64 :unix :elf :linux :sb-futex :64-bit :gencgc :linkage-table :fp-and-pc-standard-save :alien-callbacks :stack-allocatable-lists :stack-allocatable-fixed-objects :stack-allocatable-vectors :stack-allocatable-closures :compare-and-swap-vops :little-endian :unbind-in-unwind :sb-thread +:little-endian :sb-thread :darwin-jit diff --git a/crossbuild-runner/backends/arm64/stuff-groveled-from-headers.lisp b/crossbuild-runner/backends/arm64/stuff-groveled-from-headers.lisp index 11a332448c..1957f5f12e 100644 --- a/crossbuild-runner/backends/arm64/stuff-groveled-from-headers.lisp +++ b/crossbuild-runner/backends/arm64/stuff-groveled-from-headers.lisp @@ -7,6 +7,7 @@ (defconstant rtld-lazy 1) ; #x1 (defconstant rtld-now 2) ; #x2 (defconstant rtld-global 256) ; #x100 + (in-package "SB-UNIX") ;;; select() @@ -19,8 +20,6 @@ (defconstant pollnval 32) ; #x20 (defconstant pollerr 8) ; #x8 (define-alien-type nfds-t (unsigned 64)) -;;; langinfo -(defconstant codeset 14) ; #xe ;;; types, types, types (define-alien-type clock-t (signed 64)) (define-alien-type dev-t (unsigned 64)) @@ -30,6 +29,7 @@ (define-alien-type nlink-t (unsigned 32)) (define-alien-type off-t (signed 64)) (define-alien-type size-t (unsigned 64)) +(define-alien-type ssize-t (signed 64)) (define-alien-type time-t (signed 64)) (define-alien-type suseconds-t (signed 64)) (define-alien-type uid-t (unsigned 32)) @@ -79,11 +79,13 @@ (defconstant eio 5) ; #x5 (defconstant eexist 17) ; #x11 (defconstant eloop 40) ; #x28 -(defconstant espipe 29) ; #x1d (defconstant epipe 32) ; #x20 +(defconstant espipe 29) ; #x1d (defconstant ewouldblock 11) ; #xb +(defconstant sc-nprocessors-onln 84) ; #x54 ;;; for waitpid() in run-program.lisp +(defconstant wcontinued 8) ; #x8 (defconstant wnohang 1) ; #x1 (defconstant wuntraced 2) ; #x2 @@ -91,6 +93,10 @@ (defconstant tiocgpgrp 21519) ; #x540f ;;; signals +(defconstant sizeof-sigset_t 128) ; #x80 +(defconstant sig_block 0) ; #x0 +(defconstant sig_unblock 1) ; #x1 +(defconstant sig_setmask 2) ; #x2 (defconstant sigalrm 14) ; #xe (defconstant sigbus 7) ; #x7 (defconstant sigchld 17) ; #x11 @@ -129,6 +135,16 @@ (defconstant fpe-fltinv 7) ; #x7 (defconstant fpe-fltsub 8) ; #x8 +(defconstant clock-realtime 0) ; #x0 +(defconstant clock-monotonic 1) ; #x1 +(defconstant clock-process-cputime-id 2) ; #x2 +(defconstant clock-realtime-alarm 8) ; #x8 +(defconstant clock-realtime-coarse 5) ; #x5 +(defconstant clock-monotonic-coarse 6) ; #x6 +(defconstant clock-monotonic-raw 4) ; #x4 +(defconstant clock-boottime 7) ; #x7 +(defconstant clock-boottime-alarn 9) ; #x9 +(defconstant clock-thread-cputime-id 3) ; #x3 ;;; structures (define-alien-type nil (struct timeval diff --git a/crossbuild-runner/backends/hppa/local-target-features b/crossbuild-runner/backends/hppa/local-target-features deleted file mode 100644 index 4a5214ff6b..0000000000 --- a/crossbuild-runner/backends/hppa/local-target-features +++ /dev/null @@ -1 +0,0 @@ -:hppa :unix :elf :linux :cheneygc :stack-allocatable-vectors :stack-allocatable-fixed-objects :stack-allocatable-closures :stack-allocatable-lists :big-endian diff --git a/crossbuild-runner/backends/hppa/stuff-groveled-from-headers.lisp b/crossbuild-runner/backends/hppa/stuff-groveled-from-headers.lisp deleted file mode 100644 index 44d961cfbf..0000000000 --- a/crossbuild-runner/backends/hppa/stuff-groveled-from-headers.lisp +++ /dev/null @@ -1,146 +0,0 @@ -;;;; This is an automatically generated file, please do not hand-edit it. -;;;; See the program "grovel-headers.c". - -(in-package "SB-ALIEN") - -;;;flags for dlopen() -(defconstant rtld-lazy 1) ; #x1 -(defconstant rtld-now 2) ; #x2 -(defconstant rtld-global 4) ; #x4 -(in-package "SB-UNIX") - -;;; select() -(defconstant fd-setsize 1024) ; #x400 -;;; poll() -(defconstant pollin 1) ; #x1 -(defconstant pollout 4) ; #x4 -(defconstant pollpri 2) ; #x2 -(defconstant pollhup 16) ; #x10 -(defconstant pollnval 32) ; #x20 -(defconstant pollerr 8) ; #x8 -(define-alien-type nfds-t (unsigned 32)) -;;; langinfo -(defconstant codeset 14) ; #xe -;;; types, types, types -(define-alien-type clock-t (signed 32)) -(define-alien-type dev-t (unsigned 64)) -(define-alien-type gid-t (unsigned 32)) -(define-alien-type ino-t (unsigned 64)) -(define-alien-type mode-t (unsigned 32)) -(define-alien-type nlink-t (unsigned 32)) -(define-alien-type off-t (signed 64)) -(define-alien-type size-t (unsigned 32)) -(define-alien-type time-t (signed 32)) -(define-alien-type suseconds-t (signed 32)) -(define-alien-type uid-t (unsigned 32)) -;; Types in src/runtime/wrap.h. See that file for explantion. -;; Don't use these types for anything other than the stat wrapper. -(define-alien-type wst-ino-t (unsigned 64)) -(define-alien-type wst-dev-t (unsigned 32)) -(define-alien-type wst-off-t (signed 64)) -(define-alien-type wst-blksize-t (signed 32)) -(define-alien-type wst-blkcnt-t (signed 64)) -(define-alien-type wst-nlink-t (unsigned 32)) -(define-alien-type wst-uid-t (unsigned 32)) -(define-alien-type wst-gid-t (unsigned 32)) - -;;; fcntl.h (or unistd.h on OpenBSD and NetBSD) -(defconstant r_ok 4) ; #x4 -(defconstant w_ok 2) ; #x2 -(defconstant x_ok 1) ; #x1 -(defconstant f_ok 0) ; #x0 - -;;; fcntlbits.h -(defconstant o_rdonly 0) ; #x0 -(defconstant o_wronly 1) ; #x1 -(defconstant o_rdwr 2) ; #x2 -(defconstant o_accmode 3) ; #x3 -(defconstant o_creat 256) ; #x100 -(defconstant o_excl 1024) ; #x400 -(defconstant o_noctty 2048) ; #x800 -(defconstant o_trunc 512) ; #x200 -(defconstant o_append 8) ; #x8 -(defconstant o_largefile 8192) ; #x2000 -;;; -(defconstant s-ifmt 61440) ; #xf000 -(defconstant s-ififo 4096) ; #x1000 -(defconstant s-ifchr 8192) ; #x2000 -(defconstant s-ifdir 16384) ; #x4000 -(defconstant s-ifblk 24576) ; #x6000 -(defconstant s-ifreg 32768) ; #x8000 - -(defconstant s-iflnk 40960) ; #xa000 -(defconstant s-ifsock 49152) ; #xc000 - -;;; error numbers -(defconstant ebadf 9) ; #x9 -(defconstant enoent 2) ; #x2 -(defconstant eintr 4) ; #x4 -(defconstant eagain 11) ; #xb -(defconstant eio 5) ; #x5 -(defconstant eexist 17) ; #x11 -(defconstant eloop 90) ; #x5a -(defconstant espipe 29) ; #x1d -(defconstant epipe 32) ; #x20 -(defconstant ewouldblock 11) ; #xb - -;;; for waitpid() in run-program.lisp -(defconstant wnohang 1) ; #x1 -(defconstant wuntraced 2) ; #x2 - -;;; various ioctl(2) flags -(defconstant tiocgpgrp 1074033783) ; #x40047477 - -;;; signals -(defconstant sigalrm 14) ; #xe -(defconstant sigbus 10) ; #xa -(defconstant sigchld 18) ; #x12 -(defconstant sigcont 25) ; #x19 -(defconstant sigemt 7) ; #x7 -(defconstant sigfpe 8) ; #x8 -(defconstant sighup 1) ; #x1 -(defconstant sigill 4) ; #x4 -(defconstant sigint 2) ; #x2 -(defconstant sigio 22) ; #x16 -(defconstant sigkill 9) ; #x9 -(defconstant sigpipe 13) ; #xd -(defconstant sigprof 29) ; #x1d -(defconstant sigquit 3) ; #x3 -(defconstant sigsegv 11) ; #xb -(defconstant sigstop 23) ; #x17 -(defconstant sigsys 12) ; #xc -(defconstant sigterm 15) ; #xf -(defconstant sigtrap 5) ; #x5 -(defconstant sigtstp 24) ; #x18 -(defconstant sigttin 26) ; #x1a -(defconstant sigttou 27) ; #x1b -(defconstant sigurg 21) ; #x15 -(defconstant sigusr1 16) ; #x10 -(defconstant sigusr2 17) ; #x11 -(defconstant sigvtalrm 28) ; #x1c -(defconstant sigwinch 20) ; #x14 -(defconstant sigxcpu 30) ; #x1e -(defconstant sigxfsz 31) ; #x1f -(defconstant fpe-intovf 2) ; #x2 -(defconstant fpe-intdiv 1) ; #x1 -(defconstant fpe-fltdiv 3) ; #x3 -(defconstant fpe-fltovf 4) ; #x4 -(defconstant fpe-fltund 5) ; #x5 -(defconstant fpe-fltres 6) ; #x6 -(defconstant fpe-fltinv 7) ; #x7 -(defconstant fpe-fltsub 8) ; #x8 - -;;; structures -(define-alien-type nil - (struct timeval - (tv-sec (signed 32)) - (tv-usec (signed 32)))) -(define-alien-type nil - (struct timespec - (tv-sec (signed 32)) - (tv-nsec (signed 32)))) - -(in-package "SB-KERNEL") - -;;; Our runtime types -(define-alien-type os-vm-size-t (unsigned 32)) diff --git a/crossbuild-runner/backends/mips/features b/crossbuild-runner/backends/mips/features new file mode 100644 index 0000000000..d2360749c0 --- /dev/null +++ b/crossbuild-runner/backends/mips/features @@ -0,0 +1,2 @@ +:gencgc :use-cons-region :soft-card-marks +:alien-callbacks diff --git a/crossbuild-runner/backends/mips/local-target-features b/crossbuild-runner/backends/mips/local-target-features index ce6d666726..becae11c56 100644 --- a/crossbuild-runner/backends/mips/local-target-features +++ b/crossbuild-runner/backends/mips/local-target-features @@ -1 +1 @@ -:mips :unix :elf :linux :largefile :cheneygc :linkage-table :stack-allocatable-closures :stack-allocatable-vectors :stack-allocatable-lists :stack-allocatable-fixed-objects :alien-callbacks :little-endian +:largefile :little-endian diff --git a/crossbuild-runner/backends/mips/stuff-groveled-from-headers.lisp b/crossbuild-runner/backends/mips/stuff-groveled-from-headers.lisp index 44d961cfbf..b620791895 100644 --- a/crossbuild-runner/backends/mips/stuff-groveled-from-headers.lisp +++ b/crossbuild-runner/backends/mips/stuff-groveled-from-headers.lisp @@ -6,7 +6,8 @@ ;;;flags for dlopen() (defconstant rtld-lazy 1) ; #x1 (defconstant rtld-now 2) ; #x2 -(defconstant rtld-global 4) ; #x4 +(defconstant rtld-global 256) ; #x100 + (in-package "SB-UNIX") ;;; select() @@ -19,8 +20,6 @@ (defconstant pollnval 32) ; #x20 (defconstant pollerr 8) ; #x8 (define-alien-type nfds-t (unsigned 32)) -;;; langinfo -(defconstant codeset 14) ; #xe ;;; types, types, types (define-alien-type clock-t (signed 32)) (define-alien-type dev-t (unsigned 64)) @@ -30,13 +29,14 @@ (define-alien-type nlink-t (unsigned 32)) (define-alien-type off-t (signed 64)) (define-alien-type size-t (unsigned 32)) +(define-alien-type ssize-t (signed 32)) (define-alien-type time-t (signed 32)) (define-alien-type suseconds-t (signed 32)) (define-alien-type uid-t (unsigned 32)) ;; Types in src/runtime/wrap.h. See that file for explantion. ;; Don't use these types for anything other than the stat wrapper. (define-alien-type wst-ino-t (unsigned 64)) -(define-alien-type wst-dev-t (unsigned 32)) +(define-alien-type wst-dev-t (unsigned 64)) (define-alien-type wst-off-t (signed 64)) (define-alien-type wst-blksize-t (signed 32)) (define-alien-type wst-blkcnt-t (signed 64)) @@ -55,12 +55,12 @@ (defconstant o_wronly 1) ; #x1 (defconstant o_rdwr 2) ; #x2 (defconstant o_accmode 3) ; #x3 -(defconstant o_creat 256) ; #x100 -(defconstant o_excl 1024) ; #x400 -(defconstant o_noctty 2048) ; #x800 +(defconstant o_creat 64) ; #x40 +(defconstant o_excl 128) ; #x80 +(defconstant o_noctty 256) ; #x100 (defconstant o_trunc 512) ; #x200 -(defconstant o_append 8) ; #x8 -(defconstant o_largefile 8192) ; #x2000 +(defconstant o_append 1024) ; #x400 +(defconstant o_largefile 131072) ; #x20000 ;;; (defconstant s-ifmt 61440) ; #xf000 (defconstant s-ififo 4096) ; #x1000 @@ -79,48 +79,54 @@ (defconstant eagain 11) ; #xb (defconstant eio 5) ; #x5 (defconstant eexist 17) ; #x11 -(defconstant eloop 90) ; #x5a -(defconstant espipe 29) ; #x1d +(defconstant eloop 40) ; #x28 (defconstant epipe 32) ; #x20 +(defconstant espipe 29) ; #x1d (defconstant ewouldblock 11) ; #xb +(defconstant sc-nprocessors-onln 84) ; #x54 ;;; for waitpid() in run-program.lisp +(defconstant wcontinued 8) ; #x8 (defconstant wnohang 1) ; #x1 (defconstant wuntraced 2) ; #x2 ;;; various ioctl(2) flags -(defconstant tiocgpgrp 1074033783) ; #x40047477 +(defconstant tiocgpgrp 21519) ; #x540f ;;; signals +(defconstant sizeof-sigset_t 128) ; #x80 +(defconstant sig_block 0) ; #x0 +(defconstant sig_unblock 1) ; #x1 +(defconstant sig_setmask 2) ; #x2 (defconstant sigalrm 14) ; #xe -(defconstant sigbus 10) ; #xa -(defconstant sigchld 18) ; #x12 -(defconstant sigcont 25) ; #x19 -(defconstant sigemt 7) ; #x7 +(defconstant sigbus 7) ; #x7 +(defconstant sigchld 17) ; #x11 +(defconstant sigcont 18) ; #x12 (defconstant sigfpe 8) ; #x8 (defconstant sighup 1) ; #x1 (defconstant sigill 4) ; #x4 (defconstant sigint 2) ; #x2 -(defconstant sigio 22) ; #x16 +(defconstant sigio 29) ; #x1d (defconstant sigkill 9) ; #x9 (defconstant sigpipe 13) ; #xd -(defconstant sigprof 29) ; #x1d +(defconstant sigprof 27) ; #x1b (defconstant sigquit 3) ; #x3 (defconstant sigsegv 11) ; #xb -(defconstant sigstop 23) ; #x17 -(defconstant sigsys 12) ; #xc +(defconstant sigstkflt 16) ; #x10 +(defconstant sigstop 19) ; #x13 +(defconstant sigsys 31) ; #x1f (defconstant sigterm 15) ; #xf (defconstant sigtrap 5) ; #x5 -(defconstant sigtstp 24) ; #x18 -(defconstant sigttin 26) ; #x1a -(defconstant sigttou 27) ; #x1b -(defconstant sigurg 21) ; #x15 -(defconstant sigusr1 16) ; #x10 -(defconstant sigusr2 17) ; #x11 -(defconstant sigvtalrm 28) ; #x1c -(defconstant sigwinch 20) ; #x14 -(defconstant sigxcpu 30) ; #x1e -(defconstant sigxfsz 31) ; #x1f +(defconstant sigtstp 20) ; #x14 +(defconstant sigttin 21) ; #x15 +(defconstant sigttou 22) ; #x16 +(defconstant sigurg 23) ; #x17 +(defconstant sigusr1 10) ; #xa +(defconstant sigusr2 12) ; #xc +(defconstant sigvtalrm 26) ; #x1a +(defconstant sigwinch 28) ; #x1c +(defconstant sigxcpu 24) ; #x18 +(defconstant sigxfsz 25) ; #x19 (defconstant fpe-intovf 2) ; #x2 (defconstant fpe-intdiv 1) ; #x1 (defconstant fpe-fltdiv 3) ; #x3 @@ -130,6 +136,16 @@ (defconstant fpe-fltinv 7) ; #x7 (defconstant fpe-fltsub 8) ; #x8 +(defconstant clock-realtime 0) ; #x0 +(defconstant clock-monotonic 1) ; #x1 +(defconstant clock-process-cputime-id 2) ; #x2 +(defconstant clock-realtime-alarm 8) ; #x8 +(defconstant clock-realtime-coarse 5) ; #x5 +(defconstant clock-monotonic-coarse 6) ; #x6 +(defconstant clock-monotonic-raw 4) ; #x4 +(defconstant clock-boottime 7) ; #x7 +(defconstant clock-boottime-alarn 9) ; #x9 +(defconstant clock-thread-cputime-id 3) ; #x3 ;;; structures (define-alien-type nil (struct timeval @@ -142,5 +158,9 @@ (in-package "SB-KERNEL") +;;; GENCGC related +(define-alien-type page-index-t (signed 32)) +(define-alien-type generation-index-t (signed 8)) + ;;; Our runtime types (define-alien-type os-vm-size-t (unsigned 32)) diff --git a/crossbuild-runner/backends/ppc/features b/crossbuild-runner/backends/ppc/features new file mode 100644 index 0000000000..d183b010ff --- /dev/null +++ b/crossbuild-runner/backends/ppc/features @@ -0,0 +1,2 @@ +:gencgc +:compare-and-swap-vops :alien-callbacks diff --git a/crossbuild-runner/backends/ppc/local-target-features b/crossbuild-runner/backends/ppc/local-target-features index 21fed4e8b4..e9929965a3 100644 --- a/crossbuild-runner/backends/ppc/local-target-features +++ b/crossbuild-runner/backends/ppc/local-target-features @@ -1 +1 @@ -:ppc :unix :elf :linux :sb-futex :gencgc :stack-allocatable-closures :stack-allocatable-vectors :stack-allocatable-lists :stack-allocatable-fixed-objects :linkage-table :compare-and-swap-vops :alien-callbacks :big-endian :sb-thread +:gencgc :big-endian :sb-thread diff --git a/crossbuild-runner/backends/ppc/stuff-groveled-from-headers.lisp b/crossbuild-runner/backends/ppc/stuff-groveled-from-headers.lisp index 102042a919..21915bcf38 100644 --- a/crossbuild-runner/backends/ppc/stuff-groveled-from-headers.lisp +++ b/crossbuild-runner/backends/ppc/stuff-groveled-from-headers.lisp @@ -7,6 +7,7 @@ (defconstant rtld-lazy 1) ; #x1 (defconstant rtld-now 2) ; #x2 (defconstant rtld-global 256) ; #x100 + (in-package "SB-UNIX") ;;; select() @@ -19,8 +20,6 @@ (defconstant pollnval 32) ; #x20 (defconstant pollerr 8) ; #x8 (define-alien-type nfds-t (unsigned 32)) -;;; langinfo -(defconstant codeset 14) ; #xe ;;; types, types, types (define-alien-type clock-t (signed 32)) (define-alien-type dev-t (unsigned 64)) @@ -30,6 +29,7 @@ (define-alien-type nlink-t (unsigned 32)) (define-alien-type off-t (signed 32)) (define-alien-type size-t (unsigned 32)) +(define-alien-type ssize-t (signed 32)) (define-alien-type time-t (signed 32)) (define-alien-type suseconds-t (signed 32)) (define-alien-type uid-t (unsigned 32)) @@ -79,11 +79,13 @@ (defconstant eio 5) ; #x5 (defconstant eexist 17) ; #x11 (defconstant eloop 40) ; #x28 -(defconstant espipe 29) ; #x1d (defconstant epipe 32) ; #x20 +(defconstant espipe 29) ; #x1d (defconstant ewouldblock 11) ; #xb +(defconstant sc-nprocessors-onln 84) ; #x54 ;;; for waitpid() in run-program.lisp +(defconstant wcontinued 8) ; #x8 (defconstant wnohang 1) ; #x1 (defconstant wuntraced 2) ; #x2 @@ -91,6 +93,10 @@ (defconstant tiocgpgrp 1074033783) ; #x40047477 ;;; signals +(defconstant sizeof-sigset_t 128) ; #x80 +(defconstant sig_block 0) ; #x0 +(defconstant sig_unblock 1) ; #x1 +(defconstant sig_setmask 2) ; #x2 (defconstant sigalrm 14) ; #xe (defconstant sigbus 7) ; #x7 (defconstant sigchld 17) ; #x11 @@ -129,6 +135,17 @@ (defconstant fpe-fltinv 7) ; #x7 (defconstant fpe-fltsub 8) ; #x8 +(defconstant clock-realtime 0) ; #x0 +(defconstant clock-monotonic 1) ; #x1 +(defconstant clock-process-cputime-id 2) ; #x2 +(defconstant clock-realtime-alarm 8) ; #x8 +(defconstant clock-realtime-coarse 5) ; #x5 +(defconstant clock-tai 11) ; #xb +(defconstant clock-monotonic-coarse 6) ; #x6 +(defconstant clock-monotonic-raw 4) ; #x4 +(defconstant clock-boottime 7) ; #x7 +(defconstant clock-boottime-alarn 9) ; #x9 +(defconstant clock-thread-cputime-id 3) ; #x3 ;;; structures (define-alien-type nil (struct timeval diff --git a/crossbuild-runner/backends/ppc64/features b/crossbuild-runner/backends/ppc64/features new file mode 100644 index 0000000000..6742c14b09 --- /dev/null +++ b/crossbuild-runner/backends/ppc64/features @@ -0,0 +1,5 @@ +; threads are required because differing versions of the vops for BOUNDP +; and [fast-]symbol-[global-]value and CAS create extra maintenance burden. +:64-bit :untagged-fdefns :sb-thread :soft-card-marks +:gencgc +:compare-and-swap-vops :alien-callbacks diff --git a/crossbuild-runner/backends/ppc64/local-target-features b/crossbuild-runner/backends/ppc64/local-target-features index e20ea4db16..e9929965a3 100644 --- a/crossbuild-runner/backends/ppc64/local-target-features +++ b/crossbuild-runner/backends/ppc64/local-target-features @@ -1 +1 @@ -:ppc64 :unix :elf :linux :64-bit :gencgc :stack-allocatable-closures :stack-allocatable-vectors :stack-allocatable-lists :stack-allocatable-fixed-objects :linkage-table :compare-and-swap-vops :alien-callbacks :big-endian :sb-thread :sb-futex +:gencgc :big-endian :sb-thread diff --git a/crossbuild-runner/backends/ppc64/stuff-groveled-from-headers.lisp b/crossbuild-runner/backends/ppc64/stuff-groveled-from-headers.lisp index abbbeba0ce..62c686fc8b 100644 --- a/crossbuild-runner/backends/ppc64/stuff-groveled-from-headers.lisp +++ b/crossbuild-runner/backends/ppc64/stuff-groveled-from-headers.lisp @@ -7,6 +7,7 @@ (defconstant rtld-lazy 1) ; #x1 (defconstant rtld-now 2) ; #x2 (defconstant rtld-global 256) ; #x100 + (in-package "SB-UNIX") ;;; select() @@ -19,8 +20,6 @@ (defconstant pollnval 32) ; #x20 (defconstant pollerr 8) ; #x8 (define-alien-type nfds-t (unsigned 64)) -;;; langinfo -(defconstant codeset 14) ; #xe ;;; types, types, types (define-alien-type clock-t (signed 64)) (define-alien-type dev-t (unsigned 64)) @@ -80,8 +79,8 @@ (defconstant eio 5) ; #x5 (defconstant eexist 17) ; #x11 (defconstant eloop 40) ; #x28 -(defconstant espipe 29) ; #x1d (defconstant epipe 32) ; #x20 +(defconstant espipe 29) ; #x1d (defconstant ewouldblock 11) ; #xb (defconstant sc-nprocessors-onln 84) ; #x54 @@ -94,6 +93,10 @@ (defconstant tiocgpgrp 1074033783) ; #x40047477 ;;; signals +(defconstant sizeof-sigset_t 128) ; #x80 +(defconstant sig_block 0) ; #x0 +(defconstant sig_unblock 1) ; #x1 +(defconstant sig_setmask 2) ; #x2 (defconstant sigalrm 14) ; #xe (defconstant sigbus 7) ; #x7 (defconstant sigchld 17) ; #x11 @@ -132,6 +135,17 @@ (defconstant fpe-fltinv 7) ; #x7 (defconstant fpe-fltsub 8) ; #x8 +(defconstant clock-realtime 0) ; #x0 +(defconstant clock-monotonic 1) ; #x1 +(defconstant clock-process-cputime-id 2) ; #x2 +(defconstant clock-realtime-alarm 8) ; #x8 +(defconstant clock-realtime-coarse 5) ; #x5 +(defconstant clock-tai 11) ; #xb +(defconstant clock-monotonic-coarse 6) ; #x6 +(defconstant clock-monotonic-raw 4) ; #x4 +(defconstant clock-boottime 7) ; #x7 +(defconstant clock-boottime-alarn 9) ; #x9 +(defconstant clock-thread-cputime-id 3) ; #x3 ;;; structures (define-alien-type nil (struct timeval diff --git a/crossbuild-runner/backends/riscv/features b/crossbuild-runner/backends/riscv/features new file mode 100644 index 0000000000..f6d9eb7af0 --- /dev/null +++ b/crossbuild-runner/backends/riscv/features @@ -0,0 +1,2 @@ +:gencgc +:compare-and-swap-vops :memory-barrier-vops diff --git a/crossbuild-runner/backends/riscv/local-target-features b/crossbuild-runner/backends/riscv/local-target-features index 8b24ca7483..50631f0052 100644 --- a/crossbuild-runner/backends/riscv/local-target-features +++ b/crossbuild-runner/backends/riscv/local-target-features @@ -1 +1 @@ -:riscv :unix :elf :linux :64-bit :gencgc :stack-allocatable-closures :stack-allocatable-vectors :stack-allocatable-lists :stack-allocatable-fixed-objects :linkage-table :little-endian :compare-and-swap-vops :memory-barrier-vops :sb-thread +:64-bit :gencgc :little-endian :sb-thread diff --git a/crossbuild-runner/backends/riscv/stuff-groveled-from-headers.lisp b/crossbuild-runner/backends/riscv/stuff-groveled-from-headers.lisp index 8db562c693..465f1f0006 100644 --- a/crossbuild-runner/backends/riscv/stuff-groveled-from-headers.lisp +++ b/crossbuild-runner/backends/riscv/stuff-groveled-from-headers.lisp @@ -7,6 +7,7 @@ (defconstant rtld-lazy 1) ; #x1 (defconstant rtld-now 2) ; #x2 (defconstant rtld-global 256) ; #x100 + (in-package "SB-UNIX") ;;; select() @@ -19,8 +20,6 @@ (defconstant pollnval 32) ; #x20 (defconstant pollerr 8) ; #x8 (define-alien-type nfds-t (unsigned 64)) -;;; langinfo -(defconstant codeset 14) ; #xe ;;; types, types, types (define-alien-type clock-t (signed 64)) (define-alien-type dev-t (unsigned 64)) @@ -94,6 +93,10 @@ (defconstant tiocgpgrp 21519) ; #x540f ;;; signals +(defconstant sizeof-sigset_t 128) ; #x80 +(defconstant sig_block 0) ; #x0 +(defconstant sig_unblock 1) ; #x1 +(defconstant sig_setmask 2) ; #x2 (defconstant sigalrm 14) ; #xe (defconstant sigbus 7) ; #x7 (defconstant sigchld 17) ; #x11 @@ -132,6 +135,17 @@ (defconstant fpe-fltinv 7) ; #x7 (defconstant fpe-fltsub 8) ; #x8 +(defconstant clock-realtime 0) ; #x0 +(defconstant clock-monotonic 1) ; #x1 +(defconstant clock-process-cputime-id 2) ; #x2 +(defconstant clock-realtime-alarm 8) ; #x8 +(defconstant clock-realtime-coarse 5) ; #x5 +(defconstant clock-tai 11) ; #xb +(defconstant clock-monotonic-coarse 6) ; #x6 +(defconstant clock-monotonic-raw 4) ; #x4 +(defconstant clock-boottime 7) ; #x7 +(defconstant clock-boottime-alarn 9) ; #x9 +(defconstant clock-thread-cputime-id 3) ; #x3 ;;; structures (define-alien-type nil (struct timeval diff --git a/crossbuild-runner/backends/sparc/features b/crossbuild-runner/backends/sparc/features new file mode 100644 index 0000000000..0e82d75421 --- /dev/null +++ b/crossbuild-runner/backends/sparc/features @@ -0,0 +1 @@ +:gencgc diff --git a/crossbuild-runner/backends/sparc/local-target-features b/crossbuild-runner/backends/sparc/local-target-features index 6659798762..311599926c 100644 --- a/crossbuild-runner/backends/sparc/local-target-features +++ b/crossbuild-runner/backends/sparc/local-target-features @@ -1 +1 @@ -:sparc :unix :elf :linux :gencgc :linkage-table :stack-allocatable-closures :stack-allocatable-lists :big-endian +:gencgc :big-endian diff --git a/crossbuild-runner/backends/sparc/stuff-groveled-from-headers.lisp b/crossbuild-runner/backends/sparc/stuff-groveled-from-headers.lisp index 4092624b27..4d96c2e81e 100644 --- a/crossbuild-runner/backends/sparc/stuff-groveled-from-headers.lisp +++ b/crossbuild-runner/backends/sparc/stuff-groveled-from-headers.lisp @@ -91,6 +91,9 @@ (defconstant tiocgpgrp 1074033795) ; #x40047483 ;;; signals +(defconstant sizeof-sigset_t 128) ; #x80 +(defconstant sig_setmask 2) ; #x2 +(defconstant sig_unblock 2) ; #x2 (defconstant sigalrm 14) ; #xe (defconstant sigbus 10) ; #xa (defconstant sigchld 20) ; #x14 @@ -129,6 +132,10 @@ (defconstant fpe-fltinv 7) ; #x7 (defconstant fpe-fltsub 8) ; #x8 +(defconstant clock-process-cputime-id 2) ; #x2 +(defconstant clock-monotonic-coarse 6) ; #x6 +(defconstant clock-thread-cputime-id 3) ; #x3 + ;;; structures (define-alien-type nil (struct timeval @@ -147,3 +154,4 @@ ;;; Our runtime types (define-alien-type os-vm-size-t (unsigned 32)) + diff --git a/crossbuild-runner/backends/x86-64/features b/crossbuild-runner/backends/x86-64/features new file mode 100644 index 0000000000..577d167878 --- /dev/null +++ b/crossbuild-runner/backends/x86-64/features @@ -0,0 +1,16 @@ +:64-bit +:gencgc +:use-cons-region +:soft-card-marks +:stack-grows-downward-not-upward +:c-stack-is-control-stack +:compare-and-swap-vops +:unwind-to-frame-and-call-vop +:fp-and-pc-standard-save +:alien-callbacks +:cycle-counter +:integer-eql-vop +:undefined-fun-restarts +:call-symbol +:unbind-in-unwind +:no-continue-unwind diff --git a/crossbuild-runner/backends/x86-64/local-target-features b/crossbuild-runner/backends/x86-64/local-target-features index c3fd07ee6d..c74b076b9f 100644 --- a/crossbuild-runner/backends/x86-64/local-target-features +++ b/crossbuild-runner/backends/x86-64/local-target-features @@ -1 +1 @@ -:x86-64 :win32 :avx2 :sb-safepoint :sb-thruption :sb-wtimer :sb-safepoint-strictly :sb-futex :64-bit :gencgc :stack-grows-downward-not-upward :c-stack-is-control-stack :linkage-table :compare-and-swap-vops :unwind-to-frame-and-call-vop :fp-and-pc-standard-save :stack-allocatable-closures :stack-allocatable-vectors :stack-allocatable-lists :stack-allocatable-fixed-objects :alien-callbacks :cycle-counter :integer-eql-vop :sb-simd-pack :sb-simd-pack-256 :little-endian :sb-thread :call-symbol :unbind-in-unwind :no-continue-unwind +:avx2 :gencgc :sb-simd-pack :sb-simd-pack-256 :little-endian diff --git a/crossbuild-runner/backends/x86-64/stuff-groveled-from-headers.lisp b/crossbuild-runner/backends/x86-64/stuff-groveled-from-headers.lisp index 5a516598df..9b9161566c 100644 --- a/crossbuild-runner/backends/x86-64/stuff-groveled-from-headers.lisp +++ b/crossbuild-runner/backends/x86-64/stuff-groveled-from-headers.lisp @@ -14,6 +14,7 @@ (defconstant max_path 1024) (defconstant error-no-data 1) (defconstant +exception-maximum-parameters+ 6) +(defconstant +exception-heap-corruption+ #xdeadbeef) ; random (in-package "SB-ALIEN") diff --git a/crossbuild-runner/backends/x86/features b/crossbuild-runner/backends/x86/features new file mode 100644 index 0000000000..019bfbdd9e --- /dev/null +++ b/crossbuild-runner/backends/x86/features @@ -0,0 +1,8 @@ +:gencgc +:stack-grows-downward-not-upward +:c-stack-is-control-stack +:compare-and-swap-vops +:unwind-to-frame-and-call-vop +:alien-callbacks +:cycle-counter +:fp-and-pc-standard-save diff --git a/crossbuild-runner/backends/x86/local-target-features b/crossbuild-runner/backends/x86/local-target-features index 5d451765f2..c14981c5bc 100644 --- a/crossbuild-runner/backends/x86/local-target-features +++ b/crossbuild-runner/backends/x86/local-target-features @@ -1 +1 @@ -:sb-thread :x86 :unix :elf :linux :sb-futex :largefile :gencgc :stack-grows-downward-not-upward :c-stack-is-control-stack :compare-and-swap-vops :unwind-to-frame-and-call-vop :stack-allocatable-closures :stack-allocatable-vectors :stack-allocatable-lists :stack-allocatable-fixed-objects :alien-callbacks :cycle-counter :fp-and-pc-standard-save :linkage-table :little-endian +:largefile :gencgc :little-endian diff --git a/crossbuild-runner/backends/x86/stuff-groveled-from-headers.lisp b/crossbuild-runner/backends/x86/stuff-groveled-from-headers.lisp index a8684747fb..b426f59902 100644 --- a/crossbuild-runner/backends/x86/stuff-groveled-from-headers.lisp +++ b/crossbuild-runner/backends/x86/stuff-groveled-from-headers.lisp @@ -1,6 +1,22 @@ ;;;; This is an automatically generated file, please do not hand-edit it. ;;;; See the program "grovel-headers.c". +(in-package "SB-WIN32") + +(define-alien-type int-ptr (signed 32)) +(define-alien-type dword (signed 32)) +(define-alien-type bool (signed 32)) +(define-alien-type uint (unsigned 32)) +(define-alien-type ulong (unsigned 32)) + +(defconstant error_file_not_found 2) +(defconstant error_file_exists #x50) + +;; these are total fabrications +(defconstant max_path 1024) +(defconstant error-no-data 1) +(defconstant +exception-maximum-parameters+ 6) + (in-package "SB-ALIEN") ;;;flags for dlopen() @@ -92,6 +108,10 @@ (defconstant tiocgpgrp 21519) ; #x540f ;;; signals +(defconstant sizeof-sigset_t 128) ; #x80 +(defconstant sig_block 0) ; #x0 +(defconstant sig_unblock 1) ; #x1 +(defconstant sig_setmask 2) ; #x2 (defconstant sigalrm 14) ; #xe (defconstant sigbus 7) ; #x7 (defconstant sigchld 17) ; #x11 diff --git a/crossbuild-runner/build-all.sh b/crossbuild-runner/build-all.sh index 5e41a1f142..b1d6dfa9c7 100755 --- a/crossbuild-runner/build-all.sh +++ b/crossbuild-runner/build-all.sh @@ -9,7 +9,7 @@ set -e # or a host machine on which to run its native compiler. if [ -z "$*" ]; then - targets="alpha arm arm64 hppa mips ppc ppc64 riscv sparc x86 x86-64" + targets="arm arm64 mips ppc ppc64 riscv sparc x86 x86-64" else targets="$@" fi @@ -22,7 +22,15 @@ do # to this cross-build test. Some of the provisions are only for C code which # we don't compile. Or else it doesn't matter much which lisp code is compiled. # Assume that dlopen() is provided so that we don't try to read sbcl.nm though. - echo '(lambda (features) (union features (list :crossbuild-test :os-provides-dlopen ' > $ltf + echo '(lambda (features) (union features (list :os-provides-dlopen ' > $ltf + echo ":$arch" >> $ltf + # x86 and x86-64 are tested as if #+win32. Unix is otherwise plenty tested. + if [ $arch = x86 -o $arch = x86-64 ]; then + echo ':win32 :sb-thread :sb-safepoint' >> $ltf + else + echo ':unix :linux :elf' >> $ltf + fi + cat crossbuild-runner/backends/$arch/features >> $ltf cat crossbuild-runner/backends/$arch/local-target-features >> $ltf echo ')))' >> $ltf diff --git a/crossbuild-runner/pass-1.lisp b/crossbuild-runner/pass-1.lisp new file mode 100644 index 0000000000..0971cdc527 --- /dev/null +++ b/crossbuild-runner/pass-1.lisp @@ -0,0 +1,33 @@ +;; (setq *default-pathname-defaults* #p"") ; FIXME: causes redefinition warnings! +(let* ((target-name (second sb-ext:*posix-argv*)) + (build-dir (format nil "obj/xbuild/~A/" target-name)) + (ltf (format nil "~A/local-target-features" build-dir)) + (objroot (format nil "~A/from-host/" build-dir))) + (ensure-directories-exist objroot) + (defvar *sbcl-host-obj-prefix* objroot) + (setq sb-sys:*stdout* (open (format nil "~A/stdout" objroot) :direction :output + :if-does-not-exist :create :if-exists :supersede) + sb-sys:*stderr* (open (format nil "~A/stderr" objroot) :direction :output + :if-does-not-exist :create :if-exists :supersede)) + (defvar *sbcl-local-target-features-file* ltf) + (with-open-file (*standard-output* ltf :direction :output + :if-does-not-exist :create + :if-exists :supersede) + (let ((target-symbol (intern (string-upcase target-name) "KEYWORD"))) + (format t "(lambda (features) (union features (list :crossbuild-test :os-provides-dlopen ~s ~a~%" + target-symbol + (case target-symbol + ((:x86 :x86-64) ":win32 :sb-thread :sb-safepoint") + (t ":unix :linux :elf")))) + ;; "features" contains the mandatory set of symbols for any build of that target. + (dolist (features-filename '("features" "local-target-features")) + (with-open-file (f (format nil "crossbuild-runner/backends/~a/~a" + target-name features-filename)) + (let ((string (make-string (file-length f)))) + (read-sequence string f) + (write-string string)))) + (format t ")))~%")) + (load "make-host-1.lisp") + (finish-output sb-sys:*stdout*) + (finish-output sb-sys:*stderr*) + (save-lisp-and-die (format nil "~A/xc.core" build-dir))) diff --git a/crossbuild-runner/pass-2.lisp b/crossbuild-runner/pass-2.lisp new file mode 100644 index 0000000000..c80eed2fd0 --- /dev/null +++ b/crossbuild-runner/pass-2.lisp @@ -0,0 +1,35 @@ +(defvar *sbcl-local-target-features-file* + (format nil "obj/xbuild/~A/local-target-features" (second sb-ext:*posix-argv*))) +(load "src/cold/shared.lisp") +(in-package "SB-COLD") +(let* ((target-name (second sb-ext:*posix-argv*)) + (build-dir (format nil "obj/xbuild/~A/" target-name)) + (objroot (format nil "~A/from-xc/" build-dir))) + (ensure-directories-exist objroot) + (defvar *host-obj-prefix* (format nil "~A/from-host/" build-dir)) + (defvar *target-obj-prefix* objroot) + (setq sb-sys:*stdout* (open (format nil "~A/stdout" objroot) :direction :output + :if-does-not-exist :create :if-exists :supersede) + sb-sys:*stderr* (open (format nil "~A/stderr" objroot) :direction :output + :if-does-not-exist :create :if-exists :supersede))) +(load "src/cold/set-up-cold-packages.lisp") +(load "src/cold/defun-load-or-cload-xcompiler.lisp") +(load-or-cload-xcompiler #'host-load-stem) + +;;; Redefine STEM-SOURCE-PATH to take 'stuff-groveled-from-headers' from the +;;; architecture-dependent location, but otherwise the normal location. +(host-sb-int:encapsulate 'stem-source-path 'wrap + (lambda (realfun stem) + (if (string= stem "output/stuff-groveled-from-headers") + (format nil "crossbuild-runner/backends/~a/stuff-groveled-from-headers.lisp" + (string-downcase (sb-cold::target-platform-keyword))) + (funcall realfun stem)))) + +(format t "~&Target features: ~S~%" sb-xc:*features*) +(let ((warnings (sb-xc:with-compilation-unit () + (load "src/cold/compile-cold-sbcl.lisp") + sb-c::*undefined-warnings*))) + (finish-output host-sb-sys:*stdout*) + (finish-output host-sb-sys:*stderr*) + (when (and warnings (not (target-featurep :win32))) + (error "Fail"))) diff --git a/doc/clean.sh b/doc/clean.sh index 5ed17ee654..023c29c2d3 100644 --- a/doc/clean.sh +++ b/doc/clean.sh @@ -1,4 +1,4 @@ #!/bin/sh -(cd manual; sh clean.sh) -(cd internals; sh clean.sh) +(cd ./manual && sh ./clean.sh) +(cd ./internals && sh ./clean.sh) diff --git a/doc/cmu-user/.cvsignore b/doc/cmu-user/.cvsignore new file mode 100644 index 0000000000..f6773e158a --- /dev/null +++ b/doc/cmu-user/.cvsignore @@ -0,0 +1,25 @@ +*.aux +*.cdx +*.cnd +*.dvi +*.fdx +*.fnd +*.html +*.idx +*.ilg +*.log +*.out +*.pdf +*.tdx +*.tnd +*.toc +*.vdx +*.vnd +cmu-user-html.tgz +cmu-user-letter.ps +cmu-user.haux +cmu-user.hcnd +cmu-user.hfnd +cmu-user.htnd +cmu-user.htoc +cmu-user.hvnd diff --git a/doc/cmu-user/Makefile b/doc/cmu-user/Makefile new file mode 100644 index 0000000000..b554af2431 --- /dev/null +++ b/doc/cmu-user/Makefile @@ -0,0 +1,124 @@ +# -*- makefile -*- +# +# +# This Makefile contains rules for converting the LaTeX sources of the +# CMUCL User's Manual into various formats: Postscript, PDF, DVI, HTML +# and info. The useful targets are: +# +# make cmu-user.ps (A4 paper) +# make cmu-user-letter.ps (letter paper) +# make cmu-user.dvi +# make cmu-user.pdf +# make cmu-user.html +# make cmu-user.info +# make clean + +# A number of addon LaTeX packages are used in the manual, to support +# features such as hyperlinks and multiple indexes. A current +# distribution of teTeX contains everything that is necessary to +# generate the Postscript, PDF and DVI formats. HTML output is +# generated using the Hevea tool, which is available from +# . The HTML files are +# then split into sections using the hacha tool (distributed with +# hevea), and cleaned up using tidy. Note that hevea 1.10 produces +# HTML that looks a bit weird. However, hevea 1.06 works nicely. +# +# The generated DVI file should include clickable hyperlinks. The PDF +# output should include a hyperlinked table of contents, hyperlinked +# cross-references, and an index. The generated Postscript should use +# Postscript fonts that give good quality output at high resolutions. + + +SHELL = /bin/sh +LATEX ?= latex +BIBTEX ?= bibtex +PDFLATEX ?= pdflatex +HEVEA ?= hevea +HACHA ?= hacha +TIDY ?= tidy + +FILES = *.tex + +.SUFFIXES: +.SUFFIXES: .tex .dvi .ps .ps1 .pdf .html .info + + +all: cmu-user.pdf + + +# Runs LaTeX once, then reruns LaTeX as many times as necessary to get +# rid of the "undefined references" message, generates the indexes, +# the reruns LaTeX. The dependency on the .tex files means that the +# DVI file will be rebuilt only if one of the included LaTeX files has +# been modified. +%.dvi : %.tex $(FILES) + $(LATEX) $< + @while ( grep -q "Rerun to get cross" $*.log > /dev/null ); do \ + $(LATEX) $<; \ + done + if [ "$<" = "cmu-user.tex" ]; then $(MAKE) index; else $(MAKE) index-letter; fi + + $(LATEX) $< + +%.pdf : %.tex $(FILES) + $(PDFLATEX) $< + if [ "$<" = "cmu-user.tex" ]; then $(MAKE) index; else $(MAKE) index-letter; fi + @while ( grep 'Rerun to get cross' $*.log > /dev/null ); do \ + $(PDFLATEX) $<; \ + if [ "$<" = "cmu-user.tex" ]; then $(MAKE) index; else $(MAKE) index-letter; fi; \ + done + +# the "-fix" option to hevea makes it run as many times as necessary +# to resolve all cross-references and generate an index. +%.html : %.tex $(FILES) cmu-user.hva + $(HEVEA) -fix cmu-user.hva $< + $(HACHA) -tocbis $@ + -$(TIDY) -m *.html + +%.info : %.tex $(FILES) + $(HEVEA) -fix -info cmu-user.hva $< + +%.ps1 : %.dvi + dvips -o $@ $< + +# convert the Postscript file to duplex (will print double-sided if +# the printer supports it) +%.ps : %.ps1 + if [ -x psset ]; then psset -d -o $@ $<; else cp $< $@; fi + +# Tar up the html files. Note: cmucl.css is duplicated here, from the +# cmucl-www repository. Please remember to update cmucl.css here +# whenever cmucl.css changes in cmucl-www. +cmu-user-html.tgz : cmu-user.html + mkdir cmu-user + cp cmucl.css *.html *.gif cmu-user + tar cf - cmu-user | gzip > cmu-user-html.tgz + +# generate Postscript for letter format, instead of for A4 paper +.INTERMEDIATE: cmu-user-letter.tex +cmu-user-letter.tex: cmu-user.tex + cp $< $@ + perl -pi -e 's/documentclass\[a4paper\]/documentclass\[letter\]/' $@ + + +clean: + rm -f *.log *.bbl *.blg *.ps *.pdf *.aux *.lof *.toc *.out *.ilg + rm -f *.vdx *.cdx *.tdx *.fdx *.idx *.cnd *.fnd *.tnd *.vnd *.haux + rm -f *.html *.hcnd *.htnd *.hvnd *.hfnd *.htoc + rm -f cmu-user.css + +index: + makeindex cmu-user.tdx -o cmu-user.tnd + makeindex cmu-user.vdx -o cmu-user.vnd + makeindex cmu-user.fdx -o cmu-user.fnd + makeindex cmu-user.cdx -o cmu-user.cnd + +index-letter: + makeindex cmu-user-letter.tdx -o cmu-user-letter.tnd + makeindex cmu-user-letter.vdx -o cmu-user-letter.vnd + makeindex cmu-user-letter.fdx -o cmu-user-letter.fnd + makeindex cmu-user-letter.cdx -o cmu-user-letter.cnd + +.PHONY: clean index + +# EOF diff --git a/doc/cmu-user/aliens.tex b/doc/cmu-user/aliens.tex new file mode 100644 index 0000000000..34ac3176df --- /dev/null +++ b/doc/cmu-user/aliens.tex @@ -0,0 +1,1163 @@ +\chapter{Alien Objects} +\label{aliens} + +\credits{by Robert MacLachlan and William Lott} + + +\section{Introduction to Aliens} + +Because of Lisp's emphasis on dynamic memory allocation and garbage +collection, Lisp implementations use unconventional memory representations +for objects. This representation mismatch creates problems when a Lisp +program must share objects with programs written in another language. There +are three different approaches to establishing communication: + +\begin{itemize} +\item The burden can be placed on the foreign program (and programmer) by +requiring the use of Lisp object representations. The main difficulty with +this approach is that either the foreign program must be written with Lisp +interaction in mind, or a substantial amount of foreign ``glue'' code must be +written to perform the translation. + +\item The Lisp system can automatically convert objects back and forth +between the Lisp and foreign representations. This is convenient, but +translation becomes prohibitively slow when large or complex data structures +must be shared. + +\item The Lisp program can directly manipulate foreign objects through the +use of extensions to the Lisp language. Most Lisp systems make use of +this approach, but the language for describing types and expressing +accesses is often not powerful enough for complex objects to be easily +manipulated. +\end{itemize} + +\cmucl{} relies primarily on the automatic conversion and direct manipulation +approaches: Aliens of simple scalar types are automatically converted, +while complex types are directly manipulated in their foreign +representation. Any foreign objects that can't automatically be +converted into Lisp values are represented by objects of type +\code{alien-value}. Since Lisp is a dynamically typed language, even +foreign objects must have a run-time type; this type information is +provided by encapsulating the raw pointer to the foreign data within an +\code{alien-value} object. + +The Alien type language and operations are most similar to those of the +C language, but Aliens can also be used when communicating with most +other languages that can be linked with C. + + +\section{Alien Types} + +Alien types have a description language based on nested list structure. For +example: + +\begin{example} +struct foo \{ + int a; + struct foo *b[100]; +\}; +\end{example} + +has the corresponding Alien type: + +\begin{lisp} +(struct foo + (a int) + (b (array (* (struct foo)) 100))) +\end{lisp} + + +\subsection{Defining Alien Types} + +Types may be either named or anonymous. With structure and union +types, the name is part of the type specifier, allowing recursively +defined types such as: + +\begin{lisp} +(struct foo (a (* (struct foo)))) +\end{lisp} + +An anonymous structure or union type is specified by using the name +\nil{}. The \funref{with-alien} macro defines a local scope which +``captures'' any named type definitions. Other types are not +inherently named, but can be given named abbreviations using +\code{def-alien-type}. + +\begin{defmac}{alien:}{def-alien-type}{name type} + This macro globally defines \var{name} as a shorthand for the Alien + type \var{type}. When introducing global structure and union type + definitions, \var{name} may be \nil, in which case the name to + define is taken from the type's name. +\end{defmac} + + +\subsection{Alien Types and Lisp Types} + +The Alien types form a subsystem of the \cmucl{} type system. An +\code{alien} type specifier provides a way to use any Alien type as a +Lisp type specifier. For example + +\begin{lisp} +(typep foo '(alien (* int))) +\end{lisp} + +can be used to determine whether \code{foo} is a pointer to an +\code{int}. \code{alien} type specifiers can be used in the same ways +as ordinary type specifiers (like \code{string}.) Alien type +declarations are subject to the same precise type checking as any +other declaration (\pxlref{precise-type-checks}.) + +Note that the Alien type system overlaps with normal Lisp type +specifiers in some cases. For example, the type specifier +\code{(alien single-float)} is identical to \code{single-float}, since +Alien floats are automatically converted to Lisp floats. When +\code{type-of} is called on an Alien value that is not automatically +converted to a Lisp value, then it will return an \code{alien} type +specifier. + + +\subsection{Alien Type Specifiers} + +Some Alien type names are \clisp{} symbols, but the names are +still exported from the \code{alien} package, so it is legal to say +\code{alien:single-float}. These are the basic Alien type specifiers: + +\begin{deftp}{Alien type}{*}{% + \args{\var{type}}} + + A pointer to an object of the specified \var{type}. If \var{type} + is \true, then it means a pointer to anything, similar to + ``\code{void *}'' in ANSI C. Currently, the only way to detect a + null pointer is: +\begin{lisp} + (zerop (sap-int (alien-sap \var{ptr}))) +\end{lisp} +\xlref{system-area-pointers} +\end{deftp} + +\begin{deftp}{Alien type}{array}{\var{type} \mstar{\var{dimension}}} + + An array of the specified \var{dimensions}, holding elements of type + \var{type}. Note that \code{(* int)} and \code{(array int)} are + considered to be different types when type checking is done; pointer + and array types must be explicitly coerced using \code{cast}. + + Arrays are accessed using \code{deref}, passing the indices as + additional arguments. Elements are stored in column-major order (as + in C), so the first dimension determines only the size of the memory + block, and not the layout of the higher dimensions. An array whose + first dimension is variable may be specified by using \nil{} as the + first dimension. Fixed-size arrays can be allocated as array + elements, structure slots or \code{with-alien} variables. Dynamic + arrays can only be allocated using \funref{make-alien}. +\end{deftp} + +\begin{deftp}{Alien type}{struct}{\var{name} + \mstar{(\var{field} \var{type} \mopt{\var{bits}})}} + + A structure type with the specified \var{name} and \var{fields}. + Fields are allocated at the same positions used by the + implementation's C compiler. \var{bits} is intended for C-like bit + field support, but is currently unused. If \var{name} is \false, + then the type is anonymous. + + If a named Alien \code{struct} specifier is passed to + \funref{def-alien-type} or \funref{with-alien}, then this defines, + respectively, a new global or local Alien structure type. If no + \var{fields} are specified, then the fields are taken from the + current (local or global) Alien structure type definition of + \var{name}. +\end{deftp} + +\begin{deftp}{Alien type}{union}{\var{name} + \mstar{(\var{field} \var{type} \mopt{\var{bits}})}} + + Similar to \code{struct}, but defines a union type. All fields are + allocated at the same offset, and the size of the union is the size + of the largest field. The programmer must determine which field is + active from context. +\end{deftp} + +\begin{deftp}{Alien type}{enum}{\var{name} \mstar{\var{spec}}} + + An enumeration type that maps between integer values and keywords. + If \var{name} is \false, then the type is anonymous. Each + \var{spec} is either a keyword, or a list \code{(\var{keyword} + \var{value})}. If \var{integer} is not supplied, then it defaults + to one greater than the value for the preceding spec (or to zero if + it is the first spec.) +\end{deftp} + +\begin{deftp}{Alien type}{signed}{\mopt{\var{bits}}} + A signed integer with the specified number of bits precision. The + upper limit on integer precision is determined by the machine's word + size. If no size is specified, the maximum size will be used. +\end{deftp} + +\begin{deftp}{Alien type}{integer}{\mopt{\var{bits}}} + Identical to \code{signed}---the distinction between \code{signed} + and \code{integer} is purely stylistic. +\end{deftp} + +\begin{deftp}{Alien type}{unsigned}{\mopt{\var{bits}}} + Like \code{signed}, but specifies an unsigned integer. +\end{deftp} + +\begin{deftp}{Alien type}{boolean}{\mopt{\var{bits}}} + Similar to an enumeration type that maps \code{0} to \false{} and + all other values to \true. \var{bits} determines the amount of + storage allocated to hold the truth value. +\end{deftp} + +\begin{deftp}{Alien type}{single-float}{} + A floating-point number in IEEE single format. +\end{deftp} + +\begin{deftp}{Alien type}{double-float}{} + A floating-point number in IEEE double format. +\end{deftp} + +\begin{deftp}{Alien type}{function}{\var{result-type} \mstar{\var{arg-type}}} + \label{alien-function-types} + A Alien function that takes arguments of the specified + \var{arg-types} and returns a result of type \var{result-type}. + Note that the only context where a \code{function} type is directly + specified is in the argument to \code{alien-funcall} (see section + \funref{alien-funcall}.) In all other contexts, functions are + represented by function pointer types: \code{(* (function ...))}. +\end{deftp} + +\begin{deftp}{Alien type}{system-area-pointer}{} + A pointer which is represented in Lisp as a + \code{system-area-pointer} object (\pxlref{system-area-pointers}.) +\end{deftp} + + +\subsection{The C-Call Package} + +The \code{c-call} package exports these type-equivalents to the C type +of the same name: \code{char}, \code{short}, \code{int}, \code{long}, +\code{unsigned-char}, \code{unsigned-short}, \code{unsigned-int}, +\code{unsigned-long}, \code{float}, \code{double}. \code{c-call} also +exports these types: + +\begin{deftp}{Alien type}{void}{} + This type is used in function types to declare that no useful value + is returned. Evaluation of an \code{alien-funcall} form will return + zero values. +\end{deftp} + +\begin{deftp}{Alien type}{c-string}{} + This type is similar to \code{(* char)}, but is interpreted as a + null-terminated string, and is automatically converted into a Lisp + string when accessed. If the pointer is C \code{NULL} (or 0), then + accessing gives Lisp \false. + + With Unicode, a Lisp string is not the same as a C string since a + Lisp string uses two bytes for each character. In this case, a + C string is converted to a Lisp string by taking each byte of the + C-string and applying \code{code-char} to create each character of + the Lisp string. + + Similarly, a Lisp string is converted to a C string by taking the + low 8 bits of the \code{char-code} of each character and assigning + that to each byte of the C string. + + In either case, \code{string-encode} and \code{string-decode} may be + useful to convert Unicode Lisp strings to or from C strings. + + Assigning a Lisp string to a \code{c-string} structure field or + variable stores the contents of the string to the memory already + pointed to by that variable. When an Alien of type \code{(* char)} + is assigned to a \code{c-string}, then the \code{c-string} pointer + is assigned to. This allows \code{c-string} pointers to be + initialized. For example: + +\begin{lisp} + (def-alien-type nil (struct foo (str c-string))) + + (defun make-foo (str) + (let ((my-foo (make-alien (struct foo)))) + (setf (slot my-foo 'str) (make-alien char (length str))) + (setf (slot my-foo 'str) str) + my-foo)) +\end{lisp} + +Storing Lisp \false{} writes C \code{NULL} to the \code{c-string} +pointer. +\end{deftp} + + + +\section{Alien Operations} + +This section describes the basic operations on Alien values. + +\subsection{Alien Access Operations} + +\begin{defun}{alien:}{deref}{\args{\var{pointer-or-array} \amprest{} \var{indices}}} + + This function returns the value pointed to by an Alien pointer or + the value of an Alien array element. If a pointer, an optional + single index can be specified to give the equivalent of C pointer + arithmetic; this index is scaled by the size of the type pointed to. + If an array, the number of indices must be the same as the number of + dimensions in the array type. \code{deref} can be set with + \code{setf} to assign a new value. +\end{defun} + +\begin{defun}{alien:}{slot}{\args{\var{struct-or-union} \var{slot-name}}} + + This function extracts the value of slot \var{slot-name} from the an + Alien \code{struct} or \code{union}. If \var{struct-or-union} is a + pointer to a structure or union, then it is automatically + dereferenced. This can be set with \code{setf} to assign a new + value. Note that \var{slot-name} is evaluated, and need not be a + compile-time constant (but only constant slot accesses are + efficiently compiled.) +\end{defun} + + +\subsection{Alien Coercion Operations} + +\begin{defmac}{alien:}{addr}{\var{alien-expr}} + + This macro returns a pointer to the location specified by + \var{alien-expr}, which must be either an Alien variable, a use of + \code{deref}, a use of \code{slot}, or a use of + \funref{extern-alien}. +\end{defmac} + +\begin{defmac}{alien:}{cast}{\var{alien} \var{new-type}} + + This macro converts \var{alien} to a new Alien with the specified + \var{new-type}. Both types must be an Alien pointer, array or + function type. Note that the result is not \code{eq} to the + argument, but does refer to the same data bits. +\end{defmac} + +\begin{defmac}{alien:}{sap-alien}{\var{sap} \var{type}} + \defunx[alien:]{alien-sap}{\var{alien-value}} + + \code{sap-alien} converts \var{sap} (a system area pointer + \pxlref{system-area-pointers}) to an Alien value with the specified + \var{type}. \var{type} is not evaluated. + +\code{alien-sap} returns the SAP which points to \var{alien-value}'s +data. + +The \var{type} to \code{sap-alien} and the type of the \var{alien-value} to +\code{alien-sap} must some Alien pointer, array or record type. +\end{defmac} + + +\subsection{Alien Dynamic Allocation} + +Dynamic Aliens are allocated using the \code{malloc} library, so foreign code +can call \code{free} on the result of \code{make-alien}, and Lisp code can +call \code{free-alien} on objects allocated by foreign code. + +\begin{defmac}{alien:}{make-alien}{\var{type} \mopt{\var{size}}} + + This macro returns a dynamically allocated Alien of the specified + \var{type} (which is not evaluated.) The allocated memory is not + initialized, and may contain arbitrary junk. If supplied, + \var{size} is an expression to evaluate to compute the size of the + allocated object. There are two major cases: + \begin{itemize} + \item When \var{type} is an array type, an array of that type is + allocated and a \var{pointer} to it is returned. Note that you + must use \code{deref} to change the result to an array before you + can use \code{deref} to read or write elements: + +\begin{lisp} +(defvar *foo* (make-alien (array char 10))) + +(type-of *foo*) \result{} (alien (* (array (signed 8) 10))) + +(setf (deref (deref foo) 0) 10) \result{} 10 +\end{lisp} + + If supplied, \var{size} is used as the first dimension for the + array. + + \item When \var{type} is any other type, then then an object for + that type is allocated, and a \var{pointer} to it is returned. So + \code{(make-alien int)} returns a \code{(* int)}. If \var{size} + is specified, then a block of that many objects is allocated, with + the result pointing to the first one. + \end{itemize} +\end{defmac} + +\begin{defun}{alien:}{free-alien}{\var{alien}} + + This function frees the storage for \var{alien} (which must have + been allocated with \code{make-alien} or \code{malloc}.) +\end{defun} + +See also \funref{with-alien}, which stack-allocates Aliens. + + +\section{Alien Variables} + +Both local (stack allocated) and external (C global) Alien variables are +supported. + + +\subsection{Local Alien Variables} + +\begin{defmac}{alien:}{with-alien}{\mstar{(\var{name} \var{type} + \mopt{\var{initial-value}})} \mstar{form}} + + This macro establishes local alien variables with the specified + Alien types and names for dynamic extent of the body. The variable + \var{names} are established as symbol-macros; the bindings have + lexical scope, and may be assigned with \code{setq} or \code{setf}. + This form is analogous to defining a local variable in C: additional + storage is allocated, and the initial value is copied. + + \code{with-alien} also establishes a new scope for named structures + and unions. Any \var{type} specified for a variable may contain + name structure or union types with the slots specified. Within the + lexical scope of the binding specifiers and body, a locally defined + structure type \var{foo} can be referenced by its name using: +\begin{lisp} + (struct foo) +\end{lisp} +\end{defmac} + + +\subsection{External Alien Variables} +\label{external-aliens} + +External Alien names are strings, and Lisp names are symbols. When an +external Alien is represented using a Lisp variable, there must be a +way to convert from one name syntax into the other. The macros +\code{extern-alien}, \code{def-alien-variable} and +\funref{def-alien-routine} use this conversion heuristic: +\begin{itemize} +\item Alien names are converted to Lisp names by uppercasing and + replacing underscores with hyphens. + +\item Conversely, Lisp names are converted to Alien names by + lowercasing and replacing hyphens with underscores. + +\item Both the Lisp symbol and Alien string names may be separately + specified by using a list of the form: +\begin{lisp} + (\var{alien-string} \var{lisp-symbol}) +\end{lisp} +\end{itemize} + +\begin{defmac}{alien:}{def-alien-variable}{\var{name} \var{type}} + + This macro defines \var{name} as an external Alien variable of the + specified Alien \var{type}. \var{name} and \var{type} are not + evaluated. The Lisp name of the variable (see above) becomes a + global Alien variable in the Lisp namespace. Global Alien variables + are effectively ``global symbol macros''; a reference to the + variable fetches the contents of the external variable. Similarly, + setting the variable stores new contents---the new contents must be + of the declared \var{type}. + + For example, it is often necessary to read the global C variable + \code{errno} to determine why a particular function call failed. It + is possible to define errno and make it accessible from Lisp by the + following: +\begin{lisp} +(def-alien-variable "errno" int) + +;; Now it is possible to get the value of the C variable errno simply by +;; referencing that Lisp variable: +;; +(print errno) +\end{lisp} +\end{defmac} + +\begin{defmac}{alien:}{extern-alien}{\var{name} \var{type}} + + This macro returns an Alien with the specified \var{type} which + points to an externally defined value. \var{name} is not evaluated, + and may be specified either as a string or a symbol. \var{type} is + an unevaluated Alien type specifier. +\end{defmac} + + +\section{Alien Data Structure Example} + +Now that we have Alien types, operations and variables, we can manipulate +foreign data structures. This C declaration can be translated into the +following Alien type: + +\begin{lisp} +struct foo \{ + int a; + struct foo *b[100]; +\}; + + \myequiv + +(def-alien-type nil + (struct foo + (a int) + (b (array (* (struct foo)) 100)))) +\end{lisp} + +With this definition, the following C expression can be translated in this way: + +\begin{example} +struct foo f; +f.b[7].a + + \myequiv + +(with-alien ((f (struct foo))) + (slot (deref (slot f 'b) 7) 'a) + ;; + ;; Do something with f... + ) +\end{example} + + +Or consider this example of an external C variable and some accesses: + +\begin{example} +struct c_struct \{ + short x, y; + char a, b; + int z; + c_struct *n; +\}; + +extern struct c_struct *my_struct; + +my_struct->x++; +my_struct->a = 5; +my_struct = my_struct->n; +\end{example} + +which can be made be manipulated in Lisp like this: + +\begin{lisp} +(def-alien-type nil + (struct c-struct + (x short) + (y short) + (a char) + (b char) + (z int) + (n (* c-struct)))) + +(def-alien-variable "my_struct" (* c-struct)) + +(incf (slot my-struct 'x)) +(setf (slot my-struct 'a) 5) +(setq my-struct (slot my-struct 'n)) +\end{lisp} + + +\section{Loading Unix Object Files} + +\cmucl{} is able to load foreign object files at runtime, using the +function \code{load-foreign}. This function is able to load shared +libraries (that are typically named \verb|.so|) via the dlopen +mechanism. It can also load \verb|.a| or \verb|.o| object files by +calling the linker on the files and libraries to create a loadable +object file. Once loaded, the external symbols that define routines +and variables are made available for future external references (e.g. +by \code{extern-alien}.) \code{load-foreign} must be run before any of +the defined symbols are referenced. + +Note that if a Lisp core image is saved (using \funref{save-lisp}), all +loaded foreign code is lost when the image is restarted. + + +\begin{defun}{ext:}{load-foreign}{% + \args{\var{files} \keys{\kwd{libraries} \kwd{base-file} \kwd{env}}}} + + \var{files} is a \code{simple-string} or list of + \code{simple-string}s specifying the names of the object files. If + \var{files} is a simple-string, the file that it designates is + loaded using the platform's dlopen mechanism. If it is a list of + strings, the platform linker \code{ld} is invoked to transform the + object files into a loadable object file. \var{libraries} is a list + of \code{simple-string}s specifying libraries in a format that the + platform linker expects. The default value for \var{libraries} is + \code{("-lc")} (i.e., the standard C library). \var{base-file} is + the file to use for the initial symbol table information. The + default is the Lisp start up code: \file{path:lisp}. \var{env} + should be a list of simple strings in the format of Unix environment + variables (i.e., \code{\var{A}=\var{B}}, where \var{A} is an + environment variable and \var{B} is its value). The default value + for \var{env} is the environment information available at the time + Lisp was invoked. Unless you are certain that you want to change + this, you should just use the default. +\end{defun} + + +\section{Alien Function Calls} + +The foreign function call interface allows a Lisp program to call functions +written in other languages. The current implementation of the foreign +function call interface assumes a C calling convention and thus routines +written in any language that adheres to this convention may be called from +Lisp. + +Lisp sets up various interrupt handling routines and other environment +information when it first starts up, and expects these to be in place at all +times. The C functions called by Lisp should either not change the +environment, especially the interrupt entry points, or should make sure +that these entry points are restored when the C function returns to Lisp. +If a C function makes changes without restoring things to the way they were +when the C function was entered, there is no telling what will happen. + + +\subsection{The alien-funcall Primitive} + +\begin{defun}{alien:}{alien-funcall}{% + \args{\var{alien-function} \amprest{} \var{arguments}}} + + This function is the foreign function call primitive: + \var{alien-function} is called with the supplied \var{arguments} and + its value is returned. The \var{alien-function} is an arbitrary + run-time expression; to call a constant function, use + \funref{extern-alien} or \code{def-alien-routine}. + + The type of \var{alien-function} must be \code{(alien (function + ...))} or \code{(alien (* (function ...)))}, + \xlref{alien-function-types}. The function type is used to + determine how to call the function (as though it was declared with + a prototype.) The type need not be known at compile time, but only + known-type calls are efficiently compiled. Limitations: + \begin{itemize} + \item Structure type return values are not implemented. + \item Passing of structures by value is not implemented. + \end{itemize} +\end{defun} + +Here is an example which allocates a \code{(struct foo)}, calls a foreign +function to initialize it, then returns a Lisp vector of all the +\code{(* (struct foo))} objects filled in by the foreign call: + +\begin{lisp} +;; Allocate a foo on the stack. +(with-alien ((f (struct foo))) + ;; + ;; Call some C function to fill in foo fields. + (alien-funcall (extern-alien "mangle_foo" (function void (* foo))) + (addr f)) + ;; + ;; Find how many foos to use by getting the A field. + (let* ((num (slot f 'a)) + (result (make-array num))) + ;; + ;; Get a pointer to the array so that we don't have to keep + ;; extracting it: + (with-alien ((a (* (array (* (struct foo)) 100)) (addr (slot f 'b)))) + ;; + ;; Loop over the first N elements and stash them in the + ;; result vector. + (dotimes (i num) + (setf (svref result i) (deref (deref a) i))) + result))) +\end{lisp} + + +\subsection{The def-alien-routine Macro} + +\begin{defmac}{alien:}{def-alien-routine}{\var{name} \var{result-type} + \mstar{(\var{aname} \var{atype} \mopt{style})}} + + This macro is a convenience for automatically generating Lisp + interfaces to simple foreign functions. The primary feature is the + parameter style specification, which translates the C + pass-by-reference idiom into additional return values. + + \var{name} is usually a string external symbol, but may also be a + symbol Lisp name or a list of the foreign name and the Lisp name. + If only one name is specified, the other is automatically derived, + (\pxlref{external-aliens}.) + + \var{result-type} is the Alien type of the return value. Each + remaining subform specifies an argument to the foreign function. + \var{aname} is the symbol name of the argument to the constructed + function (for documentation) and \var{atype} is the Alien type of + corresponding foreign argument. The semantics of the actual call + are the same as for \funref{alien-funcall}. \var{style} should be + one of the following: + \begin{Lentry} + \item[\kwd{in}] specifies that the argument is passed by value. + This is the default. \kwd{in} arguments have no corresponding + return value from the Lisp function. + + \item[\kwd{out}] specifies a pass-by-reference output value. The + type of the argument must be a pointer to a fixed sized object + (such as an integer or pointer). \kwd{out} and \kwd{in-out} + cannot be used with pointers to arrays, records or functions. An + object of the correct size is allocated, and its address is passed + to the foreign function. When the function returns, the contents + of this location are returned as one of the values of the Lisp + function. + + \item[\kwd{copy}] is similar to \kwd{in}, but the argument is copied + to a pre-allocated object and a pointer to this object is passed + to the foreign routine. + + \item[\kwd{in-out}] is a combination of \kwd{copy} and \kwd{out}. + The argument is copied to a pre-allocated object and a pointer to + this object is passed to the foreign routine. On return, the + contents of this location is returned as an additional value. + \end{Lentry} + Any efficiency-critical foreign interface function should be inline + expanded by preceding \code{def-alien-routine} with: + +\begin{lisp} +(declaim (inline \var{lisp-name})) +\end{lisp} + + In addition to avoiding the Lisp call overhead, this allows + pointers, word-integers and floats to be passed using non-descriptor + representations, avoiding consing (\pxlref{non-descriptor}.) +\end{defmac} + + +\subsection{def-alien-routine Example} + +Consider the C function \code{cfoo} with the following calling convention: + +\begin{example} +/* a for update + * i out + */ +void cfoo (char *str, char *a, int *i); +\end{example} + +which can be described by the following call to \code{def-alien-routine}: + +\begin{lisp} +(def-alien-routine "cfoo" void + (str c-string) + (a char :in-out) + (i int :out)) +\end{lisp} + +The Lisp function \code{cfoo} will have two arguments (\var{str} and \var{a}) +and two return values (\var{a} and \var{i}). + + +\subsection{Calling Lisp from C} + +% Calling Lisp functions from C is sometimes possible, but is rather hackish. +% See \code{funcall0} ... \code{funcall3} in the \file{lisp/arch.h}. The +% arguments must be valid \cmucl{} object descriptors (e.g. fixnums must be +% left-shifted by 2.) See \file{compiler/generic/objdef.lisp} or the derived +% file \file{lisp/internals.h} for details of the object representation. +% \file{lisp/internals.h} is mechanically generated, and is not part of the +% source distribution. It is distributed in the \file{docs/} directory of the +% binary distribution. + +% Note that the garbage collector moves objects, and won't be able to fix up any +% references in C variables, so either turn GC off or don't keep Lisp pointers +% in C data unless they are to statically allocated objects. You can use +% \funref{purify} to place live data structures in static space so that they +% won't move during GC. + +\cmucl{} supports calling Lisp from C via the \funref{def-callback} +macro: + +\begin{defmac}{alien:}{def-callback}{\var{name} (\var{return-type} + \mstar{(arg-name arg-type)}) \ampbody{} \var{body}} + This macro defines a Lisp function that can be called from C and a + Lisp variable. The arguments to the function must be alien types, + and the return type must also be an alien type. This Lisp function + can be accessed via the \funref{callback} macro. + + \var{name} is the name of the Lisp function. It is also the name of + a variable to be used by the \code{callback} macro. + + \var{return-type} is the return type of the function. This must be + a recognized alien type. + + \var{arg-name} specifies the name of the argument to the function, + and the argument has type \var{arg-type}, which must be an alien type. +\end{defmac} + +\begin{defmac}{alien:}{callback}{\var{callback-symbol}} + This macro extracts the appropriate information for the function + named \var{callback-symbol} so that it can be called by a C + function. \var{callback-symbol} must be a symbol created by the + \code{def-callback} macro. +\end{defmac} + +\begin{defmac}{alien:}{callback-funcall}{\var{callback-name} \amprest{} + \var{args}} + This macro does the necessary stuff to call the callback named + \var{callback-name} with the given arguments. +\end{defmac} + +\subsection{Callback Example} + +Here is a simple example of using callbacks. +\begin{lisp} +(use-package :alien) +(use-package :c-call) + +(def-callback foo (int (arg1 int) (arg2 int)) + (format t "~&foo: ~S, ~S~%" arg1 arg2) + (+ arg1 arg2)) + +(defun test-foo () + (callback-funcall foo 555 444444)) +\end{lisp} + +In this example, the callback function \code{foo} is defined which +takes two C \code{int} parameters and returns a \code{int}. As this +shows, we can use arbitrary Lisp inside the function. + +The function \code{test-foo} shows how we can call this callback +function from Lisp. The macro \code{callback} extracts the necessary +information for the callback function \code{foo} which can be +converted into a pointer which we can call via \code{alien-funcall}. + +The following code is a more complete example where a foreign routine +calls our Lisp routine. +\begin{lisp} +(use-package :alien) +(use-package :c-call) + +(def-alien-routine qsort void + (base (* t)) + (nmemb int) + (size int) + (compar (* (function int (* t) (* t))))) + +(def-callback my< (int (arg1 (* double)) + (arg2 (* double))) + (let ((a1 (deref arg1)) + (a2 (deref arg2))) + (cond ((= a1 a2) 0) + ((< a1 a2) -1) + (t +1)))) + +(defun test-qsort () + (let ((a (make-array 10 :element-type 'double-float + :initial-contents '(0.1d0 0.5d0 0.2d0 1.2d0 1.5d0 + 2.5d0 0.0d0 0.1d0 0.2d0 0.3d0)))) + (print a) + (qsort (sys:vector-sap a) + (length a) + (alien-size double :bytes) + (alien:callback my<)) + (print a))) +\end{lisp} + +We define the alien routine, \code{qsort}, and a callback, \code{my<}, +to determine whether two \code{double}'s are less than, greater than +or equal to each other. + +The test function \code{test-qsort} shows how we can call the alien +sort routine with our Lisp comparison routine to produce a sorted +array. + +\subsection{Accessing Lisp Arrays} + +Due to the way \cmucl{} manages memory, the amount of memory that can +be dynamically allocated by \code{malloc} or \funref{make-alien} is +limited\footnote{\cmucl{} mmaps a large piece of memory for its own +use and this memory is typically about 256~MB above the start of the C +heap. Thus, only about 256~MB of memory can be dynamically allocated. +In earlier versions, this limit was closer to 8~MB.}. + +To overcome this limitation, it is possible to access the content of +Lisp arrays which are limited only by the amount of physical memory +and swap space available. However, this technique is only useful if +the foreign function takes pointers to memory instead of allocating +memory for itself. In latter case, you will have to modify the +foreign functions. + +This technique takes advantage of the fact that \cmucl{} has +specialized array types (\pxlref{specialized-array-types}) that match +a typical C array. For example, a \code{(simple-array double-float + (100))} is stored in memory in essentially the same way as the C +array \code{double x[100]} would be. The following function allows us +to get the physical address of such a Lisp array: + +\begin{example} +(defun array-data-address (array) + "Return the physical address of where the actual data of an array is +stored. + +ARRAY must be a specialized array type in \cmucl{}. This means ARRAY +must be an array of one of the following types: + + double-float + single-float + (unsigned-byte 32) + (unsigned-byte 16) + (unsigned-byte 8) + (signed-byte 32) + (signed-byte 16) + (signed-byte 8) +" + (declare (type (or (simple-array (signed-byte 8)) + (simple-array (signed-byte 16)) + (simple-array (signed-byte 32)) + (simple-array (unsigned-byte 8)) + (simple-array (unsigned-byte 16)) + (simple-array (unsigned-byte 32)) + (simple-array single-float) + (simple-array double-float) + (simple-array (complex single-float)) + (simple-array (complex double-float))) + array) + (optimize (speed 3) (safety 0)) + (ext:optimize-interface (safety 3))) + ;; with-array-data will get us to the actual data. However, because + ;; the array could have been displaced, we need to know where the + ;; data starts. + (lisp::with-array-data ((data array) + (start) + (end)) + (declare (ignore end)) + ;; DATA is a specialized simple-array. Memory is laid out like this: + ;; + ;; byte offset Value + ;; 0 type code (should be 70 for double-float vector) + ;; 4 4 * number of elements in vector + ;; 8 1st element of vector + ;; ... ... + ;; + (let ((addr (+ 8 (logandc1 7 (kernel:get-lisp-obj-address data)))) + (type-size + (let ((type (array-element-type data))) + (cond ((or (equal type '(signed-byte 8)) + (equal type '(unsigned-byte 8))) + 1) + ((or (equal type '(signed-byte 16)) + (equal type '(unsigned-byte 16))) + 2) + ((or (equal type '(signed-byte 32)) + (equal type '(unsigned-byte 32))) + 4) + ((equal type 'single-float) + 4) + ((equal type 'double-float) + 8) + (t + (error "Unknown specialized array element type")))))) + (declare (type (unsigned-byte 32) addr) + (optimize (speed 3) (safety 0) (ext:inhibit-warnings 3))) + (system:int-sap (the (unsigned-byte 32) + (+ addr (* type-size start))))))) +\end{example} + +We note, however, that the system function +\findexed{system:vector-sap} will do the same thing as above does. + +Assume we have the C function below that we wish to use: + +\begin{example} + double dotprod(double* x, double* y, int n) + \{ + int k; + double sum = 0; + + for (k = 0; k < n; ++k) \{ + sum += x[k] * y[k]; + \} + return sum; + \} +\end{example} + +The following example generates two large arrays in Lisp, and calls the C +function to do the desired computation. This would not have been +possible using \code{malloc} or \code{make-alien} since we need about +16 MB of memory to hold the two arrays. + +\begin{example} + (alien:def-alien-routine "dotprod" c-call:double + (x (* double-float) :in) + (y (* double-float) :in) + (n c-call:int :in)) + + (defun test-dotprod () + (let ((x (make-array 10000 :element-type 'double-float + :initial-element 2d0)) + (y (make-array 10000 :element-type 'double-float + :initial-element 10d0))) + (sys:without-gcing + (let ((x-addr (sys:vector-sap x)) + (y-addr (sys:vector-sap y))) + (dotprod x-addr y-addr 10000))))) +\end{example} + +In this example, we have used \code{sys:vector-sap} instead of +\code{array-data-address}, but we could have used \code{(sys:int-sap + (array-data-address x))} as well. + +Also, we have wrapped the inner \code{let} expression in a +\code{sys:without-gcing} that disables garbage collection for the +duration of the body. This will prevent garbage collection from +moving \code{x} and \code{y} arrays after we have obtained the (now +erroneous) addresses but before the call to \code{dotprod} is made. + + +\section{Step-by-Step Alien Example} + +This section presents a complete example of an interface to a somewhat +complicated C function. This example should give a fairly good idea +of how to get the effect you want for almost any kind of C function. +Suppose you have the following C function which you want to be able to +call from Lisp in the file \file{test.c}: + +\begin{verbatim} +struct c_struct +{ + int x; + char *s; +}; + +struct c_struct *c_function (i, s, r, a) + int i; + char *s; + struct c_struct *r; + int a[10]; +{ + int j; + struct c_struct *r2; + + printf("i = %d\n", i); + printf("s = %s\n", s); + printf("r->x = %d\n", r->x); + printf("r->s = %s\n", r->s); + for (j = 0; j < 10; j++) printf("a[%d] = %d.\n", j, a[j]); + r2 = (struct c_struct *) malloc (sizeof(struct c_struct)); + r2->x = i + 5; + r2->s = "A C string"; + return(r2); +}; +\end{verbatim} + +It is possible to call this function from Lisp using the file \file{test.lisp} +whose contents is: + +\begin{lisp} +;;; -*- Package: test-c-call -*- +(in-package "TEST-C-CALL") +(use-package "ALIEN") +(use-package "C-CALL") + +;;; Define the record c-struct in Lisp. +(def-alien-type nil + (struct c-struct + (x int) + (s c-string))) + +;;; Define the Lisp function interface to the C routine. It returns a +;;; pointer to a record of type c-struct. It accepts four parameters: +;;; i, an int; s, a pointer to a string; r, a pointer to a c-struct +;;; record; and a, a pointer to the array of 10 ints. +;;; +;;; The INLINE declaration eliminates some efficiency notes about heap +;;; allocation of Alien values. +(declaim (inline c-function)) +(def-alien-routine c-function + (* (struct c-struct)) + (i int) + (s c-string) + (r (* (struct c-struct))) + (a (array int 10))) + +;;; A function which sets up the parameters to the C function and +;;; actually calls it. +(defun call-cfun () + (with-alien ((ar (array int 10)) + (c-struct (struct c-struct))) + (dotimes (i 10) ; Fill array. + (setf (deref ar i) i)) + (setf (slot c-struct 'x) 20) + (setf (slot c-struct 's) "A Lisp String") + + (with-alien ((res (* (struct c-struct)) + (c-function 5 "Another Lisp String" (addr c-struct) ar))) + (format t "Returned from C function.~%") + (multiple-value-prog1 + (values (slot res 'x) + (slot res 's)) + ;; + ;; Deallocate result {\em after} we are done using it. + (free-alien res))))) +\end{lisp} + +To execute the above example, it is necessary to compile the C routine as +follows: + +\begin{example} +cc -c test.c +\end{example} + +In order to enable incremental loading with some linkers, you may need to say: + +\begin{example} +cc -G 0 -c test.c +\end{example} + +Once the C code has been compiled, you can start up Lisp and load it in: + +\begin{example} +% lisp +;;; Lisp should start up with its normal prompt. + +;;; Compile the Lisp file. This step can be done separately. You don't have +;;; to recompile every time. +* (compile-file "test.lisp") + +;;; Load the foreign object file to define the necessary symbols. This must +;;; be done before loading any code that refers to these symbols. next block +;;; of comments are actually the output of LOAD-FOREIGN. Different linkers +;;; will give different warnings, but some warning about redefining the code +;;; size is typical. +* (load-foreign "test.o") + +;;; Running library:load-foreign.csh... +;;; Loading object file... +;;; Parsing symbol table... +Warning: "_gp" moved from #x00C082C0 to #x00C08460. +Warning: "end" moved from #x00C00340 to #x00C004E0. + +;;; o.k. now load the compiled Lisp object file. +* (load "test") + +;;; Now we can call the routine that sets up the parameters and calls the C +;;; function. +* (test-c-call::call-cfun) + +;;; The C routine prints the following information to standard output. +i = 5 +s = Another Lisp string +r->x = 20 +r->s = A Lisp string +a[0] = 0. +a[1] = 1. +a[2] = 2. +a[3] = 3. +a[4] = 4. +a[5] = 5. +a[6] = 6. +a[7] = 7. +a[8] = 8. +a[9] = 9. +;;; Lisp prints out the following information. +Returned from C function. +;;; Return values from the call to test-c-call::call-cfun. +10 +"A C string" +* +\end{example} + +If any of the foreign functions do output, they should not be called +from within \hemlock{}. Depending on the situation, various strange +behavior occurs. Under X, the output goes to the window in which Lisp +was started; on a terminal, the output will overwrite the \hemlock{} +screen image; in a \hemlock{} slave, standard output is +\file{/dev/null} by default, so any output is discarded. diff --git a/doc/cmu-user/cmu-user.dict b/doc/cmu-user/cmu-user.dict new file mode 100644 index 0000000000..ce86160b64 --- /dev/null +++ b/doc/cmu-user/cmu-user.dict @@ -0,0 +1,460 @@ +'BAR +VARREF +'TEST +UPCASE +ENDLISP +SUBSEQ +ENDDEFUN +FUNARGS +GENSYM +VARS +UNINTERNED +VAR +VSOURCE +CLISP +COND +MYSTUFF +TRADEOFFS +PATHNAME +LLISP +CMUCL +REF +YETMOREKEYS +CLEANUP +ARGS +DEFUN +ZOQ +FOO +'S +CLTL +MACROEXPANDS +MACROEXPANSION +PROXY +ERRORFUL +EQ +ECASE +PYTHON +DEFMACRO +PROMISCUOUS +FLAMAGE +DEBUGGABILITY +FEATUREFULNESS +DEBUGGABLE +ENDDEFVAR +MACROEXPANDED +DEFVAR +ENDDEFMAC +KWD +MGROUP +MSTAR +DEFMAC +OFFS +NOTINLINE +TRADEOFF +FUNCALL +SOMEVAL +SOMEFUN +CM +DEFTYPE +CONSING +FIXNUMS +BIGNUMS +FROB +'FOO +RECOMPILES +FTYPE +TYPECASE +TYPEP +UNTYPED +UNIONED +GLOBALS +MODICUM +MACREF +SLEAZING +ES +STEELE +ETYPECASE +'EQL +'IDENTITY +'FUN +LOCALFUN +ISQRT +ODDP +MYFUN +POS +ZOW +YOW +'YOW +CADR +ZEROP +RES +EXPT +PARED +PUSHING +'ING +RPLACD +IOTA +NTHCDR +NTH +CADDDR +RPLACA +CADDR +FIENDS +SQRT +'SQRT +LISPY +BLANKSPACE +MYCHAPTER +UNENCAPSULATED +ENCAPSULATIONS +UNENCAPSULATE +UNTRACED +UNTRACE +EVALED +SPEC +PUSHES +TRUENAME +MYMAC +UNINFORMATIVE +FOOBAR +BAZ +BACKQUOTE +MALFORMED +MOREKEYS +FUNREF +QUIRKS +UNDILUTED +DISASSEMBLY +NAN +DENORMALIZED +ENDDEFCONST +DEFCONST +HASHTABLES +EFF +OBFUSCATING +SNOC +GRUE +GORP +FLO +NUM +VEC +MULTBY +SOMEOTHERFUN +'CHAR +NOTP +TESTP +FUNVAR +RAZ +ZUG +XFF +IO +GC'ING +EXT +MEGABYTE +SYS +UX +ED +MATCHMAKER +DIRED +PCL +CLOS +CONFORMANCE +ENDDEFCON +DEFCON +DECLAIM +DEFSTRUCT +ENUM +EXTERN +LOWERCASING +DEREFERENCED +MOPT +STRUCT +DEFTP +ENDDEFTP +MALLOC +CSH +PXLREF +ATYPE +CONSTRUCTUED +ANAME +PXREF +ENV +ONECOLUMN +TP +VR +FN +PRINTINDEX +UNNUMBERED +TWOCOLUMN +TLF +UNCOMPILED +DEACTIVATE +CALLABLE +UNREFERENCED +SUPPLIEDP +INTERNING +UNHANDLED +BACKTRACING +TEX +OOB +OBJ +PRIN +OBJS +GP +LINKERS +CC +AR +CFUN +INTS +SIZEOF +PRINTF +CFOO +SUBFORM +SVREF +STASH +FOOS +LC +LD +'N +'X +ERRNO +UPPERCASING +EXPR +ADDR +'STR +STR +DEREF +PTR +SWINDOW +IWINDOW +'SLIDER +DRAWABLE +'KEY +'EXT +TIMEOUTS +'MY +ID +PIXMAPS +'EQ +FUNCALLED +XWINDOW +'IH +SIGSTOP +GETPID +SIGTSTP +SCP +SIGINT +IH +CNT +GENERALRETURN +DEFMACX +'NUKEGARBAGE +GR +HASSLE +PREPENDS +TIMEOUT +FD +MSG +SYSCALL +UNHELPFUL +PREPENDED +VM +PAGEREF +INT +PORTSID +PORTSNAME +SERVPORT +KERN +DATATYPES +TTY +STDERR +STDOUT +STDIN +CMD +AUX +PS +UNACCOUNTED +RUNTIMES +PROFILER +UNPROFILE +REPROFILED +UNPROFILED +CF +ELT +VOPS +MAPCAR +OPTIONALS +CONSES +CONTORTIONS +ALISTS +ALIST +ASSOC +EXP +MYEXP +DEFCONSTANT +INCF +MEMQ +COERCIONS +EQL +LOGAND +AREF +CONSP +TYPEN +LOGIOR +EQUIV +SUPERTYPE +DEFMETHOD +SUBFORMS +CERROR +PSETQ +TAGBODY +DOTIMES +PLOQ +ROQ +SPECS +MPLUS +STEPPER +FDEFINITION +FUNCALLABLE +ST +BR +DB +LB +LL +HFILL +PP +VPRINT +TH +ARGLISTS +SETQ +NAMESPACE +SUBFUNCTION +BACKTRACE +'B +FLET +ARG +'A +CPSUBINDEX +PROGN +CONTRIB +WEEKDAYS +GREENWICH +TIMEZONE +DEST +WEEKDAY +JAN +CINDEX +NAMESTRING +PATHNAMES +FASL +SIGSEGV +PLIST +'ABLE +SETF +PID +EXECVE +DEV +SUBPROCESS +PTY +'TH +UNSUPPLIED +DEFVARX +GCS +CONSED +GC'ED +GC +TRASHING +XLIB +CL +HI +COMMONLOOPS +CTRL +XLREF +DEFUNX +DEFCONSTX +SUBSUBSECTION +VINDEXED +TINDEXED +RESEARCHCREDIT +EM +WHOLEY +SKEF +KAUFMANN +TODD +KOLOJEJCHICK +BUSDIECKER +'' +NOINDENT +MOORE +TIM +LOTT +LEINEN +HALLGREN +GLEICHAUF +DUNNING +TED +BADER +MYLISP +NOINIT +FINDEXED +INIT +EVAL +SUBDIRECTORIES +COPYRIGHTED +FTP +LANG +COMP +MEG +MEGABYTES +UNCOMPRESS +CD +OS +USERNAME +SLISP +RT +LIB +SETENV +SAMP +SETPATH +LOGIN +MISC +USR +MODMISC +TXT +DOC +EXECUTABLES +PERQ +UNTAGGED +BENCHMARKING +WINDOWING +INTRO +DOCS +EDU +AFS +VSPACE +IFINFO +DIR +SETFILENAME +TABLEOFCONTENTS +PAGENUMBERING +CLEARPAGE +MAKETITLE +ARPASUPPORT +CITATIONINFO +TRNUMBER +IFTEX +SUNOS +SPARC +DECSTATIONS +THEABSTRACT +DEF +KY +CP +NEWINDEX +ALWAYSREFILL +PAGESTYLE +CMULISP +TITLEPAGE +ELISP +LATEXINFO +DOCUMENTSTYLE diff --git a/doc/cmu-user/cmu-user.hva b/doc/cmu-user/cmu-user.hva new file mode 100644 index 0000000000..a5a4e2dd21 --- /dev/null +++ b/doc/cmu-user/cmu-user.hva @@ -0,0 +1,189 @@ +% -*- tex -*- +% +% This file contains macros which are used when translating +% to HTML using Hevea. By Luc Maranget and Eric Marsden. + +\newif\ifhmode\hmodefalse +\newcommand{\pdfinfo}[1]{\@print{}} +\let\hbox\mbox +\def\hfil{} +\def\hfill{} +\newcommand{\parbox}[3][]{\mbox{#3}} +\newcommand{\lengthtest}[1]{true} +\newenvironment{minipage}[2][]{}{} +\newcommand{\layout}[5][] + {\@open{DIV}{align=left}#5% + [#4] \\ + \begin{tabbing} + \fcnname{#1}\fcnname{#2} #3 \@print{   } + \end{tabbing} + \@close{DIV}} +\newcommand{\keys}[1]{\code{\&key}\@print{ }\= #1} + +\renewcommand{\textgreater}{\@print{>}} +\renewcommand{\textless}{\@print{<}} + +% \newcommand{\layout}[4][] +% {\begin{tabular} +% {llp{10cm}@{\hspace{10cm}}r}\fcnname{#1} & +% \fcnname{#2} & +% \begin{flushleft}#3\end{flushleft} & +% [#4] +% \end{tabular}} + + +\newcommand{\fcntype}[1]{\@styleattr{TT}{class=function-type}#1\@clearstyle} +\newcommand{\argtype}[1]{\@styleattr{TT}{class=argument-type}#1\@clearstyle} +\newcommand{\fcnname}[1]{\@styleattr{TT}{class=function-name}#1\@clearstyle} +\newcommand{\var}[1]{\@styleattr{TT}{class=variable}#1\@clearstyle} +\newcommand{\code}[1]{\@styleattr{TT}{class=code}#1\@clearstyle} +\newcommand{\file}[1]{\@styleattr{TT}{class=filename}#1\@clearstyle} + +%% Define a new type +%% +%% \begin{deftp}{typeclass}{typename}{args} +%% some description +%% \end{deftp} +\newenvironment{deftp}[3] + {\layout{#2}{\var{#3}}{#1}% + {\bigskip\index[types]{#2|textbf}} + \begin{quote}} + {\end{quote}} + +%% Define a function +%% +%% \begin{defun}[suffix]{pkg}{name}{params} +%% \defunx[pkg]{name}{params} +%% description of function +%% \end{defun} +\newenvironment{defun}[4][] + {\layout[#2]{#3}{#4}{Function}% + {\defunvspace\fnindexbold{#3}\label{FN:#3#1}} + \begin{quote}} + {\end{quote}} +\newcommand{\defunx}[3][\mbox{}]{% + \layout[#1]{#2}{#3}{Function}% + {\fnindexbold{#2}\label{FN:#2}}} + +%% Define a macro +%% +%% \begin{defmac}[suffix]{pkg}{name}{params} +%% \defmacx[pkg]{name}{params} +%% description of macro +%% \end{defmac} +\newenvironment{defmac}[4][]{% + \layout[#2]{#3}{#4}{Macro}% + {\defunvspace\fnindexbold{#3}\label{FN:#3#1}} + \begin{quote}} + {\end{quote}} +\newcommand{\defmacx}[3][\mbox{}]{% + \layout[#1]{#2}{#3}{Function}% + {\fnindexbold{#2}\label{FN:#2}}} + +%% Define a variable +%% +%% \begin{defvar}{pkg}{name} +%% \defvarx[pkg]{name} +%% description of defvar +%% \end{defvar} +\newenvironment{defvar}[2]{% + \layout[#1]{*#2*}{}{Variable}% + {\defunvspace\vrindexbold{#2}\label{VR:#2}} + \begin{quote}} + {\end{quote}} +\newcommand{\defvarx}[2][\mbox{}]{% + \layout[#1]{*#2*}{}{Variable}% + {\vrindexbold{#2}\label{VR:#2}}} + +%% Define a constant +%% +%% \begin{defconst}{pkg}{name} +%% \defconstx[pkg]{name} +%% description of defconst +%% \end{defconst} +\newenvironment{defconst}[2]{% + \layout[#1]{#2}{}{Constant}% + {\defunvspace} + \begin{quote}} + {\end{quote}} +\newcommand{\defconstx}[2][\mbox{}]{% + \layout[#1]{#2}{}{Constant}{}} + + + +% \@hr[NOSHADE]{.8\linewidth}{} +\newenvironment{example} + {\@open{BLOCKQUOTE}{class=example}\begin{alltt}} + {\end{alltt}\@close{BLOCKQUOTE}} +\newenvironment{lisp} + {\@open{BLOCKQUOTE}{CLASS=lisp}\begin{alltt}} + {\end{alltt}\@close{BLOCKQUOTE}} +\newcommand{\cmucl}{{\scshape cmucl}} + + +% there are no page numbers in HTML, so we need to override certain +% cross-referencing macros +\newcommand{\pxlref}[1]{see section~\ref{#1}} +\newcommand{\xlref}[1]{See section~\ref{#1}} +\newcommand{\funref}[1]{\findexed{#1}} +\newcommand{\specref}[1]{\findexed{#1}} +\newcommand{\macref}[1]{\findexed{#1}} +\newcommand{\varref}[1]{\vindexed{#1}} +\newcommand{\conref}[1]{\conindexed{#1}} +\newcommand{\ctrl}[1]{\code{Ctrl-#1}} +\newcommand{\result}{==>} +\newcommand{\myequiv}{<==>} +\newcommand{\mopt}[1]{\code{\{#1\}}} +\newcommand{\mstar}[1]{\code{\{#1\}}$^*$} +\newcommand{\mplus}[1]{\code{\{#1\}}$^+$} +\newcommand{\mgroup}[1]{\code{\{#1\}}} + + +% disable ``this document generated by'' footer +\def\@footer{} + +% \htmlhead{\@print{ +% CMUCL -> +% Documentation
} +% \@hr[NOSHADE]{.8\linewidth}{}\@print{
}} +% \htmlfoot{\@hr[NOSHADE]{.99\linewidth}{} +% \copyright{} 1995-2003 CMUCL Project} + + +\let\orig@meta=\@meta +\renewcommand{\@meta}{% +\orig@meta +\begin{rawhtml} + + +\end{rawhtml}} + + +% when generating HTML, produce file names based on the chapter name +% instead of machine-generated numbers +\let\orig@input\input +\renewcommand{\input}[1]{\orig@input{#1}\cutname{#1.html}} +\htmlprefix{CMUCL User's Manual: } + + +% generate HTML with section headers on a blue background + +\setcounter{cuttingdepth}{10} + +\input{report.hva} +%%\input{fancysection.hva} +\usepackage{color} +\definecolor{chapter}{rgb}{1, 1, 0.74} +\definecolor{part}{rgb}{1, 1, 0.81} +\definecolor{section}{rgb}{1, 1, 0.83} +\definecolor{subsection}{rgb}{1, 1, 0.89} +\definecolor{subsubsection}{rgb}{1, 1, 0.93} +\newstyle{.chapter}{padding:0.5ex;background-color:\@getstylecolor{chapter}} +\newstyle{.section} {padding:.5ex;background-color:\@getstylecolor{section}}% +\newstyle{.subsection} {padding:0.3ex;background-color:\@getstylecolor{subsection}}% +\newstyle{.subsubsection} {padding:0.5ex;background-color:\@getstylecolor{subsubsection}}% +\newstyle{.paragraph} {padding:0.5ex;background-color:\@getstylecolor{paragraph}}% +\renewcommand{\@bodyargs}{} + + +% EOF diff --git a/doc/cmu-user/cmu-user.tex b/doc/cmu-user/cmu-user.tex new file mode 100644 index 0000000000..743300e28b --- /dev/null +++ b/doc/cmu-user/cmu-user.tex @@ -0,0 +1,146 @@ +%% cmu-user.tex --- CMUCL User's Manual +%% +%% 2001-04-05 Eric Marsden +%% Modifications to work with hevea and pdflatex. +%% +%% Aug 1997 Raymond Toy +%% This is a modified version of the original CMUCL User's Manual. +%% The key changes are modification of this file to use standard +%% LaTeX2e. This means latexinfo isn't going to work anymore. +%% However, Latex2html support has been added. +%% +%% Jan 1998 Paul Werkowski +%% A few of the packages below are not part of the standard LaTeX2e +%% distribution, and must be obtained from a repository. At this time +%% I was able to fetch from +%% ftp.cdrom.com:pub/tex/ctan/macros/latex/contrib/supported/ +%% camel/index.ins +%% camel/index.dtx +%% calc/calc.ins +%% calc/calc.dtx +%% changebar/changebar.ins +%% changebar/changebar.dtx +%% One runs latex on the .ins file to produce .tex and/or .sty +%% files that must be put in a path searched by latex. +%% +%% Note all of the required packages are included in the teTeX distribution, +%% and a current version of latex2html can be obtained from: +%% http://saftsack.fs.uni-bayreuth.de/~latex2ht/ + +%% Delete "[a4paper]" if you don't want this formatted for A4 paper. +\documentclass[a4paper]{report} +\usepackage{xspace} +\usepackage{alltt} +\usepackage{index} +\usepackage{ifpdf} +\usepackage{ifthen} +\usepackage{calc} +\usepackage{sectsty} +\usepackage{varioref} +\usepackage[hyperindex=false,colorlinks=false,urlcolor=blue]{hyperref} +%% \usepackage{html} +\usepackage{typehtml} + +\input{macros} + +\title{CMUCL User's Manual} +\author{Robert A. MacLachlan, \textit{Editor}} +\newcommand{\keywords}{lisp, Common Lisp, manual, compiler, programming +language implementation, programming environment} + +\date{October 2017 \\ 21c} + + +\begin{document} + +\begin{titlepage} + \makeatletter + \vspace{60pt} + \begin{center} + \rule{\linewidth}{0.7mm} + \vspace{3em} + {\Huge \@title \par} + \vspace{4em} + {\large + \begin{tabular}[t]{c} + \@author + \end{tabular}\par} + \vspace{2em} + {\large \@date \par} + \vspace{2em} + \rule{\linewidth}{0.7mm} + \end{center} + \vfill + + \begin{quotation} + \cmucl{} is a free, high-performance implementation of the Common Lisp + programming language, which runs on most major Unix platforms. It + mainly conforms to the ANSI Common Lisp Standard. \cmucl{} features a + sophisticated native-code compiler, a foreign function interface, a + graphical source-level debugger, an interface to the X11 Window + System, and an Emacs-like editor. + + \medskip \textbf{Keywords}: \keywords + \end{quotation} + + \vspace{5cm} + + This manual is based on CMU Technical Report CMU-CS-92-161, edited by + Robert A. MacLachlan, dated July 1992. + + \thispagestyle{empty} + \makeatother +\end{titlepage} + +\ifpdf +\pdfinfo{ +/Author (Robert A. MacLachlan, ed) +/Title (CMUCL User's Manual) +/Keywords (\keywords) +} +% Add section numbers to the bookmarks, and open 2 levels by default. +\hypersetup{bookmarksnumbered=true, + bookmarksopen=true, + bookmarksopenlevel=2} +\fi + +% \maketitle + +\pagestyle{headings} +\pagenumbering{roman} +\tableofcontents + +\clearpage +\pagenumbering{arabic} + +\input{introduction} +\input{extensions} +\input{debugger} +\input{compiler} +\input{compiler-hint} +\input{unix} +\input{serve-event} +\input{aliens} +\input{ipc} +\input{internet} +\input{debug-internals} +\input{cross-referencing} +\input{unicode} + +\twocolumn +\cindex{Function Index} +\printindex[funs] + +\twocolumn +\cindex{Variable Index} +\printindex[vars] + +\twocolumn +\cindex{Type Index} +\printindex[types] + +\onecolumn +\cindex{Concept Index} +\printindex[concept] + +\end{document} diff --git a/doc/cmu-user/cmucl.css b/doc/cmu-user/cmucl.css new file mode 100644 index 0000000000..c65761f2f4 --- /dev/null +++ b/doc/cmu-user/cmucl.css @@ -0,0 +1,85 @@ +html { + color: black; + background-color: white; + margin-left: 4%; + margin-right: 2%; +} + +h1 { + text-align: center; + font-family: Helvetica, Arial, sans-serif +} + +h2 { + color: #515e4b; + font-family: Helvetica, Arial, sans-serif +} + +h3 { + font-family: Helvetica, Arial, sans-serif; +} + +.lisp { + background: #aaaaaa; + border:solid #aaaaaa 0.1px; + white-space:pre; + font-family: sans-serif; +} + +.example { + background: #cccccc; + border:solid #cccccc 0.1px; + white-space:pre; +} + +.code { + background: #faf0e6; + border:solid #faf0e6 1px; + white-space:pre-line; +} + +.technical { + background: #dddddd; + border: solid black 1px; + padding-left: 1em; + padding-right: 1em; + padding-top: 1ex; + padding-bottom: 1ex; + font-size: smaller; + font-stretch: semi-condensed; + margin-left: 10%; +} + +.credits { + background: #eeeeee; + font-stretch: condensed; + font-size: 0.8em; + font-family: Helvetica, Arial, sans-serif; + text-align: right; +} + +.function-name { + color: rgb(25%,0%,0%); +} + +.variable { + color: rgb(0%,25%,0%); +} + + +A:link +{ + text-decoration: none +} +A:active +{ + text-decoration: none +} +A:visited +{ + text-decoration: none +} +A:hover +{ + text-decoration: underline +} diff --git a/doc/cmu-user/compiler-hint.tex b/doc/cmu-user/compiler-hint.tex new file mode 100644 index 0000000000..2e68a37fb3 --- /dev/null +++ b/doc/cmu-user/compiler-hint.tex @@ -0,0 +1,4138 @@ +\chapter{Advanced Compiler Use and Efficiency Hints} +\label{advanced-compiler} + +\credits{by Robert MacLachlan} + + +\section{Advanced Compiler Introduction} + +In \cmucl{}, as with any language on any computer, the path to efficient +code starts with good algorithms and sensible programming techniques, +but to avoid inefficiency pitfalls, you need to know some of this +implementation's quirks and features. This chapter is mostly a fairly +long and detailed overview of what optimizations \python{} does. +Although there are the usual negative suggestions of inefficient +features to avoid, the main emphasis is on describing the things that +programmers can count on being efficient. + +The optimizations described here can have the effect of speeding up +existing programs written in conventional styles, but the potential +for new programming styles that are clearer and less error-prone is at +least as significant. For this reason, several sections end with a +discussion of the implications of these optimizations for programming +style. + + + +\subsection{Types} + +\python{}'s support for types is unusual in three major ways: +\begin{itemize} + +\item Precise type checking encourages the specific use of type + declarations as a form of run-time consistency checking. This + speeds development by localizing type errors and giving more + meaningful error messages. \xlref{precise-type-checks}. \python{} + produces completely safe code; optimized type checking maintains + reasonable efficiency on conventional hardware + (\pxlref{type-check-optimization}.) + +\item Comprehensive support for the \clisp{} type system makes complex + type specifiers useful. Using type specifiers such as \code{or} and + \code{member} has both efficiency and robustness advantages. + \xlref{advanced-type-stuff}. + +\item Type inference eliminates the need for some declarations, and + also aids compile-time detection of type errors. Given detailed + type declarations, type inference can often eliminate type checks + and enable more efficient object representations and code sequences. + Checking all types results in fewer type checks. See sections + \ref{type-inference} and \ref{non-descriptor}. +\end{itemize} + + +\subsection{Optimization} + +The main barrier to efficient Lisp programs is not that there is no +efficient way to code the program in Lisp, but that it is difficult to +arrive at that efficient coding. \clisp{} is a highly complex +language, and usually has many semantically equivalent ``reasonable'' +ways to code a given problem. It is desirable to make all of these +equivalent solutions have comparable efficiency so that programmers +don't have to waste time discovering the most efficient solution. + +Source level optimization increases the number of efficient ways to +solve a problem. This effect is much larger than the increase in the +efficiency of the ``best'' solution. Source level optimization +transforms the original program into a more efficient (but equivalent) +program. Although the optimizer isn't doing anything the programmer +couldn't have done, this high-level optimization is important because: + +\begin{itemize} +\item The programmer can code simply and directly, rather than + obfuscating code to please the compiler. + +\item When presented with a choice of similar coding alternatives, the + programmer can chose whichever happens to be most convenient, + instead of worrying about which is most efficient. +\end{itemize} + +Source level optimization eliminates the need for macros to optimize +their expansion, and also increases the effectiveness of inline +expansion. See sections \ref{source-optimization} and +\ref{inline-expansion}. + +Efficient support for a safer programming style is the biggest +advantage of source level optimization. Existing tuned programs +typically won't benefit much from source optimization, since their +source has already been optimized by hand. However, even tuned +programs tend to run faster under \python{} because: + +\begin{itemize} +\item Low level optimization and register allocation provides modest + speedups in any program. + +\item Block compilation and inline expansion can reduce function call + overhead, but may require some program restructuring. See sections + \ref{inline-expansion}, \ref{local-call} and + \ref{block-compilation}. + +\item Efficiency notes will point out important type declarations that + are often missed even in highly tuned programs. + \xlref{efficiency-notes}. + +\item Existing programs can be compiled safely without prohibitive + speed penalty, although they would be faster and safer with added + declarations. \xlref{type-check-optimization}. + +\item The context declaration mechanism allows both space and runtime + of large systems to be reduced without sacrificing robustness by + semi-automatically varying compilation policy without addition any + \code{optimize} declarations to the source. + \xlref{context-declarations}. + +\item Byte compilation can be used to dramatically reduce the size of + code that is not speed-critical. \xlref{byte-compile} +\end{itemize} + + +\subsection{Function Call} + +The sort of symbolic programs generally written in \llisp{} often +favor recursion over iteration, or have inner loops so complex that +they involve multiple function calls. Such programs spend a larger +fraction of their time doing function calls than is the norm in other +languages; for this reason \llisp{} implementations strive to make the +general (or full) function call as inexpensive as possible. \python{} +goes beyond this by providing two good alternatives to full call: + +\begin{itemize} +\item Local call resolves function references at compile time, + allowing better calling sequences and optimization across function + calls. \xlref{local-call}. + +\item Inline expansion totally eliminates call overhead and allows + many context dependent optimizations. This provides a safe and + efficient implementation of operations with function semantics, + eliminating the need for error-prone macro definitions or manual + case analysis. Although most \clisp{} implementations support + inline expansion, it becomes a more powerful tool with \python{}'s + source level optimization. See sections \ref{source-optimization} + and \ref{inline-expansion}. +\end{itemize} + + +Generally, \python{} provides simple implementations for simple uses +of function call, rather than having only a single calling convention. +These features allow a more natural programming style: + +\begin{itemize} +\item Proper tail recursion. \xlref{tail-recursion} + +\item Relatively efficient closures. + +\item A \code{funcall} that is as efficient as normal named call. + +\item Calls to local functions such as from \code{labels} are + optimized: +\begin{itemize} + +\item Control transfer is a direct jump. + +\item The closure environment is passed in registers rather than heap + allocated. + +\item Keyword arguments and multiple values are implemented more + efficiently. +\end{itemize} + +\xlref{local-call}. +\end{itemize} + + +\subsection{Representation of Objects} + +Sometimes traditional \llisp{} implementation techniques compare so +poorly to the techniques used in other languages that \llisp{} can +become an impractical language choice. Terrible inefficiencies appear +in number-crunching programs, since \llisp{} numeric operations often +involve number-consing and generic arithmetic. \python{} supports +efficient natural representations for numbers (and some other types), +and allows these efficient representations to be used in more +contexts. \python{} also provides good efficiency notes that warn +when a crucial declaration is missing. + +See section \ref{non-descriptor} for more about object representations and +numeric types. Also \pxlref{efficiency-notes} about efficiency notes. + + +\subsection{Writing Efficient Code} +\label{efficiency-overview} + +Writing efficient code that works is a complex and prolonged process. +It is important not to get so involved in the pursuit of efficiency +that you lose sight of what the original problem demands. Remember +that: +\begin{itemize} + +\item The program should be correct\dash{}it doesn't matter how + quickly you get the wrong answer. + +\item Both the programmer and the user will make errors, so the + program must be robust\dash{}it must detect errors in a way that + allows easy correction. + +\item A small portion of the program will consume most of the + resources, with the bulk of the code being virtually irrelevant to + efficiency considerations. Even experienced programmers familiar + with the problem area cannot reliably predict where these ``hot + spots'' will be. +\end{itemize} + + + +The best way to get efficient code that is still worth using, is to separate +coding from tuning. During coding, you should: +\begin{itemize} + +\item Use a coding style that aids correctness and robustness without + being incompatible with efficiency. + +\item Choose appropriate data structures that allow efficient + algorithms and object representations + (\pxlref{object-representation}). Try to make interfaces abstract + enough so that you can change to a different representation if + profiling reveals a need. + +\item Whenever you make an assumption about a function argument or + global data structure, add consistency assertions, either with type + declarations or explicit uses of \code{assert}, \code{ecase}, etc. +\end{itemize} + +During tuning, you should: +\begin{itemize} + +\item Identify the hot spots in the program through profiling (section + \ref{profiling}.) + +\item Identify inefficient constructs in the hot spot with efficiency + notes, more profiling, or manual inspection of the source. See + sections \ref{general-efficiency} and \ref{efficiency-notes}. + +\item Add declarations and consider the application of optimizations. + See sections \ref{local-call}, \ref{inline-expansion} and + \ref{non-descriptor}. + +\item If all else fails, consider algorithm or data structure changes. + If you did a good job coding, changes will be easy to introduce. +\end{itemize} + + +\section{More About Types in Python} +\label{advanced-type-stuff} +\cpsubindex{types}{in python} + +This section goes into more detail describing what types and declarations are +recognized by \python. The area where \python{} differs most radically from +previous \llisp{} compilers is in its support for types: +\begin{itemize} + +\item Precise type checking helps to find bugs at run time. + +\item Compile-time type checking helps to find bugs at compile time. + +\item Type inference minimizes the need for generic operations, and + also increases the efficiency of run time type checking and the + effectiveness of compile time type checking. + +\item Support for detailed types provides a wealth of opportunity for + operation-specific type inference and optimization. +\end{itemize} + + + +\subsection{More Types Meaningful} + +\clisp{} has a very powerful type system, but conventional \llisp{} +implementations typically only recognize the small set of types +special in that implementation. In these systems, there is an +unfortunate paradox: a declaration for a relatively general type like +\code{fixnum} will be recognized by the compiler, but a highly +specific declaration such as \code{\w{(integer 3 17)}} is totally +ignored. + +This is obviously a problem, since the user has to know how to specify +the type of an object in the way the compiler wants it. A very +minimal (but rarely satisfied) criterion for type system support is +that it be no worse to make a specific declaration than to make a +general one. \python{} goes beyond this by exploiting a number of +advantages obtained from detailed type information. + +Using more restrictive types in declarations allows the compiler to do +better type inference and more compile-time type checking. Also, when +type declarations are considered to be consistency assertions that +should be verified (conditional on policy), then complex types are +useful for making more detailed assertions. + +\python{} ``understands'' the list-style \code{or}, \code{member}, +\code{function}, array and number type specifiers. Understanding +means that: +\begin{itemize} + +\item If the type contains more information than is used in a + particular context, then the extra information is simply ignored, + rather than derailing type inference. + +\item In many contexts, the extra information from these type + specifier is used to good effect. In particular, type checking in + \python{} is \var{precise}, so these complex types can be used + in declarations to make interesting assertions about functions and + data structures (\pxlref{precise-type-checks}.) More specific + declarations also aid type inference and reduce the cost for type + checking. +\end{itemize} + +For related information, \pxlref{numeric-types} for numeric types, and +section \ref{array-types} for array types. + + +\subsection{Canonicalization} +\cpsubindex{types}{equivalence} +\cindex{canonicalization of types} +\cindex{equivalence of types} + +When given a type specifier, \python{} will often rewrite it into a +different (but equivalent) type. This is the mechanism that \python{} +uses for detecting type equivalence. For example, in \python{}'s +canonical representation, these types are equivalent: +\begin{example} +(or list (member :end)) \myequiv (or cons (member nil :end)) +\end{example} +This has two implications for the user: +\begin{itemize} + +\item The standard symbol type specifiers for \code{atom}, + \code{null}, \code{fixnum}, etc., are in no way magical. The + \tindexed{null} type is actually defined to be \code{\w{(member + nil)}}, \tindexed{list} is \code{\w{(or cons null)}}, and + \tindexed{fixnum} is \code{\w{(signed-byte 30)}}. + +\item When the compiler prints out a type, it may not look like the + type specifier that originally appeared in the program. This is + generally not a problem, but it must be taken into consideration + when reading compiler error messages. +\end{itemize} + + +\subsection{Member Types} +\cindex{member types} + +The \tindexed{member} type specifier can be used to represent +``symbolic'' values, analogous to the enumerated types of Pascal. For +example, the second value of \code{find-symbol} has this type: +\begin{lisp} +(member :internal :external :inherited nil) +\end{lisp} +Member types are very useful for expressing consistency constraints on data +structures, for example: +\begin{lisp} +(defstruct ice-cream + (flavor :vanilla :type (member :vanilla :chocolate :strawberry))) +\end{lisp} +Member types are also useful in type inference, as the number of members can +sometimes be pared down to one, in which case the value is a known constant. + + +\subsection{Union Types} +\cindex{union (\code{or}) types} +\cindex{or (union) types} + +The \tindexed{or} (union) type specifier is understood, and is +meaningfully applied in many contexts. The use of \code{or} allows +assertions to be made about types in dynamically typed programs. For +example: + +\begin{lisp} +(defstruct box + (next nil :type (or box null)) + (top :removed :type (or box-top (member :removed)))) +\end{lisp} + +The type assertion on the \code{top} slot ensures that an error will be signaled +when there is an attempt to store an illegal value (such as \kwd{rmoved}.) +Although somewhat weak, these union type assertions provide a useful input into +type inference, allowing the cost of type checking to be reduced. For example, +this loop is safely compiled with no type checks: + +\begin{lisp} +(defun find-box-with-top (box) + (declare (type (or box null) box)) + (do ((current box (box-next current))) + ((null current)) + (unless (eq (box-top current) :removed) + (return current)))) +\end{lisp} + +Union types are also useful in type inference for representing types that are +partially constrained. For example, the result of this expression: +\begin{lisp} +(if foo + (logior x y) + (list x y)) +\end{lisp} +can be expressed as \code{\w{(or integer cons)}}. + + +\subsection{The Empty Type} +\label{empty-type} +\cindex{NIL type} +\cpsubindex{empty type}{the} +\cpsubindex{errors}{result type of} + +The type \false{} is also called the empty type, since no object is of +type \false{}. The union of no types, \code{(or)}, is also empty. +\python{}'s interpretation of an expression whose type is \false{} is +that the expression never yields any value, but rather fails to +terminate, or is thrown out of. For example, the type of a call to +\code{error} or a use of \code{return} is \false{}. When the type of +an expression is empty, compile-time type warnings about its value are +suppressed; presumably somebody else is signaling an error. If a +function is declared to have return type \false{}, but does in fact +return, then (in safe compilation policies) a ``\code{NIL Function + returned}'' error will be signaled. See also the function +\funref{required-argument}. + + +\subsection{Function Types} +\label{function-types} +\cpsubindex{function}{types} +\cpsubindex{types}{function} + +\findexed{function} types are understood in the restrictive sense, specifying: +\begin{itemize} + +\item The argument syntax that the function must be called with. This + is information about what argument counts are acceptable, and which + keyword arguments are recognized. In \python, warnings about + argument syntax are a consequence of function type checking. + +\item The types of the argument values that the caller must pass. If + the compiler can prove that some argument to a call is of a type + disallowed by the called function's type, then it will give a + compile-time type warning. In addition to being used for + compile-time type checking, these type assertions are also used as + output type assertions in code generation. For example, if + \code{foo} is declared to have a \code{fixnum} argument, then the + \code{1+} in \w{\code{(foo (1+ x))}} is compiled with knowledge that + the result must be a fixnum. + +\item The types the values that will be bound to argument variables in + the function's definition. Declaring a function's type with + \code{ftype} implicitly declares the types of the arguments in the + definition. \python{} checks for consistency between the definition + and the \code{ftype} declaration. Because of precise type checking, + an error will be signaled when a function is called with an + argument of the wrong type. + +\item The type of return value(s) that the caller can expect. This + information is a useful input to type inference. For example, if a + function is declared to return a \code{fixnum}, then when a call to + that function appears in an expression, the expression will be + compiled with knowledge that the call will return a \code{fixnum}. + +\item The type of return value(s) that the definition must return. + The result type in an \code{ftype} declaration is treated like an + implicit \code{the} wrapped around the body of the definition. If + the definition returns a value of the wrong type, an error will be + signaled. If the compiler can prove that the function returns the + wrong type, then it will give a compile-time warning. +\end{itemize} + +This is consistent with the new interpretation of function types and +the \code{ftype} declaration in the proposed X3J13 +``function-type-argument-type-semantics'' cleanup. Note also, that if +you don't explicitly declare the type of a function using a global +\code{ftype} declaration, then \python{} will compute a function type +from the definition, providing a degree of inter-routine type +inference, \pxlref{function-type-inference}. + + +\subsection{The Values Declaration} +\cindex{values declaration} + +\cmucl{} supports the \code{values} declaration as an extension to +\clisp. The syntax of the declaration is +{\code{(values \var{type1} \var{type2}$\ldots$\var{typen})}}. This +declaration is semantically equivalent to a \code{the} form wrapped +around the body of the special form in which the \code{values} +declaration appears. The advantage of \code{values} over +\findexed{the} is purely syntactic\dash{}it doesn't introduce more +indentation. For example: + +\begin{example} +(defun foo (x) + (declare (values single-float)) + (ecase x + (:this ...) + (:that ...) + (:the-other ...))) +\end{example} + +is equivalent to: + +\begin{example} +(defun foo (x) + (the single-float + (ecase x + (:this ...) + (:that ...) + (:the-other ...)))) +\end{example} + +and + +\begin{example} +(defun floor (number &optional (divisor 1)) + (declare (values integer real)) + ...) +\end{example} + +is equivalent to: + +\begin{example} +(defun floor (number &optional (divisor 1)) + (the (values integer real) + ...)) +\end{example} + +In addition to being recognized by \code{lambda} (and hence by +\code{defun}), the \code{values} declaration is recognized by all the +other special forms with bodies and declarations: \code{let}, +\code{let*}, \code{labels} and \code{flet}. Macros with declarations +usually splice the declarations into one of the above forms, so they +will accept this declaration too, but the exact effect of a +\code{values} declaration will depend on the macro. + +If you declare the types of all arguments to a function, and also +declare the return value types with \code{values}, you have described +the type of the function. \python{} will use this argument and result +type information to derive a function type that will then be applied +to calls of the function (\pxlref{function-types}.) This provides a +way to declare the types of functions that is much less syntactically +awkward than using the \code{ftype} declaration with a \code{function} +type specifier. + +Although the \code{values} declaration is non-standard, it is +relatively harmless to use it in otherwise portable code, since any +warning in non-CMU implementations can be suppressed with the standard +\code{declaration} proclamation. + + +\subsection{Structure Types} +\label{structure-types} +\cindex{structure types} +\cindex{defstruct types} +\cpsubindex{types}{structure} + +Because of precise type checking, structure types are much better +supported by \python{} than by conventional compilers: + +\begin{itemize} +\item The structure argument to structure accessors is precisely + checked\dash{}if you call \code{foo-a} on a \code{bar}, an error + will be signaled. + +\item The types of slot values are precisely checked\dash{}if you pass + the wrong type argument to a constructor or a slot setter, then an + error will be signaled. +\end{itemize} + +This error checking is tremendously useful for detecting bugs in +programs that manipulate complex data structures. + +An additional advantage of checking structure types and enforcing slot +types is that the compiler can safely believe slot type declarations. +\python{} effectively moves the type checking from the slot access to +the slot setter or constructor call. This is more efficient since +caller of the setter or constructor often knows the type of the value, +entirely eliminating the need to check the value's type. Consider +this example: + +\begin{lisp} +(defstruct coordinate + (x nil :type single-float) + (y nil :type single-float)) + +(defun make-it () + (make-coordinate :x 1.0 :y 1.0)) + +(defun use-it (it) + (declare (type coordinate it)) + (sqrt (expt (coordinate-x it) 2) (expt (coordinate-y it) 2))) +\end{lisp} + +\code{make-it} and \code{use-it} are compiled with no checking on the +types of the float slots, yet \code{use-it} can use +\code{single-float} arithmetic with perfect safety. Note that +\code{make-coordinate} must still check the values of \code{x} and +\code{y} unless the call is block compiled or inline expanded +(\pxlref{local-call}.) But even without this advantage, it is almost +always more efficient to check slot values on structure +initialization, since slots are usually written once and read many +times. + + +\subsection{The Freeze-Type Declaration} +\cindex{freeze-type declaration} +\label{freeze-type} + +The \code{extensions:freeze-type} declaration is a \cmucl{} extension that +enables more efficient compilation of user-defined types by asserting +that the definition is not going to change. This declaration may only +be used globally (with \code{declaim} or \code{proclaim}). Currently +\code{freeze-type} only affects structure type testing done by +\code{typep}, \code{typecase}, etc. Here is an example: + +\begin{lisp} +(declaim (freeze-type foo bar)) +\end{lisp} + +This asserts that the types \code{foo} and \code{bar} and their +subtypes are not going to change. This allows more efficient type +testing, since the compiler can open-code a test for all possible +subtypes, rather than having to examine the type hierarchy at +run-time. + + +\subsection{Type Restrictions} +\cpsubindex{types}{restrictions on} + +Avoid use of the \code{and}, \code{not} and \code{satisfies} types in +declarations, since type inference has problems with them. When these +types do appear in a declaration, they are still checked precisely, +but the type information is of limited use to the compiler. +\code{and} types are effective as long as the intersection can be +canonicalized to a type that doesn't use \code{and}. For example: + +\begin{example} +(and fixnum unsigned-byte) +\end{example} + +is fine, since it is the same as: + +\begin{example} +(integer 0 \var{most-positive-fixnum}) +\end{example} + +but this type: + +\begin{example} +(and symbol (not (member :end))) +\end{example} + +will not be fully understood by type interference since the \code{and} +can't be removed by canonicalization. + +Using any of these type specifiers in a type test with \code{typep} or +\code{typecase} is fine, since as tests, these types can be translated +into the \code{and} macro, the \code{not} function or a call to the +satisfies predicate. + + +\subsection{Type Style Recommendations} +\cindex{style recommendations} + +\python{} provides good support for some currently unconventional ways of +using the \clisp{} type system. With \python{}, it is desirable to make +declarations as precise as possible, but type inference also makes +some declarations unnecessary. Here are some general guidelines for +maximum robustness and efficiency: +\begin{itemize} + +\item Declare the types of all function arguments and structure slots + as precisely as possible (while avoiding \code{not}, \code{and} and + \code{satisfies}). Put these declarations in during initial coding + so that type assertions can find bugs for you during debugging. + +\item Use the \tindexed{member} type specifier where there are a small + number of possible symbol values, for example: \w{\code{(member :red + :blue :green)}}. + +\item Use the \tindexed{or} type specifier in situations where the + type is not certain, but there are only a few possibilities, for + example: \w{\code{(or list vector)}}. + +\item Declare integer types with the tightest bounds that you can, + such as \code{\w{(integer 3 7)}}. + +\item Define \findexed{deftype} or \findexed{defstruct} types before + they are used. Definition after use is legal (producing no + ``undefined type'' warnings), but type tests and structure + operations will be compiled much less efficiently. + +\item Use the \code{extensions:freeze-type} declaration to speed up + type testing for structure types which won't have new subtypes added + later. \xlref{freeze-type} + +\item In addition to declaring the array element type and simpleness, + also declare the dimensions if they are fixed, for example: + \begin{example} + (simple-array single-float (1024 1024)) + \end{example} + This bounds information allows array indexing for multi-dimensional + arrays to be compiled much more efficiently, and may also allow + array bounds checking to be done at compile time. + \xlref{array-types}. + +\item Avoid use of the \findexed{the} declaration within expressions. + Not only does it clutter the code, but it is also almost worthless + under safe policies. If the need for an output type assertion is + revealed by efficiency notes during tuning, then you can consider + \code{the}, but it is preferable to constrain the argument types + more, allowing the compiler to prove the desired result type. + +\item Don't bother declaring the type of \findexed{let} or other + non-argument variables unless the type is non-obvious. If you + declare function return types and structure slot types, then the + type of a variable is often obvious both to the programmer and to + the compiler. An important case where the type isn't obvious, and a + declaration is appropriate, is when the value for a variable is + pulled out of untyped structure (e.g., the result of \code{car}), or + comes from some weakly typed function, such as \code{read}. + +\item Declarations are sometimes necessary for integer loop variables, + since the compiler can't always prove that the value is of a good + integer type. These declarations are best added during tuning, when + an efficiency note indicates the need. +\end{itemize} + + +\section{Type Inference} +\label{type-inference} +\cindex{type inference} +\cindex{inference of types} +\cindex{derivation of types} + +Type inference is the process by which the compiler tries to figure +out the types of expressions and variables, given an inevitable lack +of complete type information. Although \python{} does much more type +inference than most \llisp{} compilers, remember that the more precise +and comprehensive type declarations are, the more type inference will +be able to do. + + +\subsection{Variable Type Inference} +\label{variable-type-inference} + +The type of a variable is the union of the types of all the +definitions. In the degenerate case of a let, the type of the +variable is the type of the initial value. This inferred type is +intersected with any declared type, and is then propagated to all the +variable's references. The types of \findexed{multiple-value-bind} +variables are similarly inferred from the types of the individual +values of the values form. + +If multiple type declarations apply to a single variable, then all the +declarations must be correct; it is as though all the types were intersected +producing a single \tindexed{and} type specifier. In this example: +\begin{example} +(defmacro my-dotimes ((var count) &body body) + `(do ((,var 0 (1+ ,var))) + ((>= ,var ,count)) + (declare (type (integer 0 *) ,var)) + ,@body)) + +(my-dotimes (i ...) + (declare (fixnum i)) + ...) +\end{example} +the two declarations for \code{i} are intersected, so \code{i} is +known to be a non-negative fixnum. + +In practice, this type inference is limited to lets and local +functions, since the compiler can't analyze all the calls to a global +function. But type inference works well enough on local variables so +that it is often unnecessary to declare the type of local variables. +This is especially likely when function result types and structure +slot types are declared. The main areas where type inference breaks +down are: +\begin{itemize} + +\item When the initial value of a variable is a untyped expression, + such as \code{\w{(car x)}}, and + +\item When the type of one of the variable's definitions is a function + of the variable's current value, as in: \code{(setq x (1+ x))} +\end{itemize} + + +\subsection{Local Function Type Inference} +\cpsubindex{local call}{type inference} + +The types of arguments to local functions are inferred in the same was +as any other local variable; the type is the union of the argument +types across all the calls to the function, intersected with the +declared type. If there are any assignments to the argument +variables, the type of the assigned value is unioned in as well. + +The result type of a local function is computed in a special way that +takes tail recursion (\pxlref{tail-recursion}) into consideration. +The result type is the union of all possible return values that aren't +tail-recursive calls. For example, \python{} will infer that the +result type of this function is \code{integer}: + +\begin{lisp} +(defun ! (n res) + (declare (integer n res)) + (if (zerop n) + res + (! (1- n) (* n res)))) +\end{lisp} + +Although this is a rather obvious result, it becomes somewhat less +trivial in the presence of mutual tail recursion of multiple +functions. Local function result type inference interacts with the +mechanisms for ensuring proper tail recursion mentioned in section +\ref{local-call-return}. + + +\subsection{Global Function Type Inference} +\label{function-type-inference} +\cpsubindex{function}{type inference} + +As described in section \ref{function-types}, a global function type +(\tindexed{ftype}) declaration places implicit type assertions on the +call arguments, and also guarantees the type of the return value. So +wherever a call to a declared function appears, there is no doubt as +to the types of the arguments and return value. Furthermore, +\python{} will infer a function type from the function's definition if +there is no \code{ftype} declaration. Any type declarations on the +argument variables are used as the argument types in the derived +function type, and the compiler's best guess for the result type of +the function is used as the result type in the derived function type. + +This method of deriving function types from the definition implicitly assumes +that functions won't be redefined at run-time. Consider this example: +\begin{lisp} +(defun foo-p (x) + (let ((res (and (consp x) (eq (car x) 'foo)))) + (format t "It is ~:[not ~;~]foo." res))) + +(defun frob (it) + (if (foo-p it) + (setf (cadr it) 'yow!) + (1+ it))) +\end{lisp} + +Presumably, the programmer really meant to return \code{res} from +\code{foo-p}, but he seems to have forgotten. When he tries to call +do \code{\w{(frob (list 'foo nil))}}, \code{frob} will flame out when +it tries to add to a \code{cons}. Realizing his error, he fixes +\code{foo-p} and recompiles it. But when he retries his test case, he +is baffled because the error is still there. What happened in this +example is that \python{} proved that the result of \code{foo-p} is +\code{null}, and then proceeded to optimize away the \code{setf} in +\code{frob}. + +Fortunately, in this example, the error is detected at compile time +due to notes about unreachable code (\pxlref{dead-code-notes}.) +Still, some users may not want to worry about this sort of problem +during incremental development, so there is a variable to control +deriving function types. + +\begin{defvar}{extensions:}{derive-function-types} + + If true (the default), argument and result type information derived + from compilation of \code{defun}s is used when compiling calls to + that function. If false, only information from \code{ftype} + proclamations will be used. +\end{defvar} + + +\subsection{Operation Specific Type Inference} +\label{operation-type-inference} +\cindex{operation specific type inference} +\cindex{arithmetic type inference} +\cpsubindex{numeric}{type inference} + +Many of the standard \clisp{} functions have special type inference +procedures that determine the result type as a function of the +argument types. For example, the result type of \code{aref} is the +array element type. Here are some other examples of type inferences: +\begin{lisp} +(logand x #xFF) \result{} (unsigned-byte 8) + +(+ (the (integer 0 12) x) (the (integer 0 1) y)) \result{} (integer 0 13) + +(ash (the (unsigned-byte 16) x) -8) \result{} (unsigned-byte 8) +\end{lisp} + + +\subsection{Dynamic Type Inference} +\label{constraint-propagation} +\cindex{dynamic type inference} +\cindex{conditional type inference} +\cpsubindex{type inference}{dynamic} + +\python{} uses flow analysis to infer types in dynamically typed +programs. For example: + +\begin{example} +(ecase x + (list (length x)) + ...) +\end{example} + +Here, the compiler knows the argument to \code{length} is a list, +because the call to \code{length} is only done when \code{x} is a +list. The most significant efficiency effect of inference from +assertions is usually in type check optimization. + +Dynamic type inference has two inputs: explicit conditionals and +implicit or explicit type assertions. Flow analysis propagates these +constraints on variable type to any code that can be executed only +after passing though the constraint. Explicit type constraints come +from \findexed{if}s where the test is either a lexical variable or a +function of lexical variables and constants, where the function is +either a type predicate, a numeric comparison or \code{eq}. + +If there is an \code{eq} (or \code{eql}) test, then the compiler will +actually substitute one argument for the other in the true branch. +For example: +\begin{lisp} +(when (eq x :yow!) (return x)) +\end{lisp} +becomes: +\begin{lisp} +(when (eq x :yow!) (return :yow!)) +\end{lisp} +This substitution is done when one argument is a constant, or one +argument has better type information than the other. This +transformation reveals opportunities for constant folding or +type-specific optimizations. If the test is against a constant, then +the compiler can prove that the variable is not that constant value in +the false branch, or \w{\code{(not (member :yow!))}} in the example +above. This can eliminate redundant tests, for example: +\begin{example} +(if (eq x nil) + ... + (if x a b)) +\end{example} +is transformed to this: +\begin{example} +(if (eq x nil) + ... + a) +\end{example} +Variables appearing as \code{if} tests are interpreted as +\code{\w{(not (eq \var{var} nil))}} tests. The compiler also converts +\code{=} into \code{eql} where possible. It is difficult to do +inference directly on \code{=} since it does implicit coercions. + +When there is an explicit \code{\textless} or \code{\textgreater} test on numeric +variables, the compiler makes inferences about the ranges the +variables can assume in the true and false branches. This is mainly +useful when it proves that the values are small enough in magnitude to +allow open-coding of arithmetic operations. For example, in many uses +of \code{dotimes} with a \code{fixnum} repeat count, the compiler +proves that fixnum arithmetic can be used. + +Implicit type assertions are quite common, especially if you declare +function argument types. Dynamic inference from implicit type +assertions sometimes helps to disambiguate programs to a useful +degree, but is most noticeable when it detects a dynamic type error. +For example: + +\begin{lisp} +(defun foo (x) + (+ (car x) x)) +\end{lisp} + +results in this warning: + +\begin{example} +In: DEFUN FOO + (+ (CAR X) X) +==> + X +Warning: Result is a LIST, not a NUMBER. +\end{example} + +Note that \llisp{}'s dynamic type checking semantics make dynamic type +inference useful even in programs that aren't really dynamically +typed, for example: + +\begin{lisp} +(+ (car x) (length x)) +\end{lisp} + +Here, \code{x} presumably always holds a list, but in the absence of a +declaration the compiler cannot assume \code{x} is a list simply +because list-specific operations are sometimes done on it. The +compiler must consider the program to be dynamically typed until it +proves otherwise. Dynamic type inference proves that the argument to +\code{length} is always a list because the call to \code{length} is +only done after the list-specific \code{car} operation. + + +\subsection{Type Check Optimization} +\label{type-check-optimization} +\cpsubindex{type checking}{optimization} +\cpsubindex{optimization}{type check} + +\python{} backs up its support for precise type checking by minimizing +the cost of run-time type checking. This is done both through type +inference and though optimizations of type checking itself. + +Type inference often allows the compiler to prove that a value is of +the correct type, and thus no type check is necessary. For example: +\begin{lisp} +(defstruct foo a b c) +(defstruct link + (foo (required-argument) :type foo) + (next nil :type (or link null))) + +(foo-a (link-foo x)) +\end{lisp} + +Here, there is no need to check that the result of \code{link-foo} is +a \code{foo}, since it always is. Even when some type checks are +necessary, type inference can often reduce the number: +\begin{example} +(defun test (x) + (let ((a (foo-a x)) + (b (foo-b x)) + (c (foo-c x))) + ...)) +\end{example} +In this example, only one \w{\code{(foo-p x)}} check is needed. This +applies to a lesser degree in list operations, such as: +\begin{lisp} +(if (eql (car x) 3) (cdr x) y) +\end{lisp} +Here, we only have to check that \code{x} is a list once. + +Since \python{} recognizes explicit type tests, code that explicitly +protects itself against type errors has little introduced overhead due +to implicit type checking. For example, this loop compiles with no +implicit checks checks for \code{car} and \code{cdr}: +\begin{lisp} +(defun memq (e l) + (do ((current l (cdr current))) + ((atom current) nil) + (when (eq (car current) e) (return current)))) +\end{lisp} + +\cindex{complemented type checks} +\python{} reduces the cost of checks that must be done through an +optimization called \var{complementing}. A complemented check for +\var{type} is simply a check that the value is not of the type +\w{\code{(not \var{type})}}. This is only interesting when something +is known about the actual type, in which case we can test for the +complement of \w{\code{(and \var{known-type} (not \var{type}))}}, or +the difference between the known type and the assertion. An example: +\begin{lisp} +(link-foo (link-next x)) +\end{lisp} +Here, we change the type check for \code{link-foo} from a test for +\code{foo} to a test for: +\begin{lisp} +(not (and (or foo null) (not foo))) +\end{lisp} +or more simply \w{\code{(not null)}}. This is probably the most +important use of complementing, since the situation is fairly common, +and a \code{null} test is much cheaper than a structure type test. + +Here is a more complicated example that illustrates the combination of +complementing with dynamic type inference: +\begin{lisp} +(defun find-a (a x) + (declare (type (or link null) x)) + (do ((current x (link-next current))) + ((null current) nil) + (let ((foo (link-foo current))) + (when (eq (foo-a foo) a) (return foo))))) +\end{lisp} +This loop can be compiled with no type checks. The \code{link} test +for \code{link-foo} and \code{link-next} is complemented to +\w{\code{(not null)}}, and then deleted because of the explicit +\code{null} test. As before, no check is necessary for \code{foo-a}, +since the \code{link-foo} is always a \code{foo}. This sort of +situation shows how precise type checking combined with precise +declarations can actually result in reduced type checking. + + +\section{Source Optimization} +\label{source-optimization} +\cindex{optimization} + +This section describes source-level transformations that \python{} does on +programs in an attempt to make them more efficient. Although source-level +optimizations can make existing programs more efficient, the biggest advantage +of this sort of optimization is that it makes it easier to write efficient +programs. If a clean, straightforward implementation is can be transformed +into an efficient one, then there is no need for tricky and dangerous hand +optimization. + + +\subsection{Let Optimization} +\label{let-optimization} + +\cindex{let optimization} \cpsubindex{optimization}{let} + +The primary optimization of let variables is to delete them when they +are unnecessary. Whenever the value of a let variable is a constant, +a constant variable or a constant (local or non-notinline) function, +the variable is deleted, and references to the variable are replaced +with references to the constant expression. This is useful primarily +in the expansion of macros or inline functions, where argument values +are often constant in any given call, but are in general non-constant +expressions that must be bound to preserve order of evaluation. Let +variable optimization eliminates the need for macros to carefully +avoid spurious bindings, and also makes inline functions just as +efficient as macros. + +A particularly interesting class of constant is a local function. +Substituting for lexical variables that are bound to a function can +substantially improve the efficiency of functional programming styles, +for example: +\begin{lisp} +(let ((a #'(lambda (x) (zow x)))) + (funcall a 3)) +\end{lisp} +effectively transforms to: +\begin{lisp} +(zow 3) +\end{lisp} +This transformation is done even when the function is a closure, as in: +\begin{lisp} +(let ((a (let ((y (zug))) + #'(lambda (x) (zow x y))))) + (funcall a 3)) +\end{lisp} +becoming: +\begin{lisp} +(zow 3 (zug)) +\end{lisp} + +A constant variable is a lexical variable that is never assigned to, +always keeping its initial value. Whenever possible, avoid setting +lexical variables\dash{}instead bind a new variable to the new value. +Except for loop variables, it is almost always possible to avoid +setting lexical variables. This form: +\begin{example} +(let ((x (f x))) + ...) +\end{example} +is \var{more} efficient than this form: +\begin{example} +(setq x (f x)) +... +\end{example} +Setting variables makes the program more difficult to understand, both +to the compiler and to the programmer. \python{} compiles assignments +at least as efficiently as any other \llisp{} compiler, but most let +optimizations are only done on constant variables. + +Constant variables with only a single use are also optimized away, +even when the initial value is not constant.\footnote{The source + transformation in this example doesn't represent the preservation of + evaluation order implicit in the compiler's internal representation. + Where necessary, the back end will reintroduce temporaries to + preserve the semantics.} For example, this expansion of +\code{incf}: +\begin{lisp} +(let ((#:g3 (+ x 1))) + (setq x #:G3)) +\end{lisp} +becomes: +\begin{lisp} +(setq x (+ x 1)) +\end{lisp} +The type semantics of this transformation are more important than the +elimination of the variable itself. Consider what happens when +\code{x} is declared to be a \code{fixnum}; after the transformation, +the compiler can compile the addition knowing that the result is a +\code{fixnum}, whereas before the transformation the addition would +have to allow for fixnum overflow. + +Another variable optimization deletes any variable that is never read. +This causes the initial value and any assigned values to be unused, +allowing those expressions to be deleted if they have no side-effects. + +Note that a let is actually a degenerate case of local call +(\pxlref{let-calls}), and that let optimization can be done on calls +that weren't created by a let. Also, local call allows an applicative +style of iteration that is totally assignment free. + + +\subsection{Constant Folding} +\cindex{constant folding} +\cpsubindex{folding}{constant} + +Constant folding is an optimization that replaces a call of constant +arguments with the constant result of that call. Constant folding is +done on all standard functions for which it is legal. Inline +expansion allows folding of any constant parts of the definition, and +can be done even on functions that have side-effects. + +It is convenient to rely on constant folding when programming, as in this +example: +\begin{example} +(defconstant limit 42) + +(defun foo () + (... (1- limit) ...)) +\end{example} +Constant folding is also helpful when writing macros or inline +functions, since it usually eliminates the need to write a macro that +special-cases constant arguments. + +\cindex{constant-function declaration} Constant folding of a user +defined function is enabled by the \code{extensions:constant-function} +proclamation. In this example: +\begin{example} +(declaim (ext:constant-function myfun)) +(defun myexp (x y) + (declare (single-float x y)) + (exp (* (log x) y))) + + ... (myexp 3.0 1.3) ... +\end{example} +The call to \code{myexp} is constant-folded to \code{4.1711674}. + + +\subsection{Unused Expression Elimination} +\cindex{unused expression elimination} +\cindex{dead code elimination} + +If the value of any expression is not used, and the expression has no +side-effects, then it is deleted. As with constant folding, this +optimization applies most often when cleaning up after inline +expansion and other optimizations. Any function declared an +\code{extensions:constant-function} is also subject to unused +expression elimination. + +Note that \python{} will eliminate parts of unused expressions known +to be side-effect free, even if there are other unknown parts. For +example: +\begin{lisp} +(let ((a (list (foo) (bar)))) + (if t + (zow) + (raz a))) +\end{lisp} +becomes: +\begin{lisp} +(progn (foo) (bar)) +(zow) +\end{lisp} + + +\subsection{Control Optimization} +\cindex{control optimization} +\cpsubindex{optimization}{control} + +The most important optimization of control is recognizing when an +\findexed{if} test is known at compile time, then deleting the +\code{if}, the test expression, and the unreachable branch of the +\code{if}. This can be considered a special case of constant folding, +although the test doesn't have to be truly constant as long as it is +definitely not \false. Note also, that type inference propagates the +result of an \code{if} test to the true and false branches, +\pxlref{constraint-propagation}. + +A related \code{if} optimization is this transformation:\footnote{Note + that the code for \code{x} and \code{y} isn't actually replicated.} +\begin{lisp} +(if (if a b c) x y) +\end{lisp} +into: +\begin{lisp} +(if a + (if b x y) + (if c x y)) +\end{lisp} +The opportunity for this sort of optimization usually results from a +conditional macro. For example: +\begin{lisp} +(if (not a) x y) +\end{lisp} +is actually implemented as this: +\begin{lisp} +(if (if a nil t) x y) +\end{lisp} +which is transformed to this: +\begin{lisp} +(if a + (if nil x y) + (if t x y)) +\end{lisp} +which is then optimized to this: +\begin{lisp} +(if a y x) +\end{lisp} +Note that due to \python{}'s internal representations, the +\code{if}\dash{}\code{if} situation will be recognized even if other +forms are wrapped around the inner \code{if}, like: +\begin{example} +(if (let ((g ...)) + (loop + ... + (return (not g)) + ...)) + x y) +\end{example} + +In \python, all the \clisp{} macros really are macros, written in +terms of \code{if}, \code{block} and \code{tagbody}, so user-defined +control macros can be just as efficient as the standard ones. +\python{} emits basic blocks using a heuristic that minimizes the +number of unconditional branches. The code in a \code{tagbody} will +not be emitted in the order it appeared in the source, so there is no +point in arranging the code to make control drop through to the +target. + + +\subsection{Unreachable Code Deletion} +\label{dead-code-notes} +\cindex{unreachable code deletion} +\cindex{dead code elimination} + +\python{} will delete code whenever it can prove that the code can never be +executed. Code becomes unreachable when: + +\begin{itemize} +\item +An \code{if} is optimized away, or + +\item +There is an explicit unconditional control transfer such as \code{go} or +\code{return-from}, or + +\item +The last reference to a local function is deleted (or there never was any +reference.) +\end{itemize} + +When code that appeared in the original source is deleted, the compiler prints +a note to indicate a possible problem (or at least unnecessary code.) For +example: +\begin{lisp} +(defun foo () + (if t + (write-line "True.") + (write-line "False."))) +\end{lisp} +will result in this note: +\begin{example} +In: DEFUN FOO + (WRITE-LINE "False.") +Note: Deleting unreachable code. +\end{example} + +It is important to pay attention to unreachable code notes, since they often +indicate a subtle type error. For example: +\begin{example} +(defstruct foo a b) + +(defun lose (x) + (let ((a (foo-a x)) + (b (if x (foo-b x) :none))) + ...)) +\end{example} +results in this note: +\begin{example} +In: DEFUN LOSE + (IF X (FOO-B X) :NONE) +==> + :NONE +Note: Deleting unreachable code. +\end{example} +The \kwd{none} is unreachable, because type inference knows that the argument +to \code{foo-a} must be a \code{foo}, and thus can't be \false. Presumably the +programmer forgot that \code{x} could be \false{} when he wrote the binding for +\code{a}. + +Here is an example with an incorrect declaration: +\begin{lisp} +(defun count-a (string) + (do ((pos 0 (position #\back{a} string :start (1+ pos))) + (count 0 (1+ count))) + ((null pos) count) + (declare (fixnum pos)))) +\end{lisp} +This time our note is: +\begin{example} +In: DEFUN COUNT-A + (DO ((POS 0 #) (COUNT 0 #)) + ((NULL POS) COUNT) + (DECLARE (FIXNUM POS))) +--> BLOCK LET TAGBODY RETURN-FROM PROGN +==> + COUNT +Note: Deleting unreachable code. +\end{example} + +The problem here is that \code{pos} can never be null since it is declared a +\code{fixnum}. + +It takes some experience with unreachable code notes to be able to +tell what they are trying to say. In non-obvious cases, the best +thing to do is to call the function in a way that should cause the +unreachable code to be executed. Either you will get a type error, or +you will find that there truly is no way for the code to be executed. + +Not all unreachable code results in a note: + +\begin{itemize} +\item A note is only given when the unreachable code textually appears + in the original source. This prevents spurious notes due to the + optimization of macros and inline functions, but sometimes also + foregoes a note that would have been useful. + +\item Since accurate source information is not available for non-list + forms, there is an element of heuristic in determining whether or + not to give a note about an atom. Spurious notes may be given when + a macro or inline function defines a variable that is also present + in the calling function. Notes about \false{} and \true{} are never + given, since it is too easy to confuse these constants in expanded + code with ones in the original source. + +\item Notes are only given about code unreachable due to control flow. + There is no note when an expression is deleted because its value is + unused, since this is a common consequence of other optimizations. +\end{itemize} + + +Somewhat spurious unreachable code notes can also result when a macro +inserts multiple copies of its arguments in different contexts, for +example: +\begin{lisp} +(defmacro t-and-f (var form) + `(if ,var ,form ,form)) + +(defun foo (x) + (t-and-f x (if x "True." "False."))) +\end{lisp} +results in these notes: +\begin{example} +In: DEFUN FOO + (IF X "True." "False.") +==> + "False." +Note: Deleting unreachable code. + +==> + "True." +Note: Deleting unreachable code. +\end{example} + +It seems like it has deleted both branches of the \code{if}, but it has really +deleted one branch in one copy, and the other branch in the other copy. Note +that these messages are only spurious in not satisfying the intent of the rule +that notes are only given when the deleted code appears in the original source; +there is always \var{some} code being deleted when a unreachable code note is +printed. + + +\subsection{Multiple Values Optimization} +\cindex{multiple value optimization} +\cpsubindex{optimization}{multiple value} + +Within a function, \python{} implements uses of multiple values +particularly efficiently. Multiple values can be kept in arbitrary +registers, so using multiple values doesn't imply stack manipulation +and representation conversion. For example, this code: +\begin{example} +(let ((a (if x (foo x) u)) + (b (if x (bar x) v))) + ...) +\end{example} +is actually more efficient written this way: +\begin{example} +(multiple-value-bind + (a b) + (if x + (values (foo x) (bar x)) + (values u v)) + ...) +\end{example} + +Also, \pxlref{local-call-return} for information on how local call +provides efficient support for multiple function return values. + + +\subsection{Source to Source Transformation} +\cindex{source-to-source transformation} +\cpsubindex{transformation}{source-to-source} + +The compiler implements a number of operation-specific optimizations as +source-to-source transformations. You will often see unfamiliar code in error +messages, for example: + +\begin{lisp} +(defun my-zerop () (zerop x)) +\end{lisp} + +gives this warning: + +\begin{example} +In: DEFUN MY-ZEROP + (ZEROP X) +==> + (= X 0) +Warning: Undefined variable: X +\end{example} + +The original \code{zerop} has been transformed into a call to +\code{=}. This transformation is indicated with the same \code{==$>$} +used to mark macro and function inline expansion. Although it can be +confusing, display of the transformed source is important, since +warnings are given with respect to the transformed source. This a +more obscure example: + +\begin{lisp} +(defun foo (x) (logand 1 x)) +\end{lisp} + +gives this efficiency note: + +\begin{example} +In: DEFUN FOO + (LOGAND 1 X) +==> + (LOGAND C::Y C::X) +Note: Forced to do static-function Two-arg-and (cost 53). + Unable to do inline fixnum arithmetic (cost 1) because: + The first argument is a INTEGER, not a FIXNUM. + etc. +\end{example} + +Here, the compiler commuted the call to \code{logand}, introducing +temporaries. The note complains that the \var{first} argument is not +a \code{fixnum}, when in the original call, it was the second +argument. To make things more confusing, the compiler introduced +temporaries called \code{c::x} and \code{c::y} that are bound to +\code{y} and \code{1}, respectively. + +You will also notice source-to-source optimizations when efficiency +notes are enabled (\pxlref{efficiency-notes}.) When the compiler is +unable to do a transformation that might be possible if there was more +information, then an efficiency note is printed. For example, +\code{my-zerop} above will also give this efficiency note: +\begin{example} +In: DEFUN FOO + (ZEROP X) +==> + (= X 0) +Note: Unable to optimize because: + Operands might not be the same type, so can't open code. +\end{example} + + +\subsection{Style Recommendations} +\cindex{style recommendations} + +Source level optimization makes possible a clearer and more relaxed programming +style: +\begin{itemize} + +\item Don't use macros purely to avoid function call. If you want an + inline function, write it as a function and declare it inline. It's + clearer, less error-prone, and works just as well. + +\item Don't write macros that try to ``optimize'' their expansion in + trivial ways such as avoiding binding variables for simple + expressions. The compiler does these optimizations too, and is less + likely to make a mistake. + +\item Make use of local functions (i.e., \code{labels} or \code{flet}) + and tail-recursion in places where it is clearer. Local function + call is faster than full call. + +\item Avoid setting local variables when possible. Binding a new + \code{let} variable is at least as efficient as setting an existing + variable, and is easier to understand, both for the compiler and the + programmer. + +\item Instead of writing similar code over and over again so that it + can be hand customized for each use, define a macro or inline + function, and let the compiler do the work. +\end{itemize} + + +\section{Tail Recursion} +\label{tail-recursion} +\cindex{tail recursion} +\cindex{recursion} + +A call is tail-recursive if nothing has to be done after the the call +returns, i.e. when the call returns, the returned value is immediately +returned from the calling function. In this example, the recursive +call to \code{myfun} is tail-recursive: +\begin{lisp} +(defun myfun (x) + (if (oddp (random x)) + (isqrt x) + (myfun (1- x)))) +\end{lisp} + +Tail recursion is interesting because it is form of recursion that can be +implemented much more efficiently than general recursion. In general, a +recursive call requires the compiler to allocate storage on the stack at +run-time for every call that has not yet returned. This memory consumption +makes recursion unacceptably inefficient for representing repetitive algorithms +having large or unbounded size. Tail recursion is the special case of +recursion that is semantically equivalent to the iteration constructs normally +used to represent repetition in programs. Because tail recursion is equivalent +to iteration, tail-recursive programs can be compiled as efficiently as +iterative programs. + +So why would you want to write a program recursively when you can write it +using a loop? Well, the main answer is that recursion is a more general +mechanism, so it can express some solutions simply that are awkward to write as +a loop. Some programmers also feel that recursion is a stylistically +preferable way to write loops because it avoids assigning variables. +For example, instead of writing: + +\begin{lisp} +(defun fun1 (x) + something-that-uses-x) + +(defun fun2 (y) + something-that-uses-y) + +(do ((x something (fun2 (fun1 x)))) + (nil)) +\end{lisp} + +You can write: + +\begin{lisp} +(defun fun1 (x) + (fun2 something-that-uses-x)) + +(defun fun2 (y) + (fun1 something-that-uses-y)) + +(fun1 something) +\end{lisp} + +The tail-recursive definition is actually more efficient, in addition to being +(arguably) clearer. As the number of functions and the complexity of their +call graph increases, the simplicity of using recursion becomes compelling. +Consider the advantages of writing a large finite-state machine with separate +tail-recursive functions instead of using a single huge \code{prog}. + +It helps to understand how to use tail recursion if you think of a +tail-recursive call as a \code{psetq} that assigns the argument values to the +called function's variables, followed by a \code{go} to the start of the called +function. This makes clear an inherent efficiency advantage of tail-recursive +call: in addition to not having to allocate a stack frame, there is no need to +prepare for the call to return (e.g., by computing a return PC.) + +Is there any disadvantage to tail recursion? Other than an increase +in efficiency, the only way you can tell that a call has been compiled +tail-recursively is if you use the debugger. Since a tail-recursive +call has no stack frame, there is no way the debugger can print out +the stack frame representing the call. The effect is that backtrace +will not show some calls that would have been displayed in a +non-tail-recursive implementation. In practice, this is not as bad as +it sounds\dash{}in fact it isn't really clearly worse, just different. +\xlref{debug-tail-recursion} for information about the debugger +implications of tail recursion, and how to turn it off for the sake of +more conservative backtrace information. + +In order to ensure that tail-recursion is preserved in arbitrarily +complex calling patterns across separately compiled functions, the +compiler must compile any call in a tail-recursive position as a +tail-recursive call. This is done regardless of whether the program +actually exhibits any sort of recursive calling pattern. In this +example, the call to \code{fun2} will always be compiled as a +tail-recursive call: + +\begin{lisp} +(defun fun1 (x) + (fun2 x)) +\end{lisp} + +So tail recursion doesn't necessarily have anything to do with recursion +as it is normally thought of. \xlref{local-tail-recursion} for more +discussion of using tail recursion to implement loops. + + +\subsection{Tail Recursion Exceptions} + +Although \python{} is claimed to be ``properly'' tail-recursive, some +might dispute this, since there are situations where tail recursion is +inhibited: +\begin{itemize} + +\item When the call is enclosed by a special binding, or + +\item When the call is enclosed by a \code{catch} or + \code{unwind-protect}, or + +\item When the call is enclosed by a \code{block} or \code{tagbody} + and the block name or \code{go} tag has been closed over. +\end{itemize} +These dynamic extent binding forms inhibit tail recursion because they +allocate stack space to represent the binding. Shallow-binding +implementations of dynamic scoping also require cleanup code to be +evaluated when the scope is exited. + +In addition, optimization of tail-recursive calls is inhibited when +the \code{debug} optimization quality is greater than \code{2} +(\pxlref{debugger-policy}.) + + +\section{Local Call} +\label{local-call} +\cindex{local call} +\cpsubindex{call}{local} +\cpsubindex{function call}{local} + +\python{} supports two kinds of function call: full call and local call. +Full call is the standard calling convention; its late binding and +generality make \llisp{} what it is, but create unavoidable overheads. +When the compiler can compile the calling function and the called +function simultaneously, it can use local call to avoid some of the +overhead of full call. Local call is really a collection of +compilation strategies. If some aspect of call overhead is not needed +in a particular local call, then it can be omitted. In some cases, +local call can be totally free. Local call provides two main +advantages to the user: +\begin{itemize} + +\item Local call makes the use of the lexical function binding forms + \findexed{flet} and \findexed{labels} much more efficient. A local + call is always faster than a full call, and in many cases is much + faster. + +\item Local call is a natural approach to \textit{block compilation}, a + compilation technique that resolves function references at compile + time. Block compilation speeds function call, but increases + compilation times and prevents function redefinition. +\end{itemize} + + + +\subsection{Self-Recursive Calls} +\cpsubindex{recursion}{self} + +Local call is used when a function defined by \code{defun} calls itself. For +example: +\begin{lisp} +(defun fact (n) + (if (zerop n) + 1 + (* n (fact (1- n))))) +\end{lisp} + +This use of local call speeds recursion, but can also complicate +debugging, since \findexed{trace} will only show the first call to +\code{fact}, and not the recursive calls. This is because the +recursive calls directly jump to the start of the function, and don't +indirect through the \code{symbol-function}. Self-recursive local +call is inhibited when the \kwd{block-compile} argument to +\code{compile-file} is \false{} (\pxlref{compile-file-block}.) + + +\subsection{Let Calls} +\label{let-calls} +Because local call avoids unnecessary call overheads, the compiler +internally uses local call to implement some macros and special forms +that are not normally thought of as involving a function call. For +example, this \code{let}: + +\begin{example} +(let ((a (foo)) + (b (bar))) + ...) +\end{example} + +is internally represented as though it was macroexpanded into: + +\begin{example} +(funcall #'(lambda (a b) + ...) + (foo) + (bar)) +\end{example} + +This implementation is acceptable because the simple cases of local +call (equivalent to a \code{let}) result in good code. This doesn't +make \code{let} any more efficient, but does make local calls that are +semantically the same as \code{let} much more efficient than full +calls. For example, these definitions are all the same as far as the +compiler is concerned: + +\begin{example} +(defun foo () + ...some other stuff... + (let ((a something)) + ...some stuff...)) + +(defun foo () + (flet ((localfun (a) + ...some stuff...)) + ...some other stuff... + (localfun something))) + +(defun foo () + (let ((funvar #'(lambda (a) + ...some stuff...))) + ...some other stuff... + (funcall funvar something))) +\end{example} + +Although local call is most efficient when the function is called only +once, a call doesn't have to be equivalent to a \code{let} to be more +efficient than full call. All local calls avoid the overhead of +argument count checking and keyword argument parsing, and there are a +number of other advantages that apply in many common situations. +\xlref{let-optimization} for a discussion of the optimizations done on +let calls. + + +\subsection{Closures} +\cindex{closures} + +Local call allows for much more efficient use of closures, since the +closure environment doesn't need to be allocated on the heap, or even +stored in memory at all. In this example, there is no penalty for +\code{localfun} referencing \code{a} and \code{b}: +\begin{lisp} +(defun foo (a b) + (flet ((localfun (x) + (1+ (* a b x)))) + (if (= a b) + (localfun (- x)) + (localfun x)))) +\end{lisp} +In local call, the compiler effectively passes closed-over values as +extra arguments, so there is no need for you to ``optimize'' local +function use by explicitly passing in lexically visible values. +Closures may also be subject to let optimization +(\pxlref{let-optimization}.) + +Note: indirect value cells are currently always allocated on the heap +when a variable is both assigned to (with \code{setq} or \code{setf}) +and closed over, regardless of whether the closure is a local function +or not. This is another reason to avoid setting variables when you +don't have to. + + +\subsection{Local Tail Recursion} +\label{local-tail-recursion} +\cindex{tail recursion} +\cpsubindex{recursion}{tail} + +Tail-recursive local calls are particularly efficient, since they are +in effect an assignment plus a control transfer. Scheme programmers +write loops with tail-recursive local calls, instead of using the +imperative \code{go} and \code{setq}. This has not caught on in the +\clisp{} community, since conventional \llisp{} compilers don't +implement local call. In \python, users can choose to write loops +such as: +\begin{lisp} +(defun ! (n) + (labels ((loop (n total) + (if (zerop n) + total + (loop (1- n) (* n total))))) + (loop n 1))) +\end{lisp} + +\begin{defmac}{extensions:}{iterate}{% + \args{\var{name} (\mstar{(\var{var} \var{initial-value})}) + \mstar{\var{declaration}} \mstar{\var{form}}}} + + This macro provides syntactic sugar for using \findexed{labels} to + do iteration. It creates a local function \var{name} with the + specified \var{var}s as its arguments and the \var{declaration}s and + \var{form}s as its body. This function is then called with the + \var{initial-values}, and the result of the call is return from the + macro. + + Here is our factorial example rewritten using \code{iterate}: + + \begin{lisp} + (defun ! (n) + (iterate loop + ((n n) + (total 1)) + (if (zerop n) + total + (loop (1- n) (* n total))))) + \end{lisp} + + The main advantage of using \code{iterate} over \code{do} is that + \code{iterate} naturally allows stepping to be done differently + depending on conditionals in the body of the loop. \code{iterate} + can also be used to implement algorithms that aren't really + iterative by simply doing a non-tail call. For example, the + standard recursive definition of factorial can be written like this: +\begin{lisp} +(iterate fact + ((n n)) + (if (zerop n) + 1 + (* n (fact (1- n))))) +\end{lisp} +\end{defmac} + + +\subsection{Return Values} +\label{local-call-return} +\cpsubindex{return values}{local call} +\cpsubindex{local call}{return values} + +One of the more subtle costs of full call comes from allowing +arbitrary numbers of return values. This overhead can be avoided in +local calls to functions that always return the same number of values. +For efficiency reasons (as well as stylistic ones), you should write +functions so that they always return the same number of values. This +may require passing extra \false{} arguments to \code{values} in some +cases, but the result is more efficient, not less so. + +When efficiency notes are enabled (\pxlref{efficiency-notes}), and the +compiler wants to use known values return, but can't prove that the +function always returns the same number of values, then it will print +a note like this: +\begin{example} +In: DEFUN GRUE + (DEFUN GRUE (X) (DECLARE (FIXNUM X)) (COND (# #) (# NIL) (T #))) +Note: Return type not fixed values, so can't use known return convention: + (VALUES (OR (INTEGER -536870912 -1) NULL) &REST T) +\end{example} + +In order to implement proper tail recursion in the presence of known +values return (\pxlref{tail-recursion}), the compiler sometimes must +prove that multiple functions all return the same number of values. +When this can't be proven, the compiler will print a note like this: +\begin{example} +In: DEFUN BLUE + (DEFUN BLUE (X) (DECLARE (FIXNUM X)) (COND (# #) (# #) (# #) (T #))) +Note: Return value count mismatch prevents known return from + these functions: + BLUE + SNOO +\end{example} +\xlref{number-local-call} for the interaction between local call +and the representation of numeric types. + + +\section{Block Compilation} +\label{block-compilation} +\cindex{block compilation} +\cpsubindex{compilation}{block} + +Block compilation allows calls to global functions defined by +\findexed{defun} to be compiled as local calls. The function call +can be in a different top-level form than the \code{defun}, or even in a +different file. + +In addition, block compilation allows the declaration of the \textit{entry points} +to the block compiled portion. An entry point is any function that may be +called from outside of the block compilation. If a function is not an entry +point, then it can be compiled more efficiently, since all calls are known at +compile time. In particular, if a function is only called in one place, then +it will be let converted. This effectively inline expands the function, but +without the code duplication that results from defining the function normally +and then declaring it inline. + +The main advantage of block compilation is that it it preserves efficiency in +programs even when (for readability and syntactic convenience) they are broken +up into many small functions. There is absolutely no overhead for calling a +non-entry point function that is defined purely for modularity (i.e. called +only in one place.) + +Block compilation also allows the use of non-descriptor arguments and return +values in non-trivial programs (\pxlref{number-local-call}). + + +\subsection{Block Compilation Semantics} + +The effect of block compilation can be envisioned as the compiler turning all +the \code{defun}s in the block compilation into a single \code{labels} form: +\begin{example} +(declaim (start-block fun1 fun3)) + +(defun fun1 () + ...) + +(defun fun2 () + ... + (fun1) + ...) + +(defun fun3 (x) + (if x + (fun1) + (fun2))) + +(declaim (end-block)) +\end{example} +becomes: +\begin{example} +(labels ((fun1 () + ...) + (fun2 () + ... + (fun1) + ...) + (fun3 (x) + (if x + (fun1) + (fun2)))) + (setf (fdefinition 'fun1) #'fun1) + (setf (fdefinition 'fun3) #'fun3)) +\end{example} +Calls between the block compiled functions are local calls, so changing the +global definition of \code{fun1} will have no effect on what \code{fun2} does; +\code{fun2} will keep calling the old \code{fun1}. + +The entry points \code{fun1} and \code{fun3} are still installed in +the \code{symbol-function} as the global definitions of the functions, +so a full call to an entry point works just as before. However, +\code{fun2} is not an entry point, so it is not globally defined. In +addition, \code{fun2} is only called in one place, so it will be let +converted. + + +\subsection{Block Compilation Declarations} +\cpsubindex{declarations}{block compilation} +\cindex{start-block declaration} +\cindex{end-block declaration} + +The \code{extensions:start-block} and \code{extensions:end-block} +declarations allow fine-grained control of block compilation. These +declarations are only legal as a global declarations (\code{declaim} +or \code{proclaim}). + +\noindent +\vspace{1 em} +The \code{start-block} declaration has this syntax: +\begin{example} +(start-block \mstar{\var{entry-point-name}}) +\end{example} +When processed by the compiler, this declaration marks the start of +block compilation, and specifies the entry points to that block. If +no entry points are specified, then \var{all} functions are made into +entry points. If already block compiling, then the compiler ends the +current block and starts a new one. + +\noindent +\vspace{1 em} +The \code{end-block} declaration has no arguments: +\begin{lisp} +(end-block) +\end{lisp} +The \code{end-block} declaration ends a block compilation unit without +starting a new one. This is useful mainly when only a portion of a file +is worth block compiling. + + +\subsection{Compiler Arguments} +\label{compile-file-block} +\cpsubindex{compile-file}{block compilation arguments} + +The \kwd{block-compile} and \kwd{entry-points} arguments to +\code{extensions:compile-from-stream} and \funref{compile-file} provide overall +control of block compilation, and allow block compilation without requiring +modification of the program source. + +There are three possible values of the \kwd{block-compile} argument: +\begin{Lentry} + +\item[\false{}] Do no compile-time resolution of global function + names, not even for self-recursive calls. This inhibits any + \code{start-block} declarations appearing in the file, allowing all + functions to be incrementally redefined. + +\item[\true{}] Start compiling in block compilation mode. This is + mainly useful for block compiling small files that contain no + \code{start-block} declarations. See also the \kwd{entry-points} + argument. + +\item[\kwd{specified}] Start compiling in form-at-a-time mode, but + exploit any \code{start-block} declarations and compile + self-recursive calls as local calls. Normally \kwd{specified} is + the default for this argument (see \varref{block-compile-default}.) +\end{Lentry} + +The \kwd{entry-points} argument can be used in conjunction with +\w{\kwd{block-compile} \true{}} to specify the entry-points to a +block-compiled file. If not specified or \nil, all global functions +will be compiled as entry points. When \kwd{block-compile} is not +\true, this argument is ignored. + +\begin{defvar}{}{block-compile-default} + + This variable determines the default value for the + \kwd{block-compile} argument to \code{compile-file} and + \code{compile-from-stream}. The initial value of this variable is + \kwd{specified}, but \false{} is sometimes useful for totally + inhibiting block compilation. +\end{defvar} + + +\subsection{Practical Difficulties} + +The main problem with block compilation is that the compiler uses +large amounts of memory when it is block compiling. This places an +upper limit on the amount of code that can be block compiled as a +unit. To make best use of block compilation, it is necessary to +locate the parts of the program containing many internal calls, and +then add the appropriate \code{start-block} declarations. When writing +new code, it is a good idea to put in block compilation declarations +from the very beginning, since writing block declarations correctly +requires accurate knowledge of the program's function call structure. +If you want to initially develop code with full incremental +redefinition, you can compile with \varref{block-compile-default} set to +\false. + +Note if a \code{defun} appears in a non-null lexical environment, then +calls to it cannot be block compiled. + +Unless files are very small, it is probably impractical to block compile +multiple files as a unit by specifying a list of files to \code{compile-file}. +Semi-inline expansion (\pxlref{semi-inline}) provides another way to +extend block compilation across file boundaries. + + +\subsection{Context Declarations} +\label{context-declarations} +\cindex{context sensitive declarations} +\cpsubindex{declarations}{context-sensitive} + +\cmucl{} has a context-sensitive declaration mechanism which is useful +because it allows flexible control of the compilation policy in large +systems without requiring changes to the source files. The primary +use of this feature is to allow the exported interfaces of a system to +be compiled more safely than the system internals. The context used +is the name being defined and the kind of definition (function, macro, +etc.) + +The \kwd{context-declarations} option to \macref{with-compilation-unit} has +dynamic scope, affecting all compilation done during the evaluation of the +body. The argument to this option should evaluate to a list of lists of the +form: +\begin{example} +(\var{context-spec} \mplus{\var{declare-form}}) +\end{example} +In the indicated context, the specified declare forms are inserted at +the head of each definition. The declare forms for all contexts that +match are appended together, with earlier declarations getting +precedence over later ones. A simple example: +\begin{example} + :context-declarations + '((:external (declare (optimize (safety 2))))) +\end{example} +This will cause all functions that are named by external symbols to be +compiled with \code{safety 2}. + +The full syntax of context specs is: +\begin{Lentry} + +\item[\kwd{internal}, \kwd{external}] True if the symbol is internal + (external) in its home package. + +\item[\kwd{uninterned}] True if the symbol has no home package. + +\item[\code{\w{(:package \mstar{\var{package-name}})}}] True if the + symbol's home package is in any of the named packages (false if + uninterned.) + +\item[\kwd{anonymous}] True if the function doesn't have any + interesting name (not \code{defmacro}, \code{defun}, \code{labels} + or \code{flet}). + +\item[\kwd{macro}, \kwd{function}] \kwd{macro} is a global + (\code{defmacro}) macro. \kwd{function} is anything else. + +\item[\kwd{local}, \kwd{global}] \kwd{local} is a \code{labels} or + \code{flet}. \kwd{global} is anything else. + +\item[\code{\w{(:or \mstar{\var{context-spec}})}}] True when any + supplied \var{context-spec} is true. + +\item[\code{\w{(:and \mstar{\var{context-spec}})}}] True only when all + supplied \var{context-spec}s are true. + +\item[\code{\w{(:not \mstar{\var{context-spec}})}}] True when + \var{context-spec} is false. + +\item[\code{\w{(:member \mstar{\var{name}})}}] True when the defined + name is one of these names (\code{equal} test.) + +\item[\code{\w{(:match \mstar{\var{pattern}})}}] True when any of the + patterns is a substring of the name. The name is wrapped with + \code{\$}'s, so ``\code{\$FOO}'' matches names beginning with + ``\code{FOO}'', etc. +\end{Lentry} + + +\subsection{Context Declaration Example} + +Here is a more complex example of \code{with-compilation-unit} options: +\begin{example} +:optimize '(optimize (speed 2) (space 2) (inhibit-warnings 2) + (debug 1) (safety 0)) +:optimize-interface '(optimize-interface (safety 1) (debug 1)) +:context-declarations +'(((:or :external (:and (:match "\%") (:match "SET"))) + (declare (optimize-interface (safety 2)))) + ((:or (:and :external :macro) + (:match "\$PARSE-")) + (declare (optimize (safety 2))))) +\end{example} +The \code{optimize} and \code{extensions:optimize-interface} +declarations (\pxlref{optimize-declaration}) set up the global +compilation policy. The bodies of functions are to be compiled +completely unsafe (\code{safety 0}), but argument count and weakened +argument type checking is to be done when a function is called +(\code{speed 2 safety 1}). + +The first declaration specifies that all functions that are external +or whose names contain both ``\code{\%}'' and ``\code{SET}'' are to be +compiled compiled with completely safe interfaces (\code{safety 2}). +The reason for this particular \kwd{match} rule is that \code{setf} +inverse functions in this system tend to have both strings in their +name somewhere. We want \code{setf} inverses to be safe because they +are implicitly called by users even though their name is not exported. + +The second declaration makes external macros or functions whose names +start with ``\code{PARSE-}'' have safe bodies (as well as interfaces). +This is desirable because a syntax error in a macro may cause a type +error inside the body. The \kwd{match} rule is used because macros +often have auxiliary functions whose names begin with this string. + +This particular example is used to build part of the standard \cmucl{} +system. Note however, that context declarations must be set up +according to the needs and coding conventions of a particular system; +different parts of \cmucl{} are compiled with different context +declarations, and your system will probably need its own declarations. +In particular, any use of the \kwd{match} option depends on naming +conventions used in coding. + + +\section{Inline Expansion} +\label{inline-expansion} +\cindex{inline expansion} +\cpsubindex{expansion}{inline} +\cpsubindex{call}{inline} +\cpsubindex{function call}{inline} +\cpsubindex{optimization}{function call} + +\python{} can expand almost any function inline, including functions +with keyword arguments. The only restrictions are that keyword +argument keywords in the call must be constant, and that global +function definitions (\code{defun}) must be done in a null lexical +environment (not nested in a \code{let} or other binding form.) Local +functions (\code{flet}) can be inline expanded in any environment. +Combined with \python{}'s source-level optimization, inline expansion +can be used for things that formerly required macros for efficient +implementation. In \python, macros don't have any efficiency +advantage, so they need only be used where a macro's syntactic +flexibility is required. + +Inline expansion is a compiler optimization technique that reduces +the overhead of a function call by simply not doing the call: +instead, the compiler effectively rewrites the program to appear as +though the definition of the called function was inserted at each +call site. In \llisp, this is straightforwardly expressed by +inserting the \code{lambda} corresponding to the original definition: +\begin{lisp} +(proclaim '(inline my-1+)) +(defun my-1+ (x) (+ x 1)) + +(my-1+ someval) \result{} ((lambda (x) (+ x 1)) someval) +\end{lisp} + +When the function expanded inline is large, the program after inline +expansion may be substantially larger than the original program. If +the program becomes too large, inline expansion hurts speed rather +than helping it, since hardware resources such as physical memory and +cache will be exhausted. Inline expansion is called for: +\begin{itemize} + +\item When profiling has shown that a relatively simple function is + called so often that a large amount of time is being wasted in the + calling of that function (as opposed to running in that function.) + If a function is complex, it will take a long time to run relative + the time spent in call, so the speed advantage of inline expansion + is diminished at the same time the space cost of inline expansion is + increased. Of course, if a function is rarely called, then the + overhead of calling it is also insignificant. + +\item With functions so simple that they take less space to inline + expand than would be taken to call the function (such as + \code{my-1+} above.) It would require intimate knowledge of the + compiler to be certain when inline expansion would reduce space, but + it is generally safe to inline expand functions whose definition is + a single function call, or a few calls to simple \clisp{} functions. +\end{itemize} + + +In addition to this speed/space tradeoff from inline expansion's +avoidance of the call, inline expansion can also reveal opportunities +for optimization. \python{}'s extensive source-level optimization can +make use of context information from the caller to tremendously +simplify the code resulting from the inline expansion of a function. + +The main form of caller context is local information about the actual +argument values: what the argument types are and whether the arguments +are constant. Knowledge about argument types can eliminate run-time +type tests (e.g., for generic arithmetic.) Constant arguments in a +call provide opportunities for constant folding optimization after +inline expansion. + +A hidden way that constant arguments are often supplied to functions +is through the defaulting of unsupplied optional or keyword arguments. +There can be a huge efficiency advantage to inline expanding functions +that have complex keyword-based interfaces, such as this definition of +the \code{member} function: +\begin{lisp} +(proclaim '(inline member)) +(defun member (item list &key + (key #'identity) + (test #'eql testp) + (test-not nil notp)) + (do ((list list (cdr list))) + ((null list) nil) + (let ((car (car list))) + (if (cond (testp + (funcall test item (funcall key car))) + (notp + (not (funcall test-not item (funcall key car)))) + (t + (funcall test item (funcall key car)))) + (return list))))) + +\end{lisp} +After inline expansion, this call is simplified to the obvious code: +\begin{lisp} +(member a l :key #'foo-a :test #'char=) \result{} + +(do ((list list (cdr list))) + ((null list) nil) + (let ((car (car list))) + (if (char= item (foo-a car)) + (return list)))) +\end{lisp} +In this example, there could easily be more than an order of magnitude +improvement in speed. In addition to eliminating the original call to +\code{member}, inline expansion also allows the calls to \code{char=} +and \code{foo-a} to be open-coded. We go from a loop with three tests +and two calls to a loop with one test and no calls. + +\xlref{source-optimization} for more discussion of source level +optimization. + + +\subsection{Inline Expansion Recording} +\cindex{recording of inline expansions} + +Inline expansion requires that the source for the inline expanded function to +be available when calls to the function are compiled. The compiler doesn't +remember the inline expansion for every function, since that would take an +excessive about of space. Instead, the programmer must tell the compiler to +record the inline expansion before the definition of the inline expanded +function is compiled. This is done by globally declaring the function inline +before the function is defined, by using the \code{inline} and +\code{extensions:maybe-inline} (\pxlref{maybe-inline-declaration}) +declarations. + +In addition to recording the inline expansion of inline functions at the time +the function is compiled, \code{compile-file} also puts the inline expansion in +the output file. When the output file is loaded, the inline expansion is made +available for subsequent compilations; there is no need to compile the +definition again to record the inline expansion. + +If a function is declared inline, but no expansion is recorded, then the +compiler will give an efficiency note like: + +\begin{example} +Note: MYFUN is declared inline, but has no expansion. +\end{example} + +When you get this note, check that the \code{inline} declaration and the +definition appear before the calls that are to be inline expanded. This note +will also be given if the inline expansion for a \code{defun} could not be +recorded because the \code{defun} was in a non-null lexical environment. + + +\subsection{Semi-Inline Expansion} +\label{semi-inline} + +\python{} supports \var{semi-inline} functions. Semi-inline expansion +shares a single copy of a function across all the calls in a component +by converting the inline expansion into a local function +(\pxlref{local-call}.) This takes up less space when there are +multiple calls, but also provides less opportunity for context +dependent optimization. When there is only one call, the result is +identical to normal inline expansion. Semi-inline expansion is done +when the \code{space} optimization quality is \code{0}, and the +function has been declared \code{extensions:maybe-inline}. + +This mechanism of inline expansion combined with local call also +allows recursive functions to be inline expanded. If a recursive +function is declared \code{inline}, calls will actually be compiled +semi-inline. Although recursive functions are often so complex that +there is little advantage to semi-inline expansion, it can still be +useful in the same sort of cases where normal inline expansion is +especially advantageous, i.e. functions where the calling context can +help a lot. + + +\subsection{The Maybe-Inline Declaration} +\label{maybe-inline-declaration} +\cindex{maybe-inline declaration} + +The \code{extensions:maybe-inline} declaration is a \cmucl{} +extension. It is similar to \code{inline}, but indicates that inline +expansion may sometimes be desirable, rather than saying that inline +expansion should almost always be done. When used in a global +declaration, \code{extensions:maybe-inline} causes the expansion for +the named functions to be recorded, but the functions aren't actually +inline expanded unless \code{space} is \code{0} or the function is +eventually (perhaps locally) declared \code{inline}. + +Use of the \code{extensions:maybe-inline} declaration followed by the +\code{defun} is preferable to the standard idiom of: +\begin{lisp} +(proclaim '(inline myfun)) +(defun myfun () ...) +(proclaim '(notinline myfun)) + +;;; \textit{Any calls to \code{myfun} here are not inline expanded.} + +(defun somefun () + (declare (inline myfun)) + ;; + ;; \textit{Calls to \code{myfun} here are inline expanded.} + ...) +\end{lisp} +The problem with using \code{notinline} in this way is that in +\clisp{} it does more than just suppress inline expansion, it also +forbids the compiler to use any knowledge of \code{myfun} until a +later \code{inline} declaration overrides the \code{notinline}. This +prevents compiler warnings about incorrect calls to the function, and +also prevents block compilation. + +The \code{extensions:maybe-inline} declaration is used like this: +\begin{lisp} +(proclaim '(extensions:maybe-inline myfun)) +(defun myfun () ...) + +;;; \textit{Any calls to \code{myfun} here are not inline expanded.} + +(defun somefun () + (declare (inline myfun)) + ;; + ;; \textit{Calls to \code{myfun} here are inline expanded.} + ...) + +(defun someotherfun () + (declare (optimize (space 0))) + ;; + ;; \textit{Calls to \code{myfun} here are expanded semi-inline.} + ...) +\end{lisp} +In this example, the use of \code{extensions:maybe-inline} causes the +expansion to be recorded when the \code{defun} for \code{somefun} is +compiled, and doesn't waste space through doing inline expansion by +default. Unlike \code{notinline}, this declaration still allows the +compiler to assume that the known definition really is the one that +will be called when giving compiler warnings, and also allows the +compiler to do semi-inline expansion when the policy is appropriate. + +When the goal is merely to control whether inline expansion is done by +default, it is preferable to use \code{extensions:maybe-inline} rather +than \code{notinline}. The \code{notinline} declaration should be +reserved for those special occasions when a function may be redefined +at run-time, so the compiler must be told that the obvious definition +of a function is not necessarily the one that will be in effect at the +time of the call. + + +\section{Byte Coded Compilation} +\label{byte-compile} +\cindex{byte coded compilation} +\cindex{space optimization} + +\python{} supports byte compilation to reduce the size of Lisp +programs by allowing functions to be compiled more compactly. Byte +compilation provides an extreme speed/space tradeoff: byte code is +typically six times more compact than native code, but runs fifty +times (or more) slower. This is about ten times faster than the +standard interpreter, which is itself considered fast in comparison to +other \clisp{} interpreters. + +Large Lisp systems (such as \cmucl{} itself) often have large amounts +of user-interface code, compile-time (macro) code, debugging code, or +rarely executed special-case code. This code is a good target for +byte compilation: very little time is spent running in it, but it can +take up quite a bit of space. Straight-line code with many function +calls is much more suitable than inner loops. + +When byte-compiling, the compiler compiles about twice as fast, and +can produce a hardware independent object file (\file{.bytef} type.) +This file can be loaded like a normal fasl file on any implementation +of \cmucl{} with the same byte-ordering. + +The decision to byte compile or native compile can be done on a +per-file or per-code-object basis. The \kwd{byte-compile} argument to +\funref{compile-file} has these possible values: + +\begin{Lentry} +\item[\false{}] Don't byte compile anything in this file. + +\item[\true{}] Byte compile everything in this file and produce a + processor-independent \file{.bytef} file. + +\item[\kwd{maybe}] Produce a normal fasl file, but byte compile any + functions for which the \code{speed} optimization quality is + \code{0} and the \code{debug} quality is not greater than \code{1}. +\end{Lentry} + +\begin{defvar}{extensions:}{byte-compile-top-level} + + If this variable is true (the default) and the \kwd{byte-compile} + argument to \code{compile-file} is \kwd{maybe}, then byte compile + top-level code (code outside of any \code{defun}, \code{defmethod}, + etc.) +\end{defvar} + +\begin{defvar}{extensions:}{byte-compile-default} + + This variable determines the default value for the + \kwd{byte-compile} argument to \code{compile-file}, initially + \kwd{maybe}. +\end{defvar} + + +\section{Object Representation} +\label{object-representation} +\cindex{object representation} +\cpsubindex{representation}{object} +\cpsubindex{efficiency}{of objects} + +A somewhat subtle aspect of writing efficient \clisp{} programs is +choosing the correct data structures so that the underlying objects +can be implemented efficiently. This is partly because of the need +for multiple representations for a given value +(\pxlref{non-descriptor}), but is also due to the sheer number of +object types that \clisp{} has built in. The number of possible +representations complicates the choice of a good representation +because semantically similar objects may vary in their efficiency +depending on how the program operates on them. + + +\subsection{Think Before You Use a List} +\cpsubindex{lists}{efficiency of} + +Although Lisp's creator seemed to think that it was for LISt +Processing, the astute observer may have noticed that the chapter on +list manipulation makes up less that three percent of \cltltwo{}. The +language has grown since Lisp 1.5\dash{}new data types supersede lists +for many purposes. + + +\subsection{Structure Representation} +\cpsubindex{structure types}{efficiency of} One of the best ways of +building complex data structures is to define appropriate structure +types using \findexed{defstruct}. In \python, access of structure +slots is always at least as fast as list or vector access, and is +usually faster. In comparison to a list representation of a tuple, +structures also have a space advantage. + +Even if structures weren't more efficient than other representations, structure +use would still be attractive because programs that use structures in +appropriate ways are much more maintainable and robust than programs written +using only lists. For example: +\begin{lisp} +(rplaca (caddr (cadddr x)) (caddr y)) +\end{lisp} +could have been written using structures in this way: +\begin{lisp} +(setf (beverage-flavor (astronaut-beverage x)) (beverage-flavor y)) +\end{lisp} +The second version is more maintainable because it is easier to +understand what it is doing. It is more robust because structures +accesses are type checked. An \code{astronaut} will never be confused +with a \code{beverage}, and the result of \code{beverage-flavor} is +always a flavor. See sections \ref{structure-types} and +\ref{freeze-type} for more information about structure types. +\xlref{type-inference} for a number of examples that make clear the +advantages of structure typing. + +Note that the structure definition should be compiled before any uses +of its accessors or type predicate so that these function calls can be +efficiently open-coded. + + +\subsection{Arrays} +\label{array-types} +\cpsubindex{arrays}{efficiency of} + +Arrays are often the most efficient representation for collections of objects +because: +\begin{itemize} + +\item Array representations are often the most compact. An array is + always more compact than a list containing the same number of + elements. + +\item Arrays allow fast constant-time access. + +\item Arrays are easily destructively modified, which can reduce + consing. + +\item Array element types can be specialized, which reduces both + overall size and consing (\pxlref{specialized-array-types}.) +\end{itemize} + + +Access of arrays that are not of type \code{simple-array} is less +efficient, so declarations are appropriate when an array is of a +simple type like \code{simple-string} or \code{simple-bit-vector}. +Arrays are almost always simple, but the compiler may not be able to +prove simpleness at every use. The only way to get a non-simple array +is to use the \kwd{displaced-to}, \kwd{fill-pointer} or +\code{adjustable} arguments to \code{make-array}. If you don't use +these hairy options, then arrays can always be declared to be simple. + +Because of the many specialized array types and the possibility of +non-simple arrays, array access is much like generic arithmetic +(\pxlref{generic-arithmetic}). In order for array accesses to be +efficiently compiled, the element type and simpleness of the array +must be known at compile time. If there is inadequate information, +the compiler is forced to call a generic array access routine. You +can detect inefficient array accesses by enabling efficiency notes, +\pxlref{efficiency-notes}. + + +\subsection{Vectors} +\cpsubindex{vectors}{efficiency of} + +Vectors (one dimensional arrays) are particularly useful, since in +addition to their obvious array-like applications, they are also well +suited to representing sequences. In comparison to a list +representation, vectors are faster to access and take up between two +and sixty-four times less space (depending on the element type.) As +with arbitrary arrays, the compiler needs to know that vectors are not +complex, so you should use \code{simple-string} in preference to +\code{string}, etc. + +The only advantage that lists have over vectors for representing +sequences is that it is easy to change the length of a list, add to it +and remove items from it. Likely signs of archaic, slow lisp code are +\code{nth} and \code{nthcdr}. If you are using these functions you +should probably be using a vector. + + +\subsection{Bit-Vectors} +\cpsubindex{bit-vectors}{efficiency of} + +Another thing that lists have been used for is set manipulation. In +applications where there is a known, reasonably small universe of +items bit-vectors can be used to improve performance. This is much +less convenient than using lists, because instead of symbols, each +element in the universe must be assigned a numeric index into the bit +vector. Using a bit-vector will nearly always be faster, and can be +tremendously faster if the number of elements in the set is not small. +The logical operations on \code{simple-bit-vector}s are efficient, +since they operate on a word at a time. + + +\subsection{Hashtables} +\cpsubindex{hash-tables}{efficiency of} + +Hashtables are an efficient and general mechanism for maintaining associations +such as the association between an object and its name. Although hashtables +are usually the best way to maintain associations, efficiency and style +considerations sometimes favor the use of an association list (a-list). + +\code{assoc} is fairly fast when the \var{test} argument is \code{eq} +or \code{eql} and there are only a few elements, but the time goes up +in proportion with the number of elements. In contrast, the +hash-table lookup has a somewhat higher overhead, but the speed is +largely unaffected by the number of entries in the table. For an +\code{equal} hash-table or alist, hash-tables have an even greater +advantage, since the test is more expensive. Whatever you do, be sure +to use the most restrictive test function possible. + +The style argument observes that although hash-tables and alists +overlap in function, they do not do all things equally well. +\begin{itemize} + +\item Alists are good for maintaining scoped environments. They were + originally invented to implement scoping in the Lisp interpreter, + and are still used for this in \python. With an alist one can + non-destructively change an association simply by consing a new + element on the front. This is something that cannot be done with + hash-tables. + +\item Hashtables are good for maintaining a global association. The + value associated with an entry can easily be changed with + \code{setf}. With an alist, one has to go through contortions, + either \code{rplacd}'ing the cons if the entry exists, or pushing a + new one if it doesn't. The side-effecting nature of hash-table + operations is an advantage here. +\end{itemize} + + +Historically, symbol property lists were often used for global name +associations. Property lists provide an awkward and error-prone +combination of name association and record structure. If you must use +the property list, please store all the related values in a single +structure under a single property, rather than using many properties. +This makes access more efficient, and also adds a modicum of typing +and abstraction. \xlref{advanced-type-stuff} for information on types +in \cmucl. + + +\section{Numbers} +\label{numeric-types} +\cpsubindex{numeric}{types} +\cpsubindex{types}{numeric} + +Numbers are interesting because numbers are one of the few \llisp{} data types +that have direct support in conventional hardware. If a number can be +represented in the way that the hardware expects it, then there is a big +efficiency advantage. + +Using hardware representations is problematical in \llisp{} due to +dynamic typing (where the type of a value may be unknown at compile +time.) It is possible to compile code for statically typed portions +of a \llisp{} program with efficiency comparable to that obtained in +statically typed languages such as C, but not all \llisp{} +implementations succeed. There are two main barriers to efficient +numerical code in \llisp{}: +\begin{itemize} + +\item The compiler must prove that the numerical expression is in fact + statically typed, and + +\item The compiler must be able to somehow reconcile the conflicting + demands of the hardware mandated number representation with the + \llisp{} requirements of dynamic typing and garbage-collecting + dynamic storage allocation. +\end{itemize} + +Because of its type inference (\pxlref{type-inference}) and efficiency +notes (\pxlref{efficiency-notes}), \python{} is better than +conventional \llisp{} compilers at ensuring that numerical expressions +are statically typed. \python{} also goes somewhat farther than existing +compilers in the area of allowing native machine number +representations in the presence of garbage collection. + + +\subsection{Descriptors} +\cpsubindex{descriptors}{object} +\cindex{object representation} +\cpsubindex{representation}{object} +\cpsubindex{consing}{overhead of} + +\llisp{}'s dynamic typing requires that it be possible to represent +any value with a fixed length object, known as a \var{descriptor}. +This fixed-length requirement is implicit in features such as: +\begin{itemize} + +\item Data types (like \code{simple-vector}) that can contain any type + of object, and that can be destructively modified to contain + different objects (of possibly different types.) + +\item Functions that can be called with any type of argument, and that + can be redefined at run time. +\end{itemize} + +In order to save space, a descriptor is invariably represented as a +single word. Objects that can be directly represented in the +descriptor itself are said to be \var{immediate}. Descriptors for +objects larger than one word are in reality pointers to the memory +actually containing the object. + +Representing objects using pointers has two major disadvantages: +\begin{itemize} + +\item The memory pointed to must be allocated on the heap, so it must + eventually be freed by the garbage collector. Excessive heap + allocation of objects (or ``consing'') is inefficient in several + ways. \xlref{consing}. + +\item Representing an object in memory requires the compiler to emit + additional instructions to read the actual value in from memory, and + then to write the value back after operating on it. +\end{itemize} + +The introduction of garbage collection makes things even worse, since +the garbage collector must be able to determine whether a descriptor +is an immediate object or a pointer. This requires that a few bits in +each descriptor be dedicated to the garbage collector. The loss of a +few bits doesn't seem like much, but it has a major efficiency +implication\dash{}objects whose natural machine representation is a +full word (integers and single-floats) cannot have an immediate +representation. So the compiler is forced to use an unnatural +immediate representation (such as \code{fixnum}) or a natural pointer +representation (with the attendant consing overhead.) + + +\subsection{Non-Descriptor Representations} +\label{non-descriptor} +\cindex{non-descriptor representations} +\cindex{stack numbers} + +From the discussion above, we can see that the standard descriptor +representation has many problems, the worst being number consing. +\llisp{} compilers try to avoid these descriptor efficiency problems by using +\var{non-descriptor} representations. A compiler that uses non-descriptor +representations can compile this function so that it does no number consing: +\begin{lisp} +(defun multby (vec n) + (declare (type (simple-array single-float (*)) vec) + (single-float n)) + (dotimes (i (length vec)) + (setf (aref vec i) + (* n (aref vec i))))) +\end{lisp} +If a descriptor representation were used, each iteration of the loop might +cons two floats and do three times as many memory references. + +As its negative definition suggests, the range of possible non-descriptor +representations is large. The performance improvement from non-descriptor +representation depends upon both the number of types that have non-descriptor +representations and the number of contexts in which the compiler is forced to +use a descriptor representation. + +Many \llisp{} compilers support non-descriptor representations for +float types such as \code{single-float} and \code{double-float} +(section \ref{float-efficiency}.) \python{} adds support for full +word integers (\pxlref{word-integers}), characters +(\pxlref{characters}) and system-area pointers (unconstrained +pointers, \pxlref{system-area-pointers}.) Many \llisp{} compilers +support non-descriptor representations for variables (section +\ref{ND-variables}) and array elements (section +\ref{specialized-array-types}.) \python{} adds support for +non-descriptor arguments and return values in local call +(\pxlref{number-local-call}) and structure slots (\pxlref{raw-slots}). + + +\subsection{Variables} +\label{ND-variables} +\cpsubindex{variables}{non-descriptor} +\cpsubindex{type declarations}{variable} +\cpsubindex{efficiency}{of numeric variables} + +In order to use a non-descriptor representation for a variable or +expression intermediate value, the compiler must be able to prove that +the value is always of a particular type having a non-descriptor +representation. Type inference (\pxlref{type-inference}) often needs +some help from user-supplied declarations. The best kind of type +declaration is a variable type declaration placed at the binding +point: +\begin{lisp} +(let ((x (car l))) + (declare (single-float x)) + ...) +\end{lisp} +Use of \code{the}, or of variable declarations not at the binding form +is insufficient to allow non-descriptor representation of the +variable\dash{}with these declarations it is not certain that all +values of the variable are of the right type. It is sometimes useful +to introduce a gratuitous binding that allows the compiler to change +to a non-descriptor representation, like: +\begin{lisp} +(etypecase x + ((signed-byte 32) + (let ((x x)) + (declare (type (signed-byte 32) x)) + ...)) + ...) +\end{lisp} +The declaration on the inner \code{x} is necessary here due to a phase +ordering problem. Although the compiler will eventually prove that +the outer \code{x} is a \w{\code{(signed-byte 32)}} within that +\code{etypecase} branch, the inner \code{x} would have been optimized +away by that time. Declaring the type makes let optimization more +cautious. + +Note that storing a value into a global (or \code{special}) variable +always forces a descriptor representation. Wherever possible, you +should operate only on local variables, binding any referenced globals +to local variables at the beginning of the function, and doing any +global assignments at the end. + +Efficiency notes signal use of inefficient representations, so +programmer's needn't continuously worry about the details of +representation selection (\pxlref{representation-eff-note}.) + + +\subsection{Generic Arithmetic} +\label{generic-arithmetic} +\cindex{generic arithmetic} +\cpsubindex{arithmetic}{generic} +\cpsubindex{numeric}{operation efficiency} + +In \clisp, arithmetic operations are \var{generic}.\footnote{As Steele + notes in CLTL II, this is a generic conception of generic, and is + not to be confused with the CLOS concept of a generic function.} +The \code{+} function can be passed \code{fixnum}s, \code{bignum}s, +\code{ratio}s, and various kinds of \code{float}s and +\code{complex}es, in any combination. In addition to the inherent +complexity of \code{bignum} and \code{ratio} operations, there is also +a lot of overhead in just figuring out which operation to do and what +contagion and canonicalization rules apply. The complexity of generic +arithmetic is so great that it is inconceivable to open code it. +Instead, the compiler does a function call to a generic arithmetic +routine, consuming many instructions before the actual computation +even starts. + +This is ridiculous, since even \llisp{} programs do a lot of +arithmetic, and the hardware is capable of doing operations on small +integers and floats with a single instruction. To get acceptable +efficiency, the compiler special-cases uses of generic arithmetic that +are directly implemented in the hardware. In order to open code +arithmetic, several constraints must be met: +\begin{itemize} + +\item All the arguments must be known to be a good type of number. + +\item The result must be known to be a good type of number. + +\item Any intermediate values such as the result of \w{\code{(+ a b)}} + in the call \w{\code{(+ a b c)}} must be known to be a good type of + number. + +\item All the above numbers with good types must be of the \var{same} + good type. Don't try to mix integers and floats or different float + formats. +\end{itemize} + +The ``good types'' are \w{\code{(signed-byte 32)}}, +\w{\code{(unsigned-byte 32)}}, \code{single-float}, +\code{double-float}, \code{(complex single-float)}, and \code{(complex + double-float)}. See sections \ref{fixnums}, \ref{word-integers} +and \ref{float-efficiency} for more discussion of good numeric types. + +\code{float} is not a good type, since it might mean either +\code{single-float} or \code{double-float}. \code{integer} is not a +good type, since it might mean \code{bignum}. \code{rational} is not +a good type, since it might mean \code{ratio}. Note however that +these types are still useful in declarations, since type inference may +be able to strengthen a weak declaration into a good one, when it +would be at a loss if there was no declaration at all +(\pxlref{type-inference}). The \code{integer} and +\code{unsigned-byte} (or non-negative integer) types are especially +useful in this regard, since they can often be strengthened to a good +integer type. + +% Arithmetic with \code{complex} numbers is inefficient in comparison to +% float and integer arithmetic. Complex numbers are always represented +% with a pointer descriptor (causing consing overhead), and complex +% arithmetic is always closed coded using the general generic arithmetic +As noted above, \cmucl{} has support for \code{(complex single-float)} +and \code{(complex double-float)}. These can be unboxed and, thus, +are quite efficient. However, arithmetic with complex types such as: +\begin{lisp} +(complex float) +(complex fixnum) +\end{lisp} +will be significantly slower than the good complex types but is still +faster than \code{bignum} or \code{ratio} arithmetic, since the +implementation is much simpler. + +Note: don't use \code{/} to divide integers unless you want the +overhead of rational arithmetic. Use \code{truncate} even when you +know that the arguments divide evenly. + +You don't need to remember all the rules for how to get open-coded +arithmetic, since efficiency notes will tell you when and where there +is a problem\dash{}\pxlref{efficiency-notes}. + + +\subsection{Fixnums} +\label{fixnums} +\cindex{fixnums} +\cindex{bignums} + +A fixnum is a ``FIXed precision NUMber''. In modern \llisp{} +implementations, fixnums can be represented with an immediate +descriptor, so operating on fixnums requires no consing or memory +references. Clever choice of representations also allows some +arithmetic operations to be done on fixnums using hardware supported +word-integer instructions, somewhat reducing the speed penalty for +using an unnatural integer representation. + +It is useful to distinguish the \code{fixnum} type from the fixnum +representation of integers. In \python, there is absolutely nothing +magical about the \code{fixnum} type in comparison to other finite +integer types. \code{fixnum} is equivalent to (is defined with +\code{deftype} to be) \w{\code{(signed-byte 30)}}. \code{fixnum} is +simply the largest subset of integers that {\em can be represented} +using an immediate fixnum descriptor. + +Unlike in other \clisp{} compilers, it is in no way desirable to use +the \code{fixnum} type in declarations in preference to more +restrictive integer types such as \code{bit}, \w{\code{(integer -43 + 7)}} and \w{\code{(unsigned-byte 8)}}. Since \python{} does +understand these integer types, it is preferable to use the more +restrictive type, as it allows better type inference +(\pxlref{operation-type-inference}.) + +The small, efficient fixnum is contrasted with bignum, or ``BIG +NUMber''. This is another descriptor representation for integers, but +this time a pointer representation that allows for arbitrarily large +integers. Bignum operations are less efficient than fixnum +operations, both because of the consing and memory reference overheads +of a pointer descriptor, and also because of the inherent complexity +of extended precision arithmetic. While fixnum operations can often +be done with a single instruction, bignum operations are so complex +that they are always done using generic arithmetic. + +A crucial point is that the compiler will use generic arithmetic if it +can't \var{prove} that all the arguments, intermediate values, and +results are fixnums. With bounded integer types such as +\code{fixnum}, the result type proves to be especially problematical, +since these types are not closed under common arithmetic operations +such as \code{+}, \code{-}, \code{*} and \code{/}. For example, +\w{\code{(1+ (the fixnum x))}} does not necessarily evaluate to a +\code{fixnum}. Bignums were added to \llisp{} to get around this +problem, but they really just transform the correctness problem ``if +this add overflows, you will get the wrong answer'' to the efficiency +problem ``if this add \var{might} overflow then your program will run +slowly (because of generic arithmetic.)'' + +There is just no getting around the fact that the hardware only +directly supports short integers. To get the most efficient open +coding, the compiler must be able to prove that the result is a good +integer type. This is an argument in favor of using more restrictive +integer types: \w{\code{(1+ (the fixnum x))}} may not always be a +\code{fixnum}, but \w{\code{(1+ (the (unsigned-byte 8) x))}} always +is. Of course, you can also assert the result type by putting in lots +of \code{the} declarations and then compiling with \code{safety} +\code{0}. + + +\subsection{Word Integers} +\label{word-integers} +\cindex{word integers} + +\python{} is unique in its efficient implementation of arithmetic +on full-word integers through non-descriptor representations and open coding. +Arithmetic on any subtype of these types: + +\begin{lisp} +(signed-byte 32) +(unsigned-byte 32) +\end{lisp} + +is reasonably efficient, although subtypes of \code{fixnum} remain +somewhat more efficient. + +If a word integer must be represented as a descriptor, then the +\code{bignum} representation is used, with its associated consing +overhead. The support for word integers in no way changes the +language semantics, it just makes arithmetic on small bignums vastly +more efficient. It is fine to do arithmetic operations with mixed +\code{fixnum} and word integer operands; just declare the most +specific integer type you can, and let the compiler decide what +representation to use. + +In fact, to most users, the greatest advantage of word integer +arithmetic is that it effectively provides a few guard bits on the +fixnum representation. If there are missing assertions on +intermediate values in a fixnum expression, the intermediate results +can usually be proved to fit in a word. After the whole expression is +evaluated, there will often be a fixnum assertion on the final result, +allowing creation of a fixnum result without even checking for +overflow. + +The remarks in section \ref{fixnums} about fixnum result type also +apply to word integers; you must be careful to give the compiler +enough information to prove that the result is still a word integer. +This time, though, when we blow out of word integers we land in into +generic bignum arithmetic, which is much worse than sleazing from +\code{fixnum}s to word integers. Note that mixing +\w{\code{(unsigned-byte 32)}} arguments with arguments of any signed +type (such as \code{fixnum}) is a no-no, since the result might not be +unsigned. + + +\subsection{Floating Point Efficiency} +\label{float-efficiency} +\cindex{floating point efficiency} + +Arithmetic on objects of type \code{single-float} and \code{double-float} is +efficiently implemented using non-descriptor representations and open coding. +As for integer arithmetic, the arguments must be known to be of the same float +type. Unlike for integer arithmetic, the results and intermediate values +usually take care of themselves due to the rules of float contagion, i.e. +\w{\code{(1+ (the single-float x))}} is always a \code{single-float}. + +Although they are not specially implemented, \code{short-float} and +\code{long-float} are also acceptable in declarations, since they are +synonyms for the \code{single-float} and \code{double-float} types, +respectively. + +In \cmucl{}, list-style float type specifiers such as +\w{\code{(single-float 0.0 1.0)}} will be used to good effect. + +For example, in this function, + +\begin{example} + (defun square (x) + (declare (type (single-float 0f0 10f0))) + (* x x)) +\end{example} + +\python{} can deduce that the +return type of the function \code{square} is \w{\code{(single-float + 0f0 100f0)}}. + +Many union types are also supported so that + +\begin{example} + (+ (the (or (integer 1 1) (integer 5 5)) x) + (the (or (integer 10 10) (integer 20 20)) y)) +\end{example} + +has the inferred type \code{(or (integer 11 11) (integer 15 15) + (integer 21 21) (integer 25 25))}. This also works for +floating-point numbers. Member types are also supported. + +\cmucl{} can also infer types for many mathematical functions +including square root, exponential and logarithmic functions, +trignometric functions and their inverses, and hyperbolic functions +and their inverses. For numeric code, this can greatly enhance +efficiency by allowing the compiler to use specialized versions of +the functions instead of the generic versions. The greatest benefit +of this type inference is determining that the result of the +function is real-valued number instead of possibly being +a complex-valued number. + +For example, consider the function +\begin{example} + (defun fun (x) + (declare (type (single-float (0f0) 100f0) x)) + (values (sqrt x) (log x))) +\end{example} +With this declaration, the compiler can determine that the argument +to \code{sqrt} and \code{log} are always non-negative so that the result +is always a \code{single-float}. In fact, the return type for this +function is derived to be \code{(values (single-float 0f0 10f0) + (single-float * 2f0))}. + +If the declaration were reduced to just \w{\code{(declare + (single-float x))}}, the argument to \code{sqrt} and \code{log} +could be negative. This forces the use of the generic versions of +these functions because the result could be a complex number. + +We note, however, that proper interval arithmetic is not fully +implemented in the compiler so the inferred types may be slightly in +error due to round-off errors. This round-off error could +accumulate to cause the compiler to erroneously deduce the result +type and cause code to be removed as being +unreachable.\footnote{This, however, has not actually happened, but + it is a possibility.}% +Thus, the declarations should only be precise enough for the +compiler to deduce that a real-valued argument to a function would +produce a real-valued result. The efficiency notes +(\pxlref{representation-eff-note}) from the compiler will guide you +on what declarations might be useful. + +When a float must be represented as a descriptor, a pointer representation is +used, creating consing overhead. For this reason, you should try to avoid +situations (such as full call and non-specialized data structures) that force a +descriptor representation. See sections \ref{specialized-array-types}, +\ref{raw-slots} and \ref{number-local-call}. + +\xlref{ieee-float} for information on the extensions to support IEEE +floating point. + +\subsubsection{Signed Zeroes and Special Functions} + +\cmucl{} supports IEEE signed zeroes. In typical usage, the signed +zeroes are not a problem and can be treated as an unsigned zero. +However, some of the special functions have branch points at zero, so +care must be taken. + +For example, suppose we have the function +\begin{example} + (defun fun (x) + (declare (type (single-float 0f0) x)) + (log x)) +\end{example} +The derived result of the function is \code{(OR SINGLE-FLOAT +(COMPLEX SINGLE-FLOAT))} because the declared values for +\code{x} includes both $-0.0$ and $0.0$ and \code{(log -0.0)} is +actually a complex number. Because of this, the generic complex log +routine is used. + +If the declaration for \code{x} were \code{(single-float (0f0))} so $+0.0$ +is not included or \code{(or (single-float (0f0)) (member 0f0))} so + $+0.0$ is include but not $-0.0$, the derived type would be + \code{single-float} for both cases. By declaring \code{x} this way, + the log can be implemented using a fast real-valued log routine + instead of the generic log routine. + +\cmucl{} implements the branch cuts and values given by +Kahan\footnote{Kahan, W., ``Branch Cuts for Complex Elementary +Functions, or Much Ado About Nothing's Sign Bit'' +in Iserles and Powell (eds.) \textit{The State of the Art +in Numerical Analysis}, pp. 165-211, Clarendon +Press, 1987}. + + + +\subsection{Specialized Arrays} +\label{specialized-array-types} +\cindex{specialized array types} +\cpsubindex{array types}{specialized} +\cpsubindex{types}{specialized array} + +\clisp{} supports specialized array element types through the +\kwd{element-type} argument to \code{make-array}. When an array has a +specialized element type, only elements of that type can be stored in +the array. From this restriction comes two major efficiency +advantages: +\begin{itemize} + +\item A specialized array can save space by packing multiple elements + into a single word. For example, a \code{base-char} array can have + 4 elements per word, and a \code{bit} array can have 32. This + space-efficient representation is possible because it is not + necessary to separately indicate the type of each element. + +\item The elements in a specialized array can be given the same + non-descriptor representation as the one used in registers and on + the stack, eliminating the need for representation conversions when + reading and writing array elements. For objects with pointer + descriptor representations (such as floats and word integers) there + is also a substantial consing reduction because it is not necessary + to allocate a new object every time an array element is modified. +\end{itemize} + + +These are the specialized element types currently supported: +\begin{lisp} +bit +(unsigned-byte 2) +(unsigned-byte 4) +(unsigned-byte 8) +(unsigned-byte 16) +(unsigned-byte 32) +(signed-byte 8) +(signed-byte 16) +(signed-byte 30) +(signed-byte 32) +base-character +single-float +double-float +ext:double-double-float +(complex single-float) +(complex double-float) +(complex ext:double-double-float) +\end{lisp} + +Although a \code{simple-vector} can hold any type of object, \true{} +should still be considered a specialized array type, since arrays with +element type \true{} are specialized to hold descriptors. + + + +When using non-descriptor representations, it is particularly +important to make sure that array accesses are open-coded, since in +addition to the generic operation overhead, efficiency is lost when +the array element is converted to a descriptor so that it can be +passed to (or from) the generic access routine. You can detect +inefficient array accesses by enabling efficiency notes, +\pxlref{efficiency-notes}. \xlref{array-types}. + + +\subsection{Specialized Structure Slots} +\label{raw-slots} +\cpsubindex{structure types}{numeric slots} +\cindex{specialized structure slots} + +Structure slots declared by the \kwd{type} \code{defstruct} slot option +to have certain known numeric types are also given non-descriptor +representations. These types (and subtypes of these types) are supported: +\begin{lisp} +(unsigned-byte 32) +single-float +double-float +(complex single-float) +(complex double-float) +\end{lisp} + +The primary advantage of specialized slot representations is a large +reduction spurious memory allocation and access overhead of programs +that intensively use these types. + + +\subsection{Interactions With Local Call} +\label{number-local-call} +\cpsubindex{local call}{numeric operands} +\cpsubindex{call}{numeric operands} +\cindex{numbers in local call} + +Local call has many advantages (\pxlref{local-call}); one relevant to +our discussion here is that local call extends the usefulness of +non-descriptor representations. If the compiler knows from the +argument type that an argument has a non-descriptor representation, +then the argument will be passed in that representation. The easiest +way to ensure that the argument type is known at compile time is to +always declare the argument type in the called function, like: +\begin{lisp} +(defun 2+f (x) + (declare (single-float x)) + (+ x 2.0)) +\end{lisp} +The advantages of passing arguments and return values in a non-descriptor +representation are the same as for non-descriptor representations in general: +reduced consing and memory access (\pxlref{non-descriptor}.) This +extends the applicative programming styles discussed in section +\ref{local-call} to numeric code. Also, if source files are kept reasonably +small, block compilation can be used to reduce number consing to a minimum. + +Note that non-descriptor return values can only be used with the known return +convention (section \ref{local-call-return}.) If the compiler can't prove that +a function always returns the same number of values, then it must use the +unknown values return convention, which requires a descriptor representation. +Pay attention to the known return efficiency notes to avoid number consing. + + +\subsection{Representation of Characters} +\label{characters} +\cindex{characters} +\cindex{strings} + +\python{} also uses a non-descriptor representation for characters when +convenient. This improves the efficiency of string manipulation, but is +otherwise pretty invisible; characters have an immediate descriptor +representation, so there is not a great penalty for converting a character to a +descriptor. Nonetheless, it may sometimes be helpful to declare +character-valued variables as \code{base-character}. + + +\section{General Efficiency Hints} +\label{general-efficiency} +\cpsubindex{efficiency}{general hints} + +This section is a summary of various implementation costs and ways to get +around them. These hints are relatively unrelated to the use of the \python{} +compiler, and probably also apply to most other \llisp{} implementations. In +each section, there are references to related in-depth discussion. + + +\subsection{Compile Your Code} +\cpsubindex{compilation}{why to} + +At this point, the advantages of compiling code relative to running it +interpreted probably need not be emphasized too much, but remember that +in \cmucl, compiled code typically runs hundreds of times faster than +interpreted code. Also, compiled (\code{fasl}) files load significantly faster +than source files, so it is worthwhile compiling files which are loaded many +times, even if the speed of the functions in the file is unimportant. + +Even disregarding the efficiency advantages, compiled code is as good or better +than interpreted code. Compiled code can be debugged at the source level (see +chapter \ref{debugger}), and compiled code does more error checking. For these +reasons, the interpreter should be regarded mainly as an interactive command +interpreter, rather than as a programming language implementation. + +\b{Do not} be concerned about the performance of your program until you +see its speed compiled. Some techniques that make compiled code run +faster make interpreted code run slower. + + +\subsection{Avoid Unnecessary Consing} +\label{consing} +\cindex{consing} +\cindex{garbage collection} +\cindex{memory allocation} +\cpsubindex{efficiency}{of memory use} + + +Consing is another name for allocation of storage, as done by the +\code{cons} function (hence its name.) \code{cons} is by no means the +only function which conses\dash{}so does \code{make-array} and many +other functions. Arithmetic and function call can also have hidden +consing overheads. Consing hurts performance in the following ways: +\begin{itemize} + +\item Consing reduces memory access locality, increasing paging + activity. + +\item Consing takes time just like anything else. + +\item Any space allocated eventually needs to be reclaimed, either by + garbage collection or by starting a new \code{lisp} process. +\end{itemize} + + +Consing is not undiluted evil, since programs do things other than +consing, and appropriate consing can speed up the real work. It would +certainly save time to allocate a vector of intermediate results that +are reused hundreds of times. Also, if it is necessary to copy a +large data structure many times, it may be more efficient to update +the data structure non-destructively; this somewhat increases update +overhead, but makes copying trivial. + +Note that the remarks in section \ref{efficiency-overview} about the +importance of separating tuning from coding also apply to consing +overhead. The majority of consing will be done by a small portion of +the program. The consing hot spots are even less predictable than the +CPU hot spots, so don't waste time and create bugs by doing +unnecessary consing optimization. During initial coding, avoid +unnecessary side-effects and cons where it is convenient. If +profiling reveals a consing problem, \var{then} go back and fix the +hot spots. + +\xlref{non-descriptor} for a discussion of how to avoid number consing +in \python. + + +\subsection{Complex Argument Syntax} +\cpsubindex{argument syntax}{efficiency} +\cpsubindex{efficiency}{of argument syntax} +\cindex{keyword argument efficiency} +\cindex{rest argument efficiency} + +\clisp{} has very powerful argument passing mechanisms. Unfortunately, two +of the most powerful mechanisms, rest arguments and keyword arguments, have a +significant performance penalty: + +\begin{itemize} +\item +With keyword arguments, the called function has to parse the supplied keywords +by iterating over them and checking them against the desired keywords. + +\item +With rest arguments, the function must cons a list to hold the arguments. If a +function is called many times or with many arguments, large amounts of memory +will be allocated. +\end{itemize} + +Although rest argument consing is worse than keyword parsing, neither problem +is serious unless thousands of calls are made to such a function. The use of +keyword arguments is strongly encouraged in functions with many arguments or +with interfaces that are likely to be extended, and rest arguments are often +natural in user interface functions. + +Optional arguments have some efficiency advantage over keyword +arguments, but their syntactic clumsiness and lack of extensibility +has caused many \clisp{} programmers to abandon use of optionals +except in functions that have obviously simple and immutable +interfaces (such as \code{subseq}), or in functions that are only +called in a few places. When defining an interface function to be +used by other programmers or users, use of only required and keyword +arguments is recommended. + +Parsing of \code{defmacro} keyword and rest arguments is done at +compile time, so a macro can be used to provide a convenient syntax +with an efficient implementation. If the macro-expanded form contains +no keyword or rest arguments, then it is perfectly acceptable in inner +loops. + +Keyword argument parsing overhead can also be avoided by use of inline +expansion (\pxlref{inline-expansion}) and block compilation (section +\ref{block-compilation}.) + +Note: the compiler open-codes most heavily used system functions which have +keyword or rest arguments, so that no run-time overhead is involved. + + +\subsection{Mapping and Iteration} +\cpsubindex{mapping}{efficiency of} + +One of the traditional \llisp{} programming styles is a highly applicative one, +involving the use of mapping functions and many lists to store intermediate +results. To compute the sum of the square-roots of a list of numbers, one +might say: + +\begin{lisp} +(apply #'+ (mapcar #'sqrt list-of-numbers)) +\end{lisp} + +This programming style is clear and elegant, but unfortunately results +in slow code. There are two reasons why: + +\begin{itemize} +\item The creation of lists of intermediate results causes much + consing (see \ref{consing}). + +\item Each level of application requires another scan down the list. + Thus, disregarding other effects, the above code would probably take + twice as long as a straightforward iterative version. +\end{itemize} + + +An example of an iterative version of the same code: +\begin{lisp} +(do ((num list-of-numbers (cdr num)) + (sum 0 (+ (sqrt (car num)) sum))) + ((null num) sum)) +\end{lisp} + +See sections \ref{variable-type-inference} and \ref{let-optimization} +for a discussion of the interactions of iteration constructs with type +inference and variable optimization. Also, section +\ref{local-tail-recursion} discusses an applicative style of +iteration. + + +\subsection{Trace Files and Disassembly} +\label{trace-files} +\cindex{trace files} +\cindex{assembly listing} +\cpsubindex{listing files}{trace} +\cindex{Virtual Machine (VM, or IR2) representation} +\cindex{implicit continuation representation (IR1)} +\cpsubindex{continuations}{implicit representation} + +In order to write efficient code, you need to know the relative costs +of different operations. The main reason why writing efficient +\llisp{} code is difficult is that there are so many operations, and +the costs of these operations vary in obscure context-dependent ways. +Although efficiency notes point out some problem areas, the only way +to ensure generation of the best code is to look at the assembly code +output. + +The \code{disassemble} function is a convenient way to get the assembly code for a +function, but it can be very difficult to interpret, since the correspondence +with the original source code is weak. A better (but more awkward) option is +to use the \kwd{trace-file} argument to \code{compile-file} to generate a trace +file. + +A trace file is a dump of the compiler's internal representations, +including annotated assembly code. Each component in the program gets +four pages in the trace file (separated by ``\code{$\hat{ }L$}''): +\begin{itemize} + +\item The implicit-continuation (or IR1) representation of the + optimized source. This is a dump of the flow graph representation + used for ``source level'' optimizations. As you will quickly + notice, it is not really very close to the source. This + representation is not very useful to even sophisticated users. + +\item The Virtual Machine (VM, or IR2) representation of the program. + This dump represents the generated code as sequences of ``Virtual + OPerations'' (VOPs.) This representation is intermediate between + the source and the assembly code\dash{}each VOP corresponds fairly + directly to some primitive function or construct, but a given VOP + also has a fairly predictable instruction sequence. An operation + (such as \code{+}) may have multiple implementations with different + cost and applicability. The choice of a particular VOP such as + \code{+/fixnum} or \code{+/single-float} represents this choice of + implementation. Once you are familiar with it, the VM + representation is probably the most useful for determining what + implementation has been used. + +\item An assembly listing, annotated with the VOP responsible for + generating the instructions. This listing is useful for figuring + out what a VOP does and how it is implemented in a particular + context, but its large size makes it more difficult to read. + +\item A disassembly of the generated code, which has all + pseudo-operations expanded out, but is not annotated with VOPs. +\end{itemize} + + +Note that trace file generation takes much space and time, since the trace file +is tens of times larger than the source file. To avoid huge confusing trace +files and much wasted time, it is best to separate the critical program portion +into its own file and then generate the trace file from this small file. + + +\section{Efficiency Notes} +\label{efficiency-notes} +\cindex{efficiency notes} +\cpsubindex{notes}{efficiency} +\cindex{tuning} + +Efficiency notes are messages that warn the user that the compiler has +chosen a relatively inefficient implementation for some operation. +Usually an efficiency note reflects the compiler's desire for more +type information. If the type of the values concerned is known to the +programmer, then additional declarations can be used to get a more +efficient implementation. + +Efficiency notes are controlled by the +\code{extensions:inhibit-warnings} (\pxlref{optimize-declaration}) +optimization quality. When \code{speed} is greater than +\code{extensions:inhibit-warnings}, efficiency notes are enabled. +Note that this implicitly enables efficiency notes whenever +\code{speed} is increased from its default of \code{1}. + +Consider this program with an obscure missing declaration: + +\begin{lisp} +(defun eff-note (x y z) + (declare (fixnum x y z)) + (the fixnum (+ x y z))) +\end{lisp} + +If compiled with \code{\w{(speed 3) (safety 0)}}, this note is given: + +\begin{example} +In: DEFUN EFF-NOTE + (+ X Y Z) +==> + (+ (+ X Y) Z) +Note: Forced to do inline (signed-byte 32) arithmetic (cost 3). + Unable to do inline fixnum arithmetic (cost 2) because: + The first argument is a (INTEGER -1073741824 1073741822), + not a FIXNUM. +\end{example} + +This efficiency note tells us that the result of the intermediate +computation \code{\w{(+ x y)}} is not known to be a \code{fixnum}, so +the addition of the intermediate sum to \code{z} must be done less +efficiently. This can be fixed by changing the definition of +\code{eff-note}: + +\begin{lisp} +(defun eff-note (x y z) + (declare (fixnum x y z)) + (the fixnum (+ (the fixnum (+ x y)) z))) +\end{lisp} + + +\subsection{Type Uncertainty} +\cpsubindex{types}{uncertainty} +\cindex{uncertainty of types} + +The main cause of inefficiency is the compiler's lack of adequate +information about the types of function argument and result values. +Many important operations (such as arithmetic) have an inefficient +general (generic) case, but have efficient implementations that can +usually be used if there is sufficient argument type information. + +Type efficiency notes are given when a value's type is uncertain. +There is an important distinction between values that are {\em not +known} to be of a good type (uncertain) and values that are {\em known +not} to be of a good type. Efficiency notes are given mainly for the +first case (uncertain types.) If it is clear to the compiler that that +there is not an efficient implementation for a particular function +call, then an efficiency note will only be given if the +\code{extensions:inhibit-warnings} optimization quality is \code{0} +(\pxlref{optimize-declaration}.) + +In other words, the default efficiency notes only suggest that you add +declarations, not that you change the semantics of your program so +that an efficient implementation will apply. For example, compilation +of this form will not give an efficiency note: +\begin{lisp} +(elt (the list l) i) +\end{lisp} +even though a vector access is more efficient than indexing a list. + + +\subsection{Efficiency Notes and Type Checking} +\cpsubindex{type checking}{efficiency of} +\cpsubindex{efficiency}{of type checking} +\cpsubindex{optimization}{type check} + +It is important that the \code{eff-note} example above used +\w{\code{(safety 0)}}. When type checking is enabled, you may get apparently +spurious efficiency notes. With \w{\code{(safety 1)}}, the note has this extra +line on the end: + +\begin{example} +The result is a (INTEGER -1610612736 1610612733), not a FIXNUM. +\end{example} + +This seems strange, since there is a \code{the} declaration on the result of that +second addition. + +In fact, the inefficiency is real, and is a consequence of \python{}'s +treating declarations as assertions to be verified. The compiler +can't assume that the result type declaration is true\dash{}it must +generate the result and then test whether it is of the appropriate +type. + +In practice, this means that when you are tuning a program to run +without type checks, you should work from the efficiency notes +generated by unsafe compilation. If you want code to run efficiently +with type checking, then you should pay attention to all the +efficiency notes that you get during safe compilation. Since user +supplied output type assertions (e.g., from \code{the}) are +disregarded when selecting operation implementations for safe code, +you must somehow give the compiler information that allows it to prove +that the result truly must be of a good type. In our example, it +could be done by constraining the argument types more: + +\begin{lisp} +(defun eff-note (x y z) + (declare (type (unsigned-byte 18) x y z)) + (+ x y z)) +\end{lisp} + +Of course, this declaration is acceptable only if the arguments to \code{eff-note} +always \var{are} \w{\code{(unsigned-byte 18)}} integers. + + +\subsection{Representation Efficiency Notes} +\label{representation-eff-note} +\cindex{representation efficiency notes} +\cpsubindex{efficiency notes}{for representation} +\cindex{object representation efficiency notes} +\cindex{stack numbers} +\cindex{non-descriptor representations} +\cpsubindex{descriptor representations}{forcing of} + +When operating on values that have non-descriptor representations +(\pxlref{non-descriptor}), there can be a substantial time and consing +penalty for converting to and from descriptor representations. For +this reason, the compiler gives an efficiency note whenever it is +forced to do a representation coercion more expensive than +\varref{efficiency-note-cost-threshold}. + +Inefficient representation coercions may be due to type uncertainty, +as in this example: + +\begin{lisp} +(defun set-flo (x) + (declare (single-float x)) + (prog ((var 0.0)) + (setq var (gorp)) + (setq var x) + (return var))) +\end{lisp} + +which produces this efficiency note: + +\begin{example} +In: DEFUN SET-FLO + (SETQ VAR X) +Note: Doing float to pointer coercion (cost 13) from X to VAR. +\end{example} + +The variable \code{var} is not known to always hold values of type +\code{single-float}, so a descriptor representation must be used for its value. +In this sort of situation, adding a declaration will eliminate the inefficiency. + +Often inefficient representation conversions are not due to type +uncertainty\dash{}instead, they result from evaluating a +non-descriptor expression in a context that requires a descriptor +result: + +\begin{itemize} +\item Assignment to or initialization of any data structure other than + a specialized array (\pxlref{specialized-array-types}), or + +\item Assignment to a \code{special} variable, or + +\item Passing as an argument or returning as a value in any function + call that is not a local call (\pxlref{number-local-call}.) +\end{itemize} + +If such inefficient coercions appear in a ``hot spot'' in the program, data +structures redesign or program reorganization may be necessary to improve +efficiency. See sections \ref{block-compilation}, \ref{numeric-types} and +\ref{profiling}. + +Because representation selection is done rather late in compilation, +the source context in these efficiency notes is somewhat vague, making +interpretation more difficult. This is a fairly straightforward +example: + +\begin{lisp} +(defun cf+ (x y) + (declare (single-float x y)) + (cons (+ x y) t)) +\end{lisp} + +which gives this efficiency note: + +\begin{example} +In: DEFUN CF+ + (CONS (+ X Y) T) +Note: Doing float to pointer coercion (cost 13), for: + The first argument of CONS. +\end{example} + +The source context form is almost always the form that receives the value being +coerced (as it is in the preceding example), but can also be the source form +which generates the coerced value. Compiling this example: + +\begin{lisp} +(defun if-cf+ (x y) + (declare (single-float x y)) + (cons (if (grue) (+ x y) (snoc)) t)) +\end{lisp} + +produces this note: + +\begin{example} +In: DEFUN IF-CF+ + (+ X Y) +Note: Doing float to pointer coercion (cost 13). +\end{example} + +In either case, the note's text explanation attempts to include +additional information about what locations are the source and +destination of the coercion. Here are some example notes: +\begin{example} + (IF (GRUE) X (SNOC)) +Note: Doing float to pointer coercion (cost 13) from X. + + (SETQ VAR X) +Note: Doing float to pointer coercion (cost 13) from X to VAR. +\end{example} +Note that the return value of a function is also a place to which coercions may +have to be done: +\begin{example} + (DEFUN F+ (X Y) (DECLARE (SINGLE-FLOAT X Y)) (+ X Y)) +Note: Doing float to pointer coercion (cost 13) to "". +\end{example} +Sometimes the compiler is unable to determine a name for the source or +destination, in which case the source context is the only clue. + + +\subsection{Verbosity Control} +\cpsubindex{verbosity}{of efficiency notes} +\cpsubindex{efficiency notes}{verbosity} + +These variables control the verbosity of efficiency notes: + +\begin{defvar}{}{efficiency-note-cost-threshold} + + Before printing some efficiency notes, the compiler compares the + value of this variable to the difference in cost between the chosen + implementation and the best potential implementation. If the + difference is not greater than this limit, then no note is printed. + The units are implementation dependent; the initial value suppresses + notes about ``trivial'' inefficiencies. A value of \code{1} will + note any inefficiency. +\end{defvar} + +\begin{defvar}{}{efficiency-note-limit} + + When printing some efficiency notes, the compiler reports possible + efficient implementations. The initial value of \code{2} prevents + excessively long efficiency notes in the common case where there is + no type information, so all implementations are possible. +\end{defvar} + + +\section{Profiling} +\cindex{profiling} +\cindex{timing} +\cindex{consing} +\cindex{tuning} +\label{profiling} + +The first step in improving a program's performance is to profile the +activity of the program to find where it spends its time. The best +way to do this is to use the profiling utility found in the +\code{profile} package. This package provides a macro \code{profile} +that encapsulates functions with statistics gathering code. + + +\subsection{Profile Interface} + +\begin{defvar}{profile:}{timed-functions} + + This variable holds a list of all functions that are currently being + profiled. +\end{defvar} + +\begin{defmac}{profile:}{profile}{% + \args{\mstar{\var{name} \mor \kwd{callers} \code{t}}}} + + This macro wraps profiling code around the named functions. As in + \code{trace}, the \var{name}s are not evaluated. If a function is + already profiled, then the function is unprofiled and reprofiled + (useful to notice function redefinition.) A warning is printed for + each name that is not a defined function. + + If \kwd{callers \var{t}} is specified, then each function that calls + this function is recorded along with the number of calls made. +\end{defmac} + +\begin{defmac}{profile:}{unprofile}{% + \args{\mstar{\var{name}}}} + + This macro removes profiling code from the named functions. If no + \var{name}s are supplied, all currently profiled functions are + unprofiled. +\end{defmac} + +\begin{defmac}{profile:}{profile-all}{% + \args{\keys{\kwd{package} \kwd{callers-p}}}} + + This macro in effect calls \code{profile:profile} for each + function in the specified package which defaults to + \code{*package*}. \kwd{callers-p} has the same meaning as in + \code{profile:profile}. +\end{defmac} + +\begin{defmac}{profile:}{report-time}{\args{\mstar{\var{name}}}} + + This macro prints a report for each \var{name}d function of the + following information: + \begin{itemize} + \item The total CPU time used in that function for all calls, + + \item the total number of bytes consed in that function for all + calls, + + \item the total number of calls, + + \item the average amount of CPU time per call. + \end{itemize} + Summary totals of the CPU time, consing and calls columns are + printed. An estimate of the profiling overhead is also printed (see + below). If no \var{name}s are supplied, then the times for all + currently profiled functions are printed. +\end{defmac} + +\begin{defmac}{}{reset-time}{\args{\mstar{\var{name}}}} + + This macro resets the profiling counters associated with the + \var{name}d functions. If no \var{name}s are supplied, then all + currently profiled functions are reset. +\end{defmac} + + +\subsection{Profiling Techniques} + +Start by profiling big pieces of a program, then carefully choose which +functions close to, but not in, the inner loop are to be profiled next. +Avoid profiling functions that are called by other profiled functions, since +this opens the possibility of profiling overhead being included in the reported +times. + +If the per-call time reported is less than 1/10 second, then consider the clock +resolution and profiling overhead before you believe the time. It may be that +you will need to run your program many times in order to average out to a +higher resolution. + + +\subsection{Nested or Recursive Calls} + +The profiler attempts to compensate for nested or recursive calls. Time and +consing overhead will be charged to the dynamically innermost (most recent) +call to a profiled function. So profiling a subfunction of a profiled function +will cause the reported time for the outer function to decrease. However if an +inner function has a large number of calls, some of the profiling overhead may +``leak'' into the reported time for the outer function. In general, be wary of +profiling short functions that are called many times. + + +\subsection{Clock resolution} + +Unless you are very lucky, the length of your machine's clock ``tick'' is +probably much longer than the time it takes simple function to run. For +example, on the IBM RT, the clock resolution is 1/50 second. This means that +if a function is only called a few times, then only the first couple decimal +places are really meaningful. + +Note however, that if a function is called many times, then the statistical +averaging across all calls should result in increased resolution. For example, +on the IBM RT, if a function is called a thousand times, then a resolution of +tens of microseconds can be expected. + +\subsection{Profiling overhead} + +The added profiling code takes time to run every time that the profiled +function is called, which can disrupt the attempt to collect timing +information. In order to avoid serious inflation of the times for functions +that take little time to run, an estimate of the overhead due to profiling is +subtracted from the times reported for each function. + +Although this correction works fairly well, it is not totally accurate, +resulting in times that become increasingly meaningless for functions with +short runtimes. This is only a concern when the estimated profiling overhead +is many times larger than reported total CPU time. + +The estimated profiling overhead is not represented in the reported total CPU +time. The sum of total CPU time and the estimated profiling overhead should be +close to the total CPU time for the entire profiling run (as determined by the +\code{time} macro.) Time unaccounted for is probably being used by functions that +you forgot to profile. + +\subsection{Additional Timing Utilities} + +\begin{defmac}{}{time}{ \args{\var{form}}} + + This macro evaluates \var{form}, prints some timing and memory + allocation information to \code{*trace-output*}, and returns any + values that \var{form} returns. The timing information includes + real time, user run time, and system run time. This macro executes + a form and reports the time and consing overhead. If the + \code{time} form is not compiled (e.g. it was typed at top-level), + then \code{compile} will be called on the form to give more accurate + timing information. If you really want to time interpreted speed, + you can say: +\begin{lisp} +(time (eval '\var{form})) +\end{lisp} +Things that execute fairly quickly should be timed more than once, +since there may be more paging overhead in the first timing. To +increase the accuracy of very short times, you can time multiple +evaluations: +\begin{lisp} +(time (dotimes (i 100) \var{form})) +\end{lisp} +\end{defmac} + +\begin{defun}{extensions:}{get-bytes-consed}{} + + This function returns the number of bytes allocated since the first + time you called it. The first time it is called it returns zero. + The above profiling routines use this to report consing information. +\end{defun} + +\begin{defvar}{extensions:}{gc-run-time} + + This variable accumulates the run-time consumed by garbage + collection, in the units returned by + \findexed{get-internal-run-time}. +\end{defvar} + +\begin{defconst}{}{internal-time-units-per-second} +The value of internal-time-units-per-second is 100. +\end{defconst} + +\subsection{A Note on Timing} +\cpsubindex{CPU time}{interpretation of} +\cpsubindex{run time}{interpretation of} +\cindex{interpretation of run time} + +There are two general kinds of timing information provided by the +\code{time} macro and other profiling utilities: real time and run +time. Real time is elapsed, wall clock time. It will be affected in +a fairly obvious way by any other activity on the machine. The more +other processes contending for CPU and memory, the more real time will +increase. This means that real time measurements are difficult to +replicate, though this is less true on a dedicated workstation. The +advantage of real time is that it is real. It tells you really how +long the program took to run under the benchmarking conditions. The +problem is that you don't know exactly what those conditions were. + +Run time is the amount of time that the processor supposedly spent +running the program, as opposed to waiting for I/O or running other +processes. ``User run time'' and ``system run time'' are numbers +reported by the Unix kernel. They are supposed to be a measure of how +much time the processor spent running your ``user'' program (which +will include GC overhead, etc.), and the amount of time that the +kernel spent running ``on your behalf.'' + +Ideally, user time should be totally unaffected by benchmarking +conditions; in reality user time does depend on other system activity, +though in rather non-obvious ways. + +System time will clearly depend on benchmarking conditions. In Lisp +benchmarking, paging activity increases system run time (but not by as much +as it increases real time, since the kernel spends some time waiting for +the disk, and this is not run time, kernel or otherwise.) + +In my experience, the biggest trap in interpreting kernel/user run time is +to look only at user time. In reality, it seems that the \var{sum} of kernel +and user time is more reproducible. The problem is that as system activity +increases, there is a spurious \var{decrease} in user run time. In effect, as +paging, etc., increases, user time leaks into system time. + +So, in practice, the only way to get truly reproducible results is to run +with the same competing activity on the system. Try to run on a machine +with nobody else logged in, and check with ``ps aux'' to see if there are any +system processes munching large amounts of CPU or memory. If the ratio +between real time and the sum of user and system time varies much between +runs, then you have a problem. + + +\subsection{Benchmarking Techniques} +\cindex{benchmarking techniques} + +Given these imperfect timing tools, how do should you do benchmarking? The +answer depends on whether you are trying to measure improvements in the +performance of a single program on the same hardware, or if you are trying to +compare the performance of different programs and/or different hardware. + +For the first use (measuring the effect of program modifications with +constant hardware), you should look at \var{both} system+user and real time to +understand what effect the change had on CPU use, and on I/O (including +paging.) If you are working on a CPU intensive program, the change in +system+user time will give you a moderately reproducible measure of +performance across a fairly wide range of system conditions. For a CPU +intensive program, you can think of system+user as ``how long it would have +taken to run if I had my own machine.'' So in the case of comparing CPU +intensive programs, system+user time is relatively real, and reasonable to +use. + +For programs that spend a substantial amount of their time paging, you +really can't predict elapsed time under a given operating condition without +benchmarking in that condition. User or system+user time may be fairly +reproducible, but it is also relatively meaningless, since in a paging or +I/O intensive program, the program is spending its time waiting, not +running, and system time and user time are both measures of run time. +A change that reduces run time might increase real time by increasing +paging. + +Another common use for benchmarking is comparing the performance of +the same program on different hardware. You want to know which +machine to run your program on. For comparing different machines +(operating systems, etc.), the only way to compare that makes sense is +to set up the machines in \var{exactly} the way that they will +\var{normally} be run, and then measure \var{real} time. If the +program will normally be run along with X, then run X. If the program +will normally be run on a dedicated workstation, then be sure nobody +else is on the benchmarking machine. If the program will normally be +run on a machine with three other Lisp jobs, then run three other Lisp +jobs. If the program will normally be run on a machine with 64MB of +memory, then run with 64MB. Here, ``normal'' means ``normal for that +machine''. + +If you have a program you believe to be CPU intensive, then you might be +tempted to compare ``run'' times across systems, hoping to get a meaningful +result even if the benchmarking isn't done under the expected running +condition. Don't to this, for two reasons: + +\begin{itemize} +\item The operating systems might not compute run time in the same + way. + +\item Under the real running condition, the program might not be CPU + intensive after all. +\end{itemize} + + +In the end, only real time means anything\dash{}it is the amount of time you +have to wait for the result. The only valid uses for run time are: + +\begin{itemize} +\item To develop insight into the program. For example, if run time + is much less than elapsed time, then you are probably spending lots + of time paging. + +\item To evaluate the relative performance of CPU intensive programs + in the same environment. +\end{itemize} diff --git a/doc/cmu-user/compiler.tex b/doc/cmu-user/compiler.tex new file mode 100644 index 0000000000..2d84164dc0 --- /dev/null +++ b/doc/cmu-user/compiler.tex @@ -0,0 +1,1251 @@ +\chapter{The Compiler} + +\section{Compiler Introduction} + +This chapter contains information about the compiler that every \cmucl{} user +should be familiar with. Chapter \ref{advanced-compiler} goes into greater +depth, describing ways to use more advanced features. + +The \cmucl{} compiler (also known as \python{}, not to be confused +with the programming language of the same name) has many features +that are seldom or never supported by conventional \llisp{} +compilers: + +\begin{itemize} +\item Source level debugging of compiled code (see chapter + \ref{debugger}.) + +\item Type error compiler warnings for type errors detectable at + compile time. + +\item Compiler error messages that provide a good indication of where + the error appeared in the source. + +\item Full run-time checking of all potential type errors, with + optimization of type checks to minimize the cost. + +\item Scheme-like features such as proper tail recursion and extensive + source-level optimization. + +\item Advanced tuning and optimization features such as comprehensive + efficiency notes, flow analysis, and untagged number representations + (see chapter \ref{advanced-compiler}.) +\end{itemize} + + +\section{Calling the Compiler} +\cindex{compiling} + +Functions may be compiled using \code{compile}, \code{compile-file}, or +\code{compile-from-stream}. + +\begin{defun}{}{compile}{ \args{\var{name} \ampoptional{} \var{definition}}} + + This function compiles the function whose name is \var{name}. If + \var{name} is \false, the compiled function object is returned. If + \var{definition} is supplied, it should be a lambda expression that + is to be compiled and then placed in the function cell of + \var{name}. As per the proposed X3J13 cleanup + ``compile-argument-problems'', \var{definition} may also be an + interpreted function. + + The return values are as per the proposed X3J13 cleanup + ``compiler-diagnostics''. The first value is the function name or + function object. The second value is \false{} if no compiler + diagnostics were issued, and \true{} otherwise. The third value is + \false{} if no compiler diagnostics other than style warnings were + issued. A non-\false{} value indicates that there were ``serious'' + compiler diagnostics issued, or that other conditions of type + \tindexed{error} or \tindexed{warning} (but not + \tindexed{style-warning}) were signaled during compilation. +\end{defun} + + +\begin{defun}{}{compile-file}{ + \args{\var{input-pathname} + \keys{\kwd{output-file} \kwd{error-file} \kwd{trace-file}} + \morekeys{\kwd{error-output} \kwd{verbose} \kwd{print} \kwd{progress}} + \yetmorekeys{\kwd{load} \kwd{block-compile} \kwd{entry-points}} + \yetmorekeys{\kwd{byte-compile} \kwd{xref}}}} + + The \cmucl{} \code{compile-file} is extended through the addition of + several new keywords and an additional interpretation of + \var{input-pathname}: + \begin{Lentry} + + \item[\var{input-pathname}] If this argument is a list of input + files, rather than a single input pathname, then all the source + files are compiled into a single object file. In this case, the + name of the first file is used to determine the default output + file names. This is especially useful in combination with + \var{block-compile}. + + \item[\kwd{output-file}] This argument specifies the name of the + output file. \true{} gives the default name, \false{} suppresses + the output file. + + \item[\kwd{error-file}] A listing of all the error output is + directed to this file. If there are no errors, then no error file + is produced (and any existing error file is deleted.) \true{} + gives \w{"\var{name}\code{.err}"} (the default), and \false{} + suppresses the output file. + + \item[\kwd{error-output}] If \true{} (the default), then error + output is sent to \code{*error-output*}. If a stream, then output + is sent to that stream instead. If \false, then error output is + suppressed. Note that this error output is in addition to (but + the same as) the output placed in the \var{error-file}. + + \item[\kwd{verbose}] If \true{} (the default), then the compiler + prints to error output at the start and end of compilation of each + file. See \varref{compile-verbose}. + + \item[\kwd{print}] If \true{} (the default), then the compiler + prints to error output when each function is compiled. See + \varref{compile-print}. + + \item[\kwd{progress}] If \true{} (default \false{}), then the + compiler prints to error output progress information about the + phases of compilation of each function. This is a \cmucl{} extension + that is useful mainly in large block compilations. See + \varref{compile-progress}. + + \item[\kwd{trace-file}] If \true{}, several of the intermediate + representations (including annotated assembly code) are dumped out + to this file. \true{} gives \w{"\var{name}\code{.trace}"}. Trace + output is off by default. \xlref{trace-files}. + + \item[\kwd{load}] If \true{}, load the resulting output file. + + \item[\kwd{block-compile}] Controls the compile-time resolution of + function calls. By default, only self-recursive calls are + resolved, unless an \code{ext:block-start} declaration appears in + the source file. \xlref{compile-file-block}. + + \item[\kwd{entry-points}] If non-\nil, then this is a list of the + names of all functions in the file that should have global + definitions installed (because they are referenced in other + files.) \xlref{compile-file-block}. + + \item[\kwd{byte-compile}] If \true{}, compiling to a compact + interpreted byte code is enabled. Possible values are \true{}, + \false{}, and \kwd{maybe} (the default.) See + \varref{byte-compile-default} and \pxlref{byte-compile}. + + \item[\kwd{xref}] If non-\nil, enable recording of cross-reference + information. The default is the value of + \code{c:*record-xref-info*}. \xlref{xref}. Note that the + compiled fasl file will also contain cross-reference information + and loading the fasl later will populate the cross-reference database. + \end{Lentry} + + The return values are as per the proposed X3J13 cleanup + ``compiler-diagnostics''. The first value from \code{compile-file} + is the truename of the output file, or \false{} if the file could + not be created. The interpretation of the second and third values + is described above for \code{compile}. +\end{defun} + +\begin{defvar}{}{compile-verbose} + \defvarx{compile-print} + \defvarx{compile-progress} + + These variables determine the default values for the \kwd{verbose}, + \kwd{print} and \kwd{progress} arguments to \code{compile-file}. +\end{defvar} + +\begin{defun}{extensions:}{compile-from-stream}{% + \args{\var{input-stream} + \keys{\kwd{error-stream}} + \morekeys{\kwd{trace-stream}} + \yetmorekeys{\kwd{block-compile} \kwd{entry-points}} + \yetmorekeys{\kwd{byte-compile}}}} + + This function is similar to \code{compile-file}, but it takes all + its arguments as streams. It reads \llisp{} code from + \var{input-stream} until end of file is reached, compiling into the + current environment. This function returns the same two values as + the last two values of \code{compile}. No output files are + produced. +\end{defun} + + +\section{Compilation Units} +\cpsubindex{compilation}{units} + +\cmucl{} supports the \code{with-compilation-unit} macro added to the +language by the X3J13 ``with-compilation-unit'' compiler cleanup +issue. This provides a mechanism for eliminating spurious undefined +warnings when there are forward references across files, and also +provides a standard way to access compiler extensions. + +\begin{defmac}{}{with-compilation-unit}{% + \args{(\mstar{\var{key} \var{value}}) \mstar{\var{form}}}} + + This macro evaluates the \var{forms} in an environment that causes + warnings for undefined variables, functions and types to be delayed + until all the forms have been evaluated. Each keyword \var{value} + is an evaluated form. These keyword options are recognized: + \begin{Lentry} + + \item[\kwd{override}] If uses of \code{with-compilation-unit} are + dynamically nested, the outermost use will take precedence, + suppressing printing of undefined warnings by inner uses. + However, when the \code{override} option is true this shadowing is + inhibited; an inner use will print summary warnings for the + compilations within the inner scope. + + \item[\kwd{optimize}] This is a \cmucl{} extension that specifies of the + ``global'' compilation policy for the dynamic extent of the body. + The argument should evaluate to an \code{optimize} declare form, + like: + \begin{lisp} + (optimize (speed 3) (safety 0)) + \end{lisp} + \xlref{optimize-declaration} + + \item[\kwd{optimize-interface}] Similar to \kwd{optimize}, but + specifies the compilation policy for function interfaces (argument + count and type checking) for the dynamic extent of the body. + \xlref{optimize-interface-declaration}. + + \item[\kwd{context-declarations}] This is a \cmucl{} extension that + pattern-matches on function names, automatically splicing in any + appropriate declarations at the head of the function definition. + \xlref{context-declarations}. + \end{Lentry} +\end{defmac} + + +\subsection{Undefined Warnings} + +\cindex{undefined warnings} +Warnings about undefined variables, functions and types are delayed until the +end of the current compilation unit. The compiler entry functions +(\code{compile}, etc.) implicitly use \code{with-compilation-unit}, so undefined +warnings will be printed at the end of the compilation unless there is an +enclosing \code{with-compilation-unit}. In order the gain the benefit of this +mechanism, you should wrap a single \code{with-compilation-unit} around the calls +to \code{compile-file}, i.e.: +\begin{lisp} +(with-compilation-unit () + (compile-file "file1") + (compile-file "file2") + ...) +\end{lisp} + +Unlike for functions and types, undefined warnings for variables are +not suppressed when a definition (e.g. \code{defvar}) appears after +the reference (but in the same compilation unit.) This is because +doing special declarations out of order just doesn't +work\dash{}although early references will be compiled as special, +bindings will be done lexically. + +Undefined warnings are printed with full source context +(\pxlref{error-messages}), which tremendously simplifies the problem +of finding undefined references that resulted from macroexpansion. +After printing detailed information about the undefined uses of each +name, \code{with-compilation-unit} also prints summary listings of the +names of all the undefined functions, types and variables. + +\begin{defvar}{}{undefined-warning-limit} + + This variable controls the number of undefined warnings for each + distinct name that are printed with full source context when the + compilation unit ends. If there are more undefined references than + this, then they are condensed into a single warning: + \begin{example} + Warning: \var{count} more uses of undefined function \var{name}. + \end{example} + When the value is \code{0}, then the undefined warnings are not + broken down by name at all: only the summary listing of undefined + names is printed. +\end{defvar} + + +\section{Interpreting Error Messages} +\label{error-messages} +\cpsubindex{error messages}{compiler} +\cindex{compiler error messages} + +One of \python{}'s unique features is the level of source location +information it provides in error messages. The error messages contain +a lot of detail in a terse format, to they may be confusing at first. +Error messages will be illustrated using this example program: +\begin{lisp} +(defmacro zoq (x) + `(roq (ploq (+ ,x 3)))) + +(defun foo (y) + (declare (symbol y)) + (zoq y)) +\end{lisp} +The main problem with this program is that it is trying to add \code{3} to a +symbol. Note also that the functions \code{roq} and \code{ploq} aren't defined +anywhere. + + +\subsection{The Parts of the Error Message} + +The compiler will produce this warning: + +\begin{example} +File: /usr/me/stuff.lisp +In: DEFUN FOO + (ZOQ Y) +--> ROQ PLOQ + +==> + Y +Warning: Result is a SYMBOL, not a NUMBER. +\end{example} + +In this example we see each of the six possible parts of a compiler error +message: + +\begin{Lentry} +\item[\w{\code{File: /usr/me/stuff.lisp}}] This is the \var{file} that + the compiler read the relevant code from. The file name is + displayed because it may not be immediately obvious when there is an + error during compilation of a large system, especially when + \code{with-compilation-unit} is used to delay undefined warnings. + +\item[\w{\code{In: DEFUN FOO}}] This is the \var{definition} or + top-level form responsible for the error. It is obtained by taking + the first two elements of the enclosing form whose first element is + a symbol beginning with ``\code{DEF}''. If there is no enclosing + \w{\var{def}mumble}, then the outermost form is used. If there are + multiple \w{\var{def}mumbles}, then they are all printed from the + out in, separated by \code{$=>$}'s. In this example, the problem + was in the \code{defun} for \code{foo}. + +\item[\w{\code{(ZOQ Y)}}] This is the {\em original source} form + responsible for the error. Original source means that the form + directly appeared in the original input to the compiler, i.e. in the + lambda passed to \code{compile} or the top-level form read from the + source file. In this example, the expansion of the \code{zoq} macro + was responsible for the error. + +\item[\w{\code{--$>$ ROQ PLOQ +}} ] This is the {\em processing path} + that the compiler used to produce the errorful code. The processing + path is a representation of the evaluated forms enclosing the actual + source that the compiler encountered when processing the original + source. The path is the first element of each form, or the form + itself if the form is not a list. These forms result from the + expansion of macros or source-to-source transformation done by the + compiler. In this example, the enclosing evaluated forms are the + calls to \code{roq}, \code{ploq} and \code{+}. These calls resulted + from the expansion of the \code{zoq} macro. + +\item[\code{==$>$ Y}] This is the {\em actual source} responsible for + the error. If the actual source appears in the explanation, then we + print the next enclosing evaluated form, instead of printing the + actual source twice. (This is the form that would otherwise have + been the last form of the processing path.) In this example, the + problem is with the evaluation of the reference to the variable + \code{y}. + +\item[\w{\code{Warning: Result is a SYMBOL, not a NUMBER.}}] This is + the \var{explanation} the problem. In this example, the problem is + that \code{y} evaluates to a \code{symbol}, but is in a context + where a number is required (the argument to \code{+}). +\end{Lentry} + +Note that each part of the error message is distinctively marked: + +\begin{itemize} +\item \code{File:} and \code{In:} mark the file and definition, + respectively. + +\item The original source is an indented form with no prefix. + +\item Each line of the processing path is prefixed with \code{--$>$}. + +\item The actual source form is indented like the original source, but + is marked by a preceding \code{==$>$} line. This is like the + ``macroexpands to'' notation used in \cltl. + +\item The explanation is prefixed with the error severity + (\pxlref{error-severity}), either \code{Error:}, \code{Warning:}, or + \code{Note:}. +\end{itemize} + + +Each part of the error message is more specific than the preceding +one. If consecutive error messages are for nearby locations, then the +front part of the error messages would be the same. In this case, the +compiler omits as much of the second message as in common with the +first. For example: + +\begin{example} +File: /usr/me/stuff.lisp +In: DEFUN FOO + (ZOQ Y) +--> ROQ +==> + (PLOQ (+ Y 3)) +Warning: Undefined function: PLOQ + +==> + (ROQ (PLOQ (+ Y 3))) +Warning: Undefined function: ROQ +\end{example} + +In this example, the file, definition and original source are +identical for the two messages, so the compiler omits them in the +second message. If consecutive messages are entirely identical, then +the compiler prints only the first message, followed by: + +\begin{example} +[Last message occurs \var{repeats} times] +\end{example} + +where \var{repeats} is the number of times the message was given. + +If the source was not from a file, then no file line is printed. If +the actual source is the same as the original source, then the +processing path and actual source will be omitted. If no forms +intervene between the original source and the actual source, then the +processing path will also be omitted. + + +\subsection{The Original and Actual Source} +\cindex{original source} +\cindex{actual source} + +The {\em original source} displayed will almost always be a list. If the actual +source for an error message is a symbol, the original source will be the +immediately enclosing evaluated list form. So even if the offending symbol +does appear in the original source, the compiler will print the enclosing list +and then print the symbol as the actual source (as though the symbol were +introduced by a macro.) + +When the {\em actual source} is displayed (and is not a symbol), it will always +be code that resulted from the expansion of a macro or a source-to-source +compiler optimization. This is code that did not appear in the original +source program; it was introduced by the compiler. + +Keep in mind that when the compiler displays a source form in an error message, +it always displays the most specific (innermost) responsible form. For +example, compiling this function: + +\begin{lisp} +(defun bar (x) + (let (a) + (declare (fixnum a)) + (setq a (foo x)) + a)) +\end{lisp} + +gives this error message: + +\begin{example} +In: DEFUN BAR + (LET (A) (DECLARE (FIXNUM A)) (SETQ A (FOO X)) A) +Warning: The binding of A is not a FIXNUM: + NIL +\end{example} + +This error message is not saying ``there's a problem somewhere in this +\code{let}''\dash{}it is saying that there is a problem with the +\code{let} itself. In this example, the problem is that \code{a}'s +\false{} initial value is not a \code{fixnum}. + + +\subsection{The Processing Path} +\cindex{processing path} +\cindex{macroexpansion} +\cindex{source-to-source transformation} + +The processing path is mainly useful for debugging macros, so if you don't +write macros, you can ignore the processing path. Consider this example: + +\begin{lisp} +(defun foo (n) + (dotimes (i n *undefined*))) +\end{lisp} + +Compiling results in this error message: + +\begin{example} +In: DEFUN FOO + (DOTIMES (I N *UNDEFINED*)) +--> DO BLOCK LET TAGBODY RETURN-FROM +==> + (PROGN *UNDEFINED*) +Warning: Undefined variable: *UNDEFINED* +\end{example} + +Note that \code{do} appears in the processing path. This is because \code{dotimes} +expands into: + +\begin{lisp} +(do ((i 0 (1+ i)) (#:g1 n)) + ((>= i #:g1) *undefined*) + (declare (type unsigned-byte i))) +\end{lisp} + +The rest of the processing path results from the expansion of \code{do}: + +\begin{lisp} +(block nil + (let ((i 0) (#:g1 n)) + (declare (type unsigned-byte i)) + (tagbody (go #:g3) + #:g2 (psetq i (1+ i)) + #:g3 (unless (>= i #:g1) (go #:g2)) + (return-from nil (progn *undefined*))))) +\end{lisp} + +In this example, the compiler descended into the \code{block}, +\code{let}, \code{tagbody} and \code{return-from} to reach the +\code{progn} printed as the actual source. This is a place where the +``actual source appears in explanation'' rule was applied. The +innermost actual source form was the symbol \code{*undefined*} itself, +but that also appeared in the explanation, so the compiler backed out +one level. + + +\subsection{Error Severity} +\label{error-severity} +\cindex{severity of compiler errors} +\cindex{compiler error severity} + +There are three levels of compiler error severity: + +\begin{Lentry} +\item[Error] This severity is used when the compiler encounters a + problem serious enough to prevent normal processing of a form. + Instead of compiling the form, the compiler compiles a call to + \code{error}. Errors are used mainly for signaling syntax errors. + If an error happens during macroexpansion, the compiler will handle + it. The compiler also handles and attempts to proceed from read + errors. + +\item[Warning] Warnings are used when the compiler can prove that + something bad will happen if a portion of the program is executed, + but the compiler can proceed by compiling code that signals an error + at runtime if the problem has not been fixed: + \begin{itemize} + + \item Violation of type declarations, or + + \item Function calls that have the wrong number of arguments or + malformed keyword argument lists, or + + \item Referencing a variable declared \code{ignore}, or unrecognized + declaration specifiers. + \end{itemize} + + In the language of the \clisp{} standard, these are situations where + the compiler can determine that a situation with undefined + consequences or that would cause an error to be signaled would + result at runtime. + +\item[Note] Notes are used when there is something that seems a bit + odd, but that might reasonably appear in correct programs. +\end{Lentry} + +Note that the compiler does not fully conform to the proposed X3J13 +``compiler-diagnostics'' cleanup. Errors, warnings and notes mostly +correspond to errors, warnings and style-warnings, but many things +that the cleanup considers to be style-warnings are printed as +warnings rather than notes. Also, warnings, style-warnings and most +errors aren't really signaled using the condition system. + + +\subsection{Errors During Macroexpansion} +\cpsubindex{macroexpansion}{errors during} + +The compiler handles errors that happen during macroexpansion, turning +them into compiler errors. If you want to debug the error (to debug a +macro), you can set \code{*break-on-signals*} to \code{error}. For +example, this definition: + +\begin{lisp} +(defun foo (e l) + (do ((current l (cdr current)) + ((atom current) nil)) + (when (eq (car current) e) (return current)))) +\end{lisp} + +gives this error: + +\begin{example} +In: DEFUN FOO + (DO ((CURRENT L #) (# NIL)) (WHEN (EQ # E) (RETURN CURRENT)) ) +Error: (during macroexpansion) + +Error in function LISP::DO-DO-BODY. +DO step variable is not a symbol: (ATOM CURRENT) +\end{example} + + +\subsection{Read Errors} +\cpsubindex{read errors}{compiler} + +The compiler also handles errors while reading the source. For example: + +\begin{example} +Error: Read error at 2: + "(,/\back{foo})" +Error in function LISP::COMMA-MACRO. +Comma not inside a backquote. +\end{example} + +The ``\code{at 2}'' refers to the character position in the source file at +which the error was signaled, which is generally immediately after the +erroneous text. The next line, ``\code{(,/\back{foo})}'', is the line in +the source that contains the error file position. The ``\code{/\back{} }'' +indicates the error position within that line (in this example, +immediately after the offending comma.) + +When in \hemlock{} (or any other EMACS-like editor), you can go to a +character position with: + +\begin{example} +M-< C-u \var{position} C-f +\end{example} + +Note that if the source is from a \hemlock{} buffer, then the position +is relative to the start of the compiled region or \code{defun}, not the +file or buffer start. + +After printing a read error message, the compiler attempts to recover from the +error by backing up to the start of the enclosing top-level form and reading +again with \code{*read-suppress*} true. If the compiler can recover from the +error, then it substitutes a call to \code{cerror} for the unreadable form and +proceeds to compile the rest of the file normally. + +If there is a read error when the file position is at the end of the file +(i.e., an unexpected EOF error), then the error message looks like this: + +\begin{example} +Error: Read error in form starting at 14: + "(defun test ()" +Error in function LISP::FLUSH-WHITESPACE. +EOF while reading # +\end{example} + +In this case, ``\code{starting at 14}'' indicates the character +position at which the compiler started reading, i.e. the position +before the start of the form that was missing the closing delimiter. +The line \w{"\code{(defun test ()}"} is first line after the starting +position that the compiler thinks might contain the unmatched open +delimiter. + + +\subsection{Error Message Parameterization} +\cpsubindex{error messages}{verbosity} +\cpsubindex{verbosity}{of error messages} + +There is some control over the verbosity of error messages. See also +\varref{undefined-warning-limit}, \code{*efficiency-note-limit*} and +\varref{efficiency-note-cost-threshold}. + +\begin{defvar}{}{enclosing-source-cutoff} + + This variable specifies the number of enclosing actual source forms + that are printed in full, rather than in the abbreviated processing + path format. Increasing the value from its default of \code{1} + allows you to see more of the guts of the macroexpanded source, + which is useful when debugging macros. +\end{defvar} + +\begin{defvar}{}{error-print-length} + \defvarx{error-print-level} + + These variables are the print level and print length used in + printing error messages. The default values are \code{5} and + \code{3}. If null, the global values of \code{*print-level*} and + \code{*print-length*} are used. +\end{defvar} + +\begin{defmac}{extensions:}{def-source-context}{% + \args{\var{name} \var{lambda-list} \mstar{form}}} + + This macro defines how to extract an abbreviated source context from + the \var{name}d form when it appears in the compiler input. + \var{lambda-list} is a \code{defmacro} style lambda-list used to + parse the arguments. The \var{body} should return a list of + subforms that can be printed on about one line. There are + predefined methods for \code{defstruct}, \code{defmethod}, etc. If + no method is defined, then the first two subforms are returned. + Note that this facility implicitly determines the string name + associated with anonymous functions. +\end{defmac} + + +\section{Types in Python} +\cpsubindex{types}{in python} + +A big difference between \python{} and all other \llisp{} compilers +is the approach to type checking and amount of knowledge about types: +\begin{itemize} + +\item \python{} treats type declarations much differently that other + Lisp compilers do. \python{} doesn't blindly believe type + declarations; it considers them assertions about the program that + should be checked. + +\item \python{} also has a tremendously greater knowledge of the + \clisp{} type system than other compilers. Support is incomplete + only for the \code{not}, \code{and} and \code{satisfies} types. +\end{itemize} +See also sections \ref{advanced-type-stuff} and \ref{type-inference}. + + +\subsection{Compile Time Type Errors} +\cindex{compile time type errors} +\cpsubindex{type checking}{at compile time} + +If the compiler can prove at compile time that some portion of the +program cannot be executed without a type error, then it will give a +warning at compile time. It is possible that the offending code would +never actually be executed at run-time due to some higher level +consistency constraint unknown to the compiler, so a type warning +doesn't always indicate an incorrect program. For example, consider +this code fragment: +\begin{lisp} +(defun raz (foo) + (let ((x (case foo + (:this 13) + (:that 9) + (:the-other 42)))) + (declare (fixnum x)) + (foo x))) +\end{lisp} + +Compilation produces this warning: + +\begin{example} +In: DEFUN RAZ + (CASE FOO (:THIS 13) (:THAT 9) (:THE-OTHER 42)) +--> LET COND IF COND IF COND IF +==> + (COND) +Warning: This is not a FIXNUM: + NIL +\end{example} + +In this case, the warning is telling you that if \code{foo} isn't any +of \kwd{this}, \kwd{that} or \kwd{the-other}, then \code{x} will be +initialized to \false, which the \code{fixnum} declaration makes +illegal. The warning will go away if \code{ecase} is used instead of +\code{case}, or if \kwd{the-other} is changed to \true. + +This sort of spurious type warning happens moderately often in the +expansion of complex macros and in inline functions. In such cases, +there may be dead code that is impossible to correctly execute. The +compiler can't always prove this code is dead (could never be +executed), so it compiles the erroneous code (which will always signal +an error if it is executed) and gives a warning. + +\begin{defun}{extensions:}{required-argument}{} + + This function can be used as the default value for keyword arguments + that must always be supplied. Since it is known by the compiler to + never return, it will avoid any compile-time type warnings that + would result from a default value inconsistent with the declared + type. When this function is called, it signals an error indicating + that a required keyword argument was not supplied. This function is + also useful for \code{defstruct} slot defaults corresponding to + required arguments. \xlref{empty-type}. + + Although this function is a \cmucl{} extension, it is relatively harmless + to use it in otherwise portable code, since you can easily define it + yourself: + \begin{lisp} + (defun required-argument () + (error "A required keyword argument was not supplied.")) + \end{lisp} +\end{defun} + +Type warnings are inhibited when the +\code{extensions:inhibit-warnings} optimization quality is \code{3} +(\pxlref{compiler-policy}.) This can be used in a local declaration +to inhibit type warnings in a code fragment that has spurious +warnings. + + +\subsection{Precise Type Checking} +\label{precise-type-checks} +\cindex{precise type checking} +\cpsubindex{type checking}{precise} + +With the default compilation policy, all type +assertions\footnote{There are a few circumstances where a type + declaration is discarded rather than being used as type assertion. + This doesn't affect safety much, since such discarded declarations + are also not believed to be true by the compiler.} are precisely +checked. Precise checking means that the check is done as though +\code{typep} had been called with the exact type specifier that +appeared in the declaration. \python{} uses \var{policy} to determine +whether to trust type assertions (\pxlref{compiler-policy}). Type +assertions from declarations are indistinguishable from the type +assertions on arguments to built-in functions. In \python, adding +type declarations makes code safer. + +If a variable is declared to be \w{\code{(integer 3 17)}}, then its +value must always always be an integer between \code{3} and \code{17}. +If multiple type declarations apply to a single variable, then all the +declarations must be correct; it is as though all the types were +intersected producing a single \code{and} type specifier. + +Argument type declarations are automatically enforced. If you declare +the type of a function argument, a type check will be done when that +function is called. In a function call, the called function does the +argument type checking, which means that a more restrictive type +assertion in the calling function (e.g., from \code{the}) may be lost. + +The types of structure slots are also checked. The value of a +structure slot must always be of the type indicated in any \kwd{type} +slot option.\footnote{The initial value need not be of this type as + long as the corresponding argument to the constructor is always + supplied, but this will cause a compile-time type warning unless + \code{required-argument} is used.} Because of precise type checking, +the arguments to slot accessors are checked to be the correct type of +structure. + +In traditional \llisp{} compilers, not all type assertions are +checked, and type checks are not precise. Traditional compilers +blindly trust explicit type declarations, but may check the argument +type assertions for built-in functions. Type checking is not precise, +since the argument type checks will be for the most general type legal +for that argument. In many systems, type declarations suppress what +little type checking is being done, so adding type declarations makes +code unsafe. This is a problem since it discourages writing type +declarations during initial coding. In addition to being more error +prone, adding type declarations during tuning also loses all the +benefits of debugging with checked type assertions. + +To gain maximum benefit from \python{}'s type checking, you should +always declare the types of function arguments and structure slots as +precisely as possible. This often involves the use of \code{or}, +\code{member} and other list-style type specifiers. Paradoxically, +even though adding type declarations introduces type checks, it +usually reduces the overall amount of type checking. This is +especially true for structure slot type declarations. + +\python{} uses the \code{safety} optimization quality (rather than +presence or absence of declarations) to choose one of three levels of +run-time type error checking: \pxlref{optimize-declaration}. +\xlref{advanced-type-stuff} for more information about types in +\python{}. + + +\subsection{Weakened Type Checking} +\label{weakened-type-checks} +\cindex{weakened type checking} +\cpsubindex{type checking}{weakened} + +When the value for the \code{speed} optimization quality is greater +than \code{safety}, and \code{safety} is not \code{0}, then type +checking is weakened to reduce the speed and space penalty. In +structure-intensive code this can double the speed, yet still catch +most type errors. Weakened type checks provide a level of safety +similar to that of ``safe'' code in other \llisp{} compilers. + +A type check is weakened by changing the check to be for some +convenient supertype of the asserted type. For example, +\code{\w{(integer 3 17)}} is changed to \code{fixnum}, +\code{\w{(simple-vector 17)}} to \code{simple-vector}, and structure +types are changed to \code{structure}. A complex check like: +\begin{example} +(or node hunk (member :foo :bar :baz)) +\end{example} +will be omitted entirely (i.e., the check is weakened to \code{*}.) If +a precise check can be done for no extra cost, then no weakening is +done. + +Although weakened type checking is similar to type checking done by +other compilers, it is sometimes safer and sometimes less safe. +Weakened checks are done in the same places is precise checks, so all +the preceding discussion about where checking is done still applies. +Weakened checking is sometimes somewhat unsafe because although the +check is weakened, the precise type is still input into type +inference. In some contexts this will result in type inferences not +justified by the weakened check, and hence deletion of some type +checks that would be done by conventional compilers. + +For example, if this code was compiled with weakened checks: + +\begin{lisp} +(defstruct foo + (a nil :type simple-string)) + +(defstruct bar + (a nil :type single-float)) + +(defun myfun (x) + (declare (type bar x)) + (* (bar-a x) 3.0)) +\end{lisp} + +and \code{myfun} was passed a \code{foo}, then no type error would be +signaled, and we would try to multiply a \code{simple-vector} as +though it were a float (with unpredictable results.) This is because +the check for \code{bar} was weakened to \code{structure}, yet when +compiling the call to \code{bar-a}, the compiler thinks it knows it +has a \code{bar}. + +Note that normally even weakened type checks report the precise type +in error messages. For example, if \code{myfun}'s \code{bar} check is +weakened to \code{structure}, and the argument is \false{}, then the +error will be: + +\begin{example} +Type-error in MYFUN: + NIL is not of type BAR +\end{example} + +However, there is some speed and space cost for signaling a precise +error, so the weakened type is reported if the \code{speed} +optimization quality is \code{3} or \code{debug} quality is less than +\code{1}: + +\begin{example} +Type-error in MYFUN: + NIL is not of type STRUCTURE +\end{example} + +\xlref{optimize-declaration} for further discussion of the +\code{optimize} declaration. + + +\section{Getting Existing Programs to Run} +\cpsubindex{existing programs}{to run} +\cpsubindex{types}{portability} +\cindex{compatibility with other Lisps} + +Since \python{} does much more comprehensive type checking than other +Lisp compilers, \python{} will detect type errors in many programs +that have been debugged using other compilers. These errors are +mostly incorrect declarations, although compile-time type errors can +find actual bugs if parts of the program have never been tested. + +Some incorrect declarations can only be detected by run-time type +checking. It is very important to initially compile programs with +full type checks and then test this version. After the checking +version has been tested, then you can consider weakening or +eliminating type checks. {\bf This applies even to previously debugged + programs.} \python{} does much more type inference than other +\llisp{} compilers, so believing an incorrect declaration does much +more damage. + +The most common problem is with variables whose initial value doesn't +match the type declaration. Incorrect initial values will always be +flagged by a compile-time type error, and they are simple to fix once +located. Consider this code fragment: + +\begin{example} +(prog (foo) + (declare (fixnum foo)) + (setq foo ...) + ...) +\end{example} + +Here the variable \code{foo} is given an initial value of \false, but +is declared to be a \code{fixnum}. Even if it is never read, the +initial value of a variable must match the declared type. There are +two ways to fix this problem. Change the declaration: + +\begin{example} +(prog (foo) + (declare (type (or fixnum null) foo)) + (setq foo ...) + ...) +\end{example} + +or change the initial value: + +\begin{example} +(prog ((foo 0)) + (declare (fixnum foo)) + (setq foo ...) + ...) +\end{example} + +It is generally preferable to change to a legal initial value rather +than to weaken the declaration, but sometimes it is simpler to weaken +the declaration than to try to make an initial value of the +appropriate type. + +Another declaration problem occasionally encountered is incorrect +declarations on \code{defmacro} arguments. This probably usually +happens when a function is converted into a macro. Consider this +macro: + +\begin{lisp} +(defmacro my-1+ (x) + (declare (fixnum x)) + `(the fixnum (1+ ,x))) +\end{lisp} + +Although legal and well-defined \clisp, this meaning of this +definition is almost certainly not what the writer intended. For +example, this call is illegal: + +\begin{lisp} +(my-1+ (+ 4 5)) +\end{lisp} + +The call is illegal because the argument to the macro is \w{\code{(+ 4 + 5)}}, which is a \code{list}, not a \code{fixnum}. Because of +macro semantics, it is hardly ever useful to declare the types of +macro arguments. If you really want to assert something about the +type of the result of evaluating a macro argument, then put a +\code{the} in the expansion: + +\begin{lisp} +(defmacro my-1+ (x) + `(the fixnum (1+ (the fixnum ,x)))) +\end{lisp} + +In this case, it would be stylistically preferable to change this +macro back to a function and declare it inline. Macros have no +efficiency advantage over inline functions when using \python{}. +\xlref{inline-expansion}. + + +Some more subtle problems are caused by incorrect declarations that +can't be detected at compile time. Consider this code: + +\begin{example} +(do ((pos 0 (position #\back{a} string :start (1+ pos)))) + ((null pos)) + (declare (fixnum pos)) + ...) +\end{example} + +Although \code{pos} is almost always a \code{fixnum}, it is \false{} +at the end of the loop. If this example is compiled with full type +checks (the default), then running it will signal a type error at the +end of the loop. If compiled without type checks, the program will go +into an infinite loop (or perhaps \code{position} will complain +because \w{\code{(1+ nil)}} isn't a sensible start.) Why? Because if +you compile without type checks, the compiler just quietly believes +the type declaration. Since \code{pos} is always a \code{fixnum}, it +is never \nil, so \w{\code{(null pos)}} is never true, and the loop +exit test is optimized away. Such errors are sometimes flagged by +unreachable code notes (\pxlref{dead-code-notes}), but it is still +important to initially compile any system with full type checks, even +if the system works fine when compiled using other compilers. + +In this case, the fix is to weaken the type declaration to +\w{\code{(or fixnum null)}}.\footnote{Actually, this declaration is + totally unnecessary in \python{}, since it already knows + \code{position} returns a non-negative \code{fixnum} or \false.} +Note that there is usually little performance penalty for weakening a +declaration in this way. Any numeric operations in the body can still +assume the variable is a \code{fixnum}, since \false{} is not a legal +numeric argument. Another possible fix would be to say: + +\begin{example} +(do ((pos 0 (position #\back{a} string :start (1+ pos)))) + ((null pos)) + (let ((pos pos)) + (declare (fixnum pos)) + ...)) +\end{example} + +This would be preferable in some circumstances, since it would allow a +non-standard representation to be used for the local \code{pos} +variable in the loop body (see section \ref{ND-variables}.) + +In summary, remember that {\em all} values that a variable {\em ever} +has must be of the declared type, and that you should test using safe +code initially. + + +\section{Compiler Policy} +\label{compiler-policy} +\cpsubindex{policy}{compiler} +\cindex{compiler policy} + +The policy is what tells the compiler \var{how} to compile a program. +This is logically (and often textually) distinct from the program +itself. Broad control of policy is provided by the \code{optimize} +declaration; other declarations and variables control more specific +aspects of compilation. + + +\subsection{The Optimize Declaration} +\label{optimize-declaration} +\cindex{optimize declaration} +\cpsubindex{declarations}{\code{optimize}} + +The \code{optimize} declaration recognizes six different +\var{qualities}. The qualities are conceptually independent aspects +of program performance. In reality, increasing one quality tends to +have adverse effects on other qualities. The compiler compares the +relative values of qualities when it needs to make a trade-off; i.e., +if \code{speed} is greater than \code{safety}, then improve speed at +the cost of safety. + +The default for all qualities (except \code{debug}) is \code{1}. +Whenever qualities are equal, ties are broken according to a broad +idea of what a good default environment is supposed to be. Generally +this downplays \code{speed}, \code{compile-speed} and \code{space} in +favor of \code{safety} and \code{debug}. Novice and casual users +should stick to the default policy. Advanced users often want to +improve speed and memory usage at the cost of safety and +debuggability. + +If the value for a quality is \code{0} or \code{3}, then it may have a +special interpretation. A value of \code{0} means ``totally +unimportant'', and a \code{3} means ``ultimately important.'' These +extreme optimization values enable ``heroic'' compilation strategies +that are not always desirable and sometimes self-defeating. +Specifying more than one quality as \code{3} is not desirable, since +it doesn't tell the compiler which quality is most important. + + +These are the optimization qualities: +\begin{Lentry} + +\item[\code{speed}] \cindex{speed optimization quality}How fast the + program should is run. \code{speed 3} enables some optimizations + that hurt debuggability. + +\item[\code{compilation-speed}] \cindex{compilation-speed optimization + quality}How fast the compiler should run. Note that increasing + this above \code{safety} weakens type checking. + +\item[\code{space}] \cindex{space optimization quality}How much space + the compiled code should take up. Inline expansion is mostly + inhibited when \code{space} is greater than \code{speed}. A value + of \code{0} enables promiscuous inline expansion. Wide use of a + \code{0} value is not recommended, as it may waste so much space + that run time is slowed. \xlref{inline-expansion} for a discussion + of inline expansion. + +\item[\code{debug}] \cindex{debug optimization quality}How debuggable + the program should be. The quality is treated differently from the + other qualities: each value indicates a particular level of debugger + information; it is not compared with the other qualities. + \xlref{debugger-policy} for more details. + +\item[\code{safety}] \cindex{safety optimization quality}How much + error checking should be done. If \code{speed}, \code{space} or + \code{compilation-speed} is more important than \code{safety}, then + type checking is weakened (\pxlref{weakened-type-checks}). If + \code{safety} if \code{0}, then no run time error checking is done. + In addition to suppressing type checks, \code{0} also suppresses + argument count checking, unbound-symbol checking and array bounds + checks. + +\item[\code{extensions:inhibit-warnings}] \cindex{inhibit-warnings + optimization quality}This is a \cmucl{} extension that determines how + little (or how much) diagnostic output should be printed during + compilation. This quality is compared to other qualities to + determine whether to print style notes and warnings concerning those + qualities. If \code{speed} is greater than \code{inhibit-warnings}, + then notes about how to improve speed will be printed, etc. The + default value is \code{1}, so raising the value for any standard + quality above its default enables notes for that quality. If + \code{inhibit-warnings} is \code{3}, then all notes and most + non-serious warnings are inhibited. This is useful with + \code{declare} to suppress warnings about unavoidable problems. +\end{Lentry} + + +\subsection{The Optimize-Interface Declaration} +\label{optimize-interface-declaration} +\cindex{optimize-interface declaration} +\cpsubindex{declarations}{\code{optimize-interface}} + +The \code{extensions:optimize-interface} declaration is identical in +syntax to the \code{optimize} declaration, but it specifies the policy +used during compilation of code the compiler automatically generates +to check the number and type of arguments supplied to a function. It +is useful to specify this policy separately, since even thoroughly +debugged functions are vulnerable to being passed the wrong arguments. +The \code{optimize-interface} declaration can specify that arguments +should be checked even when the general \code{optimize} policy is +unsafe. + +Note that this argument checking is the checking of user-supplied +arguments to any functions defined within the scope of the +declaration, \code{not} the checking of arguments to \llisp{} +primitives that appear in those definitions. + +The idea behind this declaration is that it allows the definition of +functions that appear fully safe to other callers, but that do no +internal error checking. Of course, it is possible that arguments may +be invalid in ways other than having incorrect type. Functions +compiled unsafely must still protect themselves against things like +user-supplied array indices that are out of bounds and improper lists. +See also the \kwd{context-declarations} option to +\macref{with-compilation-unit}. + + +\section{Open Coding and Inline Expansion} +\label{open-coding} +\cindex{open-coding} +\cindex{inline expansion} +\cindex{static functions} + +Since \clisp{} forbids the redefinition of standard functions\footnote{See the +proposed X3J13 ``lisp-symbol-redefinition'' cleanup.}, the compiler can have +special knowledge of these standard functions embedded in it. This special +knowledge is used in various ways (open coding, inline expansion, source +transformation), but the implications to the user are basically the same: +\begin{itemize} + +\item Attempts to redefine standard functions may be frustrated, since + the function may never be called. Although it is technically + illegal to redefine standard functions, users sometimes want to + implicitly redefine these functions when they are debugging using + the \code{trace} macro. Special-casing of standard functions can be + inhibited using the \code{notinline} declaration. + +\item The compiler can have multiple alternate implementations of + standard functions that implement different trade-offs of speed, + space and safety. This selection is based on the compiler policy, + \pxlref{compiler-policy}. +\end{itemize} + + +When a function call is {\em open coded}, inline code whose effect is +equivalent to the function call is substituted for that function call. +When a function call is {\em closed coded}, it is usually left as is, +although it might be turned into a call to a different function with +different arguments. As an example, if \code{nthcdr} were to be open +coded, then + +\begin{lisp} +(nthcdr 4 foobar) +\end{lisp} + +might turn into + +\begin{lisp} +(cdr (cdr (cdr (cdr foobar)))) +\end{lisp} + +or even + +\begin{lisp} +(do ((i 0 (1+ i)) + (list foobar (cdr foobar))) + ((= i 4) list)) +\end{lisp} + +If \code{nth} is closed coded, then + +\begin{lisp} +(nth x l) +\end{lisp} + +might stay the same, or turn into something like: + +\begin{lisp} +(car (nthcdr x l)) +\end{lisp} + +In general, open coding sacrifices space for speed, but some functions (such as +\code{car}) are so simple that they are always open-coded. Even when not +open-coded, a call to a standard function may be transformed into a +different function call (as in the last example) or compiled as {\em +static call}. Static function call uses a more efficient calling +convention that forbids redefinition. diff --git a/doc/cmu-user/contents_motif.gif b/doc/cmu-user/contents_motif.gif new file mode 100644 index 0000000000..5d3d016702 Binary files /dev/null and b/doc/cmu-user/contents_motif.gif differ diff --git a/doc/cmu-user/cross-referencing.tex b/doc/cmu-user/cross-referencing.tex new file mode 100644 index 0000000000..e72023798e --- /dev/null +++ b/doc/cmu-user/cross-referencing.tex @@ -0,0 +1,297 @@ +\chapter{Cross-Referencing Facility} +\label{xref} +\cindex{cross-referencing} +\credits{by Eric Marsden} + +The \cmucl{} cross-referencing facility (abbreviated XREF) assists in +the analysis of static dependency relationships in a program. It +provides introspection capabilities such as the ability to know which +functions may call a given function, and the program contexts in which +a particular global variable is used. The compiler populates a +database of cross-reference information, which can be queried by the +user to know: + +\begin{itemize} +\item +the list of program contexts (functions, macros, top-level forms) +where a given function may be called at runtime, either directly or +indirectly (via its function-object); + +\item +the list of program contexts where a given global variable may be +read; + +\item +the list of program contexts that bind a global variable; + +\item +the list of program contexts where a given global variable may be +modified during the execution of the program. +\end{itemize} + +A global variable is either a dynamic variable or a constant variable, +for instance declared using \code{defvar} or \code{defparameter} or +\code{defconstant}. + + +\section{Populating the cross-reference database} + +\begin{defvar}{c:}{record-xref-info} + When non-NIL, code that is compiled (either using + \code{compile-file}, or by calling \code{compile} from the + listener), will be analyzed for cross-references. Defaults to + \nil{}. +\end{defvar} + +Cross-referencing information is only generated by the compiler; the +interpreter does not populate the cross-reference database. XREF +analysis is independent of whether the compiler is generating native +code or byte code, and of whether it is compiling from a file, from a +stream, or is invoked interactively from the listener. + +Alternatively, the \kwd{:xref} option to \code{compile-file} may be +specified to populate the cross-reference database when compiling a +file. In this case, loading the generated fasl file in a fresh lisp +will also populate the cross-reference database. + +\begin{defun}{xref:}{init-xref-database}{} + Reinitializes the database of cross-references. This can be used to + reclaim the space occupied by the database contents, or to discard + stale cross-reference information. +\end{defun} + + + +\section{Querying the cross-reference database} + +\cmucl{} provides a number of functions in the XREF package that may +be used to query the cross-reference database: + +\begin{defun}{xref:}{who-calls}{\args \var{function}} + Returns the list of xref-contexts where \var{function} (either a + symbol that names a function, or a function object) may be called + at runtime. XREF does not record calls to macro-functions (such as + \code{defun}) or to special forms (such as \code{eval-when}). +\end{defun} + +\begin{defun}{xref:}{who-references}{\args \var{global-variable}} + Returns the list of program contexts that may reference + \var{global-variable}. +\end{defun} + +\begin{defun}{xref:}{who-binds}{\args \var{global-variable}} + Returns a list of program contexts where the specified global + variable may be bound at runtime (for example using \code{LET}). +\end{defun} + +\begin{defun}{xref:}{who-sets}{\args \var{global-variable}} + Returns a list of program contexts where the given global variable + may be modified at runtime (for example using \code{SETQ}). +\end{defun} + +An \textit{xref-context} is the originating site of a cross-reference. +It identifies a portion of a program, and is defined by an +\code{xref-context} structure, that comprises a name, a source file and a +source-path. + +\begin{defun}{xref:}{xref-context-name}{\args \var{context}} + Returns the name slot of an xref-context, which is one of: +\begin{itemize} +\item +a global function, which is named by a symbol or by a list of the form +\code{(setf\ foo)}. + +\item +a macro, named by a list \verb|(:macro foo)|. + +\item +an inner function (\code{flet}, \code{labels}, or anonymous lambdas) that +is named by a list of the form \code{(:internal outer inner)}. + +\item +a method, named by a list of the form +\verb|(:method foo (specializer1 specializer2)|. + +\item +a string \verb|"Top-Level Form"| that identifies a reference from a +top-level form. Note that multiple references from top-level forms +will only be listed once. + +\item +a compiler-macro, named by a string of the form +\verb|(:compiler-macro foo)|. + +\item +a string such as \verb|"DEFSTRUCT FOO"|, identifying a reference from +within a structure accessor or constructor or copier. + +\item +a string such as +\begin{verbatim} + "Creation Form for #" +\end{verbatim} + +\item +a string such as \verb|"defun foo"|, or \verb|"defmethod bar (t)"|, +that identifies a reference from within code that has been generated +by the compiler for that form. For example, the compilation of a +\code{defclass} form causes accessor functions to be generated by the +compiler; this code is compiler-generated (it does not appear in the +source file), and so is identified by the XREF facility by a string. +\end{itemize} +\end{defun} + + +\begin{defun}{xref:}{xref-context-file}{\var{context}} + Return the truename (in the sense of the variable + \vindexed{compile-file-truename}) of the source file from which the + referencing forms were compiled. This slot will be \nil{} if the + code was compiled from a stream, or interactively from the + listener. +\end{defun} + +\begin{defun}{xref:}{xref-context-source-path}{\var{context}} + Return a list of positive integers identifying the form that + contains the cross-reference. The first integer in the source-path + is the number of the top-level form containing the cross-reference + (for example, 2 identifies the second top-level form in the source + file). The second integer in the source-path identifies the form + within this top-level form that contains the cross-reference, and so + on. This function will always return \nil{} if the file slot of an + xref-context is \nil{}. + +% While walking the top-level form, count one in depth-first order for +% each subform that is a cons. +\end{defun} + + + + +\section{Example usage} + +In this section, we will illustrate use of the XREF facility on a +number of simple examples. + +Consider the following program fragment, that defines a global +variable and a function. + +\begin{verbatim} + (defvar *variable-one* 42) + + (defun function-one (x) + (princ (* x *variable-one*))) +\end{verbatim} + +We save this code in a file named \code{example.lisp}, enable +cross-referencing, clear any previous cross-reference information, +compile the file, and can then query the cross-reference database +(output has been modified for readability). + +\begin{verbatim} + USER> (setf c:*record-xref-info* t) + USER> (xref:init-xref-database) + USER> (compile-file "example") + USER> (xref:who-calls 'princ) + (#) + USER> (xref:who-references '*variable-one*) + (#) +\end{verbatim} + +From this example, we see that the compiler has noted the call to the +global function \code{princ} in \code{function-one}, and the reference +to the global variable \code{*variable-one*}. + +Suppose that we add the following code to the previous file. + +\begin{verbatim} +(defconstant +constant-one+ 1) + +(defstruct struct-one + slot-one + (slot-two +constant-one+ :type integer) + (slot-three 42 :read-only t)) + +(defmacro with-different-one (&body body) + `(let ((*variable-one* 666)) + ,@body)) + +(defun get-variable-one () *variable-one*) + +(defun (setf get-variable-one) (new-value) + (setq *variable-one* new-value)) +\end{verbatim} + +In the following example, we detect references x and y. + + +% FIXME add function with LABELS, a binding, a set + + + +The following function illustrates the effect that various forms of +optimization carried out by the \cmucl{} compiler can have on the +cross-references that are reported for a particular program. The +compiler is able to detect that the evaluated condition is always +false, and that the first clause of the \code{if} will never be taken +(this optimization is called dead-code elimination). XREF will +therefore not register a call to the function \code{sin} from the +function \code{foo}. Likewise, no calls to the functions \code{sqrt} +and \code{\textless} are registered, because the compiler has eliminated the +code that evaluates the condition. Finally, no call to the function +\code{expt} is generated, because the compiler was able to evaluate +the result of the expression \code{(expt 3 2)} at compile-time (though +a process called constant-folding). + +\begin{verbatim} +;; zero call references are registered for this function! +(defun constantly-nine (x) + (if (< (sqrt x) 0) + (sin x) + (expt 3 2))) +\end{verbatim} + + +\section{Limitations of the cross-referencing facility} + +No cross-reference information is available for interpreted functions. +The cross-referencing database is not persistent: unless you save an +image using \code{save-lisp}, the database will be empty each time +\cmucl{} is restarted. There is no mechanism that saves +cross-reference information in FASL files, so loading a system from +compiled code will not populate the cross-reference database. The XREF +database currently accumulates ``stale'' information: when compiling a +file, it does not delete any cross-references that may have previously +been generated for that file. This latter limitation will be removed +in a future release. + +The cross-referencing facility is only able to analyze the static +dependencies in a program; it does not provide any information about +runtime (dynamic) dependencies. For instance, XREF is able to identify +the list of program contexts where a given function may be called, but +is not able to determine which contexts will be activated when the +program is executed with a specific set of input parameters. However, +the static analysis that is performed by the \cmucl{} compiler does +allow XREF to provide more information than would be available from a +mere syntactic analysis of a program. References that occur from +within unreachable code will not be displayed by XREF, because the +\cmucl{} compiler deletes dead code before cross-references are +analyzed. Certain ``trivial'' function calls (where the result of the +function call can be evaluated at compile-time) may be eliminated by +optimizations carried out by the compiler; see the example below. + +If you examine the entire database of cross-reference information (by +accessing undocumented internals of the XREF package), you will note +that XREF notes ``bogus'' cross-references to function calls that are +inserted by the compiler. For example, in safe code, the \cmucl{} +compiler inserts a call to an internal function called +\code{c::\%verify-argument-count}, so that the number of arguments +passed to the function is checked each time it is called. The XREF +facility does not distinguish between user code and these forms that +are introduced during compilation. This limitation should not be +visible if you use the documented functions in the XREF package. + +As of the 18e release of \cmucl{}, the cross-referencing facility is +experimental; expect details of its implementation to change in future +releases. In particular, the names given to CLOS methods and to inner +functions will change in future releases. + diff --git a/doc/cmu-user/debug-internals.tex b/doc/cmu-user/debug-internals.tex new file mode 100644 index 0000000000..8d21902d34 --- /dev/null +++ b/doc/cmu-user/debug-internals.tex @@ -0,0 +1,765 @@ +\chapter{Debugger Programmer's Interface} +\label{debug-internals} + +The debugger programmers interface is exported from from the +\code{DEBUG-INTERNALS} or \code{DI} package. This is a CMU +extension that allows debugging tools to be written without detailed +knowledge of the compiler or run-time system. + +Some of the interface routines take a code-location as an argument. As +described in the section on code-locations, some code-locations are +unknown. When a function calls for a \var{basic-code-location}, it +takes either type, but when it specifically names the argument +\var{code-location}, the routine will signal an error if you give it an +unknown code-location. + + +\section{DI Exceptional Conditions} + +Some of these operations fail depending on the availability debugging +information. In the most severe case, when someone saved a Lisp image +stripping all debugging data structures, no operations are valid. In +this case, even backtracing and finding frames is impossible. Some +interfaces can simply return values indicating the lack of information, +or their return values are naturally meaningful in light missing data. +Other routines, as documented below, will signal +\code{serious-condition}s when they discover awkward situations. This +interface does not provide for programs to detect these situations other +than by calling a routine that detects them and signals a condition. +These are serious-conditions because the program using the interface +must handle them before it can correctly continue execution. These +debugging conditions are not errors since it is no fault of the +programmers that the conditions occur. + +\subsection{Debug-conditions} + +The debug internals interface signals conditions when it can't adhere +to its contract. These are serious-conditions because the program +using the interface must handle them before it can correctly continue +execution. These debugging conditions are not errors since it is no +fault of the programmers that the conditions occur. The interface +does not provide for programs to detect these situations other than +calling a routine that detects them and signals a condition. + + +\begin{deftp}{Condition}{debug-condition}{} + +This condition inherits from serious-condition, and all debug-conditions +inherit from this. These must be handled, but they are not programmer errors. +\end{deftp} + + +\begin{deftp}{Condition}{no-debug-info}{} + +This condition indicates there is absolutely no debugging information +available. +\end{deftp} + + +\begin{deftp}{Condition}{no-debug-function-returns}{} + +This condition indicates the system cannot return values from a frame since +its debug-function lacks debug information details about returning values. +\end{deftp} + + +\begin{deftp}{Condition}{no-debug-blocks}{} +This condition indicates that a function was not compiled with debug-block +information, but this information is necessary necessary for some requested +operation. +\end{deftp} + +\begin{deftp}{Condition}{no-debug-variables}{} +Similar to \code{no-debug-blocks}, except that variable information was +requested. +\end{deftp} + +\begin{deftp}{Condition}{lambda-list-unavailable}{} +Similar to \code{no-debug-blocks}, except that lambda list information was +requested. +\end{deftp} + +\begin{deftp}{Condition}{invalid-value}{} + +This condition indicates a debug-variable has \kwd{invalid} or \kwd{unknown} +value in a particular frame. +\end{deftp} + + +\begin{deftp}{Condition}{ambiguous-variable-name}{} + +This condition indicates a user supplied debug-variable name identifies more +than one valid variable in a particular frame. +\end{deftp} + + +\subsection{Debug-errors} + +These are programmer errors resulting from misuse of the debugging tools' +programmers' interface. You could have avoided an occurrence of one of these +by using some routine to check the use of the routine generating the error. + + +\begin{deftp}{Condition}{debug-error}{} +This condition inherits from error, and all user programming errors inherit +from this condition. +\end{deftp} + + +\begin{deftp}{Condition}{unhandled-condition}{} +This error results from a signalled \code{debug-condition} occurring +without anyone handling it. +\end{deftp} + + +\begin{deftp}{Condition}{unknown-code-location}{} +This error indicates the invalid use of an unknown-code-location. +\end{deftp} + + +\begin{deftp}{Condition}{unknown-debug-variable}{} + +This error indicates an attempt to use a debug-variable in conjunction with an +inappropriate debug-function; for example, checking the variable's validity +using a code-location in the wrong debug-function will signal this error. +\end{deftp} + + +\begin{deftp}{Condition}{frame-function-mismatch}{} + +This error indicates you called a function returned by +\code{preprocess-for-eval} +on a frame other than the one for which the function had been prepared. +\end{deftp} + + +\section{Debug-variables} + +Debug-variables represent the constant information about where the system +stores argument and local variable values. The system uniquely identifies with +an integer every instance of a variable with a particular name and package. To +access a value, you must supply the frame along with the debug-variable since +these are particular to a function, not every instance of a variable on the +stack. + +\begin{defun}{}{debug-variable-name}{\args{\var{debug-variable}}} + + This function returns the name of the \var{debug-variable}. The + name is the name of the symbol used as an identifier when writing + the code. +\end{defun} + + +\begin{defun}{}{debug-variable-package}{\args{\var{debug-variable}}} + + This function returns the package name of the \var{debug-variable}. + This is the package name of the symbol used as an identifier when + writing the code. +\end{defun} + + +\begin{defun}{}{debug-variable-symbol}{\args{\var{debug-variable}}} + + This function returns the symbol from interning + \code{debug-variable-name} in the package named by + \code{debug-variable-package}. +\end{defun} + + +\begin{defun}{}{debug-variable-id}{\args{\var{debug-variable}}} + + This function returns the integer that makes \var{debug-variable}'s + name and package name unique with respect to other + \var{debug-variable}'s in the same function. +\end{defun} + + +\begin{defun}{}{debug-variable-validity}{% + \args{\var{debug-variable} \var{basic-code-location}}} + + This function returns three values reflecting the validity of + \var{debug-variable}'s value at \var{basic-code-location}: + \begin{Lentry} + \item[\kwd{valid}] The value is known to be available. + \item[\kwd{invalid}] The value is known to be unavailable. + \item[\kwd{unknown}] The value's availability is unknown. + \end{Lentry} +\end{defun} + + +\begin{defun}{}{debug-variable-value}{\args{\var{debug-variable} + \var{frame}}} + + This function returns the value stored for \var{debug-variable} in + \var{frame}. The value may be invalid. This is \code{SETF}'able. +\end{defun} + + +\begin{defun}{}{debug-variable-valid-value}{% + \args{\var{debug-variable} \var{frame}}} + + This function returns the value stored for \var{debug-variable} in + \var{frame}. If the value is not \kwd{valid}, then this signals an + \code{invalid-value} error. +\end{defun} + + +\section{Frames} + +Frames describe a particular call on the stack for a particular thread. This +is the environment for name resolution, getting arguments and locals, and +returning values. The stack conceptually grows up, so the top of the stack is +the most recently called function. + +\code{top-frame}, \code{frame-down}, \code{frame-up}, and +\code{frame-debug-function} can only fail when there is absolutely no +debug information available. This can only happen when someone saved a +Lisp image specifying that the system dump all debugging data. + + +\begin{defun}{}{top-frame}{} + + This function never returns the frame for itself, always the frame + before calling \code{top-frame}. +\end{defun} + + +\begin{defun}{}{frame-down}{\args{\var{frame}}} + + This returns the frame immediately below \var{frame} on the stack. + When \var{frame} is the bottom of the stack, this returns \nil. +\end{defun} + + +\begin{defun}{}{frame-up}{\args{\var{frame}}} + + This returns the frame immediately above \var{frame} on the stack. + When \var{frame} is the top of the stack, this returns \nil. +\end{defun} + + +\begin{defun}{}{frame-debug-function}{\args{\var{frame}}} + + This function returns the debug-function for the function whose call + \var{frame} represents. +\end{defun} + + +\begin{defun}{}{frame-code-location}{\args{\var{frame}}} + + This function returns the code-location where \var{frame}'s + debug-function will continue running when program execution returns + to \var{frame}. If someone interrupted this frame, the result could + be an unknown code-location. +\end{defun} + + +\begin{defun}{}{frame-catches}{\args{\var{frame}}} + + This function returns an a-list for all active catches in + \var{frame} mapping catch tags to the code-locations at which the + catch re-enters. +\end{defun} + + +\begin{defun}{}{eval-in-frame}{\args{\var{frame} \var{form}}} + + This evaluates \var{form} in \var{frame}'s environment. This can + signal several different debug-conditions since its success relies + on a variety of inexact debug information: \code{invalid-value}, + \code{ambiguous-variable-name}, \code{frame-function-mismatch}. See + also \funref{preprocess-for-eval}. +\end{defun} + +% \begin{defun}{}{return-from-frame}{\args{\var{frame} \var{values}}} +% +% This returns the elements in the list \var{values} as multiple +% values from \var{frame} as if the function \var{frame} represents +% returned these values. This signals a +% \code{no-debug-function-returns} condition when \var{frame}'s +% debug-function lacks information on returning values. +% +% \i{Not Yet Implemented} +% \end{defun} + + +\section {Debug-functions} + +Debug-functions represent the static information about a function determined at +compile time---argument and variable storage, their lifetime information, +etc. The debug-function also contains all the debug-blocks representing +basic-blocks of code, and these contains information about specific +code-locations in a debug-function. + +\begin{defmac}{}{do-debug-function-blocks}{% + \args{(\var{block-var} \var{debug-function} \mopt{result-form}) + \mstar{form}}} + + This executes the forms in a context with \var{block-var} bound to + each debug-block in \var{debug-function} successively. + \var{Result-form} is an optional form to execute for a return value, + and \code{do-debug-function-blocks} returns \nil if there is no + \var{result-form}. This signals a \code{no-debug-blocks} condition + when the \var{debug-function} lacks debug-block information. +\end{defmac} + + +\begin{defun}{}{debug-function-lambda-list}{\args{\var{debug-function}}} + + This function returns a list representing the lambda-list for + \var{debug-function}. The list has the following structure: + \begin{example} + (required-var1 required-var2 + ... + (:optional var3 suppliedp-var4) + (:optional var5) + ... + (:rest var6) (:rest var7) + ... + (:keyword keyword-symbol var8 suppliedp-var9) + (:keyword keyword-symbol var10) + ... + ) + \end{example} + Each \code{var}\var{n} is a debug-variable; however, the symbol + \kwd{deleted} appears instead whenever the argument remains + unreferenced throughout \var{debug-function}. + + If there is no lambda-list information, this signals a + \code{lambda-list-unavailable} condition. +\end{defun} + + +\begin{defmac}{}{do-debug-function-variables}{% + \args{(\var{var} \var{debug-function} \mopt{result}) + \mstar{form}}} + + This macro executes each \var{form} in a context with \var{var} + bound to each debug-variable in \var{debug-function}. This returns + the value of executing \var{result} (defaults to \nil). This may + iterate over only some of \var{debug-function}'s variables or none + depending on debug policy; for example, possibly the compilation + only preserved argument information. +\end{defmac} + + +\begin{defun}{}{debug-variable-info-available}{\args{\var{debug-function}}} + + This function returns whether there is any variable information for + \var{debug-function}. This is useful for distinguishing whether + there were no locals in a function or whether there was no variable + information. For example, if \code{do-debug-function-variables} + executes its forms zero times, then you can use this function to + determine the reason. +\end{defun} + + +\begin{defun}{}{debug-function-symbol-variables}{% + \args{\var{debug-function} \var{symbol}}} + + This function returns a list of debug-variables in + \var{debug-function} having the same name and package as + \var{symbol}. If \var{symbol} is uninterned, then this returns a + list of debug-variables without package names and with the same name + as \var{symbol}. The result of this function is limited to the + availability of variable information in \var{debug-function}; for + example, possibly \var{debug-function} only knows about its + arguments. +\end{defun} + + +\begin{defun}{}{ambiguous-debug-variables}{% + \args{\var{debug-function} \var{name-prefix-string}}} + + This function returns a list of debug-variables in + \var{debug-function} whose names contain \var{name-prefix-string} as + an initial substring. The result of this function is limited to the + availability of variable information in \var{debug-function}; for + example, possibly \var{debug-function} only knows about its + arguments. +\end{defun} + + +\begin{defun}{}{preprocess-for-eval}{% + \args{\var{form} \var{basic-code-location}}} + + This function returns a function of one argument that evaluates + \var{form} in the lexical context of \var{basic-code-location}. + This allows efficient repeated evaluation of \var{form} at a certain + place in a function which could be useful for conditional breaking. + This signals a \code{no-debug-variables} condition when the + code-location's debug-function has no debug-variable information + available. The returned function takes a frame as an argument. See + also \funref{eval-in-frame}. +\end{defun} + + +\begin{defun}{}{function-debug-function}{\args{\var{function}}} + + This function returns a debug-function that represents debug + information for \var{function}. +\end{defun} + + +\begin{defun}{}{debug-function-kind}{\args{\var{debug-function}}} + + This function returns the kind of function \var{debug-function} + represents. The value is one of the following: + \begin{Lentry} + \item[\kwd{optional}] This kind of function is an entry point to an + ordinary function. It handles optional defaulting, parsing + keywords, etc. + \item[\kwd{external}] This kind of function is an entry point to an + ordinary function. It checks argument values and count and calls + the defined function. + \item[\kwd{top-level}] This kind of function executes one or more + random top-level forms from a file. + \item[\kwd{cleanup}] This kind of function represents the cleanup + forms in an \code{unwind-protect}. + \item[\nil] This kind of function is not one of the above; that is, + it is not specially marked in any way. + \end{Lentry} +\end{defun} + + +\begin{defun}{}{debug-function-function}{\args{\var{debug-function}}} + + This function returns the Common Lisp function associated with the + \var{debug-function}. This returns \nil{} if the function is + unavailable or is non-existent as a user callable function object. +\end{defun} + + +\begin{defun}{}{debug-function-name}{\args{\var{debug-function}}} + + This function returns the name of the function represented by + \var{debug-function}. This may be a string or a cons; do not assume + it is a symbol. +\end{defun} + + +\section{Debug-blocks} + +Debug-blocks contain information pertinent to a specific range of code in a +debug-function. + +\begin{defmac}{}{do-debug-block-locations}{% + \args{(\var{code-var} \var{debug-block} \mopt{result}) + \mstar{form}}} + + This macro executes each \var{form} in a context with \var{code-var} + bound to each code-location in \var{debug-block}. This returns the + value of executing \var{result} (defaults to \nil). +\end{defmac} + + +\begin{defun}{}{debug-block-successors}{\args{\var{debug-block}}} + + This function returns the list of possible code-locations where + execution may continue when the basic-block represented by + \var{debug-block} completes its execution. +\end{defun} + + +\begin{defun}{}{debug-block-elsewhere-p}{\args{\var{debug-block}}} + + This function returns whether \var{debug-block} represents elsewhere + code. This is code the compiler has moved out of a function's code + sequence for optimization reasons. Code-locations in these blocks + are unsuitable for stepping tools, and the first code-location has + nothing to do with a normal starting location for the block. +\end{defun} + + +\section{Breakpoints} + +A breakpoint represents a function the system calls with the current frame when +execution passes a certain code-location. A break point is active or inactive +independent of its existence. They also have an extra slot for users to tag +the breakpoint with information. + +\begin{defun}{}{make-breakpoint}{% + \args{\var{hook-function} \var{what} \keys{\kwd{kind} \kwd{info} + \kwd{function-end-cookie}}}} + + This function creates and returns a breakpoint. When program + execution encounters the breakpoint, the system calls + \var{hook-function}. \var{hook-function} takes the current frame + for the function in which the program is running and the breakpoint + object. + + \var{what} and \var{kind} determine where in a function the system + invokes \var{hook-function}. \var{what} is either a code-location + or a debug-function. \var{kind} is one of \kwd{code-location}, + \kwd{function-start}, or \kwd{function-end}. Since the starts and + ends of functions may not have code-locations representing them, + designate these places by supplying \var{what} as a debug-function + and \var{kind} indicating the \kwd{function-start} or + \kwd{function-end}. When \var{what} is a debug-function and + \var{kind} is \kwd{function-end}, then hook-function must take two + additional arguments, a list of values returned by the function and + a function-end-cookie. + + \var{info} is information supplied by and used by the user. + + \var{function-end-cookie} is a function. To implement function-end + breakpoints, the system uses starter breakpoints to establish the + function-end breakpoint for each invocation of the function. Upon + each entry, the system creates a unique cookie to identify the + invocation, and when the user supplies a function for this argument, + the system invokes it on the cookie. The system later invokes the + function-end breakpoint hook on the same cookie. The user may save + the cookie when passed to the function-end-cookie function for later + comparison in the hook function. + + This signals an error if \var{what} is an unknown code-location. + + {\em Note: Breakpoints in interpreted code or byte-compiled code are + not implemented. Function-end breakpoints are not implemented for + compiled functions that use the known local return convention + (e.g. for block-compiled or self-recursive functions.)} + +\end{defun} + + +\begin{defun}{}{activate-breakpoint}{\args{\var{breakpoint}}} + + This function causes the system to invoke the \var{breakpoint}'s + hook-function until the next call to \code{deactivate-breakpoint} or + \code{delete-breakpoint}. The system invokes breakpoint hook + functions in the opposite order that you activate them. +\end{defun} + + +\begin{defun}{}{deactivate-breakpoint}{\args{\var{breakpoint}}} + + This function stops the system from invoking the \var{breakpoint}'s + hook-function. +\end{defun} + + +\begin{defun}{}{breakpoint-active-p}{\args{\var{breakpoint}}} + + This returns whether \var{breakpoint} is currently active. +\end{defun} + + +\begin{defun}{}{breakpoint-hook-function}{\args{\var{breakpoint}}} + + This function returns the \var{breakpoint}'s function the system + calls when execution encounters \var{breakpoint}, and it is active. + This is \code{SETF}'able. +\end{defun} + + +\begin{defun}{}{breakpoint-info}{\args{\var{breakpoint}}} + + This function returns \var{breakpoint}'s information supplied by the + user. This is \code{SETF}'able. +\end{defun} + + +\begin{defun}{}{breakpoint-kind}{\args{\var{breakpoint}}} + + This function returns the \var{breakpoint}'s kind specification. +\end{defun} + + +\begin{defun}{}{breakpoint-what}{\args{\var{breakpoint}}} + + This function returns the \var{breakpoint}'s what specification. +\end{defun} + + +\begin{defun}{}{delete-breakpoint}{\args{\var{breakpoint}}} + + This function frees system storage and removes computational + overhead associated with \var{breakpoint}. After calling this, + \var{breakpoint} is useless and can never become active again. +\end{defun} + + +\section{Code-locations} + +Code-locations represent places in functions where the system has correct +information about the function's environment and where interesting operations +can occur---asking for a local variable's value, setting breakpoints, +evaluating forms within the function's environment, etc. + +Sometimes the interface returns unknown code-locations. These +represent places in functions, but there is no debug information +associated with them. Some operations accept these since they may +succeed even with missing debug data. These operations' argument is +named \var{basic-code-location} indicating they take known and unknown +code-locations. If an operation names its argument +\var{code-location}, and you supply an unknown one, it will signal an +error. For example, \code{frame-code-location} may return an unknown +code-location if someone interrupted Lisp in the given frame. The +system knows where execution will continue, but this place in the code +may not be a place for which the compiler dumped debug information. + +\begin{defun}{}{code-location-debug-function}{\args{\var{basic-code-location}}} + + This function returns the debug-function representing information + about the function corresponding to the code-location. +\end{defun} + + +\begin{defun}{}{code-location-debug-block}{\args{\var{basic-code-location}}} + + This function returns the debug-block containing code-location if it + is available. Some debug policies inhibit debug-block information, + and if none is available, then this signals a \code{no-debug-blocks} + condition. +\end{defun} + + +\begin{defun}{}{code-location-top-level-form-offset}{% + \args{\var{code-location}}} + + This function returns the number of top-level forms before the one + containing \var{code-location} as seen by the compiler in some + compilation unit. A compilation unit is not necessarily a single + file, see the section on debug-sources. +\end{defun} + + +\begin{defun}{}{code-location-form-number}{\args{\var{code-location}}} + + This function returns the number of the form corresponding to + \var{code-location}. The form number is derived by walking the + subforms of a top-level form in depth-first order. While walking + the top-level form, count one in depth-first order for each subform + that is a cons. See \funref{form-number-translations}. +\end{defun} + + +\begin{defun}{}{code-location-debug-source}{\args{\var{code-location}}} + + This function returns \var{code-location}'s debug-source. +\end{defun} + + +\begin{defun}{}{code-location-unknown-p}{\args{\var{basic-code-location}}} + + This function returns whether \var{basic-code-location} is unknown. + It returns \nil{} when the code-location is known. +\end{defun} + + +\begin{defun}{}{code-location=}{\args{\var{code-location1} + \var{code-location2}}} + + This function returns whether the two code-locations are the same. +\end{defun} + + +\section{Debug-sources} + +Debug-sources represent how to get back the source for some code. The +source is either a file (\code{compile-file} or \code{load}), a +lambda-expression (\code{compile}, \code{defun}, \code{defmacro}), or +a stream (something particular to \cmucl{}, \code{compile-from-stream}). + +When compiling a source, the compiler counts each top-level form it +processes, but when the compiler handles multiple files as one block +compilation, the top-level form count continues past file boundaries. +Therefore \code{code-location-top-level-form-offset} returns an offset +that does not always start at zero for the code-location's +debug-source. The offset into a particular source is +\code{code-location-top-level-form-offset} minus +\code{debug-source-root-number}. + +Inside a top-level form, a code-location's form number indicates the +subform corresponding to the code-location. + +\begin{defun}{}{debug-source-from}{\args{\var{debug-source}}} + + This function returns an indication of the type of source. The + following are the possible values: + \begin{Lentry} + \item[\kwd{file}] from a file (obtained by \code{compile-file} if + compiled). + \item[\kwd{lisp}] from Lisp (obtained by \code{compile} if + compiled). + \item[\kwd{stream}] from a non-file stream (\cmucl{} supports + \code{compile-from-stream}). + \end{Lentry} +\end{defun} + + +\begin{defun}{}{debug-source-name}{\args{\var{debug-source}}} + + This function returns the actual source in some sense represented by + debug-source, which is related to \code{debug-source-from}: + \begin{Lentry} + \item[\kwd{file}] the pathname of the file. + \item[\kwd{lisp}] a lambda-expression. + \item[\kwd{stream}] some descriptive string that's otherwise + useless. +\end{Lentry} +\end{defun} + + +\begin{defun}{}{debug-source-created}{\args{\var{debug-source}}} + + This function returns the universal time someone created the source. + This may be \nil{} if it is unavailable. +\end{defun} + + +\begin{defun}{}{debug-source-compiled}{\args{\var{debug-source}}} + + This function returns the time someone compiled the source. This is + \nil{} if the source is uncompiled. +\end{defun} + + +\begin{defun}{}{debug-source-root-number}{\args{\var{debug-source}}} + + This returns the number of top-level forms processed by the compiler + before compiling this source. If this source is uncompiled, this is + zero. This may be zero even if the source is compiled since the + first form in the first file compiled in one compilation, for + example, must have a root number of zero---the compiler saw no other + top-level forms before it. +\end{defun} + + +\section{Source Translation Utilities} + +These two functions provide a mechanism for converting the rather +obscure (but highly compact) representation of source locations into an +actual source form: + +\begin{defun}{}{debug-source-start-positions}{\args{\var{debug-source}}} + + This function returns the file position of each top-level form as a + vector if \var{debug-source} is from a \kwd{file}. If + \code{debug-source-from} is \kwd{lisp} or \kwd{stream}, or the file + is byte-compiled, then the result is \false{}. +\end{defun} + + +\begin{defun}{}{form-number-translations}{\args{\var{form} + \var{tlf-number}}} + + This function returns a table mapping form numbers (see + \code{code-location-form-number}) to source-paths. A source-path + indicates a descent into the top-level-form \var{form}, going + directly to the subform corresponding to a form number. + \var{tlf-number} is the top-level-form number of \var{form}. +\end{defun} + + +\begin{defun}{}{source-path-context}{% + \args{\var{form} \var{path} \var{context}}} + + This function returns the subform of \var{form} indicated by the + source-path. \var{Form} is a top-level form, and \var{path} is a + source-path into it. \var{Context} is the number of enclosing forms + to return instead of directly returning the source-path form. When + \var{context} is non-zero, the form returned contains a marker, + \code{\#:****HERE****}, immediately before the form indicated by + \var{path}. +\end{defun} diff --git a/doc/cmu-user/debugger.tex b/doc/cmu-user/debugger.tex new file mode 100644 index 0000000000..26dbb484c2 --- /dev/null +++ b/doc/cmu-user/debugger.tex @@ -0,0 +1,1334 @@ +\chapter{The Debugger} +\cindex{debugger} +\label{debugger} + +\credits{by Robert MacLachlan} + + +\section{Debugger Introduction} + +The \cmucl{} debugger is unique in its level of support for source-level +debugging of compiled code. Although some other debuggers allow access of +variables by name, this seems to be the first \llisp{} debugger that: +\begin{itemize} + +\item +Tells you when a variable doesn't have a value because it hasn't been +initialized yet or has already been deallocated, or + +\item +Can display the precise source location corresponding to a code +location in the debugged program. +\end{itemize} +These features allow the debugging of compiled code to be made almost +indistinguishable from interpreted code debugging. + +The debugger is an interactive command loop that allows a user to examine +the function call stack. The debugger is invoked when: +\begin{itemize} + +\item +A \tindexed{serious-condition} is signaled, and it is not handled, or + +\item +\findexed{error} is called, and the condition it signals is not handled, or + +\item +The debugger is explicitly invoked with the \clisp{} \findexed{break} +or \findexed{debug} functions. +\end{itemize} + +{\it Note: there are two debugger interfaces in \cmucl{}: the TTY +debugger (described below) and the Motif debugger. Since the +difference is only in the user interface, much of this chapter also +applies to the Motif version. \xlref{motif-interface} for a very brief +discussion of the graphical interface.} + +When you enter the TTY debugger, it looks something like this: + +\begin{example} +Error in function CAR. +Wrong type argument, 3, should have been of type LIST. + +Restarts: + 0: Return to Top-Level. + +Debug (type H for help) + +(CAR 3) +0] +\end{example} + +The first group of lines describe what the error was that put us in the +debugger. In this case \code{car} was called on \code{3}. After \code{Restarts:} +is a list of all the ways that we can restart execution after this error. In +this case, the only option is to return to top-level. After printing its +banner, the debugger prints the current frame and the debugger prompt. + + +\section{The Command Loop} + +The debugger is an interactive read-eval-print loop much like the normal +top-level, but some symbols are interpreted as debugger commands instead +of being evaluated. A debugger command starts with the symbol name of +the command, possibly followed by some arguments on the same line. Some +commands prompt for additional input. Debugger commands can be +abbreviated by any unambiguous prefix: \code{help} can be typed as +\code{h}, \code{he}, etc. For convenience, some commands have +ambiguous one-letter abbreviations: \code{f} for \code{frame}. + +The package is not significant in debugger commands; any symbol with the +name of a debugger command will work. If you want to show the value of +a variable that happens also to be the name of a debugger command, you +can use the \code{list-locals} command or the \code{debug:var} +function, or you can wrap the variable in a \code{progn} to hide it from +the command loop. + +The debugger prompt is ``\var{frame}\code{]}'', where \var{frame} is the number +of the current frame. Frames are numbered starting from zero at the top (most +recent call), increasing down to the bottom. The current frame is the frame +that commands refer to. The current frame also provides the lexical +environment for evaluation of non-command forms. + +\cpsubindex{evaluation}{debugger} The debugger evaluates forms in the lexical +environment of the functions being debugged. The debugger can only +access variables. You can't \code{go} or \code{return-from} into a +function, and you can't call local functions. Special variable +references are evaluated with their current value (the innermost binding +around the debugger invocation)\dash{}you don't get the value that the +special had in the current frame. \xlref{debug-vars} for more +information on debugger variable access. + + +\section{Stack Frames} +\cindex{stack frames} \cpsubindex{frames}{stack} + +A stack frame is the run-time representation of a call to a function; +the frame stores the state that a function needs to remember what it is +doing. Frames have: +\begin{itemize} + +\item +Variables (\pxlref{debug-vars}), which are the values being operated +on, and + +\item +Arguments to the call (which are really just particularly interesting +variables), and + +\item +A current location (\pxlref{source-locations}), which is the place in +the program where the function was running when it stopped to call another +function, or because of an interrupt or error. +\end{itemize} + + +\subsection{Stack Motion} + +These commands move to a new stack frame and print the name of the function +and the values of its arguments in the style of a Lisp function call: +\begin{Lentry} + +\item[\code{up}] +Move up to the next higher frame. More recent function calls are considered +to be higher on the stack. + +\item[\code{down}] +Move down to the next lower frame. + +\item[\code{top}] +Move to the highest frame. + +\item[\code{bottom}] +Move to the lowest frame. + +\item[\code{frame} [\textit{n}]] +Move to the frame with the specified number. Prompts for the number if not +supplied. + +% \key{S} [\var{function-name} [\var{n}]] +% +% \item +% Search down the stack for function. Prompts for the function name if not +% supplied. Searches an optional number of times, but doesn't prompt for +% this number; enter it following the function. +% +% \item[\key{R} [\var{function-name} [\var{n}]]] +% Search up the stack for function. Prompts for the function name if not +% supplied. Searches an optional number of times, but doesn't prompt for +% this number; enter it following the function. +\end{Lentry} + + +\subsection{How Arguments are Printed} + +A frame is printed to look like a function call, but with the actual argument +values in the argument positions. So the frame for this call in the source: + +\begin{lisp} +(myfun (+ 3 4) 'a) +\end{lisp} + +would look like this: + +\begin{example} +(MYFUN 7 A) +\end{example} + +All keyword and optional arguments are displayed with their actual +values; if the corresponding argument was not supplied, the value will +be the default. So this call: + +\begin{lisp} +(subseq "foo" 1) +\end{lisp} + +would look like this: + +\begin{example} +(SUBSEQ "foo" 1 3) +\end{example} + +And this call: + +\begin{lisp} +(string-upcase "test case") +\end{lisp} + +would look like this: + +\begin{example} +(STRING-UPCASE "test case" :START 0 :END NIL) +\end{example} + +The arguments to a function call are displayed by accessing the argument +variables. Although those variables are initialized to the actual argument +values, they can be set inside the function; in this case the new value will be +displayed. + +\code{\amprest} arguments are handled somewhat differently. The value of +the rest argument variable is displayed as the spread-out arguments to +the call, so: + +\begin{lisp} +(format t "~A is a ~A." "This" 'test) +\end{lisp} + +would look like this: + +\begin{example} +(FORMAT T "~A is a ~A." "This" 'TEST) +\end{example} + +Rest arguments cause an exception to the normal display of keyword +arguments in functions that have both \code{\amprest} and \code{\&key} +arguments. In this case, the keyword argument variables are not +displayed at all; the rest arg is displayed instead. So for these +functions, only the keywords actually supplied will be shown, and the +values displayed will be the argument values, not values of the +(possibly modified) variables. + +If the variable for an argument is never referenced by the function, it will be +deleted. The variable value is then unavailable, so the debugger prints +\code{\#\textless unused-arg\textgreater} instead of the value. Similarly, if for any of a number of +reasons (described in more detail in section \ref{debug-vars}) the value of the +variable is unavailable or not known to be available, then +\code{\#\textless unavailable-arg\textgreater} will be printed instead of the argument value. + +Printing of argument values is controlled by \code{*debug-print-level*} and +\varref{debug-print-length}. + +\subsection{Function Names} +\cpsubindex{function}{names} +\cpsubindex{names}{function} + +If a function is defined by \code{defun}, \code{labels}, or \code{flet}, then the +debugger will print the actual function name after the open parenthesis, like: + +\begin{example} +(STRING-UPCASE "test case" :START 0 :END NIL) +((SETF AREF) \#\back{a} "for" 1) +\end{example} + +Otherwise, the function name is a string, and will be printed in quotes: + +\begin{example} +("DEFUN MYFUN" BAR) +("DEFMACRO DO" (DO ((I 0 (1+ I))) ((= I 13))) NIL) +("SETQ *GC-NOTIFY-BEFORE*") +\end{example} + +This string name is derived from the \w{\code{def}\var{mumble}} form +that encloses or expanded into the lambda, or the outermost enclosing +form if there is no \w{\code{def}\var{mumble}}. + +\subsection{Funny Frames} +\cindex{external entry points} +\cpsubindex{entry points}{external} +\cpsubindex{block compilation}{debugger implications} +\cpsubindex{external}{stack frame kind} +\cpsubindex{optional}{stack frame kind} +\cpsubindex{cleanup}{stack frame kind} + +Sometimes the evaluator introduces new functions that are used to implement a +user function, but are not directly specified in the source. The main place +this is done is for checking argument type and syntax. Usually these functions +do their thing and then go away, and thus are not seen on the stack in the +debugger. But when you get some sort of error during lambda-list processing, +you end up in the debugger on one of these funny frames. + +These funny frames are flagged by printing ``\code{[}\var{keyword}\code{]}'' after the +parentheses. For example, this call: + +\begin{lisp} +(car 'a 'b) +\end{lisp} + +will look like this: + +\begin{example} +(CAR 2 A) [:EXTERNAL] +\end{example} + +And this call: + +\begin{lisp} +(string-upcase "test case" :end) +\end{lisp} + +would look like this: + +\begin{example} +("DEFUN STRING-UPCASE" "test case" 335544424 1) [:OPTIONAL] +\end{example} + +As you can see, these frames have only a vague resemblance to the original +call. Fortunately, the error message displayed when you enter the debugger +will usually tell you what problem is (in these cases, too many arguments +and odd keyword arguments.) Also, if you go down the stack to the frame for +the calling function, you can display the original source (\pxlref{source-locations}.) + +With recursive or block compiled functions +(\pxlref{block-compilation}), an \kwd{EXTERNAL} frame may appear +before the frame representing the first call to the recursive function +or entry to the compiled block. This is a consequence of the way the +compiler does block compilation: there is nothing odd with your +program. You will also see \kwd{CLEANUP} frames during the execution +of \code{unwind-protect} cleanup code. Note that inline expansion and +open-coding affect what frames are present in the debugger, see +sections \ref{debugger-policy} and \ref{open-coding}. + + +\subsection{Debug Tail Recursion} +\label{debug-tail-recursion} +\cindex{tail recursion} +\cpsubindex{recursion}{tail} + +Both the compiler and the interpreter are ``properly tail recursive.'' If a +function call is in a tail-recursive position, the stack frame will be +deallocated {\em at the time of the call}, rather than after the call returns. +Consider this backtrace: +\begin{example} +(BAR ...) +(FOO ...) +\end{example} +Because of tail recursion, it is not necessarily the case that +\code{FOO} directly called \code{BAR}. It may be that \code{FOO} called +some other function \code{FOO2} which then called \code{BAR} +tail-recursively, as in this example: +\begin{example} +(defun foo () + ... + (foo2 ...) + ...) + +(defun foo2 (...) + ... + (bar ...)) + +(defun bar (...) + ...) +\end{example} + +Usually the elimination of tail-recursive frames makes debugging more +pleasant, since theses frames are mostly uninformative. If there is any +doubt about how one function called another, it can usually be +eliminated by finding the source location in the calling frame (section +\ref{source-locations}.) + +The elimination of tail-recursive frames can be prevented by disabling +tail-recursion optimization, which happens when the \code{debug} +optimization quality is greater than \code{2} +(\pxlref{debugger-policy}.) + +For a more thorough discussion of tail recursion, \pxlref{tail-recursion}. + + +\subsection{Unknown Locations and Interrupts} +\label{unknown-locations} +\cindex{unknown code locations} +\cpsubindex{locations}{unknown} +\cindex{interrupts} +\cpsubindex{errors}{run-time} + +The debugger operates using special debugging information attached to +the compiled code. This debug information tells the debugger what it +needs to know about the locations in the code where the debugger can be +invoked. If the debugger somehow encounters a location not described in +the debug information, then it is said to be \var{unknown}. If the code +location for a frame is unknown, then some variables may be +inaccessible, and the source location cannot be precisely displayed. + +There are three reasons why a code location could be unknown: +\begin{itemize} + +\item +There is inadequate debug information due to the value of the \code{debug} +optimization quality. \xlref{debugger-policy}. + +\item +The debugger was entered because of an interrupt such as \code{$\hat{ }C$}. + +\item +A hardware error such as ``\code{bus error}'' occurred in code that was +compiled unsafely due to the value of the \code{safety} optimization +quality. \xlref{optimize-declaration}. +\end{itemize} + +In the last two cases, the values of argument variables are accessible, +but may be incorrect. \xlref{debug-var-validity} for more details on +when variable values are accessible. + +It is possible for an interrupt to happen when a function call or return is in +progress. The debugger may then flame out with some obscure error or insist +that the bottom of the stack has been reached, when the real problem is that +the current stack frame can't be located. If this happens, return from the +interrupt and try again. + +When running interpreted code, all locations should be known. However, +an interrupt might catch some subfunction of the interpreter at an +unknown location. In this case, you should be able to go up the stack a +frame or two and reach an interpreted frame which can be debugged. + + +\section{Variable Access} +\label{debug-vars} +\cpsubindex{variables}{debugger access} +\cindex{debug variables} + +There are three ways to access the current frame's local variables in the +debugger. The simplest is to type the variable's name into the debugger's +read-eval-print loop. The debugger will evaluate the variable reference as +though it had appeared inside that frame. + +The debugger doesn't really understand lexical scoping; it has just one +namespace for all the variables in a function. If a symbol is the name of +multiple variables in the same function, then the reference appears ambiguous, +even though lexical scoping specifies which value is visible at any given +source location. If the scopes of the two variables are not nested, then the +debugger can resolve the ambiguity by observing that only one variable is +accessible. + +When there are ambiguous variables, the evaluator assigns each one a +small integer identifier. The \code{debug:var} function and the +\code{list-locals} command use this identifier to distinguish between +ambiguous variables: +\begin{Lentry} + +\item[\code{list-locals} \mopt{\var{prefix}}]%%\hfill\\ +This command prints the name and value of all variables in the current +frame whose name has the specified \var{prefix}. \var{prefix} may be a +string or a symbol. If no \var{prefix} is given, then all available +variables are printed. If a variable has a potentially ambiguous name, +then the name is printed with a ``\code{\#}\var{identifier}'' suffix, where +\var{identifier} is the small integer used to make the name unique. +\end{Lentry} + +\begin{defun}{debug:}{var}{\args{\var{name} \ampoptional{} \var{identifier}}} + + This function returns the value of the variable in the current frame + with the specified \var{name}. If supplied, \var{identifier} + determines which value to return when there are ambiguous variables. + + When \var{name} is a symbol, it is interpreted as the symbol name of + the variable, i.e. the package is significant. If \var{name} is an + uninterned symbol (gensym), then return the value of the uninterned + variable with the same name. If \var{name} is a string, + \code{debug:var} interprets it as the prefix of a variable name, and + must unambiguously complete to the name of a valid variable. + + This function is useful mainly for accessing the value of uninterned + or ambiguous variables, since most variables can be evaluated + directly. +\end{defun} + + +\subsection{Variable Value Availability} +\label{debug-var-validity} +\cindex{availability of debug variables} +\cindex{validity of debug variables} +\cindex{debug optimization quality} + +The value of a variable may be unavailable to the debugger in portions of the +program where \clisp{} says that the variable is defined. If a variable value is +not available, the debugger will not let you read or write that variable. With +one exception, the debugger will never display an incorrect value for a +variable. Rather than displaying incorrect values, the debugger tells you the +value is unavailable. + +The one exception is this: if you interrupt (e.g., with \code{$\hat{ }C$}) or if there is +an unexpected hardware error such as ``\code{bus error}'' (which should only happen +in unsafe code), then the values displayed for arguments to the interrupted +frame might be incorrect.\footnote{Since the location of an interrupt or hardware +error will always be an unknown location (\pxlref{unknown-locations}), +non-argument variable values will never be available in the interrupted frame.} +This exception applies only to the interrupted frame: any frame farther down +the stack will be fine. + +The value of a variable may be unavailable for these reasons: +\begin{itemize} + +\item +The value of the \code{debug} optimization quality may have omitted debug +information needed to determine whether the variable is available. +Unless a variable is an argument, its value will only be available when +\code{debug} is at least \code{2}. + +\item +The compiler did lifetime analysis and determined that the value was no longer +needed, even though its scope had not been exited. Lifetime analysis is +inhibited when the \code{debug} optimization quality is \code{3}. + +\item +The variable's name is an uninterned symbol (gensym). To save space, the +compiler only dumps debug information about uninterned variables when the +\code{debug} optimization quality is \code{3}. + +\item +The frame's location is unknown (\pxlref{unknown-locations}) because +the debugger was entered due to an interrupt or unexpected hardware error. +Under these conditions the values of arguments will be available, but might be +incorrect. This is the exception above. + +\item +The variable was optimized out of existence. Variables with no reads are +always optimized away, even in the interpreter. The degree to which the +compiler deletes variables will depend on the value of the \code{compile-speed} +optimization quality, but most source-level optimizations are done under all +compilation policies. +\end{itemize} + + +Since it is especially useful to be able to get the arguments to a function, +argument variables are treated specially when the \code{speed} optimization +quality is less than \code{3} and the \code{debug} quality is at least \code{1}. +With this compilation policy, the values of argument variables are almost +always available everywhere in the function, even at unknown locations. For +non-argument variables, \code{debug} must be at least \code{2} for values to be +available, and even then, values are only available at known locations. + + +\subsection{Note On Lexical Variable Access} +\cpsubindex{evaluation}{debugger} + +When the debugger command loop establishes variable bindings for available +variables, these variable bindings have lexical scope and dynamic +extent.\footnote{The variable bindings are actually created using the \clisp{} +\code{symbol-macrolet} special form.} You can close over them, but such closures +can't be used as upward funargs. + +You can also set local variables using \code{setq}, but if the variable was closed +over in the original source and never set, then setting the variable in the +debugger may not change the value in all the functions the variable is defined +in. Another risk of setting variables is that you may assign a value of a type +that the compiler proved the variable could never take on. This may result in +bad things happening. + + +\section{Source Location Printing} +\label{source-locations} +\cpsubindex{source location printing}{debugger} + +One of \cmucl{}'s unique capabilities is source level debugging of compiled +code. These commands display the source location for the current frame: +\begin{Lentry} + +\item[\code{source} \mopt{\var{context}}]%%\hfill\\ +This command displays the file that the current frame's function was defined +from (if it was defined from a file), and then the source form responsible for +generating the code that the current frame was executing. If \var{context} is +specified, then it is an integer specifying the number of enclosing levels of +list structure to print. + +\item[\code{vsource} \mopt{\var{context}}]%%\hfill\\ +This command is identical to \code{source}, except that it uses the +global values of \code{*print-level*} and \code{*print-length*} instead +of the debugger printing control variables \code{*debug-print-level*} +and \code{*debug-print-length*}. +\end{Lentry} + +The source form for a location in the code is the innermost list present +in the original source that encloses the form responsible for generating +that code. If the actual source form is not a list, then some enclosing +list will be printed. For example, if the source form was a reference +to the variable \code{*some-random-special*}, then the innermost +enclosing evaluated form will be printed. Here are some possible +enclosing forms: +\begin{example} +(let ((a *some-random-special*)) + ...) + +(+ *some-random-special* ...) +\end{example} + +If the code at a location was generated from the expansion of a macro or a +source-level compiler optimization, then the form in the original source that +expanded into that code will be printed. Suppose the file +\file{/usr/me/mystuff.lisp} looked like this: +\begin{example} +(defmacro mymac () + '(myfun)) + +(defun foo () + (mymac) + ...) +\end{example} +If \code{foo} has called \code{myfun}, and is waiting for it to return, then the +\code{source} command would print: +\begin{example} +; File: /usr/me/mystuff.lisp + +(MYMAC) +\end{example} +Note that the macro use was printed, not the actual function call form, +\code{(myfun)}. + +If enclosing source is printed by giving an argument to \code{source} or +\code{vsource}, then the actual source form is marked by wrapping it in a list +whose first element is \code{\#:***HERE***}. In the previous example, +\w{\code{source 1}} would print: +\begin{example} +; File: /usr/me/mystuff.lisp + +(DEFUN FOO () + (#:***HERE*** + (MYMAC)) + ...) +\end{example} + + +\subsection{How the Source is Found} + +If the code was defined from \llisp{} by \code{compile} or +\code{eval}, then the source can always be reliably located. If the +code was defined from a \code{fasl} file created by +\findexed{compile-file}, then the debugger gets the source forms it +prints by reading them from the original source file. This is a +potential problem, since the source file might have moved or changed +since the time it was compiled. + +The source file is opened using the \code{truename} of the source file +pathname originally given to the compiler. This is an absolute pathname +with all logical names and symbolic links expanded. If the file can't +be located using this name, then the debugger gives up and signals an +error. + +If the source file can be found, but has been modified since the time it was +compiled, the debugger prints this warning: +\begin{example} +; File has been modified since compilation: +; \var{filename} +; Using form offset instead of character position. +\end{example} +where \var{filename} is the name of the source file. It then proceeds using a +robust but not foolproof heuristic for locating the source. This heuristic +works if: +\begin{itemize} + +\item +No top-level forms before the top-level form containing the source have been +added or deleted, and + +\item +The top-level form containing the source has not been modified much. (More +precisely, none of the list forms beginning before the source form have been +added or deleted.) +\end{itemize} + +If the heuristic doesn't work, the displayed source will be wrong, but will +probably be near the actual source. If the ``shape'' of the top-level form in +the source file is too different from the original form, then an error will be +signaled. When the heuristic is used, the the source location commands are +noticeably slowed. + +Source location printing can also be confused if (after the source was +compiled) a read-macro you used in the code was redefined to expand into +something different, or if a read-macro ever returns the same \code{eq} +list twice. If you don't define read macros and don't use \code{\#\#} in +perverted ways, you don't need to worry about this. + + +\subsection{Source Location Availability} + +\cindex{debug optimization quality} +Source location information is only available when the \code{debug} +optimization quality is at least \code{2}. If source location information is +unavailable, the source commands will give an error message. + +If source location information is available, but the source location is +unknown because of an interrupt or unexpected hardware error +(\pxlref{unknown-locations}), then the command will print: + +\begin{example} +Unknown location: using block start. +\end{example} + +and then proceed to print the source location for the start of the +{\em basic block} enclosing the code location. +\cpsubindex{block}{basic} \cpsubindex{block}{start location} +It's a bit complicated to explain exactly what a basic block is, but +here are some properties of the block start location: + +\begin{itemize} + +\item The block start location may be the same as the true location. + +\item The block start location will never be later in the the + program's flow of control than the true location. + +\item No conditional control structures (such as \code{if}, + \code{cond}, \code{or}) will intervene between the block start and + the true location (but note that some conditionals present in the + original source could be optimized away.) Function calls {\em do not} + end basic blocks. + +\item The head of a loop will be the start of a block. + +\item The programming language concept of ``block structure'' and the + \clisp{} \code{block} special form are totally unrelated to the + compiler's basic block. +\end{itemize} + +In other words, the true location lies between the printed location and the +next conditional (but watch out because the compiler may have changed the +program on you.) + + +\section{Compiler Policy Control} +\label{debugger-policy} +\cpsubindex{policy}{debugger} +\cindex{debug optimization quality} +\cindex{optimize declaration} + +The compilation policy specified by \code{optimize} declarations affects the +behavior seen in the debugger. The \code{debug} quality directly affects the +debugger by controlling the amount of debugger information dumped. Other +optimization qualities have indirect but observable effects due to changes in +the way compilation is done. + +Unlike the other optimization qualities (which are compared in relative value +to evaluate tradeoffs), the \code{debug} optimization quality is directly +translated to a level of debug information. This absolute interpretation +allows the user to count on a particular amount of debug information being +available even when the values of the other qualities are changed during +compilation. These are the levels of debug information that correspond to the +values of the \code{debug} quality: +\begin{Lentry} + +\item[\code{0}] +Only the function name and enough information to allow the stack to +be parsed. + +\item[\code{\w{$>$ 0}}] +Any level greater than \code{0} gives level \code{0} plus all +argument variables. Values will only be accessible if the argument +variable is never set and +\code{speed} is not \code{3}. \cmucl{} allows any real value for optimization +qualities. It may be useful to specify \code{0.5} to get backtrace argument +display without argument documentation. + +\item[\code{1}] Level \code{1} provides argument documentation +(printed arglists) and derived argument/result type information. +This makes \findexed{describe} more informative, and allows the +compiler to do compile-time argument count and type checking for any +calls compiled at run-time. + +\item[\code{2}] +Level \code{1} plus all interned local variables, source location +information, and lifetime information that tells the debugger when arguments +are available (even when \code{speed} is \code{3} or the argument is set.) This is +the default. + +\item[\code{\w{$>$ 2}}] +Any level greater than \code{2} gives level \code{2} and in addition +disables tail-call optimization, so that the backtrace will contain +frames for all invoked functions, even those in tail positions. + +\item[\code{3}] +Level \code{2} plus all uninterned variables. In addition, lifetime +analysis is disabled (even when \code{speed} is \code{3}), ensuring +that all variable values are available at any known location within +the scope of the binding. This has a speed penalty in addition to the +obvious space penalty. +\end{Lentry} + +As you can see, if the \code{speed} quality is \code{3}, debugger performance is +degraded. This effect comes from the elimination of argument variable +special-casing (\pxlref{debug-var-validity}.) Some degree of +speed/debuggability tradeoff is unavoidable, but the effect is not too drastic +when \code{debug} is at least \code{2}. + +\cindex{inline expansion} +\cindex{semi-inline expansion} +In addition to \code{inline} and \code{notinline} declarations, the relative values +of the \code{speed} and \code{space} qualities also change whether functions are +inline expanded (\pxlref{inline-expansion}.) If a function is inline +expanded, then there will be no frame to represent the call, and the arguments +will be treated like any other local variable. Functions may also be +``semi-inline'', in which case there is a frame to represent the call, but the +call is to an optimized local version of the function, not to the original +function. + + +\section{Exiting Commands} + +These commands get you out of the debugger. + +\begin{Lentry} + +\item[\code{quit}] +Throw to top level. + +\item[\code{restart} \mopt{\var{n}}]%%\hfill\\ +Invokes the \var{n}th restart case as displayed by the \code{error} +command. If \var{n} is not specified, the available restart cases are +reported. + +\item[\code{go}] +Calls \code{continue} on the condition given to \code{debug}. If there is no +restart case named \var{continue}, then an error is signaled. + +\item[\code{abort}] +Calls \code{abort} on the condition given to \code{debug}. This is +useful for popping debug command loop levels or aborting to top level, +as the case may be. + +% (\code{debug:debug-return} \var{expression} \mopt{\var{frame}}) +% +% \item +% From the current or specified frame, return the result of evaluating +% expression. If multiple values are expected, then this function should be +% called for multiple values. +\end{Lentry} + + +\section{Information Commands} + +Most of these commands print information about the current frame or +function, but a few show general information. + +\begin{Lentry} + +\item[\code{help}, \code{?}] +Displays a synopsis of debugger commands. + +\item[\code{describe}] +Calls \code{describe} on the current function, displays number of local +variables, and indicates whether the function is compiled or interpreted. + +\item[\code{print}] +Displays the current function call as it would be displayed by moving to +this frame. + +\item[\code{vprint} (or \code{pp}) \mopt{\var{verbosity}}]%%\hfill\\ +Displays the current function call using \code{*print-level*} and +\code{*print-length*} instead of \code{*debug-print-level*} and +\code{*debug-print-length*}. \var{verbosity} is a small integer +(default 2) that controls other dimensions of verbosity. + +\item[\code{error}] +Prints the condition given to \code{invoke-debugger} and the active +proceed cases. + +\item[\code{backtrace} \mopt{\var{n}}]\hfill\\ +Displays all the frames from the current to the bottom. Only shows +\var{n} frames if specified. The printing is controlled by +\code{*debug-print-level*} and \code{*debug-print-length*}. + +% (\code{debug:debug-function} \mopt{\var{n}}) +% +% \item +% Returns the function from the current or specified frame. +% +% \item[(\code{debug:function-name} \mopt{\var{n}])] +% Returns the function name from the current or specified frame. +% +% \item[(\code{debug:pc} \mopt{\var{frame}})] +% Returns the index of the instruction for the function in the current or +% specified frame. This is useful in conjunction with \code{disassemble}. +% The pc returned points to the instruction after the one that was fatal. +\end{Lentry} + + +\section{Breakpoint Commands}\cindex{breakpoints} + +\cmucl{} supports setting of breakpoints inside compiled functions and +stepping of compiled code. Breakpoints can only be set at at known +locations (\pxlref{unknown-locations}), so these commands are largely +useless unless the \code{debug} optimize quality is at least \code{2} +(\pxlref{debugger-policy}). These commands manipulate breakpoints: +\begin{Lentry} +\item[\code{breakpoint} \var{location} \mstar{\var{option} \var{value}}] +%%\hfill\\ +Set a breakpoint in some function. \var{location} may be an integer +code location number (as displayed by \code{list-locations}) or a +keyword. The keyword can be used to indicate setting a breakpoint at +the function start (\kwd{start}, \kwd{s}) or function end +(\kwd{end}, \kwd{e}). The \code{breakpoint} command has +\kwd{condition}, \kwd{break}, \kwd{print} and \kwd{function} +options which work similarly to the \code{trace} options. + +\item[\code{list-locations} (or \code{ll}) \mopt{\var{function}}]%%\hfill\\ +List all the code locations in the current frame's function, or in +\var{function} if it is supplied. The display format is the code +location number, a colon and then the source form for that location: +\begin{example} +3: (1- N) +\end{example} +If consecutive locations have the same source, then a numeric range like +\code{3-5:} will be printed. For example, a default function call has a +known location both immediately before and after the call, which would +result in two code locations with the same source. The listed function +becomes the new default function for breakpoint setting (via the +\code{breakpoint}) command. + +\item[\code{list-breakpoints} (or \code{lb})]%%\hfill\\ +List all currently active breakpoints with their breakpoint number. + +\item[\code{delete-breakpoint} (or \code{db}) \mopt{\var{number}}]%%\hfill\\ +Delete a breakpoint specified by its breakpoint number. If no number is +specified, delete all breakpoints. + +\item[\code{step}]%%\hfill\\ +Step to the next possible breakpoint location in the current function. +This always steps over function calls, instead of stepping into them +\end{Lentry} + + +\subsection{Breakpoint Example} + +Consider this definition of the factorial function: + +\begin{lisp} +(defun ! (n) + (if (zerop n) + 1 + (* n (! (1- n))))) +\end{lisp} + +This debugger session demonstrates the use of breakpoints: + +\begin{example} +common-lisp-user> (break) ; Invoke debugger + +Break + +Restarts: + 0: [CONTINUE] Return from BREAK. + 1: [ABORT ] Return to Top-Level. + +Debug (type H for help) + +(INTERACTIVE-EVAL (BREAK)) +0] ll #'! +0: #'(LAMBDA (N) (BLOCK ! (IF # 1 #))) +1: (ZEROP N) +2: (* N (! (1- N))) +3: (1- N) +4: (! (1- N)) +5: (* N (! (1- N))) +6: #'(LAMBDA (N) (BLOCK ! (IF # 1 #))) +0] br 2 +(* N (! (1- N))) +1: 2 in ! +Added. +0] q + +common-lisp-user> (! 10) ; Call the function + +*Breakpoint hit* + +Restarts: + 0: [CONTINUE] Return from BREAK. + 1: [ABORT ] Return to Top-Level. + +Debug (type H for help) + +(! 10) ; We are now in first call (arg 10) before the multiply +Source: (* N (! (1- N))) +3] st + +*Step* + +(! 10) ; We have finished evaluation of (1- n) +Source: (1- N) +3] st + +*Breakpoint hit* + +Restarts: + 0: [CONTINUE] Return from BREAK. + 1: [ABORT ] Return to Top-Level. + +Debug (type H for help) + +(! 9) ; We hit the breakpoint in the recursive call +Source: (* N (! (1- N))) +3] +\end{example} + + +\section{Function Tracing} +\cindex{tracing} +\cpsubindex{function}{tracing} + +The tracer causes selected functions to print their arguments and +their results whenever they are called. Options allow conditional +printing of the trace information and conditional breakpoints on +function entry or exit. + +\begin{defmac}{}{trace}{% + \args{\mstar{option global-value} \mstar{name \mstar{option value}}}} + + \code{trace} is a debugging tool that prints information when + specified functions are called. In its simplest form: + \begin{example} + (trace \var{name-1} \var{name-2} ...) + \end{example} + \code{trace} causes a printout on \vindexed{trace-output} each time + that one of the named functions is entered or returns (the + \var{names} are not evaluated.) Trace output is indented according + to the number of pending traced calls, and this trace depth is + printed at the beginning of each line of output. Printing verbosity + of arguments and return values is controlled by + \vindexed{debug-print-level} and \vindexed{debug-print-length}. + + Local functions defined by \code{flet} and \code{labels} can be + traced using the syntax \code{(flet f f1 f2 ...)} or \code{(labels f + f1 f2 ...)} where \code{f} is the \code{flet} or \code{labels} + function we want to trace and \code{f1}, \code{f2}, are the + functions containing the local function \code{f}. + Invidiual methods can also be traced using the syntax \code{(method + \var{name} \var{qualifiers} \var{specializers})}. + See~\ref{sec:method-tracing} for more information. + + If no \var{names} or \var{options} are are given, \code{trace} + returns the list of all currently traced functions, + \code{*traced-function-list*}. + + Trace options can cause the normal printout to be suppressed, or + cause extra information to be printed. Each option is a pair of an + option keyword and a value form. Options may be interspersed with + function names. Options only affect tracing of the function whose + name they appear immediately after. Global options are specified + before the first name, and affect all functions traced by a given + use of \code{trace}. If an already traced function is traced again, + any new options replace the old options. The following options are + defined: + \begin{Lentry} + \item[\kwd{condition} \var{form}, \kwd{condition-after} \var{form}, + \kwd{condition-all} \var{form}] If \kwd{condition} is specified, + then \code{trace} does nothing unless \var{form} evaluates to true + at the time of the call. \kwd{condition-after} is similar, but + suppresses the initial printout, and is tested when the function + returns. \kwd{condition-all} tries both before and after. + + \item[\kwd{wherein} \var{names}] If specified, \var{names} is a + function name or list of names. \code{trace} does nothing unless + a call to one of those functions encloses the call to this + function (i.e. it would appear in a backtrace.) Anonymous + functions have string names like \code{"DEFUN FOO"}. Individual + methods can also be traced. See section~\ref{sec:method-tracing}. + + \item[\kwd{wherein-only} \var{names}] If specified, this is just + like \kwd{wherein}, but trace produces output only if the + immediate caller of the traced function is one of the functions + listed in \var{names}. + + \item[\kwd{break} \var{form}, \kwd{break-after} \var{form}, + \kwd{break-all} \var{form}] If specified, and \var{form} evaluates + to true, then the debugger is invoked at the start of the + function, at the end of the function, or both, according to the + respective option. + + \item[\kwd{print} \var{form}, \kwd{print-after} \var{form}, + \kwd{print-all} \var{form}] In addition to the usual printout, the + result of evaluating \var{form} is printed at the start of the + function, at the end of the function, or both, according to the + respective option. Multiple print options cause multiple values + to be printed. + + \item[\kwd{function} \var{function-form}] This is a not really an + option, but rather another way of specifying what function to + trace. The \var{function-form} is evaluated immediately, and the + resulting function is traced. + + \item[\kwd{encapsulate \mgroup{:default | t | nil}}] In \cmucl, + tracing can be done either by temporarily redefining the function + name (encapsulation), or using breakpoints. When breakpoints are + used, the function object itself is destructively modified to + cause the tracing action. The advantage of using breakpoints is + that tracing works even when the function is anonymously called + via \code{funcall}. + + When \kwd{encapsulate} is true, tracing is done via encapsulation. + \kwd{default} is the default, and means to use encapsulation for + interpreted functions and funcallable instances, breakpoints + otherwise. When encapsulation is used, forms are {\it not} + evaluated in the function's lexical environment, but + \code{debug:arg} can still be used. + + Note that if you trace using \kwd{encapsulate}, you will + only get a trace or breakpoint at the outermost call to the traced + function, not on recursive calls. + + \end{Lentry} + + In the case of functions where the known return convention is used + to optimize, encapsulation may be necessary in order to make + tracing work at all. The symptom of this occurring is an error + stating + \begin{example} + Error in function \var{foo}: :FUNCTION-END breakpoints are + currently unsupported for the known return convention. + \end{example} + in such cases we recommend using \code{(trace \var{foo} :encapsulate + t)} + + \cpsubindex{tracing}{errors} + \cpsubindex{breakpoints}{errors} + \cpsubindex{errors}{breakpoints} + \cindex{function-end breakpoints} + \cpsubindex{breakpoints}{function-end} + + \kwd{condition}, \kwd{break} and \kwd{print} forms are evaluated in + the lexical environment of the called function; \code{debug:var} and + \code{debug:arg} can be used. The \code{-after} and \code{-all} + forms are evaluated in the null environment. +\end{defmac} + +\begin{defmac}{}{untrace}{ \args{\amprest{} \var{function-names}}} + + This macro turns off tracing for the specified functions, and + removes their names from \code{*traced-function-list*}. If no + \var{function-names} are given, then all currently traced functions + are untraced. +\end{defmac} + +\begin{defvar}{extensions:}{traced-function-list} + + A list of function names maintained and used by \code{trace}, + \code{untrace}, and \code{untrace-all}. This list should contain + the names of all functions currently being traced. +\end{defvar} + +\begin{defvar}{extensions:}{max-trace-indentation} + + The maximum number of spaces which should be used to indent trace + printout. This variable is initially set to 40. +\end{defvar} + +\begin{defvar}{debug:}{trace-encapsulate-package-names} + + A list of package names. Functions from these packages are traced + using encapsulation instead of function-end breakpoints. This list + should at least include those packages containing functions used + directly or indirectly in the implementation of \code{trace}. +\end{defvar} + + +\subsection{Encapsulation Functions} +\cindex{encapsulation} +\cindex{advising} + +The encapsulation functions provide a mechanism for intercepting the +arguments and results of a function. \code{encapsulate} changes the +function definition of a symbol, and saves it so that it can be +restored later. The new definition normally calls the original +definition. The \clisp{} \findexed{fdefinition} function always returns +the original definition, stripping off any encapsulation. + +The original definition of the symbol can be restored at any time by +the \code{unencapsulate} function. \code{encapsulate} and \code{unencapsulate} +allow a symbol to be multiply encapsulated in such a way that different +encapsulations can be completely transparent to each other. + +Each encapsulation has a type which may be an arbitrary lisp object. +If a symbol has several encapsulations of different types, then any +one of them can be removed without affecting more recent ones. +A symbol may have more than one encapsulation of the same type, but +only the most recent one can be undone. + +\begin{defun}{extensions:}{encapsulate}{% + \args{\var{symbol} \var{type} \var{body}}} + + Saves the current definition of \var{symbol}, and replaces it with a + function which returns the result of evaluating the form, + \var{body}. \var{Type} is an arbitrary lisp object which is the + type of encapsulation. + + When the new function is called, the following variables are bound + for the evaluation of \var{body}: + \begin{Lentry} + + \item[\code{extensions:argument-list}] A list of the arguments to + the function. + + \item[\code{extensions:basic-definition}] The unencapsulated + definition of the function. + \end{Lentry} + The unencapsulated definition may be called with the original + arguments by including the form + \begin{lisp} + (apply extensions:basic-definition extensions:argument-list) + \end{lisp} + + \code{encapsulate} always returns \var{symbol}. +\end{defun} + +\begin{defun}{extensions:}{unencapsulate}{\args{\var{symbol} \var{type}}} + + Undoes \var{symbol}'s most recent encapsulation of type \var{type}. + \var{Type} is compared with \code{eq}. Encapsulations of other + types are left in place. +\end{defun} + +\begin{defun}{extensions:}{encapsulated-p}{% + \args{\var{symbol} \var{type}}} + + Returns \true{} if \var{symbol} has an encapsulation of type + \var{type}. Returns \nil{} otherwise. \var{type} is compared with + \code{eq}. +\end{defun} + +\subsection{Tracing Examples} + Here is an example of tracing with some of the possible options. + For simplicity, this is the function: + \begin{example} + (defun fact (n) + (declare (double-float n) (optimize speed)) + (if (zerop n) + 1d0 + (* n (fact (1- n))))) + (compile 'fact) + \end{example} + + This example shows how to use the :condition option: + \begin{example} + (trace fact :condition (= 4d0 (debug:arg 0))) + (fact 10d0) -> + 0: (FACT 4.0d0) + 0: FACT returned 24.0d0 + 3628800.0d0 + \end{example} + As we can see, we produced output when the condition was satisfied. + + Here's another example: + \begin{example} + (untrace) + (trace fact :break (= 4d0 (debug:arg 0))) + (fact 10d0) -> + 0: (FACT 5.0d0) + 1: (FACT 4.0d0) + + + Breaking before traced call to FACT: + [Condition of type SIMPLE-CONDITION] + + Restarts: + 0: [CONTINUE] Return from BREAK. + 1: [ABORT ] Return to Top-Level. + + Debug (type H for help) + \end{example} + In this example, we see that normal tracing occurs until we the + argument reaches 4d0, at which point, we break into the debugger. + + +% section{The Single Stepper} +% +% \begin{defmac}{}{step}{ \args{\var{form}}} +% +% Evaluates form with single stepping enabled or if \var{form} is +% \code{T}, enables stepping until explicitly disabled. Stepping can +% be disabled by quitting to the lisp top level, or by evaluating the +% form \w{\code{(step ())}}. +% +% While stepping is enabled, every call to eval will prompt the user +% for a single character command. The prompt is the form which is +% about to be \code{eval}ed. It is printed with \code{*print-level*} +% and \code{*print-length*} bound to \code{*step-print-level*} and +% \code{*step-print-length*}. All interaction is done through the +% stream \code{*query-io*}. Because of this, the stepper can not be +% used in Hemlock eval mode. When connected to a slave Lisp, the +% stepper can be used from Hemlock. +% +% The commands are: +% \begin{Lentry} +% +% \item[\key{n} (next)] Evaluate the expression with stepping still +% enabled. +% +% \item[\key{s} (skip)] Evaluate the expression with stepping +% disabled. +% +% \item[\key{q} (quit)] Evaluate the expression, but disable all +% further stepping inside the current call to \code{step}. +% +% \item[\key{p} (print)] Print current form. (does not use +% \code{*step-print-level*} or \code{*step-print-length*}.) +% +% \item[\key{b} (break)] Enter break loop, and then prompt for the +% command again when the break loop returns. +% +% \item[\key{e} (eval)] Prompt for and evaluate an arbitrary +% expression. The expression is evaluated with stepping disabled. +% +% \item[\key{?} (help)] Prints a brief list of the commands. +% +% \item[\key{r} (return)] Prompt for an arbitrary value to return as +% result of the current call to eval. +% +% \item[\key{g}] Throw to top level. +% \end{Lentry} +% \end{defmac} +% +% \begin{defvar}{extensions:}{step-print-level} +% \defvarx[extensions:]{step-print-length} +% +% \code{*print-level*} and \code{*print-length*} are bound to these +% values while printing the current form. \code{*step-print-level*} +% and \code{*step-print-length*} are initially bound to 4 and 5, +% respectively. +% \end{defvar} +% +% \begin{defvar}{extensions:}{max-step-indentation} +% +% Step indents the prompts to highlight the nesting of the evaluation. +% This variable contains the maximum number of spaces to use for +% indenting. Initially set to 40. +% \end{defvar} + + +\section{Specials} +These are the special variables that control the debugger action. + +\begin{defvar}{debug:}{debug-print-level} + \defvarx[debug:]{debug-print-length} + + \code{*print-level*} and \code{*print-length*} are bound to these + values during the execution of some debug commands. When evaluating + arbitrary expressions in the debugger, the normal values of + \code{*print-level*} and \code{*print-length*} are in effect. These + variables are initially set to 3 and 5, respectively. +\end{defvar} diff --git a/doc/cmu-user/extensions.tex b/doc/cmu-user/extensions.tex new file mode 100644 index 0000000000..3521a13342 --- /dev/null +++ b/doc/cmu-user/extensions.tex @@ -0,0 +1,3077 @@ +\chapter{Design Choices and Extensions} + +Several design choices in \clisp{} are left to the individual +implementation, and some essential parts of the programming environment +are left undefined. This chapter discusses the most important design +choices and extensions. + +\section{Data Types} + +\subsection{Integers} + +The \tindexed{fixnum} type is equivalent to \code{(signed-byte 30)}. +Integers outside this range are represented as a \tindexed{bignum} or +a word integer (\pxlref{word-integers}.) Almost all integers that +appear in programs can be represented as a \code{fixnum}, so integer +number consing is rare. + + +\subsection{Floats} +\label{ieee-float} + +\cmucl{} supports three floating point formats: +\tindexed{single-float}, \tindexed{double-float} and +\tindexed{double-double-float}. The first two are implemented with +IEEE single and double float arithmetic, respectively. The last is an +extension; \pxlref{extended-float} for more information. +\code{short-float} is a synonym for \code{single-float}, and +\code{long-float} is a synonym for \code{double-float}. The initial +value of \vindexed{read-default-float-format} is \code{single-float}. + +Both \code{single-float} and \code{double-float} are represented with +a pointer descriptor, so float operations can cause number consing. +Number consing is greatly reduced if programs are written to allow the +use of non-descriptor representations (\pxlref{numeric-types}.) + + +\subsubsection{IEEE Special Values} + +\cmucl{} supports the IEEE infinity and NaN special values. These +non-numeric values will only be generated when trapping is disabled +for some floating point exception (\pxlref{float-traps}), so users of +the default configuration need not concern themselves with special +values. + +\begin{defconst}{extensions:}{short-float-positive-infinity} + \defconstx[extensions:]{short-float-negative-infinity} + \defconstx[extensions:]{single-float-positive-infinity} + \defconstx[extensions:]{single-float-negative-infinity} + \defconstx[extensions:]{double-float-positive-infinity} + \defconstx[extensions:]{double-float-negative-infinity} + \defconstx[extensions:]{long-float-positive-infinity} + \defconstx[extensions:]{long-float-negative-infinity} + + The values of these constants are the IEEE positive and negative + infinity objects for each float format. +\end{defconst} + +\begin{defun}{extensions:}{float-infinity-p}{\args{\var{x}}} + + This function returns true if \var{x} is an IEEE float infinity (of + either sign.) \var{x} must be a float. +\end{defun} + +\begin{defun}{extensions:}{float-nan-p}{\args{\var{x}}} + \defunx[extensions:]{float-signaling-nan-p}{\args{\var{x}}} + \defunx[extensions:]{float-trapping-nan-p}{\args{\var{x}}} + + \code{float-nan-p} returns true if \var{x} is an IEEE NaN (Not A + Number) object. \code{float-signaling-nan-p} returns true only if + \var{x} is a trapping NaN. With either function, \var{x} must be a + float. \code{float-trapping-nan-p} is the former name of + \code{float-signaling-nan-p} and is deprecated. +\end{defun} + +\subsubsection{Negative Zero} + +The IEEE float format provides for distinct positive and negative +zeros. To test the sign on zero (or any other float), use the +\clisp{} \findexed{float-sign} function. Negative zero prints as +\code{-0.0f0} or \code{-0.0d0}. + +\subsubsection{Denormalized Floats} + +\cmucl{} supports IEEE denormalized floats. Denormalized floats +provide a mechanism for gradual underflow. The \clisp{} +\findexed{float-precision} function returns the actual precision of a +denormalized float, which will be less than \findexed{float-digits}. +Note that in order to generate (or even print) denormalized floats, +trapping must be disabled for the underflow exception +(\pxlref{float-traps}.) The \clisp{} +\w{\code{least-positive-}\var{format}-\code{float}} constants are +denormalized. + +\begin{defun}{extensions:}{float-denormalized-p}{\args{\var{x}}} + + This function returns true if \var{x} is a denormalized float. + \var{x} must be a float. +\end{defun} + + +\subsubsection{Floating Point Exceptions} +\label{float-traps} + +The IEEE floating point standard defines several exceptions that occur +when the result of a floating point operation is unclear or +undesirable. Exceptions can be ignored, in which case some default +action is taken, such as returning a special value. When trapping is +enabled for an exception, a error is signalled whenever that exception +occurs. These are the possible floating point exceptions: +\begin{Lentry} + +\item[\kwd{underflow}] This exception occurs when the result of an + operation is too small to be represented as a normalized float in + its format. If trapping is enabled, the + \tindexed{floating-point-underflow} condition is signalled. + Otherwise, the operation results in a denormalized float or zero. + +\item[\kwd{overflow}] This exception occurs when the result of an + operation is too large to be represented as a float in its format. + If trapping is enabled, the \tindexed{floating-point-overflow} + exception is signalled. Otherwise, the operation results in the + appropriate infinity. + +\item[\kwd{inexact}] This exception occurs when the result of a + floating point operation is not exact, i.e. the result was rounded. + If trapping is enabled, the \code{extensions:floating-point-inexact} + condition is signalled. Otherwise, the rounded result is returned. + +\item[\kwd{invalid}] This exception occurs when the result of an + operation is ill-defined, such as \code{\w{(/ 0.0 0.0)}}. If + trapping is enabled, the \code{extensions:floating-point-invalid} + condition is signalled. Otherwise, a quiet NaN is returned. + +\item[\kwd{divide-by-zero}] This exception occurs when a float is + divided by zero. If trapping is enabled, the + \tindexed{divide-by-zero} condition is signalled. Otherwise, the + appropriate infinity is returned. +\end{Lentry} + +\subsubsection{Floating Point Rounding Mode} +\label{float-rounding-modes} + +IEEE floating point specifies four possible rounding modes: +\begin{Lentry} + +\item[\kwd{nearest}] In this mode, the inexact results are rounded to + the nearer of the two possible result values. If the neither + possibility is nearer, then the even alternative is chosen. This + form of rounding is also called ``round to even'', and is the form + of rounding specified for the \clisp{} \findexed{round} function. + +\item[\kwd{positive-infinity}] This mode rounds inexact results to the + possible value closer to positive infinity. This is analogous to + the \clisp{} \findexed{ceiling} function. + +\item[\kwd{negative-infinity}] This mode rounds inexact results to the + possible value closer to negative infinity. This is analogous to + the \clisp{} \findexed{floor} function. + +\item[\kwd{zero}] This mode rounds inexact results to the possible + value closer to zero. This is analogous to the \clisp{} + \findexed{truncate} function. +\end{Lentry} + +Warning: Although the rounding mode can be changed with +\code{set-floating-point-modes}, use of any value other than the +default (\kwd{nearest}) can cause unusual behavior, since it will +affect rounding done by \llisp{} system code as well as rounding in +user code. In particular, the unary \code{round} function will stop +doing round-to-nearest on floats, and instead do the selected form of +rounding. + +%% \subsubsection{Precision Control} +%% \label{precision-control} +%% +%% The floating-point unit for the Intel IA-32 architecture supports a +%% precision control mechanism. The floating-point unit consists of an +%% IEEE extended double-float unit and all operations are always done +%% using his format, and this includes rounding. However, by setting the +%% precision control mode, the user can control how rounding is done for +%% each basic arithmetic operation like addition, subtraction, +%% multiplication, and division. The extra instructions for +%% trigonometric, exponential, and logarithmic operations are not +%% affected. We refer the reader to Intel documentation for more +%% information. +%% +%% The possible modes are: +%% \begin{Lentry} +%% +%% \item[\kwd{24-bit}] In this mode, all basic arithmetic operations like +%% addition, subtraction, multiplication, and division, are rounded +%% after each operation as if both the operands were IEEE single +%% precision numbers. +%% +%% \item[\kwd{53-bit}] In this mode, rounding is performed as if the +%% operands and results were IEEE double precision numbers. +%% +%% \item[\kwd{64-bit}] In this mode, the default, rounding is performed +%% on the full IEEE extended double precision format. +%% +%% \end{Lentry} +%% +%% \subsubsection{Warning:} +%% +%% Although the precision mode can be changed with +%% \code{set-floating-point-modes}, use of anything other than +%% \kwd{64-bit} or \kwd{53-bit} can cause unexpected results, especially +%% if external functions or libraries are called. A setting of +%% \kwd{64-bit} also causes \code{(= 1d0 (+ 1d0 double-float-epsilon))} +%% to return \true{} instead of \false. +%% +%% +\subsubsection{Accessing the Floating Point Modes} + +These functions can be used to modify or read the floating point modes: + +\begin{defun}{extensions:}{set-floating-point-modes}{% + \keys{\kwd{traps} \kwd{rounding-mode}} + \morekeys{\kwd{fast-mode} \kwd{accrued-exceptions}} + \yetmorekeys{\kwd{current-exceptions}}} + \defunx[extensions:]{get-floating-point-modes}{} + + The keyword arguments to \code{set-floating-point-modes} set various + modes controlling how floating point arithmetic is done: + \begin{Lentry} + + \item[\kwd{traps}] A list of the exception conditions that should + cause traps. Possible exceptions are \kwd{underflow}, + \kwd{overflow}, \kwd{inexact}, \kwd{invalid} and + \kwd{divide-by-zero}. Initially all traps except \kwd{inexact} + are enabled. \xlref{float-traps}. + + \item[\kwd{rounding-mode}] The rounding mode to use when the result + is not exact. Possible values are \kwd{nearest}, + \kwd{positive-infinity}, \kwd{negative-infinity} and \kwd{zero}. + Initially, the rounding mode is \kwd{nearest}. See the warning in + section \ref{float-rounding-modes} about use of other rounding + modes. + + \item[\kwd{current-exceptions}, \kwd{accrued-exceptions}] Lists of + exception keywords used to set the exception flags. The + \var{current-exceptions} are the exceptions for the previous + operation, so setting it is not very useful. The + \var{accrued-exceptions} are a cumulative record of the exceptions + that occurred since the last time these flags were cleared. + Specifying \code{()} will clear any accrued exceptions. + + \item[\kwd{fast-mode}] Set the hardware's ``fast mode'' flag, if + any. When set, IEEE conformance or debuggability may be impaired. + Some machines may not have this feature, in which case the value + is always \false. Sparc platforms support a fast mode where + denormal numbers are silently truncated to zero. + \end{Lentry} + If a keyword argument is not supplied, then the associated state is + not changed. + + \code{get-floating-point-modes} returns a list representing the + state of the floating point modes. The list is in the same format + as the keyword arguments to \code{set-floating-point-modes}, so + \code{apply} could be used with \code{set-floating-point-modes} to + restore the modes in effect at the time of the call to + \code{get-floating-point-modes}. +\end{defun} + +To make handling control of floating-point exceptions, the following +macro is useful. + +\begin{defmac}{ext:}{with-float-traps-masked}{\var{traps} \ampbody\ \var{body}} + \code{body} is executed with the selected floating-point exceptions + given by \code{traps} masked out (disabled). \code{traps} should be + a list of possible floating-point exceptions that should be ignored. + Possible values are \kwd{underflow}, \kwd{overflow}, \kwd{inexact}, + \kwd{invalid} and \kwd{divide-by-zero}. + + This is equivalent to saving the current traps from + \code{get-floating-point-modes}, setting the floating-point modes to + the desired exceptions, running the \code{body}, and restoring the + saved floating-point modes. The advantage of this macro is that it + causes less consing to occur. + + Some points about the with-float-traps-masked: + + \begin{itemize} + \item Two approaches are available for detecting FP exceptions: + \begin{enumerate} + \item enabling the traps and handling the exceptions + \item disabling the traps and either handling the return values or + checking the accrued exceptions. + \end{enumerate} + Of these the latter is the most portable because on the alpha port + it is not possible to enable some traps at run-time. + + \item To assist the checking of the exceptions within the body any + accrued exceptions matching the given traps are cleared at the + start of the body when the traps are masked. + + \item To allow the macros to be nested these accrued exceptions are + restored at the end of the body to their values at the start of + the body. Thus any exceptions that occurred within the body will + not affect the accrued exceptions outside the macro. + + \item Note that only the given exceptions are restored at the end of + the body so other exception will be visible in the accrued + exceptions outside the body. + + \item On the x86, setting the accrued exceptions of an unmasked + exception would cause a FP trap. The macro behaviour of restoring + the accrued exceptions ensures than if an accrued exception is + initially not flagged and occurs within the body it will be + restored/cleared at the exit of the body and thus not cause a + trap. + + \item On the x86, and, perhaps, the hppa, the FP exceptions may be + delivered at the next FP instruction which requires a FP + \code{wait} instruction (\code{x86::float-wait}) if using the lisp + conditions to catch trap within a \code{handler-bind}. The + \code{handler-bind} macro does the right thing and inserts a + float-wait (at the end of its body on the x86). The masking and + noting of exceptions is also safe here. + + \item The setting of the FP flags uses the + \code{(floating-point-modes)} and the \code{(set + (floating-point-modes)\ldots)} VOPs. These VOPs blindly update + the flags which may include other state. We assume this state + hasn't changed in between getting and setting the state. For + example, if you used the FP unit between the above calls, the + state may be incorrectly restored! The + \code{with-float-traps-masked} macro keeps the intervening code to + a minimum and uses only integer operations. + %% Safe byte-compiled? + %% Perhaps the VOPs (x86) should be smarter and only update some of + %% the flags, the trap masks and exceptions? + \end{itemize} + +\end{defmac} + +\subsection{Extended Floats} +\label{extended-float} + +\cmucl{} also has an extension to support \code{double-double-float} +type. This float format provides extended precision of about 31 +decimal digits, with the same exponent range as \code{double-float}. +It is completely integrated into \cmucl{}, and can be used just like +any other floating-point object, including arrays, complex +\code{double-double-float}'s, and special functions. With appropriate +declarations, no boxing is needed, just like \code{single-float} and +\code{double-float}. + +The exponent marker for a double-double float number is ``W'', so +``1.234w0'' is a double-double float number. + + +Note that there are a few shortcomings with +\code{double-double-float}'s: +\begin{itemize} + \item There are no equivalents to \code{most-positive-double-float}, + \code{double-float-positive-infinity}, \textit{etc}. This is because + these are not really well defined for \code{double-double-float}'s. + \item Underflow and overflow may be prematurely signaled. This is + due to how \code{double-double-float}'s are implemented. + \item Basic arithmetic operations are inlined, so the code size is + fairly large. + \item \code{double-double-float} arithmetic is quite a bit slower + than \code{double-float} since there is no hardware support for + this type. + \item The constant \code{pi} is still a \code{double-float} instead + of a \code{double-double-float}. Use \code{ext:dd-pi} if you + want a \code{double-double-float} value for $\pi$. +\end{itemize} + +\begin{deftp}{float}{extensions:double-double-float}{} + The \code{double-double-float} type. It is in the \code{EXTENSIONS} + package. +\end{deftp} + +\begin{defconst}{extensions:}{dd-pi} + A \code{double-double-float} approximation to $\pi$. +\end{defconst} + +\subsection{Characters} + +\cmucl{} implements characters according to \cltltwo{}. The +main difference from the first version is that character bits and font +have been eliminated, and the names of the types have been changed. +\tindexed{base-character} is the new equivalent of the old +\tindexed{string-char}. In this implementation, all characters are +base characters (there are no extended characters.) Character codes +range between \code{0} and \code{255}, using the ASCII encoding. +Table~\ref{tbl:chars}~\vpageref{tbl:chars} shows characters recognized +by \cmucl. + +\begin{table}[tbhp] + \begin{center} + \begin{tabular}{|c|c|l|l|l|l|} + \hline + \multicolumn{2}{|c|}{ASCII} & \multicolumn{1}{|c}{Lisp} & + \multicolumn{3}{|c|}{} \\ + \cline{1-2} + Name & Code & \multicolumn{1}{|c|}{Name} & \multicolumn{3}{|c|}{\raisebox{1.5ex}{Alternatives}}\\ + \hline + \hline + \code{nul} & 0 & \code{\#\back{NULL}} & \code{\#\back{NUL}} & &\\ + \code{bel} & 7 & \code{\#\back{BELL}} & & &\\ + \code{bs} & 8 & \code{\#\back{BACKSPACE}} & \code{\#\back{BS}} & &\\ + \code{tab} & 9 & \code{\#\back{TAB}} & & &\\ + \code{lf} & 10 & \code{\#\back{NEWLINE}} & \code{\#\back{NL}} & \code{\#\back{LINEFEED}} & \code{\#\back{LF}}\\ + \code{ff} & 11 & \code{\#\back{VT}} & \code{\#\back{PAGE}} & \code{\#\back{FORM}} &\\ + \code{cr} & 13 & \code{\#\back{RETURN}} & \code{\#\back{CR}} & &\\ + \code{esc} & 27 & \code{\#\back{ESCAPE}} & \code{\#\back{ESC}} & \code{\#\back{ALTMODE}} & \code{\#\back{ALT}}\\ + \code{sp} & 32 & \code{\#\back{SPACE}} & \code{\#\back{SP}} & &\\ + \code{del} & 127 & \code{\#\back{DELETE}} & \code{\#\back{RUBOUT}} & &\\ + \hline + \end{tabular} + \caption{Characters recognized by \cmucl} + \label{tbl:chars} + \end{center} +\end{table} + + +\subsection{Array Initialization} + +If no \kwd{initial-value} is specified, arrays are initialized to zero. + + +\subsection{Hash tables} + +The \tindexed{hash-tables} defined by \clisp{} have limited utility because they +are limited to testing their keys using the equality predicates +provided by (pre-CLOS) \clisp{}. \cmucl{} overcomes this limitation +by allowing its users to specify new hash table tests and hashing +methods. The hashing method must also be specified, since the +compiler is unable to determine a good hashing function for an +arbitrary equality (equivalence) predicate. + +\begin{defun}{extensions:}{define-hash-table-test}% + {\args{\var{hash-table-test-name} \var{test-function} \var{hash-function}}} + + The \var{hash-table-test-name} must be a symbol. + % I just assumed the above. [2002/10/10:rpg] + The \var{test-function} takes two objects and returns true + iff they are the same. The \var{hash-function} takes one object and + returns two values: the (positive fixnum) hash value and true if + the hashing depends on pointer values and will have to be redone + if the object moves. + + To create a hash-table using this new ``test'' (really, a + test/hash-function pair), use + \code{(\index[funs]{make-hash-table}make-hash-table :test + \var{hash-table-test-name} \ldots)}. + + Note that it is the \var{hash-table-test-name} that will be + returned by the function \findexed{hash-table-test}, when applied to + a hash-table created using this function. + + This function updates \vindexed{hash-table-tests}, which is now + internal. +\end{defun} + +\cmucl{} also supports a number of weak hash tables. These weak +tables are created using the \kwd{weak-p} argument to +\code{make-hash-table}. Normally, a reference to an object as either +the key or value of the hash-table will prevent that object from being +garbage-collected. However, in a weak table, if the only reference is +the hash-table, the object can be collected. + +The possible values for \kwd{weak-p} are listed below. An entry in +the table remains if the condition holds +\begin{Lentry} +\item[\kwd{key}] The key is referenced elsewhere +\item[\kwd{value}] The value is referenced elsewhere +\item[\kwd{key-and-value}] Both the key and value are referenced elsewhere +\item[\kwd{key-or-value}] Either the key or value are referenced elsewhere +\item[T] For backward compatibility, this means the same as \kwd{key}. +\end{Lentry} +If the condition does not hold, the object can be removed from the +hash table. + +Weak hash tables can only be created if the test is \code{eq} or +\code{eql}. An error is signaled if this is not the case. + +\begin{defun}{}{make-hash-table}% + {\args{\keys{\kwd{test} \kwd{size} \kwd{rehash-size} \kwd{rehash-threshold} \kwd{weak-p}}}} + Creates a hash-table with the specified properties. +\end{defun} +\section{Default Interrupts for Lisp} + +\cmucl{} has several interrupt handlers defined when it starts up, +as follows: +\begin{Lentry} + +\item[\code{SIGINT} (\ctrl{c})] causes Lisp to enter a break loop. + This puts you into the debugger which allows you to look at the + current state of the computation. If you proceed from the break + loop, the computation will proceed from where it was interrupted. + +\item[\code{SIGQUIT} (\ctrl{L})] causes Lisp to do a throw to the + top-level. This causes the current computation to be aborted, and + control returned to the top-level read-eval-print loop. + +\item[\code{SIGTSTP} (\ctrl{z})] causes Lisp to suspend execution and + return to the Unix shell. If control is returned to Lisp, the + computation will proceed from where it was interrupted. + +\item[\code{SIGILL}, \code{SIGBUS}, \code{SIGSEGV}, and \code{SIGFPE}] + cause Lisp to signal an error. +\end{Lentry} +For keyboard interrupt signals, the standard interrupt character is in +parentheses. Your \file{.login} may set up different interrupt +characters. When a signal is generated, there may be some delay before +it is processed since Lisp cannot be interrupted safely in an arbitrary +place. The computation will continue until a safe point is reached and +then the interrupt will be processed. \xlref{signal-handlers} to define +your own signal handlers. + + +\section{Implementation-Specific Packages} + +When \cmucl{} is first started up, the default package is the +\code{common-lisp-user} package. The \code{common-lisp-user} package +uses the \code{common-lisp} and \code{extensions} packages. The +symbols exported from these three packages can be referenced without +package qualifiers. This section describes packages which have +exported interfaces that may concern users. The numerous internal +packages which implement parts of the system are not described here. +Package nicknames are in parenthesis after the full name. + +\begin{Lentry} +\item[\code{alien}, \code{c-call}] Export the features of the Alien + foreign data structure facility (\pxlref{aliens}.) + +\item[\code{pcl}] This package contains PCL (Portable CommonLoops), + which is a portable implementation of CLOS (the Common Lisp Object + System.) This implements most (but not all) of the features in the + CLOS chapter of \cltltwo{}. + +\item[\code{clos-mop (mop)}] This package contains an implementation + of the CLOS Metaobject Protocol, as per the book \textit{The Art of + the Metaobject Protocol}. + +\item[\code{debug}] The \code{debug} package contains the command-line + oriented debugger. It exports utility various functions and + switches. + +\item[\code{debug-internals}] The \code{debug-internals} package + exports the primitives used to write debuggers. + \xlref{debug-internals}. + +\item[\code{extensions (ext)}] The \code{extensions} packages exports + local extensions to \clisp{} that are documented in this manual. + Examples include the \code{save-lisp} function and time parsing. + +\item[\code{hemlock (ed)}] The \code{hemlock} package contains all the + code to implement Hemlock commands. The \code{hemlock} package + currently exports no symbols. + +\item[\code{hemlock-internals (hi)}] The \code{hemlock-internals} + package contains code that implements low level primitives and + exports those symbols used to write Hemlock commands. + +\item[\code{keyword}] The \code{keyword} package contains keywords + (e.g., \kwd{start}). All symbols in the \code{keyword} package are + exported and evaluate to themselves (i.e., the value of the symbol + is the symbol itself). + +\item[\code{profile}] The \code{profile} package exports a simple + run-time profiling facility (\pxlref{profiling}). + +\item[\code{common-lisp (cl)}] The \code{common-lisp} package + exports all the symbols defined by \cltl{} and only those symbols. + Strictly portable Lisp code will depend only on the symbols exported + from the \code{common-lisp} package. + +\item[\code{unix}] This package exports system call + interfaces to Unix (\pxlref{unix-interface}). + +\item[\code{system (sys)}] The \code{system} package contains + functions and information necessary for system interfacing. This + package is used by the \code{lisp} package and exports several + symbols that are necessary to interface to system code. + +\item[\code{xlib}] The \code{xlib} package contains the Common Lisp X + interface (CLX) to the X11 protocol. This is mostly Lisp code with + a couple of functions that are defined in C to connect to the + server. + +\item[\code{wire}] The \code{wire} package exports a remote procedure + call facility (\pxlref{remote}). + +\item[\code{stream}] The \code{stream} package exports the public + interface to the simple-streams implementation (\pxlref{simple-streams}). + +\item[\code{xref}] The \code{xref} package exports the public + interface to the cross-referencing utility (\pxlref{xref}). + +\end{Lentry} + + +\input{hierarchical-packages} + +\input{package-locks} + + + +\section{The Editor} + +The \code{ed} function invokes the Hemlock editor which is described +in {\it Hemlock User's Manual} and {\it Hemlock Command Implementor's +Manual}. Most users at CMU prefer to use Hemlock's slave \llisp{} +mechanism which provides an interactive buffer for the +\code{read-eval-print} loop and editor commands for evaluating and +compiling text from a buffer into the slave \llisp. Since the editor +runs in the \llisp, using slaves keeps users from trashing their +editor by developing in the same \llisp{} with \hemlock{}. + + +\section{Garbage Collection} + +\cmucl{} uses either a stop-and-copy garbage collector or a +generational, mostly copying garbage collector. Which collector is +available depends on the platform and the features of the platform. +The stop-and-copy GC is available on all RISC platforms. The x86 +platform supports a conservative stop-and-copy collector, which is now +rarely used, and a generational conservative collector. On the Sparc +platform, both the stop-and-copy GC and the generational GC are +available, but the stop-and-copy GC is deprecated in favor of the +generational GC. + +The generational GC is available if \var{*features*} contains +\code{:gencgc}. + +%% The stop-and-copy GC compacts the items in dynamic space every time it +%% runs. Most users cause the system to garbage collect (GC) frequently, +%% long before space is exhausted. With 16 or 24 megabytes of memory, +%% causing GC's more frequently on less garbage allows the system to GC +%% without much (if any) paging. + +The following functions invoke the garbage collector or control whether +automatic garbage collection is in effect: + +\begin{defun}[-cheney]{extensions:}{gc}{\args{\ampoptional{} \var{verbose-p}}} + + This function runs the garbage collector. If + \code{ext:*gc-verbose*} is non-\nil, then it invokes + \code{ext:*gc-notify-before*} before GC'ing and + \code{ext:*gc-notify-after*} afterwards. + + \code{verbose-p} indicates whether GC statistics are printed or + not. + +\end{defun} + +\begin{defun}{extensions:}{gc-off}{} + + This function inhibits automatic garbage collection. After calling + it, the system will not GC unless you call \code{ext:gc} or + \code{ext:gc-on}. +\end{defun} + +\begin{defun}{extensions:}{gc-on}{} + + This function reinstates automatic garbage collection. If the + system would have GC'ed while automatic GC was inhibited, then this + will call \code{ext:gc}. +\end{defun} + +\subsection{GC Parameters} + +The following variables control the behavior of the garbage collector: + +\begin{defvar}{extensions:}{bytes-consed-between-gcs} + + \cmucl{} automatically GC's whenever the amount of memory + allocated to dynamic objects exceeds the value of an internal + variable. After each GC, the system sets this internal variable to + the amount of dynamic space in use at that point plus the value of + the variable \code{ext:*bytes-consed-between-gcs*}. The default + value is 2000000. +\end{defvar} + +\begin{defvar}{extensions:}{gc-verbose} + + This variable controls whether \code{ext:gc} invokes the functions + in \code{ext:*gc-notify-before*} and + \code{ext:*gc-notify-after*}. If \code{*gc-verbose*} is \nil, + \code{ext:gc} foregoes printing any messages. The default value is + \code{T}. +\end{defvar} + +\begin{defvar}{extensions:}{gc-notify-before} + + This variable's value is a function that should notify the user that + the system is about to GC. It takes one argument, the amount of + dynamic space in use before the GC measured in bytes. The default + value of this variable is a function that prints a message similar + to the following: +\begin{verbatim} + [GC threshold exceeded with 2,107,124 bytes in use. Commencing GC.] +\end{verbatim} +\end{defvar} + +\begin{defvar}{extensions:}{gc-notify-after} + + This variable's value is a function that should notify the user when + a GC finishes. The function must take three arguments, the amount + of dynamic spaced retained by the GC, the amount of dynamic space + freed, and the new threshold which is the minimum amount of space in + use before the next GC will occur. All values are byte quantities. + The default value of this variable is a function that prints a + message similar to the following: + \begin{verbatim} + [GC completed with 25,680 bytes retained and 2,096,808 bytes freed.] + [GC will next occur when at least 2,025,680 bytes are in use.] + \end{verbatim} +\end{defvar} + +Note that a garbage collection will not happen at exactly the new +threshold printed by the default \code{ext:*gc-notify-after*} +function. The system periodically checks whether this threshold has +been exceeded, and only then does a garbage collection. + +\begin{defvar}{extensions:}{gc-inhibit-hook} + + This variable's value is either a function of one argument or \nil. + When the system has triggered an automatic GC, if this variable is a + function, then the system calls the function with the amount of + dynamic space currently in use (measured in bytes). If the function + returns \nil, then the GC occurs; otherwise, the system inhibits + automatic GC as if you had called \code{ext:gc-off}. The writer of + this hook is responsible for knowing when automatic GC has been + turned off and for calling or providing a way to call + \code{ext:gc-on}. The default value of this variable is \nil. +\end{defvar} + +\begin{defvar}{extensions:}{before-gc-hooks} + \defvarx[extensions:]{after-gc-hooks} + + These variables' values are lists of functions to call before or + after any GC occurs. The system provides these purely for + side-effect, and the functions take no arguments. +\end{defvar} + +\subsection{Generational GC} +Generational GC also supports some additional functions and variables +to control it. + +\begin{defun}[-gencgc]{extensions:}{gc}{\args{\keys{\kwd{verbose} \kwd{gen} \kwd{full}}}} + + This function runs the garbage collector. If + \code{ext:*gc-verbose*} is non-\nil, then it invokes + \code{ext:*gc-notify-before*} before GC'ing and + \code{ext:*gc-notify-after*} afterwards. + + \begin{Lentry} + \item[\code{verbose}] Print GC statistics if non-\code{NIL}. + \item[\code{gen}] The number of generations to be collected. + \item[\code{full}] If non-\code{NIL}, a full collection of all + generations is performed. + \end{Lentry} +\end{defun} + +\begin{defun}{lisp::}{gencgc-stats}{\args{\var{generation}}} + Returns statistics about the generation, as multiple values: + \begin{enumerate} + \item Bytes allocated in this generation + \item The GC trigger for this generation. When this many bytes have + been allocated, a GC is started automatically. + \item The number of bytes consed between GCs. + \item The number of GCs that have been done on this generation. + This is reset to zero when the generation is raised. + \item The trigger age, which is the maximum number of GCs to perform + before this generation is raised. + \item The total number of bytes allocated to this generation. + \item Average age of the objects in this generations. The average + age is the cumulative bytes allocated divided by current number of + bytes allocated. + \end{enumerate} +\end{defun} + +\begin{defun}{lisp::}{set-gc-trigger}{\args{\var{gen} \var{trigger}}} + Sets the GC trigger value for the specified generation. +\end{defun} + +\begin{defun}{lisp::}{set-trigger-age}{\args{\var{gen} \var{trigger-age}}} + Sets the GC trigger age for the specified generation. +\end{defun} + +\begin{defun}{lisp::}{set-min-mem-age}{\args{\var{gen} \var{min-mem-age}}} + Sets the minimum average memory age for the specified generation. + If the computed memory age is below this, GC is not performed, which + helps prevent a GC when a large number of new live objects have been + added in which case a GC would usually be a waste of time. +\end{defun} + +\subsection{Weak Pointers} + +A weak pointer provides a way to maintain a reference to an object +without preventing an object from being garbage collected. If the +garbage collector discovers that the only pointers to an object are +weak pointers, then it breaks the weak pointers and deallocates the +object. + +\begin{defun}{extensions:}{make-weak-pointer}{\args{\var{object}}} + \defunx[extensions:]{weak-pointer-value}{\args{\var{weak-pointer}}} + + \code{make-weak-pointer} returns a weak pointer to an object. + \code{weak-pointer-value} follows a weak pointer, returning the two + values: the object pointed to (or \false{} if broken) and a boolean + value which is \false{} if the pointer has been broken, and true + otherwise. +\end{defun} + + +\subsection{Finalization} + +Finalization provides a ``hook'' that is triggered when the garbage +collector reclaims an object. It is usually used to recover non-Lisp +resources that were allocated to implement the finalized Lisp object. +For example, when a unix file-descriptor stream is collected, +finalization is used to close the underlying file descriptor. + +\begin{defun}{extensions:}{finalize}{\args{\var{object} \var{function}}} + + This function registers \var{object} for finalization. + \var{function} is called with no arguments when \var{object} is + reclaimed. Normally \var{function} will be a closure over the + underlying state that needs to be freed, e.g. the unix file + descriptor in the fd-stream case. Note that \var{function} must not + close over \var{object} itself, as this prevents the object from + ever becoming garbage. +\end{defun} + +\begin{defun}{extensions:}{cancel-finalization}{\args{\var{object}}} + + This function cancel any finalization request for \var{object}. +\end{defun} + + +\section{Describe} + +\begin{defun}{}{describe}{ \args{\var{object} \ampoptional{} \var{stream}}} + + The \code{describe} function prints useful information about + \var{object} on \var{stream}, which defaults to + \code{*standard-output*}. For any object, \code{describe} will + print out the type. Then it prints other information based on the + type of \var{object}. The types which are presently handled are: + + \begin{Lentry} + + \item[\tindexed{hash-table}] \code{describe} prints the number of + entries currently in the hash table and the number of buckets + currently allocated. + + \item[\tindexed{function}] \code{describe} prints a list of the + function's name (if any) and its formal parameters. If the name + has function documentation, then it will be printed. If the + function is compiled, then the file where it is defined will be + printed as well. + + \item[\tindexed{fixnum}] \code{describe} prints whether the integer + is prime or not. + + \item[\tindexed{symbol}] The symbol's value, properties, and + documentation are printed. If the symbol has a function + definition, then the function is described. + \end{Lentry} + If there is anything interesting to be said about some component of + the object, describe will invoke itself recursively to describe that + object. The level of recursion is indicated by indenting output. +\end{defun} + +A number of switches can be used to control \code{describe}'s behavior. + +\begin{defvar}{extensions:}{describe-level} + + The maximum level of recursive description allowed. Initially two. +\end{defvar} + +\begin{defvar}{extensions:}{describe-indentation} + +The number of spaces to indent for each level of recursive +description, initially three. +\end{defvar} + +\begin{defvar}{extensions:}{describe-print-level} + \defvarx[extensions:]{describe-print-length} + + The values of \code{*print-level*} and \code{*print-length*} during + description. Initially two and five. +\end{defvar} + + +\section{The Inspector} + +\cmucl{} has both a graphical inspector that uses the X Window System, +and a simple terminal-based inspector. + +\begin{defun}{}{inspect}{ \args{\ampoptional{} \var{object}}} + + \code{inspect} calls the inspector on the optional argument + \var{object}. If \var{object} is unsupplied, \code{inspect} + immediately returns \false. Otherwise, the behavior of inspect + depends on whether Lisp is running under X. When \code{inspect} is + eventually exited, it returns some selected Lisp object. +\end{defun} + + +\subsection{The Graphical Interface} +\label{motif-interface} + +\cmucl{} has an interface to Motif which is functionally similar to +CLM, but works better in \cmucl{}. This interface is documented in +separate manuals \textit{CMUCL Motif Toolkit} and \textit{Design Notes +on the Motif Toolkit}, which are distributed with \cmucl{}. + +This motif interface has been used to write the inspector and graphical +debugger. There is also a Lisp control panel with a simple file management +facility, apropos and inspector dialogs, and controls for setting global +options. See the \code{interface} and \code{toolkit} packages. + +\begin{defun}{interface:}{lisp-control-panel}{} + + This function creates a control panel for the Lisp process. +\end{defun} + +\begin{defvar}{interface:}{interface-style} + + When the graphical interface is loaded, this variable controls + whether it is used by \code{inspect} and the error system. If the + value is \kwd{graphics} (the default) and the \code{DISPLAY} + environment variable is defined, the graphical inspector and + debugger will be invoked by \findexed{inspect} or when an error is + signalled. Possible values are \kwd{graphics} and {tty}. If the + value is \kwd{graphics}, but there is no X display, then we quietly + use the TTY interface. +\end{defvar} + + +\subsection{The TTY Inspector} + +If X is unavailable, a terminal inspector is invoked. The TTY inspector +is a crude interface to \code{describe} which allows objects to be +traversed and maintains a history. This inspector prints information +about and object and a numbered list of the components of the object. +The command-line based interface is a normal +\code{read}--\code{eval}--\code{print} loop, but an integer \var{n} +descends into the \var{n}'th component of the current object, and +symbols with these special names are interpreted as commands: + +\begin{Lentry} +\item[U] Move back to the enclosing object. As you descend into the +components of an object, a stack of all the objects previously seen is +kept. This command pops you up one level of this stack. + +\item[Q, E] Return the current object from \code{inspect}. + +\item[R] Recompute object display, and print again. Useful if the +object may have changed. + +\item[D] Display again without recomputing. + +\item[H, ?] Show help message. +\end{Lentry} + + +\section{Load} + +\begin{defun}{}{load}{% + \args{\var{filename} + \keys{\kwd{verbose} \kwd{print} \kwd{if-does-not-exist}} + \morekeys{\kwd{if-source-newer} \kwd{contents}}}} + + As in standard \clisp{}, this function loads a file containing + source or object code into the running Lisp. Several CMU extensions + have been made to \code{load} to conveniently support a variety of + program file organizations. \var{filename} may be a wildcard + pathname such as \file{*.lisp}, in which case all matching files are + loaded. + + If \var{filename} has a \code{pathname-type} (or extension), then + that exact file is loaded. If the file has no extension, then this + tells \code{load} to use a heuristic to load the ``right'' file. + The \code{*load-source-types*} and \code{*load-object-types*} + variables below are used to determine the default source and object + file types. If only the source or the object file exists (but not + both), then that file is quietly loaded. Similarly, if both the + source and object file exist, and the object file is newer than the + source file, then the object file is loaded. The value of the + \var{if-source-newer} argument is used to determine what action to + take when both the source and object files exist, but the object + file is out of date: + \begin{Lentry} + \item[\kwd{load-object}] The object file is loaded even though the + source file is newer. + + \item[\kwd{load-source}] The source file is loaded instead of the + older object file. + + \item[\kwd{compile}] The source file is compiled and then the new + object file is loaded. + + \item[\kwd{query}] The user is asked a yes or no question to + determine whether the source or object file is loaded. + \end{Lentry} + This argument defaults to the value of + \code{ext:*load-if-source-newer*} (initially \kwd{load-object}.) + + The \var{contents} argument can be used to override the heuristic + (based on the file extension) that normally determines whether to + load the file as a source file or an object file. If non-null, this + argument must be either \kwd{source} or \kwd{binary}, which forces + loading in source and binary mode, respectively. You really + shouldn't ever need to use this argument. +\end{defun} + +\begin{defvar}{extensions:}{load-source-types} + \defvarx[extensions:]{load-object-types} + + These variables are lists of possible \code{pathname-type} values + for source and object files to be passed to \code{load}. These + variables are only used when the file passed to \code{load} has no + type; in this case, the possible source and object types are used to + default the type in order to determine the names of the source and + object files. +\end{defvar} + +\begin{defvar}{extensions:}{load-if-source-newer} + + This variable determines the default value of the + \var{if-source-newer} argument to \code{load}. Its initial value is + \kwd{load-object}. +\end{defvar} + + +\section{The Reader} + +\subsection{Reader Extensions} +\cmucl{} supports an ANSI-compatible extension to enable reading of +specialized arrays. Thus +\begin{example} + * (setf *print-readably* nil) + NIL + * (make-array '(2 2) :element-type '(signed-byte 8)) + #2A((0 0) (0 0)) + * (setf *print-readably* t) + T + * (make-array '(2 2) :element-type '(signed-byte 8)) + #A((SIGNED-BYTE 8) (2 2) ((0 0) (0 0))) + * (type-of (read-from-string "#A((SIGNED-BYTE 8) (2 2) ((0 0) (0 0)))")) + (SIMPLE-ARRAY (SIGNED-BYTE 8) (2 2)) + * (setf *print-readably* nil) + NIL + * (type-of (read-from-string "#A((SIGNED-BYTE 8) (2 2) ((0 0) (0 0)))")) + (SIMPLE-ARRAY (SIGNED-BYTE 8) (2 2)) +\end{example} + +\subsection{Reader Parameters} +\begin{defvar}{extensions:}{ignore-extra-close-parentheses} + + If this variable is \true{} (the default), then the reader merely + prints a warning when an extra close parenthesis is detected + (instead of signalling an error.) +\end{defvar} + +\section{Stream Extensions} +\begin{defun}{sys:}{read-n-bytes}{% + \args{\var{stream buffer start numbytes} + \ampoptional{} \var{eof-error-p}}} + + On streams that support it, this function reads multiple bytes of + data into a buffer. The buffer must be a \code{simple-string} or + \code{(simple-array (unsigned-byte 8) (*))}. The argument + \var{nbytes} specifies the desired number of bytes, and the return + value is the number of bytes actually read. + \begin{itemize} + \item If \var{eof-error-p} is true, an \tindexed{end-of-file} + condition is signalled if end-of-file is encountered before + \var{count} bytes have been read. + + \item If \var{eof-error-p} is false, \code{read-n-bytes reads} as + much data is currently available (up to count bytes.) On pipes or + similar devices, this function returns as soon as any data is + available, even if the amount read is less than \var{count} and + eof has not been hit. See also \funref{make-fd-stream}. + \end{itemize} +\end{defun} + +\input{simple-streams} + +\section{Running Programs from Lisp} + +It is possible to run programs from Lisp by using the following function. + +\begin{defun}{extensions:}{run-program}{% + \args{\var{program} \var{args} + \keys{\kwd{env} \kwd{wait} \kwd{pty} \kwd{input}} + \morekeys{\kwd{if-input-does-not-exist}} + \yetmorekeys{\kwd{output} \kwd{if-output-exists}} + \yetmorekeys{\kwd{error} \kwd{if-error-exists}} + \yetmorekeys{\kwd{status-hook} \kwd{external-format}} + \yetmorekeys{\kwd{element-type}}}} + + \code{run-program} runs \var{program} in a child process. + \var{Program} should be a pathname or string naming the program. + \var{Args} should be a list of strings which this passes to + \var{program} as normal Unix parameters. For no arguments, specify + \var{args} as \nil. The value returned is either a process + structure or \nil. The process interface follows the description of + \code{run-program}. If \code{run-program} fails to fork the child + process, it returns \nil. + + Except for sharing file descriptors as explained in keyword argument + descriptions, \code{run-program} closes all file descriptors in the + child process before running the program. When you are done using a + process, call \code{process-close} to reclaim system resources. You + only need to do this when you supply \kwd{stream} for one of + \kwd{input}, \kwd{output}, or \kwd{error}, or you supply \kwd{pty} + non-\nil. You can call \code{process-close} regardless of whether + you must to reclaim resources without penalty if you feel safer. + + \code{run-program} accepts the following keyword arguments: + + \begin{Lentry} + \item[\kwd{env}] This is an a-list mapping keywords and + simple-strings. The default is \code{ext:*environment-list*}. If + \kwd{env} is specified, \code{run-program} uses the value given + and does not combine the environment passed to Lisp with the one + specified. + + \item[\kwd{wait}] If non-\nil{} (the default), wait until the child + process terminates. If \nil, continue running Lisp while the + child process runs. + + \item[\kwd{pty}] This should be one of \true, \nil, or a stream. If + specified non-\nil, the subprocess executes under a Unix PTY. + If specified as a stream, the system collects all output to this + pty and writes it to this stream. If specified as \true, the + \code{process-pty} slot contains a stream from which you can read + the program's output and to which you can write input for the + program. The default is \nil. + + \item[\kwd{input}] This specifies how the program gets its input. + If specified as a string, it is the name of a file that contains + input for the child process. \code{run-program} opens the file as + standard input. If specified as \nil{} (the default), then + standard input is the file \file{/dev/null}. If specified as + \true, the program uses the current standard input. This may + cause some confusion if \kwd{wait} is \nil{} since two processes + may use the terminal at the same time. If specified as + \kwd{stream}, then the \code{process-input} slot contains an + output stream. Anything written to this stream goes to the + program as input. \kwd{input} may also be an input stream that + already contains all the input for the process. In this case + \code{run-program} reads all the input from this stream before + returning, so this cannot be used to interact with the process. + If \kwd{input} is a string stream, it is up to the caller to call + \code{string-encode} or other function to convert the string to + the appropriate encoding. In either case, the least significant 8 + bits of the \code{char-code} of each \code{character} is + sent to the program. + + \item[\kwd{if-input-does-not-exist}] This specifies what to do if + the input file does not exist. The following values are valid: + \nil{} (the default) causes \code{run-program} to return \nil{} + without doing anything; \kwd{create} creates the named file; and + \kwd{error} signals an error. + + \item[\kwd{output}] This specifies what happens with the program's + output. If specified as a pathname, it is the name of a file that + contains output the program writes to its standard output. If + specified as \nil{} (the default), all output goes to + \file{/dev/null}. If specified as \true, the program writes to + the Lisp process's standard output. This may cause confusion if + \kwd{wait} is \nil{} since two processes may write to the terminal + at the same time. If specified as \kwd{stream}, then the + \code{process-output} slot contains an input stream from which you + can read the program's output. \kwd{output} can also be a stream + in which case all output from the process is written to this + stream. If \kwd{output} is a string-stream, each octet read from + the program is converted to a character using \code{code-char}. + It is up to the caller to convert this using the appropriate + external format to create the desired encoded string. + + \item[\kwd{if-output-exists}] This specifies what to do if the + output file already exists. The following values are valid: + \nil{} causes \code{run-program} to return \nil{} without doing + anything; \kwd{error} (the default) signals an error; + \kwd{supersede} overwrites the current file; and \kwd{append} + appends all output to the file. + + \item[\kwd{error}] This is similar to \kwd{output}, except the file + becomes the program's standard error. Additionally, \kwd{error} + can be \kwd{output} in which case the program's error output is + routed to the same place specified for \kwd{output}. If specified + as \kwd{stream}, the \code{process-error} contains a stream + similar to the \code{process-output} slot when specifying the + \kwd{output} argument. + + \item[\kwd{if-error-exists}] This specifies what to do if the error + output file already exists. It accepts the same values as + \kwd{if-output-exists}. + + \item[\kwd{status-hook}] This specifies a function to call whenever + the process changes status. This is especially useful when + specifying \kwd{wait} as \nil. The function takes the process as + a required argument. + + \item[\kwd{external-format}] This specifies the external format to + use for streams created for \code{run-program}. This does not + apply to string streams passed in as \kwd{input} or \kwd{output} + parameters. + + \item[\kwd{element-type}] If streams are created \code{run-program}, + use this as the \kwd{element-type} for the stream. Defaults to + \code{BASE-CHAR}. + +% \item[\kwd{before-execve}] This specifies a function to run in the +% child process before it becomes the program to run. This is +% useful for actions such as authenticating the child process +% without modifying the parent Lisp process. + \end{Lentry} +\end{defun} + + +\subsection{Process Accessors} + +The following functions interface the process returned by \code{run-program}: + +\begin{defun}{extensions:}{process-p}{\args{\var{thing}}} + + This function returns \true{} if \var{thing} is a process. + Otherwise it returns \nil{} +\end{defun} + +\begin{defun}{extensions:}{process-pid}{\args{\var{process}}} + + This function returns the process ID, an integer, for the + \var{process}. +\end{defun} + +\begin{defun}{extensions:}{process-status}{\args{\var{process}}} + + This function returns the current status of \var{process}, which is + one of \kwd{running}, \kwd{stopped}, \kwd{exited}, or + \kwd{signaled}. +\end{defun} + +\begin{defun}{extensions:}{process-exit-code}{\args{\var{process}}} + + This function returns either the exit code for \var{process}, if it + is \kwd{exited}, or the termination signal \var{process} if it is + \kwd{signaled}. The result is undefined for processes that are + still alive. +\end{defun} + +\begin{defun}{extensions:}{process-core-dumped}{\args{\var{process}}} + + This function returns \true{} if someone used a Unix signal to + terminate the \var{process} and caused it to dump a Unix core image. +\end{defun} + +\begin{defun}{extensions:}{process-pty}{\args{\var{process}}} + + This function returns either the two-way stream connected to + \var{process}'s Unix PTY connection or \nil{} if there is none. +\end{defun} + +\begin{defun}{extensions:}{process-input}{\args{\var{process}}} + \defunx[extensions:]{process-output}{\args{\var{process}}} + \defunx[extensions:]{process-error}{\args{\var{process}}} + + If the corresponding stream was created, these functions return the + input, output or error fd-stream. \nil{} is returned if there + is no stream. +\end{defun} + +\begin{defun}{extensions:}{process-status-hook}{\args{\var{process}}} + + This function returns the current function to call whenever + \var{process}'s status changes. This function takes the + \var{process} as a required argument. \code{process-status-hook} is + \code{setf}'able. +\end{defun} + +\begin{defun}{extensions:}{process-plist}{\args{\var{process}}} + + This function returns annotations supplied by users, and it is + \code{setf}'able. This is available solely for users to associate + information with \var{process} without having to build a-lists or + hash tables of process structures. +\end{defun} + +\begin{defun}{extensions:}{process-wait}{ + \args{\var{process} \ampoptional{} \var{check-for-stopped}}} + + This function waits for \var{process} to finish. If + \var{check-for-stopped} is non-\nil, this also returns when + \var{process} stops. +\end{defun} + +\begin{defun}{extensions:}{process-kill}{% + \args{\var{process} \var{signal} \ampoptional{} \var{whom}}} + + This function sends the Unix \var{signal} to \var{process}. + \var{Signal} should be the number of the signal or a keyword with + the Unix name (for example, \kwd{sigsegv}). \var{Whom} should be + one of the following: + \begin{Lentry} + + \item[\kwd{pid}] This is the default, and it indicates sending the + signal to \var{process} only. + + \item[\kwd{process-group}] This indicates sending the signal to + \var{process}'s group. + + \item[\kwd{pty-process-group}] This indicates sending the signal to + the process group currently in the foreground on the Unix PTY + connected to \var{process}. This last option is useful if the + running program is a shell, and you wish to signal the program + running under the shell, not the shell itself. If + \code{process-pty} of \var{process} is \nil, using this option is + an error. + \end{Lentry} +\end{defun} + +\begin{defun}{extensions:}{process-alive-p}{\args{\var{process}}} + + This function returns \true{} if \var{process}'s status is either + \kwd{running} or \kwd{stopped}. +\end{defun} + +\begin{defun}{extensions:}{process-close}{\args{\var{process}}} + + This function closes all the streams associated with \var{process}. + When you are done using a process, call this to reclaim system + resources. +\end{defun} + + +\section{Saving a Core Image} + +A mechanism has been provided to save a running Lisp core image and to +later restore it. This is convenient if you don't want to load several files +into a Lisp when you first start it up. The main problem is the large +size of each saved Lisp image, typically at least 20 megabytes. + +\begin{defun}{extensions:}{save-lisp}{% + \args{\var{file} + \keys{\kwd{purify} \kwd{root-structures} \kwd{init-function}} + \morekeys{\kwd{load-init-file} \kwd{print-herald} \kwd{site-init}} + \yetmorekeys{\kwd{process-command-line} \kwd{batch-mode} \kwd{executable}}}} + + The \code{save-lisp} function saves the state of the currently + running Lisp core image in \var{file}. The keyword arguments have + the following meaning: + \begin{Lentry} + + \item[\kwd{purify}] If non-\nil{} (the default), the core image is + purified before it is saved (see \funref{purify}.) This reduces + the amount of work the garbage collector must do when the + resulting core image is being run. Also, if more than one Lisp is + running on the same machine, this maximizes the amount of memory + that can be shared between the two processes. + + \item[\kwd{root-structures}] + This should be a list of the main entry points in any newly + loaded systems. This need not be supplied, but locality and/or + GC performance will be better if they are. Meaningless if + \kwd{purify} is \nil. See \funref{purify}. + + \item[\kwd{init-function}] This is the function that starts running + when the created core file is resumed. The default function + simply invokes the top level read-eval-print loop. If the + function returns the lisp will exit. + + \item[\kwd{load-init-file}] If non-NIL, then load an init file; + either the one specified on the command line or + ``\w{\file{init.}\var{fasl-type}}'', or, if + ``\w{\file{init.}\var{fasl-type}}'' does not exist, + \code{init.lisp} from the user's home directory. If the init file + is found, it is loaded into the resumed core file before the + read-eval-print loop is entered. + + \item[\kwd{site-init}] If non-NIL, the name of the site init file to + quietly load. The default is \file{library:site-init}. No error + is signalled if the file does not exist. + + \item[\kwd{print-herald}] If non-NIL (the default), then print out + the standard Lisp herald when starting. + + \item[\kwd{process-command-line}] If non-NIL (the default), + processes the command line switches and performs the appropriate + actions. + + \item[\kwd{batch-mode}] If NIL (the default), then the presence of + the -batch command-line switch will invoke batch-mode processing + upon resuming the saved core. If non-NIL, the produced core will + always be in batch-mode, regardless of any command-line switches. + + \item[\kwd{executable}] If non-NIL, an executable image is created. + Normally, \cmucl{} consists of the C runtime along with a core + file image. When \kwd{executable} is non-NIL, the core file is + incorporated into the C runtime, so one (large) executable is + created instead of a new separate core file. + + This feature is only available on some platforms, as indicated by + having the feature \kwd{executable}. Currently only x86 ports and + the solaris/sparc port have this feature. + \end{Lentry} +\end{defun} + +To resume a saved file, type: +\begin{example} +lisp -core file +\end{example} +However, if the \kwd{executable} option was specified, you can just +use +\begin{example} + file +\end{example} +since the executable contains the core file within the executable. + +\begin{defun}{extensions:}{purify}{ + \args{\var{file} + \keys{\kwd{root-structures} \kwd{environment-name}}}} + + This function optimizes garbage collection by moving all currently + live objects into non-collected storage. Once statically allocated, + the objects can never be reclaimed, even if all pointers to them are + dropped. This function should generally be called after a large + system has been loaded and initialized. + + \begin{Lentry} + \item[\kwd{root-structures}] is an optional list of objects which + should be copied first to maximize locality. This should be a + list of the main entry points for the resulting core image. The + purification process tries to localize symbols, functions, etc., + in the core image so that paging performance is improved. The + default value is NIL which means that Lisp objects will still be + localized but probably not as optimally as they could be. + + \var{defstruct} structures defined with the \code{(:pure t)} + option are moved into read-only storage, further reducing GC cost. + List and vector slots of pure structures are also moved into + read-only storage. + + \item[\kwd{environment-name}] is gratuitous documentation for the + compacted version of the current global environment (as seen in + \code{c::*info-environment*}.) If \false{} is supplied, then + environment compaction is inhibited. + \end{Lentry} +\end{defun} + + +\section{Pathnames} + +In \clisp{} quite a few aspects of \tindexed{pathname} semantics are left to +the implementation. + + +\subsection{Unix Pathnames} +\cpsubindex{unix}{pathnames} + +Unix pathnames are always parsed with a \code{unix-host} object as the host and +\code{nil} as the device. The last two dots (\code{.}) in the namestring mark +the type and version, however if the first character is a dot, it is considered +part of the name. If the last character is a dot, then the pathname has the +empty-string as its type. The type defaults to \code{nil} and the version +defaults to \kwd{newest}. + +\begin{example} +(defun parse (x) + (values (pathname-name x) (pathname-type x) (pathname-version x))) + +(parse "foo") \result "foo", NIL, NIL +(parse "foo.bar") \result "foo", "bar", NIL +(parse ".foo") \result ".foo", NIL, NIL +(parse ".foo.bar") \result ".foo", "bar", NIL +(parse "..") \result NIL, NIL, NIL +(parse "foo.") \result "foo", "", NIL +(parse "foo.bar.~1~") \result "foo", "bar", 1 +(parse "foo.bar.baz") \result "foo.bar", "baz", NIL +\end{example} + +The directory of pathnames beginning with a slash (or a search-list, +\pxlref{search-lists}) is starts \kwd{absolute}, others start with +\kwd{relative}. The \code{..} directory is parsed as \kwd{up}; there is no +namestring for \kwd{back}: + +\begin{example} +(pathname-directory "/usr/foo/bar.baz") \result (:ABSOLUTE "usr" "foo") +(pathname-directory "../foo/bar.baz") \result (:RELATIVE :UP "foo") +\end{example} + + +\subsection{Wildcard Pathnames} + +Wildcards are supported in Unix pathnames. If `\code{*}' is specified for a +part of a pathname, that is parsed as \kwd{wild}. `\code{**}' can be used as a +directory name to indicate \kwd{wild-inferiors}. Filesystem operations +treat \kwd{wild-inferiors} the same as\ \kwd{wild}, but pathname pattern +matching (e.g. for logical pathname translation, \pxlref{logical-pathnames}) +matches any number of directory parts with `\code{**}' (see +\pxlref{wildcard-matching}.) + +`\code{*}' embedded in a pathname part matches any number of characters. +Similarly, `\code{?}' matches exactly one character, and `\code{[a,b]}' +matches the characters `\code{a}' or `\code{b}'. These pathname parts are +parsed as \code{pattern} objects. + +Backslash can be used as an escape character in namestring +parsing to prevent the next character from being treated as a wildcard. Note +that if typed in a string constant, the backslash must be doubled, since the +string reader also uses backslash as a quote: + +\begin{example} +(pathname-name "foo\(\backslash\backslash\)*bar") => "foo*bar" +\end{example} + + +\subsection{Logical Pathnames} +\cindex{logical pathnames} +\label{logical-pathnames} + +If a namestring begins with the name of a defined logical pathname +host followed by a colon, then it will be parsed as a logical +pathname. Both `\code{*}' and `\code{**}' wildcards are implemented. +\findexed{load-logical-pathname-translations} on \var{name} looks for a +logical host definition file in +\w{\file{library:\var{name}.translations}}. Note that \file{library:} +designates the search list (\pxlref{search-lists}) initialized to the +\cmucl{} \file{lib/} directory, not a logical pathname. The format of +the file is a single list of two-lists of the from and to patterns: + +\begin{example} +(("foo;*.text" "/usr/ram/foo/*.txt") + ("foo;*.lisp" "/usr/ram/foo/*.l")) +\end{example} + + +\subsection{Search Lists} +\cindex{search lists} +\label{search-lists} + +Search lists are an extension to \clisp{} pathnames. They serve a function +somewhat similar to \clisp{} logical pathnames, but work more like Unix PATH +variables. Search lists are used for two purposes: +\begin{itemize} +\item They provide a convenient shorthand for commonly used directory names, +and + +\item They allow the abstract (directory structure independent) specification +of file locations in program pathname constants (similar to logical pathnames.) +\end{itemize} +Each search list has an associated list of directories (represented as +pathnames with no name or type component.) The namestring for any relative +pathname may be prefixed with ``\var{slist}\code{:}'', indicating that the +pathname is relative to the search list \var{slist} (instead of to the current +working directory.) Once qualified with a search list, the pathname is no +longer considered to be relative. + +When a search list qualified pathname is passed to a file-system operation such +as \code{open}, \code{load} or \code{truename}, each directory in the search +list is successively used as the root of the pathname until the file is +located. When a file is written to a search list directory, the file is always +written to the first directory in the list. + + +\subsection{Predefined Search-Lists} + +These search-lists are initialized from the Unix environment or when Lisp was +built: +\begin{Lentry} +\item[\code{default:}] The current directory at startup. + +\item[\code{home:}] The user's home directory. + +\item[\code{library:}] The \cmucl{} \file{lib/} directory (\code{CMUCLLIB} environment +variable). + +\item[\code{path:}] The Unix command path (\code{PATH} environment variable). +\item[\code{ld-library-path:}] The Unix \code{LD\_LIBRARY\_PATH} + environment variable. +\item[\code{target:}] The root of the tree where \cmucl{} was compiled. +\item[\code{modules:}] The list of directories where \cmucl{}'s + modules can be found. +\item[\code{ext-formats:}] The list of directories where \cmucl{} can + find the implementation of external formats. +\end{Lentry} +It can be useful to redefine these search-lists, for example, \file{library:} +can be augmented to allow logical pathname translations to be located, and +\file{target:} can be redefined to point to where \cmucl{} system sources are +locally installed. + + +\subsection{Search-List Operations} + +These operations define and access search-list definitions. A search-list name +may be parsed into a pathname before the search-list is actually defined, but +the search-list must be defined before it can actually be used in a filesystem +operation. + +\begin{defun}{extensions:}{search-list}{\var{name}} + + This function returns the list of directories associated with the + search list \var{name}. If \var{name} is not a defined search list, + then an error is signaled. When set with \code{setf}, the list of + directories is changed to the new value. If the new value is just a + namestring or pathname, then it is interpreted as a one-element + list. Note that (unlike Unix pathnames), search list names are + case-insensitive. +\end{defun} + +\begin{defun}{extensions:}{search-list-defined-p}{\var{name}} + \defunx[extensions:]{clear-search-list}{\var{name}} + + \code{search-list-defined-p} returns \true{} if \var{name} is a + defined search list name, \false{} otherwise. + \code{clear-search-list} make the search list \var{name} undefined. +\end{defun} + +\begin{defmac}{extensions:}{enumerate-search-list}{% + \args{(\var{var} \var{pathname} \mopt{result}) \mstar{form}}} + + This macro provides an interface to search list resolution. The + body \var{forms} are executed with \var{var} bound to each + successive possible expansion for \var{name}. If \var{name} does + not contain a search-list, then the body is executed exactly once. + Everything is wrapped in a block named \nil, so \code{return} can be + used to terminate early. The \var{result} form (default \nil) is + evaluated to determine the result of the iteration. +\end{defmac} + + +\subsection{Search List Example} + +The search list \code{code:} can be defined as follows: +\begin{example} +(setf (ext:search-list "code:") '("/usr/lisp/code/")) +\end{example} +It is now possible to use \code{code:} as an abbreviation for the directory +\file{/usr/lisp/code/} in all file operations. For example, you can now specify +\code{code:eval.lisp} to refer to the file \file{/usr/lisp/code/eval.lisp}. + +To obtain the value of a search-list name, use the function search-list +as follows: +\begin{example} +(ext:search-list \var{name}) +\end{example} +Where \var{name} is the name of a search list as described above. For example, +calling \code{ext:search-list} on \code{code:} as follows: +\begin{example} +(ext:search-list "code:") +\end{example} +returns the list \code{("/usr/lisp/code/")}. + + +\section{Filesystem Operations} + +\cmucl{} provides a number of extensions and optional features beyond those +required by the \clisp{} specification. + + +\subsection{Wildcard Matching} +\label{wildcard-matching} + +Unix filesystem operations such as \code{open} will accept wildcard pathnames +that match a single file (of course, \code{directory} allows any number of +matches.) Filesystem operations treat \kwd{wild-inferiors} the same as\ +\kwd{wild}. + +\begin{defun}{}{directory}{\var{wildname} \keys{\kwd{all} \kwd{check-for-subdirs}} + \kwd{truenamep} \morekeys{\kwd{follow-links}}} + + The keyword arguments to this \clisp{} function are a \cmucl{} extension. + The arguments (all default to \code{t}) have the following + functions: + \begin{Lentry} + \item[\kwd{all}] Include files beginning with dot such as + \file{.login}, similar to ``\code{ls -a}''. + + \item[\kwd{check-for-subdirs}] Test whether files are directories, + similar to ``\code{ls -F}''. + + \item[\kwd{truenamep}] Call \code{truename} on each file, which + expands out all symbolic links. Note that this option can easily + result in pathnames being returned which have a different + directory from the one in the \var{wildname} argument. + + \item[\kwd{follow-links}] Follow symbolic links when searching for + matching directories. + \end{Lentry} +\end{defun} + +\begin{defun}{extensions:}{print-directory}{% + \args{\var{wildname} + \ampoptional{} \var{stream} + \keys{\kwd{all} \kwd{verbose}} + \morekeys{\kwd{return-list}}}} + + Print a directory of \var{wildname} listing to \var{stream} (default + \code{*standard-output*}.) \kwd{all} and \kwd{verbose} both default + to \false{} and correspond to the ``\code{-a}'' and ``\code{-l}'' + options of \file{ls}. Normally this function returns \false{}, but + if \kwd{return-list} is true, a list of the matched pathnames are + returned. +\end{defun} + + +\subsection{File Name Completion} + +\begin{defun}{extensions:}{complete-file}{% + \args{\var{pathname} + \keys{\kwd{defaults} \kwd{ignore-types}}}} + + Attempt to complete a file name to the longest unambiguous prefix. + If supplied, directory from \kwd{defaults} is used as the ``working + directory'' when doing completion. \kwd{ignore-types} is a list of + strings of the pathname types (a.k.a. extensions) that should be + disregarded as possible matches (binary file names, etc.) +\end{defun} + +\begin{defun}{extensions:}{ambiguous-files}{% + \args{\var{pathname} + \ampoptional{} \var{defaults}}} + + Return a list of pathnames for all the possible completions of + \var{pathname} with respect to \var{defaults}. +\end{defun} + + +\subsection{Miscellaneous Filesystem Operations} + +\begin{defun}{extensions:}{default-directory}{} + + Return the current working directory as a pathname. If set with + \code{setf}, set the working directory. +\end{defun} + +\begin{defun}{extensions:}{file-writable}{\var{name}} + + This function accepts a pathname and returns \true{} if the current + process can write it, and \false{} otherwise. +\end{defun} + +\begin{defun}{extensions:}{unix-namestring}{% + \args{\var{pathname} + \ampoptional{} \var{for-input}}} + + This function converts \var{pathname} into a string that can be used + with UNIX system calls. Search-lists and wildcards are expanded. + \var{for-input} controls the treatment of search-lists: when true + (the default) and the file exists anywhere on the search-list, then + that absolute pathname is returned; otherwise the first element of + the search-list is used as the directory. +\end{defun} + + +\section{Time Parsing and Formatting} + +\cindex{time parsing} \cindex{time formatting} +Functions are provided to allow parsing strings containing time information +and printing time in various formats are available. + +\begin{defun}{extensions:}{parse-time}{% + \args{\var{time-string} + \keys{\kwd{error-on-mismatch} \kwd{default-seconds}} + \morekeys{\kwd{default-minutes} \kwd{default-hours}} + \yetmorekeys{\kwd{default-day} \kwd{default-month}} + \yetmorekeys{\kwd{default-year} \kwd{default-zone}} + \yetmorekeys{\kwd{default-weekday}}}} + + \code{parse-time} accepts a string containing a time (e.g., + \w{"\code{Jan 12, 1952}"}) and returns the universal time if it is + successful. If it is unsuccessful and the keyword argument + \kwd{error-on-mismatch} is non-\nil{}, it signals an error. + Otherwise it returns \nil{}. The other keyword arguments have the + following meaning: + + \begin{Lentry} + \item[\kwd{default-seconds}] specifies the default value for the + seconds value if one is not provided by \var{time-string}. The + default value is 0. + + \item[\kwd{default-minutes}] specifies the default value for the + minutes value if one is not provided by \var{time-string}. The + default value is 0. + + \item[\kwd{default-hours}] specifies the default value for the hours + value if one is not provided by \var{time-string}. The default + value is 0. + + \item[\kwd{default-day}] specifies the default value for the day + value if one is not provided by \var{time-string}. The default + value is the current day. + + \item[\kwd{default-month}] specifies the default value for the month + value if one is not provided by \var{time-string}. The default + value is the current month. + + \item[\kwd{default-year}] specifies the default value for the year + value if one is not provided by \var{time-string}. The default + value is the current year. + + \item[\kwd{default-zone}] specifies the default value for the time + zone value if one is not provided by \var{time-string}. The + default value is the current time zone. + + \item[\kwd{default-weekday}] specifies the default value for the day + of the week if one is not provided by \var{time-string}. The + default value is the current day of the week. + \end{Lentry} + Any of the above keywords can be given the value \kwd{current} which + means to use the current value as determined by a call to the + operating system. +\end{defun} + +\begin{defun}{extensions:}{format-universal-time}{ + \args{\var{dest} \var{universal-time} + \\ + \keys{\kwd{timezone}} + \morekeys{\kwd{style} \kwd{date-first}} + \yetmorekeys{\kwd{print-seconds} \kwd{print-meridian}} + \yetmorekeys{\kwd{print-timezone} \kwd{print-weekday}}}} + \defunx[extensions:]{format-decoded-time}{ + \args{\var{dest} \var{seconds} \var{minutes} \var{hours} \var{day} \var{month} \var{year} + \\ + \keys{\kwd{timezone}} + \morekeys{\kwd{style} \kwd{date-first}} + \yetmorekeys{\kwd{print-seconds} \kwd{print-meridian}} + \yetmorekeys{\kwd{print-timezone} \kwd{print-weekday}}}} + + \code{format-universal-time} formats the time specified by + \var{universal-time}. \code{format-decoded-time} formats the time + specified by \var{seconds}, \var{minutes}, \var{hours}, \var{day}, + \var{month}, and \var{year}. \var{Dest} is any destination + accepted by the \code{format} function. The keyword arguments have + the following meaning: + \begin{Lentry} + + \item[\kwd{timezone}] is an integer specifying the hours west of + Greenwich. \kwd{timezone} defaults to the current time zone. + + \item[\kwd{style}] specifies the style to use in formatting the + time. The legal values are: + \begin{Lentry} + + \item[\kwd{short}] specifies to use a numeric date. + + \item[\kwd{long}] specifies to format months and weekdays as + words instead of numbers. + + \item[\kwd{abbreviated}] is similar to long except the words are + abbreviated. + + \item[\kwd{government}] is similar to abbreviated, except the + date is of the form ``day month year'' instead of ``month day, + year''. + \end{Lentry} + + \item[\kwd{date-first}] if non-\false{} (default) will place the + date first. Otherwise, the time is placed first. + + \item[\kwd{print-seconds}] if non-\false{} (default) will format + the seconds as part of the time. Otherwise, the seconds will be + omitted. + + \item[\kwd{print-meridian}] if non-\false{} (default) will format + ``AM'' or ``PM'' as part of the time. Otherwise, the ``AM'' or + ``PM'' will be omitted. + + \item[\kwd{print-timezone}] if non-\false{} (default) will format + the time zone as part of the time. Otherwise, the time zone will + be omitted. + + %%\item[\kwd{print-seconds}] + %%if non-\false{} (default) will format the seconds as part of + %%the time. Otherwise, the seconds will be omitted. + + \item[\kwd{print-weekday}] if non-\false{} (default) will format + the weekday as part of date. Otherwise, the weekday will be + omitted. + \end{Lentry} +\end{defun} + + +\section{Random Number Generation} +\cindex{random number generation} + +\clisp{} includes a random number generator as a standard part of the +language; however, the implementation of the generator is not +specified. + +\subsection{MT-19937 Generator} +\cpsubindex{random number generation}{MT-19937 generator} +On all platforms, the random number is \code{MT-19937} generator as indicated by +\kwd{rand-mt19937} being in \code{*features*}. This is a Lisp +implementation of the MT-19937 generator of Makoto Matsumoto and +T. Nishimura. We refer the reader to their paper\footnote{``Mersenne + Twister: A 623-Dimensionally Equidistributed Uniform Pseudorandom + Number Generator,'' ACM Trans. on Modeling and Computer Simulation, + Vol. 8, No. 1, January 1998, pp.3--30} or to +their +\ifpdf +\href{http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html}{website}. +\else +website at +\href{http://www.math.keio.ac.jp/~matumoto/emt.html}{\texttt{http://www.math.keio.ac.jp/~matsumoto/emt.html}}. +\fi + +When \cmucl{} starts up, \code{*random-state*} is initialized by +reading 627 words from \code{/dev/urandom}, when available. If +\code{/dev/urandom} is not available, the universal time is used to +initialize \code{*random-state*}. The initialization is done as given +in Matsumoto's paper. + +\section{Lisp Threads} +\cindex{lisp threads} + +\cmucl{} supports Lisp threads for the x86 platform. + +\section{Lisp Library} +\label{lisp-lib} + +The \cmucl{} project maintains a collection of useful or interesting +programs written by users of our system. The library is in +\file{lib/contrib/}. Two files there that users should read are: +\begin{Lentry} + +\item[CATALOG.TXT] +This file contains a page for each entry in the library. It +contains information such as the author, portability or dependency issues, how +to load the entry, etc. + +\item[READ-ME.TXT] +This file describes the library's organization and all the +possible pieces of information an entry's catalog description could contain. +\end{Lentry} + +Hemlock has a command \F{Library Entry} that displays a list of the current +library entries in an editor buffer. There are mode specific commands that +display catalog descriptions and load entries. This is a simple and convenient +way to browse the library. + + +\section{Generalized Function Names} + +\begin{defmac}{ext:}{define-function-name-syntax}{% + \var{name} (\var{var}) \ampbody\ \var{body}} + Define lists starting with the symbol \code{name} as a new extended + function name syntax. + + \code{body} is executed with \code{var} bound to an actual function + name of that form, and should return two values: + + \begin{itemize} + \item A generalized boolean that is true if \code{var} is a valid + function name. + \item A symbol that can be used as a \code{block} name in functions + whose name is \code{var}. (For some sorts of function names it + might make sense to return \code{nil} for the block name, or just + return one value.) + \end{itemize} + + Users should not define function names starting with a symbol that + \cmucl{} might be using internally. It is therefore advisable to + only define new function names starting with a symbol from a + user-defined package. +\end{defmac} + +\begin{defun}{ext:}{valid-function-name-p}{\var{name}} + Returns two values: + + \begin{itemize} + \item True if \code{name} is a valid function name. + \item A symbol that can be used as a \code{block} name in + functions whose name is \code{name}. This can be \code{nil} + for some function names. + \end{itemize} +\end{defun} + + + +\section{CLOS} + +\subsection{Primary Method Errors} +\cindex{primary method} + +The standard requires that an error is signaled when a generic +function is called and + +\begin{itemize} +\item no primary method is applicable to the generic function's actual + arguments, and +\item the generic function's method combination is either the standard + method combination or a method combination defined with the short + form of \code{define-method-combination}. The latter includes the + standardized method combinations like \code{progn}, \code{and}, etc. +\end{itemize} + +\begin{defgeneric}[-generic]{pcl:}{no-primary-method}{\var{gf} \amprest{} \var{args}} + In \cmucl, this generic function is called in the above erroneous + cases. The parameter \code{gf} is the generic function being + called, and \code{args} is a list of actual arguments in the generic + function call. +\end{defgeneric} + +\begin{defmethod}[-standard]{pcl:}{no-primary-method}{% + (\var{gf} \argtype{standard-generic-function}) \amprest{} \var{args}} + This method signals a continuable error of type + \code{pcl:no-primary-method-error}. +\end{defmethod} + + +\subsection{Slot Type Checking} +\cindex{slot type checking} + +Declared slot types are used when + +\begin{itemize} +\item reading slot values with \code{slot-value} in methods, or + +\item setting slots with \code{(setf slot-value)} in methods, or + +\item creating instances with \code{make-instance}, when slots are + initialized from initforms. This currently depends on PCL being + able to use its internal \code{make-instance} optimization, which it + usually can. +\end{itemize} + +Example: + +\begin{example} +(defclass foo () + ((a :type fixnum))) + +(defmethod bar ((object foo) value) + (with-slots (a) object + (setf a value))) + +(defmethod baz ((object foo)) + (< (slot-value object 'a) 10)) +\end{example} + +In method \code{bar}, and with a suitable safety setting, a type error +will occur if \code{value} is not a \code{fixnum}. In method +\code{baz}, a \code{fixnum} comparison can be used by the compiler. + +\begin{defvar}{pcl::}{use-slot-types-p} + Slot type checking can be turned off by setting this variable to + \false, which can be useful for compiling code containing incorrect + slot type declarations. +\end{defvar} + + +\subsection{Slot Access Optimization} +\cindex{slot access optimization} +\cindex{slot declarations} + +The declaration \code{ext:slots} is used for optimizing slot access in +methods. + +\begin{example} +declare (ext:slots specifier*) + +specifier ::= (quality class-entry*) +quality ::= SLOT-BOUNDP | INLINE +class-entry ::= class | (class slot-name*) +class ::= the name of a class +slot-name ::= the name of a slot +\end{example} + +The \code{slot-boundp} quality specifies that all or some slots of a +class are always bound. + +The \code{inline} quality specifies that access to all or some slots +of a class should be inlined, using compile-time knowledge of class +layouts. + + + +\subsubsection{\code{slot-boundp} Declaration} +\cpsubindex{slot declaration}{slot-boundp} + +Example: + +\begin{example} +(defclass foo () + (a b)) + +(defmethod bar ((x foo)) + (declare (ext:slots (slot-boundp foo))) + (list (slot-value x 'a) (slot-value x 'b))) +\end{example} + +The \code{slot-boundp} declaration in method \code{bar} specifies that +the slots \code{a} and \code{b} accessed through parameter \code{x} in +the scope of the declaration are always bound, because parameter +\code{x} is specialized on class \code{foo} to which the +\code{slot-boundp} declaration applies. The PCL-generated code for +the \code{slot-value} forms will thus not contain tests for the slots +being bound or not. The consequences are undefined should one of the +accessed slots not be bound. + + + +\subsubsection{\code{inline} Declaration} +\cpsubindex{slot declaration}{inline} + +Example: + +\begin{example} +(defclass foo () + (a b)) + +(defmethod bar ((x foo)) + (declare (ext:slots (inline (foo a)))) + (list (slot-value x 'a) (slot-value x 'b))) +\end{example} + +The \code{inline} declaration in method \code{bar} tells PCL to use +compile-time knowledge of slot locations for accessing slot \code{a} +of class \code{foo}, in the scope of the declaration. + +Class \code{foo} must be known at compile time for this optimization +to be possible. PCL prints a warning and uses normal slot access If +the class is not defined at compile time. + +If a class is \code{proclaim}ed to use inline slot access before it is +defined, the class is defined at compile time. Example: + +\begin{example} +(declaim (ext:slots (inline (foo slot-a)))) +(defclass foo () ...) +(defclass bar (foo) ...) +\end{example} + +Class \code{foo} will be defined at compile time because it is +declared to use inline slot access; methods accessing slot +\code{slot-a} of \code{foo} will use inline slot access if otherwise +possible. Class \code{bar} will be defined at compile time because +its superclass \code{foo} is declared to use inline slot access. PCL +uses compile-time information from subclasses to warn about situations +where using inline slot access is not possible. + +Normal slot access will be used if PCL finds, at method compilation +time, that + +\begin{itemize} +\item class \code{foo} has a subclass in which slot \code{a} is at a + different location, or + +\item there exists a \code{slot-value-using-class} method for + \code{foo} or a subclass of \code{foo}. +\end{itemize} + +When the declaration is used to optimize calls to slot accessor +generic functions in methods, as opposed to \code{slot-value} or +\code{(setf slot-value)}, the optimization is additionally not used if + +\begin{itemize} +\item there exist, at compile time, applicable methods on the + reader/writer generic function that are not standard accessor + methods (for instance, there exist around-methods), or + +\item applicable reader/writer methods access different slots in a + class accessed inline, and one of its subclasses. +\end{itemize} + +The consequences are undefined if the compile-time environment is not +the same as the run-time environment in these respects, or if the +definition of class \code{foo} or any subclass of \code{foo} is +changed in an incompatible way, that is, if slot locations change. + +The effect of the \code{inline} optimization combined with the +\code{slot-boundp} optimization is that CLOS slot access becomes as +fast as structure slot access, which is an order of magnitude faster +than normal CLOS slot access. + +\begin{defvar}{pcl::}{optimize-inline-slot-access-p} + This variable controls if inline slot access optimizations are + performed. It is true by default. +\end{defvar} + + + +\subsubsection{Automatic Method Recompilation} +\cindex{methods} +\cpsubindex{methods}{auto-compilation} +\cpsubindex{slot declaration}{method recompilation} + +Methods using inline slot access can be automatically recompiled after +class changes. Two declarations control which methods are +automatically recompiled. + +\begin{example} +declaim (ext:auto-compile specifier*) +declaim (ext:not-auto-compile specifier*) + +specifier ::= gf-name | (gf-name qualifier* (specializer*)) +gf-name ::= the name of a generic function +qualifier ::= a method qualifier +specializer ::= a method specializer +\end{example} + +If no specifier is given, auto-compilation is by default done/not done +for all methods of all generic functions using inline slot access; +current default is that it is not done. This global policy can be +overridden on a generic function and method basis. If +\code{specifier} is a generic function name, it applies to all methods +of that generic function. + +Examples: + +\begin{example} +(declaim (ext:auto-compile foo)) +(defmethod foo :around ((x bar)) ...) +\end{example} + +The around-method \code{foo} will be automatically recompiled because +the declamation applies to all methods with name \code{foo}. + +\begin{example} +(declaim (ext:auto-compile (foo (bar)))) +(defmethod foo :around ((x bar)) ...) +(defmethod foo ((x bar)) ...) +\end{example} + +The around-method will not be automatically recompiled, but the +primary method will. + +\begin{example} +(declaim (ext:auto-compile foo)) +(declaim (ext:not-auto-compile (foo :around (bar))) +(defmethod foo :around ((x bar)) ...) +(defmethod foo ((x bar)) ...) +\end{example} + +The around-method will not be automatically recompiled, because it +is explicitly declaimed not to be. The primary method will be +automatically recompiled because the first declamation applies to +it. + +Auto-recompilation works by recording method bodies using inline slot +access. When PCL determines that a recompilation is necessary, a +\code{defmethod} form is constructed and evaluated. + +Auto-compilation can only be done for methods defined in a null +lexical environment. PCL prints a warning and doesn't record the +method body if a method using inline slot access is defined in a +non-null lexical environment. Instead of doing a recompilation on +itself, PCL will then print a warning that the method must be +recompiled manually when classes are changed. + + + +\subsection{Inlining Methods in Effective Methods} +\cindex{effective method} +\cpsubindex{methods}{inlining in effective methods} +\cpsubindex{effective method}{inlining of methods} +\cindex{inline} + +When a generic function is called, an effective method is constructed +from applicable methods. The effective method is called with the +original arguments, and itself calls applicable methods according to +the generic function's method combination. Some of the function call +overhead in effective methods can be removed by inlining methods in +effective methods, at the expense of increased code size. + +Inlining of methods is controlled by the usual \code{inline} +declaration. In the following example, both \code{foo} methods shown +will be inlined in effective methods: + +\begin{example} +(declaim (inline (method foo (foo)) + (method foo :before (foo)))) +(defmethod foo ((x foo)) ...) +(defmethod foo :before ((x foo)) ...) +\end{example} + +Please note that this form of inlining has no noticeable effect for +effective methods that consist of a primary method only, which doesn't +have keyword arguments. In such cases, PCL uses the primary method +directly for the effective method. + +When the definition of an inlined method is changed, effective methods +are \textbf{not} automatically updated to reflect the change. This is +just as it is when inlining normal functions. Different from the +normal case is that users do not have direct access to effective +methods, as it would be the case when a function is inlined somewhere +else. Because of this, the function \code{pcl:flush-emf-cache} is +provided for forcing such an update of effective methods. + +\begin{defun}{pcl:}{flush-emf-cache}{\ampoptional{} \var{gf}} + Flush cached effective method functions. If \code{gf} is supplied, + it should be a generic function metaobject or the name of a generic + function, and this function flushes all cached effective methods for + the given generic function. If \code{gf} is not supplied, all + cached effective methods are flushed. +\end{defun} + +\begin{defvar}{pcl::}{inline-methods-in-emfs} + If true, the default, perform method inlining as described above. + If false, don't. +\end{defvar} + + + +\subsection{Effective Method Precomputation} +\cpsubindex{effective method}{precomputation} +\cpsubindex{methods}{load time} +\cpsubindex{methods}{emf precomputation} + +When a generic function is called, the generic function's +discriminating function computes the set of methods applicable to +actual arguments and constructs an effective method function from +applicable methods, using the generic function's method combination. + +Effective methods can be precomputed at method load time instead of +when the generic function is called depending on the value of +\code{pcl:*max-emf-precomputation-methods*}. + +\begin{defvar}{pcl:}{*max-emf-precomputation-methods*} + If nonzero, the default value is 100, precompute effective methods + when methods are loaded, and the method's generic function has less + than the specified number of methods. + + If zero, compute effective methods only when the generic function is + called. +\end{defvar} + + + +\subsection{Sealing} +\cindex{sealing} +\cpsubindex{sealing}{subclasses} +\cpsubindex{sealing}{methods} +\cpsubindex{methods}{sealing} + +Support for sealing classes and generic functions have been +implemented. Please note that this interface is subject to change. + +\begin{defmac}{pcl:}{seal}{\var{name} (\var{var}) \amprest{} \var{specifiers}} + Seal \code{name} with respect to the given specifiers; \code{name} + can be the name of a class or generic-function. + + Supported specifiers are \kwd{subclasses} for classes, + which prevents changing subclasses of a class, and \kwd{methods} + which prevents changing the methods of a generic function. + + Sealing violations signal an error of type \code{pcl:sealed-error}. +\end{defmac} + +\begin{defun}{pcl:}{unseal}{\var{name-or-object}} + Remove seals from \code{name-or-object}. +\end{defun} + + + +\subsection{Method Tracing and Profiling} +\label{sec:method-tracing} +\cindex{tracing} +\cpsubindex{tracing}{methods} +\cindex{profiling} +\cpsubindex{profiling}{methods} +\cpsubindex{methods}{tracing} +\cpsubindex{methods}{profiling} + +Methods can be traced with \code{trace}, using function names of the +form \code{(method )}. Example: + +\begin{example} +(defmethod foo ((x integer)) x) +(defmethod foo :before ((x integer)) x) + +(trace (method foo (integer))) +(trace (method foo :before (integer))) +(untrace (method foo :before (integer))) +\end{example} + +\code{trace} and \code{untrace} also allow a name specifier +\code{:methods gf-form} for tracing all methods of a generic function: + +\begin{example} +(trace :methods 'foo) +(untrace :methods 'foo) +\end{example} + +Methods can also be specified for the \kwd{wherein} option to +\code{trace}. Because this option is a name or a list of names, +methods must be specified as a list. Thus, to trace all calls of +\code{foo} from the method \code{bar} specialized on integer argument, +use +\begin{example} + (trace foo :wherein ((method bar (integer)))) +\end{example} +Before and after methods are supported as well: +\begin{example} + (trace foo :wherein ((method bar :before (integer)))) +\end{example} + +Method profiling is done analogously to \code{trace}: + +\begin{example} +(defmethod foo ((x integer)) x) +(defmethod foo :before ((x integer)) x) + +(profile:profile (method foo (integer))) +(profile:profile (method foo :before (integer))) +(profile:unprofile (method foo :before (integer))) + +(profile:profile :methods 'foo) +(profile:unprofile :methods 'foo) + +(profile:profile-all :methods t) +\end{example} + + + +\subsection{Misc} +\cpsubindex{methods}{interpreted} + +\begin{defvar}{pcl::}{compile-interpreted-methods-p} + This variable controls compilation of interpreted method functions, + e.g. for methods defined interactively at the REPL. Default is + true, that is, method functions are compiled. +\end{defvar} + + + + + +\section{Differences from ANSI Common Lisp} +This section describes some of the known differences between \cmucl{} +and ANSI \clisp{}. Some may be non-compliance issues; same may be +extensions. + +\subsection{Extensions} + +\begin{defun}{}{constantly}{% + \var{value} \ampoptional{} \var{val1} \var{val2} \amprest{} \var{more-values}} + As an extension, \cmucl{} allows \code{constantly} to accept more + than one value which are returned as multiple values. +\end{defun} + + + + +\section{Function Wrappers} +\cindex{function wrappers} +\cindex{fwrappers} + +Function wrappers, fwrappers for short, are a facility for efficiently +encapsulating functions\footnote{This feature was independently +developed, but the interface is modelled after a similar feature in +Allegro. Some names, however, have been changed.}. + +Functions in \cmucl{} are represented by \code{kernel:fdefn} +objects. Each \code{fdefn} object contains a reference to its +function's actual code, which we call the function's primary function. + +A function wrapper replaces the primary function in the \code{fdefn} +object with a function of its own, and records the original function +in an fwrapper object, a funcallable instance. Thus, when the +function is called, the fwrapper gets called, which in turn might call +the primary function, or a previously installed fwrapper that was +found in the \code{fdefn} object when the second fwrapper was +installed. + +Example: + +\begin{lisp} +(use-package :fwrappers) + +(define-fwrapper foo (x y) + (format t "x = ~s, y = ~s, user-data = ~s~%" + x y (fwrapper-user-data fwrapper)) + (let ((value (call-next-function))) + (format t "value = ~s~%" value) + value)) + +(defun bar (x y) + (+ x y)) + +(fwrap 'bar #'foo :type 'foo :user-data 42) + +(bar 1 2) + => + x = 1, y = 2, user-data = 42 + value = 3 + 3 +\end{lisp} + +Fwrappers are used in the implementation of \code{trace} and +\code{profile}. + +Please note that \code{fdefinition} always returns the primary +definition of a function; if a function is fwrapped, +\code{fdefinition} returns the primary function stored in the +innermost fwrapper object. Likewise, if a function is fwrapped, +\code{(setf fdefinition)} will set the primary function in the +innermost fwrapper. + +\begin{defmac}{fwrappers:}{define-fwrapper}{\var{name} \var{lambda-list} \ampbody{} \var{body}} + This macro is like \code{defun}, but defines a function named + \var{name} that can be used as an fwrapper definition. + + In \var{body}, the symbol \code{fwrapper} is bound to the current + fwrapper object. + + The macro \code{call-next-function} can be used to invoke the next + fwrapper, or the primary function that is being fwrapped. When + called with no arguments, \code{call-next-function} invokes the next + function with the original arguments passed to the fwrapper, unless + you modify one of the parameters. When called with arguments, + \code{call-next-function} invokes the next function with the given + arguments. +\end{defmac} + +\begin{defun}{fwrappers:}{fwrap}{\var{function-name} \var{fwrapper} % + \keys{\kwd{type} \kwd{user-data}}} + This function wraps function \code{function-name} in an fwrapper + \var{fwrapper} which was defined with \code{define-fwrapper}. + + The value of \var{type}, if supplied, is used as an identifying + tag that can be used in various other operations. + + The value of \var{user-data} is stored as user-supplied data in the + fwrapper object that is created for the function encapsulation. + User-data is accessible in the body of fwrappers defined with + \code{define-fwrapper} as \code{(fwrapper-user-data fwrapper)}. + + Value is the fwrapper object created. +\end{defun} + +\begin{defun}{fwrappers:}{funwrap}{\var{function-name} \keys{\kwd{type} \kwd{test}}} + Remove fwrappers from the function named \var{function-name}. If + \var{type} is supplied, remove fwrappers whose type is \code{equal} + to \var{type}. If \var{test} is supplied, remove fwrappers + satisfying \var{test}. +\end{defun} + +\begin{defun}{fwrappers:}{find-fwrapper}{\var{function-name} \keys{\kwd{type} \kwd{test}}} + Find an fwrapper of \var{function-name}. If \var{type} is supplied, + find an fwrapper whose type is \code{equal} to \var{type}. If + \var{test} is supplied, find an fwrapper satisfying \var{test}. +\end{defun} + +\begin{defun}{fwrappers:}{update-fwrapper}{\var{fwrapper}} + Update the funcallable instance function of the fwrapper object + \var{fwrapper} from the definition of its function that was + defined with \code{define-fwrapper}. This can be used to update + fwrappers after changing a \code{define-fwrapper}. +\end{defun} + +\begin{defun}{fwrappers:}{update-fwrappers}{\var{function-name} \keys{\kwd{type} \kwd{test}}} + Update fwrappers of \var{function-name}; see \code{update-fwrapper}. + If \var{type} is supplied, update fwrappers whose type is + \code{equal} to \var{type}. If \var{test} is supplied, update fwrappers + satisfying \var{test}. +\end{defun} + +\begin{defun}{fwrappers:}{set-fwrappers}{\var{function-name} \var{fwrappers}} + Set \var{function-names}'s fwrappers to elements of the list + \var{fwrappers}, which is assumed to be ordered from outermost to + innermost. \var{fwrappers} null means remove all fwrappers. +\end{defun} + +\begin{defun}{fwrappers:}{list-fwrappers}{\var{function-name}} + Return a list of all fwrappers of \var{function-name}, ordered + from outermost to innermost. +\end{defun} + +\begin{defun}{fwrappers:}{push-fwrapper}{\var{fwrapper} \var{function-name}} + Prepend fwrapper \var{fwrapper} to the definition of + \var{function-name}. Signal an error if \var{function-name} is an + undefined function. +\end{defun} + +\begin{defun}{fwrappers:}{delete-fwrapper}{\var{fwrapper} \var{function-name}} + Remove fwrapper \var{fwrapper} from the definition of + \var{function-name}. Signal an error if \var{function-name} is an + undefined function. +\end{defun} + +\begin{defmac}{fwrappers:}{do-fwrappers}{(\var{var} \var{fdefn} \ampoptional{} + \var{result}) \ampbody{} \var{body}} + Evaluate \var{body} with \var{var} bound to consecutive fwrappers of + \var{fdefn}. Return \var{result} at the end. Note that \var{fdefn} + must be an \code{fdefn} object. You can use + \code{kernel:fdefn-or-lose}, for instance, to get the \code{fdefn} + object from a function name. +\end{defmac} + +\section{Dynamic-Extent Declarations} +\cindex{dynamic-extent} + +\emph{Note: As of the 19a release, \code{dynamic-extent} is + unfortunately disabled by default. It is known to cause some issues + with CLX and Hemlock. The cause is not known, but causes random + errors and brokeness. Enable at your own risk. However, it is safe + enough to build all of CMUCL without problems.} + +On x86 and sparc, \cmucl{} can exploit \code{dynamic-extent} +declarations by allocating objects on the stack instead of the heap. + +You can tell \cmucl{} to trust or not trust \code{dynamic-extent} +declarations by setting the variable +\var{*trust-dynamic-extent-declarations*}. + +\begin{defvar}{ext:}{trust-dynamic-extent-declarations} + If the value of \var{*trust-dynamic-extent-declarations*} is + \code{NIL}, \code{dynamic-extent} declarations are effectively + ignored. + + If the value of this variable is a function, the function is called + with four arguments to determine if a \code{dynamic-extent} + declaration should be trusted. The arguments are the safety, + space, speed, and debug settings at the point where the + \code{dynamic-extent} declaration is used. If the function + returns true, the declaration is trusted, otherwise it is not + trusted. + + In all other cases, \code{dynamic-extent} declarations are + trusted. +\end{defvar} + +Please note that stack-allocation is inherently unsafe. If you make a +mistake, and a stack-allocated object or part of it escapes, \cmucl{} +is likely to crash, or format your hard disk. + +\subsection{\code{\&rest} argument lists} +\cpsubindex{dynamic-extent}{rest lists} + +Rest argument lists can be allocated on the stack by declaring the +rest argument variable \code{dynamic-extent}. Examples: + +\begin{lisp} +(defun foo (x &rest rest) + (declare (dynamic-extent rest)) + ...) + +(defun bar () + (lambda (&rest rest) + (declare (dynamic-extent rest)) + ...)) +\end{lisp} + +\subsection{Closures} +\cpsubindex{dynamic-extent}{closures} + +Closures for local functions can be allocated on the stack if the +local function is declared \code{dynamic-extent}, and the closure +appears as an argument in the call of a named function. In the +example: + +\begin{lisp} +(defun foo (x) + (flet ((bar () x)) + (declare (dynamic-extent #'bar)) + (baz #'bar))) +\end{lisp} + +the closure passed to function \code{baz} is allocated on the stack. +Likewise in the example: + +\begin{lisp} +(defun foo (x) + (flet ((bar () x)) + (baz #'bar) + (locally (declare (dynamic-extent #'bar)) + (baz #'bar)))) +\end{lisp} + +\cpsubindex{dynamic-extent}{known CL functions} + +Stack-allocation of closures can also automatically take place when +calling certain known CL functions taking function arguments, for +example \code{some} or \code{find-if}. + +\subsection{\code{list}, \code{list*}, and \code{cons}} +\cpsubindex{dynamic-extent}{list, list*, cons} + +New conses allocated by \code{list}, \code{list*}, or \code{cons} +which are used to initialize variables can be allocated from the stack +if the variables are declared \code{dynamic-extent}. In the case of +\code{cons}, only the outermost cons cell is allocated from the stack; +this is an arbitrary restriction. + +\begin{lisp} +(let ((x (list 1 2)) + (y (list* 1 2 x)) + (z (cons 1 (cons 2 nil)))) + (declare (dynamic-extent x y z)) + ... + (setq x (list 2 3)) + ...) +\end{lisp} + +Please note that the \code{setq} of \code{x} in the example program +assigns to \code{x} a list that is allocated from the heap. This is +another arbitrary restriction that exists because other Lisps behave +that way. + +\section{Modular Arithmetic} +\cindex{modular-arith} + +This section is mostly taken, with permission, from the documentation +for SBCL. + +Some numeric functions have a property: \code{N} lower bits of +the result depend only on \code{N} lower bits of (all or some) +arguments. If the compiler sees an expression of form \code{(logand +exp mask)}, where \code{exp} is a tree of such ``good'' functions +and \code{mask} is known to be of type \code{(unsigned-byte +w)}, where \code{w} is a "good" width, all intermediate results +will be cut to \code{w} bits (but it is not done for variables +and constants!). This often results in an ability to use simple +machine instructions for the functions. + +Consider an example. +\begin{lisp} +(defun i (x y) + (declare (type (unsigned-byte 32) x y)) + (ldb (byte 32 0) (logxor x (lognot y)))) +\end{lisp} +The result of \code{(lognot y)} will be negative and of +type \code{(signed-byte 33)}, so a naive implementation on a 32-bit +platform is unable to use 32-bit arithmetic here. But modular +arithmetic optimizer is able to do it: because the result is cut down +to 32 bits, the compiler will replace \code{logxor} +and \code{lognot} with versions cutting results to 32 bits, and +because terminals (here---expressions \code{x} and \code{y}) +are also of type \code{(unsigned-byte 32)}, 32-bit machine +arithmetic can be used. + + +Currently ``good'' functions +are \code{+}, \code{-}, \code{*}; \code{logand}, \code{logior}, +\code{logxor}, \code{lognot} and their combinations; +and \code{ash} with the positive second argument. ``Good'' widths +are 32 on HPPA, MIPS, PPC, Sparc and X86 and 64 on Alpha. While it is +possible to support smaller widths as well, currently it is not +implemented. + +A more extensive description of modular arithmetic can be found in the +paper ``Efficient Hardware Arithmetic in Common Lisp'' by Alexey +Dejneka, and Christophe Rhodes, to be published. + +\section{Extension to REQUIRE} +\cindex{require} + +The behavior of \code{require} when called with only one argument is +implementation-defined. In \cmucl, functions from the list +\var{*module-provider-functions*} are called in order with the +stringified module name as the argument. The first function to return +non-\var{NIL} is assumed to have loaded the module. + +By default the functions \code{module-provide-cmucl-defmodule} and +\code{module-provide- cmucl-library} are on this list of functions, in +that order. + +\begin{defvar}{ext:}{module-provider-functions} + This is a list of functions taking a single argument. + \code{require} calls each function in turn with the stringified + module name. The first function to return non-\var{NIL} indicates + that the module has been loaded. The remaining functions, if any, + are not called. + + To add new providers, push the new provider function onto the + beginning of this list. +\end{defvar} + +\begin{defmac}{ext:}{defmodule}{\var{name} \amprest{} \var{files}} + Defines a module by registering the files that need to be loaded + when the module is required. If \var{name} is a symbol, its print + name is used after downcasing it. +\end{defmac} + +\begin{defun}{ext:}{module-provide-cmucl-defmodule}{\var{module-name}} + This function is the module-provider for modules registered by a + \code{ext:defmodule} form. +\end{defun} + +\begin{defun}{ext:}{module-provide-cmucl-library}{\var{module-name}} + This function is the module-provider for \cmucl's libraries, + including Gray streams, simple streams, CLX, CLM, Hemlock, + \emph{etc}. + + This function causes a file to be loaded whose name is formed by + merging the search-list ``modules:'' and the concatenation of + module-name with the suffix ``-LIBRARY''. Note that both the + module-name and the suffix are each, separately, converted from + :case :common to :case :local. This merged name will be probed with + both a .lisp and .fasl extensions, calling \code{LOAD} if it exists. +\end{defun} + + +\section{Localization} +\label{sec:localization} + +\cmucl{} support localization where messages can be presented in the +native language. This is done in the style of \code{gettext} which +marks strings that are to be translated and provides the lookup to +convert the string to the specified language. + +All messages from \cmucl{} can be translated but as of this writing, +the only complete translation is a Pig Latin translation done by +machine. There are a few messages translated to Korean. + +In general, translatable strings are marked as such by using the +functions \code{intl:gettext} and \code{intl:ngettext} or by using the +reader macros \verb+_+ or \verb+_N+. When loading or compiling, such +strings are recorded for translation. At runtime, such strings are +looked in and the translation is returned. Doc strings do not need to +be noted in any way; the are automatically noted for translation. + +By default, recording of translatable strings is disabled. To enable +recording of strings, call \code{intl:translation-enable}. + +\subsection{Dictionary} +\label{sec:localization-dictionary} + +\begin{defun}{intl:}{translation-enable}{} + Enable recording of translatable strings. +\end{defun} + +\begin{defun}{intl:}{translation-disable}{} + Disablle recording of translatable strings. +\end{defun} + +\begin{defun}{intl:}{setlocale}{\ampoptional{} \var{locale}} + Sets the locale to the locale specified by \var{locale}. If + \var{locale} is not give or is \nil, the locale is determined by + look at the environment variables \code{LANGUAGE}, \code{LC\_ALL}, + \code{LC\_MESSAGES}, or \code{LANG}. If none of these are set, the + locale is unchanged. + + The default locale is ``C''. +\end{defun} + +\begin{defun}{intl:}{textdomain}{\var{domain}} + Set the default domain to the domain specified by \var{domain}. + Typically, this only needs to be done at the top of each source + file. This is used to \code{gettext} and \code{ngettext} to set the + domain for the message string. +\end{defun} + +\begin{defmac}{intl:}{gettext}{\var{string}} + Look up the specified string, \var{string}, in the current message + domain and return its translation. +\end{defmac} + +\begin{defun}{intl:}{dgettext}{\var{domain} \var{string}} + Look up the specified string, \var{string}, in the message domain, + \var{domain}. The translation is returned. + + When compiled, this also function also records the string so that an + appropriate message template file can be created. (See + \code{intl::dump-pot-files}.) +\end{defun} + +\begin{defmac}{intl:}{ngettext}{\var{singular} \var{plural} \var{n}} + Look up the singular or plural form of a message in the default + domain. The singular form is \var{singular}; the plural is + \var{plural}. The number of items is specified by \var{n} in case + the correct translation depends on the actual number of items. +\end{defmac} + +\begin{defun}{intl:}{dngettext}{\var{domain} \var{singular} \var{plural} \var{n}} + Look up the singular or plural form of a message in the specified + domain, \var{domain}. The singular form is \var{singular}; the + plural is \var{plural}. The number of items is specified by \var{n} + in case the correct translation depends on the actual number of + items. + + When compiled, this also function also records the singular and + plural forms so that an appropriate message template file can be + created. (See \code{intl::dump-pot-files}.) +\end{defun} + +\begin{defun}{intl::}{dump-pot-files}{\keys{\kwd{copyright} \kwd{output-directory}}} + Dumps the translatable strings recorded by \code{dgettext} and + \code{dngettext}. The message template file (pot file) is written + to a file in the directory specified by \var{output-directory}, and + the name of the file is the domain of the string. + + If \var{copyright} is specified, this is placed in the output file + as the copyright message. +\end{defun} + +\begin{defvar}{intl:}{locale-directories} + This is a list of directory pathnames where the translations can be found. +\end{defvar} + +\begin{defun}{intl:}{install}{\ampoptional{} (\var{rt} \var{*readtable*})} + Installs reader macros and comment reader into the specified + readtable as explained below. The readtable defaults to + \var{*readtable*}. +\end{defun} + +Two reader macros are also provided: \code{\_''} and \code{\_N''}. The +first is equivalent to wrapping \code{dgettext} around the string. +The second returns the string, but also records the string. This is +needed when we want to record a docstring for translation or any other +string in a place where a macro or function call would be incorrect. + +Also, the standard comment reader is extended to allow translator +comments to be saved and written to the messages template file so that +the translator may not need to look at the original source to +understand the string. Any comment line that begins with exactly +\verb|"TRANSLATORS: "| is saved. This means each translator comment +must be preceded by this string to be saved; the translator comment +ends at the end of each line. + + +\subsection{Example Usage} +\label{sec:localization-usage} + +Here is a simple example of how to localize your code. Let the file +\code{intl-ex.lisp} contain: + +\begin{example} + +(intl:textdomain "example") + +(defun foo (x y) + "Cool function foo of x and y" + (let ((result (bar x y))) + ;; TRANSLATORS: One line comment about bar. + (format t _"bar of ~A and ~A = ~A~%" x y result) + #| TRANSLATORS: Multiline comment about + how many Xs there are + |# + (format t (intl:ngettext "There is one X" + "There are many Xs" + x)) + result)) +\end{example} + +The call to \code{textdomain} sets the default domain for all +translatable strings following the call. + +Here is a sample session for creating a template file: + +\begin{example} +* (intl:install) + +T +* (intl:translation-enable) + +T +* (compile-file "intl-ex") + +#P"/Volumes/share/cmucl/cvs/intl-ex.sse2f" +NIL +NIL +* (intl::dump-pot-files :output-directory "./") + +Dumping 3 messages for domain "example" +NIL +* +\end{example} + +When this file is compiled, all of the translatable strings are +recorded. This includes the docstring for \code{foo}, the string for +the first \code{format}, and the string marked by the call to +\code{intl:ngettext}. + +A file named ``example.pot'' in the directory ``./'' is created. +The contents of this file are: +\begin{example} +#@ example + +# SOME DESCRIPTIVE TITLE +# FIRST AUTHOR , YEAR +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION" +"Report-Msgid-Bugs-To: " +"PO-Revision-Date: YEAR-MO-DA HO:MI +ZONE" +"Last-Translator: FULL NAME " +"Language-Team: LANGUAGE " +"MIME-Version: 1.0" +"Content-Type: text/plain; charset=UTF-8" +"Content-Transfer-Encoding: 8bit" + +#. One line comment about bar. +#: intl-ex.lisp +msgid "bar of ~A and ~A = ~A~%" +msgstr "" + +#. Multiline comment about + how many Xs there are +#: intl-ex.lisp +msgid "Cool function foo of x and y" +msgstr "" + +#: intl-ex.lisp +msgid "There is one X" +msgid_plural "There are many Xs" +msgstr[0] "" + +\end{example} + +To finish the translation, a corresponding ``example.po'' file needs +to be created with the appropriate translations for the given +strings. This file must be placed in some directory that is included +in \code{intl:*locale-directories*}. + +Suppose the translation is done for Korean. Then the user can set the +environment variables appropriately or call \code{(intl:setlocale + "ko")}. Note that the external format for the standard streams +needs to be set up appropriately too. It is up to the user to set +this correctly. Once this is all done, the output from the function +\code{foo} will now be in Korean instead of English as in the original +source file. + +For further information, we refer the reader to documentation on +\ifpdf +\href{http://www.gnu.org/software/gettext/manual/gettext.html}{gettext}. +\else +gettext at +\href{http://www.gnu.org/software/gettext/manual/gettext.html}{\texttt{http://www.gnu.org/software/gettext/manual/gettext.html}}. +\fi + +\section{Static Arrays} +\label{sec:static-arrays} + +\cmucl{} supports static arrays which are arrays that are not moved by +the garbage collector. To create such an array, use the +\kwd{allocation} option to \code{make-array} with a value of +\kwd{malloc}. These arrays appear as normal Lisp arrays, but are +actually allocated from the \code{C} heap (hence the \kwd{malloc}). +Thus, the number and size of such arrays are limited by the available +\code{C} heap. + +Also, only certain types of arrays can be allocated. The static array +cannot be adjustable and cannot be displaced to. The array must also +be a \code{simple-array} of one dimension. The element type is also +constrained to be one of the types in +Table~\ref{tbl:static-array-types}. + +\begin{table}[tbhp] + \begin{center} + \begin{tabular}{|c|} + \hline + \code{(unsigned-byte 8)} \\ + \hline + \code{(unsigned-byte 16)} \\ + \hline + \code{(unsigned-byte 32)} \\ + \hline + \code{(signed-byte 8)} \\ + \hline + \code{(signed-byte 16)} \\ + \hline + \code{(signed-byte 32)} \\ + \hline + \code{single-float} \\ + \hline + \code{double-float} \\ + \hline + \code{(complex single-float)} \\ + \hline + \code{(complex double-float)} \\ + \hline + \end{tabular} + \caption{Allowed element types for static arrays} + \label{tbl:static-array-types} + \end{center} +\end{table} + +The arrays are properly handled by GC. GC will not move the arrays, +but they will be properly removed up if they become garbage. diff --git a/doc/cmu-user/hierarchical-packages.tex b/doc/cmu-user/hierarchical-packages.tex new file mode 100644 index 0000000000..74e08a6bec --- /dev/null +++ b/doc/cmu-user/hierarchical-packages.tex @@ -0,0 +1,213 @@ +\section{Hierarchical Packages} +\cindex{hierarchical packages} + + +% this section is heavily based on the Franz Inc. documentation for +% the hierarchical packages feature, as per +% +% accessed on 2002-03-18. It is used by permission from Kevin Layer, +% obtained in email to Eric Marsden, in response to spr25795. +% +% Allegro-specific references in the document have been removed. + + +\subsection{Introduction} + +The \clisp{} package system, designed and standardized several years +ago, is not hierarchical. Since \clisp{} was standardized, other +languages, including Java and Perl, have evolved namespaces which are +hierarchical. This document describes a hierarchical package naming +scheme for \clisp{}. The scheme was proposed by Franz Inc and +implemented in their \textit{Allegro Common Lisp} product; a +compatible implementation of the naming scheme is implemented in +\cmucl{}. This documentation is based on the Franz Inc. documentation, +and is included with permission. + +The goals of hierarchical packages in \clisp{} are: + +\begin{itemize} +\item +Reduce collisions with user-defined packages: it is a well-known +problem that package names used by the Lisp implementation and those +defined by users can easily conflict. The intent of hierarchical +packages is to reduce such conflicts to a minimum. + +\item +Improve modularity: the current organization of packages in various +implementations has grown over the years and appears somewhat random. +Organizing future packages into a hierarchy will help make the +intention of the implementation more clear. + +\item +Foster growth in \clisp{} programs, or modules, available to the CL +community: the Perl and Java communities are able to contribute code +to repositories, with minimal fear of collision, because of the +hierarchical nature of the name spaces used by the contributed code. +We want the Lisp community to benefit from shared modules in the same +way. +\end{itemize} + +In a nutshell, a dot (\verb|.|) is used to separate levels in package +names, and a leading dot signifies a relative package name. The choice +of dot follows Java. Perl, another language with hierarchical +packages, uses a colon (\verb|:|) as a delimiter, but the colon is +already reserved in \clisp{}. Absolute package names require no +modifications to the underlying \clisp{} implementation. Relative +package names require only small and simple modifications. + + +\subsection{Relative Package Names} + +Relative package names are needed for the same reason as relative +pathnames, for brevity and to reduce the brittleness of absolute +names. A relative package name is one that begins with one or more +dots. A single dot means the current package, two dots mean the parent +of the current package, and so on. + +Table~\ref{tbl:hierarchical-packages} presents a number of examples, +assuming that the packages named \verb|foo|, \verb|foo.bar|, +\verb|mypack|, \verb|mypack.foo|, \verb|mypack.foo.bar|, +\verb|mypack.foo.baz|, \verb|mypack.bar|, and \verb|mypack.bar.baz|, +have all been created. + +\begin{table}[h] +\begin{center} +\begin{tabular}{|l|l|l|} +\hline +relative name & current package & absolute name of referenced package \\ +\hline +foo & any & foo \\ +foo.bar & any & foo.bar \\ +.foo & mypack & mypack.foo \\ + .foo.bar & mypack & mypack.foo.bar \\ + ..foo & mypack.bar & mypack.foo \\ + ..foo.baz & mypack.bar & mypack.foo.baz \\ + ...foo & mypack.bar.baz & mypack.foo \\ + . & mypack.bar.baz & mypack.bar.baz \\ + .. & mypack.bar.baz & mypack.bar \\ + ... & mypack.bar.baz & mypack \\ +\hline +\end{tabular} +\end{center} +\caption{Examples of hierarchical packages} +\label{tbl:hierarchical-packages} +\end{table} + +Additional notes: + +\begin{enumerate} +\item +All packages in the hierarchy must exist. + +\item +\textbf{Warning about nicknames}: Unless you provide nicknames for +your hierarchical packages (and we recommend against doing so because +the number gets quite large), you can only use the names supplied. You +cannot mix in nicknames or alternate names. \code{cl-user} +is nickname of the \code{common-lisp-user} package. +Consider the following: + +\begin{verbatim} + (defpackage :cl-user.foo) +\end{verbatim} + +When the current package (the value of the variable \code{*package*}) +is \code{common-lisp-user}, you might expect \verb|.foo| to refer to +\verb|cl-user.foo|, but it does not. It actually refers to the non-existent +package \verb|common-lisp-user.foo|. Note that the purpose of +nicknames is to provide shorter names in place of the longer names +that are designed to be fully descriptive. The hope is that +hierarchical packages makes longer names unnecessary and thus makes +nicknames unnecessary. + +\item +Multiple dots can only appear at the beginning of a package name. For +example, \verb|foo.bar..baz| does not mean \verb|foo.baz| -- it is +invalid. (Of course, it is perfectly legal to name a package +\verb|foo.bar..baz|, but \code{cl:find-package} will not process such +a name to find \verb|foo.baz| in the package hierarchy.) +\end{enumerate} + + +\subsection{Compatibility with ANSI \clisp{}} + +The implementation of hierarchical packages modifies the +\code{cl:find-package} function, and provides certain auxiliary +functions, \code{package-parent}, \code{package-children}, and +\code{relative-package-name-to-package}, as described in this section. +The function \code{defpackage} itself requires no modification. + +While the changes to \code{cl:find-package} are small and described +below, it is an important consideration for authors who would like +their programs to run on a variety of implementations that using +hierarchical packages will work in an implementation without the +modifications discussed in this document. We show why after +describing the changes to \code{cl:find-package}. + +Absolute hierarchical package names require no changes in the +underlying \clisp{} implementation. + + +\subsubsection{Changes to \code{cl:find-package}} + +Using relative hierarchical package names requires a simple +modification of \code{cl:find-package}. + +In ANSI \clisp{}, \code{cl:find-package}, if passed a package object, +returns it; if passed a string, \code{cl:find-package} looks for a +package with that string as its name or nickname, and returns the +package if it finds one, or returns nil if it does not; if passed a +symbol, the symbol name (a string) is extracted and +\code{cl:find-package} proceeds as it does with a string. + +For implementing hierarchical packages, the behavior when the argument +is a package object (return it) does not change. But when the argument +is a string starting with one or more dots not directly naming a +package, \code{cl:find-package} will, instead of returning nil, check +whether the string can be resolved as naming a relative package, and +if so, return the associated absolute package object. (If the argument +is a symbol, the symbol name is extracted and \code{cl:find-package} +proceeds as it does with a string argument.) + +Note that you should not use leading dots in package names when using +hierarchical packages. + +\subsubsection{Using Hierarchical Packages without Modifying cl:find-package} + +Even without the modifications to \code{cl:find-package}, authors need +not avoid using relative package names, but the ability to reuse +relative package names is restricted. Consider for example a module +\textit{foo} which is composed of the \verb|my.foo.bar| and +\verb|my.foo.baz| packages. In the code for each of the these packages +there are relative package references, \verb|..bar| and \verb|..baz|. + +Implementations that have the new \code{cl:find-package} would have +\verb|:relative-package-names| on their \code{*features*} +list (this is the case of \cmucl{} releases starting from 18d). Then, +in the \textit{foo} module, there would be definitions of the +\verb|my.foo.bar| and \verb|my.foo.baz| packages like so: + +\begin{verbatim} + (defpackage :my.foo.bar + #-relative-package-names (:nicknames #:..bar) + ...) + + (defpackage :my.foo.baz + #-relative-package-names (:nicknames #:..baz) + ...) +\end{verbatim} + +Then, in a \verb|#-relative-package-names| implementation, the symbol +\verb|my.foo.bar:blam| would be visible from \verb|my.foo.baz| as +\verb|..bar:blam|, just as it would from a +\verb|#+relative-package-names| implementation. + +So, even without the implementation of the augmented +\code{cl:find-package}, one can still write \clisp{} code that will +work in both types of implementations, but \verb|..bar| and +\verb|..baz| are now used, so you cannot also have +\verb|otherpack.foo.bar| and \verb|otherpack.foo.baz| and use +\verb|..bar| and \verb|..baz| as relative names. (The point of +hierarchical packages, of course, is to allow reusing relative package +names.) + diff --git a/doc/cmu-user/internet.tex b/doc/cmu-user/internet.tex new file mode 100644 index 0000000000..da9f13e0df --- /dev/null +++ b/doc/cmu-user/internet.tex @@ -0,0 +1,341 @@ +\chapter{Networking Support} +\label{internet} + +\credits{by Mario S. Mommer} + +This chapter documents the IPv4 networking and local sockets support +offered by \cmucl{}. It covers most of the basic sockets interface +functionality in a convenient and transparent way. + +For reasons of space it would be impossible to include a thorough +introduction to network programming, so we assume some basic knowledge +of the matter. + +\section{Byte Order Converters} + +These are the functions that convert integers from host byte order to +network byte order (big-endian). + +\begin{defun}{extensions:}{htonl}{% + \args{\var{integer}}} + + Converts a $32$ bit integer from host byte order to network byte + order. + +\end{defun} + +\begin{defun}{extensions:}{htons}{% + \args{\var{integer}}} + + Converts a $16$ bit integer from host byte order to network byte + order. + +\end{defun} + +\begin{defun}{extensions:}{ntohs}{% + \args{\var{integer}}} + + Converts a $32$ bit integer from network byte order to host + byte order. + +\end{defun} + +\begin{defun}{extensions:}{ntohl}{% + \args{\var{integer}}} + + Converts a $32$ bit integer from network byte order to host byte + order. + +\end{defun} + +\section{Domain Name Services (DNS)} + +The networking support of \cmucl{} includes the possibility of doing +DNS lookups. The function + +\begin{defun}{extensions:}{lookup-host-entry}{% + \args{\var{host}}} + + returns a structure of type \var{host-entry} (explained below) for + the given \var{host}. If \var{host} is an integer, it will be + assumed to be the IP address in host (byte-)order. If it is a string, + it can contain either the host name or the IP address in dotted + format. + + This function works by completing the structure \var{host-entry}. + That is, if the user provides the IP address, then the structure will + contain that information and also the domain names. If the user + provides the domain name, the structure will be complemented with + the IP addresses along with the any aliases the host might have. + +\end{defun} + +\newpage + +\begin{deftp}{structure}{host-entry}\args{\var{name} \var{aliases} + \var{addr-type} \var{addr-list}} + + This structure holds all information available at request time on a + given host. The entries are self-explanatory. Aliases is a list of + strings containing alternative names of the host, and addr-list a + list of addresses stored in host byte order. The field + \var{addr-type} contains the number of the address family, as + specified in {\tt socket.h}, to which the addresses belong. Since + only addresses of the IPv4 family are currently supported, this slot + always has the value $2$. + +\end{deftp} + +\begin{defun}{extensions:}{ip-string}{% + \args{\var{addr}}} + + This function takes an IP address in host order and returns a string + containing it in dotted format. + +\end{defun} + +\section{Binding to Interfaces} + +In this section, functions for creating sockets bound to an interface +are documented. + +\begin{defun}{extensions:}{create-inet-listener}{% + \args{\var{port} \ampoptional{} \var{kind} % + \keys{\kwd{reuse-address} \kwd{backlog} \kwd{host}}}} + + Creates a socket and binds it to a port, prepared to receive + connections of kind \var{kind} (which defaults to \kwd{stream}), + queuing up to \var{backlog} of them. If \kwd{reuse-address} \var{T} + is used, the option SO\_REUSEADDR is used in the call to \var{bind}. + If no value is given for \kwd{host}, it will try to bind to the + default IP address of the machine where the Lisp process is running. + +\end{defun} + +\begin{defun}{extensions:}{create-unix-listener}{% + \args{\var{path} \ampoptional{} \var{kind} \keys{ + \kwd{backlog}}}} + + Creates a socket and binds it to the file name given by \var{path}, + prepared to receive connections of kind \var{kind} (which defaults + to \kwd{stream}), queuing up to \var{backlog} of them. +% If +% \kwd{reuse-address} \var{T} is used, then the file given by +% \var{path} is unlinked first. + +\end{defun} + +\section{Accepting Connections} + +Once a socket is bound to its interface, we have to explicitly accept +connections. This task is performed by the functions we document here. + +\begin{defun}{extensions:}{accept-tcp-connection}{% + \args{\var{unconnected}}} + + Waits until a connection arrives on the (internet family) socket + \var{unconnected}. Returns the file descriptor of the connection. + These can be conveniently encapsulated using file descriptor + streams; see \ref{sec:fds}. + +\end{defun} + +\begin{defun}{extensions:}{accept-unix-connection}{% + \args{\var{unconnected}}} + + Waits until a connection arrives on the (unix family) socket + \var{unconnected}. Returns the file descriptor of the connection. + These can be conveniently encapsulated using file descriptor + streams; see \ref{sec:fds}. + +\end{defun} + +\begin{defun}{extensions:}{accept-network-stream}{% + \args{\var{socket} \keys{\kwd{buffering} \kwd{timeout} \kwd{wait-max}}}} + + Accept a connect from the specified \var{socket} and returns a stream + connected to connection. +\end{defun} + +\section{Connecting} + +The task performed by the functions we present next is connecting to +remote hosts. + +\begin{defun}{extensions:}{connect-to-inet-socket}{% + \args{\var{host} \var{port} \ampoptional{} \var{kind} + \keys{\kwd{local-host} \kwd{local-port}}}} + + Tries to open a connection to the remote host \var{host} (which may + be an IP address in host order, or a string with either a host name + or an IP address in dotted format) on port \var{port}. Returns the + file descriptor of the connection. The optional parameter + \var{kind} can be either \kwd{stream} (the default) or \kwd{datagram}. + + If \var{local-host} and \var{local-port} are specified, the socket + that is created is also bound to the specified \var{local-host} and + \var{port}. + +\end{defun} + +\begin{defun}{extensions:}{connect-to-unix-socket}{% + \args{\var{path} \ampoptional{} \var{kind}}} + + Opens a connection to the unix ``address'' given by \var{path}. + Returns the file descriptor of the connection. The type of + connection is given by \var{kind}, which can be either \kwd{stream} + (the default) or \kwd{datagram}. + +\end{defun} + +\begin{defun}{extensions:}{open-network-stream}{% + \args{\var{host} \var{port} \keys{\kwd{buffering} \kwd{timeout}}}} + + Return a stream connected to the specified \var{port} on the given \var{host}. +\end{defun} + + +\section{Out-of-Band Data} +\label{internet-oob} + +Out-of-band data is data transmitted with a higher priority than +ordinary data. This is usually used by either side of the connection +to signal exceptional conditions. Due to the fact that most TCP/IP +implementations are broken in this respect, only single characters can +reliably be sent this way. + +\begin{defun}{extensions:}{add-oob-handler}{% + \args{\var{fd} \var{char} \var{handler}}} + + Sets the function passed in \var{handler} as a handler for the + character \var{char} on the connection whose descriptor is \var{fd}. + In case this character arrives, the function in \var{handler} is + called without any argument. + +\end{defun} + +\begin{defun}{extensions:}{remove-oob-handler}{% + \args{\var{fd} \var{char}}} + + Removes the handler for the character \var{char} from the connection + with the file descriptor \var{fd} + +\end{defun} + +\begin{defun}{extensions:}{remove-all-oob-handlers}{% + \args{\var{fd}}} + + After calling this function, the connection whose descriptor is + \var{fd} will ignore any out-of-band character it receives. + +\end{defun} + +\begin{defun}{extensions:}{send-character-out-of-band}{% + \args{\var{fd} \var{char}}} + + Sends the character \var{char} through the connection \var{fd} out + of band. + +\end{defun} + +\section{Unbound Sockets, Socket Options, and Closing Sockets} + +These functions create unbound sockets. This is usually not necessary, +since connectors and listeners create their own. + +\begin{defun}{extensions:}{create-unix-socket}{% + \args{\ampoptional{} \var{type}}} + + Creates a unix socket for the unix address family, of type + \var{:stream} and (on success) returns its file descriptor. + +\end{defun} + +\begin{defun}{extensions:}{create-inet-socket}{% + \args{\ampoptional{} \var{kind}}} + + Creates a unix socket for the internet address family, of type + \var{:stream} and (on success) returns its file descriptor. + +\end{defun} +\bigskip + +Once a socket is created, it is sometimes useful to bind the socket to a +local address using \code{bind-inet-socket}: + +\begin{defun}{extensions:}{bind-inet-socket}{% + \args{\var{socket} \var{host} \var{port}}} + + Bind the \var{socket} to a local interface address specified + by \var{host} and \var{port}. + +\end{defun} +\bigskip + +Further, it is desirable to be able to change socket options. This is +performed by the following two functions, which are essentially +wrappers for system calls to {\tt getsockopt} and {\tt setsockopt}. + +\begin{defun}{extensions:}{get-socket-option}{% + \args{\var{socket} \var{level} \var{optname}}} + + Gets the value of option \var{optname} from the socket \var{socket}. + +\end{defun} + +\begin{defun}{extensions:}{set-socket-option}{% + \args{\var{socket} \var{level} \var{optname} \var{optval}}} + + Sets the value of option \var{optname} from the socket \var{socket} + to the value \var{optval}. + +\end{defun} +\bigskip + +For information on possible options and values we refer to the +manpages of {\tt getsockopt} and {\tt setsockopt}, and to {\tt + socket.h} + +Finally, the function + +\begin{defun}{extensions:}{close-socket}{% + \args{\var{socket}}} + + Closes the socket given by the file descriptor \var{socket}. + +\end{defun} + +\section{Unix Datagrams} + +Datagram network is supported with the following functions. + +\begin{defun}{extensions:}{inet-recvfrom}{% + \args{\var{fd} \var{buffer} \var{size}} + \keys{\kwd{flags}}} + A simple interface to the Unix \code{recvfrom} function. Returns + three values: bytecount, source address as integer, and source + port. Bytecount can of course be negative, to indicate faults. +\end{defun} + +\begin{defun}{extensions:}{inet-sendto}{% + \args{\var{fd} \var{buffer} \var{size} \var{addr} \var{port}} + \keys{\kwd{flags}}} + A simple interface to the Unix \code{sendto} function. +\end{defun} + +\begin{defun}{extensions:}{inet-shutdown}{% + \args{\var{fd} \var{level}}} + + A simple interface to the Unix \code{shutdown} function. For + \code{level}, you may use the following symbols to close one or + both ends of a socket: \code{shut-rd}, \code{shut-wr}, + \code{shut-rdwr}. + +\end{defun} + +\section{Errors} + +Errors that occur during socket operations signal a +\code{socket-error} condition, a subtype of the \code{error} +condition. Currently this condition includes just the Unix +\code{errno} associated with the error. diff --git a/doc/cmu-user/introduction.tex b/doc/cmu-user/introduction.tex new file mode 100644 index 0000000000..9711e7242f --- /dev/null +++ b/doc/cmu-user/introduction.tex @@ -0,0 +1,357 @@ +\chapter{Introduction} + +\cmucl{} is a free, high-performance implementation of the Common Lisp +programming language which runs on most major Unix platforms. It +mainly conforms to the ANSI Common Lisp standard. Here is a summary of +its main features: + +\begin{itemize} +\item a {\em sophisticated native-code compiler} which is capable of +powerful type inferences, and generates code competitive in speed with +C compilers. + +\item generational garbage collection and multiprocessing +capability on the x86 ports. + +\item a foreign function interface which allows interfacing with C code and +system libraries, including shared libraries on most platforms, and +direct access to Unix system calls. + +\item support for interprocess communication and remote procedure +calls. + +\item an implementation of CLOS, the Common Lisp Object System, which +includes multimethods and a metaobject protocol. + +\item a graphical source-level debugger using a Motif interface, and a +code profiler. + +\item an interface to the X11 Window System (CLX), and a sophisticated +graphical widget library (Garnet). + +\item programmer-extensible input and output streams. + +\item an Emacs-like editor implemented in Common Lisp. + +\item public domain: free, with full source code and no +strings attached (and no warranty). Like GNU/Linux and the *BSD +operating systems, \cmucl{} is maintained and improved by a team of +volunteers collaborating over the Internet. +\end{itemize} + + +This user's manual contains only implementation-specific information +about \cmucl. Users will also need a separate manual describing the +\clisp{} standard, for example, the +\ifpdf +\href{http://www.lispworks.com/documentation/HyperSpec/Front/index.htm} +{Hyperspec}. +\else +\emph{Hyperspec} at \url{http://www.lispworks.com/documentation/HyperSpec/Front/index.htm} +\fi + + +In addition to the language itself, this document describes a number +of useful library modules that run in \cmucl. \hemlock, an Emacs-like +text editor, is included as an integral part of the \cmucl{} +environment. Two documents describe \hemlock{}: the {\it Hemlock +User's Manual}, and the {\it Hemlock Command Implementor's Manual}. + + +\section{Distribution and Support} + +\cmucl{} is developed and maintained by a group of volunteers who +collaborate over the internet. Sources and binary releases for the +various supported platforms can be obtained from +\href{http://www.cons.org/cmucl/}{www.cons.org/cmucl}. These pages +describe how to download by FTP or CVS. + +A number of mailing lists are available for users and developers; +please see the web site for more information. + + +\section{Command Line Options} +\cindex{command line options} +\label{command-line-options} + +The command line syntax and environment is described in the +\verb|lisp(1)| man page in the man/man1 directory of the distribution. +See also \verb|cmucl(1)|. Currently \cmucl{} accepts the following +switches: + +\begin{Lentry} +\item[\code{-{}-help}] Same as \code{-help}. + +\item[\code{-help}] Print ou the command line options and exit. + +\item[\code{-batch}] specifies batch mode, where all input is + directed from standard-input. An error code of 0 is returned upon + encountering an EOF and 1 otherwise. + +\item[\code{-quiet}] enters quiet mode. This implies setting the + variables \code{*load-verbose*}, \code{*compile-verbose*}, + \code{*compile-print*}, \code{*compile-progress*}, + \code{*require-verbose*} and \code{*gc-verbose*} to NIL, and + disables the printing of the startup banner. + +\item[\code{-core}] requires an argument that should be the name of a + core file. Rather than using the default core file, which is searched + in a number of places, according to the initial value of the + \code{library:} search-list, the specified core file is loaded. This + switch overrides the value of the \code{CMUCLCORE} environment variable, + if present. + +\item[\code{-lib}] requires an argument that should be the path to the + CMUCL library directory, which is going to be used to initialize the + \code{library:} search-list, among other things. This switch overrides + the value of the \code{CMUCLLIB} environment variable, if present. + +\item[\code{-dynamic-space-size}] requires an argument that should be + the number of megabytes (1048576 bytes) that should be allocated to + the heap. If not specified, a platform-specific default is used. + The actual maximum allowed heap size is platform-specific. + + Currently, this option is only available for the x86 and sparc + platforms. + +\item[\code{-edit}] specifies to enter Hemlock. A file to edit may be + specified by placing the name of the file between the program name + (usually \file{lisp}) and the first switch. + +\item[\code{-eval}] accepts one argument which should be a Lisp form + to evaluate during the start up sequence. The value of the form + will not be printed unless it is wrapped in a form that does output. + +\item[\code{-hinit}] accepts an argument that should be the name of + the hemlock init file to load the first time the function + \findexed{ed} is invoked. The default is to load + \file{hemlock-init.\var{object-type}}, or if that does not exist, + \file{hemlock-init.lisp} from the user's home directory. If the + file is not in the user's home directory, the full path must be + specified. + +\item[\code{-init}] accepts an argument that should be the name of an + init file to load during the normal start up sequence. The default + is to load \file{init.\var{object-type}} or, if that does not exist, + \file{init.lisp} from the user's home directory. If neither exists, + \cmucl tries \file{.cmucl-init.\var{object-type}} and then + \file{.cmucl-init.lisp}. If the file is not + in the user's home directory, the full path must be specified. If + the file does not exist, \cmucl silently ignores it. + +\item[\code{-noinit}] accepts no arguments and specifies that an init + file should not be loaded during the normal start up sequence. + Also, this switch suppresses the loading of a hemlock init file when + Hemlock is started up with the \code{-edit} switch. + +\item[\code{-nositeinit}] accepts no arguments and specifies that the + site init file should not be loaded during the normal start up + sequence. + +\item[\code{-load}] accepts an argument which should be the name of a + file to load into Lisp before entering Lisp's read-eval-print loop. + +\item[\code{-slave}] specifies that Lisp should start up as a + \i{slave} Lisp and try to connect to an editor Lisp. The name of + the editor to connect to must be specified\dash{}to find the + editor's name, use the \hemlock{} ``\code{Accept Slave + Connections}'' command. The name for the editor Lisp is of the + form: + \begin{example} + \var{machine-name}\code{:}\var{socket} + \end{example} + where \var{machine-name} is the internet host name for the machine + and \var{socket} is the decimal number of the socket to connect to. + +\item[\code{-fpu}] specifies what fpu should be used for x87 machines. + The possible values are ``\code{x87}'', ``\code{sse2}'', or + ``\code{auto}'', which is the default. By default, \cmucl will + detect if the chip supports the SSE2 instruction set or not. If so + or if \code{-fpu sse2} is specified, the SSE2 core will be loaded + that uses SSE2 for floating-point arithmetic. If SSE2 is not + available or if \code{-fpu x87} is given, the legacy x87 core is + loaded. + +\item[\code{--}] indicates that everything after ``\code{--}'' is not + subject to \cmucl's command line parsing. Everything after + ``\code{--}'' is placed in the variable + \code{ext:*command-line-application-arguments*}. +\end{Lentry} + +For more details on the use of the \code{-edit} and \code{-slave} +switches, see the {\it Hemlock User's Manual}. + +Arguments to the above switches can be specified in one of two ways: +\w{\var{switch}\code{=}\var{value}} or +\w{\var{switch}<\var{space}>\var{value}}. For example, to start up +the saved core file mylisp.core use either of the following two +commands: + +\begin{example} + lisp -core=mylisp.core + lisp -core mylisp.core +\end{example} + + +\section{Credits} + +\cmucl{} was developed at the Computer Science Department of Carnegie +Mellon University. The work was a small autonomous part within the +Mach microkernel-based operating system project, and started more as a +tool development effort than a research project. The project started +out as Spice Lisp, which provided a modern Lisp implementation for use +in the CMU community. \cmucl{} has been under continual development since +the early 1980's (concurrent with the \clisp{} standardization +effort). Most of the CMU Common Lisp implementors went on to work on +the Gwydion environment for Dylan. The CMU team was lead by Scott E. +Fahlman, the \python{} compiler was written by Robert MacLachlan. + +\cmucl{}'s CLOS implementation is derived from the PCL reference +implementation written at Xerox PARC: +\begin{quotation} +\noindent Copyright (c) 1985, 1986, 1987, 1988, 1989, 1990 Xerox +Corporation.\\ +All rights reserved. + +\vspace{1ex} +\noindent Use and copying of this software and preparation of +derivative works based upon this software are permitted. Any +distribution of this software or derivative works must comply with all +applicable United States export control laws. + +\vspace{1ex} +\noindent This software is made available AS IS, and Xerox Corporation +makes no warranty about the software, its performance or its +conformity to any specification. +\end{quotation} +Its implementation of the LOOP macro was derived from code from +Symbolics, which was derived from code written at MIT: +\begin{quotation} +\noindent Portions of LOOP are Copyright (c) 1986 by the Massachusetts +Institute of Technology.\\ +All Rights Reserved. + +\vspace{1ex} +\noindent Permission to use, copy, modify and distribute this software +and its documentation for any purpose and without fee is hereby granted, +provided that the M.I.T. copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation. The names "M.I.T." and "Massachusetts +Institute of Technology" may not be used in advertising or publicity +pertaining to distribution of the software without specific, written +prior permission. Notice must be given in supporting documentation that +copying distribution is by permission of M.I.T. M.I.T. makes no +representations about the suitability of this software for any purpose. +It is provided "as is" without express or implied warranty. + +\vspace{3ex} +\noindent Portions of LOOP are Copyright (c) 1989, 1990, 1991, 1992 by +Symbolics, Inc.\\ +All Rights Reserved. + +\vspace{1ex} +\noindent Permission to use, copy, modify and distribute this software +and its documentation for any purpose and without fee is hereby +granted, provided that the Symbolics copyright notice appear in all +copies and that both that copyright notice and this permission notice +appear in supporting documentation. The name "Symbolics" may not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. Notice must be +given in supporting documentation that copying distribution is by +permission of Symbolics. Symbolics makes no representations about the +suitability of this software for any purpose. It is provided "as is" +without express or implied warranty. + +\vspace{1ex} +\noindent Symbolics, CLOE Runtime, and Minima are trademarks, and +CLOE, Genera, and Zetalisp are registered trademarks of Symbolics, +Inc. +\end{quotation} +The CLX code is copyrighted by Texas Instruments Incorporated: +\begin{quotation} +\noindent Copyright (C) 1987 Texas Instruments Incorporated. + +\vspace{1ex} +\noindent Permission is granted to any individual or institution to +use, copy, modify, and distribute this software, provided that this +complete copyright and permission notice is maintained, intact, in all +copies and supporting documentation. + +\vspace{1ex} +\noindent Texas Instruments Incorporated provides this software "as +is" without express or implied warranty. +\end{quotation} + +\cmucl{} was funded by DARPA under CMU's "Research on Parallel Computing" +contract. Rather than doing pure research on programming languages and +environments, the emphasis was on developing practical programming +tools. Sometimes this required new technology, but much of the work +was in creating a \clisp{} environment that incorporates +state-of-the-art features from existing systems (both Lisp and +non-Lisp). Archives of the project are available online. + +The project funding stopped in 1994, so support at Carnegie Mellon +University has been discontinued. All code and documentation developed +at CMU was released into the public domain. The project continues as a +group of users and developers collaborating over the Internet. The +current and previous maintainers include: + +\begin{itemize} +\item Marco Antoniotti +\item Martin Cracauer +\item Fred Gilham +\item Alex Goncharov +\item Rob MacLachlan +\item Pierre Mai +\item Eric Marsden +\item Gerd Moellman +\item Tim Moore +\item Carl Shapiro +\item Robert Swindells +\item Raymond Toy +\item Peter Van Eynde +\item Paul Werkowski +\end{itemize} + +In particular, Paul Werkowski and Douglas Crosher completed the port +for the x86 architecture for FreeBSD. Peter VanEnyde took the FreeBSD +port and created a Linux version. Other people who have contributed to +the development of \cmucl{} since 1981 are + +\begin{itemize} +\item David Axmark +\item Miles Bader +\item Rick Busdiecker +\item Bill Chiles +\item Douglas Thomas Crosher +\item Casper Dik +\item Ted Dunning +\item Scott Fahlman +\item Mike Garland +\item Paul Gleichauf +\item Sean Hallgren +\item Richard Harris +\item Joerg-Cyril Hoehl +\item Chris Hoover +\item John Kolojejchick +\item Todd Kaufmann +\item Simon Leinen +\item Sandra Loosemore +\item William Lott +\item Dave McDonald +\item Tim Moore +\item Skef Wholey +\item Paul Foley +\item Helmut Eller +\item Jan Rychter +\end{itemize} + +Countless others have contributed to the project by sending in bug +reports, bug fixes, and new features. + +This manual is based on CMU Technical Report CMU-CS-92-161, edited by +Robert A. MacLachlan, dated July 1992. Other contributors include +Raymond Toy, Paul Werkowski and Eric Marsden. The Hierarchical +Packages chapter is based on documentation written by Franz. Inc, and +is used with permission. The remainder of the document is in the +public domain. diff --git a/doc/cmu-user/ipc.tex b/doc/cmu-user/ipc.tex new file mode 100644 index 0000000000..6becab088d --- /dev/null +++ b/doc/cmu-user/ipc.tex @@ -0,0 +1,414 @@ +\chapter{Interprocess Communication under LISP} +\label{remote} + +\credits{by William Lott and Bill Chiles} + + +\cmucl{} offers a facility for interprocess communication (IPC) +on top of using Unix system calls and the complications of that level +of IPC. There is a simple remote-procedure-call (RPC) package build +on top of TCP/IP sockets. + + +\section{The REMOTE Package} + +The \code{remote} package provides simple RPC facility including +interfaces for creating servers, connecting to already existing +servers, and calling functions in other Lisp processes. The routines +for establishing a connection between two processes, +\code{create-request-server} and \code{connect-to-remote-server}, +return \var{wire} structures. A wire maintains the current state of +a connection, and all the RPC forms require a wire to indicate where +to send requests. + + +\subsection{Connecting Servers and Clients} + +Before a client can connect to a server, it must know the network address on +which the server accepts connections. Network addresses consist of a host +address or name, and a port number. Host addresses are either a string of the +form \code{VANCOUVER.SLISP.CS.CMU.EDU} or a 32 bit unsigned integer. Port +numbers are 16 bit unsigned integers. Note: \var{port} in this context has +nothing to do with Mach ports and message passing. + +When a process wants to receive connection requests (that is, become a +server), it first picks an integer to use as the port. Only one server +(Lisp or otherwise) can use a given port number on a given machine at +any particular time. This can be an iterative process to find a free +port: picking an integer and calling \code{create-request-server}. This +function signals an error if the chosen port is unusable. You will +probably want to write a loop using \code{handler-case}, catching +conditions of type error, since this function does not signal more +specific conditions. + +\begin{defun}{wire:}{create-request-server}{% + \args{\var{port} \ampoptional{} \var{on-connect}}} + + \code{create-request-server} sets up the current Lisp to accept + connections on the given port. If port is unavailable for any + reason, this signals an error. When a client connects to this port, + the acceptance mechanism makes a wire structure and invokes the + \var{on-connect} function. Invoking this function has a couple of + purposes, and \var{on-connect} may be \nil{} in which case the + system foregoes invoking any function at connect time. + + The \var{on-connect} function is both a hook that allows you access + to the wire created by the acceptance mechanism, and it confirms the + connection. This function takes two arguments, the wire and the + host address of the connecting process. See the section on host + addresses below. When \var{on-connect} is \nil, the request server + allows all connections. When it is non-\nil, the function returns + two values, whether to accept the connection and a function the + system should call when the connection terminates. Either value may + be \nil, but when the first value is \nil, the acceptance mechanism + destroys the wire. + + \code{create-request-server} returns an object that + \code{destroy-request-server} uses to terminate a connection. +\end{defun} + +\begin{defun}{wire:}{destroy-request-server}{\args{\var{server}}} + + \code{destroy-request-server} takes the result of + \code{create-request-server} and terminates that server. Any + existing connections remain intact, but all additional connection + attempts will fail. +\end{defun} + +\begin{defun}{wire:}{connect-to-remote-server}{% + \args{\var{host} \var{port} \ampoptional{} \var{on-death}}} + + \code{connect-to-remote-server} attempts to connect to a remote + server at the given \var{port} on \var{host} and returns a wire + structure if it is successful. If \var{on-death} is non-\nil, it is + a function the system invokes when this connection terminates. +\end{defun} + + +\subsection{Remote Evaluations} + +After the server and client have connected, they each have a wire +allowing function evaluation in the other process. This RPC mechanism +has three flavors: for side-effect only, for a single value, and for +multiple values. + +Only a limited number of data types can be sent across wires as +arguments for remote function calls and as return values: integers +inclusively less than 32 bits in length, symbols, lists, and +\var{remote-objects} (\pxlref{remote-objs}). The system sends symbols +as two strings, the package name and the symbol name, and if the +package doesn't exist remotely, the remote process signals an error. +The system ignores other slots of symbols. Lists may be any tree of +the above valid data types. To send other data types you must +represent them in terms of these supported types. For example, you +could use \code{prin1-to-string} locally, send the string, and use +\code{read-from-string} remotely. + +\begin{defmac}{wire:}{remote}{% + \args{\var{wire} \mstar{call-specs}}} + + The \code{remote} macro arranges for the process at the other end of + \var{wire} to invoke each of the functions in the \var{call-specs}. + To make sure the system sends the remote evaluation requests over + the wire, you must call \code{wire-force-output}. + + Each of \var{call-specs} looks like a function call textually, but + it has some odd constraints and semantics. The function position of + the form must be the symbolic name of a function. \code{remote} + evaluates each of the argument subforms for each of the + \var{call-specs} locally in the current context, sending these + values as the arguments for the functions. + + Consider the following example: + +\begin{verbatim} +(defun write-remote-string (str) + (declare (simple-string str)) + (wire:remote wire + (write-string str))) +\end{verbatim} + + The value of \code{str} in the local process is passed over the wire + with a request to invoke \code{write-string} on the value. The + system does not expect to remotely evaluate \code{str} for a value + in the remote process. +\end{defmac} + +\begin{defun}{wire:}{wire-force-output}{\args{\var{wire}}} + + \code{wire-force-output} flushes all internal buffers associated + with \var{wire}, sending the remote requests. This is necessary + after a call to \code{remote}. +\end{defun} + +\begin{defmac}{wire:}{remote-value}{\args{\var{wire} \var{call-spec}}} + + The \code{remote-value} macro is similar to the \code{remote} macro. + \code{remote-value} only takes one \var{call-spec}, and it returns + the value returned by the function call in the remote process. The + value must be a valid type the system can send over a wire, and + there is no need to call \code{wire-force-output} in conjunction + with this interface. + + If client unwinds past the call to \code{remote-value}, the server + continues running, but the system ignores the value the server sends + back. + + If the server unwinds past the remotely requested call, instead of + returning normally, \code{remote-value} returns two values, \nil{} + and \true. Otherwise this returns the result of the remote + evaluation and \nil. +\end{defmac} + +\begin{defmac}{wire:}{remote-value-bind}{% + \args{\var{wire} (\mstar{variable}) \var{remote-form} + \mstar{local-forms}}} + + \code{remote-value-bind} is similar to \code{multiple-value-bind} + except the values bound come from \var{remote-form}'s evaluation in + the remote process. The \var{local-forms} execute in an implicit + \code{progn}. + + If the client unwinds past the call to \code{remote-value-bind}, the + server continues running, but the system ignores the values the + server sends back. + + If the server unwinds past the remotely requested call, instead of + returning normally, the \var{local-forms} never execute, and + \code{remote-value-bind} returns \nil. +\end{defmac} + + +\subsection{Remote Objects} +\label{remote-objs} + +The wire mechanism only directly supports a limited number of data +types for transmission as arguments for remote function calls and as +return values: integers inclusively less than 32 bits in length, +symbols, lists. Sometimes it is useful to allow remote processes to +refer to local data structures without allowing the remote process +to operate on the data. We have \var{remote-objects} to support +this without the need to represent the data structure in terms of +the above data types, to send the representation to the remote +process, to decode the representation, to later encode it again, and +to send it back along the wire. + +You can convert any Lisp object into a remote-object. When you send +a remote-object along a wire, the system simply sends a unique token +for it. In the remote process, the system looks up the token and +returns a remote-object for the token. When the remote process +needs to refer to the original Lisp object as an argument to a +remote call back or as a return value, it uses the remote-object it +has which the system converts to the unique token, sending that +along the wire to the originating process. Upon receipt in the +first process, the system converts the token back to the same +(\code{eq}) remote-object. + +\begin{defun}{wire:}{make-remote-object}{\args{\var{object}}} + + \code{make-remote-object} returns a remote-object that has + \var{object} as its value. The remote-object can be passed across + wires just like the directly supported wire data types. +\end{defun} + +\begin{defun}{wire:}{remote-object-p}{\args{\var{object}}} + + The function \code{remote-object-p} returns \true{} if \var{object} + is a remote object and \nil{} otherwise. +\end{defun} + +\begin{defun}{wire:}{remote-object-local-p}{\args{\var{remote}}} + + The function \code{remote-object-local-p} returns \true{} if + \var{remote} refers to an object in the local process. This is can + only occur if the local process created \var{remote} with + \code{make-remote-object}. +\end{defun} + +\begin{defun}{wire:}{remote-object-eq}{\args{\var{obj1} \var{obj2}}} + + The function \code{remote-object-eq} returns \true{} if \var{obj1} and + \var{obj2} refer to the same (\code{eq}) lisp object, regardless of + which process created the remote-objects. +\end{defun} + +\begin{defun}{wire:}{remote-object-value}{\args{\var{remote}}} + + This function returns the original object used to create the given + remote object. It is an error if some other process originally + created the remote-object. +\end{defun} + +\begin{defun}{wire:}{forget-remote-translation}{\args{\var{object}}} + + This function removes the information and storage necessary to + translate remote-objects back into \var{object}, so the next + \code{gc} can reclaim the memory. You should use this when you no + longer expect to receive references to \var{object}. If some remote + process does send a reference to \var{object}, + \code{remote-object-value} signals an error. +\end{defun} + + +% This stuff has been moved to internet.tex. *** Remove me someday *** +% \subsection{Host Addresses} + +% The operating system maintains a database of all the valid host +% addresses. You can use this database to convert between host names +% and addresses and vice-versa. + +% \begin{defun}{ext:}{lookup-host-entry}{\args{\var{host}}} + +% \code{lookup-host-entry} searches the database for the given +% \var{host} and returns a host-entry structure for it. If it fails +% to find \var{host} in the database, it returns \nil. \var{Host} is +% either the address (as an integer) or the name (as a string) of the +% desired host. +% \end{defun} + +% \begin{defun}{ext:}{host-entry-name}{\args{\var{host-entry}}} +% \defunx[ext:]{host-entry-aliases}{\args{\var{host-entry}}} +% \defunx[ext:]{host-entry-addr-list}{\args{\var{host-entry}}} +% \defunx[ext:]{host-entry-addr}{\args{\var{host-entry}}} + +% \code{host-entry-name}, \code{host-entry-aliases}, and +% \code{host-entry-addr-list} each return the indicated slot from the +% host-entry structure. \code{host-entry-addr} returns the primary +% (first) address from the list returned by +% \code{host-entry-addr-list}. +% \end{defun} + + +\section{The WIRE Package} + +The \code{wire} package provides for sending data along wires. The +\code{remote} package sits on top of this package. All data sent +with a given output routine must be read in the remote process with +the complementary fetching routine. For example, if you send so a +string with \code{wire-output-string}, the remote process must know +to use \code{wire-get-string}. To avoid rigid data transfers and +complicated code, the interface supports sending +\var{tagged} data. With tagged data, the system sends a tag +announcing the type of the next data, and the remote system takes +care of fetching the appropriate type. + +When using interfaces at the wire level instead of the RPC level, +the remote process must read everything sent by these routines. If +the remote process leaves any input on the wire, it will later +mistake the data for an RPC request causing unknown lossage. + + +\subsection{Untagged Data} + +When using these routines both ends of the wire know exactly what types are +coming and going and in what order. This data is restricted to the following +types: + +\begin{itemize} +\item +8 bit unsigned bytes. + +\item +32 bit unsigned bytes. + +\item +32 bit integers. + +\item +simple-strings less than 65535 in length. +\end{itemize} + +\begin{defun}{wire:}{wire-output-byte}{\args{\var{wire} \var{byte}}} + \defunx[wire:]{wire-get-byte}{\args{\var{wire}}} + \defunx[wire:]{wire-output-number}{\args{\var{wire} \var{number}}} + \defunx[wire:]{wire-get-number}{\args{\var{wire} \ampoptional{} + \var{signed}}} + \defunx[wire:]{wire-output-string}{\args{\var{wire} \var{string}}} + \defunx[wire:]{wire-get-string}{\args{\var{wire}}} + + These functions either output or input an object of the specified + data type. When you use any of these output routines to send data + across the wire, you must use the corresponding input routine + interpret the data. +\end{defun} + + +\subsection{Tagged Data} + +When using these routines, the system automatically transmits and interprets +the tags for you, so both ends can figure out what kind of data transfers +occur. Sending tagged data allows a greater variety of data types: integers +inclusively less than 32 bits in length, symbols, lists, and \var{remote-objects} +(\pxlref{remote-objs}). The system sends symbols as two strings, the +package name and the symbol name, and if the package doesn't exist remotely, +the remote process signals an error. The system ignores other slots of +symbols. Lists may be any tree of the above valid data types. To send other +data types you must represent them in terms of these supported types. For +example, you could use \code{prin1-to-string} locally, send the string, and use +\code{read-from-string} remotely. + +\begin{defun}{wire:}{wire-output-object}{% + \args{\var{wire} \var{object} \ampoptional{} \var{cache-it}}} + \defunx[wire:]{wire-get-object}{\args{\var{wire}}} + + The function \code{wire-output-object} sends \var{object} over + \var{wire} preceded by a tag indicating its type. + + If \var{cache-it} is non-\nil, this function only sends \var{object} + the first time it gets \var{object}. Each end of the wire + associates a token with \var{object}, similar to remote-objects, + allowing you to send the object more efficiently on successive + transmissions. \var{cache-it} defaults to \true{} for symbols and + \nil{} for other types. Since the RPC level requires function + names, a high-level protocol based on a set of function calls saves + time in sending the functions' names repeatedly. + + The function \code{wire-get-object} reads the results of + \code{wire-output-object} and returns that object. +\end{defun} + + +\subsection{Making Your Own Wires} + +You can create wires manually in addition to the \code{remote} +package's interface creating them for you. To create a wire, you need +a Unix {\em file descriptor}. If you are unfamiliar with Unix file +descriptors, see section 2 of the Unix manual pages. + +\begin{defun}{wire:}{make-wire}{\args{\var{descriptor}}} + + The function \code{make-wire} creates a new wire when supplied with + the file descriptor to use for the underlying I/O operations. +\end{defun} + +\begin{defun}{wire:}{wire-p}{\args{\var{object}}} + + This function returns \true{} if \var{object} is indeed a wire, + \nil{} otherwise. +\end{defun} + +\begin{defun}{wire:}{wire-fd}{\args{\var{wire}}} + + This function returns the file descriptor used by the \var{wire}. +\end{defun} + + +\section{Out-Of-Band Data} + +The TCP/IP protocol allows users to send data asynchronously, otherwise +known as \var{out-of-band} data. When using this feature, the operating +system interrupts the receiving process if this process has chosen to be +notified about out-of-band data. The receiver can grab this input +without affecting any information currently queued on the socket. +Therefore, you can use this without interfering with any current +activity due to other wire and remote interfaces. + +Unfortunately, most implementations of TCP/IP are broken, so use of +out-of-band data is limited for safety reasons. You can only reliably +send one character at a time. + +The Wire package is built on top of \cmucl{}s networking support. In +view of this, it is possible to use the routines described in section +\ref{internet-oob} for handling and sending out-of-band data. These +all take a Unix file descriptor instead of a wire, but you can fetch a +wire's file descriptor with \code{wire-fd}. diff --git a/doc/cmu-user/latex2html.tex b/doc/cmu-user/latex2html.tex new file mode 100644 index 0000000000..428d14f108 --- /dev/null +++ b/doc/cmu-user/latex2html.tex @@ -0,0 +1,56 @@ +%% Replacement commands when we run latex2html. This should be last +%% so that latex2html uses these commands instead of the LaTeX +%% commands above. +\usepackage{makeidx} + +\newcommand{\var}[1]{\textnormal{\textit{#1}}} +\newcommand{\code}[1]{\textnormal{\texttt{#1}}} +%%\newcommand{\printindex}[1][\mbox{}]{} + +%% We need the quote environment because the alltt is broken. The +%% quote environment helps us in postprocessing to result to get +%% what we want. +\newenvironment{example}{\begin{quote}\begin{alltt}}{\end{alltt}\end{quote}} +\newenvironment{display}{\begin{quote}\begin{alltt}}{\end{alltt}\end{quote}} + +\newcommand{\textnormal}[1]{\rm #1} +\newcommand{\hbox}[1]{\mbox{#1}} +\newcommand{\xspace}{} +\newcommand{newindex}[4]{} + +\newcommand{\pxlref}[1]{see section~\ref{#1}} +\newcommand{\xlref}[1]{See section~\ref{#1}} + +\newcommand{\tindexed}[1]{\index{#1}\texttt{#1}} +\newcommand{\findexed}[1]{\index{#1}\texttt{#1}} +\newcommand{\vindexed}[1]{\index{#1}\texttt{*#1*}} +\newcommand{\cindex}[1]{\index{#1}} +\newcommand{\cpsubindex}[2]{\index{#1!#2}} + +\newcommand{\keys}[1]{\texttt{\&key} #1} +\newcommand{\morekeys}[1]{#1} +\newcommand{\yetmorekeys}[1]{#1} + +\newenvironment{defun}[3]{% + \textbf{[Function]}\\ + \texttt{#1#2} \emph{#3}\\}{} +\newcommand{\defunx}[3][\mbox{}]{% + \texttt{#1#2} {\em #3}\\} +\newenvironment{defmac}[3]{% + \textbf{[Macro]}\\ + \texttt{#1#2} \emph{#3}\\}{} +\newcommand{\defmacx}[3][\mbox{}]{% + \texttt{#1#2} {\em #3}\\} +\newenvironment{defvar}[2]{% + \textbf{[Variable]}\\ + \texttt{#1*#2*}\\ \\}{} +\newcommand{\defvarx}[2][\mbox{}]{% + \texttt{#1*#2*}\\} +\newenvironment{defconst}[2]{% + \textbf{[Constant]}\\ + \texttt{#1#2}\\}{} +\newcommand{\defconstx}[2][\mbox{}]{\texttt{#1#2}\\} +\newenvironment{deftp}[3]{% + \textbf{[#1]}\\ + \texttt{#2} \textit{#3}\\}{} +\newenvironment{Lentry}{\begin{description}}{\end{description}} diff --git a/doc/cmu-user/macros.tex b/doc/cmu-user/macros.tex new file mode 100644 index 0000000000..bfb1669cf6 --- /dev/null +++ b/doc/cmu-user/macros.tex @@ -0,0 +1,284 @@ +% macro.tex +% +% LaTeX macros for CMUCL User's Manual +% +% by Raymond Toy + +% use Palatino +\renewcommand{\rmdefault}{ppl} +\ifpdf +\usepackage{palatino} +\fi + +%% Define the indices. We need one for Types, Variables, Functions, +%% and a general concept index. +\makeindex +\newindex{types}{tdx}{tnd}{Type Index} +\newindex{vars}{vdx}{vnd}{Variable Index} +\newindex{funs}{fdx}{fnd}{Function Index} +\newindex{concept}{cdx}{cnd}{Concept Index} + +\newcommand{\tindexed}[1]{\index[types]{#1}\code{#1}} +\newcommand{\findexed}[1]{\index[funs]{#1}\code{#1}} +\newcommand{\vindexed}[1]{\index[vars]{#1}\code{*#1*}} +\newcommand{\cindex}[1]{\index[concept]{#1}} +\newcommand{\cpsubindex}[2]{\index[concept]{#1!#2}} + + +%% This code taken from the LaTeX companion. It's meant as a +%% replacement for the description environment. We want one that +%% prints description items in a fixed size box and puts the +%% description itself on the same line or the next depending on the +%% size of the item. +\newcommand{\entrylabel}[1]{\mbox{#1}\hfil} +\newenvironment{entry}{% + \begin{list}{}% + {\renewcommand{\makelabel}{\entrylabel}% + \setlength{\labelwidth}{45pt}% + \setlength{\leftmargin}{\labelwidth+\labelsep}}}% + {\end{list}} + +\newlength{\Mylen} +\newcommand{\Lentrylabel}[1]{% + \settowidth{\Mylen}{#1}% + \ifthenelse{\lengthtest{\Mylen > \labelwidth}}% + {\parbox[b]{\labelwidth}% term > labelwidth + {\makebox[0pt][l]{#1}\\}}% + {#1}% + \hfil\relax} +\newenvironment{Lentry}{% + \renewcommand{\entrylabel}{\Lentrylabel} + \begin{entry}}% + {\end{entry}} + +\newcommand{\fcntype}[1]{\textit{#1}} +\newcommand{\argtype}[1]{\textit{#1}} +\newcommand{\fcnname}[1]{\textsf{#1}} + +\newlength{\formnamelen} % length of a name of a form +\newlength{\pboxargslen} % length of parbox for arguments +\newlength{\typelen} % length of the type label for the form + +\newcommand{\args}[1]{#1} +\newcommand{\keys}[1]{\code{\&key} \= #1} +\newcommand{\morekeys}[1]{\\ \> #1} +\newcommand{\yetmorekeys}[1]{\\ \> #1} + +\newcommand{\defunvspace}{\ifhmode\unskip \par\fi\addvspace{18pt plus 12pt minus 6pt}} + + +%% \layout[pkg]{name}{param list}{type} +%% +%% This lays out a entry like so: +%% +%% pkg:name arg1 arg2 [Function] +%% +%% where [Function] is flush right. +%% +\newcommand{\layout}[4][\mbox{}]{% + \par\noindent + \fcnname{#1#2\hspace{1em}}% + \settowidth{\formnamelen}{\fcnname{#1#2\hspace{1em}}}% + \settowidth{\typelen}{[\argtype{#4}]}% + \setlength{\pboxargslen}{\linewidth}% + \addtolength{\pboxargslen}{-1\formnamelen}% + \addtolength{\pboxargslen}{-1\typelen}% + \begin{minipage}[t]{\pboxargslen} + \begin{tabbing} + #3 + \end{tabbing} + \end{minipage} + \hfill[\fcntype{#4}]% + \par\addvspace{2pt plus 2pt minus 2pt}} + +\newcommand{\vrindexbold}[1]{\index[vars]{#1|textbf}} +\newcommand{\fnindexbold}[1]{\index[funs]{#1|textbf}} + +%% Define a new type +%% +%% \begin{deftp}{typeclass}{typename}{args} +%% some description +%% \end{deftp} +\newenvironment{deftp}[3]{% + \par\bigskip\index[types]{#2|textbf}% + \layout{#2}{\var{#3}}{#1} + }{} + +%% Define a function with name NAME and given parameters PARAM. The +%% function is in the package PKG. If the optional arg SUFFIX is +%% given, this is used as a suffix for the label. (Useful when you +%% have functions of the same name, such as methods, but want +%% different labels for each version.) +%% +%% The defunx is for additional functions that are related to this one +%% in some way, and we want to group them all together. +%% +%% \begin{defun}[suffix]{pkg}{name}{params} +%% \defunx[pkg]{name}{params} +%% description of function +%% \end{defun} +\newenvironment{defun}[4][]{% + \par\defunvspace\fnindexbold{#3}\label{FN:#3#1}% + \layout[#2]{#3}{#4}{Function} + }{} +\newcommand{\defunx}[3][\mbox{}]{% + \par\fnindexbold{#2}\label{FN:#2}% + \layout[#1]{#2}{#3}{Function}} + +%% Define a generic function. Like defun, but for defgeneric. +%% +%% \begin{defgeneric}[suffix]{pkg}{name}{params} +%% \defgenericx[pkg]{name}{params} +%% description of function +%% \end{defgeneric} +\newenvironment{defgeneric}[4][]{% + \par\defunvspace\fnindexbold{#3}\label{FN:#3-generic#1}% + \layout[#2]{#3}{#4}{Generic Function} + }{} +\newcommand{\defgenericx}[3][\mbox{}]{% + \par\fnindexbold{#2}\label{FN:#2}% + \layout[#1]{#2}{#3}{Generic Function}} + +%% Define a method. Like defgeneric, but for methods. +%% +%% \begin{defmethod}[suffix]{pkg}{name}{params} +%% \defmethod[pkg]{name}{params} +%% description of function +%% \end{defmethod} +\newenvironment{defmethod}[4][]{% + \par\defunvspace\fnindexbold{#3}\label{FN:#3-method#1}% + \layout[#2]{#3}{#4}{Method} + }{} +\newcommand{\defmethodx}[3][\mbox{}]{% + \par\fnindexbold{#2}\label{FN:#2}% + \layout[#1]{#2}{#3}{Method}} + +%% Define a macro +%% +%% \begin{defmac}[suffix]{pkg}{name}{params} +%% \defmacx[pkg]{name}{params} +%% description of macro +%% \end{defmac} +\newenvironment{defmac}[4][]{% + \par\defunvspace\fnindexbold{#3}\label{FN:#3#1}% + \layout[#2]{#3}{#4}{Macro}}{} +\newcommand{\defmacx}[3][\mbox{}]{% + \par\fnindexbold{#2}\label{FN:#2}% + \layout[#1]{#2}{#3}{Macro}} + +%% Define a variable +%% +%% \begin{defvar}{pkg}{name} +%% \defvarx[pkg]{name} +%% description of defvar +%% \end{defvar} +\newenvironment{defvar}[2]{% + \par\defunvspace\vrindexbold{#2}\label{VR:#2} + \layout[#1]{*#2*}{}{Variable}}{} +\newcommand{\defvarx}[2][\mbox{}]{% + \par\vrindexbold{#2}\label{VR:#2} + \layout[#1]{*#2*}{}{Variable}} + +%% Define a constant +%% +%% \begin{defconst}{pkg}{name} +%% \ddefconstx[pkg]{name} +%% description of defconst +%% \end{defconst} +\newcommand{\defconstx}[2][\mbox{}]{% + \layout[#1]{#2}{}{Constant}} +\newenvironment{defconst}[2]{% + \defunvspace\defconstx[#1]{#2}}{} + +\newcommand{\credits}[1]{% + \begin{center} + \textbf{#1} + \end{center}} + +\newenvironment{example}{\begin{quote}\begin{alltt}}{\end{alltt}\end{quote}} +\newenvironment{lisp}{\begin{example}}{\end{example}} + +\newcommand{\hide}[1]{} +\newcommand{\trnumber}[1]{#1} +\newcommand{\citationinfo}[1]{#1} +\newcommand{\var}[1]{{\textsf{\textsl{#1}}\xspace}} +\newcommand{\code}[1]{\textnormal{{\sffamily #1}}} +\newcommand{\file}[1]{`\texttt{#1}'} +\newcommand{\kwd}[1]{\code{:#1}} +\newcommand{\F}[1]{\code{#1}} +\newcommand{\w}[1]{\hbox{#1}} +\newcommand{\ctrl}[1]{$\uparrow$\textsf{#1}} +\newcommand{\result}{$\Rightarrow$} +\newcommand{\myequiv}{$\equiv$} +\newcommand{\back}[1]{\(\backslash\)#1} +\newcommand{\pxlref}[1]{see section~\ref{#1}, page~\pageref{#1}} +\newcommand{\xlref}[1]{See section~\ref{#1}, page~\pageref{#1}} +\newcommand{\funref}[1]{\findexed{#1} (page~\pageref{FN:#1})} +\newcommand{\specref}[1]{\findexed{#1} (page~\pageref{FN:#1})} +\newcommand{\macref}[1]{\findexed{#1} (page~\pageref{FN:#1})} +\newcommand{\varref}[1]{\vindexed{#1} (page~\pageref{VR:#1})} +\newcommand{\conref}[1]{\conindexed{#1} (page~\pageref{VR:#1})} + +\newcommand{\false}{\code{nil}} +\newcommand{\true}{\code{t}} +\newcommand{\nil}{\false{}} +%% Printed lisp character #\foo +\newcommand{\lispchar}[1]{\code{\#\back{#1}}} + +\newcommand{\ampoptional}{\code{\&optional}} +\newcommand{\amprest}{\code{\&rest}} +\newcommand{\ampbody}{\code{\&body}} + +\newcommand{\mopt}[1]{{$\,\{$}\textnormal{\textsf{\textsl{#1\/}}}{$\}\,$}} +\newcommand{\mstar}[1]{{$\,\{$}\textnormal{\textsf{\textsl{#1\/}}}{$\}^*\,$}} +\newcommand{\mplus}[1]{{$\,\{$}\textnormal{\textsf{\textsl{#1\/}}}{$\}^+\,$}} +\newcommand{\mgroup}[1]{{$\,\{$}\textnormal{\textsf{\textsl{#1\/}}}{$\}\,$}} +\newcommand{\mor}{$|$} + + +%% Some common abbreviations +\newcommand{\dash}{---} +\newcommand{\alien}{Alien} +\newcommand{\aliens}{Aliens} +\newcommand{\hemlock}{Hemlock} +\newcommand{\python}{Python} +\newcommand{\cmucl}{\textsc{cmucl}} +\newcommand{\clisp}{Common Lisp} +\newcommand{\llisp}{Common Lisp} +\newcommand{\cltl}{\textit{Common Lisp: The Language}} +\newcommand{\cltltwo}{\textit{Common Lisp: The Language II}} + + +%% Set up margins +\setlength{\oddsidemargin}{-10pt} +\setlength{\evensidemargin}{-10pt} +\setlength{\topmargin}{-40pt} +\setlength{\headheight}{12pt} +\setlength{\headsep}{25pt} +\setlength{\footskip}{30pt} +\setlength{\textheight}{9.25in} +\setlength{\textwidth}{6.75in} +\setlength{\columnsep}{0.375in} +\setlength{\columnseprule}{0pt} + + +\setcounter{tocdepth}{2} +\setcounter{secnumdepth}{3} +\def\textfraction{.1} +\def\bottomfraction{.9} % was .3 +\def\topfraction{.9} + +%% Allow TeX some stretching space to avoid overfull and underfull +%% boxes. +\setlength{\emergencystretch}{5pt} + +%% requires the sectsty package +\allsectionsfont{\bfseries\sffamily} +\chapterfont{\fontfamily{pag}\selectfont} + +%% section numbers in the left margin +\makeatletter +\def\@seccntformat#1{\protect\makebox[0pt][r]{\csname + the#1\endcsname\quad}} +\makeatother + diff --git a/doc/cmu-user/next_motif.gif b/doc/cmu-user/next_motif.gif new file mode 100644 index 0000000000..3f84bacfb2 Binary files /dev/null and b/doc/cmu-user/next_motif.gif differ diff --git a/doc/cmu-user/package-locks.tex b/doc/cmu-user/package-locks.tex new file mode 100644 index 0000000000..aa73f5d312 --- /dev/null +++ b/doc/cmu-user/package-locks.tex @@ -0,0 +1,124 @@ +\section{Package Locks} +\cindex{package locks} + +\cmucl{} provides two types of package locks, as an extension to the +ANSI Common Lisp standard. The package-lock protects a package from +changes in its structure (the set of exported symbols, its use list, +etc). The package-definition-lock protects the symbols in the package +from being redefined due to the execution of a \code{defun}, +\code{defmacro}, \code{defstruct}, \code{deftype} or \code{defclass} +form. + + +\subsection{Rationale} + +Package locks are an aid to program development, by helping to detect +inadvertent name collisions and function redefinitions. They are +consistent with the principle that a package ``belongs to'' its +implementor, and that noone other than the package's developer should +be making or modifying definitions on symbols in that package. Package +locks are compatible with the ANSI Common Lisp standard, which states +that the consequences of redefining functions in the +\code{COMMON-LISP} package are undefined. + +Violation of a package lock leads to a continuable error of type +\code{lisp::package-locked-error} being signaled. The user may choose +to ignore the lock and proceed, or to abort the computation. Two other +restarts are available, one which disables all locks on all packages, +and one to disable only the package-lock or package-definition-lock +that was tripped. + +The following transcript illustrates the behaviour seen when +attempting to redefine a standard macro in the \code{COMMON-LISP} +package, or to redefine a function in one of \cmucl{}'s +implementation-defined packages: + +{\small +\begin{verbatim} +CL-USER> (defmacro 1+ (x) (* x 2)) +Attempt to modify the locked package COMMON-LISP, by defining macro 1+ + [Condition of type LISP::PACKAGE-LOCKED-ERROR] + +Restarts: + 0: [continue ] Ignore the lock and continue + 1: [unlock-package] Disable the package's definition-lock then continue + 2: [unlock-all ] Unlock all packages, then continue + 3: [abort ] Return to Top-Level. + +CL-USER> (defun ext:gc () t) +Attempt to modify the locked package EXTENSIONS, by redefining function GC + [Condition of type LISP::PACKAGE-LOCKED-ERROR] + +Restarts: + 0: [continue ] Ignore the lock and continue + 1: [unlock-package] Disable package's definition-lock, then continue + 2: [unlock-all ] Disable all package locks, then continue + 3: [abort ] Return to Top-Level. +\end{verbatim} + + +The following transcript illustrates the behaviour seen when an +attempt to modify the structure of a package is made: + +\begin{verbatim} +CL-USER> (unexport 'load-foreign :ext) +Attempt to modify the locked package EXTENSIONS, by unexporting symbols LOAD-FOREIGN + [Condition of type lisp::package-locked-error] + +Restarts: + 0: [continue ] Ignore the lock and continue + 1: [unlock-package] Disable package's lock then continue + 2: [unlock-all ] Unlock all packages, then continue + 3: [abort ] Return to Top-Level. +\end{verbatim} +} + +The \code{COMMON-LISP} package and the \cmucl{}-specific +implementation packages are locked on startup. Users can lock their +own packages by using the \code{ext:package-lock} and +\code{ext:package-definition-lock} accessors. + + + +\subsection{Disabling package locks} + +A package's locks can be enabled or disabled by using the +\code{ext:package-lock} and \code{ext:package-definition-lock} +accessors, as follows: + +\begin{lisp} + (setf (ext:package-lock (find-package "UNIX")) nil) + (setf (ext:package-definition-lock (find-package "UNIX")) nil) +\end{lisp} + + +\begin{defun}{ext:}{package-lock}{\var{package}} + This function is an accessor for a package's structural lock, which + protects it against modifications to its list of exported symbols. +\end{defun} + + +\begin{defun}{ext:}{package-definition-lock}{\var{package}} + This function is an accessor for a package's definition-lock, which + protects symbols in that package from redefinition. As well as + protecting the symbol's fdefinition from change, attempts to change + the symbol's definition using \code{defstruct}, \code{defclass} or + \code{deftype} will be trapped. +\end{defun} + + +\begin{defmac}{ext:}{without-package-locks}{\args{\amprest{} \var{body}}} + This macro can be used to execute forms with all package locks (both + structure and definition locks) disabled. +\end{defmac} + + +\begin{defun}{ext:}{unlock-all-packages}{} + This function disables both structure and definition locks on all + currently defined packages. Note that package locks are reset when + \cmucl{} is restarted, so the effect of this function is limited to + the current session. +\end{defun} + + +% EOF diff --git a/doc/cmu-user/previous_motif.gif b/doc/cmu-user/previous_motif.gif new file mode 100644 index 0000000000..8c8a3e6430 Binary files /dev/null and b/doc/cmu-user/previous_motif.gif differ diff --git a/doc/cmu-user/serve-event.tex b/doc/cmu-user/serve-event.tex new file mode 100644 index 0000000000..bf4d8aa172 --- /dev/null +++ b/doc/cmu-user/serve-event.tex @@ -0,0 +1,575 @@ +\chapter{Event Dispatching with SERVE-EVENT} +\label{serve-event} + +\credits{by Bill Chiles and Robert MacLachlan} + + +It is common to have multiple activities simultaneously operating in the same +Lisp process. Furthermore, Lisp programmers tend to expect a flexible +development environment. It must be possible to load and modify application +programs without requiring modifications to other running programs. \cmucl{} +achieves this by having a central scheduling mechanism based on an +event-driven, object-oriented paradigm. + +An \var{event} is some interesting happening that should cause the Lisp process +to wake up and do something. These events include X events and activity on +Unix file descriptors. The object-oriented mechanism is only available with +the first two, and it is optional with X events as described later in this +chapter. In an X event, the window ID is the object capability and the X event +type is the operation code. The Unix file descriptor input mechanism simply +consists of an association list of a handler to call when input shows up on a +particular file descriptor. + + +\section{Object Sets} +\label{object-sets} +\cindex{object sets} + +An {\em object set} is a collection of objects that have the same implementation +for each operation. Externally the object is represented by the object +capability and the operation is represented by the operation code. Within +Lisp, the object is represented by an arbitrary Lisp object, and the +implementation for the operation is represented by an arbitrary Lisp function. +The object set mechanism maintains this translation from the external to the +internal representation. + +\begin{defun}{system:}{make-object-set}{% + \args{\var{name} \ampoptional{} \var{default-handler}}} + + This function makes a new object set. \var{Name} is a string used + only for purposes of identifying the object set when it is printed. + \var{Default-handler} is the function used as a handler when an + undefined operation occurs on an object in the set. You can define + operations with the \code{serve-}\var{operation} functions exported + the \code{extensions} package for X events + (\pxlref{x-serve-mumbles}). Objects are added with + \code{system:add-xwindow-object}. Initially the object set has no + objects and no defined operations. +\end{defun} + +\begin{defun}{system:}{object-set-operation}{% + \args{\var{object-set} \var{operation-code}}} + + This function returns the handler function that is the + implementation of the operation corresponding to + \var{operation-code} in \var{object-set}. When set with + \code{setf}, the setter function establishes the new handler. The + \code{serve-}\var{operation} functions exported from the + \code{extensions} package for X events (\pxlref{x-serve-mumbles}) + call this on behalf of the user when announcing a new operation for + an object set. +\end{defun} + +\begin{defun}{system:}{add-xwindow-object}{% + \args{\var{window} \var{object} \var{object-set}}} + + These functions add \var{port} or \var{window} to \var{object-set}. + \var{Object} is an arbitrary Lisp object that is associated with the + \var{port} or \var{window} capability. \var{Window} is a CLX + window. When an event occurs, \code{system:serve-event} passes + \var{object} as an argument to the handler function. +\end{defun} + + +\section{The SERVE-EVENT Function} + +The \code{system:serve-event} function is the standard way for an application +to wait for something to happen. For example, the Lisp system calls +\code{system:serve-event} when it wants input from X or a terminal stream. +The idea behind \code{system:serve-event} is that it knows the appropriate +action to take when any interesting event happens. If an application calls +\code{system:serve-event} when it is idle, then any other applications with +pending events can run. This allows several applications to run ``at the +same time'' without interference, even though there is only one thread of +control. Note that if an application is waiting for input of any kind, +then other applications will get events. + +\begin{defun}{system:}{serve-event}{\args{\ampoptional{} \var{timeout}}} + + This function waits for an event to happen and then dispatches to + the correct handler function. If specified, \var{timeout} is the + number of seconds to wait before timing out. A time out of zero + seconds is legal and causes \code{system:serve-event} to poll for + any events immediately available for processing. + \code{system:serve-event} returns \true{} if it serviced at least + one event, and \nil{} otherwise. Depending on the application, when + \code{system:serve-event} returns \true, you might want to call it + repeatedly with a timeout of zero until it returns \nil. + + If input is available on any designated file descriptor, then this + calls the appropriate handler function supplied by + \code{system:add-fd-handler}. + + Since events for many different applications may arrive + simultaneously, an application waiting for a specific event must + loop on \code{system:serve-event} until the desired event happens. + Since programs such as \hemlock{} call \code{system:serve-event} for + input, applications usually do not need to call + \code{system:serve-event} at all; \hemlock{} allows other + application's handlers to run when it goes into an input wait. +\end{defun} + +\begin{defun}{system:}{serve-all-events}{\args{\ampoptional{} \var{timeout}}} + + This function is similar to \code{system:serve-event}, except it + serves all the pending events rather than just one. It returns + \true{} if it serviced at least one event, and \nil{} otherwise. +\end{defun} + + +\section{Using SERVE-EVENT with Unix File Descriptors} + +Object sets are not available for use with file descriptors, as there are +only two operations possible on file descriptors: input and output. +Instead, a handler for either input or output can be registered with +\code{system:serve-event} for a specific file descriptor. Whenever any input +shows up, or output is possible on this file descriptor, the function +associated with the handler for that descriptor is funcalled with the +descriptor as it's single argument. + +\begin{defun}{system:}{add-fd-handler}{% + \args{\var{fd} \var{direction} \var{function}}} + + This function installs and returns a new handler for the file + descriptor \var{fd}. \var{direction} can be either \kwd{input} if + the system should invoke the handler when input is available or + \kwd{output} if the system should invoke the handler when output is + possible. This returns a unique object representing the handler, + and this is a suitable argument for \code{system:remove-fd-handler} + \var{function} must take one argument, the file descriptor. +\end{defun} + +\begin{defun}{system:}{remove-fd-handler}{\args{\var{handler}}} + + This function removes \var{handler}, that \code{add-fd-handler} must + have previously returned. +\end{defun} + +\begin{defmac}{system:}{with-fd-handler}{% + \args{(\var{fd} \var{direction} \var{function}) + \mstar{\var{form}}}} + + This macro executes the supplied forms with a handler installed + using \var{fd}, \var{direction}, and \var{function}. See + \code{system:add-fd-handler}. The given forms are wrapped in an + \code{unwind-protect}; the handler is removed (see + \code{system:remove-fd-handler}) when done. +\end{defmac} + +\begin{defun}{system:}{wait-until-fd-usable}{% + \args{\var{fd} \var{direction} \ampoptional{} \var{timeout}}} + + This function waits for up to \var{timeout} seconds for \var{fd} to + become usable for \var{direction} (either \kwd{input} or + \kwd{output}). If \var{timeout} is \nil{} or unspecified, this + waits forever. +\end{defun} + +\begin{defun}{system:}{invalidate-descriptor}{\args{\var{fd}}} + + This function removes all handlers associated with \var{fd}. This + should only be used in drastic cases (such as I/O errors, but not + necessarily EOF). Normally, you should use \code{remove-fd-handler} + to remove the specific handler. +\end{defun} + + + + +\section{Using SERVE-EVENT with the CLX Interface to X} +\label{x-serve-mumbles} + +Remember from section \ref{object-sets}, an object set is a collection of +objects, CLX windows in this case, with some set of operations, event keywords, +with corresponding implementations, the same handler functions. Since X allows +multiple display connections from a given process, you can avoid using object +sets if every window in an application or display connection behaves the same. +If a particular X application on a single display connection has windows that +want to handle certain events differently, then using object sets is a +convenient way to organize this since you need some way to map the window/event +combination to the appropriate functionality. + +The following is a discussion of functions exported from the \code{extensions} +package that facilitate handling CLX events through \code{system:serve-event}. +The first two routines are useful regardless of whether you use +\code{system:serve-event}: +\begin{defun}{ext:}{open-clx-display}{% + \args{\ampoptional{} \var{string}}} + + This function parses \var{string} for an X display specification + including display and screen numbers. \var{String} defaults to the + following: + \begin{example} + (cdr (assoc :display ext:*environment-list* :test #'eq)) + \end{example} + If any field in the display specification is missing, this signals + an error. \code{ext:open-clx-display} returns the CLX display and + screen. +\end{defun} + +\begin{defun}{ext:}{flush-display-events}{\args{\var{display}}} + + This function flushes all the events in \var{display}'s event queue + including the current event, in case the user calls this from within + an event handler. +\end{defun} + + + +\subsection{Without Object Sets} + +Since most applications that use CLX, can avoid the complexity of object sets, +these routines are described in a separate section. The routines described in +the next section that use the object set mechanism are based on these +interfaces. + +\begin{defun}{ext:}{enable-clx-event-handling}{% + \args{\var{display} \var{handler}}} + + This function causes \code{system:serve-event} to notice when there + is input on \var{display}'s connection to the X11 server. When this + happens, \code{system:serve-event} invokes \var{handler} on + \var{display} in a dynamic context with an error handler bound that + flushes all events from \var{display} and returns. By returning, + the error handler declines to handle the error, but it will have + cleared all events; thus, entering the debugger will not result in + infinite errors due to streams that wait via + \code{system:serve-event} for input. Calling this repeatedly on the + same \var{display} establishes \var{handler} as a new handler, + replacing any previous one for \var{display}. +\end{defun} + +\begin{defun}{ext:}{disable-clx-event-handling}{\args{\var{display}}} + + This function undoes the effect of + \code{ext:enable-clx-event-handling}. +\end{defun} + +\begin{defmac}{ext:}{with-clx-event-handling}{% + \args{(\var{display} \var{handler}) \mstar{form}}} + + This macro evaluates each \var{form} in a context where + \code{system:serve-event} invokes \var{handler} on \var{display} + whenever there is input on \var{display}'s connection to the X + server. This destroys any previously established handler for + \var{display}. +\end{defmac} + + +\subsection{With Object Sets} + +This section discusses the use of object sets and +\code{system:serve-event} to handle CLX events. This is necessary +when a single X application has distinct windows that want to handle +the same events in different ways. Basically, you need some way of +asking for a given window which way you want to handle some event +because this event is handled differently depending on the window. +Object sets provide this feature. + +For each CLX event-key symbol-name \i{XXX} (for example, +\var{key-press}), there is a function \code{serve-}\i{XXX} of two +arguments, an object set and a function. The \code{serve-}\i{XXX} +function establishes the function as the handler for the \kwd{XXX} +event in the object set. Recall from section \ref{object-sets}, +\code{system:add-xwindow-object} associates some Lisp object with a +CLX window in an object set. When \code{system:serve-event} notices +activity on a window, it calls the function given to +\code{ext:enable-clx-event-handling}. If this function is +\code{ext:object-set-event-handler}, it calls the function given to +\code{serve-}\i{XXX}, passing the object given to +\code{system:add-xwindow-object} and the event's slots as well as a +couple other arguments described below. + +To use object sets in this way: + +\begin{itemize} +\item Create an object set. + +\item Define some operations on it using the \code{serve-}\i{XXX} + functions. + +\item Add an object for every window on which you receive requests. + This can be the CLX window itself or some structure more meaningful + to your application. + +\item Call \code{system:serve-event} to service an X event. +\end{itemize} + + +\begin{defun}{ext:}{object-set-event-handler}{% + \args{\var{display}}} + + This function is a suitable argument to + \code{ext:enable-clx-event-handling}. The actual event handlers + defined for particular events within a given object set must take an + argument for every slot in the appropriate event. In addition to + the event slots, \code{ext:object-set-event-handler} passes the + following arguments: + \begin{itemize} + \item The object, as established by + \code{system:add-xwindow-object}, on which the event occurred. + \item event-key, see \code{xlib:event-case}. + \item send-event-p, see \code{xlib:event-case}. + \end{itemize} + + Describing any \code{ext:serve-}\var{event-key-name} function, where + \var{event-key-name} is an event-key symbol-name (for example, + \code{ext:serve-key-press}), indicates exactly what all the + arguments are in their correct order. + +%% \begin{comment} +%% \code{ext:object-set-event-handler} ignores \kwd{no-exposure} +%% events on pixmaps, issuing a warning if one occurs. It is only +%% prepared to dispatch events for windows. +%% \end{comment} + + When creating an object set for use with + \code{ext:object-set-event-handler}, specify + \code{ext:default-clx-event-handler} as the default handler for + events in that object set. If no default handler is specified, and + the system invokes the default default handler, it will cause an + error since this function takes arguments suitable for handling port + messages. +\end{defun} + + +\section{A SERVE-EVENT Example} + +This section contains two examples using \code{system:serve-event}. The first +one does not use object sets, and the second, slightly more complicated one +does. + +\subsection{Without Object Sets Example} + +This example defines an input handler for a CLX display connection. It only +recognizes \kwd{key-press} events. The body of the example loops over +\code{system:serve-event} to get input. + +\begin{lisp} +(in-package "SERVER-EXAMPLE") + +(defun my-input-handler (display) + (xlib:event-case (display :timeout 0) + (:key-press (event-window code state) + (format t "KEY-PRESSED (Window = ~D) = ~S.~%" + (xlib:window-id event-window) + ;; See Hemlock Command Implementor's Manual for convenient + ;; input mapping function. + (ext:translate-character display code state)) + ;; Make XLIB:EVENT-CASE discard the event. + t))) +\end{lisp} + +\begin{lisp} +(defun server-example () + "An example of using the SYSTEM:SERVE-EVENT function and object sets to + handle CLX events." + (let* ((display (ext:open-clx-display)) + (screen (display-default-screen display)) + (black (screen-black-pixel screen)) + (white (screen-white-pixel screen)) + (window (create-window :parent (screen-root screen) + :x 0 :y 0 :width 200 :height 200 + :background white :border black + :border-width 2 + :event-mask + (xlib:make-event-mask :key-press)))) + ;; Wrap code in UNWIND-PROTECT, so we clean up after ourselves. + (unwind-protect + (progn + ;; Enable event handling on the display. + (ext:enable-clx-event-handling display #'my-input-handler) + ;; Map the windows to the screen. + (map-window window) + ;; Make sure we send all our requests. + (display-force-output display) + ;; Call serve-event for 100,000 events or immediate timeouts. + (dotimes (i 100000) (system:serve-event))) + ;; Disable event handling on this display. + (ext:disable-clx-event-handling display) + ;; Get rid of the window. + (destroy-window window) + ;; Pick off any events the X server has already queued for our + ;; windows, so we don't choke since SYSTEM:SERVE-EVENT is no longer + ;; prepared to handle events for us. + (loop + (unless (deleting-window-drop-event *display* window) + (return))) + ;; Close the display. + (xlib:close-display display)))) + +(defun deleting-window-drop-event (display win) + "Check for any events on win. If there is one, remove it from the + event queue and return t; otherwise, return nil." + (xlib:display-finish-output display) + (let ((result nil)) + (xlib:process-event + display :timeout 0 + :handler #'(lambda (&key event-window &allow-other-keys) + (if (eq event-window win) + (setf result t) + nil))) + result)) +\end{lisp} + + +\subsection{With Object Sets Example} + +This example involves more work, but you get a little more for your effort. It +defines two objects, \code{input-box} and \code{slider}, and establishes a +\kwd{key-press} handler for each object, \code{key-pressed} and +\code{slider-pressed}. We have two object sets because we handle events on the +windows manifesting these objects differently, but the events come over the +same display connection. + +\begin{lisp} +(in-package "SERVER-EXAMPLE") + +(defstruct (input-box (:print-function print-input-box) + (:constructor make-input-box (display window))) + "Our program knows about input-boxes, and it doesn't care how they + are implemented." + display ; The CLX display on which my input-box is displayed. + window) ; The CLX window in which the user types. +;;; +(defun print-input-box (object stream n) + (declare (ignore n)) + (format stream "#" (input-box-display object))) + +(defvar *input-box-windows* + (system:make-object-set "Input Box Windows" + #'ext:default-clx-event-handler)) + +(defun key-pressed (input-box event-key event-window root child + same-screen-p x y root-x root-y modifiers time + key-code send-event-p) + "This is our :key-press event handler." + (declare (ignore event-key root child same-screen-p x y + root-x root-y time send-event-p)) + (format t "KEY-PRESSED (Window = ~D) = ~S.~%" + (xlib:window-id event-window) + ;; See Hemlock Command Implementor's Manual for convenient + ;; input mapping function. + (ext:translate-character (input-box-display input-box) + key-code modifiers))) +;;; +(ext:serve-key-press *input-box-windows* #'key-pressed) +\end{lisp} + +\begin{lisp} +(defstruct (slider (:print-function print-slider) + (:include input-box) + (:constructor %make-slider + (display window window-width max))) + "Our program knows about sliders too, and these provide input values + zero to max." + bits-per-value ; bits per discrete value up to max. + max) ; End value for slider. +;;; +(defun print-slider (object stream n) + (declare (ignore n)) + (format stream "#" + (input-box-display object) + (1- (slider-max object)))) +;;; +(defun make-slider (display window max) + (%make-slider display window + (truncate (xlib:drawable-width window) max) + max)) + +(defvar *slider-windows* + (system:make-object-set "Slider Windows" + #'ext:default-clx-event-handler)) + +(defun slider-pressed (slider event-key event-window root child + same-screen-p x y root-x root-y modifiers time + key-code send-event-p) + "This is our :key-press event handler for sliders. Probably this is + a mouse thing, but for simplicity here we take a character typed." + (declare (ignore event-key root child same-screen-p x y + root-x root-y time send-event-p)) + (format t "KEY-PRESSED (Window = ~D) = ~S --> ~D.~%" + (xlib:window-id event-window) + ;; See Hemlock Command Implementor's Manual for convenient + ;; input mapping function. + (ext:translate-character (input-box-display slider) + key-code modifiers) + (truncate x (slider-bits-per-value slider)))) +;;; +(ext:serve-key-press *slider-windows* #'slider-pressed) +\end{lisp} + +\begin{lisp} +(defun server-example () + "An example of using the SYSTEM:SERVE-EVENT function and object sets to + handle CLX events." + (let* ((display (ext:open-clx-display)) + (screen (display-default-screen display)) + (black (screen-black-pixel screen)) + (white (screen-white-pixel screen)) + (iwindow (create-window :parent (screen-root screen) + :x 0 :y 0 :width 200 :height 200 + :background white :border black + :border-width 2 + :event-mask + (xlib:make-event-mask :key-press))) + (swindow (create-window :parent (screen-root screen) + :x 0 :y 300 :width 200 :height 50 + :background white :border black + :border-width 2 + :event-mask + (xlib:make-event-mask :key-press))) + (input-box (make-input-box display iwindow)) + (slider (make-slider display swindow 15))) + ;; Wrap code in UNWIND-PROTECT, so we clean up after ourselves. + (unwind-protect + (progn + ;; Enable event handling on the display. + (ext:enable-clx-event-handling display + #'ext:object-set-event-handler) + ;; Add the windows to the appropriate object sets. + (system:add-xwindow-object iwindow input-box + *input-box-windows*) + (system:add-xwindow-object swindow slider + *slider-windows*) + ;; Map the windows to the screen. + (map-window iwindow) + (map-window swindow) + ;; Make sure we send all our requests. + (display-force-output display) + ;; Call server for 100,000 events or immediate timeouts. + (dotimes (i 100000) (system:serve-event))) + ;; Disable event handling on this display. + (ext:disable-clx-event-handling display) + (delete-window iwindow display) + (delete-window swindow display) + ;; Close the display. + (xlib:close-display display)))) +\end{lisp} + +\begin{lisp} +(defun delete-window (window display) + ;; Remove the windows from the object sets before destroying them. + (system:remove-xwindow-object window) + ;; Destroy the window. + (destroy-window window) + ;; Pick off any events the X server has already queued for our + ;; windows, so we don't choke since SYSTEM:SERVE-EVENT is no longer + ;; prepared to handle events for us. + (loop + (unless (deleting-window-drop-event display window) + (return)))) + +(defun deleting-window-drop-event (display win) + "Check for any events on win. If there is one, remove it from the + event queue and return t; otherwise, return nil." + (xlib:display-finish-output display) + (let ((result nil)) + (xlib:process-event + display :timeout 0 + :handler #'(lambda (&key event-window &allow-other-keys) + (if (eq event-window win) + (setf result t) + nil))) + result)) +\end{lisp} diff --git a/doc/cmu-user/simple-streams.tex b/doc/cmu-user/simple-streams.tex new file mode 100644 index 0000000000..cdb60042bf --- /dev/null +++ b/doc/cmu-user/simple-streams.tex @@ -0,0 +1,21 @@ +\section{Simple Streams} +\cindex{simple-streams} +\label{simple-streams} + +\cmucl{} includes a partial implementation of \emph{Simple Streams}, a +protocol that allows user-extensible streams\footnote{This +implementation was donated by Paul Foley}. The protocol was proposed +by Franz, Inc. and is intended to replace the \emph{Gray Streams} +method of extending streams. Simple streams are distributed as a +\cmucl{} subsystem, that can be loaded into the image by saying + +\begin{lisp} + (require :simple-streams) +\end{lisp} + +Note that CMUCL's implementation of simple streams is incomplete, and +in particular is currently missing support for the functions +\code{read-sequence} and \code{write-sequence}. Please consult the +\textit{Allegro Common Lisp} documentation for more information on +simple streams. + diff --git a/doc/cmu-user/typehtml.dtx b/doc/cmu-user/typehtml.dtx new file mode 100644 index 0000000000..0cddf95988 --- /dev/null +++ b/doc/cmu-user/typehtml.dtx @@ -0,0 +1,2364 @@ +% +% \iffalse +%% +%% Source File `typehtml.dtx'. +%% Copyright (C) 1996 1997 David Carlisle +%% This file may be distributed under the terms of the LPPL. +%% See 00readme.txt for details. +%% +% +%<*dtx> + \ProvidesFile{typehtml.dtx} +% +%\NeedsTeXFormat{LaTeX2e}[1995/06/01] +%\ProvidesPackage{typehtml} +%\ProvidesFile{typehtml.drv} +% \fi +% \ProvidesFile{typehtml.dtx} + [1997/11/19 v0.12 HTML printer (DPC)] +% +% \iffalse +%<*driver> +\documentclass{ltxdoc} +\usepackage[html3,subsection*,bigint]{typehtml} +\DocInput{typehtml.dtx} +\end{document} +% +% \fi +% +% \GetFileInfo{typehtml.dtx} +% \begin{document} +% \title{The \textsf{typehtml} package\thanks{This file +% has version number \fileversion, last +% revised \filedate.}} +% \author{David Carlisle} +% \date{\filedate} +% +% \changes{v0.01}{1996/03/06}{Initial version} +% \changes{v0.02}{1996/03/07}{Fiddling} +% \changes{v0.03}{1996/03/08}{HTML3 maths} +% \changes{v0.05}{1996/03/11} +% {change name to prevent clash with html package in latex2html} +% \changes{v0.11}{1996/03/28}{Minor improvements} +% \changes{v0.12}{1997/11/29}{Assorted changes for Bernard Gaulle, active +% french punctuation} +% \maketitle +% +% \CheckSum{2283} +% +% \section{Intoduction} +% +% This package enables the processing of HTML codes. The +% \verb|\dohtml| command +% allows fragments of HTML to be placed within a \LaTeX\ +% document, +%\begin{verbatim} +% \dohtml +% +% html markup ... +% +%\end{verbatim} +% The \verb||\ldots\verb|| is \emph{required}. (It is +% anyway a good idea to have these tags in an HTML document.) +% +% The \verb|\htmlinput| command is similar, but takes a file +% name as argument. In that case the file need not necessarily start +% and end with \verb||\ldots\verb||. +% +% This package covers most of the HTML2 DTD, together with the +% mathematics extensions from HTML3.\footnote +% {The draft specification of HTML3 has expired, and the W3C group +% are currently devising a new proposed extension of HTML, so the +% mathematics typesetting part of this package may need substantial +% revision once a final specification of the HTML mathematics markup +% is agreed.} +% The rest of HTML3 may be added at a later date. +% +% Its current incarnation has not been extensively tested, having been +% thrown together during the last couple of weeks in response to a +% question on \texttt{comp.text.tex} about the availability of such a +% package. +% +% The package falls into three sections. Firstly the options section +% allows a certain amount of customisation, and enabling of +% extensions. Not all these options are fully operational at present. +% Secondly comes a section that implements a kind of SGML parser. This +% is not a real conforming SGML parser (not even a close approximation +% to such a thing!) The assumption (sadly false in the anarchic WWW) +% is that any document will have been validated by a conforming SGML +% parser before it ever gets to the stage of being printed by this +% package. Finally are a set of declarations that essentially map the +% declarations of the HTML DTD into \LaTeX\ constructs. +% +% \section{Options} +% +% \subsection{HTML Level} +% The options \texttt{html2} (the default) and \texttt{html3} control +% HTML variant supported. Using the \texttt{html3} option will use up a +% lot more memory to support the extra features, and the math entity +% (symbol) names. Against my better judgement there is also a +% \texttt{netscape} option to allow some of the non-HTML tags accepted +% by that browser. +% +% \subsection{Headings} +% The six options \texttt{chapter}, \texttt{chapter*}, \texttt{section}, +% \texttt{section*}, \texttt{subsection} and \texttt{subsection*} +% Determine to which \LaTeX\ sectional command the HTML element +% \texttt{h1} is mapped. (\texttt{h2}--\texttt{h6} will +% automatically follow suit.) The default is \texttt{section*}. +% +% \subsection{Double Quote Handling} +% Most HTML pages use |"| as as a quotation mark in text, for +% example: +%\begin{verbatim} +% quoted "like this" example +%\end{verbatim} +% +% This slot in the ISO latin-1 encoding is for `straight' double +% quotes. Unfortunately the Standard \TeX\ fonts in the OT1 encoding +% do not have such a character, only left and right quotes, ``like +% this''. By default this package uses the \texttt{straightquotedbl} +% option which uses the \LaTeX\ command |\textquotedbl| to render +% |"|. If used with the T1 encoded fonts |\usepackage[T1]{fontenc}| +% then the straight double quote from the current font is used. With +% OT1 fonts, the double quote is taken from the |\ttfamily| font, +% which looks \texttt{"}like this\texttt{"} which is fairly +% horrible, but better than the alternative which is ''like this''. +% +% The \texttt{smartquotedbl} option redefines |"| so that it produces +% alternatively an open double quote `` then a close ''. As there is a +% chance of it becoming confused, it is reset to `` at the beginning +% of every paragraph, whatever the current mode. +% +% Neither of these options affects the use of |"| as part of the SGML +% syntax to surround attribute values. +% +% In principle the package ought to have similar options dealing with +% the single quote, but there the situation is more complicated due to +% its dual use as an apostrophe, so currently the package takes no +% special precautions: all single quotes are treated as a closing +% quote/apostrophe. Also the conventions of `open' and `close' quotes +% only really apply to English. If someone wants to suggest what the +% package should do with |"| in other languages\ldots +% +% \subsection{Images} +% The default option is \texttt{imgalt} This means that all inline +% images (the HTML \texttt{img} element) are replaced by the text +% specified by the \texttt{alt} attribute, or \textsf{[image]} if no +% such attribute is specified. +% +% The \texttt{imggif} option\footnote{one day} uses the +% \verb|\includegraphics| command so that inline images appear as +% such in the printed version. +% +% The \texttt{imgps} option\footnotemark[1] is similar to +% \texttt{imggif} but first replaces the extension \texttt{.gif} at +% the end of the source file name by \texttt{.ps}. This will enable +% drivers that can not include GIF files to be used, as long as the +% user keeps the image in both PostScript and Gif formats. +% +% \subsection{Hyperref} +% +% Several options control how the HTML anchor tag is treated. +% +% The default \texttt{nohyperref} option ignores name anchors, and +% typesets the body of src anchors using |\emph|. +% +% The \texttt{ftnhyperref} option is similar to \texttt{nohyperref}, +% but adds a footnote showing the destination address of each link, +% as specified by the SRC attribute. +% +% If the \texttt{hyperref} option is specified, the hypertext markup +% in the HTML file will be replicated using the +% hypertext specials of the Hyper\TeX\ group. If in addition the +% \textsf{hyperref} package is loaded, the extra features of that +% package may be used, for instance producing `native PDF' specials +% for direct use by Adobe distiller rather than producing the specials +% of the hyper\TeX\ conventions. +% +% The \texttt{dviwindo} option converts the hypertext information in +% the HTML into the |\special| conventions of Y\&Y's \emph{dviwindo} +% previewer for Microsoft Windows. +% +% \subsection{Big Integrals} +% \LaTeX\ does not treat integral signs as variable sized symbols, +% in the way that it treats delimiters such as brackets. In common +% with summation signs and a few other operators, they come in +% just two fixed sizes, a small version for inline mathematics, and a +% large version used in displays. In fact by default \LaTeX\ always +% uses the same two sizes (from the 10\,pt math extension font) even if +% the document class has been specified with a size option such as +% \texttt{12pt}, or if a size command such as |\large| has been used. +% +% The standard \textsf{exscale} package loads the math extension font +% at larger sizes if the current font size is larger than 10\,pt. +% +% The HTML3 math description explicitly states that integral signs +% should be treated like delimiters and stretch if applied to a large +% math expression. By default this package ignores this advice and +% treats integral signs in the standard way, however an option +% \texttt{bigint} does cause integral signs to `stretch' (or at least +% be taken from a suitably large font). The standard Computer Modern +% fonts use a very `sloped' integral which means that they are +% not really suitable for being stretched. Some other math fonts, for +% instance Lucida, have more vertical integral signs, and one could +% imagine in those cases making an integral sign with a `repeatable' +% vertical middle section so that it could grow to an arbitrary size, in +% the way that brackets grow. +% +% \section{Latin-1 characters} +% The SGML character entities for the ISO-Latin1 characters such as +% \texttt{\é} are recognised by this style, although as usual, +% some of them such as the Icelandic thorn character, +% \texttt{\þ}, \verb|\th|, produce an error if the old `OT1' +% encoded fonts are being used. These characters will print correctly +% if `T1' encoded fonts are used, for example by declaring +% \verb|\usepackage[T1]{fontenc}|~. +% +% HTML also allows direct 8-bit input of characters according to the +% ISO-latin1 encoding, to enable this you need to enable latin-1 input +% for \LaTeX\ with a declaration such as +% \verb|\usepackage[latin1]{inputenc}|~. +% +% \section{Mathematics} +% The HTML3 MATH element is fairly well supported, including the BOX +% and CLASS attributes. (Currently only CHEM value for class is +% supported, and as far as I can see the BOX attribute is only in the +% report, not in the dtd.) The super and subscripts are supported, +% including the shortref maps, however only the default right +% alignment is +% implemented so far. The convention described in the draft report +% for using white space to distinguish superscript positioning is +% fairly \emph{horrible}! +% +% +% The documentation that I could find on HTML3 did not include a full +% list of the entity names to be used for the symbols. This +% package currently \emph{only} defines the following entities, which +% should be enough for testing purposes at least. +% +% \begin{itemize} +% \item +% |gt| ($>$) |lt| ($<$) (Already in the HTML2 DTD) +% +% \item +% Some Greek letters. +% +% |alpha| ($\alpha$) +% |beta| ($\beta$) +% |gamma| ($\gamma$) +% |Gamma| ($\Gamma$) +% +% \item +% Integral and Sum. $\int$ grows large if the \texttt{bigint} package +% option is given. +% +% |int| ($\int$) +% |sum| ($\sum$) +% +% \item +% Braces (The delimiters ()[] also stretch as expected in the BOX +% element) +% +% |lbrace| ($\lbrace$) +% |rbrace| ($\rbrace$) +% +% \item +% A random collection of mathematical symbols: +% +% |times| ($\times$) +% |cup| ($\cup$) +% |cap| ($\cap$) +% |vee| ($\vee$) +% |wedge| ($\wedge$) +% |infty| ($\infty$) +% |oplus| ($\oplus$) +% |ominus| ($\ominus$) +% |otimes| ($\otimes$) +% +% \item +% A Minimal set of trig functions: +% +% |sin| ($\sin$) +% |cos| ($\cos$) +% |tan| ($\tan$) +% +% \item +% Also in the special context as attributes to ABOVE and BELOW elements +% the entities: +% +% |overbrace| ($\overbrace{\quad}$) +% |underbrace| ($\underbrace{\quad}$) and any (\TeX) math accent name. +% +% \end{itemize} +% +% \section{SGML Minimisation features} +% SGML (and hence HTML) support various minimisation features that aim +% to make it easier to enter the markp `by hand'. These features make +% the kind of `casual' attempt at parsing SGML as implemented in this +% package somewhat error prone. +% +% Two particular features are enabled in HTML. The so called SHORTTAG +% feature means that the name of a tag may be omitted if it may be +% inferred from the context. Typically in HTML this is used in +% examples like +%\begin{verbatim} +% A Document Title</> +%\end{verbatim} +% The end tag is shortened to |</>| and the system infers that +% TITLE is the element to be closed. +% +% The second form of minimisation enabled in HTML is the OMITTAG +% feature. Here a tag may be omitted altogether in certain +% circumstances. +% A typical example is the HTML list, where each list item is started +% with |<li>| but the closing |</li>| at the end of the item may be +% omitted and inferred by the following |<li>| or |</ol>| tag. +% +% This package is reasonably robust with respect to omitted +% tags. However it only makes a half hearted attempt at supporting the +% SHORTTAG feature. The TITLE example above would work, but nested +% elements, with multiple levels of minimised end tags will probably +% break this package. +% +% It would be possible to build a \LaTeX\ system that had full +% knowledge of the HTML (or any other) DTD and in particular the +% `content model' of every element, this would produce a more robust +% parsing system but would take longer than I was prepared to +% spend this week\ldots\ In anycase if you need a fully conforming SGML +% parser, it probably makes sense to use an existing one (excellent +% free parsers are freely available) and then convert the output of +% the parser to a form suitable for \LaTeX. In that way all such +% concerns about SGML syntax features such as minimisation will have +% been resolved by the time \LaTeX\ sees the document. +% +% \section{Examples} +% \let\olddohtml\dohtml +% \def\dohtml{\olddohtml\MakePercentIgnore} +% +% +% \subsection{A section} +% This document uses the \texttt{subsection*} option. +%\begin{verbatim} +% <h1>HTML and LaTeX</h1> +%\end{verbatim} +% \dohtml +% <html> +% <h1>HTML and LaTeX</h1> +% </html> +% +% \subsection{An itemised list} +%\begin{verbatim} +% <ul> +% <li> something +% <li> something else +% </ul> +%\end{verbatim} +% \dohtml +% <html> +% <ul> +% <li> something +% <li> something else +% </ul> +% </html> +% +% \subsection{Latin1 Characters} +%\begin{verbatim} +% é ö +%\end{verbatim} +% \dohtml +% <html> +% é ö +% </html> +% +% \subsection{Images} +% Currently only the ALT attribute is supported. +%\begin{verbatim} +% This is an image of me <img alt="DPC" src="dpc.gif"> +%\end{verbatim} +% \dohtml +% <html> +% This is an image of me <img alt="DPC" src="dpc.gif"> +% </html> +% +% \subsection{A Form} +%\begin{verbatim} +% <form +% action="http://www.cogs.susx.ac.uk/cgi-bin/ltxbugs2html" +% method=get><hr> +% You can search for all the bug reports about: <select name="category"> +% <option>AMS LaTeX</option> +% <option>Babel</option> +% <option>Graphics and colour</option> +% <option>LaTeX</option> +% <option selected>Metafont fonts</option> +% <option>PostScript fonts</option> +% <option>Tools</option> +% </select> +% <hr> +% </form> +%\end{verbatim} +% \dohtml +% <html> +% <form +% action="http://www.cogs.susx.ac.uk/cgi-bin/ltxbugs2html" +% method=get><hr> +% You can search for all the bug reports about: <select name="category"> +% <option>AMS LaTeX</option> +% <option>Babel</option> +% <option>Graphics and colour</option> +% <option>LaTeX</option> +% <option selected>Metafont fonts</option> +% <option>PostScript fonts</option> +% <option>Tools</option> +% </select> +% <hr> +% </form> +% </html> +% +% \subsection{Styles of Mathematics} +%\begin{verbatim} +% <math> +% H_2_O + CO_2_ +% </math> +% <math class=chem> +% H_2_O + CO_2_ +% </math> +% <math box> +% H_2_O + CO_2_ +% </math> +% <math class=chem box> +% H_2_O + CO_2_ +% </math> +%\end{verbatim} +% \dohtml +% <html> +% <math> +% H_2_O + CO_2_ +% </math> +% <math class=chem> +% H_2_O + CO_2_ +% </math> +% <math box> +% H_2_O + CO_2_ +% </math> +% <math class=chem box> +% H_2_O + CO_2_ +% </math> +% </html> +% +% \subsection{Integrals} +% Stretchy integrals with the \texttt{bigint} option. +%\begin{verbatim} +% <math> +% {∫^1^_3_<left> +% 1 +% <over> +% {x+{1<over>x+{2<over>x+ +% {3<over>x+{4<over>x}}}}} +% <right>dx} +% </math> +%\end{verbatim} +% \dohtml +% <html> +% <math> +% {∫^1^_3_<left> +% 1 +% <over> +% {x+{1<over>x+{2<over>x+ +% {3<over>x+{4<over>x}}}}} +% <right><t>d</t> x} +% </math> +% </html> +% And the same integral with the standard integral sign. +% \begingroup +% \makeatletter +% \let\HTML@bigint\int +% \dohtml +% <html> +% <math> +% {∫^1^_3_<left> +% 1 +% <over> +% {x+{1<over>x+{2<over>x+ +% {3<over>x+{4<over>x}}}}} +% <right><t>d</t>x} +% </math> +% </html> +% \endgroup +% +% \subsection{Oversized delimiters} +%\begin{verbatim} +% <math> +% <box>(<left>1 <atop> 2 <right>)</box> +% <box size=large>(<left>1 <atop> 2 <right>)</box> +% </math> +%\end{verbatim} +% \dohtml +% <html> +% <math> +% <box>(<left>1 <atop> 2 <right>)</box> +% <box size=large>(<left>1 <atop> 2 <right>)</box> +% </math> +% </html> +% +% \subsection{Roots, Overbraces etc} +%\begin{verbatim} +% <math> +% <above sym=overbrace> abc </above><sup>k</sup> +%   +% <root>3<of>x</root> +% <sqrt>5</sqrt> +%   +% <below sym=underline> abc </below> +% <above sym=widehat> abc </above> +% </math> +%\end{verbatim} +% \dohtml +% <html> +% <math> +% <above sym=overbrace> a bc </above><sup>k</sup> +%   +% <root>3<of>x</root> +% <sqrt>5</sqrt> +%   +% <below sym=underline> abc </below> +% <above sym=widehat> abc </above> +% </math> +% </html> +% +% \subsection{Arrays} +% +%\begin{verbatim} +% <math> +% aa<array align=top> +% <row><item><text>first col</text><item><text>second col</text><item> +% <text>third col</text><item><text>fourth col</text> +% <row><item><text>row 2</text><item> a_22_ <item>a_23_<item>a_24_ +% <row><item><text>row 3</text><item rowspan=3 colspan=2> +% a_32_-a_53_<item>a_34_ +% <row><item><text>row 4</text><item>a_44_ +% <row><item><text>row 5</text><item>a_54_ +% <row><item><text>row 6</text><item align=left> +% al_62_<item>a_63_<item>a_64_ +% <row><item><text>row 7</text><item align=right> +% ar_72_<item>a_73_<item>a_74_ +% </array>bb +% </math> +%\end{verbatim} +% +% \dohtml +% <html> +% <math> +% aa<array align=top> +% <row><item><text>first col</text><item><text>second col</text><item> +% <text>third col</text><item><text>fourth col</text> +% <row><item><text>row 2</text><item> a_22_ <item>a_23_<item>a_24_ +% <row><item><text>row 3</text><item rowspan=3 colspan=2> +% a_32_-a_53_<item>a_34_ +% <row><item><text>row 4</text><item>a_44_ +% <row><item><text>row 5</text><item>a_54_ +% <row><item><text>row 6</text><item align=left> +% al_62_<item>a_63_<item>a_64_ +% <row><item><text>row 7</text><item align=right> +% ar_72_<item>a_73_<item>a_74_ +% </array>bb +% </math> +% </html> +% +% Repeat that element, but change the ARRAY attributes as follows: +%\begin{verbatim} +% <array ldelim="(" rdelim=")" labels> +%\end{verbatim} +% +% \dohtml +% <html> +% <math> +% aa<array ldelim="(" rdelim=")" labels> +% <row><item><text>first col</text><item><text>second col</text><item> +% <text>third col</text><item><text>fourth col</text> +% <row><item><text>row 2</text><item> a_22_ <item>a_23_<item>a_24_ +% <row><item><text>row 3</text><item rowspan=3 colspan=2> +% a_32_-a_53_<item>a_34_ +% <row><item><text>row 4</text><item>a_44_ +% <row><item><text>row 5</text><item>a_54_ +% <row><item><text>row 6</text><item align=left> +% al_62_<item>a_63_<item>a_64_ +% <row><item><text>row 7</text><item align=right> +% ar_72_<item>a_73_<item>a_74_ +% </array>bb +% </math> +% </html> +% +% and finally an example of COLSPEC +%\begin{verbatim} +% <math> +% <array colspec="R+C=L"> +% <row><item>abc_11_<item>abc_12_<item>abc_13_ +% <row><item>a_21_<item>a_22_<item>a_23_ +% <row><item>a_31_<item>a_32_<item>a_33_ +% </array> +% </math> +%\end{verbatim} +% +% \dohtml +% <html> +% <math> +% <array colspec="R+C=L"> +% <row><item>abc_11_<item>abc_12_<item>abc_13_ +% <row><item>a_21_<item>a_22_<item>a_23_ +% <row><item>a_31_<item>a_32_<item>a_33_ +% </array> +% </math> +% </html> +% +% \subsection{Tables} +% HTML3 tables are not yet supported, but there is a minimal ammount to +% catch simple cases. +% +%\begin{verbatim} +% <table> +% <caption>Simple Table</caption> +% <tr><td>one <td> two +% <tr><td>a <td> b +% </table> +%\end{verbatim} +% +% \dohtml +% <html> +% <table> +% <caption>Simple Table</caption> +% <tr><td>one <td> two +% <tr><td>a <td> b +% </table> +% </html> +% +% \StopEventually{} +% +% \section{The Code} +% +% \subsection{Option Handling} +% \begin{macrocode} +%<*package> +% \end{macrocode} +% +% \begin{macrocode} +\DeclareOption{html2}{\let\HTML@two@stop\endinput} +% \end{macrocode} +% +% The |#| here, and in later option code will need doubling +% if you are using a \LaTeX\ before June 95. +% \begin{macrocode} +\DeclareOption{netscape} + {\def\HTML@not#1{\SGML@w{<#1> is not valid HTML}}} +% \end{macrocode} +% +% \begin{macrocode} +\DeclareOption{html3}{\let\HTML@two@stop\relax} +% \end{macrocode} +% +% \changes{v0.08}{1996/03/16}{Add nohyperref option} +% \begin{macrocode} +\DeclareOption{nohyperref}{% + \let\HTML@doname\@secondoftwo + \def\HTML@dosrc#1#2{\emph{#2}}} +% \end{macrocode} +% +% \changes{v0.08}{1996/03/16}{Add ftnhyperref option} +% \begin{macrocode} +\DeclareOption{ftnhyperref}{% + \let\HTML@doname\@secondoftwo + \def\HTML@dosrc#1#2{\emph{#2}\footnote{HREF: \texttt{#1}}}} +% \end{macrocode} +% +% \changes{v0.08}{1996/03/16} +% {make hyperref independent of hyperref package} +% \begin{macrocode} +\DeclareOption{hyperref}{% + \AtBeginDocument{% + \providecommand\href[2]{\special{html:<A href="#1">}% + #2\special{html:</A>}}% + \providecommand\hypertarget[2]{\special{html:<A name="#1">}% + #2\special{html:</A>}}% + \let\HTML@doname\hypertarget + \let\HTML@dosrc\href}} +% \end{macrocode} +% +% \changes{v0.08}{1996/03/16}{Add dviwindo option} +% Dviwindo itself deals with links within a document i.e., a src +% attribute of the form |"#name"|. The code below detects +% a more general URL and fires a |launch:| action from the |\special|, +% which calls the non-existant command \texttt{typehtml}. Presumably +% this could be a batch file that calls netscape or some other WWW +% engine to process the URL. +% \begin{macrocode} +\DeclareOption{dviwindo}{% + \def\HTML@dosrc#1#2{{% + \leavevmode\sbox\z@{#2}\count@\ht\z@\@tempcnta\wd\z@ + \if\string##\@car#1\@nil + \special{button: \the\@tempcnta\space\the\count@\space + "\@gobble#1"}% + \else + \special{button: \the\@tempcnta\space\the\count@\space + launch: typehtml "#1"} + \fi + \special{color push}\special{color rgb 0 1 0}% + \unhbox\z@ + \special{color pop}}}% + \def\HTML@doname#1#2{\leavevmode\special{mark: "#1"}#2}}% +% \end{macrocode} +% +% \begin{macrocode} +\DeclareOption{imgalt}{} +% \end{macrocode} +% +% \begin{macrocode} +\DeclareOption{imggif}{\SGML@w{img gif support not done yet}} +% \end{macrocode} +% +% \begin{macrocode} +\DeclareOption{imgps}{\SGML@w{img ps support not done yet}} +% \end{macrocode} +% +% \changes{v0.10}{1996/03/25}{Add double quote handling} +% \begin{macrocode} +\DeclareOption{smartquotedbl}{% + \def\SGMLquotedbla{% + \textquotedblleft\global\let\SGMLquotedbl\SGMLquotedblb} + \def\SGMLquotedblb{% + \textquotedblright\global\let\SGMLquotedbl\SGMLquotedbla} + \let\SGMLquotedbl\SGMLquotedbla + \let\SGML@savedeverypar\everypar + \newtoks\everypar + \SGML@savedeverypar{% + \global\let\SGMLquotedbl\SGMLquotedbla\the\everypar}} +% \end{macrocode} +% +% \begin{macrocode} +\DeclareOption{straightquotedbl}{% + \DeclareTextCommandDefault{\textquotedbl}{{\ttfamily\char`\"}}% + \let\SGMLquotedbl\textquotedbl} +% \end{macrocode} +% +% \begin{macrocode} +\DeclareOption{chapter}{% + \def\HTML@headings{% + \chapter\section\subsection% + \subsubsection\paragraph\subparagraph}} +% \end{macrocode} +% +% \begin{macrocode} +\DeclareOption{chapter*}{% + \def\HTML@headings{% + {\chapter*}{\section*}{\subsection*}% + {\subsubsection*}{\paragraph*}{\subparagraph*}}} +% \end{macrocode} +% +% \begin{macrocode} +\DeclareOption{section}{% + \def\HTML@headings{% + \section\subsection% + \subsubsection\paragraph\subparagraph\endgraf}} +% \end{macrocode} +% +% \begin{macrocode} +\DeclareOption{section*}{% + \def\HTML@headings{% + {\section*}{\subsection*}% + {\subsubsection*}{\paragraph*}{\subparagraph*}\endgraf}} +% \end{macrocode} +% +% \begin{macrocode} +\DeclareOption{subsection}{% + \def\HTML@headings{% + \subsection% + \subsubsection\paragraph\subparagraph\endgraf\endgraf}} +% \end{macrocode} +% +% \begin{macrocode} +\DeclareOption{subsection*}{% + \def\HTML@headings{% + {\subsection*}% + {\subsubsection*}{\paragraph*}{\subparagraph*}\endgraf\endgraf}} +% \end{macrocode} +% +% \begin{macrocode} +\DeclareOption{bigint}{% + \let\HTML@int\int + \AtEndOfPackage{\RequirePackage{exscale}}} +% \end{macrocode} +% +% \changes{v0.08}{1996/03/16}{Make unnumbered sections the default} +% \begin{macrocode} +\ExecuteOptions{section*,imgalt,html2,nohyperref,straightquotedbl} +% \end{macrocode} +% +% \begin{macrocode} +\ProcessOptions +% \end{macrocode} +% +% \subsection{Fake SGML parser} +% +% \begin{macrocode} +\begingroup +% \end{macrocode} +% +% \changes{v0.12}{1997/11/29}{activate gtr and semicolon} +% \begin{macrocode} +\catcode`\<=\active +\catcode`\>=\active +\catcode`\&=\active +\catcode`\$=\active +\catcode`\"=\active +\catcode`\^=\active +\catcode`\_=\active +\catcode`\;=\active +\catcode`\A=\active +\catcode`\B=\active +\catcode`\C=\active +\catcode`\D=\active +% \end{macrocode} +% \changes{v0.12}{1997/11/29}{\cs{uppercase} not \cs{lowercase}} +% \begin{macrocode} +\uccode`\A=`\{% +\uccode`\B=`\}% +% \end{macrocode} +% \changes{v0.10}{1996/03/25}{Swap round lccodes of C and D} +% \changes{v0.10}{1996/03/25}{Add double quote handling} +% \begin{macrocode} +\uccode`\C=`\|% +\uccode`\D=`\\% +% \end{macrocode} +% +% \begin{macrocode} +\uppercase{\endgroup +% \end{macrocode} +% +% \begin{macro}{\SGMLent@@} +% \changes{v0.12}{1997/11/29}{delimit with active semicolon and gtr} +% \begin{macrocode} +\def\SGMLent@@#1;{\csname SGML@E@#1\endcsname} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\SGMLent@@} +% \changes{v0.12}{1997/11/29}{macro added} +% \begin{macrocode} +\def\SGML@def@active#1>{% + \expandafter\def\csname SGML@#1\endcsname} +% \end{macrocode} +% \end{macro} +% +% \begin{macrocode} +\def\dohtml{% + \begingroup + \ifx;\@undefined\expandafter\let\expandafter;\string;\fi + \ifx>\@undefined\expandafter\let\expandafter>\string>\fi + \catcode`\<=\active + \catcode`\>=\active + \catcode`\&=\active + \catcode`\{=\active + \catcode`\}=\active + \catcode`\$=\active + \catcode`\"=\active + \catcode`\^=\active + \catcode`\_=\active + \catcode`\\=\active + \catcode`\|=\active + \catcode\endlinechar=10 + \catcode`\%=12 + \catcode`\#=12 + \catcode`\;=\active + \def\verbatim@nolig@list{\do\`\do\,\do\'\do\-} + \def<{\SGMLopen}% + \def&{\SGMLent}% + \let^\textasciicircum + \let~\textasciitilde + \def_{\_}% + \let$\$% + \def"{\SGMLquotedbl}% + \def A{\{}% + \def B{\}}% + \def C{\texttt{|}}% + \def D{\texttt{\char`\\}}% +% \end{macrocode} +% \changes{v0.07}{1996/03/15}{macro added} +% Need to be careful about writing to table of contents. +% \begin{macrocode} + \def\addcontentsline##1##2##3{% + {\def<{\string<}\def&{\string&}% + \addtocontents{##1}{\protect\dotochtml<html>}% + \addtocontents{##1}{\protect\contentsline{##2}{##3}{\thepage}}% + \addtocontents{##1}{\protect</html>}}}} +% \end{macrocode} +% +% \begin{macro}{\dotochtml} +% A `compromise' version of |\dohtml| for use in table of contents +% files. +% Allows HTML markup |<|, |&| etc, but also \TeX\ markup |\|, |{|, |}|. +% As these are incompatible, this is not 100\% reliable but it seems to +% cover most cases in practice. +% \changes{v0.07}{1996/03/15}{macro added} +% \begin{macrocode} +\def\dotochtml{% + \dohtml + \catcode`\\\z@ + \catcode`\{\@ne + \catcode`\}\tw@} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\SGMLshortend} +% \changes{v0.04}{1996/03/09}{macro added} +% \begin{macrocode} +\def\SGMLshortend{/} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\SGMLgrab@} +% \begin{macrocode} +\def\SGMLgrab@#1<#2>{% + \edef\@tempd{\lowercase{\def\noexpand\@tempd{\gobblespc#2 \relax}}}% + \@tempd +% \end{macrocode} +% +% \changes{v0.04}{1996/03/09}{SHORTTAG support} +% \begin{macrocode} + \ifx\@tempd\SGMLshortend\let\@tempd\@tempc\fi +% \end{macrocode} +% +% \begin{macrocode} + \ifx\@tempb\@tempd + \advance\@tempcnta\@ne + \else + \ifx\@tempc\@tempd + \advance\@tempcnta\m@ne + \fi + \fi + \ifnum\@tempcnta=\z@ + \expandafter\@tempa\expandafter{\the\@temptokena#1}% + \else + \addto@hook\@temptokena{#1<#2>}% + \expandafter\SGMLgrab@ + \fi} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\SGMLopen} +% \changes{v0.10}{1996/03/25}{Add double quote handling} +% \changes{v0.12}{1997/11/29}{delimit with active gtr} +% \begin{macrocode} +\def\SGMLopen#1>{% + \SGMLopen@#1 \@nil} +% \end{macrocode} +% \end{macro} +% +% \begin{macrocode} +} +% \end{macrocode} +% +% \begin{macro}{\htmlinput} +% \begin{macrocode} +\def\htmlinput#1{\dohtml\let\@endhtml\relax\input{#1}\endgroup} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\gobblespc} +% \begin{macrocode} +\def\gobblespc#1 #2\relax{#1} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\SGMLgrabber} +% \begin{macrocode} +\def\SGMLgrabber#1#2{% + \def\@tempa{#2}% + \@tempcnta\@ne + \@temptokena{}% + \lowercase{\def\@tempb{#1}\def\@tempc{/#1}}% + \SGMLgrab@} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\SGMLopen@} +% \changes{v0.07}{1996/03/15}{macro added} +% \begin{macrocode} +\begingroup +\catcode`\"=\active +\uppercase{\endgroup +\def\SGMLopen@#1 #2\@nil{% + \toks@{}% + \edef\@tempa{\lowercase{\def\noexpand\SGMLelement{#1}}}\@tempa + \if!\@car#1\relax\@nil + \toks@{#1 #2}% + \SGML@w{Declaration ignored\MessageBreak<\the\toks@>\MessageBreak}% + \else + \if$#2$\else + \replacequotes#2"\@nil"% + \SGMLafterfi + \expandafter\toks@\expandafter{\expandafter}% + \expandafter\SGMLgetattrib\the\toks@ \@nil + \fi + \expandafter\ifx\csname SGML@\SGMLelement + \expandafter\endcsname\relax + \SGML@w{<\SGMLelement> undefined}% + \else + \csname SGML@\SGMLelement + \expandafter\expandafter\expandafter\endcsname + \fi + \fi} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\replacequotes} +% \begin{macrocode} +\def\replacequotes#1"#2"{% + \def\@tempb{#2}% + \ifx\@tempb\@nnil + \addto@hook\toks@{#1}% + \else + \addto@hook\toks@{#1{#2}}% + \expandafter\replacequotes + \fi}} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\SGMLafterfi} +% \begin{macrocode} +\def\SGMLafterfi#1\fi{\fi#1} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\SGMLgobbletofi} +% \begin{macrocode} +\def\SGMLgobbletofi#1\fi{\fi} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\SGMLgetattrib} +% \changes{v0.10}{1996/03/25}{use dollar to distingish empty value} +% \begin{macrocode} +\def\SGMLgetattrib#1 #2{% + \ifx\box#1\box\else + \SGMLgetval#1=$=\@nil + \def\@tempa{#2}% + \ifx\@tempa\@nnil + \expandafter\SGMLgobbletofi + \else + \expandafter\SGMLafterfi + \fi + \SGMLgetattrib#2% + \fi} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\SGMLgetval} +% \changes{v0.08}{1996/03/16}{lowercase attribute names} +% If no value was supplied |#2| will be |$| (Even if the value is |$| +% The test is false, as that would be catcode 13. Done this way rather +% than looking for empty to distinguish |alt=""| with empty value. +% \begin{macrocode} +\def\SGMLgetval#1=#2=#3\@nil{% + \ifcat$#2% + \lowercase{\SGML@addattrib\doimplied{#1}}% + \else + \lowercase{\SGML@addattrib{\do{#1}}}{#2}% + \fi} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\SGML@addattrib} +% \changes{v0.08}{1996/03/16}{macro added} +% \begin{macrocode} +\def\SGML@addattrib#1#2{\addto@hook\toks@{#1{#2}}} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\SGML@w} +% \begin{macrocode} +\def\SGML@w{\PackageWarning{typehtml}} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\SGMLdef} +% \changes{v0.12}{1997/11/29}{allow active delimiters} +% \begin{macrocode} +\def\SGMLdef#1{% + \ifcat\noexpand#1\noexpand~% + \expandafter\SGML@def@active + \else + \expandafter\SGML@def + \fi} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\SGMLdef} +% \changes{v0.12}{1997/11/29}{macro added} +% make sure this is a catcode 12 |>|. +% \begin{macrocode} +\edef\@tempa{\def\noexpand\SGML@def##1\string>}\@tempa{% + \expandafter\def\csname SGML@#1\endcsname} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\SGMLent} +% \begin{macrocode} +\expandafter\def\expandafter\SGMLent\expandafter{% + \expandafter\protect\csname& \endcsname} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{& } +% \begin{macrocode} +\expandafter\def\csname& \endcsname{% + \futurelet\@let@token\SGMLent@} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\SGMLent@} +% \begin{macrocode} +\def\SGMLent@{% + \ifx\@let@token\@sptoken + \&% + \else + \expandafter\SGMLent@@ + \fi} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\SGMLentity} +% \begin{macrocode} +\def\SGMLentity#1{% + \expandafter\def\csname SGML@E@#1\endcsname} +% \end{macrocode} +% \end{macro} +% +% \subsection{The HTML2 DTD} +% +% \begin{macrocode} +\SGMLdef<html>{} +\SGMLdef</html>{\@endhtml} +\let\@endhtml\endgroup +% \end{macrocode} +% +% \begin{macrocode} +\SGMLdef<title>{\typeout{***TITLE***}\SGMLgrabber{title}\typeout} +% \end{macrocode} +% +% \begin{macrocode} +\long\def\@tempa#1#2#3#4#5#6{% + \SGMLdef<h1>{\SGMLgrabber{h1}{\HTMLsection{#1}}}% + \SGMLdef<h2>{\SGMLgrabber{h2}{\HTMLsection{#2}}}% + \SGMLdef<h3>{\SGMLgrabber{h3}{\HTMLsection{#3}}}% + \SGMLdef<h4>{\SGMLgrabber{h4}{\HTMLsection{#4}}}% + \SGMLdef<h5>{\SGMLgrabber{h5}{\HTMLsection{#5}}}% + \SGMLdef<h6>{\SGMLgrabber{h6}{\HTMLsection{#6}}}} +% \end{macrocode} +% +% \begin{macrocode} +\expandafter\@tempa\HTML@headings +% \end{macrocode} +% +% \begin{macrocode} +\def\HTMLsection#1#2{#1{\ignorespaces#2\unskip}} +% \end{macrocode} +% +% \begin{macrocode} +\SGMLdef<head>{} +\SGMLdef</head>{} +% \end{macrocode} +% +% \begin{macrocode} +\SGMLdef<body>{} +\SGMLdef</body>{} +% \end{macrocode} +% +% \begin{macrocode} +\SGMLdef<bodytext>{} +\SGMLdef</bodytext>{} +% \end{macrocode} +% +% \begin{macrocode} +\SGMLdef<p>{\par} +\SGMLdef</p>{\par} +% \end{macrocode} +% +% \begin{macrocode} +\SGMLdef<blockquote>{\begin{quote}} +\SGMLdef</blockquote>{\end{quote}} +% \end{macrocode} +% +% \begin{macrocode} +\SGMLdef<address>{\begin{quote}} +\SGMLdef</address>{\end{quote}} +% \end{macrocode} +% +% \begin{macrocode} +\SGMLdef<ul>{\begin{itemize}} +\SGMLdef</ul>{\end{itemize}} +% \end{macrocode} +% +% \begin{macrocode} +\SGMLdef<ol>{\begin{enumerate}} +\SGMLdef</ol>{\end{enumerate}} +% \end{macrocode} +% +% \begin{macrocode} +\SGMLdef<li>{\item} +\SGMLdef</li>{} +% \end{macrocode} +% +% \begin{macrocode} +\SGMLdef<dl>{% + \let\do\dldo + \let\doimplied\dlimplied + \begin{description}\the\toks@} +\SGMLdef</dl>{\end{description}} +% \end{macrocode} +% +% \begin{macrocode} +\def\dldo#1#2{% + \def\@tempa{compact}\def\@tempb{#1}% + \ifx\@tempa\@tempb + \itemsep\z@ + \advance\@totalleftmargin-\leftmargin + \advance\linewidth\leftmargin + \itemindent-\labelsep + \leftmargin\z@ + \parshape \@ne \@totalleftmargin \linewidth + \fi} +\def\dlimplied#1{\dldo{#1}\relax} +% \end{macrocode} +% +% \begin{macrocode} +\def\itx#1{\item[#1]} +\SGMLdef<dt>{\begin{lrbox}\z@\bfseries\let\maybeenddt\enddt} +\SGMLdef</dt>{\maybeenddt} +\SGMLdef<dd>{\maybeenddt} +\SGMLdef</dd>{} +\def\enddt{\end{lrbox}\item[\unhbox\z@]} +\let\maybeenddt\relax +% \end{macrocode} +% +% \changes{v0.07}{1996/03/15}{hyperref support (SPQR)} +% \begin{macrocode} +\SGMLdef<a>{\SGMLgrabber{a}\HTML@anchor} +% \end{macrocode} +% +% \begin{macro}{\HTML@anchor} +% This handles the A tag. +% \changes{v0.04}{1996/03/09}{macro added} +% \begin{macrocode} +\def\HTML@anchor#1{{% + \let\@tempa\@gobble + \def\_{\string_}% + \let\do\ado + \the\toks@ + \@tempa{#1}}} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\ado} +% Thanks to SPQR for first pass at integrating \textsf{hyperref}. +% \begin{macrocode} +\def\ado#1#2{% + \def\@tempb{name}\def\@tempc{#1}% + \ifx\@tempb\@tempc + \let\@tempa\@firstofone + \def\@tempa{\HTML@doname{#2}}% + \else + \def\@tempa{\HTML@dosrc{#2}}% + \fi} +% \end{macrocode} +% \end{macro} +% +% \changes{v0.03}{1996/03/08}{pre is alltt not verbatim} +% \begin{macrocode} +\SGMLdef<pre>{% + \par + \begingroup + \parindent\z@ + \obeylines\verbatim@font\@noligs + \frenchspacing\@vobeyspaces} +% \end{macrocode} +% +% +% \begin{macrocode} +\SGMLdef</pre>{\endgroup} +% \end{macrocode} +% +% \begin{macrocode} +\SGMLdef<tt>{\SGMLgrabber{tt}\texttt} +\SGMLdef<b>{\SGMLgrabber{b}\textbf} +\SGMLdef<i>{\SGMLgrabber{i}\textit} +\SGMLdef<em>{\SGMLgrabber{em}\emph} +\SGMLdef<strong>{\SGMLgrabber{strong}\textbf} +\SGMLdef<code>{\SGMLgrabber{code}\texttt} +\SGMLdef<samp>{\SGMLgrabber{samp}\textsf} +\SGMLdef<kbd>{\SGMLgrabber{kbd}\texttt} +\SGMLdef<var>{\SGMLgrabber{var}\textit} +\SGMLdef<cite>{\SGMLgrabber{cite}\textit} +% \end{macrocode} +% +% \begin{macrocode} +\SGMLdef<form>{\par\medskip} +\SGMLdef</form>{\par\medskip} +% \end{macrocode} +% +% \begin{macrocode} +\SGMLdef<select>{% + \let\do\selectdo + \the\toks@\par + \begin{tabular}{|l|}% + \hline\@tempc\\\hline + \let\tabularnewline\relax + \ignorespaces} +% \end{macrocode} +% +% \begin{macrocode} +\def\selectdo#1#2{% + \def\@tempa{name}\def\@tempb{#1}% + \ifx\@tempa\@tempb\def\@tempc{#2}\fi} +% \end{macrocode} +% +% \begin{macrocode} +\SGMLdef</select>{\\\hline\end{tabular}} +% \end{macrocode} +% +% \begin{macrocode} +\SGMLdef<option>{% + \gdef\optionbul{\phantom{$\bullet$}}% + \let\do\optiondo + \let\doimplied\optionimplied + \the\toks@ + \tabularnewline + \let\tabularnewline\\% + \optionbul\space\ignorespaces} +\SGMLdef</option>{} +% \end{macrocode} +% +% \begin{macro}{\optiondo} +% Handle attributes to the OPTION element. +% \begin{macrocode} +\def\optiondo#1#2{% + \def\@tempa{selected}\def\@tempb{#1}% + \ifx\@tempa\@tempb\gdef\optionbul{$\bullet$}\fi} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\optionimplied} +% Handle the case where just the attribute value is given. +% \begin{macrocode} +\def\optionimplied#1{% + \def\@tempa{selected}\def\@tempb{#1}% + \ifx\@tempa\@tempb\gdef\optionbul{$\bullet$}\fi} +% \end{macrocode} +% \end{macro} +% +% \begin{macrocode} +\SGMLdef<input>{} +% \end{macrocode} +% +% \begin{macrocode} +\SGMLdef<img>{{% + \let\do\imgdo + \def\@tempa{\doimage}% + \the\toks@ + \@tempa}} +% \end{macrocode} +% +% \begin{macrocode} +\def\doimage{\textsf{[image]}} +% \end{macrocode} +% +% \begin{macro}{\imgdo} +% Handle IMG attributes (not very usefully) +% \begin{macrocode} +\def\imgdo#1{\csname img=#1\endcsname} +\expandafter\def\csname img=align\endcsname#1{% + \SGML@w{align=#1 ignored}} +\expandafter\def\csname img=src\endcsname#1{% + \SGML@w{src=#1 ignored}} +\expandafter\def\csname img=height\endcsname#1{% + \SGML@w{height=#1 ignored}} +\expandafter\def\csname img=alt\endcsname#1{% + \def\doimage{#1}} +% \end{macrocode} +% \end{macro} +% +% Horizontal rules and line breaks. +% \changes{v0.12}{1997/11/29}{BR in vertical mode allowed.} +% \begin{macrocode} +\SGMLdef<hr>{\par\smallskip\hrule\smallskip} +\SGMLdef<br>{\leavevmode\\} +% \end{macrocode} +% +% These are obsolete in HTML3 but do them anyway. +% \changes{v0.10}{1996/03/25}{XMP and LISTING and PLAINTEXT added} +% \begin{macrocode} +\SGMLdef<xmp>{% + \SGML@pre + \def\@tempb{/xmp}% + \let\SGMLopen\HTML@xmptest} +% \end{macrocode} +% +% \begin{macrocode} +\SGMLdef<listing>{% + \SGML@xmp + \def\@tempb{/listing}} +% \end{macrocode} +% +% \begin{macrocode} +\SGMLdef<plaintext>{% + \SGML@xmp + \def\@tempb{/plaintext}}% +% \end{macrocode} +% +% \begin{macro}{\HTML@xmptest} +% \begin{macrocode} +\def\HTML@xmptest#1>{% + \lowercase{\def\@tempa{#1}}% + \ifx\@tempa\@tempb + \endgroup + \else + \SGMLafterfi + <#1>% + \fi} +% \end{macrocode} +% \end{macro} +% +% +% SGML syntax Character entities. +% \begin{macrocode} +\SGMLentity{amp}{\&} +\SGMLentity{lt}{\ensuremath{<}} +\SGMLentity{gt}{\ensuremath{>}} +% \end{macrocode} +% +% ISO Latin-1 Character entities. +% \begin{macrocode} +\SGMLentity{aacute}{\'a} +\SGMLentity{Aacute}\'A{} +\SGMLentity{acirc}{\^a} +\SGMLentity{Acirc}{\^A} +\SGMLentity{agrave}{\`a} +\SGMLentity{Agrave}{\`A} +\SGMLentity{aring}{\r a} +\SGMLentity{Aring}{\r A} +\SGMLentity{atilde}{\~a} +\SGMLentity{Atilde}{\~A} +\SGMLentity{auml}{\"a} +\SGMLentity{Auml}{\"A} +\SGMLentity{aelig}{\ae} +\SGMLentity{AElig}{\AE} +\SGMLentity{ccedil}{\c c} +\SGMLentity{Ccedil}{\c C} +\SGMLentity{eth}{\dh} +\SGMLentity{ETH}{\DH} +\SGMLentity{eacute}{\'e} +\SGMLentity{Eacute}{\`E} +\SGMLentity{ecirc}{\^e} +\SGMLentity{Ecirc}{\^E} +\SGMLentity{egrave}{\`e} +\SGMLentity{Egrave}{\`E} +\SGMLentity{euml}{\"e} +\SGMLentity{Euml}{\"E} +\SGMLentity{iacute}{\'\i} +\SGMLentity{Iacute}{\'I} +\SGMLentity{icirc}{\^\i} +\SGMLentity{Icirc}{\^I} +\SGMLentity{igrave}{\`\i} +\SGMLentity{Igrave}{\`I} +\SGMLentity{iuml}{\"\i} +\SGMLentity{Iuml}{\"I} +\SGMLentity{ntilde}{\~n} +\SGMLentity{Ntilde}{\~N} +\SGMLentity{oacute}{\'o} +\SGMLentity{Oacute}{\'O} +\SGMLentity{ocirc}{\^o} +\SGMLentity{Ocirc}{\^O} +\SGMLentity{ograve}{\`o} +\SGMLentity{Ograve}{\`O} +\SGMLentity{oslash}{\oe} +\SGMLentity{Oslash}{\OE} +\SGMLentity{otilde}{\~o} +\SGMLentity{Otilde}{\~O} +\SGMLentity{ouml}{\"o} +\SGMLentity{Ouml}{\"O} +\SGMLentity{szlig}{\ss} +\SGMLentity{thorn}{\th} +\SGMLentity{THORN}{\TH} +\SGMLentity{uacute}{\'u} +\SGMLentity{Uacute}{\'U} +\SGMLentity{ucirc}{\^u} +\SGMLentity{Ucirc}{\^U} +\SGMLentity{ugrave}{\`u} +\SGMLentity{Ugrave}{\`U} +\SGMLentity{uuml}{\"u} +\SGMLentity{Uuml}{\"U} +\SGMLentity{yacute}{\'y} +\SGMLentity{Yacute}{\'Y} +\SGMLentity{yuml}{\"y} +% \end{macrocode} +% +% \subsection{Netscape Non-HTML tags} +% +% Netscape allows certain tags that do not correspond to HTML elements. +% These are \emph{Bad Thing}. Originally the documentation of this +% package stated that such `extensions' would not be supported, however +% as a request came from \ldots\ldots\footnote{Name withheld to +% protect the guilty} who also supplied most of the code in this +% section (and also the table section), I have added some support +% which is enabled if the \texttt{netscape} option is used. +% \begin{macrocode} +\ifx\HTML@not\@undefined\else +% \end{macrocode} +% +% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Do something with bad reprehensible nonstandard tags +% that have the annoying habit of turning up often in html files that +% I want to print. [mjd,1996/03/20] +% +% |\HTML@not| is defined above in the netscape option: +% Naughty Nonstandard Extension Warning for things like +% |<center>| and |<font>|. (I thought these were +% Netscape-specific but the technical notes at Spyglass's web site +% showed that I was wrong. [mjd,1996/03/20]) +% \begin{macrocode} +\SGMLdef<center>{\HTML@not{center}\begin{center}} +\SGMLdef</center>{\end{center}} +% \end{macrocode} +% +% \begin{macrocode} +\SGMLdef<blink>{\SGMLgrabber{blink}\textbf} +% \end{macrocode} +% +% \begin{macrocode} +\SGMLdef<font>{\HTML@not{font}\begingroup + \let\do\fontdo\the\toks@} +\SGMLdef</font>{\endgroup} +% \end{macrocode} +% |\fontdo| must look at the first character of the `size, value to see +% if it is a relative size change (|+| or |-|). Otherwise it is an +% absolute size change. +% \begin{macrocode} +\def\fontdo#1#2{% + \def\@tempa{size}\def\@tempb{#1}% + \ifx\@tempa\@tempb + \font@switch#2\relax\@nil + \fi} +% \end{macrocode} +% +% Let's hack a nice little hook into |\@setfontsize| (tsk tsk). +% If we can set the current font size number there, it makes the rest +% of the job much easier. +% \begin{macrocode} +\toks@\expandafter{\set@fontsize{#1}{#2}{#3}} +\edef\@tempa{% + \def\noexpand\set@fontsize##1##2##3{\the\toks@\noexpand\set@fontnum}} +\@tempa +% \end{macrocode} +% +% Take |\f@size| which is a real number, convert it to an integer, +% and normalize to the desired range. +% \begin{macrocode} +\def\set@fontnum{\dimen@\f@size\p@ + \dimen@\mul@ptsize\dimen@ + \count@\dimen@ \divide\count@\p@ + \advance\count@ -5\relax + \edef\@fontnum{\number\count@}} +% \end{macrocode} +% +% Nice consistent naming conventions as always. +% multiplier if 11pt or 12pt documentclass option is used +% \begin{macrocode} +\def\mul@ptsize{}% +% \end{macrocode} +% +% 5 = |\normalsize| I think +% \begin{macrocode} +\def\@fontnum{5} +% \end{macrocode} +% +% Initialize |\mul@ptsize| +% \begin{macrocode} +\ifcase 0\@ptsize\relax + \global\let\mul@ptsize\@empty% case 0, ptsize = 10 + \or\gdef\mul@ptsize{.9091}% case 1, ptsize = 11 + \else\gdef\mul@ptsize{.8333}% case 2, ptsize = 12 +\fi +% \end{macrocode} +% +% |\font@switch| looks for |+| or |-| and selects a suitable fontsize +% command. +% \begin{macrocode} +\def\font@switch#1#2\@nil{\count@\@fontnum\relax + \ifx +#1\advance\else\ifx -#1\advance\fi\fi + \count@#1#2\relax + \ifcase\count@ \tiny\or \tiny\or \scriptsize + \or\footnotesize \or\small \or\normalsize \or\large + \or\Large \or\LARGE \or\huge \else\Huge \fi} +% \end{macrocode} +% +% \begin{macrocode} +\fi +% \end{macrocode} +% +% \subsection{The HTML3 DTD} +% +% |\HTML@two@stop| is |\endinput| (and so the package stops here) +% unless the HTML3 option is given. +% \begin{macrocode} +\HTML@two@stop +\SGML@w{HTML3 support not finished yet} +% \end{macrocode} +% +% \begin{macrocode} +\SGMLdef<math>{\SGMLgrabber{math}\domath} +% \end{macrocode} +% +% \begin{macrocode} +\SGMLdef<sup>{^\bgroup\HTMLscriptmap} +\SGMLdef</sup>{\egroup} +% \end{macrocode} +% +% \begin{macrocode} +\SGMLdef<sub>{_\bgroup\HTMLscriptmap} +\SGMLdef</sub>{\egroup} +% \end{macrocode} +% +% GRUMBLE! GRUMBLE! GRUMBLE! Possibly the worst feature of \TeX's math +% markup is the nature of the infix operators for fractions and the +% like. And here it is faithfully (or actually not very faithfully) +% reconstructed here\ldots +% \begin{macrocode} +\SGMLdef<box>{\SGMLgrabber{box}\dobox} +% \end{macrocode} +% +% \begin{macrocode} +\begingroup +\catcode`\<=\active +\catcode`\>=\active +\catcode`\&=\active +\catcode`\_=\active +\catcode`\^=\active +\catcode`\"=\active +% \end{macrocode} +% +% \begin{macro}{\domath} +% Handle the MATH element. The body is pre-expanded one level to +% replace |{ }| by BOX elements, and to replace any SGML entitity +% references by single \TeX\ tokens so they can be recognised more +% easily. Then start math mode with |\[| (which may have been +% redefined locally if the BOX attribute was used) set up the +% shorteref map. +% \begin{macrocode} +\gdef\domath#1{% + {{\def&{\expandafter\expandafter\expandafter\noexpand\SGMLent@@}% + \let<\relax\let>\relax\let_\relax\let^\relax\let"\relax + \def\{{<box>}\def\}{</box>}% + \xdef\@gtempa{#1}}% + \let\do\mathdo + \let\doimplied\mathimplied + \the\toks@ + \[% + \m@th\nulldelimiterspace\z@ + \def^{<sup>}% + \def_{<sub>}% + \@gtempa\]}} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\HTMLscriptmap} +% Set up the shortref map used in super and subscripts. +% \begin{macrocode} +\gdef\HTMLscriptmap{% + \def^{</sup>}% + \def_{</sub>}} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\dobox} +% Handle the BOX element. +% First deal with the attributes, then set up the shortref map. Then +% start looking for a LEFT tag. +% \begin{macrocode} +\gdef\dobox#1{% + {\let\do\boxdo + \let\bigstrut\relax + \the\toks@ + \def^{<sup>}% + \def_{<sub>}% + \lookleft@#1<left>\@nil}} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\lookleft@} +% See whether this BOX element contains a LEFT tag. Supply a `null +% delimiter' if not one supplied. +% \begin{macrocode} +\gdef\lookleft@#1<left>#2\@nil{% + \if$#2$% + {\left.\bgroup#1\mayberight}% + \else + \lookbox@#1<box>\@nil#2\@nil + \fi} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\lookbox@} +% Having found a LEFT tag, need to check it isn't inside a nested BOX. +% The following code looks for an explicit |<BOX>| (which includes a +% |{| shortref as that will have been expanded by now, however it will +% fail if nested boxes have attributes, so it may need some further +% modifications later. +% \begin{macrocode} +\gdef\lookbox@#1<box>#2\@nil#3<left>\@nil{% + \if$#2$% + {\maybeleft#1\@nil#3\mayberight} + \else + {#1 \boxtofront#2 <left> #3}% + \fi} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\boxtofront} +% After all that messing around need to put the BOX tag back where we +% found it. +% \begin{macrocode} +\gdef\boxtofront#1<box>{<box>#1} +% \end{macrocode} +% \end{macro} +% +% \begin{macrocode} +\endgroup +% \end{macrocode} +% +% \begin{macro}{\mathdo} +% \changes{v0.04}{1996/03/10}{Support math attributes} +% \begin{macrocode} +\def\mathdo#1#2{% + \def\@tempa{class-chem}\def\@tempb{#1-#2}% + \ifx\@tempa\@tempb + \everymath{\fam\z@}\everydisplay{\fam\z@}% + \fi} +\def\mathimplied#1{% + \def\@tempa{box}\def\@tempb{#1}% + \ifx\@tempa\@tempb + \def\[{\center\setbox\z@\hbox\bgroup$\displaystyle}% + \def\]{$\egroup\fbox{\box\z@}\endcenter}% + \fi} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\boxdo} +% \changes{v0.04}{1996/03/09}{Support box size attribute} +% \begin{macrocode} +\def\boxdo#1#2{% + \def\@tempa{size}\def\@tempb{#1}% + \ifx\@tempa\@tempb + \def\@tempb{#2} + \def\@tempa{normal}\ifx\@tempa\@tempb\def\@tempc{1}\fi + \def\@tempa{medium}\ifx\@tempa\@tempb\def\@tempc{2}\fi + \def\@tempa{large}\ifx\@tempa\@tempb\def\@tempc{3}\fi + \def\@tempa{huge}\ifx\@tempa\@tempb\def\@tempc{4}\fi + \edef\bigstrut{\vrule\@height\@tempc\ht\strutbox\@width\z@} + \fi} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\SGML@left} +% \begin{macrocode} +\SGMLdef<left>{\left.\bgroup} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\mayberight} +% \begin{macrocode} +\def\mayberight{\egroup\bigstrut\right.} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\maybeleft} +% \changes{v0.04}{1996/03/09}{macro added} +% \begin{macrocode} +\def\maybeleft#1#2\@nil{% + \in@{#1}{()[]\SGML@E@rbrace\SGML@E@lbrace}% + \ifin@ + \left#1\bgroup#2% + \else + \let\SGML@E@int\HTML@bigint + #1#2\left.\bgroup\let\SGML@E@int\int + \fi} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\righttest} +% \changes{v0.04}{1996/03/09}{macro added} +% \begin{macrocode} +\def\righttest#1{% + \in@{#1}{()[]\SGML@E@rbrace\SGML@E@lbrace}% + \ifin@ + \right#1\let\mayberight\relax + \else + \right.\let\mayberight\relax\expandafter#1% + \fi} +% \end{macrocode} +% \end{macro} +% +% \subsection{`Big int' processing} +% I am not sure that stretchy integral signs are good idea in general, +% and certainly they do not fit well with the Computer Modern style of +% sloping integral sign as opposed to the more vertical style of, say, +% Lucida. However\ldots +% +% \begin{macro}{\HTML@int} +% \changes{v0.04}{1996/03/010}{macro added} +% \begin{macrocode} +\ifx\HTML@int\@undefined +% \end{macrocode} +% +% \begin{macro}{\HTML@bigint} +% Normally just use the standard |\int|. +% \begin{macrocode} +\let\HTML@bigint\int +% \end{macrocode} +% +% \begin{macrocode} +\else +% \end{macrocode} +% +% With the |bigint| option . +% The original |\int| (in a big font) together with any saved limits +% (in the normal font). +% \begin{macrocode} +\def\HTML@int{\int^{\box\tw@}_{\box4}} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\HTML@bigint} +% \begin{macrocode} +\def\HTML@bigint#1\left.\bgroup{% + \def\@tempa{#1}% + \setbox\z@\hbox\bgroup + \aftergroup\HTMLafterbigint$\displaystyle\bgroup + \aftergroup$\aftergroup\egroup} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\HTMLafterbigint} +% \begin{macrocode} +\def\HTMLafterbigint{% + \dimen@.5\ht\z@ + \advance\dimen@.5\dp\z@ + {\SGMLdef<sup>{\setbox\tw@\hbox\bgroup\HTMLscriptmap$\scriptstyle}% + \SGMLdef<sub>{\setbox4\hbox\bgroup\HTMLscriptmap$\scriptstyle}% + \SGMLdef</sup>{$\egroup}% + \SGMLdef</sub>{$\egroup}% + \setbox\tw@\box\voidb@x + \setbox4\box\voidb@x + \@tempa + \ifdim\dimen@>\f@size\p@ +% \end{macrocode} +% At this point, could do |\fontsize\dimen@\z@\selectfont| but that +% would load \emph{all} the math fonnts at a strange size, so instead +% just load the extension font, and then subvert NFSS to drop that +% into the math expression. The NFSS interface is still used to +% declare the font so that a size substitution is done on the loading +% (otherwise every integral may use up a new font). +% \changes{v0.08}{1996/03/16}{Use \cs{DeclareFixedFont}} +% \begin{macrocode} + \mathop{\hbox{\DeclareFixedFont\@tempa{OMX}{cmex}{m}{n}\dimen@ + $\displaystyle\textfont\thr@@\@tempa\HTML@int$}}% + \else + \HTML@int + \fi + }\left.\box\z@} +% \end{macrocode} +% \end{macro} +% +% \begin{macrocode} +\fi +% \end{macrocode} +% \end{macro} +% +% +% See above grumble. The HTML3 DTD comments specifically refer to +% these as `\LaTeX\ commands' but they are no such thing. They are in +% plain and survive into \LaTeX\ under protest! The AMS \LaTeX\ +% documentation contains a much longer diatribe against these infix +% commands, and they are \emph{disabled} in the AMS \LaTeX\ styles. +% \begin{macrocode} +\SGMLdef<over>{\over} +\SGMLdef<atop>{\atop} +\SGMLdef<choose>{\choose} +% \end{macrocode} +% +% \begin{macrocode} +\SGMLdef<right>{\egroup\bigstrut\righttest} +% \end{macrocode} +% +% \begin{macrocode} +\SGMLdef<above>{\SGMLgrabber{above}% + {\let\@tempc\overlineop + \let\do\abovedo + \the\toks@ + \@tempc}} +% \end{macrocode} +% +% \begin{macrocode} +\SGMLdef<below>{\SGMLgrabber{below}% + {\let\@tempc\underlineop + \let\do\abovedo + \the\toks@ + \@tempc}} +% \end{macrocode} +% +% \begin{macrocode} +\def\overlineop#1{\mathop{\overline{#1}}} +\def\underlineop#1{\mathop{\underline{#1}}} +% \end{macrocode} +% +% \begin{macrocode} +\def\abovedo#1#2{% + \def\@tempa{sym}\def\@tempb{#1}% + \ifx\@tempa\@tempb\def\@tempc{\csname#2\endcsname}\fi} +% \end{macrocode} +% +% \begin{macrocode} +\SGMLdef<vec>{\SGMLgrabber{vec}\vec} +\SGMLdef<bar>{\SGMLgrabber{bar}\bar} +\SGMLdef<dot>{\SGMLgrabber{dot}\dot} +\SGMLdef<ddot>{\SGMLgrabber{ddot}\ddot} +\SGMLdef<hat>{\SGMLgrabber{hat}\hat} +\SGMLdef<tilde>{\SGMLgrabber{tilde}\tilde} +% \end{macrocode} +% +% \begin{macrocode} +\SGMLdef<t>{\SGMLgrabber{t}\mathrm} +\SGMLdef<bt>{\SGMLgrabber{bt}\mathbf} +% \end{macrocode} +% +% \begin{macrocode} +\SGMLdef<text>{\SGMLgrabber{text}\textnormal}%%%%% not in the dtd???? +% \end{macrocode} +% +% \begin{macrocode} +\SGMLdef<root>{\rootfudge} +\def\rootfudge#1{% + \setbox\rootbox\hbox\bgroup$\m@th\scriptscriptstyle\bgroup#1} +% \end{macrocode} +% +% I think the HTML3 DTD is wrong here\footnote +% {Since confirmed by Dave Raggett, the HTML3 author}, +% it allows the OF element to +% take content, which is at variance with the description in the text. +% \begin{macrocode} +\SGMLdef<of>{\egroup$\egroup\SGMLgrabber{root}\offudge} +\SGMLdef</of>{} +\def\offudge#1{\mathpalette\r@@t{#1}} +% \end{macrocode} +% +% \begin{macrocode} +\SGMLdef<sqrt>{\SGMLgrabber{sqrt}\sqrt} +% \end{macrocode} +% +% \changes{v0.08}{1996/03/16}{Add basic support for array element} +% +% Hate allocating registers, so this will probably go, but for now +% give myself four (global) count registers to play with. +% \begin{macrocode} +\newcount\HTMLrow +\newcount\HTMLcol +\newcount\HTMLrowspan +\newcount\HTMLcolspan +% \end{macrocode} +% +% The HTML array element. Support for ALIGN, COLSPAN, ROWSPAN +% LABELS, LDELIM and RDELIM. However not all combinations of alignment +% and labels do `the right thing'. +% +% \changes{v0.09}{1996/03/21}{COLSPEC support for ARRAY} +% +% Uses a \TeX\ primitive |\halign| construction, rather than use the +% \LaTeX\ |array| environment directly. +% \begin{macrocode} +\SGMLdef<array>{{\ifnum`}=0\fi + \let\do\arraydo + \let\doimplied\arrayimplied + \let\HTMLal.% + \let\HTMLar.% + \global\HTMLrow\z@ + \let\HTMLabox\vcenter + \the\toks@ + \setbox\z@\vbox\bgroup\halign\bgroup + \strut\span\HTMLacolspec\cr\nocr} +% \end{macrocode} +% +% \begin{macro}{\HTMLacolspec} +% \changes{v0.09}{1996/03/21}{macro added} +% \begin{macrocode} +\def\HTMLacolspec{##&&##} +% \end{macrocode} +% \end{macro} +% + +% \begin{macro}{\HTMLamakepream} +% \changes{v0.09}{1996/03/21}{macro added} +% \begin{macrocode} +\def\HTMLamakepream#1{% + \let\HTMLacolspec\@empty + \let\@sharp\relax + \lowercase{\@tfor\@tempc:=#1}\do{% + \if\@tempc l% + \edef\HTMLacolspec{\HTMLacolspec\@sharp\hfill&}% + \else + \if\@tempc c% + \edef\HTMLacolspec{\HTMLacolspec\hfill\@sharp\hfill&}% + \else + \if\@tempc r% + \edef\HTMLacolspec{\HTMLacolspec\hfill\@sharp&}% + \else + \if\@tempc +% + \edef\HTMLacolspec{\HTMLacolspec$+$}% + \else + \if\@tempc -% + \edef\HTMLacolspec{\HTMLacolspec$-$}% + \else + \if\@tempc =% + \edef\HTMLacolspec{\HTMLacolspec$=$}% + \fi + \fi + \fi + \fi + \fi + \fi}% + \def\@sharp{########}% + \edef\HTMLacolspec{\HTMLacolspec&\@sharp}} +% \end{macrocode} +% \end{macro} +% +% \begin{macrocode} +\SGMLdef</array>{\HTMLendarray} +% \end{macrocode} +% +% \begin{macrocode} +\let\HTMLcr\cr +% \end{macrocode} +% +% \begin{macro}{\HTMLendarray} +% Non LABELS ending +% \begin{macrocode} +\def\HTMLendarray{% + \endi\crcr\egroup\egroup + \ifx\HTMLabox\vtop + \setbox\z@\vtop{\unvbox\z@}% + \else + \ifx\HTMLabox\vcenter + \dimen@\ht\z@ + \advance\dimen@\dp\z@ + \divide\dimen@\tw@ + \advance\dimen@-\ht\z@ + \setbox\z@\hbox{\raise\dimen@\box\z@}% + \fi + \fi + \dimen@=\ht\z@ + \setbox\z@ +\hbox{$\left\HTMLal\kern-1em\vcenter{\box\z@}\kern-1em\right\HTMLar$}% + \advance\dimen@-\ht\z@ + \raise\dimen@\box\z@ + \ifnum`{=0\fi}} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\HTMLendarraylabels} +% LABELS ending +% \begin{macrocode} +\def\HTMLendarraylabels{% + \endi\crcr\strut\cr\egroup\egroup + \setbox2=\vsplit\z@ to \baselineskip + \setbox\z@\vbox{\unvbox\z@\global\setbox\@ne\lastbox}% + \setbox4\hbox{\unhbox\@ne\unskip\global\setbox\@ne\lastbox}% + \vcenter{% + \box2 + \hbox{$\kern\wd\@ne + \left\HTMLal\kern-\wd\@ne + \vcenter{\box\z@}% + \right\HTMLar$}}% + \ifnum`{=0\fi}} +% \end{macrocode} +% \end{macro} +% +% \begin{macrocode} +\def\nocr{\relax\iffalse{\fi\let\HTMLcr\relax\iffalse}\fi} +% \end{macrocode} +% +% \begin{macrocode} +\SGMLdef<row>{% + \endi\HTMLcr + \global\advance\HTMLrow\@ne + \global\HTMLcol\z@} +% \end{macrocode} +% +% \begin{macrocode} +\SGMLdef</row>{} +% \end{macrocode} +% +% \begin{macrocode} +\SGMLdef<item>{% + \let\do\itemdo + \gdef\@gtempa{\global\advance\HTMLcol\@ne}% + \gdef\@gtempb{}% + \gdef\@gtempc{}% + \global\HTMLcolspan\@ne + \the\toks@ + \endi% + \@gtempc + \@gtempa +% \end{macrocode} +% +% If an earlier row contained an entry spanning down to this point, +% need to jump across to the next column (and perhaps further). +% \begin{macrocode} + \spanifneeded +% \end{macrocode} +% +% |\@gtempb| is normally empty but will be defined if the item had an +% ALIGN attribute. +% \begin{macrocode} + \@gtempb +% \end{macrocode} +% First box each entry which allows measuring needed (but not yet +% done) for vertical spanning. +% \begin{macrocode} + \setbox\z@\hbox\bgroup$% + \def\endi{\unskip$\egroup% + \quad\HTMLaleft\box\z@\HTMLaright\quad&}% + \ignorespaces} +% \end{macrocode} +% +% \begin{macro}{\spanifneeded} +% If the current row/column is in the list of spanned entries, jump to +% next column and look again. +% \begin{macrocode} +\def\spanifneeded{% + \edef\@tempa{\noexpand\in@{,\the\HTMLrow/\the\HTMLcol,}{\spanitems}}% + \@tempa + \ifin@ + \@firstofone{&}\global\advance\HTMLcol\@ne + \expandafter\spanifneeded + \fi} +% \end{macrocode} +% \end{macro} +% +% As usual handle end tags that may be omitted by making them +% translate to empty. +% \begin{macrocode} +\SGMLdef</item>{} +% \end{macrocode} +% +% \begin{macro}{\HTMLaleft} +% \begin{macro}{\HTMLaright} +% Default stuff to put around the entries. Locally redefined by an +% ALIGN attribute. +% \begin{macrocode} +\let\HTMLaleft\hfil +\let\HTMLaright\hfil +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\endi} +% Code to end an item. Extra indirection used to handle omitted tags. +% \begin{macrocode} +\let\endi\relax +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\arraydo} +% \changes{v0.09}{1996/03/21}{COLSPEC added} +% Handle ARRAY attributes. +% \begin{macrocode} +\def\arraydo#1#2{% + \def\@tempa{#1}\def\@tempb{#2}% + \def\@tempc{align}% + \ifx\@tempa\@tempc + \def\@tempc{top}% + \ifx\@tempb\@tempc + \let\HTMLabox\vtop + \else + \def\@tempc{bottom}% + \ifx\@tempb\@tempc + \let\HTMLabox\vbox + \fi + \fi + \else + \def\@tempc{ldelim}% + \ifx\@tempa\@tempc + \let\HTMLal\@tempb + \else + \def\@tempc{rdelim}% + \ifx\@tempa\@tempc + \let\HTMLar\@tempb + \else + \def\@tempc{labels}% + \ifx\@tempa\@tempc + \let\HTMLendarray\HTMLendarraylabels + \else + \def\@tempc{colspec}% + \ifx\@tempa\@tempc + \HTMLamakepream{#2}% + \fi + \fi + \fi + \fi + \fi} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\arrayimplied} +\def\arrayimplied#1{% + \def\@tempa{labels}\def\@tempb{#1}% + \ifx\@tempa\@tempb + \let\HTMLendarray\HTMLendarraylabels + \fi} +% \end{macro} +% +% \begin{macro}{\itemdo} +% Handle ITEM attributes +% \begin{macrocode} +\def\itemdo#1#2{% + \def\@tempa{#1}\def\@tempb{#2}% + \def\@tempc{colspan}% + \ifx\@tempa\@tempc + \global\HTMLcolspan#2\relax + \gdef\@gtempa{\@multispan#2\relax\global\advance\HTMLcol#2\relax}% + \else + \def\@tempc{align}% + \ifx\@tempa\@tempc + \def\@tempc{left}% + \ifx\@tempb\@tempc + \gdef\@gtempb{\let\HTMLaleft\relax}% + \else + \def\@tempc{right}% + \ifx\@tempb\@tempc + \gdef\@gtempb{\let\HTMLaright\relax}% + \fi + \fi + \else + \def\@tempc{rowspan}% + \ifx\@tempa\@tempc + \global\HTMLrowspan#2\relax + \gdef\@gtempc{% + \@tempcnta=\HTMLrow + \advance\@tempcnta\HTMLrowspan +% \end{macrocode} +% +% Double loop adds all the entries below this a ROWSPAN entry +% to |\spanitems| list. +% \begin{macrocode} + \loop + \@tempcntb=\HTMLcol + \advance\@tempcntb\HTMLcolspan + \advance\@tempcnta\m@ne + \ifnum\@tempcnta>\HTMLrow + {\loop + \xdef\spanitems{% + \spanitems\the\@tempcnta/\the\@tempcntb,}% + \advance\@tempcntb\m@ne + \ifnum\@tempcntb>\HTMLcol + \repeat}% + \repeat}% + \fi + \fi + \fi} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\spanitems} +% Initial value for list of spanned entries. +% \begin{macrocode} +\def\spanitems{,} +% \end{macrocode} +% \end{macro} +% +% \begin{macrocode} +\SGMLentity{thinsp}{\,} +\SGMLentity{emsp}{\quad} +% \end{macrocode} +% +% Far from final list of math symbol entity names\ldots +% \begin{macrocode} +\SGMLentity{alpha}{\alpha} +\SGMLentity{beta}{\beta} +\SGMLentity{gamma}{\gamma} +\SGMLentity{Gamma}{\Gamma} +% \end{macrocode} +% +% \begin{macrocode} +\SGMLentity{int}{\int} +\SGMLentity{sum}{\sum} +% \end{macrocode} +% +% \begin{macrocode} +\SGMLentity{lbrace}{\lbrace} +\SGMLentity{rbrace}{\rbrace} +% \end{macrocode} +% +% \begin{macrocode} +\SGMLentity{times}{\times} +\SGMLentity{cup}{\cup} +\SGMLentity{cap}{\cap} +\SGMLentity{vee}{\vee} +\SGMLentity{wedge}{\wedge} +\SGMLentity{infty}{\infty} +\SGMLentity{oplus}{\oplus} +\SGMLentity{ominus}{\ominus} +\SGMLentity{otimes}{\otimes} +% \end{macrocode} +% +% \begin{macrocode} +\SGMLentity{sin}{\sin} +\SGMLentity{cos}{\cos} +\SGMLentity{tan}{\tan} +% \end{macrocode} +% +% \section{HTML3 Tables} +% \changes{v0.09}{1996/03/21}{TABLE added (mjd)} +% Not done yet, but here is a start\ldots +% +% Final version will probably need primitive |\halign| coding +% as for (but hopefully better than) array stuff above. Also +% will need to be lontable-like. +% +% This is all very slapdash and temporary [mjd,1996/03/20]. +% Don't expect good-looking results, just results, occasionally. +% +% \begin{macrocode} +\SGMLdef<table>{\begin{table}[htp]\centering\begin{tabular}{*{10}c}} +\SGMLdef</table>{\end{tabular}\end{table}} +\SGMLdef<tr>{\ifhmode\expandafter\\\fi\relax} +\SGMLdef</tr>{\\\relax} +\SGMLdef<td>{\ifvmode\else\expandafter\hiddenamp\fi} +\def\hiddenamp{&} +% \end{macrocode} +% if |<td>| is present for each cell, then |</td>| doesn't +% need to do anything +% \begin{macrocode} +\SGMLdef</td>{} +% \end{macrocode} +% +% Whoa, if I'm to define caption properly I'd have to look up +% how/where it's used. Who, lazy old me? +% +% \begin{macrocode} +\SGMLdef<caption>{\end{tabular}\begingroup\bfseries} +\SGMLdef</caption>{\endgroup\par\smallskip\begin{tabular}{*{10}{c}}} +% \end{macrocode} +% +% \begin{macrocode} +%</package> +% \end{macrocode} +% +% \Finale +% diff --git a/doc/cmu-user/typehtml.ins b/doc/cmu-user/typehtml.ins new file mode 100644 index 0000000000..77fefef3fe --- /dev/null +++ b/doc/cmu-user/typehtml.ins @@ -0,0 +1,3 @@ +\def\batchfile{typehtml.ins} +\input docstrip +\generateFile{typehtml.sty}{f}{\from{typehtml.dtx}{package}} diff --git a/doc/cmu-user/typehtml.sty b/doc/cmu-user/typehtml.sty new file mode 100644 index 0000000000..c07cf79269 --- /dev/null +++ b/doc/cmu-user/typehtml.sty @@ -0,0 +1,899 @@ +%% +%% This is file `typehtml.sty', +%% generated with the docstrip utility. +%% +%% The original source files were: +%% +%% typehtml.dtx (with options: `package') +%% +%% IMPORTANT NOTICE: +%% +%% For the copyright see the source file. +%% +%% Any modified versions of this file must be renamed +%% with new filenames distinct from typehtml.sty. +%% +%% For distribution of the original source see the terms +%% for copying and modification in the file typehtml.dtx. +%% +%% This generated file may be distributed as long as the +%% original source files, as listed above, are part of the +%% same distribution. (The sources need not necessarily be +%% in the same archive or directory.) +%% +%% Source File `typehtml.dtx'. +%% Copyright (C) 1996 1997 David Carlisle +%% This file may be distributed under the terms of the LPPL. +%% See 00readme.txt for details. +%% +\NeedsTeXFormat{LaTeX2e}[1995/06/01] +\ProvidesPackage{typehtml} + [1997/11/19 v0.12 HTML printer (DPC)] +\DeclareOption{html2}{\let\HTML@two@stop\endinput} +\DeclareOption{netscape} + {\def\HTML@not#1{\SGML@w{<#1> is not valid HTML}}} +\DeclareOption{html3}{\let\HTML@two@stop\relax} +\DeclareOption{nohyperref}{% + \let\HTML@doname\@secondoftwo + \def\HTML@dosrc#1#2{\emph{#2}}} +\DeclareOption{ftnhyperref}{% + \let\HTML@doname\@secondoftwo + \def\HTML@dosrc#1#2{\emph{#2}\footnote{HREF: \texttt{#1}}}} +\DeclareOption{hyperref}{% + \AtBeginDocument{% + \providecommand\href[2]{\special{html:<A href="#1">}% + #2\special{html:</A>}}% + \providecommand\hypertarget[2]{\special{html:<A name="#1">}% + #2\special{html:</A>}}% + \let\HTML@doname\hypertarget + \let\HTML@dosrc\href}} +\DeclareOption{dviwindo}{% + \def\HTML@dosrc#1#2{{% + \leavevmode\sbox\z@{#2}\count@\ht\z@\@tempcnta\wd\z@ + \if\string##\@car#1\@nil + \special{button: \the\@tempcnta\space\the\count@\space + "\@gobble#1"}% + \else + \special{button: \the\@tempcnta\space\the\count@\space + launch: typehtml "#1"} + \fi + \special{color push}\special{color rgb 0 1 0}% + \unhbox\z@ + \special{color pop}}}% + \def\HTML@doname#1#2{\leavevmode\special{mark: "#1"}#2}}% +\DeclareOption{imgalt}{} +\DeclareOption{imggif}{\SGML@w{img gif support not done yet}} +\DeclareOption{imgps}{\SGML@w{img ps support not done yet}} +\DeclareOption{smartquotedbl}{% + \def\SGMLquotedbla{% + \textquotedblleft\global\let\SGMLquotedbl\SGMLquotedblb} + \def\SGMLquotedblb{% + \textquotedblright\global\let\SGMLquotedbl\SGMLquotedbla} + \let\SGMLquotedbl\SGMLquotedbla + \let\SGML@savedeverypar\everypar + \newtoks\everypar + \SGML@savedeverypar{% + \global\let\SGMLquotedbl\SGMLquotedbla\the\everypar}} +\DeclareOption{straightquotedbl}{% + \DeclareTextCommandDefault{\textquotedbl}{{\ttfamily\char`\"}}% + \let\SGMLquotedbl\textquotedbl} +\DeclareOption{chapter}{% + \def\HTML@headings{% + \chapter\section\subsection% + \subsubsection\paragraph\subparagraph}} +\DeclareOption{chapter*}{% + \def\HTML@headings{% + {\chapter*}{\section*}{\subsection*}% + {\subsubsection*}{\paragraph*}{\subparagraph*}}} +\DeclareOption{section}{% + \def\HTML@headings{% + \section\subsection% + \subsubsection\paragraph\subparagraph\endgraf}} +\DeclareOption{section*}{% + \def\HTML@headings{% + {\section*}{\subsection*}% + {\subsubsection*}{\paragraph*}{\subparagraph*}\endgraf}} +\DeclareOption{subsection}{% + \def\HTML@headings{% + \subsection% + \subsubsection\paragraph\subparagraph\endgraf\endgraf}} +\DeclareOption{subsection*}{% + \def\HTML@headings{% + {\subsection*}% + {\subsubsection*}{\paragraph*}{\subparagraph*}\endgraf\endgraf}} +\DeclareOption{bigint}{% + \let\HTML@int\int + \AtEndOfPackage{\RequirePackage{exscale}}} +\ExecuteOptions{section*,imgalt,html2,nohyperref,straightquotedbl} +\ProcessOptions +\begingroup +\catcode`\<=\active +\catcode`\>=\active +\catcode`\&=\active +\catcode`\$=\active +\catcode`\"=\active +\catcode`\^=\active +\catcode`\_=\active +\catcode`\;=\active +\catcode`\A=\active +\catcode`\B=\active +\catcode`\C=\active +\catcode`\D=\active +\uccode`\A=`\{% +\uccode`\B=`\}% +\uccode`\C=`\|% +\uccode`\D=`\\% +\uppercase{\endgroup +\def\SGMLent@@#1;{\csname SGML@E@#1\endcsname} +\def\SGML@def@active#1>{% + \expandafter\def\csname SGML@#1\endcsname} +\def\dohtml{% + \begingroup + \ifx;\@undefined\expandafter\let\expandafter;\string;\fi + \ifx>\@undefined\expandafter\let\expandafter>\string>\fi + \catcode`\<=\active + \catcode`\>=\active + \catcode`\&=\active + \catcode`\{=\active + \catcode`\}=\active + \catcode`\$=\active + \catcode`\"=\active + \catcode`\^=\active + \catcode`\_=\active + \catcode`\\=\active + \catcode`\|=\active + \catcode\endlinechar=10 + \catcode`\%=12 + \catcode`\#=12 + \catcode`\;=\active + \def\verbatim@nolig@list{\do\`\do\,\do\'\do\-} + \def<{\SGMLopen}% + \def&{\SGMLent}% + \let^\textasciicircum + \let~\textasciitilde + \def_{\_}% + \let$\$% + \def"{\SGMLquotedbl}% + \def A{\{}% + \def B{\}}% + \def C{\texttt{|}}% + \def D{\texttt{\char`\\}}% + \def\addcontentsline##1##2##3{% + {\def<{\string<}\def&{\string&}% + \addtocontents{##1}{\protect\dotochtml<html>}% + \addtocontents{##1}{\protect\contentsline{##2}{##3}{\thepage}}% + \addtocontents{##1}{\protect</html>}}}} +\def\dotochtml{% + \dohtml + \catcode`\\\z@ + \catcode`\{\@ne + \catcode`\}\tw@} +\def\SGMLshortend{/} +\def\SGMLgrab@#1<#2>{% + \edef\@tempd{\lowercase{\def\noexpand\@tempd{\gobblespc#2 \relax}}}% + \@tempd + \ifx\@tempd\SGMLshortend\let\@tempd\@tempc\fi + \ifx\@tempb\@tempd + \advance\@tempcnta\@ne + \else + \ifx\@tempc\@tempd + \advance\@tempcnta\m@ne + \fi + \fi + \ifnum\@tempcnta=\z@ + \expandafter\@tempa\expandafter{\the\@temptokena#1}% + \else + \addto@hook\@temptokena{#1<#2>}% + \expandafter\SGMLgrab@ + \fi} +\def\SGMLopen#1>{% + \SGMLopen@#1 \@nil} +} +\def\htmlinput#1{\dohtml\let\@endhtml\relax\input{#1}\endgroup} +\def\gobblespc#1 #2\relax{#1} +\def\SGMLgrabber#1#2{% + \def\@tempa{#2}% + \@tempcnta\@ne + \@temptokena{}% + \lowercase{\def\@tempb{#1}\def\@tempc{/#1}}% + \SGMLgrab@} +\begingroup +\catcode`\"=\active +\uppercase{\endgroup +\def\SGMLopen@#1 #2\@nil{% + \toks@{}% + \edef\@tempa{\lowercase{\def\noexpand\SGMLelement{#1}}}\@tempa + \if!\@car#1\relax\@nil + \toks@{#1 #2}% + \SGML@w{Declaration ignored\MessageBreak<\the\toks@>\MessageBreak}% + \else + \if$#2$\else + \replacequotes#2"\@nil"% + \SGMLafterfi + \expandafter\toks@\expandafter{\expandafter}% + \expandafter\SGMLgetattrib\the\toks@ \@nil + \fi + \expandafter\ifx\csname SGML@\SGMLelement + \expandafter\endcsname\relax + \SGML@w{<\SGMLelement> undefined}% + \else + \csname SGML@\SGMLelement + \expandafter\expandafter\expandafter\endcsname + \fi + \fi} +\def\replacequotes#1"#2"{% + \def\@tempb{#2}% + \ifx\@tempb\@nnil + \addto@hook\toks@{#1}% + \else + \addto@hook\toks@{#1{#2}}% + \expandafter\replacequotes + \fi}} +\def\SGMLafterfi#1\fi{\fi#1} +\def\SGMLgobbletofi#1\fi{\fi} +\def\SGMLgetattrib#1 #2{% + \ifx\box#1\box\else + \SGMLgetval#1=$=\@nil + \def\@tempa{#2}% + \ifx\@tempa\@nnil + \expandafter\SGMLgobbletofi + \else + \expandafter\SGMLafterfi + \fi + \SGMLgetattrib#2% + \fi} +\def\SGMLgetval#1=#2=#3\@nil{% + \ifcat$#2% + \lowercase{\SGML@addattrib\doimplied{#1}}% + \else + \lowercase{\SGML@addattrib{\do{#1}}}{#2}% + \fi} +\def\SGML@addattrib#1#2{\addto@hook\toks@{#1{#2}}} +\def\SGML@w{\PackageWarning{typehtml}} +\def\SGMLdef#1{% + \ifcat\noexpand#1\noexpand~% + \expandafter\SGML@def@active + \else + \expandafter\SGML@def + \fi} +\edef\@tempa{\def\noexpand\SGML@def##1\string>}\@tempa{% + \expandafter\def\csname SGML@#1\endcsname} +\expandafter\def\expandafter\SGMLent\expandafter{% + \expandafter\protect\csname& \endcsname} +\expandafter\def\csname& \endcsname{% + \futurelet\@let@token\SGMLent@} +\def\SGMLent@{% + \ifx\@let@token\@sptoken + \&% + \else + \expandafter\SGMLent@@ + \fi} +\def\SGMLentity#1{% + \expandafter\def\csname SGML@E@#1\endcsname} +\SGMLdef<html>{} +\SGMLdef</html>{\@endhtml} +\let\@endhtml\endgroup +\SGMLdef<title>{\typeout{***TITLE***}\SGMLgrabber{title}\typeout} +\long\def\@tempa#1#2#3#4#5#6{% + \SGMLdef<h1>{\SGMLgrabber{h1}{\HTMLsection{#1}}}% + \SGMLdef<h2>{\SGMLgrabber{h2}{\HTMLsection{#2}}}% + \SGMLdef<h3>{\SGMLgrabber{h3}{\HTMLsection{#3}}}% + \SGMLdef<h4>{\SGMLgrabber{h4}{\HTMLsection{#4}}}% + \SGMLdef<h5>{\SGMLgrabber{h5}{\HTMLsection{#5}}}% + \SGMLdef<h6>{\SGMLgrabber{h6}{\HTMLsection{#6}}}} +\expandafter\@tempa\HTML@headings +\def\HTMLsection#1#2{#1{\ignorespaces#2\unskip}} +\SGMLdef<head>{} +\SGMLdef</head>{} +\SGMLdef<body>{} +\SGMLdef</body>{} +\SGMLdef<bodytext>{} +\SGMLdef</bodytext>{} +\SGMLdef<p>{\par} +\SGMLdef</p>{\par} +\SGMLdef<blockquote>{\begin{quote}} +\SGMLdef</blockquote>{\end{quote}} +\SGMLdef<address>{\begin{quote}} +\SGMLdef</address>{\end{quote}} +\SGMLdef<ul>{\begin{itemize}} +\SGMLdef</ul>{\end{itemize}} +\SGMLdef<ol>{\begin{enumerate}} +\SGMLdef</ol>{\end{enumerate}} +\SGMLdef<li>{\item} +\SGMLdef</li>{} +\SGMLdef<dl>{% + \let\do\dldo + \let\doimplied\dlimplied + \begin{description}\the\toks@} +\SGMLdef</dl>{\end{description}} +\def\dldo#1#2{% + \def\@tempa{compact}\def\@tempb{#1}% + \ifx\@tempa\@tempb + \itemsep\z@ + \advance\@totalleftmargin-\leftmargin + \advance\linewidth\leftmargin + \itemindent-\labelsep + \leftmargin\z@ + \parshape \@ne \@totalleftmargin \linewidth + \fi} +\def\dlimplied#1{\dldo{#1}\relax} +\def\itx#1{\item[#1]} +\SGMLdef<dt>{\begin{lrbox}\z@\bfseries\let\maybeenddt\enddt} +\SGMLdef</dt>{\maybeenddt} +\SGMLdef<dd>{\maybeenddt} +\SGMLdef</dd>{} +\def\enddt{\end{lrbox}\item[\unhbox\z@]} +\let\maybeenddt\relax +\SGMLdef<a>{\SGMLgrabber{a}\HTML@anchor} +\def\HTML@anchor#1{{% + \let\@tempa\@gobble + \def\_{\string_}% + \let\do\ado + \the\toks@ + \@tempa{#1}}} +\def\ado#1#2{% + \def\@tempb{name}\def\@tempc{#1}% + \ifx\@tempb\@tempc + \let\@tempa\@firstofone + \def\@tempa{\HTML@doname{#2}}% + \else + \def\@tempa{\HTML@dosrc{#2}}% + \fi} +\SGMLdef<pre>{% + \par + \begingroup + \parindent\z@ + \obeylines\verbatim@font\@noligs + \frenchspacing\@vobeyspaces} +\SGMLdef</pre>{\endgroup} +\SGMLdef<tt>{\SGMLgrabber{tt}\texttt} +\SGMLdef<b>{\SGMLgrabber{b}\textbf} +\SGMLdef<i>{\SGMLgrabber{i}\textit} +\SGMLdef<em>{\SGMLgrabber{em}\emph} +\SGMLdef<strong>{\SGMLgrabber{strong}\textbf} +\SGMLdef<code>{\SGMLgrabber{code}\texttt} +\SGMLdef<samp>{\SGMLgrabber{samp}\textsf} +\SGMLdef<kbd>{\SGMLgrabber{kbd}\texttt} +\SGMLdef<var>{\SGMLgrabber{var}\textit} +\SGMLdef<cite>{\SGMLgrabber{cite}\textit} +\SGMLdef<form>{\par\medskip} +\SGMLdef</form>{\par\medskip} +\SGMLdef<select>{% + \let\do\selectdo + \the\toks@\par + \begin{tabular}{|l|}% + \hline\@tempc\\\hline + \let\tabularnewline\relax + \ignorespaces} +\def\selectdo#1#2{% + \def\@tempa{name}\def\@tempb{#1}% + \ifx\@tempa\@tempb\def\@tempc{#2}\fi} +\SGMLdef</select>{\\\hline\end{tabular}} +\SGMLdef<option>{% + \gdef\optionbul{\phantom{$\bullet$}}% + \let\do\optiondo + \let\doimplied\optionimplied + \the\toks@ + \tabularnewline + \let\tabularnewline\\% + \optionbul\space\ignorespaces} +\SGMLdef</option>{} +\def\optiondo#1#2{% + \def\@tempa{selected}\def\@tempb{#1}% + \ifx\@tempa\@tempb\gdef\optionbul{$\bullet$}\fi} +\def\optionimplied#1{% + \def\@tempa{selected}\def\@tempb{#1}% + \ifx\@tempa\@tempb\gdef\optionbul{$\bullet$}\fi} +\SGMLdef<input>{} +\SGMLdef<img>{{% + \let\do\imgdo + \def\@tempa{\doimage}% + \the\toks@ + \@tempa}} +\def\doimage{\textsf{[image]}} +\def\imgdo#1{\csname img=#1\endcsname} +\expandafter\def\csname img=align\endcsname#1{% + \SGML@w{align=#1 ignored}} +\expandafter\def\csname img=src\endcsname#1{% + \SGML@w{src=#1 ignored}} +\expandafter\def\csname img=height\endcsname#1{% + \SGML@w{height=#1 ignored}} +\expandafter\def\csname img=alt\endcsname#1{% + \def\doimage{#1}} +\SGMLdef<hr>{\par\smallskip\hrule\smallskip} +\SGMLdef<br>{\leavevmode\\} +\SGMLdef<xmp>{% + \SGML@pre + \def\@tempb{/xmp}% + \let\SGMLopen\HTML@xmptest} +\SGMLdef<listing>{% + \SGML@xmp + \def\@tempb{/listing}} +\SGMLdef<plaintext>{% + \SGML@xmp + \def\@tempb{/plaintext}}% +\def\HTML@xmptest#1>{% + \lowercase{\def\@tempa{#1}}% + \ifx\@tempa\@tempb + \endgroup + \else + \SGMLafterfi + <#1>% + \fi} +\SGMLentity{amp}{\&} +\SGMLentity{lt}{\ensuremath{<}} +\SGMLentity{gt}{\ensuremath{>}} +\SGMLentity{aacute}{\'a} +\SGMLentity{Aacute}\'A{} +\SGMLentity{acirc}{\^a} +\SGMLentity{Acirc}{\^A} +\SGMLentity{agrave}{\`a} +\SGMLentity{Agrave}{\`A} +\SGMLentity{aring}{\r a} +\SGMLentity{Aring}{\r A} +\SGMLentity{atilde}{\~a} +\SGMLentity{Atilde}{\~A} +\SGMLentity{auml}{\"a} +\SGMLentity{Auml}{\"A} +\SGMLentity{aelig}{\ae} +\SGMLentity{AElig}{\AE} +\SGMLentity{ccedil}{\c c} +\SGMLentity{Ccedil}{\c C} +\SGMLentity{eth}{\dh} +\SGMLentity{ETH}{\DH} +\SGMLentity{eacute}{\'e} +\SGMLentity{Eacute}{\`E} +\SGMLentity{ecirc}{\^e} +\SGMLentity{Ecirc}{\^E} +\SGMLentity{egrave}{\`e} +\SGMLentity{Egrave}{\`E} +\SGMLentity{euml}{\"e} +\SGMLentity{Euml}{\"E} +\SGMLentity{iacute}{\'\i} +\SGMLentity{Iacute}{\'I} +\SGMLentity{icirc}{\^\i} +\SGMLentity{Icirc}{\^I} +\SGMLentity{igrave}{\`\i} +\SGMLentity{Igrave}{\`I} +\SGMLentity{iuml}{\"\i} +\SGMLentity{Iuml}{\"I} +\SGMLentity{ntilde}{\~n} +\SGMLentity{Ntilde}{\~N} +\SGMLentity{oacute}{\'o} +\SGMLentity{Oacute}{\'O} +\SGMLentity{ocirc}{\^o} +\SGMLentity{Ocirc}{\^O} +\SGMLentity{ograve}{\`o} +\SGMLentity{Ograve}{\`O} +\SGMLentity{oslash}{\oe} +\SGMLentity{Oslash}{\OE} +\SGMLentity{otilde}{\~o} +\SGMLentity{Otilde}{\~O} +\SGMLentity{ouml}{\"o} +\SGMLentity{Ouml}{\"O} +\SGMLentity{szlig}{\ss} +\SGMLentity{thorn}{\th} +\SGMLentity{THORN}{\TH} +\SGMLentity{uacute}{\'u} +\SGMLentity{Uacute}{\'U} +\SGMLentity{ucirc}{\^u} +\SGMLentity{Ucirc}{\^U} +\SGMLentity{ugrave}{\`u} +\SGMLentity{Ugrave}{\`U} +\SGMLentity{uuml}{\"u} +\SGMLentity{Uuml}{\"U} +\SGMLentity{yacute}{\'y} +\SGMLentity{Yacute}{\'Y} +\SGMLentity{yuml}{\"y} +\ifx\HTML@not\@undefined\else +\SGMLdef<center>{\HTML@not{center}\begin{center}} +\SGMLdef</center>{\end{center}} +\SGMLdef<blink>{\SGMLgrabber{blink}\textbf} +\SGMLdef<font>{\HTML@not{font}\begingroup + \let\do\fontdo\the\toks@} +\SGMLdef</font>{\endgroup} +\def\fontdo#1#2{% + \def\@tempa{size}\def\@tempb{#1}% + \ifx\@tempa\@tempb + \font@switch#2\relax\@nil + \fi} +\toks@\expandafter{\set@fontsize{#1}{#2}{#3}} +\edef\@tempa{% + \def\noexpand\set@fontsize##1##2##3{\the\toks@\noexpand\set@fontnum}} +\@tempa +\def\set@fontnum{\dimen@\f@size\p@ + \dimen@\mul@ptsize\dimen@ + \count@\dimen@ \divide\count@\p@ + \advance\count@ -5\relax + \edef\@fontnum{\number\count@}} +\def\mul@ptsize{}% +\def\@fontnum{5} +\ifcase 0\@ptsize\relax + \global\let\mul@ptsize\@empty% case 0, ptsize = 10 + \or\gdef\mul@ptsize{.9091}% case 1, ptsize = 11 + \else\gdef\mul@ptsize{.8333}% case 2, ptsize = 12 +\fi +\def\font@switch#1#2\@nil{\count@\@fontnum\relax + \ifx +#1\advance\else\ifx -#1\advance\fi\fi + \count@#1#2\relax + \ifcase\count@ \tiny\or \tiny\or \scriptsize + \or\footnotesize \or\small \or\normalsize \or\large + \or\Large \or\LARGE \or\huge \else\Huge \fi} +\fi +\HTML@two@stop +\SGML@w{HTML3 support not finished yet} +\SGMLdef<math>{\SGMLgrabber{math}\domath} +\SGMLdef<sup>{^\bgroup\HTMLscriptmap} +\SGMLdef</sup>{\egroup} +\SGMLdef<sub>{_\bgroup\HTMLscriptmap} +\SGMLdef</sub>{\egroup} +\SGMLdef<box>{\SGMLgrabber{box}\dobox} +\begingroup +\catcode`\<=\active +\catcode`\>=\active +\catcode`\&=\active +\catcode`\_=\active +\catcode`\^=\active +\catcode`\"=\active +\gdef\domath#1{% + {{\def&{\expandafter\expandafter\expandafter\noexpand\SGMLent@@}% + \let<\relax\let>\relax\let_\relax\let^\relax\let"\relax + \def\{{<box>}\def\}{</box>}% + \xdef\@gtempa{#1}}% + \let\do\mathdo + \let\doimplied\mathimplied + \the\toks@ + \[% + \m@th\nulldelimiterspace\z@ + \def^{<sup>}% + \def_{<sub>}% + \@gtempa\]}} +\gdef\HTMLscriptmap{% + \def^{</sup>}% + \def_{</sub>}} +\gdef\dobox#1{% + {\let\do\boxdo + \let\bigstrut\relax + \the\toks@ + \def^{<sup>}% + \def_{<sub>}% + \lookleft@#1<left>\@nil}} +\gdef\lookleft@#1<left>#2\@nil{% + \if$#2$% + {\left.\bgroup#1\mayberight}% + \else + \lookbox@#1<box>\@nil#2\@nil + \fi} +\gdef\lookbox@#1<box>#2\@nil#3<left>\@nil{% + \if$#2$% + {\maybeleft#1\@nil#3\mayberight} + \else + {#1 \boxtofront#2 <left> #3}% + \fi} +\gdef\boxtofront#1<box>{<box>#1} +\endgroup +\def\mathdo#1#2{% + \def\@tempa{class-chem}\def\@tempb{#1-#2}% + \ifx\@tempa\@tempb + \everymath{\fam\z@}\everydisplay{\fam\z@}% + \fi} +\def\mathimplied#1{% + \def\@tempa{box}\def\@tempb{#1}% + \ifx\@tempa\@tempb + \def\[{\center\setbox\z@\hbox\bgroup$\displaystyle}% + \def\]{$\egroup\fbox{\box\z@}\endcenter}% + \fi} +\def\boxdo#1#2{% + \def\@tempa{size}\def\@tempb{#1}% + \ifx\@tempa\@tempb + \def\@tempb{#2} + \def\@tempa{normal}\ifx\@tempa\@tempb\def\@tempc{1}\fi + \def\@tempa{medium}\ifx\@tempa\@tempb\def\@tempc{2}\fi + \def\@tempa{large}\ifx\@tempa\@tempb\def\@tempc{3}\fi + \def\@tempa{huge}\ifx\@tempa\@tempb\def\@tempc{4}\fi + \edef\bigstrut{\vrule\@height\@tempc\ht\strutbox\@width\z@} + \fi} +\SGMLdef<left>{\left.\bgroup} +\def\mayberight{\egroup\bigstrut\right.} +\def\maybeleft#1#2\@nil{% + \in@{#1}{()[]\SGML@E@rbrace\SGML@E@lbrace}% + \ifin@ + \left#1\bgroup#2% + \else + \let\SGML@E@int\HTML@bigint + #1#2\left.\bgroup\let\SGML@E@int\int + \fi} +\def\righttest#1{% + \in@{#1}{()[]\SGML@E@rbrace\SGML@E@lbrace}% + \ifin@ + \right#1\let\mayberight\relax + \else + \right.\let\mayberight\relax\expandafter#1% + \fi} +\ifx\HTML@int\@undefined +\let\HTML@bigint\int +\else +\def\HTML@int{\int^{\box\tw@}_{\box4}} +\def\HTML@bigint#1\left.\bgroup{% + \def\@tempa{#1}% + \setbox\z@\hbox\bgroup + \aftergroup\HTMLafterbigint$\displaystyle\bgroup + \aftergroup$\aftergroup\egroup} +\def\HTMLafterbigint{% + \dimen@.5\ht\z@ + \advance\dimen@.5\dp\z@ + {\SGMLdef<sup>{\setbox\tw@\hbox\bgroup\HTMLscriptmap$\scriptstyle}% + \SGMLdef<sub>{\setbox4\hbox\bgroup\HTMLscriptmap$\scriptstyle}% + \SGMLdef</sup>{$\egroup}% + \SGMLdef</sub>{$\egroup}% + \setbox\tw@\box\voidb@x + \setbox4\box\voidb@x + \@tempa + \ifdim\dimen@>\f@size\p@ + \mathop{\hbox{\DeclareFixedFont\@tempa{OMX}{cmex}{m}{n}\dimen@ + $\displaystyle\textfont\thr@@\@tempa\HTML@int$}}% + \else + \HTML@int + \fi + }\left.\box\z@} +\fi +\SGMLdef<over>{\over} +\SGMLdef<atop>{\atop} +\SGMLdef<choose>{\choose} +\SGMLdef<right>{\egroup\bigstrut\righttest} +\SGMLdef<above>{\SGMLgrabber{above}% + {\let\@tempc\overlineop + \let\do\abovedo + \the\toks@ + \@tempc}} +\SGMLdef<below>{\SGMLgrabber{below}% + {\let\@tempc\underlineop + \let\do\abovedo + \the\toks@ + \@tempc}} +\def\overlineop#1{\mathop{\overline{#1}}} +\def\underlineop#1{\mathop{\underline{#1}}} +\def\abovedo#1#2{% + \def\@tempa{sym}\def\@tempb{#1}% + \ifx\@tempa\@tempb\def\@tempc{\csname#2\endcsname}\fi} +\SGMLdef<vec>{\SGMLgrabber{vec}\vec} +\SGMLdef<bar>{\SGMLgrabber{bar}\bar} +\SGMLdef<dot>{\SGMLgrabber{dot}\dot} +\SGMLdef<ddot>{\SGMLgrabber{ddot}\ddot} +\SGMLdef<hat>{\SGMLgrabber{hat}\hat} +\SGMLdef<tilde>{\SGMLgrabber{tilde}\tilde} +\SGMLdef<t>{\SGMLgrabber{t}\mathrm} +\SGMLdef<bt>{\SGMLgrabber{bt}\mathbf} +\SGMLdef<text>{\SGMLgrabber{text}\textnormal}%%%%% not in the dtd???? +\SGMLdef<root>{\rootfudge} +\def\rootfudge#1{% + \setbox\rootbox\hbox\bgroup$\m@th\scriptscriptstyle\bgroup#1} +\SGMLdef<of>{\egroup$\egroup\SGMLgrabber{root}\offudge} +\SGMLdef</of>{} +\def\offudge#1{\mathpalette\r@@t{#1}} +\SGMLdef<sqrt>{\SGMLgrabber{sqrt}\sqrt} +\newcount\HTMLrow +\newcount\HTMLcol +\newcount\HTMLrowspan +\newcount\HTMLcolspan +\SGMLdef<array>{{\ifnum`}=0\fi + \let\do\arraydo + \let\doimplied\arrayimplied + \let\HTMLal.% + \let\HTMLar.% + \global\HTMLrow\z@ + \let\HTMLabox\vcenter + \the\toks@ + \setbox\z@\vbox\bgroup\halign\bgroup + \strut\span\HTMLacolspec\cr\nocr} +\def\HTMLacolspec{##&&##} + +\def\HTMLamakepream#1{% + \let\HTMLacolspec\@empty + \let\@sharp\relax + \lowercase{\@tfor\@tempc:=#1}\do{% + \if\@tempc l% + \edef\HTMLacolspec{\HTMLacolspec\@sharp\hfill&}% + \else + \if\@tempc c% + \edef\HTMLacolspec{\HTMLacolspec\hfill\@sharp\hfill&}% + \else + \if\@tempc r% + \edef\HTMLacolspec{\HTMLacolspec\hfill\@sharp&}% + \else + \if\@tempc +% + \edef\HTMLacolspec{\HTMLacolspec$+$}% + \else + \if\@tempc -% + \edef\HTMLacolspec{\HTMLacolspec$-$}% + \else + \if\@tempc =% + \edef\HTMLacolspec{\HTMLacolspec$=$}% + \fi + \fi + \fi + \fi + \fi + \fi}% + \def\@sharp{########}% + \edef\HTMLacolspec{\HTMLacolspec&\@sharp}} +\SGMLdef</array>{\HTMLendarray} +\let\HTMLcr\cr +\def\HTMLendarray{% + \endi\crcr\egroup\egroup + \ifx\HTMLabox\vtop + \setbox\z@\vtop{\unvbox\z@}% + \else + \ifx\HTMLabox\vcenter + \dimen@\ht\z@ + \advance\dimen@\dp\z@ + \divide\dimen@\tw@ + \advance\dimen@-\ht\z@ + \setbox\z@\hbox{\raise\dimen@\box\z@}% + \fi + \fi + \dimen@=\ht\z@ + \setbox\z@ +\hbox{$\left\HTMLal\kern-1em\vcenter{\box\z@}\kern-1em\right\HTMLar$}% + \advance\dimen@-\ht\z@ + \raise\dimen@\box\z@ + \ifnum`{=0\fi}} +\def\HTMLendarraylabels{% + \endi\crcr\strut\cr\egroup\egroup + \setbox2=\vsplit\z@ to \baselineskip + \setbox\z@\vbox{\unvbox\z@\global\setbox\@ne\lastbox}% + \setbox4\hbox{\unhbox\@ne\unskip\global\setbox\@ne\lastbox}% + \vcenter{% + \box2 + \hbox{$\kern\wd\@ne + \left\HTMLal\kern-\wd\@ne + \vcenter{\box\z@}% + \right\HTMLar$}}% + \ifnum`{=0\fi}} +\def\nocr{\relax\iffalse{\fi\let\HTMLcr\relax\iffalse}\fi} +\SGMLdef<row>{% + \endi\HTMLcr + \global\advance\HTMLrow\@ne + \global\HTMLcol\z@} +\SGMLdef</row>{} +\SGMLdef<item>{% + \let\do\itemdo + \gdef\@gtempa{\global\advance\HTMLcol\@ne}% + \gdef\@gtempb{}% + \gdef\@gtempc{}% + \global\HTMLcolspan\@ne + \the\toks@ + \endi% + \@gtempc + \@gtempa + \spanifneeded + \@gtempb + \setbox\z@\hbox\bgroup$% + \def\endi{\unskip$\egroup% + \quad\HTMLaleft\box\z@\HTMLaright\quad&}% + \ignorespaces} +\def\spanifneeded{% + \edef\@tempa{\noexpand\in@{,\the\HTMLrow/\the\HTMLcol,}{\spanitems}}% + \@tempa + \ifin@ + \@firstofone{&}\global\advance\HTMLcol\@ne + \expandafter\spanifneeded + \fi} +\SGMLdef</item>{} +\let\HTMLaleft\hfil +\let\HTMLaright\hfil +\let\endi\relax +\def\arraydo#1#2{% + \def\@tempa{#1}\def\@tempb{#2}% + \def\@tempc{align}% + \ifx\@tempa\@tempc + \def\@tempc{top}% + \ifx\@tempb\@tempc + \let\HTMLabox\vtop + \else + \def\@tempc{bottom}% + \ifx\@tempb\@tempc + \let\HTMLabox\vbox + \fi + \fi + \else + \def\@tempc{ldelim}% + \ifx\@tempa\@tempc + \let\HTMLal\@tempb + \else + \def\@tempc{rdelim}% + \ifx\@tempa\@tempc + \let\HTMLar\@tempb + \else + \def\@tempc{labels}% + \ifx\@tempa\@tempc + \let\HTMLendarray\HTMLendarraylabels + \else + \def\@tempc{colspec}% + \ifx\@tempa\@tempc + \HTMLamakepream{#2}% + \fi + \fi + \fi + \fi + \fi} +\def\arrayimplied#1{% + \def\@tempa{labels}\def\@tempb{#1}% + \ifx\@tempa\@tempb + \let\HTMLendarray\HTMLendarraylabels + \fi} +\def\itemdo#1#2{% + \def\@tempa{#1}\def\@tempb{#2}% + \def\@tempc{colspan}% + \ifx\@tempa\@tempc + \global\HTMLcolspan#2\relax + \gdef\@gtempa{\@multispan#2\relax\global\advance\HTMLcol#2\relax}% + \else + \def\@tempc{align}% + \ifx\@tempa\@tempc + \def\@tempc{left}% + \ifx\@tempb\@tempc + \gdef\@gtempb{\let\HTMLaleft\relax}% + \else + \def\@tempc{right}% + \ifx\@tempb\@tempc + \gdef\@gtempb{\let\HTMLaright\relax}% + \fi + \fi + \else + \def\@tempc{rowspan}% + \ifx\@tempa\@tempc + \global\HTMLrowspan#2\relax + \gdef\@gtempc{% + \@tempcnta=\HTMLrow + \advance\@tempcnta\HTMLrowspan + \loop + \@tempcntb=\HTMLcol + \advance\@tempcntb\HTMLcolspan + \advance\@tempcnta\m@ne + \ifnum\@tempcnta>\HTMLrow + {\loop + \xdef\spanitems{% + \spanitems\the\@tempcnta/\the\@tempcntb,}% + \advance\@tempcntb\m@ne + \ifnum\@tempcntb>\HTMLcol + \repeat}% + \repeat}% + \fi + \fi + \fi} +\def\spanitems{,} +\SGMLentity{thinsp}{\,} +\SGMLentity{emsp}{\quad} +\SGMLentity{alpha}{\alpha} +\SGMLentity{beta}{\beta} +\SGMLentity{gamma}{\gamma} +\SGMLentity{Gamma}{\Gamma} +\SGMLentity{int}{\int} +\SGMLentity{sum}{\sum} +\SGMLentity{lbrace}{\lbrace} +\SGMLentity{rbrace}{\rbrace} +\SGMLentity{times}{\times} +\SGMLentity{cup}{\cup} +\SGMLentity{cap}{\cap} +\SGMLentity{vee}{\vee} +\SGMLentity{wedge}{\wedge} +\SGMLentity{infty}{\infty} +\SGMLentity{oplus}{\oplus} +\SGMLentity{ominus}{\ominus} +\SGMLentity{otimes}{\otimes} +\SGMLentity{sin}{\sin} +\SGMLentity{cos}{\cos} +\SGMLentity{tan}{\tan} +\SGMLdef<table>{\begin{table}[htp]\centering\begin{tabular}{*{10}c}} +\SGMLdef</table>{\end{tabular}\end{table}} +\SGMLdef<tr>{\ifhmode\expandafter\\\fi\relax} +\SGMLdef</tr>{\\\relax} +\SGMLdef<td>{\ifvmode\else\expandafter\hiddenamp\fi} +\def\hiddenamp{&} +\SGMLdef</td>{} +\SGMLdef<caption>{\end{tabular}\begingroup\bfseries} +\SGMLdef</caption>{\endgroup\par\smallskip\begin{tabular}{*{10}{c}}} +\endinput +%% +%% End of file `typehtml.sty'. diff --git a/doc/cmu-user/unicode.tex b/doc/cmu-user/unicode.tex new file mode 100644 index 0000000000..f3016a17fc --- /dev/null +++ b/doc/cmu-user/unicode.tex @@ -0,0 +1,733 @@ +\chapter{Internationalization} +\label{i18n} +\cindex{Internationalization} + +\cmucl{} supports internationalization by supporting Unicode +characters internally and by adding support for external formats to +convert from the internal format to an appropriate external character +coding format. + +To understand the support for Unicode, we refer the reader to the +\ifpdf +\href{http://www.unicode.org/}{Unicode standard}. +\else +\emph{Unicode standard} at \url{http://www.unicode.org} +\fi +\section{Changes} + +To support internationalization, the following changes to Common Lisp +functions have been done. + + +\subsection{Design Choices} + +To support Unicode, there are many approaches. One choice is to +support both 8-bit \code{base-char} and a 21-bit (or larger) +\code{character} since Unicode codepoints use 21 bits. This generally +means strings are much larger, and complicates the compiler by having +to support both \code{base-char} and \code{character} types and the +corresponding string types. This also adds complexity for the user to +understand the difference between the different string and character +types. + +Another choice is to have just one character and string type that can +hold the entire Unicode codepoint. While simplifying the compiler and +reducing the burden on the user, this significantly increases memory +usage for strings. + +The solution chosen by \cmucl{} is to tradeoff the size and complexity +by having only 16-bit characters. Most of the important languages can +be encoded using only 16-bits. The rest of the codepoints are for +rare languages or ancient scripts. Thus, the memory usage is +significantly reduced while still supporting the the most important +languages. Compiler complexity is also reduced since \code{base-char} +and \code{character} are the same as are the string types.. But we +still want to support the full Unicode character set. This is +achieved by making strings be UTF-16 strings internally. Hence, Lisp +strings are UTF-16 strings, and Lisp characters are UTF-16 code-units. + + +\subsection{Characters} +\label{sec:i18n:characters} + +Characters are now 16 bits long instead of 8 bits, and \code{base-char} +and \code{character} types are the same. This difference is +naturally indicated by changing \code{char-code-limit} from 256 to +65536. + +\subsection{Strings} +\label{sec:i18n:strings} + +In \cmucl{} there is only one type of string---\code{base-string} and +\code{string} are the same. + +Internally, the strings are encoded using UTF-16. This means that in +some rare cases the number of Lisp characters in a string is not the +same as the number of codepoints in the string. + + +\section{External Formats} + +To be able to communicate to the external world, \cmucl{} supports +external formats to convert to and from the external world to +\cmucl{}'s string format. The external format is specified in several +ways. The standard streams \var{*standard-input*}, +\var{*standard-output*}, and \var{*standard-error*} take the format +from the value specified by \var{*default-external-format*}. The +default value of \var{*default-external-format*} is \kwd{iso8859-1}. + +For files, \code{OPEN} takes the \kwd{external-format} +parameter to specify the format. The default external format is +\kwd{default}. + +\subsection{Available External Formats} + +The available external formats are listed below in +Table~\ref{table:external-formats}. The first column gives the +external format, and the second column gives a list of aliases that +can be used for this format. The set of aliases can be changed by +changing the \file{aliases} file. + +For all of these formats, if an illegal sequence is encountered, no +error or warning is signaled. Instead, the offending sequence is +silently replaced with the Unicode REPLACEMENT CHARACTER (U$+$FFFD). + +\begin{table} + \centering + \begin{tabular}{|l|l|p{3in}|} + \hline + \textbf{Format} & \textbf{Aliases} & \textbf{Description} \\ + \hline + \hline + \kwd{iso8859-1} & \kwd{latin1} \kwd{latin-1} \kwd{iso-8859-1} & ISO8859-1 \\ + \hline + \kwd{iso8859-2} & \kwd{latin2} \kwd{latin-2} \kwd{iso-8859-2} & ISO8859-2 \\ + \hline + \kwd{iso8859-3} & \kwd{latin3} \kwd{latin-3} \kwd{iso-8859-3} & ISO8859-3 \\ + \hline + \kwd{iso8859-4} & \kwd{latin4} \kwd{latin-4} \kwd{iso-8859-4} & ISO8859-4 \\ + \hline + \kwd{iso8859-5} & \kwd{cyrillic} \kwd{iso-8859-5} & ISO8859-5 \\ + \hline + \kwd{iso8859-6} & \kwd{arabic} \kwd{iso-8859-6} & ISO8859-6 \\ + \hline + \kwd{iso8859-7} & \kwd{greek} \kwd{iso-8859-7} & ISO8859-7 \\ + \hline + \kwd{iso8859-8} & \kwd{hebrew} \kwd{iso-8859-8} & ISO8859-8 \\ + \hline + \kwd{iso8859-9} & \kwd{latin5} \kwd{latin-5} \kwd{iso-8859-9} & ISO8859-9 \\ + \hline + \kwd{iso8859-10} & \kwd{latin6} \kwd{latin-6} \kwd{iso-8859-10} & ISO8859-10 \\ + \hline + \kwd{iso8859-13} & \kwd{latin7} \kwd{latin-7} \kwd{iso-8859-13} & ISO8859-13 \\ + \hline + \kwd{iso8859-14} & \kwd{latin8} \kwd{latin-8} \kwd{iso-8859-14} & ISO8859-14 \\ + \hline + \kwd{iso8859-15} & \kwd{latin9} \kwd{latin-9} \kwd{iso-8859-15} & ISO8859-15 \\ + \hline + \kwd{utf-8} & \kwd{utf} \kwd{utf8} & UTF-8 \\ + \hline + \kwd{utf-16} & \kwd{utf16} & UTF-16 with optional BOM \\ + \hline + \kwd{utf-16-be} & \kwd{utf-16be} \kwd{utf16-be} & UTF-16 big-endian (without BOM) \\ + \hline + \kwd{utf-16-le} & \kwd{utf-16le} \kwd{utf16-le} & UTF-16 little-endian (without BOM) \\ + \hline + \kwd{utf-32} & \kwd{utf32} & UTF-32 with optional BOM \\ + \hline + \kwd{utf-32-be} & \kwd{utf-32be} \kwd{utf32-be} & UTF-32 big-endian (without BOM) \\ + \hline + \kwd{utf-32-le} & \kwd{utf-32le} \kwd{utf32-le} & UTF-32 little-endian (without BOM) \\ + \hline + \kwd{cp1250} & & \\ + \hline + \kwd{cp1251} & & \\ + \hline + \kwd{cp1252} & \kwd{windows-1252} \kwd{windows-cp1252} \kwd{windows-latin1} & \\ + \hline + \kwd{cp1253} & & \\ + \hline + \kwd{cp1254} & & \\ + \hline + \kwd{cp1255} & & \\ + \hline + \kwd{cp1256} & & \\ + \hline + \kwd{cp1257} & & \\ + \hline + \kwd{cp1258} & & \\ + \hline + \kwd{koi8-r} & & \\ + \hline + \kwd{mac-cyrillic} & & \\ + \hline + \kwd{mac-greek} & & \\ + \hline + \kwd{mac-icelandic} & & \\ + \hline + \kwd{mac-latin2} & & \\ + \hline + \kwd{mac-roman} & & \\ + \hline + \kwd{mac-turkish} & & \\ + \hline + \end{tabular} + \caption{External formats} + \label{table:external-formats} +\end{table} + +\subsection{Composing External Formats} + +A composing external format is an external format that converts between +one codepoint and another, rather than between codepoints and octets. +A composing external format must be used in conjunction with another +(octet-producing) external format. This is specified by +using a list as the external format. For example, we can use +\code{'(\kwd{latin1} \kwd{crlf})} as the external format. In this +particular example, the external format is latin1, but whenever a +carriage-return/linefeed sequence is read, it is converted to the Lisp +\lispchar{Newline} character. Conversely, whenever a string is written, +a Lisp \lispchar{Newline} character is converted to a +carriage-return/linefeed sequence. Without the \kwd{crlf} composing +format, the carriage-return and linefeed will be read in as separate +characters, and on output the Lisp \lispchar{Newline} character is +output as a single linefeed character. + +Table~\ref{table:composing-formats} lists the available composing formats. + +\begin{table} + \centering + \begin{tabular}{|l|l|p{3in}|} + \hline + \textbf{Format} & \textbf{Aliases} & \textbf{Description} \\ + \hline + \hline + \kwd{crlf} & \kwd{dos} & Composing format for converting to/from DOS (CR/LF) + end-of-line sequence to \lispchar{Newline}\\ + \kwd{cr} & \kwd{mac} & Composing format for converting to/from DOS (CR/LF) + end-of-line sequence to \lispchar{Newline}\\ + \hline + \kwd{beta-gk} & & Composing format that translates (lower-case) Beta + code (an ASCII encoding of ancient Greek) \\ + \hline + \kwd{final-sigma} & & Composing format that attempts to detect sigma in + word-final position and change it from U+3C3 to U+3C2\\ + \hline + \end{tabular} + \caption{Composing external formats} + \label{table:composing-formats} +\end{table} + +\section{Dictionary} + +\subsection{Variables} + +\begin{defvar}{extensions:}{default-external-format} + This is the default external format to use for all newly opened + files. It is also the default format to use for + \var{*standard-input*}, \var{*standard-output*}, and + \var{*standard-error*}. The default value is \kwd{iso8859-1}. + + Setting this will cause the standard streams to start using the new + format immediately. If a stream has been created with external + format \kwd{default}, then setting \var{*default-external-format*} + will cause all subsequent input and output to use the new value of + \var{*default-external-format*}. +\end{defvar} +\subsection{Characters} + +Remember that \cmucl{}'s characters are only 16-bits long but Unicode +codepoints are up to 21 bits long. Hence there are codepoints that +cannot be represented via Lisp characters. Operating on individual +characters is not recommended. Operations on strings are better. +(This would be true even if \cmucl{}'s characters could hold a +full Unicode codepoint.) + +\begin{defun}{}{char-equal}{\amprest{} \var{characters}} + \defunx{char-not-equal}{\amprest{} \var{characters}} + \defunx{char-lessp}{\amprest{} \var{characters}} + \defunx{char-greaterp}{\amprest{} \var{characters}} + \defunx{char-not-greaterp}{\amprest{} \var{characters}} + \defunx{char-not-lessp}{\amprest{} \var{characters}} + For the comparison, the characters are converted to lowercase and + the corresponding \code{char-code} are compared. +\end{defun} + +\begin{defun}{}{alpha-char-p}{\args \var{character}} + Returns non-nil{} if the Unicode category is a letter category. +\end{defun} + +\begin{defun}{}{alphanumericp}{\args \var{character}} + Returns non-nil{} if the Unicode category is a letter category or an ASCII + digit. +\end{defun} + +\begin{defun}{}{digit-char-p}{\args \var{character} \ampoptional{} \var{radix}} + Only recognizes ASCII digits (and ASCII letters if the radix is larger + than 10). +\end{defun} + +\begin{defun}{}{graphic-char-p}{\args \var{character}} + Returns non-nil{} if the Unicode category is a graphic category. +\end{defun} + +\begin{defun}{}{upper-case-p}{\args \var{character}} + \defunx{lower-case-p}{\args \var{character}} + Returns non-nil{} if the Unicode category is an uppercase + (lowercase) character. +\end{defun} + +\begin{defun}{lisp:}{title-case-p}{\args \var{character}} + Returns non-nil{} if the Unicode category is a titlecase character. +\end{defun} + +\begin{defun}{}{both-case-p}{\args \var{character}} + Returns non-nil{} if the Unicode category is an uppercase, + lowercase, or titlecase character. +\end{defun} + +\begin{defun}{}{char-upcase}{\args \var{character}} + \defunx{char-downcase}{\args \var{character}} + The Unicode uppercase (lowercase) letter is returned. +\end{defun} + +\begin{defun}{lisp:}{char-titlecase}{\args \var{character}} + The Unicode titlecase letter is returned. +\end{defun} + +\begin{defun}{}{char-name}{\args \var{char}} + If possible the name of the character \var{char} is returned. If + there is a Unicode name, the Unicode name is returned, except + spaces are converted to underscores and the string is capitalized + via \code{string-capitalize}. If there is no Unicode name, the + form \lispchar{U+xxxx} is returned where ``xxxx'' is the + \code{char-code} of the character, in hexadecimal. +\end{defun} + +\begin{defun}{}{name-char}{\args \var{name}} + The inverse to \code{char-name}. If no character has the name + \var{name}, then \nil{} is returned. Unicode names are not + case-sensitive, and spaces and underscores are optional. +\end{defun} +\subsection{Strings} + +Strings in \cmucl{} are UTF-16 strings. That is, for Unicode code +points greater than 65535, surrogate pairs are used. We refer the +reader to the Unicode standard for more information about surrogate +pairs. We just want to make a note that because of the UTF-16 +encoding of strings, there is a distinction between Lisp characters +and Unicode codepoints. The standard string operations know about +this encoding and handle the surrogate pairs correctly. + + +\begin{defun}{}{string-upcase}{\args \var{string} \keys{\kwd{start} + \kwd{end} \kwd{casing}}} + \defunx{string-downcase}{\args \var{string} \keys{\kwd{start} + \kwd{end} \kwd{casing}}} + \defunx{string-capitalize}{\args \var{string} \keys{\kwd{start} + \kwd{end} \kwd{casing}}} + The case of the \var{string} is changed appropriately. Surrogate + pairs are handled correctly. The conversion to the appropriate case + is done based on the Unicode conversion. The additional argument + \kwd{casing} controls how case conversion is done. The default + value is \kwd{simple}, which uses simple Unicode case conversion. + If \kwd{casing} is \kwd{full}, then full Unicode case conversion is + done where the string may actually increase in length. +\end{defun} + +\begin{defun}{}{nstring-upcase}{\args \var{string} \keys{\kwd{start} \kwd{end}}} + \defunx{nstring-downcase}{\args \var{string} \keys{\kwd{start} \kwd{end}}} + \defunx{nstring-capitalize}{\args \var{string} \keys{\kwd{start} + \kwd{end}}} + The case of the \var{string} is changed appropriately. Surrogate + pairs are handled correctly. The conversion to the appropriate case + is done based on the Unicode conversion. (Full casing is not + available because the string length cannot be increased when needed.) +\end{defun} + +\begin{defun}{}{string=}{\args \var{s1} \var{s2} \keys{\kwd{start1} + \kwd{end1} \kwd{start2} \kwd{end2}}} + \defunx{string/=}{\args \var{s1} \var{s2} \keys{\kwd{start1} \kwd{end1} \kwd{start2} \kwd{end2}}} + \defunx{string\textless}{\args \var{s1} \var{s2} \keys{\kwd{start1} \kwd{end1} \kwd{start2} \kwd{end2}}} + \defunx{string\textgreater}{\args \var{s1} \var{s2} \keys{\kwd{start1} \kwd{end1} \kwd{start2} \kwd{end2}}} + \defunx{string\textless=}{\args \var{s1} \var{s2} \keys{\kwd{start1} \kwd{end1} \kwd{start2} \kwd{end2}}} + \defunx{string\textgreater=}{\args \var{s1} \var{s2} \keys{\kwd{start1} \kwd{end1} \kwd{start2} \kwd{end2}}} + The string comparison is done in codepoint order. (This is + different from just comparing the order of the individual characters + due to surrogate pairs.) Unicode collation is not done. +\end{defun} + +\begin{defun}{}{string-equal}{\args \var{s1} \var{s2} \keys{\kwd{start1} + \kwd{end1} \kwd{start2} \kwd{end2}}} + \defunx{string-not-equal}{\args \var{s1} \var{s2} \keys{\kwd{start1} \kwd{end1} \kwd{start2} \kwd{end2}}} + \defunx{string-lessp}{\args \var{s1} \var{s2} \keys{\kwd{start1} \kwd{end1} \kwd{start2} \kwd{end2}}} + \defunx{string-greaterp}{\args \var{s1} \var{s2} \keys{\kwd{start1} \kwd{end1} \kwd{start2} \kwd{end2}}} + \defunx{string-not-greaterp}{\args \var{s1} \var{s2} \keys{\kwd{start1} \kwd{end1} \kwd{start2} \kwd{end2}}} + \defunx{string-not-lessp}{\args \var{s1} \var{s2} \keys{\kwd{start1} \kwd{end1} \kwd{start2} \kwd{end2}}} + Each codepoint in each string is converted to lowercase and the + appropriate comparison of the codepoint values is done. Unicode + collation is not done. +\end{defun} + +\begin{defun}{}{string-left-trim}{\args \var{bag} \var{string}} + \defunx{string-right-trim}{\args \var{bag} \var{string}} + \defunx{string-trim}{\args \var{bag} \var{string}} + Removes any characters in \code{bag} from the left, right, or both + ends of the string \code{string}, respectively. This has potential + problems if you want to remove a surrogate character from the + string, since a single character cannot represent a surrogate. As + an extension, if \code{bag} is a string, we properly handle + surrogate characters in the \code{bag}. +\end{defun} + +\subsection{Sequences} + +Since strings are also sequences, the sequence functions can be used +on strings. We note here some issues with these functions. Most +issues are due to the fact that strings are UTF-16 strings and +characters are UTF-16 code units, not Unicode codepoints. + +\begin{defun}{}{remove-duplicates}{\args \var{sequence} + \keys{\kwd{from-end} \kwd{test} \kwd{test-not} \kwd{start} + \kwd{end} \kwd{key}}} + \defunx{delete-duplicates}{\args \var{sequence} + \keys{\kwd{from-end} \kwd{test} \kwd{test-not} \kwd{start} + \kwd{end} \kwd{key}}} + Because of surrogate pairs these functions may remove a high or low + surrogate value, leaving the string in an invalid state. Use these + functions carefully with strings. +\end{defun} + + +\subsection{Reader} + +To support Unicode characters, the reader has been extended to +recognize characters written in hexadecimal. Thus \lispchar{U+41} is +the ASCII capital letter ``A'', since 41 is the hexadecimal code for +that letter. The Unicode name of the character is also recognized, +except spaces in the name are replaced by underscores. + +Recall, however, that characters in \cmucl{} are only 16 bits long so +many Unicode characters cannot be represented. However, strings can +represent all Unicode characters. + +When symbols are read, the symbol name is converted to Unicode NFC +form before interning the symbol into the package. Hence, +\code{symbol-name (intern ``string'')} may produce a string that is +not \code{string=} to ``string''. However, after conversion to NFC +form, the strings will be identical. + +\subsection{Printer} + +When printing characters, if the character is a graphic character, the +character is printed. Thus \lispchar{U+41} is printed as +\lispchar{A}. If the character is not a graphic character, the Lisp +name (e.g., \lispchar{Tab}) is used if possible; +if there is no Lisp name, the Unicode name is used. If there is no +Unicode name, the hexadecimal char-code is +printed. For example, \lispchar{U+34e}, which is not a graphic +character, is printed as \lispchar{Combining\_Upwards\_Arrow\_Below}, +and \lispchar{U+9f} which is not a graphic character and does not have a +Unicode name, is printed as \lispchar{U+009F}. + +\subsection{Miscellaneous} + + +\subsubsection{Files} + +\cmucl{} loads external formats using the search-list +\file{ext-formats:}. The \file{aliases} file is also located using +this search-list. + +The Unicode data base is stored in compressed form in the file +\file{ext-formats:unidata.bin}. If this file is not found, Unicode +support is severely reduced; you can only use ASCII characters. + +\begin{defun}{}{open}{\args \var{filename} \amprest{} \var{options} + \keys{\kwd{direction} \kwd{element-type} \kwd{if-exists} + \kwd{if-does-not-exist} \morekeys \kwd{class} \kwd{mapped} + \kwd{input-handle} \kwd{output-handle} + \yetmorekeys \kwd{external-format} \kwd{decoding-error} + \kwd{encoding-error}}} + + The main options are covered elsewhere. Here we describe the + options specific to Unicode. The option \kwd{external-format} + specifies the external format to use for reading and writing the + file. The external format is a keyword. + + The options \kwd{decoding-error} and \kwd{encoding-error} are used + to specify how encoding and decoding errors are handled. The + default value on \nil means the external format handles errors + itself and typically replaces invalid sequences with the Unicode + replacement character. + + Otherwise, the value for \code{decoding-error} is either a + character, a symbol or a function. If a character is + specified. it is used as the replacement character for any invalid + decoding. If a symbol or a function is given, it must be a + function of three arguments: a message string to be printed, the + offending octet, and the number of octets read. If the function + returns, it should return two values: the code point to use as the + replacement character and the number of octets read. In addition, + \true{} may be specified. This indicates that a continuable error + is signaled, which, if continued, the Unicode replacement + character is used. + + For \code{encoding-error}, a character, symbol, or function can be + specified, like \code{decoding-error}, with the same meaning. The + function, however, takes two arguments: a format message string + and the incorrect codepoint. If the function returns, it should + be the replacement codepoint. +\end{defun} + +\subsubsection{Utilities} + +\begin{defun}{stream:}{set-system-external-format}{\var{terminal} \ampoptional{} \var{filenames}} + This function changes the external format used for + \var{*standard-input*}, \var{*standard-output*}, and + \var{*standard-error*} to the external format specified by + \var{terminal}. Additionally, the Unix file name encoding can be + set to the value specified by \var{filenames} if non-\nil. +\end{defun} + +\begin{defun}{extensions:}{list-all-external-formats}{} + list all of the vailable external formats. A list is returned where + each element is a list of the external format name and a list of + aliases for the format. No distinction is made between external + formats and composing external formats. +\end{defun} + +\begin{defun}{extensions:}{describe-external-format}{\var{external-format}} + Print a description of the given \var{external-format}. This may + cause the external format to be loaded (silently) if it is not + already loaded. +\end{defun} + +Since strings are UTF-16 and hence may contain surrogate pairs, some +utility functions are provided to make access easier. + +\begin{defun}{lisp:}{codepoint}{\args \var{string} \var{i} + \ampoptional{} \var{end}} + Return the codepoint value from \var{string} at position \var{i}. + If code unit at that position is a surrogate value, it is combined + with either the previous or following code unit (when possible) to + compute the codepoint. The first return value is the codepoint + itself. The second return value is \nil{} if the position is not a + surrogate pair. Otherwise, $+1$ or $-1$ is returned if the position + is the high (leading) or low (trailing) surrogate value, respectively. + + This is useful for iterating through a string in codepoint sequence. +\end{defun} + +\begin{defun}{lisp:}{surrogates-to-codepoint}{\args \var{hi} \var{lo}} + Convert the given \var{hi} and \var{lo} surrogate characters to the + corresponding codepoint value +\end{defun} + +\begin{defun}{lisp:}{surrogates}{\args \var{codepoint}} + Convert the given \var{codepoint} value to the corresponding high + and low surrogate characters. If the codepoint is less than 65536, + the second value is \nil{} since the codepoint does not need to be + represented as a surrogate pair. +\end{defun} + +\begin{defun}{stream:}{string-encode}{\args \var{string} + \var{external-format} \ampoptional{} (\var{start} 0) \var{end}} + \code{string-encode} encodes \var{string} using the format + \var{external-format}, producing an array of octets. Each octet is + converted to a character via \code{code-char} and the resulting + string is returned. + + The optional argument \var{start}, defaulting to 0, specifies the + starting index and \var{end}, defaulting to the length of the + string, is the end of the string. +\end{defun} + +\begin{defun}{stream:}{string-decode}{\args \var{string} + \var{external-format} \ampoptional{} (\var{start} 0) \var{end}} + \code{string-decode} decodes \var{string} using the format + \var{external-format} and produces a new string. Each character of + \var{string} is converted to octet (by \code{char-code}) and the + resulting array of octets is used by the external format to produce + a string. This is the inverse of \code{string-encode}. + + The optional argument \var{start}, defaulting to 0, specifies the + starting index and \var{end}, defaulting to the length of the + string, is the end of the string. + + \var{string} must consist of characters whose \code{char-code} is + less than 256. +\end{defun} + +\begin{defun}{}{string-to-octets}{\args \var{string} \keys{\kwd{start} + \kwd{end} \kwd{external-format} \kwd{buffer} \kwd{buffer-start} + \kwd{error}}} + \code{string-to-octets} converts \var{string} to a sequence of + octets according to the external format specified by + \var{external-format}. The string to be converted is bounded by + \var{start}, which defaults to 0, and \var{end}, which defaults to + the length of the string. If \var{buffer} is specified, the octets + are placed in \var{buffer}. If \var{buffer} is not specified, a new + array is allocated to hold the octets. \var{buffer-start} specifies + where in the buffer the first octet will be placed. + + An error method may also be specified by \var{error}. Any errors + encountered while converting the string to octets will be handled + according to error. If \nil{}, a replacement character is converted + to octets in place of the error. Otherwise, \var{error} should be a + symbol or function that will be called when the error occurs. The + function takes two arguments: an error string and the character + that caused the error. It should return a replacement character. + + Three values are returned: The buffer, the number of valid octets + written, and the number of characters converted. Note that the + actual number of octets written may be greater than the returned + value, These represent the partial octets of the next character to + be converted, but there was not enough room to hold the complete set + of octets. +\end{defun} + +\begin{defun}{}{octets-to-string}{\args \var{octets} \keys{\kwd{start} + \kwd{end} \kwd{external-format} \kwd{string} \kwd{s-start} + \kwd{s-end} \kwd{state}}} + \code{octets-to-string} converts the sequence of octets in + \var{octets} to a string. \var{octets} must be a + \code{(simple-array (unsigned-byte 8) (*))}. The octets to be + converted are bounded by \var{start} and \var{end}, which default to + 0 and the length of the array, respectively. The conversion is + performed according to the external format specified by + \var{external-format}. If \var{string} is specified, the octets are + converted and stored in \var{string}, starting at \var{s-start} + (defaulting to 0) and ending just before \var{s-end} (defaulting to + the end of \var{string}. \var{string} must be \code{simple-string}. + If the bounded string is not large enough to hold all of the + characters, then some octets will not be converted. If \var{string} + is not specified, a new string is created. + + The \var{state} is used as the initial state of for the external + format. This is useful when converting buffers of octets where the + buffers are not on character boundaries, and state information is + needed between buffers. + + Four values are returned: the string, the number of characters + written to the string, and the number of octets consumed to produce + the characters, and the final state of external format after + converting the octets. +\end{defun} + +\section{Writing External Formats} + +\subsection{External Formats} +Users may write their own external formats. It is probably easiest to +look at existing external formats to see how do this. + +An external format basically needs two functions: +\code{octets-to-code} to convert octets to Unicode codepoints and +\code{code-to-octets} to convert Unicode codepoints to octets. The +external format is defined using the macro +\code{stream::define-external-format}. + +% tricky +\begin{defmac}[base]{stream::}{define-external-format}{\args \var{name} + (\keys{\kwd{base} \kwd{min} \kwd{max} \kwd{size} \kwd{documentation}}) + (\amprest{} \var{slots}) + \\ + \= \ampoptional{} \var{octets-to-code} \var{code-to-octets} \var{flush-state} \var{copy-state}} + + + If \kwd{base} is not given, this defines a new external format of + the name \kwd{name}. \var{min}, \var{max}, and \var{size} are the + minimum and maximum number of octets that make up a character. + (\code{\kwd{size} n} is just a short cut for \code{\kwd{min} n + \kwd{max} n}.) The description of the external format can be + given using \kwd{documentation}. The arguments \var{octets-to-code} + and \var{code-to-octets} are not optional in this case. They + specify how to convert octets to codepoints and vice versa, + respectively. These should be backquoted forms for the body of a + function to do the conversion. See the description below for these + functions. Some good examples are the external format for + \kwd{utf-8} or \kwd{utf-16}. The \kwd{slots} argument is a list of + read-only slots, similar to defstruct. The slot names are available + as local variables inside the \var{code-to-octets} and + \var{octets-to-code} bodies. + + If \kwd{base} is given, then an external format is defined with the + name \kwd{name} that is based on a previously defined format + \kwd{base}. The \var{slots} are inherited from the \kwd{base} format + by default, although the definition may alter their values and add + new slots. See, for example, the \kwd{mac-greek} external format. + +\end{defmac} + +\begin{defmac}{}{octets-to-code}{\args \var{state} \var{input} + \var{unput} \var{error} \amprest{} \var{args}} + This defines a form to be used by an external format to convert + octets to a code point. \var{state} is a form that can be used by + the body to access the state variable of a stream. This can be used + for any reason to hold anything needed by \code{octets-to-code}. + \var{input} is a form that returns one octet from the input stream. + \var{unput} will put back \var{N} octets to the stream. \var{args} is a + list of variables that need to be defined for any symbols in the + body of the macro. + + \var{error} controls how errors are handled. If \nil, some suitable + replacement character is used. That is, any errors are silently + ignored and replaced by some replacement character. If non-\nil, + \var{error} is a symbol or function that is called to handle the + error. This function takes three arguments: a message string, the + invalid octet (or \nil), and a count of the number of octets that + have been read so far. If the function returns, it should be the + codepoint of the desired replacement character. +\end{defmac} + +\begin{defmac}{}{code-to-octets}{\args \var{code} \var{state} + \var{output} \var{error} \amprest{} \var{args}} + Defines a form to be used by the external format to convert a code + point to octets for output. \var{code} is the code point to be + converted. \var{state} is a form to access the current value of the + stream's state variable. \var{output} is a form that writes one + octet to the output stream. + + Similar to \code{octets-to-code}, \var{error} indicates how errors + should be handled. If \nil, some default replacement character is + substituted. If non-\nil, \var{error} should be a symbol or + function. This function takes two arguments: a message string and + the invalid codepoint. If the function returns, it should be the + codepoint that will be substituted for the invalid codepoint. +\end{defmac} + +\begin{defmac}{}{flush-state}{\args \var{state} + \var{output} \var{error} \amprest{} \var{args}} + Defines a form to be used by the external format to flush out + any state when an output stream is closed. Similar to + \code{code-to-octets}, but there is no code point to be output. The + \var{error} argument indicates how to handle errors. If \nil, some + default replacement character is used. Otherwise, \var{error} is a + symbol or function that will be called with a message string and + codepoint of the offending state. If the function returns, it + should be the codepoint of a suitable replacement. + + If \code{flush-state} is \false, then nothing special is needed to + flush the state to the output. + + This is called only when an output character stream is being closed. +\end{defmac} + +\begin{defmac}{}{copy-state}{\args \var{state} \amprest{} \var{args}} + Defines a form to copy any state needed by the external format. + This should probably be a deep copy so that if the original + state is modified, the copy is not. + + If not given, then nothing special is needed to copy the state + either because there is no state for the external format or that no + special copier is needed. +\end{defmac} + +\subsection{Composing External Formats} + +\begin{defmac}{stream:}{define-composing-external-format}{\args \var{name} + (\keys{\kwd{min} \kwd{max} \kwd{size} \kwd{documentation}}) \var{input} + \var{output}} + This is the same as \code{define-external-format}, except that a + composing external format is created. +\end{defmac} diff --git a/doc/cmu-user/unix.tex b/doc/cmu-user/unix.tex new file mode 100644 index 0000000000..fccd0c9ad1 --- /dev/null +++ b/doc/cmu-user/unix.tex @@ -0,0 +1,508 @@ +\chapter{UNIX Interface} +\label{unix-interface} + +\credits{by Robert MacLachlan, Skef Wholey, Bill Chiles and William Lott} + + +\cmucl{} attempts to make the full power of the underlying +environment available to the Lisp programmer. This is done using +combination of hand-coded interfaces and foreign function calls to C +libraries. Although the techniques differ, the style of interface is +similar. This chapter provides an overview of the facilities available +and general rules for using them, as well as describing specific +features in detail. It is assumed that the reader has a working +familiarity with Unix and X11, as well as access to the standard +system documentation. + + +\section{Reading the Command Line} + +The shell parses the command line with which Lisp is invoked, and +passes a data structure containing the parsed information to Lisp. +This information is then extracted from that data structure and put +into a set of Lisp data structures. + +\begin{defvar}{extensions:}{command-line-strings} + \defvarx[extensions:]{command-line-utility-name} + \defvarx[extensions:]{command-line-words} + \defvarx[extensions:]{command-line-switches} + + The value of \code{*command-line-words*} is a list of strings that + make up the command line, one word per string. The first word on + the command line, i.e. the name of the program invoked (usually + \code{lisp}) is stored in \code{*command-line-utility-name*}. The + value of \code{*command-line-switches*} is a list of + \code{command-line-switch} structures, with a structure for each + word on the command line starting with a hyphen. All the command + line words between the program name and the first switch are stored + in \code{*command-line-words*}. +\end{defvar} + +The following functions may be used to examine \code{command-line-switch} +structures. +\begin{defun}{extensions:}{cmd-switch-name}{\args{\var{switch}}} + + Returns the name of the switch, less the preceding hyphen and + trailing equal sign (if any). +\end{defun} +\begin{defun}{extensions:}{cmd-switch-value}{\args{\var{switch}}} + + Returns the value designated using an embedded equal sign, if any. + If the switch has no equal sign, then this is null. +\end{defun} +\begin{defun}{extensions:}{cmd-switch-words}{\args{\var{switch}}} + + Returns a list of the words between this switch and the next switch + or the end of the command line. +\end{defun} +\begin{defun}{extensions:}{cmd-switch-arg}{\args{\var{switch}}} + + Returns the first non-null value from \code{cmd-switch-value}, the + first element in \code{cmd-switch-words}, or the first word in + \var{command-line-words}. +\end{defun} + +\begin{defun}{extensions:}{get-command-line-switch}{\args{\var{sname}}} + + This function takes the name of a switch as a string and returns the + value of the switch given on the command line. If no value was + specified, then any following words are returned. If there are no + following words, then \true{} is returned. If the switch was not + specified, then \false{} is returned. +\end{defun} + +\begin{defmac}{extensions:}{defswitch}{% + \args{\var{name} \ampoptional{} \var{function}}} + + This macro causes \var{function} to be called when the switch + \var{name} appears in the command line. Name is a simple-string + that does not begin with a hyphen (unless the switch name really + does begin with one.) + + If \var{function} is not supplied, then the switch is parsed into + \var{command-line-switches}, but otherwise ignored. This suppresses + the undefined switch warning which would otherwise take place. The + warning can also be globally suppressed by + \var{complain-about-illegal-switches}. +\end{defmac} + + +\section{Useful Variables} + +\begin{defvar}{system:}{stdin} + \defvarx[system:]{stdout} \defvarx[system:]{stderr} + + Streams connected to the standard input, output and error file + descriptors. +\end{defvar} + +\begin{defvar}{system:}{tty} + + A stream connected to \file{/dev/tty}. +\end{defvar} + +\begin{defvar}{extensions:}{environment-list} + The environment variables inherited by the current process, as a + keyword-indexed alist. For example, to access the DISPLAY + environment variable, you could use + +\begin{lisp} + (cdr (assoc :display ext:*environment-list*)) +\end{lisp} + + Note that the case of the variable name is preserved when converting + to a keyword. Therefore, you need to specify the keyword properly for + variable names containing lower-case letters, +\end{defvar} + + +\section{Lisp Equivalents for C Routines} + +The UNIX documentation describes the system interface in terms of C +procedure headers. The corresponding Lisp function will have a somewhat +different interface, since Lisp argument passing conventions and +datatypes are different. + +The main difference in the argument passing conventions is that Lisp does not +support passing values by reference. In Lisp, all argument and results are +passed by value. Interface functions take some fixed number of arguments and +return some fixed number of values. A given ``parameter'' in the C +specification will appear as an argument, return value, or both, depending on +whether it is an In parameter, Out parameter, or In/Out parameter. The basic +transformation one makes to come up with the Lisp equivalent of a C routine is +to remove the Out parameters from the call, and treat them as extra return +values. In/Out parameters appear both as arguments and return values. Since +Out and In/Out parameters are only conventions in C, you must determine the +usage from the documentation. + +Thus, the C routine declared as + +\begin{example} +kern_return_t lookup(servport, portsname, portsid) + port servport; + char *portsname; + int *portsid; /* out */ + { + ... + *portsid = <expression to compute portsid field> + return(KERN_SUCCESS); + } +\end{example} + +has as its Lisp equivalent something like + +\begin{lisp} +(defun lookup (ServPort PortsName) + ... + (values + success + <expression to compute portsid field>)) +\end{lisp} + +If there are multiple out or in-out arguments, then there are multiple +additional returns values. + +Fortunately, \cmucl{} programmers rarely have to worry about the +nuances of this translation process, since the names of the arguments and +return values are documented in a way so that the \code{describe} function +(and the \hemlock{} \code{Describe Function Call} command, invoked with +\b{C-M-Shift-A}) will list this information. Since the names of arguments +and return values are usually descriptive, the information that +\code{describe} prints is usually all one needs to write a +call. Most programmers use this on-line documentation nearly +all of the time, and thereby avoid the need to handle bulky +manuals and perform the translation from barbarous tongues. + + +\section{Type Translations} +\cindex{aliens} +\cpsubindex{types}{alien} +\cpsubindex{types}{foreign language} + +Lisp data types have very different representations from those used by +conventional languages such as C. Since the system interfaces are +designed for conventional languages, Lisp must translate objects to and +from the Lisp representations. Many simple objects have a direct +translation: integers, characters, strings and floating point numbers +are translated to the corresponding Lisp object. A number of types, +however, are implemented differently in Lisp for reasons of clarity and +efficiency. + +Instances of enumerated types are expressed as keywords in Lisp. +Records, arrays, and pointer types are implemented with the \alien{} +facility (\pxlref{aliens}). Access functions are defined +for these types which convert fields of records, elements of arrays, +or data referenced by pointers into Lisp objects (possibly another +object to be referenced with another access function). + +One should dispose of \alien{} objects created by constructor +functions or returned from remote procedure calls when they are no +longer of any use, freeing the virtual memory associated with that +object. Since \alien{}s contain pointers to non-Lisp data, the +garbage collector cannot do this itself. If the memory +was obtained from \funref{make-alien} or from a foreign function call +to a routine that used \code{malloc}, then \funref{free-alien} should +be used. + + +\section{System Area Pointers} +\label{system-area-pointers} + +\cindex{pointers}\cpsubindex{malloc}{C function}\cpsubindex{free}{C function} +Note that in some cases an address is represented by a Lisp integer, and in +other cases it is represented by a real pointer. Pointers are usually used +when an object in the current address space is being referred to. The MACH +virtual memory manipulation calls must use integers, since in principle the +address could be in any process, and Lisp cannot abide random pointers. +Because these types are represented differently in Lisp, one must explicitly +coerce between these representations. + +System Area Pointers (SAPs) provide a mechanism that bypasses the +\alien{} type system and accesses virtual memory directly. A SAP is a +raw byte pointer into the \code{lisp} process address space. SAPs are +represented with a pointer descriptor, so SAP creation can cause +consing. However, the compiler uses a non-descriptor representation +for SAPs when possible, so the consing overhead is generally minimal. +\xlref{non-descriptor}. + +\begin{defun}{system:}{sap-int}{\args{\var{sap}}} + \defunx[system:]{int-sap}{\args{\var{int}}} + + The function \code{sap-int} is used to generate an integer + corresponding to the system area pointer, suitable for passing to + the kernel interfaces (which want all addresses specified as + integers). The function \code{int-sap} is used to do the opposite + conversion. The integer representation of a SAP is the byte offset + of the SAP from the start of the address space. +\end{defun} + +\begin{defun}{system:}{sap+}{\args{\var{sap} \var{offset}}} + + This function adds a byte \var{offset} to \var{sap}, returning a new + SAP. +\end{defun} + +\begin{defun}{system:}{sap-ref-8}{\args{\var{sap} \var{offset}}} + \defunx[system:]{sap-ref-16}{\args{\var{sap} \var{offset}}} + \defunx[system:]{sap-ref-32}{\args{\var{sap} \var{offset}}} + + These functions return the 8, 16 or 32 bit unsigned integer at + \var{offset} from \var{sap}. The \var{offset} is always a byte + offset, regardless of the number of bits accessed. \code{setf} may + be used with the these functions to deposit values into virtual + memory. +\end{defun} + +\begin{defun}{system:}{signed-sap-ref-8}{\args{\var{sap} \var{offset}}} + \defunx[system:]{signed-sap-ref-16}{\args{\var{sap} \var{offset}}} + \defunx[system:]{signed-sap-ref-32}{\args{\var{sap} \var{offset}}} + + These functions are the same as the above unsigned operations, + except that they sign-extend, returning a negative number if the + high bit is set. +\end{defun} + + +\section{Unix System Calls} + +You probably won't have much cause to use them, but all the Unix system +calls are available. The Unix system call functions are in the +\code{Unix} package. The name of the interface for a particular system +call is the name of the system call prepended with \code{unix-}. The +system usually defines the associated constants without any prefix name. +To find out how to use a particular system call, try using +\code{describe} on it. If that is unhelpful, look at the source in +\file{unix.lisp} or consult your system maintainer. + +The Unix system calls indicate an error by returning \false{} as the +first value and the Unix error number as the second value. If the call +succeeds, then the first value will always be non-\nil, often \code{t}. + +For example, to use the \code{chdir} syscall: + +\begin{lisp} +(multiple-value-bind (success errno) + (unix:unix-chdir "/tmp") + (unless success + (error "Can't change working directory: ~a" + (unix:get-unix-error-msg errno)))) +\end{lisp} + +\begin{defun}{Unix:}{get-unix-error-msg}{\args{\var{error}}} + + This function returns a string describing the Unix error number + \var{error} (this is similar to the Unix function \code{perror}). +\end{defun} + + +\section{File Descriptor Streams} +\label{sec:fds} + +Many of the UNIX system calls return file descriptors. Instead of using other +UNIX system calls to perform I/O on them, you can create a stream around them. +For this purpose, fd-streams exist. See also \funref{read-n-bytes}. + +\begin{defun}{system:}{make-fd-stream}{% + \args{\var{descriptor}} \keys{\kwd{input} \kwd{output} + \kwd{element-type}} \morekeys{\kwd{buffering} \kwd{name} + \kwd{file} \kwd{original}} \yetmorekeys{\kwd{delete-original} + \kwd{auto-close}} \yetmorekeys{\kwd{timeout} \kwd{pathname}}} + + This function creates a file descriptor stream using + \var{descriptor}. If \kwd{input} is non-\nil, input operations are + allowed. If \kwd{output} is non-\nil, output operations are + allowed. The default is input only. These keywords are defined: + \begin{Lentry} + \item[\kwd{element-type}] is the type of the unit of transaction for + the stream, which defaults to \code{string-char}. See the \clisp{} + description of \code{open} for valid values. + + \item[\kwd{buffering}] is the kind of output buffering desired for + the stream. Legal values are \kwd{none} for no buffering, + \kwd{line} for buffering up to each newline, and \kwd{full} for + full buffering. + + \item[\kwd{name}] is a simple-string name to use for descriptive + purposes when the system prints an fd-stream. When printing + fd-streams, the system prepends the streams name with \code{Stream + for }. If \var{name} is unspecified, it defaults to a string + containing \var{file} or \var{descriptor}, in order of preference. + + \item[\kwd{file}, \kwd{original}] \var{file} specifies the defaulted + namestring of the associated file when creating a file stream + (must be a \code{simple-string}). \var{original} is the + \code{simple-string} name of a backup file containing the original + contents of \var{file} while writing \var{file}. + + When you abort the stream by passing \true{} to \code{close} as + the second argument, if you supplied both \var{file} and + \var{original}, \code{close} will rename the \var{original} name + to the \var{file} name. When you \code{close} the stream + normally, if you supplied \var{original}, and + \var{delete-original} is non-\nil, \code{close} deletes + \var{original}. If \var{auto-close} is true (the default), then + \var{descriptor} will be closed when the stream is garbage + collected. + + \item[\kwd{pathname}]: The original pathname passed to open and + returned by \code{pathname}; not defaulted or translated. + + \item[\kwd{timeout}] if non-null, then \var{timeout} is an integer + number of seconds after which an input wait should time out. If a + read does time out, then the \code{system:io-timeout} condition is + signalled. + \end{Lentry} +\end{defun} + +\begin{defun}{system:}{fd-stream-p}{\args{\var{object}}} + + This function returns \true{} if \var{object} is an fd-stream, and + \nil{} if not. Obsolete: use the portable \code{(typep x + 'file-stream)}. +\end{defun} + +\begin{defun}{system:}{fd-stream-fd}{\args{\var{stream}}} + + This returns the file descriptor associated with \var{stream}. +\end{defun} + + +\section{Unix Signals} +\cindex{unix signals} \cindex{signals} + +\cmucl{} allows access to all the Unix signals that can be generated +under Unix. It should be noted that if this capability is abused, it is +possible to completely destroy the running Lisp. The following macros and +functions allow access to the Unix interrupt system. The signal names as +specified in section 2 of the {\em Unix Programmer's Manual} are exported +from the Unix package. + +\subsection{Changing Signal Handlers} +\label{signal-handlers} + +\begin{defmac}{system:}{with-enabled-interrupts}{ + \args{\var{specs} \amprest{} \var{body}}} + + This macro should be called with a list of signal specifications, + \var{specs}. Each element of \var{specs} should be a list of + two\hide{ or three} elements: the first should be the Unix signal + for which a handler should be established, the second should be a + function to be called when the signal is received\hide{, and the + third should be an optional character used to generate the signal + from the keyboard. This last item is only useful for the SIGINT, + SIGQUIT, and SIGTSTP signals.} One or more signal handlers can be + established in this way. \code{with-enabled-interrupts} establishes + the correct signal handlers and then executes the forms in + \var{body}. The forms are executed in an unwind-protect so that the + state of the signal handlers will be restored to what it was before + the \code{with-enabled-interrupts} was entered. A signal handler + function specified as NIL will set the Unix signal handler to the + default which is normally either to ignore the signal or to cause a + core dump depending on the particular signal. +\end{defmac} + +\begin{defmac}{system:}{without-interrupts}{\args{\amprest{} \var{body}}} + + It is sometimes necessary to execute a piece a code that can not be + interrupted. This macro the forms in \var{body} with interrupts + disabled. Note that the Unix interrupts are not actually disabled, + rather they are queued until after \var{body} has finished + executing. +\end{defmac} + +\begin{defmac}{system:}{with-interrupts}{\args{\amprest{} \var{body}}} + + When executing an interrupt handler, the system disables interrupts, + as if the handler was wrapped in in a \code{without-interrupts}. + The macro \code{with-interrupts} can be used to enable interrupts + while the forms in \var{body} are evaluated. This is useful if + \var{body} is going to enter a break loop or do some long + computation that might need to be interrupted. +\end{defmac} + +\begin{defmac}{system:}{without-hemlock}{\args{\amprest{} \var{body}}} + + For some interrupts, such as SIGTSTP (suspend the Lisp process and + return to the Unix shell) it is necessary to leave Hemlock and then + return to it. This macro executes the forms in \var{body} after + exiting Hemlock. When \var{body} has been executed, control is + returned to Hemlock. +\end{defmac} + +\begin{defun}{system:}{enable-interrupt}{% + \args{\var{signal} \var{function}\hide{ \ampoptional{} + \var{character}}}} + + This function establishes \var{function} as the handler for + \var{signal}. + \hide{The optional \var{character} can be specified + for the SIGINT, SIGQUIT, and SIGTSTP signals and causes that + character to generate the appropriate signal from the keyboard.} + Unless you want to establish a global signal handler, you should use + the macro \code{with-enabled-interrupts} to temporarily establish a + signal handler. \hide{Without \var{character},} + \code{enable-interrupt} returns the old function associated with the + signal. \hide{When \var{character} is specified for SIGINT, + SIGQUIT, or SIGTSTP, it returns the old character code.} +\end{defun} + +\begin{defun}{system:}{ignore-interrupt}{\args{\var{signal}}} + + Ignore-interrupt sets the Unix signal mechanism to ignore + \var{signal} which means that the Lisp process will never see the + signal. Ignore-interrupt returns the old function associated with + the signal or \false{} if none is currently defined. +\end{defun} + +\begin{defun}{system:}{default-interrupt}{\args{\var{signal}}} + + Default-interrupt can be used to tell the Unix signal mechanism to + perform the default action for \var{signal}. For details on what + the default action for a signal is, see section 2 of the {\em Unix + Programmer's Manual}. In general, it is likely to ignore the + signal or to cause a core dump. +\end{defun} + + +\subsection{Examples of Signal Handlers} + +The following code is the signal handler used by the Lisp system for the +SIGINT signal. + +\begin{lisp} +(defun ih-sigint (signal code scp) + (declare (ignore signal code scp)) + (without-hemlock + (with-interrupts + (break "Software Interrupt" t)))) +\end{lisp} + +The \code{without-hemlock} form is used to make sure that Hemlock is exited before +a break loop is entered. The \code{with-interrupts} form is used to enable +interrupts because the user may want to generate an interrupt while in the +break loop. Finally, break is called to enter a break loop, so the user +can look at the current state of the computation. If the user proceeds +from the break loop, the computation will be restarted from where it was +interrupted. + +The following function is the Lisp signal handler for the SIGTSTP signal +which suspends a process and returns to the Unix shell. + +\begin{lisp} +(defun ih-sigtstp (signal code scp) + (declare (ignore signal code scp)) + (without-hemlock + (Unix:unix-kill (Unix:unix-getpid) Unix:sigstop))) +\end{lisp} + +Lisp uses this interrupt handler to catch the SIGTSTP signal because it is +necessary to get out of Hemlock in a clean way before returning to the shell. + +To set up these interrupt handlers, the following is recommended: + +\begin{lisp} +(with-enabled-interrupts ((Unix:SIGINT #'ih-sigint) + (Unix:SIGTSTP #'ih-sigtstp)) + <user code to execute with the above signal handlers enabled.> +) +\end{lisp} diff --git a/doc/internals-notes/array-ubsan b/doc/internals-notes/array-ubsan new file mode 100644 index 0000000000..49d6da9268 --- /dev/null +++ b/doc/internals-notes/array-ubsan @@ -0,0 +1,38 @@ + +Detection of access to unitialized arrays will be performed in one +of two ways, depending on whether the vector is specialized on T or +or a "bits" type. T vectors will use no-tls-marker as a poison value. +Char/numeric will contain one extra bit per element. +The reason for not using unbound-marker on simple-vector is that +it simplifies uses of simple-vectors that have language-level semantics +for UNBOUND-MARKER, including at least the CLOS implementation +and hash-table key/value pairs. A distinct poison value avoids having +to revise a lot of code that needs to read the unbound-marker without +trapping at the vop level. + +Without array-ubsan it should nonetheless be possible to obtain a similar +effect of array-ubsan for simple-vector. The setter / getter remain the same, +but there is no tracking of the origin of the array. +Origin tracking provides an indicator of which function to "blame" +for creating the array without initializing it, such as: + +debugger invoked on a SB-KERNEL:UNINITIALIZED-ELEMENT-ERROR @539A5AF1 in thread +#<THREAD "main thread" RUNNING {1001A78183}>: + Element 0 of array + #<(SIMPLE-VECTOR 4) {1004FFA01F}> + was not assigned a value. +Origin=#<code id=8F10 [2] PROCESS-TYPEDECLS, MAKE-PACKAGE-LOCK-LEXENV {53993EBF}> + +Additionally, it should be possible to create uninitialized dynamic-extent +simple-vectors on non-precise gencgc platforms. +This is related to array-ubsan in as much as array-ubsan provides a good +indication as to where something might be going wrong before causing +application corruption. To do this, you want to compile your code in 0 safety +with array-ubsan, which will initialize dynamic-extent arrays with the trap +value. If all your tests pass (and assuming you have good coverage +in your tests), then you can remove array-ubsan, and the dynamic-extent +simple-vectors will (pending further changes) be uninitialized. +This affords a measurable speedup. In a test of creating 1000-element arrays +(repeated sufficiently many times to be able to eliminate measurement error), +it was observed that a vector takes 29 CPU cycles to create, vs 597 CPU cycles +to zero-initialize it. diff --git a/doc/internals-notes/closure b/doc/internals-notes/closure new file mode 100644 index 0000000000..d1444c469e --- /dev/null +++ b/doc/internals-notes/closure @@ -0,0 +1,40 @@ +Closure without CODE slot (#-metaspace) +--------------------------------------- +nvalues = len - 1 + +1 value: 1 value + name: +word 0: header [len=2] word 0: header [len=2] +word 1: addr word 1: addr +word 2: value word 2: value = closure-index-ref 0 +word 3: padding word 3: name = closure-index-ref 1 + +2 values: 2 values + name: +word 0: header: [len=3] word 0: header [len=4] +word 1: addr word 1: addr +word 2: value 0 word 2: value 0 = closure-index-ref 0 +word 3: value 1 word 3: value 1 = closure-index-ref 1 + word 4: pad = closure-index-ref 2 + word 5: name = closure-index-ref 3 + +Closure with CODE slot (#+metaspace) +------------------------------------ + +nvalues = len - 2 + +1 value: +word 0: header [len=3] word 0: header [len=4] +word 1: addr word 1: addr +word 2: code word 2: code +word 3: value word 3: value = closure-index-ref 0 + word 4: pad = closure-index-ref 1 + word 5: name = closure-index-ref 2 + +2 valuess: +word 0: header [len=4] word 0: header [len=4] +word 1: addr word 1: tramp +word 2: code word 2: code +word 3: value 0 word 3: value 0 = closure-index-ref 0 +word 4: value 1 word 4: value 1 = closure-index-ref 1 +word 5: pad word 5: name = closure-index-ref 2 + +In all cases, NAME is in (closure-index-ref c nvalues) diff --git a/doc/internals-notes/eden-pages b/doc/internals-notes/eden-pages new file mode 100644 index 0000000000..70e595a601 --- /dev/null +++ b/doc/internals-notes/eden-pages @@ -0,0 +1,73 @@ +Design for new page types in support of asynchronous +determination of ambiguous roots. + +Background: concurrency is only a problem pertinent +to generation 0 with open per-thread allocation regions. +Generations 1 and up are manipulated by the GC and will not have +open regions when threads are initially stopped. +If only generation 0 is to be collected, then each +thread can stack its own stack. +If generation 1 or higher is to be collected, +the GC'ing thread will have to scan all stacks. + +PAGE_TYPE_EDEN_CONS: +* Pages are initially filled with 0xff. +* All objects are conses. +* Examining an arbitrary word will, with 100% certainty, + determine that the word starts an object or does not. + (Any <-1,-1> wordpair can not possibly be a cons) +* Differs from CONS in that ordinary CONS is not prezeroed. + +PAGE_TYPE_EDEN_BOXED: +* Pages are initially zero-filled. +* All objects are headered. +* No object contains a raw slot. +* Examining an arbitrary word will, with 100% certainty, + determine that the word starts an object or does not. + (Any word containing 0 can not possibly start an object.) +* Acceptable primitive types: + - instance with no raw slots + - funinstance without embedded trampoline + - ratio, (complex rational) + - closure, value-cell, weak-pointer + - simple-array, simple-vector-nil, simple-vector + - complex-{base-string,character-string,bit-vector,vector,array} +* Lockfree list nodes should be allowed on eden boxed pages, + but we need more flag bits: one bit which says whether it can + be initially allocated to BOXED (it won't contain random bits) + and one which says whether it may be transported to BOXED. + Generations > 1 do not use scavenge methods on BOXED pages, + so it would not be allowed to have a list node there. +* Differs from BOXED in that ordinary BOXED may not contain + any object that demands a type-specific scavenge method. + +PAGE_TYPE_EDEN_MIXED: +* Pages need not be zero-filled (in theory). +* All objects are headered. +* Objects potentially contain one or more raw slots. +* A bitmap of object start addresses is maintained by the allocator. +* Acceptable primitive types: + - bignum, double-float, (complex float) + - symbol, mixed instance and/or instances made by %MAKE-INSTANCE + - funinstance with embedded trampoline + - sap, fdefn, simd-pack{-256} + - simple-unboxed-vector +* Differs from MIXED in that normal MIXED has no bitmap and will + usually not contain instances that lack raw slots. + +Similarities: +* Type-specific scavenge methods are required for EDEN pages + except for CONS. + In the case of BOXED, this is due to presence of weak pointers, + weak vectors, and address-based and/or weak KV storage vectors. + For MIXED, this is required to avoid seeing raw bits. +* Pinned objects can promote beyond gen0, but the page type remains + as EDEN_type because it would take more computation to decide whether + to turn a page into something different. + Additionally it might not be possible to change because: + - EDEN_BOXED can hold the union of ordinary BOXED and MIXED + - EDEN_MIXED can hold the union of ordinary MIXED and UNBOXED + +Caution: this writeup only applies to x86-64. +Ensuring visibility of writes for relaxed-memory-order machines +is an issue. Something can possibly be done involving sys_membarrier. diff --git a/doc/internals-notes/mach-exception-handler-notes b/doc/internals-notes/mach-exception-handler-notes deleted file mode 100644 index c2d69f533c..0000000000 --- a/doc/internals-notes/mach-exception-handler-notes +++ /dev/null @@ -1,254 +0,0 @@ - -MACH EXCEPTION HANDLER NOTES -Cyrus Harmon, December 2007 - -The goal of this work is to use make SBCL use mach exception handlers -instead of so-called BSD-style signal handlers on Mac OS X. Cyrus -Harmon and Alastair Bridgewater have been working on this. - -Mac OS X has a mach-based kernel that has its own API for things like -threads and exception handling. Both mach exception handlers and -BSD-style signal handlers are available for use by application -programmers, but the signal handlers, which are implemented as a -compatibility layer on top of mach exceptions, have some problems. The -main problem for SBCL is that when using BSD-style signal handlers to -respond to SIGSEGV for access to protected memory areas, we cannot use -gdb to debug the process. This is problematic for SBCL which sets up, -and reads and writes to, protected memory areas early and -often. Additionally, threaded builds are seeing a number of problems -with SIGILLs being thrown at odd times. It appears that these are -coming from with the OS signal handling libraries directly, so -debugging these is rather tricky, especially in the absence of a -debugger. Thirdly, the protected memory accesses can, under certain -settings, trigger the Mac OS X CrashReporter, either logging -voluminous messages to a log file or, worse yet, triggering a -user-intervention dialog. - -To address these three problems, we propose replacing the BSD-style -signal handling facility with a mach exception handling -facility. Preliminary tests with mach exceptions show that GDB is much -happier when using mach exceptions to respond to access to protected -memory. While mach exceptions probably won't directly fix the -threading problems, they remove a potentially problematic section of -code, the portion of the Mac OS X system library that deals with -BSD-style signal handling emulation and delivery of those signals to -multiple threads. Even if using mach exceptions in and of itself -doesn't immediately fix the problem, it should me much easier to -diagnose using a debugger. Finally, the CrashReporter problem appears -to go away as well, as this arises from an unfortunate placement of -the CrashReporting facility in the OS between the mach exception -handling and the BSD-style signal emulation. By catching the mach -exceptions ourselves, we avoid this problem. - -* Mach exception handling details and example - -Mach exceptions work by creating a thread that listens for mach -exceptions. The (slightly under-documented) OS function mach_msg_server -is passed the exc_server function and exc_server in turn calls our -catch_exception_raise function when an appropriate exception is -triggered. (Note that catch_exception_raise is called by exc_server -directly by that name. I have no idea how to provide multiple such -functions or to call this function by another name, but we should be -OK with a a single exception handling function.) - -To set this up we perform the following steps: - -1. allocate a mach port for our exceptions. - -2. give the process the right to send and receive exceptions on this - port. - -3. create a new thread which calls mach_msg_server, providing - exc_server as an argument. exc_server in turn calls our - catch_exception_raise when an exception is raised. - -4. finally, each thread for which we would like exceptions to be - handled must register itself with the exception port by calling - thread_set_exception_ports with the appropriate port and exception - mask. Actually, it's a bit more involved than this in order to - support multiple threads. Please document this fully. - -* USE_MACH_EXCEPTION_HANDLER - -The conditional compilation directive USE_MACH_EXCEPTION_HANDLER is a -flag to use mach exception handling. We should continue to support the -BSD-style signal handling until long after we are convinced that the -mach exception handling version works better. - -* Establishing the mach exception handler - -** x86-darwin-os.c - -A new function, darwin_init, is added which creates the mach exception -handling thread and establishes the exception port. Currently the -"main" thread sets its exception port here, but when we go to a -multithreaded SBCL, we will need to do similarly for new threads in -arch_os_thread_init. Note that even "non-threaded" SBCL builds will -have two threads, one lisp thread and a mach exception handling -thread. - -catch_exception_raise listens for EXC_BAD_ACCESS and -EXC_BAD_INSTRUCTION (and EXC_BREAKPOINT if we were to use INT3 traps -again instead of the SIGILL traps we've set up as a workaround to the -broken INT3 traps). Analogous to the signal handling context, mach -exceptions allow use to get the thread and exception state of the -triggering thread. We build a "fake" signal context, similar to what -would be seen if a SIGSEGV/SIGILL were triggered and pass this on to -SBCL's memory_fault_handler (for SIGSEGV) or sigill_handler (for -SIGILL). when the handlers return, we set the values of the -thread_state using the values from the fake context, allowing the -"signal handler" to modify the state of the calling thread. - -** x86-arch.c - -sigill_handler and sigtrap_handler are no longer installed as signal -handlers using undoably_install_low_level_interrupt_handler. Instead -sigill_handler is called directly by the mach exception handling -catch_exception_raise. This means that sigill_handler can no longer be -static void and it is changed to just void. - -** bsd-os.c - -memory_fault_error no longer installed using -undoably_install_low_level_interrupt_handler and changed to not be -static. darwin_init called. - -* Handling exceptions - -** interrupt.c - -The code for general purpose error handling, which is generally done -by a trap instruction followed by an error opcode (although on Mac OS, -we use UD2A instead of INT3 as INT3 trapping is unreliable and the -sigill_handler in turn calls the sigtrap_handler). sigtrap_handler in -turn calls functions like interrupt_internal_error that are found in -interrupt.c. - -Using BSD-style signal handling, interrupt_internal_error calls into -lisp via the lisp function INTERNAL-ERROR via funcall2 (the two -argument form of funcall). Since we are executing the exception -handler on the exception handling thread and we don't really want to -be executing lisp code on the exception handlers thread, we want to -return to the lisp thread as quickly as possible. With BSD-style -signal handling, the signal handlers themselves call into lisp using -funcallN. We can't do this as then we would be attempting to execute -lisp code on the exception handling thread. This would be a bad thing -in a multi-threaded lisp. Therefore, we borrow a trick from the -interrupt handling code and hack the stack of the offending thread -such that when the mach exception handling code returns, and returns -control back to the offending thread, it first calls a lisp function, -then (unless otherwise directed) returns control to the lisp -thread. This allows us to run our lisp (or other) code on the -offending thread's stack, but before the offending thread resumes -where it left off. See the arrange_return_to_lisp_function for details -on how this is done. - -arrange_return_to_lisp_function was modified to take an additional -parameter specifying the number of additional arguments, and -additional varargs, which are then placed on the stack in the -call_into_lisp_tramp in x86-assem.S. - -The problem with this is that both the signal handling/mach exception -handling code, on the one hand, and the lisp code expect access to the -"context" for accessing the state of the thread at the time that the -signal/exception was raised. This means that the old strategy was: - -offending thread - (operating system establishes signal context) - signal handler - lisp code - signal handler - (operating system restores state from signal context) -offending thread - -and both the signal handler and the lisp code have the chance to -examine and modify the signal context. Now the situation looks like -this: - -offending thread - (operating system establishes thread_state) - mach_exception_handler - signal handler (which may arrange return to a lisp function) - mach_exception_handler - (operating system restores from thread_state) - (optionally, a lisp function is called here) -offending thread - -So we need to figure out how to provide the lisp function with -information about the context of the offending thread and allow the -lisp code to alter this state and to restore that state prior to -resuming control to the offending thread. - -There are, presumably, additional problems with exception masking and -when threads are allowed to interrupt other threads or otherwise catch -signals/exceptions, but we can defer those for the moment. - -* Providing a "context" for lisp functions called on returning from a -mach exception handler - -Given the flow describe above, we need to expand the following step: - - (optionally, a lisp function is called here) - -now it needs to look something like: - -0. offending thread triggers a mach exception - -1. (operating system establishes thread_state) - -2. enter mach_exception_handler - - 2a. signal handler (which may arrange return to a lisp function - - 2b. frob the offending threads stack, allocating a context on the - stack (if appropriate, or always?) - -3. exit mach_exception_handler - -4. (operating system restores from thread_state) - -6. with the context on the stack, transfer control to the lisp - function - -7. restore the thread state from the context which either returns - control to original location in the offending thread or to wherever - the error-handling code has modified the context to point to - - -* x86-darwin-os.c (again) - -** call_c_function_in_context and signal_emulation_wrapper - -We arrange for a function to be a called by the offending the thread -when the mach exception handler returns. Essentially we have our own -BSD-style signal emulation library that calls memory_fault_handler, -sigtrap_handler and sigill_handler, as appropriate. It does this by -calling a function call_c_function_in_context which sets up the EIP of -the thread context to call the specified C function, which the -specified arguments. In this case, signal_emulation_wrapper which -takes as arguments a thread_state, which is a copy of the thread state -as it existed upon entry into catch_exception_raise, and an emulated -signal and siginfo and the signal handling function that -signal_emulation_wrapper is to call. - -signal_emulation_wrapper creates a BSD-style signal context and -populates it from the values in the passed in thread_state. It calls -the specified signal_handler, and then sets the values in the -thread_state from the context and loads the address of the thread -state to restore into eax and then traps with a special trap that the -catch_exception_raise looks for, which then extracts the thread state -from the trap exception's thread_state.eax. - -[MORE DETAILS TO FOLLOW] - - -===== BUGS ===== - -MEH1: on threaded macos builds, init.test.sh fails with a - memory-fault-error (NOTE: this is a threaded macos issue, not a - mach exception handler bug). - -MEH2: timer.impure lisp fails on mach-exception-handler builds - -MEH3: threads.impure lisp fails on mach-exception-handler builds - diff --git a/doc/internals-notes/make-thread-bench b/doc/internals-notes/make-thread-bench new file mode 100644 index 0000000000..3620050c93 --- /dev/null +++ b/doc/internals-notes/make-thread-bench @@ -0,0 +1,143 @@ +(defglobal *counter* 0) +(declaim (fixnum *counter*)) + +;; how many threads to make, not all at once, of course +(defparameter howmany-threads 20000) + +(defun thread-lambda () + (atomic-incf *counter*)) + +(defun test1 (&optional (n howmany-threads)) + (setq *counter* 0) + (dotimes (i n) + (sb-thread:join-thread (sb-thread:make-thread #'thread-lambda))) + (assert (= *counter* n))) + +(defun test2 (&optional (n howmany-threads)) + (setq *counter* 0) + (let (prev-thread) + (dotimes (i n) + ;; while starting the new thread, join the previously made. + (let ((new-thread (sb-thread:make-thread #'thread-lambda))) + (when prev-thread + (sb-thread:join-thread prev-thread)) + (setq prev-thread new-thread))) + (sb-thread:join-thread prev-thread)) + (assert (= *counter* n))) + +(defun test3 (&optional (n howmany-threads)) + (setq *counter* 0) + ;; try making 10 at a time and waiting for those 10 before making more + (dotimes (i (/ n 10)) + (let ((threads)) + (dotimes (i 10) + (push (sb-thread:make-thread #'thread-lambda) threads)) + (dolist (thread threads) + (sb-thread:join-thread thread)))) + (assert (= *counter* n))) + +Without :pauseless-threadstart +------------------------------- + +$ perf stat ... --eval '(test1)' --quit + 6,435.72 msec task-clock:u # 1.103 CPUs utilized + 0 context-switches:u # 0.000 K/sec + 0 cpu-migrations:u # 0.000 K/sec + 219,735 page-faults:u # 0.034 M/sec + 1,484,016,696 cycles:u # 0.231 GHz + 17,008,247,359 stalled-cycles-frontend:u # 1146.10% frontend cycles idle + 525,232,002 instructions:u # 0.35 insn per cycle + # 32.38 stalled cycles per insn + 145,098,224 branches:u # 22.546 M/sec + 4,045,481 branch-misses:u # 2.79% of all branches + + 5.834005191 seconds time elapsed + 0.684522000 seconds user + 6.391622000 seconds sys + +$ perf stat ... --eval '(test2)' --quit + 6,383.26 msec task-clock:u # 1.182 CPUs utilized + 0 context-switches:u # 0.000 K/sec + 0 cpu-migrations:u # 0.000 K/sec + 220,625 page-faults:u # 0.035 M/sec + 1,435,852,231 cycles:u # 0.225 GHz + 16,839,228,290 stalled-cycles-frontend:u # 1172.77% frontend cycles idle + 524,776,029 instructions:u # 0.37 insn per cycle + # 32.09 stalled cycles per insn + 144,951,979 branches:u # 22.708 M/sec + 4,018,908 branch-misses:u # 2.77% of all branches + + 5.401308431 seconds time elapsed + 0.773771000 seconds user + 6.235207000 seconds sys + +$ perf stat ... --eval '(test3)' --quit + 7,813.04 msec task-clock:u # 1.133 CPUs utilized + 0 context-switches:u # 0.000 K/sec + 0 cpu-migrations:u # 0.000 K/sec + 131,699 page-faults:u # 0.017 M/sec + 1,477,424,012 cycles:u # 0.189 GHz + 20,769,787,623 stalled-cycles-frontend:u # 1405.81% frontend cycles idle + 525,748,318 instructions:u # 0.36 insn per cycle + # 39.51 stalled cycles per insn + 145,134,345 branches:u # 18.576 M/sec + 4,412,369 branch-misses:u # 3.04% of all branches + + 6.894458409 seconds time elapsed + 0.641120000 seconds user + 7.864134000 seconds sys + +Conclusion: approximately 300 microseconds to start a thread + +With :pauseless-threadstart +---------------------------- + +$ perf stat ... --eval '(test1)' --quit + 1,541.91 msec task-clock:u # 1.068 CPUs utilized + 0 context-switches:u # 0.000 K/sec + 0 cpu-migrations:u # 0.000 K/sec + 633 page-faults:u # 0.411 K/sec + 801,317,853 cycles:u # 0.520 GHz + 3,751,130,586 stalled-cycles-frontend:u # 468.12% frontend cycles idle + 352,170,311 instructions:u # 0.44 insn per cycle + # 10.65 stalled cycles per insn + 81,884,155 branches:u # 53.106 M/sec + 1,334,916 branch-misses:u # 1.63% of all branches + + 1.443664147 seconds time elapsed + 0.425407000 seconds user + 1.471034000 seconds sys + +$ perf stat ... --eval '(test2)' --quit + 1,249.01 msec task-clock:u # 1.550 CPUs utilized + 0 context-switches:u # 0.000 K/sec + 0 cpu-migrations:u # 0.000 K/sec + 573 page-faults:u # 0.459 K/sec + 668,480,325 cycles:u # 0.535 GHz + 3,086,418,550 stalled-cycles-frontend:u # 461.71% frontend cycles idle + 376,966,208 instructions:u # 0.56 insn per cycle + # 8.19 stalled cycles per insn + 95,790,671 branches:u # 76.694 M/sec + 918,120 branch-misses:u # 0.96% of all branches + + 0.805563424 seconds time elapsed + 0.325539000 seconds user + 1.162641000 seconds sys + +$ perf stat ... --eval '(test3)' --quit + 1,308.09 msec task-clock:u # 1.455 CPUs utilized + 0 context-switches:u # 0.000 K/sec + 0 cpu-migrations:u # 0.000 K/sec + 4,838 page-faults:u # 0.004 M/sec + 660,514,151 cycles:u # 0.505 GHz + 3,230,465,234 stalled-cycles-frontend:u # 489.08% frontend cycles idle + 364,307,811 instructions:u # 0.55 insn per cycle + # 8.87 stalled cycles per insn + 92,966,084 branches:u # 71.070 M/sec + 730,714 branch-misses:u # 0.79% of all branches + + 0.899161220 seconds time elapsed + 0.339090000 seconds user + 1.227741000 seconds sys + +Conclusion: 40 to 100 microseconds to start a thread diff --git a/doc/internals-notes/memory-arenas.txt b/doc/internals-notes/memory-arenas.txt new file mode 100644 index 0000000000..64f0c53d71 --- /dev/null +++ b/doc/internals-notes/memory-arenas.txt @@ -0,0 +1,70 @@ + +The use-case for arenas is to allow for an allocator that consumes +space using a stack-like discpline, often called "Mark/Release" +(see e.g. https://wiki.dlang.org/Memory_Management#Mark.2FRelease) +Multiple threads can each create their own arena of memory, mark their current usage, +do some work, and very quickly unwind the mark all before GC notices anything. + +Obviously there are complications involved when dynamic space points to the arenas +and vice-versa. Most of those are surmountable, but for for CLOS dispatch being a +particularly intense pain point. PCL has a tendency to pseudo-randomly create persistent +state when you least expect it, so that you end up with FUNCALLABLE-INSTANCE-FUNCTION +of a GENERIC-FUNCTION pointing to memory that was just released via mark/release. +Discovering enough about where the PCL implementation creates state changes was +counterproductive to the overall mission of changing a minimal amount of source code. + +The starting point for exploration was a pair of macros named WITH-ARENA and +WITHOUT-ARENA that do as their names imply. They are scoped dynamically, not lexically, +which means that they control behavior of allocator at runtime, and can be thought +of as akin to binding a special variable. +Bearing in mind that the desired goal is not to have all "user" code know that it should +do something special to allocate, it seems preferable to force all system code to know +when not to use an arena. So if we assume that the toplevel of all user code has a single +WITH-ARENA placed around it, the objective becomes to strategically place WITHOUT-ARENA +throughout the internals of the PCL implementation. +(A WITHOUT-ARENA at the entry point to COMPILE takes care of the general issue of making +new code, per se. But it doesn't help the situation with PCL in general) + +PCL relies on such a significant amount of mutable state and action-at-a-distance +that even after after weeks of study of the PCL source code, it was not apparent where +to inject appropriate allocator control macros. And users have extremly little choice +over when, if ever, PCL decides to allocate anything in the first place. + +This troubles stem from two patterns prevalent in PCL. +1. lambdas that return lambdas + to decorate them would imply writing + (without-arena () (lambda () ... (without-arena () (lambda ...)))) + +2. lambdas that end up tail-calling the user's "actual" code + (lambda (args) (reoptimize-myself-for-current-state (apply actual-user-code actual-args))) + which would have to be recast as something like + (lambda (args) + (without-arena (reoptimize-myself-for-current-state + (with-arena (apply actual-user-code actual-args))))) + +It became apparent that we need a variety of techniques that entail more cooperation +between the compiler and the VM than just these 2 macros, to minimize changes in source. + +* Dynamically scoped control, as the starting point. + +* Choose based on object type at runtime- so SB-PCL::CACHE would always go "somewhere else" + than dictated by the dynamic control. i.e. we decide _statically_ that certain objects + go to either the TLAB or the arena. + This unfortunately precludes using %MAKE-INSTANCE to make variable-length structures + such as SB-INT:PACKED-INFO because there is no allocation vop which takes the length + as a variable, but a particular instance type as a constant. + +* Based on the name of the file being compiled- any allocation code could be + emitted differently at compile-time. So for example while compiling src/pcl/*.lisp + the ALLOCATION function could do something different. + This can be achieved with a compile-time DEFVAR that says that the alternative + TLABs should be used. + +* Based on a lexical scope- any allocation occurring while that declaration + is visible would go "somewhere else". This changes the scoping from dynamic + to static, but it is not apprpriate for things like a HASH-TABLE constructor, because + a HASH-TABLE could be made by user code, or PCL. + However it seems well-suited to something like SB-INT:PACKED-INFO because those + objects always imply a (relatively) permanent state change. + And that if we do see an occurence of MAKE-HASH-TABLE in the PCL source code, + we can easily wrap that in WITHOUT-ARENA. diff --git a/doc/internals-notes/metaspace b/doc/internals-notes/metaspace new file mode 100644 index 0000000000..8342b0c8bd --- /dev/null +++ b/doc/internals-notes/metaspace @@ -0,0 +1,101 @@ +Metaspace will hold all instances of LAYOUT when SBCL is +built with the :METASPACE feature enabled. +In that case, LAYOUTs may only be directly pointed to by: + * thread stacks and registers + * the header word of an INSTANCE or FUNCALLABLE-INSTANCE + * a code header's boxed constant pool + +The reason for pointing to LAYOUTs only from a restricted set of heap +objects has to do with complications to pointer tracing. +Bear in mind that there will be a finalizer attached to each WRAPPER +which is responsibile for freeing the manually-managed LAYOUT when the +wrapper is deleted by the garbage collector. + +Consider the following hypothetical example in which an arbitrary +simple-vector could allegedly point to a layout. + + DYNAMIC SPACE | MANUAL POOL + -------------------------------------------------------------- + + "V": vector + +---------+ | + | header | | + +---------+ | + | length | + +---------+ pointer "a" + | elt 0 | ------------------\ + +---------+ \ + | elt 1 | | \ + +---------+ | \ + | v + | + "I": instance | "L": instance of LAYOUT + of SOME-OBJECT | for SOME-OBJECT type + +---------------| | +---------------+ + | header word | -------------> | header word | + | ptr to LAYOUT | pointer "b" | layout-layout | + +---------------+ | +---------------+ + | payload | | | pointer to | + | ... | | / | WRAPPER | + +---------------+ | / +---------------+ + | / | | + | / | type IDs | + / | ... | + pointer "c" / +---------------+ + ------------------ | bitmap | + v +---------------+ + + "W": WRAPPER for | + SOME-OBJECT type | + +-------------| | + | header word | | + | | | + +-------------+ | + | payload | | + | ... | | + +-------------+ | + | +------------------------------------------------------------------ + +Tracing the instance "I" obviously needs to read the metadata from LAYOUT "L". +In particular, scanning requires knowledge of the raw slot bitmap. +Because the tracing algorithm needs to access the LAYOUT anyway, it can additionally +treat pointer "c" as if it originated from instance "I" by calling the pointer fixing +method on "c", thereby enlivening wrapper "W". Fixing may require writing back +pointer "c" into "L" if the pointer's value changed. From that perspective, pointer +"b" acts like a strangely encoded pointer from "I" to to "W", +and the tracing logic is totally agnostic of the encoding/decoding mechanism. + +But now consider that pointer "b" can be changed (via CHANGE-CLASS), or more simply, +instance "I" could become unreachable. Then as far as the pointer graph looks, +there is no path from a live instance of SOME-OBJECT to the wrapper "W". +Therefore the garbage collector could free W and trigger W's finalizer which +should (eventually) free the manually allocated L despite that both L (and hence W) +are still reachable through the vector V. Nothing prevents user code from reading +the vector and so on, which would constitute use-after-free error. + +We could attempt to rememdy this by saying that *every* potential pointer +into the manual pool should be examined to see whether the target is a LAYOUT. +Such an approach would add considerable overhead, quite literally every pointer +might have to be doubly-dereferenced. Without loss of generality, we have depicted +a 2-element vector, but it could be a million-element vector, or a 100-element list. +Such overhead in determining whether every pointer points to manually-managed +memory is unacceptable. + +In contrast, the cost of reading the pointer "b" from "I" to "L" has to be paid +no matter what. So confining the extra check for LAYOUT -> WRAPPER pointers to +only the scan of instance header words represents a significant decrease from the +theoretical maximum number of heap words that would be scanned using +the pessimistic (or "conservative") approach. That is, treating as few +pointers as possible as potential pointers to manual pools is to be preferred. + +However, a similar situation with code objects arises. A code object must be +allowed to point directly to a LAYOUT because the code needs to assign the layout +into an instance. Conceivably the code could point to the wrapper instead, +but we don't necessarily have an extra machine register available exactly +when needed in the allocation sequence - a register that would be needed to +extract the layout from the wrapper. As with instance scanning, it should be +relatively benign to perform a small amount of extra work in GC to facilitate +assigning layouts in object constructors. This is definitely a trade-off, +however, code blobs are not as frequently occurring as say cons cells, +vectors, and general instances. diff --git a/doc/internals-notes/structure-typep-change b/doc/internals-notes/structure-typep-change new file mode 100644 index 0000000000..d34f90467a --- /dev/null +++ b/doc/internals-notes/structure-typep-change @@ -0,0 +1,123 @@ + +Design for new implementation of TYPEP on structure-objects: + +* Assign every layout a permanent stable ID using 29 bits + (N-POSITIVE-FIXNUM-BITS for 32-bit words) and try to recycle the + unused IDs if layouts get GCd. + +* Embed all IDs of every type that a layout "is" directly in the layout. + A layout includes its own ID as the last element of the IS-A vector. + In contrast, the INHERITS vector did not include the structure itself + which always required picking off an exactly equal type as a special + case, and then also checking for type inheritance. + In the ID-based approach, (typep x 'THING) need not distinguish + between whether X is THING or a type descended from THING. + +* Reserve space for at least 6 IDs in the IS-A vector, which is 2 more + than the former ANCESTOR-n slots held. Additionally, the IS-A vector + can always holds _all_ the IDs, whereas the ANCESTOR-n slots did not, + and would fall back upon lookup in the INHERITS vector. + The IS-A vector is sized as required by the layout constructor. + Variable-length layouts are needed for the trailing bitmap anyway, + so it is no more trouble to further extend layouts with extra words. + Note that depth 0 is implicitly the ID of the type T, + and depth 1 is implicitly the ID of STRUCTURE-OBJECT, + so those are not stored in the ID vector. + +* The most common variant of the structure TYPEP test is changed from: + (OR (EQ THIS-LAYOUT EXPECT-LAYOUT) + (AND (> THIS-LAYOUT-DEPTH (LAYOUT-DEPTH EXPECT-LAYOUT)) + (EQ (SVREF INHERITS DEPTH) EXPECT-LAYOUT))) + to: + (EQ (NTH-ANCESTOR-ID) EXPECT-LAYOUT-ID) + which can usually execute safely without the depth check. + In case the depth of the type under test exceeds the mandatory minimum + length of the IS-A vector (6), then perform the depth test first + to avoid out-of-bounds indexing. + Lack of the depth check improves branch prediction rate. + +Test I: "perf stat" on make-host-1 +================================== +Old: + 30497.22 msec task-clock # 1.000 CPUs utilized + 162 context-switches # 0.005 K/sec + 0 cpu-migrations # 0.000 K/sec + 358179 page-faults # 0.012 M/sec + 85176684440 cycles # 2.793 GHz + 49191173035 stalled-cycles-frontend # 57.75% frontend cycles idle + 84764154618 instructions # 1.00 insn per cycle + # 0.58 stalled cycles per insn + 19746929213 branches # 647.499 M/sec + 607098366 branch-misses # 3.07% of all branches + + 30.503523458 seconds time elapsed + + 29.206010000 seconds user + 1.291911000 seconds sys + +New: + 28308.70 msec task-clock # 0.999 CPUs utilized + 521 context-switches # 0.018 K/sec + 3 cpu-migrations # 0.000 K/sec + 428089 page-faults # 0.015 M/sec + 79067487625 cycles # 2.793 GHz + 45445183758 stalled-cycles-frontend # 57.48% frontend cycles idle + 80724429510 instructions # 1.02 insn per cycle + # 0.56 stalled cycles per insn + 18319117558 branches # 647.120 M/sec + 552061322 branch-misses # 3.01% of all branches + + 28.324995675 seconds time elapsed + + 26.775357000 seconds user + 1.555962000 seconds sys + +delta: task-clock: -7.1% + cycles: -7.1% + intructions: -4.7% + branches: -7.2% + branch-miss: -9.0% + user sec: -8.3% + +Test II: "perf stat" on make-host-2 +=================================== +Old: + 87641.99 msec task-clock # 1.000 CPUs utilized + 403 context-switches # 0.005 K/sec + 0 cpu-migrations # 0.000 K/sec + 858614 page-faults # 0.010 M/sec + 244791150476 cycles # 2.793 GHz + 138448804561 stalled-cycles-frontend # 56.56% frontend cycles idle + 258526783085 instructions # 1.06 insn per cycle + # 0.54 stalled cycles per insn + 58641402544 branches # 669.102 M/sec + 1387692425 branch-misses # 2.37% of all branches + + 87.659365156 seconds time elapsed + + 84.883404000 seconds user + 2.759720000 seconds sys + +New: + 83026.56 msec task-clock # 1.000 CPUs utilized + 1244 context-switches # 0.015 K/sec + 7 cpu-migrations # 0.000 K/sec + 1119264 page-faults # 0.013 M/sec + 231835280270 cycles # 2.792 GHz + 129266360060 stalled-cycles-frontend # 55.76% frontend cycles idle + 254253852289 instructions # 1.10 insn per cycle + # 0.51 stalled cycles per insn + 56393384370 branches # 679.221 M/sec + 1281237117 branch-misses # 2.27% of all branches + + 83.048348272 seconds time elapsed + + 79.858200000 seconds user + 3.187928000 seconds sys + +delta: task-clock: -5.2% + cycles: -5.2% + intructions: -1.6% + branches: -3.8% + branch-miss: -7.6% + user sec: -5.9% diff --git a/doc/internals-notes/threading-specials b/doc/internals-notes/threading-specials deleted file mode 100644 index e1472ba569..0000000000 --- a/doc/internals-notes/threading-specials +++ /dev/null @@ -1,1020 +0,0 @@ -Things in SBCL that look like special variables (list created by -(apropos "*")) and could conceivably indicate potental thread safety -issues. Organised by functional area. - -The goals are - - (1) classify the unclassified symbols (in such a way as to - make sense for 2) - - (2) read through the subsystems identified looking for places - where global state is mutated. Use this list of symbols as a - guide, but be open to the possibility that other state - (e.g. closures, foreign variables) is touched too. - - When looking at a particular symbol, please annotate it in - this file when you figure out what it's for and how it's - changed. To give us some confidence that we have reasonable - coverage, please don't just delete it if it looks ok. Symbols - shoud only be deleted here if they're obviously not specials - at all (e.g. functions with * in their names), or if the same - commit actually rids SBCL of the symbol itself. Otherwise, - just add a comment saying "read-only" or "unused" or whatever. - - (3) anything else that comes to mind as potential trouble - spots. Global state in closures, etc etc - - (4) suggest strategies (e.g. rewrites of affected code, suitable - locks and lock acquisition/release places) to fix the issues - revealed in (2) and (3) - - (5) implement same - - Candidates may attempt any of the above simultaneously. - Points will be awarded for style - - -Summary so far: - -= loop -= PCL (probably ok if PCL authors did *without-interrupts* right) -= debugger -= profiler -= disassembler -= assembler (I assume protected by *big-compiler-lock*) -= unix interface (apparently ok) -= toplevel/environment stuff -= the formatter & pretty printer (two vars need checking) -= compiler (protected by *big-compiler-lock*) -= fasloader (protected by *big-compiler-lock*) -= runtime stuff - gc, control stacks, interrupts etc -= backend constants -= dead -= unclassified - -================== - -= loop - -I suspect that stuff in sb-loop is only ever frobbed at -macroexpand/compile time anyway, so covered by *big-compiler-lock*. -Haven't thought about this too hard, though - -SB-LOOP::*LOOP-BODY* -SB-LOOP::*LOOP-DESETQ-TEMPORARY* -SB-LOOP::*LOOP-INSIDE-CONDITIONAL* -SB-LOOP::*LOOP-EPILOGUE* -SB-LOOP::*LOOP-ANSI-UNIVERSE* - -= PCL - -Critical parts of PCL are protected by *world-lock* (particularly -those dealing with class graph changes), and some with finer-grained locks. - -accesses locked with a nice granularity - SB-PCL::*CLASSOID-CELLS* - -read-only & safe: - SB-PCL::*BUILT-IN-TYPEP-COST* - SB-PCL::*CACHE-EXPAND-THRESHOLD* - SB-PCL::*CACHE-LOOKUP-COST* - SB-PCL::*CASE-TABLE-LIMIT* - SB-PCL::*CHECK-CACHE-P* - SB-PCL::*COMPUTE-STD-CPL-CLASS->ENTRY-TABLE-SIZE* - SB-PCL::*EQ-CASE-TABLE-LIMIT* - SB-PCL::*NON-BUILT-IN-TYPEP-COST* - SB-PCL::*NON-VAR-DECLARATIONS* - SB-PCL::*SECONDARY-DFUN-CALL-COST* - SB-PCL::*SGF-WRAPPER* - SB-PCL::*STRUCTURE-TYPEP-COST* - SB-PCL::*UNSPECIFIC-ARG* - SB-PCL::*VAR-DECLARATIONS-WITH-ARG* - SB-PCL::*WRAPPER-OF-COST* - -bound & safe: - SB-PCL::*ALLOW-FORWARD-REFERENCED-CLASSES-IN-CPL-P* - SB-PCL::*IN-OBSOLETE-INSTANCE-TRAP* - SB-PCL::*PRECOMPILING-LAP* - SB-PCL::*CACHE-MISS-VALUES-STACK* - -protected by PCL-LOCK: - SB-PCL::*PREVIOUS-NWRAPPERS* - -believed protected by the compiler-lock: - SB-PCL::*ALL-CTORS* - SB-PCL::*FGENS* - SB-PCL::*SGF-DFUN-STATE-INDEX* - SB-PCL::*VAR-DECLARATIONS-WITHOUT-ARG* - -potentially unsafe: - SB-PCL::*CLASS-EQ-SPECIALIZER-METHODS* - SB-PCL::*EFFECTIVE-METHOD-CACHE* - SB-PCL::*EQL-SPECIALIZER-METHODS* - SB-PCL::*METHOD-FUNCTION-PLIST* - SB-PCL::*PV-KEY-TO-PV-TABLE-TABLE* - SB-PCL::*PV-TABLE-CACHE-UPDATE-INFO* - SB-PCL::*PVS* - SB-PCL::*SLOT-NAME-LISTS-INNER* - SB-PCL::*SLOT-NAME-LISTS-OUTER* - -debugging / profiling -- low relevance: - SB-PCL::*DFUN-COUNT* - SB-PCL::*ALLOW-EMF-CALL-TRACING-P* - -build-options and bootstrap machinery -- irrelevant for user-code: - SB-PCL::*ALLOW-EXPERIMENTAL-SPECIALIZERS-P* - SB-PCL::*BOOT-STATE* ; pseudoconstant in finished lisp (not in bootstrap) - SB-PCL::*BUILT-IN-CLASS-SYMBOLS* - SB-PCL::*BUILT-IN-CLASSES* - SB-PCL::*BUILT-IN-WRAPPER-SYMBOLS* - SB-PCL::*CHECKING-OR-CACHING-LIST* - -;;; global, frobbed on generic function -;;; initialization/reinitialization, method precomputation, and -;;; compute-effective-method. Potentially unsafe, may be OK because -;;; of *pcl-lock*, but could easily be liable to races. - -SB-PCL::*CONDITION-SETF-SLOT-VALUE-USING-CLASS-METHOD* -SB-PCL::*CONDITION-SLOT-BOUNDP-USING-CLASS-METHOD* -SB-PCL::*CONDITION-SLOT-VALUE-USING-CLASS-METHOD* -SB-PCL::*CREATE-CLASSES-FROM-INTERNAL-STRUCTURE-DEFINITIONS-P* -SB-PCL::*DFUN-ARG-SYMBOLS* -SB-PCL::*DFUN-CONSTRUCTORS* -SB-PCL::*DFUN-LIST* -SB-PCL::*DFUN-MISS-GFS-ON-STACK* -SB-PCL::*EARLY-CLASS-DEFINITIONS* -SB-PCL::*EARLY-CLASS-PREDICATES* -SB-PCL::*EARLY-CLASS-SLOTS* -SB-PCL::*EARLY-P* -SB-PCL::*EMF-CALL-TRACE* -SB-PCL::*EMF-CALL-TRACE-INDEX* -SB-PCL::*EMF-CALL-TRACE-SIZE* -SB-PCL::*EMIT-FUNCTION-P* -SB-PCL::*ENABLE-DFUN-CONSTRUCTOR-CACHING* -SB-PCL::*ENABLE-EMF-CALL-TRACING-P* -SB-PCL::*EQL-SPECIALIZER-TABLE* -SB-PCL::*GLOBAL-EFFECTIVE-METHOD-GENSYMS* -SB-PCL::*IN-GF-ARG-INFO-P* -SB-PCL::*IN-PRECOMPUTE-EFFECTIVE-METHODS-P* -SB-PCL::*INITFUNCTIONS-FOR-THIS-DEFCLASS* -SB-PCL::*INTERNAL-PCL-GENERALIZED-FUN-NAME-SYMBOLS* -SB-PCL::*LAZY-DFUN-COMPUTE-P* -SB-PCL::*LONG-METHOD-COMBINATION-FUNCTIONS* -SB-PCL::*MINIMUM-CACHE-SIZE-TO-LIST* -SB-PCL::*NAME->CLASS->SLOTD-TABLE* -SB-PCL::*NEW-CLASS* -SB-PCL::*NORMALIZE-TYPE -SB-PCL::*NOT-IN-CACHE* -SB-PCL::*OLD-C-A-M-GF-METHODS* -SB-PCL::*OPTIMIZE-CACHE-FUNCTIONS-P* -SB-PCL::*OPTIMIZE-SPEED* -SB-PCL::*PCL-CLASS-BOOT* -SB-PCL::*PCL-LOCK* ; protecting the rest -SB-PCL::*PCL-PACKAGE* -SB-PCL::*RAISE-METATYPES-TO-CLASS-P* -SB-PCL::*READERS-FOR-THIS-DEFCLASS* -SB-PCL::*REBOUND-EFFECTIVE-METHOD-GENSYMS* -SB-PCL::*SGF-ARG-INFO-INDEX* -SB-PCL::*SGF-METHOD-CLASS-INDEX* -SB-PCL::*SGF-METHODS-INDEX* -SB-PCL::*SGF-NAME-INDEX* -SB-PCL::*SGF-SLOTS-INIT* -SB-PCL::*SHOW-MAKE-UNORDERED-METHODS-EMF-CALLS* -SB-PCL::*SLOT-NAMES-FOR-THIS-DEFCLASS* -SB-PCL::*SLOT-VECTOR-SYMBOLS* -SB-PCL::*STANDARD-CLASSES* -SB-PCL::*STANDARD-METHOD-COMBINATION* -SB-PCL::*STANDARD-SETF-SLOT-VALUE-USING-CLASS-METHOD* -SB-PCL::*STANDARD-SLOT-BOUNDP-USING-CLASS-METHOD* -SB-PCL::*STANDARD-SLOT-LOCATIONS* -SB-PCL::*STANDARD-SLOT-VALUE-USING-CLASS-METHOD* -SB-PCL::*STD-CAM-METHODS* -SB-PCL::*STRUCTURE-SETF-SLOT-VALUE-USING-CLASS-METHOD* -SB-PCL::*STRUCTURE-SLOT-BOUNDP-USING-CLASS-METHOD* -SB-PCL::*STRUCTURE-SLOT-VALUE-USING-CLASS-METHOD* -SB-PCL::*SUBTYPEP -SB-PCL::*THE-CLASS-ARRAY* -SB-PCL::*THE-CLASS-BASE-CHAR* -SB-PCL::*THE-CLASS-BIGNUM* -SB-PCL::*THE-CLASS-BIT-VECTOR* -SB-PCL::*THE-CLASS-BUILT-IN-CLASS* -SB-PCL::*THE-CLASS-CHARACTER* -SB-PCL::*THE-CLASS-CLASS* -SB-PCL::*THE-CLASS-CLASS-EQ-SPECIALIZER* -SB-PCL::*THE-CLASS-CLASS-PROTOTYPE-SPECIALIZER* -SB-PCL::*THE-CLASS-CODE-COMPONENT* -SB-PCL::*THE-CLASS-COMPLEX* -SB-PCL::*THE-CLASS-COMPLEX-DOUBLE-FLOAT* -SB-PCL::*THE-CLASS-COMPLEX-SINGLE-FLOAT* -SB-PCL::*THE-CLASS-CONDITION* -SB-PCL::*THE-CLASS-CONDITION-CLASS* -SB-PCL::*THE-CLASS-CONDITION-DIRECT-SLOT-DEFINITION* -SB-PCL::*THE-CLASS-CONDITION-EFFECTIVE-SLOT-DEFINITION* -SB-PCL::*THE-CLASS-CONDITION-SLOT-DEFINITION* -SB-PCL::*THE-CLASS-CONS* -SB-PCL::*THE-CLASS-DEFINITION-SOURCE-MIXIN* -SB-PCL::*THE-CLASS-DEPENDENT-UPDATE-MIXIN* -SB-PCL::*THE-CLASS-DIRECT-SLOT-DEFINITION* -SB-PCL::*THE-CLASS-DOCUMENTATION-MIXIN* -SB-PCL::*THE-CLASS-DOUBLE-FLOAT* -SB-PCL::*THE-CLASS-EFFECTIVE-SLOT-DEFINITION* -SB-PCL::*THE-CLASS-EQL-SPECIALIZER* -SB-PCL::*THE-CLASS-EXACT-CLASS-SPECIALIZER* -SB-PCL::*THE-CLASS-FDEFN* -SB-PCL::*THE-CLASS-FIXNUM* -SB-PCL::*THE-CLASS-FLOAT* -SB-PCL::*THE-CLASS-FORWARD-REFERENCED-CLASS* -SB-PCL::*THE-CLASS-FUNCALLABLE-INSTANCE* -SB-PCL::*THE-CLASS-FUNCALLABLE-STANDARD-CLASS* -SB-PCL::*THE-CLASS-FUNCALLABLE-STANDARD-OBJECT* -SB-PCL::*THE-CLASS-FUNCTION* -SB-PCL::*THE-CLASS-GENERIC-FUNCTION* -SB-PCL::*THE-CLASS-INSTANCE* -SB-PCL::*THE-CLASS-INTEGER* -SB-PCL::*THE-CLASS-LIST* -SB-PCL::*THE-CLASS-LONG-METHOD-COMBINATION* -SB-PCL::*THE-CLASS-LRA* -SB-PCL::*THE-CLASS-METHOD* -SB-PCL::*THE-CLASS-METHOD-COMBINATION* -SB-PCL::*THE-CLASS-NULL* -SB-PCL::*THE-CLASS-NUMBER* -SB-PCL::*THE-CLASS-PCL-CLASS* -SB-PCL::*THE-CLASS-PLIST-MIXIN* -SB-PCL::*THE-CLASS-RANDOM-CLASS* -SB-PCL::*THE-CLASS-RATIO* -SB-PCL::*THE-CLASS-RATIONAL* -SB-PCL::*THE-CLASS-REAL* -SB-PCL::*THE-CLASS-SEQUENCE* -SB-PCL::*THE-CLASS-SIMPLE-ARRAY* -SB-PCL::*THE-CLASS-SIMPLE-ARRAY-COMPLEX-DOUBLE-FLOAT* -SB-PCL::*THE-CLASS-SIMPLE-ARRAY-COMPLEX-SINGLE-FLOAT* -SB-PCL::*THE-CLASS-SIMPLE-ARRAY-DOUBLE-FLOAT* -SB-PCL::*THE-CLASS-SIMPLE-ARRAY-SIGNED-BYTE-16* -SB-PCL::*THE-CLASS-SIMPLE-ARRAY-SIGNED-BYTE-30* -SB-PCL::*THE-CLASS-SIMPLE-ARRAY-SIGNED-BYTE-32* -SB-PCL::*THE-CLASS-SIMPLE-ARRAY-SIGNED-BYTE-8* -SB-PCL::*THE-CLASS-SIMPLE-ARRAY-SINGLE-FLOAT* -SB-PCL::*THE-CLASS-SIMPLE-ARRAY-UNSIGNED-BYTE-16* -SB-PCL::*THE-CLASS-SIMPLE-ARRAY-UNSIGNED-BYTE-2* -SB-PCL::*THE-CLASS-SIMPLE-ARRAY-UNSIGNED-BYTE-32* -SB-PCL::*THE-CLASS-SIMPLE-ARRAY-UNSIGNED-BYTE-4* -SB-PCL::*THE-CLASS-SIMPLE-ARRAY-UNSIGNED-BYTE-8* -SB-PCL::*THE-CLASS-SIMPLE-BIT-VECTOR* -SB-PCL::*THE-CLASS-SIMPLE-STRING* -SB-PCL::*THE-CLASS-SIMPLE-VECTOR* -SB-PCL::*THE-CLASS-SINGLE-FLOAT* -SB-PCL::*THE-CLASS-SLOT-CLASS* -SB-PCL::*THE-CLASS-SLOT-DEFINITION* -SB-PCL::*THE-CLASS-SLOT-OBJECT* -SB-PCL::*THE-CLASS-SPECIALIZER* -SB-PCL::*THE-CLASS-SPECIALIZER-WITH-OBJECT* -SB-PCL::*THE-CLASS-STANDARD-ACCESSOR-METHOD* -SB-PCL::*THE-CLASS-STANDARD-BOUNDP-METHOD* -SB-PCL::*THE-CLASS-STANDARD-CLASS* -SB-PCL::*THE-CLASS-STANDARD-DIRECT-SLOT-DEFINITION* -SB-PCL::*THE-CLASS-STANDARD-EFFECTIVE-SLOT-DEFINITION* -SB-PCL::*THE-CLASS-STANDARD-GENERIC-FUNCTION* -SB-PCL::*THE-CLASS-STANDARD-METHOD* -SB-PCL::*THE-CLASS-STANDARD-METHOD-COMBINATION* -SB-PCL::*THE-CLASS-STANDARD-OBJECT* -SB-PCL::*THE-CLASS-STANDARD-READER-METHOD* -SB-PCL::*THE-CLASS-STANDARD-SLOT-DEFINITION* -SB-PCL::*THE-CLASS-STANDARD-WRITER-METHOD* -SB-PCL::*THE-CLASS-STD-CLASS* -SB-PCL::*THE-CLASS-STD-OBJECT* -SB-PCL::*THE-CLASS-STREAM* -SB-PCL::*THE-CLASS-STRING* -SB-PCL::*THE-CLASS-STRUCTURE-CLASS* -SB-PCL::*THE-CLASS-STRUCTURE-DIRECT-SLOT-DEFINITION* -SB-PCL::*THE-CLASS-STRUCTURE-EFFECTIVE-SLOT-DEFINITION* -SB-PCL::*THE-CLASS-STRUCTURE-OBJECT* -SB-PCL::*THE-CLASS-STRUCTURE-SLOT-DEFINITION* -SB-PCL::*THE-CLASS-SYMBOL* -SB-PCL::*THE-CLASS-SYSTEM-AREA-POINTER* -SB-PCL::*THE-CLASS-T* -SB-PCL::*THE-CLASS-VECTOR* -SB-PCL::*THE-CLASS-WEAK-POINTER* -SB-PCL::*THE-ESLOTD-FUNCALLABLE-STANDARD-CLASS-SLOTS* -SB-PCL::*THE-ESLOTD-STANDARD-CLASS-SLOTS* -SB-PCL::*THE-SYSTEM-II-METHOD* -SB-PCL::*THE-SYSTEM-SI-METHOD* -SB-PCL::*THE-WRAPPER-OF-ARRAY* -SB-PCL::*THE-WRAPPER-OF-BASE-CHAR* -SB-PCL::*THE-WRAPPER-OF-BIGNUM* -SB-PCL::*THE-WRAPPER-OF-BIT-VECTOR* -SB-PCL::*THE-WRAPPER-OF-CHARACTER* -SB-PCL::*THE-WRAPPER-OF-CODE-COMPONENT* -SB-PCL::*THE-WRAPPER-OF-COMPLEX* -SB-PCL::*THE-WRAPPER-OF-COMPLEX-DOUBLE-FLOAT* -SB-PCL::*THE-WRAPPER-OF-COMPLEX-SINGLE-FLOAT* -SB-PCL::*THE-WRAPPER-OF-CONS* -SB-PCL::*THE-WRAPPER-OF-DOUBLE-FLOAT* -SB-PCL::*THE-WRAPPER-OF-FDEFN* -SB-PCL::*THE-WRAPPER-OF-FIXNUM* -SB-PCL::*THE-WRAPPER-OF-FLOAT* -SB-PCL::*THE-WRAPPER-OF-INTEGER* -SB-PCL::*THE-WRAPPER-OF-LIST* -SB-PCL::*THE-WRAPPER-OF-LRA* -SB-PCL::*THE-WRAPPER-OF-NULL* -SB-PCL::*THE-WRAPPER-OF-NUMBER* -SB-PCL::*THE-WRAPPER-OF-RANDOM-CLASS* -SB-PCL::*THE-WRAPPER-OF-RATIO* -SB-PCL::*THE-WRAPPER-OF-RATIONAL* -SB-PCL::*THE-WRAPPER-OF-REAL* -SB-PCL::*THE-WRAPPER-OF-SEQUENCE* -SB-PCL::*THE-WRAPPER-OF-SIMPLE-ARRAY* -SB-PCL::*THE-WRAPPER-OF-SIMPLE-ARRAY-COMPLEX-DOUBLE-FLOAT* -SB-PCL::*THE-WRAPPER-OF-SIMPLE-ARRAY-COMPLEX-SINGLE-FLOAT* -SB-PCL::*THE-WRAPPER-OF-SIMPLE-ARRAY-DOUBLE-FLOAT* -SB-PCL::*THE-WRAPPER-OF-SIMPLE-ARRAY-SIGNED-BYTE-16* -SB-PCL::*THE-WRAPPER-OF-SIMPLE-ARRAY-SIGNED-BYTE-30* -SB-PCL::*THE-WRAPPER-OF-SIMPLE-ARRAY-SIGNED-BYTE-32* -SB-PCL::*THE-WRAPPER-OF-SIMPLE-ARRAY-SIGNED-BYTE-8* -SB-PCL::*THE-WRAPPER-OF-SIMPLE-ARRAY-SINGLE-FLOAT* -SB-PCL::*THE-WRAPPER-OF-SIMPLE-ARRAY-UNSIGNED-BYTE-16* -SB-PCL::*THE-WRAPPER-OF-SIMPLE-ARRAY-UNSIGNED-BYTE-2* -SB-PCL::*THE-WRAPPER-OF-SIMPLE-ARRAY-UNSIGNED-BYTE-32* -SB-PCL::*THE-WRAPPER-OF-SIMPLE-ARRAY-UNSIGNED-BYTE-4* -SB-PCL::*THE-WRAPPER-OF-SIMPLE-ARRAY-UNSIGNED-BYTE-8* -SB-PCL::*THE-WRAPPER-OF-SIMPLE-BIT-VECTOR* -SB-PCL::*THE-WRAPPER-OF-SIMPLE-STRING* -SB-PCL::*THE-WRAPPER-OF-SIMPLE-VECTOR* -SB-PCL::*THE-WRAPPER-OF-SINGLE-FLOAT* -SB-PCL::*THE-WRAPPER-OF-STRING* -SB-PCL::*THE-WRAPPER-OF-STRUCTURE-OBJECT* -SB-PCL::*THE-WRAPPER-OF-SYMBOL* -SB-PCL::*THE-WRAPPER-OF-SYSTEM-AREA-POINTER* -SB-PCL::*THE-WRAPPER-OF-T* -SB-PCL::*THE-WRAPPER-OF-VECTOR* -SB-PCL::*THE-WRAPPER-OF-WEAK-POINTER* -SB-PCL::*WRITERS-FOR-THIS-DEFCLASS* -SB-PCL::WRAPPER-CLASS* - - -= debugger - -*DEBUG-PRINT-LENGTH* -*TRACE-FRAME* -*TRACE-ENCAPSULATE-DEFAULT* -*MAX-TRACE-INDENTATION* -*IN-THE-DEBUGGER* -*DEBUG-BEGINNER-HELP-P* -*STACK-TOP-HINT* -*DEBUG-HELP-STRING* -*ONLY-BLOCK-START-LOCATIONS* -*FLUSH-DEBUG-ERRORS* -*DEBUG-CONDITION* -*TRACE-VALUES* -*PRINT-LOCATION-KIND* -*DEBUG-PRINT-LEVEL* -*TRACED-FUN-LIST* -*TRACE-INDENTATION-STEP* -*DEBUG-READTABLE* -SB-DEBUG::*CACHED-DEBUG-SOURCE* -SB-DEBUG::*POSSIBLE-BREAKPOINTS* -SB-DEBUG::*BAD-CODE-LOCATION-TYPES* -SB-DEBUG::*TRACED-ENTRIES* -SB-DEBUG::*DEBUG-COMMAND-LEVEL* -SB-DEBUG::*CACHED-SOURCE-STREAM* -SB-DEBUG::*DEBUG-LOOP-FUN* -SB-DEBUG::*NESTED-DEBUG-CONDITION* -SB-DEBUG::*STEP-BREAKPOINTS* -SB-DEBUG::*DEBUG-RESTARTS* -SB-DEBUG::*BREAKPOINTS* -SB-DEBUG::*TRACED-FUNS* -SB-DEBUG::*DEBUG-COMMANDS* -SB-DEBUG::*DEFAULT-BREAKPOINT-DEBUG-FUN* -SB-DEBUG::*CACHED-READTABLE* -SB-DEBUG::*IN-TRACE* -SB-DEBUG::*CACHED-TOPLEVEL-FORM-OFFSET* -SB-DEBUG::*STACK-TOP* -SB-DEBUG::*CURRENT-FRAME* -SB-DEBUG::*CACHED-TOPLEVEL-FORM* -SB-DEBUG::*NUMBER-OF-STEPS* -SB-DEBUG::*REAL-STACK-TOP* -SB-DI::*PARSING-BUFFER* -SB-DI::*IR1-BLOCK-DEBUG-BLOCK* -SB-DI::*OTHER-PARSING-BUFFER* -SB-DI::*COMPILED-DEBUG-FUNS* -SB-DI::*COMPONENT-BREAKPOINT-OFFSETS* -SB-DI::*FUN-END-COOKIES* -SB-DI::*FORM-NUMBER-CIRCULARITY-TABLE* -SB-DI::*EXECUTING-BREAKPOINT-HOOKS* -SB-DI::*IR1-LAMBDA-DEBUG-FUN* - -= profiler - -SB-PROFILE::*PROFILED-FUN-NAME->INFO* -SB-PROFILE::*ENCLOSED-CONSING* -SB-PROFILE::*COMPUTING-PROFILING-DATA-FOR* -SB-PROFILE::*ENCLOSED-PROFILES* -SB-PROFILE::*TIMER-OVERHEAD-ITERATIONS* -SB-PROFILE::*OVERHEAD* -SB-PROFILE::*ENCLOSED-TICKS* - -= disassembler - -SB-DISASSEM:*DISASSEM-INST-ALIGNMENT-BYTES* -SB-DISASSEM:*DISASSEM-NOTE-COLUMN* -SB-DISASSEM:*DEFAULT-DSTATE-HOOKS* -SB-DISASSEM:*DISASSEM-OPCODE-COLUMN-WIDTH* -SB-DISASSEM:*DISASSEM-SCHEDULER-P* -SB-DISASSEM:*DISASSEM-LOCATION-COLUMN-WIDTH* -SB-DISASSEM::*ARG-FUN-PARAMS* -SB-DISASSEM::*ADDRESS-OF-NIL-OBJECT* -SB-DISASSEM::*DISASSEM-INSTS* -SB-DISASSEM::*DISASSEM-FUN-CACHE* -SB-DISASSEM::*DISASSEM-INST-FORMATS* -SB-DISASSEM::*GROKKED-SYMBOL-SLOTS* -SB-DISASSEM::*ARG-FORM-KINDS* -SB-DISASSEM::*DISASSEM-INST-SPACE* -SB-DISASSEM::*CURRENT-INSTRUCTION-FLAVOR* -SB-DISASSEM::*DISASSEM-ARG-TYPES* -SB-DISASSEM::*ASSEMBLER-ROUTINES-BY-ADDR* - -= assembler - -Currently protected by *big-compiler-lock*. Mostly uninvestigated - -SB-ASSEM:*ASSEM-MAX-LOCATIONS* -SB-ASSEM:*ASSEM-INSTRUCTIONS* -SB-ASSEM:*ASSEM-SCHEDULER-P* -SB-ASSEM::*INSTRUCTION-ATTRIBUTE-TRANSLATIONS* -SB-ASSEM::**CURRENT-VOP** -SB-ASSEM::**CURRENT-SEGMENT** - - -= unix interface - -Looks good to me - -SB-UNIX::*INTERRUPTS-ENABLED* ; ok, bound -SB-UNIX::*UNIX-SIGNALS* ; ok, read-only -SB-UNIX::*INTERRUPT-PENDING* ; ok, bound - -= toplevel/environment stuff - -Some of these should probably be bound on thread entry. I haven't -checked them yet, except where indicated - -*DEBUG-IO* -SB-SYS:*TTY* -SB-SYS:*STDIN* -SB-SYS:*STDOUT* -SB-SYS:*STDERR* -SB-SYS:*LONG-SITE-NAME* ; readonly -SB-SYS:*SHORT-SITE-NAME* ; readonly -SB-SYS::*SOFTWARE-VERSION* ; readonly -SB-THREAD::*SESSION-LOCK* ; bound -SB-THREAD::*BACKGROUND-THREADS-WAIT-FOR-DEBUGGER* ; intentionally global -*** ; bound -** ; bound -* ; bound -*PRINT-PRETTY* -*LOAD-VERBOSE* -*LOAD-TRUENAME* -*READ-BASE* -*BREAK-ON-SIGNALS* -*PRINT-READABLY* -*PRINT-CIRCLE* -*FEATURES* ; write at own risk -*PRINT-BASE* -*PACKAGE* -*PRINT-RADIX* -*READ-SUPPRESS* -*ERROR-OUTPUT* -*DEFAULT-PATHNAME-DEFAULTS* -*LOAD-PATHNAME* -*STANDARD-OUTPUT* -*PRINT-RIGHT-MARGIN* -*READTABLE* -*PRINT-CASE* -*PRINT-MISER-WIDTH* -*PRINT-PPRINT-DISPATCH* -*PRINT-LENGTH* -*TERMINAL-IO* -*PRINT-GENSYM* -*QUERY-IO* -*STANDARD-INPUT* -*LOAD-PRINT* -*DEBUGGER-HOOK* -*PRINT-LINES* -*PRINT-ESCAPE* -*PRINT-LEVEL* -*READ-EVAL* -*PRINT-ESCAPE* -*TRACE-OUTPUT* -SB-IMPL::*INSPECT-LENGTH* -SB-IMPL::*DRIBBLE-STREAM* ; what to do with dribble in threaded lisp? -SB-IMPL::*HELP-FOR-INSPECT* ; read-only -*PRINT-ARRAY* - - - -*POSIX-ARGV* ; read-only -*READ-DEFAULT-FLOAT-FORMAT* ; probably "change at own risk" -*MODULES* ; should be changed only by provide/require, needs locking -*MODULE-PROVIDER-FUNCTIONS* ; probably "change at own risk" -SB-IMPL::*REPL-FUN* -SB-INT:*REPL-READ-FORM-FUN* -SB-INT:*REPL-PROMPT-FUN* - -= the formatter & pretty printer - -== probably safe (readonly unless indicated) - -(defvar *default-format-error-control-string* nil) -(defvar *default-format-error-offset* nil) -SB-FORMAT::*ILLEGAL-INSIDE-JUSTIFICATION* -SB-FORMAT::*OUTSIDE-ARGS* ; safe, bound - - -(defvar *up-up-and-out-allowed* nil) ; safe, bound -(defvar *logical-block-popper* nil) ; bound -(defvar *expander-next-arg-macro* 'expander-next-arg) ; bound -(defvar *orig-args-available* nil) ; bound - -== needs checking - -;;; Used by the expander stuff. Initially starts as T, and gets set to NIL -;;; if someone needs to do something strange with the arg list (like use -;;; the rest, or something). Setf in late-format, haven't checked if it's -;;; always in a bound context -(defvar *only-simple-args*) - -;;; setf in late-format, haven't checked -(defvar *simple-args*) - -== haven't looked at yet - -SB-PRETTY::*INITIAL-PPRINT-DISPATCH* -SB-PRETTY::*BUILDING-INITIAL-TABLE* -SB-PRETTY::*PRECOMPILED-PPRINT-DISPATCH-FUNS* - - -= compiler - -Note that the compiler and fasloader are strongly believed not to be -thread-safe, so there is currently a big lock (*big-compiler-lock*) -around all calls to the compiler or fasloader - -INFO functions are currently believed to be multi-writer/reader threadsafe, -though it's hard to know for sure since they were definitely read-safe, -and writes are done only while holding **WORLD-LOCK** as things stand. -The algorithms employed are used in at least one industrial-strength Lisp -application, though a bug has been reported (to me, dougk) regarding -the fasloader that might be related to INFO, or to the fasloader. -Catch 22: can't expose threading bugs until lock is removed - can't remove the lock until INFO is proven to be threadsafe. - -*COMPILE-FILE-PATHNAME* -*COMPILE-FILE-TRUENAME* -*COMPILE-PRINT* -*COMPILE-VERBOSE* -*COMPILE-PROGRESS* -SB-C:*BACKEND-INTERNAL-ERRORS* -SB-C:*BACKEND-SPECIAL-ARG-TYPES* -SB-C:*LEXENV* -SB-C:*CODE-SEGMENT* -SB-C:*COMPONENT-BEING-COMPILED* -SB-C:*BACKEND-SB-NAMES* -SB-C:*BACKEND-PAGE-SIZE* -SB-C:*BACKEND-SC-NUMBERS* -SB-C:*ELSEWHERE* -SB-C:*BACKEND-T-PRIMITIVE-TYPE* -SB-C:*BACKEND-SB-LIST* -SB-C:*BACKEND-SUBFEATURES* -SB-C:*COUNT-VOP-USAGES* -SB-C:*SUPPRESS-VALUES-DECLARATION* -SB-C:*BACKEND-SC-NAMES* -SB-C::*CURRENT-COMPONENT* -SB-C::*SLOT-INHERIT-ALIST* -SB-C::*COMPILER-NOTE-COUNT* -SB-C::*BACKEND-PREDICATE-TYPES* -SB-C::*POLICY* -SB-C::*INLINEP-TRANSLATIONS* -SB-C::*PACK-OPTIMIZE-SAVES* -SB-C::*DELETION-IGNORED-OBJECTS* -SB-C::*LAST-FORMAT-ARGS* -SB-C::*CONSTANTS-BEING-CREATED* -SB-C::*IGNORED-ERRORS* -SB-C::*COMPILE-OBJECT* -SB-C::*TN-IDS* -SB-C::*LOSSAGE-FUN* -SB-C::*COMPILER-ERROR-COUNT* -SB-C::*EVENT-NOTE-THRESHOLD* -SB-C::*LAST-MESSAGE-COUNT* -SB-C::*EMIT-ASSEMBLY-CODE-NOT-VOPS-P* -SB-C::*LAST-FORMAT-STRING* -SB-C::*UNWINNAGE-FUN* -SB-C::*COMPILER-ERROR-CONTEXT* -SB-C::*SEEN-BLOCKS* -SB-C::*TN-ID* -SB-C::*IR1-OPTIMIZE-UNTIL-DONE-EVENT-INFO* -SB-C::*SPECIALIZED-ARRAY-ELEMENT-TYPE-PROPERTIES* ; readonly -SB-C::*NUMBER-CONTINUATIONS* -SB-C::*CTYPE-TEST-FUN* -SB-C::*IGNORE-COST-VOPS* -SB-C::*QUEUED-PROCLAIMS* -SB-C::*COMPILER-STYLE-WARNING-COUNT* -SB-C::*LABEL-IDS* -SB-C::TN-NEXT* -SB-C::*COMPILED-CODE-LOCATION-KINDS* -SB-C::*VOP-TN-REFS* -SB-C::*FAILURE-P* -SB-C::*LAST-ORIGINAL-SOURCE* -SB-C::NEXT* -SB-C::LIST*-IR2-CONVERT-OPTIMIZER -SB-C::*COMPILER-ERROR-BAILOUT* -SB-C::*DELAYED-IR1-TRANSFORMS* -SB-C::*INFO-TYPES* ; readonly -SB-C::*CHECK-CONSISTENCY* -SB-C::*SEEN-FUNS* -SB-C::*USING-VOP-TN-REFS* -SB-C::*MAKE-VALUE-CELL-EVENT-EVENT-INFO* -SB-C::*IN-PACK* -SB-C::*REPACK-BLOCK-EVENT-INFO* -SB-C::*UNPACK-TN-EVENT-INFO* -SB-C::*COALESCE-MORE-LTN-NUMBERS-EVENT-INFO* -SB-C::*IN-COMPILATION-UNIT* -SB-C::*BACKEND-TEMPLATE-NAMES* -SB-C::*BACKEND-PRIMITIVE-TYPE-NAMES* -SB-C::*CONSTRAINT-PROPAGATE* -SB-C::*BACKEND-PRIMITIVE-TYPE-ALIASES* -SB-C::*NO-COSTS* -SB-C::*PACK-ASSIGN-COSTS* -SB-C::*CURRENT-FORM-NUMBER* -SB-C::*BLOCK-COMPILE-ARG* -SB-C::*COMPILER-ERROR-PRINT-LENGTH* -SB-C::*CONTINUATION-NUMBER* -SB-C::*PREV-SEGMENT* -SB-C::*CONTROL-DELETED-BLOCK-EVENT-INFO* -SB-C::*ALLOW-DEBUG-CATCH-TAG* -SB-C::*ID-LABELS* -SB-C::*BACKEND-TYPE-PREDICATES* -SB-C::*COMPILER-WARNING-COUNT* -SB-C::*SUPPRESS-NOTE-VOPS* -SB-C::*COMPILER-ERROR-PRINT-LEVEL* -SB-C::*COMPLEMENT-TYPE-CHECKS* -SB-C::*FUN-NAMES-IN-THIS-FILE* -SB-C::*SPLIT-IR2-BLOCK-EVENT-INFO* -SB-C::*TRACE-TABLE* -SB-C::*LAST-SOURCE-FORM* -SB-C::*WEAKEN-TYPE-CACHE-VECTOR* ; threadsafe -SB-C::*-DERIVE-TYPE-AUX -SB-C::*BLOCK-COMPILE* -SB-C::*BIG-COMPILER-LOCK* ; protecting the rest -SB-C::*PRIMITIVE-TYPE-SLOT-ALIST* -SB-C::*PREVIOUS-LOCATION* -SB-C::*BYTE-BUFFER* -SB-C::*CONSTANTS-CREATED-SINCE-LAST-INIT* -SB-C::*LAST-SOURCE-CONTEXT* -SB-C::*FIXUPS* -SB-C::VOP* -SB-C::*REOPTIMIZE-MAXED-OUT-EVENT-INFO* -SB-C::*LIST-CONFLICTS-TABLE* -SB-C::*LOSSAGE-DETECTED* -SB-C::*LAST-ERROR-CONTEXT* -SB-C::*PREV-VOP* -SB-C::*POLICY-DEPENDENT-QUALITIES* -SB-C::*REOPTIMIZE-AFTER-TYPE-CHECK-MAX* -SB-C::*-DERIVE-TYPE-OPTIMIZER -SB-C::*IR1-ATTRIBUTE-TRANSLATIONS* -SB-C::*DYNAMIC-COUNTS-TN* -SB-C::*EXTREME-NTHCDR-OPEN-CODE-LIMIT* -SB-C::*BACKEND-PARSED-VOPS* -SB-C::*ABORTED-COMPILATION-UNIT-COUNT* -SB-C::*COPY-DELETED-MOVE-EVENT-INFO* -SB-C::*MAX-OPTIMIZE-ITERATIONS* -SB-C::*TOPLEVEL-LAMBDAS* -SB-C::*SC-VOP-SLOTS* -SB-C::*IR1-OPTIMIZE-MAXED-OUT-EVENT-INFO* -SB-C::*CONTINUATION-NUMBERS* -SB-C::*WARNINGS-P* -SB-C::*FLAME-ON-NECESSARILY-UNDEFINED-FUNCTION* -SB-C::*UNPACK-FALLBACK-EVENT-INFO* -SB-C::*SOURCE-INFO* -SB-C::*LIVE-BLOCK* -SB-C::*NEXT-LOCATION* -SB-C::*ELSEWHERE-LABEL* -SB-C::*SOURCE-PATHS* -SB-C::*DEFAULT-NTHCDR-OPEN-CODE-LIMIT* -SB-C::*ALWAYS-OPTIMIZED-AWAY* -SB-C::*CURRENT-PATH* -SB-C::*LABEL-ID* -SB-C::*ENTRY-POINTS* -SB-C::*COMPILER-TRACE-OUTPUT* -SB-C::*CONSTRAINT-NUMBER* -SB-C::*RESULT-FIXUPS* -SB-C::*REPACK-BLOCKS* -SB-C::IR1-CONVERT-LET* -SB-C::*CODE-VECTOR* -SB-C::*SOURCE-CONTEXT-METHODS* -SB-C::*VOP-ATTRIBUTE-TRANSLATIONS* -SB-C::*COMPILER-ERROR-PRINT-LINES* -SB-C::*LIVE-VOP* -SB-C::*POLICY-QUALITIES* -SB-C::*NO-LOADS* -SB-C::*TRACE-TABLE-INFO* -SB-C::*UNDEFINED-WARNINGS* -SB-C::*BLOCK-ATTRIBUTE-TRANSLATIONS* -SB-C::*EVENT-INFO* -SB-C::*UNWINNAGE-DETECTED* -SB-C::*ID-TNS* - -= fasloader - -SB-FASL:*STATIC-FOREIGN-SYMBOLS* -SB-FASL:*ASSEMBLER-ROUTINES* -SB-FASL:*FASL-FILE-TYPE* -SB-FASL::FOP-LIST*-4 -SB-FASL::*COLD-LOAD-DUMP* -SB-FASL::FOP-LIST*-7 -SB-FASL::FOP-LIST*-8 -SB-FASL::FOP-LIST*-1 -SB-FASL::FOP-LIST*-2 -SB-FASL::*FASL-INPUT-STREAM* -SB-FASL::*FOP-STACK* -SB-FASL::*LOAD-DEPTH* -SB-FASL::*FEATURES-AFFECTING-FASL-FORMAT* -SB-FASL::*DUMP-ONLY-VALID-STRUCTURES* -SB-FASL::*CURRENT-FOP-TABLE-SIZE* -SB-FASL::*FOP-STACK-POINTER-ON-ENTRY* -SB-FASL::*FREE-FOP-TABLES* -SB-FASL::*LOAD-SYMBOL-BUFFER* -SB-FASL::*FASL-HEADER-STRING-START-STRING* -SB-FASL::DUMP-FOP* -SB-FASL::FOP-LIST* -SB-FASL::*CIRCULARITIES-DETECTED* -SB-FASL::*LOAD-CODE-VERBOSE* -SB-FASL::*FEATURES-POTENTIALLY-AFFECTING-FASL-FORMAT* -SB-FASL::*LOAD-SYMBOL-BUFFER-SIZE* -SB-FASL::*CURRENT-FOP-TABLE* -SB-FASL::*FOP-STACK-POINTER* -SB-FASL::*CURRENT-FOP-TABLE-INDEX* -SB-FASL::*FOP-FUNS* -SB-FASL::*CURRENT-UNWIND-PROTECT-BLOCK* -SB-FASL::FOP-LIST*-5 -SB-FASL::*FOP-NAMES* -SB-FASL::FOP-LIST*-6 -SB-FASL::FOP-LIST*-3 - - -= runtime stuff - - -SB-VM:*STATIC-SPACE-FREE-POINTER* -SB-VM:*INITIAL-DYNAMIC-SPACE-FREE-POINTER* -SB-VM:*CURRENT-CATCH-BLOCK* ; bound at thread entry (in C) -SB-VM:*STATIC-SYMBOLS* -SB-VM:*CONTROL-STACK-START* ; safe, bound at thread entry -SB-VM:*READ-ONLY-SPACE-FREE-POINTER* -SB-VM:*BINDING-STACK-START* ; safe, bound at thread entry -SB-VM:*CONTROL-STACK-END* ; safe, bound at thread entry -SB-VM::*CURRENT-UNWIND-PROTECT-BLOCK* ; bound at thread entry (in C) -SB-VM::*FREE-TLS-INDEX* -SB-VM::*BINDING-STACK-POINTER* -SB-VM::*ALLOCATION-POINTER* ; may be mostly unused ? -SB-KERNEL:*PSEUDO-ATOMIC-ATOMIC* ; bound -SB-KERNEL:*CONTROL-STACK-EXHAUSTION-SAP* -SB-KERNEL:*FREE-INTERRUPT-CONTEXT-INDEX* ; bound -SB-KERNEL:*GC-INHIBIT* ; do not touch directly. accessors may be broke too -SB-KERNEL:*NEED-TO-COLLECT-GARBAGE* -SB-KERNEL:*ALREADY-MAYBE-GCING* -SB-KERNEL:*PSEUDO-ATOMIC-INTERRUPTED* ; bound -SB-KERNEL::*GC-TRIGGER* ; I think this is dead, check -SB-IMPL::*CURRENT-UNWIND-PROTECT-BLOCK* ; thread-local -SB-IMPL::*READ-ONLY-SPACE-FREE-POINTER* -SB-VM::*ALIEN-STACK* ; bound in create_thread_struct() - -SB-IMPL::*OBJECTS-PENDING-FINALIZATION* ; needs locking for writers - -*AFTER-GC-HOOKS* ; must be global -*GC-RUN-TIME* -SB-INT:*N-BYTES-FREED-OR-PURIFIED* - -Note also the following may need attention -SB-PROFILE::TOTAL-CONSED -GET-BYTES-CONSED (fbound) -BYTES-CONSED-BETWEEN-GCS (fbound) - - -= backend constants - -These are believed to be constant (in the general sense, not necessarily -eligible for defconstant). Mostly they're attributes of the backend machine - - -SB-C:*BACKEND-REGISTER-SAVE-PENALTY* -SB-C:*BACKEND-BYTE-ORDER* -SB-VM:*PRIMITIVE-OBJECTS* -SB-VM:*ASSEMBLY-UNIT-LENGTH* -SB-VM::*FP-CONSTANT-L2E* -SB-VM::*FLOAT-REGISTER-NAMES* -SB-VM::*FP-CONSTANT-1L0* -SB-VM::*BYTE-REGISTER-NAMES* -SB-VM::*DWORD-SC-NAMES* -SB-VM::*FP-CONSTANT-1F0* -SB-VM::*WORD-REGS* -SB-VM::*BYTE-SC-NAMES* -SB-VM::*DEFAULT-ADDRESS-SIZE* -SB-VM::*FP-CONSTANT-0D0* -SB-VM::*FP-CONSTANT-LG2* -SB-VM::*FP-CONSTANT-L2T* -SB-VM::*DWORD-REGS* -SB-VM::*WORD-REGISTER-NAMES* -SB-VM::*FP-CONSTANT-0F0* -SB-VM::*FLOAT-SC-NAMES* -SB-VM::*FLOAT-REGS* -SB-VM::*DWORD-REGISTER-NAMES* -SB-VM::*WORD-SC-NAMES* -SB-VM::*FP-CONSTANT-PI* -SB-VM::*BYTE-REGS* -SB-VM::*FP-CONSTANT-1D0* -SB-VM::*DOUBLE-SC-NAMES* -SB-VM::*FP-CONSTANT-0L0* -SB-VM::*REGISTER-ARG-OFFSETS* -SB-VM::*FLOAT-TRAP-ALIST* -SB-VM::*DWORD-REG-NAMES* -SB-VM::*BYTE-REG-NAMES* -SB-VM::*ROUNDING-MODE-ALIST* -SB-VM::*REGISTER-ARG-NAMES* -SB-VM::*FIXNUM-PRIMITIVE-TYPE* -SB-VM:*STATIC-FUNS* -SB-VM::*FP-CONSTANT-LN2* -SB-VM::*WORD-REG-NAMES* -SB-KERNEL::*BUILT-IN-CLASSES* - -= dead stuff - ------------------------------------------------------------------------- - -= unclassified - -SB-ALIEN-INTERNALS:*VALUES-TYPE-OKAY* -SB-ALIEN::ALIEN-*-TYPE-TRANSLATOR -SB-ALIEN::*DSO-LINKER* -SB-ALIEN::*HANDLES-FROM-DLOPEN* -SB-ALIEN::*ALIEN-TYPE-CLASSES* -SB-ALIEN::*RECORD-TYPES-ALREADY-UNPARSED* -SB-ALIEN::*NEW-AUXILIARY-TYPES* -SB-ALIEN::*DSO-LINKER-OPTIONS* -SB-ALIEN::*METHOD-SLOT-ALIST* - -SB-VM::*SIGNED-IMM-BYTE-PREFILTER-WRAPPER* -SB-VM::*DISPLACEMENT-PRINTER-WRAPPER* -SB-VM::*ACCUM-PRINTER-WRAPPER* -SB-VM::*WIDTH-PRINTER-WRAPPER* -SB-VM::*LABEL-1-PREFILTER-WRAPPER* -SB-VM::*WORD-ACCUM-PRINTER-WRAPPER* -SB-VM::*NUM-FIXUPS* -SB-VM::*SIGNED-IMM-DATA-PREFILTER-WRAPPER* -SB-VM::*FIXNUM-PRIMITIVE-TYPE* -SB-VM::*CONDITIONS* -SB-VM::*IGNORE-AFTER* -SB-VM::*IMM-WORD-PREFILTER-WRAPPER* -SB-VM::*REGISTER-ARG-TNS* -SB-VM::*IMM-DATA-PREFILTER-WRAPPER* -SB-VM::*PRIMITIVE-TYPE-AUX-CACHE-VECTOR* ; threadsafe -SB-VM::*LABEL-2-PREFILTER-WRAPPER* -SB-VM::*ROOM-INFO* -SB-VM::*ADJUSTABLE-VECTORS* ; under **WORLD-LOCK** - should be done better -SB-VM::*CONDITION-NAME-VEC* -SB-VM::*IMM-WORD-16-PREFILTER-WRAPPER* -SB-VM::*SIMPLE-ARRAY-PRIMITIVE-TYPES* -SB-VM::*MAYBE-USE-INLINE-ALLOCATION* -SB-VM::*SIGNED-IMM-DWORD-PREFILTER-WRAPPER* -SB-VM::*IMMEDIATE-TYPES* - -SB-KERNEL:*WILD-TYPE* ; readonly -SB-KERNEL:*UNPARSE-FUN-TYPE-SIMPLIFY* -SB-KERNEL:*CURRENT-LEVEL-IN-PRINT* -SB-KERNEL:*UNIVERSAL-FUN-TYPE* -SB-KERNEL:*UNIVERSAL-TYPE* ; readonly -SB-KERNEL:*HANDLER-CLUSTERS* ; bound per-thread -SB-KERNEL:*EMPTY-TYPE* ; readonly -SB-KERNEL:*MAXIMUM-ERROR-DEPTH* -SB-KERNEL:*CONDITION-RESTARTS* ; bound per-thread -SB-KERNEL:*TYPE-SYSTEM-INITIALIZED* -SB-KERNEL:*RESTART-CLUSTERS* ; bound per-thread -SB-KERNEL::*MAKE-VALUES-TYPE-CACHED-CACHE-VECTOR* ; threadsafe -SB-KERNEL::*BUILT-IN-CLASS-CODES* ; readonly -SB-KERNEL::*DEF!STRUCT-TYPE-MAKE-LOAD-FORM-FUN* -SB-KERNEL::*LAYOUT-CLOS-HASH-RANDOM-STATE* -SB-KERNEL::*TYPE-TEST-ORDERING* -SB-KERNEL::*COMMON-TYPESPECS* -SB-KERNEL::*TYPE=-CACHE-VECTOR* ; threadsafe -SB-KERNEL::*VALUES-SUBTYPEP-CACHE-VECTOR* ; threadsafe -SB-KERNEL::*TYPECHECKFUNS* -SB-KERNEL::*%TYPE-INTERSECTION-CACHE-VECTOR* ; threadsafe -SB-KERNEL::*TYPE-INTERSECTION2-CACHE-VECTOR* ; threadsafe -SB-KERNEL::*COLD-INIT-FORMS* -SB-KERNEL::*DEFAULT-DEFAULT* -SB-KERNEL::*RAW-SLOT-DATA-LIST* -SB-KERNEL::*SPECIALIZED-ARRAY-ELEMENT-TYPES* ; readonly -SB-KERNEL::*DEFSTRUCT-HOOKS* -SB-KERNEL::*VALUES-TYPE-UNION-CACHE-VECTOR* ; threadsafe -SB-KERNEL::*INTERNAL-ERRORS* -SB-KERNEL::*VALUES-TYPE-INTERSECTION-CACHE-VECTOR* ; threadsafe -SB-KERNEL::*FORWARD-REFERENCED-LAYOUTS* -SB-KERNEL::*SYSTEM-LETS* ; bound -SB-KERNEL::*%COERCE-TO-VALUES-CACHE-VECTOR* ; threadsafe -SB-KERNEL::*IGNORABLE-VARS* -SB-KERNEL::*ENV-VAR* ; bound -SB-KERNEL::|*%%MAKE-UNION-TYPE-cached-CACHE-VECTOR*| ; threadsafe -SB-KERNEL::*CSUBTYPEP-CACHE-VECTOR* ; threadsafe -SB-KERNEL::*EMPTY-CONDITION-SLOT* -SB-KERNEL::*TYPE-UNION2-CACHE-VECTOR* ; threadsafe -SB-KERNEL::*TYPE-CLASS-FUN-SLOTS* -SB-KERNEL::*ARG-TESTS* ; bound -SB-KERNEL::*USER-LETS* ; bound -SB-KERNEL::|*%%MAKE-ARRAY-TYPE-cached-CACHE-VECTOR*| ; threadsafe -SB-KERNEL::*FINDING-NAME* -SB-KERNEL::*TYPE-CLASSES* -SB-KERNEL::*VALUES-SPECIFIER-TYPE-CACHE-VECTOR* ; threadsafe -SB-KERNEL::*FLOAT-FORMATS* ; readonly -SB-KERNEL::*INTERNAL-ERROR-ARGS* -SB-KERNEL::*DEF!STRUCT-SUPERTYPE* -SB-KERNEL::*%TYPE-UNION-CACHE-VECTOR* ; threadsafe -SB-KERNEL::*CTYPE-OF-CACHE-VECTOR* ; threadsafe - -SB-IMPL::*READ-BUFFER* ; safe when used via WITH-READ-BUFFER -SB-IMPL::*SECONDARY-ATTRIBUTE-TABLE* ; now *CONSTITUENT-TRAIT-TABLE*, constant -SB-IMPL::*STANDARD-READTABLE* -SB-IMPL::*ERROR-ERROR-DEPTH* -SB-IMPL::*CURRENT-ERROR-DEPTH* -SB-IMPL::*INTERNAL-REAL-TIME-BASE-SECONDS* -SB-IMPL::*OFFENDING-DATUM* -SB-IMPL::*HANDLERS-INSTALLED* -SB-IMPL::*HASH-TABLE-TESTS* -SB-IMPL::*ATTRIBUTE-NAMES* -SB-IMPL::*CHARACTER-ATTRIBUTES* -SB-IMPL::*UNIX-HOST* -SB-IMPL::*DESCRIPTOR-HANDLERS* -SB-IMPL::*STRING-OUTPUT-STREAMS* -SB-IMPL::*CLOSE-ON-ERROR* -SB-IMPL::*BQ-COMMA-FLAG* ; readonly -SB-IMPL::*PROFILE-HASH-CACHE* ; not threadsafe, but don't care- debug only -SB-IMPL::*FIXNUM-POWER--1* -SB-IMPL::*SHARP-EQUAL-CIRCLE-TABLE* -SB-IMPL::*SOFTWARE-INTERRUPT-VECTOR* ; suspect unused -SB-IMPL::*INSPECT-UNBOUND-OBJECT-MARKER* -SB-IMPL::*IN-PACKAGE-INIT* -SB-IMPL::*DELAYED-DEF!METHOD-ARGS* -SB-IMPL::*GENTEMP-COUNTER* -SB-IMPL::*CLOSE-IN-PARENT* -SB-IMPL::*IN-COMPILATION-UNIT* -SB-IMPL::*CIRCULARITY-HASH-TABLE* -SB-IMPL::*LOAD-PRINT-STUFF* -SB-IMPL::*ACTIVE-PROCESSES* -SB-IMPL::*SHARP-SHARP-ALIST* -SB-IMPL::*LOGICAL-PATHNAME-DEFAULTS* -SB-IMPL::*AVAILABLE-BUFFERS* -SB-IMPL::*BQ-DOT-FLAG* ; readonly -SB-IMPL::*CIRCULARITY-COUNTER* -SB-IMPL::*DIGITS* -SB-IMPL::*BQ-VECTOR-FLAG* ; readonly -SB-IMPL::*LOGICAL-HOSTS* -SB-IMPL::*PACKAGE-NAMES* -SB-IMPL::*INSPECT-FUN* -SB-IMPL::*OUTPUT-ROUTINES* -SB-IMPL::*CHAR-NAME-ALIST* -SB-IMPL::*VALID-FUN-NAMES-ALIST* -SB-IMPL::*PERIODIC-POLLING-FUNCTION* -SB-IMPL::*ABORTED-COMPILATION-UNIT-COUNT* -SB-IMPL::*INTERNAL-SYMBOL-OUTPUT-FUN* ; FIXME: printer not threadsafe -SB-IMPL::*BACKQUOTE-COUNT* ; bound -SB-IMPL::*DIGIT-BASES* -SB-IMPL::*PREVIOUS-DRIBBLE-STREAMS* -SB-IMPL::*MAX-EVENT-TO-USEC* -SB-IMPL::*INPUT-ROUTINES* -SB-IMPL::*MAX-EVENT-TO-SEC* -SB-IMPL::*OLD-PACKAGE* -SB-IMPL::*ERROR-THROW-UP-COUNT* -SB-IMPL::*BQ-AT-FLAG* ; readonly -SB-IMPL::*MACHINE-VERSION* ; unset/unbound ? are we using this? -SB-IMPL::*IGNORE-WILDCARDS* -SB-IMPL::*SHARP-EQUAL-ALIST* - -*INLINE-EXPANSION-LIMIT* -*DERIVE-FUNCTION-TYPES* -*ENCLOSING-SOURCE-CUTOFF* -*INSPECTED* -*UNDEFINED-WARNING-LIMIT* -*EFFICIENCY-NOTE-COST-THRESHOLD* -*EFFICIENCY-NOTE-LIMIT* -*USE-IMPLEMENTATION-TYPES* -*INTEXP-MAXIMUM-EXPONENT* -*GENSYM-COUNTER* -*MACROEXPAND-HOOK* -*RANDOM-STATE* - -SB-INT:*CL-PACKAGE* ; readonly -SB-INT:*KEYWORD-PACKAGE* ; readonly -SB-INT:*SETF-FDEFINITION-HOOK* -SB-INT:*DEFAULT-INIT-CHAR-FORM* -SB-INT:*EOF-OBJECT* ; readonly -SB-INT:*AFTER-SAVE-INITIALIZATIONS* -SB-INT:*LOAD-SOURCE-DEFAULT-TYPE* -SB-INT:*BEFORE-SAVE-INITIALIZATIONS* -SB-INT:*INFO-ENVIRONMENT* ; threadsafe diff --git a/doc/internals-notes/zero-with-mmap-bug.txt b/doc/internals-notes/zero-with-mmap-bug.txt new file mode 100644 index 0000000000..321665dc43 --- /dev/null +++ b/doc/internals-notes/zero-with-mmap-bug.txt @@ -0,0 +1,48 @@ +zero_range_with_mmap is not threadsafe if using unmap/remap +----------------------------------------------------------- + +Consider a case where SBCL is not able to get its default heap address +of 0x1000000000 (x86-64 linux) +Instead it gets something way up high where there are all sorts of other +memory mappings (from malloc and shared libraries, etc). + +At the time of failure, the lisp heap was "almost" covered by 6 lines +from /proc/self/maps which we output to stderr in os_alloc_gc_space on failure. +(Excerpt below) +In this lisp process, unmap/remap had already happened several times +as evident from the multiple lines. The kernel hadn't re-combined those +distinct ranges yet. It may do so at its leisure. + + ... many other mappings + range 7F3D0851F000 7F3D08520000 rwxp size 1000 + range 7F3D08520000 7F3D09918000 rwxp size 13F8000 + range 7F3D09930000 7F3D09938000 rwxp size 8000 + range 7F3D09938000 7F3D09948000 rwxp size 10000 + range 7F3D09948000 7F3D15710000 rwxp size BDC8000 + range 7F3D15710000 7F410851F000 rwxp size 3F2E0F000 + ... many other mappings + +Our lisp heap size is exactly (- #x7F410851F000 #x7F3D0851F000) +which is 16 GiB. + +So unfortunately we then saw a failure +"mmap: wanted 98304 bytes at 0x7f3d09918000, actually mapped at 0x7f3d044da000" +which precisely corresponds to the missing range between the second +and third line of the fragment above. +(98304 = 3 x sb-vm:gencgc-page-bytes) + +In light of the postmortem dump of /proc/self/maps not being an atomic snapshot, +one of two things must have happened: +- the kernel randomly decided to be adversarial and not give back + an address that was just a moment ago unmapped by this thread +- some other thread intruded between os_deallocate() and os_alloc_gc_space(). + +As a matter of fact there were about 20 non-lisp threads in the lisp process +which did not participate in the stop-for-GC protocol. +Any of them could have gotten this memory at just the right moment to interfere +with the unmap+remap technique. + +The fix is actually easy for linux - if MADV_DONTNEED is inapplicable, +then use memset. Since that case is not expected to occur often +(an entire page of file-backed data should not often become dead) +this does not add additional overhead except after running a fullcgc. diff --git a/doc/internals/cmu/.cvsignore b/doc/internals/cmu/.cvsignore new file mode 100644 index 0000000000..7bbca4b4a0 --- /dev/null +++ b/doc/internals/cmu/.cvsignore @@ -0,0 +1,11 @@ +architecture.aux +compiler.aux +design.aux +design.dvi +design.log +design.out +design.pdf +design.toc +glossary.aux +retargeting.aux +run-time.aux diff --git a/doc/internals/cmu/back.tex b/doc/internals/cmu/back.tex new file mode 100644 index 0000000000..d63f02bf49 --- /dev/null +++ b/doc/internals/cmu/back.tex @@ -0,0 +1,728 @@ +% -*- Dictionary: design -*- + +\chapter{Copy propagation} + +File: {\tt copyprop} + +This phase is optional, but should be done whenever speed or space is more +important than compile speed. We use global flow analysis to find the reaching +definitions for each TN. This information is used here to eliminate +unnecessary TNs, and is also used later on by loop invariant optimization. + +In some cases, VMR conversion will unnecessarily copy the value of a TN into +another TN, since it may not be able to tell that the initial TN has the same +value at the time the second TN is referenced. This can happen when ICR +optimize is unable to eliminate a trivial variable binding, or when the user +does a setq, or may also result from creation of expression evaluation +temporaries during VMR conversion. Whatever the cause, we would like to avoid +the unnecessary creation and assignment of these TNs. + +What we do is replace TN references whose only reaching definition is a Move +VOP with a reference to the TN moved from, and then delete the Move VOP if the +copy TN has no remaining references. There are several restrictions on copy +propagation: +\begin{itemize} +\item The TNs must be ``ordinary'' TNs, not restricted or otherwise +unusual. Extending the life of restricted (or wired) TNs can make register +allocation impossible. Some other TN kinds have hidden references. + +\item We don't want to defeat source-level debugging by replacing named +variables with anonymous temporaries. + +\item We can't delete moves that representation selected might want to change +into a representation conversion, since we need the primitive types of both TNs +to select a conversion. +\end{itemize} + +Some cleverness reduces the cost of flow analysis. As for lifetime analysis, +we only need to do flow analysis on global packed TNs. We can't do the real +local TN assignment pass before this, since we allocate TNs afterward, so we do +a pre-pass that marks the TNs that are local for our purposes. We don't care +if block splitting eventually causes some of them to be considered global. + +Note also that we are really only interested in knowing if there is a +unique reaching definition, which we can mash into our flow analysis rules by +doing an intersection. Then a definition only appears in the set when it is +unique. We then propagate only definitions of TNs with only one write, which +allows the TN to stand for the definition. + + +\chapter{Representation selection} + +File: {\tt represent} + +Some types of object (such as {\tt single-float}) have multiple possible +representations. Multiple representations are useful mainly when there is a +particularly efficient non-descriptor representation. In this case, there is +the normal descriptor representation, and an alternate non-descriptor +representation. + +This possibility brings up two major issues: +\begin{itemize} +\item The compiler must decide which representation will be most efficient for +any given value, and + +\item Representation conversion code must be inserted where the representation +of a value is changed. +\end{itemize} +First, the representations for TNs are selected by examining all the TN +references and attempting to minimize reference costs. Then representation +conversion code is introduced. + +This phase is in effect a pre-pass to register allocation. The main reason for +its existence is that representation conversions may be farily complex (e.g. +involving memory allocation), and thus must be discovered before register +allocation. + + +VMR conversion leaves stubs for representation specific move operations. +Representation selection recognizes {\tt move} by name. Argument and return +value passing for call VOPs is controlled by the {\tt :move-arguments} option +to {\tt define-vop}. + +Representation selection is also responsible for determining what functions use +the number stack. If any representation is chosen which could involve packing +into the {\tt non-descriptor-stack} SB, then we allocate the NFP register +throughout the component. As an optimization, permit the decision of whether a +number stack frame needs to be allocated to be made on a per-function basis. +If a function doesn't use the number stack, and isn't in the same tail-set as +any function that uses the number stack, then it doesn't need a number stack +frame, even if other functions in the component do. + + +\chapter{Lifetime analysis} + +File: {\tt life} + +This phase is a preliminary to Pack. It involves three passes: + -- A pre-pass that computes the DEF and USE sets for live TN analysis, while + also assigning local TN numbers, splitting blocks if necessary. \#\#\# But +not really... + -- A flow analysis pass that does backward flow analysis on the + component to find the live TNs at each block boundary. + -- A post-pass that finds the conflict set for each TN. + +\#| +Exploit the fact that a single VOP can only exhaust LTN numbers when there are +large more operands. Since more operand reference cannot be interleaved with +temporary reference, the references all effectively occur at the same time. +This means that we can assign all the more args and all the more results the +same LTN number and the same lifetime info. +|\# + + +\section{Flow analysis} + +It seems we could use the global-conflicts structures during compute the +inter-block lifetime information. The pre-pass creates all the +global-conflicts for blocks that global TNs are referenced in. The flow +analysis pass just adds always-live global-conflicts for the other blocks the +TNs are live in. In addition to possibly being more efficient than SSets, this +would directly result in the desired global-conflicts information, rather than +having to create it from another representation. + +The DFO sorted per-TN global-conflicts thread suggests some kind of algorithm +based on the manipulation of the sets of blocks each TN is live in (which is +what we really want), rather than the set of TNs live in each block. + +If we sorted the per-TN global-conflicts in reverse DFO (which is just as good +for determining conflicts between TNs), then it seems we could scan though the +conflicts simultaneously with our flow-analysis scan through the blocks. + +The flow analysis step is the following: + If a TN is always-live or read-before-written in a successor block, then we + make it always-live in the current block unless there are already + global-conflicts recorded for that TN in this block. + +The iteration terminates when we don't add any new global-conflicts during a +pass. + +We may also want to promote TNs only read within a block to always-live when +the TN is live in a successor. This should be easy enough as long as the +global-conflicts structure contains this kind of info. + +The critical operation here is determining whether a given global TN has global +conflicts in a given block. Note that since we scan the blocks in DFO, and the +global-conflicts are sorted in DFO, if we give each global TN a pointer to the +global-conflicts for the last block we checked the TN was in, then we can +guarantee that the global-conflicts we are looking for are always at or after +that pointer. If we need to insert a new structure, then the pointer will help +us rapidly find the place to do the insertion.] + + +\section{Conflict detection} + +[\#\#\# Environment, :more TNs.] + +This phase makes use of the results of lifetime analysis to find the set of TNs +that have lifetimes overlapping with those of each TN. We also annotate call +VOPs with information about the live TNs so that code generation knows which +registers need to be saved. + +The basic action is a backward scan of each block, looking at each TN-Ref and +maintaining a set of the currently live TNs. When we see a read, we check if +the TN is in the live set. If not, we: + -- Add the TN to the conflict set for every currently live TN, + -- Union the set of currently live TNs with the conflict set for the TN, and + -- Add the TN to the set of live TNs. + +When we see a write for a live TN, we just remove it from the live set. If we +see a write to a dead TN, then we update the conflicts sets as for a read, but +don't add the TN to the live set. We have to do this so that the bogus write +doesn't clobber anything. + +[We don't consider always-live TNs at all in this process, since the conflict +of always-live TNs with other TNs in the block is implicit in the +global-conflicts structures. + +Before we do the scan on a block, we go through the global-conflicts structures +of TNs that change liveness in the block, assigning the recorded LTN number to +the TN's LTN number for the duration of processing of that block.] + + +Efficiently computing and representing this information calls for some +cleverness. It would be prohibitively expensive to represent the full conflict +set for every TN with sparse sets, as is done at the block-level. Although it +wouldn't cause non-linear behavior, it would require a complex linked structure +containing tens of elements to be created for every TN. Fortunately we can +improve on this if we take into account the fact that most TNs are ``local'' TNs: +TNs which have all their uses in one block. + +First, many global TNs will be either live or dead for the entire duration of a +given block. We can represent the conflict between global TNs live throughout +the block and TNs local to the block by storing the set of always-live global +TNs in the block. This reduces the number of global TNs that must be +represented in the conflicts for local TNs. + +Second, we can represent conflicts within a block using bit-vectors. Each TN +that changes liveness within a block is assigned a local TN number. Local +conflicts are represented using a fixed-size bit-vector of 64 elements or so +which has a 1 for the local TN number of every TN live at that time. The block +has a simple-vector which maps from local TN numbers to TNs. Fixed-size +vectors reduce the hassle of doing allocations and allow operations to be +open-coded in a maximally tense fashion. + +We can represent the conflicts for a local TN by a single bit-vector indexed by +the local TN numbers for that block, but in the global TN case, we need to be +able to represent conflicts with arbitrary TNs. We could use a list-like +sparse set representation, but then we would have to either special-case global +TNs by using the sparse representation within the block, or convert the local +conflicts bit-vector to the sparse representation at the block end. Instead, +we give each global TN a list of the local conflicts bit-vectors for each block +that the TN is live in. If the TN is always-live in a block, then we record +that fact instead. This gives us a major reduction in the amount of work we +have to do in lifetime analysis at the cost of some increase in the time to +iterate over the set during Pack. + +Since we build the lists of local conflict vectors a block at a time, the +blocks in the lists for each TN will be sorted by the block number. The +structure also contains the local TN number for the TN in that block. These +features allow pack to efficiently determine whether two arbitrary TNs +conflict. You just scan the lists in order, skipping blocks that are in only +one list by using the block numbers. When we find a block that both TNs are +live in, we just check the local TN number of one TN in the local conflicts +vector of the other. + +In order to do these optimizations, we must do a pre-pass that finds the +always-live TNs and breaks blocks up into small enough pieces so that we don't +run out of local TN numbers. If we can make a block arbitrarily small, then we +can guarantee that an arbitrarily small number of TNs change liveness within +the block. We must be prepared to make the arguments to unbounded arg count +VOPs (such as function call) always-live even when they really aren't. This is +enabled by a panic mode in the block splitter: if we discover that the block +only contains one VOP and there are still too many TNs that aren't always-live, +then we promote the arguments (which we'd better be able to do...). + +This is done during the pre-scan in lifetime analysis. We can do this because +all TNs that change liveness within a block can be found by examining that +block: the flow analysis only adds always-live TNs. + + +When we are doing the conflict detection pass, we set the LTN number of global +TNs. We can easily detect global TNs that have not been locally mapped because +this slot is initially null for global TNs and we null it out after processing +each block. We assign all Always-Live TNs to the same local number so that we +don't need to treat references to them specially when making the scan. + +We also annotate call VOPs that do register saving with the TNs that are live +during the call, and thus would need to be saved if they are packed in +registers. + +We adjust the costs for TNs that need to be saved so that TNs costing more to +save and restore than to reference get packed on the stack. We would also like +more often saved TNs to get higher costs so that they are packed in more +savable locations. + + +\chapter{Packing} + +File: {\tt pack} + +\#| + +Add lifetime/pack support for pre-packed save TNs. + +Fix GTN/VMR conversion to use pre-packed save TNs for old-cont and return-PC. +(Will prevent preference from passing location to save location from ever being +honored?) + +We will need to make packing of passing locations smarter before we will be +able to target the passing location on the stack in a tail call (when that is +where the callee wants it.) Currently, we will almost always pack the passing +location in a register without considering whether that is really a good idea. +Maybe we should consider schemes that explicitly understand the parallel +assignment semantics, and try to do the assignment with a minimum number of +temporaries. We only need assignment temps for TNs that appear both as an +actual argument value and as a formal parameter of the called function. This +only happens in self-recursive functions. + +Could be a problem with lifetime analysis, though. The write by a move-arg VOP +would look like a write in the current env, when it really isn't. If this is a +problem, then we might want to make the result TN be an info arg rather than a +real operand. But this would only be a problem in recursive calls, anyway. +[This would prevent targeting, but targeting across passing locations rarely +seems to work anyway.] [\#\#\# But the :ENVIRONMENT TN mechanism would get +confused. Maybe put env explicitly in TN, and have it only always-live in that +env, and normal in other envs (or blocks it is written in.) This would allow +targeting into environment TNs. + +I guess we would also want the env/PC save TNs normal in the return block so +that we can target them. We could do this by considering env TNs normal in +read blocks with no successors. + +ENV TNs would be treated totally normally in non-env blocks, so we don't have +to worry about lifetime analysis getting confused by variable initializations. +Do some kind of TN costing to determine when it is more trouble than it is +worth to allocate TNs in registers. + +Change pack ordering to be less pessimal. Pack TNs as they are seen in the LTN +map in DFO, which at least in non-block compilations has an effect something +like packing main trace TNs first, since control analysis tries to put the good +code first. This could also reduce spilling, since it makes it less likely we +will clog all registers with global TNs. + +If we pack a TN with a specified save location on the stack, pack in the +specified location. + +Allow old-cont and return-pc to be kept in registers by adding a new ``keep +around'' kind of TN. These are kind of like environment live, but are only +always-live in blocks that they weren't referenced in. Lifetime analysis does +a post-pass adding always-live conflicts for each ``keep around'' TN to those +blocks with no conflict for that TN. The distinction between always-live and +keep-around allows us to successfully target old-cont and return-pc to passing +locations. MAKE-KEEP-AROUND-TN (ptype), PRE-PACK-SAVE-TN (tn scn offset). +Environment needs a KEEP-AROUND-TNS slot so that conflict analysis can find +them (no special casing is needed after then, they can be made with :NORMAL +kind). VMR-component needs PRE-PACKED-SAVE-TNS so that conflict analysis or +somebody can copy conflict info from the saved TN. + + + +Note that having block granularity in the conflict information doesn't mean +that a localized packing scheme would have to do all moves at block boundaries +(which would clash with the desire to have saving done as part of this +mechanism.) All that it means is that if we want to do a move within the +block, we would need to allocate both locations throughout that block (or +something). + + + + + +Load TN pack: + +A location is out for load TN packing if: + +The location has TN live in it after the VOP for a result, or before the VOP +for an argument, or + +The location is used earlier in the TN-ref list (after) the saved results ref +or later in the TN-Ref list (before) the loaded argument's ref. + +To pack load TNs, we advance the live-tns to the interesting VOP, then +repeatedly scan the vop-refs to find vop-local conflicts for each needed load +TN. We insert move VOPs and change over the TN-Ref-TNs as we go so the TN-Refs +will reflect conflicts with already packed load-TNs. + +If we fail to pack a load-TN in the desired SC, then we scan the Live-TNs for +the SB, looking for a TN that can be packed in an unbounded SB. This TN must +then be repacked in the unbounded SB. It is important the load-TNs are never +packed in unbounded SBs, since that would invalidate the conflicts info, +preventing us from repacking TNs in unbounded SBs. We can't repack in a finite +SB, since there might have been load TNs packed in that SB which aren't +represented in the original conflict structures. + +Is it permissible to ``restrict'' an operand to an unbounded SC? Not impossible +to satisfy as long as a finite SC is also allowed. But in practice, no +restriction would probably be as good. + +We assume all locations can be used when an sc is based on an unbounded sb. + +] + + +TN-Refs are convenient structures to build the target graph out of. If we +allocated space in every TN-Ref, then there would certainly be enough to +represent arbitrary target graphs. Would it be enough to allocate a single +Target slot? If there is a target path through a given VOP, then the Target of +the write ref would be the read, and vice-versa. To find all the TNs that +target us, we look at the TN for the target of all our write refs. + +We separately chain together the read refs and the write refs for a TN, +allowing easy determination of things such as whether a TN has only a single +definition or has no reads. It would also allow easier traversal of the target +graph. + +Represent per-location conflicts as vectors indexed by block number of +per-block conflict info. To test whether a TN conflicts on a location, we +would then have to iterate over the TNs global-conflicts, using the block +number and LTN number to check for a conflict in that block. But since most +TNs are local, this test actually isn't much more expensive than indexing into +a bit-vector by GTN numbers. + +The big win of this scheme is that it is much cheaper to add conflicts into the +conflict set for a location, since we never need to actually compute the +conflict set in a list-like representation (which requires iterating over the +LTN conflicts vectors and unioning in the always-live TNs). Instead, we just +iterate over the global-conflicts for the TN, using BIT-IOR to combine the +conflict set with the bit-vector for that block in that location, or marking +that block/location combination as being always-live if the conflict is +always-live. + +Generating the conflict set is inherently more costly, since although we +believe the conflict set size to be roughly constant, it can easily contain +tens of elements. We would have to generate these moderately large lists for +all TNs, including local TNs. In contrast, the proposed scheme does work +proportional to the number of blocks the TN is live in, which is small on +average (1 for local TNs). This win exists independently from the win of not +having to iterate over LTN conflict vectors. + + +[\#\#\# Note that since we never do bitwise iteration over the LTN conflict +vectors, part of the motivation for keeping these a small fixed size has been +removed. But it would still be useful to keep the size fixed so that we can +easily recycle the bit-vectors, and so that we could potentially have maximally +tense special primitives for doing clear and bit-ior on these vectors.] + +This scheme is somewhat more space-intensive than having a per-location +bit-vector. Each vector entry would be something like 150 bits rather than one +bit, but this is mitigated by the number of blocks being 5-10x smaller than the +number of TNs. This seems like an acceptable overhead, a small fraction of the +total VMR representation. + +The space overhead could also be reduced by using something equivalent to a +two-dimensional bit array, indexed first by LTN numbers, and then block numbers +(instead of using a simple-vector of separate bit-vectors.) This would +eliminate space wastage due to bit-vector overheads, which might be 50% or +more, and would also make efficient zeroing of the vectors more +straightforward. We would then want efficient operations for OR'ing LTN +conflict vectors with rows in the array. + +This representation also opens a whole new range of allocation algorithms: ones +that store allocate TNs in different locations within different portions of the +program. This is because we can now represent a location being used to hold a +certain TN within an arbitrary subset of the blocks the TN is referenced in. + + + + + + + + + +Pack goals: + +Pack should: + +Subject to resource constraints: + -- Minimize use costs + -- ``Register allocation'' + Allocate as many values as possible in scarce ``good'' locations, + attempting to minimize the aggregate use cost for the entire program. + -- ``Save optimization'' + Don't allocate values in registers when the save/restore costs exceed + the expected gain for keeping the value in a register. (Similar to + ``opening costs'' in RAOC.) [Really just a case of representation + selection.] + + -- Minimize preference costs + Eliminate as many moves as possible. + + +``Register allocation'' is basically an attempt to eliminate moves between +registers and memory. ``Save optimization'' counterbalances ``register +allocation'' to prevent it from becoming a pessimization, since saves can +introduce register/memory moves. + +Preference optimization reduces the number of moves within an SC. Doing a good +job of honoring preferences is important to the success of the compiler, since +we have assumed in many places that moves will usually be optimized away. + +The scarcity-oriented aspect of ``register allocation'' is handled by a greedy +algorithm in pack. We try to pack the ``most important'' TNs first, under the +theory that earlier packing is more likely to succeed due to fewer constraints. + +The drawback of greedy algorithms is their inability to look ahead. Packing a +TN may mess up later ``register allocation'' by precluding packing of TNs that +are individually ``less important,'' but more important in aggregate. Packing a +TN may also prevent preferences from being honored. + + + +Initial packing: + + +Pack all TNs restricted to a finite SC first, before packing any other TNs. + +One might suppose that Pack would have to treat TNs in different environments +differently, but this is not the case. Pack simply assigns TNs to locations so +that no two conflicting TNs are in the same location. In the process of +implementing call semantics in conflict analysis, we cause TNs in different +environments not to conflict. In the case of passing TNs, cross environment +conflicts do exist, but this reflects reality, since the passing TNs are +live in both the caller and the callee. Environment semantics has already been +implemented at this point. + +This means that Pack can pack all TNs simultaneously, using one data structure +to represent the conflicts for each location. So we have only one conflict set +per SB location, rather than separating this information by environment. + + +Load TN packing: + +We create load TNs as needed in a post-pass to the initial packing. After TNs +are packed, it may be that some references to a TN will require it to be in a +SC other than the one it was packed in. We create load-TNs and pack them on +the fly during this post-pass. + +What we do is have an optional SC restriction associated with TN-refs. If we +pack the TN in an SC which is different from the required SC for the reference, +then we create a TN for each such reference, and pack it into the required SC. + +In many cases we will be able to pack the load TN with no hassle, but in +general we may need to spill a TN that has already been packed. We choose a +TN that isn't in use by the offending VOP, and then spill that TN onto the +stack for the duration of that VOP. If the VOP is a conditional, then we must +insert a new block interposed before the branch target so that the TN +value is restored regardless of which branch is taken. + +Instead of remembering lifetime information from conflict analysis, we rederive +it. We scan each block backward while keeping track of which locations have +live TNs in them. When we find a reference that needs a load TN packed, we try +to pack it in an unused location. If we can't, we unpack the currently live TN +with the lowest cost and force it into an unbounded SC. + +The per-location and per-TN conflict information used by pack doesn't +need to be updated when we pack a load TN, since we are done using those data +structures. + +We also don't need to create any TN-Refs for load TNs. [??? How do we keep +track of load-tn lifetimes? It isn't really that hard, I guess. We just +remember which load TNs we created at each VOP, killing them when we pass the +loading (or saving) step. This suggests we could flush the Refs thread if we +were willing to sacrifice some flexibility in explicit temporary lifetimes. +Flushing the Refs would make creating the VMR representation easier.] + +The lifetime analysis done during load-TN packing doubles as a consistency +check. If we see a read of a TN packed in a location which has a different TN +currently live, then there is a packing bug. If any of the TNs recorded as +being live at the block beginning are packed in a scarce SB, but aren't current +in that location, then we also have a problem. + +The conflict structure for load TNs is fairly simple, the load TNs for +arguments and results all conflict with each other, and don't conflict with +much else. We just try packing in targeted locations before trying at random. + + + +\chapter{Code generation} + +This is fairly straightforward. We translate VOPs into instruction sequences +on a per-block basis. + +After code generation, the VMR representation is gone. Everything is +represented by the assembler data structures. + + +\chapter{Assembly} + +In effect, we do much of the work of assembly when the compiler is compiled. + +The assembler makes one pass fixing up branch offsets, then squeezes out the +space left by branch shortening and dumps out the code along with the load-time +fixup information. The assembler also deals with dumping unboxed non-immediate +constants and symbols. Boxed constants are created by explicit constructor +code in the top-level form, while immediate constants are generated using +inline code. + +[\#\#\# The basic output of the assembler is: + A code vector + A representation of the fixups along with indices into the code vector for + the fixup locations + A PC map translating PCs into source paths + +This information can then be used to build an output file or an in-core +function object. +] + +The assembler is table-driven and supports arbitrary instruction formats. As +far as the assembler is concerned, an instruction is a bit sequence that is +broken down into subsequences. Some of the subsequences are constant in value, +while others can be determined at assemble or load time. + +\begin{verbatim} +Assemble Node Form* + Allow instructions to be emitted during the evaluation of the Forms by + defining Inst as a local macro. This macro caches various global + information in local variables. Node tells the assembler what node + ultimately caused this code to be generated. This is used to create the + pc=>source map for the debugger. + +Assemble-Elsewhere Node Form* + Similar to Assemble, but the current assembler location is changed to + somewhere else. This is useful for generating error code and similar + things. Assemble-Elsewhere may not be nested. + +Inst Name Arg* + Emit the instruction Name with the specified arguments. + +Gen-Label +Emit-Label (Label) + Gen-Label returns a Label object, which describes a place in the code. + Emit-Label marks the current position as being the location of Label. +\end{verbatim} + + + +\chapter{Dumping} + +So far as input to the dumper/loader, how about having a list of Entry-Info +structures in the VMR-Component? These structures contain all information +needed to dump the associated function objects, and are only implicitly +associated with the functional/XEP data structures. Load-time constants that +reference these function objects should specify the Entry-Info, rather than the +functional (or something). We would then need to maintain some sort of +association so VMR conversion can find the appropriate Entry-Info. +Alternatively, we could initially reference the functional, and then later +clobber the reference to the Entry-Info. + +We have some kind of post-pass that runs after assembly, going through the +functions and constants, annotating the VMR-Component for the benefit of the +dumper: + Resolve :Label load-time constants. + Make the debug info. + Make the entry-info structures. + +Fasl dumper and in-core loader are implementation (but not instruction set) +dependent, so we want to give them a clear interface. + +\begin{verbatim} +open-fasl-file name => fasl-file + Returns a ``fasl-file'' object representing all state needed by the dumper. + We objectify the state, since the fasdumper should be reentrant. (but + could fail to be at first.) + +close-fasl-file fasl-file abort-p + Close the specified fasl-file. + +fasl-dump-component component code-vector length fixups fasl-file + Dump the code, constants, etc. for component. Code-Vector is a vector + holding the assembled code. Length is the number of elements of Vector + that are actually in use. Fixups is a list of conses (offset . fixup) + describing the locations and things that need to be fixed up at load time. + If the component is a top-level component, then the top-level lambda will + be called after the component is loaded. + +load-component component code-vector length fixups + Like Fasl-Dump-Component, but directly installs the code in core, running + any top-level code immediately. (???) but we need some way to glue + together the componenents, since we don't have a fasl table. +\end{verbatim} + + + +Dumping: + +Dump code for each component after compiling that component, but defer dumping +of other stuff. We do the fixups on the code vectors, and accumulate them in +the table. + +We have to grovel the constants for each component after compiling that +component so that we can fix up load-time constants. Load-time constants are +values needed by the code that are computed after code generation/assembly +time. Since the code is fixed at this point, load-time constants are always +represented as non-immediate constants in the constant pool. A load-time +constant is distinguished by being a cons (Kind . What), instead of a Constant +leaf. Kind is a keyword indicating how the constant is computed, and What is +some context. + +Some interesting load-time constants: +\begin{verbatim} + (:label . <label>) + Is replaced with the byte offset of the label within the code-vector. + + (:code-vector . <component>) + Is replaced by the component's code-vector. + + (:entry . <function>) + (:closure-entry . <function>) + Is replaced by the function-entry structure for the specified function. + :Entry is how the top-level component gets a handle on the function + definitions so that it can set them up. +\end{verbatim} +We also need to remember the starting offset for each entry, although these +don't in general appear as explicit constants. + +We then dump out all the :Entry and :Closure-Entry objects, leaving any +constant-pool pointers uninitialized. After dumping each :Entry, we dump some +stuff to let genesis know that this is a function definition. Then we dump all +the constant pools, fixing up any constant-pool pointers in the already-dumped +function entry structures. + +The debug-info *is* a constant: the first constant in every constant pool. But +the creation of this constant must be deferred until after the component is +compiled, so we leave a (:debug-info) placeholder. [Or maybe this is +implicitly added in by the dumper, being supplied in a VMR-component slot.] + + + Work out details of the interface between the back-end and the + assembler/dumper. + + Support for multiple assemblers concurrently loaded? (for byte code) + + We need various mechanisms for getting information out of the assembler. + + We can get entry PCs and similar things into function objects by making a + Constant leaf, specifying that it goes in the closure, and then + setting the value after assembly. + + We have an operation Label-Value which can be used to get the value of a + label after assembly and before the assembler data structures are + deallocated. + + The function map can be constructed without any special help from the + assembler. Codegen just has to note the current label when the function + changes from one block to the next, and then use the final value of these + labels to make the function map. + + Probably we want to do the source map this way too. Although this will + make zillions of spurious labels, we would have to effectively do that + anyway. + + With both the function map and the source map, getting the locations right + for uses of Elsewhere will be a bit tricky. Users of Elsewhere will need + to know about how these maps are being built, since they must record the + labels and corresponding information for the elsewhere range. It would be + nice to have some cooperation from Elsewhere so that this isn't necessary, + otherwise some VOP writer will break the rules, resulting in code that is + nowhere. + + The Debug-Info and related structures are dumped by consing up the + structure and making it be the value of a constant. + + Getting the code vector and fixups dumped may be a bit more interesting. I + guess we want a Dump-Code-Vector function which dumps the code and fixups + accumulated by the current assembly, returning a magic object that will + become the code vector when it is dumped as a constant. +] diff --git a/doc/internals/cmu/compiler-overview.tex b/doc/internals/cmu/compiler-overview.tex new file mode 100644 index 0000000000..64b086bdc8 --- /dev/null +++ b/doc/internals/cmu/compiler-overview.tex @@ -0,0 +1,550 @@ +\chapter{Compiler Overview} % -*- Dictionary: design -*- + +The structure of the compiler may be broadly characterized by describing the +compilation phases and the data structures that they manipulate. The steps in +the compilation are called phases rather than passes since they don't +necessarily involve a full pass over the code. The data structure used to +represent the code at some point is called an {\it intermediate +representation.} + +Two major intermediate representations are used in the compiler: +\begin{itemize} + +\item The Implicit Continuation Representation (ICR) represents the lisp-level +semantics of the source code during the initial phases. Partial evaluation and +semantic analysis are done on this representation. ICR is roughly equivalent +to a subset of Common Lisp, but is represented as a flow-graph rather than a +syntax tree. Phases which only manipulate ICR comprise the ``front end''. It +would be possible to use a different back end such as one that directly +generated code for a stack machine. + +\item The Virtual Machine Representation (VMR) represents the implementation of +the source code on a virtual machine. The virtual machine may vary depending +on the the target hardware, but VMR is sufficiently stylized that most of the +phases which manipulate it are portable. +\end{itemize} + +Each phase is briefly described here. The phases from ``local call analysis'' +to ``constraint propagation'' all interact; for maximum optimization, they +are generally repeated until nothing new is discovered. The source files which +primarily contain each phase are listed after ``Files: ''. +\begin{description} + +\item[ICR conversion] +Convert the source into ICR, doing macroexpansion and simple source-to-source +transformation. All names are resolved at this time, so we don't have to worry +about name conflicts later on. Files: {\tt ir1tran, srctran, typetran} + +\item[Local call analysis] Find calls to local functions and convert them to +local calls to the correct entry point, doing keyword parsing, etc. Recognize +once-called functions as lets. Create {\it external entry points} for +entry-point functions. Files: {\tt locall} + +\item[Find components] +Find flow graph components and compute depth-first ordering. Separate +top-level code from run-time code, and determine which components are top-level +components. Files: {\tt dfo} + +\item[ICR optimize] A grab-bag of all the non-flow ICR optimizations. Fold +constant functions, propagate types and eliminate code that computes unused +values. Special-case calls to some known global functions by replacing them +with a computed function. Merge blocks and eliminate IF-IFs. Substitute let +variables. Files: {\tt ir1opt, ir1tran, typetran, seqtran, vm/vm-tran} + +\item[Type constraint propagation] +Use global flow analysis to propagate information about lexical variable +types. Eliminate unnecessary type checks and tests. Files: {\tt constraint} + +\item[Type check generation] +Emit explicit ICR code for any necessary type checks that are too complex to be +easily generated on the fly by the back end. Files: {\tt checkgen} + +\item[Event driven operations] +Various parts of ICR are incrementally recomputed, either eagerly on +modification of the ICR, or lazily, when the relevant information is needed. +\begin{itemize} +\item Check that type assertions are satisfied, marking places where type +checks need to be done. + +\item Locate let calls. + +\item Delete functions and variables with no references +\end{itemize} +Files: {\tt ir1util}, {\tt ir1opt} + +\item[ICR finalize] +This phase is run after all components have been compiled. It scans the +global variable references, looking for references to undefined variables +and incompatible function redefinitions. Files: {\tt ir1final}, {\tt main}. + +\item[Environment analysis] +Determine which distinct environments need to be allocated, and what +context needed to be closed over by each environment. We detect non-local +exits and set closure variables. We also emit cleanup code as funny +function calls. This is the last pure ICR pass. Files: {\tt envanal} + +\item[Global TN allocation (GTN)] +Iterate over all defined functions, determining calling conventions +and assigning TNs to local variables. Files: {\tt gtn} + +\item[Local TN allocation (LTN)] +Use type and policy information to determine which VMR translation to use +for known functions, and then create TNs for expression evaluation +temporaries. We also accumulate some random information needed by VMR +conversion. Files: {\tt ltn} + +\item[Control analysis] +Linearize the flow graph in a way that minimizes the number of branches. The +block-level structure of the flow graph is basically frozen at this point. +Files: {\tt control} + +\item[Stack analysis] +Maintain stack discipline for unknown-values continuation in the presence +of local exits. Files: {\tt stack} + +\item[Entry analysis] +Collect some back-end information for each externally callable function. + +\item[VMR conversion] Convert ICR into VMR by translating nodes into VOPs. +Emit type checks. Files: {\tt ir2tran, vmdef} + +\item[Copy propagation] Use flow analysis to eliminate unnecessary copying of +TN values. Files: {\tt copyprop} + +\item[Representation selection] +Look at all references to each TN to determine which representation has the +lowest cost. Emit appropriate move and coerce VOPS for that representation. + +\item[Lifetime analysis] +Do flow analysis to find the set of TNs whose lifetimes +overlap with the lifetimes of each TN being packed. Annotate call VOPs with +the TNs that need to be saved. Files: {\tt life} + +\item[Pack] +Find a legal register allocation, attempting to minimize unnecessary moves. +Files: {\tt pack} + +\item[Code generation] +Call the VOP generators to emit assembly code. Files: {\tt codegen} + +\item[Pipeline reorganization] On some machines, move memory references +backward in the code so that they can overlap with computation. On machines +with delayed branch instructions, locate instructions that can be moved into +delay slots. Files: {\tt assem-opt} + +\item[Assembly] +Resolve branches and convert into object code and fixup information. +Files: {\tt assembler} + +\item[Dumping] Convert the compiled code into an object file or in-core +function. Files: {\tt debug-dump}, {\tt dump}, {\tt vm/core} + +\end{description} + +\chapter{The Implicit Continuation Representation} + +The set of special forms recognized is exactly that specified in the Common +Lisp manual. Everything that is described as a macro in CLTL is a macro. + +Large amounts of syntactic information are thrown away by the conversion to an +anonymous flow graph representation. The elimination of names eliminates the +need to represent most environment manipulation special forms. The explicit +representation of control eliminates the need to represent BLOCK and GO, and +makes flow analysis easy. The full Common Lisp LAMBDA is implemented with a +simple fixed-arg lambda, which greatly simplifies later code. + +The elimination of syntactic information eliminates the need for most of the +``beta transformation'' optimizations in Rabbit. There are no progns, no +tagbodys and no returns. There are no ``close parens'' which get in the way of +determining which node receives a given value. + +In ICR, computation is represented by Nodes. These are the node types: +\begin{description} +\item[if] Represents all conditionals. + +\item[set] Represents a {\tt setq}. + +\item[ref] Represents a constant or variable reference. + +\item[combination] Represents a normal function call. + +\item[MV-combination] Represents a {\tt multiple-value-call}. This is used to +implement all multiple value receiving forms except for {\tt +multiple-value-prog1}, which is implicit. + +\item[bind] +This represents the allocation and initialization of the variables in +a lambda. + +\item[return] +This collects the return value from a lambda and represents the +control transfer on return. + +\item[entry] Marks the start of a dynamic extent that can have non-local exits +to it. Dynamic state can be saved at this point for restoration on re-entry. + +\item[exit] Marks a potentially non-local exit. This node is interposed +between the non-local uses of a continuation and the {\tt dest} so that code to +do a non-local exit can be inserted if necessary. +\end{description} + +Some slots are shared between all node types (via defstruct inheritance.) This +information held in common between all nodes often makes it possible to avoid +special-casing nodes on the basis of type. This shared information is +primarily concerned with the order of evaluation and destinations and +properties of results. This control and value flow is indicated in the node +primarily by pointing to continuations. + +The {\tt continuation} structure represents information sufficiently related +to the normal notion of a continuation that naming it so seems sensible. +Basically, a continuation represents a place in the code, or alternatively the +destination of an expression result and a transfer of control. These two +notions are bound together for the same reasons that they are related in the +standard functional continuation interpretation. + +A continuation may be deprived of either or both of its value or control +significance. If the value of a continuation is unused due to evaluation for +effect, then the continuation will have a null {\tt dest}. If the {\tt next} +node for a continuation is deleted by some optimization, then {\tt next} will +be {\tt :none}. + + [\#\#\# Continuation kinds...] + +The {\tt block} structure represents a basic block, in the the normal sense. +Control transfers other than simple sequencing are represented by information +in the block structure. The continuation for the last node in a block +represents only the destination for the result. + +It is very difficult to reconstruct anything resembling the original source +from ICR, so we record the original source form in each node. The location of +the source form within the input is also recorded, allowing for interfaces such +as ``Edit Compiler Warnings''. See section \ref{source-paths}. + +Forms such as special-bind and catch need to have cleanup code executed at all +exit points from the form. We represent this constraint in ICR by annotating +the code syntactically within the form with a Cleanup structure describing what +needs to be cleaned up. Environment analysis determines the cleanup locations +by watching for a change in the cleanup between two continuations. We can't +emit cleanup code during ICR conversion, since we don't know which exits will +be local until after ICR optimizations are done. + +Special binding is represented by a call to the funny function \%Special-Bind. +The first argument is the Global-Var structure for the variable bound and the +second argument is the value to bind it to. + +Some subprimitives are implemented using a macro-like mechanism for translating +\%PRIMITIVE forms into arbitrary lisp code. Subprimitives special-cased by VMR +conversion are represented by a call to the funny function \%\%Primitive. The +corresponding Template structure is passed as the first argument. + +We check global function calls for syntactic legality with respect to any +defined function type function. If the call is illegal or we are unable to +tell if it is legal due to non-constant keywords, then we give a warning and +mark the function reference as :notinline to force a full call and cause +subsequent phases to ignore the call. If the call is legal and is to a known +function, then we annotate the Combination node with the Function-Info +structure that contains the compiler information for the function. + + +\section{Tail sets} +\#| +Probably want to have a GTN-like function result equivalence class mechanism +for ICR type inference. This would be like the return value propagation being +done by Propagate-From-Calls, but more powerful, less hackish, and known to +terminate. The ICR equivalence classes could probably be used by GTN, as well. + +What we do is have local call analysis eagerly maintain the equivalence classes +of functions that return the same way by annotating functions with a Tail-Info +structure shared between all functions whose value could be the value of this +function. We don't require that the calls actually be tail-recursive, only +that the call deliver its value to the result continuation. [\#\#\# Actually +now done by ICR-OPTIMIZE-RETURN, which is currently making ICR optimize +mandatory.] + +We can then use the Tail-Set during ICR type inference. It would have a type +that is the union across all equivalent functions of the types of all the uses +other than in local calls. This type would be recomputed during optimization +of return nodes. When the type changes, we would propagate it to all calls to +any of the equivalent functions. How do we know when and how to recompute the +type for a tail-set? Recomputation is driven by type propagation on the result +continuation. + +This is really special-casing of RETURN nodes. The return node has the type +which is the union of all the non-call uses of the result. The tail-set is +found though the lambda. We can then recompute the overall union by taking the +union of the type per return node, rather than per-use. + + +How do result type assertions work? We can't intersect the assertions across +all functions in the equivalence class, since some of the call combinations may +not happen (or even be possible). We can intersect the assertion of the result +with the derived types for non-call uses. + +When we do a tail call, we obviously can't check that the returned value +matches our assertion. Although in principle, we would like to be able to +check all assertions, to preserve system integrity, we only need to check +assertions that we depend on. We can afford to lose some assertion information +as long as we entirely lose it, ignoring it for type inference as well as for +type checking. + +Things will work out, since the caller will see the tail-info type as the +derived type for the call, and will emit a type check if it needs a stronger +result. + +A remaining question is whether we should intersect the assertion with +per-RETURN derived types from the very beginning (i.e. before the type check +pass). I think the answer is yes. We delay the type check pass so that we can +get our best guess for the derived type before we decide whether a check is +necessary. But with the function return type, we aren't committing to doing +any type check when we intersect with the type assertion; the need to type +check is still determined in the type check pass by examination of the result +continuation. + +What is the relationship between the per-RETURN types and the types in the +result continuation? The assertion is exactly the Continuation-Asserted-Type +(note that the asserted type of result continuations will never change after +ICR conversion). The per-RETURN derived type is different than the +Continuation-Derived-Type, since it is intersected with the asserted type even +before Type Check runs. Ignoring the Continuation-Derived-Type probably makes +life simpler anyway, since this breaks the potential circularity of the +Tail-Info-Type will affecting the Continuation-Derived-Type, which affects... + +When a given return has no non-call uses, we represent this by using +*empty-type*. This is consistent with the interpretation that a return type of +NIL means the function can't return. + + +\section{Hairy function representation} + +Non-fixed-arg functions are represented using Optional-Dispatch. An +Optional-Dispatch has an entry-point function for each legal number of +optionals, and one for when extra args are present. Each entry point function +is a simple lambda. The entry point function for an optional is passed the +arguments which were actually supplied; the entry point function is expected to +default any remaining parameters and evaluate the actual function body. + +If no supplied-p arg is present, then we can do this fairly easily by having +each entry point supply its default and call the next entry point, with the +last entry point containing the body. If there are supplied-p args, then entry +point function is replaced with a function that calls the original entry +function with T's inserted at the position of all the supplied args with +supplied-p parameters. + +We want to be a bit clever about how we handle arguments declared special when +doing optional defaulting, or we will emit really gross code for special +optionals. If we bound the arg specially over the entire entry-point function, +then the entry point function would be caused to be non-tail-recursive. What +we can do is only bind the variable specially around the evaluation of the +default, and then read the special and store the final value of the special +into a lexical variable which we then pass as the argument. In the common case +where the default is a constant, we don't have to special-bind at all, since +the computation of the default is not affected by and cannot affect any special +bindings. + +Keyword and rest args are both implemented using a LEXPR-like ``more +args'' convention. The More-Entry takes two arguments in addition to +the fixed and optional arguments: the argument context and count. +\verb+(ARG <context> <n>)+ accesses the N'th additional argument. Keyword +args are implemented directly using this mechanism. Rest args are +created by calling \%Listify-Rest-Args with the context and count. + +The More-Entry parses the keyword arguments and passes the values to the main +function as positional arguments. If a keyword default is not constant, then +we pass a supplied-p parameter into the main entry and let it worry about +defaulting the argument. Since the main entry accepts keywords in parsed form, +we can parse keywords at compile time for calls to known functions. We keep +around the original parsed lambda-list and related information so that people +can figure out how to call the main entry. + + +\section{ICR representation of non-local exits} + +All exits are initially represented by EXIT nodes: +How about an Exit node: +\begin{verbatim} + (defstruct (exit (:include node)) + value) +\end{verbatim} +The Exit node uses the continuation that is to receive the thrown Value. +During optimization, if we discover that the Cont's home-lambda is the same as +the exit node's, then we can delete the Exit node, substituting the Cont for +all of the Value's uses. + +The successor block of an EXIT is the entry block in the entered environment. +So we use the Exit node to mark the place where exit code is inserted. During +environment analysis, we need only insert a single block containing the entry +point stub. + +We ensure that all Exits that aren't for a NLX don't have any Value, so that +local exits never require any value massaging. + +The Entry node marks the beginning of a block or tagbody: +\begin{verbatim} + (defstruct (entry (:include node)) + (continuations nil :type list)) +\end{verbatim} +It contains a list of all the continuations that the body could exit to. The +Entry node is used as a marker for the place to snapshot state, including +the control stack pointer. Each lambda has a list of its Entries so +that environment analysis can figure out which continuations are really being +closed over. There is no reason for optimization to delete Entry nodes, +since they are harmless in the degenerate case: we just emit no code (like a +no-var let). + + +We represent CATCH using the lexical exit mechanism. We do a transformation +like this: +\begin{verbatim} + (catch 'foo xxx) ==> + (block #:foo + (%catch #'(lambda () (return-from #:foo (%unknown-values))) 'foo) + (%within-cleanup :catch + xxx)) +\end{verbatim} + +\%CATCH just sets up the catch frame which points to the exit function. \%Catch +is an ordinary function as far as ICR is concerned. The fact that the catcher +needs to be cleaned up is expressed by the Cleanup slots in the continuations +in the body. \%UNKNOWN-VALUES is a dummy function call which represents the +fact that we don't know what values will be thrown. + +\%WITHIN-CLEANUP is a special special form that instantiates its first argument +as the current cleanup when converting the body. In reality, the lambda is +also created by the special special form \%ESCAPE-FUNCTION, which gives the +lambda a special :ESCAPE kind so that the back end knows not to generate any +code for it. + + +We use a similar hack in Unwind-Protect to represent the fact that the cleanup +forms can be invoked at arbitrarily random times. + +\begin{verbatim} + (unwind-protect p c) ==> + (flet ((#:cleanup () c)) + (block #:return + (multiple-value-bind + (#:next #:start #:count) + (block #:unwind + (%unwind-protect #'(lambda (x) (return-from #:unwind x))) + (%within-cleanup :unwind-protect + (return-from #:return p))) + (#:cleanup) + (%continue-unwind #:next #:start #:count)))) +\end{verbatim} + +We use the block \#:unwind to represent the entry to cleanup code in the case +where we are non-locally unwound. Calling of the cleanup function in the +drop-through case (or any local exit) is handled by cleanup generation. We +make the cleanup a function so that cleanup generation can add calls at local +exits from the protected form. \#:next, \#:start and \#:count are state used in +the case where we are unwound. They indicate where to go after doing the +cleanup and what values are being thrown. The cleanup encloses only the +protected form. As in CATCH, the escape function is specially tagged as +:ESCAPE. The cleanup function is tagged as :CLEANUP to inhibit let conversion +(since references are added in environment analysis.) + +Notice that implementing these forms using closures over continuations +eliminates any need to special-case ICR flow analysis. Obviously we don't +really want to make heap-closures here. In reality these functions are +special-cased by the back-end according to their KIND. + + +\section{Block compilation} + +One of the properties of ICR is that it supports ``block compilation'' by allowing +arbitrarily large amounts of code to be converted at once, with actual +compilation of the code being done at will. + + +In order to preserve the normal semantics we must recognize that proclamations +(possibly implicit) are scoped. A proclamation is in effect only from the time +of appearance of the proclamation to the time it is contradicted. The current +global environment at the end of a block is not necessarily the correct global +environment for compilation of all the code within the block. We solve this +problem by closing over the relevant information in the ICR at the time it is +converted. For example, each functional variable reference is marked as +inline, notinline or don't care. Similarly, each node contains a structure +known as a Cookie which contains the appropriate settings of the compiler +policy switches. + +We actually convert each form in the file separately, creating a separate +``initial component'' for each one. Later on, these components are merged as +needed. The main reason for doing this is to cause EVAL-WHEN processing to be +interleaved with reading. + + +\section{Entry points} + +\#| + +Since we need to evaluate potentially arbitrary code in the XEP argument forms +(for type checking), we can't leave the arguments in the wired passing +locations. Instead, it seems better to give the XEP max-args fixed arguments, +with the passing locations being the true passing locations. Instead of using +\%XEP-ARG, we reference the appropriate variable. + +Also, it might be a good idea to do argument count checking and dispatching +with explicit conditional code in the XEP. This would simplify both the code +that creates the XEP and the VMR conversion of XEPs. Also, argument count +dispatching would automatically benefit from any cleverness in compilation of +case-like forms (jump tables, etc). On the downside, this would push some +assumptions about how arg dispatching is done into ICR. But then we are +currently violating abstraction at least as badly in VMR conversion, which is +also supposed to be implementation independent. +|\# + +As a side-effect of finding which references to known functions can be +converted to local calls, we find any references that cannot be converted. +References that cannot be converted to a local call must evaluate to a +``function object'' (or function-entry) that can be called using the full call +convention. A function that can be called from outside the component is called +an ``entry-point''. + +Lots of stuff that happens at compile-time with local function calls must be +done at run-time when an entry-point is called. + +It is desirable for optimization and other purposes if all the calls to every +function were directly present in ICR as local calls. We cannot directly do +this with entry-point functions, since we don't know where and how the +entry-point will be called until run-time. + +What we do is represent all the calls possible from outside the component by +local calls within the component. For each entry-point function, we create a +corresponding lambda called the external entry point or XEP. This is a +function which takes the number of arguments passed as the first argument, +followed by arguments corresponding to each required or optional argument. + +If an optional argument is unsupplied, the value passed into the XEP is +undefined. The XEP is responsible for doing argument count checking and +dispatching. + +In the case of a fixed-arg lambda, we emit a call to the \%VERIFY-ARGUMENT-COUNT +funny function (conditional on policy), then call the real function on the +passed arguments. Even in this simple case, we benefit several ways from +having a separate XEP: +\begin{itemize} +\item The argument count checking is factored out, and only needs to + be done in full calls. +\item Argument type checking happens automatically as a consequence of + passing the XEP arguments in a local call to the real function. + This type checking is also only done in full calls. +\item The real function may use a non-standard calling convention for + the benefit of recursive or block-compiled calls. The XEP converts + arguments/return values to/from the standard convention. This also + requires little special-casing of XEPs. +\end{itemize} + +If the function has variable argument count (represented by an +OPTIONAL-DISPATCH), then the XEP contains a COND which dispatches off of the +argument count, calling the appropriate entry-point function (which then does +defaulting). If there is a more entry (for keyword or rest args), then the XEP +obtains the more arg context and count by calling the \%MORE-ARG-CONTEXT funny +function. + +All non-local-call references to functions are replaced with references to the +corresponding XEP. ICR optimization may discover a local call that was +previously a non-local reference. When we delete the reference to the XEP, we +may find that it has no references. In this case, we can delete the XEP, +causing the function to no longer be an entry-point. + + diff --git a/doc/internals/cmu/compiler.tex b/doc/internals/cmu/compiler.tex new file mode 100644 index 0000000000..cc5c0d7d4a --- /dev/null +++ b/doc/internals/cmu/compiler.tex @@ -0,0 +1,6 @@ +\part{Compiler Organization} +\input{compiler-overview} +\input{front} +\input{middle} +\input{back} +\input{interface} diff --git a/doc/internals/cmu/debugger.tex b/doc/internals/cmu/debugger.tex new file mode 100644 index 0000000000..4d38456aa9 --- /dev/null +++ b/doc/internals/cmu/debugger.tex @@ -0,0 +1,657 @@ +% -*- Dictionary: design; Package: C -*- +\chapter{Debugger} +Two classes of errors are handled by the Lisp debugger. These are +synchronous errors caused by something erring in program code and +asynchronous errors caused by some external context of execution +(clock interrupts, control-c interrupts). Asynchronous errors can +often be postponed if they are delivered at an inconvenient time. + +Synchronous errors are frequently handled by directly invoking the +debugger. However, there are several places where the strategy of +jumping into the debugger is not used. In those situations the +compiler emits a stylized breakpoint; a breakpoint instruction +(usually an INT3) followed by several bytes of argument data. This +will cause a trip through the operating system and ultimately the +invocation of the C-level SIGTRAP handler which, in turn, interprets +the argument bytes following the breakpoint and dispatches to the +correct handler. There is a switch statement in ``sigtrap\_handler'' +which gives the whole story on what types of errors rely on this +mechanism. The most commonly invoked handler is probably +``interrupt\_internal\_error'' as it fields such common exceptions as +the use of unbound symbols. To familiarize with the context these +traps are created in, one can disassemble just about any function and +look at the bottom of the disassembly for blocks of error handling code. +There will often be ``BREAK 10'' opcodes followed by several ``BYTE'' +opcodes with the meaning of the arguments in neatly decoded form off +in the right-hand column. + +The other types of synchronous errors are those errors delivered by +the operating system such as FPU traps and SIGSEGVs. The invocation +of those signals should be funneled through a C-level trampoline which +makes a callback into Lisp passing all of the signal handler +arguments. That code is pretty straight forward and the +``interrupt\_handle\_now'' function is pretty much where all of the +runtime logic is localized. + +Handling asynchronous errors and deferred asynchronous errors is a bit more +involved\ldots + +\section{Tracing and Breakpoints} +\label{sec:trace-and-breakpoints} + +Here are a few notes on how tracing of compiled code works. + +When a function is traced, a breakpoint instruction is placed at the +start of the function, replacing the instruction that was there. +(This is a \verb+:function-start+ breakpoint.) (This appears to be +one instruction after the no-arg parsing entry point.) The breakpoint +instruction is, of course, architecture-specific, but it must signal a +\verb+trap_Breakpoint+ trap. + +When the code is run, the breakpoint instruction is executed causing a +trap. The trap handler runs \verb+HANDLE-BREAKPOINT+ to process it. +After doing the appropriate processing, we now need to continue. Of +course, since the real instruction has been replaced, we to run the +original instruction. This is done by now inserting a \emph{new} +breakpoint after the original breakpoint. This breakpoint must be of +the type \verb+trap_AfterBreakpoint+. The original instruction is +restored and execution continues from there. Then the +\verb+trap_AfterBreakpoint+ instruction gets executed. The handler +for this puts back the original breakpoint, thereby preserving the +breakpoint. Then we replace the AfterBreakpoint with the original +instruction and continue from there. + +That's all pretty straightforward in concept. + +When tracing, additional information is needed. Breakpoints have the +ability to run arbitrary lisp code to process the breakpoint. Tracing +uses this feature. + +When this breakpoint is reached, \verb+HANDLE-BREAKPOINT+ runs the +breakpoint hook function. This function figures out where this +function would return to and creates a new return area and replaces +the original return address with this new address. Thus, when the +function returns, it returns to this new location instead of the +original. + +This new return address is a specially created bogus LRA object. It +is a code-component whose body consists of a code template copied from +an assembly routine into the body. The assembly routine is the code +in \verb+function_end_breakpoint_guts+. This bogus LRA object stores +the real LRA for the function, and also an indication if the +known-return convention is used for this function. + +The bogus LRA object contains a function-end breakpoint +(\verb+trap_FunctionEndBreakpoint+). When it's executed the trap +handler handles this breakpoint. It figures out where this trap come +from and calls \verb+HANDLE-BREAKPOINT+ to handle it. +\verb+HANDLE-BREAKPOINT+ returns and the trap handler arranges it so +that this bogus LRA returns to the real LRA. + +Thus, we can do something when a Lisp function returns, like printing +out the return value for the function for tracing. + +There are lots of internal details left out here, but gives a short +overview of how this works. For more info, look at +\verb+code/debug-int.lisp+ and \verb+lisp/breakpoint.c+, and, of +course, the various \verb+<foo>-arch.c+ files. + +\chapter{Debugger Information} +\index{debugger information} +\label{debug-info} + +Although the compiler's great freedom in choice of function call conventions +and variable representations has major efficiency advantages, it also has +unfortunate consequences for the debugger. The debug information that we need +is even more elaborate than for conventional ``compiled'' languages, since we +cannot even do a simple backtrace without some debug information. However, +once having gone this far, it is not that difficult to go the extra distance, +and provide full source level debugging of compiled code. + +Full debug information has a substantial space penalty, so we allow different +levels of debug information to be specified. In the extreme case, we can +totally omit debug information. + + +\section{The Debug-Info Structure} +\index{debug-info structure} + +The Debug-Info structure directly represents information about the +source code, and points to other structures that describe the layout of +run-time data structures. + + +Make some sort of minimal debug-info format that would support at least the +common cases of level 1 (since that is what we would release), and perhaps +level 0. Actually, it seems it wouldn't be hard to crunch nearly all of the +debug-function structure and debug-info function map into a single byte-vector. +We could have an uncrunch function that restored the current format. This +would be used by the debugger, and also could be used by purify to delete parts +of the debug-info even when the compiler dumps it in crunched form. +[Note that this isn't terribly important if purify is smart about +debug-info...] + + + +Compiled source map representation: + +[\#\#\# store in debug-function PC at which env is properly initialized, i.e. +args (and return-pc, etc.) in internal locations. This is where a +:function-start breakpoint would break.] + +[\#\#\# Note that that we can easily cache the form-number => source-path or +form-number => form translation using a vector indexed by form numbers that we +build during a walk.] + + + + +Instead of using source paths in the debug-info, use ``form numbers''. The form +number of a form is the number of forms that we walk to reach that form when +doing a pre-order walk of the source form. [Might want to use a post-order +walk, as that would more closely approximate evaluation order.] + + +We probably want to continue using source-paths in the compiler, since they are +quick to compute and to get you to a particular form. [\#\#\# But actually, I +guess we don't have to precompute the source paths and annotate nodes with +them: instead we could annotate the nodes with the actual original source form. +Then if we wanted to find the location of that form, we could walk the root +source form, looking that original form. But we might still need to enter all +the forms in a hashtable so that we can tell during IR1 conversion that a given +form appeared in the original source.] + + +Note that form numbers have an interesting property: it is quite efficient to +determine whether an arbitrary form is a subform of some other form, since the +form number of B will be \verb+>+ than A's number and \verb+<+ A's next sibling's number iff +B is a subform of A. + +This should be quite useful for doing the \verb|source=>pc| mapping in the debugger, +since that problem reduces to finding the subset of the known locations that +are for subforms of the specified form. + + +Assume a byte vector with a standard variable-length integer format, something +like this: + +\begin{verbatim} + 0..253 => the integer + 254 => read next two bytes for integer + 255 => read next four bytes for integer +\end{verbatim} + +Then a compiled debug block is just a sequence of variable-length integers in a +particular order, something like this: + +\begin{verbatim} + number of successors + ...offsets of each successor in the function's blocks vector... + first PC + [offset of first top-level form (in forms) (only if not component default)] + form number of first source form + first live mask (length in bytes determined by number of VARIABLES) + ...more <PC, top-level form offset, form-number, live-set> tuples... +\end{verbatim} + +We determine the number of locations recorded in a block by finding the +start of the next compiled debug block in the blocks vector. + +[\#\#\# Actually, only need 2 bits for number of successors {0,1,2}. We might +want to use other bits in the first byte to indicate the kind of location.] +[\#\#\# We could support local packing by having a general concept of ``alternate +locations'' instead of just regular and save locations. The location would have +a bit indicating that there are alternate locations, in which case we read the +number of alternate locations and then that many more SC-OFFSETs. In the +debug-block, we would have a second bit mask with bits set for TNs that are in +an alternate location. We then read a number for each such TN, with the value +being interpreted as an index into the Location's alternate locations.] + + + +It looks like using structures for the compiled-location-info is too bulky. +Instead we need some packed binary representation. + +First, let's represent an SC/offset pair with an ``SC-Offset'', which is an +integer with the SC in the low 5 bits and the offset in the remaining bits: +\begin{verbatim} + ---------------------------------------------------- + | Offset (as many bits as necessary) | SC (5 bits) | + ---------------------------------------------------- +\end{verbatim} +Probably the result should be constrained to fit in a fixnum, since it will be +more efficient and gives more than enough possible offsets. + +We can then represent a compiled location like this: +\begin{verbatim} + single byte of boolean flags: + uninterned name + packaged name + environment-live + has distinct save location + has ID (name not unique in this fun) + name length in bytes (as var-length integer) + ...name bytes... + [if packaged, var-length integer that is package name length] + ...package name bytes...] + [If has ID, ID as var-length integer] + SC-Offset of primary location (as var-length integer) + [If has save SC, SC-Offset of save location (as var-length integer)] +\end{verbatim} + + + + +But for a whizzy breakpoint facility, we would need a good \verb+source=>code+ map. +Dumping a complete \verb+code=>source map+ might be as good a way as any to represent +this, due to the one-to-many relationship between source and code locations. + +We might be able to get away with just storing the source locations for the +beginnings of blocks and maintaining a mapping from code ranges to blocks. +This would be fine both for the profiler and for the ``where am I running now'' +indication. Users might also be convinced that it was most interesting to +break at block starts, but I don't really know how easily people could develop +an understanding of basic blocks. + +It could also be a bit tricky to map an arbitrary user-designated source +location to some ``closest'' source location actually in the debug info. +This problem probably exists to some degree even with a full source map, since +some forms will never appear as the source of any node. It seems you might +have to negotiate with the user. He would mouse something, and then you would +highlight some source form that has a common prefix (i.e. is a prefix of the +user path, or vice-versa.) If they aren't happy with the result, they could +try something else. In some cases, the designated path might be a prefix of +several paths. This ambiguity might be resolved by picking the shortest path +or letting the user choose. + +At the primitive level, I guess what this means is that the structure of source +locations (i.e. source paths) must be known, and the \verb+source=>code+ operation +should return a list of \verb+<source,code>+ pairs, rather than just a list of code +locations. This allows the debugger to resolve the ambiguity however it wants. + +I guess the formal definition of which source paths we would return +is: +\begin{quote} + All source paths in the debug info that have a maximal common prefix with + the specified path. i.e. if several paths have the complete specified path + as a prefix, we return them all. Otherwise, all paths with an equally + large common prefix are returned: if the path with the most in common + matches only the first three elements, then we return all paths that match + in the first three elements. As a degenerate case (which probably + shouldn't happen), if there is no path with anything in common, then we + return *all* of the paths. +\end{quote} + + + +In the DEBUG-SOURCE structure we may ultimately want a vector of the start +positions of each source form, since that would make it easier for the debugger +to locate the source. It could just open the file, FILE-POSITION to the form, +do a READ, then loop down the source path. Of course, it could read each form +starting from the beginning, but that might be too slow. + + +Do XEPs really need Debug-Functions? The only time that we will commonly end +up in the debugger on an XEP is when an argument type check fails. But I +suppose it would be nice to be able to print the arguments passed... + + +Note that assembler-level code motion such as pipeline reorganization can cause +problems with our PC maps. The assembler needs to know that debug info markers +are different from real labels anyway, so I suppose it could inhibit motion +across debug markers conditional on policy. It seems unworthwhile to remember +the node for each individual instruction. + + +For tracing block-compiled calls: +\begin{verbatim} + Info about return value passing locations? + Info about where all the returns are? +\end{verbatim} + +We definitely need the return-value passing locations for debug-return. The +question is what the interface should be. We don't really want to have a +visible debug-function-return-locations operation, since there are various +value passing conventions, and we want to paper over the differences. + + +Probably should be a compiler option to initialize stack frame to a special +uninitialized object (some random immediate type). This would aid debugging, +and would also help GC problems. For the latter reason especially, this should +be locally-turn-onable (off of policy? the new debug-info quality?). + + +What about the interface between the evaluator and the debugger? (i.e. what +happens on an error, etc.) Compiler error handling should be integrated with +run-time error handling. Ideally the error messages should look the same. +Practically, in some cases the run-time errors will have less information. But +the error should look the same to the debugger (or at least similar). + + + +\subsection{Debugger Interface} + +How does the debugger interface to the ``evaluator'' (where the evaluator means +all of native code, byte-code and interpreted IR1)? It seems that it would be +much more straightforward to have a consistent user interface to debugging +all code representations if there was a uniform debugger interface to the +underlying stuff, and vice-versa. + +Of course, some operations might not be supported by some representations, etc. +For example, fine-control stepping might not be available in native code. +In other cases, we might reduce an operation to the lowest common denominator, +for example fetching lexical variables by string and admitting the possibility +of ambiguous matches. [Actually, it would probably be a good idea to store the +package if we are going to allow variables to be closed over.] + +Some objects we would need: +\begin{verbatim} +Location: + The constant information about the place where a value is stored, + everything but which particular frame it is in. Operations: + location name, type, etc. + location-value frame location (setf'able) + monitor-location location function + Function is called whenever location is set with the location, + frame and old value. If active values aren't supported, then we + dummy the effect using breakpoints, in which case the change won't + be noticed until the end of the block (and intermediate changes + will be lost.) +debug info: + All the debug information for a component. +Frame: + frame-changed-locations frame => location* + Return a list of the locations in frame that were changed since the + last time this function was called. Or something. This is for + displaying interesting state changes at breakpoints. + save-frame-state frame => frame-state + restore-frame-state frame frame-state + These operations allow the debugger to back up evaluation, modulo + side-effects and non-local control transfers. This copies and + restores all variables, temporaries, etc, local to the frame, and + also the current PC and dynamic environment (current catch, etc.) + + At the time of the save, the frame must be for the running function + (not waiting for a call to return.) When we restore, the frame + becomes current again, effectively exiting from any frames on top. + (Of course, frame must not already be exited.) + +Thread: + Representation of which stack to use, etc. +Block: + What successors the block has, what calls there are in the block. + (Don't need to know where calls are as long as we know called function, + since can breakpoint at the function.) Whether code in this block is + wildly out of order due to being the result of loop-invariant + optimization, etc. Operations: + block-successors block => code-location* + block-forms block => (source-location code-location)* + Return the corresponding source locations and code locations for + all forms (and form fragments) in the block. +\end{verbatim} + + + +\subsection{Variable maps} + +There are about five things that the debugger might want to know about a +variable: +\begin{itemize} + +\item[Name] + Although a lexical variable's name is ``really'' a symbol (package and + all), in practice it doesn't seem worthwhile to require all the symbols + for local variable names to be retained. There is much less VM and GC + overhead for a constant string than for a symbol. (Also it is useful + to be able to access gensyms in the debugger, even though they are + theoretically ineffable). + +\item[ID] + Which variable with the specified name is this? It is possible to have + multiple variables with the same name in a given function. The ID is + something that makes Name unique, probably a small integer. When + variables aren't unique, we could make this be part of the name, e.g. + ``FOO\#1'', ``FOO\#2''. But there are advantages to keeping this separate, + since in many cases lifetime information can be used to disambiguate, + making qualification unnecessary. + +\item[SC] + When unboxed representations are in use, we must have type information + to properly read and write a location. We only need to know the + SC for this, which would be amenable to a space-saving + numeric encoding. + +\item[Location] + Simple: the offset in SC. [Actually, we need the save location too.] + +\item[Lifetime] + In what parts of the program does this variable hold a meaningful + value? It seems prohibitive to record precise lifetime information, + both in space and compiler effort, so we will have to settle for some + sort of approximation. + + The finest granularity at which it is easy to determine liveness is + the block: we can regard the variable lifetime as the set of blocks + that the variable is live in. Of course, the variable may be dead (and + thus contain meaningless garbage) during arbitrarily large portions of + the block. + + Note that this subsumes the notion of which function a variable belongs + to. A given block is only in one function, so the function is + implicit. +\end{itemize} + +The variable map should represent this information space-efficiently and with +adequate computational efficiency. + +The SC and ID can be represented as small integers. Although the ID can in +principle be arbitrarily large, it should be $<$100 in practice. The location +can be represented by just the offset (a moderately small integer), since the +SB is implicit in the SC. + +The lifetime info can be represented either as a bit-vector indexed by block +numbers, or by a list of block numbers. Which is more compact depends both on +the size of the component and on the number of blocks the variable is live in. +In the limit of large component size, the sparse representation will be more +compact, but it isn't clear where this crossover occurs. Of course, it would +be possible to use both representations, choosing the more compact one on a +per-variable basis. Another interesting special case is when the variable is +live in only one block: this may be common enough to be worth picking off, +although it is probably rarer for named variables than for TNs in general. + +If we dump the type, then a normal list-style type descriptor is fine: the +space overhead is small, since the shareability is high. + +We could probably save some space by cleverly representing the var-info as +parallel vectors of different types, but this would be more painful in use. +It seems better to just use a structure, encoding the unboxed fields in a +fixnum. This way, we can pass around the structure in the debugger, perhaps +even exporting it from the low-level debugger interface. + +[\#\#\# We need the save location too. This probably means that we need two slots +of bits, since we need the save offset and save SC. Actually, we could let the +save SC be implied by the normal SC, since at least currently, we always choose +the same save SC for a given SC. But even so, we probably can't fit all that +stuff in one fixnum without squeezing a lot, so we might as well split and +record both SCs. + +In a localized packing scheme, we would have to dump a different var-info +whenever either the main location or the save location changes. As a practical +matter, the save location is less likely to change than the main location, and +should never change without the main location changing. + +One can conceive of localized packing schemes that do saving as a special case +of localized packing. If we did this, then the concept of a save location +might be eliminated, but this would require major changes in the IR2 +representation for call and/or lifetime info. Probably we will want saving to +continue to be somewhat magical.] + + +How about: + +\begin{verbatim} +(defstruct var-info + ;; + ;; This variable's name. (symbol-name of the symbol) + (name nil :type simple-string) + ;; + ;; The SC, ID and offset, encoded as bit-fields. + (bits nil :type fixnum) + ;; + ;; The set of blocks this variable is live in. If a bit-vector, then it has + ;; a 1 when indexed by the number of a block that it is live in. If an + ;; I-vector, then it lists the live block numbers. If a fixnum, then that is + ;; the number of the sole live block. + (lifetime nil :type (or vector fixnum)) + ;; + ;; The variable's type, represented as list-style type descriptor. + type) +\end{verbatim} + +Then the debug-info holds a simple-vector of all the var-info structures for +that component. We might as well make it sorted alphabetically by name, so +that we can binary-search to find the variable corresponding to a particular +name. + +We need to be able to translate PCs to block numbers. This can be done by an +I-Vector in the component that contains the start location of each block. The +block number is the index at which we find the correct PC range. This requires +that we use an emit-order block numbering distinct from the IR2-Block-Number, +but that isn't any big deal. This seems space-expensive, but it isn't too bad, +since it would only be a fraction of the code size if the average block length +is a few words or more. + +An advantage of our per-block lifetime representation is that it directly +supports keeping a variable in different locations when in different blocks, +i.e. multi-location packing. We use a different var-info for each different +packing, since the SC and offset are potentially different. The Name and ID +are the same, representing the fact that it is the same variable. It is here +that the ID is most significant, since the debugger could otherwise make +same-name variables unique all by itself. + + + +\subsection{Stack parsing} + +[\#\#\# Probably not worth trying to make the stack parseable from the bottom up. +There are too many complications when we start having variable sized stuff on +the stack. It seems more profitable to work on making top-down parsing robust. +Since we are now planning to wire the bottom-up linkage info, scanning from the +bottom to find the top frame shouldn't be too inefficient, even when there was +a runaway recursion. If we somehow jump into hyperspace, then the debugger may +get confused, but we can debug this sort of low-level system lossage using +ADB.] + + +There are currently three relevant context pointers: +\begin{itemize} + \item The PC. The current PC is wired (implicit in the machine). A saved + PC (RETURN-PC) may be anywhere in the current frame. + \item The current stack context (CONT). The current CONT is wired. + A saved CONT (OLD-CONT) may be anywhere in the current frame. + \item The current code object (ENV). The current ENV is wired. + When saved, this is extra-difficult to locate, since it is saved + by the caller, and is thus at an unknown offset in OLD-CONT, + rather than anywhere in the current frame. +\end{itemize} + +We must have all of these to parse the stack. + +With the proposed Debug-Function, we parse the stack (starting at the top) like +this: +\begin{enumerate} +\item Use ENV to locate the current Debug-Info +\item Use the Debug-Info and PC to determine the current Debug-Function. +\item Use the Debug-Function to find the OLD-CONT and RETURN-PC. +\item Find the old ENV by searching up the stack for a saved code object + containing the RETURN-PC. +\item Assign old ENV to ENV, OLD-CONT to CONT, RETURN-PC to PC and goto 1. +\end{enumerate} + +If we changed the function representation so that the code and environment were +a single object, then the location of the old ENV would be simplified. But we +still need to represent ENV as separate from PC, since interrupts and errors +can happen when the current PC isn't positioned at a valid return PC. + +It seems like it might be a good idea to save OLD-CONT, RETURN-PC and ENV at +the beginning of the frame (before any stack arguments). Then we wouldn't have +to search to locate ENV, and we also have a hope of parsing the stack even if +it is damaged. As long as we can locate the start of some frame, we can trace +the stack above that frame. We can recognize a probable frame start by +scanning the stack for a code object (presumably a saved ENV). + +Probably we want some fairly general +mechanism for specifying that a TN should be considered to be live for the +duration of a specified environment. It would be somewhat easier to specify +that the TN is live for all time, but this would become very space-inefficient +in large block compilations. + +This mechanism could be quite useful for other debugger-related things. For +example, when debuggability is important, we could make the TNs holding +arguments live for the entire environment. This would guarantee that a +backtrace would always get the right value (modulo setqs). + +Note that in this context, ``environment'' means the Environment structure (one +per non-let function). At least according to current plans, even when we do +inter-routine register allocation, the different functions will have different +environments: we just ``equate'' the environments. So the number of live +per-environment TNs is bounded by the size of a ``function'', and doesn't blow up +in block compilation. + +The implementation is simple: per-environment TNs are flagged by the +:Environment kind. :Environment TNs are treated the same as :Normal TNs by +everyone except for lifetime/conflict analysis. An environment's TNs are also +stashed in a list in the IR2-Environment structure. During the conflict +analysis post-pass, we look at each block's environment, and make all the +environment's TNs always-live in that block. + +We can implement the ``fixed save location'' concept needed for lazy frame +creation by allocating the save TNs as wired TNs at IR2 conversion time. We +would use the new ``environment lifetime'' concept to specify the lifetimes of +the save locations. There isn't any run-time overhead if we never get around +to using the save TNs. [Pack would also have to notice TNs with pre-allocated +save TNs, packing the original TN in the stack location if its FSC is the +stack.] + + +We want a standard (recognizable) format for an ``escape'' frame. We must make +an escape frame whenever we start running another function without the current +function getting a chance to save its registers. This may be due either to a +truly asynchronous event such as a software interrupt, or due to an ``escape'' +from a miscop. An escape frame marks a brief conversion to a callee-saves +convention. + +Whenever a miscop saves registers, it should make an escape frame. This +ensures that the ``current'' register contents can always be located by the +debugger. In this case, it may be desirable to be able to indicate that only +partial saving has been done. For example, we don't want to have to save all +the FP registers just so that we can use a couple extra general registers. + +When the debugger see an escape frame, it knows that register values are +located in the escape frame's ``register save'' area, rather than in the normal +save locations. + +It would be nice if there was a better solution to this internal error concept. +One problem is that it seems there is a substantial space penalty for emitting +all that error code, especially now that we don't share error code between +errors because we want to preserve the source context in the PC. But this +probably isn't really all that bad when considered as a fraction of the code. +For example, the check part of a type check is 12 bytes, whereas the error part +is usually only 6. In this case, we could never reduce the space overhead for +type checks by more than 1/3, thus the total code size reduction would be +small. This will be made even less important when we do type check +optimizations to reduce the number of type checks. + +Probably we should stick to the same general internal error mechanism, but make +it interact with the debugger better by allocating linkage registers and +allowing proceedable errors. We could support shared error calls and +non-proceedable errors when space is more important than debuggability, but +this is probably more complexity than is worthwhile. + +We jump or trap to a routine that saves the context (allocating at most the +return PC register). We then encode the error and context in the code +immediately following the jump/trap. (On the MIPS, the error code can be +encoded in the trap itself.) The error arguments would be encoded as +SC-offsets relative to the saved context. This could solve both the +arg-trashing problem and save space, since we could encode the SC-offsets more +tersely than the corresponding move instructions. diff --git a/doc/internals/cmu/design.tex b/doc/internals/cmu/design.tex new file mode 100644 index 0000000000..776ee1e994 --- /dev/null +++ b/doc/internals/cmu/design.tex @@ -0,0 +1,92 @@ +%%\documentstyle[cmu-titlepage]{report} % -*- Dictionary: design -*- +%\documentstyle{report} % -*- Dictionary: design -*- + +\documentclass{report} +\usepackage{ifpdf} +\usepackage{ifthen} +\usepackage{calc} +\usepackage{palatino} +\usepackage[hyperindex=false,colorlinks=false,urlcolor=blue]{hyperref} + +\title{Design of CMU Common Lisp} +\date{January 15, 2003} +\author{Robert A. MacLachlan (ed)} + +\ifpdf +\pdfinfo{ +/Author (Robert A. MacLachlan, ed) +/Title (Design of CMU Common Lisp) +} +% Add section numbers to the bookmarks, and open 2 levels by default. +\hypersetup{bookmarksnumbered=true, + bookmarksopen=true, + bookmarksopenlevel=2} +\fi +%%\trnumber{CMU-CS-91-???} + +%% This code taken from the LaTeX companion. It's meant as a +%% replacement for the description environment. We want one that +%% prints description items in a fixed size box and puts the +%% description itself on the same line or the next depending on the +%% size of the item. +\newcommand{\entrylabel}[1]{\mbox{#1}\hfil} +\newenvironment{entry}{% + \begin{list}{}% + {\renewcommand{\makelabel}{\entrylabel}% + \setlength{\labelwidth}{45pt}% + \setlength{\leftmargin}{\labelwidth+\labelsep}}}% + {\end{list}} + +\newlength{\Mylen} +\newcommand{\Lentrylabel}[1]{% + \settowidth{\Mylen}{#1}% + \ifthenelse{\lengthtest{\Mylen > \labelwidth}}% + {\parbox[b]{\labelwidth}% term > labelwidth + {\makebox[0pt][l]{#1}\\}}% + {#1}% + \hfil\relax} +\newenvironment{Lentry}{% + \renewcommand{\entrylabel}{\Lentrylabel} + \begin{entry}}% + {\end{entry}} + +\setcounter{tocdepth}{2} +\setcounter{secnumdepth}{3} +\def\textfraction{.1} +\def\bottomfraction{.9} % was .3 +\def\topfraction{.9} + +\newcommand{\code}[1]{\textnormal{{\sffamily #1}}} +%% Some common abbreviations +\newcommand{\cmucl}{\textsc{cmucl}} + +%% Set up margins +\setlength{\oddsidemargin}{-10pt} +\setlength{\evensidemargin}{-10pt} +\setlength{\topmargin}{-40pt} +\setlength{\headheight}{12pt} +\setlength{\headsep}{25pt} +\setlength{\footskip}{30pt} +\setlength{\textheight}{9.25in} +\setlength{\textwidth}{6.75in} +\setlength{\columnsep}{0.375in} +\setlength{\columnseprule}{0pt} + + +\begin{document} +\maketitle +\abstract{This report documents internal details of the CMU Common Lisp +compiler and run-time system. CMU Common Lisp is a public domain +implementation of Common Lisp that runs on various Unix workstations. +This document is a work in progress: neither the contents nor the +presentation are completed. Nevertheless, it provides some useful +background information, in particular regarding the \cmucl{} compiler.} + +\tableofcontents +\include{architecture} +\include{compiler} +\include{retargeting} +\include{run-time} +\appendix +\include{glossary} +\end{document} diff --git a/doc/internals/cmu/front.tex b/doc/internals/cmu/front.tex new file mode 100644 index 0000000000..1861c07b44 --- /dev/null +++ b/doc/internals/cmu/front.tex @@ -0,0 +1,968 @@ +\chapter{ICR conversion} % -*- Dictionary: design -*- + + +\section{Canonical forms} + +\#| + +Would be useful to have a Freeze-Type proclamation. Its primary use would be +to say that the indicated type won't acquire any new subtypes in the future. +This allows better open-coding of structure type predicates, since the possible +types that would satisfy the predicate will be constant at compile time, and +thus can be compiled as a skip-chain of EQ tests. + +Of course, this is only a big win when the subtypes are few: the most important +case is when there are none. If the closure of the subtypes is much larger +than the average number of supertypes of an inferior, then it is better to grab +the list of superiors out of the object's type, and test for membership in that +list. + +Should type-specific numeric equality be done by EQL rather than =? i.e. +should = on two fixnums become EQL and then convert to EQL/FIXNUM? +Currently we transform EQL into =, which is complicated, since we have to prove +the operands are the class of numeric type before we do it. Also, when EQL +sees one operand is a FIXNUM, it transforms to EQ, but the generator for EQ +isn't expecting numbers, so it doesn't use an immediate compare. + + +\subsection{Array hackery} + +Array type tests are transformed to \verb|%array-typep|, separation of the +implementation-dependent array-type handling. This way we can transform +STRINGP to: + +\begin{verbatim} + (or (simple-string-p x) + (and (complex-array-p x) + (= (array-rank x) 1) + (simple-string-p (%array-data x)))) +\end{verbatim} + +In addition to the similar bit-vector-p, we also handle vectorp and any type +tests on which the a dimension isn't wild. +[Note that we will want to expand into frobs compatible with those that +array references expand into so that the same optimizations will work on both.] + +These changes combine to convert hairy type checks into hairy typep's, and then +convert hairyp typeps into simple typeps. + + +Do we really need non-VOP templates? It seems that we could get the +desired effect through implementation-dependent ICR transforms. The +main risk would be of obscuring the type semantics of the code. We +could fairly easily retain all the type information present at the +time the tranform is run, but if we discover new type information, +then it won't be propagated unless the VM also supplies type inference +methods for its internal frobs (precluding the use of +\verb|%PRIMITIVE|, since primitives don't have derive-type methods.) + +I guess one possibility would be to have the call still considered ``known'' even +though it has been transformed. But this doesn't work, since we start doing +LET optimizations that trash the arglist once the call has been transformed +(and indeed we want to.) + +Actually, I guess the overhead for providing type inference methods for the +internal frobs isn't that great, since we can usually borrow the inference +method for a Common Lisp function. For example, in our AREF case: + +\begin{verbatim} + (aref x y) +==> + (let ((#:len (array-dimension x 0))) + (%unchecked-aref x (%check-in-bounds y #:len))) +\end{verbatim} + +Now in this case, if we made \verb|%UNCHECKED-AREF| have the same +derive-type method as AREF, then if we discovered something new about +X's element type, we could derive a new type for the entire +expression. + +Actually, it seems that baring this detail at the ICR level is +beneficial, since it admits the possibility of optimizing away the bounds +check using type information. If we discover X's dimensions, then +\verb|#:LEN| becomes a constant that can be substituted. Then +\verb|%CHECK-IN-BOUNDS| can notice that the bound is constant and +check it against the type for Y. If Y is known to be in range, then we +can optimize away the bounds check. + +Actually in this particular case, the best thing to do would be if we +discovered the bound is constant, then replace the bounds check with an +implicit type check. This way all the type check optimization mechanisms would +be brought into the act. + +So we actually want to do the bounds-check expansion as soon as possible, +rather than later than possible: it should be a source-transform, enabled by +the fast-safe policy. + +With multi-dimensional arrays we probably want to explicitly do the index +computation: this way portions of the index computation can become loop +invariants. In a scan in row-major order, the inner loop wouldn't have to do +any multiplication: it would only do an addition. We would use normal +fixnum arithmetic, counting on * to cleverly handle multiplication by a +constant, and appropriate inline expansion. + +Note that in a source transform, we can't make any assumptions the type of the +array. If it turns out to be a complex array without declared dimensions, then +the calls to ARRAY-DIMENSION will have to turn into a VOP that can be affected. +But if it is simple, then the VOP is unaffected, and if we know the bounds, it +is constant. Similarly, we would have %ARRAY-DATA and %ARRAY-DISPLACEMENT +operations. %ARRAY-DISPLACEMENT would optimize to 0 if we discover the array +is simple. [This is somewhat inefficient when the array isn't eventually +discovered to be simple, since finding the data and finding the displacement +duplicate each other. We could make %ARRAY-DATA return both as MVs, and then +optimize to (VALUES (%SIMPLE-ARRAY-DATA x) 0), but this would require +optimization of trivial VALUES uses.] + +Also need (THE (ARRAY * * * ...) x) to assert correct rank. + +|\# + +A bunch of functions have source transforms that convert them into the +canonical form that later parts of the compiler want to see. It is not legal +to rely on the canonical form since source transforms can be inhibited by a +Notinline declaration. This shouldn't be a problem, since everyone should keep +their hands off of Notinline calls. + +Some transformations: +\begin{verbatim} +Endp ==> (NULL (THE LIST ...)) +(NOT xxx) or (NULL xxx) => (IF xxx NIL T) + +(typep x '<simple type>) => (<simple predicate> x) +(typep x '<complex type>) => ...composition of simpler operations... +\end{verbatim} + +TYPEP of AND, OR and NOT types turned into conditionals over multiple TYPEP +calls. This makes hairy TYPEP calls more digestible to type constraint +propagation, and also means that the TYPEP code generators don't have to deal +with these cases. [\#\#\# In the case of union types we may want to do something +to preserve information for type constraint propagation.] + + +\begin{verbatim} + (apply \#'foo a b c) +==> + (multiple-value-call \#'foo (values a) (values b) (values-list c)) +\end{verbatim} + +This way only MV-CALL needs to know how to do calls with unknown numbers of +arguments. It should be nearly as efficient as a special-case VMR-Convert +method could be. + + +\begin{verbatim} +Make-String => Make-Array +N-arg predicates associated into two-arg versions. +Associate N-arg arithmetic ops. +Expand CxxxR and FIRST...nTH +Zerop, Plusp, Minusp, 1+, 1-, Min, Max, Rem, Mod +(Values x), (Identity x) => (Prog1 x) + +All specialized aref functions => (aref (the xxx) ...) +\end{verbatim} + +Convert (ldb (byte ...) ...) into internal frob that takes size and position as +separate args. Other byte functions also... + +Change for-value primitive predicates into \verb+(if <pred> t nil)+. This isn't +particularly useful during ICR phases, but makes life easy for VMR conversion. + + +This last can't be a source transformation, since a source transform can't tell +where the form appears. Instead, ICR conversion special-cases calls to known +functions with the Predicate attribute by doing the conversion when the +destination of the result isn't an IF. It isn't critical that this never be +done for predicates that we ultimately discover to deliver their value to an +IF, since IF optimizations will flush unnecessary IFs in a predicate. + + +\section{Inline functions} + +[\#\#\# Inline expansion is especially powerful in the presence of good lisp-level +optimization (``partial evaluation''). Many ``optimizations'' usually done in Lisp +compilers by special-case source-to-source transforms can be had simply by +making the source of the general case function available for inline expansion. +This is especially helpful in Common Lisp, which has many commonly used +functions with simple special cases but bad general cases (list and sequence +functions, for example.) + +Inline expansion of recursive functions is allowed, and is not as silly as it +sounds. When expanded in a specific context, much of the overhead of the +recursive calls may be eliminated (especially if there are many keyword +arguments, etc.) + +[Also have MAYBE-INLINE] +] + +We only record a function's inline expansion in the global environment when the +function is in the null lexical environment, since the expansion must be +represented as source. + +We do inline expansion of functions locally defined by FLET or LABELS even when +the environment is not null. Since the appearances of the local function must +be nested within the desired environment, it is possible to expand local +functions inline even when they use the environment. We just stash the source +form and environments in the Functional for the local function. When we +convert a call to it, we just reconvert the source in the saved environment. + +An interesting alternative to the inline/full-call dichotomy is ``semi-inline'' +coding. Whenever we have an inline expansion for a function, we can expand it +only once per block compilation, and then use local call to call this copied +version. This should get most of the speed advantage of real inline coding +with much less code bloat. This is especially attractive for simple system +functions such as Read-Char. + +The main place where true inline expansion would still be worth doing is where +large amounts of the function could be optimized away by constant folding or +other optimizations that depend on the exact arguments to the call. + + + +\section{Compilation policy} + +We want more sophisticated control of compilation safety than is offered in CL, +so that we can emit only those type checks that are likely to discover +something (i.e. external interfaces.) + + + +\section{Notes} + +Generalized back-end notion provides dynamic retargeting? (for byte code) + +The current node type annotations seem to be somewhat unsatisfactory, since we +lose information when we do a THE on a continuation that already has uses, or +when we convert a let where the actual result continuation has other uses. + +But the case with THE isn't really all that bad, since the test of whether +there are any uses happens before conversion of the argument, thus THE loses +information only when there are uses outside of the declared form. The LET +case may not be a big deal either. + +Note also that losing user assertions isn't really all that bad, since it won't +damage system integrity. At worst, it will cause a bug to go undetected. More +likely, it will just cause the error to be signaled in a different place (and +possibly in a less informative way). Of course, there is an efficiency hit for +losing type information, but if it only happens in strange cases, then this +isn't a big deal. + + +\chapter{Local call analysis} + +All calls to local functions (known named functions and LETs) are resolved to +the exact LAMBDA node which is to be called. If the call is syntactically +illegal, then we emit a warning and mark the reference as :notinline, forcing +the call to be a full call. We don't even think about converting APPLY calls; +APPLY is not special-cased at all in ICR. We also take care not to convert +calls in the top-level component, which would join it to normal code. Calls to +functions with rest args and calls with non-constant keywords are also not +converted. + +We also convert MV-Calls that look like MULTIPLE-VALUE-BIND to local calls, +since we know that they can be open-coded. We replace the optional dispatch +with a call to the last optional entry point, letting MV-Call magically default +the unsupplied values to NIL. + +When ICR optimizations discover a possible new local call, they explicitly +invoke local call analysis on the code that needs to be reanalyzed. + +[\#\#\# Let conversion. What it means to be a let. Argument type checking done +by caller. Significance of local call is that all callers are known, so +special call conventions may be used.] +A lambda called in only one place is called a ``let'' call, since a Let would +turn into one. + +In addition to enabling various ICR optimizations, the let/non-let distinction +has important environment significance. We treat the code in function and all +of the lets called by that function as being in the same environment. This +allows exits from lets to be treated as local exits, and makes life easy for +environment analysis. + +Since we will let-convert any function with only one call, we must be careful +about cleanups. It is possible that a lexical exit from the let function may +have to clean up dynamic bindings not lexically apparent at the exit point. We +handle this by annotating lets with any cleanup in effect at the call site. +The cleanup for continuations with no immediately enclosing cleanup is the +lambda that the continuation is in. In this case, we look at the lambda to see +if any cleanups need to be done. + +Let conversion is disabled for entry-point functions, since otherwise we might +convert the call from the XEP to the entry point into a let. Then later on, we +might want to convert a non-local reference into a local call, and not be able +to, since once a function has been converted to a let, we can't convert it +back. + + +A function's return node may also be deleted if it is unreachable, which can +happen if the function never returns normally. Such functions are not lets. + + +\chapter{Find components} + +This is a post-pass to ICR conversion that massages the flow graph into the +shape subsequent phases expect. Things done: + Compute the depth-first ordering for the flow graph. + Find the components (disconnected parts) of the flow graph. + +This pass need only be redone when newly converted code has been added to the +flow graph. The reanalyze flag in the component structure should be set by +people who mess things up. + +We create the initial DFO using a variant of the basic algorithm. The initial +DFO computation breaks the ICR up into components, which are parts that can be +compiled independently. This is done to increase the efficiency of large block +compilations. In addition to improving locality of reference and reducing the +size of flow analysis problems, this allows back-end data structures to be +reclaimed after the compilation of each component. + +ICR optimization can change the connectivity of the flow graph by discovering +new calls or eliminating dead code. Initial DFO determination splits up the +flow graph into separate components, but does so conservatively, ensuring that +parts that might become joined (due to local call conversion) are joined from +the start. Initial DFO computation also guarantees that all code which shares +a lexical environment is in the same component so that environment analysis +needs to operate only on a single component at a time. + +[This can get a bit hairy, since code seemingly reachable from the +environment entry may be reachable from a NLX into that environment. Also, +function references must be considered as links joining components even though +the flow graph doesn't represent these.] + +After initial DFO determination, components are neither split nor joined. The +standard DFO computation doesn't attempt to split components that have been +disconnected. + + +\chapter{ICR optimize} + +{\bf Somewhere describe basic ICR utilities: continuation-type, +constant-continuation-p, etc. Perhaps group by type in ICR description?} + +We are conservative about doing variable-for-variable substitution in ICR +optimization, since if we substitute a variable with a less restrictive type, +then we may prevent use of a ``good'' representation within the scope of the +inner binding. + +Note that variable-variable substitutions aren't really crucial in ICR, since +they don't create opportunities for new optimizations (unlike substitution of +constants and functions). A spurious variable-variable binding will show up as +a Move operation in VMR. This can be optimized away by reaching-definitions +and also by targeting. [\#\#\# But actually, some optimizers do see if operands +are the same variable.] + +\#| + +The IF-IF optimization can be modeled as a value driven optimization, since +adding a use definitely is cause for marking the continuation for +reoptimization. [When do we add uses? Let conversion is the only obvious +time.] I guess IF-IF conversion could also be triggered by a non-immediate use +of the test continuation becoming immediate, but to allow this to happen would +require Delete-Block (or somebody) to mark block-starts as needing to be +reoptimized when a predecessor changes. It's not clear how important it is +that IF-IF conversion happen under all possible circumstances, as long as it +happens to the obvious cases. + +[\#\#\# It isn't totally true that code flushing never enables other worthwhile +optimizations. Deleting a functional reference can cause a function to cease +being an XEP, or even trigger let conversion. It seems we still want to flush +code during ICR optimize, but maybe we want to interleave it more intimately +with the optimization pass. + +Ref-flushing works just as well forward as backward, so it could be done in the +forward pass. Call flushing doesn't work so well, but we could scan the block +backward looking for any new flushable stuff if we flushed a call on the +forward pass. + +When we delete a variable due to lack of references, we leave the variable +in the lambda-list so that positional references still work. The initial value +continuation is flushed, though (replaced with NIL) allowing the initial value +for to be deleted (modulo side-effects.) + +Note that we can delete vars with no refs even when they have sets. I guess +when there are no refs, we should also flush all sets, allowing the value +expressions to be flushed as well. + +Squeeze out single-reference unset let variables by changing the dest of the +initial value continuation to be the node that receives the ref. This can be +done regardless of what the initial value form is, since we aren't actually +moving the evaluation. Instead, we are in effect using the continuation's +locations in place of the temporary variable. + +Doing this is of course, a wild violation of stack discipline, since the ref +might be inside a loop, etc. But with the VMR back-end, we only need to +preserve stack discipline for unknown-value continuations; this ICR +transformation must be already inhibited when the DEST of the REF is a +multiple-values receiver (EXIT, RETURN or MV-COMBINATION), since we must +preserve the single-value semantics of the let-binding in this case. + +The REF and variable must be deleted as part of this operation, since the ICR +would otherwise be left in an inconsistent state; we can't wait for the REF to +be deleted due to being unused, since we have grabbed the arg continuation and +substituted it into the old DEST. + +The big reason for doing this transformation is that in macros such as INCF and +PSETQ, temporaries are squeezed out, and the new value expression is evaluated +directly to the setter, allowing any result type assertion to be applied to the +expression evaluation. Unlike in the case of substitution, there is no point +in inhibiting this transformation when the initial value type is weaker than +the variable type. Instead, we intersect the asserted type for the old REF's +CONT with the type assertion on the initial value continuation. Note that the +variable's type has already been asserted on the initial-value continuation. + +Of course, this transformation also simplifies the ICR even when it doesn't +discover interesting type assertions, so it makes sense to do it whenever +possible. This reduces the demands placed on register allocation, etc. + + +There are three dead-code flushing rules: + +\begin{enumerate} +\item Refs with no DEST may be flushed. + +\item Known calls with no dest that are flushable may be flushed. We null the +DEST in all the args. + +\item If a lambda-var has no refs, then it may be deleted. The flushed + argument continuations have their DEST nulled. +\end{enumerate} + +These optimizations all enable one another. We scan blocks backward, looking +for nodes whose CONT has no DEST, then type-dispatching off of the node. If we +delete a ref, then we check to see if it is a lambda-var with no refs. When we +flush an argument, we mark the blocks for all uses of the CONT as needing to be +reoptimized. + + +\section{Goals for ICR optimizations} + +\#| + +When an optimization is disabled, code should still be correct and not +ridiculously inefficient. Phases shouldn't be made mandatory when they have +lots of non-required stuff jammed into them. + +|\# + +This pass is optional, but is desirable if anything is more important than +compilation speed. + +This phase is a grab-bag of optimizations that concern themselves with the flow +of values through the code representation. The main things done are type +inference, constant folding and dead expression elimination. This phase can be +understood as a walk of the expression tree that propagates assertions down the +tree and propagates derived information up the tree. The main complication is +that there isn't any expression tree, since ICR is flow-graph based. + +We repeat this pass until we don't discover anything new. This is a bit of +feat, since we dispatch to arbitrary functions which may do arbitrary things, +making it hard to tell if anything really happened. Even if we solve this +problem by requiring people to flag when they changed or by checking to see if +they changed something, there are serious efficiency problems due to massive +redundant computation, since in many cases the only way to tell if anything +changed is to recompute the value and see if it is different from the old one. + +We solve this problem by requiring that optimizations for a node only depend on +the properties of the CONT and the continuations that have the node as their +DEST. If the continuations haven't changed since the last pass, then we don't +attempt to re-optimize the node, since we know nothing interesting will happen. + +We keep track of which continuations have changed by a REOPTIMIZE flag that is +set whenever something about the continuation's value changes. + +When doing the bottom up pass, we dispatch to type specific code that knows how +to tell when a node needs to be reoptimized and does the optimization. These +node types are special-cased: COMBINATION, IF, RETURN, EXIT, SET. + +The REOPTIMIZE flag in the COMBINATION-FUN is used to detect when the function +information might have changed, so that we know when there are new assertions +that could be propagated from the function type to the arguments. + +When we discover something about a leaf, or substitute for leaf, we reoptimize +the CONT for all the REF and SET nodes. + +We have flags in each block that indicate when any nodes or continuations in +the block need to be re-optimized, so we don't have to scan blocks where there +is no chance of anything happening. + +It is important for efficiency purposes that optimizers never say that they did +something when they didn't, but this by itself doesn't guarantee timely +termination. I believe that with the type system implemented, type inference +will converge in finite time, but as a practical matter, it can take far too +long to discover not much. For this reason, ICR optimization is terminated +after three consecutive passes that don't add or delete code. This premature +termination only happens 2\% of the time. + + +\section{Flow graph simplification} + +Things done: + +\begin{itemize} +\item Delete blocks with no predecessors. +\item Merge blocks that can be merged. +\item Convert local calls to Let calls. +\item Eliminate degenerate IFs. +\end{itemize} + +We take care not to merge blocks that are in different functions or have +different cleanups. This guarantees that non-local exits are always at block +ends and that cleanup code never needs to be inserted within a block. + +We eliminate IFs with identical consequent and alternative. This would most +likely happen if both the consequent and alternative were optimized away. + +[Could also be done if the consequent and alternative were different blocks, +but computed the same value. This could be done by a sort of cross-jumping +optimization that looked at the predecessors for a block and merged code shared +between predecessors. IFs with identical branches would eventually be left +with nothing in their branches.] + +We eliminate IF-IF constructs: + +\begin{verbatim} + (IF (IF A B C) D E) ==> + (IF A (IF B D E) (IF C D E)) +\end{verbatim} + +In reality, what we do is replicate blocks containing only an IF node where the +predicate continuation is the block start. We make one copy of the IF node for +each use, leaving the consequent and alternative the same. If you look at the +flow graph representation, you will see that this is really the same thing as +the above source to source transformation. + + +\section{Forward ICR optimizations} + +In the forward pass, we scan the code in forward depth-first order. We +examine each call to a known function, and: + +\begin{itemize} +\item Eliminate any bindings for unused variables. + +\item Do top-down type assertion propagation. In local calls, we propagate +asserted and derived types between the call and the called lambda. + +\item + Replace calls of foldable functions with constant arguments with the + result. We don't have to actually delete the call node, since Top-Down + optimize will delete it now that its value is unused. + +\item + Run any Optimizer for the current function. The optimizer does arbitrary + transformations by hacking directly on the IR. This is useful primarily + for arithmetic simplification and similar things that may need to examine + and modify calls other than the current call. The optimizer is responsible + for recording any changes that it makes. An optimizer can inhibit further + optimization of the node during the current pass by returning true. This + is useful when deleting the node. + +\item + Do ICR transformations, replacing a global function call with equivalent + inline lisp code. + +\item + Do bottom-up type propagation/inferencing. For some functions such as + Coerce we will dispatch to a function to find the result type. The + Derive-Type function just returns a type structure, and we check if it is + different from the old type in order to see if there was a change. + +\item + Eliminate IFs with predicates known to be true or false. + +\item + Substitute the value for unset let variables that are bound to constants, + unset lambda variables or functionals. + +\item + Propagate types from local call args to var refs. +\end{itemize} + +We use type info from the function continuation to find result types for +functions that don't have a derive-type method. + + +\subsection{ICR transformation} + +ICR transformation does ``source to source'' transformations on known global +functions, taking advantage of semantic information such as argument types and +constant arguments. Transformation is optional, but should be done if speed or +space is more important than compilation speed. Transformations which increase +space should pass when space is more important than speed. + +A transform is actually an inline function call where the function is computed +at compile time. The transform gets to peek at the continuations for the +arguments, and computes a function using the information gained. Transforms +should be cautious about directly using the values of constant continuations, +since the compiler must preserve eqlness of named constants, and it will have a +hard time if transforms go around randomly copying constants. + +The lambda that the transform computes replaces the original function variable +reference as the function for the call. This lets the compiler worry about +evaluating each argument once in the right order. We want to be careful to +preserve type information when we do a transform, since it may be less than +obvious what the transformed code does. + +There can be any number of transforms for a function. Each transform is +associated with a function type that the call must be compatible with. A +transform is only invoked if the call has the right type. This provides a way +to deal with the common case of a transform that only applies when the +arguments are of certain types and some arguments are not specified. We always +use the derived type when determining whether a transform is applicable. Type +check is responsible for setting the derived type to the intersection of the +asserted and derived types. + +If the code in the expansion has insufficient explicit or implicit argument +type checking, then it should cause checks to be generated by making +declarations. + +A transformation may decide to pass if it doesn't like what it sees when it +looks at the args. The Give-Up function unwinds out of the transform and deals +with complaining about inefficiency if speed is more important than brevity. +The format args for the message are arguments to Give-Up. If a transform can't +be done, we just record the message where ICR finalize can find it. note. We +can't complain immediately, since it might get transformed later on. + + +\section{Backward ICR optimizations} + +In the backward pass, we scan each block in reverse order, and +eliminate any effectless nodes with unused values. In ICR this is the +only way that code is deleted other than the elimination of unreachable blocks. + + +\chapter{Type checking} + +% Somehow split this section up into three parts: +% -- Conceptual: how we know a check is necessary, and who is responsible for +% doing checks. +% -- Incremental: intersection of derived and asserted types, checking for +% non-subtype relationship. +% -- Check generation phase. + +We need to do a pretty good job of guessing when a type check will ultimately +need to be done. Generic arithmetic, for example: In the absence of +declarations, we will use the safe variant, but if we don't know this, we +will generate a check for NUMBER anyway. We need to look at the fast-safe +templates and guess if any of them could apply. + +We compute a function type from the VOP arguments +and assertions on those arguments. This can be used with Valid-Function-Use +to see which templates do or might apply to a particular call. If we guess +that a safe implementation will be used, then we mark the continuation so as to +force a safe implementation to be chosen. [This will happen if ICR optimize +doesn't run to completion, so the ICR optimization after type check generation +can discover new type information. Since we won't redo type check at that +point, there could be a call that has applicable unsafe templates, but isn't +type checkable.] + +[\#\#\# A better and more general optimization of structure type checks: in type +check conversion, we look at the *original derived* type of the continuation: +if the difference between the proven type and the asserted type is a simple +type check, then check for the negation of the difference. e.g. if we want a +FOO and we know we've got (OR FOO NULL), then test for (NOT NULL). This is a +very important optimization for linked lists of structures, but can also apply +in other situations.] + +If after ICR phases, we have a continuation with check-type set in a context +where it seems likely a check will be emitted, and the type is too +hairy to be easily checked (i.e. no CHECK-xxx VOP), then we do a transformation +on the ICR equivalent to: + +\begin{verbatim} + (... (the hair <foo>) ...) +==> + (... (funcall \#'(lambda (\#:val) + (if (typep \#:val 'hair) + \#:val + (%type-check-error \#:val 'hair))) + <foo>) + ...) +\end{verbatim} +This way, we guarantee that VMR conversion never has to emit type checks for +hairy types. + +[Actually, we need to do a MV-bind and several type checks when there is a MV +continuation. And some values types are just too hairy to check. We really +can't check any assertion for a non-fixed number of values, since there isn't +any efficient way to bind arbitrary numbers of values. (could be done with +MV-call of a more-arg function, I guess...) +] + +[Perhaps only use CHECK-xxx VOPs for types equivalent to a ptype? Exceptions +for CONS and SYMBOL? Anyway, no point in going to trouble to implement and +emit rarely used CHECK-xxx vops.] + +One potential lose in converting a type check to explicit conditionals rather +than to a CHECK-xxx VOP is that VMR code motion optimizations won't be able to +do anything. This shouldn't be much of an issue, though, since type constraint +propagation has already done global optimization of type checks. + + +This phase is optional, but should be done if anything is more important than +compile speed. + +Type check is responsible for reconciling the continuation asserted and derived +types, emitting type checks if appropriate. If the derived type is a subtype +of the asserted type, then we don't need to do anything. + +If there is no intersection between the asserted and derived types, then there +is a manifest type error. We print a warning message, indicating that +something is almost surely wrong. This will inhibit any transforms or +generators that care about their argument types, yet also inhibits further +error messages, since NIL is a subtype of every type. + +If the intersection is not null, then we set the derived type to the +intersection of the asserted and derived types and set the Type-Check flag in +the continuation. We always set the flag when we can't prove that the type +assertion is satisfied, regardless of whether we will ultimately actually emit +a type check or not. This is so other phases such as type constraint +propagation can use the Type-Check flag to detect an interesting type +assertion, instead of having to duplicate much of the work in this phase. +[\#\#\# 7 extremely random values for CONTINUATION-TYPE-CHECK.] + +Type checks are generated on the fly during VMR conversion. When VMR +conversion generates the check, it prints an efficiency note if speed is +important. We don't flame now since type constraint progpagation may decide +that the check is unnecessary. [\#\#\# Not done now, maybe never.] + +In local function call, it is the caller that is in effect responsible for +checking argument types. This happens in the same way as any other type check, +since ICR optimize propagates the declared argument types to the type +assertions for the argument continuations in all the calls. + +Since the types of arguments to entry points are unknown at compile time, we +want to do runtime checks to ensure that the incoming arguments are of the +correct type. This happens without any special effort on the part of type +check, since the XEP is represented as a local call with unknown type +arguments. These arguments will be marked as needing to be checked. + + +\chapter{Constraint propagation} + +New lambda-var-slot: + +constraints: a list of all the constraints on this var for either X or Y. + +How to maintain consistency? Does it really matter if there are constraints +with deleted vars lying around? Note that whatever mechanism we use for +getting the constraints in the first place should tend to keep them up to date. +Probably we would define optimizers for the interesting relations that look at +their CONT's dest and annotate it if it is an IF. + +But maybe it is more trouble then it is worth trying to build up the set of +constraints during ICR optimize (maintaining consistency in the process). +Since ICR optimize iterates a bunch of times before it converges, we would be +wasting time recomputing the constraints, when nobody uses them till constraint +propagation runs. + +It seems that the only possible win is if we re-ran constraint propagation +(which we might want to do.) In that case, we wouldn't have to recompute all +the constraints from scratch. But it seems that we could do this just as well +by having ICR optimize invalidate the affected parts of the constraint +annotation, rather than trying to keep them up to date. This also fits better +with the optional nature of constraint propagation, since we don't want ICR +optimize to commit to doing a lot of the work of constraint propagation. + +For example, we might have a per-block flag indicating that something happened +in that block since the last time constraint propagation ran. We might have +different flags to represent the distinction between discovering a new type +assertion inside the block and discovering something new about an if +predicate, since the latter would be cheaper to update and probably is more +common. + +It's fairly easy to see how we can build these sets of restrictions and +propagate them using flow analysis, but actually using this information seems +a bit more ad-hoc. + +Probably the biggest thing we do is look at all the refs. If we have proven that +the value is EQ (EQL for a number) to some other leaf (constant or lambda-var), +then we can substitute for that reference. In some cases, we will want to do +special stuff depending on the DEST. If the dest is an IF and we proved (not +null), then we can substitute T. And if the dest is some relation on the same +two lambda-vars, then we want to see if we can show that relation is definitely +true or false. + +Otherwise, we can do our best to invert the set of restrictions into a type. +Since types hold only constant info, we have to ignore any constraints between +two vars. We can make some use of negated type restrictions by using +TYPE-DIFFERENCE to remove the type from the ref types. If our inferred type is +as good as the type assertion, then the continuation's type-check flag will be +cleared. + +It really isn't much of a problem that we don't infer union types on joins, +since union types are relatively easy to derive without using flow information. +The normal bottom-up type inference done by ICR optimize does this for us: it +annotates everything with the union of all of the things it might possibly be. +Then constraint propagation subtracts out those types that can't be in effect +because of predicates or checks. + + + +This phase is optional, but is desirable if anything is more important than +compilation speed. We use an algorithm similar to available expressions to +propagate variable type information that has been discovered by implicit or +explicit type tests, or by type inference. + +We must do a pre-pass which locates set closure variables, since we cannot do +flow analysis on such variables. We set a flag in each set closure variable so +that we can quickly tell that it is losing when we see it again. Although this +may seem to be wastefully redundant with environment analysis, the overlap +isn't really that great, and the cost should be small compared to that of the +flow analysis that we are preparing to do. [Or we could punt on set +variables...] + +A type constraint is a structure that includes sset-element and has +the type and variable. [Also a not-p flag indicating whether the sense +is negated.] + +Each variable has a list of its type constraints. We create a type +constraint when we see a type test or check. If there is already a +constraint for the same variable and type, then we just re-use it. If +there is already a weaker constraint, then we generate both the weak +constraints and the strong constraint so that the weak constraints +won't be lost even if the strong one is unavailable. + +We find all the distinct type constraints for each variable during the pre-pass +over the lambda nesting. Each constraint has a list of the weaker constraints +so that we can easily generate them. + +Every block generates all the type constraints in it, but a constraint is +available in a successor only if it is available in all predecessors. We +determine the actual type constraint for a variable at a block by intersecting +all the available type constraints for that variable. + +This isn't maximally tense when there are constraints that are not +hierarchically related, e.g. (or a b) (or b c). If these constraints were +available from two predecessors, then we could infer that we have an (or a b c) +constraint, but the above algorithm would come up with none. This probably +isn't a big problem. + +[\#\#\# Do we want to deal with \verb+(if (eq <var> '<foo>) ...)+ indicating singleton +member type?] + +We detect explicit type tests by looking at type test annotation in the IF +node. If there is a type check, the OUT sets are stored in the node, with +different sets for the consequent and alternative. Implicit type checks are +located by finding Ref nodes whose Cont has the Type-Check flag set. We don't +actually represent the GEN sets, we just initialize OUT to it, and then form +the union in place. + +When we do the post-pass, we clear the Type-Check flags in the continuations +for Refs when we discover that the available constraints satisfy the asserted +type. Any explicit uses of typep should be cleaned up by the ICR optimizer for +typep. We can also set the derived type for Refs to the intersection of the +available type assertions. If we discover anything, we should consider redoing +ICR optimization, since better type information might enable more +optimizations. + + +\chapter{ICR finalize} % -*- Dictionary: design -*- + +This pass looks for interesting things in the ICR so that we can forget about +them. Used and not defined things are flamed about. + +We postpone these checks until now because the ICR optimizations may discover +errors that are not initially obvious. We also emit efficiency notes about +optimizations that we were unable to do. We can't emit the notes immediately, +since we don't know for sure whether a repeated attempt at optimization will +succeed. + +We examine all references to unknown global function variables and update the +approximate type accordingly. We also record the names of the unknown +functions so that they can be flamed about if they are never defined. Unknown +normal variables are flamed about on the fly during ICR conversion, so we +ignore them here. + +We check each newly defined global function for compatibility with previously +recorded type information. If there is no :defined or :declared type, then we +check for compatibility with any approximate function type inferred from +previous uses. + + + +\chapter{Environment analysis} + +A related change would be to annotate ICR with information about tail-recursion +relations. What we would do is add a slot to the node structure that points to +the corresponding Tail-Info when a node is in a TR position. This annotation +would be made in a final ICR pass that runs after cleanup code is generated +(part of environment analysis). When true, the node is in a true TR position +(modulo return-convention incompatibility). When we determine return +conventions, we null out the tail-p slots in XEP calls or known calls where we +decided not to preserve tail-recursion. + + +In this phase, we also check for changes in the dynamic binding environment +that require cleanup code to be generated. We just check for changes in the +Continuation-Cleanup on local control transfers. If it changes from +an inner dynamic context to an outer one that is in the same environment, then +we emit code to clean up the dynamic bindings between the old and new +continuation. We represent the result of cleanup detection to the back end by +interposing a new block containing a call to a funny function. Local exits +from CATCH or UNWIND-PROTECT are detected in the same way. + + +|\# + +The primary activity in environment analysis is the annotation of ICR with +environment structures describing where variables are allocated and what values +the environment closes over. + +Each lambda points to the environment where its variables are allocated, and +the environments point back. We always allocate the environment at the Bind +node for the sole non-let lambda in the environment, so there is a close +relationship between environments and functions. Each ``real function'' (i.e. +not a LET) has a corresponding environment. + +We attempt to share the same environment among as many lambdas as possible so +that unnecessary environment manipulation is not done. During environment +analysis the only optimization of this sort is realizing that a Let (a lambda +with no Return node) cannot need its own environment, since there is no way +that it can return and discover that its old values have been clobbered. + +When the function is called, values from other environments may need to be made +available in the function's environment. These values are said to be ``closed +over''. + +Even if a value is not referenced in a given environment, it may need to be +closed over in that environment so that it can be passed to a called function +that does reference the value. When we discover that a value must be closed +over by a function, we must close over the value in all the environments where +that function is referenced. This applies to all references, not just local +calls, since at other references we must have the values on hand so that we can +build a closure. This propagation must be applied recursively, since the value +must also be available in *those* functions' callers. + +If a closure reference is known to be ``safe'' (not an upward funarg), then the +closure structure may be allocated on the stack. + +Closure analysis deals only with closures over values, while Common Lisp +requires closures over variables. The difference only becomes significant when +variables are set. If a variable is not set, then we can freely make copies of +it without keeping track of where they are. When a variable is set, we must +maintain a single value cell, or at least the illusion thereof. We achieve +this by creating a heap-allocated ``value cell'' structure for each set variable +that is closed over. The pointer to this value cell is passed around as the +``value'' corresponding to that variable. References to the variable must +explicitly indirect through the value cell. + +When we are scanning over the lambdas in the component, we also check for bound +but not referenced variables. + +Environment analysis emits cleanup code for local exits and markers for +non-local exits. + +A non-local exit is a control transfer from one environment to another. In a +non-local exit, we must close over the continuation that we transfer to so that +the exiting function can find its way back. We indicate the need to close a +continuation by placing the continuation structure in the closure and also +pushing it on a list in the environment structure for the target of the exit. +[\#\#\# To be safe, we would treat the continuation as a set closure variable so +that we could invalidate it when we leave the dynamic extent of the exit point. +Transferring control to a meaningless stack pointer would be apt to cause +horrible death.] + +Each local control transfer may require dynamic state such as special bindings +to be undone. We represent cleanup actions by funny function calls in a new +block linked in as an implicit MV-PROG1. + diff --git a/doc/internals/cmu/glossary.tex b/doc/internals/cmu/glossary.tex new file mode 100644 index 0000000000..e77bab5e3b --- /dev/null +++ b/doc/internals/cmu/glossary.tex @@ -0,0 +1,411 @@ +\chapter{Glossary}% -*- Dictionary: int:design -*- + +% Note: in an entry, any word that is also defined should be \it +% should entries have page references as well? + +\begin{description} +\item[assert (a type)] +In Python, all type checking is done via a general type assertion +mechanism. Explicit declarations and implicit assertions (e.g. the arg to ++ is a number) are recorded in the front-end (implicit continuation) +representation. Type assertions (and thus type-checking) are ``unbundled'' +from the operations that are affected by the assertion. This has two major +advantages: +\begin{itemize} +\item Code that implements operations need not concern itself with checking +operand types. + +\item Run-time type checks can be eliminated when the compiler can prove that +the assertion will always be satisfied. +\end{itemize} +See also {\it restrict}. + +\item[back end] The back end is the part of the compiler that operates on the +{\it virtual machine} intermediate representation. Also included are the +compiler phases involved in the conversion from the {\it front end} +representation (or {\it ICR}). + +\item[bind node] This is a node type the that marks the start of a {\it lambda} +body in {\it ICR}. This serves as a placeholder for environment manipulation +code. + +\item[IR1] The first intermediate representation, also known as {\it ICR}, or +the Implicit Continuation Represenation. + +\item[IR2] The second intermediate representation, also known as {\it VMR}, or +the Virtual Machine Representation. + +\item[basic block] A basic block (or simply ``block'') has the pretty much the +usual meaning of representing a straight-line sequence of code. However, the +code sequence ultimately generated for a block might contain internal branches +that were hidden inside the implementation of a particular operation. The type +of a block is actually {\tt cblock}. The {\tt block-info} slot holds an +{\tt VMR-block} containing backend information. + +\item[block compilation] Block compilation is a term commonly used to describe +the compile-time resolution of function names. This enables many +optimizations. + +\item[call graph] +Each node in the call graph is a function (represented by a {\it flow graph}.) +The arcs in the call graph represent a possible call from one function to +another. See also {\it tail set}. + +\item[cleanup] +A cleanup is the part of the implicit continuation representation that +retains information scoping relationships. For indefinite extent bindings +(variables and functions), we can abandon scoping information after ICR +conversion, recovering the lifetime information using flow analysis. But +dynamic bindings (special values, catch, unwind protect, etc.) must be +removed at a precise time (whenever the scope is exited.) Cleanup +structures form a hierarchy that represents the static nesting of dynamic +binding structures. When the compiler does a control transfer, it can use +the cleanup information to determine what cleanup code needs to be emitted. + +\item[closure variable] +A closure variable is any lexical variable that has references outside of +its {\it home environment}. See also {\it indirect value cell}. + +\item[closed continuation] A closed continuation represents a {\tt tagbody} tag +or {\tt block} name that is closed over. These two cases are mostly +indistinguishable in {\it ICR}. + +\item[home] Home is a term used to describe various back-pointers. A lambda +variable's ``home'' is the lambda that the variable belongs to. A lambda's ``home +environment'' is the environment in which that lambda's variables are allocated. + +\item[indirect value cell] +Any closure variable that has assignments ({\tt setq}s) will be allocated in an +indirect value cell. This is necessary to ensure that all references to +the variable will see assigned values, since the compiler normally freely +copies values when creating a closure. + +\item[set variable] Any variable that is assigned to is called a ``set +variable''. Several optimizations must special-case set variables, and set +closure variables must have an {\it indirect value cell}. + +\item[code generator] The code generator for a {\it VOP} is a potentially +arbitrary list code fragment which is responsible for emitting assembly code to +implement that VOP. + +\item[constant pool] The part of a compiled code object that holds pointers to +non-immediate constants. + +\item[constant TN] +A constant TN is the {\it VMR} of a compile-time constant value. A +constant may be immediate, or may be allocated in the {\it constant pool}. + +\item[constant leaf] +A constant {\it leaf} is the {\it ICR} of a compile-time constant value. + +\item[combination] +A combination {\it node} is the {\it ICR} of any fixed-argument function +call (not {\tt apply} or {\tt multiple-value-call}.) + +\item[top-level component] +A top-level component is any component whose only entry points are top-level +lambdas. + +\item[top-level lambda] +A top-level lambda represents the execution of the outermost form on which +the compiler was invoked. In the case of {\tt compile-file}, this is often a +truly top-level form in the source file, but the compiler can recursively +descend into some forms ({\tt eval-when}, etc.) breaking them into separate +compilations. + +\item[component] A component is basically a sequence of blocks. Each component +is compiled into a separate code object. With {\it block compilation} or {\it +local functions}, a component will contain the code for more than one function. +This is called a component because it represents a connected portion of the +call graph. Normally the blocks are in depth-first order ({\it DFO}). + +\item[component, initial] During ICR conversion, blocks are temporarily +assigned to initial components. The ``flow graph canonicalization'' phase +determines the true component structure. + +\item[component, head and tail] +The head and tail of a component are dummy blocks that mark the start and +end of the {\it DFO} sequence. The component head and tail double as the root +and finish node of the component's flow graph. + +\item[local function (call)] +A local function call is a call to a function known at compile time to be +in the same {\it component}. Local call allows compile time resolution of the +target address and calling conventions. See {\it block compilation}. + +\item[conflict (of TNs, set)] +Register allocation terminology. Two TNs conflict if they could ever be +live simultaneously. The conflict set of a TN is all TNs that it conflicts +with. + +\item[continuation] +The ICR data structure which represents both: +\begin{itemize} +\item The receiving of a value (or multiple values), and + +\item A control location in the flow graph. +\end{itemize} +In the Implicit Continuation Representation, the environment is implicit in the +continuation's BLOCK (hence the name.) The ICR continuation is very similar to +a CPS continuation in its use, but its representation doesn't much resemble (is +not interchangeable with) a lambda. + +\item[cont] A slot in the {\it node} holding the {\it continuation} which +receives the node's value(s). Unless the node ends a {\it block}, this also +implicitly indicates which node should be evaluated next. + +\item[cost] Approximations of the run-time costs of operations are widely used +in the back end. By convention, the unit is generally machine cycles, but the +values are only used for comparison between alternatives. For example, the +VOP cost is used to determine the preferred order in which to try possible +implementations. + +\item[CSP, CFP] See {\it control stack pointer} and {\it control frame +pointer}. + +\item[Control stack] The main call stack, which holds function stack frames. +All words on the control stack are tagged {\it descriptors}. In all ports done +so far, the control stack grows from low memory to high memory. The most +recent call frames are considered to be ``on top'' of earlier call frames. + +\item[Control stack pointer] The allocation pointer for the {\it control +stack}. Generally this points to the first free word at the top of the stack. + +\item[Control frame pointer] The pointer to the base of the {\it control stack} +frame for a particular function invocation. The CFP for the running function +must be in a register. + +\item[Number stack] The auxiliary stack used to hold any {\it non-descriptor} +(untagged) objects. This is generally the same as the C call stack, and thus +typically grows down. + +\item[Number stack pointer] The allocation pointer for the {\it number stack}. +This is typically the C stack pointer, and is thus kept in a register. + +\item[NSP, NFP] See {\it number stack pointer}, {\it number frame pointer}. + +\item[Number frame pointer] The pointer to the base of the {\it number stack} +frame for a particular function invocation. Functions that don't use the +number stack won't have an NFP, but if an NFP is allocated, it is always +allocated in a particular register. If there is no variable-size data on the +number stack, then the NFP will generally be identical to the NSP. + +\item[Lisp return address] The name of the {\it descriptor} encoding the +``return pc'' for a function call. + +\item[LRA] See {\it lisp return address}. Also, the name of the register where +the LRA is passed. + + +\item[Code pointer] A pointer to the header of a code object. The code pointer +for the currently running function is stored in the {\tt code} register. + +\item[Interior pointer] A pointer into the inside of some heap-allocated +object. Interior pointers confuse the garbage collector, so their use is +highly constrained. Typically there is a single register dedicated to holding +interior pointers. + +\item[dest] +A slot in the {\it continuation} which points the the node that receives this +value. Null if this value is not received by anyone. + +\item[DFN, DFO] See {\it Depth First Number}, {\it Depth First Order}. + +\item[Depth first number] Blocks are numbered according to their appearance in +the depth-first ordering (the {\tt block-number} slot.) The numbering actually +increases from the component tail, so earlier blocks have larger numbers. + +\item[Depth first order] This is a linearization of the flow graph, obtained by +a depth-first walk. Iterative flow analysis algorithms work better when blocks +are processed in DFO (or reverse DFO.) + + +\item[Object] In low-level design discussions, an object is one of the +following: +\begin{itemize} +\item a single word containing immediate data (characters, fixnums, etc) +\item a single word pointing to an object (structures, conses, etc.) +\end{itemize} +These are tagged with three low-tag bits as described in the section +\ref{sec:tagging} This is synonymous with {\it descriptor}. +In other parts of the documentation, may be used more loosely to refer to a +{\it lisp object}. + +\item[Lisp object] +A Lisp object is a high-level object discussed as a data type in the Common +Lisp definition. + +\item[Data-block] +A data-block is a dual-word aligned block of memory that either manifests a +Lisp object (vectors, code, symbols, etc.) or helps manage a Lisp object on +the heap (array header, function header, etc.). + +\item[Descriptor] +A descriptor is a tagged, single-word object. It either contains immediate +data or a pointer to data. This is synonymous with {\it object}. Storage +locations that must contain descriptors are referred to as descriptor +locations. + +\item[Pointer descriptor] +A descriptor that points to a {\it data block} in memory (i.e. not an immediate +object.) + +\item[Immediate descriptor] +A descriptor that encodes the object value in the descriptor itself; used for +characters, fixnums, etc. + +\item[Word] +A word is a 32-bit quantity. + +\item[Non-descriptor] +Any chunk of bits that isn't a valid tagged descriptor. For example, a +double-float on the number stack. Storage locations that are not scanned by +the garbage collector (and thus cannot contain {\it pointer descriptors}) are +called non-descriptor locations. {\it Immediate descriptors} can be stored in +non-descriptor locations. + + +\item[Entry point] An entry point is a function that may be subject to +``unpredictable'' control transfers. All entry points are linked to the root +of the flow graph (the component head.) The only functions that aren't entry +points are {\it let} functions. When complex lambda-list syntax is used, +multiple entry points may be created for a single lisp-level function. +See {\it external entry point}. + +\item[External entry point] A function that serves as a ``trampoline'' to +intercept function calls coming in from outside of the component. The XEP does +argument syntax and type checking, and may also translate the arguments and +return values for a locally specialized calling calling convention. + +\item[XEP] An {\it external entry point}. + +\item[lexical environment] A lexical environment is a structure that is used +during VMR conversion to represent all lexically scoped bindings (variables, +functions, declarations, etc.) Each {\tt node} is annotated with its lexical +environment, primarily for use by the debugger and other user interfaces. This +structure is also the environment object passed to {\tt macroexpand}. + +\item[environment] The environment is part of the ICR, created during +environment analysis. Environment analysis apportions code to disjoint +environments, with all code in the same environment sharing the same stack +frame. Each environment has a ``{\it real}'' function that allocates it, and +some collection {\tt let} functions. Although environment analysis is the +last ICR phase, in earlier phases, code is sometimes said to be ``in the +same/different environment(s)''. This means that the code will definitely be +in the same environment (because it is in the same real function), or that is +might not be in the same environment, because it is not in the same function. + +\item[fixup] Some sort of back-patching annotation. The main sort encountered +are load-time {\it assembler fixups}, which are a linkage annotation mechanism. + +\item[flow graph] A flow graph is a directed graph of basic blocks, where each +arc represents a possible control transfer. The flow graph is the basic data +structure used to represent code, and provides direct support for data flow +analysis. See component and ICR. + +\item[foldable] An attribute of {\it known functions}. A function is foldable +if calls may be constant folded whenever the arguments are compile-time +constant. Generally this means that it is a pure function with no side +effects. + + +\item[FSC] +\item[full call] +\item[function attribute] +function + ``real'' (allocates environment) + meaning function-entry + more vague (any lambda?) +funny function +GEN (kill and...) +global TN, conflicts, preference +GTN (number) +IR ICR VMR ICR conversion, VMR conversion (translation) +inline expansion, call +kill (to make dead) +known function +LAMBDA +leaf +let call +lifetime analysis, live (tn, variable) +load tn +LOCS (passing, return locations) +local call +local TN, conflicts, (or just used in one block) +location (selection) +LTN (number) +main entry +mess-up (for cleanup) +more arg (entry) +MV +non-local exit +non-packed SC, TN +non-set variable +operand (to vop) +optimizer (in icr optimize) +optional-dispatch +pack, packing, packed +pass (in a transform) +passing + locations (value) + conventions (known, unknown) +policy (safe, fast, small, ...) +predecessor block +primitive-type +reaching definition +REF +representation + selection + for value +result continuation (for function) +result type assertion (for template) (or is it restriction) +restrict + a TN to finite SBs + a template operand to a primitive type (boxed...) + a tn-ref to particular SCs + +return (node, vops) +safe, safety +saving (of registers, costs) +SB +SC (restriction) +semi-inline +side-effect + in ICR + in VMR +sparse set +splitting (of VMR blocks) +SSET +SUBPRIMITIVE +successor block +tail recursion + tail recursive + tail recursive loop + user tail recursion + +template +TN +TNBIND +TN-REF +transform (source, ICR) +type + assertion + inference + top-down, bottom-up + assertion propagation + derived, asserted + descriptor, specifier, intersection, union, member type + check +type-check (in continuation) +UNBOXED (boxed) descriptor +unknown values continuation +unset variable +unwind-block, unwinding +used value (dest) +value passing +VAR +VM +VOP +\item[XEP] + +\end{description} diff --git a/doc/internals/cmu/internal-design.txt b/doc/internals/cmu/internal-design.txt new file mode 100644 index 0000000000..071e1d93aa --- /dev/null +++ b/doc/internals/cmu/internal-design.txt @@ -0,0 +1,694 @@ + + +;;;; Terminology. + +OBJECT + An object is one of the following: + a single word containing immediate data (characters, fixnums, etc) + a single word pointing to an object (structures, conses, etc.) + These are tagged with three low-tag bits as described in the section + "Tagging". This is synonymous with DESCRIPTOR. + +LISP OBJECT + A Lisp object is a high-level object discussed as a data type in Common + Lisp: The Language. + +DATA-BLOCK + A data-block is a dual-word aligned block of memory that either manifests a + Lisp object (vectors, code, symbols, etc.) or helps manage a Lisp object on + the heap (array header, function header, etc.). + +DESCRIPTOR + A descriptor is a tagged, single-word object. It either contains immediate + data or a pointer to data. This is synonymous with OBJECT. + +WORD + A word is a 32-bit quantity. + + + +;;;; Tagging. + +The following is a key of the three bit low-tagging scheme: + 000 even fixnum + 001 function pointer + 010 other-immediate (header-words, characters, symbol-value trap value, etc.) + 011 list pointer + 100 odd fixnum + 101 structure pointer + 110 unused + 111 other-pointer to data-blocks (other than conses, structures, + and functions) + +This taging scheme forces a dual-word alignment of data-blocks on the heap, but +this can be pretty negligible: + RATIOS and COMPLEX must have a header-word anyway since they are not a + major type. This wastes one word for these infrequent data-blocks since + they require two words for the data. + BIGNUMS must have a header-word and probably contain only one other word + anyway, so we probably don't waste any words here. Most bignums just + barely overflow fixnums, that is by a bit or two. + Single and double FLOATS? + no waste + one word wasted + SYMBOLS are dual-word aligned with the header-word. + Everything else is vector-like including code, so these probably take up + so many words that one extra one doesn't matter. + + + +;;;; GC Comments. + +Data-Blocks comprise only descriptors, or they contain immediate data and raw +bits interpreted by the system. GC must skip the latter when scanning the +heap, so it does not look at a word of raw bits and interpret it as a pointer +descriptor. These data-blocks require headers for GC as well as for operations +that need to know how to interpret the raw bits. When GC is scanning, and it +sees a header-word, then it can determine how to skip that data-block if +necessary. Header-Words are tagged as other-immediates. See the sections +"Other-Immediates" and "Data-Blocks and Header-Words" for comments on +distinguishing header-words from other-immediate data. This distinction is +necessary since we scan through data-blocks containing only descriptors just as +we scan through the heap looking for header-words introducing data-blocks. + +Data-Blocks containing only descriptors do not require header-words for GC +since the entire data-block can be scanned by GC a word at a time, taking +whatever action is necessary or appropriate for the data in that slot. For +example, a cons is referenced by a descriptor with a specific tag, and the +system always knows the size of this data-block. When GC encounters a pointer +to a cons, it can transport it into the new space, and when scanning, it can +simply scan the two words manifesting the cons interpreting each word as a +descriptor. Actually there is no cons tag, but a list tag, so we make sure the +cons is not nil when appropriate. A header may still be desired if the pointer +to the data-block does not contain enough information to adequately maintain +the data-block. An example of this is a simple-vector containing only +descriptor slots, and we attach a header-word because the descriptor pointing +to the vector lacks necessary information -- the type of the vector's elements, +its length, etc. + +There is no need for a major tag for GC forwarding pointers. Since the tag +bits are in the low end of the word, a range check on the start and end of old +space tells you if you need to move the thing. This is all GC overhead. + + + +;;;; Structures. + +Structures comprise a word for each slot in the definition in addition to one +word, a type slot which is a pointer descriptor. This points to a structure +describing the data-block as a structure, a defstruct-descriptor object. When +operating on a structure, doing a structure test can be done by simply checking +the tag bits on the pointer descriptor referencing it. As described in section +"GC Comments", data-blocks such as those representing structures may avoid +having a header-word since they are GC-scanable without any problem. This +saves two words for every structure instance. + + + +;;;; Fixnums. + +A fixnum has one of the following formats in 32 bits: + ------------------------------------------------------- + | 30 bit 2's complement even integer | 0 0 0 | + ------------------------------------------------------- +or + ------------------------------------------------------- + | 30 bit 2's complement odd integer | 1 0 0 | + ------------------------------------------------------- + +Effectively, there is one tag for immediate integers, two zeros. This buys one +more bit for fixnums, and now when these numbers index into simple-vectors or +offset into memory, they point to word boundaries on 32-bit, byte-addressable +machines. That is, no shifting need occur to use the number directly as an +offset. + +This format has another advantage on byte-addressable machines when fixnums are +offsets into vector-like data-blocks, including structures. Even though we +previously mentioned data-blocks are dual-word aligned, most indexing and slot +accessing is word aligned, and so are fixnums with effectively two tag bits. + +Two tags also allow better usage of special instructions on some machines that +can deal with two low-tag bits but not three. + +Since the two bits are zeros, we avoid having to mask them off before using the +words for arithmetic, but division and multiplication require special shifting. + + + +;;;; Other-immediates. + +An other-immediate has the following format: + ---------------------------------------------------------------- + | Data (24 bits) | Type (8 bits with low-tag) | 0 1 0 | + ---------------------------------------------------------------- + +The system uses eight bits of type when checking types and defining system +constants. This allows allows for 32 distinct other-immediate objects given +the three low-tag bits tied down. + +The system uses this format for characters, SYMBOL-VALUE unbound trap value, +and header-words for data-blocks on the heap. The type codes are laid out to +facilitate range checks for common subtypes; for example, all numbers will have +contiguous type codes which are distinct from the contiguous array type codes. +See section "Data-Blocks and Other-immediates Typing" for details. + + + +;;;; Data-Blocks and Header-Word Format. + +Pointers to data-blocks have the following format: + ---------------------------------------------------------------- + | Dual-word address of data-block (29 bits) | 1 1 1 | + ---------------------------------------------------------------- + +The word pointed to by the above descriptor is a header-word, and it has the +same format as an other-immediate: + ---------------------------------------------------------------- + | Data (24 bits) | Type (8 bits with low-tag) | 0 1 0 | + ---------------------------------------------------------------- + +This is convenient for scanning the heap when GC'ing, but it does mean that +whenever GC encounters an other-immediate word, it has to do a range check on +the low byte to see if it is a header-word or just a character (for example). +This is easily acceptable performance hit for scanning. + +The system interprets the data portion of the header-word for non-vector +data-blocks as the word length excluding the header-word. For example, the +data field of the header for ratio and complex numbers is two, one word each +for the numerator and denominator or for the real and imaginary parts. + +For vectors and data-blocks representing Lisp objects stored like vectors, the +system ignores the data portion of the header-word: + ---------------------------------------------------------------- + | Unused Data (24 bits) | Type (8 bits with low-tag) | 0 1 0 | + ---------------------------------------------------------------- + | Element Length of Vector (30 bits) | 0 0 | + ---------------------------------------------------------------- + +Using a separate word allows for much larger vectors, and it allows LENGTH to +simply access a single word without masking or shifting. Similarly, the header +for complex arrays and vectors has a second word, following the header-word, +the system uses for the fill pointer, so computing the length of any array is +the same code sequence. + + + +;;;; Data-Blocks and Other-immediates Typing. + +These are the other-immediate types. We specify them including all low eight +bits, including the other-immediate tag, so we can think of the type bits as +one type -- not an other-immediate major type and a subtype. Also, fetching a +byte and comparing it against a constant is more efficient than wasting even a +small amount of time shifting out the other-immediate tag to compare against a +five bit constant. + + Number (< 30) +00000 010 bignum 10 +00000 010 ratio 14 +00000 010 single-float 18 +00000 010 double-float 22 +00000 010 complex 26 + + Array (>= 30 code 86) + Simple-Array (>= 20 code 70) +00000 010 simple-array 30 + Vector (>= 34 code 82) +00000 010 simple-string 34 +00000 010 simple-bit-vector 38 +00000 010 simple-vector 42 +00000 010 (simple-array (unsigned-byte 2) (*)) 46 +00000 010 (simple-array (unsigned-byte 4) (*)) 50 +00000 010 (simple-array (unsigned-byte 8) (*)) 54 +00000 010 (simple-array (unsigned-byte 16) (*)) 58 +00000 010 (simple-array (unsigned-byte 32) (*)) 62 +00000 010 (simple-array single-float (*)) 66 +00000 010 (simple-array double-float (*)) 70 +00000 010 complex-string 74 +00000 010 complex-bit-vector 78 +00000 010 (array * (*)) -- general complex vector. 82 +00000 010 complex-array 86 + +00000 010 code-header-type 90 +00000 010 function-header-type 94 +00000 010 closure-header-type 98 +00000 010 funcallable-instance-header-type 102 +00000 010 unused-function-header-1-type 106 +00000 010 unused-function-header-2-type 110 +00000 010 unused-function-header-3-type 114 +00000 010 closure-function-header-type 118 +00000 010 return-pc-header-type 122 +00000 010 value-cell-header-type 126 +00000 010 symbol-header-type 130 +00000 010 base-character-type 134 +00000 010 system-area-pointer-type (header type) 138 +00000 010 unbound-marker 142 +00000 010 weak-pointer-type 146 + + + +;;;; Strings. + +All strings in the system are C-null terminated. This saves copying the bytes +when calling out to C. The only time this wastes memory is when the string +contains a multiple of eight characters, and then the system allocates two more +words (since Lisp objects are dual-word aligned) to hold the C-null byte. +Since the system will make heavy use of C routines for systems calls and +libraries that save reimplementation of higher level operating system +functionality (such as pathname resolution or current directory computation), +saving on copying strings for C should make C call out more efficient. + +The length word in a string header, see section "Data-Blocks and Header-Word +Format", counts only the characters truly in the Common Lisp string. +Allocation and GC will have to know to handle the extra C-null byte, and GC +already has to deal with rounding up various objects to dual-word alignment. + + + +;;;; Symbols and NIL. + +Symbol data-block has the following format: + ------------------------------------------------------- + | 5 (data-block words) | Symbol Type (8 bits) | + ------------------------------------------------------- + | Value Descriptor | + ------------------------------------------------------- + | Function Pointer | + ------------------------------------------------------- + | Raw Function Address | + ------------------------------------------------------- + | Setf Function | + ------------------------------------------------------- + | Property List | + ------------------------------------------------------- + | Print Name | + ------------------------------------------------------- + | Package | + ------------------------------------------------------- + +Most of these slots are self-explanatory given what symbols must do in Common +Lisp, but a couple require comments. We added the Raw Function Address slot to +speed up named call which is the most common calling convention. This is a +non-descriptor slot, but since objects are dual word aligned, the value +inherently has fixnum low-tag bits. The GC method for symbols must know to +update this slot. The Setf Function slot is currently unused, but we had an +extra slot due to adding Raw Function Address since objects must be dual-word +aligned. + +The issues with nil are that we want it to act like a symbol, and we need list +operations such as CAR and CDR to be fast on it. CMU Common Lisp solves this +by putting nil as the first object in static space, where other global values +reside, so it has a known address in the system: + ------------------------------------------------------- <-- start static + | 0 | space + ------------------------------------------------------- + | 5 (data-block words) | Symbol Type (8 bits) | + ------------------------------------------------------- <-- nil + | Value/CAR | + ------------------------------------------------------- + | Definition/CDR | + ------------------------------------------------------- + | Raw Function Address | + ------------------------------------------------------- + | Setf Function | + ------------------------------------------------------- + | Property List | + ------------------------------------------------------- + | Print Name | + ------------------------------------------------------- + | Package | + ------------------------------------------------------- + | ... | + ------------------------------------------------------- +In addition, we make the list typed pointer to nil actually point past the +header word of the nil symbol data-block. This has usefulness explained below. +The value and definition of nil are nil. Therefore, any reference to nil used +as a list has quick list type checking, and CAR and CDR can go right through +the first and second words as if nil were a cons object. + +When there is a reference to nil used as a symbol, the system adds offsets to +the address the same as it does for any symbol. This works due to a +combination of nil pointing past the symbol header-word and the chosen list and +other-pointer type tags. The list type tag is four less than the other-pointer +type tag, but nil points four additional bytes into its symbol data-block. + + + +;;;; Array Headers. + +The array-header data-block has the following format: + ---------------------------------------------------------------- + | Header Len (24 bits) = Array Rank +5 | Array Type (8 bits) | + ---------------------------------------------------------------- + | Fill Pointer (30 bits) | 0 0 | + ---------------------------------------------------------------- + | Available Elements (30 bits) | 0 0 | + ---------------------------------------------------------------- + | Data Vector (29 bits) | 1 1 1 | + ---------------------------------------------------------------- + | Displacement (30 bits) | 0 0 | + ---------------------------------------------------------------- + | Displacedp (29 bits) -- t or nil | 1 1 1 | + ---------------------------------------------------------------- + | Range of First Index (30 bits) | 0 0 | + ---------------------------------------------------------------- + . + . + . + +The array type in the header-word is one of the eight-bit patterns from section +"Data-Blocks and Other-immediates Typing", indicating that this is a complex +string, complex vector, complex bit-vector, or a multi-dimensional array. The +data portion of the other-immediate word is the length of the array header +data-block. Due to its format, its length is always five greater than the +array's number of dimensions. The following words have the following +interpretations and types: + Fill Pointer + This is a fixnum indicating the number of elements in the data vector + actually in use. This is the logical length of the array, and it is + typically the same value as the next slot. This is the second word, so + LENGTH of any array, with or without an array header, is just four bytes + off the pointer to it. + Available Elements + This is a fixnum indicating the number of elements for which there is + space in the data vector. This is greater than or equal to the logical + length of the array when it is a vector having a fill pointer. + Data Vector + This is a pointer descriptor referencing the actual data of the array. + This a data-block whose first word is a header-word with an array type as + described in sections "Data-Blocks and Header-Word Format" and + "Data-Blocks and Other-immediates Typing" + Displacement + This is a fixnum added to the computed row-major index for any array. + This is typically zero. + Displacedp + This is either t or nil. This is separate from the displacement slot, so + most array accesses can simply add in the displacement slot. The rare + need to know if an array is displaced costs one extra word in array + headers which probably aren't very frequent anyway. + Range of First Index + This is a fixnum indicating the number of elements in the first dimension + of the array. Legal index values are zero to one less than this number + inclusively. IF the array is zero-dimensional, this slot is + non-existent. + ... (remaining slots) + There is an additional slot in the header for each dimension of the + array. These are the same as the Range of First Index slot. + + + +;;;; Bignums. + +Bignum data-blocks have the following format: + ------------------------------------------------------- + | Length (24 bits) | Bignum Type (8 bits) | + ------------------------------------------------------- + | least significant bits | + ------------------------------------------------------- + . + . + . + +The elements contain the two's complement representation of the integer with +the least significant bits in the first element or closer to the header. The +sign information is in the high end of the last element. + + + + +;;;; Code Data-Blocks. + +A code data-block is the run-time representation of a "component". A component +is a connected portion of a program's flow graph that is compiled as a single +unit, and it contains code for many functions. Some of these functions are +callable from outside of the component, and these are termed "entry points". + +Each entry point has an associated user-visible function data-block (of type +FUNCTION). The full call convention provides for calling an entry point +specified by a function object. + +Although all of the function data-blocks for a component's entry points appear +to the user as distinct objects, the system keeps all of the code in a single +code data-block. The user-visible function object is actually a pointer into +the middle of a code data-block. This allows any control transfer within a +component to be done using a relative branch. + +Besides a function object, there are other kinds of references into the middle +of a code data-block. Control transfer into a function also occurs at the +return-PC for a call. The system represents a return-PC somewhat similarly to +a function, so GC can also recognize a return-PC as a reference to a code +data-block. + +It is incorrect to think of a code data-block as a concatenation of "function +data-blocks". Code for a function is not emitted in any particular order with +respect to that function's function-header (if any). The code following a +function-header may only be a branch to some other location where the +function's "real" definition is. + + +The following are the three kinds of pointers to code data-blocks: + Code pointer (labeled A below): + A code pointer is a descriptor, with other-pointer low-tag bits, pointing + to the beginning of the code data-block. The code pointer for the + currently running function is always kept in a register (CODE). In + addition to allowing loading of non-immediate constants, this also serves + to represent the currently running function to the debugger. + Return-PC (labeled B below): + The return-PC is a descriptor, with other-pointer low-tag bits, pointing + to a location for a function call. Note that this location contains no + descriptors other than the one word of immediate data, so GC can treat + return-PC locations the same as instructions. + Function (labeled C below): + A function is a descriptor, with function low-tag bits, that is user + callable. When a function header is referenced from a closure or from + the function header's self-pointer, the pointer has other-pointer low-tag + bits, instead of function low-tag bits. This ensures that the internal + function data-block associated with a closure appears to be uncallable + (although users should never see such an object anyway). + + Information about functions that is only useful for entry points is kept + in some descriptors following the function's self-pointer descriptor. + All of these together with the function's header-word are known as the + "function header". GC must be able to locate the function header. We + provide for this by chaining together the function headers in a NIL + terminated list kept in a known slot in the code data-block. + + +A code data-block has the following format: + ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ <-- A + | Header-Word count (24 bits) | %Code-Type (8 bits) | + ---------------------------------------------------------------- + | Number of code words (fixnum tag) | + ---------------------------------------------------------------- + | Pointer to first function header (other-pointer tag) | + ---------------------------------------------------------------- + | Debug information (structure tag) | + ---------------------------------------------------------------- + | First constant (a descriptor) | + ---------------------------------------------------------------- + | ... | + ---------------------------------------------------------------- + | Last constant (and last word of code header) | + ---------------------------------------------------------------- + | Some instructions (non-descriptor) | + ---------------------------------------------------------------- + | (pad to dual-word boundary if necessary) | + ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ <-- B + | Word offset from code header (24) | %Return-PC-Type (8) | + ---------------------------------------------------------------- + | First instruction after return | + ---------------------------------------------------------------- + | ... more code and return-PC header-words | + ---------------------------------------------------------------- + | (pad to dual-word boundary if necessary) | + ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ <-- C + | Offset from code header (24) | %Function-Header-Type (8) | + ---------------------------------------------------------------- + | Self-pointer back to previous word (with other-pointer tag) | + ---------------------------------------------------------------- + | Pointer to next function (other-pointer low-tag) or NIL | + ---------------------------------------------------------------- + | Function name (a string or a symbol) | + ---------------------------------------------------------------- + | Function debug arglist (a string) | + ---------------------------------------------------------------- + | Function type (a list-style function type specifier) | + ---------------------------------------------------------------- + | Start of instructions for function (non-descriptor) | + ---------------------------------------------------------------- + | More function headers and instructions and return PCs, | + | until we reach the total size of header-words + code | + | words. | + ---------------------------------------------------------------- + + +The following are detailed slot descriptions: + Code data-block header-word: + The immediate data in the code data-block's header-word is the number of + leading descriptors in the code data-block, the fixed overhead words plus + the number of constants. The first non-descriptor word, some code, + appears at this word offset from the header. + Number of code words: + The total number of non-header-words in the code data-block. The total + word size of the code data-block is the sum of this slot and the + immediate header-word data of the previous slot. The system accesses + this slot with the system constant, %Code-Code-Size-Slot, offset from the + header-word. + Pointer to first function header: + A NIL-terminated list of the function headers for all entry points to + this component. The system accesses this slot with the system constant, + %Code-Entry-Points-Slot, offset from the header-word. + Debug information: + The DEBUG-INFO structure describing this component. All information that + the debugger wants to get from a running function is kept in this + structure. Since there are many functions, the current PC is used to + locate the appropriate debug information. The system keeps the debug + information separate from the function data-block, since the currently + running function may not be an entry point. There is no way to recover + the function object for the currently running function, since this + data-block may not exist. The system accesses this slot with the system + constant, %Code-Debug-Info-Slot, offset from the header-word. + First constant ... last constant: + These are the constants referenced by the component, if there are any. + The system accesses the first constant slot with the system constant, + %Code-Constants-Offset, offset from the header-word. + + Return-PC header word: + The immediate header-word data is the word offset from the enclosing code + data-block's header-word to this word. This allows GC and the debugger + to easily recover the code data-block from a return-PC. The code at the + return point restores the current code pointer using a subtract immediate + of the offset, which is known at compile time. + + Function entry point header-word: + The immediate header-word data is the word offset from the enclosing code + data-block's header-word to this word. This is the same as for the + retrun-PC header-word. + Self-pointer back to header-word: + In a non-closure function, this self-pointer to the previous header-word + allows the call sequence to always indirect through the second word in a + user callable function. See section "Closure Format". With a closure, + indirecting through the second word gets you a function header-word. The + system ignores this slot in the function header for a closure, since it + has already indirected once, and this slot could be some random thing + that causes an error if you jump to it. This pointer has an + other-pointer tag instead of a function pointer tag, indicating it is not + a user callable Lisp object. The system accesses this slot with the + system constant, %Function-Code-Slot, offset from the function + header-word. + Pointer to next function: + This is the next link in the thread of entry point functions found in + this component. This value is NIL when the current header is the last + entry point in the component. The system accesses this slot with the + system constant, %Function-Header-Next-Slot, offset from the function + header-word. + Function name: + This function's name (for printing). If the user defined this function + with DEFUN, then this is the defined symbol, otherwise it is a + descriptive string. The system accesses this slot with the system + constant, %Function-Header-Name-Slot, offset from the function + header-word. + Function debug arglist: + A printed string representing the function's argument list, for human + readability. If it is a macroexpansion function, then this is the + original DEFMACRO arglist, not the actual expander function arglist. The + system accesses this slot with the system constant, + %Function-Header-Debug-Arglist-Slot, offset from the function + header-word. + Function type: + A list-style function type specifier representing the argument signature + and return types for this function. For example, + (FUNCTION (FIXNUM FIXNUM FIXNUM) FIXNUM) + or + (FUNCTION (STRING &KEY (:START UNSIGNED-BYTE)) STRING) + This information is intended for machine readablilty, such as by the + compiler. The system accesses this slot with the system constant, + %Function-Header-Type-Slot, offset from the function header-word. + + + +;;;; Closure Format. + +A closure data-block has the following format: + ---------------------------------------------------------------- + | Word size (24 bits) | %Closure-Type (8 bits) | + ---------------------------------------------------------------- + | Pointer to function header (other-pointer low-tag) | + ---------------------------------------------------------------- + | . | + | Environment information | + | . | + ---------------------------------------------------------------- + + +A closure descriptor has function low-tag bits. This means that a descriptor +with function low-tag bits may point to either a function header or to a +closure. The idea is that any callable Lisp object has function low-tag bits. +Insofar as call is concerned, we make the format of closures and non-closure +functions compatible. This is the reason for the self-pointer in a function +header. Whenever you have a callable object, you just jump through the second +word, offset some bytes, and go. + + + +;;;; Function call. + +Due to alignment requirements and low-tag codes, it is not possible to use a +hardware call instruction to compute the return-PC. Instead the return-PC +for a call is computed by doing an add-immediate to the start of the code +data-block. + +An advantage of using a single data-block to represent both the descriptor and +non-descriptor parts of a function is that both can be represented by a +single pointer. This reduces the number of memory accesses that have to be +done in a full call. For example, since the constant pool is implicit in a +return-PC, a call need only save the return-PC, rather than saving both the +return PC and the constant pool. + + + +;;;; Memory Layout. + +CMU Common Lisp has four spaces, read-only, static, dynamic-0, and dynamic-1. +Read-only contains objects that the system never modifies, moves, or reclaims. +Static space contains some global objects necessary for the system's runtime or +performance (since they are located at a known offset at a know address), and +the system never moves or reclaims these. However, GC does need to scan static +space for references to moved objects. Dynamic-0 and dynamic-1 are the two +heap areas for stop-and-copy GC algorithms. + +What global objects are at the head of static space??? + NIL + eval::*top-of-stack* + lisp::*current-catch-block* + lisp::*current-unwind-protect* + FLAGS (RT only) + BSP (RT only) + HEAP (RT only) + +In addition to the above spaces, the system has a control stack, binding stack, +and a number stack. The binding stack contains pairs of descriptors, a symbol +and its previous value. The number stack is the same as the C stack, and the +system uses it for non-Lisp objects such as raw system pointers, saving +non-Lisp registers, parts of bignum computations, etc. + + + +;;;; System Pointers. + +The system pointers reference raw allocated memory, data returned by foreign +function calls, etc. The system uses these when you need a pointer to a +non-Lisp block of memory, using an other-pointer. This provides the greatest +flexibility by relieving contraints placed by having more direct references +that require descriptor type tags. + +A system area pointer data-block has the following format: + ------------------------------------------------------- + | 1 (data-block words) | SAP Type (8 bits) | + ------------------------------------------------------- + | system area pointer | + ------------------------------------------------------- + +"SAP" means "system area pointer", and much of our code contains this naming +scheme. We don't currently restrict system pointers to one area of memory, but +if they do point onto the heap, it is up to the user to prevent being screwed +by GC or whatever. diff --git a/doc/internals/cmu/middle.tex b/doc/internals/cmu/middle.tex new file mode 100644 index 0000000000..d9ff29b5ee --- /dev/null +++ b/doc/internals/cmu/middle.tex @@ -0,0 +1,667 @@ +% -*- Dictionary: design -*- + + +\chapter{Virtual Machine Representation Introduction} + + +\chapter{Global TN assignment} + +% Rename this phase so as not to be confused with the local/global TN +% representation. + +The basic mechanism for closing over values is to pass the values as additional +implicit arguments in the function call. This technique is only applicable +when: + +\begin{itemize} +\item the calling function knows which values the called function wants to close + over, and +\item the values to be closed over are available in the calling + environment. +\end{itemize} + +The first condition is always true of local function calls. Environment +analysis can guarantee that the second condition holds by closing over any +needed values in the calling environment. + +If the function that closes over values may be called in an environment where +the closed over values are not available, then we must store the values in a +``closure'' so that they are always accessible. Closures are called using the +``full call'' convention. When a closure is called, control is transferred to +the ``external entry point'', which fetches the values out of the closure and +then does a local call to the real function, passing the closure values as +implicit arguments. + +In this scheme there is no such thing as a ``heap closure variable'' in code, +since the closure values are moved into TNs by the external entry point. There +is some potential for pessimization here, since we may end up moving the values +from the closure into a stack memory location, but the advantages are also +substantial. Simplicity is gained by always representing closure values the +same way, and functions with closure references may still be called locally +without allocating a closure. All the TN based VMR optimizations will apply +to closure variables, since closure variables are represented in the same way +as all other variables in VMR. Closure values will be allocated in registers +where appropriate. + +Closures are created at the point where the function is referenced, eliminating +the need to be able to close over closures. This lazy creation of closures has +the additional advantage that when a closure reference is conditionally not +done, then the closure consing will never be done at all. The corresponding +disadvantage is that a closure over the same values may be created multiple +times if there are multiple references. Note however, that VMR loop and common +subexpression optimizations can eliminate redundant closure consing. In any +case, multiple closures over the same variables doesn't seem to be that common. + +\#| +Having the Tail-Info would also make return convention determination trivial. +We could just look at the type, checking to see if it represents a fixed number +of values. To determine if the standard return convention is necessary to +preserve tail-recursion, we just iterate over the equivalent functions, looking +for XEPs and uses in full calls. +|\# + +The Global TN Assignment pass (GTN) can be considered a post-pass to +environment analysis. This phase assigns the TNs used to hold local lexical +variables and pass arguments and return values and determines the value-passing +strategy used in local calls. + +To assign return locations, we look at the function's tail-set. + +If the result continuation for an entry point is used as the continuation for a +full call, then we may need to constrain the continuation's values passing +convention to the standard one. This is not necessary when the call is known +not to be part of a tail-recursive loop (due to being a known function). + +Once we have figured out where we must use the standard value passing strategy, +we can use a more flexible strategy to determine the return locations for local +functions. We determine the possible numbers of return values from each +function by examining the uses of all the result continuations in the +equivalence class of the result continuation. + +If the tail-set type is for a fixed number of +values, then we return that fixed number of values from all the functions whose +result continuations are equated. If the number of values is not fixed, then +we must use the unknown-values convention, although we are not forced to use +the standard locations. We assign the result TNs at this time. + +We also use the tail-sets to see what convention we want to use. What we do is +use the full convention for any function that has a XEP its tail-set, even if +we aren't required to do so by a tail-recursive full call, as long as there are +no non-tail-recursive local calls in the set. This prevents us from +gratuitously using a non-standard convention when there is no reason to. + + +\chapter{Local TN assignment} + +[Want a different name for this so as not to be confused with the different +local/global TN representations. The really interesting stuff in this phase is +operation selection, values representation selection, return strategy, etc. +Maybe this phase should be conceptually lumped with GTN as ``implementation +selection'', since GTN determines call strategies and locations.] + +\#| + +[\#\#\# I guess I believe that it is OK for VMR conversion to dick the ICR flow +graph. An alternative would be to give VMR its very own flow graph, but that +seems like overkill. + +In particular, it would be very nice if a TR local call looked exactly like a +jump in VMR. This would allow loop optimizations to be done on loops written +as recursions. In addition to making the call block transfer to the head of +the function rather than to the return, we would also have to do something +about skipping the part of the function prolog that moves arguments from the +passing locations, since in a TR call they are already in the right frame. + + +In addition to directly indicating whether a call should be coded with a TR +variant, the Tail-P annotation flags non-call nodes that can directly return +the value (an ``advanced return''), rather than moving the value to the result +continuation and jumping to the return code. Then (according to policy), we +can decide to advance all possible returns. If all uses of the result are +Tail-P, then LTN can annotate the result continuation as :Unused, inhibiting +emission of the default return code. + +[\#\#\# But not really. Now there is a single list of templates, and a given +template has only one policy.] + +In LTN, we use the :Safe template as a last resort even when the policy is +unsafe. Note that we don't try :Fast-Safe; if this is also a good unsafe +template, then it should have the unsafe policies explicitly specified. + +With a :Fast-Safe template, the result type must be proven to satisfy the +output type assertion. This means that a fast-safe template with a fixnum +output type doesn't need to do fixnum overflow checking. [\#\#\# Not right to +just check against the Node-Derived-Type, since type-check intersects with +this.] + +It seems that it would be useful to have a kind of template where the args must +be checked to be fixnum, but the template checks for overflow and signals an +error. In the case where an output assertion is present, this would generate +better code than conditionally branching off to make a bignum, and then doing a +type check on the result. + + How do we deal with deciding whether to do a fixnum overflow check? This + is perhaps a more general problem with the interpretation of result type + restrictions in templates. It would be useful to be able to discriminate + between the case where the result has been proven to be a fixnum and where + it has simply been asserted to be so. + + The semantics of result type restriction is that the result must be proven + to be of that type *except* for safe generators, which are assumed to + verify the assertion. That way ``is-fixnum'' case can be a fast-safe + generator and the ``should-be-fixnum'' case is a safe generator. We could + choose not to have a safe ``should-be-fixnum'' generator, and let the + unrestricted safe generator handle it. We would then have to do an + explicit type check on the result. + + In other words, for all template except Safe, a type restriction on either + an argument or result means ``this must be true; if it is not the system may + break.'' In contrast, in a Safe template, the restriction means ``If this is + not true, I will signal an error.'' + + Since the node-derived-type only takes into consideration stuff that can be + proved from the arguments, we can use the node-derived-type to select + fast-safe templates. With unsafe policies, we don't care, since the code + is supposed to be unsafe. + +|\# + +Local TN assignment (LTN) assigns all the TNs needed to represent the values of +continuations. This pass scans over the code for the component, examining each +continuation and its destination. A number of somewhat unrelated things are +also done at the same time so that multiple passes aren't necessary. + -- Determine the Primitive-Type for each continuation value and assigns TNs + to hold the values. + -- Use policy information to determine the implementation strategy for each + call to a known function. + -- Clear the type-check flags in continuations whose destinations have safe + implementations. + -- Determine the value-passing strategy for each continuation: known or + unknown. + -- Note usage of unknown-values continuations so that stack analysis can tell + when stack values must be discarded. + +If safety is more important than speed and space, then we consider generating +type checks on the values of nodes whose CONT has the Type-Check flag set. If +the destination for the continuation value is safe, then we don't need to do +a check. We assume that all full calls are safe, and use the template +information to determine whether inline operations are safe. + +This phase is where compiler policy switches have most of their effect. The +speed/space/safety tradeoff can determine which of a number of coding +strategies are used. It is important to make the policy choice in VMR +conversion rather than in code generation because the cost and storage +requirement information which drives TNBIND will depend strongly on what actual +VOP is chosen. In the case of +/FIXNUM, there might be three or more +implementations, some optimized for speed, some for space, etc. Some of these +VOPS might be open-coded and some not. + +We represent the implementation strategy for a call by either marking it as a +full call or annotating it with a ``template'' representing the open-coding +strategy. Templates are selected using a two-way dispatch off of operand +primitive-types and policy. The general case of LTN is handled by the +LTN-Annotate function in the function-info, but most functions are handled by a +table-driven mechanism. There are four different translation policies that a +template may have: +\begin{description} +\item[Safe] + The safest implementation; must do argument type checking. + +\item[Small] + The (unsafe) smallest implementation. + +\item[Fast] + The (unsafe) fastest implementation. + +\item[Fast-Safe] + An implementation optimized for speed, but which does any necessary + checks exclusive of argument type checking. Examples are array bounds + checks and fixnum overflow checks. +\end{description} + +Usually a function will have only one or two distinct templates. Either or +both of the safe and fast-safe templates may be omitted; if both are specified, +then they should be distinct. If there is no safe template and our policy is +safe, then we do a full call. + +We use four different coding strategies, depending on the policy: +\begin{description} +\item[Safe:] safety $>$ space $>$ speed, or +we want to use the fast-safe template, but there isn't one. + +\item[Small:] space $>$ (max speed safety) + +\item[Fast:] speed $>$ (max space safety) + +\item[Fast-Safe (and type check):] safety $>$ speed $>$ space, or we want to use +the safe template, but there isn't one. +\end{description} + +``Space'' above is actually the maximum of space and cspeed, under the theory +that less code will take less time to generate and assemble. [\#\#\# This could +lose if the smallest case is out-of-line, and must allocate many linkage +registers.] + + +\chapter{Control optimization} + +In this phase we annotate blocks with drop-throughs. This controls how code +generation linearizes code so that drop-throughs are used most effectively. We +totally linearize the code here, allowing code generation to scan the blocks +in the emit order. + +There are basically two aspects to this optimization: + +\begin{enumerate} +\item +Dynamically reducing the number of branches taken v.s. branches not +taken under the assumption that branches not taken are cheaper. +\item +Statically minimizing the number of unconditional branches, saving +space and presumably time. +\end{enumerate} + +These two goals can conflict, but if they do it seems pretty clear that the +dynamic optimization should get preference. The main dynamic optimization is +changing the sense of a conditional test so that the more commonly taken branch +is the fall-through case. The problem is determining which branch is more +commonly taken. + +The most clear-cut case is where one branch leads out of a loop and the other +is within. In this case, clearly the branch within the loop should be +preferred. The only added complication is that at some point in the loop there +has to be a backward branch, and it is preferable for this branch to be +conditional, since an unconditional branch is just a waste of time. + +In the absence of such good information, we can attempt to guess which branch +is more popular on the basis of difference in the cost between the two cases. +Min-max strategy suggests that we should choose the cheaper alternative, since +the percentagewise improvement is greater when the branch overhead is +significant with respect to the cost of the code branched to. A tractable +approximation of this is to compare only the costs of the two blocks +immediately branched to, since this would avoid having to do any hairy graph +walking to find all the code for the consequent and the alternative. It might +be worthwhile discriminating against ultra-expensive functions such as ERROR. + +For this to work, we have to detect when one of the options is empty. In this +case, the next for one branch is a successor of the other branch, making the +comparison meaningless. We use dominator information to detect this situation. +When a branch is empty, one of the predecessors of the first block in the empty +branch will be dominated by the first block in the other branch. In such a +case we favor the empty branch, since that's about as cheap as you can get. + +Statically minimizing branches is really a much more tractable problem, but +what literature there is makes it look hard. Clearly the thing to do is to use +a non-optimal heuristic algorithm. + +A good possibility is to use an algorithm based on the depth first ordering. +We can modify the basic DFO algorithm so that it chooses an ordering which +favors any drop-thrus that we may choose for dynamic reasons. When we are +walking the graph, we walk the desired drop-thru arc last, which will place it +immediately after us in the DFO unless the arc is a retreating arc. + +We scan through the DFO and whenever we find a block that hasn't been done yet, +we build a straight-line segment by setting the drop-thru to the unreached +successor block which has the lowest DFN greater than that for the block. We +move to the drop-thru block and repeat the process until there is no such +block. We then go back to our original scan through the DFO, looking for the +head of another straight-line segment. + +This process will automagically implement all of the dynamic optimizations +described above as long as we favor the appropriate IF branch when creating the +DFO. Using the DFO will prevent us from making the back branch in a loop the +drop-thru, but we need to be clever about favoring IF branches within loops +while computing the DFO. The IF join will be favored without any special +effort, since we follow through the most favored path until we reach the end. + +This needs some knowledge about the target machine, since on most machines +non-tail-recursive calls will use some sort of call instruction. In this case, +the call actually wants to drop through to the return point, rather than +dropping through to the beginning of the called function. + + +\chapter{VMR conversion} + +\#| +Single-use let var continuation substitution not really correct, since it can +cause a spurious type error. Maybe we do want stuff to prove that an NLX can't +happen after all. Or go back to the idea of moving a combination arg to the +ref location, and having that use the ref cont (with its output assertion.) +This lossage doesn't seem very likely to actually happen, though. +[\#\#\# must-reach stuff wouldn't work quite as well as combination substitute in +psetq, etc., since it would fail when one of the new values is random code +(might unwind.)] + +Is this really a general problem with eager type checking? It seems you could +argue that there was no type error in this code: + +\begin{verbatim} + (+ :foo (throw 'up nil)) +\end{verbatim} + +But we would signal an error. + + +Emit explicit you-lose operation when we do a move between two non-T ptypes, +even when type checking isn't on. Can this really happen? Seems we should +treat continuations like this as though type-check was true. Maybe LTN should +leave type-check true in this case, even when the policy is unsafe. (Do a type +check against NIL?) + +At continuation use time, we may in general have to do both a coerce-to-t and a +type check, allocating two temporary TNs to hold the intermediate results. + + +\section{VMR Control representation} + +We represent all control transfer explicitly. In particular, :Conditional VOPs +take a single Target continuation and a Not-P flag indicating whether the sense +of the test is negated. Then an unconditional Branch VOP will be emitted +afterward if the other path isn't a drop-through. + +So we linearize the code before VMR-conversion. This isn't a problem, +since there isn't much change in control flow after VMR conversion (none until +loop optimization requires introduction of header blocks.) It does make +cost-based branch prediction a bit ucky, though, since we don't have any cost +information in ICR. Actually, I guess we do have pretty good cost information +after LTN even before VMR conversion, since the most important thing to know is +which functions are open-coded. + +|\# + +VMR preserves the block structure of ICR, but replaces the nodes with a target +dependent virtual machine (VM) representation. Different implementations may +use different VMs without making major changes in the back end. The two main +components of VMR are Temporary Names (TNs) and Virtual OPerations (VOPs). TNs +represent the locations that hold values, and VOPs represent the operations +performed on the values. + +A ``primitive type'' is a type meaningful at the VM level. Examples are Fixnum, +String-Char, Short-Float. During VMR conversion we use the primitive type of +an expression to determine both where we can store the result of the expression +and which type-specific implementations of an operation can be applied to the +value. [Ptype is a set of SCs == representation choices and representation +specific operations] + +The VM specific definitions provide functions that do stuff like find the +primitive type corresponding to a type and test for primitive type subtypep. +Usually primitive types will be disjoint except for T, which represents all +types. + +The primitive type T is special-cased. Not only does it overlap with all the +other types, but it implies a descriptor (``boxed'' or ``pointer'') representation. +For efficiency reasons, we sometimes want to use +alternate representations for some objects such as numbers. The majority of +operations cannot exploit alternate representations, and would only be +complicated if they had to be able to convert alternate representations into +descriptors. A template can require an operand to be a descriptor by +constraining the operand to be of type T. + +A TN can only represent a single value, so we bare the implementation of MVs at +this point. When we know the number of multiple values being handled, we use +multiple TNs to hold them. When the number of values is actually unknown, we +use a convention that is compatible with full function call. + +Everything that is done is done by a VOP in VMR. Calls to simple primitive +functions such as + and CAR are translated to VOP equivalents by a table-driven +mechanism. This translation is specified by the particular VM definition; VMR +conversion makes no assumptions about which operations are primitive or what +operand types are worth special-casing. The default calling mechanisms and +other miscellaneous builtin features are implemented using standard VOPs that +must be implemented by each VM. + +Type information can be forgotten after VMR conversion, since all type-specific +operation selections have been made. + +Simple type checking is explicitly done using CHECK-xxx VOPs. They act like +innocuous effectless/unaffected VOPs which return the checked thing as a +result. This allows loop-invariant optimization and common subexpression +elimination to remove redundant checks. All type checking is done at the time +the continuation is used. + +Note that we need only check asserted types, since if type inference works, the +derived types will also be satisfied. We can check whichever is more +convenient, since both should be true. + +Constants are turned into special Constant TNs, which are wired down in a SC +that is determined by their type. The VM definition provides a function that +returns a constant TN to represent a Constant Leaf. + +Each component has a constant pool. There is a register dedicated to holding +the constant pool for the current component. The back end allocates +non-immediate constants in the constant pool when it discovers them during +translation from ICR. + +[\#\#\# Check that we are describing what is actually implemented. But this +really isn't very good in the presence of interesting unboxed +representations...] +Since LTN only deals with values from the viewpoint of the receiver, we must be +prepared during the translation pass to do stuff to the continuation at the +time it is used. + -- If a VOP yields more values than are desired, then we must create TNs to + hold the discarded results. An important special-case is continuations + whose value is discarded. These continuations won't be annotated at all. + In the case of a Ref, we can simply skip evaluation of the reference when + the continuation hasn't been annotated. Although this will eliminate + bogus references that for some reason weren't optimized away, the real + purpose is to handle deferred references. + -- If a VOP yields fewer values than desired, then we must default the extra + values to NIL. + -- If a continuation has its type-check flag set, then we must check the type + of the value before moving it into the result location. In general, this + requires computing the result in a temporary, and having the type-check + operation deliver it in the actual result location. + -- If the template's result type is T, then we must generate a boxed + temporary to compute the result in when the continuation's type isn't T. + + +We may also need to do stuff to the arguments when we generate code for a +template. If an argument continuation isn't annotated, then it must be a +deferred reference. We use the leaf's TN instead. We may have to do any of +the above use-time actions also. Alternatively, we could avoid hair by not +deferring references that must be type-checked or may need to be boxed. + + +\section{Stack analysis} + +Think of this as a lifetime problem: a values generator is a write and a values +receiver is a read. We want to annotate each VMR-Block with the unknown-values +continuations that are live at that point. If we do a control transfer to a +place where fewer continuations are live, then we must deallocate the newly +dead continuations. + +We want to convince ourselves that values deallocation based on lifetime +analysis actually works. In particular, we need to be sure that it doesn't +violate the required stack discipline. It is clear that it is impossible to +deallocate the values before they become dead, since later code may decide to +use them. So the only thing we need to ensure is that the ``right'' time isn't +later than the time that the continuation becomes dead. + +The only reason why we couldn't deallocate continuation A as soon as it becomes +dead would be that there is another continuation B on top of it that isn't dead +(since we can only deallocate the topmost continuation). + +The key to understanding why this can't happen is that each continuation has +only one read (receiver). If B is on top of A, then it must be the case that A +is live at the receiver for B. This means that it is impossible for B to be +live without A being live. + + +The reason that we don't solve this problem using a normal iterative flow +analysis is that we also need to know the ordering of the continuations on the +stack so that we can do deallocation. When it comes time to discard values, we +want to know which discarded continuation is on the bottom so that we can reset +SP to its start. + +[I suppose we could also decrement SP by the aggregate size of the discarded +continuations.] Another advantage of knowing the order in which we expect +continuations to be on the stack is that it allows us to do some consistency +checking. Also doing a localized graph walk around the values-receiver is +likely to be much more efficient than doing an iterative flow analysis problem +over all the code in the component (not that big a consideration.) + + + +\#| +Actually, what we do is a backward graph walk from each unknown-values +receiver. As we go, we mark each walked block with the ordered list of +continuations we believe are on the stack. Starting with an empty stack, we: + -- When we encounter another unknown-values receiver, we push that + continuation on our simulated stack. + -- When we encounter a receiver (which had better be for the topmost + continuation), we pop that continuation. + -- When we pop all continuations, we terminate our walk. + +[\#\#\# not quite right... It seems we may run into ``dead values'' during the +graph walk too. It seems that we have to check if the pushed continuation is +on stack top, and if not, add it to the ending stack so that the post-pass will +discard it.] + + + +[\#\#\# Also, we can't terminate our walk just because we hit a block previously +walked. We have to compare the End-Stack with the values received along +the current path: if we have more values on our current walk than on the walk +that last touched the block, then we need to re-walk the subgraph reachable +from that block, using our larger set of continuations. It seems that our +actual termination condition is reaching a block whose End-Stack is already EQ +to our current stack.] + + + + + +If at the start, the block containing the values receiver has already been +walked, we skip the walk for that continuation, since it has already been +handled by an enclosing values receiver. Once a walk has started, we +ignore any signs of a previous walk, clobbering the old result with our own, +since we enclose that continuation, and the previous walk doesn't take into +consideration the fact that our values block underlies its own. + +When we are done, we have annotated each block with the stack current both at +the beginning and at the end of that block. Blocks that aren't walked don't +have anything on the stack either place (although they may hack MVs +internally). + +We then scan all the blocks in the component, looking for blocks that have +predecessors with a different ending stack than that block's starting stack. +(The starting stack had better be a tail of the predecessor's ending stack.) +We insert a block intervening between all of these predecessors that sets SP to +the end of the values for the continuation that should be on stack top. Of +course, this pass needn't be done if there aren't any global unknown MVs. + +Also, if we find any block that wasn't reached during the walk, but that USEs +an outside unknown-values continuation, then we know that the DEST can't be +reached from this point, so the values are unused. We either insert code to +pop the values, or somehow mark the code to prevent the values from ever being +pushed. (We could cause the popping to be done by the normal pass if we +iterated over the pushes beforehand, assigning a correct END-STACK.) + +[\#\#\# But I think that we have to be a bit clever within blocks, given the +possibility of blocks being joined. We could collect some unknown MVs in a +block, then do a control transfer out of the receiver, and this control +transfer could be squeezed out by merging blocks. How about: + +\begin{verbatim} + (tagbody + (return + (multiple-value-prog1 (foo) + (when bar + (go UNWIND)))) + + UNWIND + (return + (multiple-value-prog1 (baz) + bletch))) +\end{verbatim} + +But the problem doesn't happen here (can't happen in general?) since a node +buried within a block can't use a continuation outside of the block. In fact, +no block can have more then one PUSH continuation, and this must always be the +last continuation. So it is trivially (structurally) true that all pops come +before any push. + +[\#\#\# But not really: the DEST of an embedded continuation may be outside the +block. There can be multiple pushes, and we must find them by iterating over +the uses of MV receivers in LTN. But it would be hard to get the order right +this way. We could easily get the order right if we added the generators as we +saw the uses, except that we can't guarantee that the continuations will be +annotated at that point. (Actually, I think we only need the order for +consistency checks, but that is probably worthwhile). I guess the thing to do +is when we process the receiver, add the generator blocks to the +Values-Generators, then do a post-pass that re-scans the blocks adding the +pushes.] + +I believe that above concern with a dead use getting mashed inside a block +can't happen, since the use inside the block must be the only use, and if the +use isn't reachable from the push, then the use is totally unreachable, and +should have been deleted, which would prevent it from ever being +annotated. +] +] +|\# + +We find the partial ordering of the values globs for unknown values +continuations in each environment. We don't have to scan the code looking for +unknown values continuations since LTN annotates each block with the +continuations that were popped and not pushed or pushed and not popped. This +is all we need to do the inter-block analysis. + +After we have found out what stuff is on the stack at each block boundary, we +look for blocks with predecessors that have junk on the stack. For each such +block, we introduce a new block containing code to restore the stack pointer. +Since unknown-values continuations are represented as \verb+<start, count>+, we can +easily pop a continuation using the Start TN. + +Note that there is only doubt about how much stuff is on the control stack, +since only it is used for unknown values. Any special stacks such as number +stacks will always have a fixed allocation. + + +\section{Non-local exit} + + +If the starting and ending continuations are not in the same environment, then +the control transfer is a non-local exit. In this case just call Unwind with +the appropriate stack pointer, and let the code at the re-entry point worry +about fixing things up. + +It seems like maybe a good way to organize VMR conversion of NLX would be to +have environment analysis insert funny functions in new interposed cleanup +blocks. The thing is that we need some way for VMR conversion to: + 1] Get its hands on the returned values. + 2] Do weird control shit. + 3] Deliver the values to the original continuation destination. +I.e. we need some way to interpose arbitrary code in the path of value +delivery. + +What we do is replace the NLX uses of the continuation with another +continuation that is received by a MV-Call to \%NLX-VALUES in a cleanup block +that is interposed between the NLX uses and the old continuation's block. The +MV-Call uses the original continuation to deliver its values to. + +[Actually, it's not really important that this be an MV-Call, since it has to +be special-cased by LTN anyway. Or maybe we would want it to be an MV call. +If we did normal LTN analysis of an MV call, it would force the returned values +into the unknown values convention, which is probably pretty convenient for use +in NLX. + +Then the entry code would have to use some special VOPs to receive the unknown +values. But we probably need special VOPs for NLX entry anyway, and the code +can share with the call VOPs. Also we probably need the technology anyway, +since THROW will use truly unknown values.] + + +On entry to a dynamic extent that has non-local-exists into it (always at an +ENTRY node), we take a complete snapshot of the dynamic state: + +\begin{itemize} +\item the top pointers for all stacks +\item current Catch and Unwind-Protect +\item current special binding (binding stack pointer in shallow binding) +\end{itemize} + +We insert code at the re-entry point which restores the saved dynamic state. +All TNs live at an NLX EP are forced onto the stack, so we don't have to restore +them, and we don't have to worry about getting them saved. + diff --git a/doc/internals/cmu/outline.txt b/doc/internals/cmu/outline.txt new file mode 100644 index 0000000000..690781c922 --- /dev/null +++ b/doc/internals/cmu/outline.txt @@ -0,0 +1,120 @@ +Todo: +fasl.tex +In good shape. + +object.tex +Fairly good, but should probably be integrated with description of primitives +in vm.tex. + +front.tex +Needs updating cleanup scan. Not too bad. + +middle.tex +Need VMR overview. New names for GTN/LTN? Needs general cleanup, but not too +bad. NLX and stack are the worst. + +back.tex +Pack and assembler need more info. General cleanup. + + +compiler-overview.tex +Adapt introductory material from /../fred/usr/ram/comp.mss, pap:talk.mss +Division between ICR overview and ICR convert needs work. + +debugger.tex +Needs much work. Merge much info from debug-info and debug-int. Duplicating a +fair amount of stuff in the source may make sense where, since this is a part +of the system that is generally interesting. And also, a part that people +building on CMU CL might want to understand. + +glossary.tex +Finish, integrate w/ main text? + +interpreter.tex +Very sketchy and tentative. Needs to be fleshed out from the code. + +retargeting.tex +Very rough. Needs to be merged with parts of vm.tex (call vops). Needs some +additional text. Documentation of assembler, and all other exported +interfaces. (Generate defined VOP descriptions from the core, keyed to files?) + +vm.tex +This file should probably cease to exist, going into object, retargeting and +introductory material. [Also other scrap in stuff/] + + +[VMR and ICR overview also needed...] + +architecture.tex +Missing sections on startup code, compiling, building. + +environment.tex +Needs to be written: type system and info database interfaces. + +interface.tex +Needs to be written: source paths and error message utilities. + +lowlev.tex +Needs to be written. All manner of low-level stuff: memory layout and +management, core file format, C interface, low-level debugging (and ldb.) + + +Several different audiences: + -- Curious compiler implementors (not a big priority. Downplay academic + aspects, i.e. comparisons to other techniques, analysis of limitations, + future work...) Compiler part can be more academic, and include some + justifications of other design decisions. + -- System maintainers. + -- People retargeting the compiler. + -- People bringing up the system in a new environment. + +Sys arch part: + Package + file structure [system.txt] + system building [compiling.txt] + bootstrapping & cross compiling + +Compiler design: + Overview (mirror structure of rest of the part) + ICR data structure + Front end [front.tex] + Basic VMR data structures (no back-end stuff) + Middle end [middle.tex] + Back end + data structures [back.tex] + + Error system interface + Source tracking + +Compiler retargeting: + VM definition concepts [porting.txt, mail.txt, retargeting.tex] + SCs, SBs, primitive-types + Defining VOPS + time specification + defining + and using the assembler + Required VOPs [internal.txt, lowlev.txt, vm.mss] + Standard primitives [vm.mss] (broken down by type, parallels object format + section structure.) + Customizing VMR conversion + multiple hardware + constant operands + VM specific transforms + special-case IR2 convert methods + +Run-time system: + type system + info database + Data format [object.tex] + Debugger: + Info format [debug.txt] + Stack parsing [debug.txt] + Breakpoints + Internal errors + Signals + Memory management: [William] + heap Layout + stacks + GC + misc implementation stuff: foreign call, assembly routines [lowlev.txt] + LDB and low-level debugging + core file format [William] + fasl format [fasl.tex] diff --git a/doc/internals/cmu/retargeting.tex b/doc/internals/cmu/retargeting.tex new file mode 100644 index 0000000000..08399cc853 --- /dev/null +++ b/doc/internals/cmu/retargeting.tex @@ -0,0 +1,1113 @@ +\part{Compiler Retargeting} + +\chapter{Retargeting the Compiler} +[\#\#\# + +In general, it is a danger sign if a generator references a TN that isn't an +operand or temporary, since lifetime analysis hasn't been done for that use. +We are doing weird stuff for the old-cont and return-pc passing locations, +hoping that the conflicts at the called function have the desired effect. +Other stuff? When a function returns unknown values, we don't reference the +values locations when a single-value return is done. But nothing is live at a +return point anyway. + + + +Have a way for template conversion to special-case constant arguments? +How about: + If an arg restriction is (:satisfies [$<$predicate function$>$]), and the + corresponding argument is constant, with the constant value satisfying the + predicate, then (if any other restrictions are satisfied), the template + will be emitted with the literal value passed as an info argument. If the + predicate is omitted, then any constant will do. + + We could sugar this up a bit by allowing (:member $<$object$>$*) for + (:satisfies (lambda (x) (member x '($<$object$>$*)))) + +We could allow this to be translated into a Lisp type by adding a new Constant +type specifier. This could only appear as an argument to a function type. +To satisfy (Constant $<$type$>$), the argument must be a compile-time constant of +the specified type. Just Constant means any constant (i.e. (Constant *)). +This would be useful for the type constraints on ICR transforms. + + +Constant TNs: we count on being able to indirect to the leaf, and don't try to +wedge the information into the offset. We set the FSC to an appropriate +immediate SC. + + Allow ``more operands'' to VOPs in define-vop. You can't do much with the + more operands: define-vop just fills in the cost information according to + the loading costs for a SC you specify. You can't restrict more operands, + and you can't make local preferences. In the generator, the named variable + is bound to the TN-ref for the first extra operand. This should be good + enough to handle all the variable arg VOPs (primarily function call and + return). Usually more operands are used just to get TN lifetimes to work + out; the generator actually ignores them. + + Variable-arg VOPs can't be used with the VOP macro. You must use VOP*. + VOP* doesn't do anything with these extra operand except stick them on the + ends of the operand lists passed into the template. VOP* is often useful + within the convert functions for non-VOP templates, since it can emit a VOP + using an already prepared TN-Ref list. + + + It is pretty basic to the whole primitive-type idea that there is only one + primitive-type for a given lisp type. This is really the same as saying + primitive types are disjoint. A primitive type serves two somewhat + unrelated purposes: + -- It is an abstraction of a Lisp type used to select type specific + operations. Originally kind of an efficiency hack, but it lets a + template's type signature be used both for selection and operand + representation determination. + -- It represents a set of possible representations for a value (SCs). The + primitive type is used to determine the legal SCs for a TN, and is also + used to determine which type-coercion/move VOP to use. + +] + +There are basically three levels of target dependence: + + -- Code in the ``front end'' (before VMR conversion) deals only with Lisp + semantics, and is totally target independent. + + -- Code after VMR conversion and before code generation depends on the VM, + but should work with little modification across a wide range of + ``conventional'' architectures. + + -- Code generation depends on the machine's instruction set and other + implementation details, so it will have to be redone for each + implementation. Most of the work here is in defining the translation into + assembly code of all the supported VOPs. + + + +\chapter{Storage bases and classes} +New interface: instead of CURRENT-FRAME-SIZE, have CURRENT-SB-SIZE \verb+<name>+ which +returns the current element size of the named SB. + +How can we have primitive types that overlap, i.e. (UNSIGNED-BYTE 32), +(SIGNED-BYTE 32), FIXNUM? +Primitive types are used for two things: + Representation selection: which SCs can be used to represent this value? + For this purpose, it isn't necessary that primitive types be disjoint, + since any primitive type can choose an arbitrary set of + representations. For moves between the overlapping representations, + the move/load operations can just be noops when the locations are the + same (vanilla MOVE), since any bad moves should be caught out by type + checking. + VOP selection: + Is this operand legal for this VOP? When ptypes overlap in interesting + ways, there is a problem with allowing just a simple ptype restriction, + since we might want to allow multiple ptypes. This could be handled + by allowing ``union primitive types'', or by allowing multiple primitive + types to be specified (only in the operand restriction.) The latter + would be along the lines of other more flexible VOP operand restriction + mechanisms, (constant, etc.) + + + +Ensure that load/save-operand never need to do representation conversion. + +The PRIMITIVE-TYPE more/coerce info would be moved into the SC. This could +perhaps go along with flushing the TN-COSTS. We would annotate the TN with +best SC, which implies the representation (boxed or unboxed). We would still +need to represent the legal SCs for restricted TNs somehow, and also would have to +come up with some other way for pack to keep track of which SCs we have already +tried. + +An SC would have a list of ``alternate'' SCs and a boolean SAVE-P value that +indicates it needs to be saved across calls in some non-SAVE-P SC. A TN is +initially given its ``best'' SC. The SC is annotated with VOPs that are used for +moving between the SC and its alternate SCs (load/save operand, save/restore +register). It is also annotated with the ``move'' VOPs used for moving between +this SC and all other SCs it is possible to move between. We flush the idea +that there is only c-to-t and c-from-t. + +But how does this mesh with the idea of putting operand load/save back into the +generator? Maybe we should instead specify a load/save function? The +load/save functions would also differ from the move VOPs in that they would +only be called when the TN is in fact in that particular alternate SC, whereas +the move VOPs will be associated with the primary SC, and will be emitted +before it is known whether the TN will be packed in the primary SC or an +alternate. + +I guess a packed SC could also have immediate SCs as alternate SCs, and +constant loading functions could be associated with SCs using this mechanism. + +So given a TN packed in SC X and an SC restriction for Y and Z, how do we know +which load function to call? There would be ambiguity if X was an alternate +for both Y and Z and they specified different load functions. This seems +unlikely to arise in practice, though, so we could just detect the ambiguity +and give an error at define-vop time. If they are doing something totally +weird, they can always inhibit loading and roll their own. + +Note that loading costs can be specified at the same time (same syntax) as +association of loading functions with SCs. It seems that maybe we will be +rolling DEFINE-SAVE-SCS and DEFINE-MOVE-COSTS into DEFINE-STORAGE-CLASS. + +Fortunately, these changes will affect most VOP definitions very little. + + +A Storage Base represents a physical storage resource such as a register set or +stack frame. Storage bases for non-global resources such as the stack are +relativized by the environment that the TN is allocated in. Packing conflict +information is kept in the storage base, but non-packed storage resources such +as closure environments also have storage bases. +Some storage bases: +\begin{verbatim} + General purpose registers + Floating point registers + Boxed (control) stack environment + Unboxed (number) stack environment + Closure environment +\end{verbatim} + +A storage class is a potentially arbitrary set of the elements in a storage +base. Although conceptually there may be a hierarchy of storage classes such +as ``all registers'', ``boxed registers'', ``boxed scratch registers'', this doesn't +exist at the implementation level. Such things can be done by specifying +storage classes whose locations overlap. A TN shouldn't have lots of +overlapping SC's as legal SC's, since time would be wasted repeatedly +attempting to pack in the same locations. + +There will be some SC's whose locations overlap a great deal, since we get Pack +to do our representation analysis by having lots of SC's. An SC is basically a +way of looking at a storage resource. Although we could keep a fixnum and an +unboxed representation of the same number in the same register, they correspond +to different SC's since they are different representation choices. + +TNs are annotated with the primitive type of the object that they hold: + T: random boxed object with only one representation. + Fixnum, Integer, XXX-Float: Object is always of the specified numeric type. + String-Char: Object is always a string-char. + +When a TN is packed, it is annotated with the SC it was packed into. The code +generator for a VOP must be able to uniquely determine the representation of +its operands from the SC. (debugger also...) + +Some SCs: + Reg: any register (immediate objects) + Save-Reg: a boxed register near r15 (registers easily saved in a call) + Boxed-Reg: any boxed register (any boxed object) + Unboxed-Reg: any unboxed register (any unboxed object) + Float-Reg, Double-Float-Reg: float in FP register. + Stack: boxed object on the stack (on cstack) + Word: any 32bit unboxed object on nstack. + Double: any 64bit unboxed object on nstack. + +We have a number of non-packed storage classes which serve to represent access +costs associated with values that are not allocated using conflicts +information. Non-packed TNs appear to already be packed in the appropriate +storage base so that Pack doesn't get confused. Costs for relevant non-packed +SC's appear in the TN-Ref cost information, but need not ever be summed into +the TN cost vectors, since TNs cannot be packed into them. + +There are SCs for non-immediate constants and for each significant kind of +immediate operand in the architecture. On the RT, 4, 8 and 20 bit integer SCs +are probably worth having. + +\begin{verbatim} +Non-packed SCs: + Constant + Immediate constant SCs: + Signed-Byte-<N>, Unsigned-Byte-<N>, for various architecture dependent + values of <N> + String-Char + XXX-Float + Magic values: T, NIL, 0. +\end{verbatim} + +\chapter{Type system parameterization} + +The main aspect of the VM that is likely to vary for good reason is the type +system: + + -- Different systems will have different ways of representing dynamic type + information. The primary effect this has on the compiler is causing VMR + conversion of type tests and checks to be implementation dependent. + Rewriting this code for each implementation shouldn't be a big problem, + since the portable semantics of types has already been dealt with. + + -- Different systems will have different specialized number and array types, + and different VOPs specialized for these types. It is easy to add this kind + of knowledge without affecting the rest of the compiler. All you have to + do is define the VOPs and translations. + + -- Different systems will offer different specialized storage resources + such as floating-point registers, and will have additional kinds of + primitive-types. The storage class mechanism handles a large part of this, + but there may be some problem in getting VMR conversion to realize the + possibly large hidden costs in implicit moves to and from these specialized + storage resources. Probably the answer is to have some sort of general + mechanism for determining the primitive-type for a TN given the Lisp type, + and then to have some sort of mechanism for automatically using specialized + Move VOPs when the source or destination has some particular primitive-type. + +\#| +How to deal with list/null(symbol)/cons in primitive-type structure? Since +cons and symbol aren't used for type-specific template selection, it isn't +really all that critical. Probably Primitive-Type should return the List +primitive type for all of Cons, List and Null (indicating when it is exact). +This would allow type-dispatch for simple sequence functions (such as length) +to be done using the standard template-selection mechanism. [Not a wired +assumption] +|\# + + + +\chapter{VOP Definition} + +Before the operand TN-refs are passed to the emit function, the following +stuff is done: + -- The refs in the operand and result lists are linked together in order using + the Across slot. This list is properly NIL terminated. + -- The TN slot in each ref is set, and the ref is linked into that TN's refs + using the Next slot. + -- The Write-P slot is set depending on whether the ref is an argument or + result. + -- The other slots have the default values. + +The template emit function fills in the Vop, Costs, Cost-Function, +SC-Restriction and Preference slots, and links together the Next-Ref chain as +appropriate. + + +\section{Lifetime model} + +\#| +Note in doc that the same TN may not be used as both a more operand and as any +other operand to the same VOP, to simplify more operand LTN number coalescing. +|\# + +It seems we need a fairly elaborate model for intra-VOP conflicts in order to +allocate temporaries without introducing spurious conflicts. Consider the +important case of a VOP such as a miscop that must have operands in certain +registers. We allocate a wired temporary, create a local preference for the +corresponding operand, and move to (or from) the temporary. If all temporaries +conflict with all arguments, the result will be correct, but arguments could +never be packed in the actual passing register. If temporaries didn't conflict +with any arguments, then the temporary for an earlier argument might get packed +in the same location as the operand for a later argument; loading would then +destroy an argument before it was read. + +A temporary's intra-VOP lifetime is represented by the times at which its life +starts and ends. There are various instants during the evaluation that start +and end VOP lifetimes. Two TNs conflict if the live intervals overlap. +Lifetimes are open intervals: if one TN's lifetime begins at a point where +another's ends, then the TNs don't conflict. + +The times within a VOP are the following: + +:Load + This is the beginning of the argument's lives, as far as intra-vop + conflicts are concerned. If load-TNs are allocated, then this is the + beginning of their lives. + +(:Argument $<$n$>$) + The point at which the N'th argument is read for the last time (by this + VOP). If the argument is dead after this VOP, then the argument becomes + dead at this time, and may be reused as a temporary or result load-TN. + +(:Eval $<$n$>$) + The N'th evaluation step. There may be any number of evaluation steps, but + it is unlikely that more than two are needed. + +(:Result $<$n$>$) + The point at which the N'th result is first written into. This is the + point at which that result becomes live. + +:Save + Similar to :Load, but marks the end of time. This is the point at which result + load-TNs are stored back to the actual location. + +In any of the list-style time specifications, the keyword by itself stands for +the first such time, i.e. +\begin{verbatim} + :argument <==> (:argument 0) +\end{verbatim} + +Note that argument/result read/write times don't actually have to be in the +order specified, but they must *appear* to happen in that order as far as +conflict analysis is concerned. For example, the arguments can be read in any +order as long as no TN is written that has a life beginning at or after +(:Argument $<$n$>$), where N is the number of an argument whose reading was +postponed. + +[\#\#\# (???) + +We probably also want some syntactic sugar in Define-VOP for automatically +moving operands to/from explicitly allocated temporaries so that this kind of +thing is somewhat easy. There isn't really any reason to consider the +temporary to be a load-TN, but we want to compute costs as though it was and +want to use the same operand loading routines. + +We also might consider allowing the lifetime of an argument/result to be +extended forward/backward. This would in many cases eliminate the need for +temporaries when operands are read/written out of order. +] + + +\section{VOP Cost model} + +Note that in this model, if an operand has no restrictions, it has no cost. +This makes sense, since the purpose of the cost is to indicate the +relative value of packing in different SCs. If the operand isn't required to +be in a good SC (i.e. a register), then we might as well leave it in memory. +The SC restriction mechanism can be used even when doing a move into the SC is +too complex to be generated automatically (perhaps requiring temporary +registers), since Define-VOP allows operand loading to be done explicitly. + + +\section{Efficiency notes} + + In addition to +being used to tell whether a particular unsafe template might get emitted, we +can also use it to give better efficiency notes: + -- We can say what is wrong with the call types, rather than just saying we + failed to open-code. + -- We can tell whether any of the ``better'' templates could possibly apply, + i.e. is the inapplicability of a template because of inadequate type + information or because the type is just plain wrong. We don't want to + flame people when a template that couldn't possibly match doesn't match, + e.g. complaining that we can't use fixnum+ when the arguments are known to + be floats. + + +This is how we give better efficiency notes: + +The Template-Note is a short noun-like string without capitalization or +punctuation that describes what the template ``does'', i.e. we say +``Unable to do ~A, doing ~A instead.'' + +The Cost is moved from the Vop-Info to the Template structure, and is used to +determine the ``goodness'' of possibly applicable templates. [Could flush +Template/Vop-Info distinction] The cost is used to choose the best applicable +template to emit, and also to determine what better templates we might have +been able to use. + +A template is possibly applicable if there is an intersection between all of +the arg/result types and the corresponding arg/result restrictions, i.e. the +template is not clearly impossible: more declarations might allow it to be +emitted. + + +\chapter{Assembler Retargeting} + + +\chapter{Writing Assembly Code} + +VOP writers expect: +\begin{Lentry} +\item[MOVE] + You write when you port the assembler.) +\item[EMIT-LABEL] + Assembler interface like INST. Takes a label you made and says ``stick it + here.'' + \item[GEN-LABEL] + Returns a new label suitable for use with EMIT-LABEL exactly once and + for referencing as often as necessary. + \item[INST] + Recognizes and dispatches to instructions you defined for assembler. + \item[ALIGN] + This takes the number of zero bits you want in the low end of the address + of the next instruction. + \item[ASSEMBLE] + \item[ASSEMBLE-ELSEWHERE] + Get ready for assembling stuff. Takes a VOP and arbitrary PROGN-style + body. Wrap these around instruction emission code announcing the first + pass of our assembler. + \item[CURRENT-NFP-TN] + This returns a TN for the NFP if the caller uses the number stack, or + nil. + \item[SB-ALLOCATED-SIZE] + This returns the size of some storage base used by the currently + compiling component. + \item[...] +\end{Lentry} +;;; +;;; VOP idioms +;;; + +\begin{Lentry} +\item[STORE-STACK-TN] +\item[LOAD-STACK-TN] + These move a value from a register to the control stack, or from the + control stack to a register. They take care of checking the TN types, + modifying offsets according to the address units per word, etc. +\end{Lentry} + +\chapter{Required VOPS} + + +Note: the move VOP cannot have any wired temps. (Move-Argument also?) This is +so we can move stuff into wired TNs without stepping on our toes. + + +We create set closure variables using the Value-Cell VOP, which takes a value +and returns a value cell containing the value. We can basically use this +instead of a Move VOP when initializing the variable. Value-Cell-Set and +Value-Cell-Ref are used to access the value cell. We can have a special effect +for value cells so that value cells references can be discovered to be common +subexpressions or loop invariants. + + + + +Represent unknown-values continuations as (start, count). Unknown values +continuations are always outside of the current frame (on stack top). Within a +function, we always set up and receive values in the standard passing +locations. If we receive stack values, then we must BLT them down to the start +of our frame, filling in any unsupplied values. If we generate unknown values +(i.e. PUSH-VALUES), then we set the values up in the standard locations, then +BLT them to stack top. When doing a tail-return of MVs, we just set them up in +the standard locations and decrement SP: no BLT is necessary. + +Unknown argument call (MV-CALL) takes its arguments on stack top (is given a +base pointer). If not a tail call, then we just set the arg pointer to the +base pointer and call. If a tail call, we must BLT the arguments down to the +beginning of the current frame. + + +Implement more args by BLT'ing the more args *on top* of the current frame. +This solves two problems: +\begin{itemize} +\item Any register more arguments can be made uniformly accessibly by copying + them into memory. [We can't store the registers in place, since the + beginning of the frame gets double use for storing the old-cont, return-pc + and env.] +\item It solves the deallocation problem: the arguments will be deallocated when + the frame is returned from or a tail full call is done out of it. So + keyword args will be properly tail-recursive without any special mechanism + for squeezing out the more arg once the parsing is done. Note that a tail + local call won't blast the more arg, since in local call the callee just + takes the frame it is given (in this case containing the more arg). +\end{itemize} + +More args in local call??? Perhaps we should not attempt local call conversion +in this case. We already special-case keyword args in local call. It seems +that the main importance of more args is primarily related to full call: it is +used for defining various kinds of frobs that need to take arbitrary arguments: +\begin{itemize} +\item Keyword arguments +\item Interpreter stubs +\item ``Pass through'' applications such as dispatch functions +\end{itemize} +Given the marginal importance of more args in local call, it seems unworth +going to any implementation difficulty. In fact, it seems that it would cause +complications both at the VMR level and also in the VM definition. This being +the case, we should flush it. + + +\section{Function Call} + + + +\subsection{Registers and frame format} + +These registers are used in function call and return: + +A0..A{\it n} + In full call, the first three arguments. In unknown values return, the + first three return values. + +CFP + The current frame pointer. In full call, this initially points to a + partial frame large enough to hold the passed stack arguments (zero-length + if none). + +CSP + The current control stack top pointer. + +OCFP + In full call, the passing location for the frame to return to. + + In unknown-values return of other than one value, the pointer to returned + stack values. In such a return, OCFP is always initialized to point to + the frame returned from, even when no stack values are returned. This + allows OCFP to be used to restore CSP. + +LRA + In full call, the passing location for the return PC. + +NARGS + In full call, the number of arguments passed. In unknown-values return of + other than one value, the number of values returned. + + +\subsection{Full call} + +What is our usage of CFP, OCFP and CSP? + +It is an invariant that CSP always points after any useful information so that +at any time an interrupt can come and allocate stuff in the stack. + +TR call is also a constraint: we can't deallocate the caller's frame before the +call, since it holds the stack arguments for the call. + +What we do is have the caller set up CFP, and have the callee set CSP to CFP +plus the frame size. The caller leaves CSP alone: the callee is the one who +does any necessary stack deallocation. + +In a TR call, we don't do anything: CFP is left as CFP, and CSP points to the +end of the frame, keeping the stack arguments from being trashed. + +In a normal call, CFP is set to CSP, causing the callee's frame to be allocated +after the current frame. + + +\subsection{Unknown values return} + +The unknown values return convention is always used in full call, and is used +in local call when the compiler either can't prove that a fixed number of +values are returned, or decides not to use the fixed values convention to allow +tail-recursive XEP calls. + +The unknown-values return convention has variants: single value and variable +values. We make this distinction to optimize the important case of a returner +who knows exactly one value is being returned. Note that it is possible to +return a single value using the variable-values convention, but it is less +efficient. + +We indicate single-value return by returning at the return-pc+4; variable value +return is indicated by returning at the return PC. + +Single-value return makes only the following guarantees: + A0 holds the value returned. + CSP has been reset: there is no garbage on the stack. + +In variable value return, more information is passed back: + A0..A2 hold the first three return values. If fewer than three values are + returned, then the unused registers are initialized to NIL. + + OCFP points to the frame returned from. Note that because of our + tail-recursive implementation of call, the frame receiving the values is + always immediately under the frame returning the values. This means that + we can use OCFP to index the values when we access them, and to restore + CSP when we want to discard them. + + NARGS holds the number of values returned. + + CSP is always (+ OCFP (* NARGS 4)), i.e. there is room on the stack + allocated for all returned values, even if they are all actually passed in + registers. + + +\subsection{External Entry Points} + +Things that need to be done on XEP entry: + 1] Allocate frame + 2] Move more arg above the frame, saving context + 3] Set up env, saving closure pointer if closure + 4] Move arguments from closure to local home + Move old-cont and return-pc to the save locations + 5] Argument count checking and dispatching + +XEP VOPs: +\begin{verbatim} +Allocate-Frame +Copy-More-Arg <nargs-tn> 'fixed {in a3} => <context>, <count> +Setup-Environment +Setup-Closure-Environment => <closure> +Verify-Argument-Count <nargs-tn> 'count {for fixed-arg lambdas} +Argument-Count-Error <nargs-tn> {Drop-thru on hairy arg dispatching} +Use fast-if-=/fixnum and fast-if-</fixnum for dispatching. +\end{verbatim} + +Closure vops: +\begin{verbatim} +make-closure <fun entry> <slot count> => <closure> +closure-init <closure> <values> 'slot +\end{verbatim} + +Things that need to be done on all function entry: +\begin{itemize} +\item Move arguments to the variable home (consing value cells as necessary) +\item Move environment values to the local home +\item Move old-cont and return-pc to the save locations +\end{itemize} + +\section{Calls} + +Calling VOP's are a cross product of the following sets (with some members +missing): + Return values + multiple (all values) + fixed (calling with unknown values conventions, wanting a certain + number.) + known (only in local call where caller/callee agree on number of + values.) + tail (doesn't return but does tail call) + What function + local + named (going through symbol, like full but stash fun name for error sys) + full (have a function) + Args + fixed (number of args are known at compile-time) + variable (MULTIPLE-VALUE-CALL and APPLY) + +Note on all jumps for calls and returns that we want to put some instruction +in the jump's delay slot(s). + +Register usage at the time of the call: + +LEXENV + This holds the lexical environment to use during the call if it's a closure, + and it is undefined otherwise. + +CNAME + This holds the symbol for a named call and garbage otherwise. + +OCFP + This holds the frame pointer, which the system restores upon return. The + callee saves this if necessary; this is passed as a pseudo-argument. + +A0 ... An + These holds the first n+1 arguments. + +NARGS + This holds the number of arguments, as a fixnum. + +LRA + This holds the lisp-return-address object which indicates where to return. + For a tail call, this retains its current value. The callee saves this + if necessary; this is passed as a pseudo-argument. + +CODE + This holds the function object being called. + +CSP + The caller ignores this. The callee sets it as necessary based on CFP. + +CFP + This holds the callee's frame pointer. Caller sets this to the new frame + pointer, which it remembered when it started computing arguments; this is + CSP if there were no stack arguments. For a tail call CFP retains its + current value. + +NSP + The system uses this within a single function. A function using NSP must + allocate and deallocate before returning or making a tail call. + +Register usage at the time of the return for single value return, which +goes with the unknown-values convention the caller used. + +A0 + This holds the value. + +CODE + This holds the lisp-return-address at which the system continues executing. + +CSP + This holds the CFP. That is, the stack is guaranteed to be clean, and there + is no code at the return site to adjust the CSP. + +CFP + This holds the OCFP. + +Additional register usage for multiple value return: + +NARGS + This holds the number of values returned. + +A0 ... An + These holds the first n+1 values, or NIL if there are less than n+1 values. + +CSP + Returner stores CSP to hold its CFP + NARGS * \verb+<address units per word>+ + +OCFP + Returner stores this as its CFP, so the returnee has a handle on either + the start of the returned values on the stack. + + +ALLOCATE FULL CALL FRAME. + +If the number of call arguments (passed to the VOP as an info argument) +indicates that there are stack arguments, then it makes some callee frame for +arguments: +\begin{verbatim} + VOP-result <- CSP + CSP <- CSP + value of VOP info arg times address units per word. +\end{verbatim} + +In a call sequence, move some arguments to the right places. + +There's a variety of MOVE-ARGUMENT VOP's. + +FULL CALL VOP'S +(variations determined by whether it's named, it's a tail call, there +is a variable arg count, etc.) +\begin{verbatim} + if variable number of arguments + NARGS <- (CSP - value of VOP argument) shift right by address units per word. + A0...An <- values off of VOP argument (just fill them all) + else + NARGS <- value of VOP info argument (always a constant) + + if tail call + OCFP <- value from VOP argument + LRA <- value from VOP argument + CFP stays the same since we reuse the frame + NSP <- NFP + else + OCFP <- CFP + LRA <- compute LRA by adding an assemble-time determined constant to + CODE. + CFP <- new frame pointer (remembered when starting to compute args) + This is CSP if no stack args. + when (current-nfp-tn VOP-self-pointer) + stack-temp <- NFP + + if named + CNAME <- function symbol name + the-fun <- function object out of symbol + + LEXENV <- the-fun (from previous line or VOP argument) + CODE <- function-entry (the first word after the-fun) + LIP <- calc first instruction addr (CODE + constant-offset) + jump and run off temp + + <emit Lisp return address data-block> + <default and move return values OR receive return values> + when (current-nfp-tn VOP-self-pointer) + NFP <- stack-temp +\end{verbatim} +Callee: + +\begin{verbatim} +XEP-ALLOCATE-FRAME + emit function header (maybe initializes offset back to component start, + but other pointers are set up at load-time. Pads + to dual-word boundary.) + CSP <- CFP + compile-time determined constant (frame size) + if the function uses the number stack + NFP <- NSP + NSP <- NSP + compile-time determined constant (number stack frame size) +\end{verbatim} + +\begin{verbatim} +SETUP-ENVIRONMENT +(either use this or the next one) + +CODE <- CODE - assembler-time determined offset from function-entry back to + the code data-block address. +\end{verbatim} + +\begin{verbatim} +SETUP-CLOSURE-ENVIRONMENT +(either use this or the previous one) +After this the CLOSURE-REF VOP can reference closure variables. + +VOP-result <- LEXENV +CODE <- CODE - assembler-time determined offset from function-entry back to + the code data-block address. +\end{verbatim} + +Return VOP's +RETURN and RETURN-MULTIPLE are for the unknown-values return convention. +For some previous caller this is either it wants n values (and it doesn't +know how many are coming), or it wants all the values returned (and it +doesn't know how many are coming). + + +RETURN +(known fixed number of values, used with the unknown-values convention + in the caller.) +When compiler invokes VOP, all values are already where they should be; +just get back to caller. + +\begin{verbatim} +when (current-nfp-tn VOP-self-pointer) + ;; The number stack grows down in memory. + NSP <- NFP + number stack frame size for calls within the currently + compiling component + times address units per word +CODE <- value of VOP argument with LRA +if VOP info arg is 1 (number of values we know we're returning) + CSP <- CFP + LIP <- calc target addr + (CODE + skip over LRA header word + skip over address units per branch) + (The branch is in the caller to skip down to the MV code.) +else + NARGS <- value of VOP info arg + nil out unused arg regs + OCFP <- CFP (This indicates the start of return values on the stack, + but you leave space for those in registers for convenience.) + CSP <- CFP + NARGS * address-units-per-word + LIP <- calc target addr (CODE + skip over LRA header word) +CFP <- value of VOP argument with OCFP +jump and run off LIP +\end{verbatim} + +RETURN-MULTIPLE +(unknown number of values, used with the unknown-values convention in + the caller.) +When compiler invokes VOP, it gets TN's representing a pointer to the +values on the stack and how many values were computed. + +\begin{verbatim} +when (current-nfp-tn VOP-self-pointer) + ;; The number stack grows down in memory. + NSP <- NFP + number stack frame size for calls within the currently + compiling component + times address units per word +NARGS <- value of VOP argument +copy the args to the beginning of the current (returner's) frame. + Actually some go into the argument registers. When putting the rest at + the beginning of the frame, leave room for those in the argument registers. +CSP <- CFP + NARGS * address-units-per-word +nil out unused arg regs +OCFP <- CFP (This indicates the start of return values on the stack, + but you leave space for those in registers for convenience.) +CFP <- value of VOP argument with OCFP +CODE <- value of VOP argument with LRA +LIP <- calc target addr (CODE + skip over LRA header word) +jump and run off LIP +\end{verbatim} + +Returnee +The call VOP's call DEFAULT-UNKNOWN-VALUES or RECEIVE-UNKNOWN-VALUES after +spitting out transfer control to get stuff from the returner. + +DEFAULT-UNKNOWN-VALUES +(We know what we want and we got something.) +If returnee wants one value, it never does anything to deal with a shortage +of return values. However, if start at PC, then it has to adjust the stack +pointer to dump extra values (move OCFP into CSP). If it starts at PC+N, +then it just goes along with the ``want one value, got it'' case. +If the returnee wants multiple values, and there's a shortage of return +values, there are two cases to handle. One, if the returnee wants fewer +values than there are return registers, and we start at PC+N, then it fills +in return registers \verb|A1..A<desired values necessary>|; if we start at PC, +then the returnee is fine since the returning conventions have filled in +the unused return registers with nil, but the returnee must adjust the +stack pointer to dump possible stack return values (move OCFP to CSP). +Two, if the returnee wants more values than the number of return registers, +and it starts at PC+N (got one value), then it sets up returnee state as if +an unknown number of values came back: +\begin{verbatim} + A0 has the one value + A1..An get nil + NARGS gets 1 + OCFP gets CSP, so general code described below can move OCFP into CSP +If we start at PC, then branch down to the general ``got k values, wanted n'' +code which takes care of the following issues: + If k < n, fill in stack return values of nil for shortage of return + values and move OCFP into CSP + If k >= n, move OCFP into CSP +This also restores CODE from LRA by subtracting an assemble-time constant. +\end{verbatim} + +RECEIVE-UKNOWN-VALUES +(I want whatever I get.) +We want these at the end of our frame. When the returnee starts at +PC, it moves the return value registers to OCFP..OCFP[An] ignoring where +the end of the stack is and whether all the return value registers had +values. The returner left room on the stack before the stack return values +for the register return values. When the returnee starts at PC+N, bump CSP +by 1 and copy A0 there. +This also restores CODE from LRA by subtracting an assemble-time constant. + + +Local call + +There are three flavors: + 1] KNOWN-CALL-LOCAL + Uses known call convention where caller and callee agree where all + the values are, and there's a fixed number of return values. + 2] CALL-LOCAL + Uses the unknown-values convention, but we expect a particular + number of values in return. + 3] MULTIPLE-CALL-LOCAL + Uses the unknown-values convention, but we want all values returned. + +ALLOCATE-FRAME + +If the number of call arguments (passed to the VOP as an info argument) +indicates that there are stack arguments, then it makes some callee frame for +arguments: +\begin{verbatim} + VOP-result1 <- CSP + CSP <- CSP + control stack frame size for calls within the currently + compiling component + times address units per word. + when (callee-nfp-tn <VOP info arg holding callee>) + ;; The number stack grows down. + ;; May have to round to dual-word boundary if machines C calling + ;; conventions demand this. + NSP <- NSP - number stack frame size for calls within the currently + compiling component + times address units per word + VOP-result2 <- NSP +\end{verbatim} +KNOWN-CALL-LOCAL, CALL-LOCAL, MULTIPLE-CALL-LOCAL +KNOWN-CALL-LOCAL has no need to affect CODE since CODE is the same for the +caller/returnee and the returner. This uses KNOWN-RETURN. +With CALL-LOCAL and MULTIPLE-CALL-LOCAL, the caller/returnee must fixup +CODE since the callee may do a tail full call. This happens in the code +emitted by DEFAULT-UNKNOWN-VALUES and RECEIVE-UNKNOWN-VALUES. We use these +return conventions since we don't know what kind of values the returner +will give us. This could happen due to a tail full call to an unknown +function, or because the callee had different return points that returned +various numbers of values. + +\begin{verbatim} +when (current-nfp-tn VOP-self-pointer) ;Get VOP self-pointer with + ;DEFINE-VOP switch :vop-var. + stack-temp <- NFP +CFP <- value of VOP arg +when (callee-nfp-tn <VOP info arg holding callee>) + <where-callee-wants-NFP-tn> <- value of VOP arg +<where-callee-wants-LRA-tn> <- compute LRA by adding an assemble-time + determined constant to CODE. +jump and run off VOP info arg holding start instruction for callee + +<emit Lisp return address data-block> +<case call convention + known: do nothing + call: default and move return values + multiple: receive return values +> +when (current-nfp-tn VOP-self-pointer) + NFP <- stack-temp +\end{verbatim} + +KNOWN-RETURN +\begin{verbatim} +CSP <- CFP +when (current-nfp-tn VOP-self-pointer) + ;; number stack grows down in memory. + NSP <- NFP + number stack frame size for calls within the currently + compiling component + times address units per word +LIP <- calc target addr (value of VOP arg + skip over LRA header word) +CFP <- value of VOP arg +jump and run off LIP + +\end{verbatim} + + +\chapter{Standard Primitives} + + +\chapter{Customizing VMR Conversion} + +Another way in which different implementations differ is in the relative cost +of operations. On machines without an integer multiply instruction, it may be +desirable to convert multiplication by a constant into shifts and adds, while +this is surely a bad idea on machines with hardware support for multiplication. +Part of the tuning process for an implementation will be adding implementation +dependent transforms and disabling undesirable standard transforms. + +When practical, ICR transforms should be used instead of VMR generators, since +transforms are more portable and less error-prone. Note that the Lisp code +need not be implementation independent: it may contain all sorts of +sub-primitives and similar stuff. Generally a function should be implemented +using a transform instead of a VMR translator unless it cannot be implemented +as a transform due to being totally evil or it is just as easy to implement as +a translator because it is so simple. + + +\section{Constant Operands} + +If the code emitted for a VOP when an argument is constant is very different +than the non-constant case, then it may be desirable to special-case the +operation in VMR conversion by emitting different VOPs. An example would be if +SVREF is only open-coded when the index is a constant, and turns into a miscop +call otherwise. We wouldn't want constant references to spuriously allocate +all the miscop linkage registers on the off chance that the offset might not be +constant. See the :constant feature of VOP primitive type restrictions. + + +\section{Supporting Multiple Hardware Configurations} + + +A winning way to change emitted code depending on the hardware configuration, +i.e. what FPA is present is to do this using primitive types. Note that the +Primitive-Type function is VM supplied, and can look at any appropriate +hardware configuration switches. Short-Float can become 6881-Short-Float, +AFPA-Short-Float, etc. There would be separate SBs and SCs for the registers +of each kind of FP hardware, with each hardware-specific primitive type +using the appropriate float register SC. Then the hardware specific templates +would provide AFPA-Short-Float as the argument type restriction. + +Primitive type changes: + +The primitive-type structure is given a new \%Type slot, which is the CType +structure that is equivalent to this type. There is also a Guard slot, which, +if true is a function that control whether this primitive type is allowed (due +to hardware configuration, etc.) + +We add new :Type and :Guard keywords to Def-Primitive-Type. Type is the type +specifier that is equivalent (default to the primitive-type name), and Guard is +an expression evaluated in the null environment that controls whether this type +applies (default to none, i.e. constant T). + +The Primitive-Type-Type function returns the Lisp CType corresponding to a +primitive type. This is the \%Type unless there is a guard that returns false, +in which case it is the empty type (i.e. NIL). + +[But this doesn't do what we want it to do, since we will compute the +function type for a template at load-time, so they will correspond to whatever +configuration was in effect then. Maybe we don't want to dick with guards here +(if at all). I guess we can defer this issue until we actually support +different FP configurations. But it would seem pretty losing to separately +flame about all the different FP configurations that could be used to open-code ++ whenever we are forced to closed-code +. + +If we separately report each better possibly applicable template that we +couldn't use, then it would be reasonable to report any conditional template +allowed by the configuration. + +But it would probably also be good to give some sort of hint that perhaps it +would be a good time to make sure you understand how to tell the compiler to +compile for a particular configuration. Perhaps if there is a template that +applies *but for the guard*, then we could give a note. This way, if someone +thinks they are being efficient by throwing in lots of declarations, we can let +them know that they may have to do more. + +I guess the guard should be associated with the template rather than the +primitive type. This would allow LTN and friends to easily tell whether a +template applies in this configuration. It is also probably more natural for +some sorts of things: with some hardware variants, it may be that the SBs and +representations (SCs) are really the same, but there are some different allowed +operations. In this case, we could easily conditionalize VOPs without the +increased complexity due to bogus SCs. If there are different storage +resources, then we would conditionalize Primitive-Type as well. + + + +\section{Special-case VMR convert methods} + + (defun continuation-tn (cont \&optional (check-p t)) + ...) +Return the TN which holds Continuation's first result value. In general +this may emit code to load the value into a TN. If Check-P is true, then +when policy indicates, code should be emitted to check that the value satisfies +the continuation asserted type. + + (defun result-tn (cont) + ...) +Return the TN that Continuation's first value is delivered in. In general, +may emit code to default any additional values to NIL. + + (defun result-tns (cont n) + ...) +Similar to Result-TN, except that it returns a list of N result TNs, one +for each of the first N values. + + +Nearly all open-coded functions should be handled using standard template +selection. Some (all?) exceptions: +\begin{itemize} +\item List, List* and Vector take arbitrary numbers of arguments. Could + implement Vector as a source transform. Could even do List in a transform + if we explicitly represent the stack args using \%More-Args or something. +\item \%Typep varies a lot depending on the type specifier. We don't want to + transform it, since we want \%Typep as a canonical form so that we can do + type optimizations. +\item Apply is weird. +\item Funny functions emitted by the compiler: \%Listify-Rest-Args, Arg, + \%More-Args, \%Special-Bind, \%Catch, \%Unknown-Values (?), \%Unwind-Protect, + \%Unwind, \%\%Primitive. +\end{itemize} diff --git a/doc/internals/cmu/vm.tex b/doc/internals/cmu/vm.tex new file mode 100644 index 0000000000..7962e83a7e --- /dev/null +++ b/doc/internals/cmu/vm.tex @@ -0,0 +1,1460 @@ +\chapter{Introduction} % -*- Dictionary: design -*- + +% (defun gvp (f) +% (with-open-file (s f :direction :output :if-exists :supersede) +% (maphash \#'(lambda (k v) +% (declare (ignore v)) +% (format s "~A~%" k)) +% (c::backend-template-names c::*backend*)))) + + +\section{Scope and Purpose} + +This document describes the Virtual Machine that serves as the basis for the +portable implementation of \ccl. The Virtual Machine (hereafter referred to as +the VM) provides a layer of abstraction that hides low-level details of +hardware and implementation strategy, while still revealing enough of the +implementation so that most of the system can be written at the VM level or +above. + +\begin{comment} + +{\#\#\# Shouldn't specify VOPs. Instead, should specify which \clisp functions +are primitive and which subprimitives exist. Isn't really anyone's business +which VOPs actually exist. Each primitive function or subprimitive is +implemented either as a VOP or as expansion into Lisp code, at the particular +implementation's discretion. + +From this point of view, the document is expressing the contract that the Lisp +level code outside of the compiler must satisfy. All functions must ultimately +be defined in terms of primitive functions and sub-primitives. + +The responsibility of the compiler is to implement these primitive operations, +and also to implement special forms, variables and function calling. + +VOPs emitted by the hard-wired translators for non-function nodes are a +somewhat different story. Each implementation will presumably implement all +these VOPs in order to avoid having to rewrite IR2 translation. We also need +to spend quite a bit of time discussing the semantics of these operations, +since they don't just correspond to some \clisp function with type constraints. + +Hard-wired stuff: + +function call +variable access: + global + function + constant + closure + local +closure creation +non-local exit +special binding/unbinding +TN hacking: + move VOPs + TN address (???) +Conditionals: + Basic conditionals: EQ, ... + Interface to generation of other conditional VOPs. + +Some VOPs don't need to be implemented at all: + VOPs to delimit the lifetimes of big stack TNs such as catch blocks + Others? Move VOPs might be defined in terms of an implementation supplied + move routine, since we probably also need this info outside of VOP generators + so that implicit moves can be generated. + + +Type testing/checking (somehow) + +} + +What this document talks about: + +Interface between compiler front-end and back end. (VOPs) + Primitive \clisp operations directly supported by the VM. + Support for complex language features such as function call. + +Sub-primitives that allow system code to do things not possible in \clisp. + +Descriptions of how the current \ccl system uses VM facilities, especially +non-standard ones accessed through sub-primitives. + +Notes about known portability problems. + +Guidelines for writing portable \ccl system code. To some degree these +guidelines are implied by statements that certain things are true of \ccl +system code. + +Descriptions of data structures that are not directly used by the VM, such as +debug information and Core files. + +Descriptions of data structures that are directly used by the VM, such as +symbols and arrays. + + +Who should read it: + +People who want to port \ccl. +People who want to understand the compiler. +People who want to understand how \ccl works. +People who need to write portable \ccl system code. +People such as debugger writers who need to access \ccl\t()'s internal data +structures. + +What it won't do: + +Tell you things that are obviously implementation dependent, such as type +systems or memory management disciplines. See the the various implementation +VM documents. + +Tell you only what you need to know. Programmers shouldn't exploit properties +of the VM documented here unless there is no way to do the same thing in +portable \clisp. + +Tell you how the compiler works. In order to understand some of the subtleties +of VOP descriptions, you will have to understand the IR2 representation and how +it fits into the rest of the compiler. + +Tell you anything about \clisp semantics. When some part of the VM has a +direct relationship to \clisp semantics, the relationship will be directly +stated using \clisp terminology, since a restatement of the semantics is likely +to be inaccurate or misleading. Exceptions will be made only when some +implication of the \clisp semantics is non-obvious. + +Tell you everything about how \ccl works. This document only offers +information that is likely to be needed by programmers doing a port or writing +system code; portable, self-contained parts of the system are totally ignored. +This document deliberately avoids replicating information that is easily +available in the system sources, since such replicated information is always +incorrect somewhere. In some cases, a forwarding pointer to the appropriate +source will be given. + + +Things the VM won't do: + +The VM specification does not totally solve the problem of porting \ccl, since +it is inevitable that it will not map cleanly to all possible combinations of +hardware and operating systems. The VM should not be regarded as being cast in +concrete, since changes in many characteristics would only affect a tiny +fraction of the system sources. + +One current major problem with porting is that large pieces of functionality +are entirely within the VM, and would need to be reimplemented for each port. +A major goal for future work on the system is moving code out of the VM, both +by supporting a ``fast-call'' convention that allows reasonable use of Lisp in +the out of line implementation of VOPs, and by having a ``bugout'' mechanism that +allows the VM to call Lisp functions to implement the hard cases in some VOPs. + +The VM is designed to support conventional, untagged, general register +architectures. Suitably lobotomized, it could be mapped to less flexible +hardware such as ``Lisp machines'', but the compiler would have serious +difficulties supporting stack architectures. + +The VM does not support concurrent lightweight processes. Locking primitives +and deep-binding of specials would be needed. + +The VM does not deal with operating systems interface issues at all. A minimal +port would require implementing at least file and terminal I/O streams. \ccl +implements system interfaces using Aliens and other facilities built on top of +them. + +\end{comment} + + + +Major components: +\begin{itemize} +Specific virtual operations implemented by the VM (VOPs). VOPs are primarily +the concern of the compiler, since it translates Lisp code into VOPs and then +translates VOPs into the implementation. + +Sub-primitives that are used by Lisp code needing to perform operations +below the Lisp level. The compiler implements some sub-primitives directly +using VOPs, while others are translated into Lisp code. Sub-primitives provide +a layer of insulation between the Lisp system code and the VM, since the Lisp +code may assume the existence of operations that are not implemented directly +by the VM. Only sub-primitives with fairly portable semantics are documented +here. Others are in implementation-specific VM documentation. +\end{itemize} + +\comment<Not all sub-primitives are VOPs, and most VOPs are not sub-primitives.> + + + +\subsection{VOP base name rules} + +The names of VOPs that implement functions are based on the function name. +Other VOPs may use any base that doesn't conflict with a function name. There +are some rules used to obtain the base name for related operations. + +To get the name of a setting operation, replace the string ``{\tt ref}'' in the name +with ``{\tt set}''. If ``{\tt ref}'' doesn't appear in the name, add the prefix ``{\tt set-}'' to the +base name. For example, {\tt svref} becomes {\tt svset}, and {\tt symbol-value} +becomes {\tt set-symbol-value}. + +To get the name of a conditional VOP from the name of a predicate, add the +prefix ``{\tt if-}'' to the predicate name. For example, {\tt eq} becomes {\tt if-eq}. +{\tt eq} by itself would be a VOP that returned true or false value. + +Some operations check for some error condition, magically signalling the error +through an implicit control transfer. These operations are prefixed with +``{\tt check-}'', as in {\tt check-fixnum} and {\tt check-bound}. + + + +\subsection{VOP name prefixes and suffixes} + +Prefixes and suffixes are added to the base to get the names of variant +versions of the VOP. The fully general VOP name looks like this: +\begin{format} + {``{\tt small-}'' | ``{\tt fast-}''} {\it name}{``{\tt -c}'' {\it info}}{``{\tt /}'' {\it type}{``{\tt =>}'' {\it result-type}} +\end{format} +The ``{\tt small-}'' and ``{\tt fast-}'' prefixes indicates that the VOP does minimal +safety checking and is optimized for space or speed, respectively. The absence +of a prefix indicates the safest (or only) version. Usually if the ``{\tt small-}'' +VOP exists, it will be a synonym for either the fast version or the safe +version, depending on which is smaller. + +The ``{\tt -c}'' suffix indicates that the some info that is passed as a normal +argument to the base version of the VOP is passed as Codegen-Info in this +version. A typical use would be for VOPs where it is important to use a +different version when one of the arguments is a compile time constant. +{\it info} is some (possibly null) string that indicates which ``{\tt -c}'' variant +is involved. + +The ``{\tt /}{\it type}'' suffix asserts that all operands that could be of {\it type} are. +For example, {\tt +/fixnum} adds two fixnums returning a fixnum, while +{\tt length/simple-vector} finds the length of a simple vector, but the result isn't +a simple vector. + +The ``{\tt =>}{\it result-type}'' suffix supplies a result type assertion on the +operation. + +A not totally silly example of all these modifiers simultaneously is + {\tt fast-+-c/fixnum=>integer}. This operation would this operation adds two +fixnums, one of which is a constant passed as codegen info, resulting in an +integer. The implementation is optimized for speed at the expense of space and +safety. + + + +\chapter{Data Types and Storage Resources} + + +\section{Lisp Objects} +\index{Lisp objects} + +A Lisp object is fixed-size data structure that is organized in a way mandated +by the VM implementation. The fixed format allows the VM to determine the type +of the object. \comment<Virtual type? VM type? Implementation type? +...provides the VM enough information about the type of the object for the VM +to implement the VM-level semantics... ...supports the ``dynamic types''...> + +Lisp objects are stored in locations known as cells. + + +Has major types: immediate and non-immediate. +Non-immediate objects may have a subtype. +Non-immediate types: + symbol (nil may be weird) + cons + ratio + complex + some float types + g-vector + i-vector + string + bit-vector + environment (always has subtype) + array header + bignum + structure + pc (code vector) + stack closure (control stack pointer) + +Non-immediate objects are allocated in ``type spaces''. The type space of an +object is characterized by a small integer known as the type code. Any two +objects of one of the above boxed types will always have the same type code. +{But not really... Some types might be allocated in different type spaces at +different times. (?)} + +The type code doesn't totally describe the object. In general, subtype +information may be involved. + + +Immediate types: + character + fixnum + unbound trap + short float + + + +\section{Type VOPs} + +We consider control transfer to be the fundamental result of comparison, rather +than anything such as a condition code. Although most compilers with whizzy +register allocation seem to explicitly allocate and manipulate the condition +codes, it seems that any benefit is small in our case. This is partly because +our VOPs are at a somewhat higher level, making it difficult to tell which VOPs +do and don't trash the the CC. Explicitly incorporating condition codes in our +VM also introduces another architecture dependency. + +At the IR2 level, we have a class of IF-XXX VOPs which transfer control to one +of two places on the basis of some test on the operands. When generating code +for a predicate, we peek at the destination IF node to find where to transfer +control to. + +The exact representation of type tests in IR2 will be fairly implementation +dependent, since it will depend on the specific type system for the given +implementation. For example, if an implementation can test some types with a +simple tag check, but other types require reading a field from the object in +addition, then the two different kinds of checks should be distinct at the VOP +level, since this will allow the VOP cost and storage information to be more +accurate. Generation of type tests should be factored out of code which would +otherwise be more portable. Probably the IR2 translator for TYPEP and the type +check generation code are the only places that should know about how type tests +are represented in IR2. + +if-type (object) +if-type-range + If-Type Tests whether Object has the type code that is passed in the + codegen info. If-Type-Range tests for a range of type codes. + +{small, fast} if-vector-type (object) + Test that Object is either of the specified type code, or is a 1d array + header with data having the specified type code. + +if-vector-subtype (object) + Test the subtype field of a vector-like object. It is assumed that the + object has already been determined to be vector-like. + +if-fixnump (object) +if-short-float-p +if-characterp + The rationale behind having these as separate VOPs is that they are likely + to be immediate types, and thus may have bizzare type schemes. + +if-consp (object) +if-listp + We have distinct operations for these predicates since one or the other + isn't a simple tag test, but we don't know which one. + +if-rationalp (object) +if-floatp +if-integerp +if-numberp +if-vectorp +if-functionp + The rationale behind having these operations is that they may take a lot of + code, so it is reasonable to put them out of line. + + + +\section{Type Sub-primitives} + +change-type (object) => result + Change the type of an object according to codegen info. The meaning of + this is highly type-system dependent, but it doesn't matter, since the + compiler will never emit this VOP directly. The only way that it can show + up is through %Primitive. +get-type + + +Storage resources: + +Boxed and unboxed locations: +Non-immediate objects may not be stored in unboxed locations. +Things not lisp objects may not be stored in boxed locations. + +Control stack is boxed. +Optional number stack is unboxed. +Heap environment is boxed. +Fixed number of registers, some boxed and some unboxed. + +PCs may be stored on the control stack or in boxed registers, subject to the +constraint that a corresponding environment is also stored. Locations +containing PCs don't need to be zeroed when they are no longer used; nothing +bad will happen if an old PC is unaccompanied by an environment. + + +\item[Trap]Illegal object trap. This value is used in symbols to signify an +undefined value or definition. + + +\chapter{Characters} + + +Character is an immediate type. Characters are manipulated primarily by +converting into an integer and accessing these fields: +\begin{description} +\item[{\tt %character-code-byte}]The character code. This is effectively required to +start at bit 0, since \cl equates {\tt char-int} to {\tt char-code} when there is +no bits or font. All current \ccl systems use ASCII for the character codes, +and define {\tt \#\newline} to be a linefeed, but system code should not count on +this. + +\item[{\tt %character-control-byte}]The character bits. Character bits are used by +Hemlock to describe modifiers in keyboard events, but there is no assumption of +any general portable significance of character bits. + +{\tt %character-font-byte}\\The character font. This is not used by \ccl, and is +not particularly useful. +\end{description} + +Characters should be converted to and from integers by using the \clisp +{\tt char-int} and {\tt int-char} functions, which the compiler translates into +these VOPs: +\begin{example} +char-int (char) => int +int-char (int) => char +\end{example} +In the common case where Char is known to be a {\tt string-char}, these +operations are equivalent to {\tt char-code} and {\tt code-char}. In addition to +providing a portable interface to character conversion, the VOP representation +of this type conversion allows the compiler to avoid unnecessary boxing and +unboxing of character objects. + +Existing code explicitly converts fixnums to characters by using the +Make-Immediate-Type sub-primitive with %Character-Type. Currently conversion +of characters to fixnums is rather confused. Originally, characters were a +subtype of the Misc type code, and the result of the Make-Fixnum sub-primitive +had to be masked with {\tt %character-int-mask}; some code still does this, while +other code may not. + +Character comparisons could be implemented by doing numeric comparisons on the +result of {\tt char-int}, or by using {\tt eq} in the case of {\tt char=}, but this +can result in unnecessary type conversions. Instead, the compiler uses these +conditional VOPs: +\begin{example} +if-char= (x y) +if-char< (x y) +if-char> (x y) +\end{example} + + +\chapter{Symbols} + + +Symbols are currently fairly boring in \ccl, containing only the obvious slots: +\begin{description} +{\tt %symbol-value-slot}\\The current dynamic value of this symbol. If the +symbol is currently unbound, then the value of this slot is the unbound marker. + +{\tt %symbol-function-slot}\\The global function function definition of this +symbol. If the symbol is not fbound, then this slot holds the unbound marker. + +\multiple{ +{\tt %symbol-plist-slot} \* +{\tt %symbol-name-slot} \* +{\tt %symbol-package-slot} +}\\The property list, print name and package for this symbol. +\end{description} + + + +\section{Sub-primitives} + +The {\tt alloc-symbol} sub-primitive allocates a new symbol object. {\it name} is +the simple-string that is to be the name of the symbol. +\begin{example} +alloc-symbol (name) => symbol +\end{example} + +The {\tt set-symbol-package} sub-primitive is used by system code that must set +the symbol package. +\begin{example} +set-symbol-package (symbol new-value) +\end{example} + + + +\section{Accessor VOPs} + +These VOPs read the global symbol value and definition cells. {\tt constant-ref} +may only be used on symbols that have been defined to be constants. Since a +constant cannot change in value and cannot be dynamically bound, the compiler +may be able to compile uses of {\tt constant-ref} more efficiently. Unsafe +versions of these VOPs may not check for the slot being unbound, which the +corresponding \clisp functions are required to do. +\begin{example} +{small, fast} symbol-value (symbol) => value +{small, fast} constant-ref (symbol) => value +{small, fast} symbol-function (symbol) => value +\end{example} + +These VOPs set the global symbol value and definition cells. {\tt makunbound} +and {\tt fmakunbound} are implemented by setting the value to the unbound marker. +\begin{example} +{small, fast} set-symbol-value (symbol new-value) +{small, fast} set-symbol-function (symbol new-value) +\end{example} + +The \clisp accessors for other symbol slots are translated into uses of the +{\tt slot-ref} and {\tt slot-set} VOPs. + + + +\section{Special Binding} + +These VOPs implement dynamic binding of special variables using shallow +binding. {\tt bind} binds {\it symbol} to the specified {\it value}, while +{\tt unbind} undoes the most recent {\it count} special bindings on the binding +stack. +\begin{example} +bind (symbol value) +unbind (count) +\end{example} + + +\section{Property Lists} + +The {\tt get} VOP implements the corresponding \clisp function, while {\tt put} +implements its setf-inverse. +\begin{example} +get (symbol indicator default) => value +put (symbol indicator value) +\end{example} + + +\chapter{Lists} + + +cons + +\begin{example} +list<n> (elt0 ... elt<n-1>) => list +list (elt0 ... elt<n-1> more-elts) => list + For some small N, we have fixed-arg versions of List. For larger lists, we + pass in additional elements in a stack TN (possibly required to be on stack + top). List* is similar. +\end{example} + +These VOPs implement the corresponding \clisp functions: +\begin{example} +{small, fast} car (list) => value +{small, fast} cdr (list) => value +\end{example} + +These VOPs set the car or cdr of a cons: +\begin{example} +{small, fast} set-car (cons new-value) +{small, fast} set-cdr (cons new-value) +\end{example} + +These VOPs implement the \clisp {\tt assoc} and {\tt member} functions with test +functions of {\tt eql} and {\tt eq}: +\begin{example} +assoc (item alist) => cons-or-nil +assq (item alist) => cons-or-nil +member (item list) => cons-or-nil +memq (item list) => cons-or-nil +\end{example} + + +{\tt getf} implements the corresponding \clisp function, while {\tt putf} is used +to implement its setf-inverse. {\tt putf} returns the new value for the list so +that it may stored back into the place. +\begin{example} +getf (list indicator default) => value +putf (list indicator new-value) => list +\end{example} + + +\chapter{Numbers} + +\index{Fixnum format} +Fixnum\\An N-bit two's complement integer. + +\index{Short float format} +Short-Float\\An immediate float format. + +\index{Bignum format} +\label{Bignums} +Bignum\\Bignums are infinite-precision integers, represented somehow. + +\index{Flonum format} +\index{Floating point formats} +Floats\\Floats are stored as consecutive words of bits. + +\index{Ratio format} +Ratio\\Ratios are stored as two consecutive words of Lisp objects, which should +both be integers. + +\index{Complex number format} +Complex\\Complex numbers are stored as two consecutive words of Lisp objects, +which should both be numbers. + + + +\section{Number VOPs} + +integer-length +{small, fast} integer-length/fixnum + +float=>xxx-float + +realpart +lmagpart +numerator +denominator +decode-float +{small, fast} decode-float/xxx-float +scale-float +{small, fast} scale-float/xxx-float + +if-= (x y) +{small, fast} if-=/fixnum +{small, fast} if-=/xxx-float + Do numeric comparison of X and Y. The codegen-info contains the + continuations to transfer to in the true and false cases. Same for $<$, $>$. + ++ (x y) => z +{small, fast} +/fixnum +{small, fast} +/fixnum=>integer +{small, fast} +/xxx-float + Same for -, *. Fixnum multiplication by a constant power of 2 (or near + power of 2) can be done by a transform. + +/ (x y) => z +{small, fast} //xxx-float + +negate +{small, fast} negate/fixnum +{small, fast} negate/fixnum=>integer +{small, fast} negate/xxx-float + Ditto for Abs. + +truncate (x y) => q r +{small, fast} truncate/fixnum + +logand (x y) => z +{small, fast} logand/fixnum + Ditto for logior, logxor. + +lognot (n) => z +{small, fast} lognot/fixnum + +ash (n x) => z +{small, fast} ash/fixnum +{small, fast} ash-c/fixnum + +ldb +dpb +mask-field +deposit-field + These will only be used as a last resort. There should be transforms that + turn fixnum operations with constant byte-specifiers into standard logical + operations. + + +\section{Number Sub-primitives} + + +alloc-bignum +make-complex +make-ratio +lsh +logldb +logdpb + + + +\chapter{Arrays} + +\cl arrays can be represented in a few different ways in \rtccl -- +different representations have different performance advantages. Simple +general vectors, simple vectors of integers, and simple strings are basic \rtccl + data types, and access to these structures is quicker than access to +non-simple (or ``complex'') arrays. However, all multi-dimensional arrays in +\rtccl are complex arrays, so references to these are always through a +header structure. + + +Once a vector has been allocated, it is possible to reduce its length by using +the Shrink-Vector sub-primitive, but never to increase its length, even back to +the original size, since the space freed by the reduction may have been +reclaimed. + + + +\subsection{Arrays} +\label{Arrays} +\index{Arrays} + +An array header is identical in form to a G-Vector. At present, the following +subtype codes are defined: +\begin{itemize, spread 0, spacing 1} +0 Normal. +1 Array is displaced to another array (which may be simple). +\end{itemize} +The entries in the header-vector are interpreted as follows: + +\index{Array header format} +\begin{description} +0 Data Vector \\This is a pointer to the I-Vector, G-Vector, or string that +contains the actual data of the array. In a multi-dimensional array, the +supplied indices are converted into a single 1-D index which is used to access +the data vector in the usual way. If the array is displaced, then this is +the array displaced to, which may be an array header. In general, array +access must loop until it finds an actual data vector. + +1 Number of Elements \\This is a fixnum indicating the number of elements for +which there is space in the data vector. + +2 Fill Pointer \\This is a fixnum indicating how many elements of the data +vector are actually considered to be in use. Normally this is initialized to +the same value as the Number of Elements field, but in some array applications +it will be given a smaller value. Any access beyond the fill pointer is +illegal. + +3 Displacement \\This fixnum value is added to the final code-vector index +after the index arithmetic is done but before the access occurs. Used for +mapping a portion of one array into another. For most arrays, this is 0. + +4 Range of First Index \\This is the number of index values along the first +dimension, or one greater than the largest legal value of this index (since the +arrays are always zero-based). A fixnum in the range 0 to 2\+{24}-1. If any +of the indices has a range of 0, the array is legal but will contain no data +and accesses to it will always be out of range. In a 0-dimension array, this +entry will not be present. + +5 - N Ranges of Subsequent Dimensions +\end{description} + +The number of dimensions of an array can be determined by looking at the length +of the array header. The rank will be this number minus 6. The maximum array +rank is 65535 - 6, or 65529. + +The ranges of all indices are checked on every access, during the conversion to +a single data-vector index. In this conversion, each index is added to the +accumulating total, then the total is multiplied by the range of the following +dimension, the next index is added in, and so on. In other words, if the data +vector is scanned linearly, the last array index is the one that varies most +rapidly, then the index before it, and so on. + + + +\section{Array VOPs} + +alloc-bit-vector +alloc-i-vector +alloc-string +alloc-g-vector + Initialized and uninitialized versions? + + +length (sequence) => size +{small, fast} length/vector +{small, fast} length/simple-vector +{small, fast} length/simple-string +{small, fast} length/simple-bit-vector + +aref1 (vector index) => value +{small, fast} aref1/simple-vector +{small, fast} aref1/simple-string +{small, fast} aref1/simple-bit-vector +{small, fast} aref1/simple-array-XXX-float + +aset1 (vector index new-value) +{small, fast} aset1/simple-vector +{small, fast} aset1/simple-string +{small, fast} aset1/simple-bit-vector +{small, fast} aset1/simple-array-XXX-float + +{small, fast} aref1/simple-array-unsigned-byte (vector index) => value +{small, fast} aset1/simple-array-unsigned-byte (vector index new-value) + Byte size is codegen info. + +aref$<$N$>$ (array index0 ... index<n-1>) => value +aset$<$N$>$ (array index0 ... index<n-1> new-value) + For some small value of N. Of course, higher dimensional arrays can also + be specialized in seven different ways.... Multi-dimensional simple array + reference with known dimensions can be open-coded using a transform (useful + for benchmarks.) + + + +\section{Array Sub-primitives} + +alloc-array +vector-subtype +set-vector-subtype +vector-access-code +set-vector-access-code +shrink-vector + +typed-vref +typed-vset + +header-length (header) => size +header-ref (header index) => value +header-set (header index new-value) + +bit-bash +byte-blt +{reverse-}find-character +{reverse-}find-character-with-attribute +{reverse-}string-compare +sxhash-simple-string +sxhash-simple-substring + + +\chapter{Structures} + +{small, fast} structure-ref (s) => value +{small, fast} structure-set (s new-value) + Read and write structure slots. Defstruct slot description is in codegen + info. + +alloc-structure + + +\chapter{Runtime Environment} +\index{Runtime Environment} +\label{Runtime} + + +\section{Register Allocation} +\index{Register allocation} + +The main idea is to globally allocate only those registers with global +significance. + +We permanently dedicate the CONT register to point to the current control stack +environment. This is the ``frame pointer'' in standard terminology. It isn't +possible to get pack to allocate this register on an as-needed basis due to the +classic phase-ordering problem. We need to know if TNs are allocated on the +stack before we can determine tell how badly we need a frame pointer register. +This is of little significance with the control stack environment, since we +almost always need one, and if there are any stack TNs, we must allocate the +frame pointer in a register, since there is nowhere else to put it. The +problem is more severe with a number stack environment pointer. We can't +dedicate a register to it, since we usually don't have any TNs on the number +stack. The only easy solution is to always allocate the number stack +environment pointer on the control stack. This really isn't too bad, when you +compare the cost of doing an extra memory reference to get at the number stack +to the cost of number-consing. + +We also dedicate the ENV register to the current constant pool. It would be +possible to explicitly allocate the constant pointer as needed if we explicitly +represented non-immediate constant access by a VOP, but this would be extra +work, and there are major advantages to representing all constants using TNs. +Another potential efficiency advantage is since the same constant pool is +shared by all the code in a component, we need only initialize ENV on entry to +the component. When we make local calls, we don't have to do anything to make +the constants available to the callee. + +Since the constant pool will also contain the code vector and the debug info, +having it in a known place may make life easier for GC and the debugger. We +may not be able to count on it too much, though, since ENV holds other things +will calls are in progress, and might be pretty random if we jumped into +hyperspace. + + +Runtime environment: + +CONT: the current control stack context. +PC is assumed to be accessible to the debugger when an error happens. +Current-Catch: pointer to the current catch frame. Format of frame is assumed. +Current-Unwind-Protect: current unwind protect frame. Similar to catch. + +If shallow-bind, binding stack and binding stack pointer. +If deep-bind, current special binding. Format of binding frame assumed. + +Everything depends on the current environment, which is CONT. + +\begin{verbatim} +PC +OLD-CONT +ENV +A<n> +CONT +CS +\end{verbatim} + +\section{Other Dynamic State} + +There are some dynamic state variables that are stored in known memory +locations, rather than having a dedicated register: +\begin{description} +binding stack pointer\\The current pointer to the top of the binding stack. + +current catch\\The pointer to the current catch block. + +current unwind-protect\\The pointer to the current unwind-protect block. +\end{description} + + + + +\section{Control-Stack Format} +\label{Control-Stack-Format} +\index{Control-stack format} + + +The control stack contains only Lisp objects. Every object pointed to by an +entry on this stack is kept alive. + +The \rtccl control stack does not have a rigid frame structure. The compiler +is allowed a large amount of freedom in the use of the stack so that it choose +the best calling sequences. Mostly the compiler is the only system that cares +how the stack is laid out, so this isn't a big problem. See chapter +\ref{debug-info} for a description of the structures which allow the debugger +to parse the stack. + + + +\section{Values Passing Conventions} + + +The first {\it nregs} arguments are passed in registers, where nregs is an +implementation dependent constant. Any additional arguments are the block of +storage between CONT and CS on the control stack. The first nregs locations in +this block of storage are unused so that register more-args can be stored on +the stack without having to BLT the stack values up. + +Returning unknown values are passed in a similar way, but the stack values +block is between OLD-CONT and CS. There isn't any underneath the values: on +return OLD-CONT is always what CS was when the function was called. The +function returned to must copy the values into the desired location in its +frame and deallocate excess stuff on the top of the stack. + +More args are represented by a pointer to the block of values and a count. The +function that originally created the more arg must allocate and deallocate this +stuff somehow. In the case of a local call to a more arg entry, we can just +allocate it as a TN. The external entry point for a more arg entry is more +magical. + + + +The caller allocates the environment for the called function, stores the +arguments into it, and jumps to the function. The caller makes the called +environment current, passing in the return OLD-CONT and PC as explicit arguments. + +When returning values, the returner directly stores the return values into the +frame being returned to. This works even though the caller doesn't know what +function it is returning to, since the same return locations are allocated in +all frames. + +In a tail-recursive call, we can destructively modify the current frame and +jump right to the callee, rather than allocating a new frame. We can do this +because TNBind globally allocates frame locations; all frames are the same size +and have the same TNs in the same place. + + +\section{Binding-Stack Format} +\index{Binding stack format} +\comment<In a symbol chapter?> + + +The special binding stack is used to hold previous values of special variables +that have been bound. It grows and shrinks with the depth of the binding +environment, as reflected in the control stack. This stack contains +symbol-value pairs, with only boxed Lisp objects present. + +Each entry of the binding-stack consists of two boxed (32-bit) words. Pushed +first is a pointer to the symbol being bound. Pushed second is the symbol's +old value (any boxed item) that is to be restored when the binding stack is +popped. + + +\chapter{Functions} + +Function calling is a way of life. + +every function is a closure. pointer to current closure is passed in ENV +unless it isn't (in local call may be elsewhere). + +The description of the representation of functions and the function calling +conventions is a large part of the VM description, since: + Function calling is one of the most complicated facilities provided by the + VM. + + Everything that happens, happens in a function, so all parts of the system + tend to get dragged in. + + +Aspects of function call: + Control + Environment CONT, ENV + Argument/value passing + Argument/value count dispatching + + + + +\section{Function Object Format} +\label{Fn-Format} + +The old notion of a ``function object'' is now broken down into four different +parts: +\begin{description} +Function entry\\A function entry is a structure that holds the information +that we need to call a function. This is the user visible function object. + +Environment\\The environment is stuff that a function needs when it runs. +This includes constants computed at load time and variables closed over at run +time. Environment information may be allocated in the function entry structure +after the required linkage information. + +Entry information\\This is information about a specific function entry that is +occasionally referenced at run time, but need not be immediately accessible. +Entry information will be either allocated in the function entry +or in the environment that it points to. + +Debug information\\This is information about a function that isn't normally +needed at run time. Debug information can be found by poking around in +environment objects. +\end{description} +See chapter \ref{control-conventions} for a description of how function objects +are used. + + +\section{Environment Object Sub-primitives} + +alloc-code ? +alloc-closure? + + +\subsection{Debug Information Location} + +If present, debug information is stored immediately following any fixed +information in the environment object. It may be necessary to chain up +multiple levels of environments to find the debug information. The debug +information can be recognized because it is represented by a defstruct +structure. See chapter \ref{debug-info} for a description of the debug +information. + + +\section{Function Calls} +\index{function call} + +\ccl supports three major calling conventions. The convention used +depends on the amount of information available at compile time: +\begin{description} +Local\\Local call is used when the call and the called function are +compiled at the same time. Using the term ``convention'' to describe this +call mechanism is somewhat of a misnomer, since the compiler can do +whatever it wants. + +Named\\Named call is used when the call is to a global function whose name +is known at compile time. + +Anonymous\\Anonymous call is used when the function called is unknown until +run time. +\end{description} + +\#| +IR2 function call: + +Environment manipulation code is always emitted at the location of the Bind or +Return node for a Lambda. + +Implicit args to functions in IR2: +\begin{description} +\item[old-cont] cont to restore on return +\item[return-pc] pc to return to +\item[env] pointer to current closure (if heap) +\item[closure$<$n$>$] closed values for current closure (if stack) +\end{description} + +Other info needed for IR2 conversion of functions: +\begin{itemize} +\item base pointers for all heap closures consed by this function also + have passing locs for each explicit arg return strategy (known or + unknown) and return locs +\end{itemize} + + +All arguments including implicit ones must have both a passing TN and a +permanent TN. Passing locs for let calls can be the actual TN that holds the +variable in the case of local variables. Set closure variables must still have +a separate passing TN. + +If we know the values counts for the argument continuations, then we compile +local mv-calls by moving the TNs for the values continuations into the argument +passing locations. Other mv-calls must be compiled using various hairy +stack-hacking VOPs and unknown argument count call VOPs. + +For now, we will create the callee's frame just before the call, instead of +creating it before the evaluation of the first argument. If we created the +environment early, then we would be able to move the argument values directly +into the frame, instead of having to store them somewhere else for a while. +The problem with early creation is that lifetime analysis gets confused because +there is more than one instance of the same TN present simultaneously in the +case where there are nested calls to the same function. + +It turns out that there isn't a problem with a simple self-call, because the TN +in the called frame is really the ``same'' TN as the one in the current frame, +due to the restricted way in which we use the passing TNs. + +We emit code for external entry points during IR2 conversion. The external +entry point is the place where we start running in a full call from a +function-entry. It does arg count checking and dispatching, moves the +arguments into the passing locations for the for the lambda being called, and +calls the lambda, moving the results into the standard locations if there +aren't there already. +|\# + + +In IR2, the environment manipulation semantics of function call are decoupled +from the control semantics. When allocating closure variables for a Let, it is +possible to do environment manipulation with only the normal sequential control +flow. In the case of a Let call with the same environment, we neither +manipulate the environment nor transfer control; we merely initialize the +variables with Move VOPs. + +If a local function returns a known number of values which is less than the +number expected by the caller, then additional code must be inserted at the +return site which sets the unused values to NIL. + +The full function call mechanism must effectively be a subset of the local call +mechanism, since the two mechanisms must mesh at entry points and full function +calls. A full call turns into some kind of full call VOP. There are different +VOPs for calling named functions and closures. We also have tail-recursive +full call VOPs. Arguments are set up using Move VOPs, just as for local call. +The only difference is that the passing locations and conventions are +restricted to the standard ones. + +The gory details of arg count checking and dispatching are buried in the +Function-Entry VOP, which takes a functional and a list of continuations, one +pointing to each external entry. + + +\subsection{Local Call} +\index{local call} + +Named and anonymous call are called full calls, to distinguish them from +local call. When making full calls, the compiler must make many worst-case +assumptions that aren't necessary in a local call. The advantage of local +call is that the compiler can choose to use only those parts of the full +call sequence that are actually necessary. + +In local call, we always know the function being called, so we never have +to do argument count checking, and can always use an immediate branch for +the control transfer. If the function doesn't return to more than one +place, then can just use a simple branch, or even drop through. + +The argument passing TNs may be allocated anywhere. The caller allocates the +stack frame for the called function, moving any non-register arguments into the +passing locations in the callee's frame. + +If we are calling a local function that doesn't always return the same +number of values, then we must use the same values returning mechanism that +is used in full call, but we don't have to use the standard registers. + +A tail-recursive local call doesn't require any call VOP. We just use Move +VOPs to put the arguments into the passing locations and then jump to the the +start of the code for the function. We don't have to do any stack hackery +since we use the same stack frame format for all the functions compiled at the +same time. In many cases tail-recursive local calls can be entirely optimized +away, since they involve only some moves and a branch. We preference the +argument values to the passing locations of the called function, making it +likely that no move will be necessary. Often the control transfer can be done +by simply dropping through. + +We have to do some funny stuff with local calls in order to get the lifetimes +for the passing locations right, since lifetime analysis skips directly from +the return point to the call point, ignoring the uses of the passing locations +in the called function. Similarly, we pretend that a block ending in a return +has no successors. + +call-local (arg*) ``fun'' => value +multiple-call-local (arg*) ``fun'' =$>$ start end val0 ... val$<$n$>$ + Call-Local is used for calls to local functions that are forced to use the + unknown-values passing convention. Value is the first return value + register; we don't really do anything to it, but we specify it as a result + to represent the assignment done by the calling function. + + Multiple-Call-Local is similar, but specifies all the values used by the + unknown-values convention. Default-Values may be used to receive a + specific number of values. + +known-call-local (arg*) ``fun'' =$>$ value* + This VOP is used for local calls to functions where we can determine at + compile time that the number of values returned is always the same. In + this case, we don't need to indicate the number of values, and can pass + them in separate TNs. The Values are the actual return locations. We + don't really do anything to the return values; we just specify them as + results to represent the assignment done by the called function. + +known-return (return-pc value*) ``fun'' + This VOP is used for returning from local calls using the known return + values convention. The specified return Values are moved into the passing + locations in the caller's frame. + + +If we know that the function we are calling is non-recursive, then we can +compile it much like a tail-recursive call. We must have a call VOP to compute +the return PC, but we don't need to allocate a frame or save registers. We +just set up the arguments in the frame and do the call. + +We require simple functions to use the known-values convention. It would be +possible to support unknown values, but it would potentially require BLT'ing +return values out of the frame and on to the top of the stack. Supporting +unknown values would also require a bunch more VOPs, since we need different +call and return VOPs for simple call. + +Known values return causes no problems, since the callee knows how many values +are wanted. We store the values directly into the current frame, since it is +also the caller's frame. + +known-call-simple () ``fun'' =$>$ return-pc +known-return-simple (return-pc) ``fun'' + Similar to the non-simple VOPs, but don't allocate or deallocate frames, + and assume that argument and value passing is done with explicit Move VOPs. + + +\subsection{Full Call} +\index{full call} + +Both named and anonymous call are optimized for calls where the number of +arguments is known at compile time. Unknown argument calls are a +pathological case of anonymous call; this case will be ignored in the main +discussion. The difference between named and anonymous calls is in the +argument count dispatching mechanism. + +Named call allows an arbitrary number of entry points, with start PCs at +arbitrary locations in the code vector. The link-table mechanism described +below allows named calls to jump directly to the actual entry point without any +run-time argument count or type checking checking. + +Anonymous call has a fixed number of entry points, with start PCs at fixed +locations in the code vector. This allows calls to be made without knowing +what function is being called, but has more run-time overhead. The object +called must be checked to be a valid function-entry object. The entry PC must +be computed from the function entry, and argument count checking must be done +if there are more than three required or optional arguments. + +Argument passing in full call is conceptually similar to local call, but the +caller can't allocate the entire frame for the callee, since it doesn't know +how much stack is needed. Instead we allocate the frame in two parts. The +caller only allocates the beginning of the frame, which contains the stack +arguments in fixed locations. We leave the first $<$n$>$ locations unused so that +the called function can move register more args onto the stack without having +to BLT down any stack arguments. + +The place in the code where a full call jumps in is called an external entry +point. The external entry point allocates the rest of the stack frame and then +does a local call to the actual entry-point function, fetching the arguments +from the standard passing locations. Usually we can do a tail-recursive local +call. + +There are two main cases where the call from the external entry point cannot be +tail-recursive: + -- It is desirable to use the known-values convention for calling the + entry-point function if the entry-point is used in other local calls + (perhaps because of recursion). In this case, the called function stores + the return values back into the frame allocated by the external entry point + and then returns back to it. The external entry point must then return + these values using the standard unknown-values convention. + -- In a more-arg entry point we don't know how many stack arguments there are + at the beginning of the frame, so we can't really use the frame allocated + by the external entry point at all. Instead we do a local call to the + more-arg entry point, passing in a pointer to the first extra value. When + the function returns, we deallocate the crap on the stack and then return + the values. It is still o.k. to use the known-values return convention + from the more-arg entry since the extra arg values are no longer needed by + the time the returning function stores the return values back into the + external entry point frame. + + +In full call we must always use the unknown-values convention for return. The +first $<$n$>$ values are passed in the standard argument registers. The Old-Cont +register holds the Start of the values block and SP points to the End. + + +{small, fast} call (function arg0 ... arg$<$n$>$) ``nargs'' =$>$ value +{small, fast} call-named (arg0 ... arg$<$n$>$) ``nargs'' ``name'' =$>$ value + Call-Closure calls Function with the specified register arguments, + returning the first value as the result. ``nargs'' is the total number of + arguments passed. Only the register arguments actually passed should be + specified as operands. + + Call-Named is similar, but calls a global function specified at compile + time by ``name''. + +{small, fast} tail-call (function pc arg0 ... arg$<$n$>$) ``nargs'' +{small, fast} tail-call-named (pc arg0 ... arg$<$n$>$) ``nargs'' ``name'' + Similar to the standard call VOPs, but passes PC as the return PC, rather + than returning to the call site. These VOPs have no results since they + don't return. + +{small, fast} multiple-call (function arg0 ... arg$<$n$>$) ``nargs'' + =$>$ start end val0 ... val$<$n$>$ +{small, fast} multiple-call-named (arg0 ... arg$<$n$>$) ``nargs'' ``name'' + =$>$ start end val0 ... val$<$n$>$ + These VOPs are similar to the standard call VOPs, but allow any number of + values to be received by returning all the value passing registers as + results. A specific number of values may be received by using + Default-Values. + +call-unknown (function count arg0 ... arg$<$n$>$) =$>$ start end val0 ... val$<$n$>$ +tail-call-unknown (function pc count arg0 ... arg$<$n$>$) + Call a function with an unknown number of arguments. Used for apply and + hairy multiple-value-call. + +Function-Entry () ``function'' =$>$ env return-pc old-cont arg* + This marks the place where we jump into a component for an external + entry point. It represents whatever magic is necessary to do argument + count checking and dispatching. The external entry points for each + argument count will be successors of the entry-vector block (might be in + the same block if only one?) + + Function-Entry also represents argument passing by specifying the actual + external passing locations as results, thus marking the beginning of their + lifetimes. All passing locations actually used by any entry point are + specified as Args, including stack arguments. + {\#\#\# Do we really need this? If we do, then we probably also need similar + entry markers for local functions. The lifetimes don't really need to be + explicitly bounded, since an entry point is effectively ``the end of the + world.''} + + +\section(Returning from a Function Call) +\label(Return) +\index(Return) + + +return (return-pc value) +multiple-return (return-pc start end val0 ... val$<$n$>$) + Return Value from the current function, jumping back to the location + specified by Return-PC. {Perhaps allow to return any fixed, known number + of values.} + + Multiple-Return is similar, but allows an arbitrary number of values to be + returned. End - Start is the total number of values returned. Start + points to the beginning of the block of return values, but the first $<$n$>$ + values val0 ... val$<$n$>$ are actually returned in registers. + +default-values (start end val0 ... val$<$n$>$) =$>$ val0 ... val$<$j$>$ + This VOP is used when we want to receive exactly J values. If fewer than J + values were supplied, then missing values are defaulted to NIL. As a + side-effect, this VOP pops off any returned stack values. + + +\section{Saving and Restoring Registers} + +We use a caller-saves convention. The caller explicitly emits saving and +restoring code. Tail-recursive calls don't need +any register saving since we never come back. + + + +\chapter{Non-local exits} + + +\subsection{Unwind Blocks} +\index{Catch} +\index{Catch frames} + +There is one aspect of the control stack format that is fixed, and which +concerns us at this level. This is the format of the ``frames'' which mark the +destination of non-local exits, such as for BLOCK and CATCH. These frames are +collectively known as unwind blocks. The basic unwind block is used for +lexical exists such as BLOCK, and for UNWIND-PROTECT. Its format is the +following: +\begin{verbatim} +0 Pointer to current unwind-protect. +1 Control stack context to restore on entry. +2 PC to enter at. +\end{verbatim} + +The unwind block for CATCH is identical except for additional cells +containing the catch tag and previous catch. +\begin{verbatim} +0 Pointer to current unwind-protect. +1 Control stack context to restore on entry. +2 PC to enter at. +3 Catch tag. +4 Previous catch. +\end{verbatim} + +The conventions used to manipulate unwind blocks are described in chapter +\ref{Control-Conventions}. + + + +\section{Non-Local Exits} +\label{Catch} +\index{Catch} +\index{Throw} +\index{Unwinding} +\index{Unwind-Protect} +\index{Non-Local Exits} + +In the normal flow of control, each function that is called executes until it +reaches a return point; under these conditions no special effort is needed to +restore the environment as long as each function undoes any change that it +makes to the dynamic state before it returns. When we make a non-local +transfer, we skip a potentially arbitrary collection of these cleanup actions. +Since we cannot in general know what changes have been made to the dynamic +environment below us on the stack, we must restore a snapshot of the dynamic +environment at the re-entry point. + +We represent the closed continuation by the pointer to the unwind-block for the +reentry point. At the exit point, we just pass this stack pointer to the +Unwind VOP, which deals with processing any unwind-protects. When Unwind is +done, it grabs the re-entry PC out of the location at the stack pointer and +jumps in. + +Catch and Unwind-Protect work in pretty much the same way. We make a stack TN +to hold the catch frame or whatever, allocate TNs in them to represent the +slots, and then initialize them. The frame can be explicitly linked in by TN +manipulations, since the active catch and whatnot are represented by TNs. +Since allocation of the frame is decoupled from linking and unlinking, some of +this stuff could be moved out of loops. We will need a VOP for loading the PC +for an arbitrary continuation so that we can set up the reentry PC. This can +be done using the Call VOP. Using a call instruction is probably a good way to +get a PC on most architectures anyway. + +These TNs are allocated by Pack like any others; we use special alloc and +dealloc VOPs to delimit the aggregate lifetimes. + +In the non-local case, the the Block, Catch and Unwind-Protect special forms +are implemented using unwind blocks. The unwind blocks are built by move +operations emitted inline by the compiler. The compiler adds and removes +catches and unwind protects by explicit moves to the locations that hold the +current catch and unwind protect blocks. The entry PC is loaded using the Call +VOP. + +The Unwind miscop is the basis non-local exits. It takes the address of an +unwind block and processes unwind-protects until the current unwind-protect is +the one recorded in the unwind block, then jumps in at the entry in the unwind +block. The entry for the unwind block is responsible for restoring any state +other than the current unwind-protect. + +Unwind is used directly to implement non-local Return-From. The address of the +unwind block is stored in a closure variable. + +Catch just does a scan up the chain of Catch blocks, starting at the current +catch. When it finds the right one, it calls unwind on it. + +Unwind-protects are represented by unwind blocks linked into the current +unwind-protect chain. The cleanup code is entered just like any other any +other unwind entry. As before, the entry is responsible for establishing the +correct dynamic environment for the cleanup code. The target unwind block is +passed in some non-argument register. When the cleanup code is done, it +just calls Unwind with the block passed in. The cleanup code must be careful +not to trash the argument registers or CS, since there may be multiple values +lurking out there. + +With Catch/Throw, we always use the variable values return value passing convention, +since we don't know how many values the catch wants. With Block/Return-From, +we can do whatever we want, since the returner and receiver know each other. + +If a Block or Catch receives stack values, it must call a VOP that BLT's the +values down the stack, squeezing out any intermediate crud. + + +unwind (context) +throw (tag) + Unwind does a non-local exit, unwinding to the place indicated by Context. + Context is a pointer to a block of storage allocated on the control stack, + containing the entry PC, current environment and current unwind-protect. + We scan up the stack, processing unwind-protects until we reach the entry + point. The values being returned are passed in the standard locations. + Throw is similar, but does a dynamic lookup for the Tag to determine what + context to unwind to. + diff --git a/doc/internals/foreign-linkage.texinfo b/doc/internals/foreign-linkage.texinfo index 54320d5072..e955054726 100644 --- a/doc/internals/foreign-linkage.texinfo +++ b/doc/internals/foreign-linkage.texinfo @@ -19,7 +19,7 @@ also utilized to allow references to as-of-yet unknown aliens. The SBCL implementation is somewhat simplified from the CMUCL one by Timothy Moore, but the basic idea and mechanism remain identical: instead of having addresses from @code{dlsym(3)} in the core, we have -addresses to an mmapped memory area (@code{LINKAGE_TABLE_SPACE}) that +addresses to an mmapped memory area (@code{ALIEN_LINKAGE_TABLE_SPACE}) that is initialized at startup to contain jumps & references to the correct addresses, based on information stored on the lisp side in @code{*LINKAGE-INFO*}. @@ -28,26 +28,18 @@ addresses, based on information stored on the lisp side in CMUCL does lazy linkage for code, keeps all foreign addresses in the linkage-table, and handles the initialization from C. We do eager -linkage for everything, maintain a separate -@code{*STATIC-FOREIGN-SYMBOLS*} just like on non-linkage-table ports -(this allows more code sharing between ports, makes thread-safety -easier to achieve, and cuts one jump's worth of overhead from stuff -like closure_tramp), and do the initialization from lisp. +linkage for everything, initialize only the runtime-critical symbols +from C, and initialize anything else from lisp. @subsection Nitty Gritty Details -Symbols in @code{*STATIC-FOREIGN-SYMBOLS*} are handled the old -fashioned way: linkage-table is only used for symbols resolved with -@code{dlsym(3)}. - On system startup @code{FOREIGN-REINIT} iterates through the @code{*LINKAGE-INFO*}, which is a hash-table mapping dynamic foreign names to @code{LINKAGE-INFO} structures, and calls @code{arch_write_linkage_table_entry} to write the appropriate entries to the linkage-table. -When a foreign symbol is referred to, it is first looked for in the -@code{*STATIC-FOREIGN-SYMBOLS*}. If not found, +When a foreign symbol is referred to, @code{ENSURE-FOREIGN-LINKAGE} is called, which looks for the corresponding entry in @code{*LINKAGE-INFO*}, creating one and writing the appropriate entry in the linkage table if necessary. @@ -80,8 +72,7 @@ is used by SB-POSIX.) Find a memory area for the linkage-table, and add it for the OS in @file{src/compiler/target/parms.lisp} by defining -@code{SB-VM:LINKAGE-TABLE-SPACE-START} and -@code{SB-VM:LINKAGE-TABLE-SPACE-END}. See existing ports and CMUCL for +@code{SB-VM:ALIEN-LINKAGE-TABLE-SPACE-START}. See existing ports and CMUCL for examples. @subsubsection Porting to new architectures @@ -90,7 +81,7 @@ Write @code{arch_write_linkage_table_entry}. Write @code{FOREIGN-SYMBOL-DATAREF} VOP. -Define correct @code{SB-VM:LINKAGE-TABLE-ENTRY-SIZE} in +Define correct @code{SB-VM:ALIEN-LINKAGE-TABLE-ENTRY-SIZE} in @file{src/compiler/target/parms.lisp}. @page @@ -98,12 +89,12 @@ Define correct @code{SB-VM:LINKAGE-TABLE-ENTRY-SIZE} in @comment node-name, next, previous, up @section Lazy Alien Resolution -On linkage-table ports SBCL is able to deal with forward-references to +SBCL is able to deal with forward-references to aliens -- which is to say, compile and load code referring to aliens before the shared object containing the alien in question has been loaded. -This is handled by @code{ENSURE-DYNAMIC-FOREIGN-SYMBOL-ADDRESS}, which +This is handled by @code{ENSURE-FOREIGN-SYMBOL-LINKAGE}, which first tries to resolve the address in the loaded shared objects, but failing that records the alien as undefined and returns the address of a read/write/execute protected guard page for variables, and address @@ -113,7 +104,7 @@ signalling the appropriate error. These placeholder addresses get recorded in the linkage-table. -When new shared objects are loaded @code{UPDATE-LINKAGE-TABLE} is +When new shared objects are loaded @code{UPDATE-ALIEN-LINKAGE-TABLE} is called, which in turn attempts to resolve all currently undefined aliens, and registers the correct addresses for them in the linkage-table. diff --git a/doc/internals/objects-in-memory.texinfo b/doc/internals/objects-in-memory.texinfo index 6154c8edcf..f1117b2c42 100644 --- a/doc/internals/objects-in-memory.texinfo +++ b/doc/internals/objects-in-memory.texinfo @@ -217,8 +217,8 @@ value for the symbol (based on the symbol name), which avoids having to recompute the hash from the name every time it is required. The other additional slot, on threaded systems only, is the TLS index, -which is either @code{no-tls-value-marker-widetag} or an unboxed byte -offset within the TLS area to the TLS slot associated with the symbol. +which is a byte offset within the TLS area to the TLS slot associated +with the symbol. Because the unboxed offset is aligned to a word boundary it appears as a @code{fixnum} when viewed as boxed data. It is not, in general, safe to increment this value as a @code{fixnum}, however, in case diff --git a/doc/internals/signals.texinfo b/doc/internals/signals.texinfo index 9c80adb966..b0105e1a6d 100644 --- a/doc/internals/signals.texinfo +++ b/doc/internals/signals.texinfo @@ -174,7 +174,7 @@ is dangerous and best avoided. @section Debugging It is not easy to debug signal problems. The best bet probably is to -enable @code{QSHOW} and @code{QSHOW_SIGNALS} in runtime.h and once +enable @code{QSHOW} in runtime.h and once SBCL runs into problems attach gdb. A simple @code{thread apply all ba} is already tremendously useful. Another possibility is to send a SIGABRT to SBCL to provoke landing in LDB, if it's compiled with it @@ -182,5 +182,4 @@ and it has not yet done so on its own. Note, that fprintf used by QSHOW is not reentrant and at least on x86 linux it is known to cause deadlocks, so place SHOW and co carefully, -ideally to places where blockable signals are blocked. Use -@code{QSHOW_SAFE} if you like. +ideally to places where blockable signals are blocked. diff --git a/doc/internals/string-types.texinfo b/doc/internals/string-types.texinfo index 663c784b2c..0a60a818a7 100644 --- a/doc/internals/string-types.texinfo +++ b/doc/internals/string-types.texinfo @@ -51,6 +51,7 @@ Objects of type @code{(simple-array nil (*))} are represented in memory as two words: the first is the object header, with the appropriate widetag, and the second is the length field. No memory is needed for elements of these objects, as they can have none. +Such object are not strings though. Objects of type @code{simple-base-string} have the header word with widetag, then a word for the length, and after that a sequence of diff --git a/doc/manual/contrib-modules.texinfo b/doc/manual/contrib-modules.texinfo index 43f82e3b72..7862d70155 100644 --- a/doc/manual/contrib-modules.texinfo +++ b/doc/manual/contrib-modules.texinfo @@ -17,6 +17,7 @@ contributed modules. * sb-posix:: * sb-queue:: * sb-rotate-byte:: +* sb-simd:: @end menu @page @@ -43,4 +44,5 @@ contributed modules. @page @include sb-rotate-byte/sb-rotate-byte.texinfo - +@page +@include sb-simd/sb-simd.texinfo diff --git a/doc/manual/debugger.texinfo b/doc/manual/debugger.texinfo index a90e75a3a9..42ed6af63f 100644 --- a/doc/manual/debugger.texinfo +++ b/doc/manual/debugger.texinfo @@ -825,6 +825,9 @@ that all variable values are available at any known location within the scope of the binding. This has a speed penalty in addition to the obvious space penalty. +Inlining of local functions is inhibited so that they may be +@code{trace}d. + @item > (max speed space) If @code{debug} is greater than both @code{speed} and @code{space}, the command @command{return} can be used to continue execution by @@ -1086,6 +1089,8 @@ function entry or exit. @include var-sb-debug-star-trace-encapsulate-default-star.texinfo +@include var-sb-debug-star-trace-report-default-star.texinfo + @comment FIXME rudi 2004-03-26: encapsulate is (per TODO file as of @comment 0.8.9) in a state of flux. When it's sorted out, revive the @comment cmucl documentation. diff --git a/doc/manual/docstrings.lisp b/doc/manual/docstrings.lisp index 9a1e72e810..ede40cfa6d 100644 --- a/doc/manual/docstrings.lisp +++ b/doc/manual/docstrings.lisp @@ -414,7 +414,10 @@ there is no corresponding docstring." (cond ((or key optional) (car x)) (t (clean (car x)))) (clean (cdr x) :key key :optional optional)))))) - (clean (sb-introspect:function-lambda-list (get-name doc)))))))) + (multiple-value-bind (ll unknown) (sb-introspect:function-lambda-list (get-name doc)) + (if unknown + (values nil t) + (clean ll)))))))) (defun get-string-name (x) (let ((name (get-name x))) @@ -739,7 +742,7 @@ followed another tabulation label or a tabulation body." ;;; KLUDGE: &AUX *PRINT-PRETTY* here means "no linebreaks please" (defun texinfo-begin (doc &aux *print-pretty*) (let ((kind (get-kind doc))) - (format *texinfo-output* "@~A {~:(~A~)} ~(~A~@[ ~{~A~^ ~}~]~)~%" + (format *texinfo-output* "@~A {~:(~A~)} ~(~A~)" (case kind ((package constant variable) "defvr") @@ -748,15 +751,24 @@ followed another tabulation label or a tabulation body." (t "deffn")) (map 'string (lambda (char) (if (eql char #\-) #\Space char)) (string kind)) - (title-name doc) - ;; &foo would be amusingly bold in the pdf thanks to TeX/Texinfo - ;; interactions,so we escape the ampersand -- amusingly for TeX. - ;; sbcl.texinfo defines macros that expand @andkey and friends to &key. - (mapcar (lambda (name) - (if (member name lambda-list-keywords) - (format nil "@and~A{}" (remove #\- (subseq (string name) 1))) - name)) - (lambda-list doc))))) + (title-name doc)) + (multiple-value-bind (lambda-list unknown) (lambda-list doc) + (cond (unknown + (format *texinfo-output* " @emph{lambda list not known}")) + ((not lambda-list)) + (t + ;; &foo would be amusingly bold in the pdf thanks to + ;; TeX/Texinfo interactions,so we escape the ampersand -- + ;; amusingly for TeX. sbcl.texinfo defines macros that + ;; expand @andkey and friends to &key. + (format *texinfo-output* " ~(~{~A~^ ~}~)" + (mapcar (lambda (name) + (if (member name lambda-list-keywords) + (format nil "@and~A{}" + (remove #\- (subseq (string name) 1))) + name)) + lambda-list))))) + (format *texinfo-output* "~%"))) (defun texinfo-inferred-body (doc) (when (member (get-kind doc) '(class structure condition)) diff --git a/doc/manual/efficiency.texinfo b/doc/manual/efficiency.texinfo index db69d049f6..812babf0fe 100644 --- a/doc/manual/efficiency.texinfo +++ b/doc/manual/efficiency.texinfo @@ -262,8 +262,8 @@ with versions cutting results to 32 bits, and because terminals As of SBCL 0.8.5 ``good'' functions are @code{+}, @code{-}; @code{logand}, @code{logior}, @code{logxor}, @code{lognot} and their combinations; and @code{ash} with the positive second -argument. ``Good'' widths are 32 on HPPA, MIPS, PPC, Sparc and x86 and -64 on Alpha. While it is possible to support smaller widths as well, +argument. ``Good'' widths are 32 on 32-bit CPUs and 64 on 64-bit CPUs. +While it is possible to support smaller widths as well, currently this is not implemented. @node Global and Always-Bound variables diff --git a/doc/manual/ffi.texinfo b/doc/manual/ffi.texinfo index 747ec6cbbb..089675b762 100644 --- a/doc/manual/ffi.texinfo +++ b/doc/manual/ffi.texinfo @@ -26,6 +26,7 @@ notably in the name of the @code{SB-ALIEN} package. * Foreign Data Structure Examples:: * Loading Shared Object Files:: * Foreign Function Calls:: +* Calling Lisp From C:: * Step-By-Step Example of the Foreign Function Interface:: @end menu @@ -718,7 +719,6 @@ the only documentation. Users of a Lisp built with the * The alien-funcall Primitive:: * The define-alien-routine Macro:: * define-alien-routine Example:: -* Calling Lisp From C:: @end menu @node The alien-funcall Primitive @@ -883,40 +883,6 @@ This can be described by the following call to The Lisp function @code{cfoo} will have two arguments (@var{str} and @var{a}) and two return values (@var{a} and @var{i}). -@node Calling Lisp From C -@comment node-name, next, previous, up -@subsection Calling Lisp From C - -Calling Lisp functions from C is sometimes possible, but is extremely -hackish and poorly supported as of SBCL 0.7.5. See @code{funcall0} -@dots{} @code{funcall3} in the runtime system. The arguments must be -valid SBCL object descriptors (so that e.g. fixnums must be -left-shifted by 2.) As of SBCL 0.7.5, the format of object descriptors -is documented only by the source code and, in parts, by the old CMUCL -@file{INTERNALS} documentation. - -Note that the garbage collector moves objects, and won't be -able to fix up any references in C variables. There are three -mechanisms for coping with this: - -@enumerate -@item -The @code{sb-ext:purify} moves all live Lisp -data into static or read-only areas such that it will never be moved -(or freed) again in the life of the Lisp session - -@item -@code{sb-sys:with-pinned-objects} is a macro which arranges for some -set of objects to be pinned in memory for the dynamic extent of its -body forms. On ports which use the generational garbage collector (most, -as of this writing) this affects exactly the specified objects. On -other ports it is implemented by turning off GC for the duration (so -could be said to have a whole-world granularity). - -@item -Disable GC, using the @code{without-gcing} macro. -@end enumerate - @c <!-- FIXME: This is a "changebar" section from the CMU CL manual. @c I (WHN 2002-07-14) am not very familiar with this content, so @c I'm not immediately prepared to try to update it for SBCL, and @@ -1058,6 +1024,68 @@ Disable GC, using the @code{without-gcing} macro. @c LaTeX @c --> +@node Calling Lisp From C +@comment node-name, next, previous, up +@section Calling Lisp From C + +SBCL supports the calling of Lisp functions using the C calling +convention. This is useful for both defining callbacks and for creating +an interface for calling into Lisp as a shared library directly from C. + +The @code{define-alien-callable} macro wraps Lisp code and creates a C +foreign function which can be called with the C calling convention. + +@include macro-sb-alien-define-alien-callable.texinfo + +The @code{alien-callable-function} function returns the foreign callable +value associated with any name defined by @code{define-alien-callable}, +so that we can, for example, pass the callable value to C as a callback. + +@include fun-sb-alien-alien-callable-function.texinfo + +Note that the garbage collector moves objects, and won't be able to fix +up any references in C variables. There are three mechanisms for coping +with this: + +@enumerate +@item +The @code{sb-ext:purify} moves all live Lisp data into static or +read-only areas such that it will never be moved (or freed) again in the +life of the Lisp session + +@item +@code{sb-sys:with-pinned-objects} is a macro which arranges for some set +of objects to be pinned in memory for the dynamic extent of its body +forms. On ports which use the generational garbage collector (most, as +of this writing) this affects exactly the specified objects. On other +ports it is implemented by turning off GC for the duration (so could be +said to have a whole-world granularity). + +@item +Disable GC, using the @code{without-gcing} macro. +@end enumerate + +@menu +* Lisp as a Shared Library:: +@end menu + +@node Lisp as a Shared Library +@comment node-name, next, previous, up +@subsection Lisp as a Shared Library +SBCL supports the use of Lisp as a shared library that can be used by C +programs using the @code{define-alien-callable} interface. See the +@code{:callable-exports} keyword to @code{save-lisp-and-die} for how to +save the Lisp image in a way that allows a C program to initialize the +Lisp runtime and the exported symbols. When SBCL is built as a library, +it exposes the symbol @code{initialize_lisp} which can be used in +conjunction with a core initializing global symbols to foreign callables +as function pointers and with object code allocating those symbols to +initialize the runtime properly. The arguments to @code{initialize_lisp} +are the same as the arguments to the main @code{sbcl} +program. + +Note: There is currently no way to run exit hooks or otherwise undo +Lisp initialization gracefully from C. @node Step-By-Step Example of the Foreign Function Interface @comment node-name, next, previous, up diff --git a/doc/manual/generate-texinfo.lisp b/doc/manual/generate-texinfo.lisp index 83451754d9..44e5edca80 100644 --- a/doc/manual/generate-texinfo.lisp +++ b/doc/manual/generate-texinfo.lisp @@ -32,8 +32,9 @@ finally (return result))) (defun generate-docstrings-texinfo (runtime - &key (docstring-directory "docstrings/")) - (let* ((contribs (sort (documented-contribs) #'string< :key #'car)) + &key (docstring-directory "docstrings/") + (blocklist '())) + (let* ((contribs (sort (documented-contribs :exclude (append '("asdf") blocklist)) #'string< :key #'car)) (packages (sort (append *documented-packages* (map 'list #'cdr contribs)) #'string<))) @@ -92,10 +93,10 @@ ;;;; Entry point -(destructuring-bind (program runtime docstring-directory) *posix-argv* +(destructuring-bind (program runtime docstring-directory blocklist) *posix-argv* (declare (ignore program)) (generate-docstrings-texinfo - runtime :docstring-directory docstring-directory) + runtime :docstring-directory docstring-directory :blocklist (uiop:split-string blocklist)) (expand-variables) (generate-external-format-texinfo)) diff --git a/doc/manual/intro.texinfo b/doc/manual/intro.texinfo index 6274c296bd..9003dede67 100644 --- a/doc/manual/intro.texinfo +++ b/doc/manual/intro.texinfo @@ -27,6 +27,29 @@ Essentially every type of non-conformance is considered a bug. (The exceptions involve internal inconsistencies in the standard.) @xref{Reporting Bugs}. +@node Exceptions to ANSI Conformance +@comment node-name, next, previous, up +@subsection Exceptions + +@itemize + +@item +@findex @cl{prog2} +@code{prog2} returns the primary value of its second form, as +specified in the @strong{Arguments and Values} section of the +specification for that operator, not that of its first form, as +specified in the @strong{Description}. + +@item +@tindex @cl{string} +@tindex @cl{character} +@tindex @cl{nil} +The @code{string} type is considered to be the union of all types +@code{(array @emph{c} (@emph{size}))} for all non-@code{nil} subtypes @code{@emph{c}} of +@code{character}, excluding arrays specialized to the empty type. + +@end itemize + @node Extensions @comment node-name, next, previous, up @section Extensions diff --git a/doc/manual/make-tempfiles.sh b/doc/manual/make-tempfiles.sh index 73944784a0..faf1bbbf99 100644 --- a/doc/manual/make-tempfiles.sh +++ b/doc/manual/make-tempfiles.sh @@ -15,31 +15,31 @@ # else an installed sbcl is used. if [ -z "$1" ] ; then - . ../../sbcl-pwd.sh - sbcl_pwd - - sbclsystem=$SBCL_PWD/../../src/runtime/sbcl - sbclcore=$SBCL_PWD/../../output/sbcl.core + SBCL_TOP=../.. + sbclsystem=$SBCL_TOP/src/runtime/sbcl + sbclcore=$SBCL_TOP/output/sbcl.core if [ -f $sbclsystem ] && [ -f $sbclcore ] then SBCLRUNTIME="$sbclsystem --core $sbclcore" - SBCL_HOME=$SBCL_PWD/../../obj/sbcl-home/; export SBCL_HOME + SBCL_HOME=$SBCL_TOP/obj/sbcl-home/; export SBCL_HOME SBCL_BUILDING_CONTRIB="please asdf install your hook"; export SBCL_BUILDING_CONTRIB else SBCLRUNTIME="`command -v sbcl`" fi + . $SBCL_TOP/output/build-config else SBCLRUNTIME="$1" - shift + SBCL_CONTRIB_BLOCKLIST= fi +shift if [ -z "$1" ] ; then DOCSTRINGDIR="${DOCSTRINGDIR:-docstrings/}" else DOCSTRINGDIR="$1" - shift fi +shift ${SBCLRUNTIME} \ --noinform --no-sysinit --no-userinit --noprint --disable-debugger \ - --script generate-texinfo.lisp "${SBCLRUNTIME}" "${DOCSTRINGDIR}" + --script generate-texinfo.lisp "${SBCLRUNTIME}" "${DOCSTRINGDIR}" "${SBCL_CONTRIB_BLOCKLIST}" diff --git a/doc/manual/support-and-bugs.texinfo b/doc/manual/support-and-bugs.texinfo index b8d695b658..627871ceb7 100644 --- a/doc/manual/support-and-bugs.texinfo +++ b/doc/manual/support-and-bugs.texinfo @@ -115,9 +115,7 @@ send a useful bug report then: @item @cindex ldb Compile SBCL with ldb enabled (feature @code{:sb-ldb}, see -@file{base-target-features.lisp-expr}) and change @code{#define -QSHOW_SIGNAL 0} to @code{#define QSHOW_SIGNAL 1} in -@file{src/runtime/runtime.h}. +@file{base-target-features.lisp-expr}). @item Isolate a smallish test case, run it. diff --git a/doc/manual/threading.texinfo b/doc/manual/threading.texinfo index fc5da5871a..eef26297d7 100644 --- a/doc/manual/threading.texinfo +++ b/doc/manual/threading.texinfo @@ -116,19 +116,11 @@ lockless algorithms. @unnumberedsubsec CAS Protocol -Our @code{compare-and-swap} is user-extensible using a protocol -similar to @code{setf}, allowing users to add CAS support to new -places via e.g. @code{defcas}. - -At the same time, new atomic operations can be built on top of CAS -using @code{get-cas-expansion}. See @code{atomic-update}, -@code{atomic-push}, and @code{atomic-pop} for examples of how to do -this. +Our @code{compare-and-swap} is user-extensible by defining functions +named (CAS place), allowing users to add CAS support to new +places. @include macro-sb-ext-cas.texinfo -@include macro-sb-ext-define-cas-expander.texinfo -@include macro-sb-ext-defcas.texinfo -@include fun-sb-ext-get-cas-expansion.texinfo @node Mutex Support @comment node-name, next, previous, up diff --git a/doc/sbcl.1 b/doc/sbcl.1 index b1f9982cf3..0a79d70289 100644 --- a/doc/sbcl.1 +++ b/doc/sbcl.1 @@ -298,7 +298,7 @@ For more information about the compiler, see the user manual. .SH SYSTEM REQUIREMENTS SBCL currently runs on X86 (Linux, FreeBSD, OpenBSD, and NetBSD), -X86-64 (Linux), Alpha (Linux, Tru64), PPC (Linux, Darwin/MacOS X), +X86-64 (Linux), PPC (Linux), SPARC (Linux and Solaris 2.x), and MIPS (Linux). For information on other ongoing and possible ports, see the sbcl\-devel mailing list, and/or the web site. diff --git a/float-math.lisp-expr b/float-math.lisp-expr index a1758483ee..a6c02aa723 100644 --- a/float-math.lisp-expr +++ b/float-math.lisp-expr @@ -4,8 +4,10 @@ ( (* (#x0 #.(MAKE-SINGLE-FLOAT #x-80000000)) #.(MAKE-SINGLE-FLOAT #x-80000000)) (* (#x0 #.(MAKE-SINGLE-FLOAT #x0)) #.(MAKE-SINGLE-FLOAT #x0)) +(* (#x0 #.(MAKE-SINGLE-FLOAT #x358637BD)) #.(MAKE-SINGLE-FLOAT #x0)) (* (#x0 #.(MAKE-SINGLE-FLOAT #x3A83126F)) #.(MAKE-SINGLE-FLOAT #x0)) (* (#x0 #.(MAKE-SINGLE-FLOAT #x3F800000)) #.(MAKE-SINGLE-FLOAT #x0)) +(* (#x0 #.(MAKE-SINGLE-FLOAT #x40000000)) #.(MAKE-SINGLE-FLOAT #x0)) (* (#x0 #.(MAKE-SINGLE-FLOAT #x4E000000)) #.(MAKE-SINGLE-FLOAT #x0)) (* (#x0 #.(MAKE-SINGLE-FLOAT #x4E6E6B28)) #.(MAKE-SINGLE-FLOAT #x0)) (* (#x0 #.(MAKE-SINGLE-FLOAT #x5D800000)) #.(MAKE-SINGLE-FLOAT #x0)) @@ -18,6 +20,7 @@ (* (#x0 #.(MAKE-DOUBLE-FLOAT #x3FE62E42 #xFEFA39EF)) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) (* (#x0 #.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0)) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) (* (#x0 #.(MAKE-DOUBLE-FLOAT #x3FFB504F #x333F9DE6)) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) +(* (#x0 #.(MAKE-DOUBLE-FLOAT #x40000000 #x0)) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) (* (#x0 #.(MAKE-DOUBLE-FLOAT #x400921FB #x54442D18)) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) (* (#x0 #.(MAKE-DOUBLE-FLOAT #x40100000 #x0)) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) (* (#x0 #.(MAKE-DOUBLE-FLOAT #x40240000 #x0)) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) @@ -62,6 +65,7 @@ (* (#.(MAKE-SINGLE-FLOAT #x3F800000) #x1) #.(MAKE-SINGLE-FLOAT #x3F800000)) (* (#.(MAKE-SINGLE-FLOAT #x3F800000) #.(MAKE-SINGLE-FLOAT #x-80000000)) #.(MAKE-SINGLE-FLOAT #x-80000000)) (* (#.(MAKE-SINGLE-FLOAT #x3F800000) #.(MAKE-SINGLE-FLOAT #x0)) #.(MAKE-SINGLE-FLOAT #x0)) +(* (#.(MAKE-SINGLE-FLOAT #x3F800000) #.(MAKE-SINGLE-FLOAT #x358637BD)) #.(MAKE-SINGLE-FLOAT #x358637BD)) (* (#.(MAKE-SINGLE-FLOAT #x3F800000) #.(MAKE-SINGLE-FLOAT #x3A83126F)) #.(MAKE-SINGLE-FLOAT #x3A83126F)) (* (#.(MAKE-SINGLE-FLOAT #x3F800000) #.(MAKE-SINGLE-FLOAT #x3F800000)) #.(MAKE-SINGLE-FLOAT #x3F800000)) (* (#.(MAKE-SINGLE-FLOAT #x3F800000) #.(MAKE-DOUBLE-FLOAT #x-80000000 #x0)) #.(MAKE-DOUBLE-FLOAT #x-80000000 #x0)) @@ -70,6 +74,8 @@ (* (#.(MAKE-SINGLE-FLOAT #x4E000000) #x0) #.(MAKE-SINGLE-FLOAT #x0)) (* (#.(MAKE-SINGLE-FLOAT #x4E000000) #.(MAKE-SINGLE-FLOAT #x40490FDB)) #.(MAKE-SINGLE-FLOAT #x4EC90FDB)) (* (#.(MAKE-SINGLE-FLOAT #x4E000000) #.(MAKE-SINGLE-FLOAT #x4E6E6B28)) #.(MAKE-SINGLE-FLOAT #x5CEE6B28)) +(* (#.(MAKE-SINGLE-FLOAT #x538637BD) #xF4240) #.(MAKE-SINGLE-FLOAT #x5D800000)) +(* (#.(MAKE-SINGLE-FLOAT #x538637BD) #.(MAKE-SINGLE-FLOAT #x49742400)) #.(MAKE-SINGLE-FLOAT #x5D800000)) (* (#.(MAKE-SINGLE-FLOAT #x5883126F) #x3E8) #.(MAKE-SINGLE-FLOAT #x5D800000)) (* (#.(MAKE-SINGLE-FLOAT #x5883126F) #.(MAKE-SINGLE-FLOAT #x447A0000)) #.(MAKE-SINGLE-FLOAT #x5D800000)) (* (#.(MAKE-SINGLE-FLOAT #x5D800000) #x0) #.(MAKE-SINGLE-FLOAT #x0)) @@ -116,6 +122,7 @@ (* (#.(MAKE-DOUBLE-FLOAT #x41C00000 #x0) #x0) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) (* (#.(MAKE-DOUBLE-FLOAT #x41C00000 #x0) #.(MAKE-DOUBLE-FLOAT #x400921FB #x54442D18)) #.(MAKE-DOUBLE-FLOAT #x41D921FB #x54442D18)) (* (#.(MAKE-DOUBLE-FLOAT #x41C00000 #x800000) #x0) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) +(* (#.(MAKE-DOUBLE-FLOAT #x4270C6F7 #xA0B5E000) #xF4240) #.(MAKE-DOUBLE-FLOAT #x43AFFFFF #xFFFFE627)) (* (#.(MAKE-DOUBLE-FLOAT #x4310624D #xD2F1A9F8) #x3E8) #.(MAKE-DOUBLE-FLOAT #x43AFFFFF #xFFFFFFF8)) (* (#.(MAKE-DOUBLE-FLOAT #x43B00000 #x0) #x0) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) (* (#.(MAKE-DOUBLE-FLOAT #x43B00000 #x0) #.(MAKE-SINGLE-FLOAT #x4E6E6B28)) #.(MAKE-DOUBLE-FLOAT #x458DCD65 #x0)) @@ -127,13 +134,12 @@ (* (#.(MAKE-DOUBLE-FLOAT #x43D00000 #x0) #.(MAKE-DOUBLE-FLOAT #x41CDCD65 #x0)) #.(MAKE-DOUBLE-FLOAT #x45ADCD65 #x0)) (* (#.(MAKE-DOUBLE-FLOAT #x5FCFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x40100000 #x0)) #.(MAKE-DOUBLE-FLOAT #x5FEFFFFF #xFFFFFFFF)) (* (#.(MAKE-DOUBLE-FLOAT #x5FCFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x5FCFFFFF #xFFFFFFFF)) #.(MAKE-DOUBLE-FLOAT #x7FAFFFFF #xFFFFFFFE)) -(+ (#x0 #.(MAKE-SINGLE-FLOAT #x-40804189)) #.(MAKE-SINGLE-FLOAT #x-40804189)) (+ (#x0 #.(MAKE-SINGLE-FLOAT #x0)) #.(MAKE-SINGLE-FLOAT #x0)) (+ (#x0 #.(MAKE-DOUBLE-FLOAT #x0 #x0)) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) (+ (#x1 #.(MAKE-SINGLE-FLOAT #x0)) #.(MAKE-SINGLE-FLOAT #x3F800000)) (+ (#x1 #.(MAKE-DOUBLE-FLOAT #x0 #x0)) #.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0)) +(+ (#x218DEF416BD #.(MAKE-SINGLE-FLOAT #x3F7FFFEF)) #.(MAKE-SINGLE-FLOAT #x540637BD)) (+ (#x83126E978D4FD #.(MAKE-SINGLE-FLOAT #x3F7FFFEF)) #.(MAKE-SINGLE-FLOAT #x5903126F)) -(+ (#.(MAKE-SINGLE-FLOAT #x-32000000) #.(MAKE-SINGLE-FLOAT #x-31800000)) #.(MAKE-SINGLE-FLOAT #x-31400000)) (+ (#.(MAKE-SINGLE-FLOAT #x-31800000) #x1) #.(MAKE-SINGLE-FLOAT #x-31800000)) (+ (#.(MAKE-SINGLE-FLOAT #x-31800000) #.(MAKE-SINGLE-FLOAT #x3F800000)) #.(MAKE-SINGLE-FLOAT #x-31800000)) (+ (#.(MAKE-SINGLE-FLOAT #x-22000000) #x1) #.(MAKE-SINGLE-FLOAT #x-22000000)) @@ -142,24 +148,19 @@ (+ (#.(MAKE-SINGLE-FLOAT #x-21000000) #.(MAKE-SINGLE-FLOAT #x3F800000)) #.(MAKE-SINGLE-FLOAT #x-21000000)) (+ (#.(MAKE-SINGLE-FLOAT #x0) #x0) #.(MAKE-SINGLE-FLOAT #x0)) (+ (#.(MAKE-SINGLE-FLOAT #x0) #x1) #.(MAKE-SINGLE-FLOAT #x3F800000)) -(+ (#.(MAKE-SINGLE-FLOAT #x0) #x3) #.(MAKE-SINGLE-FLOAT #x40400000)) -(+ (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x-40804189)) #.(MAKE-SINGLE-FLOAT #x-40804189)) (+ (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x0)) #.(MAKE-SINGLE-FLOAT #x0)) (+ (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) (+ (#.(MAKE-SINGLE-FLOAT #x3F800000) #x-1) #.(MAKE-SINGLE-FLOAT #x0)) -(+ (#.(MAKE-SINGLE-FLOAT #x4E000000) #.(MAKE-SINGLE-FLOAT #x4E800000)) #.(MAKE-SINGLE-FLOAT #x4EC00000)) (+ (#.(MAKE-SINGLE-FLOAT #x4E800000) #x1) #.(MAKE-SINGLE-FLOAT #x4E800000)) (+ (#.(MAKE-SINGLE-FLOAT #x4E800000) #.(MAKE-SINGLE-FLOAT #x3F800000)) #.(MAKE-SINGLE-FLOAT #x4E800000)) -(+ (#.(MAKE-SINGLE-FLOAT #x5903126F) #.(MAKE-SINGLE-FLOAT #x3F7FFFEF)) #.(MAKE-SINGLE-FLOAT #x5903126F)) +(+ (#.(MAKE-SINGLE-FLOAT #x540637BD) #.(MAKE-SINGLE-FLOAT #x3F7FFFEF)) #.(MAKE-SINGLE-FLOAT #x540637BD)) (+ (#.(MAKE-SINGLE-FLOAT #x5E000000) #x1) #.(MAKE-SINGLE-FLOAT #x5E000000)) (+ (#.(MAKE-SINGLE-FLOAT #x5E000000) #.(MAKE-SINGLE-FLOAT #x3F800000)) #.(MAKE-SINGLE-FLOAT #x5E000000)) (+ (#.(MAKE-SINGLE-FLOAT #x5F000000) #x1) #.(MAKE-SINGLE-FLOAT #x5F000000)) (+ (#.(MAKE-SINGLE-FLOAT #x5F000000) #.(MAKE-SINGLE-FLOAT #x3F800000)) #.(MAKE-SINGLE-FLOAT #x5F000000)) (+ (#.(MAKE-DOUBLE-FLOAT #x-4006DE05 #x54442D18) #.(MAKE-DOUBLE-FLOAT #x3FF921FB #x54442D18)) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) -(+ (#.(MAKE-DOUBLE-FLOAT #x-3F8BCB1A #x420F4374) #.(MAKE-DOUBLE-FLOAT #x-3F7C3D8D #x2107A1BA)) #.(MAKE-DOUBLE-FLOAT #x-3F72231A #x420F4374)) -(+ (#.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0) #.(MAKE-DOUBLE-FLOAT #x-3E300001 #xFF800000)) #.(MAKE-DOUBLE-FLOAT #x-3E280001 #xFFC00000)) -(+ (#.(MAKE-DOUBLE-FLOAT #x-3E300000 #x0) #x1) #.(MAKE-DOUBLE-FLOAT #x-3E300001 #xFF800000)) -(+ (#.(MAKE-DOUBLE-FLOAT #x-3E300000 #x0) #.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0)) #.(MAKE-DOUBLE-FLOAT #x-3E300001 #xFF800000)) +(+ (#.(MAKE-DOUBLE-FLOAT #x-3F8BCB1A #x420F4374) #.(MAKE-DOUBLE-FLOAT #x-3F7C458D #x2107A1BA)) #.(MAKE-DOUBLE-FLOAT #x-3F722B1A #x420F4374)) +(+ (#.(MAKE-DOUBLE-FLOAT #x-3E300001 #xFF800000) #.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0)) #.(MAKE-DOUBLE-FLOAT #x-3E300001 #xFF000000)) (+ (#.(MAKE-DOUBLE-FLOAT #x-3C400000 #x0) #x1) #.(MAKE-DOUBLE-FLOAT #x-3C400000 #x0)) (+ (#.(MAKE-DOUBLE-FLOAT #x-3C400000 #x0) #.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0)) #.(MAKE-DOUBLE-FLOAT #x-3C400000 #x0)) (+ (#.(MAKE-DOUBLE-FLOAT #x-3C200000 #x0) #x1) #.(MAKE-DOUBLE-FLOAT #x-3C200000 #x0)) @@ -176,9 +177,7 @@ (+ (#.(MAKE-DOUBLE-FLOAT #x3FF921FB #x54442D18) #.(MAKE-DOUBLE-FLOAT #x-4006DE05 #x54442D18)) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) (+ (#.(MAKE-DOUBLE-FLOAT #x3FF921FB #x54442D18) #.(MAKE-DOUBLE-FLOAT #x3FF921FB #x54442D18)) #.(MAKE-DOUBLE-FLOAT #x400921FB #x54442D18)) (+ (#.(MAKE-DOUBLE-FLOAT #x40100000 #x0) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) #.(MAKE-DOUBLE-FLOAT #x40100000 #x0)) -(+ (#.(MAKE-DOUBLE-FLOAT #x40734413 #x509F79FF) #.(MAKE-DOUBLE-FLOAT #x4083C209 #xA84FBD00)) #.(MAKE-DOUBLE-FLOAT #x408D6413 #x509F7A00)) -(+ (#.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFF000000) #.(MAKE-DOUBLE-FLOAT #x41CFFFFF #xFF800000)) #.(MAKE-DOUBLE-FLOAT #x41D7FFFF #xFF800000)) -(+ (#.(MAKE-DOUBLE-FLOAT #x41D00000 #x0) #x1) #.(MAKE-DOUBLE-FLOAT #x41D00000 #x400000)) +(+ (#.(MAKE-DOUBLE-FLOAT #x40734413 #x509F79FF) #.(MAKE-DOUBLE-FLOAT #x4083BA09 #xA84FBD00)) #.(MAKE-DOUBLE-FLOAT #x408D5C13 #x509F7A00)) (+ (#.(MAKE-DOUBLE-FLOAT #x41D00000 #x0) #.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0)) #.(MAKE-DOUBLE-FLOAT #x41D00000 #x400000)) (+ (#.(MAKE-DOUBLE-FLOAT #x43C00000 #x0) #x1) #.(MAKE-DOUBLE-FLOAT #x43C00000 #x0)) (+ (#.(MAKE-DOUBLE-FLOAT #x43C00000 #x0) #.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0)) #.(MAKE-DOUBLE-FLOAT #x43C00000 #x0)) @@ -188,26 +187,17 @@ (- (#.(MAKE-SINGLE-FLOAT #x-80000000)) #.(MAKE-SINGLE-FLOAT #x0)) (- (#.(MAKE-SINGLE-FLOAT #x-40800000)) #.(MAKE-SINGLE-FLOAT #x3F800000)) (- (#.(MAKE-SINGLE-FLOAT #x-3FB6F025)) #.(MAKE-SINGLE-FLOAT #x40490FDB)) -(- (#.(MAKE-SINGLE-FLOAT #x-368C1A80)) #.(MAKE-SINGLE-FLOAT #x4973E580)) (- (#.(MAKE-SINGLE-FLOAT #x-32000000)) #.(MAKE-SINGLE-FLOAT #x4E000000)) -(- (#.(MAKE-SINGLE-FLOAT #x-31800000)) #.(MAKE-SINGLE-FLOAT #x4E800000)) -(- (#.(MAKE-SINGLE-FLOAT #x-31400000)) #.(MAKE-SINGLE-FLOAT #x4EC00000)) (- (#.(MAKE-SINGLE-FLOAT #x-3136F025)) #.(MAKE-SINGLE-FLOAT #x4EC90FDB)) -(- (#.(MAKE-SINGLE-FLOAT #x-231194D8)) #.(MAKE-SINGLE-FLOAT #x5CEE6B28)) (- (#.(MAKE-SINGLE-FLOAT #x-22800000)) #.(MAKE-SINGLE-FLOAT #x5D800000)) (- (#.(MAKE-SINGLE-FLOAT #x-21B6F025)) #.(MAKE-SINGLE-FLOAT #x5E490FDB)) (- (#.(MAKE-SINGLE-FLOAT #x-21800000)) #.(MAKE-SINGLE-FLOAT #x5E800000)) (- (#.(MAKE-SINGLE-FLOAT #x-20B6F025)) #.(MAKE-SINGLE-FLOAT #x5F490FDB)) -(- (#.(MAKE-SINGLE-FLOAT #x-139194D8)) #.(MAKE-SINGLE-FLOAT #x6C6E6B28)) -(- (#.(MAKE-SINGLE-FLOAT #x-129194D8)) #.(MAKE-SINGLE-FLOAT #x6D6E6B28)) -(- (#.(MAKE-SINGLE-FLOAT #x-800001)) #.(MAKE-SINGLE-FLOAT #x7F7FFFFF)) (- (#.(MAKE-SINGLE-FLOAT #x-800000)) #.(MAKE-SINGLE-FLOAT #x7F800000)) (- (#.(MAKE-SINGLE-FLOAT #x0)) #.(MAKE-SINGLE-FLOAT #x-80000000)) -(- (#.(MAKE-SINGLE-FLOAT #x3F7FBE77)) #.(MAKE-SINGLE-FLOAT #x-40804189)) (- (#.(MAKE-SINGLE-FLOAT #x3F800000)) #.(MAKE-SINGLE-FLOAT #x-40800000)) (- (#.(MAKE-SINGLE-FLOAT #x4E000000)) #.(MAKE-SINGLE-FLOAT #x-32000000)) (- (#.(MAKE-SINGLE-FLOAT #x4E6E6B28)) #.(MAKE-SINGLE-FLOAT #x-319194D8)) -(- (#.(MAKE-SINGLE-FLOAT #x4EC00000)) #.(MAKE-SINGLE-FLOAT #x-31400000)) (- (#.(MAKE-SINGLE-FLOAT #x4EC90FDB)) #.(MAKE-SINGLE-FLOAT #x-3136F025)) (- (#.(MAKE-SINGLE-FLOAT #x5CEE6B28)) #.(MAKE-SINGLE-FLOAT #x-231194D8)) (- (#.(MAKE-SINGLE-FLOAT #x5D800000)) #.(MAKE-SINGLE-FLOAT #x-22800000)) @@ -223,26 +213,18 @@ (- (#.(MAKE-DOUBLE-FLOAT #x-40100000 #x0)) #.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0)) (- (#.(MAKE-DOUBLE-FLOAT #x-4006DE05 #x54442D18)) #.(MAKE-DOUBLE-FLOAT #x3FF921FB #x54442D18)) (- (#.(MAKE-DOUBLE-FLOAT #x-3FF6DE05 #x54442D18)) #.(MAKE-DOUBLE-FLOAT #x400921FB #x54442D18)) -(- (#.(MAKE-DOUBLE-FLOAT #x-3F8BCB1A #x420F4374)) #.(MAKE-DOUBLE-FLOAT #x407434E6 #x420F4374)) -(- (#.(MAKE-DOUBLE-FLOAT #x-3F7C3D8D #x2107A1BA)) #.(MAKE-DOUBLE-FLOAT #x4083C273 #x2107A1BA)) -(- (#.(MAKE-DOUBLE-FLOAT #x-3F72231A #x420F4374)) #.(MAKE-DOUBLE-FLOAT #x408DDCE6 #x420F4374)) +(- (#.(MAKE-DOUBLE-FLOAT #x-3F7C458D #x2107A1BA)) #.(MAKE-DOUBLE-FLOAT #x4083BA73 #x2107A1BA)) (- (#.(MAKE-DOUBLE-FLOAT #x-3F6F3800 #x0)) #.(MAKE-DOUBLE-FLOAT #x4090C800 #x0)) (- (#.(MAKE-DOUBLE-FLOAT #x-3F6F3400 #x0)) #.(MAKE-DOUBLE-FLOAT #x4090CC00 #x0)) (- (#.(MAKE-DOUBLE-FLOAT #x-3E400001 #xFF000000)) #.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFF000000)) (- (#.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0)) #.(MAKE-DOUBLE-FLOAT #x41C00000 #x0)) (- (#.(MAKE-DOUBLE-FLOAT #x-3E400000 #x800000)) #.(MAKE-DOUBLE-FLOAT #x41C00000 #x800000)) -(- (#.(MAKE-DOUBLE-FLOAT #x-3E300001 #xFF800000)) #.(MAKE-DOUBLE-FLOAT #x41CFFFFF #xFF800000)) -(- (#.(MAKE-DOUBLE-FLOAT #x-3E280001 #xFFC00000)) #.(MAKE-DOUBLE-FLOAT #x41D7FFFF #xFFC00000)) (- (#.(MAKE-DOUBLE-FLOAT #x-3E26DE05 #x54442D18)) #.(MAKE-DOUBLE-FLOAT #x41D921FB #x54442D18)) -(- (#.(MAKE-DOUBLE-FLOAT #x-3C62329C #xFF1194D8)) #.(MAKE-DOUBLE-FLOAT #x439DCD64 #xFF1194D8)) (- (#.(MAKE-DOUBLE-FLOAT #x-3C500000 #x0)) #.(MAKE-DOUBLE-FLOAT #x43B00000 #x0)) (- (#.(MAKE-DOUBLE-FLOAT #x-3C36DE05 #x54442D18)) #.(MAKE-DOUBLE-FLOAT #x43C921FB #x54442D18)) (- (#.(MAKE-DOUBLE-FLOAT #x-3C300000 #x0)) #.(MAKE-DOUBLE-FLOAT #x43D00000 #x0)) (- (#.(MAKE-DOUBLE-FLOAT #x-3C16DE05 #x54442D18)) #.(MAKE-DOUBLE-FLOAT #x43E921FB #x54442D18)) -(- (#.(MAKE-DOUBLE-FLOAT #x-3A72329B #x0)) #.(MAKE-DOUBLE-FLOAT #x458DCD65 #x0)) -(- (#.(MAKE-DOUBLE-FLOAT #x-3A52329B #x0)) #.(MAKE-DOUBLE-FLOAT #x45ADCD65 #x0)) (- (#.(MAKE-DOUBLE-FLOAT #x-20300001 #xFFFFFFFF)) #.(MAKE-DOUBLE-FLOAT #x5FCFFFFF #xFFFFFFFF)) -(- (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF)) #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) (- (#.(MAKE-DOUBLE-FLOAT #x-100000 #x0)) #.(MAKE-DOUBLE-FLOAT #x7FF00000 #x0)) (- (#.(MAKE-DOUBLE-FLOAT #x0 #x0)) #.(MAKE-DOUBLE-FLOAT #x-80000000 #x0)) (- (#.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0)) #.(MAKE-DOUBLE-FLOAT #x-40100000 #x0)) @@ -250,9 +232,7 @@ (- (#.(MAKE-DOUBLE-FLOAT #x400921FB #x54442D18)) #.(MAKE-DOUBLE-FLOAT #x-3FF6DE05 #x54442D18)) (- (#.(MAKE-DOUBLE-FLOAT #x407434E6 #x420F4374)) #.(MAKE-DOUBLE-FLOAT #x-3F8BCB1A #x420F4374)) (- (#.(MAKE-DOUBLE-FLOAT #x40874910 #xD52D3052)) #.(MAKE-DOUBLE-FLOAT #x-3F78B6F0 #xD52D3052)) -(- (#.(MAKE-DOUBLE-FLOAT #x408DDCE6 #x420F4374)) #.(MAKE-DOUBLE-FLOAT #x-3F72231A #x420F4374)) (- (#.(MAKE-DOUBLE-FLOAT #x41C00000 #x0)) #.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0)) -(- (#.(MAKE-DOUBLE-FLOAT #x41D7FFFF #xFFC00000)) #.(MAKE-DOUBLE-FLOAT #x-3E280001 #xFFC00000)) (- (#.(MAKE-DOUBLE-FLOAT #x41D921FB #x537B1D3D)) #.(MAKE-DOUBLE-FLOAT #x-3E26DE05 #x537B1D3D)) (- (#.(MAKE-DOUBLE-FLOAT #x41D921FB #x54442D18)) #.(MAKE-DOUBLE-FLOAT #x-3E26DE05 #x54442D18)) (- (#.(MAKE-DOUBLE-FLOAT #x439DCD64 #xFF1194D8)) #.(MAKE-DOUBLE-FLOAT #x-3C62329C #xFF1194D8)) @@ -265,31 +245,24 @@ (- (#.(MAKE-DOUBLE-FLOAT #x45ADCD65 #x0)) #.(MAKE-DOUBLE-FLOAT #x-3A52329B #x0)) (- (#.(MAKE-DOUBLE-FLOAT #x7FAFFFFF #xFFFFFFFE)) #.(MAKE-DOUBLE-FLOAT #x-500001 #xFFFFFFFE)) (- (#.(MAKE-DOUBLE-FLOAT #x7FF00000 #x0)) #.(MAKE-DOUBLE-FLOAT #x-100000 #x0)) -(- (#.(MAKE-SINGLE-FLOAT #x-32000000) #x20000000) #.(MAKE-SINGLE-FLOAT #x-31800000)) -(- (#.(MAKE-SINGLE-FLOAT #x-32000000) #.(MAKE-SINGLE-FLOAT #x4E000000)) #.(MAKE-SINGLE-FLOAT #x-31800000)) -(- (#.(MAKE-SINGLE-FLOAT #x-22800000) #.(MAKE-SINGLE-FLOAT #x5D800000)) #.(MAKE-SINGLE-FLOAT #x-22000000)) -(- (#.(MAKE-SINGLE-FLOAT #x-21800000) #.(MAKE-SINGLE-FLOAT #x5E800000)) #.(MAKE-SINGLE-FLOAT #x-21000000)) +(- (#.(MAKE-SINGLE-FLOAT #x-32000000) #.(MAKE-SINGLE-FLOAT #x4DFFFFFF)) #.(MAKE-SINGLE-FLOAT #x-31800000)) +(- (#.(MAKE-SINGLE-FLOAT #x-22800000) #.(MAKE-SINGLE-FLOAT #x5D7FFFFF)) #.(MAKE-SINGLE-FLOAT #x-22000000)) +(- (#.(MAKE-SINGLE-FLOAT #x-21800000) #.(MAKE-SINGLE-FLOAT #x5E7FFFFF)) #.(MAKE-SINGLE-FLOAT #x-21000000)) (- (#.(MAKE-SINGLE-FLOAT #x0) #x64) #.(MAKE-SINGLE-FLOAT #x-3D380000)) (- (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x4E000000)) #.(MAKE-SINGLE-FLOAT #x-32000000)) (- (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x5D800000)) #.(MAKE-SINGLE-FLOAT #x-22800000)) (- (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x5E800000)) #.(MAKE-SINGLE-FLOAT #x-21800000)) -(- (#.(MAKE-SINGLE-FLOAT #x4E000000) #x-20000000) #.(MAKE-SINGLE-FLOAT #x4E800000)) -(- (#.(MAKE-SINGLE-FLOAT #x4E000000) #.(MAKE-SINGLE-FLOAT #x-32000000)) #.(MAKE-SINGLE-FLOAT #x4E800000)) +(- (#.(MAKE-SINGLE-FLOAT #x4DFFFFFF) #.(MAKE-SINGLE-FLOAT #x-32000000)) #.(MAKE-SINGLE-FLOAT #x4E800000)) (- (#.(MAKE-SINGLE-FLOAT #x4E000000) #.(MAKE-SINGLE-FLOAT #x0)) #.(MAKE-SINGLE-FLOAT #x4E000000)) -(- (#.(MAKE-SINGLE-FLOAT #x5D800000) #.(MAKE-SINGLE-FLOAT #x-22800000)) #.(MAKE-SINGLE-FLOAT #x5E000000)) +(- (#.(MAKE-SINGLE-FLOAT #x5D7FFFFF) #.(MAKE-SINGLE-FLOAT #x-22800000)) #.(MAKE-SINGLE-FLOAT #x5E000000)) (- (#.(MAKE-SINGLE-FLOAT #x5D800000) #.(MAKE-SINGLE-FLOAT #x0)) #.(MAKE-SINGLE-FLOAT #x5D800000)) -(- (#.(MAKE-SINGLE-FLOAT #x5E800000) #.(MAKE-SINGLE-FLOAT #x-21800000)) #.(MAKE-SINGLE-FLOAT #x5F000000)) +(- (#.(MAKE-SINGLE-FLOAT #x5E7FFFFF) #.(MAKE-SINGLE-FLOAT #x-21800000)) #.(MAKE-SINGLE-FLOAT #x5F000000)) (- (#.(MAKE-SINGLE-FLOAT #x5E800000) #.(MAKE-SINGLE-FLOAT #x0)) #.(MAKE-SINGLE-FLOAT #x5E800000)) (- (#.(MAKE-DOUBLE-FLOAT #x-3F8BCB1A #x420F4374) #x134) #.(MAKE-DOUBLE-FLOAT #x-3F7C458D #x2107A1BA)) -(- (#.(MAKE-DOUBLE-FLOAT #x-3F8BCB1A #x420F4374) #x135) #.(MAKE-DOUBLE-FLOAT #x-3F7C3D8D #x2107A1BA)) -(- (#.(MAKE-DOUBLE-FLOAT #x-3F8BCB1A #x420F4374) #x3AD) #.(MAKE-DOUBLE-FLOAT #x-3F6C3EC7 #x9083D0DD)) (- (#.(MAKE-DOUBLE-FLOAT #x-3F8BCB1A #x420F4374) #.(MAKE-DOUBLE-FLOAT #x40734000 #x0)) #.(MAKE-DOUBLE-FLOAT #x-3F7C458D #x2107A1BA)) -(- (#.(MAKE-DOUBLE-FLOAT #x-3F8BCB1A #x420F4374) #.(MAKE-DOUBLE-FLOAT #x40735000 #x0)) #.(MAKE-DOUBLE-FLOAT #x-3F7C3D8D #x2107A1BA)) -(- (#.(MAKE-DOUBLE-FLOAT #x-3F8BCB1A #x420F4374) #.(MAKE-DOUBLE-FLOAT #x408D6800 #x0)) #.(MAKE-DOUBLE-FLOAT #x-3F6C3EC7 #x9083D0DD)) (- (#.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0) #.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFF000000)) #.(MAKE-DOUBLE-FLOAT #x-3E300001 #xFF800000)) -(- (#.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0) #.(MAKE-DOUBLE-FLOAT #x41C00000 #x0)) #.(MAKE-DOUBLE-FLOAT #x-3E300000 #x0)) -(- (#.(MAKE-DOUBLE-FLOAT #x-3C500000 #x0) #.(MAKE-DOUBLE-FLOAT #x43B00000 #x0)) #.(MAKE-DOUBLE-FLOAT #x-3C400000 #x0)) -(- (#.(MAKE-DOUBLE-FLOAT #x-3C300000 #x0) #.(MAKE-DOUBLE-FLOAT #x43D00000 #x0)) #.(MAKE-DOUBLE-FLOAT #x-3C200000 #x0)) +(- (#.(MAKE-DOUBLE-FLOAT #x-3C500000 #x0) #.(MAKE-DOUBLE-FLOAT #x43AFFFFF #xFFFFFFFF)) #.(MAKE-DOUBLE-FLOAT #x-3C400000 #x0)) +(- (#.(MAKE-DOUBLE-FLOAT #x-3C300000 #x0) #.(MAKE-DOUBLE-FLOAT #x43CFFFFF #xFFFFFFFF)) #.(MAKE-DOUBLE-FLOAT #x-3C200000 #x0)) (- (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #x64) #.(MAKE-DOUBLE-FLOAT #x-3FA70000 #x0)) (- (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0)) #.(MAKE-DOUBLE-FLOAT #x-40100000 #x0)) (- (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFF000000)) #.(MAKE-DOUBLE-FLOAT #x-3E400001 #xFF000000)) @@ -297,18 +270,13 @@ (- (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x43D00000 #x0)) #.(MAKE-DOUBLE-FLOAT #x-3C300000 #x0)) (- (#.(MAKE-DOUBLE-FLOAT #x3FE6A09E #x667F3BCD) #.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0)) #.(MAKE-DOUBLE-FLOAT #x-402D413D #x33018866)) (- (#.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0) #.(MAKE-DOUBLE-FLOAT #x5FCFFFFF #xFFFFFFFF)) #.(MAKE-DOUBLE-FLOAT #x-20300001 #xFFFFFFFF)) -(- (#.(MAKE-DOUBLE-FLOAT #x40734413 #x509F79FF) #x-3BC) #.(MAKE-DOUBLE-FLOAT #x4093C104 #xD427DE80)) -(- (#.(MAKE-DOUBLE-FLOAT #x40734413 #x509F79FF) #x-144) #.(MAKE-DOUBLE-FLOAT #x4083C209 #xA84FBD00)) (- (#.(MAKE-DOUBLE-FLOAT #x40734413 #x509F79FF) #x-143) #.(MAKE-DOUBLE-FLOAT #x4083BA09 #xA84FBD00)) (- (#.(MAKE-DOUBLE-FLOAT #x40734413 #x509F79FF) #.(MAKE-DOUBLE-FLOAT #x-3F8BD000 #x0)) #.(MAKE-DOUBLE-FLOAT #x4083BA09 #xA84FBD00)) -(- (#.(MAKE-DOUBLE-FLOAT #x40734413 #x509F79FF) #.(MAKE-DOUBLE-FLOAT #x-3F8BC000 #x0)) #.(MAKE-DOUBLE-FLOAT #x4083C209 #xA84FBD00)) -(- (#.(MAKE-DOUBLE-FLOAT #x40734413 #x509F79FF) #.(MAKE-DOUBLE-FLOAT #x-3F722000 #x0)) #.(MAKE-DOUBLE-FLOAT #x4093C104 #xD427DE80)) -(- (#.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFF000000) #.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0)) #.(MAKE-DOUBLE-FLOAT #x41CFFFFF #xFF800000)) -(- (#.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFF000000) #.(MAKE-DOUBLE-FLOAT #x-3E400000 #x800000)) #.(MAKE-DOUBLE-FLOAT #x41D00000 #x0)) (- (#.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFF000000) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) #.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFF000000)) -(- (#.(MAKE-DOUBLE-FLOAT #x43B00000 #x0) #.(MAKE-DOUBLE-FLOAT #x-3C500000 #x0)) #.(MAKE-DOUBLE-FLOAT #x43C00000 #x0)) +(- (#.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0)) #.(MAKE-DOUBLE-FLOAT #x41D00000 #x0)) +(- (#.(MAKE-DOUBLE-FLOAT #x43AFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x-3C500000 #x0)) #.(MAKE-DOUBLE-FLOAT #x43C00000 #x0)) (- (#.(MAKE-DOUBLE-FLOAT #x43B00000 #x0) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) #.(MAKE-DOUBLE-FLOAT #x43B00000 #x0)) -(- (#.(MAKE-DOUBLE-FLOAT #x43D00000 #x0) #.(MAKE-DOUBLE-FLOAT #x-3C300000 #x0)) #.(MAKE-DOUBLE-FLOAT #x43E00000 #x0)) +(- (#.(MAKE-DOUBLE-FLOAT #x43CFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x-3C300000 #x0)) #.(MAKE-DOUBLE-FLOAT #x43E00000 #x0)) (- (#.(MAKE-DOUBLE-FLOAT #x43D00000 #x0) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) #.(MAKE-DOUBLE-FLOAT #x43D00000 #x0)) (/ (#x0 #.(MAKE-SINGLE-FLOAT #x3089705F)) #.(MAKE-SINGLE-FLOAT #x0)) (/ (#x0 #.(MAKE-SINGLE-FLOAT #x3F800000)) #.(MAKE-SINGLE-FLOAT #x0)) @@ -319,31 +287,20 @@ (/ (#x0 #.(MAKE-DOUBLE-FLOAT #x40000000 #x0)) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) (/ (#x0 #.(MAKE-DOUBLE-FLOAT #x40240000 #x0)) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) (/ (#x1 #.(MAKE-SINGLE-FLOAT #x3089705F)) #.(MAKE-SINGLE-FLOAT #x4E6E6B28)) -(/ (#xF3E58 #.(MAKE-SINGLE-FLOAT #x49742400)) #.(MAKE-SINGLE-FLOAT #x3F7FBE77)) (/ (#xF423F #.(MAKE-SINGLE-FLOAT #x49742400)) #.(MAKE-SINGLE-FLOAT #x3F7FFFEF)) (/ (#xFFFFFFFF #.(MAKE-SINGLE-FLOAT #x3F000000)) #.(MAKE-SINGLE-FLOAT #x50000000)) (/ (#xFFFFFFFFFFFFFFFF #.(MAKE-SINGLE-FLOAT #x3F000000)) #.(MAKE-SINGLE-FLOAT #x60000000)) -(/ (#.(MAKE-SINGLE-FLOAT #x-80000000) #x1) #.(MAKE-SINGLE-FLOAT #x-80000000)) (/ (#.(MAKE-SINGLE-FLOAT #x0) #x1) #.(MAKE-SINGLE-FLOAT #x0)) (/ (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x3F800000)) #.(MAKE-SINGLE-FLOAT #x0)) (/ (#.(MAKE-SINGLE-FLOAT #x3F800000) #x3E8) #.(MAKE-SINGLE-FLOAT #x3A83126F)) -(/ (#.(MAKE-SINGLE-FLOAT #x41600000) #x1) #.(MAKE-SINGLE-FLOAT #x41600000)) -(/ (#.(MAKE-SINGLE-FLOAT #x41600000) #.(MAKE-SINGLE-FLOAT #x3F800000)) #.(MAKE-SINGLE-FLOAT #x41600000)) -(/ (#.(MAKE-SINGLE-FLOAT #x4973E580) #.(MAKE-SINGLE-FLOAT #x49742400)) #.(MAKE-SINGLE-FLOAT #x3F7FBE77)) +(/ (#.(MAKE-SINGLE-FLOAT #x3F800000) #xF4240) #.(MAKE-SINGLE-FLOAT #x358637BD)) (/ (#.(MAKE-SINGLE-FLOAT #x497423F0) #.(MAKE-SINGLE-FLOAT #x49742400)) #.(MAKE-SINGLE-FLOAT #x3F7FFFEF)) -(/ (#.(MAKE-SINGLE-FLOAT #x4B800000) #.(MAKE-SINGLE-FLOAT #x3D800000)) #.(MAKE-SINGLE-FLOAT #x4D800000)) -(/ (#.(MAKE-SINGLE-FLOAT #x4D800000) #x1) #.(MAKE-SINGLE-FLOAT #x4D800000)) (/ (#.(MAKE-SINGLE-FLOAT #x4DFFFFFF) #x1) #.(MAKE-SINGLE-FLOAT #x4DFFFFFF)) (/ (#.(MAKE-SINGLE-FLOAT #x4E000000) #x1) #.(MAKE-SINGLE-FLOAT #x4E000000)) -(/ (#.(MAKE-SINGLE-FLOAT #x4EC00000) #x1) #.(MAKE-SINGLE-FLOAT #x4EC00000)) -(/ (#.(MAKE-SINGLE-FLOAT #x5CEE6B28) #x1) #.(MAKE-SINGLE-FLOAT #x5CEE6B28)) (/ (#.(MAKE-SINGLE-FLOAT #x5D7FFFFF) #x1) #.(MAKE-SINGLE-FLOAT #x5D7FFFFF)) (/ (#.(MAKE-SINGLE-FLOAT #x5D800000) #x1) #.(MAKE-SINGLE-FLOAT #x5D800000)) (/ (#.(MAKE-SINGLE-FLOAT #x5E7FFFFF) #x1) #.(MAKE-SINGLE-FLOAT #x5E7FFFFF)) (/ (#.(MAKE-SINGLE-FLOAT #x5E800000) #x1) #.(MAKE-SINGLE-FLOAT #x5E800000)) -(/ (#.(MAKE-SINGLE-FLOAT #x6C6E6B28) #x1) #.(MAKE-SINGLE-FLOAT #x6C6E6B28)) -(/ (#.(MAKE-SINGLE-FLOAT #x6D6E6B28) #x1) #.(MAKE-SINGLE-FLOAT #x6D6E6B28)) -(/ (#.(MAKE-DOUBLE-FLOAT #x-80000000 #x0) #x1) #.(MAKE-DOUBLE-FLOAT #x-80000000 #x0)) (/ (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #x1) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) (/ (#.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0) #.(MAKE-DOUBLE-FLOAT #x41C00000 #x0)) #.(MAKE-DOUBLE-FLOAT #x3E200000 #x0)) (/ (#.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0) #.(MAKE-DOUBLE-FLOAT #x43B00000 #x0)) #.(MAKE-DOUBLE-FLOAT #x3C300000 #x0)) @@ -351,185 +308,157 @@ (/ (#.(MAKE-DOUBLE-FLOAT #x400921FB #x54442D18) #x2) #.(MAKE-DOUBLE-FLOAT #x3FF921FB #x54442D18)) (/ (#.(MAKE-DOUBLE-FLOAT #x400921FB #x54442D18) #.(MAKE-DOUBLE-FLOAT #x40000000 #x0)) #.(MAKE-DOUBLE-FLOAT #x3FF921FB #x54442D18)) (/ (#.(MAKE-DOUBLE-FLOAT #x40100000 #x0) #.(MAKE-DOUBLE-FLOAT #x5FEFFFFF #xFFFFFFFF)) #.(MAKE-DOUBLE-FLOAT #x20100000 #x1)) -(/ (#.(MAKE-DOUBLE-FLOAT #x40734413 #x509F79FF) #x1) #.(MAKE-DOUBLE-FLOAT #x40734413 #x509F79FF)) -(/ (#.(MAKE-DOUBLE-FLOAT #x407434E6 #x420F4374) #x1) #.(MAKE-DOUBLE-FLOAT #x407434E6 #x420F4374)) -(/ (#.(MAKE-DOUBLE-FLOAT #x408D6413 #x509F7A00) #x1) #.(MAKE-DOUBLE-FLOAT #x408D6413 #x509F7A00)) -(/ (#.(MAKE-DOUBLE-FLOAT #x408DDCE6 #x420F4374) #x1) #.(MAKE-DOUBLE-FLOAT #x408DDCE6 #x420F4374)) -(/ (#.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFF000000) #x1) #.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFF000000)) (/ (#.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFFFFFFFF) #x1) #.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFFFFFFFF)) (/ (#.(MAKE-DOUBLE-FLOAT #x41C00000 #x0) #x1) #.(MAKE-DOUBLE-FLOAT #x41C00000 #x0)) -(/ (#.(MAKE-DOUBLE-FLOAT #x41D7FFFF #xFF800000) #x1) #.(MAKE-DOUBLE-FLOAT #x41D7FFFF #xFF800000)) -(/ (#.(MAKE-DOUBLE-FLOAT #x41D7FFFF #xFFC00000) #x1) #.(MAKE-DOUBLE-FLOAT #x41D7FFFF #xFFC00000)) -(/ (#.(MAKE-DOUBLE-FLOAT #x439DCD64 #xFF1194D8) #x1) #.(MAKE-DOUBLE-FLOAT #x439DCD64 #xFF1194D8)) (/ (#.(MAKE-DOUBLE-FLOAT #x43AFFFFF #xFFFFFFFF) #x1) #.(MAKE-DOUBLE-FLOAT #x43AFFFFF #xFFFFFFFF)) (/ (#.(MAKE-DOUBLE-FLOAT #x43B00000 #x0) #x1) #.(MAKE-DOUBLE-FLOAT #x43B00000 #x0)) (/ (#.(MAKE-DOUBLE-FLOAT #x43CFFFFF #xFFFFFFFF) #x1) #.(MAKE-DOUBLE-FLOAT #x43CFFFFF #xFFFFFFFF)) (/ (#.(MAKE-DOUBLE-FLOAT #x43D00000 #x0) #x1) #.(MAKE-DOUBLE-FLOAT #x43D00000 #x0)) -(/ (#.(MAKE-DOUBLE-FLOAT #x458DCD65 #x0) #x1) #.(MAKE-DOUBLE-FLOAT #x458DCD65 #x0)) -(/ (#.(MAKE-DOUBLE-FLOAT #x45ADCD65 #x0) #x1) #.(MAKE-DOUBLE-FLOAT #x45ADCD65 #x0)) (/ (#.(MAKE-DOUBLE-FLOAT #x5FEFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x40100000 #x0)) #.(MAKE-DOUBLE-FLOAT #x5FCFFFFF #xFFFFFFFF)) (< (#x-8000000000000000 #.(MAKE-SINGLE-FLOAT #x-800001)) NIL) (< (#x-8000000000000000 #.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF)) NIL) -(< (#x-4000000000000001 #.(MAKE-SINGLE-FLOAT #x-800001)) NIL) -(< (#x-4000000000000001 #.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF)) NIL) (< (#x-4000000000000000 #.(MAKE-SINGLE-FLOAT #x-800001)) NIL) (< (#x-4000000000000000 #.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF)) NIL) -(< (#x-1000000000000001 #.(MAKE-SINGLE-FLOAT #x-800001)) NIL) -(< (#x-1000000000000001 #.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF)) NIL) (< (#x-1000000000000000 #.(MAKE-SINGLE-FLOAT #x-800001)) NIL) (< (#x-1000000000000000 #.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF)) NIL) +(< (#x-20000000000000 #.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF)) NIL) (< (#x-80000000 #.(MAKE-SINGLE-FLOAT #x-800001)) NIL) (< (#x-80000000 #.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF)) NIL) -(< (#x-20000001 #.(MAKE-SINGLE-FLOAT #x-800001)) NIL) -(< (#x-20000001 #.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF)) NIL) (< (#x-20000000 #.(MAKE-SINGLE-FLOAT #x-800001)) NIL) (< (#x-20000000 #.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF)) NIL) -(< (#x-F3E58 #.(MAKE-SINGLE-FLOAT #x-800001)) NIL) +(< (#x-1000000 #.(MAKE-SINGLE-FLOAT #x-800001)) NIL) (< (#x-433 #.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF)) NIL) (< (#x-432 #.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF)) NIL) -(< (#x-3BD #.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF)) NIL) -(< (#x-3BC #.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF)) NIL) -(< (#x-3AE #.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF)) NIL) (< (#x-144 #.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF)) NIL) (< (#x-143 #.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF)) NIL) (< (#x-135 #.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF)) NIL) (< (#x-F #.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF)) NIL) (< (#x-1 #.(MAKE-SINGLE-FLOAT #x-800001)) NIL) (< (#x-1 #.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF)) NIL) -(< (#x0 #.(MAKE-SINGLE-FLOAT #x-80000000)) NIL) (< (#x0 #.(MAKE-SINGLE-FLOAT #x-3136F025)) NIL) (< (#x0 #.(MAKE-SINGLE-FLOAT #x-21B6F025)) NIL) (< (#x0 #.(MAKE-SINGLE-FLOAT #x-20B6F025)) NIL) (< (#x0 #.(MAKE-SINGLE-FLOAT #x-800001)) NIL) (< (#x0 #.(MAKE-SINGLE-FLOAT #x0)) NIL) (< (#x0 #.(MAKE-SINGLE-FLOAT #x4DFFFFFF)) T) -(< (#x0 #.(MAKE-SINGLE-FLOAT #x4E000000)) T) -(< (#x0 #.(MAKE-SINGLE-FLOAT #x4EC00000)) T) (< (#x0 #.(MAKE-SINGLE-FLOAT #x4EC90FDB)) T) -(< (#x0 #.(MAKE-SINGLE-FLOAT #x5CEE6B28)) T) (< (#x0 #.(MAKE-SINGLE-FLOAT #x5D7FFFFF)) T) -(< (#x0 #.(MAKE-SINGLE-FLOAT #x5D800000)) T) (< (#x0 #.(MAKE-SINGLE-FLOAT #x5E490FDB)) T) (< (#x0 #.(MAKE-SINGLE-FLOAT #x5E7FFFFF)) T) -(< (#x0 #.(MAKE-SINGLE-FLOAT #x5E800000)) T) (< (#x0 #.(MAKE-SINGLE-FLOAT #x5F490FDB)) T) -(< (#x0 #.(MAKE-SINGLE-FLOAT #x6C6E6B28)) T) -(< (#x0 #.(MAKE-SINGLE-FLOAT #x6D6E6B28)) T) (< (#x0 #.(MAKE-DOUBLE-FLOAT #x-3E26DE05 #x54442D18)) NIL) (< (#x0 #.(MAKE-DOUBLE-FLOAT #x-3C36DE05 #x54442D18)) NIL) (< (#x0 #.(MAKE-DOUBLE-FLOAT #x-3C16DE05 #x54442D18)) NIL) (< (#x0 #.(MAKE-DOUBLE-FLOAT #x-500001 #xFFFFFFFE)) NIL) (< (#x0 #.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF)) NIL) (< (#x0 #.(MAKE-DOUBLE-FLOAT #x0 #x0)) NIL) -(< (#x0 #.(MAKE-DOUBLE-FLOAT #x40734413 #x509F79FF)) T) -(< (#x0 #.(MAKE-DOUBLE-FLOAT #x408D6413 #x509F7A00)) T) -(< (#x0 #.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFF000000)) T) (< (#x0 #.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFFFFFFFF)) T) -(< (#x0 #.(MAKE-DOUBLE-FLOAT #x41D7FFFF #xFF800000)) T) (< (#x0 #.(MAKE-DOUBLE-FLOAT #x41D921FB #x537B1D3D)) T) -(< (#x0 #.(MAKE-DOUBLE-FLOAT #x439DCD64 #xFF1194D8)) T) (< (#x0 #.(MAKE-DOUBLE-FLOAT #x43AFFFFF #xFFFFFFFF)) T) -(< (#x0 #.(MAKE-DOUBLE-FLOAT #x43B00000 #x0)) T) (< (#x0 #.(MAKE-DOUBLE-FLOAT #x43C921FB #x54442D18)) T) (< (#x0 #.(MAKE-DOUBLE-FLOAT #x43CFFFFF #xFFFFFFFF)) T) -(< (#x0 #.(MAKE-DOUBLE-FLOAT #x43D00000 #x0)) T) (< (#x0 #.(MAKE-DOUBLE-FLOAT #x43E921FB #x54442D18)) T) -(< (#x0 #.(MAKE-DOUBLE-FLOAT #x458DCD65 #x0)) T) -(< (#x0 #.(MAKE-DOUBLE-FLOAT #x45ADCD65 #x0)) T) (< (#x1/2 #.(MAKE-SINGLE-FLOAT #x-800001)) NIL) (< (#x1/2 #.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF)) NIL) (< (#x1 #.(MAKE-SINGLE-FLOAT #x-800001)) NIL) (< (#x1 #.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF)) NIL) (< (#x2 #.(MAKE-SINGLE-FLOAT #x-800001)) NIL) (< (#x2 #.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF)) NIL) -(< (#xE #.(MAKE-SINGLE-FLOAT #x-800001)) NIL) (< (#x35 #.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF)) NIL) (< (#x3E8 #.(MAKE-SINGLE-FLOAT #x-800001)) NIL) -(< (#x1FFFFFFF #.(MAKE-SINGLE-FLOAT #x-800001)) NIL) -(< (#x1FFFFFFF #.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF)) NIL) +(< (#xF4240 #.(MAKE-SINGLE-FLOAT #x-800001)) NIL) (< (#x20000000 #.(MAKE-SINGLE-FLOAT #x-800001)) NIL) (< (#x20000000 #.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF)) NIL) (< (#x80000000 #.(MAKE-SINGLE-FLOAT #x-800001)) NIL) (< (#x80000000 #.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF)) NIL) -(< (#xFFFFFFFFFFFFFFF #.(MAKE-SINGLE-FLOAT #x-800001)) NIL) -(< (#xFFFFFFFFFFFFFFF #.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF)) NIL) (< (#x1000000000000000 #.(MAKE-SINGLE-FLOAT #x-800001)) NIL) (< (#x1000000000000000 #.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF)) NIL) -(< (#x3FFFFFFFFFFFFFFF #.(MAKE-SINGLE-FLOAT #x-800001)) NIL) -(< (#x3FFFFFFFFFFFFFFF #.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF)) NIL) (< (#x4000000000000000 #.(MAKE-SINGLE-FLOAT #x-800001)) NIL) (< (#x4000000000000000 #.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF)) NIL) (< (#x8000000000000000 #.(MAKE-SINGLE-FLOAT #x-800001)) NIL) (< (#x8000000000000000 #.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF)) NIL) -(< (#.(MAKE-SINGLE-FLOAT #x-80000000) #x0) NIL) (< (#.(MAKE-SINGLE-FLOAT #x-80000000) #.(MAKE-SINGLE-FLOAT #x-80000000)) NIL) -(< (#.(MAKE-SINGLE-FLOAT #x-80000000) #.(MAKE-SINGLE-FLOAT #x3F7FFFEF)) T) +(< (#.(MAKE-SINGLE-FLOAT #x-80000000) #.(MAKE-SINGLE-FLOAT #x0)) NIL) (< (#.(MAKE-SINGLE-FLOAT #x-80000000) #.(MAKE-SINGLE-FLOAT #x3F800000)) T) (< (#.(MAKE-SINGLE-FLOAT #x-80000000) #.(MAKE-SINGLE-FLOAT #x4E6E6B28)) T) (< (#.(MAKE-SINGLE-FLOAT #x-80000000) #.(MAKE-SINGLE-FLOAT #x5CEE6B28)) T) (< (#.(MAKE-SINGLE-FLOAT #x-80000000) #.(MAKE-SINGLE-FLOAT #x6C6E6B28)) T) (< (#.(MAKE-SINGLE-FLOAT #x-80000000) #.(MAKE-SINGLE-FLOAT #x6D6E6B28)) T) -(< (#.(MAKE-SINGLE-FLOAT #x-80000000) #.(MAKE-DOUBLE-FLOAT #x-80000000 #x0)) NIL) (< (#.(MAKE-SINGLE-FLOAT #x-80000000) #.(MAKE-DOUBLE-FLOAT #x439DCD64 #xFF1194D8)) T) (< (#.(MAKE-SINGLE-FLOAT #x-80000000) #.(MAKE-DOUBLE-FLOAT #x458DCD65 #x0)) T) (< (#.(MAKE-SINGLE-FLOAT #x-80000000) #.(MAKE-DOUBLE-FLOAT #x45ADCD65 #x0)) T) -(< (#.(MAKE-SINGLE-FLOAT #x-40804189) #.(MAKE-SINGLE-FLOAT #x0)) T) +(< (#.(MAKE-SINGLE-FLOAT #x-40800000) #.(MAKE-SINGLE-FLOAT #x-80000000)) T) (< (#.(MAKE-SINGLE-FLOAT #x-40800000) #.(MAKE-SINGLE-FLOAT #x-40800000)) NIL) +(< (#.(MAKE-SINGLE-FLOAT #x-40800000) #.(MAKE-SINGLE-FLOAT #x-34800000)) NIL) (< (#.(MAKE-SINGLE-FLOAT #x-40800000) #.(MAKE-SINGLE-FLOAT #x0)) T) (< (#.(MAKE-SINGLE-FLOAT #x-40800000) #.(MAKE-SINGLE-FLOAT #x3F800000)) T) -(< (#.(MAKE-SINGLE-FLOAT #x-40800000) #.(MAKE-DOUBLE-FLOAT #x-40100000 #x0)) NIL) +(< (#.(MAKE-SINGLE-FLOAT #x-40800000) #.(MAKE-SINGLE-FLOAT #x4B7FFFFF)) T) +(< (#.(MAKE-SINGLE-FLOAT #x-40800000) #.(MAKE-SINGLE-FLOAT #x4DFFFFFF)) T) +(< (#.(MAKE-SINGLE-FLOAT #x-40800000) #.(MAKE-SINGLE-FLOAT #x5D7FFFFF)) T) +(< (#.(MAKE-SINGLE-FLOAT #x-40800000) #.(MAKE-SINGLE-FLOAT #x5E7FFFFF)) T) (< (#.(MAKE-SINGLE-FLOAT #x-40800000) #.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF)) NIL) +(< (#.(MAKE-SINGLE-FLOAT #x-34800000) #.(MAKE-SINGLE-FLOAT #x-34800000)) NIL) (< (#.(MAKE-SINGLE-FLOAT #x-32000000) #x0) T) (< (#.(MAKE-SINGLE-FLOAT #x-32000000) #.(MAKE-SINGLE-FLOAT #x-32000000)) NIL) -(< (#.(MAKE-SINGLE-FLOAT #x-32000000) #.(MAKE-SINGLE-FLOAT #x4E000000)) T) +(< (#.(MAKE-SINGLE-FLOAT #x-32000000) #.(MAKE-SINGLE-FLOAT #x0)) T) +(< (#.(MAKE-SINGLE-FLOAT #x-32000000) #.(MAKE-SINGLE-FLOAT #x4DFFFFFF)) T) (< (#.(MAKE-SINGLE-FLOAT #x-32000000) #.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF)) NIL) (< (#.(MAKE-SINGLE-FLOAT #x-319194D8) #.(MAKE-SINGLE-FLOAT #x0)) T) -(< (#.(MAKE-SINGLE-FLOAT #x-31400000) #x0) T) (< (#.(MAKE-SINGLE-FLOAT #x-3136F025) #x0) T) (< (#.(MAKE-SINGLE-FLOAT #x-3136F025) #.(MAKE-SINGLE-FLOAT #x-3136F025)) NIL) (< (#.(MAKE-SINGLE-FLOAT #x-3136F025) #.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF)) NIL) -(< (#.(MAKE-SINGLE-FLOAT #x-231194D8) #x0) T) (< (#.(MAKE-SINGLE-FLOAT #x-231194D8) #.(MAKE-SINGLE-FLOAT #x0)) T) (< (#.(MAKE-SINGLE-FLOAT #x-22800000) #x0) T) (< (#.(MAKE-SINGLE-FLOAT #x-22800000) #.(MAKE-SINGLE-FLOAT #x-22800000)) NIL) -(< (#.(MAKE-SINGLE-FLOAT #x-22800000) #.(MAKE-SINGLE-FLOAT #x5D800000)) T) +(< (#.(MAKE-SINGLE-FLOAT #x-22800000) #.(MAKE-SINGLE-FLOAT #x0)) T) +(< (#.(MAKE-SINGLE-FLOAT #x-22800000) #.(MAKE-SINGLE-FLOAT #x5D7FFFFF)) T) (< (#.(MAKE-SINGLE-FLOAT #x-22800000) #.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF)) NIL) (< (#.(MAKE-SINGLE-FLOAT #x-21B6F025) #x0) T) (< (#.(MAKE-SINGLE-FLOAT #x-21B6F025) #.(MAKE-SINGLE-FLOAT #x-21B6F025)) NIL) (< (#.(MAKE-SINGLE-FLOAT #x-21B6F025) #.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF)) NIL) (< (#.(MAKE-SINGLE-FLOAT #x-21800000) #x0) T) (< (#.(MAKE-SINGLE-FLOAT #x-21800000) #.(MAKE-SINGLE-FLOAT #x-21800000)) NIL) -(< (#.(MAKE-SINGLE-FLOAT #x-21800000) #.(MAKE-SINGLE-FLOAT #x5E800000)) T) +(< (#.(MAKE-SINGLE-FLOAT #x-21800000) #.(MAKE-SINGLE-FLOAT #x0)) T) +(< (#.(MAKE-SINGLE-FLOAT #x-21800000) #.(MAKE-SINGLE-FLOAT #x5E7FFFFF)) T) (< (#.(MAKE-SINGLE-FLOAT #x-21800000) #.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF)) NIL) (< (#.(MAKE-SINGLE-FLOAT #x-20B6F025) #x0) T) (< (#.(MAKE-SINGLE-FLOAT #x-20B6F025) #.(MAKE-SINGLE-FLOAT #x-20B6F025)) NIL) (< (#.(MAKE-SINGLE-FLOAT #x-20B6F025) #.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF)) NIL) -(< (#.(MAKE-SINGLE-FLOAT #x-139194D8) #x0) T) (< (#.(MAKE-SINGLE-FLOAT #x-139194D8) #.(MAKE-SINGLE-FLOAT #x0)) T) -(< (#.(MAKE-SINGLE-FLOAT #x-129194D8) #x0) T) (< (#.(MAKE-SINGLE-FLOAT #x-129194D8) #.(MAKE-SINGLE-FLOAT #x0)) T) (< (#.(MAKE-SINGLE-FLOAT #x0) #x-1) NIL) (< (#.(MAKE-SINGLE-FLOAT #x0) #x0) NIL) +(< (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x-80000000)) NIL) (< (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x-40800000)) NIL) +(< (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x-34800000)) NIL) (< (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x-800001)) NIL) (< (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x0)) NIL) (< (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x3D800000)) T) +(< (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x3F000000)) T) (< (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x3F800000)) T) +(< (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x4DFFFFFF)) T) (< (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x4E000000)) T) +(< (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x538637BD)) T) (< (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x5883126F)) T) +(< (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x5D7FFFFF)) T) (< (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x5D800000)) T) +(< (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x5E7FFFFF)) T) (< (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x5E800000)) T) (< (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF)) NIL) (< (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) NIL) +(< (#.(MAKE-SINGLE-FLOAT #x3D800000) #.(MAKE-SINGLE-FLOAT #x3D800000)) NIL) (< (#.(MAKE-SINGLE-FLOAT #x3F000000) #x0) NIL) +(< (#.(MAKE-SINGLE-FLOAT #x3F000000) #.(MAKE-SINGLE-FLOAT #x0)) NIL) (< (#.(MAKE-SINGLE-FLOAT #x3F000000) #.(MAKE-SINGLE-FLOAT #x3F000000)) NIL) -(< (#.(MAKE-SINGLE-FLOAT #x3F000000) #.(MAKE-SINGLE-FLOAT #x4E800000)) T) (< (#.(MAKE-SINGLE-FLOAT #x3F7FFFEF) #.(MAKE-SINGLE-FLOAT #x3F7FFFEF)) NIL) +(< (#.(MAKE-SINGLE-FLOAT #x3F800000) #x0) NIL) (< (#.(MAKE-SINGLE-FLOAT #x3F800000) #.(MAKE-SINGLE-FLOAT #x-40800000)) NIL) (< (#.(MAKE-SINGLE-FLOAT #x3F800000) #.(MAKE-SINGLE-FLOAT #x-800001)) NIL) (< (#.(MAKE-SINGLE-FLOAT #x3F800000) #.(MAKE-SINGLE-FLOAT #x0)) NIL) +(< (#.(MAKE-SINGLE-FLOAT #x3F800000) #.(MAKE-SINGLE-FLOAT #x3D800000)) NIL) (< (#.(MAKE-SINGLE-FLOAT #x3F800000) #.(MAKE-SINGLE-FLOAT #x3F800000)) NIL) (< (#.(MAKE-SINGLE-FLOAT #x3F800000) #.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF)) NIL) +(< (#.(MAKE-SINGLE-FLOAT #x3FC90FDB) #.(MAKE-SINGLE-FLOAT #x3FC90FDB)) NIL) (< (#.(MAKE-SINGLE-FLOAT #x3FC90FDB) #.(MAKE-SINGLE-FLOAT #x4EC90FDB)) T) (< (#.(MAKE-SINGLE-FLOAT #x3FC90FDB) #.(MAKE-SINGLE-FLOAT #x5E490FDB)) T) (< (#.(MAKE-SINGLE-FLOAT #x3FC90FDB) #.(MAKE-SINGLE-FLOAT #x5F490FDB)) T) @@ -537,29 +466,40 @@ (< (#.(MAKE-SINGLE-FLOAT #x40490FDB) #.(MAKE-SINGLE-FLOAT #x4EC90FDB)) T) (< (#.(MAKE-SINGLE-FLOAT #x40490FDB) #.(MAKE-SINGLE-FLOAT #x5E490FDB)) T) (< (#.(MAKE-SINGLE-FLOAT #x40490FDB) #.(MAKE-SINGLE-FLOAT #x5F490FDB)) T) +(< (#.(MAKE-SINGLE-FLOAT #x4B7FFFFF) #.(MAKE-SINGLE-FLOAT #x-40800000)) NIL) +(< (#.(MAKE-SINGLE-FLOAT #x4B7FFFFF) #.(MAKE-SINGLE-FLOAT #x-34800000)) NIL) +(< (#.(MAKE-SINGLE-FLOAT #x4B7FFFFF) #.(MAKE-SINGLE-FLOAT #x-32000000)) NIL) +(< (#.(MAKE-SINGLE-FLOAT #x4B7FFFFF) #.(MAKE-SINGLE-FLOAT #x-22800000)) NIL) +(< (#.(MAKE-SINGLE-FLOAT #x4B7FFFFF) #.(MAKE-SINGLE-FLOAT #x-21800000)) NIL) +(< (#.(MAKE-SINGLE-FLOAT #x4B7FFFFF) #.(MAKE-SINGLE-FLOAT #x4B7FFFFF)) NIL) +(< (#.(MAKE-SINGLE-FLOAT #x4DFFFFFF) #.(MAKE-SINGLE-FLOAT #x-32000000)) NIL) +(< (#.(MAKE-SINGLE-FLOAT #x4DFFFFFF) #.(MAKE-SINGLE-FLOAT #x0)) NIL) +(< (#.(MAKE-SINGLE-FLOAT #x4DFFFFFF) #.(MAKE-SINGLE-FLOAT #x4B7FFFFF)) NIL) (< (#.(MAKE-SINGLE-FLOAT #x4DFFFFFF) #.(MAKE-SINGLE-FLOAT #x4DFFFFFF)) NIL) -(< (#.(MAKE-SINGLE-FLOAT #x4E000000) #x0) NIL) -(< (#.(MAKE-SINGLE-FLOAT #x4E000000) #.(MAKE-SINGLE-FLOAT #x-32000000)) NIL) (< (#.(MAKE-SINGLE-FLOAT #x4E000000) #.(MAKE-SINGLE-FLOAT #x0)) NIL) (< (#.(MAKE-SINGLE-FLOAT #x4E000000) #.(MAKE-SINGLE-FLOAT #x4E000000)) NIL) (< (#.(MAKE-SINGLE-FLOAT #x4E6E6B28) #.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF)) NIL) -(< (#.(MAKE-SINGLE-FLOAT #x4E800000) #.(MAKE-SINGLE-FLOAT #x3F000000)) NIL) (< (#.(MAKE-SINGLE-FLOAT #x4E800000) #.(MAKE-SINGLE-FLOAT #x4E800000)) NIL) (< (#.(MAKE-SINGLE-FLOAT #x4EC90FDB) #.(MAKE-SINGLE-FLOAT #x4EC90FDB)) NIL) +(< (#.(MAKE-SINGLE-FLOAT #x538637BD) #.(MAKE-SINGLE-FLOAT #x0)) NIL) +(< (#.(MAKE-SINGLE-FLOAT #x538637BD) #.(MAKE-SINGLE-FLOAT #x538637BD)) NIL) +(< (#.(MAKE-SINGLE-FLOAT #x540637BD) #.(MAKE-SINGLE-FLOAT #x540637BD)) NIL) (< (#.(MAKE-SINGLE-FLOAT #x5883126F) #.(MAKE-SINGLE-FLOAT #x0)) NIL) (< (#.(MAKE-SINGLE-FLOAT #x5883126F) #.(MAKE-SINGLE-FLOAT #x5883126F)) NIL) (< (#.(MAKE-SINGLE-FLOAT #x5903126F) #.(MAKE-SINGLE-FLOAT #x5903126F)) NIL) (< (#.(MAKE-SINGLE-FLOAT #x5CEE6B28) #.(MAKE-SINGLE-FLOAT #x5CEE6B28)) NIL) +(< (#.(MAKE-SINGLE-FLOAT #x5D7FFFFF) #.(MAKE-SINGLE-FLOAT #x-22800000)) NIL) +(< (#.(MAKE-SINGLE-FLOAT #x5D7FFFFF) #.(MAKE-SINGLE-FLOAT #x0)) NIL) +(< (#.(MAKE-SINGLE-FLOAT #x5D7FFFFF) #.(MAKE-SINGLE-FLOAT #x4B7FFFFF)) NIL) (< (#.(MAKE-SINGLE-FLOAT #x5D7FFFFF) #.(MAKE-SINGLE-FLOAT #x5D7FFFFF)) NIL) -(< (#.(MAKE-SINGLE-FLOAT #x5D800000) #x0) NIL) -(< (#.(MAKE-SINGLE-FLOAT #x5D800000) #.(MAKE-SINGLE-FLOAT #x-22800000)) NIL) (< (#.(MAKE-SINGLE-FLOAT #x5D800000) #.(MAKE-SINGLE-FLOAT #x0)) NIL) (< (#.(MAKE-SINGLE-FLOAT #x5D800000) #.(MAKE-SINGLE-FLOAT #x5D800000)) NIL) (< (#.(MAKE-SINGLE-FLOAT #x5E000000) #.(MAKE-SINGLE-FLOAT #x5E000000)) NIL) (< (#.(MAKE-SINGLE-FLOAT #x5E490FDB) #.(MAKE-SINGLE-FLOAT #x5E490FDB)) NIL) +(< (#.(MAKE-SINGLE-FLOAT #x5E7FFFFF) #.(MAKE-SINGLE-FLOAT #x-21800000)) NIL) +(< (#.(MAKE-SINGLE-FLOAT #x5E7FFFFF) #.(MAKE-SINGLE-FLOAT #x0)) NIL) +(< (#.(MAKE-SINGLE-FLOAT #x5E7FFFFF) #.(MAKE-SINGLE-FLOAT #x4B7FFFFF)) NIL) (< (#.(MAKE-SINGLE-FLOAT #x5E7FFFFF) #.(MAKE-SINGLE-FLOAT #x5E7FFFFF)) NIL) -(< (#.(MAKE-SINGLE-FLOAT #x5E800000) #x0) NIL) -(< (#.(MAKE-SINGLE-FLOAT #x5E800000) #.(MAKE-SINGLE-FLOAT #x-21800000)) NIL) (< (#.(MAKE-SINGLE-FLOAT #x5E800000) #.(MAKE-SINGLE-FLOAT #x0)) NIL) (< (#.(MAKE-SINGLE-FLOAT #x5E800000) #.(MAKE-SINGLE-FLOAT #x5E800000)) NIL) (< (#.(MAKE-SINGLE-FLOAT #x5F000000) #.(MAKE-SINGLE-FLOAT #x5F000000)) NIL) @@ -567,33 +507,32 @@ (< (#.(MAKE-SINGLE-FLOAT #x6C6E6B28) #.(MAKE-SINGLE-FLOAT #x6C6E6B28)) NIL) (< (#.(MAKE-SINGLE-FLOAT #x6D6E6B28) #.(MAKE-SINGLE-FLOAT #x6D6E6B28)) NIL) (< (#.(MAKE-SINGLE-FLOAT #x7F7FFFFF) #x-4000000000000001) NIL) -(< (#.(MAKE-SINGLE-FLOAT #x7F7FFFFF) #x-4000000000000000) NIL) (< (#.(MAKE-SINGLE-FLOAT #x7F7FFFFF) #x-1000000000000001) NIL) -(< (#.(MAKE-SINGLE-FLOAT #x7F7FFFFF) #x-1000000000000000) NIL) (< (#.(MAKE-SINGLE-FLOAT #x7F7FFFFF) #x-20000001) NIL) -(< (#.(MAKE-SINGLE-FLOAT #x7F7FFFFF) #x-20000000) NIL) (< (#.(MAKE-SINGLE-FLOAT #x7F7FFFFF) #x-1) NIL) (< (#.(MAKE-SINGLE-FLOAT #x7F7FFFFF) #x0) NIL) (< (#.(MAKE-SINGLE-FLOAT #x7F7FFFFF) #x1/2) NIL) (< (#.(MAKE-SINGLE-FLOAT #x7F7FFFFF) #x1) NIL) +(< (#.(MAKE-SINGLE-FLOAT #x7F7FFFFF) #x2) NIL) (< (#.(MAKE-SINGLE-FLOAT #x7F7FFFFF) #x3E8) NIL) (< (#.(MAKE-SINGLE-FLOAT #x7F7FFFFF) #xF423F) NIL) -(< (#.(MAKE-SINGLE-FLOAT #x7F7FFFFF) #x1000000) NIL) -(< (#.(MAKE-SINGLE-FLOAT #x7F7FFFFF) #x1FFFFFE1) NIL) +(< (#.(MAKE-SINGLE-FLOAT #x7F7FFFFF) #xF4240) NIL) +(< (#.(MAKE-SINGLE-FLOAT #x7F7FFFFF) #xFFFFFF) NIL) +(< (#.(MAKE-SINGLE-FLOAT #x7F7FFFFF) #x1FFFFFE0) NIL) (< (#.(MAKE-SINGLE-FLOAT #x7F7FFFFF) #x1FFFFFFB) NIL) +(< (#.(MAKE-SINGLE-FLOAT #x7F7FFFFF) #x1FFFFFFC) NIL) (< (#.(MAKE-SINGLE-FLOAT #x7F7FFFFF) #x1FFFFFFF) NIL) -(< (#.(MAKE-SINGLE-FLOAT #x7F7FFFFF) #x20000001) NIL) (< (#.(MAKE-SINGLE-FLOAT #x7F7FFFFF) #x7FFFFFFF) NIL) (< (#.(MAKE-SINGLE-FLOAT #x7F7FFFFF) #xFFFFFFFF) NIL) -(< (#.(MAKE-SINGLE-FLOAT #x7F7FFFFF) #x83126E978D4FD) NIL) -(< (#.(MAKE-SINGLE-FLOAT #x7F7FFFFF) #xFFFFFF000000001) NIL) +(< (#.(MAKE-SINGLE-FLOAT #x7F7FFFFF) #x218DEF416BD) NIL) +(< (#.(MAKE-SINGLE-FLOAT #x7F7FFFFF) #xFFFFFF000000000) NIL) (< (#.(MAKE-SINGLE-FLOAT #x7F7FFFFF) #xFFFFFFFFFFFFFFB) NIL) +(< (#.(MAKE-SINGLE-FLOAT #x7F7FFFFF) #xFFFFFFFFFFFFFFC) NIL) (< (#.(MAKE-SINGLE-FLOAT #x7F7FFFFF) #xFFFFFFFFFFFFFFF) NIL) -(< (#.(MAKE-SINGLE-FLOAT #x7F7FFFFF) #x1000000000000001) NIL) -(< (#.(MAKE-SINGLE-FLOAT #x7F7FFFFF) #x3FFFFFC000000001) NIL) +(< (#.(MAKE-SINGLE-FLOAT #x7F7FFFFF) #x3FFFFFC000000000) NIL) (< (#.(MAKE-SINGLE-FLOAT #x7F7FFFFF) #x3FFFFFFFFFFFFFFB) NIL) +(< (#.(MAKE-SINGLE-FLOAT #x7F7FFFFF) #x3FFFFFFFFFFFFFFC) NIL) (< (#.(MAKE-SINGLE-FLOAT #x7F7FFFFF) #x3FFFFFFFFFFFFFFF) NIL) -(< (#.(MAKE-SINGLE-FLOAT #x7F7FFFFF) #x4000000000000001) NIL) (< (#.(MAKE-SINGLE-FLOAT #x7F7FFFFF) #x7FFFFFFFFFFFFFFF) NIL) (< (#.(MAKE-SINGLE-FLOAT #x7F7FFFFF) #xFFFFFFFFFFFFFFFF) NIL) (< (#.(MAKE-SINGLE-FLOAT #x7F7FFFFF) #.(MAKE-SINGLE-FLOAT #x3F800000)) NIL) @@ -602,7 +541,9 @@ (< (#.(MAKE-SINGLE-FLOAT #x7F7FFFFF) #.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0)) NIL) (< (#.(MAKE-SINGLE-FLOAT #x7F7FFFFF) #.(MAKE-DOUBLE-FLOAT #x3FF921FB #x54442D18)) NIL) (< (#.(MAKE-SINGLE-FLOAT #x7F7FFFFF) #.(MAKE-DOUBLE-FLOAT #x400921FB #x54442D18)) NIL) +(< (#.(MAKE-SINGLE-FLOAT #x7F7FFFFF) #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) (< (#.(MAKE-DOUBLE-FLOAT #x-80000000 #x0) #.(MAKE-DOUBLE-FLOAT #x-80000000 #x0)) NIL) +(< (#.(MAKE-DOUBLE-FLOAT #x-80000000 #x0) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) NIL) (< (#.(MAKE-DOUBLE-FLOAT #x-80000000 #x0) #.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0)) T) (< (#.(MAKE-DOUBLE-FLOAT #x-80000000 #x0) #.(MAKE-DOUBLE-FLOAT #x3FF921FB #x54442D18)) T) (< (#.(MAKE-DOUBLE-FLOAT #x-80000000 #x0) #.(MAKE-DOUBLE-FLOAT #x40734413 #x509F79FF)) T) @@ -613,42 +554,47 @@ (< (#.(MAKE-DOUBLE-FLOAT #x-80000000 #x0) #.(MAKE-DOUBLE-FLOAT #x5FEFFFFF #xFFFFFFFF)) T) (< (#.(MAKE-DOUBLE-FLOAT #x-40100000 #x0) #.(MAKE-SINGLE-FLOAT #x-40800000)) NIL) (< (#.(MAKE-DOUBLE-FLOAT #x-40100000 #x0) #.(MAKE-SINGLE-FLOAT #x-800001)) NIL) +(< (#.(MAKE-DOUBLE-FLOAT #x-40100000 #x0) #.(MAKE-SINGLE-FLOAT #x3F800000)) T) +(< (#.(MAKE-DOUBLE-FLOAT #x-40100000 #x0) #.(MAKE-DOUBLE-FLOAT #x-80000000 #x0)) T) (< (#.(MAKE-DOUBLE-FLOAT #x-40100000 #x0) #.(MAKE-DOUBLE-FLOAT #x-40100000 #x0)) NIL) +(< (#.(MAKE-DOUBLE-FLOAT #x-40100000 #x0) #.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0)) NIL) +(< (#.(MAKE-DOUBLE-FLOAT #x-40100000 #x0) #.(MAKE-DOUBLE-FLOAT #x-3CC00000 #x0)) NIL) (< (#.(MAKE-DOUBLE-FLOAT #x-40100000 #x0) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) T) (< (#.(MAKE-DOUBLE-FLOAT #x-40100000 #x0) #.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0)) T) +(< (#.(MAKE-DOUBLE-FLOAT #x-40100000 #x0) #.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFF000000)) T) +(< (#.(MAKE-DOUBLE-FLOAT #x-40100000 #x0) #.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFFFFFFFF)) T) +(< (#.(MAKE-DOUBLE-FLOAT #x-40100000 #x0) #.(MAKE-DOUBLE-FLOAT #x433FFFFF #xFFFFFFFF)) T) +(< (#.(MAKE-DOUBLE-FLOAT #x-40100000 #x0) #.(MAKE-DOUBLE-FLOAT #x43AFFFFF #xFFFFFFFF)) T) +(< (#.(MAKE-DOUBLE-FLOAT #x-40100000 #x0) #.(MAKE-DOUBLE-FLOAT #x43CFFFFF #xFFFFFFFF)) T) (< (#.(MAKE-DOUBLE-FLOAT #x-4006DE05 #x54442D18) #.(MAKE-SINGLE-FLOAT #x-800001)) NIL) (< (#.(MAKE-DOUBLE-FLOAT #x-4006DE05 #x54442D18) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) T) (< (#.(MAKE-DOUBLE-FLOAT #x-3FF6DE05 #x54442D18) #.(MAKE-SINGLE-FLOAT #x-800001)) NIL) -(< (#.(MAKE-DOUBLE-FLOAT #x-3F8BCB1A #x420F4374) #x0) T) (< (#.(MAKE-DOUBLE-FLOAT #x-3F8BCB1A #x420F4374) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) T) (< (#.(MAKE-DOUBLE-FLOAT #x-3F78B6F0 #xD52D3052) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) T) -(< (#.(MAKE-DOUBLE-FLOAT #x-3F72231A #x420F4374) #x0) T) (< (#.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0) #x0) T) (< (#.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0) #.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0)) NIL) -(< (#.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0) #.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF)) NIL) -(< (#.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0) #.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFF000000)) T) -(< (#.(MAKE-DOUBLE-FLOAT #x-3E280001 #xFFC00000) #x0) T) +(< (#.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) T) +(< (#.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0) #.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFFFFFFFF)) T) (< (#.(MAKE-DOUBLE-FLOAT #x-3E26DE05 #x537B1D3D) #x0) T) (< (#.(MAKE-DOUBLE-FLOAT #x-3E26DE05 #x54442D18) #.(MAKE-DOUBLE-FLOAT #x-3E26DE05 #x537B1D3D)) T) -(< (#.(MAKE-DOUBLE-FLOAT #x-3C62329C #xFF1194D8) #x0) T) +(< (#.(MAKE-DOUBLE-FLOAT #x-3CC00000 #x0) #.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0)) T) +(< (#.(MAKE-DOUBLE-FLOAT #x-3CC00000 #x0) #.(MAKE-DOUBLE-FLOAT #x-3CC00000 #x0)) NIL) (< (#.(MAKE-DOUBLE-FLOAT #x-3C62329C #xFF1194D8) #.(MAKE-SINGLE-FLOAT #x0)) T) (< (#.(MAKE-DOUBLE-FLOAT #x-3C62329C #xFF1194D8) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) T) (< (#.(MAKE-DOUBLE-FLOAT #x-3C500000 #x0) #x0) T) (< (#.(MAKE-DOUBLE-FLOAT #x-3C500000 #x0) #.(MAKE-DOUBLE-FLOAT #x-3C500000 #x0)) NIL) -(< (#.(MAKE-DOUBLE-FLOAT #x-3C500000 #x0) #.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF)) NIL) -(< (#.(MAKE-DOUBLE-FLOAT #x-3C500000 #x0) #.(MAKE-DOUBLE-FLOAT #x43B00000 #x0)) T) +(< (#.(MAKE-DOUBLE-FLOAT #x-3C500000 #x0) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) T) +(< (#.(MAKE-DOUBLE-FLOAT #x-3C500000 #x0) #.(MAKE-DOUBLE-FLOAT #x43AFFFFF #xFFFFFFFF)) T) (< (#.(MAKE-DOUBLE-FLOAT #x-3C36DE05 #x54442D18) #x0) T) (< (#.(MAKE-DOUBLE-FLOAT #x-3C36DE05 #x54442D18) #.(MAKE-DOUBLE-FLOAT #x-3C36DE05 #x54442D18)) NIL) (< (#.(MAKE-DOUBLE-FLOAT #x-3C300000 #x0) #x0) T) (< (#.(MAKE-DOUBLE-FLOAT #x-3C300000 #x0) #.(MAKE-DOUBLE-FLOAT #x-3C300000 #x0)) NIL) -(< (#.(MAKE-DOUBLE-FLOAT #x-3C300000 #x0) #.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF)) NIL) -(< (#.(MAKE-DOUBLE-FLOAT #x-3C300000 #x0) #.(MAKE-DOUBLE-FLOAT #x43D00000 #x0)) T) +(< (#.(MAKE-DOUBLE-FLOAT #x-3C300000 #x0) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) T) +(< (#.(MAKE-DOUBLE-FLOAT #x-3C300000 #x0) #.(MAKE-DOUBLE-FLOAT #x43CFFFFF #xFFFFFFFF)) T) (< (#.(MAKE-DOUBLE-FLOAT #x-3C16DE05 #x54442D18) #x0) T) (< (#.(MAKE-DOUBLE-FLOAT #x-3C16DE05 #x54442D18) #.(MAKE-DOUBLE-FLOAT #x-3C16DE05 #x54442D18)) NIL) -(< (#.(MAKE-DOUBLE-FLOAT #x-3A72329B #x0) #x0) T) (< (#.(MAKE-DOUBLE-FLOAT #x-3A72329B #x0) #.(MAKE-SINGLE-FLOAT #x0)) T) (< (#.(MAKE-DOUBLE-FLOAT #x-3A72329B #x0) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) T) -(< (#.(MAKE-DOUBLE-FLOAT #x-3A52329B #x0) #x0) T) (< (#.(MAKE-DOUBLE-FLOAT #x-3A52329B #x0) #.(MAKE-SINGLE-FLOAT #x0)) T) (< (#.(MAKE-DOUBLE-FLOAT #x-3A52329B #x0) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) T) (< (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #x-4000000000000001) NIL) @@ -658,25 +604,35 @@ (< (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #x-20000001) NIL) (< (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #x-20000000) NIL) (< (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-SINGLE-FLOAT #x-800001)) NIL) +(< (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-SINGLE-FLOAT #x0)) NIL) +(< (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x-80000000 #x0)) NIL) (< (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x-40100000 #x0)) NIL) (< (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x-4006DE05 #x54442D18)) NIL) +(< (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0)) NIL) +(< (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x-3CC00000 #x0)) NIL) +(< (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF)) NIL) (< (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) NIL) +(< (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x1FFFFF #xFFFFFFFE)) T) +(< (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x3FE00000 #x0)) T) (< (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x3FE6A09E #x667F3BCD)) T) +(< (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x4270C6F7 #xA0B5E000)) T) (< (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x4310624D #xD2F1A9F8)) T) (< (#.(MAKE-DOUBLE-FLOAT #x3FB99999 #x9999999A) #.(MAKE-DOUBLE-FLOAT #x3FB99999 #x9999999A)) NIL) +(< (#.(MAKE-DOUBLE-FLOAT #x3FE00000 #x0) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) NIL) (< (#.(MAKE-DOUBLE-FLOAT #x3FE00000 #x0) #.(MAKE-DOUBLE-FLOAT #x3FE00000 #x0)) NIL) -(< (#.(MAKE-DOUBLE-FLOAT #x3FE00000 #x0) #.(MAKE-DOUBLE-FLOAT #x4083C273 #x2107A1BA)) T) -(< (#.(MAKE-DOUBLE-FLOAT #x3FE00000 #x0) #.(MAKE-DOUBLE-FLOAT #x41CFFFFF #xFF800000)) T) +(< (#.(MAKE-DOUBLE-FLOAT #x3FE00000 #x0) #.(MAKE-DOUBLE-FLOAT #x4083BA73 #x2107A1BA)) T) (< (#.(MAKE-DOUBLE-FLOAT #x3FE6A09E #x667F3BCD) #.(MAKE-DOUBLE-FLOAT #x3FF33333 #x33333333)) T) (< (#.(MAKE-DOUBLE-FLOAT #x3FEFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x3FEFFFFF #xFFFFFFFF)) NIL) (< (#.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0) #.(MAKE-SINGLE-FLOAT #x-800001)) NIL) (< (#.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0) #.(MAKE-SINGLE-FLOAT #x0)) NIL) +(< (#.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0) #.(MAKE-SINGLE-FLOAT #x3F800000)) NIL) (< (#.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0) #.(MAKE-DOUBLE-FLOAT #x-40100000 #x0)) NIL) (< (#.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0) #.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF)) NIL) (< (#.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) NIL) (< (#.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0) #.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0)) NIL) (< (#.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0) #.(MAKE-DOUBLE-FLOAT #x5FCFFFFF #xFFFFFFFF)) T) (< (#.(MAKE-DOUBLE-FLOAT #x3FF33333 #x33333333) #.(MAKE-DOUBLE-FLOAT #x3FE6A09E #x667F3BCD)) NIL) +(< (#.(MAKE-DOUBLE-FLOAT #x3FF33333 #x33333333) #.(MAKE-DOUBLE-FLOAT #x3FF33333 #x33333333)) NIL) (< (#.(MAKE-DOUBLE-FLOAT #x3FF921FB #x54442D18) #.(MAKE-DOUBLE-FLOAT #x3FF921FB #x54442D18)) NIL) (< (#.(MAKE-DOUBLE-FLOAT #x3FF921FB #x54442D18) #.(MAKE-DOUBLE-FLOAT #x41D921FB #x54442D18)) T) (< (#.(MAKE-DOUBLE-FLOAT #x3FF921FB #x54442D18) #.(MAKE-DOUBLE-FLOAT #x43C921FB #x54442D18)) T) @@ -692,43 +648,49 @@ (< (#.(MAKE-DOUBLE-FLOAT #x40734413 #x509F79FF) #.(MAKE-DOUBLE-FLOAT #x40734413 #x509F79FF)) NIL) (< (#.(MAKE-DOUBLE-FLOAT #x40742000 #x0) #.(MAKE-DOUBLE-FLOAT #x40742000 #x0)) NIL) (< (#.(MAKE-DOUBLE-FLOAT #x4083BA09 #xA84FBD00) #.(MAKE-DOUBLE-FLOAT #x4083BA09 #xA84FBD00)) NIL) -(< (#.(MAKE-DOUBLE-FLOAT #x4083C209 #xA84FBD00) #.(MAKE-DOUBLE-FLOAT #x4083C209 #xA84FBD00)) NIL) -(< (#.(MAKE-DOUBLE-FLOAT #x4083C273 #x2107A1BA) #.(MAKE-DOUBLE-FLOAT #x3FE00000 #x0)) NIL) +(< (#.(MAKE-DOUBLE-FLOAT #x4083BA73 #x2107A1BA) #.(MAKE-DOUBLE-FLOAT #x3FE00000 #x0)) NIL) +(< (#.(MAKE-DOUBLE-FLOAT #x4083BA73 #x2107A1BA) #.(MAKE-DOUBLE-FLOAT #x4083BA73 #x2107A1BA)) NIL) (< (#.(MAKE-DOUBLE-FLOAT #x408628B7 #x6E3A7B61) #.(MAKE-DOUBLE-FLOAT #x408628B7 #x6E3A7B61)) NIL) -(< (#.(MAKE-DOUBLE-FLOAT #x408D6000 #x0) #.(MAKE-DOUBLE-FLOAT #x408D6000 #x0)) NIL) -(< (#.(MAKE-DOUBLE-FLOAT #x408D6413 #x509F7A00) #.(MAKE-DOUBLE-FLOAT #x408D6413 #x509F7A00)) NIL) -(< (#.(MAKE-DOUBLE-FLOAT #x408DD800 #x0) #.(MAKE-DOUBLE-FLOAT #x408DD800 #x0)) NIL) -(< (#.(MAKE-DOUBLE-FLOAT #x4093C104 #xD427DE80) #.(MAKE-DOUBLE-FLOAT #x4093C104 #xD427DE80)) NIL) +(< (#.(MAKE-DOUBLE-FLOAT #x408D5C13 #x509F7A00) #.(MAKE-DOUBLE-FLOAT #x408D5C13 #x509F7A00)) NIL) (< (#.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xE0000000) #.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xE0000000)) NIL) -(< (#.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFF000000) #x0) NIL) -(< (#.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFF000000) #.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0)) NIL) (< (#.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFF000000) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) NIL) (< (#.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFF000000) #.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFF000000)) NIL) -(< (#.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFF000000) #.(MAKE-DOUBLE-FLOAT #x41C00000 #x0)) T) -(< (#.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFF000000) #.(MAKE-DOUBLE-FLOAT #x41DFFFFF #xFFC00000)) T) +(< (#.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x-40100000 #x0)) NIL) +(< (#.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0)) NIL) +(< (#.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x-3CC00000 #x0)) NIL) +(< (#.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) NIL) (< (#.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFFFFFFFF)) NIL) +(< (#.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x433FFFFF #xFFFFFFFF)) T) (< (#.(MAKE-DOUBLE-FLOAT #x41C00000 #x0) #.(MAKE-DOUBLE-FLOAT #x41C00000 #x0)) NIL) -(< (#.(MAKE-DOUBLE-FLOAT #x41CFFFFF #xFF800000) #.(MAKE-DOUBLE-FLOAT #x3FE00000 #x0)) NIL) -(< (#.(MAKE-DOUBLE-FLOAT #x41CFFFFF #xFF800000) #.(MAKE-DOUBLE-FLOAT #x41CFFFFF #xFF800000)) NIL) (< (#.(MAKE-DOUBLE-FLOAT #x41D00000 #x0) #.(MAKE-DOUBLE-FLOAT #x41D00000 #x0)) NIL) (< (#.(MAKE-DOUBLE-FLOAT #x41D00000 #x400000) #.(MAKE-DOUBLE-FLOAT #x41D00000 #x400000)) NIL) (< (#.(MAKE-DOUBLE-FLOAT #x41D921FB #x54442D18) #.(MAKE-DOUBLE-FLOAT #x41D921FB #x54442D18)) NIL) (< (#.(MAKE-DOUBLE-FLOAT #x41D921FB #x54442D18) #.(MAKE-DOUBLE-FLOAT #x43E00000 #x0)) T) (< (#.(MAKE-DOUBLE-FLOAT #x41D921FB #x60000000) #.(MAKE-DOUBLE-FLOAT #x41D921FB #x60000000)) NIL) +(< (#.(MAKE-DOUBLE-FLOAT #x4270C6F7 #xA0B5E000) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) NIL) +(< (#.(MAKE-DOUBLE-FLOAT #x4270C6F7 #xA0B5E000) #.(MAKE-DOUBLE-FLOAT #x4270C6F7 #xA0B5E000)) NIL) (< (#.(MAKE-DOUBLE-FLOAT #x4310624D #xD2F1A9F8) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) NIL) +(< (#.(MAKE-DOUBLE-FLOAT #x4310624D #xD2F1A9F8) #.(MAKE-DOUBLE-FLOAT #x4310624D #xD2F1A9F8)) NIL) +(< (#.(MAKE-DOUBLE-FLOAT #x433FFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x-40100000 #x0)) NIL) +(< (#.(MAKE-DOUBLE-FLOAT #x433FFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0)) NIL) +(< (#.(MAKE-DOUBLE-FLOAT #x433FFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x-3CC00000 #x0)) NIL) +(< (#.(MAKE-DOUBLE-FLOAT #x433FFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x-3C500000 #x0)) NIL) +(< (#.(MAKE-DOUBLE-FLOAT #x433FFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x-3C300000 #x0)) NIL) (< (#.(MAKE-DOUBLE-FLOAT #x433FFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x433FFFFF #xFFFFFFFF)) NIL) (< (#.(MAKE-DOUBLE-FLOAT #x439DCD64 #xFF1194D8) #.(MAKE-DOUBLE-FLOAT #x439DCD64 #xFF1194D8)) NIL) +(< (#.(MAKE-DOUBLE-FLOAT #x43AFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x-3C500000 #x0)) NIL) +(< (#.(MAKE-DOUBLE-FLOAT #x43AFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) NIL) +(< (#.(MAKE-DOUBLE-FLOAT #x43AFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x433FFFFF #xFFFFFFFF)) NIL) (< (#.(MAKE-DOUBLE-FLOAT #x43AFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x43AFFFFF #xFFFFFFFF)) NIL) -(< (#.(MAKE-DOUBLE-FLOAT #x43B00000 #x0) #x0) NIL) -(< (#.(MAKE-DOUBLE-FLOAT #x43B00000 #x0) #.(MAKE-DOUBLE-FLOAT #x-3C500000 #x0)) NIL) (< (#.(MAKE-DOUBLE-FLOAT #x43B00000 #x0) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) NIL) (< (#.(MAKE-DOUBLE-FLOAT #x43B00000 #x0) #.(MAKE-DOUBLE-FLOAT #x43B00000 #x0)) NIL) (< (#.(MAKE-DOUBLE-FLOAT #x43C00000 #x0) #.(MAKE-DOUBLE-FLOAT #x43C00000 #x0)) NIL) (< (#.(MAKE-DOUBLE-FLOAT #x43C921FB #x54442D18) #.(MAKE-DOUBLE-FLOAT #x43C921FB #x54442D18)) NIL) (< (#.(MAKE-DOUBLE-FLOAT #x43C921FB #x60000000) #.(MAKE-DOUBLE-FLOAT #x43C921FB #x60000000)) NIL) +(< (#.(MAKE-DOUBLE-FLOAT #x43CFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x-3C300000 #x0)) NIL) +(< (#.(MAKE-DOUBLE-FLOAT #x43CFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) NIL) +(< (#.(MAKE-DOUBLE-FLOAT #x43CFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x433FFFFF #xFFFFFFFF)) NIL) (< (#.(MAKE-DOUBLE-FLOAT #x43CFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x43CFFFFF #xFFFFFFFF)) NIL) -(< (#.(MAKE-DOUBLE-FLOAT #x43D00000 #x0) #x0) NIL) -(< (#.(MAKE-DOUBLE-FLOAT #x43D00000 #x0) #.(MAKE-DOUBLE-FLOAT #x-3C300000 #x0)) NIL) (< (#.(MAKE-DOUBLE-FLOAT #x43D00000 #x0) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) NIL) (< (#.(MAKE-DOUBLE-FLOAT #x43D00000 #x0) #.(MAKE-DOUBLE-FLOAT #x43D00000 #x0)) NIL) (< (#.(MAKE-DOUBLE-FLOAT #x43E00000 #x0) #.(MAKE-DOUBLE-FLOAT #x43E00000 #x0)) NIL) @@ -739,114 +701,80 @@ (< (#.(MAKE-DOUBLE-FLOAT #x5FCFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x5FCFFFFF #xFFFFFFFF)) NIL) (< (#.(MAKE-DOUBLE-FLOAT #x5FEFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x-80000000 #x0)) NIL) (< (#.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF) #x-4000000000000001) NIL) -(< (#.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF) #x-4000000000000000) NIL) (< (#.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF) #x-1000000000000001) NIL) -(< (#.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF) #x-1000000000000000) NIL) (< (#.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF) #x-20000001) NIL) -(< (#.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF) #x-20000000) NIL) (< (#.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF) #x-1) NIL) (< (#.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF) #x0) NIL) (< (#.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF) #x1/2) NIL) (< (#.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF) #x1) NIL) +(< (#.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF) #x2) NIL) (< (#.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF) #x133) NIL) (< (#.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF) #x134) NIL) -(< (#.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF) #x135) NIL) (< (#.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF) #x142) NIL) -(< (#.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF) #x3AC) NIL) -(< (#.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF) #x3AD) NIL) -(< (#.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF) #x3BB) NIL) (< (#.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF) #x3FF) NIL) (< (#.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF) #x400) NIL) (< (#.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF) #x1FFFFFE0) NIL) (< (#.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF) #x1FFFFFFF) NIL) -(< (#.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF) #x20000000) NIL) (< (#.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF) #x7FFFFFFF) NIL) (< (#.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF) #xFFFFFFFF) NIL) (< (#.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF) #x1FFFFFFFFFFFFF) NIL) -(< (#.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF) #xFFFFFFFFFFFFF81) NIL) +(< (#.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF) #xFFFFFFFFFFFFF80) NIL) (< (#.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF) #xFFFFFFFFFFFFFFF) NIL) -(< (#.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF) #x1000000000000001) NIL) -(< (#.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF) #x3FFFFFFFFFFFFE01) NIL) +(< (#.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF) #x3FFFFFFFFFFFFE00) NIL) (< (#.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF) #x3FFFFFFFFFFFFFC0) NIL) (< (#.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF) #x3FFFFFFFFFFFFFFF) NIL) -(< (#.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF) #x4000000000000001) NIL) (< (#.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF) #x7FFFFFFFFFFFFFFF) NIL) (< (#.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF) #xFFFFFFFFFFFFFFFF) NIL) (< (#.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF) #.(MAKE-SINGLE-FLOAT #x0)) NIL) (< (#.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF) #.(MAKE-SINGLE-FLOAT #x3F800000)) NIL) -(< (#.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF) #.(MAKE-SINGLE-FLOAT #x4E000000)) NIL) +(< (#.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF) #.(MAKE-SINGLE-FLOAT #x4DFFFFFF)) NIL) (< (#.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF) #.(MAKE-SINGLE-FLOAT #x4E6E6B28)) NIL) (< (#.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF) #.(MAKE-SINGLE-FLOAT #x4EC90FDB)) NIL) -(< (#.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF) #.(MAKE-SINGLE-FLOAT #x5D800000)) NIL) +(< (#.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF) #.(MAKE-SINGLE-FLOAT #x5D7FFFFF)) NIL) (< (#.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF) #.(MAKE-SINGLE-FLOAT #x5E490FDB)) NIL) -(< (#.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF) #.(MAKE-SINGLE-FLOAT #x5E800000)) NIL) +(< (#.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF) #.(MAKE-SINGLE-FLOAT #x5E7FFFFF)) NIL) (< (#.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF) #.(MAKE-SINGLE-FLOAT #x5F490FDB)) NIL) -(< (#.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFF000000)) NIL) -(< (#.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x43B00000 #x0)) NIL) -(< (#.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x43D00000 #x0)) NIL) +(< (#.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) NIL) (<= (#x-4000000000000000 #.(MAKE-DOUBLE-FLOAT #x0 #x0)) T) (<= (#x-1000000000000000 #.(MAKE-DOUBLE-FLOAT #x0 #x0)) T) (<= (#x-20000000 #.(MAKE-DOUBLE-FLOAT #x0 #x0)) T) (<= (#x-1 #.(MAKE-SINGLE-FLOAT #x0)) T) (<= (#x0 #.(MAKE-SINGLE-FLOAT #x-32000000)) NIL) (<= (#x0 #.(MAKE-SINGLE-FLOAT #x-31800000)) NIL) -(<= (#x0 #.(MAKE-SINGLE-FLOAT #x-31400000)) NIL) (<= (#x0 #.(MAKE-SINGLE-FLOAT #x-3136F025)) NIL) -(<= (#x0 #.(MAKE-SINGLE-FLOAT #x-231194D8)) NIL) (<= (#x0 #.(MAKE-SINGLE-FLOAT #x-22800000)) NIL) (<= (#x0 #.(MAKE-SINGLE-FLOAT #x-22000000)) NIL) (<= (#x0 #.(MAKE-SINGLE-FLOAT #x-21B6F025)) NIL) (<= (#x0 #.(MAKE-SINGLE-FLOAT #x-21800000)) NIL) (<= (#x0 #.(MAKE-SINGLE-FLOAT #x-21000000)) NIL) (<= (#x0 #.(MAKE-SINGLE-FLOAT #x-20B6F025)) NIL) -(<= (#x0 #.(MAKE-SINGLE-FLOAT #x-139194D8)) NIL) -(<= (#x0 #.(MAKE-SINGLE-FLOAT #x-129194D8)) NIL) +(<= (#x0 #.(MAKE-SINGLE-FLOAT #x3F800000)) T) (<= (#x0 #.(MAKE-SINGLE-FLOAT #x4DFFFFFF)) T) -(<= (#x0 #.(MAKE-SINGLE-FLOAT #x4E000000)) T) (<= (#x0 #.(MAKE-SINGLE-FLOAT #x4E800000)) T) -(<= (#x0 #.(MAKE-SINGLE-FLOAT #x4EC00000)) T) (<= (#x0 #.(MAKE-SINGLE-FLOAT #x4EC90FDB)) T) -(<= (#x0 #.(MAKE-SINGLE-FLOAT #x5CEE6B28)) T) (<= (#x0 #.(MAKE-SINGLE-FLOAT #x5D7FFFFF)) T) -(<= (#x0 #.(MAKE-SINGLE-FLOAT #x5D800000)) T) (<= (#x0 #.(MAKE-SINGLE-FLOAT #x5E000000)) T) (<= (#x0 #.(MAKE-SINGLE-FLOAT #x5E490FDB)) T) (<= (#x0 #.(MAKE-SINGLE-FLOAT #x5E7FFFFF)) T) -(<= (#x0 #.(MAKE-SINGLE-FLOAT #x5E800000)) T) (<= (#x0 #.(MAKE-SINGLE-FLOAT #x5F000000)) T) (<= (#x0 #.(MAKE-SINGLE-FLOAT #x5F490FDB)) T) -(<= (#x0 #.(MAKE-SINGLE-FLOAT #x6C6E6B28)) T) -(<= (#x0 #.(MAKE-SINGLE-FLOAT #x6D6E6B28)) T) -(<= (#x0 #.(MAKE-DOUBLE-FLOAT #x-3F8BCB1A #x420F4374)) NIL) -(<= (#x0 #.(MAKE-DOUBLE-FLOAT #x-3F72231A #x420F4374)) NIL) (<= (#x0 #.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0)) NIL) -(<= (#x0 #.(MAKE-DOUBLE-FLOAT #x-3E300000 #x0)) NIL) -(<= (#x0 #.(MAKE-DOUBLE-FLOAT #x-3E280001 #xFFC00000)) NIL) (<= (#x0 #.(MAKE-DOUBLE-FLOAT #x-3E26DE05 #x537B1D3D)) NIL) (<= (#x0 #.(MAKE-DOUBLE-FLOAT #x-3E26DE05 #x54442D18)) NIL) -(<= (#x0 #.(MAKE-DOUBLE-FLOAT #x-3C62329C #xFF1194D8)) NIL) (<= (#x0 #.(MAKE-DOUBLE-FLOAT #x-3C500000 #x0)) NIL) (<= (#x0 #.(MAKE-DOUBLE-FLOAT #x-3C400000 #x0)) NIL) (<= (#x0 #.(MAKE-DOUBLE-FLOAT #x-3C36DE05 #x54442D18)) NIL) (<= (#x0 #.(MAKE-DOUBLE-FLOAT #x-3C300000 #x0)) NIL) (<= (#x0 #.(MAKE-DOUBLE-FLOAT #x-3C200000 #x0)) NIL) (<= (#x0 #.(MAKE-DOUBLE-FLOAT #x-3C16DE05 #x54442D18)) NIL) -(<= (#x0 #.(MAKE-DOUBLE-FLOAT #x-3A72329B #x0)) NIL) -(<= (#x0 #.(MAKE-DOUBLE-FLOAT #x-3A52329B #x0)) NIL) (<= (#x0 #.(MAKE-DOUBLE-FLOAT #x0 #x0)) T) -(<= (#x0 #.(MAKE-DOUBLE-FLOAT #x40734413 #x509F79FF)) T) -(<= (#x0 #.(MAKE-DOUBLE-FLOAT #x4083C209 #xA84FBD00)) T) -(<= (#x0 #.(MAKE-DOUBLE-FLOAT #x4083C273 #x2107A1BA)) T) -(<= (#x0 #.(MAKE-DOUBLE-FLOAT #x408D6413 #x509F7A00)) T) +(<= (#x0 #.(MAKE-DOUBLE-FLOAT #x4083BA09 #xA84FBD00)) T) +(<= (#x0 #.(MAKE-DOUBLE-FLOAT #x4083BA73 #x2107A1BA)) T) (<= (#x0 #.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFF000000)) T) (<= (#x0 #.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFFFFFFFF)) T) (<= (#x0 #.(MAKE-DOUBLE-FLOAT #x41C00000 #x0)) T) -(<= (#x0 #.(MAKE-DOUBLE-FLOAT #x41CFFFFF #xFF800000)) T) -(<= (#x0 #.(MAKE-DOUBLE-FLOAT #x41D00000 #x0)) T) -(<= (#x0 #.(MAKE-DOUBLE-FLOAT #x41D7FFFF #xFF800000)) T) (<= (#x0 #.(MAKE-DOUBLE-FLOAT #x41D921FB #x537B1D3D)) T) (<= (#x0 #.(MAKE-DOUBLE-FLOAT #x41D921FB #x54442D18)) T) -(<= (#x0 #.(MAKE-DOUBLE-FLOAT #x439DCD64 #xFF1194D8)) T) (<= (#x0 #.(MAKE-DOUBLE-FLOAT #x43AFFFFF #xFFFFFFFF)) T) (<= (#x0 #.(MAKE-DOUBLE-FLOAT #x43B00000 #x0)) T) (<= (#x0 #.(MAKE-DOUBLE-FLOAT #x43C00000 #x0)) T) @@ -855,27 +783,47 @@ (<= (#x0 #.(MAKE-DOUBLE-FLOAT #x43D00000 #x0)) T) (<= (#x0 #.(MAKE-DOUBLE-FLOAT #x43E00000 #x0)) T) (<= (#x0 #.(MAKE-DOUBLE-FLOAT #x43E921FB #x54442D18)) T) -(<= (#x0 #.(MAKE-DOUBLE-FLOAT #x458DCD65 #x0)) T) -(<= (#x0 #.(MAKE-DOUBLE-FLOAT #x45ADCD65 #x0)) T) (<= (#x0 #.(MAKE-DOUBLE-FLOAT #x5FCFFFFF #xFFFFFFFF)) T) (<= (#x1 #.(MAKE-SINGLE-FLOAT #x0)) NIL) (<= (#x1 #.(MAKE-DOUBLE-FLOAT #x0 #x0)) NIL) (<= (#.(MAKE-SINGLE-FLOAT #x-80000000) #.(MAKE-SINGLE-FLOAT #x-80000000)) T) (<= (#.(MAKE-SINGLE-FLOAT #x-80000000) #.(MAKE-SINGLE-FLOAT #x-40800000)) NIL) +(<= (#.(MAKE-SINGLE-FLOAT #x-80000000) #.(MAKE-SINGLE-FLOAT #x0)) T) (<= (#.(MAKE-SINGLE-FLOAT #x-80000000) #.(MAKE-SINGLE-FLOAT #x3F800000)) T) -(<= (#.(MAKE-SINGLE-FLOAT #x-40804189) #.(MAKE-SINGLE-FLOAT #x0)) T) -(<= (#.(MAKE-SINGLE-FLOAT #x-40804189) #.(MAKE-SINGLE-FLOAT #x3F7FFFEF)) T) -(<= (#.(MAKE-SINGLE-FLOAT #x-40804189) #.(MAKE-SINGLE-FLOAT #x5903126F)) T) +(<= (#.(MAKE-SINGLE-FLOAT #x-80000000) #.(MAKE-SINGLE-FLOAT #x4B7FFFFF)) T) +(<= (#.(MAKE-SINGLE-FLOAT #x-80000000) #.(MAKE-SINGLE-FLOAT #x4E6E6B28)) T) +(<= (#.(MAKE-SINGLE-FLOAT #x-80000000) #.(MAKE-SINGLE-FLOAT #x5CEE6B28)) T) +(<= (#.(MAKE-SINGLE-FLOAT #x-80000000) #.(MAKE-SINGLE-FLOAT #x6C6E6B28)) T) +(<= (#.(MAKE-SINGLE-FLOAT #x-80000000) #.(MAKE-SINGLE-FLOAT #x6D6E6B28)) T) +(<= (#.(MAKE-SINGLE-FLOAT #x-80000000) #.(MAKE-DOUBLE-FLOAT #x439DCD64 #xFF1194D8)) T) +(<= (#.(MAKE-SINGLE-FLOAT #x-80000000) #.(MAKE-DOUBLE-FLOAT #x458DCD65 #x0)) T) +(<= (#.(MAKE-SINGLE-FLOAT #x-80000000) #.(MAKE-DOUBLE-FLOAT #x45ADCD65 #x0)) T) +(<= (#.(MAKE-SINGLE-FLOAT #x-40800000) #.(MAKE-SINGLE-FLOAT #x-80000000)) T) (<= (#.(MAKE-SINGLE-FLOAT #x-40800000) #.(MAKE-SINGLE-FLOAT #x-40800000)) T) (<= (#.(MAKE-SINGLE-FLOAT #x-40800000) #.(MAKE-SINGLE-FLOAT #x0)) T) (<= (#.(MAKE-SINGLE-FLOAT #x-40800000) #.(MAKE-SINGLE-FLOAT #x3DCCCCCD)) T) (<= (#.(MAKE-SINGLE-FLOAT #x-40800000) #.(MAKE-SINGLE-FLOAT #x3F800000)) T) +(<= (#.(MAKE-SINGLE-FLOAT #x-40800000) #.(MAKE-SINGLE-FLOAT #x4B7FFFFF)) T) +(<= (#.(MAKE-SINGLE-FLOAT #x-40800000) #.(MAKE-SINGLE-FLOAT #x4DFFFFFF)) T) +(<= (#.(MAKE-SINGLE-FLOAT #x-40800000) #.(MAKE-SINGLE-FLOAT #x5D7FFFFF)) T) +(<= (#.(MAKE-SINGLE-FLOAT #x-40800000) #.(MAKE-SINGLE-FLOAT #x5E7FFFFF)) T) +(<= (#.(MAKE-SINGLE-FLOAT #x-40800000) #.(MAKE-DOUBLE-FLOAT #x-40100000 #x0)) T) +(<= (#.(MAKE-SINGLE-FLOAT #x-40800000) #.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0)) T) +(<= (#.(MAKE-SINGLE-FLOAT #x-4036F025) #.(MAKE-SINGLE-FLOAT #x3FC90FDB)) T) (<= (#.(MAKE-SINGLE-FLOAT #x-4036F025) #.(MAKE-SINGLE-FLOAT #x4EC90FDB)) T) (<= (#.(MAKE-SINGLE-FLOAT #x-4036F025) #.(MAKE-SINGLE-FLOAT #x5E490FDB)) T) (<= (#.(MAKE-SINGLE-FLOAT #x-4036F025) #.(MAKE-SINGLE-FLOAT #x5F490FDB)) T) (<= (#.(MAKE-SINGLE-FLOAT #x-3FB6F025) #.(MAKE-SINGLE-FLOAT #x40490FDB)) T) +(<= (#.(MAKE-SINGLE-FLOAT #x-34800000) #.(MAKE-SINGLE-FLOAT #x-40800000)) T) +(<= (#.(MAKE-SINGLE-FLOAT #x-34800000) #.(MAKE-SINGLE-FLOAT #x-34800000)) T) +(<= (#.(MAKE-SINGLE-FLOAT #x-34800000) #.(MAKE-SINGLE-FLOAT #x4B7FFFFF)) T) +(<= (#.(MAKE-SINGLE-FLOAT #x-34800000) #.(MAKE-SINGLE-FLOAT #x4DFFFFFF)) T) +(<= (#.(MAKE-SINGLE-FLOAT #x-34800000) #.(MAKE-SINGLE-FLOAT #x5D7FFFFF)) T) +(<= (#.(MAKE-SINGLE-FLOAT #x-34800000) #.(MAKE-SINGLE-FLOAT #x5E7FFFFF)) T) (<= (#.(MAKE-SINGLE-FLOAT #x-32000000) #x0) T) (<= (#.(MAKE-SINGLE-FLOAT #x-32000000) #.(MAKE-SINGLE-FLOAT #x-32000000)) T) +(<= (#.(MAKE-SINGLE-FLOAT #x-32000000) #.(MAKE-SINGLE-FLOAT #x3F800000)) T) +(<= (#.(MAKE-SINGLE-FLOAT #x-32000000) #.(MAKE-SINGLE-FLOAT #x4B7FFFFF)) T) (<= (#.(MAKE-SINGLE-FLOAT #x-32000000) #.(MAKE-SINGLE-FLOAT #x4DFFFFFF)) T) (<= (#.(MAKE-SINGLE-FLOAT #x-32000000) #.(MAKE-SINGLE-FLOAT #x4E000000)) T) (<= (#.(MAKE-SINGLE-FLOAT #x-319194D8) #.(MAKE-SINGLE-FLOAT #x0)) T) @@ -883,16 +831,15 @@ (<= (#.(MAKE-SINGLE-FLOAT #x-31800000) #x0) T) (<= (#.(MAKE-SINGLE-FLOAT #x-31800000) #.(MAKE-SINGLE-FLOAT #x0)) T) (<= (#.(MAKE-SINGLE-FLOAT #x-31800000) #.(MAKE-SINGLE-FLOAT #x4E800000)) T) -(<= (#.(MAKE-SINGLE-FLOAT #x-31400000) #x0) T) -(<= (#.(MAKE-SINGLE-FLOAT #x-31400000) #.(MAKE-SINGLE-FLOAT #x4EC00000)) T) (<= (#.(MAKE-SINGLE-FLOAT #x-3136F025) #x0) T) (<= (#.(MAKE-SINGLE-FLOAT #x-3136F025) #.(MAKE-SINGLE-FLOAT #x-3136F025)) T) (<= (#.(MAKE-SINGLE-FLOAT #x-3136F025) #.(MAKE-SINGLE-FLOAT #x4EC90FDB)) T) -(<= (#.(MAKE-SINGLE-FLOAT #x-231194D8) #x0) T) (<= (#.(MAKE-SINGLE-FLOAT #x-231194D8) #.(MAKE-SINGLE-FLOAT #x0)) T) (<= (#.(MAKE-SINGLE-FLOAT #x-231194D8) #.(MAKE-SINGLE-FLOAT #x5CEE6B28)) T) (<= (#.(MAKE-SINGLE-FLOAT #x-22800000) #x0) T) (<= (#.(MAKE-SINGLE-FLOAT #x-22800000) #.(MAKE-SINGLE-FLOAT #x-22800000)) T) +(<= (#.(MAKE-SINGLE-FLOAT #x-22800000) #.(MAKE-SINGLE-FLOAT #x3F800000)) T) +(<= (#.(MAKE-SINGLE-FLOAT #x-22800000) #.(MAKE-SINGLE-FLOAT #x4B7FFFFF)) T) (<= (#.(MAKE-SINGLE-FLOAT #x-22800000) #.(MAKE-SINGLE-FLOAT #x5D7FFFFF)) T) (<= (#.(MAKE-SINGLE-FLOAT #x-22800000) #.(MAKE-SINGLE-FLOAT #x5D800000)) T) (<= (#.(MAKE-SINGLE-FLOAT #x-22000000) #x0) T) @@ -903,6 +850,8 @@ (<= (#.(MAKE-SINGLE-FLOAT #x-21B6F025) #.(MAKE-SINGLE-FLOAT #x5E490FDB)) T) (<= (#.(MAKE-SINGLE-FLOAT #x-21800000) #x0) T) (<= (#.(MAKE-SINGLE-FLOAT #x-21800000) #.(MAKE-SINGLE-FLOAT #x-21800000)) T) +(<= (#.(MAKE-SINGLE-FLOAT #x-21800000) #.(MAKE-SINGLE-FLOAT #x3F800000)) T) +(<= (#.(MAKE-SINGLE-FLOAT #x-21800000) #.(MAKE-SINGLE-FLOAT #x4B7FFFFF)) T) (<= (#.(MAKE-SINGLE-FLOAT #x-21800000) #.(MAKE-SINGLE-FLOAT #x5E7FFFFF)) T) (<= (#.(MAKE-SINGLE-FLOAT #x-21800000) #.(MAKE-SINGLE-FLOAT #x5E800000)) T) (<= (#.(MAKE-SINGLE-FLOAT #x-21000000) #x0) T) @@ -911,22 +860,24 @@ (<= (#.(MAKE-SINGLE-FLOAT #x-20B6F025) #x0) T) (<= (#.(MAKE-SINGLE-FLOAT #x-20B6F025) #.(MAKE-SINGLE-FLOAT #x-20B6F025)) T) (<= (#.(MAKE-SINGLE-FLOAT #x-20B6F025) #.(MAKE-SINGLE-FLOAT #x5F490FDB)) T) -(<= (#.(MAKE-SINGLE-FLOAT #x-139194D8) #x0) T) (<= (#.(MAKE-SINGLE-FLOAT #x-139194D8) #.(MAKE-SINGLE-FLOAT #x0)) T) (<= (#.(MAKE-SINGLE-FLOAT #x-139194D8) #.(MAKE-SINGLE-FLOAT #x6C6E6B28)) T) -(<= (#.(MAKE-SINGLE-FLOAT #x-129194D8) #x0) T) (<= (#.(MAKE-SINGLE-FLOAT #x-129194D8) #.(MAKE-SINGLE-FLOAT #x0)) T) (<= (#.(MAKE-SINGLE-FLOAT #x-129194D8) #.(MAKE-SINGLE-FLOAT #x6D6E6B28)) T) (<= (#.(MAKE-SINGLE-FLOAT #x-800001) #.(MAKE-SINGLE-FLOAT #x7F7FFFFF)) T) +(<= (#.(MAKE-SINGLE-FLOAT #x-800001) #.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF)) NIL) (<= (#.(MAKE-SINGLE-FLOAT #x0) #x3FFFFFF7) T) (<= (#.(MAKE-SINGLE-FLOAT #x0) #x1FFFFFFFFFFFFFF7) T) (<= (#.(MAKE-SINGLE-FLOAT #x0) #x7FFFFFFFFFFFFFF7) T) -(<= (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x-40804189)) NIL) +(<= (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x-80000000)) T) (<= (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x-40800000)) NIL) +(<= (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x-32000000)) NIL) (<= (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x-319194D8)) NIL) (<= (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x-31800000)) NIL) (<= (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x-231194D8)) NIL) +(<= (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x-22800000)) NIL) (<= (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x-22000000)) NIL) +(<= (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x-21800000)) NIL) (<= (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x-21000000)) NIL) (<= (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x-139194D8)) NIL) (<= (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x-129194D8)) NIL) @@ -936,20 +887,27 @@ (<= (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x3F7FFFEF)) T) (<= (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x3F800000)) T) (<= (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x40490FDB)) T) +(<= (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x4B7FFFFF)) T) +(<= (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x4DFFFFFF)) T) (<= (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x4E000000)) T) (<= (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x4E800000)) T) (<= (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x4EC90FDB)) T) +(<= (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x538637BD)) T) +(<= (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x540637BD)) T) (<= (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x5883126F)) T) (<= (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x5903126F)) T) +(<= (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x5D7FFFFF)) T) (<= (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x5D800000)) T) (<= (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x5E000000)) T) (<= (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x5E490FDB)) T) +(<= (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x5E7FFFFF)) T) (<= (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x5E800000)) T) (<= (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x5F000000)) T) (<= (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x5F490FDB)) T) (<= (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-DOUBLE-FLOAT #x-3C62329C #xFF1194D8)) NIL) (<= (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-DOUBLE-FLOAT #x-3A72329B #x0)) NIL) (<= (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-DOUBLE-FLOAT #x-3A52329B #x0)) NIL) +(<= (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) T) (<= (#.(MAKE-SINGLE-FLOAT #x3D800000) #.(MAKE-SINGLE-FLOAT #x0)) NIL) (<= (#.(MAKE-SINGLE-FLOAT #x3D800000) #.(MAKE-SINGLE-FLOAT #x3D800000)) T) (<= (#.(MAKE-SINGLE-FLOAT #x3D800000) #.(MAKE-SINGLE-FLOAT #x3F800000)) T) @@ -957,20 +915,38 @@ (<= (#.(MAKE-SINGLE-FLOAT #x3DCCCCCD) #.(MAKE-SINGLE-FLOAT #x3F800000)) T) (<= (#.(MAKE-SINGLE-FLOAT #x3F000000) #.(MAKE-SINGLE-FLOAT #x0)) NIL) (<= (#.(MAKE-SINGLE-FLOAT #x3F000000) #.(MAKE-SINGLE-FLOAT #x3F000000)) T) -(<= (#.(MAKE-SINGLE-FLOAT #x3F000000) #.(MAKE-SINGLE-FLOAT #x4E800000)) T) -(<= (#.(MAKE-SINGLE-FLOAT #x3F7FFFEF) #.(MAKE-SINGLE-FLOAT #x-80000000)) NIL) (<= (#.(MAKE-SINGLE-FLOAT #x3F7FFFEF) #.(MAKE-SINGLE-FLOAT #x3F7FFFEF)) T) +(<= (#.(MAKE-SINGLE-FLOAT #x3F800000) #x1FFFFFFC) T) +(<= (#.(MAKE-SINGLE-FLOAT #x3F800000) #xFFFFFFFFFFFFFFC) T) +(<= (#.(MAKE-SINGLE-FLOAT #x3F800000) #x3FFFFFFFFFFFFFFC) T) (<= (#.(MAKE-SINGLE-FLOAT #x3F800000) #.(MAKE-SINGLE-FLOAT #x-80000000)) NIL) (<= (#.(MAKE-SINGLE-FLOAT #x3F800000) #.(MAKE-SINGLE-FLOAT #x-40800000)) NIL) +(<= (#.(MAKE-SINGLE-FLOAT #x3F800000) #.(MAKE-SINGLE-FLOAT #x-32000000)) NIL) +(<= (#.(MAKE-SINGLE-FLOAT #x3F800000) #.(MAKE-SINGLE-FLOAT #x-22800000)) NIL) +(<= (#.(MAKE-SINGLE-FLOAT #x3F800000) #.(MAKE-SINGLE-FLOAT #x-21800000)) NIL) (<= (#.(MAKE-SINGLE-FLOAT #x3F800000) #.(MAKE-SINGLE-FLOAT #x0)) NIL) (<= (#.(MAKE-SINGLE-FLOAT #x3F800000) #.(MAKE-SINGLE-FLOAT #x3D800000)) NIL) (<= (#.(MAKE-SINGLE-FLOAT #x3F800000) #.(MAKE-SINGLE-FLOAT #x3F800000)) T) +(<= (#.(MAKE-SINGLE-FLOAT #x3F800000) #.(MAKE-SINGLE-FLOAT #x4DFFFFFF)) T) +(<= (#.(MAKE-SINGLE-FLOAT #x3F800000) #.(MAKE-SINGLE-FLOAT #x5D7FFFFF)) T) +(<= (#.(MAKE-SINGLE-FLOAT #x3F800000) #.(MAKE-SINGLE-FLOAT #x5E7FFFFF)) T) +(<= (#.(MAKE-SINGLE-FLOAT #x3F800000) #.(MAKE-DOUBLE-FLOAT #x-40100000 #x0)) NIL) +(<= (#.(MAKE-SINGLE-FLOAT #x3F800000) #.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0)) T) +(<= (#.(MAKE-SINGLE-FLOAT #x3FC90FDB) #.(MAKE-SINGLE-FLOAT #x3FC90FDB)) T) (<= (#.(MAKE-SINGLE-FLOAT #x40490FDB) #.(MAKE-SINGLE-FLOAT #x40490FDB)) T) (<= (#.(MAKE-SINGLE-FLOAT #x447A0000) #.(MAKE-SINGLE-FLOAT #x40000000)) NIL) +(<= (#.(MAKE-SINGLE-FLOAT #x49742400) #.(MAKE-SINGLE-FLOAT #x40000000)) NIL) +(<= (#.(MAKE-SINGLE-FLOAT #x4B7FFFFF) #.(MAKE-SINGLE-FLOAT #x-40800000)) NIL) +(<= (#.(MAKE-SINGLE-FLOAT #x4B7FFFFF) #.(MAKE-SINGLE-FLOAT #x0)) NIL) +(<= (#.(MAKE-SINGLE-FLOAT #x4B7FFFFF) #.(MAKE-SINGLE-FLOAT #x4B7FFFFF)) T) +(<= (#.(MAKE-SINGLE-FLOAT #x4B7FFFFF) #.(MAKE-SINGLE-FLOAT #x4DFFFFFF)) T) +(<= (#.(MAKE-SINGLE-FLOAT #x4B7FFFFF) #.(MAKE-SINGLE-FLOAT #x5D7FFFFF)) T) +(<= (#.(MAKE-SINGLE-FLOAT #x4B7FFFFF) #.(MAKE-SINGLE-FLOAT #x5E7FFFFF)) T) (<= (#.(MAKE-SINGLE-FLOAT #x4DFFFFFF) #x0) NIL) +(<= (#.(MAKE-SINGLE-FLOAT #x4DFFFFFF) #.(MAKE-SINGLE-FLOAT #x-40800000)) NIL) +(<= (#.(MAKE-SINGLE-FLOAT #x4DFFFFFF) #.(MAKE-SINGLE-FLOAT #x-32000000)) NIL) (<= (#.(MAKE-SINGLE-FLOAT #x4DFFFFFF) #.(MAKE-SINGLE-FLOAT #x0)) NIL) (<= (#.(MAKE-SINGLE-FLOAT #x4DFFFFFF) #.(MAKE-SINGLE-FLOAT #x4DFFFFFF)) T) -(<= (#.(MAKE-SINGLE-FLOAT #x4E000000) #x0) NIL) (<= (#.(MAKE-SINGLE-FLOAT #x4E000000) #.(MAKE-SINGLE-FLOAT #x-32000000)) NIL) (<= (#.(MAKE-SINGLE-FLOAT #x4E000000) #.(MAKE-SINGLE-FLOAT #x0)) NIL) (<= (#.(MAKE-SINGLE-FLOAT #x4E000000) #.(MAKE-SINGLE-FLOAT #x4E000000)) T) @@ -978,22 +954,24 @@ (<= (#.(MAKE-SINGLE-FLOAT #x4E6E6B28) #.(MAKE-SINGLE-FLOAT #x40000000)) NIL) (<= (#.(MAKE-SINGLE-FLOAT #x4E800000) #x0) NIL) (<= (#.(MAKE-SINGLE-FLOAT #x4E800000) #.(MAKE-SINGLE-FLOAT #x0)) NIL) -(<= (#.(MAKE-SINGLE-FLOAT #x4E800000) #.(MAKE-SINGLE-FLOAT #x3F000000)) NIL) (<= (#.(MAKE-SINGLE-FLOAT #x4E800000) #.(MAKE-SINGLE-FLOAT #x4E800000)) T) -(<= (#.(MAKE-SINGLE-FLOAT #x4EC00000) #x0) NIL) (<= (#.(MAKE-SINGLE-FLOAT #x4EC90FDB) #x0) NIL) (<= (#.(MAKE-SINGLE-FLOAT #x4EC90FDB) #.(MAKE-SINGLE-FLOAT #x3FC90FDB)) NIL) (<= (#.(MAKE-SINGLE-FLOAT #x4EC90FDB) #.(MAKE-SINGLE-FLOAT #x40490FDB)) NIL) (<= (#.(MAKE-SINGLE-FLOAT #x4EC90FDB) #.(MAKE-SINGLE-FLOAT #x4EC90FDB)) T) +(<= (#.(MAKE-SINGLE-FLOAT #x538637BD) #.(MAKE-SINGLE-FLOAT #x0)) NIL) +(<= (#.(MAKE-SINGLE-FLOAT #x538637BD) #.(MAKE-SINGLE-FLOAT #x538637BD)) T) +(<= (#.(MAKE-SINGLE-FLOAT #x540637BD) #.(MAKE-SINGLE-FLOAT #x540637BD)) T) (<= (#.(MAKE-SINGLE-FLOAT #x5883126F) #.(MAKE-SINGLE-FLOAT #x0)) NIL) (<= (#.(MAKE-SINGLE-FLOAT #x5883126F) #.(MAKE-SINGLE-FLOAT #x5883126F)) T) (<= (#.(MAKE-SINGLE-FLOAT #x5903126F) #.(MAKE-SINGLE-FLOAT #x5903126F)) T) -(<= (#.(MAKE-SINGLE-FLOAT #x5CEE6B28) #x0) NIL) (<= (#.(MAKE-SINGLE-FLOAT #x5CEE6B28) #.(MAKE-SINGLE-FLOAT #x-80000000)) NIL) (<= (#.(MAKE-SINGLE-FLOAT #x5CEE6B28) #.(MAKE-SINGLE-FLOAT #x5CEE6B28)) T) (<= (#.(MAKE-SINGLE-FLOAT #x5D7FFFFF) #x0) NIL) +(<= (#.(MAKE-SINGLE-FLOAT #x5D7FFFFF) #.(MAKE-SINGLE-FLOAT #x-40800000)) NIL) +(<= (#.(MAKE-SINGLE-FLOAT #x5D7FFFFF) #.(MAKE-SINGLE-FLOAT #x-22800000)) NIL) +(<= (#.(MAKE-SINGLE-FLOAT #x5D7FFFFF) #.(MAKE-SINGLE-FLOAT #x0)) NIL) (<= (#.(MAKE-SINGLE-FLOAT #x5D7FFFFF) #.(MAKE-SINGLE-FLOAT #x5D7FFFFF)) T) -(<= (#.(MAKE-SINGLE-FLOAT #x5D800000) #x0) NIL) (<= (#.(MAKE-SINGLE-FLOAT #x5D800000) #.(MAKE-SINGLE-FLOAT #x-22800000)) NIL) (<= (#.(MAKE-SINGLE-FLOAT #x5D800000) #.(MAKE-SINGLE-FLOAT #x0)) NIL) (<= (#.(MAKE-SINGLE-FLOAT #x5D800000) #.(MAKE-SINGLE-FLOAT #x5D800000)) T) @@ -1005,9 +983,10 @@ (<= (#.(MAKE-SINGLE-FLOAT #x5E490FDB) #.(MAKE-SINGLE-FLOAT #x40490FDB)) NIL) (<= (#.(MAKE-SINGLE-FLOAT #x5E490FDB) #.(MAKE-SINGLE-FLOAT #x5E490FDB)) T) (<= (#.(MAKE-SINGLE-FLOAT #x5E7FFFFF) #x0) NIL) +(<= (#.(MAKE-SINGLE-FLOAT #x5E7FFFFF) #.(MAKE-SINGLE-FLOAT #x-40800000)) NIL) +(<= (#.(MAKE-SINGLE-FLOAT #x5E7FFFFF) #.(MAKE-SINGLE-FLOAT #x-21800000)) NIL) (<= (#.(MAKE-SINGLE-FLOAT #x5E7FFFFF) #.(MAKE-SINGLE-FLOAT #x0)) NIL) (<= (#.(MAKE-SINGLE-FLOAT #x5E7FFFFF) #.(MAKE-SINGLE-FLOAT #x5E7FFFFF)) T) -(<= (#.(MAKE-SINGLE-FLOAT #x5E800000) #x0) NIL) (<= (#.(MAKE-SINGLE-FLOAT #x5E800000) #.(MAKE-SINGLE-FLOAT #x-21800000)) NIL) (<= (#.(MAKE-SINGLE-FLOAT #x5E800000) #.(MAKE-SINGLE-FLOAT #x0)) NIL) (<= (#.(MAKE-SINGLE-FLOAT #x5E800000) #.(MAKE-SINGLE-FLOAT #x5E800000)) T) @@ -1018,23 +997,38 @@ (<= (#.(MAKE-SINGLE-FLOAT #x5F490FDB) #.(MAKE-SINGLE-FLOAT #x3FC90FDB)) NIL) (<= (#.(MAKE-SINGLE-FLOAT #x5F490FDB) #.(MAKE-SINGLE-FLOAT #x40490FDB)) NIL) (<= (#.(MAKE-SINGLE-FLOAT #x5F490FDB) #.(MAKE-SINGLE-FLOAT #x5F490FDB)) T) -(<= (#.(MAKE-SINGLE-FLOAT #x6C6E6B28) #x0) NIL) (<= (#.(MAKE-SINGLE-FLOAT #x6C6E6B28) #.(MAKE-SINGLE-FLOAT #x-80000000)) NIL) (<= (#.(MAKE-SINGLE-FLOAT #x6C6E6B28) #.(MAKE-SINGLE-FLOAT #x6C6E6B28)) T) -(<= (#.(MAKE-SINGLE-FLOAT #x6D6E6B28) #x0) NIL) (<= (#.(MAKE-SINGLE-FLOAT #x6D6E6B28) #.(MAKE-SINGLE-FLOAT #x-80000000)) NIL) (<= (#.(MAKE-SINGLE-FLOAT #x6D6E6B28) #.(MAKE-SINGLE-FLOAT #x6D6E6B28)) T) (<= (#.(MAKE-SINGLE-FLOAT #x7F7FFFFF) #.(MAKE-SINGLE-FLOAT #x-800001)) NIL) (<= (#.(MAKE-SINGLE-FLOAT #x7F7FFFFF) #.(MAKE-SINGLE-FLOAT #x0)) NIL) +(<= (#.(MAKE-SINGLE-FLOAT #x7F7FFFFF) #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-80000000 #x0) #.(MAKE-DOUBLE-FLOAT #x-80000000 #x0)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-80000000 #x0) #.(MAKE-DOUBLE-FLOAT #x-40100000 #x0)) NIL) +(<= (#.(MAKE-DOUBLE-FLOAT #x-80000000 #x0) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-80000000 #x0) #.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0)) T) +(<= (#.(MAKE-DOUBLE-FLOAT #x-80000000 #x0) #.(MAKE-DOUBLE-FLOAT #x3FF921FB #x54442D18)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-80000000 #x0) #.(MAKE-DOUBLE-FLOAT #x400921FB #x54442D18)) T) +(<= (#.(MAKE-DOUBLE-FLOAT #x-80000000 #x0) #.(MAKE-DOUBLE-FLOAT #x40734413 #x509F79FF)) T) +(<= (#.(MAKE-DOUBLE-FLOAT #x-80000000 #x0) #.(MAKE-DOUBLE-FLOAT #x408628B7 #x6E3A7B61)) T) +(<= (#.(MAKE-DOUBLE-FLOAT #x-80000000 #x0) #.(MAKE-DOUBLE-FLOAT #x433FFFFF #xFFFFFFFF)) T) +(<= (#.(MAKE-DOUBLE-FLOAT #x-80000000 #x0) #.(MAKE-DOUBLE-FLOAT #x439DCD64 #xFF1194D8)) T) +(<= (#.(MAKE-DOUBLE-FLOAT #x-80000000 #x0) #.(MAKE-DOUBLE-FLOAT #x458DCD65 #x0)) T) +(<= (#.(MAKE-DOUBLE-FLOAT #x-80000000 #x0) #.(MAKE-DOUBLE-FLOAT #x45ADCD65 #x0)) T) +(<= (#.(MAKE-DOUBLE-FLOAT #x-80000000 #x0) #.(MAKE-DOUBLE-FLOAT #x5FEFFFFF #xFFFFFFFF)) T) +(<= (#.(MAKE-DOUBLE-FLOAT #x-40100000 #x0) #.(MAKE-SINGLE-FLOAT #x-40800000)) T) +(<= (#.(MAKE-DOUBLE-FLOAT #x-40100000 #x0) #.(MAKE-SINGLE-FLOAT #x3F800000)) T) +(<= (#.(MAKE-DOUBLE-FLOAT #x-40100000 #x0) #.(MAKE-DOUBLE-FLOAT #x-80000000 #x0)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-40100000 #x0) #.(MAKE-DOUBLE-FLOAT #x-40100000 #x0)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-40100000 #x0) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-40100000 #x0) #.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-40100000 #x0) #.(MAKE-DOUBLE-FLOAT #x40733000 #x0)) T) -(<= (#.(MAKE-DOUBLE-FLOAT #x-40100000 #x0) #.(MAKE-DOUBLE-FLOAT #x408D6000 #x0)) T) +(<= (#.(MAKE-DOUBLE-FLOAT #x-40100000 #x0) #.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFF000000)) T) +(<= (#.(MAKE-DOUBLE-FLOAT #x-40100000 #x0) #.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFFFFFFFF)) T) +(<= (#.(MAKE-DOUBLE-FLOAT #x-40100000 #x0) #.(MAKE-DOUBLE-FLOAT #x433FFFFF #xFFFFFFFF)) T) +(<= (#.(MAKE-DOUBLE-FLOAT #x-40100000 #x0) #.(MAKE-DOUBLE-FLOAT #x43AFFFFF #xFFFFFFFF)) T) +(<= (#.(MAKE-DOUBLE-FLOAT #x-40100000 #x0) #.(MAKE-DOUBLE-FLOAT #x43CFFFFF #xFFFFFFFF)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-4006DE05 #x54442D18) #.(MAKE-DOUBLE-FLOAT #x-3FF6DE05 #x54442D18)) NIL) (<= (#.(MAKE-DOUBLE-FLOAT #x-4006DE05 #x54442D18) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-4006DE05 #x54442D18) #.(MAKE-DOUBLE-FLOAT #x3FF921FB #x54442D18)) T) @@ -1047,41 +1041,29 @@ (<= (#.(MAKE-DOUBLE-FLOAT #x-3FF6DE05 #x54442D18) #.(MAKE-DOUBLE-FLOAT #x3FF921FB #x54442D18)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-3FF6DE05 #x54442D18) #.(MAKE-DOUBLE-FLOAT #x400921FB #x54442D18)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-3FD20000 #x0) #.(MAKE-DOUBLE-FLOAT #x40733000 #x0)) T) -(<= (#.(MAKE-DOUBLE-FLOAT #x-3FD20000 #x0) #.(MAKE-DOUBLE-FLOAT #x408D6000 #x0)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-3F8CB000 #x0) #.(MAKE-DOUBLE-FLOAT #x40742000 #x0)) T) -(<= (#.(MAKE-DOUBLE-FLOAT #x-3F8BCB1A #x420F4374) #x0) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-3F8BCB1A #x420F4374) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-3F8BCB1A #x420F4374) #.(MAKE-DOUBLE-FLOAT #x40734413 #x509F79FF)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-3F8BC000 #x0) #.(MAKE-DOUBLE-FLOAT #x40733000 #x0)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-3F7C458D #x2107A1BA) #.(MAKE-DOUBLE-FLOAT #x4083BA09 #xA84FBD00)) T) -(<= (#.(MAKE-DOUBLE-FLOAT #x-3F7C3D8D #x2107A1BA) #.(MAKE-DOUBLE-FLOAT #x4083C209 #xA84FBD00)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-3F78B6F0 #xD52D3052) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-3F78B6F0 #xD52D3052) #.(MAKE-DOUBLE-FLOAT #x408628B7 #x6E3A7B61)) T) -(<= (#.(MAKE-DOUBLE-FLOAT #x-3F729000 #x0) #.(MAKE-DOUBLE-FLOAT #x408DD800 #x0)) T) -(<= (#.(MAKE-DOUBLE-FLOAT #x-3F72231A #x420F4374) #x0) T) -(<= (#.(MAKE-DOUBLE-FLOAT #x-3F72231A #x420F4374) #.(MAKE-DOUBLE-FLOAT #x408D6413 #x509F7A00)) T) -(<= (#.(MAKE-DOUBLE-FLOAT #x-3F721800 #x0) #.(MAKE-DOUBLE-FLOAT #x408D6000 #x0)) T) -(<= (#.(MAKE-DOUBLE-FLOAT #x-3F6C3EC7 #x9083D0DD) #.(MAKE-DOUBLE-FLOAT #x4093C104 #xD427DE80)) T) +(<= (#.(MAKE-DOUBLE-FLOAT #x-3F722B1A #x420F4374) #.(MAKE-DOUBLE-FLOAT #x408D5C13 #x509F7A00)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0) #x0) T) +(<= (#.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0) #.(MAKE-DOUBLE-FLOAT #x-40100000 #x0)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0) #.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0)) T) -(<= (#.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0) #.(MAKE-DOUBLE-FLOAT #x-3E400000 #x800000)) NIL) +(<= (#.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0) #.(MAKE-DOUBLE-FLOAT #x-3CC00000 #x0)) NIL) (<= (#.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) T) +(<= (#.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0) #.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0)) T) +(<= (#.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0) #.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xE0000000)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0) #.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFF000000)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0) #.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFFFFFFFF)) T) -(<= (#.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0) #.(MAKE-DOUBLE-FLOAT #x41C00000 #x0)) T) -(<= (#.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0) #.(MAKE-DOUBLE-FLOAT #x41DFFFFF #xFFC00000)) T) -(<= (#.(MAKE-DOUBLE-FLOAT #x-3E400000 #x800000) #.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0)) T) -(<= (#.(MAKE-DOUBLE-FLOAT #x-3E400000 #x800000) #.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFFFFFFFF)) T) -(<= (#.(MAKE-DOUBLE-FLOAT #x-3E400000 #x800000) #.(MAKE-DOUBLE-FLOAT #x41C00000 #x0)) T) -(<= (#.(MAKE-DOUBLE-FLOAT #x-3E300001 #xFF800000) #.(MAKE-DOUBLE-FLOAT #x-3E300000 #x0)) NIL) -(<= (#.(MAKE-DOUBLE-FLOAT #x-3E300001 #xFF800000) #.(MAKE-DOUBLE-FLOAT #x41CFFFFF #xFF800000)) T) +(<= (#.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0) #.(MAKE-DOUBLE-FLOAT #x433FFFFF #xFFFFFFFF)) T) +(<= (#.(MAKE-DOUBLE-FLOAT #x-3E300001 #xFF000000) #.(MAKE-DOUBLE-FLOAT #x41D00000 #x400000)) T) +(<= (#.(MAKE-DOUBLE-FLOAT #x-3E300001 #xFF800000) #.(MAKE-DOUBLE-FLOAT #x-3E300001 #xFF000000)) T) +(<= (#.(MAKE-DOUBLE-FLOAT #x-3E300001 #xFF800000) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-3E300001 #xFF800000) #.(MAKE-DOUBLE-FLOAT #x41D00000 #x0)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-3E300001 #xFF800000) #.(MAKE-DOUBLE-FLOAT #x41D00000 #x400000)) T) -(<= (#.(MAKE-DOUBLE-FLOAT #x-3E300000 #x0) #x0) T) -(<= (#.(MAKE-DOUBLE-FLOAT #x-3E300000 #x0) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) T) -(<= (#.(MAKE-DOUBLE-FLOAT #x-3E300000 #x0) #.(MAKE-DOUBLE-FLOAT #x41D00000 #x0)) T) -(<= (#.(MAKE-DOUBLE-FLOAT #x-3E280001 #xFFC00000) #x0) T) -(<= (#.(MAKE-DOUBLE-FLOAT #x-3E280001 #xFFC00000) #.(MAKE-DOUBLE-FLOAT #x41D7FFFF #xFF800000)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-3E26DE05 #x537B1D3D) #x0) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-3E26DE05 #x537B1D3D) #.(MAKE-DOUBLE-FLOAT #x-3E26DE05 #x54442D18)) NIL) (<= (#.(MAKE-DOUBLE-FLOAT #x-3E26DE05 #x537B1D3D) #.(MAKE-DOUBLE-FLOAT #x41D921FB #x537B1D3D)) T) @@ -1091,13 +1073,22 @@ (<= (#.(MAKE-DOUBLE-FLOAT #x-3E26DE05 #x54442D18) #.(MAKE-DOUBLE-FLOAT #x41D921FB #x537B1D3D)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-3E26DE05 #x54442D18) #.(MAKE-DOUBLE-FLOAT #x41D921FB #x54442D18)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-3E26DE05 #x60000000) #.(MAKE-DOUBLE-FLOAT #x41D921FB #x60000000)) T) -(<= (#.(MAKE-DOUBLE-FLOAT #x-3C62329C #xFF1194D8) #x0) T) +(<= (#.(MAKE-DOUBLE-FLOAT #x-3CC00000 #x0) #.(MAKE-DOUBLE-FLOAT #x-40100000 #x0)) T) +(<= (#.(MAKE-DOUBLE-FLOAT #x-3CC00000 #x0) #.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0)) T) +(<= (#.(MAKE-DOUBLE-FLOAT #x-3CC00000 #x0) #.(MAKE-DOUBLE-FLOAT #x-3CC00000 #x0)) T) +(<= (#.(MAKE-DOUBLE-FLOAT #x-3CC00000 #x0) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) T) +(<= (#.(MAKE-DOUBLE-FLOAT #x-3CC00000 #x0) #.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFFFFFFFF)) T) +(<= (#.(MAKE-DOUBLE-FLOAT #x-3CC00000 #x0) #.(MAKE-DOUBLE-FLOAT #x433FFFFF #xFFFFFFFF)) T) +(<= (#.(MAKE-DOUBLE-FLOAT #x-3CC00000 #x0) #.(MAKE-DOUBLE-FLOAT #x43AFFFFF #xFFFFFFFF)) T) +(<= (#.(MAKE-DOUBLE-FLOAT #x-3CC00000 #x0) #.(MAKE-DOUBLE-FLOAT #x43CFFFFF #xFFFFFFFF)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-3C62329C #xFF1194D8) #.(MAKE-SINGLE-FLOAT #x0)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-3C62329C #xFF1194D8) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-3C62329C #xFF1194D8) #.(MAKE-DOUBLE-FLOAT #x439DCD64 #xFF1194D8)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-3C500000 #x0) #x0) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-3C500000 #x0) #.(MAKE-DOUBLE-FLOAT #x-3C500000 #x0)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-3C500000 #x0) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) T) +(<= (#.(MAKE-DOUBLE-FLOAT #x-3C500000 #x0) #.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0)) T) +(<= (#.(MAKE-DOUBLE-FLOAT #x-3C500000 #x0) #.(MAKE-DOUBLE-FLOAT #x433FFFFF #xFFFFFFFF)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-3C500000 #x0) #.(MAKE-DOUBLE-FLOAT #x43AFFFFF #xFFFFFFFF)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-3C500000 #x0) #.(MAKE-DOUBLE-FLOAT #x43B00000 #x0)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-3C400000 #x0) #x0) T) @@ -1110,6 +1101,8 @@ (<= (#.(MAKE-DOUBLE-FLOAT #x-3C300000 #x0) #x0) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-3C300000 #x0) #.(MAKE-DOUBLE-FLOAT #x-3C300000 #x0)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-3C300000 #x0) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) T) +(<= (#.(MAKE-DOUBLE-FLOAT #x-3C300000 #x0) #.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0)) T) +(<= (#.(MAKE-DOUBLE-FLOAT #x-3C300000 #x0) #.(MAKE-DOUBLE-FLOAT #x433FFFFF #xFFFFFFFF)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-3C300000 #x0) #.(MAKE-DOUBLE-FLOAT #x43CFFFFF #xFFFFFFFF)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-3C300000 #x0) #.(MAKE-DOUBLE-FLOAT #x43D00000 #x0)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-3C200000 #x0) #x0) T) @@ -1119,27 +1112,28 @@ (<= (#.(MAKE-DOUBLE-FLOAT #x-3C16DE05 #x54442D18) #.(MAKE-DOUBLE-FLOAT #x-3C16DE05 #x54442D18)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-3C16DE05 #x54442D18) #.(MAKE-DOUBLE-FLOAT #x43E921FB #x54442D18)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-3C16DE05 #x60000000) #.(MAKE-DOUBLE-FLOAT #x43E921FB #x60000000)) T) -(<= (#.(MAKE-DOUBLE-FLOAT #x-3A72329B #x0) #x0) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-3A72329B #x0) #.(MAKE-SINGLE-FLOAT #x0)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-3A72329B #x0) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-3A72329B #x0) #.(MAKE-DOUBLE-FLOAT #x458DCD65 #x0)) T) -(<= (#.(MAKE-DOUBLE-FLOAT #x-3A52329B #x0) #x0) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-3A52329B #x0) #.(MAKE-SINGLE-FLOAT #x0)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-3A52329B #x0) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-3A52329B #x0) #.(MAKE-DOUBLE-FLOAT #x45ADCD65 #x0)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-500001 #xFFFFFFFE) #x0) T) +(<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #.(MAKE-SINGLE-FLOAT #x-800001)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #x0) T) (<= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #x1FFFFFFF) T) (<= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #xFFFFFFFFFFFFFFF) T) (<= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #x3FFFFFFFFFFFFFFF) T) +(<= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-SINGLE-FLOAT #x0)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x-80000000 #x0)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x-40100000 #x0)) NIL) (<= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x-4006DE05 #x54442D18)) NIL) (<= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x-3F8BCB1A #x420F4374)) NIL) (<= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x-3F78B6F0 #xD52D3052)) NIL) (<= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0)) NIL) -(<= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x-3E300000 #x0)) NIL) +(<= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x-3E300001 #xFF800000)) NIL) +(<= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x-3CC00000 #x0)) NIL) (<= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x-3C62329C #xFF1194D8)) NIL) (<= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x-3C500000 #x0)) NIL) (<= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x-3C400000 #x0)) NIL) @@ -1157,18 +1151,21 @@ (<= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x3FF921FB #x54442D18)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x400921FB #x54442D18)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x40742000 #x0)) T) -(<= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x4083C273 #x2107A1BA)) T) -(<= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x408DD800 #x0)) T) +(<= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x4083BA73 #x2107A1BA)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFF000000)) T) +(<= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFFFFFFFF)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x41C00000 #x0)) T) -(<= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x41CFFFFF #xFF800000)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x41D00000 #x0)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x41D00000 #x400000)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x41D921FB #x54442D18)) T) +(<= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x4270C6F7 #xA0B5E000)) T) +(<= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x4310624D #xD2F1A9F8)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x433FFFFF #xFFFFFFFF)) T) +(<= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x43AFFFFF #xFFFFFFFF)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x43B00000 #x0)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x43C00000 #x0)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x43C921FB #x54442D18)) T) +(<= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x43CFFFFF #xFFFFFFFF)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x43D00000 #x0)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x43E00000 #x0)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x43E921FB #x54442D18)) T) @@ -1177,15 +1174,22 @@ (<= (#.(MAKE-DOUBLE-FLOAT #x3FB99999 #x9999999A) #.(MAKE-DOUBLE-FLOAT #x3FB99999 #x9999999A)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x3FE00000 #x0) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) NIL) (<= (#.(MAKE-DOUBLE-FLOAT #x3FE00000 #x0) #.(MAKE-DOUBLE-FLOAT #x3FE00000 #x0)) T) -(<= (#.(MAKE-DOUBLE-FLOAT #x3FE00000 #x0) #.(MAKE-DOUBLE-FLOAT #x4083C273 #x2107A1BA)) T) -(<= (#.(MAKE-DOUBLE-FLOAT #x3FE00000 #x0) #.(MAKE-DOUBLE-FLOAT #x41CFFFFF #xFF800000)) T) +(<= (#.(MAKE-DOUBLE-FLOAT #x3FE00000 #x0) #.(MAKE-DOUBLE-FLOAT #x4083BA73 #x2107A1BA)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x3FE6A09E #x667F3BCD) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) NIL) (<= (#.(MAKE-DOUBLE-FLOAT #x3FEFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x3FEFFFFF #xFFFFFFFF)) T) +(<= (#.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0) #.(MAKE-SINGLE-FLOAT #x-40800000)) NIL) +(<= (#.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0) #.(MAKE-SINGLE-FLOAT #x3F800000)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0) #.(MAKE-DOUBLE-FLOAT #x-80000000 #x0)) NIL) (<= (#.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0) #.(MAKE-DOUBLE-FLOAT #x-40100000 #x0)) NIL) +(<= (#.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0) #.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0)) NIL) +(<= (#.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0) #.(MAKE-DOUBLE-FLOAT #x-3C500000 #x0)) NIL) +(<= (#.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0) #.(MAKE-DOUBLE-FLOAT #x-3C300000 #x0)) NIL) (<= (#.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) NIL) (<= (#.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0) #.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0)) T) +(<= (#.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0) #.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFF000000)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0) #.(MAKE-DOUBLE-FLOAT #x41C00000 #x0)) T) +(<= (#.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0) #.(MAKE-DOUBLE-FLOAT #x43AFFFFF #xFFFFFFFF)) T) +(<= (#.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0) #.(MAKE-DOUBLE-FLOAT #x43CFFFFF #xFFFFFFFF)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0) #.(MAKE-DOUBLE-FLOAT #x5FCFFFFF #xFFFFFFFF)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x3FF33333 #x33333333) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) NIL) (<= (#.(MAKE-DOUBLE-FLOAT #x3FF33333 #x33333333) #.(MAKE-DOUBLE-FLOAT #x3FE6A09E #x667F3BCD)) NIL) @@ -1213,51 +1217,43 @@ (<= (#.(MAKE-DOUBLE-FLOAT #x404A8000 #x0) #.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xE0000000)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x404A8000 #x0) #.(MAKE-DOUBLE-FLOAT #x43D00000 #x0)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x406633CE #x8FB9F87D) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) NIL) -(<= (#.(MAKE-DOUBLE-FLOAT #x406633CE #x8FB9F87E) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) NIL) (<= (#.(MAKE-DOUBLE-FLOAT #x40733000 #x0) #.(MAKE-DOUBLE-FLOAT #x40733000 #x0)) T) -(<= (#.(MAKE-DOUBLE-FLOAT #x40734413 #x509F79FF) #x0) NIL) (<= (#.(MAKE-DOUBLE-FLOAT #x40734413 #x509F79FF) #.(MAKE-DOUBLE-FLOAT #x-80000000 #x0)) NIL) (<= (#.(MAKE-DOUBLE-FLOAT #x40734413 #x509F79FF) #.(MAKE-DOUBLE-FLOAT #x40734413 #x509F79FF)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x40742000 #x0) #.(MAKE-DOUBLE-FLOAT #x40742000 #x0)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x4083BA09 #xA84FBD00) #.(MAKE-DOUBLE-FLOAT #x4083BA09 #xA84FBD00)) T) -(<= (#.(MAKE-DOUBLE-FLOAT #x4083C209 #xA84FBD00) #.(MAKE-DOUBLE-FLOAT #x4083C209 #xA84FBD00)) T) -(<= (#.(MAKE-DOUBLE-FLOAT #x4083C209 #xA84FBD00) #.(MAKE-DOUBLE-FLOAT #x4083C273 #x2107A1BA)) T) -(<= (#.(MAKE-DOUBLE-FLOAT #x4083C273 #x2107A1BA) #.(MAKE-DOUBLE-FLOAT #x3FE00000 #x0)) NIL) -(<= (#.(MAKE-DOUBLE-FLOAT #x4083C273 #x2107A1BA) #.(MAKE-DOUBLE-FLOAT #x4083C209 #xA84FBD00)) NIL) +(<= (#.(MAKE-DOUBLE-FLOAT #x4083BA09 #xA84FBD00) #.(MAKE-DOUBLE-FLOAT #x4083BA73 #x2107A1BA)) T) +(<= (#.(MAKE-DOUBLE-FLOAT #x4083BA73 #x2107A1BA) #.(MAKE-DOUBLE-FLOAT #x3FE00000 #x0)) NIL) +(<= (#.(MAKE-DOUBLE-FLOAT #x4083BA73 #x2107A1BA) #.(MAKE-DOUBLE-FLOAT #x4083BA09 #xA84FBD00)) NIL) +(<= (#.(MAKE-DOUBLE-FLOAT #x4083BA73 #x2107A1BA) #.(MAKE-DOUBLE-FLOAT #x4083BA73 #x2107A1BA)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x408628B7 #x6E3A7B61) #.(MAKE-DOUBLE-FLOAT #x-80000000 #x0)) NIL) (<= (#.(MAKE-DOUBLE-FLOAT #x408628B7 #x6E3A7B61) #.(MAKE-DOUBLE-FLOAT #x408628B7 #x6E3A7B61)) T) -(<= (#.(MAKE-DOUBLE-FLOAT #x408D6000 #x0) #.(MAKE-DOUBLE-FLOAT #x408D6000 #x0)) T) -(<= (#.(MAKE-DOUBLE-FLOAT #x408D6413 #x509F7A00) #x0) NIL) -(<= (#.(MAKE-DOUBLE-FLOAT #x408D6413 #x509F7A00) #.(MAKE-DOUBLE-FLOAT #x408D6413 #x509F7A00)) T) -(<= (#.(MAKE-DOUBLE-FLOAT #x408DD800 #x0) #.(MAKE-DOUBLE-FLOAT #x408DD800 #x0)) T) -(<= (#.(MAKE-DOUBLE-FLOAT #x4093C104 #xD427DE80) #.(MAKE-DOUBLE-FLOAT #x4093C104 #xD427DE80)) T) +(<= (#.(MAKE-DOUBLE-FLOAT #x408D5C13 #x509F7A00) #.(MAKE-DOUBLE-FLOAT #x408D5C13 #x509F7A00)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xE0000000) #.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xE0000000)) T) -(<= (#.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFF000000) #x0) NIL) +(<= (#.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFF000000) #.(MAKE-DOUBLE-FLOAT #x-40100000 #x0)) NIL) (<= (#.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFF000000) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) NIL) (<= (#.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFF000000) #.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFF000000)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFF000000) #.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFFFFFFFF)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFF000000) #.(MAKE-DOUBLE-FLOAT #x41C00000 #x0)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFFFFFFFF) #x0) NIL) +(<= (#.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x-40100000 #x0)) NIL) +(<= (#.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0)) NIL) +(<= (#.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x-3CC00000 #x0)) NIL) (<= (#.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) NIL) (<= (#.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFF000000)) NIL) (<= (#.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFFFFFFFF)) T) -(<= (#.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x41C00000 #x0)) T) +(<= (#.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x433FFFFF #xFFFFFFFF)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x41C00000 #x0) #.(MAKE-DOUBLE-FLOAT #x-3E400000 #x800000)) NIL) (<= (#.(MAKE-DOUBLE-FLOAT #x41C00000 #x0) #.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFF000000)) NIL) -(<= (#.(MAKE-DOUBLE-FLOAT #x41C00000 #x0) #.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFFFFFFFF)) NIL) (<= (#.(MAKE-DOUBLE-FLOAT #x41C00000 #x0) #.(MAKE-DOUBLE-FLOAT #x41C00000 #x0)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x41C00000 #x800000) #.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0)) NIL) (<= (#.(MAKE-DOUBLE-FLOAT #x41CDCD65 #x0) #.(MAKE-DOUBLE-FLOAT #x40000000 #x0)) NIL) -(<= (#.(MAKE-DOUBLE-FLOAT #x41CFFFFF #xFF800000) #.(MAKE-DOUBLE-FLOAT #x3FE00000 #x0)) NIL) -(<= (#.(MAKE-DOUBLE-FLOAT #x41CFFFFF #xFF800000) #.(MAKE-DOUBLE-FLOAT #x41CFFFFF #xFF800000)) T) -(<= (#.(MAKE-DOUBLE-FLOAT #x41D00000 #x0) #x0) NIL) (<= (#.(MAKE-DOUBLE-FLOAT #x41D00000 #x0) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) NIL) (<= (#.(MAKE-DOUBLE-FLOAT #x41D00000 #x0) #.(MAKE-DOUBLE-FLOAT #x41D00000 #x0)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x41D00000 #x0) #.(MAKE-DOUBLE-FLOAT #x41D00000 #x400000)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x41D00000 #x400000) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) NIL) (<= (#.(MAKE-DOUBLE-FLOAT #x41D00000 #x400000) #.(MAKE-DOUBLE-FLOAT #x41D00000 #x0)) NIL) (<= (#.(MAKE-DOUBLE-FLOAT #x41D00000 #x400000) #.(MAKE-DOUBLE-FLOAT #x41D00000 #x400000)) T) -(<= (#.(MAKE-DOUBLE-FLOAT #x41D7FFFF #xFF800000) #x0) NIL) (<= (#.(MAKE-DOUBLE-FLOAT #x41D921FB #x537B1D3D) #x0) NIL) (<= (#.(MAKE-DOUBLE-FLOAT #x41D921FB #x537B1D3D) #.(MAKE-DOUBLE-FLOAT #x41D921FB #x54442D18)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x41D921FB #x54442D18) #x0) NIL) @@ -1266,18 +1262,25 @@ (<= (#.(MAKE-DOUBLE-FLOAT #x41D921FB #x54442D18) #.(MAKE-DOUBLE-FLOAT #x41D921FB #x537B1D3D)) NIL) (<= (#.(MAKE-DOUBLE-FLOAT #x41D921FB #x54442D18) #.(MAKE-DOUBLE-FLOAT #x41D921FB #x54442D18)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x41D921FB #x60000000) #.(MAKE-DOUBLE-FLOAT #x41D921FB #x60000000)) T) -(<= (#.(MAKE-DOUBLE-FLOAT #x41DFFFFF #xFFC00000) #.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFF000000)) NIL) +(<= (#.(MAKE-DOUBLE-FLOAT #x4270C6F7 #xA0B5E000) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) NIL) +(<= (#.(MAKE-DOUBLE-FLOAT #x4270C6F7 #xA0B5E000) #.(MAKE-DOUBLE-FLOAT #x4270C6F7 #xA0B5E000)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x4310624D #xD2F1A9F8) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) NIL) (<= (#.(MAKE-DOUBLE-FLOAT #x4310624D #xD2F1A9F8) #.(MAKE-DOUBLE-FLOAT #x4310624D #xD2F1A9F8)) T) +(<= (#.(MAKE-DOUBLE-FLOAT #x433FFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x-40100000 #x0)) NIL) +(<= (#.(MAKE-DOUBLE-FLOAT #x433FFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0)) NIL) +(<= (#.(MAKE-DOUBLE-FLOAT #x433FFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) NIL) +(<= (#.(MAKE-DOUBLE-FLOAT #x433FFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFFFFFFFF)) NIL) (<= (#.(MAKE-DOUBLE-FLOAT #x433FFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x433FFFFF #xFFFFFFFF)) T) +(<= (#.(MAKE-DOUBLE-FLOAT #x433FFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x43AFFFFF #xFFFFFFFF)) T) +(<= (#.(MAKE-DOUBLE-FLOAT #x433FFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x43CFFFFF #xFFFFFFFF)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x4341C379 #x37E08000) #.(MAKE-DOUBLE-FLOAT #x40000000 #x0)) NIL) -(<= (#.(MAKE-DOUBLE-FLOAT #x439DCD64 #xFF1194D8) #x0) NIL) (<= (#.(MAKE-DOUBLE-FLOAT #x439DCD64 #xFF1194D8) #.(MAKE-SINGLE-FLOAT #x-80000000)) NIL) (<= (#.(MAKE-DOUBLE-FLOAT #x439DCD64 #xFF1194D8) #.(MAKE-DOUBLE-FLOAT #x-80000000 #x0)) NIL) (<= (#.(MAKE-DOUBLE-FLOAT #x439DCD64 #xFF1194D8) #.(MAKE-DOUBLE-FLOAT #x439DCD64 #xFF1194D8)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x43AFFFFF #xFFFFFFFF) #x0) NIL) +(<= (#.(MAKE-DOUBLE-FLOAT #x43AFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x-40100000 #x0)) NIL) +(<= (#.(MAKE-DOUBLE-FLOAT #x43AFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x-3C500000 #x0)) NIL) (<= (#.(MAKE-DOUBLE-FLOAT #x43AFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x43AFFFFF #xFFFFFFFF)) T) -(<= (#.(MAKE-DOUBLE-FLOAT #x43B00000 #x0) #x0) NIL) (<= (#.(MAKE-DOUBLE-FLOAT #x43B00000 #x0) #.(MAKE-DOUBLE-FLOAT #x-3C500000 #x0)) NIL) (<= (#.(MAKE-DOUBLE-FLOAT #x43B00000 #x0) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) NIL) (<= (#.(MAKE-DOUBLE-FLOAT #x43B00000 #x0) #.(MAKE-DOUBLE-FLOAT #x43B00000 #x0)) T) @@ -1290,9 +1293,10 @@ (<= (#.(MAKE-DOUBLE-FLOAT #x43C921FB #x54442D18) #.(MAKE-DOUBLE-FLOAT #x43C921FB #x54442D18)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x43C921FB #x60000000) #.(MAKE-DOUBLE-FLOAT #x43C921FB #x60000000)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x43CFFFFF #xFFFFFFFF) #x0) NIL) +(<= (#.(MAKE-DOUBLE-FLOAT #x43CFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x-40100000 #x0)) NIL) +(<= (#.(MAKE-DOUBLE-FLOAT #x43CFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x-3C300000 #x0)) NIL) (<= (#.(MAKE-DOUBLE-FLOAT #x43CFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) NIL) (<= (#.(MAKE-DOUBLE-FLOAT #x43CFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x43CFFFFF #xFFFFFFFF)) T) -(<= (#.(MAKE-DOUBLE-FLOAT #x43D00000 #x0) #x0) NIL) (<= (#.(MAKE-DOUBLE-FLOAT #x43D00000 #x0) #.(MAKE-DOUBLE-FLOAT #x-3C300000 #x0)) NIL) (<= (#.(MAKE-DOUBLE-FLOAT #x43D00000 #x0) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) NIL) (<= (#.(MAKE-DOUBLE-FLOAT #x43D00000 #x0) #.(MAKE-DOUBLE-FLOAT #x43D00000 #x0)) T) @@ -1304,32 +1308,30 @@ (<= (#.(MAKE-DOUBLE-FLOAT #x43E921FB #x54442D18) #.(MAKE-DOUBLE-FLOAT #x400921FB #x54442D18)) NIL) (<= (#.(MAKE-DOUBLE-FLOAT #x43E921FB #x54442D18) #.(MAKE-DOUBLE-FLOAT #x43E921FB #x54442D18)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x43E921FB #x60000000) #.(MAKE-DOUBLE-FLOAT #x43E921FB #x60000000)) T) -(<= (#.(MAKE-DOUBLE-FLOAT #x458DCD65 #x0) #x0) NIL) (<= (#.(MAKE-DOUBLE-FLOAT #x458DCD65 #x0) #.(MAKE-SINGLE-FLOAT #x-80000000)) NIL) (<= (#.(MAKE-DOUBLE-FLOAT #x458DCD65 #x0) #.(MAKE-DOUBLE-FLOAT #x-80000000 #x0)) NIL) (<= (#.(MAKE-DOUBLE-FLOAT #x458DCD65 #x0) #.(MAKE-DOUBLE-FLOAT #x458DCD65 #x0)) T) -(<= (#.(MAKE-DOUBLE-FLOAT #x45ADCD65 #x0) #x0) NIL) (<= (#.(MAKE-DOUBLE-FLOAT #x45ADCD65 #x0) #.(MAKE-SINGLE-FLOAT #x-80000000)) NIL) (<= (#.(MAKE-DOUBLE-FLOAT #x45ADCD65 #x0) #.(MAKE-DOUBLE-FLOAT #x-80000000 #x0)) NIL) (<= (#.(MAKE-DOUBLE-FLOAT #x45ADCD65 #x0) #.(MAKE-DOUBLE-FLOAT #x45ADCD65 #x0)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x5FCFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) NIL) (<= (#.(MAKE-DOUBLE-FLOAT #x5FCFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0)) NIL) (<= (#.(MAKE-DOUBLE-FLOAT #x5FCFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x5FCFFFFF #xFFFFFFFF)) T) +(<= (#.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF) #.(MAKE-SINGLE-FLOAT #x7F7FFFFF)) NIL) (<= (#.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x-80000000 #x0)) NIL) (<= (#.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF)) NIL) (<= (#.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) NIL) -(<= (#.(MAKE-SINGLE-FLOAT #x-800001) #x-20000000 #.(MAKE-SINGLE-FLOAT #x7F7FFFFF)) T) (<= (#.(MAKE-SINGLE-FLOAT #x-800001) #x-1 #.(MAKE-SINGLE-FLOAT #x7F7FFFFF)) T) (<= (#.(MAKE-SINGLE-FLOAT #x-800001) #x0 #.(MAKE-SINGLE-FLOAT #x7F7FFFFF)) T) (<= (#.(MAKE-SINGLE-FLOAT #x-800001) #x1 #.(MAKE-SINGLE-FLOAT #x7F7FFFFF)) T) -(<= (#.(MAKE-SINGLE-FLOAT #x-800001) #x3 #.(MAKE-SINGLE-FLOAT #x7F7FFFFF)) T) (<= (#.(MAKE-SINGLE-FLOAT #x-800001) #x64 #.(MAKE-SINGLE-FLOAT #x7F7FFFFF)) T) (<= (#.(MAKE-SINGLE-FLOAT #x-800001) #x3E8 #.(MAKE-SINGLE-FLOAT #x7F7FFFFF)) T) -(<= (#.(MAKE-SINGLE-FLOAT #x-800001) #xF3E58 #.(MAKE-SINGLE-FLOAT #x7F7FFFFF)) T) (<= (#.(MAKE-SINGLE-FLOAT #x-800001) #xF423F #.(MAKE-SINGLE-FLOAT #x7F7FFFFF)) T) +(<= (#.(MAKE-SINGLE-FLOAT #x-800001) #xF4240 #.(MAKE-SINGLE-FLOAT #x7F7FFFFF)) T) (<= (#.(MAKE-SINGLE-FLOAT #x-800001) #x1FFFFFFF #.(MAKE-SINGLE-FLOAT #x7F7FFFFF)) T) (<= (#.(MAKE-SINGLE-FLOAT #x-800001) #x20000000 #.(MAKE-SINGLE-FLOAT #x7F7FFFFF)) T) (<= (#.(MAKE-SINGLE-FLOAT #x-800001) #xFFFFFFFF #.(MAKE-SINGLE-FLOAT #x7F7FFFFF)) T) +(<= (#.(MAKE-SINGLE-FLOAT #x-800001) #x218DEF416BD #.(MAKE-SINGLE-FLOAT #x7F7FFFFF)) T) (<= (#.(MAKE-SINGLE-FLOAT #x-800001) #x83126E978D4FD #.(MAKE-SINGLE-FLOAT #x7F7FFFFF)) T) (<= (#.(MAKE-SINGLE-FLOAT #x-800001) #xFFFFFFFFFFFFFFF #.(MAKE-SINGLE-FLOAT #x7F7FFFFF)) T) (<= (#.(MAKE-SINGLE-FLOAT #x-800001) #x1000000000000000 #.(MAKE-SINGLE-FLOAT #x7F7FFFFF)) T) @@ -1337,15 +1339,13 @@ (<= (#.(MAKE-SINGLE-FLOAT #x-800001) #x4000000000000000 #.(MAKE-SINGLE-FLOAT #x7F7FFFFF)) T) (<= (#.(MAKE-SINGLE-FLOAT #x-800001) #xFFFFFFFFFFFFFFFF #.(MAKE-SINGLE-FLOAT #x7F7FFFFF)) T) (<= (#.(MAKE-SINGLE-FLOAT #x-800001) #.(MAKE-SINGLE-FLOAT #x-80000000) #.(MAKE-SINGLE-FLOAT #x7F7FFFFF)) T) -(<= (#.(MAKE-SINGLE-FLOAT #x-800001) #.(MAKE-SINGLE-FLOAT #x-40804189) #.(MAKE-SINGLE-FLOAT #x7F7FFFFF)) T) (<= (#.(MAKE-SINGLE-FLOAT #x-800001) #.(MAKE-SINGLE-FLOAT #x-40800000) #.(MAKE-SINGLE-FLOAT #x7F7FFFFF)) T) (<= (#.(MAKE-SINGLE-FLOAT #x-800001) #.(MAKE-SINGLE-FLOAT #x-4036F025) #.(MAKE-SINGLE-FLOAT #x7F7FFFFF)) T) (<= (#.(MAKE-SINGLE-FLOAT #x-800001) #.(MAKE-SINGLE-FLOAT #x-3FB6F025) #.(MAKE-SINGLE-FLOAT #x7F7FFFFF)) T) (<= (#.(MAKE-SINGLE-FLOAT #x-800001) #.(MAKE-SINGLE-FLOAT #x-3D380000) #.(MAKE-SINGLE-FLOAT #x7F7FFFFF)) T) -(<= (#.(MAKE-SINGLE-FLOAT #x-800001) #.(MAKE-SINGLE-FLOAT #x-368C1A80) #.(MAKE-SINGLE-FLOAT #x7F7FFFFF)) T) +(<= (#.(MAKE-SINGLE-FLOAT #x-800001) #.(MAKE-SINGLE-FLOAT #x-34800000) #.(MAKE-SINGLE-FLOAT #x7F7FFFFF)) T) (<= (#.(MAKE-SINGLE-FLOAT #x-800001) #.(MAKE-SINGLE-FLOAT #x-32000000) #.(MAKE-SINGLE-FLOAT #x7F7FFFFF)) T) (<= (#.(MAKE-SINGLE-FLOAT #x-800001) #.(MAKE-SINGLE-FLOAT #x-31800000) #.(MAKE-SINGLE-FLOAT #x7F7FFFFF)) T) -(<= (#.(MAKE-SINGLE-FLOAT #x-800001) #.(MAKE-SINGLE-FLOAT #x-31400000) #.(MAKE-SINGLE-FLOAT #x7F7FFFFF)) T) (<= (#.(MAKE-SINGLE-FLOAT #x-800001) #.(MAKE-SINGLE-FLOAT #x-3136F025) #.(MAKE-SINGLE-FLOAT #x7F7FFFFF)) T) (<= (#.(MAKE-SINGLE-FLOAT #x-800001) #.(MAKE-SINGLE-FLOAT #x-31000000) #.(MAKE-SINGLE-FLOAT #x7F7FFFFF)) T) (<= (#.(MAKE-SINGLE-FLOAT #x-800001) #.(MAKE-SINGLE-FLOAT #x-231194D8) #.(MAKE-SINGLE-FLOAT #x7F7FFFFF)) T) @@ -1358,39 +1358,32 @@ (<= (#.(MAKE-SINGLE-FLOAT #x-800001) #.(MAKE-SINGLE-FLOAT #x-139194D8) #.(MAKE-SINGLE-FLOAT #x7F7FFFFF)) T) (<= (#.(MAKE-SINGLE-FLOAT #x-800001) #.(MAKE-SINGLE-FLOAT #x-129194D8) #.(MAKE-SINGLE-FLOAT #x7F7FFFFF)) T) (<= (#.(MAKE-SINGLE-FLOAT #x-800001) #.(MAKE-SINGLE-FLOAT #x-800001) #.(MAKE-SINGLE-FLOAT #x7F7FFFFF)) T) -(<= (#.(MAKE-SINGLE-FLOAT #x-800001) #.(MAKE-SINGLE-FLOAT #x-800000) #.(MAKE-SINGLE-FLOAT #x7F7FFFFF)) NIL) (<= (#.(MAKE-SINGLE-FLOAT #x-800001) #.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x7F7FFFFF)) T) (<= (#.(MAKE-SINGLE-FLOAT #x-800001) #.(MAKE-SINGLE-FLOAT #x3089705F) #.(MAKE-SINGLE-FLOAT #x7F7FFFFF)) T) +(<= (#.(MAKE-SINGLE-FLOAT #x-800001) #.(MAKE-SINGLE-FLOAT #x358637BD) #.(MAKE-SINGLE-FLOAT #x7F7FFFFF)) T) (<= (#.(MAKE-SINGLE-FLOAT #x-800001) #.(MAKE-SINGLE-FLOAT #x3A83126F) #.(MAKE-SINGLE-FLOAT #x7F7FFFFF)) T) (<= (#.(MAKE-SINGLE-FLOAT #x-800001) #.(MAKE-SINGLE-FLOAT #x3D800000) #.(MAKE-SINGLE-FLOAT #x7F7FFFFF)) T) (<= (#.(MAKE-SINGLE-FLOAT #x-800001) #.(MAKE-SINGLE-FLOAT #x3F000000) #.(MAKE-SINGLE-FLOAT #x7F7FFFFF)) T) -(<= (#.(MAKE-SINGLE-FLOAT #x-800001) #.(MAKE-SINGLE-FLOAT #x3F0CCCCD) #.(MAKE-SINGLE-FLOAT #x7F7FFFFF)) T) -(<= (#.(MAKE-SINGLE-FLOAT #x-800001) #.(MAKE-SINGLE-FLOAT #x3F19999A) #.(MAKE-SINGLE-FLOAT #x7F7FFFFF)) T) -(<= (#.(MAKE-SINGLE-FLOAT #x-800001) #.(MAKE-SINGLE-FLOAT #x3F266666) #.(MAKE-SINGLE-FLOAT #x7F7FFFFF)) T) -(<= (#.(MAKE-SINGLE-FLOAT #x-800001) #.(MAKE-SINGLE-FLOAT #x3F59999A) #.(MAKE-SINGLE-FLOAT #x7F7FFFFF)) T) -(<= (#.(MAKE-SINGLE-FLOAT #x-800001) #.(MAKE-SINGLE-FLOAT #x3F666666) #.(MAKE-SINGLE-FLOAT #x7F7FFFFF)) T) (<= (#.(MAKE-SINGLE-FLOAT #x-800001) #.(MAKE-SINGLE-FLOAT #x3F7FFFEF) #.(MAKE-SINGLE-FLOAT #x7F7FFFFF)) T) (<= (#.(MAKE-SINGLE-FLOAT #x-800001) #.(MAKE-SINGLE-FLOAT #x3F800000) #.(MAKE-SINGLE-FLOAT #x7F7FFFFF)) T) (<= (#.(MAKE-SINGLE-FLOAT #x-800001) #.(MAKE-SINGLE-FLOAT #x3F8CCCCD) #.(MAKE-SINGLE-FLOAT #x7F7FFFFF)) T) (<= (#.(MAKE-SINGLE-FLOAT #x-800001) #.(MAKE-SINGLE-FLOAT #x3FC00000) #.(MAKE-SINGLE-FLOAT #x7F7FFFFF)) T) (<= (#.(MAKE-SINGLE-FLOAT #x-800001) #.(MAKE-SINGLE-FLOAT #x3FC90FDB) #.(MAKE-SINGLE-FLOAT #x7F7FFFFF)) T) (<= (#.(MAKE-SINGLE-FLOAT #x-800001) #.(MAKE-SINGLE-FLOAT #x40000000) #.(MAKE-SINGLE-FLOAT #x7F7FFFFF)) T) -(<= (#.(MAKE-SINGLE-FLOAT #x-800001) #.(MAKE-SINGLE-FLOAT #x40400000) #.(MAKE-SINGLE-FLOAT #x7F7FFFFF)) T) (<= (#.(MAKE-SINGLE-FLOAT #x-800001) #.(MAKE-SINGLE-FLOAT #x40490FDB) #.(MAKE-SINGLE-FLOAT #x7F7FFFFF)) T) -(<= (#.(MAKE-SINGLE-FLOAT #x-800001) #.(MAKE-SINGLE-FLOAT #x41600000) #.(MAKE-SINGLE-FLOAT #x7F7FFFFF)) T) (<= (#.(MAKE-SINGLE-FLOAT #x-800001) #.(MAKE-SINGLE-FLOAT #x447A0000) #.(MAKE-SINGLE-FLOAT #x7F7FFFFF)) T) (<= (#.(MAKE-SINGLE-FLOAT #x-800001) #.(MAKE-SINGLE-FLOAT #x497423F0) #.(MAKE-SINGLE-FLOAT #x7F7FFFFF)) T) (<= (#.(MAKE-SINGLE-FLOAT #x-800001) #.(MAKE-SINGLE-FLOAT #x49742400) #.(MAKE-SINGLE-FLOAT #x7F7FFFFF)) T) -(<= (#.(MAKE-SINGLE-FLOAT #x-800001) #.(MAKE-SINGLE-FLOAT #x4B800000) #.(MAKE-SINGLE-FLOAT #x7F7FFFFF)) T) -(<= (#.(MAKE-SINGLE-FLOAT #x-800001) #.(MAKE-SINGLE-FLOAT #x4D800000) #.(MAKE-SINGLE-FLOAT #x7F7FFFFF)) T) +(<= (#.(MAKE-SINGLE-FLOAT #x-800001) #.(MAKE-SINGLE-FLOAT #x4B7FFFFF) #.(MAKE-SINGLE-FLOAT #x7F7FFFFF)) T) (<= (#.(MAKE-SINGLE-FLOAT #x-800001) #.(MAKE-SINGLE-FLOAT #x4DFFFFFF) #.(MAKE-SINGLE-FLOAT #x7F7FFFFF)) T) (<= (#.(MAKE-SINGLE-FLOAT #x-800001) #.(MAKE-SINGLE-FLOAT #x4E000000) #.(MAKE-SINGLE-FLOAT #x7F7FFFFF)) T) (<= (#.(MAKE-SINGLE-FLOAT #x-800001) #.(MAKE-SINGLE-FLOAT #x4E6E6B28) #.(MAKE-SINGLE-FLOAT #x7F7FFFFF)) T) (<= (#.(MAKE-SINGLE-FLOAT #x-800001) #.(MAKE-SINGLE-FLOAT #x4E800000) #.(MAKE-SINGLE-FLOAT #x7F7FFFFF)) T) -(<= (#.(MAKE-SINGLE-FLOAT #x-800001) #.(MAKE-SINGLE-FLOAT #x4EC00000) #.(MAKE-SINGLE-FLOAT #x7F7FFFFF)) T) (<= (#.(MAKE-SINGLE-FLOAT #x-800001) #.(MAKE-SINGLE-FLOAT #x4EC90FDB) #.(MAKE-SINGLE-FLOAT #x7F7FFFFF)) T) (<= (#.(MAKE-SINGLE-FLOAT #x-800001) #.(MAKE-SINGLE-FLOAT #x4F000000) #.(MAKE-SINGLE-FLOAT #x7F7FFFFF)) T) (<= (#.(MAKE-SINGLE-FLOAT #x-800001) #.(MAKE-SINGLE-FLOAT #x4F800000) #.(MAKE-SINGLE-FLOAT #x7F7FFFFF)) T) +(<= (#.(MAKE-SINGLE-FLOAT #x-800001) #.(MAKE-SINGLE-FLOAT #x538637BD) #.(MAKE-SINGLE-FLOAT #x7F7FFFFF)) T) +(<= (#.(MAKE-SINGLE-FLOAT #x-800001) #.(MAKE-SINGLE-FLOAT #x540637BD) #.(MAKE-SINGLE-FLOAT #x7F7FFFFF)) T) (<= (#.(MAKE-SINGLE-FLOAT #x-800001) #.(MAKE-SINGLE-FLOAT #x5883126F) #.(MAKE-SINGLE-FLOAT #x7F7FFFFF)) T) (<= (#.(MAKE-SINGLE-FLOAT #x-800001) #.(MAKE-SINGLE-FLOAT #x5903126F) #.(MAKE-SINGLE-FLOAT #x7F7FFFFF)) T) (<= (#.(MAKE-SINGLE-FLOAT #x-800001) #.(MAKE-SINGLE-FLOAT #x5CEE6B28) #.(MAKE-SINGLE-FLOAT #x7F7FFFFF)) T) @@ -1406,22 +1399,18 @@ (<= (#.(MAKE-SINGLE-FLOAT #x-800001) #.(MAKE-SINGLE-FLOAT #x6C6E6B28) #.(MAKE-SINGLE-FLOAT #x7F7FFFFF)) T) (<= (#.(MAKE-SINGLE-FLOAT #x-800001) #.(MAKE-SINGLE-FLOAT #x6D6E6B28) #.(MAKE-SINGLE-FLOAT #x7F7FFFFF)) T) (<= (#.(MAKE-SINGLE-FLOAT #x-800001) #.(MAKE-SINGLE-FLOAT #x7F7FFFFF) #.(MAKE-SINGLE-FLOAT #x7F7FFFFF)) T) -(<= (#.(MAKE-SINGLE-FLOAT #x-800001) #.(MAKE-SINGLE-FLOAT #x7F800000) #.(MAKE-SINGLE-FLOAT #x7F7FFFFF)) NIL) -(<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #x-3BC #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) -(<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #x-144 #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #x-143 #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #x0 #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #x1 #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #x2 #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #x64 #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #x134 #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) -(<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #x135 #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) -(<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #x3AD #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #x3E8 #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #x3FF #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #x400 #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #x432 #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #x433 #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) +(<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #xF4240 #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #x1FFFFFFF #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #x20000000 #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #xFFFFFFFFFFFFFFF #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) @@ -1443,24 +1432,19 @@ (<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x-3F8BCB1A #x420F4374) #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x-3F8BC000 #x0) #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x-3F7C458D #x2107A1BA) #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) -(<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x-3F7C3D8D #x2107A1BA) #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x-3F78B6F0 #xD52D3052) #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) -(<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x-3F729000 #x0) #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) -(<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x-3F72231A #x420F4374) #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) -(<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x-3F722000 #x0) #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) -(<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x-3F721800 #x0) #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) +(<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x-3F722B1A #x420F4374) #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x-3F6F3800 #x0) #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x-3F6F3400 #x0) #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) -(<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x-3F6C3EC7 #x9083D0DD) #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x-3E400001 #xFF000000) #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0) #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x-3E400000 #x800000) #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) +(<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x-3E300001 #xFF000000) #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x-3E300001 #xFF800000) #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) -(<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x-3E300000 #x0) #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) -(<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x-3E280001 #xFFC00000) #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x-3E26DE05 #x54442D18) #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x-3E26DE05 #x60000000) #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x-3E200000 #x0) #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) +(<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x-3CC00000 #x0) #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x-3C62329C #xFF1194D8) #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x-3C500000 #x0) #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x-3C400000 #x0) #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) @@ -1495,55 +1479,49 @@ (<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x3FF921FB #x54442D18) #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x3FFB504F #x333F9DE6) #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x40000000 #x0) #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) -(<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x4005BF0A #x8B145769) #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x40080000 #x0) #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x400921FB #x54442D18) #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x40100000 #x0) #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x40240000 #x0) #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x404A8000 #x0) #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x406633CE #x8FB9F87D) #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) -(<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x406633CE #x8FB9F87E) #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x40733000 #x0) #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x40734000 #x0) #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x40734413 #x509F79FF) #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) -(<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x40735000 #x0) #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x40742000 #x0) #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x4083BA09 #xA84FBD00) #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) -(<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x4083C209 #xA84FBD00) #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) -(<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x4083C273 #x2107A1BA) #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) +(<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x4083BA73 #x2107A1BA) #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x408628B7 #x6E3A7B61) #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) -(<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x408D6000 #x0) #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) -(<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x408D6413 #x509F7A00) #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) -(<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x408D6800 #x0) #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) -(<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x408DD800 #x0) #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) +(<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x408D5C13 #x509F7A00) #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x408FF800 #x0) #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x40900000 #x0) #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) -(<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x4093C104 #xD427DE80) #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xE0000000) #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFF000000) #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x41C00000 #x0) #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x41C00000 #x800000) #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x41CDCD65 #x0) #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) -(<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x41CFFFFF #xFF800000) #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x41D00000 #x0) #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x41D00000 #x400000) #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) -(<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x41D7FFFF #xFF800000) #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x41D921FB #x54442D18) #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x41D921FB #x60000000) #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x41DFFFFF #xFFC00000) #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x41E00000 #x0) #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x41EFFFFF #xFFE00000) #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) +(<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x4270C6F7 #xA0B5E000) #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x4310624D #xD2F1A9F8) #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x433FFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x4341C379 #x37E08000) #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x439DCD64 #xFF1194D8) #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) +(<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x43AFFFFF #xE0000000) #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) +(<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x43AFFFFF #xFFFFE627) #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x43AFFFFF #xFFFFFFF8) #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x43AFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x43B00000 #x0) #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x43C00000 #x0) #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x43C921FB #x54442D18) #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x43C921FB #x60000000) #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) +(<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x43CFFFFF #xE0000000) #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x43CFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x43D00000 #x0) #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) (<= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x43E00000 #x0) #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) T) @@ -1562,142 +1540,164 @@ (= (#x-20000001 #.(MAKE-DOUBLE-FLOAT #x0 #x0)) NIL) (= (#x-20000000 #.(MAKE-DOUBLE-FLOAT #x0 #x0)) NIL) (= (#x-1 #.(MAKE-SINGLE-FLOAT #x0)) NIL) -(= (#x0 #.(MAKE-SINGLE-FLOAT #x-80000000)) T) (= (#x0 #.(MAKE-SINGLE-FLOAT #x-32000000)) NIL) (= (#x0 #.(MAKE-SINGLE-FLOAT #x-31800000)) NIL) -(= (#x0 #.(MAKE-SINGLE-FLOAT #x-31400000)) NIL) (= (#x0 #.(MAKE-SINGLE-FLOAT #x-3136F025)) NIL) -(= (#x0 #.(MAKE-SINGLE-FLOAT #x-231194D8)) NIL) (= (#x0 #.(MAKE-SINGLE-FLOAT #x-22800000)) NIL) (= (#x0 #.(MAKE-SINGLE-FLOAT #x-22000000)) NIL) (= (#x0 #.(MAKE-SINGLE-FLOAT #x-21B6F025)) NIL) (= (#x0 #.(MAKE-SINGLE-FLOAT #x-21800000)) NIL) (= (#x0 #.(MAKE-SINGLE-FLOAT #x-21000000)) NIL) (= (#x0 #.(MAKE-SINGLE-FLOAT #x-20B6F025)) NIL) -(= (#x0 #.(MAKE-SINGLE-FLOAT #x-139194D8)) NIL) -(= (#x0 #.(MAKE-SINGLE-FLOAT #x-129194D8)) NIL) (= (#x0 #.(MAKE-SINGLE-FLOAT #x0)) T) +(= (#x0 #.(MAKE-SINGLE-FLOAT #x3F800000)) NIL) (= (#x0 #.(MAKE-SINGLE-FLOAT #x4E800000)) NIL) (= (#x0 #.(MAKE-SINGLE-FLOAT #x5E000000)) NIL) (= (#x0 #.(MAKE-SINGLE-FLOAT #x5F000000)) NIL) (= (#x0 #.(MAKE-DOUBLE-FLOAT #x-80000000 #x0)) T) -(= (#x0 #.(MAKE-DOUBLE-FLOAT #x-3F8BCB1A #x420F4374)) NIL) -(= (#x0 #.(MAKE-DOUBLE-FLOAT #x-3F72231A #x420F4374)) NIL) (= (#x0 #.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0)) NIL) -(= (#x0 #.(MAKE-DOUBLE-FLOAT #x-3E300000 #x0)) NIL) -(= (#x0 #.(MAKE-DOUBLE-FLOAT #x-3E280001 #xFFC00000)) NIL) (= (#x0 #.(MAKE-DOUBLE-FLOAT #x-3E26DE05 #x537B1D3D)) NIL) (= (#x0 #.(MAKE-DOUBLE-FLOAT #x-3E26DE05 #x54442D18)) NIL) -(= (#x0 #.(MAKE-DOUBLE-FLOAT #x-3C62329C #xFF1194D8)) NIL) (= (#x0 #.(MAKE-DOUBLE-FLOAT #x-3C500000 #x0)) NIL) (= (#x0 #.(MAKE-DOUBLE-FLOAT #x-3C400000 #x0)) NIL) (= (#x0 #.(MAKE-DOUBLE-FLOAT #x-3C36DE05 #x54442D18)) NIL) (= (#x0 #.(MAKE-DOUBLE-FLOAT #x-3C300000 #x0)) NIL) (= (#x0 #.(MAKE-DOUBLE-FLOAT #x-3C200000 #x0)) NIL) (= (#x0 #.(MAKE-DOUBLE-FLOAT #x-3C16DE05 #x54442D18)) NIL) -(= (#x0 #.(MAKE-DOUBLE-FLOAT #x-3A72329B #x0)) NIL) -(= (#x0 #.(MAKE-DOUBLE-FLOAT #x-3A52329B #x0)) NIL) (= (#x0 #.(MAKE-DOUBLE-FLOAT #x-500001 #xFFFFFFFE)) NIL) (= (#x0 #.(MAKE-DOUBLE-FLOAT #x0 #x0)) T) -(= (#x0 #.(MAKE-DOUBLE-FLOAT #x41D00000 #x0)) NIL) (= (#x0 #.(MAKE-DOUBLE-FLOAT #x43C00000 #x0)) NIL) (= (#x0 #.(MAKE-DOUBLE-FLOAT #x43E00000 #x0)) NIL) (= (#x1 #.(MAKE-SINGLE-FLOAT #x0)) NIL) (= (#x1 #.(MAKE-DOUBLE-FLOAT #x0 #x0)) NIL) +(= (#x1FFFFFFC #.(MAKE-SINGLE-FLOAT #x3F800000)) NIL) (= (#x1FFFFFFF #.(MAKE-DOUBLE-FLOAT #x0 #x0)) NIL) (= (#x20000000 #.(MAKE-DOUBLE-FLOAT #x0 #x0)) NIL) (= (#x20000001 #.(MAKE-DOUBLE-FLOAT #x0 #x0)) NIL) (= (#x3FFFFFF7 #.(MAKE-SINGLE-FLOAT #x0)) NIL) +(= (#xFFFFFFFFFFFFFFC #.(MAKE-SINGLE-FLOAT #x3F800000)) NIL) (= (#xFFFFFFFFFFFFFFF #.(MAKE-DOUBLE-FLOAT #x0 #x0)) NIL) (= (#x1000000000000000 #.(MAKE-DOUBLE-FLOAT #x0 #x0)) NIL) (= (#x1000000000000001 #.(MAKE-DOUBLE-FLOAT #x0 #x0)) NIL) (= (#x1FFFFFFFFFFFFFF7 #.(MAKE-SINGLE-FLOAT #x0)) NIL) +(= (#x3FFFFFFFFFFFFFFC #.(MAKE-SINGLE-FLOAT #x3F800000)) NIL) (= (#x3FFFFFFFFFFFFFFF #.(MAKE-DOUBLE-FLOAT #x0 #x0)) NIL) (= (#x4000000000000000 #.(MAKE-DOUBLE-FLOAT #x0 #x0)) NIL) (= (#x4000000000000001 #.(MAKE-DOUBLE-FLOAT #x0 #x0)) NIL) (= (#x7FFFFFFFFFFFFFF7 #.(MAKE-SINGLE-FLOAT #x0)) NIL) -(= (#.(MAKE-SINGLE-FLOAT #x-80000000) #x0) T) -(= (#.(MAKE-SINGLE-FLOAT #x-80000000) #.(MAKE-DOUBLE-FLOAT #x-80000000 #x0)) T) +(= (#.(MAKE-SINGLE-FLOAT #x-80000000) #.(MAKE-SINGLE-FLOAT #x-80000000)) T) +(= (#.(MAKE-SINGLE-FLOAT #x-80000000) #.(MAKE-SINGLE-FLOAT #x0)) T) (= (#.(MAKE-SINGLE-FLOAT #x-40800000) #.(MAKE-SINGLE-FLOAT #x-40800000)) T) +(= (#.(MAKE-SINGLE-FLOAT #x-40800000) #.(MAKE-SINGLE-FLOAT #x0)) NIL) (= (#.(MAKE-SINGLE-FLOAT #x-40800000) #.(MAKE-SINGLE-FLOAT #x3F800000)) NIL) (= (#.(MAKE-SINGLE-FLOAT #x-40800000) #.(MAKE-DOUBLE-FLOAT #x-40100000 #x0)) T) (= (#.(MAKE-SINGLE-FLOAT #x-32000000) #.(MAKE-SINGLE-FLOAT #x-32000000)) T) +(= (#.(MAKE-SINGLE-FLOAT #x-32000000) #.(MAKE-SINGLE-FLOAT #x4DFFFFFF)) NIL) (= (#.(MAKE-SINGLE-FLOAT #x-3136F025) #.(MAKE-SINGLE-FLOAT #x-3136F025)) T) (= (#.(MAKE-SINGLE-FLOAT #x-22800000) #.(MAKE-SINGLE-FLOAT #x-22800000)) T) +(= (#.(MAKE-SINGLE-FLOAT #x-22800000) #.(MAKE-SINGLE-FLOAT #x5D7FFFFF)) NIL) (= (#.(MAKE-SINGLE-FLOAT #x-21B6F025) #.(MAKE-SINGLE-FLOAT #x-21B6F025)) T) (= (#.(MAKE-SINGLE-FLOAT #x-21800000) #.(MAKE-SINGLE-FLOAT #x-21800000)) T) +(= (#.(MAKE-SINGLE-FLOAT #x-21800000) #.(MAKE-SINGLE-FLOAT #x5E7FFFFF)) NIL) (= (#.(MAKE-SINGLE-FLOAT #x-20B6F025) #.(MAKE-SINGLE-FLOAT #x-20B6F025)) T) +(= (#.(MAKE-SINGLE-FLOAT #x-800001) #.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF)) NIL) (= (#.(MAKE-SINGLE-FLOAT #x0) #x-1) NIL) (= (#.(MAKE-SINGLE-FLOAT #x0) #x0) T) (= (#.(MAKE-SINGLE-FLOAT #x0) #x3FFFFFF7) NIL) (= (#.(MAKE-SINGLE-FLOAT #x0) #x1FFFFFFFFFFFFFF7) NIL) (= (#.(MAKE-SINGLE-FLOAT #x0) #x7FFFFFFFFFFFFFF7) NIL) (= (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x-80000000)) T) +(= (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x-40800000)) NIL) +(= (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x-32000000)) NIL) +(= (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x-319194D8)) NIL) (= (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x-31800000)) NIL) +(= (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x-231194D8)) NIL) +(= (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x-22800000)) NIL) (= (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x-22000000)) NIL) +(= (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x-21800000)) NIL) (= (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x-21000000)) NIL) +(= (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x-139194D8)) NIL) +(= (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x-129194D8)) NIL) (= (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x0)) T) (= (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x3F800000)) NIL) +(= (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x4DFFFFFF)) NIL) (= (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x4E800000)) NIL) +(= (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x5D7FFFFF)) NIL) (= (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x5E000000)) NIL) +(= (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x5E7FFFFF)) NIL) (= (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x5F000000)) NIL) (= (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-DOUBLE-FLOAT #x-80000000 #x0)) T) +(= (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-DOUBLE-FLOAT #x-3C62329C #xFF1194D8)) NIL) +(= (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-DOUBLE-FLOAT #x-3A72329B #x0)) NIL) +(= (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-DOUBLE-FLOAT #x-3A52329B #x0)) NIL) (= (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) T) (= (#.(MAKE-SINGLE-FLOAT #x3D800000) #.(MAKE-SINGLE-FLOAT #x0)) NIL) (= (#.(MAKE-SINGLE-FLOAT #x3D800000) #.(MAKE-SINGLE-FLOAT #x3D800000)) T) (= (#.(MAKE-SINGLE-FLOAT #x3D800000) #.(MAKE-SINGLE-FLOAT #x3F800000)) NIL) (= (#.(MAKE-SINGLE-FLOAT #x3F000000) #.(MAKE-SINGLE-FLOAT #x0)) NIL) (= (#.(MAKE-SINGLE-FLOAT #x3F000000) #.(MAKE-SINGLE-FLOAT #x3F000000)) T) -(= (#.(MAKE-SINGLE-FLOAT #x3F000000) #.(MAKE-SINGLE-FLOAT #x4E800000)) NIL) +(= (#.(MAKE-SINGLE-FLOAT #x3F800000) #x0) NIL) +(= (#.(MAKE-SINGLE-FLOAT #x3F800000) #x1FFFFFFC) NIL) +(= (#.(MAKE-SINGLE-FLOAT #x3F800000) #xFFFFFFFFFFFFFFC) NIL) +(= (#.(MAKE-SINGLE-FLOAT #x3F800000) #x3FFFFFFFFFFFFFFC) NIL) (= (#.(MAKE-SINGLE-FLOAT #x3F800000) #.(MAKE-SINGLE-FLOAT #x-40800000)) NIL) (= (#.(MAKE-SINGLE-FLOAT #x3F800000) #.(MAKE-SINGLE-FLOAT #x0)) NIL) (= (#.(MAKE-SINGLE-FLOAT #x3F800000) #.(MAKE-SINGLE-FLOAT #x3F800000)) T) +(= (#.(MAKE-SINGLE-FLOAT #x3F800000) #.(MAKE-DOUBLE-FLOAT #x-40100000 #x0)) NIL) (= (#.(MAKE-SINGLE-FLOAT #x3F800000) #.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0)) T) (= (#.(MAKE-SINGLE-FLOAT #x4DFFFFFF) #.(MAKE-SINGLE-FLOAT #x-32000000)) NIL) +(= (#.(MAKE-SINGLE-FLOAT #x4DFFFFFF) #.(MAKE-SINGLE-FLOAT #x0)) NIL) (= (#.(MAKE-SINGLE-FLOAT #x4DFFFFFF) #.(MAKE-SINGLE-FLOAT #x4DFFFFFF)) T) -(= (#.(MAKE-SINGLE-FLOAT #x4E000000) #x0) NIL) (= (#.(MAKE-SINGLE-FLOAT #x4E000000) #.(MAKE-SINGLE-FLOAT #x4E000000)) T) -(= (#.(MAKE-SINGLE-FLOAT #x4E800000) #x0) NIL) -(= (#.(MAKE-SINGLE-FLOAT #x4E800000) #.(MAKE-SINGLE-FLOAT #x4E800000)) T) (= (#.(MAKE-SINGLE-FLOAT #x4EC90FDB) #.(MAKE-SINGLE-FLOAT #x-3136F025)) NIL) (= (#.(MAKE-SINGLE-FLOAT #x4EC90FDB) #.(MAKE-SINGLE-FLOAT #x4EC90FDB)) T) +(= (#.(MAKE-SINGLE-FLOAT #x538637BD) #.(MAKE-SINGLE-FLOAT #x0)) NIL) +(= (#.(MAKE-SINGLE-FLOAT #x538637BD) #.(MAKE-SINGLE-FLOAT #x538637BD)) T) (= (#.(MAKE-SINGLE-FLOAT #x5883126F) #.(MAKE-SINGLE-FLOAT #x0)) NIL) (= (#.(MAKE-SINGLE-FLOAT #x5883126F) #.(MAKE-SINGLE-FLOAT #x5883126F)) T) (= (#.(MAKE-SINGLE-FLOAT #x5D7FFFFF) #.(MAKE-SINGLE-FLOAT #x-22800000)) NIL) +(= (#.(MAKE-SINGLE-FLOAT #x5D7FFFFF) #.(MAKE-SINGLE-FLOAT #x0)) NIL) (= (#.(MAKE-SINGLE-FLOAT #x5D7FFFFF) #.(MAKE-SINGLE-FLOAT #x5D7FFFFF)) T) -(= (#.(MAKE-SINGLE-FLOAT #x5D800000) #x0) NIL) (= (#.(MAKE-SINGLE-FLOAT #x5D800000) #.(MAKE-SINGLE-FLOAT #x5D800000)) T) (= (#.(MAKE-SINGLE-FLOAT #x5E490FDB) #.(MAKE-SINGLE-FLOAT #x-21B6F025)) NIL) (= (#.(MAKE-SINGLE-FLOAT #x5E490FDB) #.(MAKE-SINGLE-FLOAT #x5E490FDB)) T) (= (#.(MAKE-SINGLE-FLOAT #x5E7FFFFF) #.(MAKE-SINGLE-FLOAT #x-21800000)) NIL) +(= (#.(MAKE-SINGLE-FLOAT #x5E7FFFFF) #.(MAKE-SINGLE-FLOAT #x0)) NIL) (= (#.(MAKE-SINGLE-FLOAT #x5E7FFFFF) #.(MAKE-SINGLE-FLOAT #x5E7FFFFF)) T) -(= (#.(MAKE-SINGLE-FLOAT #x5E800000) #x0) NIL) (= (#.(MAKE-SINGLE-FLOAT #x5E800000) #.(MAKE-SINGLE-FLOAT #x5E800000)) T) (= (#.(MAKE-SINGLE-FLOAT #x5F490FDB) #.(MAKE-SINGLE-FLOAT #x-20B6F025)) NIL) (= (#.(MAKE-SINGLE-FLOAT #x5F490FDB) #.(MAKE-SINGLE-FLOAT #x5F490FDB)) T) +(= (#.(MAKE-SINGLE-FLOAT #x7F7FFFFF) #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) NIL) (= (#.(MAKE-DOUBLE-FLOAT #x-80000000 #x0) #x0) T) -(= (#.(MAKE-DOUBLE-FLOAT #x-80000000 #x0) #.(MAKE-SINGLE-FLOAT #x-80000000)) T) +(= (#.(MAKE-DOUBLE-FLOAT #x-80000000 #x0) #.(MAKE-SINGLE-FLOAT #x0)) T) +(= (#.(MAKE-DOUBLE-FLOAT #x-80000000 #x0) #.(MAKE-DOUBLE-FLOAT #x-80000000 #x0)) T) +(= (#.(MAKE-DOUBLE-FLOAT #x-80000000 #x0) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) T) (= (#.(MAKE-DOUBLE-FLOAT #x-80000000 #x0) #.(MAKE-DOUBLE-FLOAT #x20100000 #x1)) NIL) (= (#.(MAKE-DOUBLE-FLOAT #x-80000000 #x0) #.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0)) NIL) (= (#.(MAKE-DOUBLE-FLOAT #x-80000000 #x0) #.(MAKE-DOUBLE-FLOAT #x40100000 #x0)) NIL) (= (#.(MAKE-DOUBLE-FLOAT #x-40100000 #x0) #.(MAKE-SINGLE-FLOAT #x-40800000)) T) -(= (#.(MAKE-DOUBLE-FLOAT #x-40100000 #x0) #.(MAKE-SINGLE-FLOAT #x3F800000)) NIL) (= (#.(MAKE-DOUBLE-FLOAT #x-40100000 #x0) #.(MAKE-DOUBLE-FLOAT #x-40100000 #x0)) T) +(= (#.(MAKE-DOUBLE-FLOAT #x-40100000 #x0) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) NIL) (= (#.(MAKE-DOUBLE-FLOAT #x-40100000 #x0) #.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0)) NIL) -(= (#.(MAKE-DOUBLE-FLOAT #x-4006DE05 #x54442D18) #.(MAKE-DOUBLE-FLOAT #x3FF921FB #x54442D18)) NIL) (= (#.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0) #.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0)) T) -(= (#.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0) #.(MAKE-DOUBLE-FLOAT #x-3E400000 #x800000)) NIL) +(= (#.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0) #.(MAKE-DOUBLE-FLOAT #x-3CC00000 #x0)) NIL) (= (#.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) NIL) -(= (#.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0) #.(MAKE-DOUBLE-FLOAT #x41C00000 #x0)) NIL) +(= (#.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0) #.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFF000000)) NIL) +(= (#.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0) #.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFFFFFFFF)) NIL) +(= (#.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0) #.(MAKE-DOUBLE-FLOAT #x433FFFFF #xFFFFFFFF)) NIL) (= (#.(MAKE-DOUBLE-FLOAT #x-3E26DE05 #x537B1D3D) #.(MAKE-DOUBLE-FLOAT #x-3E26DE05 #x54442D18)) NIL) (= (#.(MAKE-DOUBLE-FLOAT #x-3E26DE05 #x537B1D3D) #.(MAKE-DOUBLE-FLOAT #x41D921FB #x54442D18)) NIL) +(= (#.(MAKE-DOUBLE-FLOAT #x-3CC00000 #x0) #.(MAKE-DOUBLE-FLOAT #x433FFFFF #xFFFFFFFF)) NIL) (= (#.(MAKE-DOUBLE-FLOAT #x-3C500000 #x0) #.(MAKE-DOUBLE-FLOAT #x-3C500000 #x0)) T) (= (#.(MAKE-DOUBLE-FLOAT #x-3C500000 #x0) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) NIL) +(= (#.(MAKE-DOUBLE-FLOAT #x-3C500000 #x0) #.(MAKE-DOUBLE-FLOAT #x43AFFFFF #xFFFFFFFF)) NIL) (= (#.(MAKE-DOUBLE-FLOAT #x-3C36DE05 #x54442D18) #.(MAKE-DOUBLE-FLOAT #x-3C36DE05 #x54442D18)) T) (= (#.(MAKE-DOUBLE-FLOAT #x-3C300000 #x0) #.(MAKE-DOUBLE-FLOAT #x-3C300000 #x0)) T) (= (#.(MAKE-DOUBLE-FLOAT #x-3C300000 #x0) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) NIL) +(= (#.(MAKE-DOUBLE-FLOAT #x-3C300000 #x0) #.(MAKE-DOUBLE-FLOAT #x43CFFFFF #xFFFFFFFF)) NIL) (= (#.(MAKE-DOUBLE-FLOAT #x-3C16DE05 #x54442D18) #.(MAKE-DOUBLE-FLOAT #x-3C16DE05 #x54442D18)) T) (= (#.(MAKE-DOUBLE-FLOAT #x-500001 #xFFFFFFFE) #x0) NIL) +(= (#.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #.(MAKE-SINGLE-FLOAT #x-800001)) NIL) (= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #x-4000000000000001) NIL) (= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #x-4000000000000000) NIL) (= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #x-1000000000000001) NIL) @@ -1716,26 +1716,36 @@ (= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #x4000000000000001) NIL) (= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-SINGLE-FLOAT #x0)) T) (= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x-80000000 #x0)) T) +(= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x-40100000 #x0)) NIL) +(= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x-4006DE05 #x54442D18)) NIL) +(= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x-3F8BCB1A #x420F4374)) NIL) +(= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x-3F78B6F0 #xD52D3052)) NIL) (= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0)) NIL) -(= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x-3E300000 #x0)) NIL) +(= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x-3E300001 #xFF800000)) NIL) +(= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x-3C62329C #xFF1194D8)) NIL) (= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x-3C500000 #x0)) NIL) (= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x-3C400000 #x0)) NIL) (= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x-3C300000 #x0)) NIL) (= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x-3C200000 #x0)) NIL) +(= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x-3A72329B #x0)) NIL) +(= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x-3A52329B #x0)) NIL) (= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) T) (= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFF000000)) NIL) +(= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFFFFFFFF)) NIL) (= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x41D00000 #x0)) NIL) (= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x41D00000 #x400000)) NIL) +(= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x43AFFFFF #xFFFFFFFF)) NIL) (= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x43B00000 #x0)) NIL) (= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x43C00000 #x0)) NIL) +(= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x43CFFFFF #xFFFFFFFF)) NIL) (= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x43D00000 #x0)) NIL) (= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x43E00000 #x0)) NIL) +(= (#.(MAKE-DOUBLE-FLOAT #x1FFFFF #xFFFFFFFE) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) NIL) (= (#.(MAKE-DOUBLE-FLOAT #x20100000 #x1) #.(MAKE-DOUBLE-FLOAT #x-80000000 #x0)) NIL) (= (#.(MAKE-DOUBLE-FLOAT #x3FB99999 #x9999999A) #.(MAKE-DOUBLE-FLOAT #x3FB99999 #x9999999A)) T) (= (#.(MAKE-DOUBLE-FLOAT #x3FE00000 #x0) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) NIL) (= (#.(MAKE-DOUBLE-FLOAT #x3FE00000 #x0) #.(MAKE-DOUBLE-FLOAT #x3FE00000 #x0)) T) -(= (#.(MAKE-DOUBLE-FLOAT #x3FE00000 #x0) #.(MAKE-DOUBLE-FLOAT #x4083C273 #x2107A1BA)) NIL) -(= (#.(MAKE-DOUBLE-FLOAT #x3FE00000 #x0) #.(MAKE-DOUBLE-FLOAT #x41CFFFFF #xFF800000)) NIL) +(= (#.(MAKE-DOUBLE-FLOAT #x3FE00000 #x0) #.(MAKE-DOUBLE-FLOAT #x4083BA73 #x2107A1BA)) NIL) (= (#.(MAKE-DOUBLE-FLOAT #x3FE6A09E #x667F3BCD) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) NIL) (= (#.(MAKE-DOUBLE-FLOAT #x3FE6A09E #x667F3BCD) #.(MAKE-DOUBLE-FLOAT #x3FE6A09E #x667F3BCD)) T) (= (#.(MAKE-DOUBLE-FLOAT #x3FE6A09E #x667F3BCD) #.(MAKE-DOUBLE-FLOAT #x3FF33333 #x33333333)) NIL) @@ -1752,21 +1762,22 @@ (= (#.(MAKE-DOUBLE-FLOAT #x4005BF0A #x8B145769) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) NIL) (= (#.(MAKE-DOUBLE-FLOAT #x400921FB #x54442D18) #.(MAKE-DOUBLE-FLOAT #x400921FB #x54442D18)) T) (= (#.(MAKE-DOUBLE-FLOAT #x40100000 #x0) #.(MAKE-DOUBLE-FLOAT #x-80000000 #x0)) NIL) -(= (#.(MAKE-DOUBLE-FLOAT #x4083C209 #xA84FBD00) #x0) NIL) -(= (#.(MAKE-DOUBLE-FLOAT #x4083C209 #xA84FBD00) #.(MAKE-DOUBLE-FLOAT #x4083C273 #x2107A1BA)) NIL) +(= (#.(MAKE-DOUBLE-FLOAT #x4083BA09 #xA84FBD00) #x0) NIL) +(= (#.(MAKE-DOUBLE-FLOAT #x4083BA09 #xA84FBD00) #.(MAKE-DOUBLE-FLOAT #x4083BA73 #x2107A1BA)) NIL) (= (#.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFF000000) #x0) NIL) (= (#.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFF000000) #.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0)) NIL) (= (#.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFF000000) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) NIL) (= (#.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFF000000) #.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFF000000)) T) (= (#.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFF000000) #.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFFFFFFFF)) NIL) (= (#.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFF000000) #.(MAKE-DOUBLE-FLOAT #x41C00000 #x0)) NIL) -(= (#.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x-3E400000 #x800000)) NIL) +(= (#.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0)) NIL) +(= (#.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x-3CC00000 #x0)) NIL) (= (#.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFFFFFFFF)) T) -(= (#.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x41C00000 #x0)) NIL) -(= (#.(MAKE-DOUBLE-FLOAT #x41CFFFFF #xFF800000) #x0) NIL) -(= (#.(MAKE-DOUBLE-FLOAT #x41CFFFFF #xFF800000) #.(MAKE-DOUBLE-FLOAT #x41CFFFFF #xFF800000)) T) +(= (#.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x433FFFFF #xFFFFFFFF)) NIL) (= (#.(MAKE-DOUBLE-FLOAT #x41D921FB #x537B1D3D) #.(MAKE-DOUBLE-FLOAT #x-3E26DE05 #x54442D18)) NIL) (= (#.(MAKE-DOUBLE-FLOAT #x41D921FB #x537B1D3D) #.(MAKE-DOUBLE-FLOAT #x41D921FB #x54442D18)) NIL) +(= (#.(MAKE-DOUBLE-FLOAT #x4270C6F7 #xA0B5E000) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) NIL) +(= (#.(MAKE-DOUBLE-FLOAT #x4270C6F7 #xA0B5E000) #.(MAKE-DOUBLE-FLOAT #x4270C6F7 #xA0B5E000)) T) (= (#.(MAKE-DOUBLE-FLOAT #x4310624D #xD2F1A9F8) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) NIL) (= (#.(MAKE-DOUBLE-FLOAT #x4310624D #xD2F1A9F8) #.(MAKE-DOUBLE-FLOAT #x4310624D #xD2F1A9F8)) T) (= (#.(MAKE-DOUBLE-FLOAT #x43AFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x-3C500000 #x0)) NIL) @@ -1786,6 +1797,7 @@ (= (#.(MAKE-DOUBLE-FLOAT #x5FCFFFFF #xFFFFFFFF) #x0) NIL) (= (#.(MAKE-DOUBLE-FLOAT #x5FCFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x5FCFFFFF #xFFFFFFFF)) T) (= (#.(MAKE-DOUBLE-FLOAT #x5FEFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x-80000000 #x0)) NIL) +(= (#.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF) #.(MAKE-SINGLE-FLOAT #x7F7FFFFF)) NIL) (= (#.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x-80000000 #x0)) NIL) (= (#x-4000000000000000 #x3FFFFFFFFFFFFFFF #.(MAKE-DOUBLE-FLOAT #x0 #x0)) NIL) (= (#x-1000000000000000 #xFFFFFFFFFFFFFFF #.(MAKE-DOUBLE-FLOAT #x0 #x0)) NIL) @@ -1794,36 +1806,24 @@ (= (#x-1 #x1FFFFFFFFFFFFFF7 #.(MAKE-SINGLE-FLOAT #x0)) NIL) (= (#x-1 #x7FFFFFFFFFFFFFF7 #.(MAKE-SINGLE-FLOAT #x0)) NIL) (= (#x0 #x0 #.(MAKE-DOUBLE-FLOAT #x0 #x0)) T) +(= (#x0 #x1FFFFFFC #.(MAKE-SINGLE-FLOAT #x3F800000)) NIL) +(= (#x0 #xFFFFFFFFFFFFFFC #.(MAKE-SINGLE-FLOAT #x3F800000)) NIL) +(= (#x0 #x3FFFFFFFFFFFFFFC #.(MAKE-SINGLE-FLOAT #x3F800000)) NIL) (= (#x0 #.(MAKE-SINGLE-FLOAT #x4DFFFFFF) #x0) NIL) -(= (#x0 #.(MAKE-SINGLE-FLOAT #x4E000000) #x0) NIL) -(= (#x0 #.(MAKE-SINGLE-FLOAT #x4E800000) #x0) NIL) -(= (#x0 #.(MAKE-SINGLE-FLOAT #x4E800000) #.(MAKE-SINGLE-FLOAT #x4E800000)) NIL) -(= (#x0 #.(MAKE-SINGLE-FLOAT #x4EC00000) #x0) NIL) (= (#x0 #.(MAKE-SINGLE-FLOAT #x4EC90FDB) #x0) NIL) -(= (#x0 #.(MAKE-SINGLE-FLOAT #x5CEE6B28) #x0) NIL) (= (#x0 #.(MAKE-SINGLE-FLOAT #x5D7FFFFF) #x0) NIL) -(= (#x0 #.(MAKE-SINGLE-FLOAT #x5D800000) #x0) NIL) (= (#x0 #.(MAKE-SINGLE-FLOAT #x5E490FDB) #x0) NIL) (= (#x0 #.(MAKE-SINGLE-FLOAT #x5E7FFFFF) #x0) NIL) -(= (#x0 #.(MAKE-SINGLE-FLOAT #x5E800000) #x0) NIL) (= (#x0 #.(MAKE-SINGLE-FLOAT #x5F490FDB) #x0) NIL) -(= (#x0 #.(MAKE-SINGLE-FLOAT #x6C6E6B28) #x0) NIL) -(= (#x0 #.(MAKE-SINGLE-FLOAT #x6D6E6B28) #x0) NIL) -(= (#x0 #.(MAKE-DOUBLE-FLOAT #x40734413 #x509F79FF) #x0) NIL) -(= (#x0 #.(MAKE-DOUBLE-FLOAT #x4083C209 #xA84FBD00) #x0) NIL) -(= (#x0 #.(MAKE-DOUBLE-FLOAT #x4083C273 #x2107A1BA) #x0) NIL) -(= (#x0 #.(MAKE-DOUBLE-FLOAT #x4083C273 #x2107A1BA) #.(MAKE-DOUBLE-FLOAT #x4083C209 #xA84FBD00)) NIL) -(= (#x0 #.(MAKE-DOUBLE-FLOAT #x408D6413 #x509F7A00) #x0) NIL) +(= (#x0 #.(MAKE-DOUBLE-FLOAT #x4083BA09 #xA84FBD00) #x0) NIL) +(= (#x0 #.(MAKE-DOUBLE-FLOAT #x4083BA73 #x2107A1BA) #x0) NIL) +(= (#x0 #.(MAKE-DOUBLE-FLOAT #x4083BA73 #x2107A1BA) #.(MAKE-DOUBLE-FLOAT #x4083BA09 #xA84FBD00)) NIL) (= (#x0 #.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFF000000) #x0) NIL) (= (#x0 #.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFFFFFFFF) #x0) NIL) (= (#x0 #.(MAKE-DOUBLE-FLOAT #x41C00000 #x0) #x0) NIL) (= (#x0 #.(MAKE-DOUBLE-FLOAT #x41C00000 #x0) #.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFF000000)) NIL) -(= (#x0 #.(MAKE-DOUBLE-FLOAT #x41CFFFFF #xFF800000) #x0) NIL) -(= (#x0 #.(MAKE-DOUBLE-FLOAT #x41CFFFFF #xFF800000) #.(MAKE-DOUBLE-FLOAT #x41CFFFFF #xFF800000)) NIL) -(= (#x0 #.(MAKE-DOUBLE-FLOAT #x41D7FFFF #xFF800000) #x0) NIL) (= (#x0 #.(MAKE-DOUBLE-FLOAT #x41D921FB #x537B1D3D) #x0) NIL) (= (#x0 #.(MAKE-DOUBLE-FLOAT #x41D921FB #x54442D18) #x0) NIL) -(= (#x0 #.(MAKE-DOUBLE-FLOAT #x439DCD64 #xFF1194D8) #x0) NIL) (= (#x0 #.(MAKE-DOUBLE-FLOAT #x43AFFFFF #xFFFFFFFF) #x0) NIL) (= (#x0 #.(MAKE-DOUBLE-FLOAT #x43B00000 #x0) #x0) NIL) (= (#x0 #.(MAKE-DOUBLE-FLOAT #x43B00000 #x0) #.(MAKE-DOUBLE-FLOAT #x43B00000 #x0)) NIL) @@ -1832,22 +1832,22 @@ (= (#x0 #.(MAKE-DOUBLE-FLOAT #x43D00000 #x0) #x0) NIL) (= (#x0 #.(MAKE-DOUBLE-FLOAT #x43D00000 #x0) #.(MAKE-DOUBLE-FLOAT #x43D00000 #x0)) NIL) (= (#x0 #.(MAKE-DOUBLE-FLOAT #x43E921FB #x54442D18) #x0) NIL) -(= (#x0 #.(MAKE-DOUBLE-FLOAT #x458DCD65 #x0) #x0) NIL) -(= (#x0 #.(MAKE-DOUBLE-FLOAT #x45ADCD65 #x0) #x0) NIL) (= (#x0 #.(MAKE-DOUBLE-FLOAT #x5FCFFFFF #xFFFFFFFF) #x0) NIL) (= (#.(MAKE-SINGLE-FLOAT #x-80000000) #.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x-80000000)) T) (= (#.(MAKE-SINGLE-FLOAT #x-80000000) #.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x0)) T) +(= (#.(MAKE-SINGLE-FLOAT #x-40800000) #.(MAKE-SINGLE-FLOAT #x-80000000) #.(MAKE-SINGLE-FLOAT #x0)) NIL) +(= (#.(MAKE-SINGLE-FLOAT #x-40800000) #.(MAKE-SINGLE-FLOAT #x-40800000) #.(MAKE-DOUBLE-FLOAT #x-40100000 #x0)) T) (= (#.(MAKE-SINGLE-FLOAT #x-32000000) #x0 #x0) NIL) (= (#.(MAKE-SINGLE-FLOAT #x-32000000) #.(MAKE-SINGLE-FLOAT #x-32000000) #.(MAKE-SINGLE-FLOAT #x-32000000)) T) (= (#.(MAKE-SINGLE-FLOAT #x-32000000) #.(MAKE-SINGLE-FLOAT #x4DFFFFFF) #.(MAKE-SINGLE-FLOAT #x-32000000)) NIL) (= (#.(MAKE-SINGLE-FLOAT #x-32000000) #.(MAKE-SINGLE-FLOAT #x4DFFFFFF) #.(MAKE-SINGLE-FLOAT #x4DFFFFFF)) NIL) +(= (#.(MAKE-SINGLE-FLOAT #x-319194D8) #.(MAKE-SINGLE-FLOAT #x-80000000) #.(MAKE-SINGLE-FLOAT #x0)) NIL) (= (#.(MAKE-SINGLE-FLOAT #x-31800000) #.(MAKE-SINGLE-FLOAT #x4E800000) #x0) NIL) (= (#.(MAKE-SINGLE-FLOAT #x-31800000) #.(MAKE-SINGLE-FLOAT #x4E800000) #.(MAKE-SINGLE-FLOAT #x0)) NIL) -(= (#.(MAKE-SINGLE-FLOAT #x-31400000) #x0 #x0) NIL) (= (#.(MAKE-SINGLE-FLOAT #x-3136F025) #x0 #x0) NIL) (= (#.(MAKE-SINGLE-FLOAT #x-3136F025) #.(MAKE-SINGLE-FLOAT #x4EC90FDB) #.(MAKE-SINGLE-FLOAT #x-3136F025)) NIL) (= (#.(MAKE-SINGLE-FLOAT #x-3136F025) #.(MAKE-SINGLE-FLOAT #x4EC90FDB) #.(MAKE-SINGLE-FLOAT #x4EC90FDB)) NIL) -(= (#.(MAKE-SINGLE-FLOAT #x-231194D8) #x0 #x0) NIL) +(= (#.(MAKE-SINGLE-FLOAT #x-231194D8) #.(MAKE-SINGLE-FLOAT #x-80000000) #.(MAKE-SINGLE-FLOAT #x0)) NIL) (= (#.(MAKE-SINGLE-FLOAT #x-22800000) #x0 #x0) NIL) (= (#.(MAKE-SINGLE-FLOAT #x-22800000) #.(MAKE-SINGLE-FLOAT #x-22800000) #.(MAKE-SINGLE-FLOAT #x-22800000)) T) (= (#.(MAKE-SINGLE-FLOAT #x-22800000) #.(MAKE-SINGLE-FLOAT #x5D7FFFFF) #.(MAKE-SINGLE-FLOAT #x-22800000)) NIL) @@ -1866,41 +1866,59 @@ (= (#.(MAKE-SINGLE-FLOAT #x-20B6F025) #x0 #x0) NIL) (= (#.(MAKE-SINGLE-FLOAT #x-20B6F025) #.(MAKE-SINGLE-FLOAT #x5F490FDB) #.(MAKE-SINGLE-FLOAT #x-20B6F025)) NIL) (= (#.(MAKE-SINGLE-FLOAT #x-20B6F025) #.(MAKE-SINGLE-FLOAT #x5F490FDB) #.(MAKE-SINGLE-FLOAT #x5F490FDB)) NIL) -(= (#.(MAKE-SINGLE-FLOAT #x-139194D8) #x0 #x0) NIL) -(= (#.(MAKE-SINGLE-FLOAT #x-129194D8) #x0 #x0) NIL) +(= (#.(MAKE-SINGLE-FLOAT #x-139194D8) #.(MAKE-SINGLE-FLOAT #x-80000000) #.(MAKE-SINGLE-FLOAT #x0)) NIL) +(= (#.(MAKE-SINGLE-FLOAT #x-129194D8) #.(MAKE-SINGLE-FLOAT #x-80000000) #.(MAKE-SINGLE-FLOAT #x0)) NIL) (= (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x0)) T) +(= (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) T) (= (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x3F000000) #.(MAKE-SINGLE-FLOAT #x3F000000)) NIL) +(= (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x3F800000) #.(MAKE-SINGLE-FLOAT #x-80000000)) NIL) +(= (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x3F800000) #.(MAKE-SINGLE-FLOAT #x0)) NIL) (= (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x3F800000) #.(MAKE-SINGLE-FLOAT #x3D800000)) NIL) -(= (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x4E800000) #.(MAKE-SINGLE-FLOAT #x3F000000)) NIL) +(= (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x3F800000) #.(MAKE-SINGLE-FLOAT #x3F800000)) NIL) +(= (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x4E6E6B28) #.(MAKE-SINGLE-FLOAT #x-80000000)) NIL) +(= (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x5CEE6B28) #.(MAKE-SINGLE-FLOAT #x-80000000)) NIL) +(= (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x6C6E6B28) #.(MAKE-SINGLE-FLOAT #x-80000000)) NIL) +(= (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x6D6E6B28) #.(MAKE-SINGLE-FLOAT #x-80000000)) NIL) +(= (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-DOUBLE-FLOAT #x439DCD64 #xFF1194D8) #.(MAKE-SINGLE-FLOAT #x-80000000)) NIL) +(= (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-DOUBLE-FLOAT #x458DCD65 #x0) #.(MAKE-SINGLE-FLOAT #x-80000000)) NIL) +(= (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-DOUBLE-FLOAT #x45ADCD65 #x0) #.(MAKE-SINGLE-FLOAT #x-80000000)) NIL) (= (#.(MAKE-SINGLE-FLOAT #x3D800000) #.(MAKE-SINGLE-FLOAT #x3D800000) #.(MAKE-SINGLE-FLOAT #x3D800000)) T) (= (#.(MAKE-SINGLE-FLOAT #x3D800000) #.(MAKE-SINGLE-FLOAT #x3F800000) #.(MAKE-SINGLE-FLOAT #x3D800000)) NIL) (= (#.(MAKE-SINGLE-FLOAT #x3F000000) #.(MAKE-SINGLE-FLOAT #x3F000000) #.(MAKE-SINGLE-FLOAT #x3F000000)) T) (= (#.(MAKE-SINGLE-FLOAT #x3F800000) #.(MAKE-SINGLE-FLOAT #x3F800000) #.(MAKE-SINGLE-FLOAT #x3F800000)) T) +(= (#.(MAKE-SINGLE-FLOAT #x3F800000) #.(MAKE-SINGLE-FLOAT #x3F800000) #.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0)) T) +(= (#.(MAKE-SINGLE-FLOAT #x4DFFFFFF) #.(MAKE-SINGLE-FLOAT #x4DFFFFFF) #.(MAKE-SINGLE-FLOAT #x4DFFFFFF)) T) (= (#.(MAKE-SINGLE-FLOAT #x4E000000) #.(MAKE-SINGLE-FLOAT #x4E000000) #.(MAKE-SINGLE-FLOAT #x4E000000)) T) +(= (#.(MAKE-SINGLE-FLOAT #x538637BD) #.(MAKE-SINGLE-FLOAT #x538637BD) #.(MAKE-SINGLE-FLOAT #x538637BD)) T) (= (#.(MAKE-SINGLE-FLOAT #x5883126F) #.(MAKE-SINGLE-FLOAT #x5883126F) #.(MAKE-SINGLE-FLOAT #x5883126F)) T) +(= (#.(MAKE-SINGLE-FLOAT #x5D7FFFFF) #.(MAKE-SINGLE-FLOAT #x5D7FFFFF) #.(MAKE-SINGLE-FLOAT #x5D7FFFFF)) T) (= (#.(MAKE-SINGLE-FLOAT #x5D800000) #.(MAKE-SINGLE-FLOAT #x5D800000) #.(MAKE-SINGLE-FLOAT #x5D800000)) T) +(= (#.(MAKE-SINGLE-FLOAT #x5E7FFFFF) #.(MAKE-SINGLE-FLOAT #x5E7FFFFF) #.(MAKE-SINGLE-FLOAT #x5E7FFFFF)) T) (= (#.(MAKE-SINGLE-FLOAT #x5E800000) #.(MAKE-SINGLE-FLOAT #x5E800000) #.(MAKE-SINGLE-FLOAT #x5E800000)) T) (= (#.(MAKE-DOUBLE-FLOAT #x-80000000 #x0) #.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x-80000000 #x0)) T) (= (#.(MAKE-DOUBLE-FLOAT #x-80000000 #x0) #.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) T) -(= (#.(MAKE-DOUBLE-FLOAT #x-3F8BCB1A #x420F4374) #x0 #x0) NIL) -(= (#.(MAKE-DOUBLE-FLOAT #x-3F72231A #x420F4374) #x0 #x0) NIL) +(= (#.(MAKE-DOUBLE-FLOAT #x-40100000 #x0) #.(MAKE-DOUBLE-FLOAT #x-80000000 #x0) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) NIL) +(= (#.(MAKE-DOUBLE-FLOAT #x-40100000 #x0) #.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0) #.(MAKE-SINGLE-FLOAT #x-40800000)) NIL) +(= (#.(MAKE-DOUBLE-FLOAT #x-40100000 #x0) #.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0) #.(MAKE-SINGLE-FLOAT #x3F800000)) NIL) +(= (#.(MAKE-DOUBLE-FLOAT #x-4006DE05 #x54442D18) #.(MAKE-DOUBLE-FLOAT #x-80000000 #x0) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) NIL) +(= (#.(MAKE-DOUBLE-FLOAT #x-3F8BCB1A #x420F4374) #.(MAKE-DOUBLE-FLOAT #x-80000000 #x0) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) NIL) +(= (#.(MAKE-DOUBLE-FLOAT #x-3F78B6F0 #xD52D3052) #.(MAKE-DOUBLE-FLOAT #x-80000000 #x0) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) NIL) (= (#.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0) #x0 #x0) NIL) (= (#.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0) #.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0) #.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0)) T) (= (#.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0) #.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFF000000) #.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0)) NIL) (= (#.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0) #.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFF000000) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) NIL) (= (#.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0) #.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0)) NIL) (= (#.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0) #.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFF000000)) NIL) -(= (#.(MAKE-DOUBLE-FLOAT #x-3E400000 #x800000) #.(MAKE-DOUBLE-FLOAT #x41C00000 #x0) #.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0)) NIL) -(= (#.(MAKE-DOUBLE-FLOAT #x-3E400000 #x800000) #.(MAKE-DOUBLE-FLOAT #x41C00000 #x0) #.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFFFFFFFF)) NIL) -(= (#.(MAKE-DOUBLE-FLOAT #x-3E300000 #x0) #.(MAKE-DOUBLE-FLOAT #x41D00000 #x0) #x0) NIL) -(= (#.(MAKE-DOUBLE-FLOAT #x-3E300000 #x0) #.(MAKE-DOUBLE-FLOAT #x41D00000 #x0) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) NIL) -(= (#.(MAKE-DOUBLE-FLOAT #x-3E300000 #x0) #.(MAKE-DOUBLE-FLOAT #x41D00000 #x400000) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) NIL) -(= (#.(MAKE-DOUBLE-FLOAT #x-3E280001 #xFFC00000) #x0 #x0) NIL) +(= (#.(MAKE-DOUBLE-FLOAT #x-3E300001 #xFF800000) #.(MAKE-DOUBLE-FLOAT #x41D00000 #x0) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) NIL) +(= (#.(MAKE-DOUBLE-FLOAT #x-3E300001 #xFF800000) #.(MAKE-DOUBLE-FLOAT #x41D00000 #x400000) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) NIL) (= (#.(MAKE-DOUBLE-FLOAT #x-3E26DE05 #x537B1D3D) #x0 #x0) NIL) (= (#.(MAKE-DOUBLE-FLOAT #x-3E26DE05 #x54442D18) #x0 #x0) NIL) (= (#.(MAKE-DOUBLE-FLOAT #x-3E26DE05 #x54442D18) #.(MAKE-DOUBLE-FLOAT #x41D921FB #x54442D18) #.(MAKE-DOUBLE-FLOAT #x-3E26DE05 #x537B1D3D)) NIL) (= (#.(MAKE-DOUBLE-FLOAT #x-3E26DE05 #x54442D18) #.(MAKE-DOUBLE-FLOAT #x41D921FB #x54442D18) #.(MAKE-DOUBLE-FLOAT #x41D921FB #x537B1D3D)) NIL) -(= (#.(MAKE-DOUBLE-FLOAT #x-3C62329C #xFF1194D8) #x0 #x0) NIL) +(= (#.(MAKE-DOUBLE-FLOAT #x-3CC00000 #x0) #.(MAKE-DOUBLE-FLOAT #x433FFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0)) NIL) +(= (#.(MAKE-DOUBLE-FLOAT #x-3CC00000 #x0) #.(MAKE-DOUBLE-FLOAT #x433FFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFFFFFFFF)) NIL) +(= (#.(MAKE-DOUBLE-FLOAT #x-3C62329C #xFF1194D8) #.(MAKE-SINGLE-FLOAT #x-80000000) #.(MAKE-SINGLE-FLOAT #x0)) NIL) +(= (#.(MAKE-DOUBLE-FLOAT #x-3C62329C #xFF1194D8) #.(MAKE-DOUBLE-FLOAT #x-80000000 #x0) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) NIL) (= (#.(MAKE-DOUBLE-FLOAT #x-3C500000 #x0) #x0 #x0) NIL) (= (#.(MAKE-DOUBLE-FLOAT #x-3C500000 #x0) #.(MAKE-DOUBLE-FLOAT #x-3C500000 #x0) #.(MAKE-DOUBLE-FLOAT #x-3C500000 #x0)) T) (= (#.(MAKE-DOUBLE-FLOAT #x-3C500000 #x0) #.(MAKE-DOUBLE-FLOAT #x43AFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x-3C500000 #x0)) NIL) @@ -1921,21 +1939,35 @@ (= (#.(MAKE-DOUBLE-FLOAT #x-3C16DE05 #x54442D18) #x0 #x0) NIL) (= (#.(MAKE-DOUBLE-FLOAT #x-3C16DE05 #x54442D18) #.(MAKE-DOUBLE-FLOAT #x43E921FB #x54442D18) #.(MAKE-DOUBLE-FLOAT #x-3C16DE05 #x54442D18)) NIL) (= (#.(MAKE-DOUBLE-FLOAT #x-3C16DE05 #x54442D18) #.(MAKE-DOUBLE-FLOAT #x43E921FB #x54442D18) #.(MAKE-DOUBLE-FLOAT #x43E921FB #x54442D18)) NIL) -(= (#.(MAKE-DOUBLE-FLOAT #x-3A72329B #x0) #x0 #x0) NIL) -(= (#.(MAKE-DOUBLE-FLOAT #x-3A52329B #x0) #x0 #x0) NIL) +(= (#.(MAKE-DOUBLE-FLOAT #x-3A72329B #x0) #.(MAKE-SINGLE-FLOAT #x-80000000) #.(MAKE-SINGLE-FLOAT #x0)) NIL) +(= (#.(MAKE-DOUBLE-FLOAT #x-3A72329B #x0) #.(MAKE-DOUBLE-FLOAT #x-80000000 #x0) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) NIL) +(= (#.(MAKE-DOUBLE-FLOAT #x-3A52329B #x0) #.(MAKE-SINGLE-FLOAT #x-80000000) #.(MAKE-SINGLE-FLOAT #x0)) NIL) +(= (#.(MAKE-DOUBLE-FLOAT #x-3A52329B #x0) #.(MAKE-DOUBLE-FLOAT #x-80000000 #x0) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) NIL) (= (#.(MAKE-DOUBLE-FLOAT #x-500001 #xFFFFFFFE) #x0 #x0) NIL) +(= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-SINGLE-FLOAT #x0)) T) (= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) T) (= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x3FE00000 #x0) #.(MAKE-DOUBLE-FLOAT #x3FE00000 #x0)) NIL) (= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x3FEFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) NIL) -(= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x4083C273 #x2107A1BA) #.(MAKE-DOUBLE-FLOAT #x3FE00000 #x0)) NIL) -(= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x41CFFFFF #xFF800000) #.(MAKE-DOUBLE-FLOAT #x3FE00000 #x0)) NIL) +(= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0) #.(MAKE-DOUBLE-FLOAT #x-80000000 #x0)) NIL) +(= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x3FF921FB #x54442D18) #.(MAKE-DOUBLE-FLOAT #x-80000000 #x0)) NIL) +(= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x40734413 #x509F79FF) #.(MAKE-DOUBLE-FLOAT #x-80000000 #x0)) NIL) +(= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x4083BA73 #x2107A1BA) #.(MAKE-DOUBLE-FLOAT #x3FE00000 #x0)) NIL) +(= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x408628B7 #x6E3A7B61) #.(MAKE-DOUBLE-FLOAT #x-80000000 #x0)) NIL) +(= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x439DCD64 #xFF1194D8) #.(MAKE-DOUBLE-FLOAT #x-80000000 #x0)) NIL) +(= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x458DCD65 #x0) #.(MAKE-DOUBLE-FLOAT #x-80000000 #x0)) NIL) +(= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x45ADCD65 #x0) #.(MAKE-DOUBLE-FLOAT #x-80000000 #x0)) NIL) +(= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x5FEFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x-80000000 #x0)) NIL) (= (#.(MAKE-DOUBLE-FLOAT #x3FB99999 #x9999999A) #.(MAKE-DOUBLE-FLOAT #x3FB99999 #x9999999A) #.(MAKE-DOUBLE-FLOAT #x3FB99999 #x9999999A)) T) (= (#.(MAKE-DOUBLE-FLOAT #x3FE00000 #x0) #.(MAKE-DOUBLE-FLOAT #x3FE00000 #x0) #.(MAKE-DOUBLE-FLOAT #x3FE00000 #x0)) T) (= (#.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0) #.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0) #.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0)) T) (= (#.(MAKE-DOUBLE-FLOAT #x3FF33333 #x33333333) #.(MAKE-DOUBLE-FLOAT #x3FF33333 #x33333333) #.(MAKE-DOUBLE-FLOAT #x3FF33333 #x33333333)) T) (= (#.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFF000000) #.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFF000000) #.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFF000000)) T) +(= (#.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFFFFFFFF)) T) +(= (#.(MAKE-DOUBLE-FLOAT #x4270C6F7 #xA0B5E000) #.(MAKE-DOUBLE-FLOAT #x4270C6F7 #xA0B5E000) #.(MAKE-DOUBLE-FLOAT #x4270C6F7 #xA0B5E000)) T) (= (#.(MAKE-DOUBLE-FLOAT #x4310624D #xD2F1A9F8) #.(MAKE-DOUBLE-FLOAT #x4310624D #xD2F1A9F8) #.(MAKE-DOUBLE-FLOAT #x4310624D #xD2F1A9F8)) T) +(= (#.(MAKE-DOUBLE-FLOAT #x43AFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x43AFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x43AFFFFF #xFFFFFFFF)) T) (= (#.(MAKE-DOUBLE-FLOAT #x43B00000 #x0) #.(MAKE-DOUBLE-FLOAT #x43B00000 #x0) #.(MAKE-DOUBLE-FLOAT #x43B00000 #x0)) T) +(= (#.(MAKE-DOUBLE-FLOAT #x43CFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x43CFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x43CFFFFF #xFFFFFFFF)) T) (= (#.(MAKE-DOUBLE-FLOAT #x43D00000 #x0) #.(MAKE-DOUBLE-FLOAT #x43D00000 #x0) #.(MAKE-DOUBLE-FLOAT #x43D00000 #x0)) T) (= (#.(MAKE-SINGLE-FLOAT #x3F000000) #.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x3F000000) #.(MAKE-SINGLE-FLOAT #x3F000000)) NIL) (= (#.(MAKE-SINGLE-FLOAT #x3F800000) #.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x3D800000) #.(MAKE-SINGLE-FLOAT #x3D800000)) NIL) @@ -1943,7 +1975,6 @@ (= (#.(MAKE-SINGLE-FLOAT #x4DFFFFFF) #.(MAKE-SINGLE-FLOAT #x-32000000) #.(MAKE-SINGLE-FLOAT #x4DFFFFFF) #.(MAKE-SINGLE-FLOAT #x-32000000)) NIL) (= (#.(MAKE-SINGLE-FLOAT #x4E800000) #.(MAKE-SINGLE-FLOAT #x-31800000) #x0 #x0) NIL) (= (#.(MAKE-SINGLE-FLOAT #x4E800000) #.(MAKE-SINGLE-FLOAT #x-31800000) #.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x0)) NIL) -(= (#.(MAKE-SINGLE-FLOAT #x4E800000) #.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x3F000000) #.(MAKE-SINGLE-FLOAT #x3F000000)) NIL) (= (#.(MAKE-SINGLE-FLOAT #x5D7FFFFF) #.(MAKE-SINGLE-FLOAT #x-22800000) #.(MAKE-SINGLE-FLOAT #x5D7FFFFF) #.(MAKE-SINGLE-FLOAT #x-22800000)) NIL) (= (#.(MAKE-SINGLE-FLOAT #x5E000000) #.(MAKE-SINGLE-FLOAT #x-22000000) #x0 #x0) NIL) (= (#.(MAKE-SINGLE-FLOAT #x5E000000) #.(MAKE-SINGLE-FLOAT #x-22000000) #.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x0)) NIL) @@ -1951,14 +1982,13 @@ (= (#.(MAKE-SINGLE-FLOAT #x5F000000) #.(MAKE-SINGLE-FLOAT #x-21000000) #x0 #x0) NIL) (= (#.(MAKE-SINGLE-FLOAT #x5F000000) #.(MAKE-SINGLE-FLOAT #x-21000000) #.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x0)) NIL) (= (#.(MAKE-DOUBLE-FLOAT #x3FE00000 #x0) #.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x3FE00000 #x0) #.(MAKE-DOUBLE-FLOAT #x3FE00000 #x0)) NIL) -(= (#.(MAKE-DOUBLE-FLOAT #x4083C273 #x2107A1BA) #.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x3FE00000 #x0) #.(MAKE-DOUBLE-FLOAT #x3FE00000 #x0)) NIL) +(= (#.(MAKE-DOUBLE-FLOAT #x4083BA73 #x2107A1BA) #.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x3FE00000 #x0) #.(MAKE-DOUBLE-FLOAT #x3FE00000 #x0)) NIL) (= (#.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFF000000) #.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0) #.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) NIL) (= (#.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFF000000) #.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0) #.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0)) NIL) -(= (#.(MAKE-DOUBLE-FLOAT #x41C00000 #x0) #.(MAKE-DOUBLE-FLOAT #x-3E400000 #x800000) #.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0)) NIL) -(= (#.(MAKE-DOUBLE-FLOAT #x41CFFFFF #xFF800000) #.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x3FE00000 #x0) #.(MAKE-DOUBLE-FLOAT #x3FE00000 #x0)) NIL) -(= (#.(MAKE-DOUBLE-FLOAT #x41D00000 #x0) #.(MAKE-DOUBLE-FLOAT #x-3E300000 #x0) #x0 #x0) NIL) -(= (#.(MAKE-DOUBLE-FLOAT #x41D00000 #x0) #.(MAKE-DOUBLE-FLOAT #x-3E300000 #x0) #.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) NIL) -(= (#.(MAKE-DOUBLE-FLOAT #x41D00000 #x400000) #.(MAKE-DOUBLE-FLOAT #x-3E300000 #x0) #.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) NIL) +(= (#.(MAKE-DOUBLE-FLOAT #x41D00000 #x0) #.(MAKE-DOUBLE-FLOAT #x-3E300001 #xFF800000) #.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) NIL) +(= (#.(MAKE-DOUBLE-FLOAT #x41D00000 #x400000) #.(MAKE-DOUBLE-FLOAT #x-3E300001 #xFF800000) #.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) NIL) +(= (#.(MAKE-DOUBLE-FLOAT #x433FFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x-3CC00000 #x0) #.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0) #.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0)) NIL) +(= (#.(MAKE-DOUBLE-FLOAT #x433FFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x-3CC00000 #x0) #.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFFFFFFFF)) NIL) (= (#.(MAKE-DOUBLE-FLOAT #x43AFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x-3C500000 #x0) #.(MAKE-DOUBLE-FLOAT #x43AFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x-3C500000 #x0)) NIL) (= (#.(MAKE-DOUBLE-FLOAT #x43B00000 #x0) #.(MAKE-DOUBLE-FLOAT #x-3C500000 #x0) #.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) NIL) (= (#.(MAKE-DOUBLE-FLOAT #x43C00000 #x0) #.(MAKE-DOUBLE-FLOAT #x-3C400000 #x0) #x0 #x0) NIL) @@ -1978,107 +2008,108 @@ (> (#x0 #.(MAKE-SINGLE-FLOAT #x-21B6F025)) T) (> (#x0 #.(MAKE-SINGLE-FLOAT #x-20B6F025)) T) (> (#x0 #.(MAKE-SINGLE-FLOAT #x0)) NIL) +(> (#x0 #.(MAKE-SINGLE-FLOAT #x3F800000)) NIL) (> (#x0 #.(MAKE-SINGLE-FLOAT #x4DFFFFFF)) NIL) -(> (#x0 #.(MAKE-SINGLE-FLOAT #x4E000000)) NIL) -(> (#x0 #.(MAKE-SINGLE-FLOAT #x4EC00000)) NIL) (> (#x0 #.(MAKE-SINGLE-FLOAT #x4EC90FDB)) NIL) -(> (#x0 #.(MAKE-SINGLE-FLOAT #x5CEE6B28)) NIL) (> (#x0 #.(MAKE-SINGLE-FLOAT #x5D7FFFFF)) NIL) -(> (#x0 #.(MAKE-SINGLE-FLOAT #x5D800000)) NIL) (> (#x0 #.(MAKE-SINGLE-FLOAT #x5E490FDB)) NIL) (> (#x0 #.(MAKE-SINGLE-FLOAT #x5E7FFFFF)) NIL) -(> (#x0 #.(MAKE-SINGLE-FLOAT #x5E800000)) NIL) (> (#x0 #.(MAKE-SINGLE-FLOAT #x5F490FDB)) NIL) -(> (#x0 #.(MAKE-SINGLE-FLOAT #x6C6E6B28)) NIL) -(> (#x0 #.(MAKE-SINGLE-FLOAT #x6D6E6B28)) NIL) (> (#x0 #.(MAKE-DOUBLE-FLOAT #x-80000000 #x0)) NIL) +(> (#x0 #.(MAKE-DOUBLE-FLOAT #x-40100000 #x0)) T) (> (#x0 #.(MAKE-DOUBLE-FLOAT #x-3E26DE05 #x54442D18)) T) (> (#x0 #.(MAKE-DOUBLE-FLOAT #x-3C36DE05 #x54442D18)) T) (> (#x0 #.(MAKE-DOUBLE-FLOAT #x-3C16DE05 #x54442D18)) T) (> (#x0 #.(MAKE-DOUBLE-FLOAT #x-500001 #xFFFFFFFE)) T) (> (#x0 #.(MAKE-DOUBLE-FLOAT #x0 #x0)) NIL) -(> (#x0 #.(MAKE-DOUBLE-FLOAT #x40734413 #x509F79FF)) NIL) -(> (#x0 #.(MAKE-DOUBLE-FLOAT #x408D6413 #x509F7A00)) NIL) -(> (#x0 #.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFF000000)) NIL) (> (#x0 #.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFFFFFFFF)) NIL) -(> (#x0 #.(MAKE-DOUBLE-FLOAT #x41D7FFFF #xFF800000)) NIL) (> (#x0 #.(MAKE-DOUBLE-FLOAT #x41D921FB #x537B1D3D)) NIL) -(> (#x0 #.(MAKE-DOUBLE-FLOAT #x439DCD64 #xFF1194D8)) NIL) (> (#x0 #.(MAKE-DOUBLE-FLOAT #x43AFFFFF #xFFFFFFFF)) NIL) -(> (#x0 #.(MAKE-DOUBLE-FLOAT #x43B00000 #x0)) NIL) (> (#x0 #.(MAKE-DOUBLE-FLOAT #x43C921FB #x54442D18)) NIL) (> (#x0 #.(MAKE-DOUBLE-FLOAT #x43CFFFFF #xFFFFFFFF)) NIL) -(> (#x0 #.(MAKE-DOUBLE-FLOAT #x43D00000 #x0)) NIL) (> (#x0 #.(MAKE-DOUBLE-FLOAT #x43E921FB #x54442D18)) NIL) -(> (#x0 #.(MAKE-DOUBLE-FLOAT #x458DCD65 #x0)) NIL) -(> (#x0 #.(MAKE-DOUBLE-FLOAT #x45ADCD65 #x0)) NIL) (> (#x0 #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) NIL) (> (#x1 #.(MAKE-SINGLE-FLOAT #x0)) T) (> (#x1 #.(MAKE-DOUBLE-FLOAT #x0 #x0)) T) (> (#x1 #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) NIL) (> (#x7 #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) NIL) +(> (#x1FFFFFFC #.(MAKE-SINGLE-FLOAT #x3F800000)) T) (> (#x1FFFFFFF #.(MAKE-DOUBLE-FLOAT #x0 #x0)) T) (> (#x20000000 #.(MAKE-DOUBLE-FLOAT #x0 #x0)) T) (> (#x20000001 #.(MAKE-DOUBLE-FLOAT #x0 #x0)) T) (> (#x3FFFFFF7 #.(MAKE-SINGLE-FLOAT #x0)) T) +(> (#x10C6F7A0B5E #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) NIL) (> (#x4189374BC6A7E #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) NIL) +(> (#xFFFFFFFFFFFFFFC #.(MAKE-SINGLE-FLOAT #x3F800000)) T) (> (#xFFFFFFFFFFFFFFF #.(MAKE-DOUBLE-FLOAT #x0 #x0)) T) (> (#x1000000000000000 #.(MAKE-DOUBLE-FLOAT #x0 #x0)) T) (> (#x1000000000000001 #.(MAKE-DOUBLE-FLOAT #x0 #x0)) T) (> (#x1FFFFFFFFFFFFFF7 #.(MAKE-SINGLE-FLOAT #x0)) T) +(> (#x3FFFFFFFFFFFFFFC #.(MAKE-SINGLE-FLOAT #x3F800000)) T) (> (#x3FFFFFFFFFFFFFFF #.(MAKE-DOUBLE-FLOAT #x0 #x0)) T) (> (#x4000000000000000 #.(MAKE-DOUBLE-FLOAT #x0 #x0)) T) (> (#x4000000000000001 #.(MAKE-DOUBLE-FLOAT #x0 #x0)) T) (> (#x7FFFFFFFFFFFFFF7 #.(MAKE-SINGLE-FLOAT #x0)) T) -(> (#.(MAKE-SINGLE-FLOAT #x-80000000) #x0) NIL) (> (#.(MAKE-SINGLE-FLOAT #x-80000000) #.(MAKE-SINGLE-FLOAT #x-80000000)) NIL) +(> (#.(MAKE-SINGLE-FLOAT #x-80000000) #.(MAKE-SINGLE-FLOAT #x-40800000)) T) (> (#.(MAKE-SINGLE-FLOAT #x-80000000) #.(MAKE-SINGLE-FLOAT #x0)) NIL) -(> (#.(MAKE-SINGLE-FLOAT #x-80000000) #.(MAKE-SINGLE-FLOAT #x3F7FFFEF)) NIL) (> (#.(MAKE-SINGLE-FLOAT #x-80000000) #.(MAKE-SINGLE-FLOAT #x3F800000)) NIL) (> (#.(MAKE-SINGLE-FLOAT #x-80000000) #.(MAKE-SINGLE-FLOAT #x4E6E6B28)) NIL) (> (#.(MAKE-SINGLE-FLOAT #x-80000000) #.(MAKE-SINGLE-FLOAT #x5CEE6B28)) NIL) (> (#.(MAKE-SINGLE-FLOAT #x-80000000) #.(MAKE-SINGLE-FLOAT #x6C6E6B28)) NIL) (> (#.(MAKE-SINGLE-FLOAT #x-80000000) #.(MAKE-SINGLE-FLOAT #x6D6E6B28)) NIL) -(> (#.(MAKE-SINGLE-FLOAT #x-80000000) #.(MAKE-DOUBLE-FLOAT #x-80000000 #x0)) NIL) (> (#.(MAKE-SINGLE-FLOAT #x-80000000) #.(MAKE-DOUBLE-FLOAT #x439DCD64 #xFF1194D8)) NIL) (> (#.(MAKE-SINGLE-FLOAT #x-80000000) #.(MAKE-DOUBLE-FLOAT #x458DCD65 #x0)) NIL) (> (#.(MAKE-SINGLE-FLOAT #x-80000000) #.(MAKE-DOUBLE-FLOAT #x45ADCD65 #x0)) NIL) (> (#.(MAKE-SINGLE-FLOAT #x-7F800000) #.(MAKE-SINGLE-FLOAT #x-7F800000)) NIL) -(> (#.(MAKE-SINGLE-FLOAT #x-40804189) #.(MAKE-SINGLE-FLOAT #x-40804189)) NIL) -(> (#.(MAKE-SINGLE-FLOAT #x-40804189) #.(MAKE-SINGLE-FLOAT #x3F7FFFEF)) NIL) -(> (#.(MAKE-SINGLE-FLOAT #x-40804189) #.(MAKE-SINGLE-FLOAT #x5903126F)) NIL) (> (#.(MAKE-SINGLE-FLOAT #x-40800000) #.(MAKE-SINGLE-FLOAT #x-40800000)) NIL) +(> (#.(MAKE-SINGLE-FLOAT #x-40800000) #.(MAKE-SINGLE-FLOAT #x0)) NIL) (> (#.(MAKE-SINGLE-FLOAT #x-40800000) #.(MAKE-SINGLE-FLOAT #x3F800000)) NIL) (> (#.(MAKE-SINGLE-FLOAT #x-40800000) #.(MAKE-SINGLE-FLOAT #x40E00000)) NIL) +(> (#.(MAKE-SINGLE-FLOAT #x-40800000) #.(MAKE-SINGLE-FLOAT #x4B7FFFFF)) NIL) (> (#.(MAKE-SINGLE-FLOAT #x-40800000) #.(MAKE-SINGLE-FLOAT #x4E000000)) NIL) (> (#.(MAKE-SINGLE-FLOAT #x-40800000) #.(MAKE-SINGLE-FLOAT #x5D800000)) NIL) (> (#.(MAKE-SINGLE-FLOAT #x-40800000) #.(MAKE-SINGLE-FLOAT #x5E800000)) NIL) +(> (#.(MAKE-SINGLE-FLOAT #x-4036F025) #.(MAKE-SINGLE-FLOAT #x-4036F025)) NIL) (> (#.(MAKE-SINGLE-FLOAT #x-4036F025) #.(MAKE-SINGLE-FLOAT #x-3136F025)) T) (> (#.(MAKE-SINGLE-FLOAT #x-4036F025) #.(MAKE-SINGLE-FLOAT #x-21B6F025)) T) (> (#.(MAKE-SINGLE-FLOAT #x-4036F025) #.(MAKE-SINGLE-FLOAT #x-20B6F025)) T) (> (#.(MAKE-SINGLE-FLOAT #x-4036F025) #.(MAKE-SINGLE-FLOAT #x3FC90FDB)) NIL) (> (#.(MAKE-SINGLE-FLOAT #x-3FB6F025) #.(MAKE-SINGLE-FLOAT #x-3FB6F025)) NIL) (> (#.(MAKE-SINGLE-FLOAT #x-3FB6F025) #.(MAKE-SINGLE-FLOAT #x40490FDB)) NIL) -(> (#.(MAKE-SINGLE-FLOAT #x-368C1A80) #.(MAKE-SINGLE-FLOAT #x497423F0)) NIL) +(> (#.(MAKE-SINGLE-FLOAT #x-34800000) #.(MAKE-SINGLE-FLOAT #x-40800000)) NIL) +(> (#.(MAKE-SINGLE-FLOAT #x-34800000) #.(MAKE-SINGLE-FLOAT #x-34800000)) NIL) +(> (#.(MAKE-SINGLE-FLOAT #x-34800000) #.(MAKE-SINGLE-FLOAT #x4B7FFFFF)) NIL) +(> (#.(MAKE-SINGLE-FLOAT #x-34800000) #.(MAKE-SINGLE-FLOAT #x4DFFFFFF)) NIL) +(> (#.(MAKE-SINGLE-FLOAT #x-34800000) #.(MAKE-SINGLE-FLOAT #x5D7FFFFF)) NIL) +(> (#.(MAKE-SINGLE-FLOAT #x-34800000) #.(MAKE-SINGLE-FLOAT #x5E7FFFFF)) NIL) +(> (#.(MAKE-SINGLE-FLOAT #x-32000000) #.(MAKE-SINGLE-FLOAT #x-40800000)) NIL) +(> (#.(MAKE-SINGLE-FLOAT #x-32000000) #.(MAKE-SINGLE-FLOAT #x-34800000)) NIL) (> (#.(MAKE-SINGLE-FLOAT #x-32000000) #.(MAKE-SINGLE-FLOAT #x-32000000)) NIL) +(> (#.(MAKE-SINGLE-FLOAT #x-32000000) #.(MAKE-SINGLE-FLOAT #x0)) NIL) (> (#.(MAKE-SINGLE-FLOAT #x-32000000) #.(MAKE-SINGLE-FLOAT #x4DFFFFFF)) NIL) (> (#.(MAKE-SINGLE-FLOAT #x-32000000) #.(MAKE-SINGLE-FLOAT #x4E000000)) NIL) (> (#.(MAKE-SINGLE-FLOAT #x-31800000) #.(MAKE-SINGLE-FLOAT #x-31800000)) NIL) (> (#.(MAKE-SINGLE-FLOAT #x-31800000) #.(MAKE-SINGLE-FLOAT #x4E800000)) NIL) -(> (#.(MAKE-SINGLE-FLOAT #x-31400000) #.(MAKE-SINGLE-FLOAT #x4EC00000)) NIL) (> (#.(MAKE-SINGLE-FLOAT #x-3136F025) #.(MAKE-SINGLE-FLOAT #x-3136F025)) NIL) (> (#.(MAKE-SINGLE-FLOAT #x-3136F025) #.(MAKE-SINGLE-FLOAT #x4EC90FDB)) NIL) (> (#.(MAKE-SINGLE-FLOAT #x-31000000) #.(MAKE-SINGLE-FLOAT #x4F000000)) NIL) (> (#.(MAKE-SINGLE-FLOAT #x-231194D8) #.(MAKE-SINGLE-FLOAT #x-231194D8)) NIL) (> (#.(MAKE-SINGLE-FLOAT #x-231194D8) #.(MAKE-SINGLE-FLOAT #x5CEE6B28)) NIL) +(> (#.(MAKE-SINGLE-FLOAT #x-22800000) #.(MAKE-SINGLE-FLOAT #x-40800000)) NIL) +(> (#.(MAKE-SINGLE-FLOAT #x-22800000) #.(MAKE-SINGLE-FLOAT #x-34800000)) NIL) (> (#.(MAKE-SINGLE-FLOAT #x-22800000) #.(MAKE-SINGLE-FLOAT #x-22800000)) NIL) +(> (#.(MAKE-SINGLE-FLOAT #x-22800000) #.(MAKE-SINGLE-FLOAT #x0)) NIL) (> (#.(MAKE-SINGLE-FLOAT #x-22800000) #.(MAKE-SINGLE-FLOAT #x5D7FFFFF)) NIL) (> (#.(MAKE-SINGLE-FLOAT #x-22800000) #.(MAKE-SINGLE-FLOAT #x5D800000)) NIL) (> (#.(MAKE-SINGLE-FLOAT #x-22000000) #.(MAKE-SINGLE-FLOAT #x-22000000)) NIL) (> (#.(MAKE-SINGLE-FLOAT #x-22000000) #.(MAKE-SINGLE-FLOAT #x5E000000)) NIL) (> (#.(MAKE-SINGLE-FLOAT #x-21B6F025) #.(MAKE-SINGLE-FLOAT #x-21B6F025)) NIL) (> (#.(MAKE-SINGLE-FLOAT #x-21B6F025) #.(MAKE-SINGLE-FLOAT #x5E490FDB)) NIL) +(> (#.(MAKE-SINGLE-FLOAT #x-21800000) #.(MAKE-SINGLE-FLOAT #x-40800000)) NIL) +(> (#.(MAKE-SINGLE-FLOAT #x-21800000) #.(MAKE-SINGLE-FLOAT #x-34800000)) NIL) (> (#.(MAKE-SINGLE-FLOAT #x-21800000) #.(MAKE-SINGLE-FLOAT #x-21800000)) NIL) +(> (#.(MAKE-SINGLE-FLOAT #x-21800000) #.(MAKE-SINGLE-FLOAT #x0)) NIL) (> (#.(MAKE-SINGLE-FLOAT #x-21800000) #.(MAKE-SINGLE-FLOAT #x4E000000)) NIL) (> (#.(MAKE-SINGLE-FLOAT #x-21800000) #.(MAKE-SINGLE-FLOAT #x5E7FFFFF)) NIL) (> (#.(MAKE-SINGLE-FLOAT #x-21800000) #.(MAKE-SINGLE-FLOAT #x5E800000)) NIL) @@ -2091,11 +2122,13 @@ (> (#.(MAKE-SINGLE-FLOAT #x-129194D8) #.(MAKE-SINGLE-FLOAT #x-129194D8)) NIL) (> (#.(MAKE-SINGLE-FLOAT #x-129194D8) #.(MAKE-SINGLE-FLOAT #x6D6E6B28)) NIL) (> (#.(MAKE-SINGLE-FLOAT #x-800001) #.(MAKE-SINGLE-FLOAT #x-800001)) NIL) +(> (#.(MAKE-SINGLE-FLOAT #x-800001) #.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF)) T) (> (#.(MAKE-SINGLE-FLOAT #x-800000) #.(MAKE-SINGLE-FLOAT #x-800000)) NIL) (> (#.(MAKE-SINGLE-FLOAT #x0) #x-1) T) (> (#.(MAKE-SINGLE-FLOAT #x0) #x0) NIL) (> (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x-80000000)) NIL) (> (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x-40800000)) T) +(> (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x-34800000)) T) (> (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x-32000000)) T) (> (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x-3136F025)) T) (> (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x-22800000)) T) @@ -2110,82 +2143,88 @@ (> (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x3F8CCCCD)) NIL) (> (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x40490FDB)) NIL) (> (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x497423F0)) NIL) +(> (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x4B7FFFFF)) NIL) +(> (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x4DFFFFFF)) NIL) (> (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x4E000000)) NIL) -(> (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x4E800000)) NIL) +(> (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x538637BD)) NIL) +(> (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x540637BD)) NIL) (> (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x5883126F)) NIL) (> (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x5903126F)) NIL) +(> (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x5D7FFFFF)) NIL) (> (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x5D800000)) NIL) +(> (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x5E7FFFFF)) NIL) (> (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x5E800000)) NIL) +(> (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-DOUBLE-FLOAT #x-80000000 #x0)) NIL) (> (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) NIL) (> (#.(MAKE-SINGLE-FLOAT #x800000) #.(MAKE-SINGLE-FLOAT #x800000)) NIL) (> (#.(MAKE-SINGLE-FLOAT #x3089705F) #.(MAKE-SINGLE-FLOAT #x3089705F)) NIL) (> (#.(MAKE-SINGLE-FLOAT #x33000001) #.(MAKE-SINGLE-FLOAT #x33000001)) NIL) (> (#.(MAKE-SINGLE-FLOAT #x33800001) #.(MAKE-SINGLE-FLOAT #x33800001)) NIL) +(> (#.(MAKE-SINGLE-FLOAT #x358637BD) #.(MAKE-SINGLE-FLOAT #x358637BD)) NIL) (> (#.(MAKE-SINGLE-FLOAT #x3A83126F) #.(MAKE-SINGLE-FLOAT #x3A83126F)) NIL) (> (#.(MAKE-SINGLE-FLOAT #x3D800000) #.(MAKE-SINGLE-FLOAT #x0)) T) (> (#.(MAKE-SINGLE-FLOAT #x3D800000) #.(MAKE-SINGLE-FLOAT #x3D800000)) NIL) (> (#.(MAKE-SINGLE-FLOAT #x3D800000) #.(MAKE-SINGLE-FLOAT #x3F800000)) NIL) (> (#.(MAKE-SINGLE-FLOAT #x3F000000) #.(MAKE-SINGLE-FLOAT #x0)) T) (> (#.(MAKE-SINGLE-FLOAT #x3F000000) #.(MAKE-SINGLE-FLOAT #x3F000000)) NIL) -(> (#.(MAKE-SINGLE-FLOAT #x3F0CCCCD) #.(MAKE-SINGLE-FLOAT #x3F0CCCCD)) NIL) -(> (#.(MAKE-SINGLE-FLOAT #x3F19999A) #.(MAKE-SINGLE-FLOAT #x3F19999A)) NIL) -(> (#.(MAKE-SINGLE-FLOAT #x3F266666) #.(MAKE-SINGLE-FLOAT #x3F266666)) NIL) (> (#.(MAKE-SINGLE-FLOAT #x3F333333) #.(MAKE-SINGLE-FLOAT #x3F333333)) NIL) -(> (#.(MAKE-SINGLE-FLOAT #x3F59999A) #.(MAKE-SINGLE-FLOAT #x3F59999A)) NIL) -(> (#.(MAKE-SINGLE-FLOAT #x3F666666) #.(MAKE-SINGLE-FLOAT #x3F666666)) NIL) +(> (#.(MAKE-SINGLE-FLOAT #x3F800000) #x0) T) (> (#.(MAKE-SINGLE-FLOAT #x3F800000) #.(MAKE-SINGLE-FLOAT #x-80000000)) T) (> (#.(MAKE-SINGLE-FLOAT #x3F800000) #.(MAKE-SINGLE-FLOAT #x-40800000)) T) +(> (#.(MAKE-SINGLE-FLOAT #x3F800000) #.(MAKE-SINGLE-FLOAT #x-32000000)) T) +(> (#.(MAKE-SINGLE-FLOAT #x3F800000) #.(MAKE-SINGLE-FLOAT #x-22800000)) T) +(> (#.(MAKE-SINGLE-FLOAT #x3F800000) #.(MAKE-SINGLE-FLOAT #x-21800000)) T) (> (#.(MAKE-SINGLE-FLOAT #x3F800000) #.(MAKE-SINGLE-FLOAT #x0)) T) (> (#.(MAKE-SINGLE-FLOAT #x3F800000) #.(MAKE-SINGLE-FLOAT #x3D800000)) T) (> (#.(MAKE-SINGLE-FLOAT #x3F800000) #.(MAKE-SINGLE-FLOAT #x3F800000)) NIL) -(> (#.(MAKE-SINGLE-FLOAT #x3F800000) #.(MAKE-DOUBLE-FLOAT #x-40100000 #x0)) T) -(> (#.(MAKE-SINGLE-FLOAT #x3F800000) #.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0)) NIL) +(> (#.(MAKE-SINGLE-FLOAT #x3F800000) #.(MAKE-SINGLE-FLOAT #x4DFFFFFF)) NIL) +(> (#.(MAKE-SINGLE-FLOAT #x3F800000) #.(MAKE-SINGLE-FLOAT #x5D7FFFFF)) NIL) +(> (#.(MAKE-SINGLE-FLOAT #x3F800000) #.(MAKE-SINGLE-FLOAT #x5E7FFFFF)) NIL) (> (#.(MAKE-SINGLE-FLOAT #x3F800000) #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) NIL) (> (#.(MAKE-SINGLE-FLOAT #x3F8CCCCD) #.(MAKE-SINGLE-FLOAT #x3F8CCCCD)) NIL) (> (#.(MAKE-SINGLE-FLOAT #x3FC00000) #.(MAKE-SINGLE-FLOAT #x3F800000)) T) (> (#.(MAKE-SINGLE-FLOAT #x3FC00000) #.(MAKE-SINGLE-FLOAT #x3FC00000)) NIL) (> (#.(MAKE-SINGLE-FLOAT #x40000000) #.(MAKE-SINGLE-FLOAT #x40000000)) NIL) (> (#.(MAKE-SINGLE-FLOAT #x40490FDB) #.(MAKE-SINGLE-FLOAT #x40490FDB)) NIL) -(> (#.(MAKE-SINGLE-FLOAT #x41600000) #.(MAKE-SINGLE-FLOAT #x0)) T) -(> (#.(MAKE-SINGLE-FLOAT #x41600000) #.(MAKE-SINGLE-FLOAT #x41600000)) NIL) -(> (#.(MAKE-SINGLE-FLOAT #x41600000) #.(MAKE-SINGLE-FLOAT #x4B800000)) NIL) -(> (#.(MAKE-SINGLE-FLOAT #x41600000) #.(MAKE-SINGLE-FLOAT #x4D800000)) NIL) (> (#.(MAKE-SINGLE-FLOAT #x42C80000) #.(MAKE-SINGLE-FLOAT #x42C80000)) NIL) (> (#.(MAKE-SINGLE-FLOAT #x447A0000) #.(MAKE-SINGLE-FLOAT #x447A0000)) NIL) (> (#.(MAKE-SINGLE-FLOAT #x49742400) #.(MAKE-SINGLE-FLOAT #x49742400)) NIL) +(> (#.(MAKE-SINGLE-FLOAT #x4B7FFFFF) #.(MAKE-SINGLE-FLOAT #x4B7FFFFF)) NIL) +(> (#.(MAKE-SINGLE-FLOAT #x4DFFFFFF) #x0) T) (> (#.(MAKE-SINGLE-FLOAT #x4DFFFFFF) #.(MAKE-SINGLE-FLOAT #x-32000000)) T) +(> (#.(MAKE-SINGLE-FLOAT #x4DFFFFFF) #.(MAKE-SINGLE-FLOAT #x0)) T) (> (#.(MAKE-SINGLE-FLOAT #x4DFFFFFF) #.(MAKE-SINGLE-FLOAT #x4DFFFFFF)) NIL) -(> (#.(MAKE-SINGLE-FLOAT #x4E000000) #x0) T) -(> (#.(MAKE-SINGLE-FLOAT #x4E000000) #.(MAKE-SINGLE-FLOAT #x0)) T) (> (#.(MAKE-SINGLE-FLOAT #x4E000000) #.(MAKE-SINGLE-FLOAT #x4E000000)) NIL) (> (#.(MAKE-SINGLE-FLOAT #x4E6E6B28) #.(MAKE-SINGLE-FLOAT #x4E6E6B28)) NIL) -(> (#.(MAKE-SINGLE-FLOAT #x4E800000) #.(MAKE-SINGLE-FLOAT #x3F000000)) T) -(> (#.(MAKE-SINGLE-FLOAT #x4E800000) #.(MAKE-SINGLE-FLOAT #x4E800000)) NIL) (> (#.(MAKE-SINGLE-FLOAT #x4EC90FDB) #x0) T) (> (#.(MAKE-SINGLE-FLOAT #x4EC90FDB) #.(MAKE-SINGLE-FLOAT #x4EC90FDB)) NIL) (> (#.(MAKE-SINGLE-FLOAT #x4F000000) #.(MAKE-SINGLE-FLOAT #x4F800000)) NIL) +(> (#.(MAKE-SINGLE-FLOAT #x538637BD) #.(MAKE-SINGLE-FLOAT #x0)) T) +(> (#.(MAKE-SINGLE-FLOAT #x538637BD) #.(MAKE-SINGLE-FLOAT #x538637BD)) NIL) (> (#.(MAKE-SINGLE-FLOAT #x5883126F) #.(MAKE-SINGLE-FLOAT #x0)) T) (> (#.(MAKE-SINGLE-FLOAT #x5883126F) #.(MAKE-SINGLE-FLOAT #x5883126F)) NIL) +(> (#.(MAKE-SINGLE-FLOAT #x5D7FFFFF) #x0) T) (> (#.(MAKE-SINGLE-FLOAT #x5D7FFFFF) #.(MAKE-SINGLE-FLOAT #x-22800000)) T) +(> (#.(MAKE-SINGLE-FLOAT #x5D7FFFFF) #.(MAKE-SINGLE-FLOAT #x0)) T) (> (#.(MAKE-SINGLE-FLOAT #x5D7FFFFF) #.(MAKE-SINGLE-FLOAT #x5D7FFFFF)) NIL) -(> (#.(MAKE-SINGLE-FLOAT #x5D800000) #x0) T) -(> (#.(MAKE-SINGLE-FLOAT #x5D800000) #.(MAKE-SINGLE-FLOAT #x0)) T) (> (#.(MAKE-SINGLE-FLOAT #x5D800000) #.(MAKE-SINGLE-FLOAT #x5D800000)) NIL) (> (#.(MAKE-SINGLE-FLOAT #x5E490FDB) #x0) T) (> (#.(MAKE-SINGLE-FLOAT #x5E490FDB) #.(MAKE-SINGLE-FLOAT #x5E490FDB)) NIL) +(> (#.(MAKE-SINGLE-FLOAT #x5E7FFFFF) #x0) T) (> (#.(MAKE-SINGLE-FLOAT #x5E7FFFFF) #.(MAKE-SINGLE-FLOAT #x-21800000)) T) +(> (#.(MAKE-SINGLE-FLOAT #x5E7FFFFF) #.(MAKE-SINGLE-FLOAT #x0)) T) (> (#.(MAKE-SINGLE-FLOAT #x5E7FFFFF) #.(MAKE-SINGLE-FLOAT #x5E7FFFFF)) NIL) -(> (#.(MAKE-SINGLE-FLOAT #x5E800000) #x0) T) -(> (#.(MAKE-SINGLE-FLOAT #x5E800000) #.(MAKE-SINGLE-FLOAT #x0)) T) (> (#.(MAKE-SINGLE-FLOAT #x5E800000) #.(MAKE-SINGLE-FLOAT #x5E800000)) NIL) -(> (#.(MAKE-SINGLE-FLOAT #x5F000000) #.(MAKE-SINGLE-FLOAT #x5F000000)) NIL) (> (#.(MAKE-SINGLE-FLOAT #x5F000000) #.(MAKE-SINGLE-FLOAT #x5F800000)) NIL) (> (#.(MAKE-SINGLE-FLOAT #x5F490FDB) #x0) T) (> (#.(MAKE-SINGLE-FLOAT #x5F490FDB) #.(MAKE-SINGLE-FLOAT #x5F490FDB)) NIL) (> (#.(MAKE-SINGLE-FLOAT #x7F7FFFFF) #.(MAKE-SINGLE-FLOAT #x7F7FFFFF)) NIL) +(> (#.(MAKE-SINGLE-FLOAT #x7F7FFFFF) #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) NIL) (> (#.(MAKE-SINGLE-FLOAT #x7F800000) #.(MAKE-SINGLE-FLOAT #x7F800000)) NIL) (> (#.(MAKE-DOUBLE-FLOAT #x-80000000 #x0) #x0) NIL) +(> (#.(MAKE-DOUBLE-FLOAT #x-80000000 #x0) #.(MAKE-SINGLE-FLOAT #x0)) NIL) (> (#.(MAKE-DOUBLE-FLOAT #x-80000000 #x0) #.(MAKE-DOUBLE-FLOAT #x-80000000 #x0)) NIL) +(> (#.(MAKE-DOUBLE-FLOAT #x-80000000 #x0) #.(MAKE-DOUBLE-FLOAT #x-40100000 #x0)) T) (> (#.(MAKE-DOUBLE-FLOAT #x-80000000 #x0) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) NIL) (> (#.(MAKE-DOUBLE-FLOAT #x-80000000 #x0) #.(MAKE-DOUBLE-FLOAT #x20100000 #x1)) NIL) (> (#.(MAKE-DOUBLE-FLOAT #x-80000000 #x0) #.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0)) NIL) @@ -2199,14 +2238,15 @@ (> (#.(MAKE-DOUBLE-FLOAT #x-80000000 #x0) #.(MAKE-DOUBLE-FLOAT #x5FEFFFFF #xFFFFFFFF)) NIL) (> (#.(MAKE-DOUBLE-FLOAT #x-7FF00000 #x0) #.(MAKE-DOUBLE-FLOAT #x-7FF00000 #x0)) NIL) (> (#.(MAKE-DOUBLE-FLOAT #x-402D413D #x33018866) #.(MAKE-DOUBLE-FLOAT #x-40100000 #x0)) T) -(> (#.(MAKE-DOUBLE-FLOAT #x-40100000 #x0) #.(MAKE-SINGLE-FLOAT #x3F800000)) NIL) +(> (#.(MAKE-DOUBLE-FLOAT #x-40100000 #x0) #.(MAKE-SINGLE-FLOAT #x-40800000)) NIL) (> (#.(MAKE-DOUBLE-FLOAT #x-40100000 #x0) #.(MAKE-DOUBLE-FLOAT #x-40100000 #x0)) NIL) (> (#.(MAKE-DOUBLE-FLOAT #x-40100000 #x0) #.(MAKE-DOUBLE-FLOAT #x-3F8BC000 #x0)) T) -(> (#.(MAKE-DOUBLE-FLOAT #x-40100000 #x0) #.(MAKE-DOUBLE-FLOAT #x-3F721800 #x0)) T) +(> (#.(MAKE-DOUBLE-FLOAT #x-40100000 #x0) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) NIL) (> (#.(MAKE-DOUBLE-FLOAT #x-40100000 #x0) #.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0)) NIL) (> (#.(MAKE-DOUBLE-FLOAT #x-40100000 #x0) #.(MAKE-DOUBLE-FLOAT #x401C0000 #x0)) NIL) (> (#.(MAKE-DOUBLE-FLOAT #x-40100000 #x0) #.(MAKE-DOUBLE-FLOAT #x40733000 #x0)) NIL) -(> (#.(MAKE-DOUBLE-FLOAT #x-40100000 #x0) #.(MAKE-DOUBLE-FLOAT #x408D6000 #x0)) NIL) +(> (#.(MAKE-DOUBLE-FLOAT #x-40100000 #x0) #.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFFFFFFFF)) NIL) +(> (#.(MAKE-DOUBLE-FLOAT #x-40100000 #x0) #.(MAKE-DOUBLE-FLOAT #x433FFFFF #xFFFFFFFF)) NIL) (> (#.(MAKE-DOUBLE-FLOAT #x-4006DE05 #x54442D18) #.(MAKE-DOUBLE-FLOAT #x-4006DE05 #x54442D18)) NIL) (> (#.(MAKE-DOUBLE-FLOAT #x-4006DE05 #x54442D18) #.(MAKE-DOUBLE-FLOAT #x-3E26DE05 #x54442D18)) T) (> (#.(MAKE-DOUBLE-FLOAT #x-4006DE05 #x54442D18) #.(MAKE-DOUBLE-FLOAT #x-3C36DE05 #x54442D18)) T) @@ -2217,9 +2257,7 @@ (> (#.(MAKE-DOUBLE-FLOAT #x-3FF6DE05 #x54442D18) #.(MAKE-DOUBLE-FLOAT #x400921FB #x54442D18)) NIL) (> (#.(MAKE-DOUBLE-FLOAT #x-3FD20000 #x0) #.(MAKE-DOUBLE-FLOAT #x-3FD20000 #x0)) NIL) (> (#.(MAKE-DOUBLE-FLOAT #x-3FD20000 #x0) #.(MAKE-DOUBLE-FLOAT #x-3F8BC000 #x0)) T) -(> (#.(MAKE-DOUBLE-FLOAT #x-3FD20000 #x0) #.(MAKE-DOUBLE-FLOAT #x-3F721800 #x0)) T) (> (#.(MAKE-DOUBLE-FLOAT #x-3FD20000 #x0) #.(MAKE-DOUBLE-FLOAT #x40733000 #x0)) NIL) -(> (#.(MAKE-DOUBLE-FLOAT #x-3FD20000 #x0) #.(MAKE-DOUBLE-FLOAT #x408D6000 #x0)) NIL) (> (#.(MAKE-DOUBLE-FLOAT #x-3F8CB000 #x0) #.(MAKE-DOUBLE-FLOAT #x-3F8CB000 #x0)) NIL) (> (#.(MAKE-DOUBLE-FLOAT #x-3F8CB000 #x0) #.(MAKE-DOUBLE-FLOAT #x40742000 #x0)) NIL) (> (#.(MAKE-DOUBLE-FLOAT #x-3F8BD000 #x0) #.(MAKE-DOUBLE-FLOAT #x40734000 #x0)) NIL) @@ -2227,53 +2265,46 @@ (> (#.(MAKE-DOUBLE-FLOAT #x-3F8BCB1A #x420F4374) #.(MAKE-DOUBLE-FLOAT #x40734413 #x509F79FF)) NIL) (> (#.(MAKE-DOUBLE-FLOAT #x-3F8BC000 #x0) #.(MAKE-DOUBLE-FLOAT #x-3F8BC000 #x0)) NIL) (> (#.(MAKE-DOUBLE-FLOAT #x-3F8BC000 #x0) #.(MAKE-DOUBLE-FLOAT #x40733000 #x0)) NIL) -(> (#.(MAKE-DOUBLE-FLOAT #x-3F8BC000 #x0) #.(MAKE-DOUBLE-FLOAT #x40735000 #x0)) NIL) (> (#.(MAKE-DOUBLE-FLOAT #x-3F7C458D #x2107A1BA) #.(MAKE-DOUBLE-FLOAT #x-3F7C458D #x2107A1BA)) NIL) (> (#.(MAKE-DOUBLE-FLOAT #x-3F7C458D #x2107A1BA) #.(MAKE-DOUBLE-FLOAT #x4083BA09 #xA84FBD00)) NIL) -(> (#.(MAKE-DOUBLE-FLOAT #x-3F7C3D8D #x2107A1BA) #.(MAKE-DOUBLE-FLOAT #x-3F7C3D8D #x2107A1BA)) NIL) -(> (#.(MAKE-DOUBLE-FLOAT #x-3F7C3D8D #x2107A1BA) #.(MAKE-DOUBLE-FLOAT #x4083C209 #xA84FBD00)) NIL) (> (#.(MAKE-DOUBLE-FLOAT #x-3F78B6F0 #xD52D3052) #.(MAKE-DOUBLE-FLOAT #x-3F78B6F0 #xD52D3052)) NIL) (> (#.(MAKE-DOUBLE-FLOAT #x-3F78B6F0 #xD52D3052) #.(MAKE-DOUBLE-FLOAT #x408628B7 #x6E3A7B61)) NIL) -(> (#.(MAKE-DOUBLE-FLOAT #x-3F729000 #x0) #.(MAKE-DOUBLE-FLOAT #x-3F729000 #x0)) NIL) -(> (#.(MAKE-DOUBLE-FLOAT #x-3F729000 #x0) #.(MAKE-DOUBLE-FLOAT #x408DD800 #x0)) NIL) -(> (#.(MAKE-DOUBLE-FLOAT #x-3F72231A #x420F4374) #.(MAKE-DOUBLE-FLOAT #x-3F72231A #x420F4374)) NIL) -(> (#.(MAKE-DOUBLE-FLOAT #x-3F72231A #x420F4374) #.(MAKE-DOUBLE-FLOAT #x408D6413 #x509F7A00)) NIL) -(> (#.(MAKE-DOUBLE-FLOAT #x-3F722000 #x0) #.(MAKE-DOUBLE-FLOAT #x408D6800 #x0)) NIL) -(> (#.(MAKE-DOUBLE-FLOAT #x-3F721800 #x0) #.(MAKE-DOUBLE-FLOAT #x-3F721800 #x0)) NIL) -(> (#.(MAKE-DOUBLE-FLOAT #x-3F721800 #x0) #.(MAKE-DOUBLE-FLOAT #x408D6000 #x0)) NIL) +(> (#.(MAKE-DOUBLE-FLOAT #x-3F722B1A #x420F4374) #.(MAKE-DOUBLE-FLOAT #x-3F722B1A #x420F4374)) NIL) +(> (#.(MAKE-DOUBLE-FLOAT #x-3F722B1A #x420F4374) #.(MAKE-DOUBLE-FLOAT #x408D5C13 #x509F7A00)) NIL) (> (#.(MAKE-DOUBLE-FLOAT #x-3F6F3800 #x0) #.(MAKE-DOUBLE-FLOAT #x40900000 #x0)) NIL) (> (#.(MAKE-DOUBLE-FLOAT #x-3F6F3400 #x0) #.(MAKE-DOUBLE-FLOAT #x408FF800 #x0)) NIL) -(> (#.(MAKE-DOUBLE-FLOAT #x-3F6C3EC7 #x9083D0DD) #.(MAKE-DOUBLE-FLOAT #x-3F6C3EC7 #x9083D0DD)) NIL) -(> (#.(MAKE-DOUBLE-FLOAT #x-3F6C3EC7 #x9083D0DD) #.(MAKE-DOUBLE-FLOAT #x4093C104 #xD427DE80)) NIL) (> (#.(MAKE-DOUBLE-FLOAT #x-3E400001 #xFF000000) #.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFF000000)) NIL) (> (#.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0) #.(MAKE-DOUBLE-FLOAT #x-40100000 #x0)) NIL) (> (#.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0) #.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0)) NIL) -(> (#.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0) #.(MAKE-DOUBLE-FLOAT #x-3E400000 #x800000)) T) -(> (#.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0) #.(MAKE-DOUBLE-FLOAT #x-3E200000 #x0)) T) +(> (#.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0) #.(MAKE-DOUBLE-FLOAT #x-3CC00000 #x0)) T) (> (#.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) NIL) +(> (#.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0) #.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xE0000000)) NIL) (> (#.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0) #.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFF000000)) NIL) (> (#.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0) #.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFFFFFFFF)) NIL) -(> (#.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0) #.(MAKE-DOUBLE-FLOAT #x41C00000 #x0)) NIL) -(> (#.(MAKE-DOUBLE-FLOAT #x-3E400000 #x800000) #.(MAKE-DOUBLE-FLOAT #x-3E400000 #x800000)) NIL) -(> (#.(MAKE-DOUBLE-FLOAT #x-3E400000 #x800000) #.(MAKE-DOUBLE-FLOAT #x41C00000 #x0)) NIL) +(> (#.(MAKE-DOUBLE-FLOAT #x-3E300001 #xFF000000) #.(MAKE-DOUBLE-FLOAT #x-3E300001 #xFF000000)) NIL) +(> (#.(MAKE-DOUBLE-FLOAT #x-3E300001 #xFF000000) #.(MAKE-DOUBLE-FLOAT #x41D00000 #x400000)) NIL) (> (#.(MAKE-DOUBLE-FLOAT #x-3E300001 #xFF800000) #.(MAKE-DOUBLE-FLOAT #x-3E300001 #xFF800000)) NIL) -(> (#.(MAKE-DOUBLE-FLOAT #x-3E300001 #xFF800000) #.(MAKE-DOUBLE-FLOAT #x41CFFFFF #xFF800000)) NIL) +(> (#.(MAKE-DOUBLE-FLOAT #x-3E300001 #xFF800000) #.(MAKE-DOUBLE-FLOAT #x41D00000 #x0)) NIL) (> (#.(MAKE-DOUBLE-FLOAT #x-3E300001 #xFF800000) #.(MAKE-DOUBLE-FLOAT #x41D00000 #x400000)) NIL) -(> (#.(MAKE-DOUBLE-FLOAT #x-3E300000 #x0) #.(MAKE-DOUBLE-FLOAT #x-3E300000 #x0)) NIL) -(> (#.(MAKE-DOUBLE-FLOAT #x-3E300000 #x0) #.(MAKE-DOUBLE-FLOAT #x41D00000 #x0)) NIL) -(> (#.(MAKE-DOUBLE-FLOAT #x-3E300000 #x0) #.(MAKE-DOUBLE-FLOAT #x41D00000 #x400000)) NIL) -(> (#.(MAKE-DOUBLE-FLOAT #x-3E280001 #xFFC00000) #.(MAKE-DOUBLE-FLOAT #x41D7FFFF #xFF800000)) NIL) (> (#.(MAKE-DOUBLE-FLOAT #x-3E26DE05 #x54442D18) #.(MAKE-DOUBLE-FLOAT #x-3E26DE05 #x54442D18)) NIL) (> (#.(MAKE-DOUBLE-FLOAT #x-3E26DE05 #x54442D18) #.(MAKE-DOUBLE-FLOAT #x-3C200000 #x0)) T) (> (#.(MAKE-DOUBLE-FLOAT #x-3E26DE05 #x54442D18) #.(MAKE-DOUBLE-FLOAT #x41D921FB #x54442D18)) NIL) (> (#.(MAKE-DOUBLE-FLOAT #x-3E26DE05 #x60000000) #.(MAKE-DOUBLE-FLOAT #x-3E26DE05 #x60000000)) NIL) (> (#.(MAKE-DOUBLE-FLOAT #x-3E26DE05 #x60000000) #.(MAKE-DOUBLE-FLOAT #x41D921FB #x60000000)) NIL) (> (#.(MAKE-DOUBLE-FLOAT #x-3E200000 #x0) #.(MAKE-DOUBLE-FLOAT #x41DFFFFF #xFFC00000)) NIL) +(> (#.(MAKE-DOUBLE-FLOAT #x-3CC00000 #x0) #.(MAKE-DOUBLE-FLOAT #x-40100000 #x0)) NIL) +(> (#.(MAKE-DOUBLE-FLOAT #x-3CC00000 #x0) #.(MAKE-DOUBLE-FLOAT #x-3CC00000 #x0)) NIL) +(> (#.(MAKE-DOUBLE-FLOAT #x-3CC00000 #x0) #.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFFFFFFFF)) NIL) +(> (#.(MAKE-DOUBLE-FLOAT #x-3CC00000 #x0) #.(MAKE-DOUBLE-FLOAT #x433FFFFF #xFFFFFFFF)) NIL) +(> (#.(MAKE-DOUBLE-FLOAT #x-3CC00000 #x0) #.(MAKE-DOUBLE-FLOAT #x43AFFFFF #xFFFFFFFF)) NIL) +(> (#.(MAKE-DOUBLE-FLOAT #x-3CC00000 #x0) #.(MAKE-DOUBLE-FLOAT #x43CFFFFF #xFFFFFFFF)) NIL) (> (#.(MAKE-DOUBLE-FLOAT #x-3C62329C #xFF1194D8) #.(MAKE-DOUBLE-FLOAT #x-3C62329C #xFF1194D8)) NIL) (> (#.(MAKE-DOUBLE-FLOAT #x-3C62329C #xFF1194D8) #.(MAKE-DOUBLE-FLOAT #x439DCD64 #xFF1194D8)) NIL) (> (#.(MAKE-DOUBLE-FLOAT #x-3C500000 #x0) #.(MAKE-DOUBLE-FLOAT #x-40100000 #x0)) NIL) +(> (#.(MAKE-DOUBLE-FLOAT #x-3C500000 #x0) #.(MAKE-DOUBLE-FLOAT #x-3CC00000 #x0)) NIL) (> (#.(MAKE-DOUBLE-FLOAT #x-3C500000 #x0) #.(MAKE-DOUBLE-FLOAT #x-3C500000 #x0)) NIL) (> (#.(MAKE-DOUBLE-FLOAT #x-3C500000 #x0) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) NIL) +(> (#.(MAKE-DOUBLE-FLOAT #x-3C500000 #x0) #.(MAKE-DOUBLE-FLOAT #x43AFFFFF #xE0000000)) NIL) (> (#.(MAKE-DOUBLE-FLOAT #x-3C500000 #x0) #.(MAKE-DOUBLE-FLOAT #x43AFFFFF #xFFFFFFFF)) NIL) (> (#.(MAKE-DOUBLE-FLOAT #x-3C500000 #x0) #.(MAKE-DOUBLE-FLOAT #x43B00000 #x0)) NIL) (> (#.(MAKE-DOUBLE-FLOAT #x-3C400000 #x0) #.(MAKE-DOUBLE-FLOAT #x-3C400000 #x0)) NIL) @@ -2283,8 +2314,10 @@ (> (#.(MAKE-DOUBLE-FLOAT #x-3C36DE05 #x60000000) #.(MAKE-DOUBLE-FLOAT #x-3C36DE05 #x60000000)) NIL) (> (#.(MAKE-DOUBLE-FLOAT #x-3C36DE05 #x60000000) #.(MAKE-DOUBLE-FLOAT #x43C921FB #x60000000)) NIL) (> (#.(MAKE-DOUBLE-FLOAT #x-3C300000 #x0) #.(MAKE-DOUBLE-FLOAT #x-40100000 #x0)) NIL) +(> (#.(MAKE-DOUBLE-FLOAT #x-3C300000 #x0) #.(MAKE-DOUBLE-FLOAT #x-3CC00000 #x0)) NIL) (> (#.(MAKE-DOUBLE-FLOAT #x-3C300000 #x0) #.(MAKE-DOUBLE-FLOAT #x-3C300000 #x0)) NIL) (> (#.(MAKE-DOUBLE-FLOAT #x-3C300000 #x0) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) NIL) +(> (#.(MAKE-DOUBLE-FLOAT #x-3C300000 #x0) #.(MAKE-DOUBLE-FLOAT #x43CFFFFF #xE0000000)) NIL) (> (#.(MAKE-DOUBLE-FLOAT #x-3C300000 #x0) #.(MAKE-DOUBLE-FLOAT #x43CFFFFF #xFFFFFFFF)) NIL) (> (#.(MAKE-DOUBLE-FLOAT #x-3C300000 #x0) #.(MAKE-DOUBLE-FLOAT #x43D00000 #x0)) NIL) (> (#.(MAKE-DOUBLE-FLOAT #x-3C200000 #x0) #.(MAKE-DOUBLE-FLOAT #x-3C200000 #x0)) NIL) @@ -2308,13 +2341,18 @@ (> (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #x1000000000000001) NIL) (> (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #x4000000000000000) NIL) (> (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #x4000000000000001) NIL) +(> (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-SINGLE-FLOAT #x0)) NIL) (> (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-SINGLE-FLOAT #x7F7FFFFF)) NIL) +(> (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x-80000000 #x0)) NIL) (> (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x-40100000 #x0)) T) (> (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x-4006DE05 #x54442D18)) T) (> (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x-3F8CB000 #x0)) T) -(> (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x-3F729000 #x0)) T) +(> (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0)) T) (> (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x-3E26DE05 #x54442D18)) T) +(> (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x-3CC00000 #x0)) T) +(> (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x-3C500000 #x0)) T) (> (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x-3C36DE05 #x54442D18)) T) +(> (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x-3C300000 #x0)) T) (> (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x-3C16DE05 #x54442D18)) T) (> (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) NIL) (> (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x3FE00000 #x0)) NIL) @@ -2322,22 +2360,22 @@ (> (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x3FEFFFFF #xFFFFFFFF)) NIL) (> (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0)) NIL) (> (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x3FF33333 #x33333333)) NIL) -(> (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x40000000 #x0)) NIL) -(> (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x4005BF0A #x8B145769)) NIL) (> (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x400921FB #x54442D18)) NIL) (> (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x40742000 #x0)) NIL) -(> (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x4083C273 #x2107A1BA)) NIL) -(> (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x408DD800 #x0)) NIL) +(> (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x4083BA73 #x2107A1BA)) NIL) (> (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xE0000000)) NIL) (> (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFF000000)) NIL) +(> (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFFFFFFFF)) NIL) (> (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x41C00000 #x0)) NIL) -(> (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x41CFFFFF #xFF800000)) NIL) +(> (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x4270C6F7 #xA0B5E000)) NIL) (> (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x4310624D #xD2F1A9F8)) NIL) (> (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x433FFFFF #xFFFFFFFF)) NIL) +(> (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x43AFFFFF #xFFFFE627)) NIL) (> (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x43AFFFFF #xFFFFFFF8)) NIL) +(> (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x43AFFFFF #xFFFFFFFF)) NIL) (> (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x43B00000 #x0)) NIL) +(> (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x43CFFFFF #xFFFFFFFF)) NIL) (> (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x43D00000 #x0)) NIL) -(> (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) NIL) (> (#.(MAKE-DOUBLE-FLOAT #x100000 #x0) #.(MAKE-DOUBLE-FLOAT #x100000 #x0)) NIL) (> (#.(MAKE-DOUBLE-FLOAT #x1FFFFF #xFFFFFFFE) #.(MAKE-DOUBLE-FLOAT #x1FFFFF #xFFFFFFFE)) NIL) (> (#.(MAKE-DOUBLE-FLOAT #x300000 #x2) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) T) @@ -2359,14 +2397,23 @@ (> (#.(MAKE-DOUBLE-FLOAT #x3FE6A09E #x667F3BCD) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) T) (> (#.(MAKE-DOUBLE-FLOAT #x3FE6A09E #x667F3BCD) #.(MAKE-DOUBLE-FLOAT #x3FE6A09E #x667F3BCD)) NIL) (> (#.(MAKE-DOUBLE-FLOAT #x3FEFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) T) +(> (#.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0) #x0) T) +(> (#.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0) #.(MAKE-SINGLE-FLOAT #x-40800000)) T) +(> (#.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0) #.(MAKE-SINGLE-FLOAT #x0)) T) (> (#.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0) #.(MAKE-SINGLE-FLOAT #x3F800000)) NIL) (> (#.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0) #.(MAKE-SINGLE-FLOAT #x7F7FFFFF)) NIL) (> (#.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0) #.(MAKE-DOUBLE-FLOAT #x-80000000 #x0)) T) (> (#.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0) #.(MAKE-DOUBLE-FLOAT #x-40100000 #x0)) T) +(> (#.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0) #.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0)) T) +(> (#.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0) #.(MAKE-DOUBLE-FLOAT #x-3C500000 #x0)) T) +(> (#.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0) #.(MAKE-DOUBLE-FLOAT #x-3C300000 #x0)) T) (> (#.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) T) (> (#.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0) #.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0)) NIL) +(> (#.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0) #.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFF000000)) NIL) (> (#.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0) #.(MAKE-DOUBLE-FLOAT #x41C00000 #x0)) NIL) +(> (#.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0) #.(MAKE-DOUBLE-FLOAT #x43AFFFFF #xFFFFFFFF)) NIL) (> (#.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0) #.(MAKE-DOUBLE-FLOAT #x43B00000 #x0)) NIL) +(> (#.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0) #.(MAKE-DOUBLE-FLOAT #x43CFFFFF #xFFFFFFFF)) NIL) (> (#.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0) #.(MAKE-DOUBLE-FLOAT #x43D00000 #x0)) NIL) (> (#.(MAKE-DOUBLE-FLOAT #x3FF33333 #x33333333) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) T) (> (#.(MAKE-DOUBLE-FLOAT #x3FF33333 #x33333333) #.(MAKE-DOUBLE-FLOAT #x3FE6A09E #x667F3BCD)) T) @@ -2392,41 +2439,47 @@ (> (#.(MAKE-DOUBLE-FLOAT #x404A8000 #x0) #.(MAKE-DOUBLE-FLOAT #x43D00000 #x0)) NIL) (> (#.(MAKE-DOUBLE-FLOAT #x406633CE #x8FB9F87D) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) T) (> (#.(MAKE-DOUBLE-FLOAT #x406633CE #x8FB9F87D) #.(MAKE-DOUBLE-FLOAT #x406633CE #x8FB9F87D)) NIL) -(> (#.(MAKE-DOUBLE-FLOAT #x406633CE #x8FB9F87E) #.(MAKE-DOUBLE-FLOAT #x406633CE #x8FB9F87E)) NIL) -(> (#.(MAKE-DOUBLE-FLOAT #x4083C273 #x2107A1BA) #.(MAKE-DOUBLE-FLOAT #x3FE00000 #x0)) T) -(> (#.(MAKE-DOUBLE-FLOAT #x4083C273 #x2107A1BA) #.(MAKE-DOUBLE-FLOAT #x4083C209 #xA84FBD00)) T) -(> (#.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFF000000) #x0) T) +(> (#.(MAKE-DOUBLE-FLOAT #x4083BA73 #x2107A1BA) #.(MAKE-DOUBLE-FLOAT #x3FE00000 #x0)) T) +(> (#.(MAKE-DOUBLE-FLOAT #x4083BA73 #x2107A1BA) #.(MAKE-DOUBLE-FLOAT #x4083BA09 #xA84FBD00)) T) (> (#.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFF000000) #.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0)) T) (> (#.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFF000000) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) T) (> (#.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFF000000) #.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFF000000)) NIL) +(> (#.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFFFFFFFF) #x0) T) (> (#.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0)) T) -(> (#.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x-3E400000 #x800000)) T) +(> (#.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x-3CC00000 #x0)) T) +(> (#.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) T) +(> (#.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFF000000)) T) (> (#.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFFFFFFFF)) NIL) -(> (#.(MAKE-DOUBLE-FLOAT #x41C00000 #x0) #.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0)) T) (> (#.(MAKE-DOUBLE-FLOAT #x41C00000 #x0) #.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFF000000)) T) (> (#.(MAKE-DOUBLE-FLOAT #x41CDCD65 #x0) #.(MAKE-DOUBLE-FLOAT #x41CDCD65 #x0)) NIL) -(> (#.(MAKE-DOUBLE-FLOAT #x41CFFFFF #xFF800000) #.(MAKE-DOUBLE-FLOAT #x3FE00000 #x0)) T) -(> (#.(MAKE-DOUBLE-FLOAT #x41CFFFFF #xFF800000) #.(MAKE-DOUBLE-FLOAT #x41CFFFFF #xFF800000)) NIL) (> (#.(MAKE-DOUBLE-FLOAT #x41D921FB #x54442D18) #x0) T) (> (#.(MAKE-DOUBLE-FLOAT #x41D921FB #x54442D18) #.(MAKE-DOUBLE-FLOAT #x41D921FB #x537B1D3D)) T) (> (#.(MAKE-DOUBLE-FLOAT #x41E00000 #x0) #.(MAKE-DOUBLE-FLOAT #x41EFFFFF #xFFE00000)) NIL) +(> (#.(MAKE-DOUBLE-FLOAT #x4270C6F7 #xA0B5E000) #.(MAKE-SINGLE-FLOAT #x7F7FFFFF)) NIL) +(> (#.(MAKE-DOUBLE-FLOAT #x4270C6F7 #xA0B5E000) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) T) +(> (#.(MAKE-DOUBLE-FLOAT #x4270C6F7 #xA0B5E000) #.(MAKE-DOUBLE-FLOAT #x4270C6F7 #xA0B5E000)) NIL) (> (#.(MAKE-DOUBLE-FLOAT #x4310624D #xD2F1A9F8) #.(MAKE-SINGLE-FLOAT #x7F7FFFFF)) NIL) (> (#.(MAKE-DOUBLE-FLOAT #x4310624D #xD2F1A9F8) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) T) (> (#.(MAKE-DOUBLE-FLOAT #x4310624D #xD2F1A9F8) #.(MAKE-DOUBLE-FLOAT #x4310624D #xD2F1A9F8)) NIL) +(> (#.(MAKE-DOUBLE-FLOAT #x433FFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0)) T) +(> (#.(MAKE-DOUBLE-FLOAT #x433FFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x-3CC00000 #x0)) T) +(> (#.(MAKE-DOUBLE-FLOAT #x433FFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFFFFFFFF)) T) +(> (#.(MAKE-DOUBLE-FLOAT #x433FFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x433FFFFF #xFFFFFFFF)) NIL) (> (#.(MAKE-DOUBLE-FLOAT #x4341C379 #x37E08000) #.(MAKE-DOUBLE-FLOAT #x4341C379 #x37E08000)) NIL) +(> (#.(MAKE-DOUBLE-FLOAT #x43AFFFFF #xFFFFFFFF) #x0) T) (> (#.(MAKE-DOUBLE-FLOAT #x43AFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x-3C500000 #x0)) T) +(> (#.(MAKE-DOUBLE-FLOAT #x43AFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) T) (> (#.(MAKE-DOUBLE-FLOAT #x43AFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x43AFFFFF #xFFFFFFFF)) NIL) -(> (#.(MAKE-DOUBLE-FLOAT #x43B00000 #x0) #x0) T) (> (#.(MAKE-DOUBLE-FLOAT #x43B00000 #x0) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) T) (> (#.(MAKE-DOUBLE-FLOAT #x43B00000 #x0) #.(MAKE-DOUBLE-FLOAT #x43B00000 #x0)) NIL) (> (#.(MAKE-DOUBLE-FLOAT #x43C921FB #x54442D18) #x0) T) (> (#.(MAKE-DOUBLE-FLOAT #x43C921FB #x54442D18) #.(MAKE-DOUBLE-FLOAT #x43C921FB #x54442D18)) NIL) +(> (#.(MAKE-DOUBLE-FLOAT #x43CFFFFF #xFFFFFFFF) #x0) T) (> (#.(MAKE-DOUBLE-FLOAT #x43CFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x-3C300000 #x0)) T) +(> (#.(MAKE-DOUBLE-FLOAT #x43CFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) T) (> (#.(MAKE-DOUBLE-FLOAT #x43CFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x43CFFFFF #xFFFFFFFF)) NIL) -(> (#.(MAKE-DOUBLE-FLOAT #x43D00000 #x0) #x0) T) (> (#.(MAKE-DOUBLE-FLOAT #x43D00000 #x0) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) T) (> (#.(MAKE-DOUBLE-FLOAT #x43D00000 #x0) #.(MAKE-DOUBLE-FLOAT #x43D00000 #x0)) NIL) -(> (#.(MAKE-DOUBLE-FLOAT #x43E00000 #x0) #.(MAKE-DOUBLE-FLOAT #x43E00000 #x0)) NIL) (> (#.(MAKE-DOUBLE-FLOAT #x43E00000 #x0) #.(MAKE-DOUBLE-FLOAT #x43F00000 #x0)) NIL) (> (#.(MAKE-DOUBLE-FLOAT #x43E921FB #x54442D18) #x0) T) (> (#.(MAKE-DOUBLE-FLOAT #x43E921FB #x54442D18) #.(MAKE-DOUBLE-FLOAT #x43E921FB #x54442D18)) NIL) @@ -2441,10 +2494,6 @@ (>= (#x-1000000000000000 #.(MAKE-DOUBLE-FLOAT #x0 #x0)) NIL) (>= (#x-20000000 #.(MAKE-DOUBLE-FLOAT #x0 #x0)) NIL) (>= (#x-467 #.(MAKE-DOUBLE-FLOAT #x0 #x0)) NIL) -(>= (#x-3CA #.(MAKE-DOUBLE-FLOAT #x0 #x0)) NIL) -(>= (#x-3C9 #.(MAKE-DOUBLE-FLOAT #x0 #x0)) NIL) -(>= (#x-3BD #.(MAKE-DOUBLE-FLOAT #x0 #x0)) NIL) -(>= (#x-3AE #.(MAKE-DOUBLE-FLOAT #x0 #x0)) NIL) (>= (#x-144 #.(MAKE-DOUBLE-FLOAT #x0 #x0)) NIL) (>= (#x-135 #.(MAKE-DOUBLE-FLOAT #x0 #x0)) NIL) (>= (#x0 #.(MAKE-SINGLE-FLOAT #x-40800000)) T) @@ -2454,13 +2503,10 @@ (>= (#x0 #.(MAKE-SINGLE-FLOAT #x0)) T) (>= (#x0 #.(MAKE-SINGLE-FLOAT #x3F800000)) NIL) (>= (#x0 #.(MAKE-SINGLE-FLOAT #x40490FDB)) NIL) -(>= (#x0 #.(MAKE-SINGLE-FLOAT #x497423F0)) NIL) +(>= (#x0 #.(MAKE-SINGLE-FLOAT #x4B7FFFFF)) NIL) (>= (#x0 #.(MAKE-SINGLE-FLOAT #x4DFFFFFF)) NIL) (>= (#x0 #.(MAKE-SINGLE-FLOAT #x4E000000)) NIL) (>= (#x0 #.(MAKE-SINGLE-FLOAT #x4E6E6B28)) NIL) -(>= (#x0 #.(MAKE-SINGLE-FLOAT #x4E800000)) NIL) -(>= (#x0 #.(MAKE-SINGLE-FLOAT #x4EC00000)) NIL) -(>= (#x0 #.(MAKE-SINGLE-FLOAT #x5903126F)) NIL) (>= (#x0 #.(MAKE-SINGLE-FLOAT #x5CEE6B28)) NIL) (>= (#x0 #.(MAKE-SINGLE-FLOAT #x5D7FFFFF)) NIL) (>= (#x0 #.(MAKE-SINGLE-FLOAT #x5D800000)) NIL) @@ -2478,14 +2524,13 @@ (>= (#x0 #.(MAKE-DOUBLE-FLOAT #x3FF921FB #x54442D18)) NIL) (>= (#x0 #.(MAKE-DOUBLE-FLOAT #x400921FB #x54442D18)) NIL) (>= (#x0 #.(MAKE-DOUBLE-FLOAT #x40734413 #x509F79FF)) NIL) -(>= (#x0 #.(MAKE-DOUBLE-FLOAT #x4083C209 #xA84FBD00)) NIL) -(>= (#x0 #.(MAKE-DOUBLE-FLOAT #x408D6413 #x509F7A00)) NIL) +(>= (#x0 #.(MAKE-DOUBLE-FLOAT #x4083BA09 #xA84FBD00)) NIL) +(>= (#x0 #.(MAKE-DOUBLE-FLOAT #x408D5C13 #x509F7A00)) NIL) (>= (#x0 #.(MAKE-DOUBLE-FLOAT #x408FF800 #x0)) NIL) (>= (#x0 #.(MAKE-DOUBLE-FLOAT #x40900000 #x0)) NIL) (>= (#x0 #.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFF000000)) NIL) (>= (#x0 #.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFFFFFFFF)) NIL) -(>= (#x0 #.(MAKE-DOUBLE-FLOAT #x41CFFFFF #xFF800000)) NIL) -(>= (#x0 #.(MAKE-DOUBLE-FLOAT #x41D7FFFF #xFF800000)) NIL) +(>= (#x0 #.(MAKE-DOUBLE-FLOAT #x433FFFFF #xFFFFFFFF)) NIL) (>= (#x0 #.(MAKE-DOUBLE-FLOAT #x439DCD64 #xFF1194D8)) NIL) (>= (#x0 #.(MAKE-DOUBLE-FLOAT #x43AFFFFF #xFFFFFFFF)) NIL) (>= (#x0 #.(MAKE-DOUBLE-FLOAT #x43B00000 #x0)) NIL) @@ -2522,39 +2567,46 @@ (>= (#x4000000000000001 #.(MAKE-DOUBLE-FLOAT #x0 #x0)) T) (>= (#.(MAKE-SINGLE-FLOAT #x-80000000) #x0) T) (>= (#.(MAKE-SINGLE-FLOAT #x-80000000) #.(MAKE-SINGLE-FLOAT #x-40800000)) T) +(>= (#.(MAKE-SINGLE-FLOAT #x-80000000) #.(MAKE-SINGLE-FLOAT #x-34800000)) T) (>= (#.(MAKE-SINGLE-FLOAT #x-80000000) #.(MAKE-SINGLE-FLOAT #x0)) T) (>= (#.(MAKE-SINGLE-FLOAT #x-80000000) #.(MAKE-SINGLE-FLOAT #x3F800000)) NIL) -(>= (#.(MAKE-SINGLE-FLOAT #x-40804189) #x0) NIL) -(>= (#.(MAKE-SINGLE-FLOAT #x-40804189) #.(MAKE-SINGLE-FLOAT #x-40804189)) T) (>= (#.(MAKE-SINGLE-FLOAT #x-40800000) #x0) NIL) (>= (#.(MAKE-SINGLE-FLOAT #x-40800000) #.(MAKE-SINGLE-FLOAT #x-80000000)) NIL) (>= (#.(MAKE-SINGLE-FLOAT #x-40800000) #.(MAKE-SINGLE-FLOAT #x-40800000)) T) +(>= (#.(MAKE-SINGLE-FLOAT #x-40800000) #.(MAKE-SINGLE-FLOAT #x-34800000)) T) (>= (#.(MAKE-SINGLE-FLOAT #x-40800000) #.(MAKE-SINGLE-FLOAT #x0)) NIL) (>= (#.(MAKE-SINGLE-FLOAT #x-40800000) #.(MAKE-SINGLE-FLOAT #x3DCCCCCD)) NIL) (>= (#.(MAKE-SINGLE-FLOAT #x-40800000) #.(MAKE-SINGLE-FLOAT #x3F800000)) NIL) +(>= (#.(MAKE-SINGLE-FLOAT #x-4036F025) #.(MAKE-SINGLE-FLOAT #x-4036F025)) T) (>= (#.(MAKE-SINGLE-FLOAT #x-4036F025) #.(MAKE-SINGLE-FLOAT #x-3136F025)) T) (>= (#.(MAKE-SINGLE-FLOAT #x-4036F025) #.(MAKE-SINGLE-FLOAT #x-21B6F025)) T) (>= (#.(MAKE-SINGLE-FLOAT #x-4036F025) #.(MAKE-SINGLE-FLOAT #x-20B6F025)) T) (>= (#.(MAKE-SINGLE-FLOAT #x-3FB6F025) #x0) NIL) (>= (#.(MAKE-SINGLE-FLOAT #x-3FB6F025) #.(MAKE-SINGLE-FLOAT #x-3FB6F025)) T) (>= (#.(MAKE-SINGLE-FLOAT #x-3FB6F025) #.(MAKE-SINGLE-FLOAT #x0)) NIL) -(>= (#.(MAKE-SINGLE-FLOAT #x-368C1A80) #x0) NIL) +(>= (#.(MAKE-SINGLE-FLOAT #x-34800000) #x0) NIL) +(>= (#.(MAKE-SINGLE-FLOAT #x-34800000) #.(MAKE-SINGLE-FLOAT #x-80000000)) NIL) +(>= (#.(MAKE-SINGLE-FLOAT #x-34800000) #.(MAKE-SINGLE-FLOAT #x-34800000)) T) +(>= (#.(MAKE-SINGLE-FLOAT #x-34800000) #.(MAKE-SINGLE-FLOAT #x-32000000)) T) +(>= (#.(MAKE-SINGLE-FLOAT #x-34800000) #.(MAKE-SINGLE-FLOAT #x-22800000)) T) +(>= (#.(MAKE-SINGLE-FLOAT #x-34800000) #.(MAKE-SINGLE-FLOAT #x-21800000)) T) +(>= (#.(MAKE-SINGLE-FLOAT #x-34800000) #.(MAKE-SINGLE-FLOAT #x0)) NIL) (>= (#.(MAKE-SINGLE-FLOAT #x-32000000) #x0) NIL) (>= (#.(MAKE-SINGLE-FLOAT #x-32000000) #.(MAKE-SINGLE-FLOAT #x-80000000)) NIL) (>= (#.(MAKE-SINGLE-FLOAT #x-32000000) #.(MAKE-SINGLE-FLOAT #x-32000000)) T) (>= (#.(MAKE-SINGLE-FLOAT #x-32000000) #.(MAKE-SINGLE-FLOAT #x0)) NIL) +(>= (#.(MAKE-SINGLE-FLOAT #x-32000000) #.(MAKE-SINGLE-FLOAT #x3F800000)) NIL) (>= (#.(MAKE-SINGLE-FLOAT #x-32000000) #.(MAKE-SINGLE-FLOAT #x4DFFFFFF)) NIL) (>= (#.(MAKE-SINGLE-FLOAT #x-32000000) #.(MAKE-SINGLE-FLOAT #x4E000000)) NIL) (>= (#.(MAKE-SINGLE-FLOAT #x-319194D8) #x0) NIL) -(>= (#.(MAKE-SINGLE-FLOAT #x-31800000) #x0) NIL) (>= (#.(MAKE-SINGLE-FLOAT #x-31800000) #.(MAKE-SINGLE-FLOAT #x-31800000)) T) -(>= (#.(MAKE-SINGLE-FLOAT #x-31400000) #x0) NIL) (>= (#.(MAKE-SINGLE-FLOAT #x-3136F025) #.(MAKE-SINGLE-FLOAT #x-3136F025)) T) (>= (#.(MAKE-SINGLE-FLOAT #x-231194D8) #x0) NIL) (>= (#.(MAKE-SINGLE-FLOAT #x-231194D8) #.(MAKE-SINGLE-FLOAT #x-231194D8)) T) (>= (#.(MAKE-SINGLE-FLOAT #x-22800000) #x0) NIL) (>= (#.(MAKE-SINGLE-FLOAT #x-22800000) #.(MAKE-SINGLE-FLOAT #x-22800000)) T) (>= (#.(MAKE-SINGLE-FLOAT #x-22800000) #.(MAKE-SINGLE-FLOAT #x0)) NIL) +(>= (#.(MAKE-SINGLE-FLOAT #x-22800000) #.(MAKE-SINGLE-FLOAT #x3F800000)) NIL) (>= (#.(MAKE-SINGLE-FLOAT #x-22800000) #.(MAKE-SINGLE-FLOAT #x5D7FFFFF)) NIL) (>= (#.(MAKE-SINGLE-FLOAT #x-22800000) #.(MAKE-SINGLE-FLOAT #x5D800000)) NIL) (>= (#.(MAKE-SINGLE-FLOAT #x-22000000) #.(MAKE-SINGLE-FLOAT #x-22000000)) T) @@ -2563,6 +2615,7 @@ (>= (#.(MAKE-SINGLE-FLOAT #x-21800000) #.(MAKE-SINGLE-FLOAT #x-80000000)) NIL) (>= (#.(MAKE-SINGLE-FLOAT #x-21800000) #.(MAKE-SINGLE-FLOAT #x-21800000)) T) (>= (#.(MAKE-SINGLE-FLOAT #x-21800000) #.(MAKE-SINGLE-FLOAT #x0)) NIL) +(>= (#.(MAKE-SINGLE-FLOAT #x-21800000) #.(MAKE-SINGLE-FLOAT #x3F800000)) NIL) (>= (#.(MAKE-SINGLE-FLOAT #x-21800000) #.(MAKE-SINGLE-FLOAT #x5E7FFFFF)) NIL) (>= (#.(MAKE-SINGLE-FLOAT #x-21800000) #.(MAKE-SINGLE-FLOAT #x5E800000)) NIL) (>= (#.(MAKE-SINGLE-FLOAT #x-21000000) #.(MAKE-SINGLE-FLOAT #x-21000000)) T) @@ -2580,6 +2633,7 @@ (>= (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x-80000000)) T) (>= (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x-40800000)) T) (>= (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x-3FB6F025)) T) +(>= (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x-34800000)) T) (>= (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x-32000000)) T) (>= (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x-3136F025)) T) (>= (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x-22800000)) T) @@ -2591,54 +2645,83 @@ (>= (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x3F000000)) NIL) (>= (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x3F800000)) NIL) (>= (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x40000000)) NIL) -(>= (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x41600000)) NIL) +(>= (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x4DFFFFFF)) NIL) +(>= (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x4E000000)) NIL) +(>= (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x538637BD)) NIL) (>= (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x5883126F)) NIL) +(>= (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x5D7FFFFF)) NIL) +(>= (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x5D800000)) NIL) +(>= (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x5E7FFFFF)) NIL) +(>= (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-SINGLE-FLOAT #x5E800000)) NIL) (>= (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-DOUBLE-FLOAT #x-80000000 #x0)) T) +(>= (#.(MAKE-SINGLE-FLOAT #x0) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) T) (>= (#.(MAKE-SINGLE-FLOAT #x3089705F) #x0) T) +(>= (#.(MAKE-SINGLE-FLOAT #x358637BD) #x0) T) +(>= (#.(MAKE-SINGLE-FLOAT #x358637BD) #.(MAKE-SINGLE-FLOAT #x40000000)) NIL) (>= (#.(MAKE-SINGLE-FLOAT #x3A83126F) #x0) T) (>= (#.(MAKE-SINGLE-FLOAT #x3A83126F) #.(MAKE-SINGLE-FLOAT #x40000000)) NIL) -(>= (#.(MAKE-SINGLE-FLOAT #x3D800000) #x0) T) (>= (#.(MAKE-SINGLE-FLOAT #x3D800000) #.(MAKE-SINGLE-FLOAT #x-80000000)) T) (>= (#.(MAKE-SINGLE-FLOAT #x3D800000) #.(MAKE-SINGLE-FLOAT #x0)) T) (>= (#.(MAKE-SINGLE-FLOAT #x3D800000) #.(MAKE-SINGLE-FLOAT #x3D800000)) T) (>= (#.(MAKE-SINGLE-FLOAT #x3D800000) #.(MAKE-SINGLE-FLOAT #x3F800000)) NIL) (>= (#.(MAKE-SINGLE-FLOAT #x3DCCCCCD) #.(MAKE-SINGLE-FLOAT #x-40800000)) T) (>= (#.(MAKE-SINGLE-FLOAT #x3F000000) #x0) T) -(>= (#.(MAKE-SINGLE-FLOAT #x3F000000) #.(MAKE-SINGLE-FLOAT #x4E800000)) NIL) -(>= (#.(MAKE-SINGLE-FLOAT #x3F266666) #.(MAKE-SINGLE-FLOAT #x40000000)) NIL) -(>= (#.(MAKE-SINGLE-FLOAT #x3F59999A) #.(MAKE-SINGLE-FLOAT #x40000000)) NIL) -(>= (#.(MAKE-SINGLE-FLOAT #x3F666666) #.(MAKE-SINGLE-FLOAT #x40000000)) NIL) +(>= (#.(MAKE-SINGLE-FLOAT #x3F000000) #.(MAKE-SINGLE-FLOAT #x0)) T) +(>= (#.(MAKE-SINGLE-FLOAT #x3F000000) #.(MAKE-SINGLE-FLOAT #x3F000000)) T) (>= (#.(MAKE-SINGLE-FLOAT #x3F800000) #x0) T) (>= (#.(MAKE-SINGLE-FLOAT #x3F800000) #.(MAKE-SINGLE-FLOAT #x-80000000)) T) (>= (#.(MAKE-SINGLE-FLOAT #x3F800000) #.(MAKE-SINGLE-FLOAT #x-40800000)) T) +(>= (#.(MAKE-SINGLE-FLOAT #x3F800000) #.(MAKE-SINGLE-FLOAT #x-32000000)) T) +(>= (#.(MAKE-SINGLE-FLOAT #x3F800000) #.(MAKE-SINGLE-FLOAT #x-22800000)) T) +(>= (#.(MAKE-SINGLE-FLOAT #x3F800000) #.(MAKE-SINGLE-FLOAT #x-21800000)) T) (>= (#.(MAKE-SINGLE-FLOAT #x3F800000) #.(MAKE-SINGLE-FLOAT #x0)) T) (>= (#.(MAKE-SINGLE-FLOAT #x3F800000) #.(MAKE-SINGLE-FLOAT #x3DCCCCCD)) T) (>= (#.(MAKE-SINGLE-FLOAT #x3F800000) #.(MAKE-SINGLE-FLOAT #x3F800000)) T) (>= (#.(MAKE-SINGLE-FLOAT #x3F800000) #.(MAKE-SINGLE-FLOAT #x3FC00000)) NIL) -(>= (#.(MAKE-SINGLE-FLOAT #x3F800000) #.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0)) T) +(>= (#.(MAKE-SINGLE-FLOAT #x40000000) #x0) T) (>= (#.(MAKE-SINGLE-FLOAT #x40490FDB) #.(MAKE-SINGLE-FLOAT #x-3FB6F025)) T) -(>= (#.(MAKE-SINGLE-FLOAT #x41600000) #x0) T) -(>= (#.(MAKE-SINGLE-FLOAT #x41600000) #.(MAKE-SINGLE-FLOAT #x0)) T) -(>= (#.(MAKE-SINGLE-FLOAT #x41600000) #.(MAKE-SINGLE-FLOAT #x41600000)) T) (>= (#.(MAKE-SINGLE-FLOAT #x447A0000) #x0) T) (>= (#.(MAKE-SINGLE-FLOAT #x447A0000) #.(MAKE-SINGLE-FLOAT #x40000000)) T) (>= (#.(MAKE-SINGLE-FLOAT #x49742400) #x0) T) +(>= (#.(MAKE-SINGLE-FLOAT #x49742400) #.(MAKE-SINGLE-FLOAT #x40000000)) T) +(>= (#.(MAKE-SINGLE-FLOAT #x4B7FFFFF) #.(MAKE-SINGLE-FLOAT #x-80000000)) T) +(>= (#.(MAKE-SINGLE-FLOAT #x4B7FFFFF) #.(MAKE-SINGLE-FLOAT #x-34800000)) T) +(>= (#.(MAKE-SINGLE-FLOAT #x4B7FFFFF) #.(MAKE-SINGLE-FLOAT #x0)) T) +(>= (#.(MAKE-SINGLE-FLOAT #x4B7FFFFF) #.(MAKE-SINGLE-FLOAT #x4B7FFFFF)) T) (>= (#.(MAKE-SINGLE-FLOAT #x4DFFFFFF) #.(MAKE-SINGLE-FLOAT #x-80000000)) T) +(>= (#.(MAKE-SINGLE-FLOAT #x4DFFFFFF) #.(MAKE-SINGLE-FLOAT #x-34800000)) T) (>= (#.(MAKE-SINGLE-FLOAT #x4DFFFFFF) #.(MAKE-SINGLE-FLOAT #x0)) T) +(>= (#.(MAKE-SINGLE-FLOAT #x4DFFFFFF) #.(MAKE-SINGLE-FLOAT #x4B7FFFFF)) T) +(>= (#.(MAKE-SINGLE-FLOAT #x4DFFFFFF) #.(MAKE-SINGLE-FLOAT #x4DFFFFFF)) T) (>= (#.(MAKE-SINGLE-FLOAT #x4E000000) #x0) T) (>= (#.(MAKE-SINGLE-FLOAT #x4E000000) #.(MAKE-SINGLE-FLOAT #x-80000000)) T) (>= (#.(MAKE-SINGLE-FLOAT #x4E000000) #.(MAKE-SINGLE-FLOAT #x0)) T) (>= (#.(MAKE-SINGLE-FLOAT #x4E000000) #.(MAKE-SINGLE-FLOAT #x4E000000)) T) (>= (#.(MAKE-SINGLE-FLOAT #x4E6E6B28) #x0) T) (>= (#.(MAKE-SINGLE-FLOAT #x4E6E6B28) #.(MAKE-SINGLE-FLOAT #x40000000)) T) +(>= (#.(MAKE-SINGLE-FLOAT #x538637BD) #.(MAKE-SINGLE-FLOAT #x-80000000)) T) +(>= (#.(MAKE-SINGLE-FLOAT #x538637BD) #.(MAKE-SINGLE-FLOAT #x0)) T) +(>= (#.(MAKE-SINGLE-FLOAT #x538637BD) #.(MAKE-SINGLE-FLOAT #x538637BD)) T) (>= (#.(MAKE-SINGLE-FLOAT #x5883126F) #.(MAKE-SINGLE-FLOAT #x-80000000)) T) (>= (#.(MAKE-SINGLE-FLOAT #x5883126F) #.(MAKE-SINGLE-FLOAT #x0)) T) (>= (#.(MAKE-SINGLE-FLOAT #x5883126F) #.(MAKE-SINGLE-FLOAT #x5883126F)) T) +(>= (#.(MAKE-SINGLE-FLOAT #x5D7FFFFF) #.(MAKE-SINGLE-FLOAT #x-34800000)) T) +(>= (#.(MAKE-SINGLE-FLOAT #x5D7FFFFF) #.(MAKE-SINGLE-FLOAT #x0)) T) +(>= (#.(MAKE-SINGLE-FLOAT #x5D7FFFFF) #.(MAKE-SINGLE-FLOAT #x4B7FFFFF)) T) +(>= (#.(MAKE-SINGLE-FLOAT #x5D7FFFFF) #.(MAKE-SINGLE-FLOAT #x5D7FFFFF)) T) (>= (#.(MAKE-SINGLE-FLOAT #x5D800000) #x0) T) +(>= (#.(MAKE-SINGLE-FLOAT #x5D800000) #.(MAKE-SINGLE-FLOAT #x0)) T) (>= (#.(MAKE-SINGLE-FLOAT #x5D800000) #.(MAKE-SINGLE-FLOAT #x5D800000)) T) (>= (#.(MAKE-SINGLE-FLOAT #x5E7FFFFF) #.(MAKE-SINGLE-FLOAT #x-80000000)) T) +(>= (#.(MAKE-SINGLE-FLOAT #x5E7FFFFF) #.(MAKE-SINGLE-FLOAT #x-34800000)) T) +(>= (#.(MAKE-SINGLE-FLOAT #x5E7FFFFF) #.(MAKE-SINGLE-FLOAT #x-21800000)) T) +(>= (#.(MAKE-SINGLE-FLOAT #x5E7FFFFF) #.(MAKE-SINGLE-FLOAT #x0)) T) +(>= (#.(MAKE-SINGLE-FLOAT #x5E7FFFFF) #.(MAKE-SINGLE-FLOAT #x4B7FFFFF)) T) +(>= (#.(MAKE-SINGLE-FLOAT #x5E7FFFFF) #.(MAKE-SINGLE-FLOAT #x5E7FFFFF)) T) (>= (#.(MAKE-SINGLE-FLOAT #x5E800000) #x0) T) (>= (#.(MAKE-SINGLE-FLOAT #x5E800000) #.(MAKE-SINGLE-FLOAT #x-80000000)) T) +(>= (#.(MAKE-SINGLE-FLOAT #x5E800000) #.(MAKE-SINGLE-FLOAT #x-21800000)) T) +(>= (#.(MAKE-SINGLE-FLOAT #x5E800000) #.(MAKE-SINGLE-FLOAT #x0)) T) (>= (#.(MAKE-SINGLE-FLOAT #x5E800000) #.(MAKE-SINGLE-FLOAT #x5E800000)) T) (>= (#.(MAKE-SINGLE-FLOAT #x7F7FFFFF) #.(MAKE-SINGLE-FLOAT #x-80000000)) T) (>= (#.(MAKE-SINGLE-FLOAT #x7F7FFFFF) #.(MAKE-SINGLE-FLOAT #x-800001)) T) @@ -2646,17 +2729,20 @@ (>= (#.(MAKE-DOUBLE-FLOAT #x-80000000 #x0) #x0) T) (>= (#.(MAKE-DOUBLE-FLOAT #x-80000000 #x0) #.(MAKE-DOUBLE-FLOAT #x-80000000 #x0)) T) (>= (#.(MAKE-DOUBLE-FLOAT #x-80000000 #x0) #.(MAKE-DOUBLE-FLOAT #x-40100000 #x0)) T) +(>= (#.(MAKE-DOUBLE-FLOAT #x-80000000 #x0) #.(MAKE-DOUBLE-FLOAT #x-3CC00000 #x0)) T) (>= (#.(MAKE-DOUBLE-FLOAT #x-80000000 #x0) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) T) (>= (#.(MAKE-DOUBLE-FLOAT #x-80000000 #x0) #.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0)) NIL) (>= (#.(MAKE-DOUBLE-FLOAT #x-80000000 #x0) #.(MAKE-DOUBLE-FLOAT #x400921FB #x54442D18)) NIL) (>= (#.(MAKE-DOUBLE-FLOAT #x-402D413D #x33018866) #x0) NIL) (>= (#.(MAKE-DOUBLE-FLOAT #x-402D413D #x33018866) #.(MAKE-DOUBLE-FLOAT #x-40100000 #x0)) T) (>= (#.(MAKE-DOUBLE-FLOAT #x-40100000 #x0) #x0) NIL) +(>= (#.(MAKE-DOUBLE-FLOAT #x-40100000 #x0) #.(MAKE-SINGLE-FLOAT #x0)) NIL) (>= (#.(MAKE-DOUBLE-FLOAT #x-40100000 #x0) #.(MAKE-DOUBLE-FLOAT #x-80000000 #x0)) NIL) (>= (#.(MAKE-DOUBLE-FLOAT #x-40100000 #x0) #.(MAKE-DOUBLE-FLOAT #x-402D413D #x33018866)) NIL) (>= (#.(MAKE-DOUBLE-FLOAT #x-40100000 #x0) #.(MAKE-DOUBLE-FLOAT #x-40100000 #x0)) T) (>= (#.(MAKE-DOUBLE-FLOAT #x-40100000 #x0) #.(MAKE-DOUBLE-FLOAT #x-3F8BC000 #x0)) T) -(>= (#.(MAKE-DOUBLE-FLOAT #x-40100000 #x0) #.(MAKE-DOUBLE-FLOAT #x-3F721800 #x0)) T) +(>= (#.(MAKE-DOUBLE-FLOAT #x-40100000 #x0) #.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0)) T) +(>= (#.(MAKE-DOUBLE-FLOAT #x-40100000 #x0) #.(MAKE-DOUBLE-FLOAT #x-3CC00000 #x0)) T) (>= (#.(MAKE-DOUBLE-FLOAT #x-40100000 #x0) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) NIL) (>= (#.(MAKE-DOUBLE-FLOAT #x-40100000 #x0) #.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0)) NIL) (>= (#.(MAKE-DOUBLE-FLOAT #x-40100000 #x0) #.(MAKE-DOUBLE-FLOAT #x40000000 #x0)) NIL) @@ -2676,7 +2762,6 @@ (>= (#.(MAKE-DOUBLE-FLOAT #x-3FF6DE05 #x54442D18) #.(MAKE-DOUBLE-FLOAT #x400921FB #x54442D18)) NIL) (>= (#.(MAKE-DOUBLE-FLOAT #x-3FD20000 #x0) #.(MAKE-DOUBLE-FLOAT #x-3FD20000 #x0)) T) (>= (#.(MAKE-DOUBLE-FLOAT #x-3FD20000 #x0) #.(MAKE-DOUBLE-FLOAT #x-3F8BC000 #x0)) T) -(>= (#.(MAKE-DOUBLE-FLOAT #x-3FD20000 #x0) #.(MAKE-DOUBLE-FLOAT #x-3F721800 #x0)) T) (>= (#.(MAKE-DOUBLE-FLOAT #x-3F8CB000 #x0) #.(MAKE-DOUBLE-FLOAT #x-3F8CB000 #x0)) T) (>= (#.(MAKE-DOUBLE-FLOAT #x-3F8CB000 #x0) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) NIL) (>= (#.(MAKE-DOUBLE-FLOAT #x-3F8BCB1A #x420F4374) #x0) NIL) @@ -2684,47 +2769,45 @@ (>= (#.(MAKE-DOUBLE-FLOAT #x-3F8BC000 #x0) #.(MAKE-DOUBLE-FLOAT #x-40100000 #x0)) NIL) (>= (#.(MAKE-DOUBLE-FLOAT #x-3F8BC000 #x0) #.(MAKE-DOUBLE-FLOAT #x-3FD20000 #x0)) NIL) (>= (#.(MAKE-DOUBLE-FLOAT #x-3F8BC000 #x0) #.(MAKE-DOUBLE-FLOAT #x-3F8BC000 #x0)) T) +(>= (#.(MAKE-DOUBLE-FLOAT #x-3F7C458D #x2107A1BA) #x0) NIL) (>= (#.(MAKE-DOUBLE-FLOAT #x-3F7C458D #x2107A1BA) #.(MAKE-DOUBLE-FLOAT #x-3F7C458D #x2107A1BA)) T) -(>= (#.(MAKE-DOUBLE-FLOAT #x-3F7C3D8D #x2107A1BA) #x0) NIL) -(>= (#.(MAKE-DOUBLE-FLOAT #x-3F7C3D8D #x2107A1BA) #.(MAKE-DOUBLE-FLOAT #x-3F7C3D8D #x2107A1BA)) T) (>= (#.(MAKE-DOUBLE-FLOAT #x-3F78B6F0 #xD52D3052) #.(MAKE-DOUBLE-FLOAT #x-3F78B6F0 #xD52D3052)) T) -(>= (#.(MAKE-DOUBLE-FLOAT #x-3F729000 #x0) #.(MAKE-DOUBLE-FLOAT #x-3F729000 #x0)) T) -(>= (#.(MAKE-DOUBLE-FLOAT #x-3F729000 #x0) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) NIL) -(>= (#.(MAKE-DOUBLE-FLOAT #x-3F72231A #x420F4374) #x0) NIL) -(>= (#.(MAKE-DOUBLE-FLOAT #x-3F72231A #x420F4374) #.(MAKE-DOUBLE-FLOAT #x-3F72231A #x420F4374)) T) -(>= (#.(MAKE-DOUBLE-FLOAT #x-3F721800 #x0) #.(MAKE-DOUBLE-FLOAT #x-40100000 #x0)) NIL) -(>= (#.(MAKE-DOUBLE-FLOAT #x-3F721800 #x0) #.(MAKE-DOUBLE-FLOAT #x-3FD20000 #x0)) NIL) -(>= (#.(MAKE-DOUBLE-FLOAT #x-3F721800 #x0) #.(MAKE-DOUBLE-FLOAT #x-3F721800 #x0)) T) +(>= (#.(MAKE-DOUBLE-FLOAT #x-3F722B1A #x420F4374) #x0) NIL) +(>= (#.(MAKE-DOUBLE-FLOAT #x-3F722B1A #x420F4374) #.(MAKE-DOUBLE-FLOAT #x-3F722B1A #x420F4374)) T) (>= (#.(MAKE-DOUBLE-FLOAT #x-3F6F3800 #x0) #x0) NIL) (>= (#.(MAKE-DOUBLE-FLOAT #x-3F6F3400 #x0) #x0) NIL) -(>= (#.(MAKE-DOUBLE-FLOAT #x-3F6C3EC7 #x9083D0DD) #.(MAKE-DOUBLE-FLOAT #x-3F6C3EC7 #x9083D0DD)) T) (>= (#.(MAKE-DOUBLE-FLOAT #x-3E400001 #xFF000000) #x0) NIL) (>= (#.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0) #x0) NIL) (>= (#.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0) #.(MAKE-DOUBLE-FLOAT #x-80000000 #x0)) NIL) (>= (#.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0) #.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0)) T) -(>= (#.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0) #.(MAKE-DOUBLE-FLOAT #x-3E400000 #x800000)) T) -(>= (#.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0) #.(MAKE-DOUBLE-FLOAT #x-3E200000 #x0)) T) +(>= (#.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0) #.(MAKE-DOUBLE-FLOAT #x-3CC00000 #x0)) T) (>= (#.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) NIL) +(>= (#.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0) #.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0)) NIL) (>= (#.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0) #.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFF000000)) NIL) (>= (#.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0) #.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFFFFFFFF)) NIL) -(>= (#.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0) #.(MAKE-DOUBLE-FLOAT #x41C00000 #x0)) NIL) (>= (#.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0) #.(MAKE-DOUBLE-FLOAT #x41C00000 #x800000)) NIL) -(>= (#.(MAKE-DOUBLE-FLOAT #x-3E400000 #x800000) #.(MAKE-DOUBLE-FLOAT #x-3E400000 #x800000)) T) -(>= (#.(MAKE-DOUBLE-FLOAT #x-3E400000 #x800000) #.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFFFFFFFF)) NIL) +(>= (#.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0) #.(MAKE-DOUBLE-FLOAT #x433FFFFF #xFFFFFFFF)) NIL) (>= (#.(MAKE-DOUBLE-FLOAT #x-3E400000 #x800000) #.(MAKE-DOUBLE-FLOAT #x41C00000 #x0)) NIL) -(>= (#.(MAKE-DOUBLE-FLOAT #x-3E300001 #xFF800000) #x0) NIL) +(>= (#.(MAKE-DOUBLE-FLOAT #x-3E300001 #xFF000000) #.(MAKE-DOUBLE-FLOAT #x-3E300001 #xFF000000)) T) +(>= (#.(MAKE-DOUBLE-FLOAT #x-3E300001 #xFF000000) #.(MAKE-DOUBLE-FLOAT #x-3E300001 #xFF800000)) T) +(>= (#.(MAKE-DOUBLE-FLOAT #x-3E300001 #xFF800000) #.(MAKE-DOUBLE-FLOAT #x-3E300001 #xFF000000)) NIL) (>= (#.(MAKE-DOUBLE-FLOAT #x-3E300001 #xFF800000) #.(MAKE-DOUBLE-FLOAT #x-3E300001 #xFF800000)) T) -(>= (#.(MAKE-DOUBLE-FLOAT #x-3E300001 #xFF800000) #.(MAKE-DOUBLE-FLOAT #x-3E300000 #x0)) T) -(>= (#.(MAKE-DOUBLE-FLOAT #x-3E300000 #x0) #.(MAKE-DOUBLE-FLOAT #x-3E300001 #xFF800000)) NIL) -(>= (#.(MAKE-DOUBLE-FLOAT #x-3E300000 #x0) #.(MAKE-DOUBLE-FLOAT #x-3E300000 #x0)) T) -(>= (#.(MAKE-DOUBLE-FLOAT #x-3E280001 #xFFC00000) #x0) NIL) (>= (#.(MAKE-DOUBLE-FLOAT #x-3E26DE05 #x54442D18) #.(MAKE-DOUBLE-FLOAT #x-3E26DE05 #x54442D18)) T) (>= (#.(MAKE-DOUBLE-FLOAT #x-3E26DE05 #x60000000) #.(MAKE-DOUBLE-FLOAT #x-3E26DE05 #x60000000)) T) +(>= (#.(MAKE-DOUBLE-FLOAT #x-3CC00000 #x0) #x0) NIL) +(>= (#.(MAKE-DOUBLE-FLOAT #x-3CC00000 #x0) #.(MAKE-DOUBLE-FLOAT #x-80000000 #x0)) NIL) +(>= (#.(MAKE-DOUBLE-FLOAT #x-3CC00000 #x0) #.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0)) NIL) +(>= (#.(MAKE-DOUBLE-FLOAT #x-3CC00000 #x0) #.(MAKE-DOUBLE-FLOAT #x-3CC00000 #x0)) T) +(>= (#.(MAKE-DOUBLE-FLOAT #x-3CC00000 #x0) #.(MAKE-DOUBLE-FLOAT #x-3C500000 #x0)) T) +(>= (#.(MAKE-DOUBLE-FLOAT #x-3CC00000 #x0) #.(MAKE-DOUBLE-FLOAT #x-3C300000 #x0)) T) +(>= (#.(MAKE-DOUBLE-FLOAT #x-3CC00000 #x0) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) NIL) +(>= (#.(MAKE-DOUBLE-FLOAT #x-3CC00000 #x0) #.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFFFFFFFF)) NIL) (>= (#.(MAKE-DOUBLE-FLOAT #x-3C62329C #xFF1194D8) #x0) NIL) (>= (#.(MAKE-DOUBLE-FLOAT #x-3C62329C #xFF1194D8) #.(MAKE-DOUBLE-FLOAT #x-3C62329C #xFF1194D8)) T) (>= (#.(MAKE-DOUBLE-FLOAT #x-3C500000 #x0) #x0) NIL) (>= (#.(MAKE-DOUBLE-FLOAT #x-3C500000 #x0) #.(MAKE-DOUBLE-FLOAT #x-3C500000 #x0)) T) (>= (#.(MAKE-DOUBLE-FLOAT #x-3C500000 #x0) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) NIL) +(>= (#.(MAKE-DOUBLE-FLOAT #x-3C500000 #x0) #.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0)) NIL) (>= (#.(MAKE-DOUBLE-FLOAT #x-3C500000 #x0) #.(MAKE-DOUBLE-FLOAT #x43AFFFFF #xFFFFFFFF)) NIL) (>= (#.(MAKE-DOUBLE-FLOAT #x-3C500000 #x0) #.(MAKE-DOUBLE-FLOAT #x43B00000 #x0)) NIL) (>= (#.(MAKE-DOUBLE-FLOAT #x-3C400000 #x0) #.(MAKE-DOUBLE-FLOAT #x-3C400000 #x0)) T) @@ -2734,6 +2817,7 @@ (>= (#.(MAKE-DOUBLE-FLOAT #x-3C300000 #x0) #.(MAKE-DOUBLE-FLOAT #x-80000000 #x0)) NIL) (>= (#.(MAKE-DOUBLE-FLOAT #x-3C300000 #x0) #.(MAKE-DOUBLE-FLOAT #x-3C300000 #x0)) T) (>= (#.(MAKE-DOUBLE-FLOAT #x-3C300000 #x0) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) NIL) +(>= (#.(MAKE-DOUBLE-FLOAT #x-3C300000 #x0) #.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0)) NIL) (>= (#.(MAKE-DOUBLE-FLOAT #x-3C300000 #x0) #.(MAKE-DOUBLE-FLOAT #x43CFFFFF #xFFFFFFFF)) NIL) (>= (#.(MAKE-DOUBLE-FLOAT #x-3C300000 #x0) #.(MAKE-DOUBLE-FLOAT #x43D00000 #x0)) NIL) (>= (#.(MAKE-DOUBLE-FLOAT #x-3C200000 #x0) #.(MAKE-DOUBLE-FLOAT #x-3C200000 #x0)) T) @@ -2756,11 +2840,7 @@ (>= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #x1) NIL) (>= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #x133) NIL) (>= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #x142) NIL) -(>= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #x3AC) NIL) -(>= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #x3BB) NIL) (>= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #x3CB) NIL) -(>= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #x468) NIL) -(>= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #x469) NIL) (>= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #x1FFFFFFF) NIL) (>= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #xFFFFFFFFFFFFFFF) NIL) (>= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #x3FFFFFFFFFFFFFFF) NIL) @@ -2769,9 +2849,12 @@ (>= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x-4006DE05 #x54442D18)) T) (>= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x-3FF6DE05 #x54442D18)) T) (>= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x-3F8CB000 #x0)) T) -(>= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x-3F729000 #x0)) T) +(>= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0)) T) (>= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x-3E26DE05 #x54442D18)) T) +(>= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x-3CC00000 #x0)) T) +(>= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x-3C500000 #x0)) T) (>= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x-3C36DE05 #x54442D18)) T) +(>= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x-3C300000 #x0)) T) (>= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x-3C16DE05 #x54442D18)) T) (>= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) T) (>= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x1FFFFF #xFFFFFFFE)) NIL) @@ -2784,7 +2867,14 @@ (>= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x40000000 #x0)) NIL) (>= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x40080000 #x0)) NIL) (>= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x404A8000 #x0)) NIL) +(>= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFF000000)) NIL) +(>= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFFFFFFFF)) NIL) +(>= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x4270C6F7 #xA0B5E000)) NIL) (>= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x4310624D #xD2F1A9F8)) NIL) +(>= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x43AFFFFF #xFFFFFFFF)) NIL) +(>= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x43B00000 #x0)) NIL) +(>= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x43CFFFFF #xFFFFFFFF)) NIL) +(>= (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x43D00000 #x0)) NIL) (>= (#.(MAKE-DOUBLE-FLOAT #x1FFFFF #xFFFFFFFE) #.(MAKE-DOUBLE-FLOAT #x-80000000 #x0)) T) (>= (#.(MAKE-DOUBLE-FLOAT #x1FFFFF #xFFFFFFFE) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) T) (>= (#.(MAKE-DOUBLE-FLOAT #x300000 #x2) #x0) T) @@ -2798,14 +2888,16 @@ (>= (#.(MAKE-DOUBLE-FLOAT #x3E200000 #x0) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) T) (>= (#.(MAKE-DOUBLE-FLOAT #x3FB99999 #x9999999A) #.(MAKE-DOUBLE-FLOAT #x-80000000 #x0)) T) (>= (#.(MAKE-DOUBLE-FLOAT #x3FB99999 #x9999999A) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) T) +(>= (#.(MAKE-DOUBLE-FLOAT #x3FB99999 #x9999999A) #.(MAKE-DOUBLE-FLOAT #x3FB99999 #x9999999A)) T) (>= (#.(MAKE-DOUBLE-FLOAT #x3FD00000 #x0) #x0) T) (>= (#.(MAKE-DOUBLE-FLOAT #x3FD00000 #x0) #.(MAKE-DOUBLE-FLOAT #x40000000 #x0)) NIL) (>= (#.(MAKE-DOUBLE-FLOAT #x3FD34413 #x509F79FF) #x0) T) (>= (#.(MAKE-DOUBLE-FLOAT #x3FD34413 #x509F79FF) #.(MAKE-DOUBLE-FLOAT #x40000000 #x0)) NIL) (>= (#.(MAKE-DOUBLE-FLOAT #x3FE00000 #x0) #x0) T) +(>= (#.(MAKE-DOUBLE-FLOAT #x3FE00000 #x0) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) T) +(>= (#.(MAKE-DOUBLE-FLOAT #x3FE00000 #x0) #.(MAKE-DOUBLE-FLOAT #x3FE00000 #x0)) T) (>= (#.(MAKE-DOUBLE-FLOAT #x3FE00000 #x0) #.(MAKE-DOUBLE-FLOAT #x40000000 #x0)) NIL) -(>= (#.(MAKE-DOUBLE-FLOAT #x3FE00000 #x0) #.(MAKE-DOUBLE-FLOAT #x4083C273 #x2107A1BA)) NIL) -(>= (#.(MAKE-DOUBLE-FLOAT #x3FE00000 #x0) #.(MAKE-DOUBLE-FLOAT #x41CFFFFF #xFF800000)) NIL) +(>= (#.(MAKE-DOUBLE-FLOAT #x3FE00000 #x0) #.(MAKE-DOUBLE-FLOAT #x4083BA73 #x2107A1BA)) NIL) (>= (#.(MAKE-DOUBLE-FLOAT #x3FE62E42 #xFEFA39EF) #x0) T) (>= (#.(MAKE-DOUBLE-FLOAT #x3FE62E42 #xFEFA39EF) #.(MAKE-DOUBLE-FLOAT #x40000000 #x0)) NIL) (>= (#.(MAKE-DOUBLE-FLOAT #x3FE6A09E #x667F3BCD) #.(MAKE-DOUBLE-FLOAT #x-80000000 #x0)) T) @@ -2815,6 +2907,9 @@ (>= (#.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0) #x0) T) (>= (#.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0) #.(MAKE-DOUBLE-FLOAT #x-80000000 #x0)) T) (>= (#.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0) #.(MAKE-DOUBLE-FLOAT #x-40100000 #x0)) T) +(>= (#.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0) #.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0)) T) +(>= (#.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0) #.(MAKE-DOUBLE-FLOAT #x-3C500000 #x0)) T) +(>= (#.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0) #.(MAKE-DOUBLE-FLOAT #x-3C300000 #x0)) T) (>= (#.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) T) (>= (#.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0) #.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0)) T) (>= (#.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0) #.(MAKE-DOUBLE-FLOAT #x3FFB504F #x333F9DE6)) NIL) @@ -2849,57 +2944,76 @@ (>= (#.(MAKE-DOUBLE-FLOAT #x40240000 #x0) #x0) T) (>= (#.(MAKE-DOUBLE-FLOAT #x40240000 #x0) #x1) T) (>= (#.(MAKE-DOUBLE-FLOAT #x40240000 #x0) #.(MAKE-DOUBLE-FLOAT #x-40100000 #x0)) T) -(>= (#.(MAKE-DOUBLE-FLOAT #x40240000 #x0) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) T) (>= (#.(MAKE-DOUBLE-FLOAT #x40240000 #x0) #.(MAKE-DOUBLE-FLOAT #x40000000 #x0)) T) (>= (#.(MAKE-DOUBLE-FLOAT #x40240000 #x0) #.(MAKE-DOUBLE-FLOAT #x40240000 #x0)) T) (>= (#.(MAKE-DOUBLE-FLOAT #x404A8000 #x0) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) T) (>= (#.(MAKE-DOUBLE-FLOAT #x406633CE #x8FB9F87D) #.(MAKE-DOUBLE-FLOAT #x-80000000 #x0)) T) (>= (#.(MAKE-DOUBLE-FLOAT #x406633CE #x8FB9F87D) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) T) -(>= (#.(MAKE-DOUBLE-FLOAT #x406633CE #x8FB9F87E) #.(MAKE-DOUBLE-FLOAT #x-80000000 #x0)) T) -(>= (#.(MAKE-DOUBLE-FLOAT #x406633CE #x8FB9F87E) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) T) +(>= (#.(MAKE-DOUBLE-FLOAT #x4083BA73 #x2107A1BA) #.(MAKE-DOUBLE-FLOAT #x3FE00000 #x0)) T) (>= (#.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFF000000) #x0) T) (>= (#.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFF000000) #.(MAKE-DOUBLE-FLOAT #x-80000000 #x0)) T) (>= (#.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFF000000) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) T) (>= (#.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFF000000) #.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFF000000)) T) (>= (#.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x-80000000 #x0)) T) +(>= (#.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x-3CC00000 #x0)) T) (>= (#.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) T) +(>= (#.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFFFFFFFF)) T) +(>= (#.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x433FFFFF #xFFFFFFFF)) NIL) (>= (#.(MAKE-DOUBLE-FLOAT #x41C00000 #x0) #x0) T) (>= (#.(MAKE-DOUBLE-FLOAT #x41C00000 #x0) #.(MAKE-DOUBLE-FLOAT #x3E200000 #x0)) T) (>= (#.(MAKE-DOUBLE-FLOAT #x41C00000 #x800000) #x0) T) (>= (#.(MAKE-DOUBLE-FLOAT #x41CDCD65 #x0) #x0) T) (>= (#.(MAKE-DOUBLE-FLOAT #x41CDCD65 #x0) #.(MAKE-DOUBLE-FLOAT #x40000000 #x0)) T) -(>= (#.(MAKE-DOUBLE-FLOAT #x41D00000 #x400000) #.(MAKE-DOUBLE-FLOAT #x41D00000 #x0)) T) +(>= (#.(MAKE-DOUBLE-FLOAT #x41D00000 #x0) #.(MAKE-DOUBLE-FLOAT #x-3E300001 #xFF000000)) T) +(>= (#.(MAKE-DOUBLE-FLOAT #x41D00000 #x0) #.(MAKE-DOUBLE-FLOAT #x41D00000 #x400000)) NIL) +(>= (#.(MAKE-DOUBLE-FLOAT #x4270C6F7 #xA0B5E000) #.(MAKE-DOUBLE-FLOAT #x-80000000 #x0)) T) +(>= (#.(MAKE-DOUBLE-FLOAT #x4270C6F7 #xA0B5E000) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) T) +(>= (#.(MAKE-DOUBLE-FLOAT #x4270C6F7 #xA0B5E000) #.(MAKE-DOUBLE-FLOAT #x4270C6F7 #xA0B5E000)) T) (>= (#.(MAKE-DOUBLE-FLOAT #x4310624D #xD2F1A9F8) #.(MAKE-DOUBLE-FLOAT #x-80000000 #x0)) T) (>= (#.(MAKE-DOUBLE-FLOAT #x4310624D #xD2F1A9F8) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) T) (>= (#.(MAKE-DOUBLE-FLOAT #x4310624D #xD2F1A9F8) #.(MAKE-DOUBLE-FLOAT #x4310624D #xD2F1A9F8)) T) +(>= (#.(MAKE-DOUBLE-FLOAT #x433FFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x-80000000 #x0)) T) +(>= (#.(MAKE-DOUBLE-FLOAT #x433FFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x-3CC00000 #x0)) T) +(>= (#.(MAKE-DOUBLE-FLOAT #x433FFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) T) +(>= (#.(MAKE-DOUBLE-FLOAT #x433FFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFFFFFFFF)) T) +(>= (#.(MAKE-DOUBLE-FLOAT #x433FFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x433FFFFF #xFFFFFFFF)) T) (>= (#.(MAKE-DOUBLE-FLOAT #x4341C379 #x37E08000) #x0) T) (>= (#.(MAKE-DOUBLE-FLOAT #x4341C379 #x37E08000) #.(MAKE-DOUBLE-FLOAT #x40000000 #x0)) T) +(>= (#.(MAKE-DOUBLE-FLOAT #x43AFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x-3CC00000 #x0)) T) +(>= (#.(MAKE-DOUBLE-FLOAT #x43AFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) T) +(>= (#.(MAKE-DOUBLE-FLOAT #x43AFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x433FFFFF #xFFFFFFFF)) T) +(>= (#.(MAKE-DOUBLE-FLOAT #x43AFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x43AFFFFF #xFFFFFFFF)) T) (>= (#.(MAKE-DOUBLE-FLOAT #x43B00000 #x0) #x0) T) +(>= (#.(MAKE-DOUBLE-FLOAT #x43B00000 #x0) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) T) (>= (#.(MAKE-DOUBLE-FLOAT #x43B00000 #x0) #.(MAKE-DOUBLE-FLOAT #x3C300000 #x0)) T) (>= (#.(MAKE-DOUBLE-FLOAT #x43B00000 #x0) #.(MAKE-DOUBLE-FLOAT #x43B00000 #x0)) T) (>= (#.(MAKE-DOUBLE-FLOAT #x43CFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x-80000000 #x0)) T) +(>= (#.(MAKE-DOUBLE-FLOAT #x43CFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x-3CC00000 #x0)) T) +(>= (#.(MAKE-DOUBLE-FLOAT #x43CFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x-3C300000 #x0)) T) +(>= (#.(MAKE-DOUBLE-FLOAT #x43CFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) T) +(>= (#.(MAKE-DOUBLE-FLOAT #x43CFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x433FFFFF #xFFFFFFFF)) T) +(>= (#.(MAKE-DOUBLE-FLOAT #x43CFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x43CFFFFF #xFFFFFFFF)) T) (>= (#.(MAKE-DOUBLE-FLOAT #x43D00000 #x0) #x0) T) (>= (#.(MAKE-DOUBLE-FLOAT #x43D00000 #x0) #.(MAKE-DOUBLE-FLOAT #x-80000000 #x0)) T) +(>= (#.(MAKE-DOUBLE-FLOAT #x43D00000 #x0) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) T) (>= (#.(MAKE-DOUBLE-FLOAT #x43D00000 #x0) #.(MAKE-DOUBLE-FLOAT #x3C100000 #x0)) T) (>= (#.(MAKE-DOUBLE-FLOAT #x43D00000 #x0) #.(MAKE-DOUBLE-FLOAT #x43D00000 #x0)) T) (>= (#.(MAKE-DOUBLE-FLOAT #x5FCFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x-80000000 #x0)) T) (>= (#.(MAKE-DOUBLE-FLOAT #x5FCFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) T) +(>= (#.(MAKE-DOUBLE-FLOAT #x5FCFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x5FCFFFFF #xFFFFFFFF)) T) (>= (#.(MAKE-DOUBLE-FLOAT #x5FEFFFFF #xFFFFFFFF) #x0) T) (>= (#.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x-80000000 #x0)) T) (>= (#.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF)) T) (>= (#.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) T) (>= (#.(MAKE-DOUBLE-FLOAT #x7FF00000 #x0) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) T) -(ABS #.(MAKE-SINGLE-FLOAT #x-800001) #.(MAKE-SINGLE-FLOAT #x7F7FFFFF)) -(ABS #.(MAKE-SINGLE-FLOAT #x7F7FFFFF) #.(MAKE-SINGLE-FLOAT #x7F7FFFFF)) -(ABS #.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) (ABS #.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0) #.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0)) (ABS #.(MAKE-DOUBLE-FLOAT #x3FF921FB #x54442D18) #.(MAKE-DOUBLE-FLOAT #x3FF921FB #x54442D18)) (ABS #.(MAKE-DOUBLE-FLOAT #x400921FB #x54442D18) #.(MAKE-DOUBLE-FLOAT #x400921FB #x54442D18)) -(ABS #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF) #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF)) (ATAN (#.(MAKE-DOUBLE-FLOAT #x20000000 #x1)) #.(MAKE-DOUBLE-FLOAT #x20000000 #x1)) +(CEILING (#.(MAKE-SINGLE-FLOAT #x-40800000) #x1) &VALUES #x-1 #.(MAKE-SINGLE-FLOAT #x0)) +(CEILING (#.(MAKE-SINGLE-FLOAT #x-34800000) #x1) &VALUES #x-1000000 #.(MAKE-SINGLE-FLOAT #x0)) (CEILING (#.(MAKE-SINGLE-FLOAT #x-32000000) #x1) &VALUES #x-20000000 #.(MAKE-SINGLE-FLOAT #x0)) (CEILING (#.(MAKE-SINGLE-FLOAT #x-319194D8) #x1) &VALUES #x-3B9ACA00 #.(MAKE-SINGLE-FLOAT #x0)) -(CEILING (#.(MAKE-SINGLE-FLOAT #x-31400000) #x1) &VALUES #x-60000000 #.(MAKE-SINGLE-FLOAT #x0)) (CEILING (#.(MAKE-SINGLE-FLOAT #x-231194D8) #x1) &VALUES #x-773594000000000 #.(MAKE-SINGLE-FLOAT #x0)) (CEILING (#.(MAKE-SINGLE-FLOAT #x-22800000) #x1) &VALUES #x-1000000000000000 #.(MAKE-SINGLE-FLOAT #x0)) (CEILING (#.(MAKE-SINGLE-FLOAT #x-21800000) #x1) &VALUES #x-4000000000000000 #.(MAKE-SINGLE-FLOAT #x0)) @@ -2908,10 +3022,11 @@ (CEILING (#.(MAKE-SINGLE-FLOAT #x0) #x1) &VALUES #x0 #.(MAKE-SINGLE-FLOAT #x0)) (CEILING (#.(MAKE-SINGLE-FLOAT #x50000000) #x1) &VALUES #x200000000 #.(MAKE-SINGLE-FLOAT #x0)) (CEILING (#.(MAKE-SINGLE-FLOAT #x60000000) #x1) &VALUES #x20000000000000000 #.(MAKE-SINGLE-FLOAT #x0)) +(CEILING (#.(MAKE-DOUBLE-FLOAT #x-40100000 #x0) #x1) &VALUES #x-1 #.(MAKE-DOUBLE-FLOAT #x0 #x0)) (CEILING (#.(MAKE-DOUBLE-FLOAT #x-3F8BCB1A #x420F4374) #x1) &VALUES #x-143 #.(MAKE-DOUBLE-FLOAT #x-402C66F8 #x3D0DD000)) -(CEILING (#.(MAKE-DOUBLE-FLOAT #x-3F72231A #x420F4374) #x1) &VALUES #x-3BB #.(MAKE-DOUBLE-FLOAT #x-401C66F8 #x3D0DD000)) +(CEILING (#.(MAKE-DOUBLE-FLOAT #x-3F722B1A #x420F4374) #x1) &VALUES #x-3BA #.(MAKE-DOUBLE-FLOAT #x-401C66F8 #x3D0DD000)) (CEILING (#.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0) #x1) &VALUES #x-20000000 #.(MAKE-DOUBLE-FLOAT #x0 #x0)) -(CEILING (#.(MAKE-DOUBLE-FLOAT #x-3E280001 #xFFC00000) #x1) &VALUES #x-5FFFFFFF #.(MAKE-DOUBLE-FLOAT #x0 #x0)) +(CEILING (#.(MAKE-DOUBLE-FLOAT #x-3CC00000 #x0) #x1) &VALUES #x-20000000000000 #.(MAKE-DOUBLE-FLOAT #x0 #x0)) (CEILING (#.(MAKE-DOUBLE-FLOAT #x-3C62329C #xFF1194D8) #x1) &VALUES #x-773593FC4653600 #.(MAKE-DOUBLE-FLOAT #x0 #x0)) (CEILING (#.(MAKE-DOUBLE-FLOAT #x-3C500000 #x0) #x1) &VALUES #x-1000000000000000 #.(MAKE-DOUBLE-FLOAT #x0 #x0)) (CEILING (#.(MAKE-DOUBLE-FLOAT #x-3C300000 #x0) #x1) &VALUES #x-4000000000000000 #.(MAKE-DOUBLE-FLOAT #x0 #x0)) @@ -2928,89 +3043,79 @@ (COERCE (#x-1000000000000001 SINGLE-FLOAT) #.(MAKE-SINGLE-FLOAT #x-22800000)) (COERCE (#x-1000000000000000 DOUBLE-FLOAT) #.(MAKE-DOUBLE-FLOAT #x-3C500000 #x0)) (COERCE (#x-1000000000000000 SINGLE-FLOAT) #.(MAKE-SINGLE-FLOAT #x-22800000)) +(COERCE (#x-20000000000000 DOUBLE-FLOAT) #.(MAKE-DOUBLE-FLOAT #x-3CC00000 #x0)) (COERCE (#x-80000000 DOUBLE-FLOAT) #.(MAKE-DOUBLE-FLOAT #x-3E200000 #x0)) (COERCE (#x-80000000 SINGLE-FLOAT) #.(MAKE-SINGLE-FLOAT #x-31000000)) (COERCE (#x-20000001 DOUBLE-FLOAT) #.(MAKE-DOUBLE-FLOAT #x-3E400000 #x800000)) (COERCE (#x-20000001 SINGLE-FLOAT) #.(MAKE-SINGLE-FLOAT #x-32000000)) (COERCE (#x-20000000 DOUBLE-FLOAT) #.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0)) (COERCE (#x-20000000 SINGLE-FLOAT) #.(MAKE-SINGLE-FLOAT #x-32000000)) -(COERCE (#x-F3E58 SINGLE-FLOAT) #.(MAKE-SINGLE-FLOAT #x-368C1A80)) +(COERCE (#x-1000000 SINGLE-FLOAT) #.(MAKE-SINGLE-FLOAT #x-34800000)) (COERCE (#x-433 DOUBLE-FLOAT) #.(MAKE-DOUBLE-FLOAT #x-3F6F3400 #x0)) (COERCE (#x-432 DOUBLE-FLOAT) #.(MAKE-DOUBLE-FLOAT #x-3F6F3800 #x0)) -(COERCE (#x-3BD DOUBLE-FLOAT) #.(MAKE-DOUBLE-FLOAT #x-3F721800 #x0)) -(COERCE (#x-3BC DOUBLE-FLOAT) #.(MAKE-DOUBLE-FLOAT #x-3F722000 #x0)) -(COERCE (#x-3AE DOUBLE-FLOAT) #.(MAKE-DOUBLE-FLOAT #x-3F729000 #x0)) (COERCE (#x-144 DOUBLE-FLOAT) #.(MAKE-DOUBLE-FLOAT #x-3F8BC000 #x0)) (COERCE (#x-143 DOUBLE-FLOAT) #.(MAKE-DOUBLE-FLOAT #x-3F8BD000 #x0)) (COERCE (#x-135 DOUBLE-FLOAT) #.(MAKE-DOUBLE-FLOAT #x-3F8CB000 #x0)) (COERCE (#x-F DOUBLE-FLOAT) #.(MAKE-DOUBLE-FLOAT #x-3FD20000 #x0)) (COERCE (#x-1 DOUBLE-FLOAT) #.(MAKE-DOUBLE-FLOAT #x-40100000 #x0)) -(COERCE (#x-1 FLOAT) #.(MAKE-SINGLE-FLOAT #x-40800000)) (COERCE (#x-1 LONG-FLOAT) #.(MAKE-DOUBLE-FLOAT #x-40100000 #x0)) (COERCE (#x-1 SINGLE-FLOAT) #.(MAKE-SINGLE-FLOAT #x-40800000)) (COERCE (#x0 DOUBLE-FLOAT) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) -(COERCE (#x0 FLOAT) #.(MAKE-SINGLE-FLOAT #x0)) (COERCE (#x0 LONG-FLOAT) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) (COERCE (#x0 SINGLE-FLOAT) #.(MAKE-SINGLE-FLOAT #x0)) (COERCE (#x1/2 DOUBLE-FLOAT) #.(MAKE-DOUBLE-FLOAT #x3FE00000 #x0)) (COERCE (#x1/2 SINGLE-FLOAT) #.(MAKE-SINGLE-FLOAT #x3F000000)) (COERCE (#x1 DOUBLE-FLOAT) #.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0)) -(COERCE (#x1 FLOAT) #.(MAKE-SINGLE-FLOAT #x3F800000)) (COERCE (#x1 LONG-FLOAT) #.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0)) (COERCE (#x1 SINGLE-FLOAT) #.(MAKE-SINGLE-FLOAT #x3F800000)) (COERCE (#x2 DOUBLE-FLOAT) #.(MAKE-DOUBLE-FLOAT #x40000000 #x0)) (COERCE (#x2 SINGLE-FLOAT) #.(MAKE-SINGLE-FLOAT #x40000000)) (COERCE (#x7 LONG-FLOAT) #.(MAKE-DOUBLE-FLOAT #x401C0000 #x0)) -(COERCE (#xE SINGLE-FLOAT) #.(MAKE-SINGLE-FLOAT #x41600000)) (COERCE (#x35 DOUBLE-FLOAT) #.(MAKE-DOUBLE-FLOAT #x404A8000 #x0)) (COERCE (#x133 DOUBLE-FLOAT) #.(MAKE-DOUBLE-FLOAT #x40733000 #x0)) (COERCE (#x134 DOUBLE-FLOAT) #.(MAKE-DOUBLE-FLOAT #x40734000 #x0)) -(COERCE (#x135 DOUBLE-FLOAT) #.(MAKE-DOUBLE-FLOAT #x40735000 #x0)) (COERCE (#x142 DOUBLE-FLOAT) #.(MAKE-DOUBLE-FLOAT #x40742000 #x0)) -(COERCE (#x3AC DOUBLE-FLOAT) #.(MAKE-DOUBLE-FLOAT #x408D6000 #x0)) -(COERCE (#x3AD DOUBLE-FLOAT) #.(MAKE-DOUBLE-FLOAT #x408D6800 #x0)) -(COERCE (#x3BB DOUBLE-FLOAT) #.(MAKE-DOUBLE-FLOAT #x408DD800 #x0)) (COERCE (#x3E8 SINGLE-FLOAT) #.(MAKE-SINGLE-FLOAT #x447A0000)) (COERCE (#x3FF DOUBLE-FLOAT) #.(MAKE-DOUBLE-FLOAT #x408FF800 #x0)) (COERCE (#x400 DOUBLE-FLOAT) #.(MAKE-DOUBLE-FLOAT #x40900000 #x0)) (COERCE (#xF423F SINGLE-FLOAT) #.(MAKE-SINGLE-FLOAT #x497423F0)) -(COERCE (#x1000000 SINGLE-FLOAT) #.(MAKE-SINGLE-FLOAT #x4B800000)) +(COERCE (#xF4240 SINGLE-FLOAT) #.(MAKE-SINGLE-FLOAT #x49742400)) +(COERCE (#xFFFFFF SINGLE-FLOAT) #.(MAKE-SINGLE-FLOAT #x4B7FFFFF)) (COERCE (#x1FFFFFE0 DOUBLE-FLOAT) #.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xE0000000)) -(COERCE (#x1FFFFFE1 SINGLE-FLOAT) #.(MAKE-SINGLE-FLOAT #x4DFFFFFF)) +(COERCE (#x1FFFFFE0 SINGLE-FLOAT) #.(MAKE-SINGLE-FLOAT #x4DFFFFFF)) (COERCE (#x1FFFFFFB SINGLE-FLOAT) #.(MAKE-SINGLE-FLOAT #x4E000000)) +(COERCE (#x1FFFFFFC SINGLE-FLOAT) #.(MAKE-SINGLE-FLOAT #x4E000000)) (COERCE (#x1FFFFFFF DOUBLE-FLOAT) #.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFF000000)) (COERCE (#x1FFFFFFF SINGLE-FLOAT) #.(MAKE-SINGLE-FLOAT #x4E000000)) (COERCE (#x20000000 DOUBLE-FLOAT) #.(MAKE-DOUBLE-FLOAT #x41C00000 #x0)) (COERCE (#x20000000 SINGLE-FLOAT) #.(MAKE-SINGLE-FLOAT #x4E000000)) -(COERCE (#x20000001 SINGLE-FLOAT) #.(MAKE-SINGLE-FLOAT #x4E000000)) (COERCE (#x7FFFFFFF DOUBLE-FLOAT) #.(MAKE-DOUBLE-FLOAT #x41DFFFFF #xFFC00000)) (COERCE (#x7FFFFFFF SINGLE-FLOAT) #.(MAKE-SINGLE-FLOAT #x4F000000)) (COERCE (#x80000000 DOUBLE-FLOAT) #.(MAKE-DOUBLE-FLOAT #x41E00000 #x0)) (COERCE (#x80000000 SINGLE-FLOAT) #.(MAKE-SINGLE-FLOAT #x4F000000)) (COERCE (#xFFFFFFFF DOUBLE-FLOAT) #.(MAKE-DOUBLE-FLOAT #x41EFFFFF #xFFE00000)) (COERCE (#xFFFFFFFF SINGLE-FLOAT) #.(MAKE-SINGLE-FLOAT #x4F800000)) +(COERCE (#x10C6F7A0B5E LONG-FLOAT) #.(MAKE-DOUBLE-FLOAT #x4270C6F7 #xA0B5E000)) +(COERCE (#x218DEF416BD SINGLE-FLOAT) #.(MAKE-SINGLE-FLOAT #x540637BD)) (COERCE (#x4189374BC6A7E LONG-FLOAT) #.(MAKE-DOUBLE-FLOAT #x4310624D #xD2F1A9F8)) -(COERCE (#x83126E978D4FD SINGLE-FLOAT) #.(MAKE-SINGLE-FLOAT #x5903126F)) (COERCE (#x1FFFFFFFFFFFFF DOUBLE-FLOAT) #.(MAKE-DOUBLE-FLOAT #x433FFFFF #xFFFFFFFF)) -(COERCE (#xFFFFFF000000001 SINGLE-FLOAT) #.(MAKE-SINGLE-FLOAT #x5D7FFFFF)) -(COERCE (#xFFFFFFFFFFFFF81 DOUBLE-FLOAT) #.(MAKE-DOUBLE-FLOAT #x43AFFFFF #xFFFFFFFF)) +(COERCE (#xFFFFFF000000000 SINGLE-FLOAT) #.(MAKE-SINGLE-FLOAT #x5D7FFFFF)) +(COERCE (#xFFFFFFFFFFFFF80 DOUBLE-FLOAT) #.(MAKE-DOUBLE-FLOAT #x43AFFFFF #xFFFFFFFF)) (COERCE (#xFFFFFFFFFFFFFFB SINGLE-FLOAT) #.(MAKE-SINGLE-FLOAT #x5D800000)) +(COERCE (#xFFFFFFFFFFFFFFC SINGLE-FLOAT) #.(MAKE-SINGLE-FLOAT #x5D800000)) (COERCE (#xFFFFFFFFFFFFFFF DOUBLE-FLOAT) #.(MAKE-DOUBLE-FLOAT #x43B00000 #x0)) (COERCE (#xFFFFFFFFFFFFFFF SINGLE-FLOAT) #.(MAKE-SINGLE-FLOAT #x5D800000)) (COERCE (#x1000000000000000 DOUBLE-FLOAT) #.(MAKE-DOUBLE-FLOAT #x43B00000 #x0)) (COERCE (#x1000000000000000 SINGLE-FLOAT) #.(MAKE-SINGLE-FLOAT #x5D800000)) -(COERCE (#x1000000000000001 DOUBLE-FLOAT) #.(MAKE-DOUBLE-FLOAT #x43B00000 #x0)) -(COERCE (#x1000000000000001 SINGLE-FLOAT) #.(MAKE-SINGLE-FLOAT #x5D800000)) -(COERCE (#x3FFFFFC000000001 SINGLE-FLOAT) #.(MAKE-SINGLE-FLOAT #x5E7FFFFF)) -(COERCE (#x3FFFFFFFFFFFFE01 DOUBLE-FLOAT) #.(MAKE-DOUBLE-FLOAT #x43CFFFFF #xFFFFFFFF)) +(COERCE (#x3FFFFFC000000000 SINGLE-FLOAT) #.(MAKE-SINGLE-FLOAT #x5E7FFFFF)) +(COERCE (#x3FFFFFFFFFFFFE00 DOUBLE-FLOAT) #.(MAKE-DOUBLE-FLOAT #x43CFFFFF #xFFFFFFFF)) (COERCE (#x3FFFFFFFFFFFFFC0 DOUBLE-FLOAT) #.(MAKE-DOUBLE-FLOAT #x43D00000 #x0)) (COERCE (#x3FFFFFFFFFFFFFFB SINGLE-FLOAT) #.(MAKE-SINGLE-FLOAT #x5E800000)) +(COERCE (#x3FFFFFFFFFFFFFFC SINGLE-FLOAT) #.(MAKE-SINGLE-FLOAT #x5E800000)) (COERCE (#x3FFFFFFFFFFFFFFF DOUBLE-FLOAT) #.(MAKE-DOUBLE-FLOAT #x43D00000 #x0)) (COERCE (#x3FFFFFFFFFFFFFFF SINGLE-FLOAT) #.(MAKE-SINGLE-FLOAT #x5E800000)) (COERCE (#x4000000000000000 DOUBLE-FLOAT) #.(MAKE-DOUBLE-FLOAT #x43D00000 #x0)) (COERCE (#x4000000000000000 SINGLE-FLOAT) #.(MAKE-SINGLE-FLOAT #x5E800000)) -(COERCE (#x4000000000000001 DOUBLE-FLOAT) #.(MAKE-DOUBLE-FLOAT #x43D00000 #x0)) -(COERCE (#x4000000000000001 SINGLE-FLOAT) #.(MAKE-SINGLE-FLOAT #x5E800000)) (COERCE (#x7FFFFFFFFFFFFFFF DOUBLE-FLOAT) #.(MAKE-DOUBLE-FLOAT #x43E00000 #x0)) (COERCE (#x7FFFFFFFFFFFFFFF SINGLE-FLOAT) #.(MAKE-SINGLE-FLOAT #x5F000000)) (COERCE (#x8000000000000000 DOUBLE-FLOAT) #.(MAKE-DOUBLE-FLOAT #x43E00000 #x0)) @@ -3026,12 +3131,12 @@ (COERCE (#.(MAKE-SINGLE-FLOAT #x-20B6F025) DOUBLE-FLOAT) #.(MAKE-DOUBLE-FLOAT #x-3C16DE05 #x60000000)) (COERCE (#.(MAKE-SINGLE-FLOAT #x0) DOUBLE-FLOAT) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) (COERCE (#.(MAKE-SINGLE-FLOAT #x3F800000) DOUBLE-FLOAT) #.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0)) -(COERCE (#.(MAKE-SINGLE-FLOAT #x4E000000) DOUBLE-FLOAT) #.(MAKE-DOUBLE-FLOAT #x41C00000 #x0)) +(COERCE (#.(MAKE-SINGLE-FLOAT #x4DFFFFFF) DOUBLE-FLOAT) #.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xE0000000)) (COERCE (#.(MAKE-SINGLE-FLOAT #x4E6E6B28) DOUBLE-FLOAT) #.(MAKE-DOUBLE-FLOAT #x41CDCD65 #x0)) (COERCE (#.(MAKE-SINGLE-FLOAT #x4EC90FDB) DOUBLE-FLOAT) #.(MAKE-DOUBLE-FLOAT #x41D921FB #x60000000)) -(COERCE (#.(MAKE-SINGLE-FLOAT #x5D800000) DOUBLE-FLOAT) #.(MAKE-DOUBLE-FLOAT #x43B00000 #x0)) +(COERCE (#.(MAKE-SINGLE-FLOAT #x5D7FFFFF) DOUBLE-FLOAT) #.(MAKE-DOUBLE-FLOAT #x43AFFFFF #xE0000000)) (COERCE (#.(MAKE-SINGLE-FLOAT #x5E490FDB) DOUBLE-FLOAT) #.(MAKE-DOUBLE-FLOAT #x43C921FB #x60000000)) -(COERCE (#.(MAKE-SINGLE-FLOAT #x5E800000) DOUBLE-FLOAT) #.(MAKE-DOUBLE-FLOAT #x43D00000 #x0)) +(COERCE (#.(MAKE-SINGLE-FLOAT #x5E7FFFFF) DOUBLE-FLOAT) #.(MAKE-DOUBLE-FLOAT #x43CFFFFF #xE0000000)) (COERCE (#.(MAKE-SINGLE-FLOAT #x5F490FDB) DOUBLE-FLOAT) #.(MAKE-DOUBLE-FLOAT #x43E921FB #x60000000)) (COERCE (#.(MAKE-DOUBLE-FLOAT #x-40100000 #x0) SINGLE-FLOAT) #.(MAKE-SINGLE-FLOAT #x-40800000)) (COERCE (#.(MAKE-DOUBLE-FLOAT #x-4006DE05 #x54442D18) SINGLE-FLOAT) #.(MAKE-SINGLE-FLOAT #x-4036F025)) @@ -3041,38 +3146,34 @@ (COERCE (#.(MAKE-DOUBLE-FLOAT #x3FF921FB #x54442D18) SINGLE-FLOAT) #.(MAKE-SINGLE-FLOAT #x3FC90FDB)) (COERCE (#.(MAKE-DOUBLE-FLOAT #x400921FB #x54442D18) SINGLE-FLOAT) #.(MAKE-SINGLE-FLOAT #x40490FDB)) (COERCE (#.(MAKE-DOUBLE-FLOAT #x401C0000 #x0) SINGLE-FLOAT) #.(MAKE-SINGLE-FLOAT #x40E00000)) +(COERCE (#.(MAKE-DOUBLE-FLOAT #x4270C6F7 #xA0B5E000) SINGLE-FLOAT) #.(MAKE-SINGLE-FLOAT #x538637BD)) (COERCE (#.(MAKE-DOUBLE-FLOAT #x4310624D #xD2F1A9F8) SINGLE-FLOAT) #.(MAKE-SINGLE-FLOAT #x5883126F)) (COSH (#.(MAKE-SINGLE-FLOAT #x0)) #.(MAKE-SINGLE-FLOAT #x3F800000)) (COSH (#.(MAKE-DOUBLE-FLOAT #x0 #x0)) #.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0)) (EXP #.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0) #.(MAKE-DOUBLE-FLOAT #x4005BF0A #x8B145769)) (EXPT (#.(MAKE-SINGLE-FLOAT #x40000000) #x3F) #.(MAKE-SINGLE-FLOAT #x5F000000)) (EXPT (#.(MAKE-DOUBLE-FLOAT #x40000000 #x0) #x3F) #.(MAKE-DOUBLE-FLOAT #x43E00000 #x0)) -(EXPT (#.(MAKE-DOUBLE-FLOAT #x40240000 #x0) #x-3BD) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) -(EXPT (#.(MAKE-DOUBLE-FLOAT #x40240000 #x0) #x-3AE) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) (EXPT (#.(MAKE-DOUBLE-FLOAT #x40240000 #x0) #x-144) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) (EXPT (#.(MAKE-DOUBLE-FLOAT #x40240000 #x0) #x-135) #.(MAKE-DOUBLE-FLOAT #xB815 #x7268FDAF)) (EXPT (#.(MAKE-DOUBLE-FLOAT #x40240000 #x0) #x133) #.(MAKE-DOUBLE-FLOAT #x7FAC7B1F #x3CAC7433)) (EXPT (#.(MAKE-DOUBLE-FLOAT #x40240000 #x0) #x142) #.(MAKE-DOUBLE-FLOAT #x7FF00000 #x0)) -(EXPT (#.(MAKE-DOUBLE-FLOAT #x40240000 #x0) #x3AC) #.(MAKE-DOUBLE-FLOAT #x7FF00000 #x0)) -(EXPT (#.(MAKE-DOUBLE-FLOAT #x40240000 #x0) #x3BB) #.(MAKE-DOUBLE-FLOAT #x7FF00000 #x0)) (FLOAT (#x0) #.(MAKE-SINGLE-FLOAT #x0)) (FLOAT (#x1) #.(MAKE-SINGLE-FLOAT #x3F800000)) +(FLOAT (#x-20000000000000 #.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0)) #.(MAKE-DOUBLE-FLOAT #x-3CC00000 #x0)) +(FLOAT (#x-1000000 #.(MAKE-SINGLE-FLOAT #x3F800000)) #.(MAKE-SINGLE-FLOAT #x-34800000)) (FLOAT (#x1/10 #.(MAKE-SINGLE-FLOAT #x3F800000)) #.(MAKE-SINGLE-FLOAT #x3D800000)) -(FLOAT (#x1 #.(MAKE-SINGLE-FLOAT #x-80000000)) #.(MAKE-SINGLE-FLOAT #x3F800000)) -(FLOAT (#x1 #.(MAKE-SINGLE-FLOAT #x0)) #.(MAKE-SINGLE-FLOAT #x3F800000)) -(FLOAT (#x1 #.(MAKE-DOUBLE-FLOAT #x-80000000 #x0)) #.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0)) (FLOAT (#x1 #.(MAKE-DOUBLE-FLOAT #x0 #x0)) #.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0)) (FLOAT (#x1 #.(MAKE-DOUBLE-FLOAT #x433FFFFF #xFFFFFFFF)) #.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0)) +(FLOAT (#xFFFFFF #.(MAKE-SINGLE-FLOAT #x3F800000)) #.(MAKE-SINGLE-FLOAT #x4B7FFFFF)) (FLOAT (#x1FFFFFFF #.(MAKE-SINGLE-FLOAT #x3F800000)) #.(MAKE-SINGLE-FLOAT #x4E000000)) (FLOAT (#x1FFFFFFF #.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0)) #.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFF000000)) +(FLOAT (#x10C6F7A0B5E #.(MAKE-SINGLE-FLOAT #x3F800000)) #.(MAKE-SINGLE-FLOAT #x538637BD)) (FLOAT (#x4189374BC6A7E #.(MAKE-SINGLE-FLOAT #x3F800000)) #.(MAKE-SINGLE-FLOAT #x5883126F)) +(FLOAT (#x1FFFFFFFFFFFFF #.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0)) #.(MAKE-DOUBLE-FLOAT #x433FFFFF #xFFFFFFFF)) (FLOAT (#xFFFFFFFFFFFFFFF #.(MAKE-SINGLE-FLOAT #x3F800000)) #.(MAKE-SINGLE-FLOAT #x5D800000)) (FLOAT (#xFFFFFFFFFFFFFFF #.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0)) #.(MAKE-DOUBLE-FLOAT #x43B00000 #x0)) (FLOAT (#x3FFFFFFFFFFFFFFF #.(MAKE-SINGLE-FLOAT #x3F800000)) #.(MAKE-SINGLE-FLOAT #x5E800000)) (FLOAT (#x3FFFFFFFFFFFFFFF #.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0)) #.(MAKE-DOUBLE-FLOAT #x43D00000 #x0)) -(FLOAT-SIGN (#.(MAKE-SINGLE-FLOAT #x-80000000)) #.(MAKE-SINGLE-FLOAT #x-40800000)) -(FLOAT-SIGN (#.(MAKE-SINGLE-FLOAT #x0)) #.(MAKE-SINGLE-FLOAT #x3F800000)) -(FLOAT-SIGN (#.(MAKE-DOUBLE-FLOAT #x-80000000 #x0)) #.(MAKE-DOUBLE-FLOAT #x-40100000 #x0)) (FLOAT-SIGN (#.(MAKE-DOUBLE-FLOAT #x0 #x0)) #.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0)) (FLOAT-SIGN (#.(MAKE-DOUBLE-FLOAT #x433FFFFF #xFFFFFFFF)) #.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0)) (FLOAT-SIGN (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-SINGLE-FLOAT #x0)) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) @@ -3081,12 +3182,10 @@ (FLOOR (#.(MAKE-SINGLE-FLOAT #x-22800000) #x1) &VALUES #x-1000000000000000 #.(MAKE-SINGLE-FLOAT #x0)) (FLOOR (#.(MAKE-SINGLE-FLOAT #x-21800000) #x1) &VALUES #x-4000000000000000 #.(MAKE-SINGLE-FLOAT #x0)) (FLOOR (#.(MAKE-SINGLE-FLOAT #x0) #x1) &VALUES #x0 #.(MAKE-SINGLE-FLOAT #x0)) -(FLOOR (#.(MAKE-SINGLE-FLOAT #x41600000) #x1) &VALUES #xE #.(MAKE-SINGLE-FLOAT #x0)) -(FLOOR (#.(MAKE-SINGLE-FLOAT #x4D800000) #x1) &VALUES #x10000000 #.(MAKE-SINGLE-FLOAT #x0)) +(FLOOR (#.(MAKE-SINGLE-FLOAT #x4B7FFFFF) #x1) &VALUES #xFFFFFF #.(MAKE-SINGLE-FLOAT #x0)) (FLOOR (#.(MAKE-SINGLE-FLOAT #x4DFFFFFF) #x1) &VALUES #x1FFFFFE0 #.(MAKE-SINGLE-FLOAT #x0)) (FLOOR (#.(MAKE-SINGLE-FLOAT #x4E000000) #x1) &VALUES #x20000000 #.(MAKE-SINGLE-FLOAT #x0)) (FLOOR (#.(MAKE-SINGLE-FLOAT #x4E6E6B28) #x1) &VALUES #x3B9ACA00 #.(MAKE-SINGLE-FLOAT #x0)) -(FLOOR (#.(MAKE-SINGLE-FLOAT #x4EC00000) #x1) &VALUES #x60000000 #.(MAKE-SINGLE-FLOAT #x0)) (FLOOR (#.(MAKE-SINGLE-FLOAT #x50000000) #x1) &VALUES #x200000000 #.(MAKE-SINGLE-FLOAT #x0)) (FLOOR (#.(MAKE-SINGLE-FLOAT #x5CEE6B28) #x1) &VALUES #x773594000000000 #.(MAKE-SINGLE-FLOAT #x0)) (FLOOR (#.(MAKE-SINGLE-FLOAT #x5D7FFFFF) #x1) &VALUES #xFFFFFF000000000 #.(MAKE-SINGLE-FLOAT #x0)) @@ -3101,10 +3200,10 @@ (FLOOR (#.(MAKE-DOUBLE-FLOAT #x-3C300000 #x0) #x1) &VALUES #x-4000000000000000 #.(MAKE-DOUBLE-FLOAT #x0 #x0)) (FLOOR (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #x1) &VALUES #x0 #.(MAKE-DOUBLE-FLOAT #x0 #x0)) (FLOOR (#.(MAKE-DOUBLE-FLOAT #x40734413 #x509F79FF) #x1) &VALUES #x134 #.(MAKE-DOUBLE-FLOAT #x3FD04D42 #x7DE7FC00)) -(FLOOR (#.(MAKE-DOUBLE-FLOAT #x408D6413 #x509F7A00) #x1) &VALUES #x3AC #.(MAKE-DOUBLE-FLOAT #x3FE04D42 #x7DE80000)) +(FLOOR (#.(MAKE-DOUBLE-FLOAT #x408D5C13 #x509F7A00) #x1) &VALUES #x3AB #.(MAKE-DOUBLE-FLOAT #x3FE04D42 #x7DE80000)) (FLOOR (#.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFF000000) #x1) &VALUES #x1FFFFFFF #.(MAKE-DOUBLE-FLOAT #x0 #x0)) (FLOOR (#.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFFFFFFFF) #x1) &VALUES #x1FFFFFFF #.(MAKE-DOUBLE-FLOAT #x3FEFFFFF #xE0000000)) -(FLOOR (#.(MAKE-DOUBLE-FLOAT #x41D7FFFF #xFF800000) #x1) &VALUES #x5FFFFFFE #.(MAKE-DOUBLE-FLOAT #x0 #x0)) +(FLOOR (#.(MAKE-DOUBLE-FLOAT #x433FFFFF #xFFFFFFFF) #x1) &VALUES #x1FFFFFFFFFFFFF #.(MAKE-DOUBLE-FLOAT #x0 #x0)) (FLOOR (#.(MAKE-DOUBLE-FLOAT #x439DCD64 #xFF1194D8) #x1) &VALUES #x773593FC4653600 #.(MAKE-DOUBLE-FLOAT #x0 #x0)) (FLOOR (#.(MAKE-DOUBLE-FLOAT #x43AFFFFF #xFFFFFFFF) #x1) &VALUES #xFFFFFFFFFFFFF80 #.(MAKE-DOUBLE-FLOAT #x0 #x0)) (FLOOR (#.(MAKE-DOUBLE-FLOAT #x43B00000 #x0) #x1) &VALUES #x1000000000000000 #.(MAKE-DOUBLE-FLOAT #x0 #x0)) @@ -3122,7 +3221,6 @@ (LOG (#x3FFFFFFFFFFFFFFF) #.(MAKE-SINGLE-FLOAT #x422BE687)) (LOG (#x4000000000000000) #.(MAKE-SINGLE-FLOAT #x422BE687)) (LOG (#x4000000000000001) #.(MAKE-SINGLE-FLOAT #x422BE687)) -(LOG (#.(MAKE-DOUBLE-FLOAT #x0 #x0)) #.(MAKE-DOUBLE-FLOAT #x-100000 #x0)) (LOG (#.(MAKE-DOUBLE-FLOAT #x3FEFFFFF #xFFFFFFFF)) #.(MAKE-DOUBLE-FLOAT #x-43600000 #x0)) (LOG (#.(MAKE-DOUBLE-FLOAT #x40000000 #x0)) #.(MAKE-DOUBLE-FLOAT #x3FE62E42 #xFEFA39EF)) (LOG (#.(MAKE-DOUBLE-FLOAT #x4005BF0A #x8B145769)) #.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0)) @@ -3144,30 +3242,14 @@ (MIN (#.(MAKE-SINGLE-FLOAT #x4E000000) #.(MAKE-SINGLE-FLOAT #x-21800000)) #.(MAKE-SINGLE-FLOAT #x-21800000)) (MIN (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) (MIN (#.(MAKE-DOUBLE-FLOAT #x3FE62E42 #xFEFA39EF) #.(MAKE-DOUBLE-FLOAT #x43CFFFFF #xFFFFFFFF)) #.(MAKE-DOUBLE-FLOAT #x3FE62E42 #xFEFA39EF)) -(RATIONAL #.(MAKE-SINGLE-FLOAT #x-40800000) #x-1) (RATIONAL #.(MAKE-SINGLE-FLOAT #x0) #x0) -(RATIONAL #.(MAKE-SINGLE-FLOAT #x3F800000) #x1) (RATIONAL #.(MAKE-DOUBLE-FLOAT #x-100001 #xFFFFFFFF) #x-FFFFFFFFFFFFF800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000) (RATIONAL #.(MAKE-DOUBLE-FLOAT #x0 #x0) #x0) (RATIONAL #.(MAKE-DOUBLE-FLOAT #x7FEFFFFF #xFFFFFFFF) #xFFFFFFFFFFFFF800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000) -(ROUND (#.(MAKE-SINGLE-FLOAT #x-32000000) #x1) &VALUES #x-20000000 #.(MAKE-SINGLE-FLOAT #x0)) -(ROUND (#.(MAKE-SINGLE-FLOAT #x-22800000) #x1) &VALUES #x-1000000000000000 #.(MAKE-SINGLE-FLOAT #x0)) -(ROUND (#.(MAKE-SINGLE-FLOAT #x-21800000) #x1) &VALUES #x-4000000000000000 #.(MAKE-SINGLE-FLOAT #x0)) -(ROUND (#.(MAKE-SINGLE-FLOAT #x4E000000) #x1) &VALUES #x20000000 #.(MAKE-SINGLE-FLOAT #x0)) -(ROUND (#.(MAKE-SINGLE-FLOAT #x5D800000) #x1) &VALUES #x1000000000000000 #.(MAKE-SINGLE-FLOAT #x0)) -(ROUND (#.(MAKE-SINGLE-FLOAT #x5E800000) #x1) &VALUES #x4000000000000000 #.(MAKE-SINGLE-FLOAT #x0)) (ROUND (#.(MAKE-DOUBLE-FLOAT #x-3F8BCB1A #x420F4374) #x1) &VALUES #x-143 #.(MAKE-DOUBLE-FLOAT #x-402C66F8 #x3D0DD000)) -(ROUND (#.(MAKE-DOUBLE-FLOAT #x-3E400000 #x0) #x1) &VALUES #x-20000000 #.(MAKE-DOUBLE-FLOAT #x0 #x0)) -(ROUND (#.(MAKE-DOUBLE-FLOAT #x-3C500000 #x0) #x1) &VALUES #x-1000000000000000 #.(MAKE-DOUBLE-FLOAT #x0 #x0)) -(ROUND (#.(MAKE-DOUBLE-FLOAT #x-3C300000 #x0) #x1) &VALUES #x-4000000000000000 #.(MAKE-DOUBLE-FLOAT #x0 #x0)) (ROUND (#.(MAKE-DOUBLE-FLOAT #x40734413 #x509F79FF) #x1) &VALUES #x134 #.(MAKE-DOUBLE-FLOAT #x3FD04D42 #x7DE7FC00)) -(ROUND (#.(MAKE-DOUBLE-FLOAT #x41BFFFFF #xFF000000) #x1) &VALUES #x1FFFFFFF #.(MAKE-DOUBLE-FLOAT #x0 #x0)) -(ROUND (#.(MAKE-DOUBLE-FLOAT #x43B00000 #x0) #x1) &VALUES #x1000000000000000 #.(MAKE-DOUBLE-FLOAT #x0 #x0)) -(ROUND (#.(MAKE-DOUBLE-FLOAT #x43D00000 #x0) #x1) &VALUES #x4000000000000000 #.(MAKE-DOUBLE-FLOAT #x0 #x0)) (SCALE-FLOAT (#.(MAKE-DOUBLE-FLOAT #x0 #x0) #x-35) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) (SCALE-FLOAT (#.(MAKE-DOUBLE-FLOAT #x433FFFFF #xFFFFFFFF) #x-35) #.(MAKE-DOUBLE-FLOAT #x3FEFFFFF #xFFFFFFFF)) -(SQRT (#.(MAKE-SINGLE-FLOAT #x0)) #.(MAKE-SINGLE-FLOAT #x0)) -(SQRT (#.(MAKE-DOUBLE-FLOAT #x0 #x0)) #.(MAKE-DOUBLE-FLOAT #x0 #x0)) (SQRT (#.(MAKE-DOUBLE-FLOAT #x20100000 #x1)) #.(MAKE-DOUBLE-FLOAT #x30000000 #x0)) (SQRT (#.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0)) #.(MAKE-DOUBLE-FLOAT #x3FF00000 #x0)) (SQRT (#.(MAKE-DOUBLE-FLOAT #x40100000 #x0)) #.(MAKE-DOUBLE-FLOAT #x40000000 #x0)) diff --git a/freeze.sh b/freeze.sh new file mode 100644 index 0000000000..632f2a7d0a --- /dev/null +++ b/freeze.sh @@ -0,0 +1,182 @@ +#! /bin/bash + +# Sourceforge username +SFUSER=${SFUSER:-$USER} + +set -ex + +usage() { + if ! [ -z "$1" ] + then + echo $1 + fi + cat <<EOF + +usage: $0 VERSION + + This script performs a number of sanity checks on the current repository, and creates + a lightweight tag for the revision in \$PWD/release.sbcl (or does it?). + + ENVIRONMENT: + + SFUSER: Sourceforge username. Defaults to \$USER + SBCL_RELEASE_DIR: Absolute path to directory containing all the build + artifacts. If not defined, a new build directory is created in \$PWD. + CCL: Path to Clozure Common Lisp, suitable as an argument to make.sh + CLISP: Path to CLISP, suitable as an argument to make.sh +EOF + exit 1 +} + +if [ -z "$1" ] +then + usage "No version number." +else + VERSION="$1-rc"; shift + echo $VERSION | perl -pe 'die "Invalid version number: $_\n" if !/^\d+\.\d+\.\d+-rc$/' +fi + +if ! [ -z "$@" ] +then + usage "Extra command-line arguments: $@" +fi + +if [ -z "$CLISP" ] +then + usage "CLISP environment variable not set" +fi + +SBCL_RELEASE_DIR=${SBCL_RELEASE_DIR:-$(mktemp -d $PWD/sbcl-release-dir-$(date +%Y%m%d)-XXXXXXXXX)} +SBCL_DIR=$SBCL_RELEASE_DIR/sbcl-$VERSION +GIT_DIR=$PWD/release.sbcl +LOGFILE=$SBCL_RELEASE_DIR/log.txt + +if [ ! -d $SBCL_DIR ]; then + sbcl_directory="$(cd "$(dirname $0)"; pwd)" + cd $GIT_DIR + + echo "Checking that the tree is clean." + if ! [ $(git status --porcelain | wc -l) = 0 ] + then + echo "There are uncommitted / unpushed changes in this checkout!" + git status + exit 1 + fi + + ## Find the current version using git describe + git_describe_version="$(git describe | grep -E '^sbcl-[0-9]\.[0-9]+\.[0-9]+' | sed -E 's/^sbcl-([0-9]\.[0-9]+\.[0-9]+)-.*$/\1/')" + ## Check NEWS + + echo "Checking NEWS" + if ! grep "^changes relative to sbcl-$git_describe_version:" NEWS > /dev/null + then + echo "NEWS not in correct format!" + exit 1 + fi + + ## Make draft release notes + + if [ ! -f $SBCL_RELEASE_DIR/sbcl-$VERSION-release-notes.txt ]; then + awk "BEGIN { state = 0 } + /^changes relative to sbcl-/ { state = 1 } + /^changes in sbcl-/ { state = 0 } + { if(state == 1) print \$0 }" < $GIT_DIR/NEWS > $SBCL_RELEASE_DIR/sbcl-$VERSION-release-notes.txt + fi + + ## Tag + + # I'd like to use the same tag each time, but I can't convince + # myself that that will do the right thing when pushed, and I don't + # want to break all our mirrors for this. + + # echo "Tagging as release_candidate" + # git tag release_candidate + + git clone $GIT_DIR $SBCL_DIR +fi + +# check self-build (without float oracle) + +## Build x86-64 binary for bootstrap. + +if [ ! -d $SBCL_RELEASE_DIR/bin ]; then + echo "Building bootstrap x86-64 binary" + cd $SBCL_DIR + nice -20 ./make.sh >$LOGFILE 2>&1 + + cd tests + nice -20 sh ./run-tests.sh >>$LOGFILE 2>&1 + mkdir -p $SBCL_RELEASE_DIR/bin + cp $SBCL_DIR/src/runtime/sbcl $SBCL_RELEASE_DIR/bin/sbcl + cp $SBCL_DIR/output/sbcl.core $SBCL_RELEASE_DIR/bin/sbcl.core +fi + +## Build x86-64 release candidate binary. + +if [ ! -d $SBCL_RELEASE_DIR/sbcl-$VERSION-x86-64-linux ]; then + echo "Building release candidate x86-64 binary" + cd $SBCL_DIR + sh clean.sh + nice -20 ./make.sh "$SBCL_RELEASE_DIR/bin/sbcl --core $SBCL_RELEASE_DIR/bin/sbcl.core --no-userinit" >> $LOGFILE 2>&1 + cd doc && sh ./make-doc.sh + cd $SBCL_RELEASE_DIR + + ln -s $SBCL_DIR $SBCL_RELEASE_DIR/sbcl-$VERSION-x86-64-linux + sh $SBCL_DIR/binary-distribution.sh sbcl-$VERSION-x86-64-linux + bzip2 sbcl-$VERSION-x86-64-linux-binary.tar + sh $SBCL_DIR/html-distribution.sh sbcl-$VERSION + bzip2 sbcl-$VERSION-documentation-html.tar + + mv $SBCL_DIR/obj/from-xc obj_from-xc_sbcl +fi + +# check build from ccl + +if [ -n "$CCL" ]; then + if [ ! -d $SBCL_RELEASE_DIR/obj_from-xc_ccl ]; then + cd $SBCL_DIR + sh clean.sh + nice -20 ./make.sh "$CCL" >> $LOGFILE 2>&1 + cd $SBCL_RELEASE_DIR + + mv $SBCL_DIR/obj/from-xc obj_from-xc_ccl + fi +fi + +if [ ! -d $SBCL_RELEASE_DIR/obj_from-xc_clisp ]; then + cd $SBCL_DIR + sh clean.sh + nice -20 ./make.sh "$CLISP" >> $LOGFILE 2>&1 + cd $SBCL_RELEASE_DIR + + mv $SBCL_DIR/obj/from-xc obj_from-xc_clisp +fi + +# TODO: check binary-equality between ccl, clisp, sbcl objs + +# TODO: check build from abcl, ecl + +# upload rc build + +if [ ! -f $SBCL_RELEASE_DIR/uploaded ]; then + + read -n 1 -p "Ok to upload? " A; echo + if [ $A \!= "y" ]; then + exit 1 + fi + + cd $SBCL_RELEASE_DIR +cat > $SBCL_RELEASE_DIR/sftp-batch <<EOF +cd /home/frs/project/s/sb/sbcl/sbcl-rc +put sbcl-$VERSION-x86-64-linux-binary.tar.bz2 +put sbcl-$VERSION-documentation-html.tar.bz2 +put sbcl-$VERSION-release-notes.txt +EOF + sftp -b $SBCL_RELEASE_DIR/sftp-batch $SFUSER,sbcl@frs.sourceforge.net + touch uploaded +fi + +# TODO: check self-crossbuild on x86, arm, ppc + + +# TODO: find Fix Committed lp bugs for NEWS frobbery diff --git a/generate-version.sh b/generate-version.sh index 99ec6b1cbe..03e6cc3bd4 100755 --- a/generate-version.sh +++ b/generate-version.sh @@ -35,14 +35,7 @@ else fi if [ -z "$SBCL_BUILDING_RELEASE_FROM" ] then - if [ "`git rev-list HEAD --not origin/master`" = '' ] - then - # If origin/master contains all the commits on current - # branch, use current head as the root instead. - version_root="$version_branchname" - else - version_root="origin/master" - fi + version_root=`git merge-base HEAD origin/master` else version_root="$SBCL_BUILDING_RELEASE_FROM" fi @@ -63,7 +56,7 @@ if git diff HEAD --no-ext-diff --quiet --exit-code then version_dirty="" else - version_dirty="-dirty" + version_dirty="-WIP" fi # Now that we have all the pieces, put them together. cat >version.lisp-expr <<EOF diff --git a/install.sh b/install.sh index 22e04b7704..06142430f9 100755 --- a/install.sh +++ b/install.sh @@ -113,6 +113,9 @@ test -f "$BUILD_ROOT$SBCL_HOME"/sbcl.core && \ cp src/runtime/$RUNTIME "$BUILD_ROOT$INSTALL_ROOT"/bin/ cp output/sbcl.core "$BUILD_ROOT$SBCL_HOME"/sbcl.core +test -f src/runtime/libsbcl.so && \ + cp src/runtime/libsbcl.so "$BUILD_ROOT$INSTALL_ROOT"/lib/ + cp src/runtime/sbcl.mk "$BUILD_ROOT$SBCL_HOME"/sbcl.mk for i in $(grep '^LIBSBCL=' src/runtime/sbcl.mk | cut -d= -f2-) ; do cp "src/runtime/$i" "$BUILD_ROOT$SBCL_HOME/$i" @@ -120,12 +123,12 @@ done # installing contrib -. ./sbcl-pwd.sh -sbcl_pwd +# See make-target-contrib.sh for this variable. +SBCL_TOP="../../" -SBCL="$SBCL_PWD/src/runtime/sbcl --noinform --core $SBCL_PWD/output/sbcl.core --no-userinit --no-sysinit --disable-debugger" +SBCL="$SBCL_TOP/src/runtime/sbcl --noinform --core $SBCL_TOP/output/sbcl.core --no-userinit --no-sysinit --disable-debugger" SBCL_BUILDING_CONTRIB=1 -export SBCL SBCL_BUILDING_CONTRIB SBCL_PWD +export SBCL SBCL_BUILDING_CONTRIB SBCL_TOP . ./find-gnumake.sh find_gnumake diff --git a/make-all-targets.sh b/make-all-targets.sh new file mode 100755 index 0000000000..b57aa7a8d5 --- /dev/null +++ b/make-all-targets.sh @@ -0,0 +1,12 @@ +#!/bin/sh + +rm -fr obj/xbuild +mkdir -p obj/xbuild + +make -k -j9 -f crossbuild-runner/Makefile \ + output/arm.core output/arm64.core \ + output/mips.core \ + output/ppc.core output/ppc64.core \ + output/riscv.core \ + output/sparc.core \ + output/x86.core output/x86-64.core diff --git a/make-c-runtime.sh b/make-c-runtime.sh index 02d4c4aeb9..c8a5ba7c62 100755 --- a/make-c-runtime.sh +++ b/make-c-runtime.sh @@ -3,18 +3,16 @@ # Load our build configuration . output/build-config -# This script is supposed to be host-agnostic, but unfortunately in testing -# I have found it to be sensitive to the host in the following ways: -# - using CCL it gets "Error: Incorrect keyword arguments in (:TEST EQ T)." -# - using CLISP it prints "WARNING: cross-compiler type ambiguity" 540 times. -# We could make this use the target SBCL as the new host, -# but that somewhat defeats the purpose. - -time $SBCL_XC_HOST --noinform --no-userinit --no-sysinit --noprint <<EOF +# This script has been tested with CLISP, ECL and SBCL (of course). +# Running with CCL it gets: +# > Error: Class is not yet defined or was undefined: CTYPE +# > While executing: COMPILER-LAYOUT-OR-LOSE, in process listener(1). +time $SBCL_XC_HOST <<EOF (load "src/cold/shared.lisp") (load "src/cold/set-up-cold-packages.lisp") (load "tools-for-build/corefile.lisp") (in-package "SB-COLD") +(defvar *target-sbcl-version* (read-from-file "version.lisp-expr")) (in-host-compilation-mode (lambda (&aux (sb-xc:*features* (cons :c-headers-only sb-xc:*features*))) (do-stems-and-flags (stem flags 1) @@ -27,4 +25,4 @@ EOF diff -r output/genesis-2 src/runtime/genesis -(cd src/runtime ; make) +(cd src/runtime ; $GNUMAKE) diff --git a/make-config.sh b/make-config.sh index 1e86051928..36e13fcf7f 100755 --- a/make-config.sh +++ b/make-config.sh @@ -37,6 +37,13 @@ bad_option() { WITH_FEATURES="" WITHOUT_FEATURES="" FANCY_FEATURES=":sb-core-compression :sb-xref-for-internals :sb-after-xc-core" +CONTRIBS="" +for dir in `cd contrib ; echo *`; do + if [ -d "contrib/$dir" -a -f "contrib/$dir/Makefile" ]; then + CONTRIBS="$CONTRIBS ${dir}" + fi +done +SBCL_CONTRIB_BLOCKLIST=${SBCL_CONTRIB_BLOCKLIST:-""} perform_host_lisp_check=no fancy=false @@ -88,7 +95,14 @@ do ;; --without) WITHOUT_FEATURES="$WITHOUT_FEATURES :$optarg" + case $CONTRIBS + in *"$optarg"*) + SBCL_CONTRIB_BLOCKLIST="$SBCL_CONTRIB_BLOCKLIST $optarg" + ;; esac ;; + --extra-linkage-table-entries=) + $optarg_ok && SBCL_EXTRA_LINKAGE_TABLE_ENTRIES=$optarg + ;; --fancy) WITH_FEATURES="$WITH_FEATURES $FANCY_FEATURES" # Lower down we add :sb-thread for platforms where it can be built. @@ -213,6 +227,17 @@ Options: Transfer the files to/from directory /home/user/sbcl on host-machine. + --extra-linkage-table-entries=<path> Specify extra C symbols to include in + the linkage table + + Path to a file specifying symbols that must be included in the + SBCL linkage table. Useful for statically linking libraries + into the runtime and ensuring the linker does not remove them. + The file must contain a single list of two element lists. Each + sublist must have a string naming a C symbol as its first + element and NIL or T (if the symbol names a variable) as its + second element. + EOF exit 1 fi @@ -254,6 +279,11 @@ find_gnumake ./generate-version.sh +# Copy the extra linkage entries to output folder for Genesis to find. +if [ -n "$SBCL_EXTRA_LINKAGE_TABLE_ENTRIES" ] && [ -f "$SBCL_EXTRA_LINKAGE_TABLE_ENTRIES" ]; then + cp "$SBCL_EXTRA_LINKAGE_TABLE_ENTRIES" output/extra-linkage-table-entries.lisp-expr +fi + # Now that we've done our option parsing and found various # dependencies, write them out to a file to be sourced by other # scripts. @@ -294,7 +324,7 @@ case `uname` in esac ;; DragonFly) - sbcl_os="dragonfly" + sbcl_os="dragonflybsd" ;; Darwin) sbcl_os="darwin" @@ -305,9 +335,6 @@ case `uname` in CYGWIN* | WindowsNT | MINGW* | MSYS*) sbcl_os="win32" ;; - HP-UX) - sbcl_os="hpux" - ;; Haiku) sbcl_os="haiku" ;; @@ -363,7 +390,6 @@ case `uname -m` in i86pc) guessed_sbcl_arch=x86 ;; *x86_64) guessed_sbcl_arch=x86-64 ;; amd64) guessed_sbcl_arch=x86-64 ;; - [Aa]lpha) guessed_sbcl_arch=alpha ;; sparc*) guessed_sbcl_arch=sparc ;; sun*) guessed_sbcl_arch=sparc ;; *ppc) guessed_sbcl_arch=ppc ;; @@ -371,9 +397,8 @@ case `uname -m` in ppc64le) guessed_sbcl_arch=ppc64 ;; # is ok because there was never 32-bit LE Power*Macintosh) guessed_sbcl_arch=ppc ;; ibmnws) guessed_sbcl_arch=ppc ;; - parisc*) guessed_sbcl_arch=hppa ;; - 9000/800) guessed_sbcl_arch=hppa ;; mips*) guessed_sbcl_arch=mips ;; + arm64) guessed_sbcl_arch=arm64 ;; *arm*) guessed_sbcl_arch=arm ;; aarch64) guessed_sbcl_arch=arm64 ;; riscv32) guessed_sbcl_arch=riscv xlen=32;; @@ -392,10 +417,16 @@ if [ "$sbcl_os" = "sunos" ] && [ `isainfo -k` = "amd64" ]; then fi # Under Darwin, uname -m returns "i386" even if CPU is x86_64. +# (I suspect this is not true any more - it reports "x86_64 for me) if [ "$sbcl_os" = "darwin" ] && [ "`/usr/sbin/sysctl -n hw.optional.x86_64`" = "1" ]; then guessed_sbcl_arch=x86-64 fi +# Under NetBSD, uname -m returns "evbarm" even if CPU is arm64. +if [ "$sbcl_os" = "netbsd" ] && [ `uname -p` = "aarch64" ]; then + guessed_sbcl_arch=arm64 +fi + echo //setting up CPU-architecture-dependent information if test -n "$SBCL_ARCH" then @@ -423,7 +454,7 @@ then # If --fancy, enable threads on platforms where they can be built. case $sbcl_arch in x86|x86-64|ppc|arm64|riscv) - if [ "$sbcl_os" = "dragonfly" ] + if [ "$sbcl_os" = "dragonflybsd" ] then echo "No threads on this platform." else @@ -437,12 +468,16 @@ then esac else case $sbcl_arch in - x86|x86-64|arm64) + x86|x86-64) case $sbcl_os in linux|darwin) WITH_FEATURES="$WITH_FEATURES :sb-thread" esac esac + case $sbcl_arch in + arm64|riscv) + WITH_FEATURES="$WITH_FEATURES :sb-thread" + esac fi case "$sbcl_os" in @@ -473,9 +508,12 @@ echo //initializing $ltf echo ';;;; This is a machine-generated file.' > $ltf echo ';;;; Please do not edit it by hand.' >> $ltf echo ';;;; See make-config.sh.' >> $ltf -echo "(lambda (features) (set-difference (union features (list$WITH_FEATURES " >> $ltf +echo "(lambda (features) (set-difference (union features (list :${sbcl_arch}$WITH_FEATURES " >> $ltf -printf ":%s" "$sbcl_arch" >> $ltf +# Automatically block sb-simd on non-x86 platforms, at least for now. +case "$sbcl_arch" in + x86-64) ;; *) SBCL_CONTRIB_BLOCKLIST="$SBCL_CONTRIB_BLOCKLIST sb-simd" ;; +esac echo //setting up OS-dependent information @@ -490,105 +528,69 @@ link_or_copy $sbcl_arch-arch.h target-arch.h link_or_copy $sbcl_arch-lispregs.h target-lispregs.h case "$sbcl_os" in linux) - printf ' :unix' >> $ltf - printf ' :elf' >> $ltf - printf ' :linux' >> $ltf + printf ' :unix :linux :elf' >> $ltf case "$sbcl_arch" in - x86 | x86-64 | arm64) + arm64 | ppc64 | x86 | x86-64) printf ' :gcc-tls' >> $ltf esac + case "$sbcl_arch" in + arm | arm64 | ppc | ppc64 | x86 | x86-64) + printf ' :use-sys-mmap' >> $ltf + esac # If you add other platforms here, don't forget to edit # src/runtime/Config.foo-linux too. case "$sbcl_arch" in - mips | arm) + mips | arm | x86 | x86-64) printf ' :largefile' >> $ltf ;; - x86 | x86-64) - printf ' :sb-futex :largefile' >> $ltf - ;; - ppc | ppc64 | arm64 | riscv) - printf ' :sb-futex' >> $ltf - ;; esac - link_or_copy Config.$sbcl_arch-linux Config link_or_copy $sbcl_arch-linux-os.h target-arch-os.h link_or_copy linux-os.h target-os.h ;; - hpux) - printf ' :unix' >> $ltf - printf ' :elf' >> $ltf - printf ' :hpux' >> $ltf - link_or_copy Config.$sbcl_arch-hpux Config - link_or_copy $sbcl_arch-hpux-os.h target-arch-os.h - link_or_copy hpux-os.h target-os.h - ;; haiku) - printf ' :unix :elf :haiku :int4-breakpoints' >> $ltf + printf ' :unix :haiku :elf :int4-breakpoints' >> $ltf link_or_copy Config.$sbcl_arch-haiku Config link_or_copy $sbcl_arch-haiku-os.h target-arch-os.h link_or_copy haiku-os.h target-os.h ;; *bsd) - printf ' :unix' >> $ltf - printf ' :bsd' >> $ltf + printf ' :unix :bsd :elf' >> $ltf + # FIXME: can we enable :gcc-tls across all variants? link_or_copy $sbcl_arch-bsd-os.h target-arch-os.h link_or_copy bsd-os.h target-os.h case "$sbcl_os" in *freebsd) - printf ' :elf' >> $ltf printf ' :freebsd' >> $ltf printf ' :gcc-tls' >> $ltf if [ $sbcl_os = "gnu-kfreebsd" ]; then printf ' :gnu-kfreebsd' >> $ltf fi - - if [ $sbcl_arch = "x86" ]; then - printf ' :restore-fs-segment-register-from-tls' >> $ltf - fi link_or_copy Config.$sbcl_arch-$sbcl_os Config ;; openbsd) - printf ' :elf' >> $ltf printf ' :openbsd' >> $ltf link_or_copy Config.$sbcl_arch-openbsd Config ;; netbsd) printf ' :netbsd' >> $ltf - printf ' :elf' >> $ltf link_or_copy Config.$sbcl_arch-netbsd Config ;; + dragonflybsd) + printf ' :dragonfly' >> $ltf + link_or_copy Config.$sbcl_arch-dragonfly Config + ;; *) echo unsupported BSD variant: `uname` exit 1 ;; esac ;; - dragonfly) - printf ' :unix' >> $ltf - printf ' :bsd' >> $ltf - printf ' :elf' >> $ltf - printf ' :dragonfly' >> $ltf - printf ' :sb-qshow' >> $ltf - if [ $sbcl_arch = "x86" ]; then - printf ' :restore-fs-segment-register-from-tls' >> $ltf - fi - link_or_copy $sbcl_arch-bsd-os.h target-arch-os.h - link_or_copy bsd-os.h target-os.h - link_or_copy Config.$sbcl_arch-dragonfly Config - ;; darwin) - printf ' :unix' >> $ltf - printf ' :mach-o' >> $ltf - printf ' :bsd' >> $ltf - printf ' :darwin' >> $ltf - if [ $sbcl_arch = "x86" ]; then - printf ' :mach-exception-handler :restore-fs-segment-register-from-tls' >> $ltf - fi + printf ' :unix :bsd :darwin :mach-o' >> $ltf if [ $sbcl_arch = "x86-64" ]; then - printf ' :mach-exception-handler' >> $ltf darwin_version=`uname -r` darwin_version_major=${DARWIN_VERSION_MAJOR:-${darwin_version%%.*}} @@ -596,14 +598,15 @@ case "$sbcl_os" in printf ' :inode64' >> $ltf fi fi + if [ $sbcl_arch = "arm64" ]; then + printf ' :darwin-jit :gcc-tls' >> $ltf + fi link_or_copy $sbcl_arch-darwin-os.h target-arch-os.h link_or_copy bsd-os.h target-os.h link_or_copy Config.$sbcl_arch-darwin Config ;; sunos) - printf ' :unix' >> $ltf - printf ' :elf' >> $ltf - printf ' :sunos' >> $ltf + printf ' :unix :sunos :elf' >> $ltf if [ $sbcl_arch = "x86-64" ]; then printf ' :largefile' >> $ltf fi @@ -617,7 +620,6 @@ case "$sbcl_os" in # Optional features -- We enable them by default, but the build # ought to work perfectly without them: # - printf ' :sb-futex' >> $ltf printf ' :sb-qshow' >> $ltf # # Required features -- Some of these used to be optional, but @@ -626,8 +628,7 @@ case "$sbcl_os" in # (Of course it doesn't provide dlopen, but there is # roughly-equivalent magic nevertheless:) printf ' :os-provides-dlopen' >> $ltf - printf ' :sb-thread :sb-safepoint :sb-thruption :sb-wtimer' >> $ltf - printf ' :sb-safepoint-strictly' >> $ltf + printf ' :sb-thread :sb-safepoint' >> $ltf # link_or_copy Config.$sbcl_arch-win32 Config link_or_copy $sbcl_arch-win32-os.h target-arch-os.h @@ -654,21 +655,12 @@ cd "$original_dir" # (define-feature :c-stack-grows-downwards-not-upwards (features) # (member :x86 features)) -# KLUDGE: currently the x86 only works with the generational garbage -# collector (indicated by the presence of :GENCGC in *FEATURES*) and -# alpha, sparc and ppc with the stop'n'copy collector (indicated by -# the absence of :GENCGC in *FEATURES*). This isn't a great -# separation, but for now, rather than have :GENCGC in -# base-target-features.lisp-expr, we add it into local-target-features -# if we're building for x86. -- CSR, 2002-02-21 Then we do something -# similar with :STACK-GROWS-FOOWARD, too. -- WHN 2002-03-03 -if [ "$sbcl_arch" = "x86" ]; then - printf ' :gencgc :stack-grows-downward-not-upward :c-stack-is-control-stack' >> $ltf - printf ' :compare-and-swap-vops :unwind-to-frame-and-call-vop' >> $ltf - printf ' :stack-allocatable-closures :stack-allocatable-vectors' >> $ltf - printf ' :stack-allocatable-lists :stack-allocatable-fixed-objects' >> $ltf - printf ' :alien-callbacks :cycle-counter' >> $ltf - printf ' :fp-and-pc-standard-save' >> $ltf +case "$sbcl_arch" in + x86) + if [ "$sbcl_os" = "darwin" ]; then + echo "Unsupported configuration" + exit 1 + fi if [ "$sbcl_os" = "win32" ]; then # of course it doesn't provide dlopen, but there is # roughly-equivalent magic nevertheless. @@ -678,31 +670,21 @@ if [ "$sbcl_arch" = "x86" ]; then rm -f src/runtime/openbsd-sigcontext.h sh tools-for-build/openbsd-sigcontext.sh > src/runtime/openbsd-sigcontext.h fi -elif [ "$sbcl_arch" = "x86-64" ]; then - printf ' :64-bit :gencgc :stack-grows-downward-not-upward :c-stack-is-control-stack' >> $ltf - printf ' :compare-and-swap-vops :unwind-to-frame-and-call-vop' >> $ltf - printf ' :fp-and-pc-standard-save' >> $ltf - printf ' :stack-allocatable-closures :stack-allocatable-vectors' >> $ltf - printf ' :stack-allocatable-lists :stack-allocatable-fixed-objects' >> $ltf - printf ' :alien-callbacks :cycle-counter' >> $ltf - printf ' :integer-eql-vop' >> $ltf - printf ' :sb-simd-pack :sb-simd-pack-256 :avx2' >> $ltf - printf ' :undefined-fun-restarts :call-symbol' >> $ltf - printf ' :unbind-in-unwind :no-continue-unwind' >> $ltf + ;; + x86-64) + printf ' :sb-simd-pack :sb-simd-pack-256 :avx2' >> $ltf # not mandatory + + $GNUMAKE -C tools-for-build avx2 + if tools-for-build/avx2; then + SBCL_CONTRIB_BLOCKLIST="$SBCL_CONTRIB_BLOCKLIST sb-simd" + fi case "$sbcl_os" in linux | darwin | *bsd) - printf ' :immobile-space :immobile-code :compact-instance-header' >> $ltf + printf ' :immobile-space' >> $ltf esac -elif [ "$sbcl_arch" = "mips" ]; then - printf ' :cheneygc' >> $ltf - printf ' :stack-allocatable-closures :stack-allocatable-vectors' >> $ltf - printf ' :stack-allocatable-lists :stack-allocatable-fixed-objects' >> $ltf - printf ' :alien-callbacks' >> $ltf -elif [ "$sbcl_arch" = "ppc" ]; then - printf ' :gencgc :stack-allocatable-closures :stack-allocatable-vectors' >> $ltf - printf ' :stack-allocatable-lists :stack-allocatable-fixed-objects' >> $ltf - printf ' :compare-and-swap-vops :alien-callbacks' >> $ltf + ;; + ppc) if [ "$sbcl_os" = "linux" ]; then # Use a C program to detect which kind of glibc we're building on, # to bandage across the break in source compatibility between @@ -712,28 +694,17 @@ elif [ "$sbcl_arch" = "ppc" ]; then $GNUMAKE -C tools-for-build where-is-mcontext -I ../src/runtime tools-for-build/where-is-mcontext > src/runtime/ppc-linux-mcontext.h || (echo "error running where-is-mcontext"; exit 1) elif [ "$sbcl_os" = "darwin" ]; then - # We provide a dlopen shim, so a little lie won't hurt - printf ' :os-provides-dlopen' >> $ltf - # The default stack ulimit under darwin is too small to run PURIFY. - # Best we can do is complain and exit at this stage - if [ "`ulimit -s`" = "512" ]; then - echo "Your stack size limit is too small to build SBCL." - echo "See the limit(1) or ulimit(1) commands and the README file." - exit 1 - fi + echo "Unsupported configuration" + exit 1 fi -elif [ "$sbcl_arch" = "ppc64" ]; then - # threads are required because differing versions of the vops for BOUNDP - # and [fast-]symbol-[global-]value and CAS create extra maintenance burden. - printf ' :64-bit :untagged-fdefns :sb-thread' >> $ltf - printf ' :gencgc :stack-allocatable-closures :stack-allocatable-vectors' >> $ltf - printf ' :stack-allocatable-lists :stack-allocatable-fixed-objects' >> $ltf - printf ' :compare-and-swap-vops :alien-callbacks' >> $ltf + ;; + ppc64) # there is no glibc bug that requires the 'where-is-mcontext' hack. # (Sufficiently new glibc uses the correct definition, which is the same as # 2.3.1, so define our constant for that) echo '#define GLIBC231_STYLE_UCONTEXT 1' > src/runtime/ppc-linux-mcontext.h -elif [ "$sbcl_arch" = "riscv" ]; then + ;; + riscv) if [ "$xlen" = "64" ]; then printf ' :64-bit' >> $ltf elif [ "$xlen" = "32" ]; then @@ -742,63 +713,7 @@ elif [ "$sbcl_arch" = "riscv" ]; then echo 'Architecture word width unspecified. (Either 32-bit or 64-bit.)' exit 1 fi - printf ' :gencgc' >> $ltf - printf ' :stack-allocatable-closures :stack-allocatable-vectors' >> $ltf - printf ' :stack-allocatable-lists :stack-allocatable-fixed-objects' >> $ltf - printf ' :compare-and-swap-vops :memory-barrier-vops' >> $ltf -elif [ "$sbcl_arch" = "sparc" ]; then - # Test the compiler in order to see if we are building on Sun - # toolchain as opposed to GNU binutils, and write the appropriate - # FUNCDEF macro for assembler. No harm in running this on sparc-linux - # as well. - sh tools-for-build/sparc-funcdef.sh > src/runtime/sparc-funcdef.h - if [ "$sbcl_os" = "netbsd" ] || [ "$sbcl_os" = "sunos" ] || [ "$sbcl_os" = "linux" ]; then - printf ' :gencgc' >> $ltf - else - echo '***' - echo '*** You are running SPARC on other than SunOS, NetBSD, or Linux. Since' - echo '*** GENCGC is untested on this combination, make-config.sh' - echo '*** is falling back to CHENEYGC. Please consider adjusting' - echo '*** parms.lisp to build with GENCGC instead.' - echo '***' - printf ' :cheneygc' >> $ltf - fi - printf ' :stack-allocatable-closures :stack-allocatable-lists' >> $ltf -elif [ "$sbcl_arch" = "alpha" ]; then - printf ' :64-bit-registers' >> $ltf - printf ' :cheneygc' >> $ltf - printf ' :stack-allocatable-closures :stack-allocatable-lists' >> $ltf - printf ' :stack-allocatable-fixed-objects' >> $ltf -elif [ "$sbcl_arch" = "hppa" ]; then - printf ' :cheneygc' >> $ltf - printf ' :stack-allocatable-vectors :stack-allocatable-fixed-objects' >> $ltf - printf ' :stack-allocatable-closures :stack-allocatable-lists' >> $ltf -elif [ "$sbcl_arch" = "arm" ]; then - printf ' :gencgc :alien-callbacks' >> $ltf - # As opposed to soft-float or FPA, we support VFP only (and - # possibly VFPv2 and higher only), but we'll leave the obvious - # hooks in for someone to add the support later. - printf ' :arm-vfp :arm-vfpv2' >> $ltf - printf ' :stack-allocatable-lists :stack-allocatable-fixed-objects' >> $ltf - printf ' :stack-allocatable-vectors :stack-allocatable-closures' >> $ltf - printf ' :fp-and-pc-standard-save' >> $ltf -elif [ "$sbcl_arch" = "arm64" ]; then - printf ' :64-bit :gencgc :fp-and-pc-standard-save' >> $ltf - printf ' :alien-callbacks' >> $ltf - printf ' :stack-allocatable-lists :stack-allocatable-fixed-objects' >> $ltf - printf ' :stack-allocatable-vectors :stack-allocatable-closures' >> $ltf - printf ' :unbind-in-unwind' >> $ltf - printf ' :compare-and-swap-vops :undefined-fun-restarts' >> $ltf -else - # Nothing need be done in this case, but sh syntax wants a placeholder. - echo > /dev/null -fi - -# There are only two architectures that don't have linkage tables, -# and they also don't compile for half a dozen other reasons. -case "$sbcl_arch" in - alpha | hppa) ;; - *) printf ' :linkage-table' >> $ltf + ;; esac # Use a little C program to try to guess the endianness. Ware @@ -812,8 +727,11 @@ export sbcl_os sbcl_arch sh tools-for-build/grovel-features.sh >> $ltf echo //finishing $ltf +printf " %s" "`cat crossbuild-runner/backends/${sbcl_arch}/features`" >> $ltf echo ")) (list$WITHOUT_FEATURES)))" >> $ltf +echo "SBCL_CONTRIB_BLOCKLIST=\"$SBCL_CONTRIB_BLOCKLIST\"; export SBCL_CONTRIB_BLOCKLIST" >> output/build-config + # FIXME: The version system should probably be redone along these lines: # # echo //setting up version information. diff --git a/make-genesis-2.lisp b/make-genesis-2.lisp index cb17160e1a..1bc9a27139 100644 --- a/make-genesis-2.lisp +++ b/make-genesis-2.lisp @@ -14,17 +14,17 @@ (push (stem-object-path stem flags :target-compile) list))) (nreverse list)) - :defstruct-descriptions (stem-object-path - "defstructs.lisp-expr" '(:extra-artifact) :target-compile) - :tls-init (read-from-file - (stem-object-path "tls-init.lisp-expr" - '(:extra-artifact) :target-compile)) + :defstruct-descriptions (find-bootstrap-file "output/defstructs.lisp-expr" t) + :tls-init (read-from-file "output/tls-init.lisp-expr" :build-dependent t) :c-header-dir-name "output/genesis-2" :symbol-table-file-name "src/runtime/sbcl.nm" :core-file-name "output/cold-sbcl.core" ;; The map file is not needed by the system, but can be ;; very handy when debugging cold init problems. - :map-file-name "output/cold-sbcl.map") + :map-file-name "output/cold-sbcl.map" + :linkage-table-prefill-info-c-name "src/runtime/linkage-table-prelink-info.c" + :extra-linkage-table-entries (when (probe-file "output/extra-linkage-table-entries.lisp-expr") + (read-from-file "output/extra-linkage-table-entries.lisp-expr"))) #+cmu (ext:quit) #+clisp (ext:quit) #+abcl (ext:quit) diff --git a/make-host-1.lisp b/make-host-1.lisp index c56848fa43..0a0cde559d 100644 --- a/make-host-1.lisp +++ b/make-host-1.lisp @@ -3,22 +3,20 @@ (let ((*print-pretty* nil) (*print-length* nil)) (dolist (thing '(("SB-XC" "*FEATURES*") - ("SB-COLD" "*SHEBANG-BACKEND-SUBFEATURES*"))) + ("SB-COLD" "BACKEND-SUBFEATURES"))) (let* ((sym (intern (cadr thing) (car thing))) (val (symbol-value sym))) (when val (format t "~&target ~S = ~S~%" sym val)))))) (in-package "SB-COLD") +#+sbcl +(declaim (sb-ext:muffle-conditions + sb-ext:compiler-note + (satisfies optional+key-style-warning-p))) (progn - ;; Generating ldso-stubs should be driven by GNUmakefile, but that won't work - ;; because we generate it using Lisp code, and we don't presume the target - ;; to have a lisp implementation. So we generate it on the host by knowing - ;; something about which Config files depend on ldso-stubs. - (when (or (member :alpha sb-xc:*features*) - (member :hppa sb-xc:*features*)) - (let ((*readtable* *xc-readtable*)) (load "tools-for-build/ldso-stubs.lisp"))) - - (setf *host-obj-prefix* "obj/from-host/") + (setf *host-obj-prefix* (if (boundp 'cl-user::*sbcl-host-obj-prefix*) + (symbol-value 'cl-user::*sbcl-host-obj-prefix*) + "obj/from-host/")) (load "src/cold/set-up-cold-packages.lisp") (load "src/cold/defun-load-or-cload-xcompiler.lisp") @@ -36,31 +34,22 @@ ;; UNDEFINED-VARIABLE does not cause COMPILE-FILE to return warnings-p ;; unless outside a compilation unit. You find out about it only upon ;; exit of SUMMARIZE-COMPILATION-UNIT. So we set up a handler for that. - `(let (in-summary fail) - (handler-bind (((and simple-warning (not style-warning)) - (lambda (c &aux (fc (simple-condition-format-control c))) - ;; hack for PPC. See 'build-order.lisp-expr' - ;; Ignore the warning, and the warning about the warning. - (unless (and (stringp fc) - (or (search "not allowed by the operand type" fc) - (search "ignoring FAILURE-P return" fc))) - (setq fail 'warning)))) - ;; Prevent regressions on a few platforms - ;; that are known to build cleanly. - (sb-int:simple-style-warning - (lambda (c &aux (fc (simple-condition-format-control c))) - (when (and (feature-in-list-p '(:or :x86 :x86-64 :arm64) - :target) - in-summary - (stringp fc) - (search "undefined" fc)) - (unless (eq fail 'warning) - (setq fail 'style-warning)))))) - (with-compilation-unit () - (multiple-value-prog1 (progn ,@forms) (setq in-summary t)))) - (when fail + `(let (warnp style-warnp) + (handler-bind ((style-warning + ;; Any unmuffled STYLE-WARNING should fail + ;; These would typically be from undefined functions, + ;; or optional-and-key when that was visible. + (lambda (c) + (signal c) ; won't do SETQ if MUFFLE-WARNING is invoked + (setq style-warnp 'style-warning))) + (simple-warning + (lambda (c) + (declare (ignore c)) + (setq warnp 'warning)))) + (with-compilation-unit () ,@forms)) + (when (and (or warnp style-warnp) *fail-on-warnings*) (cerror "Proceed anyway" - "make-host-1 stopped due to unexpected ~A." fail))) + "make-host-1 stopped due to unexpected ~A." (or warnp style-warnp)))) #-(or clisp sbcl) `(with-compilation-unit () ,@forms))) @@ -100,21 +89,32 @@ "tools-for-build/DerivedNormalizationProps.txt" "tools-for-build/more-ucd-consts.lisp-expr")) (outputs '("output/bidi-mirrors.lisp-expr" - "output/block-ranges.lisp-expr" + "output/BidiMirroring.txt" "output/block-names.lisp-expr" + "output/block-ranges.lisp-expr" + "output/Blocks.txt" "output/case.dat" "output/CaseFolding.txt" "output/casepages.dat" "output/casepages.lisp-expr" - "output/collation.dat" - "output/comp.dat" + "output/collation.lisp-expr" + "output/comp.lisp-expr" + "output/CompositionExclusions.txt" "output/confusables.lisp-expr" "output/decomp.dat" + "output/DerivedAge.txt" + "output/DerivedNormalizationProps.txt" + "output/EastAsianWidth.txt" "output/foldcases.lisp-expr" + "output/Jamo.txt" + "output/LineBreak.txt" "output/misc-properties.lisp-expr" - "output/n-collation-entries.lisp-expr" + "output/NormalizationCorrections.txt" "output/numerics.lisp-expr" "output/other-collation-info.lisp-expr" + "output/PropList.txt" + "output/Scripts.txt" + "output/SpecialCasing.txt" "output/titlecases.lisp-expr" "output/ucd1-names.lisp-expr" "output/ucdhigh.dat" @@ -129,7 +129,16 @@ (setf (gethash input *ucd-inputs*) 'unused)) (dolist (output outputs) (setf (gethash output *ucd-outputs*) 'unmade)) - (let ((object (compile-file "tools-for-build/ucd.lisp"))) + (let ((object (apply #'compile-file "tools-for-build/ucd.lisp" + ;; ECL creates its compiled files beside + ;; the truename of a source; that's bad + ;; when we're in a build tree of symlinks. + #+ecl + (list + :output-file + (compile-file-pathname "tools-for-build/ucd.lisp")) + #-ecl + ()))) (setf (gethash "tools-for-build/ucd.lisp" *ucd-inputs*) 'used) (load object :verbose t) (delete-file object)) @@ -160,16 +169,15 @@ #+ecl (proclaim '(optimize (safety 2) (debug 2))) (maybe-with-compilation-unit - (let ((*feature-evaluation-results* nil)) ;; If make-host-1 is parallelized, it will produce host fasls without loading ;; them. The host will have interpreted definitions of most everything, ;; which is OK because writing out the C headers is not compute-intensive. (load-or-cload-xcompiler #'host-cload-stem) - (write-feature-eval-results)) ;; propagate structure offset and other information to the C runtime ;; support code. (load "tools-for-build/corefile.lisp" :verbose nil) (host-cload-stem "src/compiler/generic/genesis" nil) ) ; END with-compilation-unit -(sb-cold:genesis :c-header-dir-name "src/runtime/genesis") +(unless (member :crossbuild-test sb-xc:*features*) + (sb-cold:genesis :c-header-dir-name "src/runtime/genesis")) diff --git a/make-host-1.sh b/make-host-1.sh index 66f75120f0..a841d0ee45 100755 --- a/make-host-1.sh +++ b/make-host-1.sh @@ -32,3 +32,14 @@ export LANG LC_ALL # environment. echo //building cross-compiler, and doing first genesis echo '(load "loader.lisp") (load-sbcl-file "make-host-1.lisp")' | $SBCL_XC_HOST + +# Use a little C program to grab stuff from the C header files and +# smash it into Lisp source code. +$GNUMAKE -C src/runtime clean +$GNUMAKE -C src/runtime sbcl.h +$GNUMAKE -C tools-for-build -I../src/runtime grovel-headers +tools-for-build/grovel-headers > output/stuff-groveled-from-headers.lisp + +if [ -n "$SBCL_HOST_LOCATION" ]; then + rsync -a output/stuff-groveled-from-headers.lisp "$SBCL_HOST_LOCATION/output" +fi diff --git a/make-host-2.lisp b/make-host-2.lisp index 88f9747742..d00d5fc741 100644 --- a/make-host-2.lisp +++ b/make-host-2.lisp @@ -14,36 +14,49 @@ ;; Supress function/macro redefinition warnings under clisp. #+clisp (setf custom:*suppress-check-redefinition* t) +;; Avoid natively compiling new code under ecl +#+ecl (ext:install-bytecodes-compiler) + ;;; Run the cross-compiler to produce cold fasl files. (setq sb-c::*track-full-called-fnames* :minimal) ; Change this as desired (setq sb-c::*static-vop-usage-counts* (make-hash-table)) (let (fail variables functions - types) - (sb-xc:with-compilation-unit () - (let ((*feature-evaluation-results* nil)) + types + warnp + style-warnp) + ;; Even the host may get STYLE-WARNINGS from e.g. cross-compiling + ;; macro definitions. FIXME: This is duplicate code from make-host-1 + (handler-bind ((style-warning + (lambda (c) + (signal c) + (setq style-warnp 'style-warning))) + (simple-warning + (lambda (c) + (declare (ignore c)) + (setq warnp 'warning)))) + (sb-xc:with-compilation-unit () (load "src/cold/compile-cold-sbcl.lisp") - (sanity-check-feature-evaluation)) - ;; Enforce absence of unexpected forward-references to warm loaded code. - ;; Looking into a hidden detail of this compiler seems fair game. - (when (and sb-c::*undefined-warnings* - (feature-in-list-p - '(:or :x86 :x86-64 :arm64) ; until all the rest are clean - :target)) - (setf fail t) - (dolist (warning sb-c::*undefined-warnings*) - (case (sb-c::undefined-warning-kind warning) - (:variable (setf variables t)) - (:type (setf types t)) - (:function (setf functions t)))))) + ;; Enforce absence of unexpected forward-references to warm loaded code. + ;; Looking into a hidden detail of this compiler seems fair game. + (when sb-c::*undefined-warnings* + (setf fail t) + (dolist (warning sb-c::*undefined-warnings*) + (case (sb-c::undefined-warning-kind warning) + (:variable (setf variables t)) + (:type (setf types t)) + (:function (setf functions t))))))) ;; Exit the compilation unit so that the summary is printed. Then complain. ;; win32 is not clean - (when (and fail (not (feature-in-list-p :win32 :target))) + (when (and fail (not (target-featurep :win32))) (cerror "Proceed anyway" "Undefined ~:[~;variables~] ~:[~;types~]~ - ~:[~;functions (incomplete SB-COLD::*UNDEFINED-FUN-WHITELIST*?)~]" - variables types functions))) + ~:[~;functions (incomplete SB-COLD::*UNDEFINED-FUN-ALLOWLIST*?)~]" + variables types functions)) + (when (and (or warnp style-warnp) *fail-on-warnings* (not (target-featurep :win32))) + (cerror "Proceed anyway" + "make-host-2 stopped due to unexpected ~A raised from the host." (or warnp style-warnp)))) #-clisp ; DO-ALL-SYMBOLS seems to kill CLISP at random (do-all-symbols (s) @@ -100,8 +113,7 @@ ;; As each platform's build becomes warning-free, ;; it should be added to the list here to prevent regresssions. (when (and likely-suspicious - (feature-in-list-p '(:and (:or :x86 :x86-64) (:or :linux :darwin)) - :target)) + (target-featurep '(:and (:or :x86 :x86-64) (:or :linux :darwin)))) (warn "Expected zero inlinining failures")))) ;; After cross-compiling, show me a list of types that checkgen diff --git a/make-shared-library.sh b/make-shared-library.sh new file mode 100755 index 0000000000..9acd9d8439 --- /dev/null +++ b/make-shared-library.sh @@ -0,0 +1,8 @@ +#!/bin/sh + +. output/build-config + +echo //entering make-shared-library.sh +echo //building sbcl runtime into a shared library + +$GNUMAKE -C src/runtime libsbcl.so diff --git a/make-target-1.sh b/make-target-1.sh index 81b4281b93..7eee8a3086 100755 --- a/make-target-1.sh +++ b/make-target-1.sh @@ -29,34 +29,17 @@ if [ -n "$SBCL_HOST_LOCATION" ]; then rsync -a "$SBCL_HOST_LOCATION/src/runtime/genesis" src/runtime fi -# Build the runtime system and symbol table (.nm) file. +# Build the runtime system # # (This C build has to come after the first genesis in order to get -# the sbcl.h the C build needs, and come before the second genesis in -# order to produce the symbol table file that second genesis needs. It -# could come either before or after running the cross compiler; that -# doesn't matter.) -# -# Note that the latter requirement does not apply to :linkage-table -# builds, since the cross compiler does not depend on symbol tables in -# that case. Only because sbcl.nm is convenient for debugging purposes -# is its generation left enabled even for those builds. +# 'sbcl.h' which the C build. It could come either before or after running +# the cross compiler; that doesn't matter.) echo //building runtime system and symbol table file -# The clean is needed for Darwin's readonlyspace hack. $GNUMAKE -C src/runtime clean -# $GNUMAKE -C src/runtime depend $GNUMAKE $SBCL_MAKE_JOBS -C src/runtime all -# Use a little C program to grab stuff from the C header files and -# smash it into Lisp source code. -$GNUMAKE -C tools-for-build -I../src/runtime grovel-headers -tools-for-build/grovel-headers > output/stuff-groveled-from-headers.lisp - -$GNUMAKE -C src/runtime after-grovel-headers - if [ -n "$SBCL_HOST_LOCATION" ]; then echo //copying target-1 output files to host - rsync -a src/runtime/sbcl.nm "$SBCL_HOST_LOCATION/src/runtime/" rsync -a output/stuff-groveled-from-headers.lisp "$SBCL_HOST_LOCATION/output" fi diff --git a/make-target-2-load.lisp b/make-target-2-load.lisp index a6dd710032..41c4441435 100644 --- a/make-target-2-load.lisp +++ b/make-target-2-load.lisp @@ -9,42 +9,67 @@ ;;; Remove symbols from CL:*FEATURES* that should not be exposed to users. (export 'sb-impl::+internal-features+ 'sb-impl) (let* ((non-target-features - '(;; :SB-AFTER-XC-CORE is essentially an option flag to make-host-2 + ;; + ;; FIXME: I suspect that this list should be changed to its inverse- + ;; features that _SHOULD_ go into SB-IMPL:+INTERNAL-FEATURES+ and + ;; comments about the reasoning behind each, rather than features to + ;; discard and reasons they're not needed. The default assumption should be + ;; to drop any build-time feature that lacks a rationale to preserve it. + ;; + ;; READ-FROM-STRING prevents making references to + ;; all these keywords from the source form itself. + (read-from-string " + (;; :SB-AFTER-XC-CORE is essentially an option flag to make-host-2 :SB-AFTER-XC-CORE ;; CONS-PROFILING sets the initial compiler policy which persists ;; into the default baseline policy. It has no relevance post-build ;; in as much as policy can be changed later arbitrarily. :CONS-PROFILING + ;; Used by nothing after compiling 'target-thread.lisp' or 'thread.c' + :SB-FUTEX :OS-THREAD-STACK + ;; These affect the BREAK instruction emitter, but the C code is able + ;; to handle anything, and post-build we don't care which it is. + :UD2-BREAKPOINTS :INT4-BREAKPOINTS ;; Uses of OS-PROVIDES-DLOPEN and -DLADDR are confined to src/code/foreign.lisp :OS-PROVIDES-DLOPEN :OS-PROVIDES-DLADDR ;; more-or-less confined to serve-event, except for a test which now ;; detects whether COMPUTE-POLLFDS is defined and therefore testable. :OS-PROVIDES-POLL - ;; The final batch of symbols is strictly for C. The prefix of - ;; "LISP_FEATURE_" on the corresponding #define is unfortunate. - :GCC-TLS - :RESTORE-FS-SEGMENT-REGISTER-FROM-TLS ; only for 'src/runtime/thread.h' - :OS-PROVIDES-BLKSIZE-T ; only for 'src/runtime/wrap.h' - :OS-PROVIDES-PUTWC)) ; only for 'src/runtime/backtrace.c' + ;; Silly feature we add in because additive features are more sensible + ;; than subtractive ones. So you opt out, not in, to having *LOAD-TRUENAME* + ;; eagerly bound. + :ANSI-COMPLIANT-LOAD-TRUENAME + ;; Used by genesis and C. Genesis uses presence of this feature to + ;; determine if a C file should be written to contain the linkage + ;; info. + :SB-PRELINK-LINKAGE-TABLE + ;; The final batch of symbols is strictly for C. The LISP_FEATURE_ + ;; prefix on the corresponding #define is unfortunate. + :GCC-TLS :USE-SYS-MMAP + ;; only for 'src/runtime/wrap.h' + :OS-PROVIDES-BLKSIZE-T + ;; only for src/runtime/run-program.c + :OS-PROVIDES-CLOSE-RANGE-WRAPPER)")) (public-features (cons sb-impl::!sbcl-architecture - '(:COMMON-LISP :SBCL :ANSI-CL :IEEE-FLOATING-POINT + (read-from-string " + (:COMMON-LISP :SBCL :ANSI-CL :IEEE-FLOATING-POINT :64-BIT ; choice of word size. 32-bit if absent :BIG-ENDIAN :LITTLE-ENDIAN ; endianness: pick one and only one :BSD :UNIX :LINUX :WIN32 :DARWIN :SUNOS :ANDROID ; OS: pick one or more - :FREEBSD :GNU-KFREEBSD :OPENBSD :NETBSD :DRAGONFLY :HAIKU :HPUX + :FREEBSD :GNU-KFREEBSD :OPENBSD :NETBSD :DRAGONFLY :HAIKU :MACH-O :ELF ; obj file format: pick zero or one ;; I would argue that this should not be exposed, - ;; but I would also anticipate blowblack from removing it. + ;; but I would also anticipate blowback from removing it. :CHENEYGC :GENCGC ; GC: pick one and only one ;; Can't use s-l-a-d :compression safely without it :SB-CORE-COMPRESSION ;; Features that are also in *FEATURES-POTENTIALLY-AFFECTING-FASL-FORMAT* ;; and would probably mess up something if made non-public, ;; though I don't think they should all be public. - :MSAN - :SB-SAFEPOINT :SB-SAFEPOINT-STRICTLY + :MSAN :UBSAN + :SB-SAFEPOINT :SB-THREAD :SB-UNICODE ;; Things which (I think) at least one person has requested be kept around :SB-LDB @@ -56,7 +81,8 @@ :PACKAGE-LOCAL-NICKNAMES ;; Developer mode features. A release build will never have them, ;; hence it makes no difference whether they're public or not. - :SB-FLUID :SB-DEVEL))) + :METASPACE + :SB-DEVEL :SB-DEVEL-LOCK-PACKAGES)"))) (removable-features (append non-target-features public-features))) (defconstant sb-impl:+internal-features+ @@ -114,13 +140,19 @@ (memq symbol '(sb-c::sb-pcl sb-c::sb-impl sb-c::sb-kernel sb-c::sb-c sb-c::sb-int)))))) + ;; Delete bootstrap-only vops + (flet ((drop-keys (table) + (loop for symbol being each hash-key of table + when (uninternable-p symbol) do (remhash symbol table)))) + (drop-keys sb-c::*backend-parsed-vops*) + (drop-keys sb-c::*backend-template-names*)) ;; A structure constructor name, in particular !MAKE-SAETP, ;; can't be uninterned if referenced by a defstruct-description. ;; So loop over all structure classoids and clobber any ;; symbol that should be uninternable. - (maphash (lambda (classoid layout) + (maphash (lambda (classoid wrapper) (when (structure-classoid-p classoid) - (let ((dd (layout-info layout))) + (let ((dd (wrapper-%info wrapper))) (setf (dd-constructors dd) (delete-if (lambda (x) (and (consp x) (uninternable-p (car x)))) @@ -161,7 +193,7 @@ result) ;;; Check for potentially bad format-control strings -(defun !scan-format-control-strings () +(defun scan-format-control-strings () (labels ((possibly-ungood-package-reference (string) ;; We want to see nothing SB-package-like at all (or (search "sb-" string :test #'char-equal) @@ -196,22 +228,10 @@ Please check that all strings which were not recognizable to the compiler (as the first argument to WARN, etc.) are wrapped in SB-FORMAT:TOKENS")) wps))) -(progn - ;; See the giant comment at the bottom of this file - ;; concerning the need for this GC. - (gc :full t) - (!scan-format-control-strings)) - -;;; Either set some more package docstrings, or remove any and all docstrings -;;; that snuck in (as can happen with any file compiled in warm load) -;;; depending on presence of the :sb-doc internal feature. -(if (member :sb-doc sb-impl:+internal-features+) - (setf (documentation (find-package "COMMON-LISP") t) - "public: home of symbols defined by the ANSI language specification" - (documentation (find-package "COMMON-LISP-USER") t) - "public: the default package for user code and data" - (documentation (find-package "KEYWORD") t) - "public: home of keywords") +;;; If the SB-DOC internal feature is not present, remove any and all +;;; docstrings that snuck in (as can happen with any file compiled in +;;; warm load). +(unless (member :sb-doc sb-impl:+internal-features+) (let ((count 0)) (macrolet ((clear-it (place) `(when ,place @@ -239,7 +259,10 @@ Please check that all strings which were not recognizable to the compiler :all) ;; 2. Variables, types, and anything else (do-all-symbols (s) - (dolist (category '(:variable :type :typed-structure :setf)) + (let ((expander (sb-int:info :setf :expander s))) + (when (typep expander '(cons t (cons string))) + (setf (second expander) nil))) + (dolist (category '(:variable :type :typed-structure)) (clear-it (sb-int:info category :documentation s))) (clear-it (sb-int:info :random-documentation :stuff s)))) (when (plusp count) @@ -297,7 +320,7 @@ Please check that all strings which were not recognizable to the compiler ;; Unintern no-longer-needed stuff before the possible PURIFY in ;; SAVE-LISP-AND-DIE. - #-(or sb-fluid sb-devel) (!unintern-init-only-stuff) + #-sb-devel (!unintern-init-only-stuff) ;; Mark interned immobile symbols so that COMPILE-FILE knows ;; which symbols will always be physically in immobile space. @@ -308,18 +331,19 @@ Please check that all strings which were not recognizable to the compiler ;; Except that symbols which existed at SBCL build time must be. (do-all-symbols (symbol) (when (sb-kernel:immobile-space-obj-p symbol) - (sb-kernel:set-header-data - symbol (logior (sb-kernel:get-header-data symbol) - (ash 1 sb-vm::+initial-core-symbol-bit+))))) + (sb-kernel:logior-header-bits + symbol (ash 1 sb-vm::+initial-core-symbol-bit+)))) ;; A symbol whose INFO slot underwent any kind of manipulation ;; such that it now has neither properties nor globaldb info, ;; can have the slot set back to NIL if it wasn't already. (do-all-symbols (symbol) - (when (and (sb-kernel:symbol-info symbol) - (null (sb-kernel:symbol-info-vector symbol)) + (when (and (sb-kernel:symbol-%info symbol) ; "raw" value is something + ;; but both "cooked" values are empty + (null (sb-kernel:symbol-dbinfo symbol)) (null (symbol-plist symbol))) - (setf (sb-kernel:symbol-info symbol) nil))) + (sb-sys:%primitive sb-vm::set-slot symbol nil + 'make-symbol sb-vm:symbol-info-slot sb-vm:other-pointer-lowtag))) ) (sb-ext:gc :full t) @@ -357,14 +381,35 @@ Please check that all strings which were not recognizable to the compiler (sb-c::repack-xref :verbose 1)) (fmakunbound 'sb-c::repack-xref) -(progn - (load (merge-pathnames "src/code/shaketree" *load-pathname*)) +(load (merge-pathnames "src/code/shaketree" *load-pathname*)) +(defun asm-inst-p (symbol) + ;; Assembler instruction names can't be made external because to do so would + ;; conflict with common-lisp symbols. Notable examples are PUSH and POP. + ;; So other criteria must pertain to detecting the important symbols. + ;; And as we don't need to preserve Lisp macros but do need to retain + ;; assembler macro instructions, those merit special consideration. + ;; Additionally, a DEFUN may co-exist with an identically named macro + ;; instruction. (I'm not happy about it, but that's historical baggage). + ;; A macro instruction is recognizable to INST by a naming convention + ;; that is unused for anything else by way of being inconvenient to use - + ;; a symbol whose print name start with "M:" is a macro instruction. + (or (get symbol 'sb-disassem::instructions) + (let ((name (string symbol))) + (and (> (length name) 2) + (string= name "M:" :end1 2))))) +(let ((counts + (mapcar (lambda (x) + (list x + (sb-impl::package-external-symbol-count x) + (sb-impl::package-internal-symbol-count x))) + (sort (list-all-packages) #'string< :key 'package-name)))) (sb-impl::shake-packages ;; Development mode: retain all symbols with any system-related properties #+sb-devel (lambda (symbol accessibility) (declare (ignore accessibility)) - (or (sb-kernel:symbol-info symbol) + (or (sb-kernel:symbol-%info symbol) + (sb-kernel:%symbol-function symbol) (and (boundp symbol) (not (keywordp symbol))))) ;; Release mode: retain all symbols satisfying this intricate test #-sb-devel @@ -375,25 +420,45 @@ Please check that all strings which were not recognizable to the compiler ;; overapproximate what we need for contribs and tests (member symbol '(sb-vm::map-referencing-objects sb-vm::map-stack-references - sb-vm::thread-profile-data-slot - sb-vm::thread-alloc-region-slot - sb-vm::primitive-object-size + sb-vm::reconstitute-object ;; need this for defining a vop which ;; tests the x86-64 allocation profiler sb-vm::pseudo-atomic ;; Naughty outside-world code uses these. - #+x86-64 sb-vm::reg-in-size - sb-vm::thread-control-stack-start-slot)) + #+x86-64 sb-vm::reg-in-size)) + (let ((s (string symbol))) (and (search "THREAD-" s) (search "-SLOT" s))) (search "-OFFSET" (string symbol)) (search "-TN" (string symbol)))) + (#.(find-package "SB-ALIEN") + (or (eq accessibility :external) (eq symbol 'sb-alien::alien-callback-p))) ((#.(find-package "SB-C") #.(find-package "SB-ASSEM") #.(find-package "SB-DISASSEM") #.(find-package "SB-IMPL") + #.(find-package "SB-FORMAT") + #.(find-package "SB-UNIX") + #.(find-package "SB-PCL") + #.(find-package "SB-MOP") #.(find-package "SB-PRETTY") + #.(find-package "SB-REGALLOC") + #.(find-package "SB-SYS") + #.(find-package "SB-UNICODE") + #.(find-package "SB-BROTHERTREE") #.(find-package "SB-KERNEL")) ;; Assume all and only external symbols must be retained (eq accessibility :external)) + (#.(find-package "SB-LOOP") + (or (eq accessibility :external) + ;; Retain some internals to keep CLSQL working. + (member symbol '(sb-loop::*loop-epilogue* + sb-loop::add-loop-path)))) + (#.(find-package "SB-THREAD") + (or (eq accessibility :external) + ;; for some reason a recent change caused the tree-shaker to drop MAKE-SPINLOCK + ;; which makes sense. I'm not sure what was rooting the symbol. + ;; However the :spinlock-api test in threads.impure asserts that spinlock symbols + ;; exist despite being internal symbols. + (sb-int:info :function :deprecated symbol))) (#.(find-package "SB-FASL") ;; Retain +BACKEND-FASL-FILE-IMPLEMENTATION+ and +FASL-FILE-VERSION+ ;; (and anything else otherwise reachable) @@ -405,17 +470,37 @@ Please check that all strings which were not recognizable to the compiler (member symbol '(sb-bignum:%allocate-bignum sb-bignum:make-small-bignum))) (t - ;; By default, retain any symbol with any attachments - (or (sb-kernel:symbol-info symbol) - (and (boundp symbol) (not (keywordp symbol))))))) + (if (eq (symbol-package symbol) + sb-assem::*backend-instruction-set-package*) + (or (eq accessibility :external) (asm-inst-p symbol)) + ;; By default, retain any symbol with any attachments + (or (sb-kernel:symbol-%info symbol) + (sb-kernel:%symbol-function symbol) + (and (boundp symbol) (not (keywordp symbol)))))))) :verbose nil :print nil) - (unintern 'sb-impl::shake-packages 'sb-impl)) + (unintern 'sb-impl::shake-packages 'sb-impl) + (let ((sum-delta-ext 0) + (sum-delta-int 0)) + (format t "~&~26TExternal | Internal~%") + (dolist (entry counts) + (let* ((ext (sb-impl::package-external-symbol-count (car entry))) + (int (sb-impl::package-internal-symbol-count (car entry))) + (delta-ext (- ext (cadr entry))) + (delta-int (- int (caddr entry)))) + (incf sum-delta-ext delta-ext) + (incf sum-delta-int delta-int) + (format t "~20a | ~5d (~5@d) | ~5d (~5@d)~%" + (package-name (car entry)) + ext delta-ext int delta-int))) + (format t "~28t (~5@d) | (~5@d) = (~d)~%" + sum-delta-ext sum-delta-int + (+ sum-delta-ext sum-delta-int)))) -;;; Use historical (stupid) behavior for storing pathname namestrings -;;; in fasls. -(setq sb-c::*name-context-file-path-selector* 'truename) +(scan-format-control-strings) ;;; Lock internal packages +#-(and sb-devel + (not sb-devel-lock-packages)) (dolist (p (list-all-packages)) (unless (member p (mapcar #'find-package '("KEYWORD" "CL-USER"))) (sb-ext:lock-package p))) diff --git a/make-target-2.sh b/make-target-2.sh index f9d63ebf1f..b37d85d0ed 100755 --- a/make-target-2.sh +++ b/make-target-2.sh @@ -57,13 +57,19 @@ if [ "$warm_compile" = yes ]; then --eval '(sb-fasl::!warm-load "src/cold/warm.lisp")' --quit fi echo //doing warm init - load and dump phase -./src/runtime/sbcl --core output/cold-sbcl.core \ - --lose-on-corruption $SBCL_MAKE_TARGET_2_OPTIONS --no-sysinit --no-userinit \ - --eval "(progn ${devel})" \ - --eval '(sb-fasl::!warm-load "make-target-2-load.lisp")' \ - --eval '(setf (extern-alien "gc_coalesce_string_literals" char) 2)' \ - --eval '(let ((sb-ext:*invoke-debugger-hook* (prog1 sb-ext:*invoke-debugger-hook* (sb-ext:enable-debugger)))) - (sb-ext:save-lisp-and-die "output/sbcl.core"))' +./src/runtime/sbcl --noinform --core output/cold-sbcl.core \ + --lose-on-corruption $SBCL_MAKE_TARGET_2_OPTIONS \ + --no-sysinit --no-userinit --noprint <<EOF +(progn ${devel}) +(sb-fasl::!warm-load "make-target-2-load.lisp") +(setf (extern-alien "gc_coalesce_string_literals" char) 2) +;;; Use the historical (bad) convention for *compile-file-pathname* +(setf sb-c::*merge-pathnames* t) +;;; and for storing pathname namestrings in fasls too. +(setq sb-c::*name-context-file-path-selector* 'truename) +(let ((sb-ext:*invoke-debugger-hook* (prog1 sb-ext:*invoke-debugger-hook* (sb-ext:enable-debugger)))) + (sb-ext:save-lisp-and-die "output/sbcl.core")) +EOF # Confirm that default evaluation strategy is :INTERPRET if sb-fasteval was built src/runtime/sbcl --core output/sbcl.core --lose-on-corruption --noinform \ diff --git a/make-target-contrib.sh b/make-target-contrib.sh index 217b5b2e00..4057e34a8b 100755 --- a/make-target-contrib.sh +++ b/make-target-contrib.sh @@ -35,16 +35,17 @@ export CC LANG LC_ALL # Load our build configuration . output/build-config -. ./sbcl-pwd.sh -sbcl_pwd +## All programs spawned by make-target-contrib.sh that use this +## variable or anything derived from it are started with CWD +## contrib/<contrib_name>/. Keeping this a relative pathname to the +## toplevel source directory makes the shell and make portions of the +## build system robust against funny stuff in PWD. +SBCL_TOP="../../" -SBCL_HOME="$SBCL_PWD/obj/sbcl-home" -export SBCL_HOME SBCL_PWD -if [ "$OSTYPE" = "cygwin" ] ; then - SBCL_PWD=`echo $SBCL_PWD | sed s/\ /\\\\\\\\\ /g` -fi +SBCL_HOME="$SBCL_TOP/obj/sbcl-home" +export SBCL_HOME SBCL_TOP -SBCL="$SBCL_PWD/src/runtime/sbcl --noinform --core $SBCL_PWD/output/sbcl.core \ +SBCL="$SBCL_TOP/src/runtime/sbcl --noinform --core $SBCL_TOP/output/sbcl.core \ --lose-on-corruption --disable-debugger --no-sysinit --no-userinit" SBCL_BUILDING_CONTRIB=1 export SBCL SBCL_BUILDING_CONTRIB @@ -72,13 +73,13 @@ fi # Otherwise report expected failures: HEADER_HAS_BEEN_PRINTED=false -for dir in `cd obj/asdf-cache/ ; echo *`; do - f="obj/asdf-cache/$dir/test-passed.test-report" +for dir in `cd ./obj/asdf-cache/ ; echo *`; do + f="obj/asdf-cache/$dir/build-passed.test-report" if test -f "$f" && grep -i fail "$f" >/dev/null; then if ! $HEADER_HAS_BEEN_PRINTED; then cat <<EOF -Note: Test suite failures which are expected for this combination of +Note: Build failures which are expected for this combination of platform and features have been ignored: EOF HEADER_HAS_BEEN_PRINTED=true @@ -89,24 +90,37 @@ EOF done if [ -z "$*" ]; then - contribs_to_build="`cd contrib ; echo *`" + contrib_candidates="`cd ./contrib ; echo *`" else - contribs_to_build="$*" + contrib_candidates=="$*" fi +# Filter out candidates that are not actually contribs and skip those that +# have been blocked explicitly with a --without-CONTRIB argument to +# make.sh. +contrib_dirs="" +for candidate in $contrib_candidates +do + if [ -d "contrib/$candidate" -a -f "contrib/$candidate/Makefile" ]; then + case $SBCL_CONTRIB_BLOCKLIST in + *"$candidate"*) ;; + *) contrib_dirs="$contrib_dirs $candidate" ;; + esac + fi +done + # Sometimes people used to see the "No tests failed." output from the last # DEFTEST in contrib self-tests and think that's all that is. So... HEADER_HAS_BEEN_PRINTED=false -for dir in $contribs_to_build +for dir in $contrib_dirs do - if [ -d "contrib/$dir" -a -f "contrib/$dir/Makefile" -a ! -f "obj/asdf-cache/$dir/test-passed.test-report" ]; then + if [ ! -f "obj/asdf-cache/$dir/build-passed.test-report" ]; then if $HEADER_HAS_BEEN_PRINTED; then echo > /dev/null else cat <<EOF -WARNING! Some of the contrib modules did not build successfully or pass -their self-tests. Failed contribs:" +WARNING! Some of the contrib modules did not build successfully. Failed contribs:" EOF HEADER_HAS_BEEN_PRINTED=true fi @@ -114,6 +128,6 @@ EOF fi done -if [ $HEADER_HAS_BEEN_PRINTED = true ]; then +if [ $HEADER_HAS_BEEN_PRINTED = true ] && [ "$IGNORE_CONTRIB_FAILURES" != "yes" ]; then exit 1 fi diff --git a/make-windows-installer.sh b/make-windows-installer.sh index cb46332366..b64b95a21d 100644 --- a/make-windows-installer.sh +++ b/make-windows-installer.sh @@ -11,12 +11,10 @@ WIX_PATH=$WIX/bin -. ./sbcl-pwd.sh -sbcl_pwd +SBCL_TOP=../ +cd ./output -cd output - -"$SBCL_PWD/src/runtime/sbcl" --noinform --core "$SBCL_PWD/output/sbcl.core" \ +"$SBCL_TOP/src/runtime/sbcl" --noinform --core "$SBCL_TOP/output/sbcl.core" \ --disable-debugger --no-sysinit --no-userinit \ --load ../tools-for-build/rtf.lisp \ --load ../tools-for-build/wxs.lisp \ diff --git a/make.sh b/make.sh index e5ac32d7fa..0d73cc3793 100755 --- a/make.sh +++ b/make.sh @@ -77,8 +77,8 @@ maybetime() { fi } maybetime sh make-host-1.sh -maybetime sh make-target-1.sh maybetime sh make-host-2.sh +maybetime sh make-target-1.sh maybetime sh make-target-2.sh maybetime sh make-target-contrib.sh @@ -87,17 +87,17 @@ maybetime sh make-target-contrib.sh # "find contrib/{sb-*,asdf}/Makefile" could work, # but as long as we only have 1 directory level, 'ls' should be adequate. NCONTRIBS=`ls -1 contrib/*/Makefile | wc -l` -NPASSED=`find obj/asdf-cache -name test-passed.test-report -print | wc -l` +NPASSED=`find obj/asdf-cache -name build-passed.test-report -print | wc -l` echo echo "The build seems to have finished successfully, including $NPASSED (out of $NCONTRIBS)" echo "contributed modules. If you would like to run more extensive tests on" echo "the new SBCL, you can try:" echo -echo " cd tests && sh ./run-tests.sh" +echo " cd ./tests && sh ./run-tests.sh" echo echo "To build documentation:" echo -echo " cd doc/manual && make" +echo " cd ./doc/manual && make" echo echo "To install SBCL (more information in INSTALL):" echo diff --git a/package-data-list.lisp-expr b/package-data-list.lisp-expr deleted file mode 100644 index 4342f1ada4..0000000000 --- a/package-data-list.lisp-expr +++ /dev/null @@ -1,3632 +0,0 @@ -;;;; -*- Lisp -*- - -;;;; the specifications of target packages, except for a few things -;;;; which are handled elsewhere by other mechanisms: -;;;; * some SHADOWing and nickname hackery; -;;;; * the standard, non-SBCL-specific packages COMMON-LISP, -;;;; COMMON-LISP-USER, and KEYWORD. -;;;; - -;;;; This software is part of the SBCL system. See the README file for -;;;; more information. -;;;; -;;;; This software is derived from the CMU CL system, which was -;;;; written at Carnegie Mellon University and released into the -;;;; public domain. The software is in the public domain and is -;;;; provided with absolutely no warranty. See the COPYING and CREDITS -;;;; files for more information. - -;;;; KLUDGE: To make it easier for emacs to autoindent this file nicely -;;;; (which prevents spurious conflicts in CVS) each longish list should -;;;; have only one string on the first line. Silly, but there you go. - -;;;; NOTE: -;;;; All uses of #+ and #- reader macros within this file refer to -;;;; the chosen target features, and not CL:*FEATURES*, but -;;;; it is generally not necessary to use reader conditionals -;;;; within this file. If A-NICE-FUNCTION is external in SB-KERNEL -;;;; but not defined for a particular backend, it will not get -;;;; interned during cold load, and hence will not exist in the target. -;;;; This is exactly as desired - it is not necessary for the writer -;;;; of architecture-specific code to clutter up the list of package -;;;; definitions to avoid exporting some stuff. You just export what you -;;;; need, and genesis will do the right thing. Most of the pre-existing -;;;; conditionals are historical baggage, and should be removed. -;;;; EXCEPTION: packages whose symbols are created mainly during -;;;; warm load might have a reason to use reader conditionals. -;;;; For those packages, all symbols listed here are interned during -;;;; genesis, since otherwise the symbols would all disappear, -;;;; and then warm load would intern them as internals, not externals. -;;;; This list of exceptional packages can be found in the -;;;; definition of the FINISH-SYMBOLS function. - -(#s(sb-cold:package-data - :name "SB-ALIEN" - :doc "public: the ALIEN foreign function interface (If you're -porting CMU CL code, note that this package corresponds roughly to a union -of the packages ALIEN and C-CALL at the time of the SBCL fork. SB-C-CALL -is a deprecated nickname to help ease the transition from older versions -of SBCL which maintained the CMU-CL-style split into two packages.)" - :use ("CL" "SB-EXT" "SB-INT" "SB-SYS" "SB-ALIEN-INTERNALS") - :reexport ("ARRAY" - "BOOLEAN" "CHAR" "DOUBLE-FLOAT" - "FLOAT" "FUNCTION" "INTEGER" "LONG-FLOAT" - "SINGLE-FLOAT" - ;; FIXME: Do we really want to reexport - ;; SYSTEM-AREA-POINTER here? Why? - "SYSTEM-AREA-POINTER" - "UNION" "VALUES" "*") - :export ("ADDR" - "ALIEN" - "ALIEN-FUNCALL" "ALIEN-SAP" "ALIEN-SIZE" - "CAST" "C-STRING" - "DEFINE-ALIEN-ROUTINE" "DEFINE-ALIEN-TYPE" "DEFINE-ALIEN-VARIABLE" - "DEREF" "DOUBLE" - "ENUM" "EXTERN-ALIEN" - "FREE-ALIEN" - "GET-ERRNO" - "INT" - "LOAD-1-FOREIGN" "LOAD-FOREIGN" "LOAD-SHARED-OBJECT" "LONG" "LONG-LONG" - "MAKE-ALIEN" - "MAKE-ALIEN-STRING" - "NULL-ALIEN" - "OFF-T" - "SAP-ALIEN" "SHORT" "SIGNED" - "SIZE-T" "SSIZE-T" - "SLOT" "STRUCT" - "UNDEFINED-ALIEN-ERROR" - "UNLOAD-SHARED-OBJECT" - "UNSIGNED" - "UNSIGNED-CHAR" "UNSIGNED-INT" "UNSIGNED-LONG" "UNSIGNED-LONG-LONG" "UNSIGNED-SHORT" - "UTF8-STRING" - "VOID" - "WITH-ALIEN")) - - #s(sb-cold:package-data - :name "SB-ALIEN-INTERNALS" - :doc "private: stuff for implementing ALIENs and friends" - :use ("CL") - :export ("%ALIEN-VALUE" - "%CAST" - "%DEREF-ADDR" "%HEAP-ALIEN" "%HEAP-ALIEN-ADDR" - "%LOCAL-ALIEN-ADDR" "%LOCAL-ALIEN-FORCED-TO-MEMORY-P" "%SAP-ALIEN" - "%SET-DEREF" "%SET-HEAP-ALIEN" "%SET-LOCAL-ALIEN" "%SET-SLOT" - "%SLOT-ADDR" "*SAVED-FP*" "*VALUES-TYPE-OKAY*" - "ALIEN-ARRAY-TYPE" - "ALIEN-ARRAY-TYPE-DIMENSIONS" "ALIEN-ARRAY-TYPE-ELEMENT-TYPE" - "ALIEN-ARRAY-TYPE-P" "ALIEN-BOOLEAN-TYPE" "ALIEN-BOOLEAN-TYPE-P" - "ALIEN-CALLBACK" - "ALIEN-CALLBACK-ACCESSOR-FORM" - "ALIEN-CALLBACK-ASSEMBLER-WRAPPER" - "ALIEN-DOUBLE-FLOAT-TYPE" "ALIEN-DOUBLE-FLOAT-TYPE-P" - "ALIEN-ENUM-TYPE" "ALIEN-ENUM-TYPE-P" "ALIEN-FLOAT-TYPE" - "ALIEN-FLOAT-TYPE-P" "ALIEN-FUN-TYPE" - "ALIEN-FUN-TYPE-ARG-TYPES" "ALIEN-FUN-TYPE-P" - "ALIEN-FUN-TYPE-RESULT-TYPE" "ALIEN-INTEGER-TYPE" - "ALIEN-INTEGER-TYPE-P" "ALIEN-INTEGER-TYPE-SIGNED" - "ALIEN-LONG-FLOAT-TYPE" "ALIEN-LONG-FLOAT-TYPE-P" - "ALIEN-POINTER-TYPE" "ALIEN-POINTER-TYPE-P" - "ALIEN-POINTER-TYPE-TO" "ALIEN-RECORD-FIELD" - "ALIEN-RECORD-FIELD-NAME" "ALIEN-RECORD-FIELD-OFFSET" - "ALIEN-RECORD-FIELD-P" "ALIEN-RECORD-FIELD-TYPE" - "ALIEN-RECORD-TYPE" "ALIEN-RECORD-TYPE-FIELDS" - "ALIEN-RECORD-TYPE-P" "ALIEN-SINGLE-FLOAT-TYPE" - "ALIEN-SINGLE-FLOAT-TYPE-P" "ALIEN-SUBTYPE-P" "ALIEN-TYPE" - "ALIEN-TYPE-=" "ALIEN-TYPE-ALIGNMENT" "ALIEN-TYPE-BITS" - "ALIEN-TYPE-P" "ALIEN-TYPEP" - "ALIEN-VALUE" - "ALIEN-VALUE-TYPE" - "ALIEN-VALUE-TYPEP" - "ALIEN-VALUE-SAP" "ALIEN-VALUE-P" - "ALIEN-VALUES-TYPE" "ALIEN-VALUES-TYPE-P" - "ALIEN-VALUES-TYPE-VALUES" "ALIGN-OFFSET" "ALIEN-VOID-TYPE-P" - "COMPUTE-ALIEN-REP-TYPE" "COMPUTE-DEPORT-ALLOC-LAMBDA" - "COMPUTE-DEPORT-LAMBDA" "COMPUTE-DEPOSIT-LAMBDA" - "COMPUTE-EXTRACT-LAMBDA" "COMPUTE-LISP-REP-TYPE" - "COMPUTE-NATURALIZE-LAMBDA" "DEFINE-ALIEN-TYPE-CLASS" - "DEFINE-ALIEN-TYPE-METHOD" "DEFINE-ALIEN-TYPE-TRANSLATOR" - "DEPORT" "DEPORT-ALLOC" - "ENTER-ALIEN-CALLBACK" - "HEAP-ALIEN-INFO" "HEAP-ALIEN-INFO-P" "HEAP-ALIEN-INFO-SAP-FORM" - "HEAP-ALIEN-INFO-TYPE" "INVOKE-ALIEN-TYPE-METHOD" - "INVOKE-WITH-SAVED-FP" "LOCAL-ALIEN" - "LOCAL-ALIEN-INFO" "LOCAL-ALIEN-INFO-FORCE-TO-MEMORY-P" - "LOCAL-ALIEN-INFO-P" "LOCAL-ALIEN-INFO-TYPE" - "MAKE-ALIEN-FUN-TYPE" "MAKE-ALIEN-POINTER-TYPE" - "MAYBE-WITH-PINNED-OBJECTS" - "MAKE-LOCAL-ALIEN" "NATURALIZE" - "NOTE-LOCAL-ALIEN-TYPE" - "PARSE-ALIEN-TYPE" "UNPARSE-ALIEN-TYPE")) - - #s(sb-cold:package-data - :name "SB-ASSEM" - :doc "private: the assembler, used by the compiler" - :use ("CL" "SB-EXT" "SB-INT") - :export ("ASSEMBLY-UNIT" - "ASSEMBLY-UNIT-BITS" - "+INST-ALIGNMENT-BYTES+" - - "ASSEM-SCHEDULER-P" - "+ASSEM-MAX-LOCATIONS+" - - "*ASMSTREAM*" "MAKE-ASMSTREAM" - "ASMSTREAM-DATA-SECTION" - "ASMSTREAM-CODE-SECTION" - "ASMSTREAM-ELSEWHERE-SECTION" - "ASMSTREAM-ELSEWHERE-LABEL" - "ASMSTREAM-CONSTANT-TABLE" - "ASMSTREAM-CONSTANT-VECTOR" - "APPEND-SECTIONS" "ASSEMBLE-SECTIONS" - "EMIT" ".ALIGN" ".BYTE" ".LISPWORD" ".SKIP" - ".COVERAGE-MARK" ".COMMENT" - "EMIT-ALIGNMENT" "EMIT-BYTE" "EMIT-BACK-PATCH" - "EMIT-CHOOSER" "DEFINE-BITFIELD-EMITTER" - "DEFINE-INSTRUCTION" "DEFINE-INSTRUCTION-MACRO" - "EMIT-POSTIT" - "ANY-ALIGNMENT-BETWEEN-P" - - "MAKE-SEGMENT" "SEGMENT-ORIGIN" "ASSEMBLE" - "SEGMENT-BUFFER" - "SEGMENT-ENCODER-STATE" - "SEGMENT-HEADER-SKEW" - "INST" "INST*" "LABEL" "LABEL-P" "GEN-LABEL" - "EMIT-LABEL" "LABEL-POSITION" "LABEL-USEDP" - "FINALIZE-SEGMENT" - "SEGMENT-CONTENTS-AS-VECTOR" "WRITE-SEGMENT-CONTENTS" - "READS" "WRITES" "SEGMENT" - "WITHOUT-SCHEDULING" - "VARIABLE-LENGTH" - "SEGMENT-COLLECT-DYNAMIC-STATISTICS" - "SECTION-START" - "STMT-LABELS" "STMT-MNEMONIC" "STMT-OPERANDS" - "STMT-PLIST" - "STMT-PREV" "STMT-NEXT" - "ADD-STMT-LABELS" "DELETE-STMT" - "LABELED-STATEMENT-P" - "DEFPATTERN" - - ;; FIXME: These are in the SB-ASSEM package now, but - ;; (left over from CMU CL) are defined in files which - ;; are IN-PACKAGE SB-C. It would probably be cleaner - ;; to move at least most of them to files which are - ;; IN-PACKAGE SB-ASSEM. - "BRANCH" "FLUSHABLE")) - - #s(sb-cold:package-data - :name "SB-BIGNUM" - :doc "private: bignum implementation" - :use ("CL" "SB-KERNEL" "SB-INT" "SB-EXT") - :export ("%ADD-WITH-CARRY" - "%ALLOCATE-BIGNUM" "%ASHL" "%ASHR" - "%BIGNUM-LENGTH" "%BIGNUM-REF" "%BIGNUM-REF-WITH-OFFSET" - "%BIGNUM-SET" - "%BIGNUM-SET-LENGTH" "%DIGIT-0-OR-PLUSP" - "%DIGIT-LOGICAL-SHIFT-RIGHT" - "%FIXNUM-DIGIT-WITH-CORRECT-SIGN" "%FIXNUM-TO-DIGIT" - "%BIGFLOOR" "%LOGAND" "%LOGIOR" "%LOGNOT" "%LOGXOR" - "%MULTIPLY" "%MULTIPLY-AND-ADD" - "%SUBTRACT-WITH-BORROW" "ADD-BIGNUMS" - "BIGNUM-ASHIFT-LEFT" "BIGNUM-ASHIFT-LEFT-FIXNUM" - "BIGNUM-ASHIFT-RIGHT" - "BIGNUM-COMPARE" - "BIGNUM-ELEMENT-TYPE" "BIGNUM-GCD" "BIGNUM-INDEX" - "BIGNUM-LENGTH" - "BIGNUM-INTEGER-LENGTH" - "BIGNUM-LOGBITP" - "BIGNUM-LOGCOUNT" "BIGNUM-LOGICAL-AND" - "BIGNUM-LOGICAL-IOR" "BIGNUM-LOGICAL-NOT" - "BIGNUM-LOGICAL-XOR" "BIGNUM-PLUS-P" - "BIGNUM-TO-FLOAT" "BIGNUM-TRUNCATE" - "MAKE-SMALL-BIGNUM" - "MULTIPLY-BIGNUM-AND-FIXNUM" "MULTIPLY-BIGNUMS" - "MULTIPLY-FIXNUMS" "NEGATE-BIGNUM" - "%RANDOM-BIGNUM" "SUBTRACT-BIGNUM" "SXHASH-BIGNUM")) - - #s(sb-cold:package-data - :name "SB-C" - :doc "private: implementation of the compiler" - ;; (It seems strange to have the compiler USE SB-ALIEN-INTERNALS, - ;; but the point seems to be to be able to express things like - ;; SB-C:DEFTRANSFORM SB-ALIEN-INTERNALS:MAKE-LOCAL-ALIEN without - ;; having to use a bunch of package prefixes, by putting them - ;; in the SB-C package. Maybe it'd be tidier to define an SB-ALIEN-COMP - ;; package for this? But it seems like a fairly low priority.) - ;; (Probably the same considerations also explain why BIGNUM is - ;;in the USE list.) - :use ("CL" "SB-ALIEN-INTERNALS" "SB-ALIEN" "SB-ASSEM" "SB-BIGNUM" - #+sb-dyncount "SB-DYNCOUNT" "SB-EXT" "SB-FASL" "SB-INT" - "SB-KERNEL" "SB-SYS") - ;; "flushable" is an assembly instruction attribute and a fun-info attribute. - ;; But why do we need SLOT re-exported? - :reexport ("SLOT" "FLUSHABLE") - :export ("%ALIEN-FUNCALL" - "%CATCH-BREAKUP" "%CONTINUE-UNWIND" "%UNWIND" - "%LISTIFY-REST-ARGS" "%MORE-ARG" "%MORE-ARG-VALUES" - "%UNWIND-PROTECT-BREAKUP" - - "*BACKEND-BYTE-ORDER*" "*BACKEND-DISASSEM-PARAMS*" - "+BACKEND-INTERNAL-ERRORS+" "+BACKEND-PAGE-BYTES+" - "*BACKEND-REGISTER-SAVE-PENALTY*" - "*BACKEND-SBS*" ; storage bases - "*BACKEND-SC-NAMES*" "*BACKEND-SC-NUMBERS*" - "*BACKEND-SUBFEATURES*" - "*BACKEND-T-PRIMITIVE-TYPE*" - - "*COMPILATION*" - "*COMPILE-TO-MEMORY-SPACE*" - "*ELSEWHERE*" - "*LEXENV*" - "*SUPPRESS-VALUES-DECLARATION*" - - #+x86 "SET-FPU-WORD-FOR-C" - #+x86 "SET-FPU-WORD-FOR-LISP" - "ALIGN-STACK-POINTER" - "ALIEN-FUNCALL-SAVES-FP-AND-PC" - "ALLOC-ALIEN-STACK-SPACE" "ALLOC-NUMBER-STACK-SPACE" - "ALLOCATE-CODE-OBJECT" "ALLOCATE-FRAME" - "ALLOCATE-FULL-CALL-FRAME" - "ALWAYS-TRANSLATABLE" - "ANCESTOR-FRAME-REF" "ANCESTOR-FRAME-SET" - "ANY" "ARG-COUNT-ERROR" "ASSEMBLE-FILE" - "ATTRIBUTES" "ATTRIBUTES-INTERSECTION" "ATTRIBUTES-UNION" - "ATTRIBUTES=" - "CALL" "CALL-LOCAL" "CALL-NAMED" "CALL-VARIABLE" - "CALL-OUT" "CALL-OUT-NAMED" - "CALLEE-NFP-TN" "CALLEE-RETURN-PC-TN" - "CASE-BODY" "CATCH-BLOCK" "UNWIND-BLOCK" - "CLOSURE-INIT" "CLOSURE-REF" "CLOSURE-INIT-FROM-FP" - "COMPARE-AND-SWAP-SLOT" - "COMPILE-IN-LEXENV" - "COMPILED-DEBUG-FUN-FORM-NUMBER" - "%COMPILER-DEFUN" "COMPILER-ERROR" "FATAL-COMPILER-ERROR" - "COMPILER-NOTIFY" - "COMPILER-STYLE-WARN" "COMPILER-WARN" - "COMPONENT" "COMPONENT-HEADER-LENGTH" - "COMPONENT-INFO" "COMPONENT-LIVE-TN" "COMPUTE-FUN" - "COMPUTE-OLD-NFP" "COPY-MORE-ARG" - "CURRENT-BINDING-POINTER" "CURRENT-NFP-TN" - "CURRENT-STACK-POINTER" - "*ALIEN-STACK-POINTER*" - "CURRENT-NSP" "SET-NSP" - "DEALLOC-ALIEN-STACK-SPACE" - "DEALLOC-NUMBER-STACK-SPACE" - "DEBUG-CATCH-TAG" - "DEF-IR1-TRANSLATOR" - "!DEF-PRIMITIVE-TYPE" "!DEF-PRIMITIVE-TYPE-ALIAS" - "DEFINE-SOURCE-TRANSFORM" - "DEFINITION-SOURCE-LOCATION" - "DEFINITION-SOURCE-LOCATION-NAMESTRING" - "DEFINITION-SOURCE-LOCATION-TOPLEVEL-FORM-NUMBER" - "DEFINITION-SOURCE-LOCATION-FORM-NUMBER" - "DEFINITION-SOURCE-LOCATION-PLIST" - "DEFINE-MODULAR-FUN" - "DEFINE-MOVE-FUN" - "DEFINE-MOVE-VOP" "!DEFINE-STORAGE-BASES" - "!DEFINE-STORAGE-CLASS" "DEFINE-VOP" - "DEFKNOWN" "DEFOPTIMIZER" - "DEFTRANSFORM" "DERIVE-TYPE" - "DIS" - "DO-FORMS-FROM-INFO" - "EMIT-BLOCK-HEADER" - "PHYSENV-DEBUG-LIVE-TN" "PHYSENV-LIVE-TN" - "FAST-SYMBOL-VALUE" - "FAST-SYMBOL-GLOBAL-VALUE" - "FIXUP-NOTE-KIND" - "FIXUP-NOTE-FIXUP" - "FIXUP-NOTE-POSITION" - "FOLDABLE" - "FORCE-TN-TO-STACK" - "FUN-INFO-DERIVE-TYPE" "FUN-INFO-IR2-CONVERT" - "FUN-INFO-LTN-ANNOTATE" "FUN-INFO-OPTIMIZER" - "GET-TOPLEVELISH-FILE-INFO" - "HALT" - "IF-EQ" - "CONSTANT-TN-P" - "INHIBIT-SAFEPOINTS" - "COMPILER-MACRO-APPLICATION-MISSED-WARNING" - "INLINING-DEPENDENCY-FAILURE" - "INSERT-STEP-CONDITIONS" - "IR2-COMPONENT-CONSTANTS" "IR2-CONVERT" - "IR2-PHYSENV-NUMBER-STACK-P" - "KNOWN-CALL-LOCAL" "KNOWN-RETURN" - "LAMBDA-VAR-IGNOREP" - "LAMBDA-WITH-LEXENV" "LEXENV-FIND" - "LOCATION=" "LTN-ANNOTATE" - "MACRO-POLICY-DECLS" - "MAKE-ALIAS-TN" "MAKE-CATCH-BLOCK" - "MAKE-CLOSURE" "MAKE-CONSTANT-TN" - "MAKE-FIXUP-NOTE" - "MAKE-LOAD-TIME-CONSTANT-TN" "MAKE-N-TNS" "MAKE-NORMAL-TN" - "MAKE-RANDOM-TN" - "MAKE-REPRESENTATION-TN" "MAKE-RESTRICTED-TN" - "MAKE-STACK-POINTER-TN" "MAKE-TN-REF" "MAKE-UNWIND-BLOCK" - "MAKE-WIRED-TN" "MAYBE-COMPILER-NOTIFY" - "MAYBE-INLINE-SYNTACTIC-CLOSURE" - "MSAN-UNPOISON" - "MORE-ARG-CONTEXT" "MOVABLE" "MOVE" "MULTIPLE-CALL" - "MULTIPLE-CALL-LOCAL" "MULTIPLE-CALL-NAMED" - "MULTIPLE-CALL-VARIABLE" - "%%NIP-DX" "%%NIP-VALUES" - "NLX-ENTRY" "NLX-ENTRY-MULTIPLE" - "NODE-STACK-ALLOCATE-P" - "NON-DESCRIPTOR-STACK" "NOTE-ENVIRONMENT-START" - "NOTE-THIS-LOCATION" "*LOCATION-CONTEXT*" - "MAKE-RESTART-LOCATION" - "OPTIMIZER" - "PACK-CODE-FIXUP-LOCS" - "PARSE-EVAL-WHEN-SITUATIONS" - "POLICY" - "%%POP-DX" - "PRIMITIVE-TYPE" "PRIMITIVE-TYPE-OF" - "PRIMITIVE-TYPE-OR-LOSE" - "PRIMITIVE-TYPE-NAME" - "PRIMITIVE-TYPE-INDIRECT-CELL-TYPE" - "PROCLAIM-FTYPE" "PROCLAIM-TYPE" - "PUSH-VALUES" - "READ-PACKED-BIT-VECTOR" - "READ-VAR-INTEGER" "READ-VAR-INTEGERF" - "SAP-READ-VAR-INTEGER" "SAP-READ-VAR-INTEGERF" - "READ-VAR-STRING" - "REGISTER-INLINE-CONSTANT" - "RESET-STACK-POINTER" "RESTORE-DYNAMIC-STATE" - "RETURN-MULTIPLE" "SAVE-DYNAMIC-STATE" "STORAGE-BASE" - "SB-ALLOCATED-SIZE" "SB-NAME" "SB-OR-LOSE" - "STORAGE-CLASS" "SC-CASE" "SC-OPERAND-SIZE" - "SC-IS" "SC-NAME" "SC-NUMBER" "SC-SB" - "SC-OR-LOSE" "SC-NUMBER-OR-LOSE" - "SC+OFFSET" "MAKE-SC+OFFSET" "SC+OFFSET-OFFSET" "SC+OFFSET-SCN" - "SET-UNWIND-PROTECT" - "SETUP-CLOSURE-ENVIRONMENT" - "SOURCE-LOCATION" - "SPECIFY-SAVE-TN" - "STATIC-CALL-NAMED" "STATIC-MULTIPLE-CALL-NAMED" "STATIC-TAIL-CALL-NAMED" - "STORE-COVERAGE-DATA" "STORE-SOURCE-FORM" - "TAIL-CALL" "TAIL-CALL-NAMED" - "TAIL-CALL-VARIABLE" "TEMPLATE-OR-LOSE" - "TN" "TN-OFFSET" "TN-P" "TN-REF" "TN-REF-ACROSS" "TN-REF-LOAD-TN" - "TN-REF-NEXT" "TN-REF-NEXT-REF" "TN-REF-P" "TN-REF-TARGET" - "TN-REF-TN" "TN-REF-TYPE" "TN-REF-VOP" "TN-REF-WRITE-P" "TN-SC" - "TN-KIND" "TN-VALUE" - "TYPE-CHECK-ERROR" "UNBIND" "UNBIND-N" "UNBIND-TO-HERE" - "UNSAFE" "UNSAFELY-FLUSHABLE" "UNWIND" "UWP-ENTRY" - "UNPACK-CODE-FIXUP-LOCS" - "VERIFY-ARG-COUNT" "WRITE-PACKED-BIT-VECTOR" - "WRITE-VAR-INTEGER" "WRITE-VAR-STRING" "XEP-ALLOCATE-FRAME" - "XEP-SETUP-SP" - "LABEL-ID" "FIXUP" "FIXUP-FLAVOR" "FIXUP-NAME" "FIXUP-OFFSET" - "FIXUP-P" "MAKE-FIXUP" - "DEF-ALLOC" - "VAR-ALLOC" - "SAFE-FDEFN-FUN" - "NOTE-FIXUP" - "DEF-CASSER" - "DEF-REFFER" - "EMIT-CONSTANT" - "EMIT-NOP" - "DEF-SETTER" - "FIXED-ALLOC" - "MAKE-FUNCALLABLE-INSTANCE-TRAMP" - "RETURN-SINGLE" - "NOTE-NEXT-INSTRUCTION" - "SET-SLOT" "INIT-SLOT" - "LOCATION-NUMBER" - "*COMPONENT-BEING-COMPILED*" - "BLOCK-NUMBER" - "IR2-BLOCK-BLOCK" - "VOP-BLOCK" - "VOP-NEXT" "NEXT-VOP-IS" "REPLACE-VOPS" - - "IMMEDIATE-CONSTANT-SC" - "BOXED-IMMEDIATE-SC-P" - "COMBINATION-IMPLEMENTATION-STYLE" - "CONVERT-CONDITIONAL-MOVE-P" - "LOCATION-PRINT-NAME" - "MAKE-CALL-OUT-TNS" - "STANDARD-ARG-LOCATION" - "STANDARD-ARG-LOCATION-SC" - "ARG-COUNT-SC" - "CLOSURE-SC" - "MAKE-RETURN-PC-PASSING-LOCATION" - "MAKE-OLD-FP-PASSING-LOCATION" - "MAKE-OLD-FP-SAVE-LOCATION" - "RETURN-PC-PASSING-OFFSET" - "OLD-FP-PASSING-OFFSET" - "MAKE-RETURN-PC-SAVE-LOCATION" - "MAKE-ARG-COUNT-LOCATION" - "MAKE-NFP-TN" - "MAKE-NUMBER-STACK-POINTER-TN" - "MAKE-UNKNOWN-VALUES-LOCATIONS" - "SELECT-COMPONENT-FORMAT" - "MAKE-NLX-SP-TN" - "MAKE-DYNAMIC-STATE-TNS" - "MAKE-NLX-ENTRY-ARG-START-LOCATION" - "GENERATE-CALL-SEQUENCE" - "GENERATE-RETURN-SEQUENCE" - "WITH-COMPILER-ERROR-RESIGNALLING" - "WITH-SOURCE-LOCATION" - "XDEFUN" ; extended defun for defstruct - - "BRANCH-IF" "MULTIWAY-BRANCH-IF-EQ" - - ;; for SB-COVER - "*CODE-COVERAGE-INFO*" "CODE-COVERAGE-RECORD-MARKED" - "CLEAR-CODE-COVERAGE" "RESET-CODE-COVERAGE" - "+CODE-COVERAGE-UNMARKED+" - ;; for SB-INTROSPECT - "MAP-PACKED-XREF-DATA" "MAP-SIMPLE-FUNS" - - "DO-BLOCKS" "DO-BLOCKS-BACKWARDS" - "DO-NODES" "DO-NODES-BACKWARDS")) - - #s(sb-cold:package-data - :name "SB-DEBUG" - :doc - "sorta public: Eventually this should become the debugger interface, with -basic stuff like BACKTRACE and ARG. For now, the actual supported interface -is still mixed indiscriminately with low-level internal implementation stuff -like *STACK-TOP-HINT* and unsupported stuff like *TRACED-FUN-LIST*." - :use ("CL" "SB-EXT" "SB-INT" "SB-SYS" "SB-KERNEL" "SB-DI") - :reexport ("*DEBUG-PRINT-VARIABLE-ALIST*") - :export ("*BACKTRACE-FRAME-COUNT*" - "*DEBUG-BEGINNER-HELP-P*" - "*DEBUG-CONDITION*" - "*DEBUG-READTABLE*" "*DEBUG-HELP-STRING*" - "*FLUSH-DEBUG-ERRORS*" "*IN-THE-DEBUGGER*" - "*METHOD-FRAME-STYLE*" - "*TRACE-INDENTATION-STEP*" "*MAX-TRACE-INDENTATION*" - "ARG" - "INTERNAL-DEBUG" "VAR" - "*STACK-TOP-HINT*" - "*TRACE-ENCAPSULATE-DEFAULT*" - "FRAME-HAS-DEBUG-TAG-P" - "UNWIND-TO-FRAME-AND-CALL" - ;; Deprecated - "BACKTRACE" "BACKTRACE-AS-LIST" - ;; Replaced by - "PRINT-BACKTRACE" "LIST-BACKTRACE")) - - #s(sb-cold:package-data - :name "SB-DI" - :doc "private: primitives used to write debuggers" - :use ("CL" "SB-EXT" "SB-INT" "SB-KERNEL" "SB-SYS" "SB-VM") - :import-from (("SB-C" - "DEBUG-SOURCE-NAMESTRING" - "DEBUG-SOURCE-CREATED" - "MAKE-DEBUG-SOURCE" - "DEBUG-SOURCE" "DEBUG-SOURCE-P" - "CORE-DEBUG-SOURCE" "CORE-DEBUG-SOURCE-P" - "CORE-DEBUG-SOURCE-FORM")) - :reexport ("DEBUG-SOURCE-NAMESTRING" - "DEBUG-SOURCE-CREATED" - "DEBUG-SOURCE" "DEBUG-SOURCE-P") - :export ("ACTIVATE-BREAKPOINT" - "AMBIGUOUS-DEBUG-VARS" "AMBIGUOUS-VAR-NAME" "BREAKPOINT" - "BREAKPOINT-ACTIVE-P" "BREAKPOINT-HOOK-FUN" "BREAKPOINT-INFO" - "BREAKPOINT-KIND" "BREAKPOINT-P" "BREAKPOINT-WHAT" "CODE-LOCATION" - "CODE-LOCATION-DEBUG-BLOCK" "CODE-LOCATION-DEBUG-FUN" - "CODE-LOCATION-DEBUG-SOURCE" "CODE-LOCATION-FORM-NUMBER" - "CODE-LOCATION-P" "CODE-LOCATION-TOPLEVEL-FORM-OFFSET" - "CODE-LOCATION-CONTEXT" - "CODE-LOCATION-UNKNOWN-P" "CODE-LOCATION=" "DEACTIVATE-BREAKPOINT" - "DEBUG-BLOCK" "DEBUG-BLOCK-ELSEWHERE-P" "DEBUG-BLOCK-P" - "DEBUG-CONDITION" "DEBUG-ERROR" - "DEBUG-FUN" "DEBUG-FUN-FUN" "DEBUG-FUN-KIND" - "DEBUG-FUN-LAMBDA-LIST" "DEBUG-FUN-NAME" "DEBUG-FUN-CLOSURE-NAME" - "DEBUG-FUN-P" "DEBUG-FUN-START-LOCATION" - "DEBUG-FUN-SYMBOL-VARS" - "DEBUG-VAR" "DEBUG-VAR-ID" "DEBUG-VAR-INFO-AVAILABLE" - "DEBUG-VAR-SYMBOL-NAME" "DEBUG-VAR-P" "DEBUG-VAR-PACKAGE-NAME" - "DEBUG-VAR-SYMBOL" "DEBUG-VAR-VALID-VALUE" - "DEBUG-VAR-VALIDITY" "DEBUG-VAR-VALUE" - "DELETE-BREAKPOINT" - "DO-DEBUG-BLOCK-LOCATIONS" "DO-DEBUG-FUN-BLOCKS" - "DO-DEBUG-FUN-VARS" - "ERROR-CONTEXT" - "FORM-NUMBER-TRANSLATIONS" - "FRAME" "FRAME-CATCHES" "FRAME-CODE-LOCATION" - "FRAME-DEBUG-FUN" "FRAME-DOWN" - "FRAME-FUN-MISMATCH" "FRAME-NUMBER" "FRAME-P" "FRAME-UP" - "GET-TOPLEVEL-FORM" - "REPLACE-FRAME-CATCH-TAG" - "FUN-DEBUG-FUN" "FUN-END-COOKIE-VALID-P" - "INVALID-CONTROL-STACK-POINTER" "INVALID-VALUE" - "LAMBDA-LIST-UNAVAILABLE" "MAKE-BREAKPOINT" "NO-DEBUG-BLOCKS" - "NO-DEBUG-FUN-RETURNS" "PREPROCESS-FOR-EVAL" - "EVAL-IN-FRAME" "RETURN-FROM-FRAME" "SOURCE-PATH-CONTEXT" - "TOP-FRAME" "UNHANDLED-DEBUG-CONDITION" - "UNKNOWN-DEBUG-VAR" - "CODE-LOCATION-KIND" "FLUSH-FRAMES-ABOVE")) - - #s(sb-cold:package-data - :name "SB-DISASSEM" - :doc "private: stuff related to the implementation of the disassembler" - :use ("CL" "SB-EXT" "SB-INT" "SB-SYS" "SB-KERNEL" "SB-DI") - :export ("*DISASSEM-NOTE-COLUMN*" "*DISASSEM-OPCODE-COLUMN-WIDTH*" - "*DISASSEM-LOCATION-COLUMN-WIDTH*" - "ALIGN" ;; prevent it from being removed, older Slime versions are using it - "ARG-VALUE" "DISASSEM-STATE" - "DISASSEMBLE-CODE-COMPONENT" - "DISASSEMBLE-FUN" "DISASSEMBLE-MEMORY" - "DISASSEMBLE-INSTRUCTION" - "DISASSEMBLE-SEGMENT" "DISASSEMBLE-SEGMENTS" - "DSTATE-BYTE-ORDER" - "DSTATE-GETPROP" - "DSTATE-SETPROP" - "DSTATE-SEGMENT-SAP" - "DSTATE-OPERANDS" - "FIND-INST" - "GET-CODE-SEGMENTS" "GET-FUN-SEGMENTS" - "GET-INST-SPACE" "HANDLE-BREAK-ARGS" - "LABEL-SEGMENTS" - "MAYBE-NOTE-ASSEMBLER-ROUTINE" - "MAYBE-NOTE-ASSOCIATED-STORAGE-REF" - "MAYBE-NOTE-NIL-INDEXED-OBJECT" - "MAYBE-NOTE-NIL-INDEXED-SYMBOL-SLOT-REF" - "MAYBE-NOTE-SINGLE-STORAGE-REF" - "MAYBE-NOTE-STATIC-SYMBOL" - "NOTE" - "NOTE-CODE-CONSTANT" - "OPERAND" - "PRIN1-QUOTED-SHORT" - "PRIN1-SHORT" "PRINT-BYTES" - "PRINT-CURRENT-ADDRESS" "PRINT-INST" - "PRINT-NOTES-AND-NEWLINE" - "SAP-REF-INT" - "SEG-CODE" "SEG-LENGTH" "SEGMENT" - "SIGN-EXTEND" - "MAKE-DSTATE" - "DEFINE-ARG-TYPE" - "READ-SIGNED-SUFFIX" - "MAKE-MEMORY-SEGMENT" - "MAKE-SEGMENT" "SEG-VIRTUAL-LOCATION" - "DCHUNK" "DCHUNK-ZERO" "*DEFAULT-DSTATE-HOOKS*" - "MAKE-CODE-SEGMENT" "MAKE-OFFS-HOOK" - "DSTATE-SEGMENT" "DSTATE-CUR-OFFS" - "PRINC16" "INSTRUCTION" "DEFINE-INSTRUCTION-FORMAT" - "DSTATE-NEXT-OFFS" - "SEG-SAP-MAKER" "DISASSEMBLE-ASSEM-SEGMENT" - "READ-SUFFIX" - "MAP-SEGMENT-INSTRUCTIONS" - "SET-LOCATION-PRINTING-RANGE" "MAKE-VECTOR-SEGMENT" - "DSTATE-CUR-ADDR" "DSTATE-NEXT-ADDR" - "SNARF-ERROR-JUNK")) - - #+sb-dyncount - #s(sb-cold:package-data - :name "SB-DYNCOUNT" - :doc "private: some somewhat-stale code for collecting runtime statistics" - :use ("CL" "SB-ALIEN-INTERNALS" "SB-ALIEN" "SB-BIGNUM" - "SB-EXT" "SB-INT" "SB-KERNEL" "SB-ASSEM" "SB-SYS") - :export ("*COLLECT-DYNAMIC-STATISTICS*" - "COUNT-ME" - "DYNCOUNT-INFO-COUNTS" "DYNCOUNT-INFO-COSTS" - "IR2-COMPONENT-DYNCOUNT-INFO" - "DYNCOUNT-INFO" "DYNCOUNT-INFO-P")) - - #s(sb-cold:package-data - :name "SB-FASL" - :doc "private: stuff related to FASL load/dump logic (and GENESIS)" - :use ("CL" "SB-ALIEN" "SB-ASSEM" "SB-BIGNUM" "SB-C" - "SB-EXT" "SB-INT" "SB-KERNEL" "SB-SYS") - :import-from (("SB-VM" "+FIXUP-KINDS+")) - :export ("*ASSEMBLER-ROUTINES*" - "GET-ASM-ROUTINE" - "+BACKEND-FASL-FILE-IMPLEMENTATION+" - "*FASL-FILE-TYPE*" - "CLOSE-FASL-OUTPUT" - "DUMP-ASSEMBLER-ROUTINES" - "DUMP-FOP" "DUMP-OBJECT" - "DUMPABLE-LAYOUT-P" - "FASL-CONSTANT-ALREADY-DUMPED-P" - "+FASL-FILE-VERSION+" - "FASL-DUMP-COMPONENT" - "FASL-DUMP-COLD-FSET" - "FASL-DUMP-LOAD-TIME-VALUE-LAMBDA" - "FASL-DUMP-TOPLEVEL-LAMBDA-CALL" - "FASL-NOTE-HANDLE-FOR-CONSTANT" - "FASL-OUTPUT" "FASL-OUTPUT-P" - "FASL-OUTPUT-ENTRY-TABLE" "FASL-OUTPUT-STREAM" - "FASL-NOTE-DUMPABLE-INSTANCE" - "LOAD-FORM-IS-DEFAULT-MLFSS-P" - "*!LOAD-TIME-VALUES*" - "OPEN-FASL-OUTPUT" - "*!COLD-DEFSYMBOLS*" "*!COLD-DEFUNS*" - "*!COLD-SETF-MACROS*" "*!COLD-TOPLEVELS*" - "COLD-CONS" "COLD-INTERN" "COLD-PUSH" "COLD-TARGET-PUSH")) - - ;; This package is a grab bag for things which used to be internal - ;; symbols in package COMMON-LISP. Lots of these symbols are accessed - ;; with explicit SB-IMPL:: prefixes in the code. It would be nice to - ;; reduce the use of this practice, so if symbols from here which are - ;; accessed that way are found to belong more appropriately in an - ;; existing package (e.g. SB-KERNEL or SB-SYS or SB-EXT or SB-FASL), - ;; I (WHN 19990223) encourage maintainers to move them there.. - #s(sb-cold:package-data - :name "SB-IMPL" - :doc "private: a grab bag of implementation details" - :import-from (("SB-KERNEL" "*PACKAGE-NAMES*")) - :export ("FORMAT-MICROSECONDS" "FORMAT-MILLISECONDS" ; for ~/fmt/ - "PRINT-TYPE" "PRINT-TYPE-SPECIFIER" - ;; protect from tree shaker so we can test this function - "EXPAND-SYMBOL-CASE" - ;; symbols used by sb-simple-streams - "ANSI-STREAM-CLEAR-INPUT" - "ANSI-STREAM-FRESH-LINE" "ANSI-STREAM-LISTEN" - "ANSI-STREAM-READ-BYTE" "ANSI-STREAM-READ-CHAR" - "ANSI-STREAM-READ-CHAR-NO-HANG" "ANSI-STREAM-READ-LINE" - "ANSI-STREAM-READ-SEQUENCE" "ANSI-STREAM-PEEK-CHAR" - "ANSI-STREAM-UNREAD-CHAR" "ANSI-STREAM-WRITE-SEQUENCE" - "ANSI-STREAM-WRITE-STRING" "DISPATCH-TABLES" - "TOKEN-DELIMITERP" "WHITESPACE[2]P" "WITH-READ-BUFFER" - ;; other - "%MAKUNBOUND") - :use ("CL" "SB-ALIEN" "SB-BIGNUM" "SB-DEBUG" "SB-EXT" - "SB-FASL" "SB-GRAY" "SB-INT" "SB-KERNEL" "SB-SYS")) - - #s(sb-cold:package-data - :name "SB-EXT" - :doc "public: miscellaneous supported extensions to the ANSI Lisp spec" - :use ("CL" "SB-ALIEN" "SB-INT" "SB-SYS" "SB-GRAY") - :export ( ;; Information about how the program was invoked is - ;; nonstandard but very useful. - "*POSIX-ARGV*" "*CORE-PATHNAME*" "*RUNTIME-PATHNAME*" - "POSIX-GETENV" "POSIX-ENVIRON" - - ;; Customizing initfile locations - "*USERINIT-PATHNAME-FUNCTION*" - "*SYSINIT-PATHNAME-FUNCTION*" - - "*DEFAULT-EXTERNAL-FORMAT*" - "*DEFAULT-C-STRING-EXTERNAL-FORMAT*" - - ;; Compare and Swap support - "CAS" - "COMPARE-AND-SWAP" - "DEFCAS" - "DEFINE-CAS-EXPANDER" - "GET-CAS-EXPANSION" - - ;; Other atomic operations and types related to them - "ATOMIC-INCF" - "ATOMIC-DECF" - "ATOMIC-UPDATE" - "ATOMIC-PUSH" - "ATOMIC-POP" - "WORD" - "MOST-POSITIVE-WORD" - - ;; Not an atomic operation, but should be used with them - "SPIN-LOOP-HINT" - - ;; Waiting for arbitrary events. - "WAIT-FOR" - - ;; Time related things - "CALL-WITH-TIMING" - "GET-TIME-OF-DAY" - - ;; People have various good reasons to mess with the GC. - "HEAP-ALLOCATED-P" - "STACK-ALLOCATED-P" - "*AFTER-GC-HOOKS*" - "BYTES-CONSED-BETWEEN-GCS" - "GC" "GET-BYTES-CONSED" - "*GC-RUN-TIME*" - "PURIFY" - "DYNAMIC-SPACE-SIZE" - ;; Gencgc only, but symbols exist for manual building - ;; convenience on all platforms. - "GENERATION-AVERAGE-AGE" - "GENERATION-BYTES-ALLOCATED" - "GENERATION-BYTES-CONSED-BETWEEN-GCS" - "GENERATION-MINIMUM-AGE-BEFORE-GC" - "GENERATION-NUMBER-OF-GCS" - "GENERATION-NUMBER-OF-GCS-BEFORE-PROMOTION" - "GC-LOGFILE" - - ;; Stack allocation control - "*STACK-ALLOCATE-DYNAMIC-EXTENT*" - - ;; Customizing printing of compiler and debugger messages - "*COMPILER-PRINT-VARIABLE-ALIST*" - "*DEBUG-PRINT-VARIABLE-ALIST*" - "COMPILE-FILE-LINE" - "COMPILE-FILE-POSITION" - - ;; Hooks into init & save sequences - "*INIT-HOOKS*" "*SAVE-HOOKS*" "*EXIT-HOOKS*" - - ;; Controlling exiting other threads. - "*EXIT-TIMEOUT*" - - ;; There is no one right way to report progress on - ;; hairy compiles. - "*COMPILE-PROGRESS*" - - ;; The default behavior for block compilation. - "*BLOCK-COMPILE-DEFAULT*" - - ;; It can be handy to be able to evaluate expressions involving - ;; the thing under examination by CL:INSPECT. - "*INSPECTED*" - - ;; There is no one right way to do efficiency notes. - "*EFFICIENCY-NOTE-COST-THRESHOLD*" "*EFFICIENCY-NOTE-LIMIT*" - - ;; There's no one right way to report errors. - "*ENCLOSING-SOURCE-CUTOFF*" - "*UNDEFINED-WARNING-LIMIT*" - - ;; and for dedicated users who really want to customize - ;; error reporting, we have - "DEFINE-SOURCE-CONTEXT" - "WITH-CURRENT-SOURCE-FORM" - - ;; and given how many users dislike strict treatment of - ;; DEFCONSTANT, let's give them enough rope to escape by - "DEFCONSTANT-UNEQL" "DEFCONSTANT-UNEQL-NAME" - "DEFCONSTANT-UNEQL-NEW-VALUE" "DEFCONSTANT-UNEQL-OLD-VALUE" - - ;; global lexicals, access to global symbol values - "DEFGLOBAL" - "DEFINE-LOAD-TIME-GLOBAL" - "SYMBOL-GLOBAL-VALUE" - - "FILE-EXISTS" - "FILE-DOES-NOT-EXIST" - "DELETE-FILE-ERROR" - "SUPERSEDE" - "OVERWRITE" - "RENAME" - "CREATE" - "RETRY" - - ;; package extensions - ;; - ;; locks - "PACKAGE-LOCKED-P" - "LOCK-PACKAGE" - "UNLOCK-PACKAGE" - "PACKAGE-IMPLEMENTED-BY-LIST" - "PACKAGE-IMPLEMENTS-LIST" - "ADD-IMPLEMENTATION-PACKAGE" - "REMOVE-IMPLEMENTATION-PACKAGE" - "WITH-UNLOCKED-PACKAGES" - "PACKAGE-LOCK-VIOLATION" - "PACKAGE-LOCKED-ERROR" - "SYMBOL-PACKAGE-LOCKED-ERROR" - "PACKAGE-LOCKED-ERROR-SYMBOL" - "WITHOUT-PACKAGE-LOCKS" - "DISABLE-PACKAGE-LOCKS" - "ENABLE-PACKAGE-LOCKS" - ;; local nicknames - "ADD-PACKAGE-LOCAL-NICKNAME" - "REMOVE-PACKAGE-LOCAL-NICKNAME" - "PACKAGE-LOCAL-NICKNAMES" - "PACKAGE-LOCALLY-NICKNAMED-BY-LIST" - - "PACKAGE-DOES-NOT-EXIST" "READER-PACKAGE-DOES-NOT-EXIST" - ;; behaviour on DEFPACKAGE variance - "*ON-PACKAGE-VARIANCE*" - - ;; Custom conditions & condition accessors for users to handle. - "CODE-DELETION-NOTE" - "COMPILER-NOTE" - "IMPLICIT-GENERIC-FUNCTION-NAME" - "IMPLICIT-GENERIC-FUNCTION-WARNING" - "INVALID-FASL" - - "NAME-CONFLICT" "NAME-CONFLICT-FUNCTION" - "NAME-CONFLICT-DATUM" "NAME-CONFLICT-SYMBOLS" - "RESOLVE-CONFLICT" - - ;; Deprecation stuff - "DEPRECATED" ; declaration - "DEPRECATION-CONDITION" - "DEPRECATION-CONDITION-NAMESPACE" - "DEPRECATION-CONDITION-NAME" - "DEPRECATION-CONDITION-SOFTWARE" - "DEPRECATION-CONDITION-VERSION" - "DEPRECATION-CONDITION-REPLACEMENTS" - "DEPRECATION-CONDITION-RUNTIME-ERROR" - "EARLY-DEPRECATION-WARNING" - "LATE-DEPRECATION-WARNING" - "FINAL-DEPRECATION-WARNING" - "DEPRECATION-ERROR" ; condition and function - - "PRINT-UNREADABLY" - - ;; Readtable normalization control - "READTABLE-BASE-CHAR-PREFERENCE" - "READTABLE-NORMALIZATION" - - ;; and a mechanism for controlling same at compile time - "MUFFLE-CONDITIONS" "UNMUFFLE-CONDITIONS" - - ;; and one for controlling same at runtime - "*MUFFLED-WARNINGS*" - - ;; specification which print errors to ignore ala *break-on-signal* - "*SUPPRESS-PRINT-ERRORS*" - - ;; extended declarations.. - "ALWAYS-BOUND" "FREEZE-TYPE" "GLOBAL" "INHIBIT-WARNINGS" - "MAYBE-INLINE" "START-BLOCK" "END-BLOCK" - - ;; ..and variables to control compiler policy - "*INLINE-EXPANSION-LIMIT*" - "*DERIVE-FUNCTION-TYPES*" - - ;; ..and inspector of compiler policy - "DESCRIBE-COMPILER-POLICY" - "RESTRICT-COMPILER-POLICY" - "SET-MACRO-POLICY" - "FOLD-IDENTICAL-CODE" ; this is a verb, not a compiler policy - - ;; a special form for breaking out of our "declarations - ;; are assertions" default - "TRULY-THE" - - ;; Misc. array and vector tools. - "ARRAY-STORAGE-VECTOR" - - ;; This is something which must exist inside any Common - ;; Lisp implementation, and which someone writing a - ;; customized toplevel might well want. It seems perverse - ;; to hide it from them.. - "INTERACTIVE-EVAL" - - ;; Used by LOAD and EVAL-WHEN to pass toplevel indexes - ;; to compiler. - "EVAL-TLF" - - ;; weak pointers and finalization - "CANCEL-FINALIZATION" - "FINALIZE" - "MAKE-WEAK-POINTER" - "WEAK-POINTER" - "WEAK-POINTER-P" - "WEAK-POINTER-VALUE" - "MAKE-WEAK-VECTOR" - "WEAK-VECTOR-P" - - ;; Hash table extensions - "DEFINE-HASH-TABLE-TEST" - "HASH-TABLE-SYNCHRONIZED-P" - "HASH-TABLE-WEAKNESS" - "WITH-LOCKED-HASH-TABLE" - - ;; If the user knows we're doing IEEE, he might reasonably - ;; want to do this stuff. - "FLOAT-DENORMALIZED-P" - "FLOAT-NAN-P" "FLOAT-TRAPPING-NAN-P" - "FLOAT-INFINITY-P" - "SHORT-FLOAT-NEGATIVE-INFINITY" - "SHORT-FLOAT-POSITIVE-INFINITY" - "SINGLE-FLOAT-NEGATIVE-INFINITY" - "SINGLE-FLOAT-POSITIVE-INFINITY" - "DOUBLE-FLOAT-NEGATIVE-INFINITY" - "DOUBLE-FLOAT-POSITIVE-INFINITY" - "LONG-FLOAT-NEGATIVE-INFINITY" - "LONG-FLOAT-POSITIVE-INFINITY" - - ;; saving Lisp images - "SAVE-LISP-AND-DIE" - - ;; provided for completeness to make it more convenient - ;; to use command-line --disable-debugger functionality - ;; in oddball situations (like building core files using - ;; scripts which run unattended, when the core files are - ;; intended for interactive use) - "DISABLE-DEBUGGER" - "ENABLE-DEBUGGER" - - ;; the mechanism by which {en,dis}able-debugger works is - ;; also exported for people writing alternative toplevels - ;; (Emacs, CLIM interfaces, etc) - "*INVOKE-DEBUGGER-HOOK*" - - ;; miscellaneous useful supported extensions - "QUIT" "EXIT" - "*ED-FUNCTIONS*" - "*MODULE-PROVIDER-FUNCTIONS*" - "MAP-DIRECTORY" - "WITH-TIMEOUT" "TIMEOUT" - "SEED-RANDOM-STATE" - "TYPEXPAND-1" "TYPEXPAND" "TYPEXPAND-ALL" - "DEFINED-TYPE-NAME-P" "VALID-TYPE-SPECIFIER-P" - "DELETE-DIRECTORY" - "SET-SBCL-SOURCE-LOCATION" - "*DISASSEMBLE-ANNOTATE*" - "PRINT-SYMBOL-WITH-PREFIX" - "*PRINT-VECTOR-LENGTH*" - "DECIMAL-WITH-GROUPED-DIGITS-WIDTH" - ;;"OBJECT-SIZE" - - ;; stepping interface - "STEP-CONDITION" "STEP-FORM-CONDITION" "STEP-FINISHED-CONDITION" - "STEP-VALUES-CONDITION" - "STEP-CONDITION-FORM" "STEP-CONDITION-RESULT" - "STEP-CONTINUE" "STEP-NEXT" "STEP-INTO" - "STEP-CONDITION-ARGS" "*STEPPER-HOOK*" "STEP-OUT" - - ;; RUN-PROGRAM is not only useful for users, but also - ;; useful to implement parts of SBCL itself, so we're - ;; going to have to implement it anyway, so we might - ;; as well support it. And then once we're committed - ;; to implementing RUN-PROGRAM, it's nice to have it - ;; return a PROCESS object with operations defined on - ;; that object. - "RUN-PROGRAM" - "PROCESS-ALIVE-P" "PROCESS-CLOSE" - "PROCESS-CORE-DUMPED" "PROCESS-ERROR" "PROCESS-EXIT-CODE" - "PROCESS-INPUT" "PROCESS-KILL" "PROCESS-OUTPUT" "PROCESS-P" - "PROCESS-PID" "PROCESS-PLIST" "PROCESS-PTY" "PROCESS-STATUS" - "PROCESS-STATUS-HOOK" "PROCESS-WAIT" - - ;; pathnames - "NATIVE-PATHNAME" - "PARSE-NATIVE-NAMESTRING" - "NATIVE-NAMESTRING" - - ;; external-format support - "OCTETS-TO-STRING" "STRING-TO-OCTETS" - - ;; Whether to use the interpreter or the compiler for EVAL - "*EVALUATOR-MODE*" - - ;; timer - "TIMER" "MAKE-TIMER" "TIMER-NAME" "TIMER-SCHEDULED-P" - "SCHEDULE-TIMER" "UNSCHEDULE-TIMER" "LIST-ALL-TIMERS" - - ;; SIMD pack - #+sb-simd-pack - ("SIMD-PACK" - "SIMD-PACK-P" - "%MAKE-SIMD-PACK-UB32" - "%MAKE-SIMD-PACK-UB64" - "%MAKE-SIMD-PACK-DOUBLE" - "%MAKE-SIMD-PACK-SINGLE" - "%SIMD-PACK-UB32S" - "%SIMD-PACK-UB64S" - "%SIMD-PACK-DOUBLES" - "%SIMD-PACK-SINGLES") - #+sb-simd-pack-256 - ("SIMD-PACK-256" - "SIMD-PACK-256-P" - "%MAKE-SIMD-PACK-256-UB32" - "%MAKE-SIMD-PACK-256-UB64" - "%MAKE-SIMD-PACK-256-DOUBLE" - "%MAKE-SIMD-PACK-256-SINGLE" - "%SIMD-PACK-256-UB32S" - "%SIMD-PACK-256-UB64S" - "%SIMD-PACK-256-DOUBLES" - "%SIMD-PACK-256-SINGLES") - - ;; versioning utility - "ASSERT-VERSION->=" - "UNKNOWN-KEYWORD-ARGUMENT" - "UNKNOWN-KEYWORD-ARGUMENT-NAME")) - - #s(sb-cold:package-data - :name "SB-FORMAT" - :doc "private: implementation of FORMAT and friends" - :use ("CL" "SB-EXT" "SB-INT" "SB-KERNEL") - :export ("%COMPILER-WALK-FORMAT-STRING" "FORMAT-ERROR" "TOKENS")) - - #s(sb-cold:package-data - :name "SB-GRAY" - :doc - "public: an implementation of the stream-definition-by-user -Lisp extension proposal by David N. Gray" - :use ("CL" "SB-EXT" "SB-INT" "SB-KERNEL") - :export ("FUNDAMENTAL-BINARY-STREAM" - "FUNDAMENTAL-BINARY-INPUT-STREAM" - "FUNDAMENTAL-BINARY-OUTPUT-STREAM" "FUNDAMENTAL-CHARACTER-STREAM" - "FUNDAMENTAL-CHARACTER-INPUT-STREAM" - "FUNDAMENTAL-CHARACTER-OUTPUT-STREAM" - "FUNDAMENTAL-INPUT-STREAM" "FUNDAMENTAL-OUTPUT-STREAM" - "FUNDAMENTAL-STREAM" - "STREAM-ADVANCE-TO-COLUMN" "STREAM-CLEAR-INPUT" - "STREAM-CLEAR-OUTPUT" "STREAM-FILE-POSITION" "STREAM-FINISH-OUTPUT" "STREAM-FORCE-OUTPUT" - "STREAM-FRESH-LINE" "STREAM-LINE-COLUMN" "STREAM-LINE-LENGTH" - "STREAM-LISTEN" "STREAM-PEEK-CHAR" "STREAM-READ-BYTE" - "STREAM-READ-CHAR" "STREAM-READ-CHAR-NO-HANG" "STREAM-READ-LINE" - "STREAM-READ-SEQUENCE" "STREAM-START-LINE-P" "STREAM-TERPRI" - "STREAM-UNREAD-CHAR" - "STREAM-WRITE-BYTE" "STREAM-WRITE-CHAR" "STREAM-WRITE-SEQUENCE" - "STREAM-WRITE-STRING")) - - #s(sb-cold:package-data - :name "SB-INT" - :doc - "private: miscellaneous unsupported extensions to the ANSI spec. Much of -the stuff in here originated in CMU CL's EXTENSIONS package and is retained, -possibly temporarily, because it might be used internally." - :use ("CL" "SB-ALIEN" "SB-GRAY" "SB-FASL" "SB-SYS") - :export (;; lambda list keyword extensions - "&MORE" - - ;; utilities for floating point zero handling - "FP-ZERO-P" - "NEG-FP-ZERO" - - ;; Advice to the compiler that it doesn't need to assert types. - "EXPLICIT-CHECK" - ;; Stack allocation without any questions asked - "TRULY-DYNAMIC-EXTENT" - - ;; Like WITH-LOCKED-HASH-TABLE, but disabled interrupts - "WITH-LOCKED-SYSTEM-TABLE" - - ;; generic set implementation backed by a list that upgrades - ;; to a hashtable if a certain size is exceeded. - "ADD-TO-XSET" - "ALLOC-XSET" - "MAP-XSET" - "XSET" - "XSET-COUNT" - "XSET-EMPTY-P" - "XSET-INTERSECTION" - "XSET-MEMBER-P" - "XSET-MEMBERS" - "XSET-SUBSET-P" - "XSET-UNION" - - ;; sparse set implementation backed by a lightweight hashtable - "COPY-SSET" - "DO-SSET-ELEMENTS" - "MAKE-SSET" - "SSET" "SSET-ELEMENT" - "SSET-ADJOIN" "SSET-DELETE" "SSET-EMPTY" "SSET-COUNT" - "SSET-MEMBER" - - ;; communication between the runtime and Lisp - "*CORE-STRING*" - - ;; INFO stuff doesn't belong in a user-visible package, we - ;; should be able to change it without apology. - "*INFO-ENVIRONMENT*" - "*RECOGNIZED-DECLARATIONS*" - "+INFOS-PER-WORD+" - "+FDEFN-INFO-NUM+" - "+NIL-PACKED-INFOS+" - "ATOMIC-SET-INFO-VALUE" - "CALL-WITH-EACH-GLOBALDB-NAME" - "CLEAR-INFO" - "CLEAR-INFO-VALUES" - "DEFINE-INFO-TYPE" - "FIND-FDEFN" - "SYMBOL-FDEFN" - "GET-INFO-VALUE-INITIALIZING" - "GLOBALDB-SXHASHOID" - "GLOBAL-FTYPE" - "INFO" - "INFO-FIND-AUX-KEY/PACKED" - "INFO-GETHASH" - "INFO-MAPHASH" - "INFO-NUMBER" - "INFO-NUMBER-BITS" - "INFO-VECTOR-FDEFN" - "MAKE-INFO-HASHTABLE" - "META-INFO" - "META-INFO-NUMBER" - "PACKED-INFO-FIELD" - "PACKED-INFO-INSERT" - "PCL-METHODFN-NAME-P" - "SET-INFO-VALUE" - "SHOW-INFO" - "UPDATE-SYMBOL-INFO" - "WITH-GLOBALDB-NAME" - "%BOUNDP" - - ;; Calling a list of hook functions, plus error handling. - "CALL-HOOKS" - ;; Constant form evaluation - "CONSTANT-FORM-VALUE" - "CONSTANT-TYPEP" - - ;; stepping control - "*STEPPING*" - - ;; packages grabbed once and for all - "*KEYWORD-PACKAGE*" "*CL-PACKAGE*" - - ;; hash mixing operations - "MIX" "MIXF" "WORD-MIX" - - ;; Macroexpansion that doesn't touch special forms - "%MACROEXPAND" - "%MACROEXPAND-1" - - "*SETF-FDEFINITION-HOOK*" - - ;; error-reporting facilities - "ARGUMENTS-OUT-OF-DOMAIN-ERROR" - "CLOSED-STREAM-ERROR" "CLOSED-SAVED-STREAM-ERROR" - "COMPILED-PROGRAM-ERROR" - "COMPILER-MACRO-KEYWORD-PROBLEM" - "ENCAPSULATED-CONDITION" - "INVALID-ARRAY-ERROR" - "INVALID-ARRAY-INDEX-ERROR" - "INVALID-ARRAY-P" - "SIMPLE-CONTROL-ERROR" "SIMPLE-FILE-ERROR" - "SIMPLE-PARSE-ERROR" - "SIMPLE-PROGRAM-ERROR" "%PROGRAM-ERROR" - "SIMPLE-READER-ERROR" - "SIMPLE-READER-PACKAGE-ERROR" - "SIMPLE-REFERENCE-ERROR" - "SIMPLE-REFERENCE-WARNING" - "SIMPLE-STREAM-ERROR" - "SIMPLE-STORAGE-CONDITION" - "SIMPLE-STYLE-WARNING" - "STREAM-ERROR-POSITION-INFO" - "TRY-RESTART" - - "BROKEN-PIPE" - - ;; error-signalling facilities - "STANDARD-READTABLE-MODIFIED-ERROR" - "STANDARD-PPRINT-DISPATCH-TABLE-MODIFIED-ERROR" - "ARRAY-BOUNDING-INDICES-BAD-ERROR" - "CIRCULAR-LIST-ERROR" - "SEQUENCE-BOUNDING-INDICES-BAD-ERROR" - "SPECIAL-FORM-FUNCTION" - "STYLE-WARN" "SIMPLE-COMPILER-NOTE" - "TWO-ARG-CHAR-EQUAL" "TWO-ARG-CHAR-NOT-EQUAL" - "TWO-ARG-CHAR-LESSP" "TWO-ARG-CHAR-NOT-LESSP" - "TWO-ARG-CHAR-GREATERP" "TWO-ARG-CHAR-NOT-GREATERP" - "CHAR-EQUAL-CONSTANT" "CHAR-CASE-INFO" - ;; FIXME: potential SB-EXT exports - "CHARACTER-CODING-ERROR" - "CHARACTER-DECODING-ERROR" "CHARACTER-DECODING-ERROR-OCTETS" - "CHARACTER-ENCODING-ERROR" "CHARACTER-ENCODING-ERROR-CODE" - "STREAM-DECODING-ERROR" "STREAM-ENCODING-ERROR" - "C-STRING-ENCODING-ERROR" - "C-STRING-DECODING-ERROR" - "ATTEMPT-RESYNC" "FORCE-END-OF-FILE" - - ;; bootstrapping magic, to make things happen both in - ;; the cross-compilation host compiler's environment and - ;; in the cross-compiler's environment - "DEF!STRUCT" "DEF!TYPE" - ;; bootstrapping magic of a different kind, wherein things happen - ;; as they ordinarily do, plus during second genesis. - "!DEFINE-LOAD-TIME-GLOBAL" - "*!REMOVABLE-SYMBOLS*" - - ;; bootstrapping macro whose effect is to delay until warm load. - "DEF*METHOD" - "!SET-LOAD-FORM-METHOD" - - ;; stuff for hinting to the compiler - "NAMED-DS-BIND" - "NAMED-LAMBDA" - - ;; other variations on DEFFOO stuff useful for bootstrapping - ;; and cross-compiling - "DEFCONSTANT-EQX" - "DEFINE-UNSUPPORTED-FUN" - - ;; messing with PATHNAMEs - "MAKE-TRIVIAL-DEFAULT-PATHNAME" - "PHYSICALIZE-PATHNAME" - "SANE-DEFAULT-PATHNAME-DEFAULTS" - "SBCL-HOMEDIR-PATHNAME" - "SIMPLIFY-NAMESTRING" - "DEBUG-SOURCE-NAMESTRING" - "DEBUG-SOURCE-CREATED" - - "*N-BYTES-FREED-OR-PURIFIED*" - - ;; Deprecating stuff - "DEFINE-DEPRECATED-FUNCTION" - "DEFINE-DEPRECATED-VARIABLE" - "DEPRECATION-STATE" - "DEPRECATION-INFO" "MAKE-DEPRECATION-INFO" - "DEPRECATION-INFO-STATE" - "DEPRECATION-INFO-SOFTWARE" - "DEPRECATION-INFO-VERSION" - "DEPRECATION-INFO-REPLACEMENTS" - "PRINT-DEPRECATION-MESSAGE" - "CHECK-DEPRECATED-THING" "CHECK-DEPRECATED-TYPE" - "DEPRECATED-THING-P" - "DEPRECATION-WARN" - "LOADER-DEPRECATION-WARN" - - ;; miscellaneous non-standard but handy user-level functions.. - "ASSQ" "DELQ" "DELQ1" "MEMQ" "POSQ" "NEQ" - "ADJUST-LIST" - "ALIGN-UP" - "%FIND-PACKAGE-OR-LOSE" "FIND-UNDELETED-PACKAGE-OR-LOSE" - "SANE-PACKAGE" - "COALESCE-TREE-P" - "COMPOUND-OBJECT-P" - "SWAPPED-ARGS-FUN" - "AND/TYPE" "NOT/TYPE" - "ANY/TYPE" "EVERY/TYPE" - "EQUAL-BUT-NO-CAR-RECURSION" - "TYPE-BOUND-NUMBER" "COERCE-NUMERIC-BOUND" - "CONSTANTLY-T" "CONSTANTLY-NIL" "CONSTANTLY-0" - "PSXHASH" - "%BREAK" - "BIT-VECTOR-=" - "PATHNAME=" - "%HASH-TABLE-ALIST" - "HASH-TABLE-EQUALP" - "READ-EVALUATED-FORM" "READ-EVALUATED-FORM-OF-TYPE" - "PICK-BEST-SXHASH-BITS" - - "MAKE-UNPRINTABLE-OBJECT" - "POSSIBLY-BASE-STRINGIZE" - "POWER-OF-TWO-CEILING" - "PRINT-NOT-READABLE-ERROR" - "REPLACE/EQL-HASH-TABLE" - "RECONS" - "SET-CLOSURE-NAME" - - ;; ..and macros.. - "COLLECT" - "COPY-LIST-MACRO" - "DO-ANONYMOUS" "DOVECTOR" "DOHASH" "DOPLIST" - "ENSURE-GETHASH" - "NAMED-LET" - "ONCE-ONLY" - "DEFENUM" - "DEFPRINTER" - "*PRINT-IR-NODES-PRETTY*" - "AVER" - "DX-FLET" "DX-LET" - "AWHEN" "ACOND" "IT" - "BINDING*" "EXTRACT-VAR-DECLS" - "!DEF-BOOLEAN-ATTRIBUTE" - "FUNARG-BIND/CALL-FORMS" - "QUASIQUOTE" - "COMMA-P" - "COMMA-EXPR" - "COMMA-KIND" - "UNQUOTE" - "PACKAGE-HASHTABLE" - "PACKAGE-ITER-STEP" - "WITH-REBOUND-IO-SYNTAX" - "WITH-SANE-IO-SYNTAX" - "WITH-PROGRESSIVE-TIMEOUT" - - ;; ..and CONDITIONs.. - "BUG" - "UNSUPPORTED-OPERATOR" - - "BOOTSTRAP-PACKAGE-NAME" - "BOOTSTRAP-PACKAGE-NOT-FOUND" - "DEBOOTSTRAP-PACKAGE" - "SYSTEM-PACKAGE-P" - - "REFERENCE-CONDITION" "REFERENCE-CONDITION-REFERENCES" - "*PRINT-CONDITION-REFERENCES*" - - "DUPLICATE-DEFINITION" "DUPLICATE-DEFINITION-NAME" - "SAME-FILE-REDEFINITION-WARNING" - "PACKAGE-AT-VARIANCE" - "PACKAGE-AT-VARIANCE-ERROR" - "ARRAY-INITIAL-ELEMENT-MISMATCH" - "TYPE-WARNING" "TYPE-STYLE-WARNING" - "SLOT-INITFORM-TYPE-STYLE-WARNING" - "LOCAL-ARGUMENT-MISMATCH" - "FORMAT-ARGS-MISMATCH" "FORMAT-TOO-FEW-ARGS-WARNING" - "FORMAT-TOO-MANY-ARGS-WARNING" "EXTENSION-FAILURE" - "STRUCTURE-INITARG-NOT-KEYWORD" "CONSTANT-MODIFIED" - - ;; ..and DEFTYPEs.. - "HASH-CODE" - "INDEX" "LOAD/STORE-INDEX" - "SIGNED-BYTE-WITH-A-BITE-OUT" - "UNSIGNED-BYTE-WITH-A-BITE-OUT" - "SFUNCTION" "UNSIGNED-BYTE*" - "CONSTANT-DISPLACEMENT" - "EXTENDED-FUNCTION-DESIGNATOR" - "EXTENDED-FUNCTION-DESIGNATOR-P" - ;; ..and type predicates - "DOUBLE-FLOAT-P" - "LOGICAL-PATHNAME-P" - "LONG-FLOAT-P" - "SHORT-FLOAT-P" - "SINGLE-FLOAT-P" - "FIXNUMP" - "FIXNUMP-INSTANCE-REF" "FIXNUMP-CAR" "FIXNUMP-CDR" - "BIGNUMP" - "RATIOP" - "UNBOUND-MARKER-P" - - ;; encapsulation - "ENCAPSULATE" "ENCAPSULATED-P" - "UNENCAPSULATE" - "ENCAPSULATE-FUNOBJ" - - ;; various CHAR-CODEs - "BACKSPACE-CHAR-CODE" "BELL-CHAR-CODE" "ESCAPE-CHAR-CODE" - "FORM-FEED-CHAR-CODE" "LINE-FEED-CHAR-CODE" - "RETURN-CHAR-CODE" "RUBOUT-CHAR-CODE" "TAB-CHAR-CODE" - - ;; symbol-hacking idioms - "GENSYMIFY" "GENSYMIFY*" "KEYWORDICATE" "SYMBOLICATE" - "INTERNED-SYMBOL-P" "PACKAGE-SYMBOLICATE" - "LOGICALLY-READONLYIZE" - - ;; certainly doesn't belong in public extensions - ;; FIXME: maybe belongs in %KERNEL with other typesystem stuff? - "CONSTANT-ARG" - - ;; various internal defaults - "*LOAD-SOURCE-DEFAULT-TYPE*" "BASE-CHAR-CODE-LIMIT" - - ;; hash caches - "DEFUN-CACHED" - "DROP-ALL-HASH-CACHES" - - ;; time - "FORMAT-DECODED-TIME" - "FORMAT-UNIVERSAL-TIME" - - ;; used for FORMAT tilde paren - "MAKE-CASE-FROB-STREAM" - - ;; helpers for C library calls - "STRERROR" "SIMPLE-PERROR" - - ;; debuggers' little helpers - #+sb-show("*/SHOW*" - "HEXSTR") - "/SHOW" "/NOSHOW" - "/SHOW0" "/NOSHOW0" - - ;; cross-compilation bootstrap hacks which turn into - ;; placeholders in a target system - "UNCROSS" - "!UNCROSS-FORMAT-CONTROL" - - ;; might as well be shared among the various files which - ;; need it: - "*EOF-OBJECT*" - - ;; allocation to static space - "MAKE-STATIC-VECTOR" - - ;; alien interface utilities - "C-STRINGS->STRING-LIST" - - ;; misc. utilities used internally - "ADDRESS-BASED-COUNTER-VAL" - "DEFINE-FUNCTION-NAME-SYNTAX" "VALID-FUNCTION-NAME-P" ; should be SB-EXT? - "LEGAL-VARIABLE-NAME-P" - "LEGAL-FUN-NAME-P" "LEGAL-FUN-NAME-OR-TYPE-ERROR" - "FUN-NAME-BLOCK-NAME" - "FUN-NAME-INLINE-EXPANSION" - "LISTEN-SKIP-WHITESPACE" - "PACKAGE-INTERNAL-SYMBOL-COUNT" "PACKAGE-EXTERNAL-SYMBOL-COUNT" - "PARSE-BODY" "PARSE-LAMBDA-LIST" "MAKE-LAMBDA-LIST" - "CHECK-DESIGNATOR" - "CHECK-LAMBDA-LIST-NAMES" - "LAMBDA-LIST-KEYWORD-MASK" - "PARSE-KEY-ARG-SPEC" "PARSE-OPTIONAL-ARG-SPEC" - "LL-KWDS-RESTP" "LL-KWDS-KEYP" "LL-KWDS-ALLOWP" - "MAKE-MACRO-LAMBDA" - "PROPER-LIST-OF-LENGTH-P" "PROPER-LIST-P" - "LIST-OF-LENGTH-AT-LEAST-P" "SEQUENCE-OF-LENGTH-AT-LEAST-P" - "LIST-WITH-LENGTH-P" - "SINGLETON-P" "ENSURE-LIST" - "MISSING-ARG" - "FEATUREP" - "FLUSH-STANDARD-OUTPUT-STREAMS" - "WITH-UNIQUE-NAMES" "MAKE-GENSYM-LIST" - "ABOUT-TO-MODIFY-SYMBOL-VALUE" - "SELF-EVALUATING-P" - "PRINT-PRETTY-ON-STREAM-P" - "ARRAY-READABLY-PRINTABLE-P" - "LOOKS-LIKE-NAME-OF-SPECIAL-VAR-P" - "POSITIVE-PRIMEP" - "EVAL-IN-LEXENV" - "SIMPLE-EVAL-IN-LEXENV" - "FORCE" "DELAY" "PROMISE-READY-P" - "FIND-RESTART-OR-CONTROL-ERROR" - "LOAD-AS-SOURCE" - "DESCRIPTOR-SAP" - "DO-PACKED-VARINTS" - - "CLOSURE-EXTRA-VALUES" - "PACK-CLOSURE-EXTRA-VALUES" - "SET-CLOSURE-EXTRA-VALUES" - "+CLOSURE-NAME-INDEX+" - - ;; These could be moved back into SB-EXT if someone has - ;; compelling reasons, but hopefully we can get by - ;; without supporting them, at least not as publicly - ;; accessible things with fixed interfaces. - "GET-FLOATING-POINT-MODES" - "SET-FLOATING-POINT-MODES" - "WITH-FLOAT-TRAPS-MASKED" - - ;; a sort of quasi-unbound tag for use in hash tables - "+EMPTY-HT-SLOT+" - - ;; low-level i/o stuff - "DONE-WITH-FAST-READ-CHAR" - "FAST-READ-BYTE" - "FAST-READ-BYTE-REFILL" - "FAST-READ-CHAR" - "FAST-READ-CHAR-REFILL" - "FAST-READ-S-INTEGER" - "FAST-READ-U-INTEGER" - "FAST-READ-VAR-U-INTEGER" - "FILE-NAME" - "FORM-TRACKING-STREAM" - "FORM-TRACKING-STREAM-OBSERVER" - "FORM-TRACKING-STREAM-P" - "FORM-TRACKING-STREAM-FORM-START-BYTE-POS" - "FORM-TRACKING-STREAM-FORM-START-CHAR-POS" - "LINE/COL-FROM-CHARPOS" - "%INTERN" - "WITH-FAST-READ-BYTE" - "PREPARE-FOR-FAST-READ-CHAR" - "OUT-STREAM-FROM-DESIGNATOR" - "STRINGIFY-OBJECT" - "%WRITE" - - ;; hackery to help set up for cold init - "!BEGIN-COLLECTING-COLD-INIT-FORMS" - "!COLD-INIT-FORMS" - "!COLD-FSET" - "!DEFUN-FROM-COLLECTED-COLD-INIT-FORMS" - - ;; catch tags - "TOPLEVEL-CATCHER" - - ;; hooks for contrib/ stuff we're insufficiently sure - ;; about to add to SB-EXT - "*REPL-PROMPT-FUN*" - "*REPL-READ-FORM-FUN*" - - ;; Character database - "**CHARACTER-MISC-DATABASE**" - "**CHARACTER-HIGH-PAGES**" - "**CHARACTER-LOW-PAGES**" - "**CHARACTER-DECOMPOSITIONS**" - "**CHARACTER-PRIMARY-COMPOSITIONS**" - "**CHARACTER-CASES**" - "**CHARACTER-CASE-PAGES**" - "**CHARACTER-COLLATIONS**" - "**UNICODE-CHAR-NAME-DATABASE**" - "**UNICODE-NAME-CHAR-DATABASE**" - "**UNICODE-1-CHAR-NAME-DATABASE**" - "**UNICODE-1-NAME-CHAR-DATABASE**" - "**UNICODE-CHARACTER-NAME-HUFFMAN-TREE**" - - ;; Character database access - "MISC-INDEX" - "CLEAR-FLAG" - "PACK-3-CODEPOINTS" - - ;; Huffman trees - "HUFFMAN-ENCODE" - "HUFFMAN-DECODE" - "BINARY-SEARCH" - "DOUBLE-VECTOR-BINARY-SEARCH")) - - ;; FIXME: This package is awfully huge. It'd probably be good to - ;; split it. There's at least one natural way to split it: the - ;; implementation of the Lisp type system (e.g. TYPE-INTERSECTION and - ;; SPECIFIER-TYPE) could move to a separate package SB-TYPE. (There's - ;; lots of stuff which currently uses the SB-KERNEL package which - ;; doesn't actually use the type system stuff.) And maybe other - ;; possible splits too: - ;; * Pull GC stuff (*GC-INHIBIT*, *GC-PENDING*, etc.) - ;; out into SB-GC. - ;; * Pull special case implementations of sequence functions (e.g. - ;; %MAP-TO-LIST-ARITY-1 and %FIND-POSITION-IF-NOT) and - ;; other sequence function implementation grot into SB-SEQ. - ;; * Pull all the math stuff (%ACOS, %COSH, WORD-LOGICAL-AND...) - ;; into SB-MATH. - ;; * Pull all the array stuff (%ARRAY-DATA, - ;; WITH-ARRAY-DATA, ALLOCATE-VECTOR, HAIRY-DATA-VECTOR-REF...) - ;; into SB-ARRAY. - ;; * Pull all the streams stuff out into SB-STREAM. - ;; * Pull all the OBJECT-NOT-FOO symbols out. Maybe we could even - ;; figure out a way to stop exporting them? Failing that, - ;; they could be in SB-INTERR. - ;; Or better still, since error names are basically meaningless except - ;; for the ~18 errors that are _not_ object-not-<x>, stop naming them. - ;; C just needs a map from number -> string-to-show. - #s(sb-cold:package-data - :name "SB-KERNEL" - :doc - "private: Theoretically this 'hides state and types used for package -integration' (said CMU CL architecture.tex) and that probably was and -is a good idea, but see SB-SYS re. blurring of boundaries." - :use ("CL" "SB-ALIEN" "SB-ALIEN-INTERNALS" "SB-BIGNUM" - "SB-EXT" "SB-FASL" "SB-INT" "SB-SYS" "SB-GRAY") - :reexport (#+sb-simd-pack("SIMD-PACK" - "SIMD-PACK-P" - "%MAKE-SIMD-PACK-UB32" - "%MAKE-SIMD-PACK-UB64" - "%MAKE-SIMD-PACK-DOUBLE" - "%MAKE-SIMD-PACK-SINGLE" - "%SIMD-PACK-UB32S" - "%SIMD-PACK-UB64S" - "%SIMD-PACK-DOUBLES" - "%SIMD-PACK-SINGLES")) - :export ("%%DATA-VECTOR-REFFERS%%" - "%%DATA-VECTOR-SETTERS%%" - "%ACOS" - "%ACOSH" - "%ADJOIN" - "%ADJOIN-EQ" - "%ADJOIN-KEY" - "%ADJOIN-KEY-EQ" - "%ADJOIN-KEY-TEST" - "%ADJOIN-KEY-TEST-NOT" - "%ADJOIN-TEST" - "%ADJOIN-TEST-NOT" - "%ARRAY-AVAILABLE-ELEMENTS" - "%ARRAY-DATA" - "%ARRAY-DATA-VECTOR" ; DO NOT USE !!! - "%ARRAY-DIMENSION" "%ARRAY-DISPLACED-P" - "%ARRAY-DISPLACED-FROM" - "%ARRAY-DISPLACEMENT" "%ARRAY-FILL-POINTER" - "%ARRAY-FILL-POINTER-P" "%ARRAY-RANK" "%ARRAY-RANK=" - "%ARRAY-ATOMIC-INCF/WORD" - "%ASH/RIGHT" - "%ASSOC" - "%ASSOC-EQ" - "%ASSOC-IF" - "%ASSOC-IF-KEY" - "%ASSOC-IF-NOT" - "%ASSOC-IF-NOT-KEY" - "%ASSOC-KEY" - "%ASSOC-KEY-EQ" - "%ASSOC-KEY-TEST" - "%ASSOC-KEY-TEST-NOT" - "%ASSOC-TEST" - "%ASSOC-TEST-NOT" - "%ASIN" "%ASINH" - "%ATAN" "%ATAN2" "%ATANH" - "%ATOMIC-DEC-CAR" "%ATOMIC-INC-CAR" - "%ATOMIC-DEC-CDR" "%ATOMIC-INC-CDR" - "%ATOMIC-DEC-SYMBOL-GLOBAL-VALUE" - "%ATOMIC-INC-SYMBOL-GLOBAL-VALUE" - "%CALLER-FRAME" - "%CALLER-PC" - "%CHECK-BOUND" "CHECK-BOUND" - "%CHECK-GENERIC-SEQUENCE-BOUNDS" - "%CHECK-VECTOR-SEQUENCE-BOUNDS" - "%CAS-SYMBOL-GLOBAL-VALUE" - "%COPY-INSTANCE" "%COPY-INSTANCE-SLOTS" - "%COMPARE-AND-SWAP-CAR" - "%COMPARE-AND-SWAP-CDR" - "%COMPARE-AND-SWAP-SVREF" - "%COMPARE-AND-SWAP-SYMBOL-INFO" - "%COMPARE-AND-SWAP-SYMBOL-VALUE" - "%CONCATENATE-TO-BASE-STRING" - "%CONCATENATE-TO-STRING" - "%CONCATENATE-TO-SIMPLE-VECTOR" - "%CONCATENATE-TO-LIST" "%CONCATENATE-TO-VECTOR" - "CONTAINS-UNKNOWN-TYPE-P" - "%COS" "%COS-QUICK" - "%COSH" "%DATA-VECTOR-AND-INDEX" "%DEPOSIT-FIELD" - "%DOUBLE-FLOAT" "%DPB" "%EQL" "%EQL/INTEGER" - "%EXIT" - "%EXP" "%EXPM1" - "%FIND-POSITION" - "%FIND-POSITION-VECTOR-MACRO" "%FIND-POSITION-IF" - "%FIND-POSITION-IF-VECTOR-MACRO" "%FIND-POSITION-IF-NOT" - "%FIND-POSITION-IF-NOT-VECTOR-MACRO" - "FIXNUM-MOD-P" - "%HYPOT" - "%INSTANCE-CAS" - "%LDB" "%LOG" "%LOGB" "%LOG10" - "%LAST0" - "%LAST1" - "%LASTN/FIXNUM" - "%LASTN/BIGNUM" - "%LOG1P" - #+long-float "%LONG-FLOAT" - "%MAKE-ARRAY" - "%MAKE-COMPLEX" "%MAKE-FUNCALLABLE-INSTANCE" - "%MAKE-FUNCALLABLE-STRUCTURE-INSTANCE-ALLOCATOR" - "%MAKE-INSTANCE" - "%MAKE-LISP-OBJ" - "%MAKE-LIST" - "%MAKE-RATIO" - #+sb-simd-pack "%MAKE-SIMD-PACK" - #+sb-simd-pack-256 "%MAKE-SIMD-PACK-256" - "%MAKE-STRUCTURE-INSTANCE" - "%MAKE-STRUCTURE-INSTANCE-ALLOCATOR" - "%MAP" "%MAP-FOR-EFFECT-ARITY-1" - "%MAP-TO-LIST-ARITY-1" "%MAP-TO-SIMPLE-VECTOR-ARITY-1" - "%MASK-FIELD" - "%MEMBER" - "%MEMBER-EQ" - "%MEMBER-IF" - "%MEMBER-IF-KEY" - "%MEMBER-IF-NOT" - "%MEMBER-IF-NOT-KEY" - "%MEMBER-KEY" - "%MEMBER-KEY-EQ" - "%MEMBER-KEY-TEST" - "%MEMBER-KEY-TEST-NOT" - "%MEMBER-TEST" - "%MEMBER-TEST-NOT" - "%MULTIPLY-HIGH" - "%NEGATE" "%POW" - "%OTHER-POINTER-WIDETAG" - "%PCL-INSTANCE-P" - "%PUTHASH" - "%RASSOC" - "%RASSOC-EQ" - "%RASSOC-IF" - "%RASSOC-IF-KEY" - "%RASSOC-IF-NOT" - "%RASSOC-IF-NOT-KEY" - "%RASSOC-KEY" - "%RASSOC-KEY-EQ" - "%RASSOC-KEY-TEST" - "%RASSOC-KEY-TEST-NOT" - "%RASSOC-TEST" - "%RASSOC-TEST-NOT" - "%VECTOR-RAW-BITS" - "%SCALB" "%SCALBN" - "%RAW-INSTANCE-ATOMIC-INCF/WORD" - "%RAW-INSTANCE-CAS/WORD" - "%RAW-INSTANCE-REF/WORD" "%RAW-INSTANCE-SET/WORD" - "%RAW-INSTANCE-CAS/SIGNED-WORD" - "%RAW-INSTANCE-REF/SIGNED-WORD" "%RAW-INSTANCE-SET/SIGNED-WORD" - "%RAW-INSTANCE-REF/SINGLE" "%RAW-INSTANCE-SET/SINGLE" - "%RAW-INSTANCE-REF/DOUBLE" "%RAW-INSTANCE-SET/DOUBLE" - "%RAW-INSTANCE-REF/COMPLEX-SINGLE" - "%RAW-INSTANCE-SET/COMPLEX-SINGLE" - "%RAW-INSTANCE-REF/COMPLEX-DOUBLE" - "%RAW-INSTANCE-SET/COMPLEX-DOUBLE" - "%SET-ARRAY-DIMENSION" "%SET-FUNCALLABLE-INSTANCE-INFO" - "%SET-VECTOR-RAW-BITS" - "%SET-SAP-REF-16" "%SET-SAP-REF-32" "%SET-SAP-REF-64" - "%SET-SAP-REF-WORD" "%SET-SAP-REF-8" "%SET-SAP-REF-DOUBLE" - "%SET-SAP-REF-LISPOBJ" "%SET-SAP-REF-LONG" "%SET-SAP-REF-SAP" - "%SET-SAP-REF-SINGLE" "%SET-SIGNED-SAP-REF-16" - "%SET-SIGNED-SAP-REF-32" "%SET-SIGNED-SAP-REF-64" - "%SET-SIGNED-SAP-REF-WORD" - "%SET-SIGNED-SAP-REF-8" "%SET-STACK-REF" - "%SET-SYMBOL-HASH" - "%SIN" "%SIN-QUICK" "%SINGLE-FLOAT" - "%SINH" "%SQRT" "%SXHASH-STRING" "%SXHASH-SIMPLE-STRING" - #+sb-simd-pack - ("%SIMD-PACK-TAG" - "%SIMD-PACK-LOW" - "%SIMD-PACK-HIGH") - #+sb-simd-pack-256 - ("%SIMD-PACK-256-TAG" - "%SIMD-PACK-256-0" "%SIMD-PACK-256-1" - "%SIMD-PACK-256-2" "%SIMD-PACK-256-3") - "%SXHASH-SIMPLE-SUBSTRING" "%TAN" "%TAN-QUICK" "%TANH" - "THE*" - "%UNARY-ROUND" - "%UNARY-TRUNCATE" - "%UNARY-TRUNCATE/SINGLE-FLOAT" - "%UNARY-TRUNCATE/DOUBLE-FLOAT" - "%UNARY-FTRUNCATE" - "%WITH-ARRAY-DATA" - "%WITH-ARRAY-DATA/FP" - "%WITH-ARRAY-DATA-MACRO" - "*APPROXIMATE-NUMERIC-UNIONS*" - "*CURRENT-INTERNAL-ERROR-CONTEXT*" - "*CURRENT-LEVEL-IN-PRINT*" - "*EMPTY-TYPE*" - "*EVAL-CALLS*" - "*GC-INHIBIT*" "*GC-PENDING*" - #+sb-thread "*STOP-FOR-GC-PENDING*" - "*IN-WITHOUT-GCING*" - "*UNIVERSAL-TYPE*" - "*UNIVERSAL-FUN-TYPE*" "*UNPARSE-FUN-TYPE-SIMPLIFY*" - "*WILD-TYPE*" "WORD-LOGICAL-AND" "WORD-LOGICAL-ANDC1" - "WORD-LOGICAL-ANDC2" "WORD-LOGICAL-EQV" - "WORD-LOGICAL-NAND" "WORD-LOGICAL-NOR" "WORD-LOGICAL-NOT" - "WORD-LOGICAL-OR" "WORD-LOGICAL-ORC1" "WORD-LOGICAL-ORC2" - "WORD-LOGICAL-XOR" - "ALLOW-NON-RETURNING-TAIL-CALL" - "ALIEN-TYPE-TYPE" "ALIEN-TYPE-TYPE-ALIEN-TYPE" "ALIEN-TYPE-TYPE-P" - "ALLOCATE-VECTOR" "ALLOCATE-STATIC-VECTOR" - "ASSERT-SYMBOL-HOME-PACKAGE-UNLOCKED" - "BUILD-RATIO" - "PROGRAM-ASSERT-SYMBOL-HOME-PACKAGE-UNLOCKED" - "DISABLED-PACKAGE-LOCKS" - "WITH-SINGLE-PACKAGE-LOCKED-ERROR" - "ALWAYS-SUBTYPEP" - "ARGS-TYPE" "ARGS-TYPE-ALLOWP" "ARGS-TYPE-KEYP" - "ARGS-TYPE-KEYWORDS" "ARGS-TYPE-OPTIONAL" "ARGS-TYPE-P" - "ARGS-TYPE-REQUIRED" "ARGS-TYPE-REST" - "ARRAY-HEADER-P" "SIMPLE-ARRAY-HEADER-P" - "ARRAY-TYPE" "ARRAY-TYPE-COMPLEXP" - "ARRAY-TYPE-DIMENSIONS" "ARRAY-TYPE-ELEMENT-TYPE" - "ARRAY-TYPE-P" "ARRAY-TYPE-SPECIALIZED-ELEMENT-TYPE" - "ARRAY-UNDERLYING-WIDETAG" - "ASSERT-ERROR" - #+sb-unicode "BASE-CHAR-P" - "BASE-STRING-P" - "BIND" "BINDING-STACK-POINTER-SAP" "BIT-INDEX" - "BOGUS-ARG-TO-VALUES-LIST-ERROR" "BOOLE-CODE" - "BOUNDING-INDICES-BAD-ERROR" "BYTE-SPECIFIER" "%BYTE-BLT" - "FUNCTION-DESIGNATOR" - "CASE-BODY-ERROR" - "CHARACTER-SET" "CHARACTER-SET-TYPE" - "CHARACTER-SET-TYPE-PAIRS" - #+sb-unicode "CHARACTER-STRING-P" - "CHARPOS" - "CHECK-FOR-CIRCULARITY" "CHECK-TYPE-ERROR" "CLOSED-FLAME" - "CLASS-CLASSOID" - "CODE-COMPONENT" "CODE-COMPONENT-P" - "CODE-HEADER-REF" "CODE-HEADER-SET" "CODE-HEADER-WORDS" - "CODE-JUMP-TABLE-WORDS" - "CODE-INSTRUCTIONS" "CODE-N-UNBOXED-DATA-BYTES" - "CODE-OBJECT-SIZE" "CODE-TRAILER-REF" - "COERCE-SYMBOL-TO-FUN" - "COERCE-TO-FUN" "COERCE-TO-LEXENV" "COERCE-TO-LIST" - "COERCE-TO-VALUES" "COERCE-TO-VECTOR" - "COMPLEX-DOUBLE-FLOAT" "COMPLEX-DOUBLE-FLOAT-P" - "COMPLEX-FLOAT-P" - #+long-float ("COMPLEX-LONG-FLOAT" "COMPLEX-LONG-FLOAT-P") - "COMPLEX-RATIONAL-P" - "COMPLEX-SINGLE-FLOAT" "COMPLEX-SINGLE-FLOAT-P" - "COMPLEX-VECTOR-P" "COMPOUND-TYPE" "COMPOUND-TYPE-P" - "COMPOUND-TYPE-TYPES" - "CONDITION-DESIGNATOR-HEAD" - "CONS-TYPE" "CONS-TYPE-CAR-TYPE" - "CONS-TYPE-CDR-TYPE" "CONS-TYPE-P" "CONSED-SEQUENCE" - "CONSTANT" "CONSTANT-TYPE" "CONSTANT-TYPE-P" - "CONSTANT-TYPE-TYPE" "CONTAINING-INTEGER-TYPE" - "CONTROL-STACK-POINTER-SAP" - "CSUBTYPEP" "CTYPE" "TYPE-HASH-VALUE" "CTYPE-OF" - "CTYPE-P" "CTYPEP" - "CTYPE-ARRAY-DIMENSIONS" "CTYPE-ARRAY-SPECIALIZED-ELEMENT-TYPES" - "CURRENT-FP" "CURRENT-SP" "CURRENT-DYNAMIC-SPACE-START" - "DATA-NIL-VECTOR-REF" - "DATA-VECTOR-REF" "DATA-VECTOR-REF-WITH-OFFSET" - "DATA-VECTOR-SET" "DATA-VECTOR-SET-WITH-OFFSET" - "DECLARATION-TYPE-CONFLICT-ERROR" - "DECODE-DOUBLE-FLOAT" - #+long-float "DECODE-LONG-FLOAT" - "DECODE-SINGLE-FLOAT" - "DEFINE-STRUCTURE-SLOT-ADDRESSOR" - "DEFINED-FTYPE-MATCHES-DECLARED-FTYPE-P" - "!DEFSTRUCT-WITH-ALTERNATE-METACLASS" "DESCEND-INTO" - "DIVISION-BY-ZERO-ERROR" - "DO-REST-ARG" - "DO-INSTANCE-TAGGED-SLOT" - "DOUBLE-FLOAT-EXPONENT" - "DOUBLE-FLOAT-BITS" - "DOUBLE-FLOAT-HIGH-BITS" "DOUBLE-FLOAT-INT-EXPONENT" - "DOUBLE-FLOAT-LOW-BITS" "DOUBLE-FLOAT-SIGNIFICAND" - "DYNBIND" - "FLOAT-WAIT" "DYNAMIC-SPACE-FREE-POINTER" "DYNAMIC-USAGE" - "EFFECTIVE-FIND-POSITION-TEST" - "EFFECTIVE-FIND-POSITION-KEY" - "ENSURE-SYMBOL-HASH" - "ENSURE-SYMBOL-TLS-INDEX" - "ERROR-NUMBER-OR-LOSE" - "EVAL-WHEN-COMPILE-TOPLEVEL" - "EXTENDED-CHAR-P" "EXTERNAL-FORMAT-DESIGNATOR" - "FAST-&REST-NTH" - "FILENAME" - "FILL-ARRAY" - "FILL-DATA-VECTOR" - "FIND-AND-INIT-OR-CHECK-LAYOUT" - "FIND-DEFSTRUCT-DESCRIPTION" - "FIND-OR-CREATE-FDEFN" - "FLOAT-EXPONENT" - "FLOAT-FORMAT-DIGITS" "FLOAT-FORMAT-NAME" - "FLOAT-FORMAT-MAX" "FLOAT-INT-EXPONENT" - "FLOAT-INFINITY-OR-NAN-P" - "FLOAT-SIGN-BIT" - "FLOATING-POINT-EXCEPTION" "FORM" "FORMAT-CONTROL" - "*FREE-INTERRUPT-CONTEXT-INDEX*" "FUNCALLABLE-INSTANCE-P" - "FSC-INSTANCE-HASH" - "%FUN-CODE-OFFSET" "FUN-CODE-HEADER" - "FUN-DESIGNATOR-TYPE" "FUN-DESIGNATOR-TYPE-P" - "FUN-TYPE" "FUN-TYPE-ALLOWP" - "FUN-TYPE-KEYP" "FUN-TYPE-KEYWORDS" "FUN-TYPE-NARGS" - "FUN-TYPE-OPTIONAL" "FUN-TYPE-P" "FUN-TYPE-REQUIRED" - "FUN-TYPE-REST" "FUN-TYPE-RETURNS" "FUN-TYPE-WILD-ARGS" - "GENERALIZED-BOOLEAN" - "GENERIC-ABSTRACT-TYPE-FUNCTION" - "GET-CLOSURE-LENGTH" "GET-HEADER-DATA" - "FUNCTION-HEADER-WORD" - "INSTANCE-HEADER-WORD" - "GET-LISP-OBJ-ADDRESS" "GENERATION-OF" - "LOWTAG-OF" "WIDETAG-OF" "WIDETAG=" - "HAIRY-DATA-VECTOR-REF" - "HAIRY-DATA-VECTOR-REF/CHECK-BOUNDS" "HAIRY-DATA-VECTOR-SET" - "HAIRY-DATA-VECTOR-SET/CHECK-BOUNDS" - "HAIRY-TYPE" "HAIRY-TYPE-P" "HAIRY-TYPE-SPECIFIER" - "HANDLE-CIRCULARITY" "HOST" "ILL-BIN" - "ILL-BOUT" "ILL-IN" "ILL-OUT" "INDEX-OR-MINUS-1" - "INDEX-TOO-LARGE-ERROR" "*!INITIAL-ASSEMBLER-ROUTINES*" - "*!INITIAL-DEBUG-SOURCES*" - "*!INITIAL-FDEFN-OBJECTS*" "*!INITIAL-FOREIGN-SYMBOLS*" - "*!INITIAL-LAYOUTS*" "*!INITIAL-SYMBOLS*" - "INTEGER-DECODE-DOUBLE-FLOAT" - #+long-float "INTEGER-DECODE-LONG-FLOAT" - "INTEGER-DECODE-SINGLE-FLOAT" "INTERNAL-ERROR" - #+win32 "HANDLE-WIN32-EXCEPTION" - "INTERNAL-TIME" "INTERNAL-SECONDS" - "INTERNAL-SECONDS-LIMIT" "SAFE-INTERNAL-SECONDS-LIMIT" - "INTERPRETED-FUNCTION" - "INTERSECTION-TYPE" "INTERSECTION-TYPE-P" - "INTERSECTION-TYPE-TYPES" "INVALID-ARG-COUNT-ERROR" - "LOCAL-INVALID-ARG-COUNT-ERROR" - "INVALID-UNWIND-ERROR" - "IRRATIONAL" "KEY-INFO" - "KEY-INFO-NAME" "KEY-INFO-P" "KEY-INFO-TYPE" - "LAYOUT-BITMAP" "LAYOUT-CLASSOID-NAME" - "LAYOUT-DEPTHOID" "LAYOUT-EQUALP-TESTS" "LAYOUT-INVALID-ERROR" - "LAYOUT-FOR-PCL-OBJ-P" - "LAYOUT-SLOT-LIST" "LAYOUT-SLOT-TABLE" - #+(or x86-64 x86) "%LEA" - "LEXENV" "LEXENV-DESIGNATOR" "LINE-LENGTH" - "LIST-ABSTRACT-TYPE-FUNCTION" - "LIST-COPY-SEQ*" - "LIST-FILL*" - "LIST-SUBSEQ*" - "ANSI-STREAM" - "ANSI-STREAM-BIN" "ANSI-STREAM-BOUT" "ANSI-STREAM-CLOSE" - "ANSI-STREAM-ELEMENT-TYPE" - "ANSI-STREAM-FILE-POSITION" - "ANSI-STREAM-IN" - "ANSI-STREAM-IN-BUFFER" "ANSI-STREAM-IN-INDEX" - "ANSI-STREAM-INPUT-STREAM-P" "ANSI-STREAM-MISC" - "ANSI-STREAM-N-BIN" "ANSI-STREAM-OPEN-STREAM-P" - "ANSI-STREAM-OUT" "ANSI-STREAM-SOUT" - "ANSI-STREAM-OUTPUT-STREAM-P" - "COMPLEX-VECTOR" - "LIST-TO-VECTOR*" - "LOGICAL-HOST" "LOGICAL-HOST-DESIGNATOR" - #+long-float ("LONG-FLOAT-EXPONENT" "LONG-FLOAT-EXP-BITS" - "LONG-FLOAT-HIGH-BITS""LONG-FLOAT-LOW-BITS" - "LONG-FLOAT-MID-BITS") - "LRA" "LRA-CODE-HEADER" "LRA-P" - "MAKE-ALIEN-TYPE-TYPE" - "MAKE-ARRAY-HEADER" "MAKE-ARRAY-TYPE" "MAKE-CONS-TYPE" - "%MAKE-DOUBLE-FLOAT" - "MAKE-DOUBLE-FLOAT" "MAKE-FUN-TYPE" "MAKE-KEY-INFO" - "MAKE-LISP-OBJ" - #+long-float "MAKE-LONG-FLOAT" - "MAKE-MEMBER-TYPE" "MAKE-NULL-LEXENV" - "MAKE-EQL-TYPE" "MEMBER-TYPE-FROM-LIST" - "MAKE-NEGATION-TYPE" "TYPE-NEGATION" - "MAKE-NUMERIC-TYPE" - "MAKE-SINGLE-FLOAT" - "MAKE-UNBOUND-MARKER" - "MAKE-SHORT-VALUES-TYPE" "MAKE-SINGLE-VALUE-TYPE" - "MAKE-VALUE-CELL" "MAKE-VALUES-TYPE" - "MAPC-MEMBER-TYPE-MEMBERS" "MAPCAR-MEMBER-TYPE-MEMBERS" - "MAXIMUM-BIGNUM-LENGTH" - "MEMBER-TYPE" "MEMBER-TYPE-MEMBERS" "MEMBER-TYPE-P" - "MEMBER-TYPE-SIZE" - "MODIFIED-NUMERIC-TYPE" - "MOST-NEGATIVE-EXACTLY-DOUBLE-FLOAT-FIXNUM" - "MOST-NEGATIVE-EXACTLY-SINGLE-FLOAT-FIXNUM" - "MOST-POSITIVE-EXACTLY-DOUBLE-FLOAT-FIXNUM" - "MOST-POSITIVE-EXACTLY-SINGLE-FLOAT-FIXNUM" - "NAMED-TYPE" "NAMED-TYPE-NAME" "NAMED-TYPE-P" - "NEGATE" "NEGATION-TYPE" "NEGATION-TYPE-TYPE" - "NIL-ARRAY-ACCESSED-ERROR" - "NIL-FUN-RETURNED-ERROR" - "NON-NULL-SYMBOL-P" - "NUMERIC-CONTAGION" "NUMERIC-TYPE" - "NUMERIC-TYPE-CLASS" "NUMERIC-TYPE-COMPLEXP" - "NUMERIC-TYPE-EQUAL" "NUMERIC-TYPE-FORMAT" - "NUMERIC-TYPE-HIGH" "NUMERIC-TYPE-LOW" "NUMERIC-TYPE-P" - "OBJECT-NOT-ARRAY-ERROR" "OBJECT-NOT-CHARACTER-ERROR" - "OBJECT-NOT-BASE-STRING-ERROR" "OBJECT-NOT-BIGNUM-ERROR" - "OBJECT-NOT-BIT-VECTOR-ERROR" - #+sb-unicode "OBJECT-NOT-CHARACTER-STRING-ERROR" - "OBJECT-NOT-COMPLEX-ERROR" - "OBJECT-NOT-COMPLEX-FLOAT-ERROR" - "OBJECT-NOT-COMPLEX-SINGLE-FLOAT-ERROR" - #+long-float "OBJECT-NOT-COMPLEX-LONG-FLOAT-ERROR" - "OBJECT-NOT-COMPLEX-DOUBLE-FLOAT-ERROR" - "OBJECT-NOT-COMPLEX-RATIONAL-ERROR" - ;; FIXME: It's confusing using "complex" to mean both - ;; "not on the real number line" and "not of a - ;; SIMPLE-ARRAY nature". Perhaps we could rename all the - ;; uses in the second sense as "hairy" instead? - "OBJECT-NOT-COMPLEX-VECTOR-ERROR" "OBJECT-NOT-CONS-ERROR" - "OBJECT-NOT-DOUBLE-FLOAT-ERROR" "OBJECT-NOT-FIXNUM-ERROR" - "OBJECT-NOT-FLOAT-ERROR" "OBJECT-NOT-FUNCTION-ERROR" - "OBJECT-NOT-INSTANCE-ERROR" "OBJECT-NOT-INTEGER-ERROR" - "OBJECT-NOT-LIST-ERROR" - #+long-float "OBJECT-NOT-LONG-FLOAT-ERROR" - "OBJECT-NOT-NUMBER-ERROR" "OBJECT-NOT-RATIO-ERROR" - "OBJECT-NOT-RATIONAL-ERROR" "OBJECT-NOT-REAL-ERROR" - "OBJECT-NOT-SAP-ERROR" "OBJECT-NOT-SIGNED-BYTE-32-ERROR" - "OBJECT-NOT-SIGNED-BYTE-64-ERROR" - "OBJECT-NOT-SIMPLE-ARRAY-COMPLEX-DOUBLE-FLOAT-ERROR" - #+long-float - "OBJECT-NOT-SIMPLE-ARRAY-COMPLEX-LONG-FLOAT-ERROR" - #+sb-simd-pack - "OBJECT-NOT-SIMD-PACK-ERROR" - #+sb-simd-pack-256 - "OBJECT-NOT-SIMD-PACK-256-ERROR" - "OBJECT-NOT-SIMPLE-ARRAY-COMPLEX-SINGLE-FLOAT-ERROR" - "OBJECT-NOT-SIMPLE-ARRAY-DOUBLE-FLOAT-ERROR" - "OBJECT-NOT-SIMPLE-ARRAY-ERROR" - #+long-float "OBJECT-NOT-SIMPLE-ARRAY-LONG-FLOAT-ERROR" - "OBJECT-NOT-SIMPLE-ARRAY-NIL-ERROR" - "OBJECT-NOT-SIMPLE-ARRAY-SINGLE-FLOAT-ERROR" - "OBJECT-NOT-SIMPLE-ARRAY-UNSIGNED-BYTE-15-ERROR" - "OBJECT-NOT-SIMPLE-ARRAY-UNSIGNED-BYTE-16-ERROR" - "OBJECT-NOT-SIMPLE-ARRAY-UNSIGNED-BYTE-2-ERROR" - ;; KLUDGE: 32-bit and 64-bit ports implement a different - ;; set of specialized array types. Various bits of code - ;; in SBCL assume that symbols connected to the - ;; specialized array types are exported. But there's not - ;; a good way at this point to know whether the port for - ;; which we're building is 32-bit or 64-bit. Granted, we - ;; could hardcode the particulars (or even come up with a - ;; special :64BIT feature), but that seems a little - ;; inelegant. For now, we brute-force the issue by - ;; always exporting all the names required for both - ;; 32-bit and 64-bit ports. Other bits connected to the - ;; same issue are noted throughout the code below with - ;; the tag "32/64-bit issues". --njf, 2004-08-09 - "OBJECT-NOT-SIMPLE-ARRAY-UNSIGNED-FIXNUM-ERROR" - "OBJECT-NOT-SIMPLE-ARRAY-UNSIGNED-BYTE-31-ERROR" - "OBJECT-NOT-SIMPLE-ARRAY-UNSIGNED-BYTE-32-ERROR" - "OBJECT-NOT-SIMPLE-ARRAY-UNSIGNED-BYTE-4-ERROR" - "OBJECT-NOT-SIMPLE-ARRAY-UNSIGNED-BYTE-63-ERROR" - "OBJECT-NOT-SIMPLE-ARRAY-UNSIGNED-BYTE-64-ERROR" - "OBJECT-NOT-SIMPLE-ARRAY-UNSIGNED-BYTE-7-ERROR" - "OBJECT-NOT-SIMPLE-ARRAY-UNSIGNED-BYTE-8-ERROR" - "OBJECT-NOT-SIMPLE-ARRAY-SIGNED-BYTE-16-ERROR" - "OBJECT-NOT-SIMPLE-ARRAY-FIXNUM-ERROR" - "OBJECT-NOT-SIMPLE-ARRAY-SIGNED-BYTE-32-ERROR" - "OBJECT-NOT-SIMPLE-ARRAY-SIGNED-BYTE-64-ERROR" - "OBJECT-NOT-SIMPLE-ARRAY-SIGNED-BYTE-8-ERROR" - "OBJECT-NOT-SIMPLE-BIT-VECTOR-ERROR" - "OBJECT-NOT-SIMPLE-BASE-STRING-ERROR" - #+sb-unicode "OBJECT-NOT-SIMPLE-CHARACTER-STRING-ERROR" - "OBJECT-NOT-SIMPLE-STRING-ERROR" - "OBJECT-NOT-SIMPLE-VECTOR-ERROR" - "OBJECT-NOT-SINGLE-FLOAT-ERROR" "OBJECT-NOT-STRING-ERROR" - "OBJECT-NOT-SYMBOL-ERROR" - "OBJECT-NOT-TYPE-ERROR" - "OBJECT-NOT-UNSIGNED-BYTE-32-ERROR" - "OBJECT-NOT-UNSIGNED-BYTE-64-ERROR" - "OBJECT-NOT-VECTOR-ERROR" - "OBJECT-NOT-VECTOR-NIL-ERROR" - "OBJECT-NOT-WEAK-POINTER-ERROR" - "ODD-KEY-ARGS-ERROR" "OUTPUT-OBJECT" "OUTPUT-UGLY-OBJECT" - "PACKAGE-DESIGNATOR" "PACKAGE-DOC-STRING" - "PACKAGE-HASHTABLE-SIZE" "PACKAGE-HASHTABLE-FREE" - "PACKAGE-INTERNAL-SYMBOLS" "PACKAGE-EXTERNAL-SYMBOLS" - "PARSE-UNKNOWN-TYPE" - "PARSE-UNKNOWN-TYPE-SPECIFIER" - "PATHNAME-DESIGNATOR" "PATHNAME-COMPONENT-CASE" - "POINTER-HASH" - "POINTERP" - #+(or x86 x86-64) "*PSEUDO-ATOMIC-BITS*" - "PUNT-PRINT-IF-TOO-LONG" - "RANDOM-DOCUMENTATION" - "READER-IMPOSSIBLE-NUMBER-ERROR" - "READER-EOF-ERROR" - "RESTART-DESIGNATOR" - "RUN-PENDING-FINALIZERS" - "SCALE-DOUBLE-FLOAT" - #+long-float "SCALE-LONG-FLOAT" - "SCALE-SINGLE-FLOAT" - "SCHWARTZIAN-STABLE-SORT-LIST" "SCHWARTZIAN-STABLE-SORT-VECTOR" - "SCRUB-POWER-CACHE" - "SEQUENCEP" "SEQUENCE-COUNT" "SEQUENCE-END" - "SEQUENCE-OF-CHECKED-LENGTH-GIVEN-TYPE" - "SET-ARRAY-HEADER" "SET-HEADER-BITS" "SET-HEADER-DATA" - "UNSET-HEADER-BITS" - "SHIFT-TOWARDS-END" - "SHIFT-TOWARDS-START" "SHRINK-VECTOR" "%SHRINK-VECTOR" - "SIGNED-BYTE-32-P" "SIGNED-BYTE-64-P" - "SIMPLE-RANK-1-ARRAY-*-P" - "SIMPLE-ARRAY-COMPLEX-DOUBLE-FLOAT-P" - #+long-float "SIMPLE-ARRAY-COMPLEX-LONG-FLOAT-P" - "SIMPLE-ARRAY-COMPLEX-SINGLE-FLOAT-P" - "SIMPLE-ARRAY-DOUBLE-FLOAT-P" - #+long-float "SIMPLE-ARRAY-LONG-FLOAT-P" - "SIMPLE-ARRAY-NIL-P" "SIMPLE-ARRAY-P" - "SIMPLE-ARRAY-SINGLE-FLOAT-P" - "SIMPLE-ARRAY-UNSIGNED-BYTE-15-P" - "SIMPLE-ARRAY-UNSIGNED-BYTE-16-P" - "SIMPLE-ARRAY-UNSIGNED-BYTE-2-P" - "SIMPLE-ARRAY-UNSIGNED-FIXNUM-P" - "SIMPLE-ARRAY-UNSIGNED-BYTE-31-P" - "SIMPLE-ARRAY-UNSIGNED-BYTE-32-P" - "SIMPLE-ARRAY-UNSIGNED-BYTE-4-P" - "SIMPLE-ARRAY-UNSIGNED-BYTE-63-P" - "SIMPLE-ARRAY-UNSIGNED-BYTE-64-P" - "SIMPLE-ARRAY-UNSIGNED-BYTE-7-P" - "SIMPLE-ARRAY-UNSIGNED-BYTE-8-P" - "SIMPLE-ARRAY-SIGNED-BYTE-16-P" - "SIMPLE-ARRAY-FIXNUM-P" - "SIMPLE-ARRAY-SIGNED-BYTE-32-P" - "SIMPLE-ARRAY-SIGNED-BYTE-64-P" - "SIMPLE-ARRAY-SIGNED-BYTE-8-P" "SIMPLE-BASE-STRING-P" - "SIMPLE-CHARACTER-STRING" - #+sb-unicode "SIMPLE-CHARACTER-STRING-P" - "SIMPLE-PACKAGE-ERROR" "SIMPLE-UNBOXED-ARRAY" - "SINGLE-FLOAT-BITS" "SINGLE-FLOAT-EXPONENT" - "SINGLE-FLOAT-INT-EXPONENT" "SINGLE-FLOAT-SIGNIFICAND" - "SINGLE-FLOAT-SIGN" "SINGLE-FLOAT-COPYSIGN" - "SINGLE-VALUE-TYPE" "SINGLE-VALUE-SPECIFIER-TYPE" - "SPECIFIER-TYPE" - #+sb-simd-pack("SIMD-PACK-SINGLE" - "SIMD-PACK-DOUBLE" - "SIMD-PACK-INT" - "SIMD-PACK-TYPE" - "SIMD-PACK-TYPE-ELEMENT-TYPE" - "*SIMD-PACK-ELEMENT-TYPES*") - #+sb-simd-pack-256("SIMD-PACK-256-SINGLE" - "SIMD-PACK-256-DOUBLE" - "SIMD-PACK-256-INT" - "SIMD-PACK-256-TYPE" - "SIMD-PACK-256-TYPE-ELEMENT-TYPE") - "STACK-REF" "STREAM-DESIGNATOR" "STRING-DESIGNATOR" - "STRING-FILL*" - "STRUCT-SLOT-SAP" - "STRUCTURE-CTOR-LAMBDA-PARTS" - "STRUCTURE-INSTANCE-ACCESSOR-P" - "SUB-GC" - "SYMBOL-TLS-INDEX" - "SYMBOLS-DESIGNATOR" - "SYMEVAL" - "SYM-GLOBAL-VAL" - "%INSTANCE-LENGTH" - "%INSTANCE-REF" "%INSTANCE-REF-EQ" - "%INSTANCE-SET" - "TESTABLE-TYPE-P" - "TLS-EXHAUSTED-ERROR" - "*TOP-LEVEL-FORM-P*" - "TWO-ARG-*" "TWO-ARG-+" "TWO-ARG--" "TWO-ARG-/" - "TWO-ARG-/=" "TWO-ARG-<" "TWO-ARG-<=" "TWO-ARG-=" - "TWO-ARG->" "TWO-ARG->=" "TWO-ARG-AND" "TWO-ARG-EQV" - "TWO-ARG-GCD" "TWO-ARG-IOR" "TWO-ARG-LCM" "TWO-ARG-XOR" - "TWO-ARG-STRING=" "TWO-ARG-STRING-EQUAL" "TWO-ARG-STRING<" - "TWO-ARG-STRING>" "TWO-ARG-STRING<=" "TWO-ARG-STRING>=" - "TWO-ARG-STRING/=" "TWO-ARG-STRING-LESSP" "TWO-ARG-STRING-GREATERP" - "TWO-ARG-STRING-NOT-LESSP" "TWO-ARG-STRING-NOT-GREATERP" "TWO-ARG-STRING-NOT-EQUAL" - "TYPE-*-TO-T" - "TYPE-DIFFERENCE" "TYPE-INTERSECTION" - "TYPE-INTERSECTION2" "TYPE-APPROX-INTERSECTION2" - "TYPE-SINGLETON-P" - "TYPE-SINGLE-VALUE-P" "TYPE-SPECIFIER" "TYPE-UNION" - "TYPE/=" "TYPE=" "TYPES-EQUAL-OR-INTERSECT" - "TYPE-OR-NIL-IF-UNKNOWN" - "UNBOUND-SYMBOL-ERROR" "UNBOXED-ARRAY" - "UNDEFINED-FUN-ERROR" "UNDEFINED-ALIEN-FUN-ERROR" - "UNION-TYPE" "UNION-TYPE-P" - "UNION-TYPE-TYPES" "UNKNOWN-ERROR" - "UNINITIALIZED-MEMORY-ERROR" - "UNKNOWN-KEY-ARG-ERROR" "UNKNOWN-TYPE" "UNKNOWN-TYPE-P" - "UNKNOWN-TYPE-SPECIFIER" "UNSEEN-THROW-TAG-ERROR" - "UNSIGNED-BYTE-32-P" "UNSIGNED-BYTE-64-P" - "UPDATE-OBJECT-LAYOUT-OR-INVALID" - "VALID-MACROEXPAND-HOOK" - "VALUE-CELL-REF" "VALUE-CELL-SET" "VALUES-SPECIFIER-TYPE" - "VALUES-SPECIFIER-TYPE-CACHE-CLEAR" "VALUES-SUBTYPEP" - "VALUES-TYPE" "VALUES-TYPE-IN" - "VALUES-TYPE-INTERSECTION" - "VALUES-TYPE-MIN-VALUE-COUNT" "VALUES-TYPE-MAX-VALUE-COUNT" - "VALUES-TYPE-MAY-BE-SINGLE-VALUE-P" "VALUES-TYPE-OPTIONAL" - "VALUES-TYPE-OUT" "VALUES-TYPE-P" "VALUES-TYPE-REQUIRED" - "VALUES-TYPE-REST" "VALUES-TYPE-UNION" - "VALUES-TYPE-TYPES" "VALUES-TYPES" - "VALUES-TYPES-EQUAL-OR-INTERSECT" - - "*VECTOR-WITHOUT-COMPLEX-TYPECODE-INFOS*" - "VECTOR-SINGLE-FLOAT-P" "VECTOR-DOUBLE-FLOAT-P" - "VECTOR-UNSIGNED-BYTE-2-P" "VECTOR-UNSIGNED-BYTE-4-P" - "VECTOR-UNSIGNED-BYTE-7-P" "VECTOR-UNSIGNED-BYTE-8-P" - "VECTOR-UNSIGNED-BYTE-15-P" "VECTOR-UNSIGNED-BYTE-16-P" - "VECTOR-UNSIGNED-BYTE-31-P" "VECTOR-UNSIGNED-BYTE-32-P" - "VECTOR-UNSIGNED-BYTE-63-P" "VECTOR-UNSIGNED-BYTE-64-P" - "VECTOR-SIGNED-BYTE-8-P" "VECTOR-SIGNED-BYTE-16-P" - "VECTOR-FIXNUM-P" "VECTOR-SIGNED-BYTE-32-P" - "VECTOR-SIGNED-BYTE-64-P" "VECTOR-COMPLEX-SINGLE-FLOAT-P" - "VECTOR-COMPLEX-DOUBLE-FLOAT-P" "VECTOR-T-P" - - "VECTOR-NIL-P" - "VECTOR-FILL*" "VECTOR-FILL/T" - "VECTOR-SUBSEQ*" - "VECTOR-TO-VECTOR*" - "VECTOR-OF-CHECKED-LENGTH-GIVEN-LENGTH" "WITH-ARRAY-DATA" - "WITH-CIRCULARITY-DETECTION" - "WITH-WORLD-LOCK" - - ;; bit bash fillers - "UB1-BASH-FILL" "SYSTEM-AREA-UB1-FILL" - "UB2-BASH-FILL" "SYSTEM-AREA-UB2-FILL" - "UB4-BASH-FILL" "SYSTEM-AREA-UB4-FILL" - "UB8-BASH-FILL" "SYSTEM-AREA-UB8-FILL" - "UB16-BASH-FILL" "SYSTEM-AREA-UB16-FILL" - "UB32-BASH-FILL" "SYSTEM-AREA-UB32-FILL" - "UB64-BASH-FILL" "SYSTEM-AREA-UB64-FILL" - - "UB1-BASH-FILL-WITH-UB1" "UB1-BASH-FILL-WITH-SB1" - "UB2-BASH-FILL-WITH-UB2" "UB2-BASH-FILL-WITH-SB2" - "UB4-BASH-FILL-WITH-UB4" "UB4-BASH-FILL-WITH-SB4" - "UB8-BASH-FILL-WITH-UB8" "UB8-BASH-FILL-WITH-SB8" - "UB16-BASH-FILL-WITH-UB16" "UB16-BASH-FILL-WITH-SB16" - "UB32-BASH-FILL-WITH-UB32" "UB32-BASH-FILL-WITH-SB32" - "UB64-BASH-FILL-WITH-SB64" - "UB32-BASH-FILL-WITH-FIXNUM" "UB64-BASH-FILL-WITH-FIXNUM" - "UB32-BASH-FILL-WITH-SINGLE-FLOAT" - "UB64-BASH-FILL-WITH-DOUBLE-FLOAT" - "UB64-BASH-FILL-WITH-COMPLEX-SINGLE-FLOAT" - - ;; bit bash copiers - "UB1-BASH-COPY" "SYSTEM-AREA-UB1-COPY" - "COPY-UB1-TO-SYSTEM-AREA" "COPY-UB1-FROM-SYSTEM-AREA" - "UB2-BASH-COPY" "SYSTEM-AREA-UB2-COPY" - "COPY-UB2-TO-SYSTEM-AREA" "COPY-UB2-FROM-SYSTEM-AREA" - "UB4-BASH-COPY" "SYSTEM-AREA-UB4-COPY" - "COPY-UB4-TO-SYSTEM-AREA" "COPY-UB4-FROM-SYSTEM-AREA" - "UB8-BASH-COPY" "SYSTEM-AREA-UB8-COPY" - "COPY-UB8-TO-SYSTEM-AREA" "COPY-UB8-FROM-SYSTEM-AREA" - "UB16-BASH-COPY" "SYSTEM-AREA-UB16-COPY" - "COPY-UB16-TO-SYSTEM-AREA" "COPY-UB16-FROM-SYSTEM-AREA" - "UB32-BASH-COPY" "SYSTEM-AREA-UB32-COPY" - "COPY-UB32-TO-SYSTEM-AREA" "COPY-UB32-FROM-SYSTEM-AREA" - "UB64-BASH-COPY" "SYSTEM-AREA-UB64-COPY" - "COPY-UB64-TO-SYSTEM-AREA" "COPY-UB64-FROM-SYSTEM-AREA" - - ;; Bit bashing position for bit-vectors - "%BIT-POSITION" "%BIT-POS-FWD" "%BIT-POS-REV" - "%BIT-POSITION/0" "%BIT-POS-FWD/0" "%BIT-POS-REV/0" - "%BIT-POSITION/1" "%BIT-POS-FWD/1" "%BIT-POS-REV/1" - - ;; SIMPLE-FUN type and accessors - "SIMPLE-FUN" - "SIMPLE-FUN-P" - "%SIMPLE-FUN-ARGLIST" - "%SIMPLE-FUN-DOC" - "%SIMPLE-FUN-INFO" - "%SIMPLE-FUN-LEXPR" - "%SIMPLE-FUN-NAME" - "%SIMPLE-FUN-NEXT" ; FIXME: remove - "%SIMPLE-FUN-SELF" ; FIXME: don't export - "%SIMPLE-FUN-TEXT-LEN" - "%SIMPLE-FUN-SOURCE" - "%SIMPLE-FUN-TYPE" - "%SIMPLE-FUN-XREFS" - - ;; CLOSURE type and accessors - "CLOSURE" - "CLOSUREP" - "DO-CLOSURE-VALUES" - "%CLOSURE-FUN" - "%CLOSURE-INDEX-REF" - "%CLOSURE-VALUES" - - ;; Abstract function accessors - "%FUN-FUN" - "%FUN-LAMBDA-LIST" - "%FUN-NAME" - - "FDEFN" "MAKE-FDEFN" "FDEFN-P" "FDEFN-NAME" "FDEFN-FUN" - "FDEFN-MAKUNBOUND" - "%COERCE-CALLABLE-TO-FUN" - "%COERCE-CALLABLE-FOR-CALL" - "FUN-SUBTYPE" - "*MAXIMUM-ERROR-DEPTH*" "%SET-SYMBOL-PLIST" - "INFINITE-ERROR-PROTECT" - "FIND-CALLER-OF-NAMED-FRAME" - "FIND-CALLER-FRAME" - "FIND-INTERRUPTED-FRAME" - "%SET-SYMBOL-VALUE" "%SET-SYMBOL-GLOBAL-VALUE" "%SET-SYMBOL-PACKAGE" - "SET-SYMBOL-GLOBAL-VALUE" - "OUTPUT-SYMBOL" "%COERCE-NAME-TO-FUN" - "DEFAULT-STRUCTURE-PRINT" - "LAYOUT" "LAYOUT-LENGTH" "LAYOUT-PURE" "DSD-RAW-TYPE" - "DEFSTRUCT-DESCRIPTION" "UNDECLARE-STRUCTURE" - "UNDEFINE-FUN-NAME" "DD-TYPE" "CLASSOID-STATE" "INSTANCE" - "*TYPE-SYSTEM-INITIALIZED*" "FIND-LAYOUT" "DSD-NAME" - "%TYPEP" "%%TYPEP" "DD-NAME" "CLASSOID-SUBCLASSES" - "CLASSOID-LAYOUT" "CLASSOID-NAME" "CLASSOID-P" - "NOTE-NAME-DEFINED" - "%CODE-CODE-SIZE" "%CODE-TEXT-SIZE" - "%CODE-SERIALNO" - "DD-SLOTS" "DD-INCLUDE" "SLOT-SETTER-LAMBDA-FORM" - "SLOT-ACCESS-TRANSFORM" - "%IMAGPART" "DSD-ACCESSOR-NAME" "%CODE-DEBUG-INFO" - "LAYOUT-CLASSOID" "LAYOUT-INVALID" - "LAYOUT-FLAGS" - "DSD-TYPE" "%INSTANCEP" "DEFSTRUCT-SLOT-DESCRIPTION" - "DD-PREDICATE-NAME" - "CLASSOID-PROPER-NAME" "%NOTE-TYPE-DEFINED" "LAYOUT-INFO" - "%SET-INSTANCE-LAYOUT" - "DD-CONSTRUCTORS" "DD-DEFAULT-CONSTRUCTOR" - "LAYOUT-OF" "%REALPART" - "STRUCTURE-CLASSOID" "STRUCTURE-CLASSOID-P" - "DSD-INDEX" "GET-DSD-INDEX" - "%INSTANCE-LAYOUT" "LAYOUT-CLOS-HASH" - "PROCLAIM-AS-FUN-NAME" "BECOME-DEFINED-FUN-NAME" - "%NUMERATOR" "CLASSOID-TYPEP" "DSD-READ-ONLY" - "DSD-DEFAULT" "LAYOUT-INHERITS" "DD-LENGTH" - "SET-LAYOUT-INHERITS" - "%CODE-ENTRY-POINT" - "%CODE-FUN-OFFSET" - "CODE-ENTRY-POINTS" ; new accessor - returns a vector - "CODE-N-ENTRIES" - "CODE-N-NAMED-CALLS" - "CODE-OBJ-IS-FILLER-P" - "%CODE-ENTRY-POINTS" ; prefer %CODE-ENTRY-POINT instead of this - "%DENOMINATOR" - "%OTHER-POINTER-P" - "%OTHER-POINTER-SUBTYPE-P" - "IMMOBILE-SPACE-ADDR-P" - "IMMOBILE-SPACE-OBJ-P" - - "STANDARD-CLASSOID" "CLASSOID-OF" - "MAKE-STANDARD-CLASSOID" - "CLASSOID-CELL-CLASSOID" - "CLASSOID-CELL-NAME" - "CLASSOID-CELL-PCL-CLASS" - "CLASSOID-CELL-TYPEP" - "%CLEAR-CLASSOID" - "FIND-CLASSOID-CELL" - "%RANDOM-DOUBLE-FLOAT" - #+long-float "%RANDOM-LONG-FLOAT" - "%RANDOM-SINGLE-FLOAT" "STATIC-CLASSOID" - "%FUNCALLABLE-INSTANCE-INFO" "RANDOM-CHUNK" "BIG-RANDOM-CHUNK" - "N-RANDOM-CHUNK-BITS" - "LAYOUT-CLOS-HASH-LIMIT" - "BUILT-IN-CLASSOID-DIRECT-SUPERCLASSES" - "BUILT-IN-CLASSOID-TRANSLATION" "HASH-LAYOUT-NAME" - "CLASSOID-PCL-CLASS" "FUNCALLABLE-STRUCTURE" - "FUNCTION-WITH-LAYOUT-P" - "%FUN-LAYOUT" - "%SET-FUNCALLABLE-INSTANCE-LAYOUT" - "REGISTER-LAYOUT" - "FUNCALLABLE-INSTANCE" - "MAKE-STATIC-CLASSOID" - "%MAKE-SYMBOL" - "%FUNCALLABLE-INSTANCE-FUN" "SYMBOL-HASH" "SYMBOL-HASH*" - "SYMBOL-INFO" "SYMBOL-INFO-VECTOR" - - "EXTENDED-SEQUENCE" "*EXTENDED-SEQUENCE-TYPE*" - "EXTENDED-SEQUENCE-P" - - "BUILT-IN-CLASSOID" "CONDITION-CLASSOID-P" - "CONDITION-CLASSOID-SLOTS" "MAKE-UNDEFINED-CLASSOID" - "FIND-CLASSOID" "CLASSOID" "CLASSOID-DIRECT-SUPERCLASSES" - "MAKE-LAYOUT" "REDEFINE-LAYOUT-WARNING" - "INSURED-FIND-CLASSOID" "ORDER-LAYOUT-INHERITS" - "STD-COMPUTE-CLASS-PRECEDENCE-LIST" - "+CTYPE-LAYOUT-FLAG+" - "+STRUCTURE-LAYOUT-FLAG+" - "+PCL-OBJECT-LAYOUT-FLAG+" - "+CONDITION-LAYOUT-FLAG+" - "+PATHNAME-LAYOUT-FLAG+" - "+LAYOUT-ALL-TAGGED+" - "**PRIMITIVE-OBJECT-LAYOUTS**" - - "*HANDLER-CLUSTERS*" "*RESTART-CLUSTERS*" - "WITH-SIMPLE-CONDITION-RESTARTS" - "CASE-FAILURE" "ECASE-FAILURE" "ETYPECASE-FAILURE" - "NAMESTRING-PARSE-ERROR" - "NAMESTRING-PARSE-ERROR-OFFSET" - "NO-NAMESTRING-ERROR" "NO-NATIVE-NAMESTRING-ERROR" - "MAKE-RESTART" "RESTART-ASSOCIATED-CONDITIONS" - "COERCE-TO-CONDITION" - - "ALLOCATE-CONDITION" - - "CONDITION-SLOT-VALUE" - "SET-CONDITION-SLOT-VALUE" - - "CONDITION-SLOT-ALLOCATION" - "CONDITION-SLOT-DOCUMENTATION" - "CONDITION-SLOT-INITARGS" - "CONDITION-SLOT-INITFORM" - "CONDITION-SLOT-INITFORM-P" - "CONDITION-SLOT-INITFUNCTION" - "CONDITION-SLOT-NAME" "CONDITION-SLOT-READERS" - "CONDITION-SLOT-WRITERS" - - "REDEFINITION-WARNING" - "REDEFINITION-WITH-DEFUN" - "REDEFINITION-WITH-DEFMACRO" - "REDEFINITION-WITH-DEFGENERIC" - "REDEFINITION-WITH-DEFMETHOD" - "UNINTERESTING-ORDINARY-FUNCTION-REDEFINITION-P" - "UNINTERESTING-GENERIC-FUNCTION-REDEFINITION-P" - "UNINTERESTING-METHOD-REDEFINITION-P" - "UNINTERESTING-REDEFINITION" - "REDEFINITION-WITH-DEFTRANSFORM" - - "DUBIOUS-ASTERISKS-AROUND-VARIABLE-NAME" - "ASTERISKS-AROUND-LEXICAL-VARIABLE-NAME" - "ASTERISKS-AROUND-CONSTANT-VARIABLE-NAME" - "&OPTIONAL-AND-&KEY-IN-LAMBDA-LIST" - "UNDEFINED-ALIEN-STYLE-WARNING" - "LEXICAL-ENVIRONMENT-TOO-COMPLEX" - "CHARACTER-DECODING-ERROR-IN-COMMENT" - "DEPRECATED-EVAL-WHEN-SITUATIONS" - "PROCLAMATION-MISMATCH" - "PROCLAMATION-MISMATCH-NAME" - "PROCLAMATION-MISMATCH-NEW" - "PROCLAMATION-MISMATCH-OLD" - "TYPE-PROCLAMATION-MISMATCH" - "TYPE-PROCLAMATION-MISMATCH-WARNING" - "TYPE-PROCLAMATION-MISMATCH-WARN" - "FTYPE-PROCLAMATION-MISMATCH" - "FTYPE-PROCLAMATION-MISMATCH-WARNING" - "FTYPE-PROCLAMATION-MISMATCH-WARN" - "FTYPE-PROCLAMATION-MISMATCH-ERROR" - - "!COLD-INIT" - "!GLOBALDB-COLD-INIT" - "!FOREIGN-COLD-INIT" - "!TYPE-CLASS-COLD-INIT" "!TYPEDEFS-COLD-INIT" - "!ALIEN-TYPE-COLD-INIT" "!CLASSES-COLD-INIT" - "!DEADLINE-COLD-INIT" - "!EARLY-TYPE-COLD-INIT" "!LATE-TYPE-COLD-INIT" - "!FIXUP-TYPE-COLD-INIT" "!TARGET-TYPE-COLD-INIT" - "!RANDOM-COLD-INIT" "!READER-COLD-INIT" - "!PATHNAME-COLD-INIT" "!DEBUG-INFO-COLD-INIT" - "!TYPECHECKFUNS-COLD-INIT" "!LOADER-COLD-INIT" - "!EXHAUST-COLD-INIT" "!PACKAGE-COLD-INIT" - "!POLICY-COLD-INIT-OR-RESANIFY" - "!VM-TYPE-COLD-INIT" "!BACKQ-COLD-INIT" - "!SHARPM-COLD-INIT" "!EARLY-PROCLAIM-COLD-INIT" - "!LATE-PROCLAIM-COLD-INIT" "!CLASS-FINALIZE" - "!CONSTANTP-COLD-INIT" "!CONSTANTP2-COLD-INIT" - "!WORLD-LOCK-COLD-INIT" - - "FLOAT-COLD-INIT-OR-REINIT" - "GC-REINIT" - "TIME-REINIT" - "SIGNAL-COLD-INIT-OR-REINIT" - "STREAM-COLD-INIT-OR-RESET" - - ;; Cleanups to run before saving a core - "FLOAT-DEINIT" - "FOREIGN-DEINIT" - "PROFILE-DEINIT" - - ;; Note: These are out of lexicographical order - ;; because in CMU CL they were defined as - ;; internal symbols in package "CL" imported - ;; into package "C", as opposed to what we're - ;; doing here, defining them as external symbols - ;; in a package which is used by both "SB-C" and - ;; "SB-IMPL". (SBCL's "SB-C" is directly - ;; analogous to CMU CL's "C"; and for this - ;; purpose, SBCL's "SB-IMPL" is analogous to CMU - ;; CL's "CL".) As far as I know there's nothing - ;; special about them, so they could be merged - ;; into the same order as everything else in the - ;; in this package. -- WHN 19990911 - "STRING>=*" "STRING>*" "STRING=*" "STRING<=*" - "STRING<*" "STRING/=*" "%SVSET" - "%SP-STRING-COMPARE" "%SETNTH" "%SETELT" - "%SET-ROW-MAJOR-AREF" "%SET-FILL-POINTER" - "%SET-FDEFINITION" "%SCHARSET" - "%RPLACD" "%RPLACA" "%PUT" "%CHARSET" - "WITH-SIMPLE-OUTPUT-TO-STRING")) - - #s(sb-cold:package-data - :name "SB-THREAD" - :use ("CL" "SB-ALIEN" "SB-INT" "SB-SYS" "SB-KERNEL") - :doc "public (but low-level): native thread support" - :export ("*CURRENT-THREAD*" - "DESTROY-THREAD" - "INTERRUPT-THREAD" - "INTERRUPT-THREAD-ERROR" - "INTERRUPT-THREAD-ERROR-THREAD" - "RETURN-FROM-THREAD" - "ABORT-THREAD" - "MAIN-THREAD-P" - "MAIN-THREAD" - "JOIN-THREAD" - "JOIN-THREAD-ERROR" - "JOIN-THREAD-ERROR-THREAD" - "LIST-ALL-THREADS" - "MAKE-THREAD" - "SYMBOL-VALUE-IN-THREAD" - "SYMBOL-VALUE-IN-THREAD-ERROR" - "TERMINATE-THREAD" - "THREAD" - "THREAD-DEADLOCK" - "THREAD-DEADLOCK-CYCLE" - "THREAD-ERROR" - "THREAD-ERROR-THREAD" - "THREAD-ALIVE-P" - "THREAD-EPHEMERAL-P" - "THREAD-NAME" - "THREAD-OS-TID" - "THREAD-YIELD" - "FOREIGN-THREAD" - #+(and sb-safepoint-strictly (not win32)) - "SIGNAL-HANDLING-THREAD" - ;; Memory barrier - "BARRIER" - ;; Mutexes - "GET-MUTEX" - "GRAB-MUTEX" - "HOLDING-MUTEX-P" - "MAKE-MUTEX" - "MUTEX" - "MUTEX-NAME" - "MUTEX-OWNER" - "MUTEX-VALUE" - "RELEASE-MUTEX" - "WITH-MUTEX" - "WITH-RECURSIVE-LOCK" - ;; Condition variables - "CONDITION-BROADCAST" - "CONDITION-NOTIFY" - "CONDITION-WAIT" - "MAKE-WAITQUEUE" - "WAITQUEUE" - "WAITQUEUE-NAME" - ;; Sessions - "MAKE-LISTENER-THREAD" - "RELEASE-FOREGROUND" - "WITH-NEW-SESSION" - ;; Semaphores - "MAKE-SEMAPHORE" - "SEMAPHORE" - "SEMAPHORE-NAME" - "SEMAPHORE-COUNT" - "SIGNAL-SEMAPHORE" - "TRY-SEMAPHORE" - "WAIT-ON-SEMAPHORE" - ;; Semaphore notification objects - "CLEAR-SEMAPHORE-NOTIFICATION" - "MAKE-SEMAPHORE-NOTIFICATION" - "SEMAPHORE-NOTIFICATION" - "SEMAPHORE-NOTIFICATION-STATUS")) - - #s(sb-cold:package-data - :name "SB-LOOP" - :doc "private: implementation details of LOOP" - :use ("CL" "SB-INT" "SB-KERNEL") - :export ()) - - #s(sb-cold:package-data - :name "SB-MOP" - :doc - "public: the MetaObject Protocol interface, as defined by -The Art of the Metaobject Protocol, by Kiczales, des Rivieres and Bobrow: -ISBN 0-262-61074-4, with exceptions as noted in the User Manual." - :use ("CL") - :reexport ("ADD-METHOD" - "ALLOCATE-INSTANCE" - "CLASS-NAME" "COMPUTE-APPLICABLE-METHODS" - "ENSURE-GENERIC-FUNCTION" "MAKE-INSTANCE" - "METHOD-QUALIFIERS" "REMOVE-METHOD" - "BUILT-IN-CLASS" "CLASS" - "FUNCTION" "GENERIC-FUNCTION" - "METHOD" "METHOD-COMBINATION" - "STANDARD-CLASS" "STANDARD-GENERIC-FUNCTION" - "STANDARD-METHOD" "STANDARD-OBJECT" "T") - :export ("ADD-DEPENDENT" - "ADD-DIRECT-METHOD" - "ADD-DIRECT-SUBCLASS" - "CLASS-DEFAULT-INITARGS" - "CLASS-DIRECT-DEFAULT-INITARGS" - "CLASS-DIRECT-SLOTS" - "CLASS-DIRECT-SUBCLASSES" - "CLASS-DIRECT-SUPERCLASSES" - "CLASS-FINALIZED-P" - "CLASS-PRECEDENCE-LIST" - "CLASS-PROTOTYPE" - "CLASS-SLOTS" - "COMPUTE-APPLICABLE-METHODS-USING-CLASSES" - "COMPUTE-CLASS-PRECEDENCE-LIST" - "COMPUTE-DEFAULT-INITARGS" - "COMPUTE-DISCRIMINATING-FUNCTION" - "COMPUTE-EFFECTIVE-METHOD" - "COMPUTE-EFFECTIVE-SLOT-DEFINITION" - "COMPUTE-SLOTS" - "DIRECT-SLOT-DEFINITION" - "DIRECT-SLOT-DEFINITION-CLASS" - "EFFECTIVE-SLOT-DEFINITION" - "EFFECTIVE-SLOT-DEFINITION-CLASS" - "ENSURE-CLASS" - "ENSURE-CLASS-USING-CLASS" - "ENSURE-GENERIC-FUNCTION-USING-CLASS" - "EQL-SPECIALIZER" - "EQL-SPECIALIZER-OBJECT" - "EXTRACT-LAMBDA-LIST" - "EXTRACT-SPECIALIZER-NAMES" - "FINALIZE-INHERITANCE" - "FIND-METHOD-COMBINATION" - "FORWARD-REFERENCED-CLASS" - "FUNCALLABLE-STANDARD-CLASS" - "FUNCALLABLE-STANDARD-INSTANCE-ACCESS" - "FUNCALLABLE-STANDARD-OBJECT" - "GENERIC-FUNCTION-ARGUMENT-PRECEDENCE-ORDER" - "GENERIC-FUNCTION-DECLARATIONS" - "GENERIC-FUNCTION-LAMBDA-LIST" - "GENERIC-FUNCTION-METHOD-CLASS" - "GENERIC-FUNCTION-METHOD-COMBINATION" - "GENERIC-FUNCTION-METHODS" - "GENERIC-FUNCTION-NAME" - "INTERN-EQL-SPECIALIZER" - "MAKE-METHOD-LAMBDA" - "MAP-DEPENDENTS" - "METAOBJECT" - "METHOD-FUNCTION" - "METHOD-GENERIC-FUNCTION" - "METHOD-LAMBDA-LIST" - "METHOD-SPECIALIZERS" - "ACCESSOR-METHOD-SLOT-DEFINITION" - "READER-METHOD-CLASS" - "REMOVE-DEPENDENT" - "REMOVE-DIRECT-METHOD" - "REMOVE-DIRECT-SUBCLASS" - "SET-FUNCALLABLE-INSTANCE-FUNCTION" - "SLOT-BOUNDP-USING-CLASS" - "SLOT-DEFINITION" - "SLOT-DEFINITION-ALLOCATION" - "SLOT-DEFINITION-INITARGS" - "SLOT-DEFINITION-INITFORM" - "SLOT-DEFINITION-INITFUNCTION" - "SLOT-DEFINITION-LOCATION" - "SLOT-DEFINITION-NAME" - "SLOT-DEFINITION-READERS" - "SLOT-DEFINITION-WRITERS" - "SLOT-DEFINITION-TYPE" - "SLOT-MAKUNBOUND-USING-CLASS" - "SLOT-VALUE-USING-CLASS" - "SPECIALIZER" - "SPECIALIZER-DIRECT-GENERIC-FUNCTIONS" - "SPECIALIZER-DIRECT-METHODS" - "STANDARD-ACCESSOR-METHOD" - "STANDARD-DIRECT-SLOT-DEFINITION" - "STANDARD-EFFECTIVE-SLOT-DEFINITION" - "STANDARD-INSTANCE-ACCESS" - "STANDARD-READER-METHOD" - "STANDARD-SLOT-DEFINITION" - "STANDARD-WRITER-METHOD" - "UPDATE-DEPENDENT" - "VALIDATE-SUPERCLASS" - "WRITER-METHOD-CLASS")) - - #s(sb-cold:package-data - :name "SB-REGALLOC" - :doc "private: implementation of the compiler's register allocator" - :use ("CL" "SB-ALIEN-INTERNALS" "SB-ALIEN" "SB-ASSEM" "SB-BIGNUM" - #+sb-dyncount "SB-DYNCOUNT" "SB-EXT" "SB-FASL" "SB-INT" - "SB-KERNEL" "SB-SYS" - "SB-C") - :import-from (("SB-C" - "*LOOP-ANALYZE*" - "BLOCK-INFO" "BLOCK-LAST" "BLOCK-LOOP" "BLOCK-NEXT" - "CLEAR-BIT-VECTOR" "COMPONENT-HEAD" "COMPONENT-TAIL" - "DEFEVENT" "DELETE-VOP" "DO-IR2-BLOCKS" "DO-LIVE-TNS" - "EMIT-LOAD-TEMPLATE" "EVENT" "FIND-IN" - "FINITE-SB" "FINITE-SB-ALWAYS-LIVE" - "FINITE-SB-WIRED-MAP" "FINITE-SB-CONFLICTS" - "FINITE-SB-CURRENT-SIZE" "FINITE-SB-LAST-BLOCK-COUNT" - "FINITE-SB-LAST-OFFSET" "FINITE-SB-LIVE-TNS" - "FINITE-SB-SIZE-ALIGNMENT" "FINITE-SB-SIZE-INCREMENT" - "GET-OPERAND-INFO" "GLOBAL-CONFLICTS-BLOCK" - "GLOBAL-CONFLICTS-CONFLICTS" "GLOBAL-CONFLICTS-KIND" - "GLOBAL-CONFLICTS-NEXT-TNWISE" "GLOBAL-CONFLICTS-NUMBER" - "GLOBAL-CONFLICTS-NEXT-BLOCKWISE" "GLOBAL-CONFLICTS-TN" - "IR2-BLOCK" "IR2-BLOCK-COUNT" "IR2-BLOCK-GLOBAL-TNS" - "IR2-BLOCK-LAST-VOP" "IR2-BLOCK-LIVE-IN" - "IR2-BLOCK-LOCAL-TN-COUNT" "IR2-BLOCK-LOCAL-TNS" - "IR2-BLOCK-NEXT" "IR2-BLOCK-NUMBER" "IR2-BLOCK-PREV" - "IR2-BLOCK-START-VOP" "IR2-COMPONENT" - "IR2-COMPONENT-GLOBAL-TN-COUNTER" - "IR2-COMPONENT-NORMAL-TNS" "IR2-COMPONENT-RESTRICTED-TNS" - "IR2-COMPONENT-SPILLED-TNS" "IR2-COMPONENT-SPILLED-VOPS" - "IR2-COMPONENT-WIRED-TNS" - "LAMBDA-PARENT" "LEXENV-LAMBDA" "LISTIFY-RESTRICTIONS" - "LOCAL-TN-BIT-VECTOR" "LOCAL-TN-COUNT" "LOCAL-TN-LIMIT" - "LOCAL-TN-NUMBER" "LOCAL-TN-VECTOR" - "LOOP-DEPTH" "MAKE-TN" "MOVE-OPERAND" "NODE" "NODE-LEXENV" - "OPERAND-PARSE-NAME" "POSITION-IN" - "PRIMITIVE-TYPE-SCS" "PRINT-TN-GUTS" - "SB-KIND" "SB-SIZE" - "SC-LOCATIONS" "MAKE-SC-LOCATIONS" "SC-OFFSET-TO-SC-LOCATIONS" - "SC-LOCATIONS-COUNT" "SC-LOCATIONS-FIRST" "SC-LOCATIONS-MEMBER" - "DO-SC-LOCATIONS" - "SC-ALIGNMENT" "SC-ALLOWED-BY-PRIMITIVE-TYPE" - "SC-ALTERNATE-SCS" "SC-CONSTANT-SCS" "SC-ELEMENT-SIZE" - "SC-LOCATIONS" "SC-MOVE-FUNS" "SC-RESERVE-LOCATIONS" - "SC-SAVE-P" "SC-VECTOR" - "SET-BIT-VECTOR" - "TEMPLATE-NAME" - "TN" "TN-COST" "TN-GLOBAL-CONFLICTS" "TN-KIND" "TN-LEAF" - "TN-LOCAL" "TN-LOCAL-CONFLICTS" "TN-LOCAL-NUMBER" - "TN-NEXT" "TN-NUMBER" "TN-PRIMITIVE-TYPE" - "TN-READS" "TN-SAVE-TN" "TN-VERTEX" "TN-WRITES" - "TNS-CONFLICT" "TNS-CONFLICT-GLOBAL-GLOBAL" - "TNS-CONFLICT-LOCAL-GLOBAL" - "VOP" "VOP-ARGS" "VOP-INFO" "VOP-INFO-ARG-LOAD-SCS" - "VOP-INFO-MOVE-ARGS" "VOP-INFO-NAME" - "VOP-INFO-RESULT-LOAD-SCS" "VOP-INFO-SAVE-P" - "VOP-NODE" - "VOP-PARSE-OR-LOSE" "VOP-PARSE-TEMPS" "VOP-PREV" - "VOP-REFS" "VOP-RESULTS" "VOP-SAVE-SET" "VOP-TEMPS")) - :export ("PACK" "TARGET-IF-DESIRABLE" "*REGISTER-ALLOCATION-METHOD*" - "*PACK-ITERATIONS*" - "*PACK-ASSIGN-COSTS*" "*PACK-OPTIMIZE-SAVES*" - "*TN-WRITE-COST*" "*TN-LOOP-DEPTH-MULTIPLIER*")) - - #s(sb-cold:package-data - :name "SB-PCL" - :doc - "semi-public: This package includes useful meta-object protocol -extensions, but even they are not guaranteed to be present in later -versions of SBCL, and the other stuff in here is definitely not -guaranteed to be present in later versions of SBCL. Use of this -package is deprecated in favour of SB-MOP." - :use ("CL" "SB-MOP" "SB-INT" "SB-EXT" "SB-WALKER" "SB-KERNEL") - ;; experimental SBCL-only (for now) symbols - :export ("SYSTEM-CLASS" - - "MAKE-METHOD-LAMBDA-USING-SPECIALIZERS" - "MAKE-METHOD-SPECIALIZERS-FORM" - - "SPECIALIZER-TYPE-SPECIFIER" - "MAKE-SPECIALIZER-FORM-USING-CLASS" - "PARSE-SPECIALIZER-USING-CLASS" - "UNPARSE-SPECIALIZER-USING-CLASS" - - "+SLOT-UNBOUND+" - - "ENSURE-CLASS-FINALIZED" - - "ILLEGAL-CLASS-NAME-ERROR" - "CLASS-NOT-FOUND-ERROR" - "SPECIALIZER-NAME-SYNTAX-ERROR") - ;; FIXME: After a little while, these reexports can probably go - ;; away, as they're superseded by the use of SB-MOP as the - ;; publically-accessible package. - :reexport ( ;; CL symbols - "ADD-METHOD" - "ALLOCATE-INSTANCE" - "CLASS-NAME" "COMPUTE-APPLICABLE-METHODS" - "ENSURE-GENERIC-FUNCTION" "MAKE-INSTANCE" - "METHOD-QUALIFIERS" "REMOVE-METHOD" - ;; MOP symbols - "ADD-DEPENDENT" - "ADD-DIRECT-METHOD" - "ADD-DIRECT-SUBCLASS" - "CLASS-DEFAULT-INITARGS" - "CLASS-DIRECT-DEFAULT-INITARGS" - "CLASS-DIRECT-SLOTS" - "CLASS-DIRECT-SUBCLASSES" - "CLASS-DIRECT-SUPERCLASSES" - "CLASS-FINALIZED-P" - "CLASS-PRECEDENCE-LIST" - "CLASS-PROTOTYPE" - "CLASS-SLOTS" - "COMPUTE-APPLICABLE-METHODS-USING-CLASSES" - "COMPUTE-CLASS-PRECEDENCE-LIST" - "COMPUTE-DEFAULT-INITARGS" - "COMPUTE-DISCRIMINATING-FUNCTION" - "COMPUTE-EFFECTIVE-METHOD" - "COMPUTE-EFFECTIVE-SLOT-DEFINITION" - "COMPUTE-SLOTS" - "DIRECT-SLOT-DEFINITION" - "DIRECT-SLOT-DEFINITION-CLASS" - "EFFECTIVE-SLOT-DEFINITION" - "EFFECTIVE-SLOT-DEFINITION-CLASS" - "ENSURE-CLASS" - "ENSURE-CLASS-USING-CLASS" - "ENSURE-GENERIC-FUNCTION-USING-CLASS" - "EQL-SPECIALIZER" - "EQL-SPECIALIZER-OBJECT" - "EXTRACT-LAMBDA-LIST" - "EXTRACT-SPECIALIZER-NAMES" - "FINALIZE-INHERITANCE" - "FIND-METHOD-COMBINATION" - "FORWARD-REFERENCED-CLASS" - "FUNCALLABLE-STANDARD-CLASS" - "FUNCALLABLE-STANDARD-INSTANCE-ACCESS" - "FUNCALLABLE-STANDARD-OBJECT" - "GENERIC-FUNCTION-ARGUMENT-PRECEDENCE-ORDER" - "GENERIC-FUNCTION-DECLARATIONS" - "GENERIC-FUNCTION-LAMBDA-LIST" - "GENERIC-FUNCTION-METHOD-CLASS" - "GENERIC-FUNCTION-METHOD-COMBINATION" - "GENERIC-FUNCTION-METHODS" - "GENERIC-FUNCTION-NAME" - "INTERN-EQL-SPECIALIZER" - "MAKE-METHOD-LAMBDA" - "MAP-DEPENDENTS" - "METHOD-FUNCTION" - "METHOD-GENERIC-FUNCTION" - "METHOD-LAMBDA-LIST" - "METHOD-SPECIALIZERS" - "ACCESSOR-METHOD-SLOT-DEFINITION" - "READER-METHOD-CLASS" - "REMOVE-DEPENDENT" - "REMOVE-DIRECT-METHOD" - "REMOVE-DIRECT-SUBCLASS" - "SET-FUNCALLABLE-INSTANCE-FUNCTION" - "SLOT-BOUNDP-USING-CLASS" - "SLOT-DEFINITION" - "SLOT-DEFINITION-ALLOCATION" - "SLOT-DEFINITION-INITARGS" - "SLOT-DEFINITION-INITFORM" - "SLOT-DEFINITION-INITFUNCTION" - "SLOT-DEFINITION-LOCATION" - "SLOT-DEFINITION-NAME" - "SLOT-DEFINITION-READERS" - "SLOT-DEFINITION-WRITERS" - "SLOT-DEFINITION-TYPE" - "SLOT-MAKUNBOUND-USING-CLASS" - "SLOT-VALUE-USING-CLASS" - "SPECIALIZER" - "SPECIALIZER-DIRECT-GENERIC-FUNCTIONS" - "SPECIALIZER-DIRECT-METHODS" - "STANDARD-ACCESSOR-METHOD" - "STANDARD-DIRECT-SLOT-DEFINITION" - "STANDARD-EFFECTIVE-SLOT-DEFINITION" - "STANDARD-INSTANCE-ACCESS" - "STANDARD-READER-METHOD" - "STANDARD-SLOT-DEFINITION" - "STANDARD-WRITER-METHOD" - "UPDATE-DEPENDENT" - "VALIDATE-SUPERCLASS" - "WRITER-METHOD-CLASS")) - - #s(sb-cold:package-data - :name "SB-PRETTY" - :doc "private: implementation of pretty-printing" - :use ("CL" "SB-EXT" "SB-INT" "SB-KERNEL") - :export ("OUTPUT-PRETTY-OBJECT" - "PRETTY-STREAM" "PRETTY-STREAM-P" - "PPRINT-DISPATCH-TABLE" - "*PPRINT-QUOTE-WITH-SYNTACTIC-SUGAR*" - "!PPRINT-COLD-INIT")) - - #s(sb-cold:package-data - :name "SB-PROFILE" - :doc "public: the interface to the profiler" - :use ("CL" "SB-EXT" "SB-INT" "SB-KERNEL") - :export ("PROFILE" "REPORT" "RESET" "UNPROFILE")) - - #s(sb-cold:package-data - :name "SB-SEQUENCE" - :doc "semi-public: implements something which might eventually -be submitted as a CDR" - :use () - :export ("PROTOCOL-UNIMPLEMENTED" - "PROTOCOL-UNIMPLEMENTED-OPERATION" - - "DOSEQUENCE" - - "MAKE-SEQUENCE-ITERATOR" "MAKE-SIMPLE-SEQUENCE-ITERATOR" - - "ITERATOR-STEP" "ITERATOR-ENDP" "ITERATOR-ELEMENT" - "ITERATOR-INDEX" "ITERATOR-COPY" - - "WITH-SEQUENCE-ITERATOR" "WITH-SEQUENCE-ITERATOR-FUNCTIONS" - - "CANONIZE-TEST" "CANONIZE-KEY" - - "EMPTYP" "LENGTH" "ELT" - "MAKE-SEQUENCE-LIKE" "ADJUST-SEQUENCE" - - "MAP" - "COUNT" "COUNT-IF" "COUNT-IF-NOT" - "FIND" "FIND-IF" "FIND-IF-NOT" - "POSITION" "POSITION-IF" "POSITION-IF-NOT" - "SUBSEQ" "COPY-SEQ" "FILL" - "NSUBSTITUTE" "NSUBSTITUTE-IF" "NSUBSTITUTE-IF-NOT" - "SUBSTITUTE" "SUBSTITUTE-IF" "SUBSTITUTE-IF-NOT" - "REPLACE" "REVERSE" "NREVERSE" "CONCATENATE" "REDUCE" - "MISMATCH" "SEARCH" - "DELETE" "DELETE-IF" "DELETE-IF-NOT" - "REMOVE" "REMOVE-IF" "REMOVE-IF-NOT" - "DELETE-DUPLICATES" "REMOVE-DUPLICATES" - - "SORT" "STABLE-SORT" "MERGE")) - - #s(sb-cold:package-data - :name "SB-SYS" - :doc - "private: In theory, this \"contains functions and information -necessary for system interfacing\" (said cmu-user.tex at the time -of the SBCL code fork). That probably was and is a good idea, but in -practice, the distinctions between this package and SB-KERNEL -and even SB-VM seem to have become somewhat blurred over the years. -Some anomalies (e.g. FIND-IF-IN-CLOSURE being in SB-SYS instead of -SB-KERNEL) have been undone, but probably more remain." - :use ("CL" "SB-EXT" "SB-INT") - :export (;; FIXME: %PRIMITIVE shouldn't be here. (I now know that %SYS - ;; is for OS-dependent stuff. %PRIMITIVE should probably be in - ;; SB-KERNEL.) - "%PRIMITIVE" - "%STANDARD-CHAR-P" - "*EXIT-ERROR-HANDLER*" - "*EXIT-IN-PROCESS*" - "*ALLOW-WITH-INTERRUPTS*" - "*INTERRUPTS-ENABLED*" - "*INTERRUPT-PENDING*" - #+sb-thruption "*THRUPTION-PENDING*" - "*LINKAGE-INFO*" - "*LONG-SITE-NAME*" "*SHORT-SITE-NAME*" - "*MACHINE-VERSION*" - "*PERIODIC-POLLING-FUNCTION*" - "*PERIODIC-POLLING-PERIOD*" - "*RUNTIME-DLHANDLE*" - "*SHARED-OBJECTS*" - #-linkage-table "*STATIC-FOREIGN-SYMBOLS*" - "*STDERR*" "*STDIN*" - "*STDOUT*" - "*TTY*" - "ADD-FD-HANDLER" - "ALLOCATE-SYSTEM-MEMORY" - "ALLOW-WITH-INTERRUPTS" - "BEEP" - "BREAKPOINT-ERROR" - "CANCEL-DEADLINE" - "CLOSE-SHARED-OBJECTS" - "DEADLINE-TIMEOUT" - "DEALLOCATE-SYSTEM-MEMORY" - "DECODE-TIMEOUT" - "DECODE-INTERNAL-TIME" - "DEFAULT-INTERRUPT" - "DEFER-DEADLINE" - "DYNAMIC-FOREIGN-SYMBOLS-P" - "DLOPEN-OR-LOSE" - "ENABLE-INTERRUPT" - "ENSURE-DYNAMIC-FOREIGN-SYMBOL-ADDRESS" - "EXTERN-ALIEN-NAME" - "EXIT-CODE" - "FD-STREAM" "FD-STREAM-FD" "FD-STREAM-P" - "FIND-DYNAMIC-FOREIGN-SYMBOL-ADDRESS" - "FIND-FOREIGN-SYMBOL-ADDRESS" - "FIND-FOREIGN-SYMBOL-IN-TABLE" - "FOREIGN-SYMBOL-SAP" - "FOREIGN-SYMBOL-ADDRESS" - "FOREIGN-SYMBOL-DATAREF-SAP" - "GET-MACHINE-VERSION" "GET-PAGE-SIZE" "GET-SYSTEM-INFO" - "IGNORE-INTERRUPT" - "IN-INTERRUPTION" - "INTERACTIVE-INTERRUPT" - "INT-SAP" - "INVALIDATE-DESCRIPTOR" - "INVOKE-INTERRUPTION" - "IO-TIMEOUT" - "LIST-DYNAMIC-FOREIGN-SYMBOLS" - "MACRO" "MAKE-FD-STREAM" - "MEMORY-FAULT-ERROR" - "MEMMOVE" - "NLX-PROTECT" - "OS-EXIT" - "OS-COLD-INIT-OR-REINIT" "OS-DEINIT" - "OS-CONTEXT-T" "OUTPUT-RAW-BYTES" - "READ-CYCLE-COUNTER" "ELAPSED-CYCLES" - "READ-N-BYTES" - "REMOVE-FD-HANDLER" - "REOPEN-SHARED-OBJECTS" - "SAP+" "SAP-" - "SAP-FOREIGN-SYMBOL" - "SAP-INT" - "SAP-REF-16" "SAP-REF-32" "SAP-REF-64" "SAP-REF-WORD" - "SAP-REF-8" - "SAP-REF-DOUBLE" "SAP-REF-LISPOBJ" "SAP-REF-LONG" - "SAP-REF-SAP" "SAP-REF-SINGLE" - "SAP<" "SAP<=" "SAP=" "SAP>" "SAP>=" - "SCRUB-CONTROL-STACK" "SERVE-ALL-EVENTS" - "SIGNAL-DEADLINE" - "SERVE-EVENT" - "SIGNED-SAP-REF-16" "SIGNED-SAP-REF-32" - "SIGNED-SAP-REF-64" "SIGNED-SAP-REF-WORD" "SIGNED-SAP-REF-8" - "STRUCTURE!OBJECT" - "SYSTEM-AREA-POINTER" "SYSTEM-AREA-POINTER-P" - "SYSTEM-CONDITION" "SYSTEM-CONDITION-ADDRESS" - "SYSTEM-CONDITION-CONTEXT" - "REINIT-INTERNAL-REAL-TIME" - "SYSTEM-INTERNAL-RUN-TIME" - "UNDEFINED-FOREIGN-SYMBOLS-P" - "UPDATE-LINKAGE-TABLE" "VECTOR-SAP" - "WAIT-UNTIL-FD-USABLE" - "WITH-DEADLINE" - "WITH-FD-HANDLER" - "WITH-INTERRUPTS" "WITH-LOCAL-INTERRUPTS" - "WITH-PINNED-OBJECTS" "WITHOUT-GCING" - "WITHOUT-INTERRUPTS" - "WITH-INTERRUPT-BINDINGS")) - - #s(sb-cold:package-data - :name "SB-UNICODE" - :doc "public: algorithms for Unicode data" - :use ("CL" "SB-INT") - :export ("GENERAL-CATEGORY" - "BIDI-CLASS" - "COMBINING-CLASS" - "DECIMAL-VALUE" - "DIGIT-VALUE" - "NUMERIC-VALUE" - "MIRRORED-P" - "BIDI-MIRRORING-GLYPH" - "AGE" - "HANGUL-SYLLABLE-TYPE" - "EAST-ASIAN-WIDTH" - "SCRIPT" - "CHAR-BLOCK" - "UNICODE-1-NAME" - "LINE-BREAK-CLASS" - "PROPLIST-P" - "UPPERCASE-P" - "LOWERCASE-P" - "CASED-P" - "CASE-IGNORABLE-P" - "ALPHABETIC-P" - "IDEOGRAPHIC-P" - "MATH-P" - "WHITESPACE-P" - "HEX-DIGIT-P" - "SOFT-DOTTED-P" - "DEFAULT-IGNORABLE-P" - "NORMALIZE-STRING" - "NORMALIZED-P" - "UPPERCASE" - "LOWERCASE" - "TITLECASE" - "CASEFOLD" - "GRAPHEME-BREAK-CLASS" - "WORD-BREAK-CLASS" - "SENTENCE-BREAK-CLASS" - "GRAPHEMES" - "WORDS" - "SENTENCES" - "LINES" - "UNICODE=" - "UNICODE-EQUAL" - "UNICODE<" - "UNICODE<=" - "UNICODE>" - "UNICODE>=" - "CONFUSABLE-P")) - - #s(sb-cold:package-data - :name "SB-UNIX" - :doc - "private: a wrapper layer for SBCL itself to use when talking -with an underlying Unix-y operating system. -This was a public package in CMU CL, but that was different. -CMU CL's UNIX package tried to provide a comprehensive, -stable Unix interface suitable for the end user. -This package only tries to implement what happens to be -needed by the current implementation of SBCL, and makes -no guarantees of interface stability." - :use ("CL" "SB-ALIEN" "SB-EXT" "SB-INT" "SB-SYS") - :reexport ("OFF-T" - "SIZE-T") - :export ( ;; wrappers around Unix stuff to give just what Lisp needs - "NANOSLEEP" - "UID-USERNAME" - "UID-HOMEDIR" - "USER-HOMEDIR" - "WITH-RESTARTED-SYSCALL" - "SB-MKSTEMP" - "UNIX-OFFSET" - "FD-TYPE" - - ;; Most of this is random detritus worthy of deletion, - ;; and the ordering is not alphabetical or anything sane. - - ;; stuff with a one-to-one mapping to Unix constructs - "DEV-T" - "F_OK" "GID-T" - "INO-T" "UNIX-ACCESS" "UNIX-SETITIMER" "UNIX-GETITIMER" - "L_INCR" "L_SET" "L_XTND" "O_APPEND" "O_CREAT" "O_NOCTTY" "O_EXCL" - "O_RDONLY" "O_RDWR" "O_TRUNC" "O_WRONLY" "POSIX-GETCWD" - "POSIX-GETCWD/" - "RU-IDRSS" "RU-INBLOCK" "RU-ISRSS" "RU-IXRSS" - "RU-MAJFLT" "RU-MAXRSS" "RU-MINFLT" "RU-MSGRCV" "RU-MSGSND" - "RU-NIVCSW" "RU-NSIGNALS" "RU-NSWAP" "RU-NVCSW" "RU-OUBLOCK" - "RU-STIME" "RU-UTIME" "RUSAGE_CHILDREN" "RUSAGE_SELF" - "R_OK" "S-IFDIR" "S-IFLNK" "S-IFMT" - "S-IFREG" - "ST-ATIME" "ST-BLKSIZE" "ST-BLOCKS" - "ST-CTIME" "ST-DEV" "ST-GID" "ST-MODE" "ST-MTIME" "ST-NLINK" - "ST-RDEV" "ST-SIZE" "ST-UID" "STAT" "TIME-T" - "TIMEVAL" "TIMEZONE" - "TIOCGPGRP" - "TV-SEC" "TV-USEC" - "TZ-DSTTIME" "TZ-MINUTESWEST" "UID-T" "UNIX-CLOSE" - "UNIX-CLOSEDIR" "UNIX-DIRENT-NAME" "UNIX-DUP" - "UNIX-FILE-MODE" "UNIX-FSTAT" - "UNIX-GETHOSTNAME" "UNIX-GETPID" "UNIX-GETRUSAGE" - "UNIX-GETTIMEOFDAY" "UNIX-GETUID" "UNIX-GID" - "UNIX-EXIT" - "UNIX-IOCTL" - "UNIX-ISATTY" "UNIX-LSEEK" "UNIX-LSTAT" "UNIX-MKDIR" - "UNIX-OPEN" "UNIX-OPENDIR" "UNIX-PATHNAME" "UNIX-PID" - "UNIX-PIPE" "UNIX-POLL" "UNIX-SIMPLE-POLL" - "UNIX-READ" "UNIX-READDIR" "UNIX-READLINK" "UNIX-REALPATH" - "UNIX-RENAME" "UNIX-SELECT" "UNIX-STAT" "UNIX-UID" - "UNIX-UNLINK" "UNIX-WRITE" - "WCONTINUED" "WNOHANG" "WUNTRACED" - "W_OK" "X_OK" - - ;; signals - "SIGALRM" "SIGBUS" "SIGCHLD" "SIGCONT" "SIGEMT" "SIGFPE" - "SIGHUP" "SIGILL" "SIGINT" "SIGIO" "SIGKILL" - "SIGPIPE" "SIGPROF" "SIGQUIT" "SIGSEGV" "SIGSTOP" "SIGSYS" - "SIGTERM" "SIGTRAP" "SIGTSTP" "SIGTTIN" "SIGTTOU" "SIGURG" - "SIGUSR1" "SIGUSR2" "SIGVTALRM" "SIGWINCH" - "SIGXCPU" "SIGXFSZ" - - ;; errors - "EAGAIN" "EBADF" "EEXIST" "EINTR" "EIO" "ELOOP" "ENOENT" - "EPIPE" "ESPIPE" "EWOULDBLOCK" - - "POLLFD" "POLLIN" "POLLOUT" "POLLHUP" "POLLNVAL" "POLLERR" - "FD" "EVENTS" "REVENTS" - "FD-ISSET" "FD-SET" "UNIX-FAST-SELECT" - "UNIX-KILL" "CODESET" - "FD-ZERO" "FD-CLR" - "FD-SETSIZE" "UNIX-FAST-GETRUSAGE" - "UNIX-KILLPG")) - - #s(sb-cold:package-data - :name "SB-VM" - :doc - "internal: the default place to hide information about the hardware and data -structure representations" - :use ("CL" "SB-ALIEN" "SB-ALIEN-INTERNALS" "SB-ASSEM" "SB-C" - "SB-EXT" "SB-FASL" "SB-INT" "SB-KERNEL" "SB-SYS" "SB-UNIX") - :reexport ("WORD") - :export ("*ALLOC-SIGNAL*" - "*PRIMITIVE-OBJECTS*" - "+HIGHEST-NORMAL-GENERATION+" - "+PSEUDO-STATIC-GENERATION+" - "+VECTOR-SHAREABLE+" - "+VECTOR-SHAREABLE-NONSTD+" - "%COMPILER-BARRIER" "%DATA-DEPENDENCY-BARRIER" - "%MEMORY-BARRIER" "%READ-BARRIER" "%WRITE-BARRIER" - "AFTER-BREAKPOINT-TRAP" - #+(and gencgc sparc) "ALLOCATION-TRAP" - "ANY-REG-SC-NUMBER" "ARRAY-DATA-SLOT" "ARRAY-DIMENSIONS-OFFSET" - "ARRAY-DISPLACED-P-SLOT" "ARRAY-DISPLACEMENT-SLOT" - "ARRAY-DISPLACED-FROM-SLOT" - "ARRAY-ELEMENTS-SLOT" "ARRAY-FILL-POINTER-P-SLOT" - "ARRAY-FILL-POINTER-SLOT" "ATOMIC-FLAG" - "CHARACTER-REG-SC-NUMBER" - "CHARACTER-STACK-SC-NUMBER" "CHARACTER-WIDETAG" - "BIGNUM-DIGITS-OFFSET" "BIGNUM-WIDETAG" "BINDING-SIZE" - "BINDING-SYMBOL-SLOT" "BINDING-VALUE-SLOT" "BREAKPOINT-TRAP" - "N-BYTE-BITS" "BYTE-REG-SC-NUMBER" - "CATCH-BLOCK-CODE-SLOT" - "CATCH-BLOCK-CFP-SLOT" "CATCH-BLOCK-UWP-SLOT" - "CATCH-BLOCK-ENTRY-PC-SLOT" "CATCH-BLOCK-PREVIOUS-CATCH-SLOT" - "CATCH-BLOCK-SC-NUMBER" "CATCH-BLOCK-SIZE" - "CATCH-BLOCK-TAG-SLOT" "CERROR-TRAP" - "CLOSURE-FUN-SLOT" - "CLOSURE-WIDETAG" - "CLOSURE-INFO-OFFSET" - "CODE-BOXED-SIZE-SLOT" - "CODE-CONSTANTS-OFFSET" "CODE-SLOTS-PER-SIMPLE-FUN" - "CODE-DEBUG-INFO-SLOT" - "CODE-HEADER-SIZE-SHIFT" - "CODE-HEADER-WIDETAG" "COMPLEX-ARRAY-WIDETAG" - "COMPLEX-BIT-VECTOR-WIDETAG" "COMPLEX-DOUBLE-FLOAT-FILLER-SLOT" - "COMPLEX-DOUBLE-FLOAT-IMAG-SLOT" "COMPLEX-DOUBLE-FLOAT-REAL-SLOT" - "COMPLEX-DOUBLE-FLOAT-SIZE" "COMPLEX-DOUBLE-FLOAT-WIDETAG" - "COMPLEX-DOUBLE-REG-SC-NUMBER" "COMPLEX-DOUBLE-STACK-SC-NUMBER" - "COMPLEX-IMAG-SLOT" "COMPLEX-REAL-SLOT" - #+long-float("COMPLEX-LONG-FLOAT-IMAG-SLOT" - "COMPLEX-LONG-FLOAT-REAL-SLOT" - "COMPLEX-LONG-FLOAT-SIZE" - "COMPLEX-LONG-FLOAT-WIDETAG" - "COMPLEX-LONG-REG-SC-NUMBER" - "COMPLEX-LONG-STACK-SC-NUMBER") - #+sb-simd-pack("SIMD-PACK-TAG-SLOT" - "SIMD-PACK-HI-VALUE-SLOT" - "SIMD-PACK-LO-VALUE-SLOT" - "SIMD-PACK-SIZE" - "SIMD-PACK-WIDETAG") - #+sb-simd-pack-256("SIMD-PACK-256-TAG-SLOT" - "SIMD-PACK-256-P0-SLOT" - "SIMD-PACK-256-P1-SLOT" - "SIMD-PACK-256-P2-SLOT" - "SIMD-PACK-256-P3-SLOT" - "SIMD-PACK-256-SIZE" - "SIMD-PACK-256-WIDETAG") - #-64-bit - ("COMPLEX-SINGLE-FLOAT-IMAG-SLOT" "COMPLEX-SINGLE-FLOAT-REAL-SLOT") - #+64-bit - "COMPLEX-SINGLE-FLOAT-DATA-SLOT" - "COMPLEX-SINGLE-FLOAT-SIZE" "COMPLEX-SINGLE-FLOAT-WIDETAG" - "COMPLEX-SINGLE-REG-SC-NUMBER" "COMPLEX-SINGLE-STACK-SC-NUMBER" - "COMPLEX-SIZE" "COMPLEX-BASE-STRING-WIDETAG" - #+sb-unicode "COMPLEX-CHARACTER-STRING-WIDETAG" - "COMPLEX-WIDETAG" - "COMPLEX-VECTOR-NIL-WIDETAG" - "COMPLEX-VECTOR-WIDETAG" "CONS-CAR-SLOT" "CONS-CDR-SLOT" - "CONS-SIZE" "CONSTANT-SC-NUMBER" - "CONTEXT-FLOATING-POINT-MODES" "CONTEXT-FLOAT-REGISTER" - "CONTEXT-PC" "CONTEXT-REGISTER" "BOXED-CONTEXT-REGISTER" - "CONTROL-STACK-SC-NUMBER" "COUNT-NO-OPS" - #+sb-safepoint "CSP-SAFEPOINT-TRAP" - "*CURRENT-CATCH-BLOCK*" - "CURRENT-FLOAT-TRAP" - "DESCRIPTOR-REG-SC-NUMBER" "DESCRIPTOR-VS-NON-DESCRIPTOR-STORAGE" - "DO-REFERENCED-OBJECT" - "DOUBLE-FLOAT-BIAS" - "DOUBLE-FLOAT-DIGITS" "DOUBLE-FLOAT-EXPONENT-BYTE" - "DOUBLE-FLOAT-HIDDEN-BIT" - "DOUBLE-FLOAT-NORMAL-EXPONENT-MAX" - "DOUBLE-FLOAT-NORMAL-EXPONENT-MIN" "DOUBLE-FLOAT-SIGNIFICAND-BYTE" - "DOUBLE-FLOAT-SIZE" "DOUBLE-FLOAT-TRAPPING-NAN-BIT" - "DOUBLE-FLOAT-WIDETAG" "DOUBLE-FLOAT-VALUE-SLOT" - "DOUBLE-REG-SC-NUMBER" - "DOUBLE-STACK-SC-NUMBER" - "EMIT-LONG-NOP" "ERROR-TRAP" "EVEN-FIXNUM-LOWTAG" - "FDEFN-FUN-SLOT" "FDEFN-NAME-SLOT" "FDEFN-RAW-ADDR-SLOT" - "FDEFN-SIZE" "FDEFN-WIDETAG" - "FILLER-WIDETAG" - "FIXNUMIZE" - "FIXNUM-TAG-MASK" - "FIXUP-CODE-OBJECT" "FLOAT-DENORMAL-TRAP-BIT" - "FLOAT-DIVIDE-BY-ZERO-TRAP-BIT" - "FLOAT-INVALID-TRAP-BIT" - "FLOAT-OVERFLOW-TRAP-BIT" "FLOAT-SIGN-SHIFT" - "FLOAT-UNDERFLOW-TRAP-BIT" "FLOATING-POINT-MODES" - "FLOAT-STICKY-BITS" - "FLOAT-TRAPS-BYTE" - "FP-CONSTANT-SC-NUMBER" - "FP-DOUBLE-ZERO-SC-NUMBER" "FP-SINGLE-ZERO-SC-NUMBER" - "FUNCALLABLE-INSTANCE-TRAMPOLINE-SLOT" - "FUNCALLABLE-INSTANCE-WIDETAG" - "FUNCALLABLE-INSTANCE-INFO-OFFSET" - "SIMPLE-FUN-ARGLIST-SLOT" "SIMPLE-FUN-INSTS-OFFSET" - "FUN-END-BREAKPOINT-TRAP" - "SIMPLE-FUN-WIDETAG" - "SIMPLE-FUN-NAME-SLOT" - "SIMPLE-FUN-ENTRY-SAP" - "FUN-POINTER-LOWTAG" - "FUNCTION-LAYOUT" - "SIMPLE-FUN-INFO-SLOT" - "SIMPLE-FUN-SELF-SLOT" - "SIMPLE-FUN-SOURCE-SLOT" - "GENCGC-CARD-BYTES" - "GENCGC-ALLOC-GRANULARITY" - "GENCGC-RELEASE-GRANULARITY" - #+(or arm64 ppc ppc64 sparc riscv) "PSEUDO-ATOMIC-INTERRUPTED-FLAG" - #+(or arm64 ppc ppc64 sparc riscv) "PSEUDO-ATOMIC-FLAG" - #+sb-safepoint "GLOBAL-SAFEPOINT-TRAP" - "HALT-TRAP" "IGNORE-ME-SC-NUMBER" - "IMMEDIATE-SC-NUMBER" - ("CANONICALIZE-INLINE-CONSTANT" - "INLINE-CONSTANT-VALUE" - "SORT-INLINE-CONSTANTS" - "EMIT-INLINE-CONSTANT") - "HEXDUMP" - "INSTANCE-DATA-START" - "INSTANCE-WIDETAG" "INSTANCE-POINTER-LOWTAG" - "INSTANCE-SLOTS-OFFSET" "INSTANCE-USAGE" - "INTERIOR-REG-SC-NUMBER" "INTERNAL-ERROR-ARGS" - "INTERRUPTED-FLAG" - "IS-LISP-POINTER" - #+gencgc "LARGE-OBJECT-SIZE" - "LIST-ALLOCATED-OBJECTS" "LIST-POINTER-LOWTAG" - "LOCKFREE-LIST-NODE-FLAG" - ;; FIXME: Possibly these other parameters (see - ;; compiler/{x86,sparc}/parms.lisp) should be defined - ;; conditionally on #+LONG-FLOAT) - "LONG-FLOAT-BIAS" "LONG-FLOAT-DIGITS" "LONG-FLOAT-EXPONENT-BYTE" - "LONG-FLOAT-HIDDEN-BIT" "LONG-FLOAT-NORMAL-EXPONENT-MAX" - "LONG-FLOAT-NORMAL-EXPONENT-MIN" "LONG-FLOAT-SIGNIFICAND-BYTE" - #+long-float "LONG-FLOAT-SIZE" - "LONG-FLOAT-TRAPPING-NAN-BIT" - #+long-float("LONG-FLOAT-WIDETAG" - "LONG-FLOAT-VALUE-SLOT" - "LONG-REG-SC-NUMBER" - "LONG-STACK-SC-NUMBER") - "LOWTAG-LIMIT" "LOWTAG-MASK" - "LRA-SAVE-OFFSET" - "MAP-ALLOCATED-OBJECTS" - "MAX-INTERRUPTS" - #+c-stack-is-control-stack "MEMORY-FAULT-EMULATION-TRAP" - "UNINITIALIZED-LOAD-TRAP" - "MEMORY-USAGE" - "N-LOWTAG-BITS" - "N-FIXNUM-TAG-BITS" - "N-FIXNUM-BITS" - "N-POSITIVE-FIXNUM-BITS" - "NIL-VALUE" - "NFP-SAVE-OFFSET" - "NON-DESCRIPTOR-REG-SC-NUMBER" - "NULL-SC-NUMBER" - "OCFP-SAVE-OFFSET" - "ODD-FIXNUM-LOWTAG" - "OTHER-IMMEDIATE-0-LOWTAG" - "OTHER-IMMEDIATE-1-LOWTAG" - "OTHER-IMMEDIATE-2-LOWTAG" - "OTHER-IMMEDIATE-3-LOWTAG" - "OTHER-POINTER-LOWTAG" - "PAD0-LOWTAG" "PAD1-LOWTAG" "PAD2-LOWTAG" - "PAD3-LOWTAG" "PAD4-LOWTAG" "PAD5-LOWTAG" - "PAD-DATA-BLOCK" "PENDING-INTERRUPT-TRAP" - "PRIMITIVE-OBJECT" "PRIMITIVE-OBJECT-WIDETAG" - "PRIMITIVE-OBJECT-LOWTAG" "PRIMITIVE-OBJECT-NAME" - "PRIMITIVE-OBJECT-OPTIONS" "PRIMITIVE-OBJECT-P" - "PRIMITIVE-OBJECT-LENGTH" "PRIMITIVE-OBJECT-SLOTS" - "PRIMITIVE-OBJECT-VARIABLE-LENGTH-P" - "PRINT-ALLOCATED-OBJECTS" - "RATIO-DENOMINATOR-SLOT" "RATIO-NUMERATOR-SLOT" - "RATIO-SIZE" "RATIO-WIDETAG" - "*READ-ONLY-SPACE-FREE-POINTER*" - "RETURN-PC-WIDETAG" - "RETURN-PC-RETURN-POINT-OFFSET" "RETURN-PC-SAVE-OFFSET" - "SAETP-CTYPE" "SAETP-INITIAL-ELEMENT-DEFAULT" - "SAETP-N-BITS" "SAETP-TYPECODE" "SAETP-PRIMITIVE-TYPE-NAME" - "SAETP-N-PAD-ELEMENTS" "SAETP-N-BITS-SHIFT" - "SAETP-SPECIFIER" - "SAETP-COMPLEX-TYPECODE" "SAETP-IMPORTANCE" - "SAETP-FIXNUM-P" - "VALID-BIT-BASH-SAETP-P" - "*SPECIALIZED-ARRAY-ELEMENT-TYPE-PROPERTIES*" - "SANCTIFY-FOR-EXECUTION" - "SAP-POINTER-SLOT" "SAP-REG-SC-NUMBER" "SAP-SIZE" - "SAP-STACK-SC-NUMBER" "SAP-WIDETAG" - "SC-NUMBER-LIMIT" "SC-NUMBER-BITS" ; SC-NUMBER in package "SB-C" - "SC-OFFSET-LIMIT" "SC-OFFSET-BITS" "SC-OFFSET" - "FINITE-SC-OFFSET-LIMIT" "FINITE-SC-OFFSET-BITS" "FINITE-SC-OFFSET" - "FINITE-SC-OFFSET-MAP" - "SHORT-HEADER-MAX-WORDS" - "SIGFPE-HANDLER" "SIGNED-REG-SC-NUMBER" "SIGNED-STACK-SC-NUMBER" - "SIGNED-WORD" - "SIMPLE-ARRAY-COMPLEX-DOUBLE-FLOAT-WIDETAG" - #+long-float "SIMPLE-ARRAY-COMPLEX-LONG-FLOAT-WIDETAG" - "SIMPLE-ARRAY-COMPLEX-SINGLE-FLOAT-WIDETAG" - "SIMPLE-ARRAY-DOUBLE-FLOAT-WIDETAG" - #+long-float "SIMPLE-ARRAY-LONG-FLOAT-WIDETAG" - "SIMPLE-ARRAY-NIL-WIDETAG" - "SIMPLE-ARRAY-SINGLE-FLOAT-WIDETAG" - "SIMPLE-ARRAY-WIDETAG" - "SIMPLE-ARRAY-UNSIGNED-BYTE-15-WIDETAG" - "SIMPLE-ARRAY-UNSIGNED-BYTE-16-WIDETAG" - "SIMPLE-ARRAY-UNSIGNED-BYTE-2-WIDETAG" - "SIMPLE-ARRAY-UNSIGNED-FIXNUM-WIDETAG" - "SIMPLE-ARRAY-UNSIGNED-BYTE-31-WIDETAG" - "SIMPLE-ARRAY-UNSIGNED-BYTE-32-WIDETAG" - "SIMPLE-ARRAY-UNSIGNED-BYTE-63-WIDETAG" - "SIMPLE-ARRAY-UNSIGNED-BYTE-64-WIDETAG" - "SIMPLE-ARRAY-UNSIGNED-BYTE-4-WIDETAG" - "SIMPLE-ARRAY-UNSIGNED-BYTE-7-WIDETAG" - "SIMPLE-ARRAY-UNSIGNED-BYTE-8-WIDETAG" - "SIMPLE-ARRAY-SIGNED-BYTE-16-WIDETAG" - "SIMPLE-ARRAY-FIXNUM-WIDETAG" - "SIMPLE-ARRAY-SIGNED-BYTE-32-WIDETAG" - "SIMPLE-ARRAY-SIGNED-BYTE-64-WIDETAG" - "SIMPLE-ARRAY-SIGNED-BYTE-8-WIDETAG" - "SIMPLE-BIT-VECTOR-WIDETAG" - "SIMPLE-BASE-STRING-WIDETAG" - #+sb-unicode "SIMPLE-CHARACTER-STRING-WIDETAG" - "SIMPLE-VECTOR-WIDETAG" "SINGLE-FLOAT-BIAS" - "SINGLE-FLOAT-DIGITS" "SINGLE-FLOAT-EXPONENT-BYTE" - "SINGLE-FLOAT-HIDDEN-BIT" "SINGLE-FLOAT-NORMAL-EXPONENT-MAX" - "SINGLE-FLOAT-NORMAL-EXPONENT-MIN" "SINGLE-FLOAT-SIGNIFICAND-BYTE" - "SINGLE-FLOAT-SIZE" "SINGLE-FLOAT-TRAPPING-NAN-BIT" - "SINGLE-FLOAT-WIDETAG" - #-64-bit "SINGLE-FLOAT-VALUE-SLOT" - "SINGLE-REG-SC-NUMBER" "SINGLE-STACK-SC-NUMBER" - "SINGLE-STEP-AROUND-TRAP" - "SINGLE-STEP-BEFORE-TRAP" - "SINGLE-STEP-BREAKPOINT-TRAP" - "INVALID-ARG-COUNT-TRAP" - "SINGLE-VALUE-RETURN-BYTE-OFFSET" - "SLOT-NAME" "SLOT-OFFSET" "SLOT-OPTIONS" - "SLOT-SPECIAL" - "SLOT-REST-P" "+STATIC-FDEFNS+" "STATIC-FUN-OFFSET" - "%SPACE-BOUNDS" "SPACE-BYTES" - "STABLE-HASH-REQUIRED-FLAG" - "HASH-SLOT-PRESENT-FLAG" - "STATIC-SYMBOL-OFFSET" "STATIC-SYMBOL-P" - "*STATIC-SPACE-FREE-POINTER*" "+STATIC-SYMBOLS+" - "SYMBOL-HASH-SLOT" "SYMBOL-WIDETAG" "SYMBOL-NAME-SLOT" - "SYMBOL-PACKAGE-SLOT" "SYMBOL-INFO-SLOT" - "SYMBOL-SIZE" "SYMBOL-VALUE-SLOT" "SYMBOL-TLS-INDEX-SLOT" - "EXTENDED-SYMBOL-SIZE" - "*BINDING-STACK-START*" - "*CONTROL-STACK-START*" "*CONTROL-STACK-END*" - "CONTROL-STACK-POINTER-VALID-P" - "DYNAMIC-SPACE-START" "DYNAMIC-SPACE-END" - #+gencgc("MAX-DYNAMIC-SPACE-END" - "PAGE-TABLE" - "FIND-PAGE-INDEX" - "NEXT-FREE-PAGE") - #-gencgc("DYNAMIC-0-SPACE-START" - "DYNAMIC-0-SPACE-END") - #+immobile-space("IMMOBILE-CARD-BYTES" - "FIXEDOBJ-SPACE-START" "FIXEDOBJ-SPACE-SIZE" - "VARYOBJ-SPACE-START" "VARYOBJ-SPACE-SIZE" - "*FIXEDOBJ-SPACE-FREE-POINTER*" - "*VARYOBJ-SPACE-FREE-POINTER*") - "READ-ONLY-SPACE-START" "READ-ONLY-SPACE-END" - "STATIC-SPACE-START" "STATIC-SPACE-END" - ("LINKAGE-TABLE-SPACE-START" - "LINKAGE-TABLE-SPACE-END" - "LINKAGE-TABLE-ENTRY-SIZE") - #+sb-safepoint "GC-SAFEPOINT-PAGE-ADDR" - #+sb-safepoint "GC-SAFEPOINT-TRAP-OFFSET" - "TLS-SIZE" "N-WIDETAG-BITS" "WIDETAG-MASK" - "INSTANCE-LENGTH-SHIFT" - "UNBOUND-MARKER-WIDETAG" - "UNDEFINED-FUNCTION-TRAP" - "NO-TLS-VALUE-MARKER-WIDETAG" - "UNSIGNED-REG-SC-NUMBER" "UNSIGNED-STACK-SC-NUMBER" - "UNWIND-BLOCK-CODE-SLOT" "UNWIND-BLOCK-CFP-SLOT" - "UNWIND-BLOCK-UWP-SLOT" "UNWIND-BLOCK-ENTRY-PC-SLOT" - "UNWIND-BLOCK-SIZE" "VALUE-CELL-WIDETAG" "VALUE-CELL-SIZE" - "VALUE-CELL-VALUE-SLOT" "VECTOR-DATA-OFFSET" "VECTOR-LENGTH-SLOT" - "VECTOR-NORMAL-SUBTYPE" - "VECTOR-WEAK-SUBTYPE" - "VECTOR-WEAK-VISITED-SUBTYPE" - "VECTOR-HASHING-SUBTYPE" - "VECTOR-ADDR-HASHING-SUBTYPE" - "WEAK-POINTER-NEXT-SLOT" - "WEAK-POINTER-SIZE" "WEAK-POINTER-WIDETAG" - "WEAK-POINTER-VALUE-SLOT" - "N-WORD-BITS" "N-WORD-BYTES" "N-MACHINE-WORD-BITS" "N-MACHINE-WORD-BYTES" - "WORD-REG-SC-NUMBER" "WORD-SHIFT" - #+win32 "CONTEXT-RESTORE-TRAP" - "ZERO-SC-NUMBER")) - - #s(sb-cold:package-data - :name "SB-RBTREE" - :doc "internal: red/black tree" - :use ("CL" "SB-INT" "SB-EXT") - :shadow ("DELETE") - :export ("INSERT" "DELETE" "FIND=" "FIND<=")) - - #s(sb-cold:package-data - :name "SB-WALKER" - :doc "internal: a code walker used by PCL" - :use ("CL" "SB-INT" "SB-EXT")) - - #+sb-eval - #s(sb-cold:package-data - :name "SB-EVAL" - :doc "internal: the evaluator implementation used to execute code without compiling it." - :use ("CL" "SB-KERNEL" "SB-EXT" "SB-INT") - :reexport ("*EVAL-CALLS*") - :export ("INTERPRETED-FUNCTION-NAME" - "INTERPRETED-FUNCTION-DEBUG-NAME" - "INTERPRETED-FUNCTION-LAMBDA-LIST" - "INTERPRETED-FUNCTION-DEBUG-LAMBDA-LIST" - "INTERPRETED-FUNCTION-DECLARATIONS" - "INTERPRETED-FUNCTION-DOCUMENTATION" - "INTERPRETED-FUNCTION-BODY" - "INTERPRETED-FUNCTION-SOURCE-LOCATION" - "EVAL-IN-ENVIRONMENT" - "MAKE-NULL-ENVIRONMENT" - "EVAL-IN-NATIVE-ENVIRONMENT" - "*EVAL-LEVEL*")) - - #+sb-fasteval - #s(sb-cold:package-data - :name "SB-INTERPRETER" - :doc "internal: a new EVAL implementation with semantic preprocessing." - :use ("CL" "SB-KERNEL" "SB-EXT" "SB-INT") - :export ("BASIC-ENV" - "ENV-POLICY" - "EVAL-IN-ENVIRONMENT" - "FIND-LEXICAL-FUN" - "FIND-LEXICAL-VAR" - "FUN-LAMBDA-EXPRESSION" - "FUN-LAMBDA-LIST" - "FUN-PROTO-FN" - "FUN-SOURCE-LOCATION" - "%FUN-TYPE" ; to avoid conflict with SB-KERNEL:FUN-TYPE - "LEXENV-FROM-ENV" - "LIST-LOCALS" - "PROTO-FN-DOCSTRING" - "PROTO-FN-NAME" - "PROTO-FN-PRETTY-ARGLIST" - "TYPE-CHECK") - :import-from (("SB-C" - "PARSE-EVAL-WHEN-SITUATIONS" - "MAKE-GLOBAL-VAR" "MAKE-LAMBDA-VAR" - "*LEXENV*") - ("SB-VM" "SYMBOL-EXTRA-SLOT-P" "SYMBOL-EXTRA") - ("SB-ALIEN" "%HEAP-ALIEN" "ALIEN-VALUE") - ("SB-KERNEL" "%%TYPEP"))) - - #+win32 - #s(sb-cold:package-data - :name "SB-WIN32" - :doc "private: a wrapper layer for Win32 functions needed by -SBCL itself" - :use ("CL" "SB-ALIEN" "SB-EXT" "SB-INT" "SB-SYS") - :export ("BOOL" - "CLOSE-HANDLE" - "CREATE-FILE" - "CREATE-FILE-MAPPING" - "CRYPT-GEN-RANDOM" - "DWORD" - "EXCEPTION" - "EXCEPTION-RECORD" - "EXCEPTION-CONTEXT" - "EXCEPTION-CODE" - "FILE-CREATE-ALWAYS" - "FILE-CREATE-NEW" - "FILE-OPEN-ALWAYS" - "FILE-OPEN-EXISTING" - "FILE-TRUNCATE-EXISTING" - "FLUSH-CONSOLE-INPUT-BUFFER" - "FLUSH-VIEW-OF-FILE" - "FORMAT-SYSTEM-MESSAGE" - "GET-FILE-ATTRIBUTES" - "GET-FILE-SIZE-EX" - "GET-FILE-TYPE" - "GET-LAST-ERROR" - "GET-OSFHANDLE" - "GET-VERSION-EX" - "HANDLE" - "HANDLE-CLEAR-INPUT" - "HANDLE-LISTEN" - "INT-PTR" - "INVALID-HANDLE" - "LSEEKI64" - "MAP-VIEW-OF-FILE" - "MILLISLEEP" - "PEEK-CONSOLE-INPUT" - "PEEK-NAMED-PIPE" - "READ-FILE" - "UNIXLIKE-CLOSE" - "UNIXLIKE-OPEN" - "UNMAP-VIEW-OF-FILE" - "WAIT-OBJECT-OR-SIGNAL" - "WRITE-FILE" - "WITH-PROCESS-TIMES"))) - -;;; The following symbols may be referenced without seeing a definition -;;; during make-host-2. No warning will result. -;;; This list is read after packages are created from the data above. -((;; CL, EXT, KERNEL - allocate-instance - compute-applicable-methods - slot-makunbound - make-load-form-saving-slots - sb-vm:map-allocated-objects - sb-vm::primitive-object-size - sb-vm::remove-static-links) - ;; CLOS implementation - (sb-mop:class-finalized-p - sb-mop:class-prototype - sb-mop:class-slots - sb-pcl::eql-specializer-to-ctype - sb-mop:finalize-inheritance - sb-mop:generic-function-name - (setf sb-mop:generic-function-name) - sb-mop:slot-definition-allocation - sb-mop:slot-definition-name - sb-pcl::method-p - sb-mop:method-function - sb-pcl::%force-cache-flushes - sb-pcl::check-wrapper-validity - sb-pcl::class-has-a-forward-referenced-superclass-p - sb-pcl::class-wrapper - sb-pcl::compute-gf-ftype - sb-pcl::definition-source - sb-pcl::ensure-accessor - sb-pcl:ensure-class-finalized) - ;; CLOS-based packages - (sb-gray:stream-clear-input - sb-gray:stream-clear-output - sb-gray:stream-file-position - sb-gray:stream-finish-output - sb-gray:stream-force-output - sb-gray:stream-fresh-line - sb-gray:stream-line-column - sb-gray:stream-line-length - sb-gray:stream-listen - sb-gray:stream-peek-char - sb-gray:stream-read-byte - sb-gray:stream-read-char - sb-gray:stream-read-char-no-hang - sb-gray:stream-read-line - sb-gray:stream-read-sequence - sb-gray:stream-terpri - sb-gray:stream-unread-char - sb-gray:stream-write-byte - sb-gray:stream-write-char - sb-gray:stream-write-sequence - sb-gray:stream-write-string - sb-sequence:concatenate - sb-sequence:copy-seq - sb-sequence:count - sb-sequence:count-if - sb-sequence:count-if-not - sb-sequence:delete - sb-sequence:delete-duplicates - sb-sequence:delete-if - sb-sequence:delete-if-not - (setf sb-sequence:elt) - sb-sequence:elt - sb-sequence:emptyp - sb-sequence:fill - sb-sequence:find - sb-sequence:find-if - sb-sequence:find-if-not - (setf sb-sequence:iterator-element) - sb-sequence:iterator-endp - sb-sequence:iterator-step - sb-sequence:length - sb-sequence:make-sequence-iterator - sb-sequence:make-sequence-like - sb-sequence:map - sb-sequence:merge - sb-sequence:mismatch - sb-sequence:nreverse - sb-sequence:nsubstitute - sb-sequence:nsubstitute-if - sb-sequence:nsubstitute-if-not - sb-sequence:position - sb-sequence:position-if - sb-sequence:position-if-not - sb-sequence:reduce - sb-sequence:remove - sb-sequence:remove-duplicates - sb-sequence:remove-if - sb-sequence:remove-if-not - sb-sequence:replace - sb-sequence:reverse - sb-sequence:search - sb-sequence:sort - sb-sequence:stable-sort - sb-sequence:subseq - sb-sequence:substitute - sb-sequence:substitute-if - sb-sequence:substitute-if-not) - ;; Fast interpreter - #+sb-fasteval - (sb-interpreter:%fun-type - sb-interpreter:env-policy - sb-interpreter:eval-in-environment - sb-interpreter:find-lexical-fun - sb-interpreter:find-lexical-var - sb-interpreter::flush-everything - sb-interpreter::fun-lexically-notinline-p - sb-interpreter:lexenv-from-env - sb-interpreter::lexically-unlocked-symbol-p - sb-interpreter:list-locals - sb-interpreter::reconstruct-syntactic-closure-env) - ;; Other - (sb-debug::find-interrupted-name-and-frame - sb-impl::encapsulate-generic-function - sb-impl::encapsulated-generic-function-p - sb-impl::get-processes-status-changes - sb-impl::step-form - sb-impl::step-values - sb-impl::stringify-package-designator - sb-impl::stringify-string-designator - sb-impl::stringify-string-designators - sb-impl::unencapsulate-generic-function) - ;; The following functions are in fact defined during make-host-2 - ;; but they are non-toplevel so they appear to be undefined. - (sb-int:gensymify* - sb-int:keywordicate - sb-int:package-symbolicate - sb-int:symbolicate - sb-kernel::preinform-compiler-about-accessors - sb-kernel::preinform-compiler-about-slot-functions - sb-impl::bytes-per-utf8-character-aref - sb-impl::bytes-per-utf8-character-sap-ref-8 - sb-impl::user-homedir-namestring - sb-c::apply-core-fixups - sb-c::compiled-debug-info-char-offset - sb-c::compiled-debug-info-tlf-number - sb-c::fopcompilable-p - sb-c::pack-xref-data - sb-c::prepare-for-compile - sb-sys:reinit-internal-real-time)) diff --git a/release.sh b/release.sh index ad76adc3c9..022bc43663 100755 --- a/release.sh +++ b/release.sh @@ -315,11 +315,9 @@ echo TODO: echo echo perform administrative tasks: echo -echo \* rebuild documentation with modern texinfo echo \* visit https://sourceforge.net/projects/sbcl/files/ echo \* select sbcl -> $VERSION -> "view details" for the source echo \ \ tarball, "Select all" and Save echo \* mail sbcl-announce echo \* check and send sbcl-$VERSION-bugmail.txt to edit@bugs.launchpad.net echo \ \ '(sign: C-c RET s p)' -echo "* update #lisp IRC topic (requires channel ops)" diff --git a/run-sbcl.sh b/run-sbcl.sh index 8c26486a79..2a87846fda 100755 --- a/run-sbcl.sh +++ b/run-sbcl.sh @@ -15,8 +15,18 @@ set -e this="$0" +build_directory_p(){ + [ -x "$1"/src/runtime/sbcl -a -f "$1"/output/sbcl.core ]; +} + # OSX 10.8 readlink doesn't have -f while [ -h "$this" ]; do + # Stop resolving symlinks when $this lives in a build tree. + # (Build trees might consist of symlinks to something that doesn't + # follow our repo layout.) + if build_directory_p `dirname "$this"`; then + break + fi # [ -h should guarantee that readlink output will be non-null link=`readlink -n "$this"` # if absolute path @@ -27,6 +37,14 @@ while [ -h "$this" ]; do fi done BASE=`dirname "$this"` +# BASE can still be relative if $0 is a relative pathname naming a +# non-symlink, or if the last symlink visited in that loop has a +# relative target. We need BASE to be an absolute pathname in order to +# make MODULE-PROVIDE-CONTRIB work throughout the Lisp session, even +# after frobbing *DEFAULT-PATHNAME-DEFAULTS*. +if expr "$BASE" : '^/.*' > /dev/null; [ $? != 0 ]; then + BASE=`cd "$BASE" && pwd` +fi CORE_DEFINED=no @@ -47,14 +65,17 @@ for arg in "$@"; do esac done -ARGUMENTS="" - if [ "$CORE_DEFINED" = "no" ]; then - ARGUMENTS="--core "$BASE"/output/sbcl.core" + CORE="$BASE"/output/sbcl.core fi -if [ -x "$BASE"/src/runtime/sbcl -a -f "$BASE"/output/sbcl.core ]; then - SBCL_HOME="$BASE/obj/sbcl-home" exec "$BASE"/src/runtime/sbcl $ARGUMENTS "$@" +if build_directory_p "$BASE"; then + export SBCL_HOME + if [ "$CORE_DEFINED" = "no" ]; then + SBCL_HOME="$BASE"/obj/sbcl-home exec "$BASE"/src/runtime/sbcl --core "$CORE" "$@" + else + SBCL_HOME="$BASE"/obj/sbcl-home exec "$BASE"/src/runtime/sbcl "$@" + fi else echo "No built SBCL here ($BASE): run 'sh make.sh' first!" exit 1 diff --git a/slam.sh b/slam.sh index dce5422996..6e79da91f9 100644 --- a/slam.sh +++ b/slam.sh @@ -65,11 +65,14 @@ set -e ####################################################################### warm_option="" -if [ "$1" == --load ]; then - warm_option="--load" +if [ "$1" == --load -o "$1" == --load-with-sb-devel ]; then + warm_option="$1" shift fi +# Load our build configuration +. output/build-config + HOST_TYPE="${1:-sbcl}" echo //HOST_TYPE=\"$HOST_TYPE\" @@ -85,7 +88,7 @@ case "$HOST_TYPE" in INIT="-noinit" CORE="-core" ;; - sbcl) LISP="${XC_LISP:-sbcl}" + sbcl) LISP="${SBCL_XC_HOST%% *}" INIT="--no-sysinit --no-userinit" CORE="--core" ;; diff --git a/src/assembly/alpha/alloc.lisp b/src/assembly/alpha/alloc.lisp deleted file mode 100644 index 0c1b0282f3..0000000000 --- a/src/assembly/alpha/alloc.lisp +++ /dev/null @@ -1,17 +0,0 @@ -;;;; stuff to handle allocation of stuff we don't want to do inline - -;;;; This software is part of the SBCL system. See the README file for -;;;; more information. -;;;; -;;;; This software is derived from the CMU CL system, which was -;;;; written at Carnegie Mellon University and released into the -;;;; public domain. The software is in the public domain and is -;;;; provided with absolutely no warranty. See the COPYING and CREDITS -;;;; files for more information. - -(in-package "SB-VM") - -;;; (Given that the pseudo-atomic sequence is so short, there is -;;; nothing that qualifies. But we want to keep the file around -;;; in case we decide to add something later.) - diff --git a/src/assembly/alpha/arith.lisp b/src/assembly/alpha/arith.lisp deleted file mode 100644 index 79047761b8..0000000000 --- a/src/assembly/alpha/arith.lisp +++ /dev/null @@ -1,418 +0,0 @@ -;;;; stuff to handle simple cases for generic arithmetic - -;;;; This software is part of the SBCL system. See the README file for -;;;; more information. -;;;; -;;;; This software is derived from the CMU CL system, which was -;;;; written at Carnegie Mellon University and released into the -;;;; public domain. The software is in the public domain and is -;;;; provided with absolutely no warranty. See the COPYING and CREDITS -;;;; files for more information. - -(in-package "SB-VM") - -(define-assembly-routine (generic-+ - (:cost 10) - (:return-style :full-call) - (:translate +) - (:policy :safe) - (:save-p t)) - ((:arg x (descriptor-reg any-reg) a0-offset) - (:arg y (descriptor-reg any-reg) a1-offset) - - (:res res (descriptor-reg any-reg) a0-offset) - - (:temp temp non-descriptor-reg nl0-offset) - (:temp temp2 non-descriptor-reg nl1-offset) - (:temp temp3 non-descriptor-reg nl2-offset) - (:temp lip interior-reg lip-offset) - (:temp lra descriptor-reg lra-offset) - (:temp nargs any-reg nargs-offset) - (:temp ocfp any-reg ocfp-offset)) - (inst and x 3 temp) - (inst bne temp DO-STATIC-FUN) - (inst and y 3 temp) - (inst bne temp DO-STATIC-FUN) - (inst addq x y res) - - ; Check whether we need a bignum. - (inst sra res 31 temp) - (inst beq temp DONE) - (inst not temp temp) - (inst beq temp DONE) - (inst sra res 2 temp3) - - ; from move-from-signed - (inst li 2 temp2) - (inst sra temp3 31 temp) - (inst cmoveq temp 1 temp2) - (inst not temp temp) - (inst cmoveq temp 1 temp2) - (inst sll temp2 n-widetag-bits temp2) - (inst bis temp2 bignum-widetag temp2) - - (pseudo-atomic (:extra (pad-data-block (+ bignum-digits-offset 3))) - (inst bis alloc-tn other-pointer-lowtag res) - (storew temp2 res 0 other-pointer-lowtag) - (storew temp3 res bignum-digits-offset other-pointer-lowtag) - (inst srl temp3 32 temp) - (storew temp res (1+ bignum-digits-offset) other-pointer-lowtag)) - DONE - (lisp-return lra lip :offset 2) - - DO-STATIC-FUN - (inst ldl lip (static-fun-offset 'two-arg-+) null-tn) - (inst li (fixnumize 2) nargs) - (inst move cfp-tn ocfp) - (inst move csp-tn cfp-tn) - (inst jmp zero-tn lip)) - - -(define-assembly-routine (generic-- - (:cost 10) - (:return-style :full-call) - (:translate -) - (:policy :safe) - (:save-p t)) - ((:arg x (descriptor-reg any-reg) a0-offset) - (:arg y (descriptor-reg any-reg) a1-offset) - - (:res res (descriptor-reg any-reg) a0-offset) - - (:temp temp non-descriptor-reg nl0-offset) - (:temp temp2 non-descriptor-reg nl1-offset) - (:temp temp3 non-descriptor-reg nl2-offset) - (:temp lip interior-reg lip-offset) - (:temp lra descriptor-reg lra-offset) - (:temp nargs any-reg nargs-offset) - (:temp ocfp any-reg ocfp-offset)) - (inst and x 3 temp) - (inst bne temp DO-STATIC-FUN) - (inst and y 3 temp) - (inst bne temp DO-STATIC-FUN) - (inst subq x y res) - - ; Check whether we need a bignum. - (inst sra res 31 temp) - (inst beq temp DONE) - (inst not temp temp) - (inst beq temp DONE) - (inst sra res 2 temp3) - - ; from move-from-signed - (inst li 2 temp2) - (inst sra temp3 31 temp) - (inst cmoveq temp 1 temp2) - (inst not temp temp) - (inst cmoveq temp 1 temp2) - (inst sll temp2 n-widetag-bits temp2) - (inst bis temp2 bignum-widetag temp2) - - (pseudo-atomic (:extra (pad-data-block (+ bignum-digits-offset 3))) - (inst bis alloc-tn other-pointer-lowtag res) - (storew temp2 res 0 other-pointer-lowtag) - (storew temp3 res bignum-digits-offset other-pointer-lowtag) - (inst srl temp3 32 temp) - (storew temp res (1+ bignum-digits-offset) other-pointer-lowtag)) - DONE - (lisp-return lra lip :offset 2) - - DO-STATIC-FUN - (inst ldl lip (static-fun-offset 'two-arg--) null-tn) - (inst li (fixnumize 2) nargs) - (inst move cfp-tn ocfp) - (inst move csp-tn cfp-tn) - (inst jmp zero-tn lip)) - - -(define-assembly-routine (generic-* - (:cost 25) - (:return-style :full-call) - (:translate *) - (:policy :safe) - (:save-p t)) - ((:arg x (descriptor-reg any-reg) a0-offset) - (:arg y (descriptor-reg any-reg) a1-offset) - - (:res res (descriptor-reg any-reg) a0-offset) - - (:temp temp non-descriptor-reg nl0-offset) - (:temp lo non-descriptor-reg nl1-offset) - (:temp hi non-descriptor-reg nl2-offset) - (:temp temp2 non-descriptor-reg nl3-offset) - (:temp lip interior-reg lip-offset) - (:temp lra descriptor-reg lra-offset) - (:temp nargs any-reg nargs-offset) - (:temp ocfp any-reg ocfp-offset)) - ;; If either arg is not a fixnum, call the static function. - (inst and x 3 temp) - (inst bne temp DO-STATIC-FUN) - (inst and y 3 temp) - (inst bne temp DO-STATIC-FUN) - - ;; Remove the tag from one arg so that the result will have the - ;; correct fixnum tag. - (inst sra x 2 temp) - (inst mulq temp y lo) - (inst sra lo 32 hi) - (inst sll lo 32 res) - (inst sra res 32 res) - ;; Check to see if the result will fit in a fixnum. (I.e. the high - ;; word is just 32 copies of the sign bit of the low word). - (inst sra res 31 temp) - (inst xor hi temp temp) - (inst beq temp DONE) - ;; Shift the double word hi:res down two bits into hi:low to get rid - ;; of the fixnum tag. - (inst sra lo 2 lo) - (inst sra lo 32 hi) - - ;; Do we need one word or two? Assume two. - (inst li (logior (ash 2 n-widetag-bits) bignum-widetag) temp2) - (inst sra lo 31 temp) - (inst xor temp hi temp) - (inst bne temp two-words) - - ;; Only need one word, fix the header. - (inst li (logior (ash 1 n-widetag-bits) bignum-widetag) temp2) - ;; Allocate one word. - (pseudo-atomic (:extra (pad-data-block (1+ bignum-digits-offset))) - (inst bis alloc-tn other-pointer-lowtag res) - (storew temp2 res 0 other-pointer-lowtag)) - ;; Store one word - (storew lo res bignum-digits-offset other-pointer-lowtag) - ;; Out of here - (lisp-return lra lip :offset 2) - - TWO-WORDS - ;; Allocate two words. - (pseudo-atomic (:extra (pad-data-block (+ 2 bignum-digits-offset))) - (inst bis alloc-tn other-pointer-lowtag res) - (storew temp2 res 0 other-pointer-lowtag)) - ;; Store two words. - (storew lo res bignum-digits-offset other-pointer-lowtag) - (storew hi res (1+ bignum-digits-offset) other-pointer-lowtag) - ;; out of here - (lisp-return lra lip :offset 2) - - DO-STATIC-FUN - (inst ldl lip (static-fun-offset 'two-arg-*) null-tn) - (inst li (fixnumize 2) nargs) - (inst move cfp-tn ocfp) - (inst move csp-tn cfp-tn) - (inst jmp zero-tn lip) - - DONE) - - -;;;; division - -(define-assembly-routine (signed-truncate - (:note "(signed-byte 64) truncate") - (:cost 60) - (:policy :fast-safe) - (:translate truncate) - (:arg-types signed-num signed-num) - (:result-types signed-num signed-num)) - - ((:arg dividend signed-reg nl0-offset) - (:arg divisor signed-reg nl1-offset) - - (:res quo signed-reg nl2-offset) - (:res rem signed-reg nl3-offset) - - (:temp quo-sign signed-reg nl5-offset) - (:temp rem-sign signed-reg nargs-offset) - (:temp temp1 non-descriptor-reg nl4-offset)) - - (let ((error (generate-error-code nil 'division-by-zero-error - dividend divisor))) - (inst beq divisor error)) - - (inst xor dividend divisor quo-sign) - (inst move dividend rem-sign) - (let ((label (gen-label))) - (inst bge dividend label) - (inst subq zero-tn dividend dividend) - (emit-label label)) - (let ((label (gen-label))) - (inst bge divisor label) - (inst subq zero-tn divisor divisor) - (emit-label label)) - (inst move zero-tn rem) - (inst move zero-tn quo) - - (dotimes (i 64) - (inst srl dividend 63 temp1) - (inst sll rem 1 rem) - (inst bis temp1 rem rem) - (inst cmple divisor rem temp1) - (inst sll quo 1 quo) - (inst bis temp1 quo quo) - (inst sll dividend 1 dividend) - (inst subq temp1 1 temp1) - (inst zap divisor temp1 temp1) - (inst subq rem temp1 rem)) - - (let ((label (gen-label))) - ;; If the quo-sign is negative, we need to negate quo. - (inst bge quo-sign label) - (inst subq zero-tn quo quo) - (emit-label label)) - (let ((label (gen-label))) - ;; If the rem-sign is negative, we need to negate rem. - (inst bge rem-sign label) - (inst subq zero-tn rem rem) - (emit-label label))) - - -;;;; comparison routines - -(macrolet - ((define-cond-assem-rtn (name translate static-fn cmp not-p) - `(define-assembly-routine (,name - (:cost 10) - (:return-style :full-call) - (:policy :safe) - (:translate ,translate) - (:save-p t)) - ((:arg x (descriptor-reg any-reg) a0-offset) - (:arg y (descriptor-reg any-reg) a1-offset) - - (:res res descriptor-reg a0-offset) - - (:temp temp non-descriptor-reg nl0-offset) - (:temp lip interior-reg lip-offset) - (:temp nargs any-reg nargs-offset) - (:temp ocfp any-reg ocfp-offset)) - (inst and x 3 temp) - (inst bne temp DO-STATIC-FN) - (inst and y 3 temp) - (inst beq temp DO-COMPARE) - - DO-STATIC-FN - (inst ldl lip (static-fun-offset ',static-fn) null-tn) - (inst li (fixnumize 2) nargs) - (inst move cfp-tn ocfp) - (inst move csp-tn cfp-tn) - (inst jmp zero-tn lip) - - DO-COMPARE - ,cmp - (inst move null-tn res) - (inst ,(if not-p 'bne 'beq) temp done) - (load-symbol res t) - DONE))) - - (define-cond-assem-rtn generic-< < two-arg-< (inst cmplt x y temp) nil) - (define-cond-assem-rtn generic-> > two-arg-> (inst cmplt y x temp) nil)) - - -(define-assembly-routine (generic-eql - (:cost 10) - (:return-style :full-call) - (:policy :safe) - (:translate eql) - (:save-p t)) - ((:arg x (descriptor-reg any-reg) a0-offset) - (:arg y (descriptor-reg any-reg) a1-offset) - - (:res res descriptor-reg a0-offset) - - (:temp temp non-descriptor-reg nl0-offset) - (:temp lip interior-reg lip-offset) - (:temp lra descriptor-reg lra-offset) - (:temp nargs any-reg nargs-offset) - (:temp ocfp any-reg ocfp-offset)) - (inst cmpeq x y temp) - (inst bne temp RETURN-T) - (inst and x 3 temp) - (inst beq temp RETURN-NIL) - (inst and y 3 temp) - (inst bne temp DO-STATIC-FN) - - RETURN-NIL - (inst move null-tn res) - (lisp-return lra lip :offset 2) - - DO-STATIC-FN - (inst ldl lip (static-fun-offset 'eql) null-tn) - (inst li (fixnumize 2) nargs) - (inst move cfp-tn ocfp) - (inst move csp-tn cfp-tn) - (inst jmp zero-tn lip) - - RETURN-T - (load-symbol res t)) - -(define-assembly-routine (generic-= - (:cost 10) - (:return-style :full-call) - (:policy :safe) - (:translate =) - (:save-p t)) - ((:arg x (descriptor-reg any-reg) a0-offset) - (:arg y (descriptor-reg any-reg) a1-offset) - - (:res res descriptor-reg a0-offset) - - (:temp temp non-descriptor-reg nl0-offset) - (:temp lip interior-reg lip-offset) - (:temp lra descriptor-reg lra-offset) - (:temp nargs any-reg nargs-offset) - (:temp ocfp any-reg ocfp-offset)) - (inst and x 3 temp) - (inst bne temp DO-STATIC-FN) - (inst and y 3 temp) - (inst bne temp DO-STATIC-FN) - (inst cmpeq x y temp) - (inst bne temp RETURN-T) - - (inst move null-tn res) - (lisp-return lra lip :offset 2) - - DO-STATIC-FN - (inst ldl lip (static-fun-offset 'two-arg-=) null-tn) - (inst li (fixnumize 2) nargs) - (inst move cfp-tn ocfp) - (inst move csp-tn cfp-tn) - (inst jmp zero-tn lip) - - RETURN-T - (load-symbol res t)) - -(define-assembly-routine (generic-/= - (:cost 10) - (:return-style :full-call) - (:policy :safe) - (:translate /=) - (:save-p t)) - ((:arg x (descriptor-reg any-reg) a0-offset) - (:arg y (descriptor-reg any-reg) a1-offset) - - (:res res descriptor-reg a0-offset) - - (:temp temp non-descriptor-reg nl0-offset) - (:temp lip interior-reg lip-offset) - (:temp lra descriptor-reg lra-offset) - (:temp nargs any-reg nargs-offset) - (:temp ocfp any-reg ocfp-offset)) - (inst and x 3 temp) - (inst bne temp DO-STATIC-FN) - (inst and y 3 temp) - (inst bne temp DO-STATIC-FN) - (inst cmpeq x y temp) - (inst bne temp RETURN-NIL) - - (load-symbol res t) - (lisp-return lra lip :offset 2) - - DO-STATIC-FN - (inst ldl lip (static-fun-offset 'two-arg-/=) null-tn) - (inst li (fixnumize 2) nargs) - (inst move cfp-tn ocfp) - (inst move csp-tn cfp-tn) - (inst jmp zero-tn lip) - - RETURN-NIL - (inst move null-tn res)) diff --git a/src/assembly/alpha/array.lisp b/src/assembly/alpha/array.lisp deleted file mode 100644 index 3f3d80914a..0000000000 --- a/src/assembly/alpha/array.lisp +++ /dev/null @@ -1,40 +0,0 @@ -;;;; support routines for arrays and vectors - -;;;; This software is part of the SBCL system. See the README file for -;;;; more information. -;;;; -;;;; This software is derived from the CMU CL system, which was -;;;; written at Carnegie Mellon University and released into the -;;;; public domain. The software is in the public domain and is -;;;; provided with absolutely no warranty. See the COPYING and CREDITS -;;;; files for more information. - -(in-package "SB-VM") - - -(define-assembly-routine (allocate-vector - (:policy :fast-safe) - (:translate allocate-vector) - (:arg-types positive-fixnum - positive-fixnum - positive-fixnum)) - ((:arg type any-reg a0-offset) - (:arg length any-reg a1-offset) - (:arg words any-reg a2-offset) - (:res result descriptor-reg a0-offset) - - (:temp ndescr non-descriptor-reg nl0-offset)) - ;; This is kinda sleezy, changing words like this. But we can because - ;; the vop thinks it is temporary. - (inst addq words (+ (1- (ash 1 n-lowtag-bits)) - (* vector-data-offset n-word-bytes)) - words) - (inst li (lognot lowtag-mask) ndescr) - (inst and words ndescr words) - (inst srl type word-shift ndescr) - - (pseudo-atomic () - (inst bis alloc-tn other-pointer-lowtag result) - (inst addq alloc-tn words alloc-tn) - (storew ndescr result 0 other-pointer-lowtag) - (storew length result vector-length-slot other-pointer-lowtag))) diff --git a/src/assembly/alpha/assem-rtns.lisp b/src/assembly/alpha/assem-rtns.lisp deleted file mode 100644 index f1548ea68d..0000000000 --- a/src/assembly/alpha/assem-rtns.lisp +++ /dev/null @@ -1,229 +0,0 @@ -;;;; This software is part of the SBCL system. See the README file for -;;;; more information. -;;;; -;;;; This software is derived from the CMU CL system, which was -;;;; written at Carnegie Mellon University and released into the -;;;; public domain. The software is in the public domain and is -;;;; provided with absolutely no warranty. See the COPYING and CREDITS -;;;; files for more information. - -(in-package "SB-VM") - -;;;; Return-multiple with other than one value - -#+sb-assembling ;; We don't want a vop for this one. -(define-assembly-routine - (return-multiple - (:return-style :none)) - - ;; These four are really arguments. - ((:temp nvals any-reg nargs-offset) - (:temp vals any-reg nl0-offset) - (:temp ocfp any-reg nl1-offset) - (:temp lra descriptor-reg lra-offset) - - ;; These are just needed to facilitate the transfer - (:temp lip interior-reg lip-offset) - (:temp count any-reg nl2-offset) - (:temp dst any-reg nl4-offset) - (:temp temp descriptor-reg l0-offset) - - ;; These are needed so we can get at the register args. - (:temp a0 descriptor-reg a0-offset) - (:temp a1 descriptor-reg a1-offset) - (:temp a2 descriptor-reg a2-offset) - (:temp a3 descriptor-reg a3-offset) - (:temp a4 descriptor-reg a4-offset) - (:temp a5 descriptor-reg a5-offset)) - - ;; Note, because of the way the RETURN-MULTIPLE VOP is written, we - ;; can assume that we are never called with NVALS == 1 and that A0 - ;; has already been loaded. - (inst ble nvals default-a0-and-on) - (inst ldl a1 (* 1 n-word-bytes) vals) - (inst subq nvals (fixnumize 2) count) - (inst ble count default-a2-and-on) - (inst ldl a2 (* 2 n-word-bytes) vals) - (inst subq nvals (fixnumize 3) count) - (inst ble count default-a3-and-on) - (inst ldl a3 (* 3 n-word-bytes) vals) - (inst subq nvals (fixnumize 4) count) - (inst ble count default-a4-and-on) - (inst ldl a4 (* 4 n-word-bytes) vals) - (inst subq nvals (fixnumize 5) count) - (inst ble count default-a5-and-on) - (inst ldl a5 (* 5 n-word-bytes) vals) - (inst subq nvals (fixnumize 6) count) - (inst ble count done) - - ;; Copy the remaining args to the top of the stack. - (inst addq vals (* 6 n-word-bytes) vals) - (inst addq cfp-tn (* 6 n-word-bytes) dst) - - LOOP - (inst ldl temp 0 vals) - (inst addq vals n-word-bytes vals) - (inst stl temp 0 dst) - (inst subq count (fixnumize 1) count) - (inst addq dst n-word-bytes dst) - (inst bne count loop) - - (inst br zero-tn done) - - DEFAULT-A0-AND-ON - (inst move null-tn a0) - (inst move null-tn a1) - DEFAULT-A2-AND-ON - (inst move null-tn a2) - DEFAULT-A3-AND-ON - (inst move null-tn a3) - DEFAULT-A4-AND-ON - (inst move null-tn a4) - DEFAULT-A5-AND-ON - (inst move null-tn a5) - DONE - - ;; Clear the stack. - (move cfp-tn ocfp-tn) - (move ocfp cfp-tn) - (inst addq ocfp-tn nvals csp-tn) - - ;; Return. - (lisp-return lra lip)) - -;;;; tail-call-variable - -#+sb-assembling ;; no vop for this one either -(define-assembly-routine - (tail-call-variable - (:return-style :none)) - - ;; These are really args. - ((:temp args any-reg nl0-offset) - (:temp lexenv descriptor-reg lexenv-offset) - - ;; We need to compute this - (:temp nargs any-reg nargs-offset) - - ;; These are needed by the blitting code. - (:temp src any-reg nl1-offset) - (:temp dst any-reg nl2-offset) - (:temp count any-reg cfunc-offset) - (:temp temp descriptor-reg l0-offset) - - ;; Needed for the jump - (:temp lip interior-reg lip-offset) - - ;; These are needed so we can get at the register args. - (:temp a0 descriptor-reg a0-offset) - (:temp a1 descriptor-reg a1-offset) - (:temp a2 descriptor-reg a2-offset) - (:temp a3 descriptor-reg a3-offset) - (:temp a4 descriptor-reg a4-offset) - (:temp a5 descriptor-reg a5-offset)) - - - ;; Calculate NARGS (as a fixnum) - (inst subq csp-tn args nargs) - - ;; Load the argument regs (must do this now, 'cause the blt might - ;; trash these locations) - (inst ldl a0 (* 0 n-word-bytes) args) - (inst ldl a1 (* 1 n-word-bytes) args) - (inst ldl a2 (* 2 n-word-bytes) args) - (inst ldl a3 (* 3 n-word-bytes) args) - (inst ldl a4 (* 4 n-word-bytes) args) - (inst ldl a5 (* 5 n-word-bytes) args) - - ;; Calc SRC, DST, and COUNT - (inst subq nargs (fixnumize register-arg-count) count) - (inst addq args (* n-word-bytes register-arg-count) src) - (inst ble count done) - (inst addq cfp-tn (* n-word-bytes register-arg-count) dst) - - LOOP - ;; Copy one arg. - (inst ldl temp 0 src) - (inst addq src n-word-bytes src) - (inst stl temp 0 dst) - (inst subq count (fixnumize 1) count) - (inst addq dst n-word-bytes dst) - (inst bgt count loop) - - DONE - ;; We are done. Do the jump. - (progn - (loadw temp lexenv closure-fun-slot fun-pointer-lowtag) - (lisp-jump temp lip))) - - -;;;; non-local exit noise - -(define-assembly-routine - (unwind - (:translate %unwind) - (:policy :fast-safe)) - ((:arg block (any-reg descriptor-reg) a0-offset) - (:arg start (any-reg descriptor-reg) ocfp-offset) - (:arg count (any-reg descriptor-reg) nargs-offset) - (:temp lip interior-reg lip-offset) - (:temp lra descriptor-reg lra-offset) - (:temp cur-uwp any-reg nl0-offset) - (:temp next-uwp any-reg nl1-offset) - (:temp target-uwp any-reg nl2-offset) - (:temp temp1 non-descriptor-reg nl3-offset)) - (declare (ignore start count)) - - (load-symbol-value cur-uwp *current-unwind-protect-block*) - (let ((error (generate-error-code nil 'invalid-unwind-error))) - (inst beq block error)) - - (loadw target-uwp block unwind-block-uwp-slot) - (inst cmpeq cur-uwp target-uwp temp1) - (inst beq temp1 do-uwp) - - (move block cur-uwp) - - do-exit - - (loadw cfp-tn cur-uwp unwind-block-cfp-slot) - (loadw code-tn cur-uwp unwind-block-code-slot) - (progn - (loadw lra cur-uwp unwind-block-entry-pc-slot) - (lisp-return lra lip :frob-code nil)) - - do-uwp - - (loadw next-uwp cur-uwp unwind-block-uwp-slot) - (store-symbol-value next-uwp *current-unwind-protect-block*) - (inst br zero-tn do-exit)) - -(define-assembly-routine - throw - ((:arg target descriptor-reg a0-offset) - (:arg start any-reg ocfp-offset) - (:arg count any-reg nargs-offset) - (:temp catch any-reg a1-offset) - (:temp tag descriptor-reg a2-offset) - (:temp temp1 non-descriptor-reg nl0-offset)) - - (progn start count) ; We just need them in the registers. - - (load-symbol-value catch *current-catch-block*) - - loop - - (let ((error (generate-error-code nil 'unseen-throw-tag-error target))) - (inst beq catch error)) - - (loadw tag catch catch-block-tag-slot) - (inst cmpeq tag target temp1) - (inst bne temp1 exit) - (loadw catch catch catch-block-previous-catch-slot) - (inst br zero-tn loop) - - exit - - (move catch target) - (inst li (make-fixup 'unwind :assembly-routine) temp1) - (inst jmp zero-tn temp1 (make-fixup 'unwind :assembly-routine))) diff --git a/src/assembly/alpha/support.lisp b/src/assembly/alpha/support.lisp deleted file mode 100644 index e1025f9e99..0000000000 --- a/src/assembly/alpha/support.lisp +++ /dev/null @@ -1,69 +0,0 @@ -;;;; the machine-specific support routines needed by the file assembler - -;;;; This software is part of the SBCL system. See the README file for -;;;; more information. -;;;; -;;;; This software is derived from the CMU CL system, which was -;;;; written at Carnegie Mellon University and released into the -;;;; public domain. The software is in the public domain and is -;;;; provided with absolutely no warranty. See the COPYING and CREDITS -;;;; files for more information. - -(in-package "SB-VM") - -(defun generate-call-sequence (name style vop options) - (declare (ignore options)) - (ecase style - ((:raw :none) - (values - `((inst li (make-fixup ',name :assembly-routine) temp) - (inst jsr lip-tn temp)) - '((:temporary (:sc non-descriptor-reg) temp)) - nil)) - (:full-call - (let ((temp (make-symbol "TEMP")) - (nfp-save (make-symbol "NFP-SAVE")) - (lra (make-symbol "LRA"))) - (values - `((let ((lra-label (gen-label)) - (cur-nfp (current-nfp-tn ,vop))) - (when cur-nfp - (store-stack-tn ,nfp-save cur-nfp)) - (inst compute-lra-from-code ,lra code-tn lra-label ,temp) - (note-next-instruction ,vop :call-site) - ; here - (inst li (make-fixup ',name :assembly-routine) temp1) - (inst jsr lip-tn temp1 (make-fixup ',name :assembly-routine)) - (emit-return-pc lra-label) - (note-this-location ,vop :single-value-return) - (without-scheduling () - (move ocfp-tn csp-tn) - (inst nop)) - (inst compute-code-from-lra code-tn code-tn - lra-label ,temp) - (when cur-nfp - (maybe-load-stack-nfp-tn cur-nfp ,nfp-save temp1)))) - `((:temporary (:scs (non-descriptor-reg) :from (:eval 0) :to (:eval 1)) - ,temp) - (:temporary (:sc descriptor-reg :offset lra-offset - :from (:eval 0) :to (:eval 1)) - ,lra) - (:temporary (:scs (control-stack) :offset nfp-save-offset) - ,nfp-save) - (:temporary (:scs (non-descriptor-reg)) temp1) - (:save-p t))))))) - -(defun generate-return-sequence (style) - (ecase style - (:raw - `((inst ret zero-tn lip-tn))) - (:full-call - `((lisp-return (make-random-tn :kind :normal - :sc (sc-or-lose - 'descriptor-reg) - :offset lra-offset) - lip-tn :offset 2))) - (:none))) - -(defun return-machine-address (scp) - (context-register scp lip-offset)) diff --git a/src/assembly/alpha/tramps.lisp b/src/assembly/alpha/tramps.lisp deleted file mode 100644 index fb925b43e3..0000000000 --- a/src/assembly/alpha/tramps.lisp +++ /dev/null @@ -1,80 +0,0 @@ -;;;; Undefined-function and closure trampoline definitions - -;;;; This software is part of the SBCL system. See the README file for -;;;; more information. - -(in-package "SB-VM") - -(define-assembly-routine - (xundefined-tramp (:return-style :none) - (:align n-lowtag-bits) - (:export undefined-tramp - (undefined-tramp-tagged - (+ xundefined-tramp - fun-pointer-lowtag)))) - ((:temp fdefn-tn descriptor-reg fdefn-offset) - (:temp nl0-tn non-descriptor-reg nl0-offset) - (:temp ocfp-tn non-descriptor-reg ocfp-offset) - (:temp lra-tn descriptor-reg lra-offset)) - (inst lword simple-fun-widetag) ;; header - (inst lword (make-fixup 'undefined-tramp-tagged - :assembly-routine)) ;; self - (dotimes (i (- simple-fun-insts-offset 2)) - (inst lword nil-value)) - - ;; If we are called with stack arguments (or in a tail-call - ;; scenario), we end up with an allocated stack frame, but the frame - ;; link information is uninitialized. Fix things by allocating and - ;; initializing our stack frame "properly". - - UNDEFINED-TRAMP - (inst lda code-tn - (- fun-pointer-lowtag - (ash simple-fun-insts-offset word-shift)) - lip-tn) - - (inst cmpule nargs-tn (fixnumize register-arg-count) nl0-tn) - (inst beq nl0-tn NO-STACK-ARGS) - (inst addq cfp-tn (fixnumize register-arg-count) csp-tn) - (inst br zero-tn FINISH-FRAME-SETUP) - - NO-STACK-ARGS - (inst addq cfp-tn nargs-tn csp-tn) - - FINISH-FRAME-SETUP - (storew ocfp-tn cfp-tn ocfp-save-offset) - (storew lra-tn cfp-tn lra-save-offset) - (error-call nil 'undefined-fun-error fdefn-tn)) - -(define-assembly-routine - (closure-tramp (:return-style :none) - (:align n-lowtag-bits)) - ((:temp fdefn-tn descriptor-reg fdefn-offset) - (:temp lexenv-tn descriptor-reg lexenv-offset)) - (loadw lexenv-tn fdefn-tn fdefn-fun-slot other-pointer-lowtag) - (loadw code-tn lexenv-tn closure-fun-slot fun-pointer-lowtag) - (inst lda lip-tn (- (ash simple-fun-insts-offset word-shift) - fun-pointer-lowtag) - code-tn) - (inst jsr zero-tn lip-tn 1)) - -(define-assembly-routine - (xfuncallable-instance-tramp (:return-style :none) - (:align n-lowtag-bits) - (:export (funcallable-instance-tramp - (+ xfuncallable-instance-tramp - fun-pointer-lowtag)))) - ((:temp code-tn descriptor-reg code-offset) - (:temp lexenv-tn descriptor-reg lexenv-offset)) - (inst lword simple-fun-widetag) - (inst lword (make-fixup 'funcallable-instance-tramp - :assembly-routine)) - (dotimes (i (- simple-fun-insts-offset 2)) - (inst lword nil-value)) - - (loadw lexenv-tn lexenv-tn funcallable-instance-function-slot fun-pointer-lowtag) - (loadw code-tn lexenv-tn closure-fun-slot fun-pointer-lowtag) - (inst lda lip-tn (- (ash simple-fun-insts-offset word-shift) - fun-pointer-lowtag) - code-tn) - (inst jsr zero-tn lip-tn 1)) diff --git a/src/assembly/arm/assem-rtns.lisp b/src/assembly/arm/assem-rtns.lisp index 92e28b1a7d..5e803bf73c 100644 --- a/src/assembly/arm/assem-rtns.lisp +++ b/src/assembly/arm/assem-rtns.lisp @@ -35,7 +35,7 @@ ;; We don't need to copy stack values at this point, so default any ;; unsupplied values that should be in arg-passing registers. First - ;; piece of black magic: A computed jump. + ;; piece of deep magic: A computed jump. (inst add pc-tn pc-tn nvals) ;; Eat a word of padding for the computed jump. (inst word 0) @@ -47,7 +47,7 @@ (inst mov r2 null-tn) ;; We've defaulted any unsupplied parameters, but now we need to - ;; load the supplied parameters. Second piece of black magic: A + ;; load the supplied parameters. Second piece of deep magic: A ;; hairier computed jump. (inst rsb count nvals (fixnumize 2)) (inst add pc-tn pc-tn count) diff --git a/src/assembly/arm/support.lisp b/src/assembly/arm/support.lisp index 23584a6552..3cb46544fc 100644 --- a/src/assembly/arm/support.lisp +++ b/src/assembly/arm/support.lisp @@ -75,7 +75,3 @@ :offset lip-offset) :offset 2))) (:none))) - -#-sb-xc-host ; CONTEXT-REGISTER is not defined at xc-time -(defun return-machine-address (scp) - (context-register scp lr-offset)) diff --git a/src/assembly/arm64/alloc.lisp b/src/assembly/arm64/alloc.lisp index 008f065dd0..2050b24f4b 100644 --- a/src/assembly/arm64/alloc.lisp +++ b/src/assembly/arm64/alloc.lisp @@ -5,7 +5,7 @@ (:translate ensure-symbol-tls-index) (:result-types positive-fixnum) (:policy :fast-safe)) - ((:arg symbol (descriptor-reg) r0-offset) + ((:arg symbol (descriptor-reg) r8-offset) (:temp free-tls-index (non-descriptor-reg) nl1-offset) (:res result (unsigned-reg) nl0-offset)) diff --git a/src/assembly/arm64/array.lisp b/src/assembly/arm64/array.lisp index b896f332df..7267a743d2 100644 --- a/src/assembly/arm64/array.lisp +++ b/src/assembly/arm64/array.lisp @@ -17,35 +17,32 @@ (:arg-types positive-fixnum positive-fixnum positive-fixnum)) - ((:arg type any-reg r0-offset) + ((:arg type any-reg r2-offset) (:arg length any-reg r1-offset) - (:arg words any-reg r2-offset) + (:arg words any-reg r0-offset) (:res result descriptor-reg r0-offset) (:temp ndescr non-descriptor-reg nl2-offset) (:temp pa-flag non-descriptor-reg nl3-offset) (:temp lra-save non-descriptor-reg nl5-offset) - (:temp vector descriptor-reg r8-offset) - (:temp lr interior-reg lr-offset)) + (:temp lr non-descriptor-reg lr-offset)) (pseudo-atomic (pa-flag) (inst lsl ndescr words (- word-shift n-fixnum-tag-bits)) (inst add ndescr ndescr (* (1+ vector-data-offset) n-word-bytes)) (inst and ndescr ndescr (bic-mask lowtag-mask)) ; double-word align (move lra-save lr) ;; The call to alloc_tramp will overwrite LR - (allocation nil ndescr other-pointer-lowtag vector - :flag-tn pa-flag :lip nil) ;; keep LR intact as per above + (allocation nil ndescr other-pointer-lowtag result + :flag-tn pa-flag) (move lr lra-save) (inst lsr ndescr type n-fixnum-tag-bits) - (storew ndescr vector 0 other-pointer-lowtag) ;; Touch the last element, to ensure that null-terminated strings ;; passed to C do not cause a WP violation in foreign code. ;; Do that before storing length, since nil-arrays don't have any ;; space, but may have non-zero length. #-gencgc (storew zr-tn pa-flag -1) - (storew length vector vector-length-slot other-pointer-lowtag) - (move result vector))) + (storew-pair ndescr 0 length vector-length-slot tmp-tn))) (define-assembly-routine (allocate-vector-on-stack (:policy :fast-safe) @@ -58,21 +55,18 @@ (:res result descriptor-reg r0-offset) (:temp temp non-descriptor-reg nl0-offset)) - (pseudo-atomic (temp) - (inst lsr temp type n-fixnum-tag-bits) - (inst lsl words words (- word-shift n-fixnum-tag-bits)) - (inst add words words (* (1+ vector-data-offset) n-word-bytes)) - (inst and words words (bic-mask lowtag-mask)) ; double-word align - (allocation nil words nil result :stack-allocate-p t) + (inst lsr temp type n-fixnum-tag-bits) + (inst lsl words words (- word-shift n-fixnum-tag-bits)) + (inst add words words (* (1+ vector-data-offset) n-word-bytes)) + (inst and words words (bic-mask lowtag-mask)) ; double-word align + (allocation nil words other-pointer-lowtag result :stack-allocate-p t) - (inst stp temp length (@ result)) - ;; Zero fill - (assemble () - ;; The header word has already been set, skip it. - (inst add temp result (* n-word-bytes 2)) - (inst add words result words) - LOOP - (inst stp zr-tn zr-tn (@ temp (* n-word-bytes 2) :post-index)) - (inst cmp temp words) - (inst b :lt LOOP)) - (inst orr result result other-pointer-lowtag))) + (inst stp temp length (@ tmp-tn)) + ;; Zero fill + ;; The header word has already been set, skip it. + (inst add temp tmp-tn (* n-word-bytes 2)) + (inst add words tmp-tn words) + LOOP + (inst stp zr-tn zr-tn (@ temp (* n-word-bytes 2) :post-index)) + (inst cmp temp words) + (inst b :lt LOOP)) diff --git a/src/assembly/arm64/assem-rtns.lisp b/src/assembly/arm64/assem-rtns.lisp index 189933dc6f..1939fdd18c 100644 --- a/src/assembly/arm64/assem-rtns.lisp +++ b/src/assembly/arm64/assem-rtns.lisp @@ -11,7 +11,7 @@ ((:temp nvals any-reg nargs-offset) (:temp vals any-reg nl1-offset) (:temp old-fp any-reg nl2-offset) - (:temp lra descriptor-reg r6-offset) + (:temp lra non-descriptor-reg lr-offset) ;; These are just needed to facilitate the transfer (:temp count any-reg nl3-offset) @@ -23,8 +23,7 @@ (:temp r0 descriptor-reg r0-offset) (:temp r1 descriptor-reg r1-offset) (:temp r2 descriptor-reg r2-offset) - (:temp r3 descriptor-reg r3-offset) - (:temp lip interior-reg lr-offset)) + (:temp r3 descriptor-reg r3-offset)) ;; Note, because of the way the return-multiple vop is written, we ;; can assume that we are never called with nvals == 1 (not that it @@ -69,11 +68,50 @@ (inst add csp-tn ocfp-tn (lsl nvals (- word-shift n-fixnum-tag-bits))) ;; Return. - (lisp-return lra lip :multiple-values)) + (lisp-return lra :multiple-values)) ;;;; tail-call-variable. - -#+sb-assembling ;; no vop for this one either. +(defun prepare-for-tail-call-variable (nargs args count dest temp r0 r1 r2 r3) + (assemble () + ;; We're in a tail-call scenario, so we use the existing LRA and + ;; OCFP, both already set up in the stack frame. We have a set of + ;; arguments, represented as the address of the first argument + ;; (ARGS) and the address just beyond the last argument (CSP-TN), + ;; and need to set up the arg-passing-registers, any stack arguments + ;; (the fourth and subsequent arguments, if such exist), and the + ;; total arg count (NARGS). + + ;; Calculate NARGS + (inst sub nargs csp-tn args) + + ;; Load the argument regs (must do this now, 'cause the blt might + ;; trash these locations, and we need ARGS to be dead for the blt) + (inst ldp r0 r1 (@ args)) + (inst ldp r2 r3 (@ args (* n-word-bytes 2))) + + ;; ARGS is now dead, we access the remaining arguments by offset + ;; from CSP-TN. + + ;; Figure out how many arguments we really need to shift. + (inst subs count nargs (* register-arg-count n-word-bytes)) + ;; If there aren't any stack args then we're done. + (inst b :le DONE) + + ;; Find where our shifted arguments need to go. + (inst add dest cfp-tn nargs) + + (inst neg count count) + LOOP + ;; Copy one arg. + (inst ldr temp (@ csp-tn count)) + (inst str temp (@ dest count)) + (inst adds count count n-word-bytes) + (inst b :ne LOOP) + + DONE + (inst asr nargs nargs (- word-shift n-fixnum-tag-bits)))) + +#+sb-assembling (define-assembly-routine (tail-call-variable (:return-style :none)) @@ -88,8 +126,8 @@ ;; These are needed by the blitting code. (:temp dest any-reg nl2-offset) ;; Not live concurrent with ARGS. (:temp count any-reg nl3-offset) - (:temp temp descriptor-reg r8-offset) - (:temp lip interior-reg lr-offset) + (:temp temp descriptor-reg r9-offset) + (:temp lr non-descriptor-reg lr-offset) ;; These are needed so we can get at the register args. (:temp r0 descriptor-reg r0-offset) @@ -97,56 +135,81 @@ (:temp r2 descriptor-reg r2-offset) (:temp r3 descriptor-reg r3-offset)) - ;; We're in a tail-call scenario, so we use the existing LRA and - ;; OCFP, both already set up in the stack frame. We have a set of - ;; arguments, represented as the address of the first argument - ;; (ARGS) and the address just beyond the last argument (CSP-TN), - ;; and need to set up the arg-passing-registers, any stack arguments - ;; (the fourth and subsequent arguments, if such exist), and the - ;; total arg count (NARGS). + (prepare-for-tail-call-variable nargs args count dest temp r0 r1 r2 r3) + (loadw lr lexenv closure-fun-slot fun-pointer-lowtag) + (lisp-jump lr)) - ;; Calculate NARGS - (inst sub nargs csp-tn args) +#+sb-assembling +(define-assembly-routine + (tail-call-callable-variable + (:return-style :none)) - ;; Load the argument regs (must do this now, 'cause the blt might - ;; trash these locations, and we need ARGS to be dead for the blt) - (inst ldp r0 r1 (@ args)) - (inst ldp r2 r3 (@ args (* n-word-bytes 2))) + ;; These are really args. + ((:temp args any-reg nl2-offset) + (:temp lexenv descriptor-reg lexenv-offset) - ;; ARGS is now dead, we access the remaining arguments by offset - ;; from CSP-TN. + ;; We need to compute this + (:temp nargs any-reg nargs-offset) - ;; Figure out how many arguments we really need to shift. - (inst subs count nargs (* register-arg-count n-word-bytes)) - ;; If there aren't any stack args then we're done. - (inst b :le DONE) + ;; These are needed by the blitting code. + (:temp dest any-reg nl2-offset) ;; Not live concurrent with ARGS. + (:temp count any-reg nl3-offset) + (:temp temp descriptor-reg r9-offset) + (:temp lr non-descriptor-reg lr-offset) - ;; Find where our shifted arguments need to go. - (inst add dest cfp-tn nargs) + ;; These are needed so we can get at the register args. + (:temp r0 descriptor-reg r0-offset) + (:temp r1 descriptor-reg r1-offset) + (:temp r2 descriptor-reg r2-offset) + (:temp r3 descriptor-reg r3-offset)) - (inst neg count count) - LOOP - ;; Copy one arg. - (inst ldr temp (@ csp-tn count)) - (inst str temp (@ dest count)) - (inst adds count count n-word-bytes) - (inst b :ne LOOP) + (prepare-for-tail-call-variable nargs args count dest temp r0 r1 r2 r3) + (inst and tmp-tn lexenv lowtag-mask) + (inst cmp tmp-tn fun-pointer-lowtag) + (inst b :eq call) + (inst b (entry-point-label 'tail-call-symbol)) + call + (loadw lr lexenv closure-fun-slot fun-pointer-lowtag) + (lisp-jump lr)) + +#+sb-assembling +(define-assembly-routine (call-symbol + (:return-style :none) + (:export tail-call-symbol)) + ((:temp fun (any-reg descriptor-reg) lexenv-offset) + (:temp temp (any-reg descriptor-reg) nl1-offset)) + (inst str lr-tn (@ cfp-tn 8)) + TAIL-CALL-SYMBOL + (inst and temp fun lowtag-mask) + (inst cmp temp other-pointer-lowtag) + (inst b :ne not-callable) + + (inst ldrb temp (@ fun (- other-pointer-lowtag))) + (inst cmp temp symbol-widetag) + (inst b :ne not-callable) + + (loadw temp fun symbol-fdefn-slot other-pointer-lowtag) + (inst cbz temp undefined) + (move fun temp) + (loadw lr-tn fun fdefn-raw-addr-slot other-pointer-lowtag) + (inst add lr-tn lr-tn 4) + (inst br lr-tn) + UNDEFINED + (inst b (entry-point-label 'undefined-tramp)) + NOT-CALLABLE + (inst cmp fun null-tn) ;; NIL doesn't have SYMBOL-WIDETAG + (inst b :eq undefined) + + (emit-error-break nil error-trap (error-number-or-lose 'sb-kernel::object-not-callable-error) + (list fun))) - DONE - ;; The call frame is all set up, so all that remains is to jump to - ;; the new function. We need a boxed register to hold the actual - ;; function object (in case of closure functions or funcallable - ;; instances) - (inst asr nargs nargs (- word-shift n-fixnum-tag-bits)) - (loadw temp lexenv closure-fun-slot fun-pointer-lowtag) - (lisp-jump temp lip)) ;;;; Non-local exit noise. (define-assembly-routine (throw - (:return-style :none)) + (:return-style :none)) ((:arg target descriptor-reg r0-offset) - (:arg start any-reg r8-offset) + (:arg start any-reg r9-offset) (:arg count any-reg nargs-offset) (:temp catch any-reg r1-offset) (:temp tag descriptor-reg r2-offset)) @@ -156,7 +219,18 @@ LOOP - (let ((error (generate-error-code nil 'unseen-throw-tag-error target))) + (let ((error (gen-label))) + (assemble (:elsewhere) + (emit-label error) + + ;; Fake up a stack frame so that backtraces come out right. + (inst mov ocfp-tn cfp-tn) + (inst mov cfp-tn csp-tn) + (inst stp ocfp-tn lr-tn (@ csp-tn 16 :post-index)) + + (emit-error-break nil error-trap + (error-number-or-lose 'unseen-throw-tag-error) + (list target))) (inst cbz catch error)) (loadw-pair tmp-tn catch-block-previous-catch-slot tag catch-block-tag-slot catch) @@ -166,49 +240,75 @@ (inst b LOOP) DONE (move target catch) ;; TARGET coincides with UNWIND's BLOCK argument - (inst b (make-fixup 'unwind :assembly-routine))) + (inst b (entry-point-label 'unwind))) (define-assembly-routine (unwind - (:return-style :none) (:translate %unwind) - (:policy :fast-safe)) + (:policy :fast-safe) + (:return-style :none)) ((:arg block (any-reg descriptor-reg) r0-offset) - (:arg start (any-reg descriptor-reg) r8-offset) + (:arg start (any-reg descriptor-reg) r9-offset) (:arg count (any-reg descriptor-reg) nargs-offset) (:temp ocfp any-reg ocfp-offset) - (:temp lra descriptor-reg lexenv-offset) (:temp cur-uwp any-reg nl2-offset) - (:temp lip interior-reg lr-offset) + (:temp lr non-descriptor-reg lr-offset) (:temp next-uwp any-reg nl3-offset) ;; for unbind-to-here (:temp where any-reg r1-offset) (:temp symbol descriptor-reg r2-offset) (:temp value descriptor-reg r3-offset)) - (declare (ignore start count)) + AGAIN (let ((error (generate-error-code nil 'invalid-unwind-error))) (inst cbz block error)) (load-tl-symbol-value cur-uwp *current-unwind-protect-block*) (loadw ocfp block unwind-block-uwp-slot) - (inst mov next-uwp cur-uwp) (inst cmp cur-uwp ocfp) - (inst b :eq EQ) - (loadw next-uwp cur-uwp unwind-block-uwp-slot) - EQ - (inst csel cur-uwp block cur-uwp :eq) + (inst b :eq DO-EXIT) + + (inst stp block start (@ csp-tn 32 :post-index)) + (inst adr next-uwp RET) ;; Avoids saving the link register on uwp entry + (inst stp count next-uwp (@ csp-tn -16)) + + ;; Need to perform unbinding before unlinking the UWP so that if + ;; interrupted here it can still run the clean up form. While the + ;; cleanup form itself cannot be protected from interrupts (can't + ;; run it twice) one of the variables being unbound can be + ;; *interrupts-enabled* (loadw where cur-uwp unwind-block-bsp-slot) (unbind-to-here where symbol value tmp-tn) + ;; Set next unwind protect context. + + (loadw next-uwp cur-uwp unwind-block-uwp-slot) (store-tl-symbol-value next-uwp *current-unwind-protect-block*) - (loadw-pair cfp-tn unwind-block-cfp-slot code-tn unwind-block-code-slot cur-uwp) + (loadw-pair cfp-tn unwind-block-cfp-slot lr unwind-block-entry-pc-slot cur-uwp) (loadw next-uwp cur-uwp unwind-block-current-catch-slot) (store-tl-symbol-value next-uwp *current-catch-block*) - - (loadw-pair tmp-tn unwind-block-nfp-slot next-uwp unwind-block-nsp-slot cur-uwp) + (loadw-pair (make-random-tn :kind :normal :sc (sc-or-lose 'any-reg) :offset nfp-offset) + unwind-block-nfp-slot next-uwp unwind-block-nsp-slot cur-uwp) (inst mov-sp nsp-tn next-uwp) - (inst cbz tmp-tn SKIP) - (inst mov (make-random-tn :kind :normal :sc (sc-or-lose 'any-reg) :offset nfp-offset) tmp-tn) - SKIP + (inst br lr) + RET + (inst ldr count (@ csp-tn -8 :pre-index)) + (inst ldp block start (@ csp-tn -16 :pre-index)) + (inst b AGAIN) + + DO-EXIT + (loadw where block unwind-block-bsp-slot) + (unbind-to-here where symbol value tmp-tn) + (loadw-pair cfp-tn unwind-block-cfp-slot lr unwind-block-entry-pc-slot block) + (loadw next-uwp block unwind-block-current-catch-slot) + (store-tl-symbol-value next-uwp *current-catch-block*) + (loadw-pair (make-random-tn :kind :normal :sc (sc-or-lose 'any-reg) :offset nfp-offset) + unwind-block-nfp-slot next-uwp unwind-block-nsp-slot block) + (inst mov-sp nsp-tn next-uwp) + + (inst br lr)) - (loadw lra cur-uwp unwind-block-entry-pc-slot) - (lisp-return lra lip :known)) +(define-vop () + (:translate %continue-unwind) + (:policy :fast-safe) + (:generator 0 + (inst ldr lr-tn (@ csp-tn -8 :pre-index)) + (inst ret))) diff --git a/src/assembly/arm64/support.lisp b/src/assembly/arm64/support.lisp index 706e8be69a..37b31befe0 100644 --- a/src/assembly/arm64/support.lisp +++ b/src/assembly/arm64/support.lisp @@ -15,64 +15,20 @@ (declare (ignore options vop)) (ecase style ((:none :raw) - (values - `((progn - ,@(if (eq style :none) - `((load-inline-constant tmp-tn '(:fixup ,name :assembly-routine)) - (inst br tmp-tn)) - `((load-inline-constant lr-tn '(:fixup ,name :assembly-routine)) - (inst blr lr-tn))))) - nil)) - #+(or) - (:full-call - (let ((temp (make-symbol "TEMP")) - (jump (make-symbol "JUMP")) - (nfp-save (make-symbol "NFP-SAVE")) - (lra (make-symbol "LRA"))) + (let ((lr (gensym))) (values - `((let ((lra-label (gen-label)) - (cur-nfp (current-nfp-tn ,vop))) - (when cur-nfp - (store-stack-tn ,nfp-save cur-nfp)) - (inst compute-lra-from-code ,lra code-tn lra-label ,temp) - (note-next-instruction ,vop :call-site) - (inst lr ,jump (make-fixup ',name :assembly-routine)) - (inst mtlr ,jump) - (inst blr) - (emit-return-pc lra-label) - (note-this-location ,vop :single-value-return) - (without-scheduling () - (move csp-tn ocfp-tn) - (inst nop)) - (inst compute-code-from-lra code-tn lra-tn - lra-label ,temp) - (when cur-nfp - (load-stack-tn cur-nfp ,nfp-save)))) - `((:temporary (:scs (non-descriptor-reg) :from (:eval 0) :to (:eval 1)) - ,temp) - (:temporary (:sc descriptor-reg :offset lra-offset - :from (:eval 0) :to (:eval 1)) - ,lra) - (:temporary (:scs (control-stack) :offset nfp-save-offset) - ,nfp-save) - (:temporary (:sc any-reg) ,jump) - (:save-p :compute-only))))))) + `((progn + ,lr + ,@(if (eq style :none) + `((load-inline-constant tmp-tn '(:fixup ,name :assembly-routine)) + (inst blr tmp-tn)) + `((load-inline-constant ,lr '(:fixup ,name :assembly-routine)) + (inst blr ,lr))))) + `((:temporary (:sc non-descriptor-reg :from (:eval 0) :to (:eval 1) :offset lr-offset) + ,lr))))))) (defun generate-return-sequence (style) (ecase style (:raw `((inst br lr-tn))) - #+(or) - (:full-call - `((lisp-return (make-random-tn :kind :normal - :sc (sc-or-lose 'descriptor-reg ) - :offset lra-offset) - (make-random-tn :kind :normal - :sc (sc-or-lose 'interior-reg ) - :offset lip-offset) - :offset 2))) (:none))) - -#-sb-xc-host ; CONTEXT-REGISTER is not defined at xc-time -(defun return-machine-address (scp) - (context-register scp lr-offset)) diff --git a/src/assembly/arm64/tramps.lisp b/src/assembly/arm64/tramps.lisp index 01071775d0..ec7b442a78 100644 --- a/src/assembly/arm64/tramps.lisp +++ b/src/assembly/arm64/tramps.lisp @@ -6,10 +6,12 @@ (in-package "SB-VM") #+gencgc -(macrolet ((define-alloc-tramp (lisp-name c-name) +(macrolet ((define-alloc-tramp (lisp-name c-name &body process-args) `(define-assembly-routine (,lisp-name (:return-style :none)) ((:temp nl0 unsigned-reg nl0-offset) - (:temp nl1 unsigned-reg nl1-offset)) + (:temp nl1 unsigned-reg nl1-offset) + (:temp nl2 unsigned-reg nl2-offset)) + (declare (ignorable nl1)) (flet ((reg (offset sc) (make-random-tn :kind :normal @@ -51,141 +53,95 @@ (incf offset ,delta))))) (map-pairs stp nsp-tn 0 nl-registers :pre-index -80) (inst mov nl0 tmp-tn) ;; size + (progn ,@process-args) #+sb-thread - (progn - (inst stp cfp-tn csp-tn (@ thread-tn (* thread-control-frame-pointer-slot n-word-bytes))) - (inst str csp-tn (@ thread-tn (* thread-foreign-function-call-active-slot n-word-bytes)))) + (inst stp cfp-tn csp-tn (@ thread-tn (* thread-control-frame-pointer-slot n-word-bytes))) #-sb-thread (progn ;; Each of these loads of a fixup loads the address of a linkage table entry, - ;; that is, if LINKAGE-TABLE-SPACE-START is #xF0200000, then the first load puts + ;; that is, if ALIEN-LINKAGE-TABLE-SPACE-START is #xF0200000, then the first load puts ;; #xF0200000+something, not the address of current_control_frame_pointer, - ;; into register nl1. + ;; into register nl2. ;; This is kinda dumb because first of all we could have calculated the address ;; of the linkage entry instead of loading it. Second, it's unnecessarily ;; double-indirect. I wonder if there's a way to remove double-indirection. ;; The ohly way I can see doing that is for os_link_runtime() to poke bytes ;; into this assembly code in the manner of the system's dynamic loader. - (load-inline-constant nl1 '(:fixup "current_control_frame_pointer" :foreign-dataref)) - (inst ldr nl1 (@ nl1)) ; now load the address of the C variable - (inst str cfp-tn (@ nl1)) - (load-inline-constant nl1 '(:fixup "current_control_stack_pointer" :foreign-dataref)) - (inst ldr nl1 (@ nl1)) ; " - (inst str csp-tn (@ nl1)) - (load-inline-constant nl1 '(:fixup "foreign_function_call_active" :foreign-dataref)) - (inst ldr nl1 (@ nl1)) ; " + (load-inline-constant nl2 '(:fixup "current_control_frame_pointer" :foreign-dataref)) + (inst ldr nl2 (@ nl2)) ; now load the address of the C variable + (inst str cfp-tn (@ nl2)) + (load-inline-constant nl2 '(:fixup "current_control_stack_pointer" :foreign-dataref)) + (inst ldr nl2 (@ nl2)) ; " + (inst str csp-tn (@ nl2)) + (load-inline-constant nl2 '(:fixup "foreign_function_call_active" :foreign-dataref)) + (inst ldr nl2 (@ nl2)) ; " ;; storing NULL ensures at least 1 set bit somewhere in the low 4 bytes - (inst str (32-bit-reg null-tn) (@ nl1))) ; (alien variable is 4 bytes, not 8) + (inst str (32-bit-reg null-tn) (@ nl2))) ; (alien variable is 4 bytes, not 8) ;; Create a new frame (inst add csp-tn csp-tn (+ 32 80)) - (inst stp cfp-tn null-tn (@ csp-tn -112)) - (inst stp code-tn lr-tn (@ csp-tn -96)) + (inst stp cfp-tn lr-tn (@ csp-tn -112)) (map-pairs stp csp-tn -80 lisp-registers) (map-pairs stp nsp-tn 0 float-registers :pre-index -512 :delta 32) - (load-inline-constant nl1 '(:fixup ,c-name :foreign)) - (inst blr nl1) + (load-inline-constant nl2 '(:fixup ,c-name :foreign)) + (inst blr nl2) (map-pairs ldp nsp-tn 480 float-registers :post-index 512 :delta -32) (map-pairs ldp csp-tn -16 lisp-registers :delta -16) - (inst ldr lr-tn (@ csp-tn -88)) + (inst ldr lr-tn (@ csp-tn -104)) (inst sub csp-tn csp-tn (+ 32 80)) ;; deallocate the frame #+sb-thread - (inst str zr-tn (@ thread-tn (* thread-foreign-function-call-active-slot n-word-bytes))) + (inst str zr-tn (@ thread-tn (* thread-control-stack-pointer-slot n-word-bytes))) #-sb-thread (progn - ;; We haven't restored NL1 yet, so it's ok to use as a scratch register here. + ;; We haven't restored NL2 yet, so it's ok to use as a scratch register here. ;; It gets restored just prior to the RET instruction. - (load-inline-constant nl1 '(:fixup "foreign_function_call_active" :foreign-dataref)) - (inst ldr nl1 (@ nl1)) - (inst str (32-bit-reg zr-tn) (@ nl1))) + (load-inline-constant nl2 '(:fixup "foreign_function_call_active" :foreign-dataref)) + (inst ldr nl2 (@ nl2)) + (inst str (32-bit-reg zr-tn) (@ nl2))) (inst mov tmp-tn nl0) ;; result (map-pairs ldp nsp-tn 64 nl-registers :post-index 80 :delta -16) (inst ret))))))) (define-alloc-tramp alloc-tramp "alloc") - (define-alloc-tramp list-alloc-tramp "alloc_list")) + (define-alloc-tramp list-alloc-tramp "alloc_list") + (define-alloc-tramp listify-&rest "listify_rest_arg" + (inst sub nl1 csp-tn tmp-tn))) (define-assembly-routine - (xundefined-tramp (:return-style :none) - (:align n-lowtag-bits) - (:export undefined-tramp - (undefined-tramp-tagged - (+ xundefined-tramp - fun-pointer-lowtag)))) + (undefined-tramp (:return-style :none)) () - HEADER - (inst dword simple-fun-widetag) - (inst dword (make-fixup 'undefined-tramp-tagged - :assembly-routine)) - (dotimes (i (- simple-fun-insts-offset 2)) - (inst dword nil-value)) - - UNDEFINED-TRAMP - (inst adr code-tn header fun-pointer-lowtag) + (inst str lr-tn (@ cfp-tn 8)) (emit-error-break nil cerror-trap (error-number-or-lose 'undefined-fun-error) (list lexenv-tn)) - (loadw code-tn lexenv-tn closure-fun-slot fun-pointer-lowtag) - (inst add lr-tn code-tn (- (* simple-fun-insts-offset n-word-bytes) fun-pointer-lowtag)) - + (loadw lr-tn lexenv-tn closure-fun-slot fun-pointer-lowtag) + (inst add lr-tn lr-tn 4) (inst br lr-tn)) (define-assembly-routine - (xundefined-alien-tramp (:return-style :none) - (:align n-lowtag-bits) - (:export undefined-alien-tramp - (undefined-alien-tramp-tagged - (+ xundefined-alien-tramp - fun-pointer-lowtag)))) - ((:temp r8-tn unsigned-reg r8-offset)) - HEADER - (inst dword simple-fun-widetag) - (inst dword (make-fixup 'undefined-alien-tramp-tagged - :assembly-routine)) - (dotimes (i (- simple-fun-insts-offset 2)) - (inst dword nil-value)) - - UNDEFINED-ALIEN-TRAMP - (inst adr code-tn header fun-pointer-lowtag) - (error-call nil 'undefined-alien-fun-error r8-tn)) + (undefined-alien-tramp (:return-style :none)) + ((:temp r9-tn unsigned-reg r9-offset)) + (inst str lr-tn (@ cfp-tn 8)) + (error-call nil 'undefined-alien-fun-error r9-tn)) (define-assembly-routine - (xclosure-tramp (:return-style :none) - (:align n-lowtag-bits) - (:export closure-tramp - (closure-tramp-tagged - (+ xclosure-tramp - fun-pointer-lowtag)))) + (closure-tramp (:return-style :none)) () - (inst dword simple-fun-widetag) - (inst dword (make-fixup 'closure-tramp-tagged - :assembly-routine)) - (dotimes (i (- simple-fun-insts-offset 2)) - (inst dword nil-value)) - - CLOSURE-TRAMP + (inst str lr-tn (@ cfp-tn 8)) (loadw lexenv-tn lexenv-tn fdefn-fun-slot other-pointer-lowtag) - (loadw code-tn lexenv-tn closure-fun-slot fun-pointer-lowtag) - (inst add lr-tn code-tn (- (* simple-fun-insts-offset n-word-bytes) fun-pointer-lowtag)) + (loadw lr-tn lexenv-tn closure-fun-slot fun-pointer-lowtag) + (inst add lr-tn lr-tn 4) (inst br lr-tn)) (define-assembly-routine - (xfuncallable-instance-tramp (:return-style :none) - (:align n-lowtag-bits) - (:export (funcallable-instance-tramp - (+ xfuncallable-instance-tramp - fun-pointer-lowtag)))) + (funcallable-instance-tramp (:return-style :none)) () - (inst dword simple-fun-widetag) - (inst dword (make-fixup 'funcallable-instance-tramp :assembly-routine)) - (dotimes (i (- simple-fun-insts-offset 2)) - (inst dword nil-value)) - + (inst str lr-tn (@ cfp-tn 8)) (loadw lexenv-tn lexenv-tn funcallable-instance-function-slot fun-pointer-lowtag) - (loadw code-tn lexenv-tn closure-fun-slot fun-pointer-lowtag) - (inst add lr-tn code-tn (- (* simple-fun-insts-offset n-word-bytes) fun-pointer-lowtag)) + (loadw lr-tn lexenv-tn closure-fun-slot fun-pointer-lowtag) + (inst add lr-tn lr-tn 4) (inst br lr-tn)) diff --git a/src/assembly/assemfile.lisp b/src/assembly/assemfile.lisp index 713d8e1fc5..18b967c07f 100644 --- a/src/assembly/assemfile.lisp +++ b/src/assembly/assemfile.lisp @@ -31,11 +31,12 @@ (won nil) (asmstream (make-asmstream)) (*asmstream* asmstream) - (*adjustable-vectors* nil)) + (sb-vm::*adjustable-vectors* nil)) (unwind-protect (let ((sb-xc:*features* (cons :sb-assembling sb-xc:*features*)) (*readtable* sb-cold:*xc-readtable*)) (load (merge-pathnames name (make-pathname :type "lisp"))) + (resolve-ep-labels (asmstream-code-section asmstream)) ;; Reserve space for the jump table. The first word of the table ;; indicates the total length in words, counting the length word itself ;; as a word, and the words comprising jump tables that were registered @@ -48,6 +49,7 @@ (n-data-words ; Space for internal jump tables if needed (loop for ((category . data) . label) across (asmstream-constant-vector asmstream) + do (progn #+host-quirks-ccl label) ; shut up the host when (eq category :jump-table) sum (length data)))) (emit (asmstream-data-section asmstream) `(.lispword ,(+ n-extra-words n-data-words 1)) @@ -68,6 +70,7 @@ (dump-assembler-routines segment (segment-buffer segment) (sb-assem::segment-fixup-notes segment) + (sb-assem::get-allocation-points asmstream) *entry-points* lap-fasl-output)) (setq won t)) @@ -120,6 +123,21 @@ for export in exports collect `(push ,(expand-one-export-spec export) *entry-points*))) +;;; Create a placeholder that will later resolve to the label of an entry point. +;;; This is because we don't know all the names of routines until seeing them. +;;; This is an alternative to using a fixup. It may generate shorter code. +(defun sb-vm::entry-point-label (name) `(sb-assem::entry ,name)) + +(defun resolve-ep-labels (section) + (do ((statement (stmt-next (section-start section)) (stmt-next statement))) + ((null statement)) + (binding* ((patch (member-if (lambda (x) (typep x '(cons (eql sb-assem::entry)))) + (stmt-operands statement)) + :exit-if-null) + (ep (assoc (cadar patch) *entry-points*))) + (aver (and ep (= (third ep) 0))) + (rplaca patch (second ep))))) + (defun expand-align-option (align) (when align `((emit-alignment ,align)))) @@ -157,7 +175,7 @@ (emit-alignment sb-vm:n-lowtag-bits ;; EMIT-LONG-NOP does not exist for (not x86-64) #+x86-64 :long-nop)) - (when *compile-print* + (when cl:*compile-print* (format *error-output* "~S assembled~%" ',name))))) (defun arg-or-res-spec (reg) @@ -226,15 +244,9 @@ :key #'car) (:generator ,cost ,@(mapcar (lambda (arg) - #+(or hppa alpha) `(move ,(reg-spec-name arg) - ,(reg-spec-temp arg)) - #-(or hppa alpha) `(move ,(reg-spec-temp arg) - ,(reg-spec-name arg))) + `(move ,(reg-spec-temp arg) ,(reg-spec-name arg))) args) ,@call-sequence ,@(mapcar (lambda (res) - #+(or hppa alpha) `(move ,(reg-spec-temp res) - ,(reg-spec-name res)) - #-(or hppa alpha) `(move ,(reg-spec-name res) - ,(reg-spec-temp res))) + `(move ,(reg-spec-name res) ,(reg-spec-temp res))) results)))))) diff --git a/src/assembly/hppa/alloc.lisp b/src/assembly/hppa/alloc.lisp deleted file mode 100644 index d702f4d017..0000000000 --- a/src/assembly/hppa/alloc.lisp +++ /dev/null @@ -1,6 +0,0 @@ -(in-package "SB-VM") - -;;; Given that the pseudo-atomic sequence is so short, there is -;;; nothing that qualifies. But we want to keep the file around -;;; in case we decide to add something later. - diff --git a/src/assembly/hppa/arith.lisp b/src/assembly/hppa/arith.lisp deleted file mode 100644 index 819fea9730..0000000000 --- a/src/assembly/hppa/arith.lisp +++ /dev/null @@ -1,296 +0,0 @@ -(in-package "SB-VM") - - -;;;; Multiplication and Division helping routines. - -;;; ?? FIXME: Where are generic-* and generic-/? -#+sb-assembling -(define-assembly-routine - multiply - ((:arg x (signed-reg) nl0-offset) - (:arg y (signed-reg) nl1-offset) - - (:res res (signed-reg) nl2-offset) - - (:temp tmp (unsigned-reg) nl3-offset) - (:temp sign (unsigned-reg) nl4-offset)) - - ;; Determine the sign of the result. - (inst extrs x 0 1 sign :=) - (inst sub zero-tn x x) - (inst extrs y 0 1 tmp :=) - (inst sub zero-tn y y) - (inst xor sign tmp sign) - - ;; Make sure X is less then Y. - (inst comclr x y tmp :<<) - (inst xor x y tmp) - (inst xor x tmp x) - (inst xor y tmp y) - ;; Blow out of here if the result is zero. - (inst comb := x zero-tn done) - (inst li 0 res) - - LOOP - (inst extru x 31 1 zero-tn :ev) - (inst add y res res) - (inst extru x 30 1 zero-tn :ev) - (inst sh1add y res res) - (inst extru x 29 1 zero-tn :ev) - (inst sh2add y res res) - (inst extru x 28 1 zero-tn :ev) - (inst sh3add y res res) - - (inst srl x 4 x) - (inst comb :<> x zero-tn loop) - (inst sll y 4 y) - - DONE - (inst xor res sign res) - (inst sub res sign res)) - -(define-assembly-routine - (truncate) - ((:arg dividend signed-reg nl0-offset) - (:arg divisor signed-reg nl1-offset) - - (:res quo signed-reg nl2-offset) - (:res rem signed-reg nl3-offset)) - ;; Move abs(divident) into quo. - (inst move dividend quo :>=) - (inst sub zero-tn quo quo) - ;; Do one divive-step with -divisor to prime V (use rem as a temp) - (inst sub zero-tn divisor rem) - (inst ds zero-tn rem zero-tn) - ;; Shift the divident/quotient one bit, setting the carry flag. - (inst add quo quo quo) - ;; The first real divive-step. - (inst ds zero-tn divisor rem) - (inst addc quo quo quo) - ;; And 31 more of them. - (dotimes (i 31) - (inst ds rem divisor rem) - (inst addc quo quo quo)) - ;; If the remainder is negative, we need to add the absolute value of the - ;; divisor. - (inst comb :>= rem zero-tn remainder-positive :nullify t) - (inst comclr divisor zero-tn zero-tn :<) - (inst add rem divisor rem :tr) - (inst sub rem divisor rem) - REMAINDER-POSITIVE - ;; Now we have to fix the signs of quo and rem. - (inst xor divisor dividend zero-tn :>=) - (inst sub zero-tn quo quo) - (inst move dividend zero-tn :>=) - (inst sub zero-tn rem rem)) - - -;;;; Generic arithmetic. - -(define-assembly-routine (generic-+ - (:cost 10) - (:return-style :full-call) - (:translate +) - (:policy :safe) - (:save-p t)) - ((:arg x (descriptor-reg any-reg) a0-offset) - (:arg y (descriptor-reg any-reg) a1-offset) - (:res res (descriptor-reg any-reg) a0-offset) - (:temp temp non-descriptor-reg nl0-offset) - (:temp temp1 non-descriptor-reg nl1-offset) - (:temp temp2 non-descriptor-reg nl2-offset) - (:temp lra descriptor-reg lra-offset) - (:temp lip interior-reg lip-offset) - (:temp nargs any-reg nargs-offset) - (:temp ocfp any-reg ocfp-offset)) - ;; If either arg is not fixnum, use two-arg-+ to summarize - (inst or x y temp) - (inst extru temp 31 3 zero-tn :=) - (inst b DO-STATIC-FUN :nullify t) - ;; check for overflow - (inst add x y temp) - (inst xor temp x temp1) - (inst xor temp y temp2) - (inst and temp1 temp2 temp1) - (inst bc :< nil temp1 zero-tn DO-OVERFLOW) - (inst move temp res) - (lisp-return lra :offset 1) - - DO-OVERFLOW - ;; We did overflow, so do the bignum version - (inst sra x n-fixnum-tag-bits temp1) - (inst sra y n-fixnum-tag-bits temp2) - (inst add temp1 temp2 temp) - (with-fixed-allocation (res nil temp2 bignum-widetag - (1+ bignum-digits-offset) nil) - (storew temp res bignum-digits-offset other-pointer-lowtag)) - (lisp-return lra :offset 1) - - DO-STATIC-FUN - (inst ldw (static-fun-offset 'two-arg-+) null-tn lip) - (inst li (fixnumize 2) nargs) - (move cfp-tn ocfp) - (inst bv lip) - (move csp-tn cfp-tn t)) - -(define-assembly-routine (generic-- - (:cost 10) - (:return-style :full-call) - (:translate -) - (:policy :safe) - (:save-p t)) - ((:arg x (descriptor-reg any-reg) a0-offset) - (:arg y (descriptor-reg any-reg) a1-offset) - - (:res res (descriptor-reg any-reg) a0-offset) - - (:temp temp non-descriptor-reg nl0-offset) - (:temp temp1 non-descriptor-reg nl1-offset) - (:temp temp2 non-descriptor-reg nl2-offset) - (:temp lra descriptor-reg lra-offset) - (:temp lip interior-reg lip-offset) - (:temp nargs any-reg nargs-offset) - (:temp ocfp any-reg ocfp-offset)) - ;; If either arg is not fixnum, use two-arg-+ to summarize - (inst or x y temp) - (inst extru temp 31 3 zero-tn :=) - (inst b DO-STATIC-FUN :nullify t) - (inst sub x y temp) - ;; check for overflow - (inst xor x y temp1) - (inst xor x temp temp2) - (inst and temp2 temp1 temp1) - (inst bc :< nil temp1 zero-tn DO-OVERFLOW) - (inst move temp res) - (lisp-return lra :offset 1) - - DO-OVERFLOW - ;; We did overflow, so do the bignum version - (inst sra x n-fixnum-tag-bits temp1) - (inst sra y n-fixnum-tag-bits temp2) - (inst sub temp1 temp2 temp) - (with-fixed-allocation (res nil temp2 bignum-widetag - (1+ bignum-digits-offset) nil) - (storew temp res bignum-digits-offset other-pointer-lowtag)) - (lisp-return lra :offset 1) - - DO-STATIC-FUN - (inst ldw (static-fun-offset 'two-arg--) null-tn lip) - (inst li (fixnumize 2) nargs) - (move cfp-tn ocfp) - (inst bv lip) - (move csp-tn cfp-tn t)) - - -;;;; Comparison routines. - -(macrolet - ((define-cond-assem-rtn (name translate static-fn cond) - `(define-assembly-routine (,name - (:cost 10) - (:return-style :full-call) - (:policy :safe) - (:translate ,translate) - (:save-p t)) - ((:arg x (descriptor-reg any-reg) a0-offset) - (:arg y (descriptor-reg any-reg) a1-offset) - - (:res res descriptor-reg a0-offset) - - (:temp lip interior-reg lip-offset) - (:temp lra descriptor-reg lra-offset) - (:temp nargs any-reg nargs-offset) - (:temp ocfp any-reg ocfp-offset)) - (inst extru x 31 2 zero-tn :=) - (inst b do-static-fn :nullify t) - (inst extru y 31 2 zero-tn :=) - (inst b do-static-fn :nullify t) - - (inst comclr x y zero-tn ,cond) - (inst move null-tn res :tr) - (load-symbol res t) - (lisp-return lra :offset 1) - - DO-STATIC-FN - (inst ldw (static-fun-offset ',static-fn) null-tn lip) - (inst li (fixnumize 2) nargs) - (inst move cfp-tn ocfp) - (inst bv lip) - (inst move csp-tn cfp-tn)))) - - (define-cond-assem-rtn generic-< < two-arg-< :<) - (define-cond-assem-rtn generic-> > two-arg-> :>)) - - -(define-assembly-routine - (generic-eql - (:cost 10) - (:return-style :full-call) - (:policy :safe) - (:translate eql) - (:save-p t)) - ((:arg x (descriptor-reg any-reg) a0-offset) - (:arg y (descriptor-reg any-reg) a1-offset) - - (:res res descriptor-reg a0-offset) - - (:temp lip interior-reg lip-offset) - (:temp lra descriptor-reg lra-offset) - (:temp nargs any-reg nargs-offset) - (:temp ocfp any-reg ocfp-offset)) - - (inst comb := x y return-t :nullify t) - (inst extru x 31 2 zero-tn :<>) - (inst b return-nil :nullify t) - (inst extru y 31 2 zero-tn :=) - (inst b do-static-fn :nullify t) - - RETURN-NIL - (inst move null-tn res) - (lisp-return lra :offset 1) - - DO-STATIC-FN - (inst ldw (static-fun-offset 'eql) null-tn lip) - (inst li (fixnumize 2) nargs) - (inst move cfp-tn ocfp) - (inst bv lip) - (inst move csp-tn cfp-tn) - - RETURN-T - (load-symbol res t)) - -(define-assembly-routine - (generic-= - (:cost 10) - (:return-style :full-call) - (:policy :safe) - (:translate =) - (:save-p t)) - ((:arg x (descriptor-reg any-reg) a0-offset) - (:arg y (descriptor-reg any-reg) a1-offset) - - (:res res descriptor-reg a0-offset) - - (:temp lip interior-reg lip-offset) - (:temp lra descriptor-reg lra-offset) - (:temp nargs any-reg nargs-offset) - (:temp ocfp any-reg ocfp-offset)) - - (inst comb := x y return-t :nullify t) - (inst extru x 31 2 zero-tn :=) - (inst b do-static-fn :nullify t) - (inst extru y 31 2 zero-tn :=) - (inst b do-static-fn :nullify t) - - (inst move null-tn res) - (lisp-return lra :offset 1) - - DO-STATIC-FN - (inst ldw (static-fun-offset 'two-arg-=) null-tn lip) - (inst li (fixnumize 2) nargs) - (inst move cfp-tn ocfp) - (inst bv lip) - (inst move csp-tn cfp-tn) - - RETURN-T - (load-symbol res t)) diff --git a/src/assembly/hppa/array.lisp b/src/assembly/hppa/array.lisp deleted file mode 100644 index b80e5342c6..0000000000 --- a/src/assembly/hppa/array.lisp +++ /dev/null @@ -1 +0,0 @@ -(in-package "SB-VM") diff --git a/src/assembly/hppa/assem-rtns.lisp b/src/assembly/hppa/assem-rtns.lisp deleted file mode 100644 index 2627265235..0000000000 --- a/src/assembly/hppa/assem-rtns.lisp +++ /dev/null @@ -1,201 +0,0 @@ -(in-package "SB-VM") - -;;;; Return-multiple with other than one value - -#+sb-assembling ;; we don't want a vop for this one. -(define-assembly-routine - (return-multiple - (:return-style :none)) - ;; These four are really arguments. - ((:temp nvals any-reg nargs-offset) - (:temp vals any-reg nl0-offset) - (:temp ocfp any-reg nl1-offset) - (:temp lra descriptor-reg lra-offset) - ;; These are just needed to facilitate the transfer - (:temp count any-reg nl2-offset) - (:temp dst any-reg nl3-offset) - (:temp temp descriptor-reg l0-offset) - ;; These are needed so we can get at the register args. - (:temp a0 descriptor-reg a0-offset) - (:temp a1 descriptor-reg a1-offset) - (:temp a2 descriptor-reg a2-offset) - (:temp a3 descriptor-reg a3-offset) - (:temp a4 descriptor-reg a4-offset) - (:temp a5 descriptor-reg a5-offset)) - ;; Note, because of the way the return-multiple vop is written, we can - ;; assume that we are never called with nvals == 1 and that a0 has already - ;; been loaded. ;FIX-lav: look at old hppa , replace comb+addi with addib - (inst comb :<= nvals zero-tn DEFAULT-A0-AND-ON) - (inst addi (- (fixnumize 2)) nvals count) - (inst comb :<= count zero-tn DEFAULT-A2-AND-ON) - (inst ldw (* 1 n-word-bytes) vals a1) - (inst addib :<= (- (fixnumize 1)) count DEFAULT-A3-AND-ON) - (inst ldw (* 2 n-word-bytes) vals a2) - (inst addib :<= (- (fixnumize 1)) count DEFAULT-A4-AND-ON) - (inst ldw (* 3 n-word-bytes) vals a3) - (inst addib :<= (- (fixnumize 1)) count DEFAULT-A5-AND-ON) - (inst ldw (* 4 n-word-bytes) vals a4) - (inst addib :<= (- (fixnumize 1)) count done) - (inst ldw (* 5 n-word-bytes) vals a5) - ;; Copy the remaining args to the top of the stack. - (inst addi (fixnumize register-arg-count) vals vals) - (inst addi (fixnumize register-arg-count) cfp-tn dst) - LOOP - (inst ldwm n-word-bytes vals temp) - (inst addib :<> (- (fixnumize 1)) count LOOP) - (inst stwm temp n-word-bytes dst) - (inst b DONE :nullify t) - - DEFAULT-A0-AND-ON - (move null-tn a0) - (move null-tn a1) - DEFAULT-A2-AND-ON - (move null-tn a2) - DEFAULT-A3-AND-ON - (move null-tn a3) - DEFAULT-A4-AND-ON - (move null-tn a4) - DEFAULT-A5-AND-ON - (move null-tn a5) - DONE - ;; Clear the stack. - (move cfp-tn ocfp-tn) - (move ocfp cfp-tn) - (inst add ocfp-tn nvals csp-tn) - (lisp-return lra)) - - -;;;; tail-call-variable. - -#+sb-assembling ;; no vop for this one either. -(define-assembly-routine - (tail-call-variable - (:return-style :none)) - ;; These are really args. - ((:temp args any-reg nl0-offset) - (:temp lexenv descriptor-reg lexenv-offset) - ;; We need to compute this - (:temp nargs any-reg nargs-offset) - ;; These are needed by the blitting code. - (:temp src any-reg nl1-offset) - (:temp dst any-reg nl2-offset) - (:temp count any-reg nl3-offset) - (:temp temp descriptor-reg l0-offset) - ;; These are needed so we can get at the register args. - (:temp a0 descriptor-reg a0-offset) - (:temp a1 descriptor-reg a1-offset) - (:temp a2 descriptor-reg a2-offset) - (:temp a3 descriptor-reg a3-offset) - (:temp a4 descriptor-reg a4-offset) - (:temp a5 descriptor-reg a5-offset)) - ;; Calculate NARGS (as a fixnum) - (inst sub csp-tn args nargs) - ;; Load the argument regs (must do this now, 'cause the blt might - ;; trash these locations) - (loadw a0 args 0) - (loadw a1 args 1) - (loadw a2 args 2) - (loadw a3 args 3) - (loadw a4 args 4) - (loadw a5 args 5) - ;; Calc SRC, DST, and COUNT - (inst addi (- (fixnumize register-arg-count)) nargs count) - (inst comb :<= count zero-tn done) - (inst addi (fixnumize register-arg-count) args src) - (inst addi (fixnumize register-arg-count) cfp-tn dst) - LOOP - ;; Copy one arg and increase src - (inst ldwm n-word-bytes src temp) - (inst addib :<> (- (fixnumize 1)) count LOOP) - (inst stwm temp n-word-bytes dst) - DONE - ;; We are done. Do the jump. - (loadw temp lexenv closure-fun-slot fun-pointer-lowtag) - (lisp-jump temp)) - - -;;;; Non-local exit noise. - -(define-assembly-routine - (unwind - (:translate %unwind) - (:return-style :none) - (:policy :fast-safe)) - ((:arg block (any-reg descriptor-reg) a0-offset) - (:arg start (any-reg descriptor-reg) ocfp-offset) - (:arg count (any-reg descriptor-reg) nargs-offset) - (:temp lra descriptor-reg lra-offset) - (:temp cur-uwp any-reg nl0-offset) - (:temp next-uwp any-reg nl1-offset) - (:temp target-uwp any-reg nl2-offset)) - (declare (ignore start count)) - - - (let ((error (generate-error-code nil 'invalid-unwind-error))) - (inst bc := nil block zero-tn error)) - - (load-symbol-value cur-uwp *current-unwind-protect-block*) - (loadw target-uwp block unwind-block-uwp-slot) - (inst bc :<> nil cur-uwp target-uwp DO-UWP) - - (move block cur-uwp) - - DO-EXIT - (loadw cfp-tn cur-uwp unwind-block-cfp-slot) - (loadw code-tn cur-uwp unwind-block-code-slot) - (loadw lra cur-uwp unwind-block-entry-pc-slot) - (lisp-return lra :frob-code nil) - - DO-UWP - (loadw next-uwp cur-uwp unwind-block-uwp-slot) - (inst b DO-EXIT) - (store-symbol-value next-uwp *current-unwind-protect-block*)) - -(define-assembly-routine - (throw - (:return-style :none)) - ((:arg target descriptor-reg a0-offset) - (:arg start any-reg ocfp-offset) - (:arg count any-reg nargs-offset) - (:temp catch any-reg a1-offset) - (:temp tag descriptor-reg a2-offset) - (:temp fix descriptor-reg nl0-offset)) - (declare (ignore start count)) ; We just need them in the registers. - - (load-symbol-value catch *current-catch-block*) - - LOOP - (let ((error (generate-error-code nil 'unseen-throw-tag-error target))) - (inst bc := nil catch zero-tn error)) - (loadw tag catch catch-block-tag-slot) - (inst comb := tag target EXIT :nullify t) - (inst b LOOP) - (loadw catch catch catch-block-previous-catch-slot) - EXIT - (let ((fixup (make-fixup 'unwind :assembly-routine))) - (inst ldil fixup fix) - (inst ble fixup lisp-heap-space fix)) - (move catch target t)) - -#+hpux -(define-assembly-routine - (return-from-lisp-stub (:return-style :none)) - ((:temp lip interior-reg lip-offset) - (:temp nl0 descriptor-reg nl0-offset) - (:temp nl1 descriptor-reg nl1-offset) - (:temp lra descriptor-reg lra-offset)) - ; before calling into lisp we must save our return address (reg_LRA) - (store-symbol-value lra *c-lra*) - ; note the lra we calculate next must "simulate" an fixnum, - ; because compute-calling-frame will use fixnump on this value. - ; either use 16 or 20, finetune it... - (inst addi 19 nl0 lra) ; then setup the new LRA (rest of this routine after branch) - (inst bv lip :nullify t) - (inst word return-pc-widetag) - ; ok, we are back from the lisp-call, lets return to c - ; FIX-lav: steal more stuff from call_into_lisp here, ideally the whole thing - (inst move ocfp-tn csp-tn) ; dont think we should ever get here - (inst nop) - (load-symbol-value nl0 *c-lra*) - (inst addi 1 nl0 nl0) - (inst ble 0 c-text-space nl0 :nullify t)) diff --git a/src/assembly/hppa/support.lisp b/src/assembly/hppa/support.lisp deleted file mode 100644 index 6c037e0ed3..0000000000 --- a/src/assembly/hppa/support.lisp +++ /dev/null @@ -1,68 +0,0 @@ -;;;; the machine-specific support routines needed by the file assembler - -;;;; This software is part of the SBCL system. See the README file for -;;;; more information. -;;;; -;;;; This software is derived from the CMU CL system, which was -;;;; written at Carnegie Mellon University and released into the -;;;; public domain. The software is in the public domain and is -;;;; provided with absolutely no warranty. See the COPYING and CREDITS -;;;; files for more information. - -(in-package "SB-VM") - -(defun generate-call-sequence (name style vop options) - (declare (ignore options)) - (ecase style - ((:raw :none) - (with-unique-names (fixup) - (values - `((let ((fixup (make-fixup ',name :assembly-routine))) - (inst ldil fixup ,fixup) - (inst ble fixup lisp-heap-space ,fixup :nullify t))) - `((:temporary (:scs (any-reg) :from (:eval 0) :to (:eval 1)) - ,fixup))))) - (:full-call - (let ((temp (make-symbol "TEMP")) - (nfp-save (make-symbol "NFP-SAVE")) - (lra (make-symbol "LRA"))) - (values - `((let ((lra-label (gen-label)) - (cur-nfp (current-nfp-tn ,vop))) - (when cur-nfp - (store-stack-tn ,nfp-save cur-nfp)) - (inst compute-lra-from-code code-tn lra-label ,temp ,lra) - (note-next-instruction ,vop :call-site) - (let ((fixup (make-fixup ',name :assembly-routine))) - (inst ldil fixup ,temp) - (inst be fixup lisp-heap-space ,temp :nullify t)) - (without-scheduling () - (emit-return-pc lra-label) - (note-this-location ,vop :single-value-return) - (inst move ocfp-tn csp-tn) - (inst nop)) ; this nop is here because of emit-return-pc align - (inst compute-code-from-lra code-tn lra-label ,temp code-tn) - (when cur-nfp - (load-stack-tn cur-nfp ,nfp-save)))) - `((:temporary (:scs (non-descriptor-reg) :from (:eval 0) :to (:eval 1)) - ,temp) - (:temporary (:sc descriptor-reg :offset lra-offset - :from (:eval 0) :to (:eval 1)) - ,lra) - (:temporary (:scs (control-stack) :offset nfp-save-offset) - ,nfp-save) - (:save-p t))))))) - -(defun generate-return-sequence (style) - (ecase style - (:raw - `((inst bv lip-tn :nullify t))) - (:full-call - `((lisp-return (make-random-tn :kind :normal - :sc (sc-or-lose 'descriptor-reg) - :offset lra-offset) - :offset 1))) - (:none))) - -(defun return-machine-address (scp) - (context-register scp lip-offset)) diff --git a/src/assembly/hppa/tramps.lisp b/src/assembly/hppa/tramps.lisp deleted file mode 100644 index 61123c27e5..0000000000 --- a/src/assembly/hppa/tramps.lisp +++ /dev/null @@ -1,100 +0,0 @@ -;;;; Undefined-function and closure trampoline definitions - -;;;; This software is part of the SBCL system. See the README file for -;;;; more information. - -(in-package "SB-VM") - -(define-assembly-routine - (xundefined-tramp (:return-style :none) - (:align n-lowtag-bits) - (:export undefined-tramp - (undefined-tramp-tagged - (+ xundefined-tramp - fun-pointer-lowtag)))) - ((:temp lra-tn descriptor-reg lra-offset) - (:temp temp non-descriptor-reg nl0-offset)) - (inst word simple-fun-widetag) ;; header - (inst word (make-fixup 'undefined-tramp-tagged - :assembly-routine)) ;; self - (dotimes (i (- simple-fun-insts-offset 2)) - (inst word nil-value)) - - UNDEFINED-TRAMP - ;; Point reg_CODE to the header and tag it as function, since the - ;; debugger regards a function pointer in reg_CODE which doesn't - ;; point to a code object as undefined function. This is (BACKTRACE - ;; UNDEFINED-FUNCTION BUG-353) in the test suite. - (inst addi (- fun-pointer-lowtag - (ash simple-fun-insts-offset word-shift)) - lip-tn code-tn) - - ;; If we are called with stack arguments (or in a tail-call - ;; scenario), we end up with an allocated stack frame, but the frame - ;; link information is uninitialized. Fix things by allocating and - ;; initializing our stack frame "properly". This is (BACKTRACE - ;; UNDEFINED-FUNCTION BUG-346) in the test suite. - - ;; The :NULLIFY T here is technically optional: If we don't nullify - ;; then we execute the following branch, which also doesn't nullify, - ;; and its branch-delay slot becomes (due to the COMIB) the - ;; instruction at NO-STACK-ARGS, and its target is the following - ;; instruction. But that's a bug waiting to happen in the unlikely - ;; event that someone needs to change this logic. - (inst addi (- (fixnumize register-arg-count)) nargs-tn temp) - (inst comb :< temp zero-tn NO-STACK-ARGS :nullify t) - - (inst b FINISH-FRAME-SETUP) - (inst addi (fixnumize register-arg-count) cfp-tn csp-tn) - - NO-STACK-ARGS - (inst add cfp-tn nargs-tn csp-tn) - - FINISH-FRAME-SETUP - (storew ocfp-tn cfp-tn ocfp-save-offset) - (storew lra-tn cfp-tn lra-save-offset) - - ;; Now that the preliminaries are dealt with, actually trap. - (error-call nil 'undefined-fun-error fdefn-tn)) - -; we need closure-tramp and funcallable-instance-tramp in -; same space as other lisp-code, because caller is doing -; normal lisp-calls where we doesnt specify space. -; if we doesnt have the lisp-function (code from defun, closure, lambda etc..) -; machine-address, resolve it here and jump to it. -(define-assembly-routine - (closure-tramp (:return-style :none)) - ((:temp lip interior-reg lip-offset) - (:temp nl0 descriptor-reg nl0-offset)) - (inst ldw (- (* fdefn-fun-slot n-word-bytes) - other-pointer-lowtag) - fdefn-tn lexenv-tn) - (inst ldw (- (* closure-fun-slot n-word-bytes) - fun-pointer-lowtag) - lexenv-tn nl0) - (inst addi (- (* simple-fun-insts-offset n-word-bytes) - fun-pointer-lowtag) - nl0 lip) - (inst bv lip :nullify t)) - -(define-assembly-routine - (funcallable-instance-tramp-header - (:return-style :none) - (:align n-lowtag-bits) - (:export (funcallable-instance-tramp - (+ funcallable-instance-tramp-header - fun-pointer-lowtag)))) - nil - (inst word simple-fun-widetag) ;;header - (inst word (make-fixup 'funcallable-instance-tramp :assembly-routine)) ;; self - (dotimes (i (- simple-fun-insts-offset 2)) - (inst word nil-value)) - (loadw lexenv-tn lexenv-tn - funcallable-instance-function-slot - fun-pointer-lowtag) - (loadw code-tn lexenv-tn - closure-fun-slot - fun-pointer-lowtag) - (inst addi (- (* simple-fun-insts-offset n-word-bytes) - fun-pointer-lowtag) code-tn lip-tn) - (inst bv lip-tn :nullify t)) diff --git a/src/assembly/master.lisp b/src/assembly/master.lisp index 24393760f6..1deb55b809 100644 --- a/src/assembly/master.lisp +++ b/src/assembly/master.lisp @@ -1,10 +1,7 @@ ;; If you change this, note that 'slam.lisp' has to be able to parse this form -(mapc (lambda (x) - (load (merge-pathnames (stem-remap-target x) - (make-pathname :type "lisp")) - :verbose nil :print nil)) - '("src/assembly/target/tramps" - "src/assembly/target/assem-rtns" - "src/assembly/target/array" - "src/assembly/target/arith" - "src/assembly/target/alloc")) +(mapc (lambda (x) (load (sb-cold:stem-source-path x) :verbose nil :print nil)) + '("src/assembly/{arch}/tramps" + "src/assembly/{arch}/assem-rtns" + "src/assembly/{arch}/array" + "src/assembly/{arch}/arith" + "src/assembly/{arch}/alloc")) diff --git a/src/assembly/mips/arith.lisp b/src/assembly/mips/arith.lisp index 72fffa9f3c..11f85c1e3c 100644 --- a/src/assembly/mips/arith.lisp +++ b/src/assembly/mips/arith.lisp @@ -175,15 +175,17 @@ ;; Only need one word, fix the header. (inst li temp (logior (ash 1 n-widetag-bits) bignum-widetag)) - (pseudo-atomic (pa-flag :extra (pad-data-block (+ 1 bignum-digits-offset))) - (inst or res alloc-tn other-pointer-lowtag) + (pseudo-atomic (pa-flag) + (allocation bignum-widetag (pad-data-block (+ 1 bignum-digits-offset)) + res other-pointer-lowtag `(,nargs ,pa-flag)) (storew temp res 0 other-pointer-lowtag)) (storew lo res bignum-digits-offset other-pointer-lowtag) (lisp-return lra lip :offset 2) TWO-WORDS - (pseudo-atomic (pa-flag :extra (pad-data-block (+ 2 bignum-digits-offset))) - (inst or res alloc-tn other-pointer-lowtag) + (pseudo-atomic (pa-flag) + (allocation bignum-widetag (pad-data-block (+ 2 bignum-digits-offset)) + res other-pointer-lowtag `(,nargs ,pa-flag)) (storew temp res 0 other-pointer-lowtag)) (storew lo res bignum-digits-offset other-pointer-lowtag) diff --git a/src/assembly/mips/assem-rtns.lisp b/src/assembly/mips/assem-rtns.lisp index 44c4fe6e97..e32b41264a 100644 --- a/src/assembly/mips/assem-rtns.lisp +++ b/src/assembly/mips/assem-rtns.lisp @@ -211,9 +211,16 @@ (inst beq tag target EXIT) (inst nop) (inst b LOOP) + ;; Is this legal MIPS I code? The LW instruction is in the delay slot of the preceding B, + ;; going to an instruction that uses the value right away. LOADW thinks it's so clever + ;; by inserting a NOP, but the control flow is altered to not hit that NOP. I wonder if + ;; this is one of the weird cases that either does or doesn't work, depending on what the + ;; microarchitecture is doing at that exact moment. i.e. I've never understood if a + ;; loaded value is guaranteed NOT to be in the register for 1 cycle, or *might* not be. + ;; Are we relying on "might or might not be and probably is"? + ;; It looks ok for MIPS II though (which eliminated load delays). (loadw catch catch catch-block-previous-catch-slot) EXIT - (inst li target (make-fixup 'unwind :assembly-routine)) - (inst j target) + (inst beq zero-tn (entry-point-label 'unwind)) (inst move target catch)) diff --git a/src/assembly/mips/support.lisp b/src/assembly/mips/support.lisp index 01618c4078..e58c16fff3 100644 --- a/src/assembly/mips/support.lisp +++ b/src/assembly/mips/support.lisp @@ -65,7 +65,3 @@ :offset lra-offset) lip-tn :offset 2))) (:none))) - -#-sb-xc-host ; CONTEXT-REGISTER is not defined at xc-time -(defun return-machine-address (scp) - (context-register scp lip-offset)) diff --git a/src/assembly/mips/tramps.lisp b/src/assembly/mips/tramps.lisp index c5b71aeff9..379647a2d0 100644 --- a/src/assembly/mips/tramps.lisp +++ b/src/assembly/mips/tramps.lisp @@ -14,6 +14,7 @@ fun-pointer-lowtag)))) ((:temp nl0 unsigned-reg nl0-offset) (:temp lra descriptor-reg lra-offset)) + (progn nl0) ; "use" it. Don't know if it's needed, and don't care to know. (inst word simple-fun-widetag) (inst word (make-fixup 'undefined-tramp-tagged :assembly-routine)) diff --git a/src/assembly/ppc/array.lisp b/src/assembly/ppc/array.lisp index 77a2e32158..52ed71c4c7 100644 --- a/src/assembly/ppc/array.lisp +++ b/src/assembly/ppc/array.lisp @@ -14,8 +14,6 @@ (define-assembly-routine (allocate-vector-on-heap (:policy :fast-safe) - #-stack-allocatable-vectors - (:translate allocate-vector) (:arg-types positive-fixnum positive-fixnum positive-fixnum)) @@ -38,20 +36,8 @@ (inst srwi ndescr type word-shift) (storew ndescr vector 0 other-pointer-lowtag) (storew length vector vector-length-slot other-pointer-lowtag)) - ;; This makes sure the zero byte at the end of a string is paged in so - ;; the kernel doesn't bitch if we pass it the string. - ;; - ;; rtoy says to turn this off as it causes problems with CMUCL. - ;; - ;; I don't think we need to do this anymore. It looks like this - ;; inherited from the SPARC port and does not seem to be - ;; necessary. Turning this on worked at some point, but I have not - ;; tested with the final GENGC-related changes. CLH 20060221 - ;; - ;; (storew zero-tn alloc-tn 0) (move result vector)) -#+stack-allocatable-vectors (define-assembly-routine (allocate-vector-on-stack (:policy :fast-safe) (:arg-types positive-fixnum diff --git a/src/assembly/ppc/support.lisp b/src/assembly/ppc/support.lisp index ed0e33a399..b2050bc250 100644 --- a/src/assembly/ppc/support.lisp +++ b/src/assembly/ppc/support.lisp @@ -68,7 +68,3 @@ :offset lip-offset) :offset 2))) (:none))) - -#-sb-xc-host ; CONTEXT-LR is not defined at xc-time -(defun return-machine-address (scp) - (sap-int (context-lr scp))) diff --git a/src/assembly/ppc64/array.lisp b/src/assembly/ppc64/array.lisp index b78262b1c6..31e25677f7 100644 --- a/src/assembly/ppc64/array.lisp +++ b/src/assembly/ppc64/array.lisp @@ -14,8 +14,6 @@ (define-assembly-routine (allocate-vector-on-heap (:policy :fast-safe) - #-stack-allocatable-vectors - (:translate allocate-vector) (:arg-types positive-fixnum positive-fixnum positive-fixnum)) @@ -39,7 +37,6 @@ (storew length vector vector-length-slot other-pointer-lowtag)) (move result vector)) -#+stack-allocatable-vectors (define-assembly-routine (allocate-vector-on-stack (:policy :fast-safe) (:arg-types positive-fixnum diff --git a/src/assembly/ppc64/assem-rtns.lisp b/src/assembly/ppc64/assem-rtns.lisp index a7316d4c59..dfaf901f4e 100644 --- a/src/assembly/ppc64/assem-rtns.lisp +++ b/src/assembly/ppc64/assem-rtns.lisp @@ -207,6 +207,6 @@ (move target catch) ;; reuse catch - (inst addi catch null-tn (make-fixup 'unwind :asm-routine-nil-offset)) + (inst addi catch null-tn (make-fixup 'unwind :assembly-routine*)) (inst mtlr catch) (inst blr)) diff --git a/src/assembly/ppc64/support.lisp b/src/assembly/ppc64/support.lisp index adbc4a24ec..75d099a13c 100644 --- a/src/assembly/ppc64/support.lisp +++ b/src/assembly/ppc64/support.lisp @@ -17,7 +17,7 @@ ((:raw :none) (let ((jump (make-symbol "JUMP"))) (values - `((inst addi ,jump null-tn (make-fixup ',name :asm-routine-nil-offset)) + `((inst addi ,jump null-tn (make-fixup ',name :assembly-routine*)) (inst mtlr ,jump) (inst blrl)) `((:temporary (:sc any-reg) ,jump))))) @@ -33,7 +33,7 @@ (store-stack-tn ,nfp-save cur-nfp)) (inst compute-lra-from-code ,lra code-tn lra-label ,temp) (note-next-instruction ,vop :call-site) - (inst addi ,jump null-tn (make-fixup ',name :asm-routine-nil-offset)) + (inst addi ,jump null-tn (make-fixup ',name :assembly-routine*)) (inst mtlr ,jump) (inst blr) (emit-return-pc lra-label) @@ -68,7 +68,3 @@ :offset lip-offset) :offset 2))) (:none))) - -#-sb-xc-host ; CONTEXT-LR is not defined at xc-time -(defun return-machine-address (scp) - (sap-int (context-lr scp))) diff --git a/src/assembly/ppc64/tramps.lisp b/src/assembly/ppc64/tramps.lisp index 7c4498920a..514ebbfc04 100644 --- a/src/assembly/ppc64/tramps.lisp +++ b/src/assembly/ppc64/tramps.lisp @@ -129,7 +129,7 @@ ;; We're back. (inst mtctr r3) ; stash the result in a reg that won't be clobbered ;; Reload a pointer to this asm routine - (inst addi lip null-tn (make-fixup 'alloc-tramp :asm-routine-nil-offset)) + (inst addi lip null-tn (make-fixup 'alloc-tramp :assembly-routine*)) ;; Restore the return address from the caller's frame. ;; 'sp' hasn't been restored yet, so add our frame size. (inst ld r0 machine-sp (+ 32 16)) diff --git a/src/assembly/riscv/assem-rtns.lisp b/src/assembly/riscv/assem-rtns.lisp index 55202aab3f..721bddc9c2 100644 --- a/src/assembly/riscv/assem-rtns.lisp +++ b/src/assembly/riscv/assem-rtns.lisp @@ -20,7 +20,7 @@ ((:temp nvals any-reg nargs-offset) (:temp vals any-reg nl0-offset) (:temp ocfp any-reg nl1-offset) - (:temp lra descriptor-reg lra-offset) + (:temp ra non-descriptor-reg ra-offset) ;; These are just needed to facilitate the transfer (:temp count any-reg nl2-offset) @@ -79,7 +79,7 @@ (with-fixnum-as-word-index (nvals temp) (inst add csp-tn ocfp-tn nvals)) ;; Return. - (lisp-return lra :multiple-values)) + (inst jalr zero-tn ra 0)) #+sb-assembling ;; no vop for this one either. (define-assembly-routine @@ -97,7 +97,9 @@ (:temp src any-reg nl1-offset) (:temp dst any-reg nl2-offset) (:temp count any-reg nl3-offset) - (:temp temp descriptor-reg l0-offset)) + (:temp temp descriptor-reg l0-offset) + + (:temp function descriptor-reg l0-offset)) ;; Calculate NARGS (as a fixnum) @@ -127,13 +129,15 @@ DONE ;; We are done. Do the jump. (with-word-index-as-fixnum (nargs nargs)) - (loadw temp lexenv closure-fun-slot fun-pointer-lowtag) - (lisp-jump temp)) + (loadw function lexenv closure-fun-slot fun-pointer-lowtag) + (inst jalr zero-tn function + (- (ash simple-fun-insts-offset word-shift) + fun-pointer-lowtag))) ;;;; Non-local exit noise. -(define-assembly-routine (throw (:return-style :none)) +(define-assembly-routine throw ((:arg target (descriptor-reg any-reg) a0-offset) (:arg start (descriptor-reg any-reg) ocfp-offset) (:arg count (descriptor-reg any-reg) nargs-offset) @@ -154,17 +158,16 @@ EXIT (move target catch) ;; TARGET coincides with UNWIND's BLOCK argument - (invoke-asm-routine 'unwind)) + (inst jal zero-tn (make-fixup 'unwind :assembly-routine))) (define-assembly-routine (unwind - (:return-style :none) (:translate %unwind) (:policy :fast-safe)) ((:arg block (descriptor-reg any-reg) a0-offset) (:arg start (descriptor-reg any-reg) ocfp-offset) (:arg count (descriptor-reg any-reg) nargs-offset) - (:temp lra descriptor-reg lra-offset) (:temp cur-uwp any-reg nl0-offset) + (:temp temp any-reg nl1-offset) (:temp target-uwp any-reg nl2-offset)) (declare (ignore start count)) @@ -180,8 +183,8 @@ DO-EXIT (loadw cfp-tn cur-uwp unwind-block-cfp-slot) (loadw code-tn cur-uwp unwind-block-code-slot) - (loadw lra cur-uwp unwind-block-entry-pc-slot) - (lisp-return lra :known) + (loadw temp cur-uwp unwind-block-entry-pc-slot) + (inst jalr zero-tn temp 0) DO-UWP (loadw target-uwp cur-uwp unwind-block-uwp-slot) @@ -254,11 +257,12 @@ (:arg nargs (any-reg) ca2-offset) #+sb-thread (:arg tls-ptr (any-reg) ca3-offset) + (:arg ra (any-reg) ra-offset) (:temp a0 descriptor-reg a0-offset) - (:temp lra descriptor-reg lra-offset) (:temp value (descriptor-reg any-reg) ca0-offset) + (:temp fun (descriptor-reg) l0-offset) ;; Don't want these to overlap with C args. (:temp pa-temp non-descriptor-reg nl6-offset) @@ -281,15 +285,11 @@ for index from 0 do (loadw arg cfp-tn index)) - (inst compute-lra lra lip-tn lra-label) ;; Indirect closure. - (loadw code-tn lexenv-tn closure-fun-slot fun-pointer-lowtag) + (loadw fun lexenv-tn closure-fun-slot fun-pointer-lowtag) ;; Call into Lisp! - (inst jalr zero-tn code-tn (- (* simple-fun-insts-offset n-word-bytes) - fun-pointer-lowtag)) - (emit-alignment n-lowtag-bits) - LRA-LABEL - (inst machine-word return-pc-widetag) + (inst jalr ra fun (- (* simple-fun-insts-offset n-word-bytes) + fun-pointer-lowtag)) (inst blt nargs-tn zero-tn single-value-return) (move csp-tn ocfp-tn) @@ -302,7 +302,7 @@ (save-lisp-context csp-tn cfp-tn temp)) (restore-c-registers) - (inst jalr zero-tn lip-tn 0)) + (inst jalr zero-tn ra 0)) (define-assembly-routine (call-into-c (:return-style :none)) ((:arg cfunc (any-reg) cfunc-offset) @@ -324,21 +324,13 @@ (inst addi csp-tn cfp-tn 32) (pseudo-atomic (pa-temp) - ;; Convert the return address to an offset and save it on the stack. - (inst sub nfp-tn lip-tn code-tn) - (inst addi nfp-tn nfp-tn other-pointer-lowtag) - ;; Ensure it has fixnum nature so GC doesn't croak. - (when (> n-fixnum-tag-bits 2) - (inst slli nfp-tn nfp-tn (- n-fixnum-tag-bits 2))) (storew ocfp-tn cfp-tn) - (storew nfp-tn cfp-tn 1) + (storew ra-tn cfp-tn 1) (storew code-tn cfp-tn 2) - (save-lisp-context csp-tn cfp-tn temp)) ;; Call into C. - (loadw cfunc cfunc) ; dereference the linkage table entry - (inst jalr lip-tn cfunc 0) + (inst jalr ra-tn cfunc 0) ;; Pass the return values to Lisp. (move value0-pass ca0) @@ -353,17 +345,14 @@ ;; registers and not bother loading them out again.. (set-up-lisp-context csp-tn cfp-tn temp) (loadw ocfp-tn cfp-tn 0) - (loadw nfp-tn cfp-tn 1) - (loadw code-tn cfp-tn 2) - (when (> n-fixnum-tag-bits 2) - (inst srli nfp-tn nfp-tn (- n-fixnum-tag-bits 2))) - (inst add lip-tn nfp-tn code-tn)) + (loadw ra-tn cfp-tn 1) + (loadw code-tn cfp-tn 2)) ;; Reset the Lisp stack. (move csp-tn cfp-tn) (move cfp-tn ocfp-tn) - (inst jalr zero-tn lip-tn (- other-pointer-lowtag))) + (inst jalr zero-tn ra-tn 0)) (define-assembly-routine (do-pending-interrupt (:return-style :none)) () diff --git a/src/assembly/riscv/support.lisp b/src/assembly/riscv/support.lisp index c57b09d374..99c2d86716 100644 --- a/src/assembly/riscv/support.lisp +++ b/src/assembly/riscv/support.lisp @@ -11,29 +11,23 @@ (in-package "SB-VM") -;;; Make sure to always write back into our return register so that -;;; backtracing in assembly routines work correctly. -(defun invoke-asm-routine (routine) - (inst jal lip-tn (make-fixup routine :assembly-routine))) - (defun generate-call-sequence (name style vop options) (declare (ignore vop options)) (ecase style - ((:none :raw) + (:raw + (let ((ra (make-symbol "RA"))) + (values + `((inst jal ,ra (make-fixup ',name :assembly-routine))) + `((:temporary (:sc descriptor-reg :from (:eval 0) :to (:eval 1) + :offset ra-offset) + ,ra))))) + (:none (values - `((inst jal lip-tn (make-fixup ',name :assembly-routine))) + `((inst jal zero-tn (make-fixup ',name :assembly-routine))) `())))) (defun generate-return-sequence (style) (ecase style - (:none) (:raw - `((inst jalr zero-tn lip-tn 0))))) - -#-sb-xc-host ; CONTEXT-REGISTER is not defined at xc-time -(defun return-machine-address (scp) - ;; KLUDGE: Taken from SPARC backend. Why does `8' need to be added - ;; to the return address? Without it, backtraces get truncated and - ;; are incorrect. Are the other backends wrong as well by not adding - ;; 8? - (+ (context-register scp lip-offset) 8)) + `((inst jalr zero-tn ra-tn 0))) + (:none))) diff --git a/src/assembly/riscv/tramps.lisp b/src/assembly/riscv/tramps.lisp index 2d0b85b95f..50da6e7c60 100644 --- a/src/assembly/riscv/tramps.lisp +++ b/src/assembly/riscv/tramps.lisp @@ -20,102 +20,88 @@ (inst #-64-bit lw #+64-bit ld tn sp-tn i)))) #+gencgc -(defmacro define-alloc-tramp-stub (alloc-tn-offset) +(defmacro define-alloc-tramp-stub (alloc-tn-offset tramp-name) `(define-assembly-routine - (,(alloc-tramp-stub-name alloc-tn-offset nil) - (:export ,(alloc-tramp-stub-name alloc-tn-offset 'list)) + (,(alloc-tramp-stub-name alloc-tn-offset + (if (eq tramp-name 'alloc-tramp-list) + 'list + 'generic)) (:return-style :none)) ((:temp free+size unsigned-reg ,alloc-tn-offset) (:temp object-end descriptor-reg ,alloc-tn-offset)) - ;; General-purpose entry point: - ;; ALLOC-TRAMP needs 1 bit of extra information to select a linkage table - ;; entry. It could be passed in the low bit of FREE+SIZE, but - ;; because the object granularity is 2 words, it is ok to use any - ;; bit under LOWTAG-MASK. e.g. with 64-bit words: - ;; v--- ; use this bit - ;; #b________10000 ; 16 bytes is the smallest object - ;; By passing it as such, it is actually an offset into the linkage table. - (inst ori free+size free+size (ash 1 word-shift)) - ;; CONS entry point: - ,(alloc-tramp-stub-name alloc-tn-offset 'list) (inst addi csp-tn csp-tn n-word-bytes) (storew free+size csp-tn -1) (move free+size lip-tn) - (invoke-asm-routine 'alloc-tramp) + (inst jal lip-tn (make-fixup ',tramp-name :assembly-routine)) (move lip-tn object-end) (loadw object-end csp-tn -1) (inst subi csp-tn csp-tn n-word-bytes) (inst jalr zero-tn lip-tn 0))) #+gencgc -(define-assembly-routine (alloc-tramp (:return-style :none)) - ((:temp temp unsigned-reg nl0-offset) - (:temp ca0 any-reg ca0-offset)) - (let* ((nl-registers - (loop for i in (intersection (union (list nl0-offset) - non-descriptor-regs) - c-unsaved-registers) - collect (make-reg-tn i 'unsigned-reg))) - (lisp-registers - (loop for i in (intersection - (union (list ca0-offset lip-offset cfp-offset - null-offset code-offset - #+sb-thread thread-offset) - descriptor-regs) - c-unsaved-registers) - collect (make-reg-tn i 'descriptor-reg))) - (float-registers - (loop for i in c-unsaved-float-registers - collect (make-reg-tn i 'double-reg))) - (float-framesize (* (length float-registers) 8)) - (nl-framesize (* (length nl-registers) n-word-bytes)) - (number-framesize - ;; New space for the number stack, making sure to respect - ;; number stack alignment. - (logandc2 (+ (+ nl-framesize float-framesize) - +number-stack-alignment-mask+) - +number-stack-alignment-mask+)) - (lisp-framesize (* (length lisp-registers) n-word-bytes)) - (nl-start (- number-framesize nl-framesize)) - (float-start (- nl-start float-framesize))) - (inst subi nsp-tn nsp-tn number-framesize) - (save-to-stack nl-registers nsp-tn nl-start) - (save-lisp-context csp-tn cfp-tn temp) - ;; Create a new frame and save descriptor regs on the stack for GC - ;; to see. - (save-to-stack lisp-registers csp-tn) - (loadw ca0 csp-tn -1) - ;; linkage entry 0 = alloc() and entry 1 = alloc_list(). - ;; Because the linkage table grows downward from NIL, entry 1 is - ;; at a lower address than 0. Adding the entry point selector bit - ;; from 'free+size' indexes to entry 0 or 1. If that bit was 1, it - ;; picks out entry 0, if 0 it picks out 1. - (inst andi temp ca0 (ash 1 sb-vm:word-shift)) - (inst add temp null-tn temp) - (loadw lip-tn temp 0 (- nil-value (linkage-table-entry-address 1))) - (inst andi ca0 ca0 (lognot (ash 1 sb-vm:word-shift))) ; clear the selector bit - ;; Recover and save the size. - (load-alloc-free-pointer temp) - (inst sub ca0 ca0 temp) - (storew ca0 csp-tn -1) - (inst addi csp-tn csp-tn lisp-framesize) - (save-to-stack float-registers nsp-tn float-start t) - (inst jalr lip-tn lip-tn 0) - (pop-from-stack float-registers nsp-tn float-start t) - (inst subi csp-tn csp-tn lisp-framesize) - (loadw temp csp-tn -1) - ;; Point to the end of the object, so we can fold the lowtag and - ;; size additions in the fast case. - (inst add ca0 ca0 temp) - (storew ca0 csp-tn -1) - (pop-from-stack lisp-registers csp-tn) - #-sb-thread - (store-foreign-symbol-value zero-tn "foreign_function_call_active" temp) - #+sb-thread - (storew zero-tn thread-base-tn thread-foreign-function-call-active-slot) - (pop-from-stack nl-registers nsp-tn nl-start) - (inst addi nsp-tn nsp-tn number-framesize) - (inst jalr zero-tn lip-tn 0))) +(defmacro define-alloc-tramp (tramp-name c-name) + `(define-assembly-routine (,tramp-name (:return-style :none)) + ((:temp temp unsigned-reg nl0-offset) + (:temp ca0 any-reg ca0-offset)) + (let* ((nl-registers + (loop for i in (intersection (union (list nl0-offset) + non-descriptor-regs) + c-unsaved-registers) + collect (make-reg-tn i 'unsigned-reg))) + (lisp-registers + (loop for i in (intersection + (union (list ca0-offset lip-offset cfp-offset + null-offset code-offset + #+sb-thread thread-offset) + descriptor-regs) + c-unsaved-registers) + collect (make-reg-tn i 'descriptor-reg))) + (float-registers + (loop for i in c-unsaved-float-registers + collect (make-reg-tn i 'double-reg))) + (float-framesize (* (length float-registers) 8)) + (nl-framesize (* (length nl-registers) n-word-bytes)) + (number-framesize + ;; New space for the number stack, making sure to respect + ;; number stack alignment. + (logandc2 (+ (+ nl-framesize float-framesize) + +number-stack-alignment-mask+) + +number-stack-alignment-mask+)) + (lisp-framesize (* (length lisp-registers) n-word-bytes)) + (nl-start (- number-framesize nl-framesize)) + (float-start (- nl-start float-framesize))) + (inst subi nsp-tn nsp-tn number-framesize) + (save-to-stack nl-registers nsp-tn nl-start) + (save-lisp-context csp-tn cfp-tn temp) + ;; Create a new frame and save descriptor regs on the stack for GC + ;; to see. + (save-to-stack lisp-registers csp-tn) + (loadw ca0 csp-tn -1) + ;; Recover and save the size. + (load-alloc-free-pointer temp) + (inst sub ca0 ca0 temp) + (storew ca0 csp-tn -1) + (inst addi csp-tn csp-tn lisp-framesize) + (save-to-stack float-registers nsp-tn float-start t) + (inst jal ra-tn (make-fixup ,c-name :foreign)) + (pop-from-stack float-registers nsp-tn float-start t) + (inst subi csp-tn csp-tn lisp-framesize) + (loadw temp csp-tn -1) + ;; Point to the end of the object, so we can fold the lowtag and + ;; size additions in the fast case. + (inst add ca0 ca0 temp) + (storew ca0 csp-tn -1) + (pop-from-stack lisp-registers csp-tn) + #-sb-thread + (store-foreign-symbol-value zero-tn "foreign_function_call_active" temp) + #+sb-thread + (storew zero-tn thread-base-tn thread-foreign-function-call-active-slot) + (pop-from-stack nl-registers nsp-tn nl-start) + (inst addi nsp-tn nsp-tn number-framesize) + (inst jalr zero-tn lip-tn 0)))) + +(define-alloc-tramp alloc-tramp "alloc") +(define-alloc-tramp alloc-tramp-list "alloc_list") ;;; Define allocation stubs. The purpose of creating these stubs is to ;;; reduce the number of instructions needed at the site of @@ -126,7 +112,9 @@ (macrolet ((define-alloc-tramp-stubs () `(progn ,@(mapcar (lambda (tn-offset) - `(define-alloc-tramp-stub ,tn-offset)) + `(progn + (define-alloc-tramp-stub ,tn-offset alloc-tramp) + (define-alloc-tramp-stub ,tn-offset alloc-tramp-list))) (union descriptor-regs non-descriptor-regs))))) (define-alloc-tramp-stubs)) @@ -135,7 +123,7 @@ (:align n-lowtag-bits) (:export (undefined-tramp (+ xundefined-tramp fun-pointer-lowtag)))) - ((:temp lra descriptor-reg lra-offset)) + ((:temp ra non-descriptor-reg ra-offset)) (inst machine-word simple-fun-widetag) (inst machine-word (make-fixup 'undefined-tramp :assembly-routine)) (dotimes (i (- simple-fun-insts-offset 2)) @@ -146,7 +134,7 @@ ;; doesn't point to a code object as undefined function. (inst li code-tn (make-fixup 'undefined-tramp :assembly-routine)) (storew ocfp-tn cfp-tn 0) - (storew lra cfp-tn 1) + (storew ra cfp-tn 1) (error-call nil 'undefined-fun-error lexenv-tn)) (define-assembly-routine @@ -154,27 +142,27 @@ (:align n-lowtag-bits) (:export (closure-tramp (+ xclosure-tramp fun-pointer-lowtag)))) - () + ((:temp function descriptor-reg l0-offset)) (inst machine-word simple-fun-widetag) (inst machine-word (make-fixup 'closure-tramp :assembly-routine)) (dotimes (i (- simple-fun-insts-offset 2)) (inst machine-word nil-value)) (loadw lexenv-tn lexenv-tn fdefn-fun-slot other-pointer-lowtag) - (loadw code-tn lexenv-tn closure-fun-slot fun-pointer-lowtag) - (inst jalr zero-tn code-tn (- (* simple-fun-insts-offset n-word-bytes) fun-pointer-lowtag))) + (loadw function lexenv-tn closure-fun-slot fun-pointer-lowtag) + (inst jalr zero-tn function (- (* simple-fun-insts-offset n-word-bytes) fun-pointer-lowtag))) (define-assembly-routine (xfuncallable-instance-tramp (:return-style :none) (:align n-lowtag-bits) (:export (funcallable-instance-tramp (+ xfuncallable-instance-tramp fun-pointer-lowtag)))) - () + ((:temp function descriptor-reg l0-offset)) (inst machine-word simple-fun-widetag) (inst machine-word (make-fixup 'funcallable-instance-tramp :assembly-routine)) (dotimes (i (- simple-fun-insts-offset 2)) (inst machine-word nil-value)) (loadw lexenv-tn lexenv-tn funcallable-instance-function-slot fun-pointer-lowtag) - (loadw code-tn lexenv-tn closure-fun-slot fun-pointer-lowtag) - (inst jalr zero-tn code-tn (- (* simple-fun-insts-offset n-word-bytes) fun-pointer-lowtag))) + (loadw function lexenv-tn closure-fun-slot fun-pointer-lowtag) + (inst jalr zero-tn function (- (* simple-fun-insts-offset n-word-bytes) fun-pointer-lowtag))) diff --git a/src/assembly/sparc/array.lisp b/src/assembly/sparc/array.lisp index 9be9c9f37a..cc4051a262 100644 --- a/src/assembly/sparc/array.lisp +++ b/src/assembly/sparc/array.lisp @@ -11,9 +11,8 @@ (in-package "SB-VM") -(define-assembly-routine (allocate-vector +(define-assembly-routine (allocate-vector-on-heap (:policy :fast-safe) - (:translate allocate-vector) (:arg-types positive-fixnum positive-fixnum positive-fixnum)) @@ -25,32 +24,48 @@ (:temp ndescr non-descriptor-reg nl0-offset) (:temp gc-temp non-descriptor-reg nl1-offset) (:temp vector descriptor-reg a3-offset)) - (pseudo-atomic () + (pseudo-atomic (gc-temp) ;; boxed words == unboxed bytes (inst add ndescr words (* (1+ vector-data-offset) n-word-bytes)) (inst andn ndescr 7) (allocation nil ndescr other-pointer-lowtag vector :temp-tn gc-temp) - (inst srl ndescr type word-shift) + (inst srl ndescr type n-fixnum-tag-bits) + (storew ndescr vector 0 other-pointer-lowtag) + (storew length vector vector-length-slot other-pointer-lowtag)) + (move result vector)) + +(define-assembly-routine (allocate-vector-on-stack + (:policy :fast-safe) + (:arg-types positive-fixnum + positive-fixnum + positive-fixnum)) + ((:arg type any-reg a0-offset) + (:arg length any-reg a1-offset) + (:arg words any-reg a2-offset) + (:res result descriptor-reg a0-offset) + + (:temp ndescr non-descriptor-reg nl0-offset) + (:temp gc-temp non-descriptor-reg nl1-offset) + (:temp vector descriptor-reg a3-offset)) + (pseudo-atomic (gc-temp) + ;; boxed words == unboxed bytes + (inst add ndescr words (* (1+ vector-data-offset) n-word-bytes)) + (inst andn ndescr 7) + (allocation nil ndescr other-pointer-lowtag vector :temp-tn gc-temp + :stack-p t) + ;; We're pseudo-atomic here, so we can do whatever is most convenient + ;; to zeroize the array data. Clear two words at a time upward from VECTOR + ;; until reaching the new CSP-TN value. Don't pre-check for 0 payload words, + ;; just consider the first two words as part of the array data. + (let ((loop (gen-label))) + (inst add ndescr vector (- other-pointer-lowtag)) + (emit-label loop) + (storew zero-tn ndescr 0 0) ; next store is in the branch delay slot + (inst add ndescr ndescr (* n-word-bytes 2)) + (inst cmp ndescr csp-tn) + (inst b :lt loop) + (storew zero-tn ndescr -1 0)) ; -1 because ptr was already bumped + (inst srl ndescr type n-fixnum-tag-bits) (storew ndescr vector 0 other-pointer-lowtag) (storew length vector vector-length-slot other-pointer-lowtag)) - ;; This makes sure the zero byte at the end of a string is paged in so - ;; the kernel doesn't bitch if we pass it the string. - ;; - ;; RLT comments in CMUCL about changing the following line to - ;; store at -1 instead of 0: - ;; This used to write to the word after the last allocated word. I - ;; (RLT) made it write to the last allocated word, which is where - ;; the zero-byte of the string is. Look at the deftransform for - ;; make-array in array-tran.lisp. For strings we always allocate - ;; enough space to hold the zero-byte. - ;; Which is most certainly motivated by the fact that this store (if - ;; performed on gencgc) overwrites the first word of the following - ;; page -- destroying the first object of an unrelated allocation region! - ;; - ;; But the CMUCL fix breaks :ELEMENT-TYPE NIL strings, so we'd need a - ;; branch to figure out whether to do it. Until and unless someone - ;; demonstrates that gencgc actually gives us uncommitted memory, I'm - ;; just not doing it at all: -- DFL - #-gencgc - (storew zero-tn alloc-tn 0) (move result vector)) diff --git a/src/assembly/sparc/assem-rtns.lisp b/src/assembly/sparc/assem-rtns.lisp index eb4c333e83..22ec87cd25 100644 --- a/src/assembly/sparc/assem-rtns.lisp +++ b/src/assembly/sparc/assem-rtns.lisp @@ -206,8 +206,7 @@ (:arg start any-reg ocfp-offset) (:arg count any-reg nargs-offset) (:temp catch any-reg a1-offset) - (:temp tag descriptor-reg a2-offset) - (:temp temp non-descriptor-reg nl0-offset)) + (:temp tag descriptor-reg a2-offset)) (declare (ignore start count)) @@ -224,15 +223,10 @@ (inst cmp tag target) (inst b :eq exit) (inst nop) - (loadw catch catch catch-block-previous-catch-slot) (inst b loop) - (inst nop) + (loadw catch catch catch-block-previous-catch-slot) ; in branch delay slot exit - (move target catch) - (inst li temp (make-fixup 'unwind :assembly-routine)) - (inst j temp) - (inst nop)) - - + (inst b (entry-point-label 'unwind)) + (move target catch)) diff --git a/src/assembly/sparc/support.lisp b/src/assembly/sparc/support.lisp index 1ac9e047dc..8fd2927b9c 100644 --- a/src/assembly/sparc/support.lisp +++ b/src/assembly/sparc/support.lisp @@ -70,7 +70,3 @@ :offset lra-offset) :offset 2))) (:none))) - -#-sb-xc-host ; CONTEXT-REGISTER is not defined at xc-time -(defun return-machine-address (scp) - (+ (context-register scp lip-offset) 8)) diff --git a/src/assembly/x86-64/alloc.lisp b/src/assembly/x86-64/alloc.lisp index 835cc445be..ab83b52128 100644 --- a/src/assembly/x86-64/alloc.lisp +++ b/src/assembly/x86-64/alloc.lisp @@ -17,44 +17,60 @@ ;;;; fixnum cases inline. #+sb-assembling (macrolet - ((signed (reg avx) - `(define-assembly-routine (,(symbolicate "ALLOC-SIGNED-BIGNUM-IN-" reg - (if avx "-AVX2" ""))) + ((signed (reg) + `(define-assembly-routine (,(symbolicate "ALLOC-SIGNED-BIGNUM-IN-" reg)) ((:temp number unsigned-reg ,(symbolicate reg "-OFFSET"))) - (inst push number) - (let (#+avx2 - (*avx-registers-used-p* ,avx)) - (alloc-other number bignum-widetag (+ bignum-digits-offset 1) nil)) - (popw number bignum-digits-offset other-pointer-lowtag))) - (unsigned (reg avx) - `(define-assembly-routine (,(symbolicate "ALLOC-UNSIGNED-BIGNUM-IN-" reg - (if avx "-AVX2" ""))) + ,@(cond + ((eq reg 'r12) ; problematic case for INSTRUMENT-ALLOC + '((inst push rax-tn) + (alloc-other bignum-widetag (+ bignum-digits-offset 1) rax-tn nil nil nil) + (storew number rax-tn bignum-digits-offset other-pointer-lowtag) + (inst mov number rax-tn) + (inst pop rax-tn))) + (t + '((inst push number) + (alloc-other bignum-widetag (+ bignum-digits-offset 1) number nil nil nil) + (popw number bignum-digits-offset other-pointer-lowtag)))))) + (unsigned (reg) + `(define-assembly-routine (,(symbolicate "ALLOC-UNSIGNED-BIGNUM-IN-" reg)) ((:temp number unsigned-reg ,(symbolicate reg "-OFFSET"))) (inst ror number (1+ n-fixnum-tag-bits)) ; restore unrotated value - (inst push number) (inst test number number) ; rotates do not update SF - (inst jmp :ns one-word-bignum) - (let (#+avx2 - (*avx-registers-used-p* ,avx)) - ;; Two word bignum - (alloc-other number bignum-widetag (+ bignum-digits-offset 2) nil)) - (popw number bignum-digits-offset other-pointer-lowtag) - (inst ret) - ONE-WORD-BIGNUM - (alloc-other number bignum-widetag (+ bignum-digits-offset 1) nil) - (popw number bignum-digits-offset other-pointer-lowtag))) - (define (op &optional avx) - ;; Don't include r11 or r13 since those are temp and thread-base respectively + ,@(cond + ((eq reg 'r12) ; problematic case for INSTRUMENT-ALLOC + '((inst push rax-tn) + (inst jmp :ns one-word-bignum) + ;; Two word bignum + (alloc-other bignum-widetag (+ bignum-digits-offset 2) rax-tn nil nil nil) + (storew number rax-tn bignum-digits-offset other-pointer-lowtag) + (inst mov number rax-tn) + (inst pop rax-tn) + (inst ret) + ONE-WORD-BIGNUM + (alloc-other bignum-widetag (+ bignum-digits-offset 1) rax-tn nil nil nil) + (storew number rax-tn bignum-digits-offset other-pointer-lowtag) + (inst mov number rax-tn) + (inst pop rax-tn))) + (t + '((inst push number) + (inst jmp :ns one-word-bignum) + ;; Two word bignum + (alloc-other bignum-widetag (+ bignum-digits-offset 2) number nil nil nil) + (popw number bignum-digits-offset other-pointer-lowtag) + (inst ret) + ONE-WORD-BIGNUM + (alloc-other bignum-widetag (+ bignum-digits-offset 1) number nil nil nil) + (popw number bignum-digits-offset other-pointer-lowtag)))))) + (define (op) + ;; R13 is usually the thread register, but might not be `(progn ,@(loop for reg in '(rax rcx rdx rbx rsi rdi - r8 r9 r10 r12 r14 r15) - collect `(,op ,reg ,avx))))) + r8 r9 r10 r11 r12 + #+gs-seg r13 + r14 r15) + collect `(,op ,reg))))) (define signed) - (define unsigned) - #+avx2 - (define signed t) - #+avx2 - (define unsigned t)) + (define unsigned)) #+sb-thread (define-assembly-routine (alloc-tls-index @@ -80,7 +96,7 @@ (pseudo-atomic () (assemble () ; for conversion of tagbody-like labels to assembler labels RETRY - (inst bts :qword free-tls-index-ea lock-bit :lock) + (inst bts :qword :lock free-tls-index-ea lock-bit) (inst jmp :nc got-tls-index-lock) (inst pause) ; spin loop hint ;; TODO: yielding the CPU here might be a good idea @@ -93,7 +109,7 @@ ;; CMP against memory showed the tls-index to be valid, so clear the lock ;; and re-read the memory (safe because transition can only occur to ;; a nonzero value), then jump out to end the PA section. - (inst btr :qword free-tls-index-ea lock-bit :lock) + (inst btr :qword :lock free-tls-index-ea lock-bit) (inst mov :dword symbol (tls-index-of symbol)) (inst jmp done) NEW-TLS-INDEX @@ -109,7 +125,7 @@ ;; Load scratch-reg with a constant that clears the lock bit ;; and bumps the free index in one go. (inst mov scratch-reg (+ (- (ash 1 lock-bit)) n-word-bytes)) - (inst add :qword free-tls-index-ea scratch-reg :lock) + (inst add :qword :lock free-tls-index-ea scratch-reg) (inst pop scratch-reg) DONE)) ; end PSEUDO-ATOMIC (inst ret) @@ -117,7 +133,7 @@ ;; The disassembly of this code looks nicer when the failure path ;; immediately follows the ordinary path vs. being in *ELSEWHERE*. (inst pop scratch-reg) ; balance the stack - (inst btr :qword free-tls-index-ea lock-bit :lock) + (inst btr :qword :lock free-tls-index-ea lock-bit) (%clear-pseudo-atomic) ;; There's a spurious RET instruction auto-inserted, but no matter. (error-call nil 'tls-exhausted-error))) diff --git a/src/assembly/x86-64/arith.lisp b/src/assembly/x86-64/arith.lisp index d6b9b06337..70e45cb3c3 100644 --- a/src/assembly/x86-64/arith.lisp +++ b/src/assembly/x86-64/arith.lisp @@ -50,10 +50,11 @@ #+sb-assembling (defun return-single-word-bignum (dest alloc-tn source) - (instrument-alloc 16 nil) - (let ((header (logior (ash 1 n-widetag-bits) bignum-widetag))) + (let ((header (logior (ash 1 n-widetag-bits) bignum-widetag)) + (nbytes #+bignum-assertions 32 #-bignum-assertions 16)) + (instrument-alloc bignum-widetag nbytes nil alloc-tn) (pseudo-atomic () - (allocation nil 16 0 nil nil alloc-tn) + (allocation bignum-widetag nbytes 0 alloc-tn nil nil nil) (storew* header alloc-tn 0 0 t) (storew source alloc-tn bignum-digits-offset 0) (if (eq dest alloc-tn) @@ -132,7 +133,7 @@ (inst cmp x rcx) (inst jmp :e SINGLE-WORD-BIGNUM) - (alloc-other res bignum-widetag (+ bignum-digits-offset 2) nil) + (alloc-other bignum-widetag (+ bignum-digits-offset 2) res nil nil nil) (storew rax res bignum-digits-offset other-pointer-lowtag) (storew rcx res (1+ bignum-digits-offset) other-pointer-lowtag) (inst clc) (inst ret) @@ -149,17 +150,17 @@ (:translate %negate) (:save-p t)) ((:arg x (descriptor-reg any-reg) rdx-offset) - (:res res (descriptor-reg any-reg) rdx-offset) - (:temp rcx unsigned-reg rcx-offset)) + (:res res (descriptor-reg any-reg) rdx-offset)) (inst test :byte x fixnum-tag-mask) (inst jmp :nz GENERIC) (move res x) (inst neg res) ; (- most-negative-fixnum) is BIGNUM - (inst jmp :o BIGNUM) - (inst clc) (inst ret) - BIGNUM - (inst shr res n-fixnum-tag-bits) ; sign bit is data - remove type bits - (return-single-word-bignum res rcx res) + ;; This constant isn't really a fixup, but it's easiest for me to think about it + ;; that way for now. It should really do whatever EMIT-EA does for a CONSTANT. + (inst cmov :o res (ea (make-fixup nil :code-object + (+ (ash code-constants-offset word-shift) + (- other-pointer-lowtag))) + rip-tn)) (inst clc) (inst ret) GENERIC (tail-call-static-fun '%negate 1)) @@ -300,34 +301,35 @@ (inst jmp :ge POSITIVE) (inst not rdx) POSITIVE)) - (unless (memq :popcnt *backend-subfeatures*) - ;; POPCNT = ECX bit 23 - (multiple-value-bind (byte bit) (floor (+ 23 n-fixnum-tag-bits) - n-byte-bits) - (inst test :byte - (static-symbol-value-ea '*cpuid-fn1-ecx* byte) (ash 1 bit))) - (inst jmp :z slow)) + (when (memq :popcnt *backend-subfeatures*) ; always use POPCNT ;; Intel's implementation of POPCNT on some models treats it as ;; a 2-operand ALU op in the manner of ADD,SUB,etc which means that ;; it falsely appears to need data from the destination register. ;; The workaround is to clear the destination. ;; See http://stackoverflow.com/questions/25078285 - (unless (location= result arg) + (unless (location= result arg) ;; We only break the spurious dep. chain if result isn't the same ;; register as arg. (If they're location=, don't trash the arg!) - (inst xor result result)) + (inst xor :dword result result)) + (inst popcnt result arg) + (return-from ,name)) + + ;; Conditionally use POPCNT + (test-cpu-feature cpu-has-popcnt) + (inst jmp :z slow) + (unless (location= result arg) + (inst xor :dword result result)) (inst popcnt result arg) (inst jmp done) slow - (unless (memq :popcnt *backend-subfeatures*) - (move rdx arg) - (invoke-asm-routine 'call 'logcount vop) - (move result rdx)) + (move rdx arg) + (invoke-asm-routine 'call 'logcount vop) + (move result rdx) done)))) (def-it unsigned-byte-64-count 14 unsigned-reg unsigned-num) (def-it signed-byte-64-count 15 signed-reg signed-num :signed t) (def-it positive-fixnum-count 12 any-reg positive-fixnum) - (def-it positive-fixnum-count 13 any-reg fixnum :signed t)) + (def-it signed-fixnum-count 13 any-reg fixnum :signed t)) ;;; General case of EQL @@ -350,8 +352,8 @@ ;;; It just doesn't seem worth the effort to do all that. (defparameter eql-dispatch nil) (define-assembly-routine (generic-eql (:return-style :none)) - ((:temp rax unsigned-reg rax-offset) - (:temp rcx unsigned-reg rcx-offset) + ((:temp rcx unsigned-reg rcx-offset) ; callee-saved + (:temp rax unsigned-reg rax-offset) ; vop temps (:temp rsi unsigned-reg rsi-offset) (:temp rdi unsigned-reg rdi-offset) (:temp r11 unsigned-reg r11-offset)) @@ -444,10 +446,24 @@ ;; as for all other objects (in byte index 3 of the header) (inst push rcx) (inst mov rcx (ea (- other-pointer-lowtag) rdi)) - (inst shl rcx 1) + (inst shl rcx 1) ; shift out GC mark bit (inst shr rcx (1+ n-widetag-bits)) - (inst jmp :z epilogue) ; zero payload length, can this happen? + #+bignum-assertions + (progn (inst mov r11 rcx) + (inst or r11 1)) ; align to start of ubsan bits compare-loop + #+bignum-assertions + (let ((ok1 (gen-label)) (ok2 (gen-label))) + (inst dec rcx) + (inst bt (ea (- n-word-bytes other-pointer-lowtag) rsi r11 8) rcx) + (inst jmp :nc ok1) + (inst break halt-trap) + (emit-label ok1) + (inst bt (ea (- n-word-bytes other-pointer-lowtag) rdi r11 8) rcx) + (inst jmp :nc ok2) + (inst break halt-trap) + (emit-label ok2) + (inst inc rcx)) (inst mov rax (ea (- other-pointer-lowtag) rsi rcx 8)) (inst cmp rax (ea (- other-pointer-lowtag) rdi rcx 8)) (inst jmp :ne epilogue) @@ -526,8 +542,6 @@ (inst cmp rcx (ea (- other-pointer-lowtag) y)) (inst jmp :ne done) (inst shr rcx n-widetag-bits) - ;; can you have 0 payload words? Probably not, but let's be safe here. - (inst jmp :z done) loop (inst mov rax (ea (- other-pointer-lowtag) x rcx 8)) (inst cmp rax (ea (- other-pointer-lowtag) y rcx 8)) diff --git a/src/assembly/x86-64/array.lisp b/src/assembly/x86-64/array.lisp index 02948e5b24..e3c1a1eabe 100644 --- a/src/assembly/x86-64/array.lisp +++ b/src/assembly/x86-64/array.lisp @@ -16,7 +16,7 @@ ;;; to deal with pre- and post-loop pieces for proper alignment. ;;; Alternatively, if the CPU has the enhanced MOVSB feature, use REP STOS ;;; depending on the number of elements to be written. -(define-assembly-routine (vector-fill/t +(define-assembly-routine (vector-fill/t ; <-- this could work on raw bits too (:translate vector-fill/t) (:policy :fast-safe)) ((:arg vector (descriptor-reg) rdx-offset) @@ -25,16 +25,46 @@ (:arg end (any-reg descriptor-reg) rsi-offset) (:res res (descriptor-reg) rdx-offset) (:temp count unsigned-reg rcx-offset) + (:temp end-card-index unsigned-reg rbx-offset) ;; storage class doesn't matter since all float regs ;; and sse regs map to the same storage base. (:temp wordpair double-reg float0-offset)) (move res vector) ; to "use" res + + ;; Mark each GC card of the vector unless ITEM is not a pointer + ;; (NIL is non-pointer) or the COUNT is 0. + (inst cmp start end) + (inst jmp :ge DONE) + (inst lea :dword count (ea -3 item)) ; same as POINTERP (see type-vops) + (inst test :byte count #b11) + (inst jmp :nz DONE-CARD-MARKING) + (inst cmp item nil-value) + (inst jmp :e DONE-CARD-MARKING) + + (let ((disp (- (ash vector-data-offset word-shift) other-pointer-lowtag)) + (card-index count) + (loop (gen-label))) + ;; Compute EA of starting and ending (inclusive) indices + (inst lea card-index (ea disp vector start (ash 1 (- word-shift n-fixnum-tag-bits)))) + (inst lea end-card-index (ea (- disp n-word-bytes) + vector end (ash 1 (- word-shift n-fixnum-tag-bits)))) + (inst shr card-index gencgc-card-shift) + (inst shr end-card-index gencgc-card-shift) + (inst and :dword card-index card-index-mask) + (inst and :dword end-card-index card-index-mask) + (emit-label LOOP) + (inst mov :byte (ea gc-card-table-reg-tn card-index) 0) ; mark one card + (inst cmp card-index end-card-index) + (inst jmp :e DONE-CARD-MARKING) + (inst inc :dword card-index) + (inst and :dword card-index card-index-mask) + (inst jmp LOOP)) + + DONE-CARD-MARKING (move count end) (inst sub count start) - ;; 'start' and 'limit' will be interior pointers into 'vector', + ;; 'start' is an interior pointer to 'vector', ;; but 'vector' is pinned because it's in a register, so this is ok. - ;; If we had a precise GC we'd want to keep start and limit as offsets - ;; because we couldn't tie them both to the vector. (inst lea start (ea (- (ash vector-data-offset word-shift) other-pointer-lowtag) vector start (ash 1 (- word-shift n-fixnum-tag-bits)))) ;; REP STOS has a fixed cost that makes it suboptimal below @@ -50,7 +80,7 @@ (inst shr count n-fixnum-tag-bits) (inst rep) - (inst stos item) + (inst stos :qword) DONE (inst ret) UNROLL diff --git a/src/assembly/x86-64/assem-rtns.lisp b/src/assembly/x86-64/assem-rtns.lisp index e52fe4054b..76e1787ec8 100644 --- a/src/assembly/x86-64/assem-rtns.lisp +++ b/src/assembly/x86-64/assem-rtns.lisp @@ -223,37 +223,29 @@ (%lea-for-lowtag-test rbx-tn fun fun-pointer-lowtag) (inst test :byte rbx-tn lowtag-mask) - (inst jmp :nz (make-fixup 'call-symbol :assembly-routine)) + (inst jmp :nz (entry-point-label 'call-symbol)) (inst jmp (ea (- (* closure-fun-slot n-word-bytes) fun-pointer-lowtag) fun))) #+sb-assembling (define-assembly-routine (call-symbol (:return-style :none)) - ((:temp fun (any-reg descriptor-reg) rax-offset) - (:temp length (any-reg descriptor-reg) rax-offset) - (:temp vector (any-reg descriptor-reg) rbx-offset)) - (%lea-for-lowtag-test vector fun other-pointer-lowtag) - (inst test :byte vector lowtag-mask) + ((:temp fun (any-reg descriptor-reg) rax-offset) ; FUN = the symbol + (:temp fdefn (any-reg descriptor-reg) rbx-offset)) + (%lea-for-lowtag-test fdefn fun other-pointer-lowtag) + (inst test :byte fdefn lowtag-mask) (inst jmp :nz not-callable) (inst cmp :byte (ea (- other-pointer-lowtag) fun) symbol-widetag) (inst jmp :ne not-callable) - (load-symbol-info-vector vector fun) - ;; info-vector-fdefn - (inst cmp vector nil-value) - (inst jmp :e undefined) - - (inst mov :dword r10-tn (ea (- (* 2 n-word-bytes) other-pointer-lowtag) vector)) - (inst and :dword r10-tn (fixnumize (1- (ash 1 (* info-number-bits 2))))) - (inst cmp :dword r10-tn (fixnumize (1+ (ash +fdefn-info-num+ info-number-bits)))) - (inst jmp :b undefined) - - (loadw length vector 1 other-pointer-lowtag) - (inst mov fun (ea (- 8 other-pointer-lowtag) vector length - (ash 1 (- word-shift n-fixnum-tag-bits)))) - (inst jmp (ea (- (* fdefn-raw-addr-slot n-word-bytes) other-pointer-lowtag) fun)) + (loadw fdefn fun symbol-fdefn-slot other-pointer-lowtag) + (inst test :dword fdefn fdefn) + (inst jmp :z UNDEFINED) + ;; I think we need this MOV because the undefined-function trap examines RAX + ;; to see what FDEFN you tried to call through. + (inst mov fun fdefn) + (inst jmp (ea (- (* fdefn-raw-addr-slot n-word-bytes) other-pointer-lowtag) fdefn)) UNDEFINED - (inst jmp (make-fixup 'undefined-tramp :assembly-routine)) + (inst jmp (entry-point-label 'undefined-tramp)) NOT-CALLABLE (inst cmp fun nil-value) ;; NIL doesn't have SYMBOL-WIDETAG (inst jmp :e undefined) @@ -268,9 +260,10 @@ ((:arg target (descriptor-reg any-reg) rdx-offset) (:arg start any-reg rbx-offset) (:arg count any-reg rcx-offset) + (:temp bsp-temp any-reg r11-offset) (:temp catch any-reg rax-offset)) - (declare (ignore start count)) + (declare (ignore start count bsp-temp)) (load-tl-symbol-value catch *current-catch-block*) @@ -301,7 +294,7 @@ ;; Here RAX points to catch block containing symbol pointed to by RDX. ;; An extra RET gets stuffed after the JMP, but oh well. You can't just change ;; the :return-style to :none because that also affects the call sequence. - (inst jmp (make-fixup 'unwind :assembly-routine))) + (inst jmp (entry-point-label 'unwind))) ;;; Simply return and enter the loop in UNWIND instead of calling ;;; UNWIND directly @@ -323,6 +316,7 @@ (:temp where unsigned-reg r8-offset) (:temp symbol unsigned-reg r9-offset) (:temp value unsigned-reg r10-offset) + (:temp bsp-temp unsigned-reg r11-offset) (:temp zero complex-double-reg float0-offset)) AGAIN (let ((error (generate-error-code nil 'invalid-unwind-error))) @@ -349,7 +343,7 @@ ;; run it twice) one of the variables being unbound can be ;; *interrupts-enabled* (loadw where uwp unwind-block-bsp-slot) - (unbind-to-here where symbol value temp-reg-tn zero) + (unbind-to-here where symbol value bsp-temp zero) ;; Set next unwind protect context. (loadw block uwp unwind-block-uwp-slot) @@ -370,7 +364,7 @@ DO-EXIT (loadw where block unwind-block-bsp-slot) - (unbind-to-here where symbol value temp-reg-tn zero) + (unbind-to-here where symbol value bsp-temp zero) (loadw rbp-tn block unwind-block-cfp-slot) @@ -383,104 +377,99 @@ #+sb-assembling (defun ensure-thread-base-tn-loaded () #-sb-thread - (progn + (let ((fixup (make-fixup "all_threads" :foreign-dataref))) ;; Load THREAD-BASE-TN from the all_threads. Does not need to be spilled ;; to stack, because we do do not give the register allocator access to it. ;; And call_into_lisp saves it as per convention, not that it matters, ;; because there's no way to get back into C code anyhow. - (inst mov thread-base-tn (ea (make-fixup "all_threads" :foreign-dataref))) - (inst mov thread-base-tn (ea thread-base-tn)))) - -;;; Perform a store to code, updating the GC page (card) protection bits. -;;; This is not a "good" implementation of soft card marking. -;;; It is used *only* for pages of code. The real implementation (work in -;;; progress) will differ in at least these ways: -;;; - there will be no use of pseudo-atomic -;;; - stores will be inlined without the helper routine below -;;; - will be insensitive to the size of a page table entry -;;; - will avoid use of a :lock prefix by allocating 1 byte per mark -;;; - won't need to subtract the heap base or compare to the card count -;;; to compute the mark address, so will use fewer instructions. -;;; It is similar in that for code objects (indeed most objects -;;; except simple-vectors), it marks the object header which is -;;; not always on the same GC card affected by the store operation -;;; + #-immobile-space (inst mov thread-tn (ea fixup)) + #+immobile-space (inst mov thread-tn (rip-relative-ea fixup)) + (inst mov thread-tn (ea thread-tn)))) + +;;; Perform a store to code, updating the GC card mark bit. +;;; This has two additional complications beyond the ordinary +;;; generational barrier: +;;; 1. immobile code uses its own card table which maps linearly +;;; with the page index, unlike the dynamic space card table +;;; that has a different way of computing a card address. +;;; 2. code objects are so seldom written that it behooves us to +;;; track within each object whether it has been written, +;;; thereby avoiding scanning of unwritten objects. +;;; This is especially important for immobile space where +;;; it is likely that new code will be co-located on a page +;;; with old code due to the non-moving allocator. #+sb-assembling (define-assembly-routine (code-header-set (:return-style :none)) () - (inst push rax-tn) - (inst push rdi-tn) - ;; stack: spill[2], ret-pc, object, index, value-to-store - + ;; stack: ret-pc, object, index, value-to-store + (symbol-macrolet ((object (ea 8 rsp-tn)) + (word-index (ea 16 rsp-tn)) + (newval (ea 24 rsp-tn)) + ;; these are declared as vop temporaries + (rax rax-tn) + (rdx rdx-tn) + (rdi rdi-tn)) (ensure-thread-base-tn-loaded) (pseudo-atomic () (assemble () #+immobile-space (progn - (inst mov temp-reg-tn (ea 24 rsp-tn)) - (inst sub temp-reg-tn (thread-slot-ea thread-varyobj-space-addr-slot)) - (inst shr temp-reg-tn (1- (integer-length immobile-card-bytes))) - (inst cmp temp-reg-tn (thread-slot-ea thread-varyobj-card-count-slot)) + (inst mov rax object) + (inst sub rax (thread-slot-ea thread-text-space-addr-slot)) + (inst shr rax (1- (integer-length immobile-card-bytes))) + (inst cmp rax (thread-slot-ea thread-text-card-count-slot)) (inst jmp :ae try-dynamic-space) - (inst mov rdi-tn (thread-slot-ea thread-varyobj-card-marks-slot)) - (inst bts :dword (ea rdi-tn) temp-reg-tn :lock) + (inst mov rdi (thread-slot-ea thread-text-card-marks-slot)) + (inst bts :dword :lock (ea rdi-tn) rax) (inst jmp store)) - TRY-DYNAMIC-SPACE - (inst mov temp-reg-tn (ea 24 rsp-tn)) ; reload - (inst sub temp-reg-tn (thread-slot-ea thread-dynspace-addr-slot)) - (inst shr temp-reg-tn (1- (integer-length gencgc-card-bytes))) - (inst cmp temp-reg-tn (thread-slot-ea thread-dynspace-card-count-slot)) - (inst jmp :ae store) ; neither dynamic nor immobile space. (weird!) - - ;; sizeof (struct page) depends on GENCGC-CARD-BYTES - ;; It's 4+2+1+1 = 8 bytes if GENCGC-CARD-BYTES is (unsigned-byte 16), - ;; or 4+4+1+1 = 10 bytes (rounded to 12) if wider than (unsigned-byte 16). - ;; See the corresponding alien structure definition in 'room.lisp' - (cond ((typep gencgc-card-bytes '(unsigned-byte 16)) - (inst shl temp-reg-tn 3) ; multiply by 8 - (inst add temp-reg-tn (thread-slot-ea thread-dynspace-pte-base-slot)) - ;; clear WP - bit index 5 of flags byte - (inst and :byte (ea 6 temp-reg-tn) (lognot (ash 1 5)) :lock)) - (t - (inst lea temp-reg-tn (ea temp-reg-tn temp-reg-tn 2)) ; multiply by 3 - (inst shl temp-reg-tn 2) ; then by 4, = 12 - (inst add temp-reg-tn (thread-slot-ea thread-dynspace-pte-base-slot)) - ;; clear WP - (inst and :byte (ea 8 temp-reg-tn) (lognot (ash 1 5)) :lock))) - + (inst mov rax object) + (inst shr rax gencgc-card-shift) + (inst and :dword rax card-index-mask) + (inst mov :byte (ea gc-card-table-reg-tn rax) 0) STORE - (inst mov rdi-tn (ea 24 rsp-tn)) ; object - (inst mov temp-reg-tn (ea 32 rsp-tn)) ; word index - (inst mov rax-tn (ea 40 rsp-tn)) ; newval + (inst mov rdi object) + (inst mov rdx word-index) + (inst mov rax newval) ;; set 'written' flag in the code header - (inst or :byte (ea (- 3 other-pointer-lowtag) rdi-tn) #x40 :lock) + (inst or :byte :lock (ea (- 3 other-pointer-lowtag) rdi) #x40) ;; store newval into object - (inst mov (ea (- other-pointer-lowtag) rdi-tn temp-reg-tn n-word-bytes) - rax-tn))) - (inst pop rdi-tn) ; restore - (inst pop rax-tn) + (inst mov (ea (- other-pointer-lowtag) rdi rdx n-word-bytes) rax)))) (inst ret 24)) ; remove 3 stack args -;;; Currently the only objects for which it is necessary to call TOUCH-GC-CARD -;;; are those on varyobj pages. Therefore if no immobile-space feature, skip it. -;;; This is not the situation for pages of code, where we manually toggle dynamic space -;;; card marks so that when recording code coverage we don't incur the cost of a kernel -;;; signal on a page that was otherwise untouched. -#+sb-assembling -(define-assembly-routine (touch-gc-card (:return-style :none)) () - ;; stack: ret-pc, object - #+immobile-space - (progn - (ensure-thread-base-tn-loaded) - (inst mov temp-reg-tn (ea 8 rsp-tn)) - (inst sub temp-reg-tn (thread-slot-ea thread-varyobj-space-addr-slot)) - (inst shr temp-reg-tn (integer-length (1- immobile-card-bytes))) - (inst cmp temp-reg-tn (thread-slot-ea thread-varyobj-card-count-slot)) - (inst jmp :ae DONE) - - (inst push rax-tn) - (inst mov rax-tn (thread-slot-ea thread-varyobj-card-marks-slot)) - (inst bts :dword (ea rax-tn) temp-reg-tn :lock) - (inst pop rax-tn)) - DONE - (inst ret 8)) ; remove 1 stack arg +;;; These are trampolines, but they benefit from not being in the 'tramps' file +;;; because they'll automatically get a vop and an assembly routine this way, +;;; where tramps only get the assembly routine. +(define-assembly-routine (update-object-layout + (:policy :fast-safe) + (:translate update-object-layout) + (:return-style :raw)) + ((:arg x (descriptor-reg) rdx-offset) + (:res r (descriptor-reg) rdx-offset)) + (progn x r) + (with-registers-preserved (lisp :except rdx-tn) + (call-static-fun 'update-object-layout 1))) + +(define-assembly-routine (sb-impl::install-hash-table-lock + (:policy :fast-safe) + (:translate sb-impl::install-hash-table-lock) + (:return-style :raw)) + ((:arg x (descriptor-reg) rdx-offset) + (:res r (descriptor-reg) rdx-offset)) + (progn x r) + (with-registers-preserved (lisp :except rdx-tn) + (call-static-fun 'sb-impl::install-hash-table-lock 1))) + +;;; From a perspective of reducing code bloat, this asm routine does not merit +;;; being one at all. A vop would suffice, because it's a single-use vop. +;;; However the WITH-REGISTERS-PRESERVED macro seems to think that it is utilized +;;; only by asm code in *ASSEMBLER-ROUTINES*. I had trouble with it otherwise. +(define-assembly-routine (alloc-code (:return-style :raw)) + ((:arg c-arg1 (signed-reg) rdi-offset) + (:arg c-arg2 (signed-reg) rsi-offset) + (:res res (descriptor-reg) rdx-offset)) + (progn c-arg1 c-arg2) ; "use" the args + ;; Don't preserve the register which holds the lisp return value + (with-registers-preserved (c :except rdx-tn) + (pseudo-atomic () + (inst call (make-fixup "alloc_code_object" :foreign))) + (move res rax-tn))) diff --git a/src/assembly/x86-64/support.lisp b/src/assembly/x86-64/support.lisp index ae8f97619e..18ec222ab9 100644 --- a/src/assembly/x86-64/support.lisp +++ b/src/assembly/x86-64/support.lisp @@ -9,36 +9,40 @@ (in-package "SB-VM") +(defun test-cpu-feature (feature-bit) + (multiple-value-bind (byte bit) + (floor (+ feature-bit n-fixnum-tag-bits) n-byte-bits) + (inst test :byte (static-symbol-value-ea '*cpu-feature-bits* byte) (ash 1 bit)))) + +(defun uniquify-fixup (name &aux (asmstream *asmstream*)) + (or (cdr (assoc name (sb-assem::asmstream-indirection-table asmstream))) + (let ((label (gen-label))) + (assemble (:elsewhere) + (emit-label label) + (inst jmp (ea (make-fixup name :assembly-routine*)))) + (push (cons name label) (sb-assem::asmstream-indirection-table asmstream)) + label))) + (defun invoke-asm-routine (inst routine vop) (declare (ignorable vop)) - (let ((fixup - (cond ((sb-c::code-immobile-p vop) - (make-fixup routine :assembly-routine)) - (t - (ea (make-fixup routine :assembly-routine*)))))) - (ecase inst - (jmp (inst jmp fixup)) - (call (inst call fixup))))) + (inst* (the (member jmp call) inst) + (if (sb-c::code-immobile-p vop) + (make-fixup routine :assembly-routine) + (ea (make-fixup routine :assembly-routine*))))) (defun generate-call-sequence (name style vop options) (declare (ignore options)) (ecase style - (:raw - (values - `((note-this-location ,vop :call-site) - (invoke-asm-routine 'call ',name ,vop) - (note-this-location ,vop :single-value-return)) - nil)) - ((:full-call :full-call-no-return) - (values - `((note-this-location ,vop :call-site) - (invoke-asm-routine 'call ',name ,vop) - (note-this-location ,vop :single-value-return)) - '((:save-p :compute-only)))) - (:none - (values - `((invoke-asm-routine 'jmp ',name ,vop)) - nil)))) + ((:raw :full-call :full-call-no-return) + (values + `((note-this-location ,vop :call-site) + (invoke-asm-routine 'call ',name ,vop) + (note-this-location ,vop :single-value-return)) + (if (eql style :raw) nil '((:save-p :compute-only))))) + (:none + (values + `((invoke-asm-routine 'jmp ',name ,vop)) + nil)))) (defun generate-return-sequence (style) (ecase style @@ -49,22 +53,18 @@ (inst ret))) ((:none :full-call-no-return)))) -(defmacro with-registers-preserved ((fpr-size &key except) &body body) - (multiple-value-bind (mnemonic fpr-align getter) - (ecase fpr-size - (xmm (values 'movaps 16 'sb-x86-64-asm::get-fpr)) - (ymm (values 'vmovaps 32 'sb-x86-64-asm::get-avx2))) - (flet ((fpr-save/restore (operation) - (loop for regno below 16 - collect - (ecase operation - (push - `(inst ,mnemonic (ea ,(* regno fpr-align) rsp-tn) (,getter ,regno))) - (pop - `(inst ,mnemonic (,getter ,regno) (ea ,(* regno fpr-align) rsp-tn)))))) - (gpr-save/restore (operation except) +(defmacro with-registers-preserved ((convention &key except) &body body) + ;: Convention: + ;; C = save GPRs that C call can change + ;; Lisp = save GPRs that lisp call can change + (let ((fpr-align 64)) + (flet ((gpr-save/restore (operation except) (declare (type (member push pop) operation)) - (let ((registers '(rax-tn rcx-tn rdx-tn rsi-tn rdi-tn r8-tn r9-tn r10-tn r11-tn))) + (let ((registers (ecase convention + ;; RBX and R12..R15 are preserved across C call + (c '#1=(rax-tn rcx-tn rdx-tn rsi-tn rdi-tn r8-tn r9-tn r10-tn r11-tn)) + ;; all GPRs are potentially destroyed across lisp call + (lisp '(rbx-tn r12-tn #-sb-thread r13-tn r14-tn r15-tn . #1#))))) (when except (setf registers (remove except registers))) ;; Preserve alignment @@ -77,11 +77,27 @@ (inst push rbp-tn) (inst mov rbp-tn rsp-tn) (inst and rsp-tn ,(- fpr-align)) - (inst sub rsp-tn ,(* 16 fpr-align)) - ,@(fpr-save/restore 'push) + (inst sub rsp-tn ,(+ 512 64 256)) ;; XSAVE area + ;; Using rip-relative call indirect makes shrinkwrapped cores work + ;; with no modification whatsoever to editcore. + ;; It wouldn't work straightforwardly using a call indirect + ;; with an absolute EA. + ;; KLUDGE: index of FPR-SAVE is 4 + ;; (inst call (ea (make-fixup 'fpr-save :assembly-routine*))) + (inst call (ea (make-fixup nil :code-object + (+ (component-header-length) + (* 4 sb-vm:n-word-bytes) + (- other-pointer-lowtag))) + rip-tn)) ,@(gpr-save/restore 'push except) ,@body ,@(gpr-save/restore 'pop except) - ,@(fpr-save/restore 'pop) + ;; KLUDGE: index of FPR-RESTORE is 6 + ;; (inst call (ea (make-fixup 'fpr-restore :assembly-routine*))) + (inst call (ea (make-fixup nil :code-object + (+ (component-header-length) + (* 6 sb-vm:n-word-bytes) + (- other-pointer-lowtag))) + rip-tn)) (inst mov rsp-tn rbp-tn) (inst pop rbp-tn))))) diff --git a/src/assembly/x86-64/tramps.lisp b/src/assembly/x86-64/tramps.lisp index 3ef881c8be..681df79d18 100644 --- a/src/assembly/x86-64/tramps.lisp +++ b/src/assembly/x86-64/tramps.lisp @@ -5,75 +5,112 @@ (in-package "SB-VM") -;;; It is arbitrary whether each of the next 4 routines is named ALLOC-something, -;;; exporting an additional entry named CONS-something, versus being named CONS-something -;;; and exporting ALLOC-something. It just depends on which of those you would like -;;; to have to set and clear the low bit to match ALLOC-DISPATCH. -;;; Think of "cons" as meaning the generic sense of "consing", not as actually -;;; allocating conses, because fixed-sized non-cons object allocation may enter -;;; through the cons entry point. Cons cells *must* use that entry point. -(define-assembly-routine (alloc->rnn (:export cons->rnn)) () - (inst or :byte (ea 8 rsp-tn) 1) - CONS->RNN - (with-registers-preserved (xmm) +(macrolet ((do-fprs (operation regset) + (multiple-value-bind (mnemonic fpr-align) + (ecase regset + (:xmm (values 'movaps 16)) + (:ymm (values 'vmovaps 32))) + `(progn + ,@(loop for regno below 16 + collect + (ecase operation + (push + `(inst ,mnemonic (ea ,(+ 8 (* regno fpr-align)) rsp-tn) + (sb-x86-64-asm::get-fpr ,regset ,regno))) + (pop + `(inst ,mnemonic (sb-x86-64-asm::get-fpr ,regset ,regno) + (ea ,(+ 8 (* regno fpr-align)) rsp-tn))))))))) + ;; Caller will have allocated 512+64+256 bytes above the stack-pointer + ;; prior to the CALL. Use that as the save area. + (define-assembly-routine (save-ymm) () + (inst push rax-tn) + (inst push rdx-tn) + (inst mov rax-tn 7) + (zeroize rdx-tn) + ;; Zero the header + (loop for i from (+ 512 24) by 8 + repeat 8 + do + (inst mov (ea i rsp-tn) rdx-tn)) + (inst xsave (ea 24 rsp-tn)) + (inst pop rdx-tn) + (inst pop rax-tn)) + (define-assembly-routine (restore-ymm) () + (inst push rax-tn) + (inst push rdx-tn) + (inst mov rax-tn 7) + (zeroize rdx-tn) + (inst xrstor (ea 24 rsp-tn)) + (inst pop rdx-tn) + (inst pop rax-tn)) + ;; As above, but only 256 bytes of the save area are needed, the rest goes to waste. + (define-assembly-routine (save-xmm (:export fpr-save)) () + fpr-save ; KLUDGE: this is element 4 of the entry point vector + (do-fprs push :xmm)) + (define-assembly-routine (restore-xmm (:export fpr-restore)) () + fpr-restore ; KLUDGE: this is element 6 of the entry point vector + (do-fprs pop :xmm))) + +(macrolet ((def-routine-pair (name&options vars &body code) + `(progn + (symbol-macrolet ((system-tlab-p 0)) + (define-assembly-routine ,name&options ,vars ,@code)) + ;; In absence of this feature, don't define extra routines. + ;; (Don't want to have a way to mess things up) + #+system-tlabs + (symbol-macrolet ((system-tlab-p 2)) + (define-assembly-routine + (,(symbolicate "SYS-" (car name&options)) . ,(cdr name&options)) + ,vars ,@code))))) + +(def-routine-pair (alloc-tramp) () + (with-registers-preserved (c) (inst mov rdi-tn (ea 16 rbp-tn)) - (inst call (make-fixup 'alloc-dispatch :assembly-routine)) + (inst mov rsi-tn system-tlab-p) + (inst call (make-fixup "alloc" :foreign)) (inst mov (ea 16 rbp-tn) rax-tn))) ; result onto stack -#+avx2 -(define-assembly-routine (alloc->rnn.avx2 (:export cons->rnn.avx2)) () - (inst or :byte (ea 8 rsp-tn) 1) - CONS->RNN.AVX2 - (with-registers-preserved (ymm) +(def-routine-pair (list-alloc-tramp) () ; CONS, ACONS, LIST, LIST* + (with-registers-preserved (c) (inst mov rdi-tn (ea 16 rbp-tn)) - (inst call (make-fixup 'alloc-dispatch :assembly-routine)) + (inst mov rsi-tn system-tlab-p) + (inst call (make-fixup "alloc_list" :foreign)) (inst mov (ea 16 rbp-tn) rax-tn))) ; result onto stack -(define-assembly-routine (alloc->r11 (:export cons->r11) (:return-style :none)) () - (inst or :byte (ea 8 rsp-tn) 1) - CONS->R11 - (with-registers-preserved (xmm :except r11-tn) +(def-routine-pair (listify-&rest (:return-style :none)) () + (with-registers-preserved (c) + (inst mov rdi-tn (ea 16 rbp-tn)) ; 1st C call arg + (inst mov rsi-tn (ea 24 rbp-tn)) ; 2nd C call arg + (inst mov rdx-tn system-tlab-p) + (inst call (make-fixup "listify_rest_arg" :foreign)) + (inst mov (ea 24 rbp-tn) rax-tn)) ; result + (inst ret 8)) ; pop one argument; the unpopped word now holds the result + +(def-routine-pair (make-list (:return-style :none)) () + (with-registers-preserved (c) + (inst mov rdi-tn (ea 16 rbp-tn)) ; 1st C call arg + (inst mov rsi-tn (ea 24 rbp-tn)) ; 2nd C call arg + (inst mov rdx-tn system-tlab-p) + (inst call (make-fixup "make_list" :foreign)) + (inst mov (ea 24 rbp-tn) rax-tn)) ; result + (inst ret 8)) ; pop one argument; the unpopped word now holds the result +) + +(define-assembly-routine (alloc-funinstance) () + (with-registers-preserved (c) (inst mov rdi-tn (ea 16 rbp-tn)) - (inst call (make-fixup 'alloc-dispatch :assembly-routine)) - (inst mov r11-tn rax-tn)) - (inst ret 8)) ; pop argument - -#+avx2 -(define-assembly-routine (alloc->r11.avx2 (:export cons->r11.avx2) (:return-style :none)) () - (inst or :byte (ea 8 rsp-tn) 1) - CONS->R11.AVX2 - (with-registers-preserved (ymm :except r11-tn) - (inst mov rdi-tn (ea 16 rbp-tn)) - (inst call (make-fixup 'alloc-dispatch :assembly-routine)) - (inst mov r11-tn rax-tn)) - (inst ret 8)) ; pop argument - -(define-assembly-routine (alloc-dispatch (:return-style :none)) () - ;; If RDI has a 0 in the low bit, then we're allocating cons cells. - ;; A 1 bit signifies anything other than cons cells, and is equivalent - ;; to "could this object consume large-object pages" in gencgc. - (inst test :byte rdi-tn 1) - (inst jmp :z (make-fixup "alloc_list" :foreign)) - (inst xor :byte rdi-tn 1) ; clear the bit - (inst jmp (make-fixup "alloc" :foreign))) - -;;; There's no layout allocator preserving YMM regs because MAKE-LAYOUT entails a full call. -#+immobile-space -(define-assembly-routine (alloc-layout) () - (with-registers-preserved (xmm :except r11-tn) - (inst call (make-fixup "alloc_layout" :foreign)) - (inst mov r11-tn rax-tn))) + (inst call (make-fixup "alloc_funinstance" :foreign)) + (inst mov (ea 16 rbp-tn) rax-tn))) ;;; These routines are for the deterministic consing profiler. ;;; The C support routine's argument is the return PC. -;;; FIXME: we're missing routines that preserve YMM. I guess nobody cares. (define-assembly-routine (enable-alloc-counter) () - (with-registers-preserved (xmm) + (with-registers-preserved (c) (inst lea rdi-tn (ea 8 rbp-tn)) (pseudo-atomic () (inst call (make-fixup "allocation_tracker_counted" :foreign))))) (define-assembly-routine (enable-sized-alloc-counter) () - (with-registers-preserved (xmm) + (with-registers-preserved (c) (inst lea rdi-tn (ea 8 rbp-tn)) (pseudo-atomic () (inst call (make-fixup "allocation_tracker_sized" :foreign))))) @@ -84,30 +121,49 @@ (inst push (ea n-word-bytes rbp-tn)) (inst jmp (ea (- (* closure-fun-slot n-word-bytes) fun-pointer-lowtag) rax))) +#+win32 +(define-assembly-routine + (undefined-alien-tramp (:return-style :none)) + () + (error-call nil 'undefined-alien-fun-error rbx-tn)) + +#-win32 (define-assembly-routine (undefined-alien-tramp (:return-style :none)) () + ;; This routine computes into RBX the address of the linkage table entry that was called, + ;; corresponding to the undefined alien function. (inst push rax-tn) ; save registers in case we want to see the old values (inst push rbx-tn) ;; load RAX with the PC after the call site (inst mov rax-tn (ea 16 rsp-tn)) ;; load RBX with the signed 32-bit immediate from the call instruction (inst movsx '(:dword :qword) rbx-tn (ea -4 rax-tn)) + ;; The decoding seems scary, but it's actually not. Any C call-out instruction has + ;; a 4-byte trailing operand, with the preceding byte being unique. ;; if at [PC-5] we see #x25 then it was a call with 32-bit mem addr ;; if ... #xE8 then ... 32-bit offset - (inst cmp :byte (ea -5 rax-tn) #x25) - (inst jmp :e ABSOLUTE) - (inst cmp :byte (ea -5 rax-tn) #xE8) - (inst jmp :e RELATIVE) + ;; if ... #x92 then it was "call *DISP(%r10)" where r10 is the table base + #-immobile-space ; only non-relocatable alien linkage table can use "CALL [ABS]" form + (progn (inst cmp :byte (ea -5 rax-tn) #x25) + (inst jmp :e ABSOLUTE)) + #+immobile-space ; only relocatable alien linkage table can use "CALL rel32" form + (progn (inst cmp :byte (ea -5 rax-tn) #xE8) + (inst jmp :e RELATIVE) + (inst cmp :byte (ea -5 rax-tn) #x92) + (inst jmp :e ABSOLUTE)) ;; failing those, assume RBX was valid. ("can't happen") (inst mov rbx-tn (ea rsp-tn)) ; restore pushed value of RBX (inst jmp trap) ABSOLUTE - (inst lea rbx-tn (ea -8 rbx-tn)) + #-immobile-space (inst sub rbx-tn 8) + #+immobile-space (inst lea rbx-tn (ea -8 r10-tn rbx-tn)) (inst jmp TRAP) RELATIVE (inst add rbx-tn rax-tn) TRAP + ;; XXX: why aren't we adding something to the stack pointer to balance the two pushes? + ;; (I guess we can only THROW at this point, so it doesn't matter) (error-call nil 'undefined-alien-fun-error rbx-tn)) ;;; the closure trampoline - entered when a global function is a closure @@ -121,7 +177,8 @@ ;;; installed as a globally named function. The fdefn contains a jump opcode ;;; to a tiny code component specific to the particular closure. ;;; The trampoline is responsible for loading RAX, since named calls don't. -#-immobile-code +;;; However, #+immobile-code might still need CLOSURE-TRAMP for any fdefn +;;; for which the compiler chooses not to use "direct" call convention. (define-assembly-routine (closure-tramp (:return-style :none)) () @@ -134,40 +191,8 @@ (loadw rax-tn rax-tn funcallable-instance-function-slot fun-pointer-lowtag) (inst jmp (object-slot-ea rax-tn closure-fun-slot fun-pointer-lowtag))) -(define-assembly-routine (ensure-symbol-hash (:return-style :none)) () - #+avx2 - (progn - (inst mov temp-reg-tn (ea (make-fixup "avx2_supported" :foreign-dataref))) - (inst test :byte (ea temp-reg-tn) 1) - (inst jmp :z call-preserving-xmm-only) - (with-registers-preserved (ymm :except r11-tn) - (inst mov rdx-tn (ea 16 rbp-tn)) ; arg - (call-static-fun 'ensure-symbol-hash 1) - (inst mov (ea 16 rbp-tn) rdx-tn)) ; result to arg passing loc - (inst ret)) - call-preserving-xmm-only - (with-registers-preserved (xmm :except r11-tn) +(define-assembly-routine (ensure-symbol-hash (:return-style :raw)) () + (with-registers-preserved (lisp) (inst mov rdx-tn (ea 16 rbp-tn)) ; arg (call-static-fun 'ensure-symbol-hash 1) - (inst mov (ea 16 rbp-tn) rdx-tn)) ; result to arg passing loc - (inst ret)) - -(define-assembly-routine (invalid-layout-trap (:return-style :none)) () - #+avx2 - (progn - (inst mov temp-reg-tn (ea (make-fixup "avx2_supported" :foreign-dataref))) - (inst test :byte (ea temp-reg-tn) 1) - (inst jmp :z call-preserving-xmm-only) - (with-registers-preserved (ymm :except r11-tn) - (inst mov rdx-tn (ea 16 rbp-tn)) ; arg1 - (inst mov rdi-tn (ea 24 rbp-tn)) ; arg2 - (call-static-fun 'update-object-layout-or-invalid 2) - (inst mov (ea 24 rbp-tn) rdx-tn)) ; result to arg passing loc - (inst ret 8)) ; remove 1 arg. Caller pops the result - call-preserving-xmm-only - (with-registers-preserved (xmm :except r11-tn) - (inst mov rdx-tn (ea 16 rbp-tn)) ; arg1 - (inst mov rdi-tn (ea 24 rbp-tn)) ; arg2 - (call-static-fun 'update-object-layout-or-invalid 2) - (inst mov (ea 24 rbp-tn) rdx-tn)) ; result to arg passing loc - (inst ret 8)) ; remove 1 arg. Caller pops the result + (inst mov (ea 16 rbp-tn) rdx-tn))) ; result to arg passing loc diff --git a/src/assembly/x86/alloc.lisp b/src/assembly/x86/alloc.lisp index 85f6686b63..8427f7158f 100644 --- a/src/assembly/x86/alloc.lisp +++ b/src/assembly/x86/alloc.lisp @@ -50,14 +50,14 @@ `((inst mov ,scratch-tn (make-ea :dword :disp +win32-tib-arbitrary-field-offset+) :fs) - (inst sub ,reg (make-ea :dword :disp (ash thread-alloc-region-slot 2) + (inst sub ,reg (make-ea :dword :disp (ash thread-mixed-tlab-slot 2) :base ,scratch-tn)))) #-win32 `(#+sb-thread (inst sub ,reg - (make-ea :dword :disp (ash thread-alloc-region-slot 2)) + (make-ea :dword :disp (ash thread-mixed-tlab-slot 2)) :fs) #-sb-thread (inst sub ,reg - (make-ea :dword :disp (+ 8 static-space-start))))))) + (make-ea :dword :disp mixed-region)))))) (case reg ;; Now that we're using lisp asm code instead of a .S file ;; this could be done more intelligently - the macro can decide @@ -139,16 +139,6 @@ (def edi) (def esi)) -#+sb-assembling -(macrolet ((def (tn-name &aux (reg (subseq (string tn-name) 0 3))) - `(define-assembly-routine (,(symbolicate "ALLOCATE-CONS-TO-" reg)) - ((:temp result descriptor-reg ,(tn-offset (symbol-value tn-name)))) - (pseudo-atomic () - (allocation 'list (* 2 n-word-bytes) - list-pointer-lowtag nil nil result))))) - (progn (def eax-tn) (def ebx-tn) (def ecx-tn) - (def edx-tn) (def esi-tn) (def edi-tn))) - #+sb-thread (define-assembly-routine (alloc-tls-index (:translate ensure-symbol-tls-index) diff --git a/src/assembly/x86/assem-rtns.lisp b/src/assembly/x86/assem-rtns.lisp index 73b6d70cb7..c19dcb6366 100644 --- a/src/assembly/x86/assem-rtns.lisp +++ b/src/assembly/x86/assem-rtns.lisp @@ -256,7 +256,7 @@ ;; Here EAX points to catch block containing symbol pointed to by EDX. ;; An extra RET gets stuffed after the JMP, but oh well. You can't just change ;; the :return-style to :none because that also affects the call sequence. - (inst jmp (make-fixup 'unwind :assembly-routine))) + (inst jmp (entry-point-label 'unwind))) ;;;; non-local exit noise @@ -482,77 +482,6 @@ (inst mov eax-tn 1) ;; exception-continue-search (inst ret)) -#+sb-assembling -(define-assembly-routine (code-header-set (:return-style :none)) () - (inst push eax-tn) - (inst push edx-tn) - (inst push edi-tn) - ;; stack: spill[3], ret-pc, object, index, value-to-store - - (symbol-macrolet ((object (make-ea :dword :base esp-tn :disp 16)) - (word-index (make-ea :dword :base esp-tn :disp 20)) - (newval (make-ea :dword :base esp-tn :disp 24)) - (prefix #+(and sb-thread (not win32)) :fs - #-(and sb-thread (not win32)) nil)) - (flet ((thread-slot-ea (slot-index) - (make-ea :dword - #+(or (not sb-thread) win32) :base #+(or (not sb-thread) win32) edi-tn - :disp (ash slot-index word-shift)))) - #-sb-thread - (progn - ;; Load 'all_threads' into EDI (which was already spilled) - ;; as the register with which to access thread slots. - (inst mov edi-tn - (make-ea :dword :disp (make-fixup "all_threads" :foreign-dataref))) - (inst mov edi-tn (make-ea :dword :base edi-tn))) - #+(and win32 sb-thread) - (inst mov edi-tn (make-ea :dword :disp +win32-tib-arbitrary-field-offset+) :fs) - - (inst mov eax-tn object) ; object - (inst sub eax-tn (thread-slot-ea thread-dynspace-addr-slot) prefix) - (inst shr eax-tn (1- (integer-length gencgc-card-bytes))) - (pseudo-atomic () - (assemble () - (inst cmp eax-tn (thread-slot-ea thread-dynspace-card-count-slot) - prefix) - (inst jmp :ae STORE) ; not dynamic space - ;; sizeof (struct page) depends on GENCGC-CARD-BYTES - ;; It's 4+2+1+1 = 8 bytes if GENCGC-CARD-BYTES is (unsigned-byte 16), - ;; or 4+4+1+1 = 10 bytes (rounded to 12) if wider than (unsigned-byte 16). - ;; See the corresponding alien structure definition in 'room.lisp' - (cond ((typep gencgc-card-bytes '(unsigned-byte 16)) - (inst shl eax-tn 3) ; multiply by 8 - (inst add eax-tn (thread-slot-ea thread-dynspace-pte-base-slot) - prefix) - ;; clear WP - bit index 5 of flags byte - (inst and (make-ea :byte :base eax-tn :disp 6) (lognot (ash 1 5)) - :lock)) - (t - (inst lea eax-tn ; multiply by 3 - (make-ea :dword :base eax-tn :index eax-tn :scale 2)) - (inst shl eax-tn 2) ; then by 4, = 12 - (inst add eax-tn (thread-slot-ea thread-dynspace-pte-base-slot) - prefix) - ;; clear WP - (inst and (make-ea :byte :base eax-tn :disp 8) (lognot (ash 1 5)) - :lock))) - STORE - (inst mov edi-tn object) - (inst mov edx-tn word-index) - (inst mov eax-tn newval) - ;; set 'written' flag in the code header - (inst or (make-ea :byte :base edi-tn :disp (- 3 other-pointer-lowtag)) - #x40 :lock) - ;; store newval into object - (inst mov (make-ea :dword :base edi-tn - :index edx-tn :scale (ash 1 word-shift) - :disp (- other-pointer-lowtag)) - eax-tn))))) - (inst pop edi-tn) ; restore - (inst pop edx-tn) - (inst pop eax-tn) - (inst ret 12)) ; remove 3 stack args - #| Turns out that setting the direction flag not only requires trapping into microcode, but also prevents the processor from using its fast REP diff --git a/src/code/alien-callback.lisp b/src/code/alien-callback.lisp index 4bc9070e42..0f0ffe930a 100644 --- a/src/code/alien-callback.lisp +++ b/src/code/alien-callback.lisp @@ -12,11 +12,16 @@ (in-package "SB-ALIEN") -;;; ALIEN-CALLBACK is supposed to be external in SB-ALIEN-INTERNALS, but the -;;; export gets lost, and then 'chill' gets a conflict with SB-ALIEN over it. +;;; ALIEN-CALLBACK is supposed to be external in SB-ALIEN-INTERNALS, +;;; but the export gets lost (as this is now a warm-loaded file), and +;;; then 'chill' gets a conflict with SB-ALIEN over it. (eval-when (:compile-toplevel :load-toplevel :execute) (export (intern "ALIEN-CALLBACK" "SB-ALIEN-INTERNALS") - "SB-ALIEN-INTERNALS")) + "SB-ALIEN-INTERNALS") + (export (intern "DEFINE-ALIEN-CALLABLE" "SB-ALIEN") + "SB-ALIEN") + (export (intern "ALIEN-CALLABLE-FUNCTION" "SB-ALIEN") + "SB-ALIEN")) ;;;; ALIEN CALLBACKS ;;;; @@ -110,16 +115,13 @@ ENTER-ALIEN-CALLBACK pulls the corresponding trampoline out and calls it.") ;; bother anyone about that sad fact (declare (muffle-conditions compiler-note) (optimize speed)) - ;; FIXME: the saps are not gc safe - (let ((args-sap (int-sap - (sb-kernel:get-lisp-obj-address args-pointer))) - (res-sap (int-sap - (sb-kernel:get-lisp-obj-address result-pointer)))) + (let ((args-sap (descriptor-sap args-pointer)) + (res-sap (descriptor-sap result-pointer))) (declare (ignorable args-sap res-sap)) - (with-alien + (let ,(loop with offset = 0 - for spec in argument-specs + for spec in argument-specs ;; KLUDGE: At least one platform requires additional ;; alignment beyond a single machine word for certain ;; arguments. Accept an additional delta (for the @@ -130,8 +132,7 @@ ENTER-ALIEN-CALLBACK pulls the corresponding trampoline out and calls it.") for (accessor-form alignment) = (multiple-value-list (alien-callback-accessor-form spec 'args-sap offset)) - collect `(,(pop argument-names) ,spec - :local ,accessor-form) + collect `(,(pop argument-names) ,accessor-form) do (incf offset (+ (alien-callback-argument-bytes spec env) (or alignment 0)))) ,(flet ((store (spec real-type) @@ -254,7 +255,7 @@ and a secondary return value of true if the callback is still valid." (defun invalidate-alien-callback (alien) "Invalidates the callback designated by the alien, if any, allowing the associated lisp function to be GC'd, and causing further calls to the same -callback signal an error." +callback to signal an error." (let ((info (alien-callback-info alien))) (when (and info (callback-info-function info)) ;; sap cache @@ -278,27 +279,59 @@ callback signal an error." (parse-callback-specification result-type typed-lambda-list) `(alien-callback ,specifier (lambda ,lambda-list ,@forms)))) -;;; FIXME: Should subsequent (SETF FDEFINITION) affect the callback or not? -;;; What about subsequent DEFINE-ALIEN-CALLBACKs? My guess is that changing -;;; the FDEFINITION should invalidate the callback, and redefining the -;;; callback should change existing callbacks to point to the new defintion. -(defmacro define-alien-callback (name result-type typed-lambda-list &body forms) - "Defines #'NAME as a function with the given body and lambda-list, and NAME as -the alien callback for that function with the given alien type." - (declare (symbol name)) - (multiple-value-bind (specifier lambda-list) - (parse-callback-specification result-type typed-lambda-list) +;;;; Alien callables + +(define-load-time-global *alien-callables* (make-hash-table :test #'eq) + "Map from Lisp symbols to the alien callable functions they name.") + +(defmacro define-alien-callable (name result-type typed-lambda-list &body body) + "Define an alien callable function in the alien callable namespace with result +type RESULT-TYPE and with lambda list specifying the alien types of the +arguments." + (multiple-value-bind (lisp-name alien-name) + (pick-lisp-and-alien-names name) + (declare (ignore alien-name)) `(progn - (defun ,name ,lambda-list ,@forms) - (defparameter ,name (alien-callback ,specifier #',name))))) + (invalidate-alien-callable ',lisp-name) + (setf (gethash ',lisp-name *alien-callables*) + (alien-lambda ,result-type ,typed-lambda-list ,@body))))) + +(defun alien-callable-function (name) + "Return the alien callable function associated with NAME." + (gethash name *alien-callables*)) + +(defun invalidate-alien-callable (name) + "Invalidates the callable designated by the alien, if any, allowing the +associated lisp function to be GC'd, and causing further calls to the same +callable to signal an error." + (multiple-value-bind (lisp-name alien-name) + (pick-lisp-and-alien-names name) + (declare (ignore alien-name)) + (let ((alien (alien-callable-function lisp-name))) + (when alien + (invalidate-alien-callback alien))) + (remhash lisp-name *alien-callables*))) + +(defun initialize-alien-callable-symbol (name) + "Initialize the alien symbol named by NAME with its alien callable +function value." + (multiple-value-bind (lisp-name alien-name) + (pick-lisp-and-alien-names name) + (setf (%alien-value (foreign-symbol-sap alien-name t) + 0 + (make-alien-pointer-type)) + (cast (alien-callable-function lisp-name) (* t))))) (in-package "SB-THREAD") #+sb-thread (defun enter-foreign-callback (index return arguments) - (let ((thread (without-gcing - ;; Hold off GCing until *current-thread* is set up - (setf *current-thread* - (make-foreign-thread :name "foreign callback"))))) - (dx-flet ((enter () - (sb-alien::enter-alien-callback index return arguments))) - (new-lisp-thread-trampoline thread nil #'enter nil)))) + (let ((thread (init-thread-local-storage (make-foreign-thread)))) + (dx-let ((startup-info (vector nil ; trampoline is n/a + nil ; cell in *STARTING-THREADS* is n/a + #'sb-alien::enter-alien-callback + (list index return arguments) + nil nil))) ; sigmask + fpu state bits + (copy-primitive-thread-fields thread) + (setf (thread-startup-info thread) startup-info) + (update-all-threads (thread-primitive-thread thread) thread) + (run)))) diff --git a/src/code/alien-type.lisp b/src/code/alien-type.lisp index 5a4bc8956c..57600ce32d 100644 --- a/src/code/alien-type.lisp +++ b/src/code/alien-type.lisp @@ -13,57 +13,13 @@ (in-package "SB-KERNEL") -(/show0 "code/alien-type.lisp 16") - (sb-xc:defstruct (alien-value (:copier nil) (:constructor %sap-alien (sap type))) (sap nil :type sb-sys:system-area-pointer) (type nil :type sb-alien::alien-type)) -(sb-xc:proclaim '(freeze-type alien-value)) - -(!begin-collecting-cold-init-forms) - -(define-type-class alien :enumerable nil :might-contain-other-types nil) - -(define-type-method (alien :negate) (type) (make-negation-type type)) - -(define-type-method (alien :unparse) (type) - `(alien ,(unparse-alien-type (alien-type-type-alien-type type)))) - -(define-type-method (alien :simple-subtypep) (type1 type2) - (values (alien-subtype-p (alien-type-type-alien-type type1) - (alien-type-type-alien-type type2)) - t)) +(proclaim '(freeze-type alien-value)) ;;; KLUDGE: This !DEFINE-SUPERCLASSES gets executed much later than the ;;; others (toplevel form time instead of cold load init time) because ;;; ALIEN-VALUE itself is a structure which isn't defined until fairly ;;; late. (!define-superclasses alien ((alien-value)) progn) - -(define-type-method (alien :simple-=) (type1 type2) - (let ((alien-type-1 (alien-type-type-alien-type type1)) - (alien-type-2 (alien-type-type-alien-type type2))) - (values (or (eq alien-type-1 alien-type-2) - (alien-type-= alien-type-1 alien-type-2)) - t))) - -(def-type-translator alien (&optional (alien-type nil)) - (typecase alien-type - (null - (make-alien-type-type)) - (alien-type - (make-alien-type-type alien-type)) - (t - (make-alien-type-type (parse-alien-type alien-type (make-null-lexenv)))))) - -(defun make-alien-type-type (&optional alien-type) - (if alien-type - (let ((lisp-rep-type (compute-lisp-rep-type alien-type))) - (if lisp-rep-type - (single-value-specifier-type lisp-rep-type) - (%make-alien-type-type alien-type))) - *universal-type*)) - -(!defun-from-collected-cold-init-forms !alien-type-cold-init) - -(/show0 "code/alien-type.lisp end of file") diff --git a/src/code/host-alieneval.lisp b/src/code/alieneval.lisp similarity index 78% rename from src/code/host-alieneval.lisp rename to src/code/alieneval.lisp index e64469211a..72db076f81 100644 --- a/src/code/host-alieneval.lisp +++ b/src/code/alieneval.lisp @@ -1,5 +1,5 @@ -;;;; the part of the Alien implementation which is needed at -;;;; cross-compilation time +;;;; This file contains parts of the Alien implementation that +;;;; are not part of the compiler. ;;;; This software is part of the SBCL system. See the README file for ;;;; more information. @@ -12,7 +12,10 @@ (in-package "SB-ALIEN") -(/show0 "host-alieneval.lisp 15") +#-sb-xc-host (sb-impl::define-thread-local *saved-fp* nil) + +(defvar *default-c-string-external-format* nil) + ;;;; utility functions @@ -22,14 +25,84 @@ (defun guess-alignment (bits) (cond ((null bits) nil) - #-(or (and x86 (not win32)) (and ppc darwin)) ((> bits 32) 64) + #-(and x86 (not win32)) ((> bits 32) 64) ((> bits 16) 32) ((> bits 8) 16) ((> bits 1) 8) (t 1))) + ;;;; ALIEN-TYPE-INFO stuff +(eval-when (#-sb-xc :compile-toplevel :load-toplevel :execute) + +(defstruct (alien-type-class (:copier nil)) + (name nil :type symbol) + (defstruct-name nil :type symbol) + (include nil :type (or null alien-type-class)) + (unparse nil :type (or null function)) + (type= nil :type (or null function)) + (lisp-rep nil :type (or null function)) + (alien-rep nil :type (or null function)) + (extract-gen nil :type (or null function)) + (deposit-gen nil :type (or null function)) + (naturalize-gen nil :type (or null function)) + (deport-gen nil :type (or null function)) + (deport-alloc-gen nil :type (or null function)) + (deport-pin-p nil :type (or null function)) + ;; Cast? + (arg-tn nil :type (or null function)) + (result-tn nil :type (or null function)) + (subtypep nil :type (or null function))) + +(defmethod print-object ((type-class alien-type-class) stream) + (print-unreadable-object (type-class stream :type t) + (prin1 (alien-type-class-name type-class) stream))) + +;;; An benefit of EQL tables of symbols is that they will never rehash due to key +;;; movement, because they use the symbol's hash which is constant even across +;;; core restart, whereas EQ tables might rehash. +;;; Perhaps we should consider using SXHASH on symbols for EQ tables. +;;; And frankly, why isn't this particular table not a globaldb info instead? +(defglobal *alien-type-classes* (make-hash-table)) ; keys are symbols + +(defun alien-type-class-or-lose (name) + (or (gethash name *alien-type-classes*) + (error "no alien type class ~S" name))) + +(defun create-alien-type-class-if-necessary (name defstruct-name include) + (let ((old (gethash name *alien-type-classes*)) + (include (and include (alien-type-class-or-lose include)))) + (if old + (setf (alien-type-class-include old) include) + (setf (gethash name *alien-type-classes*) + (make-alien-type-class :name name + :defstruct-name defstruct-name + :include include))))) + +(defconstant-eqx +method-slot-alist+ + '((:unparse . alien-type-class-unparse) + (:type= . alien-type-class-type=) + (:subtypep . alien-type-class-subtypep) + (:lisp-rep . alien-type-class-lisp-rep) + (:alien-rep . alien-type-class-alien-rep) + (:extract-gen . alien-type-class-extract-gen) + (:deposit-gen . alien-type-class-deposit-gen) + (:naturalize-gen . alien-type-class-naturalize-gen) + (:deport-gen . alien-type-class-deport-gen) + (:deport-alloc-gen . alien-type-class-deport-alloc-gen) + (:deport-pin-p . alien-type-class-deport-pin-p) + ;; cast? + (:arg-tn . alien-type-class-arg-tn) + (:result-tn . alien-type-class-result-tn)) + #'equal) + +(defun method-slot (method) + (cdr (or (assoc method +method-slot-alist+) + (error "no method ~S" method)))) + +) ; EVAL-WHEN + ;;; We define a keyword "BOA" constructor so that we can reference the ;;; slot names in init forms. (defmacro define-alien-type-class ((name &key include include-args) &rest slots) @@ -79,9 +152,54 @@ ,@body) (setf (,(method-slot method) (alien-type-class-or-lose ',class)) #',defun-name)))) + +(defmacro invoke-alien-type-method (method type &rest args) + (let ((slot (method-slot method))) + (once-only ((type type)) + `(funcall (do ((class (alien-type-class-or-lose (alien-type-class ,type)) + (alien-type-class-include class))) + ((null class) + (error "method ~S not defined for ~S" + ',method (alien-type-class ,type))) + (let ((fn (,slot class))) + (when fn + (return fn)))) + ,type ,@args)))) + + +;;;; the root alien type + +(eval-when (:compile-toplevel :load-toplevel :execute) + (create-alien-type-class-if-necessary 'root 'alien-type nil)) + +(def!struct (alien-type + (:copier nil) + (:constructor make-alien-type + (&key class bits alignment + &aux (alignment + (or alignment (guess-alignment bits)))))) + (class 'root :type symbol :read-only t) + (bits nil :type (or null unsigned-byte)) + (alignment nil :type (or null unsigned-byte))) +(!set-load-form-method alien-type (:xc :target)) + +(defmethod print-object ((type alien-type) stream) + (print-unreadable-object (type stream :type t) + (sb-impl:print-type-specifier stream (unparse-alien-type type)))) + ;;;; type parsing and unparsing +(defvar *new-auxiliary-types* nil) + +;;; Process stuff in a new scope. +(defmacro with-auxiliary-alien-types (env &body body) + ``(symbol-macrolet ((&auxiliary-type-definitions& + ,(append *new-auxiliary-types* + (auxiliary-type-definitions ,env)))) + ,(let ((*new-auxiliary-types* nil)) + ,@body))) + ;;; CMU CL used COMPILER-LET to bind *AUXILIARY-TYPE-DEFINITIONS*, and ;;; COMPILER-LET is no longer supported by ANSI or SBCL. Instead, we ;;; follow the suggestion in CLTL2 of using SYMBOL-MACROLET to achieve @@ -152,6 +270,11 @@ (when (info :alien-type kind name) (error "attempt to shadow definition of ~A ~S" kind name))))) +;;; the list of record types that have already been unparsed. This is +;;; used to keep from outputting the slots again if the same structure +;;; shows up twice. +(defvar *record-types-already-unparsed*) + (defun unparse-alien-type (type) "Convert the alien-type structure TYPE back into a list specification of the type." @@ -164,133 +287,77 @@ ;;; *RECORD-TYPES-ALREADY-UNPARSED*. (defun %unparse-alien-type (type) (invoke-alien-type-method :unparse type)) + ;;;; alien type defining stuff -(eval-when (#-sb-xc :compile-toplevel :load-toplevel :execute) - (defun %define-alien-type-translator (name translator) - (setf (info :alien-type :kind name) :primitive) - (setf (info :alien-type :translator name) translator) - (clear-info :alien-type :definition name) - name)) - -(eval-when (#-sb-xc :compile-toplevel :load-toplevel :execute) - (defun %def-auxiliary-alien-types (types source-location) - (dolist (info types) - ;; Clear up the type we're about to define from the toplevel - ;; *new-auxiliary-types* (local scopes take care of themselves). - ;; Unless this is done we never actually get back the full type - ;; from INFO, since the *new-auxiliary-types* have precendence. - (setf *new-auxiliary-types* - (remove info *new-auxiliary-types* - :test (lambda (a b) - (and (eq (first a) (first b)) - (eq (second a) (second b)))))) - (destructuring-bind (kind name defn) info - (let ((old (info :alien-type kind name))) - (unless (or (null old) (alien-type-= old defn)) - (warn "redefining ~A ~S to be:~% ~S,~%was:~% ~S" - kind name defn old))) - (setf (info :alien-type kind name) defn - (info :source-location :alien-type name) source-location)))) - - (defun %define-alien-type (name new source-location) - (ecase (info :alien-type :kind name) - (:primitive - (error "~/sb-impl:print-type-specifier/ is a built-in alien type." - name)) - (:defined - (let ((old (info :alien-type :definition name))) - (unless (or (null old) (alien-type-= new old)) - (warn "redefining ~S to be:~% ~ +(defmacro define-alien-type-translator (name lambda-list &body body) + (let ((defun-name (symbolicate "ALIEN-" name "-TYPE-TRANSLATOR")) + (macro-lambda + (make-macro-lambda nil lambda-list body + 'define-alien-type-translator name))) + `(progn + (defun ,defun-name ,(second macro-lambda) ,@(cddr macro-lambda)) + (%define-alien-type-translator ',name #',defun-name)))) + +(defun %define-alien-type-translator (name translator) + (setf (info :alien-type :kind name) :primitive) + (setf (info :alien-type :translator name) translator) + (clear-info :alien-type :definition name) + name) + +(defmacro define-alien-type (name type &environment env) + "Define the alien type NAME to be equivalent to TYPE. Name may be NIL for + STRUCT and UNION types, in which case the name is taken from the type + specifier." + (with-auxiliary-alien-types env + (let ((alien-type (parse-alien-type type env))) + `(eval-when (:compile-toplevel :load-toplevel :execute) + ,@(when *new-auxiliary-types* + `((%def-auxiliary-alien-types ',*new-auxiliary-types* + (sb-c:source-location)))) + ,@(when name + `((%define-alien-type ',name ',alien-type (sb-c:source-location)))))))) + +(defun %def-auxiliary-alien-types (types source-location) + (dolist (info types) + ;; Clear up the type we're about to define from the toplevel + ;; *new-auxiliary-types* (local scopes take care of themselves). + ;; Unless this is done we never actually get back the full type + ;; from INFO, since the *new-auxiliary-types* have precendence. + (setf *new-auxiliary-types* + (remove info *new-auxiliary-types* + :test (lambda (a b) + (and (eq (first a) (first b)) + (eq (second a) (second b)))))) + (destructuring-bind (kind name defn) info + (let ((old (info :alien-type kind name))) + (unless (or (null old) (alien-type-= old defn)) + (warn "redefining ~A ~S to be:~% ~S,~%was:~% ~S" + kind name defn old))) + (setf (info :alien-type kind name) defn + (info :source-location :alien-type name) source-location)))) + +(defun %define-alien-type (name new source-location) + (ecase (info :alien-type :kind name) + (:primitive + (error "~/sb-impl:print-type-specifier/ is a built-in alien type." + name)) + (:defined + (let ((old (info :alien-type :definition name))) + (unless (or (null old) (alien-type-= new old)) + (warn "redefining ~S to be:~% ~ ~/sb-impl:print-type-specifier/,~%was~% ~ ~/sb-impl:print-type-specifier/" - name - (unparse-alien-type new) - (unparse-alien-type old))))) - (:unknown)) - (setf (info :alien-type :definition name) new) - (setf (info :alien-type :kind name) :defined) - (setf (info :source-location :alien-type name) source-location) - name)) - -;;;; the root alien type - -(eval-when (:compile-toplevel :load-toplevel :execute) - (create-alien-type-class-if-necessary 'root 'alien-type nil)) - -(defmethod print-object ((type alien-type) stream) - (print-unreadable-object (type stream :type t) - (sb-impl:print-type-specifier stream (unparse-alien-type type)))) - -;;;; the SAP type - -(define-alien-type-class (system-area-pointer)) - -(define-alien-type-translator system-area-pointer () - (make-alien-system-area-pointer-type - :bits sb-vm:n-machine-word-bits)) - -(define-alien-type-method (system-area-pointer :unparse) (type) - (declare (ignore type)) - 'system-area-pointer) - -(define-alien-type-method (system-area-pointer :lisp-rep) (type) - (declare (ignore type)) - 'system-area-pointer) - -(define-alien-type-method (system-area-pointer :alien-rep) (type context) - (declare (ignore type context)) - 'system-area-pointer) - -(define-alien-type-method (system-area-pointer :naturalize-gen) (type alien) - (declare (ignore type)) - alien) - -(define-alien-type-method (system-area-pointer :deport-gen) (type object) - (declare (ignore type)) - (/noshow "doing alien type method SYSTEM-AREA-POINTER :DEPORT-GEN" object) - object) + name + (unparse-alien-type new) + (unparse-alien-type old))))) + (:unknown)) + (setf (info :alien-type :definition name) new) + (setf (info :alien-type :kind name) :defined) + (setf (info :source-location :alien-type name) source-location) + name) -(define-alien-type-method (system-area-pointer :extract-gen) (type sap offset) - (declare (ignore type)) - `(sap-ref-sap ,sap (/ ,offset sb-vm:n-byte-bits))) - -;;;; the ALIEN-VALUE type - -(define-alien-type-class (alien-value :include system-area-pointer)) - -(define-alien-type-method (alien-value :lisp-rep) (type) - (declare (ignore type)) - nil) - -(define-alien-type-method (alien-value :naturalize-gen) (type alien) - `(%sap-alien ,alien ',type)) - -(define-alien-type-method (alien-value :deport-gen) (type value) - (declare (ignore type)) - (/noshow "doing alien type method ALIEN-VALUE :DEPORT-GEN" value) - `(alien-sap ,value)) - -;;; HEAP-ALIEN-INFO -- defstruct. -;;; -(defmethod print-object ((info heap-alien-info) stream) - (print-unreadable-object (info stream :type t) - (format stream "~S ~S~@[ (data)~]" - (heap-alien-info-alien-name info) - (unparse-alien-type (heap-alien-info-type info)) - (heap-alien-info-datap info)))) - -;;; The form to evaluate to produce the SAP pointing to where in the heap -;;; it is. -(defun heap-alien-info-sap-form (info) - `(foreign-symbol-sap ,(heap-alien-info-alien-name info) - ,(heap-alien-info-datap info))) - -#-sb-xc-host ; No FOREIGN-SYMBOL-SAP -(defun heap-alien-info-sap (info) - (foreign-symbol-sap (heap-alien-info-alien-name info) - (heap-alien-info-datap info))) ;;;; Interfaces to the different methods @@ -368,6 +435,7 @@ ;;; details. (defun compute-alien-rep-type (type &optional (context :normal)) (invoke-alien-type-method :alien-rep type context)) + ;;;; default methods @@ -462,20 +530,20 @@ ;; the register uninitialized. On those platforms, we use an ;; alien-rep of the full register width when checking for purposes ;; of return values and override the naturalize method to perform - ;; the sign extension (in compiler/target/c-call.lisp). + ;; the sign extension (in compiler/{arch}/c-call.lisp). (ecase context - ((:normal #-(or alpha x86 x86-64) :result) + ((:normal #-(or x86 x86-64) :result) (list (if (alien-integer-type-signed type) 'signed-byte 'unsigned-byte) (alien-integer-type-bits type))) - #+(or alpha x86 x86-64) + #+(or x86 x86-64) (:result (list (if (alien-integer-type-signed type) 'signed-byte 'unsigned-byte) (max (alien-integer-type-bits type) sb-vm:n-machine-word-bits))))) ;;; As per the comment in the :ALIEN-REP method above, this is defined -;;; elsewhere for alpha and x86oids. -#-(or alpha x86 x86-64) +;;; elsewhere for x86oids. +#-(or x86 x86-64) (define-alien-type-method (integer :naturalize-gen) (type alien) (declare (ignore type)) alien) @@ -484,20 +552,23 @@ (declare (ignore type)) value) +(defun alien-integer->sap-ref-fun (signed bits) + (if signed + (case bits + (8 'signed-sap-ref-8) + (16 'signed-sap-ref-16) + (32 'signed-sap-ref-32) + (64 'signed-sap-ref-64)) + (case bits + (8 'sap-ref-8) + (16 'sap-ref-16) + (32 'sap-ref-32) + (64 'sap-ref-64)))) + (define-alien-type-method (integer :extract-gen) (type sap offset) (declare (type alien-integer-type type)) - (let ((ref-fun - (if (alien-integer-type-signed type) - (case (alien-integer-type-bits type) - (8 'signed-sap-ref-8) - (16 'signed-sap-ref-16) - (32 'signed-sap-ref-32) - (64 'signed-sap-ref-64)) - (case (alien-integer-type-bits type) - (8 'sap-ref-8) - (16 'sap-ref-16) - (32 'sap-ref-32) - (64 'sap-ref-64))))) + (let ((ref-fun (alien-integer->sap-ref-fun (alien-integer-type-signed type) + (alien-integer-type-bits type)))) (if ref-fun `(,ref-fun ,sap (/ ,offset sb-vm:n-byte-bits)) (error "cannot extract ~W-bit integers" @@ -705,6 +776,57 @@ (declare (ignore type)) `(sap-ref-double ,sap (/ ,offset sb-vm:n-byte-bits))) + +;;;; the SAP type + +(define-alien-type-class (system-area-pointer)) + +(define-alien-type-translator system-area-pointer () + (make-alien-system-area-pointer-type + :bits sb-vm:n-machine-word-bits)) + +(define-alien-type-method (system-area-pointer :unparse) (type) + (declare (ignore type)) + 'system-area-pointer) + +(define-alien-type-method (system-area-pointer :lisp-rep) (type) + (declare (ignore type)) + 'system-area-pointer) + +(define-alien-type-method (system-area-pointer :alien-rep) (type context) + (declare (ignore type context)) + 'system-area-pointer) + +(define-alien-type-method (system-area-pointer :naturalize-gen) (type alien) + (declare (ignore type)) + alien) + +(define-alien-type-method (system-area-pointer :deport-gen) (type object) + (declare (ignore type)) + (/noshow "doing alien type method SYSTEM-AREA-POINTER :DEPORT-GEN" object) + object) + +(define-alien-type-method (system-area-pointer :extract-gen) (type sap offset) + (declare (ignore type)) + `(sap-ref-sap ,sap (/ ,offset sb-vm:n-byte-bits))) + + +;;;; the ALIEN-VALUE type + +(define-alien-type-class (alien-value :include system-area-pointer)) + +(define-alien-type-method (alien-value :lisp-rep) (type) + (declare (ignore type)) + nil) + +(define-alien-type-method (alien-value :naturalize-gen) (type alien) + `(%sap-alien ,alien ',type)) + +(define-alien-type-method (alien-value :deport-gen) (type value) + (declare (ignore type)) + (/noshow "doing alien type method ALIEN-VALUE :DEPORT-GEN" value) + `(alien-sap ,value)) + ;;;; the POINTER type @@ -989,9 +1111,19 @@ (or (memq type2 types) (match-fields types))) (let ((*alien-type-matches* (make-hash-table :test #'eq))) (match-fields)))))) + ;;;; the FUNCTION and VALUES alien types +;;; not documented in CMU CL:-( +;;; +;;; reverse engineering observations: +;;; * seems to be set when translating return values +;;; * seems to enable the translation of (VALUES), which is the +;;; Lisp idiom for C's return type "void" (which is likely +;;; why it's set when when translating return values) +(defvar *values-type-okay* nil) + ;;; Calling-convention spec, typically one of predefined keywords. ;;; Add or remove as needed for target platform. It makes sense to ;;; support :cdecl everywhere. @@ -1017,7 +1149,7 @@ (arg-types (missing-arg) :type list) ;; The 3rd-party CFFI library uses presence of &REST in an argument list ;; as indicative of "..." in the C prototype. We can record that too. - (varargs nil :type (or boolean (eql :unspecified))) + (varargs nil :type (or boolean fixnum (eql :unspecified))) (stub nil :type (or null function)) (convention nil :type calling-convention)) ;;; The safe default is to assume that everything is varargs. @@ -1035,6 +1167,7 @@ ;;; result-type in this case. If convention is ever to become a part ;;; of result-type, such a syntax can be retained. + (define-alien-type-translator function (result-type &rest arg-types &environment env) (binding* (((bare-result-type calling-convention) @@ -1042,14 +1175,21 @@ ((cons calling-convention *) (values (second result-type) (first result-type))) (t result-type))) - (varargs (eq (car (last arg-types)) '&rest))) + (varargs (or (eq (car (last arg-types)) '&rest) + (position '&optional arg-types))) + (arg-types (if (integerp varargs) + (remove '&optional arg-types) + arg-types))) (make-alien-fun-type :convention calling-convention :result-type (let ((*values-type-okay* t)) (parse-alien-type bare-result-type env)) :varargs (or varargs *alien-fun-type-varargs-default*) - :arg-types (mapcar (lambda (arg-type) (parse-alien-type arg-type env)) - (if varargs (butlast arg-types) arg-types))))) + :arg-types (mapcar (lambda (arg-type) + (parse-alien-type arg-type env)) + (if (eql varargs t) + (butlast arg-types) + arg-types))))) (define-alien-type-method (fun :unparse) (type) `(function ,(let ((result-type @@ -1094,9 +1234,37 @@ (every #'alien-type-= (alien-values-type-values type1) (alien-values-type-values type2)))) + -;;;; a structure definition needed both in the target and in the -;;;; cross-compilation host +;;;; alien variables + +;;; Information describing a heap-allocated alien. +(def!struct (heap-alien-info (:copier nil)) + ;; The type of this alien. + (type (missing-arg) :type alien-type) + ;; Its name. + (alien-name (missing-arg) :type simple-string) + ;; Data or code? + (datap (missing-arg) :type boolean)) +(!set-load-form-method heap-alien-info (:xc :target)) + +(defmethod print-object ((info heap-alien-info) stream) + (print-unreadable-object (info stream :type t) + (format stream "~S ~S~@[ (data)~]" + (heap-alien-info-alien-name info) + (unparse-alien-type (heap-alien-info-type info)) + (heap-alien-info-datap info)))) + +;;; The form to evaluate to produce the SAP pointing to where in the heap +;;; it is. +(defun heap-alien-info-sap-form (info) + `(foreign-symbol-sap ,(heap-alien-info-alien-name info) + ,(heap-alien-info-datap info))) + +#-sb-xc-host ; No FOREIGN-SYMBOL-SAP +(defun heap-alien-info-sap (info) + (foreign-symbol-sap (heap-alien-info-alien-name info) + (heap-alien-info-datap info))) ;;; information about local aliens. The WITH-ALIEN macro builds one of ;;; these structures and LOCAL-ALIEN and friends communicate @@ -1120,40 +1288,29 @@ "~:[~;(forced to stack) ~]~S" (local-alien-info-force-to-memory-p info) (unparse-alien-type (local-alien-info-type info))))) - -;;;; the ADDR macro - -(sb-xc:defmacro addr (expr &environment env) - "Return an Alien pointer to the data addressed by Expr, which must be a call - to SLOT or DEREF, or a reference to an Alien variable." - (let ((form (%macroexpand expr env))) - (or (typecase form - (cons - (case (car form) - (slot - (cons '%slot-addr (cdr form))) - (deref - (cons '%deref-addr (cdr form))) - (%heap-alien - (cons '%heap-alien-addr (cdr form))) - (local-alien - (let ((info (let ((info-arg (second form))) - (and (consp info-arg) - (eq (car info-arg) 'quote) - (second info-arg))))) - (unless (local-alien-info-p info) - (error "Something is wrong, LOCAL-ALIEN-INFO not found: ~S" - form)) - (setf (local-alien-info-force-to-memory-p info) t)) - (cons '%local-alien-addr (cdr form))))) - (symbol - (let ((kind (info :variable :kind form))) - (when (eq kind :alien) - `(%heap-alien-addr ',(info :variable :alien-info form)))))) - (error "~S is not a valid L-value." form)))) -(push '("SB-ALIEN" define-alien-type-class define-alien-type-method) - *!removable-symbols*) +(defun cas-alien (symbol old new) + (let ((info (info :variable :alien-info symbol))) + (when info + (let ((type (heap-alien-info-type info))) + (when (and (typep type 'alien-integer-type) + (eq (alien-integer-type-class type) 'integer) + (member (alien-integer-type-bits type) + '(8 16 32 #+64-bit 64))) + (let ((signed (alien-integer-type-signed type)) + (bits (alien-integer-type-bits type)) + (sap-form `(foreign-symbol-sap ,(heap-alien-info-alien-name info) t))) + (cond ((and signed (< bits sb-vm:n-word-bits)) + (let ((mask (1- (ash 1 bits)))) + `(sb-vm::sign-extend + (funcall #'(cas ,(alien-integer->sap-ref-fun nil bits)) + (logand (the (signed-byte ,bits) ,old) ,mask) + (logand (the (signed-byte ,bits) ,new) ,mask) + ,sap-form 0) + ,bits))) + (t + `(funcall #'(cas ,(alien-integer->sap-ref-fun signed bits)) + ,old ,new ,sap-form 0))))))))) (in-package "SB-IMPL") @@ -1162,21 +1319,22 @@ (error () (error "invalid external alien name: ~S" name)))) -(declaim (ftype (sfunction (string hash-table) (or integer null)) - find-foreign-symbol-in-table)) -(defun find-foreign-symbol-in-table (name table) - (let ((extern (extern-alien-name name))) - (values - (or (gethash extern table) - (gethash (concatenate 'base-string "ldso_stub__" extern) table))))) - -;;; *STATIC-FOREIGN-SYMBOLS* are static as opposed to "dynamic" (not -;;; as opposed to C's "extern"). The table contains symbols known at -;;; the time that the program was built, but not symbols defined in -;;; object files which have been loaded dynamically since then. -#-linkage-table -(progn - (declaim (type hash-table *static-foreign-symbols*)) - (defvar *static-foreign-symbols* (make-hash-table :test 'equal))) - -(/show0 "host-alieneval.lisp end of file") +(in-package "SB-ALIEN") + +#+sb-xc +(defmacro maybe-with-pinned-objects (variables types &body body) + (declare (ignorable variables types)) + (let ((pin-variables + ;; Only pin things on GENCGC, since on CHENEYGC it'd imply + ;; disabling the GC. Which is something we don't want to do + ;; every time we're calling to C. + #+gencgc + (loop for variable in variables + for type in types + when (invoke-alien-type-method :deport-pin-p type) + collect variable))) + (if pin-variables + `(with-pinned-objects ,pin-variables + ,@body) + `(progn + ,@body)))) diff --git a/src/code/alloc.lisp b/src/code/alloc.lisp index d5893e1266..16b021304e 100644 --- a/src/code/alloc.lisp +++ b/src/code/alloc.lisp @@ -12,396 +12,118 @@ (in-package "SB-VM") -(!define-load-time-global *allocator-mutex* (sb-thread:make-mutex :name "Allocator")) +(define-alien-routine ("os_allocate" allocate-system-memory) + system-area-pointer + (bytes unsigned)) + +(define-alien-routine ("os_deallocate" deallocate-system-memory) + void + (addr system-area-pointer) + (bytes unsigned)) + +(define-load-time-global *allocator-mutex* (sb-thread:make-mutex :name "Allocator")) (defun allocate-static-vector (widetag length words) (declare (type (unsigned-byte #.n-widetag-bits) widetag) (type word words) (type index length)) - ;; This does not need WITHOUT-GCING, but it will be implicitly wrapped - ;; in WITHOUT-INTERRUPTS due to the default behavior of system mutexes, - ;; which is important so that we don't leave an inconsistent state. - ;; To think about why it is OK to leave GC enabled, consider that - ;; neither GC nor another thread will examine static space above the - ;; current value of *STATIC-SPACE-FREE-POINTER*. - (or (sb-thread::with-system-mutex (*allocator-mutex*) - (let* ((pointer *static-space-free-pointer*) - (nbytes (pad-data-block (+ words vector-data-offset))) - (new-pointer (sap+ pointer nbytes))) - (when (sap<= new-pointer (int-sap static-space-end)) + ;; Static space starts out zeroed, so it looks a bunch of cons cells + ;; containing (0 . 0) above the free pointer. Therefore bumping the pointer + ;; merely exposes a new range of cons cells, if GC should happen to run + ;; while executing this code. And because we assign the LENGTH of the vector + ;; prior to setting the widetag, and LENGTH is a fixnum, then at worst + ;; someone can transiently observe a cons of (0 . a-fixnum). + (let* ((nbytes (pad-data-block (+ words vector-data-offset))) + (pointer (alien-funcall (extern-alien "atomic_bump_static_space_free_ptr" + (function system-area-pointer int)) + nbytes))) + (if (/= (sap-int pointer) 0) ;; By storing the length prior to the widetag, the word at the old ;; free pointer decodes as a cons instead of a 0-length vector. ;; Not that it should matter, but it seems slightly better to change ;; the new object atomically to a correctly-sized vector rather than ;; a cons changing into the wrong vector into the right vector. - (setf (sap-ref-word pointer (ash vector-length-slot word-shift)) - (fixnumize length)) + (let ((v (%make-lisp-obj (sap-int (sap+ pointer other-pointer-lowtag))))) + (setf (%array-fill-pointer v) length ;; then store the widetag - (setf (sap-ref-word pointer 0) widetag) - ;; then the new free pointer - (setf *static-space-free-pointer* new-pointer) + (sap-ref-8 pointer (+ #+big-endian (1- n-word-bytes))) + widetag) + v) + (error 'simple-storage-condition + :format-control + "Not enough room left in static space to allocate vector.")))) + +#+darwin-jit +(defun allocate-static-code-vector (widetag length words) + (declare (type (unsigned-byte #.n-widetag-bits) widetag) + (type word words) + (type index length)) + (or (with-system-mutex (*allocator-mutex*) + (let* ((pointer *static-code-space-free-pointer*) + (nbytes (pad-data-block (+ words vector-data-offset))) + (new-pointer (sap+ pointer nbytes))) + (when (sap<= new-pointer (int-sap static-code-space-end)) + (setf (sap-ref-word-jit pointer (ash vector-length-slot word-shift)) + (fixnumize length)) + (setf (sap-ref-word-jit pointer 0) widetag) + (setf *static-code-space-free-pointer* new-pointer) (%make-lisp-obj (logior (sap-int pointer) other-pointer-lowtag))))) (error 'simple-storage-condition :format-control - "Not enough room left in static space to allocate vector."))) + "Not enough room left in static code space to allocate vector."))) #+immobile-space (progn -(define-alien-variable varyobj-space-size (unsigned 32)) +(define-alien-variable text-space-size (unsigned 32)) (define-alien-variable ("FIXEDOBJ_SPACE_START" fixedobj-space-start) unsigned-long) -(define-alien-variable ("VARYOBJ_SPACE_START" varyobj-space-start) unsigned-long) -(define-alien-variable ("varyobj_free_pointer" *varyobj-space-free-pointer*) +(define-alien-variable ("text_space_highwatermark" *text-space-free-pointer*) system-area-pointer) (define-alien-variable ("fixedobj_free_pointer" *fixedobj-space-free-pointer*) system-area-pointer) -(eval-when (:compile-toplevel) +(eval-when (:compile-toplevel) ; FIXME: these assertions look irrelevant now (assert (eql code-boxed-size-slot 1)) (assert (eql code-debug-info-slot 2))) -(define-alien-variable "varyobj_holes" long) -(define-alien-variable "varyobj_page_touched_bits" (* (unsigned 32))) -(define-alien-variable "varyobj_pages" (* (unsigned 32))) -(define-alien-routine "find_preceding_object" long (where long)) - -;;; Lazily created freelist, used only when unallocate is called: -;;; A cons whose car is a sorted list of hole sizes available -;;; and whose cdr is a hashtable. -;;; The keys in the hashtable are hole sizes, values are lists of holes. -;;; A better structure would be just a sorted array of sizes -;;; with each entry pointing to the holes which are threaded through -;;; some bytes in the storage itself rather than through cons cells. -(!define-load-time-global *immobile-freelist* nil) - -;;; Return the zero-based index within the varyobj subspace of immobile space. -(defun varyobj-page-index (address) - (declare (type (and fixnum unsigned-byte) address)) - (values (floor (- address varyobj-space-start) immobile-card-bytes))) - -(defun varyobj-page-address (index) - (+ varyobj-space-start (* index immobile-card-bytes))) - -(declaim (inline (setf varyobj-page-scan-start-offset))) -(defun (setf varyobj-page-scan-start-offset) (newval index) - ;; NEWVAL is passed in as a byte count but we want to store it as doublewords - ;; so it needs right-shifting by 1+ word-shift. However because it is a field - ;; of a packed word, it needs left-shifting by 8. We can shift by the net amount - ;; provided that no zero bits would be right-shifted out. - (aver (zerop (logand newval lowtag-mask))) - (setf (deref varyobj-pages index) - (logior (ash newval (- 8 (1+ sb-vm:word-shift))) - (logand (deref varyobj-pages index) #xFF))) - newval) - -;;; Convert a zero-based varyobj page index into a scan start address. -(defun varyobj-page-scan-start (index) - (- (+ varyobj-space-start (* (1+ index) immobile-card-bytes)) - (* 2 n-word-bytes (ash (deref varyobj-pages index) -8)))) - -(declaim (inline hole-p)) -(defun hole-p (raw-address) - ;; A code header with 0 boxed words is a hole. - ;; See also CODE-OBJ-IS-FILLER-P - (eql (sap-ref-64 (int-sap raw-address) 0) code-header-widetag)) - -(defun freed-hole-p (address) - (and (hole-p address) - ;; A hole is not considered to have been freed until it is - ;; no longer in the chain of objects linked through - ;; the debug_info slot. - (eql (sap-ref-word (int-sap address) - (ash code-debug-info-slot word-shift)) - nil-value))) - -(declaim (inline hole-size)) -(defun hole-size (hole-address) ; in bytes - (ash (sap-ref-32 (int-sap hole-address) 4) word-shift)) +;;; Size-class segregation (implying which page we try to allocate to) +;;; is done from lisp now, not C. There are 3 objects types we'll see, +;;; each in its own size class (even if some are coincidentally the same size). +;;; - Symbols +;;; - FDEFNs +;;; - Layouts +;;; The first two are truly fixed in size. Layouts occur in varying sizes. +(defun alloc-immobile-fixedobj (nwords header) + (let* ((widetag (logand (truly-the fixnum header) widetag-mask)) + (aligned-nwords (truly-the fixnum (align-up nwords 2))) + (size-class + ;; If you change this, then be sure to update tests/immobile-space.impure + ;; which hardcodes a size class to not conflict with anything. + (ecase widetag + (#.symbol-widetag 1) + (#.fdefn-widetag 2) + (#.instance-widetag + (cond ((<= aligned-nwords 8) (setq aligned-nwords 8) 3) + ((<= aligned-nwords 16) (setq aligned-nwords 16) 4) + ((<= aligned-nwords 24) (setq aligned-nwords 24) 5) + ((<= aligned-nwords 32) (setq aligned-nwords 32) 6) + ((<= aligned-nwords 48) (setq aligned-nwords 48) 7) + (t (error "Oversized layout"))))))) + (values (%primitive !alloc-immobile-fixedobj + size-class + aligned-nwords + header)))) -(declaim (inline (setf hole-size))) -(defun (setf hole-size) (new-size hole) ; NEW-SIZE is in bytes - (setf (sap-ref-32 (int-sap hole) 4) (ash new-size (- word-shift))) - new-size) - -(declaim (inline hole-end-address)) -(defun hole-end-address (hole-address) - (+ hole-address (hole-size hole-address))) - -(defun sorted-list-insert (item list key-fn) - (declare (function key-fn)) - (let ((key (funcall key-fn item)) (tail list) prev) - (loop - (when (null tail) - (let ((new-tail (list item))) - (return (cond ((not prev) new-tail) - (t (setf (cdr prev) new-tail) list))))) - (let ((head (car tail))) - (when (< key (funcall key-fn head)) - (rplaca tail item) - (rplacd tail (cons head (cdr tail))) - (return list))) - (setq prev tail tail (cdr tail))))) - -;;; These routines are not terribly efficient, but very straightforward -;;; since we can assume the existence of hashtables. -(defun add-to-freelist (hole) - (let* ((size (hole-size hole)) - (freelist *immobile-freelist*) - (table (cdr freelist)) - (old (gethash (hole-size hole) table))) - ;; Check for double-free error - #+immobile-space-debug (aver (not (member hole (gethash size table)))) - (unless old - (setf (car freelist) - (sorted-list-insert size (car freelist) #'identity))) - (setf (gethash size table) (cons hole old)))) - -(defun remove-from-freelist (hole) - (let* ((key (hole-size hole)) - (freelist *immobile-freelist*) - (table (cdr freelist)) - (list (gethash key table)) - (old-length (length list)) - (new (delete hole list :count 1))) - (declare (ignorable old-length)) - #+immobile-space-debug (aver (= (length new) (1- old-length))) - (cond (new - (setf (gethash key table) new)) - (t - (setf (car freelist) (delete key (car freelist) :count 1)) - (remhash key table))))) - -(defun find-in-freelist (size test) - (let* ((freelist *immobile-freelist*) - (hole-size - (if (eq test '<=) - (let ((sizes (member size (car freelist) :test '<=))) - (unless sizes - (return-from find-in-freelist nil)) - (car sizes)) - size)) - (found (car (gethash hole-size (cdr freelist))))) - (when found - (remove-from-freelist found)) - found)) - -(defun set-varyobj-space-free-pointer (free-ptr) - (declare (type (and fixnum unsigned-byte) free-ptr)) - (setq *varyobj-space-free-pointer* (int-sap free-ptr)) - ;; When the free pointer is not page-aligned - it usually won't be - - ;; then we create an unboxed array from the pointer to the page end - ;; so that it appears as one contiguous object when scavenging. - ;; instead of a bunch of cons cells. - (when (logtest free-ptr (1- immobile-card-bytes)) - (let ((n-trailing-bytes - (- (nth-value 1 (ceiling free-ptr immobile-card-bytes))))) - (setf (sap-ref-word (int-sap free-ptr) 0) simple-array-fixnum-widetag - (sap-ref-word (int-sap free-ptr) n-word-bytes) - ;; Convert bytes to words, subtract the header and vector length. - (ash (- (ash n-trailing-bytes (- word-shift)) 2) - n-fixnum-tag-bits))))) - -(defun unallocate (hole) - #+immobile-space-debug - (awhen *in-use-bits* (mark-range it hole (hole-size hole) nil)) - (let* ((hole-end (hole-end-address hole)) - (end-is-free-ptr (eql hole-end (sap-int *varyobj-space-free-pointer*)))) - ;; First, ensure that no page's scan-start points to this hole. - ;; For smaller-than-page objects, this will do nothing if the hole - ;; was not the scan-start. For larger-than-page, we have to update - ;; a range of pages. Example: - ;; | page1 | page2 | page3 | page4 | - ;; |-- hole A ------ | -- hole B -- - ;; If page1 had an object preceding the hole, then it is not empty, - ;; but if it pointed to the hole, and the hole extended to the end - ;; of the first page, then that page is empty. - ;; Pages (1+ first-page) through (1- last-page) inclusive - ;; must become empty. last-page may or may not be depending - ;; on whether another object can be found on it. - (let ((first-page (varyobj-page-index hole)) - (last-page (varyobj-page-index (1- hole-end)))) - (when (and (eql (varyobj-page-scan-start first-page) hole) - (< first-page last-page)) - (setf (varyobj-page-scan-start-offset first-page) 0)) - (loop for page from (1+ first-page) below last-page - do (setf (varyobj-page-scan-start-offset page) 0)) - ;; Only touch the offset for the last page if it pointed to this hole. - ;; If the following object is a hole that is in the pending free list, - ;; it's ok, but if it's a hole that is already in the freelist, - ;; it's not OK, so look beyond that object. We don't have to iterate, - ;; since there can't be two consecutive holes - so it's either the - ;; object after this hole, or the one after that. - (when (eql (varyobj-page-scan-start last-page) hole) - (let* ((page-end (varyobj-page-address (1+ last-page))) - (new-scan-start (cond (end-is-free-ptr page-end) - ((freed-hole-p hole-end) - (hole-end-address hole-end)) - (t hole-end)))) - (setf (varyobj-page-scan-start-offset last-page) - (if (< new-scan-start page-end) - ;; Compute new offset backwards relative to the page end. - (- page-end new-scan-start) - 0))))) ; Page becomes empty - - (unless *immobile-freelist* - (setf *immobile-freelist* (cons nil (make-hash-table :test #'eq)))) - - ;; find-preceding is the most expensive operation in this sequence - ;; of steps. Not sure how to improve it, but I doubt it's a problem. - (let* ((predecessor (find-preceding-object hole)) - (pred-is-free (and (not (eql predecessor 0)) - (freed-hole-p predecessor)))) - (when pred-is-free - (remove-from-freelist predecessor) - (setf hole predecessor)) - (when end-is-free-ptr - ;; Give back space below the free pointer for better space conservation. - ;; Consider when the hole touching the free pointer is equal in size - ;; to another hole that could have been used instead. Taking space at - ;; the free pointer diminishes the opportunity to use the frontier - ;; to later allocate a larger object that would not have fit - ;; into any existing hole. - (set-varyobj-space-free-pointer hole) - (return-from unallocate)) - (let* ((successor hole-end) - (succ-is-free (freed-hole-p successor))) - (when succ-is-free - (setf hole-end (hole-end-address successor)) - (remove-from-freelist successor))) - ;; The hole must be an integral number of doublewords. - (aver (not (logtest (- hole-end hole) lowtag-mask))) - (setf (hole-size hole) (- hole-end hole)))) - (add-to-freelist hole)) - -(defun allocate-immobile-obj (n-bytes word0 word1 lowtag errorp) - (declare (type (and fixnum unsigned-byte) n-bytes)) - (setq n-bytes (align-up n-bytes (* 2 n-word-bytes))) - ;; Can't allocate fewer than 4 words due to min hole size. - (aver (>= n-bytes (* 4 n-word-bytes))) - (sb-thread::with-system-mutex (*allocator-mutex* :without-gcing t) - (unless (zerop varyobj-holes) - ;; If deferred sweep needs to happen, do so now. - ;; Concurrency could potentially be improved here: at most one thread - ;; should do this step, but it doesn't need to be exclusive with GC - ;; as long as we can atomically pop items off the list of holes. - (let ((hole-addr varyobj-holes)) - (setf varyobj-holes 0) - (loop - (let ((next (sap-ref-word (int-sap hole-addr) - (ash code-debug-info-slot word-shift)))) - (setf (sap-ref-word (int-sap hole-addr) - (ash code-debug-info-slot word-shift)) - nil-value) - (unallocate hole-addr) - (if (eql (setq hole-addr next) 0) (return)))))) - (let* ((residual) - (shrunk-size) - (addr - (or (and *immobile-freelist* - (or (find-in-freelist n-bytes '=) ; 1. Exact match? - ;; 2. Try splitting a hole, adding some slack so that - ;; both pieces can potentially be used. - (let ((found (find-in-freelist (+ n-bytes 192) '<=))) - (when found - (let* ((actual-size (hole-size found)) - (remaining (- actual-size n-bytes))) - (aver (not (logtest actual-size lowtag-mask))) - (setq residual found ; Shorten the lower piece - shrunk-size remaining) - (+ found remaining)))))) ; Consume the upper piece - ;; 3. Extend the frontier. - (let* ((addr (sap-int *varyobj-space-free-pointer*)) - (free-ptr (+ addr n-bytes)) - (limit (+ varyobj-space-start varyobj-space-size))) - (when (> free-ptr limit) - (cond (errorp - (format t "~&Immobile space exhausted~%") - (sb-debug:print-backtrace) - (sb-impl::%halt)) - (t - (return-from allocate-immobile-obj nil)))) - (set-varyobj-space-free-pointer free-ptr) - addr)))) - (aver (not (logtest addr lowtag-mask))) ; Assert proper alignment - ;; Compute the start and end of the first page consumed. - (let* ((page-start (logandc2 addr (1- immobile-card-bytes))) - (page-end (+ page-start immobile-card-bytes)) - (index (varyobj-page-index addr)) - (obj-end (+ addr n-bytes))) - ;; Mark the page as being used by a nursery object. - (setf (deref varyobj-pages index) (logior (deref varyobj-pages index) 1)) - ;; On the object's first page, set the scan start only if addr - ;; is lower than the current page-scan-start object. - ;; Note that offsets are expressed in doublewords backwards from - ;; page end, so that we can direct the scan start to any doubleword - ;; on the page or in the preceding 256MiB (approximately). - (when (< addr (varyobj-page-scan-start index)) - (setf (varyobj-page-scan-start-offset index) (- page-end addr))) - ;; On subsequent pages, always set the scan start, since there can not - ;; be a lower-addressed object touching those pages. - (loop - (setq page-start page-end) - (incf page-end immobile-card-bytes) - (incf index) - (when (>= page-start obj-end) (return)) - (setf (varyobj-page-scan-start-offset index) (- page-end addr)))) - #+immobile-space-debug ; "address sanitizer" - (awhen *in-use-bits* (mark-range it addr n-bytes t)) - (setf (sap-ref-word (int-sap addr) 0) word0 - (sap-ref-word (int-sap addr) n-word-bytes) word1) - ;; 0-fill the remainder of the object - (#+64-bit system-area-ub64-fill - #-64-bit system-area-ub32-fill - 0 (int-sap addr) 2 (- (ash n-bytes (- word-shift)) 2)) - ;; Only after making the new object can we reduce the size of the hole - ;; that contained the new allocation (if it entailed chopping a hole - ;; into parts). In this way, heap scans do not read junk. - (when residual - (setf (hole-size residual) shrunk-size) - (add-to-freelist residual)) - ;; The object is live despite not having a tagged pointer yet nor - ;; this code being pseudoatomic, because the mutex acquire has - ;; :WITHOUT-GCING. Ideally we'd have some notion of hazard pointers - ;; that could prevent GC from evicting objects from pointed-to pages - ;; so that we needn't inhibit GC. - (%make-lisp-obj (logior addr lowtag))))) - -;;; I don't know whether immobile space vectors actually work. -;;; I think the idea was to use them as fd-stream buffers when applicable -;;; instead of having a finalizer on OS-allocated memory. -(defun allocate-immobile-vector (widetag length words) - (allocate-immobile-obj (pad-data-block (+ words vector-data-offset)) - widetag - (fixnumize length) - other-pointer-lowtag - t)) - -(defun allocate-immobile-simple-vector (n-elements) - (allocate-immobile-vector simple-vector-widetag n-elements n-elements)) -(defun allocate-immobile-bit-vector (n-elements) - (allocate-immobile-vector simple-bit-vector-widetag n-elements - (ceiling n-elements n-word-bits))) -(defun allocate-immobile-byte-vector (n-elements) - (allocate-immobile-vector simple-array-unsigned-byte-8-widetag n-elements - (ceiling n-elements n-word-bytes))) -(defun allocate-immobile-word-vector (n-elements) - (allocate-immobile-vector #+64-bit simple-array-unsigned-byte-64-widetag - #-64-bit simple-array-unsigned-byte-32-widetag - n-elements n-elements)) - -(defun alloc-immobile-symbol () - (values (%primitive alloc-immobile-fixedobj other-pointer-lowtag symbol-size - (logior (ash (1- symbol-size) n-widetag-bits) symbol-widetag)))) (defun make-immobile-symbol (name) - (let ((symbol (truly-the symbol (alloc-immobile-symbol)))) - ;; no pin, it's immobile (and obviously live) - (setf (sap-ref-lispobj (int-sap (get-lisp-obj-address symbol)) - (- (ash symbol-name-slot word-shift) other-pointer-lowtag)) - name) + (let ((symbol (truly-the symbol + (or (%primitive !fast-alloc-immobile-symbol) + (alloc-immobile-fixedobj + symbol-size + (logior (ash (1- symbol-size) n-widetag-bits) symbol-widetag)))))) + ;; symbol-hash and package ID start out as 0 + (%primitive set-slot symbol name 'make-symbol symbol-name-slot other-pointer-lowtag) + (%primitive set-slot symbol nil 'make-symbol symbol-info-slot other-pointer-lowtag) (%set-symbol-global-value symbol (make-unbound-marker)) - ;; symbol-hash is 0 - (setf (symbol-info symbol) nil) - (%set-symbol-package symbol nil) symbol)) ) ; end PROGN @@ -412,92 +134,146 @@ #+immobile-space (or (let ((start fixedobj-space-start)) (<= start addr (truly-the word (+ start (1- fixedobj-space-size))))) - (let ((start varyobj-space-start)) - (<= start addr (truly-the word (+ start (1- varyobj-space-size))))))) + (let ((start text-space-start)) + (<= start addr (truly-the word (+ start (1- text-space-size))))))) (defun immobile-space-obj-p (obj) (immobile-space-addr-p (get-lisp-obj-address obj))) +(define-load-time-global *immobile-codeblob-tree* nil) +(define-load-time-global *dynspace-codeblob-tree* nil) +(define-alien-variable codeblob-freelist unsigned) + +;;; For the immobile code allocator: +;;; * Insertion performs low-level allocate, then tree-insert +;;; * Deletion performs tree-delete, then low-level deallocate +;;; Invariants: +;;; - a linear space walk visits at least all the objects in the tree, possibly more +;;; - tree does not contain any key that is not the base address of an object +;;; - if a tree node points to an object, then that object is either code +;;; or a filler that has not been returned to the low-level allocator + ;;; Enforce limit on boxed words based on maximum total number of words ;;; that can be indicated in the header for 32-bit words. ;;; 22 bits = 4MiB, quite generous for one code object. +;;; (I think the reasoning behind 22 is that after adding 8 for the widetag, +;;; it's 30, and the other 2 bits are the fixnum tag) ;;; 25 bits is the maximum unboxed size expressed in bytes, ;;; if n-word-bytes = 8 and almost the entire code object is unboxed ;;; which is, practically speaking, not really possible. -(declaim (ftype (sfunction (t (unsigned-byte 16) (unsigned-byte 22) (unsigned-byte 25)) - code-component) +(declaim (ftype (sfunction (t (unsigned-byte 22) (unsigned-byte 25)) + (values code-component (integer 0))) allocate-code-object)) + +(defun update-dynamic-space-code-tree (obj) + (with-pinned-objects (obj) + (let ((addr (logandc2 (get-lisp-obj-address obj) other-pointer-lowtag)) + (tree *dynspace-codeblob-tree*)) + (loop (let ((newtree (sb-brothertree:insert addr tree))) + ;; check that it hasn't been promoted from gen0 -> gen1 already + ;; (very unlikely, but certainly possible). + (unless (eq (generation-of obj) 0) (return)) + (let ((oldval (cas *dynspace-codeblob-tree* tree newtree))) + (if (eq oldval tree) (return) (setq tree oldval)))))))) + ;;; Allocate a code component with BOXED words in the header ;;; followed by UNBOXED bytes of raw data. ;;; BOXED must be the exact count of boxed words desired. No adjustments ;;; are made for alignment considerations or the fixed slots. -(defun allocate-code-object (space n-named-calls boxed unboxed) - (declare (ignorable space n-named-calls)) +(defun allocate-code-object (space boxed unboxed) + (declare (ignorable space)) (let* ((total-words (the (unsigned-byte 22) ; Enforce limit on total words as well - (align-up (+ boxed (ceiling unboxed n-word-bytes)) 2))) - (code - #+gencgc - (or #+immobile-code - (when (member space '(:immobile :auto)) - ;; We don't need to inhibit GC here - ALLOCATE-IMMOBILE-OBJ does it. - ;; Indicate that there are initially 2 boxed words, otherwise - ;; immobile space GC thinks this object is freeable. - (allocate-immobile-obj (ash total-words word-shift) - (logior (ash total-words code-header-size-shift) - code-header-widetag) - (ash 2 n-fixnum-tag-bits) - other-pointer-lowtag - (eq space :immobile))) - ;;; x86-64 has a vop which is nothing more than wrapping - ;; pseudo-atomic around a call to alloc_code_object() in the C runtime. - ;; The vop is defined in such a way that it can't be inserted into - ;; this fuction, but instead needs an out-of-line call to a helper function - ;; (because it clobbers all registers and doesn't indicate that) - #+(and x86-64 (not win32)) - (alloc-dynamic-space-code total-words) - #-(and x86-64 (not win32)) - (without-gcing - (%make-lisp-obj - (alien-funcall (extern-alien "alloc_code_object" - (function unsigned (unsigned 32))) - total-words)))) - #+cheneygc - (%primitive var-alloc total-words 'alloc-code - ;; subtract 1 because var-alloc always adds 1 word - ;; for the header, which is not right for code objects. - -1 code-header-widetag other-pointer-lowtag nil))) - - (with-pinned-objects (code) - (let ((sap (sap+ (int-sap (get-lisp-obj-address code)) - (- other-pointer-lowtag)))) - ;; The immobile space allocator pre-zeroes, and also it needs a nonzero - ;; value in the boxed word count because otherwise it looks like - ;; an immobile space page filler. So don't do any more zeroing there. - ;; (Could dead immobile objects be converted to use FILLER-WIDETAG instead?) - (unless (immobile-space-obj-p code) - ;; Before writing the boxed word count, zeroize up to and including 1 word - ;; after the boxed header so that all point words can be safely read - ;; by GC and so the jump table count word is 0. - (loop for byte-index from (ash boxed word-shift) downto (ash 2 word-shift) - by n-word-bytes - do (setf (sap-ref-word sap byte-index) 0))) - ;; The 1st slot beyond the header stores the boxed header size in bytes - ;; as an untagged number, which has the same representation as a tagged - ;; value denoting a word count if WORD-SHIFT = N-FIXNUM-TAG-BITS. - ;; This boxed-size MUST be 0 prior to writing any pointers into the object - ;; because the boxed words will not necessarily have been pre-zeroed; - ;; scavenging them prior to zeroing them out would see wild pointers. - (setf (sap-ref-word sap (ash code-boxed-size-slot word-shift)) - ;; For 32-bit words, we'll have to add another primitive-object slot. - ;; But so far nothing makes use of the n-named-calls value. - (logior #+64-bit (ash n-named-calls 32) - (ash boxed word-shift))))) - - ;; FIXME: Sort out 64-bit and cheneygc. - #+(and 64-bit cheneygc) - (setf (code-header-ref code 0) - (%make-lisp-obj - (logior (ash total-words 32) - sb-vm:code-header-widetag))) - code)) + (align-up (+ boxed (ceiling unboxed n-word-bytes)) 2)))) + #+immobile-code + (when (member space '(:immobile :auto)) + (let (addr code holder) + ;; CODE needs to have a heap or TLS reference to it prior to adding it to the tree + ;; since implicit pinning uses the tree to find pinned ojects. + (declare (special holder)) + (with-alien ((tlsf-alloc-codeblob (function unsigned system-area-pointer unsigned) + :extern) + (tlsf-control system-area-pointer :extern)) + (with-system-mutex (*allocator-mutex* :without-gcing t) + (unless (zerop (setq addr (alien-funcall tlsf-alloc-codeblob + tlsf-control total-words))) + (setf code (%make-lisp-obj (logior addr other-pointer-lowtag)) + holder code)))) + ;; GC is allowed to run now because HOLDER references CODE + (when code + (alien-funcall (extern-alien "memset" (function void system-area-pointer int unsigned)) + (sap+ (int-sap addr) n-word-bytes) 0 (ash (1- boxed) word-shift)) + ;; BOXED-SIZE is a raw slot holding a byte count, but SET-SLOT takes its VALUE + ;; arg as a descriptor-reg, so just cleverly make it right by shifting. + (%primitive set-slot code (ash boxed (- word-shift n-fixnum-tag-bits)) + '(setf %code-boxed-size) code-boxed-size-slot other-pointer-lowtag) + (aver (= (sap-ref-8 (int-sap addr) 0) code-header-widetag)) ; wasn't trashed + (let ((tree *immobile-codeblob-tree*)) + (loop (when (eq tree (setq tree (cas *immobile-codeblob-tree* tree + (sb-brothertree:insert addr tree)))) + (return-from allocate-code-object (values code total-words))))))) + (when (eq space :immobile) + (error "Immobile code space exhausted"))) + (let ((code + ;; x86-64 has a vop which wraps pseudo-atomic around the foreign call, + ;; as is the custom for allocation trampolines. + #+x86-64 (%primitive alloc-code total-words boxed) + #-x86-64 + (without-gcing + (%make-lisp-obj + (alien-funcall (extern-alien "alloc_code_object" + (function unsigned (unsigned 32) (unsigned 32))) + total-words boxed))))) + (update-dynamic-space-code-tree code) + ;; FIXME: there may be random values in the unboxed payload and it's not obvious + ;; that all callers of ALLOCATE-CODE-OBJECT always write all raw bytes. + ;; LOAD-CODE and MAKE-CORE-COMPONENT certainly do because the representation + ;; of simple-funs requires that the final 2 bytes be aligned to the physical end + ;; of the object so that we can find the function table. + ;; But what about other things that create code objects? + ;; It could be a subtle source of nondeterministic core images. + (values code total-words)))) + +;; The freelist can only be read while holding a mutex because the codeblobs +;; themselves are used to construct the freelist. It would be dangerous to +;; suppose that you could read the "link" field out of a blob (that currently +;; has FILLER_WIDETAG allegedly) if another thread got scheduled such that it +;; freed that filler and the reallocated into it instantly. +(defun immobile-code-dealloc-1 (scratchpad) + (declare (cons scratchpad) (ignorable scratchpad)) + #+immobile-code + (flet ((pop-1 () + ;; Remove an item from codeblob-freelist. Mutex must be held + ;; and GC inhibited. + (let ((head codeblob-freelist)) + (unless (eql head 0) + (setf codeblob-freelist (sap-ref-word (int-sap head) n-word-bytes))) + (%make-lisp-obj head)))) ; use funny fixnum representation + (when (eql (car scratchpad) 0) + ;; I'd prefer that this be done using WITH-SYSTEM-MUTEX + pseudo-atomic + ;; rather than WITHOUT-GCING in as much as WITHOUT-GCING needs to cease to exist. + (let ((word (if (eql codeblob-freelist 0) + 0 + (with-system-mutex (*allocator-mutex* :without-gcing t) (pop-1))))) + (when (eql word 0) + (return-from immobile-code-dealloc-1 nil)) + (setf (car scratchpad) word))) + (let ((addr (get-lisp-obj-address (car scratchpad)))) + ;; We have to remove from the tree before removing from the TLSF pool, + ;; because presence of a key in the tree is an assertion that there is + ;; memory block at that address. Consider if we removed from the pool + ;; without removing from the tree, the block could be coalesced on either side + ;; and there would not necessarily be a block where the tree says it is. + (let ((tree sb-vm::*immobile-codeblob-tree*)) + (loop (when (eq tree (setq tree (cas *immobile-codeblob-tree* tree + (sb-brothertree:delete addr tree)))) + (return)))) + (with-alien ((tlsf-unalloc-codeblob (function void system-area-pointer unsigned) + :extern) + (tlsf-control system-area-pointer :extern)) + ;; Prevent GC from walking the text space at the exact same instant + ;; the block coalescing algorithm alters block headers. + (with-system-mutex (*allocator-mutex* :without-gcing t) + (alien-funcall tlsf-unalloc-codeblob tlsf-control addr) + (setf (car scratchpad) (pop-1))))) + t)) diff --git a/src/code/alpha-vm.lisp b/src/code/alpha-vm.lisp deleted file mode 100644 index a98ac73ed0..0000000000 --- a/src/code/alpha-vm.lisp +++ /dev/null @@ -1,120 +0,0 @@ -;;;; Alpha-specific implementation stuff - -;;;; This software is part of the SBCL system. See the README file for -;;;; more information. -;;;; -;;;; This software is derived from the CMU CL system, which was -;;;; written at Carnegie Mellon University and released into the -;;;; public domain. The software is in the public domain and is -;;;; provided with absolutely no warranty. See the COPYING and CREDITS -;;;; files for more information. - -(in-package "SB-VM") - -#-sb-xc-host -(defun machine-type () - "Return a string describing the type of the local machine." - "Alpha") - -(defconstant-eqx +fixup-kinds+ - #(:jmp-hint :bits-63-48 :bits-47-32 :ldah :lda :absolute32) - #'equalp) -(!with-bigvec-or-sap -(defun fixup-code-object (code offset value kind flavor) - (declare (ignore flavor)) - (unless (zerop (rem offset sb-assem:+inst-alignment-bytes+)) - (error "Unaligned instruction? offset=#x~X." offset)) - (let ((sap (code-instructions code))) - (ecase kind - (:jmp-hint - (aver (zerop (ldb (byte 2 0) value))) - #+nil - (setf (sap-ref-16 sap offset) - (logior (sap-ref-16 sap offset) - (ldb (byte 14 0) (ash value -2))))) - (:bits-63-48 - (let* ((value (if (logbitp 15 value) (+ value (ash 1 16)) value)) - (value (if (logbitp 31 value) (+ value (ash 1 32)) value)) - (value (if (logbitp 47 value) (+ value (ash 1 48)) value))) - (setf (sap-ref-8 sap offset) (ldb (byte 8 48) value)) - (setf (sap-ref-8 sap (1+ offset)) (ldb (byte 8 56) value)))) - (:bits-47-32 - (let* ((value (if (logbitp 15 value) (+ value (ash 1 16)) value)) - (value (if (logbitp 31 value) (+ value (ash 1 32)) value))) - (setf (sap-ref-8 sap offset) (ldb (byte 8 32) value)) - (setf (sap-ref-8 sap (1+ offset)) (ldb (byte 8 40) value)))) - (:ldah - (let ((value (if (logbitp 15 value) (+ value (ash 1 16)) value))) - (setf (sap-ref-8 sap offset) (ldb (byte 8 16) value)) - (setf (sap-ref-8 sap (1+ offset)) (ldb (byte 8 24) value)))) - (:lda - (setf (sap-ref-8 sap offset) (ldb (byte 8 0) value)) - (setf (sap-ref-8 sap (1+ offset)) (ldb (byte 8 8) value))) - (:absolute32 - (setf (sap-ref-32 sap offset) value)))) - nil)) - -;;;; "sigcontext" access functions, cut & pasted from x86-vm.lisp then -;;;; hacked for types. -;;;; -;;;; KLUDGE: The alpha has 64-bit registers, so these potentially -;;;; return 64 bit numbers (which means bignums ... ew) We think that -;;;; 99 times of 100 (i.e. unless something is badly wrong) we'll get -;;;; answers that fit in 32 bits anyway. Which probably won't help us -;;;; stop passing bignums around as the compiler can't prove they fit -;;;; in 32 bits. But maybe the stuff it does on x86 to unbox 32-bit -;;;; constants happens magically for 64-bit constants here. Just -;;;; maybe. -- Dan Barlow, ca. 2001-05-05 -;;;; -;;;; See also x86-vm for commentary on signed vs unsigned. - -#-sb-xc-host (progn -;;; This is like CONTEXT-REGISTER, but returns the value of a float -;;; register. FORMAT is the type of float to return. - -;;; FIXME: Whether COERCE actually knows how to make a float out of a -;;; long is another question. This stuff still needs testing. -(define-alien-routine ("os_context_float_register_addr" - context-float-register-addr) - (* long) - (context (* os-context-t)) - (index int)) -(defun context-float-register (context index format) - (declare (type (alien (* os-context-t)) context)) - (coerce (deref (context-float-register-addr context index)) format)) -(defun %set-context-float-register (context index format new) - (declare (type (alien (* os-context-t)) context)) - (setf (deref (context-float-register-addr context index)) - (coerce new format))) - -;;; This sets the software fp_control word, which is not the same -;;; thing as the hardware fpcr. We have to do this so that OS FPU -;;; completion works properly - -;;; Note that this means we can't set rounding modes; we'd have to do -;;; that separately. That said, almost everybody seems to agree that -;;; changing the rounding mode is rarely a good idea, because it upsets -;;; libm functions. So adding that is not a priority. Sorry. -;;; -dan 2001.02.06 - -(define-alien-routine - ("arch_get_fp_control" floating-point-modes) (unsigned 64)) - -(define-alien-routine - ("arch_set_fp_control" %floating-point-modes-setter) void (fp (unsigned 64))) - -(defun (setf floating-point-modes) (val) (%floating-point-modes-setter val)) - -;;; Given a signal context, return the floating point modes word in -;;; the same format as returned by FLOATING-POINT-MODES. -(define-alien-routine ("os_context_fp_control" context-floating-point-modes) - (unsigned 64) (context (* os-context-t))) - - -(defun internal-error-args (context) - (declare (type (alien (* os-context-t)) context)) - (let* ((pc (context-pc context)) - (trap-number (sap-ref-8 pc 3))) - (declare (type system-area-pointer pc)) - (sb-kernel::decode-internal-error-args (sap+ pc 4) trap-number))) -) ; end PROGN diff --git a/src/code/ansi-stream.lisp b/src/code/ansi-stream.lisp index a7ec46be14..9915371e95 100644 --- a/src/code/ansi-stream.lisp +++ b/src/code/ansi-stream.lisp @@ -49,7 +49,7 @@ ;;; :line-length - Return the length of a line of output. ;;; :charpos - Return current output position on the line. ;;; :file-length - Return the file length of a file stream. -;;; :file-position - Return or change the current position of a +;;; :[gs]et-file-position - Return or change the current position of a ;;; file stream. ;;; :file-name - Return the name of an associated file. ;;; :interactive-p - Is this an interactive device? @@ -90,6 +90,31 @@ (deftype ansi-stream-cin-buffer () `(simple-array character (,+ansi-stream-in-buffer-length+))) +(eval-when (:compile-toplevel :load-toplevel :execute) +(defun %stream-opcode (name) + (ecase name + (:listen 0) + (:unread 1) + (:force-output 2) + (:finish-output 3) + (:charpos 4) + (:get-file-position 5) + (:set-file-position 6) + (:element-type 7) + (:element-mode 8) + (:external-format 9) + (:line-length 10) + (:file-length 11) + (:file-string-length 12) + (:clear-input 13) + (:clear-output 14) + (:close 15) + (:interactive-p 16) + ;; This is used by string streams and is not an opcode seen + ;; by STREAM-MISC-DISPATCH. The new stream pseudomethod convention + ;; can't pass random keywords to the misc method. + (:reset-unicode-p 17)))) + ;;; base class for ANSI standard streams (as opposed to the Gray ;;; streams extension) (defstruct (ansi-stream (:constructor nil) @@ -105,13 +130,16 @@ (in-index +ansi-stream-in-buffer-length+ :type (integer 0 #.+ansi-stream-in-buffer-length+)) + ;; FIXME: declare all these function types more rigorously. + ;; buffered input functions (in #'ill-in :type function) ; READ-CHAR function (bin #'ill-bin :type function) ; byte input function ;; 'n-bin' might not transfer bytes to the consumer. ;; A character FD-STREAM uses this method to transfer octets from the ;; source buffer into characters of the destination buffer. - (n-bin #'ill-bin :type function) ; n-byte input function + (n-bin #'ill-bin :type ; n-byte input function + (sfunction (stream (simple-unboxed-array (*)) index index t) index)) ;; output functions (out #'ill-out :type function) ; WRITE-CHAR function @@ -119,12 +147,12 @@ (sout #'ill-out :type function) ; string output function ;; other, less-used methods - (misc #'no-op-placeholder :type function) + (misc #'no-op-placeholder :type (function (stream (integer 0 17) t) *)) ;; Absolute character position, acting also as a generalized boolean ;; in lieu of testing FORM-TRACKING-STREAM-P to see if we must ;; maintain correctness of the slot in ANSI-STREAM-UNREAD-CHAR. - (input-char-pos nil)) + (input-char-pos nil :type (or null index))) ;;; SYNONYM-STREAM type is needed by ANSI-STREAM-{INPUT,OUTPUT}-STREAM-P ;;; and also needed by OPEN (though not obviously), which is compiled @@ -144,6 +172,22 @@ (symbol nil :type symbol :read-only t)) (declaim (freeze-type synonym-stream)) +(defstruct (broadcast-stream (:include ansi-stream + (out #'broadcast-out) + (bout #'broadcast-bout) + (sout #'broadcast-sout) + (misc #'broadcast-misc)) + (:constructor %make-broadcast-stream + (streams)) + (:copier nil) + (:predicate nil)) + ;; a list of all the streams we broadcast to + (streams () :type list :read-only t)) +(declaim (freeze-type broadcast-stream)) + +(define-load-time-global *null-broadcast-stream* (make-broadcast-stream)) +(declaim (type stream *null-broadcast-stream*)) + (defmethod print-object ((x stream) stream) (print-unreadable-object (x stream :type t :identity t))) @@ -196,11 +240,11 @@ ;; In light of the second point, we need not close the stream if the object is ;; stack-allocated, because any attempt to access it after the forms exit will surely ;; crash, and there are otherwise no observable effects from closing the stream. - ;; The choice to avoid DX-LET in safe code is strictly unecessary, because it is + ;; The choice to avoid DX-LET in some policies is strictly unecessary, because it is ;; *always* undefined behavior to use the DX object after its extent ends, ;; however it might help expose user code bugs by keeping the stream accessible ;; but closed. - (bind (if (sb-c:policy env (= safety 3)) 'let 'dx-let)) + (bind (if (sb-c:policy env (or (= safety 3) (= debug 3))) 'let 'dx-let)) (ctor `(%init-string-input-stream ,dummy ,string ;; not (OR START 0), because ":START NIL" should err @@ -212,8 +256,9 @@ ;; the variable var." - so we can read it here with impunity. `(unwind-protect (progn ,@forms) (close ,var)) `(progn ,@forms)))) ; don't bother closing - `(,bind ((,dummy (%make-instance ,(dd-length (find-defstruct-description - 'string-input-stream))))) + `(,bind ((,dummy (%make-structure-instance + ,(find-defstruct-description 'string-input-stream) + nil))) ,(multiple-value-bind (forms decls) (parse-body forms-decls nil) (if index `(multiple-value-bind (,var ,offset) ,ctor @@ -221,6 +266,139 @@ (multiple-value-prog1 ,(uwp forms) (setf ,index (- (string-input-stream-index ,var) ,offset)))) `(let ((,var ,ctor)) + (declare (ignorable ,var)) ,@decls ,(uwp forms)))))))) ; easy way +(defstruct (string-output-stream + (:include ansi-stream) + (:constructor nil) + (:copier nil) + (:predicate nil)) + ;; Function to perform a piece of the SOUT operation + ;; Args: (stream buffer string pointer start stop) + (sout-aux nil :type (sfunction (t t t t t t) t) :read-only t) + ;; The string we throw stuff in. + ;; In terms of representation of this buffer, we could do something like + ;; always use UTF-8, or use a custom encoding that has a bit indicating + ;; whether the next bits are base-char or character, and then just the + ;; bits of that character using either 7 bits (filling out 1 byte) + ;; or 21 bits (consuming 3 or 4 bytes total) on a per-character basis. + (buffer nil :type (or simple-base-string simple-character-string)) + ;; Whether any non-base character has been written. + ;; This is :IGNORE for base-char output streams. + (unicode-p :ignore) + ;; Chains of buffers to use + (prev nil :type list) + (next nil :type list) + ;; Index of the next location to use in the current string. + (pointer 0 :type index) + ;; Global location in the stream + (index 0 :type index) + ;; Index cache: when we move backwards we save the greater of this + ;; and index here, so the greater of index and this is always the + ;; end of the stream. + (index-cache 0 :type index) + ;; Pseudo-actual element type. We no longer store the as-requested type. + ;; (If the value is :DEFAULT, we return CHARACTER on inquiry.) + (element-type nil :read-only t + :type (member #+sb-unicode :default + #+sb-unicode character + base-char nil))) +(declaim (freeze-type string-output-stream)) + +(defmacro %allocate-string-ostream () + `(%make-structure-instance ,(find-defstruct-description 'string-output-stream) nil)) + +(defmacro with-output-to-string + ((var &optional string &key (element-type ''character)) &body body) + (if string + (let ((dummy '#:stream)) + ;; "If string is supplied, element-type is ignored". + ;; Why do implementors take this to mean "evaluated and ignored?" + ;; I would have figured it meant expansion-time ignored. + `(dx-let ((,dummy (%make-structure-instance + ,(find-defstruct-description 'fill-pointer-output-stream) + nil))) + (let ((,var (truly-the fill-pointer-output-stream + (%init-fill-pointer-output-stream + ,dummy ,string ,element-type)))) + ;; http://www.lispworks.com/documentation/HyperSpec/Body/d_ignore.htm#ignore + ;; "The stream variables established by ... with-output-to-string + ;; are, by definition, always used" + (declare (ignorable ,var)) + ,@body))) + (expand-with-output-to-string var element-type body nil))) + +;;; Similar to WITH-OUTPUT-TO-STRING, but produces the most compact result +;;; string possible (BASE or CHARACTER) depending on what was written. +;;; This is not something that the standard macro permits. +(defmacro %with-output-to-string ((var) &body body) + (expand-with-output-to-string var ''character body t)) + +;;; A macro to better exploit jump tables. Even though jumping based on symbol-hash +;;; is possible, it is of course slightly faster to dispatch on small integers, +;;; and for architectures which don't implement jump tables, +;;; using integers eliminates the load of many code header constants. +;;; Streams which don't want to handle every operation (don't end in a T clause) +;;; should specify :DEFAULT NIL to avoid an error. +(defmacro stream-misc-case ((operation &key (default 'error)) &rest clauses) + (let* ((otherwise) + (clauses + (mapcar (lambda (clause) + (let ((key (car clause))) + (cons (if (eq key 't) + (setq otherwise t) + (mapcar #'%stream-opcode (ensure-list (car clause)))) + (cdr clause)))) + clauses))) + `(,(if (and (not otherwise) (eq default 'error)) 'ecase 'case) ,operation + ,@clauses))) + +(defmacro call-ansi-stream-misc (stream operation &optional (arg nil argp)) + ;; Never stuff in a placeholder in the three operations that take an argument. + (aver (or argp (not (memq operation '(:set-file-position :file-string-length :unread))))) + `(funcall (ansi-stream-misc ,stream) ,stream + ;; If operation is a literal keyword, translate it, otherwise + ;; it is a variable whose values is the opcode for passthru. + ,(if (keywordp operation) (%stream-opcode operation) operation) + ,(if argp arg 0))) + +;;; This predicate assumes some things: +;;; - that a simple-stream class will never be FUNCALLABLE-STANDARD-OBJECT +;;; (so that we need only check for %INSTANCEP) +;;; - a class will never be redefined such that it moves from one part of the stream +;;; hierarchy to the other. (i.e. you don't redefine MY-STREAM-CLASS such that +;;; it was a Gray stream and becomes a simple-stream or vice-versa) +;;; - instance invalidation, if it needs to happen, will happen somewhere later in +;;; the stream protocol. (the layout-invalid trap can be deferred) +;;; This is OK because the next level of dispatch is not to a generic function +;;; in the simple-stream layering. It is generic at the "device" but not the API. +(defmacro simple-stream-p (x) + `(and (%instancep ,x) + (logtest (layout-flags (%instance-layout ,x)) + sb-kernel::+simple-stream-layout-flag+))) + +;;; This macro is for the first-level of dispatch which usually entails +;;; deciding whether the argument is actually a stream or merely a designator +;;; for a stream (T or NIL), and then figuring out which family of stream +;;; it belongs to: ANSI, Gray, or simple. +(defmacro stream-api-dispatch ((streamvar &optional initform) &key native simple gray) + ;; Most CL: stream APIs use explicit-check, so we should assert that the thing + ;; is actually a stream. + ;; If the CL interface bypasses STREAM-API-DISPATCH then it is up to generic layer + ;; to signal an error, the class of which seems unfortunately subject to debate. + (aver (and native (or simple gray))) + `(let ,(if initform `((,streamvar ,initform))) + ;; Dispatch native first, then if sb-simple-streams have been loaded, + ;; those, and finally punt to a generic function. + (block stream + ;; Assume that simple-stream can not inherit funcallable-standard-object. + (when (%instancep ,streamvar) + (let ((layout (%instance-layout ,streamvar))) + (cond ((sb-c::%structure-is-a layout ,(find-layout 'ansi-stream)) + (let ((,streamvar (truly-the ansi-stream ,streamvar))) + (return-from stream ,native))) + ((logtest (layout-flags layout) +simple-stream-layout-flag+) + (return-from stream ,simple))))) + (let ((,streamvar (the stream ,streamvar))) ,gray)))) diff --git a/src/code/aprof.lisp b/src/code/aprof.lisp index ec4f56688f..8814cc94ca 100644 --- a/src/code/aprof.lisp +++ b/src/code/aprof.lisp @@ -64,11 +64,12 @@ (defpackage #:sb-aprof (:use #:cl #:sb-ext #:sb-alien #:sb-sys #:sb-int #:sb-kernel) - (:export #:aprof-run #:aprof-show) + (:export #:aprof-run #:aprof-show #:aprof-reset + #:aprof-start #:patch-all-code) (:import-from #:sb-di #:valid-lisp-pointer-p) - (:import-from #:sb-vm #:rbp-offset) + (:import-from #:sb-vm #:thread-reg) (:import-from #:sb-x86-64-asm - #:get-gpr #:reg #:reg-num + #:register-p #:get-gpr #:reg #:reg-num #:machine-ea #:machine-ea-p #:machine-ea-disp #:machine-ea-base #:machine-ea-index #:inc #:add #:mov)) @@ -80,10 +81,7 @@ bytes count type pc) (declaim (freeze-type alloc)) -(defvar *allocation-profile-metadata* nil) - -(defvar *allocation-fixups-installed* - (make-hash-table :test 'eq :weakness :key :synchronized t)) +(defglobal *allocation-profile-metadata* nil) (define-alien-variable alloc-profile-buffer system-area-pointer) (defun aprof-reset () @@ -93,22 +91,25 @@ (* (/ (length *allocation-profile-metadata*) 2) sb-vm:n-word-bytes))) -(defun patch-fixups () - (let ((n-fixups 0) - (n-patched 0) - (from-ht sb-c::*allocation-point-fixups*) - (to-ht *allocation-fixups-installed*)) - (when (plusp (hash-table-count from-ht)) - (dohash ((code fixups) from-ht) - (do-packed-varints (loc fixups) - (incf n-fixups) - (let ((byte (sap-ref-8 (code-instructions code) loc))) - (when (eql byte #xEB) - (setf (sap-ref-8 (code-instructions code) loc) #x74) ; JEQ - (incf n-patched)))) - (setf (gethash code to-ht) fixups) - (remhash code from-ht))) - (values n-fixups n-patched))) +(defun patch-code (code locs &aux (n 0) (n-patched 0)) + (do-packed-varints (loc locs) + (incf n) + (let ((byte (sap-ref-8 (code-instructions code) loc))) + (when (eql byte #xEB) + (setf (sap-ref-8 (code-instructions code) loc) #x74) ; JEQ + (incf n-patched)))) + (values n n-patched)) + +(defun patch-all-code () + (let ((total-n-patch-points 0) + (total-n-patched 0) + (ht sb-c::*allocation-patch-points*)) + (dohash ((code locs) ht) + (remhash code ht) + (multiple-value-bind (n-patch-points n-patched) (patch-code code locs) + (incf total-n-patch-points n-patch-points) + (incf total-n-patched n-patched))) + (values total-n-patch-points total-n-patched))) (defun aprof-start () (let ((v *allocation-profile-metadata*)) @@ -136,34 +137,13 @@ (defun layout-name (ptr) (if (eql (valid-lisp-pointer-p (int-sap ptr)) 0) 'structure - (layout-classoid-name (make-lisp-obj ptr)))) + (wrapper-classoid-name (layout-friend (make-lisp-obj ptr))))) ;;; These EAs are s-expressions, not instances of EA or MACHINE-EA. +#-sb-safepoint (defconstant-eqx p-a-flag `(ea ,(ash sb-vm::thread-pseudo-atomic-bits-slot sb-vm:word-shift) - ,(get-gpr :qword (sb-c:tn-offset sb-vm::thread-base-tn))) - #'equal) -(defconstant-eqx region-ptr - `(ea ,(ash sb-vm::thread-alloc-region-slot sb-vm:word-shift) - ,(get-gpr :qword (sb-c:tn-offset sb-vm::thread-base-tn))) + ,(get-gpr :qword sb-vm::thread-reg)) #'equal) -(defconstant-eqx region-end - `(ea ,(ash (1+ sb-vm::thread-alloc-region-slot) sb-vm:word-shift) - ,(get-gpr :qword (sb-c:tn-offset sb-vm::thread-base-tn))) - #'equal) - -(defun header-word-store-p (inst bindings) - ;; a byte-sized or word-sized store at displacement 8 through 10 is OK - (let ((ea (caddr inst)) - (freeptr (cdr (assoc '$free bindings)))) - (and (eq (car inst) 'mov) - (typep ea 'machine-ea) - (typep freeptr 'reg) - (eql (reg-num freeptr) (machine-ea-base ea)) - (or (and (member (cadr inst) '(:byte :word)) - (typep (machine-ea-disp ea) '(integer 8 10))) - (and (eq (cadr inst) :qword) - (eql (machine-ea-disp ea) 8) - (typep (cadddr inst) 'reg)))))) ;;; Templates to try in order. The one for unknown headered objects should be last ;;; so that we try to match a store to the header word if possible. @@ -173,47 +153,95 @@ ;;; "don't know how to dump R13 (default MAKE-LOAD-FORM method called)." #-sb-show (setq *allocation-templates* - `((array ;; also array-header - (xadd $free $size) - (cmp :qword $free ,region-end) - (jmp :nbe $_) - (mov :qword ,region-ptr $free) - (mov $_ (ea 0 $size) $header); after XADD, size is the old free ptr - (:optional (mov $_ (ea 8 $size) $vector-len)) - (:or (or $size ,sb-vm:other-pointer-lowtag) - (lea :qword $result (ea ,sb-vm:other-pointer-lowtag $size)))) - - (any (:or (lea :qword $end (ea $nbytes $free $nbytes-var)) + `((fixed+header + (add ?end ?nbytes) + (cmp :qword ?end :tlab-limit) + (jmp :nbe ?_) + (mov :qword :tlab-freeptr ?end) + (:or (add ?end ?bias) (dec ?end)) + (mov ?_ (ea ?_ ?end) ?header)) + + (var-array + (add ?end ?nbytes) + (cmp :qword ?end :tlab-limit) + (jmp :nbe ?_) + (mov :qword :tlab-freeptr ?end) + (sub ?end ?nbytes) + (mov ?_ (ea ?_ ?end) ?header) + (mov ?_ (ea ?_ ?end) ?vector-len)) + + (var-xadd + ;; after the xadd, SIZE holds the original value of free-ptr + ;; and free-ptr points to the end of the putative data block. + (xadd ?free ?size) + (cmp :qword ?free :tlab-limit) + (jmp :nbe ?_) + (mov :qword :tlab-freeptr ?free) + ;; Could have one or two stores prior to ORing in a lowtag. + (:optional (mov ?_ (ea 0 ?size) ?header)) + (:optional (mov ?_ (ea 8 ?size) ?vector-len)) + (:or (or ?size ?lowtag) + (lea :qword ?result (ea ?lowtag ?size)))) + + (any (:or (lea :qword ?end (ea ?nbytes ?free ?nbytes-var)) ;; LEA with scale=1 can have base and index swapped - (lea :qword $end (ea 0 $nbytes-var $free)) - (add $end $free)) ; $end originally holds the size in bytes - (cmp :qword $end ,region-end) - (jmp :nbe $_) - (mov :qword ,region-ptr $end) - (mov $_ (ea 0 $free) $header) - (:optional (:if header-word-store-p (mov $_ (ea $_ $free) $vector-len))) - (:or (or $free $lowtag) - (lea :qword $result (ea $lowtag $free)))) + (lea :qword ?end (ea 0 ?nbytes-var ?free)) + (add ?end ?free)) ; ?end originally holds the size in bytes + (cmp :qword ?end :tlab-limit) + (jmp :nbe ?_) + (mov :qword :tlab-freeptr ?end) + (mov ?_ (ea 0 ?free) ?header) + (:optional (mov ?_ (ea ?_ ?free) ?vector-len)) + (:or (or ?free ?lowtag) + (lea :qword ?result (ea ?lowtag ?free)))) + + ;; LISTIFY-REST-ARG computes a tagged pointer to the _last_ cons in the memory block, + ;; not the first cons. + (list (lea :qword ?end (ea 0 ?nbytes ?free)) + (cmp :qword ?end :tlab-limit) + (jmp :nbe ?_) + (mov :qword :tlab-freeptr ?end) + (lea :qword ?free (ea ,(- sb-vm:list-pointer-lowtag + (* sb-vm:cons-size sb-vm:n-word-bytes)) + ?free ?nbytes)) + (shr ?nbytes 4)) + + (acons (lea :qword ?end (ea 32 ?free)) + (cmp :qword ?end :tlab-limit) + (jmp :nbe ?_) + (mov :qword :tlab-freeptr ?end) + (:repeat (mov . ignore)) + (lea :qword ?result (ea #.(+ 16 sb-vm:list-pointer-lowtag) ?free))) ;; either non-headered object (cons) or unknown header or unknown nbytes - (unknown-header (:or (lea :qword $end (ea $nbytes $free $nbytes-var)) - (lea :qword $end (ea 0 $nbytes-var $free)) - (add $end $free)) - (cmp :qword $end ,region-end) - (jmp :nbe $_) - (mov :qword ,region-ptr $end) + (unknown-header (:or (lea :qword ?end (ea ?nbytes ?free ?nbytes-var)) + (lea :qword ?end (ea 0 ?nbytes-var ?free)) + (add ?end ?free)) + (cmp :qword ?end :tlab-limit) + (jmp :nbe ?_) + (mov :qword :tlab-freeptr ?end) (:repeat (:or (mov . ignore) (lea . ignore))) - (:or (or $free $lowtag) - (lea :qword $result (ea $lowtag $free)))))) + (:or (or ?free ?lowtag) + (lea :qword ?result (ea ?lowtag ?free)))))) (defglobal *allocation-templates-large* nil) (setq *allocation-templates-large* - `((array (push $nbytes) + `((array (push ?nbytes) (call . ignore) - (pop $result) - (mov $_ (ea 0 $result) $header) - (mov $_ (ea $_ $result) $vector-len) - (or $result $lowtag)))) + (pop ?result) + (mov ?_ (ea 0 ?result) ?header) + (mov ?_ (ea ?_ ?result) ?vector-len) + (or ?result ?lowtag)) + ;; not really "large" but same as preceding + (funinstance (push ?nbytes) + (call . ignore) + (pop ?result) + (mov ?_ (ea 0 ?result) ?header) + (or ?result ?lowtag)) + (list (push ?nbytes) + (call . ignore) + (pop ?result) + (or ?result ?lowtag)))) (defun iterator-begin (iterator pc code) (let ((segment (sb-disassem:make-code-segment @@ -233,15 +261,30 @@ ;; FIXME: this drops any LOCK prefix, but that seems to be ok (do ((tail (cdr inst) (cdr tail))) ((null tail)) + ;; This takes an instruction expressed thusly: + ;; (MOV (#S(MACHINE-EA :DISP n :BASE n) . :QWORD) RDX) + ;; and turns it into: + ;; (MOV :QWORD #S(MACHINE-EA :DISP n :BASE n) RDX) (when (typep (car tail) '(cons machine-ea)) - (setf inst (list* (car inst) (cdar tail) (cdr inst)) - (car tail) (caar tail)) + (let ((ea (caar tail))) + (setf inst (list* (car inst) (cdar tail) (cdr inst))) ; insert the :size) + (when (eq (machine-ea-base ea) sb-vm::thread-reg) + ;; Figure out if we're looking at an allocation buffer + (let ((disp (ash (machine-ea-disp ea) (- sb-vm:word-shift)))) + (awhen (case disp + ((#.sb-vm::thread-mixed-tlab-slot + #.sb-vm::thread-cons-tlab-slot) :tlab-freeptr) + ((#.(1+ sb-vm::thread-mixed-tlab-slot) + #.(1+ sb-vm::thread-cons-tlab-slot)) :tlab-limit)) + (setq ea it)))) + (setf (car tail) ea)) ; change the EA + ;; There can be at most one EA per instruction, so we're done (return))) (vector-push-extend inst vector) inst)))) (defparameter *debug-deduce-type* nil) -(eval-when (:compile-toplevel) +(eval-when (:compile-toplevel :execute) (defmacro note (&rest args) `(when *debug-deduce-type* (let ((*print-pretty* nil)) @@ -272,8 +315,8 @@ (note " match-atom ~s ~s ~s ~s~%" pattern input ea-reg-p bindings) (when (and (integerp input) ea-reg-p) (setq input (get-gpr :qword input))) - (cond ((eq pattern '$_) t) ; match and ignore anything - ((and (symbolp pattern) (char= (char (string pattern) 0) #\$)) + (cond ((eq pattern '?_) t) ; match and ignore anything + ((and (symbolp pattern) (char= (char (string pattern) 0) #\?)) ;; free variable binds to input, otherwise binding must match (let* ((cell (assq pattern bindings)) (binding (cdr cell))) @@ -288,7 +331,7 @@ (t (eql pattern input)))) (ok-binding (pattern input) (case pattern - ($lowtag + (?lowtag (memq input `(,sb-vm:instance-pointer-lowtag ,sb-vm:list-pointer-lowtag ,sb-vm:fun-pointer-lowtag ,sb-vm:other-pointer-lowtag))) (t t)))) @@ -326,33 +369,40 @@ (loop (when (endp template) (return bindings)) (let ((pattern (pop template))) (case (car pattern) - ((:optional :repeat) - (let ((count (if (eq (car pattern) :repeat) most-positive-fixnum 1))) - ;; :REPEAT matches zero or more instructions, but as few as possible. - ;; :OPTIONAL matches zero or one, similarly. + (:optional + ;; :OPTIONAL is greedy, preferring to match if it can, + ;; but if the rest of the template fails, we'll backtrack + ;; and skip this pattern. + (when (inst-matchp input (cadr pattern)) + (let ((bindings (matchp input template bindings))) + (cond ((eq bindings :fail) + (setf (car input) start)) ; don't match + (t + (return bindings)))))) + (:repeat + ;; :REPEAT matches zero or more instructions, as few as possible. (let ((next-pattern (pop template))) (loop (when (inst-matchp input next-pattern) (return)) - (unless (and (>= (decf count) 0) - (inst-matchp input (cadr pattern))) - (fail)))))) + (unless (inst-matchp input (cadr pattern)) + (fail))))) (t (unless (inst-matchp input pattern) (fail)))))))) (defun deduce-layout (iterator bindings) - (unless (assq '$result bindings) - (push `($result . ,(cdr (assq '$free bindings))) bindings)) - (let ((bindings - (matchp iterator - (load-time-value - `((xor :qword ,p-a-flag ,(get-gpr :qword rbp-offset)) - (jmp :eq $_) - (break . ignore) - (mov :dword (ea 1 $result) $layout)) t) - bindings))) - (if (eq bindings :fail) - 'instance - (layout-name (cdr (assq '$layout bindings)))))) + (unless (assq '?result bindings) + (push `(?result . ,(cdr (assq '?free bindings))) bindings)) + (when (eql (cdr (assq '?lowtag bindings)) sb-vm:instance-pointer-lowtag) + (destructuring-bind (pos vector . dstate) iterator + (let ((inst (aref vector (1- pos)))) + (aver (eq (car inst) 'or)) + (let* ((iterator (list* (- pos 2) vector dstate)) + (bindings (matchp iterator + (load-time-value `((mov :dword (ea 4 ?result) ?layout)) t) + bindings))) + (if (eq bindings :fail) + 'instance + (layout-name (cdr (assq '?layout bindings))))))))) (defun deduce-fun-subtype (iterator bindings) (declare (ignorable iterator bindings)) @@ -361,14 +411,14 @@ (let* ((bindings (matchp iterator (load-time-value - `((mov $scratch $header) - (or :qword $scratch + `((mov ?scratch ?header) + (or :qword ?scratch (ea ,(ash sb-vm::thread-function-layout-slot sb-vm:word-shift) - ,(get-gpr :qword (sb-c:tn-offset sb-vm::thread-base-tn)))) - (mov :qword (ea ,(- sb-vm:fun-pointer-lowtag) $result) $scratch)) + ,(get-gpr :qword sb-vm::thread-reg))) + (mov :qword (ea ,(- sb-vm:fun-pointer-lowtag) ?result) ?scratch)) t) bindings)) - (header (and (listp bindings) (cdr (assoc '$header bindings))))) + (header (and (listp bindings) (cdr (assoc '?header bindings))))) (if (and (integerp header) (eq (logand header #xFF) sb-vm:closure-widetag)) 'closure 'function))) @@ -381,36 +431,30 @@ ;; Expect an increment of the allocation point hit counter (let* ((inst (get-instruction iterator)) (ea (third inst))) ; (INC :qword EA) - (when (and (eq (car inst) 'inc) - (eql (machine-ea-base ea) (sb-c:tn-offset sb-vm::temp-reg-tn)) - (null (machine-ea-index ea))) + (when (and (eq (car inst) 'inc) (machine-ea-base ea) (null (machine-ea-index ea))) (incf (car iterator)) - (let ((profiler-index (machine-ea-disp ea))) + (let ((profiler-base (machine-ea-base ea)) + (profiler-index (machine-ea-disp ea))) ;; Optional: the total number of bytes at the allocation point (let* ((inst (get-instruction iterator)) (ea (third inst))) (when (and (eq (car inst) 'add) (machine-ea-p ea) - (eql (machine-ea-base ea) (sb-c:tn-offset sb-vm::temp-reg-tn)) + (eql (machine-ea-base ea) profiler-base) (null (machine-ea-index ea)) (eql (machine-ea-disp ea) (+ profiler-index sb-vm:n-word-bytes))) (incf (car iterator))))))) ;; Expect a store to the pseudo-atomic flag + #-sb-safepoint (when (eq (matchp iterator - (load-time-value `((mov :qword ,p-a-flag ,(get-gpr :qword rbp-offset))) t) + (load-time-value `((mov :qword ,p-a-flag ,(get-gpr :qword thread-reg))) t) nil) :fail) (return-from deduce-type (values nil nil))) (let* ((type) (bindings - (matchp iterator - ;; compiler bug? If expressed with "`" then the compiler tries to - ;; refer to the undumpable constant REGION-PTR by its value, not by its - ;; name, then complaining that it can't be dumped. - ;; Why is ",P-A-FLAG" acceptable but this not? - (load-time-value (list (list 'mov :qword '$free region-ptr)) t) - nil)) + (matchp iterator `((mov :qword ?free :tlab-freeptr)) nil)) (templates (cond (template-name (list (find template-name *allocation-templates* :key 'car))) @@ -428,22 +472,26 @@ (return)))) (if (eq bindings :fail) (values nil nil) - (let ((nbytes (cdr (assoc '$nbytes bindings))) - (header (cdr (assoc '$header bindings))) - (lowtag (cdr (assoc '$lowtag bindings)))) - ;; The low bit might signify something to the allocator. Clear it. - (when (integerp nbytes) - (setq nbytes (logandc2 nbytes 1))) + (let ((nbytes (cdr (assoc '?nbytes bindings))) + (header (cdr (assoc '?header bindings))) + (lowtag (cdr (assoc '?lowtag bindings)))) ;; matchp converts NIL in a machine-ea to 0. The disassembler uses ;; NIL to signify that there was no displacement, which makes sense ;; when register indirect mode is used without a SIB byte. (when (eq nbytes 0) (setq nbytes nil)) - (cond ((and (member type '(array any)) + (cond ((and (member type '(fixed+header var-array var-xadd any)) (typep header '(or sb-vm:word sb-vm:signed-word))) (setq type (aref *tag-to-type* (logand header #xFF))) + (when (register-p nbytes) + (setq nbytes nil)) (when (eq type 'instance) (setq type (deduce-layout iterator bindings)))) + ((eq type 'list) ; listify-rest-arg + (unless (integerp nbytes) + (setq nbytes nil))) + ((eq type 'acons) + (setq type 'list nbytes (* 2 sb-vm:cons-size sb-vm:n-word-bytes))) ((member type '(any unknown-header)) (setq type (case lowtag (#.sb-vm:list-pointer-lowtag 'list) @@ -456,12 +504,12 @@ ;;; Return a name for PC-OFFS in CODE. PC-OFFSET is relative ;;; to CODE-INSTRUCTIONS. (defun pc-offs-to-fun-name (pc-offs code &aux (di (%code-debug-info code))) - (if (consp di) ; assembler routines + (if (hash-table-p di) ; assembler routines (block nil (maphash (lambda (k v) ; FIXME: OAOO violation, at least twice over (when (<= (car v) pc-offs (cadr v)) (return k))) - (car di))) + di)) (let* ((funmap (sb-c::compiled-debug-info-fun-map di))) (unless (sb-c::compiled-debug-fun-next funmap) (aver (typep funmap 'sb-c::compiled-debug-fun-toplevel)) @@ -553,7 +601,7 @@ (sum-pct 0) (sum-bytes 0)) (when (eq stream nil) - (setq stream (make-broadcast-stream))) ; lazy's person's approach + (setq stream sb-impl::*null-broadcast-stream*)) ; lazy's person's approach (cond ((not detail) (format stream "~& % Sum % Bytes Allocations Function~%") (format stream "~& ------- ------- ----------- ----------- --------~%")) @@ -625,16 +673,20 @@ ;;; cons profiling. ;;; STREAM is where to report, defaulting to *standard-output*. ;;; The convention is that of map-segment-instructions, meaning NIL is a sink. -(defun aprof-run (fun &key (stream *standard-output*)) +(defun aprof-run (fun &key (report t) (stream *standard-output*) arguments) (aprof-reset) - (patch-fixups) - (let (nbytes) - (unwind-protect - (progn (aprof-start) (funcall fun)) - (aprof-stop) - (setq nbytes (aprof-show :stream stream)) - (when stream (terpri stream))) - nbytes)) + (patch-all-code) + (dx-let ((arglist (cons arguments nil))) ; so no consing in here + (when (listp arguments) + (setq arglist (car arglist))) ; was already a list + (let (nbytes) + (unwind-protect + (progn (aprof-start) (apply fun arglist)) + (aprof-stop)) + (when report + (setq nbytes (aprof-show :stream stream)) + (when stream (terpri stream))) + nbytes))) ;;;; diff --git a/src/code/arm-vm.lisp b/src/code/arm-vm.lisp index 82d5ec580b..f269f0c0a9 100644 --- a/src/code/arm-vm.lisp +++ b/src/code/arm-vm.lisp @@ -2,32 +2,19 @@ ;;; (in-package "SB-VM") -#-sb-xc-host (defun machine-type () "Return a string describing the type of the local machine." "ARM") - -;;;; FIXUP-CODE-OBJECT -(defconstant-eqx +fixup-kinds+ #(:absolute) #'equalp) -(!with-bigvec-or-sap -(defun fixup-code-object (code offset fixup kind flavor) - (declare (type index offset)) - (declare (ignore flavor)) - (unless (zerop (rem offset sb-assem:+inst-alignment-bytes+)) - (error "Unaligned instruction? offset=#x~X." offset)) - (let ((sap (code-instructions code))) - (ecase kind - (:absolute - (setf (sap-ref-32 sap offset) fixup)))) - nil)) +(defun return-machine-address (scp) + (context-register scp lr-offset)) + ;;;; "Sigcontext" access functions, cut & pasted from sparc-vm.lisp, ;;;; then modified for ARM. ;;;; ;;;; See also x86-vm for commentary on signed vs unsigned. -#-sb-xc-host (progn (defun context-float-register (context index format) (declare (ignorable context index)) (warn "stub CONTEXT-FLOAT-REGISTER") @@ -48,4 +35,3 @@ (trap-number (sap-ref-8 pc 4))) (declare (type system-area-pointer pc)) (sb-kernel::decode-internal-error-args (sap+ pc 5) trap-number))) -) ; end PROGN diff --git a/src/code/arm64-simd.lisp b/src/code/arm64-simd.lisp new file mode 100644 index 0000000000..b772d1ec81 --- /dev/null +++ b/src/code/arm64-simd.lisp @@ -0,0 +1,513 @@ +;;;; This software is part of the SBCL system. See the README file for +;;;; more information. +;;;; +;;;; This software is derived from the CMU CL system, which was +;;;; written at Carnegie Mellon University and released into the +;;;; public domain. The software is in the public domain and is +;;;; provided with absolutely no warranty. See the COPYING and CREDITS +;;;; files for more information. + +(in-package "SB-VM") + +(assert (= base-char-code-limit 128)) + +(eval-when (:compile-toplevel :load-toplevel :execute) + (define-vop () + (:translate vector-ref-128) + (:args (vector :scs (descriptor-reg) :to :result) + (index :scs (any-reg))) + (:temporary (:scs (non-descriptor-reg) :from (:argument 1)) offset) + (:arg-types * tagged-num) + (:results (res :scs (complex-double-reg))) + (:result-types complex-double-float) + (:policy :fast-safe) + (:generator 3 + (inst lsl offset index (1+ (- word-shift n-fixnum-tag-bits))) + (inst add offset offset (- (* vector-data-offset n-word-bytes) + other-pointer-lowtag)) + (inst ldr res (@ vector offset)))) + + (define-vop (set-vector-ref-128) + (:translate (setf vector-ref-128)) + (:args (value :scs (complex-double-reg)) + (vector :scs (descriptor-reg) :to :result) + (index :scs (any-reg))) + (:temporary (:scs (non-descriptor-reg) :from (:argument 2)) offset) + (:arg-types complex-double-float * tagged-num) + (:policy :fast-safe) + (:generator 3 + (inst lsl offset index (1+ (- word-shift n-fixnum-tag-bits))) + (inst add offset offset (- (* vector-data-offset n-word-bytes) + other-pointer-lowtag)) + (inst str value (@ vector offset)))) + + (defun reg-in-sc (tn sc) + (make-random-tn :kind :normal + :sc (sc-or-lose sc) + :offset (tn-offset tn)))) + +(defmacro simd-mask-32 (value) + `(inline-vop + (((:info value) ,value)) + ((res complex-double-reg complex-double-float)) + (inst movi res value :4s))) + +(defmacro simd-mask-8 (value) + `(inline-vop + (((:info value) ,value)) + ((res complex-double-reg complex-double-float)) + (inst movi res value :16b))) + +;;; Basically like the x86 with-pinned-object, +;;; but here only the boxed registers are pinned. +;;; This doesn't prevent the var from going to the stack, but none of +;;; the routines should do that. +(defmacro with-pinned-objects-in-registers (vars &body body) + `(multiple-value-prog1 ,@body + ,@(loop for var in vars + collect `(touch-object ,var)))) + +(defmacro simd-string-case (a source destination index fallback) + `(let ((ascii-p (simd-mask-32 192)) + (a-mask (simd-mask-32 ,(char-code a))) + (z-mask (simd-mask-32 25)) + (flip (simd-mask-32 #x20))) + (declare (optimize sb-c::preserve-single-use-debug-variables)) + (loop for ,index below (ceiling length (/ 128 32)) + do + (let ((bits (vector-ref-128 ,source ,index))) + (unless (zerop (inline-vop + (((bits complex-double-reg complex-double-float :target temp) bits) + ((ascii-p complex-double-reg complex-double-float :to :save) ascii-p) + ((temp))) + ((res unsigned-reg unsigned-num)) + (inst cmgt temp bits ascii-p :4s) + (inst umaxv temp temp :4s) + (inst umov res temp 0 :s))) + (return ,fallback)) + (setf (vector-ref-128 ,destination ,index) + (inline-vop (((bits complex-double-reg complex-double-float :target res) bits) + ((a-mask complex-double-reg complex-double-float :to :save) a-mask) + ((z-mask) z-mask) + ((flip) flip) + ((temp))) + ((res complex-double-reg complex-double-float)) + (inst s-sub temp bits a-mask :4s) + (inst cmhs temp z-mask temp :4s) + (inst s-and temp temp flip) + (inst s-eor res bits temp))))))) + +(defun simd-nreverse8 (result vector start end) + (declare (optimize speed (safety 0))) + (with-pinned-objects-in-registers (vector) + (inline-vop (((left sap-reg t) (vector-sap vector)) + ((start any-reg tagged-num) start) + ((end) end) + ((right signed-reg signed-num)) + ((gl)) + ((gr)) + ((vl complex-double-reg complex-double-float)) + ((vr))) + () + (inst add right left (lsr end 1)) + (inst add left left (lsr start 1)) + (inst sub gl right left) + (inst cmp gl 32) + (inst b :lt WORD) + (inst sub right right 16) + + LOOP + (inst ldr vl (@ left)) + (inst ldr vr (@ right)) + + (inst rev64 vl vl) + (inst ext vl vl vl 8) + (inst rev64 vr vr) + (inst ext vr vr vr 8) + + (inst str vr (@ left 16 :post-index)) + (inst str vl (@ right -16 :post-index)) + (inst cmp left right) + (inst b :lt loop) + + (inst add right right 16) + + (inst sub gl right left) + WORD + (inst cmp gl 16) + (inst b :lt BYTE) + + (inst ldr gl (@ left)) + (inst ldr gr (@ right -8 :pre-index)) + (inst rev gl gl) + (inst rev gr gr) + (inst str gr (@ left 8 :post-index)) + (inst str gl (@ right)) + + BYTE + (inst sub right right 1) + (inst cmp right left) + (inst b :lt DONE) + + ;; After the 16-element copy above there are at most 15 + ;; elements, have to swap 14 elements with one staying in the + ;; middle. + (loop repeat 7 + do + (inst ldrb gl (@ left)) + (inst ldrb gr (@ right)) + (inst strb gr (@ left 1 :post-index)) + (inst strb gl (@ right -1 :post-index)) + (inst cmp left right) + (inst b :ge DONE)) + DONE)) + result) + +(defun simd-nreverse32 (result vector start end) + (declare (optimize speed (safety 0))) + (with-pinned-objects-in-registers (vector) + (inline-vop (((left sap-reg t) (vector-sap vector)) + ((start any-reg tagged-num) start) + ((end) end) + ((right signed-reg signed-num)) + ((gl)) + ((gr)) + ((vl complex-double-reg complex-double-float)) + ((vr))) + () + (inst add right left (lsl end 1)) + (inst add left left (lsl start 1)) + (inst sub gl right left) + (inst cmp gl 32) + (inst b :lt SCALAR) + (inst sub right right 16) + + LOOP + (inst ldr vl (@ left)) + (inst ldr vr (@ right)) + + (inst rev64 vl vl :4s) + (inst ext vl vl vl 8) + (inst rev64 vr vr :4s) + (inst ext vr vr vr 8) + + (inst str vr (@ left 16 :post-index)) + (inst str vl (@ right -16 :post-index)) + (inst cmp left right) + (inst b :lt loop) + + (inst add right right 16) + + SCALAR + (inst sub right right 4) + (inst cmp right left) + (inst b :lt DONE) + (setf gl (32-bit-reg gl) + gr (32-bit-reg gr)) + + (loop repeat 3 + do + (inst ldr gl (@ left)) + (inst ldr gr (@ right)) + (inst str gr (@ left 4 :post-index)) + (inst str gl (@ right -4 :post-index)) + (inst cmp left right) + (inst b :ge DONE)) + DONE)) + result) + +(defun simd-reverse8 (target source start length) + (declare (optimize speed (safety 0))) + (with-pinned-objects-in-registers (target source) + (inline-vop (((source sap-reg t) (vector-sap source)) + ((target sap-reg t) (vector-sap target)) + ((start any-reg tagged-num) start) + ((length) length) + ((s-i signed-reg signed-num)) + ((t-i)) + ((g)) + ((v complex-double-reg complex-double-float))) + () + (inst add source source (lsr start 1)) + (inst mov t-i 0) + (inst lsr s-i length 1) + (inst cmp s-i 16) + (inst b :lt WORD) + (inst sub s-i s-i 16) + + LOOP + (inst ldr v (@ source s-i)) + + (inst rev64 v v) + (inst ext v v v 8) + (inst str v (@ target t-i)) + + (inst add t-i t-i 16) + (inst subs s-i s-i 16) + (inst b :ge LOOP) + (inst add s-i s-i 16) + + WORD + (inst cmp s-i 7) + (inst b :lt BYTE) + (inst sub s-i s-i 8) + (inst ldr g (@ source s-i)) + (inst rev g g) + (inst str g (@ target t-i)) + (inst add t-i t-i 8) + + BYTE + (inst subs s-i s-i 1) + (inst b :lt DONE) + + (loop repeat 7 + do + (inst ldrb g (@ source s-i)) + (inst strb g (@ target t-i)) + (inst add t-i t-i 1) + (inst subs s-i s-i 1) + (inst b :lt DONE)) + DONE)) + target) + +(defun simd-reverse32 (target source start length) + (declare (optimize speed (safety 0))) + (with-pinned-objects-in-registers (target source) + (inline-vop (((source sap-reg t) (vector-sap source)) + ((target sap-reg t) (vector-sap target)) + ((start any-reg tagged-num) start) + ((length) length) + ((s-i signed-reg signed-num)) + ((t-i)) + ((g)) + ((v complex-double-reg complex-double-float))) + () + (inst add source source (lsl start 1)) + (inst mov t-i 0) + (inst lsl s-i length 1) + (inst cmp s-i 16) + (inst b :lt SCALAR) + (inst sub s-i s-i 16) + + LOOP + (inst ldr v (@ source s-i)) + + (inst rev64 v v :4s) + (inst ext v v v 8) + (inst str v (@ target t-i)) + + (inst add t-i t-i 16) + (inst subs s-i s-i 16) + (inst b :ge LOOP) + (inst add s-i s-i 16) + + SCALAR + (inst subs s-i s-i 4) + (inst b :lt DONE) + + (setf g (32-bit-reg g)) + (loop repeat 3 + do + (inst ldr g (@ source s-i)) + (inst str g (@ target t-i)) + (inst add t-i t-i 4) + (inst subs s-i s-i 4) + (inst b :lt DONE)) + DONE)) + target) + +(defun simd-cmp-8-32 (byte-array 32-bit-array length) + (declare (optimize speed (safety 0))) + (with-pinned-objects-in-registers (byte-array 32-bit-array) + (inline-vop (((byte-array sap-reg t) (vector-sap byte-array)) + ((32-bit-array sap-reg t) (vector-sap 32-bit-array)) + ((length any-reg) length) + ((32-bits complex-double-reg)) + ((bytes single-reg)) + ((cmp unsigned-reg)) + ((end))) + ((res descriptor-reg t :from :load)) + (load-symbol res t) + (inst cbz length DONE) + (inst add end byte-array (lsr length 1)) + LOOP + (inst ldr bytes (@ byte-array 4 :post-index)) + (inst ldr 32-bits (@ 32-bit-array 16 :post-index)) + (setf bytes (reg-in-sc bytes 'complex-double-reg)) + + (inst ushll bytes :8h bytes :8b 0) + (inst ushll bytes :4s bytes :4h 0) + + (inst cmeq bytes bytes 32-bits :4s) + (inst uminv bytes bytes :4s) + (inst umov cmp bytes 0 :s) + (inst cbz cmp FALSE) + (inst cmp byte-array end) + (inst b :lt LOOP) + (inst b DONE) + FALSE + (inst mov res null-tn) + DONE))) + +(defun simd-cmp-8-8 (a b length) + (declare (optimize speed (safety 0))) + (with-pinned-objects-in-registers (a b) + (inline-vop (((a-array sap-reg t) (vector-sap a)) + ((b-array sap-reg t) (vector-sap b)) + ((length any-reg) length) + ((a complex-double-reg)) + ((b)) + ((cmp unsigned-reg)) + ((end))) + ((res descriptor-reg t :from :load)) + (load-symbol res t) + (inst cbz length DONE) + (inst add end a-array (lsr length 1)) + LOOP + (inst ldr a (@ a-array 16 :post-index)) + (inst ldr b (@ b-array 16 :post-index)) + (inst cmeq a a b :16b) + (inst uminv a a :16b) + (inst umov cmp a 0 :b) + (inst cbz cmp FALSE) + (inst cmp a-array end) + (inst b :lt LOOP) + (inst b DONE) + FALSE + (inst mov res null-tn) + DONE))) + +(defun simd-cmp-32-32 (a b length) + (declare (optimize speed (safety 0))) + (with-pinned-objects-in-registers (a b) + (inline-vop (((a-array sap-reg t) (vector-sap a)) + ((b-array sap-reg t) (vector-sap b)) + ((length any-reg) length) + ((a complex-double-reg)) + ((b)) + ((cmp unsigned-reg)) + ((end))) + ((res descriptor-reg t :from :load)) + (load-symbol res t) + (inst cbz length DONE) + (inst add end a-array (lsl length 1)) + LOOP + (inst ldr a (@ a-array 16 :post-index)) + (inst ldr b (@ b-array 16 :post-index)) + (inst cmeq a a b :4s) + (inst uminv a a :4s) + (inst umov cmp a 0 :s) + (inst cbz cmp FALSE) + (inst cmp a-array end) + (inst b :lt LOOP) + (inst b DONE) + FALSE + (inst mov res null-tn) + DONE))) + +(defun simd-base-string-equal (a b length) + (declare (simple-base-string a b) + (optimize speed (safety 0))) + (with-pinned-objects-in-registers (a b) + (inline-vop (((a-array sap-reg t) (vector-sap a)) + ((b-array sap-reg t) (vector-sap b)) + ((length any-reg) length) + ((a complex-double-reg)) + ((b)) + ((cmp unsigned-reg)) + ((end)) + ((a-mask complex-double-reg complex-double-float)) + ((z-mask)) + ((flip)) + ((temp)) + ((temp2))) + ((res descriptor-reg t :from :load)) + (load-symbol res t) + (inst cbz length DONE) + (inst add end a-array (lsr length 1)) + (inst movi a-mask (char-code #\a) :16b) + (inst movi z-mask 25 :16b) + (inst movi flip #x20 :16b) + LOOP + (inst ldr a (@ a-array 16 :post-index)) + (inst ldr b (@ b-array 16 :post-index)) + + ;; Upcase a + (inst s-sub temp a a-mask) + (inst cmhs temp z-mask temp) + (inst s-and temp temp flip) + (inst s-eor a a temp) + + ;; Upcase b + (inst s-sub temp2 b a-mask) + (inst cmhs temp2 z-mask temp2) + (inst s-and temp2 temp2 flip) + (inst s-eor b b temp2) + + (inst cmeq a a b) + (inst uminv a a :16b) + (inst umov cmp a 0 :b) + (inst cbz cmp FALSE) + + (inst cmp a-array end) + (inst b :lt LOOP) + (inst b DONE) + FALSE + (inst mov res null-tn) + DONE))) + +#+sb-unicode +(defun simd-base-character-string-equal (base-string character-string length) + (declare (optimize speed (safety 0))) + (with-pinned-objects-in-registers (base-string character-string) + (inline-vop (((base-string sap-reg t) (vector-sap base-string)) + ((character-string sap-reg t) (vector-sap character-string)) + ((length any-reg) length) + ((characters complex-double-reg)) + ((base-chars single-reg)) + ((cmp unsigned-reg)) + ((end)) + ((a-mask complex-double-reg complex-double-float)) + ((z-mask)) + ((flip)) + ((temp)) + ((temp2))) + ((res descriptor-reg t :from :load)) + (load-symbol res t) + (inst cbz length DONE) + (inst add end base-string (lsr length 1)) + (inst movi a-mask (char-code #\a) :4s) + (inst movi z-mask 25 :4s) + (inst movi flip #x20 :4s) + LOOP + (inst ldr base-chars (@ base-string 4 :post-index)) + (inst ldr characters (@ character-string 16 :post-index)) + (setf base-chars (reg-in-sc base-chars 'complex-double-reg)) + + ;; Upcase 32-bit wide characters + (inst s-sub temp characters a-mask :4s) + (inst cmhs temp z-mask temp :4s) + (inst s-and temp temp flip) + (inst s-eor characters characters temp) + + ;; Widen 8-bit wide characters to 32-bits + (inst ushll base-chars :8h base-chars :8b 0) + (inst ushll base-chars :4s base-chars :4h 0) + + ;; And upcase them too + (inst s-sub temp2 base-chars a-mask :4s) + (inst cmhs temp2 z-mask temp2 :4s) + (inst s-and temp2 temp2 flip) + (inst s-eor base-chars base-chars temp2) + + (inst cmeq base-chars base-chars characters :4s) + (inst uminv base-chars base-chars :4s) + (inst umov cmp base-chars 0 :s) + (inst cbz cmp FALSE) + + (inst cmp base-string end) + (inst b :lt LOOP) + (inst b DONE) + FALSE + (inst mov res null-tn) + DONE))) diff --git a/src/code/arm64-vm.lisp b/src/code/arm64-vm.lisp index a4fce06456..a1b2f9f0d7 100644 --- a/src/code/arm64-vm.lisp +++ b/src/code/arm64-vm.lisp @@ -2,39 +2,18 @@ ;;; (in-package "SB-VM") -#-sb-xc-host (defun machine-type () "Return a string describing the type of the local machine." "ARM64") - -;;;; FIXUP-CODE-OBJECT - -(defconstant-eqx +fixup-kinds+ #(:absolute :cond-branch :uncond-branch) - #'equalp) -(!with-bigvec-or-sap -(defun fixup-code-object (code offset fixup kind flavor) - (declare (type index offset)) - (declare (ignore flavor)) - (unless (zerop (rem offset sb-assem:+inst-alignment-bytes+)) - (error "Unaligned instruction? offset=#x~X." offset)) - (let ((sap (code-instructions code))) - (ecase kind - (:absolute - (setf (sap-ref-word sap offset) fixup)) - (:cond-branch - (setf (ldb (byte 19 5) (sap-ref-32 sap offset)) - (ash (- fixup (+ (sap-int sap) offset)) -2))) - (:uncond-branch - (setf (ldb (byte 26 0) (sap-ref-32 sap offset)) - (ash (- fixup (+ (sap-int sap) offset)) -2))))) - nil)) - + +(defun return-machine-address (scp) + (context-register scp lr-offset)) + ;;;; "Sigcontext" access functions, cut & pasted from sparc-vm.lisp, ;;;; then modified for ARM. ;;;; ;;;; See also x86-vm for commentary on signed vs unsigned. -#-sb-xc-host (progn (define-alien-routine ("os_context_float_register_addr" context-float-register-addr) (* unsigned) (context (* os-context-t)) (index int)) @@ -74,33 +53,104 @@ ;;; Given a (POSIX) signal context, extract the internal error ;;; arguments from the instruction stream. +;;; +;;; See EMIT-ERROR-BREAK for the scheme (defun internal-error-args (context) (declare (type (alien (* os-context-t)) context)) (let* ((pc (context-pc context)) (instruction (sap-ref-32 pc 0)) - (error-number (ldb (byte 8 13) instruction)) - (trap-number (ldb (byte 8 5) instruction))) + (trap-number (ldb (byte 8 5) instruction)) + (error-number (cond + ((>= trap-number sb-vm:error-trap) + (prog1 + (- trap-number sb-vm:error-trap) + (setf trap-number sb-vm:error-trap))) + (t + (prog1 (sap-ref-8 pc 4) + (setf pc (sap+ pc 1)))))) + (first-arg (ldb (byte 8 13) instruction)) + (first-offset (ldb (byte 5 0) first-arg)) + (first-sc (ldb (byte 2 5) first-arg))) (declare (type system-area-pointer pc)) (if (= trap-number invalid-arg-count-trap) - (values error-number '(#.arg-count-sc) trap-number) - (sb-kernel::decode-internal-error-args (sap+ pc 4) trap-number error-number)))) -) ; end PROGN + (values #.(error-number-or-lose 'invalid-arg-count-error) + '(#.arg-count-sc) + trap-number) + (let ((length (sb-kernel::error-length error-number))) + (declare (type (unsigned-byte 8) length)) + (unless (or (= first-arg zr-offset) + (zerop length)) + (decf length)) + (setf pc (sap+ pc 4)) + (let ((args (loop with index = 0 + repeat length + collect (sb-c:sap-read-var-integerf pc index)))) + (values error-number + (if (= first-offset zr-offset) + args + (cons (make-sc+offset (case first-sc + (1 sb-vm:unsigned-reg-sc-number) + (2 sb-vm:signed-reg-sc-number) + (t sb-vm:descriptor-reg-sc-number)) + first-offset) + args)) + trap-number)))))) ;;; Undo the effects of XEP-ALLOCATE-FRAME ;;; and point PC to FUNCTION -#-sb-xc-host (defun context-call-function (context function &optional arg-count) (with-pinned-objects (function) (with-pinned-context-code-object (context) (let* ((fun-addr (get-lisp-obj-address function)) - (entry (+ (sap-ref-word (int-sap fun-addr) - (- (ash simple-fun-self-slot word-shift) - fun-pointer-lowtag)) - (- (ash simple-fun-insts-offset word-shift) - fun-pointer-lowtag)))) + (entry (sap-ref-word (int-sap fun-addr) + (- (ash simple-fun-self-slot word-shift) + fun-pointer-lowtag)))) (when arg-count (setf (context-register context nargs-offset) (get-lisp-obj-address arg-count))) - (setf (context-register context lexenv-offset) fun-addr - (context-register context lr-offset) entry) + (setf (context-register context lexenv-offset) fun-addr) (set-context-pc context entry))))) + +#+darwin-jit +(progn + (define-alien-routine jit-patch + void + (address unsigned) + (value unsigned)) + + (define-alien-routine jit-patch-code + void + (code unsigned) + (value unsigned) + (index unsigned)) + + (define-alien-routine jit-memcpy + void + (dst (* char)) + (src (* char)) + (char signed)) + + (define-alien-routine jit-copy-code-constants + void + (dst unsigned) + (src unsigned)) + + (defun (setf sap-ref-word-jit) (value sap offset) + (jit-patch (+ (sap-int sap) offset) value)) + + (defun (setf code-header-ref) (value code index) + (with-pinned-objects (code value) + (jit-patch-code (get-lisp-obj-address code) + (get-lisp-obj-address value) + index)) + value)) + +(defconstant n-bit 31) +(defconstant z-bit 30) +(defconstant c-bit 29) +(defconstant v-bit 28) + +(defun context-overflow-carry-flags (context) + (let ((flags (context-flags context))) + (values (logbitp v-bit flags) + (logbitp c-bit flags)))) diff --git a/src/code/array.lisp b/src/code/array.lisp index faf6dfb674..f4b56ea573 100644 --- a/src/code/array.lisp +++ b/src/code/array.lisp @@ -11,7 +11,6 @@ (in-package "SB-VM") -#-sb-fluid (declaim (inline adjustable-array-p array-displacement)) @@ -26,25 +25,18 @@ (defun (setf ,name) (value array) (setf (,name array) value))))) (def %array-fill-pointer) - (def %array-fill-pointer-p) (def %array-available-elements) (def %array-data) (def %array-displacement) (def %array-displaced-p) (def %array-displaced-from)) -;;; For compatibility: DO NOT USE IN NEW CODE. -(defun %array-data-vector (array) (%array-data array)) - (defun %array-rank (array) (%array-rank array)) (defun %array-dimension (array axis) (%array-dimension array axis)) -(defun %set-array-dimension (array axis value) - (%set-array-dimension array axis value)) - (defun %check-bound (array bound index) (declare (type index bound) (fixnum index)) @@ -349,15 +341,6 @@ #.complex-vector-widetag)))) (make-case))) -(define-load-time-global %%simple-array-n-bits-shifts%% - (make-array (1+ widetag-mask))) -#.(loop for info across *specialized-array-element-type-properties* - collect `(setf (aref %%simple-array-n-bits-shifts%% ,(saetp-typecode info)) - ,(saetp-n-bits-shift info)) into forms - finally (return `(progn ,@forms))) - -(declaim (type (simple-vector #.(1+ widetag-mask)) %%simple-array-n-bits-shifts%%)) - (declaim (inline vector-length-in-words)) (defun vector-length-in-words (length n-bits-shift) (declare (type (integer 0 7) n-bits-shift)) @@ -366,173 +349,226 @@ (1- (integer-length n-word-bits))))) (ash (+ length mask) shift))) -;;; N-BITS-SHIFT is the shift amount needed to turn LENGTH into bits -;;; or NIL, %%simple-array-n-bits-shifts%% will be used in that case. -(defun allocate-vector-with-widetag (widetag length n-bits-shift) +;;; N-BITS-SHIFT is the shift amount needed to turn LENGTH into array-size-in-bits, +;;; i.e. log(2,bits-per-elt) +(defun allocate-vector-with-widetag (#+ubsan poisoned widetag length n-bits-shift) (declare (type (unsigned-byte 8) widetag) (type index length)) - (let* ((n-bits-shift (or n-bits-shift - (aref %%simple-array-n-bits-shifts%% widetag))) - (full-length (if (or (= widetag simple-base-string-widetag) - #+sb-unicode - (= widetag - simple-character-string-widetag)) - (1+ length) - length))) - ;; Be careful not to allocate backing storage for element type NIL. - ;; Both it and type BIT have N-BITS-SHIFT = 0, so the determination - ;; of true size can't be left up to VECTOR-LENGTH-IN-WORDS. - (allocate-vector widetag length - (if (/= widetag simple-array-nil-widetag) - (vector-length-in-words full-length n-bits-shift) - 0)))) - + (let* ( ;; KLUDGE: add SAETP-N-PAD-ELEMENTS "by hand" since there is + ;; but a single case involving it now. + (full-length (+ length (if (= widetag simple-base-string-widetag) 1 0))) + ;; Be careful not to allocate backing storage for element type NIL. + ;; Both it and type BIT have N-BITS-SHIFT = 0, so the determination + ;; of true size can't be left up to VECTOR-LENGTH-IN-WORDS. + ;; VECTOR-LENGTH-IN-WORDS potentially returns a machine-word-sized + ;; integer, so it doesn't match the primitive type restriction of + ;; POSITIVE-FIXNUM for the last argument of the vector alloc vops. + (nwords (the fixnum + (if (/= widetag simple-array-nil-widetag) + (vector-length-in-words full-length n-bits-shift) + 0)))) + #+ubsan (if poisoned ; first arg to allocate-vector must be a constant + (allocate-vector t widetag length nwords) + (allocate-vector nil widetag length nwords)) + #-ubsan (allocate-vector widetag length nwords))) + +(declaim (ftype (sfunction (array) (integer 128 255)) array-underlying-widetag)) (defun array-underlying-widetag (array) - (macrolet ((make-case () - `(case widetag - ,@(loop for saetp across *specialized-array-element-type-properties* - for complex = (saetp-complex-typecode saetp) - when complex - collect (list complex (saetp-typecode saetp))) - ((,simple-array-widetag - ,complex-vector-widetag - ,complex-array-widetag) - (with-array-data ((array array) (start) (end)) - (declare (ignore start end)) - (%other-pointer-widetag array))) - (t - widetag)))) - (let ((widetag (%other-pointer-widetag array))) - (make-case)))) - -(defun sb-impl::make-vector-like (vector length) - (allocate-vector-with-widetag (array-underlying-widetag vector) length nil)) - -;; Complain in various ways about wrong :INITIAL-foo arguments, + (macrolet ((generate-table () + (macrolet ((to-index (x) `(ash ,x -2))) + (let ((table (sb-xc:make-array 64 :initial-element 0 + :element-type '(unsigned-byte 8)))) + (dovector (saetp *specialized-array-element-type-properties*) + (let* ((typecode (saetp-typecode saetp)) + (complex-typecode (saetp-complex-typecode saetp))) + (setf (aref table (to-index typecode)) typecode) + (when complex-typecode + (setf (aref table (to-index complex-typecode)) typecode)))) + (setf (aref table (to-index simple-array-widetag)) 0 + (aref table (to-index complex-vector-widetag)) 0 + (aref table (to-index complex-array-widetag)) 0) + table))) + (to-index (x) `(ash ,x -2))) + (named-let recurse ((x array)) + (let ((result (aref (generate-table) + (to-index (%other-pointer-widetag x))))) + (if (= 0 result) + (recurse (%array-data x)) + (truly-the (integer 128 255) result)))))) + +;; Complain in various ways about wrong MAKE-ARRAY and ADJUST-ARRAY arguments, ;; returning the two initialization arguments needed for DATA-VECTOR-FROM-INITS. -(defun validate-array-initargs (element-p element contents-p contents displaced) - (cond ((and displaced (or element-p contents-p)) - (if (and element-p contents-p) - (error "Neither :INITIAL-ELEMENT nor :INITIAL-CONTENTS ~ - may be specified with the :DISPLACED-TO option") - (error "~S may not be specified with the :DISPLACED-TO option" - (if element-p :initial-element :initial-contents)))) - ((and element-p contents-p) - (error "Can't specify both :INITIAL-ELEMENT and :INITIAL-CONTENTS")) - (element-p (values :initial-element element)) - (contents-p (values :initial-contents contents)) - (t (values nil nil)))) - -(declaim (inline %save-displaced-array-backpointer)) +;; This is an unhygienic macro which would be a MACROLET other than for +;; doing so would entail moving toplevel defuns around for no good reason. +(defmacro check-make-array-initargs (displaceable &optional element-type size) + `(cond ,@(when displaceable + `((displaced-to + (when (or element-p contents-p) + (if (and element-p contents-p) + (error "Neither :INITIAL-ELEMENT nor :INITIAL-CONTENTS ~ + may be specified with the :DISPLACED-TO option") + (error "~S may not be specified with the :DISPLACED-TO option" + (if element-p :initial-element :initial-contents)))) + (unless (= (array-underlying-widetag displaced-to) widetag) + ;; Require exact match on upgraded type (lp#1331299) + (error "Can't displace an array of type ~/sb-impl:print-type-specifier/ ~ + into another of type ~/sb-impl:print-type-specifier/" + ,element-type (array-element-type displaced-to))) + (when (< (array-total-size displaced-to) + (+ displaced-index-offset ,size)) + (error "The :DISPLACED-TO array is too small."))) + (offset-p + (error "Can't specify :DISPLACED-INDEX-OFFSET without :DISPLACED-TO")))) + ((and element-p contents-p) + (error "Can't specify both :INITIAL-ELEMENT and :INITIAL-CONTENTS")) + (element-p (values :initial-element initial-element)) + (contents-p (values :initial-contents initial-contents)))) +(defmacro make-array-bad-fill-pointer (actual max adjective) + ;; There was a comment implying that this should be TYPE-ERROR + ;; but I don't see that as a spec requirement. + `(error "Can't supply a value for :FILL-POINTER (~S) that is larger ~ + than the~A size of the vector (~S)" ,actual ,adjective ,max)) + +(declaim (inline %save-displaced-array-backpointer + %save-displaced-new-array-backpointer)) (defun %save-displaced-array-backpointer (array data) (flet ((purge (pointers) (remove-if (lambda (value) (or (not value) (eq array value))) pointers :key #'weak-pointer-value))) - ;; Add backpointer to the new data vector if it has a header. + (let ((old-data (%array-data array))) + (unless (eq old-data data) + ;; Add backpointer to the new data vector if it has a header. + (when (array-header-p data) + (setf (%array-displaced-from data) + (cons (make-weak-pointer array) + (purge (%array-displaced-from data))))) + ;; Remove old backpointer, if any. + (when (array-header-p old-data) + (setf (%array-displaced-from old-data) + (purge (%array-displaced-from old-data)))))))) + +(defun %save-displaced-new-array-backpointer (array data) + (flet ((purge (pointers) + (remove-if-not #'weak-pointer-value pointers))) (when (array-header-p data) (setf (%array-displaced-from data) (cons (make-weak-pointer array) - (purge (%array-displaced-from data))))) - ;; Remove old backpointer, if any. - (let ((old-data (%array-data array))) - (when (and (neq data old-data) (array-header-p old-data)) - (setf (%array-displaced-from old-data) - (purge (%array-displaced-from old-data))))))) + (purge (%array-displaced-from data))))))) + +(defmacro populate-dimensions (header list-or-index rank) + `(if (listp ,list-or-index) + (let ((dims ,list-or-index)) + (dotimes (axis ,rank) + (declare ((integer 0 ,array-rank-limit) axis)) + (%set-array-dimension ,header axis (pop dims)))) + (%set-array-dimension ,header 0 ,list-or-index))) + +(declaim (inline rank-and-total-size-from-dims)) +(defun rank-and-total-size-from-dims (dims) + (cond ((not (listp dims)) (values 1 (the index dims))) + ((not dims) (values 0 1)) + (t (let ((rank 1) (product (car dims))) + (declare (array-rank rank) (index product)) + (dolist (dim (cdr dims) (values rank product)) + (setq product (* product (the index dim))) + (incf rank)))))) + +(declaim (inline widetag->element-type)) +(defun widetag->element-type (widetag) + (svref #.(let ((a (make-array 32 :initial-element 0))) + (dovector (saetp *specialized-array-element-type-properties* a) + (let ((tag (saetp-typecode saetp))) + (setf (aref a (ash (- tag #x80) -2)) (saetp-specifier saetp))))) + (- (ash widetag -2) 32))) + +(defun initial-contents-error (content-length length) + (error "There are ~W elements in the :INITIAL-CONTENTS, but ~ + the vector length is ~W." + content-length length)) ;;; Widetag is the widetag of the underlying vector, ;;; it'll be the same as the resulting array widetag only for simple vectors (defun %make-array (dimensions widetag n-bits &key element-type - (initial-element nil initial-element-p) - (initial-contents nil initial-contents-p) + (initial-element nil element-p) + (initial-contents nil contents-p) adjustable fill-pointer - displaced-to displaced-index-offset) + displaced-to + (displaced-index-offset 0 offset-p)) (declare (ignore element-type)) - (binding* (((array-rank dimension-0) - (if (listp dimensions) - (values (length dimensions) - (if dimensions (car dimensions) 1)) - (values 1 dimensions))) + (binding* (((array-rank total-size) (rank-and-total-size-from-dims dimensions)) ((initialize initial-data) - (validate-array-initargs initial-element-p initial-element - initial-contents-p initial-contents - displaced-to)) + ;; element-type might not be supplied, but widetag->element is always good + (check-make-array-initargs t (widetag->element-type widetag) total-size)) (simple (and (null fill-pointer) (not adjustable) (null displaced-to)))) - (declare (type array-rank array-rank)) - (declare (type index dimension-0)) - (cond ((and displaced-index-offset (null displaced-to)) - (error "Can't specify :DISPLACED-INDEX-OFFSET without :DISPLACED-TO")) - ((and simple (= array-rank 1)) + + (cond ((and simple (= array-rank 1)) (let ((vector ; a (SIMPLE-ARRAY * (*)) - (allocate-vector-with-widetag widetag dimension-0 n-bits))) + (allocate-vector-with-widetag #+ubsan (not (or element-p contents-p)) + widetag total-size n-bits))) ;; presence of at most one :INITIAL-thing keyword was ensured above - (cond (initial-element-p + (cond (element-p (fill vector initial-element)) - (initial-contents-p + (contents-p (let ((content-length (length initial-contents))) - (unless (= dimension-0 content-length) - (error "There are ~W elements in the :INITIAL-CONTENTS, but ~ - the vector length is ~W." - content-length dimension-0))) - (replace vector initial-contents))) + (unless (= total-size content-length) + (initial-contents-error content-length total-size))) + (replace vector initial-contents)) + #+ubsan + (t + ;; store the function which bears responsibility for creation of this + ;; array in case we need to blame it for not initializing. + (set-vector-extra-data (if (= widetag simple-vector-widetag) ; no shadow bits. + vector ; use the LENGTH slot directly + (vector-extra-data vector)) + (ash (sap-ref-word (current-fp) n-word-bytes) 3)) ; XXX: magic + (cond ((= widetag simple-vector-widetag) + (fill vector (%make-lisp-obj unwritten-vector-element-marker))) + ((array-may-contain-random-bits-p widetag) + ;; Leave the last word alone for base-string, + ;; in case the mandatory trailing null is part of a data word. + (dotimes (i (- (vector-length-in-words total-size n-bits) + (if (= widetag simple-base-string-widetag) 1 0))) + (setf (%vector-raw-bits vector i) sb-ext:most-positive-word)))))) vector)) - ((and (arrayp displaced-to) - (/= (array-underlying-widetag displaced-to) widetag)) - (error "Array element type of :DISPLACED-TO array does not match specified element type")) (t ;; it's non-simple or multidimensional, or both. (when fill-pointer (unless (= array-rank 1) (error "Only vectors can have fill pointers.")) - (when (and (integerp fill-pointer) (> fill-pointer dimension-0)) - ;; FIXME: should be TYPE-ERROR? - (error "invalid fill-pointer ~W" fill-pointer))) - (let* ((total-size - (if (consp dimensions) - (the index (reduce (lambda (a b) (* a (the index b))) - dimensions)) - ;; () is considered to have dimension-0 = 1. - ;; It avoids the REDUCE lambda being called with no args. - dimension-0)) - (data (or displaced-to - (data-vector-from-inits - dimensions total-size nil widetag n-bits - initialize initial-data))) + (when (and (integerp fill-pointer) (> fill-pointer total-size)) + (make-array-bad-fill-pointer fill-pointer total-size ""))) + (let* ((data (or displaced-to + (data-vector-from-inits dimensions total-size widetag n-bits + initialize initial-data))) (array (make-array-header (cond ((= array-rank 1) (%complex-vector-widetag widetag)) (simple simple-array-widetag) (t complex-array-widetag)) array-rank))) - (if fill-pointer - (setf (%array-fill-pointer-p array) t - (%array-fill-pointer array) - (if (eq fill-pointer t) dimension-0 fill-pointer)) - (setf (%array-fill-pointer-p array) nil - (%array-fill-pointer array) total-size)) + (cond (fill-pointer + (logior-array-flags array +array-fill-pointer-p+) + (setf (%array-fill-pointer array) + (if (eq fill-pointer t) total-size fill-pointer))) + (t + (reset-array-flags array +array-fill-pointer-p+) + (setf (%array-fill-pointer array) total-size))) (setf (%array-available-elements array) total-size) (setf (%array-data array) data) (setf (%array-displaced-from array) nil) (cond (displaced-to - (let ((offset (or displaced-index-offset 0))) - (when (> (+ offset total-size) - (array-total-size displaced-to)) - (error "~S doesn't have enough elements." displaced-to)) - (setf (%array-displacement array) offset) - (setf (%array-displaced-p array) t) - (%save-displaced-array-backpointer array data))) + (setf (%array-displacement array) (or displaced-index-offset 0)) + (setf (%array-displaced-p array) t) + (%save-displaced-new-array-backpointer array data)) (t (setf (%array-displaced-p array) nil))) - (if (listp dimensions) - (let ((dims dimensions)) ; avoid "prevents use of assertion" - (dotimes (axis array-rank) - (setf (%array-dimension array axis) (pop dims)))) - (setf (%array-dimension array 0) dimension-0)) + (populate-dimensions array dimensions array-rank) array))))) (defun make-array (dimensions &rest args @@ -551,8 +587,8 @@ (defun make-static-vector (length &key (element-type '(unsigned-byte 8)) - (initial-contents nil initial-contents-p) - (initial-element nil initial-element-p)) + (initial-contents nil contents-p) + (initial-element nil element-p)) "Allocate vector of LENGTH elements in static space. Only allocation of specialized arrays is supported." ;; STEP 1: check inputs fully @@ -563,9 +599,8 @@ of specialized arrays is supported." (when (eq t (upgraded-array-element-type element-type)) (error "Static arrays of type ~/sb-impl:print-type-specifier/ not supported." element-type)) - (validate-array-initargs initial-element-p initial-element - initial-contents-p initial-contents nil) ; for effect - (when initial-contents-p + (check-make-array-initargs nil) ; for effect + (when contents-p (unless (= length (length initial-contents)) (error "There are ~W elements in the :INITIAL-CONTENTS, but the ~ vector length is ~W." @@ -575,7 +610,7 @@ of specialized arrays is supported." (error ":INITIAL-CONTENTS contains elements not of type ~ ~/sb-impl:print-type-specifier/." element-type))) - (when initial-element-p + (when element-p (unless (typep initial-element element-type) (error ":INITIAL-ELEMENT ~S is not of type ~ ~/sb-impl:print-type-specifier/." @@ -586,38 +621,38 @@ of specialized arrays is supported." (multiple-value-bind (type n-bits-shift) (%vector-widetag-and-n-bits-shift element-type) (let* ((full-length - (if (or (= type simple-base-string-widetag) - #+sb-unicode - (= type - simple-character-string-widetag)) - (1+ length) - length)) + ;; KLUDGE: add SAETP-N-PAD-ELEMENTS "by hand" since there is + ;; but a single case involving it now. + (+ length (if (= type simple-base-string-widetag) 1 0))) (vector (allocate-static-vector type length (vector-length-in-words full-length n-bits-shift)))) - (cond (initial-element-p + (cond (element-p (fill vector initial-element)) - (initial-contents-p + (contents-p (replace vector initial-contents)) (t vector))))) -;;; DATA-VECTOR-FROM-INITS returns a simple vector that has the +#+darwin-jit +(defun make-static-code-vector (length initial-contents) + "Allocate vector of LENGTH elements in static space. Only allocation +of specialized arrays is supported." + (let ((vector (allocate-static-code-vector simple-array-unsigned-byte-8-widetag + length + (* length n-word-bytes)))) + (with-pinned-objects (initial-contents) + (jit-memcpy (vector-sap vector) (vector-sap initial-contents) length)) + vector)) + +;;; DATA-VECTOR-FROM-INITS returns a simple rank-1 array that has the ;;; specified array characteristics. Dimensions is only used to pass ;;; to FILL-DATA-VECTOR for error checking on the structure of ;;; initial-contents. -(defun data-vector-from-inits (dimensions total-size - element-type widetag n-bits - initialize initial-data) - ;; FIXME: element-type can be NIL when widetag is non-nil, - ;; and FILL will check the type, although the error will be not as nice. - ;; (cond (typep initial-element element-type) - ;; (error "~S cannot be used to initialize an array of type ~S." - ;; initial-element element-type)) - (let ((data (if widetag - (allocate-vector-with-widetag widetag total-size n-bits) - (make-array total-size :element-type element-type)))) +(defun data-vector-from-inits (dimensions total-size widetag n-bits initialize initial-data) + (declare (fixnum widetag n-bits)) ; really just that they're non-nil + (let ((data (allocate-vector-with-widetag #+ubsan (not initialize) widetag total-size n-bits))) (ecase initialize (:initial-element (fill (the vector data) initial-data)) @@ -705,7 +740,7 @@ of specialized arrays is supported." (tagbody ,@forms)))))))) (macrolet ((%ref (accessor-getter extra-params) - `(funcall (,accessor-getter array) array index ,@extra-params)) + `(sb-c::%funcall-no-nargs (,accessor-getter array) array index ,@extra-params)) (define (accessor-name slow-accessor-name accessor-getter extra-params check-bounds) `(progn @@ -721,7 +756,8 @@ of specialized arrays is supported." (safety 0))) (%ref ,accessor-getter ,extra-params)) (defun ,slow-accessor-name (array index ,@extra-params) - (declare (optimize speed (safety 0))) + (declare (optimize speed (safety 0)) + (array array)) (if (not (%array-displaced-p array)) ;; The reasonably quick path of non-displaced complex ;; arrays. @@ -729,14 +765,14 @@ of specialized arrays is supported." (%ref ,accessor-getter ,extra-params)) ;; The real slow path. (with-array-data - ((vector array) + ((array array) (index (locally (declare (optimize (speed 1) (safety 1))) (,@check-bounds index))) (end) :force-inline t) (declare (ignore end)) - (,accessor-name vector index ,@extra-params))))))) + (%ref ,accessor-getter ,extra-params))))))) (define hairy-data-vector-ref slow-hairy-data-vector-ref %find-data-vector-reffer nil (progn)) @@ -753,7 +789,8 @@ of specialized arrays is supported." (new-value) (check-bound array (%array-dimension array 0)))) (defun hairy-ref-error (array index &optional new-value) - (declare (ignore index new-value)) + (declare (ignore index new-value) + (optimize (sb-c:verify-arg-count 0))) (error 'type-error :datum array :expected-type 'vector)) @@ -769,9 +806,9 @@ of specialized arrays is supported." (ignorable index)) ,(if type `(data-vector-ref (the ,atype vector) - (locally - (declare (optimize (safety 1))) - (the index + (the index + (locally + (declare (optimize (safety 1))) (,@check-form index)))) `(data-nil-vector-ref (the ,atype vector) index))))) (define-setter (saetp check-form) @@ -794,10 +831,7 @@ of specialized arrays is supported." (declare (optimize (speed 1) (safety 1))) (the* (,type :context :aref) new-value))) - ;; For specialized arrays, the return from - ;; data-vector-set would have to be reboxed to be a - ;; (Lisp) return value; instead, we use the - ;; already-boxed value as the return. + ;; Low-level setters return no value new-value))) (define-reffers (symbol deffer check-form slow-path) `(progn @@ -807,7 +841,6 @@ of specialized arrays is supported." (setf ,symbol (make-array (1+ widetag-mask) :initial-element #'hairy-ref-error)) ,@(loop for widetag in '(complex-vector-widetag - complex-vector-nil-widetag complex-bit-vector-widetag #+sb-unicode complex-character-string-widetag complex-base-string-widetag @@ -1003,39 +1036,21 @@ of specialized arrays is supported." ;;;; miscellaneous array properties +(define-load-time-global *saetp-widetag-ctype* (make-array 32 :initial-element (make-unbound-marker))) + +(defun array-element-ctype (array) + ;; same as (SPECIFIER-TYPE (ARRAY-ELEMENT-TYPE ARRAY)) but more efficient + (svref *saetp-widetag-ctype* + (- (ash (array-underlying-widetag array) -2) 32))) + (defun array-element-type (array) "Return the type of the elements of the array" - (let ((widetag (%other-pointer-widetag array)) - (table (load-time-value - (let ((table (make-array 256 :initial-element :invalid))) - (dotimes (i (length *specialized-array-element-type-properties*) table) - (let* ((saetp (aref *specialized-array-element-type-properties* i)) - (typecode (saetp-typecode saetp)) - (complex-typecode (saetp-complex-typecode saetp)) - (specifier (saetp-specifier saetp))) - (aver (typep specifier '(or list symbol))) - (setf (aref table typecode) specifier) - (when complex-typecode - (setf (aref table complex-typecode) specifier)))) - (setf (aref table simple-array-widetag) nil - (aref table complex-vector-widetag) nil - (aref table complex-array-widetag) nil) - table) - t))) - (let ((result (aref table widetag))) - (if result - (truly-the (or list symbol) result) - ;; (MAKE-ARRAY :ELEMENT-TYPE NIL) goes to this branch, but - ;; gets the right answer in the end - (with-array-data ((array array) (start) (end)) - (declare (ignore start end)) - (truly-the (or list symbol) (aref table (%other-pointer-widetag array)))))))) + (truly-the (or list symbol) + (widetag->element-type (array-underlying-widetag array)))) (defun array-rank (array) "Return the number of dimensions of ARRAY." - (if (array-header-p array) - (%array-rank array) - 1)) + (%array-rank array)) (defun array-dimension (array axis-number) "Return the length of dimension AXIS-NUMBER of ARRAY." @@ -1095,48 +1110,37 @@ of specialized arrays is supported." (setf (info :function :predicate-truth-constraint 'array-has-fill-pointer-p) '(and vector (not simple-array))) -(declaim (inline array-has-fill-pointer-p)) (defun array-has-fill-pointer-p (array) "Return T if the given ARRAY has a fill pointer, or NIL otherwise." - (declare (array array)) - (and (array-header-p array) (%array-fill-pointer-p array))) + (array-has-fill-pointer-p array)) + +(defun fill-pointer-error (vector) + (declare (optimize allow-non-returning-tail-call) + (optimize (sb-c::verify-arg-count 0))) + (error 'simple-type-error + :datum vector + :expected-type '(and vector (satisfies array-has-fill-pointer-p)) + :format-control "~S is not an array with a fill pointer." + :format-arguments (list vector))) -(defun fill-pointer-error (vector &optional arg) - (declare (optimize allow-non-returning-tail-call)) - (cond (arg - (aver (array-has-fill-pointer-p vector)) - (let ((max (%array-available-elements vector))) - (error 'simple-type-error - :datum arg - :expected-type (list 'integer 0 max) - :format-control "The new fill pointer, ~S, is larger than the length of the vector (~S.)" - :format-arguments (list arg max)))) - (t - (error 'simple-type-error - :datum vector - :expected-type '(and vector (satisfies array-has-fill-pointer-p)) - :format-control "~S is not an array with a fill pointer." - :format-arguments (list vector))))) -(declaim (inline fill-pointer)) (defun fill-pointer (vector) "Return the FILL-POINTER of the given VECTOR." (declare (explicit-check)) - (if (array-has-fill-pointer-p vector) - (%array-fill-pointer vector) - (fill-pointer-error vector))) + (fill-pointer vector)) (defun %set-fill-pointer (vector new) - (declare (explicit-check) - (index new)) - (flet ((oops (x) - (fill-pointer-error vector x))) - (cond ((not (array-has-fill-pointer-p vector)) - (oops nil)) - ((> new (%array-available-elements vector)) - (oops new)) - (t - (setf (%array-fill-pointer vector) new))))) + (declare (explicit-check)) + (cond ((not (array-has-fill-pointer-p vector)) (fill-pointer-error vector)) + ((> (the index new) (%array-available-elements vector)) + (let ((max (%array-available-elements vector))) + (error 'simple-type-error + :datum new + :expected-type (list 'integer 0 max) + :format-control "The new fill pointer, ~S, is larger than the length of the vector (~S.)" + :format-arguments (list new max)))) + (t + (setf (%array-fill-pointer vector) new)))) ;;; FIXME: It'd probably make sense to use a MACROLET to share the ;;; guts of VECTOR-PUSH between VECTOR-PUSH-EXTEND. Such a macro @@ -1158,41 +1162,13 @@ of specialized arrays is supported." (setf (%array-fill-pointer array) (1+ fill-pointer)) fill-pointer)))) -;;; Widetags of FROM and TO should be equal -(defun copy-vector-data (from to start end n-bits-shift) - (declare (vector from to) - (index start end) - ((integer 0 7) n-bits-shift)) - (let ((from-length (length from))) - (cond ((simple-vector-p from) - (replace (truly-the simple-vector to) - (truly-the simple-vector from) - :start2 start :end2 end)) - ;; Vector sizes are double-word aligned and have zeros in - ;; the extra word so it's safe to copy when the boundaries - ;; are matching the whole vector. - ;; A more generic routine is left for another time, even if - ;; only handling aligned data since it will avoid consing - ;; floats or word bignums. - ((and (= start 0) - (= end from-length)) - (loop for i below (vector-length-in-words from-length n-bits-shift) - do (setf - (%vector-raw-bits to i) - (%vector-raw-bits from i)))) - (t - (replace to - from - :start2 start :end2 end))) - to)) - (defun extend-vector (vector min-extension) (declare (optimize speed) (vector vector)) (let* ((old-length (length vector)) (min-extension (or min-extension (min old-length - (- sb-xc:array-dimension-limit old-length)))) + (- array-dimension-limit old-length)))) (new-length (the index (+ old-length (max 1 min-extension)))) (fill-pointer (1+ old-length))) @@ -1202,14 +1178,24 @@ of specialized arrays is supported." (let* ((widetag (%other-pointer-widetag old-data)) (n-bits-shift (aref %%simple-array-n-bits-shifts%% widetag)) (new-data - (allocate-vector-with-widetag widetag new-length n-bits-shift))) - (copy-vector-data old-data new-data old-start old-end n-bits-shift) + ;; FIXME: mark prefix of shadow bits assigned, suffix unassigned + (allocate-vector-with-widetag #+ubsan nil + widetag new-length n-bits-shift))) + ;; Copy the data + (if (= widetag simple-vector-widetag) ; the most common case + (replace (truly-the simple-vector new-data) ; transformed + (truly-the simple-vector old-data) + :start2 old-start :end2 old-end) + (let ((copier (blt-copier-for-widetag widetag))) + (if copier + (funcall (truly-the function copier) old-data old-start new-data 0 old-length) + (replace new-data old-data :start2 old-start :end2 old-end)))) (setf (%array-data vector) new-data (%array-available-elements vector) new-length (%array-fill-pointer vector) fill-pointer (%array-displacement vector) 0 - (%array-dimension vector 0) new-length (%array-displaced-p vector) nil) + (%set-array-dimension vector 0 new-length) vector)))) (defun vector-push-extend (new-element vector &optional min-extension) @@ -1243,210 +1229,198 @@ of specialized arrays is supported." (defun adjust-array (array dimensions &key (element-type (array-element-type array) element-type-p) - (initial-element nil initial-element-p) - (initial-contents nil initial-contents-p) + (initial-element nil element-p) + (initial-contents nil contents-p) fill-pointer - displaced-to displaced-index-offset) + displaced-to (displaced-index-offset 0 offset-p)) "Adjust ARRAY's dimensions to the given DIMENSIONS and stuff." (when (invalid-array-p array) (invalid-array-error array)) - (binding* ((dimensions-rank (if (listp dimensions) - (length dimensions) - 1)) - (array-rank (array-rank array)) - (() - (unless (= dimensions-rank array-rank) - (error "The number of dimensions not equal to rank of array."))) - ((initialize initial-data) - (validate-array-initargs initial-element-p initial-element - initial-contents-p initial-contents - displaced-to)) - (widetag (array-underlying-widetag array))) - (cond ((and element-type-p - (/= (%vector-widetag-and-n-bits-shift element-type) - widetag)) - (error "The new element type, ~ - ~/sb-impl:print-type-specifier/, is incompatible ~ - with old type, ~/sb-impl:print-type-specifier/." - element-type (array-element-type array))) - ((and fill-pointer (/= array-rank 1)) - (error "Only vectors can have fill pointers.")) - ((and fill-pointer (not (array-has-fill-pointer-p array))) - ;; This case always struck me as odd. It seems like it might mean - ;; that the user asks that the array gain a fill-pointer if it didn't - ;; have one, yet CLHS is clear that the argument array must have a - ;; fill-pointer or else signal a type-error. - (fill-pointer-error array))) - (cond (initial-contents-p - ;; array former contents replaced by INITIAL-CONTENTS - (let* ((array-size (if (listp dimensions) - (apply #'* dimensions) - dimensions)) - (array-data (data-vector-from-inits - dimensions array-size element-type nil nil - initialize initial-data))) - (cond ((adjustable-array-p array) - (set-array-header array array-data array-size - (get-new-fill-pointer array array-size - fill-pointer) - 0 dimensions nil nil)) - ((array-header-p array) - ;; simple multidimensional or single dimensional array - (%make-array dimensions widetag - (aref %%simple-array-n-bits-shifts%% widetag) - :initial-contents initial-contents)) - (t - array-data)))) - (displaced-to - ;; We already established that no INITIAL-CONTENTS was supplied. - (when (/= (array-underlying-widetag displaced-to) widetag) - ;; See lp#1331299 again. Require exact match on upgraded type? - (error "can't displace an array of type ~ - ~/sb-impl:print-type-specifier/ into another ~ - of type ~/sb-impl:print-type-specifier/" - element-type (array-element-type displaced-to))) - (let ((displacement (or displaced-index-offset 0)) - (array-size (if (listp dimensions) - (apply #'* dimensions) - dimensions))) - (declare (fixnum displacement array-size)) - (if (< (the fixnum (array-total-size displaced-to)) - (the fixnum (+ displacement array-size))) - (error "The :DISPLACED-TO array is too small.")) - (if (adjustable-array-p array) - ;; None of the original contents appear in adjusted array. - (set-array-header array displaced-to array-size - (get-new-fill-pointer array array-size - fill-pointer) - displacement dimensions t nil) - ;; simple multidimensional or single dimensional array - (%make-array dimensions widetag - (aref %%simple-array-n-bits-shifts%% widetag) - :displaced-to displaced-to - :displaced-index-offset - displaced-index-offset)))) - ((= array-rank 1) - (let ((old-length (array-total-size array)) - (new-length (if (listp dimensions) - (car dimensions) - dimensions)) - new-data) - (declare (fixnum old-length new-length)) - (with-array-data ((old-data array) (old-start) - (old-end old-length)) - (cond ((or (and (array-header-p array) - (%array-displaced-p array)) - (< old-length new-length)) - (setf new-data - (data-vector-from-inits - dimensions new-length element-type - (%other-pointer-widetag old-data) nil - initialize initial-data)) - ;; Provide :END1 to avoid full call to LENGTH - ;; inside REPLACE. - (replace new-data old-data - :end1 new-length - :start2 old-start :end2 old-end)) - (t (setf new-data - (shrink-vector old-data new-length)))) - (if (adjustable-array-p array) - (set-array-header array new-data new-length - (get-new-fill-pointer array new-length - fill-pointer) - 0 dimensions nil nil) - new-data)))) - (t - (let ((old-length (%array-available-elements array)) - (new-length (apply #'* dimensions))) - (declare (fixnum old-length new-length)) - (with-array-data ((old-data array) (old-start) - (old-end old-length)) + (binding* + (((rank new-total-size) (rank-and-total-size-from-dims dimensions)) + (widetag + (let ((widetag (array-underlying-widetag array))) + (unless (= (array-rank array) rank) ; "drive-by" check of the rank + (error "Expected ~D new dimension~:P for array, but received ~D." + (array-rank array) rank)) + (if (or (not element-type-p) + ;; Quick pass if ELEMENT-TYPE is same as the element type based on widetag + (equal element-type (widetag->element-type widetag)) + (= (%vector-widetag-and-n-bits-shift element-type) widetag)) + widetag + (error "The new element type, ~/sb-impl:print-type-specifier/, is incompatible ~ + with old type, ~/sb-impl:print-type-specifier/." + element-type (array-element-type array))))) + (new-fill-pointer + (cond (fill-pointer + (unless (array-has-fill-pointer-p array) + (if (/= rank 1) + (error "Only vectors can have fill pointers.") + ;; I believe the sentence saying that this is an error pre-dates the removal + ;; of the restriction of calling ADJUST-ARRAY only on arrays that + ;; are actually adjustable. Making a new array should always work, + ;; so I think this may be a bug in the spec. + (fill-pointer-error array))) + (cond ((eq fill-pointer t) new-total-size) + ((<= fill-pointer new-total-size) fill-pointer) + (t (make-array-bad-fill-pointer fill-pointer new-total-size " new")))) + ((array-has-fill-pointer-p array) + ;; "consequences are unspecified if array is adjusted to a size smaller than its fill pointer" + (let ((old-fill-pointer (%array-fill-pointer array))) + (when (< new-total-size old-fill-pointer) + (error "can't adjust vector ~S to a size (~S) smaller than ~ + its current fill pointer (~S)" + array new-total-size old-fill-pointer)) + old-fill-pointer)))) + ((initialize initial-data) + (check-make-array-initargs t element-type new-total-size)) + (n-bits-shift (aref %%simple-array-n-bits-shifts%% widetag))) + + (cond + (displaced-to ; super easy - just repoint ARRAY to new data + (if (adjustable-array-p array) + (set-array-header array displaced-to new-total-size new-fill-pointer + displaced-index-offset dimensions t nil) + (%make-array dimensions widetag n-bits-shift + :displaced-to displaced-to + :displaced-index-offset displaced-index-offset))) + (contents-p ; array former contents replaced by INITIAL-CONTENTS + (let ((array-data (data-vector-from-inits dimensions new-total-size widetag n-bits-shift + initialize initial-data))) + (cond ((adjustable-array-p array) + (set-array-header array array-data new-total-size new-fill-pointer + 0 dimensions nil nil)) + ((array-header-p array) + ;; simple multidimensional array. + ;; fill-pointer vectors satisfy ADJUSTABLE-ARRAY-P (in SBCL, that is) + ;; and therefore are handled by the first stanza of the cond. + (%make-array dimensions widetag n-bits-shift + :initial-contents initial-contents)) + (t + array-data)))) + ((= rank 1) + (let ((old-length (array-total-size array))) + ;; Because ADJUST-ARRAY has to ignore any fill-pointer when + ;; copying from the old data, we can't just pass ARRAY as the + ;; second argument of REPLACE. + (with-array-data ((old-data array) (old-start) (old-end old-length)) + (let ((new-data + (if (and (= new-total-size old-length) + (not (and (array-header-p array) (%array-displaced-p array)))) + ;; if total size is unchanged, and it was not a displaced array, + ;; then this array owns the data and can retain it. + old-data + (let ((data (allocate-vector-with-widetag #+ubsan t + widetag new-total-size + n-bits-shift))) + (replace data old-data + :start1 0 :end1 new-total-size + :start2 old-start :end2 old-end) + (when (and element-p (> new-total-size old-length)) + (fill data initial-element :start old-length)) + data)))) + (if (adjustable-array-p array) + (set-array-header array new-data new-total-size new-fill-pointer + 0 dimensions nil nil) + new-data))))) + (t + (let ((old-total-size (%array-available-elements array))) + (with-array-data ((old-data array) (old-start) (old-end old-total-size)) (declare (ignore old-end)) (let ((new-data (if (or (and (array-header-p array) (%array-displaced-p array)) - (> new-length old-length) + (> new-total-size old-total-size) (not (adjustable-array-p array))) - (data-vector-from-inits - dimensions new-length - element-type - (%other-pointer-widetag old-data) nil - (if initial-element-p :initial-element) - initial-element) + (data-vector-from-inits dimensions new-total-size widetag + n-bits-shift initialize initial-data) old-data))) - (if (or (zerop old-length) (zerop new-length)) - (when initial-element-p (fill new-data initial-element)) + (if (or (zerop old-total-size) (zerop new-total-size)) + (when element-p (fill new-data initial-element)) (zap-array-data old-data (array-dimensions array) old-start - new-data dimensions new-length + new-data dimensions new-total-size element-type initial-element - initial-element-p)) + element-p)) (if (adjustable-array-p array) - (set-array-header array new-data new-length + (set-array-header array new-data new-total-size nil 0 dimensions nil nil) - (let ((new-array - (make-array-header - simple-array-widetag array-rank))) - (set-array-header new-array new-data new-length + (let ((new-array (make-array-header simple-array-widetag rank))) + (set-array-header new-array new-data new-total-size nil 0 dimensions nil t)))))))))) - -(defun get-new-fill-pointer (old-array new-array-size fill-pointer) - (declare (fixnum new-array-size)) - (typecase fill-pointer - (null - ;; "The consequences are unspecified if array is adjusted to a - ;; size smaller than its fill pointer ..." - (when (array-has-fill-pointer-p old-array) - (when (> (%array-fill-pointer old-array) new-array-size) - (error "cannot ADJUST-ARRAY an array (~S) to a size (~S) that is ~ - smaller than its fill pointer (~S)" - old-array new-array-size (fill-pointer old-array))) - (%array-fill-pointer old-array))) - ((eql t) - new-array-size) - (fixnum - (when (> fill-pointer new-array-size) - (error "can't supply a value for :FILL-POINTER (~S) that is larger ~ - than the new length of the vector (~S)" - fill-pointer new-array-size)) - fill-pointer))) - ;;; Destructively alter VECTOR, changing its length to NEW-LENGTH, ;;; which must be less than or equal to its current length. This can -;;; be called on vectors without a fill pointer but it is extremely -;;; dangerous to do so: shrinking the size of an object (as viewed by -;;; the gc) makes bounds checking unreliable in the face of interrupts -;;; or multi-threading. Call it only on provably local vectors. -(defun %shrink-vector (vector new-length) +;;; be called on vectors without a fill pointer but it is slightly +;;; dangerous to do so: shrinking the size of an object accessible +;;; to another thread could cause it to access an out-of-bounds element. +;;; GC should generally be fine no matter what happens, because it either +;;; reads the old length or the new length. If it reads the old length, +;;; then the whole vector is skipped if unboxed; if it reads the new length, +;;; then the next object is a filler. +;;; Exception: for SIMPLE-VECTOR we always zeroized the unused tail, +;;; because the garbage collector can scan certain pages without regard +;;; to object boundaries. The situation we need to avoid is this: +;;; "old" #(...............|.....) +;;; "new" #(..........)Fill|..... +;;; ^ page boundary +;;; where GC reads the objects on the page just after the filler +;;; because it doesn't know not to. +;;; +(defmacro make-filler (n) + `(logior (ash ,n #+64-bit 32 #-64-bit ,n-widetag-bits) filler-widetag)) +(defmacro filler-nwords (header) + `(ash ,header #+64-bit -32 #-64-bit ,(- n-widetag-bits))) + +(defun %shrink-vector (vector new-length + &aux (old-length (length vector)) + (new-length* new-length)) (declare (vector vector)) - (unless (array-header-p vector) - (macrolet ((frob (name &rest things) - `(etypecase ,name - ((simple-array nil (*)) (error 'nil-array-accessed-error)) - ,@(mapcar (lambda (thing) - (destructuring-bind (type-spec fill-value) - thing - `(,type-spec - (fill (truly-the ,type-spec ,name) - ,fill-value - :start new-length)))) - things)))) - ;; Set the 'tail' of the vector to the appropriate type of zero, - ;; "because in some cases we'll scavenge larger areas in one go, - ;; like groups of pages that had triggered the write barrier, or - ;; the whole static space" according to jsnell. - #.`(frob vector - ,@(map 'list - (lambda (saetp) - `((simple-array ,(saetp-specifier saetp) (*)) - ,(if (or (eq (saetp-specifier saetp) 'character) - #+sb-unicode - (eq (saetp-specifier saetp) 'base-char)) - '(code-char 0) - (saetp-initial-element-default saetp)))) - (remove-if-not - #'saetp-specifier - *specialized-array-element-type-properties*))))) + (cond + ((simple-vector-p vector) + ;; We do in fact call %SHRINK-VECTOR a lot from sequence functions + ;; that overallocate a temporary result. In all places where that happens, + ;; the discarded suffix was never used. So assuming pre-zeroed heap, + ;; it kind of just worked. But I don't want to assume that. + ;; For what it's worth, adding this assertion prior to FILL: + ;; (WHEN (FIND 0 VECTOR :START OLD-LENGTH :TEST #'NEQ) (BUG "No can do")) + ;; produced no failures in the regression suite. + (when (< new-length old-length) (fill vector 0 :start new-length))) + ((not (or (array-header-p vector) (typep vector '(simple-array nil (*))))) + (when (simple-base-string-p vector) + ;; We can blindly store the hidden #\null at NEW-LENGTH, but it would + ;; appear to be an out-of-bounds access if the length is not + ;; changing at all. i.e. while it's safe to always do a store, + ;; the length check has to be skipped. + (locally (declare (optimize (sb-c:insert-array-bounds-checks 0))) + (setf (schar vector new-length) (code-char 0))) + ;; Now treat both the old and new lengths as if they include + ;; the byte that holds the implicit string terminator. + (incf old-length) + (incf new-length*)) + (let* ((n-bits-shift (aref %%simple-array-n-bits-shifts%% + (%other-pointer-widetag vector))) + (old-nwords (ceiling (ash old-length n-bits-shift) n-word-bits)) + (new-nwords (ceiling (ash new-length* n-bits-shift) n-word-bits))) + (when (< new-nwords old-nwords) + (with-pinned-objects (vector) + ;; VECTOR-SAP is only for unboxed vectors. Use the vop directly. + (let ((data (%primitive vector-sap vector))) + ;; There is no requirement to zeroize memory corresponding + ;; to unused array elements. + ;; However, it's slightly nicer if the padding word (if present) is 0. + (when (oddp new-nwords) + (setf (sap-ref-word data (ash new-nwords word-shift)) 0)) + (let* ((aligned-old (align-up old-nwords 2)) + (aligned-new (align-up new-nwords 2))) + ;; Only if physically shrunk as determined by PRIMITIVE-OBJECT-SIZE + ;; will we need to (and have adequate room to) place a filler. + (when (< aligned-new aligned-old) + (let ((diff (- aligned-old aligned-new))) + ;; Certainly if the vector is unboxed it can't possibly matter + ;; if GC sees this bit pattern prior to setting the new length; + ;; but even for SIMPLE-VECTOR, it's OK, it turns out. + (setf (sap-ref-word data (ash aligned-new word-shift)) + (make-filler diff))))))))))) ;; Only arrays have fill-pointers, but vectors have their length ;; parameter in the same place. (setf (%array-fill-pointer vector) new-length) @@ -1508,7 +1482,7 @@ of specialized arrays is supported." (%array-available-elements from) 0 (%array-displaced-p from) (array-dimensions array)) (dotimes (i (%array-rank from)) - (setf (%array-dimension from i) 0))))))))) + (%set-array-dimension from i 0))))))))) (if newp (setf (%array-displaced-from array) nil) (%walk-displaced-array-backpointers array length)) @@ -1518,16 +1492,12 @@ of specialized arrays is supported." (setf (%array-available-elements array) length) (cond (fill-pointer (setf (%array-fill-pointer array) fill-pointer) - (setf (%array-fill-pointer-p array) t)) + (logior-array-flags array +array-fill-pointer-p+)) (t (setf (%array-fill-pointer array) length) - (setf (%array-fill-pointer-p array) nil))) + (reset-array-flags array +array-fill-pointer-p+))) (setf (%array-displacement array) displacement) - (if (listp dimensions) - (dotimes (axis (array-rank array)) - (declare (type index axis)) - (setf (%array-dimension array axis) (pop dimensions))) - (setf (%array-dimension array 0) dimensions)) + (populate-dimensions array dimensions (array-rank array)) (setf (%array-displaced-p array) displacedp) array)) @@ -1659,9 +1629,9 @@ function to be removed without further warning." (loop for i below rank do (%set-array-dimension result i (%array-dimension array i))) + ;; fill-pointer-p defaults to 0 (setf (%array-displaced-from result) nil (%array-displaced-p result) nil - (%array-fill-pointer-p result) nil (%array-fill-pointer result) size (%array-available-elements result) size) result)) @@ -1692,6 +1662,17 @@ function to be removed without further warning." ;;; macro. CONCATENATE-FORMAT-P returns true, so then we want to know whether the ;;; result is a base-string which entails calling SB-KERNEL:SIMPLE-BASE-STRING-P ;;; which has no definition in the cross-compiler. (We could add one of course) + +;;; Bit array operations are allowed to leave arbitrary values in the +;;; trailing bits of the result. Examples: +;;; * (format t "~b~%" (%vector-raw-bits (bit-not #*1001) 0)) +;;; 1111111111111111111111111111111111111111111111111111111111110110 +;;; * (format t "~b~%" (%vector-raw-bits (bit-nor #*1001 #*1010) 0)) +;;; 1111111111111111111111111111111111111111111111111111111111110010 +;;; But because reading is more common than writing, it seems that a better +;;; technique might be to enforce an invariant that the last word contain 0 +;;; in all unused bits so that EQUAL and SXHASH become far simpler. + (macrolet ((def-bit-array-op (name function) `(defun ,name (bit-array-1 bit-array-2 &optional result-bit-array) ,(format nil @@ -1810,7 +1791,7 @@ function to be removed without further warning." ,@(ecase style (:call - `((!define-load-time-global ,table-name ,(sb-xc:make-array (1+ widetag-mask))) + `((define-load-time-global ,table-name ,(sb-xc:make-array (1+ widetag-mask))) ;; This SUBSTITUTE call happens ** after ** all the SETFs below it. ;; DEFGLOBAL's initial value is dumped by genesis as a vector filled @@ -1884,37 +1865,34 @@ function to be removed without further warning." (array-dimensions array))) array) -;;; Why is this needed for ARM and not x86 ??? -(defun allocate-vector (type length words) - (allocate-vector type length words)) - ;;; Horrible kludge for the "static-vectors" system ;;; which uses an internal symbol in SB-IMPL. (import '%vector-widetag-and-n-bits-shift 'sb-impl) (defun make-weak-vector (length &key (initial-contents nil contents-p) (initial-element nil element-p)) + (declare (index length)) (when (and element-p contents-p) (error "Can't specify both :INITIAL-ELEMENT and :INITIAL-CONTENTS")) ;; Explicitly compute a widetag with the weakness bit ORed in. - (let ((type (logior (ash vector-weak-subtype sb-vm:n-widetag-bits) - sb-vm:simple-vector-widetag))) + (let ((type (logior (ash vector-weak-flag array-flags-position) simple-vector-widetag))) ;; These allocation calls are the transforms of MAKE-ARRAY for a vector with ;; the respective initializing keyword arg. This is badly OAOO-violating and ;; almost makes me want to cry, but not quite enough for me to improve it. (if contents-p (let ((contents-length (length initial-contents))) - (if (= (truly-the index length) contents-length) - (replace (truly-the simple-vector (allocate-vector type length length)) + (if (= length contents-length) + (replace (truly-the simple-vector + (allocate-vector #+ubsan nil type length length)) initial-contents) (error "~S has ~D elements, vector length is ~D." :initial-contents contents-length length))) (fill (truly-the simple-vector - (allocate-vector type (truly-the index length) length)) + (allocate-vector #+ubsan nil type length length)) ;; 0 is the usual default, but NIL makes more sense for weak vectors ;; as it is the value assigned to broken hearts. (if element-p initial-element nil))))) (defun weak-vector-p (x) (and (simple-vector-p x) - (eql (get-header-data x) vector-weak-subtype))) + (test-header-data-bit x (ash vector-weak-flag array-flags-data-position)))) diff --git a/src/code/avltree.lisp b/src/code/avltree.lisp index 174a6393c3..c332a3c82d 100644 --- a/src/code/avltree.lisp +++ b/src/code/avltree.lisp @@ -143,6 +143,7 @@ ((< key node-key) (find-in (avlnode-left tree))) (t tree)))))) +;;; Find a node with key less than or equal to KEY and as near it as possible. (defun avl-find<= (key root) (declare (sb-vm:word key)) (named-let find-in ((tree root) (result nil)) @@ -153,6 +154,18 @@ (t tree))) result))) +;;; Find a node with key greater than or equal to KEY and as near it as possible. +(defun avl-find>= (key root) + (declare (sb-vm:word key)) + (named-let find-in ((tree root) (result nil)) + (if tree + (let ((node-key (avlnode-key tree))) + (cond ((> key node-key) (find-in (avlnode-right tree) result)) + ((< key node-key) (find-in (avlnode-left tree) tree)) + (t tree))) + result))) + +(export '(avltree-list avl-find>= avl-find<=)) (defun avltree-list (tree &optional (transducer #'avlnode-data)) (let (result) (named-let recurse ((node tree)) @@ -162,8 +175,19 @@ (recurse (avlnode-right node)))) result)) +(defun avltree-filter (predicate tree) + (let (result) + (named-let recurse ((node tree)) + (when node + (let ((value (funcall predicate node))) + (when value + (push value result))) + (recurse (avlnode-left node)) + (recurse (avlnode-right node)))) + result)) + (defmethod print-object ((self avlnode) stream) - (write-string "#<avltree " stream) + (format stream "#<avltree key=~s " (avlnode-key self)) (let ((ct (avl-count self))) (cond ((< ct 20) ; print in order if not too many (let ((c #\[)) diff --git a/src/code/backq.lisp b/src/code/backq.lisp index 9250b48348..0ef4f86dbb 100644 --- a/src/code/backq.lisp +++ b/src/code/backq.lisp @@ -13,14 +13,13 @@ ;; An unquoting COMMA struct. (defstruct (comma (:constructor unquote (expr &optional (kind 0))) - #+sb-xc-host (:include structure!object) ;; READing unpretty commas requires a default constructor. ;; Not needed on the host. #-sb-xc-host (:constructor %default-comma-constructor) (:copier nil)) (expr nil :read-only t) (kind nil :read-only t :type (member 0 1 2))) -#+sb-xc (declaim (freeze-type comma)) +(declaim (freeze-type comma)) (defconstant !+comma-dot+ 1) (defconstant !+comma-at+ 2) @@ -51,8 +50,9 @@ result))) (defun comma-charmacro (stream char) - (declare (ignore char)) - (declare (notinline read-char unread-char)) + (declare (type stream stream) + (ignore char) + (notinline read-char unread-char)) (unless (> *backquote-depth* 0) (when *read-suppress* (return-from comma-charmacro nil)) @@ -70,10 +70,6 @@ (unquote (let ((*backquote-depth* (1- *backquote-depth*))) (read stream t nil t)) flag))) -;; KLUDGE: 'sfunction' is not a defined type yet. -(declaim (ftype (function (t fixnum boolean) (values t t &optional)) - qq-template-to-sexpr qq-template-1)) - ;; A QQ-SUBFORM is a cons whose car is an arbitrary S-expression, and ;; cdr one of {EVAL,QUOTE,NCONC,|Append|} signifying how to treat the car. ;; QUOTE and EVAL mean that a single element should be inserted, @@ -109,6 +105,7 @@ ;; the template, substituting into the outermost commas. Return two values: ;; the S-expression, and an indicator of how to incorporate it into its parent. (defun qq-template-to-sexpr (expr depth compiler-p) + (declare (type fixnum depth)) (cond ((not expr) (values nil 'quote)) ((listp expr) (qq-template-1 expr (+ (if (eq (car expr) 'quasiquote) 1 0) depth) @@ -171,6 +168,7 @@ ;; non-nil atom. Return a secondary value indicating whether it was or not. ;; The output list never "dots" its last cons, regardless of the input. (defun qq-map-template-to-list (input depth compiler-p) + (declare (type fixnum depth)) (let ((original input) list dotted-p) (flet ((to-sexpr (x) (multiple-value-call #'cons @@ -221,6 +219,7 @@ ;; and then compile it, they miss out on the opportunity for the minor ;; advantage provided by the foldable functions, but why would they do that? (defun qq-template-1 (input depth compiler-p) + (declare (type fixnum depth)) (multiple-value-bind (subforms dot-p) (qq-map-template-to-list input depth compiler-p) (labels ((const-p (subform) ; is SUBFORM constant? @@ -318,7 +317,7 @@ (set-macro-character #\, 'comma-charmacro nil rt)) ;;; This is a load-time effect, not compile-time, and *READTABLE* will have been ;;; reverted to the standard one, so be sure to assign into ours, not that. -#-sb-xc (!backq-cold-init sb-cold:*xc-readtable*) +#+sb-xc-host (!backq-cold-init sb-cold:*xc-readtable*) ;;; Since our backquote is installed on the host lisp, and since ;;; developers make mistakes with backquotes and commas too, let's diff --git a/src/code/barrier.lisp b/src/code/barrier.lisp index 55f7e79775..d267c7a0f7 100644 --- a/src/code/barrier.lisp +++ b/src/code/barrier.lisp @@ -11,35 +11,27 @@ (in-package "SB-THREAD") - -;;;; Interpreter stubs for the various barrier functions - ;;; If no memory barrier vops exist, then the %{mumble}-BARRIER function is an inline ;;; function that does nothing. If the vops exist, then the same function ;;; is always translated with a vop, and the DEFUN is merely an interpreter stub. -#-(vop-named sb-vm:%memory-barrier) -(progn -;;; Assert correctness of build order. (Need not be exhaustive) -(eval-when (:compile-toplevel) #+x86-64 (error "Expected %memory-barrier vop")) -(declaim (inline sb-vm:%compiler-barrier sb-vm:%memory-barrier - sb-vm:%read-barrier sb-vm:%write-barrier - sb-vm:%data-dependency-barrier))) - -;;; Because of cross-compiler madness, avoid defining inline functions -;;; inside a macrolet. -;;; TODO: fix that problem once and for all, and put this back into a less insane form. -(progn - . - #.(loop for name in '(sb-vm:%compiler-barrier - sb-vm:%memory-barrier - sb-vm:%read-barrier - sb-vm:%write-barrier - sb-vm:%data-dependency-barrier) - collect `(defun ,name () - #+(vop-named sb-vm:%memory-barrier) (,name) - (values)))) +(eval-when (:compile-toplevel) + (sb-xc:defmacro def-barrier (name) + (if (sb-c::vop-existsp :named sb-vm:%memory-barrier) + `(defun ,name () (,name)) + `(progn (declaim (inline ,name)) (defun ,name () (values)))))) +(def-barrier sb-vm:%compiler-barrier) +(def-barrier sb-vm:%memory-barrier) +(def-barrier sb-vm:%read-barrier) +(def-barrier sb-vm:%write-barrier) +(def-barrier sb-vm:%data-dependency-barrier) ;;;; The actual barrier macro and support +(defconstant-eqx +barrier-kind-functions+ + '(:compiler sb-vm:%compiler-barrier :memory sb-vm:%memory-barrier + :read sb-vm:%read-barrier :write sb-vm:%write-barrier + :data-dependency sb-vm:%data-dependency-barrier) + #'equal) + (defmacro barrier ((kind) &body forms) "Insert a barrier in the code stream, preventing some sort of reordering. @@ -71,10 +63,5 @@ The file \"memory-barriers.txt\" in the Linux kernel documentation is highly recommended reading for anyone programming at this level." `(multiple-value-prog1 (progn ,@forms) - (,(or (getf '(:compiler sb-vm:%compiler-barrier - :memory sb-vm:%memory-barrier - :read sb-vm:%read-barrier - :write sb-vm:%write-barrier - :data-dependency sb-vm:%data-dependency-barrier) - kind) + (,(or (getf +barrier-kind-functions+ kind) (error "Unknown barrier kind ~S" kind))))) diff --git a/src/code/bignum-random.lisp b/src/code/bignum-random.lisp index 0d95e717b3..a505adb08d 100644 --- a/src/code/bignum-random.lisp +++ b/src/code/bignum-random.lisp @@ -14,24 +14,6 @@ (in-package "SB-BIGNUM") -;;; Return T if the least significant N-BITS bits of BIGNUM are all -;;; zero, else NIL. If the integer-length of BIGNUM is less than N-BITS, -;;; the result is NIL, too. -(declaim (inline bignum-lower-bits-zero-p)) -(defun bignum-lower-bits-zero-p (bignum n-bits) - (declare (type bignum bignum) - (type bit-index n-bits)) - (multiple-value-bind (n-full-digits n-bits-partial-digit) - (floor n-bits digit-size) - (declare (type bignum-length n-full-digits)) - (when (> (%bignum-length bignum) n-full-digits) - (dotimes (index n-full-digits) - (declare (type bignum-index index)) - (unless (zerop (%bignum-ref bignum index)) - (return-from bignum-lower-bits-zero-p nil))) - (zerop (logand (1- (ash 1 n-bits-partial-digit)) - (%bignum-ref bignum n-full-digits)))))) - ;;; Return a nonnegative integer of DIGIT-SIZE many pseudo random bits. (declaim (inline random-bignum-digit)) (defun random-bignum-digit (state) @@ -56,11 +38,14 @@ (declaim (inline concatenate-random-bignum)) (defun concatenate-random-bignum (random-chunk bit-count state) (declare (type bignum-element-type random-chunk) - (type (integer 0 #.sb-xc:most-positive-fixnum) bit-count) + (type (integer 0 #.most-positive-fixnum) bit-count) (type random-state state)) (let* ((n-total-bits (+ 1 n-random-chunk-bits bit-count)) ; sign bit (length (ceiling n-total-bits digit-size)) (bignum (%allocate-bignum length))) + ;; DO NOT ASSUME THAT %ALLOCATE-BIGNUM PREZEROS + ;; [See example in MAKE-RANDOM-BIGNUM] + (setf (%bignum-ref bignum (1- length)) 0) (multiple-value-bind (n-random-digits n-random-bits) (floor bit-count digit-size) (declare (type bignum-length n-random-digits)) @@ -90,6 +75,11 @@ (length (ceiling n-total-bits digit-size)) (bignum (%allocate-bignum length))) (declare (type bignum-length length)) + ;; DO NOT ASSUME THAT %ALLOCATE-BIGNUM PREZEROS + ;; Consider: n-bits = 64 -> n-total-bits = 65 -> length = 2 + ;; and n-digits = 1, n-bits-partial-digit = 0 + ;; so DOTIMES executes exactly once, leaving the final word untouched. + (setf (%bignum-ref bignum (1- length)) 0) (multiple-value-bind (n-digits n-bits-partial-digit) (floor n-bits digit-size) (declare (type bignum-length n-digits)) @@ -133,7 +123,7 @@ ;;; generate and compare the complete random number and risk to reject ;;; it. (defun %random-bignum (arg state) - (declare (type (integer #.(1+ sb-xc:most-positive-fixnum)) arg) + (declare (type (integer #.(1+ most-positive-fixnum)) arg) (type random-state state) (inline bignum-lower-bits-zero-p)) (let ((n-bits (bignum-integer-length arg))) diff --git a/src/code/bignum.lisp b/src/code/bignum.lisp index 6b08a000c0..545b1ef6fc 100644 --- a/src/code/bignum.lisp +++ b/src/code/bignum.lisp @@ -109,83 +109,123 @@ (defconstant all-ones-digit most-positive-word) -;;;; internal inline routines +#+bignum-assertions +(progn +(declaim (notinline %allocate-bignum)) +(defmacro with-bignum-shadow-bits ((bits object &optional length) &body body) + `(let ((b ,object)) + (with-pinned-objects (b) + (let ((,bits + (sb-sys:sap+ (sb-sys:sap+ (sb-sys:int-sap (sb-kernel:get-lisp-obj-address b)) + (- sb-vm:n-word-bytes sb-vm:other-pointer-lowtag)) + ;; shadow bits always start on a double-lispword boundary, + ;; so ensure that payload length looks like an odd number. + (ash (logior ,(or length `(%bignum-length b)) 1) + sb-vm:word-shift)))) + ,@body)))) -;;; %ALLOCATE-BIGNUM must zero all elements. (defun %allocate-bignum (length) (declare (type bignum-length length)) - (%allocate-bignum length)) - -;;; Extract the length of the bignum. -(defun %bignum-length (bignum) - (declare (type bignum bignum)) - (%bignum-length bignum)) - -;;; %BIGNUM-REF needs to access bignums as obviously as possible, and it needs -;;; to be able to return the digit somewhere no one looks for real objects. -(defun %bignum-ref (bignum i) - (declare (type bignum bignum) - (type bignum-index i)) - (%bignum-ref bignum i)) + (declare (inline %allocate-bignum)) + (let ((bignum (%allocate-bignum length))) ; call the low-level allocator + (multiple-value-bind (nwords nbits) (floor length sb-vm:n-word-bits) + (with-bignum-shadow-bits (bit-base bignum length) + (dotimes (i nwords) + (setf (sap-ref-word bit-base 0) sb-ext:most-positive-word + bit-base (sap+ bit-base sb-vm:n-word-bytes))) + (when (plusp nbits) + (setf (sap-ref-word bit-base 0) + (#+little-endian shift-towards-start + #+big-endian shift-towards-end sb-ext:most-positive-word + (- nbits)))))) + (dotimes (i length) + (%%bignum-set bignum i (logior #+64-bit #xc0fefe0000 i))) + ;; If there is a padding word, then write junk in it, so we can assert that whenever + ;; bignum-set-length is used, the padding word (if present) was cleared. + (when (evenp length) (%%bignum-set bignum length #xdeadbeef)) + bignum)) + +(defun index-out-of-bounds (bignum i) + (error "out-of-bounds bignum set @ ~x[~d], len=~d~%" + (get-lisp-obj-address bignum) i (%bignum-length bignum))) + +(declaim (inline %bignum-set)) (defun %bignum-set (bignum i value) (declare (type bignum bignum) (type bignum-index i) (type bignum-element-type value)) - (%bignum-set bignum i value)) + (cond ((< i (%bignum-length bignum)) + (with-bignum-shadow-bits (bit-base bignum) + (multiple-value-bind (word-index bit-index) (floor i sb-vm:n-word-bits) + (let ((sap (sap+ bit-base (* word-index sb-vm:n-word-bytes)))) + (setf (sap-ref-word sap 0) + (logandc2 (sap-ref-word sap 0) (ash 1 bit-index)))))) + (%%bignum-set bignum i value)) + (t + (index-out-of-bounds bignum i))) + (values)) -;;; Return T if digit is positive, or NIL if negative. -(defun %digit-0-or-plusp (digit) - (declare (type bignum-element-type digit)) - (not (logbitp (1- digit-size) digit))) +(defun bignum-ref-trap (bignum i) + ;; This error might happen too early in cold-init to report it normally + (alien-funcall (extern-alien "printf" (function void system-area-pointer unsigned unsigned)) + (vector-sap #.(format nil "Element %d of bignum %p was never written~%")) + i (get-lisp-obj-address bignum)) + (sb-vm:ldb-monitor) + 0) -#-sb-fluid (declaim (inline %bignum-0-or-plusp)) +(declaim (inline %bignum-ref)) +(defun %bignum-ref (bignum i) + (declare (type bignum bignum) + (type bignum-index i)) + ;; We don't need to check %BIGNUM-LENGTH because the shadow bit won't be on + ;; presuming that we only care to detct "small" off-by-1 errors, + ;; and not egregious buffer overrun errors. + (multiple-value-bind (word-index bit-index) (floor i sb-vm:n-word-bits) + (with-bignum-shadow-bits (bit-base bignum) + (let ((sap (sap+ bit-base (* word-index sb-vm:n-word-bytes)))) + (if (logbitp bit-index (sap-ref-word sap 0)) ; word was never assigned + (truly-the sb-vm:word (bignum-ref-trap bignum i)) + (sap-ref-word (int-sap (get-lisp-obj-address bignum)) + (- (ash (+ i sb-vm:bignum-digits-offset) sb-vm:word-shift) + sb-vm:other-pointer-lowtag))))))) + +(defun aver-zeroed-from-index (bignum index) + (with-pinned-objects (bignum) + (let* ((physical-start (sap+ (int-sap (get-lisp-obj-address bignum)) + (- sb-vm:other-pointer-lowtag))) + (physlen-bytes (ash (+ (* (%bignum-length bignum) 2) 2) sb-vm:word-shift)) + (physical-end (sap+ physical-start physlen-bytes)) + (word-ptr (sap+ physical-start (ash (1+ index) sb-vm:word-shift)))) + (loop while (sb-sys:sap< word-ptr physical-end) + do (unless (= (sap-ref-word word-ptr 0) 0) + (alien-funcall (extern-alien "printf" + (function void system-area-pointer unsigned unsigned)) + (vector-sap #.(format nil "set-length %p,%d not properly zeroed~%")) + (get-lisp-obj-address bignum) index) + (sb-vm:ldb-monitor)) + (setq word-ptr (sap+ word-ptr 8)))))) +) + +;;; DO NOT ASSUME THAT LOW-LEVEL ALLOCATOR PREZEROES THE MEMORY +(defmacro alloc-zeroing (length) + `(let* ((l ,length) (new (%allocate-bignum l))) + (dotimes (i l new) + (setf (%bignum-ref new i) 0)))) +(defmacro alloc-zeroing-below (length end) + `(let ((new (%allocate-bignum ,length))) + (dotimes (i ,end new) + (setf (%bignum-ref new i) 0)))) + +(declaim (inline %bignum-0-or-plusp)) (defun %bignum-0-or-plusp (bignum len) (declare (type bignum bignum) (type bignum-length len)) (%digit-0-or-plusp (%bignum-ref bignum (1- len)))) -;;; This should be in assembler, and should not cons intermediate -;;; results. It returns a bignum digit and a carry resulting from adding -;;; together a, b, and an incoming carry. -(defun %add-with-carry (a b carry) - (declare (type bignum-element-type a b) - (type (mod 2) carry)) - (%add-with-carry a b carry)) - -;;; This should be in assembler, and should not cons intermediate -;;; results. It returns a bignum digit and a borrow resulting from -;;; subtracting b from a, and subtracting a possible incoming borrow. -;;; -;;; We really do: a - b - 1 + borrow, where borrow is either 0 or 1. -(defun %subtract-with-borrow (a b borrow) - (declare (type bignum-element-type a b) - (type (mod 2) borrow)) - (%subtract-with-borrow a b borrow)) - -;;; Multiply two digit-size numbers, returning a 2*digit-size result -;;; split into two digit-size quantities. -(defun %multiply (x y) - (declare (type bignum-element-type x y)) - (%multiply x y)) - -;;; This multiplies x-digit and y-digit, producing high and low digits -;;; manifesting the result. Then it adds the low digit, res-digit, and -;;; carry-in-digit. Any carries (note, you still have to add two digits -;;; at a time possibly producing two carries) from adding these three -;;; digits get added to the high digit from the multiply, producing the -;;; next carry digit. Res-digit is optional since two uses of this -;;; primitive multiplies a single digit bignum by a multiple digit -;;; bignum, and in this situation there is no need for a result buffer -;;; accumulating partial results which is where the res-digit comes -;;; from. -(defun %multiply-and-add (x-digit y-digit carry-in-digit - &optional (res-digit 0)) - (declare (type bignum-element-type x-digit y-digit res-digit carry-in-digit)) - (%multiply-and-add x-digit y-digit carry-in-digit res-digit)) - -(defun %lognot (digit) - (declare (type bignum-element-type digit)) - (%lognot digit)) +(declaim (inline bignum-plus-p)) +(defun bignum-plus-p (bignum) + (declare (type bignum bignum)) + (%bignum-0-or-plusp bignum (%bignum-length bignum))) ;;; Each of these does the digit-size unsigned op. (declaim (inline %logand %logior %logxor)) @@ -201,66 +241,86 @@ ;;; This takes a fixnum and sets it up as an unsigned digit-size ;;; quantity. +;;; The stub function is needed for constant-folding, or where vops don't exist (defun %fixnum-to-digit (x) (declare (fixnum x)) - (logand x (1- (ash 1 digit-size)))) - -;;; This takes three digits and returns the FLOOR'ed result of -;;; dividing the first two as a 2*digit-size integer by the third. -(defun %bigfloor (a b c) - (%bigfloor a b c)) - -;;; Convert the digit to a regular integer assuming that the digit is signed. -(defun %fixnum-digit-with-correct-sign (digit) - (declare (type bignum-element-type digit)) - (if (logbitp (1- digit-size) digit) - (logior digit (ash -1 digit-size)) - digit)) - -;;; Do an arithmetic shift right of data even though bignum-element-type is -;;; unsigned. -(defun %ashr (data count) - (declare (type bignum-element-type data) - (type (mod #.sb-vm:n-word-bits) count)) - (%ashr data count)) - -;;; This takes a digit-size quantity and shifts it to the left, -;;; returning a digit-size quantity. -(defun %ashl (data count) - (declare (type bignum-element-type data) - (type (mod #.sb-vm:n-word-bits) count)) - (%ashl data count)) - -;;; Do an unsigned (logical) right shift of a digit by Count. -(defun %digit-logical-shift-right (data count) - (declare (type bignum-element-type data) - (type (mod #.sb-vm:n-word-bits) count)) - (%digit-logical-shift-right data count)) - -;;; Change the length of bignum to be newlen. Newlen must be the same or -;;; smaller than the old length, and any elements beyond newlen must be zeroed. -(defun %bignum-set-length (bignum newlen) - (declare (type bignum bignum) - (type bignum-length newlen)) - (%bignum-set-length bignum newlen)) + #+(or arm arm64) (logand x (1- (ash 1 digit-size))) ; missing the vops + #-(or arm arm64) (%fixnum-to-digit x)) ;;; This returns 0 or "-1" depending on whether the bignum is positive. This ;;; is suitable for infinite sign extension to complete additions, ;;; subtractions, negations, etc. This cannot return a -1 represented as ;;; a negative fixnum since it would then have to low zeros. -#-sb-fluid (declaim (inline %sign-digit)) +(declaim (inline %sign-digit)) (defun %sign-digit (bignum len) (declare (type bignum bignum) (type bignum-length len)) (%ashr (%bignum-ref bignum (1- len)) (1- digit-size))) -(declaim (inline bignum-plus-p)) -(defun bignum-plus-p (bignum) - (declare (type bignum bignum)) - (%bignum-0-or-plusp bignum (%bignum-length bignum))) +(declaim (inline (setf %bignum-ref))) +(defun (setf %bignum-ref) (val bignum index) + (%bignum-set bignum index val) ; valueless + val) (declaim (optimize (speed 3) (safety 0))) +;;;; general utilities + +;;; Internal in-place operations use this to fixup remaining digits in the +;;; incoming data, such as in-place shifting. This is basically the same as +;;; the first form in %NORMALIZE-BIGNUM, but we return the length of the buffer +;;; instead of shrinking the bignum. +(declaim (maybe-inline %normalize-bignum-buffer)) +(defun %normalize-bignum-buffer (result len) + (declare (type bignum result) + (type bignum-length len)) + (unless (= len 1) + (do ((next-digit (%bignum-ref result (- len 2)) + (%bignum-ref result (- len 2))) + (sign-digit (%bignum-ref result (1- len)) next-digit)) + ((not (zerop (logxor sign-digit (%ashr next-digit (1- digit-size)))))) + (decf len) + (setf (%bignum-ref result len) 0) + (when (= len 1) (return)))) + len) + +;; Prior to calling %bignum-set-length we have to ensure that if the physical length +;; decreases, then final word that may never have been written does not contain junk. +(defmacro clear-padding-word (bignum oldlen newlen) + (declare (ignorable newlen)) + `(progn + (when (evenp ,oldlen) + (#+bignum-assertions %%bignum-set #-bignum-assertions %bignum-set ,bignum ,oldlen 0)) + #+bignum-assertions (aver-zeroed-from-index ,bignum ,newlen))) + +;;; This drops the last digit if it is unnecessary sign information. It repeats +;;; this as needed, possibly ending with a fixnum. If the resulting length from +;;; shrinking is one, see whether our one word is a fixnum. Shift the possible +;;; fixnum bits completely out of the word, and compare this with shifting the +;;; sign bit all the way through. If the bits are all 1's or 0's in both words, +;;; then there are just sign bits between the fixnum bits and the sign bit. If +;;; we do have a fixnum, shift it over for the two low-tag bits. +(defun %normalize-bignum (result len) + (declare (type bignum result) + (type bignum-length len) + (muffle-conditions compiler-note) + (inline %normalize-bignum-buffer)) + #+bignum-assertions (aver (= (%bignum-length result) len)) + (let ((newlen (%normalize-bignum-buffer result len))) + (declare (type bignum-length newlen)) + (unless (= newlen len) + ;; If the old length was even, then there is a word which was never accessed + ;; and may contains random bits. Clear it to avoid a crash in GC. + (clear-padding-word result len newlen) + (%bignum-set-length result newlen)) + (if (= newlen 1) + (let ((digit (%bignum-ref result 0))) + (if (= (%ashr digit sb-vm:n-positive-fixnum-bits) + (%ashr digit (1- digit-size))) + (%fixnum-digit-with-correct-sign digit) + result)) + result))) + ;;;; addition (defun add-bignums (a b) @@ -372,7 +432,7 @@ (len-a (%bignum-length a)) (len-b (%bignum-length b)) (len-res (+ len-a len-b)) - (res (%allocate-bignum len-res)) + (res (alloc-zeroing len-res)) (negate-res (not (eq a-plusp b-plusp)))) (declare (type bignum-length len-a len-b len-res)) (dotimes (i len-a) @@ -419,74 +479,78 @@ (negate-bignum-in-place result)) (%normalize-bignum result (1+ bignum-len)))) -(defun multiply-fixnums (a b) - (declare (fixnum a b)) - (declare (muffle-conditions compiler-note)) ; returns lispobj, so what. - (let* ((a-minusp (minusp a)) - (b-minusp (minusp b))) - (multiple-value-bind (high low) - (%multiply (if a-minusp (- a) a) - (if b-minusp (- b) b)) - (declare (type bignum-element-type high low)) - (if (and (zerop high) - (%digit-0-or-plusp low)) - (let ((low (truly-the (unsigned-byte #.(1- sb-vm:n-word-bits)) - (%fixnum-digit-with-correct-sign low)))) - (if (eq a-minusp b-minusp) - low - (- low))) - (let ((res (%allocate-bignum 2))) - (%bignum-set res 0 low) - (%bignum-set res 1 high) - (unless (eq a-minusp b-minusp) (negate-bignum-in-place res)) - (%normalize-bignum res 2)))))) +(sb-c::unless-vop-existsp (:translate sb-c::fixnum*) + (defun multiply-fixnums (a b) + (declare (fixnum a b)) + (declare (muffle-conditions compiler-note)) ; returns lispobj, so what. + (let* ((a-minusp (minusp a)) + (b-minusp (minusp b))) + (multiple-value-bind (high low) + (%multiply (if a-minusp (- a) a) + (if b-minusp (- b) b)) + (declare (type bignum-element-type high low)) + (if (and (zerop high) + (%digit-0-or-plusp low)) + (let ((low (truly-the (unsigned-byte #.(1- sb-vm:n-word-bits)) + (%fixnum-digit-with-correct-sign low)))) + (if (eq a-minusp b-minusp) + low + (- low))) + (let ((res (%allocate-bignum 2))) + (%bignum-set res 0 low) + (%bignum-set res 1 high) + (unless (eq a-minusp b-minusp) (negate-bignum-in-place res)) + (%normalize-bignum res 2))))))) ;;;; BIGNUM-REPLACE and WITH-BIGNUM-BUFFERS -(defmacro bignum-replace (dest src - &key - (start1 '0) - end1 - (start2 '0) - end2 - from-end) - (once-only ((n-dest dest) - (n-src src)) - (with-unique-names (n-start1 n-end1 n-start2 n-end2 i1 i2) - (let ((end1 (or end1 `(%bignum-length ,n-dest))) - (end2 (or end2 `(%bignum-length ,n-src)))) - (if from-end - `(let ((,n-start1 ,start1) - (,n-start2 ,start2)) - (do ((,i1 (1- ,end1) (1- ,i1)) - (,i2 (1- ,end2) (1- ,i2))) - ((or (< ,i1 ,n-start1) (< ,i2 ,n-start2))) - (declare (fixnum ,i1 ,i2)) - (%bignum-set ,n-dest ,i1 (%bignum-ref ,n-src ,i2)))) - (if (eql start1 start2) - `(let ((,n-end1 (min ,end1 ,end2))) - (do ((,i1 ,start1 (1+ ,i1))) - ((>= ,i1 ,n-end1)) - (declare (type bignum-index ,i1)) - (%bignum-set ,n-dest ,i1 (%bignum-ref ,n-src ,i1)))) - `(let ((,n-end1 ,end1) - (,n-end2 ,end2)) - (do ((,i1 ,start1 (1+ ,i1)) - (,i2 ,start2 (1+ ,i2))) - ((or (>= ,i1 ,n-end1) (>= ,i2 ,n-end2))) - (declare (type bignum-index ,i1 ,i2)) - (%bignum-set ,n-dest ,i1 (%bignum-ref ,n-src ,i2)))))))))) +#-bignum-assertions +(defmacro bignum-replace (dest src &key (start1 0) (end1 `(%bignum-length ,dest)) + (start2 0) (end2 `(%bignum-length ,src))) + (flet ((@ (obj index) + `(sap+ (sap+ (int-sap (get-lisp-obj-address ,obj)) (ash ,index sb-vm:word-shift)) + (- (ash sb-vm:bignum-digits-offset sb-vm:word-shift) + sb-vm:other-pointer-lowtag)))) + `(let ((count ,(if (and (eql start1 0) (eql start2 0)) + `(min ,end1 ,end2) + `(min (- ,end1 ,start1) (- ,end2 ,start2))))) + (cond ((= count 2) ; COUNT is almost always 2 + (setf (%bignum-ref ,dest ,start1) (%bignum-ref ,src ,start2) + (%bignum-ref ,dest (1+ ,start1)) (%bignum-ref ,src (1+ ,start2)))) + ((= count 1) + (setf (%bignum-ref ,dest ,start1) (%bignum-ref ,src ,start2))) + ((> count 0) + (with-alien ((replace (function system-area-pointer system-area-pointer + system-area-pointer sb-unix::size-t) + :extern ,(if (eq dest src) "memmove" "memcpy"))) + (with-pinned-objects (,dest ,src) + (alien-funcall replace ,(@ dest start1) ,(@ src start2) + (ash count sb-vm:word-shift))))))))) +#+bignum-assertions +(progn +(defmacro bignum-replace (dest src &key (start1 '0) (end1 `(%bignum-length ,dest)) + (start2 '0) (end2 `(%bignum-length ,src))) + `(bignum-replace-impl ,dest ,start1 ,end1 + ,src ,start2 ,end2)) + +(defun bignum-replace-impl (dest start1 end1 src start2 end2) + (do ((i1 start1 (1+ i1)) + (i2 start2 (1+ i2))) + ((or (>= i1 end1) + (>= i2 end2))) + (declare (type bignum-index i1 i2)) + (%bignum-set dest i1 (%bignum-ref src i2))))) (defmacro with-bignum-buffers (specs &body body) "WITH-BIGNUM-BUFFERS ({(var size [init])}*) Form*" (collect ((binds) (inits)) (dolist (spec specs) (let ((name (first spec)) - (size (second spec))) + (size (second spec)) + (init (third spec))) (binds `(,name (%allocate-bignum ,size))) - (let ((init (third spec))) - (when init - (inits `(bignum-replace ,name ,init)))))) + (when init + (inits `(bignum-replace ,name ,init))))) `(let* ,(binds) ,@(inits) ,@body))) @@ -496,8 +560,8 @@ ;; The asserts in the GCD implementation are way too expensive to ;; check in normal use, and are disabled here. (defmacro gcd-assert (&rest args) - (declare (ignore args)) - #+sb-bignum-assertions `(assert ,@args)) + (declare (ignorable args)) + #+bignum-assertions `(assert ,@args)) ;; We'll be doing a lot of modular arithmetic. (defmacro modularly (form) `(logand all-ones-digit ,form)) @@ -624,10 +688,10 @@ (d2 (modularly -1))) (declare (type word n1 d1 n2 d2)) (loop while (> n2 (expt 2 (truncate digit-size 2))) do - (loop for i of-type (mod #.sb-vm:n-word-bits) + (loop for i of-type fixnum downfrom (- (integer-length n1) (integer-length n2)) while (>= n1 n2) do - (when (>= n1 (modularly (ash n2 i))) + (when (>= n1 (modularly (ash n2 (truly-the (mod #.sb-vm:n-word-bits) i)))) (psetf n1 (modularly (- n1 (modularly (ash n2 i)))) d1 (modularly (- d1 (modularly (ash d2 i))))))) (psetf n1 n2 @@ -635,7 +699,7 @@ n2 n1 d2 d1)) (values n2 (if (>= d2 (expt 2 (1- digit-size))) - (lognot (logand sb-xc:most-positive-fixnum (lognot d2))) + (lognot (logand most-positive-fixnum (lognot d2))) (logand lower-ones-digit d2))))) @@ -646,7 +710,7 @@ ;;; Allocate a single word bignum that holds fixnum. This is useful when ;;; we are trying to mix fixnum and bignum operands. -#-sb-fluid (declaim (inline make-small-bignum)) +(declaim (inline make-small-bignum)) (defun make-small-bignum (fixnum) (let ((res (%allocate-bignum 1))) (setf (%bignum-ref res 0) (%fixnum-to-digit fixnum)) @@ -746,7 +810,12 @@ (- (copy-bignum tmp1 tmp1-len) (copy-bignum tmp2 tmp2-len))))) (bignum-abs-buffer u u-len) - (gcd-assert (zerop (modularly u))))) + ;; This assertion is strange, because we're trying to assert on + ;; the least significant word of U, but MODULARLY might do a full call + ;; to TWO-ARG-LOGAND, and it it does, that fails, because not all + ;; words of U are set. And rightly so- they're set only below U-LEN. + #+ppc (gcd-assert (zerop (modularly (copy-bignum u u-len)))) + #-ppc (gcd-assert (zerop (modularly u))))) (setf u-len (make-gcd-bignum-odd u u-len)) (rotatef u v) (rotatef u-len v-len)) @@ -904,7 +973,14 @@ (%add-with-carry (%lognot (%sign-digit x len-x)) 0 carry))) (if fully-normalize (%normalize-bignum res len-res) - (%mostly-normalize-bignum res len-res)))) + ;; This drops the last digit if it is unnecessary sign information. It + ;; repeats this as needed, possibly ending with a fixnum magnitude but never + ;; returning a fixnum. + (locally (declare (inline %normalize-bignum-buffer)) + (let ((newlen (%normalize-bignum-buffer res len-res))) + (clear-padding-word res len-res newlen) + (%bignum-set-length res newlen)) + res)))) ;;; This assumes bignum is positive; that is, the result of negating it will ;;; stay in the provided allocated bignum. @@ -1053,10 +1129,9 @@ (defun bignum-ashift-left-digits (bignum bignum-len digits) (declare (type bignum-length bignum-len digits)) (let* ((res-len (+ bignum-len digits)) - (res (%allocate-bignum res-len))) + (res (alloc-zeroing-below res-len digits))) (declare (type bignum-length res-len)) - (bignum-replace res bignum :start1 digits :end1 res-len :end2 bignum-len - :from-end t) + (bignum-replace res bignum :start1 digits :end1 res-len :end2 bignum-len) res)) ;;; BIGNUM-TRUNCATE uses this to store into a bignum buffer by supplying res. @@ -1074,7 +1149,7 @@ (type (mod #.digit-size) n-bits)) (let* ((remaining-bits (- digit-size n-bits)) (res-len-1 (1- res-len)) - (res (or res (%allocate-bignum res-len)))) + (res (or res (alloc-zeroing-below res-len digits)))) (declare (type bignum-length res-len res-len-1)) (do ((i 0 (1+ i)) (j (1+ digits) (1+ j))) @@ -1111,12 +1186,12 @@ (/= left-half 0))) (length (+ right-zero-digits (if left-half-p 2 1))) - (result (%allocate-bignum length))) + (result (alloc-zeroing-below length right-zero-digits))) (setf (%bignum-ref result right-zero-digits) right-half) (when left-half-p (setf (%bignum-ref result (1+ right-zero-digits)) (ldb (byte digit-size 0) left-half))) - result))) + result))) ;;;; relational operators @@ -1480,6 +1555,37 @@ (%sign-digit bignum n-digits))))) (ldb (byte low-part-size bit-index) ; low part (%bignum-ref bignum word-index))))))))) + +;;; Basically shift the bignum right by byte-pos, but assumes it's +;;; right at the end of the bignum. +(defun last-bignum-part=>fixnum (byte-pos bignum) + (declare (type bit-index byte-pos) + (bignum bignum) + (optimize speed)) + (let ((n-digits (%bignum-length bignum))) + (multiple-value-bind (word-index bit-index) (floor byte-pos digit-size) + (cond ((<= (+ bit-index sb-vm:n-fixnum-bits) digit-size) ; contained in one word + (sb-c::mask-signed-field sb-vm:n-fixnum-bits + (ash (%bignum-ref bignum word-index) (- bit-index)))) + (t + ;; At least one bit is obtained from each of two words, + ;; and not more than two words. + (let* ((low-part-size + (truly-the (integer 1 #.(1- sb-vm:n-positive-fixnum-bits)) + (- digit-size bit-index))) + (high-part-size + (truly-the (integer 1 #.(1- sb-vm:n-positive-fixnum-bits)) + (- sb-vm:n-fixnum-bits low-part-size)))) + (logior + (let ((word-index (1+ word-index))) + (sb-c::mask-signed-field sb-vm:n-fixnum-bits + (if (< word-index n-digits) ; next word exists + (ash (%bignum-ref bignum word-index) low-part-size) + (truly-the word + (mask-field (byte high-part-size low-part-size) + (%sign-digit bignum n-digits)))))) + (ldb (byte low-part-size bit-index) + (%bignum-ref bignum word-index))))))))) ;;;; TRUNCATE @@ -1569,118 +1675,67 @@ (declare (muffle-conditions compiler-note)) ; returns lispobj, so what. (let (truncate-x truncate-y) (labels - ;;; Divide X by Y when Y is a single bignum digit. BIGNUM-TRUNCATE - ;;; fixes up the quotient and remainder with respect to sign and - ;;; normalization. - ;;; - ;;; We don't have to worry about shifting Y to make its most - ;;; significant digit sufficiently large for %BIGFLOOR to return - ;;; digit-size quantities for the q-digit and r-digit. If Y is - ;;; a single digit bignum, it is already large enough for - ;;; %BIGFLOOR. That is, it has some bits on pretty high in the - ;;; digit. - ((bignum-truncate-single-digit (x len-x y) - (declare (type bignum-length len-x)) - (let ((y (%bignum-ref y 0))) - (declare (type bignum-element-type y)) - (if (not (logtest y (1- y))) - ;; Y is a power of two. - ;; SHIFT-RIGHT-UNALIGNED won't do the right thing - ;; with a shift count of 0 or -1, so special case this. - (cond ((= y 0) - (error 'division-by-zero :operation 'truncate - :operands (list x y))) - ((= y 1) - ;; We could probably get away with (VALUES X 0) - ;; here, but it's not clear that some of the - ;; normalization logic further down would avoid - ;; mutilating X. Just go ahead and cons, consing's - ;; cheap. - (values (copy-bignum x len-x) 0)) - (t - (let ((n-bits (1- (integer-length y)))) - (values - (shift-right-unaligned x 0 n-bits len-x - ((= j res-len-1) - (setf (%bignum-ref res j) - (%ashr (%bignum-ref x i) n-bits)) - res) - res) - (logand (%bignum-ref x 0) (1- y)))))) - (do ((i (1- len-x) (1- i)) - (q (%allocate-bignum len-x)) - (r 0)) - ((minusp i) - (let ((rem (%allocate-bignum 1))) - (setf (%bignum-ref rem 0) r) - (values q rem))) - (declare (type bignum-element-type r)) - (multiple-value-bind (q-digit r-digit) - (%bigfloor r (%bignum-ref x i) y) - (declare (type bignum-element-type q-digit r-digit)) - (setf (%bignum-ref q i) q-digit) - (setf r r-digit)))))) - ;;; This returns a guess for the next division step. Y1 is the - ;;; highest y digit, and y2 is the second to highest y - ;;; digit. The x... variables are the three highest x digits - ;;; for the next division step. - ;;; - ;;; From Knuth, our guess is either all ones or x-i and x-i-1 - ;;; divided by y1, depending on whether x-i and y1 are the - ;;; same. We test this guess by determining whether guess*y2 - ;;; is greater than the three high digits of x minus guess*y1 - ;;; shifted left one digit: - ;;; ------------------------------ - ;;; | x-i | x-i-1 | x-i-2 | - ;;; ------------------------------ - ;;; ------------------------------ - ;;; - | g*y1 high | g*y1 low | 0 | - ;;; ------------------------------ - ;;; ... < guess*y2 ??? - ;;; If guess*y2 is greater, then we decrement our guess by one - ;;; and try again. This returns a guess that is either - ;;; correct or one too large. - (bignum-truncate-guess (y1 y2 x-i x-i-1 x-i-2) + ;; This returns a guess for the next division step. Y1 is the + ;; highest y digit, and y2 is the second to highest y + ;; digit. The x... variables are the three highest x digits + ;; for the next division step. + ;; + ;; From Knuth, our guess is either all ones or x-i and x-i-1 + ;; divided by y1, depending on whether x-i and y1 are the + ;; same. We test this guess by determining whether guess*y2 + ;; is greater than the three high digits of x minus guess*y1 + ;; shifted left one digit: + ;; ------------------------------ + ;; | x-i | x-i-1 | x-i-2 | + ;; ------------------------------ + ;; ------------------------------ + ;; - | g*y1 high | g*y1 low | 0 | + ;; ------------------------------ + ;; ... < guess*y2 ??? + ;; If guess*y2 is greater, then we decrement our guess by one + ;; and try again. This returns a guess that is either + ;; correct or one too large. + ((bignum-truncate-guess (y1 y2 x-i x-i-1 x-i-2) (declare (type bignum-element-type y1 y2 x-i x-i-1 x-i-2)) (let ((guess (if (= x-i y1) all-ones-digit (%bigfloor x-i x-i-1 y1)))) (declare (type bignum-element-type guess)) (loop - (multiple-value-bind (high-guess*y1 low-guess*y1) - (%multiply guess y1) - (declare (type bignum-element-type low-guess*y1 - high-guess*y1)) - (multiple-value-bind (high-guess*y2 low-guess*y2) - (%multiply guess y2) - (declare (type bignum-element-type high-guess*y2 - low-guess*y2)) - (multiple-value-bind (middle-digit borrow) - (%subtract-with-borrow x-i-1 low-guess*y1 1) - (declare (type bignum-element-type middle-digit) - (fixnum borrow)) - ;; Supplying borrow of 1 means there was no - ;; borrow, and we know x-i-2 minus 0 requires - ;; no borrow. - (let ((high-digit (%subtract-with-borrow x-i - high-guess*y1 - borrow))) - (declare (type bignum-element-type high-digit)) - (if (and (= high-digit 0) - (or (> high-guess*y2 middle-digit) - (and (= middle-digit high-guess*y2) - (> low-guess*y2 x-i-2)))) - (setf guess (%subtract-with-borrow guess 1 1)) - (return guess))))))))) - ;;; Divide TRUNCATE-X by TRUNCATE-Y, returning the quotient - ;;; and destructively modifying TRUNCATE-X so that it holds - ;;; the remainder. - ;;; - ;;; LEN-X and LEN-Y tell us how much of the buffers we care about. - ;;; - ;;; TRUNCATE-X definitely has at least three digits, and it has one - ;;; more than TRUNCATE-Y. This keeps i, i-1, i-2, and low-x-digit - ;;; happy. Thanks to SHIFT-AND-STORE-TRUNCATE-BUFFERS. + (multiple-value-bind (high-guess*y1 low-guess*y1) + (%multiply guess y1) + (declare (type bignum-element-type low-guess*y1 + high-guess*y1)) + (multiple-value-bind (high-guess*y2 low-guess*y2) + (%multiply guess y2) + (declare (type bignum-element-type high-guess*y2 + low-guess*y2)) + (multiple-value-bind (middle-digit borrow) + (%subtract-with-borrow x-i-1 low-guess*y1 1) + (declare (type bignum-element-type middle-digit) + (fixnum borrow)) + ;; Supplying borrow of 1 means there was no + ;; borrow, and we know x-i-2 minus 0 requires + ;; no borrow. + (let ((high-digit (%subtract-with-borrow x-i + high-guess*y1 + borrow))) + (declare (type bignum-element-type high-digit)) + (if (and (= high-digit 0) + (or (> high-guess*y2 middle-digit) + (and (= middle-digit high-guess*y2) + (> low-guess*y2 x-i-2)))) + (setf guess (%subtract-with-borrow guess 1 1)) + (return guess))))))))) + ;; Divide TRUNCATE-X by TRUNCATE-Y, returning the quotient + ;; and destructively modifying TRUNCATE-X so that it holds + ;; the remainder. + ;; + ;; LEN-X and LEN-Y tell us how much of the buffers we care about. + ;; + ;; TRUNCATE-X definitely has at least three digits, and it has one + ;; more than TRUNCATE-Y. This keeps i, i-1, i-2, and low-x-digit + ;; happy. Thanks to SHIFT-AND-STORE-TRUNCATE-BUFFERS. (return-quotient-leaving-remainder (len-x len-y) (declare (type bignum-length len-x len-y)) (let* ((len-q (- len-x len-y)) @@ -1696,32 +1751,34 @@ (declare (type bignum-length len-q) (type bignum-index k i i-1 i-2 low-x-digit) (type bignum-element-type y1 y2)) + ;; DO NOT ASSUME THAT %ALLOCATE-BIGNUM PREZEROS + (setf (%bignum-ref q len-q) 0) (loop - (setf (%bignum-ref q k) - (try-bignum-truncate-guess - ;; This modifies TRUNCATE-X. Must access - ;; elements each pass. - (bignum-truncate-guess y1 y2 - (%bignum-ref truncate-x i) - (%bignum-ref truncate-x i-1) - (%bignum-ref truncate-x i-2)) - len-y low-x-digit)) - (cond ((zerop k) (return)) - (t (decf k) - (decf low-x-digit) - (shiftf i i-1 i-2 (1- i-2))))) + (setf (%bignum-ref q k) + (try-bignum-truncate-guess + ;; This modifies TRUNCATE-X. Must access + ;; elements each pass. + (bignum-truncate-guess y1 y2 + (%bignum-ref truncate-x i) + (%bignum-ref truncate-x i-1) + (%bignum-ref truncate-x i-2)) + len-y low-x-digit)) + (cond ((zerop k) (return)) + (t (decf k) + (decf low-x-digit) + (shiftf i i-1 i-2 (1- i-2))))) q)) - ;;; This takes a digit guess, multiplies it by TRUNCATE-Y for a - ;;; result one greater in length than LEN-Y, and subtracts this result - ;;; from TRUNCATE-X. LOW-X-DIGIT is the first digit of X to start - ;;; the subtraction, and we know X is long enough to subtract a LEN-Y - ;;; plus one length bignum from it. Next we check the result of the - ;;; subtraction, and if the high digit in X became negative, then our - ;;; guess was one too big. In this case, return one less than GUESS - ;;; passed in, and add one value of Y back into X to account for - ;;; subtracting one too many. Knuth shows that the guess is wrong on - ;;; the order of 3/b, where b is the base (2 to the digit-size power) - ;;; -- pretty rarely. + ;; This takes a digit guess, multiplies it by TRUNCATE-Y for a + ;; result one greater in length than LEN-Y, and subtracts this result + ;; from TRUNCATE-X. LOW-X-DIGIT is the first digit of X to start + ;; the subtraction, and we know X is long enough to subtract a LEN-Y + ;; plus one length bignum from it. Next we check the result of the + ;; subtraction, and if the high digit in X became negative, then our + ;; guess was one too big. In this case, return one less than GUESS + ;; passed in, and add one value of Y back into X to account for + ;; subtracting one too many. Knuth shows that the guess is wrong on + ;; the order of 3/b, where b is the base (2 to the digit-size power) + ;; -- pretty rarely. (try-bignum-truncate-guess (guess len-y low-x-digit) (declare (type bignum-index low-x-digit) (type bignum-length len-y) @@ -1776,33 +1833,33 @@ (%add-with-carry (%bignum-ref truncate-x i) 0 carry))) (%subtract-with-borrow guess 1 1))))) - ;;; This returns the amount to shift y to place a one in the - ;;; second highest bit. Y must be positive. If the last digit - ;;; of y is zero, then y has a one in the previous digit's - ;;; sign bit, so we know it will take one less than digit-size - ;;; to get a one where we want. Otherwise, we count how many - ;;; right shifts it takes to get zero; subtracting this value - ;;; from digit-size tells us how many high zeros there are - ;;; which is one more than the shift amount sought. - ;;; - ;;; Note: This is exactly the same as one less than the - ;;; integer-length of the last digit subtracted from the - ;;; digit-size. - ;;; - ;;; We shift y to make it sufficiently large that doing the - ;;; 2*digit-size by digit-size %BIGFLOOR calls ensures the quotient and - ;;; remainder fit in digit-size. + ;; This returns the amount to shift y to place a one in the + ;; second highest bit. Y must be positive. If the last digit + ;; of y is zero, then y has a one in the previous digit's + ;; sign bit, so we know it will take one less than digit-size + ;; to get a one where we want. Otherwise, we count how many + ;; right shifts it takes to get zero; subtracting this value + ;; from digit-size tells us how many high zeros there are + ;; which is one more than the shift amount sought. + ;; + ;; Note: This is exactly the same as one less than the + ;; integer-length of the last digit subtracted from the + ;; digit-size. + ;; + ;; We shift y to make it sufficiently large that doing the + ;; 2*digit-size by digit-size %BIGFLOOR calls ensures the quotient and + ;; remainder fit in digit-size. (shift-y-for-truncate (y) (let* ((len (%bignum-length y)) (last (%bignum-ref y (1- len)))) (declare (type bignum-length len) (type bignum-element-type last)) (- digit-size (integer-length last) 1))) - ;;; Stores two bignums into the truncation bignum buffers, - ;;; shifting them on the way in. This assumes x and y are - ;;; positive and at least two in length, and it assumes - ;;; truncate-x and truncate-y are one digit longer than x and - ;;; y. + ;; Stores two bignums into the truncation bignum buffers, + ;; shifting them on the way in. This assumes x and y are + ;; positive and at least two in length, and it assumes + ;; truncate-x and truncate-y are one digit longer than x and + ;; y. (shift-and-store-truncate-buffers (x len-x y len-y shift) (declare (type bignum-length len-x len-y) (type (integer 0 (#.digit-size)) shift)) @@ -1814,13 +1871,13 @@ truncate-x) (bignum-ashift-left-unaligned y 0 shift (1+ len-y) truncate-y))))) ;; LABELS - ;;; Divide X by Y returning the quotient and remainder. In the - ;;; general case, we shift Y to set up for the algorithm, and we - ;;; use two buffers to save consing intermediate values. X gets - ;;; destructively modified to become the remainder, and we have - ;;; to shift it to account for the initial Y shift. After we - ;;; multiple bind q and r, we first fix up the signs and then - ;;; return the normalized results. + ;; Divide X by Y returning the quotient and remainder. In the + ;; general case, we shift Y to set up for the algorithm, and we + ;; use two buffers to save consing intermediate values. X gets + ;; destructively modified to become the remainder, and we have + ;; to shift it to account for the initial Y shift. After we + ;; multiple bind q and r, we first fix up the signs and then + ;; return the normalized results. (let* ((x-plusp (bignum-plus-p x)) (y-plusp (bignum-plus-p y)) (x (if x-plusp x (negate-bignum x nil))) @@ -1828,17 +1885,17 @@ (len-x (%bignum-length x)) (len-y (%bignum-length y))) (multiple-value-bind (q r) - (cond ((< len-y 2) - (bignum-truncate-single-digit x len-x y)) - ((plusp (bignum-compare y x)) + (cond ((plusp (bignum-compare y x)) (let ((res (%allocate-bignum len-x))) (dotimes (i len-x) (setf (%bignum-ref res i) (%bignum-ref x i))) (values 0 res))) (t (let ((len-x+1 (1+ len-x))) - (setf truncate-x (%allocate-bignum len-x+1)) - (setf truncate-y (%allocate-bignum (1+ len-y))) + ;; TODO: someone who understands this algorithm could probably figure out + ;; whether these allocations can prezero fewer words. + (setf truncate-x (alloc-zeroing len-x+1)) + (setf truncate-y (alloc-zeroing (1+ len-y))) (let ((y-shift (shift-y-for-truncate y))) (shift-and-store-truncate-buffers x len-x y len-y y-shift) @@ -1874,68 +1931,100 @@ (if (typep rem 'fixnum) rem (%normalize-bignum rem (%bignum-length rem)))))))))) - -;;;; general utilities - -;;; Internal in-place operations use this to fixup remaining digits in the -;;; incoming data, such as in-place shifting. This is basically the same as -;;; the first form in %NORMALIZE-BIGNUM, but we return the length of the buffer -;;; instead of shrinking the bignum. -#-sb-fluid (declaim (maybe-inline %normalize-bignum-buffer)) -(defun %normalize-bignum-buffer (result len) - (declare (type bignum result) - (type bignum-length len)) - (unless (= len 1) - (do ((next-digit (%bignum-ref result (- len 2)) - (%bignum-ref result (- len 2))) - (sign-digit (%bignum-ref result (1- len)) next-digit)) - ((not (zerop (logxor sign-digit (%ashr next-digit (1- digit-size)))))) - (decf len) - (setf (%bignum-ref result len) 0) - (when (= len 1) - (return)))) - len) - -;;; This drops the last digit if it is unnecessary sign information. It repeats -;;; this as needed, possibly ending with a fixnum. If the resulting length from -;;; shrinking is one, see whether our one word is a fixnum. Shift the possible -;;; fixnum bits completely out of the word, and compare this with shifting the -;;; sign bit all the way through. If the bits are all 1's or 0's in both words, -;;; then there are just sign bits between the fixnum bits and the sign bit. If -;;; we do have a fixnum, shift it over for the two low-tag bits. -(defun %normalize-bignum (result len) - (declare (type bignum result) - (type bignum-length len) - (muffle-conditions compiler-note) - #-sb-fluid (inline %normalize-bignum-buffer)) - (let ((newlen (%normalize-bignum-buffer result len))) - (declare (type bignum-length newlen)) - (unless (= newlen len) - (%bignum-set-length result newlen)) - (if (= newlen 1) - (let ((digit (%bignum-ref result 0))) - (if (= (%ashr digit sb-vm:n-positive-fixnum-bits) - (%ashr digit (1- digit-size))) - (%fixnum-digit-with-correct-sign digit) - result)) - result))) -;;; This drops the last digit if it is unnecessary sign information. It -;;; repeats this as needed, possibly ending with a fixnum magnitude but never -;;; returning a fixnum. -(defun %mostly-normalize-bignum (result len) - (declare (type bignum result) - (type bignum-length len) - #-sb-fluid (inline %normalize-bignum-buffer)) - (let ((newlen (%normalize-bignum-buffer result len))) - (declare (type bignum-length newlen)) - (unless (= newlen len) - (%bignum-set-length result newlen)) - result)) +;;; Divide X by Y when Y fits in a word. +(defun bignum-truncate-single-digit (x y) + (declare (type bignum x) + (type (or word sb-vm:signed-word) y) + (optimize (safety 0))) + (declare (muffle-conditions compiler-note)) ; returns lispobj, so what. + (labels + ((bignum-truncate-single-digit (x len-x y) + (declare (type bignum-length len-x) + (type word y)) + (if (not (logtest y (1- y))) + ;; Y is a power of two. + ;; SHIFT-RIGHT-UNALIGNED won't do the right thing + ;; with a shift count of 0 or -1, so special case this. + (cond ((= y 0) + (error 'division-by-zero :operation 'truncate + :operands (list x y))) + ((= y 1) + ;; We could probably get away with (VALUES X 0) + ;; here, but it's not clear that some of the + ;; normalization logic further down would avoid + ;; mutilating X. Just go ahead and cons, consing's + ;; cheap. + (values (copy-bignum x len-x) 0)) + (t + (let ((n-bits (1- (integer-length y)))) + (values + (shift-right-unaligned x 0 n-bits len-x + ((= j res-len-1) + (setf (%bignum-ref res j) + (%ashr (%bignum-ref x i) n-bits)) + res) + res) + (logand (%bignum-ref x 0) (1- y)))))) + (cond ((sb-c::when-vop-existsp (:translate %half-bigfloor) + (typep y 'half-bignum-element-type)) + (do ((i (1- (* len-x 2)) (1- i)) + (q (%allocate-bignum len-x)) + (r 0)) + ((minusp i) + (values q r)) + (declare (type half-bignum-element-type r)) + (multiple-value-bind (q-digit r-digit) + (%half-bigfloor r (%half-bignum-ref x i) y) + (declare (type half-bignum-element-type q-digit r-digit)) + (setf (%half-bignum-ref q i) q-digit) + (setf r r-digit)))) + (t + (do ((i (1- len-x) (1- i)) + (q (%allocate-bignum len-x)) + (r 0)) + ((minusp i) + (values q r)) + (declare (type bignum-element-type r)) + (multiple-value-bind (q-digit r-digit) + (%bigfloor r (%bignum-ref x i) y) + (declare (type bignum-element-type q-digit r-digit)) + (setf (%bignum-ref q i) q-digit) + (setf r r-digit)))))))) + (let* ((x-plusp (bignum-plus-p x)) + (y-plusp t) + (x (if x-plusp x (negate-bignum x nil))) + (y (typecase y + (fixnum + (cond ((minusp y) + (setf y-plusp nil) + (- y)) + (t + y))) + (sb-vm:signed-word + (cond ((minusp y) + (setf y-plusp nil) + (the word (- y))) + (t + y))) + (t + y))) + (len-x (%bignum-length x))) + (declare (word y)) + (multiple-value-bind (q r) + (bignum-truncate-single-digit x len-x y) + (let ((quotient (cond ((eq x-plusp y-plusp) q) + (t (negate-bignum-in-place q)))) + (rem (cond (x-plusp r) + ((typep r 'fixnum) (the fixnum (- r))) + (t (- r))))) + (values (%normalize-bignum quotient (%bignum-length quotient)) + rem)))))) ;;;; hashing ;;; the bignum case of the SXHASH function +;;; Needs to be synchronized with sxhash-bignum-double-float (defun sxhash-bignum (x) (let ((result 316495330)) (declare (type fixnum result)) @@ -1943,7 +2032,7 @@ (declare (type index i)) (let ((xi (%bignum-ref x i))) (mixf result - (logand sb-xc:most-positive-fixnum + (logand most-positive-fixnum (logxor xi (ash xi -7)))))) result)) @@ -1956,3 +2045,39 @@ (clear-info :function :inlining-data s) (clear-info :function :inlinep s) (clear-info :source-location :declaration s)) + +;;; Return T if the least significant N-BITS bits of BIGNUM are all +;;; zero, else NIL. If the integer-length of BIGNUM is less than N-BITS, +;;; the result is NIL, too. +(declaim (inline bignum-lower-bits-zero-p)) +(defun bignum-lower-bits-zero-p (bignum n-bits) + (declare (type bignum bignum) + (type bit-index n-bits)) + (multiple-value-bind (n-full-digits n-bits-partial-digit) + (floor n-bits digit-size) + (declare (type bignum-length n-full-digits)) + (when (> (%bignum-length bignum) n-full-digits) + (dotimes (index n-full-digits) + (declare (type bignum-index index)) + (unless (zerop (%bignum-ref bignum index)) + (return-from bignum-lower-bits-zero-p nil))) + (zerop (logand (1- (ash 1 n-bits-partial-digit)) + (%bignum-ref bignum n-full-digits)))))) + +#| +(let (code-components) + (do-symbols (s 'sb-bignum) + (when (and (fboundp s) + (eq (symbol-package s) (find-package "SB-BIGNUM"))) + (pushnew (sb-kernel:fun-code-header (symbol-function s)) code-components))) + (let ((tot-size 0) (tot-consts 0)) + (dolist (code code-components) + (let ((nconsts (sb-kernel:code-header-words code)) + (size (sb-ext:primitive-object-size code))) + (incf tot-size size) + (incf tot-consts nconsts) + (format t "~5d ~3d ~a~%" size nconsts code))) + (format t "~5d ~3d~%" tot-size tot-consts))) +; => 32208 565 ; without block-compile +; => 23184 214 ; with block-compile in normal self-build +|# diff --git a/src/code/bit-bash.lisp b/src/code/bit-bash.lisp index 9f403a790b..8a3fae7b88 100644 --- a/src/code/bit-bash.lisp +++ b/src/code/bit-bash.lisp @@ -10,73 +10,10 @@ ;;;; files for more information. (in-package "SB-VM") - -;;;; types - -(eval-when (:compile-toplevel) - ;; This DEFTYPE must be macroexpanded directly by the host, as it is referenced by - ;; a defun that is also within an eval-when. Writing the eval-when situations as - ;; (:COMPILE-TOPLEVEL :LOAD-TOPLEVEL) isn't good enough, because that expands only - ;; by the cross-compiler. In reality this type isn't technically helpful to have, - ;; because both its uses are in an LDB expression whose type is trivially derivable. - ;; However I'm keeping it as a minimal example of a tricky cross-compilation issue. - (deftype bit-offset () `(integer 0 (,n-word-bits)))) -(deftype bit-offset () `(integer 0 (,n-word-bits))) ;;;; support routines -;;; A particular implementation must offer either VOPs to translate -;;; these, or DEFTRANSFORMs to convert them into something supported -;;; by the architecture. -(macrolet ((def (name &rest args) - `(defun ,name ,args - (,name ,@args)))) - (def word-logical-not x) - (def word-logical-and x y) - (def word-logical-or x y) - (def word-logical-xor x y) - (def word-logical-nor x y) - (def word-logical-eqv x y) - (def word-logical-nand x y) - (def word-logical-andc1 x y) - (def word-logical-andc2 x y) - (def word-logical-orc1 x y) - (def word-logical-orc2 x y)) - -;;; Shift NUMBER by the low-order bits of COUNTOID, adding zero bits -;;; at the "end" and removing bits from the "start". On big-endian -;;; machines this is a left-shift and on little-endian machines this -;;; is a right-shift. -(eval-when (:compile-toplevel :load-toplevel :execute) - (defun shift-towards-start (number countoid) - (declare (type word number) (fixnum countoid)) - (let ((count (ldb (byte (1- (integer-length n-word-bits)) 0) countoid))) - (declare (type bit-offset count)) - (if (zerop count) - number - (ecase sb-c:*backend-byte-order* - (:big-endian - (ash (ldb (byte (- n-word-bits count) 0) number) count)) - (:little-endian - (ash number (- count)))))))) - -;;; Shift NUMBER by COUNT bits, adding zero bits at the "start" and -;;; removing bits from the "end". On big-endian machines this is a -;;; right-shift and on little-endian machines this is a left-shift. -(eval-when (:compile-toplevel :load-toplevel :execute) - (defun shift-towards-end (number count) - (declare (type word number) (fixnum count)) - (let ((count (ldb (byte (1- (integer-length n-word-bits)) 0) count))) - (declare (type bit-offset count)) - (if (zerop count) - number - (ecase sb-c:*backend-byte-order* - (:big-endian - (ash number (- count))) - (:little-endian - (ash (ldb (byte (- n-word-bits count) 0) number) count))))))) - -#-sb-fluid (declaim (inline start-mask end-mask)) +(declaim (inline start-mask end-mask)) ;;; Produce a mask that contains 1's for the COUNT "start" bits and ;;; 0's for the remaining "end" bits. Only the lower 5 bits of COUNT @@ -94,64 +31,199 @@ (declare (fixnum count)) (shift-towards-end most-positive-word (- count))) -#-sb-fluid (declaim (inline word-sap-ref %set-word-sap-ref)) -(defun word-sap-ref (sap offset) - (declare (type system-area-pointer sap) - (type index offset) - (muffle-conditions compiler-note) ; "unsigned word to integer coercion" - (optimize (speed 3) (safety 0))) - (sap-ref-word sap (the index (ash offset word-shift)))) -(defun %set-word-sap-ref (sap offset value) - (declare (type system-area-pointer sap) - (type index offset) - (type word value) - (muffle-conditions compiler-note) ; "unsigned word to integer coercion" - (optimize (speed 3) (safety 0))) - (setf (sap-ref-word sap (the index (ash offset word-shift))) - value)) - ;;; the actual bashers and common uses of same -;;; This is a little ugly. Fixing bug 188 would bring the ability to -;;; wrap a MACROLET or something similar around this whole thing would -;;; make things significantly less ugly. --njf, 2005-02-23 -;;; -;;; Well, it turns out that we *could* wrap a MACROLET around this, -;;; but it's quite ugly in a different way: when you write -;;; (MACROLET ((GENERATOR () `(DEFUN F (X) ,@(INSANITY ...))) (GENERATOR))) -;;; and then view the inline expansion of F, you'll see it has actually -;;; captured the entirety of the MACROLET that surrounded it. -;;; With respect to building SBCL, this means, among other things, that -;;; it'd hang onto all the "!" symbols that would otherwise disappear, -;;; as well as kilobytes of completely useless s-expressions. (eval-when (:compile-toplevel :load-toplevel :execute) - -;;; Align the SAP to a word boundary, and update the offset accordingly. -(defmacro !define-sap-fixer (bitsize) - (let ((name (intern (format nil "FIX-SAP-AND-OFFSET-UB~D" bitsize)))) - `(progn - (declaim (inline ,name)) - (defun ,name (sap offset) - (declare (type system-area-pointer sap) - (type index offset) - (values system-area-pointer index)) - (let ((address (sap-int sap)) - (word-mask (1- (ash 1 word-shift)))) - (values (int-sap #-alpha (word-logical-andc2 address word-mask) - ;; KLUDGE: WORD-LOGICAL-ANDC2 is defined in - ;; terms of n-word-bits. On all systems - ;; where n-word-bits is not equal to - ;; n-machine-word-bits we have to do this - ;; another way. At this time, these - ;; systems are alphas, though there was - ;; some talk about an x86-64 build option. - #+alpha (ash (ash address (- word-shift)) word-shift)) - (+ ,(ecase bitsize - ((1 2 4) `(* (logand address word-mask) - (/ n-byte-bits ,bitsize))) - ((8 16 32 64) '(logand address word-mask))) - offset))))))) + (defconstant min-bytes-c-call-threshold + ;; mostly just guessing here + #+(or x86 x86-64 ppc ppc64) 128 + #-(or x86 x86-64 ppc ppc64) 256)) + +(defmacro verify-src/dst-bits-per-elt (source destination expect-bits-per-element) + (declare (ignorable source destination expect-bits-per-element)) + #+(and sb-devel (not sb-devel-no-errors)) + `(let ((src-bits-per-element + (ash 1 (aref #.%%simple-array-n-bits-shifts%% + (%other-pointer-widetag ,source)))) + (dst-bits-per-element + (ash 1 (aref #.%%simple-array-n-bits-shifts%% + (%other-pointer-widetag ,destination))))) + (when (or (/= src-bits-per-element ,expect-bits-per-element) + (/= dst-bits-per-element ,expect-bits-per-element)) + ;; Why enforce this: because since the arrays are lisp objects + ;; maybe we can be clever "somehow" (I'm not sure how) + ;; and/or maybe we have to unpoison the memory for #+ubsan. + ;; Whereas BYTE-BLT takes SAPs (and/or arrays) and so it has to + ;; be more strictly like memmove(). Because it is exactly that. + (error "Misuse of bash-copy: bits-per-elt=~D but src=~d and dst=~d" + ,expect-bits-per-element src-bits-per-element dst-bits-per-element)))) + +;;; 1, 2, 4, and 8 bytes per element can be handled with memmove() +;;; or, if it's easy enough, a loop over VECTOR-RAW-BITS. +(defmacro define-byte-blt-copier + (bytes-per-element + &aux (bits-per-element (* bytes-per-element 8)) + (vtype `(simple-array (unsigned-byte ,bits-per-element) (*))) + (elements-per-word (/ n-word-bytes bytes-per-element)) + (always-call-out-p ; memmove() is _always_ asymptotically faster than this + ;; code, which can't make any use of vectorization that C libraries + ;; typically do. It's a question of the overhead of a C call. + `(>= nelements ,(/ min-bytes-c-call-threshold bytes-per-element)))) + (flet ((backward-p () + ;; Iterate backwards if there is overlap and byte transfer is toward higher + ;; addresses. Technically (> dst-start src-start) is a necessary + ;; but not sufficient condition for overlap, but it's fine. + '(and (eq src dst) (> dst-start src-start))) + (down () + ;; We could reduce the number of loop variables by 1 by computing + ;; the distance between src-start and dst-start, and adding it in + ;; to each array reference. Probably it would be worse though. + '(do ((dst-index (the (or (eql -1) index) (+ dst-start nwords -1)) + (1- dst-index)) + (src-index (the (or (eql -1) index) (+ src-start nwords -1)) + (1- src-index))) + ((< dst-index dst-start)) + (declare (type (or (eql -1) index) dst-index src-index)) + ;; Assigning into SRC is right, because DST and SRC are the same array. + ;; We don't need "both" arrays to be in registers. + (%set-vector-raw-bits src dst-index + (%vector-raw-bits src (the index src-index))))) + (up () + '(do ((dst-index dst-start (the index (1+ dst-index))) + (src-index src-start (the index (1+ src-index)))) + ((>= dst-index dst-end)) + (%set-vector-raw-bits dst dst-index (%vector-raw-bits src src-index)))) + (use-memmove () + ;; %BYTE-BLT wants the end as an index, which it converts back to a count + ;; by subtracting the start. Regardless, the args are way too confusing, + ;; so let's go directly to memmove. Cribbed from (DEFTRANSFORM %BYTE-BLT) + `(with-pinned-objects (dst src) + (memmove (sap+ (vector-sap (the ,vtype dst)) + (the signed-word (* dst-start ,bytes-per-element))) + (sap+ (vector-sap (the ,vtype src)) + (the signed-word (* src-start ,bytes-per-element))) + (the word (* nelements ,bytes-per-element)))))) + ;; The arguments are array element indices. + `(defun ,(intern (format nil "UB~D-BASH-COPY" bits-per-element) + (find-package "SB-KERNEL")) + (src src-start dst dst-start nelements) + (declare (type index src-start dst-start nelements)) + (verify-src/dst-bits-per-elt src dst ,bits-per-element) + (locally + (declare (optimize (safety 0) + (sb-c::alien-funcall-saves-fp-and-pc 0))) + #+cheneygc (when (> nelements 0) + ;; cheneygc can't handle a WP fault in memcpy() + ;; because "if(!foreign_function_call_active ..." + (let ((last (truly-the index (+ dst-start (1- nelements))))) + (data-vector-set (truly-the ,vtype dst) last + (data-vector-ref (truly-the ,vtype dst) last)))) + ,(if (= bytes-per-element sb-vm:n-word-bytes) + `(if ,always-call-out-p + ,(use-memmove) + (let ((nwords nelements)) + (if ,(backward-p) + ,(down) + (let ((dst-end (the index (+ dst-start nelements)))) + ,(up))))) + `(let ((dst-subword (mod dst-start ,elements-per-word)) + (src-subword (mod src-start ,elements-per-word)) + (dst (truly-the ,vtype dst)) + (src (truly-the ,vtype src))) + (cond ((or ,always-call-out-p + (/= dst-subword src-subword)) ; too complicated + ,(use-memmove)) + (,(backward-p) + ;; Using the primitive-type-specific data-vector-set, + ;; process at most (1- ELEMENTS-PER-WORD) elements + ;; until aligned to a word. + (let ((dst-end (+ dst-start nelements)) + (src-end (+ src-start nelements)) + (original-nelements nelements)) + ,@(let (initial) + (loop for i downfrom (- elements-per-word 1) + repeat (1- elements-per-word) + do (setq initial + ;; Test NELEMENTS first because it should be in a register + ;; from the preceding DECF. + `((when (and (/= nelements 0) + (logtest dst-end ,(1- elements-per-word))) + (data-vector-set dst (1- dst-end) + (data-vector-ref src (- src-end ,i))) + (decf (the index dst-end)) + (decf (the index nelements)) + ,@initial)))) + initial) + (decf src-end (the (mod 8) (- original-nelements nelements))) + ;; Now DST-END and SRC-END are element indices that start a word. + ;; Scan backwards by whole words. + (let ((nwords (truncate nelements ,elements-per-word))) + (when (plusp nwords) + ;; Convert to word indices + (let* ((dst-start (- (truncate dst-end ,elements-per-word) nwords)) + (src-start (- (truncate src-end ,elements-per-word) nwords))) + ,(down)) + (decf (the index dst-end) (* nwords ,elements-per-word)) + (decf (the index src-end) (* nwords ,elements-per-word)) + (decf nelements (* nwords ,elements-per-word)))) + ;; If there are elements remaining after the last full word copied, + ;; process element by element. + ,@(let (final) + (loop for i from (1- elements-per-word) downto 1 + do (setq final + `((unless (= nelements 0) + (data-vector-set + dst (- dst-end ,i) + (data-vector-ref src (- src-end ,i))) + ,@(unless (= i (1- elements-per-word)) + '((decf (the index nelements)))) + ,@final)))) + final))) + (t + ;; Same as above + (let ((original-nelements nelements)) + ,@(let (initial) + (loop for i downfrom (- elements-per-word 2) + repeat (1- elements-per-word) + do (setq initial + `((when (and (/= nelements 0) + (logtest dst-start ,(1- elements-per-word))) + (data-vector-set + dst dst-start + (data-vector-ref src (+ src-start ,i))) + (incf (the index dst-start)) + (decf (the index nelements)) + ,@initial)))) + initial) + (incf (the index src-start) (- original-nelements nelements))) + (let ((nwords (truncate nelements ,elements-per-word))) + (when (plusp nwords) + (let* ((src-start (truncate src-start ,elements-per-word)) + (dst-start (truncate dst-start ,elements-per-word)) + (dst-end (the index (+ dst-start nwords)))) + ,(up)) + (incf dst-start (* nwords ,elements-per-word)) + (incf src-start (* nwords ,elements-per-word)) + (decf nelements (* nwords ,elements-per-word)))) + ;; Same as above + ,@(let (final) + (loop for i from (- elements-per-word 2) downto 0 + do (setq final + `((unless (= nelements 0) + (data-vector-set + dst (+ dst-start ,i) + (data-vector-ref src (+ src-start ,i))) + ,@(unless (= i (- elements-per-word 2)) + '((decf (the index nelements)))) + ,@final)))) + final))))) + (values))))) + +(define-byte-blt-copier 1) +(define-byte-blt-copier 2) +(define-byte-blt-copier 4) +#+64-bit (define-byte-blt-copier 8) ;;; We cheat a little bit by using TRULY-THE in the copying function to ;;; force the compiler to generate good code in the (= BITSIZE @@ -160,27 +232,17 @@ (defmacro !define-byte-bashers (bitsize) (let* ((bytes-per-word (/ n-word-bits bitsize)) (byte-offset `(integer 0 (,bytes-per-word))) - (word-offset `(integer 0 ,(ceiling sb-xc:array-dimension-limit bytes-per-word))) - (fix-sap-and-offset-name (intern (format nil "FIX-SAP-AND-OFFSET-UB~D" bitsize))) + (word-offset `(integer 0 ,(ceiling array-dimension-limit bytes-per-word))) (constant-bash-name (intern (format nil "CONSTANT-UB~D-BASH" bitsize) (find-package "SB-KERNEL"))) (array-fill-name (intern (format nil "UB~D-BASH-FILL" bitsize) (find-package "SB-KERNEL"))) - (system-area-fill-name (intern (format nil "SYSTEM-AREA-UB~D-FILL" bitsize) (find-package "SB-KERNEL"))) (unary-bash-name (intern (format nil "UNARY-UB~D-BASH" bitsize) (find-package "SB-KERNEL"))) - (array-copy-name (intern (format nil "UB~D-BASH-COPY" bitsize) (find-package "SB-KERNEL"))) - (system-area-copy-name (intern (format nil "SYSTEM-AREA-UB~D-COPY" bitsize) (find-package "SB-KERNEL"))) - (array-copy-to-system-area-name - (intern (format nil "COPY-UB~D-TO-SYSTEM-AREA" bitsize) (find-package "SB-KERNEL"))) - (system-area-copy-to-array-name - (intern (format nil "COPY-UB~D-FROM-SYSTEM-AREA" bitsize) - (find-package "SB-KERNEL")))) + (array-copy-name (intern (format nil "UB~D-BASH-COPY" bitsize) (find-package "SB-KERNEL")))) `(progn - (declaim (inline ,constant-bash-name ,unary-bash-name)) + (declaim (inline ,constant-bash-name)) ;; Fill DST with VALUE starting at DST-OFFSET and continuing ;; for LENGTH bytes (however bytes are defined). - (defun ,constant-bash-name (dst dst-offset length value - dst-ref-fn dst-set-fn) + (defun ,constant-bash-name (dst dst-offset length value) (declare (type word value) (type index dst-offset length)) - (declare (ignorable dst-ref-fn)) (multiple-value-bind (dst-word-offset dst-byte-offset) (floor dst-offset ,bytes-per-word) (declare (type ,word-offset dst-word-offset) @@ -192,40 +254,40 @@ (if (zerop n-words) ,(unless (= bytes-per-word 1) `(unless (zerop length) - (funcall dst-set-fn dst dst-word-offset + (%set-vector-raw-bits dst dst-word-offset (if (>= length ,bytes-per-word) value (let ((mask (shift-towards-end (start-mask (* length ,bitsize)) (* dst-byte-offset ,bitsize)))) (word-logical-or (word-logical-and value mask) - (word-logical-andc2 (funcall dst-ref-fn dst dst-word-offset) + (word-logical-andc2 (%vector-raw-bits dst dst-word-offset) mask))))))) (let ((interior (floor (- length final-bytes) ,bytes-per-word))) ,@(unless (= bytes-per-word 1) `((unless (zerop dst-byte-offset) (let ((mask (end-mask (* (- dst-byte-offset) ,bitsize)))) - (funcall dst-set-fn dst dst-word-offset + (%set-vector-raw-bits dst dst-word-offset (word-logical-or (word-logical-and value mask) - (word-logical-andc2 (funcall dst-ref-fn dst dst-word-offset) + (word-logical-andc2 (%vector-raw-bits dst dst-word-offset) mask)))) (incf dst-word-offset)))) (let ((end (+ dst-word-offset interior))) (declare (type ,word-offset end)) (do () ((>= dst-word-offset end)) - (funcall dst-set-fn dst dst-word-offset value) + (%set-vector-raw-bits dst dst-word-offset value) (incf dst-word-offset))) #+nil (dotimes (i interior) - (funcall dst-set-fn dst dst-word-offset value) + (%set-vector-raw-bits dst dst-word-offset value) (incf dst-word-offset)) ,@(unless (= bytes-per-word 1) `((unless (zerop final-bytes) (let ((mask (start-mask (* final-bytes ,bitsize)))) - (funcall dst-set-fn dst dst-word-offset + (%set-vector-raw-bits dst dst-word-offset (word-logical-or (word-logical-and value mask) - (word-logical-andc2 (funcall dst-ref-fn dst dst-word-offset) + (word-logical-andc2 (%vector-raw-bits dst dst-word-offset) mask))))))))))) (values)) @@ -238,22 +300,15 @@ (defun ,array-fill-name (value dst dst-offset length) (declare (type word value) (type index dst-offset length)) (declare (optimize (speed 3) (safety 1))) - (,constant-bash-name dst dst-offset length value - #'%vector-raw-bits #'%set-vector-raw-bits) + (,constant-bash-name dst dst-offset length value) dst) - (defun ,system-area-fill-name (value dst dst-offset length) - (declare (type word value) (type index dst-offset length)) - (declare (optimize (speed 3) (safety 1))) - (multiple-value-bind (dst dst-offset) (,fix-sap-and-offset-name dst dst-offset) - (,constant-bash-name dst dst-offset length value - #'word-sap-ref #'%set-word-sap-ref))) - - ;; unary byte bashing (copying) - (defun ,unary-bash-name (src src-offset dst dst-offset length - dst-ref-fn dst-set-fn src-ref-fn) - (declare (type index src-offset dst-offset length) - (type function dst-ref-fn dst-set-fn src-ref-fn) - (ignorable dst-ref-fn)) + + ;; Copying. Never use this for 8, 16, 32, 64 + ,@(when (member bitsize '(1 2 4)) + `((declaim (inline ,unary-bash-name)) + (defun ,unary-bash-name (src src-offset dst dst-offset length) + (declare (type index src-offset dst-offset length)) + (verify-src/dst-bits-per-elt src dst ,bitsize) (multiple-value-bind (dst-word-offset dst-byte-offset) (floor dst-offset ,bytes-per-word) (declare (type ,word-offset dst-word-offset) @@ -276,16 +331,16 @@ ;; writing multiple words. If SRC-BYTE-OFFSET is also zero, ;; the we just transfer the single word. Otherwise we have ;; to extract bytes from two source words. - (funcall dst-set-fn dst dst-word-offset + (%set-vector-raw-bits dst dst-word-offset (cond ((zerop src-byte-offset) - (funcall src-ref-fn src src-word-offset)) + (%vector-raw-bits src src-word-offset)) ,@(unless (= bytes-per-word 1) `((t (word-logical-or (shift-towards-start - (funcall src-ref-fn src src-word-offset) + (%vector-raw-bits src src-word-offset) (* src-byte-offset ,bitsize)) (shift-towards-end - (funcall src-ref-fn src (1+ src-word-offset)) + (%vector-raw-bits src (1+ src-word-offset)) (* (- src-byte-offset) ,bitsize))))))))) ,@(unless (= bytes-per-word 1) `((t @@ -293,7 +348,7 @@ ;; We still don't know whether we need one or two source words. (let ((mask (shift-towards-end (start-mask (* length ,bitsize)) (* dst-byte-offset ,bitsize))) - (orig (funcall dst-ref-fn dst dst-word-offset)) + (orig (%vector-raw-bits dst dst-word-offset)) (value (if (> src-byte-offset dst-byte-offset) ;; The source starts further ;; into the word than does the @@ -308,12 +363,12 @@ (if (> (+ src-byte-offset length) ,bytes-per-word) (word-logical-or (shift-towards-start - (funcall src-ref-fn src src-word-offset) + (%vector-raw-bits src src-word-offset) (* src-byte-shift ,bitsize)) (shift-towards-end - (funcall src-ref-fn src (1+ src-word-offset)) + (%vector-raw-bits src (1+ src-word-offset)) (* (- src-byte-shift) ,bitsize))) - (shift-towards-start (funcall src-ref-fn src src-word-offset) + (shift-towards-start (%vector-raw-bits src src-word-offset) (* src-byte-shift ,bitsize)))) ;; The destination starts further ;; into the word than does the @@ -323,10 +378,10 @@ ;; would too, and we wouldn't be ;; in this branch). (shift-towards-end - (funcall src-ref-fn src src-word-offset) + (%vector-raw-bits src src-word-offset) (* (- dst-byte-offset src-byte-offset) ,bitsize))))) (declare (type word mask orig value)) - (funcall dst-set-fn dst dst-word-offset + (%set-vector-raw-bits dst dst-word-offset (word-logical-or (word-logical-and value mask) (word-logical-andc2 orig mask))))))))) ((= src-byte-offset dst-byte-offset) @@ -348,10 +403,10 @@ ;; We are only writing part of the first word, so mask ;; off the bytes we want to preserve. (let ((mask (end-mask (* (- dst-byte-offset) ,bitsize))) - (orig (funcall dst-ref-fn dst dst-word-offset)) - (value (funcall src-ref-fn src src-word-offset))) + (orig (%vector-raw-bits dst dst-word-offset)) + (value (%vector-raw-bits src src-word-offset))) (declare (type word mask orig value)) - (funcall dst-set-fn dst dst-word-offset + (%set-vector-raw-bits dst dst-word-offset (word-logical-or (word-logical-and value mask) (word-logical-andc2 orig mask)))) (incf src-word-offset) @@ -364,8 +419,8 @@ (declare (type ,word-offset end)) (do () ((>= dst-word-offset end)) - (funcall dst-set-fn dst dst-word-offset - (funcall src-ref-fn src src-word-offset)) + (%set-vector-raw-bits dst dst-word-offset + (%vector-raw-bits src src-word-offset)) ,(if (= bytes-per-word 1) `(setf src-word-offset (truly-the ,word-offset (+ src-word-offset 1))) `(incf src-word-offset)) @@ -374,10 +429,10 @@ `((unless (zerop final-bytes) ;; We are only writing part of the last word. (let ((mask (start-mask (* final-bytes ,bitsize))) - (orig (funcall dst-ref-fn dst dst-word-offset)) - (value (funcall src-ref-fn src src-word-offset))) + (orig (%vector-raw-bits dst dst-word-offset)) + (value (%vector-raw-bits src src-word-offset))) (declare (type word mask orig value)) - (funcall dst-set-fn dst dst-word-offset + (%set-vector-raw-bits dst dst-word-offset (word-logical-or (word-logical-and value mask) (word-logical-andc2 orig mask)))))))) (t @@ -393,10 +448,10 @@ ,@(unless (= bytes-per-word 1) `((unless (zerop final-bytes) (let ((mask (start-mask (* final-bytes ,bitsize))) - (orig (funcall dst-ref-fn dst dst-word-offset)) - (value (funcall src-ref-fn src src-word-offset))) + (orig (%vector-raw-bits dst dst-word-offset)) + (value (%vector-raw-bits src src-word-offset))) (declare (type word mask orig value)) - (funcall dst-set-fn dst dst-word-offset + (%set-vector-raw-bits dst dst-word-offset (word-logical-or (word-logical-and value mask) (word-logical-andc2 orig mask))))))) (let ((end (- dst-word-offset interior))) @@ -404,18 +459,18 @@ ((<= dst-word-offset end)) (decf src-word-offset) (decf dst-word-offset) - (funcall dst-set-fn dst dst-word-offset - (funcall src-ref-fn src src-word-offset)))) + (%set-vector-raw-bits dst dst-word-offset + (%vector-raw-bits src src-word-offset)))) ,@(unless (= bytes-per-word 1) `((unless (zerop dst-byte-offset) ;; We are only writing part of the last word. (decf src-word-offset) (decf dst-word-offset) (let ((mask (end-mask (* (- dst-byte-offset) ,bitsize))) - (orig (funcall dst-ref-fn dst dst-word-offset)) - (value (funcall src-ref-fn src src-word-offset))) + (orig (%vector-raw-bits dst dst-word-offset)) + (value (%vector-raw-bits src src-word-offset))) (declare (type word mask orig value)) - (funcall dst-set-fn dst dst-word-offset + (%set-vector-raw-bits dst dst-word-offset (word-logical-or (word-logical-and value mask) (word-logical-andc2 orig mask)))))))))))) (t @@ -433,11 +488,11 @@ ((<= dst-offset src-offset) ;; We need to loop from left to right. (let ((prev 0) - (next (funcall src-ref-fn src src-word-offset))) + (next (%vector-raw-bits src src-word-offset))) (declare (type word prev next)) (flet ((get-next-src () (setf prev next) - (setf next (funcall src-ref-fn src + (setf next (%vector-raw-bits src (incf src-word-offset))))) (declare (inline get-next-src)) ,@(unless (= bytes-per-word 1) @@ -445,11 +500,11 @@ (when (> src-byte-offset dst-byte-offset) (get-next-src)) (let ((mask (end-mask (* (- dst-byte-offset) ,bitsize))) - (orig (funcall dst-ref-fn dst dst-word-offset)) + (orig (%vector-raw-bits dst dst-word-offset)) (value (word-logical-or (shift-towards-start prev (* src-shift ,bitsize)) (shift-towards-end next (* (- src-shift) ,bitsize))))) (declare (type word mask orig value)) - (funcall dst-set-fn dst dst-word-offset + (%set-vector-raw-bits dst dst-word-offset (word-logical-or (word-logical-and value mask) (word-logical-andc2 orig mask)))) (incf dst-word-offset)))) @@ -462,7 +517,7 @@ (shift-towards-end next (* (- src-shift) ,bitsize)) (shift-towards-start prev (* src-shift ,bitsize))))) (declare (type word value)) - (funcall dst-set-fn dst dst-word-offset value) + (%set-vector-raw-bits dst dst-word-offset value) (incf dst-word-offset)))) ,@(unless (= bytes-per-word 1) `((unless (zerop final-bytes) @@ -475,9 +530,9 @@ (shift-towards-start prev (* src-shift ,bitsize)))) (shift-towards-start next (* src-shift ,bitsize)))) (mask (start-mask (* final-bytes ,bitsize))) - (orig (funcall dst-ref-fn dst dst-word-offset))) + (orig (%vector-raw-bits dst dst-word-offset))) (declare (type word mask orig value)) - (funcall dst-set-fn dst dst-word-offset + (%set-vector-raw-bits dst dst-word-offset (word-logical-or (word-logical-and value mask) (word-logical-andc2 orig mask)))))))))) (t @@ -485,11 +540,11 @@ (incf dst-word-offset words) (incf src-word-offset (1- (ceiling (+ src-byte-offset length) ,bytes-per-word))) (let ((next 0) - (prev (funcall src-ref-fn src src-word-offset))) + (prev (%vector-raw-bits src src-word-offset))) (declare (type word prev next)) (flet ((get-next-src () (setf next prev) - (setf prev (funcall src-ref-fn src (decf src-word-offset))))) + (setf prev (%vector-raw-bits src (decf src-word-offset))))) (declare (inline get-next-src)) ,@(unless (= bytes-per-word 1) `((unless (zerop final-bytes) @@ -499,9 +554,9 @@ (shift-towards-end next (* (- src-shift) ,bitsize)) (shift-towards-start prev (* src-shift ,bitsize)))) (mask (start-mask (* final-bytes ,bitsize))) - (orig (funcall dst-ref-fn dst dst-word-offset))) + (orig (%vector-raw-bits dst dst-word-offset))) (declare (type word mask orig value)) - (funcall dst-set-fn dst dst-word-offset + (%set-vector-raw-bits dst dst-word-offset (word-logical-or (word-logical-and value mask) (word-logical-andc2 orig mask))))))) (decf dst-word-offset) @@ -513,7 +568,7 @@ (shift-towards-end next (* (- src-shift) ,bitsize)) (shift-towards-start prev (* src-shift ,bitsize))))) (declare (type word value)) - (funcall dst-set-fn dst dst-word-offset value) + (%set-vector-raw-bits dst dst-word-offset value) (decf dst-word-offset)))) ,@(unless (= bytes-per-word 1) `((unless (zerop dst-byte-offset) @@ -521,12 +576,12 @@ (get-next-src) (setf next prev prev 0)) (let ((mask (end-mask (* (- dst-byte-offset) ,bitsize))) - (orig (funcall dst-ref-fn dst dst-word-offset)) + (orig (%vector-raw-bits dst dst-word-offset)) (value (word-logical-or (shift-towards-start prev (* src-shift ,bitsize)) (shift-towards-end next (* (- src-shift) ,bitsize))))) (declare (type word mask orig value)) - (funcall dst-set-fn dst dst-word-offset + (%set-vector-raw-bits dst dst-word-offset (word-logical-or (word-logical-and value mask) (word-logical-andc2 orig mask))))))))))))))))) (values)) @@ -535,52 +590,15 @@ (defun ,array-copy-name (src src-offset dst dst-offset length) (declare (type index src-offset dst-offset length)) (locally (declare (optimize (speed 3) (safety 1))) - (,unary-bash-name src src-offset dst dst-offset length - #'%vector-raw-bits - #'%set-vector-raw-bits - #'%vector-raw-bits))) - - (defun ,system-area-copy-name (src src-offset dst dst-offset length) - (declare (type index src-offset dst-offset length)) - (locally (declare (optimize (speed 3) (safety 1))) - (multiple-value-bind (src src-offset) (,fix-sap-and-offset-name src src-offset) - (declare (type system-area-pointer src)) - (multiple-value-bind (dst dst-offset) (,fix-sap-and-offset-name dst dst-offset) - (declare (type system-area-pointer dst)) - (,unary-bash-name src src-offset dst dst-offset length - #'word-sap-ref #'%set-word-sap-ref - #'word-sap-ref))))) - - (defun ,array-copy-to-system-area-name (src src-offset dst dst-offset length) - (declare (type index src-offset dst-offset length)) - (locally (declare (optimize (speed 3) (safety 1))) - (multiple-value-bind (dst dst-offset) (,fix-sap-and-offset-name dst dst-offset) - (,unary-bash-name src src-offset dst dst-offset length - #'word-sap-ref #'%set-word-sap-ref - #'%vector-raw-bits)))) + (,unary-bash-name src src-offset dst dst-offset length)))))))) - (defun ,system-area-copy-to-array-name (src src-offset dst dst-offset length) - (declare (type index src-offset dst-offset length)) - (locally (declare (optimize (speed 3) (safety 1))) - (multiple-value-bind (src src-offset) (,fix-sap-and-offset-name src src-offset) - (,unary-bash-name src src-offset dst dst-offset length - #'%vector-raw-bits - #'%set-vector-raw-bits - #'word-sap-ref))))))) -) ; EVAL-WHEN - -(eval-when (:compile-toplevel) - (sb-xc:proclaim '(muffle-conditions compiler-note))) ;;; We would normally do this with a MACROLET, but then we run into ;;; problems with the lexical environment being too hairy for the ;;; cross-compiler and it cannot inline the basic basher functions. #.(loop for i = 1 then (* i 2) - collect `(!define-sap-fixer ,i) into fixers collect `(!define-byte-bashers ,i) into bashers until (= i n-word-bits) - ;; FIXERS must come first so their inline expansions are available - ;; for the bashers. - finally (return `(progn ,@fixers ,@bashers))) + finally (return `(progn ,@bashers))) (defmacro !define-constant-byte-bashers (bitsize type value-transformer &optional (name type)) (let ((constant-bash-name (intern (format nil "CONSTANT-UB~D-BASH" bitsize) (find-package "SB-KERNEL"))) @@ -594,8 +612,7 @@ (defun ,array-fill-name (value dst dst-offset length) (declare (type ,type value) (type index dst-offset length)) (declare (optimize (speed 3) (safety 1))) - (,constant-bash-name dst dst-offset length (,value-transformer value) - #'%vector-raw-bits #'%set-vector-raw-bits) + (,constant-bash-name dst dst-offset length (,value-transformer value)) dst)))) (macrolet ((def () diff --git a/src/code/brothertree.lisp b/src/code/brothertree.lisp new file mode 100644 index 0000000000..002a3cd954 --- /dev/null +++ b/src/code/brothertree.lisp @@ -0,0 +1,344 @@ +;;;; Pure functional 1-2 brother tree implementation + +;;;; This software is part of the SBCL system. See the README file for +;;;; more information. +;;;; +;;;; This software is derived from the CMU CL system, which was +;;;; written at Carnegie Mellon University and released into the +;;;; public domain. The software is in the public domain and is +;;;; provided with absolutely no warranty. See the COPYING and CREDITS +;;;; files for more information. + +(in-package "SB-BROTHERTREE") + +;;;; Translated from the Haskell code in +;;;; https://www.cs.ox.ac.uk/ralf.hinze/publications/Brother12.pdf + +;(declaim (optimize (sb-c::store-coverage-data 3))) + +(deftype keytype () 'sb-vm:word) + +(defstruct (binary-node (:copier nil) + (:constructor make-binary-node (key %left %right))) + ;; key must be in slot index 0 because fringe binary nodes have only this slot + (key 0 :type keytype) + %left %right) +(defstruct (unary-node (:copier nil) + (:conc-name "") + (:constructor N1 (child))) + ;; unary should not have unary child but it seems like the deletion algorithm + ;; temporarily does that and then eliminates it. + (child nil :type t)) +;;; L2 is a temporary node that gets eliminated by the insertion algorithm. +;;; My guess is that the "2" is supposed to be reminiscent of "binary", +;;; but it's a leaf, a/k/a "external node". +(declaim (inline L2)) +(defun L2 (x) `(leaf . ,x)) +;;; Ternary nodes are temporary and eliminated by the insertion algorithm +(defstruct (ternary-node (:copier nil) + (:constructor N3 (left key1 middle key2 right))) + left key1 middle key2 right) + +(declaim (freeze-type unary-node binary-node ternary-node)) +(eval-when (:compile-toplevel :load-toplevel :execute) + (let ((dd (sb-kernel:find-defstruct-description 'binary-node))) + (setf (sb-kernel:dd-flags dd) (logior (sb-kernel:dd-flags dd) sb-kernel:+dd-varylen+)))) + +;;; Roughly half the binary nodes in a tree are at the fringe, so the left and right +;;; children are both NIL. We have to use binary nodes because only binary nodes +;;; have a key, but a degenerate representation saves a nice amount of space +;;; by implicitly representing the two NILs. +(eval-when (:compile-toplevel :load-toplevel :execute) +(sb-c:defknown fringe-binary-node-p (sb-kernel:instance) boolean () + :overwrite-fndb-silently t) +#+x86-64 +(sb-c:define-vop () + (:translate fringe-binary-node-p) + (:args (x :scs (sb-vm::descriptor-reg))) + (:conditional :l) + (:policy :fast-safe) + (:generator 1 + (sb-assem:inst cmp :byte (sb-x86-64-asm::ea (- 1 sb-vm:instance-pointer-lowtag) x) + (ash (+ 3 sb-vm:instance-data-start) + (- sb-vm:instance-length-shift sb-vm:n-widetag-bits)))))) +#-x86-64 +(progn +(declaim (inline fringe-binary-node-p)) +(defun fringe-binary-node-p (x) ; has only 1 data slot + (= (sb-kernel:%instance-length x) (1+ sb-vm:instance-data-start)))) + +;;; This is the non-"smart" constructor; it only decides whether or not +;;; to store the left and right children. +;;; |n2| is the so-called "smart" constructor which imposes constraints. +(defun n2 (left key right) + (declare (inline make-binary-node)) + #+nil (when (and (unary-node-p left) (unary-node-p right)) ; for debugging only + (error "won't make binary node from ~S ~S" left right)) + (if (or left right) + (make-binary-node key left right) + (let ((instance (sb-kernel:%make-instance/mixed + (1+ sb-vm:instance-data-start)))) + (sb-kernel:%set-instance-layout instance #.(sb-kernel:find-layout 'binary-node)) + ;; Nodes are immutable, hence no setf'er exists. + (sb-kernel:%raw-instance-set/word instance sb-vm:instance-data-start key) + (truly-the binary-node instance)))) + +(defmacro binary-node-parts (node) + `(let ((n ,node)) + (if (fringe-binary-node-p n) + (values nil (binary-node-key n) nil) ; has only one data slot + ;; has left + right + (values (binary-node-%left n) (binary-node-key n) (binary-node-%right n))))) + +(defmacro ternary-node-parts (n) + `(values (ternary-node-left ,n) (ternary-node-key1 ,n) (ternary-node-middle ,n) + (ternary-node-key2 ,n) (ternary-node-right ,n))) + +(defmethod print-object ((self binary-node) stream) + (print-unreadable-object (self stream :identity t :type t) + (multiple-value-bind (left key right) (binary-node-parts self) + (format stream "K=~D L=~D R=~D" + key + (if left (if (unary-node-p left) "unary" (binary-node-key left))) + (if right (if (unary-node-p right) "unary" (binary-node-key right))))))) +(defmethod print-object ((self unary-node) stream) + (print-unreadable-object (self stream :identity t :type t) + (let ((child (child self))) + (format stream "child=~D" + (if child (binary-node-key child)))))) + +(defun insert (a tree &aux (leaf (L2 a))) + (declare (keytype a)) + (declare (dynamic-extent leaf)) + ;; The Haskell code uses different definitions of 'root' and 'n2' + ;; for insert and delete. That's certainly confusing. + ;; Anyway these have to be internal functions to avoid duplication. + ;; Were it not for that they would be DEFUNs for traceability. + (labels + ((|n1| (x) + (typecase x + ((cons (eql leaf)) (N2 nil (cdr x) nil)) + (ternary-node + (multiple-value-bind (t1 a1 t2 a2 t3) (ternary-node-parts x) + (N2 (N2 t1 a1 t2) a2 (N1 t3)))) + (t (N1 x)))) + (|n2| (left key right) + (flet ((leafp (x) (typep x '(cons (eql leaf)))) + (nodep (x) (typep x '(or unary-node binary-node)))) + (declare (inline leafp nodep)) + (cond + ((leafp left) + (binding* ((a1 (cdr left)) (a2 key) (t1 right)) + (N3 nil a1 nil a2 (the null t1)))) + ((and (typep left 'ternary-node) (nodep right)) + (binding* (((t1 a1 t2 a2 t3) (ternary-node-parts left)) + (a3 key)) + (if (typep right 'unary-node) + (N2 (N2 t1 a1 t2) a2 (N2 t3 a3 (child right))) + (N3 (N2 t1 a1 t2) a2 (N1 t3) a3 right)))) + ((leafp right) + (binding* ((t1 left) (a1 key) (a2 (cdr right))) + (N3 (the null t1) a1 nil a2 nil))) + ((and (typep right 'ternary-node) (nodep left)) + (binding* ((a1 key) ((t2 a2 t3 a3 t4) (ternary-node-parts right))) + (if (typep left 'unary-node) + (N2 (N2 (child left) a1 t2) a2 (N2 t3 a3 t4)) + (N3 left a1 (N1 t2) a2 (N2 t3 a3 t4))))) + (t + (N2 left key right))))) + (ins (x) ; find insertion point + (etypecase x + (binary-node + (binding* (((l b r) (binary-node-parts x)) + ((new-left new-key new-right) + (if (<= a b) + (values (ins l) b r) + (values l b (ins r))))) + (|n2| new-left new-key new-right))) + (unary-node (|n1| (ins (child x)))) + (null leaf))) + (root (x) ; bubble up. not sure why 'root' is a good name for this + (typecase x + ((cons (eql leaf)) (N2 nil (cdr x) nil)) + (ternary-node + (multiple-value-bind (t1 a1 t2 a2 t3) (ternary-node-parts x) + (N2 (N2 t1 a1 t2) a2 (N1 t3)))) + (t x)))) + (root (ins tree)))) + +;;; I wanted to determine if there is a best order to test the deletion patterns. +;;; But all except the last are roughly equally common, and the last is the most +;;; frequent, so unfortunately we have to try all the others first to make +;;; sure we don't wrongly pick the last. +;;; Hence it doesn't really matter much in what order the others are tried. +(defglobal *cases* (make-array 8)) +(defmacro pattern-case ((L R) &rest clauses &aux (n -1)) + (flet ((shape-is (node shape) + ;; SHAPE has a small number of hardcoded possibilities which are + ;; essentially just mnemonic devices for the author of this macro. + (cond ((string= shape "1") ; Match (N1 _) + `(unary-node-p ,node)) + ((string= shape "1(1)") ; Match (N1 (N1 _)) + `(and (unary-node-p ,node) (unary-node-p (child ,node)))) + ((string= shape "2(1 2)") ; Match (N2 (N1 _) (N2 _ _ _)) + `(and (binary-node-p ,node) + (not (fringe-binary-node-p ,node)) + (unary-node-p (binary-node-%left ,node)) + (binary-node-p (binary-node-%right ,node)))) + ((string= shape "2(2 1)") ; Match (N2 (N2 _ _ _) (N1 _)) + `(and (binary-node-p ,node) + (not (fringe-binary-node-p ,node)) + (binary-node-p (binary-node-%left ,node)) + (unary-node-p (binary-node-%right ,node)))) + ((string= shape "2(2 2)") ; Match (N2 (N2 _ _ _) (N2 _ _ _)) + `(and (binary-node-p ,node) + (not (fringe-binary-node-p ,node)) + (binary-node-p (binary-node-%left ,node)) + (binary-node-p (binary-node-%right ,node))))))) + `(cond ,@(mapcar (lambda (clause) + (incf n) + (if (eq (car clause) 't) + `(t #| (incf (aref *cases* ,n)) |# ,@(rest clause)) + (let ((test (car clause)) + (consequent (cadr clause))) + `((and ,(shape-is L (first test)) + ,(shape-is R (second test))) + ;; (incf (aref *cases* ,n)) + ,consequent)))) + clauses)))) + +(defun delete (a tree) + (declare (keytype a)) + (labels ((|n2| (left key right) + ;; this surely isn't as readable as pattern-matching in Haskell, + ;; but it'll do. + (pattern-case (left right) + ;; case 1 + (("1" "1") (N1 (N2 (child left) key (child right)))) + ;; case 2 + (("1(1)" "2(1 2)") + (binding* ((t1 (child (child left))) + (a1 key) + ((L a2 t3) (binary-node-parts right)) + (t2 (child L))) + (N1 (N2 (N2 t1 a1 t2) a2 t3)))) + ;; case 3 + (("1(1)" "2(2 1)") + (binding* ((t1 (child (child left))) + (a1 key) + ((L a3 R) (binary-node-parts right)) + ((t2 a2 t3) (binary-node-parts L)) + (t4 (child R))) + (N1 (N2 (N2 t1 a1 t2) a2 (N2 t3 a3 t4))))) + ;; case 4 + (("1(1)" "2(2 2)") + (binding* ((t1 (child left)) + (a1 key) + ((t2 a2 t3) (binary-node-parts right))) + (N2 (N2 t1 a1 t2) a2 (N1 t3)))) + ;; case 5 + (("2(1 2)" "1(1)") + (binding* (((L a1 R) (binary-node-parts left)) + (t1 (child L)) + ((t2 a2 t3) (binary-node-parts R)) + (a3 key) + (t4 (child (child right)))) + (N1 (N2 (N2 t1 a1 t2) a2 (N2 t3 a3 t4))))) + ;; case 6 + (("2(2 1)" "1(1)") + (binding* (((t1 a1 R) (binary-node-parts left)) + (t2 (child R)) + (a2 key) + (t3 (child (child right)))) + (N1 (N2 t1 a1 (N2 t2 a2 t3))))) + ;; case 7 + (("2(2 2)" "1(1)") + (binding* (((t1 a1 t2) (binary-node-parts left)) + (a2 key) + (t3 (child right))) + (N2 (N1 t1) a1 (N2 t2 a2 t3)))) + ;; case 8 + (t + (N2 left key right)))) + (del (x) + (etypecase x + (binary-node + (binding* (((l b r) (binary-node-parts x))) + (cond ((< a b) (|n2| (del l) b r)) + ((> a b) (|n2| l b (del r))) + (t + (binding* (((|a'| |r'|) (split-min r))) + (if (not |a'|) (N1 l) (|n2| l |a'| |r'|))))))) + (unary-node (N1 (del (child x)))) + (null nil))) + (split-min (x) + ;; (format t "~&enter split-min with ~s~%" x) + (etypecase x + (null + (values nil nil)) + (unary-node + (binding* (((a |t'|) (split-min (child x)))) + (if (not a) (values nil nil) (values a (N1 |t'|))))) + (binary-node + (binding* (((t1 a1 t2) (binary-node-parts x)) + ((a |t1'|) (split-min t1))) + ;; (format t "~&binary node split-min got ~s ~s~%" a + (if (not a) + (values a1 (N1 t2)) + (values a (|n2| |t1'| a1 t2))))))) + (root (x) + (typecase x + (unary-node (child x)) + (t x)))) + (root (del tree)))) + +(defun print-tree (tree) + (named-let recurse ((depth 0) (node tree)) + (etypecase node + (unary-node + (format t "~2d: ~v@t unary ~x~%" + depth (* depth 2) (sb-kernel:get-lisp-obj-address node)) + (recurse (1+ depth) (child node))) + (binary-node + (multiple-value-bind (left key right) (binary-node-parts node) + (format t "~2d: ~v@t Key=~D ~x~%" + depth (* depth 2) key (sb-kernel:get-lisp-obj-address node)) + (recurse (1+ depth) left) + (recurse (1+ depth) right))) + (null)))) + +(defun find= (key tree) + (declare (keytype key)) + (loop + (typecase tree + (binary-node + (multiple-value-bind (left node-key right) (binary-node-parts tree) + (cond ((< key node-key) (setq tree left)) + ((< node-key key) (setq tree right)) + (t (return tree))))) + (unary-node (setq tree (child tree))) + (null (return nil))))) + +(defun find<= (key tree) + (declare (keytype key)) + (named-let recurse ((node tree) (best nil)) + (typecase node + (binary-node + (multiple-value-bind (left node-key right) (binary-node-parts node) + (cond ((< key node-key) (recurse left best)) + ((< node-key key) (recurse right node)) + (t node)))) + (unary-node (recurse (child node) best)) + (t best)))) + +(defun find>= (key tree) + (declare (keytype key)) + (named-let recurse ((node tree) (best nil)) + (typecase node + (binary-node + (multiple-value-bind (left node-key right) (binary-node-parts node) + (cond ((< key node-key) (recurse left node)) + ((< node-key key) (recurse right best)) + (t node)))) + (unary-node (recurse (child node) best)) + (t best)))) diff --git a/src/code/host-c-call.lisp b/src/code/c-call.lisp similarity index 98% rename from src/code/host-c-call.lisp rename to src/code/c-call.lisp index 6c365f0b0e..8f10a12397 100644 --- a/src/code/host-c-call.lisp +++ b/src/code/c-call.lisp @@ -8,8 +8,8 @@ ;;;; files for more information. (in-package "SB-ALIEN") - -(/show0 "host-c-call.lisp 12") + +;;;; C string support. (define-alien-type-class (c-string :include pointer :include-args (to)) (external-format :default :type keyword) @@ -138,5 +138,3 @@ (simple-string (string-to-c-string ,value (c-string-external-format ,type))))))) - -(/show0 "host-c-call.lisp end of file") diff --git a/src/code/cas.lisp b/src/code/cas.lisp index 655f34ff2e..ea6e0e6ea7 100644 --- a/src/code/cas.lisp +++ b/src/code/cas.lisp @@ -1,413 +1,76 @@ (in-package "SB-IMPL") -;;;; COMPARE-AND-SWAP -;;;; -;;;; SB-EXT:COMPARE-AND-SWAP is the public API for now. -;;;; -;;;; Internally our interface has CAS, GET-CAS-EXPANSION, DEFINE-CAS-EXPANDER, -;;;; DEFCAS, and #'(CAS ...) functions -- making things mostly isomorphic with -;;;; SETF. - -(eval-when (:compile-toplevel :load-toplevel :execute) -(defun expand-structure-slot-cas (info name place) - (let* ((dd (car info)) - (structure (dd-name dd)) - (slotd (cdr info)) - (index (dsd-index slotd)) - (type (dsd-type slotd)) - (casser - (case (dsd-raw-type slotd) - ((t) '%instance-cas) - #+(or x86 x86-64 riscv) - ((word) '%raw-instance-cas/word) - #+riscv - ((signed-word) '%raw-instance-cas/signed-word)))) - (unless casser - (error "Cannot use COMPARE-AND-SWAP with structure accessor ~ - for a typed slot: ~S" - place)) - (when (dsd-read-only slotd) - (error "Cannot use COMPARE-AND-SWAP with structure accessor ~ - for a read-only slot: ~S" - place)) - (destructuring-bind (op arg) place - (aver (eq op name)) - (with-unique-names (instance old new) - (values (list instance) - (list `(the ,structure ,arg)) - old - new - `(truly-the (values ,type &optional) - (,casser ,instance ,index - (the ,type ,old) - (the ,type ,new))) - `(,op ,instance)))))) - -(defun get-cas-expansion (place &optional environment) - "Analogous to GET-SETF-EXPANSION. Returns the following six values: - - * list of temporary variables - - * list of value-forms whose results those variable must be bound - - * temporary variable for the old value of PLACE - - * temporary variable for the new value of PLACE - - * form using the aforementioned temporaries which performs the - compare-and-swap operation on PLACE - - * form using the aforementioned temporaries with which to perform a volatile - read of PLACE - -Example: - - (get-cas-expansion '(car x)) - ; => (#:CONS871), (X), #:OLD872, #:NEW873, - ; (SB-KERNEL:%COMPARE-AND-SWAP-CAR #:CONS871 #:OLD872 :NEW873). - ; (CAR #:CONS871) - - (defmacro my-atomic-incf (place &optional (delta 1) &environment env) - (multiple-value-bind (vars vals old new cas-form read-form) - (get-cas-expansion place env) - (let ((delta-value (gensym \"DELTA\"))) - `(let* (,@(mapcar 'list vars vals) - (,old ,read-form) - (,delta-value ,delta) - (,new (+ ,old ,delta-value))) - (loop until (eq ,old (setf ,old ,cas-form)) - do (setf ,new (+ ,old ,delta-value))) - ,new)))) - -EXPERIMENTAL: Interface subject to change." - ;; FIXME: this seems wrong on two points: - ;; 1. if TRULY-THE had a CAS expander (which it doesn't) we'd want - ;; to use %MACROEXPAND[-1] so as not to lose the "truly-the"-ness - ;; 2. if both a CAS expander and a macro exist, the CAS expander - ;; should be preferred before macroexpanding (just like SETF does) - (let ((expanded (sb-xc:macroexpand place environment))) - (flet ((invalid-place () - (error "Invalid place to CAS: ~S -> ~S" place expanded))) - (unless (consp expanded) - (cond ((and (symbolp expanded) - (member (info :variable :kind expanded) - '(:global :special))) - (setq expanded `(symbol-value ',expanded))) - (t - (invalid-place)))) - (let ((name (car expanded))) - (unless (symbolp name) - (invalid-place)) - (acond - ((info :cas :expander name) - ;; CAS expander. - (funcall it expanded environment)) - - ;; Structure accessor - ((structure-instance-accessor-p name) - (expand-structure-slot-cas it name expanded)) - - ;; CAS function - (t - (with-unique-names (old new) - (let ((vars nil) - (vals nil) - (args nil)) - (dolist (x (reverse (cdr expanded))) - (cond ((sb-xc:constantp x environment) - (push x args)) - (t - (let ((tmp (gensymify x))) - (push tmp args) - (push tmp vars) - (push x vals))))) - (values vars vals old new - `(funcall #'(cas ,name) ,old ,new ,@args) - `(,name ,@args)))))))))) -) - -;;; This is what it all comes down to. -(defmacro cas (place old new &environment env) - "Synonym for COMPARE-AND-SWAP. - -Additionally DEFUN, DEFGENERIC, DEFMETHOD, FLET, and LABELS can be also used to -define CAS-functions analogously to SETF-functions: - - (defvar *foo* nil) - - (defun (cas foo) (old new) - (cas (symbol-value '*foo*) old new)) - -First argument of a CAS function is the expected old value, and the second -argument of is the new value. Note that the system provides no automatic -atomicity for CAS functions, nor can it verify that they are atomic: it is up -to the implementor of a CAS function to ensure its atomicity. - -EXPERIMENTAL: Interface subject to change." - (multiple-value-bind (temps place-args old-temp new-temp cas-form) - (get-cas-expansion place env) - `(let* (,@(mapcar #'list temps place-args) - (,old-temp ,old) - (,new-temp ,new)) - ,cas-form))) - -(defmacro define-cas-expander (accessor lambda-list &body body) - "Analogous to DEFINE-SETF-EXPANDER. Defines a CAS-expansion for ACCESSOR. -BODY must return six values as specified in GET-CAS-EXPANSION. - -Note that the system provides no automatic atomicity for CAS expansion, nor -can it verify that they are atomic: it is up to the implementor of a CAS -expansion to ensure its atomicity. - -EXPERIMENTAL: Interface subject to change." - `(eval-when (:compile-toplevel :load-toplevel :execute) - (setf (info :cas :expander ',accessor) - ,(make-macro-lambda `(cas-expand ,accessor) lambda-list body - 'define-cas-expander accessor)))) - -;; FIXME: this interface is bogus - short-form DEFSETF/CAS does not -;; want a lambda-list. You just blindly substitute -;; (CAS (PLACE arg1 ... argN) old new) -> (F arg1 ... argN old new). -;; What role can this lambda-list have when there is no user-provided -;; code to read the variables? -;; And as mentioned no sbcl-devel, &REST is beyond bogus, it's broken. -;; -(defmacro defcas (accessor lambda-list function &optional docstring) - "Analogous to short-form DEFSETF. Defines FUNCTION as responsible -for compare-and-swap on places accessed using ACCESSOR. LAMBDA-LIST -must correspond to the lambda-list of the accessor. - -Note that the system provides no automatic atomicity for CAS expansions -resulting from DEFCAS, nor can it verify that they are atomic: it is up to the -user of DEFCAS to ensure that the function specified is atomic. - -EXPERIMENTAL: Interface subject to change." - (multiple-value-bind (llks reqs opts rest) - (parse-lambda-list lambda-list - :accept (lambda-list-keyword-mask '(&optional &rest)) - :context "a DEFCAS lambda-list") - (declare (ignore llks)) - `(define-cas-expander ,accessor ,lambda-list - ,@(when docstring (list docstring)) - ;; FIXME: if a &REST arg is present, this is really weird. - (let ((temps (mapcar #'gensymify ',(append reqs opts rest))) - (args (list ,@(append reqs opts rest))) - (old (gensym "OLD")) - (new (gensym "NEW"))) - (values temps - args - old - new - `(,',function ,@temps ,old ,new) - `(,',accessor ,@temps)))))) - -(defmacro compare-and-swap (place old new) - "Atomically stores NEW in PLACE if OLD matches the current value of PLACE. -Two values are considered to match if they are EQ. Returns the previous value -of PLACE: if the returned value is EQ to OLD, the swap was carried out. - -PLACE must be an CAS-able place. Built-in CAS-able places are accessor forms -whose CAR is one of the following: - - CAR, CDR, FIRST, REST, SVREF, SYMBOL-PLIST, SYMBOL-VALUE, SVREF, SLOT-VALUE - SB-MOP:STANDARD-INSTANCE-ACCESS, SB-MOP:FUNCALLABLE-STANDARD-INSTANCE-ACCESS, - -or the name of a DEFSTRUCT created accessor for a slot whose storage type -is not raw. (Refer to the the \"Efficiency\" chapter of the manual -for the list of raw slot types. Future extensions to this macro may allow -it to work on some raw slot types.) - -In case of SLOT-VALUE, if the slot is unbound, SLOT-UNBOUND is called unless -OLD is EQ to SB-PCL:+SLOT-UNBOUND+ in which case SB-PCL:+SLOT-UNBOUND+ is -returned and NEW is assigned to the slot. Additionally, the results are -unspecified if there is an applicable method on either -SB-MOP:SLOT-VALUE-USING-CLASS, (SETF SB-MOP:SLOT-VALUE-USING-CLASS), or -SB-MOP:SLOT-BOUNDP-USING-CLASS. - -Additionally, the PLACE can be a anything for which a CAS-expansion has been -specified using DEFCAS, DEFINE-CAS-EXPANDER, or for which a CAS-function has -been defined. (See SB-EXT:CAS for more information.) -" - `(cas ,place ,old ,new)) - -(define-cas-expander symbol-value (name &environment env) - (multiple-value-bind (tmp val cname) - (if (sb-xc:constantp name env) - (values nil nil (constant-form-value name env)) - (values (gensymify name) name nil)) - (let ((symbol (or tmp `',cname))) - (with-unique-names (old new) - (values (when tmp (list tmp)) - (when val (list val)) - old - new - (if (and cname (member (info :variable :kind cname) '(:special :global))) - ;; We can generate the type-check reasonably. - `(%compare-and-swap-symbol-value - ',cname ,old (the ,(info :variable :type cname) ,new)) - `(progn - (about-to-modify-symbol-value ,symbol 'compare-and-swap ,new) - (%compare-and-swap-symbol-value ,symbol ,old ,new))) - `(symbol-value ,symbol)))))) - -(define-cas-expander svref (vector index) - (with-unique-names (v i old new) - (values (list v i) - (list vector index) - old - new - `(locally (declare (simple-vector ,v)) - (%compare-and-swap-svref ,v (check-bound ,v (length ,v) ,i) ,old ,new)) - `(svref ,v ,i)))) - -;;;; ATOMIC-INCF and ATOMIC-DECF - -(eval-when (:compile-toplevel :load-toplevel :execute) -(defun expand-atomic-frob - (name specified-place diff env - &aux (place (sb-xc:macroexpand specified-place env))) - (declare (type (member atomic-incf atomic-decf) name)) - (flet ((invalid-place () - (error "Invalid first argument to ~S: ~S" name specified-place)) - (compute-newval (old) ; used only if no atomic inc vop - `(logand (,(case name (atomic-incf '+) (atomic-decf '-)) ,old - (the sb-vm:signed-word ,diff)) sb-ext:most-positive-word)) - (compute-delta () ; used only with atomic inc vop - `(logand ,(case name - (atomic-incf `(the sb-vm:signed-word ,diff)) - (atomic-decf `(- (the sb-vm:signed-word ,diff)))) - sb-ext:most-positive-word))) - (declare (ignorable #'compute-newval #'compute-delta)) - (when (and (symbolp place) - (eq (info :variable :kind place) :global) - (type= (info :variable :type place) (specifier-type 'fixnum))) - ;; Global can't be lexically rebound. - (return-from expand-atomic-frob - `(truly-the fixnum (,(case name - (atomic-incf '%atomic-inc-symbol-global-value) - (atomic-decf '%atomic-dec-symbol-global-value)) - ',place (the fixnum ,diff))))) - (unless (consp place) (invalid-place)) - (destructuring-bind (op . args) place - ;; FIXME: The lexical environment should not be disregarded. - ;; CL builtins can't be lexically rebound, but structure accessors can. - (case op - (aref - (unless (singleton-p (cdr args)) - (invalid-place)) - (with-unique-names (array) - `(let ((,array (the (simple-array word (*)) ,(car args)))) - #+compare-and-swap-vops - (%array-atomic-incf/word - ,array - (check-bound ,array (array-dimension ,array 0) ,(cadr args)) - ,(compute-delta)) - #-compare-and-swap-vops - ,(with-unique-names (index old-value) - `(without-interrupts - (let* ((,index ,(cadr args)) - (,old-value (aref ,array ,index))) - (setf (aref ,array ,index) ,(compute-newval old-value)) - ,old-value)))))) - ((car cdr first rest) - (when (cdr args) - (invalid-place)) - `(truly-the - fixnum - (,(case op - ((first car) (case name - (atomic-incf '%atomic-inc-car) - (atomic-decf '%atomic-dec-car))) - ((rest cdr) (case name - (atomic-incf '%atomic-inc-cdr) - (atomic-decf '%atomic-dec-cdr)))) - ,(car args) (the fixnum ,diff)))) - (t - (when (or (cdr args) - ;; Because accessor info is identical for the writer and reader - ;; functions, without a SYMBOLP check this would erroneously allow - ;; (ATOMIC-INCF ((SETF STRUCT-SLOT) x)) - (not (symbolp op)) - (not (structure-instance-accessor-p op))) - (invalid-place)) - (let* ((accessor-info (structure-instance-accessor-p op)) - (slotd (cdr accessor-info)) - (type (dsd-type slotd))) - (unless (and (eq 'sb-vm:word (dsd-raw-type slotd)) - (type= (specifier-type type) (specifier-type 'sb-vm:word))) - (error "~S requires a slot of type (UNSIGNED-BYTE ~S), not ~S: ~S" - name sb-vm:n-word-bits type place)) - (when (dsd-read-only slotd) - (error "Cannot use ~S with structure accessor for a read-only slot: ~S" - name place)) - #+compare-and-swap-vops - `(truly-the sb-vm:word - (%raw-instance-atomic-incf/word - (the ,(dd-name (car accessor-info)) ,@args) - ,(dsd-index slotd) - ,(compute-delta))) - #-compare-and-swap-vops - (with-unique-names (structure old-value) - `(without-interrupts - (let* ((,structure ,@args) - (,old-value (,op ,structure))) - (setf (,op ,structure) ,(compute-newval old-value)) - ,old-value)))))))))) - -(defmacro atomic-incf (&environment env place &optional (diff 1)) - #.(format nil - "Atomically increments PLACE by DIFF, and returns the value of PLACE before -the increment. - -PLACE must access one of the following: - - a DEFSTRUCT slot with declared type (UNSIGNED-BYTE ~D~:*) - or AREF of a (SIMPLE-ARRAY (UNSIGNED-BYTE ~D~:*) (*)) - The type SB-EXT:WORD can be used for these purposes. - - CAR or CDR (respectively FIRST or REST) of a CONS. - - a variable defined using DEFGLOBAL with a proclaimed type of FIXNUM. -Macroexpansion is performed on PLACE before expanding ATOMIC-INCF. - -Incrementing is done using modular arithmetic, -which is well-defined over two different domains: - - For structures and arrays, the operation accepts and produces - an (UNSIGNED-BYTE ~D~:*), and DIFF must be of type (SIGNED-BYTE ~D). - ATOMIC-INCF of #x~x by one results in #x0 being stored in PLACE. - - For other places, the domain is FIXNUM, and DIFF must be a FIXNUM. - ATOMIC-INCF of #x~x by one results in #x~x - being stored in PLACE. - -DIFF defaults to 1. - -EXPERIMENTAL: Interface subject to change." - sb-vm:n-word-bits most-positive-word - sb-xc:most-positive-fixnum sb-xc:most-negative-fixnum) - (expand-atomic-frob 'atomic-incf place diff env)) - -(defmacro atomic-decf (&environment env place &optional (diff 1)) - #.(format nil - "Atomically decrements PLACE by DIFF, and returns the value of PLACE before -the decrement. - -PLACE must access one of the following: - - a DEFSTRUCT slot with declared type (UNSIGNED-BYTE ~D~:*) - or AREF of a (SIMPLE-ARRAY (UNSIGNED-BYTE ~D~:*) (*)) - The type SB-EXT:WORD can be used for these purposes. - - CAR or CDR (respectively FIRST or REST) of a CONS. - - a variable defined using DEFGLOBAL with a proclaimed type of FIXNUM. -Macroexpansion is performed on PLACE before expanding ATOMIC-DECF. - -Decrementing is done using modular arithmetic, -which is well-defined over two different domains: - - For structures and arrays, the operation accepts and produces - an (UNSIGNED-BYTE ~D~:*), and DIFF must be of type (SIGNED-BYTE ~D). - ATOMIC-DECF of #x0 by one results in #x~x being stored in PLACE. - - For other places, the domain is FIXNUM, and DIFF must be a FIXNUM. - ATOMIC-DECF of #x~x by one results in #x~x - being stored in PLACE. - -DIFF defaults to 1. - -EXPERIMENTAL: Interface subject to change." - sb-vm:n-word-bits most-positive-word - sb-xc:most-negative-fixnum sb-xc:most-positive-fixnum) - (expand-atomic-frob 'atomic-decf place diff env)) +(declaim (inline (cas car) (cas cdr) (cas first) (cas rest))) +(defun (cas car) (old new cons) (%compare-and-swap-car cons old new)) +(defun (cas cdr) (old new cons) (%compare-and-swap-cdr cons old new)) +(defun (cas first) (old new cons) (%compare-and-swap-car cons old new)) +(defun (cas rest) (old new cons) (%compare-and-swap-cdr cons old new)) + +;;; Out-of-line definitions for various primitive cas functions. +(macrolet ((def (name lambda-list ref &optional set) + #+compare-and-swap-vops + (declare (ignore ref set)) + `(defun ,name (,@lambda-list old new) + #+compare-and-swap-vops + (,name ,@lambda-list old new) + #-compare-and-swap-vops + (progn + #+sb-thread + ,(error "No COMPARE-AND-SWAP-VOPS on a threaded build?") + #-sb-thread + (let ((current (,ref ,@lambda-list))) + ;; Shouldn't this be inside a WITHOUT-INTERRUPTS ? + (when (eq current old) + ,(if set + `(,set ,@lambda-list new) + `(setf (,ref ,@lambda-list) new))) + current))))) + (def %compare-and-swap-car (cons) car) + (def %compare-and-swap-cdr (cons) cdr) + ;; %instance-set is OK here even though it doesn't return a value + ;; because it is used for effect. And if compare-and-swap vops exist, + ;; then the setter isn't used at all. + (def %instance-cas (instance index) %instance-ref %instance-set) + #+(or x86-64 x86 riscv) + (def %raw-instance-cas/word (instance index) + %raw-instance-ref/word + %raw-instance-set/word) + #+(or arm64 riscv x86 x86-64) + (def %raw-instance-cas/signed-word (instance index) + %raw-instance-ref/signed-word + %raw-instance-set/signed-word) + (def %compare-and-swap-symbol-value (symbol) symbol-value) + (def %compare-and-swap-svref (vector index) svref)) + +;; Atomic increment/decrement ops on tagged storage cells (as contrasted with +;; specialized arrays and raw structure slots) are defined in terms of CAS. + +;; This code would be more concise if workable versions +;; of +-MODFX, --MODFX were defined generically. +(macrolet ((modular (fun a b) + #+(or x86 x86-64) + `(,(package-symbolicate "SB-VM" fun "-MODFX") ,a ,b) + #-(or x86 x86-64) + ;; algorithm of https://graphics.stanford.edu/~seander/bithacks + `(let ((res (logand (,fun ,a ,b) + (ash sb-ext:most-positive-word + (- sb-vm:n-fixnum-tag-bits)))) + (m (ash 1 (1- sb-vm:n-fixnum-bits)))) + (- (logxor res m) m)))) + + ;; Atomically frob the CAR or CDR of a cons, or a symbol-value. + ;; The latter will be a global value because the ATOMIC-INCF/DECF + ;; macros work on a symbol only if it is known global. + (macrolet ((def-frob (name op type slot) + `(defun ,name (place delta) + (declare (type ,type place) (type fixnum delta)) + (loop (let ((old (the fixnum (,slot place)))) + (when (eq (cas (,slot place) old + (modular ,op old delta)) old) + (return old))))))) + (def-frob %atomic-inc-symbol-global-value + symbol symbol-value) + (def-frob %atomic-dec-symbol-global-value - symbol symbol-value) + (def-frob %atomic-inc-car + cons car) + (def-frob %atomic-dec-car - cons car) + (def-frob %atomic-inc-cdr + cons cdr) + (def-frob %atomic-dec-cdr - cons cdr))) diff --git a/src/code/cl-specials.lisp b/src/code/cl-specials.lisp index 195a4266f0..a7274a99fa 100644 --- a/src/code/cl-specials.lisp +++ b/src/code/cl-specials.lisp @@ -28,7 +28,7 @@ cl:*gensym-counter* cl:*load-pathname* cl:*load-print* - cl:*load-truename* + #+ansi-compliant-load-truename cl:*load-truename* cl:*load-verbose* cl:*macroexpand-hook* cl:*modules* @@ -78,6 +78,27 @@ (declare (notinline (setf sb-int:info))) ; skirt failure-to-inline warning (setf (sb-int:info :variable :wired-tls symbol) t))))) +#-ansi-compliant-load-truename +(progn +;; this could almost go in target-load.lisp were it not for the use in ir1-translators +(defvar sb-fasl::%load-truename nil) +;; "The consequences are unspecified if an attempt is made to assign or bind [...]" +;; http://www.lispworks.com/documentation/HyperSpec/Body/v_ld_pns.htm#STload-truenameST +;; +;; But the rationale provided in http://www.lispworks.com/documentation/HyperSpec/Issues/iss218_w.htm +;; for the existence of the -TRUENAME* variables is dubious: +;; "Note that it is not adequate to just have the -PATHNAME* variables +;; since TRUENAME on these pathnames might not yield the value of the +;; -TRUENAME* variables if the file has been deleted or protected +;; since the open occurred (in some implementations)." +;; because in our ANSI-compliant logic, there is a delay between opening a file +;; and determining its truename, which means that it might be impossible to determine +;; the truename even if done ASAP. Supposing that somebody really were to delete +;; the very file being acted on, it's not LOAD's job to deal with race conditions. +(define-symbol-macro *load-truename* + (sb-ext:truly-the (values (or pathname null) &optional) + (sb-fasl::resolve-load-truename 'sb-fasl::%load-truename *load-pathname*)))) + (declaim (type t cl:+ cl:++ cl:+++ cl:- cl:* cl:** cl:***)) ;;; generalized booleans @@ -135,77 +156,27 @@ (declaim (type pathname cl:*default-pathname-defaults*)) -(declaim (type (or pathname null) - cl:*load-pathname* - cl:*load-truename* - cl:*compile-file-pathname* - cl:*compile-file-truename*)) - -;;;; DEFGLOBAL and DEFINE-LOAD-TIME-GLOBAL -;;;; These have alternate definitions (in cross-misc) which rely on -;;;; the underlying host DEFVAR when building the cross-compiler. +;;; Some functions for which we should *never* (or almost never) bind eagerly +;;; to the functional definition. +;;; IR2-CONVERT-GLOBAL-VAR won't use a :KNOWN-FUN constant-tn, but will instead +;;; dereference the fdefinition like for most function calls. +;;; They aren't actually "inlined", but they were bypassing the fdefinition in +;;; situations involving (APPLY ...) which rendered encapsulation impossible. +(declaim (notinline open compile-file load compile)) (in-package "SB-IMPL") -;;; Generate a consistent error message for all the standard -;;; defining macros when given an invalid NAME argument. -;;; DEFCLASS has its own thing, which is CHECK-CLASS-NAME. -;;; [This is possibly the wrong place for this, but it's needed -;;; earlier than anything else, even primordial-extensions.] -(defmacro check-designator (name macro &optional (arg-reference "NAME")) - (multiple-value-bind (predicate explanation) - (case macro - ((defun defgeneric defmethod define-compiler-macro) - (values 'legal-fun-name-p "function name")) - (t - (values 'symbolp "symbol"))) - ;; If we decide that the correct behavior is to actually macroexpand - ;; and then fail later, well, I suppose we could express all macros - ;; such that they perform their LEGAL-FUN-NAME-P/SYMBOLP check as part - ;; of the ordinary code, as in: - ;; (DEFPARAMETER "foo" 3) -> (%defparameter (the symbol '"foo") ...) - ;; which seems at least slightly preferable to failing in the - ;; internal function that would store the globaldb info. - `(unless (,predicate ,name) - (error ,(format nil "The ~A argument to ~A, ~~S, is not a ~A." - arg-reference macro explanation) - ,name)))) - -(defmacro defglobal (name value &optional (doc nil docp)) - "Defines NAME as a global variable that is always bound. VALUE is evaluated -and assigned to NAME both at compile- and load-time, but only if NAME is not -already bound. - -Global variables share their values between all threads, and cannot be -locally bound, declared special, defined as constants, and neither bound -nor defined as symbol macros. - -See also the declarations SB-EXT:GLOBAL and SB-EXT:ALWAYS-BOUND." - (check-designator name defglobal) - (let ((boundp (make-symbol "BOUNDP"))) - `(progn - (eval-when (:compile-toplevel) - (let ((,boundp (boundp ',name))) - (%compiler-defglobal ',name :always-bound - (not ,boundp) (unless ,boundp ,value)))) - (%defglobal ',name - (if (%boundp ',name) (make-unbound-marker) ,value) - (sb-c:source-location) - ,@(and docp `(',doc)))))) - -(defmacro define-load-time-global (name value &optional (doc nil docp)) - "Defines NAME as a global variable that is always bound. VALUE is evaluated -and assigned to NAME at load-time, but only if NAME is not already bound. - -Attempts to read NAME at compile-time will signal an UNBOUND-VARIABLE error -unless it has otherwise been assigned a value. - -See also DEFGLOBAL which assigns the VALUE at compile-time too." - (check-designator name define-load-time-global) - `(progn - (eval-when (:compile-toplevel) - (%compiler-defglobal ',name :eventually nil nil)) - (%defglobal ',name - (if (%boundp ',name) (make-unbound-marker) ,value) - (sb-c:source-location) - ,@(and docp `(',doc))))) + +;;; Ensure some VM symbols get wired TLS. +(in-package "SB-VM") +(eval-when (:compile-toplevel :load-toplevel :execute) + (dolist (entry '#.per-thread-c-interface-symbols) + (let ((symbol (if (consp entry) (car entry) entry))) + (declare (notinline sb-int:info (setf sb-int:info))) + ;; CURRENT-{CATCH/UWP}-BLOCK are thread slots, + ;; so the TLS indices were already assigned. + ;; There may be other symbols too. + (unless (sb-int:info :variable :wired-tls symbol) + (setf (sb-int:info :variable :wired-tls symbol) :always-thread-local)) + (unless (sb-int:info :variable :always-bound symbol) + (setf (sb-int:info :variable :always-bound symbol) :always-bound))))) diff --git a/src/code/class-init.lisp b/src/code/class-init.lisp deleted file mode 100644 index 59c7798d17..0000000000 --- a/src/code/class-init.lisp +++ /dev/null @@ -1,34 +0,0 @@ -;;;; When this file's top level forms are run, it precomputes the -;;;; translations for built in classes. This stuff is split off from -;;;; the other type stuff to get around problems with everything -;;;; needing to be loaded before everything else. This file is the -;;;; first to exercise the type machinery. - -;;;; This software is part of the SBCL system. See the README file for -;;;; more information. -;;;; -;;;; This software is derived from the CMU CL system, which was -;;;; written at Carnegie Mellon University and released into the -;;;; public domain. The software is in the public domain and is -;;;; provided with absolutely no warranty. See the COPYING and CREDITS -;;;; files for more information. - -(in-package "SB-KERNEL") - -;;; built-in classes -(/show0 "beginning class-init.lisp") -(dolist (x +!built-in-classes+) - (destructuring-bind (name &key (translation nil trans-p) &allow-other-keys) - x - (/show "doing class with" name) - (when trans-p - (let ((classoid (classoid-cell-classoid (find-classoid-cell name :create t))) - (type (specifier-type translation))) - ;; The classoid T gets its translation dumped in genesis. - ;; May as well double-check that it's right. - (when (typep (built-in-classoid-translation classoid) 'ctype) - (aver (eq (built-in-classoid-translation classoid) type))) - (setf (built-in-classoid-translation classoid) type) - (setf (info :type :builtin name) type))))) - -(/show0 "done with class-init.lisp") diff --git a/src/code/class.lisp b/src/code/class.lisp index 9b9f0eb83c..6d39785da8 100644 --- a/src/code/class.lisp +++ b/src/code/class.lisp @@ -14,21 +14,50 @@ (in-package "SB-KERNEL") (!begin-collecting-cold-init-forms) +;;; Has the type system been properly initialized? (I.e. is it OK to +;;; use it?) +(define-load-time-global *type-system-initialized* nil) +(!cold-init-forms (setq *type-system-initialized* nil)) + +(in-package "SB-PCL") + +(declaim (#+sb-xc-host special #-sb-xc-host global *the-class-t* + *the-class-slot-object* + *the-class-structure-object* + *the-class-standard-object* + *the-class-function* + *the-class-funcallable-standard-object* + *the-class-system-class* + *the-class-slot-class* + *the-class-condition-class* + *the-class-structure-class* + *the-class-standard-class* + *the-class-funcallable-standard-class* + *the-class-forward-referenced-class* + *the-class-method* + *the-class-standard-method* + *the-class-standard-reader-method* + *the-class-standard-writer-method* + *the-class-standard-boundp-method* + *the-class-global-reader-method* + *the-class-global-writer-method* + *the-class-global-boundp-method* + *the-class-standard-generic-function* + *the-class-standard-direct-slot-definition* + *the-class-standard-effective-slot-definition* + + *the-eslotd-standard-class-slots* + *the-eslotd-funcallable-standard-class-slots*)) + +(in-package "SB-KERNEL") + ;;;; the CLASSOID structure ;;; The CLASSOID structure is a supertype of all classoid types. ;;; Its definition occurs in 'early-classoid.lisp' - -(defmethod make-load-form ((self classoid) &optional env) - (declare (ignore env)) - (let ((name (classoid-name self))) - (if (and name (eq (find-classoid name nil) self)) - `(find-classoid ',name) - (error "can't use anonymous or undefined class as constant:~% ~S" - self)))) #+sb-xc-host -(defmethod sb-xc:make-load-form ((self classoid) &optional env) +(defmethod make-load-form ((self classoid) &optional env) (declare (ignore env)) `(find-classoid ',(classoid-name self))) @@ -39,172 +68,136 @@ ;;; ;;; In each cons, the car is the symbol naming the layout, and the ;;; cdr is the layout itself. -(defvar *!initial-layouts*) +;;; If #+metaspace then the cdr is actually of type WRAPPER, +;;; and if #-metaspace then the wrapper is a LAYOUT. +(defvar *!initial-wrappers*) ;;; a table mapping class names to layouts for classes we have ;;; referenced but not yet loaded. This is initialized from an alist ;;; created by genesis describing the layouts that genesis created at ;;; cold-load time. -(define-load-time-global *forward-referenced-layouts* +(define-load-time-global *forward-referenced-wrappers* ;; FIXME: why is the test EQUAL and not EQ? Aren't the keys all symbols? (make-hash-table :test 'equal)) +#-sb-xc-host (!cold-init-forms - ;; *forward-referenced-layouts* is protected by *WORLD-LOCK* + ;; *forward-referenced-wrappers* is protected by *WORLD-LOCK* ;; so it does not need a :synchronized option. - #-sb-xc-host (progn - (/show0 "processing *!INITIAL-LAYOUTS*") - (setq *forward-referenced-layouts* (make-hash-table :test 'equal)) - (dovector (x *!initial-layouts*) - (let ((expected (hash-layout-name (car x))) - (actual (layout-clos-hash (cdr x)))) - (unless (= actual expected) - (bug "XC layout hash calculation failed"))) - (setf (gethash (car x) *forward-referenced-layouts*) - (cdr x))) - (/show0 "done processing *!INITIAL-LAYOUTS*"))) + (setq *forward-referenced-wrappers* (make-hash-table :test 'equal)) + (dovector (x *!initial-wrappers*) + (let ((expected (hash-layout-name (car x))) + (actual (wrapper-clos-hash (cdr x)))) + (unless (= actual expected) (bug "XC layout hash calculation failed"))) + (setf (gethash (car x) *forward-referenced-wrappers*) (cdr x)))) + +;;; FIXME: This lock is only seized in the classoid/layout/class +;;; system, and is now a misnomer. +#-sb-xc-host +(define-load-time-global **world-lock** nil) +#-sb-xc-host +(!cold-init-forms + (setq **world-lock** (sb-thread:make-mutex :name "World Lock"))) + +(defmacro with-world-lock (() &body body) + #+sb-xc-host `(progn ,@body) + #-sb-xc-host `(sb-thread:with-recursive-lock (**world-lock**) ,@body)) ;;; The LAYOUT structure itself is defined in 'early-classoid.lisp' -(defmethod print-object ((layout layout) stream) - (print-unreadable-object (layout stream :type t :identity t) +#+sb-xc-host +(progn +(defun make-layout (hash classoid &rest keys) + (macrolet ((make (&rest extra) + `(apply #'host-make-wrapper + (cdr (assq (classoid-name classoid) *popular-structure-types*)) + hash classoid ,@extra :allow-other-keys t keys))) + #-metaspace (make) + #+metaspace (let* ((layout (%make-layout)) + (wrapper (make :friend layout))) + (setf (layout-friend layout) wrapper) + wrapper))) +;; The target reconstructs wrappers using FOP-LAYOUT but the host uses MAKE-LOAD-FORM. +(defmethod cl:make-load-form ((wrapper wrapper) &optional env) + (declare (ignore env)) + (labels ((externalize (wrapper &aux (classoid (wrapper-classoid wrapper)) + (name (classoid-name classoid))) + (when (or (wrapper-invalid wrapper) + (not name) + (typep classoid 'undefined-classoid)) + (sb-c:compiler-error "can't dump ~S" wrapper)) + `(xc-load-wrapper ',name + ,(wrapper-depthoid wrapper) + (vector ,@(map 'list #'externalize (wrapper-inherits wrapper))) + ,(wrapper-length wrapper) + ,(wrapper-bitmap wrapper)))) + (externalize wrapper))) +(defun xc-load-wrapper (name depthoid inherits length bitmap) + (let ((classoid (find-classoid name))) + (aver (and classoid (not (undefined-classoid-p classoid)))) + (let ((wrapper (classoid-wrapper classoid))) + (unless (and (= (wrapper-depthoid wrapper) depthoid) + (= (length (wrapper-inherits wrapper)) (length inherits)) + (every #'eq (wrapper-inherits wrapper) inherits) + (= (wrapper-length wrapper) length) + (= (wrapper-bitmap wrapper) bitmap)) + (error "XC can't reload layout for ~S with ~S vs ~A" + name (list depthoid inherits length bitmap) wrapper)) + wrapper))) +) ; end PROGN + +(defmethod print-object ((wrapper wrapper) stream) + (print-unreadable-object (wrapper stream :type t :identity t) (format stream - "for ~S~@[, INVALID=~S~]" - (layout-proper-name layout) - (layout-invalid layout)))) + "~@[(ID=~d) ~]for ~S~@[, INVALID=~S~]" + (layout-id wrapper) + (wrapper-proper-name wrapper) + (wrapper-invalid wrapper)))) (eval-when (#-sb-xc :compile-toplevel :load-toplevel :execute) - (defun layout-proper-name (layout) - (classoid-proper-name (layout-classoid layout)))) + (defun wrapper-proper-name (wrapper) + (classoid-proper-name (wrapper-classoid wrapper)))) -;;; If we can't find any existing layout, then we create a new one -;;; storing it in *FORWARD-REFERENCED-LAYOUTS*. In classic CMU CL, we -;;; used to immediately check for compatibility, but for -;;; cross-compilability reasons (i.e. convenience of using this -;;; function in a MAKE-LOAD-FORM expression) that functionality has -;;; been split off into INIT-OR-CHECK-LAYOUT. -(declaim (ftype (sfunction (symbol) layout) find-layout)) -;; The comment "This seems ..." is misleading but I don't have a better one. -;; FIND-LAYOUT is used by FIND-AND-INIT-OR-CHECK-LAYOUT which is used -;; by FOP-LAYOUT, so clearly it's used when reading fasl files. +;;; Return the layout currently installed in the classoid named NAME. +;;; If there is none, then make a layout referring for an undefined classoid. +;;; NB: for #+metaspace this returns a WRAPPER, not a LAYOUT. +(declaim (ftype (sfunction (symbol) wrapper) find-layout)) (defun find-layout (name) - ;; This seems to be currently used only from the compiler, but make - ;; it thread-safe all the same. We need to lock *F-R-L* before doing - ;; FIND-CLASSOID in case (SETF FIND-CLASSOID) happens in parallel. - (let ((table *forward-referenced-layouts*)) + (binding* ((classoid (find-classoid name nil) :exit-if-null) ; threadsafe + (wrapper (classoid-wrapper classoid) :exit-if-null)) + (return-from find-layout wrapper)) + (let ((table *forward-referenced-wrappers*)) (with-world-lock () (let ((classoid (find-classoid name nil))) - (or (and classoid (classoid-layout classoid)) + (or (and classoid (classoid-wrapper classoid)) (values (ensure-gethash name table (make-layout (hash-layout-name name) (or classoid (make-undefined-classoid name)))))))))) -;;; If LAYOUT is uninitialized, initialize it with CLASSOID, LENGTH, -;;; INHERITS, DEPTHOID, and BITMAP. -;;; Otherwise require that it be consistent with the existing values. -;;; -;;; UNDEFINED-CLASS values are interpreted specially as "we don't know -;;; anything about the class", so if LAYOUT is initialized, any -;;; preexisting class slot value is OK, and if it's not initialized, -;;; its class slot value is set to an UNDEFINED-CLASS. -- FIXME: This -;;; is no longer true, :UNINITIALIZED used instead. -(declaim (ftype (sfunction (layout classoid layout-length fixnum simple-vector - layout-depthoid layout-bitmap) layout) - %init-or-check-layout)) -(defun %init-or-check-layout (layout classoid length flags inherits depthoid bitmap) - ;; BITMAP is redundant information about the primitive object representation - ;; which is fully captured by the defstruct description, and not stored in the - ;; host layout. - (cond ((eq (layout-invalid layout) :uninitialized) - ;; There was no layout before, we just created one which - ;; we'll now initialize with our information. - (setf (layout-classoid layout) classoid) - (set-layout-inherits layout inherits) - (assign-layout-slots layout :depthoid depthoid :length length :flags flags) - #-sb-xc-host ; Assign target-only slots - (when (logtest +structure-layout-flag+ flags) - ;; STRING-STREAM and FILE-STREAM have depthoid=4 but are not structure types - (setf (layout-bitmap layout) bitmap)) - ;; Finally, make it valid. - (setf (layout-invalid layout) nil)) - ;; FIXME: Now that LAYOUTs are born :UNINITIALIZED, maybe this - ;; clause is not needed? - ((not *type-system-initialized*) - (setf (layout-classoid layout) classoid)) - (t - ;; There was an old layout already initialized with old - ;; information, and we'll now check that old information - ;; which was known with certainty is consistent with current - ;; information which is known with certainty. - (check-layout layout classoid length inherits depthoid bitmap))) - layout) - -;;; In code for the target Lisp, we don't dump LAYOUTs using the -;;; standard load form mechanism, we use special fops instead, in -;;; order to make cold load come out right. But when we're building -;;; the cross-compiler, we can't do that because we don't have access -;;; to special non-ANSI low-level things like special fops, and we -;;; don't need to do that anyway because our code isn't going to be -;;; cold loaded, so we use the ordinary load form system. -#+sb-xc-host -(defmethod make-load-form ((layout layout) &optional env) - (declare (ignore env)) - (when (layout-invalid layout) - (sb-c:compiler-error "can't dump reference to obsolete class: ~S" - (layout-classoid layout))) - (let* ((classoid (layout-classoid layout)) - (name (classoid-name classoid))) - (aver (= (layout-flags layout) - (typecase classoid - (structure-classoid +structure-layout-flag+) - (condition-classoid +condition-layout-flag+) - (undefined-classoid - (bug "xc MAKE-LOAD-FORM on undefined layout")) - (t 0)))) - (unless name - (sb-c:compiler-error "can't dump anonymous LAYOUT: ~S" layout)) - ;; Since LAYOUT refers to a class which refers back to the LAYOUT, - ;; we have to do this in two stages, like the TREE-WITH-PARENT - ;; example in the MAKE-LOAD-FORM entry in the ANSI spec. - (values - ;; "creation" form (which actually doesn't create a new LAYOUT if - ;; there's a preexisting one with this name) - `(find-layout ',name) - ;; "initialization" form (which actually doesn't initialize - ;; preexisting LAYOUTs, just checks that they're consistent). - `(%init-or-check-layout ,layout - ,(layout-classoid layout) - ,(layout-length layout) - ,(layout-flags layout) - ,(layout-inherits layout) - ,(layout-depthoid layout) - ,(layout-bitmap layout))))) - ;;; If LAYOUT's slot values differ from the specified slot values in ;;; any interesting way, then give a warning and return T. (declaim (ftype (function (simple-string - layout + wrapper simple-string index simple-vector layout-depthoid layout-bitmap)) - redefine-layout-warning)) -(defun redefine-layout-warning (old-context old-layout - context length inherits depthoid bitmap) - (declare (type layout old-layout) (type simple-string old-context context)) - (let ((name (layout-proper-name old-layout)) - (old-inherits (layout-inherits old-layout))) - (or (when (mismatch old-inherits inherits :key #'layout-proper-name) + warn-if-altered-layout)) +(defun warn-if-altered-layout (old-context old-layout context + length inherits depthoid bitmap) + (let ((name (wrapper-proper-name old-layout)) + (old-inherits (wrapper-inherits old-layout))) + (or (when (mismatch old-inherits inherits :key #'wrapper-proper-name) (warn "change in superclasses of class ~S:~% ~ ~A superclasses: ~S~% ~ ~A superclasses: ~S" name old-context - (map 'list #'layout-proper-name old-inherits) + (map 'list #'wrapper-proper-name old-inherits) context - (map 'list #'layout-proper-name inherits)) + (map 'list #'wrapper-proper-name inherits)) t) (let ((diff (mismatch old-inherits inherits))) (when diff @@ -213,10 +206,10 @@ ~A definition." name old-context - (layout-proper-name (svref old-inherits diff)) + (wrapper-proper-name (svref old-inherits diff)) context) t)) - (let ((old-length (layout-length old-layout))) + (let ((old-length (wrapper-length old-layout))) (unless (= old-length length) (warn "change in instance length of class ~S:~% ~ ~A length: ~W~% ~ @@ -225,79 +218,161 @@ old-context old-length context length) t)) - (let ((old-bitmap (layout-bitmap old-layout))) + ;; The "%" accessor reads the bitmap from the layout, + ;; not from its related defstruct-description. + (let ((old-bitmap (%layout-bitmap old-layout))) (unless (= old-bitmap bitmap) (warn "change in placement of raw slots of class ~S ~ between the ~A definition and the ~A definition" name old-context context) t)) - (unless (= (layout-depthoid old-layout) depthoid) + (unless (= (wrapper-depthoid old-layout) depthoid) (warn "change in the inheritance structure of class ~S~% ~ between the ~A definition and the ~A definition" name old-context context) t)))) -;;; Require that LAYOUT data be consistent with CLASSOID, LENGTH, -;;; INHERITS, DEPTHOID, and BITMAP. -(declaim (ftype (function (layout classoid index simple-vector layout-depthoid layout-bitmap)) - check-layout)) -(defun check-layout (layout classoid length inherits depthoid bitmap) - (aver (eq (layout-classoid layout) classoid)) - (when (redefine-layout-warning "current" layout - "compile time" length inherits depthoid bitmap) - ;; Classic CMU CL had more options here. There are several reasons - ;; why they might want more options which are less appropriate for - ;; us: (1) It's hard to fit the classic CMU CL flexible approach - ;; into the ANSI-style MAKE-LOAD-FORM system, and having a - ;; non-MAKE-LOAD-FORM-style system is painful when we're trying to - ;; make the cross-compiler run under vanilla ANSI Common Lisp. (2) - ;; We have CLOS now, and if you want to be able to flexibly - ;; redefine classes without restarting the system, it'd make sense - ;; to use that, so supporting complexity in order to allow - ;; modifying DEFSTRUCTs without restarting the system is a low - ;; priority. (3) We now have the ability to rebuild the SBCL - ;; system from scratch, so we no longer need this functionality in - ;; order to maintain the SBCL system by modifying running images. - (error "The loaded code expects an incompatible layout for class ~S." - (layout-proper-name layout))) - (values)) - -;;; a common idiom (the same as CMU CL FIND-LAYOUT) rolled up into a -;;; single function call -;;; ;;; Used by the loader to forward-reference layouts for classes whose ;;; definitions may not have been loaded yet. This allows type tests ;;; to be loaded when the type definition hasn't been loaded yet. -(defun find-and-init-or-check-layout (name depthoid flags length bitmap inherits) - (truly-the ; avoid an "assertion too complex to check" optimizer note - (values layout &optional) - (with-world-lock () - (let ((layout (find-layout name))) - (%init-or-check-layout layout - (or (find-classoid name nil) - (layout-classoid layout)) - length - flags - inherits - depthoid - bitmap))))) - -;;; Record LAYOUT as the layout for its class, adding it as a subtype +;;; +;;; If we can't find any existing layout, then we create a new one +;;; with the supplied information, storing it in +;;; *FORWARD-REFERENCED-LAYOUTS*. If we can find the layout, then +;;; return it, after checking for compatibility. If incompatible, we +;;; allow the layout to be replaced, altered or left alone. +(defun load-layout (name depthoid inherits length bitmap flags) + (let* ((table *forward-referenced-wrappers*) + (classoid (find-classoid name nil)) ; thread safety + (new-layout (make-layout (hash-layout-name name) + (or classoid (make-undefined-classoid name)) + :depthoid depthoid :inherits inherits + :length length :bitmap bitmap :flags flags)) + (existing-layout + (or (and classoid (classoid-wrapper classoid)) + (with-world-lock () + (let ((classoid (find-classoid name nil))) + (when classoid + (setf (wrapper-classoid new-layout) classoid)) + (or (and classoid (classoid-wrapper classoid)) + (ensure-gethash name table new-layout)))))) + (classoid + (or (find-classoid name nil) (wrapper-classoid existing-layout)))) + (cond ((or (eq (wrapper-invalid existing-layout) :uninitialized) + (not *type-system-initialized*)) + (setf (wrapper-classoid existing-layout) classoid)) + ;; There was an old layout already initialized with old + ;; information, and we'll now check that old information + ;; which was known with certainty is consistent with current + ;; information which is known with certainty. + ((warn-if-altered-layout "current" existing-layout "compile time" + length inherits depthoid bitmap) + (%redefine-defstruct classoid existing-layout new-layout))) + existing-layout)) + +(defun classoid-lock (classoid) + #+sb-xc-host (declare (ignore classoid)) + #-sb-xc-host + (or (classoid-%lock classoid) + (let* ((lock (sb-thread:make-mutex :name "classoid lock")) + (oldval (cas (classoid-%lock classoid) nil lock))) + (if (eq oldval nil) lock oldval)))) + +(defun add-subclassoid (super sub wrapper) + (with-system-mutex ((classoid-lock super)) + (let ((table (classoid-subclasses super)) + (count 0)) + (cond ((hash-table-p table) + (setf (gethash sub table) wrapper)) + ((dolist (cell table) + (when (eq (car cell) sub) + (return (setf (cdr cell) wrapper))) + (incf (truly-the fixnum count)))) + ((<= count 7) + (setf (classoid-subclasses super) (acons sub wrapper table)) + ;; Is this barrier really necessary? mutex release is a release barrier. + ;; I was probably struggling with crashes in the 'classoid-typep.impure' + ;; test, and was just trying anything and everything. + (sb-thread:barrier (:write)) + wrapper) + (t + ;; Upgrade to a hash-table + (let ((new #+sb-xc-host (make-hash-table :test 'eq) + #-sb-xc-host (make-hash-table :hash-function #'type-hash-value + :test 'eq))) + (loop for (key . val) in table do (setf (gethash key new) val)) + (setf (gethash sub new) wrapper) + (setf (classoid-subclasses super) new) + (sb-thread:barrier (:write)) + wrapper)))))) + +;;; Mnemonic device: the argument order is as GETHASH (1st = key, 2nd = table). +;;; But the 2nd arg is the superclassoid, *not* its subclassoid table, +;;; because the mutex is stored in the classoid, not the table. +(defun get-subclassoid (sub super) + (sb-thread:barrier (:read)) + (let ((table (classoid-subclasses super))) + (when table + (cond ((listp table) (cdr (assq sub table))) + (t + ;; our hash-table are not safe to read with a single writer + (with-system-mutex ((classoid-lock super)) + (values (gethash sub table)))))))) + +;;; Mnemonic device: it's like REMHASH (1st = key, 2nd = table) +(defun remove-subclassoid (sub super) + (sb-thread:barrier (:read)) + (when (classoid-subclasses super) + (with-system-mutex ((classoid-lock super)) + (let ((table (classoid-subclasses super))) + (cond ((listp table) + (setf (classoid-subclasses super) + (delete sub table :key #'car :test #'eq))) + (t + ;; There's no reason to demote a table to a list ever. + (remhash sub table)))))) + nil) + +(defmacro do-subclassoids (((classoid-var wrapper-var) super) &body body) + (let ((f (make-symbol "FUNCTION"))) + `(dx-flet ((,f (,classoid-var ,wrapper-var) ,@body)) + (call-with-subclassoids #',f (the classoid ,super))))) + +(defun call-with-subclassoids (function super &aux (table (classoid-subclasses super))) + ;; Uses of DO-SUBCLASSOIDS don't need to acquire the classoid lock on SUPER. + ;; Even if there are readers or writers, hash-table iteration is safe. + ;; This was not always so - iteration could overrun the k/v array because it always + ;; re-fetched the scan limit, which could see a higher limit than corresponded + ;; to the k/v vector that it had gotten initially. + ;; If you're doing concurrent modification of the class heterarchy, there are no + ;; real guarantees. We dont' always hold a lock at a wider scope than the table lock, + ;; but sometimes we do, such as in REGISTER-LAYOUT. + (if (listp table) + (loop for (key . value) in table do (funcall function key value)) + (maphash (lambda (key value) (funcall function key value)) + table)) + nil) + +;;; Record WRAPPER as the layout for its class, adding it as a subtype ;;; of all superclasses. This is the operation that "installs" a ;;; layout for a class in the type system, clobbering any old layout. ;;; However, this does not modify the class namespace; that is a ;;; separate operation (think anonymous classes.) ;;; -- If INVALIDATE, then all the layouts for any old definition ;;; and subclasses are invalidated, and the SUBCLASSES slot is cleared. -;;; -- If DESTRUCT-LAYOUT, then this is some old layout, and is to be -;;; destructively modified to hold the same type information. -(eval-when (#-sb-xc :compile-toplevel :load-toplevel :execute) -(defun register-layout (layout &key (invalidate t) destruct-layout) - (declare (type layout layout) (type (or layout null) destruct-layout)) +;;; -- If MODIFY is given, then it is some old layout, and is to be +;;; destructively altered to hold the same data as WRAPPER. +(macrolet ((set-bitmap-from-layout (to-layout from-layout) + `(let ((to-index (bitmap-start ,to-layout)) + (from-index (bitmap-start ,from-layout))) + (dotimes (i (bitmap-nwords ,from-layout)) + (%raw-instance-set/word ,to-layout (+ to-index i) + (%raw-instance-ref/word ,from-layout (+ from-index i))))))) +(defun register-layout (wrapper &key (invalidate t) modify) + (declare (type wrapper wrapper) (type (or wrapper null) modify)) (with-world-lock () - (let* ((classoid (layout-classoid layout)) - (classoid-layout (classoid-layout classoid)) - (subclasses (classoid-subclasses classoid))) + (let* ((classoid (wrapper-classoid wrapper)) + (classoid-wrapper (classoid-wrapper classoid))) ;; Attempting to register ourselves with a temporary undefined ;; class placeholder is almost certainly a programmer error. (I @@ -307,58 +382,73 @@ between the ~A definition and the ~A definition" ;; This assertion dates from classic CMU CL. The rationale is ;; probably that calling REGISTER-LAYOUT more than once for the ;; same LAYOUT is almost certainly a programmer error. - (aver (not (eq classoid-layout layout))) + (aver (not (eq classoid-wrapper wrapper))) ;; Figure out what classes are affected by the change, and issue ;; appropriate warnings and invalidations. - (when classoid-layout + (when classoid-wrapper (%modify-classoid classoid) - (when subclasses - (dohash ((subclass subclass-layout) subclasses :locked t) + (do-subclassoids ((subclass subclass-wrapper) classoid) ; under WORLD-LOCK (%modify-classoid subclass) (when invalidate - (%invalidate-layout subclass-layout)))) + (%invalidate-layout subclass-wrapper))) (when invalidate - (%invalidate-layout classoid-layout) + (%invalidate-layout classoid-wrapper) (setf (classoid-subclasses classoid) nil))) - (if destruct-layout + (if modify #+sb-xc-host (error "Why mutate a layout in XC host?") #-sb-xc-host ;; Destructively modifying a layout is not threadsafe at all. ;; Use at your own risk (interactive use only). - (let ((inherits (layout-inherits layout)) - (depthoid (layout-depthoid layout))) + (let ((inherits (wrapper-inherits wrapper)) + (depthoid (wrapper-depthoid wrapper)) ; "new" depthoid + (extra-id-words ; "old" extra words + (calculate-extra-id-words (wrapper-depthoid modify))) + (layout (wrapper-friend wrapper)) + (id ; read my ID before screwing with the depthoid + (layout-id modify))) (aver (logtest +structure-layout-flag+ (layout-flags layout))) (aver (= (length inherits) depthoid)) - #-64-bit (setf (layout-depthoid destruct-layout) (layout-depthoid layout) - (layout-length destruct-layout) (layout-length layout)) - (setf (layout-flags destruct-layout) (layout-flags layout) - (layout-info destruct-layout) (layout-info layout) - (layout-bitmap destruct-layout) (layout-bitmap layout)) - (set-layout-inherits destruct-layout inherits) - (setf (layout-invalid destruct-layout) nil - (classoid-layout classoid) destruct-layout)) - (setf (layout-invalid layout) nil - (classoid-layout classoid) layout)) - - (dovector (super-layout (layout-inherits layout)) - (let* ((super (layout-classoid super-layout)) - (subclasses (or (classoid-subclasses super) - (setf (classoid-subclasses super) - (make-hash-table :test 'eq - #-sb-xc-host #-sb-xc-host - :synchronized t))))) + ;; DEPTHOID implies the number of words of "extra" IDs preceding the bitmap. + ;; Layout alteration is forbidden if it would affect the number of such words. + ;; So MUTABLE-LAYOUT-P should have checked that this is OK, but assert it + ;; again to be certain. Heap corruption is the greater evil versus a minor + ;; inconvenience of not offering the RECKLESSLY-CONTINUE restart. + (aver (= (calculate-extra-id-words depthoid) extra-id-words)) + #-64-bit (setf (wrapper-depthoid modify) (wrapper-depthoid wrapper) + (wrapper-length modify) (wrapper-length wrapper)) + (setf (layout-flags (wrapper-friend modify)) (layout-flags layout) + (wrapper-info modify) (wrapper-info wrapper)) + ;; Zero out the inherited ID values one word at a time. + ;; This makes self-ID transiently disappear, but what else can we do? + ;; It's may be in the wrong slot anyway, depending on whether depthoid changed. + ;; The calculation of the min word count of 3 or 6 is done as + ;; (/ (- (1+ layout-id-vector-fixed-capacity) 2) number-of-ids-per-word) + ;; which is surely more confusing than spelling it as 3 or 6. + (dotimes (i (+ extra-id-words #+64-bit 3 #-64-bit 6)) + (%raw-instance-set/word (wrapper-friend modify) + (+ (get-dsd-index sb-vm:layout id-word0) i) + 0)) + (set-layout-inherits modify inherits t id) + (let ((dst (wrapper-friend modify)) + (src (wrapper-friend wrapper))) + (set-bitmap-from-layout dst src)) + (setf (wrapper-invalid modify) nil + (classoid-wrapper classoid) modify)) + (setf (wrapper-invalid wrapper) nil + (classoid-wrapper classoid) wrapper)) + + (dovector (super-wrapper (wrapper-inherits wrapper)) + (let ((super (wrapper-classoid super-wrapper))) (when (and (eq (classoid-state super) :sealed) - (not (gethash classoid subclasses))) + (not (get-subclassoid classoid super))) (warn "unsealing sealed class ~S in order to subclass it" (classoid-name super)) (setf (classoid-state super) :read-only)) - (setf (gethash classoid subclasses) - (or destruct-layout layout)))))) + (add-subclassoid super classoid (or modify wrapper)))))) - (values)) -); EVAL-WHEN + (values))) ;;; Arrange the inherited layouts to appear at their expected depth, ;;; ensuring that hierarchical type tests succeed. Layouts with @@ -368,6 +458,18 @@ between the ~A definition and the ~A definition" ;;; elements are filled with their successors, ensuring that each ;;; element contains a valid layout. ;;; +;;; *** FIXME *** the preceding comment seems dubious, and I'm not sure whether +;;; to fix the code or the comment or both. The code works as-is, but is too hairy. +;;; I fail to see how "still-empty" elements can exist after filling in mandatory +;;; elements. It seems to anticipate being able to create a type whose INHERITS vector +;;; length exceeds depthoid, or, say, a type at depthoid 5 which inherits STREAM but +;;; might lack an entry at depth index 1 for example. As to why I think the comment +;;; is false: FILE-STREAM and STRING-STREAM each have depthoid 4, but their INHERITS +;;; vector has length 2. So they don't store elements that would be at index 2 and 3. +;;; Length less than depthoid is opposite of what the fill-in logic supports. +;;; How, in practice, could a user achieve such weird states as need this logic? +;;; If impossible, then simplify it. + ;;; This reordering may destroy CPL ordering, so the inherits should ;;; not be read as being in CPL order. (defun order-layout-inherits (layouts) @@ -375,7 +477,7 @@ between the ~A definition and the ~A definition" (let ((length (length layouts)) (max-depth -1)) (dotimes (i length) - (let ((depth (layout-depthoid (svref layouts i)))) + (let ((depth (wrapper-depthoid (svref layouts i)))) (when (> depth max-depth) (setf max-depth depth)))) (let* ((new-length (max (1+ max-depth) length)) @@ -386,7 +488,7 @@ between the ~A definition and the ~A definition" (inherits (make-array new-length :initial-element 0))) (dotimes (i length) (let* ((layout (svref layouts i)) - (depth (layout-depthoid layout))) + (depth (wrapper-depthoid layout))) (unless (eql depth -1) (let ((old-layout (svref inherits depth))) (unless (or (eql old-layout 0) (eq old-layout layout)) @@ -397,7 +499,7 @@ between the ~A definition and the ~A definition" ((>= i length)) (declare (type index i j)) (let* ((layout (svref layouts i)) - (depth (layout-depthoid layout))) + (depth (wrapper-depthoid layout))) (when (eql depth -1) (loop (when (eql (svref inherits j) 0) (return)) @@ -479,29 +581,48 @@ between the ~A definition and the ~A definition" (note-class class) (topological-sort classes constraints #'std-cpl-tie-breaker)))) -;;;; object types to represent classes - -;;; BUILT-IN-CLASS is used to represent the standard classes that -;;; aren't defined with DEFSTRUCT and other specially implemented -;;; primitive types whose only attribute is their name. -;;; It is defined in 'early-classoid.lisp' - -;;; STRUCTURE-CLASS represents what we need to know about structure -;;; classes. Non-structure "typed" defstructs are a special case, and -;;; don't have a corresponding class. -(def!struct (structure-classoid (:include classoid) - (:copier nil) - (:constructor make-structure-classoid - (&key name &aux (%bits (pack-ctype-bits classoid name)))))) + +;;; Return the layout for an object. This is the basic operation for +;;; finding out the "type" of an object, and is used for generic +;;; function dispatch. The standard doesn't seem to say as much as it +;;; should about what this returns for built-in objects. For example, +;;; it seems that we must return NULL rather than LIST when X is NIL +;;; so that GF's can specialize on NULL. +;;; x86-64 has a vop that implements this without even needing to place +;;; the vector of layouts in the constant pool of the containing code. +#-(or sb-xc-host (and compact-instance-header x86-64)) +(progn +(declaim (inline wrapper-of)) +(defun wrapper-of (x) + (declare (optimize (speed 3) (safety 0))) + (cond ((%instancep x) (%instance-wrapper x)) + ((funcallable-instance-p x) (%fun-wrapper x)) + ;; Compiler can dump literal layouts, which handily sidesteps + ;; the question of when cold-init runs L-T-V forms. + ((null x) #.(find-layout 'null)) + (t + ;; Note that WIDETAG-OF is slightly suboptimal here and could be + ;; improved - we've already ruled out some of the lowtags. + (layout-friend + (svref (load-time-value **primitive-object-layouts** t) + (widetag-of x))))))) + +#-sb-xc-host +(progn +(declaim (inline classoid-of)) +(defun classoid-of (object) + "Return the class of the supplied object, which may be any Lisp object, not + just a CLOS STANDARD-OBJECT." + (wrapper-classoid (wrapper-of object)))) + ;;;; classoid namespace (eval-when (#-sb-xc :compile-toplevel :load-toplevel :execute) (defun (setf find-classoid) (new-value name) - #-sb-xc (declare (type (or null classoid) new-value)) + (declare (type (or null classoid) new-value)) (aver new-value) - (let ((table *forward-referenced-layouts*)) - (with-world-lock () + (with-world-lock () (let ((cell (find-classoid-cell name :create t))) (ecase (info :type :kind name) ((nil)) @@ -524,12 +645,12 @@ between the ~A definition and the ~A definition" ;; modulo potential differences with respect to ;; conditions). #+sb-xc-host - (let ((old (class-of old-value)) - (new (class-of new-value))) + (let ((old (cl:class-of old-value)) + (new (cl:class-of new-value))) (unless (eq old new) (bug "Trying to change the metaclass of ~S from ~S to ~S in the ~ cross-compiler." - name (class-name old) (class-name new)))) + name (cl:class-name old) (cl:class-name new)))) #-sb-xc-host (let ((old (classoid-of old-value)) (new (classoid-of new-value))) @@ -545,7 +666,7 @@ between the ~A definition and the ~A definition" (clear-info :type :expander name) (clear-info :type :source-location name))) - (remhash name table) + (remhash name *forward-referenced-wrappers*) (%note-type-defined name) ;; FIXME: I'm unconvinced of the need to handle either of these. ;; Package locks preclude the latter, and in the former case, @@ -567,9 +688,9 @@ between the ~A definition and the ~A definition" (setf (info :type :kind name) :instance))) (setf (classoid-cell-classoid cell) new-value) (unless (eq (info :type :compiler-layout name) - (classoid-layout new-value)) + (classoid-wrapper new-value)) (setf (info :type :compiler-layout name) - (classoid-layout new-value)))))) + (classoid-wrapper new-value))))) new-value) (defun %clear-classoid (name cell) @@ -600,6 +721,25 @@ between the ~A definition and the ~A definition" (clear-info :type :compiler-layout name) (values-specifier-type-cache-clear))))) +(defun find-classoid-cell (name &key create) + (cond ((info :type :classoid-cell name)) + (create + (get-info-value-initializing :type :classoid-cell name + (make-classoid-cell name))))) + +;;; Return the classoid with the specified NAME. If ERRORP is false, +;;; then NIL is returned when no such class exists. +(defun find-classoid (name &optional (errorp t)) + (declare (type symbol name)) + (let ((cell (find-classoid-cell name))) + (cond ((and cell (classoid-cell-classoid cell))) + (errorp + (error 'simple-type-error + :datum nil + :expected-type 'class + :format-control "Class not yet defined: ~S" + :format-arguments (list name)))))) + ;;; Called when we are about to define NAME as a class meeting some ;;; predicate (such as a meta-class type test.) The first result is ;;; always of the desired class. The second result is any existing @@ -608,23 +748,24 @@ between the ~A definition and the ~A definition" ;;; Again, this should be compiler-only, but easier to make this ;;; thread-safe. (defun insured-find-classoid (name predicate constructor) - (declare (type function predicate constructor)) - (let ((table *forward-referenced-layouts*)) - (with-locked-system-table (table) + (declare (type function predicate) + (type (or function symbol) constructor)) + (let ((table *forward-referenced-wrappers*)) + (with-system-mutex ((hash-table-lock table)) (let* ((old (find-classoid name nil)) (res (if (and old (funcall predicate old)) old (funcall constructor :name name))) (found (or (gethash name table) - (when old (classoid-layout old))))) + (when old (classoid-wrapper old))))) (when found - (setf (layout-classoid found) res)) + (setf (wrapper-classoid found) res)) (values res found))))) ;;; If the classoid has a proper name, return the name, otherwise return ;;; the classoid. (defun classoid-proper-name (classoid) - #-sb-xc (declare (type classoid classoid)) + (declare (type classoid classoid)) (let ((name (classoid-name classoid))) (if (and name (eq (find-classoid name nil) classoid)) name @@ -655,23 +796,23 @@ between the ~A definition and the ~A definition" (let ((super (if (symbolp super-or-name) (find-classoid super-or-name) super-or-name))) - (find (classoid-layout super) - (layout-inherits (classoid-layout sub))))) + (find (classoid-wrapper super) + (wrapper-inherits (classoid-wrapper sub))))) ;;; We might be passed classoids with invalid layouts; in any pairwise ;;; class comparison, we must ensure that both are valid before ;;; proceeding. (defun %ensure-classoid-valid (classoid layout error-context) (declare (ignorable error-context)) ; not used on host - (aver (eq classoid (layout-classoid layout))) - (or (not (layout-invalid layout)) + (aver (eq classoid (wrapper-classoid layout))) + (or (not (wrapper-invalid layout)) ;; Avoid accidentally reaching code that can't work. #+sb-xc-host (bug "(TYPEP x 'STANDARD-CLASSOID) can't be tested") #-sb-xc-host (if (typep classoid 'standard-classoid) (let ((class (classoid-pcl-class classoid))) (cond - ((sb-pcl:class-finalized-p class) + ((sb-mop:class-finalized-p class) (sb-pcl::%force-cache-flushes class) t) ((sb-pcl::class-has-a-forward-referenced-superclass-p class) @@ -683,17 +824,17 @@ between the ~A definition and the ~A definition" error-context)) nil) (t - (sb-pcl:finalize-inheritance class) + (sb-mop:finalize-inheritance class) t))) (bug "~@<Don't know how to ensure validity of ~S (not a STANDARD-CLASSOID) ~ for ~A.~%~:@>" classoid (or error-context 'subtypep))))) (defun %ensure-both-classoids-valid (class1 class2 &optional errorp) - (do ((layout1 (classoid-layout class1) (classoid-layout class1)) - (layout2 (classoid-layout class2) (classoid-layout class2)) + (do ((layout1 (classoid-wrapper class1) (classoid-wrapper class1)) + (layout2 (classoid-wrapper class2) (classoid-wrapper class2)) (i 0 (+ i 1))) - ((and (not (layout-invalid layout1)) (not (layout-invalid layout2))) + ((and (not (wrapper-invalid layout1)) (not (wrapper-invalid layout2))) t) (aver (< i 2)) (unless (and (%ensure-classoid-valid class1 layout1 errorp) @@ -709,10 +850,10 @@ between the ~A definition and the ~A definition" (define-type-method (classoid :simple-subtypep) (class1 class2) (aver (not (eq class1 class2))) - (with-world-lock () + (with-world-lock () ; FIXME: why such coarse lock granularity here? (if (%ensure-both-classoids-valid class1 class2) - (let ((subclasses2 (classoid-subclasses class2))) - (if (and subclasses2 (gethash class1 subclasses2)) + (let () + (if (get-subclassoid class1 class2) (values t t) (if (and (typep class1 'standard-classoid) (typep class2 'standard-classoid) @@ -735,10 +876,12 @@ between the ~A definition and the ~A definition" (let ((s-sub (classoid-subclasses sealed)) (o-sub (classoid-subclasses other))) (if (and s-sub o-sub) + ;; FIXME: should we put more locking here? + ;; [contrast with define-type-method (classoid :simple-subtypep)] (collect ((res *empty-type* type-union)) - (dohash ((subclass layout) s-sub :locked t) - (declare (ignore layout)) - (when (gethash subclass o-sub) + (do-subclassoids ((subclass wrapper) sealed) + (declare (ignore wrapper)) + (when (get-subclassoid subclass other) (res (specifier-type subclass)))) (res)) *empty-type*))) @@ -751,12 +894,8 @@ between the ~A definition and the ~A definition" class1) ;; If one is a subclass of the other, then that is the ;; intersection. - ((let ((subclasses (classoid-subclasses class2))) - (and subclasses (gethash class1 subclasses))) - class1) - ((let ((subclasses (classoid-subclasses class1))) - (and subclasses (gethash class2 subclasses))) - class2) + ((get-subclassoid class1 class2) class1) + ((get-subclassoid class2 class1) class2) ;; Otherwise, we can't in general be sure that the ;; intersection is empty, since a subclass of both might be ;; defined. But we can eliminate it for some special cases. @@ -790,7 +929,7 @@ between the ~A definition and the ~A definition" (declaim (type cons **non-instance-classoid-types**)) (defglobal **non-instance-classoid-types** '(symbol system-area-pointer weak-pointer code-component - #-(or x86 x86-64) lra + #-(or x86 x86-64 arm64 riscv) lra fdefn random-class)) (defun classoid-non-instance-p (classoid) @@ -852,319 +991,410 @@ between the ~A definition and the ~A definition" ;;; List of the direct superclasses of this class. ;;; ;;; NB: not to be confused with SB-PCL::*BUILT-IN-CLASSES* -(defconstant-eqx +!built-in-classes+ - ;; constant-quasiquote-form-p is not smart enough to notice - ;; that this entire thing is constant, so we kind of have to force it. -'#.`((t :state :read-only :translation t) - (character :codes (,sb-vm:character-widetag) - :translation (character-set) - :prototype-form (code-char 42)) - (symbol :codes (,sb-vm:symbol-widetag) - :prototype-form '*) - - (system-area-pointer :codes (,sb-vm:sap-widetag) - :prototype-form (int-sap 0)) - (weak-pointer :codes (,sb-vm:weak-pointer-widetag) - :prototype-form (make-weak-pointer 0)) - (code-component :codes (,sb-vm:code-header-widetag) - :prototype-form (fun-code-header #'identity)) - #-(or x86 x86-64) (lra :codes (,sb-vm:return-pc-widetag) - ;; Make the PROTOTYPE slot unbound. - :prototype-form sb-pcl:+slot-unbound+) - (fdefn :codes (,sb-vm:fdefn-widetag) - :prototype-form (find-or-create-fdefn 'sb-mop:class-prototype)) - (random-class ; used for unknown type codes - ;; Make the PROTOTYPE slot unbound. - :prototype-form sb-pcl:+slot-unbound+) - (function - :codes (,sb-vm:closure-widetag ,sb-vm:simple-fun-widetag) - :state :read-only - :prototype-form #'identity) - - (number :translation number :prototype-form 0) - (complex - :translation complex - :inherits (number) - :codes (,sb-vm:complex-widetag) - :prototype-form ,(complex 0 1)) - (complex-single-float - :translation (complex single-float) - :inherits (complex number) - :codes (,sb-vm:complex-single-float-widetag) - :prototype-form ,(complex $0f0 $0f0)) - (complex-double-float - :translation (complex double-float) - :inherits (complex number) - :codes (,sb-vm:complex-double-float-widetag) - :prototype-form ,(complex $0d0 $0d0)) - #+long-float - (complex-long-float - :translation (complex long-float) - :inherits (complex number) - :codes (,sb-vm:complex-long-float-widetag) - :prototype-form ,(complex $0L0 $0L0)) - #+sb-simd-pack - (simd-pack - :translation simd-pack - :codes (,sb-vm:simd-pack-widetag) - :prototype-form (%make-simd-pack-ub64 42 42)) - #+sb-simd-pack-256 - (simd-pack-256 - :translation simd-pack-256 - :codes (,sb-vm:simd-pack-256-widetag) - :prototype-form - ;; KLUDGE: doesn't work without AVX2 support from the CPU - ;; (%make-simd-pack-256-ub64 42 42 42 42) - sb-pcl:+slot-unbound+) - (real :translation real :inherits (number) :prototype-form 0) - (float :translation float :inherits (real number) :prototype-form $0f0) - (single-float - :translation single-float - :inherits (float real number) - :codes (,sb-vm:single-float-widetag) - :prototype-form $0f0) - (double-float - :translation double-float - :inherits (float real number) - :codes (,sb-vm:double-float-widetag) - :prototype-form $0d0) - #+long-float - (long-float - :translation long-float - :inherits (float real number) - :codes (,sb-vm:long-float-widetag) - :prototype-form $0L0) - (rational - :translation rational :inherits (real number) :prototype-form 0) - (ratio - :translation (and rational (not integer)) - :inherits (rational real number) - :codes (,sb-vm:ratio-widetag) - :prototype-form 1/42) - (integer - :translation integer :inherits (rational real number) :prototype-form 0) - (fixnum - :translation (integer ,sb-xc:most-negative-fixnum ,sb-xc:most-positive-fixnum) - :inherits (integer rational real number) - :codes ,(mapcar #'symbol-value sb-vm::fixnum-lowtags) - :prototype-form 42) - (bignum - :translation (and integer (not fixnum)) - :inherits (integer rational real number) - :codes (,sb-vm:bignum-widetag) - :prototype-form ,(1+ sb-xc:most-positive-fixnum)) - - (array :translation array :codes (,sb-vm:complex-array-widetag) - :hierarchical-p nil - :prototype-form (make-array nil :adjustable t)) - (simple-array - :translation simple-array :codes (,sb-vm:simple-array-widetag) - :inherits (array) - :prototype-form (make-array nil)) - (sequence - :translation (or cons (member nil) vector extended-sequence) - :state :read-only - :depth 1) - (vector - :translation vector :codes (,sb-vm:complex-vector-widetag) - :direct-superclasses (array sequence) - :inherits (array sequence) - :prototype-form (make-array 0 :adjustable t)) - (simple-vector - :translation simple-vector :codes (,sb-vm:simple-vector-widetag) - :direct-superclasses (vector simple-array) - :inherits (vector simple-array array sequence) - :prototype-form (make-array 0)) - (bit-vector - :translation bit-vector :codes (,sb-vm:complex-bit-vector-widetag) - :inherits (vector array sequence) - :prototype-form (make-array 0 :element-type 'bit :fill-pointer t)) - (simple-bit-vector - :translation simple-bit-vector :codes (,sb-vm:simple-bit-vector-widetag) - :direct-superclasses (bit-vector simple-array) - :inherits (bit-vector vector simple-array - array sequence) - :prototype-form #*) - (string - :translation string - :direct-superclasses (vector) - :inherits (vector array sequence) - :prototype-form "") - (simple-string - :translation simple-string - :direct-superclasses (string simple-array) - :inherits (string vector simple-array array sequence) - :prototype-form "") - (vector-nil - :translation (vector nil) - :codes (,sb-vm:complex-vector-nil-widetag) - :direct-superclasses (string) - :inherits (string vector array sequence) - :prototype-form (make-array 0 :element-type 'nil :fill-pointer t)) - (simple-array-nil - :translation (simple-array nil (*)) - :codes (,sb-vm:simple-array-nil-widetag) - :direct-superclasses (vector-nil simple-string) - :inherits (vector-nil simple-string string vector simple-array - array sequence) - :prototype-form (make-array 0 :element-type 'nil)) - (base-string - :translation base-string - :codes (,sb-vm:complex-base-string-widetag) - :direct-superclasses (string) - :inherits (string vector array sequence) - :prototype-form (make-array 0 :element-type 'base-char :fill-pointer t)) - (simple-base-string - :translation simple-base-string - :codes (,sb-vm:simple-base-string-widetag) - :direct-superclasses (base-string simple-string) - :inherits (base-string simple-string string vector simple-array - array sequence) - :prototype-form (make-array 0 :element-type 'base-char)) - #+sb-unicode - (character-string - :translation (vector character) - :codes (,sb-vm:complex-character-string-widetag) - :direct-superclasses (string) - :inherits (string vector array sequence) - :prototype-form (make-array 0 :element-type 'character :fill-pointer t)) - #+sb-unicode - (simple-character-string - :translation (simple-array character (*)) - :codes (,sb-vm:simple-character-string-widetag) - :direct-superclasses (character-string simple-string) - :inherits (character-string simple-string string vector simple-array - array sequence) - :prototype-form (make-array 0 :element-type 'character)) - (list - :translation (or cons (member nil)) - :inherits (sequence) - :prototype-form 'nil) - (cons - :codes (,sb-vm:list-pointer-lowtag) - :translation cons - :inherits (list sequence) - :prototype-form (cons nil nil)) - (null - :translation (member nil) - :inherits (symbol list sequence) - :direct-superclasses (symbol list) - :prototype-form 'nil) - ;; These last few are strange. STREAM has only T as an ancestor, - ;; so you'd think it would be at depth 1. FILE- and STRING-STREAM - ;; each have STREAM and T as ancestors, so you'd think they'd be at depth - ;; 1 greater than STREAM, instead of 2 greater. But changing any of - ;; these to the "obvious" value makes various type checks go wrong. - ;; - ;; Essentially the hardwiring corresponds to the indices of the - ;; respective types in the inherits vector for FD-STREAM. - ;; * (layout-inherits (find-layout 'fd-stream)) - ;; #(#<LAYOUT for T {50300003}> - ;; #<LAYOUT for STRUCTURE-OBJECT {50300103}> - ;; #<LAYOUT for STREAM {50301003}> - ;; #<LAYOUT for ANSI-STREAM {50301183}> - ;; #<LAYOUT for FILE-STREAM {50303303}>) - - (stream - :state :read-only - :depth 2) - (file-stream - :state :read-only - :depth 4 - :inherits (stream)) - (string-stream - :state :read-only - :depth 4 - :inherits (stream)) - ,@(loop for x across sb-vm:*specialized-array-element-type-properties* - unless (member (sb-vm:saetp-specifier x) '(t character base-char nil bit)) - collect - ;; I'm not sure if it's an accident that there are distinct SB-KERNEL - ;; versus SB-VM symbols for the specialized arrays. The former are types - ;; in the language, and the latter are primitive object types, - ;; but istm they should be designated by the same symbols. - `(,(intern (string (sb-vm:saetp-primitive-type-name x)) *package*) - :translation (simple-array ,(sb-vm:saetp-specifier x) (*)) - :codes (,(sb-vm:saetp-typecode x)) - :direct-superclasses (vector simple-array) - :inherits (vector simple-array array sequence) - :prototype-form - (logically-readonlyize - (make-array 0 :element-type ',(sb-vm:saetp-specifier x)))))) - #'equal) - -;;; See also src/code/class-init.lisp where we finish setting up the +;;; (note the difference in spelling, to help keep things unconfusing) +#+sb-xc-host +(defvar *builtin-classoids* + ;; This variable holds data expressed as conses, some of which are "similar" (in + ;; this case, EQUAL) to each other, but not EQL to each other at read-time. + ;; Host compilers can differ in how they treat "similar" data on + ;; file-compilation; they are entitled to coalesce data to be EQL. Differences + ;; in those host choices then manifest (cosmetically) in target data, where the + ;; resulting value of *BUILTIN-CLASSOIDS* at cold-load time differs in its + ;; structure between e.g. SBCL and CCL hosts. + ;; + ;; To avoid this difference, we postprocess the data structure to + ;; convert all similar data within it to be EQL, at which point the + ;; host compiler no longer has choices: EQL data must remain EQL + ;; after file-compilation. + ;; + ;; FIXME: it might be nice if our cross-compile backquote reader + ;; did hash-consing for us automatically. Without thinking too + ;; hard about it, though, it might need to be sufficiently smart + ;; to be able to handle nested backquotations and/or + ;; backquotations within unquotations. + (let ((table (make-hash-table :test 'equal))) + (labels ((hash-cons (thing) + (cond + ((atom thing) thing) + ((gethash thing table)) + (t (setf (gethash thing table) + (cons (hash-cons (car thing)) (hash-cons (cdr thing)))))))) + (hash-cons + `((t :state :read-only :translation t) + (character :codes (,sb-vm:character-widetag) + :translation (character-set) + :prototype-form (code-char 42)) + (symbol :codes (,sb-vm:symbol-widetag) + :predicate symbolp + :prototype-form '*) + + (system-area-pointer :codes (,sb-vm:sap-widetag) + :predicate system-area-pointer-p + :prototype-form (int-sap 0)) + (weak-pointer :codes (,sb-vm:weak-pointer-widetag) + :predicate weak-pointer-p + :prototype-form (make-weak-pointer 0)) + (code-component :codes (,sb-vm:code-header-widetag) + :predicate code-component-p + :prototype-form (fun-code-header #'identity)) + #-(or x86 x86-64 arm64 riscv) + (lra :codes (,sb-vm:return-pc-widetag) + :predicate lra-p + ;; Make the PROTOTYPE slot unbound. + :prototype-form sb-pcl:+slot-unbound+) + (fdefn :codes (,sb-vm:fdefn-widetag) + :predicate fdefn-p + :prototype-form (find-or-create-fdefn 'sb-mop:class-prototype)) + (random-class ; used for unknown type codes + ;; Make the PROTOTYPE slot unbound. + :prototype-form sb-pcl:+slot-unbound+) + (function + :codes (,sb-vm:closure-widetag ,sb-vm:simple-fun-widetag) + :predicate functionp + :state :read-only + :prototype-form #'identity) + + (number :translation number :prototype-form 0) + (complex + :translation complex + :inherits (number) + :codes (,sb-vm:complex-widetag) + :prototype-form ,(complex 0 1)) + (complex-single-float + :translation (complex single-float) + :inherits (complex number) + :codes (,sb-vm:complex-single-float-widetag) + :prototype-form ,(complex $0f0 $0f0)) + (complex-double-float + :translation (complex double-float) + :inherits (complex number) + :codes (,sb-vm:complex-double-float-widetag) + :prototype-form ,(complex $0d0 $0d0)) + #+long-float + (complex-long-float + :translation (complex long-float) + :inherits (complex number) + :codes (,sb-vm:complex-long-float-widetag) + :prototype-form ,(complex $0L0 $0L0)) + #+sb-simd-pack + (simd-pack + :translation simd-pack + :codes (,sb-vm:simd-pack-widetag) + :prototype-form (%make-simd-pack-ub64 42 42)) + #+sb-simd-pack-256 + (simd-pack-256 + :translation simd-pack-256 + :codes (,sb-vm:simd-pack-256-widetag) + :prototype-form + ;; KLUDGE: doesn't work without AVX2 support from the CPU + ;; (%make-simd-pack-256-ub64 42 42 42 42) + sb-pcl:+slot-unbound+) + (real :translation real :inherits (number) :prototype-form 0) + (float :translation float :inherits (real number) :prototype-form $0f0) + (single-float + :translation single-float + :inherits (float real number) + :codes (,sb-vm:single-float-widetag) + :prototype-form $0f0) + (double-float + :translation double-float + :inherits (float real number) + :codes (,sb-vm:double-float-widetag) + :prototype-form $0d0) + #+long-float + (long-float + :translation long-float + :inherits (float real number) + :codes (,sb-vm:long-float-widetag) + :prototype-form $0L0) + (rational + :translation rational :inherits (real number) :prototype-form 0) + (ratio + :translation (and rational (not integer)) + :inherits (rational real number) + :codes (,sb-vm:ratio-widetag) + :prototype-form 1/42) + (integer + :translation integer :inherits (rational real number) :prototype-form 0) + (fixnum + :translation (integer ,most-negative-fixnum ,most-positive-fixnum) + :inherits (integer rational real number) + :codes ,sb-vm::fixnum-lowtags + :prototype-form 42) + (bignum + :translation (and integer (not fixnum)) + :inherits (integer rational real number) + :codes (,sb-vm:bignum-widetag) + :prototype-form ,(1+ most-positive-fixnum)) + + (array :translation array :codes (,sb-vm:complex-array-widetag) + :hierarchical-p nil + :prototype-form (make-array nil :adjustable t)) + (simple-array + :translation simple-array :codes (,sb-vm:simple-array-widetag) + :inherits (array) + :prototype-form (make-array nil)) + (sequence + :translation (or cons (member nil) vector extended-sequence) + :state :read-only + :depth 1) + (vector + :translation vector :codes (,sb-vm:complex-vector-widetag) + :direct-superclasses (array sequence) + :inherits (array sequence) + :prototype-form (make-array 0 :adjustable t)) + (simple-vector + :translation simple-vector :codes (,sb-vm:simple-vector-widetag) + :direct-superclasses (vector simple-array) + :inherits (vector simple-array array sequence) + :prototype-form (make-array 0)) + (bit-vector + :translation bit-vector :codes (,sb-vm:complex-bit-vector-widetag) + :inherits (vector array sequence) + :prototype-form (make-array 0 :element-type 'bit :fill-pointer t)) + (simple-bit-vector + :translation simple-bit-vector :codes (,sb-vm:simple-bit-vector-widetag) + :direct-superclasses (bit-vector simple-array) + :inherits (bit-vector vector simple-array + array sequence) + :prototype-form #*) + (string + :translation string + :direct-superclasses (vector) + :inherits (vector array sequence) + :prototype-form "") + (simple-string + :translation simple-string + :direct-superclasses (string simple-array) + :inherits (string vector simple-array array sequence) + :prototype-form "") + (vector-nil + :translation (vector nil) + :inherits (vector array sequence) + :prototype-form (make-array 0 :element-type 'nil :fill-pointer t)) + ;; This name is imperfect. It should be SIMPLE-RANK1-ARRAY-NIL + ;; to clearly convey that the dimensions are '(*) and not '*. + (simple-array-nil + :translation (simple-array nil (*)) + :codes (,sb-vm:simple-array-nil-widetag) + :direct-superclasses (vector-nil) + :inherits (vector-nil vector simple-array array sequence) + :prototype-form (make-array 0 :element-type 'nil)) + (base-string + :translation base-string + :codes (,sb-vm:complex-base-string-widetag) + :direct-superclasses (string) + :inherits (string vector array sequence) + :prototype-form (make-array 0 :element-type 'base-char :fill-pointer t)) + (simple-base-string + :translation simple-base-string + :codes (,sb-vm:simple-base-string-widetag) + :direct-superclasses (base-string simple-string) + :inherits (base-string simple-string string vector simple-array + array sequence) + :prototype-form (make-array 0 :element-type 'base-char)) + #+sb-unicode + (character-string + :translation (vector character) + :codes (,sb-vm:complex-character-string-widetag) + :direct-superclasses (string) + :inherits (string vector array sequence) + :prototype-form (make-array 0 :element-type 'character :fill-pointer t)) + #+sb-unicode + (simple-character-string + :translation (simple-array character (*)) + :codes (,sb-vm:simple-character-string-widetag) + :direct-superclasses (character-string simple-string) + :inherits (character-string simple-string string vector simple-array + array sequence) + :prototype-form (make-array 0 :element-type 'character)) + (list + :translation (or cons (member nil)) + :inherits (sequence) + :prototype-form 'nil) + (cons + :codes (,sb-vm:list-pointer-lowtag) + :translation cons + :inherits (list sequence) + :prototype-form (cons nil nil)) + (null + :translation (member nil) + :inherits (symbol list sequence) + :direct-superclasses (symbol list) + :prototype-form 'nil) + + (sb-pcl::slot-object + :translation (or structure-object standard-object condition) + :predicate slot-object-p + :hierarchical-p nil + :state :read-only + ;; Why is this its prototype-form? It sure looks like SLOT-OBJECT's + ;; metaobject has a valid prototype object that is the canonical + ;; CLOS object (the usual 2-word thing of layout + slot vector) + :prototype-form (make-defstruct-description 'arbitrary 0)) + + ;; KLUDGE: the length must match the subsequent defstruct. + (pathname :depth 1 + :predicate pathnamep + :length ,(+ 7 sb-vm:instance-data-start) + :prototype-form (make-trivial-default-pathname)) + (logical-pathname :depth 2 + :predicate logical-pathname-p + :length ,(+ 7 sb-vm:instance-data-start) + :prototype-form (make-trivial-default-logical-pathname) + :inherits (pathname)) + + ;; These last few are strange. STREAM has only T as an ancestor, + ;; so you'd think it would be at depth 1. FILE- and STRING-STREAM + ;; each have STREAM and T as ancestors, so you'd think they'd be at depth + ;; 1 greater than STREAM, instead of 2 greater. But changing any of + ;; these to the "obvious" value makes various type checks go wrong. + ;; + ;; Essentially the hardwiring corresponds to the indices of the + ;; respective types in the inherits vector for FD-STREAM. + ;; * (wrapper-inherits (find-layout 'fd-stream)) + ;; #(#<LAYOUT for T {50300003}> + ;; #<LAYOUT for STRUCTURE-OBJECT {50300103}> + ;; #<LAYOUT for STREAM {50301003}> + ;; #<LAYOUT for ANSI-STREAM {50301183}> + ;; #<LAYOUT for FILE-STREAM {50303303}>) + + (stream + :predicate streamp + :state :read-only + :depth 2) + (file-stream + :predicate file-stream-p + :state :read-only + :depth 4 + :inherits (stream)) + (string-stream + :predicate string-stream-p + :state :read-only + :depth 4 + :inherits (stream)) + ,@(loop for x across sb-vm:*specialized-array-element-type-properties* + unless (member (sb-vm:saetp-specifier x) '(t character base-char nil bit)) + collect + ;; I'm not sure if it's an accident that there are distinct SB-KERNEL + ;; versus SB-VM symbols for the specialized arrays. The former are types + ;; in the language, and the latter are primitive object types, + ;; but istm they should be designated by the same symbols. + `(,(intern (string (sb-vm:saetp-primitive-type-name x)) *package*) + :translation (simple-array ,(sb-vm:saetp-specifier x) (*)) + :codes (,(sb-vm:saetp-typecode x)) + :direct-superclasses (vector simple-array) + :inherits (vector simple-array array sequence) + :prototype-form + (logically-readonlyize + (make-array 0 :element-type ',(sb-vm:saetp-specifier x)))))))))) + +(eval-when (#-sb-xc-host :compile-toplevel) + (defun compute-builtin-classoids () + (mapcar (lambda (x) + (let* ((name (car x)) + (classoid (find-classoid name)) + (translation (built-in-classoid-translation classoid)) + (predicate + (if (member name '(t random-class)) + 'error + (or (getf (cdr x) :predicate) + (sb-c::backend-type-predicate translation))))) + (assert predicate) + ;; destructuring-bind will see the first :translation + ;; keyword; we don't need to delete the other one. + (list* name :predicate predicate :translation translation (cdr x)))) + *builtin-classoids*))) + +;;; The read interceptor has to be disabled to avoid infinite recursion on CTYPEs +(eval-when (:compile-toplevel) (setq sb-cold::*choke-on-host-irrationals* nil)) +#-sb-xc-host +(define-load-time-global *builtin-classoids* nil) +#-sb-xc-host +(!cold-init-forms + (setq *builtin-classoids* '#.(compute-builtin-classoids))) +(eval-when (:compile-toplevel) (setq sb-cold::*choke-on-host-irrationals* t)) + +;;; See also src/code/type-init.lisp where we finish setting up the ;;; translations for built-in types. (!cold-init-forms - (dolist (x +!built-in-classes+) - #-sb-xc-host (/show0 "at head of loop over +!BUILT-IN-CLASSES+") - (destructuring-bind - (name &key - (translation nil trans-p) - inherits - codes - state - depth - prototype-form - (hierarchical-p t) ; might be modified below - (direct-superclasses (if inherits - (list (car inherits)) - '(t)))) - x - (declare (ignore codes state translation)) - ;; instance metatypes and T don't need a prototype, everything else does - (unless (or prototype-form depth (eq name 't)) - (error "Missing prototype in ~S" x)) - (let ((inherits-list (if (eq name t) + (dolist (x *builtin-classoids*) + #-sb-xc-host (/show0 "at head of loop over *BUILTIN-CLASSOIDS*") + (destructuring-bind + (name &key + (translation nil trans-p) + predicate + inherits + codes + state + depth + (length 0) + prototype-form + (hierarchical-p t) ; might be modified below + (direct-superclasses (if inherits + (list (car inherits)) + '(t)))) + x + (declare (ignorable codes state translation trans-p predicate)) + ;; instance metatypes and T don't need a prototype, everything else does + (unless (or prototype-form depth (eq name 't)) + (error "Missing prototype in ~S" x)) + (let* ((pred-fn (if (fboundp predicate) (symbol-function predicate) #'error)) + (inherits-list (if (eq name t) () (cons t (reverse inherits)))) (classoid - (acond #+sb-xc ; genesis dumps some classoid literals - ((find-classoid name nil) - ;; Unseal it so that REGISTER-LAYOUT doesn't warn - (setf (classoid-state it) nil) - it) - (t - (setf (classoid-cell-classoid - (find-classoid-cell name :create t)) - (!make-built-in-classoid + (acond #-sb-xc-host ; genesis dumps some classoid literals + ((find-classoid name nil) + (%instance-set it (get-dsd-index built-in-classoid predicate) + pred-fn) + ;; Unseal it so that REGISTER-LAYOUT doesn't warn + (setf (classoid-state it) nil) + it) + (t + (setf (classoid-cell-classoid + (find-classoid-cell name :create t)) + (!make-built-in-classoid :%bits (pack-ctype-bits classoid name) :name name - :translation (if trans-p :initializing nil) + :translation #+sb-xc-host (if trans-p :initializing nil) + #-sb-xc-host translation + :allow-other-keys t :predicate pred-fn :direct-superclasses (if (eq name t) nil (mapcar #'find-classoid direct-superclasses)))))))) - (setf (info :type :kind name) :primitive) - (unless trans-p - (setf (info :type :builtin name) classoid)) - (let* ((inherits-vector + (setf (info :type :kind name) :primitive) + #+sb-xc-host + (unless trans-p + (setf (info :type :builtin name) classoid)) + #-sb-xc-host (setf (info :type :builtin name) (or translation classoid)) + (let* ((inherits-vector (map 'simple-vector (lambda (x) (let ((super-layout - (classoid-layout (find-classoid x)))) - (when (minusp (layout-depthoid super-layout)) + (classoid-wrapper (find-classoid x)))) + (when (minusp (wrapper-depthoid super-layout)) (setf hierarchical-p nil)) super-layout)) inherits-list)) - (depthoid (if hierarchical-p - (or depth (length inherits-vector)) - -1))) - (register-layout - (find-and-init-or-check-layout name - depthoid - 0 ; flags - 0 ; length - +layout-all-tagged+ - inherits-vector) - :invalidate nil))))) - (/show0 "done with loop over +!BUILT-IN-CLASSES+")) - -;;; Now that we have set up the class heterarchy, seal the sealed + (depthoid (if hierarchical-p + (or depth (length inherits-vector)) + -1))) + (register-layout (load-layout name + depthoid + inherits-vector + length + +layout-all-tagged+ + 0) ; flags + :invalidate nil))))) + (/show0 "done with loop over *!BUILTIN-CLASSOIDS*")) + +;;; Now that we have set up the class hierarchy, seal the sealed ;;; classes. This must be done after the subclasses have been set up. (!cold-init-forms - (dolist (x +!built-in-classes+) + (dolist (x *builtin-classoids*) (destructuring-bind (name &key (state :sealed) &allow-other-keys) x (setf (classoid-state (find-classoid name)) state)))) @@ -1181,28 +1411,29 @@ between the ~A definition and the ~A definition" (warn "making ~(~A~) class ~S writable" it (classoid-name classoid)) (setf (classoid-state classoid) nil))) -;;; Mark LAYOUT as invalid. Setting DEPTHOID -1 helps cause unsafe -;;; structure type tests to fail. Remove class from all superclasses +;;; Mark LAYOUT as invalid. This is called only on CONDITION and STRUCTURE +;;; subtypes when redefining incompatibly. PCL objects use invalidate-wrapper. +;;; Remove class from all superclasses ;;; too (might not be registered, so might not be in subclasses of the ;;; nominal superclasses.) We set the layout-clos-hash slots to 0 to ;;; invalidate the wrappers for specialized dispatch functions, which ;;; use those slots as indexes into tables. -(defun %invalidate-layout (layout) - (declare (type layout layout)) - #+sb-xc-host (warn "Why are we invalidating layout ~S?" layout) - (setf (layout-invalid layout) t) - (assign-layout-slots layout :depthoid -1) - ;; Ensure that the INVALID slot conveying ancillary data describing the - ;; invalidity reason is published before causing the invalid layout trap. - (sb-thread:barrier (:write)) - (setf (layout-clos-hash layout) 0) - (let ((inherits (layout-inherits layout)) - (classoid (layout-classoid layout))) - (%modify-classoid classoid) - (dovector (super inherits) - (let ((subs (classoid-subclasses (layout-classoid super)))) - (when subs - (remhash classoid subs))))) +(defun %invalidate-layout (wrapper) + (declare (type wrapper wrapper)) + #+sb-xc-host (error "Can't invalidate layout ~S" wrapper) + #-sb-xc-host + (progn + (setf (wrapper-invalid wrapper) t) + ;; Ensure that the INVALID slot conveying ancillary data describing the + ;; invalidity reason is published before causing the invalid layout trap. + (sb-thread:barrier (:write)) + #+metaspace (setf (layout-clos-hash (wrapper-friend wrapper)) 0) + (setf (wrapper-clos-hash wrapper) 0) + (let ((inherits (wrapper-inherits wrapper)) + (classoid (wrapper-classoid wrapper))) + (%modify-classoid classoid) + (dovector (super inherits) + (remove-subclassoid classoid (wrapper-classoid super))))) (values)) ;;;; cold loading initializations @@ -1213,14 +1444,14 @@ between the ~A definition and the ~A definition" ;;; late in the build-order.lisp-expr sequence, and be put in ;;; !COLD-INIT-FORMS there? (defun !class-finalize () - (dohash ((name layout) *forward-referenced-layouts*) + (dohash ((name wrapper) *forward-referenced-wrappers*) (let ((class (find-classoid name nil))) (cond ((not class) - (setf (layout-classoid layout) (make-undefined-classoid name))) - ((eq (classoid-layout class) layout) - (remhash name *forward-referenced-layouts*)) + (error "How is there no classoid for ~S ?" name)) + ((eq (classoid-wrapper class) wrapper) + (remhash name *forward-referenced-wrappers*)) (t (error "Something strange with forward layout for ~S:~% ~S" - name layout)))))) + name wrapper)))))) (!defun-from-collected-cold-init-forms !classes-cold-init) diff --git a/src/code/cmacros.lisp b/src/code/cmacros.lisp index 5988797067..64643dd26f 100644 --- a/src/code/cmacros.lisp +++ b/src/code/cmacros.lisp @@ -37,13 +37,6 @@ eof-error-p 'read-from-string) t))) -(eval-when (:compile-toplevel :execute) - (setf (sb-int:info :function :kind 'sb-c:policy) :macro - (sb-int:info :function :macro-function 'sb-c:policy) - (lambda (form env) - (declare (ignore env)) - (values (cl:macroexpand-1 form nil))))) - (define-compiler-macro read-from-string (&whole form string &rest args &environment env) ;; Check this at compile-time, and rewrite it so we're silent at runtime. @@ -76,7 +69,7 @@ (:preserve-whitespace 2) (otherwise (return-from read-from-string form)))) (var (if (logbitp index seen) - (let ((x (sb-xc:gensym "IGNORE"))) + (let ((x (gensym "IGNORE"))) (push x ignore) x) (setf seen (logior (ash 1 index) seen) diff --git a/src/code/coerce.lisp b/src/code/coerce.lisp index 6f1ec74762..380355d22b 100644 --- a/src/code/coerce.lisp +++ b/src/code/coerce.lisp @@ -59,19 +59,6 @@ (declaim (inline coerce-to-list)) (declaim (inline coerce-to-vector)) -(defun coerce-symbol-to-fun (symbol) - ;; FIXME? I would think to use SYMBOL-FUNCTION here which does not strip off - ;; encapsulations. But Stas wrote FDEFINITION so ... - ;; [Also note, we won't encapsulate a macro or special-form, so this - ;; introspective technique to decide what kind something is works either way] - (let ((def (fdefinition symbol))) - (if (macro/special-guard-fun-p def) - (error (ecase (car (%fun-name def)) - (:macro "~S names a macro.") - (:special "~S names a special operator.")) - symbol) - def))) - (defun coerce-to-fun (object) ;; (Unlike the other COERCE-TO-FOOs, this one isn't inline, because ;; it's so big and because optimizing away the outer ETYPECASE diff --git a/src/code/cold-error.lisp b/src/code/cold-error.lisp index 649cebb569..ef4145fdc9 100644 --- a/src/code/cold-error.lisp +++ b/src/code/cold-error.lisp @@ -11,7 +11,7 @@ (in-package "SB-KERNEL") -(defparameter *break-on-signals* nil ; initialized by genesis +(defvar *break-on-signals* nil "When (TYPEP condition *BREAK-ON-SIGNALS*) is true, then calls to SIGNAL will enter the debugger prior to signalling that condition.") @@ -79,10 +79,10 @@ (declare (explicit-check)) (%signal (apply #'coerce-to-condition datum 'simple-condition 'signal arguments))) (defun %signal (condition) - (let ((handler-clusters *handler-clusters*) - (sb-debug:*stack-top-hint* (or sb-debug:*stack-top-hint* '%signal))) + (let ((handler-clusters *handler-clusters*)) (when *break-on-signals* - (maybe-break-on-signal condition)) + (let ((sb-debug:*stack-top-hint* (or sb-debug:*stack-top-hint* '%signal))) + (maybe-break-on-signal condition))) (do ((cluster (pop handler-clusters) (pop handler-clusters))) ((null cluster) nil) @@ -93,29 +93,17 @@ ;; would lead to infinite recursive SIGNAL calls. (let ((*handler-clusters* handler-clusters)) (dolist (handler cluster) - (macrolet ((cast-to-fun (f possibly-symbolp) - ;; For efficiency the cases are tested in this order: - ;; - FUNCTIONP is just a lowtag test - ;; - FDEFN-P is a lowtag + widetag. - ;; Avoiding a SYMBOLP test is fine because - ;; SYMBOL-FUNCTION rejects bogosity anyway. - `(let ((f ,f)) - (cond ((functionp f) f) - (,(if possibly-symbolp `(fdefn-p f) 't) - (sb-c:safe-fdefn-fun f)) - ,@(if possibly-symbolp - `((t (symbol-function f)))))))) - (let ((test (car (truly-the cons handler)))) - (when (if (%instancep test) ; a condition classoid cell - (classoid-cell-typep test condition) - (funcall (cast-to-fun test nil) condition)) - (funcall (cast-to-fun (cdr handler) t) condition))))))))) + (let ((test (car (truly-the cons handler)))) + (when (if (%instancep test) ; a condition classoid cell + (classoid-cell-typep test condition) + (funcall test condition)) + (funcall (cdr handler) condition)))))))) ;;;; working with *CURRENT-ERROR-DEPTH* and *MAXIMUM-ERROR-DEPTH* ;;; counts of nested errors (with internal errors double-counted) (defvar *maximum-error-depth*) ; this gets set to 10 in !COLD-INIT -(defparameter *current-error-depth* 0) ; initialized by genesis +(defvar *current-error-depth* 0) ;;; INFINITE-ERROR-PROTECT is used by ERROR and friends to keep us out ;;; of hyperspace. @@ -209,9 +197,10 @@ of condition handling occurring." (apply #'%break 'break datum arguments))) ;;; These functions definitions are for cold-init. -;;; The real definitions are found in 'condition.lisp' -(defvar *!cold-warn-action* nil) +;;; The real definitions are found in 'warm-error.lisp' +(defvar *!cold-warn-action* #+sb-devel 'print #-sb-devel nil) (defun warn (datum &rest arguments) + (declare (explicit-check datum)) ;; CONDITION-CLASS not yet defined (when (and (stringp datum) (plusp (mismatch "defining setf macro" datum))) (return-from warn nil)) (let ((action (cond ((boundp '*!cold-warn-action*) *!cold-warn-action*) @@ -221,14 +210,30 @@ of condition handling occurring." 'print)))) (when (member action '(lose print)) (let ((*package* *cl-package*)) - (write-string "cold WARN: datum=") ; WRITE could be too broken as yet + (write-string "cold WARN: datum=") (write (get-lisp-obj-address datum) :radix t :base 16) (write-string " = ") (write datum) (write-char #\space) (write (get-lisp-obj-address arguments) :radix t :base 16) - (terpri))) - (when (eq action 'lose) (sb-sys:%primitive sb-c:halt)))) + (terpri) + (cond ((typep datum 'instance) + (dotimes (i (%instance-length datum)) + (write-string " Slot ") + (write i) + (write-string " = ") + (write (%instance-ref datum i)) + (terpri))) + (arguments + (write-string "Args:") + (terpri) + (do-rest-arg ((arg) arguments) + (write-string " | ") + (write arg) + (terpri)))))) + (when (eq action 'lose) + (sb-sys:%primitive sb-c:halt) + (sb-impl::critically-unreachable "losing-warn")))) (defun style-warn (datum &rest arguments) (declare (notinline warn)) (apply 'warn datum arguments)) diff --git a/src/code/cold-init-helper-macros.lisp b/src/code/cold-init-helper-macros.lisp index 0dfb60c7a6..73a465e540 100644 --- a/src/code/cold-init-helper-macros.lisp +++ b/src/code/cold-init-helper-macros.lisp @@ -52,17 +52,6 @@ (makunbound '*!cold-init-forms*))) #-sb-xc (declare (ignore name))) -;;; !DEFINE-LOAD-TIME-GLOBAL avoids this anti-pattern: -;;; (!begin-collecting-cold-init-forms) -;;; (define-load-time-global *foo* nil) -;;; (!cold-init-forms (setq *foo* nil)) -;;; (!defun-from-cold-init-forms !some-cold-init-fun) -(defmacro !define-load-time-global (sym value &optional (doc nil doc-p)) - `(progn (define-load-time-global ,sym ,value ,@(if doc-p (list doc))) - ;; The expansion of the DEFINE-L-T-G is too hairy to fopcompile, - ;; but SETQ is ok provided that the value form is ok. - #-sb-xc-host (setq ,sym ,value))) - (defmacro !set-load-form-method (class-name usable-by &optional method) ;; If USABLE-BY is: ;; :host - the host compiler can execute this M-L-F method @@ -75,17 +64,19 @@ (case method ((nil) ; default (values '(cl:make-load-form-saving-slots obj :environment env) - '(sb-xc:make-load-form-saving-slots obj :environment env))) + '(make-load-form-saving-slots obj :environment env))) + ((:ignore-it) + (values '(values nil nil) '(values nil nil))) (t (assert (not (member :host usable-by))) (values nil `(funcall ,method obj env)))) `(progn ,@(when (or #+sb-xc-host (member :host usable-by)) - `((defmethod make-load-form ((obj ,class-name) &optional env) + `((defmethod cl:make-load-form ((obj ,class-name) &optional env) ,host-expr))) ,@(when (or #+sb-xc-host (member :xc usable-by)) ;; Use the host's CLOS implementation to select the target's method. - `((defmethod sb-xc:make-load-form ((obj ,class-name) &optional env) + `((defmethod make-load-form ((obj ,class-name) &optional env) (declare (ignorable obj env)) ,target-expr))) ,@(when (or #-sb-xc-host (member :target usable-by)) diff --git a/src/code/cold-init.lisp b/src/code/cold-init.lisp index 2fdd0eacf5..b1ebef38dc 100644 --- a/src/code/cold-init.lisp +++ b/src/code/cold-init.lisp @@ -20,14 +20,6 @@ (%primitive print "too early in cold init to recover from errors") (%halt)) -(defun !cold-failed-aver (expr) - ;; output the message and invoke ldb monitor - (terpri) - (write-line "failed AVER:") - (write expr) - (terpri) - (%halt)) - ;;; last-ditch error reporting for things which should never happen ;;; and which, if they do happen, are sufficiently likely to torpedo ;;; the normal error-handling system that we want to bypass it @@ -40,65 +32,166 @@ ;;;; !COLD-INIT ;;; a list of toplevel things set by GENESIS -(defvar *!cold-toplevels*) ; except for DEFUNs and SETF macros -(defvar *!cold-setf-macros*) ; just SETF macros -(defvar *!cold-defuns*) ; just DEFUNs -(defvar *!cold-defsymbols*) ; "easy" DEFCONSTANTs and DEFPARAMETERs +(defvar *!cold-toplevels*) ;;; a SIMPLE-VECTOR set by GENESIS (defvar *!load-time-values*) - ;; FIXME: Perhaps we should make SHOW-AND-CALL-AND-FMAKUNBOUND, too, - ;; and use it for most of the cold-init functions. (Just be careful - ;; not to use it for the COLD-INIT-OR-REINIT functions.) +;; FIXME: Perhaps we should make SHOW-AND-CALL-AND-FMAKUNBOUND, too, +;; and use it for most of the cold-init functions. (Just be careful +;; not to use it for the COLD-INIT-OR-REINIT functions.) (defmacro show-and-call (name) - `(progn - (/show "Calling" ,(symbol-name name)) - (,name))) + `(progn + (/show "Calling" ,(symbol-name name)) + (,name))) (defun !c-runtime-noinform-p () (/= (extern-alien "lisp_startup_options" char) 0)) +(defun !format-cold-init () + (sb-format::!late-format-init) + (sb-format::!format-directives-init)) + +;;; Allows the SIGNAL function to be called early. +(defun !signal-function-cold-init () + #+sb-devel + (progn + (setq *break-on-signals* nil) + (setq sb-kernel::*current-error-depth* 0)) + (setq *stack-top-hint* nil)) + +(defun !printer-control-init () + (setq *print-readably* nil + *print-escape* t + *print-pretty* nil + *print-base* 10 + *print-radix* nil + *print-vector-length* nil + *print-circle* nil + *print-case* :upcase + *print-array* t + *print-gensym* t + *print-lines* nil + *print-right-margin* nil + *print-miser-width* nil + *print-pprint-dispatch* (sb-pretty::make-pprint-dispatch-table #() nil nil) + *suppress-print-errors* nil + *current-level-in-print* 0)) + +;;; Create a stream that works early. +(defun !make-cold-stderr-stream () + (let ((stderr + #-win32 2 + #+win32 (sb-win32::get-std-handle-or-null sb-win32::+std-error-handle+)) + (buf (make-string 1 :element-type 'base-char :initial-element #\Space))) + (%make-fd-stream + :out (lambda (stream ch) + (declare (ignore stream)) + (setf (char buf 0) ch) + (sb-unix:unix-write stderr buf 0 1)) + :sout (lambda (stream string start end) + (declare (ignore stream)) + (flet ((out (s start len) + (when (plusp len) + (setf (char buf 0) (char s (+ start len -1)))) + (sb-unix:unix-write stderr s start len))) + (if (typep string 'simple-base-string) + (out string start (- end start)) + (let ((n (- end start))) + ;; will croak if there is any non-BASE-CHAR in the string + (out (replace (make-array n :element-type 'base-char) + string :start2 start) 0 n))))) + :misc (lambda (stream operation arg1) + (declare (ignore stream arg1)) + (stream-misc-case (operation :default nil) + (:charpos ; impart just enough smarts to make FRESH-LINE dtrt + (if (eql (char buf 0) #\newline) 0 1))))))) + +(defun xc-sanity-checks () + ;; Verify on startup that some constants were dumped reflecting the + ;; correct action of our vanilla-host-compatible functions. For + ;; now, just SXHASH is checked. + + ;; Parallelized build doesn't get the full set of data because the + ;; side effect of data recording when invoking compile-time + ;; functions aren't propagated back to process that forked the + ;; children doing the grunt work. + (let ((sxhash-crosscheck + '#.(let (pairs) + ;; De-duplicate, which reduces the list from ~8000 entries to ~1000 entries. + ;; But make sure that any key which isolated repeated has the same value + ;; at each repetition. + (dolist (pair sb-c::*sxhash-crosscheck* (coerce pairs 'simple-vector)) + (let ((found (assoc (car pair) pairs))) + (if found + (aver (= (cdr found) (cdr pair))) + (push pair pairs))))))) + (loop for (object . hash) across sxhash-crosscheck + unless (= (sxhash object) hash) + do (error "SXHASH computed wrong answer for ~S. Got ~x should be ~x" + object hash (sxhash object))))) + ;;; called when a cold system starts up -(defun !cold-init (&aux (real-choose-symbol-out-fun #'choose-symbol-out-fun) - (real-failed-aver-fun #'%failed-aver)) +(defun !cold-init () "Give the world a shove and hope it spins." (/show0 "entering !COLD-INIT") - (setf (symbol-function '%failed-aver) #'!cold-failed-aver) - (!cold-init-hash-table-methods) ; needed by MAKE-READTABLE - (setq *readtable* (make-readtable) - *print-length* 6 *print-level* 3) - (setq *error-output* (!make-cold-stderr-stream) - *standard-output* *error-output* - *trace-output* *error-output*) + #+sb-show (setq */show* t) + (setq sb-vm::*immobile-codeblob-tree* nil + sb-vm::*dynspace-codeblob-tree* nil) + (setq sb-kernel::*defstruct-hooks* '(sb-kernel::!bootstrap-defstruct-hook) + sb-kernel::*struct-accesss-fragments-delayed* nil) + (let ((stream (!make-cold-stderr-stream))) + (setq *error-output* stream + *standard-output* stream + *trace-output* stream)) + (show-and-call !signal-function-cold-init) + (show-and-call !printer-control-init) ; needed before first instance of FORMAT or WRITE-STRING + (setq *unparse-fun-type-simplify* nil) ; needed by TLFs in target-error.lisp + (setq sb-unix::*unblock-deferrables-on-enabling-interrupts-p* nil) ; needed by LOAD-LAYOUT called by CLASSES-INIT + (setq *print-length* 6 + *print-level* 3) (/show "testing '/SHOW" *print-length* *print-level*) ; show anything + ;; This allows FORMAT to work, and can go as early needed for + ;; debugging. + (show-and-call !format-cold-init) (unless (!c-runtime-noinform-p) - (write-string "COLD-INIT... ")) - ;; Establish **initial-handler-clusters** - (show-and-call sb-kernel::!target-error-cold-init) - ;; And now *CURRENT-THREAD* and *HANDLER-CLUSTERS* - (sb-thread::init-initial-thread) - - ;; Assert that FBOUNDP doesn't choke when its answer is NIL. - ;; It was fine if T because in that case the legality of the arg is certain. - ;; And be extra paranoid - ensure that it really gets called. - (locally (declare (notinline fboundp)) (fboundp '(setf !zzzzzz))) + ;; I'd like FORMAT to remain working in cold-init, where it does work, + ;; hence the conditional. + #+(or x86 x86-64) (format t "COLD-INIT... ") + #-(or x86 x86-64) (write-string "COLD-INIT... ")) ;; Anyone might call RANDOM to initialize a hash value or something; ;; and there's nothing which needs to be initialized in order for ;; this to be initialized, so we initialize it right away. (show-and-call !random-cold-init) - ;; Putting data in a synchronized hashtable (*PACKAGE-NAMES*) - ;; requires that the main thread be properly initialized. - (show-and-call thread-init-or-reinit) + ;; All sorts of things need INFO and/or (SETF INFO). + (/show0 "about to SHOW-AND-CALL !GLOBALDB-COLD-INIT") + (show-and-call !globaldb-cold-init) + (show-and-call !function-names-init) + + ;; And now *CURRENT-THREAD* + (sb-thread::init-main-thread) + + ;; not sure why this is needed on some architectures. Dark magic. + (setf (fdefn-fun (find-or-create-fdefn '%coerce-callable-for-call)) + #'%coerce-callable-to-fun) + ;; Assert that FBOUNDP doesn't choke when its answer is NIL. + ;; It was fine if T because in that case the legality of the arg is certain. + ;; And be extra paranoid - ensure that it really gets called. + (locally (declare (notinline fboundp)) (fboundp '(setf !zzzzzz))) + ;; Printing of symbols requires that packages be filled in, because - ;; OUTPUT-SYMBOL calls FIND-SYMBOL to determine accessibility. + ;; OUTPUT-SYMBOL calls FIND-SYMBOL to determine accessibility. Also + ;; allows IN-PACKAGE to work. (show-and-call !package-cold-init) - (setq *print-pprint-dispatch* (sb-pretty::make-pprint-dispatch-table nil nil nil)) - ;; Because L-T-V forms have not executed, CHOOSE-SYMBOL-OUT-FUN doesn't work. - (setf (symbol-function 'choose-symbol-out-fun) - (lambda (&rest args) (declare (ignore args)) #'output-preserve-symbol)) + + ;; The readtable needs to be initialized for printing symbols early, + ;; which is useful for debugging. + (!readtable-cold-init) + (write-string "Checking symbol printer: ") + (write 't) + (terpri) ;; *RAW-SLOT-DATA* is essentially a compile-time constant ;; but isn't dumpable as such because it has functions in it. @@ -107,94 +200,60 @@ ;; Must be done before any non-opencoded array references are made. (show-and-call sb-vm::!hairy-data-vector-reffer-init) - (show-and-call !character-database-cold-init) - (show-and-call !character-name-database-cold-init) - (show-and-call sb-unicode::!unicode-properties-cold-init) - - ;; All sorts of things need INFO and/or (SETF INFO). - (/show0 "about to SHOW-AND-CALL !GLOBALDB-COLD-INIT") - (show-and-call !globaldb-cold-init) - ;; Various toplevel forms call MAKE-ARRAY, which calls SUBTYPEP, so ;; the basic type machinery needs to be initialized before toplevel ;; forms run. (show-and-call !type-class-cold-init) - (show-and-call sb-kernel::!primordial-type-cold-init) (show-and-call !classes-cold-init) - (show-and-call !pred-cold-init) - (show-and-call !early-type-cold-init) - (show-and-call !late-type-cold-init) - (show-and-call !alien-type-cold-init) - ;; FIXME: It would be tidy to make sure that that these cold init - ;; functions are called in the same relative order as the toplevel - ;; forms of the corresponding source files. + (show-and-call sb-kernel::!primordial-type-cold-init) + (show-and-call !type-cold-init) (show-and-call !policy-cold-init-or-resanify) (/show0 "back from !POLICY-COLD-INIT-OR-RESANIFY") + (show-and-call !loader-cold-init) + #+x86-64 (sb-fasl::validate-asm-routine-vector) ;; Must be done before toplevel forms are invoked ;; because a toplevel defstruct will need to add itself ;; to the subclasses of STRUCTURE-OBJECT. (show-and-call sb-kernel::!set-up-structure-object-class) - ;; Genesis is able to perform some of the work of DEFCONSTANT and - ;; DEFPARAMETER, but not all of it. It assigns symbol values, but can not - ;; manipulate globaldb. Therefore, a subtlety of these macros for bootstrap - ;; is that we see each DEFthing twice: once during cold-load and again here. - ;; Now it being the case that DEFPARAMETER implies variable assignment - ;; unconditionally, you may think it should assign. No! This was logically - ;; ONE use of the defining macro, but split into pieces as a consequence - ;; of the implementation. - (dolist (x *!cold-defsymbols*) - (destructuring-bind (fun name source-loc . docstring) x - (aver (boundp name)) ; it's a bug if genesis didn't initialize - (ecase fun - (sb-c::%defconstant - (apply #'sb-c::%defconstant name (symbol-value name) source-loc docstring)) - (sb-impl::%defparameter ; use %DEFVAR which will not clobber - (apply #'%defvar name source-loc nil docstring))))) - (dolist (x *!cold-defuns*) - (destructuring-bind (name inline-expansion dxable-args) x - (%defun name (fdefinition name) inline-expansion dxable-args))) - (unless (!c-runtime-noinform-p) - (write `("Length(TLFs)=" ,(length *!cold-toplevels*)) :escape nil) - (terpri)) - - (loop with *package* = *package* ; rebind to self, as if by LOAD - for index-in-cold-toplevels from 0 - for toplevel-thing in (prog1 *!cold-toplevels* - (makunbound '*!cold-toplevels*)) - do - #+sb-show - (when (zerop (mod index-in-cold-toplevels 1000)) - (/show index-in-cold-toplevels)) + #+(or x86 x86-64) (format t "[Length(TLFs)=~D]" (length *!cold-toplevels*)) + #-(or x86 x86-64) (write `("Length(TLFs)=" ,(length *!cold-toplevels*)) :escape nil)) + + (setq sb-pcl::*!docstrings* nil) ; needed before any documentation is set + (setq sb-c::*queued-proclaims* nil) ; needed before any proclaims are run + + (/show0 "calling cold toplevel forms and fixups") + (let ((*package* *package*)) ; rebind to self, as if by LOAD + (dolist (toplevel-thing *!cold-toplevels*) (typecase toplevel-thing (function (funcall toplevel-thing)) ((cons (eql :load-time-value)) - (setf (svref *!load-time-values* (third toplevel-thing)) - (funcall (second toplevel-thing)))) + (setf (svref *!load-time-values* (third toplevel-thing)) + (funcall (second toplevel-thing)))) ((cons (eql :load-time-value-fixup)) (destructuring-bind (object index value) (cdr toplevel-thing) (aver (typep object 'code-component)) - (aver (eq (code-header-ref object index) (make-unbound-marker))) + (aver (unbound-marker-p (code-header-ref object index))) (setf (code-header-ref object index) (svref *!load-time-values* value)))) - ((cons (eql defstruct)) - (apply 'sb-kernel::%defstruct (cdr toplevel-thing))) + ((cons (eql :named-constant)) + (destructuring-bind (object index name) (cdr toplevel-thing) + (aver (typep object 'code-component)) + (aver (unbound-marker-p (code-header-ref object index))) + (sb-fasl::named-constant-set object index name))) + ((cons (eql :begin-file)) + (unless (!c-runtime-noinform-p) (print (cdr toplevel-thing)))) (t - (!cold-lose "bogus operation in *!COLD-TOPLEVELS*")))) + (!cold-lose "bogus operation in *!COLD-TOPLEVELS*"))))) (/show0 "done with loop over cold toplevel forms and fixups") + (unless (!c-runtime-noinform-p) (terpri)) - ;; Precise GC seems to think these symbols are live during the final GC - ;; which in turn enlivens a bunch of other "*!foo*" symbols. - ;; Setting them to NIL helps a little bit. - (setq *!cold-defuns* nil *!cold-defsymbols* nil *!cold-toplevels* nil) - - ;; Now that L-T-V forms have executed, the symbol output chooser works. - (setf (symbol-function 'choose-symbol-out-fun) real-choose-symbol-out-fun) + (makunbound '*!cold-toplevels*) ; so it gets GC'd - (show-and-call time-reinit) + #+win32 (show-and-call reinit-internal-real-time) ;; Set sane values again, so that the user sees sane values instead ;; of whatever is left over from the last DECLAIM/PROCLAIM. @@ -207,10 +266,13 @@ ;; now that the type system is definitely initialized, fixup UNKNOWN ;; types that have crept in. (show-and-call !fixup-type-cold-init) - ;; run the PROCLAIMs. - (show-and-call !late-proclaim-cold-init) - (show-and-call !loader-cold-init) + ;; We run through queued-up type and ftype proclaims that were made + ;; before the type system was initialized, and (since it is now + ;; initalized) reproclaim them.. + (mapcar #'proclaim sb-c::*queued-proclaims*) + (makunbound 'sb-c::*queued-proclaims*) + (show-and-call os-cold-init-or-reinit) (show-and-call !pathname-cold-init) @@ -223,7 +285,6 @@ (show-and-call float-cold-init-or-reinit) (show-and-call !class-finalize) - (show-and-call sb-pcl::!fixup-print-object-method-guards) ;; The reader and printer are initialized very late, so that they ;; can do hairy things like invoking the compiler as part of their @@ -245,7 +306,6 @@ (setf sb-kernel:*maximum-error-depth* 10) (/show0 "enabling internal errors") (setf (extern-alien "internal_errors_enabled" int) 1) - (setf (symbol-function '%failed-aver) real-failed-aver-fun) (show-and-call sb-disassem::!compile-inst-printers) @@ -257,11 +317,12 @@ (logically-readonlyize (sb-c::sc-move-vops sc)) (logically-readonlyize (sb-c::sc-move-costs sc)))) - ; hppa heap is segmented, lisp and c uses a stub to call eachother - #+hpux (%primitive sb-vm::setup-return-from-lisp-stub) + (show-and-call xc-sanity-checks) + ;; The system is finally ready for GC. (/show0 "enabling GC") (setq *gc-inhibit* nil) + #+sb-thread (finalizer-thread-start) ;; The show is on. (/show0 "going into toplevel loop") @@ -315,46 +376,46 @@ Consequences are unspecified if serious conditions occur during EXIT excepting errors from *EXIT-HOOKS*, which cause warnings and stop execution of the hook that signaled, but otherwise allow the exit process to continue normally." - (if (or abort *exit-in-process*) + (if (or abort *exit-in-progress*) (os-exit (or code 1) :abort t) (let ((code (or code 0))) (with-deadline (:seconds nil :override t) (sb-thread:grab-mutex *exit-lock*)) - (setf *exit-in-process* code + (setf *exit-in-progress* code *exit-timeout* timeout) (throw '%end-of-the-world t))) (critically-unreachable "After trying to die in EXIT.")) ;;;; initialization functions -(defun thread-init-or-reinit () - (sb-thread::init-job-control) - (sb-thread::get-foreground)) - -(defun reinit () +(defun reinit (total) ;; WITHOUT-GCING implies WITHOUT-INTERRUPTS. (without-gcing ;; Until *CURRENT-THREAD* has been set, nothing the slightest bit complicated ;; can be called, as pretty much anything can assume that it is set. - (sb-thread::init-initial-thread) + (when total ; newly started process, and not a failed save attempt + (sb-thread::init-main-thread) + #+x86-64 (sb-fasl::validate-asm-routine-vector) + (rebuild-package-vector)) ;; Initializing the standard streams calls ALLOC-BUFFER which calls FINALIZE (finalizers-reinit) ;; Initialize streams next, so that any errors can be printed (stream-reinit t) (os-cold-init-or-reinit) - (thread-init-or-reinit) #-(and win32 (not sb-thread)) (signal-cold-init-or-reinit) (setf (extern-alien "internal_errors_enabled" int) 1) (float-cold-init-or-reinit)) (gc-reinit) (foreign-reinit) - (time-reinit) + #+win32 (reinit-internal-real-time) ;; If the debugger was disabled in the saved core, we need to ;; re-disable ldb again. (when (eq *invoke-debugger-hook* 'sb-debug::debugger-disabled-hook) (sb-debug::disable-debugger)) - (call-hooks "initialization" *init-hooks*)) + (call-hooks "initialization" *init-hooks*) + #+sb-thread (finalizer-thread-start) + (sb-vm::!setup-cpu-specific-routines)) ;;;; some support for any hapless wretches who end up debugging cold ;;;; init code diff --git a/src/code/common-os.lisp b/src/code/common-os.lisp index abddb6f701..e922a5fa1b 100644 --- a/src/code/common-os.lisp +++ b/src/code/common-os.lisp @@ -35,7 +35,7 @@ (define-load-time-global *core-string* "") (define-load-time-global *core-pathname* nil "The absolute pathname of the running SBCL core.") - +(define-load-time-global *software-version* nil) (define-load-time-global *runtime-pathname* nil "The absolute pathname of the running SBCL runtime.") (define-load-time-global *sbcl-homedir-pathname* nil) @@ -61,7 +61,10 @@ (init-var-ignoring-errors *posix-argv* (loop for i from 0 - for arg = (sb-alien:deref (sb-alien:extern-alien posix_argv (* sb-alien:c-string)) i) + for arg = (sb-alien:deref (sb-alien:extern-alien posix_argv + (* (sb-alien:c-string + #+win32 :external-format #+win32 :ucs-2))) + i) while arg collect arg)) (/show0 "setting *DEFAULT-PATHNAME-DEFAULTS*") diff --git a/src/code/condition-boot.lisp b/src/code/condition-boot.lisp deleted file mode 100644 index f68e5b6333..0000000000 --- a/src/code/condition-boot.lisp +++ /dev/null @@ -1,57 +0,0 @@ -;;;; This software is part of the SBCL system. See the README file for -;;;; more information. -;;;; -;;;; This software is derived from the CMU CL system, which was -;;;; written at Carnegie Mellon University and released into the -;;;; public domain. The software is in the public domain and is -;;;; provided with absolutely no warranty. See the COPYING and CREDITS -;;;; files for more information. - -(in-package "SB-KERNEL") - -(!defstruct-with-alternate-metaclass condition - :slot-names (assigned-slots) - :constructor nil - :superclass-name t - :metaclass-name condition-classoid - :metaclass-constructor make-condition-classoid - :dd-type structure) - -;;; Define just enough condition-classoids to get TYPEP -;;; to optimize into classoid-typep. -(macrolet ((def (name direct-supers &rest inherits) - `(eval-when (:compile-toplevel :execute) - ;; INHERITS is a list of symbols, unevaluated, - ;; excluding T which is assumed. - (%compiler-define-condition - ',name ',direct-supers - ,(make-layout - (hash-layout-name name) - (make-undefined-classoid name) - :flags +condition-layout-flag+ - :inherits (map 'vector #'find-layout (cons t inherits)) - :depthoid -1 - ;; 1 declared slot, plus the layout if it takes a slot - :length (+ sb-vm:instance-data-start 1)) - nil nil)))) - ;; These are grotesquely OAOO-violating, but on the bright side, - ;; compilation will fail if the subsequent real definition differs, - ;; so there's a built-in safety net. - ;; As has been suggested in 'cross-condition', a DEF!CONDITION macro - ;; might help, but still that's possibly not a complete solution, - ;; because DEBUG-CONDITION is defined in a file with the :NOT-HOST flag. - (def simple-condition (condition) condition) - (def warning (condition) condition) - (def style-warning (warning) condition warning) - (def compiler-note (condition) condition) - (def parse-unknown-type (condition) condition) - (def parse-deprecated-type (condition) condition) - (def serious-condition (condition) condition) - (def error (serious-condition) condition serious-condition) - (def sb-di:debug-condition (serious-condition) condition serious-condition) - (def stream-error (error) condition serious-condition error) - (def reference-condition (condition) condition) - ) - -;;; Needed for !CALL-A-METHOD to pick out CONDITIONs -(defun !condition-p (x) (typep x 'condition)) diff --git a/src/code/condition.lisp b/src/code/condition.lisp deleted file mode 100644 index 1ca2b719ae..0000000000 --- a/src/code/condition.lisp +++ /dev/null @@ -1,2003 +0,0 @@ -;;;; stuff originally from CMU CL's error.lisp which can or should -;;;; come late (mostly related to the CONDITION class itself) -;;;; - -;;;; This software is part of the SBCL system. See the README file for -;;;; more information. -;;;; -;;;; This software is derived from the CMU CL system, which was -;;;; written at Carnegie Mellon University and released into the -;;;; public domain. The software is in the public domain and is -;;;; provided with absolutely no warranty. See the COPYING and CREDITS -;;;; files for more information. - -(in-package "SB-KERNEL") - -;;;; the CONDITION class - -(/show0 "condition.lisp 20") - -(defstruct (condition-slot (:copier nil)) - (name (missing-arg) :type symbol) - ;; list of all applicable initargs - (initargs (missing-arg) :type list) - ;; names of reader and writer functions - (readers (missing-arg) :type list) - (writers (missing-arg) :type list) - ;; true if :INITFORM was specified - (initform-p (missing-arg) :type (member t nil)) - ;; the initform if :INITFORM was specified, otherwise NIL - (initform nil :type t) - ;; if this is a function, call it with no args to get the initform value - (initfunction (missing-arg) :type t) - ;; allocation of this slot, or NIL until defaulted - (allocation nil :type (member :instance :class nil)) - ;; If ALLOCATION is :CLASS, this is a cons whose car holds the value - (cell nil :type (or cons null)) - ;; slot documentation - (documentation nil :type (or string null))) - -(eval-when (:compile-toplevel :load-toplevel :execute) - (/show0 "condition.lisp 103") - (let ((condition-class (find-classoid 'condition))) - (setf (condition-classoid-cpl condition-class) - (list condition-class))) - (/show0 "condition.lisp 103")) - -(setf (condition-classoid-report (find-classoid 'condition)) - (lambda (cond stream) - (format stream "Condition ~/sb-impl:print-type-specifier/ was signalled." - (type-of cond)))) - -(eval-when (:compile-toplevel :load-toplevel :execute) - -(defun find-condition-layout (name parent-types) - (let* ((cpl (remove-duplicates - (reverse - (reduce #'append - (mapcar (lambda (x) - (condition-classoid-cpl - (find-classoid x))) - parent-types))))) - (cond-layout (info :type :compiler-layout 'condition)) - (olayout (info :type :compiler-layout name)) - ;; FIXME: Does this do the right thing in case of multiple - ;; inheritance? A quick look at DEFINE-CONDITION didn't make - ;; it obvious what ANSI intends to be done in the case of - ;; multiple inheritance, so it's not actually clear what the - ;; right thing is.. - (new-inherits - (order-layout-inherits (concatenate 'simple-vector - (layout-inherits cond-layout) - (mapcar #'classoid-layout cpl))))) - (if (and olayout - (not (mismatch (layout-inherits olayout) new-inherits))) - olayout - (make-layout (hash-layout-name name) - (make-undefined-classoid name) - :flags +condition-layout-flag+ - :inherits new-inherits - :depthoid -1 - :length (layout-length cond-layout))))) - -) ; EVAL-WHEN - -;;; FIXME: ANSI's definition of DEFINE-CONDITION says -;;; Condition reporting is mediated through the PRINT-OBJECT method -;;; for the condition type in question, with *PRINT-ESCAPE* always -;;; being nil. Specifying (:REPORT REPORT-NAME) in the definition of -;;; a condition type C is equivalent to: -;;; (defmethod print-object ((x c) stream) -;;; (if *print-escape* (call-next-method) (report-name x stream))) -;;; The current code doesn't seem to quite match that. -(defmethod print-object ((object condition) stream) - (cond - ((not *print-escape*) - ;; KLUDGE: A comment from CMU CL here said - ;; 7/13/98 BUG? CPL is not sorted and results here depend on order of - ;; superclasses in define-condition call! - (funcall (or (some #'condition-classoid-report - (condition-classoid-cpl (classoid-of object))) - (error "no REPORT? shouldn't happen!")) - object stream)) - ((and (typep object 'simple-condition) - (condition-slot-value object 'format-control)) - (print-unreadable-object (object stream :type t :identity t) - (write (simple-condition-format-control object) - :stream stream :lines 1))) - (t - (print-unreadable-object (object stream :type t :identity t))))) - -;;;; slots of CONDITION objects - -(defun find-slot-default (class slot) - (multiple-value-bind (value found) (find-slot-default-initarg class slot) - ;; When CLASS or a superclass has a default initarg for SLOT, use - ;; that. - (cond (found - value) - ;; Otherwise use the initform of SLOT, if there is one. - ((condition-slot-initform-p slot) - (let ((initfun (condition-slot-initfunction slot))) - (aver (functionp initfun)) - (funcall initfun))) - (t - (error "Unbound condition slot: ~S" (condition-slot-name slot)))))) - -(defun find-slot-default-initarg (class slot) - (let ((initargs (condition-slot-initargs slot)) - (cpl (condition-classoid-cpl class))) - (dolist (class cpl) - (let ((direct-default-initargs - (condition-classoid-direct-default-initargs class))) - (dolist (initarg initargs) - (let ((initfunction (third (assoc initarg direct-default-initargs)))) - (when initfunction - (return-from find-slot-default-initarg - (values (funcall initfunction) t))))))) - (values nil nil))) - -(defun find-condition-class-slot (condition-class slot-name) - (dolist (sclass - (condition-classoid-cpl condition-class) - (error "There is no slot named ~S in ~S." - slot-name condition-class)) - (dolist (slot (condition-classoid-slots sclass)) - (when (eq (condition-slot-name slot) slot-name) - (return-from find-condition-class-slot slot))))) - -(defun set-condition-slot-value (condition new-value name) - (dolist (cslot (condition-classoid-class-slots - (layout-classoid (%instance-layout condition))) - (setf (getf (condition-assigned-slots condition) name) - new-value)) - (when (eq (condition-slot-name cslot) name) - (return (setf (car (condition-slot-cell cslot)) new-value))))) - -(defun condition-slot-value (condition name) - (let ((val (getf (condition-assigned-slots condition) name sb-pcl:+slot-unbound+))) - (if (unbound-marker-p val) - (let ((class (layout-classoid (%instance-layout condition)))) - (dolist (cslot - (condition-classoid-class-slots class) - (let ((instance-length (%instance-length condition)) - (slot (or (find-condition-class-slot class name) - (error "missing slot ~S of ~S" name condition)))) - (setf (getf (condition-assigned-slots condition) name) - (do ((i (+ sb-vm:instance-data-start 1) (+ i 2))) - ((>= i instance-length) (find-slot-default class slot)) - (when (member (%instance-ref condition i) - (condition-slot-initargs slot)) - (return (%instance-ref condition (1+ i)))))))) - (when (eq (condition-slot-name cslot) name) - (let ((value (car (condition-slot-cell cslot)))) - (if (unbound-marker-p value) - (error "Unbound condition slot: ~S" (condition-slot-name cslot)) - (return value)))))) - val))) - -;;;; MAKE-CONDITION - -(defun allocate-condition (designator &rest initargs) - (when (oddp (length initargs)) - (error 'simple-error - :format-control "odd-length initializer list: ~S." - :format-arguments - (let (list) - ;; avoid direct reference to INITARGS as a list - ;; so that it is not reified unless we reach here. - (do-rest-arg ((arg) initargs) (push arg list)) - (list (nreverse list))))) - ;; I am going to assume that people are not somehow getting to here - ;; with a CLASSOID, which is not strictly legal as a designator, - ;; but which is accepted because it is actually the desired thing. - ;; It doesn't seem worth sweating over that detail, and in any event - ;; we could say that it's a supported extension. - (let ((classoid (named-let lookup ((designator designator)) - (typecase designator - (symbol (find-classoid designator nil)) - (class (lookup (class-name designator))) - (t designator))))) - (if (condition-classoid-p classoid) - ;; Interestingly we fail to validate the actual-initargs, - ;; allowing any random initarg names. Is this permissible? - ;; And why is lazily filling in ASSIGNED-SLOTS beneficial anyway? - (let ((instance (%make-instance (+ sb-vm:instance-data-start - 1 ; ASSIGNED-SLOTS - (length initargs))))) ; rest - (setf (%instance-layout instance) (classoid-layout classoid) - (condition-assigned-slots instance) nil) - (do-rest-arg ((val index) initargs) - (setf (%instance-ref instance (+ sb-vm:instance-data-start index 1)) val)) - (values instance classoid)) - (error 'simple-type-error - :datum designator - ;; CONDITION-CLASS isn't a type-specifier. Is this legal? - :expected-type 'condition-class - :format-control "~S does not designate a condition class." - :format-arguments (list designator))))) - -(defun make-condition (type &rest initargs) - "Make an instance of a condition object using the specified initargs." - ;; Note: While ANSI specifies no exceptional situations in this function, - ;; ALLOCATE-CONDITION will signal a type error if TYPE does not designate - ;; a condition class. This seems fair enough. - (declare (explicit-check)) - ;; FIXME: the compiler should have a way to make GETF operate on a &MORE arg - ;; so that the initargs are never listified. - (declare (dynamic-extent initargs)) - (multiple-value-bind (condition classoid) - (apply #'allocate-condition type initargs) - - ;; Set any class slots with initargs present in this call. - (dolist (cslot (condition-classoid-class-slots classoid)) - (loop for (key value) on initargs by #'cddr - when (memq key (condition-slot-initargs cslot)) - do (setf (car (condition-slot-cell cslot)) value) - (return) - finally - (multiple-value-bind (value found) - (find-slot-default-initarg classoid cslot) - (when found - (setf (car (condition-slot-cell cslot)) value))))) - - ;; Default any slots with non-constant defaults now. - (dolist (hslot (condition-classoid-hairy-slots classoid)) - (when (dolist (initarg (condition-slot-initargs hslot) t) - (unless (unbound-marker-p (getf initargs initarg sb-pcl:+slot-unbound+)) - (return nil))) - (setf (getf (condition-assigned-slots condition) - (condition-slot-name hslot)) - (find-slot-default classoid hslot)))) - - condition)) - - -;;;; DEFINE-CONDITION - -;;; Compute the effective slots of CLASS, copying inherited slots and -;;; destructively modifying direct slots. -;;; -;;; FIXME: It'd be nice to explain why it's OK to destructively modify -;;; direct slots. Presumably it follows from the semantics of -;;; inheritance and redefinition of conditions, but finding the cite -;;; and documenting it here would be good. (Or, if this is not in fact -;;; ANSI-compliant, fixing it would also be good.:-) -(defun compute-effective-slots (class) - (collect ((res (copy-list (condition-classoid-slots class)))) - (dolist (sclass (cdr (condition-classoid-cpl class))) - (dolist (sslot (condition-classoid-slots sclass)) - (let ((found (find (condition-slot-name sslot) (res) - :key #'condition-slot-name))) - (cond (found - (setf (condition-slot-initargs found) - (union (condition-slot-initargs found) - (condition-slot-initargs sslot))) - (unless (condition-slot-initform-p found) - (setf (condition-slot-initform-p found) - (condition-slot-initform-p sslot)) - (setf (condition-slot-initform found) - (condition-slot-initform sslot)) - (setf (condition-slot-initfunction found) - (condition-slot-initfunction sslot))) - (unless (condition-slot-allocation found) - (setf (condition-slot-allocation found) - (condition-slot-allocation sslot)))) - (t - (res (copy-structure sslot))))))) - (res))) - -;;; Early definitions of slot accessor creators. -;;; -;;; Slot accessors must be generic functions, but ANSI does not seem -;;; to specify any of them, and we cannot support it before end of -;;; warm init. So we use ordinary functions inside SBCL, and switch to -;;; GFs only at the end of building. -(declaim (notinline install-condition-slot-reader - install-condition-slot-writer)) -(defun install-condition-slot-reader (name condition slot-name) - (declare (ignore condition)) - (setf (fdefinition name) - (set-closure-name - (lambda (condition) (condition-slot-value condition slot-name)) - t - `(condition-slot-reader ,name)))) -(defun install-condition-slot-writer (name condition slot-name) - (declare (ignore condition)) - (setf (fdefinition name) - (set-closure-name - (lambda (new-value condition) - (set-condition-slot-value condition new-value slot-name)) - t - `(condition-slot-writer ,name)))) - -(!define-load-time-global *define-condition-hooks* nil) - -(defun %set-condition-report (name report) - (setf (condition-classoid-report (find-classoid name)) - report)) - -(defun %define-condition (name parent-types layout slots - direct-default-initargs all-readers all-writers - source-location &optional documentation) - (call-with-defining-class - 'condition name - (lambda () - (%%compiler-define-condition name parent-types layout all-readers all-writers) - (let ((classoid (find-classoid name))) - (when source-location - (setf (classoid-source-location classoid) source-location)) - (setf (condition-classoid-slots classoid) slots - (condition-classoid-direct-default-initargs classoid) direct-default-initargs - (documentation name 'type) documentation) - - (dolist (slot slots) - ;; Set up reader and writer functions. - (let ((slot-name (condition-slot-name slot))) - (dolist (reader (condition-slot-readers slot)) - (install-condition-slot-reader reader name slot-name)) - (dolist (writer (condition-slot-writers slot)) - (install-condition-slot-writer writer name slot-name)))) - - ;; Compute effective slots and set up the class and hairy slots - ;; (subsets of the effective slots.) - (setf (condition-classoid-class-slots classoid) '() - (condition-classoid-hairy-slots classoid) '()) - (let ((eslots (compute-effective-slots classoid)) - (e-def-initargs - (reduce #'append - (mapcar #'condition-classoid-direct-default-initargs - (condition-classoid-cpl classoid))))) - (dolist (slot eslots) - (ecase (condition-slot-allocation slot) - (:class - (unless (condition-slot-cell slot) - (setf (condition-slot-cell slot) - (list (if (condition-slot-initform-p slot) - (let ((initfun (condition-slot-initfunction slot))) - (aver (functionp initfun)) - (funcall initfun)) - sb-pcl:+slot-unbound+)))) - (push slot (condition-classoid-class-slots classoid))) - ((:instance nil) - (setf (condition-slot-allocation slot) :instance) - ;; FIXME: isn't this "always hairy"? - (when (or (functionp (condition-slot-initfunction slot)) - (dolist (initarg (condition-slot-initargs slot) nil) - (when (functionp (third (assoc initarg e-def-initargs))) - (return t)))) - (push slot (condition-classoid-hairy-slots classoid))))))) - (dolist (fun *define-condition-hooks*) - (funcall fun classoid))))) - name) - -(defmacro define-condition (name (&rest parent-types) (&rest slot-specs) - &body options) - "DEFINE-CONDITION Name (Parent-Type*) (Slot-Spec*) Option* - Define NAME as a condition type. This new type inherits slots and its - report function from the specified PARENT-TYPEs. A slot spec is a list of: - (slot-name :reader <rname> :initarg <iname> {Option Value}* - - The DEFINE-CLASS slot options :ALLOCATION, :INITFORM, [slot] :DOCUMENTATION - and :TYPE and the overall options :DEFAULT-INITARGS and - [type] :DOCUMENTATION are also allowed. - - The :REPORT option is peculiar to DEFINE-CONDITION. Its argument is either - a string or a two-argument lambda or function name. If a function, the - function is called with the condition and stream to report the condition. - If a string, the string is printed. - - Condition types are classes, but (as allowed by ANSI and not as described in - CLtL2) are neither STANDARD-OBJECTs nor STRUCTURE-OBJECTs. WITH-SLOTS and - SLOT-VALUE may not be used on condition objects." - (check-designator name define-condition) - (let* ((parent-types (or parent-types '(condition))) - (layout (find-condition-layout name parent-types)) - (documentation nil) - (report nil) - (direct-default-initargs ())) - (collect ((slots) - (all-readers nil append) - (all-writers nil append)) - (dolist (spec slot-specs) - (with-current-source-form (spec) - (when (keywordp spec) - (warn "Keyword slot name indicates probable syntax error:~% ~S" - spec)) - (let* ((spec (if (consp spec) spec (list spec))) - (slot-name (first spec)) - (allocation :instance) - (initform-p nil) - documentation - initform) - (collect ((initargs) - (readers) - (writers)) - (do ((options (rest spec) (cddr options))) - ((null options)) - (unless (and (consp options) (consp (cdr options))) - (error "malformed condition slot spec:~% ~S." spec)) - (let ((arg (second options))) - (case (first options) - (:reader (readers arg)) - (:writer (writers arg)) - (:accessor - (readers arg) - (writers `(setf ,arg))) - (:initform - (when initform-p - (error "more than one :INITFORM in ~S" spec)) - (setq initform-p t) - (setq initform arg)) - (:initarg (initargs arg)) - (:allocation - (setq allocation arg)) - (:documentation - (when documentation - (error "more than one :DOCUMENTATION in ~S" spec)) - (unless (stringp arg) - (error "slot :DOCUMENTATION argument is not a string: ~S" - arg)) - (setq documentation arg)) - (:type - (check-slot-type-specifier - arg slot-name (cons 'define-condition name))) - (t - (error "unknown slot option:~% ~S" (first options)))))) - - (all-readers (readers)) - (all-writers (writers)) - (slots `(make-condition-slot - :name ',slot-name - :initargs ',(initargs) - :readers ',(readers) - :writers ',(writers) - :initform-p ',initform-p - :documentation ',documentation - :initform ,(when initform-p `',initform) - :initfunction ,(when initform-p - `#'(lambda () ,initform)) - :allocation ',allocation)))))) - - (dolist (option options) - (unless (consp option) - (error "bad option:~% ~S" option)) - (case (first option) - (:documentation (setq documentation (second option))) - (:report - (let ((arg (second option))) - (setq report - `#'(named-lambda (condition-report ,name) (condition stream) - (declare (type condition condition) - (type stream stream)) - ,@(if (stringp arg) - `((declare (ignore condition)) - (write-string ,arg stream)) - `((funcall #',arg condition stream))))))) - (:default-initargs - (doplist (initarg initform) (rest option) - (push ``(,',initarg ,',initform ,#'(lambda () ,initform)) - direct-default-initargs))) - (t - (error "unknown option: ~S" (first option))))) - - ;; Maybe kill docstring, but only under the cross-compiler. - #+(and (not sb-doc) sb-xc-host) (setq documentation nil) - `(progn - ,@(when *top-level-form-p* - ;; Avoid dumping uninitialized layouts, for sb-fasl::dump-layout - `((eval-when (:compile-toplevel) - (%compiler-define-condition ',name ',parent-types ,layout - ',(all-readers) ',(all-writers))))) - (%define-condition ',name - ',parent-types - ,(if *top-level-form-p* - layout - `(find-condition-layout ',name ',parent-types)) - (list ,@(slots)) - (list ,@direct-default-initargs) - ',(all-readers) - ',(all-writers) - (sb-c:source-location) - ,@(and documentation - `(,documentation))) - ;; This needs to be after %DEFINE-CONDITION in case :REPORT - ;; is a lambda referring to condition slot accessors: - ;; they're not proclaimed as functions before it has run if - ;; we're under EVAL or loaded as source. - (%set-condition-report ',name ,report) - ',name)))) - -;;;; various CONDITIONs specified by ANSI - -(define-condition serious-condition (condition) ()) - -(define-condition error (serious-condition) ()) - -(define-condition warning (condition) ()) -(define-condition style-warning (warning) ()) - -(defun simple-condition-printer (condition stream) - (let ((control (simple-condition-format-control condition))) - (if control - (apply #'format stream - control - (simple-condition-format-arguments condition)) - (error "No format-control for ~S" condition)))) - -(define-condition simple-condition () - ((format-control :reader simple-condition-format-control - :initarg :format-control - :initform nil - :type format-control) - (format-arguments :reader simple-condition-format-arguments - :initarg :format-arguments - :initform nil - :type list)) - (:report simple-condition-printer)) - -(define-condition simple-warning (simple-condition warning) ()) - -(define-condition simple-error (simple-condition error) ()) - -(define-condition storage-condition (serious-condition) ()) - -(defun decode-type-error-context (context type) - (typecase context - (cons - (case (car context) - (:struct - (format nil "when setting slot ~s of structure ~s" - (cddr context) (cadr context))) - (t context))) - ((eql :aref) - (let (*print-circle*) - (format nil "when setting an element of (ARRAY ~s)" - type))) - ((eql :ftype) - "from the function type declaration.") - ((and symbol - (not null)) - (format nil "when binding ~s" context)) - (t - context))) - -(define-condition type-error (error) - ((datum :reader type-error-datum :initarg :datum) - (expected-type :reader type-error-expected-type :initarg :expected-type) - (context :initform nil :reader type-error-context :initarg :context)) - (:report - (lambda (condition stream) - (let ((type (type-error-expected-type condition))) - (format stream "~@<The value ~ - ~@:_~2@T~S ~ - ~@:_is not of type ~ - ~@:_~2@T~/sb-impl:print-type-specifier/~@[ ~ - ~@:_~a~]~:@>" - (type-error-datum condition) - type - (decode-type-error-context (type-error-context condition) - type)))))) - -;;; not specified by ANSI, but too useful not to have around. -(define-condition simple-style-warning (simple-condition style-warning) ()) -(define-condition simple-type-error (simple-condition type-error) ()) - -(define-condition program-error (error) ()) -(define-condition parse-error (error) ()) -(define-condition control-error (error) ()) -(define-condition stream-error (error) - ((stream :reader stream-error-stream :initarg :stream))) - -(define-condition end-of-file (stream-error) () - (:report - (lambda (condition stream) - (format stream - "end of file on ~S" - (stream-error-stream condition))))) - -(define-condition closed-stream-error (stream-error) () - (:report - (lambda (condition stream) - (format stream "~S is closed" (stream-error-stream condition))))) - -(define-condition closed-saved-stream-error (closed-stream-error) () - (:report - (lambda (condition stream) - (format stream "~S was closed by SB-EXT:SAVE-LISP-AND-DIE" (stream-error-stream condition))))) - -(define-condition file-error (error) - ((pathname :reader file-error-pathname :initarg :pathname)) - (:report - (lambda (condition stream) - (format stream "error on file ~S" (file-error-pathname condition))))) - -(define-condition package-error (error) - ((package :reader package-error-package :initarg :package))) - -(define-condition cell-error (error) - ((name :reader cell-error-name :initarg :name))) - -(define-condition values-list-argument-error (type-error) - () - (:report - (lambda (condition stream) - (format stream "~@<Attempt to use ~S on a dotted list: ~ - ~2I~_~S~:>" - 'values-list (type-error-datum condition))))) - -(define-condition unbound-variable (cell-error) - ((not-yet-loaded :initform nil :reader not-yet-loaded :initarg :not-yet-loaded)) - (:report - (lambda (condition stream) - (format stream - "~@<The variable ~S is unbound.~@?~@:>" - (cell-error-name condition) - (case (not-yet-loaded condition) - (:local - "~:@_It is a local variable ~ - not available at compile-time.") - (t - "")))))) - -(define-condition retry-unbound-variable - (simple-condition unbound-variable) ()) - -(define-condition undefined-function (cell-error) - ((not-yet-loaded :initform nil :reader not-yet-loaded :initarg :not-yet-loaded)) - (:report - (lambda (condition stream) - (let ((name (cell-error-name condition))) - (format stream - (if (and (symbolp name) (macro-function name)) - (sb-format:tokens "~@<~/sb-ext:print-symbol-with-prefix/ is a macro, ~ - not a function.~@:>") - (sb-format:tokens "~@<The function ~/sb-ext:print-symbol-with-prefix/ ~ - is undefined.~@?~@:>")) - name - (case (not-yet-loaded condition) - (:local - (sb-format:tokens "~:@_It is a local function ~ - not available at compile-time.")) - ((t) (sb-format:tokens "~:@_It is defined earlier in the ~ - file but is not available at compile-time.")) - (t - ""))))))) - -(define-condition retry-undefined-function - (simple-condition undefined-function) ()) - -(define-condition special-form-function (undefined-function) () - (:report - (lambda (condition stream) - (format stream - "Cannot FUNCALL the SYMBOL-FUNCTION of special operator ~S." - (cell-error-name condition))))) - -(define-condition arithmetic-error (error) - ((operation :reader arithmetic-error-operation - :initarg :operation - :initform nil) - (operands :reader arithmetic-error-operands - :initarg :operands)) - (:report (lambda (condition stream) - (format stream - "arithmetic error ~S signalled" - (type-of condition)) - (when (arithmetic-error-operation condition) - (format stream - "~%Operation was (~S ~{~S~^ ~})." - (arithmetic-error-operation condition) - (arithmetic-error-operands condition)))))) - -(define-condition division-by-zero (arithmetic-error) ()) -(define-condition floating-point-overflow (arithmetic-error) ()) -(define-condition floating-point-underflow (arithmetic-error) ()) -(define-condition floating-point-inexact (arithmetic-error) ()) -(define-condition floating-point-invalid-operation (arithmetic-error) ()) - -(define-condition print-not-readable (error) - ((object :reader print-not-readable-object :initarg :object)) - (:report - (lambda (condition stream) - (let ((obj (print-not-readable-object condition)) - (*print-array* nil)) - (format stream "~S cannot be printed readably." obj))))) - -(define-condition reader-error (parse-error stream-error) () - (:report (lambda (condition stream) - (%report-reader-error condition stream)))) - -;;; a READER-ERROR whose REPORTing is controlled by FORMAT-CONTROL and -;;; FORMAT-ARGS (the usual case for READER-ERRORs signalled from -;;; within SBCL itself) -;;; -;;; (Inheriting CL:SIMPLE-CONDITION here isn't quite consistent with -;;; the letter of the ANSI spec: this is not a condition signalled by -;;; SIGNAL when a format-control is supplied by the function's first -;;; argument. It seems to me (WHN) to be basically in the spirit of -;;; the spec, but if not, it'd be straightforward to do our own -;;; DEFINE-CONDITION SB-INT:SIMPLISTIC-CONDITION with -;;; FORMAT-CONTROL and FORMAT-ARGS slots, and use that condition in -;;; place of CL:SIMPLE-CONDITION here.) -(define-condition simple-reader-error (reader-error simple-condition) - () - (:report (lambda (condition stream) - (%report-reader-error condition stream :simple t)))) - -;;; base REPORTing of a READER-ERROR -;;; -;;; When SIMPLE, we expect and use SIMPLE-CONDITION-ish FORMAT-CONTROL -;;; and FORMAT-ARGS slots. -(defun %report-reader-error (condition stream &key simple position) - (let ((error-stream (stream-error-stream condition))) - (pprint-logical-block (stream nil) - (if simple - (apply #'format stream - (simple-condition-format-control condition) - (simple-condition-format-arguments condition)) - (prin1 (class-name (class-of condition)) stream)) - (format stream "~2I~@[~:@_ ~:@_~:{~:(~A~): ~S~:^, ~:_~}~]~:@_ ~:@_Stream: ~S" - (stream-error-position-info error-stream position) - error-stream)))) - -;;;; special SBCL extension conditions - -;;; an error apparently caused by a bug in SBCL itself -;;; -;;; Note that we don't make any serious effort to use this condition -;;; for *all* errors in SBCL itself. E.g. type errors and array -;;; indexing errors can occur in functions called from SBCL code, and -;;; will just end up as ordinary TYPE-ERROR or invalid index error, -;;; because the signalling code has no good way to know that the -;;; underlying problem is a bug in SBCL. But in the fairly common case -;;; that the signalling code does know that it's found a bug in SBCL, -;;; this condition is appropriate, reusing boilerplate and helping -;;; users to recognize it as an SBCL bug. -(define-condition bug (simple-error) - () - (:report - (lambda (condition stream) - (format stream - "~@< ~? ~:@_~?~:>" - (simple-condition-format-control condition) - (simple-condition-format-arguments condition) - "~@<This is probably a bug in SBCL itself. (Alternatively, ~ - SBCL might have been corrupted by bad user code, e.g. by an ~ - undefined Lisp operation like ~S, or by stray pointers from ~ - alien code or from unsafe Lisp code; or there might be a bug ~ - in the OS or hardware that SBCL is running on.) If it seems to ~ - be a bug in SBCL itself, the maintainers would like to know ~ - about it. Bug reports are welcome on the SBCL ~ - mailing lists, which you can find at ~ - <http://sbcl.sourceforge.net/>.~:@>" - '((fmakunbound 'compile)))))) - -(define-condition simple-storage-condition (storage-condition simple-condition) - ()) - -(define-condition sanitizer-error (simple-error) - ((value :reader sanitizer-error-value :initarg :value) - (address :reader sanitizer-error-address :initarg :address) - (size :reader sanitizer-error-size :initarg :size))) - -;;; a condition for use in stubs for operations which aren't supported -;;; on some platforms -;;; -;;; E.g. in sbcl-0.7.0.5, it might be appropriate to do something like -;;; #-(or freebsd linux) -;;; (defun load-foreign (&rest rest) -;;; (error 'unsupported-operator :name 'load-foreign)) -;;; #+(or freebsd linux) -;;; (defun load-foreign ... actual definition ...) -;;; By signalling a standard condition in this case, we make it -;;; possible for test code to distinguish between (1) intentionally -;;; unimplemented and (2) unintentionally just screwed up somehow. -;;; (Before this condition was defined, test code tried to deal with -;;; this by checking for FBOUNDP, but that didn't work reliably. In -;;; sbcl-0.7.0, a package screwup left the definition of -;;; LOAD-FOREIGN in the wrong package, so it was unFBOUNDP even on -;;; architectures where it was supposed to be supported, and the -;;; regression tests cheerfully passed because they assumed that -;;; unFBOUNDPness meant they were running on an system which didn't -;;; support the extension.) -(define-condition unsupported-operator (simple-error) ()) - -;;; (:ansi-cl :function remove) -;;; (:ansi-cl :section (a b c)) -;;; (:ansi-cl :glossary "similar") -;;; -;;; (:sbcl :node "...") -;;; (:sbcl :variable *ed-functions*) -;;; -;;; FIXME: this is not the right place for this. -(defun print-reference (reference stream) - (ecase (car reference) - (:amop - (format stream "AMOP") - (format stream ", ") - (destructuring-bind (type data) (cdr reference) - (ecase type - (:readers "Readers for ~:(~A~) Metaobjects" - (substitute #\ #\- (symbol-name data))) - (:initialization - (format stream "Initialization of ~:(~A~) Metaobjects" - (substitute #\ #\- (symbol-name data)))) - (:generic-function (format stream "Generic Function ~S" data)) - (:function (format stream "Function ~S" data)) - (:section (format stream "Section ~{~D~^.~}" data))))) - (:ansi-cl - (format stream "The ANSI Standard") - (format stream ", ") - (destructuring-bind (type data) (cdr reference) - (ecase type - (:function (format stream "Function ~S" data)) - (:special-operator (format stream "Special Operator ~S" data)) - (:macro (format stream "Macro ~S" data)) - (:section (format stream "Section ~{~D~^.~}" data)) - (:glossary (format stream "Glossary entry for ~S" data)) - (:type (format stream "Type ~S" data)) - (:system-class (format stream "System Class ~S" data)) - (:issue (format stream "writeup for Issue ~A" data))))) - (:sbcl - (format stream "The SBCL Manual") - (format stream ", ") - (destructuring-bind (type data) (cdr reference) - (ecase type - (:node (format stream "Node ~S" data)) - (:variable (format stream "Variable ~S" data)) - (:function (format stream "Function ~S" data))))) - ;; FIXME: other documents (e.g. CLIM, Franz documentation :-) - )) -(define-condition reference-condition () - ((references :initarg :references :reader reference-condition-references))) -(defvar *print-condition-references* t) - -(define-condition simple-reference-error (reference-condition simple-error) - ()) - -(define-condition simple-reference-warning (reference-condition simple-warning) - ()) - -(define-condition arguments-out-of-domain-error - (arithmetic-error reference-condition) - ()) - -;; per CLHS: "The consequences are unspecified if functions are ... -;; multiply defined in the same file." so we are within reason to do any -;; unspecified behavior at compile-time and/or time, but the compiler was -;; annoyingly mum about genuinely inadvertent duplicate macro definitions. -;; Redefinition is henceforth a style-warning, and for compatibility it does -;; not cause the ERRORP value from COMPILE-TIME to be T. -;; Nor do we cite section 3.2.2.3 as the governing prohibition. -(defun report-duplicate-definition (condition stream) - (format stream "~@<Duplicate definition for ~S found in one file.~@:>" - (slot-value condition 'name))) - -(define-condition duplicate-definition (reference-condition warning) - ((name :initarg :name :reader duplicate-definition-name)) - (:report report-duplicate-definition) - (:default-initargs :references '((:ansi-cl :section (3 2 2 3))))) -;; To my thinking, DUPLICATE-DEFINITION should be the ancestor condition, -;; and not fatal. But changing the meaning of that concept would be a bad idea, -;; so instead there is a new condition for the softer variant, which does not -;; inherit from the former. -(define-condition same-file-redefinition-warning (style-warning) - ;; Slot readers aren't proper generic functions until CLOS is built, - ;; so this doesn't get a reader because you can't pick the same name, - ;; and it wouldn't do any good to pick a different name that nothing knows. - ((name :initarg :name)) - (:report report-duplicate-definition)) - -(define-condition constant-modified (reference-condition warning) - ((fun-name :initarg :fun-name :reader constant-modified-fun-name) - (values :initform nil :initarg :values :reader constant-modified-values)) - (:report (lambda (c s) - (format s "~@<Destructive function ~S called on ~ - constant data: ~{~s~^, ~}~:>" - (constant-modified-fun-name c) - (constant-modified-values c)))) - (:default-initargs :references '((:ansi-cl :special-operator quote) - (:ansi-cl :section (3 2 2 3))))) - -(define-condition package-at-variance (reference-condition simple-warning) - () - (:default-initargs :references '((:ansi-cl :macro defpackage) - (:sbcl :variable *on-package-variance*)))) - -(define-condition package-at-variance-error (reference-condition simple-condition - package-error) - () - (:default-initargs :references '((:ansi-cl :macro defpackage)))) - -(define-condition defconstant-uneql (reference-condition error) - ((name :initarg :name :reader defconstant-uneql-name) - (old-value :initarg :old-value :reader defconstant-uneql-old-value) - (new-value :initarg :new-value :reader defconstant-uneql-new-value)) - (:report - (lambda (condition stream) - (format stream - "~@<The constant ~S is being redefined (from ~S to ~S)~@:>" - (defconstant-uneql-name condition) - (defconstant-uneql-old-value condition) - (defconstant-uneql-new-value condition)))) - (:default-initargs :references '((:ansi-cl :macro defconstant) - (:sbcl :node "Idiosyncrasies")))) - -(define-condition array-initial-element-mismatch - (reference-condition simple-warning) - () - (:default-initargs - :references '((:ansi-cl :function make-array) - (:ansi-cl :function sb-xc:upgraded-array-element-type)))) - -(define-condition type-warning (reference-condition simple-warning) - () - (:default-initargs :references '((:sbcl :node "Handling of Types")))) -(define-condition type-style-warning (reference-condition simple-style-warning) - () - (:default-initargs :references '((:sbcl :node "Handling of Types")))) -(define-condition slot-initform-type-style-warning (type-style-warning) ()) - -(define-condition local-argument-mismatch (reference-condition simple-warning) - () - (:default-initargs :references '((:ansi-cl :section (3 2 2 3))))) - -(define-condition format-args-mismatch (reference-condition) - () - (:default-initargs :references '((:ansi-cl :section (22 3 10 2))))) - -(define-condition format-too-few-args-warning - (format-args-mismatch simple-warning) - ()) -(define-condition format-too-many-args-warning - (format-args-mismatch simple-style-warning) - ()) - -(define-condition implicit-generic-function-warning (style-warning) - ((name :initarg :name :reader implicit-generic-function-name)) - (:report - (lambda (condition stream) - (format stream "~@<Implicitly creating new generic function ~ - ~/sb-ext:print-symbol-with-prefix/.~:@>" - (implicit-generic-function-name condition))))) - -(define-condition extension-failure (reference-condition simple-error) - ()) - -(define-condition structure-initarg-not-keyword - (reference-condition simple-style-warning) - () - (:default-initargs :references '((:ansi-cl :section (2 4 8 13))))) - -(define-condition package-lock-violation (package-error - reference-condition - simple-condition) - ((current-package :initform *package* - :reader package-lock-violation-in-package)) - (:report - (lambda (condition stream) - (let ((control (simple-condition-format-control condition)) - (error-package (package-name - (package-error-package condition))) - (current-package (package-name - (package-lock-violation-in-package condition)))) - (format stream "~@<Lock on package ~A violated~@[~{ when ~?~}~] ~ - while in package ~A.~:@>" - error-package - (when control - (list control (simple-condition-format-arguments condition))) - current-package)))) - ;; no :default-initargs -- reference-stuff provided by the - ;; signalling form in target-package.lisp - (:documentation - "Subtype of CL:PACKAGE-ERROR. A subtype of this error is signalled -when a package-lock is violated.")) - -(define-condition package-locked-error (package-lock-violation) () - (:documentation - "Subtype of SB-EXT:PACKAGE-LOCK-VIOLATION. An error of this type is -signalled when an operation on a package violates a package lock.")) - -(define-condition symbol-package-locked-error (package-lock-violation) - ((symbol :initarg :symbol :reader package-locked-error-symbol)) - (:documentation - "Subtype of SB-EXT:PACKAGE-LOCK-VIOLATION. An error of this type is -signalled when an operation on a symbol violates a package lock. The -symbol that caused the violation is accessed by the function -SB-EXT:PACKAGE-LOCKED-ERROR-SYMBOL.")) - -(define-condition undefined-alien-error (cell-error) () - (:report - (lambda (condition stream) - (if (slot-boundp condition 'name) - (format stream "Undefined alien: ~S" (cell-error-name condition)) - (format stream "Undefined alien symbol."))))) - -(define-condition undefined-alien-variable-error (undefined-alien-error) () - (:report - (lambda (condition stream) - (declare (ignore condition)) - (format stream "Attempt to access an undefined alien variable.")))) - -(define-condition undefined-alien-function-error (undefined-alien-error) () - (:report - (lambda (condition stream) - (if (and (slot-boundp condition 'name) - (cell-error-name condition)) - (format stream "The alien function ~s is undefined." - (cell-error-name condition)) - (format stream "Attempt to call an undefined alien function."))))) - -(define-condition unknown-keyword-argument (program-error) - ((name :reader unknown-keyword-argument-name :initarg :name)) - (:report - (lambda (condition stream) - (format stream "Unknown &KEY argument: ~S" - (unknown-keyword-argument-name condition))))) - - -;;;; various other (not specified by ANSI) CONDITIONs -;;;; -;;;; These might logically belong in other files; they're here, after -;;;; setup of CONDITION machinery, only because that makes it easier to -;;;; get cold init to work. - -;;; OAOOM warning: see cross-condition.lisp -(define-condition encapsulated-condition (condition) - ((condition :initarg :condition :reader encapsulated-condition))) - -;;; KLUDGE: a condition for floating point errors when we can't or -;;; won't figure out what type they are. (In FreeBSD and OpenBSD we -;;; don't know how, at least as of sbcl-0.6.7; in Linux we probably -;;; know how but the old code was broken by the conversion to POSIX -;;; signal handling and hasn't been fixed as of sbcl-0.6.7.) -;;; -;;; FIXME: Perhaps this should also be a base class for all -;;; floating point exceptions? -(define-condition floating-point-exception (arithmetic-error) - ((flags :initarg :traps - :initform nil - :reader floating-point-exception-traps)) - (:report (lambda (condition stream) - (format stream - "An arithmetic error ~S was signalled.~%" - (type-of condition)) - (let ((traps (floating-point-exception-traps condition))) - (if traps - (format stream - "Trapping conditions are: ~%~{ ~S~^~}~%" - traps) - (write-line - "No traps are enabled? How can this be?" - stream)))))) - -(define-condition invalid-array-index-error (type-error) - ((array :initarg :array :reader invalid-array-index-error-array) - (axis :initarg :axis :reader invalid-array-index-error-axis)) - (:report - (lambda (condition stream) - (let ((array (invalid-array-index-error-array condition))) - (format stream "Invalid index ~W for ~@[axis ~W of ~]~S, ~ - should be a non-negative integer below ~W." - (type-error-datum condition) - (when (> (array-rank array) 1) - (invalid-array-index-error-axis condition)) - (type-of array) - ;; Extract the bound from (INTEGER 0 (BOUND)) - (caaddr (type-error-expected-type condition))))))) - -(define-condition invalid-array-error (reference-condition type-error) () - (:report - (lambda (condition stream) - (let ((*print-array* nil)) - (format stream - "~@<Displaced array originally of type ~ - ~/sb-impl:print-type-specifier/ has been invalidated ~ - due its displaced-to array ~S having become too small ~ - to hold it: the displaced array's dimensions have all ~ - been set to zero to trap accesses to it.~:@>" - (type-error-expected-type condition) - (array-displacement (type-error-datum condition)))))) - (:default-initargs - :references - (list '(:ansi-cl :function adjust-array)))) - -(define-condition index-too-large-error (type-error) - ((sequence :initarg :sequence)) - (:report - (lambda (condition stream) - (let ((sequence (slot-value condition 'sequence)) - (index (type-error-datum condition))) - (if (vectorp sequence) - (format stream "Invalid index ~W for ~S ~@[with fill-pointer ~a~], ~ - should be a non-negative integer below ~W." - index - (type-of sequence) - (and (array-has-fill-pointer-p sequence) - (fill-pointer sequence)) - (length sequence)) - (format stream - "The index ~S is too large for a ~a of length ~s." - index - (if (listp sequence) - "list" - "sequence") - (length sequence))))))) - -(define-condition bounding-indices-bad-error (reference-condition type-error) - ((object :reader bounding-indices-bad-object :initarg :object)) - (:report - (lambda (condition stream) - (let* ((datum (type-error-datum condition)) - (start (car datum)) - (end (cdr datum)) - (object (bounding-indices-bad-object condition))) - (etypecase object - (sequence - (format stream - "The bounding indices ~S and ~S are bad ~ - for a sequence of length ~S." - start end (length object))) - (array - ;; from WITH-ARRAY-DATA - (format stream - "The START and END parameters ~S and ~S are ~ - bad for an array of total size ~S." - start end (array-total-size object))))))) - (:default-initargs - :references - (list '(:ansi-cl :glossary "bounding index designator") - '(:ansi-cl :issue "SUBSEQ-OUT-OF-BOUNDS:IS-AN-ERROR")))) - -(define-condition nil-array-accessed-error (reference-condition type-error) - () - (:report (lambda (condition stream) - (declare (ignore condition)) - (format stream - "An attempt to access an array of element-type ~ - NIL was made. Congratulations!"))) - (:default-initargs - :references '((:ansi-cl :function sb-xc:upgraded-array-element-type) - (:ansi-cl :section (15 1 2 1)) - (:ansi-cl :section (15 1 2 2))))) - -(define-condition namestring-parse-error (parse-error) - ((complaint :reader namestring-parse-error-complaint :initarg :complaint) - (args :reader namestring-parse-error-args :initarg :args :initform nil) - (namestring :reader namestring-parse-error-namestring :initarg :namestring) - (offset :reader namestring-parse-error-offset :initarg :offset)) - (:report - (lambda (condition stream) - (format stream - "parse error in namestring: ~?~% ~A~% ~V@T^" - (namestring-parse-error-complaint condition) - (namestring-parse-error-args condition) - (namestring-parse-error-namestring condition) - (namestring-parse-error-offset condition))))) - -(define-condition pathname-unparse-error (file-error - simple-condition) - ((problem :reader pathname-unparse-error-problem :initarg :problem)) - (:report (lambda (condition stream) - (format stream "~@<The pathname ~S ~A~:[.~; because ~:*~?~]~@:>" - (file-error-pathname condition) - (pathname-unparse-error-problem condition) - (simple-condition-format-control condition) - (simple-condition-format-arguments condition)))) - (:default-initargs - :problem (missing-arg))) - -(define-condition no-namestring-error (pathname-unparse-error - reference-condition) - () - (:default-initargs - :problem "does not have a namestring" - :references '((:ansi-cl :section (19 1 2))))) -(defun no-namestring-error - (pathname &optional format-control &rest format-arguments) - (error 'no-namestring-error - :pathname pathname - :format-control format-control :format-arguments format-arguments)) - -(define-condition no-native-namestring-error (pathname-unparse-error) - () - (:default-initargs - :problem "does not have a native namestring")) -(defun no-native-namestring-error - (pathname &optional format-control &rest format-arguments) - (error 'no-native-namestring-error - :pathname pathname - :format-control format-control :format-arguments format-arguments)) - -(define-condition simple-package-error (simple-condition package-error) ()) - -(define-condition package-does-not-exist (simple-package-error) ()) - -(define-condition simple-reader-package-error (simple-reader-error package-error) ()) -(define-condition reader-package-does-not-exist (simple-reader-package-error package-does-not-exist) ()) - -(define-condition reader-eof-error (end-of-file) - ((context :reader reader-eof-error-context :initarg :context)) - (:report - (lambda (condition stream) - (format stream - "unexpected end of file on ~S ~A" - (stream-error-stream condition) - (reader-eof-error-context condition))))) - -(define-condition reader-impossible-number-error (simple-reader-error) - ((error :reader reader-impossible-number-error-error :initarg :error)) - (:report - (lambda (condition stream) - (let ((error-stream (stream-error-stream condition))) - (format stream - "READER-ERROR ~@[at ~W ~]on ~S:~%~?~%Original error: ~A" - (sb-impl::file-position-or-nil-for-error error-stream) error-stream - (simple-condition-format-control condition) - (simple-condition-format-arguments condition) - (reader-impossible-number-error-error condition)))))) - -(define-condition standard-readtable-modified-error (reference-condition error) - ((operation :initarg :operation :reader standard-readtable-modified-operation)) - (:report (lambda (condition stream) - (format stream "~S would modify the standard readtable." - (standard-readtable-modified-operation condition)))) - (:default-initargs :references `((:ansi-cl :section (2 1 1 2)) - (:ansi-cl :glossary "standard readtable")))) - -(define-condition standard-pprint-dispatch-table-modified-error - (reference-condition error) - ((operation :initarg :operation - :reader standard-pprint-dispatch-table-modified-operation)) - (:report (lambda (condition stream) - (format stream "~S would modify the standard pprint dispatch table." - (standard-pprint-dispatch-table-modified-operation - condition)))) - (:default-initargs - :references `((:ansi-cl :glossary "standard pprint dispatch table")))) - -(define-condition timeout (serious-condition) - ((seconds :initarg :seconds :initform nil :reader timeout-seconds)) - (:report (lambda (condition stream) - (format stream "Timeout occurred~@[ after ~A second~:P~]." - (timeout-seconds condition)))) - (:documentation - "Signaled when an operation does not complete within an allotted time budget.")) - -(define-condition io-timeout (stream-error timeout) - ((direction :reader io-timeout-direction :initarg :direction)) - (:report - (lambda (condition stream) - (declare (type stream stream)) - (format stream - "I/O timeout while doing ~(~A~) on ~S." - (io-timeout-direction condition) - (stream-error-stream condition))))) - -(define-condition deadline-timeout (timeout) - () - (:report (lambda (condition stream) - (format stream "A deadline was reached after ~A second~:P." - (timeout-seconds condition)))) - (:documentation - "Signaled when an operation in the context of a deadline takes -longer than permitted by the deadline.")) - -(define-condition declaration-type-conflict-error (reference-condition - simple-error) - () - (:default-initargs - :format-control - #.(sb-xc:macroexpand-1 ; stuff in a literal #<fmt-control> - '(sb-format:tokens "Symbol ~/sb-ext:print-symbol-with-prefix/ cannot ~ - be both the name of a type and the name of a declaration")) - :references '((:ansi-cl :section (3 8 21))))) - -;;; Single stepping conditions - -(define-condition step-condition () - ((form :initarg :form :reader step-condition-form)) - (:documentation "Common base class of single-stepping conditions. -STEP-CONDITION-FORM holds a string representation of the form being -stepped.")) - -(setf (documentation 'step-condition-form 'function) - "Form associated with the STEP-CONDITION.") - -(define-condition step-form-condition (step-condition) - ((args :initarg :args :reader step-condition-args)) - (:report - (lambda (condition stream) - (let ((*print-circle* t) - (*print-pretty* t) - (*print-readably* nil)) - (format stream - "Evaluating call:~%~< ~@;~A~:>~%~ - ~:[With arguments:~%~{ ~S~%~}~;With unknown arguments~]~%" - (list (step-condition-form condition)) - (eq (step-condition-args condition) :unknown) - (step-condition-args condition))))) - (:documentation "Condition signalled by code compiled with -single-stepping information when about to execute a form. -STEP-CONDITION-FORM holds the form, STEP-CONDITION-PATHNAME holds the -pathname of the original file or NIL, and STEP-CONDITION-SOURCE-PATH -holds the source-path to the original form within that file or NIL. -Associated with this condition are always the restarts STEP-INTO, -STEP-NEXT, and STEP-CONTINUE.")) - -(define-condition step-result-condition (step-condition) - ((result :initarg :result :reader step-condition-result))) - -(setf (documentation 'step-condition-result 'function) - "Return values associated with STEP-VALUES-CONDITION as a list, -or the variable value associated with STEP-VARIABLE-CONDITION.") - -(define-condition step-values-condition (step-result-condition) - () - (:documentation "Condition signalled by code compiled with -single-stepping information after executing a form. -STEP-CONDITION-FORM holds the form, and STEP-CONDITION-RESULT holds -the values returned by the form as a list. No associated restarts.")) - -(define-condition step-finished-condition (step-condition) - () - (:report - (lambda (condition stream) - (declare (ignore condition)) - (format stream "Returning from STEP"))) - (:documentation "Condition signaled when STEP returns.")) - -;;; A knob for muffling warnings, mostly for use while loading files. -(defvar *muffled-warnings* 'uninteresting-redefinition - "A type that ought to specify a subtype of WARNING. Whenever a -warning is signaled, if the warning is of this type and is not -handled by any other handler, it will be muffled.") - -;;; Various STYLE-WARNING signaled in the system. -;; For the moment, we're only getting into the details for function -;; redefinitions, but other redefinitions could be done later -;; (e.g. methods). -(define-condition redefinition-warning (style-warning) - ((name - :initarg :name - :reader redefinition-warning-name) - (new-location - :initarg :new-location - :reader redefinition-warning-new-location))) - -(define-condition function-redefinition-warning (redefinition-warning) - ((new-function - :initarg :new-function - :reader function-redefinition-warning-new-function))) - -(define-condition redefinition-with-defun (function-redefinition-warning) - () - (:report (lambda (warning stream) - (format stream "redefining ~/sb-ext:print-symbol-with-prefix/ ~ - in DEFUN" - (redefinition-warning-name warning))))) - -(define-condition redefinition-with-defmacro (function-redefinition-warning) - () - (:report (lambda (warning stream) - (format stream "redefining ~/sb-ext:print-symbol-with-prefix/ ~ - in DEFMACRO" - (redefinition-warning-name warning))))) - -(define-condition redefinition-with-defgeneric (redefinition-warning) - () - (:report (lambda (warning stream) - (format stream "redefining ~/sb-ext:print-symbol-with-prefix/ ~ - in DEFGENERIC" - (redefinition-warning-name warning))))) - -(define-condition redefinition-with-defmethod (redefinition-warning) - ((qualifiers :initarg :qualifiers - :reader redefinition-with-defmethod-qualifiers) - (specializers :initarg :specializers - :reader redefinition-with-defmethod-specializers) - (new-location :initarg :new-location - :reader redefinition-with-defmethod-new-location) - (old-method :initarg :old-method - :reader redefinition-with-defmethod-old-method)) - (:report (lambda (warning stream) - (format stream "redefining ~S~{ ~S~} ~S in DEFMETHOD" - (redefinition-warning-name warning) - (redefinition-with-defmethod-qualifiers warning) - (redefinition-with-defmethod-specializers warning))))) - -;;;; Deciding which redefinitions are "interesting". - -(defun function-file-namestring (function) - (when (typep function 'interpreted-function) - (return-from function-file-namestring - #+sb-eval - (sb-c:definition-source-location-namestring - (sb-eval:interpreted-function-source-location function)) - #+sb-fasteval - (awhen (sb-interpreter:fun-source-location function) - (sb-c:definition-source-location-namestring it)))) - (let* ((fun (%fun-fun function)) - (code (fun-code-header fun)) - (debug-info (%code-debug-info code)) - (debug-source (when debug-info - (sb-c::debug-info-source debug-info))) - (namestring (when debug-source - (debug-source-namestring debug-source)))) - namestring)) - -(defun interesting-function-redefinition-warning-p (warning old) - (let ((new (function-redefinition-warning-new-function warning))) - (or - ;; compiled->interpreted is interesting. - (and (typep old 'compiled-function) - (typep new '(not compiled-function))) - ;; fin->regular is interesting except for interpreted->compiled. - (and (typep new '(not funcallable-instance)) - (typep old '(and funcallable-instance (not interpreted-function)))) - ;; different file or unknown location is interesting. - (let* ((old-namestring (function-file-namestring old)) - (new-namestring (function-file-namestring new))) - (and (or (not old-namestring) - (not new-namestring) - (not (string= old-namestring new-namestring)))))))) - -(setf (info :function :predicate-truth-constraint - 'uninteresting-ordinary-function-redefinition-p) 'warning) -(defun uninteresting-ordinary-function-redefinition-p (warning) - (and - (typep warning 'redefinition-with-defun) - ;; Shared logic. - (let ((name (redefinition-warning-name warning))) - (not (interesting-function-redefinition-warning-p - warning (or (fdefinition name) (macro-function name))))))) - -(setf (info :function :predicate-truth-constraint - 'uninteresting-macro-redefinition-p) 'warning) -(defun uninteresting-macro-redefinition-p (warning) - (and - (typep warning 'redefinition-with-defmacro) - ;; Shared logic. - (let ((name (redefinition-warning-name warning))) - (not (interesting-function-redefinition-warning-p - warning (or (macro-function name) (fdefinition name))))))) - -(setf (info :function :predicate-truth-constraint - 'uninteresting-generic-function-redefinition-p) 'warning) -(defun uninteresting-generic-function-redefinition-p (warning) - (and - (typep warning 'redefinition-with-defgeneric) - ;; Can't use the shared logic above, since GF's don't get a "new" - ;; definition -- rather the FIN-FUNCTION is set. - (let* ((name (redefinition-warning-name warning)) - (old (fdefinition name)) - (old-location (when (typep old 'generic-function) - (sb-pcl::definition-source old))) - (old-namestring (when old-location - (sb-c:definition-source-location-namestring old-location))) - (new-location (redefinition-warning-new-location warning)) - (new-namestring (when new-location - (sb-c:definition-source-location-namestring new-location)))) - (and old-namestring - new-namestring - (string= old-namestring new-namestring))))) - -(setf (info :function :predicate-truth-constraint - 'uninteresting-method-redefinition-p) 'warning) -(defun uninteresting-method-redefinition-p (warning) - (and - (typep warning 'redefinition-with-defmethod) - ;; Can't use the shared logic above, since GF's don't get a "new" - ;; definition -- rather the FIN-FUNCTION is set. - (let* ((old-method (redefinition-with-defmethod-old-method warning)) - (old-location (sb-pcl::definition-source old-method)) - (old-namestring (when old-location - (sb-c:definition-source-location-namestring old-location))) - (new-location (redefinition-warning-new-location warning)) - (new-namestring (when new-location - (sb-c:definition-source-location-namestring new-location)))) - (and new-namestring - old-namestring - (string= new-namestring old-namestring))))) - -(deftype uninteresting-redefinition () - '(or (satisfies uninteresting-ordinary-function-redefinition-p) - (satisfies uninteresting-macro-redefinition-p) - (satisfies uninteresting-generic-function-redefinition-p) - (satisfies uninteresting-method-redefinition-p))) - -(define-condition redefinition-with-deftransform (redefinition-warning) - ((transform :initarg :transform - :reader redefinition-with-deftransform-transform)) - (:report (lambda (warning stream) - (format stream "Overwriting ~S" - (redefinition-with-deftransform-transform warning))))) - -;;; Various other STYLE-WARNINGS -(define-condition dubious-asterisks-around-variable-name - (style-warning simple-condition) - () - (:report (lambda (warning stream) - (format stream "~@?, even though the name follows~@ -the usual naming convention (names like *FOO*) for special variables" - (simple-condition-format-control warning) - (simple-condition-format-arguments warning))))) - -(define-condition asterisks-around-lexical-variable-name - (dubious-asterisks-around-variable-name) - ()) - -(define-condition asterisks-around-constant-variable-name - (dubious-asterisks-around-variable-name) - ()) - -(define-condition &optional-and-&key-in-lambda-list - (style-warning simple-condition) - ()) - -;; We call this UNDEFINED-ALIEN-STYLE-WARNING because there are some -;; subclasses of ERROR above having to do with undefined aliens. -(define-condition undefined-alien-style-warning (style-warning) - ((symbol :initarg :symbol :reader undefined-alien-symbol)) - (:report (lambda (warning stream) - (format stream "Undefined alien: ~S" - (undefined-alien-symbol warning))))) - -;;; Formerly this was guarded by "#+(or sb-eval sb-fasteval)", but -;;; why would someone build with no interpreter? And if they did, -;;; would they really care that one extra condition definition exists? -(define-condition lexical-environment-too-complex (style-warning) - ((form :initarg :form :reader lexical-environment-too-complex-form) - (lexenv :initarg :lexenv :reader lexical-environment-too-complex-lexenv)) - (:report (lambda (warning stream) - (format stream - "~@<Native lexical environment too complex for ~ - SB-EVAL to evaluate ~S, falling back to ~ - SIMPLE-EVAL-IN-LEXENV. Lexenv: ~S~:@>" - (lexical-environment-too-complex-form warning) - (lexical-environment-too-complex-lexenv warning))))) - -;; If the interpreter is in use (and the REPL is interpreted), -;; it's easy to accidentally make the macroexpand-hook an interpreted -;; function. So MACROEXPAND-1 is a little more careful, -;; and might signal this, instead of only EVAL being able to signal it. -(define-condition macroexpand-hook-type-error (type-error) - () - (:report (lambda (condition stream) - (format stream "The value of *MACROEXPAND-HOOK* is not a designator for a compiled function: ~S" - (type-error-datum condition))))) - -;; Although this has -ERROR- in the name, it's just a STYLE-WARNING. -(define-condition character-decoding-error-in-comment (style-warning) - ((stream :initarg :stream :reader decoding-error-in-comment-stream) - (position :initarg :position :reader decoding-error-in-comment-position)) - (:report (lambda (warning stream) - (format stream - "Character decoding error in a ~A-comment at ~ - position ~A reading source stream ~A, ~ - resyncing." - (decoding-error-in-comment-macro warning) - (decoding-error-in-comment-position warning) - (decoding-error-in-comment-stream warning))))) - -(define-condition character-decoding-error-in-macro-char-comment - (character-decoding-error-in-comment) - ((char :initform #\; :initarg :char - :reader character-decoding-error-in-macro-char-comment-char))) - -(define-condition character-decoding-error-in-dispatch-macro-char-comment - (character-decoding-error-in-comment) - ;; ANSI doesn't give a way for a reader function invoked by a - ;; dispatch macro character to determine which dispatch character - ;; was used, so if a user wants to signal one of these from a custom - ;; comment reader, he'll have to supply the :DISP-CHAR himself. - ((disp-char :initform #\# :initarg :disp-char - :reader character-decoding-error-in-macro-char-comment-disp-char) - (sub-char :initarg :sub-char - :reader character-decoding-error-in-macro-char-comment-sub-char))) - -(defun decoding-error-in-comment-macro (warning) - (etypecase warning - (character-decoding-error-in-macro-char-comment - (character-decoding-error-in-macro-char-comment-char warning)) - (character-decoding-error-in-dispatch-macro-char-comment - (format - nil "~C~C" - (character-decoding-error-in-macro-char-comment-disp-char warning) - (character-decoding-error-in-macro-char-comment-sub-char warning))))) - -(define-condition deprecated-eval-when-situations (style-warning) - ((situations :initarg :situations - :reader deprecated-eval-when-situations-situations)) - (:report (lambda (warning stream) - (format stream "using deprecated EVAL-WHEN situation names~{ ~S~}" - (deprecated-eval-when-situations-situations warning))))) - -(define-condition proclamation-mismatch (condition) - ((kind :initarg :kind :reader proclamation-mismatch-kind) - (description :initarg :description :reader proclamation-mismatch-description :initform nil) - (name :initarg :name :reader proclamation-mismatch-name) - (old :initarg :old :reader proclamation-mismatch-old) - (new :initarg :new :reader proclamation-mismatch-new)) - (:report - (lambda (condition stream) - (format stream - "~@<The new ~A proclamation for~@[ ~A~] ~ - ~/sb-ext:print-symbol-with-prefix/~ - ~@:_~2@T~/sb-impl:print-type-specifier/~@:_~ - does not match the old ~4:*~A~3* proclamation~ - ~@:_~2@T~/sb-impl:print-type-specifier/~@:>" - (proclamation-mismatch-kind condition) - (proclamation-mismatch-description condition) - (proclamation-mismatch-name condition) - (proclamation-mismatch-new condition) - (proclamation-mismatch-old condition))))) - -(define-condition type-proclamation-mismatch (proclamation-mismatch) - () - (:default-initargs :kind 'type)) - -(define-condition type-proclamation-mismatch-warning (style-warning - type-proclamation-mismatch) - ()) - -(define-condition ftype-proclamation-mismatch (proclamation-mismatch) - () - (:default-initargs :kind 'ftype)) - -(define-condition ftype-proclamation-mismatch-warning (style-warning - ftype-proclamation-mismatch) - ()) - -(define-condition ftype-proclamation-mismatch-error (error - ftype-proclamation-mismatch) - () - (:default-initargs :kind 'ftype :description "known function")) - - -;;;; deprecation conditions - -(define-condition deprecation-condition (reference-condition) - ((namespace :initarg :namespace - :reader deprecation-condition-namespace) - (name :initarg :name - :reader deprecation-condition-name) - (replacements :initarg :replacements - :reader deprecation-condition-replacements) - (software :initarg :software - :reader deprecation-condition-software) - (version :initarg :version - :reader deprecation-condition-version) - (runtime-error :initarg :runtime-error - :reader deprecation-condition-runtime-error - :initform nil)) - (:default-initargs - :namespace (missing-arg) - :name (missing-arg) - :replacements (missing-arg) - :software (missing-arg) - :version (missing-arg) - :references '((:sbcl :node "Deprecation Conditions"))) - (:documentation - "Superclass for deprecation-related error and warning -conditions.")) - -(defmethod print-object ((condition deprecation-condition) stream) - (flet ((print-it (stream) - (print-deprecation-message - (deprecation-condition-namespace condition) - (deprecation-condition-name condition) - (deprecation-condition-software condition) - (deprecation-condition-version condition) - (deprecation-condition-replacements condition) - stream))) - (if *print-escape* - (print-unreadable-object (condition stream :type t) - (print-it stream)) - (print-it stream)))) - -(macrolet ((define-deprecation-warning - (name superclass check-runtime-error format-string - &optional documentation) - `(progn - (define-condition ,name (,superclass deprecation-condition) - () - ,@(when documentation - `((:documentation ,documentation)))) - - (defmethod print-object :after ((condition ,name) stream) - (when (and (not *print-escape*) - ,@(when check-runtime-error - `((deprecation-condition-runtime-error condition)))) - (format stream ,format-string - (deprecation-condition-software condition) - (deprecation-condition-name condition))))))) - - ;; These conditions must not occur in self-build! - (define-deprecation-warning early-deprecation-warning style-warning nil - "~%~@<~:@_In future~@[ ~A~] versions ~ - ~/sb-ext:print-symbol-with-prefix/ will signal a full warning ~ - at compile-time.~:@>" - "This warning is signaled when the use of a variable, -function, type, etc. in :EARLY deprecation is detected at -compile-time. The use will work at run-time with no warning or -error.") - - (define-deprecation-warning late-deprecation-warning warning t - "~%~@<~:@_In future~@[ ~A~] versions ~ - ~/sb-ext:print-symbol-with-prefix/ will signal a runtime ~ - error.~:@>" - "This warning is signaled when the use of a variable, -function, type, etc. in :LATE deprecation is detected at -compile-time. The use will work at run-time with no warning or -error.") - - (define-deprecation-warning final-deprecation-warning warning t - "~%~@<~:@_~*An error will be signaled at runtime for ~ - ~/sb-ext:print-symbol-with-prefix/.~:@>" - "This warning is signaled when the use of a variable, -function, type, etc. in :FINAL deprecation is detected at -compile-time. An error will be signaled at run-time.")) - -(define-condition deprecation-error (error deprecation-condition) - () - (:documentation - "This error is signaled at run-time when an attempt is made to use -a thing that is in :FINAL deprecation, i.e. call a function or access -a variable.")) - -;;;; restart definitions - -(define-condition abort-failure (control-error) () - (:report - "An ABORT restart was found that failed to transfer control dynamically.")) - -(defun abort (&optional condition) - "Transfer control to a restart named ABORT, signalling a CONTROL-ERROR if - none exists." - (invoke-restart (find-restart-or-control-error 'abort condition)) - ;; ABORT signals an error in case there was a restart named ABORT - ;; that did not transfer control dynamically. This could happen with - ;; RESTART-BIND. - (error 'abort-failure)) - -(defun muffle-warning (&optional condition) - "Transfer control to a restart named MUFFLE-WARNING, signalling a - CONTROL-ERROR if none exists." - (invoke-restart (find-restart-or-control-error 'muffle-warning condition))) - -(defun try-restart (name condition &rest arguments) - (let ((restart (find-restart name condition))) - (when restart - (apply #'invoke-restart restart arguments)))) - -(macrolet ((define-nil-returning-restart (name args doc) - `(defun ,name (,@args &optional condition) - ,doc - (try-restart ',name condition ,@args)))) - (define-nil-returning-restart continue () - "Transfer control to a restart named CONTINUE, or return NIL if none exists.") - (define-nil-returning-restart store-value (value) - "Transfer control and VALUE to a restart named STORE-VALUE, or -return NIL if none exists.") - (define-nil-returning-restart use-value (value) - "Transfer control and VALUE to a restart named USE-VALUE, or -return NIL if none exists.") - (define-nil-returning-restart print-unreadably () - "Transfer control to a restart named SB-EXT:PRINT-UNREADABLY, or -return NIL if none exists.")) - -;;; single-stepping restarts - -(macrolet ((def (name doc) - `(defun ,name (condition) - ,doc - (invoke-restart (find-restart-or-control-error ',name condition))))) - (def step-continue - "Transfers control to the STEP-CONTINUE restart associated with -the condition, continuing execution without stepping. Signals a -CONTROL-ERROR if the restart does not exist.") - (def step-next - "Transfers control to the STEP-NEXT restart associated with the -condition, executing the current form without stepping and continuing -stepping with the next form. Signals CONTROL-ERROR if the restart does -not exist.") - (def step-into - "Transfers control to the STEP-INTO restart associated with the -condition, stepping into the current form. Signals a CONTROL-ERROR if -the restart does not exist.")) - -;;; Compiler macro magic - -(define-condition compiler-macro-keyword-problem () - ((argument :initarg :argument :reader compiler-macro-keyword-argument)) - (:report (lambda (condition stream) - (format stream "~@<Argument ~S in keyword position is not ~ - a self-evaluating symbol, preventing compiler-macro ~ - expansion.~@:>" - (compiler-macro-keyword-argument condition))))) - -;; After (or if) we deem this the optimal name for this condition, -;; it should be exported from SB-EXT so that people can muffle it. -(define-condition sb-c:inlining-dependency-failure (simple-style-warning) ()) - - -(define-condition layout-invalid (type-error) - () - (:report - (lambda (condition stream) - (format stream - "~@<invalid structure layout: ~ - ~2I~_A test for class ~4I~_~S ~ - ~2I~_was passed the obsolete instance ~4I~_~S~:>" - (classoid-proper-name (type-error-expected-type condition)) - (type-error-datum condition))))) - -(define-condition case-failure (type-error) - ((name :reader case-failure-name :initarg :name) - (possibilities :reader case-failure-possibilities :initarg :possibilities)) - (:report - (lambda (condition stream) - (let ((*print-escape* t)) - (format stream "~@<~S fell through ~S expression.~@[ ~ - ~:_Wanted one of (~/pprint-fill/).~]~:>" - (type-error-datum condition) - (case-failure-name condition) - (case-failure-possibilities condition)))))) - -(define-condition compiled-program-error (program-error) - ((message :initarg :message :reader program-error-message) - (source :initarg :source :reader program-error-source)) - (:report (lambda (condition stream) - (format stream "Execution of a form compiled with errors.~%~ - Form:~% ~A~%~ - Compile-time error:~% ~A" - (program-error-source condition) - (program-error-message condition))))) - -(define-condition simple-control-error (simple-condition control-error) ()) -(define-condition simple-file-error (simple-condition file-error) ()) - -(defun %file-error (pathname &optional datum &rest arguments) - (typecase datum - (format-control (error 'simple-file-error :pathname pathname - :format-control datum - :format-arguments arguments)) - (t (apply #'error datum :pathname pathname arguments)))) - -(define-condition file-exists (simple-file-error) ()) -(define-condition file-does-not-exist (simple-file-error) ()) -(define-condition delete-file-error (simple-file-error) ()) - -(define-condition simple-stream-error (simple-condition stream-error) ()) -(define-condition simple-parse-error (simple-condition parse-error) ()) - -(define-condition broken-pipe (simple-stream-error) ()) - -(define-condition character-coding-error (error) - ((external-format :initarg :external-format :reader character-coding-error-external-format))) -(define-condition character-encoding-error (character-coding-error) - ((code :initarg :code :reader character-encoding-error-code))) -(define-condition character-decoding-error (character-coding-error) - ((octets :initarg :octets :reader character-decoding-error-octets))) -(define-condition stream-encoding-error (stream-error character-encoding-error) - () - (:report - (lambda (c s) - (let ((stream (stream-error-stream c)) - (code (character-encoding-error-code c))) - (format s "~@<~S stream encoding error on ~S: ~2I~_~ - the character with code ~D cannot be encoded.~@:>" - (character-coding-error-external-format c) - stream - code))))) -(define-condition stream-decoding-error (stream-error character-decoding-error) - () - (:report - (lambda (c s) - (let ((stream (stream-error-stream c)) - (octets (character-decoding-error-octets c))) - (format s "~@<~S stream decoding error on ~S: ~2I~_~ - the octet sequence ~S cannot be decoded.~@:>" - (character-coding-error-external-format c) - stream - octets))))) - -(define-condition c-string-encoding-error (character-encoding-error) - () - (:report - (lambda (c s) - (format s "~@<~S c-string encoding error: ~2I~_~ - the character with code ~D cannot be encoded.~@:>" - (character-coding-error-external-format c) - (character-encoding-error-code c))))) - -(define-condition c-string-decoding-error (character-decoding-error) - () - (:report - (lambda (c s) - (format s "~@<~S c-string decoding error: ~2I~_~ - the octet sequence ~S cannot be decoded.~@:>" - (character-coding-error-external-format c) - (character-decoding-error-octets c))))) - -(define-condition control-stack-exhausted (storage-condition) - () - (:report - (lambda (condition stream) - (declare (ignore condition)) - (format stream - ;; no pretty-printing, because that would use a lot of stack. - "Control stack exhausted (no more space for function call frames). -This is probably due to heavily nested or infinitely recursive function -calls, or a tail call that SBCL cannot or has not optimized away. - -PROCEED WITH CAUTION.")))) - -(define-condition binding-stack-exhausted (storage-condition) - () - (:report - (lambda (condition stream) - (declare (ignore condition)) - (format stream - ;; no pretty-printing, because that would use a lot of stack. - "Binding stack exhausted. - -PROCEED WITH CAUTION.")))) - -(define-condition alien-stack-exhausted (storage-condition) - () - (:report - (lambda (condition stream) - (declare (ignore condition)) - (format stream - ;; no pretty-printing, because that would use a lot of stack. - "Alien stack exhausted. - -PROCEED WITH CAUTION.")))) - -(define-condition heap-exhausted-error (storage-condition) - () - (:report - (lambda (condition stream) - (declare (ignore condition)) - (declare (special *heap-exhausted-error-available-bytes* - *heap-exhausted-error-requested-bytes*)) - ;; See comments in interr.lisp -- there is a method to this madness. - (if (and (boundp '*heap-exhausted-error-available-bytes*) - (boundp '*heap-exhausted-error-requested-bytes*)) - (format stream - ;; no pretty-printing, because that will use a lot of heap. - "Heap exhausted (no more space for allocation). -~D bytes available, ~D requested. - -PROCEED WITH CAUTION." - *heap-exhausted-error-available-bytes* - *heap-exhausted-error-requested-bytes*) - (format stream - "A ~S condition without bindings for heap statistics. (If -you did not expect to see this message, please report it." - 'heap-exhausted-error))))) - -(define-condition system-condition (condition) - ((address :initarg :address :reader system-condition-address :initform nil) - (context :initarg :context :reader system-condition-context :initform nil))) - -(define-condition memory-fault-error (system-condition error) () - (:report - (lambda (condition stream) - (format stream "Unhandled memory fault at #x~X." - (system-condition-address condition))))) - -(define-condition breakpoint-error (system-condition error) () - (:report - (lambda (condition stream) - (format stream "Unhandled breakpoint/trap at #x~X." - (system-condition-address condition))))) - -(define-condition interactive-interrupt (system-condition serious-condition) () - (:report - (lambda (condition stream) - (format stream "Interactive interrupt at #x~X." - (system-condition-address condition))))) diff --git a/src/code/cross-byte.lisp b/src/code/cross-byte.lisp index 1cea9823c2..391d88ebe3 100644 --- a/src/code/cross-byte.lisp +++ b/src/code/cross-byte.lisp @@ -55,7 +55,7 @@ (declaim (ftype function bug)) (define-setf-expander sb-xc:ldb (cross-byte int &environment env) (multiple-value-bind (temps vals stores store-form access-form) - (get-setf-expansion int env) + (cl:get-setf-expansion int env) (when (cdr stores) (bug "SETF SB-XC:LDB too hairy!")) (let ((btemp (gensym)) @@ -69,8 +69,8 @@ `(cl:ldb (uncross-byte ,btemp) ,access-form))))) (define-setf-expander sb-xc:mask-field (cross-byte int &environment env) - (multiple-value-bind (temps vals stores store-form access-form) - (get-setf-expansion int env) + (multiple-value-bind (temps vals stores store-form access-form) + (cl:get-setf-expansion int env) (when (cdr stores) (bug "SETF SB-XC:MASK-FIELD too hairy!")) (let ((btemp (gensym)) diff --git a/src/code/cross-early.lisp b/src/code/cross-early.lisp index ce95ad14cc..b1b20be9fe 100644 --- a/src/code/cross-early.lisp +++ b/src/code/cross-early.lisp @@ -11,11 +11,6 @@ (in-package "SB-IMPL") -;;; The STRUCTURE!OBJECT abstract class is the base of the hierarchy -;;; of objects that need to be identifiable as SBCL system objects -;;; in the host Lisp. This type does not exist in the target. -(defstruct (structure!object (:constructor nil) (:copier nil) (:predicate nil))) - (declaim (declaration truly-dynamic-extent)) ;;; MAYBE-INLINE, FREEZE-TYPE, and block compilation declarations can be safely ignored @@ -30,13 +25,6 @@ (defgeneric sb-xc:make-load-form (obj &optional env)) -;;; There's no real reason that the cross-compiler shouldn't get the -;;; same macro as the target for this, except that the host doesn't -;;; compile 'cl-specials', and it's kind of unlikely that we'd have -;;; our own sources not fail in make-host-1 using illegal designators. -;;; As to make-host-2, well, it's not a user-facing problem. -(defmacro check-designator (&rest junk) (declare (ignore junk))) - ;;; Restore normalcy of MOD and RATIONAL as type specifiers. (deftype mod (n) `(integer 0 ,(1- n))) (deftype rational (&optional low high) `(cl:rational ,low ,high)) @@ -103,7 +91,7 @@ (declaim (inline zerop)) (defun zerop (x) (if (rationalp x) (= x 0) (xfloat-zerop x))) -(defmethod make-load-form ((self target-num) &optional env) +(defmethod cl:make-load-form ((self target-num) &optional env) (declare (ignore env)) (if (complexp self) `(complex ,(complexnum-real self) ,(complexnum-imag self)) diff --git a/src/code/cross-float.lisp b/src/code/cross-float.lisp index 2b04191f4c..b9b9130efe 100644 --- a/src/code/cross-float.lisp +++ b/src/code/cross-float.lisp @@ -185,7 +185,7 @@ (exp-marker (if (and marker-pos (char-not-equal (char string marker-pos) #\E)) (char-upcase (char string marker-pos)) - (ecase *read-default-float-format* + (ecase cl:*read-default-float-format* ((cl:single-float cl:short-float) #\F) ((cl:double-float cl:long-float) #\D)))) (significand (if marker-pos (subseq string 0 marker-pos) string)) @@ -287,9 +287,9 @@ (rest values) values) table)))) + (setf (cdr cache) (hash-table-count table)) (when cl:*compile-verbose* - (format t "~&; Float-ops cache prefill: ~D entries~%" - (setf (cdr cache) (hash-table-count table))))))) + (format t "~&; Float-ops cache prefill: ~D entries~%" (cdr cache)))))) table)) (defun record-math-op (key &rest values) @@ -381,7 +381,7 @@ ((null value) ; must not be one of the exceptional symbols (setf (flonum-%value x) (calculate-flonum-value x))) (t ; infinity or minus-zero - (error "~S has no portable value" x))))) + (error "~S (~D) has no portable value" value x))))) (t (error "Got host float")))) (defun realnumify* (args) (mapcar #'realnumify args)) @@ -714,28 +714,28 @@ ;;; These use "#." so that they are dumped as literals rather than having to ;;; call read-from-string at load-time (and failing) due to the reader intercept. ;; #define __FLT_MAX__ 3.40282347e+38F -(defconstant sb-xc:most-positive-single-float +(defconstant most-positive-single-float #.(make-flonum (read-from-string "+3.40282347F38") 'single-float)) -(defconstant sb-xc:most-negative-single-float +(defconstant most-negative-single-float #.(make-flonum (read-from-string "-3.40282347F38") 'single-float)) ;; #define __DBL_MAX__ 1.7976931348623157e+308 -(defconstant sb-xc:most-positive-double-float +(defconstant most-positive-double-float #.(make-flonum (read-from-string "+1.7976931348623157D308") 'double-float)) -(defconstant sb-xc:most-negative-double-float +(defconstant most-negative-double-float #.(make-flonum (read-from-string "-1.7976931348623157D308") 'double-float)) ;;; PI is needed in order to build the cross-compiler mainly so that vm-fndb ;;; can define bounds on irrational functions. -(defconstant sb-xc:pi +(defconstant pi #.(make-flonum (read-from-string "3.14159265358979323846264338327950288419716939937511L0") 'double-float)) (eval-when (:compile-toplevel :execute) (setq sb-cold::*choke-on-host-irrationals* t)) -;;; These two constants are used in 'late-type' -(defconstant sb-xc:most-positive-long-float sb-xc:most-positive-double-float) -(defconstant sb-xc:most-negative-long-float sb-xc:most-negative-double-float) +;;; These two constants are used in 'type' +(defconstant most-positive-long-float most-positive-double-float) +(defconstant most-negative-long-float most-negative-double-float) (defun substitute-minus-zero (list) (substitute $0.0d0 @@ -758,7 +758,13 @@ `(let ((x (car args)) (y (cadr args))) (and (floatp x) (floatp y) (eql (flonum-%bits x) (flonum-%bits y))))) (two-zeros-p () - `(and (eql nargs 2) (zerop (car args)) (zerop (cadr args))))) + `(and (eql nargs 2) (zerop (car args)) (zerop (cadr args)))) + (same-sign-infinities-p () + `(and (eql nargs 2) + (floatp (car args)) + (floatp (cadr args)) + (member (flonum-%value (car args)) '(:-infinity :+infinity)) + (eq (flonum-%value (cadr args)) (flonum-%value (car args)))))) ;; Simple case of using the interceptor to return a boolean. If ;; infinity leaks in, the host will choke since those are @@ -768,11 +774,19 @@ ;; Simple case of using the interceptor to return a float. ;; As above, no funky values allowed. - (intercept (max min + sqrt acos acosh asin asinh atan atanh conjugate cos cosh fceiling ffloor fround ftruncate phase sin sinh tan tanh) (&rest args) + (intercept (max min + acos acosh asin asinh atan atanh conjugate cos cosh fceiling ffloor fround ftruncate phase sin sinh tan tanh) (&rest args) (dispatch :me (make-flonum (apply #':me (realnumify* args)) (apply #'pick-result-format args)))) + (intercept (sqrt) (&rest args) + (destructuring-bind (x) args + (if (zerop x) + x + (dispatch :me + (make-flonum (funcall #':me (realnumify x)) + (pick-result-format x)))))) + (intercept (*) (&rest args) (dispatch :me (let ((res (make-flonum (apply #':me (realnumify* (substitute-minus-zero args))) @@ -833,6 +847,7 @@ (eql b $2.0d0)))) nil) ((two-zeros-p) t) ; signed zeros are equal + ((same-sign-infinities-p) t) ; infinities are = ((and (eql nargs 2) (zerop (cadr args))) ;; Need this case if the first arg is represented as bits (if (rationalp (car args)) @@ -851,16 +866,17 @@ (if (and (eq (flonum-format a) (flonum-format c)) (or (eq (flonum-format b) (flonum-format a)) (eq (flonum-format b) 'single-float))) - (cond ((and (eql a sb-xc:most-negative-single-float) - (eql c sb-xc:most-positive-single-float)) + (cond ((and (eql a most-negative-single-float) + (eql c most-positive-single-float)) (not (float-infinity-p b))) - ((and (eql a sb-xc:most-negative-double-float) - (eql c sb-xc:most-positive-double-float)) + ((and (eql a most-negative-double-float) + (eql c most-positive-double-float)) (not (float-infinity-p b))) (t (error "Unhandled"))) (error "Unhandled")))) ((two-zeros-p) t) ; signed zeros are equal + ((same-sign-infinities-p) t) ; infinities are = ((and (eql nargs 2) (zerop (cadr args))) ;; Need this case if the first arg is represented as bits (if (floatp (car args)) @@ -992,6 +1008,7 @@ (assert (eq (make-flonum :+infinity format) (sb-xc:- (make-flonum :-infinity format)))) (assert (eq (make-flonum :-infinity format) (sb-xc:- (make-flonum :+infinity format)))) (assert (eq (sb-xc:- (coerce 0 format)) (make-flonum :minus-zero format))) + (let ((*break-on-signals* nil)) (flet ((assert-not-number (x) (handler-case (realnumify x) (:no-error (x) (error "Expected an error, got ~S" x)) @@ -1001,7 +1018,7 @@ (assert-not-number nan) (assert (float-nan-p nan))) (dolist (symbol '(:+infinity :-infinity :minus-zero)) - (assert-not-number (make-flonum symbol format))))) + (assert-not-number (make-flonum symbol format)))))) #+host-quirks-sbcl ; Cross-check some more things if we can (loop for (our-symbol host-single host-double) diff --git a/src/code/cross-misc.lisp b/src/code/cross-misc.lisp index c5ba3b1d8e..d18cebbc70 100644 --- a/src/code/cross-misc.lisp +++ b/src/code/cross-misc.lisp @@ -14,19 +14,30 @@ ;;; Forward declarations +(defun make-system-hash-table (&rest args) + (let ((args (copy-list args))) + (remf args :weakness) + (remf args :synchronized) + (remf args :finalizer) + (let ((hash-fun (getf args :hash-function))) + (when hash-fun + (assert (eq (getf args :test) 'eq)) + (remf args :hash-function))) + (apply 'make-hash-table args))) + ;;; In correct code, TRULY-THE has only a performance impact and can ;;; be safely degraded to ordinary THE. (defmacro truly-the (type expr) `(the ,type ,expr)) +(defmacro the* ((type &rest args) expr) + (declare (ignore args)) + `(the ,type ,expr)) + (defmacro named-lambda (name args &body body) (declare (ignore name)) `#'(lambda ,args ,@body)) -(defmacro with-locked-system-table ((table) &body body) - (declare (ignore table)) - `(progn ,@body)) - (defmacro define-thread-local (&rest rest) `(defvar ,@rest)) (defmacro defglobal (name value &rest doc) @@ -41,7 +52,30 @@ ;;; Necessary only to placate the host compiler in %COMPILER-DEFGLOBAL. (defun set-symbol-global-value (sym val) - (error "Can't set symbol-global-value: ~S ~S" sym val)) + (setf (symbol-value sym) val)) + +(defun %defun (name lambda &optional inline-expansion) + (declare (ignore inline-expansion)) + (cl:proclaim `(ftype function ,name)) + (setf (fdefinition name) lambda)) + +(defun %defglobal (name value source-location &optional (doc nil docp)) + (declare (ignore source-location doc docp)) + (cl:proclaim `(special ,name)) + (setf (symbol-value name) value)) + +(defun %defparameter (var val source-location &optional (doc nil docp)) + (declare (ignore source-location doc docp)) + (cl:proclaim `(special ,var)) + (setf (symbol-value var) val)) + +(defun %defvar (var source-location &optional (val nil valp) (doc nil docp)) + (declare (ignore source-location doc docp)) + (cl:proclaim `(special ,var)) + (when (and valp (not (boundp var))) + (setf (symbol-value var) val))) + +(defun %boundp (symbol) (boundp symbol)) ;;; The GENESIS function works with fasl code which would, in the ;;; target SBCL, work on ANSI-STREAMs (streams which aren't extended @@ -52,25 +86,12 @@ ;;; In the target SBCL, the INSTANCE type refers to a base ;;; implementation for compound types with lowtag ;;; INSTANCE-POINTER-LOWTAG. There's no way to express exactly that -;;; concept portably, but we know that anything derived from STRUCTURE!OBJECT -;;; is equivalent to the target INSTANCE type. Also, because we use host packages -;;; as proxies for target packages, those too must satisfy our INSTANCEP -;;; - even if not a subtype of (OR STANDARD-OBJECT STRUCTURE-OBJECT). -;;; Nothing else satisfies this definition of INSTANCEP. -;;; As a guarantee that our set of host object types is exhaustive, we add one -;;; more constraint when self-hosted: host instances of unknown type cause failure. -;;; Some objects manipulated by the cross-compiler like the INTERVAL struct -;;; - which is not a STRUCTURE!OBJECT - should never be seen as literals in code. -;;; We assert that by way of the guard function. -#+host-quirks-sbcl -(defun unsatisfiable-instancep (x) - (when (and (host-sb-kernel:%instancep x) - (not (target-num-p x))) - (bug "%INSTANCEP test on ~S" x))) +;;; concept portably, but we can at least declare here what kind of +;;; host objects get dumped into something that when loaded would be a +;;; target INSTANCE. (deftype instance () - '(or structure!object package - #+host-quirks-sbcl (and host-sb-kernel:instance ; optimizes out a call when false - (satisfies unsatisfiable-instancep)))) + '(or (and structure-object (not target-num)) + package)) (defun %instancep (x) (typep x 'instance)) @@ -104,6 +125,8 @@ (or (not (typep x 'simple-array)) (/= (array-rank x) 1)))) +;;; We maintain a separate GENSYM counter since the host is allowed to +;;; mutate its counter however it wishes. (defvar sb-xc:*gensym-counter* 0) (defun sb-xc:gensym (&optional (thing "G")) @@ -179,10 +202,18 @@ (declaim (declaration enable-package-locks disable-package-locks)) +;;; The XC-STRICT-CL and SB-XC packages are called COMMON-LISP in the +;;; target image. +(defun sb-xc:package-name (package) + (if (or (eq package #.(find-package "SB-XC")) + (eq package #.(find-package "XC-STRICT-CL"))) + "COMMON-LISP" + (cl:package-name package))) + ;; Nonstandard accessor for when you know you have a valid package in hand. ;; This avoids double lookup in *PACKAGE-NAMES* in a few places. ;; But portably we have to just fallback to PACKAGE-NAME. -(defun package-%name (x) (package-name x)) +(defun package-%name (x) (sb-xc:package-name x)) ;;; This definition collapses SB-XC back into COMMON-LISP. ;;; Use CL:SYMBOL-PACKAGE if that's not the behavior you want. @@ -191,10 +222,14 @@ ;;; host CL package. This works around situations where the host has *more* ;;; symbols exported from CL than should be. (defun sb-xc:symbol-package (symbol) - (let ((p (cl:symbol-package symbol))) + (let ((p (cl:symbol-package symbol)) + (name (string symbol))) (if (and p - (or (eq (find-symbol (string symbol) "XC-STRICT-CL") symbol) - (eq (find-symbol (string symbol) "SB-XC") symbol))) + (let ((xc-strict-symbol (find-symbol name #.(find-package "XC-STRICT-CL")))) + (and xc-strict-symbol + (or (eq xc-strict-symbol symbol) + (eq symbol (find-symbol name #.(find-package "SB-XC"))) + (eq symbol (find-symbol name #.(find-package "COMMON-LISP"))))))) *cl-package* p))) @@ -205,6 +240,32 @@ (write structure :stream stream :circle t)) (in-package "SB-KERNEL") + +;;; These functions are required to emulate SBCL kernel functions +;;; in a vanilla ANSI Common Lisp cross-compilation host. +;;; The emulation doesn't need to be efficient, since it's needed +;;; only for object dumping. + +;; The set of structure types that we access by slot position at cross-compile +;; time is fairly small: +;; - DEFINITION-SOURCE-LOCATION +;; - DEFSTRUCT-DESCRIPTION, DEFSTRUCT-SLOT-DESCRIPTION +;; - DEBUG-SOURCE, COMPILED-DEBUG-INFO, COMPILED-DEBUG-FUN-{something} +;; - HEAP-ALIEN-INFO and ALIEN-{something}-TYPE +;; - COMMA +#-metaspace (defmacro wrapper-friend (x) x) +(defun %instance-wrapper (instance) + (declare (notinline classoid-wrapper)) + (classoid-wrapper (find-classoid (type-of instance)))) +(defun %instance-length (instance) + (declare (notinline wrapper-length)) + ;; In the target, it is theoretically possible to have %INSTANCE-LENGTH + ;; exceeed layout length, but in the cross-compiler they're the same. + (wrapper-length (%instance-wrapper instance))) +(defun layout-id (x) + (declare (notinline sb-kernel::wrapper-id)) + (sb-kernel::wrapper-id x)) + (defun %find-position (item seq from-end start end key test) (let ((position (position item seq :from-end from-end :start start :end end :key key :test test))) @@ -216,23 +277,62 @@ ;;; Needed for constant-folding (defun system-area-pointer-p (x) x nil) ; nothing is a SAP -;;; Needed for DEFINE-MOVE-FUN LOAD-SYSTEM-AREA-POINTER -(defun sap-int (x) (error "can't take SAP-INT ~S" x)) +(defmacro sap-ref-word (sap offset) + `(#+64-bit sap-ref-64 #-64-bit sap-ref-32 ,sap ,offset)) + +;;; Needed for assembler. +(defstruct (asm-sap-wrapper (:constructor vector-sap (vector))) + (vector (missing-arg) :type (simple-array (unsigned-byte 8) (*)))) +(defmacro with-pinned-objects (list &body body) + (declare (ignore list)) + `(progn ,@body)) +;;; The assembler does not USE-PACKAGE sb-sys, which works to our advantage +;;; in that we can define SAP-REF-16 and -32 as macros in the ASM package +;;; which avoids conflict with genesis. Genesis has its own SAP emulations in SB-SYS +;;; so all the definitions of FIXUP-CODE-OBJECT using the native accessors +;;; can transparently operate on genesis's model of target code blobs. +(defsetf sb-assem::sap-ref-16 sb-assem::asm-set-sap-ref-16) +(defsetf sb-assem::sap-ref-32 sb-assem::asm-set-sap-ref-32) +(defun sb-assem::asm-set-sap-ref-16 (sap index val) + (declare (type asm-sap-wrapper sap)) + (multiple-value-bind (b0 b1) + #+little-endian (values (ldb (byte 8 0) val) (ldb (byte 8 8) val)) + #+big-endian (values (ldb (byte 8 8) val) (ldb (byte 8 0) val)) + (let ((octets (asm-sap-wrapper-vector sap))) + (setf (aref octets (+ index 0)) b0 + (aref octets (+ index 1)) b1))) + val) +(defun sb-assem::asm-set-sap-ref-32 (sap index val) + (declare (type asm-sap-wrapper sap)) + (multiple-value-bind (b0 b1 b2 b3) + #+little-endian (values (ldb (byte 8 0) val) (ldb (byte 8 8) val) + (ldb (byte 8 16) val) (ldb (byte 8 24) val)) + #+big-endian (values (ldb (byte 8 24) val) (ldb (byte 8 16) val) + (ldb (byte 8 8) val) (ldb (byte 8 0) val)) + (let ((octets (asm-sap-wrapper-vector sap))) + (setf (aref octets (+ index 0)) b0 + (aref octets (+ index 1)) b1 + (aref octets (+ index 2)) b2 + (aref octets (+ index 3)) b3))) + val) (defun logically-readonlyize (x) x) ;;; Mainly for the fasl loader (defun %fun-name (f) (nth-value 2 (function-lambda-expression f))) +(defun %svset (vector index val) ; stemming from toplevel (SETF SVREF) + (setf (aref vector index) val)) +(defun %puthash (key table val) ; stemming from toplevel (SETF GETHASH) + (setf (gethash key table) val)) + ;;;; Variables which have meaning only to the cross-compiler, defined here ;;;; in lieu of #+sb-xc-host elsewere which messes up toplevel form numbers. (in-package "SB-C") -;;; For macro lambdas that are processed by the host -(declaim (declaration top-level-form)) - -;;; The opposite of the whitelist - if certain full calls are seen, it is probably -;;; the result of a missed transform and/or misconfiguration. +;;; The opposite of *undefined-fun-allowlist* - if certain full calls +;;; are seen, it is probably the result of a missed transform and/or +;;; misconfiguration. (defparameter *full-calls-to-warn-about* '(;mask-signed-field ;; Too many to fix )) @@ -243,9 +343,9 @@ (let* ((n (length string)) (a (make-array n :element-type '(unsigned-byte 8)))) (dotimes (i n a) - (let ((code (sb-xc:char-code (char string i)))) + (let ((code (char-code (char string i)))) (unless (<= 0 code 127) - (setf code (sb-xc:char-code #\?))) + (setf code (char-code #\?))) (setf (aref a i) code))))) ;;;; Stubs for host @@ -255,91 +355,14 @@ `(lambda ,@(cddr lambda)) lambda))) -(defun sb-impl::%defun (name lambda &optional inline-expansion) - (declare (ignore inline-expansion)) - (proclaim `(ftype function ,name)) - (setf (fdefinition name) (eval lambda))) - -(defun %svset (vector index val) ; stemming from toplevel (SETF SVREF) - (setf (aref vector index) val)) -(defun %puthash (key table val) ; stemming from toplevel (SETF GETHASH) - (setf (gethash key table) val)) - ;;; The compiler calls this with forms in EVAL-WHEN (:COMPILE-TOPLEVEL) situations. -;;; Since we've already performed macroexpansion using our macros, we can either -;;; implement target-compatible functions for all things into which we might expand, -;;; or we can un-macro-expand the form. This does a little of both, -;;; mainly for the sake of showing that it's quite easily done. -;;; Truth be told I'd have preferred to use the anti-expansion technique consistently, -;;; however occasionally we see things like (LET ((V FROB)) (%SVSET *THING* X V)) -;;; which means that the host is going to do the LET and then call %SVSET. (defun eval-tlf (form index &optional lexenv) (declare (ignore index lexenv)) - (flet ((matchp (template form &aux results) - (if (named-let recurse ((form form) (template template)) - (typecase template - (null (null form)) - ((eql ?) (push form results) t) ; match and store anything - ((eql :ignore) t) ; match anything and disregard - ((cons (eql :or)) - (some (lambda (template) - (recurse form template)) - (cdr template))) - (cons (and (consp form) - (and (recurse (car form) (car template)) - (recurse (cdr form) (cdr template))))) - (t (eql template form)))) ; match template exactly - (nreverse results) - (error "Pattern match failure: ~S~% ~S~%" template form)))) - ;; Note that in all cases below, the package lock on CL prevents - ;; accidental appearance of a CL symbol as a thing being defined. - (named-let recurse ((form form)) - (case (car form) - (progn (mapc #'recurse (cdr form))) ; compiler doesn't care about return value - (t - (eval - (case (car form) - (sb-impl::%defglobal - (destructuring-bind (symbol value) - (matchp '((quote ?) (if (%boundp :ignore) :ignore ?)) (cdr form)) - `(defvar ,symbol ,value))) - (sb-impl::%defparameter - (destructuring-bind (symbol value) - (matchp '((quote ?) ? :ignore) (cdr form)) - `(defparameter ,symbol ,value))) - (sb-impl::%defvar - (destructuring-bind (symbol value) ; always occurs with a value - (matchp '((quote ?) (source-location) (:or (unless (%boundp :ignore) ?) ?)) - (cdr form)) - `(defvar ,symbol ,value))) - (sb-c::%defconstant - ;; There is genuinely ambiguity here - does :COMPILE-TOPLEVEL situation for - ;; DEFCONSTANT mean that we want the host compiler to know the constant? - ;; It must, because the standard specifies that defconstant need not be within - ;; EVAL-WHEN for the compiler to know it. But because of how our defconstant - ;; expands - calling %defconstant inside of an eval-when listing all 3 - ;; situations - we can't discern whether this is our defconstant doing its - ;; normal thing, versus inside an explicity written eval-when with intent - ;; to convey the constant to the host - perhaps because of a DEFUN also inside - ;; an eval-when where we need the host to reference the constant. - ;; Therefore every constant has to be made known to the host under the - ;; assumption that it needs it, AND the cross-compiler under the assumption - ;; that this is our normal :compile-toplevel handling. - (destructuring-bind (symbol value) (matchp '((quote ?) ? . :ignore) (cdr form)) - `(progn (defconstant ,symbol ,value) - (sb-c::%defconstant ',symbol ,symbol nil)))) - (sb-xc:defconstant ; we see this maro as well. The host expansion will not do, - ;; because it calls our %defconstant which does not assign the symbol a value. - ;; It might be possible to change that now that we don't use CL: symbols. - (destructuring-bind (symbol value) (cdr form) - `(progn (defconstant ,symbol ,value) - (sb-c::%defconstant ',symbol ,symbol nil)))) - (t - form)))))))) + (eval form)) (defmacro sb-format:tokens (string) string) -(defmacro sb-thread::with-recursive-system-lock ((lock) &body body) +(defmacro with-system-mutex ((lock) &body body) (declare (ignore lock)) `(progn ,@body)) @@ -352,3 +375,10 @@ (defmacro %primitive (name arg) (ecase name (print `(format t "~A~%" ,arg)))) + +(defmacro %with-output-to-string ((var) &body body) + ;; Let's suppose that the host lisp knows what it's doing to efficiently + ;; compile the standard macro. Don't try to outdo it. + `(with-output-to-string (,var) ,@body)) + +(defun source-location ()) diff --git a/src/code/cross-modular.lisp b/src/code/cross-modular.lisp index b334e580d8..74aea77c3c 100644 --- a/src/code/cross-modular.lisp +++ b/src/code/cross-modular.lisp @@ -45,13 +45,38 @@ (do-mfuns *tagged-modular-class*))) `(progn ,@(forms))) -#.` -(defun ,(intern (format nil "ASH-LEFT-MOD~D" sb-vm:n-machine-word-bits) - "SB-VM") +(defun #.(intern (format nil "ASH-LEFT-MOD~D" sb-vm:n-machine-word-bits) "SB-VM") (integer amount) - (ldb (byte ,sb-vm:n-machine-word-bits 0) (ash integer amount))) + (ldb (byte #.sb-vm:n-machine-word-bits 0) (ash integer amount))) #+(or x86 x86-64 arm arm64) (defun sb-vm::ash-left-modfx (integer amount) (mask-signed-field (- sb-vm:n-word-bits sb-vm:n-fixnum-tag-bits) (ash integer amount))) + +;;;; these cross-compiler compatibility functions have vops for +;;;; the target machine. +;;;; COUNT is regarded as having either 5 (for 32-machines) or 6 +;;;; (for 64-bit machines) significant bits. Excess bits must be ignored +;;;; either explicitly in the vops (arm[64], ppc[64]) or by the CPU +;;;; (x86, sparc, mips, riscv). + +;;; Shift NUMBER by the low-order bits of COUNT, adding zero bits +;;; at the "end" and removing bits from the "start". On big-endian +;;; machines this is a left-shift and on little-endian machines this +;;; is a right-shift. +(defun shift-towards-start (number count) + (declare (type word number) (fixnum count)) + (let ((count (ldb (byte (1- (integer-length sb-vm:n-word-bits)) 0) count))) + #+big-endian (logand (ash number count) most-positive-word) + #+little-endian (ash number (- count)))) + +;;; Shift NUMBER by the low-order bits of COUNT, adding zero bits +;;; at the "start" and removing bits from the "end". On big-endian +;;; machines this is a right-shift and on little-endian machines this +;;; is a left-shift. +(defun shift-towards-end (number count) + (declare (type word number) (fixnum count)) + (let ((count (ldb (byte (1- (integer-length sb-vm:n-word-bits)) 0) count))) + #+big-endian (ash number (- count)) + #+little-endian (logand (ash number count) most-positive-word))) diff --git a/src/code/cross-type.lisp b/src/code/cross-type.lisp index 949ce00d38..861bbace67 100644 --- a/src/code/cross-type.lisp +++ b/src/code/cross-type.lisp @@ -69,7 +69,7 @@ ;;; Defined here so that CROSS-TYPEP can use it. ;;; The target variant of this is in src/code/package. (defmacro system-package-p (package) - `(eql (mismatch "SB-" (package-name ,package)) 3)) + `(eql (mismatch "SB-" (cl:package-name ,package)) 3)) ;;; This is like TYPEP, except that it asks whether OBJ (a host object acting ;;; as a proxy for some logically equivalent object in the target sytem) @@ -82,7 +82,7 @@ ;;; The logic is a mixture of the code for CTYPEP and %%TYPEP ;;; because it handles both. ;;; The order of clauses is fairly symmetrical with that of %%TYPEP. -(defvar *xtypep-uncertainty-action* 'warn) ; {BREAK WARN STYLE-WARN ERROR NIL} +(defvar *xtypep-uncertainty-action* #-sb-devel 'warn #+sb-devel nil) ; {BREAK WARN STYLE-WARN ERROR NIL} (macrolet ((unimplemented () '(bug "Incomplete implementation of ~S ~S ~S" caller obj type)) (uncertain () @@ -137,7 +137,7 @@ #+sb-simd-pack-256 simd-pack-256-type) (values nil t)) (character-set-type - ;; provided that SB-XC:CHAR-CODE doesn't fail, the answer is certain + ;; provided that CHAR-CODE doesn't fail, the answer is certain (values (test-character-type type) t)) (classoid ; = {built-in,structure,condition,standard,static}-classoid (let ((name (classoid-name type))) @@ -150,18 +150,16 @@ ;; probably not a function. What about FMT-CONTROL instances? (values nil t))) ((system-area-pointer stream fdefn weak-pointer file-stream - code-component lra) + code-component lra pathname logical-pathname) (values nil t))) (cond ((eq name 'pathname) (values (pathnamep obj) t)) ((not (%instancep obj)) (values nil t)) ; false certainly (t - (if (and (cl:find-class name nil) ; see if the host knows the type - ;; and it's in our object hierarchy - (cl:subtypep name 'structure!object)) + (if (cl:find-class name nil) ; see if the host knows the type (values (cl:typep obj name) t) - (unimplemented))))))) + (unimplemented))))))) (fun-type (if (fun-designator-type-p type) (values (typep obj '(or symbol function)) t) @@ -172,7 +170,7 @@ (if (and (functionp obj) (eq caller 'sb-xc:typep)) (error "TYPEP called with function type") (values (functionp obj) t)))) - (alien-type-type (if (null obj) (values nil t) (unimplemented))) + (alien-type-type (if (symbolp obj) (values nil t) (unimplemented))) ;; Test UNKNOWN before falling into the HAIRY case (unknown-type (let ((spec (unknown-type-specifier type))) @@ -186,8 +184,8 @@ ;; true for various X that are not known yet. (cond ((and (symbolp spec) (cl:find-class spec nil) - ;; See if the host knows our DEF!STRUCT yet - (cl:subtypep spec 'structure!object)) + ;; See if the host knows our DEFSTRUCT yet + (cl:subtypep spec 'instance)) (values (cl:typep obj spec) t)) ;; Sometimes we try to test a forward-referenced type ;; that was unknown at the point of creation but has @@ -226,6 +224,7 @@ ;; subtypes of structure-object in make-host-1. '(hash-table lexenv sb-c::abstract-lexenv condition restart + pathname sb-impl::host sb-impl::pattern synonym-stream ;; why on earth is LABEL needed here? sb-assem:label)))) @@ -240,6 +239,10 @@ ;; Keep in sync with KEYWORDP test in src/code/target-type (cond ((eq predicate 'keywordp) (test-keywordp)) + ;; These are needed in order to compile the predicates + ;; for the initial pprint dispatch table. + ((and (eq obj nil) (member predicate '(fboundp macro-function))) + (values nil t)) ((acceptable-cross-typep-pred predicate caller) (values (funcall predicate obj) t)) (t @@ -308,6 +311,7 @@ (and (boundp 'sb-c::*compilation*) (eq (sb-c::block-compile sb-c::*compilation*) t))) (values answer certain) + #-sb-devel (warn 'cross-type-giving-up :call `(ctypep ,obj ,ctype))))) (defun ctype-of (x) @@ -343,14 +347,15 @@ (t ;; Beyond this, there seems to be no portable correspondence. (error "can't map host Lisp CHARACTER ~S to target Lisp" x)))) - (sb-c::opaque-box (find-classoid 'structure-object)) - (instance - (let ((type (type-of x))) - (if (eq type 'sb-format::fmt-control-proxy) - ;; These are functions, but they're weird. We don't want any IR1 transform - ;; on FORMAT to kick in and try to convert to FUNCALL on the thing. - (specifier-type '(or string function)) - (find-classoid type)))) + (instance + (let ((type (type-of x))) + (if (eq type 'sb-format::fmt-control-proxy) + ;; These are functions, but they're weird. We don't want any IR1 transform + ;; on FORMAT to kick in and try to convert to FUNCALL on the thing. + (specifier-type '(or string function)) + ;; The structure may not be defined on the target yet. + (or (find-classoid type nil) + (find-classoid 'structure-object))))) (t ;; There might be more cases which we could handle with ;; sufficient effort; since all we *need* to handle are enough diff --git a/src/code/deadline.lisp b/src/code/deadline.lisp index d5111c0624..a32f2f7e62 100644 --- a/src/code/deadline.lisp +++ b/src/code/deadline.lisp @@ -32,7 +32,7 @@ (declaim (inline seconds-to-internal-time)) (defun seconds-to-internal-time (seconds) (the internal-time - (values (truncate (* seconds sb-xc:internal-time-units-per-second))))) + (values (truncate (* seconds internal-time-units-per-second))))) (eval-when (:compile-toplevel :load-toplevel :execute) ; for "#." (defconstant safe-internal-seconds-limit @@ -46,11 +46,10 @@ ;; #. is needed to make the value constant per se as opposed to ;; constant by decree, otherwise genesis runs into a problem. #.(floor (ash 1 (1- sb-kernel::internal-time-bits)) - sb-xc:internal-time-units-per-second))) + internal-time-units-per-second))) (declaim (inline seconds-to-maybe-internal-time)) (defun seconds-to-maybe-internal-time (seconds) - (declare (optimize (speed 3))) (typecase seconds ((integer 0 #.internal-seconds-limit) (locally ; FIXME compiler should learn to figure that out @@ -115,8 +114,8 @@ Experimental." "Returns internal time value TIME decoded into seconds and microseconds." (declare (type internal-time time)) (multiple-value-bind (sec frac) - (truncate time sb-xc:internal-time-units-per-second) - (values sec (* frac sb-unix::micro-seconds-per-internal-time-unit)))) + (truncate time internal-time-units-per-second) + (values sec (* frac sb-unix::microseconds-per-internal-time-unit)))) (defun signal-timeout (datum &rest arguments) "Signals a timeout condition while inhibiting further timeouts due to diff --git a/src/code/debug-info.lisp b/src/code/debug-info.lisp index 723f629760..7039f8f8d0 100644 --- a/src/code/debug-info.lisp +++ b/src/code/debug-info.lisp @@ -134,6 +134,11 @@ (blocks nil :type (or (simple-array (unsigned-byte 8) (*)) (simple-array (signed-byte 8) (*)) null)) + ;; If all code locations in this function are in the same top level + ;; form, then this is the number of that form, otherwise NIL. If + ;; NIL, then each code location represented in the BLOCKS specifies + ;; the TLF number. + (tlf-number nil :type (or index null)) ;; a vector describing the variables that the argument values are ;; stored in within this function. The locations are represented by ;; the ordinal number of the entry in the VARIABLES slot value. The @@ -388,16 +393,12 @@ ;; the universal time that the source was written, or NIL if ;; unavailable (created nil :type (or unsigned-byte null)) + ;; The FILE-POSITIONs of the truly top level forms read from this + ;; file (if applicable). The vector element type will be chosen to + ;; hold the largest element. + (start-positions nil :type (or (simple-array * (*)) null) :read-only t) ;; Additional information from (WITH-COMPILATION-UNIT (:SOURCE-PLIST ...)) (plist *source-plist* :read-only t)) -(def!struct (core-debug-source (:pure t) - (:copier nil) - (:include debug-source)) - ;; Compilation to memory stores each toplevel form given to %COMPILE. - ;; That form can generate multiple functions, and those functions can - ;; be in one or more code components. They all point at the same form. - form - (function nil :read-only t)) ;;;; DEBUG-INFO structures @@ -418,16 +419,9 @@ ;; Location contexts ;; A (simple-array * (*)) or a context if there's only one context. (contexts nil :type t :read-only t) - (tlf-num+offset nil :type integer)) - -;;; The TLF-NUMBER and CHAR-OFFSET of a compiled-debug-info can each be NIL, -;;; but aren't often. However, to allow that, convert NIL to 0 and non-nil -;;; value N to N+1. -(defun pack-tlf-num+offset (tlf-number char-offset) - (with-adjustable-vector (v) - (write-var-integer (if tlf-number (1+ tlf-number) 0) v) - (write-var-integer (if char-offset (1+ char-offset) 0) v) - (integer-from-octets v))) + ;; The CDR is an alist which maps SB-C::COMPILED-DEBUG-FUN to + ;; SB-DI::COMPILED-DEBUG-FUN instances. Null when unassigned. + (memo-cell nil :type list)) ;;;; file reading ;;;; @@ -445,17 +439,18 @@ (:copier nil) (:print-object (lambda (s stream) (print-unreadable-object (s stream :type t) - (princ (file-info-name s) stream))))) + (princ (file-info-truename s) stream))))) ;; If a file, the truename of the corresponding source file. If from - ;; a Lisp form, :LISP. If from a stream, :STREAM. - (name (missing-arg) :type (or pathname (eql :lisp)) :read-only t) + ;; a Lisp form, :LISP. In COMPILE-FILE, this gets filled lazily + ;; after the file gets opened. + (truename nil :type (or pathname null (eql :lisp))) ;; the external format that we'll call OPEN with, if NAME is a file. (external-format nil :read-only t) ;; the defaulted, but not necessarily absolute file name (i.e. prior ;; to TRUENAME call.) Null if not a file. This is used to set ;; *COMPILE-FILE-PATHNAME*, and if absolute (a harmful constraint to be sure), ;; is dumped in the debug-info. - (untruename nil :type (or pathname null) :read-only t) + (pathname nil :type (or pathname null) :read-only t) ;; the file's write date (if relevant) (write-date nil :type (or unsigned-byte null) :read-only t) ;; parallel vectors containing the forms read out of the file and diff --git a/src/code/debug-int.lisp b/src/code/debug-int.lisp index 67b0a2b6fb..c9c42228b4 100644 --- a/src/code/debug-int.lisp +++ b/src/code/debug-int.lisp @@ -12,6 +12,15 @@ (in-package "SB-DI") +(defstruct (sb-c::core-debug-source (:pure t) + (:copier nil) + (:include debug-source)) + ;; Compilation to memory stores each toplevel form given to %COMPILE. + ;; That form can generate multiple functions, and those functions can + ;; be in one or more code components. They all point at the same form. + form + (function nil :read-only t)) + ;;; FIXME: There are an awful lot of package prefixes in this code. ;;; Couldn't we have SB-DI use the SB-C and SB-VM packages? @@ -287,6 +296,9 @@ ;; the DEBUG-BLOCK containing CODE-LOCATION. XXX Possibly toss this ;; out and just find it in the blocks cache in DEBUG-FUN. (%debug-block :unparsed :type (or debug-block (member :unparsed))) + ;; This is the number of forms processed by the compiler or loader + ;; before the top level form containing this code-location. + (%tlf-offset :unparsed :type (or index (member :unparsed))) ;; This is the depth-first number of the node that begins ;; code-location within its top level form. (%form-number :unparsed :type (or index (member :unparsed)))) @@ -341,21 +353,9 @@ ;;; This maps SB-C::COMPILED-DEBUG-FUNs to ;;; COMPILED-DEBUG-FUNs, so we can get at cached stuff and not ;;; duplicate COMPILED-DEBUG-FUN structures. +#+cheneygc ; can't write to debug-info in a purified code object (define-load-time-global *compiled-debug-funs* (make-hash-table :test 'eq :weakness :key)) - -;;; Make a COMPILED-DEBUG-FUN for a SB-C::COMPILER-DEBUG-FUN and its -;;; component. This maps the latter to the former in -;;; *COMPILED-DEBUG-FUNS*. If there already is a COMPILED-DEBUG-FUN, -;;; then this returns it from *COMPILED-DEBUG-FUNS*. -;;; -;;; FIXME: It seems this table can potentially grow without bounds, -;;; and retains roots to functions that might otherwise be collected. -(defun make-compiled-debug-fun (compiler-debug-fun component) - (let ((table *compiled-debug-funs*)) - (with-locked-system-table (table) - (ensure-gethash compiler-debug-fun table - (%make-compiled-debug-fun compiler-debug-fun component))))) ;;;; breakpoints @@ -369,7 +369,7 @@ ;; This is the byte offset into the component. (offset nil :type index :read-only t) ;; The original instruction replaced by the breakpoint. - (instruction nil :type (or null sb-vm:word)) + (instruction nil :type (or null word)) ;; A list of user breakpoints at this location. (breakpoints nil :type list)) (defmethod print-object ((obj breakpoint-data) str) @@ -448,6 +448,46 @@ ;; the :FUN-START breakpoint (if any) used to facilitate ;; function end breakpoints (end-starter nil :type (or null breakpoint))) + +;;; Map a SB-C::COMPILED-DEBUG-FUN to a SB-DI::COMPILED-DEBUG-FUN. +;;; The mapping is memoized into a slot of %CODE-DEBUG-INFO of COMPONENT +;;; except on #+cheneygc where that is assumed not to be possible +;;; (even if it is possible), because usually it's not, because +;;; code and the debug structures are defined with :PURE T and might reside +;;; in readonly space, which can only have pointers to static space. +;;; +;;; BTW, the nomenclature here is utter and total confusion. +;;; The type of the object in the argument named COMPILER-DEBUG-FUN +;;; is SB-C::COMPILED-DEBUG-FUN. +;;; There is no such type as a "COMPILER-DEBUG-FUN", it's just the name +;;; of the slot in the SB-DI:: version of the structure. +(defun make-compiled-debug-fun (compiler-debug-fun component) + (declare (code-component component)) + #+gencgc + (let ((memo-cell + (let* ((info (sb-vm::%%code-debug-info component)) + (val (sb-c::compiled-debug-info-memo-cell info))) + (if (null val) + (let* ((list (cons val nil)) + (old (cas (sb-c::compiled-debug-info-memo-cell info) val list))) + (if (eq old val) list old)) + val)))) + ;; The CDR of MEMO-CELL slot is an alist from compiler -> debugger structure. + (let ((new-df nil) (new-pair nil) (new-alist nil) (alist (cdr memo-cell))) + (loop + ;; This list generally contains 5 items or less. At least, in our tests it does + ;; which I assume is typical. + (awhen (assoc compiler-debug-fun alist :test #'eq) (return (cdr it))) + (if new-alist + (rplacd new-alist alist) + (setq new-df (%make-compiled-debug-fun compiler-debug-fun component) + new-pair (cons compiler-debug-fun new-df) + new-alist (cons new-pair alist))) + (let ((old (cas (cdr memo-cell) alist new-alist))) + (if (eq old alist) (return new-df) (setq alist old)))))) + #+cheneygc + (ensure-gethash compiler-debug-fun *compiled-debug-funs* + (%make-compiled-debug-fun compiler-debug-fun component))) ;;;; CODE-LOCATIONs @@ -457,12 +497,12 @@ str))) (defstruct (compiled-code-location - (:include code-location) - (:constructor make-known-code-location - (pc debug-fun %debug-block %form-number - %live-set kind step-info context &aux (%unknown-p nil))) - (:constructor make-compiled-code-location (pc debug-fun)) - (:copier nil)) + (:include code-location) + (:constructor make-known-code-location + (pc debug-fun %debug-block %tlf-offset %form-number + %live-set kind step-info context &aux (%unknown-p nil))) + (:constructor make-compiled-code-location (pc debug-fun)) + (:copier nil)) ;; an index into DEBUG-FUN's component slot (pc nil :type index :read-only t) ;; a bit-vector indexed by a variable's position in @@ -472,7 +512,7 @@ ;; (unexported) To see SB-C::LOCATION-KIND, do ;; (SB-KERNEL:TYPEXPAND 'SB-C::LOCATION-KIND). (kind :unparsed :type (or (member :unparsed) sb-c::location-kind)) - (step-info :unparsed :type (or (member :unparsed :foo) simple-string)) + (step-info :unparsed :type (or (member :unparsed) simple-string)) (context :unparsed)) ;;;; frames @@ -486,9 +526,18 @@ ;;; "#define REAL_LRA_SLOT" in breakpoint.c. These have unfortunately ;;; different values, because this slot is relative to the object base ;;; address, whereas the one in C is an index into code->constants. -(defconstant real-lra-slot sb-vm:code-constants-offset) - -#-sb-fluid (declaim (inline control-stack-pointer-valid-p)) +(defconstant bpt-lra-boxed-nwords + ;; * For non-x86: a single boxed constant holds the true LRA. + ;; Additionally, MIPS gets a boxed slot for the cookie + ;; that formerly went in a weak hash-table. + ;; * For x86[-64]: one boxed constant holds the code object to which + ;; to return, one holds the displacement into that object, + ;; and one holds the cookie + (+ code-constants-offset 2 #+(or x86-64 x86) 1)) +(defconstant real-lra-slot code-constants-offset) +(defconstant cookie-slot (+ code-constants-offset 1 #+(or x86 x86-64) 1)) + +(declaim (inline control-stack-pointer-valid-p)) (defun control-stack-pointer-valid-p (x &optional (aligned t)) (declare (type system-area-pointer x)) (let* (#-stack-grows-downward-not-upward @@ -501,12 +550,12 @@ (and (sap< x (current-sp)) (sap<= control-stack-start x) (or (not aligned) (zerop (logand (sap-int x) - (1- (ash 1 sb-vm:word-shift)))))) + (1- (ash 1 word-shift)))))) #+stack-grows-downward-not-upward (and (sap>= x (current-sp)) (sap> control-stack-end x) (or (not aligned) (zerop (logand (sap-int x) - (1- (ash 1 sb-vm:word-shift)))))))) + (1- (ash 1 word-shift)))))))) (declaim (inline valid-lisp-pointer-p)) (sb-alien:define-alien-routine valid-lisp-pointer-p sb-alien:int @@ -525,7 +574,7 @@ ;;; (1) use unsafe %MAKE-LISP-OBJ, since we've already determined ;;; where the code object starts with certainty, and we don't need ;;; yet another search to test validity of the address. -;;; (2) wrap the calls in WITHOUT-GCING. +;;; (2) wrap the calls in WITH-CODE-PAGES-PINNED. ;;; ;;; Here's a concrete example, assuming the following objects exists: ;;; 0x8000: vector header | @@ -561,7 +610,7 @@ ;;; to any object on a specified page. ;;; ;;; On top of the considerations about dynamic space, there is a further issue -;;; with allocatin of immobile code. The allocator creates transient inconsistent +;;; with allocation of immobile code. The allocator creates transient inconsistent ;;; states when it reuses holes. Even if the header could be written atomically, ;;; there can be junk in the remaining bytes of the hole that gets rewritten as ;;; a smaller hole. It's evident that acquiring the allocator mutex works around @@ -584,18 +633,15 @@ ;;; to malloc() in that regard. (defun code-header-from-pc (pc) - (declare (system-area-pointer pc)) - (macrolet ((heap-scan () - `(let ((component-ptr - (sb-alien:alien-funcall - (sb-alien:extern-alien - "component_ptr_from_pc" - (function system-area-pointer system-area-pointer)) - pc))) - (unless (sap= component-ptr (int-sap 0)) - (%make-lisp-obj - (logior (sap-int component-ptr) sb-vm:other-pointer-lowtag)))))) - (without-gcing (heap-scan)))) + (with-code-pages-pinned (:dynamic) + (let ((base-ptr + (sb-alien:alien-funcall + (sb-alien:extern-alien "component_ptr_from_pc" + (function sb-alien:unsigned system-area-pointer)) + (etypecase pc + (system-area-pointer pc) + (word (int-sap pc)))))) + (unless (= base-ptr 0) (%make-lisp-obj (logior base-ptr other-pointer-lowtag)))))) ;;;; (OR X86 X86-64) support @@ -615,7 +661,7 @@ ;;; address. ;;; ;;; XXX Could be a little smarter. -#-sb-fluid (declaim (inline ra-pointer-valid-p)) +(declaim (inline ra-pointer-valid-p)) (defun ra-pointer-valid-p (ra) (declare (type system-area-pointer ra)) (and @@ -674,6 +720,8 @@ (when saved-fp (compute-calling-frame saved-fp saved-pc up-frame t)))) +#+c-stack-is-control-stack +(progn (defun walk-binding-stack (symbol function) (let* (#+sb-thread (tls-index (symbol-tls-index symbol)) @@ -682,8 +730,10 @@ (sap-ref-lispobj (sb-thread::current-thread-sap) tls-index) #-sb-thread (symbol-value symbol))) - (unless (eq (get-lisp-obj-address current-value) - no-tls-value-marker-widetag) + ;; This is slightly dangerous - the right thing would be + ;; to access using SAP-REF-WORD and compare like a few lines below. + ;; Why does #-sb-thread even check for this at all? + (unless (eql (get-lisp-obj-address current-value) no-tls-value-marker) (funcall function current-value) (loop for start = (descriptor-sap *binding-stack-start*) for pointer = (descriptor-sap sb-vm::*binding-stack-pointer*) @@ -693,13 +743,11 @@ #+sb-thread (eq (sap-ref-word pointer (* n-word-bytes -1)) tls-index) #-sb-thread (eq (sap-ref-lispobj pointer (* n-word-bytes -1)) symbol) do (unless (or #+sb-thread - (= (sap-ref-word pointer (* n-word-bytes -2)) - no-tls-value-marker-widetag)) + (= (sap-ref-word pointer (* n-word-bytes -2)) no-tls-value-marker)) (funcall function (sap-ref-lispobj pointer (* n-word-bytes -2)))))))) -#+c-stack-is-control-stack (defun find-saved-fp-and-pc (fp) (block nil (walk-binding-stack @@ -719,6 +767,7 @@ (sap-ref-sap saved-fp (sb-vm::frame-byte-offset return-pc-save-offset))))))))))) +) ; end PROGN (defun return-pc-offset-for-location (debug-fun location) (declare (ignorable debug-fun location)) @@ -735,7 +784,7 @@ (bogus-debug-fun ;; No handy backend (or compiler) defined constant for this one, ;; so construct it here and now. - (sb-c:make-sc+offset control-stack-sc-number lra-save-offset)))) + (sb-c:make-sc+offset control-stack-sc-number #-riscv lra-save-offset #+riscv sb-vm::ra-save-offset)))) (defun old-fp-offset-for-location (debug-fun location) (declare (ignorable debug-fun location)) @@ -822,7 +871,7 @@ ;;; Note: Sometimes LRA is actually a fixnum. This happens when lisp ;;; calls into C. In this case, the code object is stored on the stack ;;; after the LRA, and the LRA is the word offset. -#-(or x86 x86-64) +#-(or x86 x86-64 arm64 riscv) (defun compute-calling-frame (caller lra up-frame &optional savedp) (declare (type system-area-pointer caller) (ignore savedp)) @@ -845,7 +894,7 @@ (if code (values code (* (1+ (- word-offset (code-header-words code))) - sb-vm:n-word-bytes) + n-word-bytes) nil) (values :foreign-function 0 @@ -874,7 +923,42 @@ escaped) (if up-frame (1+ (frame-number up-frame)) 0) escaped)))))) - +#+(or arm64 riscv) +(defun compute-calling-frame (caller ra up-frame &optional savedp) + (declare (type system-area-pointer caller) + (ignore savedp)) + (when (control-stack-pointer-valid-p caller) + (multiple-value-bind (code pc-offset escaped) + (if ra + (let* ((ra-sap (int-sap (ash ra n-fixnum-tag-bits))) + (code (code-header-from-pc ra-sap))) + (values code + (if code + (sap- ra-sap (code-instructions code)) + 0))) + (find-escaped-frame caller)) + (if (and (code-component-p code) + (eq (%code-debug-info code) :bpt-lra)) + (let ((real-lra (code-header-ref code real-lra-slot))) + (compute-calling-frame caller real-lra up-frame)) + (let ((d-fun (case code + (:undefined-function + (make-bogus-debug-fun + "undefined function")) + (:foreign-function + (make-bogus-debug-fun + (foreign-function-backtrace-name + (int-sap (get-lisp-obj-address ra))))) + ((nil) + (make-bogus-debug-fun + "bogus stack frame")) + (t + (debug-fun-from-pc code pc-offset escaped))))) + (make-compiled-frame caller up-frame d-fun + (code-location-from-pc d-fun pc-offset + escaped) + (if up-frame (1+ (frame-number up-frame)) 0) + escaped)))))) #+(or x86 x86-64) (defun compute-calling-frame (caller ra up-frame &optional savedp) (declare (type system-area-pointer caller ra)) @@ -924,27 +1008,13 @@ (defun nth-interrupt-context (n) (declare (muffle-conditions compiler-note)) - (declare (type (mod #.(- sb-vm:max-interrupts sb-vm::thread-header-slots)) n) + (declare (type (mod #.max-interrupts) n) (optimize (speed 3) (safety 0))) - (let* ((n (- -1 (+ sb-vm::thread-header-slots n) - #+sb-safepoint - ;; the C safepoint page - (/ sb-c:+backend-page-bytes+ n-word-bytes))) - (context-pointer - ;; The Alpha code is quite possibly wrong; I have no idea. - (sb-vm::current-thread-offset-sap - #-alpha n - #+alpha (* 2 n)))) - (sb-alien:sap-alien context-pointer (* os-context-t)))) - -;;; With :LINKAGE-TABLE symbols which come from the runtime go through -;;; an indirection table, but the debugger needs to know the actual -;;; address. -(defun static-foreign-symbol-address (name) - #+linkage-table - (find-dynamic-foreign-symbol-address name) - #-linkage-table - (foreign-symbol-address name)) + (let ((tls-words (ash (sb-alien:extern-alien "dynamic_values_bytes" + (sb-alien:unsigned 32)) + (- word-shift)))) + (sb-alien:sap-alien (sb-vm::current-thread-offset-sap (+ tls-words n)) + (* os-context-t)))) (defun catch-runaway-unwind (block) (declare (ignorable block)) @@ -1000,8 +1070,7 @@ (unless (control-stack-pointer-valid-p cfp) (return (values nil nil nil t))) (when (sap= frame-pointer cfp) - (without-gcing - (/noshow0 "in WITHOUT-GCING") + (with-code-pages-pinned (:dynamic) (return (escaped-frame-from-context context))))))) #+(or x86 x86-64) @@ -1058,8 +1127,10 @@ (sap-int (context-pc context)) code (%code-entry-point code 0) - #-(or arm arm64) + #-(or riscv arm arm64) (context-register context sb-vm::lra-offset) + #+riscv + (context-register context sb-vm::ra-offset) #+(or arm arm64) (stack-ref (int-sap (context-register context sb-vm::cfp-offset)) @@ -1085,22 +1156,21 @@ For some architectures (such as PPC) this will not be the $LRA register." (with-pinned-objects (code) (let ((return-machine-address (sb-vm::return-machine-address scp)) - (code-header-len (* (code-header-words code) sb-vm:n-word-bytes))) + (code-header-len (* (code-header-words code) n-word-bytes))) (values (- return-machine-address - (- (get-lisp-obj-address code) - sb-vm:other-pointer-lowtag) + (- (get-lisp-obj-address code) other-pointer-lowtag) code-header-len) return-machine-address)))) ;;; Find the code object corresponding to the object represented by ;;; bits and return it. We assume bogus functions correspond to the ;;; undefined-function. -#+(or x86 x86-64) +#+(or x86 x86-64 arm64) (defun code-object-from-context (context) (declare (type (sb-alien:alien (* os-context-t)) context)) (code-header-from-pc (context-pc context))) -#-(or x86 x86-64) +#-(or x86 x86-64 arm64) (defun code-object-from-context (context) (declare (type (sb-alien:alien (* os-context-t)) context)) ;; The GC constraint on the program counter on precisely-scavenged @@ -1135,6 +1205,7 @@ register." (let ((widetag (widetag-of object))) (cond ((= widetag code-header-widetag) object) + #-riscv ((= widetag return-pc-widetag) (lra-code-header object)) ((= widetag simple-fun-widetag) @@ -1150,9 +1221,9 @@ register." (normalize-candidate #+ppc64 (let ((code (context-register context sb-vm::code-offset))) - (%make-lisp-obj (if (logtest sb-vm:lowtag-mask code) + (%make-lisp-obj (if (logtest lowtag-mask code) code - (logior code sb-vm:other-pointer-lowtag)))) + (logior code other-pointer-lowtag)))) #-ppc64 (boxed-context-register context sb-vm::code-offset))) (let ((candidate @@ -1201,8 +1272,8 @@ register." (etypecase info (sb-c::compiled-debug-info (make-compiled-debug-fun (compiled-debug-fun-from-pc info pc escaped) component)) - (cons ; interrupted in an assembler routine - (let ((routine (dohash ((name pc-range) (car info)) + (hash-table ; interrupted in an assembler routine + (let ((routine (dohash ((name pc-range) info) (when (<= (car pc-range) pc (cadr pc-range)) (return name))))) (make-bogus-debug-fun (cond ((not routine) @@ -1243,7 +1314,7 @@ register." (fp (frame-pointer frame))) (labels ((catch-ref (slot) (sap-ref-lispobj catch (* slot n-word-bytes))) - #-(or x86 x86-64) + #-(or x86 x86-64 arm64 riscv) (catch-entry-offset () (let* ((lra (catch-ref catch-block-entry-pc-slot)) (component (catch-ref catch-block-code-slot)) @@ -1253,12 +1324,15 @@ register." (* (- (1+ (get-header-data lra)) (code-header-words component)) n-word-bytes))) - #+(or x86 x86-64) + #+(or x86 x86-64 arm64 riscv) (catch-entry-offset () (let* ((ra (sap-ref-sap catch (* catch-block-entry-pc-slot n-word-bytes))) - (component (code-header-from-pc ra))) + (component #+riscv + (catch-ref catch-block-code-slot) + #+(or x86 x86-64 arm64) + (code-header-from-pc ra))) (- (sap-int ra) (- (get-lisp-obj-address component) other-pointer-lowtag) @@ -1343,7 +1417,7 @@ register." (let* ((fun (%fun-fun function)) (code (fun-code-header fun))) (- (%fun-code-offset fun) - (* (code-header-words code) sb-vm:n-word-bytes)))) + (* (code-header-words code) n-word-bytes)))) ;;; Return the object of type FUNCTION associated with the DEBUG-FUN, ;;; or NIL if the function is unavailable or is non-existent as a user @@ -1428,31 +1502,34 @@ register." (sub-access-debug-var-slot (frame-pointer frame) it))))))) ;;; Return a DEBUG-FUN that represents debug information for FUN. -(defun fun-debug-fun (fun) +(defun fun-debug-fun (fun &key local-name) (declare (type function fun)) (let ((simple-fun (%fun-fun fun))) - (let* ((name (%simple-fun-name simple-fun)) + (let* ((name (or local-name (%simple-fun-name simple-fun))) (component (fun-code-header simple-fun)) (res (loop for fmap-entry = (sb-c::compiled-debug-info-fun-map (%code-debug-info component)) then next for next = (sb-c::compiled-debug-fun-next fmap-entry) - when (and (eq (sb-c::compiled-debug-fun-name fmap-entry) name) + ;; Is NAME really the right thing to match on given how bogus + ;; it might be? I would think PC range is better. + when (and (equal (sb-c::compiled-debug-fun-name fmap-entry) name) (eq (sb-c::compiled-debug-fun-kind fmap-entry) nil)) return fmap-entry while next))) - (if res - (make-compiled-debug-fun res component) - ;; KLUDGE: comment from CMU CL: - ;; This used to be the non-interpreted branch, but - ;; William wrote it to return the debug-fun of fun's XEP - ;; instead of fun's debug-fun. The above code does this - ;; more correctly, but it doesn't get or eliminate all - ;; appropriate cases. It mostly works, and probably - ;; works for all named functions anyway. - ;; -- WHN 20000120 - (debug-fun-from-pc component - (function-start-pc-offset simple-fun)))))) + (cond (res + (make-compiled-debug-fun res component)) + ((null local-name) + ;; KLUDGE: comment from CMU CL: + ;; This used to be the non-interpreted branch, but + ;; William wrote it to return the debug-fun of fun's XEP + ;; instead of fun's debug-fun. The above code does this + ;; more correctly, but it doesn't get or eliminate all + ;; appropriate cases. It mostly works, and probably + ;; works for all named functions anyway. + ;; -- WHN 20000120 + (debug-fun-from-pc component + (function-start-pc-offset simple-fun))))))) ;;; Return the kind of the function, which is one of :OPTIONAL, :MORE ;;; :EXTERNAL, :TOPLEVEL, :CLEANUP, or NIL. @@ -1479,7 +1556,7 @@ register." (defun debug-fun-symbol-vars (debug-fun symbol) (let ((vars (ambiguous-debug-vars debug-fun (symbol-name symbol))) (package (and (sb-xc:symbol-package symbol) - (package-name (sb-xc:symbol-package symbol))))) + (sb-xc:package-name (sb-xc:symbol-package symbol))))) (delete-if (if (stringp package) (lambda (var) (let ((p (debug-var-package-name var))) @@ -1646,47 +1723,48 @@ register." :deleted (compact-vector-ref vars index-or-deleted)))) (loop - :while (< i len) - :for ele = (compact-vector-ref args i) :do - (cond - ((eq ele sb-c::debug-info-var-optional) - (setf optionalp t)) - ((eq ele sb-c::debug-info-var-rest) - (push-var '(:rest) 1)) - ;; The next two args are the &MORE arg context and - ;; count. - ((eq ele sb-c::debug-info-var-more) - (push-var '(:more) 2)) - ;; SUPPLIED-P var immediately following keyword or - ;; optional. Stick the extra var in the result element - ;; representing the keyword or optional, which is the - ;; previous one. - ((eq ele sb-c::debug-info-var-supplied-p) - (push-var (pop result) 1)) - ;; The keyword of a keyword parameter. Store it so the next - ;; element can be used to form a (:keyword KEYWORD VALUE) - ;; entry. - ((typep ele 'symbol) - (setf keyword ele)) - ;; The previous element was the keyword of a keyword - ;; parameter and is stored in KEYWORD. The current element - ;; is the index of the value (or a deleted - ;; marker). Construct and push the complete entry. - (keyword - (push-var (list :keyword keyword (var-or-deleted ele)))) - ;; We saw an optional marker, so the following non-symbols - ;; are indexes (or deleted markers) indicating optional - ;; variables. - (optionalp - (push-var (list :optional (var-or-deleted ele)))) - ;; Deleted required, optional or keyword argument. - ((eq ele sb-c::debug-info-var-deleted) - (push-var :deleted)) - ;; Required arg at beginning of args array. - (t - (push-var (compact-vector-ref vars ele)))) - (incf i) - :finally (return (nreverse result)))))) + while (< i len) + do + (let ((ele (compact-vector-ref args i))) + (cond + ((eq ele sb-c::debug-info-var-optional) + (setf optionalp t)) + ((eq ele sb-c::debug-info-var-rest) + (push-var '(:rest) 1)) + ;; The next two args are the &MORE arg context and + ;; count. + ((eq ele sb-c::debug-info-var-more) + (push-var '(:more) 2)) + ;; SUPPLIED-P var immediately following keyword or + ;; optional. Stick the extra var in the result element + ;; representing the keyword or optional, which is the + ;; previous one. + ((eq ele sb-c::debug-info-var-supplied-p) + (push-var (pop result) 1)) + ;; The keyword of a keyword parameter. Store it so the next + ;; element can be used to form a (:keyword KEYWORD VALUE) + ;; entry. + ((typep ele 'symbol) + (setf keyword ele)) + ;; The previous element was the keyword of a keyword + ;; parameter and is stored in KEYWORD. The current element + ;; is the index of the value (or a deleted + ;; marker). Construct and push the complete entry. + (keyword + (push-var (list :keyword keyword (var-or-deleted ele)))) + ;; We saw an optional marker, so the following non-symbols + ;; are indexes (or deleted markers) indicating optional + ;; variables. + (optionalp + (push-var (list :optional (var-or-deleted ele)))) + ;; Deleted required, optional or keyword argument. + ((eq ele sb-c::debug-info-var-deleted) + (push-var :deleted)) + ;; Required arg at beginning of args array. + (t + (push-var (compact-vector-ref vars ele)))) + (incf i)) + finally (return (nreverse result)))))) ;;; This is used in COMPILED-DEBUG-FUN-LAMBDA-LIST. (defun compiled-debug-fun-lambda-list-var (args i vars) @@ -1739,6 +1817,7 @@ register." ;; element size of the packed binary representation of the ;; blocks data. (live-set-len (ceiling var-count 8)) + (tlf-number (sb-c::compiled-debug-fun-tlf-number compiler-debug-fun)) (elsewhere-pc (sb-c::compiled-debug-fun-elsewhere-pc compiler-debug-fun)) elsewhere-p (len (length blocks)) @@ -1767,6 +1846,8 @@ register." (ldb (byte 3 0) flags))) (pc (+ last-pc (sb-c:read-var-integerf blocks i))) + (tlf-offset (or tlf-number + (sb-c::read-var-integerf blocks i))) (equal-live (logtest sb-c::compiled-code-location-equal-live flags)) (form-number (cond ((logtest sb-c::compiled-code-location-zero-form-number flags) @@ -1800,7 +1881,7 @@ register." (setf elsewhere-p t))) (new-block)) (push (make-known-code-location - pc debug-fun block + pc debug-fun block tlf-offset form-number live-set kind step-info context) locations) @@ -1875,7 +1956,7 @@ register." prev-name) (t (geti)))) ;; Keep the condition in sync with DUMP-1-VAR - (large-fixnums (>= (integer-length sb-xc:most-positive-fixnum) 62)) + (large-fixnums (>= (integer-length most-positive-fixnum) 62)) (sc+offset (if deleted 0 (if large-fixnums (ldb (byte 27 8) flags) (geti)))) (save-sc+offset (and save @@ -1992,9 +2073,22 @@ register." ;;; compilation unit is not necessarily a single file, see the section ;;; on debug-sources.) (defun code-location-toplevel-form-offset (code-location) - (let ((di (compiled-debug-fun-debug-info - (code-location-debug-fun code-location)))) - (sb-c::compiled-debug-info-tlf-number di))) + (when (code-location-unknown-p code-location) + (error 'unknown-code-location :code-location code-location)) + (let ((tlf-offset (code-location-%tlf-offset code-location))) + (cond ((eq tlf-offset :unparsed) + (etypecase code-location + (compiled-code-location + (unless (fill-in-code-location code-location) + ;; This check should be unnecessary. We're missing + ;; debug info the compiler should have dumped. + (bug "unknown code location")) + (code-location-%tlf-offset code-location)) + ;; (There used to be more cases back before sbcl-0.7.0,, + ;; when we did special tricks to debug the IR1 + ;; interpreter.) + )) + (t tlf-offset)))) ;;; Return the number of the form corresponding to CODE-LOCATION. The ;;; form number is derived by a walking the subforms of a top level @@ -2134,6 +2228,8 @@ register." (when found (setf (code-location-%debug-block code-location) (code-location-%debug-block found)) + (setf (code-location-%tlf-offset code-location) + (code-location-%tlf-offset found)) (setf (code-location-%form-number code-location) (code-location-%form-number found)) (setf (compiled-code-location-%live-set code-location) @@ -2192,7 +2288,7 @@ register." ;;; be acceptable to have NIL returned, or that it's only called on ;;; DEBUG-VARs whose symbols have non-NIL packages. (defun debug-var-package-name (debug-var) - (package-name (sb-xc:symbol-package (debug-var-symbol debug-var)))) + (sb-xc:package-name (sb-xc:symbol-package (debug-var-symbol debug-var)))) ;;; Return the value stored for DEBUG-VAR in frame, or if the value is ;;; not :VALID, then signal an INVALID-VALUE error. @@ -2288,15 +2384,15 @@ register." (defun make-lisp-obj (val &optional (errorp t)) (if (or ;; fixnum - (zerop (logand val sb-vm:fixnum-tag-mask)) + (zerop (logand val fixnum-tag-mask)) ;; immediate single float, 64-bit only #+64-bit - (= (logand val #xff) sb-vm:single-float-widetag) + (= (logand val #xff) single-float-widetag) ;; character (and (zerop (logandc2 val #x1fffffff)) ; Top bits zero - (= (logand val #xff) sb-vm:character-widetag)) ; char tag + (= (logand val #xff) character-widetag)) ; char tag ;; unbound marker - (= val sb-vm:unbound-marker-widetag)) + (= val unbound-marker-widetag)) (values (%make-lisp-obj val) t) ;; To mitigate the danger of GC running in between testing pointer ;; validity and returning the object, we must pin a potentially @@ -2328,8 +2424,7 @@ register." ;; highlight its brokenness. (macrolet ((with-escaped-value ((var) &body forms) `(if escaped - (let ((,var (sb-vm:context-register - escaped + (let ((,var (context-register escaped (sb-c:sc+offset-offset sc+offset)))) ,@forms) :invalid-value-for-unescaped-register-storage)) @@ -2341,8 +2436,7 @@ register." :invalid-value-for-unescaped-register-storage)) (escaped-float-value (format) `(if escaped - (sb-vm:context-float-register - escaped + (context-float-register escaped (sb-c:sc+offset-offset sc+offset) ',format) :invalid-value-for-unescaped-register-storage)) (with-nfp ((var) &body body) @@ -2354,108 +2448,168 @@ register." #-c-stack-is-control-stack `(let ((,var (if escaped (int-sap - (sb-vm:context-register escaped - sb-vm::nfp-offset)) - #-alpha - (sap-ref-sap fp (* nfp-save-offset - sb-vm:n-word-bytes)) - #+alpha - (sb-vm::make-number-stack-pointer - (sap-ref-32 fp (* nfp-save-offset - sb-vm:n-word-bytes)))))) + (context-register escaped sb-vm::nfp-offset)) + (sap-ref-sap fp (* nfp-save-offset n-word-bytes))))) ,@body)) (number-stack-offset (&optional (offset 0)) #+(or x86 x86-64) `(+ (sb-vm::frame-byte-offset (sb-c:sc+offset-offset sc+offset)) ,offset) #-(or x86 x86-64) - `(+ (* (sb-c:sc+offset-offset sc+offset) sb-vm:n-word-bytes) + `(+ (* (sb-c:sc+offset-offset sc+offset) n-word-bytes) ,offset))) (ecase (sb-c:sc+offset-scn sc+offset) - ((#.sb-vm:any-reg-sc-number - #.sb-vm:descriptor-reg-sc-number) + ((#.any-reg-sc-number + #.descriptor-reg-sc-number) (escaped-boxed-value)) - (#.sb-vm:character-reg-sc-number + (#.character-reg-sc-number (with-escaped-value (val) (code-char val))) - (#.sb-vm:sap-reg-sc-number + (#.sap-reg-sc-number (with-escaped-value (val) (int-sap val))) - (#.sb-vm:signed-reg-sc-number + (#.signed-reg-sc-number (with-escaped-value (val) - (if (logbitp (1- sb-vm:n-word-bits) val) - (logior val (ash -1 sb-vm:n-word-bits)) + (if (logbitp (1- n-word-bits) val) + (logior val (ash -1 n-word-bits)) val))) - (#.sb-vm:unsigned-reg-sc-number + (#.unsigned-reg-sc-number (with-escaped-value (val) val)) #-(or x86 x86-64) - (#.sb-vm:non-descriptor-reg-sc-number + (#.non-descriptor-reg-sc-number (error "Local non-descriptor register access?")) - #-(or x86 x86-64) - (#.sb-vm:interior-reg-sc-number + #-(or x86 x86-64 arm64) + (#.interior-reg-sc-number (error "Local interior register access?")) - (#.sb-vm:single-reg-sc-number + #+sb-simd-pack + ((#.sb-vm::sse-reg-sc-number #.sb-vm::int-sse-reg-sc-number) + (escaped-float-value simd-pack-int)) + #+sb-simd-pack + ((#.sb-vm::single-sse-reg-sc-number) + (escaped-float-value simd-pack-single)) + #+sb-simd-pack + ((#.sb-vm::double-sse-reg-sc-number) + (escaped-float-value simd-pack-double)) + #+sb-simd-pack + ((#.sb-vm::int-sse-stack-sc-number) + (with-nfp (nfp) + (%make-simd-pack-ub64 + (sap-ref-64 nfp (number-stack-offset 0)) + (sap-ref-64 nfp (number-stack-offset 8))))) + #+sb-simd-pack + ((#.sb-vm::single-sse-stack-sc-number) + (with-nfp (nfp) + (%make-simd-pack-single + (sap-ref-single nfp (number-stack-offset 0)) + (sap-ref-single nfp (number-stack-offset 4)) + (sap-ref-single nfp (number-stack-offset 8)) + (sap-ref-single nfp (number-stack-offset 12))))) + #+sb-simd-pack + ((#.sb-vm::double-sse-stack-sc-number) + (with-nfp (nfp) + (%make-simd-pack-double + (sap-ref-double nfp (number-stack-offset 0)) + (sap-ref-double nfp (number-stack-offset 8))))) + #+sb-simd-pack-256 + ((#.sb-vm::ymm-reg-sc-number #.sb-vm::int-avx2-reg-sc-number) + (escaped-float-value simd-pack-256-int)) + #+sb-simd-pack-256 + ((#.sb-vm::single-avx2-reg-sc-number) + (escaped-float-value simd-pack-256-single)) + #+sb-simd-pack-256 + ((#.sb-vm::double-avx2-reg-sc-number) + (escaped-float-value simd-pack-256-double)) + #+sb-simd-pack-256 + ((#.sb-vm::int-avx2-stack-sc-number) + (with-nfp (nfp) + (%make-simd-pack-256-ub64 + (sap-ref-64 nfp (number-stack-offset 0)) + (sap-ref-64 nfp (number-stack-offset 8)) + (sap-ref-64 nfp (number-stack-offset 16)) + (sap-ref-64 nfp (number-stack-offset 24))))) + #+sb-simd-pack-256 + ((#.sb-vm::single-avx2-stack-sc-number) + (with-nfp (nfp) + (%make-simd-pack-256-single + (sap-ref-single nfp (number-stack-offset 0)) + (sap-ref-single nfp (number-stack-offset 4)) + (sap-ref-single nfp (number-stack-offset 8)) + (sap-ref-single nfp (number-stack-offset 12)) + (sap-ref-single nfp (number-stack-offset 16)) + (sap-ref-single nfp (number-stack-offset 20)) + (sap-ref-single nfp (number-stack-offset 24)) + (sap-ref-single nfp (number-stack-offset 28))))) + #+sb-simd-pack-256 + ((#.sb-vm::double-avx2-stack-sc-number) + (with-nfp (nfp) + (%make-simd-pack-256-double + (sap-ref-double nfp (number-stack-offset 0)) + (sap-ref-double nfp (number-stack-offset 8)) + (sap-ref-double nfp (number-stack-offset 16)) + (sap-ref-double nfp (number-stack-offset 24))))) + (#.single-reg-sc-number (escaped-float-value single-float)) - (#.sb-vm:double-reg-sc-number + (#.double-reg-sc-number (escaped-float-value double-float)) #+long-float - (#.sb-vm:long-reg-sc-number + (#.long-reg-sc-number (escaped-float-value long-float)) - (#.sb-vm:complex-single-reg-sc-number + (#.complex-single-reg-sc-number (escaped-float-value complex-single-float)) - (#.sb-vm:complex-double-reg-sc-number + (#.complex-double-reg-sc-number (escaped-float-value complex-double-float)) #+long-float - (#.sb-vm:complex-long-reg-sc-number + (#.complex-long-reg-sc-number (escaped-float-value sb-kernel::complex-long-float)) - (#.sb-vm:single-stack-sc-number + (#.single-stack-sc-number (with-nfp (nfp) (sap-ref-single nfp (number-stack-offset)))) - (#.sb-vm:double-stack-sc-number + (#.double-stack-sc-number (with-nfp (nfp) (sap-ref-double nfp (number-stack-offset)))) #+long-float - (#.sb-vm:long-stack-sc-number + (#.long-stack-sc-number (with-nfp (nfp) (sap-ref-long nfp (number-stack-offset)))) - (#.sb-vm:complex-single-stack-sc-number + (#.complex-single-stack-sc-number (with-nfp (nfp) (complex (sap-ref-single nfp (number-stack-offset)) (sap-ref-single nfp (number-stack-offset 4))))) - (#.sb-vm:complex-double-stack-sc-number + (#.complex-double-stack-sc-number (with-nfp (nfp) (complex (sap-ref-double nfp (number-stack-offset)) (sap-ref-double nfp (number-stack-offset 8))))) #+long-float - (#.sb-vm:complex-long-stack-sc-number + (#.complex-long-stack-sc-number (with-nfp (nfp) (complex (sap-ref-long nfp (number-stack-offset)) (sap-ref-long nfp (number-stack-offset #+sparc 4 #+(or x86 x86-64) 3))))) - (#.sb-vm:control-stack-sc-number + (#.control-stack-sc-number (stack-ref fp (sb-c:sc+offset-offset sc+offset))) - (#.sb-vm:character-stack-sc-number + (#.character-stack-sc-number (with-nfp (nfp) (code-char (sap-ref-word nfp (number-stack-offset))))) - (#.sb-vm:unsigned-stack-sc-number + (#.unsigned-stack-sc-number (with-nfp (nfp) (sap-ref-word nfp (number-stack-offset)))) - (#.sb-vm:signed-stack-sc-number + (#.signed-stack-sc-number (with-nfp (nfp) (signed-sap-ref-word nfp (number-stack-offset)))) - (#.sb-vm:sap-stack-sc-number + (#.sap-stack-sc-number (with-nfp (nfp) (sap-ref-sap nfp (number-stack-offset)))) (#.constant-sc-number (if escaped - (code-header-ref - (code-header-from-pc (sb-vm:context-pc escaped)) - (sb-c:sc+offset-offset sc+offset)) + (let ((code (code-header-from-pc (context-pc escaped)))) + (if code + (code-header-ref code (sb-c:sc+offset-offset sc+offset)) + :invalid-code-object-at-pc)) :invalid-value-for-unescaped-register-storage)) (#.immediate-sc-number (sb-c:sc+offset-offset sc+offset))))) @@ -2464,7 +2618,7 @@ register." ;;; COMPILED-DEBUG-VAR case, access the current value to determine if ;;; it is an indirect value cell. This occurs when the variable is ;;; both closed over and set. -(defun %set-debug-var-value (debug-var frame new-value) +(defun (setf debug-var-value) (new-value debug-var frame) (aver (typep frame 'compiled-frame)) (let ((old-value (access-compiled-debug-var-slot debug-var frame))) (if (indirect-value-cell-p old-value) @@ -2506,8 +2660,7 @@ register." ;; systems. (macrolet ((set-escaped-value (val) `(if escaped - (setf (sb-vm:context-register - escaped + (setf (context-register escaped (sb-c:sc+offset-offset sc+offset)) ,val) value)) @@ -2520,8 +2673,7 @@ register." value)) (set-escaped-float-value (format val) `(if escaped - (setf (sb-vm:context-float-register - escaped + (setf (context-float-register escaped (sb-c:sc+offset-offset sc+offset) ',format) ,val) @@ -2534,73 +2686,129 @@ register." ,@body) #-c-stack-is-control-stack `(let ((,var (if escaped - (int-sap - (sb-vm:context-register escaped - sb-vm::nfp-offset)) - #-alpha - (sap-ref-sap fp - (* nfp-save-offset - sb-vm:n-word-bytes)) - #+alpha - (sb-vm::make-number-stack-pointer - (sap-ref-32 fp - (* nfp-save-offset - sb-vm:n-word-bytes)))))) + (int-sap (context-register escaped sb-vm::nfp-offset)) + (sap-ref-sap fp (* nfp-save-offset n-word-bytes))))) ,@body)) (number-stack-offset (&optional (offset 0)) #+(or x86 x86-64) `(+ (sb-vm::frame-byte-offset (sb-c:sc+offset-offset sc+offset)) ,offset) #-(or x86 x86-64) - `(+ (* (sb-c:sc+offset-offset sc+offset) sb-vm:n-word-bytes) + `(+ (* (sb-c:sc+offset-offset sc+offset) n-word-bytes) ,offset))) (ecase (sb-c:sc+offset-scn sc+offset) - ((#.sb-vm:any-reg-sc-number - #.sb-vm:descriptor-reg-sc-number) + ((#.any-reg-sc-number + #.descriptor-reg-sc-number) (set-escaped-boxed-value value)) - (#.sb-vm:character-reg-sc-number + (#.character-reg-sc-number (set-escaped-value (char-code value))) - (#.sb-vm:sap-reg-sc-number + (#.sap-reg-sc-number (set-escaped-value (sap-int value))) - (#.sb-vm:signed-reg-sc-number + (#.signed-reg-sc-number (set-escaped-value (logand value most-positive-word))) - (#.sb-vm:unsigned-reg-sc-number + (#.unsigned-reg-sc-number (set-escaped-value value)) #-(or x86 x86-64) - (#.sb-vm:non-descriptor-reg-sc-number + (#.non-descriptor-reg-sc-number (error "Local non-descriptor register access?")) - #-(or x86 x86-64) - (#.sb-vm:interior-reg-sc-number + #-(or x86 x86-64 arm64) + (#.interior-reg-sc-number (error "Local interior register access?")) - (#.sb-vm:single-reg-sc-number + #+sb-simd-pack + ((#.sb-vm::sse-reg-sc-number #.sb-vm::int-sse-reg-sc-number) + (set-escaped-float-value simd-pack-int value)) + #+sb-simd-pack + ((#.sb-vm::single-sse-reg-sc-number) + (set-escaped-float-value simd-pack-single value)) + #+sb-simd-pack + ((#.sb-vm::double-sse-reg-sc-number) + (set-escaped-float-value simd-pack-double value)) + #+sb-simd-pack + ((#.sb-vm::int-sse-stack-sc-number) + (multiple-value-bind (a b) (%simd-pack-ub64s value) + (with-nfp (nfp) + (setf (sap-ref-64 nfp (number-stack-offset 0)) a + (sap-ref-64 nfp (number-stack-offset 8)) b)))) + #+sb-simd-pack + ((#.sb-vm::single-sse-stack-sc-number) + (multiple-value-bind (a b c d) (%simd-pack-singles value) + (with-nfp (nfp) + (setf (sap-ref-single nfp (number-stack-offset 0)) a + (sap-ref-single nfp (number-stack-offset 4)) b + (sap-ref-single nfp (number-stack-offset 8)) c + (sap-ref-single nfp (number-stack-offset 12)) d)))) + #+sb-simd-pack + ((#.sb-vm::double-sse-stack-sc-number) + (multiple-value-bind (a b) (%simd-pack-doubles value) + (with-nfp (nfp) + (setf (sap-ref-double nfp (number-stack-offset 0)) a + (sap-ref-double nfp (number-stack-offset 8)) b)))) + #+sb-simd-pack-256 + ((#.sb-vm::ymm-reg-sc-number #.sb-vm::int-avx2-reg-sc-number) + (set-escaped-float-value simd-pack-256-int value)) + #+sb-simd-pack-256 + ((#.sb-vm::single-avx2-reg-sc-number) + (set-escaped-float-value simd-pack-256-single value)) + #+sb-simd-pack-256 + ((#.sb-vm::double-avx2-reg-sc-number) + (set-escaped-float-value simd-pack-256-double value)) + #+sb-simd-pack-256 + ((#.sb-vm::int-avx2-stack-sc-number) + (with-nfp (nfp) + (multiple-value-bind (a b c d) (%simd-pack-256-ub64s value) + (setf (sap-ref-64 nfp (number-stack-offset 0)) a + (sap-ref-64 nfp (number-stack-offset 8)) b + (sap-ref-64 nfp (number-stack-offset 16)) c + (sap-ref-64 nfp (number-stack-offset 24)) d)))) + #+sb-simd-pack-256 + ((#.sb-vm::single-avx2-stack-sc-number) + (multiple-value-bind (a b c d e f g h) (%simd-pack-256-singles value) + (with-nfp (nfp) + (setf (sap-ref-single nfp (number-stack-offset 0)) a + (sap-ref-single nfp (number-stack-offset 4)) b + (sap-ref-single nfp (number-stack-offset 8)) c + (sap-ref-single nfp (number-stack-offset 12)) d + (sap-ref-single nfp (number-stack-offset 16)) e + (sap-ref-single nfp (number-stack-offset 20)) f + (sap-ref-single nfp (number-stack-offset 24)) g + (sap-ref-single nfp (number-stack-offset 28)) h)))) + #+sb-simd-pack-256 + ((#.sb-vm::double-avx2-stack-sc-number) + (multiple-value-bind (a b c d) (%simd-pack-256-doubles value) + (with-nfp (nfp) + (setf (sap-ref-double nfp (number-stack-offset 0)) a + (sap-ref-double nfp (number-stack-offset 8)) b + (sap-ref-double nfp (number-stack-offset 16)) c + (sap-ref-double nfp (number-stack-offset 24)) d)))) + (#.single-reg-sc-number #-(or x86 x86-64) ;; don't have escaped floats. (set-escaped-float-value single-float value)) - (#.sb-vm:double-reg-sc-number + (#.double-reg-sc-number (set-escaped-float-value double-float value)) #+long-float - (#.sb-vm:long-reg-sc-number + (#.long-reg-sc-number (set-escaped-float-value long-float value)) - (#.sb-vm:complex-single-reg-sc-number + (#.complex-single-reg-sc-number (set-escaped-float-value complex-single-float value)) - (#.sb-vm:complex-double-reg-sc-number + (#.complex-double-reg-sc-number (set-escaped-float-value complex-double-float value)) #+long-float - (#.sb-vm:complex-long-reg-sc-number + (#.complex-long-reg-sc-number (set-escaped-float-value complex-long-float)) - (#.sb-vm:single-stack-sc-number + (#.single-stack-sc-number (with-nfp (nfp) (setf (sap-ref-single nfp (number-stack-offset)) (the single-float value)))) - (#.sb-vm:double-stack-sc-number + (#.double-stack-sc-number (with-nfp (nfp) (setf (sap-ref-double nfp (number-stack-offset)) (the double-float value)))) #+long-float - (#.sb-vm:long-stack-sc-number + (#.long-stack-sc-number (with-nfp (nfp) (setf (sap-ref-long nfp (number-stack-offset)) (the long-float value)))) - (#.sb-vm:complex-single-stack-sc-number + (#.complex-single-stack-sc-number (with-nfp (nfp) (setf (sap-ref-single nfp (number-stack-offset)) #+(or x86 x86-64) @@ -2612,7 +2820,7 @@ register." (imagpart (the (complex single-float) value)) #-(or x86 x86-64) (the single-float (realpart value))))) - (#.sb-vm:complex-double-stack-sc-number + (#.complex-double-stack-sc-number (with-nfp (nfp) (setf (sap-ref-double nfp (number-stack-offset)) #+(or x86 x86-64) @@ -2625,7 +2833,7 @@ register." #-(or x86 x86-64) (the double-float (realpart value))))) #+long-float - (#.sb-vm:complex-long-stack-sc-number + (#.complex-long-stack-sc-number (with-nfp (nfp) (setf (sap-ref-long nfp (number-stack-offset)) @@ -2640,20 +2848,21 @@ register." (imagpart (the (complex long-float) value)) #-(or x86 x86-64) (the long-float (realpart value))))) - (#.sb-vm:control-stack-sc-number - (setf (stack-ref fp (sb-c:sc+offset-offset sc+offset)) value)) - (#.sb-vm:character-stack-sc-number + (#.control-stack-sc-number + (%set-stack-ref fp (sb-c:sc+offset-offset sc+offset) value) + value) ; I doubt that the return value matters, but who knows ... + (#.character-stack-sc-number (with-nfp (nfp) (setf (sap-ref-word nfp (number-stack-offset 0)) (char-code (the character value))))) - (#.sb-vm:unsigned-stack-sc-number + (#.unsigned-stack-sc-number (with-nfp (nfp) (setf (sap-ref-word nfp (number-stack-offset 0)) (the word value)))) - (#.sb-vm:signed-stack-sc-number + (#.signed-stack-sc-number (with-nfp (nfp) (setf (signed-sap-ref-word nfp (number-stack-offset)) (the signed-word value)))) - (#.sb-vm:sap-stack-sc-number + (#.sap-stack-sc-number (with-nfp (nfp) (setf (sap-ref-sap nfp (number-stack-offset)) (the system-area-pointer value))))))) @@ -2663,7 +2872,7 @@ register." ;;; indirection cell. (defun indirect-value-cell-p (x) (and (%other-pointer-p x) - (eql (%other-pointer-widetag x) sb-vm:value-cell-widetag))) + (eql (%other-pointer-widetag x) value-cell-widetag))) ;;; Return three values reflecting the validity of DEBUG-VAR's value ;;; at BASIC-CODE-LOCATION: @@ -2846,27 +3055,36 @@ register." rt)) ;;; Locate the source file (if it still exists) and grab the top level -;;; form. If the file is modified, we use the top level form offset -;;; instead of the recorded character offset. +;;; form. If the file is modified, or if we are in the middle of +;;; loading the file (so that the start positions map is not available +;;; yet), we use the top level form offset instead of the recorded +;;; character offset. (defun get-file-toplevel-form (location) (let* ((d-source (code-location-debug-source location)) - (di (compiled-debug-fun-debug-info - (code-location-debug-fun location))) - (tlf-offset (sb-c::compiled-debug-info-tlf-number di)) - (char-offset (sb-c::compiled-debug-info-char-offset di)) - (namestring (debug-source-namestring d-source))) + (tlf-offset (code-location-toplevel-form-offset location)) + (start-positions (sb-di:debug-source-start-positions d-source)) + (namestring (debug-source-namestring d-source)) + (sbcl-source-p (eql (search "SYS:" namestring) 0))) ;; FIXME: External format? (with-open-file (f namestring :if-does-not-exist nil) (when f (let ((*readtable* (safe-readtable))) - (cond ((eql (debug-source-created d-source) (file-write-date f)) - (file-position f char-offset)) + (cond ((and (eql (debug-source-created d-source) (file-write-date f)) + start-positions) + (file-position f (aref start-positions tlf-offset))) (t + (when start-positions + (format *debug-io* + "~%; File has been modified since compilation:~%; ~A" + namestring)) (format *debug-io* - "~%; File has been modified since compilation:~%; ~A~@ - ; Using form offset instead of character position.~%" - namestring) - (let ((*read-suppress* t)) + "~%; Using form offset instead of character position.~%") + (let ((*read-suppress* t) + (*features* (if sbcl-source-p + (append *features* + '(:sb-xc) + (symbol-value 'sb-impl::+internal-features+)) + *features*))) (loop repeat tlf-offset do (read f))))) (read f)))))) @@ -3058,15 +3276,6 @@ register." ;; the DEBUG-FUN associated with this cookie (debug-fun nil :read-only t)) -;;; This maps bpt-lra objects to cookies, so that -;;; HANDLE-FUN-END-BREAKPOINT can find the appropriate cookie for the -;;; breakpoint hook. -;;; FIXME: assuming the preceding comment is correct, this seems an incredibly bad -;;; way to store the data. Why not just allocate an additional boxed slot in every -;;; bpt-lra object to store its cookies? Why use a hash table? -(define-load-time-global *fun-end-cookies* - (make-hash-table :test 'eq :synchronized t)) - ;;; This returns a hook function for the start helper breakpoint ;;; associated with a :FUN-END breakpoint. The returned function ;;; makes a fake LRA that all returns go through, and this piece of @@ -3080,16 +3289,16 @@ register." (lambda (frame breakpoint) (declare (ignore breakpoint) (type frame frame)) - (multiple-value-bind (lra component offset) + (multiple-value-bind (lra bpt-codeblob offset) (make-bpt-lra (frame-saved-lra frame debug-fun)) (setf (frame-saved-lra frame debug-fun) lra) (let ((end-bpts (breakpoint-%info starter-bpt))) - (let ((data (breakpoint-data component offset))) + (let ((data (breakpoint-data bpt-codeblob offset))) (setf (breakpoint-data-breakpoints data) end-bpts) (dolist (bpt end-bpts) (setf (breakpoint-internal-data bpt) data))) (let ((cookie (make-fun-end-cookie lra debug-fun))) - (setf (gethash component *fun-end-cookies*) cookie) + (setf (code-header-ref bpt-codeblob cookie-slot) cookie) (dolist (bpt end-bpts) (let ((fun (breakpoint-cookie-fun bpt))) (when fun (funcall fun frame cookie))))))))) @@ -3169,7 +3378,7 @@ register." :unknown-return-partner) (eq (compiled-code-location-kind loc) :single-value-return)) - sb-vm:single-value-return-byte-offset + single-value-return-byte-offset 0)))))) (defun activate-compiled-fun-start-breakpoint (breakpoint) @@ -3243,11 +3452,12 @@ register." ;;; is SETF'able. (defun breakpoint-info (breakpoint) (breakpoint-%info breakpoint)) -(defun %set-breakpoint-info (breakpoint value) +(defun (setf breakpoint-info) (value breakpoint) (setf (breakpoint-%info breakpoint) value) (let ((other (breakpoint-unknown-return-partner breakpoint))) (when other - (setf (breakpoint-%info other) value)))) + (setf (breakpoint-%info other) value))) + value) ;;;; BREAKPOINT-ACTIVE-P and DELETE-BREAKPOINT @@ -3305,6 +3515,11 @@ register." ;;;; breakpoint handlers (layer between C and exported interface) ;;; This maps components to a mapping of offsets to BREAKPOINT-DATAs. +;;; FIXME: these data should hang off of the component itself. +;;; We already have a thin wrapper on %CODE-DEBUG-INFO which allows it to +;;; hold both the compiler-generated metadata and the debugger's data. +;;; It might be preferable not to write to code if #+darwin-jit +;;; but I don't think so - the hash-table entails far more overhead. (define-load-time-global *component-breakpoint-offsets* (make-hash-table :test 'eq :synchronized t)) @@ -3418,12 +3633,12 @@ register." (defun signal-context-frame (signal-context) (let* ((scp (sb-alien:sap-alien signal-context (* os-context-t))) - (cfp (int-sap (sb-vm:context-register scp sb-vm::cfp-offset)))) + (cfp (int-sap (context-register scp sb-vm::cfp-offset)))) (compute-calling-frame cfp ;; KLUDGE: This argument is ignored on ;; x86oids in this scenario, but is ;; declared to be a SAP. - #+(or x86 x86-64) (sb-vm:context-pc scp) + #+(or x86 x86-64) (context-pc scp) #-(or x86 x86-64) nil nil))) @@ -3448,8 +3663,7 @@ register." (let* ((scp (sb-alien:sap-alien signal-context (* os-context-t))) (frame (signal-context-frame signal-context)) (component (breakpoint-data-component data)) - (cookie (gethash component *fun-end-cookies*))) - (remhash component *fun-end-cookies*) + (cookie (code-header-ref component cookie-slot))) (dolist (bpt breakpoints) (funcall (breakpoint-hook-fun bpt) frame bpt @@ -3457,10 +3671,11 @@ register." cookie)))) (defun get-fun-end-breakpoint-values (scp) - (let ((ocfp (int-sap (sb-vm:context-register + (let ((ocfp (int-sap (context-register scp #-(or x86 x86-64) sb-vm::ocfp-offset - #+(or x86 x86-64) sb-vm::ebx-offset))) + #+x86-64 sb-vm::rbx-offset + #+x86 sb-vm::ebx-offset))) (nargs (boxed-context-register scp sb-vm::nargs-offset)) (reg-arg-offsets '#.sb-vm::*register-arg-offsets*) (results nil)) @@ -3474,6 +3689,9 @@ register." ;;;; MAKE-BPT-LRA (used for :FUN-END breakpoints) +;;; FIXME: why does this imply that it makes an LRA when it actually makes +;;; a code blob? Despite the rename in git rev 2437d7f139 apparently I took a cue +;;; from the former name ("MAKE-BOGUS-LRA") as if that spoke the truth. ;;; Make a breakpoint LRA object that signals a breakpoint trap when returned to. ;;; If the breakpoint trap handler returns, REAL-LRA is returned to. ;;; Three values are returned: the new LRA object, the code component it is part of, @@ -3482,10 +3700,13 @@ register." ;;; state of the program, not merely a return PC location. ;;; (I tried changing this to DEFUN-CACHED, which failed a regression test) (defun make-bpt-lra (real-lra) - (declare (type #-(or x86 x86-64) lra #+(or x86 x86-64) system-area-pointer real-lra)) + (declare (type #-(or x86 x86-64 arm64 riscv) lra #+(or x86 x86-64 arm64 riscv) system-area-pointer real-lra)) + real-lra + #+arm64 (error "Breakpoints do not work on ARM64") + #+riscv (error "Breakpoints don't work on RISC-V") + #-(or arm64 riscv) (macrolet ((symbol-addr (name) - ;; "static" is not really correct if #+linkage-table - `(static-foreign-symbol-address ,name)) + `(find-foreign-symbol-address ,name)) (trap-offset () `(- (symbol-addr "fun_end_breakpoint_trap") src-start))) ;; These are really code labels, not variables: but this way we get @@ -3494,48 +3715,50 @@ register." (length (the index (- (symbol-addr "fun_end_breakpoint_end") src-start))) (code-object - (sb-c:allocate-code-object - nil 0 - ;; For non-x86: a single boxed constant holds the true LRA. - ;; For x86[-64]: one boxed constant holds the code object to which - ;; to return, and one holds the displacement into that object. - ;; Ensure required boxed header alignment. - (align-up (+ sb-vm:code-constants-offset 1 #+(or x86-64 x86) 1) - sb-c::code-boxed-words-align) - ;; 2 extra raw bytes represent CODE-N-ENTRIES (which is zero) - (+ length 2)))) + (sb-c:allocate-code-object + nil + ;; Ensure required boxed header alignment. + (align-up bpt-lra-boxed-nwords sb-c::code-boxed-words-align) + (+ length + n-word-bytes ; Jump Table prefix word + ;; Alignment padding, LRA header + #-(or x86 x86-64) (* 2 n-word-bytes) + ;; 2 extra raw bytes represent CODE-N-ENTRIES (which is zero) + 2)))) (setf (%code-debug-info code-object) :bpt-lra) (with-pinned-objects (code-object) - (system-area-ub8-copy (int-sap src-start) 0 - (code-instructions code-object) 0 length)) - #+(or x86 x86-64) - (multiple-value-bind (offset code) (compute-lra-data-from-pc real-lra) - (setf (code-header-ref code-object real-lra-slot) code - (code-header-ref code-object (1+ real-lra-slot)) offset) - ;; Holy hell, returning a SAP looks GC-unsafe, but it's sort of OK. - ;; It points into CODE-OBJECT which is implicitly pinned. - ;; WITHOUT-GCING which formerly enclosed this function was disingenuous - ;; because we escaped from its scope when returning the SAP. - (values (code-instructions code-object) code-object (trap-offset))) - #-(or x86 x86-64) - (progn - ;; We used to set the header value of the LRA here to the - ;; offset from the enclosing component to the LRA header, but - ;; MAKE-LISP-OBJ actually checks the value before we get a - ;; chance to set it, so it's now done in arch-assem.S. - ;; KLUDGE: The preceding concern is rendered irrelevant by - ;; use of unsafe %MAKE-LISP-OBJ, but we do still copy the lisp header - ;; from arch-assem.S which is horrible. Either that assembly code - ;; should be emitted as Lisp asm routine so that it has access to - ;; SB-VM:CODE-CONSTANTS-OFFSET, or we should emit the header. - ;; The issue is that the backpointer (word count) from the LRA to - ;; its containing code object has to be right. - (setf (code-header-ref code-object real-lra-slot) real-lra) - (values (with-pinned-objects (code-object) - (%make-lisp-obj (logior (sap-int (code-instructions code-object)) - sb-vm:other-pointer-lowtag))) - (sb-vm:sanctify-for-execution code-object) - (trap-offset)))))) + #+(or x86 x86-64 arm64) + (let ((instructions ; Don't touch the jump table prefix word + (sap+ (code-instructions code-object) n-word-bytes))) + (multiple-value-bind (offset code) (compute-lra-data-from-pc real-lra) + (setf (code-header-ref code-object real-lra-slot) code + (code-header-ref code-object (1+ real-lra-slot)) offset) + (system-area-ub8-copy (int-sap src-start) 0 instructions 0 length) + ;; CODE-OBJECT is implicitly pinned after leaving WITH-PINNED-OBJECTS + ;; (and would be pinned even if the W-P-O were deleted), so we're OK + ;; to return a SAP to the instructions. + ;; TRAP-OFFSET is the distance from CODE-INSTRUCTIONS to the trapping + ;; opcode, for which we have to account for the jump table prefix word. + (values instructions code-object (+ (trap-offset) n-word-bytes)))) + #-(or x86 x86-64 arm64) + (let* ((lra-header-addr + ;; Skip over the jump table prefix, and align properly for LRA header + (sap+ (code-instructions code-object) (* 2 n-word-bytes))) + ;; Compute the LRA->code backpointer in words + (delta (ash (sap- lra-header-addr + (int-sap (logandc2 (get-lisp-obj-address code-object) + lowtag-mask))) + (- word-shift)))) + (setf (code-header-ref code-object real-lra-slot) real-lra) + (setf (sap-ref-word lra-header-addr 0) + (logior (ash delta n-widetag-bits) return-pc-widetag)) + (system-area-ub8-copy (int-sap src-start) 0 + (sap+ lra-header-addr n-word-bytes) + 0 length) + (values (%make-lisp-obj (logior (sap-int lra-header-addr) other-pointer-lowtag)) + (sanctify-for-execution code-object) + ;; FIXME: what does "3" represent in this formula? + (+ (trap-offset) (* 3 n-word-bytes)))))))) ;;;; miscellaneous @@ -3619,6 +3842,10 @@ register." ;; something like GET-FDEFN-FOR-SINGLE-STEP (+ (sap-ref-32 (context-pc context) 1) -2 other-pointer-lowtag)) (t + #+ppc64 + (logior (context-register context callee-register-offset) + other-pointer-lowtag) + #-ppc64 (context-register context callee-register-offset))))) (step-info (single-step-info-from-context context))) ;; If there was not enough debug information available, there's no @@ -3682,6 +3909,9 @@ register." (sb-vm::incf-context-pc context 5)) (t (setf (context-register context callee-register-offset) + #+ppc64 + (logandc2 (get-lisp-obj-address new-callee) lowtag-mask) + #-ppc64 (get-lisp-obj-address new-callee)))))))) ;;; Given a signal context, fetch the step-info that's been stored in diff --git a/src/code/debug-var-io.lisp b/src/code/debug-var-io.lisp index ede135e025..b7b7d6e794 100644 --- a/src/code/debug-var-io.lisp +++ b/src/code/debug-var-io.lisp @@ -124,6 +124,27 @@ (defun integer-from-octets (octets) (declare (type (array (unsigned-byte 8) (*)) octets)) + #-sb-xc-host (aver (array-header-p octets)) + + ;; Bignums are little-endian by word, but native-endian within each word, + ;; making use of the less consy algorithm too tricky for big-endian CPUs. + ;; And this does not work for little-endian, but I don't know why. + ;; It should not be too hard to use random testing to find an input + ;; at which the output obviously differs from the shift+add loop. + #+nil + (let ((input (%array-data octets))) + (if (typep (%vector-raw-bits input 0) 'fixnum) + (%vector-raw-bits input 0) + (let* ((nbytes (length octets)) + (last-byte (if (plusp nbytes) (aref octets (1- nbytes)) 0)) + ;; If the high bit of the highest byte is 1, we might need one more + ;; byte to avoid the bignum coming out negative. + (nbits (* (+ nbytes (ash last-byte -7)) sb-vm:n-byte-bits)) + (ndigits (ceiling nbits sb-vm:n-word-bits)) + (bignum (sb-bignum:%allocate-bignum ndigits))) + (dotimes (i ndigits (sb-bignum::%normalize-bignum bignum ndigits)) + (setf (%bignum-ref bignum i) (%vector-raw-bits input i)))))) + (let ((result 0) (shift 0)) (dovector (byte octets result) (setf result (logior result (ash byte shift)) @@ -143,11 +164,13 @@ ;;; the code that could not be deduced by examining the object. ;;; It makes sense to store these externally to the object, as it would otherwise ;;; intrude on text pages. Also, some of the bignums are shareable this way. -(defun pack-code-fixup-locs (abs-fixups rel-fixups) - (let ((bytes (make-array (* 2 (+ (length abs-fixups) ; guess at final length - (length rel-fixups))) - :fill-pointer 0 :adjustable t - :element-type '(unsigned-byte 8)))) +(defun pack-code-fixup-locs (abs-fixups rel-fixups more) + (dx-let ((bytes (make-array (min (* 2 (+ (length abs-fixups) ; guess at final length + (length rel-fixups) + (length more))) + 1024) ; limit the stack usage + :fill-pointer 0 :adjustable t + :element-type '(unsigned-byte 8)))) (flet ((pack (list &aux (prev 0)) (dolist (x list) ;; two fixups at the same location have to be wrong, @@ -156,9 +179,12 @@ (write-var-integer (- x prev) bytes) (setq prev x)))) (pack (sort abs-fixups #'<)) - (when rel-fixups + (when (or rel-fixups more) + (write-var-integer 0 bytes) + (pack (sort rel-fixups #'<))) + (when more (write-var-integer 0 bytes) - (pack (sort rel-fixups #'<)))) + (pack (sort more #'<)))) ;; Stuff octets into an integer ;; It would be quite possible in the target to do something clever here ;; by creating a bignum directly from the ub8 vector. @@ -189,12 +215,14 @@ (let ((,loc (+ ,prev ,acc))) ,@body (setq ,prev ,loc)) (setq ,acc 0 ,shift 0)))))))) +;;; Unpack the (potentially) three stream of data in PACKED-INTEGER. (defun unpack-code-fixup-locs (packed-integer) - (collect ((abs-locs) (rel-locs)) + (collect ((stream1) (stream2) (stream3)) (let ((pos 0)) - (do-packed-varints (loc packed-integer pos) (abs-locs loc)) - (do-packed-varints (loc packed-integer pos) (rel-locs loc))) - (values (abs-locs) (rel-locs)))) + (do-packed-varints (loc packed-integer pos) (stream1 loc)) + (do-packed-varints (loc packed-integer pos) (stream2 loc)) + (do-packed-varints (loc packed-integer pos) (stream3 loc))) + (values (stream1) (stream2) (stream3)))) (define-symbol-macro lz-symbol-1 210) ; arbitrary value that isn't frequent in the input (define-symbol-macro lz-symbol-2 218) ; ditto @@ -210,7 +238,7 @@ lz-compress)) (defun lz-compress (input) (if (> (length input) +max-lz-size+) - (sb-xc:coerce input '(simple-array (unsigned-byte 8) (*))) + (coerce input '(simple-array (unsigned-byte 8) (*))) (let* ((length (length input)) (output (make-array length :element-type '(unsigned-byte 8) @@ -270,7 +298,7 @@ (mask-signed-field 8 (the (unsigned-byte 8) x))) input) #+sb-xc-host - (sb-xc:coerce output '(simple-array (unsigned-byte 8) (*))) + (coerce output '(simple-array (unsigned-byte 8) (*))) #-sb-xc-host (%shrink-vector (%array-data output) (fill-pointer output))))) #+(or) diff --git a/src/code/debug.lisp b/src/code/debug.lisp index 57797151d4..5eda12adfb 100644 --- a/src/code/debug.lisp +++ b/src/code/debug.lisp @@ -62,7 +62,7 @@ provide bindings for printer control variables.") ;;; If this is bound before the debugger is invoked, it is used as the stack ;;; top by the debugger. It can either be the first interesting frame, or the ;;; name of the last uninteresting frame. -(defparameter *stack-top-hint* nil) ; initialized by genesis +(defvar *stack-top-hint* nil) (defvar *current-frame* nil) (declaim (always-bound *stack-top-hint* *current-frame*)) @@ -147,7 +147,7 @@ Other commands: deeply nested input syntax, and now the reader is confused.)") (defmacro with-debug-io-syntax (() &body body) - (let ((thunk (sb-xc:gensym "THUNK"))) + (let ((thunk (gensym "THUNK"))) `(dx-flet ((,thunk () ,@body)) (funcall-with-debug-io-syntax #',thunk)))) @@ -465,11 +465,19 @@ information." (< a (get-lisp-obj-address sb-vm:*control-stack-end*))) sb-thread:*current-thread*) (all-threads - ;; find a stack whose base is nearest and below A. - (awhen (sb-thread::avl-find<= a sb-thread::*all-threads*) - (let ((thread (sb-thread::avlnode-data it))) - (when (< a (sb-thread::thread-stack-end thread)) - thread)))))))) + (macrolet ((in-stack-range-p () + `(and (>= a (sb-thread::thread-control-stack-start thread)) + (< a (sb-thread::thread-control-stack-end thread))))) + #+win32 ; exhaustive search + (dolist (thread (sb-thread:list-all-threads)) ; conses, but I don't care + (when (in-stack-range-p) + (return thread))) + #-win32 + ;; find a stack whose primitive-thread is nearest and above A. + (awhen (sb-thread::avl-find>= a sb-thread::*all-threads*) + (let ((thread (sb-thread::avlnode-data it))) + (when (in-stack-range-p) + thread))))))))) ;;;; frame printing @@ -673,7 +681,7 @@ the current thread are replaced with dummy objects which can safely escape." (defun ensure-printable-object (object) (handler-case - (with-open-stream (out (make-broadcast-stream)) + (with-open-stream (out sb-impl::*null-broadcast-stream*) (prin1 object out) object) (error (cond) @@ -910,11 +918,19 @@ the current thread are replaced with dummy objects which can safely escape." ;; until bug 403 is fixed, PPRINT-LOGICAL-BLOCK (STREAM NIL) is ;; definitely preferred, because the FORMAT alternative was acting odd. (pprint-logical-block (stream nil) + #-sb-thread + (format stream "debugger invoked on a ~S: ~2I~_~A" (type-of condition) condition) + #+sb-thread (format stream - "debugger invoked on a ~S~@[ in thread ~_~A~]: ~2I~_~A" + "debugger invoked on a ~S~@[ @~x~] in thread ~_~A: ~2I~_~A" (type-of condition) - #+sb-thread sb-thread:*current-thread* - #-sb-thread nil + (when (boundp '*current-internal-error-context*) + (if (system-area-pointer-p *current-internal-error-context*) + (sb-alien:with-alien ((context (* os-context-t) + sb-kernel:*current-internal-error-context*)) + (sap-int (sb-vm:context-pc context))) + (sap-int (sb-vm:context-pc *current-internal-error-context*)))) + sb-thread:*current-thread* condition)) (terpri stream)) @@ -1636,7 +1652,7 @@ forms that explicitly control this kind of evaluation.") (show-restarts *debug-restarts* *debug-io*)) (!def-debug-command "BACKTRACE" () - (print-backtrace :count (read-if-available sb-xc:most-positive-fixnum))) + (print-backtrace :count (read-if-available most-positive-fixnum))) (!def-debug-command "PRINT" () (print-frame-call *current-frame* *debug-io*)) @@ -1802,6 +1818,8 @@ forms that explicitly control this kind of evaluation.") (funcall thunk)) #+unbind-in-unwind thunk #+unbind-in-unwind unbind-to + #+(and unbind-in-unwind (not c-stack-is-control-stack)) + (%primitive sb-c:current-nsp) #+unbind-in-unwind catch-block))) #-unwind-to-frame-and-call-vop (let ((tag (gensym))) @@ -1933,3 +1951,39 @@ forms that explicitly control this kind of evaluation.") (if (listen-skip-whitespace *debug-io*) (read *debug-io*) default)) + +#+(and sb-devel x86-64) +(defun show-catch-tags () + (declare (notinline format)) + (let ((sap (descriptor-sap sb-vm:*current-catch-block*))) + (loop + (let ((tag (sap-ref-lispobj sap (ash sb-vm:catch-block-tag-slot 3))) + (link (sap-ref-sap sap (ash sb-vm:catch-block-previous-catch-slot 3)))) + (format t "~S ~A~%" tag link) + (setq sap link) + (if (= (sap-int sap) 0) (return)))))) + +;;; Sometimes in cold-init it is not possible to call LIST-BACKTRACE +;;; because that depends on a zillion things being set up correctly. +;;; This simple version seems to always work. +#+(or x86 x86-64) +(defun ultralite-backtrace (&optional (decode-pcs t)) + ;; this misses the current frame but that's perfectly fine for its intended use + (let ((fp (current-fp)) (list)) + (loop + (let ((prev-fp (sap-ref-sap fp 0))) + (cond ((and (sap> prev-fp fp) + (sap< prev-fp (descriptor-sap sb-vm:*control-stack-end*))) + (push (sap-ref-sap fp sb-vm:n-word-bytes) list) ; pc + (setq fp prev-fp)) + (t + (return))))) + (setq list (nreverse list)) + (if decode-pcs + (mapcar (lambda (pc) + (let ((code (sb-di::code-header-from-pc pc))) + (if code + (cons code (sap- pc (code-instructions code))) + pc))) + list) + list))) diff --git a/src/code/defbangstruct.lisp b/src/code/defbangstruct.lisp index ebfb15e596..7dba5d8572 100644 --- a/src/code/defbangstruct.lisp +++ b/src/code/defbangstruct.lisp @@ -22,7 +22,7 @@ (defstruct (delayed-defstruct (:constructor make-delayed-defstruct (args))) (args nil :type cons) ;; because the expansion autogenerates slot names based on current package - (package (package-name *package*) :type string)) + (package (cl:package-name *package*) :type string)) ;; a list of DELAYED-DEFSTRUCTs stored until we get SB-XC:DEFSTRUCT ;; working fully so that we can apply it to them then. After ;; SB-XC:DEFSTRUCT is made to work fully, this list is processed, then @@ -30,32 +30,23 @@ (defvar *delayed-defstructs* nil) ;;; DEF!STRUCT defines a structure for both the host and target. -;;; The host's structure inherits from STRUCTURE!OBJECT so that we can test -;;; for containment in the target's type hierarchy with minimal fuss. -;;; (A similar thing could be achieved by testing the package probably) -;;; When executed by the cross-compiler, DEF!STRUCT is just DEFSTRUCT. (defmacro def!struct (&rest args) - (multiple-value-bind (name supertype options slots) + (multiple-value-bind (name options slots) (destructuring-bind (nameoid &rest slots) args (multiple-value-bind (name options) (if (consp nameoid) (values (first nameoid) (rest nameoid)) (values nameoid nil)) (declare (type list options)) - (let ((include-clause (find :include options :key #'first))) - (when (find :type options :key #'first) - (error "can't use :TYPE option in DEF!STRUCT")) - (values name (second include-clause) options slots)))) + (when (find :type options :key #'first) + (error "can't use :TYPE option in DEF!STRUCT")) + (values name options slots))) ;; Attempting to define a type named by a CL symbol is an error. - ;; Therefore NAME is wrong if it uncrosses to something other than itself. - (assert (eq (uncross name) name)) + (assert (not (eq (sb-xc:symbol-package name) *cl-package*))) (assert (equal (uncross options) options)) `(progn (sb-xc:defstruct ,@args) - ,@(when supertype - `((aver (subtypep ',supertype 'structure!object)))) (defstruct (,name - ,@(unless supertype '((:include structure!object))) ,@(remove :pure options :key #'car)) ,@slots)))) @@ -69,7 +60,7 @@ (defmacro sb-xc:defstruct (&rest args) `(push (make-delayed-defstruct ',args) *delayed-defstructs*)) ;;; But instead it's this. No eval-when needed, since we LOAD this file. -(setf (macro-function 'sb-xc:defstruct) +(setf (cl:macro-function 'sb-xc:defstruct) (lambda (form environment) (declare (ignore environment)) `(push (make-delayed-defstruct ',(cdr form)) *delayed-defstructs*))) diff --git a/src/code/defbangtype.lisp b/src/code/defbangtype.lisp index 176aca179a..a6a020c3ad 100644 --- a/src/code/defbangtype.lisp +++ b/src/code/defbangtype.lisp @@ -25,8 +25,7 @@ (defmacro def!type (name &rest rest) ;; Attempting to define a type named by a CL symbol is an error. - ;; Therefore NAME is wrong if it uncrosses to something other than itself. - (assert (eq (uncross name) name)) + (assert (not (eq (sb-xc:symbol-package name) *cl-package*))) `(progn (deftype ,name ,@rest) #+sb-xc-host diff --git a/src/code/defmacro.lisp b/src/code/defmacro.lisp index dc73794e92..19e9a27bcb 100644 --- a/src/code/defmacro.lisp +++ b/src/code/defmacro.lisp @@ -9,11 +9,57 @@ ;;;; provided with absolutely no warranty. See the COPYING and CREDITS ;;;; files for more information. -(in-package "SB-IMPL") +(in-package "SB-C") + +(defun macro-function (symbol &optional env) + "If SYMBOL names a macro in ENV, returns the expansion function, +else returns NIL. If ENV is unspecified or NIL, use the global environment +only." + ;; local function definitions (ordinary) can shadow a global macro + (typecase env + #+(and sb-fasteval (not sb-xc-host)) + (sb-interpreter:basic-env + (multiple-value-bind (kind def) + (sb-interpreter:find-lexical-fun env symbol) + (when def + (return-from macro-function (when (eq kind :macro) def))))) + (lexenv + (let ((def (cdr (assoc symbol (lexenv-funs env))))) + (when def + (return-from macro-function + (when (typep def '(cons (eql macro))) (cdr def))))))) + (values (info :function :macro-function symbol))) + +(defvar *setf-macro-function-hook* nil + "A list of functions that (SETF MACRO-FUNCTION) invokes before storing the new + value. The functions take the macro name and the new value.") + +(defun (setf macro-function) (function symbol &optional environment) + (declare (symbol symbol) (type function function)) + (when environment + ;; Note: Technically there could be an ENV optional argument to + ;; SETF MACRO-FUNCTION, but since ANSI says that the consequences + ;; of supplying a non-nil one are undefined, we don't allow it. + ;; (Thus our implementation of this unspecified behavior is to + ;; complain. Since the behavior is unspecified, this is + ;; conforming.:-) + (error "Non-NIL environment argument in SETF of MACRO-FUNCTION ~S: ~S" + symbol environment)) + (when (eq (info :function :kind symbol) :special-form) + (error "~S names a special form." symbol)) + (when (boundp '*setf-macro-function-hook*) ; unbound during cold init + (dolist (f *setf-macro-function-hook*) + (funcall f symbol function))) + (with-single-package-locked-error (:symbol symbol "setting the macro-function of ~S") + (clear-info :function :type symbol) + (setf (info :function :kind symbol) :macro) + (setf (info :function :macro-function symbol) function) + #-sb-xc-host (install-guard-function symbol `(:macro ,symbol))) + function) (let () (defmacro sb-xc:defmacro (name lambda-list &body body) - (check-designator name defmacro) + (check-designator name 'defmacro) ;; When we are building the cross-compiler, we could be in a host ;; lisp which implements CL macros (e.g. CL:AND) as special ;; operators (while still providing a macroexpansion for @@ -27,17 +73,40 @@ name)) ;; The name of the lambda is (MACRO-FUNCTION name) ;; which does not conflict with any legal function name. - (let ((def (make-macro-lambda (sb-c::debug-name 'macro-function name) + (let ((def (make-macro-lambda (debug-name 'macro-function name) lambda-list body 'defmacro name))) `(progn ;; %COMPILER-DEFMACRO just performs a check for duplicate definitions ;; within a file. (eval-when (:compile-toplevel) - (sb-c::%compiler-defmacro :macro-function ',name)) + (%compiler-defmacro :macro-function ',name)) (eval-when (:compile-toplevel :load-toplevel :execute) - (sb-c::%defmacro ',name ,def (sb-c:source-location))))))) + (%defmacro ',name ,def (source-location))))))) -(defun sb-c::%defmacro (name definition source-location) +;;; Detect duplicate definitions within a file. However, no package +;;; lock check is necessary - it's handled elsewhere. +;;; +;;; Additionally, this is a STYLE-WARNING, not a WARNING, because there is +;;; meaningful behavior that can be ascribed to some redefinitions, e.g. +;;; (defmacro foo () first-definition) +;;; (defun f () (use-it (foo ))) +;;; (defmacro foo () other-definition) +;;; will use the first definition when compiling F, but make the second available +;;; in the loaded fasl. In this usage it would have made sense to wrap the +;;; respective definitions with EVAL-WHEN for different situations, +;;; but as long as the compile-time behavior is deterministic, it's just bad style +;;; and not flat-out wrong, though there is indeed some waste in the fasl. +;;; +;;; KIND is the globaldb KIND of this NAME +(defun %compiler-defmacro (kind name) + (let ((name-key `(,kind ,name))) + (when (boundp '*lexenv*) + ;; a slight OAOO issue here wrt %COMPILER-DEFUN + (if (member name-key (fun-names-in-this-file *compilation*) :test #'equal) + (compiler-style-warn 'same-file-redefinition-warning :name name) + (push name-key (fun-names-in-this-file *compilation*)))))) + +(defun %defmacro (name definition source-location) (declare (ignorable source-location)) ; xc-host doesn't use ;; old note (ca. 1985, maybe:-): "Eventually %%DEFMACRO ;; should deal with clearing old compiler information for @@ -62,20 +131,5 @@ ;; and comparing it with the new one. (warn 'redefinition-with-defmacro :name name :new-function definition :new-location source-location)) - (setf (sb-xc:macro-function name) definition))) + (setf (macro-function name) definition))) name) - -#+sb-xc-host -(let ((real-expander (macro-function 'sb-xc:defmacro))) - ;; Inform the cross-compiler how to expand SB-XC:DEFMACRO (= DEFMACRO). - (setf (sb-xc:macro-function 'sb-xc:defmacro) - (lambda (form env) - (declare (ignore env)) - ;; Since SB-KERNEL:LEXENV isn't compatible with the host, - ;; just pass NIL. The expansion correctly captures a non-null - ;; environment, but the expander doesn't need it. - (funcall real-expander form nil))) - ;; Building the cross-compiler should skip the compile-time-too - ;; processing SB-XC:DEFMACRO. - (setf (macro-function 'sb-xc:defmacro) - (lambda (form env) `(let () ,(funcall real-expander form env))))) diff --git a/src/code/defpackage.lisp b/src/code/defpackage.lisp index 26899a6846..83ddc865e9 100644 --- a/src/code/defpackage.lisp +++ b/src/code/defpackage.lisp @@ -11,31 +11,249 @@ (in-package "SB-IMPL") -;;; FIXME: figure out why a full call to FORMAT this early in warm load -;;; says that CLASS is not a known type. (Obviously it needs to parse -;;; a type spec, but then why it is only a style-warning and not an error?) -;;; Weirder still, why does it depend on the target architecture? +;;; ANSI specifies that: +;;; (1) MAKE-PACKAGE and DEFPACKAGE use the same default package-use-list +;;; (2) that it (as an implementation-defined value) should be documented, +;;; which we do in the doc string. +;;; For OAOO reasons we give a name to this value and then use #. readmacro +;;; to splice it in as a constant. Anyone who actually wants a random value +;;; is free to :USE (PACKAGE-USE-LIST :CL-USER) or whatever. +(defglobal *!default-package-use-list* nil) + +(defun make-package (name &key + (use '#.*!default-package-use-list*) + nicknames + (internal-symbols 10) + (external-symbols 10)) + #.(format nil + "Make a new package having the specified NAME, NICKNAMES, and USE +list. :INTERNAL-SYMBOLS and :EXTERNAL-SYMBOLS are estimates for the number of +internal and external symbols which will ultimately be present in the package. +The default value of USE is implementation-dependent, and in this +implementation it is ~S." *!default-package-use-list*) + (prog ((name (stringify-string-designator name)) + (nicks (stringify-string-designators nicknames)) + (package + (or (resolve-deferred-package name) + (resolve-rehoming-package name) + (%make-package (make-package-hashtable internal-symbols) + (make-package-hashtable external-symbols)))) + clobber) + :restart + (when (find-package name) + ;; ANSI specifies that this error is correctable. + (signal-package-cerror + name + "Clobber existing package." + "A package named ~S already exists" name) + (setf clobber t)) + (with-package-graph () + ;; Check for race, signal the error outside the lock. + (when (and (not clobber) (find-package name)) + (go :restart)) + (setf (package-%name package) name) + ;; Do a USE-PACKAGE for each thing in the USE list so that checking for + ;; conflicting exports among used packages is done. + (use-package use package) + ;; FIXME: ENTER-NEW-NICKNAMES can fail (ERROR) if nicknames are illegal, + ;; which would leave us with possibly-bad side effects from the earlier + ;; USE-PACKAGE (e.g. this package on the used-by lists of other packages, + ;; but not in *PACKAGE-NAMES*, and possibly import side effects too?). + ;; Perhaps this can be solved by just moving ENTER-NEW-NICKNAMES before + ;; USE-PACKAGE, but I need to check what kinds of errors can be caused by + ;; USE-PACKAGE, too. + (%enter-new-nicknames package nicks) + ;; The name table is actually multi-writer concurrent, but due to + ;; lazy removal of :DELETED entries we want to enforce a single-writer. + ;; We're inside WITH-PACKAGE-GRAPH so this is already synchronized with + ;; other MAKE-PACKAGE operations, but we need the additional lock + ;; so that it synchronizes with RENAME-PACKAGE. + (with-package-names (table) + (%register-package table name package)) + (atomic-incf *package-names-cookie*) + (when (boundp 'sb-c::*compilation*) + (setf (sb-c::package-environment-changed sb-c::*compilation*) t)) + (return package)) + (bug "never"))) + +(flet ((remove-names (package name-table keep-primary-name) + ;; An INFO-HASHTABLE does not support REMHASH. We can simulate it + ;; by changing the value to :DELETED. + ;; (NIL would be preferable, but INFO-GETHASH does not return + ;; a secondary value indicating whether the NIL was by default + ;; or found, not does it take a different default to return). + ;; At some point the table might contain more deleted values than + ;; useful values. We call %REBUILD-PACKAGE-NAMES to rectify that. + (dx-let ((names (cons (package-name package) + (package-nicknames package))) + (i 0)) + (when keep-primary-name (pop names)) + (dolist (name names) + ;; Aver that the following SETF doesn't insert a new <k,v> pair. + (aver (info-gethash name name-table)) + (setf (info-gethash name name-table) :deleted) + (incf i)) + (incf (info-env-tombstones name-table) i)) + nil)) + +;;; Change the name if we can, blast any old nicknames and then +;;; add in any new ones. +;;; +;;; The spec says that NAME is a package designator (not just a string designator) +;;; which is weird, but potentially meaningful if assigning new global nicknames. +;;; If not called for that purpose, then it's largely pointless, because you can't +;;; rename to any package-designator other than itself without causing a conflict. +;;; A survey of some other implementations suggests that we're in the minority +;;; as to the legality of (RENAME-PACKAGE "A" (FIND-PACKAGE "A") '("A-NICK")). +;;; +;;; ABCL: +;;; The value #<PACKAGE A> is not of type (OR STRING SYMBOL CHARACTER). +;;; CCL: +;;; Error: The value #<Package "A"> is not of the expected type (OR STRING SYMBOL CHARACTER). +;;; CMUCL: +;;; #<The A package, 0/9 internal, 0/9 external> cannot be coerced to a string. +;;; ECL: +;;; In function STRING, the value of the first argument is #<"A" package> +;;; which is not of the expected type STRING +;;; +;;; CLISP agrees with us that this usage is permitted. If the new "name" is a +;;; different package, it is merely the same error as if any already-existing name +;;; was given. I see no reason to be more strict than the spec would have it be. +(defun rename-package (package-designator name &optional (nicknames ())) + "Changes the name and nicknames for a package." + (prog ((nicks (stringify-string-designators nicknames))) + :restart + (let ((package (find-undeleted-package-or-lose package-designator)) + ;; This is the "weirdness" alluded to. Do it in the loop in case + ;; the stringified value changes on restart when NAME is a package. + (name (stringify-package-designator name)) + (found (find-package name))) + (unless (or (not found) (eq found package)) + (signal-package-error name + "A package named ~S already exists." name)) + (with-single-package-locked-error () + (unless (and (string= name (package-name package)) + (null (set-difference nicks (package-nicknames package) + :test #'string=))) + (assert-package-unlocked + package "renaming as ~A~@[ with nickname~*~P ~1@*~{~A~^, ~}~]" + name nicks (length nicks))) + (with-package-names (table) + ;; Check for race conditions now that we have the lock. + (unless (eq package (find-package package-designator)) + (go :restart)) + ;; Do the renaming. + ;; As a special case, do not allow the package to transiently disappear + ;; if PACKAGE-NAME is unchanged. This avoids glitches with build systems + ;; which try to operate on subcomponents in parallel, where one of the + ;; built subcomponents needs to add nicknames to an existing package. + ;; We could be clever here as well by not removing nicknames that + ;; will ultimately be re-added, but that didn't seem as critical. + (let ((keep-primary-name (string= name (package-%name package)))) + (remove-names package table keep-primary-name) + (unless keep-primary-name + (%register-package table name package))) + (setf (package-%name package) name + (package-%nicknames package) ())) + ;; Adding each nickname acquires and releases the table lock, + ;; because it's potentially interactive (on failure) and therefore + ;; not ideal to hold the lock for the entire duration. + (%enter-new-nicknames package nicks)) + (atomic-incf *package-names-cookie*) + (when (boundp 'sb-c::*compilation*) + (setf (sb-c::package-environment-changed sb-c::*compilation*) t)) + (return package)))) + +(defun delete-package (package-designator) + "Delete the package designated by PACKAGE-DESIGNATOR from the package + system data structures." + (tagbody :restart + (let ((package (find-package package-designator))) + (cond ((not package) + ;; This continuable error is required by ANSI. + (signal-package-cerror + package-designator + "Ignore." + "There is no package named ~S." package-designator) + (return-from delete-package nil)) + ((not (package-name package)) ; already deleted + (return-from delete-package nil)) + (t + (with-single-package-locked-error + (:package package "deleting package ~A" package) + (let ((use-list (package-used-by-list package))) + (when use-list + ;; This continuable error is specified by ANSI. + (signal-package-cerror + package + "Remove dependency in other packages." + "~@<Package ~S is used by package~P:~2I~_~S~@:>" + (package-name package) + (length use-list) + (mapcar #'package-name use-list)) + (dolist (p use-list) + (unuse-package package p)))) + (dolist (p (package-implements-list package)) + (remove-implementation-package package p)) + (with-package-graph () + ;; Check for races, restart if necessary. + (let ((package2 (find-package package-designator))) + (when (or (neq package package2) (package-used-by-list package2)) + (go :restart))) + (dolist (used (package-use-list package)) + (unuse-package used package)) + (setf (package-%local-nicknames package) nil) + (let ((rehoming-package (make-rehoming-package package))) + (flet ((nullify-home (symbols) + (dovector (x (package-hashtable-cells symbols)) + (when (and (symbolp x) + (eq (symbol-package x) package)) + (%set-symbol-package x rehoming-package))))) + (nullify-home (package-internal-symbols package)) + (nullify-home (package-external-symbols package)))) + (with-package-names (table) + (awhen (package-id package) + (setf (aref *id->package* it) nil (package-id package) nil)) + (remove-names package table nil) + (setf (package-%name package) nil + ;; Setting PACKAGE-%NAME to NIL is required in order to + ;; make PACKAGE-NAME return NIL for a deleted package as + ;; ANSI requires. Setting the other slots to NIL + ;; and blowing away the PACKAGE-HASHTABLES is just done + ;; for tidiness and to help the GC. + (package-%nicknames package) nil)) + (atomic-incf *package-names-cookie*) + (when (boundp 'sb-c::*compilation*) + (setf (sb-c::package-environment-changed sb-c::*compilation*) t)) + (setf (package-%use-list package) nil + (package-tables package) #() + (package-%shadowing-symbols package) nil + (package-internal-symbols package) + (make-package-hashtable 0) + (package-external-symbols package) + (make-package-hashtable 0))) + (return-from delete-package t))))))) +) ; end FLET (defmacro defpackage (package &rest options) - #.(locally (declare (notinline format)) - (format nil - "Defines a new package called PACKAGE. Each of OPTIONS should be one of the + #.(format nil + "Defines a new package called PACKAGE. Each of OPTIONS should be one of the following: ~{~&~4T~A~} All options except ~{~A, ~}and :DOCUMENTATION can be used multiple times." - '((:use "{package-name}*") - (:export "{symbol-name}*") - (:import-from "<package-name> {symbol-name}*") - (:shadow "{symbol-name}*") - (:shadowing-import-from "<package-name> {symbol-name}*") - (:local-nicknames "{(local-nickname actual-package-name)}*") - (:lock "boolean") - (:implement "{package-name}*") - (:documentation "doc-string") - (:intern "{symbol-name}*") - (:size "<integer>") - (:nicknames "{package-name}*")) - '(:size :lock))) + '((:use "{package-name}*") + (:export "{symbol-name}*") + (:import-from "<package-name> {symbol-name}*") + (:shadow "{symbol-name}*") + (:shadowing-import-from "<package-name> {symbol-name}*") + (:local-nicknames "{(local-nickname actual-package-name)}*") + (:lock "boolean") + (:implement "{package-name}*") + (:documentation "doc-string") + (:intern "{symbol-name}*") + (:size "<integer>") + (:nicknames "{package-name}*")) + '(:size :lock)) (let ((nicknames nil) (local-nicknames nil) (size nil) @@ -64,7 +282,7 @@ (%program-error "can't specify ~S more than once." optname)) (unless (typep optval '(cons t null)) (%program-error "~S expects a single argument. Got ~S" - (car option) (cdr option))) + (car option) (cdr option))) (push optname seen) (setq optval (car optval)))) (case optname @@ -150,24 +368,25 @@ but have common elements ~% ~S" (car x) (car y) z)))) -(flet ((designator-to-string (kind designator) - (cond ((and (eq kind 'package) (packagep designator)) - (package-name designator)) ; already simple and basic if possible - (t - (possibly-base-stringize - (cond ((stringp designator) designator) - ((symbolp designator) (symbol-name designator)) - ((characterp designator) (string designator)) - (t (error 'simple-type-error - :datum designator - :expected-type - (if (eq kind 'package) 'package-designator 'string-designator) - :format-control "~S does not designate a ~(~A~)" - :format-arguments (list designator kind))))))))) +(flet ((designator-to-string (designator type format-control) + (possibly-base-stringize + (typecase designator + (string designator) + (symbol (symbol-name designator)) + (character (string designator)) + (t (error 'simple-type-error + :datum designator + :expected-type type + :format-control format-control + :format-arguments (list designator))))))) (defun stringify-string-designator (string-designator) - (designator-to-string 'string string-designator)) + (designator-to-string string-designator 'string-designator + "~S does not designate a string")) (defun stringify-package-designator (package-designator) - (designator-to-string 'package package-designator))) + (if (packagep package-designator) + (package-name package-designator) ; already simple, and base-string when possible + (designator-to-string package-designator 'package-designator + "~S does not designate a package")))) (defun stringify-string-designators (string-designators) (mapcar #'stringify-string-designator string-designators)) @@ -403,29 +622,130 @@ specifies to signal a warning if SWANK package is in variance, and an error othe :format-arguments (list name (package-name package)))) (intern name package))))) -;;;; One more package-related transform. I'm unsure why this can't be installed -;;;; sooner, but it can't. It's a symptom of our build weirdness involving -;;;; the lack of a class definition for the class CLASS, but I can't see what -;;;; that's got to do with anything. -(in-package "SB-C") - -;;; As for the INTERN transform, you could be screwed if you use any of the -;;; standard package names as a local nickname of a random package. -(deftransform find-package ((name) ((constant-arg string-designator))) - (multiple-value-bind (form constp) (find-package-xform name) - ;; standard packages are effectively constant objects, otherwise - ;; we have to invoke the find function. - (if constp form `(sb-impl::cached-find-package ,form)))) - -;;;; package hacking - -;;; FIXME: This nickname is a deprecated hack for backwards -;;; compatibility with code which assumed the CMU-CL-style -;;; SB-ALIEN/SB-C-CALL split. That split went away and was deprecated -;;; in 0.7.0, so we should get rid of this nickname after a while. -(let ((package (find-package "SB-ALIEN"))) - (rename-package package package - (cons "SB-C-CALL" (package-nicknames package)))) - -(let ((package (find-package "SB-SEQUENCE"))) - (rename-package package package (list "SEQUENCE"))) +;;;; APROPOS and APROPOS-LIST + +(defun briefly-describe-symbol (symbol) + (fresh-line) + (prin1 symbol) + (when (boundp symbol) + (let ((value (symbol-value symbol))) + (if (typep value '(or fixnum symbol hash-table)) + (format t " = ~S" value) + (format t " (bound, ~S)" (type-of value))))) + (when (fboundp symbol) + (write-string " (fbound)"))) + +(flet ((add-to-bag-if-found (table string length hash result) + (with-symbol ((symbol) table string length hash) + ;; HASH-TABLE degenerates to a list when used by FIND-ALL-SYMBOLS + ;; since homographs have the same SXHASH, so handle either + ;; a hash-table or a cons containing a list. + (if (hash-table-p result) + (setf (gethash symbol result) t) + (pushnew symbol (car result)))))) + +(defun find-all-symbols (string-designator) + "Return a list of all symbols in the system having the specified name." + (let* ((string (truly-the simple-string + (stringify-string-designator string-designator))) + (length (length string)) + (hash (compute-symbol-hash string length)) + (result (list nil))) + (do-packages (p) ; FIXME: should not acquire package-names lock + (add-to-bag-if-found (package-internal-symbols p) string length hash result) + (add-to-bag-if-found (package-external-symbols p) string length hash result)) + (car result))) + +(defun apropos-list (string-designator + &optional + package-designator + external-only + &aux (string (the simple-string + (stringify-string-designator string-designator)))) + "Like APROPOS, except that it returns a list of the symbols found instead + of describing them." + (if package-designator ; rare to supply this, I suspect + ;; This loop is extremely inefficient because both DO-SYMBOLS and FIND-SYMBOL + ;; check for inheritance, which we shouldn't if EXTERNAL-ONLY was given. + ;; Technically the external-p test could use FIND-EXTERNAL-SYMBOL but portable code + ;; can't care. Somebody did, and noticed that it wasn't working, so it got fixed + ;; in rev e92a2f8844d9 which is ironic because it came from CMUCL, which implemented + ;; APROPOS differently but then removed the nonstandard option in + ;; https://gitlab.common-lisp.net/cmucl/cmucl/-/commit/9f652c0515f90b1fc8166d5099a0cee37e76e07c + (let ((package (find-undeleted-package-or-lose package-designator)) + (result nil)) + (do-symbols (symbol package) + (when (and (or (not external-only) + (and (eq (symbol-package symbol) package) + (eq (nth-value 1 (find-symbol (symbol-name symbol) + package)) + :external))) + (search string (symbol-name symbol) :test #'char-equal)) + (pushnew symbol result))) + (return-from apropos-list (sort result #'string-lessp)))) + ;; Since we're going to scan all packages, there are two admissible optimizations: + ;; * only scan directly present symbols, because each symbol returned has to + ;; be in some package. + ;; * if the table was not modified since core save, as is often the case, + ;; then compare by EQ to set of possibly matching strings. This has to be + ;; an improvement, because it compares STRING at most once to any symbol-name. + ;; + ;; Comparison of (TIME (APROPOS-LIST "str")) in a core with over 300,000 symbols: + ;; .840 seconds = baseline + ;; .140 seconds = inlining WITH-SYMBOL + ;; .104 seconds = MODIFIED check then R/O scan or else WITH-SYMBOL + (let (candidates) + (block done + (sb-vm:map-allocated-objects + (lambda (obj widetag size) + (declare (ignore size)) + (cond ((or (= widetag sb-vm:simple-base-string-widetag) + #+sb-unicode + (= widetag sb-vm:simple-character-string-widetag)) + (when (search string obj :test #'char-equal) + (push (cons (compute-symbol-hash obj (length obj)) obj) candidates))) + (t + (return-from done)))) + :read-only)) + (let ((result (make-hash-table :test 'eq)) + ;; darwin-jit will never take the purified branch. Readonly space exists, + ;; but contains no symbol names. TUNE-HASHTABLE-SIZES-OF-ALL-PACKAGES knows that + ;; and will never reset a table's MODIFIED flag. However, for all other platforms, + ;; we need to detect if purification happened. + (core-purified-p (sap> sb-vm:*read-only-space-free-pointer* + (sb-sys:int-sap sb-vm:read-only-space-start)))) + (flet ((find-all-in-table (table) + (if (and core-purified-p (not (package-hashtable-modified table))) + (dolist (candidate candidates) + (let* ((hash (the hash-code (car candidate))) + (string (the simple-string (cdr candidate))) + (length (length string))) + (add-to-bag-if-found table string length hash result))) + (dovector (entry (package-hashtable-cells table)) + ;; I would have guessed that GETHASH is faster than SEARCH, but if + ;; interposed between SYMBOLP and SEARCH, it slows down this loop. + ;; That's because almost always the symbol is NOT yet in the result, + ;; so an extra GETHASH is a strict increase in the number of + ;; instructions executed, for no net reduction in time. + (when (and (symbolp entry) + (search string (symbol-name entry) :test #'char-equal)) + (setf (gethash entry result) t)))))) + (do-packages (package) ; FIXME: should not acquire package-names lock + (find-all-in-table (package-external-symbols package)) + (unless external-only + (find-all-in-table (package-internal-symbols package))))) + (sort (loop for k being each hash-key of result collect k) #'string-lessp)))) +) ; end FLET + +(defun apropos (string-designator &optional package external-only) + "Briefly describe all symbols which contain the specified STRING. + If PACKAGE is supplied then only describe symbols present in + that package. If EXTERNAL-ONLY then only describe + external symbols in the specified package." + ;; Implementing this in terms of APROPOS-LIST keeps things simple at the cost + ;; of some unnecessary consing; and the unnecessary consing shouldn't be an + ;; issue, since this function is is only useful interactively anyway, and + ;; we can cons and GC a lot faster than the typical user can read.. + (dolist (symbol (apropos-list string-designator package external-only)) + (briefly-describe-symbol symbol)) + (values)) diff --git a/src/code/defsetfs.lisp b/src/code/defsetfs.lisp index 1fab144388..ec1b444d00 100644 --- a/src/code/defsetfs.lisp +++ b/src/code/defsetfs.lisp @@ -24,34 +24,41 @@ (defsetf context-register %set-context-register) (defsetf boxed-context-register %set-boxed-context-register) (defsetf context-float-register %set-context-float-register) -;;; from bit-bash.lisp -(defsetf word-sap-ref %set-word-sap-ref) -;;; from debug-int.lisp -(in-package "SB-DI") -(defsetf stack-ref %set-stack-ref) -(defsetf debug-var-value %set-debug-var-value) -(defsetf breakpoint-info %set-breakpoint-info) +#-x86-64 +(progn + (declaim (inline assign-vector-flags logior-header-bits reset-header-bits)) + (defun assign-vector-flags (vector flags) + (set-header-data vector (dpb flags (byte 8 #.array-flags-data-position) (get-header-data vector))) + (values)) + (defun logior-header-bits (object bits) + (set-header-data object (logior (get-header-data object) bits)) + object) + (defun reset-header-bits (object bits) + (set-header-data object (logand (get-header-data object) (lognot bits))) + (values))) + +(defmacro logior-array-flags (array flags) + `(logior-header-bits ,array (ash ,flags #.array-flags-data-position))) +(defmacro reset-array-flags (array flags) + `(reset-header-bits ,array (ash ,flags #.array-flags-data-position))) -;;; from bignum.lisp (in-package "SB-IMPL") -(defsetf %bignum-ref %bignum-set) -;;; from defstruct.lisp -(defsetf %instance-ref %instance-set) - -(defsetf %raw-instance-ref/word %raw-instance-set/word) -(defsetf %raw-instance-ref/signed-word %raw-instance-set/signed-word) -(defsetf %raw-instance-ref/single %raw-instance-set/single) -(defsetf %raw-instance-ref/double %raw-instance-set/double) -(defsetf %raw-instance-ref/complex-single %raw-instance-set/complex-single) -(defsetf %raw-instance-ref/complex-double %raw-instance-set/complex-double) - -(defsetf %instance-layout %set-instance-layout) -(defsetf %funcallable-instance-info %set-funcallable-instance-info) -;;; The writer is named after the reader, but only operates on FUNCALLABLE-INSTANCE -;;; even if the reader operates on any FUNCTION. -(defsetf %fun-layout %set-funcallable-instance-layout) +(declaim (inline (setf %funcallable-instance-info))) +;;; Funcallable instances are just like closures, but there's another slot or two +;;; depending on whether the layout pointer is in a slot or in the header word. +(defun (setf %funcallable-instance-info) (newval fin index) + (%closure-index-set fin (+ index (- sb-vm:funcallable-instance-info-offset + sb-vm:closure-info-offset)) + newval) + newval) +;;; This is just to keep the DEFSTRUCT logic consistent with %INSTANCE-SET, +;;; but the canonical setter is the function named (setf %funcallable-instance-info) +(declaim (inline %set-funcallable-instance-info)) +(defun %set-funcallable-instance-info (fin index newval) + (funcall #'(setf %funcallable-instance-info) newval fin index) + (values)) ;;; from early-setf.lisp @@ -154,35 +161,23 @@ (defsetf svref %svset) (defsetf char %charset) (defsetf schar %scharset) -(defsetf %array-dimension %set-array-dimension) -(defsetf %vector-raw-bits %set-vector-raw-bits) +(declaim (inline (setf %vector-raw-bits))) +(defun (setf %vector-raw-bits) (bits vector index) + (%set-vector-raw-bits vector index bits) + bits) (defsetf symbol-value set) (defsetf symbol-global-value set-symbol-global-value) -(defsetf symbol-plist %set-symbol-plist) (defsetf fill-pointer %set-fill-pointer) -(defsetf sap-ref-8 %set-sap-ref-8) -(defsetf signed-sap-ref-8 %set-signed-sap-ref-8) -(defsetf sap-ref-16 %set-sap-ref-16) -(defsetf signed-sap-ref-16 %set-signed-sap-ref-16) -(defsetf sap-ref-32 %set-sap-ref-32) -(defsetf signed-sap-ref-32 %set-signed-sap-ref-32) -(defsetf sap-ref-64 %set-sap-ref-64) -(defsetf signed-sap-ref-64 %set-signed-sap-ref-64) -(defsetf sap-ref-word %set-sap-ref-word) -(defsetf signed-sap-ref-word %set-signed-sap-ref-word) -(defsetf sap-ref-sap %set-sap-ref-sap) -(defsetf sap-ref-lispobj %set-sap-ref-lispobj) -(defsetf sap-ref-single %set-sap-ref-single) -(defsetf sap-ref-double %set-sap-ref-double) -#+long-float (defsetf sap-ref-long %set-sap-ref-long) (defsetf subseq (sequence start &optional end) (v) `(progn (replace ,sequence ,v :start1 ,start :end1 ,end) ,v)) -;;; from fdefinition.lisp -(defsetf fdefinition %set-fdefinition) - ;;; from kernel.lisp -(defsetf code-header-ref code-header-set) +#-darwin-jit +(progn +(declaim (inline (setf code-header-ref))) +(defun (setf code-header-ref) (value code index) + (code-header-set code index value) + value)) ;;; from pcl (defsetf slot-value sb-pcl::set-slot-value) @@ -199,14 +194,14 @@ ;; it. In particular, this must fail: (SETF (GET 'SYM 'IND (ERROR "Foo")) 3). (defsetf get (symbol indicator &optional default &environment e) (newval) - (let ((constp (sb-xc:constantp default e))) + (let ((constp (constantp default e))) ;; always reference default's temp var to "use" it `(%put ,symbol ,indicator ,(if constp newval `(progn ,default ,newval))))) ;; A possible optimization for read/modify/write of GETHASH ;; would be to predetermine the vector element where the key/value pair goes. (defsetf gethash (key hashtable &optional default &environment e) (newval) - (let ((constp (sb-xc:constantp default e))) + (let ((constp (constantp default e))) ;; always reference default's temp var to "use" it `(%puthash ,key ,hashtable ,(if constp newval `(progn ,default ,newval))))) @@ -215,7 +210,7 @@ (define-setf-expander the (&whole form type place &environment env) (binding* ((op (car form)) ((temps subforms store-vars setter getter) - (sb-xc:get-setf-expansion place env))) + (get-setf-expansion place env))) (values temps subforms store-vars `(multiple-value-bind ,store-vars (,op ,type (values ,@store-vars)) ,setter) @@ -223,7 +218,7 @@ (define-setf-expander getf (place prop &optional default &environment env) (binding* (((place-tempvars place-tempvals stores set get) - (sb-xc:get-setf-expansion place env)) + (get-setf-expansion place env)) ((call-tempvars call-tempvals call-args bitmask) (collect-setf-temps (list prop default) env '(indicator default))) (newval (gensym "NEW"))) @@ -245,7 +240,7 @@ (let (all-dummies all-vals newvals setters getters) (dolist (place places) (multiple-value-bind (dummies vals newval setter getter) - (sb-xc:get-setf-expansion place env) + (get-setf-expansion place env) ;; ANSI 5.1.2.3 explains this logic quite precisely. -- ;; CSR, 2004-06-29 (setq all-dummies (append all-dummies dummies (cdr newval)) @@ -307,8 +302,8 @@ place with bits from the low-order end of the new value." (collect-setf-temps (list spec) env '(bytespec)))) (byte (if (cdr byte-args) (cons 'byte byte-args) (car byte-args))) ((place-tempvars place-tempvals stores setter getter) - (sb-xc:get-setf-expansion place env)) - (newval (sb-xc:gensym "NEW")) + (get-setf-expansion place env)) + (newval (gensym "NEW")) (new-int `(,store-fun ,(if (eq load-fun 'logbitp) `(if ,newval 1 0) newval) ,byte ,getter))) @@ -335,18 +330,19 @@ place with bits from the low-order end of the new value." (eval-when (:compile-toplevel :load-toplevel :execute) (%defsetf 'truly-the (info :setf :expander 'the)) (%defsetf 'the* (info :setf :expander 'the)) - - (%defsetf 'mask-field (info :setf :expander 'ldb) - "The first argument is a byte specifier. The second is any place form + (%defsetf 'mask-field + (lambda (&rest args) + "The first argument is a byte specifier. The second is any place form acceptable to SETF. Replaces the specified byte of the number in this place -with bits from the corresponding position in the new value.") +with bits from the corresponding position in the new value." + (apply (info :setf :expander 'ldb) args))) ;;; SETF of LOGBITP is not mandated by CLHS but is nice to have. ;;; FIXME: the code is suboptimal. Better code would "pre-shift" the 1 bit, ;;; so that result = (in & ~mask) | (flag ? mask : 0) ;;; Additionally (setf (logbitp N x) t) is extremely stupid- it first clears ;;; and then sets the bit, though it does manage to pre-shift the constants. - (%defsetf 'logbitp (info :setf :expander 'ldb)))) + (%defsetf 'logbitp (info :setf :expander 'ldb)))) ;;; Rather than have a bunch of SB-PCL::FAST-METHOD function names all point ;;; to one that is randomly chosen - and therefore looks confusing - @@ -362,3 +358,21 @@ with bits from the corresponding position in the new value.") (defun 1-arg-t (a) (declare (ignore a)) t) (defun 2-arg-nil (a b) (declare (ignore a b)) nil) (defun 3-arg-nil (a b c) (declare (ignore a b c)) nil) + +(in-package "SB-VM") + +(defun blt-copier-for-widetag (x) + (declare ((mod 256) x)) + (aref (load-time-value + (map-into (make-array 32) + (lambda (x) (and x + (symbol-function x))) + '#.(let ((a (make-array 32 :initial-element nil))) + (dovector (saetp *specialized-array-element-type-properties* a) + (when (and (not (member (saetp-specifier saetp) '(t nil))) + (<= (saetp-n-bits saetp) n-word-bits)) + (setf (svref a (ash (- (saetp-typecode saetp) 128) -2)) + (intern (format nil "UB~D-BASH-COPY" (saetp-n-bits saetp)) + "SB-KERNEL")))))) + t) + (ash (logand x #x7f) -2))) diff --git a/src/code/defstruct.lisp b/src/code/defstruct.lisp index 7fd7760faf..b0f5fa6cee 100644 --- a/src/code/defstruct.lisp +++ b/src/code/defstruct.lisp @@ -22,7 +22,7 @@ (let ((res (info :type :compiler-layout name))) (cond ((not res) (error "Class is not yet defined or was undefined: ~S" name)) - ((not (typep (layout-info res) 'defstruct-description)) + ((not (typep (wrapper-%info res) 'defstruct-description)) (error "Class is not a structure class: ~S" name)) (t (check-deprecated-type name) @@ -30,7 +30,7 @@ (defun compiler-layout-ready-p (name) (let ((layout (info :type :compiler-layout name))) - (and layout (typep (layout-info layout) 'defstruct-description)))) + (and layout (typep (wrapper-%info layout) 'defstruct-description)))) (sb-xc:defmacro %make-structure-instance-macro (dd slot-specs &rest slot-vars) (if (compiler-layout-ready-p (dd-name dd)) @@ -48,64 +48,39 @@ (%make-structure-instance-allocator ,dd ,slot-specs)) ,@slot-vars))))) +(sb-xc:defmacro %new-instance (layout size) + `(let* ((l ,layout) + (i (truly-the ,(if (constantp layout) (wrapper-classoid layout) 'instance) + (%make-instance ,size)))) + (%set-instance-layout i l) + i)) +(sb-xc:defmacro %new-instance* (layout len) + `(let ((i (truly-the + ,(if (constantp layout) (wrapper-classoid layout) 'instance) + (if (logtest (layout-flags ,layout) sb-vm::+strictly-boxed-flag+) + (%make-instance ,len) + (%make-instance/mixed ,len))))) + (%set-instance-layout i ,layout) + i)) + (declaim (ftype (sfunction (defstruct-description list) function) %make-structure-instance-allocator)) (defun %make-structure-instance-allocator (dd slot-specs) (let ((vars (make-gensym-list (length slot-specs)))) (values (compile nil `(lambda (,@vars) + (declare (optimize (sb-c:store-source-form 0))) (%make-structure-instance-macro ,dd ',slot-specs ,@vars)))))) (defun %make-funcallable-structure-instance-allocator (dd slot-specs) (when slot-specs (bug "funcallable-structure-instance allocation with slots unimplemented")) - (let ((name (dd-name dd)) - (length (dd-length dd)) - (nobject (gensym "OBJECT"))) - (values + (values (compile nil `(lambda () - (let ((,nobject (%make-funcallable-instance ,length))) - (setf (%fun-layout ,nobject) - (%delayed-get-compiler-layout ,name)) - ,nobject)))))) - -;;; Delay looking for compiler-layout until the constructor is being -;;; compiled, since it doesn't exist until after the EVAL-WHEN -;;; (COMPILE) stuff is compiled. (Or, in the oddball case when -;;; DEFSTRUCT is executing in a non-toplevel context, the -;;; compiler-layout still doesn't exist at compilation time, and we -;;; delay still further.) -(sb-xc:defmacro %delayed-get-compiler-layout (name) - (let ((layout (info :type :compiler-layout name))) - (cond (layout - ;; ordinary case: When the DEFSTRUCT is at top level, - ;; then EVAL-WHEN (COMPILE) stuff will have set up the - ;; layout for us to use. - (unless (typep (layout-info layout) 'defstruct-description) - (error "Class is not a structure class: ~S" name)) - `,layout) - (t - ;; KLUDGE: In the case that DEFSTRUCT is not at top-level - ;; the layout doesn't exist at compile time. In that case - ;; we laboriously look it up at run time. This code will - ;; run on every constructor call and will likely be quite - ;; slow, so if anyone cares about performance of - ;; non-toplevel DEFSTRUCTs, it should be rewritten to be - ;; cleverer. -- WHN 2002-10-23 - (sb-c:compiler-notify - "implementation limitation: ~ - Non-toplevel DEFSTRUCT constructors are slow.") - (with-unique-names (layout) - `(let ((,layout (info :type :compiler-layout ',name))) - (unless (typep (layout-info ,layout) 'defstruct-description) - (error "Class is not a structure class: ~S" ',name)) - ,layout)))))) - -;;; re. %DELAYED-GET-COMPILER-LAYOUT and COMPILE-TIME-FIND-LAYOUT, above.. -;;; -;;; FIXME: Perhaps both should be defined with SB-XC:DEFMACRO? -;;; FIXME: Do we really need both? If so, their names and implementations -;;; should probably be tweaked to be more parallel. + (declare (optimize (sb-c:store-source-form 0))) + (let ((object (%make-funcallable-instance ,(dd-length dd)))) + (setf (%fun-wrapper object) ,(find-layout (dd-name dd))) + object))))) ;;;; DEFSTRUCT-DESCRIPTION @@ -119,6 +94,12 @@ ;;; Does DD describe a structure with a class? (defun dd-class-p (dd) (if (member (dd-type dd) '(structure funcallable-structure)) t nil)) +(defmacro dd-named (dd) `(logtest (dd-flags ,dd) +dd-named+)) +(defmacro dd-pure (dd) `(logtest (dd-flags ,dd) +dd-pure+)) +(defmacro dd-null-lexenv-p (dd) `(logtest (dd-flags ,dd) +dd-nullenv+)) +(defun dd-print-option (dd) + (cond ((logtest (dd-flags dd) +dd-printfun+) :print-function) + ((logtest (dd-flags dd) +dd-printobj+) :print-object))) (defun dd-layout-or-lose (dd) (compiler-layout-or-lose (dd-name dd))) @@ -140,24 +121,25 @@ ;; and we don't have structures whose slot indices run into the thousands. (bits 0 :type fixnum :read-only t) (default nil :read-only t)) ; default value expression -#-sb-fluid (declaim (freeze-type defstruct-slot-description)) +(declaim (freeze-type defstruct-slot-description)) (eval-when (:compile-toplevel) ;; Ensure that rsd-index is representable in 3 bits. (Can easily be changed) (assert (<= (1+ (length *raw-slot-data*)) 8))) -;; genesis needs to know how many bits are to the right of the 'index' field -;; in the packed BITS slot of a DSD. -(defconstant +dsd-index-shift+ 6) -(defun pack-dsd-bits (index read-only safe-p always-boundp rsd-index) - (logior (ash index +dsd-index-shift+) - (if read-only (ash 1 5) 0) - (if safe-p (ash 1 4) 0) - (if always-boundp (ash 1 3) 0) +(defconstant sb-vm:dsd-index-shift 7) +(defconstant sb-vm:dsd-raw-type-mask #b111) +(defun pack-dsd-bits (index read-only safe-p always-boundp gc-ignorable rsd-index) + (logior (ash index sb-vm:dsd-index-shift) + (if read-only (ash 1 6) 0) + (if safe-p (ash 1 5) 0) + (if always-boundp (ash 1 4) 0) + (if gc-ignorable (ash 1 3) 0) (the (unsigned-byte 3) (if rsd-index (1+ rsd-index) 0)))) (declaim (inline dsd-always-boundp dsd-safe-p + dsd-gc-ignorable ; dsd-read-only ; compilation order problem )) @@ -187,36 +169,46 @@ ;; Index into *RAW-SLOT-DATA* vector of the RAW-SLOT-DATA for this slot. ;; The index is NIL if this slot is not raw. (defun dsd-rsd-index (dsd) - (let ((val (ldb (byte 3 0) (dsd-bits dsd)))) + (let ((val (logand (dsd-bits dsd) sb-vm:dsd-raw-type-mask))) (if (plusp val) (the (mod #.(length *raw-slot-data*)) (1- val))))) +;;; GC-ignorable slots are a superset of raw slots. +(defun dsd-gc-ignorable (dsd) (logbitp 3 (dsd-bits dsd))) ;; Whether the slot is always bound. Slots are almost always bound, ;; the exception being those which appear as an &AUX var with no value ;; in a BOA constructor. -(defun dsd-always-boundp (dsd) (logbitp 3 (dsd-bits dsd))) +(defun dsd-always-boundp (dsd) (logbitp 4 (dsd-bits dsd))) ;; Whether the slot is known to be always of the specified type ;; A slot may be SAFE-P even if not always-boundp. -(defun dsd-safe-p (dsd) (logbitp 4 (dsd-bits dsd))) -(defun dsd-read-only (dsd) (logbitp 5 (dsd-bits dsd))) +(defun dsd-safe-p (dsd) (logbitp 5 (dsd-bits dsd))) +(defun dsd-read-only (dsd) (logbitp 6 (dsd-bits dsd))) ;; its position in the implementation sequence (defun dsd-index (dsd) - (the index (ash (dsd-bits dsd) (- +dsd-index-shift+)))) + (the index (ash (dsd-bits dsd) (- sb-vm:dsd-index-shift)))) (sb-c:define-source-transform dsd-index (dsd) - `(truly-the index (ash (dsd-bits ,dsd) ,(- +dsd-index-shift+)))) + `(truly-the index (ash (dsd-bits ,dsd) ,(- sb-vm:dsd-index-shift)))) (!set-load-form-method defstruct-slot-description (:host :xc :target)) (defmethod print-object ((x defstruct-slot-description) stream) (print-unreadable-object (x stream :type t) (prin1 (dsd-name x) stream))) + (defun dsd-raw-slot-data (dsd) (let ((rsd-index (dsd-rsd-index dsd))) (and rsd-index (svref *raw-slot-data* rsd-index)))) + (defun dsd-raw-type (dsd) (acond ((dsd-raw-slot-data dsd) (raw-slot-data-raw-type it)) (t))) -(defun dsd-primitive-accessor (dsd &aux (rsd (dsd-raw-slot-data dsd))) - (if rsd (raw-slot-data-accessor-name rsd) '%instance-ref)) + +(defun dsd-reader (dsd funinstancep) + (acond ((dsd-raw-slot-data dsd) + (values (raw-slot-data-reader-name it) (raw-slot-data-writer-name it))) + (funinstancep + (values '%funcallable-instance-info '%set-funcallable-instance-info)) + (t + (values '%instance-ref '%instance-set)))) ;;;; typed (non-class) structures @@ -224,7 +216,7 @@ (defun dd-lisp-type (defstruct) (ecase (dd-type defstruct) (list 'list) - (vector `(simple-array ,(dd-element-type defstruct) (*))))) + (vector `(simple-array ,(dd-%element-type defstruct) (*))))) ;;;; shared machinery for inline and out-of-line slot accessor functions @@ -260,6 +252,58 @@ ;;; the source form to them directly. (defvar *dsd-source-form*) +(defun accessor-definitions (dd defuns) + (if defuns + ;; Return the ordinary toplevel (usually, anyway) defuns + (loop for dsd in (dd-slots dd) + for accessor-name = (dsd-accessor-name dsd) + unless (accessor-inherited-data accessor-name dd) + nconc (dx-let ((key (cons dd dsd))) + (let ((source-form (and (boundp '*dsd-source-form*) + (cdr (assq dsd *dsd-source-form*))))) + `(,@(unless (dsd-read-only dsd) + `((sb-c:xdefun (setf ,accessor-name) :accessor ,source-form (value instance) + ,(slot-access-transform :setf '(instance value) key)))) + (sb-c:xdefun ,accessor-name :accessor ,source-form (instance) + ,(slot-access-transform :read '(instance) key)))))) + ;; Return fragements of code that CLOS can use. + ;; We don't return the toplevel DEFUNs because those generally + ;; perform an unneeded type-check unless in safety 0. + ;; These lambdas don't need to check the instance + ;; because it was already subject to type-based dispatch. + ;; FIXME: it seems like all these fragments should be packed into a single codebob + ;; which will have less overhead than separate blobs. + ;; Afaict, the only way to do that is to return one lambda that returns all the lambdas. + (collect ((result)) + (dolist (dsd (dd-slots dd) (result)) + (binding* ((key (cons dd dsd)) + (name (string (dsd-name dsd))) ; anonymize by stringification + ;; reader and writer are the primitive operations + ((reader writer) (dsd-reader dsd (neq (dd-type dd) 'structure))) + ;; accessor is the global defun + (accessor (dsd-accessor-name dsd))) + (declare (dynamic-extent key)) + (result (if (dsd-read-only dsd) + `(named-lambda (setf ,name) (#1=#:v #2=#:x) + ,@(if (eql (dsd-type dsd) 't) + ;; no typecheck + `((,writer (truly-the ,(dd-name dd) #2#) ,(dsd-index dsd) #1#) #1#) + `(,(slot-access-transform :setf `(#1# (truly-the ,(dd-name dd) #2#)) + key :function)))) + `'(setf ,accessor)) + (if nil ; TODO: policy-based selection perhaps? + `(named-lambda ,name (#2#) + ,(if (and (dsd-always-boundp dsd) (dsd-safe-p dsd)) + ;; Most slots are always-boundp (don't have a BOA constructor + ;; that omits slots) and safe-p (type-safe for reading), + ;; so we can be concise rather than use SLOT-ACCESS-TRANSFORM + ;; plus a rebinding of X with TRULY-THE. + `(,reader (truly-the ,(dd-name dd) #2#) ,(dsd-index dsd)) + ;; Don't check X, but do check the the fetched value. + (slot-access-transform :read `((truly-the ,(dd-name dd) #2#)) + key))) + `',accessor))))))) + ;;; shared logic for host macroexpansion for SB-XC:DEFSTRUCT and ;;; cross-compiler macroexpansion for CL:DEFSTRUCT ;;; This monster has exactly one inline use in the final image, @@ -294,7 +338,7 @@ ;;; So FOO-VAL got compiled on demand. ;;; (declaim (inline !expander-for-defstruct)) -(defun !expander-for-defstruct (null-env-p delayp name-and-options +(defun !expander-for-defstruct (null-env-p optimize-speed delayp name-and-options slot-descriptions expanding-into-code-for) (binding* (((name options) @@ -305,13 +349,16 @@ ;; Rather than hit MAKE-DEFSTRUCT-DESCRIPTION's type-check ;; on the NAME slot, we can be a little more clear. (error "DEFSTRUCT: ~S is not a symbol." name))) - (dd (make-defstruct-description null-env-p name)) + (flagbits (logior #+sb-xc-host (if (member name '(wrapper layout)) +dd-varylen+ 0) + (if null-env-p +dd-nullenv+ 0))) + (dd (make-defstruct-description name flagbits)) (*dsd-source-form* nil) - ((classoid inherits) (parse-defstruct dd options slot-descriptions)) + ((inherits comparators) (parse-defstruct dd options slot-descriptions)) (constructor-definitions (mapcar (lambda (ctor) `(sb-c:xdefun ,(car ctor) - :constructor + :constructor + nil ,@(structure-ctor-lambda-parts dd (cdr ctor)))) (dd-constructors dd))) (print-method @@ -329,11 +376,10 @@ ((not (symbolp fname)) ;; Don't dump the source form into the DD constant; ;; just indicate that there was an expression there. - (setf (dd-printer-fname dd) t))) + (setf (dd-printer-fname dd) 'lambda))) `((defmethod print-object ((,x ,name) ,s) (funcall #',fname ,x ,s ,@(if depthp `(*current-level-in-print*))))))))) - (declare (ignore classoid)) ;; Return a list of forms (if (dd-class-p dd) `(,@(when (eq expanding-into-code-for :target) @@ -352,12 +398,12 @@ ,@(when (eq expanding-into-code-for :target) `(,@(let ((defuns `(,@(awhen (dd-copier-name dd) - `((sb-c:xdefun ,(dd-copier-name dd) :copier (instance) + `((sb-c:xdefun ,(dd-copier-name dd) :copier nil (instance) (copy-structure (the ,(dd-name dd) instance))))) ,@(awhen (dd-predicate-name dd) - `((sb-c:xdefun ,(dd-predicate-name dd) :predicate (object) + `((sb-c:xdefun ,(dd-predicate-name dd) :predicate nil (object) (typep object ',(dd-name dd))))) - ,@(accessor-definitions dd)))) + ,@(accessor-definitions dd t)))) (if (and delayp (not (compiler-layout-ready-p name))) `((sb-impl::%simple-eval ',(cons 'progn defuns) (make-null-lexenv))) @@ -366,7 +412,11 @@ ,@constructor-definitions ,@print-method ;; Various other operations only make sense on the target SBCL. - (%target-defstruct ',dd)))) ; returns NAME + ;; %TARGET-DEFSTRUCT returns NAME + (%target-defstruct ',dd + ,(if optimize-speed + (gen-custom-equalp dd comparators)) + ,@(accessor-definitions dd nil))))) ;; Not DD-CLASS-P ;; FIXME: missing package lock checks `((eval-when (:compile-toplevel :load-toplevel :execute) @@ -384,15 +434,42 @@ ',(dd-doc dd)))))) ',name)))) +(defun gen-custom-equalp (dd comparators) + ;; Process the easiest slots first. + ;; TODO: consecutive word-sized slots should try to use instructions + ;; that compare more than one word at a time. + (collect ((group1) (group2) (group3)) + (mapc (lambda (dsd comparator) + (let ((x `(truly-the ,(dsd-type dsd) (,(dsd-reader dsd nil) a ,(dsd-index dsd)))) + (y `(truly-the ,(dsd-type dsd) (,(dsd-reader dsd nil) b ,(dsd-index dsd))))) + (cond ((member comparator '(= char-equal)) + (group1 `(,comparator ,x ,y))) ; bounded amount of testing + ((member comparator '(bit-vector-=)) + ;; unbounded but not recursive. Try EQ first though + (group2 + `((lambda (x y) (or (eq x y) (bit-vector-= x y))) ,x ,y))) + (t + (group3 `(,comparator ,x ,y)))))) ; recursive + (dd-slots dd) + comparators) + ;; use a string for the name since it's not a global function + `(named-lambda ,(format nil "~A-EQUALP" (dd-name dd)) (a b) + (declare (optimize (sb-c:store-source-form 0) (safety 0)) (type ,(dd-name dd) a b) + (ignorable a b)) ; if zero slots + (and ,@(group1) ,@(group2) ,@(group3))))) + #+sb-xc-host (progn +;; When compiling and loading the cross-compiler, SB-XC:DEFSTRUCT gets +;; a bootstrap definition from src/code/defbangstruct. +;; The old definition has to be uninstalled to avoid a redefinition warning here. (eval-when (:compile-toplevel :load-toplevel :execute) (fmakunbound 'sb-xc:defstruct)) (defmacro sb-xc:defstruct (name-and-options &rest slot-descriptions) "Cause information about a target structure to be built into the cross-compiler." `(progn ,@(!expander-for-defstruct - t nil name-and-options slot-descriptions :host)))) + t nil nil name-and-options slot-descriptions :host)))) (sb-xc:defmacro defstruct (name-and-options &rest slot-descriptions &environment env) @@ -435,11 +512,13 @@ ;; This is about performance, not semantics. Non-toplevel ;; effects happen when they should even if this were to ;; produce the preferred expansion for toplevel. - (delayp (not (or *top-level-form-p* null-env-p)))) + (delayp (not (or *top-level-form-p* null-env-p))) + (optimize-speed + (and (not delayp) (sb-c:policy env (< space 3))))) `(progn - ,@(!expander-for-defstruct - null-env-p delayp name-and-options slot-descriptions - :target)))) + ,@(!expander-for-defstruct null-env-p optimize-speed delayp + name-and-options slot-descriptions + :target)))) ;;;; functions to generate code for various parts of DEFSTRUCT definitions @@ -491,21 +570,22 @@ (let ((name (dsd-accessor-name slot)) (index (dsd-index slot)) (new-value '(value)) + (structure '(structure)) (slot-type `(and ,(dsd-type slot) - ,(dd-element-type defstruct)))) + ,(dd-%element-type defstruct)))) (let ((inherited (accessor-inherited-data name defstruct))) (cond ((not inherited) (stuff `(declaim (inline ,name ,@(unless (dsd-read-only slot) `((setf ,name)))))) - (stuff `(defun ,name (structure) - (declare (type ,ltype structure)) - (the ,slot-type (elt structure ,index)))) + (stuff `(defun ,name ,structure + (declare (type ,ltype . ,structure)) + (the ,slot-type (elt ,(car structure) ,index)))) (unless (dsd-read-only slot) (stuff - `(defun (setf ,name) (,(car new-value) structure) - (declare (type ,ltype structure) (type ,slot-type . ,new-value)) - (setf (elt structure ,index) . ,new-value))))) + `(defun (setf ,name) (,(car new-value) . ,structure) + (declare (type ,ltype . ,structure) (type ,slot-type . ,new-value)) + (setf (elt ,(car structure) ,index) . ,new-value))))) ((not (= (cdr inherited) index)) (style-warn "~@<Non-overwritten accessor ~S does not access ~ slot with name ~S (accessing an inherited slot ~ @@ -610,13 +690,25 @@ requires exactly~;accepts at most~] one argument" keyword syntax-group) (when (dd-print-option dd) (error "~S and ~S may not both be specified" (dd-print-option dd) keyword)) - (setf (dd-print-option dd) keyword (dd-printer-fname dd) arg)) + (setf (dd-flags dd) (logior (if (eq keyword :print-object) +dd-printobj+ +dd-printfun+) + (dd-flags dd)) + (dd-printer-fname dd) arg)) (:type (cond ((member arg '(list vector)) - (setf (dd-type dd) arg (dd-element-type dd) t)) + (setf (dd-type dd) arg (dd-%element-type dd) t)) ((and (listp arg) (eq (first arg) 'vector)) + ;; The spec is self-contradictory about this! + ;; It defines: + ;; type-option::= (:type type) + ;; type --- one of the type specifiers list, vector, or (vector size), + ;; or some other type specifier defined by the implementation to be appropriate. + ;; However the description of the keyword makes it pretty clear that + ;; the option's syntax is (vector /element-type/). + ;; I'm not sure if it's valid to specify (VECTOR *) as the representation. + ;; CLISP thinks it is not, but only signals an error when the constructor + ;; is called. So at minimum it's unportable, if not illegal. (destructuring-bind (elt-type) (cdr arg) - (setf (dd-type dd) 'vector (dd-element-type dd) elt-type))) + (setf (dd-type dd) 'vector (dd-%element-type dd) elt-type))) (t (error "~S is a bad :TYPE for DEFSTRUCT." arg)))) (:named @@ -624,7 +716,8 @@ requires exactly~;accepts at most~] one argument" keyword syntax-group) (:initial-offset (setf (dd-offset dd) arg)) ; FIXME: disallow (:INITIAL-OFFSET NIL) (:pure - (setf (dd-pure dd) arg)) + (setf (dd-flags dd) (logior (logandc2 (dd-flags dd) +dd-pure+) + (if arg +dd-pure+ 0)))) (t (error "unknown DEFSTRUCT option:~% ~S" option))) seen-options)) @@ -636,7 +729,8 @@ requires exactly~;accepts at most~] one argument" keyword syntax-group) (declare (type (unsigned-byte #.(length +dd-option-names+)) seen-options)) (dolist (option options) (if (eq option :named) - (setf named-p t (dd-named dd) t) + (setf named-p t + (dd-flags dd) (logior (dd-flags dd) +dd-named+)) (setq seen-options (parse-1-dd-option (cond ((consp option) option) @@ -667,11 +761,11 @@ requires exactly~;accepts at most~] one argument" keyword syntax-group) ;; CLHS - "The structure can be :named only if the type SYMBOL ;; is a subtype of the supplied element-type." (multiple-value-bind (winp certainp) - (subtypep 'symbol (dd-element-type dd)) + (subtypep 'symbol (dd-%element-type dd)) (when (and (not winp) certainp) (error ":NAMED option is incompatible with element ~ type ~/sb-impl:print-type-specifier/" - (dd-element-type dd)))) + (dd-%element-type dd)))) (when (dd-predicate-name dd) (error ":PREDICATE cannot be used with :TYPE ~ unless :NAMED is also specified."))) @@ -731,15 +825,23 @@ unless :NAMED is also specified."))) (let ((super (compiler-layout-or-lose (or (first (dd-include dd)) 'structure-object)))) (concatenate 'simple-vector - (layout-inherits super) (vector super))))) + (wrapper-inherits super) (vector super))))) (proto-classoid (if (dd-class-p dd) + ;; The classoid needs a layout whereby to convey inheritance. + ;; Classoids only store a *direct* superclass list. + ;; Both the layout and classoid are throwaway objects. + ;; It's probably too dangerous to stack-allocate, because references + ;; could leak from the type cache machinery. (let* ((classoid (make-structure-classoid :name (dd-name dd))) - (layout (make-layout (hash-layout-name (dd-name dd)) - classoid :inherits inherits))) - (setf (layout-invalid layout) nil - (classoid-layout classoid) layout) - classoid)))) + (layout (make-temporary-wrapper (hash-layout-name (dd-name dd)) + classoid inherits))) + (setf (classoid-wrapper classoid) layout) + classoid))) + (ancestor-slot-comparator-list)) + #+sb-xc-host + (when (member (dd-name dd) '(pathname logical-pathname)) + (setf (dd-alternate-metaclass dd) '(t built-in-classoid nil))) ;; Type parsing should be done assuming that prototype classoid ;; exists, which fixes a problem when redefining a DEFTYPE which ;; appeared to be a raw slot. e.g. @@ -748,27 +850,51 @@ unless :NAMED is also specified."))) ;; Also make self-referential definitions not signal PARSE-UNKNOWN-TYPE ;; on slots whose :TYPE option allows an instance of itself (when (dd-include dd) - (frob-dd-inclusion-stuff proto-classoid dd option-bits)) + (setq ancestor-slot-comparator-list + (frob-dd-inclusion-stuff proto-classoid dd option-bits))) (when (stringp (car slot-descriptions)) (setf (dd-doc dd) (pop slot-descriptions))) - (dolist (slot-description slot-descriptions) - (parse-1-dsd proto-classoid dd slot-description)) - (values proto-classoid inherits))) + (collect ((comparator-list ancestor-slot-comparator-list)) + (dolist (slot-description slot-descriptions) + (let ((comparator + (nth-value 1 (parse-1-dsd proto-classoid dd slot-description)))) + (comparator-list comparator))) + (when (dd-class-p dd) + (multiple-value-bind (bitmap any-raw) (calculate-dd-bitmap dd) + (when any-raw (setf (dd-%element-type dd) '*)) + (setf (dd-bitmap dd) bitmap))) + (values inherits (comparator-list))))) + +(defmacro dd-has-raw-slot-p (dd) `(eq (dd-%element-type ,dd) '*)) ;;;; stuff to parse slot descriptions +;;; Decide whether TYPE as stored in a structure can be a raw slot. +;;; Return the index of the matching RAW-SLOT-DATA if it should be, NIL if not. +(defun choose-raw-slot-representation (ctype) + ;; If TYPE isn't a subtype of NUMBER, it can't go in a raw slot. + ;; In the negative case (which is most often), doing 1 SUBTYPEP test + ;; beats doing 5 or 6. + (when (and (csubtypep ctype (specifier-type 'number)) + ;; FIXNUMs and smaller go in tagged slots, not raw slots + (not (csubtypep ctype (specifier-type 'fixnum)))) + (dotimes (i (length *raw-slot-data*)) + (let ((data (svref *raw-slot-data* i))) + (when (csubtypep ctype (specifier-type (raw-slot-data-raw-type data))) + (return i)))))) + ;;; Parse a slot description for DEFSTRUCT, add it to the description ;;; and return it. If supplied, INCLUDED-SLOT is used to get the default, ;;; type, and read-only flag for the new slot. (defun parse-1-dsd (proto-classoid defstruct spec &optional included-slot &aux accessor-name (always-boundp t) (safe-p t) - rsd-index index) + ctype rsd-index index) #-sb-xc-host (declare (muffle-conditions style-warning)) (multiple-value-bind (name default default-p type type-p read-only ro-p) (typecase spec (symbol (typecase spec - ((or null (member :conc-name :constructor :copier :predicate :named)) + ((member nil :conc-name :constructor :copier :predicate :named) (warn "slot name of ~S indicates probable syntax error in DEFSTRUCT" spec)) (keyword (style-warn "slot name of ~S indicates possible syntax error in DEFSTRUCT" spec))) @@ -848,6 +974,21 @@ unless :NAMED is also specified."))) (setf type (cond ((not type-p) inherited-type) ((eq inherited-type t) type) (t `(and ,inherited-type ,type))))) + + #+sb-xc-host + ;; Test whether the type can hold NIL. This avoids a bootstrapping + ;; problem involving forward references to undefined types, + ;; because we want never to pass unknown types into CROSS-TYPEP. + ;; But also, don't call SB-XC:TYPEP on a type-specifier because it does + ;; not receive a type-context which specifies the proto-classoid. + (when (and (typep type '(cons (eql or))) (member 'null type)) + (setq ctype *universal-type*)) ; a harmless lie + + (unless ctype + (let ((context (make-type-context type proto-classoid + +type-parse-cache-inhibit+))) + (setq ctype (specifier-type type context)))) ; Parse once only + (cond (included-slot (cond ((not ro-p) (setq read-only (dsd-read-only included-slot))) @@ -861,13 +1002,12 @@ unless :NAMED is also specified."))) index (dsd-index included-slot)) (when (and safe-p (not (equal type (dsd-type included-slot))) - (not (sb-xc:subtypep (dsd-type included-slot) type))) + (not (subtypep (dsd-type included-slot) type))) (setf safe-p nil))) (t ;; Compute the index of this DSD. First decide whether the slot is raw. (setf rsd-index (and (eq (dd-type defstruct) 'structure) - (structure-raw-slot-data-index - type proto-classoid))) + (choose-raw-slot-representation ctype))) (let ((n-words (if rsd-index (let ((rsd (svref *raw-slot-data* rsd-index))) @@ -902,46 +1042,48 @@ unless :NAMED is also specified."))) (when (or rsd-index (neq (dd-type defstruct) 'structure)) (setf always-boundp t safe-p nil))) ; "demote" to unsafe. - (let ((dsd (make-dsd name type accessor-name - (pack-dsd-bits index read-only safe-p - always-boundp rsd-index) - default))) - #-sb-xc-host + ;; Check for writable slots in pure structures + #+nil + (when (dd-pure defstruct) + (unless read-only + (format t "~&structure ~s slot ~s is writable" defstruct name))) + + (let* ((gc-ignorable + (csubtypep ctype + (specifier-type '(or fixnum boolean character + #+64-bit single-float)))) + (dsd (make-dsd name type accessor-name + (pack-dsd-bits index read-only safe-p + always-boundp gc-ignorable + rsd-index) + default))) (push (cons dsd spec) *dsd-source-form*) (setf (dd-slots defstruct) (nconc (dd-slots defstruct) (list dsd))) - dsd))) - -;;; When a value of type TYPE is stored in a structure, should it be -;;; stored in a raw slot? Return the index of the matching RAW-SLOT-DATA -;;; if TYPE should be stored in a raw slot, or NIL if not. -(defun structure-raw-slot-data-index (slot-type proto-classoid) - ;; If TYPE isn't a subtype of NUMBER, it can't go in a raw slot. - ;; In the negative case (which is most often), doing 1 SUBTYPEP test - ;; beats doing 5 or 6. - - ;; First test whether the type can hold NIL. This avoids a bootstrapping - ;; problem involving forward references to undefined types, - ;; because we want never to pass unknown types into CROSS-TYPEP. - ;; But also, don't call SB-XC:TYPEP on a type-specifier because it does - ;; not receive a type-context which specifies the proto-classoid. - #+sb-xc-host - (when (and (typep slot-type '(cons (eql or))) (member 'null slot-type)) - (return-from structure-raw-slot-data-index nil)) - - (let* ((context (make-type-context slot-type proto-classoid nil)) - (ctype (specifier-type slot-type context))) ; Parse once only - (when (and (csubtypep ctype (specifier-type 'number)) - ;; FIXNUMs and smaller go in tagged slots, not raw slots - (not (csubtypep ctype (specifier-type 'fixnum)))) - (dotimes (i (length *raw-slot-data*)) - (let ((data (svref *raw-slot-data* i))) - (when (csubtypep ctype (specifier-type (raw-slot-data-raw-type data))) - (return i))))))) + (let ((comparator + ;; this is enough specialization for now + (cond ((csubtypep ctype (specifier-type 'character)) 'char-equal) + ((csubtypep ctype (specifier-type 'number)) '=) + ((csubtypep ctype (specifier-type 'bit-vector)) 'bit-vector-=) + (t 'equalp)))) + (values dsd comparator))))) (defun typed-structure-info-or-lose (name) (or (info :typed-structure :info name) (error ":TYPE'd DEFSTRUCT ~S not found for inclusion." name))) +(defmacro dd-element-type (dd) + `(case (dd-type ,dd) + (vector + ;; %ELEMENT-TYPE might actually be * which is weird + ;; but seems to mostly work. I suspect that it should not. + (dd-%element-type ,dd)) + (t + ;; In theory we have the ability to represent that all slots + ;; of a classoid structure are of type SB-VM:WORD (for example), + ;; but in practice that is not useful. + ;; Just don't return * which is not a type specifier. + t))) + ;;; Process any included slots pretty much like they were specified. ;;; Also inherit various other attributes. (defun frob-dd-inclusion-stuff (proto-classoid dd option-bits) @@ -949,7 +1091,7 @@ unless :NAMED is also specified."))) (let* ((type (dd-type dd)) (included-structure (if (dd-class-p dd) - (layout-info (compiler-layout-or-lose included-name)) + (wrapper-info (compiler-layout-or-lose included-name)) (typed-structure-info-or-lose included-name)))) ;; checks on legality @@ -963,8 +1105,8 @@ unless :NAMED is also specified."))) ;; It's not particularly well-defined to :INCLUDE any of the ;; CMU CL INSTANCE weirdosities like CONDITION or ;; GENERIC-FUNCTION, and it's certainly not ANSI-compliant. - (let* ((included-layout (classoid-layout included-classoid)) - (included-dd (layout-info included-layout))) + (let* ((included-layout (classoid-wrapper included-classoid)) + (included-dd (wrapper-dd included-layout))) (when (dd-alternate-metaclass included-dd) (error "can't :INCLUDE class ~S (has alternate metaclass)" included-name))))) @@ -989,33 +1131,38 @@ unless :NAMED is also specified."))) ;; FIXME: This POSITION call should be foldable without read-time eval ;; since literals are immutable, and +DD-OPTION-NAMES+ was initialized ;; from a literal. - (unless (logbitp #.(position :pure +dd-option-names+) option-bits) - (setf (dd-pure dd) (dd-pure included-structure)))) + (when (and (dd-pure included-structure) + (not (logbitp #.(position :pure +dd-option-names+) option-bits))) + (setf (dd-flags dd) (logior (dd-flags dd) +dd-pure+)))) (setf (dd-inherited-accessor-alist dd) (dd-inherited-accessor-alist included-structure)) - (dolist (included-slot (dd-slots included-structure)) - (let* ((included-name (dsd-name included-slot)) - (modified (or (find included-name modified-slots - :key (lambda (x) (if (atom x) x (car x))) - :test #'string=) - `(,included-name)))) - ;; We stash away an alist of accessors to parents' slots - ;; that have already been created to avoid conflicts later - ;; so that structures with :INCLUDE and :CONC-NAME (and - ;; other edge cases) can work as specified. - (when (dsd-accessor-name included-slot) - ;; the "oldest" (i.e. highest up the tree of inheritance) - ;; will prevail, so don't push new ones on if they - ;; conflict. - (pushnew (cons (dsd-accessor-name included-slot) - (dsd-index included-slot)) - (dd-inherited-accessor-alist dd) - :test #'eq :key #'car)) - (let ((new-slot (parse-1-dsd proto-classoid dd modified included-slot))) - (when (and (dsd-safe-p included-slot) (not (dsd-safe-p new-slot))) - ;; XXX: notify? - ))))))) + (collect ((comparator-list)) + (dolist (included-slot (dd-slots included-structure) + (comparator-list)) + (let* ((included-name (dsd-name included-slot)) + (modified (or (find included-name modified-slots + :key (lambda (x) (if (atom x) x (car x))) + :test #'string=) + `(,included-name)))) + ;; We stash away an alist of accessors to parents' slots + ;; that have already been created to avoid conflicts later + ;; so that structures with :INCLUDE and :CONC-NAME (and + ;; other edge cases) can work as specified. + (when (dsd-accessor-name included-slot) + ;; the "oldest" (i.e. highest up the tree of inheritance) + ;; will prevail, so don't push new ones on if they + ;; conflict. + (pushnew (cons (dsd-accessor-name included-slot) + (dsd-index included-slot)) + (dd-inherited-accessor-alist dd) + :test #'eq :key #'car)) + (multiple-value-bind (new-slot comparator) + (parse-1-dsd proto-classoid dd modified included-slot) + (comparator-list comparator) + (when (and (dsd-safe-p included-slot) (not (dsd-safe-p new-slot))) + ;; XXX: notify? + )))))))) ;;;; various helper functions for setting up DEFSTRUCTs @@ -1029,7 +1176,7 @@ unless :NAMED is also specified."))) (super (if include (compiler-layout-or-lose (first include)) - (classoid-layout (find-classoid + (classoid-wrapper (find-classoid (or (first superclass-opt) 'structure-object)))))) (case (dd-name info) @@ -1037,22 +1184,24 @@ unless :NAMED is also specified."))) ;; STREAM is an abstract class and you can't :include it, ;; so the inheritance has to be hardcoded. (concatenate 'simple-vector - (layout-inherits super) - (vector super (classoid-layout (find-classoid 'stream))))) + (wrapper-inherits super) + (vector super (classoid-wrapper (find-classoid 'stream))))) ((fd-stream) ; Similarly, FILE-STREAM is abstract (concatenate 'simple-vector - (layout-inherits super) + (wrapper-inherits super) (vector super - (classoid-layout (find-classoid 'file-stream))))) + (classoid-wrapper (find-classoid 'file-stream))))) ((sb-impl::string-input-stream ; etc sb-impl::string-output-stream sb-impl::fill-pointer-output-stream) (concatenate 'simple-vector - (layout-inherits super) + (wrapper-inherits super) (vector super - (classoid-layout (find-classoid 'string-stream))))) + (classoid-wrapper (find-classoid 'string-stream))))) + (pathname (vector (find-layout 't))) + (logical-pathname (vector (find-layout 't) (find-layout 'pathname))) (t (concatenate 'simple-vector - (layout-inherits super) + (wrapper-inherits super) (vector super)))))) ;;; Do miscellaneous (LOAD EVAL) time actions for the structure @@ -1065,59 +1214,45 @@ unless :NAMED is also specified."))) (multiple-value-bind (classoid layout old-layout) (ensure-structure-class dd inherits "current" "new") (cond ((not old-layout) - (unless (eq (classoid-layout classoid) layout) + (unless (eq (classoid-wrapper classoid) layout) (register-layout layout))) (t (%redefine-defstruct classoid old-layout layout) - (let ((old-dd (layout-info old-layout))) + (let ((old-dd (wrapper-info old-layout))) (when (defstruct-description-p old-dd) (dolist (slot (dd-slots old-dd)) (fmakunbound (dsd-accessor-name slot)) (unless (dsd-read-only slot) (fmakunbound `(setf ,(dsd-accessor-name slot))))))) - (setq layout (classoid-layout classoid)))) - (setf (find-classoid (dd-name dd)) classoid) + (setq layout (classoid-wrapper classoid)))) + ;; Don't want to (setf find-classoid) on a a built-in-classoid + (unless (and (built-in-classoid-p classoid) + (eq (find-classoid (dd-name dd) nil) classoid)) + (setf (find-classoid (dd-name dd)) classoid)) (when source-location (setf (classoid-source-location classoid) source-location)))) -;;; Return a form accessing the writable place used for the slot -;;; described by DD and DSD in the INSTANCE (a form). -(defun %accessor-place-form (dd dsd instance) - (let (;; Compute REF even if not using it, as a sanity-check of DD-TYPE. - (ref (ecase (dd-type dd) - (structure '%instance-ref) - (funcallable-structure '%funcallable-instance-info) - (list 'nth) - (vector 'aref))) - (index (dsd-index dsd)) - (rsd (dsd-raw-slot-data dsd))) - (cond (rsd - (list (raw-slot-data-accessor-name rsd) instance index)) - ((eq ref 'nth) - (list ref index instance)) - (t - (list ref instance index))))) - -;;; Return the transform of conceptual FUNCTION one of {:READ,:WRITE,:SETF} +;;; Return the transform of OPERATION which is either :READ or :SETF. ;;; as applied to ARGS, given SLOT-KEY which is a cons of a DD and a DSD. +;;; FUN-OR-MACRO, which is used only for the :SETF operation, +;;; indicates whether the argument order corresponds to +;;; (funcall #'(setf mystruct-myslot) newval s) ; :FUNCTION +;;; versus +;;; (setf (mystruct-myslot s) newval) ; :MACRO ;;; Return NIL on failure. -(defun slot-access-transform (function args slot-key) - (when (consp args) ; need at least one arg - (let* ((dd (car slot-key)) - (dsd (cdr slot-key)) - ;; optimistically compute PLACE before checking length of ARGS - ;; because we expect success, and this unifies the three cases. - ;; :SETF is like an invocation of the SETF macro - newval is - ;; the second arg, but :WRITER is #'(SETF fn) - newval is first. - (place - (%accessor-place-form - dd dsd `(the ,(dd-name dd) - ,(car (if (eq function :write) (cdr args) args))))) - (type-spec (dsd-type dsd))) - (if (eq function :read) - (when (singleton-p args) +(defun slot-access-transform (operation args slot-key &optional (fun-or-macro :macro)) + (binding* ((dd (car slot-key)) + (dsd (cdr slot-key)) + ((reader writer) (dsd-reader dsd (neq (dd-type dd) 'structure))) + (type-spec (dsd-type dsd)) + (index (dsd-index dsd))) + (ecase operation + (:read + (when (singleton-p args) + (let* ((instance-form `(the ,(dd-name dd) ,(car args))) + (place `(,reader ,instance-form ,index))) ;; There are 4 cases of {safe,unsafe} x {always-boundp,possibly-unbound} ;; If unsafe - which implies TYPE-SPEC other than type T - then we must ;; check the type on each read. Assuming that type-checks reject @@ -1126,28 +1261,37 @@ unless :NAMED is also specified."))) `(the ,type-spec ,place)) (t (unless (dsd-always-boundp dsd) - (setf place `(the* ((not (satisfies sb-vm::unbound-marker-p)) - :context (:struct-read ,(dd-name dd) . ,(dsd-name dsd))) - ,place))) - (if (eq type-spec t) place `(the* (,type-spec :derive-type-only t) ,place))))) - (when (singleton-p (cdr args)) - (let ((inverse (info :setf :expander (car place)))) - (flet ((check (newval) - (if (eq type-spec t) - newval - `(the* (,type-spec :context - (:struct ,(dd-name dd) . ,(dsd-name dsd))) - ,newval)))) - (ecase function - (:setf - ;; Instance setters take newval last, which matches - ;; the order in which a use of SETF has them. - `(,inverse ,@(cdr place) ,(check (second args)))) - (:write - ;; The call to #'(SETF fn) had newval first. - ;; We need to preserve L-to-R evaluation. - (once-only ((new (first args))) - `(,inverse ,@(cdr place) ,(check new)))))))))))) + (setf place + `(the* ((not (satisfies sb-vm::unbound-marker-p)) + :context (:struct-read ,(dd-name dd) . ,(dsd-name dsd))) + ,place))) + (if (eq type-spec t) place + `(the* (,type-spec :derive-type-only t) ,place))))))) + (:setf + ;; The primitive object slot setting vops take newval last, which matches + ;; the order in which a use of SETF has them, but because the vops + ;; do not return anything, we have to bind both arguments. + (when (and (listp args) (singleton-p (cdr args))) + (multiple-value-bind (newval-form instance-form) + (ecase fun-or-macro + (:function (values (first args) (second args))) + (:macro (values (second args) (first args)))) + (if (eq fun-or-macro :function) + ;; This used only for source-transforming (funcall #'(setf myslot) ...). + ;; (SETF x) writer functions have been defined as source-transforms instead of + ;; inline functions, which improved the semantics around clobbering defstruct + ;; writers with random DEFUNs either deliberately or accidentally. + ;; Since users can't define source-transforms (not portably anyway), + ;; we can easily discern which functions were system-generated. + `(let ((#2=#:val + #4=,(if (eq type-spec t) + newval-form + `(the* (,type-spec :context (:struct ,(dd-name dd) . ,(dsd-name dsd))) + ,newval-form))) + (#1=#:instance #3=(the ,(dd-name dd) ,instance-form))) + (,writer #1# ,index #2#) + #2#) + `(let ((#1# #3#) (#2# #4#)) (,writer #1# ,index #2#) #2#)))))))) ;;; Apply TRANSFORM - a special indicator stored in :SOURCE-TRANSFORM ;;; for a DEFSTRUCT copier, accessor, or predicate - to SEXPR. @@ -1168,8 +1312,8 @@ unless :NAMED is also specified."))) (:predicate `(sb-c::%instance-typep ,arg ',type)) (:copier `(copy-structure (the ,type ,arg))))))) (t - (slot-access-transform (if (consp name) :write :read) - (cdr sexpr) transform))))) + (slot-access-transform (if (consp name) :setf :read) + (cdr sexpr) transform :function))))) (values result (not result)))) ;;; Return a LAMBDA form which can be used to set a slot @@ -1184,7 +1328,7 @@ unless :NAMED is also specified."))) ;;; the same for subclasses. FIXME: maybe rename UNDEFINE-FUN-NAME to ;;; UNDECLARE-FUNCTION-NAME? (defun undeclare-structure (classoid subclasses-p) - (let ((info (layout-info (classoid-layout classoid)))) + (let ((info (wrapper-%info (classoid-wrapper classoid)))) (when (defstruct-description-p info) (let ((type (dd-name info))) (clear-info :type :compiler-layout type) @@ -1201,39 +1345,20 @@ unless :NAMED is also specified."))) ;; references are unknown types. (values-specifier-type-cache-clear))) (when subclasses-p - (let ((subclasses (classoid-subclasses classoid))) - (when subclasses - (collect ((subs)) - (dohash ((classoid layout) - subclasses - :locked t) - (declare (ignore layout)) - (undeclare-structure classoid nil) - (subs (classoid-proper-name classoid))) + (collect ((subs)) + (do-subclassoids ((classoid wrapper) classoid) + (declare (ignore wrapper)) + (undeclare-structure classoid nil) + (subs (classoid-proper-name classoid))) ;; Is it really necessary to warn about ;; undeclaring functions for subclasses? - (when (subs) - (warn "undeclaring functions for old subclasses ~ - of ~S:~% ~S" - (classoid-name classoid) - (subs)))))))) + (when (subs) + (warn "undeclaring functions for old subclasses of ~S:~% ~S" + (classoid-name classoid) (subs)))))) ;;; core compile-time setup of any class with a LAYOUT, used even by ;;; !DEFSTRUCT-WITH-ALTERNATE-METACLASS weirdosities -(defun %compiler-set-up-layout (dd - &optional - ;; Several special cases - ;; (STRUCTURE-OBJECT itself, and - ;; structures with alternate - ;; metaclasses) call this function - ;; directly, and they're all at the - ;; base of the instance class - ;; structure, so this is a handy - ;; default. (But note - ;; FUNCALLABLE-STRUCTUREs need - ;; assistance here) - (inherits (vector (find-layout t)))) - +(defun %compiler-set-up-layout (dd inherits) (multiple-value-bind (classoid layout old-layout) (multiple-value-bind (clayout clayout-p) (info :type :compiler-layout (dd-name dd)) @@ -1245,19 +1370,22 @@ unless :NAMED is also specified."))) "the most recently loaded" :compiler-layout clayout)) (cond (old-layout - (undeclare-structure (layout-classoid old-layout) + (undeclare-structure (wrapper-classoid old-layout) (and (classoid-subclasses classoid) (not (eq layout old-layout)))) - (setf (layout-invalid layout) nil) + (setf (wrapper-invalid layout) nil) ;; FIXME: it might be polite to hold onto old-layout and ;; restore it at the end of the file. -- RMK 2008-09-19 ;; (International Talk Like a Pirate Day). (warn "~@<Clobbering the compiler's idea of the layout of ~A.~:@>" classoid)) (t - (unless (eq (classoid-layout classoid) layout) + (unless (eq (classoid-wrapper classoid) layout) (register-layout layout :invalidate nil)) - (setf (find-classoid (dd-name dd)) classoid))) + ;; Don't want to (setf find-classoid) on a a built-in-classoid + (unless (and (built-in-classoid-p classoid) + (eq (find-classoid (dd-name dd) nil) classoid)) + (setf (find-classoid (dd-name dd)) classoid)))) ;; At this point the class should be set up in the INFO database. ;; But the logic that enforces this is a little tangled and @@ -1273,8 +1401,8 @@ unless :NAMED is also specified."))) (dolist (ctor (dd-constructors dd)) (setf (info :function :source-transform (car ctor)) info)))) -;;; Do (COMPILE LOAD EVAL)-time actions for the normal (not -;;; ALTERNATE-LAYOUT) DEFSTRUCT described by DD. +;;; Do (COMPILE LOAD EVAL)-time actions for the structure described by DD +;;; which may be a "normal" defstruct or an alternate-metaclass struct. ;;; This includes generation of a style-warning about previously compiled ;;; calls to the accessors and/or predicate that weren't inlined. (defun %compiler-defstruct (dd inherits) @@ -1332,7 +1460,7 @@ unless :NAMED is also specified."))) accessor-name (dsd-name dsd)))))))) - (awhen (remove-if-not #'sb-c::emitted-full-call-count fnames) + (awhen (remove-if-not #'sb-impl::emitted-full-call-count fnames) (sb-c:compiler-style-warn 'sb-c:inlining-dependency-failure ;; This message omits the http://en.wikipedia.org/wiki/Serial_comma @@ -1360,7 +1488,7 @@ or they must be declared locally notinline at each call site.~@:>" (dolist (name (intersection onames nnames)) (let ((os (find name oslots :key #'dsd-name :test #'string=)) (ns (find name nslots :key #'dsd-name :test #'string=))) - (unless (sb-xc:subtypep (dsd-type ns) (dsd-type os)) + (unless (subtypep (dsd-type ns) (dsd-type os)) (retyped name)) (unless (and (= (dsd-index os) (dsd-index ns)) (eq (dsd-raw-type os) (dsd-raw-type ns))) @@ -1390,16 +1518,34 @@ or they must be declared locally notinline at each call site.~@:>" ;;; Return true if destructively modifying OLD-LAYOUT into NEW-LAYOUT ;;; would be possible in as much as it won't harm the garbage collector. ;;; Harm potentially results from turning a raw word into a tagged word. +;;; There are additional mutations which would be permissible but don't +;;; strike me as important - e.g. permitting a fixnum slot to become type T +;;; is permissible, but the fixnum may or may not be marked as tagged +;;; in the bitmap, depending on whether any raw slot exists. +;;; I can't imagine that many users will complain that they can no longer +;;; incompatibly redefine defstructs involving raw slots. +;;; Additionally, it is no longer possible to RECKLESSLY-CONTINUE on a defstruct +;;; if the number of words in the layout would differ due to extra ID words, +;;; but given that it was already not possible if the bitmaps differ, +;;; it does not seem a big sacrifice to disallow redefining structures +;;; at depthoids in excess of 7 (LAYOUT-ID-VECTOR-FIXED-CAPACITY) unless +;;; both the old and new structure are at the same depthoid. +#-sb-xc-host (defun mutable-layout-p (old-layout new-layout) - (if (layout-info old-layout) - (let ((old-bitmap (layout-bitmap old-layout)) - (new-bitmap (layout-bitmap new-layout))) - (aver (= old-bitmap (dd-bitmap (layout-info old-layout)))) - (aver (= new-bitmap (dd-bitmap (layout-info new-layout)))) - (dotimes (i (dd-length (layout-info old-layout)) t) - (when (and (logbitp i new-bitmap) ; a tagged (i.e. scavenged) slot - (not (logbitp i old-bitmap))) ; that was opaque bits - (return nil)))) + (declare (type wrapper old-layout new-layout)) + (if (wrapper-info old-layout) + (let ((old-bitmap (wrapper-bitmap old-layout)) + (new-bitmap (%layout-bitmap new-layout))) + ;; The number of extra ID words has to match, as does the number of bitmap + ;; words, or else GC will croak when parsing the bitmap. + (and (= (calculate-extra-id-words (wrapper-depthoid old-layout)) + (calculate-extra-id-words (wrapper-depthoid new-layout))) + (= (bitmap-nwords (wrapper-friend new-layout)) + (bitmap-nwords (wrapper-friend old-layout))) + (dotimes (i (dd-length (wrapper-dd old-layout)) t) + (when (and (logbitp i new-bitmap) ; a tagged (i.e. scavenged) slot + (not (logbitp i old-bitmap))) ; that was opaque bits + (return nil))))) t)) ;;; This function is called when we are incompatibly redefining a @@ -1408,7 +1554,8 @@ or they must be declared locally notinline at each call site.~@:>" ;;; be used. (defun %redefine-defstruct (classoid old-layout new-layout) (declare (type classoid classoid) - (type layout old-layout new-layout)) + (type wrapper old-layout new-layout)) + (declare (ignorable old-layout)) ; for host (let ((name (classoid-proper-name classoid))) (restart-case (error "~@<attempt to redefine the ~S class ~S incompatibly with the current definition~:@>" @@ -1421,6 +1568,7 @@ or they must be declared locally notinline at each call site.~@:>" already-loaded code and instances.~@:>" name)) (register-layout new-layout)) + #-sb-xc-host (recklessly-continue () :test (lambda (c) (declare (ignore c)) @@ -1436,53 +1584,146 @@ or they must be declared locally notinline at each call site.~@:>" ;; I hope you know what you're doing..." (register-layout new-layout :invalidate nil - :destruct-layout old-layout)))) + :modify old-layout)))) (values)) +(defun dd-custom-gc-method-p (dd) + (cond ((eq (dd-name dd) 'sb-lockless::list-node) t) + ((dd-include dd) + (dd-custom-gc-method-p + (wrapper-info (compiler-layout-or-lose (car (dd-include dd)))))))) + ;;; Compute DD's bitmap, storing 1 for each tagged word. -;;; The bitmap should be stored as a negative fixnum in two cases: -;;; (1) if the positive value is a bignum but the negative is a fixnum. -;;; (2) if there are no raw slots at all. -;;; Example: given (DEFSTRUCT S A B C), the computed bitmap is #b11111 - -;;; one bit for the layout; one each for A, B, C; and one for padding. -;;; Whether this is stored as 31 or -1 is mostly immaterial, -;;; but -1 is preferable because GC has a special case for it. -;;; Suppose instead we have 1 untagged word followed by N tagged words -;;; for N > n-fixnum-bits. The computed bitmap is #b111...11101 -;;; but the sign-extended value is -3, which is a fixnum. -;;; If both the + and - values are fixnums, and raw slots are present, -;;; we'll choose the positive value. -(defun dd-bitmap (dd) - ;; With compact instances, LAYOUT is not reflected in the bitmap. - ;; Without compact instances, the 0th bitmap bit (for the LAYOUT) is always 1. - ;; In neither case is the place for the layout represented in in DD-SLOTS. - (let ((bitmap sb-vm:instance-data-start)) +;;; The GC can parse signed fixnums and bignums, with which we can +;;; represent an unlimited number of "&rest" slots all with the same +;;; nature - tagged or raw. If REST is :TAGGED or :UNTAGGED, it +;;; specifies a particular nature. If :UNSPECIFIC, then we sign-extend +;;; from the last specified slot which tends to reduce the bitmap to +;;; -1 in the case of everything being tagged, (or -2 if non-compact +;;; header), or a small positive fixnum if the last is untagged. +;;; +;;; Bit indices correspond to physical word indices excluding +;;; the header word. So the least-significant bit of a bitmap is +;;; always the word just after the instance header word. +;;; +;;; Examples: (Legend: u=untaggged slot, t=tagged slot) +;;; +;;; logical arithmetic +;;; bitmap value +;;; Funcallable object: +;;; Non-compact header: #b...1100 -4 +;;; word0: header +;;; word1: (*) entry address +;;; word2: (u) layout +;;; word3: (t) implementation-fun +;;; word4: (t) tagged slots ... +;;; Compact header: #b...1000 -7 +;;; word0: header/layout +;;; word1: (*) entry address +;;; word2: (u) machine instructions +;;; word3: (u) machine instructions +;;; word4: (t) implementation-fun +;;; word5: (t) tagged slots ... +;;; (*) entry address can be treated as either tagged or raw. +;;; For some architectures it has a lowtag, but points to +;;; read-only space. For others it is a fixnum. +;;; In either case the GC need not observe the value. +;;; +;;; Ordinary instance with only tagged slots: +;;; Non-compact header: #b...1110 -2 +;;; word0: header +;;; word1: (u) layout +;;; word2: (t) tagged slots ... +;;; Compact header: #b...1111 -1 +;;; word0: header/layout +;;; word1: (t) tagged slots ... +;;; Ordinary instance with only raw slots slots: +;;; [this also includes objects whose slots all have types +;;; ignorable by GC such as fixum/character] +;;; Non-compact header: #b...0000 0 +;;; word0: header +;;; word1: (u) layout +;;; word2: (u) raw slots ... +;;; Compact header: #b...0000 0 +;;; word0: header/layout +;;; word1: (u) raw slots ... +;;; +;;; Notes: +;;; 1. LAYOUT has to be scanned separately regardless of where stored. +;;; (compact header or not). Hence it is regarded as an untagged slot. +;;; 2. For funcallable objects these examples are exhaustive of all +;;; possible bitmaps. The instance length can be anything, +;;; but untagged slots are not generally supported. +;;; For ordinary instance the examples are merely illustrative. +;;; +(defun calculate-dd-bitmap (dd &optional (rest :unspecific)) + (declare (type (member :unspecific :tagged :untagged) rest)) + #+sb-xc-host + (when (eq (dd-name dd) 'layout) + (setf rest :untagged)) + #-compact-instance-header + (when (eq (car (dd-alternate-metaclass dd)) 'function) + ;; There is only one possible bitmap, which excludes LAYOUT from tagged slots + (return-from calculate-dd-bitmap standard-gf-primitive-obj-layout-bitmap)) + ;; Compute two masks with a 1 bit for each dsd-index which contains a descriptor. + ;; The "mininal" bitmap contains a 1 for each slot which *must* be scanned in GC, + ;; and the "maximal" bitmap contains a 1 for each which *may* be scanned. + ;; If a non-raw slot type can be ignored - such as (OR FIXNUM NULL), then it + ;; sets a 1 in the maximal bitmap but not in the minimal bitmap. + ;; Note that the GC can always add one slot for a stable hash, but that slot + ;; can only hold a fixnum, so need not be traced even though it is a descriptor. + (let ((n-bits (dd-length dd)) + (any-raw) + (maximal-bitmap 0) + (minimal-bitmap 0)) (dolist (slot (dd-slots dd)) - (when (eql t (dsd-raw-type slot)) - (setf bitmap (logior bitmap (ash 1 (dsd-index slot)))))) - ;; The garbage collector can add one more word, but it doesn't need - ;; to be accounted for in the bitmap. - ;; If the bitmap is -1 ("all tagged"), we leave it alone; if a positive - ;; number, the added trailing slot can be regarded as untagged. - (let* ((length (dd-length dd)) - (n-bits (logior length 1))) - (when (evenp length) ; Add padding word if necessary. - (setq bitmap (logior bitmap (ash 1 length)))) - (when (and (logbitp (1- n-bits) bitmap) - ;; Bitmap of -1 implies that all slots are tagged, - ;; and no extraordinary GC treatment is needed. - ;; If all are tagged but any special treatment is required, - ;; then the bitmap can't be -1. - (named-let admits-bitmap-optimization ((dd dd)) - (cond ((eq (dd-name dd) 'list-node) nil) - ((not (dd-include dd)) t) - ((admits-bitmap-optimization - (find-defstruct-description (car (dd-include dd)))))))) - (let ((sign-ext (logior (ash -1 n-bits) bitmap))) - (when (or (and (fixnump sign-ext) (sb-xc:typep bitmap 'bignum)) - (eql sign-ext -1)) - (return-from dd-bitmap sign-ext))))) - bitmap)) + (cond ((eql t (dsd-raw-type slot)) + (let ((bit (ash 1 (dsd-index slot)))) + (setf maximal-bitmap (logior maximal-bitmap bit)) + (unless (dsd-gc-ignorable slot) + (setf minimal-bitmap (logior minimal-bitmap bit))))) + (t + (setq any-raw t)))) + + ;; If the structure has a custom GC scavenging method then always return + ;; the minimal bitmap, and disallow arbitrary trailing slots. + ;; The optimization for all-tagged (avoiding use of the bitmap) + ;; indicates in addition to no raw slots, no custom GC method either. + ;; As of now this only pertains to lockfree-singly-linked-list nodes + ;; and descendant types. (The lockfree list uses one pointer bit + ;; as a pending-deletion flag. See "src/code/target-lflist.lisp") + (when (dd-custom-gc-method-p dd) + (aver (eq rest :unspecific)) + ;; Pretend there are raw slots so that the layout + ;; does not get the STRICTLY-BOXED flag set. + (return-from calculate-dd-bitmap (values minimal-bitmap t))) + + ;; The minimal bitmap will have the least number of bits set, and the maximal + ;; will have the most, but it is not always a performance improvement to prefer + ;; fewer bits. If the total number of bits is large, and there are no raw slots, + ;; then the "all tagged" treatment may be better because it does not need to + ;; parse the bitmap. But if there are any raw slots, the minimal bitmap is best. + (let ((bitmap + (if (or (= minimal-bitmap 0) ; don't need a bitmap + any-raw ; must use a bitmap + ;; for other cases, it is not clear-cut + (and (> (logcount maximal-bitmap) 10) ; arb + (< (logcount minimal-bitmap) + (floor (logcount maximal-bitmap) 2)))) + minimal-bitmap + maximal-bitmap))) + + ;; If the trailing slots have tagged nature, extend bitmap with + ;; an infinite sequence of 1 bits. If :UNSPECIFIC, replicate + ;; the most-significant-bit whether it be 0 or 1. + (values (cond ((or (eq rest :tagged) + (and (eq rest :unspecific) + (plusp n-bits) + (logbitp (1- n-bits) bitmap))) + (dpb bitmap (byte n-bits 0) -1)) + (t + bitmap)) + any-raw)))) ;;; This is called when we are about to define a structure class. It ;;; returns a (possibly new) class object and the layout which should @@ -1491,8 +1732,10 @@ or they must be declared locally notinline at each call site.~@:>" ;;; value is true if this is an incompatible redefinition, in which ;;; case it is the old layout. (defun ensure-structure-class (info inherits old-context new-context - &key compiler-layout) + &key compiler-layout + &aux (flags 0)) (declare (type defstruct-description info)) + ;; NB: the variables named "layout" are in fact of type WRAPPER (multiple-value-bind (classoid old-layout) (multiple-value-bind (class constructor) (acond ((cdr (dd-alternate-metaclass info)) @@ -1500,36 +1743,53 @@ or they must be declared locally notinline at each call site.~@:>" (t (values 'structure-classoid 'make-structure-classoid))) (insured-find-classoid (dd-name info) - (if (eq class 'structure-classoid) - (lambda (x) - (sb-xc:typep x 'structure-classoid)) - (lambda (x) - (sb-xc:typep x (classoid-name (find-classoid class))))) - (fdefinition constructor))) + (ecase class + (structure-classoid #'structure-classoid-p) + (built-in-classoid #'built-in-classoid-p) + (static-classoid #'static-classoid-p) + (condition-classoid #'condition-classoid-p)) + constructor)) (setf (classoid-direct-superclasses classoid) (case (dd-name info) + ;; Argh, could this case be any more opaque??? + ;; It's ostensibly the set of types whose superclasse would come out wrong + ;; if we didn't fudge them manually. But the computation of the superclass + ;; list is obfuscated. I think we have assertions about this somewhere. + ;; But ideally we remove this junky case from the target image somehow + ;; while leaving it in for self-build. ((ansi-stream fd-stream sb-impl::string-input-stream sb-impl::string-output-stream sb-impl::fill-pointer-output-stream) - (list (layout-classoid (svref inherits (1- (length inherits)))) - (layout-classoid (svref inherits (- (length inherits) 2))))) + (list (wrapper-classoid (svref inherits (1- (length inherits)))) + (wrapper-classoid (svref inherits (- (length inherits) 2))))) (t - (list (layout-classoid + (list (wrapper-classoid (svref inherits (1- (length inherits)))))))) + (unless (dd-alternate-metaclass info) + (setq flags +structure-layout-flag+)) + (cond ((some #'dsd-rsd-index (dd-slots info))) ; mixed boxed + raw (or wholly raw) + ((and (not (dd-alternate-metaclass info)) + (not (dd-custom-gc-method-p info))) + (setf flags (logior flags +strictly-boxed-flag+)))) + ;; FIXME: explain why this is #-sb-xc-host. + #-sb-xc-host + (dovector (ancestor inherits) + (setq flags (logior (logand (logior +stream-layout-flag+ + +file-stream-layout-flag+ + +string-stream-layout-flag+) + (wrapper-flags ancestor)) + flags))) (let* ((old-layout (or compiler-layout old-layout)) - (flags (if (dd-alternate-metaclass info) 0 +structure-layout-flag+)) (new-layout (when (or (not old-layout) *type-system-initialized*) - (set-layout-inherits (make-layout (hash-layout-name (dd-name info)) classoid :flags flags :inherits inherits :depthoid (length inherits) :length (dd-length info) - :info info) - inherits)))) + :info info)))) (cond ((not old-layout) (values classoid new-layout nil)) @@ -1537,31 +1797,31 @@ or they must be declared locally notinline at each call site.~@:>" ;; The assignment of INFO here can almost be deleted, ;; except for a few magical types that don't d.t.r.t. in cold-init: ;; STRUCTURE-OBJECT, CONDITION, ALIEN-VALUE, INTERPRETED-FUNCTION - (setf (layout-info old-layout) info) + (setf (wrapper-info old-layout) info) (values classoid old-layout nil)) (;; This clause corresponds to an assertion in REDEFINE-LAYOUT-WARNING ;; of classic CMU CL. I moved it out to here because it was only ;; exercised in this code path anyway. -- WHN 19990510 - (not (eq (layout-classoid new-layout) (layout-classoid old-layout))) + (not (eq (wrapper-classoid new-layout) (wrapper-classoid old-layout))) (error "shouldn't happen: weird state of OLD-LAYOUT?")) - ((redefine-layout-warning old-context + ((warn-if-altered-layout old-context old-layout new-context - (layout-length new-layout) - (layout-inherits new-layout) - (layout-depthoid new-layout) - (layout-bitmap new-layout)) + (wrapper-length new-layout) + (wrapper-inherits new-layout) + (wrapper-depthoid new-layout) + (wrapper-bitmap new-layout)) (values classoid new-layout old-layout)) (t - (let ((old-info (layout-info old-layout))) + (let ((old-info (wrapper-info old-layout))) (if old-info (cond ((redefine-structure-warning classoid old-info info) (values classoid new-layout old-layout)) (t - (setf (layout-info old-layout) info) + (setf (wrapper-info old-layout) info) (values classoid old-layout nil))) (progn - (setf (layout-info old-layout) info) + (setf (wrapper-info old-layout) info) (values classoid old-layout nil))))))))) ;;; Return a list of pairs (name . index). Used for :TYPE'd @@ -1594,24 +1854,11 @@ or they must be declared locally notinline at each call site.~@:>" ;;; ;;; This is split into two functions: ;;; * INSTANCE-CONSTRUCTOR-FORM has to deal with raw slots -;;; (there are two variations on this) ;;; * TYPED-CONSTRUCTOR-FORM deal with LIST & VECTOR ;;; which might have "name" symbols stuck in at various weird places. (defun instance-constructor-form (dd values &aux (dd-slots (dd-slots dd))) - ;; The difference between the two implementations here is that on all - ;; platforms we don't have the appropriate RAW-INSTANCE-INIT VOPS, which - ;; must be able to deal with immediate values as well -- unlike - ;; RAW-INSTANCE-SET VOPs, which never end up seeing immediate values. With - ;; some additional cleverness we might manage without them and just a single - ;; implementation here, though -- figure out a way to ensure that on those - ;; platforms we always still get a non-immediate TN in every case... - ;; - ;; Until someone does that, this means that instances with raw slots can be - ;; DX allocated only on platforms with those additional VOPs. (aver (= (length dd-slots) (length values))) - (if (or #+(or ppc ppc64 x86 x86-64) t) - ;; Have raw-instance-init vops - (collect ((slot-specs) (slot-values)) + (collect ((slot-specs) (slot-values)) (mapc (lambda (dsd value &aux (raw-type (dsd-raw-type dsd)) (spec (list* :slot raw-type (dsd-index dsd)))) (cond ((eq value '.do-not-initialize-slot.) @@ -1623,43 +1870,14 @@ or they must be declared locally notinline at each call site.~@:>" (slot-values value)))) dd-slots values) `(%make-structure-instance-macro ,dd ',(slot-specs) ,@(slot-values))) - ;; Don't have raw-instance-init vops - (collect ((slot-specs) (slot-values) (raw-slots) (raw-values)) - ;; Partition into non-raw and raw - (mapc (lambda (dsd value &aux (raw-type (dsd-raw-type dsd)) - (spec (list* :slot raw-type (dsd-index dsd)))) - (cond ((eq value '.do-not-initialize-slot.) - (when (eq raw-type t) - (rplaca spec :unbound) - (slot-specs spec))) - ((eq raw-type t) - (slot-specs spec) - (slot-values value)) - (t - (raw-slots dsd) - (raw-values value)))) - dd-slots values) - (let ((instance-form - `(%make-structure-instance-macro ,dd - ',(slot-specs) ,@(slot-values)))) - (if (raw-slots) - (let ((temp (make-symbol "INSTANCE"))) - `(let ((,temp ,instance-form)) - ;; Transform to %RAW-INSTANCE-SET/foo, not SETF, - ;; in case any slots are readonly. - ,@(mapcar (lambda (dsd value) - (slot-access-transform - :setf (list temp value) (cons dd dsd))) - (raw-slots) (raw-values)) - ,temp)) - instance-form))))) + ) ;;; A "typed" constructor prefers to use a single call to LIST or VECTOR ;;; if possible, but can't always do that for VECTOR because it might not ;;; be a (VECTOR T). If not, we fallback to MAKE-ARRAY and (SETF AREF). (defun typed-constructor-form (dd values) (multiple-value-bind (operator initial-element) - (cond ((and (eq (dd-type dd) 'vector) (eq (dd-element-type dd) t)) + (cond ((and (eq (dd-type dd) 'vector) (eq (dd-%element-type dd) t)) (values 'vector 0)) ((eq (dd-type dd) 'list) (values 'list nil))) @@ -1686,7 +1904,7 @@ or they must be declared locally notinline at each call site.~@:>" (cons operator vals)) (let ((temp (make-symbol "OBJ"))) `(let ((,temp (make-array ,length - :element-type ',(dd-element-type dd)))) + :element-type ',(dd-%element-type dd)))) ,@(mapcar (lambda (x) `(setf (aref ,temp ,(cdr x)) ',(car x))) names) ,@(mapcan (lambda (dsd val) @@ -1738,7 +1956,7 @@ or they must be declared locally notinline at each call site.~@:>" keys)))))) (values ,(cond ((dd-class-p dd) (dd-name dd)) ((eq (dd-type dd) 'list) 'list) - (t `(vector ,(dd-element-type dd) ,(dd-length dd)))) + (t `(vector ,(dd-%element-type dd) ,(dd-length dd)))) &optional)))) ;;; Return the ftype of global function NAME. @@ -1898,17 +2116,6 @@ or they must be declared locally notinline at each call site.~@:>" ;; because the container itself will check. (if (eq type t) initform `(the ,type ,initform))))) (dd-slots dd)))))))))) - -(defun accessor-definitions (dd) - (loop for dsd in (dd-slots dd) - for accessor-name = (dsd-accessor-name dsd) - unless (accessor-inherited-data accessor-name dd) - nconc (dx-let ((key (cons dd dsd))) - `(,@(unless (dsd-read-only dsd) - `((sb-c:xdefun (setf ,accessor-name) :accessor (value instance) - ,(slot-access-transform :setf '(instance value) key)))) - (sb-c:xdefun ,accessor-name :accessor (instance) - ,(slot-access-transform :read '(instance) key)))))) ;;;; instances with ALTERNATE-METACLASS ;;;; @@ -1947,37 +2154,38 @@ or they must be declared locally notinline at each call site.~@:>" (dd-type (missing-arg)) metaclass-constructor slot-names) - (let* ((dd (make-defstruct-description t class-name)) + (let* ((dd (make-defstruct-description class-name +dd-nullenv+)) (conc-name (string (gensymify* class-name "-"))) - ;; Without compact instance headers, the index starts at 1 for - ;; named slots, because slot 0 is the LAYOUT. - ;; This is the same in ordinary structures too: see (INCF DD-LENGTH) - ;; in PARSE-DEFSTRUCT-NAME-AND-OPTIONS. - ;; With compact instance headers, slot 0 is a data slot. - (slot-index sb-vm:instance-data-start)) + (slot-index 0)) ;; We do *not* fill in the COPIER-NAME and PREDICATE-NAME ;; because alternate-metaclass structures can not have either. (case dd-type - ;; We don't support inheritance of alternate metaclass stuff, - ;; and it's not a general-purpose facility, so sanity check our - ;; own code. + ;; We don't fully support inheritance of alternate metaclass stuff, + ;; so sanity check our own code. (structure - (aver (eq superclass-name 't))) + (aver (eq superclass-name 't)) + ;; Without compact instance headers, the index starts at 1 for + ;; named slots, because slot 0 is the LAYOUT. + ;; This is the same in ordinary structures too: see (INCF DD-LENGTH) + ;; in PARSE-DEFSTRUCT-NAME-AND-OPTIONS. + ;; With compact instance headers, slot 0 is a data slot. + (incf slot-index sb-vm:instance-data-start)) (funcallable-structure (aver (eq superclass-name 'function))) (t (bug "Unknown DD-TYPE in ALTERNATE-METACLASS: ~S" dd-type))) - (setf (dd-alternate-metaclass dd) (list superclass-name + (setf (dd-type dd) dd-type + (dd-alternate-metaclass dd) (list superclass-name metaclass-name metaclass-constructor) (dd-slots dd) (mapcar (lambda (slot-name) (make-dsd slot-name t (symbolicate conc-name slot-name) (pack-dsd-bits (prog1 slot-index (incf slot-index)) - nil t t nil) + nil t t nil nil) nil)) slot-names) (dd-length dd) slot-index - (dd-type dd) dd-type) + (dd-bitmap dd) (calculate-dd-bitmap dd)) dd)) (sb-xc:defmacro !defstruct-with-alternate-metaclass @@ -1989,7 +2197,7 @@ or they must be declared locally notinline at each call site.~@:>" (metaclass-constructor (missing-arg)) (dd-type (missing-arg))) - (declare (type (and list (not null)) slot-names)) + (declare (type list slot-names)) (declare (type (and symbol (not null)) superclass-name metaclass-name @@ -1997,42 +2205,50 @@ or they must be declared locally notinline at each call site.~@:>" (declare (symbol constructor)) ; NIL for none (declare (type (member structure funcallable-structure) dd-type)) - (let* ((dd (make-dd-with-alternate-metaclass + (let ((dd (make-dd-with-alternate-metaclass :class-name class-name :slot-names slot-names :superclass-name superclass-name :metaclass-name metaclass-name :metaclass-constructor metaclass-constructor - :dd-type dd-type)) - (delayed-layout-form `(%delayed-get-compiler-layout ,class-name)) - (raw-maker-form - (ecase dd-type - (structure `(%make-structure-instance-macro ,dd nil)) - (funcallable-structure - `(let ((object - ;; TRULY-THE should not be needed. But it is, to avoid - ;; a type check on the next SETF. Why??? - (truly-the funcallable-instance - (%make-funcallable-instance ,(dd-length dd))))) - (setf (%fun-layout object) ,delayed-layout-form) - object))))) + :dd-type dd-type))) `(progn - (eval-when (:compile-toplevel :load-toplevel :execute) + (eval-when (:compile-toplevel :load-toplevel :execute) (%compiler-defstruct ',dd ',(!inherits-for-structure dd)) + (when (eq (info :type :kind ',class-name) :defined) + (setf (info :type :kind ',class-name) :instance)) ,@(when (eq metaclass-name 'static-classoid) `((declaim (freeze-type ,class-name))))) - ,@(accessor-definitions dd) - ,@(when constructor - `((defun ,constructor (,@slot-names &aux (object ,raw-maker-form)) + ,@(accessor-definitions dd t) + ,@(when constructor + (multiple-value-bind (allocate set-layout) + (ecase dd-type + (structure + ;; I think the only nonfuncallable alternate-metaclass structure + ;; is CONDITION, which has its own fancy constructor. + ;; Maybe this should be (bug "Can't happen") ? + (values `(%make-structure-instance-macro ,dd nil) nil)) + (funcallable-structure + (values `(truly-the ,class-name + (%make-funcallable-instance ,(dd-length dd))) + `((macrolet ((the-layout () + (info :type :compiler-layout ',class-name))) + (setf (%fun-wrapper object) (the-layout))))))) + `((defun ,constructor (,@slot-names &aux (object ,allocate)) + ,@set-layout + #+x86-64 + ,@(when (and (eq dd-type 'funcallable-structure) + ;; fmt-control is not an executable function + (neq class-name 'sb-format::fmt-control)) + '((sb-vm::write-funinstance-prologue object))) ,@(mapcar (lambda (dsd) `(setf (,(dsd-accessor-name dsd) object) ,(dsd-name dsd))) (dd-slots dd)) - object))) - - ;; Usually we AVER instead of ASSERT, but AVER isn't defined yet. - ;; A naive reading of 'build-order' suggests it is, - ;; but due to def!struct delay voodoo, it isn't. - (assert (null (symbol-value '*defstruct-hooks*)))))) + object)))) + (!target-defstruct-altmetaclass ',dd ,@(accessor-definitions dd nil))))) +#+sb-xc-host +(defun !target-defstruct-altmetaclass (&rest args) + (declare (ignore args))) ;;;; finalizing bootstrapping @@ -2044,18 +2260,14 @@ or they must be declared locally notinline at each call site.~@:>" ;;; special enough (and simple enough) that we just build it by hand ;;; instead of trying to generalize the ordinary DEFSTRUCT code. (defun !set-up-structure-object-class () - (let ((dd (make-defstruct-description t 'structure-object))) - (setf - (dd-slots dd) nil - (dd-length dd) sb-vm:instance-data-start - (dd-type dd) 'structure) - (%compiler-set-up-layout dd))) + (let ((dd (make-defstruct-description 'structure-object +dd-nullenv+))) + (setf (dd-length dd) sb-vm:instance-data-start) + (%compiler-set-up-layout dd (vector (find-layout 't))))) #+sb-xc-host(!set-up-structure-object-class) (defun find-defstruct-description (name &optional (errorp t)) (let* ((classoid (find-classoid name errorp)) - (info (and classoid - (layout-info (classoid-layout classoid))))) + (info (and classoid (wrapper-%info (classoid-wrapper classoid))))) (cond ((defstruct-description-p info) info) (errorp @@ -2072,160 +2284,59 @@ or they must be declared locally notinline at each call site.~@:>" (when (typep ctor '(cons t (eql :default))) (car ctor)))) -;;; These functions are required to emulate SBCL kernel functions -;;; in a vanilla ANSI Common Lisp cross-compilation host. -;;; The emulation doesn't need to be efficient, since it's needed -;;; only for object dumping. #+sb-xc-host -(progn - (defun %instance-layout (instance) - (classoid-layout (find-classoid (type-of instance)))) - (defun %instance-length (instance) - ;; In the target, it is theoretically possible to have %INSTANCE-LENGTH - ;; exceeed layout length, but in the cross-compiler they're the same. - (layout-length (%instance-layout instance))) - (defun %instance-ref (instance index) - (let ((layout (%instance-layout instance))) - ;; with compact headers, 0 is an ordinary slot index. - ;; without, it's the layout. - (if (eql index (1- sb-vm:instance-data-start)) - (error "XC Host should use %INSTANCE-LAYOUT, not %INSTANCE-REF 0") - (let* ((dd (layout-info layout)) - ;; If data starts at 1, then subtract 1 from index. - ;; otherwise use the index as-is. - (dsd (elt (dd-slots dd) - (- index sb-vm:instance-data-start))) - (accessor-name (dsd-accessor-name dsd))) - ;; Why AVER these: because it is slightly abstraction-breaking - ;; to assume that the slot-index N is the NTH item in the DSDs. - ;; The target Lisp never assumes that. - (aver (and (eql (dsd-index dsd) index) (eq (dsd-raw-type dsd) t))) - (funcall accessor-name instance))))) - - (defun %raw-instance-ref/word (instance index) - (declare (ignore instance index)) - (error "No such thing as raw structure access on the host")) - - ;; Setting with (FUNCALL `(SETF ,accessor) ...) is unportable because - ;; "The mechanism by which defstruct arranges for slot accessors to be - ;; usable with setf is implementation-dependent; for example, it may - ;; use setf functions, setf expanders, or some other - ;; implementation-dependent mechanism ..." - ;; But such capability seems not to be needed. - (defun %instance-set (instance index new-value) - (declare (ignore instance index new-value)) - (error "Can not use %INSTANCE-SET on cross-compilation host."))) - -;;; It's easier for the compiler to recognize the output of M-L-F-S-S -;;; without extraneous QUOTE forms, so we define some trivial wrapper macros. -(defmacro new-instance (type) `(allocate-instance (find-class ',type))) -(defmacro sb-pcl::set-slots (instance name-list &rest values) - `(sb-pcl::%set-slots ,instance ',name-list ,@values)) - -;;; We require that MAKE-LOAD-FORM-SAVING-SLOTS produce deterministic output -;;; and that its output take a particular recognizable form so that it can -;;; be optimized into a sequence of fasl ops. -;;; The cross-compiler depends critically on optimizing the resulting sexprs -;;; so that the host can load cold objects, which it could not do -;;; if constructed by machine code for the target. -;;; This ends up being a performance win for the target system as well. +(defun %instance-ref (instance index) + (let* ((wrapper (%instance-wrapper instance)) + (map (wrapper-index->accessor-map wrapper))) + (when (zerop (length map)) ; construct it on demand + (let ((slots (dd-slots (wrapper-%info wrapper)))) + (setf map (make-array (1+ (reduce #'max slots :key #'dsd-index)) + :initial-element nil) + (wrapper-index->accessor-map wrapper) map) + (dolist (dsd slots) + (setf (aref map (dsd-index dsd)) (dsd-accessor-name dsd))))) + (funcall (aref map index) instance))) + +#+sb-xc-host +(defun %raw-instance-ref/word (instance index) (%instance-ref instance index)) + ;;; It is possible to produce instances of structure-object which violate ;;; the assumption throughout the compiler that slot readers are safe ;;; unless dictated otherwise by the SAFE-P flag in the DSD. ;;; * (defstruct S a (b (error "Must supply me") :type symbol)) ;;; * (defmethod make-load-form ((x S) &optional e) (m-l-f-s-s x :slot-names '(a))) -;;; After these definitions, a dumped S will have 0 in slot B. -;;; -(defun sb-xc:make-load-form-saving-slots (object &key (slot-names nil slot-names-p) - environment) +;;; After these definitions, a dumped S will have #<unbound> in slot B. +(defun make-load-form-saving-slots (object &key (slot-names nil slot-names-p) + environment) (declare (ignore environment)) - (flet ((quote-p (thing) (not (self-evaluating-p thing)))) - (declare (inline quote-p)) - ;; If TYPE-OF isn't a symbol, the creation form probably can't be compiled - ;; unless there is a MAKE-LOAD-FORM on the class without a proper-name. - ;; This is better than returning a creation form that produces - ;; something completely different. - (values (let ((type (type-of object))) - `(,(if (symbolp type) 'new-instance 'allocate-instance) ,type)) - (if (typep object 'structure-object) - `(setf ,@(mapcan - (lambda (dsd) - (declare (type defstruct-slot-description dsd)) - (when (or (not slot-names-p) - (memq (dsd-name dsd) slot-names)) - (let* ((acc (dsd-primitive-accessor dsd)) - (ind (dsd-index dsd)) - (val (funcall acc object ind))) - (list `(,acc ,object ,ind) - (if (quote-p val) `',val val))))) - (dd-slots (layout-info (%instance-layout object))))) - #-sb-xc-host - (loop for slot in (sb-mop:class-slots (class-of object)) - for name = (sb-mop:slot-definition-name slot) - when (if slot-names-p - (memq name slot-names) - (eq (sb-mop:slot-definition-allocation slot) :instance)) - collect name into names - and - collect (if (slot-boundp object name) - (let ((val (slot-value object name))) - (if (quote-p val) `',val val)) - 'sb-pcl:+slot-unbound+) into vals - finally (return `(sb-pcl::set-slots ,object ,names ,@vals))))))) - -;;; Call MAKE-LOAD-FORM inside a condition handler in case the method fails, -;;; returning its two values on success. -;;; If the resulting CREATION-FORM and INIT-FORM are equivalent to those -;;; returned from MAKE-LOAD-FORM-SAVING-SLOTS, return NIL and 'SB-FASL::FOP-STRUCT. -(defun sb-c::%make-load-form (constant) - (flet ((canonical-p (inits dsds object &aux reader) - ;; Return T if (but not only-if) INITS came from M-L-F-S-S. - (dolist (dsd dsds (null inits)) - (declare (type defstruct-slot-description dsd)) - (if (and (listp inits) - (let ((place (pop inits))) - (and (listp place) - (eq (setq reader (dsd-primitive-accessor dsd)) - (pop place)) - (listp place) (eq object (pop place)) - (singleton-p place) - (eql (dsd-index dsd) (car place)))) - (let ((init (and (listp inits) (car inits))) - (val (funcall reader object (dsd-index dsd)))) - (if (self-evaluating-p val) - (and inits (eql val init)) - (and (typep init '(cons (eql quote))) - (singleton-p (cdr init)) - (eq val (cadr init)))))) - (pop inits) - (return nil))))) - (multiple-value-bind (creation-form init-form) - (handler-case (sb-xc:make-load-form constant (make-null-lexenv)) - (error (condition) (sb-c:compiler-error condition))) - (cond ((and (listp creation-form) - (typep constant 'structure-object) - (typep creation-form - '(cons (eql new-instance) (cons symbol null))) - (eq (second creation-form) (type-of constant)) - (typep init-form '(cons (eql setf))) - (canonical-p (cdr init-form) - (dd-slots (layout-info (%instance-layout constant))) - constant)) - (values nil 'sb-fasl::fop-struct)) - (t - (values creation-form init-form)))))) - -(defmacro get-dsd-index (type-name slot-name) - ;; Without the NOTINLINE we get: - ; caught STYLE-WARNING: - ; Derived type of SB-C::VAL is - ; (VALUES NULL &OPTIONAL), - ; conflicting with its asserted type - ; SB-KERNEL:DEFSTRUCT-SLOT-DESCRIPTION. - (declare (notinline find dsd-bits)) - (dsd-index (find slot-name - (dd-slots (find-defstruct-description type-name)) - :key #'dsd-name))) + (if (typep object 'structure-object) + (let ((type (type-of object))) + (collect ((inits)) + (dolist (dsd (dd-slots (wrapper-dd (%instance-wrapper object)))) + (declare (type defstruct-slot-description dsd)) + (let ((slot-name (dsd-name dsd))) + (when (or (memq slot-name slot-names) + (not slot-names-p)) + (let* ((accessor (dsd-reader dsd nil)) + (index (dsd-index dsd)) + (value (funcall accessor object index))) + (inits `(setf (,accessor ,object ,index) ',value)))))) + (values `(allocate-struct ',(the symbol type)) ;; no anonymous defstructs + `(progn ,@(inits))))) + #-sb-xc-host + (let ((class (class-of object))) + (collect ((inits)) + (dolist (slot (sb-mop:class-slots class)) + (let ((slot-name (sb-mop:slot-definition-name slot))) + (when (or (memq slot-name slot-names) + (and (not slot-names-p) + (eq :instance (sb-mop:slot-definition-allocation slot)))) + (if (slot-boundp object slot-name) + (let ((value (slot-value object slot-name))) + (inits `(setf (slot-value ,object ',slot-name) ',value))) + (inits `(slot-makunbound ,object ',slot-name)))))) + (values `(allocate-instance (find-class ',(class-name class))) + `(progn ,@(inits))))))) ;;; Compute a SAP to the specified slot in INSTANCE. ;;; This looks mildly redundant with DEFINE-STRUCTURE-SLOT-ADDRESSOR, @@ -2236,4 +2347,44 @@ or they must be declared locally notinline at each call site.~@:>" sb-vm:word-shift) sb-vm:instance-pointer-lowtag))) +#+sb-xc-host +(defun write-structure-definitions-as-text (pathname) + (with-open-file (output pathname :direction :output :if-exists :supersede) + (dolist (root '(structure-object function)) + (dolist (pair (let ((subclassoids (classoid-subclasses (find-classoid root)))) + (if (listp subclassoids) + subclassoids + (flet ((pred (x y) + (or (string< x y) + (and (string= x y) + (let ((xpn (cl:package-name (cl:symbol-package x))) + (ypn (cl:package-name (cl:symbol-package y)))) + (string< xpn ypn)))))) + (sort (%hash-table-alist subclassoids) + #'pred + ;; pair = (#<classoid> . #<layout>) + :key (lambda (pair) (classoid-name (car pair)))))))) + (let* ((wrapper (cdr pair)) + (dd (wrapper-info wrapper))) + (cond + (dd + (let* ((*print-pretty* nil) ; output should be insensitive to host pprint + (*print-readably* t) + (classoid-name (classoid-name (car pair))) + (*package* (cl:symbol-package classoid-name))) + (format output "~/sb-ext:print-symbol-with-prefix/ ~S (~%" + classoid-name + (list* (the (unsigned-byte 16) (wrapper-flags wrapper)) + (wrapper-depthoid wrapper) + (map 'list #'wrapper-classoid-name + (wrapper-inherits wrapper)))) + (dolist (dsd (dd-slots dd) (format output ")~%")) + (format output " (~d ~S ~S)~%" + (dsd-bits dsd) + (dsd-name dsd) + (dsd-accessor-name dsd))))) + (t + (error "Missing DD for ~S" pair)))))) + (format output ";; EOF~%"))) + (/show0 "code/defstruct.lisp end of file") diff --git a/src/code/deftypes-for-target.lisp b/src/code/deftypes-for-target.lisp index 9ad4de6906..26be4391ed 100644 --- a/src/code/deftypes-for-target.lisp +++ b/src/code/deftypes-for-target.lisp @@ -101,11 +101,9 @@ `(simple-array base-char (,size))) (sb-xc:deftype string (&optional size) `(or (array character (,size)) - (array nil (,size)) (base-string ,size))) (sb-xc:deftype simple-string (&optional size) `(or (simple-array character (,size)) - (simple-array nil (,size)) (simple-base-string ,size))) ;;; On Unicode builds, SIMPLE-CHARACTER-STRING is a builtin type. ;;; For non-Unicode it is convenient to be able to use the type name @@ -169,9 +167,9 @@ '(or list symbol classoid class)) ;;; array rank, total size... -(sb-xc:deftype array-rank () `(integer 0 (,sb-xc:array-rank-limit))) +(sb-xc:deftype array-rank () `(integer 0 (,array-rank-limit))) (sb-xc:deftype array-total-size () - `(integer 0 (,sb-xc:array-total-size-limit))) + `(integer 0 (,array-total-size-limit))) ;;; The range returned by SXHASH and PSXHASH ;;; Do not confuse this type with the type that EQ-HASH and related hash @@ -179,7 +177,7 @@ ;;; precludes us from using the entire fixnum range. Doing so avoids ;;; an extra AND operation, which is pretty much effectless in as much as ;;; the hash code is masked down to a much smaller value anyway. -(sb-xc:deftype hash-code () `(integer 0 ,sb-xc:most-positive-fixnum)) +(sb-xc:deftype hash-code () `(integer 0 ,most-positive-fixnum)) ;;; something legal in an evaluated context ;;; FIXME: could probably go away @@ -208,7 +206,7 @@ '(or float (complex float))) ;;; character components -(sb-xc:deftype char-code () `(integer 0 (,sb-xc:char-code-limit))) +(sb-xc:deftype char-code () `(integer 0 (,char-code-limit))) ;;; a consed sequence result. If a vector, is a simple array. (sb-xc:deftype consed-sequence () @@ -262,4 +260,6 @@ (sb-xc:deftype extended-function-designator () '(satisfies extended-function-designator-p)) +#-metaspace (sb-xc:deftype sb-vm:layout () 'wrapper) + (/show0 "deftypes-for-target.lisp end of file") diff --git a/src/code/describe.lisp b/src/code/describe.lisp index e423344412..f7709fc5b0 100644 --- a/src/code/describe.lisp +++ b/src/code/describe.lisp @@ -20,13 +20,7 @@ class))) ;;;; the ANSI interface to function names (and to other stuff too) -;;; Note: this function gets called by the compiler (as of 1.0.17.x, -;;; in MAYBE-INLINE-SYNTACTIC-CLOSURE), and so although ANSI says -;;; we're allowed to return NIL here freely, it seems plausible that -;;; small changes to the circumstances under which this function -;;; returns non-NIL might have subtle consequences on the compiler. -;;; So it might be desirable to have the compiler not rely on this -;;; function, eventually. + (defun function-lambda-expression (fun) "Return (VALUES DEFINING-LAMBDA-EXPRESSION CLOSURE-P NAME), where DEFINING-LAMBDA-EXPRESSION is NIL if unknown, or a suitable argument @@ -67,7 +61,7 @@ (limit (truncate (- *print-right-margin* reserve) columns))) (flet ((trunc (&optional end) (let ((line-end (- limit 2))) - (with-simple-output-to-string (s) + (%with-output-to-string (s) (write-string line s :end (if end (min end line-end) line-end)) @@ -100,6 +94,9 @@ (defun describe (object &optional (stream-designator *standard-output*)) "Print a description of OBJECT to STREAM-DESIGNATOR." + ;; This DECLARE works around a compiler bug that FTYPE does not force + ;; type-checking of the optional argument. + (declare (stream-designator stream-designator)) (let ((stream (out-stream-from-designator stream-designator)) (*print-right-margin* (or *print-right-margin* 72)) (*print-circle* t) @@ -247,6 +244,15 @@ (print-standard-describe-header object stream) (describe-instance object stream)) +(defmethod describe-object ((object pathname) stream) + (print-standard-describe-header object stream) + (loop for name across #(host device directory name type version) + for i from (get-dsd-index pathname host) + do (awhen (%instance-ref object i) + (format stream "~% ~10A = ~A" name + (prin1-to-line (if (eq name 'directory) (car it) it))))) + (terpri stream)) + (defmethod describe-object ((object character) stream) (print-standard-describe-header object stream) (format stream "~%Char-code: ~S~%Char-name: ~A" @@ -527,13 +533,15 @@ (let ((*print-circle* nil) (*print-level* 24) (*print-length* 100)) - (format stream "~@:_Lambda-list: ~:S" lambda-list))) + (format stream "~@:_Lambda-list: ~/sb-impl:print-lambda-list/" lambda-list))) (defun describe-argument-precedence-order (argument-list stream) (let ((*print-circle* nil) (*print-level* 24) (*print-length* 100)) - (format stream "~@:_Argument precedence order: ~:A" argument-list))) + (format stream "~@:_Argument precedence order: ~ + ~/sb-impl:print-lambda-list/" + argument-list))) (defun describe-function-source (function stream) (declare (function function)) @@ -587,7 +595,7 @@ (t (let* ((fun (or function (fdefinition name))) (derived-type (and function - (%fun-type function))) + (%fun-ftype function))) (legal-name-p (legal-fun-name-p name)) (ctype (and legal-name-p (global-ftype name))) @@ -602,7 +610,7 @@ (member from '(:defined-method :defined))) (setf derived-type type))) (unless derived-type - (setf derived-type (%fun-type fun))) + (setf derived-type (%fun-ftype fun))) (if (typep fun 'standard-generic-function) (values fun "a generic function" @@ -662,7 +670,7 @@ (when methods (format stream "~@:_Method-combination: ~S" (sb-pcl::method-combination-type-name - (sb-pcl:generic-function-method-combination fun))) + (sb-mop:generic-function-method-combination fun))) (cond ((eq :none methods) (format stream "~@:_No methods.")) (t @@ -671,7 +679,8 @@ (format stream "Methods:") (dolist (method methods) (pprint-indent :block 2 stream) - (format stream "~@:_(~A ~{~S ~}~:S)" + (format stream "~@:_(~A ~{~S ~}~ + ~/sb-impl:print-lambda-list/)" name (method-qualifiers method) (sb-pcl::unparse-specializers @@ -684,12 +693,14 @@ (describe-block (stream "~A has a compiler-macro:" name) (describe-documentation it t stream) (describe-function-source it stream))) + ;; It seems entirely bogus to claim that, for example (SETF CAR) + ;; has a setf expander when what we mean is that CAR has. (when (and (consp name) (eq 'setf (car name)) (not (cddr name))) (let* ((name2 (second name)) (expander (info :setf :expander name2))) - (cond ((typep expander '(and symbol (not null))) + (cond ((typep expander '(cons symbol)) (describe-block (stream "~A has setf-expansion: ~S" - name expander) + name (car expander)) (describe-documentation name2 'setf stream))) (expander (when (listp expander) diff --git a/src/code/destructuring-bind.lisp b/src/code/destructuring-bind.lisp deleted file mode 100644 index a762b80a63..0000000000 --- a/src/code/destructuring-bind.lisp +++ /dev/null @@ -1,53 +0,0 @@ -;;;; This software is part of the SBCL system. See the README file for -;;;; more information. -;;;; -;;;; This software is derived from the CMU CL system, which was -;;;; written at Carnegie Mellon University and released into the -;;;; public domain. The software is in the public domain and is -;;;; provided with absolutely no warranty. See the COPYING and CREDITS -;;;; files for more information. - -(in-package "SB-IMPL") - -(macrolet (#+sb-xc-host ; Bootstrap NAMED-DS-BIND - (named-ds-bind (name lambda-list expression &body body) - (declare (ignore name)) - `(cl:destructuring-bind ,lambda-list ,expression ,@body))) - - (sb-xc:defmacro destructuring-bind (lambda-list expression &body body - &environment env) - (declare (ignore env)) ; could be policy-sensitive (but isn't) - "Bind the variables in LAMBDA-LIST to the corresponding values in the -tree structure resulting from the evaluation of EXPRESSION." - `(binding* ,(sb-c::expand-ds-bind lambda-list expression t nil) - ,@body)) - - (let () - ;; This is a variant of destructuring-bind that provides the name - ;; of the containing construct in generated error messages. - ;; There is a cyclic dependence between it and DEFMACRO. - (sb-xc:defmacro named-ds-bind (name lambda-list expression &body body - &environment env) - (declare (ignore env)) ; could be policy-sensitive (but isn't) - `(binding* ,(sb-c::expand-ds-bind lambda-list expression t nil name - (and (eq (car name) :macro) - (eq (cddr name) 'deftype) - ''*)) - ,@body)))) - -#+sb-xc-host -(progn - ;; The expander for NAMED-DS-BIND in the host could almost always be - ;; the above MACROLET, but that would fail to use the default of '* for - ;; optional args of SB-XC:DEFTYPE that lack an overriding default. - ;; So install our expander even if it produces suboptimal code for the host. - (defmacro named-ds-bind (&whole form &rest args) - (declare (ignore args)) - (funcall (sb-xc:macro-function 'named-ds-bind) form nil)) - - ;; A similar problem in reverse: SB-XC:DEFMACRO's expansion uses NAMED-DS-BIND - ;; which expands to BINDING* (from "early-extensions") that hand-written code - ;; also wants to use. So expand it in the target by using the host's expander - ;; until it gets seen again during make-host-2. - (setf (sb-xc:macro-function 'binding*) - (lambda (form env) (declare (ignore env)) (cl:macroexpand-1 form nil)))) diff --git a/src/code/dyncount.lisp b/src/code/dyncount.lisp index 9bfc63ba6e..6d986236a8 100644 --- a/src/code/dyncount.lisp +++ b/src/code/dyncount.lisp @@ -35,7 +35,7 @@ comments from CMU CL: "Return a hash-table containing only the entries in Table1 whose key is not also a key in Table2." (declare (type hash-table table1 table2)) (let ((res (make-hash-table-like table1))) - (with-locked-system-table (table2) + (with-system-mutex ((hash-table-lock table2)) (dohash ((k v) table1 :locked t) (unless (nth-value 1 (gethash k table2)) (setf (gethash k res) v)))) @@ -109,7 +109,7 @@ comments from CMU CL: (setf (vop-stats-cost res) cost) res)) -#-sb-fluid (declaim (freeze-type dyncount-info vop-stats)) +(declaim (freeze-type dyncount-info vop-stats)) ;;; Add the Info into the cumulative result on the VOP name plist. We use ;;; plists so that we will touch minimal system code outside of this file @@ -389,7 +389,7 @@ comments from CMU CL: (defun entry-report (entries cut-off compensated compare total-cost) (let ((counter (if (and cut-off (> (length entries) cut-off)) cut-off - sb-xc:most-positive-fixnum))) + most-positive-fixnum))) (dolist (entry entries) (let* ((cost (vop-stats-cost entry)) (name (vop-stats-name entry)) diff --git a/src/code/early-alieneval.lisp b/src/code/early-alieneval.lisp deleted file mode 100644 index d480603884..0000000000 --- a/src/code/early-alieneval.lisp +++ /dev/null @@ -1,153 +0,0 @@ -;;;; This software is part of the SBCL system. See the README file for -;;;; more information. -;;;; -;;;; This software is derived from the CMU CL system, which was -;;;; written at Carnegie Mellon University and released into the -;;;; public domain. The software is in the public domain and is -;;;; provided with absolutely no warranty. See the COPYING and CREDITS -;;;; files for more information. - -(in-package "SB-ALIEN") - -(defglobal *alien-type-classes* (make-hash-table :test 'eq)) - -#-sb-xc-host (sb-impl::define-thread-local *saved-fp* nil) - -(defvar *new-auxiliary-types* nil) - -;;; the list of record types that have already been unparsed. This is -;;; used to keep from outputting the slots again if the same structure -;;; shows up twice. -(defvar *record-types-already-unparsed*) - -;;; not documented in CMU CL:-( -;;; -;;; reverse engineering observations: -;;; * seems to be set when translating return values -;;; * seems to enable the translation of (VALUES), which is the -;;; Lisp idiom for C's return type "void" (which is likely -;;; why it's set when when translating return values) -(defvar *values-type-okay* nil) - -(defvar *default-c-string-external-format* nil) - -(defmacro define-alien-type-translator (name lambda-list &body body) - (let ((defun-name (symbolicate "ALIEN-" name "-TYPE-TRANSLATOR")) - (macro-lambda - (make-macro-lambda nil lambda-list body - 'define-alien-type-translator name))) - `(progn - (eval-when (#-sb-xc :compile-toplevel :load-toplevel :execute) - (defun ,defun-name ,(second macro-lambda) ,@(cddr macro-lambda))) - (eval-when (:compile-toplevel :load-toplevel :execute) - (%define-alien-type-translator ',name #',defun-name))))) - -;;; Process stuff in a new scope. -(defmacro with-auxiliary-alien-types (env &body body) - ``(symbol-macrolet ((&auxiliary-type-definitions& - ,(append *new-auxiliary-types* - (auxiliary-type-definitions ,env)))) - ,(let ((*new-auxiliary-types* nil)) - ,@body))) - -(defmacro define-alien-type (name type &environment env) - "Define the alien type NAME to be equivalent to TYPE. Name may be NIL for - STRUCT and UNION types, in which case the name is taken from the type - specifier." - (with-auxiliary-alien-types env - (let ((alien-type (parse-alien-type type env))) - `(eval-when (:compile-toplevel :load-toplevel :execute) - ,@(when *new-auxiliary-types* - `((%def-auxiliary-alien-types ',*new-auxiliary-types* - (sb-c:source-location)))) - ,@(when name - `((%define-alien-type ',name ',alien-type (sb-c:source-location)))))))) - -(defstruct (alien-type-class (:copier nil)) - (name nil :type symbol) - (defstruct-name nil :type symbol) - (include nil :type (or null alien-type-class)) - (unparse nil :type (or null function)) - (type= nil :type (or null function)) - (lisp-rep nil :type (or null function)) - (alien-rep nil :type (or null function)) - (extract-gen nil :type (or null function)) - (deposit-gen nil :type (or null function)) - (naturalize-gen nil :type (or null function)) - (deport-gen nil :type (or null function)) - (deport-alloc-gen nil :type (or null function)) - (deport-pin-p nil :type (or null function)) - ;; Cast? - (arg-tn nil :type (or null function)) - (result-tn nil :type (or null function)) - (subtypep nil :type (or null function))) - -(defmethod print-object ((type-class alien-type-class) stream) - (print-unreadable-object (type-class stream :type t) - (prin1 (alien-type-class-name type-class) stream))) - -(defun alien-type-class-or-lose (name) - (or (gethash name *alien-type-classes*) - (error "no alien type class ~S" name))) - -(defun create-alien-type-class-if-necessary (name defstruct-name include) - (let ((old (gethash name *alien-type-classes*)) - (include (and include (alien-type-class-or-lose include)))) - (if old - (setf (alien-type-class-include old) include) - (setf (gethash name *alien-type-classes*) - (make-alien-type-class :name name - :defstruct-name defstruct-name - :include include))))) - -(defconstant-eqx +method-slot-alist+ - '((:unparse . alien-type-class-unparse) - (:type= . alien-type-class-type=) - (:subtypep . alien-type-class-subtypep) - (:lisp-rep . alien-type-class-lisp-rep) - (:alien-rep . alien-type-class-alien-rep) - (:extract-gen . alien-type-class-extract-gen) - (:deposit-gen . alien-type-class-deposit-gen) - (:naturalize-gen . alien-type-class-naturalize-gen) - (:deport-gen . alien-type-class-deport-gen) - (:deport-alloc-gen . alien-type-class-deport-alloc-gen) - (:deport-pin-p . alien-type-class-deport-pin-p) - ;; cast? - (:arg-tn . alien-type-class-arg-tn) - (:result-tn . alien-type-class-result-tn)) - #'equal) - -(defun method-slot (method) - (cdr (or (assoc method +method-slot-alist+) - (error "no method ~S" method)))) - -(defmacro invoke-alien-type-method (method type &rest args) - (let ((slot (method-slot method))) - (once-only ((type type)) - `(funcall (do ((class (alien-type-class-or-lose (alien-type-class ,type)) - (alien-type-class-include class))) - ((null class) - (error "method ~S not defined for ~S" - ',method (alien-type-class ,type))) - (let ((fn (,slot class))) - (when fn - (return fn)))) - ,type ,@args)))) - -#+sb-xc -(defmacro maybe-with-pinned-objects (variables types &body body) - (declare (ignorable variables types)) - (let ((pin-variables - ;; Only pin things on GENCGC, since on CHENEYGC it'd imply - ;; disabling the GC. Which is something we don't want to do - ;; every time we're calling to C. - #+gencgc - (loop for variable in variables - for type in types - when (invoke-alien-type-method :deport-pin-p type) - collect variable))) - (if pin-variables - `(with-pinned-objects ,pin-variables - ,@body) - `(progn - ,@body)))) diff --git a/src/code/early-array.lisp b/src/code/early-array.lisp deleted file mode 100644 index f7f2fce265..0000000000 --- a/src/code/early-array.lisp +++ /dev/null @@ -1,20 +0,0 @@ -;;;; This software is part of the SBCL system. See the README file for -;;;; more information. -;;;; -;;;; This software is derived from the CMU CL system, which was -;;;; written at Carnegie Mellon University and released into the -;;;; public domain. The software is in the public domain and is -;;;; provided with absolutely no warranty. See the COPYING and CREDITS -;;;; files for more information. - -(in-package "SB-IMPL") - -(defconstant sb-xc:array-rank-limit 65529 - "the exclusive upper bound on the rank of an array") - -;;; - 2 to leave space for the array header -(defconstant sb-xc:array-dimension-limit (- sb-xc:most-positive-fixnum 2) - "the exclusive upper bound on any given dimension of an array") - -(defconstant sb-xc:array-total-size-limit (- sb-xc:most-positive-fixnum 2) - "the exclusive upper bound on the total number of elements in an array") diff --git a/src/code/early-cl.lisp b/src/code/early-cl.lisp deleted file mode 100644 index 038fe63bf7..0000000000 --- a/src/code/early-cl.lisp +++ /dev/null @@ -1,76 +0,0 @@ -;;;; miscellaneous stuff about the ANSI standard - -;;;; This software is part of the SBCL system. See the README file for -;;;; more information. -;;;; -;;;; This software is derived from the CMU CL system, which was -;;;; written at Carnegie Mellon University and released into the -;;;; public domain. The software is in the public domain and is -;;;; provided with absolutely no warranty. See the COPYING and CREDITS -;;;; files for more information. - -(in-package "SB-KERNEL") - -;;; the Common Lisp defined type spec symbols -(defparameter *!standard-type-names* - '(array atom bignum bit bit-vector character compiled-function - complex cons double-float extended-char fixnum float function - hash-table integer keyword list long-float nil null number package - pathname random-state ratio rational real readtable sequence - short-float simple-array simple-bit-vector simple-string simple-vector - single-float standard-char stream string base-char symbol t vector)) - -(define-load-time-global sb-sys::*software-version* nil) - -;;; The BOOLE function dispaches to any logic operation depending on -;;; the value of an argument. Presently, legal selector values are [0..15]. -;;; BOOLE is open coded for calls with any of the constants declared below. - -(defconstant sb-xc:boole-clr 0 - "Boole function op, makes BOOLE return 0.") - -(defconstant sb-xc:boole-set 1 - "Boole function op, makes BOOLE return -1.") - -(defconstant sb-xc:boole-1 2 - "Boole function op, makes BOOLE return integer1.") - -(defconstant sb-xc:boole-2 3 - "Boole function op, makes BOOLE return integer2.") - -(defconstant sb-xc:boole-c1 4 - "Boole function op, makes BOOLE return complement of integer1.") - -(defconstant sb-xc:boole-c2 5 - "Boole function op, makes BOOLE return complement of integer2.") - -(defconstant sb-xc:boole-and 6 - "Boole function op, makes BOOLE return logand of integer1 and integer2.") - -(defconstant sb-xc:boole-ior 7 - "Boole function op, makes BOOLE return logior of integer1 and integer2.") - -(defconstant sb-xc:boole-xor 8 - "Boole function op, makes BOOLE return logxor of integer1 and integer2.") - -(defconstant sb-xc:boole-eqv 9 - "Boole function op, makes BOOLE return logeqv of integer1 and integer2.") - -(defconstant sb-xc:boole-nand 10 - "Boole function op, makes BOOLE return log nand of integer1 and integer2.") - -(defconstant sb-xc:boole-nor 11 - "Boole function op, makes BOOLE return lognor of integer1 and integer2.") - -(defconstant sb-xc:boole-andc1 12 - "Boole function op, makes BOOLE return logandc1 of integer1 and integer2.") - -(defconstant sb-xc:boole-andc2 13 - "Boole function op, makes BOOLE return logandc2 of integer1 and integer2.") - -(defconstant sb-xc:boole-orc1 14 - "Boole function op, makes BOOLE return logorc1 of integer1 and integer2.") - -(defconstant sb-xc:boole-orc2 15 - "Boole function op, makes BOOLE return logorc2 of integer1 and integer2.") - diff --git a/src/code/early-class.lisp b/src/code/early-class.lisp deleted file mode 100644 index 75fd684bbe..0000000000 --- a/src/code/early-class.lisp +++ /dev/null @@ -1,134 +0,0 @@ -;;;; Early support routines for class-related things (including conditions). - -;;;; This software is part of the SBCL system. See the README file for -;;;; more information. -;;;; -;;;; This software is derived from the CMU CL system, which was -;;;; written at Carnegie Mellon University and released into the -;;;; public domain. The software is in the public domain and is -;;;; provided with absolutely no warranty. See the COPYING and CREDITS -;;;; files for more information. - -(in-package "SB-KERNEL") - -(defun call-with-defining-class (kind name thunk) - (declare (ignorable kind name)) - (with-single-package-locked-error - (:symbol name "defining ~S as a ~(~A~)" kind) - (funcall thunk))) - -(defun preinform-compiler-about-class-type (name forthcoming-info) - ;; Unless the type system already has an actual type attached to - ;; NAME (in which case (1) writing a placeholder value over that - ;; actual type as a compile-time side-effect would probably be a bad - ;; idea and (2) anyway we don't need to modify it in order to make - ;; NAME be recognized as a valid type name) - (when (and forthcoming-info (not (info :type :kind name))) - ;; Tell the compiler to expect a class with the given NAME, by - ;; writing a kind of minimal placeholder type information. This - ;; placeholder will be overwritten later when the class is - ;; defined. - (setf (info :type :kind name) :forthcoming-defclass-type))) - -(symbol-macrolet - ((reader-function-type (specifier-type '(function (t) t))) - (writer-function-type (specifier-type '(function (t t) t)))) - (flet ((proclaim-ftype-for-name (kind name type) - (ecase kind - (condition - (sb-xc:proclaim `(ftype ,(type-specifier type) ,name))) - (class - (when (eq (info :function :where-from name) :assumed) - (sb-c:proclaim-ftype name type nil :defined)))))) - - (defun preinform-compiler-about-accessors (kind readers writers) - (flet ((inform (names type) - (mapc (lambda (name) (proclaim-ftype-for-name kind name type)) - names))) - (inform readers reader-function-type) - (inform writers writer-function-type))) - - (defun preinform-compiler-about-slot-functions (kind slots) - (flet ((inform (slots key type) - (mapc (lambda (slot) - (let ((name (funcall key slot))) - (proclaim-ftype-for-name kind name type))) - slots))) - (inform slots #'sb-pcl::slot-reader-name reader-function-type) - (inform slots #'sb-pcl::slot-boundp-name reader-function-type) - (inform slots #'sb-pcl::slot-writer-name writer-function-type))))) - -(defun %%compiler-defclass (name readers writers slots) - ;; ANSI says (Macro DEFCLASS, section 7.7) that DEFCLASS, if it - ;; "appears as a top level form, the compiler must make the class - ;; name be recognized as a valid type name in subsequent - ;; declarations (as for deftype) and be recognized as a valid class - ;; name for defmethod parameter specializers and for use as the - ;; :metaclass option of a subsequent defclass." - (preinform-compiler-about-class-type name t) - (preinform-compiler-about-accessors 'class readers writers) - (preinform-compiler-about-slot-functions 'class slots)) - -(defun %compiler-defclass (name readers writers slots) - (call-with-defining-class - 'class name - (lambda () - (%%compiler-defclass name readers writers slots)))) - -;;; This used to be in an (EVAL-WHEN (:COMPILE-TOPLEVEL ...)) -;;; which no longer works, because at run-the-xc-time the -;;; WITH-SINGLE-PACKAGE-LOCKED-ERROR macro doesn't work yet, -;;; so just use the definition that was loaded from the fasl -;;; when the cross-compiler was compiled. -(defun %%compiler-define-condition (name direct-supers layout readers writers) - (declare (notinline find-classoid)) - (preinform-compiler-about-class-type name nil) - (preinform-compiler-about-accessors 'condition readers writers) - (multiple-value-bind (class old-layout) - (insured-find-classoid name - #'condition-classoid-p - #'make-condition-classoid) - (setf (layout-classoid layout) class) - (setf (classoid-direct-superclasses class) - (mapcar #'find-classoid direct-supers)) - (cond ((not old-layout) - (register-layout layout)) - ((not *type-system-initialized*) - (setf (layout-classoid old-layout) class) - (setq layout old-layout) - (unless (eq (classoid-layout class) layout) - (register-layout layout))) - ((redefine-layout-warning "current" - old-layout - "new" - (layout-length layout) - (layout-inherits layout) - (layout-depthoid layout) - (layout-bitmap layout)) - (register-layout layout :invalidate t)) - ((not (classoid-layout class)) - (register-layout layout))) - - ;; This looks totally bogus - it essentially means that the LAYOUT-INFO - ;; of a condition is good for nothing, because it describes something - ;; that is not the condition class being defined. - ;; In addition to which, the INFO for CONDITION itself describes - ;; slots which do not exist, viz: - ;; (dd-slots (layout-info (classoid-layout (find-classoid 'condition)))) - ;; => (#<DEFSTRUCT-SLOT-DESCRIPTION ACTUAL-INITARGS> - ;; #<DEFSTRUCT-SLOT-DESCRIPTION ASSIGNED-SLOTS>) - (setf (layout-info layout) - (layout-info (classoid-layout (find-classoid 'condition)))) - - (setf (find-classoid name) class) - - ;; Initialize CPL slot. - (setf (condition-classoid-cpl class) - (remove-if-not #'condition-classoid-p - (std-compute-class-precedence-list class))))) - -(defun %compiler-define-condition (name direct-supers layout readers writers) - (call-with-defining-class - 'condition name - (lambda () - (%%compiler-define-condition name direct-supers layout readers writers)))) diff --git a/src/code/early-classoid.lisp b/src/code/early-classoid.lisp index 9995877e8f..c20fd3eb0d 100644 --- a/src/code/early-classoid.lisp +++ b/src/code/early-classoid.lisp @@ -15,17 +15,25 @@ ;;;; DEFSTRUCT-DESCRIPTION +(defconstant +dd-named+ #b000001) ; :NAMED was specified +(defconstant +dd-printfun+ #b000010) ; :PRINT-FUNCTION was specified +(defconstant +dd-printobj+ #b000100) ; :PRINT-OBJECT was specified +(defconstant +dd-pure+ #b001000) ; :PURE T was specified +(defconstant +dd-varylen+ #b010000) +(defconstant +dd-nullenv+ #b100000) + ;;; The DEFSTRUCT-DESCRIPTION structure holds compile-time information ;;; about a structure type. -;;; It is defined prior to LAYOUT because a LAYOUT-INFO slot +;;; It is defined prior to WRAPPER because WRAPPER-INFO ;;; is declared to hold a DEFSTRUCT-DESCRIPTION. (def!struct (defstruct-description (:conc-name dd-) (:copier nil) (:pure t) - (:constructor make-defstruct-description (null-lexenv-p name))) + (:constructor make-defstruct-description (name flags))) ;; name of the structure (name (missing-arg) :type symbol :read-only t) + (flags 0 :type fixnum) ; see the constants above ;; documentation on the structure (doc nil :type (or string null)) ;; prefix for slot names. If NIL, none. @@ -33,8 +41,6 @@ ;; All the :CONSTRUCTOR specs and posssibly an implied constructor, ;; keyword constructors first, then BOA constructors. NIL if none. (constructors () :type list) - ;; True if the DEFSTRUCT appeared in a null lexical environment. - (null-lexenv-p nil :type boolean :read-only t) ; the safe default is NIL ;; name of copying function (copier-name nil :type symbol) ;; name of type predicate @@ -50,50 +56,60 @@ ;; a list of DEFSTRUCT-SLOT-DESCRIPTION objects for all slots ;; (including included ones) (slots () :type list) + ;; bit mask containing a 1 for each word that the garbage collector must visit + ;; (as opposed to a raw slot). Certain slot types (notably fixnum) may have either + ;; a 0 or a 1 in the mask because it does not matter if it is seen by GC. + ;; Bit index 0 in the mask is the word just after the header, and so on. + (bitmap +layout-all-tagged+ :type integer) ;; a list of (NAME . INDEX) pairs for accessors of included structures (inherited-accessor-alist () :type list) ;; number of data words, including the layout itself if the layout ;; requires an entire word (when no immobile-space) + ;; Technically this is redundant information: it can be derived from DD-SLOTS + ;; by taking the index of the final slot and adding its length in words. + ;; If there are no slots, then it's just INSTANCE-DATA-START. (length 0 :type index) ;; General kind of implementation. (type 'structure :type (member structure vector list funcallable-structure)) - ;; The next three slots are for :TYPE'd structures (which aren't - ;; classes, DD-CLASS-P = NIL) - ;; - ;; vector element type - (element-type t) - ;; T if :NAMED was explicitly specified, NIL otherwise - (named nil :type boolean) + ;; If this structure is a classoid, then T if all slots are tagged, * if not. + ;; If a vector, the vector element type. + ;; If a list, not used. + (%element-type t) ;; any INITIAL-OFFSET option on this direct type (offset nil :type (or index null)) - ;; which :PRINT-mumble option was given, if either was. - (print-option nil :type (member nil :print-function :print-object)) ;; the argument to the PRINT-FUNCTION or PRINT-OBJECT option. ;; NIL if the option was given with no argument. - (printer-fname nil :type (or cons symbol)) - - ;; the value of the :PURE option, used by cheneygc when purifying. - ;; This is true if objects of this class are never modified to - ;; contain dynamic pointers in their slots or constant-like - ;; substructure (and hence can be copied into read-only space by - ;; PURIFY). - ;; This is only meaningful if DD-CLASS-P = T. - (pure nil :type (member t nil))) -#-sb-fluid (declaim (freeze-type defstruct-description)) + (printer-fname nil :type (or cons symbol))) +(declaim (freeze-type defstruct-description)) (!set-load-form-method defstruct-description (:host :xc :target)) ;;;; basic LAYOUT stuff ;;; Careful here: if you add more bits, then adjust the bit packing for ;;; 64-bit layouts which also store LENGTH + DEPTHOID in the same word. -(defconstant +structure-layout-flag+ #b00000001) -(defconstant +pathname-layout-flag+ #b00000010) -(defconstant +condition-layout-flag+ #b00001000) -(defconstant +pcl-object-layout-flag+ #b00010000) -(defconstant sb-vm:lockfree-list-node-flag #b01000000) ; exported for use in gc-private.h +(defconstant +structure-layout-flag+ #b000000001) +(defconstant +pathname-layout-flag+ #b000000010) +(defconstant +pcl-object-layout-flag+ #b000000100) +(defconstant +condition-layout-flag+ #b000001000) +(defconstant +simple-stream-layout-flag+ #b000010000) +(defconstant +file-stream-layout-flag+ #b000100000) +(defconstant +string-stream-layout-flag+ #b001000000) +(defconstant +stream-layout-flag+ #b010000000) +(defconstant +sequence-layout-flag+ #b100000000) +(defconstant +strictly-boxed-flag+ #b1000000000) +(defconstant layout-flags-mask #xffff) ; "strictly flags" bits from the packed field + +;;; the type of LAYOUT-DEPTHOID and LAYOUT-LENGTH values. +;;; Each occupies two bytes of the %BITS slot when possible, +;;; otherwise a slot unto itself. +(def!type layout-depthoid () '(integer -1 #x7FFF)) +(def!type layout-length () '(integer 0 #xFFFF)) +(def!type layout-bitmap () 'integer) +;;; ID must be an fixnum for either value of n-word-bits. +(def!type layout-id () '(signed-byte 30)) ;;; The LAYOUT structure is pointed to by the first cell of instance ;;; (or structure) objects. It represents what we need to know for @@ -130,15 +146,12 @@ ;;; 32-bit is not done yet. Three slots are still used, instead of two. -;;; Maximum value of N in ANCESTOR_N. Couldn't come up with a better name. -(defconstant sb-c::layout-inherits-max-optimized-depth 5) -(sb-xc:defstruct (layout - ;; Accept a specific subset of keywords - #+64-bit (:constructor %make-layout - (clos-hash classoid flags info bitmap)) - #-64-bit (:constructor %make-layout - (clos-hash classoid depthoid length flags info bitmap)) - (:copier nil)) +#-metaspace +(progn +(sb-xc:defstruct (wrapper (:copier nil) + ;; Parsing DEFSTRUCT uses a temporary layout + (:constructor make-temporary-wrapper + (clos-hash classoid inherits &aux (invalid nil)))) ;; A packed field containing the DEPTHOID, LENGTH, and FLAGS #+64-bit (flags 0 :type (signed-byte #.sb-vm:n-word-bits)) @@ -188,140 +201,264 @@ #-64-bit (length 0 :type layout-length) ; smaller than SB-INT:INDEX ;; If this layout has some kind of compiler meta-info, then this is ;; it. If a structure, then we store the DEFSTRUCT-DESCRIPTION here. - (info nil :type (or null defstruct-description)) - ;; Map of raw slot indices. - (bitmap +layout-all-tagged+ :type layout-bitmap) - ;; Per-slot comparator for implementing EQUALP. - (equalp-tests #() :type simple-vector) ;; If this layout is for an object of metatype STANDARD-CLASS, - ;; these are the EFFECTIVE-SLOT-DEFINITION metaobjects. - (slot-list nil :type list) + ;; then these are the EFFECTIVE-SLOT-DEFINITION metaobjects. + ;; The two are mutually exclusive. + (%info nil :type (or list defstruct-description)) + ;; EQUALP comparator for two instances with this layout + ;; Could be the generalized function, or a type-specific one + ;; if the defstruct was compiled in a policy of SPEED 3. + (equalp-impl #'equalp-err :type (sfunction (t t) boolean) :read-only t) ;; Information about slots in the class to PCL: this provides fast ;; access to slot-definitions and locations by name, etc. ;; See MAKE-SLOT-TABLE in pcl/slots-boot.lisp for further details. (slot-table #(1 nil) :type simple-vector) - ;; inherited layouts or 0, only pertinent to structure classoids. - ;; There is no need to store the layout at depths 0 or 1 - ;; since they're predetermined to be T and STRUCTURE-OBJECT. - (ancestor_2 0) - (ancestor_3 0) - (ancestor_4 0) - (ancestor_5 0)) -(declaim (freeze-type layout)) - -;;; Applicable only if bit-packed (for 64-bit architectures) -(defmacro pack-layout-flags (depthoid length flags) - `(logior (ash ,(or depthoid -1) (+ 32 sb-vm:n-fixnum-tag-bits)) - (ash ,(or length 0) 16) - ,(or flags 0))) - -(defmacro set-layout-inherits (layout inherits &optional depthoid) - `(let* ((l ,layout) (i ,inherits) (d ,(or depthoid '(length i)))) - (declare (ignorable i d)) - ;; I tried putting a /SHOW here for debugging, but it's just too broken - ;; because layouts affect the printer dispatch mechanism. - #+nil - (let ((*print-pretty* nil)) - (fresh-line) - (write-string "SET-INHERITS ") - (write (layout-classoid-name l)) - (write-string " ") - (write (map 'list #'layout-classoid-name i)) - (terpri)) - (setf (layout-inherits l) i) - #-sb-xc-host - (setf (layout-ancestor_2 l) (if (> d 2) (svref i 2) 0) - (layout-ancestor_3 l) (if (> d 3) (svref i 3) 0) - (layout-ancestor_4 l) (if (> d 4) (svref i 4) 0) - (layout-ancestor_5 l) (if (> d 5) (svref i 5) 0)) - l)) - -#-sb-xc-host -(defun make-layout (clos-hash classoid - &key (depthoid -1) (length 0) (flags 0) - (inherits #() inheritsp) - (info nil) - (bitmap (if info (dd-bitmap info) +layout-all-tagged+))) - (let ((layout (%make-layout clos-hash classoid - #+64-bit (pack-layout-flags depthoid length flags) - #-64-bit depthoid #-64-bit length #-64-bit flags - info bitmap))) - (when inheritsp - (set-layout-inherits layout inherits)) - layout)) + (id-word0 0 :type word) + (id-word1 0 :type word) + (id-word2 0 :type word) + #-64-bit (id-word3 0 :type word) + #-64-bit (id-word4 0 :type word) + #-64-bit (id-word5 0 :type word)) +(declaim (freeze-type wrapper))) + +#+metaspace +(progn +;;; Separating the pointer and nonpointer slots of LAYOUT satisfies the +;;; requirement of a certain garbage collector (WIP), but also opens up the +;;; possibility of absorbing at least one of the vectorish slots into the +;;; WRAPPER since it could be reallocated with variable size. +;;; The SLOT-TABLE slot might be a good candidate for trailing tagged slots. +(sb-xc:defstruct (wrapper (:copier nil) (:constructor %make-wrapper)) + ;; !!! The FRIEND slot in WRAPPER *MUST* BE FIRST !!! (Wired-in assumption in genesis) + (friend nil :type sb-vm:layout) + (clos-hash (missing-arg) :type (and fixnum unsigned-byte)) ; redundant + (classoid (missing-arg) :type classoid) + (inherits #() :type simple-vector) + (equalp-impl #'equalp-err :type (sfunction (t t) boolean) :read-only t) + (slot-table #(1 nil) :type simple-vector) + (%info nil :type (or list defstruct-description)) + (invalid :uninitialized :type (or cons (member nil t :uninitialized)))) +;;; See #-metaspace structure definition for remarks about each slot. +;;; LAYOUT points to WRAPPER and vice-versa. +;;; The most common LAYOUT is 8 words. +;;; Needing >64 words would be quite unusual - the layout would have +;;; an enormous depthoid or bitmap or both. +(sb-xc:defstruct (sb-vm:layout (:copier nil) + ;; Parsing DEFSTRUCT uses a temporary layout + (:constructor %make-temporary-layout (friend clos-hash))) + ;; !!! The FRIEND slot in LAYOUT *MUST* BE FIRST !!! + (friend nil :type wrapper) + (clos-hash (missing-arg) :type (and fixnum unsigned-byte)) + (flags 0 :type (signed-byte #.sb-vm:n-word-bits)) + (id-word0 0 :type word) + (id-word1 0 :type word) + (id-word2 0 :type word) + ;; There are zero or more raw words if a type needs to store additional layout-ids, + ;; and there are one or more raw words for the GC bitmap. + ) +(declaim (freeze-type wrapper sb-vm:layout))) ;;; The cross-compiler representation of a LAYOUT omits several things: -;;; * BITMAP - obtainable via (DD-MAPMAP (LAYOUT-INFO layout)). +;;; * BITMAP - obtainable via (DD-BITMAP (LAYOUT-INFO layout)). ;;; GC wants it in the layout to avoid double indirection. ;;; * EQUALP-TESTS - needed only for the target's implementation of EQUALP. ;;; * SLOT-TABLE, and SLOT-LIST - used only by the CLOS implementation. -;;; * ANCESTOR_N are optimizations for TYPEP. +;;; * ID-WORDn are optimizations for TYPEP. ;;; So none of those really make sense on the host. ;;; Also, we eschew the packed representation of length+depthoid+flags. -;;; FLAGS are not even strictly necessary, since they are for optimizing -;;; various type checks. +;;; FLAGS are computed on demand, and not stored. #+sb-xc-host (progn - (defstruct (layout (:include structure!object) - (:constructor make-layout - (clos-hash classoid &key depthoid length flags inherits info))) + (defstruct (wrapper (:constructor host-make-wrapper + (id clos-hash classoid + &key ((:info %info)) depthoid inherits length invalid + #+metaspace friend))) + #+metaspace (friend) + (id nil :type (or null fixnum)) + ;; Cross-compiler-only translation from slot index to symbol naming + ;; the accessor to call. (Since access by position is not a thing) + (index->accessor-map #() :type simple-vector) ;; CLOS-HASH is needed to convert some TYPECASE forms to jump tables. ;; Theoretically we don't need this in the cross-compiler, because the ;; layout has a classoid which has a name which has a known hash. ;; But there's no harm in storing it. (clos-hash nil :type (and sb-xc:fixnum unsigned-byte)) (classoid nil :type classoid) - (flags 0 :type word) (invalid :uninitialized :type (or cons (member nil t :uninitialized))) (inherits #() :type simple-vector) (depthoid -1 :type layout-depthoid) (length 0 :type layout-length) - (info nil :type (or null defstruct-description))) - (defun layout-bitmap (layout) - (if (layout-info layout) (dd-bitmap (layout-info layout)) +layout-all-tagged+))) - -(defmacro sb-c::layout-nth-ancestor-slot (n) - `(case ,n - (2 'layout-ancestor_2) - (3 'layout-ancestor_3) - (4 'layout-ancestor_4) - (5 'layout-ancestor_5))) - -#+(and (not sb-xc-host) 64-bit) -;;; LAYOUT-DEPTHOID gets a vop and a stub -(defmacro layout-length (layout) ; SETFable - `(ldb (byte 16 16) (layout-flags ,layout))) + (%info nil :type (or null defstruct-description))) + #+metaspace (defstruct (sb-vm:layout (:constructor %make-layout)) + friend) + (defun make-temporary-wrapper (clos-hash classoid inherits) + (host-make-wrapper nil clos-hash classoid :inherits inherits :invalid nil)) + (defun wrapper-flags (wrapper) + (declare (type wrapper wrapper)) + (let ((mapping `((structure-object ,+structure-layout-flag+) + (standard-object ,+pcl-object-layout-flag+) + (pathname ,+pathname-layout-flag+) + (condition ,+condition-layout-flag+) + (file-stream ,+file-stream-layout-flag+) + (string-stream ,+string-stream-layout-flag+) + (stream ,+stream-layout-flag+) + (sequence ,+sequence-layout-flag+))) + (flags 0)) + (dolist (x (cons wrapper (coerce (wrapper-inherits wrapper) 'list))) + (let ((cell (assoc (wrapper-classoid-name x) mapping))) + (when cell (setq flags (logior flags (second cell)))))) + (let ((dd (wrapper-%info wrapper))) + (when (or (logtest flags (logior +pathname-layout-flag+ +condition-layout-flag+)) + (and (logtest flags +structure-layout-flag+) + dd + (eq (dd-%element-type dd) 't))) + (setf flags (logior flags +strictly-boxed-flag+)))) + ;; KLUDGE: I really don't care to make defstruct-with-alternate-metaclass + ;; any more complicated than necessary. It is unable to express that + ;; these funcallable instances can go on pure boxed pages. + ;; (The trampoline is always an assembler routine, thus ignorable) + (when (member (wrapper-classoid-name wrapper) + '(sb-pcl::ctor sb-pcl::%method-function)) + (setf flags (logior flags +strictly-boxed-flag+))) + flags)) + (defun wrapper-bitmap (wrapper) + (acond ((wrapper-%info wrapper) (dd-bitmap it)) + ;; Give T a 0 bitmap. It's arbitrary, but when we need some layout + ;; that has this bitmap we can use the layout of T. + ((eq wrapper (find-layout t)) 0) + (t + +layout-all-tagged+))) + (defun %layout-bitmap (layout) (wrapper-bitmap layout)) +) ; end PROGN #+sb-xc-host + +(defun equalp-err (a b) + (bug "EQUALP ~S ~S" a b)) + +(defmacro name->dd (name) + ;; This wants to be a toplevel macrolet but can't be, because the body of + ;; the macro (which is run in the host) wouldn't see NAME->DD as a macro + ;; when expanding for the target. And it can't be a toplevel FLET because + ;; that would demote the two using macros from toplevel. + `(find-defstruct-description (cond #-metaspace ((eq ,name 'sb-vm:layout) 'wrapper) + (t ,name)))) +(defmacro type-dd-length (type-name) (dd-length (name->dd type-name))) +(defmacro get-dsd-index (type-name slot-name) + (declare (notinline dsd-index)) ; avoid later inlining failure style-warning + (dsd-index (find slot-name (dd-slots (name->dd type-name)) :key #'dsd-name))) -(defconstant layout-flags-mask #xffff) ; "strictly flags" bits from the packed field +;;; Applicable only if bit-packed (for 64-bit architectures) +(defmacro pack-layout-flags (depthoid length flags) + `(logior (ash ,depthoid (+ 32 sb-vm:n-fixnum-tag-bits)) (ash ,length 16) ,flags)) + +(defconstant layout-id-vector-fixed-capacity 7) +(defmacro calculate-extra-id-words (depthoid) + ;; There are 1 or 2 ids per word depending on n-word-bytes. + ;; We can always store IDs at depthoids 2,3,4,5,6,7, + ;; so depthoid less than or equal to 7 needs no extra words. + ;; 0 and 1 for T and STRUCTURE-OBJECT respectively are not stored. + `(ceiling (max 0 (- ,depthoid ,layout-id-vector-fixed-capacity)) + ,(/ sb-vm:n-word-bytes 4))) + +(declaim (inline wrapper-info wrapper-dd)) +(defun wrapper-info (wrapper) + (let ((info (wrapper-%info wrapper))) (unless (listp info) info))) +(defun (setf wrapper-info) (newval wrapper) + ;; The current value must be nil or a defstruct-description, + ;; otherwise we'd clobber a non-nil slot list. + (aver (not (consp (wrapper-%info wrapper)))) + (setf (wrapper-%info wrapper) newval)) +;; Use WRAPPER-DD to read WRAPPER-INFO and assert that it is non-nil. +(defun wrapper-dd (wrapper) + (the defstruct-description (wrapper-%info wrapper))) + +;;; See the pictures above DD-BITMAP in src/code/defstruct for the details. +(defconstant standard-gf-primitive-obj-layout-bitmap + ;; layout has no bitmap bit. The other slots all look tagged even though + ;; it's an accident that the raw instruction words resemble fixnums. + ;; I should probably find a more principled way to express this, + ;; but the old - technically correct - way based on a bitmap really made + ;; the logic look like crap. But now that the variable-length part of a + ;; funcallable-instance follows its embedded trampoline, it would be simple + ;; to alter the GC to skip a fixed number of slots. + ;; I think that is preferable to using a bitmap. + #+compact-instance-header -1 + ;; the layout is considered untagged so that we don't doubly process it + ;; if walking tagged slots. The assumption is that layout is always + ;; handled separately, so therefore we don't want to process it again + ;; in a bitmap-based scan. And the entry point is considered untagged + ;; because it points to an assembler routine, thus ignorable. + #-compact-instance-header -4) -;;; Abstract out the differences between {32-bit,64-bit} target and XC layouts. -;;; FLAGS can't change once assigned. -(defmacro assign-layout-slots (layout &key depthoid length - (flags `(layout-flags ,layout)) flagsp) - (let ((invalidate-p (and (eql depthoid -1) (not length) (not flagsp)))) - #+(and 64-bit (not xc-host)) ; packed slot - `(setf (layout-flags ,layout) - ,(if invalidate-p - `(logior (ash -1 (+ 32 sb-vm:n-fixnum-tag-bits)) - (ldb (byte 32 0) (layout-flags ,layout))) - `(pack-layout-flags ,depthoid ,length - (logand ,flags layout-flags-mask)))) - #+(or (not 64-bit) sb-xc-host) ; ordinary slot - (if invalidate-p - `(setf (layout-depthoid ,layout) -1) - `(setf (layout-depthoid ,layout) ,depthoid - (layout-length ,layout) ,length - (layout-flags ,layout) ,flags)))) +#-sb-xc-host +(progn +(declaim (inline bitmap-start bitmap-nwords bitmap-all-taggedp)) +(defun bitmap-start (layout) + (+ (type-dd-length sb-vm:layout) + (calculate-extra-id-words (layout-depthoid layout)))) +(defun bitmap-nwords (layout) + (declare (sb-vm:layout layout)) + (- (%instance-length layout) + (calculate-extra-id-words (layout-depthoid layout)) + (type-dd-length sb-vm:layout))) +(defun bitmap-all-taggedp (layout) + ;; All bitmaps have at least 1 word; read that first. + (and (= (%raw-instance-ref/signed-word layout (bitmap-start layout)) + +layout-all-tagged+) + ;; Then check that there are no additional words. + (= (bitmap-nwords layout) 1))) + +#+metaspace ; If metaspace, then WRAPPER has no flags; they're in the LAYOUT. +(defmacro wrapper-flags (x) `(layout-flags (wrapper-friend ,x))) + +;; 32-bit has the depthoid as a slot, 64-bit has it is part of FLAGS which are +;; in the LAYOUT +#+64-bit +(defun wrapper-depthoid (wrapper) (layout-depthoid (wrapper-friend wrapper))) + +;;; Extract the bitmap from 1 or more words of bits that have the same format +;;; as a BIGNUM - least-significant word first, native bit order within each word, +;;; all but the last are unsigned, and the last is signed. +(defun %layout-bitmap (wrapper) + (declare (type wrapper wrapper)) + (do ((accumulator 0) + (shift 0) + (index (bitmap-start wrapper) (1+ index)) + (last (1- (%instance-length wrapper)))) + ((> index last) accumulator) + (setf accumulator (logior accumulator + (ash (if (= index last) + (%raw-instance-ref/signed-word wrapper index) + (%raw-instance-ref/word wrapper index)) + shift))) + (incf shift sb-vm:n-word-bits))) + +(defun wrapper-bitmap (wrapper) + (declare (type wrapper wrapper)) + ;; Whenever we call WRAPPER-BITMAP on a structure-object subtype, + ;; it's supposed to have the INFO slot populated, linking it to a defstruct-description. + (acond ((wrapper-info wrapper) (dd-bitmap it)) + ;; Instances lacking DD-INFO are CLOS objects, which can't generally have + ;; raw slots, except that funcallable-instances may have 2 raw slots - + ;; the trampoline and the layout. The trampoline can have a tag, depending + ;; on the platform, and the layout is tagged but a special case. + ;; In any event, the bitmap is always 1 word, and there are no "extra ID" + ;; words preceding it. + (t + (aver (not (logtest +structure-layout-flag+ (wrapper-flags wrapper)))) + (the fixnum + (%raw-instance-ref/signed-word (wrapper-friend wrapper) + (type-dd-length sb-vm:layout)))))) +#+64-bit +(defmacro wrapper-length (wrapper) ; SETFable + `(ldb (byte 16 16) (layout-flags (wrapper-friend ,wrapper)))) + +) ; end PROGN #-sb-xc-host ;;; True of STANDARD-OBJECT, which include generic functions. -;;; This one includes any class that mixes in STANDARD-OBJECT. (declaim (inline layout-for-pcl-obj-p)) -(defun layout-for-pcl-obj-p (x) - (logtest (layout-flags x) +pcl-object-layout-flag+)) - -(declaim (inline sb-fasl:dumpable-layout-p)) -(defun sb-fasl:dumpable-layout-p (x) - (and (typep x 'layout) (not (layout-for-pcl-obj-p x)))) +(defun layout-for-pcl-obj-p (wrapper) + (declare (type wrapper wrapper)) + (logtest (wrapper-flags wrapper) +pcl-object-layout-flag+)) ;;; The CLASSOID structure is a supertype of all classoid types. A ;;; CLASSOID is also a CTYPE structure as recognized by the type @@ -347,8 +484,8 @@ #-sb-xc-host (:pure nil)) ;; the value to be returned by CLASSOID-NAME. (name nil :type symbol) - ;; the current layout for this class, or NIL if none assigned yet - (layout nil :type (or layout null)) + ;; the current WRAPPER for this class, or NIL if none assigned yet + (wrapper nil :type (or null wrapper)) ;; How sure are we that this class won't be redefined? ;; :READ-ONLY = We are committed to not changing the effective ;; slots or superclasses. @@ -365,14 +502,16 @@ ;; otherwise, it's an EQ hash-table mapping CLASSOID objects to the ;; subclass layout that was in effect at the time the subclass was ;; created. - (subclasses nil :type (or null hash-table)) + ;; Initially an alist, and changed to a hash-table at some threshold. + (subclasses nil :type (or list hash-table)) + (%lock nil) ; install it just-in-time, similar to hash-table-lock ;; the PCL class (= CL:CLASS, but with a view to future flexibility ;; we don't just call it the CLASS slot) object for this class, or ;; NIL if none assigned yet (pcl-class nil)) -(defun layout-classoid-name (x) - (classoid-name (layout-classoid x))) +(defun wrapper-classoid-name (x) + (classoid-name (wrapper-classoid x))) ;;;; object types to represent classes @@ -394,13 +533,13 @@ ;;; This translation is done when type specifiers are parsed. Type ;;; system operations (union, subtypep, etc.) should never encounter ;;; translated classes, only their translation. -(def!struct (built-in-classoid (:include classoid) - (:copier nil) - (:constructor !make-built-in-classoid)) +(def!struct (built-in-classoid (:include classoid) (:copier nil) + (:constructor !make-built-in-classoid)) ;; the type we translate to on parsing. If NIL, then this class - ;; stands on its own; or it can be set to :INITIALIZING for a period - ;; during cold-load. - (translation nil :type (or ctype (member nil :initializing)))) + ;; stands on its own. Only :INITIALIZING for a period during cold + ;; load. + (translation nil :type (or null ctype (member :initializing))) + (predicate (missing-arg) :type (sfunction (t) boolean) :read-only t)) (def!struct (condition-classoid (:include classoid) (:copier nil) @@ -430,6 +569,15 @@ ;; environment of MAKE-CONDITION. (hairy-slots nil :type list)) +;;; STRUCTURE-CLASSOID represents what we need to know about structure +;;; classes. Non-structure "typed" defstructs are a special case, and +;;; don't have a corresponding class. +(def!struct (structure-classoid + (:include classoid) + (:copier nil) + (:constructor make-structure-classoid + (&key name &aux (%bits (pack-ctype-bits classoid name)))))) + ;;;; classoid namespace ;;; We use an indirection to allow forward referencing of class @@ -452,26 +600,6 @@ (declare (ignore env)) `(find-classoid-cell ',(classoid-cell-name self) :create t))) -(defun find-classoid-cell (name &key create) - (let ((real-name (uncross name))) - (cond ((info :type :classoid-cell real-name)) - (create - (get-info-value-initializing :type :classoid-cell real-name - (make-classoid-cell real-name)))))) - -;;; Return the classoid with the specified NAME. If ERRORP is false, -;;; then NIL is returned when no such class exists. -(defun find-classoid (name &optional (errorp t)) - (declare (type symbol name)) - (let ((cell (find-classoid-cell name))) - (cond ((and cell (classoid-cell-classoid cell))) - (errorp - (error 'simple-type-error - :datum nil - :expected-type 'class - :format-control "Class not yet defined: ~S" - :format-arguments (list name)))))) - ;;;; PCL stuff ;;; the CLASSOID that we use to represent type information for @@ -493,49 +621,3 @@ (declaim (freeze-type built-in-classoid condition-classoid standard-classoid static-classoid)) - -(in-package "SB-C") - -;;; layout for this type being used by the compiler -(define-info-type (:type :compiler-layout) - :type-spec (or layout null) - :default (lambda (name) - (awhen (find-classoid name nil) (classoid-layout it)))) - -(eval-when (#-sb-xc :compile-toplevel :load-toplevel :execute) -(defun ftype-from-fdefn (name) - (declare (ignorable name)) - ;; Again [as in (DEFINE-INFO-TYPE (:FUNCTION :TYPE) ...)] it's - ;; not clear how to generalize the FBOUNDP expression to the - ;; cross-compiler. -- WHN 19990330 - #+sb-xc-host - (specifier-type 'function) - #-sb-xc-host - (let* ((fdefn (sb-kernel::find-fdefn name)) - (fun (and fdefn (fdefn-fun fdefn)))) - (if fun - (handler-bind ((style-warning #'muffle-warning)) - (specifier-type (sb-impl::%fun-type fun))) - (specifier-type 'function))))) - -;;; The parsed or unparsed type for this function, or the symbol :GENERIC-FUNCTION. -;;; Ordinarily a parsed type is stored. Only if the parsed type contains -;;; an unknown type will the original specifier be stored; we attempt to reparse -;;; on each lookup, in the hope that the type becomes known at some point. -;;; If :GENERIC-FUNCTION, the info is recomputed from methods at the time of lookup -;;; and stored back. Method redefinition resets the value to :GENERIC-FUNCTION. -(define-info-type (:function :type) - :type-spec (or ctype (cons (eql function)) (member :generic-function)) - :default #'ftype-from-fdefn) - -(defun summarize-layouts () - (let ((prev -1)) - (dolist (layout (sort (loop for v being each hash-value - of (classoid-subclasses (find-classoid 't)) - collect v) - #'< :key #'sb-kernel:layout-flags)) - (let ((flags (sb-kernel:layout-flags layout))) - (unless (= flags prev) - (format t "Layout flags = ~d~%" flags) - (setq prev flags))) - (format t " ~a~%" layout)))) diff --git a/src/code/early-constants.lisp b/src/code/early-constants.lisp index c0b9f79441..b06d41801a 100644 --- a/src/code/early-constants.lisp +++ b/src/code/early-constants.lisp @@ -9,15 +9,67 @@ (in-package "SB-IMPL") -(defconstant-eqx sb-xc:lambda-list-keywords - '(&allow-other-keys - &aux - &body - &environment - &key - &more - &optional - &rest - &whole) - #'equal - "A list of symbols used as lambda list keywords in SBCL.") +(defconstant-eqx lambda-list-keywords + '(&allow-other-keys + &aux + &body + &environment + &key + &more + &optional + &rest + &whole) + #'equal + "A list of symbols used as lambda list keywords in SBCL.") + +;;; The BOOLE function dispaches to any logic operation depending on +;;; the value of an argument. Presently, legal selector values are [0..15]. +;;; BOOLE is open coded for calls with any of the constants declared below. + +(defconstant boole-clr 0 + "Boole function op, makes BOOLE return 0.") + +(defconstant boole-set 1 + "Boole function op, makes BOOLE return -1.") + +(defconstant boole-1 2 + "Boole function op, makes BOOLE return integer1.") + +(defconstant boole-2 3 + "Boole function op, makes BOOLE return integer2.") + +(defconstant boole-c1 4 + "Boole function op, makes BOOLE return complement of integer1.") + +(defconstant boole-c2 5 + "Boole function op, makes BOOLE return complement of integer2.") + +(defconstant boole-and 6 + "Boole function op, makes BOOLE return logand of integer1 and integer2.") + +(defconstant boole-ior 7 + "Boole function op, makes BOOLE return logior of integer1 and integer2.") + +(defconstant boole-xor 8 + "Boole function op, makes BOOLE return logxor of integer1 and integer2.") + +(defconstant boole-eqv 9 + "Boole function op, makes BOOLE return logeqv of integer1 and integer2.") + +(defconstant boole-nand 10 + "Boole function op, makes BOOLE return log nand of integer1 and integer2.") + +(defconstant boole-nor 11 + "Boole function op, makes BOOLE return lognor of integer1 and integer2.") + +(defconstant boole-andc1 12 + "Boole function op, makes BOOLE return logandc1 of integer1 and integer2.") + +(defconstant boole-andc2 13 + "Boole function op, makes BOOLE return logandc2 of integer1 and integer2.") + +(defconstant boole-orc1 14 + "Boole function op, makes BOOLE return logorc1 of integer1 and integer2.") + +(defconstant boole-orc2 15 + "Boole function op, makes BOOLE return logorc2 of integer1 and integer2.") diff --git a/src/code/early-defmethod.lisp b/src/code/early-defmethod.lisp index 32edb78d56..0468143a89 100644 --- a/src/code/early-defmethod.lisp +++ b/src/code/early-defmethod.lisp @@ -9,122 +9,106 @@ (in-package "SB-PCL") -;;;; Rudimentary DEFMETHOD - -(sb-xc:defmacro defmethod (&whole form name lambda-list &rest body - &aux qualifier) - (when (member name '((setf documentation) documentation) :test 'equal) - (return-from defmethod `(push ',form *!documentation-methods*))) - (when (keywordp lambda-list) - ;; Allow an :AFTER method in 'condition.lisp'. - ;; It's ignored during cold-init, but eventually takes effect. - (assert (eq lambda-list :after)) - (setq qualifier lambda-list lambda-list (pop body))) - (ecase name - (make-load-form - ;; Expect one mandatory class-name and the optional environment. - (assert (typep lambda-list - '(cons (cons symbol (cons symbol null)) - (cons (eql &optional) (cons symbol null)))))) - (print-object - ;; Expect one unqualified mandatory arg and one unqualified. - (assert (typep lambda-list '(cons (cons symbol (cons symbol null)) - (cons symbol null)))))) - (binding* ((specializer (cadar lambda-list)) ; only one allowd - (unspecialized-ll `(,(caar lambda-list) ,@(cdr lambda-list))) - ((forms decls) (parse-body body nil))) ; Note: disallowing docstring - `(!trivial-defmethod - ;; An extra NIL in front puts the GF name is the same position it would be in - ;; for a normal LOAD-DEFMETHOD. - nil ',name ',specializer ,qualifier ',unspecialized-ll - ;; OAOO problem: compute the same lambda name as real DEFMETHOD would - (named-lambda (fast-method ,name - (,specializer ,@(if (eq name 'print-object) '(t)))) - (.pv. .next-method-call. .arg0. ,@(cdr unspecialized-ll) - ;; Rebind specialized arg with unchecked type assertion. - &aux (,(car unspecialized-ll) (truly-the ,specializer .arg0.))) - (declare (ignore .pv. .next-method-call.) - (ignorable ,(car unspecialized-ll))) - ,@decls - ;; Fail at compile-time if any transformational magic needs to happen. - (macrolet ,(mapcar (lambda (f) - `(,f (&rest args) - (declare (ignore args)) - (error "can't use ~A in trivial method" ',f))) - '(slot-boundp slot-value %set-slot-value call-next-method)) - (flet (((setf slot-value) (&rest args) `(%set-slot-value ,@args))) - (declare (inline (setf slot-value))) - (block ,name ,@forms)))) - ;; Why is SOURCE-LOC needed? Lambdas should know their location. - (sb-c:source-location)))) +(define-condition specialized-lambda-list-error + (reference-condition simple-program-error) + () + (:default-initargs :references '((:ansi-cl :section (3 4 3))))) -(defvar *!trivial-methods* '()) ; necessary methods for system startup -(defvar *!documentation-methods* nil) ; saved up for after PCL bootstrap -(defun !trivial-defmethod (dummy name specializer qualifier lambda-list lambda source-loc) - (declare (ignore dummy)) ; this would be the method class in LOAD-DEFMETHOD - (let ((gf (assoc name *!trivial-methods*))) - ;; Append the method but don't bother finding a predicate for it. - ;; Methods occurring in early warm load (notably from SB-FASTEVAL) - ;; will be properly installed when 'pcl/print-object.lisp' is loaded. - (rplacd gf (concatenate 'vector (cdr gf) - (list (vector nil ; guard - qualifier specializer lambda - lambda-list source-loc)))))) +(defun specialized-lambda-list-error (format-control &rest format-arguments) + (error 'specialized-lambda-list-error + :format-control format-control + :format-arguments format-arguments)) -;;; Slow-but-correct logic for single-dispatch sans method combination, -;;; allowing exactly one primary method. Methods are sorted most-specific-first, -;;; so we can stop looking as soon as a match is found. -;;; Sorting is performed during genesis. -(defun !call-a-method (gf-name specialized-arg &rest rest) - (let* ((methods (the simple-vector - (cdr (or (assoc gf-name *!trivial-methods*) - (error "No methods on ~S" gf-name))))) - (applicable-method - ;; Find a method where the guard returns T. If that fails, find a method - ;; which exactly matches TYPE-OF the specialized-arg. - ;; It might be nice to rely only on the TYPE-OF test, but then we'd have to - ;; concern ourselves with type hierarchies. - ;; The "method" is a vector: - ;; #(#<GUARD> QUALIFIER SPECIALIZER #<FMF> LAMBDA-LIST SOURCE-LOC) - (or (find-if (lambda (method &aux (guard (svref method 0))) - (and (or (functionp guard) (fboundp guard)) - (funcall guard specialized-arg))) - methods) - (find (type-of specialized-arg) methods - :key (lambda (x) (svref x 2)))))) +;; Return 3 values: +;; - the bound variables, without defaults, supplied-p vars, or &AUX vars. +;; - the lambda list without specializers. +;; - just the specializers +(defun parse-specialized-lambda-list (arglist) + (binding* (((llks specialized optional rest key aux) + (parse-lambda-list + arglist + :context 'defmethod + :accept (lambda-list-keyword-mask + '(&optional &rest &key &allow-other-keys &aux)) + :silent t ; never signal &OPTIONAL + &KEY style-warning + :condition-class 'specialized-lambda-list-error)) + (required (mapcar (lambda (x) (if (listp x) (car x) x)) specialized)) + (specializers (mapcar (lambda (x) (if (listp x) (cadr x) t)) specialized))) + (check-lambda-list-names + llks required optional rest key aux nil nil + :context "a method lambda list" :signal-via #'specialized-lambda-list-error) + (values (append required + (mapcar #'parse-optional-arg-spec optional) + rest + ;; Preserve keyword-names when given as (:KEYWORD var) + (mapcar (lambda (x) + (if (typep x '(cons cons)) + (car x) + (parse-key-arg-spec x))) + key)) + (make-lambda-list llks nil required optional rest key aux) + specializers))) + - (if applicable-method - ;; Call using no permutation-vector / no precomputed next method. - (apply (svref applicable-method 3) nil nil specialized-arg rest) - (error "No applicable method for ~S on ~S~%" gf-name - (type-of specialized-arg))))) +;;; PARSE-DEFMETHOD is used by DEFMETHOD to parse the &REST argument +;;; into the 'real' arguments. This is where the syntax of DEFMETHOD +;;; is really implemented. +(defun parse-defmethod (cdr-of-form) + (declare (list cdr-of-form)) + (let ((qualifiers ()) + (spec-ll ())) + (loop (if (and (car cdr-of-form) (atom (car cdr-of-form))) + (push (pop cdr-of-form) qualifiers) + (return (setq qualifiers (nreverse qualifiers))))) + (setq spec-ll (pop cdr-of-form)) + (values qualifiers spec-ll cdr-of-form))) -;;; For any "trivial" PRINT-OBJECT method lacking a predicate to determine -;;; its applicability, try to install one now. -;;; (Question: could not genesis find a predicate for everything?) -(defun !fixup-print-object-method-guards () - ;; LAYOUT-OF has an ordinary definition appearing later, unless a vop translates - ;; it, in which case it has to be inlined because the stub isn't ready for use. - #-(vop-translates sb-kernel:layout-of) (declare (notinline layout-of)) - ;; Wouldn't you know, DOVECTOR is in early-extensions, - ;; and it would need to go in primordial-extensions to use it here. - (loop for method across (cdr (assoc 'print-object sb-pcl::*!trivial-methods*)) - unless (svref method 0) - do (let ((classoid (find-classoid (elt method 2)))) - (setf (svref method 0) - (lambda (x) (classoid-typep (layout-of x) classoid x)))))) - -(defun make-load-form (object &optional environment) - (!call-a-method 'make-load-form object environment)) -(defun print-object (object stream) - (!call-a-method 'print-object object stream)) +;;;; Rudimentary DEFMETHOD -;;; FIXME: this no longer holds methods, but it seems to have an effect -;;; on the caching of a discriminating function for PRINT-OBJECT -(defvar *!delayed-defmethod-args* nil) +;;; This expander avoids the use of the rest of CLOS in order to help +;;; with bootstrapping. +(sb-xc:defmacro defmethod (name &rest args) + (check-designator name 'defmethod #'legal-fun-name-p "function name") + (multiple-value-bind (qualifiers lambda-list body) + (parse-defmethod args) + (multiple-value-bind (parameters unspecialized-ll specializers) + (parse-specialized-lambda-list lambda-list) + (multiple-value-bind (forms decls) + (parse-body body nil) ; Note: disallowing docstring + `(!early-load-method 'standard-method + ',name ',qualifiers ',specializers ',unspecialized-ll + ;; OAOO problem: compute the same lambda name as real DEFMETHOD would + (named-lambda (fast-method ,name ,@qualifiers ,specializers) + (.pv. .next-method-call. ,@unspecialized-ll) + ,@decls + (declare (ignore .pv. .next-method-call.)) + ;; Rebind arguments, asserting specialized types. (unchecked) + (let ,(mapcar (lambda (parameter specializer) + `(,parameter (truly-the ,specializer ,parameter))) + parameters specializers) + (declare ,@(mapcar (lambda (parameter specializer) + (declare (ignore specializer)) + `(ignorable ,parameter)) + parameters specializers)) + ;; Fail at compile-time if any fancy slot access would happen, if compiled + ;; by the eventual implementation. + ;; (SETF SLOT-VALUE) is not a legal macro name, so transform it as a + ;; an ignorable function that uses a legal macro name. + (macrolet ,(mapcar (lambda (f) + `(,f (&rest args) + (declare (ignore args)) + (error "can't use ~A in initial method" ',f))) + '(slot-boundp slot-value %set-slot-value call-next-method)) + (flet (((setf slot-value) (&rest args) `(%set-slot-value ,@args))) + (declare (inline (setf slot-value)) (ignorable #'(setf slot-value))) + (block ,(fun-name-block-name name) ,@forms))))) + (sb-c:source-location)))))) -;;; This exists only to show that the cross-compiler can constant-fold -;;; a constant index into a literal array without crashing. -(defun !test-svref-folding () - (let ((z #(42 test))) - (if (< (svref z 0) 100) t nil))) +(define-source-context defmethod (name &rest stuff) + (let ((arg-pos (position-if #'listp stuff))) + (if arg-pos + `(defmethod ,name ,@(subseq stuff 0 arg-pos) + ,(handler-case + (nth-value 2 (parse-specialized-lambda-list (elt stuff arg-pos))) + (error () "<illegal syntax>"))) + `(defmethod ,name "<illegal syntax>")))) diff --git a/src/code/early-extensions.lisp b/src/code/early-extensions.lisp index 135d0d6813..e015ad1128 100644 --- a/src/code/early-extensions.lisp +++ b/src/code/early-extensions.lisp @@ -13,10 +13,42 @@ (in-package "SB-IMPL") +;;; FIXME: a lot of places in the code that should use ARRAY-RANGE +;;; instead use INDEX and vice-versa, but the thing is, we have +;;; a ton of fenceposts errors all over the place regardless. +;;; CLHS glosary reference: +;;; "array total size n. the total number of elements in an array, +;;; computed by taking the product of the dimensions of the array." +;;; and ARRAY-TOTAL-SIZE-LIMIT: +;;; "The upper exclusive bound on the array total size of an array." + +;;; Consider a reduced example for the sake of argument in which +;;; ARRAY-TOTAL-SIZE-LIMIT were 21. +;;; - the largest vector would have LENGTH 20. +;;; - the largest legal index for AREF on it would be 19. +;;; - the largest legal :END on sequence functions would be 20. +;;; Nothing should allow 21. So DEFTYPE ARRAY-RANGE is wrong +;;; and must never be used for anything. +;;; Unfortunately, it's all over mb-util and enc-utf etc. +;;; +;;; *Also* INDEX is wrong, as the comment there says. +;;; To fix these and also SEQUENCE-END: +;;; - INDEX should be `(integer 0 (,1- array-dimension-limit)) +;;; - ARRAY-RANGE should be `(integer 0 (,array-dimension-limit)) +;;; - SEQUENCE-END (in deftypes-for-target) should be +;;; `(OR NULL ARRAY-RANGE) +;;; +;;; A further consideration for INDEX on 64-bit machines is that +;;; if INDEX were equivalent to (UNSIGNED-BYTE n) for some 'n' +;;; then (TYPEP X 'INDEX) can combines FIXNUMP and the range test into +;;; one bit-masking test, depending on the architecture. +;;; Probably it should be (UNSIGNED-BYTE 61) except on ppc64 +;;; where it would have to be (UNSIGNED-BYTE 59). + ;;; A number that can represent an index into a vector, including ;;; one-past-the-end (deftype array-range () - `(integer 0 ,sb-xc:array-dimension-limit)) + `(integer 0 ,array-dimension-limit)) ;;; a type used for indexing into sequences, and for related ;;; quantities like lengths of lists and other sequences. @@ -35,13 +67,13 @@ ;;; MOST-POSITIVE-FIXNUM lets the system know it can increment a value ;;; of type INDEX without having to worry about using a bignum to ;;; represent the result. -(def!type index () `(integer 0 (,sb-xc:array-dimension-limit))) +(def!type index () `(integer 0 (,array-dimension-limit))) ;;; like INDEX, but augmented with -1 (useful when using the index ;;; to count downwards to 0, e.g. LOOP FOR I FROM N DOWNTO 0, with ;;; an implementation which terminates the loop by testing for the ;;; index leaving the loop range) -(def!type index-or-minus-1 () `(integer -1 (,sb-xc:array-dimension-limit))) +(def!type index-or-minus-1 () `(integer -1 (,array-dimension-limit))) ;;; The smallest power of two that is equal to or greater than X. (declaim (inline power-of-two-ceiling)) @@ -277,7 +309,7 @@ ,result))) `(let ((,n-table ,table)) ,(if locked - `(with-locked-system-table (,n-table) ,iter-form) + `(with-system-mutex ((hash-table-lock ,n-table)) ,iter-form) iter-form)))) ;;; Executes BODY for all entries of PLIST with KEY and VALUE bound to @@ -285,6 +317,7 @@ (defmacro doplist ((key val) plist &body body) (with-unique-names (tail) `(let ((,tail ,plist) ,key ,val) + (declare (ignorable ,key ,val)) (loop (when (null ,tail) (return nil)) (setq ,key (pop ,tail)) (when (null ,tail) @@ -435,6 +468,7 @@ NOTE: This interface is experimental and subject to change." ;; Make a new hash-cache and optionally create the statistics vector. (defun alloc-hash-cache (size symbol) + (declare (type index size)) (let (cache) ;; It took me a while to figure out why infinite recursion could occur ;; in VALUES-SPECIFIER-TYPE. It's because SET calls VALUES-SPECIFIER-TYPE. @@ -556,7 +590,7 @@ NOTE: This interface is experimental and subject to change." (let* ,(case (length temps) (2 `((,(first temps) (car ,entry)) (,(second temps) (cdr ,entry)))) - (3 (let ((arg-temp (sb-xc:gensym "ARGS"))) + (3 (let ((arg-temp (gensym "ARGS"))) `((,arg-temp (cdr ,entry)) (,(first temps) (car ,entry)) (,(second temps) @@ -604,7 +638,7 @@ NOTE: This interface is experimental and subject to change." (values ,@result-temps)))))) `(progn (pushnew ',var-name *cache-vector-symbols*) - (!define-load-time-global ,var-name nil) + (define-load-time-global ,var-name nil) ,@(when *profile-hash-cache* `((declaim (type (simple-array fixnum (3)) ,statistics-name)) (defvar ,statistics-name))) @@ -706,6 +740,10 @@ NOTE: This interface is experimental and subject to change." (defun legal-fun-name-p (name) (values (valid-function-name-p name))) +(declaim (inline legal-class-name-p)) +(defun legal-class-name-p (thing) + (symbolp thing)) + ;;; * extended-function-designator: an object that denotes a function and that is one of: ;;; a function name (denoting the function it names in the global environment), ;;; or a function (denoting itself). The consequences are undefined if a function name @@ -789,7 +827,7 @@ NOTE: This interface is experimental and subject to change." (let* ((name (first spec)) (exp-temp (gensym "ONCE-ONLY"))) `(let ((,exp-temp ,(second spec)) - (,name (sb-xc:gensym ,(symbol-name name)))) + (,name (gensym ,(symbol-name name)))) `(let ((,,name ,,exp-temp)) ,,(frob (rest specs) body)))))))) @@ -1039,6 +1077,12 @@ NOTE: This interface is experimental and subject to change." (defun print-type (stream type &optional colon at) (print-type-specifier stream (type-specifier type) colon at))) +(defun print-lambda-list (stream lambda-list &optional colon at) + (declare (ignore colon at)) + (let ((sb-pretty:*pprint-quote-with-syntactic-sugar* nil) + (*package* *cl-package*)) + (format stream "~:A" lambda-list))) + ;;;; Deprecating stuff @@ -1126,7 +1170,7 @@ NOTE: This interface is experimental and subject to change." ((or symbol cons) (%check-deprecated-type type-specifier)) (class - (let ((name (class-name type-specifier))) + (let ((name (cl:class-name type-specifier))) (when (and name (symbolp name) (eq type-specifier (find-class name nil))) (%check-deprecated-type name)))))) @@ -1161,13 +1205,6 @@ NOTE: This interface is experimental and subject to change." ;;; - SOCKINT::WIN32-IOCTL since 1.2.10 (03/2015) -> Late: 08/2015 ;;; - SOCKINT::WIN32-SETSOCKOPT since 1.2.10 (03/2015) -> Late: 08/2015 ;;; - SOCKINT::WIN32-GETSOCKOPT since 1.2.10 (03/2015) -> Late: 08/2015 -;;; -;;; - SB-C::MERGE-TAIL-CALLS (policy) since 1.0.53.74 (11/2011) -> Late: 11/2012 -;;; -;;; LATE: -;;; - SB-C::STACK-ALLOCATE-DYNAMIC-EXTENT (policy) since 1.0.19.7 -> Final: anytime -;;; - SB-C::STACK-ALLOCATE-VECTOR (policy) since 1.0.19.7 -> Final: anytime -;;; - SB-C::STACK-ALLOCATE-VALUE-CELLS (policy) since 1.0.19.7 -> Final: anytime (defun setup-function-in-final-deprecation (software version name replacement-spec) @@ -1196,7 +1233,7 @@ NOTE: This interface is experimental and subject to change." (defun setup-type-in-final-deprecation (software version name replacement-spec) (declare (ignore software version replacement-spec)) - (%compiler-deftype name (constant-type-expander name t) nil)) + (%deftype name (constant-type-expander name t) nil)) ;; Given DECLS as returned by from parse-body, and SYMBOLS to be bound ;; (with LET, MULTIPLE-VALUE-BIND, etc) return two sets of declarations: @@ -1216,7 +1253,9 @@ NOTE: This interface is experimental and subject to change." ((or (listp id) ; must be a type-specifier (memq id '(special ignorable ignore dynamic-extent - truly-dynamic-extent)) + truly-dynamic-extent + sb-c::constant-value + sb-c::no-constraints)) (info :type :kind id)) (cdr decl)))))) (partition (spec) @@ -1335,33 +1374,6 @@ NOTE: This interface is experimental and subject to change." (length cache)))) short-name)))))) -;;; Just like WITH-OUTPUT-TO-STRING but doesn't close the stream, -;;; producing more compact code. -(defmacro with-simple-output-to-string - ((var &optional string (element-type :default)) &body body) - ;; Don't need any fancy type-specifier parsing. Uses of this macro - ;; are confined to our own code. So the element-type is literally - ;; either :DEFAULT or BASE-CHAR. - (aver (member element-type '(base-char :default))) - (multiple-value-bind (forms decls) (parse-body body nil) - (if string - `(let ((,var (make-fill-pointer-output-stream ,string))) - ,@decls - ,@forms) - ;; Why not dxify this stream? - `(let ((,var #+sb-xc-host (make-string-output-stream) - #-sb-xc-host - ,(case element-type - ;; Non-unicode doesn't have %MAKE-DEFAULT-STRING-OSTREAM - #+sb-unicode - (:default '(%make-default-string-ostream)) - ;; and this macro is never employed to make streams - ;; that can only return CHARACTER string. - (t '(%make-base-string-ostream))))) - ,@decls - ,@forms - (get-output-stream-string ,var))))) - (in-package "SB-KERNEL") (defun fp-zero-p (x) diff --git a/src/code/early-fasl.lisp b/src/code/early-fasl.lisp deleted file mode 100644 index 4b54500e6f..0000000000 --- a/src/code/early-fasl.lisp +++ /dev/null @@ -1,188 +0,0 @@ -;;;; needed-early, or at least meaningful-early, stuff for FASL files - -;;;; This software is part of the SBCL system. See the README file for -;;;; more information. -;;;; -;;;; This software is derived from the CMU CL system, which was -;;;; written at Carnegie Mellon University and released into the -;;;; public domain. The software is in the public domain and is -;;;; provided with absolutely no warranty. See the COPYING and CREDITS -;;;; files for more information. - -(in-package "SB-FASL") - -;;;; various constants and essentially-constants - -;;; a string which appears at the start of a fasl file header -;;; -;;; This value is used to identify fasl files. Even though this is not -;;; declared as a constant (because ANSI Common Lisp has no facility -;;; for declaring values which are constant under EQUAL but not EQL), -;;; obviously you shouldn't mess with it lightly. If you do set a new -;;; value for some reason, keep these things in mind: -;;; * To avoid confusion with the similar but incompatible CMU CL -;;; fasl file format, the value should not be "FASL FILE", which -;;; is what CMU CL used for the same purpose. -;;; * Since its presence at the head of a file is used by LOAD to -;;; decide whether a file is to be fasloaded or just loaded -;;; ordinarily (as source), the value should be something which -;;; can't legally appear at the head of a Lisp source file. -;;; * The value should not contain any line-terminating characters, -;;; because they're hard to express portably and because the LOAD -;;; code might reasonably use READ-LINE to get the value to compare -;;; against. -(defglobal *fasl-header-string-start-string* "# FASL") - -;;; a list of SB-XC:*FEATURES* flags which affect binary compatibility, -;;; i.e. which must be the same between the SBCL which compiled the code -;;; and the SBCL which executes the code. This is a property of SBCL executables -;;; in the abstract, not of this particular SBCL executable, -;;; so any flag in this list may or may not be present -;;; in the *FEATURES* list of this particular build. -(defglobal *features-potentially-affecting-fasl-format* - (append '(:sb-thread :sb-unicode :cheneygc - :gencgc :msan :sb-safepoint :sb-safepoint-strictly))) - -;;; Return a string representing symbols in *FEATURES-POTENTIALLY-AFFECTING-FASL-FORMAT* -;;; which are present in a particular compilation. -(defun compute-features-affecting-fasl-format () - (let ((list (sort (copy-list (intersection *features-potentially-affecting-fasl-format* - sb-xc:*features*)) - #'string< :key #'symbol-name))) - ;; Stringify the subset of *FEATURES* that affect fasl format. - ;; A list would be the natural representation choice for this, but a string - ;; is convenient for and a requirement for writing to and reading from fasls - ;; at this stage of the loading. WITH-STANDARD-IO-SYNTAX and WRITE-TO-STRING - ;; would work, but this is simple enough to do by hand. - (with-simple-output-to-string (stream) - (let ((delimiter #\()) - (dolist (symbol list) - (write-char delimiter stream) - (write-string (string symbol) stream) - (setq delimiter #\Space))) - (write-char #\) stream)))) - -#-sb-xc-host -(eval-when (:compile-toplevel) - (let ((string (compute-features-affecting-fasl-format))) - (assert (and (> (length string) 2) - (not (find #\newline string)) - (not (find #\# string)) - (not (search ".." string)))))) - -;;; the code for a character which terminates a fasl file header -(defconstant +fasl-header-string-stop-char-code+ 255) - -;;; This value should be incremented when the system changes in such a -;;; way that it will no longer work reliably with old fasl files. In -;;; practice, I (WHN) have often forgotten to increment it for CVS -;;; versions which break binary compatibility. But it certainly should -;;; be incremented for release versions which break binary -;;; compatibility. -(defconstant +fasl-file-version+ 78) -;;; (description of versions before 0.9.0.1 deleted in 0.9.17) -;;; 56: (2005-05-22) Something between 0.9.0.1 and 0.9.0.14. My money is -;;; on 0.9.0.6 (MORE CASE CONSISTENCY). -;;; 57: (2005-06-12) Raw slot rearrangement in 0.9.1.38 -;;; 58: (2005-08-16) Multiple incompatible changes between 0.9.3 and 0.9.3.60 -;;; 59: (2005-09-18) METAOBJECT implementation, removal of INSTANCE and -;;; FUNCALLABLE-INSTANCE classes. -;;; 60: (2005-10-24) Bumped for 0.9.6 -;;; 61: (2005-11-06) Improved source location recording added extra parameters -;;; to multiple %DEFMUMBLE functions. -;;; 62: (2005-12-30) Make the count of FASL header counted strings -;;; a 32-bit value also on 64-bit platforms. -;;; 63: (2006-01-27) Shuffle storage classes around to reduce the error -;;; trap information size on RISCy platforms. -;;; 64: (2006-03-24) New calling convention for unknown-values on x86 and -;;; x86-64. Also (belatedly) PPC/gencgc, including :gencgc on FPAFF. -;;; 65: (2006-04-11) Package locking interface changed. -;;; 66: (2006-05-13) Fopcompiler -;;; 67: (2006-07-25) Reports on #lisp about 0.9.13 fasls being invalid on -;;; 0.9.14.something -;;; 68: (2006-08-14) changed number of arguments of LOAD-DEFMETHOD -;;; 69: (2006-08-17) changed validity of various initargs for methods -;;; 70: (2006-09-13) changes to *PSEUDO-ATOMIC* on x86 and x86-64 -;;; 71: (2006-11-19) CLOS calling convention changes -;;; 72: (2006-12-05) Added slot to the primitive function type -;;; 73: (2007-04-13) Changed a hash function -;;; 74: (2007-06-05) UNWIND-TO-FRAME-AND-CALL -;;; 75: (2007-08-06) FD-STREAM layout changes -;;; 76: (2007-10-05) MUTEX layout changes -;;; 77: (2007-11-08) Essentially obsolete fasl-file-version, fasls are now -;;; considered compatible only when the version numbers of the compiling -;;; SBCL instance is exactly the same as the one of the loading instance. -;;; Further fasl-file-version bumps should only be done for real changes -;;; in the fasl format, not for changes in function/macro signatures or -;;; lisp data structures. -;;; 78: (2010-04-02) Add FOP-{SMALL-,}NAMED-PACKAGE, remove FOP-NORMAL-LOAD -;;; and FOP-MAYBE-COLD-LOAD. - -;;; the conventional file extension for our fasl files -;;; FIXME this should be (DEFCONSTANT-EQX +FASL-FILE-TYPE+ "fasl" #'EQUAL), -;;; but renaming the variable would harm 'asdf-dependency-grovel' and other -;;; random 3rd-party libraries. However, we can't keep the name and make it -;;; constant, because the compiler warns about asterisks on constants. -;;; So we keep the asterisks and make it defglobal. -(declaim (type simple-string *fasl-file-type*)) -(defglobal *fasl-file-type* "fasl") - -;;;; the FOP database - -(eval-when (:compile-toplevel :load-toplevel :execute) - ;; The bottom 5 bits of the opcodes above 128 encode an implicit operand. - (defconstant n-ordinary-fops 128)) - -;;; a vector indexed by a FaslOP that yields a function which performs -;;; the operation. Most functions take 0 arguments - they only manipulate -;;; the fop stack. But if the fop is defined to receive an argument (or two) -;;; then loader's main loop is responsible for supplying it. -(defglobal **fop-funs** (make-array n-ordinary-fops :initial-element 0)) -(declaim (type (simple-vector #.n-ordinary-fops) **fop-funs**)) - -;;; Two arrays indicate fop function signature. -;;; The first array indicates how many integer operands follow the opcode. -;;; The second tells whether the fop wants its result pushed on the stack. -(declaim (type (cons (simple-array (mod 4) (#.n-ordinary-fops)) - (simple-bit-vector #.n-ordinary-fops)) - **fop-signatures**)) -(defglobal **fop-signatures** - (cons (make-array n-ordinary-fops :element-type '(mod 4) :initial-element 0) - (make-array n-ordinary-fops :element-type 'bit :initial-element 0))) - -;;;; variables - -(defvar *load-depth* 0 - "the current number of recursive LOADs") -(declaim (type index *load-depth*)) - -(defun make-fop-vector (size) - (declare (type index size)) - (let ((vector (make-array size))) - (setf (aref vector 0) 0) - vector)) - -;;; a holder for the FASL file we're reading from -(defstruct (fasl-input (:conc-name %fasl-input-) - (:constructor make-fasl-input (stream)) - (:predicate nil) - (:copier nil)) - (stream nil :type ansi-stream :read-only t) - (table (make-fop-vector 1000) :type simple-vector) - (stack (make-fop-vector 100) :type simple-vector) - (name-buffer (vector (make-string 1 :element-type 'character) - (make-string 31 :element-type 'base-char))) - (deprecated-stuff nil :type list) - ;; Sometimes we want to skip over any FOPs with side-effects (like - ;; function calls) while executing other FOPs. SKIP-UNTIL will - ;; either contain the position where the skipping will stop, or - ;; NIL if we're executing normally. - (skip-until nil :type (or null fixnum))) -(declaim (freeze-type fasl-input)) - -;;; Unique number assigned into high 4 bytes of 64-bit code size slot -;;; so that we can sort the contents of varyobj space in a more-or-less -;;; predictable manner based on the order in which code was loaded. -;;; This wraps around at 32 bits, but it's still deterministic. -(define-load-time-global *code-serialno* 0) -(declaim (fixnum *code-serialno*)) diff --git a/src/code/early-float.lisp b/src/code/early-float.lisp index d2a6bf64a3..4588bbd815 100644 --- a/src/code/early-float.lisp +++ b/src/code/early-float.lisp @@ -17,7 +17,8 @@ ;;;; utilities -(eval-when (:compile-toplevel :load-toplevel :execute) +;;; Don't need to define it in the host in both passes +(eval-when (#-sb-xc :compile-toplevel :load-toplevel :execute) ;;; These functions let us create floats from bits with the ;;; significand uniformly represented as an integer. This is less @@ -49,58 +50,58 @@ ) ; EVAL-WHEN ;;;; float parameters -(defconstant sb-xc:most-positive-single-float #.sb-xc:most-positive-single-float) -(defconstant sb-xc:most-negative-single-float #.sb-xc:most-negative-single-float) -(defconstant sb-xc:most-positive-double-float #.sb-xc:most-positive-double-float) -(defconstant sb-xc:most-negative-double-float #.sb-xc:most-negative-double-float) -(defconstant sb-xc:pi #.sb-xc:pi) +(defconstant most-positive-single-float #.most-positive-single-float) +(defconstant most-negative-single-float #.most-negative-single-float) +(defconstant most-positive-double-float #.most-positive-double-float) +(defconstant most-negative-double-float #.most-negative-double-float) +(defconstant pi #.pi) -(defconstant sb-xc:least-positive-single-float (single-from-bits 0 0 1)) -(defconstant sb-xc:least-positive-short-float (single-from-bits 0 0 1)) -(defconstant sb-xc:least-negative-single-float (single-from-bits 1 0 1)) -(defconstant sb-xc:least-negative-short-float (single-from-bits 1 0 1)) -(defconstant sb-xc:least-positive-double-float (double-from-bits 0 0 1)) +(defconstant least-positive-single-float (single-from-bits 0 0 1)) +(defconstant least-positive-short-float (single-from-bits 0 0 1)) +(defconstant least-negative-single-float (single-from-bits 1 0 1)) +(defconstant least-negative-short-float (single-from-bits 1 0 1)) +(defconstant least-positive-double-float (double-from-bits 0 0 1)) #-long-float -(defconstant sb-xc:least-positive-long-float (double-from-bits 0 0 1)) +(defconstant least-positive-long-float (double-from-bits 0 0 1)) #+(and long-float x86) -(defconstant sb-xc:least-positive-long-float (long-from-bits 0 0 1)) -(defconstant sb-xc:least-negative-double-float (double-from-bits 1 0 1)) +(defconstant least-positive-long-float (long-from-bits 0 0 1)) +(defconstant least-negative-double-float (double-from-bits 1 0 1)) #-long-float -(defconstant sb-xc:least-negative-long-float (double-from-bits 1 0 1)) +(defconstant least-negative-long-float (double-from-bits 1 0 1)) #+(and long-float x86) -(defconstant sb-xc:least-negative-long-float (long-from-bits 1 0 1)) +(defconstant least-negative-long-float (long-from-bits 1 0 1)) -(defconstant sb-xc:least-positive-normalized-single-float +(defconstant least-positive-normalized-single-float (single-from-bits 0 sb-vm:single-float-normal-exponent-min 0)) -(defconstant sb-xc:least-positive-normalized-short-float - sb-xc:least-positive-normalized-single-float) -(defconstant sb-xc:least-negative-normalized-single-float +(defconstant least-positive-normalized-short-float + least-positive-normalized-single-float) +(defconstant least-negative-normalized-single-float (single-from-bits 1 sb-vm:single-float-normal-exponent-min 0)) -(defconstant sb-xc:least-negative-normalized-short-float - sb-xc:least-negative-normalized-single-float) -(defconstant sb-xc:least-positive-normalized-double-float +(defconstant least-negative-normalized-short-float + least-negative-normalized-single-float) +(defconstant least-positive-normalized-double-float (double-from-bits 0 sb-vm:double-float-normal-exponent-min 0)) #-long-float -(defconstant sb-xc:least-positive-normalized-long-float - sb-xc:least-positive-normalized-double-float) +(defconstant least-positive-normalized-long-float + least-positive-normalized-double-float) #+(and long-float x86) -(defconstant sb-xc:least-positive-normalized-long-float +(defconstant least-positive-normalized-long-float (long-from-bits 0 sb-vm:long-float-normal-exponent-min (ash sb-vm:long-float-hidden-bit 32))) -(defconstant sb-xc:least-negative-normalized-double-float +(defconstant least-negative-normalized-double-float (double-from-bits 1 sb-vm:double-float-normal-exponent-min 0)) #-long-float -(defconstant sb-xc:least-negative-normalized-long-float - sb-xc:least-negative-normalized-double-float) +(defconstant least-negative-normalized-long-float + least-negative-normalized-double-float) #+(and long-float x86) -(defconstant sb-xc:least-negative-normalized-long-float +(defconstant least-negative-normalized-long-float (long-from-bits 1 sb-vm:long-float-normal-exponent-min (ash sb-vm:long-float-hidden-bit 32))) -(defconstant sb-xc:most-positive-short-float sb-xc:most-positive-single-float) -(defconstant sb-xc:most-negative-short-float sb-xc:most-negative-single-float) -(defconstant sb-xc:most-positive-long-float sb-xc:most-positive-double-float) -(defconstant sb-xc:most-negative-long-float sb-xc:most-negative-double-float) +(defconstant most-positive-short-float most-positive-single-float) +(defconstant most-negative-short-float most-negative-single-float) +(defconstant most-positive-long-float most-positive-double-float) +(defconstant most-negative-long-float most-negative-double-float) (defconstant single-float-positive-infinity #.(sb-impl::make-flonum :+infinity 'single-float)) (defconstant single-float-negative-infinity #.(sb-impl::make-flonum :-infinity 'single-float)) @@ -124,28 +125,28 @@ (long-from-bits 1 (1+ sb-vm:long-float-normal-exponent-max) (ash sb-vm:long-float-hidden-bit 32))) -(defconstant sb-xc:single-float-epsilon +(defconstant single-float-epsilon (single-from-bits 0 (- sb-vm:single-float-bias (1- sb-vm:single-float-digits)) 1)) -(defconstant sb-xc:short-float-epsilon sb-xc:single-float-epsilon) -(defconstant sb-xc:single-float-negative-epsilon +(defconstant short-float-epsilon single-float-epsilon) +(defconstant single-float-negative-epsilon (single-from-bits 0 (- sb-vm:single-float-bias sb-vm:single-float-digits) 1)) -(defconstant sb-xc:short-float-negative-epsilon sb-xc:single-float-negative-epsilon) -(defconstant sb-xc:double-float-epsilon +(defconstant short-float-negative-epsilon single-float-negative-epsilon) +(defconstant double-float-epsilon (double-from-bits 0 (- sb-vm:double-float-bias (1- sb-vm:double-float-digits)) 1)) #-long-float -(defconstant sb-xc:long-float-epsilon sb-xc:double-float-epsilon) +(defconstant long-float-epsilon double-float-epsilon) #+(and long-float x86) -(defconstant sb-xc:long-float-epsilon +(defconstant long-float-epsilon (long-from-bits 0 (- sb-vm:long-float-bias (1- sb-vm:long-float-digits)) (+ 1 (ash sb-vm:long-float-hidden-bit 32)))) -(defconstant sb-xc:double-float-negative-epsilon +(defconstant double-float-negative-epsilon (double-from-bits 0 (- sb-vm:double-float-bias sb-vm:double-float-digits) 1)) #-long-float -(defconstant sb-xc:long-float-negative-epsilon sb-xc:double-float-negative-epsilon) +(defconstant long-float-negative-epsilon double-float-negative-epsilon) #+(and long-float x86) -(defconstant sb-xc:long-float-negative-epsilon +(defconstant long-float-negative-epsilon (long-from-bits 0 (- sb-vm:long-float-bias sb-vm:long-float-digits) (+ 1 (ash sb-vm:long-float-hidden-bit 32)))) diff --git a/src/code/early-format.lisp b/src/code/early-format.lisp deleted file mode 100644 index 9d274f5934..0000000000 --- a/src/code/early-format.lisp +++ /dev/null @@ -1,50 +0,0 @@ -;;;; This software is part of the SBCL system. See the README file for -;;;; more information. -;;;; -;;;; This software is derived from the CMU CL system, which was -;;;; written at Carnegie Mellon University and released into the -;;;; public domain. The software is in the public domain and is -;;;; provided with absolutely no warranty. See the COPYING and CREDITS -;;;; files for more information. - -(in-package "SB-FORMAT") - -(declaim (type (simple-vector 128) - *format-directive-expanders* - *format-directive-interpreters*)) -(defglobal *format-directive-expanders* (make-array 128 :initial-element nil)) -(define-load-time-global *format-directive-interpreters* - (make-array 128 :initial-element nil)) - -(defvar *default-format-error-control-string* nil) -(defvar *default-format-error-offset* nil) - -;;;; specials used to communicate information - -;;; Used both by the expansion stuff and the interpreter stuff. When it is -;;; non-NIL, up-up-and-out (~:^) is allowed. Otherwise, ~:^ isn't allowed. -(defvar *up-up-and-out-allowed* nil) - -;;; Used by the interpreter stuff. When it's non-NIL, it's a function -;;; that will invoke PPRINT-POP in the right lexical environemnt. -(defvar *logical-block-popper* nil) -(declaim (type (or null function) *logical-block-popper*) - (always-bound *logical-block-popper*)) - -;;; Used by the expander stuff. This is bindable so that ~<...~:> -;;; can change it. -(defvar *expander-next-arg-macro* 'expander-next-arg) - -;;; Used by the expander stuff. Initially starts as T, and gets set to NIL -;;; if someone needs to do something strange with the arg list (like use -;;; the rest, or something). -(defvar *only-simple-args*) - -;;; Used by the expander stuff. We do an initial pass with this as NIL. -;;; If someone doesn't like this, they (THROW 'NEED-ORIG-ARGS NIL) and we try -;;; again with it bound to T. If this is T, we don't try to do anything -;;; fancy with args. -(defvar *orig-args-available* nil) - -;;; Used by the expander stuff. List of (symbol . offset) for simple args. -(defvar *simple-args*) diff --git a/src/code/early-full-eval.lisp b/src/code/early-full-eval.lisp index 7acf3107ae..9bb0d35b74 100644 --- a/src/code/early-full-eval.lisp +++ b/src/code/early-full-eval.lisp @@ -11,9 +11,6 @@ (in-package "SB-EVAL") -(defparameter *eval-level* -1) ; initialized by genesis -(defparameter *eval-verbose* nil) ; initialized by genesis - ;; !defstruct-with-alternate-metaclass is unslammable and the ;; RECOMPILE restart doesn't work on it. This is the main reason why ;; this stuff is split out into its own file. Also, it lets the @@ -32,20 +29,3 @@ :metaclass-name static-classoid :metaclass-constructor make-static-classoid :dd-type funcallable-structure) - -(defun make-interpreted-function - (&key name lambda-list env declarations documentation body source-location - (debug-lambda-list lambda-list)) - (let ((function (%make-interpreted-function - name name lambda-list debug-lambda-list env - declarations documentation body source-location))) - (setf (%funcallable-instance-fun function) - #'(lambda (&rest args) - (interpreted-apply function args))) - function)) - -(defmethod print-object ((obj interpreted-function) stream) - (print-unreadable-object (obj stream - :identity (not (interpreted-function-name obj))) - (format stream "~A ~A" '#:interpreted-function - (interpreted-function-name obj)))) diff --git a/src/code/early-impl.lisp b/src/code/early-impl.lisp index 70754f90b0..7aa23d549b 100644 --- a/src/code/early-impl.lisp +++ b/src/code/early-impl.lisp @@ -23,25 +23,22 @@ sb-vm:*control-stack-start* sb-vm:*control-stack-end* sb-vm:*binding-stack-start* - #+(or hpux) sb-vm::*c-lra* *allow-with-interrupts* sb-unix::*unblock-deferrables-on-enabling-interrupts-p* *interrupts-enabled* *interrupt-pending* - #+sb-thruption *thruption-pending* + #+sb-safepoint *thruption-pending* #+sb-safepoint *in-safepoint* *free-interrupt-context-index* - #-gencgc - sb-vm::*allocation-pointer* sb-vm::*binding-stack-pointer* sb-pcl::*cache-miss-values-stack* sb-pcl::*dfun-miss-gfs-on-stack*)) -(defvar sb-vm:*alloc-signal*) ; initialized by create_thread_struct() + ;;; This is a slot of 'struct thread' if multithreaded, ;;; and the symbol-global-value should never be used. ;;; (And in any case it is not really a special var) #+(and (or x86 x86-64) (not sb-thread)) -(defparameter *pseudo-atomic-bits* 0) ; initialized by genesis +(defvar *pseudo-atomic-bits* 0) #+c-stack-is-control-stack (setf (info :variable :always-bound 'sb-c:*alien-stack-pointer*) :always-bound) @@ -60,14 +57,20 @@ ;;; comparisons. Unlikely, but the cost of using a cons instead is too ;;; small to measure. -- JES, 2007-09-30 (declaim (type cons sb-kernel::*gc-epoch*)) -(!define-load-time-global sb-kernel::*gc-epoch* '(nil . nil)) +(define-load-time-global sb-kernel::*gc-epoch* '(nil . nil)) -;;; Default evaluator mode (interpeter / compiler) +;;; Default evaluator mode (interpreter / compiler) (declaim (type (member :compile #+(or sb-eval sb-fasteval) :interpret) *evaluator-mode*)) -(defparameter *evaluator-mode* :compile ; initialized by genesis +(defparameter *evaluator-mode* :compile "Toggle between different evaluator implementations. If set to :COMPILE, an implementation of EVAL that calls the compiler will be used. If set to :INTERPRET, an interpreter will be used.") (declaim (always-bound *evaluator-mode*)) + +(declaim (inline sb-vm:is-lisp-pointer)) +(defun sb-vm:is-lisp-pointer (addr) ; Same as is_lisp_pointer() in C + #-64-bit (oddp addr) + #+ppc64 (= (logand addr #b101) #b100) + #+(and 64-bit (not ppc64)) (not (logtest (logxor addr 3) 3))) diff --git a/src/code/early-ntrace.lisp b/src/code/early-ntrace.lisp index c57382260d..7c36cca971 100644 --- a/src/code/early-ntrace.lisp +++ b/src/code/early-ntrace.lisp @@ -20,16 +20,28 @@ (defvar *trace-encapsulate-default* t "the default value for the :ENCAPSULATE option to TRACE") + +(defvar *trace-report-default* 'trace + "the default value for the :REPORT option to TRACE") + ;;;; internal state ;;; a hash table that maps each traced function to the TRACE-INFO. The -;;; entry for a closure is the shared function entry object. +;;; entry for a closure is the shared function entry object. The entry +;;; for a method is a (CL:METHOD name qualifiers* (specializers*)) +;;; list. (define-load-time-global *traced-funs* - (make-hash-table :test 'eq :synchronized t)) + (make-hash-table :test 'equal :synchronized t)) + +;;; a hash-table that maps the name of outer functions to local +;;; functions keys in the *TRACED-FUNS* hash-table, e.g.: NAME-X -> +;;; ((NAME-Y :IN NAME-X) (NAME-Z :IN NAME-X)). +(define-load-time-global *traced-locals* + (make-hash-table :test 'equal :synchronized t)) (deftype trace-report-type () - '(member nil trace)) + '(or symbol function)) ;;; A TRACE-INFO object represents all the information we need to ;;; trace a given function. @@ -39,8 +51,6 @@ (prin1 (trace-info-what x) stream))))) ;; the original representation of the thing traced (what nil :type (or function cons symbol)) - ;; Is WHAT a function name whose definition we should track? - (named nil) ;; Is tracing to be done by encapsulation rather than breakpoints? ;; T implies NAMED. (encapsulated *trace-encapsulate-default*) @@ -64,7 +74,7 @@ ;; (the default.) ;; report type - (report 'trace :type trace-report-type) + (report *trace-report-default* :type trace-report-type) ;; current environment forms (condition nil) (break nil) diff --git a/src/code/early-package.lisp b/src/code/early-package.lisp index ac2712d1c1..547eb35cc6 100644 --- a/src/code/early-package.lisp +++ b/src/code/early-package.lisp @@ -18,11 +18,6 @@ ;;; context. (define-thread-local *ignored-package-locks* :invalid) -;; This proclamation avoids a ton of style warnings due to so many calls -;; that get cross-compiled prior to compiling "target-package.lisp" -(declaim (ftype (sfunction ((or symbol list) &optional (or string function) &rest t) t) - assert-symbol-home-package-unlocked)) - (defmacro with-single-package-locked-error ((&optional kind thing &rest format) &body body) (with-unique-names (topmost) diff --git a/src/code/early-print.lisp b/src/code/early-print.lisp deleted file mode 100644 index fcdfdebba6..0000000000 --- a/src/code/early-print.lisp +++ /dev/null @@ -1,213 +0,0 @@ -;;;; printer stuff which has to be defined early (e.g. DEFMACROs) - -;;;; This software is part of the SBCL system. See the README file for -;;;; more information. -;;;; -;;;; This software is derived from the CMU CL system, which was -;;;; written at Carnegie Mellon University and released into the -;;;; public domain. The software is in the public domain and is -;;;; provided with absolutely no warranty. See the COPYING and CREDITS -;;;; files for more information. - -(in-package "SB-IMPL") - -;;;; level and length abbreviations - -;;; The current level we are printing at, to be compared against -;;; *PRINT-LEVEL*. See the macro DESCEND-INTO for a handy interface to -;;; depth abbreviation. -(defparameter *current-level-in-print* 0) ; initialized by genesis -(declaim (index *current-level-in-print*)) - -;;; Automatically handle *PRINT-LEVEL* abbreviation. If we are too -;;; deep, then a #\# is printed to STREAM and BODY is ignored. -(defmacro descend-into ((stream) &body body) - (let ((flet-name (sb-xc:gensym "DESCEND"))) - `(flet ((,flet-name () - ,@body)) - (cond ((and (null *print-readably*) - (let ((level *print-level*)) - (and level (>= *current-level-in-print* level)))) - (write-char #\# ,stream)) - (t - (let ((*current-level-in-print* (1+ *current-level-in-print*))) - (,flet-name))))))) - -;;; Punt if INDEX is equal or larger then *PRINT-LENGTH* (and -;;; *PRINT-READABLY* is NIL) by outputting \"...\" and returning from -;;; the block named NIL. -(defmacro punt-print-if-too-long (index stream) - `(when (and (not *print-readably*) - (let ((len *print-length*)) - (and len (>= ,index len)))) - (write-string "..." ,stream) - (return))) - - -;;;; circularity detection stuff - -;;; When *PRINT-CIRCLE* is T, this gets bound to a hash table that -;;; (eventually) ends up with entries for every object printed. When -;;; we are initially looking for circularities, we enter a T when we -;;; find an object for the first time, and a 0 when we encounter an -;;; object a second time around. When we are actually printing, the 0 -;;; entries get changed to the actual marker value when they are first -;;; printed. -(defvar *circularity-hash-table* nil) - -;;; When NIL, we are just looking for circularities. After we have -;;; found them all, this gets bound to 0. Then whenever we need a new -;;; marker, it is incremented. -(defvar *circularity-counter* nil) - -;;; Check to see whether OBJECT is a circular reference, and return -;;; something non-NIL if it is. If ASSIGN is true, reference -;;; bookkeeping will only be done for existing entries, no new -;;; references will be recorded. If ASSIGN is true, then the number to -;;; use in the #n= and #n# noise is assigned at this time. -;;; -;;; Note: CHECK-FOR-CIRCULARITY must be called *exactly* once with -;;; ASSIGN true, or the circularity detection noise will get confused -;;; about when to use #n= and when to use #n#. If this returns non-NIL -;;; when ASSIGN is true, then you must call HANDLE-CIRCULARITY on it. -;;; If CHECK-FOR-CIRCULARITY returns :INITIATE as the second value, -;;; you need to initiate the circularity detection noise, e.g. bind -;;; *CIRCULARITY-HASH-TABLE* and *CIRCULARITY-COUNTER* to suitable values -;;; (see #'OUTPUT-OBJECT for an example). -;;; -;;; Circularity detection is done in two places, OUTPUT-OBJECT and -;;; WITH-CIRCULARITY-DETECTION (which is used from PPRINT-LOGICAL-BLOCK). -;;; These checks aren't really redundant (at least I can't really see -;;; a clean way of getting by with the checks in only one of the places). -;;; This causes problems when mixed with pprint-dispatching; an object is -;;; marked as visited in OUTPUT-OBJECT, dispatched to a pretty printer -;;; that uses PPRINT-LOGICAL-BLOCK (directly or indirectly), leading to -;;; output like #1=#1#. The MODE parameter is used for detecting and -;;; correcting this problem. -(defun check-for-circularity (object &optional assign (mode t)) - (when (null *print-circle*) - ;; Don't bother, nobody cares. - (return-from check-for-circularity nil)) - (let ((circularity-hash-table *circularity-hash-table*)) - (cond - ((null circularity-hash-table) - (values nil :initiate)) - ((null *circularity-counter*) - (ecase (gethash object circularity-hash-table) - ((nil) - ;; first encounter - (setf (gethash object circularity-hash-table) mode) - ;; We need to keep looking. - nil) - ((:logical-block) - (setf (gethash object circularity-hash-table) - :logical-block-circular) - t) - ((t) - (cond ((eq mode :logical-block) - ;; We've seen the object before in output-object, and now - ;; a second time in a PPRINT-LOGICAL-BLOCK (for example - ;; via pprint-dispatch). Don't mark it as circular yet. - (setf (gethash object circularity-hash-table) - :logical-block) - nil) - (t - ;; second encounter - (setf (gethash object circularity-hash-table) 0) - ;; It's a circular reference. - t))) - ((0 :logical-block-circular) - ;; It's a circular reference. - t))) - (t - (let ((value (gethash object circularity-hash-table))) - (case value - ((nil t :logical-block) - ;; If NIL, we found an object that wasn't there the - ;; first time around. If T or :LOGICAL-BLOCK, this - ;; object appears exactly once. Either way, just print - ;; the thing without any special processing. Note: you - ;; might argue that finding a new object means that - ;; something is broken, but this can happen. If someone - ;; uses the ~@<...~:> format directive, it conses a new - ;; list each time though format (i.e. the &REST list), - ;; so we will have different cdrs. - nil) - ;; A circular reference to something that will be printed - ;; as a logical block. Wait until we're called from - ;; PPRINT-LOGICAL-BLOCK with ASSIGN true before assigning the - ;; number. - ;; - ;; If mode is :LOGICAL-BLOCK and assign is false, return true - ;; to indicate that this object is circular, but don't assign - ;; it a number yet. This is necessary for cases like - ;; #1=(#2=(#2# . #3=(#1# . #3#))))). - (:logical-block-circular - (cond ((and (not assign) - (eq mode :logical-block)) - t) - ((and assign - (eq mode :logical-block)) - (let ((value (incf *circularity-counter*))) - ;; first occurrence of this object: Set the counter. - (setf (gethash object circularity-hash-table) value) - value)) - (t - nil))) - (0 - (if (eq assign t) - (let ((value (incf *circularity-counter*))) - ;; first occurrence of this object: Set the counter. - (setf (gethash object circularity-hash-table) value) - value) - t)) - (t - ;; second or later occurrence - (- value)))))))) - -;;; Handle the results of CHECK-FOR-CIRCULARITY. If this returns T then -;;; you should go ahead and print the object. If it returns NIL, then -;;; you should blow it off. -(defun handle-circularity (marker stream) - (case marker - (:initiate - ;; Someone forgot to initiate circularity detection. - (let ((*print-circle* nil)) - (error "trying to use CHECK-FOR-CIRCULARITY when ~ - circularity checking isn't initiated"))) - ((t :logical-block) - ;; It's a second (or later) reference to the object while we are - ;; just looking. So don't bother groveling it again. - nil) - (t - (write-char #\# stream) - (output-integer (abs marker) stream 10 nil) - (cond ((minusp marker) - (write-char #\# stream) - nil) - (t - (write-char #\= stream) - t))))) - -(defmacro with-circularity-detection ((object stream) &body body) - (with-unique-names (marker body-name) - `(labels ((,body-name () - ,@body)) - (cond ((or (not *print-circle*) - (uniquely-identified-by-print-p ,object)) - (,body-name)) - (*circularity-hash-table* - (let ((,marker (check-for-circularity ,object t :logical-block))) - (if ,marker - (when (handle-circularity ,marker ,stream) - (,body-name)) - (,body-name)))) - (t - (let ((*circularity-hash-table* (make-hash-table :test 'eq))) - (output-object ,object (make-broadcast-stream)) - (let ((*circularity-counter* 0)) - (let ((,marker (check-for-circularity ,object t - :logical-block))) - (when ,marker - (handle-circularity ,marker ,stream))) - (,body-name)))))))) diff --git a/src/code/early-raw-slots.lisp b/src/code/early-raw-slots.lisp index 1295e1ba23..297ec5b074 100644 --- a/src/code/early-raw-slots.lisp +++ b/src/code/early-raw-slots.lisp @@ -45,7 +45,14 @@ ;; these abstractions are provided as soon as the raw slots defs are. (def!type sb-vm:word () `(unsigned-byte ,sb-vm:n-word-bits)) (def!type sb-vm:signed-word () `(signed-byte ,sb-vm:n-word-bits)) -(defconstant +layout-all-tagged+ -1) + +;;; This constant has a 1 bit meaning "tagged" for every user data slot. +;;; If LAYOUT is not in the header word, then (%INSTANCE-REF instance 0) +;;; indicates as raw so that GC treats layouts consistently, not scanning +;;; them en passant while visiting the payload. Consequently, 0 means either +;;; no slots or all raw, no matter if the layout consumes a slot. +;;; See remarks above CALCULATE-DD-BITMAP for further details. +(defconstant +layout-all-tagged+ (ash -1 sb-vm:instance-data-start)) ;; information about how a slot of a given DSD-RAW-TYPE is to be accessed (defstruct (raw-slot-data @@ -61,20 +68,28 @@ #-sb-xc-host (comparator (missing-arg) :type function :read-only t) ;; the type specifier, which must specify a numeric type. (raw-type (missing-arg) :type symbol :read-only t) - (init-vop (missing-arg) :type symbol :read-only t) + (init-vop (missing-arg) :type symbol :read-only t) ; FIXME: remove ;; How many words are each value of this type? (n-words (missing-arg) :type (and index (integer 1)) :read-only t) ;; Necessary alignment in units of words. Note that instances ;; themselves are aligned by exactly two words, so specifying more ;; than two words here would not work. (alignment 1 :type (integer 1 2) :read-only t)) +(declaim (freeze-type raw-slot-data)) -#-sb-xc-host -(progn (declaim (inline raw-slot-data-accessor-name)) - (defun raw-slot-data-accessor-name (rsd) - (%simple-fun-name (raw-slot-data-accessor-fun rsd)))) +(declaim (inline raw-slot-data-reader-name)) +(defun raw-slot-data-reader-name (rsd) + #+sb-xc-host (raw-slot-data-accessor-name rsd) + #-sb-xc-host (%simple-fun-name (raw-slot-data-accessor-fun rsd))) -#-sb-fluid (declaim (freeze-type raw-slot-data)) +(defun raw-slot-data-writer-name (rsd) + (ecase (raw-slot-data-reader-name rsd) + (%raw-instance-ref/word '%raw-instance-set/word) + (%raw-instance-ref/single '%raw-instance-set/single) + (%raw-instance-ref/double '%raw-instance-set/double) + (%raw-instance-ref/signed-word '%raw-instance-set/signed-word) + (%raw-instance-ref/complex-single '%raw-instance-set/complex-single) + (%raw-instance-ref/complex-double '%raw-instance-set/complex-double))) ;; Simulate DEFINE-LOAD-TIME-GLOBAL - always bound in the image ;; but not eval'd in the compiler. @@ -160,32 +175,55 @@ #+sb-xc (declaim (type (simple-vector #.(length *raw-slot-data*)) *raw-slot-data*)) -;; DO-INSTANCE-TAGGED-SLOT iterates over the manifest slots of THING -;; that contain tagged objects. (The LAYOUT does not count as a manifest slot). -;; INDEX-VAR is bound to successive slot-indices, -;; and is usually used as the second argument to %INSTANCE-REF. -;; :PAD, if T, includes a final word that may be present at the end of the -;; structure due to alignment requirements. -;; LAYOUT is optional and somewhat unnecessary, but since some uses of -;; this macro already have a layout in hand, it can be supplied. -;; [If the compiler were smarter about doing fewer memory accesses, -;; there would be no need at all for the LAYOUT - if it had already been -;; accessed, it shouldn't be another memory read] -;; -(defmacro do-instance-tagged-slot ((index-var thing &key layout - ((:bitmap bitmap-expr)) (pad t)) - &body body) - (with-unique-names (instance bitmap limit) - `(let* ((,instance ,thing) - (,bitmap ,(or bitmap-expr - `(layout-bitmap - ,(or layout `(%instance-layout ,instance))))) - (,limit ,(if pad - ;; target instances have an odd number of payload words. - `(logior (%instance-length ,instance) #-sb-xc-host 1) - `(%instance-length ,instance)))) - (do ((,index-var sb-vm:instance-data-start (1+ ,index-var))) - ((>= ,index-var ,limit)) - (declare (type index ,index-var)) - (when (logbitp ,index-var ,bitmap) +;;; DO-INSTANCE-TAGGED-SLOT iterates over the manifest slots of THING +;;; that contain tagged objects. (The LAYOUT does not count as a manifest slot). +;;; INDEX-VAR is bound to successive slot-indices, +;;; and is usually used as the second argument to %INSTANCE-REF. +#+sb-xc-host +(defmacro do-instance-tagged-slot ((index-var thing) &body body) + (with-unique-names (instance dsd) + `(let ((,instance ,thing)) + (dolist (,dsd (dd-slots (find-defstruct-description (type-of ,instance)))) + (let ((,index-var (dsd-index ,dsd))) ,@body))))) + +#-sb-xc-host +(progn +(defmacro do-layout-bitmap ((index-var taggedp-var layout count) &body guts) + `(let* ((layout ,layout) + (bitmap-word-index (bitmap-start layout)) + (bitmap-word-limit (%instance-length layout)) + ;; Shift out 1 bit if skipping bit 0 of the 0th mask word + ;; because it's not user-visible data. + (mask (ash (%raw-instance-ref/signed-word + layout (prog1 bitmap-word-index (incf bitmap-word-index))) + ,(- sb-vm:instance-data-start))) + ;; If this was the last word of the bitmap, then the high bit + ;; is infinitely sign-extended, and we can keep right-shifting + ;; the mask word indefinitely. Most bitmaps will have only 1 word. + (nbits (if (= bitmap-word-index bitmap-word-limit) + ,sb-vm:instance-length-mask + ,(- sb-vm:n-word-bits sb-vm:instance-data-start)))) + (declare (type sb-vm:signed-word mask) + (type fixnum nbits)) + (do ((,index-var sb-vm:instance-data-start (1+ ,index-var)) + (end ,count)) + ((>= ,index-var end)) + (declare (type (unsigned-byte 14) ,index-var end)) + ;; If mask was fully consumed, fetch the next bitmap word + (when (zerop nbits) + (setq mask (%raw-instance-ref/signed-word layout bitmap-word-index) + nbits (if (= (incf (truly-the index bitmap-word-index)) + bitmap-word-limit) + ,sb-vm:instance-length-mask + ,sb-vm:n-word-bits))) + (let ((,taggedp-var (logbitp 0 mask))) ,@guts) + (setq mask (ash mask -1) + nbits (truly-the fixnum (1- nbits)))))) + +(defmacro do-instance-tagged-slot ((index-var thing) &body body) + (with-unique-names (instance layout taggedp) + `(let* ((,instance ,thing) + (,layout (%instance-layout ,instance))) + (do-layout-bitmap (,index-var ,taggedp ,layout (%instance-length ,instance)) + (when ,taggedp ,@body)))))) diff --git a/src/code/early-source-location.lisp b/src/code/early-source-location.lisp deleted file mode 100644 index b0581401bf..0000000000 --- a/src/code/early-source-location.lisp +++ /dev/null @@ -1,51 +0,0 @@ -;;;; Source location tracking macros. - -;;;; This software is part of the SBCL system. See the README file for -;;;; more information. -;;;; -;;;; This software is derived from the CMU CL system, which was -;;;; written at Carnegie Mellon University and released into the -;;;; public domain. The software is in the public domain and is -;;;; provided with absolutely no warranty. See the COPYING and CREDITS -;;;; files for more information. - -(in-package "SB-C") - -#| No calls to #'SOURCE-LOCATION must happen from this file because: -;; - it would imply lack of location information for the definition, -;; since deferring the call past compile-time means we've already lost. -;; - it would be a style-warning to subsequently define the compiler-macro. -;; (DEFINE-COMPILER-MACRO SOURCE-LOCATION) does not itself use SOURCE-LOCATION -;; but this is possibly a mistake! Ordinary DEFMACRO supplies the location -;; to %DEFMACRO. Compiler macros should too. This extra form will be needed: -(eval-when (#+sb-xc :compile-toplevel) - (setf (info :function :compiler-macro-function 'source-location) - (lambda (form env) - (declare (ignore form env)) - (make-definition-source-location)))) |# - -#+sb-source-locations -(progn - #-sb-xc-host - (define-compiler-macro source-location () - (make-definition-source-location)) - ;; We need a regular definition of SOURCE-LOCATION for calls processed - ;; during LOAD on a source file while *EVALUATOR-MODE* is :INTERPRET. - (defun source-location () - #-sb-xc-host (make-definition-source-location))) - -#-sb-source-locations -(defun source-location () nil) - -#-sb-xc-host -(eval-when (:compile-toplevel :load-toplevel :execute) - (dolist (entry '#.sb-vm::!per-thread-c-interface-symbols) - (let ((symbol (if (consp entry) (car entry) entry))) - (declare (notinline info (setf info))) - ;; CURRENT-{CATCH/UWP}-BLOCK are thread slots, - ;; so the TLS indices were already assigned. - ;; There may be other symbols too. - (unless (info :variable :wired-tls symbol) - (setf (info :variable :wired-tls symbol) :always-thread-local)) - (unless (info :variable :always-bound symbol) - (setf (info :variable :always-bound symbol) :always-bound))))) diff --git a/src/code/early-time.lisp b/src/code/early-time.lisp index b58d939870..0ff03be700 100644 --- a/src/code/early-time.lisp +++ b/src/code/early-time.lisp @@ -12,6 +12,14 @@ (in-package "SB-IMPL") -(defconstant sb-xc:internal-time-units-per-second 1000 +(defconstant internal-time-units-per-second + #+64-bit 1000000 ; microseconds + ;; 1 week in milliseconds is: (* 1000 60 60 24 7) = 604800000 which is + ;; a 30-bit number, but there are only 29 bits in a positive fixnum. + ;; It is left as an exercise to change the 32-bit code to use hundredths + ;; instead of thousands of a second. The upside of so doing is that + ;; GET-INTERNAL-REAL-TIME would be able to express more range without consing. + ;; The downside is of course decreased resolution. + #-64-bit 1000 ; milliseconds "The number of internal time units that fit into a second. See GET-INTERNAL-REAL-TIME and GET-INTERNAL-RUN-TIME.") diff --git a/src/code/early-type.lisp b/src/code/early-type.lisp deleted file mode 100644 index 1e6209643c..0000000000 --- a/src/code/early-type.lisp +++ /dev/null @@ -1,1156 +0,0 @@ -;;;; This software is part of the SBCL system. See the README file for -;;;; more information. -;;;; -;;;; This software is derived from the CMU CL system, which was -;;;; written at Carnegie Mellon University and released into the -;;;; public domain. The software is in the public domain and is -;;;; provided with absolutely no warranty. See the COPYING and CREDITS -;;;; files for more information. - -(in-package "SB-KERNEL") - -;; The following macros expand into either constructor calls, -;; if building the cross-compiler, or forms which reference -;; previously constructed objects, if running the cross-compiler. -#+sb-xc-host -(progn - (defmacro literal-ctype (constructor &optional specifier) - (declare (ignore specifier)) - `(load-time-value ,constructor)) - - (defmacro literal-ctype-vector (var) - `(load-time-value ,var nil))) - -;; Omitting the specifier works only if the unparser method has been -;; defined in time to use it, and you're sure that constructor's result -;; can be unparsed - some unparsers may be confused if called on a -;; non-canonical object, such as an instance of (CONS T T) that is -;; not EQ to the interned instance. -#-sb-xc-host -(progn - (defmacro literal-ctype (constructor &optional (specifier nil specifier-p)) - (if specifier-p (specifier-type specifier) (symbol-value constructor))) - - (defmacro literal-ctype-vector (var) - (symbol-value var))) - -(!begin-collecting-cold-init-forms) - -;;;; representations of types - -;; ENUMERABLE-P is T because a hairy type could be equivalent to a MEMBER type. -;; e.g. any SATISFIES with a predicate returning T over a finite domain. -;; But in practice there's nothing that can be done with this information, -;; because we don't call random predicates when performing operations on types -;; as objects, only when checking for inclusion of something in the type. -(define-type-class hairy :enumerable t :might-contain-other-types t) - -;;; Without some special HAIRY cases, we massively pollute the type caches -;;; with objects that are all equivalent to *EMPTY-TYPE*. e.g. -;;; (AND (SATISFIES LEGAL-FUN-NAME-P) (SIMPLE-ARRAY CHARACTER (*))) and -;;; (AND (SATISFIES KEYWORDP) CONS). Since the compiler doesn't know -;;; that they're just *EMPTY-TYPE*, its keeps building more and more complex -;;; expressions involving them. I'm not sure why those two are so prevalent -;;; but they definitely seem to be. We can improve performance by reducing -;;; them to *EMPTY-TYPE* which means we need a way to recognize those hairy -;;; types in order reason about them. Interning them is how we recognize -;;; them, as they can be compared by EQ. -#+sb-xc-host -(progn - (defvar *satisfies-keywordp-type* - (!make-interned-hairy-type '(satisfies keywordp))) - (defvar *fun-name-type* - (!make-interned-hairy-type '(satisfies legal-fun-name-p)))) - -;;; An UNKNOWN-TYPE is a type not known to the type system (not yet -;;; defined). We make this distinction since we don't want to complain -;;; about types that are hairy but defined. -(defstruct (unknown-type (:include hairy-type (%bits (pack-ctype-bits hairy))) - (:copier nil))) - -(defun maybe-reparse-specifier (type) - (when (unknown-type-p type) - (let* ((spec (unknown-type-specifier type)) - (name (if (consp spec) - (car spec) - spec))) - (when (info :type :kind name) - (let ((new-type (specifier-type spec))) - (unless (unknown-type-p new-type) - new-type)))))) - -;;; Evil macro. -(defmacro maybe-reparse-specifier! (type) - (aver (symbolp type)) - (with-unique-names (new-type) - `(let ((,new-type (maybe-reparse-specifier ,type))) - (when ,new-type - (setf ,type ,new-type) - t)))) - -(defstruct (negation-type (:include ctype (%bits (pack-ctype-bits negation))) - (:copier nil) - (:constructor make-negation-type (type))) - (type (missing-arg) :type ctype :read-only t)) - -;; Former comment was: -;; FIXME: is this right? It's what they had before, anyway -;; But I think the reason it's right is that "enumerable :t" is equivalent -;; to "maybe" which is actually the conservative assumption, same as HAIRY. -(define-type-class negation :enumerable t :might-contain-other-types t) - -(defun canonicalize-args-type-args (required optional rest &optional keyp) - (when (eq rest *empty-type*) - ;; or vice-versa? - (setq rest nil)) - (loop with last-not-rest = nil - for i from 0 - for opt in optional - do (cond ((eq opt *empty-type*) - (return (values required (subseq optional 0 i) rest))) - ((and (not keyp) (neq opt rest)) - (setq last-not-rest i))) - finally (return (values required - (cond (keyp - optional) - (last-not-rest - (subseq optional 0 (1+ last-not-rest)))) - rest)))) - -;;; CONTEXT is the cookie passed down from the outermost surrounding call -;;; of BASIC-PARSE-TYPE. INNER-CONTEXT-KIND is an indicator of whether -;;; we are currently parsing a FUNCTION or a VALUES compound type specifier. - -;;; Why do we allow * for items in a list for FUNCTION type? I don't know -;;; and I don't think we should. -;;; VALUES is quite clear that it's not allowed. FUNCTION is less clear, -;;; but * is not a type specifier, it is merely a way to write something in a place -;;; where a specifier requires a positional argument that you don't want to supply, -;;; but must supply in order to supply following arguments. -;;; I would bet we're overly permissive. -(defun parse-args-types (context lambda-listy-thing inner-context-kind) - (multiple-value-bind (llks required optional rest keys) - (parse-lambda-list - lambda-listy-thing - :context inner-context-kind - :accept (ecase inner-context-kind - (:values-type (lambda-list-keyword-mask '(&optional &rest))) - (:function-type (lambda-list-keyword-mask - '(&optional &rest &key &allow-other-keys)))) - :silent t) - (labels ((parse-list (list) (mapcar #'parse-one list)) - (parse-one (x) - (if (eq inner-context-kind :function-type) - (single-value-specifier-type x context) ; allow * - ;; "* is not permitted as an argument to the VALUES type specifier." - (specifier-type x context 'values)))) ; forbid * - (let ((required (parse-list required)) - (optional (parse-list optional)) - (rest (when rest (parse-one (car rest)))) - (keywords - (collect ((key-info)) - (dolist (key keys) - (unless (proper-list-of-length-p key 2) - (error "Keyword type description is not a two-list: ~S." key)) - (let ((kwd (first key))) - (when (find kwd (key-info) :key #'key-info-name) - (error "~@<repeated keyword ~S in lambda list: ~2I~_~S~:>" - kwd lambda-listy-thing)) - (key-info - (make-key-info - ;; MAKE-KEY-INFO will complain if KWD is not a symbol. - ;; That's good enough - we don't need an extra check here. - :name kwd - :type (single-value-specifier-type (second key) context))))) - (key-info)))) - (multiple-value-bind (required optional rest) - (canonicalize-args-type-args required optional rest - (ll-kwds-keyp llks)) - (values llks required optional rest keywords)))))) - -(defstruct (values-type - (:include args-type (%bits (pack-ctype-bits values))) - (:constructor %make-values-type) - (:predicate %values-type-p) - (:copier nil))) - -(declaim (inline values-type-p)) -(defun values-type-p (x) - (or (eq x *wild-type*) - (%values-type-p x))) - -(defun-cached (make-values-type-cached - :hash-bits 8 - :hash-function - (lambda (req opt rest allowp) - (logxor (type-list-cache-hash req) - (type-list-cache-hash opt) - (if rest - (type-hash-value rest) - 42) - ;; Results (logand #xFF (sxhash t/nil)) - ;; hardcoded to avoid relying on the xc host. - ;; [but (logand (sxhash nil) #xff) => 2 - ;; for me, so the code and comment disagree, - ;; but not in a way that matters.] - (if allowp - 194 - 11)))) - ((required equal-but-no-car-recursion) - (optional equal-but-no-car-recursion) - (rest eq) - (allowp eq)) - (%make-values-type :required required - :optional optional - :rest rest - :allowp allowp)) - -(defun make-values-type (&key required optional rest allowp) - (multiple-value-bind (required optional rest) - (canonicalize-args-type-args required optional rest) - (cond ((and (null required) - (null optional) - (eq rest *universal-type*)) - *wild-type*) - ((memq *empty-type* required) - *empty-type*) - (t (make-values-type-cached required optional - rest allowp))))) - -(define-type-class values :enumerable nil - :might-contain-other-types nil) - -(define-type-class function :enumerable nil - :might-contain-other-types nil) - -#+sb-xc-host -(defvar *interned-fun-types* - (flet ((fun-type (n) - (!make-interned-fun-type (pack-interned-ctype-bits 'function) - (make-list n :initial-element *universal-type*) - nil nil nil nil nil nil *wild-type*))) - (vector (fun-type 0) (fun-type 1) (fun-type 2) (fun-type 3)))) - -(defun make-fun-type (&key required optional rest - keyp keywords allowp - wild-args returns - designator) - (let ((rest (if (eq rest *empty-type*) nil rest)) - (n (length required))) - (cond (designator - (make-fun-designator-type required optional rest keyp keywords - allowp wild-args returns)) - ((and - (<= n 3) - (not optional) (not rest) (not keyp) - (not keywords) (not allowp) (not wild-args) - (eq returns *wild-type*) - (not (find *universal-type* required :test #'neq))) - (svref (literal-ctype-vector *interned-fun-types*) n)) - (t - (%make-fun-type required optional rest keyp keywords - allowp wild-args returns))))) - -;; This seems to be used only by cltl2, and within 'cross-type', -;; where it is never used, which makes sense, since pretty much we -;; never want this object, but instead the classoid FUNCTION -;; if we know nothing about a function's signature. -;; Maybe this should not exist unless cltl2 is loaded??? -(define-load-time-global *universal-fun-type* - (make-fun-type :wild-args t :returns *wild-type*)) - -;;; The CONSTANT-TYPE structure represents a use of the CONSTANT-ARG -;;; "type specifier", which is only meaningful in function argument -;;; type specifiers used within the compiler. (It represents something -;;; that the compiler knows to be a constant.) -(defstruct (constant-type - (:include ctype (%bits (pack-ctype-bits constant))) - (:copier nil)) - ;; The type which the argument must be a constant instance of for this type - ;; specifier to win. - (type (missing-arg) :type ctype :read-only t)) - -(define-type-class number :enumerable #'numeric-type-enumerable - :might-contain-other-types nil) - -(defun interned-numeric-type (specifier &rest args) - (apply '%make-numeric-type - :%bits (pack-interned-ctype-bits - 'number nil - (when specifier (sb-vm::saetp-index-or-lose specifier))) - args)) - -#+sb-xc-host -(progn - ;; Work around an ABCL bug. This fails to load: - ;; (macrolet ((foo-it (x) `(- ,x))) (defvar *var* (foo-it 3))) - (defvar *interned-signed-byte-types*) - (defvar *interned-unsigned-byte-types*) - (macrolet ((int-type (low high) - `(interned-numeric-type (when (sb-c::find-saetp spec) spec) - :class 'integer :enumerable t - :low ,low :high ,high))) - (setq *interned-signed-byte-types* - (do ((v (make-array sb-vm:n-word-bits)) - (i 1 (1+ i)) - (j -1)) - ((> i sb-vm:n-word-bits) v) - (let ((spec (if (= i sb-vm:n-fixnum-bits) - 'fixnum - `(signed-byte ,i)))) - (setf (svref v (1- i)) (int-type j (lognot j)) - j (ash j 1))))) - (setq *interned-unsigned-byte-types* - (let ((v (make-array (1+ sb-vm:n-word-bits)))) - (dotimes (i (length v) v) - (let ((spec (if (= i 1) 'bit `(unsigned-byte ,i)))) - (setf (svref v i) (int-type 0 (1- (ash 1 i)))))))))) - -;;; Coerce a numeric type bound to the given type while handling -;;; exclusive bounds. -(defun coerce-numeric-bound (bound type) - (flet ((c (thing) - (case type - (rational (rational thing)) - ((float single-float) - (cond #-sb-xc-host - ((<= sb-xc:most-negative-single-float thing sb-xc:most-positive-single-float) - (coerce thing 'single-float)) - (t - (return-from coerce-numeric-bound)))) - (double-float - (cond #-sb-xc-host - ((<= sb-xc:most-negative-double-float thing sb-xc:most-positive-double-float) - (coerce thing 'double-float)) - (t - (return-from coerce-numeric-bound))))))) - (when bound - (if (consp bound) - (list (c (car bound))) - (c bound))))) - -(declaim (inline bounds-unbounded-p)) -(defun bounds-unbounded-p (low high) - (and (null low) (eq high low))) - -;;; Impose canonicalization rules for NUMERIC-TYPE. Note that in some -;;; cases, despite the name, we return *EMPTY-TYPE* or a UNION-TYPE instead of a -;;; NUMERIC-TYPE. -;;; -;;; FIXME: The ENUMERABLE flag is unexpectedly NIL for types that -;;; come from parsing MEMBER. But bounded integer ranges, -;;; however large, are enumerable: -;;; (TYPE-ENUMERABLE (SPECIFIER-TYPE '(SIGNED-BYTE 99))) => T -;;; (TYPE-ENUMERABLE (SPECIFIER-TYPE '(COMPLEX (SIGNED-BYTE 99)))) => T -;;; but, in contrast, -;;; (TYPE-ENUMERABLE (SPECIFIER-TYPE '(EQL 5))) => NIL. -;;; I can't figure out whether this is supposed to matter. -;;; Moreover, it seems like this function should be responsible -;;; for figuring out the right value so that callers don't have to. -(defun make-numeric-type (&key class format (complexp :real) low high - enumerable) - (declare (type (member integer rational float nil) class)) - (macrolet ((unionize (types classes initargs) - `(let (types) - (loop for thing in ',types - for class in ',classes - do - (let ((low (coerce-numeric-bound low thing)) - (high (coerce-numeric-bound high thing))) - (push (make-numeric-type - ,@initargs - :class class - :complexp complexp :low low :high high :enumerable enumerable) - types))) - (apply #'type-union types)))) - (when (and (null class) (member complexp '(:real :complex))) - (return-from make-numeric-type - (if (bounds-unbounded-p low high) - (if (eq complexp :complex) - (specifier-type 'complex) - (specifier-type 'real)) - (unionize (rational single-float double-float) - (rational float float) - (:format format))))) - (when (and (eql class 'float) (member complexp '(:complex :real)) (eql format nil)) - (return-from make-numeric-type - (if (bounds-unbounded-p low high) - (if (eq complexp :complex) - (specifier-type '(complex float)) - (specifier-type 'real)) - (unionize (single-float double-float #+long-float (error "long-float")) - (float float) - (:format thing)))))) - (multiple-value-bind (low high) - (case class - (integer - ;; INTEGER types always have their LOW and HIGH bounds - ;; represented as inclusive, not exclusive values. - (values (if (consp low) (1+ (type-bound-number low)) low) - (if (consp high) (1- (type-bound-number high)) high))) - (t - ;; no canonicalization necessary - (values low high))) - ;; if interval is empty - (when (and low high - (if (or (consp low) (consp high)) ; if either bound is exclusive - (sb-xc:>= (type-bound-number low) (type-bound-number high)) - (sb-xc:> low high))) - (return-from make-numeric-type *empty-type*)) - (when (and (eq class 'rational) (integerp low) (eql low high)) - (setf class 'integer)) - ;; Either lookup the canonical interned object for - ;; a point in the type lattice, or construct a new one. - (or (case class - (float - (macrolet ((float-type (fmt complexp - &aux (spec (if (eq complexp :complex) - `(complex ,fmt) fmt))) - `(literal-ctype (interned-numeric-type ',spec - :class 'float :complexp ,complexp - :format ',fmt :enumerable nil) - ,spec))) - (when (bounds-unbounded-p low high) - (ecase format - (single-float - (case complexp - (:real (float-type single-float :real)) - (:complex (float-type single-float :complex)))) - (double-float - (case complexp - (:real (float-type double-float :real)) - (:complex (float-type double-float :complex)))))))) - (integer - (macrolet ((int-type (low high) - `(literal-ctype - (interned-numeric-type nil - :class 'integer :low ,low :high ,high - :enumerable (if (and ,low ,high) t nil)) - (integer ,(or low '*) ,(or high '*))))) - (cond ((neq complexp :real) nil) - ((and (eql low 0) (eql high (1- sb-xc:array-dimension-limit))) - (int-type 0 #.(1- sb-xc:array-dimension-limit))) ; INDEX type - ((null high) - (cond ((not low) (int-type nil nil)) - ((eql low 0) (int-type 0 nil)) - ((eql low (1+ sb-xc:most-positive-fixnum)) - ;; positive bignum - (int-type #.(1+ sb-xc:most-positive-fixnum) nil)))) - ((or (eql high most-positive-word) - ;; is (1+ high) a power-of-2 ? - (and (typep high 'word) (zerop (logand (1+ high) high)))) - (cond ((eql low 0) - (svref (literal-ctype-vector *interned-unsigned-byte-types*) - (integer-length (truly-the word high)))) - ((and (< high most-positive-word) (eql low (lognot high))) - (svref (literal-ctype-vector *interned-signed-byte-types*) - (integer-length (truly-the word high)))))) - ((and (not low) (eql high (1- sb-xc:most-negative-fixnum))) - ;; negative bignum - (int-type nil #.(1- sb-xc:most-negative-fixnum)))))) - (rational - (cond ((and (eq complexp :real) (bounds-unbounded-p low high)) - (literal-ctype (interned-numeric-type nil :class 'rational) - rational)) - ((and (eq complexp :complex) (bounds-unbounded-p low high)) - (literal-ctype (interned-numeric-type nil :complexp :complex - :class 'rational) - (complex rational))))) - ((nil) - (and (not format) - (not complexp) - (bounds-unbounded-p low high) - (literal-ctype (interned-numeric-type nil :complexp nil) number)))) - (%make-numeric-type :class class :format format :complexp complexp - :low low :high high :enumerable enumerable)))) - -(defun modified-numeric-type (base - &key - (class (numeric-type-class base)) - (format (numeric-type-format base)) - (complexp (numeric-type-complexp base)) - (low (numeric-type-low base)) - (high (numeric-type-high base)) - (enumerable (type-enumerable base))) - (make-numeric-type :class class - :format format - :complexp complexp - :low low - :high high - :enumerable enumerable)) - -(defun make-character-set-type (pairs) - ; (aver (equal (mapcar #'car pairs) - ; (sort (mapcar #'car pairs) #'<))) - ;; aver that the cars of the list elements are sorted into increasing order - (when pairs - (do ((p pairs (cdr p))) - ((null (cdr p))) - (aver (<= (caar p) (caadr p))))) - (let ((pairs (let (result) - (do ((pairs pairs (cdr pairs))) - ((null pairs) (nreverse result)) - (destructuring-bind (low . high) (car pairs) - (loop for (low1 . high1) in (cdr pairs) - if (<= low1 (1+ high)) - do (progn (setf high (max high high1)) - (setf pairs (cdr pairs))) - else do (return nil)) - (cond - ((>= low sb-xc:char-code-limit)) - ((< high 0)) - (t (push (cons (max 0 low) - (min high (1- sb-xc:char-code-limit))) - result)))))))) - (unless pairs - (return-from make-character-set-type *empty-type*)) - (unless (cdr pairs) - (macrolet ((range (low high &optional saetp-index) - `(return-from make-character-set-type - (literal-ctype (!make-interned-character-set-type - (pack-interned-ctype-bits 'character-set nil ,saetp-index) - '((,low . ,high))) - (character-set ((,low . ,high))))))) - (let* ((pair (car pairs)) - (low (car pair)) - (high (cdr pair))) - (cond ((eql high (1- sb-xc:char-code-limit)) - (cond ((eql low 0) - (range 0 #.(1- sb-xc:char-code-limit) - (sb-vm::saetp-index-or-lose 'character))) - #+sb-unicode - ((eql low base-char-code-limit) - (range #.base-char-code-limit - #.(1- sb-xc:char-code-limit))))) - #+sb-unicode - ((and (eql low 0) (eql high (1- base-char-code-limit))) - (range 0 #.(1- base-char-code-limit) - (sb-vm::saetp-index-or-lose 'base-char))))))) - (%make-character-set-type pairs))) - -(define-type-class array :enumerable nil - :might-contain-other-types nil) - -;; For all ctypes which are the element types of specialized arrays, -;; 3 ctype objects are stored for the rank-1 arrays of that specialization, -;; one for each of simple, maybe-simple, and non-simple (in that order), -;; and 2 ctype objects for unknown-rank arrays, one each for simple -;; and maybe-simple. (Unknown rank, known-non-simple isn't important) -#+sb-xc-host -(progn -(defvar *interned-array-types* - (labels ((make-1 (type-index dims complexp type) - (aver (= (type-saetp-index type) type-index)) - (!make-interned-array-type (pack-interned-ctype-bits 'array) - dims complexp type type)) - (make-all (element-type type-index array) - (replace array - (list (make-1 type-index '(*) nil element-type) - (make-1 type-index '(*) :maybe element-type) - (make-1 type-index '(*) t element-type) - (make-1 type-index '* nil element-type) - (make-1 type-index '* :maybe element-type)) - :start1 (* type-index 5))) - (integer-range (low high) - (make-numeric-type :class 'integer :complexp :real - :enumerable t :low low :high high))) - (let ((array (make-array (* 32 5))) - (index 0)) - ;; Index 31 is available to store *WILD-TYPE* - ;; because there are fewer than 32 array widetags. - (make-all *wild-type* 31 array) - (dovector (saetp sb-vm:*specialized-array-element-type-properties* - (progn (aver (< index 31)) array)) - (make-all - (let ((x (sb-vm:saetp-specifier saetp))) - ;; Produce element-type representation without parsing a spec. - ;; (SPECIFIER-TYPE doesn't work when bootstrapping.) - ;; The MAKE- constructors return an interned object as appropriate. - (etypecase x - ((cons (eql unsigned-byte)) - (integer-range 0 (1- (ash 1 (second x))))) - ((cons (eql signed-byte)) - (let ((lim (ash 1 (1- (second x))))) - (integer-range (- lim) (1- lim)))) - ((eql bit) (integer-range 0 1)) - ;; FIXNUM is its own thing, why? See comment in vm-array - ;; saying to "See the comment in PRIMITIVE-TYPE-AUX" - ((eql fixnum) ; One good kludge deserves another. - (integer-range sb-xc:most-negative-fixnum - sb-xc:most-positive-fixnum)) - ((member single-float double-float) - (make-numeric-type :class 'float :format x :complexp :real)) - ((cons (eql complex)) - (make-numeric-type :class 'float :format (cadr x) - :complexp :complex)) - ((eql character) - (make-character-set-type `((0 . ,(1- sb-xc:char-code-limit))))) - #+sb-unicode - ((eql base-char) - (make-character-set-type `((0 . ,(1- base-char-code-limit))))) - ((eql t) *universal-type*) - ((eql nil) *empty-type*))) - index - array) - (incf index))))) -(defvar *parsed-specialized-array-element-types* - (let ((a (make-array (length sb-vm:*specialized-array-element-type-properties*)))) - (loop for i below (length a) - do (setf (aref a i) (array-type-specialized-element-type - (aref *interned-array-types* (* i 5))))) - a))) - -(declaim (ftype (sfunction (t &key (:complexp t) - (:element-type t) - (:specialized-element-type t)) - ctype) make-array-type)) -(defun make-array-type (dimensions &key (complexp :maybe) element-type - (specialized-element-type *wild-type*)) - (if (and (eq element-type specialized-element-type) - (or (and (eq dimensions '*) (neq complexp t)) - (typep dimensions '(cons (eql *) null)))) - (let ((res (svref (literal-ctype-vector *interned-array-types*) - (+ (* (type-saetp-index element-type) 5) - (if (listp dimensions) 0 3) - (ecase complexp ((nil) 0) ((:maybe) 1) ((t) 2)))))) - (aver (eq (array-type-element-type res) element-type)) - res) - (%make-array-type dimensions - complexp element-type specialized-element-type))) - -(define-type-class member :enumerable t - :might-contain-other-types nil) - -(declaim (ftype (sfunction (xset list) ctype) make-member-type)) -(defun member-type-from-list (members) - (let ((xset (alloc-xset)) - (fp-zeroes)) - (dolist (elt members (make-member-type xset fp-zeroes)) - (if (fp-zero-p elt) - (pushnew elt fp-zeroes) - (add-to-xset elt xset))))) -(defun make-eql-type (elt) (member-type-from-list (list elt))) -;; Return possibly a union of a MEMBER type and a NUMERIC type, -;; or just one or the other, or *EMPTY-TYPE* depending on what's in the XSET -;; and the FP-ZEROES. XSET should not contains characters or real numbers. -(defun make-member-type (xset fp-zeroes) - ;; if we have a pair of zeros (e.g. 0.0d0 and -0.0d0), then we can - ;; canonicalize to (DOUBLE-FLOAT 0.0d0 0.0d0), because numeric - ;; ranges are compared by arithmetic operators (while MEMBERship is - ;; compared by EQL). -- CSR, 2003-04-23 - (let ((presence 0) - (unpaired nil) - (float-types nil)) - (when fp-zeroes ; avoid doing two passes of nothing - (dotimes (pass 2) - (dolist (z fp-zeroes) - (let ((sign (float-sign-bit z)) - (pair-idx - (etypecase z - (single-float 0) - (double-float 2 - #+long-float (long-float 4))))) - (if (= pass 0) - (setf (ldb (byte 1 (+ pair-idx sign)) presence) 1) - (if (= (ldb (byte 2 pair-idx) presence) #b11) - (when (= sign 0) - (push (ctype-of z) float-types)) - (push z unpaired))))))) - (let ((member-type - (block nil - (unless unpaired - (macrolet ((member-type (&rest elts) - `(literal-ctype - (!make-interned-member-type - (pack-interned-ctype-bits 'member) (xset-from-list ',elts) nil) - (member ,@elts)))) - (let ((elts (xset-data xset))) - (when (singleton-p elts) - (case (first elts) - ((nil) (return (member-type nil))) - ((t) (return (member-type t))))) - (when (or (equal elts '(t nil)) (equal elts '(nil t))) - ;; Semantically this is fine - XSETs - ;; are not order-preserving except by accident - ;; (when not represented as a hash-table). - (return (member-type t nil)))))) - (when (or unpaired (not (xset-empty-p xset))) - (%make-member-type xset unpaired))))) - ;; The actual member-type contains the XSET (with no FP zeroes), - ;; and a list of unpaired zeroes. - (if float-types - (make-union-type t (if member-type - (cons member-type float-types) - float-types)) - (or member-type *empty-type*))))) - -(defun member-type-size (type) - (+ (length (member-type-fp-zeroes type)) - (xset-count (member-type-xset type)))) - -(defun member-type-member-p (x type) - (if (fp-zero-p x) - (and (member x (member-type-fp-zeroes type)) t) - (xset-member-p x (member-type-xset type)))) - -(defun mapcar-member-type-members (function type) - (declare (function function)) - (collect ((results)) - (map-xset (lambda (x) - (results (funcall function x))) - (member-type-xset type)) - (dolist (zero (member-type-fp-zeroes type)) - (results (funcall function zero))) - (results))) - -(defun mapc-member-type-members (function type) - (declare (function function)) - (map-xset function (member-type-xset type)) - (dolist (zero (member-type-fp-zeroes type)) - (funcall function zero))) - -(defun member-type-members (type) - (append (member-type-fp-zeroes type) - (xset-members (member-type-xset type)))) - -;;; Return TYPE converted to canonical form for a situation where the -;;; "type" '* (which SBCL still represents as a type even though ANSI -;;; CL defines it as a related but different kind of placeholder) is -;;; equivalent to type T. -(defun type-*-to-t (type) - (if (type= type *wild-type*) - *universal-type* - type)) - -(define-type-class cons :enumerable nil :might-contain-other-types nil) - -#+sb-xc-host -(declaim (ftype (sfunction (ctype ctype) (values t t)) type=)) -(defun make-cons-type (car-type cdr-type) - (aver (not (or (eq car-type *wild-type*) - (eq cdr-type *wild-type*)))) - (cond ((or (eq car-type *empty-type*) - (eq cdr-type *empty-type*)) - *empty-type*) - ;; It's not a requirement that (CONS T T) be interned, - ;; but it improves the hit rate in the function caches. - ((and (type= car-type *universal-type*) - (type= cdr-type *universal-type*)) - (literal-ctype (!make-interned-cons-type (pack-interned-ctype-bits 'cons) - *universal-type* - *universal-type*) - cons)) - (t - (%make-cons-type car-type cdr-type)))) - -;;; A SIMD-PACK-TYPE is used to represent a SIMD-PACK type. -#+sb-simd-pack -(defstruct (simd-pack-type - (:include ctype (%bits (pack-ctype-bits simd-pack))) - (:constructor %make-simd-pack-type (element-type)) - (:copier nil)) - (element-type (missing-arg) - :type (cons #||(member #.*simd-pack-element-types*) ||#) - :read-only t)) - -#+sb-simd-pack-256 -(defstruct (simd-pack-256-type - (:include ctype (%bits (pack-ctype-bits simd-pack-256))) - (:constructor %make-simd-pack-256-type (element-type)) - (:copier nil)) - (element-type (missing-arg) - :type (cons #||(member #.*simd-pack-element-types*) ||#) - :read-only t)) - -#+sb-simd-pack -(defun make-simd-pack-type (element-type) - (aver (neq element-type *wild-type*)) - (if (eq element-type *empty-type*) - *empty-type* - (%make-simd-pack-type - (dolist (pack-type *simd-pack-element-types* - (error "~S element type must be a subtype of ~ - ~{~/sb-impl:print-type-specifier/~#[~;, or ~ - ~:;, ~]~}." - 'simd-pack *simd-pack-element-types*)) - (when (csubtypep element-type (specifier-type pack-type)) - (return (list pack-type))))))) - -#+sb-simd-pack-256 -(defun make-simd-pack-256-type (element-type) - (aver (neq element-type *wild-type*)) - (if (eq element-type *empty-type*) - *empty-type* - (%make-simd-pack-256-type - (dolist (pack-type *simd-pack-element-types* - (error "~S element type must be a subtype of ~ - ~{~/sb-impl:print-type-specifier/~#[~;, or ~ - ~:;, ~]~}." - 'simd-pack-256 *simd-pack-element-types*)) - (when (csubtypep element-type (specifier-type pack-type)) - (return (list pack-type))))))) - -;;;; type utilities - -;;; Return the type structure corresponding to a type specifier. -;;; -;;; Note: VALUES-SPECIFIER-TYPE-CACHE-CLEAR must be called whenever a -;;; type is defined (or redefined). -;;; -;;; As I understand things, :FORTHCOMING-DEFCLASS-TYPE behaves contrarily -;;; to the CLHS intent, which is to make the type known to the compiler. -;;; If we compile in one file: -;;; (DEFCLASS FRUITBAT () ()) -;;; (DEFUN FRUITBATP (X) (TYPEP X 'FRUITBAT)) -;;; we see that it emits a call to %TYPEP with the symbol FRUITBAT as its -;;; argument, whereas it should involve CLASSOID-CELL-TYPEP and LAYOUT-OF, -;;; which (correctly) signals an error if the class were not defined by the -;;; time of the call. Delayed re-parsing of FRUITBAT into any random specifier -;;; at call time is wrong. -;;; -;;; FIXME: symbols which are :PRIMITIVE are inconsistently accepted as singleton -;;; lists. e.g. (BIT) and (ATOM) are considered legal, but (FIXNUM) and -;;; (CHARACTER) are not. It has to do with whether the primitive is actually -;;; a DEFTYPE. The CLHS glossary implies that the singleton is *always* legal. -;;; "For every atomic type specifier, x, there is an _equivalent_ [my emphasis] -;;; compound type specifier with no arguments supplied, (x)." -;;; By that same reasonining, is (x) accepted if x names a class? -;;; - -;;; The xc host uses an ordinary hash table for memoization. -#+sb-xc-host -(let ((table (make-hash-table :test 'equal))) - (defun !values-specifier-type-memo-wrapper (thunk specifier) - (multiple-value-bind (type yesp) (gethash specifier table) - (if yesp - type - (setf (gethash specifier table) (funcall thunk))))) - (defun values-specifier-type-cache-clear () - (clrhash table))) -;;; This cache is sized extremely generously, which has payoff -;;; elsewhere: it improves the TYPE= and CSUBTYPEP functions, -;;; since EQ types are an immediate win. -#-sb-xc-host -(sb-impl::!define-hash-cache values-specifier-type - ((orig equal-but-no-car-recursion)) () - :hash-function #'sxhash :hash-bits 10) - -(declaim (inline make-type-context)) -(defstruct (type-context - (:constructor make-type-context - (spec &optional proto-classoid (cacheable t))) - (:copier nil) - (:predicate nil)) - (spec nil :read-only t) - (proto-classoid nil :read-only t) - (cacheable t)) - -;;; Maintain a table of symbols designating unknown types that have any references -;;; to them, making it easy to inquire whether such things exist. This is at a lower -;;; layer than the parser cache - it's a cache of the constructor itself - so we'll -;;; sitll signal that an unknown specifier is unknown on each reparse of the same. -;;; But as long as any reference enlivens the relevant CTYPE, we'll return that object. -(defglobal **unknown-type-atoms** - ;; I think it's safe to say that if the host is SBCL, we can employ a weak table. - ;; SBCL has had weak tables since Sep 2006 (git rev 1479483c5f). - ;; For other hosts, just use an ordinary hash-table. - ;; This table isn't specified as synchronized because we need to wrap the lock - ;; around a read/modify/write. GETHASH and PUTHASH can't do that themselves. - ;; Not that it would matter anyway - weak tables are always synchronized. - (let ((weakness #+(or (not sb-xc-host) host-quirks-sbcl) '(:weakness :value))) - (apply #'make-hash-table :test 'eq weakness))) - -#-sb-xc-host -(progn (declaim (inline class-classoid)) - (defun class-classoid (class) - (layout-classoid (sb-pcl::class-wrapper class)))) - -;;; Parsing of type specifiers comes in many variations: -;;; SINGLE-VALUE-SPECIFIER-TYPE: -;;; disallow VALUES even if single value, but allow * -;;; SPECIFIER-TYPE: -;;; disallow (VALUES ...) even if single value, and disallow * -;;; VALUES-SPECIFIER-TYPE: -;;; allow VALUES and * -;;; TYPE-OR-NIL-IF-UNKNOWN: -;;; like SPECIFIER-TYPE, but return NIL if contains unknown -;;; all the above are funneled through BASIC-PARSE-TYPESPEC. - -;;; The recursive %PARSE-TYPE function is used for nested invocations -;;; of type spec parsing, passing the outermost context through on each call. -;;; Callers should use the BASIC-PARSE-TYPESPEC interface. - -;;; Hint for when you bork this and/or bork the :UNPARSE methods - do: -;;; (remove-method #'print-object (find-method #'print-object nil -;;; (list (find-class 'ctype) (find-class 't)))) -;;; so that 'backtrace' doesn't encounter an infinite chain of errors. - -(macrolet ((fail (spec) - `(error "bad thing to be a type specifier: ~/sb-impl:print-type-specifier/" - ,spec))) -(defun %parse-type (spec context) - (declare (type type-context context)) - (prog* ((head (if (listp spec) (car spec) spec)) - (builtin (if (symbolp head) - (info :type :builtin head) - (return (fail spec))))) - (when (deprecated-thing-p 'type head) - (setf (type-context-cacheable context) nil) - (signal 'parse-deprecated-type :specifier spec)) - (when (atom spec) - ;; If spec is non-atomic, the :BUILTIN value is inapplicable. - ;; There used to be compound builtins, but not any more. - (when builtin (return builtin)) - ;; Any spec that apparently refers to a defstruct form - ;; that's being macroexpanded should refer to that type. - (awhen (type-context-proto-classoid context) - (when (eq (classoid-name it) spec) (return it))) - (case (info :type :kind spec) - (:instance (return (find-classoid spec))) - (:forthcoming-defclass-type (go unknown)))) - ;; Expansion brings up an interesting question - should the cache - ;; contain entries for intermediary types? Say A -> B -> REAL. - ;; As it stands, we cache the ctype corresponding to A but not B. - (awhen (info :type :expander head) - (when (listp it) ; The function translates directly to a CTYPE. - (return (or (funcall (car it) context spec) (fail spec)))) - ;; The function produces a type expression. - (let ((expansion (funcall it (ensure-list spec)))) - (return (if (typep expansion 'instance) - (basic-parse-typespec expansion context) - (%parse-type expansion context))))) - ;; If the spec is (X ...) and X has neither a translator - ;; nor expander, and is a builtin, such as FIXNUM, fail now. - ;; But - see FIXME at top - it would be consistent with - ;; DEFTYPE to reject spec only if not a singleton. - (when builtin (return (fail spec))) - ;; SPEC has a legal form, so return an unknown type. - (signal 'parse-unknown-type :specifier spec) - UNKNOWN - (setf (type-context-cacheable context) nil) - (return (if (atom spec) - (let ((table **unknown-type-atoms**)) - (sb-thread::with-recursive-system-lock ((sb-impl::hash-table-lock table)) - (or (gethash spec table) - (progn #+sb-xc-host - (when *compile-print* - (format t "~&; NEW UNKNOWN-TYPE ~S~%" spec)) - (setf (gethash spec table) - (make-unknown-type :specifier spec)))))) - (make-unknown-type :specifier spec))))) - -;;; BASIC-PARSE-TYPESPEC can grok some simple cases that involve turning an object -;;; used as a type specifier into an internalized type object (which might be -;;; the selfsame object, in the case of a CLASSOID). -(defun basic-parse-typespec (type-specifier context) - (declare (type type-context context)) - (when (typep type-specifier 'instance) - ;; An instance never needs the type parser cache, because it almost always - ;; represents itself or a slot in itself. - (flet ((classoid-to-ctype (classoid) - ;; A few classoids have translations, - ;; e.g. the classoid CONS is a CONS-TYPE. - ;; Hmm, perhaps this should signal PARSE-UNKNOWN-TYPE - ;; if CLASSOID is an instance of UNDEFINED-CLASSOID ? - ;; Can that happen? - (or (and (built-in-classoid-p classoid) - (built-in-classoid-translation classoid)) - classoid))) - (return-from basic-parse-typespec - (cond ((classoid-p type-specifier) (classoid-to-ctype type-specifier)) - ;; Avoid TYPEP on SB-MOP:EQL-SPECIALIZER and CLASS because - ;; the fake metaobjects do not allow type analysis, and - ;; would cause a compiler error as it tries to decide - ;; whether any clause of this COND subsumes another. - ;; Moreover, we don't require the host to support MOP. - #-sb-xc-host - ((sb-pcl::classp type-specifier) - ;; A CLOS class is translated to its CLASSOID, or the classoid's translation. - (classoid-to-ctype (sb-pcl::class-classoid type-specifier))) - #-sb-xc-host - ((sb-pcl::eql-specializer-p type-specifier) - ;; EQL specializers are are seldom used and not 100% portable, - ;; though they are part of the AMOP. - ;; See https://sourceforge.net/p/sbcl/mailman/message/11217378/ - ;; We implement the notion that an EQL-SPECIALIZER has-a CTYPE. - ;; You might think that a cleverer way would be to say that - ;; EQL-SPECIALIZER is-a CTYPE, i.e. incorporating EQL-SPECIALIZER - ;; objects into the type machinary. Well, that's a problem - - ;; it would mess up admissibility of the TYPE= optimization. - ;; We don't want to create another way of representing - ;; the type NULL = (MEMBER NIL), for example. - (sb-pcl::eql-specializer-to-ctype type-specifier)) - ((layout-p type-specifier) - (layout-classoid type-specifier)) - (t (fail type-specifier)))))) - (when (atom type-specifier) - ;; Try to bypass the cache, which avoids using a cache line for standard - ;; atomic specifiers. This is a trade-off- cache seek might be faster, - ;; but this solves the problem that a full call to (TYPEP #\A 'FIXNUM) - ;; consed a cache line every time the cache missed on FIXNUM (etc). - (awhen (info :type :builtin type-specifier) - (return-from basic-parse-typespec it))) - - ;; If CONTEXT was non-cacheable as supplied, the cache is bypassed - ;; for any nested lookup, and we don't insert the result. - (if (not (type-context-cacheable context)) - (%parse-type (uncross type-specifier) context) - ;; Otherwise, try for a cache hit first, and usually update the cache. - (!values-specifier-type-memo-wrapper - (lambda () - (let ((answer (%parse-type (uncross type-specifier) context))) - (if (type-context-cacheable context) - answer - ;; Lookup was cacheable, but result isn't. - ;; Non-caching ensures that we see every occurrence of an unknown - ;; type no matter how deeply nested it is in the expression. - ;; e.g. (OR UNKNOWN-FOO CONS) and (OR INTEGER UNKNOWN-FOO) - ;; should both signal the PARSE-UNKNOWN condition, which would - ;; not happen if the first cached UNKNOWN-FOO. - - ;; During make-host-2 I'm seeing the types &OPTIONAL-AND-&KEY-IN-LAMBDA-LIST, - ;; SIMPLE-ERROR, DISASSEM-STATE as non-cacheable, - ;; and much, much more during make-target-2. - ;; The condition types are obvious, because we mention them before - ;; defining them. - ;; DISASSEM-STATE comes from building **TYPE-SPEC-INTERR-SYMBOLS** - ;; where we have a fixed list of types which get assigned single-byte - ;; error codes. - (progn - #+nil - (unless (type-context-cacheable context) - (format t "~&non-cacheable: ~S ~%" type-specifier)) - (return-from basic-parse-typespec answer))))) - type-specifier))) -) ; end MACROLET - -;;; This takes no CONTEXT (which implies lack of recursion) because -;;; you can't reasonably place a VALUES type inside another type. -(defun values-specifier-type (type-specifier) - (dx-let ((context (make-type-context type-specifier))) - (basic-parse-typespec type-specifier context))) - -;;; This is like VALUES-SPECIFIER-TYPE, except that we guarantee to -;;; never return a VALUES type. -;;; CONTEXT is either an instance of TYPE-CONTEXT or NIL. -;;; SUBCONTEXT is a symbol denoting the head of the current expression, or NIL. -(defun specifier-type (type-specifier &optional context subcontext) - (let ((ctype - (if context - (basic-parse-typespec type-specifier context) - (dx-let ((context (make-type-context type-specifier))) - (basic-parse-typespec type-specifier context))))) - (when (values-type-p ctype) - ;; We have to see how it was spelled to give an intelligent message. - ;; If it's instance of VALUES-TYPE, then it was spelled as VALUES - ;; whereas if it isn't, the user either spelled it as (VALUES) or *. - ;; The case where this heuristic doesn't work is a DEFTYPE that expands - ;; to *, but that's not worth worrying about. - (cond ((or (%values-type-p ctype) (consp type-specifier)) - (error "VALUES type illegal in this context:~% ~ - ~/sb-impl:print-type-specifier/" - type-specifier)) - (subcontext - (error "* is not permitted as an argument to the ~S type specifier" - subcontext)) - (t - (error "* is not permitted as a type specifier~@[ in the context ~S~]" - ;; If the entire surrounding context is * then there's not much - ;; else to say. Otherwise, show the original expression. - (when (and context (neq (type-context-spec context) '*)) - (type-context-spec context)))))) - ctype)) - -(defun single-value-specifier-type (x &optional context) - (if (eq x '*) - *universal-type* - (specifier-type x context))) - -;;; Parse TYPE-SPECIFIER, returning NIL if any sub-part of it is unknown -(defun type-or-nil-if-unknown (type-specifier &optional allow-values) - (dx-let ((context (make-type-context type-specifier))) - (let ((result (if allow-values - (basic-parse-typespec type-specifier context) - (specifier-type type-specifier context)))) - ;; If it was non-cacheable, either it contained a deprecated type - ;; or unknown type, or was a pending defstruct definition. - (if (and (not (type-context-cacheable context)) - (contains-unknown-type-p result)) - nil - result)))) - -(defun typexpand-1 (type-specifier &optional env) - "Takes and expands a type specifier once like MACROEXPAND-1. -Returns two values: the expansion, and a boolean that is true when -expansion happened." - (declare (type type-specifier type-specifier)) - (declare (type lexenv-designator env) (ignore env)) - (let* ((spec type-specifier) - (atom (if (listp spec) (car spec) spec)) - (expander (and (symbolp atom) (info :type :expander atom)))) - ;; We do not expand builtins even though it'd be - ;; possible to do so sometimes (e.g. STRING) for two - ;; reasons: - ;; - ;; a) From a user's point of view, CL types are opaque. - ;; - ;; b) so (EQUAL (TYPEXPAND 'STRING) (TYPEXPAND-ALL 'STRING)) - (if (and (functionp expander) (not (info :type :builtin atom))) - (values (funcall expander (if (symbolp spec) (list spec) spec)) t) - (values type-specifier nil)))) - -(defun typexpand (type-specifier &optional env) - "Takes and expands a type specifier repeatedly like MACROEXPAND. -Returns two values: the expansion, and a boolean that is true when -expansion happened." - ;; TYPE-SPECIFIER is of type TYPE-SPECIFIER, but it is preferable to - ;; defer to TYPEXPAND-1 for the typecheck. Similarly for ENV. - (multiple-value-bind (expansion expanded) - (typexpand-1 type-specifier env) - (if expanded - (values (typexpand expansion env) t) - (values expansion expanded)))) - -;;; Note that the type NAME has been (re)defined, updating the -;;; undefined warnings and VALUES-SPECIFIER-TYPE cache. -(defun %note-type-defined (name) - (declare (symbol name)) - (note-name-defined name :type) - (values-specifier-type-cache-clear) - (values)) - - -(!defun-from-collected-cold-init-forms !early-type-cold-init) - -;;; When cross-compiling SPECIFIER-TYPE with a quoted argument, -;;; it can be rendered as a literal object unless it mentions -;;; certain classoids. -;;; -;;; This is important for type system initialization. -;;; -;;; After the target is built, we remove this transform, both because calls -;;; to SPECIFIER-TYPE do not arise organically through user code, -;;; and because it is possible that user changes to types could make parsing -;;; return a different thing, e.g. changing a DEFTYPE to a DEFCLASS. -;;; -#+sb-xc-host -(labels ((xform (type-spec env parser) - (if (not (sb-xc:constantp type-spec env)) - (values nil t) - (let* ((expr (constant-form-value type-spec env)) - (parse (funcall parser expr))) - (if (cold-dumpable-type-p parse) - parse - (values nil t))))) - (cold-dumpable-type-p (ctype) - (when (contains-unknown-type-p ctype) - (bug "SPECIFIER-TYPE transform parsed an unknown type: ~S" ctype)) - (map-type (lambda (type) - (when (and (classoid-p type) (eq (classoid-name type) 'class)) - (return-from cold-dumpable-type-p nil))) - ctype) - t)) - (sb-c:define-source-transform specifier-type (type-spec &environment env) - (xform type-spec env #'specifier-type)) - (sb-c:define-source-transform values-specifier-type (type-spec &environment env) - (xform type-spec env #'values-specifier-type))) diff --git a/src/code/error.lisp b/src/code/error.lisp index ca86ae7599..940e719022 100644 --- a/src/code/error.lisp +++ b/src/code/error.lisp @@ -20,12 +20,12 @@ (declare (explicit-check) (dynamic-extent arguments)) (cond ((and (%instancep datum) - (let ((layout (%instance-layout datum))) - (and (logtest +condition-layout-flag+ (layout-flags layout)) + (let ((wrapper (%instance-wrapper datum))) + (and (logtest (wrapper-flags wrapper) +condition-layout-flag+) ;; An invalid layout will drop into the (MAKE-CONDITION) branch ;; which rightly fails because ALLOCATE-CONDITION asserts that ;; the first argument is a condition-designator, which it won't be. - (not (layout-invalid layout))))) + (not (wrapper-invalid wrapper))))) (when (and arguments (not (eq fun-name 'cerror))) (cerror "Ignore the additional arguments." 'simple-type-error @@ -69,7 +69,7 @@ ;; is one dx cons cell for the whole cluster. ;; Otherwise it takes 1+2N cons cells where N is the number of bindings. ;; - (collect ((local-functions) (cluster-entries) (dummy-forms)) + (collect ((local-functions) (cluster-entries) (dummy-forms) (complex-initforms)) (flet ((const-cons (test handler) ;; If possible, render HANDLER as a load-time constant so that ;; consing the test and handler is also load-time constant. @@ -85,25 +85,20 @@ ((info :function :info name) ; known ;; This takes care of CONTINUE,ABORT,MUFFLE-WARNING. ;; #' will be evaluated in the null environment. - `(load-time-value - (cons ,test (the (function-designator (condition)) #',name)) - t)) + `(load-time-value (cons ,test (the (function (condition)) #',name)) + t)) (t - ;; For each handler specified as #'F we must verify - ;; that F is fboundp upon entering the binding scope. - ;; Referencing #'F is enough to ensure a warning if the - ;; function isn't defined at compile-time, but the - ;; compiler considers it elidable unless something forces - ;; an apparent use of the form at runtime, - ;; so instead use SAFE-FDEFN-FUN on the fdefn. - (when (eq (car handler) 'function) + ;; The CLHS writeup of HANDLER-BIND says "Exceptional Situations: None." + ;; which might suggest that it's not an error if #'HANDLER is un-fboundp + ;; on entering the body, but we should check in safe code. + (when (and (eq (car handler) 'function) (sb-c:policy env (= safety 3))) + ;; Referencing #'F is enough to get a compile-time warning about unknown + ;; functions, but the use itself is flushable, so employ SAFE-FDEFN-FUN. (dummy-forms `(sb-c:safe-fdefn-fun (load-time-value (find-or-create-fdefn ',name) t)))) - ;; Resolve to an fdefn at load-time. `(load-time-value - (cons ,test (find-or-create-fdefn - (the (function-designator (condition)) ',name))) + (cons ,test (the (function-designator (condition)) ',name)) t))))) (const-list (items) @@ -132,24 +127,19 @@ ;; whether you wrote T or CONDITION, this is ;; always an eligible handler. '#'constantly-t) - ((typep type '(cons (eql satisfies) (cons t null))) - ;; (SATISFIES F) => #'F but never a local - ;; definition of F. The predicate is used only - ;; if needed - it's not an error if not fboundp - ;; (though dangerously stupid) - so just - ;; reference #'F for the compiler to see the - ;; use of the name. But (KLUDGE): since the - ;; ref is to force a compile-time effect, the - ;; interpreter should not see that form, - ;; because there is no way for it to perform an - ;; unsafe ref, (and it wouldn't signal a - ;; style-warning anyway), and so it would - ;; actually fail immediately if predicate were - ;; not defined. + ((typep type '(cons (eql satisfies) (cons symbol null))) + ;; (SATISFIES F) => #'F but never a local definition of F. + ;; The predicate is used only if needed - it's not an error if not + ;; fboundp (though dangerously stupid) - so reference #'F for the + ;; compiler to see the use of the name. But (KLUDGE): since the + ;; ref is to force a compile-time effect, the interpreter should not + ;; see that form, because there is no way for it to perform an + ;; unsafe ref, and it wouldn't signal a style-warning anyway. (let ((name (second type))) - (when (typep env 'lexenv) - (dummy-forms `#',name)) - `(find-or-create-fdefn ',name))) + ;; FIXME: if you've locally flet NAME (why would you do that?) + ;; then this does not notice the use of the global function. + (when (typep env 'lexenv) (dummy-forms `#',name)) + `',name)) ((and (symbolp type) (condition-classoid-p (find-classoid type nil))) ;; It's debatable whether we need to go through @@ -166,34 +156,42 @@ ;; Unless the expression is ({FUNCTION|QUOTE} <sym>), then create a ;; new local function. If the supplied handler is spelled ;; (LAMBDA ...) or #'(LAMBDA ...), then the local function is the - ;; lambda but named. If not spelled as such, the function funcalls - ;; the user's sexpr so that the compiler enforces callable-ness. + ;; lambda but named. If not spelled as such, the function funcalls + ;; the user's sexpr through a variable binding so that the compiler + ;; enforces callable-ness but evaluates the supplied form only once. (if (typep handler '(cons (member function quote) (cons symbol null))) handler - (let ((lexpr - (typecase handler - ;; These two are merely expansion prettifiers, - ;; and not strictly necessary. - ((cons (eql function) (cons (cons (eql lambda)) null)) - (cadr handler)) - ((cons (eql lambda)) - handler) - (t - ;; Should be (THE (FUNCTION-DESIGNATOR (CONDITION))) - ;; but the cast kills DX allocation. - `(lambda (c) (funcall ,handler c))))) - (name (let ((sb-xc:*gensym-counter* - (length (cluster-entries)))) - (sb-xc:gensym "H")))) - (local-functions `(,name ,@(rest lexpr))) + (let* ((name (let ((*gensym-counter* + (length (cluster-entries)))) + (gensym "H"))) + (lexpr + (typecase handler + ;; These two are merely expansion prettifiers, + ;; and not strictly necessary. + ((cons (eql function) (cons (cons (eql lambda)) null)) + (cadr handler)) + ((cons (eql lambda)) + handler) + (t + (complex-initforms `(,name ,handler)) + ;; Should be (THE (FUNCTION-DESIGNATOR (CONDITION))) + ;; but the cast kills DX allocation. + `(lambda (c) (funcall ,name c)))))) + (local-functions + `(,name ,(cadr lexpr) + (declare (sb-c::source-form ,binding)) + ,@(when (typep (cadr lexpr) '(cons t null)) + '((declare (sb-c::local-optimize (sb-c::verify-arg-count 0))))) + ,@(cddr lexpr))) `#',name)))))))) - `(dx-flet ,(local-functions) - ,@(dummy-forms) - (dx-let ((*handler-clusters* - (cons ,(const-list (cluster-entries)) - *handler-clusters*))) - ,form))))) + `(let ,(complex-initforms) + (dx-flet ,(local-functions) + ,@(dummy-forms) + (dx-let ((*handler-clusters* + (cons ,(const-list (cluster-entries)) + *handler-clusters*))) + ,form)))))) (sb-xc:defmacro handler-bind (bindings &body forms) "(HANDLER-BIND ( {(type handler)}* ) body) @@ -235,7 +233,7 @@ specification." (annotated-cases (mapcar (lambda (case) (with-current-source-form (case) - (with-unique-names (tag fun) + (with-unique-names (block fun) (destructuring-bind (type ll &body body) case (unless (and (listp ll) (symbolp (car ll)) @@ -244,48 +242,48 @@ specification." ll)) (multiple-value-bind (body declarations) (parse-body body nil) - (push `(,fun ,ll ,@declarations (progn ,@body)) local-funs)) - (list tag type ll fun))))) + (push `(,fun ,ll + (declare (sb-c::source-form ,case)) + ,@declarations + (progn ,@body)) + local-funs)) + (list block type ll fun))))) cases))) - (with-unique-names (block cell form-fun) - `(dx-flet ((,form-fun () - #-x86 (progn ,form) ;; no declarations are accepted - ;; Need to catch FP errors here! - #+x86 (multiple-value-prog1 ,form (float-wait))) - ,@(reverse local-funs)) - (declare (optimize (sb-c::check-tag-existence 0))) - (block ,block - ;; KLUDGE: We use a dx CONS cell instead of just assigning to - ;; the variable directly, so that we can stack allocate - ;; robustly: dx value cells don't work quite right, and it is - ;; possible to construct user code that should loop - ;; indefinitely, but instead eats up some stack each time - ;; around. - (dx-let ((,cell (cons :condition nil))) - (declare (ignorable ,cell)) - (tagbody - (%handler-bind - ,(mapcar (lambda (annotated-case) - (destructuring-bind (tag type ll fun-name) annotated-case - (declare (ignore fun-name)) - (list type - `(lambda (temp) - ,(if ll - `(setf (cdr ,cell) temp) - '(declare (ignore temp))) - (go ,tag))))) - annotated-cases) - (return-from ,block (,form-fun))) - ,@(mapcan - (lambda (annotated-case) - (destructuring-bind (tag type ll fun-name) annotated-case - (declare (ignore type)) - (list tag - `(return-from ,block - ,(if ll - `(,fun-name (cdr ,cell)) - `(,fun-name)))))) - annotated-cases)))))))))) + (with-unique-names (block form-fun) + (let ((body `(%handler-bind + ,(mapcar (lambda (annotated-case) + (destructuring-bind (block type ll fun-name) annotated-case + (declare (ignore fun-name)) + (list type + `(lambda (temp) + ,@(unless ll + `((declare (ignore temp)))) + (return-from ,block + ,@(and ll '(temp))))))) + annotated-cases) + (return-from ,block (,form-fun))))) + (labels ((wrap (cases) + (if cases + (destructuring-bind (fun-block type ll fun-name) (car cases) + (declare (ignore type)) + `(return-from ,block + ,(if ll + `(,fun-name (block ,fun-block + ,(wrap (cdr cases)))) + `(progn (block ,fun-block + ,(wrap (cdr cases))) + (,fun-name))))) + body))) + `(flet ((,form-fun () + #-x86 (progn ,form) ;; no declarations are accepted + ;; Need to catch FP errors here! + #+x86 (multiple-value-prog1 ,form (float-wait))) + ,@(reverse local-funs)) + (declare (optimize (sb-c::check-tag-existence 0)) + (inline ,form-fun + ,@(mapcar #'car local-funs))) + (block ,block + ,(wrap annotated-cases)))))))))) (sb-xc:defmacro ignore-errors (&rest forms) "Execute FORMS handling ERROR conditions, returning the result of the last diff --git a/src/code/eval.lisp b/src/code/eval.lisp index 874578bf97..dd9fb9a7ea 100644 --- a/src/code/eval.lisp +++ b/src/code/eval.lisp @@ -11,7 +11,7 @@ (in-package "SB-IMPL") -(defparameter *eval-calls* 0) ; initialized by genesis +(defparameter *eval-calls* 0) ;;;; Turns EXPR into a lambda-form we can pass to COMPILE. Returns ;;;; a secondary value of T if we must call the resulting function @@ -100,7 +100,8 @@ ;; 2002-10-24 (let* ((sb-c:*lexenv* lexenv) (sb-c::*ir1-namespace* (sb-c::make-ir1-namespace)) - (sb-c::*undefined-warnings* nil)) + (sb-c::*undefined-warnings* nil) + sb-c::*argument-mismatch-warnings*) ;; FIXME: VALUES declaration (sb-c::process-decls decls vars diff --git a/src/code/external-formats/enc-basic.lisp b/src/code/external-formats/enc-basic.lisp index 737f6e6a6d..5f3818e3fb 100644 --- a/src/code/external-formats/enc-basic.lisp +++ b/src/code/external-formats/enc-basic.lisp @@ -16,7 +16,7 @@ (declaim (inline code->ascii-mapper)) (defun code->ascii-mapper (code) - (declare (optimize speed (safety 0)) + (declare (optimize speed #.*safety-0*) (type char-code code)) (if (> code 127) nil @@ -24,13 +24,13 @@ (declaim (inline get-ascii-bytes)) (defun get-ascii-bytes (string pos) - (declare (optimize speed (safety 0)) + (declare (optimize speed #.*safety-0*) (type simple-string string) (type array-range pos)) (get-latin-bytes #'code->ascii-mapper :ascii string pos)) (defun string->ascii (string sstart send null-padding) - (declare (optimize speed (safety 0)) + (declare (optimize speed #.*safety-0*) (type simple-string string) (type array-range sstart send)) (values (string->latin% string sstart send #'get-ascii-bytes null-padding))) @@ -74,13 +74,13 @@ (declaim (inline get-latin1-bytes)) (defun get-latin1-bytes (string pos) - (declare (optimize speed (safety 0)) + (declare (optimize speed #.*safety-0*) (type simple-string string) (type array-range pos)) (get-latin-bytes #'identity :latin-1 string pos)) (defun string->latin1 (string sstart send null-padding) - (declare (optimize speed (safety 0)) + (declare (optimize speed #.*safety-0*) (type simple-string string) (type array-range sstart send)) (values (string->latin% string sstart send #'get-latin1-bytes null-padding))) @@ -117,8 +117,8 @@ (declaim (inline char-len-as-utf8)) (defun char-len-as-utf8 (code) - (declare (optimize speed (safety 0)) - (type (integer 0 (#.sb-xc:char-code-limit)) code)) + (declare (optimize speed #.*safety-0*) + (type (integer 0 (#.char-code-limit)) code)) (cond ((< code 0) (bug "can't happen")) ((< code #x80) 1) ((< code #x800) 2) @@ -127,7 +127,7 @@ (t (bug "can't happen")))) (defun string->utf8 (string sstart send null-padding) - (declare (optimize (speed 3) (safety 0)) + (declare (optimize (speed 3) #.*safety-0*) (type simple-string string) (type (integer 0 1) null-padding) (type array-range sstart send)) @@ -204,12 +204,7 @@ ;; so we can take a fast path -- and get benefit of the element ;; type information. On non-unicode build BASE-CHAR == ;; CHARACTER, handled above. - (ascii-bash)) - ((simple-array nil (*)) - (if (= send sstart) - (make-array null-padding :element-type '(unsigned-byte 8)) - ;; Just get the error... - (aref string sstart)))))) + (ascii-bash))))) ;;; from UTF-8 @@ -218,11 +213,11 @@ `(progn ;;(declaim (inline ,name)) (let ((lexically-max - (string->utf8 (string (code-char ,(1- sb-xc:char-code-limit))) + (string->utf8 (string (code-char ,(1- char-code-limit))) 0 1 0))) (declare (type (simple-array (unsigned-byte 8) (#+sb-unicode 4 #-sb-unicode 2)) lexically-max)) (defun ,name (array pos end) - (declare (optimize speed (safety 0)) + (declare (optimize speed #.*safety-0*) (type ,type array) (type array-range pos end)) ;; returns the number of bytes consumed and nil if it's a @@ -339,7 +334,7 @@ `(progn (declaim (inline ,name)) (defun ,name (array pos bytes) - (declare (optimize speed (safety 0)) + (declare (optimize speed #.*safety-0*) (type ,type array) (type array-range pos) (type (integer 1 4) bytes)) @@ -363,7 +358,7 @@ (let ((name (make-od-name 'utf8->string accessor))) `(progn (defun ,name (array astart aend) - (declare (optimize speed (safety 0)) + (declare (optimize speed #.*safety-0*) (type ,type array) (type array-range astart aend)) (let ((string (make-array 0 :adjustable t :fill-pointer 0 :element-type 'character))) diff --git a/src/code/external-formats/enc-cn.lisp b/src/code/external-formats/enc-cn.lisp index 59457fc360..e5c8efdd29 100644 --- a/src/code/external-formats/enc-cn.lisp +++ b/src/code/external-formats/enc-cn.lisp @@ -9,24 +9,24 @@ mb-len-as-gbk gbk-continuation-byte-p)) (defun ucs-to-gbk (code) - (declare (optimize speed (safety 0)) + (declare (optimize speed #.*safety-0*) (type fixnum code)) (if (<= code #x7f) code (get-multibyte-mapper +ucs-to-gbk-table+ code))) (defun gbk-to-ucs (code) - (declare (optimize speed (safety 0)) + (declare (optimize speed #.*safety-0*) (type fixnum code)) (if (<= code #x7f) code (get-multibyte-mapper +gbk-to-ucs-table+ code))) (defun mb-len-as-gbk (code) - (declare (optimize speed (safety 0)) + (declare (optimize speed #.*safety-0*) (type (unsigned-byte 8) code)) (if (< code #x80) 1 2)) (defun gbk-continuation-byte-p (code) - (declare (optimize speed (safety 0)) + (declare (optimize speed #.*safety-0*) (type (unsigned-byte 8) code) (ignore code)) t) diff --git a/src/code/external-formats/enc-ebcdic.lisp b/src/code/external-formats/enc-ebcdic.lisp index 4dd2b5eb9a..de0d3a7f1d 100644 --- a/src/code/external-formats/enc-ebcdic.lisp +++ b/src/code/external-formats/enc-ebcdic.lisp @@ -9,11 +9,11 @@ (setf (aref code-to-byte-table (aref byte-to-code-table i)) i)) `(progn (defun ,byte-code-name (byte) - (declare (optimize speed (safety 0)) + (declare (optimize speed #.*safety-0*) (type (unsigned-byte 8) byte)) (aref ,byte-to-code-table byte)) (defun ,code-byte-name (code) - (declare (optimize speed (safety 0)) + (declare (optimize speed #.*safety-0*) (type char-code code)) (if (> code 255) nil @@ -39,13 +39,13 @@ (declaim (inline get-ebcdic-us-bytes)) (defun get-ebcdic-us-bytes (string pos) - (declare (optimize speed (safety 0)) + (declare (optimize speed #.*safety-0*) (type simple-string string) (type array-range pos)) (get-latin-bytes #'code->ebcdic-us-mapper :ebcdic-us string pos)) (defun string->ebcdic-us (string sstart send null-padding) - (declare (optimize speed (safety 0)) + (declare (optimize speed #.*safety-0*) (type simple-string string) (type array-range sstart send)) (values (string->latin% string sstart send #'get-ebcdic-us-bytes null-padding))) diff --git a/src/code/external-formats/enc-jpn.lisp b/src/code/external-formats/enc-jpn.lisp index d4630c3d1b..147b432324 100644 --- a/src/code/external-formats/enc-jpn.lisp +++ b/src/code/external-formats/enc-jpn.lisp @@ -5,26 +5,26 @@ mb-len-as-eucjp eucjp-continuation-byte-p)) (defun ucs-to-eucjp (code) - (declare (optimize speed (safety 0)) + (declare (optimize speed #.*safety-0*) (type fixnum code)) (if (<= code #x7F) code (get-multibyte-mapper +ucs-to-eucjp-table+ code))) (defun eucjp-to-ucs (code) - (declare (optimize speed (safety 0)) + (declare (optimize speed #.*safety-0*) (type fixnum code)) (if (<= code #x7F) code (get-multibyte-mapper +eucjp-to-ucs-table+ code))) (defun mb-len-as-eucjp (code) - (declare (optimize speed (safety 0)) + (declare (optimize speed #.*safety-0*) (type (unsigned-byte 8) code)) (cond ((< code #x80) 1) ((or (= code #x8E) (<= #xA1 code #xFE)) 2) ((= code #x8F) 3))) (defun eucjp-continuation-byte-p (code) - (declare (optimize speed (safety 0)) + (declare (optimize speed #.*safety-0*) (type (unsigned-byte 8) code)) (<= #xA1 code #xFE)) @@ -37,25 +37,25 @@ mb-len-as-sjis sjis-continuation-byte-p)) (defun ucs-to-sjis (code) - (declare (optimize speed (safety 0)) + (declare (optimize speed #.*safety-0*) (type fixnum code)) (if (<= code #x7F) code (get-multibyte-mapper +ucs-to-sjis-table+ code))) (defun sjis-to-ucs (code) - (declare (optimize speed (safety 0)) + (declare (optimize speed #.*safety-0*) (type fixnum code)) (if (<= code #x7F) code (get-multibyte-mapper +sjis-to-ucs-table+ code))) (defun mb-len-as-sjis (code) - (declare (optimize speed (safety 0)) + (declare (optimize speed #.*safety-0*) (type (unsigned-byte 8) code)) (cond ((or (< code #x80) (<= #xA1 code #xDF)) 1) ((or (<= #x81 code #x9F) (<= #xE0 code #xFC)) 2))) (defun sjis-continuation-byte-p (code) - (declare (optimize speed (safety 0)) + (declare (optimize speed #.*safety-0*) (type (unsigned-byte 8) code)) (or (<= #x40 code #x7E) (<= #x80 code #xFC))) diff --git a/src/code/external-formats/enc-ucs.lisp b/src/code/external-formats/enc-ucs.lisp index de9d0e7bd0..5a35a00fd8 100644 --- a/src/code/external-formats/enc-ucs.lisp +++ b/src/code/external-formats/enc-ucs.lisp @@ -86,7 +86,7 @@ ;;; Conversion to UCS-2{LE,BE} (declaim (inline char->ucs-2le)) (defun char->ucs-2le (char dest string pos) - (declare (optimize speed (safety 0)) + (declare (optimize speed #.*safety-0*) (type (array (unsigned-byte 8) (*)) dest)) (let ((code (char-code char))) (if (< code #x10000) @@ -103,7 +103,7 @@ (declaim (inline char->ucs-2be)) (defun char->ucs-2be (char dest string pos) - (declare (optimize speed (safety 0)) + (declare (optimize speed #.*safety-0*) (type (array (unsigned-byte 8) (*)) dest)) (let ((code (char-code char))) (if (< code #x10000) @@ -119,7 +119,7 @@ (vector-push-extend (aref replacement i) dest)))))) (defun string->ucs-2le (string sstart send additional-space) - (declare (optimize speed (safety 0)) + (declare (optimize speed #.*safety-0*) (type simple-string string) (type array-range sstart send additional-space)) (let ((array (make-array (* 2 (+ additional-space (- send sstart))) @@ -132,7 +132,7 @@ (coerce array '(simple-array (unsigned-byte 8) (*))))) (defun string->ucs-2be (string sstart send additional-space) - (declare (optimize speed (safety 0)) + (declare (optimize speed #.*safety-0*) (type simple-string string) (type array-range sstart send additional-space)) (let ((array (make-array (* 2 (+ additional-space (- send sstart))) @@ -163,7 +163,7 @@ (name-be (make-od-name 'simple-get-ucs-2be-char accessor))) `(progn (defun ,name-le (array pos bytes) - (declare (optimize speed (safety 0)) + (declare (optimize speed #.*safety-0*) (type ,type array) (type array-range pos) (type (integer 1 4) bytes) @@ -178,7 +178,7 @@ (declare (inline cref)) (code-char (dpb (cref 1) (byte 8 8) (cref 0)))))) (defun ,name-be (array pos bytes) - (declare (optimize speed (safety 0)) + (declare (optimize speed #.*safety-0*) (type ,type array) (type array-range pos) (type (integer 1 4) bytes) @@ -199,7 +199,7 @@ (name-be (make-od-name 'ucs-2be->string accessor))) `(progn (defun ,name-le (array astart aend) - (declare (optimize speed (safety 0)) + (declare (optimize speed #.*safety-0*) (type ,type array) (type array-range astart aend)) (let ((string (make-array 0 :adjustable t :fill-pointer 0 :element-type 'character))) @@ -216,7 +216,7 @@ (incf pos bytes))) string)) (defun ,name-be (array astart aend) - (declare (optimize speed (safety 0)) + (declare (optimize speed #.*safety-0*) (type ,type array) (type array-range astart aend)) (let ((string (make-array 0 :adjustable t :fill-pointer 0 :element-type 'character))) @@ -259,7 +259,7 @@ (declaim (inline char->ucs-4le)) (defun char->ucs-4le (char dest string pos) - (declare (optimize speed (safety 0)) + (declare (optimize speed #.*safety-0*) (type (array (unsigned-byte 8) (*)) dest) (ignore string pos)) (let ((code (char-code char))) @@ -274,7 +274,7 @@ (declaim (inline char->ucs-4be)) (defun char->ucs-4be (char dest string pos) - (declare (optimize speed (safety 0)) + (declare (optimize speed #.*safety-0*) (type (array (unsigned-byte 8) (*)) dest) (ignore string pos)) (let ((code (char-code char))) @@ -288,7 +288,7 @@ (add-byte (ldb (byte 8 0) code))))) (defun string->ucs-4le (string sstart send additional-space) - (declare (optimize speed (safety 0)) + (declare (optimize speed #.*safety-0*) (type simple-string string) (type array-range sstart send additional-space)) (let ((array (make-array (* 4 (+ additional-space (- send sstart))) @@ -301,7 +301,7 @@ (coerce array '(simple-array (unsigned-byte 8) (*))))) (defun string->ucs-4be (string sstart send additional-space) - (declare (optimize speed (safety 0)) + (declare (optimize speed #.*safety-0*) (type simple-string string) (type array-range sstart send additional-space)) (let ((array (make-array (* 4 (+ additional-space (- send sstart))) @@ -332,7 +332,7 @@ (name-be (make-od-name 'simple-get-ucs-4be-char accessor))) `(progn (defun ,name-le (array pos bytes) - (declare (optimize speed (safety 0)) + (declare (optimize speed #.*safety-0*) (type ,type array) (type array-range pos) (type (integer 1 4) bytes)) @@ -347,12 +347,12 @@ (dpb (cref 3) (byte 8 24) (dpb (cref 2) (byte 8 16) (dpb (cref 1) (byte 8 8) (cref 0)))))))) - (if (< code sb-xc:char-code-limit) + (if (< code char-code-limit) (code-char code) (decoding-error array pos (+ pos bytes) :ucs-4le 'octet-decoding-error pos)))) (defun ,name-be (array pos bytes) - (declare (optimize speed (safety 0)) + (declare (optimize speed #.*safety-0*) (type ,type array) (type array-range pos) (type (integer 1 4) bytes)) @@ -366,13 +366,13 @@ (dpb (cref 0) (byte 8 24) (dpb (cref 1) (byte 8 16) (dpb (cref 2) (byte 8 8) (cref 3)))))))) - (if (< code sb-xc:char-code-limit) + (if (< code char-code-limit) (code-char code) (decoding-error array pos (+ pos bytes) :ucs-4be 'octet-decoding-error pos))))))) (eval-when (:compile-toplevel) - (sb-xc:proclaim '(muffle-conditions compiler-note))) + (proclaim '(muffle-conditions compiler-note))) (instantiate-octets-definition define-simple-get-ucs4-character) (defmacro define-ucs-4->string (accessor type) @@ -380,7 +380,7 @@ (name-be (make-od-name 'ucs-4be->string accessor))) `(progn (defun ,name-le (array astart aend) - (declare (optimize speed (safety 0)) + (declare (optimize speed #.*safety-0*) (type ,type array) (type array-range astart aend)) (let ((string (make-array 0 :adjustable t :fill-pointer 0 :element-type 'character))) @@ -398,7 +398,7 @@ (incf pos bytes))) string)) (defun ,name-be (array astart aend) - (declare (optimize speed (safety 0)) + (declare (optimize speed #.*safety-0*) (type ,type array) (type array-range astart aend)) (let ((string (make-array 0 :adjustable t :fill-pointer 0 :element-type 'character))) @@ -424,7 +424,7 @@ (setf (sap-ref-32le sap tail) bits) 4 (let ((code (sap-ref-32le sap head))) - (if (< code sb-xc:char-code-limit) + (if (< code char-code-limit) (code-char code) (return-from decode-break-reason 4))) ucs-4le->string-aref @@ -436,7 +436,7 @@ (setf (sap-ref-32be sap tail) bits) 4 (let ((code (sap-ref-32be sap head))) - (if (< code sb-xc:char-code-limit) + (if (< code char-code-limit) (code-char code) (return-from decode-break-reason 4))) ucs-4be->string-aref diff --git a/src/code/external-formats/enc-utf.lisp b/src/code/external-formats/enc-utf.lisp index 00636482d4..eeb5ee4199 100644 --- a/src/code/external-formats/enc-utf.lisp +++ b/src/code/external-formats/enc-utf.lisp @@ -26,7 +26,7 @@ ;;; Conversion to UTF-16{LE,BE} (declaim (inline char->utf-16le)) (defun char->utf-16le (char dest string pos) - (declare (optimize speed (safety 0)) + (declare (optimize speed #.*safety-0*) (type (array (unsigned-byte 8) (*)) dest)) (let ((code (char-code char))) (if (utf-noncharacter-code-p code) @@ -53,7 +53,7 @@ (declaim (inline char->utf-16be)) (defun char->utf-16be (char dest string pos) - (declare (optimize speed (safety 0)) + (declare (optimize speed #.*safety-0*) (type (array (unsigned-byte 8) (*)) dest)) (let ((code (char-code char))) (if (utf-noncharacter-code-p code) @@ -79,7 +79,7 @@ (add-byte (ldb (byte 8 0) low))))))))) (defun string->utf-16le (string sstart send additional-space) - (declare (optimize speed (safety 0)) + (declare (optimize speed #.*safety-0*) (type simple-string string) (type array-range sstart send additional-space)) (let ((array (make-array (* 2 (+ additional-space (- send sstart))) @@ -92,7 +92,7 @@ (coerce array '(simple-array (unsigned-byte 8) (*))))) (defun string->utf-16be (string sstart send additional-space) - (declare (optimize speed (safety 0)) + (declare (optimize speed #.*safety-0*) (type simple-string string) (type array-range sstart send additional-space)) (let ((array (make-array (* 2 (+ additional-space (- send sstart))) @@ -157,7 +157,7 @@ (name-be (make-od-name 'simple-get-utf-16be-char accessor))) `(progn (defun ,name-le (array pos bytes) - (declare (optimize speed (safety 0)) + (declare (optimize speed #.*safety-0*) (type ,type array) (type array-range pos) (type (integer 1 4) bytes) @@ -182,7 +182,7 @@ (code-char (+ #x10000 (dpb (ldb (byte 10 0) code) (byte 10 10) (ldb (byte 10 0) next))))) (code-char code)))) (defun ,name-be (array pos bytes) - (declare (optimize speed (safety 0)) + (declare (optimize speed #.*safety-0*) (type ,type array) (type array-range pos) (type (integer 1 4) bytes) @@ -213,7 +213,7 @@ (name-be (make-od-name 'utf-16be->string accessor))) `(progn (defun ,name-le (array astart aend) - (declare (optimize speed (safety 0)) + (declare (optimize speed #.*safety-0*) (type ,type array) (type array-range astart aend)) (let ((string (make-array 0 :adjustable t :fill-pointer 0 :element-type 'character))) @@ -233,7 +233,7 @@ (incf pos bytes))) string)) (defun ,name-be (array astart aend) - (declare (optimize speed (safety 0)) + (declare (optimize speed #.*safety-0*) (type ,type array) (type array-range astart aend)) (let ((string (make-array 0 :adjustable t :fill-pointer 0 :element-type 'character))) @@ -327,7 +327,7 @@ (declaim (inline char->utf-32le)) (defun char->utf-32le (char dest string pos) - (declare (optimize speed (safety 0)) + (declare (optimize speed #.*safety-0*) (type (array (unsigned-byte 8) (*)) dest)) (let ((code (char-code char))) (if (utf-noncharacter-code-p code) @@ -346,7 +346,7 @@ (declaim (inline char->utf-32be)) (defun char->utf-32be (char dest string pos) - (declare (optimize speed (safety 0)) + (declare (optimize speed #.*safety-0*) (type (array (unsigned-byte 8) (*)) dest)) (let ((code (char-code char))) (if (utf-noncharacter-code-p code) @@ -364,7 +364,7 @@ (add-byte (ldb (byte 8 0) code)))))) (defun string->utf-32le (string sstart send additional-space) - (declare (optimize speed (safety 0)) + (declare (optimize speed #.*safety-0*) (type simple-string string) (type array-range sstart send additional-space)) (let ((array (make-array (* 4 (+ additional-space (- send sstart))) @@ -377,7 +377,7 @@ (coerce array '(simple-array (unsigned-byte 8) (*))))) (defun string->utf-32be (string sstart send additional-space) - (declare (optimize speed (safety 0)) + (declare (optimize speed #.*safety-0*) (type simple-string string) (type array-range sstart send additional-space)) (let ((array (make-array (* 4 (+ additional-space (- send sstart))) @@ -408,7 +408,7 @@ (name-be (make-od-name 'simple-get-utf-32be-char accessor))) `(progn (defun ,name-le (array pos bytes) - (declare (optimize speed (safety 0)) + (declare (optimize speed #.*safety-0*) (type ,type array) (type array-range pos) (type (integer 1 4) bytes)) @@ -429,7 +429,7 @@ (decoding-error array pos (+ pos bytes) :utf-32le 'octet-decoding-error pos)))) (defun ,name-be (array pos bytes) - (declare (optimize speed (safety 0)) + (declare (optimize speed #.*safety-0*) (type ,type array) (type array-range pos) (type (integer 1 4) bytes)) @@ -457,7 +457,7 @@ (name-be (make-od-name 'utf-32be->string accessor))) `(progn (defun ,name-le (array astart aend) - (declare (optimize speed (safety 0)) + (declare (optimize speed #.*safety-0*) (type ,type array) (type array-range astart aend)) (let ((string (make-array 0 :adjustable t :fill-pointer 0 :element-type 'character))) @@ -475,7 +475,7 @@ (incf pos bytes))) string)) (defun ,name-be (array astart aend) - (declare (optimize speed (safety 0)) + (declare (optimize speed #.*safety-0*) (type ,type array) (type array-range astart aend)) (let ((string (make-array 0 :adjustable t :fill-pointer 0 :element-type 'character))) diff --git a/src/code/external-formats/mb-util.lisp b/src/code/external-formats/mb-util.lisp index 0ffca0112e..b1ff4e17b4 100644 --- a/src/code/external-formats/mb-util.lisp +++ b/src/code/external-formats/mb-util.lisp @@ -1,16 +1,20 @@ (in-package "SB-IMPL") (defmacro define-multibyte-mapper (name list) - (let ((list (sort (copy-list list) #'< :key #'car)) - (hi (loop for x in list maximize (max (car x) (cadr x))))) - `(defconstant-eqx ,name - (make-array '(,(length list) 2) - :element-type '(integer 0 ,hi) - :initial-contents ',list) - #'equalp))) + (let* ((list (sort (copy-list list) #'< :key #'car)) + (hi (loop for x in list maximize (max (car x) (cadr x)))) + (array (make-array `(,(length list) 2) + :element-type `(integer 0 ,hi) + :initial-contents list))) + ;; This used to invoke MAKE-ARRAY in the defining form, but a quoted constant + ;; is better - it's literal and therefore implicitly readonly. + ;; And the cross-compiler dumps specialized arrays correctly these days, + ;; but guess what, this is compiled in warm build anyway, so who even cares + ;; what the cross-compiler used to not be OK with? + `(defconstant-eqx ,name ,array #'equalp))) (defun get-multibyte-mapper (table code) - (declare (optimize speed (safety 0)) + (declare (optimize speed #.*safety-0*) (type (array * (* 2)) table) (type fixnum code)) (labels ((recur (start end) @@ -42,7 +46,7 @@ `(progn ;;(declaim (inline ,name)) (defun ,name (array pos end) - (declare (optimize speed (safety 0)) + (declare (optimize speed #.*safety-0*) (type ,type array) (type array-range pos end)) ;; returns the number of bytes consumed and nil if it's a @@ -113,7 +117,7 @@ `(progn (declaim (inline ,name)) (defun ,name (array pos bytes) - (declare (optimize speed (safety 0)) + (declare (optimize speed #.*safety-0*) (type ,type array) (type array-range pos) (type (integer 1 3) bytes)) @@ -140,7 +144,7 @@ (make-od-name-list 'simple-get format 'char accessor))) `(progn (defun ,name (array astart aend) - (declare (optimize speed (safety 0)) + (declare (optimize speed #.*safety-0*) (type ,type array) (type array-range astart aend)) (let ((string (make-array 0 :adjustable t :fill-pointer 0 :element-type 'character))) @@ -165,7 +169,7 @@ (declaim (inline mb-char-len)) (defun mb-char-len (code) - (declare (optimize speed (safety 0)) + (declare (optimize speed #.*safety-0*) (type fixnum code)) (cond ((< code 0) (bug "can't happen")) ((< code #x100) 1) @@ -196,7 +200,7 @@ (declaim (inline ,char->mb)) (defun ,char->mb (char dest string pos) - (declare (optimize speed (safety 0)) + (declare (optimize speed #.*safety-0*) (type (array (unsigned-byte 8) (*)) dest)) (let ((code (,ucs-to-mb (char-code char)))) (if code @@ -218,7 +222,7 @@ (encoding-error ,format string pos)))) (defun ,string->mb (string sstart send additional-space) - (declare (optimize speed (safety 0)) + (declare (optimize speed #.*safety-0*) (type simple-string string) (type array-range sstart send additional-space)) (let ((array (make-array (+ additional-space (- send sstart)) diff --git a/src/code/fd-stream.lisp b/src/code/fd-stream.lisp index 81e3861e28..6d1e432ace 100644 --- a/src/code/fd-stream.lisp +++ b/src/code/fd-stream.lisp @@ -51,7 +51,7 @@ (define-load-time-global *available-buffers* () "List of available buffers.") -(defconstant +bytes-per-buffer+ (* 4 1024) +(defconstant +bytes-per-buffer+ (* 8 1024) "Default number of bytes per buffer.") (defun alloc-buffer (&optional (size +bytes-per-buffer+)) @@ -96,6 +96,8 @@ (:conc-name fd-stream-) (:predicate fd-stream-p) (:include ansi-stream + ;; FIXME: would a type constraint on IN-BUFFER + ;; and/or CIN-BUFFER improve anything? (misc #'fd-stream-misc-routine)) (:copier nil)) @@ -207,18 +209,22 @@ (defun line/col-from-charpos (stream &optional (charpos (ansi-stream-input-char-pos stream))) - (let* ((newlines (form-tracking-stream-newlines stream)) - (index (position charpos newlines :test #'>= :from-end t))) - ;; Line numbers traditionally begin at 1, columns at 0. - (if index - ;; INDEX is 1 less than the number of newlines seen - ;; up to and including this startpos. - ;; e.g. index=0 => 1 newline seen => line=2 - (cons (+ index 2) - ;; 1 char after the newline = column 0 - (- charpos (aref newlines index) 1)) - ;; zero newlines were seen - (cons 1 charpos)))) + (let ((newlines (form-tracking-stream-newlines stream))) + (if charpos + (let ((index (position charpos newlines :test #'>= :from-end t))) + ;; Line numbers traditionally begin at 1, columns at 0. + (if index + ;; INDEX is 1 less than the number of newlines seen + ;; up to and including this startpos. + ;; e.g. index=0 => 1 newline seen => line=2 + (cons (+ index 2) + ;; 1 char after the newline = column 0 + (- charpos (aref newlines index) 1)) + ;; zero newlines were seen + (cons 1 charpos))) + ;; No charpos means the error is before reading the first char + ;; e.g. an encoding error. Take the last Newline. + (cons (1+ (length newlines)) 0)))) ;;;; CORE OUTPUT FUNCTIONS @@ -249,10 +255,17 @@ ;; something, or be even full. (let* ((obuf (fd-stream-obuf stream)) (tail (buffer-tail obuf)) - (space (- (buffer-length obuf) tail))) - (when (plusp space) - (copy-to-buffer obuf tail (min space (- end start))) - (go :more-output-p))) + (buffer-length (buffer-length obuf)) + (space (- buffer-length tail)) + (length (- end start))) + (cond ((and (not (fd-stream-serve-events stream)) + (>= length buffer-length)) + (flush-output-buffer stream) + (finish-writing-sequence thing stream start end) + (return-from buffer-output)) + ((plusp space) + (copy-to-buffer obuf tail (min space length)) + (go :more-output-p)))) :flush-and-fill ;; Later copies should always have an empty buffer, since ;; they are freshly flushed, but if another thread is @@ -325,6 +338,34 @@ (simple-stream-perror +write-failed+ stream errno))))))))))))) +(defun finish-writing-sequence (sequence stream start end) + (synchronize-stream-output stream) + (loop + (let ((length (- end start))) + (multiple-value-bind (count errno) + (sb-unix:unix-write (fd-stream-fd stream) sequence start length) + (flet ((wait () + (or (wait-until-fd-usable (fd-stream-fd stream) :output + (fd-stream-timeout stream) + nil) + (signal-timeout 'io-timeout + :stream stream + :direction :output + :seconds (fd-stream-timeout stream))))) + (cond ((eql count length) + (return t)) + (count + (incf start count) + (wait)) + #-win32 + ((eql errno sb-unix:ewouldblock) + (wait)) + ;; if interrupted on win32, just try again + #+win32 ((eql errno sb-unix:eintr)) + (t + (simple-stream-perror +write-failed+ + stream errno)))))))) + ;;; Helper for FLUSH-OUTPUT-BUFFER -- returns the new buffer. (defun %queue-and-replace-output-buffer (stream) (aver (fd-stream-serve-events stream)) @@ -426,15 +467,6 @@ (if (= errno sb-unix:ewouldblock) (buffer-output stream thing start end) (simple-stream-perror +write-failed+ stream errno))))))))) - -;;; Deprecated -- can go away after 1.1 or so. Deprecated because -;;; this is not something we want to export. Nikodemus thinks the -;;; right thing is to support a low-level non-stream like IO layer, -;;; akin to java.nio. -(declaim (inline output-raw-bytes)) -(define-deprecated-function :late "1.0.8.16" output-raw-bytes write-sequence - (stream thing &optional start end) - (write-or-buffer-output stream thing (or start 0) (or end (length thing)))) ;;;; output routines and related noise @@ -462,16 +494,16 @@ (defun file-perror (pathname errno &optional datum &rest arguments) (declare (optimize allow-non-returning-tail-call)) - (multiple-value-bind (condition-type arguments) - (typecase datum - (format-control - (values 'simple-file-error - (list :format-control "~@<~?~@[: ~2I~_~A~]~:>" - :format-arguments (list datum arguments - (when errno (strerror errno)))))) - (t - (values datum arguments))) - (apply #'error condition-type :pathname pathname arguments))) + (let ((message (when errno (strerror errno)))) + (multiple-value-bind (condition-type arguments) + (typecase datum + (format-control + (values 'simple-file-error (list :format-control datum + :format-arguments arguments))) + (t + (values datum arguments))) + (apply #'error condition-type :pathname pathname :message message + arguments)))) (defun c-string-encoding-error (external-format code) (declare (optimize allow-non-returning-tail-call)) @@ -753,7 +785,7 @@ ;;; the routine to use to output a string. If the stream is ;;; unbuffered, slam the string down the file descriptor, otherwise -;;; use OUTPUT-RAW-BYTES to buffer the string. Update charpos by +;;; use BUFFER-OUTPUT to buffer the string. Update charpos by ;;; checking to see where the last newline was. (defun fd-sout (stream thing start end) (declare (type fd-stream stream) (type string thing)) @@ -964,7 +996,7 @@ ;;; further assurance than "may" versus "will definitely not". (defun sysread-may-block-p (stream) #+win32 - ;; This answers T at EOF on win32, I think. + ;; This answers T at EOF on win32. (not (sb-win32:handle-listen (fd-stream-fd stream))) #-win32 (not (sb-unix:unix-simple-poll (fd-stream-fd stream) :input 0))) @@ -1468,6 +1500,7 @@ (let* ((byte (aref string start)) (bits (char-code byte)) (size ,out-size-expr)) + (declare (ignorable byte bits)) ,out-expr (incf tail size) (setf (buffer-tail obuf) tail) @@ -1606,7 +1639,7 @@ (let* ((stream ,name) (size 0) (head 0) (byte 0) (char nil) (decode-break-reason nil) - (length (dotimes (count (1- sb-xc:array-dimension-limit) count) + (length (dotimes (count (1- array-dimension-limit) count) (setf decode-break-reason (block decode-break-reason (setf byte (sap-ref-8 sap head) @@ -1628,7 +1661,7 @@ (make-string length :element-type 'character)) (t (make-string length :element-type element-type))))) - (declare (ignorable stream) + (declare (ignorable stream byte) (type index head length) ;; size (type (unsigned-byte 8) byte) (type (or null character) char) @@ -1902,9 +1935,12 @@ ;; us with a dangling finalizer (that would close the same ;; --possibly reassigned-- FD again), or a stream with a closed ;; FD that appears open. - (sb-unix:unix-close (fd-stream-fd fd-stream)) - (set-closed-flame fd-stream) - (cancel-finalization fd-stream)) + (cancel-finalization fd-stream) + (let ((fd (fd-stream-fd fd-stream))) + (when (and (/= fd -1) + (eq (cas (fd-stream-fd fd-stream) fd -1) fd)) + (sb-unix:unix-close fd))) + (set-closed-flame fd-stream)) ;; On error unwind from WITHOUT-INTERRUPTS. (serious-condition (e) (error e))) @@ -1942,17 +1978,13 @@ t)) ;;; Handle miscellaneous operations on FD-STREAM. -(defun fd-stream-misc-routine (fd-stream operation &optional arg1 arg2) - (declare (ignore arg2)) - (case operation +(defun fd-stream-misc-routine (fd-stream operation arg1) + (stream-misc-case (operation :default nil) (:listen (labels ((do-listen () (let ((ibuf (fd-stream-ibuf fd-stream))) (or (not (eql (buffer-head ibuf) (buffer-tail ibuf))) (fd-stream-listen fd-stream) - #+win32 - (sb-win32:handle-listen (fd-stream-fd fd-stream)) - #-win32 ;; If the read can block, LISTEN will certainly return NIL. (if (sysread-may-block-p fd-stream) nil @@ -2102,10 +2134,8 @@ (etypecase arg1 (character (fd-stream-character-size fd-stream arg1)) (string (fd-stream-string-size fd-stream arg1)))) - (:file-position - (if arg1 - (fd-stream-set-file-position fd-stream arg1) - (fd-stream-get-file-position fd-stream))))) + (:get-file-position (fd-stream-get-file-position fd-stream)) + (:set-file-position (fd-stream-set-file-position fd-stream arg1)))) ;; FIXME: Think about this. ;; @@ -2311,11 +2341,13 @@ namestring err "~@<couldn't rename ~2I~_~S ~I~_to ~2I~_~S~:>" namestring original)))) +(defun file-exist-p (path) + #-win32 (sb-unix:unix-access path sb-unix:f_ok) + #+win32 (/= (sb-win32:get-file-attributes path) sb-win32::invalid-file-attributes)) + (defun %open-error (pathname errno if-exists if-does-not-exist) - (flet ((signal-it (&optional (condition 'simple-file-error)) - (file-perror pathname errno condition - :format-control "Error opening ~S" - :format-arguments (list pathname)))) + (flet ((signal-it (&rest arguments) + (apply #'file-perror pathname errno arguments))) (restart-case (case errno (#-win32 #.sb-unix:enoent @@ -2351,14 +2383,14 @@ :report "Reopen with :if-exists :append" '(:new-if-exists :append))))) (t - (signal-it))) + (signal-it "Error opening ~S" pathname))) (continue () :report "Retry opening." '()) (use-value (value) :report "Try opening a different file." :interactive read-evaluated-form - (list :filename (the pathname-designator value)))))) + (list :new-filename (the pathname-designator value)))))) (defun open (filename &key @@ -2396,16 +2428,17 @@ (declare (type index mask)) (let* (;; PATHNAME is the pathname we associate with the stream. (pathname (merge-pathnames filename)) - (physical (physicalize-pathname pathname)) - (truename (probe-file physical)) - ;; NAMESTRING is the native namestring we open the file with. - (namestring (cond (truename - (native-namestring truename :as-file t)) - ((or (not input) - (and input (eq if-does-not-exist :create)) - (and (eq direction :io) - (not if-does-not-exist-given))) - (native-namestring physical :as-file t))))) + (physical (native-namestring (physicalize-pathname pathname) :as-file t)) + ;; One call to access() is reasonable. 40 calls to lstat() is not. + ;; So DO NOT CALL TRUENAME HERE. + (existsp (file-exist-p physical)) + ;; Leave NAMESTRING as NIL if nonexistent and not creating a file. + (namestring (when (or existsp + (or (not input) + (and input (eq if-does-not-exist :create)) + (and (eq direction :io) + (not if-does-not-exist-given)))) + physical))) ;; Process if-exists argument if we are doing any output. (cond (output (unless if-exists-given @@ -2435,9 +2468,7 @@ nil) (t :create)))) - (cond ((and if-exists-given - truename - (eq if-exists :new-version)) + (cond ((and existsp if-exists-given (eq if-exists :new-version)) (sb-kernel::%file-error pathname "OPEN :IF-EXISTS :NEW-VERSION is not supported ~ when a new version must be created.")) @@ -2454,7 +2485,7 @@ pathname "OPEN :IF-DOES-NOT-EXIST ~s ~ :IF-EXISTS ~s will always signal an error." if-does-not-exist if-exists)) - (truename + (existsp (if if-exists (sb-kernel::%file-error pathname 'file-exists) (return))) @@ -2486,15 +2517,16 @@ (when (and output (= (logand orig-mode #o170000) #o40000)) (file-perror - pathname - "can't open ~A for output: is a directory" pathname)) + pathname nil + "Can't open ~S for output: is a directory" + pathname)) (setf mode (logand orig-mode #o777)) t) ((eql err/dev sb-unix:enoent) nil) (t - (file-perror - namestring err/dev "can't find ~S" namestring))))))) + (file-perror namestring err/dev + "Can't find ~S" namestring))))))) (unless (and exists (rename-the-old-one namestring original)) (setf original nil) @@ -2559,134 +2591,6 @@ (when new-if-does-not-exist (setf if-does-not-exist new-if-does-not-exist if-does-not-exist-given t))))))))) - -;;;; initialization - -;;; the stream connected to the controlling terminal, or NIL if there is none -(defvar *tty*) - -;;; the stream connected to the standard input (file descriptor 0) -(defvar *stdin*) - -;;; the stream connected to the standard output (file descriptor 1) -(defvar *stdout*) - -;;; the stream connected to the standard error output (file descriptor 2) -(defvar *stderr*) - -;;; This is called when the cold load is first started up, and may also -;;; be called in an attempt to recover from nested errors. -(defun stream-cold-init-or-reset () - (stream-reinit) - (setf *terminal-io* (make-synonym-stream '*tty*)) - (setf *standard-output* (make-synonym-stream '*stdout*)) - (setf *standard-input* (make-synonym-stream '*stdin*)) - (setf *error-output* (make-synonym-stream '*stderr*)) - (setf *query-io* (make-synonym-stream '*terminal-io*)) - (setf *debug-io* *query-io*) - (setf *trace-output* *standard-output*) - (values)) - -(defun stream-deinit () - (setq *tty* nil *stdin* nil *stdout* nil *stderr* nil) - ;; Unbind to make sure we're not accidently dealing with it - ;; before we're ready (or after we think it's been deinitialized). - ;; This uses the internal %MAKUNBOUND because the CL: function would - ;; rightly complain that *AVAILABLE-BUFFERS* is proclaimed always bound. - (%makunbound '*available-buffers*)) - -(defvar *streams-closed-by-slad*) - -(defun restore-fd-streams () - (loop for (stream in bin n-bin out bout sout misc) in *streams-closed-by-slad* - do - (setf (ansi-stream-in stream) in) - (setf (ansi-stream-bin stream) bin) - (setf (ansi-stream-n-bin stream) n-bin) - (setf (ansi-stream-out stream) out) - (setf (ansi-stream-bout stream) bout) - (setf (ansi-stream-sout stream) sout) - (setf (ansi-stream-misc stream) misc))) - -(defun stdstream-external-format (fd) - #-win32 (declare (ignore fd)) - (let* ((keyword (cond #+(and win32 sb-unicode) - ((sb-win32::console-handle-p fd) - :ucs-2) - (t - (default-external-format)))) - (ef (get-external-format keyword)) - (replacement (ef-default-replacement-character ef))) - `(,keyword :replacement ,replacement))) - -;;; This is called whenever a saved core is restarted. -(defun stream-reinit (&optional init-buffers-p) - (when init-buffers-p - ;; Use the internal %BOUNDP for similar reason to that cited above- - ;; BOUNDP on a known global transforms to the constant T. - (aver (not (%boundp '*available-buffers*))) - (setf *available-buffers* nil)) - (with-simple-output-to-string (*error-output*) - (multiple-value-bind (in out err) - #-win32 (values 0 1 2) - #+win32 (sb-win32::get-std-handles) - (labels (#+win32 - (nul-stream (name inputp outputp) - (let ((nul-handle - (cond - ((and inputp outputp) - (sb-win32:unixlike-open "NUL" sb-unix:o_rdwr)) - (inputp - (sb-win32:unixlike-open "NUL" sb-unix:o_rdonly)) - (outputp - (sb-win32:unixlike-open "NUL" sb-unix:o_wronly)) - (t - ;; Not quite sure what to do in this case. - nil)))) - (make-fd-stream - nul-handle - :name name - :input inputp - :output outputp - :buffering :line - :element-type :default - :serve-events inputp - :auto-close t - :external-format (stdstream-external-format nul-handle)))) - (stdio-stream (handle name inputp outputp) - (cond - #+win32 - ((null handle) - ;; If no actual handle was present, create a stream to NUL - (nul-stream name inputp outputp)) - (t - (make-fd-stream - handle - :name name - :input inputp - :output outputp - :buffering :line - :element-type :default - :serve-events inputp - :external-format (stdstream-external-format handle)))))) - (setf *stdin* (stdio-stream in "standard input" t nil) - *stdout* (stdio-stream out "standard output" nil t) - *stderr* (stdio-stream err "standard error" nil t)))) - #+win32 - (setf *tty* (make-two-way-stream *stdin* *stdout*)) - #-win32 - (let ((tty (sb-unix:unix-open "/dev/tty" sb-unix:o_rdwr #o666))) - (setf *tty* - (if tty - (make-fd-stream tty :name "the terminal" - :input t :output t :buffering :line - :external-format (stdstream-external-format tty) - :serve-events t - :auto-close t) - (make-two-way-stream *stdin* *stdout*)))) - (princ (get-output-stream-string *error-output*) *stderr*)) - (values)) - ;;;; miscellany ;;; the Unix way to beep @@ -2699,7 +2603,10 @@ ;;; ;;; FIXME: misleading name, screwy interface (defun file-name (stream &optional new-name) - (when (typep stream 'fd-stream) + (stream-api-dispatch (stream) + :gray (declare (ignore stream)) + :native + (when (typep stream 'fd-stream) (cond (new-name (setf (fd-stream-pathname stream) new-name) (setf (fd-stream-file stream) @@ -2707,7 +2614,8 @@ :as-file t)) t) (t - (fd-stream-pathname stream))))) + (fd-stream-pathname stream)))) + :simple (s-%file-name stream new-name))) ;; Fix the INPUT-CHAR-POS slot of STREAM after having consumed characters ;; from the CIN-BUFFER. This operation is done upon exit from a FAST-READ-CHAR @@ -2726,45 +2634,11 @@ (setf (form-tracking-stream-last-newline stream) pos)) (incf pos)))) -(defun tracking-stream-misc (stream operation &optional arg1 arg2) +(defun tracking-stream-misc (stream operation arg1) ;; The :UNREAD operation will never be invoked because STREAM has a buffer, ;; so unreading is implemented entirely within ANSI-STREAM-UNREAD-CHAR. ;; But we do need to prevent attempts to change the absolute position. - (case operation - (:file-position - (if arg1 - (simple-stream-perror "~S is not positionable" stream) - (fd-stream-get-file-position stream))) + (stream-misc-case (operation) + (:set-file-position (simple-stream-perror "~S is not positionable" stream)) (t ; call next method - (fd-stream-misc-routine stream operation arg1 arg2)))) - -(!define-load-time-global *!cold-stderr-buf* " ") -(declaim (type (simple-base-string 1) *!cold-stderr-buf*)) - -(defun !make-cold-stderr-stream () - (let ((stderr - #-win32 2 - #+win32 (sb-win32::get-std-handle-or-null sb-win32::+std-error-handle+))) - (%make-fd-stream - :out (lambda (stream ch) - (declare (ignore stream)) - (let ((b *!cold-stderr-buf*)) - (setf (char b 0) ch) - (sb-unix:unix-write stderr b 0 1))) - :sout (lambda (stream string start end) - (declare (ignore stream)) - (flet ((out (s start len) - (when (plusp len) - (setf (char *!cold-stderr-buf* 0) (char s (+ start len -1)))) - (sb-unix:unix-write stderr s start len))) - (if (typep string 'simple-base-string) - (out string start (- end start)) - (let ((n (- end start))) - ;; will croak if there is any non-BASE-CHAR in the string - (out (replace (make-array n :element-type 'base-char) - string :start2 start) 0 n))))) - :misc (lambda (stream operation &optional arg1 arg2) - (declare (ignore stream arg1 arg2)) - (case operation - (:charpos ; impart just enough smarts to make FRESH-LINE dtrt - (if (eql (char *!cold-stderr-buf* 0) #\newline) 0 1))))))) + (fd-stream-misc-routine stream operation arg1)))) diff --git a/src/code/fdefinition.lisp b/src/code/fdefinition.lisp index 788563ea09..c33e0f21be 100644 --- a/src/code/fdefinition.lisp +++ b/src/code/fdefinition.lisp @@ -14,10 +14,6 @@ (in-package "SB-IMPL") -;; This variable properly belongs in 'target-hash-table', -;; but it's compiled after this file is. -(!define-load-time-global *user-hash-table-tests* nil) - ;;;; fdefinition (fdefn) objects @@ -27,10 +23,8 @@ (let ((fdefn (truly-the (values fdefn &optional) (sb-vm::alloc-immobile-fdefn)))) (sb-vm::%set-fdefn-name fdefn name) - ;; Return the result of FDEFN-MAKUNBOUND because it (strangely) returns its - ;; argument. Using FDEFN as the value of this function, as if we didn't know - ;; that FDEFN-MAKUNBOUND did that, would cause a redundant register move. - (truly-the fdefn (fdefn-makunbound fdefn)))) + (fdefn-makunbound fdefn) + fdefn)) (defun (setf fdefn-fun) (fun fdefn) (declare (type function fun) @@ -39,41 +33,15 @@ #+immobile-code (sb-vm::%set-fdefn-fun fdefn fun) #-immobile-code (setf (fdefn-fun fdefn) fun)) -;; Given Info-Vector VECT, return the fdefn that it contains for its root name, -;; or nil if there is no value. NIL input is acceptable and will return NIL. -;; (see src/compiler/info-vector for more details) -(declaim (inline info-vector-fdefn)) -(defun info-vector-fdefn (vect) - (when vect - ;; This is safe: Info-Vector invariant requires that it have length >= 1. - (let ((word (the fixnum (svref vect 0)))) - ;; Test that the first info-number is +fdefn-info-num+ and its n-infos - ;; field is nonzero. These conditions can be tested simultaneously - ;; using a SIMD-in-a-register idea. The low 6 bits must be nonzero - ;; and the next 6 must be exactly #b111111, so considered together - ;; as a 12-bit unsigned integer it must be >= #b111111000001 - (when (>= (ldb (byte (* info-number-bits 2) 0) word) - (1+ (ash +fdefn-info-num+ info-number-bits))) - ;; DATA-REF-WITH-OFFSET doesn't know the info-vector length invariant, - ;; so depite (safety 0) eliding bounds check, FOLD-INDEX-ADDRESSING - ;; wasn't kicking in without (TRULY-THE (INTEGER 1 *)). - (aref vect (1- (truly-the (integer 1 *) (length vect)))))))) - -;; Return SYMBOL's fdefinition, if any, or NIL. SYMBOL must already -;; have been verified to be a symbol by the caller. -(defun symbol-fdefn (symbol) - (declare (optimize (safety 0))) - (info-vector-fdefn (symbol-info-vector symbol))) - -;; Return the fdefn object for NAME, or NIL if there is no fdefn. -;; Signal an error if name isn't valid. -;; Assume that exists-p implies LEGAL-FUN-NAME-P. -;; +;;; Return the FDEFN object for NAME, or NIL if there is no fdefn. +;;; Signal an error if name isn't valid. +;;; Assume that exists-p implies LEGAL-FUN-NAME-P. (declaim (ftype (sfunction ((or symbol list)) (or fdefn null)) find-fdefn)) (defun find-fdefn (name) (declare (explicit-check)) (when (symbolp name) ; Don't need LEGAL-FUN-NAME-P check - (return-from find-fdefn (symbol-fdefn name))) + (let ((fdefn (sb-vm::%symbol-fdefn name))) ; slot default is 0, not NIL + (return-from find-fdefn (if (eql fdefn 0) nil fdefn)))) ;; Technically the ALLOW-ATOM argument of NIL isn't needed, but ;; the compiler isn't figuring out not to test SYMBOLP twice in a row. (with-globaldb-name (key1 key2 nil) name @@ -82,7 +50,7 @@ (return-from find-fdefn it)) :simple (progn - (awhen (symbol-info-vector key1) + (awhen (symbol-dbinfo key1) (multiple-value-bind (data-idx descriptor-idx field-idx) (info-find-aux-key/packed it key2) (declare (type index descriptor-idx) @@ -95,14 +63,53 @@ (when (eql (packed-info-field it descriptor-idx field-idx) +fdefn-info-num+) (return-from find-fdefn - (aref it (1- (the index data-idx)))))))) + (%info-ref it (1- (the index data-idx)))))))) (when (eq key1 'setf) ; bypass the legality test (return-from find-fdefn nil)))) (legal-fun-name-or-type-error name)) +;;; Return T if FUNCTION is the error-signaling trampoline for a macro or a +;;; special operator. Test for this by seeing whether FUNCTION is the same +;;; closure as for a known macro. +(declaim (inline macro/special-guard-fun-p)) +(defun macro/special-guard-fun-p (function) + ;; When inlined, this is a few instructions shorter than CLOSUREP + ;; if we already know that FUNCTION is a function. + ;; It will signal a type error if not, which is the right thing to do anyway. + ;; (this isn't quite a true predicate) + (and (= (%fun-pointer-widetag function) sb-vm:closure-widetag) + ;; This test needs to reference the name of any macro, but in order for + ;; cold-init to work, the macro has to be defined first. + ;; So pick DX-LET, as it's in primordial-extensions. + ;; Prior to cold-init fixing up the load-time-value, this compares + ;; %closure-fun to 0, which is ok - it returns NIL. + (eq (load-time-value (%closure-fun (symbol-function 'dx-let)) t) + (%closure-fun function)))) + +;;; This is the implementation of (COERCE s 'function) when S is of type symbol +;;; used by either the full call or the compile-time transform for that pattern. +(defun coerce-symbol-to-fun (symbol) + (let ((def (%symbol-function symbol))) + (cond ((not def) (error 'undefined-function :name symbol)) + ((macro/special-guard-fun-p def) + (error (ecase (car (%fun-name def)) + (:macro "~S names a macro.") + (:special "~S names a special operator.")) + symbol)) + (t def)))) + (declaim (ftype (sfunction (t) fdefn) find-or-create-fdefn)) (defun find-or-create-fdefn (name) - (or (find-fdefn name) + (cond + ((symbolp name) + (let ((fdefn (sb-vm::%symbol-fdefn name))) + (if (eql fdefn 0) + (let* ((new (make-fdefn name)) + (actual (sb-vm::cas-symbol-fdefn name 0 new))) + (if (eql actual 0) new (the fdefn actual))) + fdefn))) + ((find-fdefn name)) + (t ;; We won't reach here if the name was not legal (let (made-new) (dx-flet ((new (name) @@ -120,25 +127,7 @@ (when (and made-new (typep name '(cons (eql sb-pcl::slot-accessor)))) (sb-pcl::ensure-accessor name)) - fdefn))))) - -;;; Return T if FUNCTION is the error-signaling trampoline for a macro or a -;;; special operator. Test for this by seeing whether FUNCTION is the same -;;; closure as for a known macro. -(declaim (inline macro/special-guard-fun-p)) -(defun macro/special-guard-fun-p (function) - ;; When inlined, this is a few instructions shorter than CLOSUREP - ;; if we already know that FUNCTION is a function. - ;; It will signal a type error if not, which is the right thing to do anyway. - ;; (this isn't quite a true predicate) - (and (= (fun-subtype function) sb-vm:closure-widetag) - ;; This test needs to reference the name of any macro, but in order for - ;; cold-init to work, the macro has to be defined first. - ;; So pick DX-LET, as it's in primordial-extensions. - ;; Prior to cold-init fixing up the load-time-value, this compares - ;; %closure-fun to 0, which is ok - it returns NIL. - (eq (load-time-value (%closure-fun (symbol-function 'dx-let)) t) - (%closure-fun function)))) + fdefn)))))) ;;; Remove NAME's FTYPE information unless it was explicitly PROCLAIMED. ;;; The NEW-FUNCTION argument is presently unused, but could be used @@ -151,42 +140,27 @@ (unless (eq :declared (info :function :where-from name)) (clear-info :function :type name)))) -;;; Return the fdefn-fun of NAME's fdefinition including any encapsulations. -;;; LOOKUP-FN, defaulting to FIND-FDEFN, specifies how to lookup the fdefn. -;;; As a special case it can be given as SYMBOL-FDEFN which is slightly quicker. -;;; This is the core of the implementation of the standard FDEFINITION function, -;;; but as we've defined FDEFINITION, that strips encapsulations. -(defmacro %coerce-name-to-fun (name &optional (lookup-fn 'find-fdefn) - strictly-functionp) - ;; Whoa! We were getting a warning from the *host* here - - ;; "Abbreviated type declaration: (BOOLEAN SB-IMPL::STRICTLY-FUNCTIONP)." - ;; I guess it's because we hand it a lambda and it doesn't like our style? - (declare (type boolean strictly-functionp)) - `(let* ((name ,name) (fdefn (,lookup-fn name)) f) - (if (and fdefn - (setq f (fdefn-fun (truly-the fdefn fdefn))) - ;; If STRICTLY-FUNCTIONP is true, we make sure not to return an error - ;; trampoline. This extra check ensures that full calls such as - ;; (MAPCAR 'OR '()) signal an error that OR isn't a function. - ;; This accords with the non-requirement that macros store strictly - ;; a function in the symbol that names them. In many implementations, - ;; (FUNCTIONP (SYMBOL-FUNCTION 'OR)) => NIL. We want to pretend that. - ,@(if strictly-functionp '((not (macro/special-guard-fun-p f))))) - f - (retry-%coerce-name-to-fun name ,strictly-functionp)))) - -;;; If %COERCE-NAME-TO-FUN fails, continue here. -;;; LOOKUP-FN, being more about speed than semantics, is irrelevant. -;;; Once we're forced down the slow path, it doesn't matter whether the fdefn -;;; lookup considers generalized function names (which require a hash-table) -;;; versus optimizing for just symbols (by using SYMBOL-INFO). -;;; -;;; Furthermore we explicitly allow any function name when retrying, -;;; even if the erring caller was SYMBOL-FUNCTION. It is consistent -;;; that both #'(SETF MYNEWFUN) and '(SETF MYNEWFUN) are permitted -;;; as the object to use in the USE-VALUE restart. -(defun retry-%coerce-name-to-fun (name strictly-functionp) - (setq name (restart-case (error 'undefined-function :name name) +;;; Return the fdefn-fun of NAME's fdefinition including any +;;; encapsulations. This is the core of the implementation of the standard +;;; FDEFINITION function, but as we've defined FDEFINITION, that +;;; strips encapsulations. +(defun %coerce-name-to-fun (name) + (typecase name + ((and symbol (not null)) + (let ((fun (%symbol-function name))) + (when (and fun (not (macro/special-guard-fun-p fun))) + (return-from %coerce-name-to-fun fun)))) + (cons + (binding* ((fdefn (find-fdefn name) :exit-if-null) + (fun (fdefn-fun fdefn) :exit-if-null)) + (return-from %coerce-name-to-fun fun)))) + ;; We explicitly allow any function name when retrying, + ;; even if the erring caller was SYMBOL-FUNCTION. It is consistent + ;; that both #'(SETF MYNEWFUN) and '(SETF MYNEWFUN) are permitted + ;; as the object to use in the USE-VALUE restart. + (setq name (restart-case (if (legal-fun-name-p name) + (error 'undefined-function :name name) + (legal-fun-name-or-type-error name)) (continue () :report (lambda (stream) (format stream "Retry using ~s." name)) @@ -196,15 +170,9 @@ (format stream "Use specified function")) :interactive read-evaluated-form (if (functionp value) - (return-from retry-%coerce-name-to-fun value) + (return-from %coerce-name-to-fun value) value)))) - (let ((fdefn (find-fdefn name))) - (when fdefn - (let ((f (fdefn-fun (truly-the fdefn fdefn)))) - (when (and f (or (not strictly-functionp) - (not (macro/special-guard-fun-p f)))) - (return-from retry-%coerce-name-to-fun f))))) - (retry-%coerce-name-to-fun name strictly-functionp)) + (%coerce-name-to-fun name)) ;; Coerce CALLABLE (a function-designator) to a FUNCTION. ;; The compiler emits this when someone tries to FUNCALL something. @@ -218,13 +186,21 @@ ;; if a symbol does not satisfy FBOUNDP. (defun %coerce-callable-to-fun (callable) (declare (explicit-check)) - (etypecase callable - (function callable) - (symbol (%coerce-name-to-fun callable symbol-fdefn t)))) + (typecase callable + (function + (return-from %coerce-callable-to-fun callable)) + ((and symbol (not null)) ; NIL can't be fboundp. Quicker test this way. + (let ((fun (%symbol-function callable))) + (when (and fun (not (macro/special-guard-fun-p fun))) + (return-from %coerce-callable-to-fun fun)))) + ;; If NIL, it's not technically a type-error, so instead hit the error + ;; in %coerce-name-to-fun which has a restart. + (null) + (t (error 'type-error :expected-type '(or symbol function) :datum callable))) + (%coerce-name-to-fun callable)) ;;; Behaves just like %COERCE-CALLABLE-TO-FUN but has an ir2-convert optimizer. -(%defun '%coerce-callable-for-call - #'%coerce-callable-to-fun) +(setf (symbol-function '%coerce-callable-for-call) (symbol-function '%coerce-callable-to-fun)) ;;;; definition encapsulation @@ -365,14 +341,18 @@ encapsulations and to return the innermost encapsulated definition. This is SETF'able." (declare (explicit-check)) - (let ((fun (%coerce-name-to-fun name))) + ;; %COERCE-NAME-TO-FUN signals an error for macros and special operators, + ;; but FDEFINITION should not, so pick off symbols using %SYMBOL-FUNCTION. + (strip-encapsulation (or (and (symbolp name) (%symbol-function name)) + (%coerce-name-to-fun name)))) +(defun strip-encapsulation (fun) (loop (let ((encap-info (encapsulation-info fun))) (if encap-info (setf fun (encapsulation-info-definition encap-info)) - (return fun)))))) + (return fun))))) -(defvar *setf-fdefinition-hook* nil +(define-load-time-global *setf-fdefinition-hook* nil "A list of functions that (SETF FDEFINITION) invokes before storing the new value. The functions take the function name and the new value.") @@ -386,36 +366,31 @@ :format-control "~S is not acceptable to ~S." :format-arguments (list object setter)))) -(defun %set-fdefinition (name new-value) +(defun (setf fdefinition) (new-value name) "Set NAME's global function definition." (declare (type function new-value) (optimize (safety 1))) (declare (explicit-check)) (err-if-unacceptable-function new-value '(setf fdefinition)) + (setq new-value (strip-encapsulation new-value)) (with-single-package-locked-error (:symbol name "setting fdefinition of ~A") (maybe-clobber-ftype name new-value) ;; Check for hash-table stuff. Woe onto him that mixes encapsulation ;; with this. - (when (and (symbolp name) (fboundp name)) - (let ((old (symbol-function name))) + (when (symbolp name) + (let ((old (%symbol-function name))) (dolist (spec *user-hash-table-tests*) - (cond ((eq old (second spec)) - ;; test-function - (setf (second spec) new-value)) - ((eq old (third spec)) - ;; hash-function - (setf (third spec) new-value)))))) + (cond ((eq old (second spec)) + ;; test-function + (setf (second spec) new-value)) + ((eq old (third spec)) + ;; hash-function + (setf (third spec) new-value)))))) - ;; FIXME: This is a good hook to have, but we should probably - ;; reserve it for users. (let ((fdefn (find-or-create-fdefn name))) - ;; *SETF-FDEFINITION-HOOK* won't be bound when initially running - ;; top level forms in the kernel core startup. - (when (boundp '*setf-fdefinition-hook*) - (dolist (f *setf-fdefinition-hook*) - (declare (type function f)) - (funcall f name new-value))) - + (dolist (f *setf-fdefinition-hook*) + (declare (type function f)) + (funcall f name new-value)) (let ((encap-info (encapsulation-info (fdefn-fun fdefn)))) (cond (encap-info (loop @@ -424,9 +399,8 @@ (encapsulation-info-definition encap-info)))) (if more-info (setf encap-info more-info) - (return - (setf (encapsulation-info-definition encap-info) - new-value)))))) + (return (setf (encapsulation-info-definition encap-info) + new-value)))))) (t (setf (fdefn-fun fdefn) new-value))))))) @@ -435,8 +409,7 @@ (defun fboundp (name) "Return true if name has a global function definition." (declare (explicit-check)) - (let ((fdefn (find-fdefn name))) - (and fdefn (fdefn-fun fdefn) t))) + (awhen (find-fdefn name) (fdefn-fun it))) (defun fmakunbound (name) "Make NAME have no global function definition." @@ -463,8 +436,8 @@ ;;; https://fgiesen.wordpress.com/2015/02/22/triangular-numbers-mod-2n/ ;;; contains a proof that triangular numbers mod 2^N visit every cell. -;;; The intent here - which may be impossible to realize - was to allow GC -;;; methods whose name is not reachable. I couldn't get it to do the right thing. +;;; The intent here - which may be impossible to realize - was to allow garbage-collection +;;; of FDEFNs whose name is not reachable. I couldn't get it to do the right thing. ;;; e.g. (defmethod foo (x (y cons)) ...) creates mappings: ;;; (SB-PCL::FAST-METHOD FOO (T CONS)) -> #<SB-KERNEL:FDEFN (SB-PCL::FAST-METHOD FOO (T CONS))> ;;; (SB-PCL::SLOW-METHOD FOO (T CONS)) -> #<SB-KERNEL:FDEFN (SB-PCL::SLOW-METHOD FOO (T CONS))> @@ -509,7 +482,7 @@ (or (let ((result (lookup (car *fdefns*)))) (when (fdefn-p result) result)) (when constructor ; double-check w/lock before inserting - (sb-thread::with-system-mutex (*fdefns-lock*) + (with-system-mutex (*fdefns-lock*) (let* ((fdefns *fdefns*) (vector (car fdefns)) (result (lookup vector))) diff --git a/src/code/filesys.lisp b/src/code/filesys.lisp index 692b4609ae..a405a32cb9 100644 --- a/src/code/filesys.lisp +++ b/src/code/filesys.lisp @@ -266,20 +266,25 @@ :newest))))) -;;;; Grabbing the kind of file when we have a namestring. -(defun native-file-kind (namestring) +;;;; Grabbing the kind of file when we have a native-namestring. +(defun native-file-kind (namestring &optional resolve-symlinks) + #+win32 (declare (ignore resolve-symlinks)) + #+win32 (nth-value 1 (sb-win32::native-probe-file-name namestring)) + #-win32 (multiple-value-bind (existsp errno ino mode) - #-win32 - (sb-unix:unix-lstat namestring) - #+win32 - (sb-unix:unix-stat namestring) + ;; Note that when resolve-symlinks is true, we'll return NIL if + ;; there are circular and dangling symlinks anywhere in the + ;; path. That's different than what our TRUENAME does; this is + ;; intended as an efficient internal routine. + (if resolve-symlinks + (sb-unix:unix-stat namestring) + (sb-unix:unix-lstat namestring)) (declare (ignore errno ino)) (when existsp (let ((ifmt (logand mode sb-unix:s-ifmt))) (case ifmt (#.sb-unix:s-ifreg :file) (#.sb-unix:s-ifdir :directory) - #-win32 (#.sb-unix:s-iflnk :symlink) (t :special)))))) @@ -360,13 +365,13 @@ :as-directory (eq :directory kind)))) (errorp (file-perror filename (sb-win32:get-last-error) - "Failed to find the ~a of ~A" query-for filename))))) + "Failed to find the ~A of ~S" query-for filename))))) (:write-date (cond ((sb-win32::native-file-write-date filename)) (errorp (file-perror filename (sb-win32:get-last-error) - "Failed to find the ~a of ~A" query-for filename))))))) + "Failed to find the ~A of ~S" query-for filename))))))) #-win32 (defun %query-file-system (pathname query-for errorp) @@ -404,7 +409,7 @@ (realpath (parse realpath :as-directory t)) (errorp - (file-perror filename errno "couldn't resolve ~A"))))) + (file-perror filename errno "Couldn't resolve ~S" filename))))) (resolve-problematic-symlink (filename errno realpath-failed) ;; SBCL has for many years had a policy that a pathname ;; that names an existing, dangling or self-referential @@ -442,7 +447,8 @@ ;; The file doesn't exist; maybe error. (errorp (file-perror - pathname errno "Failed to find the ~A of ~A" query-for pathname)))))) + pathname errno + "Failed to find the ~A of ~A" query-for pathname)))))) (binding* ((filename (native-namestring pathname :as-file t)) ((existsp errno nil mode nil uid nil nil nil nil mtime) (sb-unix:unix-stat filename))) @@ -543,9 +549,7 @@ per standard Unix unlink() behaviour." (values nil (sb-win32:get-last-error))) (unless res (with-simple-restart (continue "Return T") - (file-perror namestring err 'delete-file-error - :format-control "Couldn't delete ~A" - :format-arguments (list namestring)))))) + (file-perror namestring err 'delete-file-error))))) t) (defun directorize-pathname (pathname) @@ -619,9 +623,8 @@ exist or if is a file or a symbolic link." (get-errno)) (if res dir - (file-perror - namestring errno - "Could not delete directory ~A" namestring)))))) + (file-perror namestring errno + "Could not delete directory ~S" namestring)))))) (let ((physical (directorize-pathname (physicalize-pathname (merge-pathnames @@ -1242,6 +1245,15 @@ Experimental: interface subject to change." (null (pathname-name pathname)) (null (pathname-type pathname)))) +;; FIXME: repeatedly poking at the file system ought to be +;; unnecessary, and walking the directory hierarchy from the top down +;; is probably a waste of effort in most cases. If we can trust mkdir +;; returning ENOENT and EEXIST always and only where it's supposed to, +;; we could get this down to two syscalls in the optimal success case +;; case, one in the pessimal failure case, and no worse than this in a +;; hypothetical average. (It looks like we inherited this approach +;; from CMUCL; maybe some ancient Unix's mkdir errno values weren't +;; reliable?) (defun ensure-directories-exist (pathspec &key verbose (mode #o777)) "Test whether the directories containing the specified file actually exist, and attempt to create them if they do not. @@ -1251,37 +1263,37 @@ Experimental: interface subject to change." (created-p nil)) (when (wild-pathname-p pathname) (sb-kernel::%file-error pathspec "bad place for a wild pathname")) - (let* ((dir (pathname-directory pathname)) - (*default-pathname-defaults* - (make-pathname :directory dir :device (pathname-device pathname))) - (dev (pathname-device pathname))) + (let* ((host (pathname-host pathname)) + (dir (pathname-directory pathname)) + (dev (pathname-device pathname))) (loop for i from (case dev (:unc 3) (otherwise 2)) upto (length dir) do (let* ((newpath (make-pathname - :host (pathname-host pathname) + :host host :device dev :directory (subseq dir 0 i))) - (probed (probe-file newpath))) - (unless (directory-pathname-p probed) - (let ((namestring (coerce (native-namestring newpath) - 'string))) - (when verbose - (format *standard-output* - "~&creating directory: ~A~%" - namestring)) - (sb-unix:unix-mkdir namestring mode) - (unless (directory-pathname-p (probe-file newpath)) + (namestring (coerce (native-namestring newpath :as-file t) + 'string)) + (kind (native-file-kind namestring t))) + (unless (eq :directory kind) + (when verbose + (format *standard-output* + "~&creating directory: ~A~%" + namestring)) + (sb-unix:unix-mkdir namestring mode) + (let ((newkind (native-file-kind namestring t))) + (unless (eq :directory newkind) (restart-case (sb-kernel::%file-error pathspec "Can't create directory ~A~:[~;,~%a file with ~ the same name already exists.~]" namestring - (and probed (not (directory-pathname-p probed)))) + (and kind (not (eq :directory newkind)))) (retry () :report "Retry directory creation." (ensure-directories-exist - pathspec :verbose verbose :mode mode)))) - (setf created-p t))))) + pathspec :verbose verbose :mode mode))))) + (setf created-p t)))) (values pathspec created-p)))) diff --git a/src/code/final.lisp b/src/code/final.lisp index 2046d46e34..efc65132dd 100644 --- a/src/code/final.lisp +++ b/src/code/final.lisp @@ -12,24 +12,22 @@ (in-package "SB-IMPL") (defmacro with-finalizer-store ((var) &body body) - `(let ((mutex (hash-table-lock (finalizer-id-map **finalizer-store**)))) - ;; This does not inhibit GC, though the hashtable operations will, - ;; as is (currently) required for tables with non-null weakness. - (sb-thread::with-recursive-system-lock (mutex) - ;; Grab the store again inside the lock in case the array was enlarged - ;; after we referenced the mutex but before we acquired it. - (let ((,var **finalizer-store**)) - ,@body)))) + `(with-system-mutex ((hash-table-lock (finalizer-id-map **finalizer-store**))) + ;; Grab the global var inside the lock in case the array was enlarged + ;; after we referenced the mutex but before we acquired it. + ;; It's OK to reference the FINALIZER-ID-MAP because that is always + ;; in element 1 of the array regardless of what happens to the array. + (let ((,var **finalizer-store**)) + ,@body))) (defmacro finalizer-recycle-bin (store) `(cdr (elt ,store 0))) (defmacro finalizer-id-map (store) `(elt ,store 1)) (defmacro finalizer-max-id (store) `(elt ,store 2)) (defun make-finalizer-store (array-length) - (let* ((v (make-array (the index array-length))) - (ht (make-hash-table :test 'eq :weakness :key))) - (setf (%instance-ref ht (get-dsd-index hash-table flags)) - (logior (hash-table-flags ht) hash-table-finalizer-flag)) + (let* ((v (make-array (the index array-length) :initial-element 0)) + (ht (make-system-hash-table :test 'eq :weakness :key :synchronized nil + :finalizer t))) ;; The recycle bin has a dummy item in front so that the simple-vector ;; is growable without messing up RUN-PENDING-FINALIZERS when it atomically ;; pushes items into the recycle bin - it is unaffected by looking at @@ -45,7 +43,8 @@ (declaim (simple-vector **finalizer-store**)) (defun finalize (object function &key dont-save - &aux (item (if dont-save (list function) function))) + &aux (function (%coerce-callable-to-fun function)) + (item (if dont-save (list function) function))) "Arrange for the designated FUNCTION to be called when there are no more references to OBJECT, including references in FUNCTION itself. @@ -160,7 +159,9 @@ Examples: ;; finalizers can in practice almost never be run, as pseudo-static objects ;; don't die, making this more-or-less an exercise in futility. (with-finalizer-store (old-store) - (without-gcing + ;; This doesn't need WITHOUT-GCING. MAPHASH will never present its funarg + ;; with a culled entry. GC during the MAPHASH could remove some items + ;; before we get to them, and that's fantastic. (let ((new-store (make-finalizer-store (max (1+ (finalizer-max-id old-store)) +finalizers-initial-size+))) @@ -183,7 +184,7 @@ Examples: old-objects) (clrhash old-objects) (fill old-store 0) - (setq **finalizer-store** new-store))))) + (setq **finalizer-store** new-store)))) ;;; Replace the finalizer store with a copy. Tenured (gen6 = pseudo-static) ;;; vectors are problematic in many ways for gencgc, unless immutable. @@ -233,18 +234,34 @@ Examples: object)) ;;; Drain the queue of finalizers and return when empty. -;;; Concurrent invocations of this function are ok. -(defun scan-finalizers () +;;; Concurrent invocations of this function in different threads are ok. +;;; Nested invocations (from a GC forced by a finalizer) are not ok. +;;; See the trace at the bottom of this file. +(defvar *in-a-finalizer* nil) +#+sb-thread (define-alien-variable finalizer-thread-runflag int) + +(defun run-pending-finalizers (&aux (hashtable (finalizer-id-map **finalizer-store**)) + (ran-a-system-finalizer) + (system-finalizer-scratchpad (list 0)) + (ran-a-user-finalizer)) + (declare (truly-dynamic-extent system-finalizer-scratchpad)) ;; This never acquires the finalizer store lock. Code accordingly. - (let ((hashtable (finalizer-id-map **finalizer-store**))) - (loop - (let ((cell (hash-table-culled-values hashtable))) - ;; This is like atomic-pop, but its obtains the first cons cell - ;; in the list, not the car of the first cons. - (loop (unless cell (return-from scan-finalizers)) - (let ((actual (cas (hash-table-culled-values hashtable) - cell (cdr cell)))) - (if (eq actual cell) (return) (setq cell actual)))) + (loop + ;; Perform no further work if trying to stop the thread, even if there is work. + #+sb-thread (when (zerop finalizer-thread-runflag) (return)) + ;; Try to run 1 system finalizer + (setq ran-a-system-finalizer (sb-vm::immobile-code-dealloc-1 system-finalizer-scratchpad)) + ;; Try to run 1 user finalizer + (let ((cell (hash-table-culled-values hashtable))) + ;; This is like atomic-pop, but its obtains the first cons cell + ;; in the list, not the car of the first cons. + ;; Possible TODO: when no other work remains, free the *JOINABLE-THREADS*, + ;; though MAKE-THREAD and JOIN-THREAD do that also, so there's no memory leak. + (loop (unless cell (return)) + (let ((actual (cas (hash-table-culled-values hashtable) + cell (cdr cell)))) + (if (eq actual cell) (return) (setq cell actual)))) + (when cell (let* ((id (the index (car cell))) ;; No other thread can modify **FINALIZER-STORE** at index ID ;; because the table no longer contains an object mapping to @@ -252,7 +269,7 @@ Examples: ;; so always load the vector again before dereferencing. (store **finalizer-store**) ;; I don't think we need a barrier; this has a data dependency - ;; on (CAR CELL) and STORE. (Alpha with threads, anyone?) + ;; on (CAR CELL) and STORE. (finalizers (svref store id))) ; [1] load (setf (svref store id) 0) ; [2] store ;; The ID can be reused right away. Link it into the recycle list, @@ -265,12 +282,13 @@ Examples: ;; Now call the function(s) (flet ((call (finalizer) (let ((fun (if (consp finalizer) (car finalizer) finalizer))) - (handler-case (funcall fun) + (handler-case (let ((*in-a-finalizer* t)) (funcall fun)) (error (c) (warn "Error calling finalizer ~S:~% ~S" fun c)))))) (if (simple-vector-p finalizers) (map nil #'call finalizers) (call finalizers))) + (setq ran-a-user-finalizer t) ;; While the assignment to (SVREF STORE ID) should have been adequate, ;; we don't know that the vector is current - a new vector could have ;; gotten assigned into **FINALIZER-STORE** in between [1] and [2], @@ -288,85 +306,193 @@ Examples: ;; removing dangling references, but if it's just a function, ;; there's nothing to smash. (cond ((simple-vector-p finalizers) (fill finalizers 0)) - ((consp finalizers) (rplaca finalizers 0)))))))) + ((consp finalizers) (rplaca finalizers 0)))))) + ;; Did this iteration do anything at all? + (unless (or ran-a-system-finalizer ran-a-user-finalizer) (return)) + (setq ran-a-system-finalizer nil + ran-a-user-finalizer nil))) +(define-load-time-global *finalizer-thread* nil) +(declaim (type (or sb-thread:thread (eql :start) null) *finalizer-thread*)) #+sb-thread (progn - ;; *FINALIZER-THREAD* is either a boolean value indicating whether to start a - ;; thread, or a thread object (which is created no sooner than needed). - ;; Saving a core sets the flag to NIL so that finalizers which execute - ;; between stopping the thread and writing to disk will be synchronous. - ;; Restarting a saved core resets the flag to T. - (define-load-time-global *finalizer-thread* t) - (declaim (type (or sb-thread:thread boolean) *finalizer-thread*)) - (define-load-time-global *finalizer-queue-lock* - (sb-thread:make-mutex :name "finalizer")) - (define-load-time-global *finalizer-queue* - (sb-thread:make-waitqueue :name "finalizer"))) +(defun finalizer-thread-notify () + (alien-funcall (extern-alien "finalizer_thread_wake" (function void))) + nil) -(defun run-pending-finalizers () - (when (hash-table-culled-values (finalizer-id-map **finalizer-store**)) - (cond #+sb-thread - ((%instancep *finalizer-thread*) - (sb-thread::with-system-mutex (*finalizer-queue-lock*) - (sb-thread:condition-notify *finalizer-queue*))) - #+sb-thread - ((eq *finalizer-thread* t) ; Create a new thread - (sb-thread::make-ephemeral-thread +;;; The following operations are synchronized by *MAKE-THREAD-LOCK* - +;;; FINALIZER-THREAD-{START,STOP}, S-L-A-D, SB-POSIX:FORK +(defun finalizer-thread-start () + (with-system-mutex (sb-thread::*make-thread-lock*) + #+(and unix sb-safepoint) + (sb-thread::make-system-thread "sigwait" + #'sb-unix::signal-handler-loop + nil 'sb-unix::*sighandler-thread*) + (aver (not *finalizer-thread*)) + (setf finalizer-thread-runflag 1) + (setq *finalizer-thread* :start) + (let ((thread + (sb-thread::make-system-thread "finalizer" (lambda () - ;; If we already called FINALIZER-THREAD-STOP, then - ;; *FINALIZER-THREAD* is NIL, and this WHEN test is false. - (when (eq t (cas *finalizer-thread* t - sb-thread:*current-thread*)) - ;; Don't enter the loop if this thread lost the - ;; competition to become a finalizer thread. - (loop - (scan-finalizers) - ;; Wait for a notification - (sb-thread::with-system-mutex (*finalizer-queue-lock*) - ;; Don't go to sleep if *FINALIZER-THREAD* became NIL - (unless *finalizer-thread* - (return)) - ;; The return value of CONDITION-WAIT is irrelevant - ;; since it is always legal to call SCAN-FINALIZERS - ;; even when it has nothing to do. - ;; Spurious wakeup is of no concern to us here. - (sb-thread:condition-wait - *finalizer-queue* *finalizer-queue-lock*))))) - nil)) - (t - (scan-finalizers))))) + (setf *finalizer-thread* sb-thread:*current-thread*) + (loop (run-pending-finalizers) + (alien-funcall (extern-alien "finalizer_thread_wait" (function void))) + (when (zerop finalizer-thread-runflag) (return))) + (setq *finalizer-thread* nil)) + nil nil))) + ;; Don't return from this function until *FINALIZER-THREAD* has a good value, + ;; but don't set it to a thread if the thread was not created, or exited already. + (cas *finalizer-thread* :start thread)))) -;;; If a finalizer thread was started, stop it and wait for it to finish. -;;; Make no attempt to drain the queue of pending finalizers. -;;; (When called from EXIT, the user must invoke a final GC if there is -;;; an expectation that GC-based things run. Similarly when saving a core) +;;; You should almost always invoke this with *MAKE-THREAD-LOCK* held. +;;; Some tests violate that, but they know what they're doing. (defun finalizer-thread-stop () - #+sb-thread + #+(and unix sb-safepoint) + (let ((thread sb-unix::*sighandler-thread*)) + (aver (sb-thread::thread-p thread)) + (setq sb-unix::*sighandler-thread* nil) + ;; This kill causes the thread's sigwait() syscall to return normally + ;; and then not invoke any handler. + (sb-unix:pthread-kill (sb-thread::thread-os-thread thread) sb-unix:sigterm) + (sb-thread:join-thread thread)) (let ((thread *finalizer-thread*)) - ;; valid state transitions: - ;; T to a #<thread> - ;; #<thread> to NIL - ;; T to NIL - ;; If it was NIL, it is latched at that state, so we can ignore it. - (when (null thread) - (return-from finalizer-thread-stop)) - (let ((oldval (cas *finalizer-thread* thread nil))) - ;; If GC had started the thread, and it got to its main body only after - ;; we observed *FINALIZER-THREAD* = T, then we could see a transition - ;; from T to #<thread> now. That is unlikely, but we must try once - ;; again to CAS the value to NIL. - (unless (eq oldval thread) - (setq thread oldval) - ;; Also, we could be racing with someone else trying to stop the - ;; thread, so we could see T | #<thread> -> NIL. - (when (null thread) - (return-from finalizer-thread-stop)) - (aver (eq (cas *finalizer-thread* thread nil) thread)))) - (when (%instancep thread) - ;; The finalizer thread will exit when we wake it up - ;; and it sees that *FINALIZER-THREAD* is NIL. - (sb-thread::with-system-mutex (*finalizer-queue-lock*) - (sb-thread:condition-notify *finalizer-queue*)) - (sb-thread:join-thread thread)))) ; wait for it + (aver (sb-thread::thread-p thread)) + (alien-funcall (extern-alien "finalizer_thread_stop" (function void))) + (sb-thread:join-thread thread))) +) + +#| +;;; This is a display produced by annotating parts of gc-common.c and +;;; interrupt.c with each thread's output in its own column. +;;; The main thread is on the right. + +;;; This output shows that if the finalizer thread calls a function that +;;; triggers a GC, the interrupt nesting depth can grow without limit. +;;; The finalizer thread does not have to be a memory hog - it just has +;;; to be unlucky enough to be the thread that triggers the collection. +;;; _Any_ thread can bring the GC trigger up to the threshold, +;;; and as long as the finalizer thread is the one to cross the +;;; the threshold, it is tasked with triggering the next scan +;;; of finalizers, but it MUST NOT do so recursively. +;;; +;;; The same thing can happen without using a finalizer thread, +;;; but it's actually easier to understand the output this way. + +Thread 2 Main +-------- -------- +| Enter SB-EXT:GC 0 +| Stopping world +| Stopped world +| SUB-GC calling gc(0) +| set auto_gc_trig=4858833 +| completed GC +| Restarted world +| SB-EXT:GC calling POST-GC +| ENTER run-pending-finalizers +| Enter SB-EXT:GC 0 +| Stopping world +| Stopped world +| SUB-GC calling gc(6) +| set auto_gc_trig=5075473 +| completed GC +| Restarted world +| SB-EXT:GC calling POST-GC +| ENTER run-pending-finalizers +| Trying to start finalizer thread +| starting +| Enter SB-EXT:GC 0 +| Stopping world +| Caught SIGUSR2, pc=52a946bd +| STOP_FOR_GC PA=1 inh=N sigmask=0 +| Caught SIGILL, pc=52a946cc code 0x9 +| evt 1 >handle_pending +| STOP_FOR_GC PA=0 inh=N sigmask=0 +| fake ffcall "stop_for_gc" +| bind(free_ICI, 1) +| Stopped world +| SUB-GC calling gc(6) +| set auto_gc_trig=520eeb3 +| completed GC +| Restarted world +| SB-EXT:GC calling POST-GC +| ENTER run-pending-finalizers +| Notify finalizer thread +| unbind free_ICI -> 0 +| leave STOP_FOR_GC +| evt 1 <handle_pending +| gc_trig=52bcf80, setting PA-int +| Caught SIGILL, pc=52a946cc code 0x9 +| evt 2 >handle_pending +| ENTER maybe_gc (pc was 52a946ce) +| fake ffcall "maybe_gc" +| bind(free_ICI, 1) +| maybe_gc calling SUB-GC +| Stopping world +| Caught SIGUSR2, pc=7ff010deef47 +| STOP_FOR_GC PA=0 inh=N sigmask=0 +| fake ffcall "stop_for_gc" +| bind(free_ICI, 1) +| Stopped world +| SUB-GC calling gc(0) +| set auto_gc_trig=552b033 +| completed GC +| Restarted world +| maybe_gc calling POST-GC +| ENTER run-pending-finalizers +| unbind free_ICI -> 0 +| leave STOP_FOR_GC +| gc_trig=55d9110, setting PA-int +| Caught SIGILL, pc=52a946cc code 0x9 +| evt 3 >handle_pending +| ENTER maybe_gc (pc was 52a946ce) +| fake ffcall "maybe_gc" +| bind(free_ICI, 2) +| maybe_gc calling SUB-GC +| Stopping world +| Caught SIGUSR2, pc=7ff010deef47 +| STOP_FOR_GC PA=0 inh=N sigmask=0 +| fake ffcall "stop_for_gc" +| bind(free_ICI, 1) +| Stopped world +| SUB-GC calling gc(0) +| set auto_gc_trig=56c0423 +| completed GC +| Restarted world +| maybe_gc calling POST-GC +| ENTER run-pending-finalizers +| unbind free_ICI -> 0 +| leave STOP_FOR_GC +| gc_trig=576e500, setting PA-int +| Caught SIGILL, pc=52a946cc code 0x9 +| evt 4 >handle_pending +| ENTER maybe_gc (pc was 52a946ce) +| fake ffcall "maybe_gc" +| bind(free_ICI, 3) +| maybe_gc calling SUB-GC +| Stopping world +| Caught SIGUSR2, pc=7ff010deef47 +| STOP_FOR_GC PA=0 inh=N sigmask=0 +| fake ffcall "stop_for_gc" +| bind(free_ICI, 1) +| Stopped world +| SUB-GC calling gc(0) +| set auto_gc_trig=59dc213 +| completed GC +| Restarted world +| maybe_gc calling POST-GC +| ENTER run-pending-finalizers +| unbind free_ICI -> 0 +| leave STOP_FOR_GC +| gc_trig=5a8a2f0, setting PA-int +| Caught SIGILL, pc=52a946cc code 0x9 +| evt 5 >handle_pending +| ENTER maybe_gc (pc was 52a946ce) +| fake ffcall "maybe_gc" +| bind(free_ICI, 4) +| maybe_gc calling SUB-GC +| Stopping world +| +;;; This pattern of binding FREE_INTERRUPT_CONTEXT_INDEX to successively +;;; higher values will continue forever until reaching the limit and crashing. +|# diff --git a/src/code/float-inf-nan.lisp b/src/code/float-inf-nan.lisp new file mode 100644 index 0000000000..1d594b4ef4 --- /dev/null +++ b/src/code/float-inf-nan.lisp @@ -0,0 +1,144 @@ +;;;; This file contains the definitions of float-specific number +;;;; support (other than irrational stuff, which is in irrat.) There is +;;;; code in here that assumes there are only two float formats: IEEE +;;;; single and double. (LONG-FLOAT support has been added, but bugs +;;;; may still remain due to old code which assumes this dichotomy.) + +;;;; This software is part of the SBCL system. See the README file for +;;;; more information. +;;;; +;;;; This software is derived from the CMU CL system, which was +;;;; written at Carnegie Mellon University and released into the +;;;; public domain. The software is in the public domain and is +;;;; provided with absolutely no warranty. See the COPYING and CREDITS +;;;; files for more information. + +(in-package "SB-KERNEL") + +(declaim (maybe-inline float-denormalized-p float-infinity-p float-nan-p + float-trapping-nan-p)) + +(defmacro sfloat-bits-subnormalp (bits) + `(zerop (ldb sb-vm:single-float-exponent-byte ,bits))) +#-64-bit +(defmacro dfloat-high-bits-subnormalp (bits) + `(zerop (ldb sb-vm:double-float-exponent-byte ,bits))) +#+64-bit +(progn +(defmacro dfloat-exponent-from-bits (bits) + `(ldb (byte ,(byte-size sb-vm:double-float-exponent-byte) + ,(+ 32 (byte-position sb-vm:double-float-exponent-byte))) + ,bits)) +(defmacro dfloat-bits-subnormalp (bits) + `(zerop (dfloat-exponent-from-bits ,bits)))) + +(defun float-denormalized-p (x) + "Return true if the float X is denormalized." + (declare (explicit-check)) + (number-dispatch ((x float)) + ((single-float) + #+64-bit + (let ((bits (single-float-bits x))) + (and (ldb-test (byte 31 0) bits) ; is nonzero (disregard the sign bit) + (sfloat-bits-subnormalp bits))) + #-64-bit + (and (zerop (ldb sb-vm:single-float-exponent-byte (single-float-bits x))) + (not (zerop x)))) + ((double-float) + #+64-bit + (let ((bits (double-float-bits x))) + ;; is nonzero after shifting out the sign bit + (and (not (zerop (logand (ash bits 1) most-positive-word))) + (dfloat-bits-subnormalp bits))) + #-64-bit + (and (zerop (ldb sb-vm:double-float-exponent-byte + (double-float-high-bits x))) + (not (zerop x)))) + #+(and long-float x86) + ((long-float) + (and (zerop (ldb sb-vm:long-float-exponent-byte (long-float-exp-bits x))) + (not (zerop x)))))) + +(defmacro define-float-inf-or-nan-test + (name doc single double #+(and long-float x86) long) + `(defun ,name (x) ,doc + (number-dispatch ((x float)) + ((single-float) + (let ((bits (single-float-bits x))) + (and (> (ldb sb-vm:single-float-exponent-byte bits) + sb-vm:single-float-normal-exponent-max) + ,single))) + ((double-float) + #+64-bit + ;; With 64-bit words, all the FOO-float-byte constants need to be reworked + ;; to refer to a byte position in the whole word. I think we can reasonably + ;; get away with writing the well-known values here. + (let ((bits (double-float-bits x))) + (and (> (ldb (byte 11 52) bits) sb-vm:double-float-normal-exponent-max) + ,double)) + #-64-bit + (let ((hi (double-float-high-bits x)) + (lo (double-float-low-bits x))) + (declare (ignorable lo)) + (and (> (ldb sb-vm:double-float-exponent-byte hi) + sb-vm:double-float-normal-exponent-max) + ,double))) + #+(and long-float x86) + ((long-float) + (let ((exp (long-float-exp-bits x)) + (hi (long-float-high-bits x)) + (lo (long-float-low-bits x))) + (declare (ignorable lo)) + (and (> (ldb sb-vm:long-float-exponent-byte exp) + sb-vm:long-float-normal-exponent-max) + ,long)))))) + +;; Infinities and NANs have the maximum exponent +(define-float-inf-or-nan-test float-infinity-or-nan-p nil + t t #+(and long-float x86) t) + +;; Infinity has 0 for the significand +(define-float-inf-or-nan-test float-infinity-p + "Return true if the float X is an infinity (+ or -)." + (zerop (ldb sb-vm:single-float-significand-byte bits)) + + #+64-bit (zerop (ldb (byte 52 0) bits)) + #-64-bit (zerop (logior (ldb sb-vm:double-float-significand-byte hi) lo)) + + #+(and long-float x86) + (and (zerop (ldb sb-vm:long-float-significand-byte hi)) + (zerop lo))) + +;; NaNs have nonzero for the significand +(define-float-inf-or-nan-test float-nan-p + "Return true if the float X is a NaN (Not a Number)." + (not (zerop (ldb sb-vm:single-float-significand-byte bits))) + + #+64-bit (not (zerop (ldb (byte 52 0) bits))) + #-64-bit (not (zerop (logior (ldb sb-vm:double-float-significand-byte hi) lo))) + + #+(and long-float x86) + (or (not (zerop (ldb sb-vm:long-float-significand-byte hi))) + (not (zerop lo)))) + +(define-float-inf-or-nan-test float-trapping-nan-p + "Return true if the float X is a trapping NaN (Not a Number)." + ;; MIPS has trapping NaNs (SNaNs) with the trapping-nan-bit SET. + ;; All the others have trapping NaNs (SNaNs) with the + ;; trapping-nan-bit CLEAR. Note that the given implementation + ;; considers infinities to be FLOAT-TRAPPING-NAN-P on most + ;; architectures. + + ;; SINGLE-FLOAT + #+mips (logbitp 22 bits) + #-mips (not (logbitp 22 bits)) + + ;; DOUBLE-FLOAT + #+mips (logbitp 19 hi) + #+(and (not mips) 64-bit) (not (logbitp 51 bits)) + #+(and (not mips) (not 64-bit)) (not (logbitp 19 hi)) + + ;; LONG-FLOAT (this code is dead anyway) + #+(and long-float x86) + (zerop (logand (ldb sb-vm:long-float-significand-byte hi) + (ash 1 30)))) diff --git a/src/code/float-trap.lisp b/src/code/float-trap.lisp index 8c111f67d2..ec78d49030 100644 --- a/src/code/float-trap.lisp +++ b/src/code/float-trap.lisp @@ -48,10 +48,10 @@ names))) ) ; EVAL-WHEN -;;; interpreter stubs for floating point modes get/setters for the -;;; alpha have been removed to alpha-vm.lisp, as they are implemented -;;; in C rather than as VOPs. Likewise for x86-64 and mips. -#-(or alpha x86-64 mips) +;;; interpreter stubs for floating point modes get/setters for +;;; some architectures have been removed, as they are implemented +;;; in C rather than as VOPs. +#-(or x86-64 mips) (progn (defun floating-point-modes () (floating-point-modes)) @@ -119,8 +119,6 @@ in effect." (setf (ldb float-precision-control modes) (or (cdr (assoc precision +precision-mode-alist+)) (error "unknown precision mode: ~S" precision)))) - ;; FIXME: This apparently doesn't work on Darwin - #-(and darwin ppc) (setf (floating-point-modes) modes)) (values)) @@ -159,7 +157,7 @@ sets the floating point modes to their current values (and thus is a no-op)." ;;; LEAST-NEGATIVE-SINGLE-FLOAT, so the :UNDERFLOW exceptions are ;;; disabled by default. Joe User can explicitly enable them if ;;; desired. -(defvar *saved-floating-point-modes* +(define-load-time-global *saved-floating-point-modes* '(:traps (:overflow #-(or netbsd ppc) :invalid :divide-by-zero) :rounding-mode :nearest :current-exceptions nil :accrued-exceptions nil :fast-mode nil @@ -201,8 +199,7 @@ sets the floating point modes to their current values (and thus is a no-op)." (with-interrupts ;; Reset the accumulated exceptions, may be needed on other ;; platforms too, at least Linux doesn't seem to require it. - #+(or sunos (and hppa linux)) - (setf (ldb sb-vm:float-sticky-bits (floating-point-modes)) 0) + #+sunos (setf (ldb sb-vm:float-sticky-bits (floating-point-modes)) 0) (error (or (cdr (assoc code +sigfpe-code-error-alist+)) 'floating-point-exception) :operation op diff --git a/src/code/float.lisp b/src/code/float.lisp index a6cffd81ae..2e76e8811c 100644 --- a/src/code/float.lisp +++ b/src/code/float.lisp @@ -17,138 +17,35 @@ ;;;; float predicates and environment query -#-sb-fluid -(declaim (maybe-inline float-denormalized-p float-infinity-p float-nan-p - float-trapping-nan-p)) - -(defun float-denormalized-p (x) - "Return true if the float X is denormalized." - (number-dispatch ((x float)) - ((single-float) - (and (zerop (ldb sb-vm:single-float-exponent-byte (single-float-bits x))) - (not (zerop x)))) - ((double-float) - (and (zerop (ldb sb-vm:double-float-exponent-byte - (double-float-high-bits x))) - (not (zerop x)))) - #+(and long-float x86) - ((long-float) - (and (zerop (ldb sb-vm:long-float-exponent-byte (long-float-exp-bits x))) - (not (zerop x)))))) - -(defmacro define-float-inf-or-nan-test - (name doc single double #+(and long-float x86) long) - `(defun ,name (x) ,doc - (number-dispatch ((x float)) - ((single-float) - (let ((bits (single-float-bits x))) - (and (> (ldb sb-vm:single-float-exponent-byte bits) - sb-vm:single-float-normal-exponent-max) - ,single))) - ((double-float) - #+64-bit - ;; With 64-bit words, all the FOO-float-byte constants need to be reworked - ;; to refer to a byte position in the whole word. I think we can reasonably - ;; get away with writing the well-known values here. - (let ((bits (double-float-bits x))) - (and (> (ldb (byte 11 52) bits) sb-vm:double-float-normal-exponent-max) - ,double)) - #-64-bit - (let ((hi (double-float-high-bits x)) - (lo (double-float-low-bits x))) - (declare (ignorable lo)) - (and (> (ldb sb-vm:double-float-exponent-byte hi) - sb-vm:double-float-normal-exponent-max) - ,double))) - #+(and long-float x86) - ((long-float) - (let ((exp (long-float-exp-bits x)) - (hi (long-float-high-bits x)) - (lo (long-float-low-bits x))) - (declare (ignorable lo)) - (and (> (ldb sb-vm:long-float-exponent-byte exp) - sb-vm:long-float-normal-exponent-max) - ,long)))))) - -;; Infinities and NANs have the maximum exponent -(define-float-inf-or-nan-test float-infinity-or-nan-p nil - t t #+(and long-float x86) t) - -;; Infinity has 0 for the significand -(define-float-inf-or-nan-test float-infinity-p - "Return true if the float X is an infinity (+ or -)." - (zerop (ldb sb-vm:single-float-significand-byte bits)) - - #+64-bit (zerop (ldb (byte 52 0) bits)) - #-64-bit (zerop (logior (ldb sb-vm:double-float-significand-byte hi) lo)) - - #+(and long-float x86) - (and (zerop (ldb sb-vm:long-float-significand-byte hi)) - (zerop lo))) - -;; NaNs have nonzero for the significand -(define-float-inf-or-nan-test float-nan-p - "Return true if the float X is a NaN (Not a Number)." - (not (zerop (ldb sb-vm:single-float-significand-byte bits))) - - #+64-bit (not (zerop (ldb (byte 52 0) bits))) - #-64-bit (not (zerop (logior (ldb sb-vm:double-float-significand-byte hi) lo))) - - #+(and long-float x86) - (or (not (zerop (ldb sb-vm:long-float-significand-byte hi))) - (not (zerop lo)))) - -(define-float-inf-or-nan-test float-trapping-nan-p - "Return true if the float X is a trapping NaN (Not a Number)." - ;; HPPA (and apparently MIPS) have trapping NaNs (SNaNs) with the - ;; trapping-nan-bit SET. PPC, SPARC, Alpha, and x86 (and presumably - ;; x86-64, ARM, and ARM64) have trapping NaNs (SNaNs) with the - ;; trapping-nan-bit CLEAR. Note that the given implementation - ;; considers infinities to be FLOAT-TRAPPING-NAN-P on most - ;; architectures. - - ;; SINGLE-FLOAT - #+(or mips hppa) (logbitp 22 bits) - #-(or mips hppa) (not (logbitp 22 bits)) - - ;; DOUBLE-FLOAT - #+(or mips hppa) (logbitp 19 hi) - #+(and (not (or mips hppa)) 64-bit) (not (logbitp 51 bits)) - #+(and (not (or mips hppa)) (not 64-bit)) (not (logbitp 19 hi)) - - ;; LONG-FLOAT (this code is dead anyway) - #+(and long-float x86) - (zerop (logand (ldb sb-vm:long-float-significand-byte hi) - (ash 1 30)))) - ;;; If denormalized, use a subfunction from INTEGER-DECODE-FLOAT to find the ;;; actual exponent (and hence how denormalized it is), otherwise we just ;;; return the number of digits or 0. -#-sb-fluid (declaim (maybe-inline float-precision)) +(declaim (maybe-inline float-precision)) (defun float-precision (f) "Return a non-negative number of significant digits in its float argument. Will be less than FLOAT-DIGITS if denormalized or zero." (declare (explicit-check)) - (macrolet ((frob (digits bias decode) - `(cond ((zerop f) 0) - ((float-denormalized-p f) - (multiple-value-bind (ignore exp) (,decode f) - (declare (ignore ignore)) - (truly-the fixnum - (+ ,digits (1- ,digits) ,bias exp)))) - (t - ,digits)))) - (number-dispatch ((f float)) - ((single-float) - (frob sb-vm:single-float-digits sb-vm:single-float-bias - integer-decode-single-denorm)) - ((double-float) - (frob sb-vm:double-float-digits sb-vm:double-float-bias - integer-decode-double-denorm)) - #+long-float - ((long-float) - (frob sb-vm:long-float-digits sb-vm:long-float-bias - integer-decode-long-denorm))))) + (integer-length + (number-dispatch ((f float)) + ((single-float) + (let ((bits (single-float-bits f))) + (if (sfloat-bits-subnormalp bits) + (ldb sb-vm:single-float-significand-byte bits) + (return-from float-precision sb-vm:single-float-digits)))) + ((double-float) + #+64-bit + (let ((bits (double-float-bits f))) + (if (dfloat-bits-subnormalp bits) + (ldb (byte 52 0) bits) + (return-from float-precision sb-vm:double-float-digits))) + #-64-bit + (let ((high (double-float-high-bits f))) + (if (not (dfloat-high-bits-subnormalp high)) + (return-from float-precision sb-vm:double-float-digits) + (let ((n (integer-length (ldb sb-vm:double-float-significand-byte high)))) + (if (/= 0 n) + (return-from float-precision (+ n 32)) + (double-float-low-bits f))))))))) (defun float-sign (float1 &optional (float2 (float 1 float1))) "Return a floating-point number that has the same sign as @@ -189,7 +86,7 @@ #+long-float (long-float sb-vm:long-float-digits))) -#-sb-fluid (declaim (inline float-digits float-radix)) +(declaim (inline float-digits float-radix)) (defun float-digits (f) (declare (explicit-check)) @@ -209,172 +106,69 @@ (defconstant-eqx float-decoding-error "Can't decode NaN or infinity: ~S." #'string=) -#-sb-fluid (declaim (maybe-inline integer-decode-single-float integer-decode-double-float)) -;;; Handle the denormalized case of INTEGER-DECODE-FLOAT for SINGLE-FLOAT. -(defun integer-decode-single-denorm (x) - (declare (type single-float x)) - (let* ((bits (single-float-bits x)) - (sig (ash (ldb sb-vm:single-float-significand-byte bits) 1)) - (extra-bias 0)) - (declare (type (unsigned-byte 24) sig) - (type (integer 0 23) extra-bias)) - (loop - (unless (zerop (logand sig sb-vm:single-float-hidden-bit)) - (return)) - (setq sig (ash sig 1)) - (incf extra-bias)) - (values sig - (- (- sb-vm:single-float-bias) - sb-vm:single-float-digits - extra-bias) - (if (minusp bits) -1 1)))) +;;; binary point is to the left of the 23 represented mantissa bits, +;;; and normal exponent min is -126, so -149 is the effective exponent +;;; of a subnormal in common-lisp terms. +(defconstant subnormal-sfloat-exponent -149) +;; binary point is to the left of the 52 represented mantissa bits, +;; and normal exponent min is -1022, so -1074 is the effective exponent. +(defconstant subnormal-dfloat-exponent -1074) ;;; Handle the single-float case of INTEGER-DECODE-FLOAT. If an infinity or -;;; NaN, error. If a denorm, call i-d-s-DENORM to handle it. +;;; NaN, error. (defun integer-decode-single-float (x) (declare (single-float x)) (let* ((bits (single-float-bits x)) + (frac (ldb sb-vm:single-float-significand-byte bits)) + (sign (if (minusp bits) -1 1)) (exp (ldb sb-vm:single-float-exponent-byte bits))) - (cond ((zerop (ldb (byte 31 0) bits)) - (values 0 0 (if (minusp bits) -1 1))) - ((< exp sb-vm:single-float-normal-exponent-min) - (integer-decode-single-denorm x)) + (cond ((= exp 0) + (values frac (if (= frac 0) 0 subnormal-sfloat-exponent) sign)) ((> exp sb-vm:single-float-normal-exponent-max) (error float-decoding-error x)) (t - (values (logior (ldb sb-vm:single-float-significand-byte bits) - sb-vm:single-float-hidden-bit) + (values (logior sb-vm:single-float-hidden-bit frac) (- exp sb-vm:single-float-bias sb-vm:single-float-digits) - (if (minusp bits) -1 1)))))) - -;;; like INTEGER-DECODE-SINGLE-DENORM, only doubly so -(defun integer-decode-double-denorm (x) - (declare (type double-float x)) - (let* ((high-bits (double-float-high-bits x)) - (sig-high (ldb sb-vm:double-float-significand-byte high-bits)) - (low-bits (double-float-low-bits x)) - (sign (if (minusp high-bits) -1 1)) - (biased (- (- sb-vm:double-float-bias) sb-vm:double-float-digits))) - (if (zerop sig-high) - (let ((sig low-bits) - (extra-bias (- sb-vm:double-float-digits 33)) - (bit (ash 1 31))) - (declare (type (unsigned-byte 32) sig) (fixnum extra-bias)) - (loop - (unless (zerop (logand sig bit)) (return)) - (setq sig (ash sig 1)) - (incf extra-bias)) - (values (ash sig (- sb-vm:double-float-digits 32)) - (truly-the fixnum (- biased extra-bias)) - sign)) - (let ((sig (ash sig-high 1)) - (extra-bias 0)) - (declare (type (unsigned-byte 32) sig) (fixnum extra-bias)) - (loop - (unless (zerop (logand sig sb-vm:double-float-hidden-bit)) - (return)) - (setq sig (ash sig 1)) - (incf extra-bias)) - (values (logior (ash sig 32) (ash low-bits (1- extra-bias))) - (truly-the fixnum (- biased extra-bias)) - sign))))) + sign))))) ;;; like INTEGER-DECODE-SINGLE-FLOAT, only doubly so (defun integer-decode-double-float (x) (declare (double-float x)) #-64-bit ; treat high and low bits separately until the end (let* ((hi (double-float-high-bits x)) + (sign (if (minusp hi) -1 1)) (lo (double-float-low-bits x)) + (mantissa (logior (ash (ldb sb-vm:double-float-significand-byte hi) 32) lo)) (exp (ldb sb-vm:double-float-exponent-byte hi))) (cond ((zerop (logior (ldb (byte 31 0) hi) lo)) - (values 0 0 (if (minusp hi) -1 1))) + (values 0 0 sign)) ((< exp sb-vm:double-float-normal-exponent-min) - (integer-decode-double-denorm x)) + (values mantissa subnormal-dfloat-exponent sign)) ((> exp sb-vm:double-float-normal-exponent-max) (error float-decoding-error x)) (t - (values (logior (ash (logior (ldb sb-vm:double-float-significand-byte hi) - sb-vm:double-float-hidden-bit) - 32) - lo) + ;; DOUBLE-FLOAT-HIDDEN-BIT is nonsense. It's 20 because it's the index + ;; within the high half. It should be an index within the entire fraction. + ;; If you want to manipulate the fraction as two 4-byte parts, that's on you. + (values (logior (ash sb-vm:double-float-hidden-bit 32) mantissa) (- exp sb-vm:double-float-bias sb-vm:double-float-digits) - (if (minusp hi) -1 1))))) + sign)))) #+64-bit ; don't split the high and low bits (let* ((bits (double-float-bits x)) - ;; It's unfortunate that the implied meaning of EXPONENT-BYTE and - ;; SIGNIFICAND-BYTE for double-floats assumes refererence to the high half - ;; and not the entire word. Because knowledge of the splitup is imparted here - ;; and elsewhere such as SB-BIGNUM:DOUBLE-FLOAT-FROM-BITS, it isn't really - ;; up to the backend parms to impart meaning, appearances to the contrary. - (exp (ldb (byte (byte-size sb-vm:double-float-exponent-byte) - (+ 32 (byte-position sb-vm:double-float-exponent-byte))) - bits))) - (cond ((zerop (ldb (byte 63 0) bits)) - (values 0 0 (if (minusp bits) -1 1))) - ((< exp sb-vm:double-float-normal-exponent-min) - (integer-decode-double-denorm x)) + (frac (ldb (byte 52 0) bits)) + (sign (if (minusp bits) -1 1)) + (exp (dfloat-exponent-from-bits bits))) + (cond ((= exp 0) + (values frac (if (= frac 0) 0 subnormal-dfloat-exponent) sign)) ((> exp sb-vm:double-float-normal-exponent-max) (error float-decoding-error x)) (t - ;; the count of digits [sic] includes a hidden bit - (values (logior (ldb (byte (1- sb-vm:double-float-digits) 0) bits) - (ash sb-vm:double-float-hidden-bit 32)) + (values (logior (ash sb-vm:double-float-hidden-bit 32) frac) (- exp sb-vm:double-float-bias sb-vm:double-float-digits) - (if (minusp bits) -1 1)))))) - -#+(and long-float x86) -(defun integer-decode-long-denorm (x) - (declare (type long-float x)) - (let* ((high-bits (long-float-high-bits (abs x))) - (sig-high (ldb sb-vm:long-float-significand-byte high-bits)) - (low-bits (long-float-low-bits x)) - (sign (if (minusp (float-sign x)) -1 1)) - (biased (- (- sb-vm:long-float-bias) sb-vm:long-float-digits))) - (if (zerop sig-high) - (let ((sig low-bits) - (extra-bias (- sb-vm:long-float-digits 33)) - (bit (ash 1 31))) - (declare (type (unsigned-byte 32) sig) (fixnum extra-bias)) - (loop - (unless (zerop (logand sig bit)) (return)) - (setq sig (ash sig 1)) - (incf extra-bias)) - (values (ash sig (- sb-vm:long-float-digits 32)) - (truly-the fixnum (- biased extra-bias)) - sign)) - (let ((sig (ash sig-high 1)) - (extra-bias 0)) - (declare (type (unsigned-byte 32) sig) (fixnum extra-bias)) - (loop - (unless (zerop (logand sig sb-vm:long-float-hidden-bit)) - (return)) - (setq sig (ash sig 1)) - (incf extra-bias)) - (values (logior (ash sig 32) (ash low-bits (1- extra-bias))) - (truly-the fixnum (- biased extra-bias)) - sign))))) - -#+(and long-float x86) -(defun integer-decode-long-float (x) - (declare (long-float x)) - (let* ((hi (long-float-high-bits x)) - (lo (long-float-low-bits x)) - (exp-bits (long-float-exp-bits x)) - (exp (ldb sb-vm:long-float-exponent-byte exp-bits)) - (sign (if (minusp exp-bits) -1 1)) - (biased (- exp sb-vm:long-float-bias sb-vm:long-float-digits))) - (declare (fixnum biased)) - (cond ((and (zerop exp) (zerop hi) (zerop lo)) - (values 0 biased sign)) - ((< exp sb-vm:long-float-normal-exponent-min) - (integer-decode-long-denorm x)) - ((> exp sb-vm:long-float-normal-exponent-max) - (error float-decoding-error x)) - (t - (values (logior (ash hi 32) lo) biased sign))))) + sign))))) ;;; Dispatch to the correct type-specific i-d-f function. (defun integer-decode-float (x) @@ -390,113 +184,71 @@ ((single-float) (integer-decode-single-float x)) ((double-float) - (integer-decode-double-float x)) - #+long-float - ((long-float) - (integer-decode-long-float x)))) - -#-sb-fluid (declaim (maybe-inline decode-single-float decode-double-float)) - -;;; Handle the denormalized case of DECODE-SINGLE-FLOAT. We call -;;; INTEGER-DECODE-SINGLE-DENORM and then make the result into a float. -(defun decode-single-denorm (x) - (declare (type single-float x)) - (multiple-value-bind (sig exp sign) (integer-decode-single-denorm x) - (values (make-single-float - (dpb sig sb-vm:single-float-significand-byte - (dpb sb-vm:single-float-bias - sb-vm:single-float-exponent-byte - 0))) - (truly-the fixnum (+ exp sb-vm:single-float-digits)) - (float sign x)))) + (integer-decode-double-float x)))) ;;; Handle the single-float case of DECODE-FLOAT. If an infinity or NaN, -;;; error. If a denorm, call d-s-DENORM to handle it. +;;; error. For subnormals, we left-align the significant bits into a field +;;; that is FLOAT-DIGITS wide, and decrease the exponent. (defun decode-single-float (x) (declare (single-float x)) - (let* ((bits (ldb (byte 31 0) (single-float-bits x))) ; unset the sign bit - (exp (ldb sb-vm:single-float-exponent-byte bits)) - (sign (float-sign x))) - (cond ((zerop bits) - (values $0.0f0 0 sign)) - ((< exp sb-vm:single-float-normal-exponent-min) - (decode-single-denorm x)) - ((> exp sb-vm:single-float-normal-exponent-max) - (error float-decoding-error x)) - (t - (values (make-single-float - (dpb sb-vm:single-float-bias ; set the effective exponent to 0 - sb-vm:single-float-exponent-byte - bits)) - (truly-the single-float-exponent (- exp sb-vm:single-float-bias)) - sign))))) - -;;; like DECODE-SINGLE-DENORM, only doubly so -(defun decode-double-denorm (x) - (declare (double-float x)) - (multiple-value-bind (sig exp sign) (integer-decode-double-denorm x) - (values (make-double-float - (dpb (logand (ash sig -32) (lognot sb-vm:double-float-hidden-bit)) - sb-vm:double-float-significand-byte - (dpb sb-vm:double-float-bias - sb-vm:double-float-exponent-byte 0)) - (ldb (byte 32 0) sig)) - (truly-the fixnum (+ exp sb-vm:double-float-digits)) - (float sign x)))) - -;;; like DECODE-SINGLE-FLOAT, only doubly so + (multiple-value-bind (bits exp) + (let* ((bits (single-float-bits x)) + (biased-exp (ldb sb-vm:single-float-exponent-byte bits))) + (if (> biased-exp sb-vm:single-float-normal-exponent-max) + (error float-decoding-error x) + (let ((frac (ldb sb-vm:single-float-significand-byte bits))) + (multiple-value-bind (new-exp new-frac lisp-exponent) + (cond ((/= biased-exp 0) ; normal + ;; SINGLE-FLOAT-BIAS as the stored exponent yields + ;; an effective exponent of -1. + (values sb-vm:single-float-bias frac + (- biased-exp sb-vm:single-float-bias))) + ((= frac 0) (values 0 0 0)) + (t ; subnormal. Normalize it and unset the implied 1 bit + (let ((prec (integer-length frac))) + (values sb-vm:single-float-bias + (ldb (byte (1- sb-vm:single-float-digits) 0) + (ash frac (- sb-vm:single-float-digits prec))) + (+ subnormal-sfloat-exponent prec))))) + (values (dpb new-exp sb-vm:single-float-exponent-byte new-frac) + lisp-exponent))))) + (values (make-single-float bits) exp (float-sign x)))) + +;;; The double-float logic mostly follows the skeleton of the above code, +;;; but there is a consed bignum or two on 32-bit architectures. +;;; Consing for the sake of code clarity is worth it as far as I'm concerned. (defun decode-double-float (x) (declare (double-float x)) - (let* ((hi (double-float-high-bits x)) - (exp (ldb sb-vm:double-float-exponent-byte hi)) - (sign (float-sign x))) - (cond ((zerop x) - (values $0.0d0 0 sign)) - ((< exp sb-vm:double-float-normal-exponent-min) - (decode-double-denorm x)) - ((> exp sb-vm:double-float-normal-exponent-max) - (error float-decoding-error x)) - (t - (values (make-double-float - (dpb sb-vm:double-float-bias ; set the effective exponent to 0 - sb-vm:double-float-exponent-byte - (ldb (byte 31 0) hi)) ; unset the sign bit - (double-float-low-bits x)) - (truly-the double-float-exponent (- exp sb-vm:double-float-bias)) - sign))))) - -#+(and long-float x86) -(defun decode-long-denorm (x) - (declare (long-float x)) - (multiple-value-bind (sig exp sign) (integer-decode-long-denorm x) - (values (make-long-float sb-vm:long-float-bias (ash sig -32) - (ldb (byte 32 0) sig)) - (truly-the fixnum (+ exp sb-vm:long-float-digits)) - (float sign x)))) - -#+(and long-float x86) -(defun decode-long-float (x) - (declare (long-float x)) - (let* ((hi (long-float-high-bits x)) - (lo (long-float-low-bits x)) - (exp-bits (long-float-exp-bits x)) - (exp (ldb sb-vm:long-float-exponent-byte exp-bits)) - (sign (if (minusp exp-bits) -1l0 1l0)) - (biased (truly-the long-float-exponent - (- exp sb-vm:long-float-bias)))) - (cond ((zerop x) - (values 0.0l0 biased sign)) - ((< exp sb-vm:long-float-normal-exponent-min) - (decode-long-denorm x)) - ((> exp sb-vm:long-float-normal-exponent-max) - (error float-decoding-error x)) - (t - (values (make-long-float - (dpb sb-vm:long-float-bias sb-vm:long-float-exponent-byte - exp-bits) - hi - lo) - biased sign))))) + (multiple-value-bind (high-bits low-bits exp) + (let* #+64-bit ((bits (double-float-bits x)) + (biased-exp (dfloat-exponent-from-bits bits))) + #-64-bit ((high (double-float-high-bits x)) + (biased-exp (ldb sb-vm:double-float-exponent-byte high))) + (if (> biased-exp sb-vm:double-float-normal-exponent-max) + (error float-decoding-error x) + (let ((frac #+64-bit (ldb (byte 52 0) bits) + #-64-bit (logior (ash (ldb sb-vm:double-float-significand-byte high) 32) + (double-float-low-bits x)))) + (multiple-value-bind (new-exp new-frac lisp-exponent) + (cond ((/= biased-exp 0) ; normal + ;; DOUBLE-FLOAT-BIAS as the stored exponent yields + ;; an effective exponent of -1. + (values sb-vm:double-float-bias frac + (- biased-exp sb-vm:double-float-bias))) + ((= frac 0) (values 0 0 0)) + (t ; subnormal. Normalize it and unset the implied 1 bit + (let ((prec (integer-length frac))) + (values sb-vm:double-float-bias + (ldb (byte (1- sb-vm:double-float-digits) 0) + (ash frac (- sb-vm:double-float-digits prec))) + (+ subnormal-dfloat-exponent prec))))) + ;; Now comes the dumb part for 64-bit machines - + ;; splitting the fraction into halves for no good reason. + (values (dpb new-exp sb-vm:double-float-exponent-byte + (ldb (byte 32 32) new-frac)) + (ldb (byte 32 0) new-frac) + lisp-exponent))))) + (values (make-double-float high-bits low-bits) exp (float-sign x)))) ;;; Dispatch to the appropriate type-specific function. (defun decode-float (f) @@ -510,14 +262,11 @@ ((single-float) (decode-single-float f)) ((double-float) - (decode-double-float f)) - #+long-float - ((long-float) - (decode-long-float f)))) + (decode-double-float f)))) ;;;; SCALE-FLOAT -#-sb-fluid (declaim (maybe-inline scale-single-float scale-double-float)) +(declaim (maybe-inline scale-single-float scale-double-float)) ;;; Handle float scaling where the X is denormalized or the result is ;;; denormalized or underflows to 0. @@ -628,11 +377,6 @@ (unsigned-byte (scale-float-maybe-overflow x exp)) ((integer * 0) (scale-float-maybe-underflow x exp)))) -#+(and x86 long-float) -(defun scale-long-float (x exp) - (declare (long-float x) (integer exp)) - (scale-float x exp)) - ;;; Dispatch to the correct type-specific scale-float function. (defun scale-float (f ex) "Return the value (* f (expt (float 2 f) ex)), but with no unnecessary loss @@ -642,10 +386,7 @@ ((single-float) (scale-single-float f ex)) ((double-float) - (scale-double-float f ex)) - #+long-float - ((long-float) - (scale-long-float f ex)))) + (scale-double-float f ex)))) ;;;; converting to/from floats @@ -805,31 +546,132 @@ ;;; caller if needed. ;;; ;;; In the float case, we pick off small arguments so that compiler -;;; can use special-case operations. We use an exclusive test, since -;;; (due to round-off error), (float most-positive-fixnum) is likely -;;; to be equal to (1+ most-positive-fixnum). An exclusive test is -;;; good enough, because most-positive-fixnum will be one less than a -;;; power of two, and that power of two will be exactly representable -;;; as a float (at least until we get 128-bit fixnums). +;;; can use special-case operations. (defun %unary-truncate (number) - (number-dispatch ((number real)) - ((integer) number) - ((ratio) (values (truncate (numerator number) (denominator number)))) - (((foreach single-float double-float #+long-float long-float)) - (if (and (<= (float sb-xc:most-negative-fixnum number) number) - (< number (float sb-xc:most-positive-fixnum number))) - (truly-the fixnum (%unary-truncate number)) - (multiple-value-bind (bits exp) (integer-decode-float number) - (let ((res (ash bits exp))) - (if (minusp number) - (- res) - res))))))) + (declare (explicit-check number)) + (macrolet ((fits-fixnum (type) + `(<= ,(symbol-value (symbolicate 'most-negative-fixnum- type)) + number + ,(symbol-value (symbolicate 'most-positive-fixnum- type))))) + (number-dispatch ((number real)) + ((integer) number) + ((ratio) (values (truncate (numerator number) (denominator number)))) + (((foreach single-float double-float #+long-float long-float)) + (if (fits-fixnum (dispatch-type number)) + (truly-the fixnum (%unary-truncate number)) + (multiple-value-bind (bits exp sign) (integer-decode-float number) + (ash (if (minusp sign) + (- bits) + bits) + exp))))))) + +;;; Produce both values, unlike %unary-truncate +(defun unary-truncate (number) + (declare (explicit-check number)) + (macrolet ((fits-fixnum (type) + `(<= ,(symbol-value (symbolicate 'most-negative-fixnum- type)) + number + ,(symbol-value (symbolicate 'most-positive-fixnum- type))))) + (number-dispatch ((number real)) + ((integer) (values number 0)) + ((ratio) + (let ((truncated (truncate (numerator number) (denominator number)))) + (values truncated + (- number truncated)))) + (((foreach single-float double-float #+long-float long-float)) + (if (fits-fixnum (dispatch-type number)) + (let* ((truncated (truly-the fixnum (%unary-truncate number)))) + (values truncated + (- number + (coerce truncated '(dispatch-type number))))) + (multiple-value-bind (bits exp sign) (integer-decode-float number) + (let ((truncated (ash (if (minusp sign) + (- bits) + bits) + exp))) + (values + truncated + #+64-bit + (coerce 0 '(dispatch-type number)) + #-64-bit + (if (eq '(dispatch-type number) 'single-float) + (coerce 0 '(dispatch-type number)) + (- number (coerce truncated '(dispatch-type number)))))))))))) + +(macrolet ((def (type) + (let ((decode (symbolicate 'integer-decode- type))) + `(defun ,(symbolicate 'unary-truncate- type '-to-bignum) (number) + (declare (inline ,decode)) + (multiple-value-bind (bits exp sign) (,decode number) + (let ((truncated (ash (if (minusp sign) + (- bits) + bits) + exp))) + (values + truncated + ,(case type + ((single-float #+64-bit double-float) + `(coerce 0 ',type)) + (t + `(- number (coerce truncated ',type))))))))))) + (def double-float) + (def single-float)) + +(macrolet ((def (type) + (let ((decode (symbolicate 'integer-decode- type))) + `(defun ,(symbolicate '%unary-truncate- type '-to-bignum) (number) + (declare (inline ,decode)) + (multiple-value-bind (bits exp sign) (,decode number) + (ash (if (minusp sign) (- bits) bits) + exp)))))) + (def double-float) + (def single-float)) + +;;; Needs to be synchronized with sxhash-bignum +(macrolet ((def (type) + (let ((decode (symbolicate 'integer-decode- type))) + `(defun ,(symbolicate 'sxhash-bignum- type) (number) + (declare (inline ,decode)) + (let ((result 316495330) + (digit-size sb-bignum::digit-size)) + (declare (type fixnum result)) + (multiple-value-bind (bits exp sign) (,decode number) + (let ((bits (if (minusp sign) + (- bits) + bits))) + (multiple-value-bind (digits remaining) (truncate exp digit-size) + (dotimes (i digits) + do (mixf result 0)) + ;; Taken from bignum-ashift-left-fixnum. + (let* ((right-half (ldb (byte digit-size 0) + (ash bits remaining))) + (sign-bit-p + (logbitp (1- digit-size) right-half)) + (left-half (ash bits + (- remaining digit-size))) + (left-half-p (if sign-bit-p + (/= left-half -1) + (/= left-half 0)))) + (mixf result + (logand most-positive-fixnum + (logxor right-half + (ash right-half -7)))) + (when left-half-p + (let ((left-half (ldb (byte digit-size 0) left-half))) + (mixf result + (logand most-positive-fixnum + (logxor left-half + (ash left-half -7)))))))))) + result))))) + (def double-float) + (def single-float)) ;;; Specialized versions for floats. (macrolet ((def (type name) `(defun ,name (number) - (if (and (<= ,(coerce sb-xc:most-negative-fixnum type) number) - (< number ,(coerce sb-xc:most-positive-fixnum type))) + (if (<= ,(symbol-value (symbolicate 'most-negative-fixnum- type)) + number + ,(symbol-value (symbolicate 'most-positive-fixnum- type))) (truly-the fixnum (,name number)) ;; General -- slow -- case. (multiple-value-bind (bits exp) (integer-decode-float number) @@ -849,28 +691,32 @@ ;;; so all single-floats larger than most-positive-fixnum can be precisely ;;; represented by an integer.] (defun %unary-round (number) - (number-dispatch ((number real)) - ((integer) number) - ((ratio) (values (round (numerator number) (denominator number)))) - (((foreach single-float double-float #+long-float long-float)) - (if (< (float sb-xc:most-negative-fixnum number) - number - (float sb-xc:most-positive-fixnum number)) - (truly-the fixnum (%unary-round number)) - (multiple-value-bind (bits exp) (integer-decode-float number) - (let* ((shifted (ash bits exp)) - (rounded (if (minusp exp) - (let ((fractional-bits (logand bits (lognot (ash -1 (- exp))))) - (0.5bits (ash 1 (- -1 exp)))) - (cond - ((> fractional-bits 0.5bits) (1+ shifted)) - ((< fractional-bits 0.5bits) shifted) - (t (if (oddp shifted) (1+ shifted) shifted)))) - shifted))) - (if (minusp number) - (- rounded) - rounded))))))) - + (declare (explicit-check)) + (macrolet ((fits-fixnum (type) + `(<= ,(symbol-value (symbolicate 'most-negative-fixnum- type)) + number + ,(symbol-value (symbolicate 'most-positive-fixnum- type))))) + (number-dispatch ((number real)) + ((integer) number) + ((ratio) (values (round (numerator number) (denominator number)))) + (((foreach single-float double-float #+long-float long-float)) + (if (fits-fixnum (dispatch-type number)) + (truly-the fixnum (%unary-round number)) + (multiple-value-bind (bits exp) (integer-decode-float number) + (let* ((shifted (ash bits exp)) + (rounded (if (minusp exp) + (let ((fractional-bits (logand bits (lognot (ash -1 (- exp))))) + (0.5bits (ash 1 (- -1 exp)))) + (cond + ((> fractional-bits 0.5bits) (1+ shifted)) + ((< fractional-bits 0.5bits) shifted) + (t (if (oddp shifted) (1+ shifted) shifted)))) + shifted))) + (if (minusp number) + (- rounded) + rounded)))))))) + +#-round-float (defun %unary-ftruncate (number) (number-dispatch ((number real)) ((integer) (float number)) @@ -878,6 +724,14 @@ (((foreach single-float double-float #+long-float long-float)) (%unary-ftruncate number)))) +(declaim (inline first-bit-set)) +(defun first-bit-set (x) + #+x86-64 + (truly-the (values (mod #.sb-vm:n-word-bits) &optional) + (%primitive sb-vm::unsigned-word-find-first-bit (the word x))) + #-x86-64 + (1- (integer-length (logand x (- x))))) + (defun rational (x) "RATIONAL produces a rational number for any real numeric argument. This is more efficient than RATIONALIZE, but it assumes that floating-point is @@ -890,10 +744,85 @@ 0 (let ((int (if (minusp x) (- bits) bits))) (if (minusp exp) - (integer-/-integer int (ash 1 (- exp))) + ;; Instead of division (which also involves GCD) + ;; find the first set bit of the numerator and shift accordingly, + ;; as the denominator is a power of two. + (let* ((pexp (- exp)) + (set (first-bit-set bits)) + (shifted (ash int (- set)))) + (if (> pexp set) + (%make-ratio shifted + (let ((shift (- pexp set))) + (if (< shift sb-vm:n-fixnum-bits) + (ash 1 shift) + (bignum-ashift-left-fixnum 1 shift)))) + (ash int exp))) (ash int exp)))))) ((rational) x))) +#+64-bit +(defun float-bignum-= (float bignum) + (declare (optimize speed)) + (number-dispatch ((float)) + (((foreach single-float double-float)) + (multiple-value-bind (bits exp) (integer-decode-float float) + (if (or (eql bits 0) + (minusp exp)) + nil + (let ((int (if (minusp float) (- bits) bits))) + (and (= (truly-the bignum-length (bignum-integer-length bignum)) + (+ (integer-length int) exp)) + (sb-bignum::bignum-lower-bits-zero-p bignum exp) + (= int + (truly-the fixnum + (sb-bignum::last-bignum-part=>fixnum exp bignum)))))))))) + +#+64-bit +(defun float-bignum-< (float bignum) + (declare (optimize speed)) + (number-dispatch ((float)) + (((foreach single-float double-float)) + (multiple-value-bind (bits exp) (integer-decode-float float) + (if (or (eql bits 0) + (minusp exp)) + (bignum-plus-p bignum) + (let* ((int (if (minusp float) (- bits) bits)) + (length-diff (- (truly-the bignum-length (bignum-integer-length bignum)) + (+ (integer-length int) exp)))) + (cond + ((plusp length-diff) (bignum-plus-p bignum)) + ((minusp length-diff) (minusp float)) + (t + (let ((diff (- (truly-the fixnum + (sb-bignum::last-bignum-part=>fixnum exp bignum)) + int))) + (cond ((plusp diff) t) + ((minusp diff) nil) + (t + (not (sb-bignum::bignum-lower-bits-zero-p bignum exp))))))))))))) + +#+64-bit +(defun float-bignum-> (float bignum) + (declare (optimize speed)) + (number-dispatch ((float)) + (((foreach single-float double-float)) + (multiple-value-bind (bits exp) (integer-decode-float float) + (if (or (eql bits 0) + (minusp exp)) + (not (bignum-plus-p bignum)) + (let* ((int (if (minusp float) (- bits) bits)) + (length-diff (- (truly-the bignum-length (bignum-integer-length bignum)) + (+ (integer-length int) exp)))) + (cond + ((plusp length-diff) (not (bignum-plus-p bignum))) + ((minusp length-diff) (not (minusp float))) + (t + (let ((diff (- (truly-the fixnum + (sb-bignum::last-bignum-part=>fixnum exp bignum)) + int))) + (cond ((plusp diff) nil) + ((minusp diff) t))))))))))) + ;;; This algorithm for RATIONALIZE, due to Bruno Haible, is included ;;; with permission. ;;; diff --git a/src/code/fop.lisp b/src/code/fop.lisp deleted file mode 100644 index 365fe560a0..0000000000 --- a/src/code/fop.lisp +++ /dev/null @@ -1,676 +0,0 @@ -;;;; FOP definitions - -(in-package "SB-FASL") - -;;; Bind STACK-VAR and PTR-VAR to the start of a subsequence of -;;; the fop stack of length COUNT, then execute BODY. -;;; Within the body, FOP-STACK-REF is used in lieu of SVREF -;;; to elide bounds checking. -(defmacro with-fop-stack (((stack-var &optional stack-expr) ptr-var count) - &body body) - `(macrolet ((fop-stack-ref (i) - `(locally - #-sb-xc-host - (declare (optimize (sb-c::insert-array-bounds-checks 0))) - (svref ,',stack-var (truly-the index ,i))))) - (let* (,@(when stack-expr - (list `(,stack-var (the simple-vector ,stack-expr)))) - (,ptr-var (truly-the index (fop-stack-pop-n ,stack-var ,count)))) - ,@body))) - -;;; Define NAME as a fasl operation, with op-code FOP-CODE. -;;; PUSHP describes what the body does to the fop stack: -;;; T - The result of the body is pushed on the fop stack. -;;; NIL - The result of the body is discarded. -;;; In either case, the body is permitted to pop the stack. -;;; -(defmacro define-fop (fop-code &rest stuff) - (multiple-value-bind (name allowp operands stack-args pushp forms) - (let ((allowp (if (eq (car stuff) :not-host) - (progn (pop stuff) (or #-sb-xc-host t)) - t))) - (destructuring-bind ((name &optional arglist (pushp t)) . forms) stuff - (aver (member pushp '(nil t))) - (multiple-value-bind (operands stack-args) - (if (atom (car arglist)) - (values nil arglist) - (ecase (caar arglist) - (:operands (values (cdar arglist) (cdr arglist))))) - (assert (<= (length operands) 3)) - (values name allowp operands stack-args pushp forms)))) - `(progn - (defun ,name (.fasl-input. ,@operands) - (declare (ignorable .fasl-input.)) - ,@(if allowp - `((macrolet - ((fasl-input () '(truly-the fasl-input .fasl-input.)) - (fasl-input-stream () '(%fasl-input-stream (fasl-input))) - (operand-stack () '(%fasl-input-stack (fasl-input))) - (skip-until () '(%fasl-input-skip-until (fasl-input)))) - ,@(if (null stack-args) - forms - (with-unique-names (stack ptr) - `((with-fop-stack ((,stack (operand-stack)) - ,ptr ,(length stack-args)) - (multiple-value-bind ,stack-args - (values ,@(loop for i below (length stack-args) - collect `(fop-stack-ref (+ ,ptr ,i)))) - ,@forms))))))) - `((declare (ignore ,@operands)) - (error ,(format nil "Not-host fop invoked: ~A" name))))) - (!%define-fop ',name ,fop-code ,(length operands) ,(if pushp 1 0))))) - -(defun !%define-fop (name opcode n-operands pushp) - (declare (type (mod 4) n-operands)) - (let ((function (svref **fop-funs** opcode))) - (when (functionp function) - (let ((oname (nth-value 2 (function-lambda-expression function)))) - (when (and oname (not (eq oname name))) - (error "fop ~S with opcode ~D conflicts with fop ~S." - name opcode oname)))) - (let ((existing-opcode (get name 'opcode))) - (when (and existing-opcode (/= existing-opcode opcode)) - (error "multiple codes for fop name ~S: ~D and ~D" - name opcode existing-opcode))) - (setf (get name 'opcode) opcode - (svref **fop-funs** opcode) (symbol-function name) - (aref (car **fop-signatures**) opcode) n-operands - (sbit (cdr **fop-signatures**) opcode) pushp)) - name) - -;;; Compatibity macros that allow some fops to share the identical -;;; body between genesis and the target code. -#-sb-xc-host -(progn - (defmacro cold-cons (x y) `(cons ,x ,y)) - (defmacro number-to-core (x) x) - (defmacro make-character-descriptor (x) `(code-char ,x))) - -;;; helper functions for reading string values from FASL files: sort -;;; of like READ-SEQUENCE specialized for files of (UNSIGNED-BYTE 8), -;;; with an automatic conversion from (UNSIGNED-BYTE 8) into CHARACTER -;;; for each element read - -;;; Variation 1: character string, transfer elements of type (unsigned-byte 8) -;;: [Can we eliminate this one?] -(defun read-string-as-bytes (stream string &optional (length (length string))) - (declare (type (simple-array character (*)) string) - (type index length) - (optimize speed)) - (with-fast-read-byte ((unsigned-byte 8) stream) - (dotimes (i length) - (setf (aref string i) - (sb-xc:code-char (fast-read-byte))))) - string) -;;; Variation 2: base-string, transfer elements of type (unsigned-byte 8) -(defun read-base-string-as-bytes (stream string &optional (length (length string))) - (declare (type (simple-array base-char (*)) string) - (type index length) - (optimize speed)) - (with-fast-read-byte ((unsigned-byte 8) stream) - (dotimes (i length) - (setf (aref string i) - (sb-xc:code-char (fast-read-byte))))) - string) -;;; Variation 3: character-string, transfer elements of type varint -(defun read-char-string-as-varints - (stream string &optional (length (length string))) - (declare (type (simple-array character (*)) string) - (type index length) - (optimize speed)) - (with-fast-read-byte ((unsigned-byte 8) stream) - ;; OAOO violation- This repeats code in DEFINE-READ-VAR-INTEGER in 'debug-var-io' - ;; but there isn't a good expansion of that macro that would operate on a stream - ;; (which is ok in itself) but also that would entail only a single wrapping of - ;; WITH-FAST-READ-BYTE for all work. - ;; i.e. we don't want to update the stream slots after each varint. - (flet ((read-varint () - (loop for shift :of-type (integer 0 28) from 0 by 7 ; position in integer - for octet = (fast-read-byte) - for accum :of-type (mod #.sb-xc:char-code-limit) - = (logand octet #x7F) - then (logior (ash (logand octet #x7F) shift) accum) - unless (logbitp 7 octet) return accum))) - (dotimes (i length) - (setf (aref string i) - (sb-xc:code-char (read-varint)))))) - string) - -;;;; miscellaneous fops - -(define-fop 0 (fop-nop () nil)) -(define-fop 1 (fop-pop (x) nil) (push-fop-table x (fasl-input))) -(define-fop 2 (fop-empty-list) nil) -(define-fop 3 (fop-truth) t) -(define-fop 4 (fop-push ((:operands index))) - (ref-fop-table (fasl-input) index)) -(define-fop 5 (fop-move-to-table (x)) - (push-fop-table x (fasl-input)) - x) - -(define-fop 66 :not-host (fop-misc-trap) - (make-unbound-marker)) - -(define-fop 76 (fop-character ((:operands char-code))) - (make-character-descriptor char-code)) - -;; %MAKE-INSTANCE does not exist on the host. -(define-fop 48 :not-host (fop-struct ((:operands size) layout)) - (let ((res (%make-instance size)) ; number of words excluding header - ;; Discount the layout from number of user-visible words. - (n-data-words (- size sb-vm:instance-data-start))) - (setf (%instance-layout res) layout) - (with-fop-stack ((stack (operand-stack)) ptr n-data-words) - (declare (type index ptr)) - (let ((bitmap (layout-bitmap layout))) - ;; Values on the stack are in the same order as in the structure itself. - (do ((i sb-vm:instance-data-start (1+ i))) - ((>= i size)) - (declare (type index i)) - (let ((val (fop-stack-ref ptr))) - (if (logbitp i bitmap) - (setf (%instance-ref res i) val) - (setf (%raw-instance-ref/word res i) val)) - (incf ptr))))) - res)) - -;;; Symbol-like entities -(define-fop 49 :not-host (fop-debug-name-marker ((:operands kind))) - (ecase kind - (1 sb-c::*debug-name-sharp*) - (2 sb-c::*debug-name-ellipsis*))) - -(define-fop 45 :not-host (fop-layout ((:operands depthoid flags length) - name bitmap inherits)) - (decf depthoid) ; was bumped by 1 since non-stack args can't encode negatives - (find-and-init-or-check-layout name depthoid flags length bitmap inherits)) - -;; Allocate a CLOS object. This is used when the compiler detects that -;; MAKE-LOAD-FORM returned a simple use of MAKE-LOAD-FORM-SAVING-SLOTS, -;; or possibly a hand-written equivalent (however unlikely). -(define-fop 68 :not-host (fop-allocate-instance (name) nil) - (let ((instance (allocate-instance (find-class (the symbol name))))) - (push-fop-table instance (fasl-input)))) - -;; Fill in object slots as dictated by the second return value from -;; MAKE-LOAD-FORM-SAVING-SLOTS. -(define-fop 69 :not-host (fop-set-slot-values ((:operands n-slots) slot-names obj) nil) - (let* ((stack (operand-stack)) - (ptr (fop-stack-pop-n stack n-slots))) - (dotimes (i n-slots) - (let ((val (svref stack (+ ptr i))) - (slot-name (pop slot-names))) - (if (unbound-marker-p val) - ;; SLOT-MAKUNBOUND-USING-CLASS might do something nonstandard. - (slot-makunbound obj slot-name) - (setf (slot-value obj slot-name) val)))))) - -(define-fop 64 (fop-end-group () nil) - (throw 'fasl-group-end t)) - -(define-fop 62 (fop-verify-table-size ((:operands expected-index)) nil) - (unless (= (svref (%fasl-input-table (fasl-input)) 0) expected-index) - (bug "fasl table of improper size"))) -(define-fop 63 (fop-verify-empty-stack () nil) - (unless (fop-stack-empty-p (operand-stack)) - (bug "fasl stack not empty when it should be"))) - -;;;; fops for loading symbols - -(defstruct (undefined-package (:copier nil)) - (error nil :read-only t)) -(declaim (freeze-type undefined-package)) - -;;; Cold load has its own implementation of all symbol fops, -;;; but we have to execute define-fop now to assign their numbers. -;;; -;;; Any symbols created by the loader must have their SYMBOL-HASH computed. -;;; This is a requirement for the CASE macro to work. When code is compiled -;;; to memory, symbols in the expansion are subject to SXHASH, so all is well. -;;; When loaded, even uninterned symbols need a hash. -;;; Interned symbols automatically get a precomputed hash. -(labels #+sb-xc-host () - #-sb-xc-host - ((read-symbol-name (length+flag fasl-input) - (let* ((namelen (ash (the fixnum length+flag) -1)) - (base-p (logand length+flag 1)) - (elt-type (if (eql base-p 1) 'base-char 'character)) - (buffer (%fasl-input-name-buffer fasl-input)) - (string (the string (svref buffer base-p)))) - (when (< (length string) namelen) ; grow - (setf string (make-string namelen :element-type elt-type) - (svref buffer base-p) string)) - (funcall (if (eql base-p 1) - 'read-base-string-as-bytes - 'read-char-string-as-varints) - (%fasl-input-stream fasl-input) string namelen) - (values string namelen elt-type))) - (aux-fop-intern (length+flag package fasl-input) - (multiple-value-bind (name length elt-type) - (read-symbol-name length+flag fasl-input) - (if (undefined-package-p package) - (error 'simple-package-error - :format-control "Error finding package for symbol ~s:~% ~a" - :format-arguments - (list (subseq name 0 length) - (undefined-package-error package))) - (push-fop-table (%intern name length package elt-type t) - fasl-input)))) - (ensure-hashed (symbol) - ;; ENSURE-SYMBOL-HASH when vop-translated is flushable since it is - ;; conceptually just a slot reader, however its actual effect is to fill in - ;; the hash if absent, so it's not quite flushable when called expressly - ;; to fill in the slot. In this case we need a full call to ENSURE-SYMBOL-HASH - ;; to ensure the side-effect happens. - ;; Careful if changing this again. There'a regression test thank goodness. - (declare (notinline ensure-symbol-hash)) - (ensure-symbol-hash symbol) - symbol)) - - (define-fop 77 :not-host (fop-lisp-symbol-save ((:operands length+flag))) - (aux-fop-intern length+flag *cl-package* (fasl-input))) - (define-fop 78 :not-host (fop-keyword-symbol-save ((:operands length+flag))) - (aux-fop-intern length+flag *keyword-package* (fasl-input))) - (define-fop 79 :not-host (fop-symbol-in-package-save ((:operands length+flag pkg-index))) - (aux-fop-intern length+flag (ref-fop-table (fasl-input) pkg-index) (fasl-input))) - - (define-fop 80 :not-host (fop-uninterned-symbol-save ((:operands length+flag))) - (multiple-value-bind (name len) (read-symbol-name length+flag (fasl-input)) - (push-fop-table (ensure-hashed (make-symbol (subseq name 0 len))) - (fasl-input)))) - - (define-fop 81 :not-host (fop-copy-symbol-save ((:operands table-index))) - (push-fop-table (ensure-hashed - (copy-symbol (ref-fop-table (fasl-input) table-index))) - (fasl-input)))) - -(define-fop 82 (fop-package (pkg-designator)) - (find-undeleted-package-or-lose pkg-designator)) - -(define-fop 83 :not-host (fop-named-package-save ((:operands length)) nil) - (let ((package-name (make-string length))) - (read-char-string-as-varints (fasl-input-stream) package-name) - (push-fop-table - (handler-case (find-undeleted-package-or-lose package-name) - (simple-package-error (c) - (make-undefined-package :error (princ-to-string c)))) - (fasl-input)))) - -;;;; fops for loading numbers - -;;; Load a signed integer LENGTH bytes long from FASL-INPUT-STREAM. -(defun load-s-integer (length fasl-input-stream) - (declare (fixnum length) - (optimize speed) - #-sb-xc-host (muffle-conditions compiler-note)) - (with-fast-read-byte ((unsigned-byte 8) fasl-input-stream) - (do* ((index length (1- index)) - (byte 0 (fast-read-byte)) - (result 0 (+ result (ash byte bits))) - (bits 0 (+ bits 8))) - ((= index 0) - (if (logbitp 7 byte) ; look at sign bit - (- result (ash 1 bits)) - result)) - (declare (fixnum index byte bits))))) - -(define-fop 36 (fop-integer ((:operands n-bytes))) - (number-to-core (load-s-integer n-bytes (fasl-input-stream)))) - -(define-fop 34 (fop-word-integer) - (with-fast-read-byte ((unsigned-byte 8) (fasl-input-stream)) - (number-to-core (fast-read-s-integer #.sb-vm:n-word-bytes)))) - -(define-fop 35 (fop-byte-integer) - ;; FIXME: WITH-FAST-READ-BYTE for exactly 1 byte is not really faster/better - ;; than regular READ-BYTE. The expansion of READ-ARG corroborates this claim. - (with-fast-read-byte ((unsigned-byte 8) (fasl-input-stream)) - (number-to-core (fast-read-s-integer 1)))) - -;; There's a long tail to the distribution of FOP-BYTE-INTEGER uses, -;; but these 4 seem to account for about half of them. -(define-fop 37 (fop-int-const0) (number-to-core 0)) -(define-fop 38 (fop-int-const1) (number-to-core 1)) -(define-fop 39 (fop-int-const2) (number-to-core 2)) -(define-fop 40 (fop-int-const-neg1) (number-to-core -1)) - -(define-fop 70 (fop-ratio (num den)) - #+sb-xc-host (number-pair-to-core num den sb-vm:ratio-widetag) - #-sb-xc-host (%make-ratio num den)) - -(define-fop 71 (fop-complex (realpart imagpart)) - #+sb-xc-host (number-pair-to-core realpart imagpart sb-vm:complex-widetag) - #-sb-xc-host (%make-complex realpart imagpart)) - -(macrolet ((fast-read-single-float () - '(make-single-float (fast-read-s-integer 4))) - (fast-read-double-float () - '(let ((lo (fast-read-u-integer 4))) - (make-double-float (fast-read-s-integer 4) lo)))) - (macrolet ((define-complex-fop (opcode name type) - (let ((reader (symbolicate "FAST-READ-" type))) - `(define-fop ,opcode (,name) - (with-fast-read-byte ((unsigned-byte 8) (fasl-input-stream)) - (number-to-core (complex (,reader) (,reader))))))) - (define-float-fop (opcode name type) - (let ((reader (symbolicate "FAST-READ-" type))) - `(define-fop ,opcode (,name) - (with-fast-read-byte ((unsigned-byte 8) (fasl-input-stream)) - (number-to-core (,reader))))))) - (define-complex-fop 72 fop-complex-single-float single-float) - (define-complex-fop 73 fop-complex-double-float double-float) - #+long-float - (define-complex-fop 67 fop-complex-long-float long-float) - (define-float-fop 46 fop-single-float single-float) - (define-float-fop 47 fop-double-float double-float) - #+long-float - (define-float-fop 52 fop-long-float long-float))) - -#+sb-simd-pack -(define-fop 88 :not-host (fop-simd-pack) - (with-fast-read-byte ((unsigned-byte 8) (fasl-input-stream)) - (let ((tag (fast-read-s-integer 8))) - (cond #+sb-simd-pack-256 - ((logbitp 2 tag) - (%make-simd-pack-256 (logand tag #b11) - (fast-read-u-integer 8) - (fast-read-u-integer 8) - (fast-read-u-integer 8) - (fast-read-u-integer 8))) - (t - (%make-simd-pack tag - (fast-read-u-integer 8) - (fast-read-u-integer 8))))))) - -;;;; loading lists - -(defun fop-list (fasl-input n &aux (stack (%fasl-input-stack fasl-input))) - (declare (type index n) - (optimize (speed 3))) - (with-fop-stack ((stack) ptr n) - (do* ((i (+ ptr n) (1- i)) - (res () (cold-cons (fop-stack-ref i) res))) - ((= i ptr) res) - (declare (type index i))))) -(defun fop-list* (fasl-input n &aux (stack (%fasl-input-stack fasl-input))) - (declare (type index n) - (optimize (speed 3))) - (with-fop-stack ((stack) ptr (1+ n)) - (do* ((i (+ ptr n) (1- i)) - (res (fop-stack-ref (+ ptr n)) - (cold-cons (fop-stack-ref i) res))) - ((= i ptr) res) - (declare (type index i))))) - -;;;; fops for loading arrays - -(define-fop 100 :not-host (fop-base-string ((:operands length))) - (logically-readonlyize - (read-base-string-as-bytes (fasl-input-stream) - (make-string length :element-type 'base-char)))) - -(define-fop 101 :not-host (fop-character-string ((:operands length))) - (logically-readonlyize - (read-char-string-as-varints (fasl-input-stream) (make-string length)))) - -(define-fop 92 (fop-vector ((:operands size))) - (if (zerop size) - #() - (let ((res (make-array size)) - (stack (operand-stack))) - (declare (fixnum size)) - (let ((ptr (fop-stack-pop-n stack size))) - (replace res stack :start2 ptr)) - (logically-readonlyize res)))) - -;; No MAKE-ARRAY-HEADER on host -(define-fop 89 :not-host (fop-array ((:operands rank) vec)) - (let ((length (length vec)) - (res (make-array-header sb-vm:simple-array-widetag rank))) - (declare (simple-array vec) - (type (unsigned-byte #.(- sb-vm:n-word-bits sb-vm:n-widetag-bits)) rank)) - (set-array-header res vec length nil 0 (fop-list (fasl-input) rank) nil t) - res)) - -(defglobal **saetp-bits-per-length** - (let ((array (make-array (1+ sb-vm:widetag-mask) - :element-type '(unsigned-byte 8) - :initial-element 255))) - (loop for saetp across sb-vm:*specialized-array-element-type-properties* - do - (setf (aref array (sb-vm:saetp-typecode saetp)) - (sb-vm:saetp-n-bits saetp))) - array) - "255 means bad entry.") -(declaim (type (simple-array (unsigned-byte 8) (#.(1+ sb-vm:widetag-mask))) - **saetp-bits-per-length**)) - -(define-fop 43 (fop-spec-vector ((:operands length))) - (let* ((widetag (read-byte-arg (fasl-input-stream))) - (bits-per-length (aref **saetp-bits-per-length** widetag)) - (bits (progn (aver (< bits-per-length 255)) - (* length bits-per-length))) - (bytes (ceiling bits sb-vm:n-byte-bits)) - (words (ceiling bytes sb-vm:n-word-bytes)) - (vector - (progn (aver (/= widetag sb-vm:simple-vector-widetag)) - (logically-readonlyize - (allocate-vector widetag length words))))) - (declare (type index length bytes words) - (type word bits)) - (read-n-bytes (fasl-input-stream) vector 0 bytes) - vector)) - -(define-fop 53 (fop-eval (expr)) ; This seems to be unused - (if (skip-until) - expr - (eval expr))) - -(define-fop 54 (fop-eval-for-effect (expr) nil) ; This seems to be unused - (unless (skip-until) - (eval expr)) - nil) - -(defun fop-funcall* (argc stack skipping) - (with-fop-stack ((stack) ptr (1+ argc)) - (unless skipping - (do ((i (+ ptr argc)) - (args)) - ((= i ptr) (apply (fop-stack-ref i) args)) - (declare (type index i)) - (push (fop-stack-ref i) args) - (decf i))))) - -(define-fop 55 (fop-funcall ((:operands n))) - (fop-funcall* n (operand-stack) (skip-until))) -(define-fop 56 (fop-funcall-for-effect ((:operands n)) nil) - (fop-funcall* n (operand-stack) (skip-until))) - -;;; For LOAD-TIME-VALUE which is used for MAKE-LOAD-FORM -(define-fop 57 (fop-funcall-no-skip ((:operands n))) - (fop-funcall* n (operand-stack) nil)) - -;;;; fops for fixing up circularities - -(define-fop 11 (fop-rplaca ((:operands tbl-slot idx) val) nil) - (let ((obj (ref-fop-table (fasl-input) tbl-slot))) - (setf (car (nthcdr idx obj)) val))) - -(define-fop 12 (fop-rplacd ((:operands tbl-slot idx) val) nil) - (let ((obj (ref-fop-table (fasl-input) tbl-slot))) - (setf (cdr (nthcdr idx obj)) val))) - -(define-fop 13 (fop-svset ((:operands tbl-slot idx) val) nil) - (setf (svref (ref-fop-table (fasl-input) tbl-slot) idx) val)) - -(define-fop 14 :not-host (fop-structset ((:operands tbl-slot idx) val) nil) - (setf (%instance-ref (ref-fop-table (fasl-input) tbl-slot) idx) val)) - -(define-fop 15 (fop-nthcdr ((:operands n) obj)) - (nthcdr n obj)) - -;;;; fops for loading functions - -;;; (In CMU CL there was a FOP-CODE-FORMAT (47) which was -;;; conventionally placed at the beginning of each fasl file to test -;;; for compatibility between the fasl file and the CMU CL which -;;; loaded it. In SBCL, this functionality has been replaced by -;;; putting the implementation and version in required fields in the -;;; fasl file header.) - -(define-fop 16 :not-host (fop-load-code ((:operands header n-code-bytes n-fixups))) - (let* ((n-named-calls (read-unsigned-byte-32-arg (fasl-input-stream))) - (n-boxed-words (ash header -1)) - (n-constants (- n-boxed-words sb-vm:code-constants-offset))) - ;; stack has (at least) N-CONSTANTS words plus debug-info - (with-fop-stack ((stack (operand-stack)) ptr (1+ n-constants)) - (let* ((debug-info-index (+ ptr n-constants)) - (n-boxed-words (+ sb-vm:code-constants-offset n-constants)) - (code (sb-c:allocate-code-object - (if (oddp header) :immobile :dynamic) - n-named-calls - (align-up n-boxed-words sb-c::code-boxed-words-align) - n-code-bytes))) - (with-pinned-objects (code) - ;; * DO * NOT * SEPARATE * THESE * STEPS * - ;; For a full explanation, refer to the comment above MAKE-CORE-COMPONENT - ;; concerning the corresponding use therein of WITH-PINNED-OBJECTS etc. - (read-n-bytes (fasl-input-stream) (code-instructions code) 0 n-code-bytes) - (sb-thread:barrier (:write)) - ;; Assign debug-info last. A code object that has no debug-info will never - ;; have its fun table accessed in conservative_root_p() or pin_object(). - (setf (%code-debug-info code) (svref stack debug-info-index)) - ;; Boxed constants can be assigned only after figuring out where the range - ;; of implicitly tagged words is, which requires knowing how many functions - ;; are in the code component, which requires reading the code trailer. - (let* ((fdefns-start (sb-impl::code-fdefns-start-index code)) - (fdefns-end (1- (+ fdefns-start n-named-calls)))) ; inclusive bound - (loop for i of-type index from sb-vm:code-constants-offset - for j of-type index from ptr below debug-info-index - do (let ((constant (svref stack j))) - (if (<= fdefns-start i fdefns-end) - (sb-c::set-code-fdefn code i constant) - (setf (code-header-ref code i) constant))))) - ;; Now apply fixups. The fixups to perform are popped from the fasl stack. - (sb-c::apply-fasl-fixups stack code n-fixups)) - #-sb-xc-host - (when (typep (code-header-ref code (1- n-boxed-words)) - '(cons (eql sb-c::coverage-map))) - ;; Record this in the global list of coverage-instrumented code. - (atomic-push (make-weak-pointer code) (cdr *code-coverage-info*))) - code)))) - -;; this gets you an #<fdefn> object, not the result of (FDEFINITION x) -;; cold-loader uses COLD-FDEFINITION-OBJECT instead. -(define-fop 17 :not-host (fop-fdefn (name)) - (awhen (deprecated-thing-p 'function name) ; returns the stage of deprecation - (pushnew (list* it name :function) - (%fasl-input-deprecated-stuff (fasl-input)) :test 'equal)) - (find-or-create-fdefn name)) - -(define-fop 18 :not-host (fop-known-fun (name)) - (%coerce-name-to-fun name)) - -;; This FOP is only encountered in cross-compiled files for cold-load. -(define-fop 74 :not-host (fop-fset (name fn) nil) - ;; Ordinary, not-for-cold-load code shouldn't need to mess with this - ;; at all, since it's only used as part of the conspiracy between - ;; the cross-compiler and GENESIS to statically link FDEFINITIONs - ;; for cold init. - (warn "~@<FOP-FSET seen in ordinary load (not cold load) -- quite -strange! ~ If you didn't do something strange to cause this, please -report it as a ~ bug.~:@>") - ;; Unlike CMU CL, we don't treat this as a no-op in ordinary code. - ;; If the user (or, more likely, developer) is trying to reload - ;; compiled-for-cold-load code into a warm SBCL, we'll do a warm - ;; assignment. (This is partly for abstract tidiness, since the warm - ;; assignment is the closest analogy to what happens at cold load, - ;; and partly because otherwise our compiled-for-cold-load code will - ;; fail, since in SBCL things like compiled-for-cold-load %DEFUN - ;; depend more strongly than in CMU CL on FOP-FSET actually doing - ;; something.) - (setf (fdefinition name) fn)) - -;;; Modify a slot of the code boxed constants. -(define-fop 19 (fop-alter-code ((:operands index) code value) nil) - (flet (#+sb-xc-host - ((setf code-header-ref) (value code index) - (write-wordindexed code index value))) - (setf (code-header-ref code index) value) - (values))) - -(define-fop 20 :not-host (fop-fun-entry ((:operands fun-index) code-object)) - (%code-entry-point code-object fun-index)) - -;;;; assemblerish fops - -(define-fop 21 (fop-assembler-code) - (error "cannot load assembler code except at cold load")) - -;;; FOPs needed for implementing an IF operator in a FASL - -;;; Skip until a FOP-MAYBE-STOP-SKIPPING with the same POSITION is -;;; executed. While skipping, we execute most FOPs normally, except -;;; for ones that a) funcall/eval b) start skipping. This needs to -;;; be done to ensure that the fop table gets populated correctly -;;; regardless of the execution path. -(define-fop 6 (fop-skip ((:operands position)) nil) - (unless (skip-until) - (setf (skip-until) position)) - (values)) - -;;; As before, but only start skipping if the top of the FOP stack is NIL. -(define-fop 7 (fop-skip-if-false ((:operands position) condition) nil) - (unless (or condition (skip-until)) - (setf (skip-until) position)) - (values)) - -;;; If skipping, pop the top of the stack and discard it. Needed for -;;; ensuring that the stack stays balanced when skipping. -(define-fop 8 (fop-drop-if-skipping () nil) - (when (skip-until) - (fop-stack-pop-n (operand-stack) 1)) - (values)) - -;;; If skipping, push a dummy value on the stack. Needed for -;;; ensuring that the stack stays balanced when skipping. -(define-fop 9 (fop-push-nil-if-skipping () nil) - (when (skip-until) - (push-fop-stack nil (fasl-input))) - (values)) - -;;; Stop skipping if the top of the stack matches SKIP-UNTIL -(define-fop 10 (fop-maybe-stop-skipping ((:operands label)) nil) - (when (eql (skip-until) label) - (setf (skip-until) nil)) - (values)) - -;;; Primordial layouts. -(macrolet ((frob (&rest specs) - `(progn - (defun known-layout-fop (name) - (case name - ,@(mapcar (lambda (spec) `((,(cadr spec)) ,(car spec))) - specs))) - ,@(mapcar (lambda (spec) - `(define-fop ,(car spec) - (,(symbolicate "FOP-LAYOUT-OF-" - (cadr spec))) - (find-layout ',(cadr spec)))) - specs)))) - (frob (#x68 t) - (#x69 structure-object) - (#x6a condition) - (#x6b definition-source-location) - (#x6c sb-c::debug-info) - (#x6d sb-c::compiled-debug-info) - (#x6e sb-c::debug-source) - (#x6f defstruct-description) - (#x70 defstruct-slot-description) - (#x71 sb-c::debug-fun) - (#x72 sb-c::compiled-debug-fun) - (#x73 sb-c::compiled-debug-fun-optional) - (#x74 sb-c::compiled-debug-fun-more) - (#x75 sb-c::compiled-debug-fun-external) - (#x76 sb-c::compiled-debug-fun-toplevel) - (#x77 sb-c::compiled-debug-fun-cleanup))) diff --git a/src/code/foreign-load.lisp b/src/code/foreign-load.lisp index 040922087a..b07f695491 100644 --- a/src/code/foreign-load.lisp +++ b/src/code/foreign-load.lisp @@ -88,21 +88,11 @@ will be signalled when the core is saved -- this is orthogonal from DONT-SAVE." (dlopen-or-lose obj)) (setf *shared-objects* (append (remove obj *shared-objects*) (list obj))) - ;; FIXME: Why doesn't the linkage table work on Windows? (Or maybe it - ;; does and this can be just #+linkage-table?) Note: remember to change - ;; FOREIGN-DEINIT as well then! - ;; - ;; Kovalenko 2010-11-24: I think so. Alien _data_ references - ;; are the only thing on win32 that is even slightly - ;; problematic. Handle function references in the same way as - ;; other linkage-table platforms is easy. - ;; - #+linkage-table (when (or old (cdr *linkage-info*)) ;; If OLD is non-NIL, then we're passing "true" which causes all foreign ;; symbols to get looked up again. Otherwise we're passing "false" ;; which only tries to find symbols that aren't already found. - (update-linkage-table old)))) + (update-alien-linkage-table old)))) pathname)) (defun unload-shared-object (pathname) @@ -116,10 +106,9 @@ Experimental." :key #'shared-object-pathname :test #'equal))) (when old - #-hpux (dlclose-or-lose old) + (dlclose-or-lose old) (setf *shared-objects* (remove old *shared-objects*)) - #+linkage-table - (update-linkage-table t) + (update-alien-linkage-table t) ;; Return T for unloaded, vs whatever update-linkage-info returns t))))) @@ -155,8 +144,9 @@ Experimental." ;;; Open libraries in *SHARED-OBJECTS* and the runtime. Called during ;;; initialization. (defun reopen-shared-objects () - ;; Ensure that the runtime is open - (setf *runtime-dlhandle* (dlopen-or-lose)) + ;; Try to open the runtime. If we can't, errors will be produced later on + ;; when it's actually used. + (setf *runtime-dlhandle* (ignore-errors (dlopen-or-lose))) ;; Without this many symbols aren't accessible. #+android (load-shared-object "libc.so" :dont-save t) ;; Reopen stuff. @@ -168,32 +158,8 @@ Experimental." (defun close-shared-objects () (let (saved) (dolist (obj (reverse *shared-objects*)) - #-hpux (dlclose-or-lose obj) + (dlclose-or-lose obj) (unless (shared-object-dont-save obj) (push obj saved))) (setf *shared-objects* saved)) - #-hpux (dlclose-or-lose)) - -;;; This table is unsynchronized, but the only platforms that use it -;;; lack thread support, and they don't work anyway. -#-linkage-table -(let ((symbols (make-hash-table :test #'equal))) - (defun ensure-dynamic-foreign-symbol-address (symbol &optional datap) - "Returns the address of the foreign symbol as an integer. On linkage-table -ports if the symbols isn't found a special guard address is returned instead, -accesses to which will result in an UNDEFINED-ALIEN-ERROR. On other ports an -error is immediately signalled if the symbol isn't found. The returned address -is never in the linkage-table." - (declare (ignorable datap)) - (let ((addr (find-dynamic-foreign-symbol-address symbol))) - (cond ((not addr) - (error 'undefined-alien-error :name symbol)) - (t - (setf (gethash symbol symbols) t) - addr)))) - (defun dynamic-foreign-symbols-p () - (plusp (hash-table-count symbols))) - (defun list-dynamic-foreign-symbols () - (loop for symbol being each hash-key in symbols - collect symbol))) diff --git a/src/code/foreign.lisp b/src/code/foreign.lisp index 6a30c9cb5f..dd6d13e240 100644 --- a/src/code/foreign.lisp +++ b/src/code/foreign.lisp @@ -11,92 +11,189 @@ (in-package "SB-IMPL") +(define-alien-routine arch-write-linkage-table-entry void + (index int) (real-address unsigned) (datap int)) +(define-alien-variable undefined-alien-address unsigned) + +(define-alien-routine arch-read-linkage-table-entry (* t) + (index int) (datap int)) + +(define-load-time-global *linkage-info* + ;; CDR of the cons is the list of undefineds + (list (make-hash-table :test 'equal :synchronized t))) +(declaim (type (cons hash-table) *linkage-info*)) + +#+os-provides-dlopen +(macrolet ((dlsym-wrapper (&optional warn) + ;; Produce two values: an indicator of whether the foreign symbol was + ;; found; and the address as an integer if found, or a guard address + ;; which when accessed will result in an UNDEFINED-ALIEN-ERROR. + `(let ((addr (find-dynamic-foreign-symbol-address name))) + (cond (addr + (values t addr)) + (t + (when ,warn + ;; If we can report the actual name when an undefined + ;; alien is called don't warn. + #-(or arm arm64 x86-64) + (style-warn 'sb-kernel:undefined-alien-style-warning + :symbol name)) + (values + nil + (if datap + undefined-alien-address + (or + (sb-fasl:get-asm-routine 'sb-vm::undefined-alien-tramp) + (find-foreign-symbol-address "undefined_alien_function") + (bug "unreachable"))))))))) + +;;; Return the index of NAME+DATAP in the table, adding it if it doesn't exist. +(defun ensure-alien-linkage-index (name datap) + (let* ((key (if datap (list name) name)) + (info *linkage-info*) + (ht (car info))) + (or (with-system-mutex ((hash-table-lock ht)) + (or (gethash key ht) + (let* ((index (hash-table-count ht)) + (capacity (floor sb-vm:alien-linkage-table-space-size + sb-vm:alien-linkage-table-entry-size))) + (when (< index capacity) + (multiple-value-bind (defined real-address) (dlsym-wrapper t) + (unless defined (push key (cdr info))) + (arch-write-linkage-table-entry index real-address (if datap 1 0)) + (logically-readonlyize name) + (setf (gethash key ht) index)))))) + (error "Linkage-table full (~D entries): cannot link ~S." + (hash-table-count ht) name)))) + +;;; Update the linkage-table. Called during initialization after all +;;; shared libraries have been reopened, and after a previously loaded +;;; shared object is reloaded. +;;; +;;; FIXME: Should figure out how to write only those entries that need +;;; updating. +;;; The problem is that when unloading a library, lacking any way to know which +;;; symbols came from it, we have to try to find every symbol again. +;;; If the shared-object-handle in which each symbol was originally found were +;;; stored in linkage-info, we could know which will become undefined on unload. +;;; The only "problem" is my lack of motivation to change this further. +(defun update-alien-linkage-table (full-scan) + ;; This symbol is of course itself a prelinked symbol. + (let* ((n-prelinked (extern-alien "alien_linkage_table_n_prelinked" int)) + (info *linkage-info*) + (ht (car info)) + ;; for computing anew the list of undefined symbols + (notdef)) + (flet ((recheck (key index) + (let* ((datap (listp key)) + (name (if datap (car key) key))) + ;; Symbols required for Lisp startup + ;; will not be re-pointed to a different address ever. + ;; Nor will those referenced by ELF core. + (when (>= index n-prelinked) + (multiple-value-bind (defined real-address) (dlsym-wrapper) + (unless defined (push key notdef)) + (arch-write-linkage-table-entry index real-address + (if datap 1 0))))))) + (with-system-mutex ((hash-table-lock ht)) + (if full-scan + ;; Look up everything; this is for image restart or library unload. + (dohash ((key index) ht) + (recheck key index)) + ;; Look up only the currently undefined foreign symbols + (dolist (key (cdr info)) + (recheck key (the (not null) (gethash key ht))))) + (setf (cdr info) notdef))))) +) + (defun find-foreign-symbol-address (name) "Returns the address of the foreign symbol NAME, or NIL. Does not enter the symbol in the linkage table, and never returns an address in the linkage-table." - (or #-linkage-table - (find-foreign-symbol-in-table name *static-foreign-symbols*) - (find-dynamic-foreign-symbol-address name))) + (or + #+os-provides-dlopen + (find-dynamic-foreign-symbol-address name) + (find-linkage-table-foreign-symbol-address name))) ;;; Note that much conditionalization is for nothing at this point, because all ;;; platforms that we care about implement dlopen(). But if one did not, only ;;; supporting static linking, we could still implement the entirety of the feature -;;; known as :linkage-table and the feature formerly known as "dynamic core" -;;; (folded into :linkage-table now) by mocking out dlsym() within the SBCL runtime +;;; formerly known as "dynamic core" by mocking out dlsym() within the SBCL runtime ;;; as a lookup table translating strings to functions needed in our runtime. ;;; It's not our problem that shared objects aren't loadable, but we get the ;;; flexibility of recompiling C without recompiling Lisp. +;;; +;;; This function is somewhat badly named, because when DATAP is true, +;;; the answer is not really the address of NAME, but rather the address +;;; of the word in the alien-linkage-table holding the address of NAME. +;;; (This would be better off named ALIEN-LINKAGE-ADDRESS) +;;; Unfortunately we can not rename it, because CFFI uses it, which is weird +;;; because the use is from a function named %FOREIGN-SYMBOL-POINTER which is +;;; documented to return "a pointer to a foreign symbol NAME." +;;; which it certainly does not do in all cases. (defun foreign-symbol-address (name &optional datap) "Returns the address of the foreign symbol NAME. DATAP must be true if the -symbol designates a variable (used only on linkage-table platforms). -Returns a secondary value T if the symbol is a dynamic foreign symbol. - -On linkage-table ports the returned address is always static: either direct -address of a static symbol, or the linkage-table address of a dynamic one. -Dynamic symbols are entered into the linkage-table if they aren't there already. +symbol designates a variable. +Returns a secondary value T for historical reasons. -On non-linkage-table ports signals an error if the symbol isn't found." +The returned address is always a linkage-table address. +Symbols are entered into the linkage-table if they aren't there already." (declare (ignorable datap)) - #+linkage-table - (values (ensure-foreign-symbol-linkage name datap) t) - #-linkage-table - (let ((static (find-foreign-symbol-in-table name *static-foreign-symbols*))) - (if static - (values static nil) - #+os-provides-dlopen (values (ensure-dynamic-foreign-symbol-address name) t) - #-os-provides-dlopen (error 'undefined-alien-error :name name)))) + (values + (or (linkage-table-address name datap) + #+os-provides-dlopen + (ensure-alien-linkage-index name datap) + (error 'undefined-alien-error :name name)) + t)) (defun foreign-symbol-sap (symbol &optional datap) "Returns a SAP corresponding to the foreign symbol. DATAP must be true if the -symbol designates a variable (used only on linkage-table platforms). May enter -the symbol into the linkage-table. On non-linkage-table ports signals an error -if the symbol isn't found." - (declare (ignorable datap)) - #-linkage-table - (int-sap (foreign-symbol-address symbol)) - #+linkage-table - (multiple-value-bind (addr sharedp) - (foreign-symbol-address symbol datap) - ;; If the address is from linkage-table and refers to data - ;; we need to do a bit of juggling. It is not the address of the - ;; variable, but the address where the real address is stored. - (if (and sharedp datap) - (int-sap (sap-ref-word (int-sap addr) 0)) +symbol designates a variable. May enter the symbol into the linkage-table." + (let ((addr (foreign-symbol-address symbol datap))) + (if datap ; return the real answer, not an address in the linkage table + (sap-ref-sap (int-sap addr) 0) (int-sap addr)))) (defun foreign-reinit () + (fixup-prelinked-linkage-table-entries) #+os-provides-dlopen (reopen-shared-objects) - #+linkage-table (update-linkage-table t)) + #+os-provides-dlopen (update-alien-linkage-table t)) ;;; Cleanups before saving a core (defun foreign-deinit () - #+(and os-provides-dlopen (not linkage-table)) ; at most HPPA and Alpha now - (when (dynamic-foreign-symbols-p) - (warn "~@<Saving cores with alien definitions referring to non-static ~ - foreign symbols is unsupported on this platform: references to ~ - such foreign symbols from the restarted core will not work. You ~ - may be able to work around this limitation by reloading all ~ - foreign definitions and code using them in the restarted core, ~ - but no guarantees.~%~%Dynamic foreign symbols in this core: ~ - ~{~A~^, ~}~:@>" (list-dynamic-foreign-symbols))) ;; Clobber list of undefineds. Reinit will figure it all out again. - #+linkage-table (setf (cdr *linkage-info*) nil) + (setf (cdr *linkage-info*) nil) #+os-provides-dlopen (close-shared-objects)) +(defun alien-linkage-index-to-name (index) + ;; Entries are never removed from the linkage-table, so we can take advantage + ;; of the fact that indices are inserted in order, and hash-table growth + ;; preserves order. So we know where the entry is. + ;; INDEX should be of type HASH-TABLE-INDEX but this might be called + ;; on an arbitrary (bogus) value which exceeds that. + (declare (fixnum index)) + (let* ((table (car *linkage-info*)) + (pairs (sb-impl::hash-table-pairs table)) + (pair-index (+ (* index 2) 2)) + (key + (cond ((>= index (hash-table-count table)) nil) + ((eql (aref pairs (1+ pair-index)) index) (aref pairs pair-index)) + (t (block found ; "shouldn't happen" + (dohash ((key value) table) ; no lock necessary + (when (= value index) (return-from found key)))))))) + (if (listp key) (car key) key))) + (declaim (maybe-inline sap-foreign-symbol)) (defun sap-foreign-symbol (sap) (declare (ignorable sap)) (let ((addr (sap-int sap))) (declare (ignorable addr)) - #+linkage-table - (when (<= sb-vm:linkage-table-space-start + (when (<= sb-vm:alien-linkage-table-space-start addr - sb-vm:linkage-table-space-end) - (let ((table-index (sb-vm::linkage-table-index-from-address addr))) - (dohash ((key value) (car *linkage-info*) :locked t) - (when (= value table-index) - (return-from sap-foreign-symbol (if (listp key) (car key) key)))))) + (+ sb-vm:alien-linkage-table-space-start sb-vm:alien-linkage-table-space-size)) + (return-from sap-foreign-symbol + (alien-linkage-index-to-name + (sb-vm::alien-linkage-table-index-from-address addr)))) #+os-provides-dladdr (with-alien ((info (struct dl-info (filename c-string) @@ -119,20 +216,13 @@ if the symbol isn't found." ;; static foreign symbols (and *linkage-info*, for that matter). )) -;;; How we learn about foreign symbols and dlhandles initially -(defvar *!initial-foreign-symbols*) - (defun !foreign-cold-init () (declare (special *runtime-dlhandle* *shared-objects*)) - #-linkage-table - (dovector (symbol *!initial-foreign-symbols*) - (setf (gethash (car symbol) *static-foreign-symbols*) (cdr symbol))) - #+linkage-table (loop for table-offset from 0 and reference across (symbol-value 'sb-vm::+required-foreign-symbols+) do (setf (gethash reference (car *linkage-info*)) table-offset)) #+os-provides-dlopen - (setf *runtime-dlhandle* (dlopen-or-lose)) + (setf *runtime-dlhandle* (ignore-errors (dlopen-or-lose))) #+os-provides-dlopen (setf *shared-objects* nil)) @@ -154,3 +244,55 @@ if the symbol isn't found." #-os-provides-dlopen (define-unsupported-fun load-shared-object) + +;; TODO: Is there a way to avoid this? This is needed because on some +;; platforms, the undefined alien function handler is not available at compile +;; time (it's an assembly routine created in Lisp). +(defun fixup-prelinked-linkage-table-entries () + "Called during reinit. Used to rewrite NULL function references to the +correct undefined alien function handler." + (let* ((n-prelinked (extern-alien "alien_linkage_table_n_prelinked" int)) + (info *linkage-info*) + (ht (car info)) + (notdef)) + (with-system-mutex ((hash-table-lock ht)) + (dohash ((key index) ht) + (when (< index n-prelinked) + (let* ((datap (listp key)) + (sap (alien-sap (arch-read-linkage-table-entry index (if datap 1 0))))) + (when (zerop (sap-int sap)) + (push key notdef) + (arch-write-linkage-table-entry index + (if datap + undefined-alien-address + (or + (sb-fasl:get-asm-routine 'sb-vm::undefined-alien-tramp) + (find-foreign-symbol-address "undefined_alien_function") + (bug "unreachable"))) + (if datap 1 0))))))) + (setf (cdr info) notdef))) + +(defun linkage-table-index (name datap) + "Returns the index of the foreign symbol in the linkage table or NIL if it is +not present." + (let* ((key (if datap (list name) name)) + (info *linkage-info*) + (ht (car info))) + (with-system-mutex ((hash-table-lock ht)) + (gethash key ht)))) + +(defun linkage-table-address (name datap) + "Returns the address of the foreign symbol's entry in the linkage table or NIL +if it is not present." + (awhen (linkage-table-index name datap) + (sb-vm::alien-linkage-table-index-from-address it))) + +(defun find-linkage-table-foreign-symbol-address (name) + "Returns the address of the foreign symbol NAME, or NIL. Consults only the +linkage table to find the address." + (multiple-value-bind (index datap) + (or (linkage-table-index name nil) + (values (linkage-table-index name t) t)) + (when (and index + (not (member (if datap (list name) name) (cdr *linkage-info*) :test #'equal))) + (sap-int (alien-sap (arch-read-linkage-table-entry index (if datap 1 0))))))) diff --git a/src/code/format-directive.lisp b/src/code/format-directive.lisp index 64d9395fd7..1e8e0873cb 100644 --- a/src/code/format-directive.lisp +++ b/src/code/format-directive.lisp @@ -8,7 +8,46 @@ ;;;; files for more information. (in-package "SB-FORMAT") - + +(defstruct (format-directive (:copier nil) + (:constructor %make-directive + (string start end params bits function)) + (:conc-name directive-)) + (string (missing-arg) :type simple-string :read-only t) + (start (missing-arg) :type (and unsigned-byte fixnum) :read-only t) + (end (missing-arg) :type (and unsigned-byte fixnum) :read-only t) + (bits nil :type (unsigned-byte 9) :read-only t) ; colon, atsign, char + ;; for early binding to the function in "~/pkg:fun/" directives + (function nil :type symbol :read-only t) + (params nil :type list :read-only t)) +(declaim (freeze-type format-directive)) + +(defun make-format-directive (string start end params colon atsign char symbol) + (let ((code (char-code char))) + (%make-directive string start end params + (logior (if colon #x100 0) + (if atsign #x080 0) + (if (< code 128) code 0)) + symbol))) + +(defglobal *format-directive-expanders* (make-array 128 :initial-element nil)) +(declaim (type (simple-vector 128) + *format-directive-expanders*)) + +(defun %print-format-error (condition stream) + (format stream + "~:[~*~;error in ~S: ~]~?~@[~% ~A~% ~V@T^~@[~V@T^~]~]" + (format-error-print-banner condition) + 'format + (format-error-complaint condition) + (format-error-args condition) + (format-error-control-string condition) + (format-error-offset condition) + (format-error-second-relative condition))) + +(defvar *default-format-error-control-string* nil) +(defvar *default-format-error-offset* nil) + (define-condition format-error (error reference-condition) ((complaint :reader format-error-complaint :initarg :complaint) (args :reader format-error-args :initarg :args :initform nil) @@ -24,17 +63,6 @@ (:report %print-format-error) (:default-initargs :references nil)) -(defun %print-format-error (condition stream) - (format stream - "~:[~*~;error in ~S: ~]~?~@[~% ~A~% ~V@T^~@[~V@T^~]~]" - (format-error-print-banner condition) - 'format - (format-error-complaint condition) - (format-error-args condition) - (format-error-control-string condition) - (format-error-offset condition) - (format-error-second-relative condition))) - (defun format-error* (complaint args &rest initargs &key &allow-other-keys) (apply #'error 'format-error :complaint complaint :args args initargs)) @@ -53,33 +81,13 @@ (format-error-at* control-string offset complaint args)) -(defstruct (format-directive (:copier nil) - (:constructor %make-directive - (string start end params bits function)) - (:conc-name directive-)) - (string (missing-arg) :type simple-string :read-only t) - (start (missing-arg) :type (and unsigned-byte fixnum) :read-only t) - (end (missing-arg) :type (and unsigned-byte fixnum) :read-only t) - (bits nil :type (unsigned-byte 9) :read-only t) ; colon, atsign, char - ;; for early binding to the function in "~/pkg:fun/" directives - (function nil :type symbol :read-only t) - (params nil :type list :read-only t)) -(declaim (freeze-type format-directive)) - -(defun make-format-directive (string start end params colon atsign char symbol) - (let ((code (sb-xc:char-code char))) - (%make-directive string start end params - (logior (if colon #x100 0) - (if atsign #x080 0) - (if (< code 128) code 0)) - symbol))) (declaim (inline directive-colonp directive-atsignp)) (defun directive-colonp (x) (logbitp 8 (directive-bits x))) (defun directive-atsignp (x) (logbitp 7 (directive-bits x))) (declaim (inline directive-code directive-character)) (defun directive-code (x) (logand (directive-bits x) #x7F)) -(defun directive-character (x) (sb-xc:code-char (directive-code x))) +(defun directive-character (x) (code-char (directive-code x))) ;;; This works even if directive char is invalid, where -CHARACTER ;;; would return (code-char 0) (defun directive-char-name (x) @@ -87,7 +95,7 @@ (char-name (if (eql byte 0) ;; extract the character from the string (char (directive-string x) (1- (directive-end x))) - (sb-xc:code-char byte))))) + (code-char byte))))) (defun check-modifier (modifier-name value) (when value @@ -99,8 +107,8 @@ ;;; FMT-CONTROL is a structure with a nonstandard metaclass. ;;; The compile-time representation of that object is an ordinary defstruct ;;; which of course works on any cross-compiler host. -(def!struct (fmt-control-proxy (:constructor make-fmt-control-proxy - (string symbols))) +(defstruct (fmt-control-proxy (:constructor make-fmt-control-proxy + (string symbols))) string symbols) (!set-load-form-method fmt-control-proxy (:xc :target) (lambda (self env) diff --git a/src/code/late-format.lisp b/src/code/format.lisp similarity index 95% rename from src/code/late-format.lisp rename to src/code/format.lisp index f74fc053d4..2e01c6df38 100644 --- a/src/code/late-format.lisp +++ b/src/code/format.lisp @@ -31,10 +31,11 @@ `(combine-directives (%tokenize-control-string string 0 (length string) nil) t))) - (if (logtest (get-header-data string) - ;; shareable = readonly - (logior sb-vm:+vector-shareable+ - sb-vm:+vector-shareable-nonstd+)) + (if (test-header-data-bit string + ;; shareable = readonly + (ash (logior sb-vm:+vector-shareable+ + sb-vm:+vector-shareable-nonstd+) + sb-vm:array-flags-data-position)) (memoize (compute-it)) (compute-it)))) @@ -194,6 +195,36 @@ (nreverse params) colonp atsignp (char-upcase char) (when (eql char #\/) (car symbols)))))))) +;;;; specials used to communicate information + +;;; Used both by the expansion stuff and the interpreter stuff. When it is +;;; non-NIL, up-up-and-out (~:^) is allowed. Otherwise, ~:^ isn't allowed. +(defvar *up-up-and-out-allowed* nil) + +;;; Used by the interpreter stuff. When it's non-NIL, it's a function +;;; that will invoke PPRINT-POP in the right lexical environemnt. +(defvar *logical-block-popper* nil) +(declaim (type (or null function) *logical-block-popper*) + (always-bound *logical-block-popper*)) + +;;; Used by the expander stuff. This is bindable so that ~<...~:> +;;; can change it. +(defvar *expander-next-arg-macro* 'expander-next-arg) + +;;; Used by the expander stuff. Initially starts as T, and gets set to NIL +;;; if someone needs to do something strange with the arg list (like use +;;; the rest, or something). +(defvar *only-simple-args*) + +;;; Used by the expander stuff. We do an initial pass with this as NIL. +;;; If someone doesn't like this, they (THROW 'NEED-ORIG-ARGS NIL) and we try +;;; again with it bound to T. If this is T, we don't try to do anything +;;; fancy with args. +(defvar *orig-args-available* nil) + +;;; Used by the expander stuff. List of (symbol . offset) for simple args. +(defvar *simple-args*) + ;;; Make a few simplifications to the directive list in INPUT, ;;; including translation of ~% to literal newline. ;;; I think that this does not have implications on conditional newlines @@ -264,7 +295,7 @@ (if (and (not colon) (stringp (car input))) (string-left-trim ;; #\Tab is a nonstandard char - `(#-sb-xc-host ,(sb-xc:code-char tab-char-code) + `(#-sb-xc-host ,(code-char tab-char-code) #\space #\newline) (pop input)) "")))) @@ -284,7 +315,7 @@ (when (or (plusp n) (emit-placeholder-p)) (let ((char (case char (#\% #\Newline) - (#\| (sb-xc:code-char form-feed-char-code)) + #-sb-xc-host (#\| (code-char form-feed-char-code)) (t char)))) (emit-string (make-string n :initial-element char)))) (return))))) @@ -296,9 +327,10 @@ `#',(%formatter control-string)) (defun %formatter (control-string &optional (arg-count 0) (need-retval t) - &aux (lambda-name - (possibly-base-stringize - (concatenate 'string "fmt$" control-string)))) + &aux (lambda-name + (logically-readonlyize + (possibly-base-stringize + (concatenate 'string "fmt$" control-string))))) ;; ARG-COUNT is supplied only when the use of this formatter is in a literal ;; call to FORMAT, in which case we can possibly elide &optional parsing. ;; But we can't in general, because FORMATTER may be called by users @@ -331,7 +363,7 @@ (let ((*orig-args-available* t) (*only-simple-args* nil)) `(named-lambda ,lambda-name (stream &rest orig-args) - (declare (ignorable stream)) + (declare (ignorable stream) (muffle-conditions compiler-note)) (let ((args orig-args)) ,(expand-control-string control-string) ,(and need-retval 'args)))))) @@ -438,7 +470,7 @@ (collect ((expander-bindings) (runtime-bindings)) (dolist (spec specs) (destructuring-bind (var default) spec - (let ((symbol (sb-xc:gensym "FVAR"))) + (let ((symbol (gensym "FVAR"))) (expander-bindings `(,var ',symbol)) (runtime-bindings @@ -473,8 +505,8 @@ (let ((defun-name (intern (format nil "~:@(~:C~)-FORMAT-DIRECTIVE-EXPANDER" char))) - (directive (sb-xc:gensym "DIRECTIVE")) - (directives (if lambda-list (car (last lambda-list)) (sb-xc:gensym "DIRECTIVES")))) + (directive (gensym "DIRECTIVE")) + (directives (if lambda-list (car (last lambda-list)) (gensym "DIRECTIVES")))) `(progn (defun ,defun-name (,directive ,directives) ,@(if lambda-list @@ -488,7 +520,7 @@ (%set-format-directive-expander ,char #',defun-name)))) (defmacro def-format-directive (char lambda-list &body body) - (let ((directives (sb-xc:gensym "DIRECTIVES")) + (let ((directives (gensym "DIRECTIVES")) (declarations nil) (body-without-decls body)) (loop @@ -503,7 +535,7 @@ ,directives)))) (defun %set-format-directive-expander (char fn) - (let ((code (sb-xc:char-code (char-upcase char)))) + (let ((code (char-code (char-upcase char)))) (setf (aref *format-directive-expanders* code) fn)) char) @@ -561,7 +593,7 @@ (def-format-directive #\C (colonp atsignp params string end) (expand-bind-defaults () params - (let ((n-arg (sb-xc:gensym "ARG"))) + (let ((n-arg (gensym "ARG"))) `(let ((,n-arg ,(expand-next-arg))) (unless (typep ,n-arg 'character) (format-error-at ,string ,(1- end) @@ -615,7 +647,7 @@ ((base nil) (mincol 0) (padchar #\space) (commachar #\,) (commainterval 3)) params - (let ((n-arg (sb-xc:gensym "ARG"))) + (let ((n-arg (gensym "ARG"))) `(let ((,n-arg ,(expand-next-arg))) (unless (or ,base (integerp ,n-arg)) @@ -810,6 +842,7 @@ `(handler-bind ((format-error (lambda (condition) + (declare (optimize (sb-c:store-source-form 0))) (error 'format-error :complaint "~A~%while processing indirect format string:" @@ -1008,6 +1041,7 @@ `((handler-bind ((format-error (lambda (condition) + (declare (optimize (sb-c:store-source-form 0))) (format-error-at* ,string ,(1- end) "~A~%while processing indirect format string:" @@ -1279,7 +1313,7 @@ (block nil ,@(when newline-segment-p `((setf newline-segment - (with-simple-output-to-string (stream) + (%with-output-to-string (stream) ,@(expand-directive-list (pop segments)))) ,(expand-bind-defaults ((extra 0) @@ -1287,7 +1321,7 @@ (directive-params first-semi) `(setf extra-space ,extra line-len ,line-len)))) ,@(mapcar (lambda (segment) - `(push (with-simple-output-to-string (stream) + `(push (%with-output-to-string (stream) ,@(expand-directive-list segment)) segments)) segments)) @@ -1305,7 +1339,7 @@ (collect ((param-names) (bindings)) (dolist (param-and-offset params) (let ((param (cdr param-and-offset))) - (let ((param-name (sb-xc:gensym "PARAM"))) + (let ((param-name (gensym "PARAM"))) (param-names param-name) (bindings `(,param-name ,(case param @@ -1436,7 +1470,7 @@ ((not (directive-colonp close)) (values 0 0 directives)) ((directive-atsignp justification) - (values 0 sb-xc:call-arguments-limit directives)) + (values 0 call-arguments-limit directives)) ;; FIXME: here we could assert that the ;; corresponding argument was a list. (t (values 1 1 remaining)))))) @@ -1472,7 +1506,7 @@ ;; a format control (either a function or a string). (if (directive-atsignp iteration) (values (if (zerop posn) 1 0) - sb-xc:call-arguments-limit + call-arguments-limit remaining) ;; FIXME: the argument corresponding to this ;; directive must be a list. @@ -1483,7 +1517,7 @@ (loop (let ((directive (pop directives))) (when (null directive) - (return (values min (min max sb-xc:call-arguments-limit)))) + (return (values min (min max call-arguments-limit)))) (when (format-directive-p directive) (incf-both (count :arg (directive-params directive) :key #'cdr)) @@ -1508,7 +1542,7 @@ (cond ((directive-atsignp directive) (incf min) - (setq max sb-xc:call-arguments-limit)) + (setq max call-arguments-limit)) (t (incf-both 2)))) (t (throw 'give-up-format-string-walk nil)))))))))) (catch 'give-up-format-string-walk @@ -1581,3 +1615,7 @@ (sb-c:define-source-transform write-to-string (object &rest keys) (expand 'write-to-string object keys))) + +#-sb-xc-host +(defun !late-format-init () + (setq sb-format::**tokenize-control-string-cache-vector** nil)) diff --git a/src/code/full-eval.lisp b/src/code/full-eval.lisp index cd28b943af..c71daec753 100644 --- a/src/code/full-eval.lisp +++ b/src/code/full-eval.lisp @@ -323,14 +323,20 @@ (let*-like-bindings nil)) (cond ((< arguments-present required-length) - (ip-error "~@<Too few arguments in ~S to satisfy lambda list ~S.~:@>" + (ip-error (sb-format:tokens + "~@<Too few arguments in ~S to satisfy lambda list ~ + ~/sb-impl:print-lambda-list/.~:@>") arguments lambda-list)) ((and (not (or rest-p keyword-p)) keywords-present-p) - (ip-error "~@<Too many arguments in ~S to satisfy lambda list ~S.~:@>" + (ip-error (sb-format:tokens + "~@<Too many arguments in ~S to satisfy lambda list ~ + ~/sb-impl:print-lambda-list/.~:@>") arguments lambda-list)) ((and keyword-p keywords-present-p (oddp (- arguments-present non-keyword-arguments))) - (ip-error "~@<Odd number of &KEY arguments in ~S for ~S.~:@>" + (ip-error (sb-format:tokens + "~@<Odd number of &KEY arguments in ~S for ~ + /sb-impl:print-lambda-list/.~:@>") arguments lambda-list))) (dotimes (i required-length) (push (cons (pop required) (pop arguments)) let-like-bindings)) @@ -356,7 +362,9 @@ (loop for (key value) on keyword-plist by #'cddr doing (when (and (not (eq key :allow-other-keys)) (not (member key keyword :key #'keyword-key))) - (ip-error "~@<Unknown &KEY argument ~S in ~S for ~S.~:@>" + (ip-error (sb-format:tokens + "~@<Unknown &KEY argument ~S in ~S for ~ + ~/sb-impl:print-lambda-list/.~:@>") key original-arguments lambda-list)))) (dolist (keyword-spec keyword) (let ((supplied (getf keyword-plist (keyword-key keyword-spec) @@ -601,6 +609,23 @@ (t (return (values form documentation declarations lambda-list)))) finally (return (values nil documentation declarations lambda-list)))) +(defun make-interpreted-function + (&key name lambda-list env declarations documentation body source-location + (debug-lambda-list lambda-list)) + (let ((function (%make-interpreted-function + name name lambda-list debug-lambda-list env + declarations documentation body source-location))) + (setf (%funcallable-instance-fun function) + #'(lambda (&rest args) + (interpreted-apply function args))) + function)) + +(defmethod print-object ((obj interpreted-function) stream) + (print-unreadable-object (obj stream + :identity (not (interpreted-function-name obj))) + (format stream "~A ~A" '#:interpreted-function + (interpreted-function-name obj)))) + ;;; Create an interpreted function from the lambda-form EXP evaluated ;;; in the environment ENV. (defun eval-lambda (exp env) @@ -1004,6 +1029,8 @@ (sb-sys:with-pinned-objects ((%eval (car values) env)) (eval-with-pinned-objects (cons (cdr values) body) env))))) +(defparameter *eval-level* -1) +(defparameter *eval-verbose* nil) (defvar *eval-dispatch-functions* nil) ;;; Dispatch to the appropriate EVAL-FOO function based on the contents of EXP. diff --git a/src/code/function-names.lisp b/src/code/function-names.lisp index 999da69f7a..c96a656c32 100644 --- a/src/code/function-names.lisp +++ b/src/code/function-names.lisp @@ -1,7 +1,7 @@ (in-package "SB-IMPL") ;;;; generalized function names -(!define-load-time-global *valid-fun-names-alist* nil) +(define-load-time-global *valid-fun-names-alist* nil) (defun %define-fun-name-syntax (symbol checker) (let ((found (assoc symbol *valid-fun-names-alist* :test #'eq))) @@ -10,12 +10,6 @@ (setq *valid-fun-names-alist* (acons symbol checker *valid-fun-names-alist*))))) -#+sb-xc-host -(setf (get '%define-fun-name-syntax :sb-cold-funcall-handler/for-effect) - (lambda (symbol checker) - (cold-target-push (cold-cons (cold-intern symbol) checker) - '*valid-fun-names-alist*))) - (defmacro define-function-name-syntax (symbol (var) &body body) "Define function names of the form of a list headed by SYMBOL to be a legal function name, subject to restrictions imposed by BODY. BODY @@ -60,8 +54,15 @@ use as a BLOCK name in the function in question." (cons (unless (member (car fun) '(cas setf)) (valid-function-name-p fun)))))))) -;; CAS and SETF names should have in common the aspect that -;; (CAS (CAS BAZ)), (SETF (CAS BAZ)), (CAS (SETF BAZ)) are not reasonable. -;; 'cas.lisp' doesn't need to know this technique for sharing the parser, -;; so the name syntax is defined here instead of there. -(%define-fun-name-syntax 'cas #'%check-setf-fun-name) +;;; FBOUNDP wants to know what names are valid early on in COLD-INIT. +(defun !function-names-init () + (setq *valid-fun-names-alist* nil) + ;; CAS and SETF names should have in common the aspect that + ;; (CAS (CAS BAZ)), (SETF (CAS BAZ)), (CAS (SETF BAZ)) are not reasonable. + ;; 'cas.lisp' doesn't need to know this technique for sharing the parser, + ;; so the name syntax is defined here instead of there. + (%define-fun-name-syntax 'setf #'%check-setf-fun-name) + (%define-fun-name-syntax 'cas #'%check-setf-fun-name)) + +#+sb-xc-host +(!function-names-init) diff --git a/src/code/funutils.lisp b/src/code/funutils.lisp index acdf365da5..13d87add92 100644 --- a/src/code/funutils.lisp +++ b/src/code/funutils.lisp @@ -41,10 +41,10 @@ ;;; some commonly-occurring CONSTANTLY forms (macrolet ((def-constantly-fun (name constant-expr) - `(progn - (declaim (ftype (sfunction * (eql ,constant-expr)) ,name)) - (setf (symbol-function ',name) - (constantly ,constant-expr))))) + `(defun ,name (&rest arguments) + (declare (ignore arguments)) + (declare (optimize (speed 3) (safety 0) (debug 0))) + ,constant-expr))) (def-constantly-fun constantly-t t) (def-constantly-fun constantly-nil nil) (def-constantly-fun constantly-0 0)) diff --git a/src/code/gc.lisp b/src/code/gc.lisp index 7856a17fdd..fc95cf31be 100644 --- a/src/code/gc.lisp +++ b/src/code/gc.lisp @@ -13,30 +13,19 @@ ;;;; DYNAMIC-USAGE and friends -#+gencgc -(define-alien-variable ("DYNAMIC_SPACE_START" sb-vm:dynamic-space-start) os-vm-size-t) -#-sb-fluid -(declaim (inline current-dynamic-space-start)) -(defun current-dynamic-space-start () - #+gencgc sb-vm:dynamic-space-start - #-gencgc (extern-alien "current_dynamic_space" unsigned-long)) - -#+(or x86 x86-64) -(progn - (declaim (inline dynamic-space-free-pointer)) - (defun dynamic-space-free-pointer () - (extern-alien "dynamic_space_free_pointer" system-area-pointer))) +(defun dynamic-space-obj-p (x) ; X must not be an immediate object + (with-pinned-objects (x) + (let ((addr (get-lisp-obj-address x))) + (< sb-vm:dynamic-space-start addr (sap-int (dynamic-space-free-pointer)))))) -#-sb-fluid (declaim (inline dynamic-usage)) -#+gencgc -(defun dynamic-usage () - (extern-alien "bytes_allocated" os-vm-size-t)) -#-gencgc (defun dynamic-usage () + #+gencgc + (extern-alien "bytes_allocated" os-vm-size-t) + #-gencgc (truly-the word (- (sap-int (sb-c::dynamic-space-free-pointer)) - (current-dynamic-space-start)))) + sb-vm:dynamic-space-start))) (defun static-space-usage () (- (sap-int sb-vm:*static-space-free-pointer*) sb-vm:static-space-start)) @@ -65,6 +54,13 @@ (define-load-time-global *n-bytes-freed-or-purified* 0) (defun gc-reinit () (setq *gc-inhibit* nil) + ;; This GC looks utterly unnecessary, but when I tried removing it, + ;; I got heap exhaustions sooner than when I left it in. + ;; So why is that? Well, it seems like there's some state that is getting + ;; saved into the core which needs resetting, such as these SETQs, + ;; but how is that affecting the C runtime's decision on when to + ;; perform the first auto-triggered GC? How is not doing an explicit + ;; GC delaying the decision? It seems wrong. (gc) (setf *n-bytes-freed-or-purified* 0 *gc-run-time* 0)) @@ -79,10 +75,63 @@ SB-PROFILE package does), or to design a more microefficient interface and submit it as a patch." (+ (dynamic-usage) *n-bytes-freed-or-purified*)) + +(defun primitive-object-size (object) + "Return number of bytes of heap or stack directly consumed by OBJECT" + (cond ((not (sb-vm:is-lisp-pointer (get-lisp-obj-address object))) 0) + ((eq object nil) (ash sb-vm::sizeof-nil-in-words sb-vm:word-shift)) + ((simple-fun-p object) (code-object-size (fun-code-header object))) + #-(or x86 x86-64 arm64 riscv) ((lra-p object) 1) + (t + (with-alien ((sizer (function unsigned unsigned) :extern "primitive_object_size")) + (with-pinned-objects (object) + (alien-funcall sizer (get-lisp-obj-address object))))))) + +(defun sb-vm:hexdump (thing &optional (n-words nil wordsp) + ;; pass NIL explicitly if T crashes on you + (decode t)) + (multiple-value-bind (obj addr count) + (if (typep thing 'word) ; ambiguous in the edge case, but assume it's + ;; an address (though you might be trying to dump a bignum's data) + (values nil thing (if wordsp n-words 1)) + (values + thing + (logandc2 (get-lisp-obj-address thing) sb-vm:lowtag-mask) + (if wordsp + n-words + (if (and (typep thing 'code-component) (plusp (code-n-entries thing))) + ;; Display up through the first fun header + (+ (code-header-words thing) + (ash (%code-fun-offset thing 0) (- sb-vm:word-shift)) + sb-vm:simple-fun-insts-offset) + ;; at most 16 words + (min 16 (ash (primitive-object-size thing) (- sb-vm:word-shift))))))) + (with-pinned-objects (obj) + (dotimes (i count) + (let ((word (sap-ref-word (int-sap addr) (ash i sb-vm:word-shift)))) + (multiple-value-bind (lispobj ok fmt) + (cond ((and (typep thing 'code-component) + (< 1 i (code-header-words thing))) + (values (code-header-ref thing i) t)) + #+compact-symbol + ((and (typep thing '(and symbol (not null))) + (= i sb-vm:symbol-name-slot)) + (values (list (sb-impl::symbol-package-id thing) + (symbol-name thing)) + t + "{~{~A,~S~}}")) + (decode + (make-lisp-obj word nil))) + (let ((*print-lines* 1) + (*print-pretty* t)) + (format t "~x: ~v,'0x~:[~; = ~@?~]~%" + (+ addr (ash i sb-vm:word-shift)) + (* 2 sb-vm:n-word-bytes) + word ok (or fmt "~S") lispobj)))))))) ;;;; GC hooks -(!define-load-time-global *after-gc-hooks* nil +(define-load-time-global *after-gc-hooks* nil "Called after each garbage collection, except for garbage collections triggered during thread exits. In a multithreaded environment these hooks may run in any thread.") @@ -90,8 +139,7 @@ run in any thread.") ;;;; internal GC -(define-alien-routine collect-garbage int - (#+gencgc last-gen #-gencgc ignore int)) +(define-alien-routine collect-garbage int (last-gen int)) #+(or sb-thread sb-safepoint) (progn @@ -102,35 +150,10 @@ run in any thread.") (defun gc-stop-the-world ()) (defun gc-start-the-world ())) -#+gencgc -(progn - (define-alien-variable ("gc_logfile" %gc-logfile) (* char)) - (defun (setf gc-logfile) (pathname) - (let ((new (when pathname - (make-alien-string - (native-namestring (translate-logical-pathname pathname) - :as-file t)))) - (old %gc-logfile)) - (setf %gc-logfile new) - (when old - (free-alien old)) - pathname)) - (defun gc-logfile () - "Return the pathname used to log garbage collections. Can be SETF. -Default is NIL, meaning collections are not logged. If non-null, the -designated file is opened before and after each collection, and generation -statistics are appended to it." - (let ((val (cast %gc-logfile c-string))) - (when val - (native-pathname val))))) - (declaim (inline dynamic-space-size)) (defun dynamic-space-size () "Size of the dynamic space in bytes." (extern-alien "dynamic_space_size" os-vm-size-t)) -#+gencgc -(define-symbol-macro sb-vm:dynamic-space-end - (+ (dynamic-space-size) sb-vm:dynamic-space-start)) ;;;; SUB-GC @@ -149,7 +172,13 @@ statistics are appended to it." ;;; For GENCGC all generations < GEN will be GC'ed. -(define-load-time-global *already-in-gc* (sb-thread:make-mutex :name "GC lock")) +(defmacro try-acquire-gc-lock (&rest forms) + #-sb-thread `(progn ,@forms t) + #+sb-thread + `(when (eql (alien-funcall (extern-alien "try_acquire_gc_lock" (function int))) 1) + ,@forms + (alien-funcall (extern-alien "release_gc_lock" (function void))) + t)) (defun sub-gc (gen) (cond (*gc-inhibit* @@ -195,8 +224,6 @@ statistics are appended to it." ;; Let's make sure we're not interrupted and that none of ;; the deadline or deadlock detection stuff triggers. (without-interrupts - (sb-thread::without-thread-waiting-for - (:already-without-interrupts t) (let ((sb-impl::*deadline* nil) (epoch *gc-epoch*)) (loop @@ -210,10 +237,9 @@ statistics are appended to it." ;; execute the remainder of the GC: stopping the ;; world with interrupts disabled is the mother of ;; all critical sections. - (cond ((sb-thread:with-mutex (*already-in-gc* :wait-p nil) + (cond ((try-acquire-gc-lock (unsafe-clear-roots gen) - (gc-stop-the-world) - t) + (gc-stop-the-world)) ;; Success! GC. (perform-gc) ;; Return, but leave *gc-pending* as is: we @@ -240,8 +266,19 @@ statistics are appended to it." ;; runtime. (when (and (eql gen 0) (neq epoch *gc-pending*)) - (return 0)))))))))) + (return 0))))))))) +#+sb-thread +(defun post-gc () + (sb-impl::finalizer-thread-notify) + (alien-funcall (extern-alien "empty_thread_recyclebin" (function void))) + ;; Post-GC actions are invoked synchronously by the GCing thread, + ;; which is an arbitrary one. If those actions aquire any locks, or are sensitive + ;; to the state of *ALLOW-WITH-INTERRUPTS*, any deadlocks of what-have-you + ;; are user error. Hooks need to be sufficiently uncomplicated as to be harmless. + (call-hooks "after-GC" *after-gc-hooks* :on-error :warn)) + +#-sb-thread (defun post-gc () ;; Outside the mutex, interrupts may be enabled: these may cause ;; another GC. FIXME: it can potentially exceed maximum interrupt @@ -253,33 +290,48 @@ statistics are appended to it." ;; ;; KLUDGE: Don't run the hooks in GC's if: ;; - ;; A) this thread is dying, so that user-code never runs with - ;; (thread-alive-p *current-thread*) => nil + ;; A) this thread is dying or just born, so that user-code never runs with + ;; (thread-alive-p *current-thread*) => nil. + ;; The just-born case can happen with foreign threads that are unlucky + ;; enough to be elected to perform GC just as they begin executing + ;; ENTER-FOREIGN-CALLBACK. This definitely seems to happen with sb-safepoint. + ;; I'm not sure whether it can happen without sb-safepoint. ;; ;; B) interrupts are disabled somewhere up the call chain since we ;; don't want to run user code in such a case. ;; + ;; Condition (A) is tested in the C runtime at can_invoke_post_gc(). + ;; Condition (B) is tested here. ;; The long-term solution will be to keep a separate thread for ;; after-gc hooks. ;; Finalizers are in a separate thread (usually), ;; but it's not permissible to invoke CONDITION-NOTIFY from a ;; dying thread, so we still need the guard for that, but not ;; the guard for whether interupts are enabled. - (when (sb-thread:thread-alive-p sb-thread:*current-thread*) - (let ((threadp #+sb-thread (%instancep sb-impl::*finalizer-thread*))) - (when threadp - ;; It's OK to frob a condition variable regardless of - ;; *allow-with-interrupts*, and probably OK to start a thread. - ;; For consistency with the previous behavior, we delay finalization - ;; if there is no finalizer thread and interrupts are disabled. - ;; That's my excuse anyway, not having looked more in-depth. - (run-pending-finalizers)) - (when *allow-with-interrupts* - (sb-thread::without-thread-waiting-for () - (with-interrupts - (unless threadp - (run-pending-finalizers)) - (call-hooks "after-GC" *after-gc-hooks* :on-error :warn))))))) + + ;; Here's one reason that MAX_INTERRUPTS is as high as it is. + ;; If the thread that performed GC runs post-GC hooks which cons enough to + ;; cause another GC while in the hooks, then as soon as interrupts are allowed + ;; again, a GC can be invoked "recursively" - while there is a maybe_gc() on + ;; the C call stack. It's not even true that _this_ thread had to cons a ton - + ;; any thread could have, causing this thread to hit the GC trigger which sets the + ;; P-A interrupted bit which causes the interrupt instruction at the end of a + ;; pseudo-atomic sequence to take a signal hit. So with interrupts eanbled, + ;; we get back into the GC, which calls post-GC, which might cons ... + ;; See the example at the bottom of src/code/final for a clear picture. + ;; Logically, the finalizer existence test belongs in src/code/final, + ;; but the flaw in that is we're not going to call that code until unmasking + ;; interrupts, which is precisely the thing we need to NOT do if already + ;; in post-GC code of any kind (be it finalizer or other). + (when (and *allow-with-interrupts* + (or (and (sb-impl::hash-table-culled-values + (sb-impl::finalizer-id-map sb-impl::**finalizer-store**)) + (not sb-impl::*in-a-finalizer*)) + *after-gc-hooks*)) + (sb-thread::without-thread-waiting-for () + (with-interrupts + (run-pending-finalizers) + (call-hooks "after-GC" *after-gc-hooks* :on-error :warn))))) ;;; This is the user-advertised garbage collection function. (defun gc (&key (full nil) (gen 0) &allow-other-keys) @@ -347,7 +399,7 @@ Note: currently changes to this value are lost when saving core." (extern-alien "bytes_consed_between_gcs" os-vm-size-t)) (defun (setf bytes-consed-between-gcs) (val) - (declare (type index val)) + (declare (type (and fixnum unsigned-byte) val)) (setf (extern-alien "bytes_consed_between_gcs" os-vm-size-t) val)) @@ -360,16 +412,33 @@ Note: currently changes to this value are lost when saving core." ;;;; GENCGC specifics ;;;; -;;;; For documentation convenience, these have stubs on non-GENCGC platforms -;;;; as well. -#+gencgc +(define-alien-variable ("gc_logfile" %gc-logfile) (* char)) + +(defun (setf gc-logfile) (pathname) + (let ((new (when pathname + (make-alien-string + (native-namestring (translate-logical-pathname pathname) + :as-file t)))) + (old %gc-logfile)) + (setf %gc-logfile new) + (when old + (free-alien old)) + pathname)) +(defun gc-logfile () + "Return the pathname used to log garbage collections. Can be SETF. +Default is NIL, meaning collections are not logged. If non-null, the +designated file is opened before and after each collection, and generation +statistics are appended to it." + (let ((val (cast %gc-logfile c-string))) + (when val + (native-pathname val)))) + (deftype generation-index () `(integer 0 ,sb-vm:+pseudo-static-generation+)) ;;; FIXME: GENERATION (and PAGE, as seen in room.lisp) should probably be ;;; defined in Lisp, and written to header files by genesis, instead of this ;;; OAOOMiness -- this duplicates the struct definition in gencgc.c. -#+gencgc (define-alien-type generation (struct generation (bytes-allocated os-vm-size-t) @@ -380,34 +449,79 @@ Note: currently changes to this value are lost when saving core." (cum-sum-bytes-allocated os-vm-size-t) (minimum-age-before-gc double))) -#+gencgc (define-alien-variable generations (array generation #.(1+ sb-vm:+pseudo-static-generation+))) -(macrolet ((def (slot doc &optional setfp) +;;; Why is PAGE-INDEX-T in SB-KERNEL but PAGE and the page table are in SB-VM? +(define-alien-type (struct sb-vm::page) + (struct sb-vm::page + ;; To cut down the size of the page table, the scan_start_offset + ;; - a/k/a "start" - is measured in 4-byte integers regardless + ;; of word size. This is fine for 32-bit address space, + ;; but if 64-bit then we have to scale the value. Additionally + ;; there is a fallback for when even the scaled value is too big. + (sb-vm::start #+64-bit (unsigned 32) #-64-bit signed) + ;; Caution: The low bit of WORDS-USED* is a flag bit + (sb-vm::words-used* (unsigned 16)) ; (* in the name is a memory aid) + (sb-vm::flags (unsigned 8)) ; this named 'type' in C + (sb-vm::gen (signed 8)))) +(define-alien-variable ("page_table" sb-vm:page-table) (* (struct sb-vm::page))) +(declaim (inline sb-vm:find-page-index)) +(define-alien-routine ("ext_find_page_index" sb-vm:find-page-index) page-index-t (address unsigned)) + +(defun generation-of (object) + (with-pinned-objects (object) + (let* ((addr (get-lisp-obj-address object)) + (page (sb-vm:find-page-index addr))) + (cond ((>= page 0) (slot (deref sb-vm:page-table page) 'sb-vm::gen)) + #+immobile-space + ((immobile-space-addr-p addr) + ;; SIMPLE-FUNs don't contain a generation byte + (when (simple-fun-p object) + (setq addr (get-lisp-obj-address (fun-code-header object)))) + (let ((sap (int-sap (logandc2 addr sb-vm:lowtag-mask)))) + (logand (if (fdefn-p object) (sap-ref-8 sap 1) (sap-ref-8 sap 3)) + #xF))))))) + +(export 'page-protected-p) +(macrolet ((addr->mark (addr) + `(sap-ref-8 (extern-alien "gc_card_mark" system-area-pointer) + (logand (ash ,addr (- (integer-length (1- sb-vm:gencgc-card-bytes)))) + (extern-alien "gc_card_table_mask" int)))) + (markedp (val) + #+soft-card-marks `(eql ,val 0) + ;; With physical protection there are 2 single-bit fields packed in the mark byte. + ;; The 0 bit is the card mark bit (inverse of protected-p) + #-soft-card-marks `(oddp ,val))) + (defun page-protected-p (object) ; OBJECT must be pinned by caller + (not (markedp (addr->mark (get-lisp-obj-address object))))) + (defun object-card-marks (obj) + (aver (eq (heap-allocated-p obj) :dynamic)) + ;; Return a bit-vector with a 1 for each marked card the object is on + ;; and a 0 for each unmarked card. + (with-pinned-objects (obj) + (let* ((base (logandc2 (get-lisp-obj-address obj) sb-vm:lowtag-mask)) + (last (+ base (1- (primitive-object-size obj)))) + (aligned-base (logandc2 base (1- sb-vm:gencgc-card-bytes))) + (aligned-last (logandc2 last (1- sb-vm:gencgc-card-bytes))) + (result (make-array (1+ (truncate (- aligned-last aligned-base) + sb-vm:gencgc-card-bytes)) + :element-type 'bit))) + (loop for addr from aligned-base to aligned-last by sb-vm:gencgc-card-bytes + for i from 0 + do (setf (aref result i) (if (markedp (addr->mark addr)) 1 0))) + result)))) + +(macrolet ((def (slot doc &optional adjustable) `(progn (defun ,(symbolicate "GENERATION-" slot) (generation) ,doc - #+gencgc (declare (generation-index generation)) - #-gencgc - (declare (ignore generation)) - #-gencgc - (error "~S is a GENCGC only function and unavailable in this build" - ',slot) - #+gencgc (slot (deref generations generation) ',slot)) - ,@(when setfp - `((defun (setf ,(symbolicate "GENERATION-" slot)) (value generation) - #+gencgc - (declare (generation-index generation)) - #-gencgc - (declare (ignore value generation)) - #-gencgc - (error "(SETF ~S) is a GENCGC only function and unavailable in this build" - ',slot) - #+gencgc - (setf (slot (deref generations generation) ',slot) value))))))) + ,@(when adjustable + `((defun (setf ,(symbolicate "GENERATION-" slot)) (value generation) + (declare (generation-index generation)) + (setf (slot (deref generations generation) ',slot) value))))))) (def bytes-consed-between-gcs "Number of bytes that can be allocated to GENERATION before that generation is considered for garbage collection. This value is meaningless for @@ -441,26 +555,20 @@ Experimental: interface subject to change.") "Number of times garbage collection has been done on GENERATION without promotion. Available on GENCGC platforms only. -Experimental: interface subject to change.")) +Experimental: interface subject to change.") (defun generation-average-age (generation) "Average age of memory allocated to GENERATION: average number of times objects allocated to the generation have seen younger objects promoted to it. Available on GENCGC platforms only. Experimental: interface subject to change." - #+gencgc (declare (generation-index generation)) - #-gencgc (declare (ignore generation)) - #-gencgc - (error "~S is a GENCGC only function and unavailable in this build." - 'generation-average-age) - #+gencgc (alien-funcall (extern-alien "generation_average_age" (function double generation-index-t)) - generation)) + generation))) (macrolet ((cases () - `(cond ((< (current-dynamic-space-start) addr + `(cond ((< sb-vm:dynamic-space-start addr (sap-int (dynamic-space-free-pointer))) :dynamic) ((immobile-space-addr-p addr) :immobile) @@ -472,20 +580,27 @@ Experimental: interface subject to change." :static)))) ;;; Return true if X is in any non-stack GC-managed space. ;;; (Non-stack implies not TLS nor binding stack) -;;; This assumes a single contiguous dynamic space, which is of course a -;;; bad assumption, but nonetheless one that has been true for, say, ~20 years. -;;; Also note, we don't have to pin X - an object can not move between spaces, -;;; so a non-nil answer is the definite answer. As to whether the object could -;;; have moved, or worse, died - by say reusing the same register as held X for -;;; the value that is (get-lisp-obj-address X), with no surrounding pin or even -;;; reference to X - then that's your problem. -;;; If you wanted the object not to die or move, you should have held on tighter! +;;; There's a microscopic window of time in which next_free_page for dynamic space +;;; could _decrease_ after calculating the address of X, so we'll pin X +;;; to ensure that can't happen. (defun heap-allocated-p (x) - (let ((addr (get-lisp-obj-address x))) - (and (sb-vm:is-lisp-pointer addr) - (cases)))) + (with-pinned-objects (x) + (let ((addr (get-lisp-obj-address x))) + (and (sb-vm:is-lisp-pointer addr) + (cases))))) ;;; Internal use only. FIXME: I think this duplicates code that exists ;;; somewhere else which I could not find. (defun lisp-space-p (sap &aux (addr (sap-int sap))) (cases)) ) ; end MACROLET + +(define-condition memory-fault-error (system-condition error) () + (:report + (lambda (condition stream) + (let* ((faultaddr (system-condition-address condition)) + (string (if (<= sb-vm:read-only-space-start + faultaddr + (sap-int (sap+ sb-vm:*read-only-space-free-pointer* -1))) + "Attempt to modify a read-only object at #x~X." + "Unhandled memory fault at #x~X."))) + (format stream string faultaddr))))) diff --git a/src/code/globals.lisp b/src/code/globals.lisp index 843f4ab2a7..45d517d21c 100644 --- a/src/code/globals.lisp +++ b/src/code/globals.lisp @@ -19,7 +19,7 @@ ;;; to running into any errors, or else you've got twice the trouble. ;;; ;;; There are other thread-locals which are used by C code, and those are all -;;; defined in !PER-THREAD-C-INTERFACE-SYMBOLS. Those other symbols must have +;;; defined in PER-THREAD-C-INTERFACE-SYMBOLS. Those other symbols must have ;;; initial values of either a fixnum or a static symbol (typically T or NIL). ;;; ;;; In contrast, DEFINE-THREAD-LOCAL allows more-or-less an arbitrary form, @@ -37,17 +37,10 @@ docstring) `(locally (declare (notinline (setf info))) - ;; This initial value expression is a mite confusing. - ;; Most thread-locals that we use are of the :ALWAYS-BOUNDP kind, and since the - ;; value is stuffed in the moment a thread is created, no value is ever needed here, - ;; because this value form is evaluated exactly once (in cold-init) and never again. - ;; But if not always bound, we have a problem: INIT-THREAD-LOCAL-STORAGE writes - ;; an unbound marker, which makes this DEFVAR want to compute something. - ;; But that "something" has to be the unbound marker. - (defvar ,name ,(if always-boundp - `(error "~S had no value in cold-init" ',name) - initform) - ,docstring) + ;; We don't error here on ALWAYS-BOUND variables as they may have + ;; variable reference initforms that aren't initialized until + ;; later in cold-init. + (defvar ,name ,initform ,docstring) ;; :EXECUTE is for parallelized make-host-2 to see the compile-toplevel effect (eval-when (:compile-toplevel :execute) (%define-thread-local ',name ',initform ',always-boundp)) @@ -65,15 +58,14 @@ (let ((found (assq symbol (cdr list)))) (if found (setf (cadr found) initform) - (let* ((thread-struct (find 'sb-vm::thread sb-vm:*primitive-objects* - :key #'sb-vm:primitive-object-name)) + (let* ((thread-struct (sb-vm::primitive-object 'sb-vm::thread)) (n-fixed (+ (sb-vm:primitive-object-length thread-struct) (count-if-not (lambda (x) (find (car (ensure-list x)) (sb-vm:primitive-object-slots thread-struct) :key #'sb-vm:slot-special)) - sb-vm::!per-thread-c-interface-symbols))) + sb-vm::per-thread-c-interface-symbols))) (tls-slot (+ n-fixed (length (cdr list))))) (nconc list (list (list symbol initform))) (setf (info :variable :wired-tls symbol) (ash tls-slot sb-vm:word-shift)) @@ -84,7 +76,7 @@ ;;; by RESTART-BIND. (define-thread-local *restart-clusters* nil) -(define-load-time-global sb-kernel::**initial-handler-clusters** nil) +(define-load-time-global sb-kernel::**initial-handler-clusters** '(nil)) ;;; a list of handlers maintained by HANDLER-BIND (define-thread-local *handler-clusters* sb-kernel::**initial-handler-clusters**) @@ -95,7 +87,6 @@ *posix-argv*)) ;;; This constant is assigned by Genesis and never read by Lisp code. ;;; (To prove that it isn't used, it's not a toplevel form) -#+linkage-table (let () (defconstant sb-vm::+required-foreign-symbols+ (symbol-value 'sb-vm::+required-foreign-symbols+))) diff --git a/src/code/hash-table.lisp b/src/code/hash-table.lisp index 6fecf8bdad..61a71eab2c 100644 --- a/src/code/hash-table.lisp +++ b/src/code/hash-table.lisp @@ -52,16 +52,18 @@ ;;; The PAIRS vector has an odd length with the following overhead elements: ;;; -;;; [0] = backpointer to hash-table +;;; [0] = high-water-mark ;;; [1] = rehash-due-to-GC indicator ;;; ... -;;; [length-1] = high-water-mark +;;; [length-1] = auxiliary info depending on kind of table +;;; See KV-VECTOR-AUX-INFO in 'target-hash-table' ;;; HASH-TABLE is implemented as a STRUCTURE-OBJECT. (sb-xc:deftype hash-table-index () '(unsigned-byte 32)) (sb-xc:defstruct (hash-table (:copier nil) - (:constructor %make-hash-table - (gethash-impl + (:constructor %alloc-hash-table + (flags + gethash-impl puthash-impl remhash-impl clrhash-impl @@ -73,13 +75,12 @@ pairs index-vector next-vector - hash-vector - flags))) + hash-vector))) - (gethash-impl #'error :type function :read-only t) - (puthash-impl #'error :type function :read-only t) - (remhash-impl #'error :type function :read-only t) - (clrhash-impl #'error :type function :read-only t) + (gethash-impl #'error :type (sfunction * (values t boolean)) :read-only t) + (puthash-impl #'error :type (sfunction * t) :read-only t) + (remhash-impl #'error :type (sfunction * t) :read-only t) + (clrhash-impl #'error :type (sfunction * t) :read-only t) ;; The Key-Value pair vector. ;; Note: this vector has a "high water mark" which resembles a fill ;; pointer, but unlike a fill pointer, GC can ignore elements @@ -106,22 +107,25 @@ ;; +MAGIC-HASH-VECTOR-VALUE+ represents address-based hashing on the ;; respective key. (hash-vector nil :type (or null (simple-array hash-table-index (*)))) - ;; flags: WEAKNESS-KIND | WEAKP | FINALIZERSP | USERFUNP | SYNCHRONIZEDP - ;; WEAKNESS-KIND is 2 bits, the rest are 1 bit each + ;; flags: WEAKNESS | KIND | WEAKP | FINALIZERSP | USERFUNP | SYNCHRONIZEDP + ;; WEAKNESS is 2 bits, KIND is 2 bits, the rest are 1 bit each + ;; - WEAKNESS : {K-and-V, K, V, K-or-V}, irrelevant unless WEAKP + ;; - KIND : {EQ, EQL, EQUAL, EQUALP}, irrelevant if USERFUNP ;; - WEAKP : table is weak ;; - FINALIZERSP : table is the global finalizer store - ;; - USERFUNP : table has a user-defined predicate + ;; - USERFUNP : table has a nonstandard hash function ;; - SYCHRONIZEDP : all operations are automatically guarded by a mutex ;; If you change these, be sure to check the definition of hash_table_weakp() ;; in 'gc-private.h' - (flags 0 :type (unsigned-byte 6) :read-only t) + (flags 0 :type (unsigned-byte 8) :read-only t) ;; Used for locking GETHASH/(SETF GETHASH)/REMHASH - (lock (sb-thread:make-mutex :name "hash-table lock") - #-c-headers-only :type #-c-headers-only sb-thread:mutex - :read-only t) + ;; The lock is always created for synchronized tables, or created just-in-time + ;; with nonsynchronized tables that are guarded by WITH-LOCKED-HASH-TABLE + ;; or an equivalent "system" variant of the locking macro. + (%lock nil #-c-headers-only :type #-c-headers-only (or null sb-thread:mutex)) ;; The 4 standard tests functions don't need these next 2 slots: - + ;; (TODO: possibly don't have them in all hash-tables) ;; The function used to compare two keys. Returns T if they are the ;; same and NIL if not. (test-fun nil :type function :read-only t) @@ -130,9 +134,9 @@ ;; next GC. (hash-fun nil :type function :read-only t) - ;; The type of hash table this is. Only used for printing and as - ;; part of the exported interface. - (test nil :type symbol :read-only t) + ;; The type of hash table this is. Part of the exported interface, + ;; as well as needed for the MAKE-LOAD-FORM and PRINT-OBJECT methods. + (test nil :type (or symbol function) :read-only t) ;; How much to grow the hash table by when it fills up. If an index, ;; then add that amount. If a floating point number, then multiply ;; it by that. @@ -156,13 +160,31 @@ ;; Statistics gathering for new gethash algorithm that doesn't ;; disable GC during rehash as a consequence of key movement. - (n-rehash+find 0 :type word) - (n-lsearch 0 :type word) + #+hash-table-metrics (n-rehash+find 0 :type word) + #+hash-table-metrics (n-lsearch 0 :type word) + ;; only for debugging system bootstrap when hash-tables are completely ;; broken (which seems to be quite often as I optimize them) - #+hash-table-simulate (%alist) - - ;;; Supporting slots for weak hash-tables. + #+hash-table-simulate (%alist)) + +(sb-xc:defstruct (general-hash-table (:copier nil) + (:conc-name hash-table-) + (:include hash-table) + (:constructor %alloc-general-hash-table + (flags + gethash-impl + puthash-impl + remhash-impl + clrhash-impl + test + test-fun + hash-fun + rehash-size + rehash-threshold + pairs + index-vector + next-vector + hash-vector))) ;; List of (pair-index . bucket-number) which GC smashed and are almost ;; equivalent to free cells, except that they are not yet unlinked from ;; their chain. Skipping the removal in GC eliminates a race with REMHASH. @@ -176,14 +198,17 @@ ;; List of values (i.e. the second half of the k/v pair) culled out during ;; GC, used only by the finalizer hash-table. This informs Lisp of the IDs ;; (small fixnums) of the finalizers that need to run. - (culled-values nil :type list) - ;; For detecting concurrent accesses. - #+sb-hash-table-debug - (signal-concurrent-access t :type (member nil t)) - #+sb-hash-table-debug - (reading-thread nil) - #+sb-hash-table-debug - (writing-thread nil)) + (culled-values nil :type list)) + +(sb-xc:defmacro hash-table-lock (table) + `(let ((ht ,table)) (or (hash-table-%lock ht) (install-hash-table-lock ht)))) + +(sb-xc:defmacro pack-ht-flags-weakness (x) `(logior (ash ,x 6) hash-table-weak-flag)) +(sb-xc:defmacro ht-flags-weakness (flags) `(ldb (byte 2 6) ,flags)) +;;; KIND corresponds directly to the HASH-TABLE-TEST for the 4 standard tests, +;;; but is not meaningful with a user-provided test or hash function. +(sb-xc:defmacro pack-ht-flags-kind (x) `(ash ,x 4)) +(sb-xc:defmacro ht-flags-kind (flags) `(ldb (byte 2 4) ,flags)) ;; Our hash-tables store precomputed hashes to speed rehash and to guard ;; the call of the general comparator. diff --git a/src/code/host-pprint.lisp b/src/code/host-pprint.lisp index 1c324d9995..c018f56ed3 100644 --- a/src/code/host-pprint.lisp +++ b/src/code/host-pprint.lisp @@ -22,7 +22,7 @@ (:predicate nil)) ;; A list of all the entries (except for CONS entries below) in highest ;; to lowest priority. - (entries nil :type list) + (entries #() :type simple-vector) ;; A hash table mapping things to entries for type specifiers of the ;; form (CONS (MEMBER <thing>)). If the type specifier is of this form, ;; we put it in this hash table instead of the regular entries table. @@ -33,7 +33,3 @@ (only-initial-entries nil :type boolean)) (declaim (freeze-type pprint-dispatch-table)) - -#+sb-xc -(defmethod print-object ((table pprint-dispatch-table) stream) - (print-unreadable-object (table stream :type t :identity t))) diff --git a/src/code/hppa-vm.lisp b/src/code/hppa-vm.lisp deleted file mode 100644 index 4dbdaa1ab5..0000000000 --- a/src/code/hppa-vm.lisp +++ /dev/null @@ -1,78 +0,0 @@ -(in-package "SB-VM") - -#-sb-xc-host -(defun machine-type () - "Returns a string describing the type of the local machine." - "HPPA") - -;;;; FIXUP-CODE-OBJECT -(defconstant-eqx +fixup-kinds+ - #(:absolute :load :load11u :load-short :hi :branch) - #'equalp) -(!with-bigvec-or-sap -(defun fixup-code-object (code offset value kind flavor) - (declare (ignore flavor)) - (unless (zerop (rem offset sb-assem:+inst-alignment-bytes+)) - (error "Unaligned instruction? offset=#x~X." offset)) - (let* ((sap (code-instructions code)) - (inst (sap-ref-32 sap offset))) - (setf (sap-ref-32 sap offset) - (ecase kind - (:absolute - value) - (:load - (logior (mask-field (byte 18 14) value) - (if (< value 0) - (1+ (ash (ldb (byte 13 0) value) 1)) - (ash (ldb (byte 13 0) value) 1)))) - (:load11u - (logior (if (< value 0) - (1+ (ash (ldb (byte 10 0) value) 1)) - (ash (ldb (byte 11 0) value) 1)) - (mask-field (byte 18 14) inst))) - (:load-short - (let ((low-bits (ldb (byte 11 0) value))) - (aver (<= 0 low-bits (1- (ash 1 4)))) - (logior (ash (dpb (ldb (byte 4 0) value) - (byte 4 1) - (ldb (byte 1 4) value)) 17) - (logand inst #xffe0ffff)))) - (:hi - (logior (ash (ldb (byte 5 13) value) 16) - (ash (ldb (byte 2 18) value) 14) - (ash (ldb (byte 2 11) value) 12) - (ash (ldb (byte 11 20) value) 1) - (ldb (byte 1 31) value) - (logand inst #xffe00000))) - (:branch - (let ((bits (ldb (byte 9 2) value))) - (aver (zerop (ldb (byte 2 0) value))) - (logior (ash bits 3) - (mask-field (byte 1 1) inst) - (mask-field (byte 3 13) inst) - (mask-field (byte 11 21) inst))))))) - nil)) - -#-sb-xc-host (progn - -;;; For now. -(defun context-floating-point-modes (context) - (declare (ignore context)) - (warn "stub CONTEXT-FLOATING-POINT-MODES") - 0) - -;;;; Internal-error-arguments. - -;;; INTERNAL-ERROR-ARGUMENTS -- interface. -;;; -;;; Given the sigcontext, extract the internal error arguments from the -;;; instruction stream. -;;; -(defun internal-error-args (context) - (declare (type (alien (* os-context-t)) context)) - (let* ((pc (context-pc context)) - (trap-number (logand (sap-ref-8 pc 3) #x1f))) - (declare (type system-area-pointer pc)) - (sb-kernel::decode-internal-error-args (sap+ pc 5) trap-number - (sap-ref-8 pc 4)))) -) ; end PROGN diff --git a/src/code/hpux-os.lisp b/src/code/hpux-os.lisp deleted file mode 100644 index 379d3d004e..0000000000 --- a/src/code/hpux-os.lisp +++ /dev/null @@ -1,34 +0,0 @@ -;;;; OS interface functions for SBCL under HPUX - -;;;; This software is part of the SBCL system. See the README file for -;;;; more information. -;;;; -;;;; This software is derived from the CMU CL system, which was -;;;; written at Carnegie Mellon University and released into the -;;;; public domain. The software is in the public domain and is -;;;; provided with absolutely no warranty. See the COPYING and CREDITS -;;;; files for more information. - -(in-package "SB-SYS") - -;;; Check that target machine features are set up consistently with -;;; this file. -#-hpux (error "missing :HPUX feature") - -(defun software-type () - "Return a string describing the supporting software." - (values "HPUX")) - -;;; Return system time, user time and number of page faults. -(defun get-system-info () - (multiple-value-bind - (err? utime stime maxrss ixrss idrss isrss minflt majflt) - (sb-unix:unix-getrusage sb-unix:rusage_self) - (declare (ignore maxrss ixrss idrss isrss minflt)) - (unless err? ; FIXME: nonmnemonic (reversed) name for ERR? - (error "Unix system call getrusage failed: ~A." (strerror utime))) - (values utime stime majflt))) - -;;; support for CL:MACHINE-VERSION defined OAOO elsewhere -(defun get-machine-version () - nil) diff --git a/src/code/huffman.lisp b/src/code/huffman.lisp index ff9774e656..faa42661c0 100644 --- a/src/code/huffman.lisp +++ b/src/code/huffman.lisp @@ -14,7 +14,8 @@ (defstruct (huffman-node (:constructor make-huffman-node (key weight)) (:copier nil)) - key weight) + (key nil :read-only t) + (weight nil :read-only t)) (defstruct (huffman-pair (:include huffman-node) @@ -26,7 +27,8 @@ (huffman-node-key right))) (weight (+ (huffman-node-weight left) (huffman-node-weight right)))))) - left right) + (left nil :read-only t) + (right nil :read-only t)) (declaim (freeze-type huffman-node)) (defun huffman-weights (corpus) diff --git a/src/code/icf.lisp b/src/code/icf.lisp index bab37f5212..705d242a45 100644 --- a/src/code/icf.lisp +++ b/src/code/icf.lisp @@ -25,6 +25,7 @@ ;;; Return T if any pointers were replaced in a code object. (defun apply-forwarding-map (map print &aux any-change) + (declare (optimize (sb-c::aref-trapping 0))) (when print (let ((*print-pretty* nil)) (dohash ((k v) map) @@ -47,22 +48,19 @@ (lambda (object widetag size &aux touchedp) (declare (ignore size)) (macrolet ((rewrite (place &aux (accessor (if (listp place) (car place)))) - ;; These two slots have no setters, but nor are - ;; they possibly affected by code folding. - (unless (member accessor '(symbol-name symbol-package)) + ;; SYMBOL-NAME, SYMBOL-PACKAGE, SYMBOL-%INFO have no setters, + ;; but nor are they possibly affected by code folding. + ;; {%INSTANCE,%FUN}-LAYOUT have setters but they are not spelled + ;; SETF, nor are they affected by code folding. + (unless (member accessor '(symbol-name symbol-package symbol-%info + %fun-layout %instance-layout)) `(let* ((oldval ,place) (newval (forward oldval))) (unless (eq newval oldval) ,(case accessor (data-vector-ref `(setf (svref ,@(cdr place)) newval touchedp t)) (value-cell-ref - ;; pinned already because we're iterating over the heap - ;; which disables GC, but maybe some day it won't. - `(with-pinned-objects (object) - (setf (sap-ref-lispobj (int-sap (get-lisp-obj-address object)) - (- (ash value-cell-value-slot word-shift) - other-pointer-lowtag)) - newval))) + `(%primitive value-cell-set object newval)) (weak-pointer-value ;; Preserve gencgc invariant that a weak pointer ;; can't point to an object younger than itself. @@ -73,12 +71,10 @@ #+nil (warn "Can't update weak pointer ~s" object)) (t - (with-pinned-objects (object) - (setf (sap-ref-lispobj - (int-sap (get-lisp-obj-address object)) - (- (ash weak-pointer-value-slot word-shift) - other-pointer-lowtag)) - newval))))) + (%primitive set-slot object newval + '(setf weak-pointer-value) + weak-pointer-value-slot + other-pointer-lowtag)))) (%primitive (ecase (cadr place) (fast-symbol-global-value @@ -89,8 +85,9 @@ (do-referenced-object (object rewrite) (simple-vector :extend - (when (and (logtest (get-header-data object) vector-addr-hashing-subtype) - touchedp) + (when (and touchedp + (test-header-data-bit object (ash vector-addr-hashing-flag + array-flags-data-position))) (setf (svref object 1) 1))) (code-component :override @@ -114,6 +111,7 @@ (let* ((oldval (%closure-fun object)) (newval (forward oldval))) (unless (eq newval oldval) + #+nil ; FIXME: gotta figure out GC marking situation here (with-pinned-objects (object newval) (setf (sap-ref-sap (int-sap (- (get-lisp-obj-address object) fun-pointer-lowtag)) @@ -123,11 +121,7 @@ (let* ((oldval (%closure-index-ref object i)) (newval (forward oldval))) (unless (eq newval oldval) - (with-pinned-objects (object) - (setf (sap-ref-lispobj (int-sap (get-lisp-obj-address object)) - (- (ash (+ i closure-info-offset) word-shift) - fun-pointer-lowtag)) - newval)))))) + (%closure-index-set object i newval))))) (ratio :override) ((complex rational) :override) (t @@ -385,6 +379,7 @@ (name (and entry (sb-kernel:%fun-name entry)))) (and (symbolp name) + (symbol-package name) (eq (nth-value 1 (find-symbol (symbol-name name) (symbol-package name))) :external)))) diff --git a/src/code/immobile-space.lisp b/src/code/immobile-space.lisp index 3cbe699bc5..5b559f1f0b 100644 --- a/src/code/immobile-space.lisp +++ b/src/code/immobile-space.lisp @@ -11,10 +11,13 @@ (in-package "SB-X86-64-ASM") +(eval-when (:compile-toplevel) ; not needed outside this file (defmacro do-immobile-code ((code-var) &body body) ;; Loop over all code objects `(let* ((call (find-inst #xE8 (get-inst-space))) (jmp (find-inst #xE9 (get-inst-space))) + (mov-ea (find-inst #x8B (get-inst-space))) + (mov-imm-acc (find-inst #xB8 (get-inst-space))) (dstate (make-dstate nil)) (sap (int-sap 0)) (seg (sb-disassem::%make-segment :sap-maker (lambda () sap)))) @@ -38,8 +41,8 @@ (when (= obj-type code-header-widetag) ,@body)) ;; Slowness here is bothersome, especially for SB-VM::REMOVE-STATIC-LINKS, ;; so skip right over all fixedobj pages. - (ash varyobj-space-start (- n-fixnum-tag-bits)) - (%make-lisp-obj (sap-int *varyobj-space-free-pointer*)))))) + (ash text-space-start (- n-fixnum-tag-bits)) + (%make-lisp-obj (sap-int *text-space-free-pointer*))))))) (defun sb-vm::collect-immobile-code-relocs () (let ((code-components @@ -113,33 +116,75 @@ (vector-push-extend (fill-pointer relocs) code-components) (values code-components relocs))) +(export 'sb-vm::statically-link-core "SB-VM") +(declaim (inline rip-relative-p)) +(defun rip-relative-p (modrm-byte) (= (logand modrm-byte #b11000111) #b00000101)) + (defun sb-vm::statically-link-core (&key callers) (do-immobile-code (code) (when (or (not callers) (and (plusp (code-n-entries code)) (member (%simple-fun-name (%code-entry-point code 0)) callers))) (let* ((fixups) + (all-fdefns + (do ((i sb-vm:code-constants-offset (1+ i)) + (end (code-header-words code)) + (list)) + ((= i end) list) + (let ((const (code-header-ref code i))) + (typecase const + (fdefn (push const list)) + ;; CONS may occur due to previous invocation of statically-link. + ((cons fdefn) (push (car const) list)))))) + (observable-fdefns) ; ones that an instruction explicitly dereferences (code-begin (- (get-lisp-obj-address code) sb-vm:other-pointer-lowtag)) (code-end (+ code-begin (sb-vm::code-object-size code))) + (boxed-begin (+ code-begin (* sb-vm:code-constants-offset sb-vm:n-word-bytes))) + (boxed-end (+ code-begin (* (code-header-words code) sb-vm:n-word-bytes))) (code-insts (code-instructions code))) (do-functions (fun addr) ;; Loop over function's assembly code (dx-flet ((process-inst (chunk inst) - (when (or (eq inst jmp) (eq inst call)) - (let ((target (+ (near-jump-displacement chunk dstate) - (dstate-next-addr dstate)))) - ;; Do not call FIND-CALLED-OBJECT if the target is - ;; within the same code object - (unless (and (<= code-begin target) (< target code-end)) - (let ((fdefn (sb-vm::find-called-object target))) - (when (fdefn-p fdefn) - (push (cons (+ (sap- sap code-insts) - (sb-disassem:dstate-cur-offs dstate) - 1) - fdefn) - fixups)))))))) + (cond + ;; find FDEFNs as the source of move-immediate-to-register. + ;; There can be false positives, but that's OK. + ((and (eq inst mov-imm-acc) + ;; ensure not a 64-bit move + (eql (sb-disassem::dstate-inst-properties dstate) 0)) + (let ((value (sap-ref-32 sap (1+ (dstate-cur-offs dstate))))) + (dolist (fdefn all-fdefns) + (when (eql (get-lisp-obj-address fdefn) value) + (pushnew fdefn observable-fdefns))))) + ;; find FDEFNs in code header as the source of MOV EA to register + ((and (eq inst mov-ea) + (eql (sap-ref-8 sap (dstate-cur-offs dstate)) #x8B) + (rip-relative-p (sap-ref-8 sap (1+ (dstate-cur-offs dstate))))) + (let ((addr (+ (signed-sap-ref-32 sap (+ (dstate-cur-offs dstate) 2)) + (dstate-next-addr dstate)))) + (when (and (not (logtest addr (ash sb-vm:lowtag-mask -1))) ; aligned + (<= boxed-begin addr) (< addr boxed-end)) + (let ((const (sap-ref-lispobj (int-sap addr) 0))) + (when (fdefn-p const) + (pushnew const observable-fdefns)))))) + ;; find FDEFN as the target of JMP/CALL + ((or (eq inst jmp) (eq inst call)) + (let ((target (+ (near-jump-displacement chunk dstate) + (dstate-next-addr dstate)))) + ;; Can't be an FDEFN if within the same code object + (unless (and (<= code-begin target) (< target code-end)) + (let ((fdefn (dolist (fdefn all-fdefns) + (when (= target (+ (get-lisp-obj-address fdefn) + ;; KLUDGE: 2 = address of 'jmp' inst + (- 2 other-pointer-lowtag))) + (return fdefn))))) + (when (and fdefn (neq (info :function :inlinep (fdefn-name fdefn)) + 'notinline)) + (push (cons (+ (sap- sap code-insts) + (1+ (sb-disassem:dstate-cur-offs dstate))) + fdefn) + fixups))))))))) (map-segment-instructions #'process-inst seg dstate))) - (sb-vm::statically-link-code-obj code fixups))))) + (sb-vm::statically-link-code-obj code fixups observable-fdefns))))) ;;; While concurrent use of un-statically-link is unlikely, misuse could easily ;;; cause heap corruption. It's preventable by ensuring that this is atomic @@ -151,14 +196,12 @@ ;;; current jump address, which means we need to fix them *all* before anyone ;;; else gets an opportunity to change the fdefn-fun of this same fdefn again. (defun sb-vm::remove-static-links (fdefn) - (sb-thread::with-system-mutex (sb-c::*static-linker-lock*) + (sb-int:with-system-mutex (sb-vm::*static-linker-lock*) (let ((fun-entry (sb-vm::fdefn-raw-addr fdefn)) (fdefn-entry (sb-vm::fdefn-entry-address fdefn))) (flet ((code-statically-links-fdefn-p (code) - (let ((fdefns-start (+ code-constants-offset - (* code-slots-per-simple-fun - (code-n-entries code))))) - (dotimes (i (code-n-named-calls code)) + (multiple-value-bind (fdefns-start count) (sb-vm::code-header-fdefn-range code) + (dotimes (i count) (let ((constant (code-header-ref code (+ fdefns-start i)))) (when (or (eq constant fdefn) (and (consp constant) (eq (car constant) fdefn))) @@ -169,8 +212,9 @@ ;; CMPXCHG is atomic even when misaligned, and x86-64 promises ;; that self-modifying code works correctly, so the fetcher ;; should never see a torn write. - (%primitive sb-vm::signed-sap-cas-32 - sap 0 oldval newval)))) + (cas (sap-ref-32 sap 0) + (ldb (byte 32 0) oldval) + (ldb (byte 32 0) newval))))) (do-immobile-code (code) ;; Examine only those code components which potentially use FDEFN. (binding* ((constant-index (code-statically-links-fdefn-p code) :exit-if-null) diff --git a/src/code/initial-method.lisp b/src/code/initial-method.lisp new file mode 100644 index 0000000000..a0326adacb --- /dev/null +++ b/src/code/initial-method.lisp @@ -0,0 +1,98 @@ +;;;; This software is part of the SBCL system. See the README file for +;;;; more information. +;;;; +;;;; This software is derived from the CMU CL system, which was +;;;; written at Carnegie Mellon University and released into the +;;;; public domain. The software is in the public domain and is +;;;; provided with absolutely no warranty. See the COPYING and CREDITS +;;;; files for more information. + +(in-package "SB-PCL") + +;;; Initial methods are methods available to use immediately on system startup. +;;; They have the following constraints: +;;; -- Only one (the first) argument may be specialized on. +;;; -- They are unqualified (primary) methods. +;;; Thus exactly one primary method is chosen respecting class +;;; precedence order on method invocation. +(defvar *!initial-methods* '()) + +;;; Deferred methods (which include initial methods) are installed +;;; later by the full CLOS implementation. These can have any number +;;; of specialized arguments or qualifiers. +(defvar *!deferred-methods* '()) + +(defun !early-load-method (class name quals specls ll lambda source-loc) + (declare (ignore class)) + (push (list quals specls lambda ll source-loc) + (cdr (or (assoc name *!deferred-methods*) + (car (push (list name) *!deferred-methods*)))))) + +;;; Slow-but-correct logic for single-dispatch sans method +;;; combination, allowing exactly one primary method. Initial methods +;;; are sorted most-specific-first, so we can stop looking as soon as +;;; a match is found. +(defun initial-call-a-method (gf-name emergency-fallback specialized-arg &rest rest) + (let* ((methods (the simple-vector + (cdr (or (assoc gf-name *!initial-methods*) + (error "No methods on ~S" gf-name))))) + ;; WRAPPER-OF can't be called until its constants have been patched in, + ;; which is potentially too early in cold init especially if trying + ;; to debug to figure out what has been patched in. + ;; And sometimes the thing we need to print is a FMT-CONTROL, + ;; which means we can see a funcallable-instance here. + (arg-wrapper + (cond ((%instancep specialized-arg) (%instance-wrapper specialized-arg)) + ((funcallable-instance-p specialized-arg) (%fun-wrapper specialized-arg)) + ;; Non-instance-like types always call a predicate. + (t #.(find-layout 't)))) + (applicable-method + ;; Each "method" is represented as a vector: + ;; #(#<GUARD> SPECIALIZER #<FMF>) + ;; SPECIALIZER is either a symbol for a classoid, or a genesis-time #<LAYOUT>. + ;; Pick the first applicable one. + (find-if (lambda (method) + (let ((guard (the symbol (svref method 0)))) + (if (fboundp guard) + (funcall guard specialized-arg) + (let ((test-wrapper (svref method 1))) + (and (sb-kernel::wrapper-p test-wrapper) + (or (find test-wrapper (wrapper-inherits arg-wrapper)) + (eq arg-wrapper test-wrapper))))))) + methods))) + (cond (applicable-method + ;; Call using no permutation-vector / no precomputed next method. + (apply (svref applicable-method 2) nil nil specialized-arg rest)) + (emergency-fallback + (apply emergency-fallback specialized-arg rest)) + (t + (error "No applicable method for ~S on ~S~%" gf-name + (type-of specialized-arg)))))) + +(defun make-load-form (object &optional environment) + (initial-call-a-method 'make-load-form nil object environment)) +(defun print-object (object stream) + (flet ((last-ditch-effort (object stream) + ;; Depending on what you're poking at in cold-init it was possible to see + ;; "No applicable method for PRINT-OBJECT on SB-KERNEL::RANDOM-CLASS" + ;; so just print the address and carry on. + (format stream "#<UNPRINTABLE @ #x~X>" (get-lisp-obj-address object)))) + (initial-call-a-method 'print-object #'last-ditch-effort object stream))) + +(macrolet ((ensure-gfs (names) + `(progn ,@(mapcar (lambda (name) + `(defun ,name (x) (initial-call-a-method ',name nil x))) + names)))) + (ensure-gfs (open-stream-p interactive-stream-p input-stream-p output-stream-p + stream-element-type))) +(defun close (x &key abort) (initial-call-a-method 'close nil x :abort abort)) + +;;; FIXME: this no longer holds methods, but it seems to have an effect +;;; on the caching of a discriminating function for PRINT-OBJECT +(defvar *!delayed-defmethod-args* nil) + +;;; This exists only to show that the cross-compiler can constant-fold +;;; a constant index into a literal array without crashing. +(defun !test-svref-folding () + (let ((z #(42 test))) + (if (< (svref z 0) 100) t nil))) diff --git a/src/code/inspect.lisp b/src/code/inspect.lisp index f91c04796a..70d7541005 100644 --- a/src/code/inspect.lisp +++ b/src/code/inspect.lisp @@ -165,7 +165,7 @@ evaluated expressions. (defun inspected-structure-elements (object) (let ((parts-list '()) - (info (layout-info (sb-kernel:layout-of object)))) + (info (wrapper-info (sb-kernel:wrapper-of object)))) (when (sb-kernel::defstruct-description-p info) (dolist (dd-slot (dd-slots info) (nreverse parts-list)) (push (cons (dsd-name dd-slot) @@ -178,6 +178,11 @@ evaluated expressions. t (inspected-structure-elements object))) +(defmethod inspected-parts ((object pathname)) + (values (format nil "The object is a ~S.~%" (type-of object)) + t + (inspected-structure-elements object))) + (defun inspected-standard-object-elements (object) (let ((reversed-elements nil) (class-slots (sb-pcl::class-slots (class-of object)))) @@ -216,7 +221,7 @@ evaluated expressions. ;; to DESCRIBE from the inspector. (list* (cons "Lambda-list" (%fun-lambda-list object)) - (cons "Ftype" (%fun-type object)) + (cons "Ftype" (%fun-ftype object)) (when (closurep object) (list (cons "Closed over values" (%closure-values object))))))) diff --git a/src/code/interr.lisp b/src/code/interr.lisp index 2bec9de5b8..835f62bf01 100644 --- a/src/code/interr.lisp +++ b/src/code/interr.lisp @@ -20,8 +20,8 @@ `(progn (defconstant n-internal-error-handlers ,n) (declaim ((simple-vector ,n) **internal-error-handlers**)) - (!define-load-time-global **internal-error-handlers** - ,(make-array n :initial-element 0)))))) + (define-load-time-global **internal-error-handlers** + ,(make-array n :initial-element 0)))))) (def-it)) (defmacro deferr (name args &rest body) @@ -53,18 +53,14 @@ (labels ((retry-value (value) (or (typecase value (fdefn (fdefn-fun value)) - (symbol - (let ((fdefn (symbol-fdefn value))) - (and fdefn - (fdefn-fun fdefn)))) + (symbol (sb-impl::%symbol-function value)) (function value) - (t - (if (valid-function-name-p value) - (let ((fdefn (find-fdefn value))) - (and fdefn - (fdefn-fun fdefn))) + ((satisfies legal-fun-name-p) + (let ((fdefn (find-fdefn value))) + (and fdefn (fdefn-fun fdefn)))) + (t (still-bad "Bad value when restarting ~s: ~s" - name value)))) + name value))) (still-bad (if (fdefn-p value) "~S is still undefined" "Can't replace ~s with ~s because it is undefined") @@ -221,10 +217,12 @@ (info :variable :type symbol) (if (and defined (not (ctypep value type))) - (still-bad (sb-format:tokens - "Type mismatch when restarting unbound symbol error:~@ - ~s is not of type ~/sb-impl:print-type/") - value type) + (try (make-condition 'type-error + :datum value + :expected-type (type-specifier type) + :context + (format nil "while restarting unbound variable ~a." + symbol))) value))) (set-value (value &optional set-symbol) (sb-di::sub-set-debug-var-slot @@ -238,12 +236,7 @@ (retry-evaluation () (if (boundp symbol) (set-value (symbol-value symbol)) - (still-bad "~s is still unbound" symbol))) - (still-bad (format-control &rest format-arguments) - (try (make-condition 'retry-unbound-variable - :name symbol - :format-control format-control - :format-arguments format-arguments))) + (try condition))) (try (condition) (restart-case (error condition) (continue () @@ -314,34 +307,66 @@ :operation '/ :operands (list this that))) +(defun restart-type-error (type condition pc-offset) + (let ((tn-offset (car *current-internal-error-args*))) + (labels ((retry-value (value) + (if (typep value type) + value + (try (make-condition 'type-error + :expected-type type + :datum value + :context "while restarting a type error.")))) + (set-value (value) + (sb-di::sub-set-debug-var-slot + nil tn-offset (retry-value value) + *current-internal-error-context*) + (sb-vm::incf-context-pc *current-internal-error-context* + pc-offset) + (return-from restart-type-error)) + (try (condition) + (restart-case (error condition) + (use-value (value) + :report (lambda (stream) + (format stream "Use specified value.")) + :interactive read-evaluated-form + (set-value value))))) + (try condition)))) + +(defun object-not-type-error (object type &optional (context nil context-p)) + (if (invalid-array-p object) + (invalid-array-error object) + (let* ((context (if context-p + context + (sb-di:error-context))) + (condition + (make-condition (if (and (%instancep object) + (wrapper-invalid (%instance-wrapper object))) + ;; Signaling LAYOUT-INVALID is dubious, but I guess it provides slightly + ;; more information in that it says that the object may have at some point + ;; been TYPE. Anyway, it's not wrong - it's a subtype of TYPE-ERROR. + 'layout-invalid + 'type-error) + :datum object + :expected-type (typecase type + (classoid-cell + (classoid-cell-name type)) + (wrapper + (wrapper-proper-name type)) + (t + type)) + :context (and (not (integerp context)) + context)))) + (if (integerp context) + (restart-type-error type condition context) + (error condition))))) + (macrolet ((def (errname fun-name) `(setf (svref **internal-error-handlers** ,(error-number-or-lose errname)) (fdefinition ',fun-name)))) (def etypecase-failure-error etypecase-failure) - (def ecase-failure-error ecase-failure)) - -(deferr object-not-type-error (object type) - (if (invalid-array-p object) - (invalid-array-error object) - (error (if (and (%instancep object) - (layout-invalid (%instance-layout object))) - 'layout-invalid - 'type-error) - :datum object - :expected-type (typecase type - (classoid-cell - (classoid-cell-name type)) - (layout - (layout-proper-name type)) - (t - type)) - :context (sb-di:error-context)))) - -(deferr layout-invalid-error (object layout) - (error 'layout-invalid - :datum object - :expected-type (layout-classoid layout))) + (def ecase-failure-error ecase-failure) + (def object-not-type-error object-not-type-error)) (deferr odd-key-args-error () (%program-error "odd number of &KEY arguments")) @@ -358,10 +383,12 @@ context))) (error 'unknown-keyword-argument :name key-name)))) -;; TODO: make the arguments (ARRAY INDEX &optional BOUND) -;; and don't need the bound for vectors. Just read it. (deferr invalid-array-index-error (array bound index) (invalid-array-index-error array index bound)) +(deferr invalid-vector-index-error (vector index) + (invalid-array-index-error vector index (length vector))) +(deferr uninitialized-element-error (vector index) + (error 'uninitialized-element-error :name (cons vector index))) (deferr tls-exhausted-error () ;; There is nothing we can do about it. A number of entries in the @@ -401,6 +428,55 @@ (bug "~@<failed AVER: ~2I~_~S~:>" form)) (deferr unreachable-error () (bug "Unreachable code reached")) + +(deferr mul-overflow-error (low high) + (destructuring-bind (raw-low raw-high) *current-internal-error-args* + (declare (ignorable raw-low raw-high)) + (let ((type (or (sb-di:error-context) + 'fixnum))) + (object-not-type-error #+x86-64 + (* low high) + #-x86-64 + (if (memq (sb-c:sc+offset-scn raw-low) `(,sb-vm:any-reg-sc-number + ,sb-vm:descriptor-reg-sc-number)) + (ash (logior + (ash high sb-vm:n-word-bits) + (ldb (byte sb-vm:n-word-bits 0) (ash low sb-vm:n-fixnum-tag-bits))) + (- sb-vm:n-fixnum-tag-bits)) + (logior + (ash high sb-vm:n-word-bits) + (ldb (byte sb-vm:n-word-bits 0) low))) + type + nil)))) + +(sb-c::when-vop-existsp (:translate sb-c::unsigned+) + (flet ((err (x of cf) + (let* ((raw-x (car *current-internal-error-args*)) + (signed (= (sb-c:sc+offset-scn raw-x) sb-vm:signed-reg-sc-number))) + (let ((type (or (sb-di:error-context) + 'fixnum)) + (x (if signed + (cond ((and of cf) + (dpb x (byte sb-vm:n-word-bits 0) -1)) + (of + (ldb (byte sb-vm:n-word-bits 0) x)) + (t + (bug "flags"))) + (cond (cf + (dpb 1 (byte 1 sb-vm:n-word-bits) x)) + (of + (sb-c::mask-signed-field sb-vm:n-word-bits x)) + (t + (dpb x (byte sb-vm:n-word-bits 0) -1)))))) + (object-not-type-error x type nil))))) + (deferr add-sub-overflow-error (x) + (multiple-value-bind (of cf) (sb-vm::context-overflow-carry-flags *current-internal-error-context*) + (err x of cf))) + + #+x86-64 + (deferr sub-overflow-error (x) + (multiple-value-bind (of cf) (sb-vm::context-overflow-carry-flags *current-internal-error-context*) + (err x of (not cf)))))) ;;;; INTERNAL-ERROR signal handler @@ -450,13 +526,10 @@ :format-arguments (list slot-name struct-name) :datum (make-unbound-marker) :expected-type (if dsd (dsd-type dsd) 't)))) - (error 'type-error - :datum (sb-di::sub-access-debug-var-slot - fp (first arguments) alien-context) - :expected-type - (car (svref sb-c:+backend-internal-errors+ - error-number)) - :context context))) + (object-not-type-error (sb-di::sub-access-debug-var-slot + fp (first arguments) alien-context) + (car (svref sb-c:+backend-internal-errors+ + error-number))))) (let ((handler (and (typep error-number `(mod ,n-internal-error-handlers)) (svref **internal-error-handlers** error-number)))) diff --git a/src/code/irrat.lisp b/src/code/irrat.lisp index 9213fb35e1..0de792c2e6 100644 --- a/src/code/irrat.lisp +++ b/src/code/irrat.lisp @@ -34,6 +34,7 @@ `(progn (declaim (inline ,function)) (defun ,function ,args + (declare (sb-c:flushable sb-c:%alien-funcall)) (truly-the ;; avoid checking the result ,(type-specifier (fun-type-returns (info :function :type function))) (alien-funcall @@ -76,6 +77,7 @@ #-x86 (def-math-rtn "atan" 1) #-x86 (def-math-rtn "atan2" 2) +;;; See src/runtime/wrap.c for the definitions of the "sb_"-prefixed things. (def-math-rtn "acos" 1 #+win32 t) (def-math-rtn "asin" 1 #+win32 t) (def-math-rtn "cosh" 1 #+win32 t) @@ -119,6 +121,12 @@ (if (evenp power) 1 base)) + ((eql base 0) + (cond ((= power 0) 1) + ((> power 0) 0) + (t (error 'division-by-zero + :operands (list 0 power) + :operation 'expt)))) ((ratiop base) (let ((den (denominator base)) (num (numerator base))) @@ -253,7 +261,7 @@ (when (< x-hi 0) (cond ((and (= x-ihi #x3ff00000) (zerop yisint)) ;; (-1)**non-int - (let ((y*pi (* y sb-xc:pi))) + (let ((y*pi (* y pi))) (declare (double-float y*pi)) (return-from real-expt (complex @@ -276,7 +284,7 @@ (2 ; even (coerce pow rtype)) (t ; non-integer - (let ((y*pi (* y sb-xc:pi))) + (let ((y*pi (* y pi))) (declare (double-float y*pi)) (complex (coerce (* pow (%cos y*pi)) @@ -375,11 +383,11 @@ (number-dispatch ((number number)) (((foreach fixnum bignum)) (if (minusp number) - (complex (log (- number)) (coerce sb-xc:pi 'single-float)) + (complex (log (- number)) (coerce pi 'single-float)) (coerce (/ (log2 number) (log (exp $1.0d0) $2.0d0)) 'single-float))) ((ratio) (if (minusp number) - (complex (log (- number)) (coerce sb-xc:pi 'single-float)) + (complex (log (- number)) (coerce pi 'single-float)) (let ((numerator (numerator number)) (denominator (denominator number))) (if (= (integer-length numerator) @@ -394,7 +402,7 @@ ;; Since this doesn't seem to be an implementation issue ;; I (pw) take the Kahan result. (if (= (float-sign-bit number) 1) ; MINUSP - (complex (log (- number)) (coerce sb-xc:pi '(dispatch-type number))) + (complex (log (- number)) (coerce pi '(dispatch-type number))) (coerce (%log (coerce number 'double-float)) '(dispatch-type number)))) ((complex) @@ -449,15 +457,15 @@ (number-dispatch ((number number)) ((rational) (if (minusp number) - (coerce sb-xc:pi 'single-float) + (coerce pi 'single-float) $0.0f0)) ((single-float) (if (minusp (float-sign number)) - (coerce sb-xc:pi 'single-float) + (coerce pi 'single-float) $0.0f0)) ((double-float) (if (minusp (float-sign number)) - (coerce sb-xc:pi 'double-float) + (coerce pi 'double-float) $0.0d0)) (handle-complex (atan (imagpart number) (realpart number))))) @@ -548,8 +556,8 @@ (if (zerop y) (if (= (float-sign-bit x) 0) ; PLUSP y - (float-sign y sb-xc:pi)) - (float-sign y (sb-xc:/ sb-xc:pi 2))) + (float-sign y pi)) + (float-sign y (sb-xc:/ pi 2))) (%atan2 y x)))) (number-dispatch ((y real) (x real)) ((double-float @@ -909,9 +917,9 @@ (declare (muffle-conditions compiler-note)) (declare (type (or rational complex) z)) (let* (;; constants - (theta (sb-xc:/ (sb-xc:sqrt sb-xc:most-positive-double-float) $4.0d0)) - (rho (sb-xc:/ $4.0d0 (sb-xc:sqrt sb-xc:most-positive-double-float))) - (half-pi (sb-xc:/ sb-xc:pi $2.0d0)) + (theta (sb-xc:/ (sb-xc:sqrt most-positive-double-float) $4.0d0)) + (rho (sb-xc:/ $4.0d0 (sb-xc:sqrt most-positive-double-float))) + (half-pi (sb-xc:/ pi $2.0d0)) (rp (float (realpart z) $1.0d0)) (beta (float-sign rp $1.0d0)) (x (* beta rp)) diff --git a/src/code/last-file.lisp b/src/code/last-file.lisp deleted file mode 100644 index f4a3e4b20c..0000000000 --- a/src/code/last-file.lisp +++ /dev/null @@ -1,68 +0,0 @@ -;;;; This software is part of the SBCL system. See the README file for -;;;; more information. -;;;; -;;;; This software is derived from the CMU CL system, which was -;;;; written at Carnegie Mellon University and released into the -;;;; public domain. The software is in the public domain and is -;;;; provided with absolutely no warranty. See the COPYING and CREDITS -;;;; files for more information. - -(in-package "SB-IMPL") - -;;; Verify on startup that some constants were dumped reflecting the correct -;;; action of our vanilla-host-compatible functions. -;;; For now, just SXHASH is checked. - -;;; Parallelized build doesn't get the full set of data because the side effect -;;; of data recording when invoking compile-time functions aren't propagated -;;; back to process that forked the children doing the grunt work. -(defvar sb-c::*sxhash-crosscheck* - '#.(let (pairs) - ;; De-duplicate, which reduces the list from ~8000 entries to ~1000 entries. - ;; But make sure that any key which is repeated has the same value - ;; at each repetition. - (dolist (pair sb-c::*sxhash-crosscheck* (coerce pairs 'simple-vector)) - (let ((found (assoc (car pair) pairs))) - (if found - (aver (= (cdr found) (cdr pair))) - (push pair pairs)))))) -(defun check-compile-time-sxhashes () - (loop for (object . hash) across sb-c::*sxhash-crosscheck* - unless (= (sxhash object) hash) - do (error "SB-XC:SXHASH computed wrong answer for ~S. Got ~x should be ~x" - object hash (sxhash object)))) -(check-compile-time-sxhashes) - -(eval-when (:compile-toplevel) ;; Inform genesis of all defstructs - (with-open-file (output (sb-cold:stem-object-path "defstructs.lisp-expr" - '(:extra-artifact) :target-compile) - :direction :output :if-exists :supersede) - (dolist (root '(structure-object function)) - (dolist (pair (sort (%hash-table-alist - (classoid-subclasses (find-classoid root))) - #'string< - ;; pair = (#<classoid> . #<layout>) - :key (lambda (pair) (classoid-name (car pair))))) - (let* ((layout (cdr pair)) - (dd (layout-info layout))) - (cond - (dd - (let* ((*print-pretty* nil) ; output should be insensitive to host pprint - (*print-readably* t) - (classoid-name (classoid-name (car pair))) - (*package* (cl:symbol-package classoid-name))) - (format output "~/sb-ext:print-symbol-with-prefix/ ~S (~%" - classoid-name - (list* (the (unsigned-byte 16) (layout-flags layout)) - (layout-depthoid layout) - (map 'list - (lambda (x) (classoid-name (layout-classoid x))) - (layout-inherits layout)))) - (dolist (dsd (dd-slots dd) (format output ")~%")) - (format output " (~d ~S ~S)~%" - (sb-kernel::dsd-bits dsd) - (dsd-name dsd) - (dsd-accessor-name dsd))))) - (t - (error "Missing DD for ~S" pair)))))) - (format output ";; EOF~%"))) diff --git a/src/code/late-cas.lisp b/src/code/late-cas.lisp deleted file mode 100644 index b639c2fe6e..0000000000 --- a/src/code/late-cas.lisp +++ /dev/null @@ -1,144 +0,0 @@ -(in-package "SB-IMPL") - -(defcas car (cons) %compare-and-swap-car) -(defcas cdr (cons) %compare-and-swap-cdr) -(defcas first (cons) %compare-and-swap-car) -(defcas rest (cons) %compare-and-swap-cdr) -(defcas symbol-plist (symbol) %compare-and-swap-symbol-plist) - -;;; Out-of-line definitions for various primitive cas functions. -(macrolet ((def (name lambda-list ref &optional set) - #+compare-and-swap-vops - (declare (ignore ref set)) - `(defun ,name (,@lambda-list old new) - #+compare-and-swap-vops - (,name ,@lambda-list old new) - #-compare-and-swap-vops - (progn - #+sb-thread - ,(error "No COMPARE-AND-SWAP-VOPS on a threaded build?") - #-sb-thread - (let ((current (,ref ,@lambda-list))) - ;; Shouldn't this be inside a WITHOUT-INTERRUPTS ? - (when (eq current old) - ,(if set - `(,set ,@lambda-list new) - `(setf (,ref ,@lambda-list) new))) - current))))) - (def %compare-and-swap-car (cons) car) - (def %compare-and-swap-cdr (cons) cdr) - (def %instance-cas (instance index) %instance-ref %instance-set) - #+(or x86-64 x86 riscv) - (def %raw-instance-cas/word (instance index) - %raw-instance-ref/word - %raw-instance-set/word) - #+riscv - (def %raw-instance-cas/signed-word (instance index) - %raw-instance-ref/signed-word - %raw-instance-set/signed-word) - (def %compare-and-swap-symbol-info (symbol) symbol-info) - (def %compare-and-swap-symbol-value (symbol) symbol-value) - (def %compare-and-swap-svref (vector index) svref)) - -;; Atomic increment/decrement ops on tagged storage cells (as contrasted with -;; specialized arrays and raw structure slots) are defined in terms of CAS. - -;; This code would be more concise if workable versions -;; of +-MODFX, --MODFX were defined generically. -(macrolet ((modular (fun a b) - #+(or x86 x86-64) - `(,(package-symbolicate "SB-VM" fun "-MODFX") ,a ,b) - #-(or x86 x86-64) - ;; algorithm of https://graphics.stanford.edu/~seander/bithacks - `(let ((res (logand (,fun ,a ,b) - (ash sb-ext:most-positive-word - (- sb-vm:n-fixnum-tag-bits)))) - (m (ash 1 (1- sb-vm:n-fixnum-bits)))) - (- (logxor res m) m)))) - - ;; Atomically frob the CAR or CDR of a cons, or a symbol-value. - ;; The latter will be a global value because the ATOMIC-INCF/DECF - ;; macros work on a symbol only if it is known global. - (macrolet ((def-frob (name op type slot) - `(defun ,name (place delta) - (declare (type ,type place) (type fixnum delta)) - (loop (let ((old (the fixnum (,slot place)))) - (when (eq (cas (,slot place) old - (modular ,op old delta)) old) - (return old))))))) - (def-frob %atomic-inc-symbol-global-value + symbol symbol-value) - (def-frob %atomic-dec-symbol-global-value - symbol symbol-value) - (def-frob %atomic-inc-car + cons car) - (def-frob %atomic-dec-car - cons car) - (def-frob %atomic-inc-cdr + cons cdr) - (def-frob %atomic-dec-cdr - cons cdr))) - -;;; ATOMIC-MUMBLE functions are not used when self-building. - -(defmacro atomic-update (place update-fn &rest arguments &environment env) - "Updates PLACE atomically to the value returned by calling function -designated by UPDATE-FN with ARGUMENTS and the previous value of PLACE. - -PLACE may be read and UPDATE-FN evaluated and called multiple times before the -update succeeds: atomicity in this context means that the value of PLACE did -not change between the time it was read, and the time it was replaced with the -computed value. - -PLACE can be any place supported by SB-EXT:COMPARE-AND-SWAP. - -Examples: - - ;;; Conses T to the head of FOO-LIST. - (defstruct foo list) - (defvar *foo* (make-foo)) - (atomic-update (foo-list *foo*) #'cons t) - - (let ((x (cons :count 0))) - (mapc #'sb-thread:join-thread - (loop repeat 1000 - collect (sb-thread:make-thread - (lambda () - (loop repeat 1000 - do (atomic-update (cdr x) #'1+) - (sleep 0.00001)))))) - ;; Guaranteed to be (:COUNT . 1000000) -- if you replace - ;; atomic update with (INCF (CDR X)) above, the result becomes - ;; unpredictable. - x) -" - (multiple-value-bind (vars vals old new cas-form read-form) - (get-cas-expansion place env) - `(let* (,@(mapcar 'list vars vals) - (,old ,read-form)) - (loop for ,new = (funcall ,update-fn ,@arguments ,old) - until (eq ,old (setf ,old ,cas-form)) - finally (return ,new))))) - -(defmacro atomic-push (obj place &environment env) - "Like PUSH, but atomic. PLACE may be read multiple times before -the operation completes -- the write does not occur until such time -that no other thread modified PLACE between the read and the write. - -Works on all CASable places." - (multiple-value-bind (vars vals old new cas-form read-form) - (get-cas-expansion place env) - `(let* (,@(mapcar 'list vars vals) - (,old ,read-form) - (,new (cons ,obj ,old))) - (loop until (eq ,old (setf ,old ,cas-form)) - do (setf (cdr ,new) ,old) - finally (return ,new))))) - -(defmacro atomic-pop (place &environment env) - "Like POP, but atomic. PLACE may be read multiple times before -the operation completes -- the write does not occur until such time -that no other thread modified PLACE between the read and the write. - -Works on all CASable places." - (multiple-value-bind (vars vals old new cas-form read-form) - (get-cas-expansion place env) - `(let* (,@(mapcar 'list vars vals) - (,old ,read-form)) - (loop (let ((,new (cdr ,old))) - (when (eq ,old (setf ,old ,cas-form)) - (return (car (truly-the list ,old))))))))) diff --git a/src/code/late-extensions.lisp b/src/code/late-extensions.lisp index 54a98114ee..764188b287 100644 --- a/src/code/late-extensions.lisp +++ b/src/code/late-extensions.lisp @@ -58,7 +58,7 @@ "Read the content of STREAM into a buffer in order to count lines and columns." (unless (and old-position position - (< position sb-xc:array-dimension-limit)) + (< position array-dimension-limit)) (return-from read-content)) (let ((content (make-string position :element-type (stream-element-type stream)))) diff --git a/src/code/late-globaldb.lisp b/src/code/late-globaldb.lisp index 578f332f5f..9274511464 100644 --- a/src/code/late-globaldb.lisp +++ b/src/code/late-globaldb.lisp @@ -9,14 +9,32 @@ (in-package "SB-IMPL") -;; Call FUNCTION once for each Name in globaldb that has information associated -;; with it, passing the function the Name as its only argument. -;; ;; This is in its own file to avoid creating an early dependency on ;; target-package iterators. (macrolet ((def (&rest situations) `(eval-when ,situations + ;; Return all function names that are stored in SYMBOL's packe-info. + ;; As an example, (INFO-NAME-LIST 'SB-PCL::DIRECT-SUPERCLASSES) => + ;; ((SB-PCL::SLOT-ACCESSOR :GLOBAL SB-PCL::DIRECT-SUPERCLASSES SB-PCL::READER) + ;; (SB-PCL::SLOT-ACCESSOR :GLOBAL SB-PCL::DIRECT-SUPERCLASSES BOUNDP) + ;; (SB-PCL::SLOT-ACCESSOR :GLOBAL SB-PCL::DIRECT-SUPERCLASSES SB-PCL::WRITER)) + (defun info-name-list (symbol) + (let ((packed-info (symbol-dbinfo symbol)) + (list)) + (cond (packed-info + (do-packed-info-aux-key (packed-info key-index) + (push (construct-globaldb-name (%info-ref packed-info key-index) symbol) + list)) + (nconc (and (or (plusp (packed-info-field packed-info 0 0)) + ;; fdefns are stored directly in the symbol. + (fboundp symbol)) + (list symbol)) + (nreverse list))) + ((fboundp symbol) + (list symbol))))) + ;; Call FUNCTION once for each Name in globaldb that has information associated + ;; with it, passing the function the Name as its only argument. (defun call-with-each-globaldb-name (fun-designator) (let ((function (cl:coerce fun-designator 'function))) (with-package-iterator (iter (list-all-packages) :internal :external) @@ -28,7 +46,7 @@ ;; always keep it since we can't know if it has been seen once. (when (or (not (sb-xc:symbol-package symbol)) (eq package (sb-xc:symbol-package symbol))) - (dolist (name (info-vector-name-list symbol)) + (dolist (name (info-name-list symbol)) (funcall function name)))))) ,@(unless (equal situations '(:compile-toplevel)) `((dovector (obj (car *fdefns*)) diff --git a/src/code/linkage-table.lisp b/src/code/linkage-table.lisp deleted file mode 100644 index 094b1a4806..0000000000 --- a/src/code/linkage-table.lisp +++ /dev/null @@ -1,115 +0,0 @@ -;;;; Linkage table specifics - -;;;; This software is part of the SBCL system. See the README file for -;;;; more information. -;;;; -;;;; This software is derived from the CMU CL system, which was -;;;; written at Carnegie Mellon University and released into the -;;;; public domain. The software is in the public domain and is -;;;; provided with absolutely no warranty. See the COPYING and CREDITS -;;;; files for more information. - -;;;; Linkage table itself is a mmapped memory area in C-land, which is -;;;; initialized by INIT-LINKAGE-TABLE once all shared objects have -;;;; been reopened, based on the information stored in *LINKAGE-INFO*. -;;;; -;;;; For data entries the linkage table holds the real address -;;;; of the foreign symbol, and for code the entries are jumps -;;;; to the real addresses. - -(in-package "SB-IMPL") - -(define-alien-routine arch-write-linkage-table-entry void - (index int) (real-address unsigned) (datap int)) - -(define-load-time-global *linkage-info* - ;; CDR of the cons is the list of undefineds - (list (make-hash-table :test 'equal :synchronized t))) - -(define-alien-variable undefined-alien-address unsigned) - -(macrolet ((dlsym-wrapper (&optional warn) - ;; Produce two values: an indicator of whether the foreign symbol was - ;; found; and the address as an integer if found, or a guard address - ;; which when accessed will result in an UNDEFINED-ALIEN-ERROR. - `(let ((addr (find-dynamic-foreign-symbol-address name))) - (cond (addr - (values t addr)) - (t - (when ,warn - ;; If we can report the actual name when an undefined - ;; alien is called don't warn. - #-(or arm arm64 x86-64) - (style-warn 'sb-kernel:undefined-alien-style-warning - :symbol name)) - (values - nil - (if datap - undefined-alien-address - (or - (sb-fasl:get-asm-routine 'sb-vm::undefined-alien-tramp) - (find-foreign-symbol-address "undefined_alien_function") - (bug "unreachable"))))))))) - -;;; Add a foreign linkage entry if none exists, return the address -;;; in the linkage table. -(defun ensure-foreign-symbol-linkage (name datap) - (let* ((key (if datap (list name) name)) - (info *linkage-info*) - (ht (car info))) - (or (awhen (with-locked-system-table (ht) - (or (gethash key ht) - (let* ((index (hash-table-count ht)) - (capacity (floor (- sb-vm:linkage-table-space-end - sb-vm:linkage-table-space-start) - sb-vm:linkage-table-entry-size))) - (when (< index capacity) - (multiple-value-bind (defined real-address) (dlsym-wrapper t) - (unless defined (push key (cdr info))) - (arch-write-linkage-table-entry index real-address - (if datap 1 0)) - (logically-readonlyize name) - (setf (gethash key ht) index)))))) - (sb-vm::linkage-table-entry-address it)) - (error "Linkage-table full (~D entries): cannot link ~S." - (hash-table-count ht) name)))) - -;;; Update the linkage-table. Called during initialization after all -;;; shared libraries have been reopened, and after a previously loaded -;;; shared object is reloaded. -;;; -;;; FIXME: Should figure out how to write only those entries that need -;;; updating. -;;; The problem is that when unloading a library, lacking any way to know which -;;; symbols came from it, we have to try to find every symbol again. -;;; If the shared-object-handle in which each symbol was originally found were -;;; stored in linkage-info, we could know which will become undefined on unload. -;;; The only "problem" is my lack of motivation to change this further. -(defun update-linkage-table (full-scan) - ;; This symbol is of course itself a prelinked symbol. - (let* ((n-prelinked (extern-alien "lisp_linkage_table_n_prelinked" int)) - (info *linkage-info*) - (ht (car info)) - ;; for computing anew the list of undefined symbols - (notdef)) - (flet ((recheck (key index) - (let* ((datap (listp key)) - (name (if datap (car key) key))) - ;; Symbols required for Lisp startup - ;; will not be re-pointed to a different address ever. - ;; Nor will those referenced by ELF core. - (when (>= index n-prelinked) - (multiple-value-bind (defined real-address) (dlsym-wrapper) - (unless defined (push key notdef)) - (arch-write-linkage-table-entry index real-address - (if datap 1 0))))))) - (with-locked-system-table (ht) - (if full-scan - ;; Look up everything; this is for image restart or library unload. - (dohash ((key index) ht) - (recheck key index)) - ;; Look up only the currently undefined foreign symbols - (dolist (key (cdr info)) - (recheck key (the (not null) (gethash key ht))))) - (setf (cdr info) notdef))))) -) diff --git a/src/code/list.lisp b/src/code/list.lisp index a3a6e9c606..7f16731da5 100644 --- a/src/code/list.lisp +++ b/src/code/list.lisp @@ -175,7 +175,7 @@ (endp object)) (defun list-length (list) - "Return the length of the given List, or Nil if the List is circular." + "Return the length of LIST, or NIL if LIST is circular." (do ((n 0 (+ n 2)) (y list (cddr y)) (z list (cdr z))) @@ -343,7 +343,7 @@ (lastn-macro unsigned-byte))))))) (define-compiler-macro last (&whole form list &optional (n 1) &environment env) - (if (sb-xc:constantp n env) + (if (constantp n env) (case (constant-form-value n env) (0 `(%last0 ,list)) (1 `(%last1 ,list)) @@ -351,7 +351,7 @@ form)) (defun list (&rest args) - "Return constructs and returns a list of its arguments." + "Construct and return a list containing the objects ARGS." args) ;;; LIST* is done the same as LIST, except that the last cons is made @@ -380,7 +380,7 @@ result))))) (defun make-list (size &key initial-element) - "Constructs a list with size elements each set to value" + "Construct and return a list with SIZE elements each set to INITIAL-ELEMENT." (declare (explicit-check)) (%make-list size initial-element)) ;;; This entry point is to be preferred, irrespective of @@ -393,7 +393,7 @@ (declare (type index count)))) (defun append (&rest lists) - "Construct a new list by concatenating the list arguments" + "Construct and return a list by concatenating LISTS." (let* ((result (list nil)) (tail result) (index 0) @@ -1107,7 +1107,11 @@ (dolist (elt list1) (unless (funcall member-test elt list2 key test) (push elt result))) - (dx-flet ((test (x y) (funcall (truly-the function test) y x))) + (dx-flet ((test (x y) + ;; This local function is never called if TEST is NIL, + ;; but the compiler doesn't know that, suppress the warning. + (funcall (the* (function :truly t :silent-conflict t) test) + y x))) (dolist (elt list2) (unless (funcall member-test elt list1 key #'test) (push elt result))))) @@ -1190,7 +1194,11 @@ (defun acons (key datum alist) "Construct a new alist by adding the pair (KEY . DATUM) to ALIST." - (cons (cons key datum) alist)) + ;; This function is maybe-inline, so can't use vop-existsp + ;; which does not remain in the image post-build. + #.(if (gethash 'acons sb-c::*backend-template-names*) + '(acons key datum alist) ; vop translated + '(cons (cons key datum) alist))) (defun pairlis (keys data &optional (alist '())) "Construct an association list from KEYS and DATA (adding to ALIST)." diff --git a/src/code/load.lisp b/src/code/load.lisp index ad19bcb69c..2f5eb687da 100644 --- a/src/code/load.lisp +++ b/src/code/load.lisp @@ -15,9 +15,133 @@ ;;;; files for more information. (in-package "SB-FASL") + + +;;;; various constants and essentially-constants + +;;; a string which appears at the start of a fasl file header +;;; +;;; This value is used to identify fasl files. Even though this is not +;;; declared as a constant (because ANSI Common Lisp has no facility +;;; for declaring values which are constant under EQUAL but not EQL), +;;; obviously you shouldn't mess with it lightly. If you do set a new +;;; value for some reason, keep these things in mind: +;;; * To avoid confusion with the similar but incompatible CMU CL +;;; fasl file format, the value should not be "FASL FILE", which +;;; is what CMU CL used for the same purpose. +;;; * Since its presence at the head of a file is used by LOAD to +;;; decide whether a file is to be fasloaded or just loaded +;;; ordinarily (as source), the value should be something which +;;; can't legally appear at the head of a Lisp source file. +;;; * The value should not contain any line-terminating characters, +;;; because they're hard to express portably and because the LOAD +;;; code might reasonably use READ-LINE to get the value to compare +;;; against. +(defglobal *fasl-header-string-start-string* "# FASL") + +;;; a list of SB-XC:*FEATURES* flags which affect binary compatibility, +;;; i.e. which must be the same between the SBCL which compiled the code +;;; and the SBCL which executes the code. This is a property of SBCL executables +;;; in the abstract, not of this particular SBCL executable, +;;; so any flag in this list may or may not be present +;;; in the *FEATURES* list of this particular build. +(defglobal *features-potentially-affecting-fasl-format* + (append '(:sb-thread :sb-unicode :cheneygc :gencgc :msan :sb-safepoint))) + +;;; the code for a character which terminates a fasl file header +(defconstant +fasl-header-string-stop-char-code+ 255) + +;;; This value should be incremented when the system changes in such a +;;; way that it will no longer work reliably with old fasl files. In +;;; practice, I (WHN) have often forgotten to increment it for CVS +;;; versions which break binary compatibility. But it certainly should +;;; be incremented for release versions which break binary +;;; compatibility. +(defconstant +fasl-file-version+ 78) +;;; (description of versions before 0.9.0.1 deleted in 0.9.17) +;;; 56: (2005-05-22) Something between 0.9.0.1 and 0.9.0.14. My money is +;;; on 0.9.0.6 (MORE CASE CONSISTENCY). +;;; 57: (2005-06-12) Raw slot rearrangement in 0.9.1.38 +;;; 58: (2005-08-16) Multiple incompatible changes between 0.9.3 and 0.9.3.60 +;;; 59: (2005-09-18) METAOBJECT implementation, removal of INSTANCE and +;;; FUNCALLABLE-INSTANCE classes. +;;; 60: (2005-10-24) Bumped for 0.9.6 +;;; 61: (2005-11-06) Improved source location recording added extra parameters +;;; to multiple %DEFMUMBLE functions. +;;; 62: (2005-12-30) Make the count of FASL header counted strings +;;; a 32-bit value also on 64-bit platforms. +;;; 63: (2006-01-27) Shuffle storage classes around to reduce the error +;;; trap information size on RISCy platforms. +;;; 64: (2006-03-24) New calling convention for unknown-values on x86 and +;;; x86-64. Also (belatedly) PPC/gencgc, including :gencgc on FPAFF. +;;; 65: (2006-04-11) Package locking interface changed. +;;; 66: (2006-05-13) Fopcompiler +;;; 67: (2006-07-25) Reports on #lisp about 0.9.13 fasls being invalid on +;;; 0.9.14.something +;;; 68: (2006-08-14) changed number of arguments of LOAD-DEFMETHOD +;;; 69: (2006-08-17) changed validity of various initargs for methods +;;; 70: (2006-09-13) changes to *PSEUDO-ATOMIC* on x86 and x86-64 +;;; 71: (2006-11-19) CLOS calling convention changes +;;; 72: (2006-12-05) Added slot to the primitive function type +;;; 73: (2007-04-13) Changed a hash function +;;; 74: (2007-06-05) UNWIND-TO-FRAME-AND-CALL +;;; 75: (2007-08-06) FD-STREAM layout changes +;;; 76: (2007-10-05) MUTEX layout changes +;;; 77: (2007-11-08) Essentially obsolete fasl-file-version, fasls are now +;;; considered compatible only when the version numbers of the compiling +;;; SBCL instance is exactly the same as the one of the loading instance. +;;; Further fasl-file-version bumps should only be done for real changes +;;; in the fasl format, not for changes in function/macro signatures or +;;; lisp data structures. +;;; 78: (2010-04-02) Add FOP-{SMALL-,}NAMED-PACKAGE, remove FOP-NORMAL-LOAD +;;; and FOP-MAYBE-COLD-LOAD. + +;;; the conventional file extension for our fasl files +;;; FIXME this should be (DEFCONSTANT-EQX +FASL-FILE-TYPE+ "fasl" #'EQUAL), +;;; but renaming the variable would harm 'asdf-dependency-grovel' and other +;;; random 3rd-party libraries. However, we can't keep the name and make it +;;; constant, because the compiler warns about asterisks on constants. +;;; So we keep the asterisks and make it defglobal. +(declaim (type simple-string *fasl-file-type*)) +(defglobal *fasl-file-type* "fasl") + +;;;; internal state variables + +(defvar *load-depth* 0 + "the current number of recursive LOADs") +(declaim (type index *load-depth*)) + ;;;; miscellaneous load utilities +(defun make-fop-vector (size) + (declare (type index size)) + (let ((vector (make-array size))) + (setf (aref vector 0) 0) + vector)) + +;;; a holder for the FASL file we're reading from +(defstruct (fasl-input (:conc-name %fasl-input-) + (:constructor make-fasl-input (stream print)) + (:predicate nil) + (:copier nil)) + (stream nil :type ansi-stream :read-only t) + (table (make-fop-vector 1000) :type simple-vector) + (stack (make-fop-vector 100) :type simple-vector) + (name-buffer (vector (make-string 1 :element-type 'character) + (make-string 31 :element-type 'base-char))) + (print nil :type boolean) + ;; We keep track of partial source info for the input in case + ;; loading gets interrupted. + (partial-source-info nil :type (or null sb-c::debug-source))) +(declaim (freeze-type fasl-input)) + +;;; Lisp assembler routines are named by Lisp symbols, not strings, +;;; and so can be compared by EQ. +(define-load-time-global *assembler-routines* nil) +#+immobile-space (define-load-time-global *asm-routine-vector* nil) +#-sb-xc-host (declaim (code-component *assembler-routines*)) + ;;; Output the current number of semicolons after a fresh-line. ;;; FIXME: non-mnemonic name (defun load-fresh-line () @@ -43,8 +167,6 @@ ;;;; utilities for reading from fasl files -#-sb-fluid (declaim (inline read-byte)) - ;;; This expands into code to read an N-byte unsigned integer using ;;; FAST-READ-BYTE. (defmacro fast-read-u-integer (n) @@ -99,13 +221,7 @@ `(with-fast-read-byte ((unsigned-byte 8) ,fasl-input-stream) (fast-read-u-integer ,n)))) -;; FIXME: on x86-64, these functions exceed 600, 900, and 1200 bytes of code -;; respectively. Either don't inline them, or make a "really" fast inline case -;; that punts if inapplicable. e.g. if the fast-read-byte buffer will not be -;; refilled, then SAP-REF-WORD could work to read 8 bytes. -;; But this would only be feasible on machines that are little-endian -;; and that allow unaligned reads. (like x86) -(declaim (inline read-byte-arg read-word-arg)) +(declaim (inline read-byte-arg)) (defun read-byte-arg (stream) (declare (optimize (speed 0))) (read-arg 1 stream)) @@ -118,6 +234,56 @@ (declare (optimize (speed 0))) (read-arg 4 stream)) +;;; helper functions for reading string values from FASL files: sort +;;; of like READ-SEQUENCE specialized for files of (UNSIGNED-BYTE 8), +;;; with an automatic conversion from (UNSIGNED-BYTE 8) into CHARACTER +;;; for each element read + +;;; Variation 1: character string, transfer elements of type (unsigned-byte 8) +;;: [Can we eliminate this one?] +(defun read-string-as-bytes (stream string &optional (length (length string))) + (declare (type (simple-array character (*)) string) + (type index length) + (optimize speed)) + (with-fast-read-byte ((unsigned-byte 8) stream) + (dotimes (i length) + (setf (aref string i) + (code-char (fast-read-byte))))) + string) +;;; Variation 2: base-string, transfer elements of type (unsigned-byte 8) +(defun read-base-string-as-bytes (stream string &optional (length (length string))) + (declare (type (simple-array base-char (*)) string) + (type index length) + (optimize speed)) + (with-fast-read-byte ((unsigned-byte 8) stream) + (dotimes (i length) + (setf (aref string i) + (code-char (fast-read-byte))))) + string) +;;; Variation 3: character-string, transfer elements of type varint +(defun read-char-string-as-varints + (stream string &optional (length (length string))) + (declare (type (simple-array character (*)) string) + (type index length) + (optimize speed)) + (with-fast-read-byte ((unsigned-byte 8) stream) + ;; OAOO violation- This repeats code in DEFINE-READ-VAR-INTEGER in 'debug-var-io' + ;; but there isn't a good expansion of that macro that would operate on a stream + ;; (which is ok in itself) but also that would entail only a single wrapping of + ;; WITH-FAST-READ-BYTE for all work. + ;; i.e. we don't want to update the stream slots after each varint. + (flet ((read-varint () + (loop for shift :of-type (integer 0 28) from 0 by 7 ; position in integer + for octet = (fast-read-byte) + for accum :of-type (mod #.char-code-limit) + = (logand octet #x7F) + then (logior (ash (logand octet #x7F) shift) accum) + unless (logbitp 7 octet) return accum))) + (dotimes (i length) + (setf (aref string i) + (code-char (read-varint)))))) + string) + ;;;; the fop table @@ -191,6 +357,107 @@ (setf (svref stack 0) next (svref stack next) value))) +;;; Bind STACK-VAR and PTR-VAR to the start of a subsequence of +;;; the fop stack of length COUNT, then execute BODY. +;;; Within the body, FOP-STACK-REF is used in lieu of SVREF +;;; to elide bounds checking. +(defmacro with-fop-stack (((stack-var &optional stack-expr) ptr-var count) + &body body) + `(macrolet ((fop-stack-ref (i) + `(locally + #-sb-xc-host + (declare (optimize (sb-c:insert-array-bounds-checks 0))) + (svref ,',stack-var (truly-the index ,i))))) + (let* (,@(when stack-expr + (list `(,stack-var (the simple-vector ,stack-expr)))) + (,ptr-var (truly-the index (fop-stack-pop-n ,stack-var ,count)))) + ,@body))) + + +;;;; the FOP database + +(eval-when (:compile-toplevel :load-toplevel :execute) + ;; The bottom 5 bits of the opcodes above 128 encode an implicit operand. + (defconstant n-ordinary-fops 128)) + +;;; a vector indexed by a FaslOP that yields a function which performs +;;; the operation. Most functions take 0 arguments - they only manipulate +;;; the fop stack. But if the fop is defined to receive an argument (or two) +;;; then loader's main loop is responsible for supplying it. +(defglobal **fop-funs** (make-array n-ordinary-fops :initial-element 0)) +(declaim (type (simple-vector #.n-ordinary-fops) **fop-funs**)) + +;;; Two arrays indicate fop function signature. +;;; The first array indicates how many integer operands follow the opcode. +;;; The second tells whether the fop wants its result pushed on the stack. +(declaim (type (cons (simple-array (mod 4) (#.n-ordinary-fops)) + (simple-bit-vector #.n-ordinary-fops)) + **fop-signatures**)) +(defglobal **fop-signatures** + (cons (make-array n-ordinary-fops :element-type '(mod 4) :initial-element 0) + (make-array n-ordinary-fops :element-type 'bit :initial-element 0))) + + +;;; Define NAME as a fasl operation, with op-code FOP-CODE. +;;; PUSHP describes what the body does to the fop stack: +;;; T - The result of the body is pushed on the fop stack. +;;; NIL - The result of the body is discarded. +;;; In either case, the body is permitted to pop the stack. +;;; +(defmacro define-fop (fop-code &rest stuff) + (multiple-value-bind (name allowp operands stack-args pushp forms) + (let ((allowp (if (eq (car stuff) :not-host) + (progn (pop stuff) (or #-sb-xc-host t)) + t))) + (destructuring-bind ((name &optional arglist (pushp t)) . forms) stuff + (aver (member pushp '(nil t))) + (multiple-value-bind (operands stack-args) + (if (atom (car arglist)) + (values nil arglist) + (ecase (caar arglist) + (:operands (values (cdar arglist) (cdr arglist))))) + (assert (<= (length operands) 3)) + (values name allowp operands stack-args pushp forms)))) + `(progn + (defun ,name (.fasl-input. ,@operands) + (declare (ignorable .fasl-input.)) + ,@(if allowp + `((macrolet + ((fasl-input () '(truly-the fasl-input .fasl-input.)) + (fasl-input-stream () '(%fasl-input-stream (fasl-input))) + (operand-stack () '(%fasl-input-stack (fasl-input)))) + ,@(if (null stack-args) + forms + (with-unique-names (stack ptr) + `((with-fop-stack ((,stack (operand-stack)) + ,ptr ,(length stack-args)) + (multiple-value-bind ,stack-args + (values ,@(loop for i below (length stack-args) + collect `(fop-stack-ref (+ ,ptr ,i)))) + ,@forms))))))) + `((declare (ignore ,@operands)) + (error ,(format nil "Not-host fop invoked: ~A" name))))) + (!%define-fop ',name ,fop-code ,(length operands) ,(if pushp 1 0))))) + +(defun !%define-fop (name opcode n-operands pushp) + (declare (type (mod 4) n-operands)) + (let ((function (svref **fop-funs** opcode))) + (when (functionp function) + (let ((oname (nth-value 2 (function-lambda-expression function)))) + (when (and oname (not (eq oname name))) + (cerror "Define it anyway" + "fop ~S with opcode ~D conflicts with fop ~S." + name opcode oname)))) + (let ((existing-opcode (get name 'opcode))) + (when (and existing-opcode (/= existing-opcode opcode)) + (error "multiple codes for fop name ~S: ~D and ~D" + name opcode existing-opcode))) + (setf (get name 'opcode) opcode + (svref **fop-funs** opcode) (symbol-function name) + (aref (car **fop-signatures**) opcode) n-operands + (sbit (cdr **fop-signatures**) opcode) pushp)) + name) + ;;;; Conditions signalled on invalid fasls (wrong fasl version, etc), ;;;; so that user code (esp. ASDF) can reasonably handle attempts to @@ -262,6 +529,33 @@ (when p (file-position stream p))))))) +;;; Return a string representing symbols in *FEATURES-POTENTIALLY-AFFECTING-FASL-FORMAT* +;;; which are present in a particular compilation. +(defun compute-features-affecting-fasl-format () + (let ((list (sort (copy-list (intersection *features-potentially-affecting-fasl-format* + sb-xc:*features*)) + #'string< :key #'symbol-name))) + ;; Stringify the subset of *FEATURES* that affect fasl format. + ;; A list would be the natural representation choice for this, but a string + ;; is convenient for and a requirement for writing to and reading from fasls + ;; at this stage of the loading. WITH-STANDARD-IO-SYNTAX and WRITE-TO-STRING + ;; would work, but this is simple enough to do by hand. + (%with-output-to-string (stream) + (let ((delimiter #\()) + (dolist (symbol list) + (write-char delimiter stream) + (write-string (string symbol) stream) + (setq delimiter #\Space))) + (write-char #\) stream)))) + +#-sb-xc-host +(eval-when (:compile-toplevel) + (let ((string (compute-features-affecting-fasl-format))) + (assert (and (> (length string) 2) + (not (find #\newline string)) + (not (find #\# string)) + (not (search ".." string)))))) + ;;;; LOAD-AS-FASL ;;;; ;;;; Note: LOAD-AS-FASL is used not only by LOAD, but also (with @@ -306,7 +600,12 @@ (result (make-string length))) (read-string-as-bytes stream result) (push result results) - result))) + result)) + (unsuffix (s) + (if (and (> (length s) 4) + (string= s "-WIP" :start1 (- (length s) 4))) + (subseq s 0 (- (length s) 4)) + s))) ;; Read and validate implementation and version. (let ((implementation (string-from-stream)) (expected-implementation +backend-fasl-file-implementation+)) @@ -322,9 +621,9 @@ (sbcl-version (if (<= fasl-version 76) "1.0.11.18" (string-from-stream))) - (expected-version (sb-xc:lisp-implementation-version))) + (expected-version (lisp-implementation-version))) (push fasl-version results) - (unless (string= expected-version sbcl-version) + (unless (string= (unsuffix expected-version) (unsuffix sbcl-version)) (restart-case (error 'invalid-fasl-version :stream stream @@ -386,17 +685,7 @@ ;;; Return true if we successfully load a group from the stream, or ;;; NIL if EOF was encountered while trying to read from the stream. ;;; Dispatch to the right function for each fop. -;;; -;;; When true, PRINT causes most tlf-equivalent forms to print their primary value. -;;; This differs from loading of Lisp source, which prints all values of -;;; only truly-toplevel forms. This is permissible per CLHS - -;;; "If print is true, load incrementally prints information to standard -;;; output showing the progress of the loading process. [...] -;;; For a compiled file, what is printed might not reflect precisely the -;;; contents of the source file, but some information is generally printed." -;;; -(defun load-fasl-group (fasl-input print) - (declare (ignorable print)) +(defun load-fasl-group (fasl-input) (let ((stream (%fasl-input-stream fasl-input)) (trace *show-fops-p*)) (unless (check-fasl-header stream) @@ -427,51 +716,627 @@ byte n-operands arg1 arg2 arg3) (when (functionp function) - (format *trace-output* " ~35t~(~a~)" (%fun-name function)))) - (let ((stack (%fasl-input-stack fasl-input))) - (declare (ignorable stack)) ; not used in xc-host - (when (and (eq byte #.(get 'fop-funcall-for-effect 'opcode)) - (fop-stack-empty-p stack)) ; (presumed) end of TLF - (awhen (%fasl-input-deprecated-stuff fasl-input) - ;; Delaying this message rather than printing it - ;; in fop-fdefn makes it more informative (usually). - (setf (%fasl-input-deprecated-stuff fasl-input) nil) - (loader-deprecation-warn - it - (and (eq (svref stack 1) 'sb-impl::%defun) (svref stack 2)))) - (when print - (load-fresh-line) - (prin1 result))))))))) - -;; This is the moral equivalent of a warning from /usr/bin/ld that -;; "gets() is dangerous." You're informed by both the compiler and linker. -(defun loader-deprecation-warn (stuff whence) - ;; Stuff is a list: ((<state> name . category) ...) - ;; For now we only deal with category = :FUNCTION so we ignore it. - (let ((warning-class - ;; We're only going to warn once (per toplevel form), - ;; so pick the most stern warning applicable. - (if (every (lambda (x) (eq (car x) :early)) stuff) - 'simple-style-warning 'simple-warning))) - (warn warning-class - :format-control "Reference to deprecated function~P ~S~@[ from ~S~]" - :format-arguments - (list (length stuff) (mapcar #'second stuff) whence)))) + (format *trace-output* " ~35t~(~a~)" (%fun-name function))))))))) (defun load-as-fasl (stream verbose print) (when (zerop (file-length stream)) (error "attempt to load an empty FASL file:~% ~S" (namestring stream))) (maybe-announce-load stream verbose) - (let ((fasl-input (make-fasl-input stream))) - (unwind-protect - (loop while (load-fasl-group fasl-input print)) - ;; Nuke the table and stack to avoid keeping garbage on - ;; conservatively collected platforms. - (nuke-fop-vector (%fasl-input-table fasl-input)) - (nuke-fop-vector (%fasl-input-stack fasl-input)))) + (let ((fasl-input (make-fasl-input stream print))) + (with-loader-package-names + (unwind-protect + (loop while (load-fasl-group fasl-input)) + ;; Nuke the table and stack to avoid keeping garbage on + ;; conservatively collected platforms. + (nuke-fop-vector (%fasl-input-table fasl-input)) + (nuke-fop-vector (%fasl-input-stack fasl-input))))) t) -(declaim (notinline read-byte)) ; Why is it even *declaimed* inline above? + +;;; Compatibity macros that allow some fops to share the identical +;;; body between genesis and the target code. +#-sb-xc-host +(progn + (defmacro cold-cons (x y) `(cons ,x ,y)) + (defmacro number-to-core (x) x) + (defmacro make-character-descriptor (x) `(code-char ,x))) + +;;;; Actual FOP definitions: + +(define-fop 0 (fop-nop () nil)) +(define-fop 1 (fop-pop (x) nil) (push-fop-table x (fasl-input))) +(define-fop 2 (fop-empty-list) nil) +(define-fop 3 (fop-truth) t) +(define-fop 4 (fop-push ((:operands index))) + (ref-fop-table (fasl-input) index)) +(define-fop 5 (fop-move-to-table (x)) + (push-fop-table x (fasl-input)) + x) + +(define-fop 66 :not-host (fop-misc-trap) + (make-unbound-marker)) + +(define-fop 76 (fop-character ((:operands char-code))) + (make-character-descriptor char-code)) + +;; %MAKE-INSTANCE does not exist on the host. +(define-fop 48 :not-host (fop-struct ((:operands size) layout)) + (let ((res (sb-kernel::%new-instance* layout size)) ; number of words excluding header + ;; Discount the layout from number of user-visible words. + (n-data-words (- size sb-vm:instance-data-start))) + (with-fop-stack ((stack (operand-stack)) ptr n-data-words) + (declare (type index ptr)) + ;; FIXME: this is basically DO-LAYOUT-BITMAP, but probably not as efficient. + (let ((bitmap (sb-kernel::%layout-bitmap layout))) + ;; Values on the stack are in the same order as in the structure itself. + (do ((i sb-vm:instance-data-start (1+ i))) + ((>= i size)) + (declare (type index i)) + (let ((val (fop-stack-ref ptr))) + (if (logbitp i bitmap) + (%instance-set res i val) + (%raw-instance-set/word res i val)) + (incf ptr))))) + res)) + +;;; Symbol-like entities +(define-fop 49 :not-host (fop-debug-name-marker ((:operands kind))) + (ecase kind + (1 sb-c::*debug-name-sharp*) + (2 sb-c::*debug-name-ellipsis*))) + +(define-fop 45 :not-host (fop-layout ((:operands depthoid flags length) + name bitmap inherits)) + (decf depthoid) ; was bumped by 1 since non-stack args can't encode negatives + (sb-kernel::load-layout name depthoid inherits length bitmap flags)) + +;;; This is dumped when the compiler detects that MAKE-LOAD-FORM +;;; returned a simple use of MAKE-LOAD-FORM-SAVING-SLOTS, or possibly +;;; a hand-written equivalent (however unlikely). +(define-fop 68 :not-host (fop-instance ((:operands n-slots) name)) + (let* ((instance (allocate-instance (find-class (the symbol name)))) + (stack (operand-stack)) + (ptr (fop-stack-pop-n stack (* 2 n-slots)))) + (dotimes (i n-slots) + (let* ((index (+ ptr (* 2 i))) + (value (svref stack index)) + (slot-name (svref stack (1+ index)))) + (if (unbound-marker-p value) + ;; SLOT-MAKUNBOUND-USING-CLASS might do something nonstandard. + (slot-makunbound instance slot-name) + (setf (slot-value instance slot-name) value)))) + instance)) + +(define-fop 64 (fop-end-group () nil) + (throw 'fasl-group-end t)) + +(define-fop 62 (fop-verify-table-size ((:operands expected-index)) nil) + (unless (= (svref (%fasl-input-table (fasl-input)) 0) expected-index) + (bug "fasl table of improper size"))) +(define-fop 63 (fop-verify-empty-stack () nil) + (unless (fop-stack-empty-p (operand-stack)) + (bug "fasl stack not empty when it should be"))) + +;;;; fops for loading symbols + +;;; Cold load has its own implementation of all symbol fops, +;;; but we have to execute define-fop now to assign their numbers. +;;; +;;; Any symbols created by the loader must have their SYMBOL-HASH computed. +;;; This is a requirement for the CASE macro to work. When code is compiled +;;; to memory, symbols in the expansion are subject to SXHASH, so all is well. +;;; When loaded, even uninterned symbols need a hash. +;;; Interned symbols automatically get a precomputed hash. +(labels #+sb-xc-host () + #-sb-xc-host + ((read-symbol-name (length+flag fasl-input) + (let* ((namelen (ash (the fixnum length+flag) -1)) + (base-p (logand length+flag 1)) + (elt-type (if (eql base-p 1) 'base-char 'character)) + (buffer (%fasl-input-name-buffer fasl-input)) + (string (the string (svref buffer base-p)))) + (when (< (length string) namelen) ; grow + (setf string (make-string namelen :element-type elt-type) + (svref buffer base-p) string)) + (funcall (if (eql base-p 1) + 'read-base-string-as-bytes + 'read-char-string-as-varints) + (%fasl-input-stream fasl-input) string namelen) + (values string namelen elt-type))) + (aux-fop-intern (length+flag package inherited fasl-input) + (multiple-value-bind (name length elt-type) + (read-symbol-name length+flag fasl-input) + (push-fop-table (%intern name length package elt-type t inherited) + fasl-input))) + (ensure-hashed (symbol) + ;; ENSURE-SYMBOL-HASH when vop-translated is flushable since it is + ;; conceptually just a slot reader, however its actual effect is to fill in + ;; the hash if absent, so it's not quite flushable when called expressly + ;; to fill in the slot. In this case we need a full call to ENSURE-SYMBOL-HASH + ;; to ensure the side-effect happens. + ;; Careful if changing this again. There'a regression test thank goodness. + (declare (notinline ensure-symbol-hash)) + (ensure-symbol-hash symbol) + symbol)) + + (define-fop 77 :not-host (fop-lisp-symbol-save ((:operands length+flag))) + (aux-fop-intern length+flag *cl-package* t (fasl-input))) + (define-fop 78 :not-host (fop-keyword-symbol-save ((:operands length+flag))) + (aux-fop-intern length+flag *keyword-package* t (fasl-input))) + (define-fop 79 :not-host (fop-symbol-in-package-save ((:operands length+flag pkg-index))) + (aux-fop-intern length+flag (ref-fop-table (fasl-input) pkg-index) t (fasl-input))) + (define-fop 84 :not-host (fop-symbol-in-package-internal-save ((:operands length+flag pkg-index))) + (aux-fop-intern length+flag (ref-fop-table (fasl-input) pkg-index) nil (fasl-input))) + + (define-fop 80 :not-host (fop-uninterned-symbol-save ((:operands length+flag))) + (multiple-value-bind (name len) (read-symbol-name length+flag (fasl-input)) + (push-fop-table (ensure-hashed (make-symbol (subseq name 0 len))) + (fasl-input)))) + + (define-fop 81 :not-host (fop-copy-symbol-save ((:operands table-index))) + (push-fop-table (ensure-hashed + (copy-symbol (ref-fop-table (fasl-input) table-index))) + (fasl-input)))) + +(define-fop 82 (fop-package (pkg-designator)) + (find-undeleted-package-or-lose pkg-designator)) + +(define-fop 83 :not-host (fop-named-package-save ((:operands length)) nil) + (let ((package-name (make-string length))) + (read-char-string-as-varints (fasl-input-stream) package-name) + (push-fop-table (find-or-maybe-make-deferred-package package-name) + (fasl-input)))) + +;;;; fops for loading numbers + +;;; Load a signed integer LENGTH bytes long from FASL-INPUT-STREAM. +(defun load-s-integer (length fasl-input-stream) + (declare (fixnum length) + (optimize speed) + #-sb-xc-host (muffle-conditions compiler-note)) + (with-fast-read-byte ((unsigned-byte 8) fasl-input-stream) + (do* ((index length (1- index)) + (byte 0 (fast-read-byte)) + (result 0 (+ result (ash byte bits))) + (bits 0 (+ bits 8))) + ((= index 0) + (if (logbitp 7 byte) ; look at sign bit + (- result (ash 1 bits)) + result)) + (declare (fixnum index byte bits))))) + +(define-fop 36 (fop-integer ((:operands n-bytes))) + (number-to-core (load-s-integer n-bytes (fasl-input-stream)))) + +(define-fop 33 :not-host (fop-word-pointer) + (with-fast-read-byte ((unsigned-byte 8) (fasl-input-stream)) + (int-sap (fast-read-u-integer #.sb-vm:n-word-bytes)))) + +(define-fop 34 (fop-word-integer) + (with-fast-read-byte ((unsigned-byte 8) (fasl-input-stream)) + (number-to-core (fast-read-s-integer #.sb-vm:n-word-bytes)))) + +(define-fop 35 (fop-byte-integer) + ;; FIXME: WITH-FAST-READ-BYTE for exactly 1 byte is not really faster/better + ;; than regular READ-BYTE. The expansion of READ-ARG corroborates this claim. + (with-fast-read-byte ((unsigned-byte 8) (fasl-input-stream)) + (number-to-core (fast-read-s-integer 1)))) + +;; There's a long tail to the distribution of FOP-BYTE-INTEGER uses, +;; but these 4 seem to account for about half of them. +(define-fop 37 (fop-int-const0) (number-to-core 0)) +(define-fop 38 (fop-int-const1) (number-to-core 1)) +(define-fop 39 (fop-int-const2) (number-to-core 2)) +(define-fop 40 (fop-int-const-neg1) (number-to-core -1)) + +(define-fop 70 (fop-ratio (num den)) + #+sb-xc-host (number-pair-to-core num den sb-vm:ratio-widetag) + #-sb-xc-host (%make-ratio num den)) + +(define-fop 71 (fop-complex (realpart imagpart)) + #+sb-xc-host (number-pair-to-core realpart imagpart sb-vm:complex-widetag) + #-sb-xc-host (%make-complex realpart imagpart)) + +(macrolet ((fast-read-single-float () + '(make-single-float (fast-read-s-integer 4))) + (fast-read-double-float () + '(let ((lo (fast-read-u-integer 4))) + (make-double-float (fast-read-s-integer 4) lo)))) + (macrolet ((define-complex-fop (opcode name type) + (let ((reader (symbolicate "FAST-READ-" type))) + `(define-fop ,opcode (,name) + (with-fast-read-byte ((unsigned-byte 8) (fasl-input-stream)) + (number-to-core (complex (,reader) (,reader))))))) + (define-float-fop (opcode name type) + (let ((reader (symbolicate "FAST-READ-" type))) + `(define-fop ,opcode (,name) + (with-fast-read-byte ((unsigned-byte 8) (fasl-input-stream)) + (number-to-core (,reader))))))) + (define-complex-fop 72 fop-complex-single-float single-float) + (define-complex-fop 73 fop-complex-double-float double-float) + #+long-float + (define-complex-fop 67 fop-complex-long-float long-float) + (define-float-fop 46 fop-single-float single-float) + (define-float-fop 47 fop-double-float double-float) + #+long-float + (define-float-fop 52 fop-long-float long-float))) + +#+sb-simd-pack +(define-fop 88 :not-host (fop-simd-pack) + (with-fast-read-byte ((unsigned-byte 8) (fasl-input-stream)) + (let ((tag (fast-read-s-integer 8))) + (cond #+sb-simd-pack-256 + ((logbitp 6 tag) + (%make-simd-pack-256 (logand tag #b00111111) + (fast-read-u-integer 8) + (fast-read-u-integer 8) + (fast-read-u-integer 8) + (fast-read-u-integer 8))) + (t + (%make-simd-pack tag + (fast-read-u-integer 8) + (fast-read-u-integer 8))))))) + +;;;; loading lists + +(defun fop-list (fasl-input n &aux (stack (%fasl-input-stack fasl-input))) + (declare (type index n) + (optimize (speed 3))) + (with-fop-stack ((stack) ptr n) + (do* ((i (+ ptr n) (1- i)) + (res () (cold-cons (fop-stack-ref i) res))) + ((= i ptr) res) + (declare (type index i))))) +(defun fop-list* (fasl-input n &aux (stack (%fasl-input-stack fasl-input))) + (declare (type index n) + (optimize (speed 3))) + (with-fop-stack ((stack) ptr (1+ n)) + (do* ((i (+ ptr n) (1- i)) + (res (fop-stack-ref (+ ptr n)) + (cold-cons (fop-stack-ref i) res))) + ((= i ptr) res) + (declare (type index i))))) + +;;;; fops for loading arrays + +(define-fop 100 :not-host (fop-base-string ((:operands length))) + (logically-readonlyize + (read-base-string-as-bytes (fasl-input-stream) + (make-string length :element-type 'base-char)))) + +(define-fop 101 :not-host (fop-character-string ((:operands length))) + (logically-readonlyize + (read-char-string-as-varints (fasl-input-stream) (make-string length)))) + +(define-fop 92 (fop-vector ((:operands size))) + (if (zerop size) + #() + (let ((res (make-array size)) + (stack (operand-stack))) + (declare (fixnum size)) + (let ((ptr (fop-stack-pop-n stack size))) + (replace res stack :start2 ptr)) + (logically-readonlyize res)))) + +;; No MAKE-ARRAY-HEADER on host +(define-fop 89 :not-host (fop-array ((:operands rank) vec)) + (let ((length (length vec)) + (res (make-array-header sb-vm:simple-array-widetag rank))) + (declare (simple-array vec) + (type (unsigned-byte #.(- sb-vm:n-word-bits sb-vm:n-widetag-bits)) rank)) + (set-array-header res vec length nil 0 (fop-list (fasl-input) rank) nil t) + res)) + +(define-fop 43 (fop-spec-vector ((:operands length))) + (let* ((widetag (read-byte-arg (fasl-input-stream))) + (bits (* length (sb-vm::simple-array-widetag->bits-per-elt widetag))) + (bytes (ceiling bits sb-vm:n-byte-bits)) + (words (ceiling bytes sb-vm:n-word-bytes)) + (vector (logically-readonlyize + (allocate-vector #+(and (not sb-xc-host) ubsan) nil + widetag length words)))) + (declare (type index length bytes words) + (type word bits)) + (read-n-bytes (fasl-input-stream) vector 0 bytes) + vector)) + +(defun fop-funcall* (argc stack) + (with-fop-stack ((stack) ptr (1+ argc)) + (if (zerop argc) + (funcall (fop-stack-ref ptr)) + (do ((i (+ ptr argc)) + (args)) + ((= i ptr) (apply (fop-stack-ref i) args)) + (declare (type index i)) + (push (fop-stack-ref i) args) + (decf i))))) + +(define-fop 55 (fop-funcall ((:operands n))) + (fop-funcall* n (operand-stack))) +(define-fop 56 (fop-funcall-for-effect ((:operands n)) nil) + (fop-funcall* n (operand-stack))) + +;;;; fops for fixing up circularities + +(define-fop 11 (fop-rplaca ((:operands tbl-slot index) value) nil) + (let ((obj (ref-fop-table (fasl-input) tbl-slot))) + (setf (car (nthcdr index obj)) value))) + +(define-fop 12 (fop-rplacd ((:operands tbl-slot index) value) nil) + (let ((obj (ref-fop-table (fasl-input) tbl-slot))) + (setf (cdr (nthcdr index obj)) value))) + +(define-fop 13 (fop-svset ((:operands tbl-slot index) value) nil) + (setf (svref (ref-fop-table (fasl-input) tbl-slot) index) value)) + +(define-fop 14 :not-host (fop-structset ((:operands tbl-slot index) value) nil) + (%instance-set (ref-fop-table (fasl-input) tbl-slot) index value)) + +(define-fop 15 :not-host (fop-slotset ((:operands tbl-slot index) value slot-name) nil) + index + (setf (slot-value (ref-fop-table (fasl-input) tbl-slot) slot-name) value)) + +(define-fop 16 (fop-nthcdr ((:operands n) obj)) + (nthcdr n obj)) + +;;;; fops for loading functions + +;;; (In CMU CL there was a FOP-CODE-FORMAT (47) which was +;;; conventionally placed at the beginning of each fasl file to test +;;; for compatibility between the fasl file and the CMU CL which +;;; loaded it. In SBCL, this functionality has been replaced by +;;; putting the implementation and version in required fields in the +;;; fasl file header.) + +;;; Caution: don't try to "test" WITH-WRITABLE-CODE-INSTRUCTIONS in copy-in/out mode +;;; on any architecture where fixup application cares what the address of the code actually is. +;;; This means x86 is disqualified. You're just wasting your time if you try, as I did. +(defmacro with-writable-code-instructions ((code-var total-nwords debug-info-var + n-fdefns n-funs) + &key copy fixup) + (declare (ignorable n-fdefns)) + ;; N-FDEFNS is important for PPC64, slightly important for X86-64, not important for + ;; any others, and doesn't even have a place to store it if lispwords are 32 bits. + ;; The :DEDUPLICATED-FDEFNS test in compiler-2.pure asserts that the value is valid + (let ((body + ;; The following operations need the code pinned: + ;; 1. copying into code-instructions (a SAP) + ;; 2. apply-core-fixups and sanctify-for-execution + ;; A very specific store order is necessary to allow using uninitialized memory + ;; pages for code. Storing of the debug-info slot must occur between steps 1 and 2. + ;; Note that this does not have to take care to ensure atomicity + ;; of the store to the final word of unboxed data. Even if BYTE-BLT were + ;; interrupted in between the store of any individual byte, this code + ;; is GC-safe because we no longer need to know where simple-funs are embedded + ;; within the object to trace pointers. We *do* need to know where the funs + ;; are when transporting the object, but it's pinned within the body forms. + `(,copy + (sb-c::code-header/trailer-adjust ,code-var ,total-nwords ,n-fdefns) + ;; Check that the code trailer matches our expectation on number of embedded simple-funs + (aver (= (code-n-entries ,code-var) ,n-funs)) + ;; Until debug-info is assigned, it is illegal to create a simple-fun pointer + ;; into this object, because the C code assumes that the fun table is in an + ;; invalid/incomplete state (i.e. can't be read) until the code has debug-info. + ;; That is, C code can't deal with an interior code pointer until the fun-table + ;; is valid. This store must occur prior to calling %CODE-ENTRY-POINT, and + ;; applying fixups calls %CODE-ENTRY-POINT, so we have to do this before that. + (setf (%code-debug-info ,code-var) ,debug-info-var) + ,fixup))) + #+darwin-jit + `(with-pinned-objects (,code-var ,debug-info-var) + ;; DEBUG-INFO is pinned so that after assigning it into the temporary + ;; block of memory, the off-heap word which is invisible to GC remains valid. + (let* ((temp-copy (alien-funcall (extern-alien "duplicate_codeblob_offheap" + (function unsigned unsigned)) + (get-lisp-obj-address ,code-var))) + (aligned (+ temp-copy (logand temp-copy sb-vm:n-word-bytes)))) + ;; Rebind CODE-VAR to the replica, then execute BODY + (let ((,code-var (%make-lisp-obj (logior aligned sb-vm:other-pointer-lowtag)))) ,@body) + ;; Copy back, and fixup the simple-funs in the managed object + (alien-funcall (extern-alien "jit_copy_code_insts" (function void unsigned unsigned)) + (get-lisp-obj-address ,code-var) + temp-copy))) + #-darwin-jit + `(with-pinned-objects (,code-var) ,@body))) + +(define-load-time-global *show-new-code* nil) +#+sb-xc-host +(defun possibly-log-new-code (object reason) + (declare (ignore reason)) + object) +#-sb-xc-host +(defun possibly-log-new-code (object reason &aux (show *show-new-code*)) + (when show + (let ((size (code-object-size object)) + (fmt "~&New code(~Db,~A): ~A~%") + (file "jit-code.txt") + (*print-pretty* nil)) + ;; DISASSEMBLE is for limited debugging only. + ;; It may write garbled output if multiple threads + ;; I tried WITH-OPEN-STREAM during cold-init and got: + ;; "vicious metacircle: The computation of an effective method of + ;; #<STREAM-FUNCTION COMMON-LISP:CLOSE (2)> for arguments of types + ;; (#<STRUCTURE-CLASS SB-SYS:FD-STREAM>) uses the effective method + ;; being computed." + ;; so just leave the stream open. Or we could call the fd-stream misc routine. + (if (or (eq show 'disassemble) (streamp show)) + (let ((f (if (streamp show) + show + (prog1 + (setq *show-new-code* + (open file :direction :output + :if-exists :append :if-does-not-exist :create)) + (format t "~&; Logging code allocation to ~S~%" file))))) + (format f fmt size reason object) + (disassemble object :stream f) + (terpri f) + (force-output f)) + (format *trace-output* fmt (code-object-size object) reason object)))) + object) + +(define-fop 17 :not-host (fop-load-code ((:operands header n-code-bytes n-fixup-elts))) + ;; The stack looks like: + ;; ... | constant0 constant1 ... constantN | DEBUG-INFO | FIXUPS-ITEMS .... || + ;; | <--------- n-constants ---------> | | <-- n-fixup-elts -> || + (let* ((n-simple-funs (read-unsigned-byte-32-arg (fasl-input-stream))) + (n-fdefns (read-unsigned-byte-32-arg (fasl-input-stream))) + (n-boxed-words (ash header -1)) + (n-constants (- n-boxed-words sb-vm:code-constants-offset)) + (stack-elts-consumed (+ n-constants 1 n-fixup-elts))) + (with-fop-stack ((stack (operand-stack)) ptr stack-elts-consumed) + ;; We've already ensured that all FDEFNs the code uses exist. + ;; This happened by virtue of calling fop-fdefn for each. + (loop for stack-index from (+ ptr (* n-simple-funs sb-vm:code-slots-per-simple-fun)) + repeat n-fdefns + do (aver (typep (svref stack stack-index) 'fdefn))) + (binding* (((code total-nwords) + (sb-c:allocate-code-object + (if (oddp header) :immobile :dynamic) + (align-up n-boxed-words sb-c::code-boxed-words-align) + n-code-bytes)) + (real-code code) + (debug-info (svref stack (+ ptr n-constants)))) + (with-writable-code-instructions + (code total-nwords debug-info n-fdefns n-simple-funs) + :copy (read-n-bytes (fasl-input-stream) (code-instructions code) 0 n-code-bytes) + :fixup (sb-c::apply-fasl-fixups code stack (+ ptr (1+ n-constants)) n-fixup-elts real-code)) + ;; Don't need the code pinned from here on + (setf (sb-c::debug-info-source (%code-debug-info code)) + (%fasl-input-partial-source-info (fasl-input))) + ;; Boxed constants can be assigned only after figuring out where the range + ;; of implicitly tagged words is, which requires knowing how many functions + ;; are in the code component, which requires reading the code trailer. + #+darwin-jit (sb-c::assign-code-constants code (subseq stack ptr (+ ptr n-constants))) + #-darwin-jit + (let* ((header-index sb-vm:code-constants-offset) + (stack-index ptr)) + (declare (type index header-index stack-index)) + (dotimes (n (* n-simple-funs sb-vm:code-slots-per-simple-fun)) + (setf (code-header-ref code header-index) (svref stack stack-index)) + (incf header-index) + (incf stack-index)) + (dotimes (i n-fdefns) + (sb-c::set-code-fdefn code header-index (svref stack stack-index)) + (incf header-index) + (incf stack-index)) + (do () ((>= header-index n-boxed-words)) + (setf (code-header-ref code header-index) (svref stack stack-index)) + (incf header-index) + (incf stack-index))) + (when (typep (code-header-ref code (1- n-boxed-words)) + '(cons (eql sb-c::coverage-map))) + ;; Record this in the global list of coverage-instrumented code. + (atomic-push (make-weak-pointer code) (cdr *code-coverage-info*))) + (possibly-log-new-code code "load"))))) + +;; this gets you an #<fdefn> object, not the result of (FDEFINITION x) +;; cold-loader uses COLD-FDEFINITION-OBJECT instead. +(define-fop 18 :not-host (fop-fdefn (name)) + (when (deprecated-thing-p 'function name) + ;; This is the moral equivalent of a warning from /usr/bin/ld + ;; that "gets() is dangerous." You're informed by both the + ;; compiler and linker. + (check-deprecated-thing 'function name)) + (find-or-create-fdefn name)) + +(define-fop 19 :not-host (fop-known-fun (name)) + (%coerce-name-to-fun name)) + +;;; This FOP is only encountered in cross-compiled FASLs for cold load, +;;; and is a no-op except in cold load. A developer may want to load a +;;; cross-compiled FASL into a running system, and this FOP doesn't +;;; have to do anything, as the system can load top level forms and +;;; will define the function normally. +(define-fop 74 :not-host (fop-fset (name fn) nil) + (declare (ignore name fn))) + +;;; Like FOP-FSET, but for method definitions. +(define-fop 75 :not-host (fop-mset (name qualifiers specializer fn) nil) + (declare (ignore name qualifiers specializer fn))) + +;;; Modify a slot of the code boxed constants. +(define-fop 20 (fop-alter-code ((:operands index) code value) nil) + (flet (#+sb-xc-host + ((setf code-header-ref) (value code index) + (write-wordindexed code index value))) + (setf (code-header-ref code index) value) + (values))) + +;;; Set the named constant value in the boxed constants, setting up +;;; backpatching information if the symbol is not yet bound. Forward +;;; references can occur at load time when non-top-level components +;;; containing named constant references get loaded before the top +;;; level form defining the constant gets loaded. This can happen when +;;; top level lambdas get merged. +#-sb-xc-host +(defun named-constant-set (code index name) + (cond ((boundp name) + (setf (code-header-ref code index) (symbol-global-value name))) + (t + (push (lambda (value) + (setf (code-header-ref code index) value)) + (info :variable :forward-references name))))) + +(define-fop 121 :not-host (fop-named-constant-set ((:operands index) name code) nil) + (named-constant-set code index name)) + +(define-fop 21 (fop-fun-entry ((:operands fun-index) code-object)) + (let ((fun (%code-entry-point code-object fun-index))) + (when (%fasl-input-print (fasl-input)) + (load-fresh-line) + (format t "~S loaded" fun)) + fun)) + +;;;; assemblerish fops + +(define-fop 22 (fop-assembler-code) + (error "cannot load assembler code except at cold load")) + +;;;; fops for debug info + +(define-fop 124 (fop-note-partial-source-info (namestring created plist) nil) + (setf (%fasl-input-partial-source-info (fasl-input)) + (sb-c::make-debug-source :namestring namestring + :created created + :plist plist)) + (values)) + +;;;; fops for code coverage + +(define-fop 120 :not-host (fop-record-code-coverage (namestring cc) nil) + (setf (gethash namestring (car *code-coverage-info*)) cc) + (values)) + +;;; Primordial layouts. +(macrolet ((frob (&rest specs) + `(progn + (defun known-layout-fop (name) + (case name + ,@(mapcar (lambda (spec) `((,(cadr spec)) ,(car spec))) + specs))) + ,@(mapcar (lambda (spec) + `(define-fop ,(car spec) :not-host + (,(symbolicate "FOP-LAYOUT-OF-" + (cadr spec))) + ,(find-layout (cadr spec)))) + specs)))) + (frob (#x68 t) + (#x69 structure-object) + (#x6a condition) + (#x6b definition-source-location) + (#x6c sb-c::debug-info) + (#x6d sb-c::compiled-debug-info) + (#x6e sb-c::debug-source) + (#x6f defstruct-description) + (#x70 defstruct-slot-description) + (#x71 sb-c::debug-fun) + (#x72 sb-c::compiled-debug-fun) + (#x73 sb-c::compiled-debug-fun-optional) + (#x74 sb-c::compiled-debug-fun-more) + (#x75 sb-c::compiled-debug-fun-external) + (#x76 sb-c::compiled-debug-fun-toplevel) + (#x77 sb-c::compiled-debug-fun-cleanup))) + ;;;; stuff for debugging/tuning by collecting statistics on FOPs (?) @@ -510,4 +1375,3 @@ (dolist (m times) (format t "~30S: ~6,2F~%" (car m) (/ (float (cdr m)) 60.0)))))) |# - diff --git a/src/code/loop.lisp b/src/code/loop.lisp index 91669c4dfc..e1452da398 100644 --- a/src/code/loop.lisp +++ b/src/code/loop.lisp @@ -94,7 +94,8 @@ ((head-var tail-var &optional user-head-var) &body body) (let ((l (and user-head-var (list (list user-head-var nil))))) `(let* ((,head-var (list nil)) (,tail-var ,head-var) ,@l) - (declare (truly-dynamic-extent ,head-var)) + (declare (truly-dynamic-extent ,head-var) + ,@(and user-head-var `((list ,user-head-var)))) ,@body))) (sb-xc:defmacro loop-collect-rplacd @@ -140,13 +141,13 @@ (when user-head-var (setq answer `(progn ,answer - (setq ,user-head-var (cdr ,head-var))))) + (setq ,user-head-var (sb-ext:truly-the list (cdr ,head-var)))))) answer)))) (sb-xc:defmacro loop-collect-answer (head-var - &optional user-head-var) - (or user-head-var - `(cdr ,head-var))) + &optional user-head-var) + `(sb-ext:truly-the list ,(or user-head-var + `(cdr ,head-var)))) ;;;; maximization technology @@ -177,7 +178,7 @@ constructed. (declaim (sb-ext:freeze-type loop-minimax)) (defconstant-eqx +loop-minimax-type-infinities-alist+ - '((fixnum sb-xc:most-positive-fixnum sb-xc:most-negative-fixnum) + '((fixnum most-positive-fixnum most-negative-fixnum) (single-float sb-ext:single-float-positive-infinity sb-ext:single-float-negative-infinity) (double-float sb-ext:double-float-positive-infinity sb-ext:double-float-negative-infinity)) #'equal) @@ -185,7 +186,7 @@ constructed. (defun make-loop-minimax (answer-variable type) (let ((infinity-data (cdr (assoc type +loop-minimax-type-infinities-alist+ - :test #'sb-xc:subtypep)))) + :test #'subtypep)))) (make-loop-minimax-internal :answer-variable answer-variable :type type @@ -289,10 +290,10 @@ code to be loaded. (:constructor !make-loop-universe) (:copier nil) (:predicate nil)) - keywords ; hash table, value = (fn-name . extra-data) - iteration-keywords ; hash table, value = (fn-name . extra-data) - for-keywords ; hash table, value = (fn-name . extra-data) - path-keywords) ; hash table, value = (fn-name . extra-data) + (keywords nil :read-only t) ; hash table, value = (fn-name . extra-data) + (iteration-keywords nil :read-only t) ; hash table, value = (fn-name . extra-data) + (for-keywords nil :read-only t) ; hash table, value = (fn-name . extra-data) + (path-keywords nil :read-only t)) ; hash table, value = (fn-name . extra-data) (declaim (sb-ext:freeze-type loop-universe)) (defmethod print-object ((u loop-universe) stream) (print-unreadable-object (u stream :type t :identity t))) @@ -521,7 +522,7 @@ code to be loaded. ;;;; code analysis stuff (defun loop-constant-fold-if-possible (form &optional expected-type) - (let* ((constantp (sb-xc:constantp form)) + (let* ((constantp (constantp form)) (value (and constantp (constant-form-value form)))) (when (and constantp expected-type) (unless (sb-xc:typep value expected-type) @@ -576,7 +577,7 @@ code to be loaded. &optional (default-type required-type)) (if (null specified-type) default-type - (multiple-value-bind (a b) (sb-xc:subtypep specified-type required-type) + (multiple-value-bind (a b) (subtypep specified-type required-type) (cond ((not b) (loop-warn "LOOP couldn't verify that ~S is a subtype of the required type ~S." specified-type required-type)) @@ -769,6 +770,9 @@ code to be loaded. ""))) #+sb-unicode ((csubtypep ctype (specifier-type 'extended-char)) + #+sb-xc-host + (error "Unimplemented on cross-compiler.") + #-sb-xc-host (code-char base-char-code-limit)) ((csubtypep ctype (specifier-type 'character)) #\x) @@ -905,6 +909,12 @@ code to be loaded. (check-var-name name) (loop-declare-var name dtype :step-var-p step-var-p :initialization initialization) + ;; IGNORABLEize every variable because neither binding nor assignment constitutes + ;; a "use". Unfortunately there is no syntax for declaring what to ignore in LOOP. + ;; The idiom is to use NIL as a variable, but sometimes users don't, because they + ;; want variables names as information within a destructuring operation, + ;; e.g. (for (this . that-not-used) in stuff do (frob this)) + (push `(ignorable ,name) (declarations loop)) ;; We use ASSOC on this list to check for duplications (above), ;; so don't optimize out this list: (push (list name (or initialization (loop-typed-init dtype step-var-p))) @@ -958,7 +968,7 @@ code to be loaded. desetq &aux (loop *loop*)) (cond ((or (null name) (null dtype) (eq dtype t)) nil) ((symbolp name) - (unless (or (sb-xc:subtypep t dtype) + (unless (or (subtypep t dtype) (and (eq (sb-xc:symbol-package name) *cl-package*) (eq :special (info :variable :kind name)))) (let ((dtype `(type ,(if initialization @@ -1063,11 +1073,11 @@ code to be loaded. (defstruct (loop-collector (:copier nil) (:predicate nil)) - name - class + (name nil :read-only t) + (class nil :read-only t) (history nil) (tempvars nil) - specified-type + (specified-type nil :read-only t) dtype (data nil)) ;collector-specific data (declaim (sb-ext:freeze-type loop-collector)) @@ -1399,15 +1409,17 @@ code to be loaded. (loop-constant-fold-if-possible val) (let ((listvar var)) (cond ((and var (symbolp var)) - (loop-make-var var list data-type)) + (loop-make-var var + ;; Don't want to assert the type, as ENDP will do that + `(the* (list :use-annotations t :source-form ,list) ,list) + data-type)) (t (loop-make-var (setq listvar (gensym)) list 't) (loop-make-var var nil data-type))) (let ((list-step (loop-list-step listvar))) (let* ((first-endtest - ;; mysterious comment from original CMU CL sources: - ;; the following should use `atom' instead of `endp', - ;; per [bug2428] + ;; the following should use `atom' instead of `endp', + ;; per 6.1.2.1.3 `(atom ,listvar)) (other-endtest first-endtest)) (when (and constantp (listp list-value)) @@ -1428,7 +1440,10 @@ code to be loaded. (loop-constant-fold-if-possible val) (let ((listvar (gensym "LOOP-LIST-"))) (loop-make-var var nil data-type) - (loop-make-var listvar list t) + (loop-make-var listvar + ;; Don't want to assert the type, as ENDP will do that + `(the* (list :use-annotations t :source-form ,list) ,list) + t) (let ((list-step (loop-list-step listvar))) (let* ((first-endtest `(endp ,listvar)) (other-endtest first-endtest) diff --git a/src/code/macroexpand.lisp b/src/code/macroexpand.lisp index 228cfc5b45..2f9f696047 100644 --- a/src/code/macroexpand.lisp +++ b/src/code/macroexpand.lisp @@ -13,12 +13,12 @@ ;;;; syntactic environment access -(defun sb-xc:special-operator-p (symbol) +(defun special-operator-p (symbol) "If the symbol globally names a special form, return T, otherwise NIL." (declare (symbol symbol)) (eq (info :function :kind symbol) :special-form)) -(defvar sb-xc:*macroexpand-hook* 'funcall +(defvar *macroexpand-hook* 'funcall "The value of this variable must be a designator for a function that can take three arguments, a macro expander function, the macro form to be expanded, and the lexical environment to expand in. The function should @@ -59,7 +59,7 @@ :datum hook :expected-type 'compiled-function)))) -(defun sb-xc:macroexpand-1 (form &optional env) +(defun macroexpand-1 (form &optional env) "If form is a macro (or symbol macro), expand it once. Return two values, the expanded form and a T-or-NIL flag indicating whether the form was, in fact, a macro. ENV is the lexical environment to expand in, which defaults @@ -105,19 +105,19 @@ (values form nil)))) ((and (listp form) (let ((fn (car form))) - (and (symbolp fn) (sb-xc:macro-function fn env)))) + (and (symbolp fn) (macro-function fn env)))) (perform-expansion it)) (t (values form nil))))) -(defun sb-xc:macroexpand (form &optional env) +(defun macroexpand (form &optional env) "Repetitively call MACROEXPAND-1 until the form can no longer be expanded. Returns the final resultant form, and T if it was expanded. ENV is the lexical environment to expand in, or NIL (the default) for the null environment." (labels ((frob (form expanded) (multiple-value-bind (new-form newly-expanded-p) - (sb-xc:macroexpand-1 form env) + (macroexpand-1 form env) (if newly-expanded-p (frob new-form t) (values new-form expanded))))) @@ -127,8 +127,8 @@ (defun %macroexpand-1 (form &optional env) (if (or (atom form) (let ((op (car form))) - (not (and (symbolp op) (sb-xc:special-operator-p op))))) - (sb-xc:macroexpand-1 form env) + (not (and (symbolp op) (special-operator-p op))))) + (macroexpand-1 form env) (values form nil))) ;;; Like MACROEXPAND, but takes care not to expand special forms. @@ -140,3 +140,43 @@ (frob new-form t) (values new-form expanded))))) (frob form nil))) + +(defun compiler-macro-function (name &optional env) + "If NAME names a compiler-macro in ENV, return the expansion function, else +return NIL. Can be set with SETF when ENV is NIL." + (legal-fun-name-or-type-error name) + ;; CLHS 3.2.2.1: Creating a lexical binding for the function name + ;; not only creates a new local function or macro definition, but + ;; also shadows[2] the compiler macro. + (unless (sb-c::fun-locally-defined-p name env) + ;; Note: CMU CL used to return NIL here when a NOTINLINE + ;; declaration was in force. That's fairly logical, given the + ;; specified effect of NOTINLINE declarations on compiler-macro + ;; expansion. However, (1) it doesn't seem to be consistent with + ;; the ANSI spec for COMPILER-MACRO-FUNCTION, and (2) it would + ;; give surprising behavior for (SETF (COMPILER-MACRO-FUNCTION + ;; FOO) ...) in the presence of a (PROCLAIM '(NOTINLINE FOO)). So + ;; we don't do it. + (values (info :function :compiler-macro-function name)))) + +(defvar *setf-compiler-macro-function-hook* nil + "A list of functions that (SETF COMPILER-MACRO-FUNCTION) invokes before + storing the new value. The functions take the function name and the new + value.") + +;;; FIXME: we don't generate redefinition warnings for these. +(defun (setf compiler-macro-function) (function name &optional env) + (declare (type (or symbol list) name) + (type (or function null) function)) + (when env + ;; ANSI says this operation is undefined. + (error "can't SETF COMPILER-MACRO-FUNCTION when ENV is non-NIL")) + (when (eq (info :function :kind name) :special-form) + (error "~S names a special form." name)) + (when (boundp '*setf-compiler-macro-function-hook*) ; unbound during cold init + (dolist (f *setf-compiler-macro-function-hook*) + (funcall f name function))) + (with-single-package-locked-error + (:symbol name "setting the compiler-macro-function of ~A") + (setf (info :function :compiler-macro-function name) function) + function)) diff --git a/src/code/macros.lisp b/src/code/macros.lisp index 7d0b742bb5..3bd5768b6a 100644 --- a/src/code/macros.lisp +++ b/src/code/macros.lisp @@ -10,6 +10,40 @@ ;;;; files for more information. (in-package "SB-IMPL") + + +;;;; DEFMACRO + +;;; Inform the cross-compiler how to expand SB-XC:DEFMACRO (= DEFMACRO) +;;; and supporting macros using the already defined host macros until +;;; this file is itself cross-compiled. +#+sb-xc-host +(flet ((defmacro-using-host-expander (name) + (setf (macro-function name) + (lambda (form env) + (declare (ignore env)) + ;; Since SB-KERNEL:LEXENV isn't compatible with the host, + ;; just pass NIL. The expansion correctly captures a non-null + ;; environment, but the expander doesn't need it. + (funcall (cl:macro-function name) form nil))))) + (defmacro-using-host-expander 'sb-xc:defmacro) + (defmacro-using-host-expander 'named-ds-bind) + (defmacro-using-host-expander 'binding*) + (defmacro-using-host-expander 'sb-xc:deftype) + ;; FIXME: POLICY doesn't support DEFMACRO, but we need it ASAP. + (defmacro-using-host-expander 'sb-c:policy)) + + +;;;; Destructuring-bind + +(sb-xc:defmacro destructuring-bind (lambda-list expression &body body + &environment env) + (declare (ignore env)) ; could be policy-sensitive (but isn't) + "Bind the variables in LAMBDA-LIST to the corresponding values in the +tree structure resulting from the evaluation of EXPRESSION." + `(binding* ,(sb-c::expand-ds-bind lambda-list expression t nil) + ,@body)) + ;;;; DEFUN @@ -79,7 +113,7 @@ entry-points (not (member name entry-points :test #'equal)))))) -(flet ((defun-expander (env name lambda-list body snippet) +(flet ((defun-expander (env name lambda-list body snippet &optional source-form) (multiple-value-bind (forms decls doc) (parse-body body t) ;; Maybe kill docstring, but only under the cross-compiler. #+(and (not sb-doc) sb-xc-host) (setq doc nil) @@ -87,7 +121,6 @@ (lambda-guts `(,@decls (block ,(fun-name-block-name name) ,@forms))) (lambda `(lambda ,lambda-list ,@lambda-guts)) (named-lambda `(named-lambda ,name ,lambda-list - ,@(when *top-level-form-p* '((declare (sb-c::top-level-form)))) ,@(when doc (list doc)) ,@lambda-guts)) ;; DXABLE-ARGS and SNIPPET are mutually exclusive, so we can sleazily pass ;; whichever exists (if either does) as one parameter to %DEFUN. @@ -98,7 +131,7 @@ ;; a full inline expansion depending on the lexical environment. ((save-inline-expansion-p name) ;; we want to attempt to inline, so complain if we can't - (cond ((sb-c:maybe-inline-syntactic-closure lambda env)) + (cond ((sb-c:inline-syntactic-closure-lambda lambda env)) (t (#+sb-xc-host warn #-sb-xc-host sb-c:maybe-compiler-notify @@ -113,46 +146,47 @@ (setq inline-thing (list 'quote inline-thing))) (when (and extra-info (not (keywordp extra-info))) (setq extra-info (list 'quote extra-info))) - `(progn - (eval-when (:compile-toplevel) - (sb-c:%compiler-defun ',name t ,inline-thing ,extra-info)) - ,(if (block-compilation-non-entry-point name) - `(progn - ;; Tell the compiler to convert the lambda without - ;; referencing it, so no stray reference stays around - ;; and find-initial-dfo works correctly. - (sb-c::%fun-name-leaf ,named-lambda) - ',name) - `(%defun ',name ,named-lambda - ,@(when (or inline-thing extra-info) `(,inline-thing)) - ,@(when extra-info `(,extra-info)))) - ;; This warning, if produced, comes after the DEFUN happens. - ;; When compiling, there's no real difference, but when interpreting, - ;; if there is a handler for style-warning that nonlocally exits, - ;; it's wrong to have skipped the DEFUN itself, since if there is no - ;; function, then the warning ought not to have been issued at all. - ,@(when (typep name '(cons (eql setf))) - `((eval-when (:compile-toplevel :execute) - (sb-c::warn-if-setf-macro ',name)) - ',name))))))) + (let ((definition + (if (block-compilation-non-entry-point name) + `(progn + (sb-c::%refless-defun ,named-lambda) + ',name) + `(%defun ',name ,named-lambda + ,@(when (or inline-thing extra-info) `(,inline-thing)) + ,@(when extra-info `(,extra-info)))))) + `(progn + (eval-when (:compile-toplevel) + (sb-c:%compiler-defun ',name t ,inline-thing ,extra-info)) + ,(if source-form + `(sb-c::with-source-form ,source-form ,definition) + definition) + ;; This warning, if produced, comes after the DEFUN happens. + ;; When compiling, there's no real difference, but when interpreting, + ;; if there is a handler for style-warning that nonlocally exits, + ;; it's wrong to have skipped the DEFUN itself, since if there is no + ;; function, then the warning ought not to have been issued at all. + ,@(when (typep name '(cons (eql setf))) + `((eval-when (:compile-toplevel :execute) + (sb-c::warn-if-setf-macro ',name)) + ',name)))))))) ;;; This is one of the major places where the semantics of block -;;; compilation is handled. Substitution for global names is totally -;;; inhibited if (block-compile *compilation*) is NIL. And if +;;; compilation is handled. Substitution for global names is totally +;;; inhibited if (block-compile *compilation*) is NIL. And if ;;; (block-compile *compilation*) is true and entry points are ;;; specified, then we don't install global definitions for non-entry ;;; functions (effectively turning them into local lexical functions.) (sb-xc:defmacro defun (&environment env name lambda-list &body body) "Define a function at top level." - (check-designator name defun) + (check-designator name 'defun #'legal-fun-name-p "function name") #+sb-xc-host (unless (cl:symbol-package (fun-name-block-name name)) (warn "DEFUN of uninterned function name ~S (tricky for GENESIS)" name)) (defun-expander env name lambda-list body nil)) ;; extended defun as used by defstruct - (sb-xc:defmacro sb-c:xdefun (&environment env name snippet lambda-list &body body) - (defun-expander env name lambda-list body snippet))) + (sb-xc:defmacro sb-c:xdefun (&environment env name snippet source-form lambda-list &body body) + (defun-expander env name lambda-list body snippet source-form))) ;;;; DEFCONSTANT, DEFVAR and DEFPARAMETER @@ -161,17 +195,16 @@ compiled into code. If the variable already has a value, and this is not EQL to the new value, the code is not portable (undefined behavior). The third argument is an optional documentation string for the variable." - (check-designator name defconstant) + (check-designator name 'defconstant) `(eval-when (:compile-toplevel :load-toplevel :execute) - (sb-c::%defconstant ',name ,value (sb-c:source-location) - ,@(and docp `(',doc))))) + (%defconstant ',name ,value (sb-c:source-location) + ,@(and docp `(',doc))))) (declaim (ftype (sfunction (symbol t &optional t t) null) about-to-modify-symbol-value)) ;;; the guts of DEFCONSTANT - -(defun sb-c::%defconstant (name value source-location &optional (doc nil docp)) +(defun %defconstant (name value source-location &optional (doc nil docp)) #+sb-xc-host (declare (ignore doc docp)) (unless (symbolp name) (error "The constant name is not a symbol: ~S" name)) @@ -199,7 +232,16 @@ ;; Non-continuable error. (about-to-modify-symbol-value name 'defconstant) (let ((old (symbol-value name))) - (unless (eql value old) + (unless (or (eql value old) + ;; SAPs behave like numbers but yet EQL doesn't work on them, + ;; special case it. + ;; Nobody will notices that the constant + ;; is not EQ, since it can be copied at + ;; any time anyway. + #-sb-xc-host + (and (system-area-pointer-p old) + (system-area-pointer-p value) + (sap= old value))) (multiple-value-bind (ignore aborted) (with-simple-restart (abort "Keep the old value.") (cerror "Go ahead and change the value." @@ -209,13 +251,16 @@ :new-value value)) (declare (ignore ignore)) (when aborted - (return-from sb-c::%defconstant name)))))) + (return-from %defconstant name)))))) (warn "redefining a MAKUNBOUND constant: ~S" name))) (:unknown ;; (This is OK -- undefined variables are of this kind. So we ;; don't warn or error or anything, just fall through.) ) (t (warn "redefining ~(~A~) ~S to be a constant" kind name))))) + (dolist (backpatch (info :variable :forward-references name)) + (funcall backpatch value)) + (clear-info :variable :forward-references name) ;; We ought to be consistent in treating any change of :VARIABLE :KIND ;; as a continuable error. The above CASE expression pre-dates the ;; existence of symbol-macros (I believe), but at a bare minimum, @@ -228,6 +273,11 @@ (when docp (setf (documentation name 'variable) doc)) (%set-symbol-value name value)) + ;; Define the constant in the cross-compilation host, since the + ;; value is used when cross-compiling for :COMPILE-TOPLEVEL contexts + ;; which reference the constant. + #+sb-xc-host + (eval `(defconstant ,name ',value)) (setf (info :variable :kind name) :constant) name) @@ -236,7 +286,7 @@ SPECIAL and, optionally, initialize it. If the variable already has a value, the old value is not clobbered. The third argument is an optional documentation string for the variable." - (check-designator var defvar) + (check-designator var 'defvar) ;; Maybe kill docstring, but only under the cross-compiler. #+(and (not sb-doc) sb-xc-host) (setq doc nil) `(progn @@ -260,7 +310,7 @@ variable special and sets its value to VAL, overwriting any previous value. The third argument is an optional documentation string for the parameter." - (check-designator var defparameter) + (check-designator var 'defparameter) ;; Maybe kill docstring, but only under the cross-compiler. #+(and (not sb-doc) sb-xc-host) (setq doc nil) `(progn @@ -270,8 +320,53 @@ ,@(and docp `(',doc))))) +(defun %compiler-defvar (var) + (proclaim `(special ,var))) + + +;;;; DEFGLOBAL and DEFINE-LOAD-TIME-GLOBAL + +(sb-xc:defmacro defglobal (name value &optional (doc nil docp)) + "Defines NAME as a global variable that is always bound. VALUE is evaluated +and assigned to NAME both at compile- and load-time, but only if NAME is not +already bound. + +Global variables share their values between all threads, and cannot be +locally bound, declared special, defined as constants, and neither bound +nor defined as symbol macros. + +See also the declarations SB-EXT:GLOBAL and SB-EXT:ALWAYS-BOUND." + (check-designator name 'defglobal) + (let ((boundp (make-symbol "BOUNDP"))) + `(progn + (eval-when (:compile-toplevel) + (let ((,boundp (boundp ',name))) + (%compiler-defglobal ',name :always-bound + (not ,boundp) (unless ,boundp ,value)))) + (%defglobal ',name + (if (%boundp ',name) (make-unbound-marker) ,value) + (sb-c:source-location) + ,@(and docp `(',doc)))))) + +(sb-xc:defmacro define-load-time-global (name value &optional (doc nil docp)) + "Defines NAME as a global variable that is always bound. VALUE is evaluated +and assigned to NAME at load-time, but only if NAME is not already bound. + +Attempts to read NAME at compile-time will signal an UNBOUND-VARIABLE error +unless it has otherwise been assigned a value. + +See also DEFGLOBAL which assigns the VALUE at compile-time too." + (check-designator name 'define-load-time-global) + `(progn + (eval-when (:compile-toplevel) + (%compiler-defglobal ',name :eventually nil nil)) + (%defglobal ',name + (if (%boundp ',name) (make-unbound-marker) ,value) + (sb-c:source-location) + ,@(and docp `(',doc))))) + (defun %compiler-defglobal (name always-boundp assign-it-p value) - (sb-xc:proclaim `(global ,name)) + (proclaim `(global ,name)) (when assign-it-p (set-symbol-global-value name value)) (sb-c::process-variable-declaration @@ -281,9 +376,6 @@ :always-bound always-boundp))) -(defun %compiler-defvar (var) - (sb-xc:proclaim `(special ,var))) - ;;;; various conditional constructs (flet ((prognify (forms env) @@ -410,7 +502,7 @@ evaluated as a PROGN." ;; Certainly for the evaluator it's preferable. `(let ((,(car vars) ,value-form)) ,@body) - (let ((ignore (sb-xc:gensym))) + (let ((ignore (gensym))) `(multiple-value-call #'(lambda (&optional ,@(mapcar #'list vars) &rest ,ignore) (declare (ignore ,ignore)) @@ -440,12 +532,12 @@ evaluated as a PROGN." ;; form will take longer than can be described as adequate, as the ;; optional dispatch mechanism for the M-V-B gets increasingly ;; hairy. - (let ((val (and (sb-xc:constantp n env) (constant-form-value n env)))) + (let ((val (and (constantp n env) (constant-form-value n env)))) (if (and (integerp val) (<= 0 val (or #+(or x86-64 arm64 riscv) ;; better DEFAULT-UNKNOWN-VALUES 1000 10))) ; Arbitrary limit. (let ((dummy-list (make-gensym-list val)) - (keeper (sb-xc:gensym "KEEPER"))) + (keeper (gensym "KEEPER"))) `(multiple-value-bind (,@dummy-list ,keeper) ,form (declare (ignore ,@dummy-list)) ,keeper)) @@ -491,13 +583,13 @@ evaluated as a PROGN." (let* ((func (if (listp test-form) (car test-form))) (new-test (if (and (typep func '(and symbol (not null))) - (not (sb-xc:macro-function func env)) - (not (sb-xc:special-operator-p func)) + (not (macro-function func env)) + (not (special-operator-p func)) (proper-list-p (cdr test-form))) ;; TEST-FORM is a function call. We do not attempt this ;; if TEST-FORM is a macro invocation or special form. `(,func ,@(mapcar (lambda (place) - (if (sb-xc:constantp place env) + (if (constantp place env) place (with-unique-names (temp) (bindings `(,temp ,place)) @@ -567,7 +659,11 @@ invoked. In that case it will store into PLACE and start over." ;; variable to work around Python's blind spot in type derivation. ;; For more complex places getting the type derived should not ;; matter so much anyhow. - (let ((expanded (%macroexpand place env))) + (let ((expanded (%macroexpand place env)) + (type (let ((ctype (sb-c::careful-specifier-type type))) + (if ctype + (type-specifier ctype) + type)))) (if (symbolp expanded) `(do () ((typep ,place ',type)) @@ -616,7 +712,8 @@ invoked. In that case it will store into PLACE and start over." (sb-xc:defmacro define-compiler-macro (name lambda-list &body body) "Define a compiler-macro for NAME." - (check-designator name define-compiler-macro) + (check-designator name 'define-compiler-macro + #'legal-fun-name-p "function name") (when (and (symbolp name) (special-operator-p name)) (%program-error "cannot define a compiler-macro for a special operator: ~S" name)) @@ -625,18 +722,20 @@ invoked. In that case it will store into PLACE and start over." (let ((def (make-macro-lambda (sb-c::debug-name 'compiler-macro name) lambda-list body 'define-compiler-macro name :accessor 'sb-c::compiler-macro-args))) + ;; FIXME: Shouldn't compiler macros also get source locations? + ;; Plain DEFMACRO supplies source location information. `(progn - (eval-when (:compile-toplevel) - (sb-c::%compiler-defmacro :compiler-macro-function ',name)) - (eval-when (:compile-toplevel :load-toplevel :execute) - (sb-c::%define-compiler-macro ',name ,def))))) + (eval-when (:compile-toplevel) + (sb-c::%compiler-defmacro :compiler-macro-function ',name)) + (eval-when (:compile-toplevel :load-toplevel :execute) + (sb-c::%define-compiler-macro ',name ,def))))) (eval-when (#-sb-xc :compile-toplevel :load-toplevel :execute) (defun sb-c::%define-compiler-macro (name definition) (sb-c::warn-if-compiler-macro-dependency-problem name) ;; FIXME: warn about incompatible lambda list with ;; respect to parent function? - (setf (sb-xc:compiler-macro-function name) definition) + (setf (compiler-macro-function name) definition) name)) ;;;; CASE, TYPECASE, and friends @@ -824,8 +923,8 @@ symbol-case giving up: case=((V U) (F)) (flet ((try-one-byte () (let ((best-answer nil) ;; "best" means smallest - (best-max-bin-count sb-xc:most-positive-fixnum) ; sentinel value - (best-average sb-xc:most-positive-fixnum)) + (best-max-bin-count most-positive-fixnum) ; sentinel value + (best-average most-positive-fixnum)) (loop named try for nbits from smallest-nbits to largest-nbits do (let ((bin-counts (make-array (ash 1 nbits) :initial-element 0))) @@ -834,8 +933,8 @@ symbol-case giving up: case=((V U) (F)) finally (return-from try (values best-max-bin-count best-answer))))) (try-two-bytes () (let ((best-answer nil) - (best-max-bin-count sb-xc:most-positive-fixnum) - (best-average sb-xc:most-positive-fixnum)) + (best-max-bin-count most-positive-fixnum) + (best-average most-positive-fixnum)) (loop named try for nbits from smallest-nbits to largest-nbits do (let ((bin-counts (make-array (ash 1 nbits) :initial-element 0))) @@ -854,68 +953,57 @@ symbol-case giving up: case=((V U) (F)) (values score1 answer1) ; not improved (values score2 answer2))))))))) ; 2 bytes = better -;;; TODO: see if it's possible to not use SXHASH on layouts here. -;;; (etypecase x -;;; ((or named-type numeric-type member-type classoid ..) something) -;;; -> (SB-IMPL::%SEALED-STRUCT-TYPECASE-INDEX -;;; ((named-type numeric-type member-type classoid ...)CHARACTER-SET-TYPE -;;; -> (LET* ((ARRAY -;;; #(4048 NIL NIL NIL NIL NIL -;;; ((#<LAYOUT for ALIEN-TYPE-TYPE {50202A03}> . 1)) NIL -;;; ((#<LAYOUT for NAMED-TYPE {50202503}> . 1)) NIL NIL -;;; (defun build-sealed-struct-typecase-map (type-unions) (let* ((layout-lists (mapcar (lambda (x) (mapcar #'find-layout x)) type-unions)) (byte (nth-value 1 (pick-best-sxhash-bits (apply #'append layout-lists) - #'layout-clos-hash 1))) - (bin-count (ash 1 (byte-size byte))) - (array (make-array (1+ bin-count) :initial-element nil)) - (mask (1- bin-count)) + #'wrapper-clos-hash 1))) + (array (make-array (ash 1 (byte-size byte)) :initial-element nil)) + (perfectp t) (seen)) - (setf (aref array 0) (logior (ash mask 6) (byte-position byte))) (loop for layout-list in layout-lists - for i from 1 + for selector from 1 do (dolist (layout layout-list) (unless (member layout seen) ; in case of dups / overlaps (push layout seen) - (let ((bin (1+ (logand (ash (layout-clos-hash layout) - (- (the (mod #.sb-vm:n-word-bits) - (byte-position byte)))) - (the (and fixnum unsigned-byte) mask))))) + (let ((bin (ldb byte (wrapper-clos-hash layout)))) + (when (aref array bin) + (setq perfectp nil)) (setf (aref array bin) - (nconc (aref array bin) (list (cons layout i)))))))) - array)) - -;;; FIXME: now that structure classoid hashes are computable at compile-time, -;;; we can do ever better in this expander: if the hash is perfect, -;;; then do not iterate over candidates, just flatten the array into -;;; #(<LAYOUT> case-index #<LAYOUT> case-index ...) -;;; then test for a hit on the indexed layout, get the case-index, and jump. + (nconc (aref array bin) (list (cons layout selector)))))))) + (values `(byte ,(byte-size byte) ,(byte-position byte)) + perfectp + (if perfectp + ;; at most one element is in each bin + (let ((result (make-array (* (length array) 2) :initial-element 0))) + (dotimes (index (length array) result) + (awhen (aref array index) + (setf (aref result index) (caar it) + (aref result (+ index (length array))) (cdar it))))) + array)))) + (sb-xc:defmacro %sealed-struct-typecase-index (cases object) - `(if (%instancep ,object) - (locally (declare (optimize (safety 0))) - ;; When the second argument to LOAD-TIME-VALUE is T in COMPILE (but not COMPILE-FILE) - ;; then element 0 of the vector is used as a compile-time constant and we'll wire in - ;; the shift and mask which produces an even better instruction sequence. - ;; This is pretty awesome and I did not know that we would do that. - (let* ((array ,(build-sealed-struct-typecase-map cases)) - (layout (%instance-layout ,object)) - (hash-spec (the fixnum (svref array 0))) - (shift (ldb (byte ,(integer-length (1- sb-vm:n-word-bits)) 0) - hash-spec))) + (binding* (((byte perfectp cells) (build-sealed-struct-typecase-map cases)) + (n-pairs (/ (length cells) 2))) + `(if (not (%instancep ,object)) + 0 + (let* ((layout (%instance-layout ,object)) + (index (ldb ,byte (layout-clos-hash layout))) + ;; Compare by WRAPPER, not LAYOUT. LAYOUTs can't go in a simple-vector. + (wrapper (layout-friend layout)) + (cells ,cells)) + (declare (optimize (safety 0))) (the (mod ,(1+ (length cases))) - ;; DOLIST performs a leading test, but we're OK with a cell - ;; that is NIL. It'll miss and then exit at the end of the loop. - ;; This potentially avoids one comparison vs NIL if we hit immediately. - (let ((list (svref array - (1+ (logand (ash (layout-clos-hash layout) (- shift)) - (ash hash-spec -6)))))) - (loop (let ((cell (car list))) - (cond ((eq layout (car cell)) (return (cdr cell))) - ((null (setq list (cdr list))) (return 0))))))))) - 0)) + ,(if perfectp + `(if (eq (aref cells index) wrapper) (aref cells (+ index ,n-pairs)) 0) + ;; DOLIST performs a leading test, but we're OK with a cell + ;; that is NIL. It'll miss and then exit at the end of the loop. + ;; This potentially avoids one comparison vs NIL if we hit immediately. + `(let ((list (svref cells index))) + (loop (let ((cell (car list))) + (cond ((eq wrapper (car cell)) (return (cdr cell))) + ((null (setq list (cdr list))) (return 0)))))))))))) ;;; Given an arbitrary TYPECASE, see if it is a discriminator over ;;; an assortment of structure-object subtypes. If it is, potentially turn it @@ -935,12 +1023,18 @@ symbol-case giving up: case=((V U) (F)) ;;; for a match on both the hash and the layout. (defun expand-struct-typecase (keyform temp normal-clauses type-specs default errorp &aux (n-root-types 0) (exhaustive-list)) - (flet ((discover-subtypes (specifier) + (labels + ((ok-classoid (classoid) + (or (structure-classoid-p classoid) + (and (sb-kernel::built-in-classoid-p classoid) + (not (memq (classoid-name classoid) + sb-kernel::**non-instance-classoid-types**))))) + (discover-subtypes (specifier) (let* ((parse (specifier-type specifier)) (worklist - (cond ((structure-classoid-p parse) (list parse)) + (cond ((ok-classoid parse) (list parse)) ((and (union-type-p parse) - (every #'structure-classoid-p (union-type-types parse))) + (every #'ok-classoid (union-type-types parse))) (copy-list (union-type-types parse))) (t (return-from discover-subtypes nil))))) @@ -953,12 +1047,11 @@ symbol-case giving up: case=((V U) (F)) (loop (unless worklist (return)) (let ((classoid (pop worklist))) (visited classoid) - (awhen (classoid-subclasses classoid) - (dohash ((classoid layout) it) - (declare (ignore layout)) - (unless (or (member classoid (visited)) - (member classoid worklist)) - (setf worklist (nconc worklist (list classoid)))))))) + (sb-kernel::do-subclassoids ((subclassoid wrapper) classoid) + (declare (ignore wrapper)) + (unless (or (member subclassoid (visited)) + (member subclassoid worklist)) + (setf worklist (nconc worklist (list subclassoid))))))) (setf exhaustive-list (union (visited) exhaustive-list)) (visited))))) (let ((classoid-lists (mapcar #'discover-subtypes type-specs))) @@ -1058,9 +1151,9 @@ symbol-case giving up: case=((V U) (F)) (clause->bins (make-array (length clauses) :initial-element nil)) (table-nbits (byte-size (if (vectorp byte) (elt byte 0) byte))) (bins (make-array (ash 1 table-nbits) :initial-element 0)) - (symbol (sb-xc:gensym "S")) - (hash (sb-xc:gensym "H")) - (vector (sb-xc:gensym "V")) + (symbol (gensym "S")) + (hash (gensym "H")) + (vector (gensym "V")) (is-hashable ;; For x86-64, any non-immediate object is considered hashable, ;; so we only do a lowtag test on the object, though the correct hash @@ -1111,7 +1204,7 @@ symbol-case giving up: case=((V U) (F)) ;; every consequent is trivial. (when (= maxprobes 1) (block try-table-lookup - (let ((values (make-array (length bins))) + (let ((values (make-array (length bins) :initial-element 0)) (single-value) ; only if exactly one clause (types nil)) (dolist (clause clauses) @@ -1262,7 +1355,7 @@ symbol-case giving up: case=((V U) (F)) ;; Produce a COND only if the backend supports the multiway branch vop. #+(or x86 x86-64) - (let ((block (sb-xc:gensym "B")) + (let ((block (gensym "B")) (unused-bins)) ;; Take note of the unused bins (dotimes (i (length bins)) @@ -1413,23 +1506,18 @@ symbol-case giving up: case=((V U) (F)) errorp proceedp expected-type) (when proceedp ; CCASE or CTYPECASE (return-from case-body-aux - (let ((block (gensym)) - (again (gensym))) - `(let ((,keyform-value ,keyform)) - (block ,block - (tagbody - ,again - (return-from - ,block - (cond ,@(nreverse clauses) - (t - (setf ,keyform-value - (setf ,keyform - (case-body-error - ',name ',keyform ,keyform-value - ',expected-type ',keys))) - (go ,again)))))))))) - + ;; It is not a requirement to evaluate subforms of KEYFORM once only, but it often + ;; reduces code size to do so, as the update form will take advantage of typechecks + ;; already performed. (Nor is it _required_ to re-evaluate subforms) + (binding* ((switch (make-symbol "SWITCH")) + (retry + ;; TODO: consider using the union type simplifier algorithm here + `(case-body-error ',name ',keyform ,keyform-value ',expected-type ',keys)) + ((vars vals stores writer reader) (get-setf-expansion keyform))) + `(let* ,(mapcar #'list vars vals) + (named-let ,switch ((,keyform-value ,reader)) + (cond ,@(nreverse clauses) + (t (multiple-value-bind ,stores ,retry (,switch ,writer))))))))) (let ((implement-as name) (original-keys keys)) (when (member name '(typecase etypecase)) @@ -1467,9 +1555,9 @@ symbol-case giving up: case=((V U) (F)) (setq clauses (if default (cons default new-clauses) new-clauses) keys (new-keys) implement-as 'case)) - #+(vop-named sb-c:multiway-branch-if-eq) - ((expand-struct-typecase keyform keyform-value normal-clauses keys - default errorp) + ((and (sb-c::vop-existsp :named sb-c:multiway-branch-if-eq) + (expand-struct-typecase keyform keyform-value normal-clauses keys + default errorp)) (return-from case-body-aux it)))))) ;; Efficiently expanding CASE over symbols depends on CASE over integers being @@ -1485,10 +1573,33 @@ symbol-case giving up: case=((V U) (F)) (declare (ignorable ,keyform-value)) ; e.g. (CASE KEY (T)) (cond ,@(nreverse clauses) ,@(when errorp - `((t (,(ecase name - (etypecase 'etypecase-failure) - (ecase 'ecase-failure)) - ,keyform-value ',original-keys)))))))) + `((t ,(ecase name + (etypecase + `(etypecase-failure + ,keyform-value ,(etypecase-error-spec original-keys))) + (ecase + `(ecase-failure ,keyform-value ',original-keys)))))))))) + +;;; ETYPECASE over clauses that form a "simpler" type specifier should use that, +;;; e.g. partitions of INTEGER: +;;; (etypecase ((integer * -1) ...) ((eql 0) ...) ((integer 1 *) ...)) +;;; (etypecase (fixnum ...) (bignum ...)) +(defun etypecase-error-spec (types) + (when (cdr types) ; no sense in doing this for a single type + (let ((parsed (mapcar #'sb-c::careful-specifier-type types))) + (when (every (lambda (x) (and x (not (contains-unknown-type-p x)))) + parsed) + (let* ((union (apply #'type-union parsed)) + (unparsed (type-specifier union))) + ;; If the type-union of the types is a simpler expression than (OR ...), + ;; then return the simpler one. CTYPECASE could do this also, but doesn't. + ;; http://www.lispworks.com/documentation/HyperSpec/Body/m_tpcase.htm#etypecase + ;; "If no normal-clause matches, a non-correctable error of type type-error + ;; is signaled. The offending datum is the test-key and the expected type + ;; is /type equivalent/ to (or type1 type2 ...)" + (when (symbolp unparsed) + (return-from etypecase-error-spec `',unparsed)))))) + `',types) (sb-xc:defmacro case (keyform &body cases) "CASE Keyform {({(Key*) | Key} Form*)}* @@ -1532,7 +1643,7 @@ symbol-case giving up: case=((V U) (F)) ;;; only for strings, hence the name. Renaming it to something more ;;; generic might not be a bad idea. (sb-xc:defmacro string-dispatch ((&rest types) var &body body) - (let ((fun (sb-xc:gensym "STRING-DISPATCH-FUN"))) + (let ((fun (gensym "STRING-DISPATCH-FUN"))) `(flet ((,fun (,var) ,@body)) (declare (inline ,fun)) @@ -1565,41 +1676,6 @@ symbol-case giving up: case=((V U) (F)) (setq ,abortp nil)) (when ,stream (close ,stream :abort ,abortp))))))) - -(sb-xc:defmacro with-output-to-string - ((var &optional string &key (element-type ''character)) - &body forms-decls) - (multiple-value-bind (forms decls) (parse-body forms-decls nil) - (if string - (let ((element-type-var (gensym))) - `(let ((,var (make-fill-pointer-output-stream ,string)) - ;; ELEMENT-TYPE isn't currently used for anything - ;; (see FILL-POINTER-OUTPUT-STREAM FIXME in stream.lisp), - ;; but it still has to be evaluated for side-effects. - (,element-type-var ,element-type)) - (declare (ignore ,element-type-var)) - ,@decls - (unwind-protect - (progn ,@forms) - (close ,var)))) - ;; I don't see why we need the unwind-protect. - ;; CLHS says: "The output string stream to which the variable /var/ - ;; is bound has dynamic extent; its extent ends when the form is exited." - ;; So technically you can't reference the stream after the string - ;; is returned. And since the implication is that we can legally DXify - ;; the stream, what difference does it make whether it's open or closed? - ;; Certainly in code that is compiled in SAFETY < 3 we should - ;; just not bother with the unwind-protect or the close. - `(let ((,var (make-string-output-stream - ;; CHARACTER is the default element-type of - ;; string-ouput-stream, save a few bytes when passing it - ,@(and (not (equal element-type ''character)) - `(:element-type ,element-type))))) - ,@decls - (unwind-protect - (progn ,@forms) - (close ,var)) - (get-output-stream-string ,var))))) ;;;; Iteration macros: @@ -1621,7 +1697,7 @@ symbol-case giving up: case=((V U) (F)) (with-current-source-form (varlist) (mapcar (lambda (var) (with-current-source-form (var) - (or (cond ((symbolp var) var) + (or (cond ((symbolp var) (list var)) ((listp var) (unless (symbolp (first var)) (error "~S step variable is not a symbol: ~S" @@ -1634,10 +1710,11 @@ symbol-case giving up: case=((V U) (F)) var name)))) varlist)))) (multiple-value-bind (code decls) (parse-body decls-and-code nil) - (let ((label-1 (sb-xc:gensym)) (label-2 (sb-xc:gensym))) + (let ((label-1 (gensym)) (label-2 (gensym))) `(block ,block (,bind ,inits ,@decls + (declare (ignorable ,@(mapcar #'car inits))) (tagbody (go ,label-2) ,label-1 @@ -1649,7 +1726,7 @@ symbol-case giving up: case=((V U) (F)) ;; This is like DO, except it has no implicit NIL block. (sb-xc:defmacro do-anonymous (varlist endlist &rest body) - (frob-do-body varlist endlist body 'let 'psetq 'do-anonymous (sb-xc:gensym))) + (frob-do-body varlist endlist body 'let 'psetq 'do-anonymous (gensym))) (sb-xc:defmacro do (varlist endlist &body body) "DO ({(Var [Init] [Step])}*) (Test Exit-Form*) Declaration* Form* @@ -1676,7 +1753,7 @@ symbol-case giving up: case=((V U) (F)) (sb-xc:defmacro dotimes ((var count &optional (result nil)) &body body) ;; A nice optimization would be that if VAR is never referenced, ;; it's slightly more efficient to count backwards, but that's tricky. - (let ((c (if (integerp count) count (sb-xc:gensym)))) + (let ((c (if (integerp count) count (gensym)))) `(do ((,var 0 (1+ ,var)) ,@(if (symbolp c) `((,c (the integer ,count))))) ((>= ,var ,c) ,result) @@ -1693,12 +1770,12 @@ symbol-case giving up: case=((V U) (F)) ;; since we don't want to use IGNORABLE on what might be a special ;; var. (binding* (((forms decls) (parse-body body nil)) - (n-list (gensym "N-LIST")) + (n-list (gensym "LIST")) (start (gensym "START")) ((clist members clist-ok) (with-current-source-form (list) (cond - ((sb-xc:constantp list env) + ((constantp list env) (binding* ((value (constant-form-value list env)) ((all dot) (list-members value :max-length 20))) (when (eql dot t) @@ -1709,19 +1786,26 @@ symbol-case giving up: case=((V U) (F)) (values value nil nil) (values value all t)))) ((and (consp list) (eq 'list (car list)) - (every (lambda (arg) (sb-xc:constantp arg env)) (cdr list))) + (every (lambda (arg) (constantp arg env)) (cdr list))) (let ((values (mapcar (lambda (arg) (constant-form-value arg env)) (cdr list)))) (values values values t))) (t (values nil nil nil)))))) `(block nil - (let ((,n-list ,(if clist-ok (list 'quote clist) list))) + (let ((,n-list ,(if clist-ok + (list 'quote clist) + ;; Don't want to use a cast because + ;; the type will actually be checked by ENDP first. + ;; But it doesn't detect the mismatch because the SETF + ;; mixes in T with the initial type. + `(the* (list :use-annotations t :source-form ,list) ,list)))) (tagbody ,start (unless (endp ,n-list) (let ((,var ,(if clist-ok `(truly-the (member ,@members) (car ,n-list)) `(car ,n-list)))) + (declare (ignorable ,var)) ,@decls (setq ,n-list (cdr ,n-list)) (tagbody ,@forms)) @@ -1756,9 +1840,6 @@ symbol-case giving up: case=((V U) (F)) `(sb-c::%proclaim ',spec (sb-c:source-location))) specs))) -;; Avoid unknown return values in emitted code for PRINT-UNREADABLE-OBJECT -(sb-xc:proclaim '(ftype (sfunction (t t t &optional t) null) - %print-unreadable-object)) (sb-xc:defmacro print-unreadable-object ((object stream &key type identity) &body body) "Output OBJECT to STREAM with \"#<\" prefix, \">\" suffix, optionally @@ -1781,7 +1862,7 @@ symbol-case giving up: case=((V U) (F)) (cons (eql quote) (cons symbol null)) (cons (eql lambda)))) (values nil `(funcall ,funarg . ,arg-forms)) - (let ((fn-sym (sb-xc:gensym))) ; for ONCE-ONLY-ish purposes + (let ((fn-sym (gensym))) ; for ONCE-ONLY-ish purposes (values `((,fn-sym (%coerce-callable-to-fun ,funarg))) `(sb-c::%funcall ,fn-sym . ,arg-forms))))) @@ -1809,3 +1890,450 @@ symbol-case giving up: case=((V U) (F)) ;; is cheaper than a branch around a write. (rplacd (truly-the cons ,splice) ,orig))) ,copy)))))) + +(defun expand-with-output-to-string (var element-type body wild-result-type) + ;; This is simpler than trying to arrange transforms that cause + ;; MAKE-STRING-OUTPUT-STREAM to be DXable. While that might be awesome, + ;; this macro exists for a reason. + (let ((initial-buffer '#:buf) + (dummy '#:stream) + (string-let (or #+c-stack-is-control-stack 'dx-let 'let)) + (string-ctor + (if (and (sb-xc:constantp element-type) + (let ((ctype (sb-c::careful-specifier-type + (constant-form-value element-type)))) + (and ctype + (csubtypep ctype (specifier-type 'character)) + (neq ctype *empty-type*)))) + ;; Using MAKE-ARRAY avoids a style-warning if et is 'STANDARD-CHAR: + ;; "The default initial element #\Nul is not a STANDARD-CHAR." + 'make-array ; hooray! it's known be a valid string type + ;; Force a runtime STRINGP check unless futher transforms + ;; deduce a known type. You'll get "could not stack allocate" + ;; perhaps, but that's acceptable. + 'make-string))) + ;; A full call to MAKE-STRING-OUTPUT-STREAM uses a larger initial buffer + ;; if BASE-CHAR but I really don't care to think about that here. + `(,string-let ((,initial-buffer (,string-ctor 31 :element-type ,element-type))) + (dx-let ((,dummy (%allocate-string-ostream))) + (let ((,var (%init-string-output-stream ,dummy ,initial-buffer + ,wild-result-type))) + (declare (ignorable ,var)) + ,@body) + (get-output-stream-string ,dummy))))) + + +;;;; COMPARE-AND-SWAP +;;;; +;;;; SB-EXT:COMPARE-AND-SWAP is the public API for now. +;;;; +;;;; Internally our interface has CAS, GET-CAS-EXPANSION, +;;;; DEFCAS, and #'(CAS ...) functions. + +(defun expand-structure-slot-cas (info name place) + (let* ((dd (car info)) + (structure (dd-name dd)) + (slotd (cdr info)) + (index (dsd-index slotd)) + (type (dsd-type slotd)) + (casser + (case (dsd-raw-type slotd) + ((t) '%instance-cas) + #+(or arm64 ppc ppc64 riscv x86 x86-64) + ((word) '%raw-instance-cas/word) + #+(or arm64 riscv x86 x86-64) + ((sb-vm:signed-word) '%raw-instance-cas/signed-word)))) + (unless casser + (error "Cannot use COMPARE-AND-SWAP with structure accessor ~ + for a typed slot: ~S" + place)) + (when (dsd-read-only slotd) + (error "Cannot use COMPARE-AND-SWAP with structure accessor ~ + for a read-only slot: ~S" + place)) + (destructuring-bind (op arg) place + (aver (eq op name)) + (with-unique-names (instance old new) + (values (list instance) + (list `(the ,structure ,arg)) + old + new + `(truly-the (values ,type &optional) + (,casser ,instance ,index + (the ,type ,old) + (the ,type ,new))) + `(,op ,instance)))))) + +;;; FIXME: remove (it's EXPERIMENTAL, so doesn't need to go through deprecation) +(defun get-cas-expansion (place &optional environment) + "Analogous to GET-SETF-EXPANSION. Returns the following six values: + + * list of temporary variables + + * list of value-forms whose results those variable must be bound + + * temporary variable for the old value of PLACE + + * temporary variable for the new value of PLACE + + * form using the aforementioned temporaries which performs the + compare-and-swap operation on PLACE + + * form using the aforementioned temporaries with which to perform a volatile + read of PLACE + +Example: + + (get-cas-expansion '(car x)) + ; => (#:CONS871), (X), #:OLD872, #:NEW873, + ; (SB-KERNEL:%COMPARE-AND-SWAP-CAR #:CONS871 #:OLD872 :NEW873). + ; (CAR #:CONS871) + + (defmacro my-atomic-incf (place &optional (delta 1) &environment env) + (multiple-value-bind (vars vals old new cas-form read-form) + (get-cas-expansion place env) + (let ((delta-value (gensym \"DELTA\"))) + `(let* (,@(mapcar 'list vars vals) + (,old ,read-form) + (,delta-value ,delta) + (,new (+ ,old ,delta-value))) + (loop until (eq ,old (setf ,old ,cas-form)) + do (setf ,new (+ ,old ,delta-value))) + ,new)))) + +EXPERIMENTAL: Interface subject to change." + ;; FIXME: this seems wrong on two points: + ;; 1. if TRULY-THE had a CAS expander (which it doesn't) we'd want + ;; to use %MACROEXPAND[-1] so as not to lose the "truly-the"-ness + ;; 2. if both a CAS expander and a macro exist, the CAS expander + ;; should be preferred before macroexpanding (just like SETF does) + (let ((expanded (macroexpand place environment))) + (flet ((invalid-place () + (error "Invalid place to CAS: ~S -> ~S" place expanded))) + (unless (consp expanded) + (cond ((and (symbolp expanded) + (member (info :variable :kind expanded) + '(:global :special))) + (setq expanded `(symbol-value ',expanded))) + (t + (invalid-place)))) + (let ((name (car expanded))) + (unless (symbolp name) + (invalid-place)) + (acond + ((info :cas :expander name) + ;; CAS expander. + (funcall it expanded environment)) + + ;; Structure accessor + ((structure-instance-accessor-p name) + (expand-structure-slot-cas it name expanded)) + + ;; CAS function + (t + (with-unique-names (old new) + (let ((vars nil) + (vals nil) + (args nil)) + (dolist (x (reverse (cdr expanded))) + (cond ((constantp x environment) + (push x args)) + (t + (let ((tmp (gensymify x))) + (push tmp args) + (push tmp vars) + (push x vals))))) + (values vars vals old new + `(funcall #'(cas ,name) ,old ,new ,@args) + `(,name ,@args)))))))))) + + +;;; This is what it all comes down to. +(sb-xc:defmacro cas (place old new &environment env) + "Synonym for COMPARE-AND-SWAP. + +Additionally DEFUN, DEFGENERIC, DEFMETHOD, FLET, and LABELS can be also used to +define CAS-functions analogously to SETF-functions: + + (defvar *foo* nil) + + (defun (cas foo) (old new) + (cas (symbol-value '*foo*) old new)) + +First argument of a CAS function is the expected old value, and the second +argument of is the new value. Note that the system provides no automatic +atomicity for CAS functions, nor can it verify that they are atomic: it is up +to the implementor of a CAS function to ensure its atomicity. + +EXPERIMENTAL: Interface subject to change." + ;; It's not necessary that GET-CAS-EXPANSION work on defined alien vars. + ;; They're not generalized places in the sense that they could hold any object, + ;; so there's very little point to being more general. + ;; In particular, allowing ATOMIC-PUSH or ATOMIC-POP on them is wrong. + (awhen (and (symbolp place) + (eq (info :variable :kind place) :alien) + (sb-alien::cas-alien place old new)) + (return-from cas it)) + (multiple-value-bind (temps place-args old-temp new-temp cas-form) + (get-cas-expansion place env) + `(let* (,@(mapcar #'list temps place-args) + (,old-temp ,old) + (,new-temp ,new)) + ,cas-form))) + +(sb-xc:defmacro compare-and-swap (place old new) + "Atomically stores NEW in PLACE if OLD matches the current value of PLACE. +Two values are considered to match if they are EQ. Returns the previous value +of PLACE: if the returned value is EQ to OLD, the swap was carried out. + +PLACE must be an CAS-able place. Built-in CAS-able places are accessor forms +whose CAR is one of the following: + + CAR, CDR, FIRST, REST, SVREF, SYMBOL-PLIST, SYMBOL-VALUE, SVREF, SLOT-VALUE + SB-MOP:STANDARD-INSTANCE-ACCESS, SB-MOP:FUNCALLABLE-STANDARD-INSTANCE-ACCESS, + +or the name of a DEFSTRUCT created accessor for a slot whose storage type +is not raw. (Refer to the the \"Efficiency\" chapter of the manual +for the list of raw slot types. Future extensions to this macro may allow +it to work on some raw slot types.) + +In case of SLOT-VALUE, if the slot is unbound, SLOT-UNBOUND is called unless +OLD is EQ to SB-PCL:+SLOT-UNBOUND+ in which case SB-PCL:+SLOT-UNBOUND+ is +returned and NEW is assigned to the slot. Additionally, the results are +unspecified if there is an applicable method on either +SB-MOP:SLOT-VALUE-USING-CLASS, (SETF SB-MOP:SLOT-VALUE-USING-CLASS), or +SB-MOP:SLOT-BOUNDP-USING-CLASS. + +Additionally, the PLACE can be a anything for which a CAS-function has +been defined. (See SB-EXT:CAS for more information.) +" + `(cas ,place ,old ,new)) + + +;;;; ATOMIC-INCF and ATOMIC-DECF + +(defun expand-atomic-frob + (name specified-place diff env + &aux (place (macroexpand specified-place env))) + (declare (type (member atomic-incf atomic-decf) name)) + (flet ((invalid-place () + (error "Invalid first argument to ~S: ~S" name specified-place)) + (compute-newval (old) ; used only if no atomic inc vop + `(logand (,(case name (atomic-incf '+) (atomic-decf '-)) ,old + (the sb-vm:signed-word ,diff)) sb-ext:most-positive-word)) + (compute-delta () ; used only with atomic inc vop + `(logand ,(case name + (atomic-incf `(the sb-vm:signed-word ,diff)) + (atomic-decf `(- (the sb-vm:signed-word ,diff)))) + sb-ext:most-positive-word))) + (declare (ignorable #'compute-newval #'compute-delta)) + (when (and (symbolp place) + (eq (info :variable :kind place) :global) + (type= (info :variable :type place) (specifier-type 'fixnum))) + ;; Global can't be lexically rebound. + (return-from expand-atomic-frob + `(truly-the fixnum (,(case name + (atomic-incf '%atomic-inc-symbol-global-value) + (atomic-decf '%atomic-dec-symbol-global-value)) + ',place (the fixnum ,diff))))) + (unless (consp place) (invalid-place)) + (destructuring-bind (op . args) place + ;; FIXME: The lexical environment should not be disregarded. + ;; CL builtins can't be lexically rebound, but structure accessors can. + (case op + (aref + (unless (singleton-p (cdr args)) + (invalid-place)) + (with-unique-names (array) + `(let ((,array (the (simple-array word (*)) ,(car args)))) + #+compare-and-swap-vops + (%array-atomic-incf/word + ,array + (check-bound ,array (array-dimension ,array 0) ,(cadr args)) + ,(compute-delta)) + #-compare-and-swap-vops + ,(with-unique-names (index old-value) + `(without-interrupts + (let* ((,index ,(cadr args)) + (,old-value (aref ,array ,index))) + (setf (aref ,array ,index) ,(compute-newval old-value)) + ,old-value)))))) + ((car cdr first rest) + (when (cdr args) + (invalid-place)) + `(truly-the + fixnum + (,(case op + ((first car) (case name + (atomic-incf '%atomic-inc-car) + (atomic-decf '%atomic-dec-car))) + ((rest cdr) (case name + (atomic-incf '%atomic-inc-cdr) + (atomic-decf '%atomic-dec-cdr)))) + ,(car args) (the fixnum ,diff)))) + (t + (when (or (cdr args) + ;; Because accessor info is identical for the writer and reader + ;; functions, without a SYMBOLP check this would erroneously allow + ;; (ATOMIC-INCF ((SETF STRUCT-SLOT) x)) + (not (symbolp op)) + (not (structure-instance-accessor-p op))) + (invalid-place)) + (let* ((accessor-info (structure-instance-accessor-p op)) + (slotd (cdr accessor-info)) + (type (dsd-type slotd))) + (unless (and (eq 'sb-vm:word (dsd-raw-type slotd)) + (type= (specifier-type type) (specifier-type 'sb-vm:word))) + (error "~S requires a slot of type (UNSIGNED-BYTE ~S), not ~S: ~S" + name sb-vm:n-word-bits type place)) + (when (dsd-read-only slotd) + (error "Cannot use ~S with structure accessor for a read-only slot: ~S" + name place)) + #+compare-and-swap-vops + `(truly-the sb-vm:word + (%raw-instance-atomic-incf/word + (the ,(dd-name (car accessor-info)) ,@args) + ,(dsd-index slotd) + ,(compute-delta))) + #-compare-and-swap-vops + (with-unique-names (structure old-value) + `(without-interrupts + (let* ((,structure ,@args) + (,old-value (,op ,structure))) + (setf (,op ,structure) ,(compute-newval old-value)) + ,old-value))))))))) + +(sb-xc:defmacro atomic-incf (&environment env place &optional (diff 1)) + #.(format nil + "Atomically increments PLACE by DIFF, and returns the value of PLACE before +the increment. + +PLACE must access one of the following: + - a DEFSTRUCT slot with declared type (UNSIGNED-BYTE ~D~:*) + or AREF of a (SIMPLE-ARRAY (UNSIGNED-BYTE ~D~:*) (*)) + The type SB-EXT:WORD can be used for these purposes. + - CAR or CDR (respectively FIRST or REST) of a CONS. + - a variable defined using DEFGLOBAL with a proclaimed type of FIXNUM. +Macroexpansion is performed on PLACE before expanding ATOMIC-INCF. + +Incrementing is done using modular arithmetic, +which is well-defined over two different domains: + - For structures and arrays, the operation accepts and produces + an (UNSIGNED-BYTE ~D~:*), and DIFF must be of type (SIGNED-BYTE ~D). + ATOMIC-INCF of #x~x by one results in #x0 being stored in PLACE. + - For other places, the domain is FIXNUM, and DIFF must be a FIXNUM. + ATOMIC-INCF of #x~x by one results in #x~x + being stored in PLACE. + +DIFF defaults to 1. + +EXPERIMENTAL: Interface subject to change." + sb-vm:n-word-bits most-positive-word + most-positive-fixnum most-negative-fixnum) + (expand-atomic-frob 'atomic-incf place diff env)) + +(sb-xc:defmacro atomic-decf (&environment env place &optional (diff 1)) + #.(format nil + "Atomically decrements PLACE by DIFF, and returns the value of PLACE before +the decrement. + +PLACE must access one of the following: + - a DEFSTRUCT slot with declared type (UNSIGNED-BYTE ~D~:*) + or AREF of a (SIMPLE-ARRAY (UNSIGNED-BYTE ~D~:*) (*)) + The type SB-EXT:WORD can be used for these purposes. + - CAR or CDR (respectively FIRST or REST) of a CONS. + - a variable defined using DEFGLOBAL with a proclaimed type of FIXNUM. +Macroexpansion is performed on PLACE before expanding ATOMIC-DECF. + +Decrementing is done using modular arithmetic, +which is well-defined over two different domains: + - For structures and arrays, the operation accepts and produces + an (UNSIGNED-BYTE ~D~:*), and DIFF must be of type (SIGNED-BYTE ~D). + ATOMIC-DECF of #x0 by one results in #x~x being stored in PLACE. + - For other places, the domain is FIXNUM, and DIFF must be a FIXNUM. + ATOMIC-DECF of #x~x by one results in #x~x + being stored in PLACE. + +DIFF defaults to 1. + +EXPERIMENTAL: Interface subject to change." + sb-vm:n-word-bits most-positive-word + most-negative-fixnum most-positive-fixnum) + (expand-atomic-frob 'atomic-decf place diff env)) + +(sb-xc:defmacro atomic-update (place update-fn &rest arguments &environment env) + "Updates PLACE atomically to the value returned by calling function +designated by UPDATE-FN with ARGUMENTS and the previous value of PLACE. + +PLACE may be read and UPDATE-FN evaluated and called multiple times before the +update succeeds: atomicity in this context means that the value of PLACE did +not change between the time it was read, and the time it was replaced with the +computed value. + +PLACE can be any place supported by SB-EXT:COMPARE-AND-SWAP. + +Examples: + + ;;; Conses T to the head of FOO-LIST. + (defstruct foo list) + (defvar *foo* (make-foo)) + (atomic-update (foo-list *foo*) #'cons t) + + (let ((x (cons :count 0))) + (mapc #'sb-thread:join-thread + (loop repeat 1000 + collect (sb-thread:make-thread + (lambda () + (loop repeat 1000 + do (atomic-update (cdr x) #'1+) + (sleep 0.00001)))))) + ;; Guaranteed to be (:COUNT . 1000000) -- if you replace + ;; atomic update with (INCF (CDR X)) above, the result becomes + ;; unpredictable. + x) +" + (multiple-value-bind (vars vals old new cas-form read-form) + (get-cas-expansion place env) + `(let* (,@(mapcar 'list vars vals) + (,old ,read-form)) + (loop for ,new = (funcall ,update-fn ,@arguments ,old) + until (eq ,old (setf ,old ,cas-form)) + finally (return ,new))))) + +(sb-xc:defmacro atomic-push (obj place &environment env) + "Like PUSH, but atomic. PLACE may be read multiple times before +the operation completes -- the write does not occur until such time +that no other thread modified PLACE between the read and the write. + +Works on all CASable places." + (multiple-value-bind (vars vals old new cas-form read-form) + (get-cas-expansion place env) + `(let* (,@(mapcar 'list vars vals) + (,old ,read-form) + (,new (cons ,obj ,old))) + (loop until (eq ,old (setf ,old ,cas-form)) + do (setf (cdr ,new) ,old) + finally (return ,new))))) + +(sb-xc:defmacro atomic-pop (place &environment env) + "Like POP, but atomic. PLACE may be read multiple times before +the operation completes -- the write does not occur until such time +that no other thread modified PLACE between the read and the write. + +Works on all CASable places." + (multiple-value-bind (vars vals old new cas-form read-form) + (get-cas-expansion place env) + `(let* (,@(mapcar 'list vars vals) + (,old ,read-form)) + (loop (let ((,new (cdr ,old))) + (when (eq ,old (setf ,old ,cas-form)) + (return (car (truly-the list ,old))))))))) + +#-metaspace +(progn +(sb-xc:defmacro wrapper-friend (x) x) +(sb-xc:defmacro layout-friend (x) x) +(sb-xc:defmacro layout-clos-hash (x) `(wrapper-clos-hash ,x)) +#-64-bit (sb-xc:defmacro layout-depthoid (x) `(wrapper-depthoid ,x)) +(sb-xc:defmacro layout-flags (x) `(wrapper-flags ,x)) +) diff --git a/src/code/maphash.lisp b/src/code/maphash.lisp index 9adae7b5d6..6dbf2b8a01 100644 --- a/src/code/maphash.lisp +++ b/src/code/maphash.lisp @@ -22,7 +22,7 @@ ;;; like INDEX, but only up to half the maximum. Used by hash-table ;;; code that does plenty to (aref v (* 2 i)) and (aref v (1+ (* 2 i))). -(deftype index/2 () `(integer 0 (,(floor sb-xc:array-dimension-limit 2)))) +(deftype index/2 () `(integer 0 (,(floor array-dimension-limit 2)))) ;;; The high water mark is an element of the pairs vector, and not ;;; a slot in the table. @@ -97,22 +97,81 @@ applies to all threads, not just the current one -- even for synchronized hash-tables. If the table may be mutated by another thread during iteration, use eg. SB-EXT:WITH-LOCKED-HASH-TABLE to protect the WITH-HASH-TABLE-ITERATOR for." - (let ((function (gensymify* name "-FUN"))) - `(let ((,function - (let* ((kv-vector (hash-table-pairs ,hash-table)) - (limit (1+ (* 2 (kv-vector-high-water-mark kv-vector)))) - (index 3)) - (declare (fixnum index)) - (flet ((,name () - (loop - (when (> index limit) (return nil)) - (let ((i index)) - (incf (truly-the index index) 2) - (let ((key (data-vector-ref kv-vector (1- i))) - (value (data-vector-ref kv-vector i))) - (unless (or (empty-ht-slot-p key) - (empty-ht-slot-p value)) - (return (values t key value)))))))) - #',name)))) - (macrolet ((,name () '(funcall ,function))) - ,@body)))) + ;; If within the BODY code the stepping function is used exactly once, then + ;; it gets let-converted and so it should make no difference whether it returns + ;; one or more than one value (it would never need RETURN-MULTIPLE). + ;; However if the iterator is not let-converted then it is best to return + ;; a fixed number of values on success or failure. + (let ((kvv (make-symbol "KVV")) + (lim (make-symbol "LIMIT")) + (ind (make-symbol "INDEX")) + (step (make-symbol "THUNK"))) + `(let* ((,kvv (hash-table-pairs ,hash-table)) + (,lim (1+ (* 2 (kv-vector-high-water-mark ,kvv)))) + (,ind 3)) + (declare (fixnum ,ind)) + (dx-flet ((,step () + (loop + (when (> ,ind ,lim) (return (values t nil nil))) + (let ((i ,ind)) + (incf (truly-the index ,ind) 2) + (let ((k (data-vector-ref ,kvv (1- i))) + (v (data-vector-ref ,kvv i))) + (unless (or (empty-ht-slot-p k) (empty-ht-slot-p v)) + (return (values nil k v)))))))) + (macrolet ((,name () + '(multiple-value-bind (endp k v) (,step) + (unless endp (values t k v))))) + ,@body))))) + +(define-compiler-macro make-hash-table (&whole form &rest keywords) + (let ((kind + (cond ((not keywords) 1) + ((typep keywords '(cons (eql :test) (cons t null))) + (let* ((arg (cadr keywords)) + (test (when (typep arg '(cons (member function quote) (cons t null))) + (cadr arg)))) + (position test #(eq eql equal equalp))))))) + (if kind + `(make-hash-table-using-defaults ,kind) + form))) + +(defconstant hash-table-weak-flag 8) +(defconstant hash-table-finalizer-flag 4) +;;; USERFUN-FLAG implies a nonstandard hash function. Such tables may also have +;;; a custom comparator. But you can't have a custom comparator without a custom +;;; hash, because there's no way in general to produce a compatible hash. +(defconstant hash-table-userfun-flag 2) +(defconstant hash-table-synchronized-flag 1) + +;;; Keep in sync with weak_ht_alivep_funs[] in gc-common +(defconstant +ht-weak-key-AND-value+ 0) +(defconstant +ht-weak-key+ 1) +(defconstant +ht-weak-value+ 2) +(defconstant +ht-weak-key-OR-value+ 3) + +(eval-when (:compile-toplevel :load-toplevel :execute) + ;; Don't raise this number to 8 - if you do it'll increase the memory + ;; consumption of a default MAKE-HASH-TABLE call by 7% just due to + ;; padding slots. This is a "perfect" minimal size. + (defconstant +min-hash-table-size+ 7) + (defconstant default-rehash-size $1.5)) + +(defmacro make-system-hash-table (&key test synchronized weakness finalizer) + (multiple-value-bind (kind args) + (cond ((equal test '(quote eq)) (values 0 '('eq #'eq #'eq-hash))) + ((equal test '(quote eql)) (values 1 '('eql #'eql #'eql-hash))) + (t + (bug "Incomplete implementation of MAKE-SYSTEM-HASH-TABLE") + 0)) + `(%make-hash-table + (logior ,(ecase weakness + (:key '(pack-ht-flags-weakness +ht-weak-key+)) + (:value '(pack-ht-flags-weakness +ht-weak-value+))) + (pack-ht-flags-kind ,kind) + ,(if synchronized 'hash-table-synchronized-flag 0) + ,(if finalizer 'hash-table-finalizer-flag 0)) + ,@args + ,+min-hash-table-size+ + default-rehash-size + $1.0))) diff --git a/src/code/metaspace.lisp b/src/code/metaspace.lisp new file mode 100644 index 0000000000..09019443a8 --- /dev/null +++ b/src/code/metaspace.lisp @@ -0,0 +1,370 @@ +;;;; Allocator for LAYOUTs in the metadata space a/k/a "metaspace". +;;;; These objects are manually allocated and freed. + +;;;; This software is part of the SBCL system. See the README file for +;;;; more information. +;;;; +;;;; This software is derived from the CMU CL system, which was +;;;; written at Carnegie Mellon University and released into the +;;;; public domain. The software is in the public domain and is +;;;; provided with absolutely no warranty. See the COPYING and CREDITS +;;;; files for more information. + +(in-package "SB-VM") + +;; A slab "size class" holds any object of that size or smaller. +(defconstant-eqx chunk-size-classes ; measured in lispwords + #.(sb-xc:make-array 8 :initial-contents '(0 8 12 16 24 32 48 64) + :element-type '(unsigned-byte 16)) + #'equalp) + +;;; The most common layout size is just 8 words: +;;; word 0: header +;;; word 1: wrapper +;;; word 2: clos hash +;;; word 3: flags +;;; word 4..6 : ID vector +;;; word 7: bitmap +;;; Thus the smallest size the slab allocator can dole out is 8 words. + +;; The largest size class nust not exceed the physical size of the slab, +;; counting the fixed overhead of 4 words. +;; nwords | capacity | used | waste +;; | | (bytes) +;; --------+----------+--------------- +;; 8 | 31 | 2016 | 32 +;; 12 | 21 | 2048 | 0 +;; 16 | 15 | 1952 | 96 +;; 24 | 10 | 1952 | 96 +;; 32 | 7 | 1824 | 224 +;; 48 | 5 | 1952 | 96 +;; 64 | 3 | 1472 | 480 +;; "Waste" = slab size - overhead - (chunk_size_in_bytes * capacity). + +(defun chunk-nwords-to-sizeclass-index (nwords) + (let ((classes chunk-size-classes)) + (loop for i from 1 below (length classes) + when (<= nwords (aref classes i)) + do (return i) + finally (error "Oversized chunk: ~D words" nwords)))) + +(defun metaspace-sizeclass->nbytes (sizeclass) + (* (aref chunk-size-classes sizeclass) n-word-bytes)) + +(define-load-time-global *metaspace-freelists* (make-array 8 :element-type 'word :initial-element 0)) +(declaim (type (simple-array word (8)) *metaspace-freelists*)) + +;;; A completely empty slab is put back in this list for reuse, +;;; and a different chunk size can be chosen for it when next used. +;;; This is a singly-linked list threaded through SLAB-NEXT. +(defmacro metaspace-slab-recycler () '(aref *metaspace-freelists* 0)) + +;;; A list of memory ranges obtained directly from os_allocate. +;;; A tract is represented by a pointer to its start and a pointer +;;; to the highest address not yet used. Slabs are allocated downwards, +;;; so that when the start and the in-use pointer of a tract collide, +;;; the tract is full. +;;; In typical usage, there will be exactly 1 tract. This is enough room +;;; to hold approximately 32768 instances of LAYOUT, depending on the +;;; size of the layouts stored. It is unlikely that more room would be +;;; needed, but it does work to have a variable number of tracts. +;;; +;;; If at some point we ever figure out how to make both the static space +;;; and metaspace relocatable, and we permanently wire a CPU register to point +;;; to the boundary between the spaces, then the fact that metaspace grows +;;; downward will be halpful in as much as the register will be able to access +;;; a certain amount of either space using small positive or negative offsets. +;;; +;;; Tract: #(base free end next-tract) +(define-load-time-global *metaspace-tracts* nil) +(defmacro tract-base (tract) + `(aref (truly-the (simple-array word (4)) ,tract) 0)) +(defmacro tract-current (tract) + `(aref (truly-the (simple-array word (4)) ,tract) 1)) +(defmacro tract-end (tract) + `(aref (truly-the (simple-array word (4)) ,tract) 2)) + +(defmacro do-tracts ((var) &body body) + `(let ((,var *metaspace-tracts*)) + ;; no iteration yet + ,@body)) + +;;; Try to place a tract just below the readonly space, which we know to be +;;; at a good sub-2GiB address that works for the architecture and OS. +;;; TODO: if multiple tracts exist and were allocated consecutively, +;;; can we coalesce them? +(defun os-allocate-metaspace-tract () + (error "Can't allocate new metaspace tracts") + #+nil + (let* ((request (- (if (null *metaspace-tracts*) + sb-vm:read-only-space-start + (reduce #'min *metaspace-tracts* + :key (lambda (x) (sap-int (car x))))) + metaspace-tract-size)) + (actual (alien-funcall + (extern-alien "os_validate" (function system-area-pointer int unsigned unsigned)) + #+linux 3 ; movable | MAP_32BIT + #-linux 1 ; movable + request metaspace-tract-size))) + ;; The tract's representation is (base-address . current-pointer) + (let ((tract (cons actual (sap+ actual metaspace-tract-size)))) + (push tract *metaspace-tracts*) + tract))) + +;;; Grab a slab out of an available tract and assign it a chunk size +;;; which is represented both as bytes and a class index. +(defun new-metaspace-slab (chunk-size-bytes sizeclass) + (let ((slab (int-sap (metaspace-slab-recycler)))) + (if (/= (sap-int slab) 0) + (setf (metaspace-slab-recycler) (sap-int (slab-next slab))) + (let ((tract *metaspace-tracts*)) + (when (= (tract-base tract) (tract-current tract)) + (setq tract (os-allocate-metaspace-tract))) + ;; Claim some new space from the tract, below CURRENT and above BASE. + (let* ((end (int-sap (tract-current tract))) + (start (sap+ end (- metaspace-slab-size)))) + (setf (tract-current tract) (sap-int start) + slab start)))) + ;; Build a linked list of chunks in the slab. The highest-addressed chunk + ;; in the slab aligns its end to exactly the end of the slab. In this way + ;; any unused bytes can be lumped together with the fixed overhead at the + ;; beginning, versus if the first chunk's start abutted the end of the fixed + ;; words, then there may be unused space at both ends, and so the math + ;; for checking valid pointers would get too messy. + ;; i.e. we need an inquiry operation for "is it a valid chunk?" given any + ;; random bit pattern, and it must be reliable and efficient. + (let* ((chunk-end (sap+ slab metaspace-slab-size)) + (chunk (sap+ chunk-end (- chunk-size-bytes))) ; chunk start + (usable-range-start (slab-usable-range-start slab)) + (capacity 1)) + (setf (sap-ref-word chunk 0) 0) ; terminate the freelist + (loop (let ((previous (sap+ chunk (- chunk-size-bytes)))) + (when (sap< previous usable-range-start) (return)) + (incf capacity) + (setf (sap-ref-sap previous 0) chunk + chunk-end chunk + chunk previous))) + (init-slab-header slab sizeclass chunk-size-bytes capacity) + (setf (slab-freelist slab) chunk) + ;; Insert this as the sole slab for this sizeclass. + ;; A new slab is never allocated if the sizeclass has any slabs + ;; with space available. + (setf (aref *metaspace-freelists* sizeclass) (sap-int slab)) + #+debug (format t "New slab @ ~x, capacity ~d, waste=~Db~% list=~x~%" + slab (slab-capacity slab) + (- metaspace-slab-size + (* slab-overhead-words n-word-bytes) + (* (slab-capacity slab) chunk-size-bytes)) + (slab-freelist-as-list slab)) + slab))) + +(defmacro chunk-used-p (chunk) + `(= (sap-ref-8 ,chunk #+little-endian 0 #+big-endian ,(1- n-word-bytes)) + instance-widetag)) + +;;; A not-in-use chunk is linked through its 0th word, which will never +;;; resemble a lisp object header word. +(defmacro chunk-next (chunk) `(sap-ref-sap ,chunk 0)) + +;;; Test whether ADDRESS is a conservative (ambiguous) root. +;;; This algorithm will need to be in C of course. +(defun valid-metaspace-chunk-p (addr) + (declare (word addr)) + (unless (= (logand addr lowtag-mask) instance-pointer-lowtag) + (return-from valid-metaspace-chunk-p nil)) + (setq addr (logandc2 addr lowtag-mask)) + (do-tracts (tract) + (when (and (>= addr (tract-current tract)) (< addr (tract-end tract))) + ;; Align to containing slab + (let ((slab (int-sap (logandc2 addr (1- metaspace-slab-size))))) + (return-from valid-metaspace-chunk-p + (and (not (zerop (slab-usage slab))) + ;; Chunks are aligned such that the final chunk touches the + ;; final word of the slab. Therefore to find a chunk index + ;; we need to compute the displacement backwards from end. + (multiple-value-bind (index remainder) + (floor (sap- (sap+ slab metaspace-slab-size) (int-sap addr)) + (slab-chunk-size slab)) + (and (zerop remainder) ; correctly aligned + (<= index (slab-capacity slab)) ; within the slab + (chunk-used-p (int-sap addr)))))))))) + +(defun allocate-metaspace-chunk (nwords) + (let ((sizeclass (chunk-nwords-to-sizeclass-index nwords))) + (with-system-mutex (*allocator-mutex*) + (let* ((slab-addr (aref *metaspace-freelists* sizeclass)) + (slab (if (zerop slab-addr) + (new-metaspace-slab (metaspace-sizeclass->nbytes sizeclass) + sizeclass) + (int-sap slab-addr))) + (hole (slab-freelist slab)) + (next-hole (chunk-next hole))) + (aver (/= (sap-int hole) 0)) + (setf (slab-freelist slab) next-hole) + (incf (slab-usage slab)) + (when (= (sap-int next-hole) 0) + ;; Check some invariants - this had to be the head of the list of slabs + ;; for the sizeclass, and it has to be at max capacity. + (aver (= 0 (sap-int (slab-prev slab)))) + (aver (= (slab-usage slab) (slab-capacity slab))) + ;; Remove the slab from the list of slabs that have any + ;; available space for the size class. + (let ((next-slab (slab-next slab))) + (setf (aref *metaspace-freelists* sizeclass) + (cond ((= (sap-int next-slab) 0) + 0) + (t + (setf (slab-next slab) (int-sap 0) + (slab-prev next-slab) (int-sap 0)) + (sap-int next-slab)))))) + ;; Deposit a valid instance header word + (setf (sap-ref-word hole 0) + (logior (ash (1- nwords) (+ sb-vm:n-widetag-bits 2)) + instance-widetag)) + ;; Use the unchecked %MAKE-LISP-obj to return it + (%make-lisp-obj (logior (sap-int hole) instance-pointer-lowtag)))))) + +;;; Address should be an aligned (not tagged) base address of a chunk. +(defun unallocate-metaspace-chunk (address) + (declare (word address)) + #+debug (aver (metaspace-chunk-valid-p address)) + (let* ((slab (int-sap (logandc2 address (1- metaspace-slab-size)))) + (sizeclass (ash (slab-sizeclass slab) (- sb-vm:n-fixnum-tag-bits))) + (size (slab-chunk-size slab))) + (aver (= size (metaspace-sizeclass->nbytes sizeclass))) + ;; Clear the memory + (alien-funcall (extern-alien "memset" (function void unsigned int size-t)) + address 0 size) + (with-system-mutex (*allocator-mutex*) + (let* ((freelist (int-sap (aref *metaspace-freelists* sizeclass))) + (slab-was-partly-available ; true if already in freelist + (or (sap= freelist slab) (/= 0 (sap-int (slab-prev slab))))) + (n-objects (decf (slab-usage slab)))) ; new count + #+debug (format t "~&Hole in slab @ ~x, sizeclass ~D, newcount=~D of ~D~%" + slab sizeclass n-objects (slab-capacity slab)) + ;; If slab has become completely available, add it to the recycle bin. + (when (zerop n-objects) + (when slab-was-partly-available + ;; Capacity 1 can't exist in "partially available" state + (aver (> (slab-capacity slab) 1)) + ;; Remove from size-specific doubly-linked freelist before + ;; adding to recycle bin. + (let ((prev (slab-prev slab)) + (next (slab-next slab))) + ;; prev->next = this->next + (if (= (sap-int prev) 0) ; no previous, was the head of freelist + (setf (aref *metaspace-freelists* sizeclass) (sap-int next)) + (setf (slab-next prev) next)) + ;; next->prev = this->prev + (unless (= (sap-int next) 0) + (setf (slab-prev next) prev)))) + ;; Like (PUSH slab recycler) + (setf (slab-next slab) (int-sap (metaspace-slab-recycler)) + (metaspace-slab-recycler) (sap-int slab)) + ;; Clear out the unused words + (setf (sap-ref-word slab 0) 0 + (slab-prev slab) (int-sap 0) + (slab-freelist slab) (int-sap 0)) + #+debug (format t "~&Slab moved to recycle bin~%") + (return-from unallocate-metaspace-chunk)) + + ;; Slab has some used chunks, and gains an available chunk. + ;; Do like (PUSH address (slab-freelist slab)) + (let ((hole (int-sap address))) + (setf (chunk-next hole) (slab-freelist slab) + (slab-freelist slab) hole)) + + ;; If the slab was not already in the list of partly-available slabs for + ;; its sizeclass, it goes to the head of the respective doubly-linked list. + (unless slab-was-partly-available + #+debug (format t "~&Insert slab in sizeclass freelist~%") + (aver (= (sap-int (slab-prev slab)) 0)) + (setf (slab-next slab) freelist) + (unless (= (sap-int freelist) 0) + (setf (slab-prev freelist) slab)) + (setf (aref *metaspace-freelists* sizeclass) (sap-int slab)))))) + nil) + +;;;; That's the entire allocator. These are for examination of the state. + +(defun slab-freelist-as-list (slab &aux (sap (slab-freelist slab)) result) + (loop (if (sap= sap (int-sap 0)) (return (nreverse result))) + (push (sap-int sap) result) + (setq sap (sap-ref-sap sap 0)))) + +(export 'show-slabs) +(defun show-slabs (&aux (*print-right-margin* 128)) + (do-tracts (tract) + (let ((tract-end (int-sap (tract-end tract))) + (slab (int-sap (tract-current tract)))) + (format t "tract: Begin = ~x Current = ~x End = ~x~%" + (tract-base tract) (sap-int slab) (sap-int tract-end)) + (do ((slab slab (sap+ slab metaspace-slab-size))) + ((sap>= slab tract-end)) + (let ((ptr (sap+ slab metaspace-slab-size)) + (map)) + (dotimes (i (slab-capacity slab)) + (setf ptr (sap+ ptr (- (slab-chunk-size slab)))) + (push (if (chunk-used-p ptr) #\* #\_) map)) + (if (zerop (slab-capacity slab)) + (format t " slab @ ~x: free~%" (sap-int slab)) + (format t " slab @ ~x: cl=~D=~3Db, cap=~d, ct=~2d [~A]~%" + (sap-int slab) + (ash (slab-sizeclass slab) (- n-fixnum-tag-bits)) + (slab-chunk-size slab) + (slab-capacity slab) + (slab-usage slab) + ;; Map is collected in reverse order, so it shows in forward order + (coerce map 'string))))))) + (when (find 0 *metaspace-freelists* :start 1 :test #'/=) + (format t "Freelists:~%")) + (do ((sizeclass 1 (1+ sizeclass))) + ((= sizeclass (length *metaspace-freelists*))) + (let ((addr (aref *metaspace-freelists* sizeclass))) + (unless (zerop addr) + (format t " sizeclass ~d~%" sizeclass) + (let ((slab (int-sap addr))) + (aver (= (sap-int (slab-prev slab)) 0)) + (loop (format t " slab @ ~x: holes=~x~%" + (sap-int slab) (slab-freelist-as-list slab)) + (let ((next (slab-next slab))) + (if (sap= next (int-sap 0)) (return)) + (aver (sap= (slab-prev next) slab)) + (setq slab next))))))) + (do ((ptr (metaspace-slab-recycler)) + (list)) + ((= ptr 0) + (when list + (format t "Recycle: ~x~%" (nreverse list)))) + (push ptr list) + (setq ptr (sap-int (slab-next (int-sap ptr)))))) + +(defun slab-chunk-at (slab-base object-index) ; for hand-testing only + (declare (word slab-base)) + (let* ((slab (int-sap slab-base)) + (capacity (slab-capacity slab))) + (if (< object-index capacity) + (let ((ptr (sap+ slab + (- metaspace-slab-size + ;; Step backwards N objects + (* (slab-chunk-size slab) + (- capacity object-index)))))) + (when (chunk-used-p ptr) + (%make-lisp-obj (logior (sap-int ptr) instance-pointer-lowtag)))) + (warn "bad index")))) + +#| +(defun unallocate-lispobj (obj) + (unallocate-chunk (- (get-lisp-obj-address obj) instance-pointer-lowtag))) + +(defun unallocate-chunk-at (slab-base object-index) + (let ((obj (slab-chunk-at slab-base object-index))) + (when obj + (unallocate-lispobj obj)))) + +(defun dealloc-metaspace () + (fill *metaspace-freelists* 0) + (dolist (tract *metaspace-tracts*) + (deallocate-system-memory (tract-base tract) metaspace-tract-size)) + (setq *metaspace-tracts* nil)) +|# diff --git a/src/code/mips-vm.lisp b/src/code/mips-vm.lisp index 4c77767604..d8d07dcbe8 100644 --- a/src/code/mips-vm.lisp +++ b/src/code/mips-vm.lisp @@ -2,39 +2,12 @@ ;;; (in-package "SB-VM") - -#-sb-xc-host (defun machine-type () "Returns a string describing the type of the local machine." "MIPS") - -;;;; FIXUP-CODE-OBJECT -(defconstant-eqx +fixup-kinds+ #(:absolute :jmp :lui :addi) #'equalp) -(!with-bigvec-or-sap -(defun fixup-code-object (code offset value kind flavor) - (declare (type index offset)) - (declare (ignore flavor)) - (unless (zerop (rem offset sb-assem:+inst-alignment-bytes+)) - (error "Unaligned instruction? offset=#x~X." offset)) - (let ((sap (code-instructions code))) - (ecase kind - (:absolute - (setf (sap-ref-32 sap offset) value)) - (:jump - (aver (zerop (ash value -28))) - (setf (ldb (byte 26 0) (sap-ref-32 sap offset)) - (ash value -2))) - (:lui - (setf (ldb (byte 16 0) (sap-ref-32 sap offset)) - (ash (1+ (ash value -15)) -1))) - (:addi - (setf (ldb (byte 16 0) (sap-ref-32 sap offset)) - (ldb (byte 16 0) value))))) - nil)) - - -#-sb-xc-host (progn +(defun return-machine-address (scp) + (context-register scp lip-offset)) (define-alien-routine ("os_context_bd_cause" context-bd-cause-int) unsigned-int @@ -85,5 +58,14 @@ (offset (if (logbitp 31 cause) 4 0)) (trap-number (ldb (byte 8 6) (sap-ref-32 pc offset)))) (declare (type system-area-pointer pc)) - (sb-kernel::decode-internal-error-args (sap+ pc (+ offset 4)) trap-number))) -) ; end PROGN + ;; Pick off invalid-arg-count here. Otherwise call the generic routine + (let ((inst (sap-ref-32 pc offset))) + ;; FIXME: recognize the whole gamut of trap instructions + (cond ((and (= (ldb (byte 6 0) inst) #b110110) ; TNE + (= (ldb (byte 10 6) inst) invalid-arg-count-trap)) + (let ((rs (ldb (byte 5 21) inst))) ; expect this to be NARGS-TN + (values (error-number-or-lose 'invalid-arg-count-error) + (list (make-sc+offset (sc-number-or-lose 'any-reg) rs)) + invalid-arg-count-trap))) + (t + (sb-kernel::decode-internal-error-args (sap+ pc (+ offset 4)) trap-number)))))) diff --git a/src/code/mipsstrops.lisp b/src/code/mipsstrops.lisp index 06d4cb6b6b..6e9e48161b 100644 --- a/src/code/mipsstrops.lisp +++ b/src/code/mipsstrops.lisp @@ -14,7 +14,7 @@ ;;; Compare the substrings specified by STRING1 and STRING2 and return ;;; two values, the last index and the difference between the last characters -(defun %sp-string-compare (string1 start1 end1 string2 start2 end2) +(defun %sp-string-compare (string1 string2 start1 end1 start2 end2) (let* ((end1 (or end1 (length string1))) (end2 (or end2 @@ -57,3 +57,24 @@ (return (values index1 (- (char-code char1) (char-code char2))))))))))) + +;;; Doesn't need to return a mismatch index +(defun %sp-string= (string1 string2 start1 end1 start2 end2) + (let* ((end1 (or end1 + (length string1))) + (end2 (or end2 + (length string2))) + (len1 (- end1 start1)) + (len2 (- end2 start2))) + (declare (fixnum len1 len2 + end1 end2)) + (cond + ((= len1 len2) + (do ((index1 start1 (1+ index1)) + (index2 start2 (1+ index2))) + ((= index1 end1) t) + (declare (fixnum index1 index2)) + (let ((char1 (schar string1 index1)) + (char2 (schar string2 index2))) + (if (char/= char1 char2) + (return nil)))))))) diff --git a/src/code/misc-aliens.lisp b/src/code/misc-aliens.lisp index c67abb403b..140a7f2696 100644 --- a/src/code/misc-aliens.lisp +++ b/src/code/misc-aliens.lisp @@ -12,17 +12,56 @@ (in-package "SB-IMPL") ;;; Declare each of the free space pointers (except dynamic) as an alien var +;;; with darwin-jit, READ-ONLY-SPACE-START is a constant from genesis +;;; Maybe this whole file should go in sb-kernel to avoid sb-kernel:: +#-darwin-jit +(define-alien-variable ("READ_ONLY_SPACE_START" sb-vm:read-only-space-start) sb-kernel::os-vm-size-t) (define-alien-variable ("read_only_space_free_pointer" sb-vm:*read-only-space-free-pointer*) system-area-pointer) + +;;; STATIC-SPACE-START is a constant from genesis (define-alien-variable ("static_space_free_pointer" sb-vm:*static-space-free-pointer*) system-area-pointer) +(define-alien-variable ("DYNAMIC_SPACE_START" sb-vm:dynamic-space-start) sb-kernel::os-vm-size-t) +;;; Dynamic doesn't really have a "free pointer" but it's the upper bound on space usage. +(declaim (inline dynamic-space-free-pointer)) +(defun dynamic-space-free-pointer () + (sap+ (int-sap sb-vm:dynamic-space-start) + ;; not sure why next_free_page is 'sword_t' instead of 'uword_t' ! + (truly-the (signed-byte 64) + (* (extern-alien "next_free_page" signed) sb-vm:gencgc-page-bytes)))) + +#+immobile-space +(progn +(define-symbol-macro sb-vm:alien-linkage-table-space-start + (extern-alien "ALIEN_LINKAGE_TABLE_SPACE_START" unsigned)) +(define-alien-variable ("TEXT_SPACE_START" sb-vm:text-space-start) unsigned-long)) + +#+darwin-jit +(define-alien-variable ("static_code_space_free_pointer" sb-vm:*static-code-space-free-pointer*) + system-area-pointer) + (declaim (inline memmove)) -(define-alien-routine ("memmove" memmove) void +(define-alien-routine ("memmove" memmove) void ; BUG: technically returns void* (dest (* char)) (src (* char)) - (n unsigned-int)) + (n sb-unix::size-t)) + +(defun copy-ub8-to-system-area (src src-offset dst dst-offset length) + (with-pinned-objects (src) + (memmove (sap+ dst dst-offset) (sap+ (vector-sap src) src-offset) length)) + (values)) + +(defun copy-ub8-from-system-area (src src-offset dst dst-offset length) + (with-pinned-objects (dst) + (memmove (sap+ (vector-sap dst) dst-offset) (sap+ src src-offset) length)) + (values)) + +(defun system-area-ub8-copy (src src-offset dst dst-offset length) + (memmove (sap+ dst dst-offset) (sap+ src src-offset) length) + (values)) (define-alien-routine ("os_get_errno" get-errno) int) (setf (documentation 'get-errno 'function) @@ -36,3 +75,16 @@ #+win32 (defun strerror (&optional (errno (sb-win32:get-last-error))) (sb-win32:format-system-message errno)) + +;;; This gives you a way to call the low-level debugger in situations +;;; where something is broken, though the REPL works. One example is that +;;; when the cold core first starts up, you can't compile alien accessors, +;;; so an alien-funcall at the REPL would fail thusly: +;;; 0: ("undefined function" ...) ; EVAL-IN-NATIVE-ENVIRONMENT +;;; 1: (EVAL (LAMBDA (SB-ALIEN::SAP SB-ALIEN::OFFSET IGNORE) ...)) +;;; 2: (SB-ALIEN::COERCE-TO-INTERPRETED-FUNCTION (LAMBDA (...))) +;;; 3: (SB-ALIEN-INTERNALS:%ALIEN-VALUE #.(SB-SYS:INT-SAP #X50000BB0) ...) +;;; +;;; or more generally, the compiler could be messed up for whatever reason. +(defun sb-vm:ldb-monitor () + (alien-funcall (extern-alien "ldb_monitor" (function void)))) diff --git a/src/code/misc.lisp b/src/code/misc.lisp index 3410737eae..aa5c6e94fb 100644 --- a/src/code/misc.lisp +++ b/src/code/misc.lisp @@ -12,11 +12,9 @@ (in-package "SB-IMPL") -(defun sb-xc:lisp-implementation-type () +(defun lisp-implementation-type () "SBCL") -(defun sb-xc:lisp-implementation-version () - ;; Read the version file once and once only - #+sb-xc-host #.(sb-cold:read-from-file "version.lisp-expr") - #-sb-xc-host #.(sb-xc:lisp-implementation-version)) - +(defun lisp-implementation-version () + #+sb-xc-host #.sb-cold:*target-sbcl-version* + #-sb-xc-host #.(lisp-implementation-version)) diff --git a/src/code/module.lisp b/src/code/module.lisp index d36c6c4cc8..2a7e4f51ba 100644 --- a/src/code/module.lisp +++ b/src/code/module.lisp @@ -82,8 +82,9 @@ (merge-pathnames (make-pathname :directory (list :relative "contrib") :name filesys-name) - (truename (or (sbcl-homedir-pathname) - (return-from module-provide-contrib nil))))) + ;; DO NOT CALL TRUENAME HERE. YOU SHOULD NOT NEED THAT. + (or (sbcl-homedir-pathname) + (return-from module-provide-contrib nil)))) (fasl-path (merge-pathnames (make-pathname :type *fasl-file-type*) unadorned-path)) @@ -93,9 +94,24 @@ ;; be removed by the time we get round to trying to load it. ;; Maybe factor out the logic in the LOAD guesser as to which file ;; was meant, so that we can use it here on open streams instead? - (let ((file (or (probe-file fasl-path) - (probe-file unadorned-path) - (probe-file lisp-path)))) + ;; + ;; Prefer the untruename as the argument to give to LOAD, + ;; because users need to see (in backtraces and similar) the pathnames + ;; actually handed off to the filesystem calls, like: + ;; ... #P"blaze-out/k8-fastbuild/bin/third_party/lisp/sbcl/binary-distribution/k8/sbcl/bin/../lib/sbcl/contrib/sb-md5.fasl" + ;; and not names that have been obtained through readlink like + ;; ... #P"/build/cas/081/081f9f05e4af917b63b6ccf7453e4565fc66587a093a45fb1c6dbe64e8c8ad58_0100b65b" + ;; as the latter can not be reverse-engineered to a source file + ;; except possibly by much trial and error. + ;; + ;; If the idea of using PROBE-FILE was to get the newest version + ;; on a versioned file system, I don't see how it helps to truenameize early, + ;; because as per the "possible race" cited above, there may be an even newer version + ;; when you call LOAD, or it may go away. Aside from ensuring existence, + ;; was there any benefit to using the result of PROBE-FILE? + (let ((file (cond ((probe-file fasl-path) fasl-path) + ((probe-file unadorned-path) unadorned-path) + ((probe-file lisp-path) lisp-path)))) (when file (handler-bind (((or style-warning package-at-variance) #'muffle-warning)) diff --git a/src/code/ntrace.lisp b/src/code/ntrace.lisp index 369af95a38..d21ffa4637 100644 --- a/src/code/ntrace.lisp +++ b/src/code/ntrace.lisp @@ -17,52 +17,97 @@ ;;;; utilities -;;; Given a function name, a function or a macro name, return the raw -;;; definition and some information. "Raw" means that if the result is -;;; a closure, we strip off the closure and return the bare code. The -;;; second value is T if the argument was a function name. The third -;;; value is one of :COMPILED, :COMPILED-CLOSURE, :INTERPRETED, -;;; :INTERPRETED-CLOSURE and :FUNCALLABLE-INSTANCE. -(defun trace-fdefinition (x) - (flet ((get-def () - (if (valid-function-name-p x) - (if (fboundp x) - (fdefinition x) - (warn "~/sb-ext:print-symbol-with-prefix/ is ~ - undefined, not tracing." x)) - (warn "~S is not a valid function name, not tracing." x)))) - (multiple-value-bind (res named-p) - (typecase x - (symbol - (cond ((special-operator-p x) - (warn "~S is a special operator, not tracing." x)) - ((macro-function x)) - (t - (values (get-def) t)))) - (function - x) - (t - (values (get-def) t))) - (typecase res - (closure - (values (%closure-fun res) named-p :compiled-closure)) - (funcallable-instance - (values res named-p :funcallable-instance)) - ;; FIXME: What about SB-KERNEL:INTERPRETED-FUNCTION -- it gets picked off - ;; by the FIN above, is that right? - (t - (values res named-p :compiled)))))) +;;; Given X -- a function object or an s-expression naming a global function, +;;; local function, method, macro or compiler-macro -- return the following +;;; values: +;;; * a function object suitable for introspection via +;;; SB-DI:FUN-DEBUG-FUN. For local functions, their parent function is +;;; returned. For methods, their generic function is returned, unless +;;; IF-METHOD is :FAST-METHOD, in which case their respective +;;; SB-PCL::FAST-METHOD function is returned. +;;; * The function's BLOCK name, useful for looking up local functions. +;;; * A keyword symbol describing what X denotes: :ANONYMOUS-FUNCTION, +;;; :FUNCTION, :LOCAL-FUNCTION, :METHOD, :MACRO-FUNCTION. +;;; * [For local functions only] A local name suitable for SB-DI:FUN-DEBUG-FUN +;;; lookup. +(defun %trace-fdefinition (x &key (if-method :gf) definition) + (typecase x + (function + (values x nil :anonymous-function)) + ((cons (eql compiler-macro) (cons t null)) + (let ((fun (or definition (compiler-macro-function (second x))))) + (if fun + (values fun (second x) :compiler-macro) + (warn "~S is undefined, not tracing." x)))) + ((cons (eql method)) ; (METHOD name qualifiers (specializers*)) + (assert (null definition)) + (multiple-value-bind (gf block-name) + (%trace-fdefinition (second x)) + (when gf + (if (find-method gf (butlast (cddr x)) (car (last x)) nil) + (ecase if-method + (:fast-method + (%trace-fdefinition `(sb-pcl::fast-method ,@(rest x)))) + (:gf + (values gf block-name :method))) + (warn "~S not found, not tracing." x))))) + ((cons (member flet labels)) ; ({FLET,LABELS} name :IN outer-function) + (destructuring-bind (flet/labels name &key in) x + (multiple-value-bind (fun block-name) + (%trace-fdefinition in :if-method :fast-method :definition definition) + (when fun + (let ((local-name `(,flet/labels ,name :in ,block-name))) + (if (sb-di:fun-debug-fun fun :local-name local-name) + (values fun nil :local-function local-name) + (warn "~S not found, not tracing." x))))))) + ((and symbol (satisfies special-operator-p)) + (warn "~S is a special operator, not tracing." x)) + ((and symbol (satisfies macro-function)) + (values (or definition (macro-function x)) x :macro-function)) + (t + (multiple-value-bind (valid block-name) + (valid-function-name-p x) + (cond ((not valid) + (warn "~S is not a valid function name, not tracing." x)) + ((fboundp x) + (values (or definition (fdefinition x)) block-name :function)) + (t + (warn "~/sb-ext:print-symbol-with-prefix/ is ~ + undefined, not tracing." x))))))) + +(defun trace-fdefinition (x &optional definition) + (multiple-value-bind (fun block-name kind local-name) + (%trace-fdefinition x :definition definition) + (declare (ignore block-name)) + (values fun kind local-name))) + +(defun retrace-local-funs (fname &optional new-value) + (dolist (local (gethash fname *traced-locals*)) + (let ((trace-info (gethash local *traced-funs*))) + (untrace-1 local) + (trace-1 local trace-info new-value)))) ;;; When a function name is redefined, and we were tracing that name, ;;; then untrace the old definition and trace the new one. -(defun trace-redefined-update (fname new-value) - (when (fboundp fname) - (let* ((fun (trace-fdefinition fname)) - (info (gethash fun *traced-funs*))) - (when (and info (trace-info-named info)) - (untrace-1 fname) - (trace-1 fname info new-value))))) -(push #'trace-redefined-update *setf-fdefinition-hook*) +(defun maybe-retrace (name new-value) + (let ((info (gethash name *traced-funs*))) + (when info + (untrace-1 name) + (trace-1 name info new-value)) + (retrace-local-funs name new-value))) + +(defun maybe-retrace-function (name new-value) + (when (fboundp name) + (maybe-retrace name new-value))) + +(push #'maybe-retrace-function *setf-fdefinition-hook*) +(push #'maybe-retrace-function *setf-macro-function-hook*) + +(defun maybe-retrace-compiler-macro (name new-value) + (when (compiler-macro-function name) + (maybe-retrace `(compiler-macro ,name) new-value))) + +(push #'maybe-retrace-compiler-macro *setf-compiler-macro-function-hook*) ;;; Annotate a FORM to evaluate with pre-converted functions. FORM is ;;; really a cons (EXP . FUNCTION). LOC is the code location to use @@ -106,13 +151,16 @@ (format t "~V,0@T~W: " indent depth))) ;;; Return true if any of the NAMES appears on the stack below FRAME. -(defun trace-wherein-p (frame names) - (do ((frame (sb-di:frame-down frame) (sb-di:frame-down frame))) - ((not frame) nil) - (when (member (sb-di:debug-fun-name (sb-di:frame-debug-fun frame)) - names - :test #'equal) - (return t)))) +(defun trace-wherein-p (encapsulated frame names) + ;; When tracing without encapsulation (i.e. when using breakpoints), + ;; FRAME points to the function being traced, so skip it. + (let ((initial-frame (if encapsulated frame (sb-di:frame-down frame)))) + (do ((frame initial-frame (sb-di:frame-down frame))) + ((not frame) nil) + (when (member (sb-di:debug-fun-name (sb-di:frame-debug-fun frame)) + names + :test #'equal) + (return t))))) ;;; Handle PRINT and PRINT-AFTER options. (defun trace-print (frame forms &rest args) @@ -161,7 +209,9 @@ (defun trace-start-breakpoint-fun (info) (let (conditionp) (values - (lambda (frame bpt &rest args) + ;; HOOK-ARGS holds the function arguments when tracing via + ;; encapsulation and but is NIL when tracing via breakpoints. + (lambda (frame bpt &rest hook-args) (declare (ignore bpt)) (discard-invalid-entries frame) (let ((condition (trace-info-condition info)) @@ -169,32 +219,40 @@ (setq conditionp (and (not *in-trace*) (or (not condition) - (apply (cdr condition) frame args)) + (apply (cdr condition) frame hook-args)) (or (not wherein) - (trace-wherein-p frame wherein))))) + (trace-wherein-p (trace-info-encapsulated info) frame wherein))))) (when conditionp (with-standard-io-syntax (let ((*print-readably* nil) (*current-level-in-print* 0) (*standard-output* (make-string-output-stream)) (*in-trace* t)) - (ecase (trace-info-report info) + (case (trace-info-report info) (trace (fresh-line) (print-trace-indentation) (if (trace-info-encapsulated info) (prin1 `(,(trace-info-what info) - ,@(mapcar #'ensure-printable-object args))) + ,@(mapcar #'ensure-printable-object hook-args))) (print-frame-call frame *standard-output*)) (terpri) - (apply #'trace-print frame (trace-info-print info) args)) + (apply #'trace-print frame (trace-info-print info) hook-args)) ((nil) - (apply #'trace-print-unadorned frame (trace-info-print info) args))) + (apply #'trace-print-unadorned frame (trace-info-print info) hook-args)) + (t + (funcall (trace-info-report info) + (count-if #'cdr *traced-entries*) + (trace-info-what info) :enter frame + (if (trace-info-encapsulated info) + hook-args + (nth-value 1 (frame-call frame)))) + (apply #'trace-print-unadorned frame (trace-info-print info) hook-args))) (write-sequence (get-output-stream-string *standard-output*) *trace-output*) (finish-output *trace-output*)) (apply #'trace-maybe-break info (trace-info-break info) "before" - frame args)))) + frame hook-args)))) (lambda (frame cookie) (declare (ignore frame)) (push (cons cookie conditionp) *traced-entries*))))) @@ -207,13 +265,13 @@ ;;; succeeded before printing anything. (declaim (ftype (function (trace-info) function) trace-end-breakpoint-fun)) (defun trace-end-breakpoint-fun (info) - (lambda (frame bpt values cookie) - (declare (ignore bpt)) + (lambda (frame bpt-or-nle values cookie) (unless (eq cookie (caar *traced-entries*)) (setf *traced-entries* (member cookie *traced-entries* :key #'car))) - (let ((entry (pop *traced-entries*))) + (let ((entry (pop *traced-entries*)) + (non-local-exit (eq bpt-or-nle :nle))) (when (and (not (trace-info-untraced info)) (or (cdr entry) (let ((cond (trace-info-condition-after info))) @@ -221,21 +279,34 @@ (let ((*current-level-in-print* 0) (*standard-output* (make-string-output-stream)) (*in-trace* t)) - (ecase (trace-info-report info) + (case (trace-info-report info) (trace (fresh-line) (let ((*print-pretty* t)) (pprint-logical-block (*standard-output* nil) (print-trace-indentation) (pprint-indent :current 2) - (format t "~S returned" (trace-info-what info)) - (dolist (v values) - (write-char #\space) - (pprint-newline :linear) - (prin1 (ensure-printable-object v)))) + (cond (non-local-exit + (format t "~S exited non-locally" (trace-info-what info))) + (t + (format t "~S returned" (trace-info-what info)) + (dolist (v values) + (write-char #\space) + (pprint-newline :linear) + (prin1 (ensure-printable-object v)))))) (terpri)) - (apply #'trace-print frame (trace-info-print-after info) values)) + (unless non-local-exit + (apply #'trace-print frame (trace-info-print-after info) values))) ((nil) + (unless non-local-exit + (apply #'trace-print-unadorned frame (trace-info-print-after info) values))) + (t + (funcall (trace-info-report info) + (count-if #'cdr *traced-entries*) + (trace-info-what info) + (if non-local-exit :non-local-exit :exit) + frame + values) (apply #'trace-print-unadorned frame (trace-info-print-after info) values))) (write-sequence (get-output-stream-string *standard-output*) *trace-output*) @@ -253,8 +324,15 @@ (apply #'funcall start frame nil args) (let ((*traced-entries* *traced-entries*)) (funcall cookie frame nil) - (let ((vals (multiple-value-list (apply function args)))) - (funcall (trace-end-breakpoint-fun info) frame nil vals nil) + (let* ((non-local-exit '#:nle) + (vals non-local-exit)) + (unwind-protect + (setq vals (multiple-value-list (apply function args))) + (funcall (trace-end-breakpoint-fun info) + frame + (if (eq vals non-local-exit) :nle nil) + (if (eq vals non-local-exit) nil vals) + nil)) (values-list vals)))))) ;;; This function is like TRACE-CALL above, but munges the method @@ -269,8 +347,15 @@ (apply #'funcall start frame nil (funcall transform args)) (let ((*traced-entries* *traced-entries*)) (funcall cookie frame nil) - (let ((vals (multiple-value-list (apply function args)))) - (funcall (trace-end-breakpoint-fun info) frame nil vals nil) + (let* ((non-local-exit '#:nle) + (vals non-local-exit)) + (unwind-protect + (setq vals (multiple-value-list (apply function args))) + (funcall (trace-end-breakpoint-fun info) + frame + (if (eq vals non-local-exit) :nle nil) + (if (eq vals non-local-exit) nil vals) + nil)) (values-list vals))))))) ;;; Trace one function according to the specified options. We copy the @@ -280,35 +365,30 @@ ;;; If non-null, DEFINITION is the new definition of a function that ;;; we are automatically retracing. (defun trace-1 (function-or-name info &optional definition) - (multiple-value-bind (fun named kind) - (if definition - (values definition t - (nth-value 2 (trace-fdefinition definition))) - (trace-fdefinition function-or-name)) + (multiple-value-bind (fun kind local-name) + (trace-fdefinition function-or-name definition) (when fun - (when (gethash fun *traced-funs*) + (when (closurep fun) + (setq fun (%closure-fun fun)) + (when (eq (trace-info-encapsulated info) :default) + (warn "tracing shared code for ~S:~% ~S" function-or-name fun))) + (when (gethash function-or-name *traced-funs*) (warn "~S is already TRACE'd, untracing it first." function-or-name) - (untrace-1 fun)) - (let* ((debug-fun (sb-di:fun-debug-fun fun)) + (untrace-1 function-or-name)) + (let* ((debug-fun (sb-di:fun-debug-fun fun :local-name local-name)) (encapsulated - (if (eq (trace-info-encapsulated info) :default) - (ecase kind - (:compiled nil) - (:compiled-closure - (unless (functionp function-or-name) - (warn "tracing shared code for ~S:~% ~S" - function-or-name - fun)) - nil) - ((:interpreted :interpreted-closure :funcallable-instance) - t)) - (trace-info-encapsulated info))) + (ecase kind + ((:function :method) + (if (eq (trace-info-encapsulated info) :default) + (funcallable-instance-p fun) + (trace-info-encapsulated info))) + ((:anonymous-function :compiler-macro :macro-function :local-function) + nil))) (loc (if encapsulated :encapsulated (sb-di:debug-fun-start-location debug-fun))) (info (make-trace-info :what function-or-name - :named named :encapsulated encapsulated :wherein (trace-info-wherein info) :methods (trace-info-methods info) @@ -330,12 +410,11 @@ (cond (encapsulated - (unless named - (error "can't use encapsulation to trace anonymous function ~S" - fun)) - (encapsulate function-or-name 'trace - (lambda (function &rest args) - (apply #'trace-call info function args)))) + (if (eq kind :method) + (reinitialize-instance fun) + (encapsulate function-or-name 'trace + (lambda (function &rest args) + (apply #'trace-call info function args))))) (t (multiple-value-bind (start-fun cookie-fun) (trace-start-breakpoint-fun info) @@ -356,7 +435,10 @@ (sb-di:activate-breakpoint start) (sb-di:activate-breakpoint end))))) - (setf (gethash fun *traced-funs*) info)) + (when (eq kind :local-function) + (push function-or-name + (gethash (fourth function-or-name) *traced-locals*))) + (setf (gethash function-or-name *traced-funs*) info)) (when (and (typep fun 'generic-function) (trace-info-methods info) @@ -370,9 +452,7 @@ ;; requested, because the function objects themselves are ;; stored in the method object; (b) when the method in ;; question is particularly simple, when the method - ;; functionality is in the dfun. See src/pcl/env.lisp for a - ;; stub implementation of encapsulating through a - ;; traced-method class. + ;; functionality is in the dfun. (trace-1 mf info) (when (typep mf 'sb-pcl::%method-function) (trace-1 (sb-pcl::%method-function-fast-function mf) info))))) @@ -442,12 +522,16 @@ (current (parse-trace-options specs global-options))) (loop (when (endp current) (return)) - (let ((name (pop current)) - (options (copy-trace-info global-options))) + (let* ((name (pop current)) + (fn (when (eq name :function) + (pop current))) + (options (copy-trace-info global-options))) + ;; parse options for the current spec. + (setq current (parse-trace-options current options)) (cond ((eq name :function) (let ((temp (gensym))) - (binds `(,temp ,(pop current))) + (binds `(,temp ,fn)) (forms `(trace-1 ,temp ',options)))) ((and (keywordp name) (not (or (fboundp name) (macro-function name)))) @@ -463,10 +547,12 @@ (let ((setf-name `(setf ,symbol))) (when (fboundp setf-name) (forms `(trace-1 ',setf-name ',options)))))))) - ;; special-case METHOD: it itself is not a general function - ;; name symbol, but it (at least here) designates one of a - ;; pair of such. - ((and (consp name) (eq (car name) 'method)) + ;; special-case METHOD (without encapsulation): it itself + ;; is not a general function name symbol, but it (at least + ;; here) designates one of a pair of such. + ((and (consp name) + (eq (car name) 'method) + (not (trace-info-encapsulated options))) (when (fboundp (list* 'sb-pcl::slow-method (cdr name))) (forms `(trace-1 ',(list* 'sb-pcl::slow-method (cdr name)) ',options))) @@ -474,9 +560,7 @@ (forms `(trace-1 ',(list* 'sb-pcl::fast-method (cdr name)) ',options)))) (t - (forms `(trace-1 ',name ',options)))) - (setq current (parse-trace-options current options))))) - + (forms `(trace-1 ',name ',options))))))) `(let ,(binds) (remove nil (list ,@(forms)))))) @@ -492,9 +576,18 @@ functions are called. In its simplest form: (TRACE NAME-1 NAME-2 ...) -The NAMEs are not evaluated. Each may be a symbol, denoting an -individual function, or a string, denoting all functions fbound to -symbols whose home package is the package with the given name. +The NAMEs are not evaluated. Each may be one of the following: + * SYMBOL, denoting a function or macro. + * FNAME, a valid function name, denoting a function. + * (METHOD FNAME QUALIFIERS* (SPECIALIZERS*)) denoting a method. + * (COMPILER-MACRO SYMBOL) denoting a compiler macro. + * (LABELS FNAME :IN OUTER-NAME) or (FLET FNAME :IN OUTER-NAME) + denoting a local function where OUTER-NAME may be any of the + previous names for functions, macros, methods or compiler macros. + Tracing local functions may require DEBUG policy 3 to inhibit + inlining. + * STRING denoting all functions fbound to symbols whose home package + is the package with the given name. Options allow modification of the default behavior. Each option is a pair of an option keyword and a value form. Global options are @@ -514,7 +607,12 @@ The following options are defined: If Report-Type is TRACE (the default) then information is reported by printing immediately. If Report-Type is NIL, then the only effect of the trace is to execute other - options (e.g. PRINT or BREAK). + options (e.g. PRINT or BREAK). Otherwise, Report-Type is + treated as a function designator and, for each trace event, + funcalled with 5 arguments: trace depth (a non-negative + integer), a function name or a function object, a + keyword (:ENTER, :EXIT or :NON-LOCAL-EXIT), a stack frame, and + a list of values (arguments or return values). :CONDITION Form :CONDITION-AFTER Form @@ -576,28 +674,32 @@ the N-th value returned by the function." ;;; Untrace one function. (defun untrace-1 (function-or-name) - (let* ((fun (trace-fdefinition function-or-name)) - (info (when fun (gethash fun *traced-funs*)))) - (cond - ((and fun (not info)) - (warn "Function is not TRACEd: ~S" function-or-name)) - ((not fun) - ;; Someone has FMAKUNBOUND it. - (let ((table *traced-funs*)) - (with-locked-system-table (table) - (maphash (lambda (fun info) - (when (equal function-or-name (trace-info-what info)) - (remhash fun table))) - table)))) - (t - (cond - ((trace-info-encapsulated info) - (unencapsulate (trace-info-what info) 'trace)) - (t - (sb-di:delete-breakpoint (trace-info-start-breakpoint info)) - (sb-di:delete-breakpoint (trace-info-end-breakpoint info)))) - (setf (trace-info-untraced info) t) - (remhash fun *traced-funs*))))) + (multiple-value-bind (fun kind) + (trace-fdefinition function-or-name) + (when fun + (let ((info (gethash function-or-name *traced-funs*))) + (cond ((and fun (not info)) + (warn "Function is not TRACEd: ~S" function-or-name)) + (t + (cond + ((trace-info-encapsulated info) + (if (eq kind :method) + (reinitialize-instance fun) + (unencapsulate (trace-info-what info) 'trace))) + (t + (sb-di:delete-breakpoint (trace-info-start-breakpoint info)) + (sb-di:delete-breakpoint (trace-info-end-breakpoint info)))) + (setf (trace-info-untraced info) t) + (when (eq kind :local-function) + (let ((table *traced-locals*) + (outer (fourth function-or-name))) + (with-system-mutex ((hash-table-lock table)) + (let* ((locals (gethash outer table)) + (remaining (remove function-or-name locals :test #'equal))) + (if remaining + (setf (gethash outer table) remaining) + (remhash outer table)))))))))) + (remhash function-or-name *traced-funs*))) ;;; Untrace all traced functions. (defun untrace-all () @@ -621,8 +723,9 @@ the N-th value returned by the function." functions when called with no arguments." (if specs `(progn - ,@(loop while specs - for name = (pop specs) + ,@(loop for name = (car specs) + while specs + do (pop specs) collect (cond ((eq name :function) `(untrace-1 ,(pop specs))) ((stringp name) @@ -644,21 +747,45 @@ functions when called with no arguments." (defun set-tracing-bit (code bit) (declare (ignorable code bit)) - #+64-bit ; there are no bits to spare in a 32-bit header word + ;; there are no bits to spare in a 32-bit header word, + ;; and with darwin-jit it's not worth the extra complexity + #+(and 64-bit (not darwin-jit)) (with-pinned-objects (code) (let ((sap (int-sap (get-lisp-obj-address code)))) ;; NB: This is not threadsafe on machines that don't promise that ;; stores to single bytes are atomic. - (setf (sap-ref-8 sap #+little-endian (- 1 sb-vm:other-pointer-lowtag) - #+big-endian (- 6 sb-vm:other-pointer-lowtag)) + (setf (sap-ref-8 sap #+little-endian (- 2 sb-vm:other-pointer-lowtag) + #+big-endian (- 5 sb-vm:other-pointer-lowtag)) bit) - ;; touch the card mark + ;; touch the card mark - WHY??? (setf (code-header-ref code 1) (code-header-ref code 1))))) ;;; FIXME: Symbol is lost by accident (eval-when (:compile-toplevel :load-toplevel) (export 'sb-int::encapsulate-funobj 'sb-int)) +;;; Suppose you want to trace function #'FOO no matter how a caller +;;; references it (maybe capturing #'FOO in a variable before asking +;;; to trace FOO). We can do that without resorting to breakpoints, +;;; by replacing the simple-fun entry point in the header of the code +;;; that contains FOO such that it points to a different simple-fun +;;; outside of itself. That other simple-fun calls the tracing routine +;;; and then the real FOO. An entry point can't be replaced with a +;;; closure, because CLOSURE and SIMPLE-FUN are not fungible. +;;; +;;; +-------------------------+ +--------------------+ +;;; | codeblob foo | | codeblob "TRACER" | +;;; | ... | | | +;;; | ... boxed data ... | | boxed word: #'foo | -> the "real" FOO +;;; | ... | | | +;;; | ... unboxed data ... | | | +;;; | ... | +--------------------+ +;;; | simple-fun-header #'foo | --> | call trace helper | +;;; | redirected entry point | --/ +--------------------+ +;;; | instructions of #'FOO | +;;; | ... | +;;; +-------------------------+ + (defun compile-funobj-encapsulation (wrapper info actual-fun) #+(or x86 x86-64) (let ((code @@ -700,68 +827,60 @@ functions when called with no arguments." (defun encapsulate-funobj (traced-fun &optional fdefn) (declare (type (or simple-fun closure) traced-fun)) (let* ((proxy-fun - (typecase traced-fun - (simple-fun - ;; Generate a "closure" (that closes over nothing) which calls the - ;; original underlying function so that the original's entry point - ;; can be redirected to a tracing wrapper, which will produce trace - ;; output and invoke the closure which invokes the original fun. - #+x86-64 - (let ((closure (%primitive sb-vm::make-closure nil 0 nil))) - (with-pinned-objects (closure traced-fun) - (setf (sap-ref-word (int-sap (get-lisp-obj-address closure)) - (- sb-vm:n-word-bytes sb-vm:fun-pointer-lowtag)) - ;; Disregard the fun-self slot of fun. - (+ (get-lisp-obj-address traced-fun) - (- sb-vm:fun-pointer-lowtag) - (ash sb-vm:simple-fun-insts-offset sb-vm:word-shift)))) - closure) - #-x86-64 (%primitive sb-vm::make-closure traced-fun nil 0 nil)) - (closure - ;; Same as above, but simpler - the original closure will redirect - ;; to the tracing wraper, which will invoke a new closure that is - ;; behaviorally identical to the original closure. - (sb-impl::copy-closure traced-fun)))) + (typecase traced-fun + (simple-fun + ;; Generate a "closure" (that closes over nothing) which calls the + ;; original underlying function so that the original's entry point + ;; can be redirected to a tracing wrapper, which will produce trace + ;; output and invoke the closure which invokes the original fun. + #+(or x86-64 arm64) + (with-pinned-objects ((%closure-fun traced-fun)) + (sb-vm::%alloc-closure 0 (sb-vm::%closure-callee traced-fun))) + #-(or x86-64 arm64) (%primitive sb-vm::make-closure traced-fun nil 0 nil)) + (closure + ;; Same as above, but simpler - the original closure will redirect + ;; to the tracing wraper, which will invoke a new closure that is + ;; behaviorally identical to the original closure. + (sb-impl::copy-closure traced-fun)))) (info (make-trace-info :what (cond (fdefn (fdefn-name fdefn)) (t (%fun-name traced-fun))) :encapsulated t - :named t :report 'trace)) (tracing-wrapper - (compile-funobj-encapsulation 'trace-call info proxy-fun))) + (compile-funobj-encapsulation 'trace-call info proxy-fun))) (with-pinned-objects (tracing-wrapper) - (let (#+(or x86 x86-64) + (let (#+(or x86 x86-64 arm64) (tracing-wrapper-entry - (+ (get-lisp-obj-address tracing-wrapper) - (- sb-vm:fun-pointer-lowtag) - (ash sb-vm:simple-fun-insts-offset sb-vm:word-shift)))) + (+ (get-lisp-obj-address tracing-wrapper) + (- sb-vm:fun-pointer-lowtag) + (ash sb-vm:simple-fun-insts-offset sb-vm:word-shift)))) (typecase traced-fun - (simple-fun - (let ((code (fun-code-header traced-fun))) - (set-tracing-bit code code-is-traced) - (let ((fun-header-word-index - (with-pinned-objects (code) - (let ((delta (- (get-lisp-obj-address traced-fun) - (get-lisp-obj-address code) - sb-vm:fun-pointer-lowtag - (- sb-vm:other-pointer-lowtag)))) - (aver (not (logtest delta sb-vm:lowtag-mask))) - (ash delta (- sb-vm:word-shift)))))) - ;; the entry point in CODE points to the tracing wrapper - (setf (code-header-ref code (1+ fun-header-word-index)) - #+(or x86 x86-64) (make-lisp-obj tracing-wrapper-entry) - #-(or x86 x86-64) tracing-wrapper)))) - (closure - (with-pinned-objects (traced-fun) - ;; redirect the original closure to the tracing wrapper - #+(or x86 x86-64) - (setf (sap-ref-word (int-sap (get-lisp-obj-address traced-fun)) - (- sb-vm:n-word-bytes sb-vm:fun-pointer-lowtag)) - tracing-wrapper-entry) - #-(or x86 x86-64) - (setf (sap-ref-lispobj (int-sap (get-lisp-obj-address traced-fun)) - (- sb-vm:n-word-bytes sb-vm:fun-pointer-lowtag)) - tracing-wrapper)))))) + (simple-fun + (let ((code (fun-code-header traced-fun))) + (set-tracing-bit code code-is-traced) + (let ((fun-header-word-index + (with-pinned-objects (code) + (let ((delta (- (get-lisp-obj-address traced-fun) + (get-lisp-obj-address code) + sb-vm:fun-pointer-lowtag + (- sb-vm:other-pointer-lowtag)))) + (aver (not (logtest delta sb-vm:lowtag-mask))) + (ash delta (- sb-vm:word-shift)))))) + ;; the entry point in CODE points to the tracing wrapper + (setf (code-header-ref code (1+ fun-header-word-index)) + #+(or x86 x86-64 arm64) (make-lisp-obj tracing-wrapper-entry) + #-(or x86 x86-64 arm64) tracing-wrapper)))) + (closure + (with-pinned-objects (traced-fun) + ;; redirect the original closure to the tracing wrapper + #+(or x86 x86-64 arm64) + (setf (sap-ref-word (int-sap (get-lisp-obj-address traced-fun)) + (- sb-vm:n-word-bytes sb-vm:fun-pointer-lowtag)) + tracing-wrapper-entry) + #-(or x86 x86-64 arm64) + (setf (sap-ref-lispobj (int-sap (get-lisp-obj-address traced-fun)) + (- sb-vm:n-word-bytes sb-vm:fun-pointer-lowtag)) + tracing-wrapper)))))) ;; Update fdefn's raw-addr slot to point to the tracing wrapper (when (and fdefn (eq (fdefn-fun fdefn) traced-fun)) (setf (fdefn-fun fdefn) tracing-wrapper)) diff --git a/src/code/number-dispatch.lisp b/src/code/number-dispatch.lisp new file mode 100644 index 0000000000..152bd84bb5 --- /dev/null +++ b/src/code/number-dispatch.lisp @@ -0,0 +1,227 @@ +;;;; This file contains the the NUMBER-DISPATCH macro + +;;;; This software is part of the SBCL system. See the README file for +;;;; more information. +;;;; +;;;; This software is derived from the CMU CL system, which was +;;;; written at Carnegie Mellon University and released into the +;;;; public domain. The software is in the public domain and is +;;;; provided with absolutely no warranty. See the COPYING and CREDITS +;;;; files for more information. + +(in-package "SB-KERNEL") + +(eval-when (:compile-toplevel :load-toplevel :execute) + +;;; Grovel an individual case to NUMBER-DISPATCH, augmenting RESULT +;;; with the type dispatches and bodies. Result is a tree built of +;;; alists representing the dispatching off each arg (in order). The +;;; leaf is the body to be executed in that case. + (defun parse-number-dispatch (vars result types var-types body) + ;; Shouldn't be necessary, but avoids a warning in certain lisps that + ;; seem to like to warn about self-calls in :COMPILE-TOPLEVEL situation. + (named-let parse-number-dispatch ((vars vars) (result result) (types types) + (var-types var-types) (body body)) + (cond ((null vars) + (unless (null types) (error "More types than vars.")) + (when (cdr result) + (error "Duplicate case: ~S." body)) + (setf (cdr result) + (sublis var-types body :test #'equal))) + ((null types) + (error "More vars than types.")) + (t + (flet ((frob (var type) + (parse-number-dispatch + (rest vars) + (or (assoc type (cdr result) :test #'equal) + (car (setf (cdr result) + (acons type nil (cdr result))))) + (rest types) + (acons `(dispatch-type ,var) type var-types) + body))) + (let ((type (first types)) + (var (first vars))) + (if (and (consp type) (eq (first type) 'foreach)) + (dolist (type (rest type)) + (frob var type)) + (frob var type)))))))) + +;;; our guess for the preferred order in which to do type tests +;;; (cheaper and/or more probable first.) + (defconstant-eqx +type-test-ordering+ + '(fixnum single-float double-float integer #+long-float long-float + sb-vm:signed-word word bignum + complex ratio) + #'equal) + +;;; Should TYPE1 be tested before TYPE2? + (defun type-test-order (type1 type2) + (let ((o1 (position type1 +type-test-ordering+)) + (o2 (position type2 +type-test-ordering+))) + (cond ((not o1) nil) + ((not o2) t) + (t + (< o1 o2))))) + +;;; Return an ETYPECASE form that does the type dispatch, ordering the +;;; cases for efficiency. +;;; Check for some simple to detect problematic cases where the caller +;;; used types that are not disjoint and where this may lead to +;;; unexpected behaviour of the generated form, for example making +;;; a clause unreachable, and throw an error if such a case is found. +;;; An example: +;;; (number-dispatch ((var1 integer) (var2 float)) +;;; ((fixnum single-float) a) +;;; ((integer float) b)) +;;; Even though the types are not reordered here, the generated form, +;;; basically +;;; (etypecase var1 +;;; (fixnum (etypecase var2 +;;; (single-float a))) +;;; (integer (etypecase var2 +;;; (float b)))) +;;; would fail at runtime if given var1 fixnum and var2 double-float, +;;; even though the second clause matches this signature. To catch +;;; this earlier than runtime we throw an error already here. + (defun generate-number-dispatch (vars error-tags cases) + ;; Shouldn't be necessary, but avoids a warning in certain lisps that + ;; seem to like to warn about self-calls in :COMPILE-TOPLEVEL situation. + (named-let generate-number-dispatch ((vars vars) (error-tags error-tags) (cases cases)) + (if vars + (let ((var (first vars)) + (cases (sort cases #'type-test-order :key #'car))) + (flet ((error-if-sub-or-supertype (type1 type2) + (when (or (subtypep type1 type2) + (subtypep type2 type1)) + (error "Types not disjoint: ~S ~S." type1 type2))) + (error-if-supertype (type1 type2) + (when (subtypep type2 type1) + (error "Type ~S ordered before subtype ~S." + type1 type2))) + (test-type-pairs (fun) + ;; Apply FUN to all (ordered) pairs of types from the + ;; cases. + (mapl (lambda (cases) + (when (cdr cases) + (let ((type1 (caar cases))) + (dolist (case (cdr cases)) + (funcall fun type1 (car case)))))) + cases))) + ;; For the last variable throw an error if a type is followed + ;; by a subtype, for all other variables additionally if a + ;; type is followed by a supertype. + (test-type-pairs (if (cdr vars) + #'error-if-sub-or-supertype + #'error-if-supertype))) + `((typecase ,var + ,@(mapcar (lambda (case) + `(,(first case) + ,@(generate-number-dispatch (rest vars) + (rest error-tags) + (cdr case)))) + cases) + (t (go ,(first error-tags)))))) + cases))) + + ) ; EVAL-WHEN + +;;; This is a vaguely case-like macro that does number cross-product +;;; dispatches. The Vars are the variables we are dispatching off of. +;;; The Type paired with each Var is used in the error message when no +;;; case matches. Each case specifies a Type for each var, and is +;;; executed when that signature holds. A type may be a list +;;; (FOREACH Each-Type*), causing that case to be repeatedly +;;; instantiated for every Each-Type. In the body of each case, any +;;; list of the form (DISPATCH-TYPE Var-Name) is substituted with the +;;; type of that var in that instance of the case. +;;; +;;; [Though it says "_any_ list", it's still an example of how not to perform +;;; incomplete lexical analysis within a macro imho. Let's say that the body +;;; code passes a lambda that happens name its args DISPATCH-TYPE and X. +;;; What happens? +;;; (macroexpand-1 '(number-dispatch ((x number)) +;;; ((float) (f x (lambda (dispatch-type x) (wat)))))) +;;; -> [stuff elided] +;;; (TYPECASE X (FLOAT (F X (LAMBDA FLOAT (WAT)))) +;;; +;;; So the NUMBER-DISPATCH macro indeed substituted for *any* appearance +;;; just like it says. I wonder if we could define DISPATCH-TYPE as macrolet +;;; that expands to the type for the current branch, so that it _must_ +;;; be in a for-evaluation position; but maybe I'm missing something?] +;;; +;;; As an alternate to a case spec, there may be a form whose CAR is a +;;; symbol. In this case, we apply the CAR of the form to the CDR and +;;; treat the result of the call as a list of cases. This process is +;;; not applied recursively. +;;; +;;; Be careful when using non-disjoint types in different cases for the +;;; same variable. Some uses will behave as intended, others not, as the +;;; variables are dispatched off sequentially and clauses are reordered +;;; for efficiency. Some, but not all, problematic cases are detected +;;; and lead to a compile time error; see GENERATE-NUMBER-DISPATCH above +;;; for an example. +(defmacro number-dispatch (var-specs &body cases) + (let ((res (list nil)) + (vars (mapcar #'car var-specs)) + (block (gensym))) + (dolist (case cases) + (if (symbolp (first case)) + (let ((cases (apply (symbol-function (first case)) (rest case)))) + (dolist (case cases) + (parse-number-dispatch vars res (first case) nil (rest case)))) + (parse-number-dispatch vars res (first case) nil (rest case)))) + + (collect ((errors) + (error-tags)) + (dolist (spec var-specs) + (let ((var (first spec)) + (type (second spec)) + (tag (gensym))) + (error-tags tag) + (errors tag) + (errors + (sb-c::internal-type-error-call var type)))) + + `(block ,block + (tagbody + (return-from ,block + ,@(generate-number-dispatch vars (error-tags) + (cdr res))) + ,@(errors)))))) + +;;;; binary operation dispatching utilities + +(eval-when (:compile-toplevel :execute #+sb-devel :load-toplevel) + +;;; Return NUMBER-DISPATCH forms for rational X float. +(defun float-contagion (op x y &optional (rat-types '(fixnum bignum ratio))) + `(((single-float single-float) (,op ,x ,y)) + (((foreach ,@rat-types) + (foreach single-float double-float #+long-float long-float)) + (,op (coerce ,x '(dispatch-type ,y)) ,y)) + (((foreach single-float double-float #+long-float long-float) + (foreach ,@rat-types)) + (,op ,x (coerce ,y '(dispatch-type ,x)))) + #+long-float + (((foreach single-float double-float long-float) long-float) + (,op (coerce ,x 'long-float) ,y)) + #+long-float + ((long-float (foreach single-float double-float)) + (,op ,x (coerce ,y 'long-float))) + (((foreach single-float double-float) double-float) + (,op (coerce ,x 'double-float) ,y)) + ((double-float single-float) + (,op ,x (coerce ,y 'double-float))))) + +;;; Return NUMBER-DISPATCH forms for bignum X fixnum. +(defun bignum-cross-fixnum (fix-op big-op) + `(((fixnum fixnum) (,fix-op x y)) + ((fixnum bignum) + (,big-op (make-small-bignum x) y)) + ((bignum fixnum) + (,big-op x (make-small-bignum y))) + ((bignum bignum) + (,big-op x y)))) + +) ; EVAL-WHEN diff --git a/src/code/numbers.lisp b/src/code/numbers.lisp index a43ae08b7e..8ff6282771 100644 --- a/src/code/numbers.lisp +++ b/src/code/numbers.lisp @@ -10,230 +10,13 @@ ;;;; files for more information. (in-package "SB-KERNEL") - -;;;; the NUMBER-DISPATCH macro - -(eval-when (:compile-toplevel :load-toplevel :execute) -;;; Grovel an individual case to NUMBER-DISPATCH, augmenting RESULT -;;; with the type dispatches and bodies. Result is a tree built of -;;; alists representing the dispatching off each arg (in order). The -;;; leaf is the body to be executed in that case. -(defun parse-number-dispatch (vars result types var-types body) - ;; Shouldn't be necessary, but avoids a warning in certain lisps that - ;; seem to like to warn about self-calls in :COMPILE-TOPLEVEL situation. - (named-let parse-number-dispatch ((vars vars) (result result) (types types) - (var-types var-types) (body body)) - (cond ((null vars) - (unless (null types) (error "More types than vars.")) - (when (cdr result) - (error "Duplicate case: ~S." body)) - (setf (cdr result) - (sublis var-types body :test #'equal))) - ((null types) - (error "More vars than types.")) - (t - (flet ((frob (var type) - (parse-number-dispatch - (rest vars) - (or (assoc type (cdr result) :test #'equal) - (car (setf (cdr result) - (acons type nil (cdr result))))) - (rest types) - (acons `(dispatch-type ,var) type var-types) - body))) - (let ((type (first types)) - (var (first vars))) - (if (and (consp type) (eq (first type) 'foreach)) - (dolist (type (rest type)) - (frob var type)) - (frob var type)))))))) - -;;; our guess for the preferred order in which to do type tests -;;; (cheaper and/or more probable first.) -(defconstant-eqx +type-test-ordering+ - '(fixnum single-float double-float integer #+long-float long-float - sb-vm:signed-word word bignum - complex ratio) - #'equal) - -;;; Should TYPE1 be tested before TYPE2? -(defun type-test-order (type1 type2) - (let ((o1 (position type1 +type-test-ordering+)) - (o2 (position type2 +type-test-ordering+))) - (cond ((not o1) nil) - ((not o2) t) - (t - (< o1 o2))))) - -;;; Return an ETYPECASE form that does the type dispatch, ordering the -;;; cases for efficiency. -;;; Check for some simple to detect problematic cases where the caller -;;; used types that are not disjoint and where this may lead to -;;; unexpected behaviour of the generated form, for example making -;;; a clause unreachable, and throw an error if such a case is found. -;;; An example: -;;; (number-dispatch ((var1 integer) (var2 float)) -;;; ((fixnum single-float) a) -;;; ((integer float) b)) -;;; Even though the types are not reordered here, the generated form, -;;; basically -;;; (etypecase var1 -;;; (fixnum (etypecase var2 -;;; (single-float a))) -;;; (integer (etypecase var2 -;;; (float b)))) -;;; would fail at runtime if given var1 fixnum and var2 double-float, -;;; even though the second clause matches this signature. To catch -;;; this earlier than runtime we throw an error already here. -(defun generate-number-dispatch (vars error-tags cases) - ;; Shouldn't be necessary, but avoids a warning in certain lisps that - ;; seem to like to warn about self-calls in :COMPILE-TOPLEVEL situation. - (named-let generate-number-dispatch ((vars vars) (error-tags error-tags) (cases cases)) - (if vars - (let ((var (first vars)) - (cases (sort cases #'type-test-order :key #'car))) - (flet ((error-if-sub-or-supertype (type1 type2) - (when (or (sb-xc:subtypep type1 type2) - (sb-xc:subtypep type2 type1)) - (error "Types not disjoint: ~S ~S." type1 type2))) - (error-if-supertype (type1 type2) - (when (sb-xc:subtypep type2 type1) - (error "Type ~S ordered before subtype ~S." - type1 type2))) - (test-type-pairs (fun) - ;; Apply FUN to all (ordered) pairs of types from the - ;; cases. - (mapl (lambda (cases) - (when (cdr cases) - (let ((type1 (caar cases))) - (dolist (case (cdr cases)) - (funcall fun type1 (car case)))))) - cases))) - ;; For the last variable throw an error if a type is followed - ;; by a subtype, for all other variables additionally if a - ;; type is followed by a supertype. - (test-type-pairs (if (cdr vars) - #'error-if-sub-or-supertype - #'error-if-supertype))) - `((typecase ,var - ,@(mapcar (lambda (case) - `(,(first case) - ,@(generate-number-dispatch (rest vars) - (rest error-tags) - (cdr case)))) - cases) - (t (go ,(first error-tags)))))) - cases))) - -) ; EVAL-WHEN - -;;; This is a vaguely case-like macro that does number cross-product -;;; dispatches. The Vars are the variables we are dispatching off of. -;;; The Type paired with each Var is used in the error message when no -;;; case matches. Each case specifies a Type for each var, and is -;;; executed when that signature holds. A type may be a list -;;; (FOREACH Each-Type*), causing that case to be repeatedly -;;; instantiated for every Each-Type. In the body of each case, any -;;; list of the form (DISPATCH-TYPE Var-Name) is substituted with the -;;; type of that var in that instance of the case. -;;; -;;; [Though it says "_any_ list", it's still an example of how not to perform -;;; incomplete lexical analysis within a macro imho. Let's say that the body -;;; code passes a lambda that happens name its args DISPATCH-TYPE and X. -;;; What happens? -;;; (macroexpand-1 '(number-dispatch ((x number)) -;;; ((float) (f x (lambda (dispatch-type x) (wat)))))) -;;; -> [stuff elided] -;;; (TYPECASE X (FLOAT (F X (LAMBDA FLOAT (WAT)))) -;;; -;;; So the NUMBER-DISPATCH macro indeed substituted for *any* appearance -;;; just like it says. I wonder if we could define DISPATCH-TYPE as macrolet -;;; that expands to the type for the current branch, so that it _must_ -;;; be in a for-evaluation position; but maybe I'm missing something?] -;;; -;;; As an alternate to a case spec, there may be a form whose CAR is a -;;; symbol. In this case, we apply the CAR of the form to the CDR and -;;; treat the result of the call as a list of cases. This process is -;;; not applied recursively. -;;; -;;; Be careful when using non-disjoint types in different cases for the -;;; same variable. Some uses will behave as intended, others not, as the -;;; variables are dispatched off sequentially and clauses are reordered -;;; for efficiency. Some, but not all, problematic cases are detected -;;; and lead to a compile time error; see GENERATE-NUMBER-DISPATCH above -;;; for an example. -(defmacro number-dispatch (var-specs &body cases) - (let ((res (list nil)) - (vars (mapcar #'car var-specs)) - (block (gensym))) - (dolist (case cases) - (if (symbolp (first case)) - (let ((cases (apply (symbol-function (first case)) (rest case)))) - (dolist (case cases) - (parse-number-dispatch vars res (first case) nil (rest case)))) - (parse-number-dispatch vars res (first case) nil (rest case)))) - - (collect ((errors) - (error-tags)) - (dolist (spec var-specs) - (let ((var (first spec)) - (type (second spec)) - (tag (gensym))) - (error-tags tag) - (errors tag) - (errors - (sb-c::internal-type-error-call var type)))) - - `(block ,block - (tagbody - (return-from ,block - ,@(generate-number-dispatch vars (error-tags) - (cdr res))) - ,@(errors)))))) - -;;;; binary operation dispatching utilities - -(eval-when (:compile-toplevel :execute) - -;;; Return NUMBER-DISPATCH forms for rational X float. -(defun float-contagion (op x y &optional (rat-types '(fixnum bignum ratio))) - `(((single-float single-float) (,op ,x ,y)) - (((foreach ,@rat-types) - (foreach single-float double-float #+long-float long-float)) - (,op (coerce ,x '(dispatch-type ,y)) ,y)) - (((foreach single-float double-float #+long-float long-float) - (foreach ,@rat-types)) - (,op ,x (coerce ,y '(dispatch-type ,x)))) - #+long-float - (((foreach single-float double-float long-float) long-float) - (,op (coerce ,x 'long-float) ,y)) - #+long-float - ((long-float (foreach single-float double-float)) - (,op ,x (coerce ,y 'long-float))) - (((foreach single-float double-float) double-float) - (,op (coerce ,x 'double-float) ,y)) - ((double-float single-float) - (,op ,x (coerce ,y 'double-float))))) - -;;; Return NUMBER-DISPATCH forms for bignum X fixnum. -(defun bignum-cross-fixnum (fix-op big-op) - `(((fixnum fixnum) (,fix-op x y)) - ((fixnum bignum) - (,big-op (make-small-bignum x) y)) - ((bignum fixnum) - (,big-op x (make-small-bignum y))) - ((bignum bignum) - (,big-op x y)))) - -) ; EVAL-WHEN - ;;;; canonicalization utilities ;;; If IMAGPART is 0, return REALPART, otherwise make a complex. This is ;;; used when we know that REALPART and IMAGPART are the same type, but ;;; rational canonicalization might still need to be done. -#-sb-fluid (declaim (inline canonical-complex)) +(declaim (inline canonical-complex)) (defun canonical-complex (realpart imagpart) (if (eql imagpart 0) realpart @@ -253,7 +36,7 @@ ;;; Given a numerator and denominator with the GCD already divided ;;; out, make a canonical rational. We make the denominator positive, ;;; and check whether it is 1. -#-sb-fluid (declaim (inline build-ratio)) +(declaim (inline build-ratio)) (defun build-ratio (num den) (multiple-value-bind (num den) (if (minusp den) @@ -268,7 +51,7 @@ (t (%make-ratio num den))))) ;;; Truncate X and Y, but bum the case where Y is 1. -#-sb-fluid (declaim (inline maybe-truncate)) +(declaim (inline maybe-truncate)) (defun maybe-truncate (x y) (if (eql y 1) x @@ -419,6 +202,7 @@ (defmacro two-arg-+/- (name op big-op) `(defun ,name (x y) + (declare (explicit-check)) (number-dispatch ((x number) (y number)) (bignum-cross-fixnum ,op ,big-op) (float-contagion ,op x y) @@ -463,6 +247,7 @@ (two-arg-+/- two-arg-- - subtract-bignum) (defun two-arg-* (x y) + (declare (explicit-check)) (flet ((integer*ratio (x y) (if (eql x 0) 0 (let* ((ny (numerator y)) @@ -479,8 +264,7 @@ (canonical-complex (* (realpart x) y) (* (imagpart x) y)))) (number-dispatch ((x number) (y number)) (float-contagion * x y) - - ((fixnum fixnum) (multiply-fixnums x y)) + ((fixnum fixnum) (* x y)) ((bignum fixnum) (multiply-bignum-and-fixnum x y)) ((fixnum bignum) (multiply-bignum-and-fixnum y x)) ((bignum bignum) (multiply-bignums x y)) @@ -532,10 +316,29 @@ (declare (explicit-check)) (macrolet ((truncate-float (rtype) `(let* ((float-div (coerce divisor ',rtype)) - (res (%unary-truncate (/ number float-div)))) + (divided (/ number float-div)) + (res (%unary-truncate divided))) (values res (- number - (* (coerce res ',rtype) float-div)))))) + (* #-round-float + (coerce res ',rtype) + #+round-float + (,(ecase rtype + (double-float 'round-double) + (single-float 'round-single)) + divided :truncate) + float-div))))) + (single-digit-bignum-p (x) + #+(or x86-64 x86 ppc64) + `(or (typep ,x 'word) + (typep ,x 'sb-vm:signed-word)) + ;; Other backends don't have native double-word/word division, + ;; and their bigfloor implementation doesn't handle + ;; full-width divisors. + #-(or x86-64 x86 ppc64) + `(or (typep ,x '(unsigned-byte ,(1- sb-vm:n-word-bits))) + (typep ,x '(integer ,(- 1 (expt 2 (- sb-vm:n-word-bits 1))) + ,(1- (expt 2 (- sb-vm:n-word-bits 1)))))))) (number-dispatch ((number real) (divisor real)) ((fixnum fixnum) (truncate number divisor)) (((foreach fixnum bignum) ratio) @@ -546,16 +349,19 @@ (numerator divisor)) (values quot (/ rem (denominator divisor)))))) ((fixnum bignum) - (bignum-truncate (make-small-bignum number) divisor)) + (if (single-digit-bignum-p divisor) + (bignum-truncate-single-digit (make-small-bignum number) divisor) + (bignum-truncate (make-small-bignum number) divisor))) ((ratio (or float rational)) (let ((q (truncate (numerator number) (* (denominator number) divisor)))) (values q (- number (* q divisor))))) ((bignum fixnum) - (bignum-truncate number (make-small-bignum divisor))) + (bignum-truncate-single-digit number divisor)) ((bignum bignum) - (bignum-truncate number divisor)) - + (if (single-digit-bignum-p divisor) + (bignum-truncate-single-digit number divisor) + (bignum-truncate number divisor))) (((foreach single-float double-float #+long-float long-float) (or rational single-float)) (if (eql divisor 1) @@ -635,71 +441,134 @@ ;;; ROUND and FROUND are not declared inline since they seem too ;;; obscure and too big to inline-expand by default. Also, this gives ;;; the compiler a chance to pick off the unary float case. -#-sb-fluid (declaim (inline fceiling ffloor ftruncate)) -(defun ftruncate (number &optional (divisor 1)) - "Same as TRUNCATE, but returns first value as a float." - (declare (explicit-check)) - (macrolet ((ftruncate-float (rtype) - `(let* ((float-div (coerce divisor ',rtype)) - (res (%unary-ftruncate (/ number float-div)))) - (values res - (- number - (* (coerce res ',rtype) float-div)))))) - (number-dispatch ((number real) (divisor real)) - (((foreach fixnum bignum ratio) (or fixnum bignum ratio)) - (multiple-value-bind (q r) - (truncate number divisor) - (values (float q) r))) - (((foreach single-float double-float #+long-float long-float) - (or rational single-float)) - (if (eql divisor 1) - (let ((res (%unary-ftruncate number))) - (values res (- number (coerce res '(dispatch-type number))))) - (ftruncate-float (dispatch-type number)))) - #+long-float - ((long-float (or single-float double-float long-float)) - (ftruncate-float long-float)) - #+long-float - (((foreach double-float single-float) long-float) - (ftruncate-float long-float)) - ((double-float (or single-float double-float)) - (ftruncate-float double-float)) - ((single-float double-float) - (ftruncate-float double-float)) - (((foreach fixnum bignum ratio) - (foreach single-float double-float #+long-float long-float)) - (ftruncate-float (dispatch-type divisor)))))) - -(defun ffloor (number &optional (divisor 1)) - "Same as FLOOR, but returns first value as a float." - (declare (explicit-check)) - (multiple-value-bind (tru rem) (ftruncate number divisor) - (if (and (not (zerop rem)) - (if (minusp divisor) - (plusp number) - (minusp number))) - (values (1- tru) (+ rem divisor)) - (values tru rem)))) - -(defun fceiling (number &optional (divisor 1)) - "Same as CEILING, but returns first value as a float." - (declare (explicit-check)) - (multiple-value-bind (tru rem) (ftruncate number divisor) - (if (and (not (zerop rem)) - (if (minusp divisor) - (minusp number) - (plusp number))) - (values (+ tru 1) (- rem divisor)) - (values tru rem)))) +(declaim (inline fceiling ffloor ftruncate)) + +#-round-float +(progn + (defun ftruncate (number &optional (divisor 1)) + "Same as TRUNCATE, but returns first value as a float." + (declare (explicit-check)) + (macrolet ((ftruncate-float (rtype) + `(let* ((float-div (coerce divisor ',rtype)) + (res (%unary-ftruncate (/ number float-div)))) + (values res + (- number + (* (coerce res ',rtype) float-div)))))) + (number-dispatch ((number real) (divisor real)) + (((foreach fixnum bignum ratio) (or fixnum bignum ratio)) + (multiple-value-bind (q r) + (truncate number divisor) + (values (float q) r))) + (((foreach single-float double-float #+long-float long-float) + (or rational single-float)) + (if (eql divisor 1) + (let ((res (%unary-ftruncate number))) + (values res (- number (coerce res '(dispatch-type number))))) + (ftruncate-float (dispatch-type number)))) + #+long-float + ((long-float (or single-float double-float long-float)) + (ftruncate-float long-float)) + #+long-float + (((foreach double-float single-float) long-float) + (ftruncate-float long-float)) + ((double-float (or single-float double-float)) + (ftruncate-float double-float)) + ((single-float double-float) + (ftruncate-float double-float)) + (((foreach fixnum bignum ratio) + (foreach single-float double-float #+long-float long-float)) + (ftruncate-float (dispatch-type divisor)))))) + + (defun ffloor (number &optional (divisor 1)) + "Same as FLOOR, but returns first value as a float." + (declare (explicit-check)) + (multiple-value-bind (tru rem) (ftruncate number divisor) + (if (and (not (zerop rem)) + (if (minusp divisor) + (plusp number) + (minusp number))) + (values (1- tru) (+ rem divisor)) + (values tru rem)))) + + (defun fceiling (number &optional (divisor 1)) + "Same as CEILING, but returns first value as a float." + (declare (explicit-check)) + (multiple-value-bind (tru rem) (ftruncate number divisor) + (if (and (not (zerop rem)) + (if (minusp divisor) + (minusp number) + (plusp number))) + (values (+ tru 1) (- rem divisor)) + (values tru rem)))) ;;; FIXME: this probably needs treatment similar to the use of ;;; %UNARY-FTRUNCATE for FTRUNCATE. -(defun fround (number &optional (divisor 1)) - "Same as ROUND, but returns first value as a float." - (declare (explicit-check)) - (multiple-value-bind (res rem) - (round number divisor) - (values (float res (if (floatp rem) rem $1.0)) rem))) + (defun fround (number &optional (divisor 1)) + "Same as ROUND, but returns first value as a float." + (declare (explicit-check)) + (multiple-value-bind (res rem) + (round number divisor) + (values (float res (if (floatp rem) rem $1.0)) rem)))) + +#+round-float +(macrolet ((def (name mode docstring) + `(defun ,name (number &optional (divisor 1)) + ,docstring + (declare (explicit-check)) + (macrolet ((ftruncate-float (rtype) + `(let* ((float-div (coerce divisor ',rtype)) + (res (,(case rtype + (double-float 'sb-kernel:round-double) + (single-float 'sb-kernel:round-single)) + (/ number float-div) + ,,mode))) + (values res + (- number + (* (coerce res ',rtype) float-div))))) + (unary-ftruncate-float (rtype) + `(let* ((res (,(case rtype + (double-float 'sb-kernel:round-double) + (single-float 'sb-kernel:round-single)) + number + ,,mode))) + (values res (- number res))))) + (number-dispatch ((number real) (divisor real)) + (((foreach fixnum bignum ratio) (or fixnum bignum ratio)) + (multiple-value-bind (q r) + (,(find-symbol (string mode) :cl) number divisor) + (values (float q) r))) + (((foreach single-float double-float) + (or rational single-float)) + (if (eql divisor 1) + (unary-ftruncate-float (dispatch-type number)) + (ftruncate-float (dispatch-type number)))) + ((double-float (or single-float double-float)) + (ftruncate-float double-float)) + ((single-float double-float) + (ftruncate-float double-float)) + (((foreach fixnum bignum ratio) + (foreach single-float double-float)) + (ftruncate-float (dispatch-type divisor)))))))) + (def ftruncate :truncate + "Same as TRUNCATE, but returns first value as a float.") + + (def ffloor :floor + "Same as FLOOR, but returns first value as a float.") + + (def fceiling :ceiling + "Same as CEILING, but returns first value as a float.") + (def fround :round + "Same as ROUND, but returns first value as a float.") + + (macrolet ((def (name) + `(defun ,name (x mode) + (ecase mode + ,@(loop for m in '(:round :floor :ceiling :truncate) + collect `(,m (,name x ,m))))))) + + + (def round-single) + (def round-double))) ;;;; comparisons @@ -794,7 +663,7 @@ the first." ((>= ,integer 0) (< (float quot ,float) ,float)))))))))) -(eval-when (:compile-toplevel :execute) +(eval-when (:compile-toplevel :load-toplevel :execute) ;;; The INFINITE-X-FINITE-Y and INFINITE-Y-FINITE-X args tell us how ;;; to handle the case when X or Y is a floating-point infinity and ;;; the other arg is a rational. (Section 12.1.4.1 of the ANSI spec @@ -820,7 +689,6 @@ the first." (,op x (coerce 0 '(dispatch-type x))) (if (float-infinity-p x) ,infinite-x-finite-y - ;; Likewise (make-fixnum-float-comparer ,(case op (> '<) (< '>) @@ -830,41 +698,79 @@ the first." (,op (coerce x 'double-float) y)) ((double-float single-float) (,op x (coerce y 'double-float))) - (((foreach single-float double-float #+long-float long-float) rational) - (if (eql y 0) - (,op x (coerce 0 '(dispatch-type x))) - (if (float-infinity-p x) - ,infinite-x-finite-y - (,op (rational x) y)))) - (((foreach bignum fixnum ratio) float) + (((foreach single-float double-float #+long-float long-float) ratio) + (if (float-infinity-p x) + ,infinite-x-finite-y + ;; Avoid converting the float into a rational, since it + ;; will be taken apart later anyway. + (multiple-value-bind (bits exp) (integer-decode-float x) + (if (eql bits 0) + (,op 0 y) + (let ((int (if (minusp x) (- bits) bits))) + (if (minusp exp) + (,op (* int (denominator y)) + (ash (numerator y) (- exp))) + (,op (ash int exp) y))))))) + ((ratio (foreach single-float double-float)) + (if (float-infinity-p y) + ,infinite-y-finite-x + (multiple-value-bind (bits exp) (integer-decode-float y) + (if (eql bits 0) + (,op x 0) + (let ((int (if (minusp y) (- bits) bits))) + (if (minusp exp) + (,op (ash (numerator x) (- exp)) + (* int (denominator x))) + (,op x (ash int exp)))))))) + (((foreach single-float double-float) bignum) + (if (float-infinity-p x) + ,infinite-x-finite-y + #+64-bit + (,(case op + (> 'float-bignum->) + (< 'float-bignum-<) + (= 'float-bignum-=)) + x y) + #-64-bit + (,op (rational x) y))) + ((bignum float) (if (float-infinity-p y) ,infinite-y-finite-x + #+64-bit + (,(case op + (> 'float-bignum-<) + (< 'float-bignum->) + (= 'float-bignum-=)) + y x) + #-64-bit (,op x (rational y)))))) ) ; EVAL-WHEN (macrolet ((def-two-arg-</> (name op ratio-arg1 ratio-arg2 &rest cases) `(defun ,name (x y) + (declare (inline float-infinity-p) + (explicit-check)) (number-dispatch ((x real) (y real)) - (basic-compare - ,op - :infinite-x-finite-y - (,op x (coerce 0 '(dispatch-type x))) - :infinite-y-finite-x - (,op (coerce 0 '(dispatch-type y)) y)) - (((foreach fixnum bignum) ratio) - (,op x (,ratio-arg2 (numerator y) - (denominator y)))) - ((ratio integer) - (,op (,ratio-arg1 (numerator x) - (denominator x)) - y)) - ((ratio ratio) - (,op (* (numerator (truly-the ratio x)) - (denominator (truly-the ratio y))) - (* (numerator (truly-the ratio y)) - (denominator (truly-the ratio x))))) - ,@cases)))) + (basic-compare + ,op + :infinite-x-finite-y + (,op x (coerce 0 '(dispatch-type x))) + :infinite-y-finite-x + (,op (coerce 0 '(dispatch-type y)) y)) + (((foreach fixnum bignum) ratio) + (,op x (,ratio-arg2 (numerator y) + (denominator y)))) + ((ratio integer) + (,op (,ratio-arg1 (numerator x) + (denominator x)) + y)) + ((ratio ratio) + (,op (* (numerator (truly-the ratio x)) + (denominator (truly-the ratio y))) + (* (numerator (truly-the ratio y)) + (denominator (truly-the ratio x))))) + ,@cases)))) (def-two-arg-</> two-arg-< < floor ceiling ((fixnum bignum) (bignum-plus-p y)) @@ -881,6 +787,8 @@ the first." (plusp (bignum-compare x y))))) (defun two-arg-= (x y) + (declare (inline float-infinity-p) + (explicit-check)) (number-dispatch ((x number) (y number)) (basic-compare = ;; An infinite value is never equal to a finite value. @@ -934,37 +842,37 @@ the first." (fixnum (lognot (truly-the fixnum number))) (bignum (bignum-logical-not number)))) -(macrolet ((def (name explicit-check op big-op &optional doc) +(macrolet ((def (name op big-op &optional doc) `(defun ,name (integer1 integer2) ,@(when doc (list doc)) - ,@(when explicit-check `((declare (explicit-check)))) + (declare (explicit-check)) (let ((x integer1) (y integer2)) (number-dispatch ((x integer) (y integer)) (bignum-cross-fixnum ,op ,big-op)))))) - (def two-arg-and nil logand bignum-logical-and) - (def two-arg-ior nil logior bignum-logical-ior) - (def two-arg-xor nil logxor bignum-logical-xor) + (def two-arg-and logand bignum-logical-and) + (def two-arg-ior logior bignum-logical-ior) + (def two-arg-xor logxor bignum-logical-xor) ;; BIGNUM-LOGICAL-{AND,IOR,XOR} need not return a bignum, so must ;; call the generic LOGNOT... - (def two-arg-eqv nil logeqv (lambda (x y) (lognot (bignum-logical-xor x y)))) - (def lognand t lognand + (def two-arg-eqv logeqv (lambda (x y) (lognot (bignum-logical-xor x y)))) + (def lognand lognand (lambda (x y) (lognot (bignum-logical-and x y))) "Complement the logical AND of INTEGER1 and INTEGER2.") - (def lognor t lognor + (def lognor lognor (lambda (x y) (lognot (bignum-logical-ior x y))) "Complement the logical OR of INTEGER1 and INTEGER2.") ;; ... but BIGNUM-LOGICAL-NOT on a bignum will always return a bignum - (def logandc1 t logandc1 + (def logandc1 logandc1 (lambda (x y) (bignum-logical-and (bignum-logical-not x) y)) "Bitwise AND (LOGNOT INTEGER1) with INTEGER2.") - (def logandc2 t logandc2 + (def logandc2 logandc2 (lambda (x y) (bignum-logical-and x (bignum-logical-not y))) "Bitwise AND INTEGER1 with (LOGNOT INTEGER2).") - (def logorc1 t logorc1 + (def logorc1 logorc1 (lambda (x y) (bignum-logical-ior (bignum-logical-not x) y)) "Bitwise OR (LOGNOT INTEGER1) with INTEGER2.") - (def logorc2 t logorc2 + (def logorc2 logorc2 (lambda (x y) (bignum-logical-ior x (bignum-logical-not y))) "Bitwise OR INTEGER1 with (LOGNOT INTEGER2).")) @@ -976,8 +884,8 @@ and the number of 0 bits if INTEGER is negative." (fixnum (logcount #-x86-64 (truly-the (integer 0 - #.(max sb-xc:most-positive-fixnum - (lognot sb-xc:most-negative-fixnum))) + #.(max most-positive-fixnum + (lognot most-negative-fixnum))) (if (minusp (truly-the fixnum integer)) (lognot (truly-the fixnum integer)) integer)) @@ -992,6 +900,7 @@ and the number of 0 bits if INTEGER is negative." (defun logbitp (index integer) "Predicate returns T if bit index of integer is a 1." + (declare (explicit-check)) (number-dispatch ((index integer) (integer integer)) ((fixnum fixnum) (if (< index sb-vm:n-positive-fixnum-bits) (not (zerop (logand integer (ash 1 index)))) @@ -1219,7 +1128,7 @@ and the number of 0 bits if INTEGER is negative." (values n m)) (* (truncate max (gcd n m)) min))))) -(declaim (inline fixnum-gcd)) +(declaim (maybe-inline fixnum-gcd)) (defun fixnum-gcd (u v) (declare (optimize (safety 0))) (locally @@ -1238,7 +1147,7 @@ and the number of 0 bits if INTEGER is negative." (setq v (- temp))) (setq temp (- u v)) (when (zerop temp) - (return (the (integer 0 #.(1+ sb-xc:most-positive-fixnum)) (ash u k))))))) + (return (the (integer 0 #.(1+ most-positive-fixnum)) (ash u k))))))) (declare (type (mod #.sb-vm:n-word-bits) k) (type sb-vm:signed-word u v))))) @@ -1248,7 +1157,8 @@ and the number of 0 bits if INTEGER is negative." ;;; of 0 before the dispatch so that the bignum code doesn't have to worry ;;; about "small bignum" zeros. (defun two-arg-gcd (u v) - (declare (muffle-conditions compiler-note)) + (declare (muffle-conditions compiler-note) + (inline fixnum-gcd)) (cond ((eql u 0) (abs v)) ((eql v 0) (abs u)) (t @@ -1267,6 +1177,7 @@ and the number of 0 bits if INTEGER is negative." ;;; bignum case, we don't bother, since bignum division is expensive, ;;; and the test is not very likely to succeed. (defun integer-/-integer (x y) + (declare (explicit-check)) (if (and (typep x 'fixnum) (typep y 'fixnum)) (multiple-value-bind (quo rem) (truncate x y) (if (zerop rem) @@ -1283,9 +1194,9 @@ and the number of 0 bits if INTEGER is negative." (values x y) (values (truncate x gcd) (truncate y gcd))) (build-ratio num den))))) -(declaim (notinline fixnum-gcd)) (defun two-arg-/ (x y) + (declare (explicit-check)) (number-dispatch ((x number) (y number)) (float-contagion / x y (ratio integer)) @@ -1378,7 +1289,7 @@ and the number of 0 bits if INTEGER is negative." (significant-half (ash ,arg (- (ash fourth-size 1)))) (significant-half-isqrt (if-fixnum-p-truly-the - (integer 1 #.(isqrt sb-xc:most-positive-fixnum)) + (integer 1 #.(isqrt most-positive-fixnum)) (,recurse significant-half))) (zeroth-iteration (ash significant-half-isqrt fourth-size))) @@ -1461,10 +1372,6 @@ and the number of 0 bits if INTEGER is negative." (do-mfuns sb-c::*tagged-modular-class*))) `(progn ,@(sort (forms) #'string< :key #'cadr))) -;;; KLUDGE: these out-of-line definitions can't use the modular -;;; arithmetic, as that is only (currently) defined for constant -;;; shifts. See also the comment in (LOGAND OPTIMIZER) for more -;;; discussion of this hack. -- CSR, 2003-10-09 #-(or 64-bit 64-bit-registers) (defun sb-vm::ash-left-mod32 (integer amount) (etypecase integer @@ -1485,3 +1392,12 @@ and the number of 0 bits if INTEGER is negative." (etypecase integer (fixnum (sb-c::mask-signed-field fixnum-width (ash integer amount))) (integer (sb-c::mask-signed-field fixnum-width (ash (sb-c::mask-signed-field fixnum-width integer) amount)))))) + +(sb-c::when-vop-existsp (:translate sb-vm::ash-modfx) + (defun sb-vm::ash-mod64 (integer amount) + (ldb (byte 64 0) (ash integer amount))) + + (defun sb-vm::ash-modfx (integer amount) + (if (minusp integer) + (sb-c::mask-signed-field sb-vm:n-fixnum-bits (ash integer amount)) + (logand most-positive-fixnum (ash integer amount))))) diff --git a/src/code/octets.lisp b/src/code/octets.lisp index 909c2b7da5..0d5f9cabcc 100644 --- a/src/code/octets.lisp +++ b/src/code/octets.lisp @@ -22,6 +22,9 @@ ;;; encoding condition +(eval-when (:compile-toplevel :load-toplevel :execute) + (defparameter *safety-0* '(safety 0))) + (define-condition octets-encoding-error (character-encoding-error) ((string :initarg :string :reader octets-encoding-error-string) (position :initarg :position :reader octets-encoding-error-position) @@ -181,7 +184,7 @@ ;; this, you generally want a load-time ref to a global constant. ;(declaim (inline ,byte-char-name)) (defun ,byte-char-name (byte) - (declare (optimize speed (safety 0)) + (declare (optimize speed #.*safety-0*) (type (unsigned-byte 8) byte)) ,(let ((byte-to-code (loop for byte below 256 @@ -203,7 +206,7 @@ `(aref ,(sb-c::coerce-to-smallest-eltype byte-to-code) byte)))) (defun ,code-byte-name (code) - (declare (optimize speed (safety 0)) + (declare (optimize speed #.*safety-0*) (type char-code code)) (if (< code ,lowest-non-equivalent-code) code @@ -253,7 +256,7 @@ do (let ((byte (funcall get-bytes string pos))) (typecase byte ((unsigned-byte 8) - (locally (declare (optimize (sb-c::insert-array-bounds-checks 0))) + (locally (declare (optimize (sb-c:insert-array-bounds-checks 0))) (setf (aref octets index) byte))) ((simple-array (unsigned-byte 8) (*)) ;; KLUDGE: We ran into encoding errors. Bail and do @@ -295,7 +298,7 @@ `(progn (declaim (inline ,name)) (defun ,name (string sstart send array astart aend mapper) - (declare (optimize speed (safety 0)) + (declare (optimize speed #.*safety-0*) (type simple-string string) (type ,type array) (type array-range sstart send astart aend) @@ -312,7 +315,7 @@ `(progn (declaim (inline ,name)) (defun ,name (array astart aend mapper) - (declare (optimize speed (safety 0)) + (declare (optimize speed #.*safety-0*) (type ,type array) (type array-range astart aend) (type function mapper)) @@ -402,12 +405,6 @@ STRING (or the subsequence bounded by START and END)." (funcall (ef-string-to-octets-fun ef) string start end (if null-terminate 1 0))))) -#+sb-unicode -(defvar +unicode-replacement-character+ (string (code-char #xfffd))) -#+sb-unicode -(defun use-unicode-replacement-char (condition) - (use-value +unicode-replacement-character+ condition)) - ;;; Vector of all available EXTERNAL-FORMAT instances. Each format is named ;;; by one or more keyword symbols. The mapping from symbol to index into this ;;; vector is memoized into the symbol's :EXTERNAL-FORMAT property. diff --git a/src/code/package.lisp b/src/code/package.lisp index 09fa51b90b..12e66c0908 100644 --- a/src/code/package.lisp +++ b/src/code/package.lisp @@ -36,12 +36,29 @@ ;;; symbol whose name is spelled "NIL" have the identical strange hash ;;; so that the hash is a pure function of the name's characters. +(eval-when (:compile-toplevel :load-toplevel :execute) + (defconstant package-id-bits 16) + ;; Give 48 bits to SYMBOL-NAME, which spans 256 TiB of memory. + ;; Omitting the lowtag bits could span up to 4 PiB because we could left-shift + ;; and re-tag to read the name. That seems excessive though. Another viable + ;; technique would be to store a heap-base-relative pointer, which might be + ;; needed if dynamic-space is small but at a very high address. + ;; For now, it seems fine to treat the low 48 bits as a tagged pointer. + (defconstant symbol-name-bits (- sb-vm:n-word-bits package-id-bits))) +(defconstant +package-id-overflow+ (1- (ash 1 package-id-bits))) +(defconstant +package-id-none+ 0) +(defconstant +package-id-lisp+ 1) +(defconstant +package-id-keyword+ 2) +(defconstant +package-id-user+ 3) +(defconstant +package-id-kernel+ 4) + (sb-xc:defstruct (package-hashtable (:constructor %make-package-hashtable (cells size &aux (free size))) (:copier nil)) - ;; The general-vector of symbols, with a hash-vector in its last cell. + ;; The general-vector of symbols (cells (missing-arg) :type simple-vector) + (modified nil :type boolean) ;; The total number of entries allowed before resizing. ;; ;; FIXME: CAPACITY would be a more descriptive name. (This is @@ -57,12 +74,14 @@ (sb-xc:defstruct (package (:constructor %make-package - (%name internal-symbols external-symbols)) + (internal-symbols external-symbols)) (:copier nil) (:predicate packagep)) "the standard structure for the description of a package" ;; the name of the package, or NIL for a deleted package (%name nil :type (or simple-string null)) + ;; A small integer ID, unless it overflows the global package index + (id nil :type (or (unsigned-byte #.package-id-bits) null)) ;; nickname strings (%nicknames () :type list) ;; packages used by this package @@ -93,12 +112,7 @@ (%local-nicknames nil :type (or null (cons simple-vector simple-vector))) ;; Definition source location (source-location nil :type (or null sb-c:definition-source-location))) -(sb-xc:proclaim '(freeze-type package-hashtable package)) -(!set-load-form-method package (:xc) - (lambda (obj env) - (declare (ignore env)) - ;; the target code will use FIND-UNDELETED-PACKAGE-OR-LOSE - `(find-package ,(package-name obj)))) +(proclaim '(freeze-type package-hashtable package)) (defconstant +initial-package-bits+ 2) ; for genesis @@ -108,8 +122,14 @@ (defmacro package-lock (package) `(logbitp 0 (package-%bits ,package))) +(defmacro with-loader-package-names (&body body) + #+sb-xc-host + `(progn ,@body) + #-sb-xc-host + `(call-with-loader-package-names (lambda () ,@body))) + ;;;; IN-PACKAGE -(sb-xc:proclaim '(special *package*)) +(proclaim '(special *package*)) (sb-xc:defmacro in-package (string-designator) (let ((string (string string-designator))) `(eval-when (:compile-toplevel :load-toplevel :execute) diff --git a/src/code/parse-defmacro-errors.lisp b/src/code/parse-defmacro-errors.lisp index 4d9dbb8c26..d6bea69da9 100644 --- a/src/code/parse-defmacro-errors.lisp +++ b/src/code/parse-defmacro-errors.lisp @@ -56,7 +56,7 @@ (n-actual (if (proper-list-p actual) (length actual) nil))) (format stream "~A elements in ~2I~_~:S ~ - ~I~_to satisfy lambda list ~2I~_~:S: ~I~_" + ~I~_to satisfy lambda list ~2I~_~/sb-impl:print-lambda-list/: ~I~_" (cond ((and n-actual (< n-actual min)) "too few") ((and n-actual max (> n-actual max)) "too many") (t "invalid number of")) diff --git a/src/code/pathname.lisp b/src/code/pathname.lisp index 49b15ae9c2..0318ac8d0d 100644 --- a/src/code/pathname.lisp +++ b/src/code/pathname.lisp @@ -16,12 +16,11 @@ ;;; The HOST structure holds the functions that both parse the ;;; pathname information into structure slot entries, and after ;;; translation the inverse (unparse) functions. -(sb-xc:defstruct (host (:constructor nil) - (:copier nil) - (:print-object - (lambda (host stream) - (print-unreadable-object - (host stream :type t :identity t))))) +(defstruct (host (:constructor nil) + (:copier nil) + (:print-object + (lambda (host stream) + (print-unreadable-object (host stream :type t :identity t))))) (parse (missing-arg) :type function :read-only t) (parse-native (missing-arg) :type function :read-only t) (unparse (missing-arg) :type function :read-only t) @@ -36,36 +35,36 @@ ;;; A PATTERN is a list of entries and wildcards used for pattern ;;; matches of translations. -(sb-xc:defstruct (pattern (:constructor make-pattern (pieces)) (:copier nil)) - (pieces nil :type list)) +(defstruct (pattern (:constructor %make-pattern (hash pieces)) + (:copier nil)) + (hash 0 :type fixnum :read-only t) + (pieces nil :type list :read-only t)) ;;;; PATHNAME structures ;;; the various magic tokens that are allowed to appear in pretty much ;;; all pathname components -(sb-xc:deftype pathname-component-tokens () +(deftype pathname-component-tokens () '(member nil :unspecific :wild :unc)) -(sb-xc:defstruct (pathname (:conc-name %pathname-) - (:copier nil) - (:constructor %%make-pathname - (host device directory name type version - &aux (dir-hash (pathname-dir-hash directory)) - (stem-hash (mix (sxhash name) (sxhash type))))) - (:predicate pathnamep)) +;;; This definition relies on compiler magic to turn the metclass +;;; into BUILT-IN-CLASSOID. Same for LOGICAL-PATHNAME. +(defstruct (pathname (:conc-name %pathname-) + (:copier nil) + (:constructor !allocate-pathname + (host device dir+hash name type version)) + (:predicate pathnamep)) (namestring nil) ; computed on demand - ;; support for pathname interning and hashing. - ;; Host and device might be reducible to small integers if we keep tables (vectors) - ;; of the values seen. - ;; We might even be able to pack DIR-HASH, STEM-HASH, and HOST, DEVICE into one slot. - (dir-hash nil :type hash-code :read-only t) - (stem-hash nil :type hash-code :read-only t) ; name hash and type hash mixed ;; the host (at present either a UNIX or logical host) + ;; Host and device could be reduced to small integers and packed in one slot + ;; by keeping tables of the observed values. (host nil :type (or host null) :read-only t) ;; the name of a logical or physical device holding files (device nil :type (or simple-string pathname-component-tokens) :read-only t) - ;; a list of strings that are the component subdirectory components - (directory nil :type list :read-only t) + ;; an interned list of strings headed by :ABSOLUTE or :RELATIVE + ;; comprising the path, or NIL. + ;; if the list is non-NIL, it's a cons of the list and a numeric hash. + (dir+hash nil :type list :read-only t) ;; the filename (name nil :type (or simple-string pattern pathname-component-tokens) :read-only t) ;; the type extension of the file @@ -75,3 +74,9 @@ (version nil :type (or integer pathname-component-tokens (member :newest)) :read-only t)) +(let ((to (find-layout 'logical-pathname)) + (from (find-layout 'pathname))) + (setf (wrapper-info to) (wrapper-info from) + (wrapper-slot-table to) (wrapper-slot-table from))) +(declaim (inline logical-pathname-p)) +(defun logical-pathname-p (x) (typep x 'logical-pathname)) diff --git a/src/code/ppc-vm.lisp b/src/code/ppc-vm.lisp index b27a49b5a1..4783c0d00e 100644 --- a/src/code/ppc-vm.lisp +++ b/src/code/ppc-vm.lisp @@ -2,55 +2,19 @@ ;;; (in-package "SB-VM") -#-sb-xc-host (defun machine-type () "Returns a string describing the type of the local machine." #-64-bit "PowerPC" #+64-bit "PowerPC64") - -;;;; FIXUP-CODE-OBJECT -(defconstant-eqx +fixup-kinds+ #(:absolute :absolute64 :b :ba :ha :l) #'equalp) -(!with-bigvec-or-sap -(defun fixup-code-object (code offset fixup kind flavor) - (declare (type index offset)) - (declare (ignore flavor)) - (unless (zerop (rem offset sb-assem:+inst-alignment-bytes+)) - (error "Unaligned instruction? offset=#x~X." offset)) - (let ((sap (code-instructions code))) - (ecase kind - (:absolute - ;; There is an implicit addend currently stored in the fixup location. - (incf (sap-ref-32 sap offset) fixup)) - (:absolute64 - (incf (sap-ref-64 sap offset) fixup)) - (:b - (error "Can't deal with CALL fixups, yet.")) - (:ba - (setf (ldb (byte 24 2) (sap-ref-32 sap offset)) - (ash fixup -2))) - (:ha - (let* ((h (ldb (byte 16 16) fixup)) - (l (ldb (byte 16 0) fixup))) - ; Compensate for possible sign-extension when the low half - ; is added to the high. We could avoid this by ORI-ing - ; the low half in 32-bit absolute loads, but it'd be - ; nice to be able to do: - ; lis rX,foo@ha - ; lwz rY,foo@l(rX) - ; and lwz/stw and friends all use a signed 16-bit offset. - (setf (ldb (byte 16 0) (sap-ref-32 sap offset)) - (if (logbitp 15 l) (ldb (byte 16 0) (1+ h)) h)))) - (:l - (setf (ldb (byte 16 0) (sap-ref-32 sap offset)) - (ldb (byte 16 0) fixup))))) - nil)) +(defun return-machine-address (scp) + (sap-int (context-lr scp))) + ;;;; "Sigcontext" access functions, cut & pasted from x86-vm.lisp then ;;;; hacked for types. -#-sb-xc-host (progn (define-alien-routine ("os_context_lr_addr" context-lr-addr) (* unsigned-long) (context (* os-context-t))) @@ -67,21 +31,22 @@ (* long) (context (* os-context-t)) (index int)) -#+nil (defun context-float-register (context index format) (declare (type (alien (* os-context-t)) context)) + (error "context-float-register not working yet? ~S" (list context index format)) + #+nil (coerce (deref (context-float-register-addr context index)) format)) -#+nil (defun %set-context-float-register (context index format new) (declare (type (alien (* os-context-t)) context)) + (error "%set-context-float-register not working yet? ~S" (list context index format new)) + #+nil (setf (deref (context-float-register-addr context index)) (coerce new format))) ;;; Given a signal context, return the floating point modes word in ;;; the same format as returned by FLOATING-POINT-MODES. ;;; -;;; FIXME: surely this must be accessible somewhere under Darwin? Or -;;; under NetBSD? +;;; FIXME: surely this must be accessible somewhere under *BSD? #+linux (define-alien-routine ("os_context_fp_control" context-floating-point-modes) (unsigned 32) @@ -130,4 +95,3 @@ '(#.arg-count-sc))))) (t (values #.(error-number-or-lose 'unknown-error) nil))))) -) ; end PROGN diff --git a/src/code/pprint.lisp b/src/code/pprint.lisp index 702dcfdaa3..7a60ed9635 100644 --- a/src/code/pprint.lisp +++ b/src/code/pprint.lisp @@ -13,25 +13,26 @@ ;;; Ancestral types (defstruct (queued-op (:constructor nil) (:copier nil)) - (posn 0 :type posn)) + (posn 0 :type posn :read-only t)) (defstruct (block-end (:include queued-op) (:copier nil)) - (suffix nil :type (or null simple-string))) + (suffix nil :type (or null simple-string) :read-only t)) (declaim (start-block)) (defstruct (section-start (:include queued-op) (:constructor nil) (:copier nil)) - (depth 0 :type index) + (depth 0 :type index :read-only t) (section-end nil :type (or null newline block-end))) (defstruct (newline (:include section-start) (:copier nil)) (kind (missing-arg) + :read-only t :type (member :linear :fill :miser :literal :mandatory))) (declaim (freeze-type newline) (end-block)) -#-sb-fluid (declaim (inline index-posn posn-index posn-column)) +(declaim (inline index-posn posn-index posn-column)) (defun index-posn (index stream) (declare (type index index) (type pretty-stream stream) (values posn)) @@ -121,8 +122,8 @@ (return)) (incf start count))))))))))) -(defun pretty-misc (stream op &optional arg1 arg2) - (declare (ignore stream op arg1 arg2))) +(defun pretty-misc (stream op arg) + (declare (ignore stream op arg))) ;;;; logical blocks @@ -727,7 +728,6 @@ line break." ;;;; pprint-dispatch tables -(define-load-time-global *standard-pprint-dispatch-table* nil) (define-load-time-global *initial-pprint-dispatch-table* nil) (defstruct (pprint-dispatch-entry @@ -739,11 +739,9 @@ line break." ;; either (LAMBDA (OBJ) (TYPEP OBJECT TYPE)) or a builtin predicate. ;; We don't bother computing this for entries in the CONS ;; hash table, because we don't need it. - (test-fn nil :type (or function null)) + (test-fn #'bug :type function) ;; the priority for this guy (priority 0 :type real :read-only t) - ;; T iff one of the original entries. - (initial-p (null *initial-pprint-dispatch-table*) :type boolean :read-only t) ;; and the associated function (fun nil :type function-designator :read-only t)) @@ -751,23 +749,19 @@ line break." (defmethod print-object ((entry pprint-dispatch-entry) stream) (print-unreadable-object (entry stream :type t) - (format stream "type=~S, priority=~S~@[ [initial]~]" + (format stream "type=~S, priority=~S]" (pprint-dispatch-entry-type entry) - (pprint-dispatch-entry-priority entry) - (pprint-dispatch-entry-initial-p entry)))) + (pprint-dispatch-entry-priority entry)))) + +(defmethod print-object ((table pprint-dispatch-table) stream) + (print-unreadable-object (table stream :type t :identity t))) ;; Return T iff E1 is strictly less preferable than E2. +(declaim (inline entry<)) (defun entry< (e1 e2) (declare (type pprint-dispatch-entry e1 e2)) - (if (pprint-dispatch-entry-initial-p e1) - (if (pprint-dispatch-entry-initial-p e2) - (< (pprint-dispatch-entry-priority e1) - (pprint-dispatch-entry-priority e2)) - t) - (if (pprint-dispatch-entry-initial-p e2) - nil - (< (pprint-dispatch-entry-priority e1) - (pprint-dispatch-entry-priority e2))))) + (< (pprint-dispatch-entry-priority (truly-the pprint-dispatch-entry e1)) + (pprint-dispatch-entry-priority (truly-the pprint-dispatch-entry e2)))) ;; Return the predicate for CTYPE, equivalently TYPE-SPEC. ;; This used to involve rewriting into a sexpr if CONS was involved, @@ -777,7 +771,7 @@ line break." (or (and (eq (info :type :kind type-spec) :instance) (let ((layout (info :type :compiler-layout type-spec))) (and layout - (let ((info (layout-info layout))) + (let ((info (wrapper-info layout))) (and info (let ((pred (dd-predicate-name info))) (and pred (fboundp pred) @@ -804,11 +798,10 @@ line break." (defun copy-pprint-dispatch (&optional (table *print-pprint-dispatch*)) (declare (type (or pprint-dispatch-table null) table)) (let* ((orig (or table *initial-pprint-dispatch-table*)) - (new (make-pprint-dispatch-table (copy-list (pp-dispatch-entries orig)) + (new (make-pprint-dispatch-table (copy-seq (pp-dispatch-entries orig)) (pp-dispatch-number-matchable-p orig) (pp-dispatch-only-initial-entries orig)))) - (replace/eql-hash-table (pp-dispatch-cons-entries new) - (pp-dispatch-cons-entries orig)) + (hash-table-replace (pp-dispatch-cons-entries new) (pp-dispatch-cons-entries orig)) new)) (defun pprint-dispatch (object &optional (table *print-pprint-dispatch*)) @@ -839,14 +832,18 @@ line break." (let ((cons-entry (and (consp object) (sb-impl::gethash/eql (car object) (pp-dispatch-cons-entries table) nil)))) - (cond ((not cons-entry) - (dolist (entry (pp-dispatch-entries table) nil) - (when (funcall (pprint-dispatch-entry-test-fn entry) object) + (cond ((not cons-entry) ; impossible, unless you've removed all initial cons entries + (dovector (entry (pp-dispatch-entries table) nil) + (when (funcall (pprint-dispatch-entry-test-fn + (truly-the pprint-dispatch-entry entry)) + object) (return entry)))) ((pp-dispatch-only-initial-entries table) cons-entry) (t - (dolist (entry (pp-dispatch-entries table) cons-entry) + ;; This gives cons entries precedence over non-cons entries that have + ;; the same numerical priority. + (dovector (entry (pp-dispatch-entries table) cons-entry) (when (entry< entry cons-entry) (return cons-entry)) (when (funcall (pprint-dispatch-entry-test-fn entry) object) @@ -861,9 +858,9 @@ line break." :operation operation))) (defun defer-type-checker (entry) - (let ((saved-nonce sb-c::*type-cache-nonce*)) + (let ((saved-nonce sb-kernel::*type-cache-nonce*)) (lambda (obj) - (let ((nonce sb-c::*type-cache-nonce*)) + (let ((nonce sb-kernel::*type-cache-nonce*)) (if (eq nonce saved-nonce) nil (let ((ctype (specifier-type (pprint-dispatch-entry-type entry)))) @@ -905,8 +902,9 @@ line break." (entry (if function (make-pprint-dispatch-entry type priority function - (unless (or consp disabled-p) - (compute-test-fn ctype type function)))))) + (if (or consp disabled-p) + #'bug + (compute-test-fn ctype type function)))))) (when (and function disabled-p) ;; a DISABLED-P test function has to close over the ENTRY (setf (pprint-dispatch-entry-test-fn entry) (defer-type-checker entry))) @@ -920,39 +918,38 @@ line break." (remhash key hashtable)))) (setf (pp-dispatch-only-initial-entries table) nil (pp-dispatch-entries table) - (let ((list (delete type (pp-dispatch-entries table) - :key #'pprint-dispatch-entry-type - :test #'equal))) + (let ((old (remove type (pp-dispatch-entries table) + :key #'pprint-dispatch-entry-type + :test #'equal))) (if function ;; ENTRY< is T if lower in priority, which should sort to ;; the end, but MERGE's predicate wants T for the (a,b) pair ;; if 'a' should go in front of 'b', so swap them. ;; (COMPLEMENT #'entry<) is unstable wrt insertion order. - (merge 'list list (list entry) (lambda (a b) (entry< b a))) - list))))) + (merge 'vector old (list entry) (lambda (a b) (entry< b a))) + old))))) nil) +(clear-info :function :inlining-data 'entry<) ; can be removed ;;;; standard pretty-printing routines (defun pprint-array (stream array) - (cond ((and (null *print-array*) (null *print-readably*)) - (output-ugly-object stream array)) + (cond ((or (null (array-element-type array)) + (and (null *print-array*) (null *print-readably*))) + (print-object array stream)) ((and *print-readably* (not (array-readably-printable-p array))) (sb-impl::output-unreadable-array-readably array stream)) ((vectorp array) - (pprint-vector stream array)) + (pprint-logical-block (stream nil :prefix "#(" :suffix ")") + (dotimes (i (length array)) + (unless (zerop i) + (format stream " ~:_")) + (pprint-pop) + (output-object (aref array i) stream)))) (t (pprint-multi-dim-array stream array)))) -(defun pprint-vector (stream vector) - (pprint-logical-block (stream nil :prefix "#(" :suffix ")") - (dotimes (i (length vector)) - (unless (zerop i) - (format stream " ~:_")) - (pprint-pop) - (output-object (aref vector i) stream)))) - (defun pprint-multi-dim-array (stream array) (funcall (formatter "#~DA") stream (array-rank array)) (with-array-data ((data array) (start) (end)) @@ -1345,29 +1342,28 @@ line break." stream list)) -(defun pprint-data-list (stream list &rest noise) - (declare (ignore noise)) - (pprint-fill stream list)) - ;;; Return the number of positional arguments that macro NAME accepts ;;; by looking for &BODY. A dotted list is indented as it it had &BODY. ;;; ANSI says that a dotted tail is like &REST, but the pretty-printer ;;; can do whatever it likes anyway. I happen to think this makes sense. -(defun macro-indentation (name) +(defun macro-indentation (macro-function) (do ((n 0) - (list (%fun-lambda-list (macro-function name)) (cdr list))) + (list (%fun-lambda-list macro-function) (cdr list))) ((or (atom list) (eq (car list) '&body)) (if (null list) nil n)) (unless (eq (car list) '&optional) (incf n)))) ;;; Pretty-Print macros by looking where &BODY appears in a macro's -;;; lambda-list. -(defun pprint-macro-call (stream list &rest noise) +;;; lambda-list. If LIST is not macro invocation, or a macro without a &BODY arg +;;; then print it as a function. +(defun pprint-call-form (stream list &rest noise) (declare (ignore noise)) - (let ((indentation (and (car list) (macro-indentation (car list))))) + (let ((indentation (binding* ((car (car list) :exit-if-null) + (mf (macro-function car) :exit-if-null)) + (macro-indentation mf)))) (unless indentation - (return-from pprint-macro-call + (return-from pprint-call-form (pprint-fun-call stream list))) (pprint-logical-block (stream list :prefix "(" :suffix ")") (output-object (pprint-pop) stream) @@ -1399,7 +1395,7 @@ line break." (defmacro with-pretty-stream ((stream-var &optional (stream-expression stream-var)) &body body) - (let ((flet-name (sb-xc:gensym "WITH-PRETTY-STREAM"))) + (let ((flet-name (gensym "WITH-PRETTY-STREAM"))) `(flet ((,flet-name (,stream-var) ,@body)) (let ((stream ,stream-expression)) @@ -1486,34 +1482,54 @@ line break." (t (incf (car state)))))) +;;; Warm bootup is slightly less brittle if we can avoid first having to run +;;; the compiler to make some predicates for the initial PPD type specifiers. +;;; In particular I'm trying to eradicate a bunch of PARSE-UNKNOWN conditions +;;; that occur, e.g. installing (AND ARRAY (NOT (OR STRING BIT-VECTOR))) +;;; entails (compile nil '(typep sb-pretty::object <that-type>)) +;;; -> (sb-c::find-free-fun typep) +;;; -> (sb-kernel:specifier-type (function (t (or cons symbol sb-kernel:classoid class) ...))) +;;; -> (sb-kernel::parse-args-types ...) +;;; -> (sb-kernel::%parse-type CLASS) +;;; where the type specifier for CLASS is as yet unknown +(defmacro initial-entry (specifier handler &optional predicate) + ;; Assign the lowest possible priority + `(make-pprint-dispatch-entry + ',specifier single-float-negative-infinity #',handler + ,(or predicate + `(named-lambda ,(format nil "~A-P" handler) (x) + ,(sb-c::source-transform-typep 'x specifier))))) + + +;;;; Interface seen by regular (ugly) printer. + +;;; OUTPUT-PRETTY-OBJECT is called by OUTPUT-OBJECT when +;;; *PRINT-PRETTY* is true. +(defun output-pretty-object (stream fun object) + (with-pretty-stream (stream) + (funcall fun stream object))) + (defun !pprint-cold-init () (/show0 "entering !PPRINT-COLD-INIT") ;; Kludge: We set *STANDARD-PP-D-TABLE* to a new table even though ;; it's going to be set to a copy of *INITIAL-PP-D-T* below because ;; it's used in WITH-STANDARD-IO-SYNTAX, and condition reportery ;; possibly performed in the following extent may use W-S-IO-SYNTAX. - (setf *standard-pprint-dispatch-table* (make-pprint-dispatch-table nil nil nil)) + (setf *standard-pprint-dispatch-table* (make-pprint-dispatch-table #() nil nil)) (setf *initial-pprint-dispatch-table* nil) - (let ((*print-pprint-dispatch* (make-pprint-dispatch-table nil nil nil))) - (/show0 "doing SET-PPRINT-DISPATCH for regular types") - ;; * PLEASE NOTE : If you change these definitions, then you may need to adjust - ;; the computation of POSSIBLY-MATCHABLE in PPRINT-DISPATCH. - ;; - ;; Assign a lower priority than for the cons entries below, making - ;; fewer type tests when dispatching. - (set-pprint-dispatch '(and array (not (or string bit-vector))) 'pprint-array -1) - ;; MACRO-FUNCTION must have effectively higher priority than FBOUNDP. - ;; The implementation happens to check identical priorities in the order added, - ;; but that's unspecified behavior. Both must be _strictly_ lower than the - ;; default cons entries though. - (set-pprint-dispatch '(cons (and symbol (satisfies macro-function))) - 'pprint-macro-call -1) - (set-pprint-dispatch '(cons (and symbol (satisfies fboundp))) - 'pprint-fun-call -1) - (set-pprint-dispatch '(cons symbol) - 'pprint-data-list -2) - (set-pprint-dispatch 'cons 'pprint-fill -2) - (set-pprint-dispatch 'sb-impl::comma 'pprint-unquoting-comma -3) + (let* ((initial-entries + (vector + ;; * PLEASE NOTE : If you change these definitions, then you may need to adjust + ;; the computation of POSSIBLY-MATCHABLE in PPRINT-DISPATCH. + ;; + ;; The implementation happens to check identical priorities in the order added, + ;; but that's unspecified behavior. + (initial-entry (and array (not (or string bit-vector))) pprint-array) + (initial-entry (cons (and symbol (satisfies fboundp))) pprint-call-form) + (initial-entry cons pprint-fill #'consp) + (initial-entry sb-impl::comma pprint-unquoting-comma #'comma-p))) + (*print-pprint-dispatch* + (make-pprint-dispatch-table initial-entries nil nil))) ;; cons cells with interesting things for the car (/show0 "doing SET-PPRINT-DISPATCH for CONS with interesting CAR") (dolist (magic-form '((lambda pprint-lambda) @@ -1566,7 +1582,8 @@ line break." ;; Grouping some symbols together in the above list looks pretty. ;; The sharing of dispatch entries is inconsequential. (set-pprint-dispatch `(cons (member ,@(ensure-list (first magic-form)))) - (second magic-form))) + (second magic-form) + most-negative-single-float)) (setf (pp-dispatch-only-initial-entries *print-pprint-dispatch*) t *initial-pprint-dispatch-table* *print-pprint-dispatch*)) diff --git a/src/code/pred.lisp b/src/code/pred.lisp index ed0de81cf5..371a644387 100644 --- a/src/code/pred.lisp +++ b/src/code/pred.lisp @@ -13,10 +13,15 @@ ;;;; miscellaneous non-primitive predicates -#-sb-fluid (declaim (inline streamp)) +(declaim (inline streamp)) (defun streamp (stream) (typep stream 'stream)) +;;; These would only be called from %%TYPEP given a built-in-classoid. +;;; Ordinarily TYPEP on either one would be transformed. +(defun sb-kernel::file-stream-p (x) (typep x 'file-stream)) +(defun sb-kernel::string-stream-p (x) (typep x 'string-stream)) + ;;; various (VECTOR FOO) type predicates, not implemented as simple ;;; widetag tests (macrolet @@ -89,15 +94,19 @@ ;; the type it tests for in the Common Lisp type system, and since it's ;; only used in the implementation of a few specialized things.) (def-type-predicate-wrapper double-float-p) - (def-type-predicate-wrapper extended-char-p) (def-type-predicate-wrapper fdefn-p) (def-type-predicate-wrapper fixnump) (def-type-predicate-wrapper floatp) (def-type-predicate-wrapper functionp) + ;; SIMPLE-FUN-P is needed for constant folding in early warm load, + ;; and its absence would be obscured by the fact that + ;; CONSTANT-FUNCTION-CALL-P allows the call to fail. + (def-type-predicate-wrapper closurep) + (def-type-predicate-wrapper simple-fun-p) (def-type-predicate-wrapper integerp) (def-type-predicate-wrapper listp) (def-type-predicate-wrapper long-float-p) - #-(or x86 x86-64) (def-type-predicate-wrapper lra-p) + #-(or x86 x86-64 arm64 riscv) (def-type-predicate-wrapper lra-p) (def-type-predicate-wrapper null) (def-type-predicate-wrapper numberp) (def-type-predicate-wrapper rationalp) @@ -117,10 +126,15 @@ (def-type-predicate-wrapper system-area-pointer-p) (def-type-predicate-wrapper unbound-marker-p) (def-type-predicate-wrapper weak-pointer-p) - #-64-bit - (progn - (def-type-predicate-wrapper unsigned-byte-32-p) + + (sb-c::when-vop-existsp (:translate signed-byte-8-p) + (def-type-predicate-wrapper signed-byte-8-p)) + (sb-c::when-vop-existsp (:translate signed-byte-16-p) + (def-type-predicate-wrapper signed-byte-16-p)) + (sb-c::when-vop-existsp (:translate signed-byte-32-p) (def-type-predicate-wrapper signed-byte-32-p)) + #-64-bit + (def-type-predicate-wrapper unsigned-byte-32-p) #+64-bit (progn (def-type-predicate-wrapper unsigned-byte-64-p) @@ -139,67 +153,13 @@ (def-type-predicate-wrapper simple-rank-1-array-*-p) (def-type-predicate-wrapper simple-string-p) (def-type-predicate-wrapper stringp) - (def-type-predicate-wrapper vectorp) - (def-type-predicate-wrapper vector-nil-p)) + (def-type-predicate-wrapper vectorp)) -#+(or x86 x86-64 arm arm64) -(defun fixnum-mod-p (x limit) - (and (fixnump x) - (<= 0 x limit))) +(sb-c::when-vop-existsp (:translate fixnum-mod-p) + (defun fixnum-mod-p (x limit) + (and (fixnump x) + (<= 0 x limit)))) -;;; a vector that maps widetags to layouts, used for quickly finding -;;; the layouts of built-in classes -(define-load-time-global **primitive-object-layouts** nil) -(declaim (type simple-vector **primitive-object-layouts**)) -(defun !pred-cold-init () - ;; This vector is allocated in immobile space when possible. There isn't - ;; a way to do that from lisp, so it's special-cased in genesis. - #-immobile-space (setq **primitive-object-layouts** (make-array 256)) - (map-into **primitive-object-layouts** - (lambda (name) (classoid-layout (find-classoid name))) - #.(let ((table (make-array 256 :initial-element 'sb-kernel::random-class))) - (dolist (x sb-kernel::+!built-in-classes+) - (destructuring-bind (name &key codes &allow-other-keys) x - (dolist (code codes) - (setf (svref table code) name)))) - (loop for i from sb-vm:list-pointer-lowtag by (* 2 sb-vm:n-word-bytes) - below 256 - do (setf (aref table i) 'cons)) - (loop for i from sb-vm:even-fixnum-lowtag by (ash 1 sb-vm:n-fixnum-tag-bits) - below 256 - do (setf (aref table i) 'fixnum)) - table))) - -;;; Return the layout for an object. This is the basic operation for -;;; finding out the "type" of an object, and is used for generic -;;; function dispatch. The standard doesn't seem to say as much as it -;;; should about what this returns for built-in objects. For example, -;;; it seems that we must return NULL rather than LIST when X is NIL -;;; so that GF's can specialize on NULL. -;;; x86-64 has a vop that implements this without even needing to place -;;; the vector of layouts in the constant pool of the containing code. -#-(and compact-instance-header x86-64) -(progn -(declaim (inline layout-of)) -(defun layout-of (x) - (declare (optimize (speed 3) (safety 0))) - (cond ((%instancep x) (%instance-layout x)) - ((funcallable-instance-p x) (%fun-layout x)) - ;; Compiler can dump literal layouts, which handily sidesteps - ;; the question of when cold-init runs L-T-V forms. - ((null x) #.(find-layout 'null)) - (t - ;; Note that WIDETAG-OF is slightly suboptimal here and could be - ;; improved - we've already ruled out some of the lowtags. - (svref (load-time-value **primitive-object-layouts** t) - (widetag-of x)))))) - -(declaim (inline classoid-of)) -#-sb-xc-host -(defun classoid-of (object) - "Return the class of the supplied object, which may be any Lisp object, not - just a CLOS STANDARD-OBJECT." - (layout-classoid (layout-of object))) ;;; Return the specifier for the type of object. This is not simply ;;; (TYPE-SPECIFIER (CTYPE-OF OBJECT)) because CTYPE-OF has different @@ -216,10 +176,10 @@ (cond ((<= 0 object 1) 'bit) ((< object 0) 'fixnum) - (t `(integer 0 ,sb-xc:most-positive-fixnum)))) + (t `(integer 0 ,most-positive-fixnum)))) (integer (if (>= object 0) - `(integer ,(1+ sb-xc:most-positive-fixnum)) + `(integer ,(1+ most-positive-fixnum)) 'bignum)) (character (typecase object @@ -235,25 +195,45 @@ ((eq object nil) 'null) ((eq (sb-xc:symbol-package object) *keyword-package*) 'keyword) (t 'symbol))) - ((or array complex #+sb-simd-pack simd-pack #+sb-simd-pack-256 simd-pack-256) - (let ((sb-kernel::*unparse-allow-negation* nil)) - (declare (special sb-kernel::*unparse-allow-negation*)) ; forward ref - (type-specifier (ctype-of object)))) + (array + (let ((etype (sb-vm::array-element-ctype object))) + ;; Obviously :COMPLEXP is known to be T or NIL, but it's not allowed to + ;; return (NOT SIMPLE-ARRAY), so use :MAYBE in lieu of T. + (type-specifier + (make-array-type (array-dimensions object) + :complexp (if (typep object 'simple-array) nil :maybe) + :element-type etype + :specialized-element-type etype)))) + ((or complex #+sb-simd-pack simd-pack #+sb-simd-pack-256 simd-pack-256) + (type-specifier (ctype-of object))) + (simple-fun 'compiled-function) (t - (let* ((classoid (classoid-of object)) - (name (classoid-name classoid))) - (if (%instancep object) - (case name - (sb-alien-internals:alien-value - `(alien - ,(sb-alien-internals:unparse-alien-type - (sb-alien-internals:alien-value-type object)))) - (t - (let ((pname (classoid-proper-name classoid))) - (if (classoid-p pname) - (classoid-pcl-class pname) - pname)))) - name))))) + #+metaspace ; WRAPPER-OF can't be called on layoutless objects. + (unless (logtest (get-lisp-obj-address (%instanceoid-layout object)) + sb-vm:widetag-mask) + ;; [fun-]instances momentarily have no layout in any code interrupted + ;; just after allocating and before assigning slots. + ;; OUTPUT-UGLY-OBJECT has a similar precaution as this. + (return-from type-of (if (functionp object) 'funcallable-instance 'instance))) + (let ((wrapper (wrapper-of object))) + #-metaspace ; already checked for a good layout if metaspace + (when (= (get-lisp-obj-address wrapper) 0) + (return-from type-of + (if (functionp object) 'funcallable-instance 'instance))) + (let* ((classoid (wrapper-classoid wrapper)) + (name (classoid-name classoid))) + ;; FIXME: should the first test be (not (or (%instancep) (%funcallable-instance-p)))? + ;; God forbid anyone makes anonymous classes of generic functions. + (cond ((not (%instancep object)) + name) + ((eq name 'sb-alien-internals:alien-value) + `(alien ,(sb-alien-internals:unparse-alien-type + (sb-alien-internals:alien-value-type object)))) + (t + (let ((pname (classoid-proper-name classoid))) + (if (classoid-p pname) + (classoid-pcl-class pname) + pname))))))))) ;;;; equality predicates @@ -273,8 +253,8 @@ ;; Anyway it suffices to disable type checking and pretend its the always ;; the first arg that's an integer, but that won't work on the host because ;; it might enforce the type since we can't portably unenforce after declaring. - #-sb-xc-host (declare (optimize (sb-c::type-check 0))) - (eql #+sb-xc-host obj1 #-sb-xc-host (the integer obj1) obj2)) + (declare (optimize (sb-c::type-check 0))) + (eql (the integer obj1) obj2)) (declaim (inline %eql)) (defun %eql (obj1 obj2) @@ -387,11 +367,11 @@ length and have identical components. Other arrays must be EQ to be EQUAL." (equal x y))))) ;;; EQUALP comparison of HASH-TABLE values +;;; Can be called only if both X and Y are definitely hash-tables. (defun hash-table-equalp (x y) - (declare (type hash-table x y)) + (declare (type hash-table x y) (explicit-check)) (or (eq x y) - (and (hash-table-p y) - (eql (hash-table-count x) (hash-table-count y)) + (and (eql (hash-table-count x) (hash-table-count y)) (eql (hash-table-test x) (hash-table-test y)) (block comparison-of-entries (maphash (lambda (key x-value) @@ -402,75 +382,116 @@ length and have identical components. Other arrays must be EQ to be EQUAL." x) t)))) -(declaim (inline instance-equalp)) +(macrolet ((slot-ref-equalp () + `(let ((x-el (%instance-ref x i)) + (y-el (%instance-ref y i))) + (or (eq x-el y-el) (equalp x-el y-el))))) (defun instance-equalp (x y) - (let ((layout-x (%instance-layout x))) - (and - (eq layout-x (%instance-layout y)) - (logtest +structure-layout-flag+ (layout-flags layout-x)) - (macrolet ((slot-ref-equalp () - `(let ((x-el (%instance-ref x i)) - (y-el (%instance-ref y i))) - (or (eq x-el y-el) (equalp x-el y-el))))) - (let ((n (%instance-length x))) - (if (eql (layout-bitmap layout-x) sb-kernel:+layout-all-tagged+) - (loop for i downfrom (1- n) to sb-vm:instance-data-start - always (slot-ref-equalp)) - (let ((comparators (layout-equalp-tests layout-x))) - (unless (= (length comparators) (- n sb-vm:instance-data-start)) - (bug "EQUALP got incomplete instance layout")) - ;; See remark at the source code for %TARGET-DEFSTRUCT - ;; explaining how to use the vector of comparators. - (loop for i downfrom (1- n) to sb-vm:instance-data-start - for test = (data-vector-ref - comparators (- i sb-vm:instance-data-start)) - always (cond ((eql test 0) (slot-ref-equalp)) - ((functionp test) (funcall test i x y)) - (t)))))))))) + (declare (optimize (safety 0))) + (loop for i downfrom (1- (%instance-length x)) to sb-vm:instance-data-start + always (slot-ref-equalp))) +(defun instance-equalp* (comparators x y) + (declare (optimize (safety 0)) + (simple-vector comparators) + (type instance x y)) + ;; See remark at the source code for %TARGET-DEFSTRUCT + ;; explaining how to use the vector of comparators. + (loop for i downfrom (1- (%instance-length x)) to sb-vm:instance-data-start + for test = (data-vector-ref comparators (- i sb-vm:instance-data-start)) + always (cond ((eql test 0) (slot-ref-equalp)) + ((functionp test) (funcall test i x y)) + (t))))) -;;; Doesn't work on simple vectors -(defun array-equalp (x y) - (declare (array x y)) - (let ((rank (array-rank x))) - (and - (= rank (array-rank y)) - (dotimes (axis rank t) - (unless (= (%array-dimension x axis) - (%array-dimension y axis)) - (return nil))) - (with-array-data ((x x) (start-x) (end-x) :force-inline t - :array-header-p t) - (with-array-data ((y y) (start-y) (end-y) :force-inline t - :array-header-p t) - (declare (ignore end-y)) - (let* ((reffers %%data-vector-reffers%%) - (getter-x (truly-the function (svref reffers (%other-pointer-widetag x)))) - (getter-y (truly-the function (svref reffers (%other-pointer-widetag y))))) - (loop for x-i fixnum from start-x below end-x - for y-i fixnum from start-y - for x-el = (funcall getter-x x x-i) - for y-el = (funcall getter-y y y-i) - always (or (eq x-el y-el) - (equalp x-el y-el))))))))) - -(defun vector-equalp (x y) - (declare (vector x y)) - (let ((length (length x))) - (and (= length (length y)) - (with-array-data ((x x) (start-x) (end-x) :force-inline t - :check-fill-pointer t) - (with-array-data ((y y) (start-y) (end-y) :force-inline t - :check-fill-pointer t) - (declare (ignore end-y)) - (let* ((reffers %%data-vector-reffers%%) - (getter-x (truly-the function (svref reffers (%other-pointer-widetag x)))) - (getter-y (truly-the function (svref reffers (%other-pointer-widetag y))))) - (loop for x-i fixnum from start-x below end-x - for y-i fixnum from start-y - for x-el = (funcall getter-x x x-i) - for y-el = (funcall getter-y y y-i) - always (or (eq x-el y-el) - (equalp x-el y-el))))))))) +(macrolet ((numericp (v) + (let ((widetags + (map 'list #'sb-vm:saetp-typecode + (remove-if (lambda (x) + (not (typep (sb-vm:saetp-ctype x) 'numeric-type))) + sb-vm:*specialized-array-element-type-properties*)))) + `(%other-pointer-subtype-p ,v ',widetags))) + (compare-loop (typespec) + `(let ((x (truly-the (simple-array ,typespec 1) x)) + (y (truly-the (simple-array ,typespec 1) y))) + (loop for x-i fixnum from start-x below end-x + for y-i fixnum from start-y + always (= (aref x x-i) (aref y y-i)))))) +(defun array-equalp (a b) + (flet + ((data-vector-compare (x y start-x end-x start-y) + (declare (index start-x end-x start-y) + (optimize (sb-c:insert-array-bounds-checks 0))) + (let ((xtag (%other-pointer-widetag (truly-the (simple-array * 1) x))) + (ytag (%other-pointer-widetag (truly-the (simple-array * 1) y)))) + (case (if (= xtag ytag) xtag 0) + (#.sb-vm:simple-vector-widetag + (let ((x (truly-the simple-vector x)) + (y (truly-the simple-vector y))) + (loop for x-i fixnum from start-x below end-x + for y-i fixnum from start-y + always (let ((a (svref x x-i)) (b (svref y y-i))) + (or (eq a b) (equalp a b)))))) + ;; Special-case the important array types that would cause consing in aref. + ;; Though (UNSIGNED-BYTE 62) and (UNSIGNED-BYTE 63) arrays exist, + ;; I highly doubt that they occur anywhere except in contrived code + ;; that does nothing but test that those types exist. i.e. They are + ;; beyond worthless, and are frankly wasteful of space in array dispatch + ;; scenarios, or to put it mildy: I disagree with their existence per se. + #+64-bit (#.sb-vm:simple-array-unsigned-byte-64-widetag + (compare-loop (unsigned-byte 64))) + #+64-bit (#.sb-vm:simple-array-signed-byte-64-widetag + (compare-loop (signed-byte 64))) + #-64-bit (#.sb-vm:simple-array-unsigned-byte-32-widetag + (compare-loop (unsigned-byte 32))) + #-64-bit (#.sb-vm:simple-array-signed-byte-32-widetag + (compare-loop (signed-byte 32))) + ;; SINGLE-FLOAT wouldn't cons on 64-bit, but it should be treated + ;; no less efficiently than DOUBLE-FLOAT. + (#.sb-vm:simple-array-single-float-widetag + (compare-loop single-float)) + (#.sb-vm:simple-array-double-float-widetag + (compare-loop double-float)) + (#.sb-vm:simple-array-complex-single-float-widetag + (compare-loop (complex single-float))) + (#.sb-vm:simple-array-complex-double-float-widetag + (compare-loop (complex double-float))) + (t + (let* ((reffers %%data-vector-reffers%%) + (getter-x (truly-the function (svref reffers xtag))) + (getter-y (truly-the function (svref reffers ytag)))) + ;; The arrays won't both be strings, because EQUALP has a case for that. + ;; If they're both numeric, use = as the test. + (if (and (numericp x) (numericp y)) + (loop for x-i fixnum from start-x below end-x + for y-i fixnum from start-y + always (= (funcall getter-x x x-i) (funcall getter-y y y-i))) + ;; Everything else + (loop for x-i fixnum from start-x below end-x + for y-i fixnum from start-y + for x-el = (funcall getter-x x x-i) + for y-el = (funcall getter-y y y-i) + always (or (eq x-el y-el) + (equalp x-el y-el)))))))))) + (if (vectorp (truly-the array a)) + (and (vectorp (truly-the array b)) + (= (length a) (length b)) + (with-array-data ((x a) (start-x) (end-x) + :force-inline t :check-fill-pointer t) + (with-array-data ((y b) (start-y) (end-y) + :force-inline t :check-fill-pointer t) + (declare (ignore end-y)) + (data-vector-compare x y start-x end-x start-y)))) + (let ((rank (array-rank (truly-the array a)))) + (and (= rank (array-rank (truly-the array b))) + (dotimes (axis rank t) + (unless (= (%array-dimension a axis) + (%array-dimension b axis)) + (return nil))) + (with-array-data ((x a) (start-x) (end-x) + :force-inline t :array-header-p t) + (with-array-data ((y b) (start-y) (end-y) + :force-inline t :array-header-p t) + (declare (ignore end-y)) + (data-vector-compare x y start-x end-x start-y))))))))) (defun equalp (x y) "Just like EQUAL, but more liberal in several respects. @@ -486,30 +507,23 @@ length and have identical components. Other arrays must be EQ to be EQUAL." (and (consp y) (equalp (car x) (car y)) (equalp (cdr x) (cdr y)))) - ((pathnamep x) - (and (pathnamep y) (pathname= x y))) - ((hash-table-p x) - (and (hash-table-p y) - (hash-table-equalp x y))) ((%instancep x) (and (%instancep y) - (instance-equalp x y))) - ((and (simple-vector-p x) (simple-vector-p y)) - (let ((len (length x))) - (and (= len (length y)) - (loop for i below len ; somewhat faster than the generic loop - always (let ((a (svref x i)) (b (svref y i))) - (or (eq a b) (equalp a b))))))) - ((and (bit-vector-p x) (bit-vector-p y)) - (bit-vector-= x y)) - ((vectorp x) - (and (vectorp y) - (vector-equalp x y))) + (let ((layout (%instance-layout x))) + (and (logtest (logior +structure-layout-flag+ +pathname-layout-flag+) + (layout-flags layout)) + (eq (%instance-layout y) layout) + (funcall (wrapper-equalp-impl (layout-friend layout)) + x y))))) ((arrayp x) (and (arrayp y) - (array-equalp x y))) + ;; string-equal is nearly 2x the speed of array-equalp for comparing strings + (cond ((and (stringp x) (stringp y)) (string-equal x y)) + ((and (bit-vector-p x) (bit-vector-p y)) (bit-vector-= x y)) + (t (array-equalp x y))))) (t nil))) +#-sb-show ;; I don't know why these tests crash with #+sb-show (let ((test-cases `(($0.0 $-0.0 t) ($0.0 $1.0 nil) ;; There is no cross-compiler #C reader macro. @@ -529,4 +543,14 @@ length and have identical components. Other arrays must be EQ to be EQUAL." (bresult (if result 1 0)) (expected-bresult (if expected-result 1 0))) (unless (= bresult expected-bresult) + ;; If a test fails, there's a chance of getting into a recursive error here + ;; because, among other things, *BASE-CHAR-NAME-ALIST* has not been filled in, + ;; so then you're get into an error printing#(#\h #\E #\l #\l #\o). + ;; Hopefully the write-string calls will work though. + (progn + (write-string "test failed: ") + (write (get-lisp-obj-address x) :base 16 :radix t) + (write-char #\space) + (write (get-lisp-obj-address y) :base 16 :radix t) + (terpri)) (error "failed test (EQUALP ~S ~S)" x y)))))) diff --git a/src/code/primordial-extensions.lisp b/src/code/primordial-extensions.lisp index 0a27ba859d..de168d1554 100644 --- a/src/code/primordial-extensions.lisp +++ b/src/code/primordial-extensions.lisp @@ -61,7 +61,7 @@ (stem (if (every #'alpha-char-p symbol-name) symbol-name (string (gensymify* symbol-name "-"))))) - `(,symbol (sb-xc:gensym ,stem)))) + `(,symbol (gensym ,stem)))) symbols) ,@body)) @@ -69,7 +69,7 @@ ;;; macros and other code-manipulating code.) (defun make-gensym-list (n &optional name) (let ((arg (if name (string name) "G"))) - (loop repeat n collect (sb-xc:gensym arg)))) + (loop repeat n collect (gensym arg)))) ;;;; miscellany @@ -92,8 +92,8 @@ (defun gensymify (x) (if (symbolp x) - (sb-xc:gensym (symbol-name x)) - (sb-xc:gensym))) + (gensym (symbol-name x)) + (gensym))) (eval-when (:load-toplevel :execute #+sb-xc-host :compile-toplevel) (labels ((symbol-concat (package &rest things) @@ -274,26 +274,16 @@ ;;; Otherwise, evaluate DEFAULT, store the resulting value in ;;; HASH-TABLE and return two values: 1) the result of evaluating ;;; DEFAULT 2) NIL. -;;; If ATOMICP is true, perform the lookup and potential update -;;; atomically. -(defmacro ensure-gethash (key hash-table &optional default atomicp) - (check-type atomicp boolean) +(defmacro ensure-gethash (key hash-table default) (with-unique-names (n-key n-hash-table value foundp) - (flet ((probe-and-update (&optional update) - `(multiple-value-bind (,value ,foundp) (gethash ,n-key ,n-hash-table) - (if ,foundp - (values ,value t) - ,(or update - `(values (setf (gethash ,n-key ,n-hash-table) ,default) nil)))))) - `(let ((,n-key ,key) - (,n-hash-table ,hash-table)) - ,(if atomicp - (probe-and-update `(with-locked-system-table (,n-hash-table) - ,(probe-and-update))) - (probe-and-update)))))) + `(let ((,n-key ,key) + (,n-hash-table ,hash-table)) + (multiple-value-bind (,value ,foundp) (gethash ,n-key ,n-hash-table) + (if ,foundp + (values ,value t) + (values (setf (gethash ,n-key ,n-hash-table) ,default) nil)))))) (defvar *!removable-symbols* nil) -(push '("SB-INT" check-designator) *!removable-symbols*) (defun %defconstant-eqx-value (symbol expr eqx) (declare (type function eqx)) @@ -312,39 +302,15 @@ ;;; #+sb-xc-host (defmacro defconstant-eqx (symbol expr eqx &optional doc) - ;; CLISP needs the EVAL-WHEN here, or else the symbol defined is unavailable - ;; for later uses within the same file. For instance, in x86-64/vm, defining - ;; TEMP-REG-TN as R11-TN would get an error that R11-TN is unbound. - ;; We don't want that junk in our expansion, especially as our requirement - ;; is to separate the compile-time and load-time effect. + ;; CLISP needs the EVAL-WHEN here, or else the symbol defined is + ;; unavailable for later uses within the same file. For instance, in + ;; x86-64/vm, defining TEMP-REG-TN as R11-TN would get an error that + ;; R11-TN is unbound. We don't want that junk in our expansion. `(eval-when (:compile-toplevel :load-toplevel :execute) (defconstant ,symbol (%defconstant-eqx-value ',symbol ,expr ,eqx) ,@(when doc (list doc))))) -;;; This is the expansion as it should be for us, but notice that this -;;; recapitulation of the macro is actually not defined at compile-time. #-sb-xc-host -(let () - (defmacro defconstant-eqx (symbol expr eqx &optional doc) - `(defconstant ,symbol (%defconstant-eqx-value ',symbol ,expr ,eqx) - ,@(when doc (list doc))))) - -;;; Special variant at cross-compile-time. Face it: the "croak-if-not-EQx" test -;;; is irrelevant - there can be no pre-existing value to test against. -;;; The extra magic is that we need to discern between constants simple enough -;;; to assigned during genesis (cold-load) from those assigned in cold-init. -;;; This choice informs the compiler how to emit references to the symbol. -(defvar sb-c::*!const-value-deferred* '()) -#-sb-xc-host -(eval-when (:compile-toplevel) - (sb-xc:defmacro defconstant-eqx (symbol expr eqx &optional doc) - (let ((constp (sb-xc:constantp expr))) - `(progn - (eval-when (:compile-toplevel) - (sb-xc:defconstant ,symbol (%defconstant-eqx-value ',symbol ,expr ,eqx)) - ,@(unless constp - `((push ',symbol sb-c::*!const-value-deferred*)))) - (eval-when (:load-toplevel) - (sb-c::%defconstant ',symbol - ,(if constp `',(constant-form-value expr) expr) - (sb-c:source-location) ,@(when doc (list doc)))))))) +(defmacro defconstant-eqx (symbol expr eqx &optional doc) + `(defconstant ,symbol (%defconstant-eqx-value ',symbol ,expr ,eqx) + ,@(when doc (list doc)))) diff --git a/src/code/primordial-type.lisp b/src/code/primordial-type.lisp index fed5f4e378..3c4d5a5126 100644 --- a/src/code/primordial-type.lisp +++ b/src/code/primordial-type.lisp @@ -18,16 +18,16 @@ ;; Toggle some bits so that the hash is not equal to the hash ;; for a classoid of this name (relevant for named type T only) (perturbed-bit-string - (let ((string (format nil "~32,'0b" name-hash))) - (concatenate 'string - (subseq string 0 22) (reverse (subseq string 22))))) + (let ((string (format nil "~32,'0b" name-hash))) + (concatenate 'string + (subseq string 0 22) (reverse (subseq string 22))))) (bits `(pack-interned-ctype-bits 'named ,(parse-integer perturbed-bit-string :radix 2) ,(case type - ((*) 31) - ((nil t) (sb-vm::saetp-index-or-lose type)) - (t nil))))) + ((*) 31) + ((nil t) (sb-vm::saetp-index-or-lose type)) + (t nil))))) (declare (ignorable bits)) ; not used in XC `(progn #+sb-xc-host @@ -35,55 +35,60 @@ ;; Make it known as a constant in the cross-compiler. (setf (info :variable :kind ',global-sym) :constant)) (!cold-init-forms - #+sb-xc (sb-c::%defconstant ',global-sym ,global-sym - (sb-c:source-location)) - (setf (info :type :builtin ',type) ,global-sym + #+sb-xc (sb-impl::%defconstant ',global-sym ,(symbol-value global-sym) + (sb-c:source-location)) + (setf (info :type :builtin ',type) #+sb-xc-host ,global-sym #-sb-xc-host ,(symbol-value global-sym) (info :type :kind ',type) :primitive)))))) - ;; KLUDGE: In ANSI, * isn't really the name of a type, it's just a - ;; special symbol which can be stuck in some places where an - ;; ordinary type can go, e.g. (ARRAY * 1) instead of (ARRAY T 1). - ;; In SBCL it also used to denote universal VALUES type. - (frob * *wild-type*) - (frob nil *empty-type*) - (frob t *universal-type*) - ;; new in sbcl-0.9.5: these used to be CLASSOID types, but that - ;; view of them was incompatible with requirements on the MOP - ;; metaobject class hierarchy: the INSTANCE and - ;; FUNCALLABLE-INSTANCE types are disjoint (instances have - ;; instance-pointer-lowtag; funcallable-instances have - ;; fun-pointer-lowtag), while FUNCALLABLE-STANDARD-OBJECT is - ;; required to be a subclass of STANDARD-OBJECT. -- CSR, - ;; 2005-09-09 - (frob instance *instance-type*) - (frob funcallable-instance *funcallable-instance-type*) - ;; new in sbcl-1.0.3.3: necessary to act as a join point for the - ;; extended sequence hierarchy. (Might be removed later if we use - ;; a dedicated FUNDAMENTAL-SEQUENCE class for this.) - (frob extended-sequence *extended-sequence-type*)) + ;; KLUDGE: In ANSI, * isn't really the name of a type, it's just a + ;; special symbol which can be stuck in some places where an + ;; ordinary type can go, e.g. (ARRAY * 1) instead of (ARRAY T 1). + ;; In SBCL it also used to denote universal VALUES type. + (frob * *wild-type*) + (frob nil *empty-type*) + (frob t *universal-type*) + ;; new in sbcl-0.9.5: these used to be CLASSOID types, but that + ;; view of them was incompatible with requirements on the MOP + ;; metaobject class hierarchy: the INSTANCE and + ;; FUNCALLABLE-INSTANCE types are disjoint (instances have + ;; instance-pointer-lowtag; funcallable-instances have + ;; fun-pointer-lowtag), while FUNCALLABLE-STANDARD-OBJECT is + ;; required to be a subclass of STANDARD-OBJECT. -- CSR, + ;; 2005-09-09 + (frob instance *instance-type*) + (frob funcallable-instance *funcallable-instance-type*) + ;; new in sbcl-1.0.3.3: necessary to act as a join point for the + ;; extended sequence hierarchy. (Might be removed later if we use + ;; a dedicated FUNDAMENTAL-SEQUENCE class for this.) + (frob extended-sequence *extended-sequence-type*)) -(!defun-from-collected-cold-init-forms !primordial-type-cold-init) +#-sb-xc-host +(progn +;;; a vector that maps widetags to layouts, used for quickly finding +;;; the layouts of built-in classes +(define-load-time-global **primitive-object-layouts** nil) +(declaim (type simple-vector **primitive-object-layouts**))) + +#-sb-xc-host +(!cold-init-forms -;;; A HAIRY-TYPE represents anything too weird to be described -;;; reasonably or to be useful, such as NOT, SATISFIES, unknown types, -;;; and unreasonably complicated types involving AND. We just remember -;;; the original type spec. -;;; A possible improvement would be for HAIRY-TYPE to have a subtype -;;; named SATISFIES-TYPE for the hairy types which are specifically -;;; of the form (SATISFIES pred) so that we don't have to examine -;;; the sexpr repeatedly to decide whether it takes that form. -;;; And as a further improvement, we might want a table that maps -;;; predicates to their exactly recognized type when possible. -;;; We have such a table in fact - *BACKEND-PREDICATE-TYPES* -;;; as a starting point. But something like PLUSP isn't in there. -;;; On the other hand, either of these points may not be sources of -;;; inefficiency, and the latter if implemented might have undesirable -;;; user-visible ramifications, though it seems unlikely. -(defstruct (hairy-type (:include ctype) - (:constructor %make-hairy-type - (specifier &aux (%bits (pack-ctype-bits hairy)))) - (:constructor !make-interned-hairy-type - (specifier &aux (%bits (pack-interned-ctype-bits 'hairy)))) - (:copier nil)) - ;; the Common Lisp type-specifier of the type we represent. - ;; For other than an unknown type, this must be a (SATISFIES f) expression. - (specifier nil :type t :read-only t)) +;; This vector is allocated in immobile space when possible. There isn't +;; a way to do that from lisp, so it's special-cased in genesis. +#-immobile-space (setq **primitive-object-layouts** (make-array 256)) +;; If #+metaspace, we can't generally store layouts in heap objects except in +;; the instance header, but this vector can because it too will go in metaspace. +(map-into **primitive-object-layouts** + (lambda (name) (wrapper-friend (classoid-wrapper (find-classoid name)))) + #.(let ((table (make-array 256 :initial-element 'sb-kernel::random-class))) + (dolist (x sb-kernel::*builtin-classoids*) + (destructuring-bind (name &key codes &allow-other-keys) x + (dolist (code codes) + (setf (svref table code) name)))) + (loop for i from sb-vm:list-pointer-lowtag by (* 2 sb-vm:n-word-bytes) + below 256 + do (setf (aref table i) 'cons)) + (loop for i from sb-vm:even-fixnum-lowtag by (ash 1 sb-vm:n-fixnum-tag-bits) + below 256 + do (setf (aref table i) 'fixnum)) + table))) + +(!defun-from-collected-cold-init-forms !primordial-type-cold-init) diff --git a/src/code/print.lisp b/src/code/print.lisp index f8a9153d49..452afedc72 100644 --- a/src/code/print.lisp +++ b/src/code/print.lisp @@ -13,56 +13,56 @@ ;;;; exported printer control variables -;; NB: all of the following are initialized during genesis -(defparameter *print-readably* nil +(defvar *print-readably* nil "If true, all objects will be printed readably. If readable printing is impossible, an error will be signalled. This overrides the value of *PRINT-ESCAPE*.") -(defparameter *print-escape* t +(defvar *print-escape* t "Should we print in a reasonably machine-readable way? (possibly overridden by *PRINT-READABLY*)") -(defparameter *print-pretty* nil ; (set later when pretty-printer is initialized) +(defvar *print-pretty* nil ; (set later when pretty-printer is initialized) "Should pretty printing be used?") -(defparameter *print-base* 10. +(defvar *print-base* 10. "The output base for RATIONALs (including integers).") -(defparameter *print-radix* nil +(defvar *print-radix* nil "Should base be verified when printing RATIONALs?") -(defparameter *print-level* nil +(defvar *print-level* nil "How many levels should be printed before abbreviating with \"#\"?") -(defparameter *print-length* nil +(defvar *print-length* nil "How many elements at any level should be printed before abbreviating with \"...\"?") -(defparameter *print-vector-length* nil +(defvar *print-vector-length* nil "Like *PRINT-LENGTH* but works on strings and bit-vectors. Does not affect the cases that are already controlled by *PRINT-LENGTH*") -(defparameter *print-circle* nil +(defvar *print-circle* nil "Should we use #n= and #n# notation to preserve uniqueness in general (and circularity in particular) when printing?") -(defparameter *print-case* :upcase +(defvar *print-case* :upcase "What case should the printer should use default?") -(defparameter *print-array* t +(defvar *print-array* t "Should the contents of arrays be printed?") -(defparameter *print-gensym* t +(defvar *print-gensym* t "Should #: prefixes be used when printing symbols with null SYMBOL-PACKAGE?") -(defparameter *print-lines* nil +(defvar *print-lines* nil "The maximum number of lines to print per object.") -(defparameter *print-right-margin* nil +(defvar *print-right-margin* nil "The position of the right margin in ems (for pretty-printing).") -(defparameter *print-miser-width* nil +(defvar *print-miser-width* nil "If the remaining space between the current column and the right margin is less than this, then print using ``miser-style'' output. Miser style conditional newlines are turned on, and all indentations are turned off. If NIL, never use miser mode.") (defvar *print-pprint-dispatch* - (sb-pretty::make-pprint-dispatch-table nil nil nil) ; for type-correctness + (sb-pretty::make-pprint-dispatch-table #() nil nil) "The pprint-dispatch-table that controls how to pretty-print objects.") -(defparameter *suppress-print-errors* nil +(defvar *suppress-print-errors* nil "Suppress printer errors when the condition is of the type designated by this variable: an unreadable object representing the error is printed instead.") ;; duplicate defglobal because this file is compiled before "reader" (define-load-time-global *standard-readtable* nil) +(define-load-time-global sb-pretty::*standard-pprint-dispatch-table* nil) (defun %with-standard-io-syntax (function) (declare (type function function)) (declare (dynamic-extent function)) @@ -193,9 +193,8 @@ variable: an unreadable object representing the error is printed instead.") (multiple-value-bind (fun pretty) (and *print-pretty* (pprint-dispatch object)) (if pretty - (with-simple-output-to-string (stream) - (sb-pretty::with-pretty-stream (stream) - (funcall fun stream object))) + (%with-output-to-string (stream) + (sb-pretty:output-pretty-object stream fun object)) (let ((buffer-size (approx-chars-in-repr object))) (let* ((string (make-string buffer-size :element-type 'base-char)) (stream (%make-finite-base-string-output-stream string))) @@ -206,7 +205,7 @@ variable: an unreadable object representing the error is printed instead.") (finite-base-string-output-stream-pointer stream))))))) ;; Could do something for other numeric types, symbols, ... (t - (with-simple-output-to-string (stream) + (%with-output-to-string (stream) (output-object object stream))))) ;;; Estimate the number of chars in the printed representation of OBJECT. @@ -218,7 +217,7 @@ variable: an unreadable object representing the error is printed instead.") ;; This is exact for bases which are exactly a power-of-2, or an overestimate ;; otherwise, as mandated by the finite output stream. (let ((bits-per-char - (aref #.(sb-xc:coerce + (aref #.(coerce ;; base 2 or base 3 = 1 bit per character ;; base 4 .. base 7 = 2 bits per character ;; base 8 .. base 15 = 3 bits per character, etc @@ -285,6 +284,208 @@ variable: an unreadable object representing the error is printed instead.") (print-description) (write-char #\> stream))))) nil) + + +;;;; circularity detection stuff + +;;; When *PRINT-CIRCLE* is T, this gets bound to a hash table that +;;; (eventually) ends up with entries for every object printed. When +;;; we are initially looking for circularities, we enter a T when we +;;; find an object for the first time, and a 0 when we encounter an +;;; object a second time around. When we are actually printing, the 0 +;;; entries get changed to the actual marker value when they are first +;;; printed. +(defvar *circularity-hash-table* nil) + +;;; When NIL, we are just looking for circularities. After we have +;;; found them all, this gets bound to 0. Then whenever we need a new +;;; marker, it is incremented. +(defvar *circularity-counter* nil) + +;;; Check to see whether OBJECT is a circular reference, and return +;;; something non-NIL if it is. If ASSIGN is true, reference +;;; bookkeeping will only be done for existing entries, no new +;;; references will be recorded. If ASSIGN is true, then the number to +;;; use in the #n= and #n# noise is assigned at this time. +;;; +;;; Note: CHECK-FOR-CIRCULARITY must be called *exactly* once with +;;; ASSIGN true, or the circularity detection noise will get confused +;;; about when to use #n= and when to use #n#. If this returns non-NIL +;;; when ASSIGN is true, then you must call HANDLE-CIRCULARITY on it. +;;; If CHECK-FOR-CIRCULARITY returns :INITIATE as the second value, +;;; you need to initiate the circularity detection noise, e.g. bind +;;; *CIRCULARITY-HASH-TABLE* and *CIRCULARITY-COUNTER* to suitable values +;;; (see #'OUTPUT-OBJECT for an example). +;;; +;;; Circularity detection is done in two places, OUTPUT-OBJECT and +;;; WITH-CIRCULARITY-DETECTION (which is used from PPRINT-LOGICAL-BLOCK). +;;; These checks aren't really redundant (at least I can't really see +;;; a clean way of getting by with the checks in only one of the places). +;;; This causes problems when mixed with pprint-dispatching; an object is +;;; marked as visited in OUTPUT-OBJECT, dispatched to a pretty printer +;;; that uses PPRINT-LOGICAL-BLOCK (directly or indirectly), leading to +;;; output like #1=#1#. The MODE parameter is used for detecting and +;;; correcting this problem. +(defun check-for-circularity (object &optional assign (mode t)) + (when (null *print-circle*) + ;; Don't bother, nobody cares. + (return-from check-for-circularity nil)) + (let ((circularity-hash-table *circularity-hash-table*)) + (cond + ((null circularity-hash-table) + (values nil :initiate)) + ((null *circularity-counter*) + (ecase (gethash object circularity-hash-table) + ((nil) + ;; first encounter + (setf (gethash object circularity-hash-table) mode) + ;; We need to keep looking. + nil) + ((:logical-block) + (setf (gethash object circularity-hash-table) + :logical-block-circular) + t) + ((t) + (cond ((eq mode :logical-block) + ;; We've seen the object before in output-object, and now + ;; a second time in a PPRINT-LOGICAL-BLOCK (for example + ;; via pprint-dispatch). Don't mark it as circular yet. + (setf (gethash object circularity-hash-table) + :logical-block) + nil) + (t + ;; second encounter + (setf (gethash object circularity-hash-table) 0) + ;; It's a circular reference. + t))) + ((0 :logical-block-circular) + ;; It's a circular reference. + t))) + (t + (let ((value (gethash object circularity-hash-table))) + (case value + ((nil t :logical-block) + ;; If NIL, we found an object that wasn't there the + ;; first time around. If T or :LOGICAL-BLOCK, this + ;; object appears exactly once. Either way, just print + ;; the thing without any special processing. Note: you + ;; might argue that finding a new object means that + ;; something is broken, but this can happen. If someone + ;; uses the ~@<...~:> format directive, it conses a new + ;; list each time though format (i.e. the &REST list), + ;; so we will have different cdrs. + nil) + ;; A circular reference to something that will be printed + ;; as a logical block. Wait until we're called from + ;; PPRINT-LOGICAL-BLOCK with ASSIGN true before assigning the + ;; number. + ;; + ;; If mode is :LOGICAL-BLOCK and assign is false, return true + ;; to indicate that this object is circular, but don't assign + ;; it a number yet. This is necessary for cases like + ;; #1=(#2=(#2# . #3=(#1# . #3#))))). + (:logical-block-circular + (cond ((and (not assign) + (eq mode :logical-block)) + t) + ((and assign + (eq mode :logical-block)) + (let ((value (incf *circularity-counter*))) + ;; first occurrence of this object: Set the counter. + (setf (gethash object circularity-hash-table) value) + value)) + (t + nil))) + (0 + (if (eq assign t) + (let ((value (incf *circularity-counter*))) + ;; first occurrence of this object: Set the counter. + (setf (gethash object circularity-hash-table) value) + value) + t)) + (t + ;; second or later occurrence + (- value)))))))) + +;;; Handle the results of CHECK-FOR-CIRCULARITY. If this returns T then +;;; you should go ahead and print the object. If it returns NIL, then +;;; you should blow it off. +(defun handle-circularity (marker stream) + (case marker + (:initiate + ;; Someone forgot to initiate circularity detection. + (let ((*print-circle* nil)) + (error "trying to use CHECK-FOR-CIRCULARITY when ~ + circularity checking isn't initiated"))) + ((t :logical-block) + ;; It's a second (or later) reference to the object while we are + ;; just looking. So don't bother groveling it again. + nil) + (t + (write-char #\# stream) + (output-integer (abs marker) stream 10 nil) + (cond ((minusp marker) + (write-char #\# stream) + nil) + (t + (write-char #\= stream) + t))))) + +(defmacro with-circularity-detection ((object stream) &body body) + (with-unique-names (marker body-name) + `(labels ((,body-name () + ,@body)) + (cond ((or (not *print-circle*) + (uniquely-identified-by-print-p ,object)) + (,body-name)) + (*circularity-hash-table* + (let ((,marker (check-for-circularity ,object t :logical-block))) + (if ,marker + (when (handle-circularity ,marker ,stream) + (,body-name)) + (,body-name)))) + (t + (let ((*circularity-hash-table* (make-hash-table :test 'eq))) + (output-object ,object *null-broadcast-stream*) + (let ((*circularity-counter* 0)) + (let ((,marker (check-for-circularity ,object t + :logical-block))) + (when ,marker + (handle-circularity ,marker ,stream))) + (,body-name)))))))) + +;;;; level and length abbreviations + +;;; The current level we are printing at, to be compared against +;;; *PRINT-LEVEL*. See the macro DESCEND-INTO for a handy interface to +;;; depth abbreviation. +(defvar *current-level-in-print* 0) +(declaim (index *current-level-in-print*)) + +;;; Automatically handle *PRINT-LEVEL* abbreviation. If we are too +;;; deep, then a #\# is printed to STREAM and BODY is ignored. +(defmacro descend-into ((stream) &body body) + (let ((flet-name (gensym "DESCEND"))) + `(flet ((,flet-name () + ,@body)) + (cond ((and (null *print-readably*) + (let ((level *print-level*)) + (and level (>= *current-level-in-print* level)))) + (write-char #\# ,stream)) + (t + (let ((*current-level-in-print* (1+ *current-level-in-print*))) + (,flet-name))))))) + +;;; Punt if INDEX is equal or larger then *PRINT-LENGTH* (and +;;; *PRINT-READABLY* is NIL) by outputting \"...\" and returning from +;;; the block named NIL. +(defmacro punt-print-if-too-long (index stream) + `(when (and (not *print-readably*) + (let ((len *print-length*)) + (and len (>= ,index len)))) + (write-string "..." ,stream) + (return))) + ;;;; OUTPUT-OBJECT -- the main entry point @@ -309,8 +510,7 @@ variable: an unreadable object representing the error is printed instead.") (multiple-value-bind (fun pretty) (and *print-pretty* (pprint-dispatch object)) (if pretty - (sb-pretty::with-pretty-stream (stream) - (funcall fun stream object)) + (sb-pretty:output-pretty-object stream fun object) (output-ugly-object stream object)))) (handle-it (stream) (if *suppress-print-errors* @@ -342,7 +542,7 @@ variable: an unreadable object representing the error is printed instead.") (if (eq initiate :initiate) (let ((*circularity-hash-table* (make-hash-table :test 'eq))) - (check-it (make-broadcast-stream)) + (check-it *null-broadcast-stream*) (let ((*circularity-counter* 0)) (check-it stream))) ;; otherwise @@ -378,15 +578,24 @@ variable: an unreadable object representing the error is printed instead.") (return-from output-ugly-object (print-unreadable-object (object stream :identity t) (prin1 'instance stream)))) - (let ((classoid (layout-classoid layout))) - ;; Additionally, if the object is an obsolete CONDITION, don't crash. - ;; (There is no update-instance protocol for conditions) + (let* ((wrapper (layout-friend layout)) + (classoid (wrapper-classoid wrapper))) + ;; Additionally, don't crash if the object is an obsolete thing with + ;; no update protocol. (when (or (sb-kernel::undefined-classoid-p classoid) - (and (layout-invalid layout) - (logtest (layout-flags layout) +condition-layout-flag+))) + (and (wrapper-invalid wrapper) + (logtest (layout-flags layout) + (logior +structure-layout-flag+ + +condition-layout-flag+)))) (return-from output-ugly-object (print-unreadable-object (object stream :identity t) (format stream "UNPRINTABLE instance of ~W" classoid))))))) + (when (funcallable-instance-p object) + (let ((layout (%fun-layout object))) + (unless (logtest (get-lisp-obj-address layout) sb-vm:widetag-mask) + (return-from output-ugly-object + (print-unreadable-object (object stream :identity t) + (prin1 'funcallable-instance stream)))))) (print-object object stream)) ;;;; symbols @@ -397,14 +606,14 @@ variable: an unreadable object representing the error is printed instead.") (output-symbol object (sb-xc:symbol-package object) stream) ;; Write only the characters of the name, never the package (let ((rt *readtable*)) - (funcall (truly-the function - (choose-symbol-out-fun *print-case* (%readtable-case rt))) - (symbol-name object) stream rt)))) + (output-symbol-case-dispatch *print-case* (readtable-case rt) + (symbol-name object) stream rt)))) (defun output-symbol (symbol package stream) (let* ((readably *print-readably*) (readtable (if readably *standard-readtable* *readtable*)) - (out-fun (choose-symbol-out-fun *print-case* (%readtable-case readtable)))) + (print-case *print-case*) + (readtable-case (readtable-case readtable))) (flet ((output-token (name) (declare (type simple-string name)) (cond ((or (and (readtable-normalization readtable) @@ -423,7 +632,8 @@ variable: an unreadable object representing the error is printed instead.") (write-char char stream))) (write-char #\| stream)) (t - (funcall (truly-the function out-fun) name stream readtable))))) + (output-symbol-case-dispatch print-case readtable-case + name stream readtable))))) (let ((name (symbol-name symbol)) (current (sane-package))) (cond @@ -488,20 +698,23 @@ variable: an unreadable object representing the error is printed instead.") ;;; For each character, the value of the corresponding element is the ;;; lowest base in which that character is a digit. -(defconstant +digit-bases+ - #.(let ((a (sb-xc:make-array 128 ; FIXME +(defconstant-eqx +digit-bases+ + #.(let ((a (sb-xc:make-array base-char-code-limit + :retain-specialization-for-after-xc-core t :element-type '(unsigned-byte 8) :initial-element 36))) (dotimes (i 36 a) (let ((char (digit-char i 36))) - (setf (aref a (sb-xc:char-code char)) i))))) + (setf (aref a (char-code char)) i)))) + #'equalp) -(defconstant +character-attributes+ +(defconstant-eqx +character-attributes+ #.(let ((a (sb-xc:make-array 160 ; FIXME + :retain-specialization-for-after-xc-core t :element-type '(unsigned-byte 16) :initial-element 0))) (flet ((set-bit (char bit) - (let ((code (sb-xc:char-code char))) + (let ((code (char-code char))) (setf (aref a code) (logior bit (aref a code)))))) (dolist (char '(#\! #\@ #\$ #\% #\& #\* #\= #\~ #\[ #\] #\{ #\} @@ -511,12 +724,12 @@ variable: an unreadable object representing the error is printed instead.") (dotimes (i 10) (set-bit (digit-char i) number-attribute)) - (do ((code (sb-xc:char-code #\A) (1+ code)) - (end (sb-xc:char-code #\Z))) + (do ((code (char-code #\A) (1+ code)) + (end (char-code #\Z))) ((> code end)) (declare (fixnum code end)) - (set-bit (sb-xc:code-char code) uppercase-attribute) - (set-bit (char-downcase (sb-xc:code-char code)) lowercase-attribute)) + (set-bit (code-char code) uppercase-attribute) + (set-bit (char-downcase (code-char code)) lowercase-attribute)) (set-bit #\- sign-attribute) (set-bit #\+ sign-attribute) @@ -529,7 +742,8 @@ variable: an unreadable object representing the error is printed instead.") (dotimes (i 160) ; FIXME (when (zerop (aref a i)) (setf (aref a i) funny-attribute)))) - a)) + a) + #'equalp) ;;; A FSM-like thingie that determines whether a symbol is a potential ;;; number or has evil characters in it. @@ -564,13 +778,13 @@ variable: an unreadable object representing the error is printed instead.") (< (the fixnum (aref bases code)) base)))) (prog ((len (length name)) - (attributes +character-attributes+) - (bases +digit-bases+) + (attributes #.+character-attributes+) + (bases #.+digit-bases+) (base *print-base*) (letter-attribute - (case (%readtable-case readtable) - (#.+readtable-upcase+ uppercase-attribute) - (#.+readtable-downcase+ lowercase-attribute) + (case (readtable-case readtable) + (:upcase uppercase-attribute) + (:downcase lowercase-attribute) (t (logior lowercase-attribute uppercase-attribute)))) (index 0) (bits 0) @@ -694,6 +908,8 @@ variable: an unreadable object representing the error is printed instead.") ;;;; case hackery: One of these functions is chosen to output symbol ;;;; names according to the values of *PRINT-CASE* and READTABLE-CASE. +(declaim (start-block output-symbol-case-dispatch)) + ;;; called when: ;;; READTABLE-CASE *PRINT-CASE* ;;; :UPCASE :UPCASE @@ -728,7 +944,7 @@ variable: an unreadable object representing the error is printed instead.") (defun output-capitalize-symbol (pname stream readtable) (declare (simple-string pname)) (let ((prev-not-alphanum t) - (up (eql (%readtable-case readtable) +readtable-upcase+))) + (up (eq (readtable-case readtable) :upcase))) (dotimes (i (length pname)) (let ((char (char pname i))) (write-char (if up @@ -759,37 +975,23 @@ variable: an unreadable object representing the error is printed instead.") (t (write-string pname stream))))) -(defun choose-symbol-out-fun (print-case readtable-case) - (macrolet - ((compute-fun-vector (&aux (vector (make-array 12))) - ;; Pack a 2D array of functions into a simple-vector. - ;; Major axis is *PRINT-CASE*, minor axis is %READTABLE-CASE. - (dotimes (readtable-case-index 4) - (dotimes (print-case-index 3) - (let ((readtable-case - (elt '(:upcase :downcase :preserve :invert) readtable-case-index)) - (print-case - (elt '(:upcase :downcase :capitalize) print-case-index))) - (setf (aref vector (logior (ash print-case-index 2) - readtable-case-index)) - (case readtable-case - (:upcase - (case print-case - (:upcase 'output-preserve-symbol) - (:downcase 'output-lowercase-symbol) - (:capitalize 'output-capitalize-symbol))) - (:downcase - (case print-case - (:upcase 'output-uppercase-symbol) - (:downcase 'output-preserve-symbol) - (:capitalize 'output-capitalize-symbol))) - (:preserve 'output-preserve-symbol) - (:invert 'output-invert-symbol)))))) - `(load-time-value (vector ,@(map 'list (lambda (x) `(function ,x)) vector)) - t))) - (aref (compute-fun-vector) - (logior (case print-case (:upcase 0) (:downcase 4) (t 8)) - (truly-the (mod 4) readtable-case))))) +;;; Call an output function based on PRINT-CASE and READTABLE-CASE. +(defun output-symbol-case-dispatch (print-case readtable-case name stream readtable) + (ecase readtable-case + (:upcase + (ecase print-case + (:upcase (output-preserve-symbol name stream readtable)) + (:downcase (output-lowercase-symbol name stream readtable)) + (:capitalize (output-capitalize-symbol name stream readtable)))) + (:downcase + (ecase print-case + (:upcase (output-uppercase-symbol name stream readtable)) + (:downcase (output-preserve-symbol name stream readtable)) + (:capitalize (output-capitalize-symbol name stream readtable)))) + (:preserve (output-preserve-symbol name stream readtable)) + (:invert (output-invert-symbol name stream readtable)))) + +(declaim (end-block)) ;;;; recursive objects @@ -835,7 +1037,8 @@ variable: an unreadable object representing the error is printed instead.") (write-char #\" stream)) (t (write-string vector stream)))) - ((not (or *print-array* readably)) + ((or (null (array-element-type vector)) + (not (or *print-array* readably))) (output-terse-array vector stream)) ((bit-vector-p vector) (cond ((cut-length)) @@ -858,22 +1061,35 @@ variable: an unreadable object representing the error is printed instead.") (t (output-unreadable-array-readably vector stream)))))) -;;; This function outputs a string quoting characters sufficiently -;;; so that someone can read it in again. Basically, put a slash in -;;; front of an character satisfying NEEDS-SLASH-P. +;;; Output a string, quoting characters to be readable by putting a slash in front +;;; of any character satisfying NEEDS-SLASH-P. (defun quote-string (string stream) (macrolet ((needs-slash-p (char) ;; KLUDGE: We probably should look at the readtable, but just do ;; this for now. [noted by anonymous long ago] -- WHN 19991130 - `(or (char= ,char #\\) - (char= ,char #\")))) + `(let ((c ,char)) (or (char= c #\\) (char= c #\")))) + (scan (type) + ;; Pre-test for any escaping, and if needed, do char-at-a-time output. + ;; For 1 or 0 characters, always take the WRITE-CHAR branch. + `(let ((data (truly-the ,type data))) + (declare (optimize (sb-c:insert-array-bounds-checks 0))) + (when (or (<= (- end start) 1) + (do ((index start (1+ index))) + ((>= index end)) + (when (needs-slash-p (schar data index)) (return t)))) + (do ((index start (1+ index))) + ((>= index end) (return-from quote-string)) + (let ((char (schar data index))) + (when (needs-slash-p char) (write-char #\\ stream)) + (write-char char stream))))))) (with-array-data ((data string) (start) (end) :check-fill-pointer t) - (do ((index start (1+ index))) - ((>= index end)) - (let ((char (schar data index))) - (when (needs-slash-p char) (write-char #\\ stream)) - (write-char char stream)))))) + (if (simple-base-string-p data) + (scan simple-base-string) + #+sb-unicode (scan simple-character-string))) + ;; If no escaping needed, WRITE-STRING is way faster, up to 2x in my testing, + ;; than WRITE-CHAR because the stream layer will get so many fewer calls. + (write-string string stream))) (defun array-readably-printable-p (array) (and (eq (array-element-type array) t) @@ -886,7 +1102,7 @@ variable: an unreadable object representing the error is printed instead.") ;;; Output the printed representation of any array in either the #< or #A ;;; form. (defmethod print-object ((array array) stream) - (if (or *print-array* *print-readably*) + (if (and (or *print-array* *print-readably*) (array-element-type array)) (output-array-guts array stream) (output-terse-array array stream))) @@ -894,7 +1110,10 @@ variable: an unreadable object representing the error is printed instead.") (defun output-terse-array (array stream) (let ((*print-level* nil) (*print-length* nil)) - (print-unreadable-object (array stream :type t :identity t)))) + (if (and (not (array-element-type array)) *print-readably* *read-eval*) + (format stream "#.(~S '~D :ELEMENT-TYPE ~S)" + 'make-array (array-dimensions array) nil) + (print-unreadable-object (array stream :type t :identity t))))) ;;; Convert an array into a list that can be used with MAKE-ARRAY's ;;; :INITIAL-CONTENTS keyword argument. @@ -1107,7 +1326,7 @@ variable: an unreadable object representing the error is printed instead.") ;; "The function SB-KERNEL:SIMPLE-CHARACTER-STRING-P is undefined." ;; but a symbol-macrolet is ok. This is a FIXME except I don't care. (symbol-macrolet ((chars "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ")) - (declare (optimize (sb-c::insert-array-bounds-checks 0) speed)) + (declare (optimize (sb-c:insert-array-bounds-checks 0) speed)) (macrolet ((iterative-algorithm () `(loop (multiple-value-bind (q r) (truncate (truly-the word integer) base) @@ -1348,8 +1567,14 @@ variable: an unreadable object representing the error is printed instead.") (double-float double-float-min-e) #+long-float (long-float long-float-min-e)))) - (multiple-value-bind (f e) - (integer-decode-float float) + (multiple-value-bind (f e) (integer-decode-float float) + ;; An extra step became necessary here for subnormals because the + ;; algorithm assumes that the fraction is left-aligned in a field + ;; that is FLOAT-DIGITS wide. + (when (< (float-precision float) float-digits) + (let ((shift (- float-digits (integer-length f)))) + (setq f (ash f shift) + e (- e shift)))) (let ( ;; FIXME: these even tests assume normal IEEE rounding ;; mode. I wonder if we should cater for non-normal? (high-ok (evenp f)) @@ -1668,10 +1893,7 @@ variable: an unreadable object representing the error is printed instead.") (defmethod print-object ((component code-component) stream) (print-unreadable-object (component stream :identity t) (let (dinfo) - (cond ((code-obj-is-filler-p component) - (format stream "filler ~dw" - (ash (code-object-size component) (- sb-vm:word-shift)))) - ((eq (setq dinfo (%code-debug-info component)) :bpt-lra) + (cond ((eq (setq dinfo (%code-debug-info component)) :bpt-lra) (write-string "bpt-trap-return" stream)) ((functionp dinfo) (format stream "trampoline ~S" dinfo)) @@ -1689,7 +1911,7 @@ variable: an unreadable object representing the error is printed instead.") (write-string ", " stream) (output-object (sb-c::debug-info-name dinfo) stream))))))))) -#-(or x86 x86-64) +#-(or x86 x86-64 arm64 riscv) (defmethod print-object ((lra lra) stream) (print-unreadable-object (lra stream :identity t) (write-string "return PC object" stream))) @@ -1706,114 +1928,138 @@ variable: an unreadable object representing the error is printed instead.") #+sb-simd-pack (defmethod print-object ((pack simd-pack) stream) (cond ((and *print-readably* *read-eval*) - (multiple-value-bind (format maker extractor) - (etypecase pack - ((simd-pack double-float) - (values "#.(~S ~S ~S)" - '%make-simd-pack-double #'%simd-pack-doubles)) - ((simd-pack single-float) - (values "#.(~S ~S ~S ~S ~S)" - '%make-simd-pack-single #'%simd-pack-singles)) - (t - (values "#.(~S #X~16,'0X #X~16,'0X)" - '%make-simd-pack-ub64 #'%simd-pack-ub64s))) - (multiple-value-call - #'format stream format maker (funcall extractor pack)))) + (format stream "#.(~S #b~3,'0b #x~16,'0X #x~16,'0X)" + '%make-simd-pack + (%simd-pack-tag pack) + (%simd-pack-low pack) + (%simd-pack-high pack))) (*print-readably* (print-not-readable-error pack stream)) (t (print-unreadable-object (pack stream) - (flet ((all-ones-p (value start end &aux (mask (- (ash 1 end) (ash 1 start)))) - (= (logand value mask) mask)) - (split-num (value start) - (loop - for i from 0 to 3 - and v = (ash value (- start)) then (ash v -8) - collect (logand v #xFF)))) - (multiple-value-bind (low high) - (%simd-pack-ub64s pack) - (etypecase pack - ((simd-pack double-float) - (multiple-value-bind (v0 v1) (%simd-pack-doubles pack) - (format stream "~S~@{ ~:[~,13E~;~*TRUE~]~}" - 'simd-pack - (all-ones-p low 0 64) v0 - (all-ones-p high 0 64) v1))) - ((simd-pack single-float) - (multiple-value-bind (v0 v1 v2 v3) (%simd-pack-singles pack) - (format stream "~S~@{ ~:[~,7E~;~*TRUE~]~}" - 'simd-pack - (all-ones-p low 0 32) v0 - (all-ones-p low 32 64) v1 - (all-ones-p high 0 32) v2 - (all-ones-p high 32 64) v3))) - (t - (format stream "~S~@{ ~{ ~2,'0X~}~}" - 'simd-pack - (split-num low 0) (split-num low 32) - (split-num high 0) (split-num high 32)))))))))) + (etypecase pack + ((simd-pack double-float) + (multiple-value-call #'format stream "~S~@{ ~,13E~}" 'simd-pack + (%simd-pack-doubles pack))) + ((simd-pack single-float) + (multiple-value-call #'format stream "~S~@{ ~,7E~}" 'simd-pack + (%simd-pack-singles pack))) + ((simd-pack (unsigned-byte 8)) + (multiple-value-call #'format stream "~S~@{ ~3D~}" 'simd-pack + (%simd-pack-ub8s pack))) + ((simd-pack (unsigned-byte 16)) + (multiple-value-call #'format stream "~S~@{ ~5D~}" 'simd-pack + (%simd-pack-ub16s pack))) + ((simd-pack (unsigned-byte 32)) + (multiple-value-call #'format stream "~S~@{ ~10D~}" 'simd-pack + (%simd-pack-ub32s pack))) + ((simd-pack (unsigned-byte 64)) + (multiple-value-call #'format stream "~S~@{ ~20D~}" 'simd-pack + (%simd-pack-ub64s pack))) + ((simd-pack (signed-byte 8)) + (multiple-value-call #'format stream "~S~@{ ~4,@D~}" 'simd-pack + (%simd-pack-sb8s pack))) + ((simd-pack (signed-byte 16)) + (multiple-value-call #'format stream "~S~@{ ~6,@D~}" 'simd-pack + (%simd-pack-sb16s pack))) + ((simd-pack (signed-byte 32)) + (multiple-value-call #'format stream "~S~@{ ~11@D~}" 'simd-pack + (%simd-pack-sb32s pack))) + ((simd-pack (signed-byte 64)) + (multiple-value-call #'format stream "~S~@{ ~20@D~}" 'simd-pack + (%simd-pack-sb64s pack)))))))) #+sb-simd-pack-256 (defmethod print-object ((pack simd-pack-256) stream) (cond ((and *print-readably* *read-eval*) - (multiple-value-bind (format maker extractor) - (etypecase pack - ((simd-pack-256 double-float) - (values "#.(~@{~S~^ ~})" - '%make-simd-pack-256-double #'%simd-pack-256-doubles)) - ((simd-pack-256 single-float) - (values "#.(~@{~S~^ ~})" - '%make-simd-pack-256-single #'%simd-pack-256-singles)) - (t - (values "#.(~S~@{ #X~16,'0X~})" - '%make-simd-pack-256-ub64 #'%simd-pack-256-ub64s))) - (multiple-value-call - #'format stream format maker (funcall extractor pack)))) + (format stream "#.(~S #b~3,'0B #x~16,'0D #x~16,'0D #x~16,'0D #x~16,'0D)" + '%make-simd-pack-256 + (%simd-pack-256-tag pack) + (%simd-pack-256-0 pack) + (%simd-pack-256-1 pack) + (%simd-pack-256-2 pack) + (%simd-pack-256-3 pack))) (*print-readably* (print-not-readable-error pack stream)) (t (print-unreadable-object (pack stream) (etypecase pack ((simd-pack-256 double-float) - (multiple-value-call #'format stream "~S~@{ ~,13E~}" - 'simd-pack-256 + (multiple-value-call #'format stream "~S~@{ ~,13E~}" 'simd-pack-256 (%simd-pack-256-doubles pack))) ((simd-pack-256 single-float) - (multiple-value-call #'format stream "~S~@{ ~,7E~}" - 'simd-pack-256 + (multiple-value-call #'format stream "~S~@{ ~,7E~}" 'simd-pack-256 (%simd-pack-256-singles pack))) - (t - (multiple-value-bind (p0 p1 p2 p3) - (%simd-pack-256-ub64s pack) - (format stream "~S~@{ ~16,'0X~}" - 'simd-pack-256 - p0 p1 p2 p3)))))))) + ((simd-pack-256 (unsigned-byte 8)) + (multiple-value-call #'format stream "~S~@{ ~3D~}" 'simd-pack-256 + (%simd-pack-256-ub8s pack))) + ((simd-pack-256 (unsigned-byte 16)) + (multiple-value-call #'format stream "~S~@{ ~5D~}" 'simd-pack-256 + (%simd-pack-256-ub16s pack))) + ((simd-pack-256 (unsigned-byte 32)) + (multiple-value-call #'format stream "~S~@{ ~10D~}" 'simd-pack-256 + (%simd-pack-256-ub32s pack))) + ((simd-pack-256 (unsigned-byte 64)) + (multiple-value-call #'format stream "~S~@{ ~20D~}" 'simd-pack-256 + (%simd-pack-256-ub64s pack))) + ((simd-pack-256 (signed-byte 8)) + (multiple-value-call #'format stream "~S~@{ ~4@D~}" 'simd-pack-256 + (%simd-pack-256-sb8s pack))) + ((simd-pack-256 (signed-byte 16)) + (multiple-value-call #'format stream "~S~@{ ~6@D~}" 'simd-pack-256 + (%simd-pack-256-sb16s pack))) + ((simd-pack-256 (signed-byte 32)) + (multiple-value-call #'format stream "~S~@{ ~11@D~}" 'simd-pack-256 + (%simd-pack-256-sb32s pack))) + ((simd-pack-256 (signed-byte 64)) + (multiple-value-call #'format stream "~S~@{ ~20@D~}" 'simd-pack-256 + (%simd-pack-256-sb64s pack)))))))) ;;;; functions (defmethod print-object ((object function) stream) + (macrolet ((unprintable-instance-p (x) + ;; Guard against calling %FUN-FUN if it would return 0. + ;; %FUNCALLABLE-INSTANCE-FUN is known to return FUNCTION so determining + ;; whether it is actually assigned requires a low-level trick. + (let ((s (sb-vm::primitive-object-slot + (sb-vm:primitive-object 'funcallable-instance) + 'function))) + `(and (funcallable-instance-p ,x) + (eql 0 (%primitive sb-alien:slot ,x 'function ,(sb-vm:slot-offset s) + ,sb-vm:fun-pointer-lowtag)))))) + (when (unprintable-instance-p object) + (return-from print-object + (print-unreadable-object (object stream :type t :identity t))))) (let* ((name (%fun-name object)) (proper-name-p (and (legal-fun-name-p name) (fboundp name) (eq (fdefinition name) object)))) ;; ":TYPE T" is no good, since CLOSURE doesn't have full-fledged status. (print-unreadable-object (object stream :identity (not proper-name-p)) (format stream "~A~@[ ~S~]" - ;; TYPE-OF is so that GFs print as #<STANDARD-GENERIC-FUNCTION> - ;; and not #<FUNCTION> before SRC;PCL;PRINT-OBJECT is loaded. - (if (closurep object) 'closure (type-of object)) + ;; CLOSURE and SIMPLE-FUN should print as #<FUNCTION> + ;; but anything else prints as its exact type. + (if (funcallable-instance-p object) (type-of object) 'function) name)))) ;;;; catch-all for unknown things -(declaim (inline lowtag-of)) -(defun lowtag-of (x) (logand (get-lisp-obj-address x) sb-vm:lowtag-mask)) - (defmethod print-object ((object t) stream) (when (eq object sb-pcl:+slot-unbound+) ;; If specifically the unbound marker with 0 data, ;; as opposed to any other unbound marker. (print-unreadable-object (object stream) (write-string "unbound" stream)) (return-from print-object)) + ;; NO-TLS-VALUE was added here as a printable object type for #+ubsan which, + ;; among other things, detects read-before-write on a per-array-element basis. + ;; Git rev 22d8038118 caused uninitialized SIMPLE-VECTORs to get prefilled + ;; with NO_TLS_VALUE_MARKER, but a better choice would be + ;; (logior (mask-field (byte (- n-word-bits 8) 8) -1) unbound-marker-widetag). + ;; #+ubsan has probably bitrotted for other reasons, so this is untested. + #+ubsan + (when (eql (get-lisp-obj-address object) unwritten-vector-element-marker) + (print-unreadable-object (object stream) (write-string "novalue" stream)) + (return-from print-object)) (print-unreadable-object (object stream :identity t) (let ((lowtag (lowtag-of object))) (case lowtag @@ -1823,6 +2069,7 @@ variable: an unreadable object representing the error is printed instead.") (#.sb-vm:value-cell-widetag (write-string "value cell " stream) (output-object (value-cell-ref object) stream)) + #+nil (#.sb-vm:filler-widetag (write-string "pad " stream) (write (1+ (get-header-data object)) :stream stream) diff --git a/src/code/profile.lisp b/src/code/profile.lisp index bac261807f..40f425e504 100644 --- a/src/code/profile.lisp +++ b/src/code/profile.lisp @@ -68,9 +68,6 @@ ;;;; High resolution timer -;;; FIXME: High resolution this is not. Build a microsecond-accuracy version -;;; on top of unix-getrusage, maybe. - (defconstant +ticks-per-second+ internal-time-units-per-second) (declaim (inline get-internal-ticks)) diff --git a/src/code/quantifiers.lisp b/src/code/quantifiers.lisp index 85f442d30d..8061118659 100644 --- a/src/code/quantifiers.lisp +++ b/src/code/quantifiers.lisp @@ -15,13 +15,13 @@ ;;; arbitrary sequence arguments, both in the full call case and in ;;; the open code case. (flet ((expand (pred sequences test found-result unfound-result) - (unless (proper-list-of-length-p sequences 1 sb-xc:call-arguments-limit) + (unless (proper-list-of-length-p sequences 1 call-arguments-limit) (return-from expand (values nil t))) ; give up (binding* ((elements (make-gensym-list (length sequences))) ((bind-fun call-it) (funarg-bind/call-forms pred elements)) - (blockname (sb-xc:gensym "BLOCK")) - (wrapper (sb-xc:gensym "WRAPPER")) - (value (sb-xc:gensym "VAL"))) + (blockname (gensym "BLOCK")) + (wrapper (gensym "WRAPPER")) + (value (gensym "VAL"))) (let ((form `(block ,blockname ;; Does DX actually help? INLINE should win anyway. diff --git a/src/code/reader.lisp b/src/code/reader.lisp index 8b7f36c55a..f816756edc 100644 --- a/src/code/reader.lisp +++ b/src/code/reader.lisp @@ -16,10 +16,14 @@ ;;; ANSI: "the floating-point format that is to be used when reading a ;;; floating-point number that has no exponent marker or that has e or ;;; E for an exponent marker" -(defparameter *read-default-float-format* 'single-float) +(defvar *read-default-float-format* 'single-float) (defvar *readtable*) +(defun !readtable-cold-init () + (setq *empty-extended-char-table* (make-hash-table :rehash-size 1 :test #'eq) + *readtable* (make-readtable))) + (setf (documentation '*readtable* 'variable) "Variable bound to current readtable.") @@ -37,15 +41,15 @@ ;;;; reader errors (defun reader-eof-error (stream context) - (declare (optimize allow-non-returning-tail-call)) + ;; Don't worry if STREAM isn't a valid stream; it's not a reason to fail now. + (declare (explicit-check) (optimize allow-non-returning-tail-call)) (error 'reader-eof-error :stream stream :context context)) -;;; If The Gods didn't intend for us to use multiple namespaces, why -;;; did They specify them? (defun simple-reader-error (stream control &rest args) - (declare (optimize allow-non-returning-tail-call)) + ;; Don't worry if STREAM isn't a valid stream; it's not a reason to fail now. + (declare (explicit-check) (optimize allow-non-returning-tail-call)) (error 'simple-reader-error :stream stream :format-control control @@ -53,89 +57,93 @@ ;;;; macros and functions for character tables -(declaim (ftype (sfunction (character readtable) (unsigned-byte 8)) - get-cat-entry)) -(defun get-cat-entry (char rt) - (if (typep char 'base-char) - (elt (character-attribute-array rt) (char-code char)) - (values (gethash char (character-attribute-hash-table rt) - +char-attr-constituent+)))) - -(defun set-cat-entry (char newvalue &optional (rt *readtable*)) - (declare (character char) (type (unsigned-byte 8) newvalue) (readtable rt)) - (if (typep char 'base-char) - (setf (elt (character-attribute-array rt) (char-code char)) newvalue) - (if (= newvalue +char-attr-constituent+) - ;; Default value for the C-A-HASH-TABLE is +CHAR-ATTR-CONSTITUENT+. - (remhash char (character-attribute-hash-table rt)) - (setf (gethash char (character-attribute-hash-table rt)) newvalue))) - (values)) - -;; Set the character-macro-table entry without coercing NEW-VALUE. -;; As used by set-syntax-from-char it must always process "raw" values. -(defun set-cmt-entry (char new-value &optional (rt *readtable*)) - (declare (character char) - (type (or null function fdefn) new-value) - (type readtable rt)) +;;; As efficiently as possible look up the character attributes of CHAR. +;;; If CAST is true then insert an assertion that CHARACTER is actually +;;; a character. This seems to be necessary to ensure that gray stream +;;; methods that should return characters don't return random objects. +(defmacro char-syntax (char syntax-array extension-table &optional cast) + #-sb-unicode (declare (ignore cast)) + `(progn + #-sb-unicode ,extension-table + (truly-the (unsigned-byte 8) + #-sb-unicode + (elt ,syntax-array (char-code ,char)) + #+sb-unicode + (if (typep ,char 'base-char) + (elt ,syntax-array (char-code ,char)) + (car (truly-the list + (gethash ,(if cast `(the character ,char) char) + ,extension-table + ',`(,+char-attr-constituent+)))))))) + +;;; Formerly known as SET-CAT-ENTRY and SET-CMT-ENTRY +(defun assign-char-syntax (readtable char attributes function) + (declare (readtable readtable) + (character char) + (type (unsigned-byte 8) attributes) + (type (or function symbol) function)) (if (typep char 'base-char) - (setf (svref (character-macro-array rt) (char-code char)) new-value) - (if new-value ; never store NILs - (setf (gethash char (character-macro-hash-table rt)) new-value) - (remhash char (character-macro-hash-table rt))))) - -;;; the value actually stored in the character macro table. As per -;;; ANSI #'GET-MACRO-CHARACTER and #'SET-MACRO-CHARACTER, this can -;;; be either a function-designator or NIL, except that we store -;;; symbols not as themselves but as their #<fdefn>. + (setf (aref (base-char-syntax-array readtable) (char-code char)) attributes + (aref (base-char-macro-array readtable) (char-code char)) function) + (let ((table (extended-char-table readtable))) + (cond ((or function (/= attributes +char-attr-constituent+)) + (when (eq table *empty-extended-char-table*) ; copy-on-write + (setf table (make-hash-table :test 'eq) + (extended-char-table readtable) table)) + (setf (gethash char table) (cons attributes function))) + ((neq table *empty-extended-char-table*) + (remhash char table))))) + nil) + +;;; Get the value stored in the character macro table for CHAR. As per +;;; ANSI #'GET-MACRO-CHARACTER and #'SET-MACRO-CHARACTER, this return as +;;; function-designator (possibly NIL). (defun get-raw-cmt-entry (char readtable) (declare (character char) (readtable readtable)) (if (typep char 'base-char) - (svref (character-macro-array readtable) (char-code char)) - (values (gethash char (character-macro-hash-table readtable) nil)))) - -;; As above but get the entry for SUB-CHAR in a dispatching macro table. + (svref (base-char-macro-array readtable) (char-code char)) + ;; extended-char entry if present is a cons of the attributes and function + (cdr (truly-the list (gethash char (extended-char-table readtable)))))) + +;;; As above but get the entry for SUB-CHAR in a dispatching macro table. +(defmacro charmacro-dtable-base-chars (dtable) + `(truly-the (simple-vector ,base-char-code-limit) (car ,dtable))) +(defmacro charmacro-dtable-extended-chars (dtable) + `(cdr ,dtable)) (defun get-raw-cmt-dispatch-entry (sub-char sub-table) (declare (character sub-char)) (if (typep sub-char 'base-char) - (svref (truly-the (simple-vector #.base-char-code-limit) - (cdr (truly-the cons sub-table))) - (char-code sub-char)) - (awhen (car sub-table) - (gethash sub-char it)))) - -;; Coerce THING to a character-macro-table entry -(defmacro coerce-to-cmt-entry (thing) - `(let ((x ,thing)) - (if (typep x '(or null function)) x (find-or-create-fdefn x)))) - -;; Return a callable function given a character-macro-table entry. -(defmacro cmt-entry-to-function (val fallback) - `(let ((x ,val)) - (truly-the - function - (cond ((functionp x) x) - ((null x) ,fallback) - (t (sb-c:safe-fdefn-fun x)))))) - -;; Return a function-designator given a character-macro-table entry. -(defmacro cmt-entry-to-fun-designator (val) - `(let ((x ,val)) - (if (fdefn-p x) (fdefn-name x) x))) + (svref (charmacro-dtable-base-chars (truly-the cons sub-table)) + (char-code (char-upcase (truly-the base-char sub-char)))) + (awhen (charmacro-dtable-extended-chars sub-table) + (gethash (char-upcase sub-char) it)))) + +(eval-when (:compile-toplevel) ; wire in the fallbacks via :KNOWN-FUN constants + (sb-c:defknown read-token (stream character) *) + (sb-c:defknown dispatch-char-error (stream character t) *)) +;;; Invoke the character macro table entry for FUN-DESIGNATOR passing it +;;; ARGS, but if DESIGNATOR is NIL then call FALLBACK instead. +(defmacro invoke-cmt-entry ((fun-designator fallback) &rest args) + `(funcall (truly-the (or function symbol) (or ,fun-designator ,fallback)) + ,@args)) ;;; The character attribute table is a BASE-CHAR-CODE-LIMIT vector ;;; of (unsigned-byte 8) plus a hashtable to handle higher character codes. - -(defmacro test-attribute (char whichclass rt) - `(= (get-cat-entry ,char ,rt) ,whichclass)) +(defmacro test-attribute (char whichclass readtable &optional cast) + (let ((temp '#:readtable)) + `(let ((,temp ,readtable)) + (= (char-syntax ,char + (base-char-syntax-array ,temp) + (extended-char-table ,temp) + ,cast) + ,whichclass)))) ;;; predicates for testing character attributes -#-sb-fluid -(progn - (declaim (inline whitespace[1]p whitespace[2]p)) - (declaim (inline constituentp terminating-macrop)) - (declaim (inline single-escape-p multiple-escape-p)) - (declaim (inline token-delimiterp))) +(declaim (inline whitespace[1]p whitespace[2]p)) +(declaim (inline constituentp terminating-macrop)) +(declaim (inline single-escape-p multiple-escape-p)) +(declaim (inline token-delimiterp)) ;;; the [1] and [2] here refer to ANSI glossary entries for ;;; "whitespace". @@ -146,7 +154,7 @@ (defun whitespace[1]p (char) (test-attribute char +char-attr-whitespace+ *standard-readtable*)) (defun whitespace[2]p (char &optional (rt *readtable*)) - (test-attribute char +char-attr-whitespace+ rt)) + (test-attribute char +char-attr-whitespace+ rt t)) (defun constituentp (char rt) (test-attribute char +char-attr-constituent+ rt)) @@ -162,21 +170,22 @@ (defun token-delimiterp (char &optional (rt *readtable*)) ;; depends on actual attribute numbering in readtable.lisp. - (<= (get-cat-entry char rt) +char-attr-terminating-macro+)) + (<= (char-syntax char (base-char-syntax-array rt) (extended-char-table rt)) + +char-attr-terminating-macro+)) ;;;; constituent traits (see ANSI 2.1.4.2) ;;; There are a number of "secondary" attributes which are constant ;;; properties of characters (as long as they are constituents). -;;; FIXME: this initform is considered too hairy to assign (a constant array, really?) -;;; if changed to DEFCONSTANT-EQX, which makes this file unslammable as-is. Oh well. -(defconstant +constituent-trait-table+ +(defconstant-eqx +constituent-trait-table+ #.(let ((a (sb-xc:make-array base-char-code-limit + :retain-specialization-for-after-xc-core t :element-type '(unsigned-byte 8)))) (fill a +char-attr-constituent+) - (flet ((!set-constituent-trait (char trait) - (aver (typep char 'base-char)) - (setf (elt a (char-code char)) trait))) + (labels ((!set-code-constituent-trait (code trait) + (setf (elt a code) trait)) + (!set-constituent-trait (char trait) + (!set-code-constituent-trait (char-code char) trait))) (!set-constituent-trait #\: +char-attr-package-delimiter+) (!set-constituent-trait #\. +char-attr-constituent-dot+) (!set-constituent-trait #\+ +char-attr-constituent-sign+) @@ -184,7 +193,7 @@ (!set-constituent-trait #\/ +char-attr-constituent-slash+) (do ((i (char-code #\0) (1+ i))) ((> i (char-code #\9))) - (!set-constituent-trait (code-char i) +char-attr-constituent-digit+)) + (!set-code-constituent-trait i +char-attr-constituent-digit+)) (!set-constituent-trait #\E +char-attr-constituent-expt+) (!set-constituent-trait #\F +char-attr-constituent-expt+) (!set-constituent-trait #\D +char-attr-constituent-expt+) @@ -201,8 +210,9 @@ (!set-constituent-trait #\Newline +char-attr-invalid+) (dolist (c (list backspace-char-code tab-char-code form-feed-char-code return-char-code rubout-char-code)) - (!set-constituent-trait (code-char c) +char-attr-invalid+))) - a)) + (!set-code-constituent-trait c +char-attr-invalid+))) + a) + #'equalp) (declaim (inline get-constituent-trait)) (defun get-constituent-trait (char) @@ -217,19 +227,18 @@ (cerror "Frob it anyway!" 'standard-readtable-modified-error :operation operation))) +(declaim (inline readtable-case)) (defun readtable-case (readtable) - (aref #(:upcase :downcase :preserve :invert) (%readtable-case readtable))) + (%readtable-case readtable)) (defun (setf readtable-case) (case readtable) ;; This function does not accept a readtable designator, only a readtable. (assert-not-standard-readtable readtable '(setf readtable-case)) - (setf (%readtable-case readtable) - (ecase case (:upcase 0) (:downcase 1) (:preserve 2) (:invert 3))) - case) + (setf (%readtable-case readtable) case)) (declaim (inline readtable-normalization)) (defun readtable-normalization (readtable) - "Returns T if READTABLE normalizes strings to NFKC, and NIL otherwise. + "Returns T if READTABLE normalizes symbols to NFKC, and NIL otherwise. The READTABLE-NORMALIZATION of the standard readtable is T." (%readtable-normalization readtable)) @@ -264,7 +273,7 @@ be interned (returned, respectively) as required. The default is :SYMBOLS." (if (member new-value '(:strings :both)) 'base-char 'character)) new-value) -(defun replace/eql-hash-table (to from &optional (transform #'identity)) +(defun hash-table-replace (to from &optional (transform #'identity)) (maphash (lambda (k v) (setf (gethash k to) (funcall transform v))) from) to) @@ -280,15 +289,15 @@ be interned (returned, respectively) as required. The default is :SYMBOLS." t)) (find-if-in-closure #'consp fun))) -;; If ENTRY is a dispatching macro, copy its dispatch table. -;; Otherwise return it without alteration. +;;; Copy a char-macro-table entry. +;;; If ENTRY is a dispatching macro, copy its dispatch table; otherwise return it unchanged. (defun copy-cmt-entry (entry) (let ((dtable (%dispatch-macro-char-table entry))) (if dtable (%make-dispatch-macro-char - (cons (awhen (car dtable) - (replace/eql-hash-table (make-hash-table) it)) - (copy-seq (cdr dtable)))) + (cons (copy-seq (charmacro-dtable-base-chars dtable)) + (awhen (charmacro-dtable-extended-chars dtable) + (hash-table-replace (make-hash-table :test 'eq) it)))) entry))) (defun copy-readtable (&optional (from-readtable *readtable*) to-readtable) @@ -299,18 +308,24 @@ readtable when not provided." (assert-not-standard-readtable to-readtable 'copy-readtable) (let ((really-from-readtable (or from-readtable *standard-readtable*)) (really-to-readtable (or to-readtable (make-readtable)))) - (replace (character-attribute-array really-to-readtable) - (character-attribute-array really-from-readtable)) - (replace/eql-hash-table - (clrhash (character-attribute-hash-table really-to-readtable)) - (character-attribute-hash-table really-from-readtable)) - (map-into (character-macro-array really-to-readtable) + (replace (base-char-syntax-array really-to-readtable) + (base-char-syntax-array really-from-readtable)) + (map-into (base-char-macro-array really-to-readtable) #'copy-cmt-entry - (character-macro-array really-from-readtable)) - (replace/eql-hash-table - (clrhash (character-macro-hash-table really-to-readtable)) - (character-macro-hash-table really-from-readtable) - #'copy-cmt-entry) + (base-char-macro-array really-from-readtable)) + (setf (extended-char-table really-to-readtable) + (let ((source-ht (extended-char-table really-from-readtable))) + (if (eq source-ht *empty-extended-char-table*) + source-ht + (let ((copy (make-hash-table :test 'eq))) + (hash-table-replace + copy source-ht + (lambda (x) + (when x + ;; (syntax . macro) in which macro could be + ;; a function with a nested dispatch table. + (cons (car x) (copy-cmt-entry (cdr x)))))) + copy)))) (setf (readtable-case really-to-readtable) (readtable-case really-from-readtable)) (setf (%readtable-string-preference really-to-readtable) @@ -329,10 +344,11 @@ standard Lisp readtable when NIL." ;; TO-READTABLE is a readtable, not a readtable-designator (assert-not-standard-readtable to-readtable 'set-syntax-from-char) (let* ((really-from-readtable (or from-readtable *standard-readtable*)) - (att (get-cat-entry from-char really-from-readtable)) + (att (char-syntax from-char + (base-char-syntax-array really-from-readtable) + (extended-char-table really-from-readtable))) (mac (get-raw-cmt-entry from-char really-from-readtable))) - (set-cat-entry to-char att to-readtable) - (set-cmt-entry to-char (copy-cmt-entry mac) to-readtable)) + (assign-char-syntax to-readtable to-char att (copy-cmt-entry mac))) t) (defun set-macro-character (char function &optional @@ -343,11 +359,11 @@ standard Lisp readtable when NIL." character non-terminating, i.e. embeddable in a symbol name." (let ((designated-readtable (or rt-designator *standard-readtable*))) (assert-not-standard-readtable designated-readtable 'set-macro-character) - (set-cat-entry char (if non-terminatingp - +char-attr-constituent+ - +char-attr-terminating-macro+) - designated-readtable) - (set-cmt-entry char (coerce-to-cmt-entry function) designated-readtable) + (assign-char-syntax + designated-readtable + char + (if non-terminatingp +char-attr-constituent+ +char-attr-terminating-macro+) + function) t)) ; (ANSI-specified return value) (defun get-macro-character (char &optional (rt-designator *readtable*)) @@ -358,8 +374,7 @@ standard Lisp readtable when NIL." (let* ((designated-readtable (or rt-designator *standard-readtable*)) ;; the first return value: (OR FUNCTION SYMBOL) if CHAR is a macro ;; character, or NIL otherwise - (fun-value (cmt-entry-to-fun-designator - (get-raw-cmt-entry char designated-readtable)))) + (fun-value (get-raw-cmt-entry char designated-readtable))) (values fun-value ;; NON-TERMINATING-P return value: (if fun-value @@ -388,13 +403,12 @@ standard Lisp readtable when NIL." ;; by catching the error, so I removed it. ;; RT is a readtable, not a readtable-designator, as per CLHS. (unless (get-dispatch-macro-char-table char rt nil) - ;; The dtable is a cons whose whose CAR is initially NIL but upgraded - ;; to a hashtable if required, and whose CDR is a vector indexed by - ;; char-code up to the maximum base-char. - (let ((dtable (cons nil (make-array base-char-code-limit - :initial-element nil)))) - (set-macro-character char (%make-dispatch-macro-char dtable) - non-terminating-p rt))) + ;; Dispatch table is a cons whose whose CAR is a vector indexed by base char code + ;; and CDR is initially NIL, changed to a hashtable if there are extended chars. + (set-macro-character char + (%make-dispatch-macro-char + (list (make-array base-char-code-limit :initial-element nil))) + non-terminating-p rt)) t) (defun set-dispatch-macro-character (disp-char sub-char function @@ -408,17 +422,16 @@ standard Lisp readtable when NIL." (assert-not-standard-readtable readtable 'set-dispatch-macro-character) (when (digit-char-p sub-char) (error "SUB-CHAR must not be a decimal digit: ~S" sub-char)) - (let ((dtable (get-dispatch-macro-char-table disp-char readtable)) - (function (coerce-to-cmt-entry function))) + (let ((dtable (get-dispatch-macro-char-table disp-char readtable))) ;; (SET-MACRO-CHARACTER #\$ (GET-MACRO-CHARACTER #\#)) will share ;; the dispatch table. Perhaps it should be copy-on-write? (if (typep sub-char 'base-char) - (setf (svref (cdr dtable) (char-code sub-char)) function) - (let ((hashtable (car dtable))) + (setf (svref (charmacro-dtable-base-chars dtable) (char-code sub-char)) function) + (let ((hashtable (charmacro-dtable-extended-chars dtable))) (cond (function ; allocate the hashtable if it wasn't made yet (setf (gethash sub-char - (or hashtable (setf (car dtable) - (make-hash-table)))) + (or hashtable (setf (charmacro-dtable-extended-chars dtable) + (make-hash-table :test 'eq)))) function)) (hashtable ; remove an existing entry (remhash sub-char hashtable))))))) @@ -430,8 +443,7 @@ standard Lisp readtable when NIL." or NIL if there is no associated function." (let ((dtable (get-dispatch-macro-char-table disp-char (or rt-designator *standard-readtable*)))) - (cmt-entry-to-fun-designator - (get-raw-cmt-dispatch-entry (char-upcase sub-char) dtable)))) + (get-raw-cmt-dispatch-entry sub-char dtable))) ;;;; definitions to support internal programming conventions @@ -441,16 +453,11 @@ standard Lisp readtable when NIL." (defun flush-whitespace (stream) ;; This flushes whitespace chars, returning the last char it read (a ;; non-white one). It always gets an error on end-of-file. - (let* ((stream (in-stream-from-designator stream)) - (rt *readtable*) - (attribute-array (character-attribute-array rt)) - (attribute-hash-table (character-attribute-hash-table rt))) + (let* ((rt *readtable*) + (base (base-char-syntax-array rt)) + (extended (extended-char-table rt))) (macrolet ((done-p () - '(not (eql (if (typep char 'base-char) - (aref attribute-array (char-code char)) - (gethash char attribute-hash-table - +char-attr-constituent+)) - +char-attr-whitespace+)))) + '(neq (char-syntax char base extended) +char-attr-whitespace+))) (if (ansi-stream-p stream) (prepare-for-fast-read-char stream (loop (let ((char (fast-read-char t))) @@ -469,25 +476,21 @@ standard Lisp readtable when NIL." ;;;; temporary initialization hack ;; Install the (easy) standard macro-chars into *READTABLE*. -(defun !cold-init-standard-readtable () - (/show0 "entering !cold-init-standard-readtable") +(defun !reader-cold-init () ;; All characters get boring defaults in MAKE-READTABLE. Now we ;; override the boring defaults on characters which need more ;; interesting behavior. (flet ((whitespaceify (char) - (set-cmt-entry char nil) - (set-cat-entry char +char-attr-whitespace+))) + (assign-char-syntax *readtable* char +char-attr-whitespace+ nil))) (whitespaceify (code-char tab-char-code)) (whitespaceify #\Newline) (whitespaceify #\Space) (whitespaceify (code-char form-feed-char-code)) (whitespaceify (code-char return-char-code))) - (set-cat-entry #\\ +char-attr-single-escape+) - (set-cmt-entry #\\ nil) + (assign-char-syntax *readtable* #\\ +char-attr-single-escape+ nil) - (set-cat-entry #\| +char-attr-multiple-escape+) - (set-cmt-entry #\| nil) + (assign-char-syntax *readtable* #\| +char-attr-multiple-escape+ nil) ;; Easy macro-character definitions are in this source file. (set-macro-character #\" #'read-string) @@ -499,16 +502,7 @@ standard Lisp readtable when NIL." (set-macro-character #\; #'read-comment) ;; (The hairier macro-character definitions, for #\# and #\`, are ;; defined elsewhere, in their own source files.) - - ;; all constituents - (do ((ichar 0 (1+ ichar)) - (char)) - ((= ichar base-char-code-limit)) - (setq char (code-char ichar)) - (when (constituentp char *readtable*) - (set-cmt-entry char nil))) - - (/show0 "leaving !cold-init-standard-readtable")) + ) ;;;; implementation of the read buffer @@ -529,7 +523,7 @@ standard Lisp readtable when NIL." ;; Counter advanced as characters are placed into 'string' (fill-ptr 0 :type index) ;; Counter advanced as characters are consumed from 'string' on re-scan - ;; by auxilliary functions MAKE-{INTEGER,FLOAT,RATIONAL} etc. + ;; by auxiliary functions MAKE-{INTEGER,FLOAT,RATIONAL} etc. (cursor 0 :type index) ;; A string used only for FIND-PACKAGE calls in package-qualified ;; symbols so that we don't need to call SUBSEQ on the 'string'. @@ -569,7 +563,7 @@ standard Lisp readtable when NIL." (defun ouch-read-buffer (char buffer) ;; When buffer overflow (let ((op (token-buf-fill-ptr buffer))) - (declare (optimize (sb-c::insert-array-bounds-checks 0))) + (declare (optimize (sb-c:insert-array-bounds-checks 0))) (when (>= op (length (token-buf-string buffer))) ;; an out-of-line call for the uncommon case avoids bloat. ;; Size should be doubled. @@ -592,7 +586,7 @@ standard Lisp readtable when NIL." ;; Retun the next character from the buffered token, or NIL. (declaim (maybe-inline token-buf-getchar)) (defun token-buf-getchar (b) - (declare (optimize (sb-c::insert-array-bounds-checks 0))) + (declare (optimize (sb-c:insert-array-bounds-checks 0))) (let ((i (token-buf-cursor (truly-the token-buf b)))) (and (< i (token-buf-fill-ptr b)) (prog1 (elt (token-buf-string b) i) @@ -734,8 +728,9 @@ standard Lisp readtable when NIL." "Read from STREAM and return the value read, preserving any whitespace that followed the object." (declare (explicit-check)) - (check-for-recursive-read stream recursive-p 'read-preserving-whitespace) - (%read-preserving-whitespace stream eof-error-p eof-value recursive-p)) + (let ((stream (in-stream-from-designator stream))) + (check-for-recursive-read stream recursive-p 'read-preserving-whitespace) + (%read-preserving-whitespace stream eof-error-p eof-value recursive-p))) ;;; Read from STREAM given starting CHAR, returning 1 and the resulting ;;; object, unless CHAR is a macro yielding no value, then 0 and NIL, @@ -755,14 +750,14 @@ standard Lisp readtable when NIL." (and (form-tracking-stream-p stream) ;; Subtract 1 because the position points _after_ CHAR. (1- (form-tracking-stream-input-char-pos stream))) - (funcall (cmt-entry-to-function - (get-raw-cmt-entry char *readtable*) #'read-token) - stream char))) + (invoke-cmt-entry ((get-raw-cmt-entry char *readtable*) #'read-token) + stream char))) (defun read (&optional (stream *standard-input*) (eof-error-p t) (eof-value nil) - (recursive-p nil)) + (recursive-p nil) + &aux (stream (in-stream-from-designator stream))) "Read the next Lisp value from STREAM, and return it." (declare (explicit-check)) (check-for-recursive-read stream recursive-p 'read) @@ -799,16 +794,15 @@ standard Lisp readtable when NIL." 'sb-kernel::character-decoding-error-in-macro-char-comment :position (file-position stream) :stream stream) (invoke-restart 'attempt-resync)))) - (let ((stream (in-stream-from-designator stream))) - (if (ansi-stream-p stream) - (prepare-for-fast-read-char stream + (if (ansi-stream-p stream) + (prepare-for-fast-read-char stream (loop (let ((char (fast-read-char nil +EOF+))) (when (or (eq char +EOF+) (char= char #\newline)) (return (done-with-fast-read-char)))))) ;; CLOS stream - (loop (let ((char (read-char stream nil +EOF+))) + (loop (let ((char (read-char stream nil +EOF+))) (when (or (eq char +EOF+) (char= char #\newline)) - (return))))))) + (return)))))) ;; Don't return anything. (values)) @@ -868,7 +862,9 @@ standard Lisp readtable when NIL." ;;; (This is a COMMON-LISP exported symbol.) (defun read-delimited-list (endchar &optional (input-stream *standard-input*) - recursive-p) + recursive-p + &aux (input-stream + (in-stream-from-designator input-stream))) "Read Lisp values from INPUT-STREAM until the next character after a value's representation is ENDCHAR, and return the objects as a list." (declare (explicit-check)) @@ -878,7 +874,8 @@ standard Lisp readtable when NIL." (read-list-item input-stream)))) (if recursive-p (%read-delimited-list) - (with-read-buffer () (%read-delimited-list)))))) ; end MACROLET + (let ((*sharp-equal* nil)) + (with-read-buffer () (%read-delimited-list))))))) ; end MACROLET (defun read-after-dot (stream firstchar collectp) ;; FIRSTCHAR is non-whitespace! @@ -914,7 +911,7 @@ standard Lisp readtable when NIL." (declare (character closech)) (macrolet ((scan (read-a-char eofp &optional finish) `(loop (let ((char ,read-a-char)) - (declare (optimize (sb-c::insert-array-bounds-checks 0))) + (declare (optimize (sb-c:insert-array-bounds-checks 0))) (cond (,eofp (error 'end-of-file :stream stream)) ((eql char closech) (return ,finish)) @@ -935,7 +932,6 @@ standard Lisp readtable when NIL." (let* ((token-buf *read-buffer*) (buf (token-buf-string token-buf)) (rt *readtable*) - (stream (in-stream-from-designator stream)) (suppress *read-suppress*) (lim (length buf)) (ptr 0) @@ -1028,12 +1024,8 @@ standard Lisp readtable when NIL." ;;; Return the character class for CHAR. ;;; -;;; FIXME: why aren't these ATT-getting forms using GET-CAT-ENTRY? -;;; Because we've cached the readtable tables? (defmacro char-class (char attarray atthash) - `(let ((att (if (typep (truly-the character ,char) 'base-char) - (aref ,attarray (char-code ,char)) - (gethash ,char ,atthash +char-attr-constituent+)))) + `(let ((att (char-syntax ,char ,attarray ,atthash))) (declare (fixnum att)) (cond ((<= att +char-attr-terminating-macro+) +char-attr-delimiter+) @@ -1046,9 +1038,7 @@ standard Lisp readtable when NIL." ;;; Return the character class for CHAR, which might be part of a ;;; rational number. (defmacro char-class2 (char attarray atthash read-base) - `(let ((att (if (typep (truly-the character ,char) 'base-char) - (aref ,attarray (char-code ,char)) - (gethash ,char ,atthash +char-attr-constituent+)))) + `(let ((att (char-syntax ,char ,attarray ,atthash))) (declare (fixnum att)) (cond ((<= att +char-attr-terminating-macro+) +char-attr-delimiter+) @@ -1065,9 +1055,7 @@ standard Lisp readtable when NIL." ;;; rational or floating number. (Assume that it is a digit if it ;;; could be.) (defmacro char-class3 (char attarray atthash read-base) - `(let ((att (if (typep (truly-the character ,char) 'base-char) - (aref ,attarray (char-code ,char)) - (gethash ,char ,atthash +char-attr-constituent+)))) + `(let ((att (char-syntax ,char ,attarray ,atthash))) (declare (fixnum att)) (cond ((<= att +char-attr-terminating-macro+) +char-attr-delimiter+) @@ -1145,7 +1133,7 @@ standard Lisp readtable when NIL." ((and (zerop (length escapes)) (eq case :upcase)) (let ((buffer (token-buf-string token-buf))) (dotimes (i (token-buf-fill-ptr token-buf)) - (declare (optimize (sb-c::insert-array-bounds-checks 0))) + (declare (optimize (sb-c:insert-array-bounds-checks 0))) (setf (schar buffer i) (char-upcase (schar buffer i)))))) ((eq case :preserve)) (t @@ -1156,7 +1144,7 @@ standard Lisp readtable when NIL." -1 (vector-pop escapes)))) ((minusp i)) (declare (fixnum i) - (optimize (sb-c::insert-array-bounds-checks 0))) + (optimize (sb-c:insert-array-bounds-checks 0))) (if (< esc i) (let ((ch (schar buffer i))) ,@body) @@ -1226,8 +1214,8 @@ extended <package-name>::<form-in-package> syntax." (return-from read-token nil)) (let* ((rt *readtable*) (base *read-base*) - (attribute-array (character-attribute-array rt)) - (attribute-hash-table (character-attribute-hash-table rt)) + (attribute-array (base-char-syntax-array rt)) + (attribute-hash-table (extended-char-table rt)) (buf *read-buffer*) (package-designator nil) (colons 0) @@ -1454,8 +1442,7 @@ extended <package-name>::<form-in-package> syntax." (#.+char-attr-package-delimiter+ (go COLON)) (t (go SYMBOL))) SYMBOL ; not a dot, dots, or number - (let ((stream (in-stream-from-designator stream))) - (macrolet + (macrolet ((scan (read-a-char &optional finish) `(prog () SYMBOL-LOOP @@ -1474,7 +1461,7 @@ extended <package-name>::<form-in-package> syntax." (prepare-for-fast-read-char stream (scan (fast-read-char nil +EOF+) (done-with-fast-read-char))) ;; CLOS stream - (scan (read-char stream nil +EOF+))))) + (scan (read-char stream nil +EOF+)))) SINGLE-ESCAPE ; saw a single-escape ;; Don't put the escape character in the read buffer. ;; READ-NEXT CHAR, put in buffer (no case conversion). @@ -1536,13 +1523,15 @@ extended <package-name>::<form-in-package> syntax." (case (char-class char attribute-array attribute-hash-table) (#.+char-attr-delimiter+ (unread-char char stream) - (if package-designator - (let* ((*reader-package* - (reader-find-package package-designator stream nil))) - (return (read stream t nil t))) - (simple-reader-error stream - "illegal terminating character after a double-colon: ~S" - char))) + (let* ((*reader-package* + (reader-find-package package-designator stream nil))) + (return (read stream t nil t))) + ;; We used to signal this error before package::(form) syntax + ;; was added. + #+(or) + (simple-reader-error stream + "illegal terminating character after a double-colon: ~S" + char)) (#.+char-attr-single-escape+ (go SINGLE-ESCAPE)) (#.+char-attr-multiple-escape+ (go MULT-ESCAPE)) (#.+char-attr-package-delimiter+ @@ -1566,6 +1555,9 @@ extended <package-name>::<form-in-package> syntax." (multiple-value-bind (symbol accessibility) (%find-symbol (token-buf-string buf) (token-buf-fill-ptr buf) pkg) (when (eq accessibility :external) (return symbol)) + (when (and accessibility + (check-deprecated-export pkg symbol)) + (return symbol)) (with-simple-restart (continue "Use symbol anyway.") (error 'simple-reader-package-error :package pkg @@ -1634,7 +1626,7 @@ extended <package-name>::<form-in-package> syntax." (defmacro !setq-optional-leading-sign (sign-flag token-buf rewind) ;; guaranteed to have at least one character in buffer at the start ;; or immediately following [ESFDL] marker depending on 'rewind' flag. - `(locally (declare (optimize (sb-c::insert-array-bounds-checks 0))) + `(locally (declare (optimize (sb-c:insert-array-bounds-checks 0))) (,(if rewind 'setf 'incf) (token-buf-cursor ,token-buf) (case (elt (token-buf-string ,token-buf) @@ -1650,8 +1642,8 @@ extended <package-name>::<form-in-package> syntax." (inline token-buf-getchar)) ; makes for smaller code (let* ((fixnum-max-digits (macrolet ((maxdigits () - (sb-xc:coerce (integer-reader-safe-digits) - '(vector (unsigned-byte 8))))) + (coerce (integer-reader-safe-digits) + '(vector (unsigned-byte 8))))) (aref (maxdigits) (- base 2)))) (base-power (macrolet ((base-powers () @@ -1812,22 +1804,23 @@ extended <package-name>::<form-in-package> syntax." (defun read-dispatch-char (stream dispatch-table) ;; Read some digits. - (let ((numargp nil) - (numarg 0) - (sub-char ())) - (loop - (let ((ch (read-char stream nil +EOF+))) - (if (eq ch +EOF+) - (reader-eof-error stream "inside dispatch character") - ;; Take care of the extra char. - (let ((dig (digit-char-p ch))) - (if dig - (setq numargp t numarg (+ (* numarg 10) dig)) - (return (setq sub-char (char-upcase ch)))))))) + (let* ((numarg nil) + (sub-char + (loop + (let ((ch (read-char stream nil +EOF+))) + (if (eq ch +EOF+) + (reader-eof-error stream "inside dispatch character") + ;; Take care of the extra char. + (let ((dig (digit-char-p ch))) + (cond ((not dig) (return ch)) + ((not numarg) (setq numarg dig)) + (t (setq numarg (+ (* numarg 10) dig)))))))))) ;; Look up the function and call it. - (let ((fn (get-raw-cmt-dispatch-entry sub-char dispatch-table))) - (funcall (cmt-entry-to-function fn #'dispatch-char-error) - stream sub-char (if numargp numarg nil))))) + ;; We used to give the user the upcased sub-char, but not only is that + ;; not stipulated, the "lossiness" could be construed as a bug. + (invoke-cmt-entry ((get-raw-cmt-dispatch-entry sub-char dispatch-table) + #'dispatch-char-error) + stream sub-char numarg))) ;;;; READ-FROM-STRING @@ -1924,9 +1917,6 @@ extended <package-name>::<form-in-package> syntax." ;;;; reader initialization code -(defun !reader-cold-init () - (!cold-init-standard-readtable)) - (defmethod print-object ((readtable readtable) stream) (print-unreadable-object (readtable stream :identity t :type t))) @@ -1936,24 +1926,31 @@ extended <package-name>::<form-in-package> syntax." ;; values was a hashtable which got immediately coerced to an alist. ;; In anticipation of perhaps not doing an extra re-shaping, if HASH-TABLE-P ;; is NIL then return nested alists: ((#\# (#\R . #<FUNCTION SHARP-R>) ...)) +;; FIXME: provide a better interface for iterating over reader macros (defun dispatch-tables (readtable &optional (hash-table-p t)) (let (alist) (flet ((process (char fn &aux (dtable (%dispatch-macro-char-table fn))) (when dtable - (let ((output (awhen (car dtable) (%hash-table-alist it)))) - (loop for fn across (the simple-vector (cdr dtable)) + (let ((output (awhen (charmacro-dtable-extended-chars dtable) + (%hash-table-alist it)))) + (loop for fn across (the simple-vector (charmacro-dtable-base-chars dtable)) and ch from 0 when fn do (push (cons (code-char ch) fn) output)) - (dolist (cell output) ; coerce values to function-designator - (rplacd cell (cmt-entry-to-fun-designator (cdr cell)))) - (when hash-table-p ; caller wants hash-tables + (when hash-table-p ; caller wants hash-tables (setq output (%stuff-hash-table (make-hash-table) output))) (push (cons char output) alist))))) - (loop for fn across (character-macro-array readtable) and ch from 0 + (loop for fn across (base-char-macro-array readtable) and ch from 0 do (process (code-char ch) fn)) - (maphash #'process (character-macro-hash-table readtable))) + (maphash (lambda (char val) (process char (cdr val))) + (extended-char-table readtable))) alist)) +(declaim (inline character-macro-array character-macro-hash-table)) +(define-deprecated-function :early "2.0.6" character-macro-array base-char-macro-array (readtable) + (base-char-macro-array readtable)) +(define-deprecated-function :early "2.0.6" character-macro-hash-table extended-char-table (readtable) + (extended-char-table readtable)) + ;; Stub - should never get called with anything but NIL ;; and only after all macros have been changed to constituents already. (defun (setf dispatch-tables) (new-alist readtable) diff --git a/src/code/readtable.lisp b/src/code/readtable.lisp index 7c857a49ec..a23e5b406a 100644 --- a/src/code/readtable.lisp +++ b/src/code/readtable.lisp @@ -45,6 +45,8 @@ ;; Meta: there is no such function as READ-UNQUALIFIED-TOKEN. No biggie. (defconstant +char-attr-delimiter+ 14) ; (a fake for READ-UNQUALIFIED-TOKEN) +(define-load-time-global *empty-extended-char-table* (make-hash-table :rehash-size 1 :test #'eq)) + (sb-xc:defstruct (readtable (:conc-name nil) (:constructor make-readtable ()) (:predicate readtablep) @@ -54,7 +56,7 @@ (:copier nil)) "A READTABLE is a data structure that maps characters into syntax types for the Common Lisp expression reader." - ;; The CHARACTER-ATTRIBUTE-TABLE is a vector of BASE-CHAR-CODE-LIMIT + ;; The BASE-CHAR-SYNTAX-ARRAY is a vector of BASE-CHAR-CODE-LIMIT ;; integers for describing the character type. Conceptually, there ;; are 4 distinct "primary" character attributes: ;; +CHAR-ATTR-WHITESPACE+, +CHAR-ATTR-TERMINATING-MACRO+, @@ -65,28 +67,25 @@ types for the Common Lisp expression reader." ;; In order to make READ-TOKEN fast, all this information is stored ;; in the character attribute table by having different varieties of ;; constituents. - (character-attribute-array + (base-char-syntax-array (make-array base-char-code-limit :element-type '(unsigned-byte 8) :initial-element +char-attr-constituent+) :type attribute-table :read-only t) - (character-attribute-hash-table (make-hash-table) - :type hash-table - :read-only t) - ;; The CHARACTER-MACRO-TABLE is a vector of BASE-CHAR-CODE-LIMIT + ;; The BASE-CHAR-MACRO-TABLE is a vector of BASE-CHAR-CODE-LIMIT ;; functions. One of these functions called with appropriate ;; arguments whenever any non-WHITESPACE character is encountered ;; inside READ-PRESERVING-WHITESPACE. These functions are used to ;; implement user-defined read-macros, system read-macros, and the ;; number-symbol reader. - (character-macro-array + (base-char-macro-array (make-array base-char-code-limit :initial-element nil) :type (simple-vector #.base-char-code-limit) :read-only t) - (character-macro-hash-table (make-hash-table) :type hash-table - :read-only t) - (%readtable-case 0 :type (mod 4)) + ;; Characters above the BASE-CHAR range + (extended-char-table *empty-extended-char-table* :type hash-table) + (%readtable-case :upcase :type (member :upcase :downcase :preserve :invert)) ;; Element type to use when reading a string literal with no extended-chars. ;; The system itself prefers base-string, but otherwise it is a contentious ;; issue. We don't (by default) use base-strings, because people often write: @@ -110,7 +109,4 @@ types for the Common Lisp expression reader." (%readtable-symbol-preference 'base-char :type (member character base-char)) (%readtable-normalization #+sb-unicode t #-sb-unicode nil :type boolean)) -(defconstant +readtable-upcase+ 0) -(defconstant +readtable-downcase+ 1) - (declaim (freeze-type readtable)) diff --git a/src/code/redblack.lisp b/src/code/redblack.lisp index 75562cbb25..e310cb181d 100644 --- a/src/code/redblack.lisp +++ b/src/code/redblack.lisp @@ -9,8 +9,6 @@ ;;;; provided with absolutely no warranty. See the COPYING and CREDITS ;;;; files for more information. -(in-package "SB-RBTREE") - ;;; For testing ;;; (declaim (optimize sb-c:store-coverage-data)) @@ -23,60 +21,99 @@ ;;; http://matt.might.net/papers/germane2014deletion.pdf ;;; which I found to be less simple when translated from Haskell. -;; This structure is exactly 4 words with #+compact-instance-header -(defstruct (rbnode (:conc-name "") (:constructor nil)) - (left nil :read-only t :type (or rbnode null)) - (right nil :read-only t :type (or rbnode null)) - ;; It would be conventional to store key and value as two slots, - ;; but using a cons is actually better - the table operations - ;; create new RBNODEs, but we can share the immutable cons cells. - (data nil :read-only t :type cons)) - -(defstruct (red-node (:include rbnode) - (:predicate redp) - (:constructor red-node (left data right)) - (:conc-name ""))) -(defstruct (black-node (:include rbnode) - (:predicate blackp) - (:constructor black-node (left data right)) - (:conc-name ""))) - -;; FIXME: should blackp return T of NIL? +(defpackage "SB-RBTREE" + (:use "CL" "SB-INT" "SB-EXT")) +(defpackage "SB-RBTREE.WORD" + (:use "CL") + (:shadow "DELETE") + (:export "INSERT" "DELETE")) +(defpackage "SB-RBTREE.MAP" + (:use "CL") + (:shadow "DELETE") + (:export "INSERT" "DELETE")) -(declaim (inline node-key node-value)) -(defun node-key (node) (car (data node))) -(defun node-value (node) (cdr (data node))) +(in-package "SB-RBTREE") + +(defmacro define-tree-class (&key key-type value-type (lessp '<) + &aux (data-type (if value-type 'cons key-type)) + (name (intern "RBNODE")) + (red-ctor (intern "RED-NODE")) + (balance (intern "BALANCE")) + (key (if value-type 'car 'identity))) + +;; remap accessors/constructors/predicates as written in this package +;; to the corresponding symbols in the specialization package. +`(macrolet ((rb-node (&rest r) `(,(intern "RB-NODE") ,@r)) + (red-node (&rest r) `(,(intern "RED-NODE") ,@r)) + (black-node (&rest r) `(,(intern "BLACK-NODE") ,@r)) + (balance (&rest r) `(,(intern "BALANCE") ,@r)) + (color-of (x) `(,(intern "COLOR-OF") ,x)) + (left (x) `(,(intern "LEFT") ,x)) + (data (x) `(,(intern "DATA") ,x)) + (right (x) `(,(intern "RIGHT") ,x)) + (redp (x) `(,(intern "REDP") ,x)) + (blackp (x) `(,(intern "BLACKP") ,x)) + (redden (x) `(,(intern "REDDEN") ,x)) + (blacken (x) `(,(intern "BLACKEN") ,x))) + +;;; This structure is exactly 4 words with #+compact-instance-header +;;; I really wanted one variant of thie structure to have a raw slot (SB-VM:WORD) +;;; for DATA, and one not to, but that wasn't working, only because of unintended +;;; consing and not for any real reason. +;;; But that doesn't mean I want to merge these definitions back together - +;;; I still want to figure out why there was excess consing. +(defstruct (,name (:conc-name "") (:constructor nil) + (:copier nil) (:predicate nil)) + (left nil :read-only t :type (or ,name null)) + (right nil :read-only t :type (or ,name null)) + (data nil :read-only t :type ,data-type)) + +(defstruct (,(intern "RED-NODE") (:include ,name) (:copier nil) + (:predicate ,(intern "REDP")) + (:constructor ,(intern "RED-NODE") (left data right)) + (:conc-name ""))) + +(defstruct (,(intern "BLACK-NODE") (:include ,name) (:copier nil) + (:predicate ,(intern "BLACKP")) + (:constructor ,(intern "BLACK-NODE") (left data right)) + (:conc-name ""))) -(defmethod print-object ((self rbnode) stream) +(defmethod print-object ((self ,name) stream) + (declare (optimize (speed 1) (safety 1))) (print-unreadable-object (self stream :type t :identity t) (format stream "~s" (data self)))) -(defun rb-node (color left data right) +(defun ,(intern "RB-NODE") (color left data right) (ecase color (red (red-node left data right)) (black (black-node left data right)))) -(defun blacken (tree) +(defun ,(intern "BLACKEN") (tree) + ;; FIXME: should blackp return T of NIL? (cond ((not tree) nil) ((blackp tree) tree) (t (black-node (left tree) (data tree) (right tree))))) -(defun redden (tree) +(defun ,(intern "REDDEN") (tree) (if (redp tree) tree (red-node (left tree) (data tree) (right tree)))) -(defun color-of (node) +(defun ,(intern "COLOR-OF") (node) (etypecase node - (red-node 'red) - (black-node 'black))) + (,(intern "RED-NODE") 'red) + (,(intern "BLACK-NODE") 'black))) + +(declaim (inline ,(intern "RED-NODE") ,(intern "BLACK-NODE"))) +(declaim (optimize (sb-c::insert-step-conditions 0) + (sb-c::instrument-consing 0))) ;;; This implementation of BALANCE differs from the reference algorithm ;;; only in that by passing 4 arguments rather than an object we can ;;; sometimes avoid consing and immediately discarding one node. -(defun balance (color L data R) +(flet ((,balance (color L data R) (when (eq color 'red) - (return-from balance (red-node L data R))) + (return-from ,balance (red-node L data R))) (macrolet ((values* (&rest args) `(values ,@(mapcan (lambda (arg) (if (typep arg '(cons (eql node-slots))) @@ -98,35 +135,40 @@ (let ((RR (right R))) (values* L data (left R) (data R) (node-slots RR)))) (t - (return-from balance (rb-node color L data R)))) - (red-node (black-node a x b) y (black-node c z d))))) + (return-from ,balance (rb-node color L data R)))) + (red-node (black-node a x b) y (black-node c z d)))))) -(defun insert (tree key value) - (let ((data (cons key value))) +(defun ,(intern "INSERT") (tree key ,@(when value-type '(value))) + (declare (type ,key-type key)) + (let ((data ,(if value-type '(cons key value) 'key))) (labels ((ins (tree) (cond (tree (let ((c (color-of tree)) (a (left tree)) (x (data tree)) (b (right tree))) - (cond ((< key (car x)) (balance c (ins a) x b)) - ((< (car x) key) (balance c a x (ins b))) + (cond ((,lessp key (the ,key-type (,key x))) + (balance c (ins a) x b)) + ((,lessp (the ,key-type (,key x)) key) + (balance c a x (ins b))) (t (rb-node c a data b))))) (t (red-node nil data nil))))) (blacken (ins tree))))) -(defun delete (key tree) +(defun ,(intern "DELETE") (key tree) + (declare (type ,key-type key)) + (declare (notinline ,(intern "RED-NODE") ,(intern "BLACK-NODE"))) (labels ((del (tree) (when tree (binding* (((a y b) (node-slots tree))) - (cond ((< key (car y)) (delete-left a y b)) - ((< (car y) key) (delete-right a y b)) + (cond ((,lessp key (the ,key-type (,key y))) (delete-left a y b)) + ((,lessp (the ,key-type (,key y)) key) (delete-right a y b)) (t (rb-merge a b)))))) (delete-left (a y b) - (funcall (if (blackp a) #'balance-left #'red-node) (del a) y b)) + (funcall (if (blackp a) #'balance-left #',red-ctor) (del a) y b)) (delete-right (a y b) - (funcall (if (blackp b) #'balance-right #'red-node) a y (del b))) + (funcall (if (blackp b) #'balance-right #',red-ctor) a y (del b))) (sub1 (tree) ; decrease the black height by 1 (aver (blackp tree)) (redden tree)) @@ -172,17 +214,84 @@ (node-slots (x) (values (left x) (data x) (right x)))) (declare (inline node-slots)) (blacken (del tree)))) +) ; end (FLET BALANCE) +) ; end MACROLET +) ; end DEFMACRO + +(defmacro define-search-methods (lessp methods) + `(macrolet ; remap symbols to the specialization package + ((node-key (x) `(,(intern "NODE-KEY") ,x)) + (left (x) `(,(intern "LEFT") ,x)) + (right (x) `(,(intern "RIGHT") ,x))) + + ,@(when (member '= methods) + `((defun ,(intern "FIND=") (key tree) + (loop + (cond ((null tree) (return nil)) + ((,lessp key (node-key tree)) (setq tree (left tree))) + ((,lessp (node-key tree) key) (setq tree (right tree))) + (t (return tree))))))) + + ;; Find a node with key less than or equal to KEY and as near it as possible. + ,@(when (member '<= methods) + `((defun ,(intern "FIND<=") (key tree) + (named-let recurse ((node tree) (best nil)) + (cond ((null node) best) + ((,lessp key (node-key node)) (recurse (left node) best)) + ((,lessp (node-key node) key) (recurse (right node) node)) + (t node)))))) + + ;; Find a node with key greater than or equal to KEY and as near it as possible. + ,@(when (member '>= methods) + `((defun ,(intern "FIND>=") (key tree) + (named-let recurse ((node tree) (best nil)) + (cond ((null node) best) + ((,lessp key (node-key node)) (recurse (left node) node)) + ((,lessp (node-key node) key) (recurse (right node) best)) + (t node)))))))) -(defun find= (key tree) - (loop - (cond ((null tree) (return nil)) - ((< key (node-key tree)) (setq tree (left tree))) - ((< (node-key tree) key) (setq tree (right tree))) - (t (return tree))))) - -(defun find<= (key tree) - (named-let recurse ((node tree) (best nil)) - (cond ((null node) best) - ((< key (node-key node)) (recurse (left node) best)) - ((< (node-key node) key) (recurse (right node) node)) - (t node)))) +;;; Each specialization of the structure is in its own package. +;;; This may not be the best way to do it. +;;; I was hoping that the FLET of BALANCE would eliminate consing when passing +;;; the arg, but it didn't. Block compilation might. +;;; So maybe I will need to rename the two structure types as something like +;;; SB-RBTREE::|TREE<SET<WORD>>| +;;; SB-RBTREE::|TREE<TABLE<FIXNUM,T>>| +;;; where the C++-template-like syntax indicates firstly whether the tree +;;; is used as a set versus k,v pairs, and secondly the element types, +;;; and devise a similar naming scheme for the insert/delete operators. +;;; Packages seemed like the natural choice. What are packages for if not this? +;;; (Anyway, I thought we only generate a warning about DEFPACKAGE and not also +;;; when changing the package. Maybe I was holding it wrong) + +(in-package "SB-RBTREE.WORD") +;; WORD trees will be used to find a code blob base address from an interior pointer, +;; both in the debugger and in stack scanning. +;; I'd like the type of the DATA slot to be SB-EXT:WORD, but I saw an excessive number +;; of compiler notes about consing from that. FIXNUM is ok as long as we use *untagged* +;; base pointers, and a specified comparator and not just "<" which would do the wrong +;; thing (because "negative" fixnums are large positive adddresses) +(declaim (inline addr<)) +(defun addr< (a b) + (< (sb-kernel:get-lisp-obj-address a) (sb-kernel:get-lisp-obj-address b))) +(sb-rbtree::define-tree-class + :key-type fixnum :value-type nil + :lessp addr<) +(declaim (inline node-key node-value)) +(defun node-key (node) (data node)) +(defun node-value (node) node) +(sb-rbtree::define-search-methods addr< (= <=)) +(export '(find= find<=)) + +(in-package "SB-RBTREE.MAP") +;; MAP trees can have any data associated with the key, which is an ordinary fixnum. +;; It would be conventional to store key and value as two slots, +;; but using a cons is actually better - the table operations +;; create new RBNODEs, but we can share the cons cells and/or update +;; the CDR (the user data) of any node while tree operations are in progress. +(sb-rbtree::define-tree-class :key-type fixnum :value-type t) +(declaim (inline node-key node-value)) +(defun node-key (node) (sb-ext:truly-the fixnum (car (data node)))) +(defun node-value (node) (cdr (data node))) +(sb-rbtree::define-search-methods < (= <= >=)) +(export '(find= find>= find<=)) diff --git a/src/code/repack-xref.lisp b/src/code/repack-xref.lisp index dd2f9f4ac7..11e3a893f3 100644 --- a/src/code/repack-xref.lisp +++ b/src/code/repack-xref.lisp @@ -41,25 +41,35 @@ (funcall function name it)))) (call-with-each-globaldb-name (lambda (name) - ;; In general it might be unsafe to call INFO with a NAME - ;; that is not valid for the kind of info being retrieved, - ;; as when the defaulting function tries to perform a - ;; sanity-check. But here it's safe. - (awhen (or (info :function :macro-function name) - (info :function :definition name)) + (awhen (or (and (symbolp name) (macro-function name)) + (and (legal-fun-name-p name) (find-fdefn name))) (cond ((and (fdefn-p it) (typep (fdefn-fun it) 'generic-function)) (loop for method in (sb-mop:generic-function-methods (fdefn-fun it)) - for fun = (sb-pcl::safe-method-fast-function method) - when fun do (process (sb-kernel:%fun-name fun) fun))) + for fun = (sb-pcl::safe-method-fast-function method) + when fun do (process (sb-kernel:%fun-name fun) fun))) ;; Methods are already processed above ((and (fdefn-p it) (typep (fdefn-name it) '(cons (member sb-pcl::slow-method - sb-pcl::fast-method))))) + sb-pcl::fast-method))))) (t - (process name it)))))))))) + (process name it)))) + #+sb-xref-for-internals + (let ((info (info :function :info name))) + (when info + (loop for transform in (fun-info-transforms info) + for fun = (transform-function transform) + ;; Defined using :defun-only and a later %deftransform. + unless (symbolp fun) + do (process transform fun)))))) + #+sb-xref-for-internals + (dohash ((name vop) *backend-template-names*) + (declare (ignore name)) + (let ((fun (vop-info-generator-function vop))) + (when fun + (process vop fun)))))))) ;;; Repack all xref data vectors in the system, potentially making ;;; them compact, but without changing their meaning: diff --git a/src/code/restart.lisp b/src/code/restart.lisp index 2fb3565758..8816281b2b 100644 --- a/src/code/restart.lisp +++ b/src/code/restart.lisp @@ -9,7 +9,6 @@ (in-package "SB-KERNEL") -#+stack-allocatable-fixed-objects (declaim (inline make-restart)) ;; to allow DX-allocation (defstruct (restart (:constructor make-restart @@ -32,7 +31,7 @@ ;; extent. (associated-conditions '() :type list)) -#-sb-fluid (declaim (freeze-type restart)) +(declaim (freeze-type restart)) (defmacro with-condition-restarts (condition-form restarts-form &body body) @@ -96,12 +95,13 @@ (let* ((name (car exp)) (args (if (eq name 'cerror) (cddr exp) (cdr exp)))) (if (member name '(signal error cerror warn)) - `(with-simple-condition-restarts - ',name - ,(and (eq name 'cerror) - (second exp)) - ,(first args) - ,@(rest args)) + `(sb-c::with-source-form ,expression + (with-simple-condition-restarts + ',name + ,(and (eq name 'cerror) + (second exp)) + ,(first args) + ,@(rest args))) expression)) expression)))) @@ -126,7 +126,7 @@ ;; the respective BODY. (let ((block-tag (gensym "BLOCK")) (temp-var (gensym))) - (labels ((parse-keywords-and-body (keywords-and-body) + (labels ((parse-keywords-and-body (keywords-and-body source-form) (do ((form keywords-and-body (cddr form)) (result '())) (nil) (destructuring-bind (&optional key (arg nil argp) &rest rest) @@ -137,14 +137,19 @@ (cond ((and (eq key :report) argp) (list :report-function - (if (stringp arg) - `#'(lambda (stream) - (write-string ,arg stream)) - `#',arg))) + `(sb-c::with-source-form ,source-form + ,(if (stringp arg) + `#'(lambda (stream) + (write-string ,arg stream)) + `#',arg)))) ((and (eq key :interactive) argp) - (list :interactive-function `#',arg)) + (list :interactive-function + `(sb-c::with-source-form ,source-form + #',arg))) ((and (eq key :test) argp) - (list :test-function `#',arg)) + (list :test-function + `(sb-c::with-source-form ,source-form + #',arg))) (t (return (values result form)))) result))))) @@ -156,7 +161,7 @@ 'restart-case clause)) (destructuring-bind (name lambda-list &body body) clause (multiple-value-bind (keywords body) - (parse-keywords-and-body body) + (parse-keywords-and-body body clause) (list name (gensym "TAG") keywords lambda-list body))))) (make-binding (clause-data) (destructuring-bind (name tag keywords lambda-list body) clause-data @@ -174,7 +179,7 @@ (locally (declare (optimize (safety 0))) (go ,tag))) ,@keywords))) - (make-apply-and-return (clause-data) + (make-apply-and-return (clause-data source-form) (destructuring-bind (name tag keywords lambda-list body) clause-data (declare (ignore name keywords)) (multiple-value-bind (body declarations) (parse-body body nil) @@ -185,11 +190,13 @@ (not (member (car lambda-list) '(&optional &key &aux)))) `(funcall (lambda ,lambda-list + (declare (sb-c::source-form ,source-form)) ,@declarations (progn ,@body)) ,temp-var)) (t `(apply (lambda ,lambda-list + (declare (sb-c::source-form ,source-form)) ,@declarations (progn ,@body)) ,temp-var))))))))) @@ -202,7 +209,7 @@ ,(mapcar #'make-binding clauses-data) (return-from ,block-tag ,(munge-restart-case-expression expression env))) - ,@(mapcan #'make-apply-and-return clauses-data)))))))) + ,@(mapcan #'make-apply-and-return clauses-data clauses)))))))) (defmacro with-simple-restart ((restart-name format-string &rest format-arguments) diff --git a/src/code/riscv-vm.lisp b/src/code/riscv-vm.lisp index 73abf95bbb..320eeebf8a 100644 --- a/src/code/riscv-vm.lisp +++ b/src/code/riscv-vm.lisp @@ -1,56 +1,20 @@ ;;; This file contains the RISC-V-specific runtime stuff. (in-package "SB-VM") - -#-sb-xc-host + (defun machine-type () "Return a string describing the type of the local machine." #-64-bit "RV32G" #+64-bit "RV64G") - -;;; FIXUP-CODE-OBJECT - -(defconstant-eqx +fixup-kinds+ #(:absolute :i-type :s-type :u-type) #'equalp) - -(defun u-and-i-inst-immediate (value) - (let ((hi (ash (+ value (expt 2 11)) -12))) - (values hi (- value (ash hi 12))))) - -(def!type short-immediate () `(signed-byte 12)) -(def!type short-immediate-fixnum () `(signed-byte ,(- 12 n-fixnum-tag-bits))) -(def!type u+i-immediate () - #-64-bit `(or (signed-byte 32) (unsigned-byte 32)) - #+64-bit `(or (integer #x-80000800 #x7ffff7ff) - (integer ,(+ (ash 1 64) #x-80000800) - ,(1- (ash 1 64))))) +(defun return-machine-address (scp) + ;; KLUDGE: Taken from SPARC backend. Why does `8' need to be added + ;; to the return address? Without it, backtraces get truncated and + ;; are incorrect. Are the other backends wrong as well by not adding + ;; 8? + (+ (context-register scp ra-offset) 8)) -(!with-bigvec-or-sap - (defun fixup-code-object (code offset fixup kind flavor) - (declare (type index offset)) - (declare (ignore flavor)) - (unless (zerop (rem offset sb-assem:+inst-alignment-bytes+)) - (error "Unaligned instruction? offset=#x~X." offset)) - #+64-bit - (unless (typep fixup 'u+i-immediate) - (error "Tried to fixup with ~a." fixup)) - (let ((sap (code-instructions code))) - (multiple-value-bind (u i) (u-and-i-inst-immediate fixup) - (ecase kind - (:absolute - (setf (sap-ref-32 sap offset) fixup)) - (:i-type - (setf (ldb (byte 12 20) (sap-ref-32 sap offset)) i)) - (:s-type - (setf (ldb (byte 5 7) (sap-ref-32 sap offset)) - (ldb (byte 5 0) i)) - (setf (ldb (byte 7 25) (sap-ref-32 sap offset)) - (ldb (byte 7 5) i))) - (:u-type - (setf (ldb (byte 20 12) (sap-ref-32 sap offset)) u))))) - nil)) ;;; CONTEXT-FLOAT-REGISTER -#-sb-xc-host (progn (define-alien-routine ("os_context_float_register_addr" context-float-register-addr) (* unsigned) (context (* os-context-t)) (index int)) @@ -84,13 +48,12 @@ (locally (declare (type (complex double-float) value)) (setf (sap-ref-double sap 0) (realpart value) - (sap-ref-double sap 8) (imagpart value)))))))) + (sap-ref-double sap 8) (imagpart value))))))) ;;; INTERNAL-ERROR-ARGS ;;; Given a (POSIX) signal context, extract the internal error ;;; arguments from the instruction stream. -#-sb-xc-host (defun internal-error-args (context) (declare (type (alien (* os-context-t)) context)) (let* ((pc (context-pc context)) @@ -105,7 +68,6 @@ ;;; Undo the effects of XEP-ALLOCATE-FRAME ;;; and point PC to FUNCTION -#-sb-xc-host (defun context-call-function (context function &optional arg-count) (declare (ignore context function arg-count)) (style-warn "Unimplemented.")) diff --git a/src/code/room.lisp b/src/code/room.lisp index aa5947990c..d3d16982a1 100644 --- a/src/code/room.lisp +++ b/src/code/room.lisp @@ -11,21 +11,14 @@ (in-package "SB-VM") -(eval-when (:compile-toplevel :load-toplevel :execute) - (export 'sb-sys::get-page-size "SB-SYS")) ;;;; type format database -(defstruct (room-info (:constructor make-room-info (mask name kind)) +;;; FIXME: this structure seems to no longer serve a purpose. +;;; We'd do as well with a simple-vector of (or symbol cons saetp). +(defstruct (room-info (:constructor make-room-info (name)) (:copier nil)) - ;; the mask applied to HeaderValue to compute object size - (mask 0 :type (and fixnum unsigned-byte) :read-only t) - ;; the name of this type - (name nil :type symbol :read-only t) - ;; kind of type (how to reconstitute an object) - (kind nil - :type (member :other :closure :instance :list :code :fdefn) - :read-only t)) + (name nil :type symbol :read-only t)) ; the name of this type (declaim (freeze-type room-info)) (defun room-info-type-name (info) @@ -34,55 +27,29 @@ (room-info-name info))) (defconstant tiny-boxed-size-mask #xFF) -(defun !compute-room-infos () - (let ((infos (make-array 256 :initial-element nil)) - (default-size-mask (mask-field (byte 23 0) -1))) +(defun compute-room-infos () + (let ((infos (make-array 256 :initial-element nil))) (dolist (obj *primitive-objects*) (let ((widetag (primitive-object-widetag obj)) (lowtag (primitive-object-lowtag obj)) (name (primitive-object-name obj))) - (when (and (eq lowtag 'other-pointer-lowtag) - (not (member widetag '(t nil)))) - (setf (svref infos (symbol-value widetag)) - (case name - (fdefn (make-room-info 0 name :fdefn)) - (symbol (make-room-info tiny-boxed-size-mask name :other)) - (t (make-room-info default-size-mask name :other))))))) - - (let ((info (make-room-info default-size-mask 'array-header :other))) + (when (and (member lowtag '(other-pointer-lowtag fun-pointer-lowtag + instance-pointer-lowtag)) + (not (member widetag '(t nil simple-fun-widetag)))) + (setf (svref infos (symbol-value widetag)) (make-room-info name))))) + + (let ((info (make-room-info 'array-header))) (dolist (code (list #+sb-unicode complex-character-string-widetag complex-base-string-widetag simple-array-widetag complex-bit-vector-widetag complex-vector-widetag - complex-array-widetag complex-vector-nil-widetag)) + complex-array-widetag)) (setf (svref infos code) info))) - (setf (svref infos bignum-widetag) - ;; Lose 1 more bit than n-widetag-bits because fullcgc robs 1 bit, - ;; not that this is expected to work concurrently with gc. - (make-room-info (ash most-positive-word (- (1+ n-widetag-bits))) - 'bignum :other)) - - (setf (svref infos closure-widetag) - (make-room-info short-header-max-words 'closure :closure)) - (dotimes (i (length *specialized-array-element-type-properties*)) (let ((saetp (aref *specialized-array-element-type-properties* i))) - (when (saetp-specifier saetp) ;; SIMPLE-ARRAY-NIL is a special case. - (setf (svref infos (saetp-typecode saetp)) saetp)))) - - (setf (svref infos simple-array-nil-widetag) - (make-room-info 0 'simple-array-nil :other)) - - (setf (svref infos code-header-widetag) - (make-room-info 0 'code :code)) - - (setf (svref infos instance-widetag) - (make-room-info 0 'instance :instance)) - - (setf (svref infos funcallable-instance-widetag) - (make-room-info short-header-max-words 'funcallable-instance :closure)) + (setf (svref infos (saetp-typecode saetp)) saetp))) - (let ((cons-info (make-room-info 0 'cons :list))) + (let ((cons-info (make-room-info 'cons))) ;; A cons consists of two words, both of which may be either a ;; pointer or immediate data. According to the runtime this means ;; either a fixnum, a character, an unbound-marker, a single-float @@ -109,7 +76,8 @@ infos)) -(define-load-time-global *room-info* (!compute-room-infos)) +(define-load-time-global *room-info* (compute-room-infos)) +(declaim (type (simple-vector 256) *room-info*)) (defconstant-eqx +heap-spaces+ '((:dynamic "Dynamic space" dynamic-usage) @@ -143,7 +111,9 @@ (defun %space-bounds (space) (macrolet ((bounds (a b) `(values (%make-lisp-obj ,a) (%make-lisp-obj ,b)))) (ecase space - (:static + (:static ;; These bounds are appropriate for computing the space usage + ;; but NOT for computing iteration bounds, because there are + ;; "unformatted" words preceding the lowest addressable object. (bounds static-space-start (sap-int *static-space-free-pointer*))) (:read-only @@ -155,10 +125,10 @@ (sap-int *fixedobj-space-free-pointer*))) #+immobile-space (:variable - (bounds varyobj-space-start - (sap-int *varyobj-space-free-pointer*))) + (bounds text-space-start + (sap-int *text-space-free-pointer*))) (:dynamic - (bounds (current-dynamic-space-start) + (bounds dynamic-space-start (sap-int (dynamic-space-free-pointer))))))) ;;; Return the total number of bytes used in SPACE. @@ -169,13 +139,6 @@ (multiple-value-bind (start end) (%space-bounds space) (ash (- end start) n-fixnum-tag-bits)))) -;;; Round SIZE (in bytes) up to the next dualword boundary. A dualword -;;; is eight bytes on platforms with 32-bit word size and 16 bytes on -;;; platforms with 64-bit word size. -#-sb-fluid (declaim (inline round-to-dualword)) -(defun round-to-dualword (size) - (logand (the word (+ size lowtag-mask)) (lognot lowtag-mask))) - (defun instance-length (instance) ; excluding header, not aligned to even ;; Add 1 if expressed length PLUS header (total number of words) would be ;; an even number, and the hash state bits indicate hashed-and-moved. @@ -192,131 +155,24 @@ (ash header-word (- hash-slot-present-flag)) 1)))) -;;; Return the vector OBJ, its WIDETAG, and the number of octets -;;; required for its storage (including padding and alignment). -(defun reconstitute-vector (obj saetp) - (declare (type (simple-array * (*)) obj) - (type specialized-array-element-type-properties saetp)) - (let* ((length (+ (length obj) - (saetp-n-pad-elements saetp))) - (n-bits (saetp-n-bits saetp)) - (alignment-pad (floor 7 n-bits)) - (n-data-octets (if (>= n-bits 8) - (* length (ash n-bits -3)) - (ash (* (+ length alignment-pad) - n-bits) - -3)))) - (values obj - (saetp-typecode saetp) - (round-to-dualword (+ (* vector-data-offset n-word-bytes) - n-data-octets))))) - -;;; * If symbols are 7 words incl header, as they are on 32-bit w/threads, -;;; then the part of NIL that manifests as symbol slots consumes 6 words -;;; (less the header) because NIL's symbol widetag precedes it by 1 word. -;;; So, there are 6 post-header words and 2 pre-header: one containing -;;; the widetag (not that it is ever read), and one 0 word. -;;; * If symbols are 6 words incl header, as they are on 64-bit and -;;; 32-bit w/o threads, then the symbol-like part of NIL is 5 words, -;;; which aligns up to 6, plus the two pre-header words. -;;; So either way, NIL's alignment padding makes it come out to 8 words in total. -(defconstant sizeof-nil-in-words (+ 2 (sb-int:align-up (1- sb-vm:symbol-size) 2))) - -(defun primitive-object-size (object) - "Return number of bytes of heap or stack directly consumed by OBJECT" - (if (is-lisp-pointer (get-lisp-obj-address object)) - (let ((words - (typecase object - (cons 2) - (instance (1+ (instance-length object))) - (function - (when (= (fun-subtype object) simple-fun-widetag) - (return-from primitive-object-size - (primitive-object-size (fun-code-header object)))) - (1+ (get-closure-length object))) - (null sizeof-nil-in-words) - (code-component - (return-from primitive-object-size (code-object-size object))) - (fdefn 4) ; no length stored in the header - ;; Anything else is an OTHER pointer. - (t - (let ((room-info - (aref *room-info* (%other-pointer-widetag object)))) - (if (arrayp object) - (cond ((array-header-p object) - (+ array-dimensions-offset (array-rank object))) - ((simple-array-nil-p object) 2) - (t - (return-from primitive-object-size - (nth-value 2 (reconstitute-vector object room-info))))) - ;; Other things (symbol, value-cell, etc) - ;; don't have a sizer, so use GET-HEADER-DATA - (1+ (logand (get-header-data object) - (room-info-mask room-info))))))))) - (* (align-up words 2) n-word-bytes)) - 0)) - -;;; Given the address (untagged, aligned, and interpreted as a FIXNUM) -;;; of a lisp object, return the object, its "type code" (either -;;; LIST-POINTER-LOWTAG or a header widetag), and the number of octets -;;; required for its storage (including padding and alignment). Note -;;; that this function is designed to NOT CONS, even if called -;;; out-of-line. -;;; FIXME: size calculation should be via PRIMITIVE-OBJECT-SIZE, not reinvented +;;; Macros not needed after this file (and avoids a redefinition warning this way) +(eval-when (:compile-toplevel) +(defmacro widetag@baseptr (sap) + #+big-endian `(sap-ref-8 ,sap ,(1- n-word-bytes)) + #+little-endian `(sap-ref-8 ,sap 0)) + +(defmacro lispobj@baseptr (sap widetag) + `(%make-lisp-obj + (logior (sap-int ,sap) + (logand (deref (extern-alien "widetag_lowtag" (array char 256)) ,widetag) + lowtag-mask))))) + +;;; This uses the funny fixnum representation of ADDRESS. I'd like to change this +;;; to take a SAP but god forbid people are using it? +;;; DO NOT USE THIS! It is soon to be removed (defun reconstitute-object (address) - (let* ((object-sap (int-sap (get-lisp-obj-address address))) - (header (sap-ref-word object-sap 0)) - (widetag (logand header widetag-mask)) - (header-value (ash header (- n-widetag-bits))) - (info (svref *room-info* widetag))) - (macrolet - ((boxed-size (header-value) - `(round-to-dualword (ash (1+ ,header-value) word-shift))) - (tagged-object (tag) - `(%make-lisp-obj (logior ,tag (get-lisp-obj-address address))))) - (cond - ;; Pick off arrays, as they're the only plausible cause for - ;; a non-nil, non-ROOM-INFO object as INFO. - ((specialized-array-element-type-properties-p info) - (reconstitute-vector (tagged-object other-pointer-lowtag) info)) - ((= widetag filler-widetag) - (values nil filler-widetag (boxed-size header-value))) - ((null info) - (error "Unrecognized widetag #x~2,'0X in reconstitute-object" - widetag)) - - (t - (case (room-info-kind info) - (:list - (values (tagged-object list-pointer-lowtag) - list-pointer-lowtag - (* 2 n-word-bytes))) - - (:instance - (let ((instance (tagged-object instance-pointer-lowtag))) - (values instance - widetag - (boxed-size (instance-length instance))))) - - (:closure ; also funcallable-instance - (values (tagged-object fun-pointer-lowtag) - widetag - (boxed-size (logand header-value short-header-max-words)))) - - (:code - (let ((c (tagged-object other-pointer-lowtag))) - (values c - code-header-widetag - (code-object-size c)))) - - (:fdefn - (values (tagged-object other-pointer-lowtag) widetag - (* fdefn-size n-word-bytes))) - - (:other - (values (tagged-object other-pointer-lowtag) - widetag - (boxed-size (logand header-value (room-info-mask info))))))))))) + (let ((sap (descriptor-sap address))) + (lispobj@baseptr sap (widetag@baseptr sap)))) ;;; Iterate over all the objects in the contiguous block of memory ;;; with the low address at START and the high address just before @@ -327,52 +183,50 @@ (defun map-objects-in-range (fun start end &optional (strict-bound t)) (declare (type function fun)) (declare (dynamic-extent fun)) - (named-let iter ((start start)) - (cond - ((< (get-lisp-obj-address start) (get-lisp-obj-address end)) - (multiple-value-bind (obj typecode size) (reconstitute-object start) - ;; SIZE is almost surely a fixnum. Non-fixnum would mean at least - ;; a 512MB object if 32-bit words, and is inconceivable if 64-bit. - (aver (not (logtest (the word size) lowtag-mask))) - (unless (= typecode filler-widetag) - (funcall fun obj typecode size)) - ;; This special little dance is to add a number of octets - ;; (and it had best be a number evenly divisible by our - ;; allocation granularity) to an unboxed, aligned address - ;; masquerading as a fixnum. Without consing. - (iter (%make-lisp-obj - (mask-field (byte #.n-word-bits 0) - (+ (get-lisp-obj-address start) - size)))))) - (strict-bound + (let ((start (descriptor-sap start)) + (end (descriptor-sap end))) + (loop + (if (sap>= start end) (return)) + (let ((word (sap-ref-word start 0))) + (cond + ((= (logand word widetag-mask) filler-widetag) ; pseudo-object + (let ((size (ash (filler-nwords word) word-shift))) + (setq start (sap+ start size)))) + ((= word most-positive-word) + ;; has to be a pseudo-cons resulting from removing an insignificant + ;; sign word of a bignum. Don't call FUN + (setq start (sap+ start (* 2 n-word-bytes)))) + (t + (binding* + ((widetag (widetag@baseptr start)) + (obj (lispobj@baseptr start widetag)) + ((typecode size) + ;; PRIMITIVE-OBJECT-SIZE works on conses, but they're exceptions already + ;; because of absence of a widetag, so may as well not call the sizer. + (if (listp obj) + (values list-pointer-lowtag (* 2 n-word-bytes)) + (values widetag (primitive-object-size obj))))) + ;; SIZE is surely a fixnum. Non-fixnum would imply at least + ;; a 512MB object if 32-bit words, and is inconceivable if 64-bit. + ;; But check to be sure. + (aver (not (logtest (the fixnum size) lowtag-mask))) + (funcall fun obj typecode size) + (setq start (sap+ start size))))))) + (when strict-bound ;; If START is not eq to END, then we have blown past our endpoint. - (aver (eq start end)))))) + #+sb-devel + (unless (sap= start end) + ;; don't make things go more wrong than they already are. + (alien-funcall (extern-alien "printf" (function void system-area-pointer)) + (vector-sap #.(format nil "map-objects-in-range failure~%"))) + (ldb-monitor)) + #-sb-devel + (aver (sap= start end))))) ;;; Access to the GENCGC page table for better precision in ;;; MAP-ALLOCATED-OBJECTS -#+gencgc +#+immobile-space (progn - (define-alien-type (struct page) - (struct page - ;; To cut down the size of the page table, the scan_start_offset - ;; - a/k/a "start" - is measured in 4-byte integers regardless - ;; of word size. This is fine for 32-bit address space, - ;; but if 64-bit then we have to scale the value. Additionally - ;; there is a fallback for when even the scaled value is too big. - ;; (None of this matters to Lisp code for the most part) - (start #+64-bit (unsigned 32) #-64-bit signed) - ;; On platforms with small enough GC pages, this field - ;; will be a short. On platforms with larger ones, it'll - ;; be an int. - ;; Measured in bytes; the low bit has to be masked off. - (bytes-used (unsigned - #.(if (typep gencgc-card-bytes '(unsigned-byte 16)) - 16 - 32))) - (flags (unsigned 8)) - (gen (signed 8)))) - #+immobile-space - (progn (define-alien-type (struct immobile-page) ;; ... and yet another place for Lisp to become out-of-sync with C. (struct immobile-page @@ -384,11 +238,7 @@ (page-link (unsigned 16)) (prior-free-index (unsigned 16)))) (define-alien-variable "fixedobj_pages" (* (struct immobile-page)))) - (declaim (inline find-page-index)) - (define-alien-routine ("ext_find_page_index" find-page-index) - long (index unsigned)) - (define-alien-variable "next_free_page" sb-kernel::page-index-t) - (define-alien-variable "page_table" (* (struct page)))) +(define-alien-variable "next_free_page" sb-kernel::page-index-t) #+immobile-space (progn @@ -458,46 +308,54 @@ We could try a few things to mitigate this: ;; You can't specify :ALL and also a list of spaces. Check that up front. (do-rest-arg ((space) spaces) (the spaces space)) (flet ((do-1-space (space) - (ecase space - (:static - ;; Static space starts with NIL, which requires special - ;; handling, as the header and alignment are slightly off. - (multiple-value-bind (start end) (%space-bounds space) - (declare (ignore start)) - (funcall fun nil symbol-widetag (* sizeof-nil-in-words n-word-bytes)) - (let ((start (+ (logandc2 sb-vm:nil-value sb-vm:lowtag-mask) - (ash (- sizeof-nil-in-words 2) sb-vm:word-shift)))) - (map-objects-in-range fun - (ash start (- sb-vm:n-fixnum-tag-bits)) - end)))) - - ((:read-only #-gencgc :dynamic) - ;; Read-only space (and dynamic space on cheneygc) is a block - ;; of contiguous allocations. - (multiple-value-bind (start end) (%space-bounds space) - (map-objects-in-range fun start end))) - #+immobile-space - (:immobile - ;; Filter out filler objects. These either look like cons cells - ;; in fixedobj subspace, or code without enough header words - ;; in varyobj subspace. (cf 'filler_obj_p' in gc-internal.h) - (dx-flet ((filter (obj type size) - (unless (= type list-pointer-lowtag) - (funcall fun obj type size)))) - (map-immobile-objects #'filter :fixed)) - (dx-flet ((filter (obj type size) - (unless (and (code-component-p obj) - (code-obj-is-filler-p obj)) - (funcall fun obj type size)))) - (map-immobile-objects #'filter :variable))) - - #+gencgc - (:dynamic + (ecase space + (:static + ;; Static space starts with NIL, which requires special + ;; handling, as the header and alignment are slightly off. + (funcall fun nil symbol-widetag (* sizeof-nil-in-words n-word-bytes)) + (let ((start (%make-lisp-obj static-space-objects-start)) + (end (%make-lisp-obj (sap-int *static-space-free-pointer*)))) + (map-objects-in-range fun start end))) + ((:read-only #-gencgc :dynamic) + ;; Read-only space (and dynamic space on cheneygc) is a block + ;; of contiguous allocations. + (multiple-value-bind (start end) (%space-bounds space) + (map-objects-in-range fun start end))) + #+immobile-space + (:immobile + (with-system-mutex (*allocator-mutex*) + (map-immobile-objects fun :variable)) + ;; Filter out padding words + (dx-flet ((filter (obj type size) + (unless (= type list-pointer-lowtag) + (funcall fun obj type size)))) + (map-immobile-objects #'filter :fixed)))))) + (do-rest-arg ((space) spaces) + (if (eq space :dynamic) + (without-gcing #+cheneygc (do-1-space space) + #+gencgc (walk-dynamic-space fun #b1111111 0 0)) + (do-1-space space))))) + +;;; Using the mask bits you can make many different match conditions resulting +;;; from a product of {boxed,unboxed,code,any} x {large,non-large,both} +;;; e.g. mask = #b10011" constraint = "#b10010" +;;; matches "large & (unboxed | code)" +;;; +;;; I think, when iterating over only code, that if we grab the code_allocator_lock +;;; and free_pages_lock, that this can be made reliable (both crash-free and +;;; guaranteed to visit all chosen objects) despite other threads running. +;;; As things are it is only "maybe" reliable, regardless of the parameters. +#+gencgc +(defun walk-dynamic-space (fun generation-mask + page-type-mask page-type-constraint) + (declare (function fun) + (type (unsigned-byte 7) generation-mask) + (type (unsigned-byte 5) page-type-mask page-type-constraint)) ;; Dynamic space on gencgc requires walking the GC page tables ;; in order to determine what regions contain objects. ;; We explicitly presume that any pages in an allocation region - ;; that are in-use have a BYTES-USED of GENCGC-CARD-BYTES + ;; that are in-use have a BYTES-USED of GENCGC-PAGE-BYTES ;; (indicating a full page) or an otherwise-valid BYTES-USED. ;; We also presume that the pages of an open allocation region ;; after the first page, and any pages that are unallocated, @@ -505,113 +363,69 @@ We could try a few things to mitigate this: ;; Our procedure is to scan forward through the page table, ;; maintaining an "end pointer" until we reach a page where - ;; BYTES-USED is not GENCGC-CARD-BYTES or we reach + ;; BYTES-USED is not GENCGC-PAGE-BYTES or we reach ;; NEXT-FREE-PAGE. We then MAP-OBJECTS-IN-RANGE if the range ;; is not empty, and proceed to the next page (unless we've hit - ;; NEXT-FREE-PAGE). We happily take advantage of the fact that - ;; MAP-OBJECTS-IN-RANGE will simply return if passed two - ;; coincident pointers for the range. + ;; NEXT-FREE-PAGE). ;; FIXME: WITHOUT-GCING prevents a GC flip, but doesn't prevent ;; closing allocation regions and opening new ones. This may ;; prove to be an issue with concurrent systems, or with ;; spectacularly poor timing for closing an allocation region ;; in a single-threaded system. - (close-current-gc-region) - (do ((initial-next-free-page next-free-page) - ;; This is a "funny" fixnum - essentially the bit cast of a pointer - (start (the fixnum (%make-lisp-obj (current-dynamic-space-start)))) - (page-index 0 (1+ page-index)) - ;; SPAN is a page count, for which an unsigned fixnum is adequate. - (span 0)) - ;; We can safely iterate up to and including next_free_page - ;; even if next_free_page is the total number of pages in the space, - ;; because there is one extra page table entry as a sentinel. - ;; The extra page always has 0 bytes used, so we'll observe the end - ;; of a contiguous block without needing a termination clause to - ;; handle a final sequence of totally full pages that exactly abut - ;; the heap end. [Also note that for our purposes, contiguous blocks - ;; can span different GC generations and page types, whereas within - ;; GC, a page ends a block if the next differs in those aspects] - ((> page-index initial-next-free-page)) - ;; The type constraint on PAGE-INDEX is probably too generous, + (close-thread-alloc-region) + (do ((initial-next-free-page next-free-page) + (base (int-sap dynamic-space-start)) + (start-page 0) + (end-page 0) + (end-page-bytes-used 0)) + ((> start-page initial-next-free-page)) + ;; The type constraint on page indices is probably too generous, ;; but it does its job of producing efficient code. - (declare (type (integer 0 (#.(/ (ash 1 n-machine-word-bits) gencgc-card-bytes))) - page-index) - (type (and fixnum unsigned-byte) span)) - (let ((page-bytes-used ; The low bit of bytes-used is the need-to-zero flag. - (logandc1 1 (slot (deref page-table page-index) 'bytes-used)))) - (if (= page-bytes-used gencgc-card-bytes) - (incf span) - ;; RANGE-END forces funny increment of START by the extent in bytes, - ;; returning a negative fixum when the word's high bit flips. - ;; The proper way to add "funny" fixnums is via +-MODFX which for - ;; reasons unknown isn't defined on all backends. - (macrolet - ((range-end (extra) - `(truly-the fixnum - (%make-lisp-obj - (logand most-positive-word - ;; The first and third addends are known good - ;; The second needs help to avoid an expensive ASH - (+ (get-lisp-obj-address start) - (logand (* span gencgc-card-bytes) most-positive-word) - ,extra)))))) - (map-objects-in-range fun start (range-end page-bytes-used) - (< page-index initial-next-free-page)) - ;; In a certain rare situation, we must restart the next loop iteration - ;; at exactly PAGE-INDEX instead of 1+ PAGE-INDEX. - ;; Normally the contents of PAGE-INDEX are always included in the - ;; current range. But what if it contributed 0 bytes to the range? - ;; - ;; N : #x8000 bytes used - ;; N+1 : #x8000 bytes used - ;; N+2 : 0 bytes used <- PAGE-INDEX now points here - ;; N+3 : initially 0 bytes, then gets some bytes - ;; - ;; We invoked the map function with page_address(N) for #x10000 bytes. - ;; Suppose that function consed a partly unboxed object starting on - ;; page N+2 extending to page N+3, and that NEXT-FREE-PAGE was greater - ;; than both to begin with, so the termination condition isn't in play. - ;; In the best case scenario, resuming the scan at page N+3 (mid-object) - ;; would read valid widetags, but in the worst case scenario, we get - ;; random bits. Page N+2 needs a fighting chance to be the start of - ;; a range, so go back 1 page if the current page had zero bytes used - ;; and the span exceeded 1. That is, always make forward progress. - (setq start (range-end (cond ((and (zerop page-bytes-used) (plusp span)) - (decf page-index) - 0) - (t - gencgc-card-bytes))) - span 0))))))))) - - (do-rest-arg ((space) spaces) - (if (eq space :dynamic) - (without-gcing (do-1-space space)) - (do-1-space space))))) - -;; Start with a Lisp rendition of ensure_region_closed() on the active -;; thread's region, since users are often surprised to learn that a -;; just-consed object can't necessarily be seen by MAP-ALLOCATED-OBJECTS. + (declare (type (integer 0 (#.(/ (ash 1 n-machine-word-bits) gencgc-page-bytes))) + start-page end-page)) + (setq end-page start-page) + (loop (setq end-page-bytes-used + (ash (ash (slot (deref page-table end-page) 'words-used*) -1) + word-shift)) + ;; See 'page_ends_contiguous_block_p' in gencgc.c + (when (or (< end-page-bytes-used gencgc-page-bytes) + (= (slot (deref page-table (1+ end-page)) 'start) 0)) + (return)) + (incf end-page)) + (let ((start (sap+ base (truly-the signed-word + (logand (* start-page gencgc-page-bytes) + most-positive-word)))) + (end (sap+ base (truly-the signed-word + (logand (+ (* end-page gencgc-page-bytes) + end-page-bytes-used) + most-positive-word))))) + (when (sap> end start) + (let ((flags (slot (deref page-table start-page) 'flags))) + ;; The GEN slot is declared as (SIGNED 8) which does not satisfy the + ;; type restriction on the first argument to LOGBITP. + ;; Masking it to 3 bits fixes that, and allows using the other 5 bits + ;; for something potentially. + (when (and (logbitp (logand (slot (deref page-table start-page) 'gen) 7) + generation-mask) + (= (logand flags page-type-mask) page-type-constraint)) + ;; FIXME: should exclude (0 . 0) conses on PAGE_TYPE_{BOXED,UNBOXED} + ;; resulting from zeroing the tail of a bignum or vector etc. + (map-objects-in-range fun + (%make-lisp-obj (sap-int start)) + (%make-lisp-obj (sap-int end)) + (< start-page initial-next-free-page)))))) + (setq start-page (1+ end-page)))) + +;; Users are often surprised to learn that a just-consed object can't +;; necessarily be seen by MAP-ALLOCATED-OBJECTS, so close the region +;; to update the page table. ;; Since we're in WITHOUT-GCING, there can be no interrupts. -;; This is probably better than calling MAP-OBJECTS-IN-RANGE on the -;; thread's region, because then we might visit some page twice -;; by doing that. -;; (And seeing small consing by other threads is hopeless either way) -(defun close-current-gc-region () - #+gencgc - (let ((region-struct - #+sb-thread (sap+ (sb-thread::current-thread-sap) - (ash thread-alloc-region-slot word-shift)) - ;; If no threads, the region structure is 2 words past the static space start, - ;; embedded in an unboxed array. - #-sb-thread (int-sap (+ static-space-start (* 2 n-word-bytes))))) - ;; The 'start_addr' field is at word index 3 of the structure (see gencgc-alloc-region.h). - (unless (eql (sap-ref-word region-struct (ash 3 word-shift)) 0) - (alien-funcall (extern-alien "gc_close_region" (function void system-area-pointer int)) - region-struct - 1)) - nil)) +;; Moreover it's probably not safe in the least to walk any thread's +;; allocation region, unless the observer and observed aren't consing. +(defun close-thread-alloc-region () + #+gencgc (alien-funcall (extern-alien "close_current_thread_tlab" (function void))) + nil) ;;;; MEMORY-USAGE @@ -624,15 +438,20 @@ We could try a few things to mitigate this: (used-bytes (ash (- free-pointer start) n-fixnum-tag-bits)) (holes '()) (hole-bytes 0)) - (map-immobile-objects - (lambda (obj type size) - (let ((address (logandc2 (get-lisp-obj-address obj) lowtag-mask))) - (when (case subspace - (:fixed (= type list-pointer-lowtag)) - (:variable (hole-p address))) - (push (cons address size) holes) - (incf hole-bytes size)))) - subspace) + (if (eq subspace :fixed) + (map-immobile-objects + (lambda (obj type size) + (let ((address (logandc2 (get-lisp-obj-address obj) lowtag-mask))) + (when (= type list-pointer-lowtag) + (incf hole-bytes size)))) + subspace) + (let ((sum-sizes 0)) + (map-immobile-objects + (lambda (obj type size) + (declare (ignore obj type)) + (incf sum-sizes size)) + subspace) + (setq hole-bytes (- used-bytes sum-sizes)))) (values holes hole-bytes used-bytes))) (defun show-fragmentation (&key (subspaces '(:fixed :variable)) @@ -818,9 +637,9 @@ We could try a few things to mitigate this: (eql type funcallable-instance-widetag)) (incf total-objects) (let* ((layout (if (eql type funcallable-instance-widetag) - (%fun-layout obj) - (%instance-layout obj))) - (classoid (layout-classoid layout)) + (%fun-wrapper obj) + (%instance-wrapper obj))) + (classoid (wrapper-classoid layout)) (found (ensure-gethash classoid totals (cons 0 0))) (size size)) (declare (fixnum size)) @@ -875,11 +694,6 @@ We could try a few things to mitigate this: ;;;; PRINT-ALLOCATED-OBJECTS -;;; This notion of page-size is completely arbitrary - it affects 2 things: -;;; (1) how much output to print "per page" in print-allocated-objects -;;; (2) sb-sprof deciding how many regions [sic] were made if #+cheneygc -(defun get-page-size () sb-c:+backend-page-bytes+) - ;;; This function is sheer madness. You're better off using ;;; LIST-ALLOCATED-OBJECTS and then iterating over that, to avoid ;;; seeing all the junk created while doing this thing. @@ -890,10 +704,12 @@ We could try a few things to mitigate this: (type stream stream) (type spaces space) (type (or index null) type larger smaller count)) (multiple-value-bind (start end) (%space-bounds space) + (when (eq space :static) + (setq start (%make-lisp-obj static-space-objects-start))) (let* ((space-start (ash start n-fixnum-tag-bits)) (space-end (ash end n-fixnum-tag-bits)) (space-size (- space-end space-start)) - (pagesize (get-page-size)) + (pagesize sb-c:+backend-page-bytes+) (start (+ space-start (round (* space-size percent) 100))) (printed-conses (make-hash-table :test 'eq)) (pages-so-far 0) @@ -963,19 +779,6 @@ We could try a few things to mitigate this: ;;;; LIST-ALLOCATED-OBJECTS, LIST-REFERENCING-OBJECTS -(defvar *ignore-after* nil) - -(defun valid-obj (space x) - (or (not (eq space :dynamic)) - ;; this test looks bogus if the allocator doesn't work linearly, - ;; which I suspect is the case for GENCGC. -- CSR, 2004-06-29 - (< (get-lisp-obj-address x) (get-lisp-obj-address *ignore-after*)))) - -(defun maybe-cons (space x stuff) - (if (valid-obj space x) - (cons x stuff) - stuff)) - (defun list-allocated-objects (space &key type larger smaller count test) (declare (type (or (eql :all) spaces) space) @@ -1061,11 +864,6 @@ We could try a few things to mitigate this: #+stack-grows-downward-not-upward (iter + *control-stack-end* sap>) #-stack-grows-downward-not-upward (iter - *control-stack-start* sap<))) -(declaim (inline symbol-extra-slot-p)) -(defun symbol-extra-slot-p (x) - (> (logand (get-header-data x) tiny-boxed-size-mask) - (1- symbol-size))) - ;;; Invoke FUNCTOID (a macro or function) on OBJ and any values in MORE. ;;; Note that neither OBJ nor items in MORE undergo ONCE-ONLY treatment. ;;; The fact that FUNCTOID can be a macro allows treatment of its first argument @@ -1095,12 +893,13 @@ We could try a few things to mitigate this: ;; These two are in fact generally the most frequently occurring type. ,.(make-case 'cons `(car ,obj) `(cdr ,obj)) ,.(make-case* 'instance - `(let ((.l. (%instance-layout ,obj))) - ;; Though we've bound %INSTANCE-LAYOUT to a variable, - ;; pass the form %INSTANCE-LAYOUT to functoid - ;; in case it wants to examine the form + ;; %INSTANCE-LAYOUT is defknown'ed to return a LAYOUT, + ;; but heap walking might encounter an instance with no layout, + ;; hence the need to access the slot opaquely. + `(unless (eql 0 #+compact-instance-header (%primitive %instance-layout ,obj) + #-compact-instance-header (%instance-ref ,obj 0)) (,functoid (%instance-layout ,obj) ,@more) - (do-instance-tagged-slot (.i. ,obj :layout .l. :pad nil) + (do-instance-tagged-slot (.i. ,obj) (,functoid (%instance-ref ,obj .i.) ,@more)))) (function (typecase ,obj @@ -1112,23 +911,39 @@ We could try a few things to mitigate this: ;; if functoid is a macro that does nothing. (,functoid .o. ,@more))) ,.(make-case* 'funcallable-instance - `(let ((.l. (%fun-layout ,obj))) + `(progn ;; As for INSTANCE, allow the functoid to see the access form (,functoid (%fun-layout ,obj) ,@more) (,functoid (%funcallable-instance-fun ,obj) ,@more) - (ecase (layout-bitmap .l.) - (#.sb-kernel:+layout-all-tagged+ - (loop for .i. from instance-data-start ; exclude layout + ;; Unfortunately for FUNCALLABLE-INSTANCEs, the relation + ;; between layout bitmap indices and indices as given to + ;; FUNCALLABLE-INSTANCE-INFO is not so obvious, and it's + ;; both tricky and unnecessary to generalize iteration. + ;; So just hardcode the few cases that exist. + #+compact-instance-header + (ecase (wrapper-bitmap (%fun-wrapper ,obj)) + (-1 ; external trampoline, all slots are tagged + ;; In this case, the trampoline word is scanned, with no ill effect. + (loop for .i. from 0 to (- (get-closure-length ,obj) funcallable-instance-info-offset) do (,functoid (%funcallable-instance-info ,obj .i.) ,@more))) - (#b0110 - ;; A pedantically correct kludge which shall remain unless need arises - ;; for more general partially unboxed FINs. - ;; payload word 0 is raw (but looks like a fixnum, by design) - ;; word 1 is the fin-fun which we already accounted for above - ;; word 2 (info slot 0) is the only one that hasn't been processed. - ;; words 3 and 4 are raw but looks like fixnums by accident. - (,functoid (%funcallable-instance-info ,obj 0) ,@more))))) + (#b0110 ; internal trampoline, 2 raw slots, 1 tagged slot + ;; ^ ---- trampoline + ;; ^------ implementation function + ;; ^------- (FUNCALLABLE-INSTANCE-INFO 0) + ;; and the rest of the words are raw. + (,functoid (%funcallable-instance-info ,obj 0) ,@more))) + #-compact-instance-header + (progn + (aver (eql (wrapper-bitmap (%fun-wrapper ,obj)) -4)) + ;; v ----trampoline + ;; = #b1...1100 + ;; ^----- layout + ;; ^------ implementation function + ;; ^------- (FUNCALLABLE-INSTANCE-INFO 0) + (loop for .i. from 0 + to (- (get-closure-length ,obj) funcallable-instance-info-offset) + do (,functoid (%funcallable-instance-info ,obj .i.) ,@more))))) .,(make-case 'function))) ; in case there was code provided for it (t ;; TODO: the generated code is pretty horrible. OTHER-POINTER-LOWTAG @@ -1147,11 +962,9 @@ We could try a few things to mitigate this: ,.(make-case 'array) ,.(make-case* 'symbol `(,functoid (%primitive sb-c:fast-symbol-global-value ,obj) ,@more) - `(,functoid (symbol-info ,obj) ,@more) + `(,functoid (symbol-%info ,obj) ,@more) `(,functoid (symbol-name ,obj) ,@more) - `(,functoid (symbol-package ,obj) ,@more) - `(when (symbol-extra-slot-p ,obj) - (,functoid (symbol-extra ,obj) ,@more))) + `(,functoid (symbol-package ,obj) ,@more)) ,.(make-case 'fdefn `(fdefn-name ,obj) `(fdefn-fun ,obj) @@ -1168,7 +981,7 @@ We could try a few things to mitigate this: ;; to enliven any object other than code. #+immobile-code `(%make-lisp-obj - (alien-funcall (extern-alien "fdefn_callee_lispobj" (function unsigned unsigned)) + (alien-funcall (extern-alien "decode_fdefn_rawfun" (function unsigned unsigned)) (logandc2 (get-lisp-obj-address ,obj) lowtag-mask)))) ,.(make-case* 'code-component `(loop for .i. from 2 below (code-header-words ,obj) @@ -1190,6 +1003,7 @@ We could try a few things to mitigate this: ;;; code-components are considered to reference their embedded ;;; simple-funs for this purpose; if THIS is a simple-fun, it is ignored. (defun references-p (this that) + (declare (optimize (sb-c::aref-trapping 0))) (macrolet ((test (x) `(when (eq ,x that) (go win)))) (tagbody (do-referenced-object (this test) @@ -1204,7 +1018,6 @@ We could try a few things to mitigate this: (case (widetag-of this) (#.value-cell-widetag (test (value-cell-ref this))) - (#.filler-widetag) (t (bug "Unknown object type #x~x addr=~x" (widetag-of this) @@ -1219,16 +1032,16 @@ We could try a few things to mitigate this: (defun map-referencing-objects (fun space object) (declare (type (or (eql :all) spaces) space)) (declare (dynamic-extent fun)) - (unless *ignore-after* - (setq *ignore-after* (cons 1 2))) - (let ((fun (%coerce-callable-to-fun fun))) + (let (list) (map-allocated-objects (lambda (referer widetag size) (declare (ignore widetag size)) - (when (and (valid-obj space referer) ; semi-bogus! + ;; Don't count a self-reference as a reference + (when (and (neq referer object) (references-p referer object)) - (funcall fun referer))) - space))) + (push referer list))) + space) + (mapc (%coerce-callable-to-fun fun) list))) (defun list-referencing-objects (space object) (collect ((res)) @@ -1304,15 +1117,17 @@ We could try a few things to mitigate this: &aux (n-code-bytes 0) (total-pages next-free-page) (pages - (make-array total-pages :element-type 'bit))) + (make-array total-pages :element-type 'bit + :initial-element 0))) (flet ((dump-page (page-num) (format stream "~&Page ~D~%" page-num) - (let ((where (+ dynamic-space-start (* page-num gencgc-card-bytes))) + (let ((where (+ dynamic-space-start (* page-num gencgc-page-bytes))) (seen-filler nil)) (loop - (multiple-value-bind (obj type size) - (reconstitute-object (ash where (- n-fixnum-tag-bits))) - (when (= type code-header-widetag) + (let* ((obj (let ((sap (int-sap where))) + (lispobj@baseptr sap (widetag@baseptr sap)))) + (size (primitive-object-size obj))) + (when (code-component-p obj) (incf n-code-bytes size)) (when (if (and (consp obj) (eq (car obj) 0) (eq (cdr obj) 0)) (if seen-filler @@ -1325,7 +1140,7 @@ We could try a few things to mitigate this: (loop for index from page-num to (find-page-index (1- where)) do (setf (sbit pages index) 1))) (let ((next-page (find-page-index where))) - (cond ((= (logand where (1- gencgc-card-bytes)) 0) + (cond ((= (logand where (1- gencgc-page-bytes)) 0) (format stream "~&-- END OF PAGE --~%") (return next-page)) ((eq next-page page-num)) @@ -1333,12 +1148,12 @@ We could try a few things to mitigate this: (setq page-num next-page seen-filler nil)))))))) (let ((i 0)) (loop while (< i total-pages) - do (let ((type (ldb (byte 2 0) (slot (deref page-table i) 'flags)))) - (if (= type 3) + do (let ((type (slot (deref page-table i) 'flags))) + (if (= (logand type 7) 7) (setq i (dump-page i)) (incf i))))) (let* ((n-pages (count 1 pages)) - (tot (* n-pages gencgc-card-bytes)) + (tot (* n-pages gencgc-page-bytes)) (waste (- tot n-code-bytes))) (format t "~&Used-bytes=~D Pages=~D Waste=~D (~F%)~%" n-code-bytes n-pages waste @@ -1348,7 +1163,7 @@ We could try a few things to mitigate this: (defun show-immobile-spaces (which) (flet ((show (obj type size) (declare (ignore type size)) - (let ((*print-pretty* nil)) + (let ((*print-pretty* nil) (*print-length* 3)) (format t "~x: ~s~%" (get-lisp-obj-address obj) obj)))) (when (or (eq which :fixed) (eq which :both)) (format t "Fixedobj space~%==============~%") @@ -1356,24 +1171,10 @@ We could try a few things to mitigate this: (%make-lisp-obj fixedobj-space-start) (%make-lisp-obj (sap-int *fixedobj-space-free-pointer*)))) (when (or (eq which :variable) (eq which :both)) - (format t "Varyobj space~%=============~%") + (format t "Text space~%=============~%") (map-objects-in-range #'show - (%make-lisp-obj varyobj-space-start) - (%make-lisp-obj (sap-int *varyobj-space-free-pointer*)))))) - -#+gencgc -(defun generation-of (object) - (let* ((addr (get-lisp-obj-address object)) - (page (find-page-index addr))) - (cond ((>= page 0) (slot (deref page-table page) 'gen)) - #+immobile-space - ((immobile-space-addr-p addr) - ;; SIMPLE-FUNs don't contain a generation byte - (when (simple-fun-p object) - (setq addr (get-lisp-obj-address (fun-code-header object)))) - (let ((sap (int-sap (logandc2 addr lowtag-mask)))) - (logand (if (fdefn-p object) (sap-ref-8 sap 1) (sap-ref-8 sap 3)) - #xF)))))) + (%make-lisp-obj text-space-start) + (%make-lisp-obj (sap-int *text-space-free-pointer*)))))) ;;; Show objects in a much simpler way than print-allocated-objects. ;;; Probably don't use this for generation 0 of dynamic space. Other spaces are ok. @@ -1391,13 +1192,17 @@ We could try a few things to mitigate this: ;;; Unfortunately this is a near total copy of the test in gc.impure.lisp (defun !ensure-genesis-code/data-separation () #+gencgc - (let* ((n-bits (+ next-free-page 10)) - (code-bits (make-array n-bits :element-type 'bit)) - (data-bits (make-array n-bits :element-type 'bit)) + (let* ((n-bits + (progn + (close-thread-alloc-region) + (+ next-free-page 50))) + (code-bits (make-array n-bits :element-type 'bit :initial-element 0)) + (data-bits (make-array n-bits :element-type 'bit :initial-element 0)) (total-code-size 0)) (map-allocated-objects (lambda (obj type size) - (declare ((and fixnum (integer 1)) size)) + (declare ((and fixnum (integer 1)) size)) + (unless (= type funcallable-instance-widetag) ;; M-A-O disables GC, therefore GET-LISP-OBJ-ADDRESS is safe (let ((obj-addr (get-lisp-obj-address obj)) (array (cond ((= type code-header-widetag) @@ -1409,6 +1214,19 @@ We could try a few things to mitigate this: data-bits) (t code-bits)))) + ;; If Lisp allocates to cons pages, then this check is always valid. + ;; If not, then at first glance we could weaken the check to allow + ;; gen0 conses on MIXED pages, but even that is not enough- pinned conses + ;; will promote but keep their MIXED page type. So don't bother with this. + #+use-cons-region + (let* ((type (slot (deref page-table (find-page-index obj-addr)) 'flags)) + (ok (if (consp obj) + (or (= type #b101) ; PAGE_TYPE_CONS + (and (eq (car obj) 0) (eq (cdr obj) 0))) + (/= type #b101)))) + (unless ok + (error "Object @ ~x (gen~D) is on page-type ~b~%" + obj-addr (generation-of obj) type))) ;; This is not the most efficient way to update the bit arrays, ;; but the simplest and clearest for sure. (The loop could avoided ;; if the current page is the same as the previously seen page) @@ -1419,75 +1237,143 @@ We could try a few things to mitigate this: do (cond ((= (sbit other-array index) 1) (format t "~&broken on page index ~d base ~x~%" index - (+ dynamic-space-start (* index gencgc-card-bytes))) + (+ dynamic-space-start (* index gencgc-page-bytes))) (alien-funcall (extern-alien "ldb_monitor" (function void)))) (t - (setf (sbit array index) 1)))))) + (setf (sbit array index) 1))))))) :dynamic))) ;;; Because pseudo-static objects can not move nor be freed, ;;; this is a valid test that genesis separated code and data. (!ensure-genesis-code/data-separation) -(defun hexdump (thing &optional (n-words nil wordsp) - ;; pass NIL explicitly if T crashes on you - (decode t)) - (multiple-value-bind (obj addr count) - (if (typep thing 'word) ; ambiguous in the edge case, but assume it's - ;; an address (though you might be trying to dump a bignum's data) - (values nil thing (if wordsp n-words 1)) - (values - thing - (logandc2 (get-lisp-obj-address thing) lowtag-mask) - (if wordsp - n-words - (if (and (typep thing 'code-component) (plusp (code-n-entries thing))) - ;; Display up through the first fun header - (+ (code-header-words thing) - (ash (%code-fun-offset thing 0) (- word-shift)) - simple-fun-insts-offset) - ;; at most 16 words - (min 16 (ash (primitive-object-size thing) (- word-shift))))))) - (with-pinned-objects (obj) - (dotimes (i count) - (let ((word (sap-ref-word (int-sap addr) (ash i word-shift)))) - (multiple-value-bind (lispobj ok) - (cond ((and (typep thing 'code-component) - (< 1 i (code-header-words thing))) - (values (code-header-ref thing i) t)) - (decode - (make-lisp-obj word nil))) - (let ((*print-lines* 1) - (*print-pretty* t)) - (format t "~x: ~v,'0x~:[~; = ~S~]~%" - (+ addr (ash i word-shift)) - (* 2 n-word-bytes) - word ok lispobj)))))))) #+sb-thread (defun show-tls-map () (let ((list - (sort (sb-vm::list-allocated-objects + (sort (list-allocated-objects :all - :type sb-vm:symbol-widetag + :type symbol-widetag :test (lambda (x) (plusp (sb-kernel:symbol-tls-index x)))) #'< :key #'sb-kernel:symbol-tls-index)) (prev 0)) (dolist (x list) - (let ((n (ash (sb-kernel:symbol-tls-index x) (- sb-vm:word-shift)))) - (when (and (> n sb-vm::primitive-thread-object-length) + (let ((n (ash (sb-kernel:symbol-tls-index x) (- word-shift)))) + (when (and (> n primitive-thread-object-length) (> n (1+ prev))) (format t "(unused)~%")) (format t "~5d = ~s~%" n x) (setq prev n))))) +#+gencgc +(flet ((print-it (obj type size) + (declare (ignore type size)) + (let ((*print-level* 2) (*print-lines* 1)) + (format t "~x ~s~%" (get-lisp-obj-address obj) obj)))) +(defun print-all-code () + (walk-dynamic-space #'print-it #x7f #b01111 #b00111)) +(defun print-large-code () + (walk-dynamic-space #'print-it #x7f #b11111 #b10111)) +(defun print-large-unboxed () + (walk-dynamic-space #'print-it #x7f #b11111 #b10010)) +;;; Use this only if you know what you're doing. It can fail because a page +;;; that needs to continue onto the next page will cause the "overrun" check +;;; to fail. +(defun print-page-contents (page) + (let* ((start + (+ dynamic-space-start (* gencgc-page-bytes page))) + (end + (+ start gencgc-page-bytes))) + (map-objects-in-range #'print-it (%make-lisp-obj start) (%make-lisp-obj end))))) + +(defun map-code-objects (fun) + (dx-flet ((filter (obj type size) + (declare (ignore size)) + (when (= type code-header-widetag) + (funcall fun obj)))) + (without-gcing + #+immobile-code + (map-objects-in-range #'filter + (ash text-space-start (- n-fixnum-tag-bits)) + (%make-lisp-obj (sap-int *text-space-free-pointer*))) + (alien-funcall (extern-alien "close_code_region" (function void))) + (walk-dynamic-space #'filter + #b1111111 ; all generations + #b111 #b111)))) ; type mask and constraint + +(export 'code-from-serialno) +(defun code-from-serialno (serial) + (dx-flet ((visit (obj) + (when (= (%code-serialno obj) serial) + (return-from code-from-serialno obj)))) + (map-code-objects #'visit))) + +(defun show-all-layouts () + (let ((l (list-allocated-objects :all :test #'sb-kernel::wrapper-p)) + zero trailing-raw trailing-tagged vanilla) + (dolist (x l) + (let ((m (wrapper-bitmap x))) + (cond ((eql m +layout-all-tagged+) (push x vanilla)) + ((eql m 0) (push x zero)) + ((minusp m) (push x trailing-tagged)) + (t (push x trailing-raw))))) + (flet ((legend (newline str list) + (when newline (terpri)) + (let ((s (format nil str (length list)))) + (format t "~A~%~A~%" s (make-string (length s) :initial-element #\-))))) + (when zero + (legend nil "Zero bitmap (~d):" zero) + (dolist (x zero) (format t "~a~%" (wrapper-classoid-name x)))) + (when trailing-raw + (legend t "Trailing raw (~d):" trailing-raw) + (dolist (x trailing-raw) + (let ((m (wrapper-bitmap x))) + (format t "~30a 0...~v,'0b~%" + (wrapper-classoid-name x) + (acond ((wrapper-info x) (1+ (dd-length it))) (t 32)) + m)))) + (when trailing-tagged + (legend t "Trailing tagged (~d):" trailing-tagged) + (dolist (x trailing-tagged) + (let ((m (wrapper-bitmap x))) + (format t "~30a 1...~b~%" + (wrapper-classoid-name x) + (acond ((wrapper-info x) (ldb (byte (dd-length it) 0) m)) + (t (ldb (byte 32 0) m))))))) + (legend t "Default: (~d) [not shown]" vanilla)))) + +#+ubsan +(defun find-poisoned-vectors (&aux result) + (dolist (v (list-allocated-objects :all :type simple-vector-widetag) + result) + (when (dotimes (i (length v)) + (declare (optimize (sb-c::aref-trapping 0))) + (let ((val (svref v i))) + (when (= (get-lisp-obj-address val) unwritten-vector-element-marker) + (return t)))) + (push (make-weak-pointer v) result) + (let* ((origin (vector-extra-data v)) + (code (sb-di::code-header-from-pc (ash origin -3))) + (*print-array* nil)) + (format t "g~d ~a ~a~%" (sb-kernel:generation-of v) v code))))) + (in-package "SB-C") ;;; As soon as practical in warm build it makes sense to add -;;; cold-allocation-point-fixups into the weak hash-table. -(defvar *!cold-allocation-point-fixups*) -(let ((hash-table (make-hash-table :test 'eq))) - ;; Group by code component - (loop for (code . offset) across *!cold-allocation-point-fixups* - do (push offset (gethash code hash-table))) - (dohash ((code list) hash-table) - (setf (gethash code *allocation-point-fixups*) - (convert-alloc-point-fixups code list)))) +;;; cold-allocation-patch-points into the weak hash-table. +;;; FIXME: I suspect that this wants to be just a weak vector +;;; (all code objects that have any allocation profiling compiled in), +;;; and not a hash-table, and that the list of fixups in the component +;;; can be attached to the debug info (in the manner of debug funs). +;;; When this was first implemented, weak-vectors weren't a thing. Maybe? +(defvar *!cold-allocation-patch-point*) +(loop for (code . points) in *!cold-allocation-patch-point* + do (setf (gethash code *allocation-patch-points*) points)) + +(defun gctablesize (heap-size-gb page-size cards-per-page) + (let* ((card-size (/ page-size cards-per-page)) + (heap-size (* heap-size-gb (expt 1024 3))) + (npages (/ heap-size page-size)) + (ncards (/ heap-size card-size)) + (pte-nbytes (* 8 npages))) + (format t " PTE bytes: ~8D~%" pte-nbytes) + (format t "card bytes: ~8D~%" ncards) + (format t " total: ~8D~%" (+ pte-nbytes ncards)))) diff --git a/src/code/run-program.lisp b/src/code/run-program.lisp index 0667fe50dd..56f3b93218 100644 --- a/src/code/run-program.lisp +++ b/src/code/run-program.lisp @@ -165,7 +165,7 @@ ;;; mutex is needed. More importantly the sigchld signal handler also ;;; accesses it, that's why we need without-interrupts. (defmacro with-active-processes-lock (() &body body) - `(sb-thread::with-system-mutex (*active-processes-lock*) + `(with-system-mutex (*active-processes-lock*) ,@body)) (deftype process-status () @@ -307,7 +307,8 @@ PROCESS." "Hand SIGNAL to PROCESS. If WHOM is :PID, use the kill Unix system call. If WHOM is :PROCESS-GROUP, use the killpg Unix system call. If WHOM is :PTY-PROCESS-GROUP deliver the signal to whichever process group is - currently in the foreground." + currently in the foreground. + Returns T if successful, otherwise returns NIL and error number (two values)." (let ((pid (ecase whom ((:pid :process-group) (process-pid process)) @@ -405,8 +406,11 @@ status slot." ;;;; RUN-PROGRAM and close friends -;;; list of file descriptors to close when RUN-PROGRAM exits due to an error -(defvar *close-on-error* nil) +;;; list of file descriptors and streams to close when RUN-PROGRAM +;;; exits due to an error +(defvar *close-fds-on-error* nil) +;;; Separate from fds to ensure the finalizer and all the buffers are cleared too. +(defvar *close-streams-on-error* nil) ;;; list of file descriptors to close when RUN-PROGRAM returns in the parent (defvar *close-in-parent* nil) @@ -447,14 +451,14 @@ status slot." ;; No dice, try using the old-school method. (dolist (char '(#\p #\q)) (dotimes (digit 16) - (let* ((master-name (with-simple-output-to-string (str nil base-char) + (let* ((master-name (with-output-to-string (str nil :element-type 'base-char) (format str "/dev/pty~C~X" char digit))) (master-fd (sb-unix:unix-open master-name (logior sb-unix:o_rdwr sb-unix:o_noctty) #o666))) (when master-fd - (let* ((slave-name (with-simple-output-to-string (str nil base-char) + (let* ((slave-name (with-output-to-string (str nil :element-type 'base-char) (format str "/dev/tty~C~X" char digit))) (slave-fd (sb-unix:unix-open slave-name (logior sb-unix:o_rdwr @@ -492,13 +496,13 @@ status slot." (multiple-value-bind (master slave name) (find-a-pty) - (push master *close-on-error*) + (push master *close-fds-on-error*) (push slave *close-in-parent*) (when (streamp pty) (multiple-value-bind (new-fd errno) (sb-unix:unix-dup master) (unless new-fd (error "couldn't SB-UNIX:UNIX-DUP ~W: ~A" master (strerror errno))) - (push new-fd *close-on-error*) + (push new-fd *close-fds-on-error*) (copy-descriptor-to-stream new-fd pty cookie external-format))) (values name (make-fd-stream master :input t :output t @@ -543,7 +547,10 @@ status slot." ;; Copy string. (copy-ub8-to-system-area octets 0 string-sap 0 size) ;; NULL-terminate it - (system-area-ub8-fill 0 string-sap size 4) + ;; (As it says up top: "assume 4 byte is enough for everyone.") + (let ((sap (sap+ string-sap size))) + (setf (sap-ref-8 sap 0) 0 (sap-ref-8 sap 1) 0 + (sap-ref-8 sap 2) 0 (sap-ref-8 sap 3) 0)) ;; Put the pointer in the vector. (setf (sap-ref-sap vec-sap vec-index-offset) string-sap) ;; Advance string-sap for the next string. @@ -589,7 +596,8 @@ status slot." (envp (* c-string)) (pty-name c-string) (channel (array int 2)) - (dir c-string)) + (dir c-string) + (preserve-fds (* int))) #-win32 (define-alien-routine wait-for-exec @@ -630,7 +638,7 @@ status slot." #+win32 (defun prepare-args (args escape) - (with-simple-output-to-string (str) + (%with-output-to-string (str) (loop for (arg . rest) on args do (cond ((and escape @@ -649,6 +657,11 @@ status slot." (loop for arg in args collect (coerce arg 'simple-string)))) +(defmacro coerce-or-copy (object type) + `(if (typep ,object ,type) + (copy-seq ,object) + (coerce ,object ,type))) + ;;; FIXME: There shouldn't be two semiredundant versions of the ;;; documentation. Since this is a public extension function, the ;;; documentation should be in the doc string. So all information from @@ -694,26 +707,34 @@ status slot." ;;; the fork worked, and NIL if it did not. (defun run-program (program args &key - (env nil env-p) - (environment - (when env-p - (unix-environment-sbcl-from-cmucl env)) - environment-p) - (wait t) - search - #-win32 pty - input - if-input-does-not-exist - output - (if-output-exists :error) - (error :output) - (if-error-exists :error) - status-hook - (external-format :default) - directory - #+win32 (escape-arguments t)) + (env nil env-p) + (environment + (when env-p + (unix-environment-sbcl-from-cmucl env)) + environment-p) + (wait t) + search + #-win32 pty + input + if-input-does-not-exist + output + (if-output-exists :error) + (error :output) + (if-error-exists :error) + status-hook + (external-format :default) + directory + preserve-fds + #+win32 (escape-arguments t) + #+win32 (window nil)) "RUN-PROGRAM creates a new process specified by PROGRAM. -ARGS are passed as the arguments to the program. +ARGS is a list of strings to be passed literally to the new program. +In POSIX environments, this list becomes the array supplied as the second +parameter to the execv() or execvp() system call, each list element becoming +one array element. The strings should not contain shell escaping, as there is +no shell involvement. Further note that while conventionally the process +receives its own pathname in argv[0], that is automatic, and the 0th string +should not be present in ARGS. The program arguments and the environment are encoded using the default external format for streams. @@ -799,14 +820,27 @@ Users Manual for details about the PROCESS structure. Specifies the directory in which the program should be run. NIL (the default) means the directory is unchanged. + :PRESERVE-FDS + A sequence of file descriptors which should remain open in the child + process. + Windows specific options: :ESCAPE-ARGUMENTS (default T) - Controls escaping of the arguments passed to CreateProcess." + Controls escaping of the arguments passed to CreateProcess. + :WINDOW (default NIL) + When NIL, the subprocess decides how it will display its window. The + following options control how the subprocess window should be displayed: + :HIDE, :SHOW-NORMAL, :SHOW-MAXIMIZED, :SHOW-MINIMIZED, :SHOW-NO-ACTIVATE, + :SHOW-MIN-NO-ACTIVE, :SHOW-NA. + Note: console application subprocesses may or may not display a console + window depending on whether the SBCL runtime is itself a console or GUI + application. Invoke CMD /C START to consistently display a console window + or use the :WINDOW :HIDE option to consistently hide the console window." (when (and env-p environment-p) (error "can't specify :ENV and :ENVIRONMENT simultaneously")) (let* (;; Clear various specials used by GET-DESCRIPTOR-FOR to ;; communicate cleanup info. - *close-on-error* + *close-fds-on-error* *close-in-parent* *handlers-installed* ;; Establish PROC at this level so that we can return it. @@ -855,11 +889,13 @@ Users Manual for details about the PROCESS structure. output cookie :direction :output :if-exists if-output-exists + :if-does-not-exist :create :external-format external-format) (with-fd-and-stream-for ((stderr error-stream) :error error cookie :direction :output :if-exists if-error-exists + :if-does-not-exist :create :external-format external-format) ;; Make sure we are not notified about the child ;; death before we have installed the PROCESS @@ -871,21 +907,37 @@ Users Manual for details about the PROCESS structure. (with-open-pty ((pty-name pty-stream) (pty cookie)) (setf (values child #+win32 handle) #+win32 - (sb-thread::with-system-mutex (*spawn-lock*) + (with-system-mutex (*spawn-lock*) (sb-win32::mswin-spawn progname args stdin stdout stderr - search environment-vec directory)) + search environment-vec directory + window + preserve-fds)) #-win32 - (with-args (args-vec args) - (sb-thread::with-system-mutex (*spawn-lock*) - (spawn progname args-vec - stdin stdout stderr - (if search 1 0) - environment-vec pty-name - channel - directory)))) + (let ((preserve-fds + (and preserve-fds + (sort (coerce-or-copy preserve-fds + '(simple-array (signed-byte #.(alien-size int)) (*))) + #'<)))) + (multiple-value-bind (readfd writefd) (sb-unix:unix-pipe) + (if (null readfd) ; writefd = errno when it fails + (file-perror nil writefd "Error creating pipe") + (setf (deref channel 0) readfd + (deref channel 1) writefd))) + (with-pinned-objects (preserve-fds) + (with-args (args-vec args) + (with-system-mutex (*spawn-lock*) + (spawn progname args-vec + stdin stdout stderr + (if search 1 0) + environment-vec pty-name + channel + directory + (if preserve-fds + (vector-sap preserve-fds) + (int-sap 0)))))))) (unless (minusp child) #-win32 (setf child (wait-for-exec child channel)) @@ -923,8 +975,10 @@ Users Manual for details about the PROCESS structure. (dolist (fd *close-in-parent*) (sb-unix:unix-close fd)) (unless proc - (dolist (fd *close-on-error*) + (dolist (fd *close-fds-on-error*) (sb-unix:unix-close fd)) + (dolist (stream *close-streams-on-error*) + (close stream :abort t)) #-win32 (dolist (handler *handlers-installed*) (remove-fd-handler handler))) @@ -992,19 +1046,8 @@ Users Manual for details about the PROCESS structure. (loop (unless handler (return)) - (multiple-value-bind - (result readable/errno) - (sb-unix:unix-select (1+ descriptor) - (ash 1 descriptor) - 0 0 0) - (cond ((null result) - (if (eql sb-unix:eintr readable/errno) - (return) - (error "~@<Couldn't select on sub-process: ~ - ~2I~_~A~:>" - (strerror readable/errno)))) - ((zerop result) - (return)))) + (unless (sb-unix:unix-simple-poll descriptor :input 0) + (return)) (multiple-value-bind (count errno) (with-pinned-objects (buf) (sb-unix:unix-read descriptor @@ -1140,26 +1183,26 @@ Users Manual for details about the PROCESS structure. (eq direction :output)) (case direction (:input - (push read-fd *close-in-parent*) - (push write-fd *close-on-error*) - (let ((stream (make-fd-stream write-fd :output t + (push read-fd *close-in-parent*) + (let ((stream (make-fd-stream write-fd :output t :element-type :default - :external-format - external-format))) - (values read-fd stream))) + :external-format external-format + :auto-close t))) + (push stream *close-streams-on-error*) + (values read-fd stream))) (:output - (push read-fd *close-on-error*) - (push write-fd *close-in-parent*) - (let ((stream (make-fd-stream read-fd :input t - :element-type :default - :external-format - external-format))) - (values write-fd stream))) + (push write-fd *close-in-parent*) + (let ((stream (make-fd-stream read-fd :input t + :element-type :default + :external-format external-format + :auto-close t))) + (push stream *close-streams-on-error*) + (values write-fd stream))) (t - (sb-unix:unix-close read-fd) - (sb-unix:unix-close write-fd) - (fail "Direction must be either :INPUT or :OUTPUT, not ~S." - direction))))) + (sb-unix:unix-close read-fd) + (sb-unix:unix-close write-fd) + (fail "Direction must be either :INPUT or :OUTPUT, not ~S." + direction))))) ((or (pathnamep object) (stringp object)) ;; GET-DESCRIPTOR-FOR uses &allow-other-keys, so rather ;; than munge the &rest list for OPEN, just disable keyword @@ -1273,23 +1316,27 @@ Users Manual for details about the PROCESS structure. (setf (sb-win32::inheritable-handle-p write-fd) t) (copy-descriptor-to-stream read-fd object cookie external-format) - (push read-fd *close-on-error*) + (push read-fd *close-fds-on-error*) (push write-fd *close-in-parent*) (return (values write-fd nil))))))) (t (fail "invalid option: ~S" object)))))) -#+(or linux sunos hpux haiku) +#+(or linux sunos haiku) (defun software-version () "Return a string describing version of the supporting software, or NIL if not available." (or sb-sys::*software-version* (setf sb-sys::*software-version* - (string-trim '(#\newline) - (with-simple-output-to-string (stream) + (possibly-base-stringize + #+linux + (with-open-file (f "/proc/sys/kernel/osrelease") (read-line f)) + #-linux + (string-trim '(#\newline) + (%with-output-to-string (stream) (run-program "/bin/uname" ;; "-r" on haiku just prints "1" ;; but "-v" prints some detail. #+haiku '("-v") #-haiku '("-r") - :output stream)))))) + :output stream))))))) diff --git a/src/code/save.lisp b/src/code/save.lisp index b517b0f6ff..1029886e8c 100644 --- a/src/code/save.lisp +++ b/src/code/save.lisp @@ -31,6 +31,7 @@ (define-alien-routine "gc_and_save" void (file c-string) (prepend-runtime int) + (purify int) (save-runtime-options int) (compressed int) (compression-level int) @@ -66,21 +67,36 @@ ;;; This variable is accessed by C code when saving. Export it to survive tree-shaker. ;;; The symbols in this set are clobbered just in time to avoid saving them to the core -;;; but not so early that we kill the running image. (Though in fact if SAVE-ERROR -;;; and hence REINIT is reached, we reassign them all anyway) +;;; but not so early that we kill the running image. (export 'sb-kernel::*save-lisp-clobbered-globals* 'sb-kernel) (define-load-time-global sb-kernel::*save-lisp-clobbered-globals* '#(sb-impl::*exit-lock* sb-thread::*make-thread-lock* sb-thread::*initial-thread* + ;; Saving *JOINABLE-THREADS* could cause catastophic failure on restart. + ;; SAVE-LISP-AND-DIE should have cleaned up, but there's a timing problem + ;; with the finalizer thread, and I'm loathe to put in a SLEEP delay. + sb-thread::*joinable-threads* sb-thread::*all-threads* sb-thread::*session* sb-kernel::*gc-epoch*)) +(defun start-lisp (toplevel callable-exports) + (if callable-exports + (named-lambda %start-lisp () + (reinit t) + (dolist (export callable-exports) + (sb-alien::initialize-alien-callable-symbol export))) + (named-lambda %start-lisp () + (handling-end-of-the-world + (reinit t) + (funcall toplevel))))) + (defun save-lisp-and-die (core-file-name &key - (toplevel #'toplevel-init) + (toplevel #'toplevel-init toplevel-supplied) (executable nil) (save-runtime-options nil) + (callable-exports ()) (purify t) (root-structures ()) (environment-name "auxiliary") @@ -116,14 +132,18 @@ The following &KEY arguments are defined: all command line arguments to be passed to the toplevel. Meaningless if :EXECUTABLE is NIL. + :CALLABLE-EXPORTS + This should be a list of symbols to be initialized to the + appropriate alien callables on startup. All exported symbols should + be present as global symbols in the symbol table of the runtime + before the saved core is loaded. When this list is non-empty, the + :TOPLEVEL argument cannot be supplied. + :PURIFY - If true (the default on cheneygc), do a purifying GC which moves all - dynamically allocated objects into static space. This takes - somewhat longer than the normal GC which is otherwise done, but - it's only done once, and subsequent GC's will be done less often - and will take less time in the resulting core file. See the PURIFY - function. This parameter has no effect on platforms using the - generational garbage collector. + If true (the default), then some objects in the restarted core will + be memory-mapped as read-only. Among those objects are numeric vectors + that were determined to be compile-time constants, and any immutable + values according to the language specification such as symbol names. :ROOT-STRUCTURES This should be a list of the main entry points in any newly loaded @@ -144,8 +164,8 @@ The following &KEY arguments are defined: This is only meaningful if the runtime was built with the :SB-CORE-COMPRESSION feature enabled. If NIL (the default), saves to uncompressed core files. If :SB-CORE-COMPRESSION was enabled at build-time, the argument may also be - an integer from -1 to 9, corresponding to zlib compression levels, or T - (which is equivalent to the default compression level, -1). + an integer from -7 to 22, corresponding to zstd compression levels, or T + (which is equivalent to the default compression level, 9). :APPLICATION-TYPE Present only on Windows and is meaningful only with :EXECUTABLE T. @@ -184,16 +204,18 @@ seem to be good quick fixes for either limitation and no one has been sufficiently motivated to do lengthy fixes." (declare (ignore environment-name)) #+gencgc - (declare (ignore purify) (ignorable root-structures)) + (declare (ignorable root-structures)) + (when (and callable-exports toplevel-supplied) + (error ":TOPLEVEL cannot be supplied when there are callable exports.")) ;; If the toplevel function is not defined, this will signal an ;; error before saving, not at startup time. (let ((toplevel (%coerce-callable-to-fun toplevel)) *streams-closed-by-slad*) #+sb-core-compression - (check-type compression (or boolean (integer -1 9))) + (check-type compression (or boolean (integer -7 22))) #-sb-core-compression (when compression - (error "Unable to save compressed core: this runtime was not built with zlib support")) + (error "Unable to save compressed core: this runtime was not built with zstd support")) (when *dribble-stream* (restart-case (error "Dribbling to ~s is enabled." (pathname *dribble-stream*)) (continue () @@ -203,26 +225,13 @@ sufficiently motivated to do lengthy fixes." :report "Abort saving the core." (return-from save-lisp-and-die)))) (when (eql t compression) - (setf compression -1)) - (labels ((restart-lisp () - (handling-end-of-the-world - (reinit) - ;; REINIT can not discern between a restarted image and a - ;; failure to save. It doesn't make a lot of sense to start - ;; a finalizer thread in the failed case, so we set the flag - ;; here, not in REINIT which would do it for both cases. - #+sb-thread (setq *finalizer-thread* t) - #+hpux (%primitive sb-vm::setup-return-from-lisp-stub) - (funcall toplevel))) - (foreign-bool (value) - (if value 1 0))) + (setf compression 9)) + (flet ((foreign-bool (value) + (if value 1 0))) (let ((name (native-namestring (physicalize-pathname core-file-name) - :as-file t))) + :as-file t)) + (startfun (start-lisp toplevel callable-exports))) (deinit) - ;; FIXME: Would it be possible to unmix the PURIFY logic from this - ;; function, and just do a GC :FULL T here? (Then if the user wanted - ;; a PURIFYed image, he'd just run PURIFY immediately before calling - ;; SAVE-LISP-AND-DIE.) #+gencgc (progn ;; Scan roots as close as possible to GC-AND-SAVE, in case anything @@ -237,14 +246,15 @@ sufficiently motivated to do lengthy fixes." sb-disassem::*disassem-inst-space* nil) ;; Save the restart function. Logically a passed argument, but can't be, ;; as it would require pinning around the whole save operation. - (with-pinned-objects (#'restart-lisp) - (setf lisp-init-function (get-lisp-obj-address #'restart-lisp))) + (with-pinned-objects (startfun) + (setf lisp-init-function (get-lisp-obj-address startfun))) ;; Do a destructive non-conservative GC, and then save a core. ;; A normal GC will leave huge amounts of storage unreclaimed ;; (over 50% on x86). This needs to be done by a single function ;; since the GC will invalidate the stack. (gc-and-save name (foreign-bool executable) + (foreign-bool purify) (foreign-bool save-runtime-options) (foreign-bool compression) (or compression 0) @@ -260,7 +270,7 @@ sufficiently motivated to do lengthy fixes." (if purify (purify :root-structures root-structures) (gc)) (without-gcing (save name - (get-lisp-obj-address #'restart-lisp) + (get-lisp-obj-address startfun) (foreign-bool executable) (foreign-bool save-runtime-options) (foreign-bool compression) @@ -271,7 +281,7 @@ sufficiently motivated to do lengthy fixes." ;; Something went very wrong -- reinitialize to have a prayer ;; of being able to report the error. (restore-fd-streams) - (reinit) + (reinit nil) (error 'save-error))) (defun tune-image-for-dump () @@ -298,45 +308,43 @@ sufficiently motivated to do lengthy fixes." (defun deinit () (call-hooks "save" *save-hooks*) - #+sb-wtimer - (itimer-emulation-deinit) + #+win32 (itimer-emulation-deinit) #+sb-thread - (progn - ;; Terminate finalizer thread now, especially given that the thread runs - ;; user-supplied code that might not even work in later steps of deinit. - ;; See also the comment at definition of THREAD-EPHEMERAL-P. - (finalizer-thread-stop) - (let ((threads (sb-thread:list-all-threads))) - (when (cdr threads) - ;; Despite calling FINALIZER-THREAD-STOP, an unlucky thread schedule - ;; courtesy of the OS might notionally start the finalizer thread but not - ;; run it until now. Suppose it barely got to its lisp trampoline, - ;; at which point we see it in *ALL-THREADS* not having observed it - ;; in *FINALIZER-THREAD*. FINALIZER-THREAD-STOP didn't know to stop it. - ;; Without adding significantly more synchronization, the best recourse - ;; is to consider it as nonexistent whenever it was "stopped". - ;; A newly started finalizer thread can do nothing but exit immediately - ;; whenever *FINALIZER-THREAD* is NIL so we don't actually care - ;; what that thread is doing at this point. - (let ((finalizer (find-if (lambda (x) - (and (sb-thread::thread-%ephemeral-p x) - (string= (sb-thread:thread-name x) "finalizer"))) - threads))) - (when finalizer - (sb-thread:join-thread finalizer))) - ;; Regardless of what happened above, grab the all-threads list again. - (setq threads (sb-thread:list-all-threads))) - (when (cdr threads) - (let* ((interactive (sb-thread::interactive-threads)) - (other (set-difference threads interactive))) - (error 'save-with-multiple-threads-error - :interactive-threads interactive - :other-threads other))))) + (let (error) + (with-system-mutex (sb-thread::*make-thread-lock*) + (finalizer-thread-stop) + (sb-thread::%dispose-thread-structs) + (let ((threads (sb-thread:list-all-threads)) + (starting + (setq sb-thread::*starting-threads* ; ordinarily pruned in MAKE-THREAD + (delete 0 sb-thread::*starting-threads*))) + (joinable sb-thread::*joinable-threads*)) + (when (or (cdr threads) starting joinable) + (let* ((interactive (sb-thread::interactive-threads)) + (other (union (set-difference threads interactive) + (union starting joinable)))) + (setf error (make-condition 'save-with-multiple-threads-error + :interactive-threads interactive + :other-threads other)))))) + (when error (error error)) + #+allocator-metrics (setq sb-thread::*allocator-metrics* nil) + (setq sb-thread::*sprof-data* nil)) (tune-image-for-dump) (float-deinit) (profile-deinit) (foreign-deinit) - (fill *pathnames* nil) + ;; To have any hope of making pathname interning actually work, + ;; this MAKE-PATHNAME-TABLE (formerly CLRHASH) would need to be removed. + ;; But removing this step causes excess garbage retention because the + ;; table's weakness isn't actually working (not sure why). + ;; And CLRHASH doesn't do as much as it should, because if the table + ;; is actually empty, but at some point held 20,000 pathnames, + ;; then we'd write out an enormous vector full of nothing. + (setq sb-impl::*pathnames* (make-pathname-intern-table)) + (when (zerop (hash-table-count sb-kernel::*forward-referenced-wrappers*)) + ;; I think this table should always be empty but I'm not sure. If it is, + ;; recreate it so that we don't preserve an empty vector taking up 16KB + (setq sb-kernel::*forward-referenced-wrappers* (make-hash-table :test 'equal))) ;; Clean up the simulated weak list of covered code components. (rplacd sb-c:*code-coverage-info* (delete-if-not #'weak-pointer-value (cdr sb-c:*code-coverage-info*))) @@ -350,8 +358,11 @@ sufficiently motivated to do lengthy fixes." #+immobile-code (sb-vm::statically-link-core) (invalidate-fd-streams) (finalizers-deinit) + (sb-vm::restore-cpu-specific-routines) ;; Do this last, to have some hope of printing if we need to. (stream-deinit) + (setf sb-c::*compile-elapsed-time* 0 + sb-c::*compile-file-elapsed-time* 0) (setf * nil ** nil *** nil - nil + nil ++ nil +++ nil /// nil // nil / nil)) @@ -377,6 +388,7 @@ sufficiently motivated to do lengthy fixes." ;;; Doing too much consing within MAP-ALLOCATED-OBJECTS can lead to heap ;;; exhaustion (due to inhibited GC), so this takes several passes. (defun coalesce-ctypes (&optional verbose) + (declare (optimize (sb-c::aref-trapping 0))) (let* ((table (make-hash-table :test 'equal)) interned-ctypes referencing-objects) @@ -456,7 +468,9 @@ sufficiently motivated to do lengthy fixes." (%set-symbol-global-value obj (coalesce part))))) ((not (memq accessor '(%closure-fun - symbol-package symbol-name fdefn-name + %fun-layout %instance-layout + symbol-package symbol-name symbol-%info + fdefn-name %numerator %denominator %realpart %imagpart %make-lisp-obj ; fdefn referent @@ -468,12 +482,14 @@ sufficiently motivated to do lengthy fixes." (sb-vm:do-referenced-object (obj examine) (simple-vector :extend - (when (and written (logtest sb-vm:vector-addr-hashing-subtype - (get-header-data obj))) + (when (and written (test-header-data-bit obj + (ash sb-vm:vector-addr-hashing-flag + sb-vm:array-flags-data-position))) (setf (svref obj 1) 1)))))))))) ; set need-to-rehash sb-c:: (defun coalesce-debug-info () + #+cheneygc (clrhash sb-di::*compiled-debug-funs*) (flet ((debug-source= (a b) (and (equal (debug-source-plist a) (debug-source-plist b)) (eql (debug-source-created a) (debug-source-created b))))) @@ -491,6 +507,10 @@ sb-c:: (declare (ignore size)) (case widetag (#.sb-vm:code-header-widetag + (let ((di (sb-vm::%%code-debug-info obj))) + ;; Discard memoized debugger's debug info + (when (typep di 'sb-c::compiled-debug-info) + (setf (sb-c::compiled-debug-info-memo-cell di) nil))) (dotimes (i (sb-kernel:code-n-entries obj)) (let* ((fun (sb-kernel:%code-entry-point obj i)) (arglist (%simple-fun-arglist fun)) @@ -509,7 +529,7 @@ sb-c:: (compiled-debug-info (let ((source (compiled-debug-info-source obj))) (typecase source - (core-debug-source) ; skip + (core-debug-source) ; skip - uh, why? (debug-source (let* ((namestring (debug-source-namestring source)) (canonical-repr @@ -528,8 +548,7 @@ sb-c:: (cond ((not foundp) (setf (gethash name name-ht) name)) ((neq name new) - (setf (%instance-ref debug-fun - (get-dsd-index compiled-debug-fun name)) + (%instance-set debug-fun (get-dsd-index compiled-debug-fun name) new)))) while next)) (sb-lockless::linked-list @@ -567,7 +586,7 @@ sb-c:: result)) (pushnew (code-from-fun fun) result))))))) (code-from-fun (fun) - (ecase (fun-subtype fun) + (ecase (%fun-pointer-widetag fun) (#.simple-fun-widetag (fun-code-header fun)) (#.funcallable-instance-widetag @@ -621,7 +640,7 @@ sb-c:: (callees (cdr item))) (dolist (callee callees) (push caller (gethash callee reverse-graph))))) - ;; Compute popularity of each code component in varyobj space + ;; Compute popularity of each code component in text space (map-allocated-objects (lambda (obj type size) (declare (ignore size)) diff --git a/src/code/sc-offset.lisp b/src/code/sc-offset.lisp index 3f1ccc2cd8..2e70ceccb6 100644 --- a/src/code/sc-offset.lisp +++ b/src/code/sc-offset.lisp @@ -19,7 +19,9 @@ ;;;; +SC+OFFSET-OFFSET-BYTES+ and exported to sc-offset.h during ;;;; genesis for use by the runtime. -(deftype sc+offset () +;;; This has to be DEF!TYPE because it appears in COMPILED-DEBUG-FUN +;;; which is DEF!STRUCT. +(def!type sc+offset () `(unsigned-byte ,(+ sb-vm:sc-number-bits sb-vm:sc-offset-bits))) (defconstant-eqx +sc+offset-scn-bytes+ diff --git a/src/code/seq.lisp b/src/code/seq.lisp index f06e2066cc..063c55a74c 100644 --- a/src/code/seq.lisp +++ b/src/code/seq.lisp @@ -32,12 +32,12 @@ `((count nil nil (etypecase count - (null (1- sb-xc:most-positive-fixnum)) + (null (1- most-positive-fixnum)) (fixnum (max 0 count)) (integer (if (minusp count) 0 - (1- sb-xc:most-positive-fixnum)))) - (mod #.sb-xc:most-positive-fixnum)) + (1- most-positive-fixnum)))) + (mod #.most-positive-fixnum)) ;; Entries for {start,end}{,1,2} ,@(mapcan (lambda (names) (destructuring-bind (start end length sequence) names @@ -190,6 +190,12 @@ (sb-c::%type-check-error/c ,sequence 'sb-kernel::object-not-sequence-error nil))))))) +(defmacro make-vector-like (vector length poison) + (declare (ignorable poison)) + `(let ((type (array-underlying-widetag ,vector))) + (sb-vm::allocate-vector-with-widetag + #+ubsan ,poison type ,length (aref sb-vm::%%simple-array-n-bits-shifts%% type)))) + ;;; Like SEQ-DISPATCH-CHECKING, but also assert that OTHER-FORM produces ;;; a sequence. This assumes that the containing function declares its ;;; result to be explicitly checked, @@ -203,7 +209,7 @@ "Return a sequence of the same type as SEQUENCE and the given LENGTH." `(seq-dispatch ,sequence (make-list ,length) - (make-vector-like ,sequence ,length) + (make-vector-like ,sequence ,length t) (sb-sequence:make-sequence-like ,sequence ,length))) (defun bad-sequence-type-error (type-spec) @@ -362,7 +368,7 @@ (car list))) (declare (type index count))) (locally - (declare (optimize (sb-c::insert-array-bounds-checks 0))) + (declare (optimize (sb-c:insert-array-bounds-checks 0))) (when (>= index (length sequence)) (signal-index-too-large-error sequence index)) (aref sequence index)) @@ -470,6 +476,12 @@ ;;;; SUBSEQ ;;;; +;;; FIXME: surely we can emit tighter code by not having 16 copies of the +;;; vector allocator buried inside this (and similar) functions. +;;; Instead there can be a size calculation up front, then ALLOCATE-VECTOR +;;; with the underlying widetag, then perform an N-way dispatch for the copy. +;;; Also, there should only be as many different ways to copy +;;; as there are different element sizes. (!define-array-dispatch :jump-table vector-subseq-dispatch (array start end) (declare (optimize speed (safety 0))) (declare (type index start end)) @@ -603,33 +615,36 @@ do (setf pointer (cdr (rplaca pointer item))))))) sequence) -(define-load-time-global %%fill-bashers%% (make-array (1+ sb-vm:widetag-mask))) -#.`(progn - ,@(loop for saetp across sb-vm:*specialized-array-element-type-properties* - for et = (sb-vm:saetp-specifier saetp) - if (or (null et) - (sb-vm:valid-bit-bash-saetp-p saetp)) - collect - (multiple-value-bind (basher value-transform) - (if et - (sb-c::find-basher saetp) - '(lambda (item vector start length) - (declare (ignore item start length)) - (data-nil-vector-ref (truly-the (simple-array nil (*)) vector) 0))) - `(setf - (aref %%fill-bashers%% ,(sb-vm:saetp-typecode saetp)) - (cons #',basher - ,(if et - `(lambda (sb-c::item) - (declare (type ,et sb-c::item)) - ,value-transform) - '#'identity)))) - else do - ;; vector-fill* depends on this assertion - (assert (member et '(t (complex double-float) - #-64-bit (complex single-float) - #-64-bit double-float) - :test #'equal)))) +(define-load-time-global %%fill-bashers%% (make-array (1+ sb-vm:widetag-mask) + :initial-element 0)) +(macrolet ((init-fill-bashers () + `(progn + ,@(loop for saetp across sb-vm:*specialized-array-element-type-properties* + for et = (sb-vm:saetp-specifier saetp) + if (or (null et) + (sb-vm:valid-bit-bash-saetp-p saetp)) + collect + (multiple-value-bind (basher value-transform) + (if et + (sb-c::find-basher saetp) + '(lambda (item vector start length) + (declare (ignore item start length)) + (data-nil-vector-ref (truly-the (simple-array nil (*)) vector) 0))) + `(setf + (aref %%fill-bashers%% ,(sb-vm:saetp-typecode saetp)) + (cons #',basher + ,(if et + `(lambda (sb-c::item) + (declare (type ,et sb-c::item)) + ,value-transform) + '#'identity)))) + else do + ;; vector-fill* depends on this assertion + (assert (member et '(t (complex double-float) + #-64-bit (complex single-float) + #-64-bit double-float) + :test #'equal)))))) + (init-fill-bashers)) (defun vector-fill* (vector item start end) (declare (type index start) (type (or index null) end) @@ -709,55 +724,53 @@ collect `(eq ,tag ,(sb-vm:saetp-typecode saetp))))) ;;;; REPLACE -(defun vector-replace (vector1 vector2 start1 start2 end1 diff) - (declare ((or (eql -1) index) start1 start2 end1) - (optimize (sb-c::insert-array-bounds-checks 0)) - ((integer -1 1) diff)) - (let ((tag1 (%other-pointer-widetag vector1)) - (tag2 (%other-pointer-widetag vector2))) - (macrolet ((copy (&body body) - `(do ((index1 start1 (+ index1 diff)) - (index2 start2 (+ index2 diff))) - ((= index1 end1)) - (declare (fixnum index1 index2)) - ,@body))) - (cond ((= tag1 tag2 sb-vm:simple-vector-widetag) - (copy - (setf (svref vector1 index1) (svref vector2 index2)))) - ;; TODO: can do the same with small specialized arrays - ((and (= tag1 tag2) - (word-specialized-vector-tag-p tag1)) - (copy - (setf (%vector-raw-bits vector1 index1) - (%vector-raw-bits vector2 index2)))) - (t - (let ((getter (the function (svref %%data-vector-reffers%% tag2))) - (setter (the function (svref %%data-vector-setters%% tag1)))) - (copy - (funcall setter vector1 index1 - (funcall getter vector2 index2)))))))) - vector1) ;;; If we are copying around in the same vector, be careful not to copy the ;;; same elements over repeatedly. We do this by copying backwards. +;;; Bounding indices were checked for validity by DEFINE-SEQUENCE-TRAVERSER. (defmacro vector-replace-from-vector () - `(let ((nelts (min (- target-end target-start) - (- source-end source-start)))) - (with-array-data ((data1 target-sequence) (start1 target-start) (end1)) - (declare (ignore end1)) - (let ((end1 (the fixnum (+ start1 nelts)))) - (if (and (eq target-sequence source-sequence) - (> target-start source-start)) - (let ((end (the fixnum (1- end1)))) - (vector-replace data1 data1 - end - (the fixnum (- end - (- target-start source-start))) - (1- start1) - -1)) - (with-array-data ((data2 source-sequence) (start2 source-start) (end2)) - (declare (ignore end2)) - (vector-replace data1 data2 start1 start2 end1 1))))) + `(locally + (declare (optimize (safety 0))) + (let ((nelts (min (- target-end target-start) + (- source-end source-start)))) + (when (plusp nelts) + (with-array-data ((data1 target-sequence) (start1 target-start) (end1)) + (progn end1) + (with-array-data ((data2 source-sequence) (start2 source-start) (end2)) + (progn end2) + (let ((tag1 (%other-pointer-widetag data1)) + (tag2 (%other-pointer-widetag data2))) + (block replace + (when (= tag1 tag2) + (when (= tag1 sb-vm:simple-vector-widetag) ; rely on the transform + (replace (truly-the simple-vector data1) + (truly-the simple-vector data2) + :start1 start1 :end1 (truly-the index (+ start1 nelts)) + :start2 start2 :end2 (truly-the index (+ start2 nelts))) + (return-from replace)) + (let ((copier (sb-vm::blt-copier-for-widetag tag1))) + (when copier + ;; these copiers figure out which direction to step. + ;; arg order is FROM, TO which is the opposite of REPLACE. + (funcall (truly-the function copier) data2 start2 data1 start1 nelts) + (return-from replace)))) + ;; General case is just like the code emitted by TRANSFORM-REPLACE + ;; but using the getter and setter. + (let ((getter (the function (svref %%data-vector-reffers%% tag2))) + (setter (the function (svref %%data-vector-setters%% tag1)))) + (cond ((and (eq data1 data2) (> start1 start2)) + (do ((i (the (or (eql -1) index) (+ start1 nelts -1)) (1- i)) + (j (the (or (eql -1) index) (+ start2 nelts -1)) (1- j))) + ((< i start1)) + (declare (index i j)) + (funcall setter data1 i (funcall getter data2 j)))) + (t + (do ((i start1 (1+ i)) + (j start2 (1+ j)) + (end (the index (+ start1 nelts)))) + ((>= i end)) + (declare (index i j)) + (funcall setter data1 i (funcall getter data2 j)))))))))))) target-sequence)) (defmacro list-replace-from-list () @@ -810,50 +823,12 @@ (declare (fixnum target-index source-index)) (setf (aref target-sequence target-index) (car source-sequence)))) -;;;; The support routines for REPLACE are used by compiler transforms, so we -;;;; worry about dealing with END being supplied or defaulting to NIL -;;;; at this level. - -(defun list-replace-from-list* (target-sequence source-sequence target-start - target-end source-start source-end) - (when (null target-end) (setq target-end (length target-sequence))) - (when (null source-end) (setq source-end (length source-sequence))) - (list-replace-from-list)) - -(defun list-replace-from-vector* (target-sequence source-sequence target-start - target-end source-start source-end) - (when (null target-end) (setq target-end (length target-sequence))) - (when (null source-end) (setq source-end (length source-sequence))) - (list-replace-from-vector)) - -(defun vector-replace-from-list* (target-sequence source-sequence target-start - target-end source-start source-end) - (when (null target-end) (setq target-end (length target-sequence))) - (when (null source-end) (setq source-end (length source-sequence))) - (vector-replace-from-list)) - -(defun vector-replace-from-vector* (target-sequence source-sequence - target-start target-end source-start - source-end) - (when (null target-end) (setq target-end (length target-sequence))) - (when (null source-end) (setq source-end (length source-sequence))) - (vector-replace-from-vector)) - -#+sb-unicode -(defun simple-character-string-replace-from-simple-character-string* - (target-sequence source-sequence - target-start target-end source-start source-end) - (declare (type (simple-array character (*)) target-sequence source-sequence)) - (when (null target-end) (setq target-end (length target-sequence))) - (when (null source-end) (setq source-end (length source-sequence))) - (vector-replace-from-vector)) - (define-sequence-traverser replace (target-sequence1 source-sequence2 &rest args &key start1 end1 start2 end2) "Destructively modifies SEQUENCE1 by copying successive elements into it from the SEQUENCE2. -Elements are copied to the subseqeuence bounded by START1 and END1, +Elements are copied to the subsequence bounded by START1 and END1, from the subsequence bounded by START2 and END2. If these subsequences are not of the same length, then the shorter length determines how many elements are copied." @@ -924,9 +899,11 @@ many elements are copied." (let ((length (length vector))) (with-array-data ((vector vector) (start) (end) :check-fill-pointer t) - (declare (ignore start)) + (declare (ignorable start)) (let* ((tag (%other-pointer-widetag vector)) - (new-vector (sb-vm::allocate-vector-with-widetag tag length nil))) + (new-vector (sb-vm::allocate-vector-with-widetag + #+ubsan nil tag length + (aref sb-vm::%%simple-array-n-bits-shifts%% tag)))) (cond ((= tag sb-vm:simple-vector-widetag) (do ((left-index 0 (1+ left-index)) (right-index end)) @@ -937,6 +914,18 @@ many elements are copied." (svref vector right-index)))) ((word-specialized-vector-tag-p tag) (reverse-word-specialized-vector vector new-vector end)) + #+(or arm64 x86-64) + ((typep vector '(or (simple-array base-char (*)) + (simple-array (signed-byte 8) (*)) + (simple-array (unsigned-byte 8) (*)))) + (sb-vm::simd-reverse8 new-vector vector start length)) + #+(or arm64 x86-64) + ((typep vector '(or #+sb-unicode + (simple-array character (*)) + (simple-array (signed-byte 32) (*)) + (simple-array (unsigned-byte 32) (*)) + (simple-array single-float (*)))) + (sb-vm::simd-reverse32 new-vector vector start length)) (t (let ((getter (the function (svref %%data-vector-reffers%% tag))) (setter (the function (svref %%data-vector-setters%% tag)))) @@ -952,12 +941,13 @@ many elements are copied." ;;;; NREVERSE (defun list-nreverse (list) - (do ((1st (cdr list) (if (endp 1st) 1st (cdr 1st))) + (do ((1st (cdr (truly-the list list)) (cdr 1st)) (2nd list 1st) (3rd '() 2nd)) ((atom 2nd) 3rd) (rplacd 2nd 3rd))) +(declaim (inline nreverse-word-specialized-vector)) (defun nreverse-word-specialized-vector (vector start end) (do ((left-index start (1+ left-index)) (right-index (1- end) (1- right-index))) @@ -969,11 +959,12 @@ many elements are copied." (%vector-raw-bits vector right-index) left))) vector) -(defun vector-nreverse (vector) - (declare (vector vector)) - (when (> (length vector) 1) - (with-array-data ((vector vector) (start) (end) - :check-fill-pointer t) +(defun vector-nreverse (original-vector) + (declare (vector original-vector)) + (when (> (length original-vector) 1) + (with-array-data ((vector original-vector) (start) (end) + :check-fill-pointer t + :force-inline t) (let ((tag (%other-pointer-widetag vector))) (cond ((= tag sb-vm:simple-vector-widetag) (do ((left-index start (1+ left-index)) @@ -986,6 +977,20 @@ many elements are copied." (svref vector right-index) left)))) ((word-specialized-vector-tag-p tag) (nreverse-word-specialized-vector vector start end)) + #+(or arm64 x86-64) + ((typep vector '(or (simple-array base-char (*)) + (simple-array (signed-byte 8) (*)) + (simple-array (unsigned-byte 8) (*)))) + (return-from vector-nreverse + (sb-vm::simd-nreverse8 original-vector vector start end))) + #+(or arm64 x86-64) + ((typep vector '(or #+sb-unicode + (simple-array character (*)) + (simple-array (signed-byte 32) (*)) + (simple-array (unsigned-byte 32) (*)) + (simple-array single-float (*)))) + (return-from vector-nreverse + (sb-vm::simd-nreverse32 original-vector vector start end))) (t (let* ((getter (the function (svref %%data-vector-reffers%% tag))) (setter (the function (svref %%data-vector-setters%% tag)))) @@ -997,7 +1002,7 @@ many elements are copied." (right (funcall getter vector right-index))) (funcall setter vector left-index right) (funcall setter vector right-index left))))))))) - vector) + original-vector) (defun nreverse (sequence) "Return a sequence of the same elements in reverse order; the argument @@ -1116,7 +1121,7 @@ many elements are copied." (macrolet ((def (name element-type &rest dispatch) `(defun ,name (&rest sequences) (declare (explicit-check) - (optimize (sb-c::insert-array-bounds-checks 0))) + (optimize (sb-c:insert-array-bounds-checks 0))) (let ((length 0)) (declare (index length)) (do-rest-arg ((seq) sequences) @@ -1153,9 +1158,11 @@ many elements are copied." (declare (index length)) (do-rest-arg ((seq) sequences) (incf length (length seq))) - (let ((result (sb-vm::allocate-vector-with-widetag widetag length nil)) - (setter (the function (svref %%data-vector-setters%% widetag))) - (index 0)) + (let* ((n-bits-shift (aref sb-vm::%%simple-array-n-bits-shifts%% widetag)) + (result (sb-vm::allocate-vector-with-widetag + #+ubsan nil widetag length n-bits-shift)) + (setter (the function (svref %%data-vector-setters%% widetag))) + (index 0)) (declare (index index)) (do-rest-arg ((seq) sequences) (sb-sequence:dosequence (e seq) @@ -1245,7 +1252,7 @@ many elements are copied." (progn (setf (car in-apply-args) (funcall elt s state)) (setf (caar in-iters) (funcall step s state from-end))))))))))))) -#-sb-devel + (declaim (start-block map %map)) (defun %map-to-list (fun sequences) @@ -1422,17 +1429,15 @@ many elements are copied." (setf (car node) (apply really-fun args)) (setf node (cdr node))))) (sequence - (multiple-value-bind (iter limit from-end) + (multiple-value-bind (iter limit from-end step endp elt set) (sb-sequence:make-sequence-iterator result-sequence) + (declare (ignore elt) (type function step endp set)) (map-into-lambda sequences (&rest args) (declare (truly-dynamic-extent args) (optimize speed)) - (when (sb-sequence:iterator-endp result-sequence - iter limit from-end) + (when (funcall endp result-sequence iter limit from-end) (return-from map-into result-sequence)) - (setf (sb-sequence:iterator-element result-sequence iter) - (apply really-fun args)) - (setf iter (sb-sequence:iterator-step result-sequence - iter from-end))))))) + (funcall set (apply really-fun args) result-sequence iter) + (setf iter (funcall step result-sequence iter from-end))))))) result-sequence) ;;;; REDUCE @@ -2206,7 +2211,7 @@ many elements are copied." start end count key test test-not old) (declare (fixnum start count end incrementer right) (type (or null function) key)) - (let* ((result (make-vector-like sequence length)) + (let* ((result (make-vector-like sequence length nil)) (getter (the function (svref %%data-vector-reffers%% (%other-pointer-widetag sequence)))) (setter (the function (svref %%data-vector-setters%% diff --git a/src/code/serve-event.lisp b/src/code/serve-event.lisp index 9b269a2961..d5ad7f58dc 100644 --- a/src/code/serve-event.lisp +++ b/src/code/serve-event.lisp @@ -192,7 +192,6 @@ ;;;; SERVE-ALL-EVENTS, SERVE-EVENT, and friends -#-sb-devel (declaim (start-block wait-until-fd-usable serve-event serve-all-events compute-pollfds)) ;;; When a *periodic-polling-function* is defined the server will not @@ -260,7 +259,7 @@ waiting." (+ (* 1000 to-sec) (truncate to-usec 1000)) -1) when (or #+win32 (eq direction :output) - #+win32 (sb-win32:handle-listen fd) + #+win32 (sb-win32:handle-listen fd (or to-sec 0) (or to-usec 0)) #-win32 (sb-unix:unix-simple-poll fd direction to-msec)) do (return-from wait-until-fd-usable t) @@ -322,7 +321,7 @@ happens. Server returns T if something happened and NIL otherwise. Timeout (let ((count 0)) (declare (type index count)) - ;; Initialize the fd-sets for UNIX-SELECT and return the active + ;; Initialize the fd-sets for UNIX-FAST-SELECT and return the active ;; descriptor count. (map-descriptor-handlers (lambda (handler) diff --git a/src/code/setf-funs.lisp b/src/code/setf-funs.lisp index 35ece7f5ac..1750e76bf4 100644 --- a/src/code/setf-funs.lisp +++ b/src/code/setf-funs.lisp @@ -14,10 +14,18 @@ (eval-when (:compile-toplevel :execute) +(defun c*r-function-p (string) + (and (char= (char string 0) #\C) + (char= (char string (1- (length string))) #\R) + (loop for i from 1 below (1- (length string)) + always (member (char string i) '(#\A #\D))))) + (defun compute-one-setter (name type) (let ((args (second type))) (cond ((null (intersection args lambda-list-keywords)) + (when (c*r-function-p (string name)) + (setq args '(cons))) (let ((res (type-specifier (single-value-type (values-specifier-type (third type))))) @@ -57,7 +65,7 @@ (let ((type (type-specifier (global-ftype sym)))) (aver (consp type)) (list - #-sb-fluid `(declaim (inline (setf ,sym))) + `(declaim (inline (setf ,sym))) (compute-one-setter sym type)))) (sort (res) #'string<))))) diff --git a/src/code/setf.lisp b/src/code/setf.lisp index 614d909f42..e560191818 100644 --- a/src/code/setf.lisp +++ b/src/code/setf.lisp @@ -46,14 +46,14 @@ ;;; of value forms, a list of the single store-value form, a storing function, ;;; and an accessing function. (declaim (ftype (function (t &optional lexenv-designator)) - sb-xc:get-setf-expansion)) -(defun sb-xc:get-setf-expansion (form &optional environment) + get-setf-expansion)) +(defun get-setf-expansion (form &optional environment) "Return five values needed by the SETF machinery: a list of temporary variables, a list of values with which to fill them, a list of temporaries for the new values, the setting function, and the accessing function." (named-let retry ((form form)) (labels ((newvals (count) - (let ((sb-xc:*gensym-counter* 1)) + (let ((*gensym-counter* 1)) (make-gensym-list count "NEW"))) ;; Produce the expansion of a SETF form that calls either ;; #'(SETF name) or an inverse given by short form DEFSETF. @@ -68,7 +68,7 @@ (multiple-value-bind (expansion expanded) ;; Previously this called %MACROEXPAND, but the two operations ;; are equivalent on atoms, so do the one that is "less". - (sb-xc:macroexpand-1 form environment) + (macroexpand-1 form environment) (if expanded (retry expansion) (let ((vals (newvals 1))) @@ -76,12 +76,18 @@ (let ((fname (car form))) ;; Local functions inhibit global SETF methods. (unless (sb-c::fun-locally-defined-p fname environment) + ;; There are 3 possibilities for the expander: + ;; #<fun> - define-setf-expander + ;; (symbol doc . source-loc) - defsetf short form + ;; (integer . #<fun>) - defsetf long form (awhen (info :setf :expander fname) (return-from retry (typecase it - (symbol ; short DEFSETF - (call `(,it) (lambda (new args) `(,@args ,new)))) - (list ; long DEFSETF + (function ; DEFINE-SETF-EXPANDER + (funcall it form environment)) + ((cons symbol) ; short form DEFSETF + (call `(,(car it)) (lambda (new args) `(,@args ,new)))) + (t ; long form DEFSETF (binding* ((newvals (newvals (car it))) (expander (the function (cdr it))) ((tempvars tempvals call-args) @@ -91,18 +97,14 @@ (or #+sb-xc (%fun-lambda-list expander))))) (values tempvars tempvals newvals (apply expander call-args environment newvals) - `(,fname ,@call-args)))) - ;; DEFINE-SETF-EXPANDER - (function (funcall it form environment))))) + `(,fname ,@call-args))))))) (awhen (transformable-struct-setf-p form environment) (let ((instance (make-symbol "OBJ")) (vals (newvals 1))) (return-from retry (values (list instance) (list (cadr form)) vals - (slot-access-transform - :setf (list instance (car vals)) it) - (slot-access-transform - :read (list instance) it)))))) + (slot-access-transform :setf (list instance (car vals)) it) + (slot-access-transform :read (list instance) it)))))) (multiple-value-bind (expansion expanded) (%macroexpand-1 form environment) (if expanded @@ -178,15 +180,14 @@ ;; NIL is not a valid setf inverse name, for two reasons: ;; 1. you can't define a function named NIL, ;; 2. (DEFSETF THING () ...) is the long form DEFSETF syntax. - (when (typep inverse '(and symbol (not null))) - (return-from setf `(,inverse ,@(cdr place) ,value-form)))) + (when (typep inverse '(cons symbol)) + (return-from setf `(,(car inverse) ,@(cdr place) ,value-form)))) (awhen (transformable-struct-setf-p place env) (return-from setf - (slot-access-transform - :setf (list (cadr place) value-form) it))))) + (slot-access-transform :setf (list (cadr place) value-form) it))))) (multiple-value-bind (temps vals newval setter) - (sb-xc:get-setf-expansion place env) + (get-setf-expansion place env) (car (gen-let* (mapcar #'list temps vals) (gen-mv-bind newval value-form (forms-list setter))))))) @@ -202,7 +203,7 @@ (collect ((let*-bindings) (mv-bindings) (setters) (getters)) (dolist (arg (butlast args)) (multiple-value-bind (temps subforms store-vars setter getter) - (sb-xc:get-setf-expansion arg env) + (get-setf-expansion arg env) (let*-bindings (mapcar #'list temps subforms)) (mv-bindings store-vars) (setters setter) @@ -216,7 +217,7 @@ (thunk (cdr mv-bindings) (cdr getters) setters)) setters))) (let ((outputs (loop for i below (length (car (mv-bindings))) - collect (sb-xc:gensym "OUT")))) + collect (gensym "OUT")))) (car (gen-let* (reduce #'nconc (let*-bindings)) (gen-mv-bind outputs (car (getters)) (thunk (mv-bindings) (cdr (getters)) @@ -239,7 +240,7 @@ (when (and (not (symbolp place)) (eq operator 'psetq)) (%program-error "Place ~S in PSETQ is not a SYMBOL" place)) (multiple-value-bind (temps vals stores setter) - (sb-xc:get-setf-expansion place env) + (get-setf-expansion place env) (let*-bindings (mapcar #'list temps vals)) (mv-bindings (cons stores value-form)) (setters setter)))) @@ -276,7 +277,7 @@ (collect ((let*-bindings) (mv-bindings) (setters) (getters)) (dolist (arg args) (multiple-value-bind (temps subforms store-vars setter getter) - (sb-xc:get-setf-expansion arg env) + (get-setf-expansion arg env) (let*-bindings (mapcar #'list temps subforms)) (mv-bindings store-vars) (setters setter) @@ -321,7 +322,7 @@ (if (symbolp (setq place (macroexpand-for-setf place env))) `(prog1 (car ,place) (setq ,place (cdr ,place))) (multiple-value-bind (temps vals stores setter getter) - (sb-xc:get-setf-expansion place env) + (get-setf-expansion place env) (let ((list (copy-symbol 'list)) (ret (copy-symbol 'car))) `(let* (,@(mapcar #'list temps vals) @@ -338,7 +339,7 @@ remove the property specified by the indicator. Returns T if such a property was present, NIL if not." (multiple-value-bind (temps vals newval setter getter) - (sb-xc:get-setf-expansion place env) + (get-setf-expansion place env) (let* ((flag (make-symbol "FLAG")) (body `(multiple-value-bind (,(car newval) ,flag) ;; See ANSI 5.1.3 for why we do out-of-order evaluation @@ -380,7 +381,7 @@ (if (symbolp (setq place (macroexpand-for-setf place env))) `(setq ,place (,operator ,delta ,place)) (multiple-value-bind (dummies vals newval setter getter) - (sb-xc:get-setf-expansion place env) + (get-setf-expansion place env) `(let* (,@(mapcar #'list dummies vals) (,(car newval) (,operator ,delta ,getter)) ,@(cdr newval)) @@ -399,7 +400,7 @@ (sb-xc:defmacro define-modify-macro (name lambda-list function &optional doc-string) "Creates a new read-modify-write macro like PUSH or INCF." - (check-designator name define-modify-macro) + (check-designator name 'define-modify-macro) (binding* (((nil required optional rest) (parse-lambda-list lambda-list @@ -418,8 +419,7 @@ ;;;; DEFSETF ;;; Assign SETF macro information for NAME, making all appropriate checks. -(defun %defsetf (name expander &optional doc) - (declare (ignorable doc)) +(defun %defsetf (name expander) (with-single-package-locked-error (:symbol name "defining a setf-expander for ~A")) (let ((setf-fn-name `(setf ,name))) @@ -449,9 +449,6 @@ (style-warn "defining setf macro for ~S when ~S is also defined" name setf-fn-name))))) (setf (info :setf :expander name) expander) - #-sb-xc-host - (when doc - (setf (documentation name 'setf) doc)) name) ;;; This is pretty broken if there are keyword arguments (lp#1452947) @@ -460,11 +457,13 @@ (sb-xc:defmacro defsetf (access-fn &rest rest) "Associates a SETF update function or macro with the specified access function or macro. The format is complex. See the manual for details." - (check-designator access-fn defsetf "access-function") + (check-designator access-fn 'defsetf + #'symbolp "symbol" "access-function") (typecase rest ((cons (and symbol (not null)) (or null (cons string null))) `(eval-when (:load-toplevel :compile-toplevel :execute) - (%defsetf ',access-fn ',(car rest) ,@(cdr rest)))) + (%defsetf ',access-fn + (list* ',(car rest) ,(cadr rest) (sb-c:source-location))))) ((cons list (cons list)) (destructuring-bind (lambda-list (&rest stores) &body body) rest (binding* (((llks req opt rest key aux env) @@ -484,15 +483,14 @@ `(eval-when (:compile-toplevel :load-toplevel :execute) (%defsetf ',access-fn (cons ,(length stores) - (named-lambda (%defsetf ,access-fn) - (,subforms ,env-var ,@stores) + (named-lambda (%defsetf ,access-fn) (,subforms ,env-var ,@stores) (declare (sb-c::lambda-list ,lambda-list)) + ,@(if doc (list doc)) ,@(if outer-decls (list outer-decls)) ,@(unless env `((declare (ignore ,env-var)))) (apply (lambda ,lambda-list ,@inner-decls (block ,access-fn ,@forms)) - ,subforms))) - ,@(and doc `(,doc))))))) + ,subforms)))))))) (t (error "Ill-formed DEFSETF for ~S" access-fn)))) @@ -507,7 +505,8 @@ ;; (defun collect-setf-temps (sexprs environment name-hints) (labels ((next-name-hint () - (let ((sym (pop name-hints))) ; OK if list was nil + ;; OK if list was nil or :UNKNOWN + (let ((sym (and (listp name-hints) (pop name-hints)))) (case sym (&optional (next-name-hint)) ((&key &rest) (setq name-hints nil)) @@ -519,7 +518,7 @@ (let ((mask 0) (bit 1)) (dolist (form sexprs (values (temp-vars) (temp-vals) (call-arguments) mask)) - (call-arguments (if (sb-xc:constantp form environment) + (call-arguments (if (constantp form environment) (progn (next-name-hint) form) ; Skip one hint. (let ((temp (nice-tempname form))) (setq mask (logior mask bit)) @@ -541,7 +540,7 @@ (binding* (((before-temps before-vals before-args) (collect-setf-temps before-arg-forms environment name-hints)) ((place-temps place-subforms stores setter getter) - (sb-xc:get-setf-expansion place environment)) + (get-setf-expansion place environment)) ((after-temps after-vals after-args) (if after-args-bindp (collect-setf-temps after-arg-forms environment name-hints) @@ -558,7 +557,7 @@ (every (lambda (x) (or (member x place-temps) (eq x newval-temp) - (sb-xc:constantp x environment))) + (constantp x environment))) (cdr setter))))) (setq newval-binding nil setter (substitute compute newval-temp setter))) @@ -577,14 +576,10 @@ (sb-xc:defmacro define-setf-expander (access-fn lambda-list &body body) "Syntax like DEFMACRO, but creates a setf expander function. The body of the definition must be a form that returns five appropriate values." - (check-designator access-fn define-setf-expander "access-function") - (multiple-value-bind (def doc) - ;; Perhaps it would be more elegant to keep the docstring attached - ;; to the expander function, as for CAS? - (make-macro-lambda `(setf-expander ,access-fn) lambda-list body - 'sb-xc:define-setf-expander access-fn - :doc-string-allowed :external) - ;; Maybe kill docstring, but only under the cross-compiler. - #+(and (not sb-doc) sb-xc-host) (setq doc nil) - `(eval-when (:compile-toplevel :load-toplevel :execute) - (%defsetf ',access-fn ,def ,@(and doc `(,doc)))))) + (check-designator access-fn 'define-setf-expander + #'symbolp "symbol" "access-function") + `(eval-when (:compile-toplevel :load-toplevel :execute) + (%defsetf ',access-fn + ,(make-macro-lambda `(setf-expander ,access-fn) lambda-list body + 'define-setf-expander access-fn + :doc-string-allowed :internal)))) diff --git a/src/code/share-vm.lisp b/src/code/share-vm.lisp index 12a32c171f..5a219583cf 100644 --- a/src/code/share-vm.lisp +++ b/src/code/share-vm.lisp @@ -19,7 +19,7 @@ #+(or x86 x86-64) `(progn ,@body) #-(or x86 x86-64) - `(with-pinned-objects ((without-gcing + `(with-pinned-objects ((with-code-pages-pinned (:dynamic) (sb-di::code-object-from-context ,context))) ,@body)) @@ -55,40 +55,29 @@ ;; the pointer in order to read the lower half. This has been broken ;; at least twice in the past. MIPS also appears to be the ONLY ;; system for which the signal context field size may differ from -;; n-word-bits (well, and ALPHA, but that's a separate matter), but -;; this entire thing will likely need to be revisited when we add x32 -;; or n32 ABI support. +;; n-word-bits. (defconstant kludge-big-endian-short-pointer-offset (+ 0 #+(and mips big-endian (not 64-bit)) 1)) -(declaim (inline context-pc-addr)) -(define-alien-routine ("os_context_pc_addr" context-pc-addr) (* unsigned) - (context (* os-context-t))) - (declaim (inline context-pc)) (defun context-pc (context) (declare (type (alien (* os-context-t)) context)) - (let ((addr (context-pc-addr context))) - (declare (type (alien (* unsigned)) addr)) - (int-sap (deref addr kludge-big-endian-short-pointer-offset)))) + (alien-funcall (extern-alien "os_context_pc" (function system-area-pointer (* os-context-t))) + context)) -(declaim (inline incf-context-pc)) -(defun incf-context-pc (context offset) +(declaim (inline set-context-pc)) +(defun set-context-pc (context new) (declare (type (alien (* os-context-t)) context)) (with-pinned-context-code-object (context) - (let ((addr (context-pc-addr context))) - (declare (type (alien (* unsigned)) addr)) - (setf (deref addr kludge-big-endian-short-pointer-offset) - (+ (deref addr kludge-big-endian-short-pointer-offset) offset))))) + (alien-funcall (extern-alien "set_os_context_pc" (function void (* os-context-t) unsigned)) + context new))) -(declaim (inline set-context-pc)) -(defun set-context-pc (context new) +(declaim (inline incf-context-pc)) +(defun incf-context-pc (context offset) (declare (type (alien (* os-context-t)) context)) (with-pinned-context-code-object (context) - (let ((addr (context-pc-addr context))) - (declare (type (alien (* unsigned)) addr)) - (setf (deref addr kludge-big-endian-short-pointer-offset) new)))) + (set-context-pc context (sap-int (sap+ (context-pc context) offset))))) (declaim (inline context-register-addr)) (define-alien-routine ("os_context_register_addr" context-register-addr) @@ -96,6 +85,19 @@ (context (* os-context-t)) (index int)) +(sb-c::when-vop-existsp (:translate sb-c::unsigned+) + (declaim (inline os-context-flags-addr)) + (define-alien-routine ("os_context_flags_addr" os-context-flags-addr) + (* unsigned) + (context (* os-context-t))) + + (declaim (inline context-flags)) + (defun context-flags (context) + (declare (type (alien (* os-context-t)) context)) + (let ((addr (os-context-flags-addr context))) + (declare (type (alien (* unsigned)) addr)) + (deref addr)))) + (declaim (inline context-register)) (defun context-register (context index) (declare (type (alien (* os-context-t)) context)) @@ -135,3 +137,50 @@ ;;; change our notion of what we think they are. (declaim (inline descriptor-sap)) (defun descriptor-sap (x) (int-sap (get-lisp-obj-address x))) + + + +(eval-when (:compile-toplevel :load-toplevel :execute) + (defparameter *cpu-features* nil)) + +(defmacro def-cpu-feature (name detect) + ;; eval-when doesn't work correctly in the XC + (setf (getf *cpu-features* name) detect) + `(progn + (defglobal ,(symbolicate '+ name '-routines+) ()) + (setf (getf *cpu-features* ',name) ',detect))) + +(defmacro def-variant (name cpu-feature lambda-list &body body) + (let ((variant (symbolicate name '- cpu-feature))) + `(progn + (eval-when (:compile-toplevel :load-toplevel :execute) + (setf (info :function :type ',variant) (info :function :type ',name) + (info :function :info ',variant) (info :function :info ',name))) + (defun ,variant ,lambda-list + ,@body) + ;; Avoid STATICALLY-LINK-CORE from making it harder to redefine. + (proclaim '(notinline ,name)) + (let ((fun #',variant)) + (setf (getf ,(symbolicate '+ cpu-feature '-routines+) ',name) fun) + ;; Redefinition at run-time. + (when (eq (%fun-name #',name) ',variant) + (setf (%symbol-function ',name) fun)))))) + +(defvar *previous-cpu-routines* nil) + +(defmacro !setup-cpu-specific-routines () + `(progn + ,@(loop for (feature detect) on *cpu-features* by #'cddr + collect + `(when ,detect + (loop for (symbol definition) on ,(package-symbolicate "SB-VM" '+ feature '-routines+) + by #'cddr + do + (push (cons symbol (%symbol-function symbol)) + *previous-cpu-routines*) + (setf (%symbol-function symbol) definition)))))) + +(defun restore-cpu-specific-routines () + (loop for (symbol . fun) in *previous-cpu-routines* + do (setf (%symbol-function symbol) fun)) + (setf *previous-cpu-routines* nil)) diff --git a/src/code/sharpm.lisp b/src/code/sharpm.lisp index 9be90052cf..0d3045f8a1 100644 --- a/src/code/sharpm.lisp +++ b/src/code/sharpm.lisp @@ -49,42 +49,33 @@ (defun sharp-star (stream ignore numarg) (declare (ignore ignore)) (declare (type (or null integer) numarg)) - (binding* (((buffer escape-appearedp) (read-extended-token stream)) + (binding* (((buffer escaped) (read-extended-token stream)) (input-len (token-buf-fill-ptr buffer)) (bstring (token-buf-string buffer))) - (cond (*read-suppress* nil) - (escape-appearedp - (simple-reader-error stream - "An escape character appeared after #*.")) - ((and numarg (zerop input-len) (not (zerop numarg))) - (simple-reader-error - stream - "You have to give a little bit for non-zero #* bit-vectors.")) - ((or (null numarg) (>= numarg input-len)) - (do ((bvec - (make-array (or numarg input-len) - :element-type 'bit - :initial-element - (if (and (plusp input-len) - (char= (char bstring (1- input-len)) #\1)) - 1 0))) - (i 0 (1+ i))) - ((= i input-len) bvec) - (declare (index i) (optimize (sb-c::insert-array-bounds-checks 0))) - (let ((char (char bstring i))) - (setf (elt bvec i) - (case char - (#\0 0) - (#\1 1) - (t (simple-reader-error - stream "illegal element given for bit-vector: ~S" - char))))))) - (t - (simple-reader-error - stream - "Bit vector is longer than specified length #~A*~A" - numarg - (copy-token-buf-string buffer)))))) + (when *read-suppress* (return-from sharp-star nil)) + (when escaped (simple-reader-error stream "An escape character appeared after #*.")) + (when numarg + (cond ((and (not (eql numarg 0)) (zerop input-len)) + (simple-reader-error + stream "#~D* requires at least 1 bit of input." numarg)) + ((> input-len numarg) + (simple-reader-error + stream "Too many bits in ~S: expected ~D or fewer" + (copy-token-buf-string buffer) numarg))) + (when (eql numarg 0) (setq numarg nil))) + (let* ((fill (if numarg (logand (char-code (char bstring (1- input-len))) 1) 0)) + (bvec (make-array (or numarg input-len) + :element-type 'bit :initial-element fill))) + (do ((i 0 (1+ i))) + ((= i input-len) bvec) + (declare (index i) (optimize (sb-c:insert-array-bounds-checks 0))) + (let ((char (char bstring i))) + (setf (elt bvec i) + (case char + (#\0 0) + (#\1 1) + (t (simple-reader-error + stream "illegal element given for bit-vector: ~S" char))))))))) (defun sharp-A (stream ignore rank) (declare (ignore ignore)) @@ -157,8 +148,9 @@ (simple-reader-error stream "~S is not a defined structure type." (car body))) - (let ((default-constructor (dd-default-constructor - (layout-info (classoid-layout classoid))))) + (let ((default-constructor + (dd-default-constructor + (sb-kernel::wrapper-%info (classoid-wrapper classoid))))) (unless default-constructor (simple-reader-error stream @@ -236,6 +228,9 @@ ;; though the docs say this is undefined behavior, so it's ok, ;; other than it being something we should complain about ;; for portability reasons. + ;; Some other things that shouldn't work: + ;; * (read-from-string "#x a") => 10 + ;; * (read-from-string "#x #+foo a b") => 11 (let ((res (let ((*read-base* radix)) (read stream t nil t)))) (unless (typep res 'rational) @@ -280,7 +275,9 @@ `(let* ((old ,place) (new (recurse old))) (unless (eq old new) - (setf ,place new))))) + ,(if (eq (car place) '%instance-ref) + `(%instance-set ,@(cdr place) new) + `(setf ,place new)))))) (typecase tree (cons (process (car tree)) @@ -294,25 +291,21 @@ (instance ;; Don't refer to the DD-SLOTS unless there is reason to, ;; that is, unless some slot might be raw. - (if (/= +layout-all-tagged+ (layout-bitmap (%instance-layout tree))) - (let ((dd (layout-info (%instance-layout tree)))) - (dolist (dsd (dd-slots dd)) - (when (eq (dsd-raw-type dsd) t) - (process (%instance-ref tree (dsd-index dsd)))))) + (if (sb-kernel::bitmap-all-taggedp (%instance-layout tree)) (do ((len (%instance-length tree)) (i sb-vm:instance-data-start (1+ i))) ((>= i len)) - (process (%instance-ref tree i))))) - ;; It is not safe to iterate over %FUNCALLABLE-INSTANCE-INFO without knowing - ;; where the raw slots are, if any. We can safely process FSC-INSTANCE-SLOTS - ;; though, and that's the *only* slot to look at. - ;; No other funcallable structure (%METHOD-FUNCTION, INTERPRETED-FUNCTION, etc) - ;; has a reader syntax. - ;; ASSUMPTION: all funcallable structures have at least 1 slot beyond - ;; %FUNCALLABLE-INSTANCE-FUN (overlapping with FSC-INSTANCE-SLOTS) - ;; and that slot is never a raw slot. + (process (%instance-ref tree i))) + (let ((dd (wrapper-dd (%instance-wrapper tree)))) + (dolist (dsd (dd-slots dd)) + (when (eq (dsd-raw-type dsd) t) + (process (%instance-ref tree (dsd-index dsd)))))))) + ;; ASSUMPTION: all funcallable instances have at least 1 slot + ;; accessible via FUNCALLABLE-INSTANCE-INFO. + ;; The only such objects with reader syntax are CLOS objects, + ;; and those have exactly 1 slot in the primitive object. (funcallable-instance - (process (sb-pcl::%fsc-instance-slots tree)))))) + (process (%funcallable-instance-info tree 0)))))) tree))) ;;; Sharp-equal works as follows. @@ -434,7 +427,6 @@ 'sb-kernel::character-decoding-error-in-dispatch-macro-char-comment :sub-char sub-char :position (file-position stream) :stream stream) (invoke-restart 'attempt-resync)))) - (let ((stream (in-stream-from-designator stream))) (macrolet ((munch (get-char &optional finish) `(do ((level 1) (prev ,get-char char) @@ -453,7 +445,7 @@ (prepare-for-fast-read-char stream (munch (fast-read-char) (done-with-fast-read-char))) ;; fundamental-stream - (munch (read-char stream t))))))) + (munch (read-char stream t)))))) ;;;; a grab bag of other sharp readmacros: #', #:, and #. diff --git a/src/code/signal.lisp b/src/code/signal.lisp index dbde366c38..724a497722 100644 --- a/src/code/signal.lisp +++ b/src/code/signal.lisp @@ -48,10 +48,10 @@ ;;; (foo)) ;;; provided that the first branch is true "often enough". -;;; These 4 symbols are initialized by create_thread_struct() +;;; These 4 symbols are initialized by alloc_thread_struct() (defvar *interrupts-enabled*) (defvar *interrupt-pending*) -#+sb-thruption (defvar *thruption-pending*) +#+sb-safepoint (defvar *thruption-pending*) (defvar *allow-with-interrupts*) ;;; This is to support signal handlers that want to return to the @@ -65,13 +65,13 @@ ;;; would not cut it, as upon leaving WITHOUT-INTERRUPTS the pending ;;; handlers is run with stuff from the function in which this is ;;; still on the stack. -(defparameter *unblock-deferrables-on-enabling-interrupts-p* nil) +(defvar *unblock-deferrables-on-enabling-interrupts-p* nil) (eval-when (:compile-toplevel :load-toplevel :execute) (dolist (symbol '(*unblock-deferrables-on-enabling-interrupts-p* *interrupts-enabled* *interrupt-pending* - #+sb-thruption *thruption-pending* + #+sb-safepoint *thruption-pending* *allow-with-interrupts*)) ;; Force these to be always bound despite absence of a compile-time binding. ;; (Avoid accidentally installing a value into symbol->value in cold-load) @@ -154,7 +154,7 @@ WITHOUT-INTERRUPTS in: ;; handled immediately upon exit from said ;; WITHOUT-INTERRUPTS, so it is as if nothing has happened. (when (or *interrupt-pending* - #+sb-thruption *thruption-pending*) + #+sb-safepoint *thruption-pending*) (receive-pending-interrupt))) (,without-interrupts-body))))) diff --git a/src/code/simd-fndb.lisp b/src/code/simd-fndb.lisp new file mode 100644 index 0000000000..c8a15b4426 --- /dev/null +++ b/src/code/simd-fndb.lisp @@ -0,0 +1,34 @@ +;;;; This software is part of the SBCL system. See the README file for +;;;; more information. +;;;; +;;;; This software is derived from the CMU CL system, which was +;;;; written at Carnegie Mellon University and released into the +;;;; public domain. The software is in the public domain and is +;;;; provided with absolutely no warranty. See the COPYING and CREDITS +;;;; files for more information. + +(in-package "SB-VM") + +(deftype 128-element () + #+x86-64 '(simd-pack (unsigned-byte 32)) + #+arm64 'complex-double-float) + +(defknown vector-ref-128 (t index) 128-element + (flushable)) + +(defknown (setf vector-ref-128) (128-element t index) (values) + ()) + +(defknown (simd-nreverse8 simd-nreverse32) (vector (simple-array * (*)) fixnum fixnum) + vector + (sb-c::fixed-args)) + +(defknown (simd-reverse8 simd-reverse32) ((simple-array * (*)) (simple-array * (*)) fixnum fixnum) + (simple-array * (*)) + (sb-c::fixed-args)) + +(defknown (simd-cmp-8-8 simd-cmp-8-32 simd-cmp-32-32 simd-base-string-equal + simd-base-character-string-equal) + ((simple-array * (*)) (simple-array * (*)) fixnum) + (boolean) + (sb-c::no-verify-arg-count)) diff --git a/src/code/simple-fun.lisp b/src/code/simple-fun.lisp index 7234950bfc..113aaf1b85 100644 --- a/src/code/simple-fun.lisp +++ b/src/code/simple-fun.lisp @@ -14,8 +14,7 @@ ;;; Underlying SIMPLE-FUN (defun %fun-fun (function) (declare (function function)) - ;; It's too bad that TYPECASE isn't able to generate equivalent code. - (case (fun-subtype function) + (case (%fun-pointer-widetag function) (#.sb-vm:closure-widetag (%closure-fun function)) (#.sb-vm:funcallable-instance-widetag @@ -39,51 +38,54 @@ (logand (ash (function-header-word f) (- sb-vm:n-widetag-bits)) sb-vm:short-header-max-words)) -(macrolet ((%closure-index-set (closure index val) - ;; Use the identical convention as %CLOSURE-INDEX-REF for the index. - ;; There are no closure slot setters, and in fact SLOT-SET - ;; does not exist in a variant that takes a non-constant index. - `(setf (sap-ref-lispobj (int-sap (get-lisp-obj-address ,closure)) - (+ (ash sb-vm:closure-info-offset sb-vm:word-shift) - (ash ,index sb-vm:word-shift) - (- sb-vm:fun-pointer-lowtag))) - ,val)) - (closure-header-word (closure) - `(sap-ref-word (int-sap (get-lisp-obj-address ,closure)) - (- sb-vm:fun-pointer-lowtag))) - (new-closure (len) - #-(or x86 x86-64) - `(sb-vm::%alloc-closure ,len (%closure-fun closure)) - #+(or x86 x86-64) +(defmacro closure-len->nvalues (length) + `(- ,length (1- sb-vm:closure-info-offset))) + +;; Return T if and only if CLOSURE has extra values that are physically +;; in a padding slot of the object and not in the external hash-table. +(defun closure-has-extra-values-slot-p (closure) + (declare (closure closure)) + (and (logtest (function-header-word closure) closure-extra-data-indicator) + (evenp (get-closure-length closure)))) + +(macrolet ((new-closure (nvalues) + ;; argument is the number of INFO words + #-(or x86 x86-64 arm64) + `(sb-vm::%alloc-closure ,nvalues (%closure-fun closure)) + #+(or x86 x86-64 arm64) `(with-pinned-objects ((%closure-fun closure)) ;; %CLOSURE-CALLEE manifests as a fixnum which remains ;; valid across GC due to %CLOSURE-FUN being pinned ;; until after the new closure is made. - (sb-vm::%alloc-closure ,len (sb-vm::%closure-callee closure)))) - (copy-slots (extra-bit) - `(progn - (loop with sap = (int-sap (get-lisp-obj-address copy)) - for i from 0 below (1- payload-len) - for ofs from (- (ash 2 sb-vm:word-shift) sb-vm:fun-pointer-lowtag) - by sb-vm:n-word-bytes - do (setf (sap-ref-lispobj sap ofs) (%closure-index-ref closure i))) - (setf (closure-header-word copy) ; Update the header - ;; Closure copy lost its high header bits, so OR them in again. - (logior #+(and immobile-space 64-bit sb-thread) - (sap-int (sb-vm::current-thread-offset-sap - sb-vm::thread-function-layout-slot)) - #+(and immobile-space 64-bit (not sb-thread)) - (get-lisp-obj-address sb-vm:function-layout) - (function-header-word copy) - ,extra-bit))))) + (sb-vm::%alloc-closure ,nvalues (sb-vm::%closure-callee closure)))) + (copy-slots (has-extra-data) + `(do ((j 0 (1+ j))) + ((>= j nvalues) + (with-pinned-objects (copy) + (let ((sap (sap+ (int-sap (get-lisp-obj-address copy)) + (- sb-vm:fun-pointer-lowtag)))) + (declare (ignorable sap)) + ,@(when has-extra-data + `((setf (sap-ref-word sap 0) + (logior (function-header-word copy) + closure-extra-data-indicator)))) + #+immobile-space ; copy the layout + (setf (sap-ref-32 sap 4) ; ASSUMPTION: little-endian + (logior (get-lisp-obj-address + (wrapper-friend ,(find-layout 'function))))) + #+metaspace ; copy the CODE (not accessible by index-ref) + (setf (sap-ref-lispobj sap (ash sb-vm::closure-code-slot sb-vm:word-shift)) + (sb-vm::%closure-code closure))))) + (%closure-index-set copy j (%closure-index-ref closure j))))) ;; This is factored out because of a cutting-edge implementation ;; of tracing wrappers that I'm trying to finish. (defun copy-closure (closure) (declare (closure closure)) - (let* ((payload-len (get-closure-length (truly-the function closure))) - (copy (new-closure (1- payload-len)))) - (with-pinned-objects (copy) (copy-slots 0)) + (let* ((nvalues (closure-len->nvalues + (get-closure-length (truly-the function closure)))) + (copy (new-closure nvalues))) + (copy-slots nil) copy)) ;;; Assign CLOSURE a new name and/or docstring in VALUES, and return the @@ -96,17 +98,15 @@ ;;; then a copy of the closure with extra slots reduces to case (1). (defun set-closure-extra-values (closure permit-copy data) (declare (closure closure)) - (let ((payload-len (get-closure-length (truly-the function closure))) - (extendedp (logtest (function-header-word closure) - closure-extra-data-indicator))) - (when (and (not extendedp) permit-copy (oddp payload-len)) - ;; PAYLOAD-LEN includes the trampoline, so the number of slots we would - ;; pass to %ALLOC-CLOSURE is 1 less than that, were it not for - ;; the fact that we actually want to create 1 additional slot. - ;; So in effect, asking for PAYLOAD-LEN does exactly the right thing. - (let ((copy (new-closure payload-len))) + (let* ((len (get-closure-length (truly-the function closure))) + (nvalues (closure-len->nvalues len)) + (has-padding-slot (evenp len)) + (extendedp (logtest (function-header-word closure) + closure-extra-data-indicator))) + (when (and (not extendedp) (not has-padding-slot) permit-copy) + (let ((copy (new-closure (1+ nvalues)))) (with-pinned-objects (copy) - (copy-slots closure-extra-data-indicator) + (copy-slots t) ;; We copy only if there was no padding, which means that adding 1 slot ;; physically adds 2 slots. You might think that the added data go in the ;; first new slot, followed by padding. Nope! Take an example of a @@ -121,17 +121,20 @@ ;; CLOSURE-EXTRA-VALUES always reads 1 word past the stated payload size ;; regardless of whether the closure really captured the implied ;; number of closure values. - (%closure-index-set copy payload-len data) + (%closure-index-set copy (1+ nvalues) data) (return-from set-closure-extra-values copy)))) (unless (with-pinned-objects (closure) (unless extendedp ; Set the header bit - (setf (closure-header-word closure) + (setf (sap-ref-word (int-sap (get-lisp-obj-address closure)) + (- sb-vm:fun-pointer-lowtag)) (logior (function-header-word closure) closure-extra-data-indicator))) - (when (evenp payload-len) - (%closure-index-set closure (1- payload-len) data) + (when has-padding-slot + (%closure-index-set closure nvalues data) t)) - (setf (gethash closure **closure-extra-values**) data))) + (if (unbound-marker-p data) + (remhash closure **closure-extra-values**) + (setf (gethash closure **closure-extra-values**) data)))) closure)) (defun pack-closure-extra-values (name docstring) @@ -158,40 +161,21 @@ ;; an even-length payload takes the last slot for the name, ;; and an odd-length payload uses the global hashtable. (declare (closure closure)) - (let ((header-word (function-header-word closure))) - (if (not (logtest header-word closure-extra-data-indicator)) - (values unbound unbound) - (let* ((len (logand (ash header-word (- sb-vm:n-widetag-bits)) - sb-vm:short-header-max-words)) - (data - (if (oddp len) - ;; Boxed length odd implies total length even which implies - ;; no extra slot in which to store ancillary data. - (gethash closure **closure-extra-values** 0) - ;; GET-CLOSURE-LENGTH counts the 'fun' slot in the length, - ;; but %CLOSURE-INDEX-REF starts indexing from the value slots. - (%closure-index-ref closure (1- len))))) - ;; There can be a concurrency glitch, because the 'extended' flag is - ;; toggled to indicate that extra data are present before the data - ;; are written; so there's a window where NAME looks like 0. That could - ;; be fixed in the setter, or caught here, but it shouldn't matter. + (if (logtest (function-header-word closure) closure-extra-data-indicator) + (let* ((len (get-closure-length closure)) + ;; See examples in doc/internals-notes/closure + (data (if (evenp len) ; has padding slot + (%closure-index-ref closure (closure-len->nvalues len)) + ; No padding slot + (gethash closure **closure-extra-values** 0)))) (typecase data + ((eql 0) (values unbound unbound)) ((cons t (or string null (satisfies unbound-marker-p))) (values (car data) (cdr data))) ;; NIL represents an explicit docstring of NIL, not the name. ((or string null) (values unbound data)) - (t (values data unbound))))))) - -;; Return T if and only if CLOSURE has extra values that are physically -;; in the padding slot of the object and not in the external hash-table. -(defun closure-has-extra-values-slot-p (closure) - (declare (closure closure)) - (let ((header-word (function-header-word closure))) - (and (logtest header-word closure-extra-data-indicator) - ;; If the boxed payload length is even, adding the header makes it odd, - ;; so there's a padding slot for alignment to an even total word count. - ;; i.e. if the least-significant bit of the size field is 0, there's padding. - (not (logbitp sb-vm:n-widetag-bits header-word))))) + (t (values data unbound)))) + (values unbound unbound))) (defconstant +closure-name-index+ 0) (defconstant +closure-doc-index+ 1) @@ -206,7 +190,7 @@ ;;; (i.e., the third value returned from CL:FUNCTION-LAMBDA-EXPRESSION), ;;; or NIL if there's none (defun %fun-name (function) - (case (fun-subtype function) + (case (%fun-pointer-widetag function) (#.sb-vm:closure-widetag (let ((val (nth-value +closure-name-index+ (closure-extra-values function)))) (unless (unbound-marker-p val) @@ -226,7 +210,7 @@ (%simple-fun-name (%fun-fun function))) (defun (setf %fun-name) (new-value function) - (case (fun-subtype function) + (case (%fun-pointer-widetag function) (#.sb-vm:closure-widetag (set-closure-name (truly-the closure function) nil new-value)) (#.sb-vm:simple-fun-widetag @@ -310,7 +294,7 @@ ((not simple-vector) info)))) ;; For backward-compatibility we expand SFUNCTION -> FUNCTION. (if (and (listp internal-type) (eq (car internal-type) 'sfunction)) - (sb-ext:typexpand-1 internal-type) + (values (sb-ext:typexpand-1 internal-type)) internal-type))) (defun %simple-fun-xrefs (fun) @@ -319,14 +303,36 @@ ((cons t simple-vector) (cdr info)) (simple-vector info)))) -(defun %fun-type (function) +(defun %fun-ftype (function) (typecase function #+sb-fasteval ;; Obtain a list of the right shape, usually with T for each ;; arg type, but respecting local declarations if any. - (interpreted-function (sb-interpreter:%fun-type function)) + (interpreted-function (sb-interpreter:%fun-ftype function)) (t (%simple-fun-type (%fun-fun function))))) +(defun sb-c::ftype-from-definition (name) + (let ((function (fboundp name))) + (cond + ((not function) + (specifier-type 'function)) + ((and (symbolp name) (macro-function name)) + ;; this seems to be called often on macros + ;; what's the right answer ??? + ;; (warn "ftype-from-fdefn called on macro ~s" name) + (specifier-type '(function (t t) t))) + (t + ;; Never signal the PARSE-UNKNOWN-TYPE condition. + ;; This affects 2 regression tests, both very contrived: + ;; - in defstruct.impure ASSERT-ERROR (BUG127--FOO (MAKE-BUG127-E :FOO 3)) + ;; - in compiler.impure at :IDENTIFY-SUSPECT-VOPS + (let* ((ftype (%fun-ftype function)) + (context + (sb-kernel::make-type-context + ftype nil sb-kernel::+type-parse-signal-inhibit+))) + (declare (truly-dynamic-extent context)) + (values (sb-kernel::basic-parse-typespec ftype context))))))) + ;;; Return the lambda expression for SIMPLE-FUN if compiled to memory ;;; and rentention of forms was enabled via the EVAL-STORE-SOURCE-FORM policy ;;; (as is the default). @@ -352,10 +358,6 @@ (if (and form doc) (cons form doc) (or form doc)))) doc) -(defun %simple-fun-next (simple-fun) ; DO NOT USE IN NEW CODE - (%code-entry-point (fun-code-header simple-fun) - (1+ (%simple-fun-index simple-fun)))) - ;;; Return the number of bytes to subtract from the untagged address of SIMPLE-FUN ;;; to obtain the untagged address of its code component. ;;; See also CODE-FROM-FUNCTION. @@ -374,36 +376,46 @@ ;;;; CODE-COMPONENT -(defun %code-entry-points (code-obj) ; DO NOT USE IN NEW CODE - (%code-entry-point code-obj 0)) - -(declaim (inline code-obj-is-filler-p)) -(defun code-obj-is-filler-p (code-obj) - ;; See also HOLE-P in the allocator (same thing but using SAPs) - ;; and filler_obj_p() in the C code - (eql (sb-vm::%code-boxed-size code-obj) 0)) - -#+(or sparc alpha hppa ppc64) +;;; software mark bits on pages of code require that all assignments to +;;; header slots go through the CODE-HEADER-SET vop, +;;; which is slightly different from the general soft card mark implementation +;;; for historical reasons. +(defun (setf %code-debug-info) (newval code) + (setf (code-header-ref code sb-vm:code-debug-info-slot) newval) + newval) + +(defun %code-debug-info (code-obj) + ;; Extract the unadulterated debug-info emitted by the compiler. The slot + ;; value might be a cons of that and info stuffed in by the debugger. + (let ((info (sb-vm::%%code-debug-info code-obj))) + (if (and (listp info) (%instancep (car info))) + (car info) + ;; return it unchanged in all other cases + info))) + +(defun (setf sb-vm::%code-fixups) (newval code) + (code-header-set code sb-vm::code-fixups-slot newval) + newval) + +#+(or sparc ppc64) (defun code-trailer-ref (code offset) (with-pinned-objects (code) (sap-ref-32 (int-sap (get-lisp-obj-address code)) (+ (code-object-size code) offset (- sb-vm:other-pointer-lowtag))))) ;;; The last 'uint16' in the object holds the trailer length (see 'src/runtime/code.h') -;;; but do not attempt to read it if the object is a filler. (declaim (inline code-trailer-len)) (defun code-trailer-len (code-obj) - (if (code-obj-is-filler-p code-obj) - 0 - (let ((word (code-trailer-ref code-obj -4))) - ;; TRAILER-REF returns 4-byte quantities. Extract a two-byte quantity. - #+little-endian (ldb (byte 16 16) word) - #+big-endian (ldb (byte 16 0) word)))) + (let ((word (code-trailer-ref code-obj -4))) + ;; TRAILER-REF returns 4-byte quantities. Extract a two-byte quantity. + #+little-endian (ldb (byte 16 16) word) + #+big-endian (ldb (byte 16 0) word))) ;;; The fun-table-count is a uint16_t immediately preceding the trailer length ;;; containing two subfields: -;;; 12 bits for the number of simple-funs in the code component -;;; 4 bits for the number of pad bytes added to align the fun-offset-table +;;; 11 bits for the number of simple-funs in the code component +;;; 5 bits for the number of pad bytes added to align the fun-offset-table +;;; See also code_n_funs() in code.h (declaim (inline code-fun-table-count)) (defun code-fun-table-count (code-obj) (if (eql (code-trailer-len code-obj) 0) @@ -417,26 +429,22 @@ ;;; Keep in sync with C function code_n_funs() (defun code-n-entries (code-obj) (declare (type code-component code-obj)) - (ash (code-fun-table-count code-obj) -4)) - -;;; Index to start of named-call fdefns -;;; FIXME: Naming symmetry between this and code-n-named-calls might be nice. -(defun code-fdefns-start-index (code-obj) - (+ sb-vm:code-constants-offset - (* (code-n-entries code-obj) sb-vm:code-slots-per-simple-fun))) + (ash (code-fun-table-count code-obj) -5)) -;;; Number of "called" fdefns, which does not count fdefns in the boxed -;;; constants that are used in #'FUN syntax without a funcall necessarily -;;; occuring, though it may. -(defun code-n-named-calls (code-obj) - (ash (sb-vm::%code-boxed-size code-obj) - (+ -32 sb-vm:n-fixnum-tag-bits))) +;;; Start and count of fdefns used in #'F synax or normal named call +;;; (i.e. at the head of an expression) +(export 'sb-vm::code-header-fdefn-range 'sb-vm) ; protect from tree-shaker +(defun sb-vm::code-header-fdefn-range (code-obj) + (values (+ sb-vm:code-constants-offset + (* (code-n-entries code-obj) sb-vm:code-slots-per-simple-fun)) + (ash (sb-vm::%code-boxed-size code-obj) + (+ -32 sb-vm:n-fixnum-tag-bits)))) ;;; Return the offset in bytes from (CODE-INSTRUCTIONS CODE-OBJ) ;;; to its FUN-INDEXth function. (declaim (inline %code-fun-offset)) (defun %code-fun-offset (code-obj fun-index) - (declare ((unsigned-byte 12) fun-index)) + (declare ((unsigned-byte 11) fun-index)) (code-trailer-ref code-obj (* -4 (+ fun-index 2)))) ;;; Subtract from %CODE-CODE-SIZE the number of trailing data bytes which aren't @@ -454,21 +462,17 @@ (defun %code-text-size (code-obj) (- (%code-code-size code-obj) (code-trailer-len code-obj) - ;; Subtract between 0 and 15 bytes of padding - (logand (code-fun-table-count code-obj) #xf))) + ;; Subtract between 0 and 31 bytes of padding + (logand (code-fun-table-count code-obj) #x1f))) (defun %code-entry-point (code-obj fun-index) (declare (type (unsigned-byte 16) fun-index)) + ;; FIXME: it should probably be an error to pass FUN-INDEX too large (when (< fun-index (code-n-entries code-obj)) (truly-the function (values (%primitive sb-c:compute-fun code-obj (%code-fun-offset code-obj fun-index)))))) -(defun code-entry-points (code-obj) ; FIXME: obsolete - (let ((a (make-array (code-n-entries code-obj)))) - (dotimes (i (length a) a) - (setf (aref a i) (%code-entry-point code-obj i))))) - ;;; Return the 0-based index of SIMPLE-FUN within its code component. ;;; Computed via binary search. (defun %simple-fun-index (simple-fun) @@ -621,29 +625,3 @@ (do-closure-values (value closure) (when (funcall test value) (return value)))) - -(in-package "SB-C") - -;;; This is target-only code, so doesn't belong in 'debug-info.lisp' -(flet ((unpack-tlf-num+offset (integer &aux (bytepos 0)) - (flet ((unpack-1 () - (let ((shift 0) (acc 0)) - (declare (notinline sb-kernel:%ldb)) ; lp#1573398 - (loop - (let ((byte (ldb (byte 8 bytepos) integer))) - (incf bytepos 8) - (setf acc (logior acc (ash (logand byte #x7f) shift))) - (if (logtest byte #x80) - (incf shift 7) - (return acc))))))) - (let ((v1 (unpack-1)) - (v2 (unpack-1))) - (values (if (eql v1 0) nil (1- v1)) - (if (eql v2 0) nil (1- v2))))))) - (defun compiled-debug-info-tlf-number (cdi) - (nth-value 0 (unpack-tlf-num+offset - (compiled-debug-info-tlf-num+offset cdi)))) - - (defun compiled-debug-info-char-offset (cdi) - (nth-value 1 (unpack-tlf-num+offset - (compiled-debug-info-tlf-num+offset cdi))))) diff --git a/src/code/sort.lisp b/src/code/sort.lisp index 0708ec8c43..a13daf232b 100644 --- a/src/code/sort.lisp +++ b/src/code/sort.lisp @@ -325,14 +325,18 @@ (type (or null function) key)) (declare (explicit-check)) (declare (dynamic-extent pred key)) - (vector-merge-sort vector pred key svref)) + (if (<= (length vector) 1) ; avoid consing + vector + (vector-merge-sort vector pred key svref))) (defun stable-sort-vector (vector pred key) (declare (type function pred) (type (or null function) key)) (declare (explicit-check)) (declare (dynamic-extent pred key)) - (vector-merge-sort vector pred key aref)) + (if (<= (length vector) 1) ; avoid consing + vector + (vector-merge-sort vector pred key aref))) ;;;; merging diff --git a/src/code/source-location.lisp b/src/code/source-location.lisp index 87b97c096f..59c0770537 100644 --- a/src/code/source-location.lisp +++ b/src/code/source-location.lisp @@ -84,7 +84,7 @@ (or *source-namestring* (when source-info (make-file-info-namestring - *compile-file-pathname* + cl:*compile-file-pathname* (get-toplevelish-file-info source-info))))) tlf-number form-number) @@ -96,14 +96,27 @@ (%make-definition-source-location namestring tlf-number form-number))) (defun make-file-info-namestring (name file-info) - (let* ((untruename (file-info-untruename file-info)) - (dir (and untruename (pathname-directory untruename)))) + (let* ((pathname (file-info-pathname file-info)) + (dir (and pathname (pathname-directory pathname)))) (if (and dir (eq (first dir) :absolute)) - (namestring untruename) + (namestring pathname) (if name (namestring name) nil)))) +#+sb-source-locations +(progn + (define-source-transform source-location () + (make-definition-source-location)) + ;; We need a regular definition of SOURCE-LOCATION for calls processed + ;; during LOAD on a source file while *EVALUATOR-MODE* is :INTERPRET. + #-sb-xc-host + (defun source-location () + (make-definition-source-location))) + +#-sb-source-locations +(defun source-location () nil) + (in-package "SB-IMPL") (defvar *eval-source-context* nil) diff --git a/src/code/sparc-vm.lisp b/src/code/sparc-vm.lisp index 1035296e03..338456edc0 100644 --- a/src/code/sparc-vm.lisp +++ b/src/code/sparc-vm.lisp @@ -11,39 +11,18 @@ (in-package "SB-VM") ;;; See x86-vm.lisp for a description of this. -#-sb-xc-host (defun machine-type () "Returns a string describing the type of the local machine." "SPARC") - -(defconstant-eqx +fixup-kinds+ #(:call :sethi :add :absolute) #'equalp) -(!with-bigvec-or-sap -(defun fixup-code-object (code offset fixup kind flavor) - (declare (type index offset)) - (declare (ignore flavor)) - (unless (zerop (rem offset sb-assem:+inst-alignment-bytes+)) - (error "Unaligned instruction? offset=#x~X." offset)) - (let ((sap (code-instructions code))) - (ecase kind - (:call - (error "Can't deal with CALL fixups, yet.")) - (:sethi - (setf (ldb (byte 22 0) (sap-ref-32 sap offset)) - (ldb (byte 22 10) fixup))) - (:add - (setf (ldb (byte 10 0) (sap-ref-32 sap offset)) - (ldb (byte 10 0) fixup))) - (:absolute - (setf (sap-ref-32 sap offset) - fixup)))) - nil)) + +(defun return-machine-address (scp) + (+ (context-register scp lip-offset) 8)) ;;;; "Sigcontext" access functions, cut & pasted from alpha-vm.lisp. ;;;; ;;;; See also x86-vm for commentary on signed vs unsigned. -#-sb-xc-host (progn ;;; This is like CONTEXT-REGISTER, but returns the value of a float ;;; register. FORMAT is the type of float to return. @@ -54,13 +33,15 @@ (* long) (context (* os-context-t)) (index int)) -#+nil (defun context-float-register (context index format) (declare (type (alien (* os-context-t)) context)) + (error "context-float-register not working yet? ~S" (list context index format)) + #+nil (coerce (deref (context-float-register-addr context index)) format)) -#+nil (defun %set-context-float-register (context index format new) (declare (type (alien (* os-context-t)) context)) + (error "%set-context-float-register not working yet? ~S" (list context index format new)) + #+nil (setf (deref (context-float-register-addr context index)) (coerce new format))) @@ -87,4 +68,3 @@ (trap-number (sap-ref-8 pc 3))) (declare (type system-area-pointer pc)) (sb-kernel::decode-internal-error-args (sap+ pc 4) trap-number))) -) ; end PROGN diff --git a/src/code/specializable-array.lisp b/src/code/specializable-array.lisp index 1854ceeed8..2cbfd9edb8 100644 --- a/src/code/specializable-array.lisp +++ b/src/code/specializable-array.lisp @@ -52,9 +52,13 @@ ;; Because this is not performance-critical, we can just punt to a function. ;; If no contents given, explicitly 0-fill in case element-type upgrades to T ;; and would get a default of NIL where we would use 0 in our specialization. + +(defvar *array-to-specialization* (make-hash-table :test #'eq)) + (defun sb-xc:make-array (dims &key (element-type 't) (initial-contents nil contentsp) - (initial-element 0)) + (initial-element 0) + (retain-specialization-for-after-xc-core)) ;; ECL fails to compile MAKE-ARRAY when keyword args are not literal keywords. e.g.: ;; (DEFUN TRY (DIMS SELECT VAL) ;; (MAKE-ARRAY DIMS (IF SELECT :INITIAL-CONTENTS :INITIAL-ELEMENT) VAL)) -> @@ -79,15 +83,22 @@ (if contentsp :initial-contents :initial-element) (if contentsp initial-contents initial-element)))) (unless (eq element-type 't) - (setf (gethash array sb-cold::*array-to-specialization*) element-type)) + (setf (gethash array *array-to-specialization*) + (cons element-type retain-specialization-for-after-xc-core))) array)) (defun sb-xc:array-element-type (array) - (cond ((gethash array sb-cold::*array-to-specialization*)) + (cond ((car (gethash array *array-to-specialization*))) ((bit-vector-p array) 'bit) ((stringp array) 'base-char) (t t))) (defun target-specialized-array-p (array) - (gethash array sb-cold::*array-to-specialization*)) + (if (gethash array *array-to-specialization*) t nil)) (deftype sb-xc:simple-vector () '(and cl:simple-vector (not (satisfies target-specialized-array-p)))) + +(defun sb-cold::clear-specialized-array-registry () + (let ((registry *array-to-specialization*)) + (maphash (lambda (key value) + (unless (cdr value) (remhash key registry))) ; cdr = "retain" + registry))) diff --git a/src/code/step.lisp b/src/code/step.lisp index c051dab93c..9509ce7cfe 100644 --- a/src/code/step.lisp +++ b/src/code/step.lisp @@ -13,7 +13,7 @@ ;;;; signalling forms into code compiled at high debug settings, and ;;;; having a handler for them at the toplevel. -(in-package "SB-IMPL") ; in warm SBCL +(in-package "SB-IMPL") (defun step-form (form args) (restart-case diff --git a/src/code/stream.lisp b/src/code/stream.lisp index d6118c6746..91bfae5e85 100644 --- a/src/code/stream.lisp +++ b/src/code/stream.lisp @@ -90,19 +90,6 @@ ;;; stream manipulation functions -(defstruct (broadcast-stream (:include ansi-stream - (out #'broadcast-out) - (bout #'broadcast-bout) - (sout #'broadcast-sout) - (misc #'broadcast-misc)) - (:constructor %make-broadcast-stream - (streams)) - (:copier nil) - (:predicate nil)) - ;; a list of all the streams we broadcast to - (streams () :type list :read-only t)) -(declaim (freeze-type broadcast-stream)) - (defun maybe-resolve-synonym-stream (stream) (labels ((recur (stream) (if (synonym-stream-p stream) @@ -117,8 +104,7 @@ (maybe-resolve-synonym-stream result) result))) -(defun ansi-stream-input-stream-p (stream) - (declare (type ansi-stream stream)) +(defmethod input-stream-p ((stream ansi-stream)) (if (synonym-stream-p stream) (input-stream-p (resolve-synonym-stream stream)) (and (not (eq (ansi-stream-in stream) #'closed-flame)) @@ -129,60 +115,36 @@ (or (not (eq (ansi-stream-in stream) #'ill-in)) (not (eq (ansi-stream-bin stream) #'ill-bin)))))) -;;; Temporary definition that gets overwritten by pcl/gray-streams -(defun input-stream-p (stream) - (declare (type stream stream)) - (and (ansi-stream-p stream) - (ansi-stream-input-stream-p stream))) - -(defun ansi-stream-output-stream-p (stream) - (declare (type ansi-stream stream)) +(defmethod output-stream-p ((stream ansi-stream)) (if (synonym-stream-p stream) (output-stream-p (resolve-synonym-stream stream)) (and (not (eq (ansi-stream-in stream) #'closed-flame)) (or (not (eq (ansi-stream-out stream) #'ill-out)) (not (eq (ansi-stream-bout stream) #'ill-bout)))))) -;;; Temporary definition that gets overwritten by pcl/gray-streams -(defun output-stream-p (stream) - (declare (type stream stream)) - (and (ansi-stream-p stream) - (ansi-stream-output-stream-p stream))) - -(declaim (inline ansi-stream-open-stream-p)) -(defun ansi-stream-open-stream-p (stream) - (declare (type ansi-stream stream)) - ;; CLHS 22.1.4 lets us not worry about synonym streams here. - (not (eq (ansi-stream-in stream) #'closed-flame))) - -(defun open-stream-p (stream) - (ansi-stream-open-stream-p stream)) +(defmethod open-stream-p ((stream ansi-stream)) + ;; CLHS 21.1.4 lets us not worry about synonym streams here. + (let ((in (ansi-stream-in stream))) + (not (or (eq in (load-time-value #'closed-flame t)) + (eq in (load-time-value #'closed-flame-saved t)))))) -(declaim (inline ansi-stream-element-type)) -(defun ansi-stream-element-type (stream) - (declare (type ansi-stream stream)) - (funcall (ansi-stream-misc stream) stream :element-type)) - -(defun stream-element-type (stream) - (ansi-stream-element-type stream)) +(defmethod stream-element-type ((stream ansi-stream)) + (call-ansi-stream-misc stream :element-type)) (defun stream-external-format (stream) - (funcall (ansi-stream-misc stream) stream :external-format)) + (stream-api-dispatch (stream) + :simple (s-%stream-external-format stream) + :gray (error "~S is not defined for ~S" 'stream-external-format stream) + :native (call-ansi-stream-misc stream :external-format))) -(defun interactive-stream-p (stream) - (declare (type stream stream)) - (funcall (ansi-stream-misc stream) stream :interactive-p)) +(defmethod interactive-stream-p ((stream ansi-stream)) + (call-ansi-stream-misc stream :interactive-p)) -(declaim (inline ansi-stream-close)) -(defun ansi-stream-close (stream abort) - (declare (type ansi-stream stream)) - (when (ansi-stream-open-stream-p stream) - (funcall (ansi-stream-misc stream) stream :close abort)) +(defmethod close ((stream ansi-stream) &key abort) + (unless (eq (ansi-stream-in stream) #'closed-flame) + (call-ansi-stream-misc stream :close abort)) t) -(defun close (stream &key abort) - (ansi-stream-close stream abort)) - (defun set-closed-flame (stream) (setf (ansi-stream-in stream) #'closed-flame) (setf (ansi-stream-bin stream) #'closed-flame) @@ -205,25 +167,20 @@ (defun external-format-char-size (external-format) (ef-char-size (get-external-format external-format))) -;;; Call the MISC method with the :FILE-POSITION operation. -#-sb-fluid (declaim (inline ansi-stream-file-position)) -(defun ansi-stream-file-position (stream position) +;;; Call the MISC method with the :GET-FILE-POSITION operation. +(declaim (inline !ansi-stream-ftell)) ; named for the stdio inquiry function +(defun !ansi-stream-ftell (stream) (declare (type stream stream)) - (declare (type (or index (alien sb-unix:unix-offset) (member nil :start :end)) - position)) ;; FIXME: It would be good to comment on the stuff that is done here... ;; FIXME: This doesn't look interrupt safe. - (cond - (position - (setf (ansi-stream-in-index stream) +ansi-stream-in-buffer-length+) - (funcall (ansi-stream-misc stream) stream :file-position position)) - (t - (let ((res (funcall (ansi-stream-misc stream) stream :file-position nil))) - (when res + (let ((res (call-ansi-stream-misc stream :get-file-position)) + (delta (- +ansi-stream-in-buffer-length+ + (ansi-stream-in-index stream)))) + (if (eql delta 0) + res + (when res #-sb-unicode - (- res - (- +ansi-stream-in-buffer-length+ - (ansi-stream-in-index stream))) + (- res delta) #+sb-unicode (let ((char-size (if (fd-stream-p stream) (fd-stream-char-size stream) @@ -236,17 +193,54 @@ for i from start below +ansi-stream-in-buffer-length+ sum (funcall char-size (aref buffer i)))) (fixnum - (* char-size - (- +ansi-stream-in-buffer-length+ - (ansi-stream-in-index stream)))))))))))) - -(defun file-position (stream &optional position) - (if (ansi-stream-p stream) - (ansi-stream-file-position stream position) - (let ((result (stream-file-position stream position))) - (if (numberp result) - result - (and result t))))) + (* char-size delta))))))))) + +;;; You're not allowed to specify NIL for the position but we were permitting +;;; it, which made it impossible to test for a bad call that tries to assign +;;; the position, versus a inquiry for the current position. +;;; CLHS specifies: file-position stream position-spec => success-p +;;; and position-spec is a "file position designator" which precludes NIL +;;; but the implementation methods can't detect supplied vs unsupplied. +;;; What a fubar API at the CL: layer. Was #'(SETF FILE-POSITION) not invented? +(defun file-position (stream &optional (position 0 suppliedp)) + (if suppliedp + ;; Setter + (let ((arg (the (or index (alien sb-unix:unix-offset) (member :start :end)) + position))) + (stream-api-dispatch (stream) + :native (progn + (setf (ansi-stream-in-index stream) +ansi-stream-in-buffer-length+) + (call-ansi-stream-misc stream :set-file-position arg)) + ;; The impl method is expected to return a success indication as + ;; a generalized boolean. + :simple (s-%file-position stream arg) + ;; I think our fndb entry is overconstrained - it says that this returns + ;; either unsigned-byte or strict boolean, however CLHS says that setting + ;; FILE-POSITION returns a /generalized boolean/. + ;; A stream-specific method should be allowed to convey more information + ;; than T/NIL yet we are forced to discard that information, + ;; lest the return value constraint on this be violated. + :gray (let ((result (stream-file-position stream arg))) + (if (numberp result) result (and result t))))) + ;; Getter + (let ((result (stream-api-dispatch (stream) + :native (!ansi-stream-ftell stream) + :simple (s-%file-position stream nil) + :gray (stream-file-position stream)))) + (the (or unsigned-byte null) result)))) + +(defmethod stream-file-position ((stream ansi-stream) &optional position) + ;; Excuse me for asking, but why is this even a thing? + ;; Users are not supposed to call the stream implementation directly, + ;; they're supposed to call the function in the CL: package + ;; which indirects to this. But if they do ... make it work. + ;; And note that inlining of !ansi-stream-file-position would be pointless, + ;; it's nearly 1K of code. + ;; Oh, this is srsly wtf now. If POSITION is NIL, + ;; then you must not call FILE-POSITION with both arguments. + (if position + (file-position stream position) + (file-position stream))) ;;; This is a literal translation of the ANSI glossary entry "stream ;;; associated with a file". @@ -289,7 +283,10 @@ stream))) (defun file-string-length (stream object) - (funcall (ansi-stream-misc stream) stream :file-string-length object)) + (stream-api-dispatch (stream) + :gray (declare (ignore stream)) + :simple (s-%file-string-length stream object) + :native (call-ansi-stream-misc stream :file-string-length object))) ;;;; input functions @@ -334,60 +331,73 @@ (progn (done-with-fast-read-char) (eof-or-lose stream eof-error-p (values eof-value t)))))))) -#-sb-fluid (declaim (inline ansi-stream-read-line)) -(defun ansi-stream-read-line (stream eof-error-p eof-value recursive-p) - (declare (ignore recursive-p)) +;; to potentially avoid consing a bufer on sucessive calls to read-line +;; (just consing the result string) +(define-load-time-global *read-line-buffers* nil) +(declaim (list *read-line-buffers*)) + +(declaim (inline ansi-stream-read-line)) +(defun ansi-stream-read-line (stream eof-error-p eof-value) (if (ansi-stream-cin-buffer stream) ;; Stream has a fast-read-char buffer. Copy large chunks directly ;; out of the buffer. (ansi-stream-read-line-from-frc-buffer stream eof-error-p eof-value) ;; Slow path, character by character. - (prepare-for-fast-read-char stream - (let ((res (make-string 80)) - (len 80) - (index 0)) - (loop - (let ((ch (fast-read-char nil nil))) - (cond (ch - (when (char= ch #\newline) - (done-with-fast-read-char) - (return (values (%shrink-vector res index) nil))) + ;; There is no need to use PREPARE-FOR-FAST-READ-CHAR + ;; because the CIN-BUFER is known to be NIL. + (let ((ch (funcall (ansi-stream-in stream) stream nil 0))) + (case ch + (#\newline (values "" nil)) + (0 (values (eof-or-lose stream eof-error-p eof-value) t)) + (t + (let* ((buffer (or (atomic-pop *read-line-buffers*) + (make-string 128))) + (res buffer) + (len (length res)) + (eof) + (index 0)) + (declare (type (simple-array character (*)) buffer)) + (declare (optimize (sb-c:insert-array-bounds-checks 0))) + (declare (index index)) + (setf (schar res index) (truly-the character ch)) + (incf index) + (loop (case (setq ch (funcall (ansi-stream-in stream) stream nil 0)) + (#\newline (return)) + (0 (return (setq eof t))) + (t (when (= index len) (setq len (* len 2)) (let ((new (make-string len))) (replace new res) (setq res new))) - (setf (schar res index) ch) - (incf index)) - ((zerop index) - (done-with-fast-read-char) - (return (values (eof-or-lose stream - eof-error-p - eof-value) - t))) - ;; Since FAST-READ-CHAR already hit the eof char, we - ;; shouldn't do another READ-CHAR. - (t - (done-with-fast-read-char) - (return (values (%shrink-vector res index) t)))))))))) + (setf (schar res index) (truly-the character ch)) + (incf index)))) + (if (eq res buffer) + (setq res (subseq buffer 0 index)) + (%shrink-vector res index)) + ;; Do not push an enlarged buffer, only the original one. + (atomic-push buffer *read-line-buffers*) + (values res eof))))))) (defun read-line (&optional (stream *standard-input*) (eof-error-p t) eof-value recursive-p) (declare (explicit-check)) - (let ((stream (in-stream-from-designator stream))) - (if (ansi-stream-p stream) - (ansi-stream-read-line stream eof-error-p eof-value recursive-p) - ;; must be Gray streams FUNDAMENTAL-STREAM + (declare (ignore recursive-p)) + (stream-api-dispatch (stream (in-stream-from-designator stream)) + :simple (s-%read-line stream eof-error-p eof-value) + :native (ansi-stream-read-line stream eof-error-p eof-value) + :gray (multiple-value-bind (string eof) (stream-read-line stream) (if (and eof (zerop (length string))) (values (eof-or-lose stream eof-error-p eof-value) t) - (values string eof)))))) + (values string eof))))) -;;; We proclaim them INLINE here, then proclaim them NOTINLINE later on, -;;; so, except in this file, they are not inline by default, but they can be. -#-sb-fluid (declaim (inline read-char unread-char read-byte listen)) +;;; We proclaim them INLINE here, then proclaim them MAYBE-INLINE +;;; later on, so, except in this file, they are not inline by default, +;;; but they can be. +(declaim (inline read-char unread-char read-byte)) -#-sb-fluid (declaim (inline ansi-stream-read-char)) +(declaim (inline ansi-stream-read-char)) (defun ansi-stream-read-char (stream eof-error-p eof-value recursive-p) (declare (ignore recursive-p)) (prepare-for-fast-read-char stream @@ -400,16 +410,20 @@ eof-value recursive-p) (declare (explicit-check)) - (let ((stream (in-stream-from-designator stream))) - (if (ansi-stream-p stream) - (ansi-stream-read-char stream eof-error-p eof-value recursive-p) - ;; must be Gray streams FUNDAMENTAL-STREAM + (stream-api-dispatch (stream (in-stream-from-designator stream)) + :native (ansi-stream-read-char stream eof-error-p eof-value recursive-p) + ;; The final T is BLOCKING-P. I removed the ignored recursive-p arg. + :simple (let ((char (s-%read-char stream eof-error-p eof-value t))) + (if (eq char eof-value) + char + (the character char))) + :gray (let ((char (stream-read-char stream))) (if (eq char :eof) (eof-or-lose stream eof-error-p eof-value) - (the character char)))))) + (the character char))))) -#-sb-fluid (declaim (inline ansi-stream-unread-char)) +(declaim (inline ansi-stream-unread-char)) (defun ansi-stream-unread-char (character stream) (let ((index (1- (ansi-stream-in-index stream))) (buffer (ansi-stream-cin-buffer stream))) @@ -423,39 +437,39 @@ (when (ansi-stream-input-char-pos stream) (decf (ansi-stream-input-char-pos stream)))) (t - (funcall (ansi-stream-misc stream) stream - :unread character))))) + (call-ansi-stream-misc stream :unread character))))) (defun unread-char (character &optional (stream *standard-input*)) (declare (explicit-check)) - (let ((stream (in-stream-from-designator stream))) - (if (ansi-stream-p stream) - (ansi-stream-unread-char character stream) - ;; must be Gray streams FUNDAMENTAL-STREAM - (stream-unread-char stream character))) + (stream-api-dispatch (stream (in-stream-from-designator stream)) + :simple (s-%unread-char stream character) + :native (ansi-stream-unread-char character stream) + :gray (stream-unread-char stream character)) nil) -#-sb-fluid (declaim (inline ansi-stream-listen)) -(defun ansi-stream-listen (stream) +(declaim (inline %ansi-stream-listen)) +(defun %ansi-stream-listen (stream) (or (/= (the fixnum (ansi-stream-in-index stream)) +ansi-stream-in-buffer-length+) - ;; Handle :EOF return from misc methods specially - (let ((result (funcall (ansi-stream-misc stream) stream :listen))) - (if (eq result :eof) - nil - result)))) + (call-ansi-stream-misc stream :listen))) + +(declaim (inline ansi-stream-listen)) +(defun ansi-stream-listen (stream) + (let ((result (%ansi-stream-listen stream))) + (if (eq result :eof) + nil + result))) (defun listen (&optional (stream *standard-input*)) (declare (explicit-check)) - (let ((stream (in-stream-from-designator stream))) - (if (ansi-stream-p stream) - (ansi-stream-listen stream) - ;; Fall through to Gray streams FUNDAMENTAL-STREAM case. - (stream-listen stream)))) + (stream-api-dispatch (stream (in-stream-from-designator stream)) + :simple (error "Unimplemented") ; gets redefined + :native (ansi-stream-listen stream) + :gray (stream-listen stream))) -#-sb-fluid (declaim (inline ansi-stream-read-char-no-hang)) +(declaim (inline ansi-stream-read-char-no-hang)) (defun ansi-stream-read-char-no-hang (stream eof-error-p eof-value recursive-p) - (if (funcall (ansi-stream-misc stream) stream :listen) + (if (%ansi-stream-listen stream) ;; On T or :EOF get READ-CHAR to do the work. (ansi-stream-read-char stream eof-error-p eof-value recursive-p) nil)) @@ -465,31 +479,33 @@ eof-value recursive-p) (declare (explicit-check)) - (let ((stream (in-stream-from-designator stream))) - (if (ansi-stream-p stream) + (stream-api-dispatch (stream (in-stream-from-designator stream)) + :native (ansi-stream-read-char-no-hang stream eof-error-p eof-value recursive-p) - ;; must be Gray streams FUNDAMENTAL-STREAM + ;; Absence of EOF-OR-LOSE here looks a little suspicious + ;; considering that the impl function didn't use recursive-p + :simple (s-%read-char-no-hang stream eof-error-p eof-value) + :gray (let ((char (stream-read-char-no-hang stream))) (if (eq char :eof) (eof-or-lose stream eof-error-p eof-value) - (the (or character null) char)))))) + (the (or character null) char))))) -#-sb-fluid (declaim (inline ansi-stream-clear-input)) +(declaim (inline ansi-stream-clear-input)) (defun ansi-stream-clear-input (stream) (setf (ansi-stream-in-index stream) +ansi-stream-in-buffer-length+) - (funcall (ansi-stream-misc stream) stream :clear-input)) + (call-ansi-stream-misc stream :clear-input)) (defun clear-input (&optional (stream *standard-input*)) (declare (explicit-check)) - (let ((stream (in-stream-from-designator stream))) - (if (ansi-stream-p stream) - (ansi-stream-clear-input stream) - ;; must be Gray streams FUNDAMENTAL-STREAM - (stream-clear-input stream))) + (stream-api-dispatch (stream (in-stream-from-designator stream)) + :simple (error "Unimplemented") ; gets redefined + :native (ansi-stream-clear-input stream) + :gray (stream-clear-input stream)) nil) -#-sb-fluid (declaim (inline ansi-stream-read-byte)) +(declaim (inline ansi-stream-read-byte)) (defun ansi-stream-read-byte (stream eof-error-p eof-value recursive-p) ;; Why the "recursive-p" parameter? a-s-r-b is funcall'ed from ;; a-s-read-sequence and needs a lambda list that's congruent with @@ -500,9 +516,13 @@ (defun read-byte (stream &optional (eof-error-p t) eof-value) (declare (explicit-check)) - (if (ansi-stream-p stream) - (ansi-stream-read-byte stream eof-error-p eof-value nil) - ;; must be Gray streams FUNDAMENTAL-STREAM + (stream-api-dispatch (stream) + :native (ansi-stream-read-byte stream eof-error-p eof-value nil) + :simple (let ((byte (s-%read-byte stream eof-error-p eof-value))) + (if (eq byte eof-value) + byte + (the integer byte))) + :gray (let ((byte (stream-read-byte stream))) (if (eq byte :eof) (eof-or-lose stream eof-error-p eof-value) @@ -518,7 +538,7 @@ ;;; some cases, but it wasn't being used in SBCL, so it was dropped. ;;; If we ever need it, it could be added later as a new variant N-BIN ;;; method (perhaps N-BIN-ASAP?) or something. -#-sb-fluid (declaim (inline read-n-bytes)) +(declaim (inline read-n-bytes)) (defun read-n-bytes (stream buffer start numbytes &optional (eof-error-p t)) (if (ansi-stream-p stream) (ansi-stream-read-n-bytes stream buffer start numbytes eof-error-p) @@ -532,44 +552,25 @@ (declare (type ansi-stream stream) (type index numbytes start) (type (or (simple-array * (*)) system-area-pointer) buffer)) - (let* ((in-buffer (ansi-stream-in-buffer stream)) - (index (ansi-stream-in-index stream)) - (num-buffered (- +ansi-stream-in-buffer-length+ index))) - (declare (fixnum index num-buffered)) - (cond - ((not in-buffer) - (funcall (ansi-stream-n-bin stream) - stream - buffer - start - numbytes - eof-error-p)) - ((<= numbytes num-buffered) - #+nil - (let ((copy-function (typecase buffer - ((simple-array * (*)) #'ub8-bash-copy) - (system-area-pointer #'copy-ub8-to-system-area)))) - (funcall copy-function in-buffer index buffer start numbytes)) - (%byte-blt in-buffer index - buffer start (+ start numbytes)) - (setf (ansi-stream-in-index stream) (+ index numbytes)) - numbytes) - (t - (let ((end (+ start num-buffered))) - #+nil - (let ((copy-function (typecase buffer - ((simple-array * (*)) #'ub8-bash-copy) - (system-area-pointer #'copy-ub8-to-system-area)))) - (funcall copy-function in-buffer index buffer start num-buffered)) - (%byte-blt in-buffer index buffer start end) - (setf (ansi-stream-in-index stream) +ansi-stream-in-buffer-length+) - (+ (funcall (ansi-stream-n-bin stream) - stream - buffer - end - (- numbytes num-buffered) - eof-error-p) - num-buffered)))))) + (let ((in-buffer (ansi-stream-in-buffer stream))) + (unless in-buffer + (return-from ansi-stream-read-n-bytes + (funcall (ansi-stream-n-bin stream) stream buffer start numbytes eof-error-p))) + (let* ((index (ansi-stream-in-index stream)) + (num-buffered (- +ansi-stream-in-buffer-length+ index))) + ;; These bytes are of course actual bytes, i.e. 8-bit octets + ;; and not variable-length bytes. + (cond ((<= numbytes num-buffered) + (%byte-blt in-buffer index buffer start (+ start numbytes)) + (setf (ansi-stream-in-index stream) (+ index numbytes)) + numbytes) + (t + (let ((end (+ start num-buffered))) + (%byte-blt in-buffer index buffer start end) + (setf (ansi-stream-in-index stream) +ansi-stream-in-buffer-length+) + (+ (funcall (ansi-stream-n-bin stream) stream buffer + end (- numbytes num-buffered) eof-error-p) + num-buffered))))))) ;;; the amount of space we leave at the start of the in-buffer for ;;; unreading @@ -672,153 +673,160 @@ (defun write-char (character &optional (stream *standard-output*)) (declare (explicit-check)) - (with-out-stream stream (ansi-stream-out character) - (stream-write-char character)) + (stream-api-dispatch (stream (out-stream-from-designator stream)) + :native (funcall (ansi-stream-out stream) stream character) + :simple (s-%write-char stream character) + :gray (stream-write-char stream character)) character) (defun terpri (&optional (stream *standard-output*)) (declare (explicit-check)) - (with-out-stream stream (ansi-stream-out #\newline) (stream-terpri)) + (stream-api-dispatch (stream (out-stream-from-designator stream)) + :native (funcall (ansi-stream-out stream) stream #\Newline) + :simple (s-%terpri stream) + :gray (stream-terpri stream)) nil) -#-sb-fluid (declaim (inline ansi-stream-fresh-line)) -(defun ansi-stream-fresh-line (stream) - (unless (eql (charpos stream) 0) - (funcall (ansi-stream-out stream) stream #\newline) - t)) - (defun fresh-line (&optional (stream *standard-output*)) (declare (explicit-check)) - (let ((stream (out-stream-from-designator stream))) - (if (ansi-stream-p stream) - (ansi-stream-fresh-line stream) - ;; must be Gray streams FUNDAMENTAL-STREAM - (stream-fresh-line stream)))) - -#-sb-fluid (declaim (inline ansi-stream-write-string)) -(defun ansi-stream-write-string (string stream start end) - (with-array-data ((data string) (offset-start start) - (offset-end end) - :check-fill-pointer t) - (funcall (ansi-stream-sout stream) - stream data offset-start offset-end))) - -(defun %write-string (string stream start end) - (let ((stream (out-stream-from-designator stream))) - (if (ansi-stream-p stream) - (ansi-stream-write-string string stream start end) - ;; must be Gray streams FUNDAMENTAL-STREAM - (stream-write-string stream string start end))) - string) + (stream-api-dispatch (stream (out-stream-from-designator stream)) + :native (unless (eql (charpos stream) 0) + (funcall (ansi-stream-out stream) stream #\newline) + t) + :simple (s-%fresh-line stream) + :gray (stream-fresh-line stream))) + +(macrolet + ((define (name) + `(defun ,name (string stream start end) + (with-array-data ((data string) (start start) (end end) :check-fill-pointer t) + (stream-api-dispatch (stream) + :native (progn (funcall (ansi-stream-sout stream) stream data start end) + ,@(when (eq name '%write-line) + '((funcall (ansi-stream-out stream) stream #\newline)))) + :simple (,(symbolicate "S-" name) stream data start end) + :gray (progn (stream-write-string stream data start end) + ,@(when (eq name '%write-line) + '((stream-write-char stream #\newline)))))) + string))) + (define %write-line) + (define %write-string)) (defun write-string (string &optional (stream *standard-output*) &key (start 0) end) - (declare (type string string)) - (declare (type stream-designator stream)) (declare (explicit-check)) - (%write-string string stream start end)) + (%write-string string (out-stream-from-designator stream) start end)) (defun write-line (string &optional (stream *standard-output*) &key (start 0) end) - (declare (type string string)) - (declare (type stream-designator stream)) (declare (explicit-check)) - (let ((stream (out-stream-from-designator stream))) - (cond ((ansi-stream-p stream) - (ansi-stream-write-string string stream start end) - (funcall (ansi-stream-out stream) stream #\newline)) - (t - (stream-write-string stream string start end) - (stream-write-char stream #\newline)))) - string) + (%write-line string (out-stream-from-designator stream) start end)) (defun charpos (&optional (stream *standard-output*)) - (with-out-stream stream (ansi-stream-misc :charpos) (stream-line-column))) + (stream-api-dispatch (stream (out-stream-from-designator stream)) + :native (call-ansi-stream-misc stream :charpos) + :simple (s-%charpos stream) + :gray (stream-line-column stream))) (defun line-length (&optional (stream *standard-output*)) - (with-out-stream stream (ansi-stream-misc :line-length) - (stream-line-length))) + (stream-api-dispatch (stream (out-stream-from-designator stream)) + :native (call-ansi-stream-misc stream :line-length) + :simple (s-%line-length stream) + :gray (stream-line-length stream))) (defun finish-output (&optional (stream *standard-output*)) (declare (explicit-check)) - (with-out-stream stream (ansi-stream-misc :finish-output) - (stream-finish-output)) + (stream-api-dispatch (stream (out-stream-from-designator stream)) + :native (call-ansi-stream-misc stream :finish-output) + :simple (s-%finish-output stream) + :gray (stream-finish-output stream)) nil) (defun force-output (&optional (stream *standard-output*)) (declare (explicit-check)) - (with-out-stream stream (ansi-stream-misc :force-output) - (stream-force-output)) + (stream-api-dispatch (stream (out-stream-from-designator stream)) + :native (call-ansi-stream-misc stream :force-output) + :simple (s-%force-output stream) + :gray (stream-force-output stream)) nil) (defun clear-output (&optional (stream *standard-output*)) (declare (explicit-check)) - (with-out-stream stream (ansi-stream-misc :clear-output) - (stream-clear-output)) + (stream-api-dispatch (stream (out-stream-from-designator stream)) + :native (call-ansi-stream-misc stream :clear-output) + :simple (s-%clear-output stream) + :gray (stream-clear-output stream)) nil) (defun write-byte (integer stream) (declare (explicit-check)) ;; The STREAM argument is not allowed to be a designator. - (%with-out-stream stream (ansi-stream-bout integer) (stream-write-byte integer)) + (stream-api-dispatch (stream) + :native (funcall (ansi-stream-bout stream) stream integer) + :simple (s-%write-byte stream integer) + :gray (stream-write-byte stream integer)) integer) -;;; Meta: the following comment is mostly true, but gray stream support -;;; is already incorporated into the definitions within this file. -;;; But these need to redefinable, otherwise the relative order of -;;; loading sb-simple-streams and any user-defined code which executes -;;; (F #'read-char ...) is sensitive to the order in which those -;;; are loaded, though insensitive at compile-time. -;;; (These were inline throughout this file, but that's not appropriate -;;; globally. And we must not inline them in the rest of this file if -;;; dispatch to gray or simple streams is to work, since both redefine -;;; these functions later.) -(declaim (notinline read-char unread-char read-byte listen)) +(declaim (maybe-inline read-char unread-char read-byte)) ; too big ;;; This is called from ANSI-STREAM routines that encapsulate CLOS ;;; streams to handle the misc routines and dispatch to the ;;; appropriate SIMPLE- or FUNDAMENTAL-STREAM functions. -(defun stream-misc-dispatch (stream operation &optional arg1 arg2) - (declare (type stream stream) (ignore arg2)) - (ecase operation - (:listen - ;; Return T if input available, :EOF for end-of-file, otherwise NIL. - (let ((char (read-char-no-hang stream nil :eof))) - (when (characterp char) - (unread-char char stream)) - char)) - (:unread - (unread-char arg1 stream)) - (:close - (close stream)) - (:clear-input - (clear-input stream)) - (:force-output - (force-output stream)) - (:finish-output - (finish-output stream)) - (:clear-output - (clear-output stream)) - (:element-type - (stream-element-type stream)) - (:element-mode - (stream-element-type-stream-element-mode - (stream-element-type stream))) - (:stream-external-format - (stream-external-format stream)) - (:interactive-p - (interactive-stream-p stream)) - (:line-length - (line-length stream)) - (:charpos - (charpos stream)) - (:file-length - (file-length stream)) - (:file-string-length - (file-string-length stream arg1)) - (:file-position - (file-position stream arg1)))) +(defun stream-misc-dispatch (stream operation arg) + (if (simple-stream-p stream) + + ;; Dispatch to a simple-stream implementation function + (stream-misc-case (operation) + (:listen (listen stream)) ; call the redefined LISTEN + (:unread (s-%unread-char stream arg)) + (:close (error "Attempted to close inner stream ~S" stream)) + (:clear-input (clear-input stream)) ; call the redefined CLEAR-INPUT + (:force-output (s-%force-output stream)) + (:finish-output (s-%finish-output stream)) + (:clear-output (s-%clear-output stream)) + ;; All simple-streams use (UNSIGNED-BYTE 8) - it's one of the + ;; salient distinctions between simple-streams and Gray streams. + ;; See (DEFMETHOD STREAM-ELEMENT-TYPE ((STREAM SIMPLE-STREAM)) ...) + (:element-type '(unsigned-byte 8)) + ;; FIXME: All simple-streams are actually bivalent. We historically have + ;; returned UNSIGNED-BYTE based on element-type. But this is wrong! + (:element-mode 'UNSIGNED-BYTE) + ;; This call returns an instance of the format structure defined + ;; by the SB-SIMPLE-STREAMS package, not the SB-IMPL:: structure. + ;; This also needs to be fixed. + (:external-format (s-%stream-external-format stream)) + (:interactive-p (interactive-stream-p stream)) + (:line-length (s-%line-length stream)) + (:charpos (s-%charpos stream)) + (:file-length (s-%file-length stream)) + (:file-string-length (s-%file-string-length stream arg)) + (:set-file-position (s-%file-position stream arg)) + ;; yeesh, this wants a _required_ NIL argument to mean "inquire". + (:get-file-position (s-%file-position stream nil))) + + ;; else call the generic function + (stream-misc-case (operation) + (:listen (stream-listen stream)) + (:unread (stream-unread-char stream arg)) ; specialized arg first + (:close (error "Attempted to close inner stream ~S" stream)) + (:clear-input (stream-clear-input stream)) + (:force-output (stream-force-output stream)) + (:finish-output (stream-finish-output stream)) + (:clear-output (stream-clear-output stream)) + (:element-type (stream-element-type stream)) + (:element-mode + (stream-element-type-stream-element-mode (stream-element-type stream))) + (:interactive-p (interactive-stream-p stream)) ; is generic + (:line-length (stream-line-length stream)) + (:charpos (stream-line-column stream)) + (:set-file-position (stream-file-position stream arg)) + (:get-file-position (stream-file-position stream)) + ;; This last bunch of pseudo-methods will probably just signal an error + ;; since they aren't generic and don't work on Gray streams. + (:external-format (stream-external-format stream)) + (:file-length (file-length stream)) + (:file-string-length (file-string-length stream arg))))) (declaim (inline stream-element-mode)) (defun stream-element-mode (stream) @@ -827,7 +835,7 @@ ((fd-stream-p stream) (fd-stream-element-mode stream)) ((and (ansi-stream-p stream) - (funcall (ansi-stream-misc stream) stream :element-mode))) + (call-ansi-stream-misc stream :element-mode))) (t (stream-element-type-stream-element-mode (stream-element-type stream))))) @@ -835,26 +843,23 @@ ;;;; broadcast streams (defun make-broadcast-stream (&rest streams) - (unless streams - (return-from make-broadcast-stream - (load-time-value (let ((out (lambda (stream arg) - (declare (ignore stream arg) - (optimize speed (safety 0))))) - (sout (lambda (stream string start end) - (declare (ignore stream string start end) - (optimize speed (safety 0))))) - (stream (%make-broadcast-stream nil))) - (setf (broadcast-stream-out stream) out - (broadcast-stream-bout stream) out - (broadcast-stream-sout stream) sout) - stream) - t))) (dolist (stream streams) (unless (output-stream-p stream) (error 'type-error :datum stream :expected-type '(satisfies output-stream-p)))) - (%make-broadcast-stream streams)) + (let ((stream (%make-broadcast-stream streams))) + (unless streams + (flet ((out (stream arg) + (declare (ignore stream arg) + (optimize speed (safety 0)))) + (sout (stream string start end) + (declare (ignore stream string start end) + (optimize speed (safety 0))))) + (setf (broadcast-stream-out stream) #'out + (broadcast-stream-bout stream) #'out + (broadcast-stream-sout stream) #'sout))) + stream)) (macrolet ((out-fun (name fun &rest args) `(defun ,name (stream ,@args) @@ -864,9 +869,9 @@ (out-fun broadcast-bout write-byte byte) (out-fun broadcast-sout %write-string string start end)) -(defun broadcast-misc (stream operation &optional arg1 arg2) +(defun broadcast-misc (stream operation arg1) (let ((streams (broadcast-stream-streams stream))) - (case operation + (stream-misc-case (operation) ;; FIXME: This may not be the best place to note this, but I ;; think the :CHARPOS protocol needs revision. Firstly, I think ;; this is the last place where a NULL return value was possible @@ -907,31 +912,32 @@ (if last (file-length (car last)) 0))) - (:file-position - (if arg1 + (:set-file-position (let ((res (or (eql arg1 :start) (eql arg1 0)))) (dolist (stream streams res) - (setq res (file-position stream arg1)))) + (setq res (file-position stream arg1))))) + (:get-file-position (let ((last (last streams))) (if last (file-position (car last)) - 0)))) + 0))) (:file-string-length (let ((last (last streams))) (if last (file-string-length (car last) arg1) 1))) (:close - (when (broadcast-stream-streams stream) - (set-closed-flame stream))) + ;; I don't know how something is trying to close the + ;; universal sink stream, but it is. Stop it from happening. + (unless (eq stream *null-broadcast-stream*) + (set-closed-flame stream))) (t (let ((res nil)) (dolist (stream streams res) (setq res (if (ansi-stream-p stream) - (funcall (ansi-stream-misc stream) stream operation - arg1 arg2) - (stream-misc-dispatch stream operation arg1 arg2))))))))) + (call-ansi-stream-misc stream operation arg1) + (stream-misc-dispatch stream operation arg1))))))))) ;;;; synonym streams @@ -962,22 +968,33 @@ (in-fun synonym-bin read-byte eof-error-p eof-value) (in-fun synonym-n-bin read-n-bytes buffer start numbytes eof-error-p)) -(defun synonym-misc (stream operation &optional arg1 arg2) +(defun synonym-misc (stream operation arg1) (declare (optimize (safety 1))) - (let ((syn (symbol-value (synonym-stream-symbol stream)))) - (if (ansi-stream-p syn) + ;; CLHS 21.1.4 implies that CLOSE on a synonym stream closes the synonym stream in that + ;; "The consequences are undefined if the synonym stream symbol is not bound to an open + ;; stream from the time of the synonym stream's creation until the time it is closed." + ;; The antecent of this "it" is the synonym stream --------------^ + ;; which means that there exist a way to close synonym streams. + ;; We can presume that CLOSE is that way, despite some text seemingly to the contrary + ;; "Any operations on a synonym stream will be performed on the stream that is then + ;; the value of the dynamic variable named by the synonym stream symbol." + ;; so "any" in that sentence mean "almost any, with a notable exception". + (stream-misc-case (operation) + (:close + (set-closed-flame stream)) + (t + (let ((syn (symbol-value (synonym-stream-symbol stream)))) + (if (ansi-stream-p syn) ;; We have to special-case some operations which interact with ;; the in-buffer of the wrapped stream, since just calling ;; ANSI-STREAM-MISC on them - (case operation - (:listen (or (/= (the fixnum (ansi-stream-in-index syn)) - +ansi-stream-in-buffer-length+) - (funcall (ansi-stream-misc syn) syn :listen))) + (stream-misc-case (operation) + (:listen (%ansi-stream-listen syn)) (:clear-input (clear-input syn)) (:unread (unread-char arg1 syn)) (t - (funcall (ansi-stream-misc syn) syn operation arg1 arg2))) - (stream-misc-dispatch syn operation arg1 arg2)))) + (call-ansi-stream-misc syn operation arg1))) + (stream-misc-dispatch syn operation arg1)))))) ;;;; two-way streams @@ -996,7 +1013,12 @@ (input-stream (missing-arg) :type stream :read-only t) (output-stream (missing-arg) :type stream :read-only t)) -(defprinter (two-way-stream) input-stream output-stream) +(defmethod print-object ((x two-way-stream) stream) + (print-unreadable-object (x stream :type t :identity t) + (format stream + ":INPUT-STREAM ~S :OUTPUT-STREAM ~S" + (two-way-stream-input-stream x) + (two-way-stream-output-stream x)))) (defun make-two-way-stream (input-stream output-stream) "Return a bidirectional stream which gets its input from INPUT-STREAM and @@ -1026,22 +1048,20 @@ (in-fun two-way-bin read-byte eof-error-p eof-value) (in-fun two-way-n-bin read-n-bytes buffer start numbytes eof-error-p)) -(defun two-way-misc (stream operation &optional arg1 arg2) +(defun two-way-misc (stream operation arg1) (let* ((in (two-way-stream-input-stream stream)) (out (two-way-stream-output-stream stream)) (in-ansi-stream-p (ansi-stream-p in)) (out-ansi-stream-p (ansi-stream-p out))) - (case operation + (stream-misc-case (operation) (:listen (if in-ansi-stream-p - (or (/= (the fixnum (ansi-stream-in-index in)) - +ansi-stream-in-buffer-length+) - (funcall (ansi-stream-misc in) in :listen)) + (%ansi-stream-listen in) (listen in))) ((:finish-output :force-output :clear-output) (if out-ansi-stream-p - (funcall (ansi-stream-misc out) out operation arg1 arg2) - (stream-misc-dispatch out operation arg1 arg2))) + (call-ansi-stream-misc out operation arg1) + (stream-misc-dispatch out operation arg1))) (:clear-input (clear-input in)) (:unread (unread-char arg1 in)) (:element-type @@ -1059,11 +1079,11 @@ (set-closed-flame stream)) (t (or (if in-ansi-stream-p - (funcall (ansi-stream-misc in) in operation arg1 arg2) - (stream-misc-dispatch in operation arg1 arg2)) + (call-ansi-stream-misc in operation arg1) + (stream-misc-dispatch in operation arg1)) (if out-ansi-stream-p - (funcall (ansi-stream-misc out) out operation arg1 arg2) - (stream-misc-dispatch out operation arg1 arg2))))))) + (call-ansi-stream-misc out operation arg1) + (stream-misc-dispatch out operation arg1))))))) ;;;; concatenated streams @@ -1126,18 +1146,17 @@ (when (zerop remaining-bytes) (return numbytes))) (setf (concatenated-stream-streams stream) (cdr streams)))) -(defun concatenated-misc (stream operation &optional arg1 arg2) +(defun concatenated-misc (stream operation arg1) (let* ((left (concatenated-stream-streams stream)) (current (car left))) - (case operation + (stream-misc-case (operation) (:listen (unless left (return-from concatenated-misc :eof)) (loop (let ((stuff (if (ansi-stream-p current) - (funcall (ansi-stream-misc current) current - :listen) - (stream-misc-dispatch current :listen)))) + (%ansi-stream-listen current) + (stream-misc-dispatch current operation arg1)))) (cond ((eq stuff :eof) ;; Advance STREAMS, and try again. (pop (concatenated-stream-streams stream)) @@ -1159,8 +1178,8 @@ (t (when left (if (ansi-stream-p current) - (funcall (ansi-stream-misc current) current operation arg1 arg2) - (stream-misc-dispatch current operation arg1 arg2))))))) + (call-ansi-stream-misc current operation arg1) + (stream-misc-dispatch current operation arg1))))))) ;;;; echo streams @@ -1236,16 +1255,16 @@ start numbytes nil)) (cond ((not eof-error-p) - (write-sequence buffer (echo-stream-output-stream stream) - :start start :end (+ start bytes-read)) + (write-seq-impl buffer (echo-stream-output-stream stream) + start (+ start bytes-read)) bytes-read) ((> numbytes bytes-read) - (write-sequence buffer (echo-stream-output-stream stream) - :start start :end (+ start bytes-read)) + (write-seq-impl buffer (echo-stream-output-stream stream) + start (+ start bytes-read)) (error 'end-of-file :stream stream)) (t - (write-sequence buffer (echo-stream-output-stream stream) - :start start :end (+ start bytes-read)) + (write-seq-impl buffer (echo-stream-output-stream stream) + start (+ start bytes-read)) (aver (= numbytes (+ start bytes-read))) numbytes)))) @@ -1266,21 +1285,20 @@ (declaim (freeze-type string-input-stream)) -(defun string-in-misc (stream operation &optional arg1 arg2) - (declare (type string-input-stream stream) - (ignore arg2)) - (case operation - (:file-position - (if arg1 +(defun string-in-misc (stream operation arg1) + (declare (type string-input-stream stream)) + (stream-misc-case (operation :default nil) + (:set-file-position (setf (string-input-stream-index stream) (case arg1 (:start (string-input-stream-start stream)) (:end (string-input-stream-limit stream)) ;; We allow moving position beyond EOF. Errors happen ;; on read, not move. - (t (+ (string-input-stream-start stream) arg1)))) + (t (+ (string-input-stream-start stream) arg1))))) + (:get-file-position (- (string-input-stream-index stream) - (string-input-stream-start stream)))) + (string-input-stream-start stream))) ;; According to ANSI: "Should signal an error of type type-error ;; if stream is not a stream associated with a file." ;; This is checked by FILE-LENGTH, so no need to do it here either. @@ -1300,14 +1318,13 @@ ;;; of WITH-INPUT-FROM-STRING, and we lack a way to perform partial inline ;;; dx allocation of structures, this'll have to do. (defun %init-string-input-stream (stream string &optional (start 0) end) - (declare (string string)) - (setf (%instance-layout (truly-the instance stream)) - #.(find-layout 'string-input-stream)) + (declare (explicit-check string)) (macrolet ((initforms () - `(setf - ,@(mapcan (lambda (dsd) - (list `(%instance-ref stream ,(dsd-index dsd)) - (case (dsd-name dsd) + `(progn + ,@(mapcar (lambda (dsd) + ;; good thing we have no raw slots in stream structures + `(%instance-set stream ,(dsd-index dsd) + ,(case (dsd-name dsd) ((index start) 'start) (limit 'end) (string 'simple-string) @@ -1326,31 +1343,25 @@ (t (setf (string-input-stream-index stream) (1+ index)) (char string index)))))) - (flet ((base-char-in (stream eof-error-p eof-value) - (declare (optimize (sb-c::verify-arg-count 0) - (sb-c::insert-array-bounds-checks 0))) - (char-in base-char)) - (character-in (stream eof-error-p eof-value) - (declare (optimize (sb-c::verify-arg-count 0) - (sb-c::insert-array-bounds-checks 0))) - (char-in character)) - (nil-in (stream eof-error-p eof-value) - (if (>= (string-input-stream-index stream) - (string-input-stream-limit stream)) - (eof-or-lose stream eof-error-p eof-value) - (error "Attempt to read from stream with NIL element type")))) - (let ((input-routine - (typecase string - #+sb-unicode (sb-kernel::character-string #'character-in) - (base-string #'base-char-in) - (t #'nil-in)))) - (with-array-data ((simple-string string :offset-var offset) - (start start) - (end end) - :check-fill-pointer t) - (initforms) - (values (truly-the string-input-stream stream) - offset)))))) + (flet ((base-char-in (stream eof-error-p eof-value) + (declare (optimize (sb-c::verify-arg-count 0) + (sb-c:insert-array-bounds-checks 0))) + (char-in base-char)) + (character-in (stream eof-error-p eof-value) + (declare (optimize (sb-c::verify-arg-count 0) + (sb-c:insert-array-bounds-checks 0))) + (char-in character))) + (let ((input-routine + (etypecase string + (base-string #'base-char-in) + (string #'character-in)))) + (with-array-data ((simple-string string :offset-var offset) + (start start) + (end end) + :check-fill-pointer t) + (initforms) + (values (truly-the string-input-stream stream) + offset)))))) ;;; It's debatable whether we should try to convert ;;; (let ((s (make-string-input-stream))) (declare (dynamic-extent s)) ...) @@ -1358,9 +1369,11 @@ (defun make-string-input-stream (string &optional (start 0) end) "Return an input stream which will supply the characters of STRING between START and END in order." - (macrolet ((nwords () (dd-length (find-defstruct-description 'string-input-stream)))) + (macrolet ((make () `(%make-structure-instance + ,(find-defstruct-description 'string-input-stream) + nil))) ;; kill the secondary value - (values (%init-string-input-stream (%make-instance (nwords)) string start end)))) + (values (%init-string-input-stream (make) string start end)))) ;;;; STRING-OUTPUT-STREAM stuff ;;;; @@ -1369,147 +1382,144 @@ ;;;; corrupt the heap here, it certainly is possible to end up with ;;;; a string-output-stream whose internal state is messed up. ;;;; -(defconstant +string-output-stream-buffer-initial-size+ 64) +(defun %init-string-output-stream (stream buffer wild-result-type) + (declare (optimize speed (sb-c::verify-arg-count 0))) + (declare (string buffer) + (ignorable wild-result-type)) ; if #-sb-unicode + (macrolet ((initforms () + `(progn + ,@(mapcar (lambda (dsd) + `(%instance-set stream ,(dsd-index dsd) + ,(case (dsd-name dsd) + (sout '#'string-sout) ; global fun + (misc '#'misc) ; local fun + ((element-type unicode-p out sout-aux buffer) + (dsd-name dsd)) + (t (dsd-default dsd))))) + (dd-slots + (find-defstruct-description 'string-output-stream))))) + (cout (elt-type) + `(let ((pointer (string-output-stream-pointer + (truly-the string-output-stream stream))) + (buffer (truly-the (simple-array ,elt-type (*)) + (string-output-stream-buffer stream))) + (index (string-output-stream-index stream))) + (declare (optimize (sb-c:insert-array-bounds-checks 0))) + (when (= pointer (length buffer)) + ;; The usual doubling technique: the new buffer shall hold as many + ;; characters as were already emplaced. + (setf buffer (string-output-stream-new-buffer stream index) + pointer 0)) + (setf (aref (truly-the (simple-array ,elt-type (*)) buffer) pointer) + char + (string-output-stream-pointer stream) (1+ pointer)) + (setf (string-output-stream-index stream) (1+ index)))) + (sout (elt-type) + ;; Only one case cares whether the string contains non-base chars. + ;; base-string source and buffer : OK + ;; base-string source, character-string buffer : OK + ;; character-string source, base-string buf verifies base-char on copy + ;; character-string source + buf needs a pre-scan for Unicode. + `(etypecase src + #+sb-unicode + (simple-character-string + ,@(when (eq elt-type 'character) + ;; When UNICODE-P is NIL, meaning no non-base chars were seen yet + ;; in the input, pre-scan to see whether that still holds. + '((when (and (not (string-output-stream-unicode-p + (truly-the string-output-stream stream))) + (input-contains-unicode)) + (setf (string-output-stream-unicode-p stream) t + ;; no need to keep checking each character + (ansi-stream-out stream) #'character-out)))) + ;; There are transforms for all the necessary REPLACE variations. + (replace (truly-the (simple-array ,elt-type (*)) dst) + (truly-the simple-character-string src) + :start1 start1 :start2 start2 :end2 end2)) + (simple-base-string + (replace (truly-the (simple-array ,elt-type (*)) dst) + (truly-the simple-base-string src) + :start1 start1 :start2 start2 :end2 end2)))) + (input-contains-unicode () + ;; For streams with :DEFAULT element-type (producing the most space-efficient + ;; string that can hold the output), checking whether Unicode characters appear + ;; in the source material is potentially advantageous versus checking the + ;; buffer in GET-OUTPUT-STREAM-STRING, because if all source strings are + ;; BASE-STRING, we needn't check anything. + ;; Bounds check was already performed + `(let ((s (truly-the simple-character-string src))) + (declare (optimize (sb-c:insert-array-bounds-checks 0))) + (loop for i from start2 below end2 + thereis (>= (char-code (aref s i)) base-char-code-limit))))) + ;; The "wonderful" thing is you never know where type checks have already been done. + ;; Is CHAR a character for sure? I have no idea. And how about the indices in SOUT? + (labels ((base-char-out (stream char) + (cout base-char)) + (character-out (stream char) + (cout character)) + (default-out (stream char) + (when (>= (char-code char) base-char-code-limit) + (setf (string-output-stream-unicode-p stream) t + ;; no need to keep checking each character + (ansi-stream-out stream) #'character-out)) + (cout character)) + (base-string-out (stream dst src start1 start2 end2) + (declare (ignorable stream) (index start1 start2 end2)) + (sout base-char)) + (char-string-out (stream dst src start1 start2 end2) + (declare (ignorable stream) (index start1 start2 end2)) + (sout character)) + (reject (&rest args) + (declare (ignore args)) + (error "Stream can not accept characters")) + (misc (stream operation arg1) + ;; Intercept the misc handler to reset the Unicode state + ;; (since the char handlers are local functions). + ;; Technically this should be among the actions performed on :CLEAR-OUTPUT, + ;; which would also include *actually* clearing the output. But we don't. + (stream-misc-case (operation) + (:reset-unicode-p + (setf (string-output-stream-unicode-p stream) nil + ;; resume checking for Unicode characters + (ansi-stream-out stream) #'default-out)) + (t + (string-out-misc stream operation arg1))))) + (multiple-value-bind (element-type unicode-p out sout-aux) + (case (%other-pointer-widetag buffer) + #+sb-unicode + (#.sb-vm:simple-character-string-widetag + (if wild-result-type + (values :default nil #'default-out #'char-string-out) + (values 'character t #'character-out #'char-string-out))) + (#.sb-vm:simple-base-string-widetag + (values 'base-char :ignore #'base-char-out #'base-string-out)) + (t + (values nil :ignore #'reject #'reject))) + (initforms) + (truly-the string-output-stream stream))))) + +;;; Constructors used by the transform of MAKE-STRING-OUTPUT-STREAM, +;;; avoiding parsing of the specified element-type at runtime. +(defun %make-base-string-ostream () + (%init-string-output-stream (%allocate-string-ostream) + (make-array 63 :element-type 'base-char) ; 2w + 64b + nil)) +(defun %make-character-string-ostream () + (%init-string-output-stream (%allocate-string-ostream) + (make-array 32 :element-type 'character) ; 2w + 128b + nil)) -(defstruct (string-output-stream - (:include ansi-stream - (sout #'string-sout) - (misc #'string-out-misc)) - (:constructor nil) - (:copier nil) - (:predicate nil)) - ;; Function to perform a piece of the SOUT operation - (sout-aux nil :type (sfunction (t t t t t) t) :read-only t) - ;; The string we throw stuff in. - (buffer nil :type (or simple-base-string simple-character-string)) - ;; Whether any non-base character has been written. - ;; BASE-STRING-OUTPUT-STREAM initializes this to :IGNORE - ;; which prevents SOUT from doing unnecessary work. - (unicode-p :ignore) - ;; Chains of buffers to use - (prev nil :type list) - (next nil :type list) - ;; Index of the next location to use in the current string. - (pointer 0 :type index) - ;; Global location in the stream - (index 0 :type index) - ;; Index cache: when we move backwards we save the greater of this - ;; and index here, so the greater of index and this is always the - ;; end of the stream. - (index-cache 0 :type index) - ;; Pseudo-actual element type. We no longer store the as-requested type. - ;; (If the value is :DEFAULT, we return CHARACTER on inquiry.) - (element-type nil :read-only t - :type (member #+sb-unicode :default - #+sb-unicode character - base-char nil))) - -;;; NB: BASE-STRING-OUTPUT-STREAM means a string-output-stream that holds BASE-CHAR. -;;; It is not the "ancestral type" of output streams. That's just STRING-OUTPUT-STREAM. -;;; -;;; This is not the only way to implement a more space-efficient string stream. -;;; One other possibility would be to have only one type of stream that buffers -;;; octets and uses UTF-8 encoding. But depending on how FILE-POSITION is supposed -;;; to work (if it is) for setting the position, using a variable-length encoding -;;; may not be a wise choice. -(defmacro def-string-stream (et kind) - ;; DEFSTRUCTs aren't so happy when buried in a macrolet, - ;; especially if we want to inline the constructor to stack-allocate the thing. - (let ((obj-type (symbolicate kind "-STRING-OSTREAM")) - (buf-type `(simple-array ,et (*))) - (ouch-fun (symbolicate kind "-STRING-OUCH"))) - `(progn - (defstruct (,obj-type - (:include string-output-stream - (buffer (make-string +string-output-stream-buffer-initial-size+ - :element-type ',et) - :type ,buf-type) - (out #',ouch-fun) - (sout-aux #',(symbolicate kind "-STRING-SOUT"))) - ,@(case et - (base-char - ;; BASE-STRING stream can create an output string - ;; of type (VECTOR NIL) - whether we need to or not, - ;; which seems somewhat in dispute - by supplying an - ;; element-type of NIL to the constructor. - `((:constructor %make-base-string-ostream - (&optional (element-type 'base-char))))) - (character - `((:constructor %make-default-string-ostream - (&aux (element-type :default) (unicode-p nil) - (out #'default-string-ouch))) - (:constructor %make-character-string-ostream - (&aux (element-type 'character) (unicode-p t)))))) - ;; Don't want a distinct family of accessors - (:conc-name string-output-stream-) - (:copier nil) - (:predicate nil))) - - (declaim (freeze-type ,obj-type)) - - ;; For CHARACTER stream, we define two OUCH functions, one which checks - ;; per each character whether it is above the range of base-char, - ;; setting UNICODE-P if true, and one which doesn't check. - ;; The checking version is used when the stream element type is :DEFAULT, - ;; which means that we want to try to return a BASE-STRING if possible. - ,@(flet ((define-char-out-fun (name initially) - `(defun ,name (stream char) - (declare (,et char)) - ,@initially - (let ((pointer (string-output-stream-pointer stream)) - (buffer (truly-the ,buf-type - (string-output-stream-buffer stream))) - (index (string-output-stream-index stream))) - (when (= pointer (length buffer)) - (setf buffer (string-output-stream-new-buffer stream index) - pointer 0)) - (setf (aref buffer pointer) char - (string-output-stream-pointer stream) (1+ pointer)) - (setf (string-output-stream-index stream) (1+ index)))))) - - (list - (when (eq et 'character) - (define-char-out-fun - 'default-string-ouch - '((when (>= (char-code char) base-char-code-limit) - (setf (string-output-stream-unicode-p stream) t - ;; no need to keep checking each character - (ansi-stream-out stream) #'character-string-ouch))))) - (define-char-out-fun ouch-fun nil))) - - ;; Define some helper functions for the STRING-SOUT method to handle - ;; all combinations of {base,character} source and destination string. - ;; REPLACE transforms (see src/compiler/seqtran) can handle those 4 cases - ;; efficiently, utilizing a bit-bash copier for same-sized copies, - ;; otherwise an inlined loop. The one case that needs to type-check each - ;; character copied is a Unicode source string into a stream of base-char, - ;; which may signal OBJECT-NOT-BASE-CHAR-ERROR. - (defun ,(symbolicate kind "-STRING-SOUT") (dst src start1 start2 end2) - (declare (index start1 start2 end2) (optimize speed)) - (macrolet ((copy (dst-type src-type) - `(replace (truly-the ,dst-type dst) - (truly-the ,src-type src) - :start1 start1 :start2 start2 :end2 end2))) - (etypecase src - #+sb-unicode (simple-character-string - (copy ,buf-type simple-character-string)) - (simple-base-string (copy ,buf-type simple-base-string)))))))) - -;; Define two stream types and 2 helper functions for copying strings -;; into the stream buffer for purposes of WRITE-STRING. -;; For non-unicode, only define BASE-STRING-OUTPUT-STREAM and 1 helper. -#+sb-unicode (def-string-stream character character) -(def-string-stream base-char base) - -(declaim (freeze-type string-output-stream)) (defun make-string-output-stream (&key (element-type 'character)) "Return an output stream which will accumulate all output given it for the benefit of the function GET-OUTPUT-STREAM-STRING." (declare (explicit-check)) + ;; No point in optimizing for unsupplied ELEMENT-TYPE. + ;; Compiler transforms into %MAKE-CHARACTER-STRING-OSTREAM. (let ((ctype (specifier-type element-type))) - (cond ((csubtypep ctype (specifier-type 'base-char)) - (%make-base-string-ostream (if (eq ctype *empty-type*) nil 'base-char))) - #+sb-unicode + (cond ((and (csubtypep ctype (specifier-type 'base-char)) + ;; Let NIL mean "default", i.e. CHARACTER + (neq ctype *empty-type*)) + (%make-base-string-ostream)) ((csubtypep ctype (specifier-type 'character)) (%make-character-string-ostream)) (t @@ -1587,29 +1597,6 @@ benefit of the function GET-OUTPUT-STREAM-STRING." (defun string-sout (stream string start end) (declare (explicit-check string) (type index start end)) - (case (%other-pointer-widetag string) - #+sb-unicode - (#.sb-vm:simple-character-string-widetag - ;; For streams with :DEFAULT element-type (producing the most space-efficient - ;; string that can hold the output), checking whether Unicode characters appear - ;; in the source material is potentially advantageous versus checking the - ;; buffer in GET-OUTPUT-STREAM-STRING, because if all source strings are - ;; BASE-STRING, we needn't check anything. - ;; When UNICODE-P is NIL, then we care whether Unicode characters - ;; would be written, changing the flag to T. If non-nil, skip this. - (unless (string-output-stream-unicode-p stream) - ;; Bounds check was already performed by ANSI-STREAM-WRITE-STRING - (locally - (declare (optimize (sb-c::insert-array-bounds-checks 0))) - (let ((s (truly-the simple-character-string string))) - (when (loop for i from start below end - thereis (>= (char-code (aref s i)) base-char-code-limit)) - (setf (string-output-stream-unicode-p stream) t - ;; no need to keep checking each character - (ansi-stream-out stream) #'character-string-ouch)))))) - (#.sb-vm:simple-array-nil-widetag - (return-from string-sout ; fail if the span is nonempty - (if (> end start) (aref string start))))) (let* ((full-length (- end start)) (length full-length) (buffer (string-output-stream-buffer stream)) @@ -1624,11 +1611,16 @@ benefit of the function GET-OUTPUT-STREAM-STRING." :more (when (plusp here) (funcall (string-output-stream-sout-aux stream) - buffer string pointer start stop) + stream buffer string pointer start stop) (setf (string-output-stream-pointer stream) (+ here pointer))) (when (plusp overflow) (setf start stop length (- end start) + ;; BUG: doesn't always enlarge as intended. Consider: + ;; - initial buffer capacity of 63 characters + ;; - WRITE-STRING with 2 characters setting INDEX=2, SPACE=61 + ;; - another WRITE-STRING with 62 characters. 61 copied, 1 overflow. + ;; - then new BUFFER length is (MAX OVERFLOW INDEX) = 2 buffer (string-output-stream-new-buffer stream (max overflow (string-output-stream-index stream))) pointer 0 @@ -1642,6 +1634,7 @@ benefit of the function GET-OUTPUT-STREAM-STRING." (incf (string-output-stream-index stream) full-length))) ;;; Factored out of the -misc method due to size. +;;; This is a steaming pile of horsecrap (lp#1839040) (defun set-string-output-stream-file-position (stream pos) (let* ((index (string-output-stream-index stream)) (end (max index (string-output-stream-index-cache stream)))) @@ -1685,10 +1678,9 @@ benefit of the function GET-OUTPUT-STREAM-STRING." (setf (string-output-stream-pointer stream) (+ size diff) (string-output-stream-index stream) pos)))))))) -(defun string-out-misc (stream operation &optional arg1 arg2) - (declare (ignore arg2)) +(defun string-out-misc (stream operation arg1) (declare (optimize speed)) - (case operation + (stream-misc-case (operation :default nil) (:charpos ;; Keeping this first is a silly micro-optimization: FRESH-LINE ;; makes this the most common one. @@ -1713,10 +1705,10 @@ benefit of the function GET-OUTPUT-STREAM-STRING." pointer (length buffer)) (/noshow0 "/string-out-misc charpos next") (go :next)))) - (:file-position - (/noshow0 "/string-out-misc file-position") - (when arg1 - (set-string-output-stream-file-position stream arg1)) + (:set-file-position + (set-string-output-stream-file-position stream arg1) + t) ; just claim it worked, who cares (see lp#1839040) + (:get-file-position (string-output-stream-index stream)) (:close (/noshow0 "/string-out-misc close") @@ -1731,9 +1723,6 @@ benefit of the function GET-OUTPUT-STREAM-STRING." ;;; MAKE-STRING-OUTPUT-STREAM since the last call to this function. (defun get-output-stream-string (stream) (declare (type string-output-stream stream)) - (when (eq (string-output-stream-element-type stream) nil) - (return-from get-output-stream-string - (load-time-value (make-array 0 :element-type nil) t))) (let* ((length (max (string-output-stream-index stream) (string-output-stream-index-cache stream))) (prev (nreverse (string-output-stream-prev stream))) @@ -1759,12 +1748,9 @@ benefit of the function GET-OUTPUT-STREAM-STRING." (string-output-stream-next stream) nil) ;; Reset UNICODE-P unless it was :IGNORE or element-type is CHARACTER. - #+sb-unicode (when (and (eq (string-output-stream-element-type stream) :default) (eq (string-output-stream-unicode-p stream) t)) - (setf (string-output-stream-unicode-p stream) nil - ;; resume checking for Unicode characters - (ansi-stream-out stream) #'default-string-ouch)) + (call-ansi-stream-misc stream :reset-unicode-p)) ;; There are exactly 3 cases that we have to deal with when copying: ;; CHARACTER-STRING into BASE-STRING (without type-checking per character) @@ -1775,16 +1761,18 @@ benefit of the function GET-OUTPUT-STREAM-STRING." ;; The first case occurs when and only when the element type is :DEFAULT and ;; only base characters were written. The other two cases can be handled ;; using BYTE-BLT with indices multiplied by either 1 or 4. - (flet ((copy (fun) + (flet ((copy (fun extra) (let ((start 0)) ; index into RESULT (declare (index start)) (dolist (buffer prev) - (funcall fun buffer start) + ;; It doesn't look as though we should have to pass RESULT + ;; in to FUN to avoid closure consing, but indeed we do. + (funcall fun result buffer start extra) (incf start (length buffer))) - (funcall fun this start) + (funcall fun result this start extra) (incf start (length this)) (dolist (buffer next) - (funcall fun buffer start) + (funcall fun result buffer start extra) (incf start (length buffer)))))) (if (and (eq (string-output-stream-element-type stream) :default) base-string-p) @@ -1792,28 +1780,32 @@ benefit of the function GET-OUTPUT-STREAM-STRING." ;; PRINx-TO-STRING, (FORMAT NIL ...), and many other constructs. ;; REPLACE will elide the type test per compilation policy ;; which is fine because we've already checked that it'll work. - (copy (lambda (source start) + (copy (lambda (result source start dummy) (declare (optimize speed (sb-c::type-check 0))) + (declare (ignore dummy)) (replace (the simple-base-string result) (the simple-character-string source) - :start1 start))) - (let ((scale (if base-string-p 0 2))) - (with-pinned-objects (result) + :start1 start)) + 0) + (with-pinned-objects (result) ;; BYTE-BLT doesn't know that it could use memcpy rather then memmove, ;; but it nonetheless should be faster than REPLACE. - (copy (lambda (source start) + (copy (lambda (result source start scale) + (declare (index start)) (let* ((length (min (- (length result) start) (length source))) (end (+ start length))) + (declare (index length end)) (with-pinned-objects (source) (%byte-blt (vector-sap source) 0 (vector-sap result) - (truly-the index (ash (the index start) scale)) - (truly-the index (ash (the index end) scale))))))))))) + (truly-the index (ash start scale)) + (truly-the index (ash end scale)))))) + (if base-string-p 0 2))))) result)) (defun finite-base-string-ouch (stream character) - (declare (optimize (sb-c::insert-array-bounds-checks 0))) + (declare (optimize (sb-c:insert-array-bounds-checks 0))) (let ((pointer (finite-base-string-output-stream-pointer stream)) (buffer (finite-base-string-output-stream-buffer stream))) (cond ((= pointer (length buffer)) @@ -1824,7 +1816,7 @@ benefit of the function GET-OUTPUT-STREAM-STRING." (truly-the index (1+ pointer))))))) (defun finite-base-string-sout (stream string start end) - (declare (optimize (sb-c::insert-array-bounds-checks 0))) + (declare (optimize (sb-c:insert-array-bounds-checks 0))) (let* ((pointer (finite-base-string-output-stream-pointer stream)) (buffer (finite-base-string-output-stream-buffer stream)) (length (- end start)) @@ -1840,8 +1832,8 @@ benefit of the function GET-OUTPUT-STREAM-STRING." :start1 pointer :start2 start :end2 end))) (setf (finite-base-string-output-stream-pointer stream) new-pointer))) -(defun finite-base-string-out-misc (stream operation &optional arg1 arg2) - (declare (ignore stream operation arg1 arg2)) +(defun finite-base-string-out-misc (stream operation arg1) + (declare (ignore stream operation arg1)) (error "finite-base-string-out-misc needs an implementation")) ;;;; fill-pointer streams @@ -1878,15 +1870,36 @@ benefit of the function GET-OUTPUT-STREAM-STRING." (out #'fill-pointer-ouch) (sout #'fill-pointer-sout) (misc #'fill-pointer-misc)) - (:constructor make-fill-pointer-output-stream (string)) + (:constructor nil) (:copier nil) (:predicate nil)) ;; a string with a fill pointer where we stuff the stuff we write (string (missing-arg) :type string-with-fill-pointer :read-only t)) (declaim (freeze-type fill-pointer-output-stream)) +;;; TODO: specialize on string type? +(defun %init-fill-pointer-output-stream (stream string element-type) + (declare (optimize speed (sb-c::verify-arg-count 0))) + (declare (ignore element-type)) + (unless (and (stringp string) + (array-has-fill-pointer-p string)) + (error "~S is not a string with a fill-pointer" string)) + (macrolet ((initforms () + `(progn ,@(mapcar (lambda (dsd) + `(%instance-set stream ,(dsd-index dsd) + ,(case (dsd-name dsd) + (string 'string) + (t (dsd-default dsd))))) + (dd-slots + (find-defstruct-description 'fill-pointer-output-stream)))))) + (initforms) + (truly-the fill-pointer-output-stream stream))) (defun fill-pointer-ouch (stream character) + ;; FIXME: ridiculously inefficient. Can we throw some TRULY-THEs in here? + ;; I think the prohibition against touching the string - implying that you can't + ;; decide to re-displace it - means we should be able to just look at the + ;; underlying vector, at least until we run out of space in it. (let* ((buffer (fill-pointer-output-stream-string stream)) (current (fill-pointer buffer)) (current+1 (1+ current))) @@ -1944,12 +1957,10 @@ benefit of the function GET-OUTPUT-STREAM-STRING." :start1 offset-current :start2 start :end2 end))) dst-end))) -(defun fill-pointer-misc (stream operation &optional arg1 arg2) - (declare (ignore arg2)) - (case operation - (:file-position - (let ((buffer (fill-pointer-output-stream-string stream))) - (if arg1 +(defun fill-pointer-misc (stream operation arg1 + &aux (buffer (fill-pointer-output-stream-string stream))) + (stream-misc-case (operation :default nil) + (:set-file-position (setf (fill-pointer buffer) (case arg1 (:start 0) @@ -1964,11 +1975,11 @@ benefit of the function GET-OUTPUT-STREAM-STRING." (error "Cannot move FILE-POSITION beyond the end ~ of WITH-OUTPUT-TO-STRING stream ~ constructed with non-adjustable string."))) - arg1))) - (fill-pointer buffer)))) + arg1)))) + (:get-file-position + (fill-pointer buffer)) (:charpos - (let* ((buffer (fill-pointer-output-stream-string stream)) - (current (fill-pointer buffer))) + (let ((current (fill-pointer buffer))) (with-array-data ((string buffer) (start) (end current)) (declare (simple-string string)) (let ((found (position #\newline string :test #'char= @@ -2027,7 +2038,7 @@ benefit of the function GET-OUTPUT-STREAM-STRING." #'case-frob-capitalize-first-sout))) (%make-case-frob-stream target out sout)))) -(defun case-frob-misc (stream op &optional arg1 arg2) +(defun case-frob-misc (stream op arg1) (declare (type case-frob-stream stream)) (case op (:close @@ -2036,9 +2047,13 @@ benefit of the function GET-OUTPUT-STREAM-STRING." (t (let ((target (case-frob-stream-target stream))) (if (ansi-stream-p target) - (funcall (ansi-stream-misc target) target op arg1 arg2) - (stream-misc-dispatch target op arg1 arg2)))))) + (call-ansi-stream-misc target op arg1) + (stream-misc-dispatch target op arg1)))))) +;;; FIXME: formatted output into a simple-stream is currently hampered +;;; by the fact that case-frob streams assume that the stream is either ANSI +;;; or Gray. Probably the easiest fix would be to define STREAM-WRITE-CHAR +;;; and STREAM-WRITE-STRING on simple-stream. (defun case-frob-upcase-out (stream char) (declare (type case-frob-stream stream) (type character char)) @@ -2276,12 +2291,12 @@ benefit of the function GET-OUTPUT-STREAM-STRING." (type index start) (type sequence-end end) (values index)) - (if (ansi-stream-p stream) - (ansi-stream-read-sequence seq stream start end) - ;; must be Gray streams FUNDAMENTAL-STREAM - (stream-read-sequence stream seq start end))) + (stream-api-dispatch (stream) + :simple (error "Unimplemented") ; gets redefined + :native (ansi-stream-read-sequence seq stream start end) + :gray (stream-read-sequence stream seq start end))) -(declaim (inline read-sequence/read-function)) +(declaim (maybe-inline read-sequence/read-function)) (defun read-sequence/read-function (seq stream start %end stream-element-mode character-read-function binary-read-function) @@ -2349,7 +2364,6 @@ benefit of the function GET-OUTPUT-STREAM-STRING." data offset-start offset-end)))) (t (read-generic-sequence (compute-read-function nil))))))) -(declaim (notinline read-sequence/read-function)) (defun ansi-stream-read-sequence (seq stream start %end) (declare (type sequence seq) @@ -2409,18 +2423,11 @@ benefit of the function GET-OUTPUT-STREAM-STRING." (defun write-sequence (seq stream &key (start 0) (end nil)) "Write the elements of SEQ bounded by START and END to STREAM." - (cond ((typep stream 'broadcast-stream) - (let* ((length (length seq)) - (end (or end length))) - (unless (<= start end length) - (sequence-bounding-indices-bad-error seq start end)) - (dolist (s (broadcast-stream-streams stream) seq) - (write-sequence seq s :start start :end end)))) - ((ansi-stream-p stream) - (ansi-stream-write-sequence seq stream start end)) - (t - ;; must be Gray-streams FUNDAMENTAL-STREAM - (stream-write-sequence stream seq start end)))) + (let* ((length (length seq)) + (end (or end length))) + (unless (<= start end length) + (sequence-bounding-indices-bad-error seq start end))) + (write-seq-impl seq stream start end)) ;;; This macro allows sharing code between ;;; WRITE-SEQUENCE/WRITE-FUNCTION and SB-GRAY:STREAM-WRITE-STRING. @@ -2436,7 +2443,7 @@ benefit of the function GET-OUTPUT-STREAM-STRING." (declare (type index i)) (funcall ,write-function ,stream (aref ,seq i)))))) -(declaim (inline write-sequence/write-function)) +(declaim (maybe-inline write-sequence/write-function)) (defun write-sequence/write-function (seq stream start %end stream-element-mode character-write-function @@ -2481,7 +2488,9 @@ benefit of the function GET-OUTPUT-STREAM-STRING." (write-list (compute-write-function nil))) (string (if (ansi-stream-p stream) - (ansi-stream-write-string seq stream start end) + (with-array-data ((data seq) (start start) (end end) + :check-fill-pointer t) + (funcall (ansi-stream-sout stream) stream data start end)) (stream-write-string stream seq start end))) (vector (with-array-data ((data seq) (offset-start start) (offset-end end) @@ -2497,18 +2506,35 @@ benefit of the function GET-OUTPUT-STREAM-STRING." (buffer-output stream data offset-start offset-end))))) (sequence (write-generic-sequence (compute-write-function nil))))))) -(declaim (notinline write-sequence/write-function)) -(defun ansi-stream-write-sequence (seq stream start %end) +;;; This takes any kind of stream, not just ansi streams, because of recursion. +;;; It's basically just the non-keyword-accepting entry for WRITE-SEQUENCE. +(defun write-seq-impl (seq stream start %end) (declare (type sequence seq) - (type ansi-stream stream) + (type stream stream) (type index start) (type sequence-end %end) - (values sequence) (inline write-sequence/write-function)) - (write-sequence/write-function - seq stream start %end (stream-element-mode stream) - (ansi-stream-out stream) (ansi-stream-bout stream)) + (stream-api-dispatch (stream) + :simple (s-%write-sequence stream seq start (or %end (length seq))) + :gray (stream-write-sequence stream seq start %end) + :native + (typecase stream + ;; Don't merely extract one layer of composite stream, because a synonym stream + ;; may redirect to a broadcast stream which wraps a two-way-stream etc etc. + (synonym-stream + (write-seq-impl seq (symbol-value (synonym-stream-symbol stream)) start %end)) + (broadcast-stream + (dolist (s (broadcast-stream-streams stream) seq) + (write-seq-impl seq s start %end))) + (two-way-stream ; handles ECHO-STREAM also + (write-seq-impl seq (two-way-stream-output-stream stream) start %end)) + ;; file, string, pretty, and case-frob streams all fall through to the default, + ;; which has special logic for fd-stream. + (t + (write-sequence/write-function + seq stream start %end (stream-element-mode stream) + (ansi-stream-out stream) (ansi-stream-bout stream))))) seq) ;;; like FILE-POSITION, only using :FILE-LENGTH @@ -2518,9 +2544,14 @@ benefit of the function GET-OUTPUT-STREAM-STRING." ;; aren't according to the glossary). However, the behaviour of ;; FILE-LENGTH for broadcast streams is explicitly described in the ;; BROADCAST-STREAM entry. - (unless (typep stream 'broadcast-stream) - (stream-file-stream-or-lose stream)) - (funcall (ansi-stream-misc stream) stream :file-length)) + (stream-api-dispatch (stream) + :simple (s-%file-length stream) + ;; Perhaps if there were a generic function to obtain the pathname? + :gray (error "~S is not defined for ~S" 'file-length stream) + :native (progn + (unless (typep stream 'broadcast-stream) + (stream-file-stream-or-lose stream)) + (call-ansi-stream-misc stream :file-length)))) ;; Placing this definition (formerly in "toplevel") after the important ;; stream types are known produces smaller+faster code than it did before. @@ -2536,4 +2567,162 @@ benefit of the function GET-OUTPUT-STREAM-STRING." (t stream))) -;;;; etc. +;;; STREAM-ERROR-STREAM is supposed to return a stream even if the +;;; stream has dynamic-extent. While technically a stream, +;;; this object is not actually usable as such - it's only for error reporting. +(defstruct (stub-stream + (:include ansi-stream) + (:constructor %make-stub-stream (direction string))) + (direction nil :read-only t) + (string nil :read-only t)) ; string or nil + +(defun make-stub-stream (underlying-stream) + (multiple-value-bind (direction string) + (etypecase underlying-stream + (string-input-stream + (values :input (string-input-stream-string underlying-stream))) + (string-output-stream + (values :output nil)) + (fill-pointer-output-stream + (values :output (fill-pointer-output-stream-string underlying-stream)))) + (%make-stub-stream direction string))) + +(defmethod print-object ((stub stub-stream) stream) + (print-unreadable-object (stub stream) + (let ((direction (stub-stream-direction stub)) + (string (stub-stream-string stub))) + (format stream "dynamic-extent ~A (unavailable)~@[ ~A ~S~]" + (if (eq direction :input) 'string-input-stream 'string-output-stream) + (if string (if (eq direction :input) "from" "to")) + (if (> (length string) 10) + (concatenate 'string (subseq string 0 8) "...") + string))))) + + +;;;; initialization + +;;; the stream connected to the controlling terminal, or NIL if there is none +(defvar *tty*) + +;;; the stream connected to the standard input (file descriptor 0) +(defvar *stdin*) + +;;; the stream connected to the standard output (file descriptor 1) +(defvar *stdout*) + +;;; the stream connected to the standard error output (file descriptor 2) +(defvar *stderr*) + +;;; This is called when the cold load is first started up, and may also +;;; be called in an attempt to recover from nested errors. +(defun stream-cold-init-or-reset () + (stream-reinit) + (setf *terminal-io* (make-synonym-stream '*tty*)) + (setf *standard-output* (make-synonym-stream '*stdout*)) + (setf *standard-input* (make-synonym-stream '*stdin*)) + (setf *error-output* (make-synonym-stream '*stderr*)) + (setf *query-io* (make-synonym-stream '*terminal-io*)) + (setf *debug-io* *query-io*) + (setf *trace-output* *standard-output*) + (values)) + +(defun stream-deinit () + (setq *tty* nil *stdin* nil *stdout* nil *stderr* nil) + ;; Unbind to make sure we're not accidently dealing with it + ;; before we're ready (or after we think it's been deinitialized). + ;; This uses the internal %MAKUNBOUND because the CL: function would + ;; rightly complain that *AVAILABLE-BUFFERS* is proclaimed always bound. + (%makunbound '*available-buffers*)) + +(defvar *streams-closed-by-slad*) + +(defun restore-fd-streams () + (loop for (stream in bin n-bin out bout sout misc) in *streams-closed-by-slad* + do + (setf (ansi-stream-in stream) in) + (setf (ansi-stream-bin stream) bin) + (setf (ansi-stream-n-bin stream) n-bin) + (setf (ansi-stream-out stream) out) + (setf (ansi-stream-bout stream) bout) + (setf (ansi-stream-sout stream) sout) + (setf (ansi-stream-misc stream) misc))) + +(defun stdstream-external-format (fd) + #-win32 (declare (ignore fd)) + (let* ((keyword (cond #+(and win32 sb-unicode) + ((sb-win32::console-handle-p fd) + :ucs-2) + (t + (default-external-format)))) + (ef (get-external-format keyword)) + (replacement (ef-default-replacement-character ef))) + `(,keyword :replacement ,replacement))) + +;;; This is called whenever a saved core is restarted. +(defun stream-reinit (&optional init-buffers-p) + (when init-buffers-p + ;; Use the internal %BOUNDP for similar reason to that cited above- + ;; BOUNDP on a known global transforms to the constant T. + (aver (not (%boundp '*available-buffers*))) + (setf *available-buffers* nil)) + (%with-output-to-string (*error-output*) + (multiple-value-bind (in out err) + #-win32 (values 0 1 2) + #+win32 (sb-win32::get-std-handles) + (labels (#+win32 + (nul-stream (name inputp outputp) + (let ((nul-handle + (cond + ((and inputp outputp) + (sb-win32:unixlike-open "NUL" sb-unix:o_rdwr)) + (inputp + (sb-win32:unixlike-open "NUL" sb-unix:o_rdonly)) + (outputp + (sb-win32:unixlike-open "NUL" sb-unix:o_wronly)) + (t + ;; Not quite sure what to do in this case. + nil)))) + (make-fd-stream + nul-handle + :name name + :input inputp + :output outputp + :buffering :line + :element-type :default + :serve-events inputp + :auto-close t + :external-format (stdstream-external-format nul-handle)))) + (stdio-stream (handle name inputp outputp) + (cond + #+win32 + ((null handle) + ;; If no actual handle was present, create a stream to NUL + (nul-stream name inputp outputp)) + (t + (make-fd-stream + handle + :name name + :input inputp + :output outputp + :buffering :line + :element-type :default + :serve-events inputp + :external-format (stdstream-external-format handle)))))) + (setf *stdin* (stdio-stream in "standard input" t nil) + *stdout* (stdio-stream out "standard output" nil t) + *stderr* (stdio-stream err "standard error" nil t)))) + #+win32 + (setf *tty* (make-two-way-stream *stdin* *stdout*)) + #-win32 + (let ((tty (sb-unix:unix-open "/dev/tty" sb-unix:o_rdwr #o666))) + (setf *tty* + (if tty + (make-fd-stream tty :name "the terminal" + :input t :output t :buffering :line + :external-format (stdstream-external-format tty) + :serve-events t + :auto-close t) + (make-two-way-stream *stdin* *stdout*)))) + (princ (get-output-stream-string *error-output*) *stderr*)) + (values)) + diff --git a/src/code/string-hash.lisp b/src/code/string-hash.lisp index b3c987ea1e..b1bacf22ee 100644 --- a/src/code/string-hash.lisp +++ b/src/code/string-hash.lisp @@ -53,7 +53,7 @@ (set-result (+ result (ash result 3))) (set-result (logxor result (ash result -11))) (set-result (logxor result (ash result 15))) - (logand result sb-xc:most-positive-fixnum)))) + (logand result most-positive-fixnum)))) ;;; test: ;;; (let ((ht (make-hash-table :test 'equal))) ;;; (do-all-symbols (symbol) @@ -122,10 +122,10 @@ ;; search starting from 2^60*pi. The multiplication should be ;; efficient no matter what the platform thanks to modular ;; arithmetic. - (let* ((mul (logand 3622009729038463111 sb-xc:most-positive-fixnum)) - (xor (logand 608948948376289905 sb-xc:most-positive-fixnum)) - (xy (logand (+ (* x mul) y) sb-xc:most-positive-fixnum))) - (logand (logxor xor xy (ash xy -5)) sb-xc:most-positive-fixnum))) + (let* ((mul (logand 3622009729038463111 most-positive-fixnum)) + (xor (logand 608948948376289905 most-positive-fixnum)) + (xy (logand (+ (* x mul) y) most-positive-fixnum))) + (logand (logxor xor xy (ash xy -5)) most-positive-fixnum))) ;;; Same as above, but don't mask computations to n-positive-fixnum-bits. (declaim (inline word-mix)) @@ -142,24 +142,37 @@ ;;; Please excuse the C-like syle. #-64-bit (progn -(declaim (maybe-inline murmur3-fmix32)) +(declaim (inline murmur3-fmix32)) (defun murmur3-fmix32 (h) - (declare (type (unsigned-byte 32) h)) + (declare (type sb-vm:word h)) (setq h (logxor h (ash h -16))) - (setq h (logand (* h #x85ebca6b) most-positive-word)) + (setq h (logand (* h #x85ebca6b) #.most-positive-word)) (setq h (logxor h (ash h -13))) - (setq h (logand (* h #xc2b2ae35) most-positive-word)) - (logxor h (ash h -16)))) + (setq h (logand (* h #xc2b2ae35) #.most-positive-word)) + (logxor h (ash h -16))) +(defmacro murmur3-fmix-word (x) `(murmur3-fmix32 ,x))) #+64-bit (progn -(declaim (maybe-inline murmur3-fmix64)) +(declaim (inline murmur3-fmix64)) (defun murmur3-fmix64 (k) + (declare (type sb-vm:word k)) (setq k (logxor k (ash k -33))) (setq k (logand (* k #xff51afd7ed558ccd) most-positive-word)) (setq k (logxor k (ash k -33))) (setq k (logand (* k #xc4ceb9fe1a85ec53) most-positive-word)) - (logxor k (ash k -33)))) + (logxor k (ash k -33))) +(defmacro murmur3-fmix-word (x) `(murmur3-fmix64 ,x))) + +(defun murmur-fmix-word (x) + (murmur3-fmix-word (truly-the sb-vm:word x))) +(export 'murmur-fmix-word) ; for unit testing vs C code + +;;; The "good" hash function on sb-vm:word returns a fixnum, does not cons, +;;; and has better avalanche behavior then SXHASH - changing any one input bit +;;; should affect each bit of output with equal chance. +(defun good-hash-word->fixnum (x) + (logand (murmur3-fmix-word (truly-the sb-vm:word x)) most-positive-fixnum)) ;;;; support for the hash values used by CLOS when working with LAYOUTs @@ -185,15 +198,13 @@ ;;; an extra right-shift to remove bits that lack any randomness. CACHE-MASK can be ;;; reworked to examine bits other than at the low end. (defun hash-layout-name (name) - (let ((limit (1+ (ash sb-xc:most-positive-fixnum -1))) - (random-state (load-time-value (make-random-state)))) + (let ((limit (1+ (ash most-positive-fixnum -1)))) (declare (notinline random)) (logior (if (typep name '(and symbol (not null))) - (flet ((improve-hash (x) - (#+64-bit murmur3-fmix64 #-64-bit murmur3-fmix32 x))) + (flet ((improve-hash (x) (murmur3-fmix-word x))) (mix (logand (improve-hash (sb-impl::%sxhash-simple-string (symbol-name name))) - sb-xc:most-positive-fixnum) + most-positive-fixnum) (let ((package (sb-xc:symbol-package name))) (sb-impl::%sxhash-simple-string ;; Must specifically look for CL package when cross-compiling @@ -202,6 +213,17 @@ ;; host happens to have standard symbols homed elsewhere. (cond #+sb-xc ((eq package *cl-package*) "COMMON-LISP") ((not package) "uninterned") - (t (package-name package))))))) - (random (ash limit -1) random-state)) + (t (sb-xc:package-name package))))))) + ;; This L-T-V form has to remain out of the common path, + ;; or else cheneygc will crash in cold-init. + ;; Cold-init calls HASH-LAYOUT-NAME many times *before* the L-T-V + ;; is actually executed and stuffed in as a constant. + ;; That's harmless - the loader put an unbound marker there, and we don't care. + ;; *HOWEVER* there is an interesting issue that arises if the value-cell + ;; indirection is present (see the IR1 translator for L-T-V and the + ;; conditional code for cheneygc): when can the compiler dereference the + ;; value-cell? If the binding were earlier (before the IF), then the dereference + ;; would happen earlier, and crash, because unbound-marker isn't a pointer. + (let ((random-state (load-time-value (make-random-state)))) + (random (ash limit -1) random-state))) limit))) diff --git a/src/code/string.lisp b/src/code/string.lisp index b21074d07c..dc25ac6278 100644 --- a/src/code/string.lisp +++ b/src/code/string.lisp @@ -95,92 +95,192 @@ (declare (optimize (safety 1))) (setf (schar string index) new-el)) -(defun string=* (string1 string2 start1 end1 start2 end2) - (declare (optimize speed)) - (with-two-strings string1 string2 start1 end1 nil start2 end2 - (let ((len (- end1 start1))) - (unless (= len (- end2 start2)) ; trivial - (return-from string=* nil)) - ;; Optimizing the non-unicode builds is not terribly important - ;; because no per-character test for base/UCS4 is needed. - #+sb-unicode - (let* ((widetag1 (%other-pointer-widetag string1)) - (widetag2 (%other-pointer-widetag string2)) - (char-shift +(macrolet ((memcmp (shift) + ;; Efficiently compute byte indices. Derive-type on ASH isn't + ;; good enough. For 32-bit, it should be ok because + ;; (TYPEP (ASH ARRAY-TOTAL-SIZE-LIMIT 2) 'SB-VM:SIGNED-WORD) => T + ;; For 63-bit fixnums, that's false in theory, but true in practice. + ;; ARRAY-TOTAL-SIZE-LIMIT is too large for a 48-bit address space. + `(macrolet ((sap (string start) + `(sap+ (vector-sap (truly-the string ,string)) + (scale ,start))) + (scale (index) + `(truly-the sb-vm:signed-word + (ash (truly-the index ,index) ,',shift)))) + (declare (optimize (sb-c:alien-funcall-saves-fp-and-pc 0))) + (with-pinned-objects (string1 string2) + (zerop (alien-funcall + (extern-alien "memcmp" + (function int (* char) (* char) long)) + (sap string1 start1) (sap string2 start2) + (scale len)))))) + (char-loop (type1 type2) + `(let ((string1 (truly-the (simple-array ,type1 1) string1)) + (string2 (truly-the (simple-array ,type2 1) string2))) + (declare (optimize (sb-c:insert-array-bounds-checks 0))) + (do ((index1 start1 (1+ index1)) + (index2 start2 (1+ index2))) + ((>= index1 end1) t) + (declare (index index1 index2)) + (unless (char= (schar string1 index1) + (schar string2 index2)) + (return nil)))))) + + (defun string=* (string1 string2 start1 end1 start2 end2) + (declare (explicit-check)) + #+(or arm64 (and x86-64 sb-unicode)) + (when (and (eql start1 0) + (eql start2 0) + (not end1) + (not end2)) + ;; With the range spanning the whole string it can be compared + ;; 128 bits at a time without the need to process any leftover + ;; bits. + (prog ((string1 string1) + (string2 string2)) + (cond ((simple-base-string-p string1) + (cond #+sb-unicode + ((simple-character-string-p string2) + (go 8-32)) + #+arm64 + ((simple-base-string-p string2) + (go 8-8)) + (t + (go normal)))) + #+sb-unicode + ((simple-character-string-p string1) + (cond ((simple-base-string-p string2) + (rotatef string1 string2) + (go 8-32)) + #+arm64 + ((simple-character-string-p string2) + (go 32-32)) + (t + (go normal)))) + (t + (go normal))) + 8-32 + (return-from string=* + (let ((length1 (length string1))) + (and (= length1 + (length string2)) + (sb-vm::simd-cmp-8-32 string1 string2 length1)))) + 8-8 + #+arm64 + (return-from string=* + (let ((length1 (length string1))) + (and (= length1 + (length string2)) + (sb-vm::simd-cmp-8-8 string1 string2 length1)))) + + 32-32 + #+arm64 + (return-from string=* + (let ((length1 (length string1))) + (and (= length1 + (length string2)) + (sb-vm::simd-cmp-32-32 string1 string2 length1)))) + normal)) + (with-two-strings string1 string2 start1 end1 nil start2 end2 + (let ((len (- end1 start1))) + (unless (= len (- end2 start2)) ; trivial + (return-from string=* nil)) + ;; Optimizing the non-unicode builds is not terribly important + ;; because no per-character test for base/UCS4 is needed. + #+sb-unicode + (let* ((widetag1 (%other-pointer-widetag string1)) + (widetag2 (%other-pointer-widetag string2))) + (macrolet ((char-loop (type1 type2) + `(return-from string=* + (let ((string1 (truly-the (simple-array ,type1 1) string1)) + (string2 (truly-the (simple-array ,type2 1) string2))) + (declare (optimize (sb-c:insert-array-bounds-checks 0))) + (do ((index1 start1 (1+ index1)) + (index2 start2 (1+ index2))) + ((>= index1 end1) t) + (declare (index index1 index2)) + (unless (char= (schar string1 index1) + (schar string2 index2)) + (return nil))))))) + (cond #+(or x86 x86-64) + ;; The cost of WITH-PINNED-OBJECTS is near nothing on x86, + ;; and memcmp() is much faster except below a cutoff point. + ;; The threshold is higher on x86-32 because the overhead + ;; of a foreign call is higher due to FPU stack save/restore. + ((and (= widetag1 widetag2) + (>= len #+x86 16 + #+x86-64 8)) + (let ((shift (case widetag1 + (#.sb-vm:simple-base-string-widetag 0) + (#.sb-vm:simple-character-string-widetag 2)))) + (memcmp shift))) + ((= widetag1 widetag2) + (case widetag1 + (#.sb-vm:simple-base-string-widetag + (char-loop base-char base-char)) + (#.sb-vm:simple-character-string-widetag + (char-loop character character)))) + ((or (and (= widetag1 sb-vm:simple-character-string-widetag) + (= widetag2 sb-vm:simple-base-string-widetag)) + (and (= widetag2 sb-vm:simple-character-string-widetag) + (= widetag1 sb-vm:simple-base-string-widetag) + (progn (rotatef start1 start2) + (rotatef end1 end2) + (rotatef string1 string2) + t))) + (char-loop character base-char)))))) + #-sb-unicode + (%sp-string= string1 string2 start1 end1 start2 end2))) + + (defun simple-base-string= (string1 string2 start1 end1 start2 end2) + #+arm64 + (when (and (zerop start1) + (zerop start2) + (not end1) + (not end2)) + (return-from simple-base-string= + (let ((length1 (length string1))) + (and (= length1 + (length string2)) + (sb-vm::simd-cmp-8-8 string1 string2 length1))))) + (with-two-strings string1 string2 start1 end1 nil start2 end2 + (let ((len (- end1 start1))) + (cond ((/= len (- end2 start2)) + nil) + #+(or x86 x86-64) + ((>= len #+x86 16 + #+x86-64 8) + (memcmp 0)) + (t + (char-loop base-char base-char)))))) + + #+sb-unicode + (defun simple-character-string= (string1 string2 start1 end1 start2 end2) + #+arm64 + (when (and (eql start1 0) + (eql start2 0) + (not end1) + (not end2)) + (return-from simple-character-string= + (let ((length1 (length string1))) + (and (= length1 + (length string2)) + (sb-vm::simd-cmp-32-32 string1 string2 length1))))) + (with-two-strings string1 string2 start1 end1 nil start2 end2 + (let ((len (- end1 start1))) + (cond ((/= len (- end2 start2)) + nil) #+(or x86 x86-64) - ;; The cost of WITH-PINNED-OBJECTS is near nothing on x86, - ;; and memcmp() is much faster except below a cutoff point. - ;; The threshold is higher on x86-32 because the overhead - ;; of a foreign call is higher due to FPU stack save/restore. - (if (and (= widetag1 widetag2) - (>= len #+x86 16 - #+x86-64 8)) - (case widetag1 - (#.sb-vm:simple-base-string-widetag 0) - (#.sb-vm:simple-character-string-widetag 2))))) - (when char-shift - (return-from string=* - ;; Efficiently compute byte indices. Derive-type on ASH isn't - ;; good enough. For 32-bit, it should be ok because - ;; (TYPEP (ASH ARRAY-TOTAL-SIZE-LIMIT 2) 'SB-VM:SIGNED-WORD) => T - ;; For 63-bit fixnums, that's false in theory, but true in practice. - ;; ARRAY-TOTAL-SIZE-LIMIT is too large for a 48-bit address space. - (macrolet ((sap (string start) - `(sap+ (vector-sap (truly-the string ,string)) - (scale ,start))) - (scale (index) - `(truly-the sb-vm:signed-word - (ash (truly-the index ,index) char-shift)))) - (declare (optimize (sb-c:alien-funcall-saves-fp-and-pc 0))) - (with-pinned-objects (string1 string2) - (zerop (alien-funcall - (extern-alien "memcmp" - (function int (* char) (* char) long)) - (sap string1 start1) (sap string2 start2) - (scale len))))))) - (macrolet - ((char-loop (type1 type2) - `(return-from string=* - (let ((string1 (truly-the (simple-array ,type1 1) string1)) - (string2 (truly-the (simple-array ,type2 1) string2))) - (declare (optimize (sb-c::insert-array-bounds-checks 0))) - (do ((index1 start1 (1+ index1)) - (index2 start2 (1+ index2))) - ((>= index1 end1) t) - (declare (index index1 index2)) - (unless (char= (schar string1 index1) - (schar string2 index2)) - (return nil))))))) - ;; On x86-64, short strings with same widetag use the general case. - ;; Why not always have cases for equal widetags and short strings? - ;; Because the code below deals with comparison when memcpy _can't_ - ;; be used and is essential to this logic. No major speed gain is had - ;; with extra cases where memcpy would do, but was avoided. - ;; On non-x86, Lisp code is used always because I did not profile - ;; memcmp(), and this code is at least as good as %SP-STRING-COMPARE. - ;; Also, (ARRAY NIL) always punts. - (cond #-x86-64 - ((= widetag1 widetag2) - (case widetag1 - (#.sb-vm:simple-base-string-widetag - (char-loop base-char base-char)) - (#.sb-vm:simple-character-string-widetag - (char-loop character character)))) - ((or (and (= widetag1 sb-vm:simple-character-string-widetag) - (= widetag2 sb-vm:simple-base-string-widetag)) - (and (= widetag2 sb-vm:simple-character-string-widetag) - (= widetag1 sb-vm:simple-base-string-widetag) - (progn (rotatef start1 start2) - (rotatef end1 end2) - (rotatef string1 string2) - t))) - (char-loop character base-char)))))) - (zerop (nth-value 1 (%sp-string-compare string1 start1 end1 string2 start2 end2))))) + ((>= len #+x86 16 + #+x86-64 8) + (memcmp 2)) + (t + (char-loop character character))))))) (defun string/=* (string1 string2 start1 end1 start2 end2) (with-two-strings string1 string2 start1 end1 offset1 start2 end2 (multiple-value-bind (index diff) - (%sp-string-compare string1 start1 end1 string2 start2 end2) + (%sp-string-compare string1 string2 start1 end1 start2 end2) (if (zerop diff) nil (- index offset1))))) @@ -188,8 +288,8 @@ (defmacro string<>=*-body (test index) `(with-two-strings string1 string2 start1 end1 offset1 start2 end2 (multiple-value-bind (index diff) - (%sp-string-compare string1 start1 end1 - string2 start2 end2) + (%sp-string-compare string1 string2 + start1 end1 start2 end2) (if (,test diff 0) ,(if index '(- index offset1) nil) ,(if index nil '(- index offset1)))))) @@ -307,6 +407,44 @@ (string-not-equal-loop 1 t nil))))) (defun two-arg-string-equal (string1 string2) + #+arm64 + (prog ((string1 string1) + (string2 string2)) + (cond ((simple-base-string-p string1) + (cond #+sb-unicode + ((simple-character-string-p string2) + (go 8-32)) + ((simple-base-string-p string2) + (go 8-8)) + (t + (go normal)))) + #+sb-unicode + ((simple-character-string-p string1) + (cond ((simple-base-string-p string2) + (rotatef string1 string2) + (go 8-32)) + #+(or) + ((simple-character-string-p string2) + (go 32-32)) + (t + (go normal)))) + (t + (go normal))) + 8-32 + #+sb-unicode + (return-from two-arg-string-equal + (let ((length1 (length string1))) + (and (= length1 + (length string2)) + (sb-vm::simd-base-character-string-equal string1 string2 length1)))) + 8-8 + (return-from two-arg-string-equal + (let ((length1 (length string1))) + (and (= length1 + (length string2)) + (sb-vm::simd-base-string-equal string1 string2 length1)))) + 32-32 + normal) (with-two-arg-strings string1 string2 start1 end1 nil start2 end2 (let ((slen1 (- (the fixnum end1) start1)) (slen2 (- (the fixnum end2) start2))) @@ -435,93 +573,236 @@ (defun two-arg-string-not-greaterp (string1 string2) (string-not-greaterp* string1 string2 0 nil 0 nil)) -(defun make-string (count &key - (element-type 'character) - ((:initial-element fill-char))) +(defun make-string (count &key (element-type 'character) + (initial-element nil iep)) "Given a character count and an optional fill character, makes and returns a new string COUNT long filled with the fill character." (declare (index count)) (declare (explicit-check)) - ;; FIXME: while this is a correct implementation relying on an IR1 transform, - ;; it would be better if in the following example (assuming NOTINLINE): - ;; (MAKE-STRING 1000 :ELEMENT-TYPE 'BIT :INITIAL-element #\a) - ;; we could report that "BIT is not a subtype of CHARACTER" - ;; instead of "#\a is not of type BIT". Additionally, in this case: - ;; (MAKE-STRING 200000000 :ELEMENT-TYPE 'WORD :INITIAL-ELEMENT #\a) - ;; the error reported is heap exhaustion rather than type mismatch. - (if fill-char - (make-string count :element-type element-type - :initial-element (the character fill-char)) - (make-string count :element-type element-type))) - -(declaim (inline nstring-upcase)) -(defun nstring-upcase (string &key (start 0) end) - (declare (explicit-check)) - (if (typep string '(array nil (*))) - (if (zerop (length string)) - string - (data-nil-vector-ref string 0)) - (locally - (declare ((or base-string - (array character (*))) - string)) - (with-one-string (string start end) - (do ((index start (1+ index)) - (cases **character-cases**) - (case-pages **character-case-pages**)) - ((>= index end)) - (declare (optimize (sb-c::insert-array-bounds-checks 0))) - (let ((char (schar string index))) - (with-case-info (char case-index cases - :cases cases - :case-pages case-pages) - (let ((code (aref cases (1+ case-index)))) - (unless (zerop code) - (setf (schar string index) - (code-char (truly-the char-code code))))))))) - string))) -(declaim (notinline nstring-upcase)) + (cond ((eq element-type 'character) + (let ((c (if iep (the character initial-element))) + (s (make-string count :element-type 'character))) + (when c (sb-vm::unpoison s) (fill s c)) + s)) + ((or (eq element-type 'base-char) + (eq element-type 'standard-char) + ;; What's the "most specialized" thing possible that's still a string? + ;; Well clearly it's a string whose elements have the smallest domain. + ;; So that would be 8 bits per character, not 32 bits per character. + (eq element-type nil)) + (let ((c (if iep (the base-char initial-element))) + (s (make-string count :element-type 'base-char))) + (when c (sb-vm::unpoison s) (fill s c)) + s)) + (t + (multiple-value-bind (widetag n-bits-shift) + (sb-vm::%vector-widetag-and-n-bits-shift element-type) + (unless (or #+sb-unicode (= widetag sb-vm:simple-character-string-widetag) + (= widetag sb-vm:simple-base-string-widetag)) + (error "~S is not a valid :ELEMENT-TYPE for MAKE-STRING" element-type)) + ;; If you give a ridiculous type such as (member #\EN_SPACE) as your + ;; :ELEMENT-TYPE, then you get what you deserve - slow type checking. + (when (and iep (not (typep initial-element element-type))) + (error 'simple-type-error + :datum initial-element + :expected-type element-type + :format-control "~S is not a ~S" + :format-arguments (list initial-element element-type))) + (let ((string + (sb-vm::allocate-vector-with-widetag + #+ubsan nil widetag count n-bits-shift))) + (when initial-element (fill string initial-element)) + string))))) + +(defmacro nstring-case (case-index a z) + (declare (ignorable a z)) + `(cond ((and (zerop start) + (not end) + (typecase string + #+sb-unicode + (simple-base-string + (let* ((repeat (ldb (byte sb-vm:n-word-bits 0) #x0101010101010101)) + (a-mask (* (- 128 (char-code ,a)) repeat)) + (z-mask (* (- 127 (char-code ,z)) repeat)) + (7-mask (* 128 repeat))) + (declare (optimize sb-c::preserve-single-use-debug-variables + sb-c::preserve-constants)) + (flet ((%case (bits) + (logxor bits (ash (logand (logxor (+ bits a-mask) + (+ bits z-mask)) + 7-mask) + -2)))) + (declare (inline %case)) + (loop for i below (ceiling (length string) sb-vm:n-word-bytes) + do + (setf (%vector-raw-bits string i) + (%case (%vector-raw-bits string i)))))) + string) + #+(or x86-64 arm64) + ((simple-array character) + (let ((length (length string))) + (sb-vm::simd-string-case ,a string string + i + (do ((index i (1+ index)) + (cases +character-cases+)) + ((>= index length)) + (let ((char (schar string index))) + (with-case-info (char case-index cases + :cases cases) + (let ((code (aref cases ,case-index))) + (unless (zerop code) + (setf (schar string index) + (code-char (truly-the char-code code)))))))))) + string)))) + (t + (with-one-string (string start end) + (declare (optimize (sb-c:insert-array-bounds-checks 0))) + (cond #+sb-unicode + ((simple-base-string-p string) + (do ((index start (1+ index))) + ((>= index end)) + (let ((char (char-code (schar string index)))) + (when (<= (char-code ,a) char (char-code ,z)) + (setf (schar string index) + (code-char (truly-the char-code (logxor char #x20)))))))) + (t + (do ((index start (1+ index)) + (cases +character-cases+)) + ((>= index end)) + (let ((char (schar string index))) + (with-case-info (char case-index cases + :cases cases) + (let ((code (aref cases ,case-index))) + (unless (zerop code) + (setf (schar string index) + (code-char (truly-the char-code code)))))))))))))) -(defun string-upcase (string &key (start 0) end) - (declare (explicit-check) - (inline nstring-upcase)) - (nstring-upcase (copy-seq (%string string)) :start start :end end)) +(defun nstring-upcase (string &key (start 0) end) + (nstring-case (1+ case-index) #\a #\z) + string) -(declaim (inline nstring-downcase)) (defun nstring-downcase (string &key (start 0) end) + (nstring-case case-index #\A #\Z) + string) + +(defmacro string-case (case-index a z) + (declare (ignorable a z)) + `(let* ((string (%string string)) + (length (length string))) + (or + (and (eql start 0) + (not end) + (typecase string + #+sb-unicode + (simple-base-string + (let* ((repeat (ldb (byte sb-vm:n-word-bits 0) #x0101010101010101)) + (a-mask (* (- 128 (char-code ,a)) repeat)) + (z-mask (* (- 127 (char-code ,z)) repeat)) + (7-mask (* 128 repeat))) + (declare (optimize sb-c::preserve-single-use-debug-variables + sb-c::preserve-constants)) + (flet ((%case (bits) + (logxor bits (ash (logand (logxor (+ bits a-mask) + (+ bits z-mask)) + 7-mask) + -2)))) + (declare (inline %case)) + (let ((new (make-string length :element-type 'base-char))) + (loop for i below (ceiling (length string) sb-vm:n-word-bytes) + do + (setf (%vector-raw-bits new i) + (%case (%vector-raw-bits string i)))) + new)))) + #+(or x86-64 arm64) + ((simple-array character) + (let ((new (make-string length))) + (sb-vm::simd-string-case ,a string new + i + (do ((index i (1+ index)) + (cases +character-cases+)) + ((>= index length)) + (let* ((char (schar string index)) + (cased (with-case-info (char case-index cases + :cases cases + :miss-value char) + (let ((code (aref cases ,case-index))) + (if (zerop code) + char + (code-char (truly-the char-code code))))))) + (setf (schar new index) cased)))) + new)))) + (with-array-data ((string-data string :offset-var offset) + (s-start start) + (s-end end) + :check-fill-pointer t) + (declare (optimize (sb-c:insert-array-bounds-checks 0))) + (cond #+sb-unicode + ((simple-base-string-p string-data) + (let* ((new (make-string length :element-type 'base-char))) + (when (> start 0) + (loop for d-i below start + for s-i from offset + do + (locally (declare (optimize (safety 0))) + (setf (schar new d-i) + (schar string-data s-i))))) + (when (and end + (< end length)) + (loop for d-i from end below length + for s-i from s-end + do (locally (declare (optimize (safety 0))) + (setf (schar new d-i) + (schar string-data s-i))))) + (do ((s-i s-start (truly-the index (1+ s-i))) + (d-i start (truly-the index (1+ d-i)))) + ((>= s-i s-end)) + (declare (index d-i)) + (let ((char (char-code (schar string-data s-i)))) + (setf (schar new d-i) + (code-char + (if (<= (char-code ,a) char (char-code ,z)) + (truly-the char-code (logxor char #x20)) + char))))) + new)) + (t + (let ((new (make-string length))) + (when (> start 0) + (loop for d-i below start + for s-i from offset + do + (locally (declare (optimize (safety 0))) + (setf (schar new d-i) + (schar string-data s-i))))) + (when (and end + (< end length)) + (loop for d-i from end below length + for s-i from s-end + do (locally (declare (optimize (safety 0))) + (setf (schar new d-i) + (schar string-data s-i))))) + (do ((s-i s-start (truly-the index (1+ s-i))) + (d-i start (truly-the index (1+ d-i))) + (cases +character-cases+)) + ((>= s-i s-end)) + (declare (index d-i)) + (let* ((char (schar string-data s-i)) + (cased (with-case-info (char case-index cases + :cases cases + :miss-value char) + (let ((code (aref cases ,case-index))) + (if (zerop code) + char + (code-char (truly-the char-code code))))))) + (setf (schar new d-i) cased))) + new))))))) + +(defun string-upcase (string &key (start 0) end) (declare (explicit-check)) - (if (typep string '(array nil (*))) - (if (zerop (length string)) - string - (data-nil-vector-ref string 0)) - (locally - (declare ((or base-string - (array character (*))) - string)) - (with-one-string (string start end) - (do ((index start (1+ index)) - (cases **character-cases**) - (case-pages **character-case-pages**)) - ((>= index end)) - (declare (optimize (sb-c::insert-array-bounds-checks 0))) - (let ((char (schar (truly-the (or simple-base-string - simple-character-string) - string) - index))) - (with-case-info (char case-index cases - :cases cases - :case-pages case-pages) - (let ((code (aref cases case-index))) - (unless (zerop code) - (setf (schar string index) - (code-char (truly-the char-code code))))))))) - string))) -(declaim (notinline nstring-downcase)) + (string-case (1+ case-index) #\a #\z)) (defun string-downcase (string &key (start 0) end) - (declare (explicit-check) - (inline nstring-downcase)) - (nstring-downcase (copy-seq (%string string)) :start start :end end)) + (declare (explicit-check)) + (string-case case-index #\A #\Z)) (flet ((%capitalize (string start end) (declare (string string) (index start) (type sequence-end end)) @@ -601,12 +882,19 @@ new string COUNT long filled with the fill character." (generic-string-trim char-bag string t t)) (defun logically-readonlyize (vector &optional (always-shareable t)) - ;; "Always" means that regardless of whether the user want + ;; "Always" means that regardless of whether the user wanted ;; coalescing of strings used as literals in code compiled to memory, ;; the string is shareable. - ;; #b01_ ; symbol name, literal compiled to fasl, some other stuff - ;; #b10_ ; literal compiled to core - (set-header-data (the (simple-array * 1) vector) - (if always-shareable - sb-vm:+vector-shareable+ - sb-vm:+vector-shareable-nonstd+))) + (when (sb-kernel::dynamic-space-obj-p vector) + ;; FIXME: did I get the condition backwards? I'm trying to remember what it meant. + ;; "Always" should mean that the language specifies the behavior, e.g. strings used + ;; as print names can not be modified. (edge case: if it ceases to be a print name, + ;; can it then be modified?) "Not always" means that we've done an + ;; implementation-specific thing to make more strings shareable than specified. + ;; "Always" isn't really the best terminology for the semantics, I guess. + ;; And are there any tests around this??? + (logior-array-flags (the (simple-array * 1) vector) + (if always-shareable + sb-vm:+vector-shareable+ + sb-vm:+vector-shareable-nonstd+))) + vector) diff --git a/src/code/stubs.lisp b/src/code/stubs.lisp index 7e48d50fd2..91e59edea5 100644 --- a/src/code/stubs.lisp +++ b/src/code/stubs.lisp @@ -13,6 +13,37 @@ (in-package "SB-IMPL") +(defun (cas symbol-value) (old new symbol) + (cas (symbol-value symbol) old new)) +(defun (cas svref) (old new vector index) + (cas (svref vector index) old new)) +#+(or ppc64 x86-64) +(macrolet ((def (name) + `(defun (cas ,name) (old new sap index) + (funcall #'(cas ,name) old new sap index)))) + (def sb-sys:sap-ref-8) + (def sb-sys:sap-ref-16) + (def sb-sys:sap-ref-32) + (def sb-sys:sap-ref-64) + (def sb-sys:signed-sap-ref-64) + (def sb-sys:sap-ref-sap) + (def sb-sys:sap-ref-lispobj)) + +(macrolet ((def (name &rest args) + `(defun ,name ,args + (,name ,@args)))) + (def word-logical-not x) + (def word-logical-and x y) + (def word-logical-or x y) + (def word-logical-xor x y) + (def word-logical-nor x y) + (def word-logical-eqv x y) + (def word-logical-nand x y) + (def word-logical-andc1 x y) + (def word-logical-andc2 x y) + (def word-logical-orc1 x y) + (def word-logical-orc2 x y)) + (macrolet ((def (name &optional (args '(x))) `(defun ,name ,args (,@(if (listp name) `(funcall #',name) `(,name)) ,@args))) @@ -29,7 +60,8 @@ (def sap-int) (def int-sap) (macrolet ((def-accessor (name) - `(progn (def ,(symbolicate "%SET-" name) (sap offset value)) + ;; the low-level %SET functions should not need stubs + `(progn (def (setf ,name) (value sap offset)) (def ,name (sap offset))))) (def-accessor sap-ref-8) (def-accessor sap-ref-16) @@ -46,6 +78,8 @@ (def-accessor sap-ref-single) (def-accessor sap-ref-double)) (def %byte-blt (src src-start dst dst-start dst-end)) + (def shift-towards-start (number count)) + (def shift-towards-end (number count)) (def get-header-data) (def set-header-data (x val)) (def widetag-of) @@ -53,14 +87,10 @@ (def pointer-hash) (def vector-sap) (def binding-stack-pointer-sap ()) - ;; x86 uses a plain old inline function for 'dynamic_space_free_pointer' - ;; so there's no stub function for DYNAMIC-SPACE-FREE-POINTER. - #-(or x86 x86-64) (def dynamic-space-free-pointer ()) + #+cheneygc (def dynamic-space-free-pointer ()) (def control-stack-pointer-sap ()) (def sb-c:safe-fdefn-fun) - (def fun-subtype) - (def simple-fun-p) - (def closurep) + (def %fun-pointer-widetag) (def %closure-fun) (def %closure-index-ref (closure index)) (def fdefn-name) @@ -70,7 +100,6 @@ (def make-array-header (type rank)) (def code-instructions) #-untagged-fdefns (def code-header-ref (code-obj index)) - (def code-header-set (code-obj index new)) (def %vector-raw-bits (object offset)) (def %set-vector-raw-bits (object offset value)) (def single-float-bits) @@ -81,27 +110,30 @@ (def value-cell-ref) (def %caller-frame ()) (def %caller-pc ()) - (def %code-debug-info) - #+(or x86 x86-64) (def sb-vm::%code-fixups) + (def sb-vm::%code-fixups) #+x86-64 (def pointerp) + (def sb-bignum:%bignum-length) ;; instances (def %make-instance) ; Allocate a new instance with X data slots. + (def %make-instance/mixed) (def %instance-length) ; Given an instance, return its length. (def %instance-layout) + (def %instance-wrapper) (def %set-instance-layout (instance new-value)) ; (def %instance-ref (instance index)) ; defined in 'target-defstruct' (def %instance-set (instance index new-value)) ;; funcallable instances (def %make-funcallable-instance) (def %fun-layout) - (def %set-funcallable-instance-layout (fin new-value)) + (def %fun-wrapper) + (def %set-fun-layout (fin new-value)) (def %funcallable-instance-fun) (def (setf %funcallable-instance-fun) (fin new-value)) (def %funcallable-instance-info (fin i)) - (def %set-funcallable-instance-info (fin i new-value)) - #+(and compact-instance-header x86-64) (def layout-of) - #+64-bit (def layout-depthoid) + #+compact-instance-header (progn (def wrapper-of) + (def %instanceoid-layout)) + ;; lists (def %rplaca (x val)) (def %rplacd (x val)) @@ -115,29 +147,23 @@ (%make-simd-pack-single (x y z w)) (%make-simd-pack-double (low high)) (%make-simd-pack-ub64 (low high)) - (%simd-pack-tag) - (%simd-pack-low) - (%simd-pack-high)) + (%simd-pack-tag)) #+sb-simd-pack-256 (def* (%make-simd-pack-256 (tag p0 p1 p2 p3)) (%make-simd-pack-256-single (a b c d e f g h)) (%make-simd-pack-256-double (a b c d)) (%make-simd-pack-256-ub64 (a b c d)) - (%simd-pack-256-tag) - (%simd-pack-256-0) - (%simd-pack-256-1) - (%simd-pack-256-2) - (%simd-pack-256-3)) + (%simd-pack-256-tag)) #+sb-thread (def sb-vm::current-thread-offset-sap) (def current-sp ()) (def current-fp ()) (def stack-ref (s n)) - (def %set-stack-ref (s n value)) (def fun-code-header) (def symbol-hash) - (def sb-vm::symbol-extra) - #+sb-thread (def symbol-tls-index) - #.(if (fboundp 'symbol-info-vector) (values) '(def symbol-info-vector)) + (def symbol-%info) ; primitive reader always needs a stub + ;; but the "wrapped" reader might not need a stub. + ;; If it's already a proper function, then it doesn't. + #.(if (fboundp 'symbol-dbinfo) (values) '(def symbol-dbinfo)) #-(or x86 x86-64) (def lra-code-header) (def %make-lisp-obj) (def get-lisp-obj-address) @@ -146,10 +172,47 @@ #+x86-64 (def single-float-sign)) +#+sb-simd-pack +(macrolet ((def (name) + `(defun ,name (pack) + (sb-vm::simd-pack-dispatch pack + (,name pack))))) + (def %simd-pack-low) + (def %simd-pack-high)) + +#+sb-simd-pack-256 +(macrolet ((def (name) + `(defun ,name (pack) + (sb-vm::simd-pack-256-dispatch pack + (,name pack))))) + (def %simd-pack-256-0) + (def %simd-pack-256-1) + (def %simd-pack-256-2) + (def %simd-pack-256-3)) + (defun spin-loop-hint () "Hints the processor that the current thread is spin-looping." (spin-loop-hint)) +;;; The stub for sb-c::%structure-is-a should really use layout-id in the same way +;;; that the vop does, however, because the all 64-bit architectures other than +;;; x86-64 need to use with-pinned-objects to extract a layout-id, it is cheaper not to. +;;; I should add a vop for uint32 access to raw slots. +(defun sb-c::%structure-is-a (object-layout test-layout) + (or (eq object-layout test-layout) + (let ((depthoid (wrapper-depthoid test-layout)) + (inherits (wrapper-inherits object-layout))) + (and (> (length inherits) depthoid) + (eq (svref inherits depthoid) test-layout))))) + +(defun sb-c::structure-typep (object test-layout) + (and (%instancep object) + (let ((object-layout (%instance-layout object))) + (or (eq object-layout test-layout) + (let ((depthoid (wrapper-depthoid test-layout)) + (inherits (wrapper-inherits object-layout))) + (and (> (length inherits) depthoid) + (eq (svref inherits depthoid) test-layout))))))) (defun %other-pointer-subtype-p (x choices) (and (%other-pointer-p x) diff --git a/src/code/sunos-os.lisp b/src/code/sunos-os.lisp index 96e0b4044b..bc096c0e69 100644 --- a/src/code/sunos-os.lisp +++ b/src/code/sunos-os.lisp @@ -32,3 +32,20 @@ ;;; support for CL:MACHINE-VERSION defined OAOO elsewhere (defun get-machine-version () nil) + +(in-package "SB-UNIX") + +;; SunOS defines CLOCK_PROCESS_CPUTIME_ID but you get EINVAL if you try to use it. +(defun system-internal-run-time () + (multiple-value-bind (utime-sec utime-usec stime-sec stime-usec) + (with-alien ((usage (struct sb-unix::rusage))) + (syscall* ("sb_getrusage" int (* (struct sb-unix::rusage))) + (values (slot (slot usage 'sb-unix::ru-utime) 'sb-unix::tv-sec) + (slot (slot usage 'sb-unix::ru-utime) 'sb-unix::tv-usec) + (slot (slot usage 'sb-unix::ru-stime) 'sb-unix::tv-sec) + (slot (slot usage 'sb-unix::ru-stime) 'sb-unix::tv-usec)) + rusage_self (addr usage))) + (+ (* (+ utime-sec stime-sec) internal-time-units-per-second) + (floor (+ utime-usec stime-usec + (floor microseconds-per-internal-time-unit 2)) + microseconds-per-internal-time-unit)))) diff --git a/src/code/symbol.lisp b/src/code/symbol.lisp index a850d9ab47..292720275c 100644 --- a/src/code/symbol.lisp +++ b/src/code/symbol.lisp @@ -88,7 +88,7 @@ distinct from the global value. Can also be SETF." (return-from compute-symbol-hash (sxhash nil))) ;; And make a symbol's hash not the same as (sxhash name) in general. (let ((sxhash (logxor (%sxhash-simple-substring string 0 length) - sb-xc:most-positive-fixnum))) + most-positive-fixnum))) ;; The low 32 bits of the word in memory should have at least a 1 bit somewhere. ;; If not, OR in a constant value. (if (ldb-test (byte (- 32 sb-vm:n-fixnum-tag-bits) 0) sxhash) @@ -105,9 +105,20 @@ distinct from the global value. Can also be SETF." (%set-symbol-hash symbol (compute-symbol-hash name (length name)))) hash))) +;;; Return the function binding of SYMBOL or NIL if not fboundp. +;;; Don't strip encapsulations. +(declaim (inline %symbol-function)) +(defun %symbol-function (symbol) + (let ((fdefn (sb-vm::%symbol-fdefn symbol))) + (if (eql fdefn 0) nil (fdefn-fun (truly-the fdefn fdefn))))) +(defun (setf %symbol-function) (newval symbol) ; OK to use only if fdefn exists + (let ((fdefn (sb-vm::%symbol-fdefn symbol))) + (setf (fdefn-fun (truly-the fdefn fdefn)) newval))) + (defun symbol-function (symbol) "Return SYMBOL's current function definition. Settable with SETF." - (%coerce-name-to-fun symbol symbol-fdefn)) + (truly-the function (or (%symbol-function symbol) ; fast way + (%coerce-name-to-fun symbol)))) ; fallback w/restart ;; I think there are two bugs here. ;; Per CLHS "SETF may be used with symbol-function to replace a global @@ -124,6 +135,7 @@ distinct from the global value. Can also be SETF." ;; on SYMBOL-FUNCTION. It doesn't say that SETF behaves the same, but let's ;; assume it does, and that we can't assign our macro/special guard funs. (err-if-unacceptable-function new-value '(setf symbol-function)) + (setq new-value (strip-encapsulation new-value)) (with-single-package-locked-error (:symbol symbol "setting the symbol-function of ~A") ;; This code is a little "surprising" in that it is not just a limited @@ -135,6 +147,25 @@ distinct from the global value. Can also be SETF." (let ((fdefn (find-or-create-fdefn symbol))) (setf (fdefn-fun fdefn) new-value)))) +;;; Incredibly bogus kludge: the :CAS-TRANS option in objdef makes no indication +;;; that you can not use it on certain platforms, so then you do try to use it, +;;; and you silently get no automatic IR2 conversion. The workaround in src/code/cas +;;; is unnecessary imho - why are we comparing the old value? +;;; To catch programming errors that occur only for non-threads apparently? +;;; The flaw is that it's dissociated from objdef, which ought to you give you +;;; the stub automatically somehow. +;;; Furthermore it's annoying that you can't name the CAS function (CAS fn). +#-compare-and-swap-vops +(progn +(defun cas-symbol-%info (symbol old new) + (%primitive sb-vm::set-slot symbol new + '(setf symbol-%info) sb-vm:symbol-info-slot sb-vm:other-pointer-lowtag) + old) +(defun sb-vm::cas-symbol-fdefn (symbol old new) + (%primitive sb-vm::set-slot symbol new + '(setf symbol-fdefn) sb-vm:symbol-fdefn-slot sb-vm:other-pointer-lowtag) + old)) + ;;; Accessors for the dual-purpose info/plist slot ;; A symbol's INFO slot is always in one of three states: @@ -149,14 +180,6 @@ distinct from the global value. Can also be SETF." ;; State 2 transitions to state 3 via ({SETF|CAS} SYMBOL-PLIST). ;; There are *no* other permissible state transitions. -(defun symbol-info (symbol) - (symbol-info symbol)) - -;; An "interpreter stub" for an operation that is only implemented for -;; the benefit of platforms without compare-and-swap-vops. -(defun (setf symbol-info) (new-info symbol) - (setf (symbol-info symbol) new-info)) - ;; Atomically update SYMBOL's info/plist slot to contain a new info vector. ;; The vector is computed by calling UPDATE-FN on the old vector, ;; repeatedly as necessary, until no conflict happens with other updaters. @@ -164,25 +187,25 @@ distinct from the global value. Can also be SETF." (defun update-symbol-info (symbol update-fn) (declare (symbol symbol) (type (function (t) t) update-fn)) - (prog ((info-holder (symbol-info symbol)) - (current-vect)) + (prog ((info-holder (symbol-%info symbol)) + (current-info)) ; a PACKED-INFO or NIL outer-restart - ;; Do not use SYMBOL-INFO-VECTOR - this must not perform a slot read again. - (setq current-vect (if (listp info-holder) (cdr info-holder) info-holder)) + ;; This _must_ _not_ perform another read of the INFO slot here. + (setq current-info (if (listp info-holder) (cdr info-holder) info-holder)) inner-restart - (let ((new-vect (funcall update-fn (or current-vect +nil-packed-infos+)))) - (unless (simple-vector-p new-vect) - (aver (null new-vect)) + (let ((new-info (funcall update-fn (or current-info +nil-packed-infos+)))) + (unless (%instancep new-info) + (aver (null new-info)) (return)) ; nothing to do (if (consp info-holder) ; State 3: exchange the CDR - (let ((old (%compare-and-swap-cdr info-holder current-vect new-vect))) - (when (eq old current-vect) (return t)) ; win - (setq current-vect old) ; Don't touch holder- it's still a cons + (let ((old (cas (cdr info-holder) current-info new-info))) + (when (eq old current-info) (return t)) ; win + (setq current-info old) ; Don't touch holder- it's still a cons (go inner-restart))) - ;; State 1 or 2: info-holder is NIL or a vector. - ;; Exchange the contents of the info slot. Type-inference derives - ;; SIMPLE-VECTOR-P on the args to CAS, so no extra checking. - (let ((old (%compare-and-swap-symbol-info symbol info-holder new-vect))) + ;; State 1 or 2: info-holder is NIL or a PACKED-INFO. + ;; Exchange the contents of the info slot. Type-inference should have + ;; derived that NEW-INFO satisfies the slot type restriction (I hope). + (let ((old (cas-symbol-%info symbol info-holder new-info))) (when (eq old info-holder) (return t)) ; win ;; Check whether we're in state 2 or 3 now. ;; Impossible to be in state 1: nobody ever puts NIL in the slot. @@ -190,39 +213,27 @@ distinct from the global value. Can also be SETF." (setq info-holder old) (go outer-restart))))) -(eval-when (:compile-toplevel) - ;; If we're in state 1 or state 3, we can take (CAR (SYMBOL-INFO S)) - ;; to get the property list. If we're in state 2, this same access - ;; gets the fixnum which is the VECTOR-LENGTH of the info vector. - ;; So all we have to do is turn any fixnum to NIL, and we have a plist. - ;; Ensure that this pun stays working. - #-ppc64 ; ppc64 has unevenly spaced lowtags - (assert (= (- (* sb-vm:n-word-bytes sb-vm:cons-car-slot) - sb-vm:list-pointer-lowtag) - (- (* sb-vm:n-word-bytes sb-vm:vector-length-slot) - sb-vm:other-pointer-lowtag)))) - (defun symbol-plist (symbol) "Return SYMBOL's property list." - #+(vop-translates cl:symbol-plist) - (symbol-plist symbol) - #-(vop-translates cl:symbol-plist) - (let ((list (car (truly-the list (symbol-info symbol))))) ; a white lie - ;; Just ensure the result is not a fixnum, and we're done. - (if (fixnump list) nil list))) + (let ((list (symbol-%info symbol))) + ;; The compiler can't possibly know that the CAR of LIST + ;; is also a list (if LIST is a LIST), so force it with a TRULY-THE. + ;; See the comments above UPDATE-SYMBOL-INFO for a + ;; reminder as to why this logic is right. + (if (%instancep list) nil (truly-the list (car list))))) (declaim (ftype (sfunction (symbol t) cons) %ensure-plist-holder) (inline %ensure-plist-holder)) ;; When a plist update (setf or cas) is first performed on a symbol, ;; a one-time allocation of an extra cons is done which creates two -;; "slots" from one: a slot for the info-vector and a slot for the plist. +;; "slots" from one: a slot for the PACKED-INFO and a slot for the plist. ;; This avoids complications in the implementation of the user-facing ;; (CAS SYMBOL-PLIST) function, which should not have to be aware of ;; competition from globaldb mutators even if no other threads attempt ;; to manipulate the plist per se. -;; Given a SYMBOL and its current INFO of type (OR LIST SIMPLE-VECTOR) +;; Given a SYMBOL and its current INFO of type (OR LIST INSTANCE) ;; ensure that SYMBOL's current info is a cons, and return that. ;; If racing with multiple threads, at most one thread will install the cons. (defun %ensure-plist-holder (symbol info) @@ -234,56 +245,55 @@ distinct from the global value. Can also be SETF." ;; The pointer from the new cons to the old info must be persisted ;; to memory before the symbol's info slot points to the cons. ;; [x86oid doesn't need the barrier, others might] - (sb-thread:barrier (:write) - (setq newcell (cons nil info))) - (loop (let ((old (%compare-and-swap-symbol-info symbol info newcell))) + (setq newcell (cons nil info)) + (sb-thread:barrier (:write)) ; oh such ghastly syntax + (loop (let ((old (cas-symbol-%info symbol info newcell))) (cond ((eq old info) (return newcell)) ; win ((consp old) (return old))) ; somebody else made a cons! (setq info old) - (sb-thread:barrier (:write) ; Retry using same newcell - (rplacd newcell info))))))) + (rplacd newcell info) + (sb-thread:barrier (:write))))))) ; Retry using same newcell -(declaim (inline %compare-and-swap-symbol-plist - %set-symbol-plist)) +(declaim (inline (cas symbol-plist) (setf symbol-plist))) -(defun %compare-and-swap-symbol-plist (symbol old new) - ;; This is the entry point into which (CAS SYMBOL-PLIST) is transformed. +(defun (cas symbol-plist) (old new symbol) ;; If SYMBOL's info cell is a cons, we can do (CAS CAR). Otherwise punt. (declare (symbol symbol) (list old new)) - (let ((cell (symbol-info symbol))) + (let ((cell (symbol-%info symbol))) (if (consp cell) (%compare-and-swap-car cell old new) - (%%compare-and-swap-symbol-plist symbol old new)))) + (%cas-symbol-plist old new symbol)))) -(defun %%compare-and-swap-symbol-plist (symbol old new) +(defun %cas-symbol-plist (old new symbol) ;; This is just the second half of a partially-inline function, to avoid ;; code bloat in the exceptional case. Type assertions should have been ;; done - or not, per policy - by the caller of %COMPARE-AND-SWAP-SYMBOL-PLIST ;; so now use TRULY-THE to avoid further type checking. (%compare-and-swap-car (%ensure-plist-holder (truly-the symbol symbol) - (symbol-info symbol)) + (symbol-%info symbol)) old new)) -(defun %set-symbol-plist (symbol new-value) - ;; This is the entry point into which (SETF SYMBOL-PLIST) is transformed. +(defun (setf symbol-plist) (new-value symbol) ;; If SYMBOL's info cell is a cons, we can do (SETF CAR). Otherwise punt. (declare (symbol symbol) (list new-value)) - (let ((cell (symbol-info symbol))) + (let ((cell (symbol-%info symbol))) (if (consp cell) (setf (car cell) new-value) - (%%set-symbol-plist symbol new-value)))) + (%set-symbol-plist symbol new-value)))) -(defun %%set-symbol-plist (symbol new-value) - ;; Same considerations as for %%COMPARE-AND-SWAP-SYMBOL-PLIST, +(defun %set-symbol-plist (symbol new-value) + ;; Same considerations as for %CAS-SYMBOL-PLIST, ;; with a slight efficiency hack: if the symbol has no plist holder cell ;; and the NEW-VALUE is NIL, try to avoid creating a holder cell. ;; Yet we must write something, because omitting a memory operation ;; could have a subtle effect in the presence of multi-threading. - (let ((info (symbol-info (truly-the symbol symbol)))) + (let ((info (symbol-%info (truly-the symbol symbol)))) (when (and (not new-value) (atom info)) ; try to treat this as a no-op - (let ((old (%compare-and-swap-symbol-info symbol info info))) + ;; INFO is either an INSTANCE (a PACKED-INFO) or NIL. + ;; Write the same thing back, to say we set the plist to NIL. + (let ((old (cas-symbol-%info symbol info info))) (if (eq old info) ; good enough - (return-from %%set-symbol-plist new-value) ; = nil + (return-from %set-symbol-plist new-value) ; = nil (setq info old)))) (setf (car (%ensure-plist-holder symbol info)) new-value))) @@ -293,14 +303,46 @@ distinct from the global value. Can also be SETF." "Return SYMBOL's name as a string." (symbol-name symbol)) +(define-symbol-macro *id->package* + (truly-the simple-vector + (sap-ref-lispobj (foreign-symbol-sap "lisp_package_vector" t) 0))) +(export '*id->package*) + (defun sb-xc:symbol-package (symbol) - "Return the package SYMBOL was interned in, or NIL if none." - (sb-xc:symbol-package symbol)) + "Return SYMBOL's home package, or NIL if none." + (let ((id (symbol-package-id symbol))) + (truly-the (or null package) + (if (= id +package-id-overflow+) + (values (info :symbol :package symbol)) + (aref *id->package* id))))) (defun %set-symbol-package (symbol package) (declare (type symbol symbol)) - (%set-symbol-package symbol package)) - + (let* ((new-id (cond ((not package) +package-id-none+) + ((package-id package)) + (t +package-id-overflow+))) + (old-id (symbol-package-id symbol)) + (name (symbol-name symbol))) + (with-pinned-objects (name) + (let ((name-bits (logior (ash new-id (- sb-vm:n-word-bits package-id-bits)) + (get-lisp-obj-address name)))) + (declare (ignorable name-bits)) + (when (= new-id +package-id-overflow+) ; put the package in the dbinfo + (setf (info :symbol :package symbol) package)) + #-compact-symbol (set-symbol-package-id symbol new-id) + #+compact-symbol + (with-pinned-objects (symbol) + (setf (sap-ref-word (int-sap (get-lisp-obj-address symbol)) + (- (ash sb-vm:symbol-name-slot sb-vm:word-shift) + sb-vm:other-pointer-lowtag)) + name-bits)))) + ;; CLEAR-INFO is inefficient, so try not to call it. + (when (and (= old-id +package-id-overflow+) (/= new-id +package-id-overflow+)) + (clear-info :symbol :package symbol)) + package)) + +;;; MAKE-SYMBOL is the external API, %MAKE-SYMBOL is the internal function receiving +;;; a known simple-string, and %%MAKE-SYMBOL is the primitive constructor. (defun make-symbol (string) "Make and return a new symbol with the STRING as its print name." (declare (type string string)) @@ -327,19 +369,26 @@ distinct from the global value. Can also be SETF." ;;; It's kinda useless to do that, though not technically forbidden. ;;; (It can produce a not-necessarily-self-evaluating keyword) -#+immobile-space (defun %make-symbol (kind name) (declare (ignorable kind) (type simple-string name)) - (set-header-data name sb-vm:+vector-shareable+) ; Set "logically read-only" bit - (if #-immobile-symbols - (or (eql kind 1) ; keyword - (and (eql kind 2) ; random interned symbol - (plusp (length name)) - (char= (char name 0) #\*) - (char= (char name (1- (length name))) #\*))) - #+immobile-symbols t ; always place them there - (truly-the (values symbol) (sb-vm::make-immobile-symbol name)) - (sb-vm::%%make-symbol name))) + ;; Avoid writing to the string header if it's already flagged as readonly, or off-heap. + (when (and (not (logtest (ash sb-vm:+vector-shareable+ 8) (get-header-data name))) + (sb-kernel::dynamic-space-obj-p name)) + (logior-array-flags name sb-vm:+vector-shareable+)) ; Set "logically read-only" bit + (let ((symbol + (truly-the symbol + #+immobile-symbols (sb-vm::make-immobile-symbol name) + #-immobile-space (sb-vm::%%make-symbol name) + #+(and immobile-space (not immobile-symbols)) + (if (or (eql kind 1) ; keyword + (and (eql kind 2) ; random interned symbol + (plusp (length name)) + (char= (char name 0) #\*) + (char= (char name (1- (length name))) #\*))) + (sb-vm::make-immobile-symbol name) + (sb-vm::%%make-symbol name))))) + (%set-symbol-package symbol nil) + symbol)) (defun get (symbol indicator &optional (default nil)) "Look on the property list of SYMBOL for the specified INDICATOR. If this @@ -448,8 +497,7 @@ distinct from the global value. Can also be SETF." (defun keywordp (object) "Return true if Object is a symbol in the \"KEYWORD\" package." - (and (symbolp object) - (eq (sb-xc:symbol-package object) *keyword-package*))) + (keywordp object)) ; transformed ;;;; GENSYM and friends @@ -458,25 +506,22 @@ distinct from the global value. Can also be SETF." (flet ((%symbol-nameify (prefix counter) (declare (string prefix)) - (if (typep counter '(and fixnum unsigned-byte)) + (if (and (typep prefix 'simple-base-string) + (typep counter '(and fixnum unsigned-byte))) (let ((s "")) - (declare (simple-string s)) + (declare (simple-base-string s)) (labels ((recurse (depth n) (multiple-value-bind (q r) (truncate n 10) (if (plusp q) (recurse (1+ depth) q) - (let ((et (if (or (base-string-p prefix) - #+sb-unicode ; no #'base-char-p - (every #'base-char-p prefix)) - 'base-char 'character))) - (setq s (make-string (+ (length prefix) depth) - :element-type et)) - (replace s prefix))) + (replace (setq s (make-string (+ (length prefix) depth) + :element-type 'base-char)) + (truly-the simple-base-string prefix))) (setf (char s (- (length s) depth)) (code-char (+ (char-code #\0) r))) s))) (recurse 1 counter))) - (with-simple-output-to-string (s) + (%with-output-to-string (s) (write-string prefix s) (%output-integer-in-base counter 10 s))))) @@ -564,3 +609,5 @@ distinct from the global value. Can also be SETF." :datum new-value :expected-type spec))))))) nil)) + +#+sb-thread (defun symbol-tls-index (x) (symbol-tls-index x)) ; necessary stub diff --git a/src/code/sysmacs.lisp b/src/code/sysmacs.lisp index 7fa4735634..d3f740782a 100644 --- a/src/code/sysmacs.lisp +++ b/src/code/sysmacs.lisp @@ -11,10 +11,11 @@ (in-package "SB-IMPL") -;;;; these are initialized by create_thread_struct() +;;;; these are initialized by alloc_thread_struct() (defvar *in-without-gcing*) (defvar *gc-inhibit*) +(defvar *gc-pin-code-pages*) ;;; When the dynamic usage increases beyond this amount, the system ;;; notes that a garbage collection needs to occur by setting @@ -25,11 +26,10 @@ #+sb-thread (defvar *stop-for-gc-pending*) -;;; This one is initialized by the runtime, at thread creation. On -;;; non-x86oid gencgc targets, this is a per-thread list of objects -;;; which must not be moved during GC. It is frobbed by the code for -;;; with-pinned-objects in src/compiler/target/macros.lisp. -#+(and gencgc (not (or x86 x86-64))) +;;; This one is initialized by the runtime, at thread creation. +;;; It is a per-thread list of objects which must not be moved during GC, +;;; and manipulated by WITH-PINNED-OBJECTS. +;;; If doesn't really do anything if #+cheneygc (defvar sb-vm::*pinned-objects*) (defmacro without-gcing (&body body) @@ -63,7 +63,7 @@ maintained." (*interrupts-enabled* nil) (*gc-inhibit* t)) (,without-gcing-body)) - ;; This is not racy becuase maybe_defer_handler + ;; This is not racy because can_hande_now() ;; defers signals if *GC-INHIBIT* is NIL but there ;; is a pending gc or stop-for-gc. (when (or *interrupt-pending* @@ -123,35 +123,6 @@ maintained." :format-control "~S isn't an output stream." :format-arguments (list ,svar))) ,svar))))) - -;;; WITH-mumble-STREAM calls the function in the given SLOT of the -;;; STREAM with the ARGS for ANSI-STREAMs, or the FUNCTION with the -;;; ARGS for FUNDAMENTAL-STREAMs. -(defmacro with-in-stream (stream (slot &rest args) &optional stream-dispatch) - `(let ((stream (in-stream-from-designator ,stream))) - ,(if stream-dispatch - `(if (ansi-stream-p stream) - (funcall (,slot stream) stream ,@args) - ,@(when stream-dispatch - `(,(destructuring-bind (function &rest args) stream-dispatch - `(,function stream ,@args))))) - `(funcall (,slot stream) stream ,@args)))) - -(defmacro %with-out-stream (stream (slot &rest args) &optional stream-dispatch) - `(let ((stream ,stream)) - ,(if stream-dispatch - `(if (ansi-stream-p stream) - (funcall (,slot stream) stream ,@args) - ,@(when stream-dispatch - `(,(destructuring-bind (function &rest args) stream-dispatch - `(,function stream ,@args))))) - `(funcall (,slot stream) stream ,@args)))) - -(defmacro with-out-stream (stream (slot &rest args) &optional stream-dispatch) - `(%with-out-stream (out-stream-from-designator ,stream) - (,slot ,@args) - ,stream-dispatch)) - ;;;; These are hacks to make the reader win. @@ -263,7 +234,7 @@ maintained." &body body) ;; If the &REST arg never needs to be reified, this is slightly quicker ;; than using a DX list. - (let ((index (sb-xc:gensym "INDEX"))) + (let ((index (gensym "INDEX"))) `(let ((,index ,start)) (loop (cond ((< (truly-the index ,index) (length ,rest-var)) diff --git a/src/code/target-alieneval.lisp b/src/code/target-alieneval.lisp index 1e1a07a1bc..cf3f3e4615 100644 --- a/src/code/target-alieneval.lisp +++ b/src/code/target-alieneval.lisp @@ -1,4 +1,4 @@ -;;;; This file contains parts of the ALIEN implementation that +;;;; This file contains parts of the Alien implementation that ;;;; are not part of the compiler. ;;;; This software is part of the SBCL system. See the README file for @@ -155,8 +155,8 @@ This is SETFable." (foreign-symbol-sap ,initial-value ,datap) 0 ,alien-type))) ,@body))) (:local - (let* ((var (sb-xc:gensym "VAR")) - (initval (if initial-value (sb-xc:gensym "INITVAL"))) + (let* ((var (gensym "VAR")) + (initval (if initial-value (gensym "INITVAL"))) (info (make-local-alien-info :type alien-type)) (inner-body `((note-local-alien-type ',info ,var) @@ -198,7 +198,7 @@ This is SETFable." :sap (sap-int (alien-value-sap value)) :type (unparse-alien-type (alien-value-type value))))) -#-sb-fluid (declaim (inline null-alien)) +(declaim (inline null-alien)) (defun null-alien (x) "Return true if X (which must be an ALIEN pointer) is null, false otherwise." (zerop (sap-int (alien-sap x)))) @@ -296,7 +296,7 @@ Examples: ;;; Allocate a block of memory at least BYTES bytes long and return a ;;; system area pointer to it. -#-sb-fluid (declaim (inline %make-alien)) +(declaim (inline %make-alien)) (defun %make-alien (bytes) (declare (type index bytes) (optimize (sb-c:alien-funcall-saves-fp-and-pc 0))) @@ -314,13 +314,13 @@ Examples: ;;; an invocation of INVOKE-WITH-SAVED-FP, which should be inlined. #+c-stack-is-control-stack (defun invoke-with-saved-fp (fn) - (declare #-sb-xc-host (muffle-conditions compiler-note) + (declare (muffle-conditions compiler-note) (optimize (speed 3))) ;; No need to link to the previous value, it can be fetched from the binding stack. (let ((*saved-fp* (sb-c::current-fp-fixnum))) (funcall fn))) -#-sb-fluid (declaim (inline free-alien)) +(declaim (inline free-alien)) (defun free-alien (alien) "Dispose of the storage pointed to by ALIEN. The ALIEN must have been allocated by MAKE-ALIEN, MAKE-ALIEN-STRING or malloc(3)." @@ -570,6 +570,42 @@ null byte." (unless (local-alien-info-force-to-memory-p info) (error "~S isn't forced to memory. Something went wrong." alien)) alien) + + +;;;; the ADDR macro + +(defmacro addr (expr &environment env) + "Return an Alien pointer to the data addressed by Expr, which must be a call + to SLOT or DEREF, or a reference to an Alien variable." + (let ((form (%macroexpand expr env))) + (or (typecase form + (cons + (case (car form) + (slot + (cons '%slot-addr (cdr form))) + (deref + (cons '%deref-addr (cdr form))) + (%heap-alien + (cons '%heap-alien-addr (cdr form))) + (local-alien + (let ((info (let ((info-arg (second form))) + (and (consp info-arg) + (eq (car info-arg) 'quote) + (second info-arg))))) + (unless (local-alien-info-p info) + (error "Something is wrong, LOCAL-ALIEN-INFO not found: ~S" + form)) + (setf (local-alien-info-force-to-memory-p info) t)) + (cons '%local-alien-addr (cdr form))))) + (symbol + (let ((kind (info :variable :kind form))) + (when (eq kind :alien) + `(%heap-alien-addr ',(info :variable :alien-info form)))))) + (error "~S is not a valid L-value." form)))) + +(push '("SB-ALIEN" define-alien-type-class define-alien-type-method) + *!removable-symbols*) + ;;;; the CAST macro @@ -679,7 +715,7 @@ type specifies the argument and result types." (let ((stub (alien-fun-type-stub type))) (unless stub (setf stub - (let ((fun (sb-xc:gensym "FUN")) + (let ((fun (gensym "FUN")) (parms (make-gensym-list (length args)))) (compile nil `(lambda (,fun ,@parms) @@ -731,8 +767,13 @@ way that the argument is passed. passed, with the object being initialized from the supplied argument and the return value being determined by accessing the object on return." - (multiple-value-bind (lisp-name alien-name) - (pick-lisp-and-alien-names name) + (binding* (((lisp-name alien-name) (pick-lisp-and-alien-names name)) + ;; The local name is uninterned so that we don't preclude + ;; (defconstant kill 9) + ;; (define-alien-routine "kill" int (pid int) (sig int)) + ;; which, if we didn't hide the local name, would get: + ;; "Attempt to bind a constant variable with SYMBOL-MACROLET: KILL" + (local-name (copy-symbol lisp-name))) (collect ((docs) (lisp-args) (lisp-arg-types) (lisp-result-types (cond ((eql result-type 'void) @@ -746,38 +787,41 @@ way that the argument is passed. (arg-types) (alien-vars) (alien-args) (results)) (dolist (arg args) - (if (stringp arg) - (docs arg) - (destructuring-bind (name type &optional (style :in)) arg - (unless (member style '(:in :copy :out :in-out)) - (error "bogus argument style ~S in ~S" style arg)) - (when (and (member style '(:out :in-out)) - (typep (parse-alien-type type lexenv) - 'alien-pointer-type)) - (error "can't use :OUT or :IN-OUT on pointer-like type:~% ~S" - type)) - (let (arg-type) - (cond ((eq style :in) - (setq arg-type type) - (alien-args name)) - (t - (setq arg-type `(* ,type)) - (if (eq style :out) - (alien-vars `(,name ,type)) - (alien-vars `(,name ,type ,name))) - (alien-args `(addr ,name)))) - (arg-types arg-type) - (unless (eq style :out) - (lisp-args name) - (lisp-arg-types t - ;; FIXME: It should be something - ;; like `(ALIEN ,ARG-TYPE), except - ;; for we also accept SAPs where - ;; pointers are required. - ))) - (when (or (eq style :out) (eq style :in-out)) - (results name) - (lisp-result-types `(alien ,type)))))) + (cond ((stringp arg) + (docs arg)) + ((eq arg '&optional) + (arg-types arg)) + (t + (destructuring-bind (name type &optional (style :in)) arg + (unless (member style '(:in :copy :out :in-out)) + (error "bogus argument style ~S in ~S" style arg)) + (when (and (member style '(:out :in-out)) + (typep (parse-alien-type type lexenv) + 'alien-pointer-type)) + (error "can't use :OUT or :IN-OUT on pointer-like type:~% ~S" + type)) + (let (arg-type) + (cond ((eq style :in) + (setq arg-type type) + (alien-args name)) + (t + (setq arg-type `(* ,type)) + (if (eq style :out) + (alien-vars `(,name ,type)) + (alien-vars `(,name ,type ,name))) + (alien-args `(addr ,name)))) + (arg-types arg-type) + (unless (eq style :out) + (lisp-args name) + (lisp-arg-types t + ;; FIXME: It should be something + ;; like `(ALIEN ,ARG-TYPE), except + ;; for we also accept SAPs where + ;; pointers are required. + ))) + (when (or (eq style :out) (eq style :in-out)) + (results name) + (lisp-result-types `(alien ,type))))))) `(progn ;; The theory behind this automatic DECLAIM is that (1) if ;; you're calling C, static typing is what you're doing @@ -790,13 +834,13 @@ way that the argument is passed. (defun ,lisp-name ,(lisp-args) ,@(docs) (with-alien - ((,lisp-name (function ,result-type ,@(arg-types)) + ((,local-name (function ,result-type ,@(arg-types)) :extern ,alien-name) ,@(alien-vars)) ,@(if (eq 'void result-type) - `((alien-funcall ,lisp-name ,@(alien-args)) + `((alien-funcall ,local-name ,@(alien-args)) (values nil ,@(results))) - `((values (alien-funcall ,lisp-name ,@(alien-args)) + `((values (alien-funcall ,local-name ,@(alien-args)) ,@(results)))))))))) (defun alien-typep (object type) diff --git a/src/code/target-allocate.lisp b/src/code/target-allocate.lisp deleted file mode 100644 index db16901c62..0000000000 --- a/src/code/target-allocate.lisp +++ /dev/null @@ -1,21 +0,0 @@ -;;;; system memory allocation - -;;;; This software is part of the SBCL system. See the README file for -;;;; more information. -;;;; -;;;; This software is derived from the CMU CL system, which was -;;;; written at Carnegie Mellon University and released into the -;;;; public domain. The software is in the public domain and is -;;;; provided with absolutely no warranty. See the COPYING and CREDITS -;;;; files for more information. - -(in-package "SB-KERNEL") - -(define-alien-routine ("os_allocate" allocate-system-memory) - system-area-pointer - (bytes unsigned)) - -(define-alien-routine ("os_deallocate" deallocate-system-memory) - void - (addr system-area-pointer) - (bytes unsigned)) diff --git a/src/code/target-char.lisp b/src/code/target-char.lisp index 4f254a219a..d890896402 100644 --- a/src/code/target-char.lisp +++ b/src/code/target-char.lisp @@ -12,21 +12,19 @@ (in-package "SB-IMPL") ;;; We compile some trivial character operations via inline expansion. -#-sb-fluid (declaim (inline standard-char-p graphic-char-p alpha-char-p alphanumericp)) (declaim (maybe-inline upper-case-p lower-case-p both-case-p digit-char-p)) (deftype char-code () - `(integer 0 (,sb-xc:char-code-limit))) - -(define-load-time-global **unicode-character-name-huffman-tree** ()) + `(integer 0 (,char-code-limit))) (declaim (inline pack-3-codepoints)) -(defun pack-3-codepoints (first &optional (second 0) (third 0)) - (declare (type (unsigned-byte 21) first second third)) - (sb-c::mask-signed-field 63 (logior first (ash second 21) (ash third 42)))) +(eval-when (:compile-toplevel :load-toplevel :execute) + (defun pack-3-codepoints (first &optional (second 0) (third 0)) + (declare (type (unsigned-byte 21) first second third)) + (sb-c::mask-signed-field 63 (logior first (ash second 21) (ash third 42))))) (defun unpack-3-codepoints (codepoints) (declare (type (signed-byte 63) codepoints)) @@ -40,103 +38,79 @@ (code-char (ldb (byte 21 21) codepoints)) (code-char (ldb (byte 21 (* 21 2)) codepoints)))))) +(declaim (inline clear-flag)) +(eval-when (:compile-toplevel :load-toplevel :execute) + (defun clear-flag (bit integer) + (logandc2 integer (ash 1 bit)))) + +(eval-when (:compile-toplevel) + (defconstant +misc-width+ 9) + (defmacro misc-index-from-char-code (codepoint high-pages low-pages) + `(let* ((cp ,codepoint) + (cp-high (ash cp -8)) + (high-index (aref ,high-pages cp-high))) + (if (logbitp 15 high-index) + (* ,+misc-width+ (clear-flag 15 high-index)) + (* ,+misc-width+ (aref ,low-pages (* 2 (+ (ldb (byte 8 0) cp) (ash high-index 8)))))))) + (setf (sb-xc:macro-function 'misc-index-from-char-code) + (lambda (form env) + (declare (ignore env)) + (funcall (cl:macro-function 'misc-index-from-char-code) form nil))) +) + (macrolet ((frob () - (flet ((coerce-it (array) - (sb-xc:coerce array '(simple-array (unsigned-byte 8) 1))) - (file (name type) - (let ((dir (sb-cold:prepend-genfile-path "output/"))) - (make-pathname :directory (pathname-directory (merge-pathnames dir)) - :name name :type type))) + (flet ((file (name type) + (sb-cold:find-bootstrap-file (format nil "output/~A.~A" name type))) (read-ub8-vector (pathname) (with-open-file (stream pathname :element-type '(unsigned-byte 8)) (let* ((length (file-length stream)) (array (sb-xc:make-array - length :element-type '(unsigned-byte 8)))) + length :element-type '(unsigned-byte 8) + :retain-specialization-for-after-xc-core t))) (read-sequence array stream) array))) - (init-global (name type &optional length) - `(progn - (define-load-time-global ,name - ,(if (eql type 'hash-table) - `(make-hash-table) - `(make-array ,length :element-type ',type))) - (declaim (type ,(if (eql type 'hash-table) - 'hash-table - `(simple-array ,type (,length))) ,name))))) - (let ((misc-database (read-ub8-vector (file "ucdmisc" "dat"))) + (make-ubn-vector (raw-bytes n) + (let* ((et (if (= n 3) + '(unsigned-byte 31) + `(unsigned-byte ,(* 8 n)))) + (array (sb-xc:make-array (/ (length raw-bytes) n) + :element-type et + :retain-specialization-for-after-xc-core t))) + (loop for i from 0 below (length raw-bytes) by n + do (loop with element = 0 + for offset from 0 below n + do (incf element (ash (aref raw-bytes (+ i offset)) + (* 8 (- n offset 1)))) + finally (setf (aref array (/ i n)) element))) + array))) + (let* ((misc-database (read-ub8-vector (file "ucdmisc" "dat"))) (ucd-high-pages (read-ub8-vector (file "ucdhigh" "dat"))) (ucd-low-pages (read-ub8-vector (file "ucdlow" "dat"))) (decompositions (read-ub8-vector (file "decomp" "dat"))) - (primary-compositions (read-ub8-vector (file "comp" "dat"))) (case-data (read-ub8-vector (file "case" "dat"))) (case-pages (read-ub8-vector (file "casepages" "dat"))) - (collations (read-ub8-vector (file "collation" "dat")))) + (high-pages (make-ubn-vector ucd-high-pages 2)) + (low-pages (make-ubn-vector ucd-low-pages 2)) + (%*character-case-pages*% (make-ubn-vector case-pages 1))) + `(progn - ;; KLUDGE: All temporary values, fixed up in cold-load - ,(init-global '**character-misc-database** '(unsigned-byte 8) - (length misc-database)) - ,(init-global '**character-high-pages** '(unsigned-byte 16) - (/ (length ucd-high-pages) 2)) - ,(init-global '**character-low-pages** '(unsigned-byte 16) - (/ (length ucd-low-pages) 2)) - ,(init-global '**character-decompositions** '(unsigned-byte 21) - (/ (length decompositions) 3)) - ,(init-global '**character-case-pages** '(unsigned-byte 8) - (length case-pages)) - ,(init-global '**character-primary-compositions** 'hash-table) - ,(init-global '**character-unicode-cases** t - (* 64 (1+ (aref case-pages - (1- (length case-pages)))))) - ,(init-global '**character-cases** '(unsigned-byte 32) - (* 2 64 (1+ (aref case-pages - (1- (length case-pages)))))) - ,(init-global '**character-collations** 'hash-table) - - (defun !character-database-cold-init () - (flet ((make-ubn-vector (raw-bytes n) - (let ((new-array - (make-array - (/ (length raw-bytes) n) - :element-type `(unsigned-byte ,(* 8 n))))) - (loop for i from 0 below (length raw-bytes) by n - for element = 0 do - (loop for offset from 0 below n do - (incf element - (ash (aref raw-bytes (+ i offset)) - (* 8 (- n offset 1))))) - (setf (aref new-array (/ i n)) element)) - new-array))) - (setf **character-misc-database** - ,misc-database - **character-high-pages** - (make-ubn-vector ,ucd-high-pages 2) - **character-low-pages** - (make-ubn-vector ,ucd-low-pages 2) - **character-case-pages** - ,(coerce-it case-pages) - **character-decompositions** - (make-ubn-vector ,decompositions 3)) - - (setf **character-primary-compositions** - (let* ((info (make-ubn-vector ,primary-compositions 3)) - (table (make-hash-table #+64-bit :test #+64-bit #'eq - :size (/ (length info) 3)))) - (dotimes (i (/ (length info) 3)) - (setf (gethash (dpb (aref info (* 3 i)) (byte 21 21) - (aref info (1+ (* 3 i)))) - table) - (aref info (+ (* 3 i) 2)))) - table)) - - (let* ((unicode-table + (defconstant-eqx sb-unicode::+character-misc-database+ ,misc-database #'equalp) + (defconstant-eqx sb-unicode::+character-high-pages+ ,high-pages #'equalp) + (defconstant-eqx sb-unicode::+character-low-pages+ ,low-pages #'equalp) + (defconstant-eqx sb-unicode::+character-decompositions+ + ,(make-ubn-vector decompositions 3) #'equalp) + (defconstant-eqx +character-case-pages+ ,%*character-case-pages*% #'equalp) + ,@(let* ((unicode-table (make-array - (* 64 (1+ (aref **character-case-pages** - (1- (length **character-case-pages**))))))) - (table (make-array + (* 64 (1+ (aref %*character-case-pages*% + (1- (length %*character-case-pages*%))))) + :initial-element 0)) + (table (sb-xc:make-array (* 2 (length unicode-table)) + :retain-specialization-for-after-xc-core t :element-type '(unsigned-byte 32))) - (info ,case-data) + (info case-data) (index 0) (length (length info))) (labels ((read-codepoint () @@ -154,72 +128,38 @@ (t (dotimes (i len) (push (read-codepoint) ret)) - (nreverse ret)))))) - (loop until (>= index length) - for key = (read-codepoint) - for upper = (read-length-tagged) - for lower = (read-length-tagged) - for page = (aref **character-case-pages** (ash key -6)) - for i = (+ (ash page 6) (ldb (byte 6 0) key)) - do - (setf (aref unicode-table i) - (if (or (consp upper) - (consp lower)) - (cons upper lower) - (dpb upper (byte 21 21) lower))) - when - (flet (#+sb-unicode - (both-case-p (code) - (logbitp 7 (aref **character-misc-database** - (+ 5 (misc-index (code-char code))))))) - (and (atom upper) - (atom lower) - ;; Some characters are only equal under unicode rules, - ;; e.g. #\MICRO_SIGN and #\GREEK_CAPITAL_LETTER_MU - #+sb-unicode - (both-case-p lower) - #+sb-unicode - (both-case-p upper))) - do - (setf (aref table (* i 2)) lower - (aref table (1+ (* i 2))) upper))) - (setf **character-unicode-cases** unicode-table) - (setf **character-cases** table)) - - (setf **character-collations** - (let* ((n-entries - ,(let ((n-entries-file (file "n-collation-entries" "lisp-expr"))) - (with-open-file (s n-entries-file) - (read s)))) - (table (make-hash-table :size n-entries - #+64-bit :test #+64-bit #'eq)) - (index 0) - (info (make-ubn-vector ,collations 4)) - (len (length info))) - (loop while (< index len) do - (let* ((entry-head (aref info index)) - (cp-length (ldb (byte 4 28) entry-head)) - (key-length (ldb (byte 5 23) entry-head)) - (key 0) - (codepoints nil)) - (aver (and (/= cp-length 0) (/= key-length 0))) - (loop repeat cp-length do - (push (dpb 0 (byte 10 22) (aref info index)) - codepoints) - (incf index)) - (setf codepoints (nreverse codepoints)) - (dotimes (i key-length) - (setf (ldb (byte 32 (* i 32)) key) (aref info index)) - (incf index)) - ;; verify the validity of - ;; :test 'eq on 64-bit - #+64-bit (aver (typep (apply #'pack-3-codepoints codepoints) 'fixnum)) - (setf (gethash (apply #'pack-3-codepoints codepoints) table) - key))) - (aver (= (hash-table-count table) n-entries)) - table)))) - - ,(with-open-file + (nreverse ret))))) + #+sb-unicode + (both-case-p-local (code) + (logbitp 7 (aref misc-database + (+ 5 (misc-index-from-char-code + code high-pages low-pages)))))) + (loop + until (>= index length) + do (let* ((key (read-codepoint)) + (upper (read-length-tagged)) + (lower (read-length-tagged)) + (page (aref %*character-case-pages*% (ash key -6))) + (i (+ (ash page 6) (ldb (byte 6 0) key)))) + (setf (aref unicode-table i) + (if (or (consp upper) + (consp lower)) + (cons upper lower) + (dpb upper (byte 21 21) lower))) + (when (and (atom upper) + (atom lower) + ;; Some characters are only equal under unicode rules, + ;; e.g. #\MICRO_SIGN and #\GREEK_CAPITAL_LETTER_MU + #+sb-unicode + (both-case-p-local lower) + #+sb-unicode + (both-case-p-local upper)) + (setf (aref table (* i 2)) lower + (aref table (1+ (* i 2))) upper))))) + `((defconstant-eqx +character-unicode-cases+ ,unicode-table #'equalp) + (defconstant-eqx +character-cases+ ,table #'equalp))) + + ,@(with-open-file (stream (file "ucd-names" "lisp-expr")) (with-open-file (u1-stream (file "ucd1-names" "lisp-expr")) (flet ((convert-to-double-vector (vector &optional reversed) @@ -282,28 +222,18 @@ (sort (copy-seq code->u1-name) #'< :key #'cdr) code->u1-name (sort (copy-seq u1-name->code) #'< :key #'car)) - `(progn - ,(init-global '**unicode-char-name-database** t - (* 2 (length code->name))) - ,(init-global '**unicode-name-char-database** t - (* 2 (length name->code))) - ,(init-global '**unicode-1-char-name-database** t - (* 2 (length code->u1-name))) - ,(init-global '**unicode-1-name-char-database** t - (* 2 (length u1-name->code))) - (defun !character-name-database-cold-init () - (setf **unicode-character-name-huffman-tree** ',tree - **unicode-char-name-database** - ',(convert-to-double-vector code->name) - **unicode-name-char-database** - ',(convert-to-double-vector name->code t) - **unicode-1-char-name-database** - ',(convert-to-double-vector code->u1-name) - **unicode-1-name-char-database** - ',(convert-to-double-vector u1-name->code t)))))))))))))) + `((defconstant-eqx +unicode-char-name-database+ + ,(convert-to-double-vector code->name) #'equalp) + (defconstant-eqx +unicode-name-char-database+ + ,(convert-to-double-vector name->code t) #'equalp) + (defconstant-eqx sb-unicode::+unicode-1-char-name-database+ + ,(convert-to-double-vector code->u1-name) #'equalp) + (defconstant-eqx +unicode-1-name-char-database+ + ,(convert-to-double-vector u1-name->code t) #'equalp) + (defconstant-eqx sb-unicode::+unicode-character-name-huffman-tree+ + ',tree #'equal)))))))))))) (frob)) -#+sb-xc-host (!character-name-database-cold-init) (define-load-time-global *base-char-name-alist* ;; Note: The *** markers here indicate character names which are @@ -380,8 +310,8 @@ ;;;; UCD accessor functions ;;; The character database is made of several arrays. -;;; **CHARACTER-MISC-DATABASE** is an array of bytes that encode character -;;; attributes. Each entry in the misc database is +misc-width+ (currently 8) +;;; +CHARACTER-MISC-DATABASE+ is an array of bytes that encode character +;;; attributes. Each entry in the misc database is +MISC-WIDTH+ (currently 9) ;;; bytes wide. Within each entry, the bytes represent: general category, BIDI ;;; class, canonical combining class, digit value, decomposition info, other ;;; flags, script, line break class, and age, respectively. Several of the @@ -400,23 +330,23 @@ ;;; the minor version in bits 0-2, and the major version in the remaining 5 ;;; bits. ;;; -;;; To find which entry in **CHARACTER-MISC-DATABASE** encodes a character's -;;; attributes, first index **CHARACTER-HIGH-PAGES** (an array of 16-bit +;;; To find which entry in +CHARACTER-MISC-DATABASE+ encodes a character's +;;; attributes, first index +CHARACTER-HIGH-PAGES+ (an array of 16-bit ;;; values) with the high 13 bits of the character's codepoint. If the result ;;; value has its high bit set, the character is in a "compressed page". To ;;; find the misc entry number, simply clear the high bit. If the high bit is ;;; not set, the misc entry number must be looked up in -;;; **CHARACTER-LOW-PAGES**, which is an array of 16-bit values. Each entry in +;;; +CHARACTER-LOW-PAGES+, which is an array of 16-bit values. Each entry in ;;; the array consists of two such values, the misc entry number and the ;;; decomposition index. To find the misc entry number, index into -;;; **CHARACTER-LOW-PAGES** using the value retreived from -;;; **CHARACTER-HIGH-PAGES** (shifted left 8 bits) plus the low 8 bits of the +;;; +CHARACTER-LOW-PAGES+ using the value retreived from +;;; +CHARACTER-HIGH-PAGES+ (shifted left 8 bits) plus the low 8 bits of the ;;; codepoint, all times two to account for the widtth of the entries. The -;;; value in **CHARACTER-LOW-PAGES** at this point is the misc entry number. To +;;; value in +CHARACTER-LOW-PAGES+ at this point is the misc entry number. To ;;; transform a misc entry number into an index into -;;; **CHARACTER-MISC-DATABASE**, multiply it by +misc-width*. This gives the +;;; +CHARACTER-MISC-DATABASE+, multiply it by +MISC-WIDTH+. This gives the ;;; index of the start of the charater's misc entry in -;;; **CHARACTER-MISC-DATABASE**. +;;; +CHARACTER-MISC-DATABASE+. ;;; ;;; To look up a character's decomposition, first retreive its ;;; decomposition-info from the misc database as described above. If the @@ -430,7 +360,7 @@ ;;; index, are the decomposition of the character. This proceduce does not ;;; apply to Hangul syllables, which have their own decomposition algorithm. ;;; -;;; Case information is stored in **CHARACTER-UNICODE-CASES**, an array that +;;; Case information is stored in +CHARACTER-UNICODE-CASES+, an array that ;;; indirectly maps a character's codepoint to (cons uppercase ;;; lowercase). Uppercase and lowercase are either a single codepoint, ;;; which is the upper- or lower-case of the given character, or a @@ -438,7 +368,7 @@ ;;; lower-case. These case lists are only used in Unicode case ;;; transformations, not in Common Lisp ones. ;;; -;;; **CHARACTER-CASES** is similar to the above but it stores codes in +;;; +CHARACTER-CASES+ is similar to the above but it stores codes in ;;; a flat array twice as large, and it includes only the standard casing rules, ;;; so there's always just two characters. ;;; @@ -446,30 +376,19 @@ ;;; which is a hash table of codepoints indexed by (+ (ash codepoint1 21) ;;; codepoint2). -(declaim (inline clear-flag)) -(defun clear-flag (bit integer) - (logandc2 integer (ash 1 bit))) - -(defconstant +misc-width+ 9) - (declaim (ftype (sfunction (t) (unsigned-byte 16)) misc-index)) (defun misc-index (char) - (let* ((cp (char-code char)) - (cp-high (ash cp -8)) - (high-index (aref **character-high-pages** cp-high))) - (if (logbitp 15 high-index) - (* +misc-width+ (clear-flag 15 high-index)) - (* +misc-width+ - (aref **character-low-pages** - (* 2 (+ (ldb (byte 8 0) cp) (ash high-index 8)))))))) + (misc-index-from-char-code (char-code char) + sb-unicode::+character-high-pages+ + sb-unicode::+character-low-pages+)) (declaim (ftype (sfunction (t) (unsigned-byte 8)) ucd-general-category) (inline ucd-general-category)) (defun ucd-general-category (char) - (aref **character-misc-database** (misc-index char))) + (aref sb-unicode::+character-misc-database+ (misc-index char))) (defun ucd-decimal-digit (char) - (let ((digit (aref **character-misc-database** + (let ((digit (aref sb-unicode::+character-misc-database+ (+ 3 (misc-index char))))) (when (logbitp 6 digit) ; decimalp flag (ldb (byte 4 0) digit)))) @@ -515,10 +434,10 @@ strings and symbols of length 1." (let ((char-code (char-code char))) (or (second (assoc char-code *base-char-name-alist*)) (let ((h-code (double-vector-binary-search char-code - **unicode-char-name-database**))) + +unicode-char-name-database+))) (cond (h-code - (huffman-decode h-code **unicode-character-name-huffman-tree**)) + (huffman-decode h-code sb-unicode::+unicode-character-name-huffman-tree+)) (t (format nil "U~X" char-code))))))) @@ -541,14 +460,14 @@ name is that string, if one exists. Otherwise, NIL is returned." (code-char (parse-integer name :start start :radix 16))))) (t (let ((encoding (huffman-encode (string-upcase name) - **unicode-character-name-huffman-tree**))) + sb-unicode::+unicode-character-name-huffman-tree+))) (when encoding (let ((char-code (or (double-vector-binary-search encoding - **unicode-name-char-database**) + +unicode-name-char-database+) (double-vector-binary-search encoding - **unicode-1-name-char-database**)))) + +unicode-1-name-char-database+)))) (and char-code (code-char char-code))))))))) @@ -583,20 +502,19 @@ argument is an alphabetic character, A-Z or a-z; otherwise NIL." (defmacro with-case-info ((char index-var cases-var &key miss-value - (cases '**character-cases**) - (case-pages '**character-case-pages**)) + (cases +character-cases+)) &body body) (let ((code-var (gensym "CODE")) (shifted-var (gensym "SHIFTED")) (page-var (gensym "PAGE"))) `(block nil (locally - (declare (optimize (sb-c::insert-array-bounds-checks 0))) + (declare (optimize (sb-c:insert-array-bounds-checks 0))) (let ((,code-var (char-code ,char))) (let* ((,shifted-var (ash ,code-var -6)) - (,page-var (if (>= ,shifted-var (length **character-case-pages**)) + (,page-var (if (>= ,shifted-var ,(length +character-case-pages+)) (return ,miss-value) - (aref ,case-pages ,shifted-var)))) + (aref ,+character-case-pages+ ,shifted-var)))) (if (= ,page-var 255) ,miss-value (let ((,index-var (* (+ (ash ,page-var 6) @@ -661,10 +579,10 @@ is either numeric or alphabetic." (declaim (inline char-case-info)) (defun char-case-info (character) (let* ((code (char-code character)) - (page (aref **character-case-pages** (ash code -6)))) + (page (aref +character-case-pages+ (ash code -6)))) ;; Pages with 255 means the character is not both-case. - ;; **character-cases** has 0 for those characters. - (aref **character-unicode-cases** + ;; +CHARACTER-CASES+ has 0 for those characters. + (aref +character-unicode-cases+ (+ (ash page 6) (ldb (byte 6 0) code))))) @@ -673,13 +591,13 @@ is either numeric or alphabetic." (defun equal-char-code (char) (let* ((code (char-code char)) (shifted (ash code -6)) - (page (if (>= shifted (length **character-case-pages**)) + (page (if (>= shifted (length +character-case-pages+)) (return-from equal-char-code code) - (aref **character-case-pages** shifted)))) + (aref #.+character-case-pages+ shifted)))) (if (= page 255) code (let ((down-code - (aref **character-cases** + (aref #.+character-cases+ (* (+ (ash page 6) (ldb (byte 6 0) code)) 2)))) diff --git a/src/code/target-defstruct.lisp b/src/code/target-defstruct.lisp index d23030bbb4..13f0af751c 100644 --- a/src/code/target-defstruct.lisp +++ b/src/code/target-defstruct.lisp @@ -13,36 +13,225 @@ ;;;; structure frobbing primitives +;;; For lack of any better to place to write up some detail surrounding +;;; layout creation for structure types, I'm putting here. +;;; When you issue a DEFSTRUCT at the REPL, there are *three* instances +;;; of LAYOUT makde for the new structure. +;;; 1) The first is one associated with a temporary instance of +;;; structure-classoid used in parsing the DEFSTRUCT form so that +;;; we don't signal an UNKNOWN-TYPE condition for something like: +;;; (defstruct chain (next nil :type (or null chain)). +;;; The temporary classoid is garbage immediately after parsing +;;; and is never installed. +;;; 2) The next is the actual LAYOUT that ends up being registered. +;;; 3) The third is a layout created when setting the "compiler layout" +;;; which contains copies of the length/depthoid/inherits etc +;;; that we compare against the installed one to make sure they match. +;;; The third one also gets thrown away. +(define-load-time-global *layout-id-generator* (cons 0 nil)) +(declaim (type (cons fixnum) *layout-id-generator*)) +;;; NB: for #+metaspace this returns a WRAPPER, not a LAYOUT. +(defun make-layout (clos-hash classoid + &key (depthoid -1) (length 0) (flags 0) + (inherits #()) + (info nil) + (bitmap (if info (dd-bitmap info) 0)) + (invalid :uninitialized) + &aux (id (or (atomic-pop (cdr *layout-id-generator*)) + (atomic-incf (car *layout-id-generator*))))) + (unless (typep id '(and layout-id (not (eql 0)))) + (error "Layout ID limit reached")) + (let* ((fixed-words (type-dd-length sb-vm:layout)) + (extra-id-words ; count of additional words needed to store ancestors + (if (logtest flags +structure-layout-flag+) + (calculate-extra-id-words depthoid) + 0)) + (bitmap-words (ceiling (1+ (integer-length bitmap)) sb-vm:n-word-bits)) + (nwords (+ fixed-words extra-id-words bitmap-words)) + (layout + (truly-the sb-vm:layout + #-(or metaspace immobile-space) (%make-instance/mixed nwords) + #+metaspace (sb-vm::allocate-metaspace-chunk (1+ nwords)) + #+(and immobile-space (not metaspace)) + (sb-vm::alloc-immobile-fixedobj + (1+ nwords) + (logior (ash nwords sb-vm:instance-length-shift) + sb-vm:instance-widetag)))) + (wrapper #-metaspace layout)) + (%set-instance-layout layout + (wrapper-friend #.(find-layout #+metaspace 'sb-vm:layout + #-metaspace 'wrapper))) + #+metaspace + (setf wrapper (%make-wrapper :clos-hash clos-hash :classoid classoid + :%info info :invalid invalid :friend layout) + (layout-friend layout) wrapper) + (setf (layout-flags layout) #+64-bit (pack-layout-flags depthoid length flags) + #-64-bit flags) + (setf (layout-clos-hash layout) clos-hash + (wrapper-classoid wrapper) classoid + (wrapper-invalid wrapper) invalid) + #-64-bit (setf (wrapper-depthoid wrapper) depthoid + (wrapper-length wrapper) length) + #-metaspace (setf (wrapper-%info wrapper) info ; already set if #+metaspace + (wrapper-slot-table wrapper) #(1 nil)) + (set-layout-inherits wrapper inherits (logtest flags +structure-layout-flag+) id) + (let ((bitmap-base (+ fixed-words extra-id-words))) + (dotimes (i bitmap-words) + (%raw-instance-set/word layout (+ bitmap-base i) + (ldb (byte sb-vm:n-word-bits (* i sb-vm:n-word-bits)) bitmap)))) + (aver (= (%layout-bitmap layout) bitmap)) ; verify it reads back the same + ;; It's not terribly important that we recycle layout IDs, but I have some other + ;; changes planned that warrant a finalizer per layout. + ;; FIXME: structure IDs should never be recycled because code blobs referencing + ;; th ID do not reference the layout, and so the layout could be GCd allowing + ;; reuse of an old ID for a new type. + (unless (built-in-classoid-p classoid) + (let ((layout-addr (- (get-lisp-obj-address layout) sb-vm:instance-pointer-lowtag))) + (declare (ignorable layout-addr)) + (finalize wrapper + (lambda () + #+metaspace (sb-vm::unallocate-metaspace-chunk layout-addr) + (atomic-push id (cdr *layout-id-generator*))) + :dont-save t))) + ;; Rather than add and delete this line of debugging which I've done so many times, + ;; let's instead keep it but commented out. + #+nil + (alien-funcall (extern-alien "printf" (function void system-area-pointer unsigned unsigned + unsigned system-area-pointer)) + (vector-sap #.(format nil "New wrapper ID=%d %p %p '%s'~%")) + id (get-lisp-obj-address layout) (get-lisp-obj-address wrapper) + (vector-sap (string (classoid-name classoid)))) + wrapper)) + +#+metaspace +(defun make-temporary-wrapper (clos-hash classoid inherits) + (let* ((layout (%make-temporary-layout #.(find-layout t) clos-hash)) + (wrapper (%make-wrapper :clos-hash clos-hash :classoid classoid + :inherits inherits :invalid nil + :friend layout))) + (setf (layout-friend layout) wrapper) + wrapper)) + +;;; This allocator is used by the expansion of MAKE-LOAD-FORM-SAVING-SLOTS +;;; when given a STRUCTURE-OBJECT. +(defun allocate-struct (type) + (let* ((wrapper (classoid-wrapper (the structure-classoid (find-classoid type)))) + (dd (wrapper-dd wrapper)) + (structure (let ((len (wrapper-length wrapper))) + (if (dd-has-raw-slot-p dd) + (%make-instance/mixed len) + (%make-instance len))))) + (%set-instance-layout structure wrapper) + (dolist (dsd (dd-slots dd) structure) + (when (eq (dsd-raw-type dsd) 't) + (%instance-set structure (dsd-index dsd) (make-unbound-marker)))))) + ;;; Return the value from the INDEXth slot of INSTANCE. This is SETFable. ;;; This is used right away in warm compile by MAKE-LOAD-FORM-SAVING-SLOTS, ;;; so without it already defined, you can't define it, because you can't dump ;;; debug info structures. Were it not for that, this would go in 'stubs'. (defun %instance-ref (instance index) (%instance-ref instance index)) +(defun (setf %instance-ref) (newval instance index) + (%instance-set instance index newval) + newval) + +(macrolet ((define-raw-slot-accessors () + `(progn + ,@(map 'list + (lambda (rsd) + (let* ((reader (sb-kernel::raw-slot-data-reader-name rsd)) + (writer (sb-kernel::raw-slot-data-writer-name rsd)) + (type (sb-kernel::raw-slot-data-raw-type rsd))) + `(progn + (defun ,reader (instance index) (,reader instance index)) + ;; create a well-behaving SETF-compatible slot setter + (defun (setf ,reader) (newval instance index) + (declare (,type newval)) + (,writer instance index newval) + newval) + ;; .. and a non-SETF-compatible one + (defun ,writer (instance index newval) + (declare (,type newval)) + (,writer instance index newval) + (values))))) + sb-kernel::*raw-slot-data*)))) + (define-raw-slot-accessors)) + +(macrolet ((id-bits-sap () + `(sap+ (int-sap (get-lisp-obj-address layout)) + ,(- (sb-vm::id-bits-offset) sb-vm:instance-pointer-lowtag)))) +(defun layout-id (layout) + ;; If a structure type at depthoid >= 2, then fetch the INDEXth id + ;; where INDEX is depthoid - 2. Otherwise fetch the 0th id. + ;; There are a few non-structure types at positive depthoid; those do not store + ;; their ancestors in the vector; they only store self-id at index 0. + ;; This isn't performance-critical. If it were, then we should store self-ID + ;; at a fixed index. Using it for type-based dispatch remains a possibility. + (let* ((layout (cond #+metaspace ((typep layout 'wrapper) (wrapper-friend layout)) + (t layout))) + (depth (- (sb-vm::layout-depthoid layout) 2)) + (index (if (or (< depth 0) (not (logtest (layout-flags layout) + +structure-layout-flag+))) + 0 depth))) + (truly-the layout-id + #-64-bit (%raw-instance-ref/signed-word + layout (+ (get-dsd-index sb-vm:layout id-word0) index)) + #+64-bit ; use SAP-ref for lack of half-sized slots + (with-pinned-objects (layout) + (signed-sap-ref-32 (id-bits-sap) (ash index 2)))))) + +(defun set-layout-inherits (wrapper inherits structurep this-id + &aux (layout (wrapper-friend wrapper))) + (setf (wrapper-inherits wrapper) inherits) + ;;; If structurep, and *only* if, store all the inherited layout IDs. + ;;; It looks enticing to try to always store "something", but that goes wrong, + ;;; because only structure-object layouts are growable, and only structure-object + ;;; can store the self-ID in the proper index. + ;;; If the depthoid is -1, the self-ID has to go in index 0. + ;;; Standard-object layouts are not growable. The inherited layouts are known + ;;; only at class finalization time, at which point we've already made the layout. + ;;; Hence, the required indirection to the simple-vector of inherits. + (with-pinned-objects (layout) + ;; The layout-id vector is an array of int32_t starting at the ID-WORD0 slot. + ;; We could use (SETF %RAW-INSTANCE-REF/WORD) for 32-bit architectures, + ;; but on 64-bit we have to use SAP-REF, so may as well be consistent here + ;; and use a SAP either way. + (let ((sap (id-bits-sap))) + (cond (structurep + (loop for i from 0 by 4 + for j from 2 below (length inherits) ; skip T and STRUCTURE-OBJECT + do (setf (signed-sap-ref-32 sap i) (layout-id (svref inherits j))) + finally (setf (signed-sap-ref-32 sap i) this-id))) + ((not (eql this-id 0)) + (setf (signed-sap-ref-32 sap 0) this-id)))))) +) ; end MACROLET ;;; Normally IR2 converted, definition needed for interpreted structure ;;; constructors only. +;;; [Hmm, do we correctly type-check in the call to the constructor? +;;; Because this sure as heck doesn't check anything] #+(or sb-eval sb-fasteval) (defun %make-structure-instance (dd slot-specs &rest slot-values) - (let ((instance (%make-instance (dd-length dd))) ; length = sans header word + (let ((instance (let ((len (dd-length dd))) ; # of words excluding the header + (if (dd-has-raw-slot-p dd) + (%make-instance/mixed len) + (%make-instance len)))) (value-index 0)) (declare (index value-index)) - (setf (%instance-layout instance) (dd-layout-or-lose dd)) + (%set-instance-layout instance (dd-layout-or-lose dd)) (dolist (spec slot-specs instance) (destructuring-bind (kind raw-type . index) spec (if (eq kind :unbound) - (setf (%instance-ref instance index) - (sb-sys:%primitive make-unbound-marker)) + (%instance-set instance index (make-unbound-marker)) (macrolet ((make-case () `(ecase raw-type - ((t) - (setf (%instance-ref instance index) value)) + ((t) (%instance-set instance index value)) ,@(map 'list (lambda (rsd) `(,(raw-slot-data-raw-type rsd) - (setf (,(raw-slot-data-accessor-name rsd) - instance index) - value))) + (,(raw-slot-data-writer-name rsd) + instance index value))) *raw-slot-data*)))) (let ((value (fast-&rest-nth value-index slot-values))) (incf value-index) @@ -53,108 +242,138 @@ ;;; A list of hooks designating functions of one argument, the ;;; classoid, to be called when a defstruct is evaluated. -(!define-load-time-global *defstruct-hooks* nil) +(define-load-time-global *defstruct-hooks* nil) ;;; the part of %DEFSTRUCT which makes sense only on the target SBCL ;;; -(defun %target-defstruct (dd) +(defmacro set-wrapper-equalp-impl (wrapper newval) + `(%instance-set ,wrapper (get-dsd-index wrapper equalp-impl) ,newval)) + +(defun assign-equalp-impl (type-name function) + (set-wrapper-equalp-impl (find-layout type-name) function)) + +;;; This variable is just a somewhat hokey way to pass additional +;;; arguments to the defstruct hook (which renders the structure definition +;;; into a CLOS class) without having to figure out some means of stashing +;;; functions in the DD or DD for the structure. +(defvar *struct-accesss-fragments* nil) +(define-load-time-global *struct-accesss-fragments-delayed* nil) + +(defun !bootstrap-defstruct-hook (classoid) + ;; I hate this, but do whatever it takes... + ;; A better approach might be to write the correct data + ;; into the LAYOUT-SLOT-TABLE now. + ;; (I think that's where the code fragments end up) + (unless (member (classoid-name classoid) '(pathname condition)) ; KLUDGE + (push (cons (classoid-name classoid) *struct-accesss-fragments*) + *struct-accesss-fragments-delayed*))) + +(defun %target-defstruct (dd equalp &rest accessors) (declare (type defstruct-description dd)) (when (dd-doc dd) - (setf (documentation (dd-name dd) 'structure) - (dd-doc dd))) + (setf (documentation (dd-name dd) 'structure) (dd-doc dd))) - (let* ((classoid (find-classoid (dd-name dd))) - (layout (classoid-layout classoid))) - ;; Make a vector of EQUALP slots comparators, indexed by (- word-index data-start). - ;; This has to be assigned to something regardless of whether there are - ;; raw slots just in case someone mutates a layout which had raw - ;; slots into one which does not - although that would probably crash - ;; unless no instances exist or all raw slots miraculously contained - ;; bits which were the equivalent of valid Lisp descriptors. - (setf (layout-equalp-tests layout) - (if (eql (layout-bitmap layout) +layout-all-tagged+) - #() - ;; The initial element of NIL means "do not compare". - ;; Ignored words (comparator = NIL) fall into two categories: - ;; - pseudo-ignored, which get compared by their - ;; predecessor word, as for complex-double-float, - ;; - internal padding words which are truly ignored. - ;; Other words are compared as tagged if the comparator is 0, - ;; or as untagged if the comparator is a type-specific function. - (let ((comparators + (let ((classoid (find-classoid (dd-name dd)))) + (let ((layout (classoid-wrapper classoid))) + (set-wrapper-equalp-impl + layout + (cond ((compiled-function-p equalp) equalp) + ((eql (dd-bitmap dd) +layout-all-tagged+) #'sb-impl::instance-equalp) + (t + ;; Make a vector of EQUALP slots comparators, indexed by + ;; (- word-index INSTANCE-DATA-START). + ;; The initial element of NIL means "do not compare". + ;; Ignored words (comparator = NIL) fall into two categories: + ;; - pseudo-ignored, which get compared by their + ;; predecessor word, as for complex-double-float, + ;; - internal padding words which are truly ignored. + ;; Other words are compared as tagged if the comparator is 0, + ;; or as untagged if the comparator is a type-specific function. + (let ((comparators ;; If data-start is 1, subtract 1 because we don't need ;; a comparator for the LAYOUT slot. (make-array (- (dd-length dd) sb-vm:instance-data-start) :initial-element nil))) - (dolist (slot (dd-slots dd) comparators) - ;; -1 because LAYOUT (slot index 0) has no comparator stored. - (setf (aref comparators - (- (dsd-index slot) sb-vm:instance-data-start)) - (let ((rsd (dsd-raw-slot-data slot))) - (if (not rsd) - 0 ; means recurse using EQUALP - (raw-slot-data-comparator rsd)))))))) + (dolist (slot (dd-slots dd) comparators) + (setf (aref comparators + (- (dsd-index slot) sb-vm:instance-data-start)) + (let ((rsd (dsd-raw-slot-data slot))) + (if (not rsd) + 0 ; means recurse using EQUALP + (raw-slot-data-comparator rsd))))) + (lambda (a b) + (sb-impl::instance-equalp* comparators a b))))))) - (dolist (fun *defstruct-hooks*) - (funcall fun classoid))) + (let ((*struct-accesss-fragments* accessors)) + (dolist (fun *defstruct-hooks*) + (funcall fun classoid)))) (dd-name dd)) +(defun !target-defstruct-altmetaclass (dd &rest accessors) + (declare (type defstruct-description dd)) + (let ((classoid (find-classoid (dd-name dd))) + (*struct-accesss-fragments* accessors)) + (dolist (fun *defstruct-hooks*) + (funcall fun classoid))) + t) ;;; Copy any old kind of structure. (defun copy-structure (structure) "Return a copy of STRUCTURE with the same (EQL) slot values." (declare (type structure-object structure)) - (let ((layout (%instance-layout structure))) - (when (layout-invalid layout) - (error "attempt to copy an obsolete structure:~% ~S" structure)) - ;; Previously this had to used LAYOUT-LENGTH in the allocation, - ;; to avoid copying random bits from the stack to the heap if you had a - ;; padding word in a stack-allocated instance. This is no longer an issue. - ;; %INSTANCE-LENGTH returns the number of words that are logically in the - ;; instance, with no padding. Using %INSTANCE-LENGTH allows potentially - ;; interesting nonstandard things like variable-length structures. - (let* ((len (%instance-length structure)) - (res (%make-instance len))) - (declare (type index len)) - (let ((bitmap (layout-bitmap layout))) - ;; Don't assume that %INSTANCE-REF can access the layout. - (setf (%instance-layout res) (%instance-layout structure)) - ;; On backends which don't segregate descriptor vs. non-descriptor - ;; registers, we could speed up this code in an obvious way. - (macrolet ((copy-loop (tagged-p &optional step) - `(do ((i sb-vm:instance-data-start (1+ i))) - ((>= i len)) - (declare (index i)) - (if ,tagged-p - (setf (%instance-ref res i) - (%instance-ref structure i)) - (setf (%raw-instance-ref/word res i) - (%raw-instance-ref/word structure i))) - ,step))) - (cond ((eql bitmap +layout-all-tagged+) (copy-loop t)) - ;; The fixnum case uses fixnum operations for ODDP and ASH. - ((fixnump bitmap) ; shift and mask is faster than logbitp - (copy-loop (oddp (truly-the fixnum bitmap)) - (setq bitmap (ash bitmap -1)))) - (t ; bignum - use LOGBITP to avoid consing more bignums - (copy-loop (logbitp i bitmap)))))) - res))) + ;; %INSTANCE-LENGTH returns the number of words that are logically in the + ;; instance excluding any padding and/or stable-hash slot. + ;; Variable-length structure types are allowed. + (let* ((layout (%instance-layout structure)) + (len (%instance-length structure))) + ;; The finicky backends disallow loading and storing raw words + ;; using %INSTANCE-REF. The robust backends allow it. + ;; MIPS is probably robust, but I don't care to try it. + (macrolet ((fast-loop () + `(do ((i sb-vm:instance-data-start (1+ i))) + ((>= i len) res) + (declare (index i)) + (%instance-set res i (%instance-ref structure i))))) + #+(or x86 x86-64) ; Two allocators, but same loop either way + (let ((res (%new-instance* layout len))) + (fast-loop)) + #-(or x86 x86-64) ; Different loops + (if (logtest (layout-flags layout) sb-vm::+strictly-boxed-flag+) + (let ((res (%new-instance layout len))) + (fast-loop)) + (let ((res (%make-instance/mixed len))) + (%set-instance-layout res layout) + ;; DO-LAYOUT-BITMAP does not visit the LAYOUT itself + ;; (if that occupies a whole slot vs. being in the header) + (do-layout-bitmap (i taggedp layout len) + (if taggedp + (%instance-set res i (%instance-ref structure i)) + (%raw-instance-set/word + res i (%raw-instance-ref/word structure i)))) + res))))) + ;;; Like above, but copy all slots (including the LAYOUT) as though boxed. ;;; If the structure might contain raw slots and the GC is precise, ;;; this won't ever be called. (defun %copy-instance (to from) (declare (structure-object to from) (optimize (safety 0))) - (setf (%instance-layout to) (%instance-layout from)) + (%set-instance-layout to (%instance-layout from)) (dotimes (i (%instance-length to) to) - (setf (%instance-ref to i) (%instance-ref from i)))) + (%instance-set to i (%instance-ref from i)))) ;;; Like %COPY-INSTANCE, but layout was already assigned. ;;; Similarly, will not be called if raw slots and precise GC. (defun %copy-instance-slots (to from) (declare (structure-object to from) (optimize (safety 0))) (loop for i from sb-vm:instance-data-start below (%instance-length to) - do (setf (%instance-ref to i) (%instance-ref from i))) + do (%instance-set to i (%instance-ref from i))) to) +(defun (setf %instance-wrapper) (newval x) + (%set-instance-layout x (wrapper-friend newval)) + newval) +(defun (setf %fun-wrapper) (newval x) + (%set-fun-layout x (wrapper-friend newval)) + newval) ;;; default PRINT-OBJECT method @@ -196,7 +415,7 @@ (write name :stream stream) (do ((index 0 (1+ index)) (limit (or (and (not *print-readably*) *print-length*) - sb-xc:most-positive-fixnum)) + most-positive-fixnum)) (remaining-slots (dd-slots dd) (cdr remaining-slots))) ((or (null remaining-slots) (>= index limit)) (write-string (if remaining-slots " ...)" ")") stream)) @@ -212,20 +431,24 @@ (declare (ignore depth)) (if (funcallable-instance-p structure) (print-unreadable-object (structure stream :identity t :type t)) - (let* ((layout (%instance-layout structure)) - (dd (layout-info layout)) - (name (layout-classoid-name layout))) + (let* ((wrapper (%instance-wrapper structure)) + (dd (wrapper-info wrapper)) + (name (wrapper-classoid-name wrapper))) (cond ((not dd) ;; FIXME? this branch may be unnecessary as a consequence ;; of change f02bee325920166b69070e4735a8a3f295f8edfd which ;; stopped the badness is a stronger way. It should be the case ;; that absence of a DD can't happen unless the classoid is absent. - ;; KLUDGE: during PCL build debugging, we can sometimes - ;; attempt to print out a PCL object (with null LAYOUT-INFO). + ;; KLUDGE: during warm build, we may see a CONDITION or STANDARD-OBJECT + ;; here, and we need a way to get a handle on it (for SB-VM:HEXDUMP at least). + ;; I'm not sure why a condition-report function isn't called in the former + ;; case. Using the default structure printer won't solve anything, because + ;; the layout of a condition does not describe any slot of interest. (pprint-logical-block (stream nil :prefix "#<" :suffix ">") - (prin1 name stream) - (write-char #\space stream) - (write-string "(no LAYOUT-INFO)" stream))) + (prin1 name stream) + (write-char #\space stream) + (write-string "(no LAYOUT-INFO) " stream) + (write (get-lisp-obj-address structure) :base 16 :radix t :stream stream))) ((not (dd-slots dd)) ;; the structure type doesn't count as a component for *PRINT-LEVEL* ;; processing. We can likewise elide the logical block processing, @@ -260,5 +483,32 @@ ,(+ (- sb-vm:instance-pointer-lowtag) (* (+ sb-vm:instance-slots-offset index) sb-vm:n-word-bytes)))))))) + +#+metaspace +(defmethod print-object ((self sb-vm:layout) stream) + (print-unreadable-object (self stream :type t :identity t) + (write (layout-id self) :stream stream))) + +(defun id-to-layout (id) + (maphash (lambda (k v) + (declare (ignore k)) + (when (eql (layout-id v) id) + (return-from id-to-layout (wrapper-friend v)))) + (classoid-subclasses (find-classoid 't)))) +(export 'id-to-layout) + +(defun summarize-layouts () + (flet ((flag-bits (x) (logand (layout-flags (wrapper-friend x)) + layout-flags-mask))) + (let ((prev -1)) + (dolist (layout (sort (loop for v being each hash-value + of (classoid-subclasses (find-classoid 't)) + collect v) + #'> :key #'flag-bits)) + (let ((flags (flag-bits layout))) + (unless (= flags prev) + (format t "Layout flags = #b~10,'0b~%" flags) + (setq prev flags))) + (format t " ~a~%" layout))))) (/show0 "target-defstruct.lisp end of file") diff --git a/src/code/target-error.lisp b/src/code/target-error.lisp index 3bfc8fe325..d163b9b985 100644 --- a/src/code/target-error.lisp +++ b/src/code/target-error.lisp @@ -12,6 +12,25 @@ (in-package "SB-KERNEL") +(declaim (global *type-system-initialized*)) + +(defun decode-internal-error-args (sap trap-number &optional error-number) + (let ((error-number (cond (error-number) + ((>= trap-number sb-vm:error-trap) + (prog1 + (- trap-number sb-vm:error-trap) + (setf trap-number sb-vm:error-trap))) + (t + (prog1 (sap-ref-8 sap 0) + (setf sap (sap+ sap 1))))))) + (let ((length (error-length error-number))) + (declare (type (unsigned-byte 8) length)) + (values error-number + (loop with index = 0 + repeat length + collect (sb-c:sap-read-var-integerf sap index)) + trap-number)))) + (defun muffle-warning-p (warning) (declare (special *muffled-warnings*)) (typep warning *muffled-warnings*)) @@ -31,19 +50,6 @@ ;;; Lists to which *HANDLER-CLUSTERS* is bound generally have dynamic ;;; extent. -(defun !target-error-cold-init () - ;; Anonymous lambdas are too complicated to dump as constants in genesis. - ;; (that's sad, I wish we could do something about it) - (setq **initial-handler-clusters** - `(((,(find-classoid-cell 'warning :create t) - . - ,(named-lambda "MAYBE-MUFFLE" (warning) - (when (muffle-warning-p warning) - (muffle-warning warning)))) - (,(find-classoid-cell 'step-condition) - . - sb-impl::invoke-stepper))))) - (defmethod print-object ((restart restart) stream) (if *print-escape* (print-unreadable-object (restart stream :type t :identity t) @@ -216,6 +222,2199 @@ with that condition (or with no condition) will be returned." (cerror cerror-arg condition) (funcall function condition))))) + +;;;; Conditions. + +(!defstruct-with-alternate-metaclass condition + :slot-names (assigned-slots) + :constructor nil + :superclass-name t + :metaclass-name condition-classoid + :metaclass-constructor make-condition-classoid + :dd-type structure) + +;;; Needed for !CALL-A-METHOD to pick out CONDITIONs +(defun !condition-p (x) (typep x 'condition)) + +(defstruct (condition-slot (:copier nil)) + (name (missing-arg) :type symbol) + ;; list of all applicable initargs + (initargs (missing-arg) :type list) + ;; names of reader and writer functions + (readers (missing-arg) :type list) + (writers (missing-arg) :type list) + ;; true if :INITFORM was specified + (initform-p (missing-arg) :type (member t nil)) + ;; the initform if :INITFORM was specified, otherwise NIL + (initform nil :type t) + ;; if this is a function, call it with no args to get the initform value + (initfunction (missing-arg) :type t) + ;; allocation of this slot, or NIL until defaulted + (allocation nil :type (member :instance :class nil)) + ;; If ALLOCATION is :CLASS, this is a cons whose car holds the value + (cell nil :type (or cons null)) + ;; slot documentation + (documentation nil :type (or string null))) + +(eval-when (:compile-toplevel :load-toplevel :execute) + (let ((condition-class (find-classoid 'condition))) + (setf (condition-classoid-cpl condition-class) + (list condition-class)))) + +(setf (condition-classoid-report (find-classoid 'condition)) + (lambda (cond stream) + (format stream "Condition ~/sb-impl:print-type-specifier/ was signalled." + (type-of cond)))) + +(eval-when (:compile-toplevel :load-toplevel :execute) + +(defun find-condition-layout (name parent-types) + (let* ((cpl (remove-duplicates + (reverse + (reduce #'append + (mapcar (lambda (x) + (condition-classoid-cpl + (find-classoid x))) + parent-types))))) + (cond-layout (info :type :compiler-layout 'condition)) + (olayout (info :type :compiler-layout name)) + ;; FIXME: Does this do the right thing in case of multiple + ;; inheritance? A quick look at DEFINE-CONDITION didn't make + ;; it obvious what ANSI intends to be done in the case of + ;; multiple inheritance, so it's not actually clear what the + ;; right thing is.. + (new-inherits + (order-layout-inherits (concatenate 'simple-vector + (wrapper-inherits cond-layout) + (mapcar #'classoid-wrapper cpl))))) + (if (and olayout + (not (mismatch (wrapper-inherits olayout) new-inherits))) + olayout + ;; All condition classoid layouts carry the same LAYOUT-INFO - the defstruct + ;; description for CONDITION - which is a representation of the primitive object + ;; and not the lisp-level object. + (make-layout (hash-layout-name name) + (make-undefined-classoid name) + :info (wrapper-info cond-layout) + :flags (logior +condition-layout-flag+ +strictly-boxed-flag+) + :inherits new-inherits + :depthoid -1 + :length (wrapper-length cond-layout))))) + +) ; EVAL-WHEN + + +;;;; slots of CONDITION objects + +(defun find-slot-default (class slot) + (multiple-value-bind (value found) (find-slot-default-initarg class slot) + ;; When CLASS or a superclass has a default initarg for SLOT, use + ;; that. + (cond (found + value) + ;; Otherwise use the initform of SLOT, if there is one. + ((condition-slot-initform-p slot) + (let ((initfun (condition-slot-initfunction slot))) + (aver (functionp initfun)) + (funcall initfun))) + (t + (error "Unbound condition slot: ~S" (condition-slot-name slot)))))) + +(defun find-slot-default-initarg (class slot) + (let ((initargs (condition-slot-initargs slot)) + (cpl (condition-classoid-cpl class))) + (dolist (class cpl) + (let ((direct-default-initargs + (condition-classoid-direct-default-initargs class))) + (dolist (initarg initargs) + (let ((initfunction (third (assoc initarg direct-default-initargs)))) + (when initfunction + (return-from find-slot-default-initarg + (values (funcall initfunction) t))))))) + (values nil nil))) + +(defun find-condition-class-slot (condition-class slot-name) + (dolist (sclass + (condition-classoid-cpl condition-class) + (error "There is no slot named ~S in ~S." + slot-name condition-class)) + (dolist (slot (condition-classoid-slots sclass)) + (when (eq (condition-slot-name slot) slot-name) + (return-from find-condition-class-slot slot))))) + +(defun set-condition-slot-value (condition new-value name) + (dolist (cslot (condition-classoid-class-slots + (wrapper-classoid (%instance-wrapper condition))) + (setf (getf (condition-assigned-slots condition) name) + new-value)) + (when (eq (condition-slot-name cslot) name) + (return (setf (car (condition-slot-cell cslot)) new-value))))) + +(defun condition-slot-value (condition name) + (let ((val (getf (condition-assigned-slots condition) name sb-pcl:+slot-unbound+))) + (if (unbound-marker-p val) + (let ((class (wrapper-classoid (%instance-wrapper condition)))) + (dolist (cslot + (condition-classoid-class-slots class) + (let ((instance-length (%instance-length condition)) + (slot (or (find-condition-class-slot class name) + (error "missing slot ~S of ~S" name condition)))) + (setf (getf (condition-assigned-slots condition) name) + (do ((i (+ sb-vm:instance-data-start 1) (+ i 2))) + ((>= i instance-length) (find-slot-default class slot)) + (when (member (%instance-ref condition i) + (condition-slot-initargs slot)) + (return (%instance-ref condition (1+ i)))))))) + (when (eq (condition-slot-name cslot) name) + (let ((value (car (condition-slot-cell cslot)))) + (if (unbound-marker-p value) + (error "Unbound condition slot: ~S" (condition-slot-name cslot)) + (return value)))))) + val))) + + +;;;; MAKE-CONDITION + +;;; Pre-scan INITARGS to see whether any are stack-allocated. +;;; If not, then life is easy. If any are, then depending on whether the +;;; condition is a TYPE-ERROR, call TYPE-OF on the bad datum, so that +;;; if the condition outlives the extent of the object, and someone tries +;;; to print the condition, we don't crash. +;;; Putting a placeholder in for the datum would work, but seems a bit evil, +;;; since the user might actually want to know what it was. And we shouldn't +;;; assume that the object would definitely escape its dynamic-extent. + +(defun allocate-condition (designator &rest initargs) + (when (oddp (length initargs)) + (error 'simple-error + :format-control "odd-length initializer list: ~S." + ;; Passing the initargs to LIST avoids consing them into + ;; a list except when this error is signaled. + :format-arguments (list (apply #'list initargs)))) + ;; I am going to assume that people are not somehow getting to here + ;; with a CLASSOID, which is not strictly legal as a designator, + ;; but which is accepted because it is actually the desired thing. + ;; It doesn't seem worth sweating over that detail, and in any event + ;; we could say that it's a supported extension. + (let ((classoid (named-let lookup ((designator designator)) + (typecase designator + (symbol (find-classoid designator nil)) + (class (lookup (class-name designator))) + (t designator))))) + (unless (condition-classoid-p classoid) + (error 'simple-type-error + :datum designator + :expected-type 'sb-pcl::condition-class + :format-control "~S does not designate a condition class." + :format-arguments (list designator))) + (flet ((stream-err-p (layout) + (let ((stream-err-layout (load-time-value (find-layout 'stream-error)))) + (or (eq layout stream-err-layout) + (find stream-err-layout (wrapper-inherits layout))))) + (type-err-p (layout) + (let ((type-err-layout (load-time-value (find-layout 'type-error)))) + (or (eq layout type-err-layout) + (find type-err-layout (wrapper-inherits layout))))) + ;; avoid full calls to STACK-ALLOCATED-P here + (stackp (x) + (let ((addr (get-lisp-obj-address x))) + (and (sb-vm:is-lisp-pointer addr) + (<= (get-lisp-obj-address sb-vm:*control-stack-start*) addr) + (< addr (get-lisp-obj-address sb-vm:*control-stack-end*)))))) + (let* ((any-dx + (loop for arg-index from 1 below (length initargs) by 2 + thereis (stackp (fast-&rest-nth arg-index initargs)))) + (layout (classoid-wrapper classoid)) + (extra (if (and any-dx (type-err-p layout)) 2 0)) ; space for secret initarg + (instance (%new-instance layout + (+ sb-vm:instance-data-start + 1 ; ASSIGNED-SLOTS + (length initargs) + extra))) + (data-index (1+ sb-vm:instance-data-start)) + (arg-index 0) + (have-type-error-datum) + (type-error-datum)) + (setf (condition-assigned-slots instance) nil) + (macrolet ((store-pair (key val) + `(progn (%instance-set instance data-index ,key) + (%instance-set instance (1+ data-index) ,val)))) + (cond ((not any-dx) + ;; uncomplicated way + (loop (when (>= arg-index (length initargs)) (return)) + (store-pair (fast-&rest-nth arg-index initargs) + (fast-&rest-nth (1+ arg-index) initargs)) + (incf data-index 2) + (incf arg-index 2))) + (t + (loop (when (>= arg-index (length initargs)) (return)) + (let ((key (fast-&rest-nth arg-index initargs)) + (val (fast-&rest-nth (1+ arg-index) initargs))) + (when (and (eq key :datum) + (not have-type-error-datum) + (type-err-p layout)) + (setq type-error-datum val + have-type-error-datum t)) + (if (and (eq key :stream) (stream-err-p layout) (stackp val)) + (store-pair key (sb-impl::make-stub-stream val)) + (store-pair key val))) + (incf data-index 2) + (incf arg-index 2)) + (when (and have-type-error-datum (/= extra 0)) + ;; We can get into serious trouble here if the + ;; datum is already stack garbage! + (let ((actual-type (type-of type-error-datum))) + (store-pair 'dx-object-type actual-type)))))) + (values instance classoid))))) + +;;; Access the type of type-error-datum if the datum can't be accessed. +;;; Testing the stack pointer when rendering the condition is a heuristic +;;; that might work, but more likely, the erring frame has been exited +;;; and then the stack pointer changed again to make it seems like the +;;; object pointer is valid. I'm not sure what to do, but we can leave +;;; that decision for later. +(defun type-error-datum-stored-type (condition) + (do ((i (- (%instance-length condition) 2) (- i 2))) + ((<= i (1+ sb-vm:instance-data-start)) + (make-unbound-marker)) + (when (eq (%instance-ref condition i) 'dx-object-type) + (return (%instance-ref condition (1+ i)))))) + +(defun make-condition (type &rest initargs) + "Make an instance of a condition object using the specified initargs." + ;; Note: While ANSI specifies no exceptional situations in this function, + ;; ALLOCATE-CONDITION will signal a type error if TYPE does not designate + ;; a condition class. This seems fair enough. + (declare (explicit-check)) + ;; FIXME: the compiler should have a way to make GETF operate on a &MORE arg + ;; so that the initargs are never listified. + (declare (dynamic-extent initargs)) + (multiple-value-bind (condition classoid) + (apply #'allocate-condition type initargs) + + ;; Set any class slots with initargs present in this call. + (dolist (cslot (condition-classoid-class-slots classoid)) + (loop for (key value) on initargs by #'cddr + when (memq key (condition-slot-initargs cslot)) + do (setf (car (condition-slot-cell cslot)) value) + (return) + finally + (multiple-value-bind (value found) + (find-slot-default-initarg classoid cslot) + (when found + (setf (car (condition-slot-cell cslot)) value))))) + + ;; Default any slots with non-constant defaults now. + (dolist (hslot (condition-classoid-hairy-slots classoid)) + (when (dolist (initarg (condition-slot-initargs hslot) t) + (unless (unbound-marker-p (getf initargs initarg sb-pcl:+slot-unbound+)) + (return nil))) + (setf (getf (condition-assigned-slots condition) + (condition-slot-name hslot)) + (find-slot-default classoid hslot)))) + + condition)) + +;;;; DEFINE-CONDITION + +(define-load-time-global *define-condition-hooks* nil) + +(defun %set-condition-report (name report) + (setf (condition-classoid-report (find-classoid name)) + report)) + +;;; Early definitions of slot accessor creators. +;;; +;;; Slot accessors must be generic functions, but ANSI does not seem +;;; to specify any of them, and we cannot support it before end of +;;; warm init. So we use ordinary functions inside SBCL, and switch to +;;; GFs only at the end of building. +(declaim (notinline install-condition-slot-reader + install-condition-slot-writer)) +(defun install-condition-slot-reader (name condition slot-name) + (declare (ignore condition)) + (setf (fdefinition name) + (set-closure-name + (lambda (condition) (condition-slot-value condition slot-name)) + t + `(condition-slot-reader ,name)))) +(defun install-condition-slot-writer (name condition slot-name) + (declare (ignore condition)) + (setf (fdefinition name) + (set-closure-name + (lambda (new-value condition) + (set-condition-slot-value condition new-value slot-name)) + t + `(condition-slot-writer ,name)))) + +(eval-when (:compile-toplevel :load-toplevel :execute) +(defun %%compiler-define-condition (name direct-supers layout readers writers) + (declare (notinline find-classoid)) + (preinform-compiler-about-class-type name nil) + (preinform-compiler-about-accessors 'condition readers writers) + (multiple-value-bind (class old-layout) + (insured-find-classoid name + #'condition-classoid-p + #'make-condition-classoid) + (setf (wrapper-classoid layout) class) + (setf (classoid-direct-superclasses class) + (mapcar #'find-classoid direct-supers)) + (cond ((not old-layout) + (register-layout layout)) + ((not *type-system-initialized*) + (setf (wrapper-classoid old-layout) class) + (setq layout old-layout) + (unless (eq (classoid-wrapper class) layout) + (register-layout layout))) + ((warn-if-altered-layout "current" + old-layout + "new" + (wrapper-length layout) + (wrapper-inherits layout) + (wrapper-depthoid layout) + (wrapper-bitmap layout)) + (register-layout layout :invalidate t)) + ((not (classoid-wrapper class)) + (register-layout layout))) + + (setf (find-classoid name) class) + + ;; Initialize CPL slot. + (setf (condition-classoid-cpl class) + (remove-if-not #'condition-classoid-p + (std-compute-class-precedence-list class))))) + +(defun %compiler-define-condition (name direct-supers layout readers writers) + (call-with-defining-class + 'condition name + (lambda () + (%%compiler-define-condition name direct-supers layout readers writers)))) +) ; EVAL-WHEN + +(defun %define-condition (name parent-types layout slots + direct-default-initargs all-readers all-writers + source-location &optional documentation) + (call-with-defining-class + 'condition name + (lambda () + (%%compiler-define-condition name parent-types layout all-readers all-writers) + (let ((classoid (find-classoid name))) + (when source-location + (setf (classoid-source-location classoid) source-location)) + (setf (condition-classoid-slots classoid) slots + (condition-classoid-direct-default-initargs classoid) direct-default-initargs + (documentation name 'type) documentation) + + (dolist (slot slots) + ;; Set up reader and writer functions. + (let ((slot-name (condition-slot-name slot))) + (dolist (reader (condition-slot-readers slot)) + (install-condition-slot-reader reader name slot-name)) + (dolist (writer (condition-slot-writers slot)) + (install-condition-slot-writer writer name slot-name)))) + + ;; Compute effective slots and set up the class and hairy slots + ;; (subsets of the effective slots.) + (setf (condition-classoid-class-slots classoid) '() + (condition-classoid-hairy-slots classoid) '()) + (let ((eslots (compute-effective-slots classoid)) + (e-def-initargs + (reduce #'append + (mapcar #'condition-classoid-direct-default-initargs + (condition-classoid-cpl classoid))))) + (dolist (slot eslots) + (ecase (condition-slot-allocation slot) + (:class + (unless (condition-slot-cell slot) + (setf (condition-slot-cell slot) + (list (if (condition-slot-initform-p slot) + (let ((initfun (condition-slot-initfunction slot))) + (aver (functionp initfun)) + (funcall initfun)) + sb-pcl:+slot-unbound+)))) + (push slot (condition-classoid-class-slots classoid))) + ((:instance nil) + (setf (condition-slot-allocation slot) :instance) + ;; FIXME: isn't this "always hairy"? + (when (or (functionp (condition-slot-initfunction slot)) + (dolist (initarg (condition-slot-initargs slot) nil) + (when (functionp (third (assoc initarg e-def-initargs))) + (return t)))) + (push slot (condition-classoid-hairy-slots classoid))))))) + (when *type-system-initialized* + (dolist (fun *define-condition-hooks*) + (funcall fun classoid)))))) + name) + +(defmacro define-condition (name (&rest parent-types) (&rest slot-specs) + &body options) + "DEFINE-CONDITION Name (Parent-Type*) (Slot-Spec*) Option* + Define NAME as a condition type. This new type inherits slots and its + report function from the specified PARENT-TYPEs. A slot spec is a list of: + (slot-name :reader <rname> :initarg <iname> {Option Value}* + + The DEFINE-CLASS slot options :ALLOCATION, :INITFORM, [slot] :DOCUMENTATION + and :TYPE and the overall options :DEFAULT-INITARGS and + [type] :DOCUMENTATION are also allowed. + + The :REPORT option is peculiar to DEFINE-CONDITION. Its argument is either + a string or a two-argument lambda or function name. If a function, the + function is called with the condition and stream to report the condition. + If a string, the string is printed. + + Condition types are classes, but (as allowed by ANSI and not as described in + CLtL2) are neither STANDARD-OBJECTs nor STRUCTURE-OBJECTs. WITH-SLOTS and + SLOT-VALUE may not be used on condition objects." + (check-designator name 'define-condition) + (let* ((parent-types (or parent-types '(condition))) + (layout (find-condition-layout name parent-types)) + (documentation nil) + (report nil) + (direct-default-initargs ())) + (collect ((slots) + (all-readers nil append) + (all-writers nil append)) + (dolist (spec slot-specs) + (with-current-source-form (spec) + (when (keywordp spec) + (warn "Keyword slot name indicates probable syntax error:~% ~S" + spec)) + (let* ((spec (if (consp spec) spec (list spec))) + (slot-name (first spec)) + (allocation :instance) + (initform-p nil) + documentation + initform) + (collect ((initargs) + (readers) + (writers)) + (do ((options (rest spec) (cddr options))) + ((null options)) + (unless (and (consp options) (consp (cdr options))) + (error "malformed condition slot spec:~% ~S." spec)) + (let ((arg (second options))) + (case (first options) + (:reader (readers arg)) + (:writer (writers arg)) + (:accessor + (readers arg) + (writers `(setf ,arg))) + (:initform + (when initform-p + (error "more than one :INITFORM in ~S" spec)) + (setq initform-p t) + (setq initform arg)) + (:initarg (initargs arg)) + (:allocation + (setq allocation arg)) + (:documentation + (when documentation + (error "more than one :DOCUMENTATION in ~S" spec)) + (unless (stringp arg) + (error "slot :DOCUMENTATION argument is not a string: ~S" + arg)) + (setq documentation arg)) + (:type + (check-slot-type-specifier + arg slot-name (cons 'define-condition name))) + (t + (error "unknown slot option:~% ~S" (first options)))))) + + (all-readers (readers)) + (all-writers (writers)) + (slots `(make-condition-slot + :name ',slot-name + :initargs ',(initargs) + :readers ',(readers) + :writers ',(writers) + :initform-p ',initform-p + :documentation ',documentation + :initform ,(when initform-p `',initform) + :initfunction ,(when initform-p + `#'(lambda () ,initform)) + :allocation ',allocation)))))) + + (dolist (option options) + (unless (consp option) + (error "bad option:~% ~S" option)) + (case (first option) + (:documentation (setq documentation (second option))) + (:report + (let ((arg (second option))) + (setq report + `#'(named-lambda (condition-report ,name) (condition stream) + (declare (type condition condition) + (type stream stream)) + ,@(if (stringp arg) + `((declare (ignore condition)) + (write-string ,arg stream)) + `((funcall #',arg condition stream))))))) + (:default-initargs + (doplist (initarg initform) (rest option) + (push ``(,',initarg ,',initform ,#'(lambda () ,initform)) + direct-default-initargs))) + (t + (error "unknown option: ~S" (first option))))) + + ;; Maybe kill docstring, but only under the cross-compiler. + #+(and (not sb-doc) sb-xc-host) (setq documentation nil) + `(progn + ,@(when *top-level-form-p* + ;; Avoid dumping uninitialized layouts, for sb-fasl::dump-layout + `((eval-when (:compile-toplevel) + (%compiler-define-condition ',name ',parent-types ,layout + ',(all-readers) ',(all-writers))))) + (%define-condition ',name + ',parent-types + ,(if *top-level-form-p* + layout + `(find-condition-layout ',name ',parent-types)) + (list ,@(slots)) + (list ,@direct-default-initargs) + ',(all-readers) + ',(all-writers) + (sb-c:source-location) + ,@(and documentation + `(,documentation))) + ;; This needs to be after %DEFINE-CONDITION in case :REPORT + ;; is a lambda referring to condition slot accessors: + ;; they're not proclaimed as functions before it has run if + ;; we're under EVAL or loaded as source. + (%set-condition-report ',name ,report) + ',name)))) + +;;; Compute the effective slots of CLASS, copying inherited slots and +;;; destructively modifying direct slots. +;;; +;;; FIXME: It'd be nice to explain why it's OK to destructively modify +;;; direct slots. Presumably it follows from the semantics of +;;; inheritance and redefinition of conditions, but finding the cite +;;; and documenting it here would be good. (Or, if this is not in fact +;;; ANSI-compliant, fixing it would also be good.:-) +(defun compute-effective-slots (class) + (collect ((res (copy-list (condition-classoid-slots class)))) + (dolist (sclass (cdr (condition-classoid-cpl class))) + (dolist (sslot (condition-classoid-slots sclass)) + (let ((found (find (condition-slot-name sslot) (res) + :key #'condition-slot-name))) + (cond (found + (setf (condition-slot-initargs found) + (union (condition-slot-initargs found) + (condition-slot-initargs sslot))) + (unless (condition-slot-initform-p found) + (setf (condition-slot-initform-p found) + (condition-slot-initform-p sslot)) + (setf (condition-slot-initform found) + (condition-slot-initform sslot)) + (setf (condition-slot-initfunction found) + (condition-slot-initfunction sslot))) + (unless (condition-slot-allocation found) + (setf (condition-slot-allocation found) + (condition-slot-allocation sslot)))) + (t + (res (copy-structure sslot))))))) + (res))) + + + +;;;; various CONDITIONs specified by ANSI + +(define-condition serious-condition (condition) ()) + +(define-condition error (serious-condition) ()) + +(define-condition warning (condition) ()) +(define-condition style-warning (warning) ()) + +(defun simple-condition-printer (condition stream) + (let ((control (simple-condition-format-control condition))) + (if control + (apply #'format stream + control + (simple-condition-format-arguments condition)) + (error "No format-control for ~S" condition)))) + +(define-condition simple-condition () + ((format-control :reader simple-condition-format-control + :initarg :format-control + :initform nil + :type format-control) + (format-arguments :reader simple-condition-format-arguments + :initarg :format-arguments + :initform nil + :type list)) + (:report simple-condition-printer)) + +(define-condition simple-warning (simple-condition warning) ()) + +(define-condition simple-error (simple-condition error) ()) + +(define-condition storage-condition (serious-condition) ()) + +(defun decode-type-error-context (context type) + (typecase context + (cons + (case (car context) + (:struct + (format nil "when setting slot ~s of structure ~s" + (cddr context) (cadr context))) + (t context))) + ((eql :aref) + (let (*print-circle*) + (format nil "when setting an element of (ARRAY ~s)" + type))) + ((eql :ftype) + "from the function type declaration.") + ((and symbol + (not null)) + (format nil "when binding ~s" context)) + (t + context))) + +(define-condition type-error (error) + ((datum :reader type-error-datum :initarg :datum) + (expected-type :reader type-error-expected-type :initarg :expected-type) + (context :initform nil :reader type-error-context :initarg :context)) + (:report report-general-type-error)) +(defun report-general-type-error (condition stream) + (let ((type (type-error-expected-type condition)) + (context (type-error-context condition))) + (if (eq context :multiple-values) + (format stream "~@<The values ~ + ~@:_~2@T~S ~ + ~@:_are not of type ~ + ~@:_~2@T~/sb-impl:print-type-specifier/~:@>" + (type-error-datum condition) + type) + (format stream "~@<The value ~ + ~@:_~2@T~S ~ + ~@:_is not of type ~ + ~@:_~2@T~/sb-impl:print-type-specifier/~@[ ~ + ~@:_~a~]~:@>" + (type-error-datum condition) + type + (decode-type-error-context (type-error-context condition) + type))))) + +;;; not specified by ANSI, but too useful not to have around. +(define-condition simple-style-warning (simple-condition style-warning) ()) +(define-condition simple-type-error (simple-condition type-error) ()) + +(define-condition program-error (error) ()) +(define-condition parse-error (error) ()) +(define-condition control-error (error) ()) +(define-condition stream-error (error) + ((stream :reader stream-error-stream :initarg :stream))) + +(define-condition end-of-file (stream-error) () + (:report + (lambda (condition stream) + (format stream + "end of file on ~S" + (stream-error-stream condition))))) + +(define-condition closed-stream-error (stream-error) () + (:report + (lambda (condition stream) + (format stream "~S is closed" (stream-error-stream condition))))) + +(define-condition closed-saved-stream-error (closed-stream-error) () + (:report + (lambda (condition stream) + (format stream "~S was closed by SB-EXT:SAVE-LISP-AND-DIE" (stream-error-stream condition))))) + +(define-condition file-error (error) + ((pathname :reader file-error-pathname :initarg :pathname)) + (:report + (lambda (condition stream) + (format stream "error on file ~S" (file-error-pathname condition))))) + +(define-condition package-error (error) + ((package :reader package-error-package :initarg :package))) + +(define-condition cell-error (error) + ((name :reader cell-error-name :initarg :name))) + +(define-condition values-list-argument-error (type-error) + () + (:report + (lambda (condition stream) + (format stream "~@<Attempt to use ~S on a dotted list: ~ + ~2I~_~S~:>" + 'values-list (type-error-datum condition))))) + +(define-condition unbound-variable (cell-error) + ((not-yet-loaded :initform nil :reader not-yet-loaded :initarg :not-yet-loaded)) + (:report + (lambda (condition stream) + (format stream + "~@<The variable ~S is unbound.~@?~@:>" + (cell-error-name condition) + (case (not-yet-loaded condition) + (:local + "~:@_It is a local variable ~ + not available at compile-time.") + (t + "")))))) + +(define-condition undefined-function (cell-error) + ((not-yet-loaded :initform nil :reader not-yet-loaded :initarg :not-yet-loaded)) + (:report + (lambda (condition stream) + (let ((name (cell-error-name condition))) + (format stream + (if (and (symbolp name) (macro-function name)) + (sb-format:tokens "~@<~/sb-ext:print-symbol-with-prefix/ is a macro, ~ + not a function.~@:>") + (sb-format:tokens "~@<The function ~/sb-ext:print-symbol-with-prefix/ ~ + is undefined.~@?~@:>")) + name + (case (not-yet-loaded condition) + (:local + (sb-format:tokens "~:@_It is a local function ~ + not available at compile-time.")) + ((t) (sb-format:tokens "~:@_It is defined earlier in the ~ + file but is not available at compile-time.")) + (t + ""))))))) + +(define-condition retry-undefined-function + (simple-condition undefined-function) ()) + +(define-condition special-form-function (undefined-function) () + (:report + (lambda (condition stream) + (format stream + "Cannot FUNCALL the SYMBOL-FUNCTION of special operator ~S." + (cell-error-name condition))))) + +(define-condition arithmetic-error (error) + ((operation :reader arithmetic-error-operation + :initarg :operation + :initform nil) + (operands :reader arithmetic-error-operands + :initarg :operands)) + (:report (lambda (condition stream) + (format stream + "arithmetic error ~S signalled" + (type-of condition)) + (when (arithmetic-error-operation condition) + (format stream + "~%Operation was (~S ~{~S~^ ~})." + (arithmetic-error-operation condition) + (arithmetic-error-operands condition)))))) + +(define-condition division-by-zero (arithmetic-error) ()) +(define-condition floating-point-overflow (arithmetic-error) ()) +(define-condition floating-point-underflow (arithmetic-error) ()) +(define-condition floating-point-inexact (arithmetic-error) ()) +(define-condition floating-point-invalid-operation (arithmetic-error) ()) + +(define-condition illegal-class-name-error (error) + ((name :initarg :name :reader illegal-class-name-error-name)) + (:default-initargs :name (missing-arg)) + (:report (lambda (condition stream) + (format stream "~@<~S is not a legal class name.~@:>" + (illegal-class-name-error-name condition))))) + +(define-condition print-not-readable (error) + ((object :reader print-not-readable-object :initarg :object)) + (:report + (lambda (condition stream) + (let ((obj (print-not-readable-object condition)) + (*print-array* nil)) + (format stream "~S cannot be printed readably." obj))))) + +(define-condition reader-error (parse-error stream-error) () + (:report (lambda (condition stream) + (%report-reader-error condition stream)))) + +;;; a READER-ERROR whose REPORTing is controlled by FORMAT-CONTROL and +;;; FORMAT-ARGS (the usual case for READER-ERRORs signalled from +;;; within SBCL itself) +;;; +;;; (Inheriting CL:SIMPLE-CONDITION here isn't quite consistent with +;;; the letter of the ANSI spec: this is not a condition signalled by +;;; SIGNAL when a format-control is supplied by the function's first +;;; argument. It seems to me (WHN) to be basically in the spirit of +;;; the spec, but if not, it'd be straightforward to do our own +;;; DEFINE-CONDITION SB-INT:SIMPLISTIC-CONDITION with +;;; FORMAT-CONTROL and FORMAT-ARGS slots, and use that condition in +;;; place of CL:SIMPLE-CONDITION here.) +(define-condition simple-reader-error (reader-error simple-condition) + () + (:report (lambda (condition stream) + (%report-reader-error condition stream :simple t)))) + +;;; base REPORTing of a READER-ERROR +;;; +;;; When SIMPLE, we expect and use SIMPLE-CONDITION-ish FORMAT-CONTROL +;;; and FORMAT-ARGS slots. +(defun %report-reader-error (condition stream &key simple position) + (let ((error-stream (stream-error-stream condition))) + (pprint-logical-block (stream nil) + (if simple + (apply #'format stream + (simple-condition-format-control condition) + (simple-condition-format-arguments condition)) + (prin1 (class-name (class-of condition)) stream)) + (format stream "~2I~@[~:@_ ~:@_~:{~:(~A~): ~S~:^, ~:_~}~]~:@_ ~:@_Stream: ~S" + (stream-error-position-info error-stream position) + error-stream)))) + +;;;; special SBCL extension conditions + +;;; an error apparently caused by a bug in SBCL itself +;;; +;;; Note that we don't make any serious effort to use this condition +;;; for *all* errors in SBCL itself. E.g. type errors and array +;;; indexing errors can occur in functions called from SBCL code, and +;;; will just end up as ordinary TYPE-ERROR or invalid index error, +;;; because the signalling code has no good way to know that the +;;; underlying problem is a bug in SBCL. But in the fairly common case +;;; that the signalling code does know that it's found a bug in SBCL, +;;; this condition is appropriate, reusing boilerplate and helping +;;; users to recognize it as an SBCL bug. +(define-condition bug (simple-error) + () + (:report + (lambda (condition stream) + (format stream + "~@< ~? ~:@_~?~:>" + (simple-condition-format-control condition) + (simple-condition-format-arguments condition) + "~@<This is probably a bug in SBCL itself. (Alternatively, ~ + SBCL might have been corrupted by bad user code, e.g. by an ~ + undefined Lisp operation like ~S, or by stray pointers from ~ + alien code or from unsafe Lisp code; or there might be a bug ~ + in the OS or hardware that SBCL is running on.) If it seems to ~ + be a bug in SBCL itself, the maintainers would like to know ~ + about it. Bug reports are welcome on the SBCL ~ + mailing lists, which you can find at ~ + <http://sbcl.sourceforge.net/>.~:@>" + '((fmakunbound 'compile)))))) + +(define-condition simple-storage-condition (storage-condition simple-condition) + ()) + +(define-condition sanitizer-error (simple-error) + ((value :reader sanitizer-error-value :initarg :value) + (address :reader sanitizer-error-address :initarg :address) + (size :reader sanitizer-error-size :initarg :size))) + +;;; a condition for use in stubs for operations which aren't supported +;;; on some platforms +;;; +;;; E.g. in sbcl-0.7.0.5, it might be appropriate to do something like +;;; #-(or freebsd linux) +;;; (defun load-foreign (&rest rest) +;;; (error 'unsupported-operator :name 'load-foreign)) +;;; #+(or freebsd linux) +;;; (defun load-foreign ... actual definition ...) +;;; By signalling a standard condition in this case, we make it +;;; possible for test code to distinguish between (1) intentionally +;;; unimplemented and (2) unintentionally just screwed up somehow. +;;; (Before this condition was defined, test code tried to deal with +;;; this by checking for FBOUNDP, but that didn't work reliably. In +;;; sbcl-0.7.0, a package screwup left the definition of +;;; LOAD-FOREIGN in the wrong package, so it was unFBOUNDP even on +;;; architectures where it was supposed to be supported, and the +;;; regression tests cheerfully passed because they assumed that +;;; unFBOUNDPness meant they were running on an system which didn't +;;; support the extension.) +(define-condition unsupported-operator (simple-error) ()) + +;;; (:ansi-cl :function remove) +;;; (:ansi-cl :section (a b c)) +;;; (:ansi-cl :glossary "similar") +;;; +;;; (:sbcl :node "...") +;;; (:sbcl :variable *ed-functions*) + +;;; +;;; FIXME: this is not the right place for this. +(defun print-reference (reference stream) + (ecase (car reference) + (:amop + (format stream "AMOP") + (format stream ", ") + (destructuring-bind (type data) (cdr reference) + (ecase type + (:readers "Readers for ~:(~A~) Metaobjects" + (substitute #\ #\- (symbol-name data))) + (:initialization + (format stream "Initialization of ~:(~A~) Metaobjects" + (substitute #\ #\- (symbol-name data)))) + (:generic-function (format stream "Generic Function ~S" data)) + (:function (format stream "Function ~S" data)) + (:section (format stream "Section ~{~D~^.~}" data))))) + (:ansi-cl + (format stream "The ANSI Standard") + (format stream ", ") + (destructuring-bind (type data) (cdr reference) + (ecase type + (:function (format stream "Function ~S" data)) + (:special-operator (format stream "Special Operator ~S" data)) + (:macro (format stream "Macro ~S" data)) + (:section (format stream "Section ~{~D~^.~}" data)) + (:glossary (format stream "Glossary entry for ~S" data)) + (:type (format stream "Type ~S" data)) + (:system-class (format stream "System Class ~S" data)) + (:issue (format stream "writeup for Issue ~A" data))))) + (:sbcl + (format stream "The SBCL Manual") + (format stream ", ") + (destructuring-bind (type data) (cdr reference) + (ecase type + (:node (format stream "Node ~S" data)) + (:variable (format stream "Variable ~S" data)) + (:function (format stream "Function ~S" data))))) + ;; FIXME: other documents (e.g. CLIM, Franz documentation :-) + )) +(define-condition reference-condition () + ((references :initarg :references :reader reference-condition-references))) +(defvar *print-condition-references* t) + +(define-condition simple-reference-error (reference-condition simple-error) + ()) + +(define-condition simple-reference-warning (reference-condition simple-warning) + ()) + +(define-condition arguments-out-of-domain-error + (arithmetic-error reference-condition) + ()) + +;; per CLHS: "The consequences are unspecified if functions are ... +;; multiply defined in the same file." so we are within reason to do any +;; unspecified behavior at compile-time and/or time, but the compiler was +;; annoyingly mum about genuinely inadvertent duplicate macro definitions. +;; Redefinition is henceforth a style-warning, and for compatibility it does +;; not cause the ERRORP value from COMPILE-TIME to be T. +;; Nor do we cite section 3.2.2.3 as the governing prohibition. +(defun report-duplicate-definition (condition stream) + (format stream "~@<Duplicate definition for ~S found in one file.~@:>" + (slot-value condition 'name))) + +(define-condition duplicate-definition (reference-condition warning) + ((name :initarg :name :reader duplicate-definition-name)) + (:report report-duplicate-definition) + (:default-initargs :references '((:ansi-cl :section (3 2 2 3))))) +;; To my thinking, DUPLICATE-DEFINITION should be the ancestor condition, +;; and not fatal. But changing the meaning of that concept would be a bad idea, +;; so instead there is a new condition for the softer variant, which does not +;; inherit from the former. +(define-condition same-file-redefinition-warning (style-warning) + ;; Slot readers aren't proper generic functions until CLOS is built, + ;; so this doesn't get a reader because you can't pick the same name, + ;; and it wouldn't do any good to pick a different name that nothing knows. + ((name :initarg :name)) + (:report report-duplicate-definition)) + +(define-condition constant-modified (reference-condition warning) + ((fun-name :initarg :fun-name :reader constant-modified-fun-name) + (values :initform nil :initarg :values :reader constant-modified-values)) + (:report (lambda (c s) + (format s "~@<Destructive function ~S called on ~ + constant data: ~{~s~^, ~}~:>" + (constant-modified-fun-name c) + (constant-modified-values c)))) + (:default-initargs :references '((:ansi-cl :special-operator quote) + (:ansi-cl :section (3 7 1))))) + +(define-condition macro-arg-modified (constant-modified) + ((variable :initform nil :initarg :variable :reader macro-arg-modified-variable)) + (:report (lambda (c s) + (format s "~@<Destructive function ~S called on a macro argument: ~S.~:>" + (constant-modified-fun-name c) + (macro-arg-modified-variable c)))) + (:default-initargs :references nil)) + +(define-condition package-at-variance (reference-condition simple-warning) + () + (:default-initargs :references '((:ansi-cl :macro defpackage) + (:sbcl :variable *on-package-variance*)))) + +(define-condition package-at-variance-error (reference-condition simple-condition + package-error) + () + (:default-initargs :references '((:ansi-cl :macro defpackage)))) + +(define-condition defconstant-uneql (reference-condition error) + ((name :initarg :name :reader defconstant-uneql-name) + (old-value :initarg :old-value :reader defconstant-uneql-old-value) + (new-value :initarg :new-value :reader defconstant-uneql-new-value)) + (:report + (lambda (condition stream) + (format stream + "~@<The constant ~S is being redefined (from ~S to ~S)~@:>" + (defconstant-uneql-name condition) + (defconstant-uneql-old-value condition) + (defconstant-uneql-new-value condition)))) + (:default-initargs :references '((:ansi-cl :macro defconstant) + (:sbcl :node "Idiosyncrasies")))) + +(define-condition array-initial-element-mismatch + (reference-condition simple-warning) + () + (:default-initargs + :references '((:ansi-cl :function make-array) + (:ansi-cl :function upgraded-array-element-type)))) + +(define-condition initial-element-mismatch-style-warning + (array-initial-element-mismatch simple-style-warning) + ()) + +(define-condition type-warning (reference-condition simple-warning) + () + (:default-initargs :references '((:sbcl :node "Handling of Types")))) +(define-condition type-style-warning (reference-condition simple-style-warning) + () + (:default-initargs :references '((:sbcl :node "Handling of Types")))) +(define-condition slot-initform-type-style-warning (type-style-warning) ()) + +(define-condition local-argument-mismatch (reference-condition simple-warning) + () + (:default-initargs :references '((:ansi-cl :section (3 2 2 3))))) + +(define-condition format-args-mismatch (reference-condition) + () + (:default-initargs :references '((:ansi-cl :section (22 3 10 2))))) + +(define-condition format-too-few-args-warning + (format-args-mismatch simple-warning) + ()) +(define-condition format-too-many-args-warning + (format-args-mismatch simple-style-warning) + ()) + +(define-condition implicit-generic-function-warning (style-warning) + ((name :initarg :name :reader implicit-generic-function-name)) + (:report + (lambda (condition stream) + (format stream "~@<Implicitly creating new generic function ~ + ~/sb-ext:print-symbol-with-prefix/.~:@>" + (implicit-generic-function-name condition))))) + +(define-condition extension-failure (reference-condition simple-error) + ()) + +(define-condition structure-initarg-not-keyword + (reference-condition simple-style-warning) + () + (:default-initargs :references '((:ansi-cl :section (2 4 8 13))))) + +(define-condition package-lock-violation (package-error + reference-condition + simple-condition) + ((current-package :initform *package* + :reader package-lock-violation-in-package)) + (:report + (lambda (condition stream) + (let ((control (simple-condition-format-control condition)) + (error-package (package-name + (package-error-package condition))) + (current-package (package-name + (package-lock-violation-in-package condition)))) + (format stream "~@<Lock on package ~A violated~@[~{ when ~?~}~] ~ + while in package ~A.~:@>" + error-package + (when control + (list control (simple-condition-format-arguments condition))) + current-package)))) + ;; no :default-initargs -- reference-stuff provided by the + ;; signalling form in target-package.lisp + (:documentation + "Subtype of CL:PACKAGE-ERROR. A subtype of this error is signalled +when a package-lock is violated.")) + +(define-condition package-locked-error (package-lock-violation) () + (:documentation + "Subtype of SB-EXT:PACKAGE-LOCK-VIOLATION. An error of this type is +signalled when an operation on a package violates a package lock.")) + +(define-condition symbol-package-locked-error (package-lock-violation) + ((symbol :initarg :symbol :reader package-locked-error-symbol)) + (:documentation + "Subtype of SB-EXT:PACKAGE-LOCK-VIOLATION. An error of this type is +signalled when an operation on a symbol violates a package lock. The +symbol that caused the violation is accessed by the function +SB-EXT:PACKAGE-LOCKED-ERROR-SYMBOL.")) + +(define-condition undefined-alien-error (cell-error) () + (:report + (lambda (condition stream) + (if (slot-boundp condition 'name) + (format stream "Undefined alien: ~S" (cell-error-name condition)) + (format stream "Undefined alien symbol."))))) + +(define-condition undefined-alien-variable-error (undefined-alien-error) () + (:report + (lambda (condition stream) + (declare (ignore condition)) + (format stream "Attempt to access an undefined alien variable.")))) + +(define-condition undefined-alien-function-error (undefined-alien-error) () + (:report + (lambda (condition stream) + (if (and (slot-boundp condition 'name) + (cell-error-name condition)) + (format stream "The alien function ~s is undefined." + (cell-error-name condition)) + (format stream "Attempt to call an undefined alien function."))))) + +(define-condition unknown-keyword-argument (program-error) + ((name :reader unknown-keyword-argument-name :initarg :name)) + (:report + (lambda (condition stream) + (format stream "Unknown &KEY argument: ~S" + (unknown-keyword-argument-name condition))))) + + +;;;; various other (not specified by ANSI) CONDITIONs +;;;; +;;;; These might logically belong in other files; they're here, after +;;;; setup of CONDITION machinery, only because that makes it easier to +;;;; get cold init to work. + +;;; OAOOM warning: see cross-condition.lisp +(define-condition encapsulated-condition (condition) + ((condition :initarg :condition :reader encapsulated-condition))) + +;;; KLUDGE: a condition for floating point errors when we can't or +;;; won't figure out what type they are. (In FreeBSD and OpenBSD we +;;; don't know how, at least as of sbcl-0.6.7; in Linux we probably +;;; know how but the old code was broken by the conversion to POSIX +;;; signal handling and hasn't been fixed as of sbcl-0.6.7.) +;;; +;;; FIXME: Perhaps this should also be a base class for all +;;; floating point exceptions? +(define-condition floating-point-exception (arithmetic-error) + ((flags :initarg :traps + :initform nil + :reader floating-point-exception-traps)) + (:report (lambda (condition stream) + (format stream + "An arithmetic error ~S was signalled.~%" + (type-of condition)) + (let ((traps (floating-point-exception-traps condition))) + (if traps + (format stream + "Trapping conditions are: ~%~{ ~S~^~}~%" + traps) + (write-line + "No traps are enabled? How can this be?" + stream)))))) + +(define-condition invalid-array-index-error (type-error) + ((array :initarg :array :reader invalid-array-index-error-array) + (axis :initarg :axis :reader invalid-array-index-error-axis)) + (:report + (lambda (condition stream) + (let ((array (invalid-array-index-error-array condition))) + (format stream "Invalid index ~W for ~@[axis ~W of ~]~S, ~ + should be a non-negative integer below ~W." + (type-error-datum condition) + (when (> (array-rank array) 1) + (invalid-array-index-error-axis condition)) + (type-of array) + ;; Extract the bound from (INTEGER 0 (BOUND)) + (caaddr (type-error-expected-type condition))))))) + +(define-condition invalid-array-error (reference-condition type-error) () + (:report + (lambda (condition stream) + (let ((*print-array* nil)) + (format stream + "~@<Displaced array originally of type ~ + ~/sb-impl:print-type-specifier/ has been invalidated ~ + due its displaced-to array ~S having become too small ~ + to hold it: the displaced array's dimensions have all ~ + been set to zero to trap accesses to it.~:@>" + (type-error-expected-type condition) + (array-displacement (type-error-datum condition)))))) + (:default-initargs + :references + (list '(:ansi-cl :function adjust-array)))) + +(define-condition uninitialized-element-error (cell-error) () + (:report + (lambda (condition stream) + ;; NAME is a cons of the array and index + (destructuring-bind (array . index) (cell-error-name condition) + (declare (ignorable index)) + #+ubsan + (let* ((origin-pc + (ash (sb-vm::vector-extra-data + (if (simple-vector-p array) + array + (sb-vm::vector-extra-data array))) + -3)) ; XXX: ubsan magic + (origin-code (sb-di::code-header-from-pc (int-sap origin-pc)))) + (let ((*print-array* nil)) + (format stream "Element ~D of array ~_~S ~_was not assigned a value.~%Origin=~X" + index array (or origin-code origin-pc)))) + #-ubsan + ;; FOLD-INDEX-ADDRESSING could render INDEX wrong. There's no way to know. + (let ((*print-array* nil)) + (format stream "Uninitialized element accessed in array ~S" + array)))))) + + +;;; We signal this one for SEQUENCE operations, but INVALID-ARRAY-INDEX-ERROR +;;; for arrays. Might it be better to use the above condition for operations +;;; on SEQUENCEs that happen to be arrays? +(define-condition index-too-large-error (type-error) + ((sequence :initarg :sequence)) + (:report + (lambda (condition stream) + (let ((sequence (slot-value condition 'sequence)) + (index (type-error-datum condition))) + (if (vectorp sequence) + (format stream "Invalid index ~W for ~S ~@[with fill-pointer ~a~], ~ + should be a non-negative integer below ~W." + index + (type-of sequence) + (and (array-has-fill-pointer-p sequence) + (fill-pointer sequence)) + (length sequence)) + (format stream + "The index ~S is too large for a ~a of length ~s." + index + (if (listp sequence) + "list" + "sequence") + (length sequence))))))) + +(define-condition bounding-indices-bad-error (reference-condition type-error) + ((object :reader bounding-indices-bad-object :initarg :object)) + (:report + (lambda (condition stream) + (let* ((datum (type-error-datum condition)) + (start (car datum)) + (end (cdr datum)) + (object (bounding-indices-bad-object condition))) + (etypecase object + (sequence + (format stream + "The bounding indices ~S and ~S are bad ~ + for a sequence of length ~S." + start end (length object))) + (array + ;; from WITH-ARRAY-DATA + (format stream + "The START and END parameters ~S and ~S are ~ + bad for an array of total size ~S." + start end (array-total-size object))))))) + (:default-initargs + :references + (list '(:ansi-cl :glossary "bounding index designator") + '(:ansi-cl :issue "SUBSEQ-OUT-OF-BOUNDS:IS-AN-ERROR")))) + +(define-condition nil-array-accessed-error (reference-condition type-error) + () + (:report (lambda (condition stream) + (declare (ignore condition)) + (format stream + "An attempt to access an array of element-type ~ + NIL was made. Congratulations!"))) + (:default-initargs + :references '((:ansi-cl :function upgraded-array-element-type) + (:ansi-cl :section (15 1 2 1)) + (:ansi-cl :section (15 1 2 2))))) + +(define-condition namestring-parse-error (parse-error) + ((complaint :reader namestring-parse-error-complaint :initarg :complaint) + (args :reader namestring-parse-error-args :initarg :args :initform nil) + (namestring :reader namestring-parse-error-namestring :initarg :namestring) + (offset :reader namestring-parse-error-offset :initarg :offset)) + (:report + (lambda (condition stream) + (format stream + "parse error in namestring: ~?~% ~A~% ~V@T^" + (namestring-parse-error-complaint condition) + (namestring-parse-error-args condition) + (namestring-parse-error-namestring condition) + (namestring-parse-error-offset condition))))) + +(define-condition pathname-unparse-error (file-error + simple-condition) + ((problem :reader pathname-unparse-error-problem :initarg :problem)) + (:report (lambda (condition stream) + (format stream "~@<The pathname ~S ~A~:[.~; because ~:*~?~]~@:>" + (file-error-pathname condition) + (pathname-unparse-error-problem condition) + (simple-condition-format-control condition) + (simple-condition-format-arguments condition)))) + (:default-initargs + :problem (missing-arg))) + +(define-condition no-namestring-error (pathname-unparse-error + reference-condition) + () + (:default-initargs + :problem "does not have a namestring" + :references '((:ansi-cl :section (19 1 2))))) +(defun no-namestring-error + (pathname &optional format-control &rest format-arguments) + (error 'no-namestring-error + :pathname pathname + :format-control format-control :format-arguments format-arguments)) + +(define-condition no-native-namestring-error (pathname-unparse-error) + () + (:default-initargs + :problem "does not have a native namestring")) +(defun no-native-namestring-error + (pathname &optional format-control &rest format-arguments) + (error 'no-native-namestring-error + :pathname pathname + :format-control format-control :format-arguments format-arguments)) + +(define-condition simple-package-error (simple-condition package-error) ()) + +(define-condition package-does-not-exist (simple-package-error) ()) + +(define-condition simple-reader-package-error (simple-reader-error package-error) ()) +(define-condition reader-package-does-not-exist (simple-reader-package-error package-does-not-exist) ()) + +(define-condition reader-eof-error (end-of-file) + ((context :reader reader-eof-error-context :initarg :context)) + (:report + (lambda (condition stream) + (format stream + "unexpected end of file on ~S ~A" + (stream-error-stream condition) + (reader-eof-error-context condition))))) + +(define-condition reader-impossible-number-error (simple-reader-error) + ((error :reader reader-impossible-number-error-error :initarg :error)) + (:report + (lambda (condition stream) + (let ((error-stream (stream-error-stream condition))) + (format stream + "READER-ERROR ~@[at ~W ~]on ~S:~%~?~%Original error: ~A" + (sb-impl::file-position-or-nil-for-error error-stream) error-stream + (simple-condition-format-control condition) + (simple-condition-format-arguments condition) + (reader-impossible-number-error-error condition)))))) + +(define-condition standard-readtable-modified-error (reference-condition error) + ((operation :initarg :operation :reader standard-readtable-modified-operation)) + (:report (lambda (condition stream) + (format stream "~S would modify the standard readtable." + (standard-readtable-modified-operation condition)))) + (:default-initargs :references `((:ansi-cl :section (2 1 1 2)) + (:ansi-cl :glossary "standard readtable")))) + +(define-condition standard-pprint-dispatch-table-modified-error + (reference-condition error) + ((operation :initarg :operation + :reader standard-pprint-dispatch-table-modified-operation)) + (:report (lambda (condition stream) + (format stream "~S would modify the standard pprint dispatch table." + (standard-pprint-dispatch-table-modified-operation + condition)))) + (:default-initargs + :references `((:ansi-cl :glossary "standard pprint dispatch table")))) + +(define-condition timeout (serious-condition) + ((seconds :initarg :seconds :initform nil :reader timeout-seconds)) + (:report (lambda (condition stream) + (format stream "Timeout occurred~@[ after ~A second~:P~]." + (timeout-seconds condition)))) + (:documentation + "Signaled when an operation does not complete within an allotted time budget.")) + +(define-condition io-timeout (stream-error timeout) + ((direction :reader io-timeout-direction :initarg :direction)) + (:report + (lambda (condition stream) + (declare (type stream stream)) + (format stream + "I/O timeout while doing ~(~A~) on ~S." + (io-timeout-direction condition) + (stream-error-stream condition))))) + +(define-condition deadline-timeout (timeout) + () + (:report (lambda (condition stream) + (format stream "A deadline was reached after ~A second~:P." + (timeout-seconds condition)))) + (:documentation + "Signaled when an operation in the context of a deadline takes +longer than permitted by the deadline.")) + +(define-condition declaration-type-conflict-error (reference-condition + simple-error) + () + (:default-initargs + :format-control + #.(macroexpand-1 ; stuff in a literal #<fmt-control> + '(sb-format:tokens "Symbol ~/sb-ext:print-symbol-with-prefix/ cannot ~ + be both the name of a type and the name of a declaration")) + :references '((:ansi-cl :section (3 8 21))))) + +;;; Single stepping conditions + +(define-condition step-condition () + ((form :initarg :form :reader step-condition-form)) + (:documentation "Common base class of single-stepping conditions. +STEP-CONDITION-FORM holds a string representation of the form being +stepped.")) + +(setf (documentation 'step-condition-form 'function) + "Form associated with the STEP-CONDITION.") + +(define-condition step-form-condition (step-condition) + ((args :initarg :args :reader step-condition-args)) + (:report + (lambda (condition stream) + (let ((*print-circle* t) + (*print-pretty* t) + (*print-readably* nil)) + (format stream + "Evaluating call:~%~< ~@;~A~:>~%~ + ~:[With arguments:~%~{ ~S~%~}~;With unknown arguments~]~%" + (list (step-condition-form condition)) + (eq (step-condition-args condition) :unknown) + (step-condition-args condition))))) + (:documentation "Condition signalled by code compiled with +single-stepping information when about to execute a form. +STEP-CONDITION-FORM holds the form, STEP-CONDITION-PATHNAME holds the +pathname of the original file or NIL, and STEP-CONDITION-SOURCE-PATH +holds the source-path to the original form within that file or NIL. +Associated with this condition are always the restarts STEP-INTO, +STEP-NEXT, and STEP-CONTINUE.")) + +(define-condition step-result-condition (step-condition) + ((result :initarg :result :reader step-condition-result))) + +(setf (documentation 'step-condition-result 'function) + "Return values associated with STEP-VALUES-CONDITION as a list, +or the variable value associated with STEP-VARIABLE-CONDITION.") + +(define-condition step-values-condition (step-result-condition) + () + (:documentation "Condition signalled by code compiled with +single-stepping information after executing a form. +STEP-CONDITION-FORM holds the form, and STEP-CONDITION-RESULT holds +the values returned by the form as a list. No associated restarts.")) + +(define-condition step-finished-condition (step-condition) + () + (:report + (lambda (condition stream) + (declare (ignore condition)) + (format stream "Returning from STEP"))) + (:documentation "Condition signaled when STEP returns.")) + +;;; A knob for muffling warnings, mostly for use while loading files. +(defvar *muffled-warnings* 'uninteresting-redefinition + "A type that ought to specify a subtype of WARNING. Whenever a +warning is signaled, if the warning is of this type and is not +handled by any other handler, it will be muffled.") + +;;; Various STYLE-WARNING signaled in the system. +;; For the moment, we're only getting into the details for function +;; redefinitions, but other redefinitions could be done later +;; (e.g. methods). +(define-condition redefinition-warning (style-warning) + ((name + :initarg :name + :reader redefinition-warning-name) + (new-location + :initarg :new-location + :reader redefinition-warning-new-location))) + +(define-condition function-redefinition-warning (redefinition-warning) + ((new-function + :initarg :new-function + :reader function-redefinition-warning-new-function))) + +(define-condition redefinition-with-defun (function-redefinition-warning) + () + (:report (lambda (warning stream) + (format stream "redefining ~/sb-ext:print-symbol-with-prefix/ ~ + in DEFUN" + (redefinition-warning-name warning))))) + +(define-condition redefinition-with-defmacro (function-redefinition-warning) + () + (:report (lambda (warning stream) + (format stream "redefining ~/sb-ext:print-symbol-with-prefix/ ~ + in DEFMACRO" + (redefinition-warning-name warning))))) + +(define-condition redefinition-with-defgeneric (redefinition-warning) + () + (:report (lambda (warning stream) + (format stream "redefining ~/sb-ext:print-symbol-with-prefix/ ~ + in DEFGENERIC" + (redefinition-warning-name warning))))) + +(define-condition redefinition-with-defmethod (redefinition-warning) + ((qualifiers :initarg :qualifiers + :reader redefinition-with-defmethod-qualifiers) + (specializers :initarg :specializers + :reader redefinition-with-defmethod-specializers) + (new-location :initarg :new-location + :reader redefinition-with-defmethod-new-location) + (old-method :initarg :old-method + :reader redefinition-with-defmethod-old-method)) + (:report (lambda (warning stream) + (format stream "redefining ~S~{ ~S~} ~S in DEFMETHOD" + (redefinition-warning-name warning) + (redefinition-with-defmethod-qualifiers warning) + (redefinition-with-defmethod-specializers warning))))) + +;;;; Deciding which redefinitions are "interesting". + +(defun function-file-namestring (function) + (when (typep function 'interpreted-function) + (return-from function-file-namestring + #+sb-eval + (sb-c:definition-source-location-namestring + (sb-eval:interpreted-function-source-location function)) + #+sb-fasteval + (awhen (sb-interpreter:fun-source-location function) + (sb-c:definition-source-location-namestring it)))) + (let* ((fun (%fun-fun function)) + (code (fun-code-header fun)) + (debug-info (%code-debug-info code)) + (debug-source (when debug-info + (sb-c::debug-info-source debug-info))) + (namestring (when debug-source + (debug-source-namestring debug-source)))) + namestring)) + +(defun interesting-function-redefinition-warning-p (warning old) + (let ((new (function-redefinition-warning-new-function warning))) + (or + ;; compiled->interpreted is interesting. + (and (typep old 'compiled-function) + (typep new '(not compiled-function))) + ;; fin->regular is interesting except for interpreted->compiled. + (and (typep new '(not funcallable-instance)) + (typep old '(and funcallable-instance (not interpreted-function)))) + ;; different file or unknown location is interesting. + (let* ((old-namestring (function-file-namestring old)) + (new-namestring (function-file-namestring new))) + (and (or (not old-namestring) + (not new-namestring) + (not (string= old-namestring new-namestring)))))))) + +(setf (info :function :predicate-truth-constraint + 'uninteresting-ordinary-function-redefinition-p) 'warning) +(defun uninteresting-ordinary-function-redefinition-p (warning) + (and + (typep warning 'redefinition-with-defun) + ;; Shared logic. + (let ((name (redefinition-warning-name warning))) + (not (interesting-function-redefinition-warning-p + warning (or (fdefinition name) (macro-function name))))))) + +(setf (info :function :predicate-truth-constraint + 'uninteresting-macro-redefinition-p) 'warning) +(defun uninteresting-macro-redefinition-p (warning) + (and + (typep warning 'redefinition-with-defmacro) + ;; Shared logic. + (let ((name (redefinition-warning-name warning))) + (not (interesting-function-redefinition-warning-p + warning (or (macro-function name) (fdefinition name))))))) + +(setf (info :function :predicate-truth-constraint + 'uninteresting-generic-function-redefinition-p) 'warning) +(defun uninteresting-generic-function-redefinition-p (warning) + (and + (typep warning 'redefinition-with-defgeneric) + ;; Can't use the shared logic above, since GF's don't get a "new" + ;; definition -- rather the FIN-FUNCTION is set. + (let* ((name (redefinition-warning-name warning)) + (old (fdefinition name)) + (old-location (when (typep old 'generic-function) + (sb-pcl::definition-source old))) + (old-namestring (when old-location + (sb-c:definition-source-location-namestring old-location))) + (new-location (redefinition-warning-new-location warning)) + (new-namestring (when new-location + (sb-c:definition-source-location-namestring new-location)))) + (and old-namestring + new-namestring + (string= old-namestring new-namestring))))) + +(setf (info :function :predicate-truth-constraint + 'uninteresting-method-redefinition-p) 'warning) +(defun uninteresting-method-redefinition-p (warning) + (and + (typep warning 'redefinition-with-defmethod) + ;; Can't use the shared logic above, since GF's don't get a "new" + ;; definition -- rather the FIN-FUNCTION is set. + (let* ((old-method (redefinition-with-defmethod-old-method warning)) + (old-location (sb-pcl::definition-source old-method)) + (old-namestring (when old-location + (sb-c:definition-source-location-namestring old-location))) + (new-location (redefinition-warning-new-location warning)) + (new-namestring (when new-location + (sb-c:definition-source-location-namestring new-location)))) + (and new-namestring + old-namestring + (string= new-namestring old-namestring))))) + +(deftype uninteresting-redefinition () + '(or (satisfies uninteresting-ordinary-function-redefinition-p) + (satisfies uninteresting-macro-redefinition-p) + (satisfies uninteresting-generic-function-redefinition-p) + (satisfies uninteresting-method-redefinition-p))) + +(define-condition redefinition-with-deftransform (redefinition-warning) + ((transform :initarg :transform + :reader redefinition-with-deftransform-transform)) + (:report (lambda (warning stream) + (format stream "Overwriting ~S" + (redefinition-with-deftransform-transform warning))))) + +;;; Various other STYLE-WARNINGS +(define-condition dubious-asterisks-around-variable-name + (style-warning simple-condition) + () + (:report (lambda (warning stream) + (format stream "~@?, even though the name follows~@ +the usual naming convention (names like *FOO*) for special variables" + (simple-condition-format-control warning) + (simple-condition-format-arguments warning))))) + +(define-condition asterisks-around-lexical-variable-name + (dubious-asterisks-around-variable-name) + ()) + +(define-condition asterisks-around-constant-variable-name + (dubious-asterisks-around-variable-name) + ()) + +(define-condition &optional-and-&key-in-lambda-list (simple-style-warning) ()) + +;; We call this UNDEFINED-ALIEN-STYLE-WARNING because there are some +;; subclasses of ERROR above having to do with undefined aliens. +(define-condition undefined-alien-style-warning (style-warning) + ((symbol :initarg :symbol :reader undefined-alien-symbol)) + (:report (lambda (warning stream) + (format stream "Undefined alien: ~S" + (undefined-alien-symbol warning))))) + +;;; Formerly this was guarded by "#+(or sb-eval sb-fasteval)", but +;;; why would someone build with no interpreter? And if they did, +;;; would they really care that one extra condition definition exists? +(define-condition lexical-environment-too-complex (style-warning) + ((form :initarg :form :reader lexical-environment-too-complex-form) + (lexenv :initarg :lexenv :reader lexical-environment-too-complex-lexenv)) + (:report (lambda (warning stream) + (format stream + "~@<Native lexical environment too complex for ~ + SB-EVAL to evaluate ~S, falling back to ~ + SIMPLE-EVAL-IN-LEXENV. Lexenv: ~S~:@>" + (lexical-environment-too-complex-form warning) + (lexical-environment-too-complex-lexenv warning))))) + +;; If the interpreter is in use (and the REPL is interpreted), +;; it's easy to accidentally make the macroexpand-hook an interpreted +;; function. So MACROEXPAND-1 is a little more careful, +;; and might signal this, instead of only EVAL being able to signal it. +(define-condition macroexpand-hook-type-error (type-error) + () + (:report (lambda (condition stream) + (format stream "The value of *MACROEXPAND-HOOK* is not a designator for a compiled function: ~S" + (type-error-datum condition))))) + +;; Although this has -ERROR- in the name, it's just a STYLE-WARNING. +(define-condition character-decoding-error-in-comment (style-warning) + ((stream :initarg :stream :reader decoding-error-in-comment-stream) + (position :initarg :position :reader decoding-error-in-comment-position)) + (:report (lambda (warning stream) + (format stream + "Character decoding error in a ~A-comment at ~ + position ~A reading source stream ~A, ~ + resyncing." + (decoding-error-in-comment-macro warning) + (decoding-error-in-comment-position warning) + (decoding-error-in-comment-stream warning))))) + +(define-condition character-decoding-error-in-macro-char-comment + (character-decoding-error-in-comment) + ((char :initform #\; :initarg :char + :reader character-decoding-error-in-macro-char-comment-char))) + +(define-condition character-decoding-error-in-dispatch-macro-char-comment + (character-decoding-error-in-comment) + ;; ANSI doesn't give a way for a reader function invoked by a + ;; dispatch macro character to determine which dispatch character + ;; was used, so if a user wants to signal one of these from a custom + ;; comment reader, he'll have to supply the :DISP-CHAR himself. + ((disp-char :initform #\# :initarg :disp-char + :reader character-decoding-error-in-macro-char-comment-disp-char) + (sub-char :initarg :sub-char + :reader character-decoding-error-in-macro-char-comment-sub-char))) + +(defun decoding-error-in-comment-macro (warning) + (etypecase warning + (character-decoding-error-in-macro-char-comment + (character-decoding-error-in-macro-char-comment-char warning)) + (character-decoding-error-in-dispatch-macro-char-comment + (format + nil "~C~C" + (character-decoding-error-in-macro-char-comment-disp-char warning) + (character-decoding-error-in-macro-char-comment-sub-char warning))))) + +(define-condition deprecated-eval-when-situations (style-warning) + ((situations :initarg :situations + :reader deprecated-eval-when-situations-situations)) + (:report (lambda (warning stream) + (format stream "using deprecated EVAL-WHEN situation names~{ ~S~}" + (deprecated-eval-when-situations-situations warning))))) + +(define-condition proclamation-mismatch (condition) + ((kind :initarg :kind :reader proclamation-mismatch-kind) + (description :initarg :description :reader proclamation-mismatch-description :initform nil) + (name :initarg :name :reader proclamation-mismatch-name) + (old :initarg :old :reader proclamation-mismatch-old) + (new :initarg :new :reader proclamation-mismatch-new)) + (:report + (lambda (condition stream) + (format stream + "~@<The new ~A proclamation for~@[ ~A~] ~ + ~/sb-ext:print-symbol-with-prefix/~ + ~@:_~2@T~/sb-impl:print-type-specifier/~@:_~ + does not match the old ~4:*~A~3* proclamation~ + ~@:_~2@T~/sb-impl:print-type-specifier/~@:>" + (proclamation-mismatch-kind condition) + (proclamation-mismatch-description condition) + (proclamation-mismatch-name condition) + (proclamation-mismatch-new condition) + (proclamation-mismatch-old condition))))) + +(define-condition type-proclamation-mismatch (proclamation-mismatch) + () + (:default-initargs :kind 'type)) + +(define-condition type-proclamation-mismatch-warning (style-warning + type-proclamation-mismatch) + ()) + +(define-condition ftype-proclamation-mismatch (proclamation-mismatch) + () + (:default-initargs :kind 'ftype)) + +(define-condition ftype-proclamation-mismatch-warning (style-warning + ftype-proclamation-mismatch) + ()) + +(define-condition ftype-proclamation-mismatch-error (error + ftype-proclamation-mismatch) + () + (:default-initargs :kind 'ftype :description "known function")) + + +;;;; deprecation conditions + +(define-condition deprecation-condition (reference-condition) + ((namespace :initarg :namespace + :reader deprecation-condition-namespace) + (name :initarg :name + :reader deprecation-condition-name) + (replacements :initarg :replacements + :reader deprecation-condition-replacements) + (software :initarg :software + :reader deprecation-condition-software) + (version :initarg :version + :reader deprecation-condition-version) + (runtime-error :initarg :runtime-error + :reader deprecation-condition-runtime-error + :initform nil)) + (:default-initargs + :namespace (missing-arg) + :name (missing-arg) + :replacements (missing-arg) + :software (missing-arg) + :version (missing-arg) + :references '((:sbcl :node "Deprecation Conditions"))) + (:documentation + "Superclass for deprecation-related error and warning +conditions.")) + +(defmethod print-object ((condition deprecation-condition) stream) + (flet ((print-it (stream) + (print-deprecation-message + (deprecation-condition-namespace condition) + (deprecation-condition-name condition) + (deprecation-condition-software condition) + (deprecation-condition-version condition) + (deprecation-condition-replacements condition) + stream))) + (if *print-escape* + (print-unreadable-object (condition stream :type t) + (print-it stream)) + (print-it stream)))) + +(macrolet ((define-deprecation-warning + (name superclass check-runtime-error format-string + &optional documentation) + `(progn + (define-condition ,name (,superclass deprecation-condition) + () + ,@(when documentation + `((:documentation ,documentation)))) + + (defmethod print-object :after ((condition ,name) stream) + (when (and (not *print-escape*) + ,@(when check-runtime-error + `((deprecation-condition-runtime-error condition)))) + (format stream ,format-string + (deprecation-condition-software condition) + (deprecation-condition-name condition))))))) + + ;; These conditions must not occur in self-build! + (define-deprecation-warning early-deprecation-warning style-warning nil + "~%~@<~:@_In future~@[ ~A~] versions ~ + ~/sb-ext:print-symbol-with-prefix/ will signal a full warning ~ + at compile-time.~:@>" + "This warning is signaled when the use of a variable, +function, type, etc. in :EARLY deprecation is detected at +compile-time. The use will work at run-time with no warning or +error.") + + (define-deprecation-warning late-deprecation-warning warning t + "~%~@<~:@_In future~@[ ~A~] versions ~ + ~/sb-ext:print-symbol-with-prefix/ will signal a runtime ~ + error.~:@>" + "This warning is signaled when the use of a variable, +function, type, etc. in :LATE deprecation is detected at +compile-time. The use will work at run-time with no warning or +error.") + + (define-deprecation-warning final-deprecation-warning warning t + "~%~@<~:@_~*An error will be signaled at runtime for ~ + ~/sb-ext:print-symbol-with-prefix/.~:@>" + "This warning is signaled when the use of a variable, +function, type, etc. in :FINAL deprecation is detected at +compile-time. An error will be signaled at run-time.")) + +(define-condition deprecation-error (error deprecation-condition) + () + (:documentation + "This error is signaled at run-time when an attempt is made to use +a thing that is in :FINAL deprecation, i.e. call a function or access +a variable.")) + +;;;; restart definitions + +(define-condition abort-failure (control-error) () + (:report + "An ABORT restart was found that failed to transfer control dynamically.")) + +(defun abort (&optional condition) + "Transfer control to a restart named ABORT, signalling a CONTROL-ERROR if + none exists." + (invoke-restart (find-restart-or-control-error 'abort condition)) + ;; ABORT signals an error in case there was a restart named ABORT + ;; that did not transfer control dynamically. This could happen with + ;; RESTART-BIND. + (error 'abort-failure)) + +(defun muffle-warning (&optional condition) + "Transfer control to a restart named MUFFLE-WARNING, signalling a + CONTROL-ERROR if none exists." + (invoke-restart (find-restart-or-control-error 'muffle-warning condition))) + +(defun try-restart (name condition &rest arguments) + (let ((restart (find-restart name condition))) + (when restart + (apply #'invoke-restart restart arguments)))) + +(macrolet ((define-nil-returning-restart (name args doc) + `(defun ,name (,@args &optional condition) + ,doc + (try-restart ',name condition ,@args)))) + (define-nil-returning-restart continue () + "Transfer control to a restart named CONTINUE, or return NIL if none exists.") + (define-nil-returning-restart store-value (value) + "Transfer control and VALUE to a restart named STORE-VALUE, or +return NIL if none exists.") + (define-nil-returning-restart use-value (value) + "Transfer control and VALUE to a restart named USE-VALUE, or +return NIL if none exists.") + (define-nil-returning-restart print-unreadably () + "Transfer control to a restart named SB-EXT:PRINT-UNREADABLY, or +return NIL if none exists.")) + +;;; single-stepping restarts + +(macrolet ((def (name doc) + `(defun ,name (condition) + ,doc + (invoke-restart (find-restart-or-control-error ',name condition))))) + (def step-continue + "Transfers control to the STEP-CONTINUE restart associated with +the condition, continuing execution without stepping. Signals a +CONTROL-ERROR if the restart does not exist.") + (def step-next + "Transfers control to the STEP-NEXT restart associated with the +condition, executing the current form without stepping and continuing +stepping with the next form. Signals CONTROL-ERROR if the restart does +not exist.") + (def step-into + "Transfers control to the STEP-INTO restart associated with the +condition, stepping into the current form. Signals a CONTROL-ERROR if +the restart does not exist.")) + +;;; Compiler macro magic + +(define-condition compiler-macro-keyword-problem () + ((argument :initarg :argument :reader compiler-macro-keyword-argument)) + (:report (lambda (condition stream) + (format stream "~@<Argument ~S in keyword position is not ~ + a self-evaluating symbol, preventing compiler-macro ~ + expansion.~@:>" + (compiler-macro-keyword-argument condition))))) + +;; After (or if) we deem this the optimal name for this condition, +;; it should be exported from SB-EXT so that people can muffle it. +(define-condition sb-c:inlining-dependency-failure (simple-style-warning) ()) + + +(define-condition layout-invalid (type-error) + () + (:report + (lambda (condition stream) + (format stream + "~@<invalid structure layout: ~ + ~2I~_A test for class ~4I~_~S ~ + ~2I~_was passed the obsolete instance ~4I~_~S~:>" + (classoid-proper-name (type-error-expected-type condition)) + (type-error-datum condition))))) + +(define-condition case-failure (type-error) + ((name :reader case-failure-name :initarg :name) + ;; This is an internal symbol of SB-KERNEL, so I can't imagine that anyone + ;; expects an invariant that it be a list. + (possibilities :reader case-failure-possibilities :initarg :possibilities)) + (:report + (lambda (condition stream) + (let ((possibilities (case-failure-possibilities condition))) + (if (symbolp possibilities) + (report-general-type-error condition stream) + (let ((*print-escape* t)) + (format stream "~@<~S fell through ~S expression.~@[ ~ + ~:_Wanted one of (~/pprint-fill/).~]~:>" + (type-error-datum condition) + (case-failure-name condition) + (case-failure-possibilities condition)))))))) + +(define-condition compiled-program-error (program-error) + ((message :initarg :message :reader program-error-message) + (source :initarg :source :reader program-error-source)) + (:report (lambda (condition stream) + (format stream "Execution of a form compiled with errors.~%~ + Form:~% ~A~%~ + Compile-time error:~% ~A" + (program-error-source condition) + (program-error-message condition))))) + +(define-condition simple-control-error (simple-condition control-error) ()) + +(define-condition simple-file-error (simple-condition file-error) + ((message :initarg :message :reader simple-file-error-message :initform nil)) + (:report + (lambda (condition stream) + (format stream "~@<~?~@[: ~2I~_~A~]~@:>" + (simple-condition-format-control condition) + (simple-condition-format-arguments condition) + (simple-file-error-message condition))))) + +(defun %file-error (pathname &optional datum &rest arguments) + (typecase datum + (format-control (error 'simple-file-error :pathname pathname + :format-control datum + :format-arguments arguments)) + (t (apply #'error datum :pathname pathname arguments)))) + +(define-condition file-exists (simple-file-error) () + (:report + (lambda (condition stream) + (format stream "~@<The file ~S already exists~@[: ~2I~_~A~]~@:>" + (file-error-pathname condition) + (simple-file-error-message condition))))) + +(define-condition file-does-not-exist (simple-file-error) () + (:report + (lambda (condition stream) + (format stream "~@<The file ~S does not exist~@[: ~2I~_~A~]~@:>" + (file-error-pathname condition) + (simple-file-error-message condition))))) + +(define-condition delete-file-error (simple-file-error) () + (:report + (lambda (condition stream) + (format stream "~@<Could not delete the file ~S~@[: ~2I~_~A~]~@:>" + (file-error-pathname condition) + (simple-file-error-message condition))))) + +(define-condition simple-stream-error (simple-condition stream-error) ()) +(define-condition simple-parse-error (simple-condition parse-error) ()) + +(define-condition broken-pipe (simple-stream-error) ()) + +(define-condition character-coding-error (error) + ((external-format :initarg :external-format :reader character-coding-error-external-format))) +(define-condition character-encoding-error (character-coding-error) + ((code :initarg :code :reader character-encoding-error-code))) +(define-condition character-decoding-error (character-coding-error) + ((octets :initarg :octets :reader character-decoding-error-octets))) +(define-condition stream-encoding-error (stream-error character-encoding-error) + () + (:report + (lambda (c s) + (let ((stream (stream-error-stream c)) + (code (character-encoding-error-code c))) + (format s "~@<~S stream encoding error on ~S: ~2I~_~ + the character with code ~D cannot be encoded.~@:>" + (character-coding-error-external-format c) + stream + code))))) +(define-condition stream-decoding-error (stream-error character-decoding-error) + () + (:report + (lambda (c s) + (let ((stream (stream-error-stream c)) + (octets (character-decoding-error-octets c))) + (format s "~@<~S stream decoding error on ~S: ~2I~_~ + the octet sequence ~S cannot be decoded.~@:>" + (character-coding-error-external-format c) + stream + octets))))) + +(define-condition c-string-encoding-error (character-encoding-error) + () + (:report + (lambda (c s) + (format s "~@<~S c-string encoding error: ~2I~_~ + the character with code ~D cannot be encoded.~@:>" + (character-coding-error-external-format c) + (character-encoding-error-code c))))) + +(define-condition c-string-decoding-error (character-decoding-error) + () + (:report + (lambda (c s) + (format s "~@<~S c-string decoding error: ~2I~_~ + the octet sequence ~S cannot be decoded.~@:>" + (character-coding-error-external-format c) + (character-decoding-error-octets c))))) + +(define-condition control-stack-exhausted (storage-condition) + () + (:report + (lambda (condition stream) + (declare (ignore condition)) + (format stream + ;; no pretty-printing, because that would use a lot of stack. + "Control stack exhausted (no more space for function call frames). +This is probably due to heavily nested or infinitely recursive function +calls, or a tail call that SBCL cannot or has not optimized away. + +PROCEED WITH CAUTION.")))) + +(define-condition binding-stack-exhausted (storage-condition) + () + (:report + (lambda (condition stream) + (declare (ignore condition)) + (format stream + ;; no pretty-printing, because that would use a lot of stack. + "Binding stack exhausted. + +PROCEED WITH CAUTION.")))) + +(define-condition alien-stack-exhausted (storage-condition) + () + (:report + (lambda (condition stream) + (declare (ignore condition)) + (format stream + ;; no pretty-printing, because that would use a lot of stack. + "Alien stack exhausted. + +PROCEED WITH CAUTION.")))) + +(define-condition heap-exhausted-error (storage-condition) + () + (:report + (lambda (condition stream) + (declare (ignore condition)) + (declare (special *heap-exhausted-error-available-bytes* + *heap-exhausted-error-requested-bytes*)) + ;; See comments in interr.lisp -- there is a method to this madness. + (if (and (boundp '*heap-exhausted-error-available-bytes*) + (boundp '*heap-exhausted-error-requested-bytes*)) + (format stream + ;; no pretty-printing, because that will use a lot of heap. + "Heap exhausted (no more space for allocation). +~D bytes available, ~D requested. + +PROCEED WITH CAUTION." + *heap-exhausted-error-available-bytes* + *heap-exhausted-error-requested-bytes*) + (format stream + "A ~S condition without bindings for heap statistics. (If +you did not expect to see this message, please report it." + 'heap-exhausted-error))))) + +(define-condition system-condition (condition) + ((address :initarg :address :reader system-condition-address :initform nil) + (context :initarg :context :reader system-condition-context :initform nil))) + +(define-condition breakpoint-error (system-condition error) () + (:report + (lambda (condition stream) + (format stream "Unhandled breakpoint/trap at #x~X." + (system-condition-address condition))))) + +(define-condition interactive-interrupt (system-condition serious-condition) () + (:report + (lambda (condition stream) + (format stream "Interactive interrupt at #x~X." + (system-condition-address condition))))) + + +;;;; Condition reporting: + +;;; FIXME: ANSI's definition of DEFINE-CONDITION says +;;; Condition reporting is mediated through the PRINT-OBJECT method +;;; for the condition type in question, with *PRINT-ESCAPE* always +;;; being nil. Specifying (:REPORT REPORT-NAME) in the definition of +;;; a condition type C is equivalent to: +;;; (defmethod print-object ((x c) stream) +;;; (if *print-escape* (call-next-method) (report-name x stream))) +;;; The current code doesn't seem to quite match that. +(defmethod print-object ((object condition) stream) + (declare (notinline classoid-of)) ; to avoid can't inline warning. speed irrelevant here + (cond + ((not *print-escape*) + ;; KLUDGE: A comment from CMU CL here said + ;; 7/13/98 BUG? CPL is not sorted and results here depend on order of + ;; superclasses in define-condition call! + (funcall (or (some #'condition-classoid-report + (condition-classoid-cpl (classoid-of object))) + (error "no REPORT? shouldn't happen!")) + object stream)) + ((and (typep object 'simple-condition) + (condition-slot-value object 'format-control)) + (print-unreadable-object (object stream :type t :identity t) + (write (simple-condition-format-control object) + :stream stream :lines 1))) + (t + (print-unreadable-object (object stream :type t :identity t))))) + (defun assert-error (assertion &rest rest) (let* ((rest rest) @@ -296,7 +2495,7 @@ with that condition (or with no condition) will be returned." (error 'case-failure :name 'etypecase :datum value - :expected-type `(or ,@keys) + :expected-type (if (symbolp keys) keys `(or ,@keys)) :possibilities keys)) (defun ecase-failure (value keys) diff --git a/src/code/target-exception.lisp b/src/code/target-exception.lisp index fc081fbdfc..8886125689 100644 --- a/src/code/target-exception.lisp +++ b/src/code/target-exception.lisp @@ -59,6 +59,8 @@ ;; Various (cons-name +exception-single-step+) (cons +exception-access-violation+ 'memory-fault-error) + #+x86-64 + (cons +exception-heap-corruption+ 'foreign-heap-corruption) (cons-name +exception-array-bounds-exceeded+) (cons-name +exception-breakpoint+) (cons-name +exception-datatype-misalignment+) @@ -112,6 +114,19 @@ (exception-record c) (exception-code c))))) +;;; Undocumented exception (STATUS_HEAP_CORRUPTION). Occurs when calling free() +;;; with a bad pointer and possibly other places. On 64-bit processes, +;;; frame-based handlers don't get a chance to handle this exception because the +;;; HeapSetInformation() option HeapEnableTerminationOnCorruption is enabled by +;;; default and cannot be disabled. For the sake of interactive development and +;;; error reporting, we special-case this exception in our vectored exception +;;; handler, otherwise the SBCL process would be abruptly terminated. +#+x86-64 +(define-condition foreign-heap-corruption (error) () + (:report + #.(format nil "A foreign heap corruption exception occurred. (Exception code: ~S)" + +exception-heap-corruption+))) + ;;; Actual exception handler. We hit something the runtime doesn't ;;; want to or know how to deal with (that is, not a sigtrap or gc wp ;;; violation), so it calls us here. diff --git a/src/code/target-extensions.lisp b/src/code/target-extensions.lisp index a6d022249a..fb5c32a2df 100644 --- a/src/code/target-extensions.lisp +++ b/src/code/target-extensions.lisp @@ -55,7 +55,8 @@ Unused by SBCL itself: reserved for user and applications.") (define-load-time-global *init-hooks* nil "A list of function designators which are called in an unspecified order when a saved core image starts up, after the system itself has -been initialized. +been initialized, but before non-user threads such as the finalizer +thread have been started. Unused by SBCL itself: reserved for user and applications.") @@ -148,11 +149,11 @@ these hooks.") `(let* ((,size ,initial-size) (,string (make-array ,size :element-type ',element-type)) (,pointer 0)) - (declare (type (integer 0 ,sb-xc:array-dimension-limit) ,size) - (type (integer 0 ,(1- sb-xc:array-dimension-limit)) ,pointer) + (declare (type (integer 0 ,array-dimension-limit) ,size) + (type (integer 0 ,(1- array-dimension-limit)) ,pointer) (type (simple-array ,element-type (*)) ,string)) (flet ((push-char (char) - (declare (optimize (sb-c::insert-array-bounds-checks 0))) + (declare (optimize (sb-c:insert-array-bounds-checks 0))) (when (= ,pointer ,size) (let ((old ,string)) (setf ,size (* 2 (+ ,size 2)) @@ -184,11 +185,6 @@ unspecified." `(sb-thread:with-recursive-lock ((hash-table-lock ,hash-table)) ,@body)) -(defmacro with-locked-system-table ((hash-table) &body body) - `(sb-thread::with-recursive-system-lock - ((hash-table-lock ,hash-table)) - ,@body)) - (defmacro find-package-restarts ((package-designator &optional reader) &body body) (let ((package `(or ,(if reader @@ -286,3 +282,20 @@ unspecified." `(defvar ,name ,@(when valuep (list value)))) ((:final) `',name)))) + +(define-load-time-global *deprecated-exports* nil) + +(defun deprecate-export (package symbol state version) + (declare (type deprecation-state state) + (type string version) + (type symbol symbol)) + (setf (getf (getf *deprecated-exports* package) symbol) + (cons state version))) + +(defun check-deprecated-export (package symbol) + (let ((state (getf (getf *deprecated-exports* package) symbol))) + (when state + (deprecation-warn (car state) "SBCL" (cdr state) 'symbol + (format nil "~A:~A" (package-name package) symbol) + (list symbol)) + t))) diff --git a/src/code/target-format.lisp b/src/code/target-format.lisp index 7eccbf0b5b..0612a1194c 100644 --- a/src/code/target-format.lisp +++ b/src/code/target-format.lisp @@ -50,7 +50,7 @@ f)) (defun unparse-fmt-control (fmt) - (with-simple-output-to-string (s) + (%with-output-to-string (s) (write-char #\" s) (let ((symbols (fmt-control-symbols fmt))) (dolist (piece (tokenize-control-string (fmt-control-string fmt))) @@ -98,10 +98,10 @@ (dynamic-extent format-arguments)) (etypecase destination (null - (with-simple-output-to-string (stream) + (%with-output-to-string (stream) (%format stream control-string format-arguments))) (string - (with-simple-output-to-string (stream destination) + (with-output-to-string (stream destination) (%format stream control-string format-arguments))) ((member t) (%format *standard-output* control-string format-arguments) @@ -134,6 +134,14 @@ (tokenize-control-string string)))) (interpret-directive-list stream tokens orig-args args))))) + +(!begin-collecting-cold-init-forms) +(define-load-time-global *format-directive-interpreters* nil) +(!cold-init-forms + (setq *format-directive-interpreters* (make-array 128 :initial-element nil))) +(declaim (type (simple-vector 128) + *format-directive-interpreters*)) + (defun interpret-directive-list (stream directives orig-args args) (loop (unless directives @@ -177,9 +185,10 @@ "~:@(~:C~)-FORMAT-DIRECTIVE-INTERPRETER" char))) (directive '.directive) ; expose this var to the lambda. it's easiest - (directives (if lambda-list (car (last lambda-list)) (sb-xc:gensym "DIRECTIVES")))) - `(setf - (aref *format-directive-interpreters* (sb-xc:char-code (char-upcase ,char))) + (directives (if lambda-list (car (last lambda-list)) (gensym "DIRECTIVES")))) + `(!cold-init-forms + (setf + (aref *format-directive-interpreters* ,(char-code (char-upcase char))) (named-lambda ,defun-name (stream ,directive ,directives orig-args args) (declare (ignorable stream orig-args args)) ,@(if lambda-list @@ -189,10 +198,10 @@ (butlast lambda-list)) (values (progn ,@body) args))) `((declare (ignore ,directive ,directives)) - ,@body)))))) + ,@body))))))) (defmacro def-format-interpreter (char lambda-list &body body) - (let ((directives (sb-xc:gensym "DIRECTIVES"))) + (let ((directives (gensym "DIRECTIVES"))) `(def-complex-format-interpreter ,char (,@lambda-list ,directives) ,@body ,directives))) @@ -388,36 +397,22 @@ (format-print-ordinal stream arg) (format-print-cardinal stream arg))))))) -(defconstant +cardinal-ones+ - #(nil "one" "two" "three" "four" "five" "six" "seven" "eight" "nine")) - -(defconstant +cardinal-tens+ +(defconstant-eqx +cardinal-tens+ #(nil nil "twenty" "thirty" "forty" - "fifty" "sixty" "seventy" "eighty" "ninety")) + "fifty" "sixty" "seventy" "eighty" "ninety") + #'equalp) -(defconstant +cardinal-teens+ +(defconstant-eqx +cardinal-teens+ #("ten" "eleven" "twelve" "thirteen" "fourteen" ;;; RAD - "fifteen" "sixteen" "seventeen" "eighteen" "nineteen")) - -(defconstant +cardinal-periods+ - #("" " thousand" " million" " billion" " trillion" " quadrillion" - " quintillion" " sextillion" " septillion" " octillion" " nonillion" - " decillion" " undecillion" " duodecillion" " tredecillion" - " quattuordecillion" " quindecillion" " sexdecillion" " septendecillion" - " octodecillion" " novemdecillion" " vigintillion")) + "fifteen" "sixteen" "seventeen" "eighteen" "nineteen") + #'equalp) -(defconstant +ordinal-ones+ - #(nil "first" "second" "third" "fourth" - "fifth" "sixth" "seventh" "eighth" "ninth")) - -(defconstant +ordinal-tens+ - #(nil "tenth" "twentieth" "thirtieth" "fortieth" - "fiftieth" "sixtieth" "seventieth" "eightieth" "ninetieth")) - -(defun format-print-small-cardinal (stream n) +(defun format-print-small-cardinal + (stream n &aux (.cardinal-ones. + #(nil "one" "two" "three" "four" "five" "six" "seven" "eight" "nine"))) (multiple-value-bind (hundreds rem) (truncate n 100) (when (plusp hundreds) - (write-string (svref +cardinal-ones+ hundreds) stream) + (write-string (svref .cardinal-ones. hundreds) stream) (write-string " hundred" stream) (when (plusp rem) (write-char #\space stream))) @@ -427,11 +422,11 @@ (write-string (svref +cardinal-tens+ tens) stream) (when (plusp ones) (write-char #\- stream) - (write-string (svref +cardinal-ones+ ones) stream))) + (write-string (svref .cardinal-ones. ones) stream))) ((= tens 1) (write-string (svref +cardinal-teens+ ones) stream)) ((plusp ones) - (write-string (svref +cardinal-ones+ ones) stream))))))) + (write-string (svref .cardinal-ones. ones) stream))))))) (defun format-print-cardinal (stream n) (cond ((minusp n) @@ -442,7 +437,14 @@ (t (format-print-cardinal-aux stream n 0 n)))) -(defun format-print-cardinal-aux (stream n period err) +(defun format-print-cardinal-aux + (stream n period err + &aux (.cardinal-periods. + #("" " thousand" " million" " billion" " trillion" " quadrillion" + " quintillion" " sextillion" " septillion" " octillion" " nonillion" + " decillion" " undecillion" " duodecillion" " tredecillion" + " quattuordecillion" " quindecillion" " sexdecillion" " septendecillion" + " octodecillion" " novemdecillion" " vigintillion"))) (multiple-value-bind (beyond here) (truncate n 1000) (unless (<= period 21) (error "Number too large to print in English: ~:D" err)) @@ -452,9 +454,15 @@ (unless (zerop beyond) (write-char #\space stream)) (format-print-small-cardinal stream here) - (write-string (svref +cardinal-periods+ period) stream)))) - -(defun format-print-ordinal (stream n) + (write-string (svref .cardinal-periods. period) stream)))) + +(defun format-print-ordinal + (stream n &aux (.ordinal-ones. + #(nil "first" "second" "third" "fourth" + "fifth" "sixth" "seventh" "eighth" "ninth")) + (.ordinal-tens. + #(nil "tenth" "twentieth" "thirtieth" "fortieth" + "fiftieth" "sixtieth" "seventieth" "eightieth" "ninetieth"))) (when (minusp n) (write-string "negative " stream)) (let ((number (abs n))) @@ -469,13 +477,13 @@ (write-string (svref +cardinal-teens+ ones) stream);;;RAD (write-string "th" stream)) ((and (zerop tens) (plusp ones)) - (write-string (svref +ordinal-ones+ ones) stream)) + (write-string (svref .ordinal-ones. ones) stream)) ((and (zerop ones)(plusp tens)) - (write-string (svref +ordinal-tens+ tens) stream)) + (write-string (svref .ordinal-tens. tens) stream)) ((plusp bot) (write-string (svref +cardinal-tens+ tens) stream) (write-char #\- stream) - (write-string (svref +ordinal-ones+ ones) stream)) + (write-string (svref .ordinal-ones. ones) stream)) ((plusp number) (write-string "th" stream)) (t @@ -685,15 +693,17 @@ (fmin (if (minusp k) 1 fdig))) (multiple-value-bind (fstr flen lpoint tpoint) (sb-impl::flonum-to-string num spaceleft fdig k fmin) - (when (and d (zerop d)) (setq tpoint nil)) + (when (eql fdig 0) (setq tpoint nil)) (when w (decf spaceleft flen) (when lpoint (if (or (> spaceleft 0) tpoint) (decf spaceleft) (setq lpoint nil))) - (when (and tpoint (<= spaceleft 0)) - (setq tpoint nil))) + (when tpoint + (if (<= spaceleft 0) + (setq tpoint nil) + (decf spaceleft)))) (cond ((and w (< spaceleft 0) ovf) ;;significand overflow (dotimes (i w) (write-char ovf stream))) @@ -704,6 +714,7 @@ (if atsign (write-char #\+ stream))) (when lpoint (write-char #\0 stream)) (write-string fstr stream) + (when tpoint (write-char #\0 stream)) (write-char (if marker marker (format-exponent-marker number)) @@ -1142,7 +1153,7 @@ (len (or (sb-impl::line-length stream) 72))) (directive-params first-semi) (setf newline-string - (with-simple-output-to-string (stream) + (%with-output-to-string (stream) (setf args (interpret-directive-list stream (pop segments) @@ -1151,7 +1162,7 @@ (setf extra-space extra) (setf line-len len))) (dolist (segment segments) - (push (with-simple-output-to-string (stream) + (push (%with-output-to-string (stream) (setf args (interpret-directive-list stream segment orig-args args))) @@ -1229,6 +1240,8 @@ (t (args param))))) (apply symbol stream (next-arg) colonp atsignp (args))))) +(!defun-from-collected-cold-init-forms !format-directives-init) + (push '("SB-FORMAT" def-format-directive def-complex-format-directive def-format-interpreter def-complex-format-interpreter diff --git a/src/code/target-hash-table.lisp b/src/code/target-hash-table.lisp index 5677c1b99b..6c21f1742c 100644 --- a/src/code/target-hash-table.lisp +++ b/src/code/target-hash-table.lisp @@ -24,11 +24,6 @@ ;;;; swapped out for a new instance with new vectors. Remove array bounds ;;;; checking since all the arrays will be tied together. -(defconstant hash-table-weak-flag 8) -(defconstant hash-table-finalizer-flag 4) -(defconstant hash-table-userfun-flag 2) -(defconstant hash-table-synchronized-flag 1) - ;;; T if and only if table has non-null weakness kind. (declaim (inline hash-table-weak-p)) (defun hash-table-weak-p (ht) @@ -55,73 +50,14 @@ "Return the WEAKNESS of HASH-TABLE which is one of NIL, :KEY, :VALUE, :KEY-AND-VALUE, :KEY-OR-VALUE." (and (hash-table-weak-p ht) - (decode-hash-table-weakness (ash (hash-table-flags ht) -4)))) - -;;; Code for detecting concurrent accesses to the same table from -;;; multiple threads. Only compiled in when the :SB-HASH-TABLE-DEBUG -;;; feature is enabled. The main reason for the existence of this code -;;; is to detect thread-unsafe uses of hash-tables in sbcl itself, -;;; where debugging anythign can be impossible after an important -;;; internal hash-table has been corrupted. It's plausible that this -;;; could be useful for some user code too, but the runtime cost is -;;; really too high to enable it by default. -;;; TODO: This macro needs to be repaired or removed. -(defmacro with-concurrent-access-check (hash-table operation &body body) - (declare (ignorable hash-table operation) - (type (member :read :write) operation)) - #-sb-hash-table-debug - `(progn ,@body) - #+sb-hash-table-debug - (let ((thread-slot-accessor (if (eq operation :read) - 'hash-table-reading-thread - 'hash-table-writing-thread))) - (once-only ((hash-table hash-table)) - `(progn - (flet ((body-fun () - ,@body) - (error-fun () - ;; Don't signal more errors for this table. - (setf (hash-table-signal-concurrent-access ,hash-table) nil) - (cerror "Ignore the concurrent access" - "Concurrent access to ~A" ,hash-table))) - (declare (inline body-fun)) - (if (hash-table-signal-concurrent-access ,hash-table) - (unwind-protect - (progn - (unless (and (null (hash-table-writing-thread - ,hash-table)) - ,@(when (eq operation :write) - `((null (hash-table-reading-thread - ,hash-table))))) - (error-fun)) - (setf (,thread-slot-accessor ,hash-table) - sb-thread::*current-thread*) - (body-fun)) - (unless (and ,@(when (eq operation :read) - `((null (hash-table-writing-thread - ,hash-table)))) - ,@(when (eq operation :write) - ;; no readers are allowed while writing - `((null (hash-table-reading-thread - ,hash-table)) - (eq (hash-table-writing-thread - ,hash-table) - sb-thread::*current-thread*)))) - (error-fun)) - (when (eq (,thread-slot-accessor ,hash-table) - sb-thread::*current-thread*) - ;; this is not 100% correct here and may hide - ;; concurrent access in rare circumstances. - (setf (,thread-slot-accessor ,hash-table) nil))) - (body-fun))))))) - -(declaim (inline sb-vm:is-lisp-pointer)) -(defun sb-vm:is-lisp-pointer (addr) ; Same as is_lisp_pointer() in C - #-64-bit (oddp addr) - #+ppc64 (= (logand addr #b101) #b100) - #+(and 64-bit (not ppc64)) (not (logtest (logxor addr 3) 3))) - -#-sb-fluid (declaim (inline eq-hash)) + (decode-hash-table-weakness (ht-flags-weakness (hash-table-flags ht))))) + +;;; Hash table hash functions can return any FIXNUM, because POINTER-HASH can. +;;; This is less restrictive than SXHASH which says it has to be positive. +(declaim (ftype (sfunction (t) (values fixnum boolean)) + eq-hash eql-hash equal-hash equalp-hash)) + +(declaim (inline eq-hash)) (defun eq-hash (key) (declare (values fixnum (member t nil))) ;; I think it would be ok to pick off SYMBOL here and use its hash slot @@ -129,33 +65,123 @@ ;; the lightest-weight in terms of speed, so I'm letting everything use ;; address-based hashing, unlike the other standard hash-table hash functions ;; which try use the hash slot of certain objects. + ;; Note also that as we add logic into the EQ-HASH function to decide whether + ;; the hash is address-based, we either have to replicate that logic into + ;; rehashing, or else actually call EQ-HASH to decide for us. (values (pointer-hash key) (sb-vm:is-lisp-pointer (get-lisp-obj-address key)))) -#-sb-fluid (declaim (inline eql-hash)) -(defun eql-hash (key) - (declare (values fixnum (member t nil))) - (if (%other-pointer-subtype-p - key - ;; SYMBOL is listed here so that we can hash symbols address-insensitively. - ;; Given that we're already picking off a bunch of OTHER-POINTER objects - ;; and already calling SXHASH, the overhead is minimal. In fact, with suitably - ;; and rearranged widetags, this would be included in the numeric range. - '#.(list sb-vm:bignum-widetag sb-vm:ratio-widetag sb-vm:double-float-widetag - sb-vm:single-float-widetag - sb-vm:complex-widetag sb-vm:complex-single-float-widetag sb-vm:complex-double-float-widetag - sb-vm:symbol-widetag)) - (values (if (= (%other-pointer-widetag key) sb-vm:symbol-widetag) - (sxhash (truly-the symbol key)) - (number-sxhash key)) - nil) - ;; I don't want to add a case for INSTANCE-WITH-HASH-P here, - ;; but in the EQUAL and EQUAL hash functions, we do that. - (eq-hash key))) - -#-sb-fluid (declaim (inline equal-hash)) +;;; Note: We could somewhat easily add SAP-WIDETAG into the list of types +;;; that get a stable hash for EQL tables (via SAP-HASH), however: +;;; - we don't compare SAPs with SAP= when the table's test is EQL, +;;; so there is no real advantage (nor requirement) to have a hash +;;; derived from the object's contents. +;;; - I don't imagine that users often store SAPs in hash-tables. +(declaim (inline eql-hash eql-hash-no-memoize)) +(macrolet + ((define-eql-hash (name symbol-hash-fun) + `(defun ,name (key) + (declare (values fixnum (member t nil))) + (if (%other-pointer-subtype-p + key + ;; SYMBOL is listed here so that we can hash symbols address-insensitively. + ;; We have to pick off a bunch of OTHER-POINTER objects anyway, so there + ;; no overhead to extending the widetag range by 1 widetag. + '#.(list sb-vm:bignum-widetag sb-vm:ratio-widetag sb-vm:double-float-widetag + sb-vm:single-float-widetag + sb-vm:complex-widetag sb-vm:complex-single-float-widetag + sb-vm:complex-double-float-widetag + sb-vm:symbol-widetag)) + ;; NON-NULL-SYMBOL-P skips a test for NIL which is sensible, and we're + ;; excluding NIL anyway because it's not an OTHER-POINTER. + ;; To produce the best code for NON-NULL-SYMBOL-P (omitting a lowtag test) + ;; we need to force the compiler to see that KEY is definitely an + ;; OTHER-POINTER (cf OTHER-POINTER-TN-REF-P) because %OTHER-POINTER-SUBTYPE-P + ;; doesn't suffice, though it would be nice if it did. + (values (if (non-null-symbol-p + (truly-the (or (and number (not fixnum) #+64-bit (not single-float)) + (and symbol (not null))) + key)) + (,symbol-hash-fun (truly-the symbol key)) + (number-sxhash (truly-the number key))) + nil) + ;; Consider picking off %INSTANCEP too before using EQ-HASH ? + (eq-hash key))))) + (define-eql-hash eql-hash sxhash) ; via transform + ;; For GETHASH we should never compute a symbol-hash. If it hasn't been + ;; computed, KEY won't be found, and it doesn't matter what the hash is. + ;; This could theoretically avoid clearing the fixnum tag since the symbol + ;; is not n. + (define-eql-hash eql-hash-no-memoize symbol-hash)) + +;;; Decide if WIDETAG (an OTHER-POINTER) should use SXHASH in EQUAL-HASH +(defmacro equal-hash-sxhash-widetag-p (widetag) + (let ((list `(,sb-vm:simple-base-string-widetag + #+sb-unicode ,sb-vm:simple-character-string-widetag + ,sb-vm:complex-base-string-widetag + #+sb-unicode ,sb-vm:complex-character-string-widetag + ,sb-vm:bignum-widetag + ,sb-vm:ratio-widetag + ,sb-vm:double-float-widetag + ,sb-vm:complex-widetag + ,sb-vm:complex-single-float-widetag + ,sb-vm:complex-double-float-widetag + ,sb-vm:simple-bit-vector-widetag + ,sb-vm:complex-bit-vector-widetag))) + (let ((mask 0)) + (dolist (i list mask) + (setf mask (logior mask (ash 1 (ash i -2))))) + #+64-bit `(logbitp (ash ,widetag -2) ,mask) + #-64-bit `(let ((bit (ash ,widetag -2))) + (if (<= bit 31) + (logbitp bit ,(ldb (byte 32 0) mask)) + (logbitp (- bit 32) ,(ash mask -32))))))) + +;;; this macro has not been tested on 32-bit +;;; (quite obviously the OTHER-IMMEDIATE case is wrong) and +;;; probably doesn't work on ppc64 due the alternate lowtag assignments. +(defmacro lowtag-case (x &rest clauses) + `(case (lowtag-of ,x) + ,@(mapcar (lambda (clause) + `(,(case (car clause) + (instance sb-vm:instance-pointer-lowtag) + (list sb-vm:list-pointer-lowtag) + (function sb-vm:fun-pointer-lowtag) + (other-immediate '(1 5 9 13)) + (fixnum sb-vm::fixnum-lowtags) + (other-pointer sb-vm:other-pointer-lowtag)) + ,@(cdr clause))) + clauses))) + +;;; As a consequence of change 3bdd4d28ed, the compiler started to emit multiple +;;; definitions of certain INLINE global functions. +;;; Genesis is so fraught with other pitfalls and traps that I want no chance +;;; of seeing duplicate definitions. So no INLINE here. Tail wagging the dog? +;;; Perhaps, but that was an dangerous thing to sneakily allow. +;; (declaim (inline equal-hash)) (defun equal-hash (key) (declare (values fixnum (member t nil))) + ;; Ultimately we just need to choose between SXHASH or EQ-HASH. As to using + ;; INSTANCE-SXHASH, it doesn't matter, and in fact it's quicker to use EQ-HASH. + ;; If the outermost object passed as a key is LIST, then it descends using SXASH, + ;; you will in fact get stable hashes for nested objects. + ;; Same for symbols- hash-tables don't care whether we use SYMBOL-HASH. + ;; It's mainly for users who call SXHASH directly that stable hashes are important. + ;; I have not benchmarked this for other than x86-64. + #+x86-64 + (if (lowtag-case key + ;; pathnames require SXHASH, all other instances are indifferent. + (instance (pathnamep (truly-the instance key))) + (list t) + (other-pointer (equal-hash-sxhash-widetag-p (%other-pointer-widetag key))) + (function nil) + (fixnum nil) + ;; EQUAL on numbers is the same as EQL on numbers, so single-float + ;; does *not* need to be picked off here. + (other-immediate nil)) + (values (sxhash key) nil) + (eq-hash key)) + #-x86-64 (typecase key ;; For some types the definition of EQUAL implies a special hash ((or string cons number bit-vector pathname) @@ -165,7 +191,6 @@ ;; And wow, typecase isn't enough to get use to use the transform ;; for (sxhash symbol) without an explicit THE form. (symbol (values (sxhash (the symbol key)) nil)) ; transformed - (instance (values (instance-sxhash key) nil)) ;; Otherwise use an EQ hash, rather than SXHASH, since the values ;; of SXHASH will be extremely badly distributed due to the ;; requirements of the spec fitting badly with our implementation @@ -173,20 +198,6 @@ (t (eq-hash key)))) -;;; Basically the same as EQUAL hash, but do not use the stable hash on instances -;;; so that we do not cause all structures (in the worst case) to grow a new slot. -;;; This is not for user consumption. I thought it might be needed for internals, -;;; but EQUAL hashing of structures turned out to stem from a compiler bug in our dumping -;;; of structure constants: we should never look in the similar constants table, -;;; because either there is an EQ one or there isn't. -;;; But maybe there are other use-cases where it is beneficial to store structures -;;; in an EQUAL table without causing them to be extended by one slot. -(defun equal-hash/unstable (key) - (declare (values fixnum (member t nil))) - (if (typep key '(or string cons number bit-vector pathname symbol)) - (values (sxhash key) nil) - (eq-hash key))) - (defun equalp-hash (key) (declare (values fixnum (member t nil))) (typecase key @@ -225,6 +236,8 @@ ;;;; user-defined hash table tests +(define-load-time-global *user-hash-table-tests* nil) + (defun register-hash-table-test (name hash-fun) (declare (symbol name) (function hash-fun)) (unless (fboundp name) @@ -315,10 +328,11 @@ Examples: ;;; So we allocate 14 k/v pairs = 28 cells + 3 overhead = 31 cells, ;;; and at maximum load the table will have a load factor of 87.5% (eval-when (:compile-toplevel :load-toplevel :execute) - (defconstant +min-hash-table-size+ 14) - (defconstant kv-pairs-overhead-slots 3) - (defconstant default-rehash-size $1.5)) -(defconstant +min-hash-table-rehash-threshold+ (float 1/16 $1.0)) + (defconstant kv-pairs-overhead-slots 3)) +(defconstant bad-next-value #xfefefefe) +;;; This constant is referenced via its name in cold load, so it needs to +;;; be evaluable in the host. +(defconstant +min-hash-table-rehash-threshold+ #.(sb-xc:float 1/16 $1.0)) ;; The GC will set this to 1 if it moves an address-sensitive key. This used ;; to be signaled by a bit in the header of the kv vector, but that @@ -334,36 +348,76 @@ Examples: ;; ;; We could do it with a single bit by implementing vops for atomic ;; read/modify/write on the header. In C there's sync_or_and_fetch, etc. -(defmacro kv-vector-needs-rehash (vector) `(svref ,vector 1)) +(defconstant rehash-stamp-elt 1) +(defmacro kv-vector-rehash-stamp (vector) `(truly-the fixnum (svref ,vector 1))) +(defconstant kv-vector-rehashing 2) -;;; The 'table' points to the hash-table if the table is weak, +;;; The 'supplement' points to the hash-table if the table is weak, ;;; or to the hash vector if the table is not weak. -(defmacro kv-vector-table (pairs) `(svref ,pairs (1- (length ,pairs)))) +;;; Other possible values are NIL for an EQ table, or T for an EQL table. +(defmacro kv-vector-supplement (pairs) `(svref ,pairs (1- (length ,pairs)))) (declaim (inline set-kv-hwm)) ; can't setf data-vector-ref (defun set-kv-hwm (vector hwm) (setf (svref vector 0) hwm)) (defsetf kv-vector-high-water-mark set-kv-hwm) -(defmacro new-kv-vector (size weakp) - `(let ((v (make-array (+ (* 2 ,size) kv-pairs-overhead-slots) - :initial-element +empty-ht-slot+))) +;;; Make a new key/value vector. Weak tables do not mark the vector as weak +;;; initially, because the vector can't hold a backpointer to the table +;;; since the table hasn't been made yet. (GC asserts that every weak hash-table +;;; storage vector has a table pointer - no exceptions) +;;; Also we can't set the HASHING bit in the header until the vector is prepared, +;;; but if GC occurs meanwhile, it must not move this to a purely boxed page. +;;; But we can set the ALLOC-MIXED bit. That's what it's there for. +(defmacro %alloc-kv-pairs (size) + `(let* ((nwords + (truly-the index (+ (* 2 (truly-the index/2 ,size)) + ,kv-pairs-overhead-slots))) + (v (truly-the simple-vector + (allocate-vector (logior sb-vm::+vector-alloc-mixed-region-bit+ + sb-vm:simple-vector-widetag) + nwords nwords)))) + (declare (optimize (sb-c:insert-array-bounds-checks 0))) + (fill v (make-unbound-marker)) (setf (kv-vector-high-water-mark v) 0) - (setf (kv-vector-needs-rehash v) 0) - (set-header-data v (if ,weakp - (logior sb-vm:vector-weak-subtype - sb-vm:vector-hashing-subtype) - sb-vm:vector-hashing-subtype)) - + (setf (kv-vector-rehash-stamp v) 0) + ;; If GC observes VECTOR-HASHING-FLAG, it needs to see a valid value + ;; in the 'supplement' slot. Neither 0 nor +empty-ht-slot+ is valid. + ;; And if we ever get non-prezeroed-memory to work, this will be even more + ;; important to do things in the right order. + (setf (kv-vector-supplement v) nil) + (logior-array-flags v sb-vm:vector-hashing-flag) v)) -(defun make-hash-table (&key - (test 'eql) - (size #.+min-hash-table-size+) - (rehash-size #.default-rehash-size) - (rehash-threshold 1) - (hash-function nil hash-function-suppliedp) - (weakness nil) - (synchronized)) +(defun install-hash-table-lock (table) + (declare (inline sb-thread:make-mutex)) + (let* ((lock (sb-thread:make-mutex :name "hash-table lock")) + (oldval (cas (hash-table-%lock (truly-the hash-table table)) nil lock))) + (if (eq oldval nil) lock oldval))) + +(defconstant hash-table-kind-eq 0) +(defconstant hash-table-kind-eql 1) +(defconstant hash-table-kind-equal 2) +(defconstant hash-table-kind-equalp 3) + +;;; I don't want to change peoples' assumptions about what operations are threadsafe +;;; on a weak table that was not created as expressly synchronized, so we continue to +;;; create nearly all weak tables as synchronized. With such tables, lock acquisition +;;; might be recursive, because we also told users that they can use +;;; SB-EXT:WITH-LOCKED-HASH-TABLE even with tables that are self-locking. +;;; This results in a really strange design in which it is exceptionally difficult +;;; to plug in standard POSIX mutexes which do not default to being recursive. +;;; To slightly mitigate the problem of assuming all mutexes should be recursive, +;;; some of the system weak hash-table are frobbed to turn off SYNCHRONIZED. +;;; Maybe I can figure out how to make concurrent weak GETHASH threadsafe, +;;; but I've spent a bit of time on it and it is quite difficult. + +(defun make-hash-table (&key (test 'eql) + (size #.+min-hash-table-size+) + (rehash-size #.default-rehash-size) + (rehash-threshold 1) + (hash-function nil user-hashfun-p) + (weakness nil) + (synchronized)) "Create and return a new hash table. The keywords are as follows: :TEST @@ -387,12 +441,14 @@ Examples: approaches 0. Density 1 means an average of one entry per bucket. :HASH-FUNCTION - If NIL (the default), a hash function based on the TEST argument is used, + If unsupplied, a hash function based on the TEST argument is used, which then must be one of the standardized hash table test functions, or one for which a default hash function has been defined using SB-EXT:DEFINE-HASH-TABLE-TEST. If HASH-FUNCTION is specified, the TEST argument can be any two argument predicate consistent with it. The HASH-FUNCTION is expected to return a non-negative fixnum hash code. + If TEST is neither standard nor defined by DEFINE-HASH-TABLE-TEST, + then the HASH-FUNCTION must be specified. :WEAKNESS When :WEAKNESS is not NIL, garbage collection may remove entries from the @@ -420,48 +476,38 @@ Examples: but results are undefined if a thread writes to the hash-table concurrently with another reader or writer. If T, all concurrent accesses are safe, but note that CLHS 3.6 (Traversal Rules and Side Effects) - remains in force. See also: SB-EXT:WITH-LOCKED-HASH-TABLE. This keyword - argument is experimental, and may change incompatibly or be removed in the - future." + remains in force. See also: SB-EXT:WITH-LOCKED-HASH-TABLE." (declare (type (or function symbol) test)) (declare (type unsigned-byte size)) - (multiple-value-bind (userfunp test test-fun hash-fun) - (cond ((or (eq test #'eq) (eq test 'eq)) (values nil 'eq #'eq #'eq-hash)) - ((or (eq test #'eql) (eq test 'eql)) (values nil 'eql #'eql #'eql-hash)) + (multiple-value-bind (kind test test-fun hash-fun) + (cond ((or (eq test #'eq) (eq test 'eq)) + (values 0 'eq #'eq #'eq-hash)) + ((or (eq test #'eql) (eq test 'eql)) + (values 1 'eql #'eql #'eql-hash)) ((or (eq test #'equal) (eq test 'equal)) - (cond ((or (eq hash-function #'equal-hash/unstable) - (eq hash-function 'equal-hash/unstable)) - ;; USERFUNP must remain NIL to permit address-based hashing. - ;; Don't want to assign HASH-FUNCTION itself - ;; because that prevents use of the argument's type assertion. - (setq hash-function-suppliedp nil) - (values nil 'equal #'equal #'equal-hash/unstable)) - (t - (values nil 'equal #'equal #'equal-hash)))) + (values 2 'equal #'equal #'equal-hash)) ((or (eq test #'equalp) (eq test 'equalp)) - (values nil 'equalp #'equalp #'equalp-hash)) + (values 3 'equalp #'equalp #'equalp-hash)) (t - ;; FIXME: It would be nice to have a compiler-macro - ;; that resolved this at compile time: we could grab - ;; the alist cell in a LOAD-TIME-VALUE, etc. (dolist (info *user-hash-table-tests* - (if hash-function - (if (functionp test) - (values t (%fun-name test) test nil) - (values t test (%coerce-callable-to-fun test) nil)) - (error "Unknown :TEST for MAKE-HASH-TABLE: ~S" - test))) + (flet ((proper-name (fun &aux (name (%fun-name fun))) + (if (and (symbolp name) (fboundp name) (eq (symbol-function name) fun)) + name + fun))) + (if hash-function + (if (functionp test) + (values -1 (proper-name test) test nil) + (values -1 test (%coerce-callable-to-fun test) nil)) + (error "Unknown :TEST for MAKE-HASH-TABLE: ~S" test)))) (destructuring-bind (test-name test-fun hash-fun) info (when (or (eq test test-name) (eq test test-fun)) - (return (values t test-name test-fun hash-fun))))))) - (when (and hash-function-suppliedp hash-function) + (return (values -1 test-name test-fun hash-fun))))))) + (when user-hashfun-p + ;; It is permitted to specify a custom hash function with any of the standard predicates. + ;; This forces use of the generalized table methods. (setf hash-fun (%coerce-callable-to-fun hash-function) - ;; It is permitted to specify your own hash function with one of the - ;; builtin predicates. This forces use of the general predicate. - userfunp t)) - - (binding* - ((size (max +min-hash-table-size+ + kind -1)) + (let* ((size (max +min-hash-table-size+ ;; Our table sizes are capped by the 32-bit integers used as indices ;; into the chains. Prevent our code from failing if the user specified ;; most-positive-fixnum here. (fndb says that size is 'unsigned-byte') @@ -472,8 +518,40 @@ Examples: ;; FIXME: Original REHASH-THRESHOLD default should be 1.0, ;; not 1, to make it easier for the compiler to avoid ;; boxing. - (rehash-threshold (max +min-hash-table-rehash-threshold+ - (float rehash-threshold $1.0))) ; always single-float + (rehash-threshold (max #.+min-hash-table-rehash-threshold+ + (float rehash-threshold $1.0)))) ; always single-float + (%make-hash-table + ;; compute flags. The stored KIND bits don't matter for a user-supplied hash + ;; and/or test fun, however we don't want to imply that it is an EQ table + ;; because EQ tables don't get a hash-vector allocated. + (logior (if weakness + (or (loop for i below 4 + when (eq (decode-hash-table-weakness i) weakness) + do (return (pack-ht-flags-weakness i))) + (bug "Unreachable")) + 0) + (pack-ht-flags-kind (logand kind 3)) ; kind -1 becomes 3 + (if (or weakness synchronized) hash-table-synchronized-flag 0) + (if (eql kind -1) hash-table-userfun-flag 0)) + test test-fun hash-fun + size rehash-size rehash-threshold)))) + +(defmacro make-index-vector (n) + `(let ((a (make-array ,n :element-type 'hash-table-index + :initial-element 0))) + a)) + +(defun validate-index-vector (tbl reason) + (let* ((iv (hash-table-index-vector tbl)) + (pairs (hash-table-pairs tbl)) + (npairs (length pairs))) + (dovector (indexval iv) + (when (> (* 2 indexval) npairs) + (bug "~a: Busted index vector on ~S, pairlen=~d 2*index=~d" + reason tbl npairs (* 2 indexval)))))) + +(defun %make-hash-table (flags test test-fun hash-fun size rehash-size rehash-threshold) + (binding* ( ;; KLUDGE: The most natural way of expressing the below is ;; (round (/ (float size) rehash-threshold)), and indeed ;; it was expressed like that until 0.7.0. However, @@ -488,55 +566,85 @@ Examples: (scaled-size (truncate (/ (float size) rehash-threshold))) (bucket-count (power-of-two-ceiling (max scaled-size +min-hash-table-size+))) - (index-vector (make-array bucket-count - :element-type 'hash-table-index - :initial-element 0)) - (kv-vector (new-kv-vector size weakness)) + (weakp (logtest flags hash-table-weak-flag)) + ;; Non-weak tables created with no options other than :TEST + ;; are allocated at 0 size. Weak tables are complicated enough, + ;; so just do their usual thing. + (defaultp (and (not weakp) (= size +min-hash-table-size+))) + (index-vector + (if defaultp + #.(sb-xc:make-array 2 :element-type '(unsigned-byte 32) + :initial-element 0) + (make-index-vector bucket-count))) + (kv-vector (if defaultp #(0 0 nil) (%alloc-kv-pairs size))) ;; Needs to be the half the length of the KV vector to link ;; KV entries - mapped to indices at 2i and 2i+1 - ;; together. ;; We don't need this to be initially 0-filled, so don't specify ;; an initial element (in case we ever meaningfully distinguish ;; between don't-care and 0-fill) - (next-vector (make-array (1+ size) :element-type 'hash-table-index)) + (next-vector (if defaultp + #.(sb-xc:make-array 0 :element-type '(unsigned-byte 32)) + (make-array (1+ size) :element-type 'hash-table-index + ;; For testing, preload huge values for all 'next' elements + ;; so that we generate an error if any is inadvertently read + ;; above the high-water-mark for the k/v vector. + #+sb-devel :initial-element #+sb-devel bad-next-value))) + (table-kind (ht-flags-kind flags)) + (userfunp (logtest flags hash-table-userfun-flag)) ;; same here - don't care about initial contents - ;; A simple space optimization is possible for EQL tables: most keys - ;; (notably excepting numbers) are address-based, and the interface functions - ;; don't look at hashes, so there should be no hash-vector stored. - ;; Rehashing would need to recompute hashes of numbers which is easy enough. - ;; For GC to know whether to set the 'rehash' flag after moving a key, - ;; it would need to know which pointer objects aren't hashed by address. - ;; Conversely, we use a hash-vector for an EQ table if it has - ;; a user-supplied hash function. - (hash-vector (when (or hash-function (neq test 'eq)) - (make-array (1+ size) :element-type 'hash-table-index))) - (weakness-bits - (if weakness - (or (loop for i below 4 - when (eq (decode-hash-table-weakness i) weakness) - do (return (logior (ash i 4) hash-table-weak-flag))) - (bug "Unreachable")) - 0)) + (hash-vector (when (or userfunp (>= table-kind 2)) + (if defaultp + #.(sb-xc:make-array 1 :element-type '(unsigned-byte 32)) + (make-array (1+ size) :element-type 'hash-table-index)))) ((getter setter remover) - (if weakness + (if weakp (values #'gethash/weak #'puthash/weak #'remhash/weak) - (pick-table-methods synchronized userfunp test))) - (table (%make-hash-table - getter setter remover #'clrhash-impl - test test-fun hash-fun - rehash-size rehash-threshold - kv-vector index-vector next-vector hash-vector - (logior (if userfunp hash-table-userfun-flag 0) - ;; FIXME: shouldn't weak tables always return - ;; T from HASH-TABLE-SYNCHRONIZED-P ? - (if synchronized hash-table-synchronized-flag 0) - weakness-bits)))) + (pick-table-methods (logtest flags hash-table-synchronized-flag) + (if userfunp -1 table-kind)))) + (table + (funcall (if weakp #'%alloc-general-hash-table #'%alloc-hash-table) + flags getter setter remover #'clrhash-impl + test test-fun hash-fun + rehash-size rehash-threshold + kv-vector index-vector next-vector hash-vector))) (declare (type index scaled-size)) ;; The trailing metadata element is either the table itself or the hash-vector ;; depending on weakness. Non-weak hashing vectors can be GCed without looking ;; at the table. Weak hashing vectors need the table. - (setf (kv-vector-table kv-vector) (if weakness table hash-vector)) - table))) + ;; As a special-case, non-weak tables with EQL hashing put T in this slot. + ;; GC can't get the table kind since it doesn't have access to the table. + (cond (defaultp + ;; Stash the desired size for the first time the vectors are grown. + (setf (hash-table-cache table) size + ;; Cause the overflow logic to be invoked on the first insert. + (hash-table-next-free-kv table) 0)) + (t + (setf (kv-vector-supplement kv-vector) + (if weakp + table + (or hash-vector (= table-kind hash-table-kind-eql)))) + (when weakp + (logior-array-flags kv-vector (logior sb-vm:vector-hashing-flag + sb-vm:vector-weak-flag))))) + (when (logtest flags hash-table-synchronized-flag) + (install-hash-table-lock table)) + table)) + +;;; a "plain" hash-table has nothing fancy: default size, default growth rate, +;;; not weak, not synchronized, not a user-defined hash fun and/or comparator. +(defun make-hash-table-using-defaults (kind) + (declare ((integer 0 3) kind)) + (let ((test (aref #(eq eql equal equalp) kind))) + (declare (optimize (safety 0))) ; skip FBOUNDP checks + (let ((test-fun (symbol-function test)) + (hash-fun (symbol-function + (aref #(eq-hash eql-hash equal-hash equalp-hash) kind)))) + (%make-hash-table (pack-ht-flags-kind kind) + test test-fun hash-fun + +min-hash-table-size+ + #.default-rehash-size + $1.0)))) ; rehash threshold ;;; I guess we might have more than one representation of a table, ;;; hence this small wrapper function. But why not for the others? @@ -562,7 +670,8 @@ Examples: "Return a size that can be used with MAKE-HASH-TABLE to create a hash table that can hold however many entries HASH-TABLE can hold without having to be grown." - (hash-table-pairs-capacity (hash-table-pairs hash-table))) + (let ((n (hash-table-pairs-capacity (hash-table-pairs hash-table)))) + (if (= n 0) +min-hash-table-size+ n))) (setf (documentation 'hash-table-test 'function) "Return the test HASH-TABLE was created with.") @@ -626,29 +735,16 @@ multiple threads accessing the same hash-table without locking." pow2ceil)) ;; These vector lengths are exactly analogous to those in MAKE-HASH-TABLE, ;; prompting the question of whether we can share some code. - (new-index-vector (make-array new-n-buckets - :element-type 'hash-table-index - :initial-element 0)) - ;; New kv vector is not marked as weak, even for a weak table - (new-kv-vector (new-kv-vector new-size nil)) - (new-next-vector (make-array (1+ new-size) :element-type 'hash-table-index)) + (new-index-vector (make-index-vector new-n-buckets)) + (new-kv-vector (%alloc-kv-pairs new-size)) + (new-next-vector (make-array (1+ new-size) :element-type 'hash-table-index + ;; for robustness testing, as explained in %MAKE-HASH-TABLE + #+sb-devel :initial-element #+sb-devel bad-next-value)) (new-hash-vector (when old-hash-vector (make-array (1+ new-size) :element-type 'hash-table-index)))) (values new-kv-vector new-next-vector new-hash-vector new-index-vector))) -#-(vop-translates sb-kernel:set-header-bits) -(progn - (declaim (inline set-header-bits unset-header-bits)) - (defun set-header-bits (vector bits) - (set-header-data vector (logior (get-header-data vector) bits)) - (values)) - (defun unset-header-bits (vector bits) - (set-header-data vector (logand (get-header-data vector) - (ldb (byte (- sb-vm:n-word-bits sb-vm:n-widetag-bits) 0) - (lognot bits)))) - (values))) - ;;; We don't define +-MODFX for all backends, and I can't figure out ;;; the rationale, nor how to detect this other than by trial and error. ;;; Like why does 64-bit ARM have it but 32-bit not have? @@ -660,6 +756,25 @@ multiple threads accessing the same hash-table without locking." (get-lisp-obj-address (the fixnum y))) most-positive-word)))) +;;; Clear rehash bit and bump the rolling count, wrapping around to keep it a fixnum. +;;; need-to-rehash is indicated by a stamp of #b______01 ; "initial stamp" +;;; which is changed during rehash to #b______10 ; "rehashing stamp" +;;; rolling count --------^^^^^^ (some number of bits) +(defmacro done-rehashing (kv-vector initial-stamp) + `(let ((rehashing-stamp (1+ ,initial-stamp)) + ;; new stamp has the "count" field bumped up by 1, and the low 2 bits are 0. + (new-stamp (sb-vm::+-modfx ,initial-stamp 3))) + ;; Assigning new stamp races with GC which might set the 'rehash' (low) bit again. + ;; At most one more attempt is needed since no other state change can occur - + ;; we don't need to keep trying to achieve a state in which 'rehash' is clear. + (let ((old (cas (svref ,kv-vector rehash-stamp-elt) rehashing-stamp new-stamp))) + (unless (eq old rehashing-stamp) + ;; While rehashing, GC could have set the 0 bit indicating + ;; that the hashes are obsolete yet again. + (aver (eq old (logior rehashing-stamp 1))) + ;; So bump the count field, but leave the least-significant bit on. + (aver (eq old (cas (svref ,kv-vector rehash-stamp-elt) old (logior new-stamp 1)))))))) + (macrolet ((with-pair ((key-var &optional val-var) &body body) `(let* ((key-index (* 2 i)) @@ -679,16 +794,17 @@ multiple threads accessing the same hash-table without locking." (type (simple-array hash-table-index (*)) next-vector index-vector) (type (or null (simple-array hash-table-index (*))) hash-vector)) (declare (ignorable table)) - (if hash-vector + (cond + (hash-vector ;; Scan backwards so that chains are in ascending index order. (do ((i hwm (1- i))) ((zerop i)) (declare (type index/2 i)) - (with-pair (pair-key pair-val) + (with-pair (key val) ;; It's unclear why we check for key AND value being empty - a half ;; empty cell could only appear mid-insertion, but concurrent ;; insert is forbidden, so how could it happen? ;; i.e. I would think KEY emptiness is an adequate test. - (cond ((and (empty-ht-slot-p pair-key) (empty-ht-slot-p pair-val)) + (cond ((and (empty-ht-slot-p key) (empty-ht-slot-p val)) ;; Slot is empty, push it onto free list. (setf (aref next-vector i) next-free next-free i)) ((/= (aref hash-vector i) +magic-hash-vector-value+) @@ -698,18 +814,49 @@ multiple threads accessing the same hash-table without locking." ;; Set address-sensitivity BEFORE depending on the bits. ;; Precise GC platforms can move any key except the ones which ;; are explicitly pinned. - (set-header-bits kv-vector sb-vm:vector-addr-hashing-subtype) - (push-in-chain (pointer-hash->bucket - (pointer-hash pair-key) mask)))))) + (logior-array-flags kv-vector sb-vm:vector-addr-hashing-flag) + (push-in-chain (pointer-hash->bucket (pointer-hash key) mask))))))) + ((= (ht-flags-kind (hash-table-flags table)) hash-table-kind-eql) + ;; There's a very tricky issue here with using EQL-HASH - you can't just + ;; call it and then decide to set the address-sensitivity bit if the secondary + ;; result is T. Normally we call the hash function with the key pinned, + ;; so we have to do the same here. Consider if we didn't, on a precise GC + ;; architecture given the initial condition that the kv-vector is not + ;; marked as address-sensitive: + ;; - call EQL hash, take PAIR-KEY's address as its hash + ;; - GC observes that vector is not address-sensitive, + ;; moves PAIR-KEY, gives it a new address, does not flag vector + ;; as needing rehash. + ;; - set the vector header as address-sensitive + ;; - push in chain + ;; After that sequence of operations, the item is in the wrong chain, + ;; for its new address, but the need-rehash bit is not set in the vector. + ;; It would work to call EQL-HASH twice per key: once to get the secondary + ;; value, maybe set the vector bit, call it again. But that's not great. + ;; Instead we use a macro that is like WITH-PINNED-OBJECTS, but cheaper + ;; than binding a special variable once per key. + (sb-vm::with-pinned-object-iterator (pin-object) (do ((i hwm (1- i))) ((zerop i)) (declare (type index/2 i)) - (with-pair (pair-key pair-val) - (cond ((and (empty-ht-slot-p pair-key) (empty-ht-slot-p pair-val)) + (with-pair (key val) + (cond ((and (empty-ht-slot-p key) (empty-ht-slot-p val)) (setf (aref next-vector i) next-free next-free i)) (t - (set-header-bits kv-vector sb-vm:vector-addr-hashing-subtype) - (push-in-chain (pointer-hash->bucket - (pointer-hash pair-key) mask))))))) + (pin-object key) + (multiple-value-bind (hash address-based) (eql-hash-no-memoize key) + (when address-based + (logior-array-flags kv-vector sb-vm:vector-addr-hashing-flag)) + (push-in-chain (mask-hash (prefuzz-hash hash) mask))))))))) + (t + (do ((i hwm (1- i))) ((zerop i)) + (declare (type index/2 i)) + (with-pair (key val) + (cond ((and (empty-ht-slot-p key) (empty-ht-slot-p val)) + (setf (aref next-vector i) next-free next-free i)) + (t + (when (sb-vm:is-lisp-pointer (get-lisp-obj-address key)) + (logior-array-flags kv-vector sb-vm:vector-addr-hashing-flag)) + (push-in-chain (pointer-hash->bucket (pointer-hash key) mask)))))))) ;; This is identical to the calculation of next-free-kv in INSERT-AT. (cond ((/= next-free 0) next-free) ((= hwm (hash-table-pairs-capacity kv-vector)) 0) @@ -727,7 +874,7 @@ multiple threads accessing the same hash-table without locking." (hash-vector (hash-table-hash-vector table)) (rehashing-state (1+ epoch))) (declare (hash-table table) (fixnum epoch)) - (atomic-incf (hash-table-n-rehash+find table)) + #+hash-table-metrics (atomic-incf (hash-table-n-rehash+find table)) ;; Verify some invariants prior to disabling array bounds checking (aver (>= (length kv-vector) #.(+ (* 2 +min-hash-table-size+) kv-pairs-overhead-slots))) @@ -735,16 +882,17 @@ multiple threads accessing the same hash-table without locking." (when hash-vector (aver (= (length hash-vector) (length next-vector)))) ;; Empty cells must be in the free chain already, and no smashed cells exist. - (aver (null (hash-table-smashed-cells table))) + (when (typep table 'general-hash-table) + (aver (null (hash-table-smashed-cells table)))) ;; Must not permit the rehashing state to stick due to a nonlocal exit. ;; All further normal use of the table would be prevented. (without-interrupts ;; Transitioning from #b01 to #b10 clears the 'rehash' bit and sets the ;; rehash-in-progress bit. It also gives this thread exclusive write access ;; to the hashing vectors, since at most one thread can win this CAS. - (when (eq (cas (svref kv-vector 1) epoch rehashing-state) epoch) + (when (eq (cas (svref kv-vector rehash-stamp-elt) epoch rehashing-state) epoch) ;; Remove address-sensitivity, preserving the other flags. - (unset-header-bits kv-vector sb-vm:vector-addr-hashing-subtype) + (reset-array-flags kv-vector sb-vm:vector-addr-hashing-flag) ;; Rehash in place. For the duration of the rehash, readers who otherwise ;; might have seen intact chains (by which to find address-insensitive keys) ;; can't. No big deal. If we were willing to cons new vectors, we could @@ -754,8 +902,9 @@ multiple threads accessing the same hash-table without locking." (mask (1- (length index-vector))) (hwm (kv-vector-high-water-mark kv-vector)) (result 0)) - (declare (optimize (sb-c::insert-array-bounds-checks 0))) - (if hash-vector + (declare (optimize (sb-c:insert-array-bounds-checks 0))) + (cond + (hash-vector (do ((i hwm (1- i))) ((zerop i)) (declare (type index/2 i)) (with-pair (pair-key) @@ -765,27 +914,34 @@ multiple threads accessing the same hash-table without locking." (cond ((/= (aref hash-vector i) +magic-hash-vector-value+) (push-in-chain (mask-hash (aref hash-vector i) mask))) (t - (set-header-bits kv-vector sb-vm:vector-addr-hashing-subtype) + (logior-array-flags kv-vector sb-vm:vector-addr-hashing-flag) (push-in-chain (pointer-hash->bucket (pointer-hash pair-key) mask)))) - (when (eq pair-key key) (setq result key-index))))) - ;; No hash vector + (when (eq pair-key key) (setq result key-index)))))) + ((= (ht-flags-kind (hash-table-flags table)) hash-table-kind-eql) + (sb-vm::with-pinned-object-iterator (pin-object) + (do ((i hwm (1- i))) ((zerop i)) + (declare (type index/2 i)) + (with-pair (pair-key) + (unless (empty-ht-slot-p pair-key) + (pin-object pair-key) + (multiple-value-bind (hash address-based) (eql-hash-no-memoize pair-key) + (when address-based + (logior-array-flags kv-vector sb-vm:vector-addr-hashing-flag)) + (push-in-chain (mask-hash (prefuzz-hash hash) mask))) + (when (eq pair-key key) (setq result key-index))))))) + (t + ;; No hash vector and not an EQL table, so it's an EQ table (do ((i hwm (1- i))) ((zerop i)) (declare (type index/2 i)) (with-pair (pair-key) (unless (empty-ht-slot-p pair-key) - (set-header-bits kv-vector sb-vm:vector-addr-hashing-subtype) + (when (sb-vm:is-lisp-pointer (get-lisp-obj-address pair-key)) + (logior-array-flags kv-vector sb-vm:vector-addr-hashing-flag)) (push-in-chain (pointer-hash->bucket (pointer-hash pair-key) mask)) - (when (eq pair-key key) (setq result key-index)))))) - ;; Clear rehash bit and bump the epoch, wrapping around to keep it a fixnum - (let ((new-epoch (sb-vm::+-modfx epoch 3))) - ;; Setting the new epoch races with GC which might set 'rehash' again. - ;; At most 2 attempts are needed since no other state change can occur. - (let ((old (cas (svref kv-vector 1) rehashing-state new-epoch))) - (unless (eq rehashing-state old) - (aver (eq old (logior rehashing-state 1))) ; rehashed, but already obsolete - (aver (eq old (cas (svref kv-vector 1) old (logior new-epoch 1))))))) + (when (eq pair-key key) (setq result key-index))))))) + (done-rehashing kv-vector epoch) (unless (eql result 0) (setf (hash-table-cache table) result)) result)))) @@ -795,14 +951,30 @@ multiple threads accessing the same hash-table without locking." ;;; made non-weak so that we don't have to deal with GC-related shenanigans. (defun grow-hash-table (table) (declare (type hash-table table)) + (when (= (hash-table-%count table) 0) ; special case for new table + (let* ((size (shiftf (hash-table-cache table) 0)) + (scaled-size (truncate (/ (float size) (hash-table-rehash-threshold table)))) + (bucket-count (power-of-two-ceiling (max scaled-size +min-hash-table-size+))) + (index-vector (make-index-vector bucket-count)) + (kv-vector (%alloc-kv-pairs size)) + (next-vector (make-array (1+ size) :element-type 'hash-table-index + #+sb-devel :initial-element #+sb-devel bad-next-value)) + (hash-vector (when (hash-table-hash-vector table) + (make-array (1+ size) :element-type 'hash-table-index)))) + (setf (kv-vector-supplement kv-vector) (or hash-vector + (eq (hash-table-test table) 'eql)) + (hash-table-pairs table) kv-vector + (hash-table-index-vector table) index-vector + (hash-table-next-vector table) next-vector + (hash-table-hash-vector table) hash-vector) + (return-from grow-hash-table 1))) (binding* (((new-kv-vector new-next-vector new-hash-vector new-index-vector) (hash-table-new-vectors table)) (old-kv-vector (hash-table-pairs table)) (hwm (kv-vector-high-water-mark old-kv-vector))) (declare (type simple-vector new-kv-vector) - (type (simple-array hash-table-index (*)) new-next-vector new-index-vector) - (type (or null (simple-array hash-table-index (*))) new-hash-vector)) + (type (simple-array hash-table-index (*)) new-next-vector new-index-vector)) ;; Rehash + resize only occurs when: ;; (1) every usable pair was at some point filled (so HWM = SIZE) @@ -817,7 +989,8 @@ multiple threads accessing the same hash-table without locking." ;; This is done early because when GC scans the new vector, it needs to see ;; each hash to know which keys were hashed address-sensitively. (awhen (hash-table-hash-vector table) - (replace new-hash-vector it :start1 1 :start2 1)) ; 1st element not used + (replace (the (simple-array hash-table-index (*)) new-hash-vector) + it :start1 1 :start2 1)) ; 1st element not used ;; Preserve only the 'hashing' bit on the OLD-KV-VECTOR so that ;; its high-water-mark can meaningfully be reduced to 0 when done. @@ -826,8 +999,8 @@ multiple threads accessing the same hash-table without locking." ;; for rehash (it's going to be zeroed out). ;; Clearing the weakness causes all entries to stay alive. ;; Furthermore, clearing both makes the trailing metadata ignorable. - (set-header-data old-kv-vector sb-vm:vector-hashing-subtype) - (setf (kv-vector-table old-kv-vector) 0) + (assign-vector-flags old-kv-vector sb-vm:vector-hashing-flag) + (setf (kv-vector-supplement old-kv-vector) nil) ;; The high-water-mark remains unchanged. ;; Set this before copying pairs, otherwise they would not be seen @@ -842,7 +1015,9 @@ multiple threads accessing the same hash-table without locking." ;; but I'd rather the table remain in a consistent state, in case we ;; ever devise a way to allow concurrent reads with a single writer, ;; for example. - (setf (kv-vector-table new-kv-vector) new-hash-vector) + (setf (kv-vector-supplement new-kv-vector) + (or new-hash-vector + (= (ht-flags-kind (hash-table-flags table)) hash-table-kind-eql))) ;; Copy the k/v pairs excluding leading and trailing metadata. (replace new-kv-vector old-kv-vector @@ -860,8 +1035,8 @@ multiple threads accessing the same hash-table without locking." (setf (hash-table-smashed-cells table) nil) ;; Now that the table points to the right hash-vector ;; we can set the vector's backpointer and turn it weak. - (setf (kv-vector-table new-kv-vector) table) - (set-header-bits new-kv-vector sb-vm:vector-weak-subtype)) + (setf (kv-vector-supplement new-kv-vector) table) + (logior-array-flags new-kv-vector sb-vm:vector-weak-flag)) ;; Zero-fill the old kv-vector. For weak hash-tables this removes the ;; strong references to each k/v. For non-weak vectors there is no technical @@ -912,16 +1087,26 @@ if there is no such entry. Entries can be added using SETF." ;; to keep things simple so that we don't have to pass in the names ;; of local variables to bind. (Being unhygienic on purpose) - (defun ht-hash-setup (std-fn) + (defun ht-hash-setup (std-fn caller) (if std-fn `(((hash0 address-based-p) ;; so many warnings about generic SXHASH - who cares (locally (declare (muffle-conditions compiler-note)) - ,(if (eq std-fn 'equal) - `(if (eq (hash-table-hash-fun table) #'equal-hash) - (equal-hash key) ; inlined - (funcall (hash-table-hash-fun table) key)) - `(,(symbolicate std-fn "-HASH") key)))) + ,(case std-fn + (eql + ;; GETHASH in an EQL table doesn't need to compute and writeback + ;; a hash into a symbol that didn't already have a hash. + ;; So the hash computation is a touch shorter by avoiding that. + `(,(if (eq caller 'gethash) 'eql-hash-no-memoize 'eql-hash) key)) + (equal + ;; EQUAL tables can opt out of using the stable instance hash + ;; to avoid increasing the length of all structures. + ;; There is no exposed interface to this; it's for system use. + `(if (eq (hash-table-hash-fun table) #'equal-hash) + (equal-hash key) ; inlined + (funcall (hash-table-hash-fun table) key))) + (t + `(,(symbolicate std-fn "-HASH") key))))) (hash (prefuzz-hash hash0))) '((hash0 (funcall (hash-table-hash-fun hash-table) key)) (address-based-p nil) @@ -1071,11 +1256,9 @@ if there is no such entry. Entries can be added using SETF." (defmacro ht-probe-advance (var) `(setq ,var (truly-the index/2 (aref next-vector ,var)))) -(defmacro kv-vector-rehash-epoch (vector) `(truly-the fixnum (svref ,vector 1))) -(defconstant kv-vector-rehashing 2) #| -bottom 2 bits of kv-vector-rehash-epoch: +bottom 2 bits of kv-vector-rehash-stamp: 00 = valid hashes 01 = an address-sensitive key moved @@ -1119,7 +1302,7 @@ nnnn 1_ any linear scan (/= cache 0)) ; don't falsely match the metadata cell (return-from ,name (values (aref kv-vector (1+ cache)) t)))) (with-pinned-objects (key) - (binding* (,@(ht-hash-setup std-fn) + (binding* (,@(ht-hash-setup std-fn 'gethash) (eq-test ,(ht-probing-should-use-eq std-fn))) (declare (fixnum hash0)) (flet ((hash-search (&aux ,@(ht-probe-setup std-fn)) @@ -1151,8 +1334,8 @@ nnnn 1_ any linear scan ,(if (eq std-fn 'eql) '(loop (probe) (probe) (check-excessive-probes 2)) '(loop (probe) (check-excessive-probes 1)))))))) - (named-let retry ((initial-epoch (kv-vector-rehash-epoch kv-vector))) - (if (logtest initial-epoch kv-vector-rehashing) + (named-let retry ((initial-stamp (kv-vector-rehash-stamp kv-vector))) + (if (logtest initial-stamp kv-vector-rehashing) (truly-the (values t boolean &optional) (hash-table-lsearch hash-table eq-test key hash default)) (let ((index (hash-search))) @@ -1160,28 +1343,28 @@ nnnn 1_ any linear scan (let ((key-index (* 2 (truly-the index/2 index)))) (setf (hash-table-cache hash-table) key-index) (values (aref kv-vector (1+ key-index)) t)) - (let ((epoch (kv-vector-rehash-epoch kv-vector))) - (cond ((and (evenp initial-epoch) ; valid hashes at start? - (zerop (logandc2 (logxor epoch initial-epoch) 1))) - ;; Provided that the epoch didn't change, the 'rehash' + (let ((stamp (kv-vector-rehash-stamp kv-vector))) + (cond ((and (evenp initial-stamp) ; valid hashes at start? + (zerop (logandc2 (logxor stamp initial-stamp) 1))) + ;; Provided that the stamp didn't change, the 'rehash' ;; bit can be ignored since rehash did not occur. (values default nil)) - ((and (oddp initial-epoch) (= epoch initial-epoch)) - ;; Epoch didn't change, but address-based hashes were + ((and (oddp initial-stamp) (= stamp initial-stamp)) + ;; Stamp didn't change, but address-based hashes were ;; not valid at the start of the lookup. ;; Stably hashed (address-insensitive) keys are ok. (if (not address-based-p) (values default nil) - (let ((key-index (%rehash-and-find hash-table epoch key))) + (let ((key-index (%rehash-and-find hash-table stamp key))) (cond ((eql key-index 0) ; didn't find, again (values default nil)) ((not (fixnump key-index)) ;; conflicted with other thread trying to rehash - (retry (kv-vector-rehash-epoch kv-vector))) + (retry (kv-vector-rehash-stamp kv-vector))) (t (values (aref kv-vector (1+ key-index)) t)))))) - (t ; epoch changed - (retry epoch))))))))))))) + (t ; stamp changed + (retry stamp))))))))))))) ;;;; Weak table variant. @@ -1191,86 +1374,87 @@ nnnn 1_ any linear scan ;;; to change a cell from non-empty to smashed. Therefore if we could leverage a ;;; collector from some other language, it need not understand our weak ;;; hash-table representation in depth. -(macrolet ((with-pair ((&optional (physical-index '(* next 2))) &body body) - ;; Load the {k,v} of a pair. We will check that they're not smashed - ;; before using. Note an extreme subtlety: by loading VAL first, - ;; we decrease the chance of seeing a live key but smashed value. - `(let* ((physical-index (truly-the index ,physical-index)) - (probed-val (svref kv-vector (1+ physical-index))) - (probed-key (svref kv-vector physical-index))) - ,@body))) - (defun findhash-weak (key hash-table hash address-based-p) - (declare (hash-table hash-table) (optimize speed) - (type (unsigned-byte #-64-bit 29 #+64-bit 31) hash)) - (macrolet ((return-hit () - '(return-from findhash-weak - (values probed-val probed-key physical-index predecessor)))) - ;; FIXME: since a weak table is always synchronized, maybe get rid of - ;; this loop-over-epoch noise? - (let ((start-epoch sb-kernel::*gc-epoch*) - (kv-vector (hash-table-pairs hash-table))) - (tagbody - (go entry) - MISS - (let ((current-epoch sb-kernel::*gc-epoch*)) - (when (eq start-epoch current-epoch) - (return-from findhash-weak (values +empty-ht-slot+ 0 0 0))) - (setq start-epoch current-epoch)) - ENTRY - (when (oddp (truly-the fixnum - (kv-vector-needs-rehash (hash-table-pairs hash-table)))) - (without-interrupts - ;; Remove weakness and address-sensitivity. - (set-header-data kv-vector sb-vm:vector-hashing-subtype) - ;; Clear the need-to-rehash flag. Since there can be no other readers, - ;; we're not publishing bad information (i.e. allegedly valid hashes - ;; when they're in an inconsistent state). If GC sets the flag again, - ;; we'll know that the end state is already obsolete. - ;; In this regard the algorithm is simpler than that of %REHASH-AND-FIND. - (setf (kv-vector-needs-rehash kv-vector) 0) - ;; We don't need to zero-fill the NEXT vector, just the INDEX vector. - ;; Unless a key slot can be reached by a chain starting from the index - ;; vector or the 'next' of a previous chain element, we don't read either - ;; the key or its corresponding 'next'. So we only need to assign a - ;; 'next' at the moment a slot is linked into a chain. - (setf (hash-table-next-free-kv hash-table) - (rehash kv-vector (hash-table-hash-vector hash-table) - (fill (hash-table-index-vector hash-table) 0) - (hash-table-next-vector hash-table) - hash-table)) - ;; Empty cells will have been placed in the ordinary freelist, - ;; so clear the list of GC-smashed cells. - (setf (hash-table-smashed-cells hash-table) nil) - ;; Re-enable weakness - (set-header-bits kv-vector sb-vm:vector-weak-subtype))) - ;; Note that it's OK for a GC + another rehash to - ;; be triggered by another thread after this point, since the - ;; GC epoch check will catch it. - (binding* #.(ht-probe-setup '* '((predecessor nil))) + +;;; TODO: it would be ideal if GETHASH/WEAK could share code with GETHASH/ANY +;;; (the general case of hash-function + predicate). +;;; The difficulty in doing so is that %REHASH-AND-FIND has trouble understanding +;;; how to treat keys that are +empty-ht-slot+ in a weak table - we don't know if +;;; a key was smashed by GC and the cell still exists in a bucket's chain, +;;; versus the cell being in the freelist. So the code diverges in at least that way. +(defun findhash-weak (key hash-table hash address-based-p) + (declare (hash-table hash-table) (optimize speed) + (type (unsigned-byte #-64-bit 29 #+64-bit 31) hash)) + (let* ((kv-vector (hash-table-pairs hash-table)) + (initial-stamp (kv-vector-rehash-stamp kv-vector))) + (flet ((hash-search () + (binding* #.(ht-probe-setup '* '((predecessor nil))) (declare (index/2 index)) - ;; Everything in an EQ table is address-based - though this is subject - ;; to change, as we could stably hash symbols, because why not - - ;; but the hash fun's second value is NIL on immediate objects. - (if (or address-based-p (eq (hash-table-test hash-table) 'eq)) - (do ((next index (aref next-vector next))) - ((zerop next) (go miss)) - (declare (type index/2 next)) - (with-pair () (when (eq key probed-key) (return-hit))) - (check-excessive-probes 1) - (setq predecessor next)) - ;; For any other test, we assume that it is not safe to pass the - ;; unbound marker to the predicate (though EQUAL and EQUALP are - ;; probably OK). Also, compare hashes first. - (do ((next index (aref next-vector next))) - ((zerop next) (go miss)) - (declare (type index/2 next)) - (with-pair () - (when (and (not (empty-ht-slot-p probed-key)) - (= hash (aref hash-vector next)) - (funcall test-fun key probed-key)) - (return-hit))) - (check-excessive-probes 1) - (setq predecessor next))))))))) + (macrolet + ((probing-loop (comparison-expr) + `(do ((next index (aref next-vector next))) + ((zerop next) (values +empty-ht-slot+ 0 0 0)) + (declare (type index/2 next)) + (let* ((physical-index (truly-the index (* next 2))) + (probed-val (svref kv-vector (1+ physical-index))) + (probed-key (svref kv-vector physical-index))) + (when ,comparison-expr + (return (values probed-val probed-key physical-index predecessor))) + (check-excessive-probes 1) + (setq predecessor next))))) + (cond + ((or (eq (hash-table-test hash-table) 'eq) address-based-p) + ;; Everything in an EQ table is address-based - though this is subject + ;; to change, as we could stably hash symbols, because why not - + ;; but the hash fun's second value is NIL on immediate objects. + (probing-loop (eq key probed-key))) + ((eq (hash-table-test hash-table) 'eql) + ;; similar to EQ except for the different comparator + (probing-loop (%eql key probed-key))) + (t + ;; For any other test, we assume that it is not safe to pass the + ;; unbound marker to the predicate (though EQUAL and EQUALP are + ;; probably OK). Also, compare hashes first. + (probing-loop (and (not (empty-ht-slot-p probed-key)) + (= hash (aref hash-vector next)) + (funcall test-fun key probed-key))))))))) + ;; Weak tables disallow concurrent GETHASH therefore we can't + ;; be in the midst of fixing up obsolete address-based hashes. + (aver (not (logtest initial-stamp kv-vector-rehashing))) + (multiple-value-bind (probed-val probed-key physical-index predecessor) + (hash-search) + (cond + ((or (neq physical-index 0) ; found + (not address-based-p) ; key was stably hashed + (evenp initial-stamp)) ; not found, but address-based hashes were valid + (values probed-val probed-key physical-index predecessor)) + (t ; invalid hashes at start, and key's hash was address-based + (without-interrupts + ;; set the stamp to rehashing. There should be no concurrent + ;; access, but use CAS to be sure. + (aver (eql (cas (svref kv-vector rehash-stamp-elt) initial-stamp + (1+ initial-stamp)) initial-stamp)) + ;; Remove weakness and address-sensitivity. + (assign-vector-flags kv-vector sb-vm:vector-hashing-flag) + ;; We don't need to zero-fill the NEXT vector, just the INDEX vector. + ;; Unless a key slot can be reached by a chain starting from the index + ;; vector or the 'next' of a previous chain element, we don't read either + ;; the key or its corresponding 'next'. So we only need to assign a + ;; 'next' at the moment a slot is linked into a chain. + (setf (hash-table-next-free-kv hash-table) + (rehash kv-vector (hash-table-hash-vector hash-table) + (fill (hash-table-index-vector hash-table) 0) + (hash-table-next-vector hash-table) + hash-table)) + ;; Empty cells will have been placed in the ordinary freelist, + ;; so clear the list of GC-smashed cells. + (setf (hash-table-smashed-cells hash-table) nil) + ;; Re-enable weakness + (logior-array-flags kv-vector sb-vm:vector-weak-flag) + (done-rehashing kv-vector initial-stamp)) + ;; One more try gives the definitive answer even if the hashes are + ;; obsolete again. KEY's hash can't have changed, and there + ;; are no concurrent readers to potentially mess up the chains. + (hash-search))))))) (defmacro with-weak-hash-table-entry (&body body) `(with-pinned-objects (key) @@ -1280,18 +1464,22 @@ nnnn 1_ any linear scan (unless (logtest (hash-table-flags hash-table) hash-table-userfun-flag) address-sensitive-p)) (hash (prefuzz-hash (the fixnum hash0)))) + (dx-flet ((body () + (binding* (((probed-value probed-key physical-index predecessor) + (findhash-weak key hash-table hash address-sensitive-p)) + (kv-vector (hash-table-pairs hash-table))) + (declare (index physical-index)) + ,@body))) ;; It would be ideal if we were consistent about all tables NOT having - ;; synchronization unless created with ":SYNCHRONIZED T". - ;; But removing the implicit synchronization from weak tables looks tricky - ;; and doesn't seem worth spending much time on. - (sb-thread::with-recursive-system-lock ((hash-table-lock hash-table)) - ;; Receive the existing k,v pair to ensure liveness thereof because - ;; otherwise we have no "certificate of existence" of the pair. - (binding* (((probed-value probed-key physical-index predecessor) - (findhash-weak key hash-table hash address-sensitive-p)) - (kv-vector (hash-table-pairs hash-table))) - (declare (index physical-index)) - ,@body))))) + ;; synchronization unless created with ":SYNCHRONIZED T" + ;; but it looks tricky to support concurrent gethash on weak tables, + ;; so we mostly default to locking, except where there is an outer scope + ;; providing mutual exclusion such as WITH-FINALIZER-STORE. + (if (hash-table-synchronized-p hash-table) + ;; Use the private slot accessor for the lock because it's known + ;; to have a mutex. + (sb-thread::call-with-recursive-system-lock #'body (hash-table-%lock hash-table)) + (body)))))) (defun gethash/weak (key hash-table default) (declare (type hash-table hash-table) (optimize speed)) @@ -1322,9 +1510,9 @@ nnnn 1_ any linear scan ;;; key and hash-table-test whenever some thread is rehashing. If hash-based ;;; lookup uses EQ as the comparator for KEY, then linear search does too. (defun hash-table-lsearch (hash-table eq-test key hash default) - (declare (optimize (sb-c::insert-array-bounds-checks 0))) + (declare (optimize (sb-c:insert-array-bounds-checks 0))) (declare (type (and fixnum unsigned-byte) hash)) - (atomic-incf (hash-table-n-lsearch hash-table)) + #+hash-table-metrics (atomic-incf (hash-table-n-lsearch hash-table)) (let* ((kv-vector (hash-table-pairs hash-table)) (key-index (let ((hash-vector (hash-table-hash-vector hash-table)) @@ -1352,48 +1540,49 @@ nnnn 1_ any linear scan (t (values default nil))))) -(defun pick-table-methods (synchronized userp test) - (macrolet ((gen-cases (wrapping) - `(case test - (eq (,wrapping gethash/eq puthash/eq remhash/eq)) - (eql (,wrapping gethash/eql puthash/eql remhash/eql)) - (equal (,wrapping gethash/equal puthash/equal remhash/equal)) - (t (,wrapping gethash/equalp puthash/equalp remhash/equalp)))) - (locked-methods (getter setter remover) +(defun pick-table-methods (synchronized kind) + (declare ((integer -1 3) kind)) + ;; test is specified as 0..3 for a standard fun or -1 for userfun + (macrolet ((gen-cases (wrapping) + `(case kind + (-1 (,wrapping gethash/any puthash/any remhash/any)) + (0 (,wrapping gethash/eq puthash/eq remhash/eq)) + (1 (,wrapping gethash/eql puthash/eql remhash/eql)) + (2 (,wrapping gethash/equal puthash/equal remhash/equal)) + (3 (,wrapping gethash/equalp puthash/equalp remhash/equalp)))) + (locked-methods (getter setter remover) + ;; We might want to think about inlining the guts of CALL-WITH-...LOCK + ;; into these methods + ;; Use the private slot accessor, because we know that the mutex + ;; has been constructed. `(values (named-lambda ,(symbolicate getter "/LOCK") (key table default) (declare (optimize speed (sb-c:verify-arg-count 0))) (truly-the (values t t &optional) (sb-thread::with-recursive-system-lock - ((hash-table-lock (truly-the hash-table table))) + ((hash-table-%lock (truly-the hash-table table))) (,getter key table default)))) (named-lambda ,(symbolicate setter "/LOCK") (key table value) (declare (optimize speed (sb-c:verify-arg-count 0))) (truly-the (values t &optional) (sb-thread::with-recursive-system-lock - ((hash-table-lock (truly-the hash-table table))) + ((hash-table-%lock (truly-the hash-table table))) (,setter key table value)))) (named-lambda ,(symbolicate remover "/LOCK") (key table) (declare (optimize speed (sb-c:verify-arg-count 0))) (truly-the (values t &optional) (sb-thread::with-recursive-system-lock - ((hash-table-lock (truly-the hash-table table))) + ((hash-table-%lock (truly-the hash-table table))) (,remover key table)))))) - (methods (getter setter remover) + (methods (getter setter remover) `(values #',getter #',setter #',remover))) - (if userp - (if synchronized - (locked-methods gethash/any puthash/any remhash/any) - (methods gethash/any puthash/any remhash/any)) - (if synchronized - (gen-cases locked-methods) - (gen-cases methods))))) + (if synchronized + (gen-cases locked-methods) + (gen-cases methods)))) ;;; Three argument version of GETHASH (defun gethash3 (key hash-table default) (declare (type hash-table hash-table)) - (funcall (truly-the (sfunction (t t t) (values t boolean)) - (hash-table-gethash-impl hash-table)) - key hash-table default)) + (funcall (hash-table-gethash-impl hash-table) key hash-table default)) ;;; so people can call #'(SETF GETHASH) ;;; FIXME: this function is not mandated. Why do we have it? @@ -1433,12 +1622,12 @@ nnnn 1_ any linear scan (setf (aref next-vector kv-index) (hash-table-next-free-kv hash-table)) kv-index))) -;;; We don't need the looping and checking for GC epoch in PUTHASH +;;; We don't need the looping and checking for GC activiy in PUTHASH ;;; because insertion can not co-occur with any other operation, ;;; unlike GETHASH which we allow to execute in multiple threads. (defmacro define-ht-setter (name std-fn) - `(named-lambda ,name (key table value &aux (hash-table (truly-the hash-table table)) - (kv-vector (hash-table-pairs hash-table))) + `(defun ,name (key table value &aux (hash-table (truly-the hash-table table)) + (kv-vector (hash-table-pairs hash-table))) (declare (optimize speed (sb-c:verify-arg-count 0))) (block done (let ((cache (hash-table-cache hash-table))) @@ -1466,8 +1655,8 @@ nnnn 1_ any linear scan ;; until t3, we're forced to conclude that KEY's hash might have been wrong. ;; Granted that the bit might have been 1 at timestamp 't1', ;; but it's best to read it at t1 and not later. - (binding* ((initial-epoch (kv-vector-rehash-epoch kv-vector)) - ,@(ht-hash-setup std-fn) + (binding* ((initial-stamp (kv-vector-rehash-stamp kv-vector)) + ,@(ht-hash-setup std-fn 'puthash) ,@(ht-probe-setup std-fn) (eq-test ,(ht-probing-should-use-eq std-fn))) (declare (fixnum hash0) (index/2 index)) @@ -1495,14 +1684,14 @@ nnnn 1_ any linear scan ;; Only the initial state of the 'rehash' bit is important. ;; If the bit changed from 0 to 1, then KEY's hash was good because ;; it was pinned at the time we observed the rehash status to be 0. - (when (and address-based-p (oddp initial-epoch)) - ;; The current epoch must be the same as initial-epoch, because + (when (and address-based-p (oddp initial-stamp)) + ;; The current stamp must be the same as initial-stamp, because ;; PUTHASH is disallowed concurrently with any other operation, ;; and the 'rehash' bit can't be cleared except by rehashing ;; as part of such operation. - (unless (eq (kv-vector-rehash-epoch kv-vector) initial-epoch) + (unless (eq (kv-vector-rehash-stamp kv-vector) initial-stamp) (signal-corrupt-hash-table hash-table)) - (let ((key-index (%rehash-and-find hash-table initial-epoch key))) + (let ((key-index (%rehash-and-find hash-table initial-stamp key))) ;; If we see NIL here, it means that some other operation is racing ;; to rehash. GETHASH can deal with that scenario, PUTHASH can't. (cond ((eql key-index 0)) ; fallthrough to insert @@ -1512,78 +1701,77 @@ nnnn 1_ any linear scan (insert-at (hash-table-next-free-kv hash-table) hash-table key hash address-based-p value)))))) -(defun get-puthash-definitions () - (flet ((insert-at (index hash-table key hash address-based-p value) - (declare (optimize speed) (type index/2 index)) - (when (zerop index) - (setq index (grow-hash-table hash-table)) - ;; Growing the table can not make the key become found when it was not - ;; found before, so we can just proceed with insertion. - (aver (not (zerop index)))) - ;; Grab the vectors AFTER possibly growing the table - (let ((kv-vector (hash-table-pairs hash-table)) - (next-vector (hash-table-next-vector hash-table))) - (setf (hash-table-next-free-kv hash-table) - (let ((hwm (kv-vector-high-water-mark kv-vector)) - (cap (hash-table-pairs-capacity kv-vector))) - (cond ((> index hwm) ; raise the high-water-mark - (setf (kv-vector-high-water-mark kv-vector) index) - ;; CPU must not buffer storing the new HWM versus the - ;; stores of the K+V since they wouldn't be seen. - (sb-thread:barrier (:write)) - (cond ((= index cap) 0) - (t (1+ index)))) - (t ; don't raise - (let ((next (aref next-vector index))) - (cond ((/= next 0) next) - ((= hwm cap) 0) - (t (1+ hwm)))))))) - - ;; We've potentially depended on the bits of the address of KEY - ;; before informing GC that we've done so, but the key is pinned, - ;; so as long as the table informs GC that it has the dependency - ;; by the time the key is free to move, all is well. - (when address-based-p - (set-header-bits kv-vector sb-vm:vector-addr-hashing-subtype)) - - ;; Store the hash unless an EQ table. Because the key is pinned, it is - ;; OK that GC would not have seen +magic-hash-vector-value+ for this - ;; key if applicable. - (awhen (hash-table-hash-vector hash-table) - (setf (aref it index) - (if address-based-p +magic-hash-vector-value+ hash))) - - ;; Store the pair - (let ((i (* 2 index))) - (setf (aref kv-vector i) key (aref kv-vector (1+ i)) value)) - ;; Push this slot onto the front of the chain for its bucket. - (let* ((index-vector (hash-table-index-vector hash-table)) - (bucket (mask-hash hash (1- (length index-vector))))) - (setf (aref next-vector index) (aref index-vector bucket) - (aref index-vector bucket) index))) - (incf (hash-table-%count hash-table)) - value)) - - (values (named-lambda puthash/weak (key hash-table value) - (declare (type hash-table hash-table) (optimize speed)) - (with-weak-hash-table-entry - (declare (ignore predecessor)) - (cond ((= physical-index 0) - ;; There are two kinds of freelists. Prefer a smashed cell - ;; so that we might shorten the chain it belonged to. - (insert-at (or (hash-table-next-smashed-kv hash-table) - (hash-table-next-free-kv hash-table)) - hash-table key hash address-sensitive-p value)) - ((or (empty-ht-slot-p (cas (svref kv-vector (1+ physical-index)) - probed-value value)) - (neq (svref kv-vector physical-index) probed-key)) - (signal-corrupt-hash-table hash-table)) - (t value)))) - (define-ht-setter puthash/eq eq) - (define-ht-setter puthash/eql eql) - (define-ht-setter puthash/equal equal) - (define-ht-setter puthash/equalp equalp) - (define-ht-setter puthash/any nil)))) +(flet ((insert-at (index hash-table key hash address-based-p value) + (declare (optimize speed) (type index/2 index)) + (when (zerop index) + (setq index (grow-hash-table hash-table)) + ;; Growing the table can not make the key become found when it was not + ;; found before, so we can just proceed with insertion. + (aver (not (zerop index)))) + ;; Grab the vectors AFTER possibly growing the table + (let ((kv-vector (hash-table-pairs hash-table)) + (next-vector (hash-table-next-vector hash-table))) + (setf (hash-table-next-free-kv hash-table) + (let ((hwm (kv-vector-high-water-mark kv-vector)) + (cap (hash-table-pairs-capacity kv-vector))) + (cond ((> index hwm) ; raise the high-water-mark + (setf (kv-vector-high-water-mark kv-vector) index) + ;; CPU must not buffer storing the new HWM versus the + ;; stores of the K+V since they wouldn't be seen. + (sb-thread:barrier (:write)) + (cond ((= index cap) 0) + (t (1+ index)))) + (t ; don't raise + (let ((next (aref next-vector index))) + (cond ((/= next 0) next) + ((= hwm cap) 0) + (t (1+ hwm)))))))) + + ;; We've potentially depended on the bits of the address of KEY + ;; before informing GC that we've done so, but the key is pinned, + ;; so as long as the table informs GC that it has the dependency + ;; by the time the key is free to move, all is well. + (when address-based-p + (logior-array-flags kv-vector sb-vm:vector-addr-hashing-flag)) + + ;; Store the hash unless an EQ table. Because the key is pinned, it is + ;; OK that GC would not have seen +magic-hash-vector-value+ for this + ;; key if applicable. + (awhen (hash-table-hash-vector hash-table) + (setf (aref it index) + (if address-based-p +magic-hash-vector-value+ hash))) + + ;; Store the pair + (let ((i (* 2 index))) + (setf (aref kv-vector i) key (aref kv-vector (1+ i)) value)) + ;; Push this slot onto the front of the chain for its bucket. + (let* ((index-vector (hash-table-index-vector hash-table)) + (bucket (mask-hash hash (1- (length index-vector))))) + (setf (aref next-vector index) (aref index-vector bucket) + (aref index-vector bucket) index))) + (incf (hash-table-%count hash-table)) + value)) + + (defun puthash/weak (key hash-table value) + (declare (type hash-table hash-table) (optimize speed)) + (with-weak-hash-table-entry + (declare (ignore predecessor)) + (cond ((= physical-index 0) + ;; There are two kinds of freelists. Prefer a smashed cell + ;; so that we might shorten the chain it belonged to. + (insert-at (or (hash-table-next-smashed-kv hash-table) + (hash-table-next-free-kv hash-table)) + hash-table key hash address-sensitive-p value)) + ((or (empty-ht-slot-p (cas (svref kv-vector (1+ physical-index)) + probed-value value)) + (neq (svref kv-vector physical-index) probed-key)) + (signal-corrupt-hash-table hash-table)) + (t value)))) + (define-ht-setter puthash/eq eq) + (define-ht-setter puthash/eql eql) + (define-ht-setter puthash/equal equal) + (define-ht-setter puthash/equalp equalp) + (define-ht-setter puthash/any nil)) (defun %puthash (key hash-table value) (declare (type hash-table hash-table)) @@ -1596,17 +1784,17 @@ nnnn 1_ any linear scan (funcall (hash-table-puthash-impl hash-table) key hash-table value)) (defmacro define-remhash (name std-fn) - `(named-lambda ,name (key table &aux (hash-table (truly-the hash-table table)) + `(defun ,name (key table &aux (hash-table (truly-the hash-table table)) (kv-vector (hash-table-pairs hash-table))) (declare (optimize speed (sb-c:verify-arg-count 0))) ;; The cache provides no benefit to REMHASH. A hit would just mean there is work ;; to do in removing the item from a chain, whereas a miss means we don't know ;; if there is work to do, so effectively there is work to do either way. (with-pinned-objects (key) - ;; See comment in DEFINE-HT-SETTER about why to read initial-epoch + ;; See comment in DEFINE-HT-SETTER about why to read initial-stamp ;; as soon as possible after pinning KEY. - (binding* ((initial-epoch (kv-vector-rehash-epoch kv-vector)) - ,@(ht-hash-setup std-fn) + (binding* ((initial-stamp (kv-vector-rehash-stamp kv-vector)) + ,@(ht-hash-setup std-fn 'remhash) ,@(ht-probe-setup std-fn) (eq-test ,(ht-probing-should-use-eq std-fn))) (declare (fixnum hash0) (index/2 index) (ignore probe-limit)) @@ -1637,8 +1825,8 @@ nnnn 1_ any linear scan ;; Only the initial state of the 'rehash' bit is important. ;; If the bit changed from 0 to 1, then KEY's hash was good because ;; it was pinned at the time we observed the rehash status to be 0. - (when (and address-based-p (oddp initial-epoch)) - (remove-from-bucket key bucket hash-table initial-epoch))))))) + (when (and address-based-p (oddp initial-stamp)) + (remove-from-bucket key bucket hash-table initial-stamp))))))) (defun remhash/weak (key hash-table) (declare (type hash-table hash-table) (optimize speed)) @@ -1666,93 +1854,77 @@ nnnn 1_ any linear scan (decf (hash-table-%count hash-table)) t))))) -(defun get-remhash-definitions () - (labels ((clear-slot (index hash-table kv-vector next-vector) - (declare (type index/2 index)) - ;; Mark slot as empty. - (let ((physindex (* 2 index))) - (setf (aref kv-vector physindex) +empty-ht-slot+ - (aref kv-vector (1+ physindex)) +empty-ht-slot+)) - ;; Push KV slot onto free chain. - ;; Possible optimization: if we linked the free chain through - ;; the 'value' half of a pair, we could avoid rebuilding the - ;; free chain in %REHASH because rehashing won't affect it. - ;; (Maybe it already doesn't?) - (setf (aref next-vector index) (hash-table-next-free-kv hash-table) - (hash-table-next-free-kv hash-table) index) - ;; On parallel accesses this may turn out to be a - ;; type-error, so don't turn down the safety! - (decf (hash-table-%count hash-table)) - t) - (remove-from-bucket (key bucket hash-table initial-epoch - &aux (kv-vector (hash-table-pairs hash-table))) - ;; Remove KEY from BUCKET which is based on the current address - ;; of key after pinning. When the key was not found initially, - ;; the "problem" so to speak was that the bucket that was searched - ;; did not hold the key, and not that search was done on the wrong - ;; bucket. Rehashing will place the key into the expected bucket. - ;; - ;; The current epoch must be the same as initial-epoch, because - ;; REMHASH is disallowed concurrently with any other operation, - ;; and the 'rehash' bit can't be cleared except by rehashing - ;; as part of such operation. - (unless (eq (kv-vector-rehash-epoch kv-vector) initial-epoch) +(labels ((clear-slot (index hash-table kv-vector next-vector) + (declare (type index/2 index)) + ;; Mark slot as empty. + (let ((physindex (* 2 index))) + (setf (aref kv-vector physindex) +empty-ht-slot+ + (aref kv-vector (1+ physindex)) +empty-ht-slot+)) + ;; Push KV slot onto free chain. + ;; Possible optimization: if we linked the free chain through + ;; the 'value' half of a pair, we could avoid rebuilding the + ;; free chain in %REHASH because rehashing won't affect it. + ;; (Maybe it already doesn't?) + (setf (aref next-vector index) (hash-table-next-free-kv hash-table) + (hash-table-next-free-kv hash-table) index) + ;; On parallel accesses this may turn out to be a + ;; type-error, so don't turn down the safety! + (decf (hash-table-%count hash-table)) + t) + (remove-from-bucket (key bucket hash-table initial-stamp + &aux (kv-vector (hash-table-pairs hash-table))) + ;; Remove KEY from BUCKET which is based on the current address + ;; of key after pinning. When the key was not found initially, + ;; the "problem" so to speak was that the bucket that was searched + ;; did not hold the key, and not that search was done on the wrong + ;; bucket. Rehashing will place the key into the expected bucket. + ;; + ;; The current stamp must be the same as initial-stamp, because + ;; REMHASH is disallowed concurrently with any other operation, + ;; and the 'rehash' bit can't be cleared except by rehashing + ;; as part of such operation. + (unless (eq (kv-vector-rehash-stamp kv-vector) initial-stamp) + (signal-corrupt-hash-table hash-table)) + (let ((key-index (%rehash-and-find hash-table initial-stamp key))) + ;; If we see NIL here, it means that some other operation is racing + ;; to rehash. GETHASH can deal with that scenario, REMHASH can't. + (unless (fixnump key-index) (signal-corrupt-hash-table hash-table)) - (let ((key-index (%rehash-and-find hash-table initial-epoch key))) - ;; If we see NIL here, it means that some other operation is racing - ;; to rehash. GETHASH can deal with that scenario, REMHASH can't. - (unless (fixnump key-index) - (signal-corrupt-hash-table hash-table)) - (when (/= key-index 0) ; found - (let* ((index-vector (hash-table-index-vector hash-table)) - (start (aref index-vector bucket)) - (next-vector (hash-table-next-vector hash-table)) - (next (aref next-vector start)) - (pair-index (ash key-index -1))) - (if (if (= start pair-index) ; remove head of chain - (setf (aref index-vector bucket) next) - (do ((probe-limit (length next-vector)) - (predecessor start this) - (this next (aref next-vector this))) - ((zerop this)) - (declare (type index/2 predecessor this)) - (when (eql this pair-index) - (return (setf (aref next-vector predecessor) - (aref next-vector this)))) - (check-excessive-probes 1))) - (clear-slot pair-index hash-table kv-vector next-vector) - (signal-corrupt-hash-table hash-table)))))) - (%remhash/eq (key hash-table kv-vector next-vector start) - (do ((probe-limit (length next-vector)) - (predecessor start this) - (this (aref next-vector start) (aref next-vector this))) - ((zerop this) nil) - (declare (type index/2 predecessor this)) - (when (eq key (aref kv-vector (* 2 this))) - (setf (aref next-vector predecessor) (aref next-vector this)) - (return (clear-slot this hash-table kv-vector next-vector))) - (check-excessive-probes 1)))) - - (values (define-remhash remhash/eq eq) - (define-remhash remhash/eql eql) - (define-remhash remhash/equal equal) - (define-remhash remhash/equalp equalp) - (define-remhash remhash/any nil)))) - -(defun !cold-init-hash-table-methods () - (multiple-value-bind (weak eq eql equal equalp any) (get-puthash-definitions) - (setf (symbol-function 'puthash/weak) weak - (symbol-function 'puthash/eq) eq - (symbol-function 'puthash/eql) eql - (symbol-function 'puthash/equal) equal - (symbol-function 'puthash/equalp) equalp - (symbol-function 'puthash/any) any)) - (multiple-value-bind (eq eql equal equalp any) (get-remhash-definitions) - (setf (symbol-function 'remhash/eq) eq - (symbol-function 'remhash/eql) eql - (symbol-function 'remhash/equal) equal - (symbol-function 'remhash/equalp) equalp - (symbol-function 'remhash/any) any))) + (when (/= key-index 0) ; found + (let* ((index-vector (hash-table-index-vector hash-table)) + (start (aref index-vector bucket)) + (next-vector (hash-table-next-vector hash-table)) + (next (aref next-vector start)) + (pair-index (ash key-index -1))) + (if (if (= start pair-index) ; remove head of chain + (setf (aref index-vector bucket) next) + (do ((probe-limit (length next-vector)) + (predecessor start this) + (this next (aref next-vector this))) + ((zerop this)) + (declare (type index/2 predecessor this)) + (when (eql this pair-index) + (return (setf (aref next-vector predecessor) + (aref next-vector this)))) + (check-excessive-probes 1))) + (clear-slot pair-index hash-table kv-vector next-vector) + (signal-corrupt-hash-table hash-table)))))) + (%remhash/eq (key hash-table kv-vector next-vector start) + (do ((probe-limit (length next-vector)) + (predecessor start this) + (this (aref next-vector start) (aref next-vector this))) + ((zerop this) nil) + (declare (type index/2 predecessor this)) + (when (eq key (aref kv-vector (* 2 this))) + (setf (aref next-vector predecessor) (aref next-vector this)) + (return (clear-slot this hash-table kv-vector next-vector))) + (check-excessive-probes 1)))) + + (define-remhash remhash/eq eq) + (define-remhash remhash/eql eql) + (define-remhash remhash/equal equal) + (define-remhash remhash/equalp equalp) + (define-remhash remhash/any nil)) (defun remhash (key hash-table) "Remove the entry in HASH-TABLE associated with KEY. Return T if @@ -1762,15 +1934,12 @@ there was such an entry, or NIL if not." :test (hash-table-test-fun hash-table)))) (when cell (setf (hash-table-%alist hash-table) (delq1 cell (hash-table-%alist hash-table))))) - (funcall (truly-the (sfunction (t t) (values boolean &optional)) - (hash-table-remhash-impl hash-table)) - key hash-table)) + (funcall (hash-table-remhash-impl hash-table) key hash-table)) (defun clrhash (hash-table) "This removes all the entries from HASH-TABLE and returns the hash table itself." - (truly-the (values hash-table &optional) - (funcall (hash-table-clrhash-impl hash-table) hash-table))) + (funcall (hash-table-clrhash-impl hash-table) hash-table)) (defun clrhash-impl (hash-table) ;; This used to do nothing at all for tables that has a COUNT of 0, @@ -1789,43 +1958,37 @@ table itself." ;; observe junk, but you can't put good value at higher than the HWM] #+hash-table-simulate (setf (hash-table-%alist hash-table) nil) (when (plusp (kv-vector-high-water-mark (hash-table-pairs hash-table))) - (sb-thread::with-recursive-system-lock ((hash-table-lock hash-table)) - (let* ((kv-vector (hash-table-pairs hash-table)) - (high-water-mark (kv-vector-high-water-mark kv-vector))) - (when (hash-table-weak-p hash-table) - (aver (eq (kv-vector-table kv-vector) hash-table))) - ;; Remove address-sensitivity. - (unset-header-bits kv-vector sb-vm:vector-addr-hashing-subtype) - ;; Do this only after unsetting the address-sensitive bit, - ;; otherwise GC might come along and touch this bit again. - (setf (kv-vector-needs-rehash kv-vector) 0) - ;; We always deposit empty makers into k/v pairs that are REMHASHed, - ;; so a count of 0 implies no clearing need be done. - (when (plusp (hash-table-%count hash-table)) - (setf (hash-table-%count hash-table) 0) - ;; Fill all slots with the empty marker. - (fill kv-vector +empty-ht-slot+ :start 2 :end (* (1+ high-water-mark) 2)) - ;; Clear the index-vector. - ;; Don't need to clear the hash-vector or the next-vector. - (fill (hash-table-index-vector hash-table) 0)) - (setf (hash-table-smashed-cells hash-table) nil - (hash-table-next-free-kv hash-table) 1 - (kv-vector-high-water-mark kv-vector) 0)))) + (dx-flet ((clear () + (let* ((kv-vector (hash-table-pairs hash-table)) + (high-water-mark (kv-vector-high-water-mark kv-vector))) + (when (hash-table-weak-p hash-table) + (aver (eq (kv-vector-supplement kv-vector) hash-table))) + ;; Remove address-sensitivity. + (reset-array-flags kv-vector sb-vm:vector-addr-hashing-flag) + ;; Do this only after unsetting the address-sensitive bit, + ;; otherwise GC might come along and touch this bit again. + (setf (kv-vector-rehash-stamp kv-vector) 0) + ;; We always deposit empty markers into k/v pairs that are REMHASHed, + ;; so a count of 0 implies no clearing need be done. + (when (plusp (hash-table-%count hash-table)) + (setf (hash-table-%count hash-table) 0) + ;; Fill all slots with the empty marker. + (fill kv-vector +empty-ht-slot+ :start 2 :end (* (1+ high-water-mark) 2)) + ;; Clear the index-vector. + ;; Don't need to clear the hash-vector or the next-vector. + (fill (hash-table-index-vector hash-table) 0)) + (when (typep hash-table 'general-hash-table) + (setf (hash-table-smashed-cells hash-table) nil)) + (setf (hash-table-next-free-kv hash-table) 1 + (kv-vector-high-water-mark kv-vector) 0)))) + (if (hash-table-synchronized-p hash-table) + (sb-thread::call-with-recursive-system-lock #'clear (hash-table-%lock hash-table)) + (clear)))) hash-table) ;;;; methods on HASH-TABLE -;;; Return a list of keyword args and values to use for MAKE-HASH-TABLE -;;; when reconstructing HASH-TABLE. -;;; FIXME: synchronized? custom function? -(defun %hash-table-ctor-args (hash-table) - `(:test ',(hash-table-test hash-table) - :size ',(hash-table-size hash-table) - :rehash-size ',(hash-table-rehash-size hash-table) - :rehash-threshold ',(hash-table-rehash-threshold hash-table) - :weakness ',(hash-table-weakness hash-table))) - ;;; Return an association list representing the same data as HASH-TABLE. ;;; Iterate downward so that PUSH creates the result in insertion order. ;;; One the one hand, this should not to be construed as a guarantee about @@ -1843,40 +2006,105 @@ table itself." (push (cons k v) result))))) result)) -;;; Stuff an association list into HASH-TABLE. Return the hash table, -;;; so that we can use this for the *PRINT-READABLY* case in -;;; PRINT-OBJECT (HASH-TABLE T) without having to worry about LET -;;; forms and readable gensyms and stuff. -(defun %stuff-hash-table (hash-table alist) - (dolist (x alist) - (setf (gethash (car x) hash-table) (cdr x))) +;;; Stuff an association list, or a vector, into HASH-TABLE. Return the hash table, +;;; so that we can use this for the *PRINT-READABLY* case in PRINT-OBJECT (HASH-TABLE T) +;;; without having to worry about LET forms and readable gensyms and stuff. +(defun %stuff-hash-table (hash-table data &optional pure) + (if (vectorp data) + (dovector (x data) (setf (gethash (car x) hash-table) (cdr x))) + (dolist (x data) (setf (gethash (car x) hash-table) (cdr x)))) + (when pure + ;; Mark the index vector, next-vector, hash-vector (if present), + ;; and even the key vector, as shareable, provided that no key is hashed + ;; address-sensitively. As a first crack I'm just requiring keys to be + ;; fixnum or character, but some table types would stably hash more things. + (let ((stably-hashed + (loop for k being each hash-key of hash-table + always (typep k '(or fixnum character))))) + (when stably-hashed + (logically-readonlyize (hash-table-pairs hash-table)) + (logically-readonlyize (hash-table-index-vector hash-table)) + (logically-readonlyize (hash-table-next-vector hash-table)) + (awhen (hash-table-hash-vector hash-table) (logically-readonlyize it))))) hash-table) +;;; Return a list of keyword args and values to use for MAKE-HASH-TABLE +;;; when reconstructing HASH-TABLE. +(flet ((%hash-table-ctor (hash-table &aux (test (hash-table-test hash-table))) + (when (or (not (logtest (hash-table-flags hash-table) hash-table-userfun-flag)) + ;; If it has a named test function - it wasn't a lambda expression - + ;; and the table's hash-function is identical to the hash function + ;; dictated by *USER-HASH-TABLE-TESTS* for that test, we're OK. + ;; And it's not worth the risk of trying to reverse-engineer the hash + ;; function if all we have is a name. + (and test (eq (third (assoc test *user-hash-table-tests*)) + (hash-table-hash-fun hash-table)))) + `(make-hash-table + ,@(loop for (key accessor default) + in + (load-time-value + `((:test ,#'hash-table-test eql) + (:size ,#'hash-table-size ,+min-hash-table-size+) + (:rehash-size ,#'hash-table-rehash-size ,default-rehash-size) + (:rehash-threshold ,#'hash-table-rehash-threshold $1.0) + (:synchronized ,#'hash-table-synchronized-p nil) + (:weakness ,#'hash-table-weakness nil))) + for value = (funcall accessor hash-table) + unless (eql value default) + collect key + and + collect (if (self-evaluating-p value) + value + `',value)))))) + (defmethod print-object ((hash-table hash-table) stream) (declare (type stream stream)) - (cond ((or (not *print-readably*) (not *read-eval*)) - (print-unreadable-object (hash-table stream :type t :identity t) - (format stream - ":TEST ~S~@[ :HASH-FUNCTION ~S~] :COUNT ~S~@[ :WEAKNESS ~S~]" - (hash-table-test hash-table) - (when (and (eq (hash-table-test hash-table) 'eq) - (neq (hash-table-hash-fun hash-table) #'eq-hash)) - (hash-table-hash-fun hash-table)) - (hash-table-count hash-table) - (hash-table-weakness hash-table)))) - (t - (write-string "#." stream) - (write `(%stuff-hash-table (make-hash-table ,@(%hash-table-ctor-args - hash-table)) - ',(%hash-table-alist hash-table)) - :stream stream)))) + (let ((ctor (and *print-readably* *read-eval* (%hash-table-ctor hash-table)))) + (cond + ((not ctor) + ;; Perhaps we should add :SYNCHRONIZED to the string? + (print-unreadable-object (hash-table stream :type t :identity t) + (format stream + ":TEST ~S~@[ :HASH-FUNCTION ~S~] :COUNT ~S~@[ :WEAKNESS ~S~]" + (or (hash-table-test hash-table) (hash-table-test-fun hash-table)) + (when (logtest (hash-table-flags hash-table) hash-table-userfun-flag) + (hash-table-hash-fun hash-table)) + (hash-table-count hash-table) + (hash-table-weakness hash-table)))) + (t + (write-string "#." stream) + (let ((alist (%hash-table-alist hash-table))) + (write (if alist + `(%stuff-hash-table ,ctor ',alist) + ctor) + :stream stream)))))) (defmethod make-load-form ((hash-table hash-table) &optional environment) (declare (ignore environment)) - (values `(make-hash-table ,@(%hash-table-ctor-args hash-table)) - `(%stuff-hash-table ,hash-table ',(%hash-table-alist hash-table)))) + (let ((ctor (%hash-table-ctor hash-table))) + (if ctor + (values ctor + ;; This uses a separate initform in case the hash table contains itself + ;; as either a key or value. + ;; FIXME: k/v pairs would take less space as a vector, not an alist. + (unless (zerop (hash-table-count hash-table)) + `(%stuff-hash-table ,hash-table ',(%hash-table-alist hash-table)))) + (error "~S is not externalizable" hash-table)))) +) + +;;; This assignment has to occur some time after the defstruct. +;;; We don't call EQUALP on hash-table, so as late as possible is fine. +;;; It can't go in src/code/pred whose forms execute *before* the defstruct, +;;; so its effect would just get clobbered by the defstruct. +(sb-kernel::assign-equalp-impl 'hash-table #'hash-table-equalp) #| +(defun memusage (x) + (+ (sb-vm::primitive-object-size (hash-table-pairs x)) + (acond ((hash-table-hash-vector x) (sb-vm::primitive-object-size it)) (t 0)) + (sb-vm::primitive-object-size (hash-table-index-vector x)) + (sb-vm::primitive-object-size (hash-table-next-vector x)))) + (defun show-address-sensitivity (&optional tbl) (flet ((show1 (tbl) (let ((kv (hash-table-pairs tbl)) @@ -1942,10 +2170,10 @@ table itself." ht)))) (defun hash-table-mem-used (ht) - (+ (sb-vm::primitive-object-size (hash-table-pairs ht)) - (sb-vm::primitive-object-size (hash-table-index-vector ht)) - (sb-vm::primitive-object-size (hash-table-next-vector ht)) - (acond ((hash-table-hash-vector ht) (sb-vm::primitive-object-size it)) + (+ (primitive-object-size (hash-table-pairs ht)) + (primitive-object-size (hash-table-index-vector ht)) + (primitive-object-size (hash-table-next-vector ht)) + (acond ((hash-table-hash-vector ht) (primitive-object-size it)) (t 0)))) (defun show-growth (&optional (factor 1.5)) diff --git a/src/code/target-lfhash.lisp b/src/code/target-lfhash.lisp index b86cebe5ce..d575bed91a 100644 --- a/src/code/target-lfhash.lisp +++ b/src/code/target-lfhash.lisp @@ -112,7 +112,7 @@ (comparator #'equal :type function) (hash-function #'globaldb-sxhashoid :type function) (mutex (sb-thread:make-mutex)) - ;; the number of phantom entries for simulated deletion. + ;; The number of phantom entries for simulated deletion. ;; Our tombstones are not the usual ones. Ordinarily an open-addressing ;; table will use tombstone keys that can be written over if inserting a new ;; pair into a dead entry. That doesn't work for the lockfree algorithm @@ -159,7 +159,7 @@ ;; The common skeleton of {Get, Put, Rehash} operations. Probe key cells until ;; either a hit occurs, in which case the :HIT form is executed and looping -;; stops; or an empty slot is seen in which case the :MISS code is executed. +;; stops; or an empty slot is seen, in which case the :MISS code is executed. ;; :MISS should contain a GO or RETURN on success, otherwise probing continues. ;; No precaution exists against probing forever, such as could happen if the ;; probing strategy fails to visit all candidate free cells. @@ -215,7 +215,7 @@ ;; Wait for ENV's storage to change to something other than STORAGE, and ;; return the new one. As long as rehash finishes in finite time, every thread -;; makes progess. We don't protect against untimely death of the thread +;; makes progress. We don't protect against untimely death of the thread ;; that holds the lock. ;; (defun %wait-for-rehash (env storage) @@ -243,15 +243,16 @@ (!do-probe-sequence (storage key env) :miss (return-from info-gethash nil) ;; With 99% certainty the :READ barrier is needed for non-x86, and if not, - ;; it can't hurt. 'info-storage-next' can be empty until at least one cell + ;; it can't hurt. INFO-STORAGE-NEXT can be empty until at least one cell ;; has been forwarded, but in general an unsynchronized read might be ;; perceived as executing before a conditional that guards whether the - ;; read should happen at all. 'storage-next' has the deceptive look of a - ;; data dependency but it's not - it's a control dependency which as per - ;; the 'memory-barriers.txt' document at kernel.org, demands a barrier. + ;; read should happen at all. STORAGE-NEXT has the deceptive look of a + ;; data dependency but it's not - it's a control dependency which, as per + ;; [1], demands a barrier. ;; The subsequent ref to storage (if the loop iterates) has a ;; data-dependency, and will never be reordered except on an Alpha :-( - ;; so we _don't_ need a barrier after resetting 'storage' and 'index'. + ;; so we _don't_ need a barrier after resetting STORAGE and INDEX. + ;; Ad 1: https://www.kernel.org/doc/Documentation/memory-barriers.txt :hit (let ((index (value-index))) (loop (let ((value (sb-thread:barrier (:read) (svref storage index)))) @@ -292,7 +293,7 @@ ;; Unlike above, this read of storage-next can not ;; be perceived as having occurred prior to CAS. ;; x86 synchronizes at every locked instruction, and our - ;; PPC CAS vops sync as a nececessity of performing CAS. + ;; PPC CAS vops sync as a necessity of performing CAS. (cond ((eq oldval actual-old) newval) ; win ((info-value-moved-p actual-old) ; forwarded (put (info-storage-next array) @@ -407,7 +408,7 @@ ;; CAS is the primitive operation on an info hashtable, ;; and SETF is implemented in terms of CAS. For the most part it is ;; inadvisable to use this for anything other than tinkering at the REPL. -;; Of if the table has external sychronization, it's ok to use. +;; Of if the table has external synchronization, it's ok to use. (defun (setf info-gethash) (newval key env) (dx-flet ((update (old) (declare (ignore old)) newval)) (info-puthash env key #'update))) diff --git a/src/code/target-lflist.lisp b/src/code/target-lflist.lisp index cd13939c20..20c39b4965 100644 --- a/src/code/target-lflist.lisp +++ b/src/code/target-lflist.lisp @@ -15,19 +15,11 @@ ;;;; provided with absolutely no warranty. See the COPYING and CREDITS ;;;; files for more information. -(defpackage "SB-LOCKLESS" - (:use "CL" "SB-EXT" "SB-INT" "SB-SYS" "SB-KERNEL") - (:shadow "ENDP")) - (in-package "SB-LOCKLESS") -(setf (system-package-p *package*) t) ;;; The changes to GC to support this code were as follows: -;;; * One bit of the payload length in an instance header is reserved to signify -;;; that the instance has a special GC scavenge method. This avoids indirecting -;;; to the layout to see whether all instances of a type have a special method. ;;; -;;; * If an instance has a header bit so indicating, then the first data slot +;;; * If an instance is flagged as being a LFlist node, then the first data slot ;;; is treated as an instance pointer even if it missing its tag bits. ;;; ;;; * Since you can't pin an object that you don't a-priori have a tagged pointer @@ -45,15 +37,6 @@ ;;; DO-REFERENCED-OBJECT can follow untagged pointers. ;;; This is potentially more of an annoyance than it is a bug. -(eval-when (:compile-toplevel :load-toplevel :execute) - (import 'sb-kernel::list-node)) - -(defstruct (list-node - (:conc-name nil) - (:constructor %make-sentinel-node ()) - (:copier nil)) - (%node-next nil)) - (defstruct (keyed-node (:conc-name nil) (:include list-node) @@ -61,10 +44,6 @@ (node-key 0 :read-only t) (node-data)) -(let ((layout (find-layout 'keyed-node))) - (setf (layout-flags layout) - (logior (layout-flags layout) sb-vm:lockfree-list-node-flag))) - (declaim (inline ptr-markedp node-markedp)) (defun ptr-markedp (bits) (fixnump bits)) (defun node-markedp (node) (fixnump (%node-next node))) @@ -82,20 +61,6 @@ (defmacro endp (node) `(eq ,node (load-time-value *tail-atom*))) -;;; Specialized list variants will be created for -;;; fixnum, integer, real, string, generic "comparable" -;;; but the node type and list type is the same regardless of key type. -(defstruct (linked-list - (:constructor %make-lfl - (head inserter deleter finder inequality equality)) - (:conc-name list-)) - (head nil :type list-node :read-only t) - (inserter nil :type function :read-only t) - (deleter nil :type function :read-only t) - (finder nil :type function :read-only t) - (inequality nil :type function :read-only t) - (equality nil :type function :read-only t)) - (defconstant-eqx +predefined-key-types+ #((fixnum lfl-insert/fixnum lfl-delete/fixnum lfl-find/fixnum < =) (integer lfl-insert/integer lfl-delete/integer lfl-find/integer < =) @@ -134,7 +99,7 @@ ;;; MAKE-MARKED-REF can only be called in the scope of WITH-PINNED-OBJECTS. ;;; The critical invariant is that once a 'next' pointer has been turned into ;;; a fixnum, it CAN NOT change. Therefore, the object that GC implicitly pins -;;; - along with the explicit pin of NODE within MARKED+NEXT - is definitely the +;;; - along with the explicit pin of NODE within GET-NEXT - is definitely the ;;; object whose tagged pointer is reconstructed. This is exactly why we choose ;;; the tagged state as the normal state and the untagged state as deleted. ;;; If that were reversed (so tag bits = deleted, no tag bits = normal) to be like @@ -148,12 +113,14 @@ (declaim (inline get-next)) (defun get-next (node) - (with-pinned-objects (node) ; pinning a node also pins its 'next' - (let ((%next (%node-next node))) - (values (truly-the list-node - (%make-lisp-obj (logior (get-lisp-obj-address %next) - sb-vm:instance-pointer-lowtag))) - %next)))) + ;; Storing NODE in *PINNED-OBJECTS* causes its successor to become pinned. + (let* ((sb-vm::*pinned-objects* (cons node sb-vm::*pinned-objects*)) + (%next (%node-next node))) + (declare (truly-dynamic-extent sb-vm::*pinned-objects*)) + (values (truly-the list-node + (%make-lisp-obj (logior (get-lisp-obj-address %next) + sb-vm:instance-pointer-lowtag))) + %next))) (defmethod print-object ((list linked-list) stream) (print-unreadable-object (list stream :type t) @@ -283,6 +250,9 @@ (unless (fixnump succ) ;; Pin here because we're taking the address of the successor object. ;; Instead we could use bit-test-and-set on the x86 architecture. + ;; This is the ordinary WITH-PINNED-OBJECTS which manipulates + ;; *PINNED-OBJECTS* only if precise GC. Compare/contrast with + ;; GET-NEXT which _always_ binds *PINNED-OBJECTS*. (with-pinned-objects (succ) ;; Step 2: logically delete 'this' (when (eq (cas (%node-next this) succ (make-marked-ref succ)) succ) @@ -368,6 +338,10 @@ (do-lockfree-list (x list) (incf n)) n)) +;;; This function is not really part of the API. It preserve the deletion bit, +;;; which doesn't really make sense from an interface perspective. +;;; However, when devising tests of the algorithms, it is useful to capture +;;; a complete snapshot of the list. (defun copy-lfl (lfl) (labels ((copy-chain (node) (if (eq node *tail-atom*) @@ -381,6 +355,6 @@ copy-of-next))) copy)))) (let ((new (copy-structure lfl))) - (setf (%instance-ref new (get-dsd-index linked-list head)) + (%instance-set new (get-dsd-index linked-list head) (copy-chain (list-head new))) new))) diff --git a/src/code/target-load.lisp b/src/code/target-load.lisp index 90e042a6f5..35a2a2f739 100644 --- a/src/code/target-load.lisp +++ b/src/code/target-load.lisp @@ -16,10 +16,27 @@ (defvar *load-source-default-type* "lisp" "The source file types which LOAD looks for by default.") +(defvar *load-verbose* nil + ;; Note that CMU CL's default for this was T, and ANSI says it's + ;; implementation-dependent. We choose NIL on the theory that it's + ;; a nicer default behavior for Unix programs. + "the default for the :VERBOSE argument to LOAD") + +(defvar *load-print* nil + "the default for the :PRINT argument to LOAD") + +#+ansi-compliant-load-truename (defvar *load-truename* nil "the TRUENAME of the file that LOAD is currently loading") +#-ansi-compliant-load-truename +(setf (documentation '*load-truename* 'variable) + "the TRUENAME of the file that LOAD is currently loading") + (defvar *load-pathname* nil "the defaulted pathname that LOAD is currently loading") + +(declaim (type (or pathname null) *load-truename* *load-pathname*)) + ;;;; LOAD-AS-SOURCE @@ -74,8 +91,7 @@ (locally (declare (optimize (sb-c::type-check 0))) (setf sb-c::*current-path* (make-unbound-marker))) (if pathname - (let* ((info (sb-c::make-file-source-info - pathname (stream-external-format stream))) + (let* ((info (sb-c::make-file-stream-source-info stream)) (sb-c::*source-info* info)) (locally (declare (optimize (sb-c::type-check 0))) (setf sb-c::*current-path* (make-unbound-marker))) @@ -108,32 +124,34 @@ (invalid-fasl-expected condition) (invalid-fasl-fhsss condition))))) +(defun call-with-load-bindings (function stream arg pathname-designator) + (let* (;; FIXME: we should probably document the circumstances + ;; where *LOAD-PATHNAME* and *LOAD-TRUENAME* aren't + ;; pathnames during LOAD. ANSI makes no exceptions here. + (*load-pathname* (handler-case (pathname pathname-designator) + ;; FIXME: it should probably be a type + ;; error to try to get a pathname for a + ;; stream that doesn't have one, but I + ;; don't know if we guarantee that. + (error () nil))) + ;; FIXME: this ANSI-specified nonsense should have been an accessor call + ;; because eager binding might force dozens of syscalls to occur. + ;; The non-ansi-compliant code resolves *LOAD-TRUENAME* only if referenced. + #-ansi-compliant-load-truename (%load-truename (make-unbound-marker)) + #+ansi-compliant-load-truename + (*load-truename* (when *load-pathname* + (handler-case (truename stream) + (file-error () nil)))) + ;; Bindings used internally. + (*load-depth* (1+ *load-depth*))) + (funcall function stream arg))) -;;; The following comment preceded the pre 1.0.12.36 definition of -;;; LOAD; it may no longer be accurate: - -;; FIXME: Daniel Barlow's ilsb.tar ILISP-for-SBCL patches contain an -;; implementation of "DEFUN SOURCE-FILE" which claims, in a comment, -;; that CMU CL does not correctly record source file information when -;; LOADing a non-compiled file. Check whether this bug exists in SBCL -;; and fix it if so. - -(defun call-with-load-bindings (function stream) - (let* (;; FIXME: we should probably document the circumstances - ;; where *LOAD-PATHNAME* and *LOAD-TRUENAME* aren't - ;; pathnames during LOAD. ANSI makes no exceptions here. - (*load-pathname* (handler-case (pathname stream) - ;; FIXME: it should probably be a type - ;; error to try to get a pathname for a - ;; stream that doesn't have one, but I - ;; don't know if we guarantee that. - (error () nil))) - (*load-truename* (when *load-pathname* - (handler-case (truename stream) - (file-error () nil)))) - ;; Bindings used internally. - (*load-depth* (1+ *load-depth*))) - (funcall function))) +(defun resolve-load-truename (symbol untruename) + (if (boundp symbol) + (symbol-value symbol) + (set symbol (when untruename + (handler-case (truename untruename) + (file-error () nil)))))) ;;; Returns T if the stream is a binary input stream with a FASL header. (defun fasl-header-p (stream &key errorp) @@ -150,7 +168,10 @@ (when p ; Can't do it non-destructively on non-seekable streams. (unwind-protect (let* ((header *fasl-header-string-start-string*) - (buffer (make-array (length header) :element-type '(unsigned-byte 8))) + ;; MISMATCH is called no matter how few octets are read in, + ;; so start with BUFFER completely 0-initialized. + (buffer (make-array (length header) :element-type '(unsigned-byte 8) + :initial-element 0)) (n 0)) (flet ((scan () (maybe-skip-shebang-line stream) @@ -173,51 +194,79 @@ :expected header)))) (file-position stream p)))))) -(defun load (pathspec &key (verbose *load-verbose*) (print *load-print*) - (if-does-not-exist t) (external-format :default)) - "Load the file given by FILESPEC into the Lisp environment, returning - T on success." - (flet ((load-stream (stream faslp) - (when (and (fd-stream-p stream) +(defun load (filespec &key (verbose *load-verbose*) (print *load-print*) + (if-does-not-exist :error) (external-format :default)) + "Load the file given by FILESPEC into the Lisp environment, returning T on + success. The file type (a.k.a extension) is defaulted if missing. These + options are defined: + + :IF-DOES-NOT-EXIST + If :ERROR (the default), signal an error if the file can't be located. + If NIL, simply return NIL (LOAD normally returns T.) + + :VERBOSE + If true, print a line describing each file loaded. + + :PRINT + If true, print information about loaded values. When loading the + source, the result of evaluating each top-level form is printed. + + :EXTERNAL-FORMAT + The external-format to use when opening the FILENAME. The default is + :DEFAULT which uses the SB-EXT:*DEFAULT-EXTERNAL-FORMAT*." + (labels ((load-stream (stream faslp) + (if (and (fd-stream-p stream) (eq (sb-impl::fd-stream-fd-type stream) :directory)) - (error 'simple-file-error - :pathname (pathname stream) - :format-control - "Can't LOAD a directory: ~s." - :format-arguments (list (pathname stream)))) - (dx-flet ((thunk () - (let (;; Bindings required by ANSI. - (*readtable* *readtable*) - (*package* (sane-package)) - ;; KLUDGE: I can't find in the ANSI spec where it says - ;; that DECLAIM/PROCLAIM of optimization policy should - ;; have file scope. CMU CL did this, and it seems - ;; reasonable, but it might not be right; after all, - ;; things like (PROCLAIM '(TYPE ..)) don't have file - ;; scope, and I can't find anything under PROCLAIM or - ;; COMPILE-FILE or LOAD or OPTIMIZE which justifies this - ;; behavior. Hmm. -- WHN 2001-04-06 - (sb-c::*policy* sb-c::*policy*) - (sb-c::*handled-conditions* sb-c::*handled-conditions*)) - (if faslp - (load-as-fasl stream verbose print) - (sb-c:with-compiler-error-resignalling - (load-as-source stream :verbose verbose - :print print)))))) - (call-with-load-bindings #'thunk stream)))) + (error 'simple-file-error + :pathname (pathname stream) + :format-control "Can't LOAD a directory: ~s." + :format-arguments (list (pathname stream))) + (call-with-load-bindings + #'load-stream-1 stream + faslp + ;; If you prefer *LOAD-PATHNAME* to reflect what the user specified prior + ;; to merging, then CALL-WITH-LOAD-BINDINGS is passed FILESPEC, + ;; otherwise it is passed STREAM. + (cond ((and (not sb-c::*merge-pathnames*) + (typep filespec '(or string pathname))) + filespec) + (t stream))))) + (load-stream-1 (stream faslp) + (let (;; Bindings required by ANSI. + (*readtable* *readtable*) + (*package* (sane-package)) + ;; KLUDGE: I can't find in the ANSI spec where it says + ;; that DECLAIM/PROCLAIM of optimization policy should + ;; have file scope. CMU CL did this, and it seems + ;; reasonable, but it might not be right; after all, + ;; things like (PROCLAIM '(TYPE ..)) don't have file + ;; scope, and I can't find anything under PROCLAIM or + ;; COMPILE-FILE or LOAD or OPTIMIZE which justifies this + ;; behavior. Hmm. -- WHN 2001-04-06 + (sb-c::*policy* sb-c::*policy*) + (sb-c::*handled-conditions* sb-c::*handled-conditions*)) + (if faslp + (load-as-fasl stream verbose print) + ;; FIXME: if *EVALUATOR-MODE* is :INTERPRET, + ;; then this should have nothing whatsoever to do with + ;; compiler-error-resignaling. That's an artifact + ;; of using the compiler to perform interpretation. + (sb-c:with-compiler-error-resignalling + (load-as-source stream :verbose verbose :print print)))))) + (declare (truly-dynamic-extent #'load-stream-1)) ;; Case 1: stream. - (when (streamp pathspec) - (return-from load (load-stream pathspec (fasl-header-p pathspec)))) + (when (streamp filespec) + (return-from load (load-stream filespec (fasl-header-p filespec)))) - (let ((pathname (pathname pathspec))) + (let ((pathname (pathname filespec))) ;; Case 2: Open as binary, try to process as a fasl. (with-open-stream - (stream (or (open pathspec :element-type '(unsigned-byte 8) + (stream (or (open filespec :element-type '(unsigned-byte 8) :if-does-not-exist nil) - (when (null (pathname-type pathspec)) + (when (null (pathname-type filespec)) (let ((defaulted-pathname - (probe-load-defaults pathspec))) + (probe-load-defaults filespec))) (if defaulted-pathname (progn (setq pathname defaulted-pathname) (open pathname @@ -226,11 +275,28 @@ :element-type '(unsigned-byte 8)))))) (if if-does-not-exist (error 'simple-file-error - :pathname pathspec + :pathname filespec :format-control "~@<Couldn't load ~S: file does not exist.~@:>" - :format-arguments (list pathspec)) + :format-arguments (list filespec)) (return-from load nil)))) + ;; This is the understandable logic. + #-ansi-compliant-load-truename + (if (string-equal (pathname-type pathname) *fasl-file-type*) + (load-stream stream t) + (with-open-file (stream pathname :external-format external-format + :class 'form-tracking-stream) + (load-stream stream nil))) + ;; I have no idea what "don't allow empty .fasls" was supposed to mean. + ;; The more natural interpretation to me would be that if a file is empty, + ;; we don't treat the file as fasl, but instead treat it as source (and do nothing) + ;; regardless of the name. But the actual effect seems to be to force an error. + ;; So I would have commented that as "force an error on empty fasls", especially + ;; as there is ambiguity in "don't X and Y" - does it mean "don't X" and "don't Y"? + ;; Because surely that would be illogical - "don't assume empty files are source". + ;; Anyway, reasonable users should never test the edge cases of this, + ;; and so all it effectively achieves is slowing down the loading of files. + #+ansi-compliant-load-truename (let* ((real (probe-file stream)) (should-be-fasl-p (and real (string-equal (pathname-type real) *fasl-file-type*)))) @@ -285,13 +351,8 @@ ;;;; linkage fixups -;;; Lisp assembler routines are named by Lisp symbols, not strings, -;;; and so can be compared by EQ. -(define-load-time-global *assembler-routines* nil) -(declaim (code-component *assembler-routines*)) - (defun calc-asm-routine-bounds () - (loop for v being each hash-value of (car (%code-debug-info *assembler-routines*)) + (loop for v being each hash-value of (%code-debug-info *assembler-routines*) minimize (car v) into min maximize (cadr v) into max ;; min/max are inclusive byte ranges, but return the answer @@ -302,28 +363,61 @@ (defvar *!initial-assembler-routines*) (defun get-asm-routine (name &optional indirect &aux (code *assembler-routines*)) - (awhen (the list (gethash (the symbol name) (car (%code-debug-info code)))) - (sap-int (sap+ (code-instructions code) - (if indirect - ;; Return the address containing the routine address - (ash (cddr it) sb-vm:word-shift) - ;; Return the routine address itself - (car it)))))) + ;; Each architecture can define an "indirect" value in its own peculiar way. + ;; Only some of our architectures use that option. + (awhen (the list (gethash (the symbol name) (%code-debug-info code))) + (destructuring-bind (start end . index) it + (declare (ignore end) (ignorable index)) + (let* ((insts (code-instructions code)) + (addr (sap-int (sap+ insts start)))) + (unless indirect + (return-from get-asm-routine addr)) + #-(or ppc ppc64 x86 x86-64) (bug "Indirect asm-routine lookup") + #+(or ppc ppc64) (- addr sb-vm:nil-value) + #+(or x86 x86-64) ; return the address of a word containing 'addr' + (let ((offset (ash index sb-vm:word-shift))) + ;; the address is in the "external" static-space jump table + #+immobile-space (+ (get-lisp-obj-address *asm-routine-vector*) + (ash sb-vm:vector-data-offset sb-vm:word-shift) + ;; offset is biased by 1 word, accounting for the jump-table-count + ;; at the first word in code-instructions. So unbias it. + (- offset sb-vm:n-word-bytes sb-vm:other-pointer-lowtag)) + #-immobile-space ; the address is in the "internal" jump table + (sap-int (sap+ insts offset))))))) (defun !loader-cold-init () (let* ((code *assembler-routines*) (size (%code-text-size code)) (vector (the simple-vector *!initial-assembler-routines*)) (count (length vector)) - (ht (make-hash-table :test 'eq))) + (ht (make-hash-table))) ; keys are symbols (rplaca (%code-debug-info code) ht) + (setf *asm-routine-index-to-name* (make-array (1+ (length vector)))) (dotimes (i count) (destructuring-bind (name . offset) (svref vector i) (let ((next-offset (if (< (1+ i) count) (cdr (svref vector (1+ i))) size))) - (aver (> next-offset offset)) + (setf (aref *asm-routine-index-to-name* (1+ i)) name) + ;; Must be in ascending order, but one address can have more than one name. + (aver (>= next-offset offset)) ;; store inclusive bounds on PC offset range and the function index (setf (gethash name ht) (list* offset (1- next-offset) (1+ i)))))))) +#+x86-64 +(defun validate-asm-routine-vector () + ;; If the jump table in static space does not match the jump table + ;; in *assembler-routines*, fix the one one in static space. + ;; It's OK that this is delayed until startup, because code pertinent to + ;; core restart always uses relative jumps to asm code. + #+immobile-space + (let* ((code *assembler-routines*) + (external-table *asm-routine-vector*) + (insts (code-instructions code)) + (n (hash-table-count (%code-debug-info code)))) + (dotimes (i n) + (unless (= (aref external-table i) 0) + (setf (aref external-table i) + (sap-ref-word insts (ash (1+ i) sb-vm:word-shift))))))) + (defun !warm-load (file) (restart-case (let ((sb-c::*source-namestring* (format nil "SYS:~A" (substitute #\; #\/ file)))) diff --git a/src/code/target-misc.lisp b/src/code/target-misc.lisp index f6378c3e0c..dd2157bb7c 100644 --- a/src/code/target-misc.lisp +++ b/src/code/target-misc.lisp @@ -16,7 +16,7 @@ ;;; This is a tentative list of target features; many are removed later. ;;; :SB-XC is removed now, because it is plain wrong unless cross-compiling. -(defparameter *features* '#.(remove :sb-xc sb-xc:*features*) +(defvar *features* '#.(remove :sb-xc sb-xc:*features*) "a list of symbols that describe features provided by the implementation") (defconstant !sbcl-architecture #.(sb-cold::target-platform-keyword)) @@ -26,15 +26,16 @@ #+win32 (sb-win32::get-computer-name) #-win32 (truly-the simple-string (sb-unix:unix-gethostname))) -(declaim (type (or null string) *machine-version*)) -(defvar *machine-version*) +(declaim (type (or null simple-string) *machine-version*)) +(declaim (global *machine-version*)) (defun machine-version () "Return a string describing the version of the computer hardware we are running on, or NIL if we can't find any useful information." - (unless (boundp '*machine-version*) - (setf *machine-version* (get-machine-version))) - *machine-version*) + (if (boundp '*machine-version*) + *machine-version* + (setf *machine-version* + (awhen (get-machine-version) (possibly-base-stringize it))))) ;;; FIXME: Don't forget to set these in a sample site-init file. ;;; FIXME: Perhaps the functions could be SETFable instead of having the @@ -42,7 +43,7 @@ are running on, or NIL if we can't find any useful information." ;;; from ANSI 11.1.2.1.1 "Constraints on the COMMON-LISP Package ;;; for Conforming Implementations" it is kosher to add a SETF function for ;;; a symbol in COMMON-LISP.. -(declaim (type (or null string) *short-site-name* *long-site-name*)) +(declaim (type (or null simple-string) *short-site-name* *long-site-name*)) (define-load-time-global *short-site-name* nil "The value of SHORT-SITE-NAME.") (define-load-time-global *long-site-name* nil @@ -118,19 +119,8 @@ the file system." (close *dribble-stream*) (apply #'install-streams (pop *previous-dribble-streams*))))) (values)) - -;;;; some *LOAD-FOO* variables - -(defvar *load-print* nil - "the default for the :PRINT argument to LOAD") - -(defvar *load-verbose* nil - ;; Note that CMU CL's default for this was T, and ANSI says it's - ;; implementation-dependent. We choose NIL on the theory that it's - ;; a nicer default behavior for Unix programs. - "the default for the :VERBOSE argument to LOAD") - -;;; DEFmumble helpers + +;;;; DEFmumble helpers (defun %defglobal (name value source-location &optional (doc nil docp)) (%compiler-defglobal name :always-bound @@ -184,32 +174,6 @@ the file system." (in-package "SB-C") -(defun real-function-name (name) - ;; Resolve the actual name of the function named by NAME - ;; e.g. (setf (name-function 'x) #'car) - ;; (real-function-name 'x) => CAR - (cond ((not (fboundp name)) - nil) - ((and (symbolp name) - (macro-function name)) - (let ((name (%fun-name (macro-function name)))) - (and (consp name) - (eq (car name) 'macro-function) - (cadr name)))) - (t - (%fun-name (fdefinition name))))) - -(defun random-documentation (name type) - (cdr (assoc type (info :random-documentation :stuff name)))) - -(defun (setf random-documentation) (new-value name type) - (let ((pair (assoc type (info :random-documentation :stuff name)))) - (if pair - (setf (cdr pair) new-value) - (push (cons type new-value) - (info :random-documentation :stuff name)))) - new-value) - (defun split-version-string (string) (loop with subversion and start = 0 with end = (length string) @@ -250,8 +214,29 @@ version 1[.0.0...] or greater." (lisp-implementation-version) subversions)))) -(defparameter sb-pcl::*!docstrings* nil) +(defvar sb-pcl::*!docstrings* nil) (defun (setf documentation) (string name doc-type) (declare (type (or null string) string)) (push (list string name doc-type) sb-pcl::*!docstrings*) string) + +(in-package "SB-LOCKLESS") +(defstruct (list-node + (:conc-name nil) + (:constructor %make-sentinel-node ()) + (:copier nil)) + (%node-next nil)) + +;;; Specialized list variants will be created for +;;; fixnum, integer, real, string, generic "comparable" +;;; but the node type and list type is the same regardless of key type. +(defstruct (linked-list + (:constructor %make-lfl + (head inserter deleter finder inequality equality)) + (:conc-name list-)) + (head nil :type list-node :read-only t) + (inserter nil :type function :read-only t) + (deleter nil :type function :read-only t) + (finder nil :type function :read-only t) + (inequality nil :type function :read-only t) + (equality nil :type function :read-only t)) diff --git a/src/code/target-package.lisp b/src/code/target-package.lisp index aea38c64a6..945eb40eba 100644 --- a/src/code/target-package.lisp +++ b/src/code/target-package.lisp @@ -48,7 +48,7 @@ ;;;; sufficient, though interaction between parallel intern and use-package ;;;; needs to be considered with some care. -(!define-load-time-global *package-graph-lock* (sb-thread:make-mutex :name "Package Graph Lock")) +(define-load-time-global *package-graph-lock* nil) (defmacro with-package-graph ((&key) &body forms) ;; FIXME: Since name conflicts can be signalled while holding the @@ -157,7 +157,7 @@ ;; index. The returned value is a physical index. (named-let recurse ((start 0) (end (ash (length v) -1))) (declare (type (unsigned-byte 9) start end) - (optimize (sb-c::insert-array-bounds-checks 0))) + (optimize (sb-c:insert-array-bounds-checks 0))) (when (< start end) (let* ((i (ash (+ start end) -1)) (elt (keyfn (aref v (ash i 1))))) @@ -211,7 +211,7 @@ (ash (ldb (byte pkgnick-index-bits 0) token) 1)))))) ;;; This would have to be bumped ~ 2*most-positive-fixnum times to overflow. -(define-load-time-global *package-names-cookie* sb-xc:most-negative-fixnum) +(define-load-time-global *package-names-cookie* most-negative-fixnum) (declaim (fixnum *package-names-cookie*)) (defmacro with-package-names ((table-var &key) &body body) @@ -219,10 +219,6 @@ (sb-thread::with-recursive-system-lock ((info-env-mutex ,table-var)) ,@body))) -(defmethod make-load-form ((p package) &optional environment) - (declare (ignore environment)) - `(find-undeleted-package-or-lose ,(package-name p))) - ;;;; iteration macros (defmacro with-package-iterator ((mname package-list &rest symbol-types) &body body) @@ -326,13 +322,13 @@ of :INHERITED :EXTERNAL :INTERNAL." (defun make-package-hashtable (size) (flet ((actual-package-hashtable-size (size) (loop for n of-type fixnum - from (logior (ceiling size +package-rehash-threshold+) 1) + from (logior (ceiling size #.+package-rehash-threshold+) 1) by 2 when (positive-primep n) return n))) (let* ((n (actual-package-hashtable-size size)) ;; SIZE is how many symbols we'd like to be able to store, ;; but the number of physical cells is N, chosen for its primality. - (size (truncate (* n +package-rehash-threshold+))) + (size (truncate (* n #.+package-rehash-threshold+))) (table (make-array n :initial-element 0))) (%make-package-hashtable table size)))) @@ -499,7 +495,7 @@ error if any of PACKAGES is not a valid package designator." ;;; WITH-SINGLE-PACKAGE-LOCKED-ERROR. ;;; ;;; FIXME: Maybe we should establish such contours for he toplevel -;;; and others, so that %set-fdefinition and others could just use +;;; and others, so that (setf fdefinition) and others could just use ;;; this. (defun assert-symbol-home-package-unlocked (name &optional format-control &rest format-arguments) @@ -547,7 +543,7 @@ error if any of PACKAGES is not a valid package designator." ;;; making this a generic function then packages with custom package classes ;;; could hook into this to provide their own resolution. ;;; (Any such generic solution will turn the performance to crap, so let's not) -(declaim (inline find-package-using-package)) +(declaim (maybe-inline find-package-using-package)) (defun find-package-using-package (package-designator base) (let ((string (typecase package-designator (package @@ -579,11 +575,11 @@ Example: See also: ADD-PACKAGE-LOCAL-NICKNAME, PACKAGE-LOCAL-NICKNAMES, REMOVE-PACKAGE-LOCAL-NICKNAME, and the DEFPACKAGE option :LOCAL-NICKNAMES." - (declare (explicit-check)) + (declare (explicit-check) + (inline find-package-using-package)) ;; We had a BOUNDP check on *PACKAGE* here, but it's effectless due to the ;; always-bound proclamation. (find-package-using-package package-designator *package*)) -(declaim (notinline find-package-using-package)) ;;; ANSI says (in the definition of DELETE-PACKAGE) that these, and ;;; most other operations, are unspecified for deleted packages. We @@ -809,6 +805,7 @@ Experimental: interface subject to change." ;;; Add a symbol to a package hashtable. The symbol MUST NOT be present. (defun add-symbol (table symbol) + (setf (package-hashtable-modified table) t) (when (zerop (package-hashtable-free table)) ;; The hashtable is full. Resize it to be able to hold twice the ;; amount of symbols than it currently contains. The actual new size @@ -840,15 +837,33 @@ Experimental: interface subject to change." ;;; list of a package) into TABLE (the hashtable in *PACKAGE-NAMES*), ;;; taking care to adjust the count of phantom entries. (defun %register-package (table name object) + ;; Registration ensures a non-null id if it can (even for a "deferred" package) + (let ((package (if (listp object) (car object) object))) + (unless (package-id package) + ;; manipulation of the id->package vector is hard to do lock-freeely + ;; and it's not really a bottleneck, so just grab a lock. + (with-package-names (dummy) + (let* ((vector *id->package*) + ;; 30 is an arbitrary constant exceeding the number of builtin packages + (new-id (position nil vector :start 30))) + (when (and (null new-id) (< (length vector) +package-id-overflow+)) + (let* ((current-length (length vector)) + (new-length (min (+ current-length 10) +package-id-overflow+)) + (new-vector (make-array new-length :initial-element nil))) + (replace new-vector vector) + (setf *id->package* new-vector) + (setf new-id current-length + vector new-vector))) + (when new-id + (setf (package-id package) new-id + (aref vector new-id) package)))))) (let ((oldval (info-gethash name table))) (unless oldval ; if any value existed, no new physical cell is claimed (when (> (info-env-tombstones table) (floor (info-storage-capacity (info-env-storage table)) 4)) ;; Otherwise, when >1/4th of the table consists of tombstones, ;; then rebuild the table. - (%rebuild-package-names table) - (when (eq oldval :deleted) - (setq oldval nil)))) + (%rebuild-package-names table))) (setf (info-gethash name table) object) (when (eq oldval :deleted) (decf (info-env-tombstones table))))) @@ -880,13 +895,25 @@ Experimental: interface subject to change." (when (plusp (info-env-tombstones table)) (%rebuild-package-names table))) (flet ((tune-table-size (table) - (resize-package-hashtable - table - (round (* (/ +package-rehash-threshold+ - +package-hashtable-image-load-factor+) - (- (package-hashtable-size table) - (package-hashtable-free table) - (package-hashtable-deleted table))))))) + ;; The APROPOS-LIST R/O scan optimization is inadmissible if no R/O space + #-darwin-jit (setf (package-hashtable-modified table) nil) + ;; This is some cringeworthy logic but it solves a problem that has baffled + ;; me so many times that I can't even. See the test 'unintern.impure.lisp' + (let ((ct (- (package-hashtable-size table) + (package-hashtable-free table) + (package-hashtable-deleted table)))) + (cond ((zerop ct) + (aver (notany #'symbolp (package-hashtable-cells table))) + (setf (package-hashtable-cells table) #(0 0 0) ; literal is OK ! + ;; the secret to reconstructing on next use: it has 0 free cells + (package-hashtable-free table) 0 + (package-hashtable-size table) 2 + (package-hashtable-deleted table) 0)) + (t + (resize-package-hashtable + table + (round (* (/ +package-rehash-threshold+ + +package-hashtable-image-load-factor+) ct)))))))) (dolist (package (list-all-packages)) (tune-table-size (package-internal-symbols package)) (tune-table-size (package-external-symbols package))))) @@ -975,216 +1002,6 @@ Experimental: interface subject to change." "~S is already a nickname for ~S." nickname (package-%name found))))))) -;;; ANSI specifies that: -;;; (1) MAKE-PACKAGE and DEFPACKAGE use the same default package-use-list -;;; (2) that it (as an implementation-defined value) should be documented, -;;; which we do in the doc string. -;;; For OAOO reasons we give a name to this value and then use #. readmacro -;;; to splice it in as a constant. Anyone who actually wants a random value -;;; is free to :USE (PACKAGE-USE-LIST :CL-USER) or whatever. -;;; -;;; This must not use DEFGLOBAL, which calls SET-SYMBOL-GLOBAL-VALUE at -;;; compile-time. The xc stub for that is defined to error out on purpose, -;;; since there is no such thing as a global variable in portable CL. -;;; Anyway this is a trivial compile-time constant that disappears after -;;; self-build, so efficiency of reads (one of the concerns of DEFGLOBAL, -;;; the other being documentation of intent) doesn't matter in the least. -(eval-when (:compile-toplevel :load-toplevel :execute) - (defvar *!default-package-use-list* nil)) - -(defun make-package (name &key - (use '#.*!default-package-use-list*) - nicknames - (internal-symbols 10) - (external-symbols 10)) - #.(format nil - "Make a new package having the specified NAME, NICKNAMES, and USE -list. :INTERNAL-SYMBOLS and :EXTERNAL-SYMBOLS are estimates for the number of -internal and external symbols which will ultimately be present in the package. -The default value of USE is implementation-dependent, and in this -implementation it is ~S." *!default-package-use-list*) - (prog ((name (stringify-string-designator name)) - (nicks (stringify-string-designators nicknames)) - clobber) - :restart - (when (find-package name) - ;; ANSI specifies that this error is correctable. - (signal-package-cerror - name - "Clobber existing package." - "A package named ~S already exists" name) - (setf clobber t)) - (with-package-graph () - ;; Check for race, signal the error outside the lock. - (when (and (not clobber) (find-package name)) - (go :restart)) - (let ((package - (%make-package - name - (make-package-hashtable internal-symbols) - (make-package-hashtable external-symbols)))) - - ;; Do a USE-PACKAGE for each thing in the USE list so that checking for - ;; conflicting exports among used packages is done. - (use-package use package) - - ;; FIXME: ENTER-NEW-NICKNAMES can fail (ERROR) if nicknames are illegal, - ;; which would leave us with possibly-bad side effects from the earlier - ;; USE-PACKAGE (e.g. this package on the used-by lists of other packages, - ;; but not in *PACKAGE-NAMES*, and possibly import side effects too?). - ;; Perhaps this can be solved by just moving ENTER-NEW-NICKNAMES before - ;; USE-PACKAGE, but I need to check what kinds of errors can be caused by - ;; USE-PACKAGE, too. - (%enter-new-nicknames package nicks) - ;; The name table is actually multi-writer concurrent, but due to - ;; lazy removal of :DELETED entries we want to enforce a single-writer. - ;; We're inside WITH-PACKAGE-GRAPH so this is already synchronized with - ;; other MAKE-PACKAGE operations, but we need the additional lock - ;; so that it synchronizes with RENAME-PACKAGE. - (with-package-names (table) - (%register-package table name package)) - (atomic-incf *package-names-cookie*) - (return package))) - (bug "never"))) - -(flet ((remove-names (package name-table) - ;; An INFO-HASHTABLE does not support REMHASH. We can simulate it - ;; by changing the value to :DELETED. - ;; (NIL would be preferable, but INFO-GETHASH does not return - ;; a secondary value indicating whether the NIL was by default - ;; or found, not does it take a different default to return). - ;; At some point the table might contain more deleted values than - ;; useful values. We call %REBUILD-PACKAGE-NAMES to rectify that. - (dx-let ((names (cons (package-name package) - (package-nicknames package))) - (i 0)) - (dolist (name names) - ;; Aver that the following SETF doesn't insert a new <k,v> pair. - (aver (info-gethash name name-table)) - (setf (info-gethash name name-table) :deleted) - (incf i)) - (incf (info-env-tombstones name-table) i)) - nil)) - -;;; Change the name if we can, blast any old nicknames and then -;;; add in any new ones. -;;; -;;; The spec says that NAME is a package designator (not just a string designator) -;;; which is weird, but potentially meaningful if assigning new global nicknames. -;;; If not called for that purpose, then it's largely pointless, because you can't -;;; rename to any package-designator other than itself without causing a conflict. -;;; A survey of some other implementations suggests that we're in the minority -;;; as to the legality of (RENAME-PACKAGE "A" (FIND-PACKAGE "A") '("A-NICK")). -;;; -;;; ABCL: -;;; The value #<PACKAGE A> is not of type (OR STRING SYMBOL CHARACTER). -;;; CCL: -;;; Error: The value #<Package "A"> is not of the expected type (OR STRING SYMBOL CHARACTER). -;;; CMUCL: -;;; #<The A package, 0/9 internal, 0/9 external> cannot be coerced to a string. -;;; ECL: -;;; In function STRING, the value of the first argument is #<"A" package> -;;; which is not of the expected type STRING -;;; -;;; CLISP agrees with us that this usage is permitted. If the new "name" is a -;;; different package, it is merely the same error as if any already-existing name -;;; was given. I see no reason to be more strict than the spec would have it be. -(defun rename-package (package-designator name &optional (nicknames ())) - "Changes the name and nicknames for a package." - (prog ((nicks (stringify-string-designators nicknames))) - :restart - (let ((package (find-undeleted-package-or-lose package-designator)) - ;; This is the "weirdness" alluded to. Do it in the loop in case - ;; the stringified value changes on restart when NAME is a package. - (name (stringify-package-designator name)) - (found (find-package name))) - (unless (or (not found) (eq found package)) - (signal-package-error name - "A package named ~S already exists." name)) - (with-single-package-locked-error () - (unless (and (string= name (package-name package)) - (null (set-difference nicks (package-nicknames package) - :test #'string=))) - (assert-package-unlocked - package "renaming as ~A~@[ with nickname~*~P ~1@*~{~A~^, ~}~]" - name nicks (length nicks))) - (with-package-names (table) - ;; Check for race conditions now that we have the lock. - (unless (eq package (find-package package-designator)) - (go :restart)) - ;; Do the renaming. - (remove-names package table) - (%register-package table name package) - (setf (package-%name package) name - (package-%nicknames package) ())) - (%enter-new-nicknames package nicks)) - (atomic-incf *package-names-cookie*) - (return package)))) - -(defun delete-package (package-designator) - "Delete the package designated by PACKAGE-DESIGNATOR from the package - system data structures." - (tagbody :restart - (let ((package (find-package package-designator))) - (cond ((not package) - ;; This continuable error is required by ANSI. - (signal-package-cerror - package-designator - "Ignore." - "There is no package named ~S." package-designator) - (return-from delete-package nil)) - ((not (package-name package)) ; already deleted - (return-from delete-package nil)) - (t - (with-single-package-locked-error - (:package package "deleting package ~A" package) - (let ((use-list (package-used-by-list package))) - (when use-list - ;; This continuable error is specified by ANSI. - (signal-package-cerror - package - "Remove dependency in other packages." - "~@<Package ~S is used by package~P:~2I~_~S~@:>" - (package-name package) - (length use-list) - (mapcar #'package-name use-list)) - (dolist (p use-list) - (unuse-package package p)))) - (dolist (p (package-implements-list package)) - (remove-implementation-package package p)) - (with-package-graph () - ;; Check for races, restart if necessary. - (let ((package2 (find-package package-designator))) - (when (or (neq package package2) (package-used-by-list package2)) - (go :restart))) - (dolist (used (package-use-list package)) - (unuse-package used package)) - (setf (package-%local-nicknames package) nil) - ;; FIXME: lacking a way to advise UNINTERN that this package - ;; is pending deletion, a large package conses successively - ;; many smaller tables for no good reason. - (do-symbols (sym package) - (unintern sym package)) - (with-package-names (table) - (remove-names package table) - (setf (package-%name package) nil - ;; Setting PACKAGE-%NAME to NIL is required in order to - ;; make PACKAGE-NAME return NIL for a deleted package as - ;; ANSI requires. Setting the other slots to NIL - ;; and blowing away the PACKAGE-HASHTABLES is just done - ;; for tidiness and to help the GC. - (package-%nicknames package) nil)) - (atomic-incf *package-names-cookie*) - (setf (package-%use-list package) nil - (package-tables package) #() - (package-%shadowing-symbols package) nil - (package-internal-symbols package) - (make-package-hashtable 0) - (package-external-symbols package) - (make-package-hashtable 0))) - (return-from delete-package t))))))) -) ; end FLET - (defun list-all-packages () "Return a list of all existing packages." (let ((result ())) @@ -1226,17 +1043,17 @@ implementation it is ~S." *!default-package-use-list*) ;;; The fasloader always supplies NAME as a (SIMPLE-ARRAY <ELT-TYPE> 1), ;;; but the reader uses a buffer of CHARACTER, which, based on a flag, ;;; can be demoted to an array of BASE-CHAR. -(defun %intern (name length package elt-type ignore-lock) +(defun %intern (name length package elt-type ignore-lock &optional (allow-inherited t)) ;; No type declarations, %find-symbol will perform the checks (multiple-value-bind (symbol where) (%find-symbol name length package) - (if where + (if (and where (or allow-inherited (neq where :inherited))) (values symbol where) ;; Double-checked lock pattern: the common case has the symbol already interned, ;; but in case another thread is interning in parallel we need to check after ;; grabbing the lock. (with-package-graph () (setf (values symbol where) (%find-symbol name length package)) - (if where + (if (and where (or allow-inherited (neq where :inherited))) (values symbol where) (let* ((symbol-name (logically-readonlyize @@ -1780,62 +1597,6 @@ PACKAGE." (setf (package-%used-by-list p) (remove package (the list (package-%used-by-list p)))))) t))) - -(defun find-all-symbols (string-or-symbol) - "Return a list of all symbols in the system having the specified name." - (let ((string (string string-or-symbol)) - (result ())) - (do-packages (package) - (multiple-value-bind (symbol found) (find-symbol string package) - (when found (pushnew symbol result)))) - result)) - -;;;; APROPOS and APROPOS-LIST - -(defun briefly-describe-symbol (symbol) - (fresh-line) - (prin1 symbol) - (when (boundp symbol) - (write-string " (bound)")) - (when (fboundp symbol) - (write-string " (fbound)"))) - -(defun apropos-list (string-designator - &optional - package-designator - external-only) - "Like APROPOS, except that it returns a list of the symbols found instead - of describing them." - (if package-designator - (let ((package (find-undeleted-package-or-lose package-designator)) - (string (stringify-string-designator string-designator)) - (result nil)) - (do-symbols (symbol package) - (when (and (or (not external-only) - (and (eq (sb-xc:symbol-package symbol) package) - (eq (nth-value 1 (find-symbol (symbol-name symbol) - package)) - :external))) - (search string (symbol-name symbol) :test #'char-equal)) - (pushnew symbol result))) - (sort result #'string-lessp)) - (delete-duplicates - (mapcan (lambda (package) - (apropos-list string-designator package external-only)) - (sort (list-all-packages) #'string-lessp :key #'package-name))))) - -(defun apropos (string-designator &optional package external-only) - "Briefly describe all symbols which contain the specified STRING. - If PACKAGE is supplied then only describe symbols present in - that package. If EXTERNAL-ONLY then only describe - external symbols in the specified package." - ;; Implementing this in terms of APROPOS-LIST keeps things simple at the cost - ;; of some unnecessary consing; and the unnecessary consing shouldn't be an - ;; issue, since this function is is only useful interactively anyway, and - ;; we can cons and GC a lot faster than the typical user can read.. - (dolist (symbol (apropos-list string-designator package external-only)) - (briefly-describe-symbol symbol)) - (values)) ;;;; final initialization @@ -1844,19 +1605,35 @@ PACKAGE." ;;;; are delayed until cold-init. ;;;; The cold loader (GENESIS) set *!INITIAL-SYMBOLS* to the target ;;;; representation of the hosts's *COLD-PACKAGE-SYMBOLS*. -;;;; The shape of this list is ((package . (externals . internals)) ...) +;;;; The shape of this list is +;;;; (uninterned-symbols . ((package . (externals . internals)) ...) (defvar *!initial-symbols*) +(defun rebuild-package-vector () + (let ((max-id 0)) + (do-packages (pkg) + (let ((id (package-id pkg))) + (when id (setq max-id (max id max-id))))) + (let ((a (make-array (1+ max-id) :initial-element nil))) + (setf *id->package* a) + (do-packages (pkg) + (let ((id (package-id pkg))) + (when id + (setf (aref a id) pkg))))))) + (defun pkg-name= (a b) (and (not (eql a 0)) (string= a b))) -(defun !package-cold-init () +(defun !package-cold-init (&aux (specs (cdr *!initial-symbols*))) + (setf *package-graph-lock* (sb-thread:make-mutex :name "Package Graph Lock")) (setf *package-names* (make-info-hashtable :comparator #'pkg-name= - :hash-function #'sxhash) - *package-nickname-ids* - (cons (make-info-hashtable :comparator #'pkg-name= - :hash-function #'sxhash) - 1)) + :hash-function #'sxhash)) + (setf *package-nickname-ids* (cons (make-info-hashtable :comparator #'pkg-name= + :hash-function #'sxhash) + 1)) + (setf (sb-thread:mutex-name (info-env-mutex *package-names*)) "package names" + (sb-thread:mutex-name (info-env-mutex (car *package-nickname-ids*))) + "package nicknames") (with-package-names (names) - (dolist (spec *!initial-symbols*) + (dolist (spec specs) (let ((pkg (car spec)) (symbols (cdr spec))) ;; the symbol MAKE-TABLE wouldn't magically disappear, ;; though its only use be to name an FLET in a function @@ -1876,11 +1653,27 @@ PACKAGE." (setf (package-%implementation-packages pkg) nil)))) ;; pass 2 - set the 'tables' slots only after all tables have been made - (dolist (spec *!initial-symbols*) + (dolist (spec specs) (let ((pkg (car spec))) (setf (package-tables pkg) (map 'vector #'package-external-symbols (package-%use-list pkg))))) + (rebuild-package-vector) + ;; Having made all packages, verify that symbol hashes are good. + (flet ((check-hash-slot (symbols) ; a vector + ;; type decl is critical here - can't invoke a hairy aref routine yet + (dovector (symbol (the simple-vector symbols)) + (when symbol ; skip NIL because of its magic-ness + (let* ((stored-hash (symbol-hash symbol)) + (name (symbol-name symbol)) + (computed-hash (compute-symbol-hash name (length name)))) + (aver (= stored-hash computed-hash))))))) + (check-hash-slot (car *!initial-symbols*)) + (dolist (spec specs) + (check-hash-slot (second spec)) + (check-hash-slot (third spec)))) + + ;; The joke's on you. They're pseudo-static, hence not GCable... (/show0 "about to MAKUNBOUND *!INITIAL-SYMBOLS*") (%makunbound '*!initial-symbols*)) ; (so that it gets GCed) @@ -1962,7 +1755,7 @@ PACKAGE." (logand start-state 3)))))) (when (zerop index) (return (advance start-state)))))) - (declare (optimize (sb-c::insert-array-bounds-checks 0))) + (declare (optimize (sb-c:insert-array-bounds-checks 0))) (if (logtest start-state +package-iter-check-shadows+) (let ((shadows (package-%shadowing-symbols (this-package)))) (scan (not (member sym shadows :test #'string=)))) @@ -2058,6 +1851,103 @@ PACKAGE." ;; cookie. i.e. a cached NIL is correct until the next cache invalidation. (or (null pkg) (and (packagep pkg) (package-%name pkg))))) + +;;;; special package hacks for the loader + +(defvar *deferred-package-names*) + +;;; A deferred package is a package which is not added to the normal +;;; package database until some later point in time. The current +;;; purpose for deferred packages is so that the loader symbol fasl +;;; ops can intern symbols into packages, without the packages +;;; necessarily being created yet. This is important for deferred +;;; top-level form loading, as to not cause loading symbols (which may +;;; appear as literal code constants) to fail early. Since the +;;; deferred package is not added to the normal package database until +;;; the package is actually created, we preserve package environment +;;; semantics at runtime, and give a reasonable error if the package +;;; has not been created by the end of the load. +(defun find-or-maybe-make-deferred-package (name) + (or (find-package name) + (progn + (unless *deferred-package-names* ; bind on demand + (setq *deferred-package-names* + (make-info-hashtable :comparator #'pkg-name= + :hash-function #'sxhash))) + (or (%get-package name *deferred-package-names*) + (let ((package (%make-package (make-package-hashtable 0) + (make-package-hashtable 0)))) + (%register-package *deferred-package-names* name package) + (setf (package-%name package) name) + package))))) + +;;; Return the deferred package object for NAME if it exists, otherwise +;;; return NIL. +(defun resolve-deferred-package (name) + (and (boundp '*deferred-package-names*) + *deferred-package-names* + (let ((package (%get-package name *deferred-package-names*))) + (when package + ;; To simulate remhash. + (setf (info-gethash name *deferred-package-names*) :deleted)) + package))) + +(defvar *rehoming-package-names*) + +;;; When we are in the loader, DELETE-PACKAGE installs a rehoming +;;; package in the SYMBOL-PACKAGE of its internal symbols. This has +;;; the effect that when a package of the same name is newly redefined +;;; later in the compiled file, the package gets updated and those +;;; internal symbols get rehomed properly. +(defun make-rehoming-package (package) + (and (boundp '*rehoming-package-names*) + (let ((name (package-%name package))) + (unless *rehoming-package-names* ; bind on demand + (setq *rehoming-package-names* + (make-info-hashtable :comparator #'pkg-name= + :hash-function #'sxhash))) + (aver (not (%get-package name *rehoming-package-names*))) + (let ((package (%make-package (package-internal-symbols package) + (package-external-symbols package)))) + (%register-package *rehoming-package-names* name package) + (setf (package-%name package) name) + package)))) + +;;; Return the rehoming object for NAME if it exists, otherwise return +;;; NIL. +(defun resolve-rehoming-package (name) + (and (boundp '*rehoming-package-names*) + *rehoming-package-names* + (let ((package (%get-package name *rehoming-package-names*))) + (when package + ;; To simulate remhash. + (setf (info-gethash name *rehoming-package-names*) :deleted)) + package))) + +;;; Bind the deferred and rehoming package name tables and test to see +;;; if the deferred package table still has any unresolved entries +;;; after FUNCTION is called. +(defun call-with-loader-package-names (function) + (let* ((boundp (boundp '*deferred-package-names*)) + ;; bind on demand + (*deferred-package-names* (if boundp *deferred-package-names* nil)) + (*rehoming-package-names* (if boundp *rehoming-package-names* nil))) + (funcall function) + (when (and (not boundp) *deferred-package-names*) + (info-maphash + (lambda (name package) + (unless (eq package :deleted) + (dovector (sym (package-hashtable-cells + (package-internal-symbols package))) + (when (symbolp sym) + (error 'simple-package-error + :format-control + "The loader tried loading the symbol named ~a ~ + into the package named ~a, but the package did ~ + not get defined, and does not exist." + :format-arguments (list (symbol-name sym) name)))))) + *deferred-package-names*)))) + ;;; We don't benefit from these transforms because any time we have a constant ;;; package in our code, we refer to it via #.(FIND-PACKAGE). ;;; This is a necessity due to the fact that historically all packages got renamed @@ -2087,3 +1977,11 @@ PACKAGE." (deftransform find-symbol ((name package-name) (t (constant-arg string-designator))) `(sb-impl::find-symbol2 name ,(find-package-xform package-name))) + +;;; As for the INTERN transform, you could be screwed if you use any of the +;;; standard package names as a local nickname of a random package. +(deftransform find-package ((name) ((constant-arg string-designator))) + (multiple-value-bind (form constp) (find-package-xform name) + ;; standard packages are effectively constant objects, otherwise + ;; we have to invoke the find function. + (if constp form `(sb-impl::cached-find-package ,form)))) diff --git a/src/code/target-pathname.lisp b/src/code/target-pathname.lisp index 7e743c4865..5045fe09ee 100644 --- a/src/code/target-pathname.lisp +++ b/src/code/target-pathname.lisp @@ -37,6 +37,7 @@ (unparse-directory-separator ";") (simplify-namestring #'identity) (customary-case :upper))) + (name-hash 0 :type fixnum) (name "" :type simple-string :read-only t) (translations nil :type list) (canon-transls nil :type list)) @@ -57,34 +58,27 @@ ;;; ;;; Physical pathnames include all these slots and a device slot. -;;; Logical pathnames are a subclass of PATHNAME. Their class -;;; relations are mimicked using structures for efficiency. -(defstruct (logical-pathname (:conc-name %logical-pathname-) - (:include pathname) - (:copier nil) - (:constructor %make-logical-pathname - (host device directory name type version - &aux (dir-hash (pathname-dir-hash directory)) - (stem-hash (mix (sxhash name) (sxhash type))))))) - -;;; FIXME: this, and many other FREEZE-TYPEs don't actually do anything. -;;; Unobvious order of execution of TLFs in cold-init is one potential problem, -;;; but there could be other issues as well, like maybe we're unsealing classes -;;; because the FREEZE-TYPE was wrong to begin with. (So why no warnings then?) -;;; This declamation also freezes LOGICAL-PATHNAME, but we can't freeze HOST -;;; because later on we define either UNIX-HOST or WIN32-HOST. -#-sb-fluid (declaim (freeze-type pathname logical-host)) - -(defmethod make-load-form ((logical-host logical-host) &optional env) - (declare (ignore env)) - (values `(find-logical-host ',(logical-host-name logical-host)) - nil)) +;;; We can't freeze HOST because later on we define either UNIX-HOST or WIN32-HOST. +(declaim (freeze-type logical-host)) ;;; Utility functions (deftype absent-pathname-component () '(member nil :unspecific)) +(defun make-pattern (pieces) + ;; Ensure that the hash will meet the SXASH persistence requirement: + ;; "2. For any two objects, x and y, both of which are ... pathnames ... and which are similar, + ;; (sxhash x) and (sxhash y) yield the same mathematical value even if x and y exist in + ;; different Lisp images of the same implementation." + ;; Specifically, hashes that depend on object identity (address) are impermissible. + (dolist (piece pieces) + (aver (typep piece '(or string symbol (cons (eql :character-set) string))))) + (%make-pattern (sxhash pieces) pieces)) + +(declaim (inline %pathname-directory)) +(defun %pathname-directory (pathname) (car (%pathname-dir+hash pathname))) + (declaim (inline pathname-component-present-p)) (defun pathname-component-present-p (component) (not (typep component 'absent-pathname-component))) @@ -238,37 +232,10 @@ ;;; *DEFAULT-PATHNAME-DEFAULTS* before *DEFAULT-PATHNAME-DEFAULTS* is ;;; initialized (at which time we can't safely call e.g. #'PATHNAME). (defun make-trivial-default-pathname () - (%%make-pathname *physical-host* nil nil nil nil :newest)) + (intern-pathname *physical-host* nil nil nil nil :newest)) ;;; pathname methods -;;; SXHASH does a really poor job on pathname directory, especially if in your -;;; environment, the directories of interest are all many levels down from the -;;; filesystem root- every directory in your work space might hash to the same -;;; value under SXHASH. Mixing in all pieces of the directory path solves that. -(defun pathname-dir-hash (directory) - ;; FIXME: all instances of PATTERN hash to the same thing. - ;; We should probably hash the pattern pieces. (Same for stem-hash) - (let ((hash (sxhash (car directory)))) - (dolist (piece (cdr directory) hash) - (mixf hash (sxhash piece))))) -;;; Pathname hashing used to be nested inside SXHASH so that it could utilize -;;; the depth cutoff to avoid performing unbounded work. We don't need that any more, -;;; as the parts of the pathname that invoke SXHASH (host, device, version) are atoms -;;; and hence they entail bounded computation. -(defun pathname-sxhash (x) - (declare (pathname x)) - ;; Pathnames are EQUAL if all the components are EQUAL, so - ;; we hash all of the components of a pathname together. - (let ((hash (sxhash (pathname-host x)))) - (mixf hash (sxhash (pathname-device x))) - (mixf hash (logxor (%pathname-dir-hash x) - (%pathname-stem-hash x))) - ;; Hash :NEWEST the same as NIL because EQUAL for - ;; pathnames assumes that :newest and nil are equal. - (let ((version (%pathname-version x))) - (mixf hash (sxhash (if (eq version :newest) nil version)))))) - (defmethod print-object ((pathname pathname) stream) (let ((namestring (handler-case (namestring pathname) (error nil)))) @@ -288,41 +255,98 @@ (%pathname-name pathname) (%pathname-type pathname) (%pathname-version pathname)))))) - -(defmethod make-load-form ((pathname pathname) &optional environment) - (make-load-form-saving-slots pathname :environment environment)) +;;; Use an unsynchronized weak hash table with explicit locking to "try" +;;; to intern pathnames. "Try" because there are several factors that preclude +;;; ensuring uniqueness: +;;; - pathname is a STRUCTURE-OBJECT, so users might call COPY-STRUCTURE. +;;; We can make that fail by inventing a subtype of instance that is not +;;; a STRUCTURE-OBJECT. Whatever that metatype is could be useful for +;;; PATTERN (parts of the pathname) as well as THREAD, MUTEX, HASH-TABLE +;;; and maybe some other things that yield strange semantics if copied. +;;; - the load form methods use MAKE-LOAD-FORM-SAVING-SLOTS thereby +;;; bypassing the interning operation. That seems totally fixable. +;;; +;;; Additionally, it would be nice if this table would act to reduce +;;; EQUAL to EQ on pathnames by ensuring that we never intern two distinct +;;; pathnames that are EQUAL. +;;; That would require performing some canonicalization immediately which may +;;; or may not pose a problem for fixing https://bugs.launchpad.net/sbcl/+bug/1834266 +;;; which is to say, if hosts can actually be :UNSPECIFIC, then the version +;;; collapsing that is done here would not be done. I don't know if it's that simple. +;;; If it isn't that simple, then the answer is that hash function and comparator +;;; function used for the *PATHNAMES* table needs to be more fine-grained than +;;; the hash value that SXHASH returns for a pathname. +;;; +;;; The spec is actually extremely underspecified in regard to the meaning of +;;; "pathnames that are equal should be functionally equivalent." +;;; The simple test: +;;; (equal (make-pathname :name "a" :version nil) (make-pathname :name "a" :version :newest)) +;;; shows that EQUAL is inconsistent in terms of what "functionally equivalent" means: +;;; SBCL, ABCL, and CCL => T +;;; CLISP and ECL => NIL +;;; Also, on case-sensitive-case-preserving filesystems it's not possible +;;; to know which pathnames are equivalent without asking the filesystem. +;;; +;;; This table uses %MAKE-HASH-TABLE, not MAKE-HASH-TABLE, because the latter +;;; always creates a synchronized table if :WEAKNESS is specified. +;;; But to correctly use the "put-if-absent" operation, the locking must occur +;;; *around* the get and put operations. It makes no sense to lock the table around +;;; individual operations, hence the unsynchronized table. + +(defun make-pathname-intern-table () + (let ((h (%make-hash-table (logior (pack-ht-flags-weakness +ht-weak-value+) + (pack-ht-flags-kind 3) + hash-table-userfun-flag) + 'pathname-key= + #'pathname-key= + #'pathname-sxhash + 10 + default-rehash-size + $1.0))) + (install-hash-table-lock h) + h)) +(define-load-time-global *pathnames* (make-pathname-intern-table)) + ;;; A pathname is logical if the host component is a logical host. ;;; This constructor is used to make an instance of the correct type ;;; from parsed arguments. -(defun %make-maybe-logical-pathname (host device directory name type version) +(defun intern-pathname (host device directory name type version) ;; We canonicalize logical pathname components to uppercase. ANSI ;; doesn't strictly require this, leaving it up to the implementor; ;; but the arguments given in the X3J13 cleanup issue ;; PATHNAME-LOGICAL:ADD seem compelling: we should canonicalize the ;; case, and uppercase is the ordinary way to do that. (flet ((upcase-maybe (x) (typecase x (string (logical-word-or-lose x)) (t x)))) - (if (typep host 'logical-host) - (%make-logical-pathname host - :unspecific - (mapcar #'upcase-maybe directory) - (upcase-maybe name) - (upcase-maybe type) - version) - (progn - (aver (eq host *physical-host*)) - (%make-pathname host device directory name type version))))) - -;;; Hash table searching maps a logical pathname's host to its -;;; physical pathname translation. -(define-load-time-global *logical-hosts* - (make-hash-table :test 'equal :synchronized t)) + (when (typep host 'logical-host) + (setq device :unspecific + directory (mapcar #'upcase-maybe directory) + name (upcase-maybe name) + type (upcase-maybe type)))) + (let ((table *pathnames*)) + (declare (inline !allocate-pathname)) ; for DXability + (with-system-mutex ((hash-table-%lock table)) + (let* ((dir+hash (when directory + (ensure-gethash + directory table + (cons directory (pathname-sxhash directory))))) + (key (!allocate-pathname host device dir+hash name type version))) + (declare (truly-dynamic-extent key)) + (or (gethash key table) + (let ((key (!allocate-pathname host device dir+hash name type version))) + (when (typep host 'logical-host) + (setf (%instance-wrapper key) #.(find-layout 'logical-pathname))) + (setf (gethash key table) key))))))) + +;;; Vector of logical host objects, each of which contains its translations. +;;; The vector is never mutated- always a new vector is created when adding +;;; translations for a new host. So nothing needs locking. +;;; And the fact that hosts are never deleted keeps things really simple. +(define-load-time-global *logical-hosts* #()) +(declaim (simple-vector *logical-hosts*)) ;;;; patterns -(defmethod make-load-form ((pattern pattern) &optional environment) - (make-load-form-saving-slots pattern :environment environment)) - (defmethod print-object ((pattern pattern) stream) (print-unreadable-object (pattern stream :type t) (if *print-pretty* @@ -446,7 +470,7 @@ (pattern ;; A pattern is only matched by an identical pattern. (and (pattern-p wild) (pattern= thing wild))) - (integer + (bignum ;; An integer (version number) is matched by :WILD or the ;; same integer. This branch will actually always be NIL as ;; long as the version is a fixnum. @@ -454,120 +478,91 @@ ;;; a predicate for comparing two pathname slot component sub-entries (defun compare-component (this that) - (or (eql this that) + (or (eq this that) (typecase this (simple-string (and (simple-string-p that) (string= this that))) (pattern + ;; PATTERN instances should probably become interned objects + ;; so that we can use EQ on them. But that currently has the same + ;; problem as PATHAME= has - the cache can be bypassed. (and (pattern-p that) (pattern= this that))) (cons (and (consp that) (compare-component (car this) (car that)) - (compare-component (cdr this) (cdr that))))))) + (compare-component (cdr this) (cdr that)))) + (bignum + (eql this that))))) ;;;; pathname functions -(defun pathname= (pathname1 pathname2) - (declare (type pathname pathname1) - (type pathname pathname2)) - (or (eq pathname1 pathname2) - (and (eq (%pathname-host pathname1) - (%pathname-host pathname2)) - (= (%pathname-dir-hash pathname1) (%pathname-dir-hash pathname2)) - (= (%pathname-stem-hash pathname1) (%pathname-stem-hash pathname2)) - (compare-component (%pathname-device pathname1) - (%pathname-device pathname2)) - (compare-component (%pathname-directory pathname1) - (%pathname-directory pathname2)) - (compare-component (%pathname-name pathname1) - (%pathname-name pathname2)) - (compare-component (%pathname-type pathname1) - (%pathname-type pathname2)) - (or (eq (%pathname-host pathname1) *physical-host*) - (compare-component (%pathname-version pathname1) - (%pathname-version pathname2)))))) - -;;; This is conceptually like (DEFUN-CACHED (%MAKE-PATHNAME ...)) -;;; except that we try hard never to evict entries until SAVE-LISP-AND-DIE. -;;; Entries can still be kicked out randomly though. -;;; A two-level lookup is used- it works better than mixing all -;;; pathname components into a hash key. -(define-load-time-global *pathnames* (make-array 211 :initial-element nil)) -(define-load-time-global *pathnames-lock* (sb-thread:make-mutex :name "Pathnames")) - -(defun %make-pathname (host device directory name type version) - (if (or device (neq host *physical-host*)) - (%%make-pathname host device directory name type version) - (let* ((table *pathnames*) - (index (rem (pathname-dir-hash directory) (length table))) - (dir-holder - ;; Candidates is a list of ((dir . contents) ...) - (loop named outer - with candidates = (svref table index) and new = nil - do - (let ((n-candidates 0)) - (dolist (candidate candidates) - (incf n-candidates) - (when (compare-component (car candidate) directory) - (return-from outer candidate))) - (unless new - (setq new (cons directory (make-array 3 :initial-element nil)))) - (cond ((< n-candidates 10) - (let* ((cell (cons new candidates)) - (actual-old (cas (svref table index) candidates cell))) - (when (eq actual-old candidates) - (return-from outer new)) - (setq candidates actual-old))) - (t - ;; Clobber this cache entry, losing all directories in it. - ;; Hopefully this doesn't happen often. - #+nil (format t "~&*** Pathname cache overflow: ~D ~S~%" - index (mapcar 'car candidates)) - (setf (svref table index) (list new)) - (return-from outer new))))))) - (flet ((matchp (stem-hash candidates) - (let ((n-candidates 0)) - (dolist (pathname candidates (values nil n-candidates)) - (when (and (= (%pathname-stem-hash pathname) stem-hash) - (compare-component (%pathname-version pathname) version) - (compare-component (%pathname-name pathname) name) - (compare-component (%pathname-type pathname) type)) - (return (values pathname 0))) - (incf n-candidates))))) - ;; We have tests asserting that the distinction between :NEWEST - ;; and NIL is preserved, though there is no effective difference. - (binding* ((stem-hash (mix (sxhash name) (sxhash type))) - (vector (the simple-vector (cdr dir-holder))) - (index (rem stem-hash (length vector))) - (candidates (svref vector index)) - ((found n-candidates) (matchp stem-hash candidates))) - (when found - (return-from %make-pathname found)) - ;; Optimistically assuming that the pathname won't be found - ;; on the double-check, allocate it now - (let ((pathname (%%make-pathname *physical-host* nil (car dir-holder) - name type version))) - (sb-thread::with-system-mutex (*pathnames-lock*) - (when (>= n-candidates 10) - ;; Rehash into a larger vector - (let* ((old-len (length vector)) - (new-len (+ old-len 4)) - (new-vector (make-array new-len :initial-element nil))) - (dovector (list vector) - (dolist (p list) - (push p (svref new-vector (rem (%pathname-stem-hash p) - new-len))))) - (rplacd dir-holder new-vector) - (setq vector new-vector - index (rem stem-hash new-len) - candidates (svref vector index)))) - (let ((found (matchp stem-hash candidates))) - (if found - (setq pathname found) - (push pathname (svref vector index))))) - pathname)))))) +(macrolet ((compare-most-components () + `(and (eq (%pathname-host a) (%pathname-host b)) ; Interned + ;; Unless the pathname cache can be made 100% reliable, + ;; strength-reducing EQUAL to EQ is inadmissible here. + ;; To fix that, MAKE-LOAD-FORM methods need not to bypass + ;; INTERN-PATHNAME. + (let ((dir-a (%pathname-dir+hash a)) + (dir-b (%pathname-dir+hash b))) + (or (eq dir-a dir-b) + (compare-component (car dir-a) (car dir-b)))) + (compare-component (%pathname-device a) (%pathname-device b)) + (compare-component (%pathname-name a) (%pathname-name b)) + (compare-component (%pathname-type a) (%pathname-type b))))) + +;;; PATHNAME-KEY= can receive two different subsets of keys: +;;; - non-nil LIST is the directory part of a pathname +;;; - entire PATHNAME +(defun pathname-key= (a b) + (etypecase a + (list (and (listp b) (compare-component a b))) + (pathname (and (pathnamep b) + (compare-most-components) + (eql (pathname-version a) (pathname-version b)))))) + +(defun pathname= (a b) + (declare (type pathname a b)) + (or (eq a b) + (and (compare-most-components) + (or (eq (%pathname-host a) *physical-host*) + (compare-component (pathname-version a) + (pathname-version b))))))) + +(sb-kernel::assign-equalp-impl 'pathname #'pathname=) +(sb-kernel::assign-equalp-impl 'logical-pathname #'pathname=) + +;;; Hash either a PATHNAME or a PATHNAME-DIRECTORY. This is called byt both SXHASH +;;; and by the interning of pathnames, which uses a multi-step approaching to +;;; coalescing shared subparts. If an EQUAL directory was used before, we share that. +;;; Since a directory is stored with its hash precomputed, hashing a PATHNAME as a +;;; whole entails at most 4 more MIX operations. So using pathnames as keys in +;;; a hash-table pays a small up-front price for later speed improvement. +(defun pathname-sxhash (x) + (flet ((hash-piece (piece) + (etypecase piece + (string (sxhash piece)) ; transformed + (symbol (sxhash piece)) ; transformed + (pattern (pattern-hash piece)) + ((cons (eql :home) (cons string null)) + (sxhash (second piece)))))) + (etypecase x + (pathname + (let* ((host (%pathname-host x)) + ;; NAME-HASH is based on SXHASH of a string + (hash (if (typep host 'logical-host) (logical-host-name-hash host) 0))) + (mixf hash (hash-piece (%pathname-device x))) ; surely stringlike, right? + (awhen (%pathname-dir+hash x) (mixf hash (cdr it))) + (mixf hash (hash-piece (%pathname-name x))) + (mixf hash (hash-piece (%pathname-type x))) + ;; EQUAL might ignore the version, and it doesn't provide many bits + ;; of randomness, so don't bother with it. + hash)) + (list ;; a directory + (let ((hash 0)) + (dolist (piece x hash) + (mixf hash (hash-piece piece)))))))) ;;; Convert PATHNAME-DESIGNATOR (a pathname, or string, or ;;; stream), into a pathname in PATHNAME. @@ -767,7 +762,7 @@ the operating system native pathname conventions." (if diddle-case (diddle-case default) default))))) - (%make-maybe-logical-pathname + (intern-pathname (or pathname-host default-host) ;; The device of ~/ shouldn't be merged, because the ;; expansion may have a different device @@ -902,7 +897,7 @@ a host-structure or string." diddle-defaults)) (t nil)))) - (%make-maybe-logical-pathname + (intern-pathname host (pick device devp %pathname-device) ; forced to :UNSPECIFIC when logical dir @@ -1043,22 +1038,9 @@ a host-structure or string." does not match the explicit HOST argument, ~S." :format-arguments (list new-host host))) (let ((pn-host (or new-host host (pathname-host defaults)))) - (values (%make-maybe-logical-pathname - pn-host device directory file type version) + (values (intern-pathname pn-host device directory file type version) end))))))) -;;; If NAMESTR begins with a colon-terminated, defined, logical host, -;;; then return that host, otherwise return NIL. -(defun extract-logical-host-prefix (namestr start end) - (declare (type simple-string namestr) - (type index start end) - (values (or logical-host null))) - (let ((colon-pos (position #\: namestr :start start :end end))) - (if colon-pos - (values (gethash (nstring-upcase (subseq namestr start colon-pos)) - *logical-hosts*)) - nil))) - (defun parse-namestring (thing &optional host @@ -1134,8 +1116,7 @@ a host-structure or string." does not match the explicit HOST argument, ~S." :format-arguments (list new-host host))) (let ((pn-host (or new-host host (pathname-host defaults)))) - (values (%make-pathname - pn-host device directory file type version) + (values (intern-pathname pn-host device directory file type version) end))))))) (defun parse-native-namestring (thing @@ -1499,7 +1480,7 @@ unspecified elements into a completed to-pathname based on the to-wildname." (if (eq result :error) (error "~S doesn't match ~S." source from) result)))) - (%make-maybe-logical-pathname + (intern-pathname (or to-host source-host) (frob %pathname-device) (frob %pathname-directory translate-directories) @@ -1572,8 +1553,13 @@ unspecified elements into a completed to-pathname based on the to-wildname." (defun find-logical-host (thing &optional (errorp t)) (etypecase thing (string - (let ((found (gethash (logical-word-or-lose thing) - *logical-hosts*))) + (let* ((name (logical-word-or-lose thing)) + (hash (sxhash name)) + ;; Can do better here: binary search, since we maintain sorted order. + (found (dovector (x *logical-hosts*) + (when (and (eq (logical-host-name-hash x) hash) + (string= (logical-host-name x) name)) + (return x))))) (if (or found (not errorp)) found ;; This is the error signalled from e.g. @@ -1591,13 +1577,16 @@ unspecified elements into a completed to-pathname based on the to-wildname." ;;; Given a logical host name or host, return a logical host, creating ;;; a new one if necessary. -(defun intern-logical-host (thing) - (with-locked-system-table (*logical-hosts*) - (or (find-logical-host thing nil) - (let* ((name (logical-word-or-lose thing)) - (new (make-logical-host :name name))) - (setf (gethash name *logical-hosts*) new) - new)))) +(defun intern-logical-host (thing &aux name host) + (loop + (awhen (find-logical-host thing nil) (return it)) + (unless name + (setq name (logical-word-or-lose thing) + host (make-logical-host :name name :name-hash (sxhash name)))) + (let* ((old *logical-hosts*) + (new (merge 'vector old (list host) #'string< :key #'logical-host-name))) + (when (eq (cas *logical-hosts* old new) old) + (return host))))) ;;;; logical pathname parsing @@ -1747,9 +1736,14 @@ unspecified elements into a completed to-pathname based on the to-wildname." (parse-host (logical-chunkify namestr start end))) (values host :unspecific (directory) name type version)))) -;;; We can't initialize this yet because not all host methods are -;;; loaded yet. -(defvar *logical-pathname-defaults*) +;;; Return a value suitable, e.g., for preinitializing +;;; *DEFAULT-PATHNAME-DEFAULTS* before *DEFAULT-PATHNAME-DEFAULTS* is +;;; initialized (at which time we can't safely call e.g. #'PATHNAME). +(defun make-trivial-default-logical-pathname () + (intern-pathname (make-logical-host :name "") :unspecific nil nil nil nil)) + +(define-load-time-global *logical-pathname-defaults* + (make-trivial-default-logical-pathname)) (defun logical-namestring-p (x) (and (stringp x) @@ -1943,11 +1937,6 @@ unspecified elements into a completed to-pathname based on the to-wildname." (translate-logical-pathname possibly-logical-pathname) possibly-logical-pathname)) -(defvar *logical-pathname-defaults* - (%make-logical-pathname - (make-logical-host :name (logical-word-or-lose "BOGUS")) - :unspecific nil nil nil nil)) - (defun load-logical-pathname-translations (host) "Reads logical pathname translations from SYS:SITE;HOST.TRANSLATIONS.NEWEST, with HOST replaced by the supplied parameter. Returns T on success. @@ -2024,3 +2013,24 @@ existing translations for \"SYS:SRC;\", \"SYS:CONTRIB;\", and ("SYS:CONTRIB;**;*.*.*" ,(physical-target "contrib")) ("SYS:OUTPUT;**;*.*.*" ,(physical-target "output")) ,@current-translations))))) + +(defmethod make-load-form ((pn pathname) &optional env) + (declare (ignore env)) + (labels ((reconstruct (component) + (cond ((pattern-p component) (patternify component)) + ((and (listp component) (some #'pattern-p component)) + (cons 'list (mapcar #'patternify component))) + (t `',component))) + (patternify (subcomponent) + (if (pattern-p subcomponent) + `(make-pattern ',(pattern-pieces subcomponent)) + `',subcomponent))) + (values `(intern-pathname + ,(if (typep pn 'logical-pathname) + `(find-logical-host ',(logical-host-name (%pathname-host pn))) + '*physical-host*) + ,(reconstruct (%pathname-device pn)) + ,(reconstruct (%pathname-directory pn)) + ,(reconstruct (%pathname-name pn)) + ,(reconstruct (%pathname-type pn)) + ,(reconstruct (%pathname-version pn)))))) diff --git a/src/code/target-random.lisp b/src/code/target-random.lisp index 4988bd049e..36cda367fa 100644 --- a/src/code/target-random.lisp +++ b/src/code/target-random.lisp @@ -275,11 +275,10 @@ http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html (ash y -1) (aref state (logand y 1))))) (values)) -#-sb-devel (declaim (start-block random %random-single-float %random-double-float random-chunk big-random-chunk)) -#-sb-fluid (declaim (inline random-chunk)) +(declaim (inline random-chunk)) #-x86 (defun random-chunk (state) (declare (type random-state state)) @@ -308,7 +307,7 @@ http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html (declare (type random-state state)) (sb-vm::random-mt19937 (random-state-state state))) -#-sb-fluid (declaim (inline big-random-chunk)) +(declaim (inline big-random-chunk)) (defun big-random-chunk (state) (declare (type random-state state)) (logior (ash (random-chunk state) 32) @@ -318,20 +317,25 @@ http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html ;;; float between 0.0 and 1.0 by clobbering the significand of 1.0 ;;; with random bits, then subtracting 1.0. This hides the fact that ;;; we have a hidden bit. -#-sb-fluid (declaim (inline %random-single-float %random-double-float)) +(declaim (inline %random-single-float %random-double-float)) (declaim (ftype (function ((single-float ($0f0)) random-state) (single-float $0f0)) %random-single-float)) (defun %random-single-float (arg state) (declare (type (single-float ($0f0)) arg) (type random-state state)) - (* arg - (- (make-single-float - (dpb (ash (random-chunk state) - (- sb-vm:single-float-digits n-random-chunk-bits)) - sb-vm:single-float-significand-byte - (single-float-bits $1.0))) - $1.0))) + (loop for candidate of-type single-float + = (* arg + (- (make-single-float + (dpb (ash (random-chunk state) + (- sb-vm:single-float-digits n-random-chunk-bits)) + sb-vm:single-float-significand-byte + (single-float-bits $1.0))) + $1.0)) + while (#+x86 eql ;; Can't use = due to 80-bit precision + #-x86 = + candidate arg) + finally (return candidate))) (declaim (ftype (function ((double-float ($0d0)) random-state) (double-float $0d0)) %random-double-float)) @@ -348,14 +352,17 @@ http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html (defun %random-double-float (arg state) (declare (type (double-float ($0d0)) arg) (type random-state state)) - (* arg - (- (sb-impl::make-double-float - (dpb (ash (random-chunk state) - (- sb-vm:double-float-digits n-random-chunk-bits 32)) - sb-vm:double-float-significand-byte - (sb-impl::double-float-high-bits $1d0)) - (random-chunk state)) - $1d0))) + (loop for candidate of-type double-float + = (* arg + (- (sb-impl::make-double-float + (dpb (ash (random-chunk state) + (- sb-vm:double-float-digits n-random-chunk-bits 32)) + sb-vm:double-float-significand-byte + (sb-impl::double-float-high-bits $1d0)) + (random-chunk state)) + $1d0)) + while (= candidate arg) + finally (return candidate))) ;;; using a faster inline VOP #+x86 @@ -363,15 +370,19 @@ http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html (declare (type (double-float ($0d0)) arg) (type random-state state)) (let ((state-vector (random-state-state state))) - (* arg - (- (sb-impl::make-double-float - (dpb (ash (sb-vm::random-mt19937 state-vector) - (- sb-vm:double-float-digits n-random-chunk-bits - sb-vm:n-word-bits)) - sb-vm:double-float-significand-byte - (sb-impl::double-float-high-bits $1d0)) - (sb-vm::random-mt19937 state-vector)) - $1d0)))) + (loop for candidate of-type double-float + = (* arg + (- (sb-impl::make-double-float + (dpb (ash (sb-vm::random-mt19937 state-vector) + (- sb-vm:double-float-digits n-random-chunk-bits + sb-vm:n-word-bits)) + sb-vm:double-float-significand-byte + (sb-impl::double-float-high-bits $1d0)) + (sb-vm::random-mt19937 state-vector)) + $1d0)) + ;; Can't use = due to 80-bit precision + while (eql candidate arg) + finally (return candidate)))) ;;;; random fixnums @@ -390,9 +401,9 @@ http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html ;;; as the speed gains due to needing fewer loop iterations are by far ;;; outweighted by the cost of the two divisions required (one to find ;;; the multiplier and one to bring the result into the correct range). -#-sb-fluid (declaim (inline %random-fixnum)) +(declaim (inline %random-fixnum)) (defun %random-fixnum (arg state) - (declare (type (integer 1 #.sb-xc:most-positive-fixnum) arg) + (declare (type (integer 1 #.most-positive-fixnum) arg) (type random-state state)) (if (= arg 1) 0 @@ -409,9 +420,9 @@ http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html (accept-reject-loop big-random-chunk)))))) (defun random (arg &optional (state *random-state*)) - #-sb-fluid (declare (inline %random-fixnum - %random-single-float %random-double-float - #+long-float %random-long-float)) + (declare (inline %random-fixnum + %random-single-float %random-double-float + #+long-float %random-long-float)) (declare (explicit-check)) (cond ((and (fixnump arg) (> arg 0)) diff --git a/src/code/target-signal-common.lisp b/src/code/target-signal-common.lisp index 291f63468c..d8603a19bd 100644 --- a/src/code/target-signal-common.lisp +++ b/src/code/target-signal-common.lisp @@ -41,7 +41,7 @@ (let (*unblock-deferrables-on-enabling-interrupts-p*) (unblock-deferrable-signals) (when (or *interrupt-pending* - #+sb-thruption *thruption-pending*) + #+sb-safepoint *thruption-pending*) (receive-pending-interrupt)) (funcall function)) (alien-funcall (extern-alien "block_deferrable_signals" @@ -50,10 +50,23 @@ (t (when (and enable-interrupts (or *interrupt-pending* - #+sb-thruption *thruption-pending*)) + #+sb-safepoint *thruption-pending*)) (receive-pending-interrupt)) (funcall function)))) +(defmacro pthread-sigmask (how new old) + `(let ((how ,how) (new ,new) (old ,old)) + (alien-funcall (extern-alien + #+sb-thread ,(or #+unix "pthread_sigmask" #-unix "sb_pthread_sigmask") + #-sb-thread ,(or #+netbsd "sb_sigprocmask" #-netbsd "sigprocmask") + (function void int system-area-pointer system-area-pointer)) + how + (cond ((system-area-pointer-p new) new) + (new (vector-sap new)) + (t (int-sap 0))) + (cond ((system-area-pointer-p old) old) + (old (vector-sap old)) + (t (int-sap 0)))))) (defun invoke-interruption (function) (without-interrupts @@ -69,16 +82,18 @@ (sb-thread::without-thread-waiting-for (:already-without-interrupts t) (allow-with-interrupts (nlx-protect (funcall function) - ;; We've been running with deferrables - ;; blocked in Lisp called by a C signal - ;; handler. If we return normally the sigmask - ;; in the interrupted context is restored. - ;; However, if we do an nlx the operating - ;; system will not restore it for us. - (when *unblock-deferrables-on-enabling-interrupts-p* - ;; This means that storms of interrupts - ;; doing an nlx can still run out of stack. - (unblock-deferrable-signals))) + ;; We've been running with blockable + ;; blocked in Lisp called by a C signal + ;; handler. If we return normally the sigmask + ;; in the interrupted context is restored. + ;; However, if we do an nlx the operating + ;; system will not restore it for us. + (when *unblock-deferrables-on-enabling-interrupts-p* + ;; This means that storms of interrupts + ;; doing an nlx can still run out of stack. + (pthread-sigmask SIG_UNBLOCK + (foreign-symbol-sap "blockable_sigset" t) + nil))) ;; The return value doesn't matter, just return 0 0)))))) @@ -86,4 +101,3 @@ "Convenience macro on top of INVOKE-INTERRUPTION." `(dx-flet ((interruption () ,@body)) (invoke-interruption #'interruption))) - diff --git a/src/code/target-signal.lisp b/src/code/target-signal.lisp index 419787f554..843d5ea19e 100644 --- a/src/code/target-signal.lisp +++ b/src/code/target-signal.lisp @@ -15,18 +15,37 @@ ;;; Send the signal SIGNAL to the process with process id PID. SIGNAL ;;; should be a valid signal number -#-sb-fluid (declaim (inline unix-kill)) +(declaim (inline unix-kill)) (define-alien-routine ("kill" unix-kill) int (pid int) (signal int)) ;;; Send the signal SIGNAL to the all the process in process group ;;; PGRP. SIGNAL should be a valid signal number -#-sb-fluid (declaim (inline unix-killpg)) +(declaim (inline unix-killpg)) (define-alien-routine ("killpg" unix-killpg) int (pgrp int) (signal int)) +;;; A macro, because OS-THREAD is a WORD which could cause boxing if passed +;;; to a function. +(defmacro pthread-kill (os-thread signal) + (declare (ignorable os-thread)) + ;; If no threads, pthread_kill() won't exist since we didn't link with -lpthread. + ;; And raise() - as we use it - can't fail, so just ignore the result. + ;; (The signal number is always SIGURG or SIGINT, and the process is obviously not dead) + ;; This isn't used on win32 so we don't need to change the symbol to sb_pthr_kill there. + #-sb-thread `(raise ,signal) + #+sb-thread + `(unless (= 0 (alien-funcall (extern-alien "pthread_kill" + (function int unsigned int)) + ,os-thread ,signal)) + (error "pthread_kill() failed"))) + +;;; raise() is defined to send the signal to pthread_self() if multithreaded. +(defmacro raise (signal) + `(alien-funcall (extern-alien "raise" (function int int)) ,signal)) + ;;; Reset the current set of masked signals (those being blocked from ;;; delivery). ;;; @@ -42,95 +61,44 @@ (with-alien ((%unblock-gc-signals (function void) :extern "unblock_gc_signals")) (alien-funcall %unblock-gc-signals) nil)) - -;;;; C routines that actually do all the work of establishing signal handlers -(define-alien-routine ("install_handler" install-handler) - unsigned-long - (signal int) - (handler unsigned-long) - (ohandler unsigned-long) - (synchronous boolean)) - -;;;; interface to enabling and disabling signal handlers - -;;; Note on the SYNCHRONOUS argument: On builds without pseudo-atomic, -;;; we have no way of knowing whether interrupted code was in an -;;; allocation sequence, and cannot delay signals until after -;;; allocation. Any signal that can occur asynchronously must be -;;; considered unsafe for immediate execution, and the invocation of its -;;; lisp handler will get delayed into a newly spawned signal handler -;;; thread. However, there are signals which we must handle -;;; immediately, because they occur synchonously (hence the boolean flag -;;; SYNCHRONOUS to this function), luckily implying that the signal -;;; happens only in specific places (illegal instructions, floating -;;; point instructions, certain system calls), hopefully ruling out the -;;; possibility that we would trigger it during allocation. - -(defun enable-interrupt (signal handler &key synchronous) - (declare (type (or function fixnum (member :default :ignore)) handler)) - (/show0 "enable-interrupt") - (flet ((run-handler (&rest args) - (declare (truly-dynamic-extent args)) - #-(or c-stack-is-control-stack sb-safepoint) ;; able to do that in interrupt_handle_now() - (unblock-gc-signals) - (in-interruption () - (apply handler args)))) - (dx-let ((ohandler (make-array 1 :initial-element nil))) - ;; Pin OHANDLER in case the backend heap-allocates it - (with-pinned-objects (#'run-handler ohandler) - ;; 0 and 1 probably coincide with SIG_DFL and SIG_IGN, but those - ;; constants are opaque. We use our own explicit translation - ;; of them in the C install_handler() argument and return convention. - (let ((result (install-handler - signal +;;;; interface to installing signal handlers + +(defun enable-interrupt (signal handler) + (declare (type (or function (member :default :ignore)) handler)) + (%install-handler signal handler) + ;; This used to return the previously installed handler, if any. + ;; It no longer does, but the old handler can be obtained via SAP-REF-LISPOBJ + ;; on 'lisp_sig_handlers'. The reason for not returning it is that the value was + ;; always a closure, and there's no easy/portable way to ask what function was + ;; really meant. And you can't use that closure to reinstall the old thing + ;; because it would install a new closure on the old closure which, though + ;; feasible, is definitely not what was intended. + nil) + +(defun %install-handler (signal handler) + ;; 0 and 1 should coincide with SIG_DFL and SIG_IGN, but in theory those values + ;; are opaque. We use our own explicit translation of 0 and 1 to them + ;; in the C install_handler() argument passing convention. + (with-alien ((%sigaction (function void int unsigned) :extern "install_handler")) + #+sb-safepoint + (alien-funcall %sigaction signal + (case handler + (:default 0) + (:ignore 1) + (t (sb-kernel:get-lisp-obj-address handler)))) + #-sb-safepoint + (flet ((run-handler (signo info-sap context-sap) + #-(or c-stack-is-control-stack sb-safepoint) ;; able to do that in interrupt_handle_now() + (unblock-gc-signals) + (in-interruption () (funcall handler signo info-sap context-sap)))) + (with-pinned-objects (#'run-handler) + (alien-funcall %sigaction signal (case handler (:default 0) (:ignore 1) - (t (sb-kernel:get-lisp-obj-address #'run-handler))) - ;; VECTOR-SAP does not work on SIMPLE-VECTOR - (sb-kernel:get-lisp-obj-address ohandler) - synchronous))) - (cond ((= result 0) :default) - ((= result 1) :ignore) - (t - ;; The value in OHANDLER, if a lisp function, is not the right thing to - ;; return, but we do it anyway. It's always the RUN-HANDLER closure - ;; instead of what was supplied before as HANDLER. We can only hope that - ;; users don't pass the result of ENABLE-INTERRUPT as the argument to - ;; another call, as that would create a chain of closures. - ;; I wonder if the fact that we at some point decided that we need - ;; to allow signal nesting to about 1024 levels deep had anything - ;; to do with this bug? - (the (or function fixnum) (aref ohandler 0))))))))) - -(defun default-interrupt (signal) - (enable-interrupt signal :default)) - -(defun ignore-interrupt (signal) - (enable-interrupt signal :ignore)) - -;;;; Support for signal handlers which aren't. -;;;; -;;;; On safepoint builds, user-defined Lisp signal handlers do not run -;;;; in the handler for their signal, because we have no pseudo atomic -;;;; mechanism to prevent handlers from hitting during allocation. -;;;; Rather, the signal spawns off a fresh native thread, which calls -;;;; into lisp with a fake context through this callback: - -#+sb-safepoint-strictly -(defun signal-handler-callback (run-handler signal args) - ;; SAPs are dx allocated, close over the values, not the SAPs. - (let ((thread (without-gcing - ;; Hold off GCing until *current-thread* is set up - (setf sb-thread:*current-thread* - (sb-thread::make-signal-handling-thread :name "signal handler" - :signal-number signal)))) - (info (sap-ref-sap args 0)) - (context (sap-ref-sap args sb-vm:n-word-bytes))) - (dx-flet ((callback () - (funcall run-handler signal info context))) - (sb-thread::new-lisp-thread-trampoline thread nil #'callback nil)))) + (t (sb-kernel:get-lisp-obj-address #'run-handler))))))) + nil) ;;;; default LISP signal handlers @@ -167,7 +135,7 @@ (flet ((interrupt-it () ;; SB-KERNEL:*CURRENT-INTERNAL-ERROR-CONTEXT* will ;; either be bound in this thread by SIGINT-HANDLER or - ;; in the target thread by SIGPIPE-HANDLER. + ;; in the target thread by SIGURG-HANDLER. (with-alien ((context (* os-context-t) sb-kernel:*current-internal-error-context*)) (with-interrupts @@ -182,9 +150,9 @@ (let ((target (sb-thread::foreground-thread))) ;; Note that INTERRUPT-THREAD on *CURRENT-THREAD* doesn't actually ;; interrupt right away, because deferrables are blocked. Rather, - ;; the kernel would arrange for the SIGPIPE to hit when the SIGINT + ;; the kernel would arrange for the SIGURG to hit when the SIGINT ;; handler is done. However, on safepoint builds, we don't use - ;; SIGPIPE and lack an appropriate mechanism to handle pending + ;; SIGURG and lack an appropriate mechanism to handle pending ;; thruptions upon exit from signal handlers (and this situation is ;; unlike WITHOUT-INTERRUPTS, which handles pending interrupts ;; explicitly at the end). Only as long as safepoint builds pretend @@ -197,23 +165,24 @@ (sb-thread:interrupt-thread (sb-thread::foreground-thread) #'interrupt-it))) -#-sb-wtimer (defun sigalrm-handler (signal info context) (declare (ignore signal info context)) - (declare (type system-area-pointer context)) + ;; Safepoint invokes the "signal handler" without a signal context, + ;; since it's not a signal handler. + #-sb-safepoint (declare (type system-area-pointer context)) (sb-impl::run-expired-timers)) (defun sigterm-handler (signal code context) (declare (ignore signal code context)) (exit)) -#-sb-thruption -;;; SIGPIPE is not used in SBCL for its original purpose, instead it's +#-sb-safepoint +;;; SIGURG is not used in SBCL for its original purpose, instead it's ;;; for signalling a thread that it should look at its interruption ;;; queue. The handler (RUN_INTERRUPTION) just returns if there is -;;; nothing to do so it's safe to receive spurious SIGPIPEs coming +;;; nothing to do so it's safe to receive spurious SIGURGs coming ;;; from the kernel. -(defun sigpipe-handler (signal code sb-kernel:*current-internal-error-context*) +(defun sigurg-handler (signal code sb-kernel:*current-internal-error-context*) (declare (ignore signal code)) (sb-thread::run-interruption)) @@ -224,26 +193,37 @@ (defun sb-kernel:signal-cold-init-or-reinit () "Enable all the default signals that Lisp knows how to deal with." - (enable-interrupt sigint #'sigint-handler) - (enable-interrupt sigterm #'sigterm-handler) - (enable-interrupt sigill #'sigill-handler :synchronous t) - #-(or linux android haiku) - (enable-interrupt sigemt #'sigemt-handler) - (enable-interrupt sigfpe #'sb-vm:sigfpe-handler :synchronous t) + (%install-handler sigint #'sigint-handler) + (%install-handler sigterm #'sigterm-handler) + (%install-handler sigill #'sigill-handler) + #-(or linux android haiku) (%install-handler sigemt #'sigemt-handler) + (%install-handler sigfpe #'sb-vm:sigfpe-handler) (if (/= (extern-alien "install_sig_memory_fault_handler" int) 0) - (enable-interrupt sigbus #'sigbus-handler :synchronous t) + (%install-handler sigbus #'sigbus-handler) (write-string ";;;; SIGBUS handler not installed " sb-sys:*stderr*)) - #-(or linux android) - (enable-interrupt sigsys #'sigsys-handler :synchronous t) - #-sb-wtimer - (enable-interrupt sigalrm #'sigalrm-handler) - #-sb-thruption - (enable-interrupt sigpipe #'sigpipe-handler) - (enable-interrupt sigchld #'sigchld-handler) - #+hpux (ignore-interrupt sigxcpu) - #-sb-safepoint (unblock-gc-signals) - (unblock-deferrable-signals) + #-(or linux android) (%install-handler sigsys #'sigsys-handler) + (%install-handler sigalrm #'sigalrm-handler) + #-sb-safepoint (%install-handler sigurg #'sigurg-handler) + (%install-handler sigchld #'sigchld-handler) + ;; Don't want to silently quit on broken pipes. + (%install-handler sigpipe :ignore) + ;; Undo the effect of block_blockable_signals() from right at the top of sbcl_main() + ;; and (if pertinent) blocking stop-for-GC somewhere thereafter. + (dx-let ((mask (make-array sizeof-sigset_t :element-type '(unsigned-byte 8) + :initial-element 0))) + (with-pinned-objects (mask) + #+(and unix sb-safepoint) + ;; For safepoints we unblock SIGURG (to receive interrupt-thread), + ;; SIGPROF (because why not), and SIGPIPE (because it's synchronous + ;; and not in deferrables). Everything else stays blocked. + (with-alien ((sigaddset (function int system-area-pointer int) :extern "sigaddset")) + (alien-funcall sigaddset (vector-sap mask) sigurg) + (alien-funcall sigaddset (vector-sap mask) sigprof) + (alien-funcall sigaddset (vector-sap mask) sigpipe) + (pthread-sigmask SIG_UNBLOCK mask nil)) + ;; The normal thing is to start with no signals blocked + #-(and unix sb-safepoint) (pthread-sigmask SIG_SETMASK mask nil))) (values)) ;;;; etc. @@ -251,3 +231,28 @@ ;;; extract si_code from siginfo_t (define-alien-routine ("siginfo_code" siginfo-code) int (info system-area-pointer)) + +;;;; On safepoint builds, user-defined Lisp signal handlers all run +;;;; in one thread that waits for signals. +;;;; Keyboard interrupts work by forwarding SIGINT from that thread +;;;; to the foreground thread via INTERRUPT-THREAD, which is the only +;;;; quasi-asynchronous signal allowed to run in arbitrary threads. +#+sb-safepoint +(progn +(define-load-time-global *sighandler-thread* nil) +(declaim (type (or sb-thread:thread null) *sighandler-thread*)) +(defun signal-handler-loop () + ;; We could potentially use sigwaitinfo() to obtain more information about the signal, + ;; but I don't see the point. This is just minimal functionality. + (with-alien ((sigwait (function int system-area-pointer (* int)) :extern "sigwait") + (mask (array (unsigned 8) #.sizeof-sigset_t)) + (num int)) + (pthread-sigmask SIG_BLOCK nil (alien-sap mask)) ; Retrieve current mask + (loop (let ((result (alien-funcall sigwait (alien-sap mask) (addr num)))) + (when (and (= result 0) (= num sigterm) (not *sighandler-thread*)) + (return)) + (when (and (= result 0) (> num 0)) + (let ((fun (sap-ref-lispobj (foreign-symbol-sap "lisp_sig_handlers" t) + (ash num sb-vm:word-shift)))) + (when (functionp fun) + (funcall fun num nil nil))))))))) diff --git a/src/code/target-stream.lisp b/src/code/target-stream.lisp index ded4ced1d2..0706eadf2f 100644 --- a/src/code/target-stream.lisp +++ b/src/code/target-stream.lisp @@ -68,14 +68,11 @@ ;;; unread-char, read-byte, listen here that was removed because these ;;; functions are redefined when simple-streams are loaded. -#-sb-fluid (declaim (inline ansi-stream-peek-char)) +(declaim (inline ansi-stream-peek-char)) (defun ansi-stream-peek-char (peek-type stream eof-error-p eof-value recursive-p) (cond ((typep stream 'echo-stream) - (echo-misc stream - :peek-char - peek-type - (list eof-error-p eof-value))) + (echo-stream-peek-char stream peek-type eof-error-p eof-value)) (t (generalized-peeking-mechanism peek-type eof-value char @@ -89,11 +86,15 @@ eof-value recursive-p) (declare (type (or character boolean) peek-type) (explicit-check)) - (let ((stream (in-stream-from-designator stream))) - (if (ansi-stream-p stream) + (stream-api-dispatch (stream (in-stream-from-designator stream)) + :simple (let ((char (s-%peek-char stream peek-type eof-error-p eof-value))) + ;; simple-streams -%PEEK-CHAR always ignored RECURSIVE-P + ;; so I removed it from the call. + (if (eq char eof-value) char (the character char))) + :native (ansi-stream-peek-char peek-type stream eof-error-p eof-value recursive-p) - ;; by elimination, must be Gray streams FUNDAMENTAL-STREAM + :gray (let ((char (generalized-peeking-mechanism peek-type :eof char @@ -108,18 +109,16 @@ (eof-or-lose stream eof-error-p eof-value)))) (if (eq char eof-value) char - (the character char)))))) + (the character char))))) -(defun echo-misc (stream operation &optional arg1 arg2) +(defun echo-misc (stream operation arg1) (let* ((in (two-way-stream-input-stream stream)) (out (two-way-stream-output-stream stream))) - (case operation + (stream-misc-case (operation) (:listen (if (ansi-stream-p in) - (or (/= (the fixnum (ansi-stream-in-index in)) - +ansi-stream-in-buffer-length+) - (funcall (ansi-stream-misc in) in :listen)) - (stream-misc-dispatch in :listen))) + (%ansi-stream-listen in) + (stream-misc-dispatch in operation arg1))) (:unread (setf (echo-stream-unread-stuff stream) t) (unread-char arg1 in)) (:element-type @@ -135,9 +134,17 @@ in-mode))) (:close (set-closed-flame stream)) - (:peek-char - ;; For the special case of peeking into an echo-stream - ;; arg1 is PEEK-TYPE, arg2 is (EOF-ERROR-P EOF-VALUE) + (t + (or (if (ansi-stream-p in) + (call-ansi-stream-misc in operation arg1) + (stream-misc-dispatch in operation arg1)) + (if (ansi-stream-p out) + (call-ansi-stream-misc out operation arg1) + (stream-misc-dispatch out operation arg1))))))) + +(defun echo-stream-peek-char (stream peek-type eof-error-p eof-value) + (let* ((in (two-way-stream-input-stream stream)) + (out (two-way-stream-output-stream stream))) ;; returns peeked-char, eof-value, or errors end-of-file ;; ;; Note: This code could be moved into PEEK-CHAR if desired. @@ -163,17 +170,33 @@ (setf unread-p (echo-stream-unread-stuff stream)) (setf (echo-stream-unread-stuff stream) nil)) (setf initial-peek-p nil) - (read-char in (first arg2) :eof))) + (read-char in eof-error-p :eof))) (generalized-peeking-mechanism - arg1 (second arg2) char + peek-type eof-value char (infn) :eof (unread-char char in) - (outfn char))))) - (t - (or (if (ansi-stream-p in) - (funcall (ansi-stream-misc in) in operation arg1 arg2) - (stream-misc-dispatch in operation arg1 arg2)) - (if (ansi-stream-p out) - (funcall (ansi-stream-misc out) out operation arg1 arg2) - (stream-misc-dispatch out operation arg1 arg2))))))) + (outfn char)))))) + +;;; Stop wasting space with unnecessarily preserved inline definitions. +;;; ANSI-STREAM-LISTEN, %ANSI-STREAM-LISTEN, ANSI-STREAM-CLEAR-INPUT +;;; are needed for sb-simple-streams. +;;; Maybe everything else can just get dropped entirely, the symbol and its +;;; function, instead of just the inline sexpr. +(dolist (name '(!ansi-stream-ftell + ansi-stream-read-line ansi-stream-read-char + ansi-stream-unread-char + ansi-stream-read-char-no-hang + ansi-stream-read-byte read-n-bytes + read-char unread-char read-byte + read-sequence/read-function write-sequence/write-function + stream-element-mode)) + (clear-info :function :inlinep name) + (clear-info :function :inlining-data name)) +;;; Can all the ANSI- function names be removed now? Maybe? +(push '("SB-IMPL" ansi-stream-peek-char ansi-stream-unread-char) + *!removable-symbols*) +;;; These two wants to get invoked by simple-streams but would get tree-shaken out +;;; were they not externalized. +(export '(sb-impl::in-stream-from-designator sb-impl::eof-or-lose) + 'sb-impl) diff --git a/src/code/target-sxhash.lisp b/src/code/target-sxhash.lisp index 3eefbc1716..e26a3072e1 100644 --- a/src/code/target-sxhash.lisp +++ b/src/code/target-sxhash.lisp @@ -24,23 +24,18 @@ ;; The result is guaranteed to be a positive fixnum. (declaim (inline address-based-counter-val)) (defun address-based-counter-val () - #+(and (not sb-thread) cheneygc) - (ash (sap-int (dynamic-space-free-pointer)) (- (1+ sb-vm:word-shift))) - ;; dynamic-space-free-pointer increments only when a page is full. - ;; Using boxed_region directly is finer-grained. - #+(and (not sb-thread) gencgc) - (progn #+(or arm arm64 riscv x86 x86-64 ppc ppc64) ; new way: alloc_region is in static space - (ash (sb-sys:sap-ref-word (sb-sys:int-sap sb-vm:static-space-start) - (* 2 sb-vm:n-word-bytes)) - (- (1+ sb-vm:word-shift))) - #-(or arm arm64 riscv x86 x86-64 ppc ppc64) ; old way: alloc_region is in C data - (ash (extern-alien "gc_alloc_region" unsigned-long) - (- (1+ sb-vm:word-shift)))) - ;; threads imply gencgc. use the per-thread alloc region pointer - #+sb-thread - (ash (sap-int (sb-vm::current-thread-offset-sap - #.sb-vm::thread-alloc-region-slot)) - (- (1+ sb-vm:word-shift)))) + (let ((word + ;; threads imply gencgc. use the per-thread alloc region pointer + #+sb-thread + (sap-int (sb-vm::current-thread-offset-sap sb-vm::thread-mixed-tlab-slot)) + #+(and (not sb-thread) cheneygc) + (sap-int (dynamic-space-free-pointer)) + ;; dynamic-space-free-pointer increments only when a page is full. + ;; Using mixed_region directly is finer-grained. + #+(and (not sb-thread) gencgc) + (sb-sys:sap-ref-word (sb-sys:int-sap sb-vm::mixed-region) 0))) + ;; counter should increase by 1 for each cons cell allocated + (ash word (- (1+ sb-vm:word-shift))))) ;;; Return some bits that are dependent on the next address that will be ;;; allocated, mixed with the previous state (in case addresses get recycled). @@ -95,11 +90,12 @@ ;;; that's what I'm going with. ;;; (defun %instance-sxhash (instance) - ;; to avoid consing in fmix - (declare (inline #+64-bit murmur3-fmix64 #-64-bit murmur3-fmix32)) - ;; FIXME: this special case might be removable, but there are callers - ;; of sxhash on layouts due to the expansion of TYPECASE. - (when (typep instance 'layout) + ;; LAYOUT must not acquire an extra slot for the stable hash, + ;; because the bitmap length is derived from the instance length. + ;; It would probably be simple to eliminate this as a special case + ;; by ensuring that instances of LAYOUT commence life with a trailing + ;; hash slot and the SB-VM:HASH-SLOT-PRESENT-FLAG set. + (when (typep instance 'sb-vm:layout) ;; This might be wrong if the clos-hash was clobbered to 0 (return-from %instance-sxhash (layout-clos-hash instance))) ;; Non-simple cases: no hash slot, and either unhashed or hashed-not-moved. @@ -115,8 +111,7 @@ #+sb-thread (%primitive sb-vm::set-instance-hashed instance)) (get-lisp-obj-address instance)))) ;; perturb the address - (logand (#+64-bit murmur3-fmix64 #-64-bit murmur3-fmix32 addr) - sb-xc:most-positive-fixnum))) + (logand (murmur3-fmix-word addr) most-positive-fixnum))) (declaim (inline instance-sxhash)) (defun instance-sxhash (instance) @@ -124,14 +119,9 @@ (instance-header-word (truly-the instance instance))) ;; easy case: 1 word beyond the apparent length is a word added ;; by GC (which may have resized the object, but we don't need to know). - (%instance-ref instance (%instance-length instance)) + (truly-the hash-code (%instance-ref instance (%instance-length instance))) (%instance-sxhash instance))) -;;; Object must be pinned to use this. -(defmacro fsc-instance-trailer-hash (fin) - `(sap-ref-32 (int-sap (get-lisp-obj-address ,fin)) - (- (+ (* 5 sb-vm:n-word-bytes) 4) sb-vm:fun-pointer-lowtag))) - ;;; Return a pseudorandom number that was assigned on allocation. ;;; FIN is a STANDARD-FUNCALLABLE-INSTANCE but we don't care to type-check it. ;;; You might rightly wonder - for what reason do we require good hash codes for @@ -140,15 +130,18 @@ ;;; due to a change in the definition of a method-combination. (declaim (inline fsc-instance-hash)) (defun fsc-instance-hash (fin) - (cond #+x86-64 - ((= (logand (function-header-word (truly-the function fin)) #xFF00) - (ash 5 sb-vm:n-widetag-bits)) ; KLUDGE: 5 data words implies 2 raw words - ;; get the upper 4 bytes of wordindex 5 - (with-pinned-objects (fin) (fsc-instance-trailer-hash fin))) - (t - (truly-the hash-code - (sb-pcl::standard-funcallable-instance-hash-code - (truly-the sb-pcl::standard-funcallable-instance fin)))))) + (truly-the hash-code + #+compact-instance-header + (with-pinned-objects (fin) + (let ((hash (sb-vm::compact-fsc-instance-hash + (truly-the sb-pcl::standard-funcallable-instance fin)))) + ;; There is not more entropy imparted by doing a mix step on a value that had + ;; at most 32 bits of randomness, but this makes more of the bits vary. + ;; Some uses of the hash might expect the high bits to have randomness in them. + (logand (murmur-fmix-word hash) most-positive-fixnum))) + #-compact-instance-header + (sb-pcl::standard-funcallable-instance-hash-code + (truly-the sb-pcl::standard-funcallable-instance fin)))) (declaim (inline integer-sxhash)) (defun integer-sxhash (x) @@ -156,6 +149,7 @@ (defun number-sxhash (x) (declare (optimize (sb-c:verify-arg-count 0) speed)) + (declare (explicit-check)) (labels ((hash-ratio (x) (let ((result 127810327)) (declare (type fixnum result)) @@ -193,9 +187,102 @@ (clear-info :function :inlinep 'integer-sxhash) +(macrolet ((with-hash ((var seed) &body body) + `(let ((,var (word-mix 410823708 ,seed))) + (declare (type word ,var)) + ,@body)) + (mix-chunk (word) + `(setq result (word-mix ,word result))) + (mix-remaining (word) + ;; In the current implementation of bit operations, they may leave random + ;; bits in an ignored suffix of bits, hence the need for a masking operation. + ;; (See examples above DEF-BIT-ARRAY-OP) + ;; N-BITS-REMAINING is between 1 inclusive and N-WORD-BITS exclusive. + ;; Produce a mask of 1s spanning the remaining bits, which would be + ;; (- n-word-bits n-bits-remaining) and logically AND it with word. + ;; The mask is equal mod N-WORD-BITS to (- n-bits-remaining). + ;; SHIFT-TOWARDS-START clips the shift count explicitly if the CPU doesn't. + `(mix-chunk (logand (shift-towards-start most-positive-word + (- n-bits-remaining)) + ,word)))) +(defun %sxhash-simple-bit-vector (x) + (with-hash (result (length (truly-the simple-bit-vector x))) + (multiple-value-bind (n-full-words n-bits-remaining) (floor (length x) sb-vm:n-word-bits) + (dotimes (i n-full-words) (mix-chunk (%vector-raw-bits x i))) + (when (plusp n-bits-remaining) + (mix-remaining (%vector-raw-bits x n-full-words)))) + (logand result sb-xc:most-positive-fixnum))) +(defun %sxhash-bit-vector (bit-vector) + (with-array-data ((x bit-vector) (start) (end) :check-fill-pointer t) + (multiple-value-bind (start-word start-bit) (floor start sb-vm:n-word-bits) + (cond ((= start-bit 0) ; relevant bits are word-aligned + (multiple-value-bind (end-word n-bits-remaining) (floor end sb-vm:n-word-bits) + (with-hash (result (- end start)) + (do ((i start-word (1+ i))) + ((>= i end-word)) + (mix-chunk (%vector-raw-bits x i))) + (when (plusp n-bits-remaining) + (mix-remaining (%vector-raw-bits x end-word))) + (logand result sb-xc:most-positive-fixnum)))) + #+(or arm64 x86 x86-64) + ((not (logtest start-bit 7)) ; relevant bits are byte-aligned + ;; The case is probably ok on all little-endian CPUs that permit + ;; unaligned loads but I didn't try it on them all. + (with-pinned-objects (x) + (let ((byte-offset (ash start -3)) + (n-bits-remaining (- end start)) + (sap (vector-sap x))) + (with-hash (result (- end start)) + (loop (unless (>= n-bits-remaining sb-vm:n-word-bits) (return)) + #+nil + (format t "~& mixing middle word: [~a]~%" + (nreverse (format nil "~64,'0b" (sap-ref-word sap byte-offset)))) + ;; Since we have at least sb-vm:n-word-bits more to go, + ;; and the non-simple vector fits within its backing vector, + ;; it must be OK to read an entire word from that vector. + (mix-chunk (sap-ref-word sap byte-offset)) + (incf byte-offset sb-vm:n-word-bytes) + (decf n-bits-remaining sb-vm:n-word-bits)) + (when (plusp n-bits-remaining) + ;; Perform exactly one more word-sized load rather than N-BYTES-REMAINING + ;; byte-sized loads + shifts to reconstruct the final word. This load puts + ;; the final relevant byte into the MSB of the loaded word and is + ;; guaranteed neither to overrun nor underrun the backing vector. + ;; It might grab some bytes from the vector-length word as an edge case. + ;; Consider e.g. a non-simple vector of 8 bits with displaced-index-offset 16 + ;; into an underlying vector of 30 bits. + (let* ((n-bytes-remaining (ceiling n-bits-remaining sb-vm:n-byte-bits)) + ;; Compute how many bytes we didn't actually want to read. It could + ;; be 0 if we want all remaining bytes (but presumably not all bits) + (shift-out (- sb-vm:n-word-bytes n-bytes-remaining)) + (word (ash (sap-ref-word + sap + (+ byte-offset n-bytes-remaining (- sb-vm:n-word-bytes))) + (* -8 shift-out)))) + #+nil (format t "~& mixing final word: [~a]~%" + (nreverse (format nil "~64,'0b" word))) + (mix-remaining word))) + (logand result sb-xc:most-positive-fixnum))))) + (t ; not aligned in a way that this can deal with. + ;; Fallback to the simple algorithm using a copy. + ;; Nobody has complained in 17 years, ever since git rev a3ab89c1db when this + ;; was corrected to hash more than 4 bits. Prior to that, the code was plain wrong, + ;; violating constraint 1 in the spec for SXHASH. + ;; If we do manage to improve this not to cons a new vector, the test + ;; in hash.pure.lisp should be made more rigorous as well. + (%sxhash-simple-bit-vector (copy-seq bit-vector)))))))) + ;;; To avoid "note: Return type not fixed values ..." +;;; PATHNAME-SXHASH can't easily be placed in pathname.lisp because that file +;;; depends on LOGICAL-HOST but the definition of LOGICAL-HOST is complicated +;;; and seems to belong where it is, in target-pathname.lisp, though maybe not. (declaim (ftype (sfunction (t) hash-code) pathname-sxhash)) +(defun sap-hash (x) + ;; toss in a LOGNOT so that (the word a) and (int-sap a) hash differently + (let ((w (logand (lognot (sap-int x)) most-positive-word))) + (logand (murmur3-fmix-word w) most-positive-fixnum))) + (defun sxhash (x) ;; profiling SXHASH is hard, but we might as well try to make it go ;; fast, in case it is the bottleneck somewhere. -- CSR, 2003-03-14 @@ -213,8 +300,7 @@ ;; so we should pick off SYMBOL sooner than INSTANCE as well. ;; * INSTANCE (except for PATHNAME) doesn't recurse anyway - in fact ;; it is particularly dumb (by design), so performing that test later - ;; doesn't incur much of a penalty. And our users probably know that - ;; SXHASH on instance doesn't really do anything. + ;; doesn't incur much of a penalty. ;; Anyway, afaiu, the code below was previously ordered by gut feeling ;; rather than than actual measurement, so having any rationale for ordering ;; is better than having no rationale. And as a further comment observes, @@ -245,24 +331,9 @@ (instance-sxhash x))) (array (typecase x - ;; If we could do something smart for widetag-based jump tables, - ;; then we wouldn't have to think so much about whether to test - ;; STRING and BIT-VECTOR inside or outside of the ARRAY stanza. - ;; The code is structured now to narrow down in broad strokes with - ;; the outer typecase, and then refines the type further. - ;; We could equally well move the STRING test into the outer - ;; typecase, but that would impart one more test in front of - ;; all remaining stanzas. (string (%sxhash-string x)) - (simple-bit-vector (sxhash x)) ; through DEFTRANSFORM - (bit-vector - ;; FIXME: It must surely be possible to do better - ;; than this. The problem is that a non-SIMPLE - ;; BIT-VECTOR could be displaced to another, with a - ;; non-zero offset -- so that significantly more - ;; work needs to be done using the %VECTOR-RAW-BITS - ;; approach. This will probably do for now. - (sxhash-recurse (copy-seq x) depthoid)) + (bit-vector (%sxhash-bit-vector x)) + ;; Would it be legal to mix in the widetag? (t (logxor 191020317 (sxhash (array-rank x)))))) ;; general, inefficient case of NUMBER ;; There's a spurious FIXNUMP test here, as we've already picked it off. @@ -274,72 +345,91 @@ (logxor 72185131 (sxhash (char-code x)))) ; through DEFTRANSFORM (funcallable-instance - (if (layout-for-pcl-obj-p (%fun-layout x)) + (if (logtest (layout-flags (%fun-layout x)) +pcl-object-layout-flag+) ;; We have a hash code, so might as well use it. (fsc-instance-hash x) ;; funcallable structure, not funcallable-standard-object 9550684)) + (system-area-pointer (sap-hash x)) (t 42)))) (sxhash-recurse x +max-hash-depthoid+))) ;;;; the PSXHASH function -;;; To avoid "note: Return type not fixed values ..." -(declaim (ftype (sfunction (number) hash-code) number-psxhash)) - ;;; like SXHASH, but for EQUALP hashing instead of EQUAL hashing +(macrolet ((hash-float (type key) + ;; Floats that represent integers must hash as the integer would. + (let ((lo (symbol-value (package-symbolicate :sb-kernel 'most-negative-fixnum- type))) + (hi (symbol-value (package-symbolicate :sb-kernel 'most-positive-fixnum- type))) + (bignum-hash (symbolicate 'sxhash-bignum- type))) + `(let ((key ,key)) + (declare (inline float-infinity-p)) + (cond (;; This clause allows FIXNUM-sized integer + ;; values to be handled without consing. + (<= ,lo key ,hi) + (multiple-value-bind (q r) (truly-the fixnum (floor (the (,type ,lo ,hi) key))) + (if (zerop (the ,type r)) + (sxhash q) + (sxhash (coerce key 'double-float))))) + ((float-infinity-p key) + ;; {single,double}-float infinities are EQUALP + (if (minusp key) + (sxhash sb-ext:single-float-negative-infinity) + (sxhash sb-ext:single-float-positive-infinity))) + #+64-bit + (t + (,bignum-hash key)) + #-64-bit + (t + ,(if (eq type 'double-float) + `(multiple-value-bind (q r) (floor key) + (if (zerop (the ,type r)) + (sxhash q) + (sxhash key))) + `(,bignum-hash key)))))))) (defun psxhash (key) (declare (optimize speed)) (labels - ((array-psxhash (key depthoid) - (declare (type array key)) - (declare (type (integer 0 #.+max-hash-depthoid+) depthoid)) - (if (vectorp key) - ;; VECTORs have to be treated specially because ANSI specifies - ;; that we must respect fill pointers. - (let ((result 572539)) - (declare (type hash-code result)) - (mixf result (length key)) - (when (plusp depthoid) - (decf depthoid) - (macrolet ((traverse (element-hasher) - `(dotimes (i (length key)) - (declare (type index i)) - (mixf result - ,(ecase element-hasher - (character `(char-code (char-upcase (aref key i)))) - (integer `(sxhash (aref key i))) - (number `(number-psxhash (aref key i))) - (:default `(%psxhash (aref key i) depthoid))))))) - (typecase key - ;; There are two effects from the typecase: - ;; 1. using a specialized array reffer - ;; 2. dispatching to a specific hash function - (simple-base-string (traverse character)) ; both effects - ((simple-array character (*)) (traverse character)) ; "" - (simple-vector (traverse :default)) ; effect #1 only - ((simple-array (unsigned-byte 8) (*)) (traverse integer)) ; both effects - ;; this seems arbitrary. I think (simple-array word (*)) is more popular! - ((simple-array fixnum (*)) (traverse integer)) ; both effects - (string (traverse character)) ; effect #2 only - ((vector t) (traverse :default)) ; weed out non-simple T vector from final case - (t (traverse number))))) ; all else - effect #2 only - result) - ;; Any other array can be hashed by working with its underlying - ;; one-dimensional physical representation. - (let ((result 60828)) - (declare (type fixnum result)) - (dotimes (i (array-rank key)) - (mixf result (%array-dimension key i))) - (when (plusp depthoid) - (decf depthoid) - (with-array-data ((key key) (start) (end)) - (let ((getter (truly-the function (svref %%data-vector-reffers%% - (%other-pointer-widetag key))))) - (loop for i from start below end - do (mixf result (%psxhash (funcall getter key i) depthoid)))))) - result))) - (structure-object-psxhash (key depthoid) + ((data-vector-hash (data start end depthoid) + (declare (optimize (sb-c:insert-array-bounds-checks 0))) + (let ((result 572539)) + (declare (type hash-code result)) + (when (plusp depthoid) + (decf depthoid) + (macrolet ((traverse (et &aux (elt '(aref data i))) + `(let ((data (truly-the (simple-array ,et (*)) data))) + (loop for i fixnum from (truly-the fixnum start) + below (truly-the fixnum end) + do (mixf result + ,(case et + ((t) `(%psxhash ,elt depthoid)) + ((base-char character) + `(char-code (char-upcase ,elt))) + (single-float `(sfloat-psxhash ,elt)) + (double-float `(dfloat-psxhash ,elt)) + ;; the remaining types are integers and complex numbers. + ;; COMPLEX will cons here, as will word-sized + ;; integers. Nothing else should though. + (t `(sxhash ,elt)))))))) ; xformed + (typecase data + ;; There are two effects of this typecase: + ;; 1. using an optimized array reader + ;; 2. dispatching to a type-specific hash function + (simple-vector (traverse t)) ; effect #1 only + (simple-base-string (traverse base-char)) ; both effects + #+sb-unicode (simple-character-string (traverse character)) ; both + ((simple-array single-float (*)) (traverse single-float)) ; and so on + ((simple-array double-float (*)) (traverse double-float)) + ;; (SIMPLE-ARRAY WORD (*)) would be helpful to avoid consing, + ;; but there is no SXHASH transform on word-sized integers. + ;; It might be possible to do something involving WORD-MIX. + ((simple-array fixnum (*)) (traverse fixnum)) + (t + (let ((getter (svref %%data-vector-reffers%% (%other-pointer-widetag data)))) + (loop for i fixnum from (truly-the fixnum start) below (truly-the fixnum end) + do (mixf result (number-psxhash (funcall getter data i))))))))) + result)) + (structure-object-psxhash (key depthoid) ;; Compute a PSXHASH for KEY. Salient points: ;; * It's not enough to use the bitmap to figure out how to mix in raw slots. ;; The floating-point types all need special treatment. And we want to avoid @@ -371,7 +461,7 @@ ;; Access as unsigned. +X and -X hash differently because ;; of 2's complement, so disregarding the sign bit is fine. (mixf result (logand (%raw-instance-ref/word key i) - sb-xc:most-positive-fixnum))) + most-positive-fixnum))) (,(1+index-of 'single-float) ,(mix-float '(%raw-instance-ref/single key i) $0f0)) (,(1+index-of 'double-float) @@ -384,15 +474,16 @@ (let ((cplx (%raw-instance-ref/complex-double key i))) ,(mix-float '(realpart cplx) $0d0) ,(mix-float '(imagpart cplx) $0d0))))))) - (let* ((layout (%instance-layout key)) - (result (layout-clos-hash layout))) + (let* ((wrapper (%instance-wrapper key)) + (result (wrapper-clos-hash wrapper))) (declare (type fixnum result)) (when (plusp depthoid) (let ((max-iterations depthoid) - (depthoid (1- depthoid))) + (depthoid (1- depthoid)) + (dd (wrapper-dd wrapper))) (declare (index max-iterations)) - (if (/= (layout-bitmap layout) +layout-all-tagged+) - (let ((slots (dd-slots (layout-info layout)))) + (if (/= (sb-kernel::dd-bitmap dd) +layout-all-tagged+) + (let ((slots (dd-slots dd))) (loop (unless slots (return)) (let* ((slot (pop slots)) (rsd-index+1 (rsd-index+1 slot)) @@ -413,97 +504,77 @@ (incf i) (if (zerop (decf max-iterations)) (return))))))) result))) - (%psxhash (key depthoid) - (typecase key - (array (array-psxhash key depthoid)) - (structure-object - (cond ((hash-table-p key) - ;; This is a purposely not very strong hash so that it does not make any - ;; distinctions that EQUALP does not make. Computing a hash of the k/v pair - ;; vector would incorrectly take insertion order into account. - (mix (mix 103924836 (hash-table-count key)) - (sxhash (hash-table-test key)))) - ((pathnamep key) (pathname-sxhash key)) - (t - (structure-object-psxhash key depthoid)))) - (list - (cond ((null key) - (the fixnum 480929)) - ((eql depthoid 0) - (the fixnum 779578)) - (t - (let ((depthoid (1- (truly-the (integer 0 #.+max-hash-depthoid+) - depthoid)))) - (mix (%psxhash (car key) depthoid) - (%psxhash (cdr key) depthoid)))))) - (number (number-psxhash key)) - (character (char-code (char-upcase key))) - (t (sxhash key))))) + (sfloat-psxhash (key) + (declare (single-float key)) + (hash-float single-float key)) + (dfloat-psxhash (key) + (declare (double-float key)) + (hash-float double-float key)) + (number-psxhash (key) + (declare (type number key) + (muffle-conditions compiler-note)) + (macrolet ((hash-complex (hasher) + `(if (zerop (imagpart key)) + (,hasher (realpart key)) + ;; I'm not sure what the point of an additional mix step + ;; with a constant was. Maybe trying to get it not to hash + ;; like a ratio whose num/den are equal to the real and imag + ;; parts of a complex number? That seems silly. + ;; But sure, let's do something like it, but simpler. + ;; (It might hash like a cons of these integers anyway) + (logand (lognot (mix (,hasher (realpart key)) (,hasher (imagpart key)))) + most-positive-fixnum)))) + (etypecase key + (integer (sxhash key)) + (single-float (sfloat-psxhash key)) + (double-float (dfloat-psxhash key)) + (rational (if (and (<= most-negative-double-float + key + most-positive-double-float) + (= (coerce key 'double-float) key)) + (sxhash (coerce key 'double-float)) + ;; a rational for which '=' does not return T when compared + ;; to itself cast as double-float need to have the same hash + ;; as any float. That's why this case is legitimate. + (sxhash key))) + ((complex double-float) (hash-complex dfloat-psxhash)) + ((complex single-float) (hash-complex sfloat-psxhash)) + ((complex rational) (hash-complex number-psxhash))))) + (%psxhash (key depthoid) + (typecase key + (array + (if (vectorp key) + (with-array-data ((a key) (start) (end) :force-inline t :check-fill-pointer t) + (mix (data-vector-hash a start end depthoid) (length key))) + (with-array-data ((a key) (start) (end) :force-inline t :array-header-p t) + (let ((result (data-vector-hash a start end depthoid))) + (dotimes (i (array-rank key) result) + (mixf result (%array-dimension key i))))))) + (structure-object + (cond ((hash-table-p key) + ;; This is a purposely not very strong hash so that it does not make any + ;; distinctions that EQUALP does not make. Computing a hash of the k/v pair + ;; vector would incorrectly take insertion order into account. + (mix (mix 103924836 (hash-table-count key)) + (sxhash (hash-table-test key)))) + ((pathnamep key) (pathname-sxhash key)) + (t + (structure-object-psxhash key depthoid)))) + (list + (cond ((null key) + (the fixnum 480929)) + ((eql depthoid 0) + (the fixnum 779578)) + (t + (let ((depthoid (1- (truly-the (integer 0 #.+max-hash-depthoid+) + depthoid)))) + (mix (%psxhash (car key) depthoid) + (%psxhash (cdr key) depthoid)))))) + (number (number-psxhash key)) + (character (char-code (char-upcase key))) + (t (sxhash key))))) (%psxhash key +max-hash-depthoid+))) - -(defun number-psxhash (key) - (declare (type number key) - (explicit-check) - (muffle-conditions compiler-note) - (optimize speed)) - (flet ((sxhash-double-float (val) - (declare (type double-float val)) - ;; FIXME: Check to make sure that the DEFTRANSFORM kicks in and the - ;; resulting code works without consing. (In Debian cmucl 2.4.17, - ;; it didn't.) - (sxhash val))) - (macrolet ((hash-float (type key) - (let ((lo (coerce sb-xc:most-negative-fixnum type)) - (hi (coerce sb-xc:most-positive-fixnum type))) - `(let ((key ,key)) - (cond ( ;; This clause allows FIXNUM-sized integer - ;; values to be handled without consing. - (<= ,lo key ,hi) - (multiple-value-bind (q r) - (floor (the (,type ,lo ,hi) key)) - (if (zerop (the ,type r)) - (sxhash q) - (sxhash-double-float - (coerce key 'double-float))))) - ((float-infinity-p key) - ;; {single,double}-float infinities are EQUALP - (if (minusp key) - (sxhash sb-ext:single-float-negative-infinity) - (sxhash sb-ext:single-float-positive-infinity))) - (t - (multiple-value-bind (q r) (floor key) - (if (zerop (the ,type r)) - (sxhash q) - (sxhash-double-float - (coerce key 'double-float))))))))) - (hash-complex (&optional (hasher '(number-psxhash))) - `(if (zerop (imagpart key)) - (,@hasher (realpart key)) - (let ((result 330231)) - (declare (type fixnum result)) - (mixf result (,@hasher (realpart key))) - (mixf result (,@hasher (imagpart key))) - result)))) - (etypecase key - (integer (sxhash key)) - (float (macrolet () - (etypecase key - (single-float (hash-float single-float key)) - (double-float (hash-float double-float key)) - #+long-float - (long-float (error "LONG-FLOAT not currently supported"))))) - (rational (if (and (<= sb-xc:most-negative-double-float - key - sb-xc:most-positive-double-float) - (= (coerce key 'double-float) key)) - (sxhash-double-float (coerce key 'double-float)) - (sxhash key))) - ((complex double-float) - (hash-complex (hash-float double-float))) - ((complex single-float) - (hash-complex (hash-float single-float))) - ((complex rational) - (hash-complex)))))) +) ; end MACROLET ;;; Semantic equivalent of SXHASH, but better-behaved for function names. ;;; It performs more work by not cutting off as soon in the CDR direction. @@ -525,7 +596,7 @@ (declare (fixnum depthoid)) (cond ((atom x) (sxhash x)) ((zerop depthoid) - #.(logand sb-xc:most-positive-fixnum #36Rglobaldbsxhashoid)) + #.(logand most-positive-fixnum #36Rglobaldbsxhashoid)) (t (mix (recurse (car x) (1- depthoid)) (recurse (cdr x) (1- depthoid))))))) (traverse 0 name 10)))) diff --git a/src/code/target-thread.lisp b/src/code/target-thread.lisp index 699d8a6d96..a27f503fa1 100644 --- a/src/code/target-thread.lisp +++ b/src/code/target-thread.lisp @@ -11,6 +11,25 @@ (in-package "SB-THREAD") +;;; symbols to protect from tree-shaker, for some tests +(export '(%thread-local-references + current-thread-sap + get-spinlock + release-spinlock + spinlock + with-deathlok + with-session-lock + with-spinlock)) + +#+(or linux win32) +(defmacro my-kernel-thread-id () + `(sb-ext:truly-the + (unsigned-byte 32) + (sap-int (sb-vm::current-thread-offset-sap sb-vm::thread-os-kernel-tid-slot)))) +;; using the pthread_id seems fine, the umtx interface uses word-sized values +#+freebsd +(defmacro my-kernel-thread-id () `(thread-primitive-thread *current-thread*)) + ;;; CAS Lock ;;; ;;; Locks don't come any simpler -- or more lightweight than this. While @@ -126,6 +145,10 @@ offending thread using THREAD-ERROR-THREAD.")) (format s "Joining thread timed out: thread ~A ~ did not exit in time." (thread-error-thread c))) + (:foreign + (format s "Joining thread failed: thread ~A ~ + is not a lisp thread." + (thread-error-thread c))) (:self-join (format s "In thread ~A, attempt to join the current ~ thread." @@ -151,56 +174,52 @@ exited. The offending thread can be accessed using THREAD-ERROR-THREAD.")) (condition) (thread-error-thread condition)) -;;; Of the WITH-PINNED-OBJECTS in this file, not every single one is -;;; necessary because threads are only supported with the conservative -;;; gencgc and numbers on the stack (returned by GET-LISP-OBJ-ADDRESS) -;;; are treated as references. - (setf (documentation 'thread-name 'function) - "Name of the thread. Can be assigned to using SETF. Thread names can be -arbitrary printable objects, and need not be unique.") + "Name of the thread. Can be assigned to using SETF. A thread name must be +a simple-string (not necessarily unique) or NIL.") (defmethod print-object ((thread thread) stream) (print-unreadable-object (thread stream :type t :identity t) - (let* ((cookie (list thread)) - (info (if (thread-alive-p thread) - :running - (multiple-value-list - (join-thread thread :default cookie)))) - (state (if (eq :running info) - (let* ((thing (progn - (barrier (:read)) - (thread-waiting-for thread)))) - (typecase thing - (cons - (list "waiting on:" (cdr thing) - "timeout: " (car thing))) - (null - (list info)) - (t - (list "waiting on:" thing)))) - (if (eq cookie (car info)) - (list :aborted) - :finished))) - (values (when (eq :finished state) - info)) + (let* ((values (cond ((thread-alive-p thread) :running) + ;; don't call JOIN-THREAD, just read the result if ALIVE-P is NIL + ((listp (thread-result thread)) (thread-result thread)) + (t :aborted))) + (state (cond ((eq values :running) + (let* ((thing (progn + (barrier (:read)) + (thread-waiting-for thread)))) + (typecase thing + (null '(:running)) + (cons + (list "waiting on:" (cdr thing) + "timeout: " (car thing))) + (t + (list "waiting on:" thing))))) + ((eq values :aborted) '(:aborted)) + (t :finished))) + (*print-array* nil) (*print-level* 4)) (format stream + ;; if not finished, show the STATE as a list. + ;; if finished, show the VALUES. "~@[~S ~]~:[~{~I~A~^~2I~_ ~}~_~;~A~:[ no values~; values: ~:*~{~S~^, ~}~]~]" (thread-name thread) (eq :finished state) state values)))) -(defun print-lock (lock name owner stream) - (let ((*print-circle* t)) - (print-unreadable-object (lock stream :type t :identity (not name)) - (if owner - (format stream "~@[~S ~]~2I~_owner: ~S" name owner) - (format stream "~@[~S ~](free)" name))))) - (defmethod print-object ((mutex mutex) stream) - (print-lock mutex (mutex-name mutex) (mutex-owner mutex) stream)) + (let ((name (mutex-name mutex))) + (print-unreadable-object (mutex stream :type t :identity (not name)) + #+sb-futex + (format stream "~@[~S ~]~[free~;taken~;contested~:;err~] owner=~X" + name (mutex-state mutex) (vmthread-name (mutex-%owner mutex))) + #-sb-futex + (let ((owner (mutex-owner mutex)) + (*print-circle* t)) + (if owner + (format stream "~@[~S ~]~2I~_owner: ~S" name owner) + (format stream "~@[~S ~](free)" name)))))) ;; NB: ephemeral threads must terminate strictly before the test of NTHREADS>1 ;; in DEINIT, i.e. this is not a promise that the thread will terminate @@ -212,17 +231,54 @@ to terminate this thread cleanly prior to core file saving without signalling an error in that case." (thread-%ephemeral-p thread)) -;; A thread is eligible for gc iff it has finished and there are no -;; more references to it. This structure keeps a reference to -;; all running threads ordered by stack base address. +;;; Keep an AVL tree of threads ordered by stack base address. NIL is the empty tree. (sb-ext:define-load-time-global *all-threads* ()) -(sb-ext:define-load-time-global *all-threads-lock* (make-mutex :name "all threads lock")) - -(defvar *default-alloc-signal* nil) - -(defmacro with-all-threads-lock (&body body) - `(with-system-mutex (*all-threads-lock*) - ,@body)) +;;; Ensure that THREAD is in *ALL-THREADS*. +(defmacro update-all-threads (key thread) + `(let ((addr ,key)) + (barrier (:read)) + (let ((old *all-threads*)) + (loop + ;; If ADDR exists, then we have a bug in the thread exit handler. + ;; The workaround here would be to delete the old thread first, + ;; but I'd rather find out about the bug than bury it. + (aver (not (avl-find addr old))) + (let ((new (avl-insert old addr ,thread))) + (when (eq old (setq old (sb-ext:cas *all-threads* old new))) (return))))))) + +(defun vmthread-name (vmthread) + (binding* ((node (avl-find (vmthread-id->addr vmthread) *all-threads*) :exit-if-null) + (thread (avlnode-data node) :exit-if-null) + (name (thread-name thread) :exit-if-null)) + (return-from vmthread-name name)) + vmthread) ; lacking a string, the identifier constitutes its name + +;;; Translate a 'struct thread*' to a SB-THREAD:THREAD. +;;; I'd like to do this simply by reading the 'lisp_thread' field, +;;; but that's dangerous. Ultimately I think we will have to either store a +;;; refcount in the structure (freeing it only when its last referer is gone) +;;; or implement hazard pointers. Either one is going to be tricky because we can't +;;; store the refcount in the structure if it can go away while we're trying +;;; to increment the count. But having the ability to manipulate the structure +;;; of any thread from any thread would simplify other things in this file +;;; as well as making MUTEX-OWNER more efficient. +(defun mutex-owner-lookup (vmthread) + ;; Convert the "fixnum-encoded" thread ID to a word. + ;; It's possible that a race could cause find to fail. If the mutex + ;; really has a dead thread as its owner, you've got bigger problems. + ;; Moreover, because 'struct thread' can be recycled (very quickly) + ;; it's possible for the following sequence to occur: thread T1 at address A1 + ;; grabs the mutex, then thread T2 reads MUTEX-%OWNER slot, then T1 exits + ;; and T3 gets allocated at address A1, and grabs the mutex. + ;; Thread T2 then performs AVL-FIND and concludes that T3 is the apparent owner. + ;; Well, as the docstring at MUTEX-OWNER says, it is "racy by design". + (acond ((avl-find (vmthread-id->addr vmthread) *all-threads*) (avlnode-data it)) + ((= vmthread 0) nil) + ;; This is the same keyword that SYMBOL-VALUE-IN-THREAD can return on error. + ;; If people don't like seeing it, we could return instead + ;; (LOAD-TIME-VALUE (%make-thread "dead-thread" nil nil)) + ;; indicating that you observed a value of %OWNER which no longer exists. + (t :thread-dead))) (defun list-all-threads () "Return a list of the live threads. Note that the return value is @@ -232,61 +288,72 @@ created and old ones may exit at any time." ;; Of course by the time we're done collecting nodes, the tree can have ;; been replaced by a different tree. (barrier (:read)) - (avltree-list *all-threads*)) + (avltree-filter (lambda (node) + (let ((thread (avlnode-data node))) + (when (and (= (thread-%visible thread) 1) + (neq thread sb-impl::*finalizer-thread*)) + thread))) + *all-threads*)) ;;; used by debug-int.lisp to access interrupt contexts -#-sb-thread -(progn - (declaim (inline sb-vm::current-thread-offset-sap)) - (defun sb-vm::current-thread-offset-sap (n) - (sap-ref-sap (alien-sap (extern-alien "all_threads" (* t))) - (* n sb-vm:n-word-bytes)))) - -(declaim (inline current-thread-sap)) -(defun current-thread-sap () - #+sb-thread - (sb-vm::current-thread-offset-sap sb-vm::thread-this-slot) - #-sb-thread - (int-sap 0)) - -(declaim (inline current-thread-os-thread)) -(defun current-thread-os-thread () - #+sb-thread - (sap-int (sb-vm::current-thread-offset-sap sb-vm::thread-os-thread-slot)) - #-sb-thread - 0) - (sb-ext:define-load-time-global *initial-thread* nil) -(sb-ext:define-load-time-global *make-thread-lock* nil) - -(eval-when (:compile-toplevel :load-toplevel) - #+(and sb-thread sb-futex linux) (push :futex-use-tid sb-xc:*features*)) -#+linux (define-alien-routine "sb_GetTID" (unsigned 32)) - -(defun init-initial-thread () - (/show0 "Entering INIT-INITIAL-THREAD") - ;;; FIXME: is it purposeful or accidental that we recreate some of - ;;; the global mutexes but not *ALL-THREADS-LOCKS* ? +;;; *JOINABLE-THREADS* is a list of THREAD instances. +;;; I had attempted to construct the list using the thread's memory to create cons +;;; cells but that turned out to be flawed- the cells must be freshly heap-allocated, +;;; because ATOMIC-POP is vulnerable to the A/B/A problem if cells are reused. +;;; Example: initial state: *JOINABLE-THREADS* -> node1 -> node2 -> node3. +;;; After reading *JOINABLE-THREADS* we want to CAS it to node2. +;;; If, after reading the variable, all of node1, node2, and node3 are popped +;;; by another thread, and then node1 is reused, and made to point to node4, +;;; then the new state is: *JOINABLE-THREADS* -> node1 -> node4 +;;; which looks like CAS(*joinable-threads*, node1, node2) should succeed, +;;; but it should not. The LL/SC model would detect that, but CAS can not. +;;; +;;; A thread is pushed into *JOINABLE-THREADS* while still using its lisp stack. +;;; This is fine, because the C code will perform a join, which will effectively +;;; wait until the lisp thread is off its stack. It won't have to wait long, +;;; because pushing into *JOINABLE-THREADS* is the last thing to happen in lisp. +;;; In theory we could support some mode of keeping the memory while joining +;;; the pthread, but we currently do not. +(sb-ext:define-load-time-global *joinable-threads* nil) +(declaim (list *joinable-threads*)) ; list of threads + +;;; Copy some slots from the C 'struct thread' into the SB-THREAD:THREAD. +(defmacro copy-primitive-thread-fields (this) + `(progn + (setf (thread-primitive-thread ,this) (current-thread-sap-int)) + #-win32 + (setf (thread-os-thread ,this) + (sap-int (sb-vm::current-thread-offset-sap sb-vm::thread-os-thread-slot))))) + +(defmacro set-thread-control-stack-slots (this) + `(setf (thread-control-stack-start ,this) (get-lisp-obj-address sb-vm:*control-stack-start*) + (thread-control-stack-end ,this) (get-lisp-obj-address sb-vm:*control-stack-end*))) + +(defvar *session*) + +;;; Not uncoincidentally, the variables assigned here are also +;;; listed in SB-KERNEL::*SAVE-LISP-CLOBBERED-GLOBALS* +(defun init-main-thread () + (/show0 "Entering INIT-MAIN-THREAD") (setf sb-impl::*exit-lock* (make-mutex :name "Exit Lock") *make-thread-lock* (make-mutex :name "Make-Thread Lock")) - (let ((thread (%make-thread :name "main thread" - :%alive-p t))) - #+linux (setf (thread-os-tid thread) (sb-gettid)) + (let* ((name "main thread") + (thread (%make-thread name nil (make-semaphore :name name)))) + (copy-primitive-thread-fields thread) + (set-thread-control-stack-slots thread) ;; Run the macro-generated function which writes some values into the TLS, ;; most especially *CURRENT-THREAD*. (init-thread-local-storage thread) - (setf (thread-os-thread thread) (current-thread-os-thread) - (thread-stack-end thread) (get-lisp-obj-address sb-vm:*control-stack-end*) - (thread-primitive-thread thread) (sap-int (current-thread-sap)) - *initial-thread* thread) - (grab-mutex (thread-result-lock thread)) - ;; Either *all-threads* is empty or it contains exactly one thread - ;; in case we are in reinit since saving core with multiple - ;; threads doesn't work. + (setf *initial-thread* thread) + (setf *joinable-threads* nil) + (setq *session* (new-session thread)) (setq *all-threads* - (avl-insert nil (get-lisp-obj-address sb-vm:*control-stack-start*) thread)))) + (avl-insert nil + (sb-thread::thread-primitive-thread sb-thread:*current-thread*) + thread)))) (defun main-thread () "Returns the main thread of the process." @@ -356,47 +423,41 @@ See also: RETURN-FROM-THREAD and SB-EXT:EXIT." ;;;; Aliens, low level stuff -(define-alien-routine "kill_safely" - int - (os-thread #-alpha unsigned #+alpha unsigned-int) - (signal int)) - -(define-alien-routine "wake_thread" - int - (os-thread unsigned)) +;;; *STARTING-THREADS* receives special treatment by the garbage collector. +;;; The contents of it are pinned (in that respect it is like *PINNED-OBJECTS*) +;;; but also the STARTUP-INFO of each thread is pinned. +(sb-ext:define-load-time-global *starting-threads* nil) +(declaim (list *starting-threads*)) ; list of threads #+sb-thread (progn - ;; FIXME it would be good to define what a thread id is or isn't - ;; (our current assumption is that it's a fixnum). It so happens - ;; that on Linux it's a pid, but it might not be on posix thread - ;; implementations. - (define-alien-routine ("create_thread" %create-thread) - unsigned (lisp-fun-address unsigned)) - - (declaim (inline %block-deferrable-signals)) - (define-alien-routine ("block_deferrable_signals" %block-deferrable-signals) - void - (where unsigned) - (old unsigned)) - - (defun block-deferrable-signals () - (%block-deferrable-signals 0 0)) - #+sb-futex (progn - (declaim (inline futex-wait %futex-wait futex-wake)) + (locally (declare (sb-ext:muffle-conditions sb-ext:compiler-note)) + (define-structure-slot-addressor mutex-state-address + ;; """ (Futexes are 32 bits in size on all platforms, including 64-bit systems.) """ + ;; which means we need to add 4 bytes to get to the low 32 bits of the slot contents + ;; where we store state. This would be prettier if we had 32-bit raw slots. + :structure mutex + :slot state + :byte-offset (+ #+(and 64-bit big-endian) 4)) + (define-structure-slot-addressor waitqueue-token-address + :structure waitqueue + :slot token + :byte-offset (+ #+(and 64-bit big-endian) 4))) - (define-alien-routine ("futex_wait" %futex-wait) int - (word unsigned) (old-value #+linux (unsigned 32) #-linux unsigned) - (to-sec long) (to-usec unsigned-long)) + (export 'futex-wake) ; for naughty users only + (declaim (inline futex-wait futex-wake)) - (defun futex-wait (word old to-sec to-usec) - (with-interrupts - (%futex-wait word old to-sec to-usec))) + (define-alien-routine "futex_wake" int (word-addr unsigned) (n unsigned-long)) - (define-alien-routine "futex_wake" - int (word unsigned) (n unsigned-long)))) + (defun futex-wait (word-addr oldval to-sec to-usec) + (with-alien ((%wait (function int unsigned + #+freebsd unsigned #-freebsd (unsigned 32) + long unsigned-long) + :extern "futex_wait")) + (with-interrupts + (alien-funcall %wait word-addr oldval to-sec to-usec)))))) (defmacro with-deadlocks ((thread lock &optional (timeout nil timeoutp)) &body forms) (with-unique-names (n-thread n-lock new n-timeout) @@ -418,7 +479,7 @@ See also: RETURN-FROM-THREAD and SB-EXT:EXIT." (barrier (:write)) ,@forms) ;; Interrupt handlers and GC save and restore any - ;; previous wait marks using WITHOUT-DEADLOCKS below. + ;; previous wait marks using WITHOUT-THREAD-WAITING-FOR (setf (thread-waiting-for ,n-thread) nil) (barrier (:write)))))) @@ -427,70 +488,21 @@ See also: RETURN-FROM-THREAD and SB-EXT:EXIT." (setf (documentation 'make-mutex 'function) "Create a mutex." (documentation 'mutex-name 'function) "The name of the mutex. Setfable.") -#+(and sb-thread sb-futex) -(progn - (locally (declare (sb-ext:muffle-conditions sb-ext:compiler-note)) - ;; """ (Futexes are 32 bits in size on all platforms, including 64-bit systems.) """ - ;; which means we need to add 4 bytes to get to the low 32 bits of the slot contents - ;; where we store state. This would be prettier if we had 32-bit raw slots. - (define-structure-slot-addressor mutex-state-address - :structure mutex - :slot state - :byte-offset (+ #+(and 64-bit big-endian) 4))) - ;; Important: current code assumes these are fixnums or other - ;; lisp objects that don't need pinning. - (defconstant +lock-free+ 0) - (defconstant +lock-taken+ 1) - (defconstant +lock-contested+ 2)) - -(defun mutex-owner (mutex) - "Current owner of the mutex, NIL if the mutex is free. Naturally, -this is racy by design (another thread may acquire the mutex after -this function returns), it is intended for informative purposes. For -testing whether the current thread is holding a mutex see -HOLDING-MUTEX-P." - ;; Make sure to get the current value. - (sb-ext:compare-and-swap (mutex-%owner mutex) nil nil)) - (sb-ext:define-load-time-global **deadlock-lock** nil) -#+(or (not sb-thread) sb-futex) -(defstruct (waitqueue (:copier nil) (:constructor make-waitqueue (&key name))) - "Waitqueue type." - #+(and sb-thread sb-futex) - (token 0 - ;; actually 32-bits, but it needs to be a raw slot and we don't have - ;; 32-bit raw slots on 64-bit machines. - #+futex-use-tid :type #+futex-use-tid sb-ext:word) - ;; If adding slots between TOKEN and NAME, please see futex_name() in linux_os.c - ;; which attempts to divine a string from a futex word address. - (name nil :type (or null string))) - -#+(and sb-thread (not sb-futex)) -(defstruct (waitqueue (:copier nil) (:constructor make-waitqueue (&key name))) - "Waitqueue type." - (name nil :type (or null string)) - ;; For WITH-CAS-LOCK: because CONDITION-WAIT must be able to call - ;; %WAITQUEUE-WAKEUP without re-aquiring the mutex, we need a separate - ;; lock. In most cases this should be uncontested thanks to the mutex -- - ;; the only case where that might not be true is when CONDITION-WAIT - ;; unwinds and %WAITQUEUE-DROP is called. - %owner - %head - %tail) -(declaim (sb-ext:freeze-type waitqueue)) - ;;; Signals an error if owner of LOCK is waiting on a lock whose release ;;; depends on the current thread. Does not detect deadlocks from sempahores. (defun check-deadlock () (let* ((self *current-thread*) (origin (progn (barrier (:read)) + ;; Not sure why a barrier is needed on our own data. + ;; Who else stores thread-waiting-for of me? (thread-waiting-for self)))) (labels ((detect-deadlock (lock) - (let ((other-thread (mutex-%owner lock))) - (cond ((not other-thread)) - ((eq self other-thread) + (let ((other-vmthread-id (mutex-%owner lock))) + (cond ((= 0 other-vmthread-id)) + ((= (current-vmthread-id) other-vmthread-id) (let ((chain (with-cas-lock ((symbol-value '**deadlock-lock**)) (prog1 (deadlock-chain self origin) @@ -510,9 +522,10 @@ HOLDING-MUTEX-P." :thread *current-thread* :cycle chain))) (t - (let ((other-lock (progn - (barrier (:read)) - (thread-waiting-for other-thread)))) + (let* ((other-thread (mutex-owner-lookup other-vmthread-id)) + (other-lock (when (thread-p other-thread) + (barrier (:read)) + (thread-waiting-for other-thread)))) ;; If the thread is waiting with a timeout OTHER-LOCK ;; is a cons, and we don't consider it a deadlock -- since ;; it will time out on its own sooner or later. @@ -520,10 +533,10 @@ HOLDING-MUTEX-P." (detect-deadlock other-lock))))))) (deadlock-chain (thread lock) (let* ((other-thread (mutex-owner lock)) - (other-lock (when other-thread + (other-lock (when (thread-p other-thread) (barrier (:read)) (thread-waiting-for other-thread)))) - (cond ((not other-thread) + (cond ((member other-thread '(nil :thread-dead)) ;; The deadlock is gone -- maybe someone unwound ;; from the same deadlock already? (return-from check-deadlock nil)) @@ -581,9 +594,9 @@ HOLDING-MUTEX-P." (loop with max-ticks = (max 100000 (min (* 2 try-ticks) (expt 10 7))) for scale of-type fixnum = 1 - then (let ((x (logand sb-xc:most-positive-fixnum (* 2 scale)))) + then (let ((x (logand most-positive-fixnum (* 2 scale)))) (if (> scale x) - sb-xc:most-positive-fixnum + most-positive-fixnum x)) do (try) (let* ((now (get-tick)) @@ -645,110 +658,192 @@ returns NIL each time." (,deadline (when ,sec (+ (get-internal-real-time) - (round (* ,seconds sb-xc:internal-time-units-per-second)))))) + (round (* ,seconds internal-time-units-per-second)))))) (flet ((,name () (when ,deadline (let ((,time-left (- ,deadline (get-internal-real-time)))) (if (plusp ,time-left) (* (coerce ,time-left 'single-float) - (sb-xc:/ $1.0f0 sb-xc:internal-time-units-per-second)) + (sb-xc:/ $1.0f0 internal-time-units-per-second)) 0))))) ,@body)))) -(defun %try-mutex (mutex new-owner) +(defun %try-mutex (mutex) (declare (type mutex mutex) (optimize (speed 3))) - (barrier (:read)) - (let ((old (mutex-%owner mutex))) - (when (eq new-owner old) - (error "Recursive lock attempt ~S." mutex)) - #-sb-thread - (when old - (error "Strange deadlock on ~S in an unithreaded build?" mutex)) - #-(and sb-thread sb-futex) - (and (not old) - ;; Don't even bother to try to CAS if it looks bad. - (not (sb-ext:compare-and-swap (mutex-%owner mutex) nil new-owner))) - #+(and sb-thread sb-futex) - ;; From the Mutex 2 algorithm from "Futexes are Tricky" by Ulrich Drepper. - (when (eql +lock-free+ (sb-ext:compare-and-swap (mutex-state mutex) - +lock-free+ - +lock-taken+)) - (let ((prev (sb-ext:compare-and-swap (mutex-%owner mutex) nil new-owner))) - (when prev - (bug "Old owner in free mutex: ~S" prev)) - t)))) + (cond #+sb-futex + (t + ;; From the Mutex 2 algorithm from "Futexes are Tricky" by Ulrich Drepper. + (cond ((= (sb-ext:cas (mutex-state mutex) 0 1) 0) + (setf (mutex-%owner mutex) (current-vmthread-id)) + t) ; GRAB-MUTEX wants %TRY-MUTEX to return boolean, not generalized boolean + ((= (mutex-%owner mutex) (current-vmthread-id)) + (error "Recursive lock attempt ~S." mutex)))) + #-sb-futex + (t + (barrier (:read)) + (let ((old (mutex-%owner mutex))) + (when (= (current-vmthread-id) old) + (error "Recursive lock attempt ~S." mutex)) + #-sb-thread + (when (/= old 0) + (error "Strange deadlock on ~S in an unithreaded build?" mutex)) + (and (zerop old) + ;; Don't even bother to try to CAS if it looks bad. + (zerop (sb-ext:compare-and-swap (mutex-%owner mutex) 0 + (current-vmthread-id)))))))) #+sb-thread -(defun %%wait-for-mutex (mutex new-owner to-sec to-usec stop-sec stop-usec) +(defun %%wait-for-mutex (mutex to-sec to-usec stop-sec stop-usec) (declare (type mutex mutex) (optimize (speed 3))) (declare (sb-ext:muffle-conditions sb-ext:compiler-note)) - #-sb-futex - (declare (ignore to-sec to-usec)) - #-sb-futex - (flet ((cas () + (declare (ignorable to-sec to-usec)) + (cond + #+sb-futex + (t + ;; This is a fairly direct translation of the Mutex 2 algorithm from + ;; "Futexes are Tricky" by Ulrich Drepper. + ;; + ;; void lock () { + ;; int c; + ;; if ((c = cmpxchg(val, 0, 1)) != 0) + ;; do { + ;; if (c == 2 || cmpxchg(val, 1, 2) != 0) + ;; futex_wait(&val, 2); + ;; } while ((c = cmpxchg(val, 0, 2)) != 0); + ;; } + ;; + (symbol-macrolet ((val (mutex-state mutex))) + (let ((c (sb-ext:cas val 0 1))) ; available -> taken + (unless (= c 0) ; Got it right off the bat? + (nlx-protect + (if (not stop-sec) + (loop ; untimed + ;; Mark it as contested, and sleep, unless it is now in state 0. + (when (or (eql c 2) (/= 0 (sb-ext:cas val 1 2))) + (with-pinned-objects (mutex) + (futex-wait (mutex-state-address mutex) 2 -1 0))) + ;; Try to get it, still marking it as contested. + (when (= 0 (setq c (sb-ext:cas val 0 2))) (return))) ; win + (loop ; same as above but check for timeout + (when (or (eql c 2) (/= 0 (sb-ext:cas val 1 2))) + (if (eql 1 (with-pinned-objects (mutex) + (futex-wait (mutex-state-address mutex) 2 to-sec to-usec))) + ;; -1 = EWOULDBLOCK, possibly spurious wakeup + ;; 0 = normal wakeup + ;; 1 = ETIMEDOUT ***DONE*** + ;; 2 = EINTR, a spurious wakeup + (return-from %%wait-for-mutex nil))) + (when (= 0 (setq c (sb-ext:cas val 0 2))) (return)) ; win + ;; Update timeout + (setf (values to-sec to-usec) + (sb-impl::relative-decoded-times stop-sec stop-usec)))) + ;; Unwinding because futex-wait allows interrupts, wake up another futex + (with-pinned-objects (mutex) + (futex-wake (mutex-state-address mutex) 1))))) + (setf (mutex-%owner mutex) (current-vmthread-id)) + t)) + #-sb-futex + (t + (flet ((cas () (loop repeat 100 - when (and (progn - (barrier (:read)) - (not (mutex-%owner mutex))) - (not (sb-ext:compare-and-swap (mutex-%owner mutex) nil - new-owner))) + when (and (progn (barrier (:read)) + (zerop (mutex-%owner mutex))) + (zerop (sb-ext:compare-and-swap (mutex-%owner mutex) 0 + (current-vmthread-id)))) do (return-from cas t) else do (sb-ext:spin-loop-hint)) ;; Check for pending interrupts. (with-interrupts nil))) - (declare (dynamic-extent #'cas)) - (%%wait-for #'cas stop-sec stop-usec)) - #+sb-futex - ;; This is a fairly direct translation of the Mutex 2 algorithm from - ;; "Futexes are Tricky" by Ulrich Drepper. - (flet ((maybe (old) - (when (eql +lock-free+ old) - (let ((prev (sb-ext:compare-and-swap (mutex-%owner mutex) - nil new-owner))) - (when prev - (bug "Old owner in free mutex: ~S" prev)) - (return-from %%wait-for-mutex t))))) - (prog ((old (sb-ext:compare-and-swap (mutex-state mutex) - +lock-free+ +lock-taken+))) - ;; Got it right off the bat? - (maybe old) - :retry - ;; Mark it as contested, and sleep. (Exception: it was just released.) - (when (or (eql +lock-contested+ old) - (not (eql +lock-free+ - (sb-ext:compare-and-swap - (mutex-state mutex) +lock-taken+ +lock-contested+)))) - (when (eql 1 (with-pinned-objects (mutex) - (futex-wait (mutex-state-address mutex) - (get-lisp-obj-address +lock-contested+) - (or to-sec -1) - (or to-usec 0)))) - ;; -1 = EWOULDBLOCK, possibly spurious wakeup - ;; 0 = normal wakeup - ;; 1 = ETIMEDOUT ***DONE*** - ;; 2 = EINTR, a spurious wakeup - (return-from %%wait-for-mutex nil))) - ;; Try to get it, still marking it as contested. - (maybe - (sb-ext:compare-and-swap (mutex-state mutex) +lock-free+ +lock-contested+)) - ;; Update timeout if necessary. - (when stop-sec - (setf (values to-sec to-usec) - (sb-impl::relative-decoded-times stop-sec stop-usec))) - ;; Spin. - (go :retry)))) + (declare (dynamic-extent #'cas)) + (%%wait-for #'cas stop-sec stop-usec))))) + +#+mutex-benchmarks +(symbol-macrolet ((val (mutex-state mutex))) + (export '(wait-for-mutex-algorithm-2 + wait-for-mutex-algorithm-3 + wait-for-mutex-2-partial-inline + wait-for-mutex-3-partial-inline)) + (declaim (sb-ext:maybe-inline %wait-for-mutex-algorithm-2 + %wait-for-mutex-algorithm-3)) + (sb-ext:define-load-time-global *grab-mutex-calls-performed* 0) + ;; Like futex-wait but without garbage having to do with re-invoking + ;; a wake on account of async unwind while releasing the mutex. + (declaim (inline fast-futex-wait)) + (defun fast-futex-wait (word-addr oldval to-sec to-usec) + (with-alien ((%wait (function int unsigned + #+freebsd unsigned #-freebsd (unsigned 32) + long unsigned-long) + :extern "futex_wait")) + (alien-funcall %wait word-addr oldval to-sec to-usec))) + + (defun %wait-for-mutex-algorithm-2 (mutex) + (incf *grab-mutex-calls-performed*) + (let* ((mutex (sb-ext:truly-the mutex mutex)) + (c (sb-ext:cas val 0 1))) ; available -> taken + (unless (= c 0) ; Got it right off the bat? + (loop + ;; Mark it as contested, and sleep, unless it is now in state 0. + (when (or (eql c 2) (/= 0 (sb-ext:cas val 1 2))) + (with-pinned-objects (mutex) + (fast-futex-wait (mutex-state-address mutex) 2 -1 0))) + ;; Try to get it, still marking it as contested. + (when (= 0 (setq c (sb-ext:cas val 0 2))) (return)))))) ; win + (defun %wait-for-mutex-algorithm-3 (mutex) + (incf *grab-mutex-calls-performed*) + (let* ((mutex (sb-ext:truly-the mutex mutex)) + (c (sb-ext:cas val 0 1))) ; available -> taken + (unless (= c 0) ; Got it right off the bat? + (unless (= c 2) + (setq c (%raw-instance-xchg/word mutex (get-dsd-index mutex state) 2))) + (loop while (/= c 0) + do (with-pinned-objects (mutex) + (fast-futex-wait (mutex-state-address mutex) 2 -1 0)) + (setq c (%raw-instance-xchg/word mutex (get-dsd-index mutex state) 2)))))) + + (defun wait-for-mutex-algorithm-2 (mutex) + (declare (inline %wait-for-mutex-algorithm-2)) + (let ((mutex (sb-ext:truly-the mutex mutex))) + (%wait-for-mutex-algorithm-2 mutex) + (setf (mutex-%owner mutex) (current-vmthread-id)))) + ;; The improvement with algorithm 3 is fairly negligible. + ;; Code size is a little less. More improvement comes from doing the + ;; partial-inline algorithms which perform one CAS without a function call. + (defun wait-for-mutex-algorithm-3 (mutex) + (declare (inline %wait-for-mutex-algorithm-3)) + (let ((mutex (sb-ext:truly-the mutex mutex))) + (%wait-for-mutex-algorithm-3 mutex) + (setf (mutex-%owner mutex) (current-vmthread-id)))) + (defmacro wait-for-mutex-2-partial-inline (mutex) + `(let ((m ,mutex)) + (or (= (sb-ext:cas (mutex-state m) 0 1) 0) (%wait-for-mutex-algorithm-2 m)) + (setf (mutex-%owner m) (current-vmthread-id)))) + (defmacro wait-for-mutex-3-partial-inline (mutex) + `(let ((m ,mutex)) + (or (= (sb-ext:cas (mutex-state m) 0 1) 0) (%wait-for-mutex-algorithm-3 m)) + (setf (mutex-%owner m) (current-vmthread-id)))) + ;; This is like RELEASE-MUTEX but without keyword arg parsing + ;; and all the different error modes. + (export 'fast-release-mutex) + (defun fast-release-mutex (mutex) + (let ((mutex (sb-ext:truly-the mutex mutex))) + (setf (mutex-%owner mutex) 0) + (unless (eql (sb-ext:atomic-decf (mutex-state mutex) 1) 1) + (setf (mutex-state mutex) 0) + (with-pinned-objects (mutex) + (futex-wake (mutex-state-address mutex) 1)))))) #+sb-thread -(defun %wait-for-mutex (mutex self timeout to-sec to-usec stop-sec stop-usec deadlinep) +(defun %wait-for-mutex (mutex timeout to-sec to-usec stop-sec stop-usec deadlinep + &aux (self *current-thread*)) (declare (sb-ext:muffle-conditions sb-ext:compiler-note)) (with-deadlocks (self mutex timeout) (with-interrupts (check-deadlock)) (tagbody :again (return-from %wait-for-mutex - (or (%%wait-for-mutex mutex self to-sec to-usec stop-sec stop-usec) + (or (%%wait-for-mutex mutex to-sec to-usec stop-sec stop-usec) (when deadlinep (signal-deadline) ;; FIXME: substract elapsed time from timeout... @@ -759,12 +854,12 @@ returns NIL each time." (define-deprecated-function :early "1.0.37.33" get-mutex (grab-mutex) (mutex &optional new-owner (waitp t) (timeout nil)) (declare (ignorable waitp timeout)) - (let ((new-owner (or new-owner *current-thread*))) - (or (%try-mutex mutex new-owner) - #+sb-thread - (when waitp - (multiple-value-call #'%wait-for-mutex - mutex new-owner timeout (decode-timeout timeout)))))) + (when (and new-owner (neq new-owner *current-thread*)) + (error "GET-MUTEX won't get a mutex on behalf of a different thread")) + (or (%try-mutex mutex) + #+sb-thread + (when waitp + (multiple-value-call #'%wait-for-mutex mutex timeout (decode-timeout timeout))))) (declaim (ftype (sfunction (mutex &key (:waitp t) (:timeout (or null (real 0)))) boolean) grab-mutex)) (defun grab-mutex (mutex &key (waitp t) (timeout nil)) @@ -803,12 +898,10 @@ Notes: directly. " (declare (ignorable waitp timeout)) - (let ((self *current-thread*)) - (or (%try-mutex mutex self) - #+sb-thread - (when waitp - (multiple-value-call #'%wait-for-mutex - mutex self timeout (decode-timeout timeout)))))) + (or (%try-mutex mutex) + #+sb-thread + (when waitp + (multiple-value-call #'%wait-for-mutex mutex timeout (decode-timeout timeout))))) (declaim (ftype (sfunction (mutex &key (:if-not-owner (member :punt :warn :error :force))) null) release-mutex)) (defun release-mutex (mutex &key (if-not-owner :punt)) @@ -824,37 +917,27 @@ WARNING (if IF-NOT-OWNER is :WARN), or releases the mutex anyway (if IF-NOT-OWNER is :FORCE)." (declare (type mutex mutex)) ;; Order matters: set owner to NIL before releasing state. - (let* ((self *current-thread*) - (old-owner (sb-ext:compare-and-swap (mutex-%owner mutex) self nil))) - (unless (eq self old-owner) + (let* ((self (current-vmthread-id)) + (old-owner (sb-ext:compare-and-swap (mutex-%owner mutex) self 0))) + (unless (= self old-owner) (ecase if-not-owner ((:punt) (return-from release-mutex nil)) ((:warn) - (warn "Releasing ~S, owned by another thread: ~S" mutex old-owner)) + (warn "Releasing ~S, owned by another thread: ~S" mutex (vmthread-name old-owner))) ((:error) - (error "Releasing ~S, owned by another thread: ~S" mutex old-owner)) + (error "Releasing ~S, owned by another thread: ~S" mutex (vmthread-name old-owner))) ((:force))) - (setf (mutex-%owner mutex) nil) + (setf (mutex-%owner mutex) 0) ;; FIXME: Is a :memory barrier too strong here? Can we use a :write ;; barrier instead? (barrier (:memory))) - #+(and sb-thread sb-futex) - (when old-owner - ;; FIXME: once ATOMIC-INCF supports struct slots with word sized - ;; unsigned-byte type this can be used: - ;; - ;; (let ((old (sb-ext:atomic-incf (mutex-state mutex) -1))) - ;; (unless (eql old +lock-free+) - ;; (setf (mutex-state mutex) +lock-free+) - ;; (with-pinned-objects (mutex) - ;; (futex-wake (mutex-state-address mutex) 1)))) - (let ((old (sb-ext:compare-and-swap (mutex-state mutex) - +lock-taken+ +lock-free+))) - (when (eql old +lock-contested+) - (sb-ext:compare-and-swap (mutex-state mutex) - +lock-contested+ +lock-free+) - (with-pinned-objects (mutex) - (futex-wake (mutex-state-address mutex) 1)))) + #+sb-futex + (when (/= old-owner 0) + (unless (eql (sb-ext:atomic-decf (mutex-state mutex) 1) 1) + (setf (mutex-state mutex) 0) + (sb-thread:barrier (:write)) ; paranoid ? + (with-pinned-objects (mutex) + (futex-wake (mutex-state-address mutex) 1))) nil))) @@ -892,15 +975,16 @@ IF-NOT-OWNER is :FORCE)." nil) (defun %waitqueue-wakeup (queue n) (declare (fixnum n)) - (loop while (plusp n) - for next = (let ((head (waitqueue-%head queue)) - (tail (waitqueue-%tail queue))) - (when head - (if (eq head tail) - (setf (waitqueue-%head queue) nil - (waitqueue-%tail queue) nil) - (setf (waitqueue-%head queue) (cdr head))) - (car head))) + (loop with next = nil + while (plusp n) + do (setq next (let ((head (waitqueue-%head queue)) + (tail (waitqueue-%tail queue))) + (when head + (if (eq head tail) + (setf (waitqueue-%head queue) nil + (waitqueue-%tail queue) nil) + (setf (waitqueue-%head queue) (cdr head))) + (car head)))) while next do (when (eq queue (sb-ext:compare-and-swap (thread-waiting-for next) queue nil)) @@ -914,14 +998,15 @@ IF-NOT-OWNER is :FORCE)." (setf (documentation 'waitqueue-name 'function) "The name of the waitqueue. Setfable." (documentation 'make-waitqueue 'function) "Create a waitqueue.") -#+(and sb-thread sb-futex) -(locally (declare (sb-ext:muffle-conditions sb-ext:compiler-note)) - (define-structure-slot-addressor waitqueue-token-address - :structure waitqueue - :slot token - :byte-offset (+ #+(and 64-bit big-endian) 4))) +(defmacro nlx-protect-futex (protected &body cleanup) + (declare (ignorable cleanup)) + #+sb-futex + `(nlx-protect ,protected + ,@cleanup) + #-sb-futex + protected) -(declaim (inline %condition-wait)) +(declaim (sb-ext:maybe-inline %condition-wait)) (defun %condition-wait (queue mutex timeout to-sec to-usec stop-sec stop-usec deadlinep) #-sb-thread @@ -930,17 +1015,45 @@ IF-NOT-OWNER is :FORCE)." (sb-ext:wait-for nil :timeout timeout) ; Yeah... #+sb-thread (let ((me *current-thread*)) + (declare (ignorable me)) ; not used if #+sb-futex (barrier (:read)) - (unless (eq me (mutex-%owner mutex)) + (unless (holding-mutex-p mutex) (error "The current thread is not holding ~s." mutex)) (let ((status :interrupted)) ;; Need to disable interrupts so that we don't miss grabbing ;; the mutex on our way out. (without-interrupts - (unwind-protect - (progn - #-sb-futex - (progn + (nlx-protect-futex + (unwind-protect + (cond + #+sb-futex + (t + (with-pinned-objects (queue) + (setf (waitqueue-token queue) (my-kernel-thread-id)) + (release-mutex mutex) + ;; Now we go to sleep using futex-wait. If anyone else + ;; manages to grab MUTEX and call CONDITION-NOTIFY during + ;; this comment, it will change the token, and so futex-wait + ;; returns immediately instead of sleeping. Ergo, no lost + ;; wakeup. We may get spurious wakeups, but that's ok. + (setf status + (case (allow-with-interrupts + (futex-wait (waitqueue-token-address queue) + (my-kernel-thread-id) + ;; our way of saying "no + ;; timeout": + (or to-sec -1) + (or to-usec 0))) + ((1) + ;; 1 = ETIMEDOUT + :timeout) + (t + ;; -1 = EWOULDBLOCK, possibly spurious wakeup + ;; 0 = normal wakeup + ;; 2 = EINTR, a spurious wakeup + :ok))))) + #-sb-futex + (t (%with-cas-lock ((waitqueue-%owner queue)) (%waitqueue-enqueue me queue)) (release-mutex mutex) @@ -952,73 +1065,47 @@ IF-NOT-OWNER is :FORCE)." (declare (dynamic-extent #'wakeup)) (allow-with-interrupts (%%wait-for #'wakeup stop-sec stop-usec))) - :timeout))) - #+sb-futex - (with-pinned-objects (queue - ;; No point in pinning ME if not taking the adddress. - #-futex-use-tid me) - (setf (waitqueue-token queue) #+futex-use-tid (thread-os-tid me) - #-futex-use-tid me) - (release-mutex mutex) - ;; Now we go to sleep using futex-wait. If anyone else - ;; manages to grab MUTEX and call CONDITION-NOTIFY during - ;; this comment, it will change the token, and so futex-wait - ;; returns immediately instead of sleeping. Ergo, no lost - ;; wakeup. We may get spurious wakeups, but that's ok. - (setf status - (case (allow-with-interrupts - (futex-wait (waitqueue-token-address queue) - #+futex-use-tid (thread-os-tid me) - #-futex-use-tid (get-lisp-obj-address me) - ;; our way of saying "no - ;; timeout": - (or to-sec -1) - (or to-usec 0))) - ((1) - ;; 1 = ETIMEDOUT - :timeout) - (t - ;; -1 = EWOULDBLOCK, possibly spurious wakeup - ;; 0 = normal wakeup - ;; 2 = EINTR, a spurious wakeup - :ok))))) - #-sb-futex - (%with-cas-lock ((waitqueue-%owner queue)) - (if (eq queue (thread-waiting-for me)) - (%waitqueue-drop me queue) - (unless (eq :ok status) - ;; CONDITION-NOTIFY thinks we've been woken up, but really - ;; we're unwinding. Wake someone else up. - (%waitqueue-wakeup queue 1)))) - ;; Update timeout for mutex re-aquisition unless we are - ;; already past the requested timeout. - (when (and (eq :ok status) to-sec) - (setf (values to-sec to-usec) - (sb-impl::relative-decoded-times stop-sec stop-usec)) - (when (and (zerop to-sec) (not (plusp to-usec))) - (setf status :timeout))) - ;; If we ran into deadline, try to get the mutex before - ;; signaling. If we don't unwind it will look like a normal - ;; return from user perspective. - (when (and (eq :timeout status) deadlinep) - (let ((got-it (%try-mutex mutex me))) - (allow-with-interrupts - (signal-deadline) - (cond (got-it - (return-from %condition-wait t)) - (t - ;; The deadline may have changed. - (setf (values to-sec to-usec stop-sec stop-usec deadlinep) - (decode-timeout timeout)) - (setf status :ok)))))) - ;; Re-acquire the mutex for normal return. - (when (eq :ok status) - (unless (or (%try-mutex mutex me) - (allow-with-interrupts - (%wait-for-mutex mutex me timeout - to-sec to-usec - stop-sec stop-usec deadlinep))) - (setf status :timeout))))) + :timeout)))) + #-sb-futex + (%with-cas-lock ((waitqueue-%owner queue)) + (if (eq queue (thread-waiting-for me)) + (%waitqueue-drop me queue) + (unless (eq :ok status) + ;; CONDITION-NOTIFY thinks we've been woken up, but really + ;; we're unwinding. Wake someone else up. + (%waitqueue-wakeup queue 1)))) + ;; Update timeout for mutex re-aquisition unless we are + ;; already past the requested timeout. + (when (and (eq :ok status) to-sec) + (setf (values to-sec to-usec) + (sb-impl::relative-decoded-times stop-sec stop-usec)) + (when (and (zerop to-sec) (not (plusp to-usec))) + (setf status :timeout))) + ;; If we ran into deadline, try to get the mutex before + ;; signaling. If we don't unwind it will look like a normal + ;; return from user perspective. + (when (and (eq :timeout status) deadlinep) + (let ((got-it (%try-mutex mutex))) + (allow-with-interrupts + (signal-deadline) + (cond (got-it + (return-from %condition-wait t)) + (t + ;; The deadline may have changed. + (setf (values to-sec to-usec stop-sec stop-usec deadlinep) + (decode-timeout timeout)) + (setf status :ok)))))) + ;; Re-acquire the mutex for normal return. + (when (eq :ok status) + (unless (or (%try-mutex mutex) + (allow-with-interrupts + (%wait-for-mutex mutex timeout to-sec to-usec + stop-sec stop-usec deadlinep))) + (setf status :timeout)))) + ;; Unwinding because futex-wait and %wait-for-mutex above + ;; allow interrupts, wake up another futex + (with-pinned-objects (queue) + (futex-wake (waitqueue-token-address queue) 1)))) ;; Determine actual return value. :ok means (potentially ;; spurious) wakeup => T. :timeout => NIL. (case status @@ -1034,7 +1121,6 @@ IF-NOT-OWNER is :FORCE)." ;; The only case we return normally without re-acquiring ;; the mutex is when there is a :TIMEOUT that runs out. (bug "%CONDITION-WAIT: invalid status on normal return: ~S" status)))))) -(declaim (notinline %condition-wait)) (declaim (ftype (sfunction (waitqueue mutex &key (:timeout (or null (real 0)))) boolean) condition-wait)) (defun condition-wait (queue mutex &key timeout) @@ -1095,26 +1181,25 @@ must be held by this thread during this call." #-sb-thread (error "Not supported in unithread builds.") #+sb-thread - (progn - #-sb-futex - (with-cas-lock ((waitqueue-%owner queue)) - (%waitqueue-wakeup queue n)) - #+sb-futex - (progn + (cond + #+sb-futex + (t ;; No problem if >1 thread notifies during the comment in condition-wait: ;; as long as the value in queue-data isn't the waiting thread's id, it - ;; matters not what it is -- using the queue object itself is handy. - ;; But "handy" is not right (lp#1876825) if pointers are 64 bits, - ;; so then just use 0 which can not correspond to any thread. + ;; matters not what it is. We rely on kernel thread ID being nonzero. ;; ;; XXX we should do something to ensure that the result of this setf ;; is visible to all CPUs. ;; ;; ^-- surely futex_wake() involves a memory barrier? - (setf (waitqueue-token queue) #+futex-use-tid 0 #-futex-use-tid queue) + (setf (waitqueue-token queue) 0) (with-pinned-objects (queue) (futex-wake (waitqueue-token-address queue) n)) - nil))) + nil) + #-sb-futex + (t + (with-cas-lock ((waitqueue-%owner queue)) + (%waitqueue-wakeup queue n))))) (declaim (ftype (sfunction (waitqueue) null) condition-broadcast)) @@ -1127,30 +1212,24 @@ must be held by this thread during this call." ;; On a 64-bit platform truncating M-P-F to an int ;; results in -1, which wakes up only one thread. (ldb (byte 29 0) - sb-xc:most-positive-fixnum))) + most-positive-fixnum))) ;;;; Semaphores -(defstruct (semaphore (:copier nil) - (:constructor make-semaphore - (&key name ((:count %count) 0)))) - "Semaphore type. The fact that a SEMAPHORE is a STRUCTURE-OBJECT -should be considered an implementation detail, and may change in the -future." - (name nil :type (or null string) :read-only t) - (%count 0 :type (integer 0)) - (waitcount 0 :type sb-vm:word) - (mutex (make-mutex :name "semaphore lock") :read-only t - :type mutex) - (queue (make-waitqueue) :read-only t - :type waitqueue)) -(declaim (sb-ext:freeze-type semaphore)) - -(setf (documentation 'semaphore-name 'function) - "The name of the semaphore INSTANCE. Setfable." - (documentation 'make-semaphore 'function) - "Create a semaphore with the supplied COUNT and NAME.") +(defun make-semaphore (&key name (count 0)) + "Create a semaphore with the supplied COUNT and NAME." + (declare (inline make-mutex make-waitqueue)) + (%make-semaphore count + (make-mutex :name name) + (make-waitqueue :name name))) + +(defun semaphore-name (semaphore) + "The name of the semaphore INSTANCE. Setfable." + (waitqueue-name (semaphore-queue semaphore))) + +(defun (setf semaphore-name) (newval semaphore) + (setf (waitqueue-name (semaphore-queue semaphore)) newval)) (defstruct (semaphore-notification (:constructor make-semaphore-notification ()) (:copier nil)) @@ -1304,41 +1383,59 @@ on this semaphore, then N of them is woken up." ;;;; Job control, independent listeners (defstruct (session (:copier nil)) + ;; New threads are atomically pushed into NEW-ENROLLEES without acquiring the + ;; session lock. Any operation on the session that transfers ownership of the + ;; foreground must move the enrollees into THREADS while holding the lock. + (new-enrollees) (lock (make-mutex :name "session lock")) + ;; If we wanted to get fancy, these next 2 lists might become lockfree linked lists + ;; so that it would be possible for threads to exit without acquiring the lock. + ;; It might be tricky (i.e. too much trouble) to figure out how to reimplement + ;; the various operations on a session though. (threads nil) (interactive-threads nil) - (interactive-threads-queue (make-waitqueue))) + (interactive-threads-queue (make-waitqueue :name "session"))) (declaim (sb-ext:freeze-type session)) -(defvar *session* nil) - ;;; The debugger itself tries to acquire the session lock, don't let ;;; funny situations (like getting a sigint while holding the session ;;; lock) occur. At the same time we need to allow interrupts while ;;; *waiting* for the session lock for things like GET-FOREGROUND to ;;; be interruptible. ;;; -;;; Take care: we sometimes need to obtain the session lock while -;;; holding on to *ALL-THREADS-LOCK*, so we must _never_ obtain it -;;; _after_ getting a session lock! (Deadlock risk.) -;;; -;;; FIXME: It would be good to have ordered locks to ensure invariants -;;; like the above. +;;; FIXME: It might be good to have a way to enforce lock ordering invariants (defmacro with-session-lock ((session) &body body) `(with-system-mutex ((session-lock ,session) :allow-with-interrupts t) + (%enroll-new-threads ,session) ,@body)) -(defun new-session () - (make-session :threads (list *current-thread*) - :interactive-threads (list *current-thread*))) - -(defun init-job-control () - (/show0 "Entering INIT-JOB-CONTROL") - (setf *session* (new-session)) - (/show0 "Exiting INIT-JOB-CONTROL")) - -(defun %delete-thread-from-session (thread session) +;;; Move new enrollees into SESSION-THREADS. The session lock must be held. +;;; The reason this can be lazy is that a thread is never an interactive thread +;;; just by joining a session, so it doesn't involve itself with the waitqueue; +;;; it can't cause a thread waiting on the condition to wake. +;;; i.e. even if a newly created thread were required to obtain the lock to insert +;;; itself into the session, it would not and could not have any effect on any other +;;; thread in the session. +(defun %enroll-new-threads (session) + (loop (let ((thread (sb-ext:atomic-pop (session-new-enrollees session)))) + (cond ((not thread) (return)) + ((thread-alive-p thread) + ;; Can it become dead immediately upon insertion into THREADS? + ;; No, because to become dead, it must acquire the session lock. + (push thread (session-threads session))))))) + +(defun new-session (thread) + (make-session :threads (list thread) + :interactive-threads (list thread))) + +(defun %delete-thread-from-session (thread &aux (session *session*)) (with-session-lock (session) + ;; One of two things about THREAD must be true, either: + ;; - it was transferred from SESSION-NEW-ENROLLEES to SESSION-THREADS + ;; - it was NOT yet transferred from SESSION-NEW-ENROLLEES. + ;; There can't be an "in flight" state of having done the atomic-pop from + ;; SESSION-NEW-ENROLLEES but not the push into THREADS, because anyone manipulating + ;; the THREADS list must be holding the session lock. (let ((was-foreground (eq thread (foreground-thread session)))) (setf (session-threads session) ;; FIXME: I assume these could use DELQ1. @@ -1350,29 +1447,133 @@ on this semaphore, then N of them is woken up." (condition-broadcast (session-interactive-threads-queue session)))))) (defun call-with-new-session (fn) - (%delete-thread-from-session *current-thread* *session*) - (let ((*session* (new-session))) + (%delete-thread-from-session *current-thread*) + (let ((*session* (new-session *current-thread*))) (funcall fn))) (defmacro with-new-session (args &body forms) (declare (ignore args)) ;for extensibility - (with-unique-names (fb-name) + (with-unique-names (fb-name) ; FIXME: what's the significance of "fb-" ? `(labels ((,fb-name () ,@forms)) (call-with-new-session (function ,fb-name))))) -;;; Remove thread from its session, if it has one. +;;; WITH-DEATHLOK ensures that the 'struct thread' and/or OS thread won't go away +;;; by synchronizing with HANDLE-THREAD-EXIT. +(defmacro with-deathlok ((thread &optional c-thread) &body body) + `(with-system-mutex ((thread-interruptions-lock ,thread)) + ,@(if c-thread + `((let ((,c-thread (thread-primitive-thread ,thread))) ,@body)) + body))) + +(sb-ext:define-load-time-global *sprof-data* nil) +#+allocator-metrics +(sb-ext:define-load-time-global *allocator-metrics* nil) + #+sb-thread -(defun handle-thread-exit (thread control-stack-start) - (/show0 "HANDLING THREAD EXIT") - (when *exit-in-process* - (%exit)) - ;; Lisp-side cleanup - (with-all-threads-lock - (setf (thread-%alive-p thread) nil) - (setf (thread-os-thread thread) sb-ext:most-positive-word) - (setq *all-threads* (avl-delete control-stack-start *all-threads*)) - (when *session* - (%delete-thread-from-session thread *session*)))) +(progn +;;; Remove thread from its session, if it has one, and from *all-threads*. +;;; Also clobber the pointer to the primitive thread +;;; which makes THREAD-ALIVE-P return false hereafter. +(defmacro handle-thread-exit () + '(let* ((thread *current-thread*) + ;; use the "funny fixnum" representation + (c-thread (%make-lisp-obj (thread-primitive-thread thread))) + (sem (thread-semaphore thread))) + ;; System threads exit peacefully when asked, and they don't bother anyone. + ;; They must not participate in shutting other threads down. + (when (and *exit-in-progress* (not (thread-ephemeral-p thread))) + (%exit)) + ;; This AVER failed when I messed up deletion from *STARTING-THREADS*. + ;; That in turn caused a failure in GC because a fixnum is not a legal value + ;; for the startup info when observed by GC. + (aver (not (memq thread *starting-threads*))) + ;; If collecting allocator metrics, transfer them to the global list + ;; so that we can summarize over exited threads. + #+allocator-metrics + (let ((metrics (cons (thread-name thread) (allocator-histogram)))) + (sb-ext:atomic-push metrics *allocator-metrics*)) + ;; Stash the primitive thread SAP for reuse, but clobber the PRIMITIVE-THREAD + ;; slot which makes ALIVE-P return NIL. + ;; A minor TODO: can this lock acquire/release be moved to where we actually + ;; unmap the memory an do a pthread_join()? I would think so, because until then, + ;; there is no real harm in reading the memory. In this state the pthread library + ;; will usually return ESRCH if you try to use the pthread id - it's a valid + ;; pointer, but it knows that it has no underlying OS thread. + (with-deathlok (thread) + (when sem ; ordinary lisp thread, not FOREIGN-THREAD + (setf (thread-startup-info thread) c-thread)) + ;; Accept no further interruptions. Other threads can't add new ones to the queue + ;; as doing so requires grabbing the per-thread mutex which we currently own. + ;; Deferrable signals are masked at this point, but it is best to tidy up + ;; any stray data such as captured closure values. + (setf (thread-interruptions thread) nil + (thread-primitive-thread thread) 0) + (setf (sap-ref-8 (current-thread-sap) ; state_word.sprof_enable + (1+ (ash sb-vm:thread-state-word-slot sb-vm:word-shift))) + 0) + ;; Take ownership of our statistical profiling data and transfer the results to + ;; the global pool. This doesn't need to synchronize with the signal handler, + ;; which is effectively disabled now, but does synchronize via the interruptions + ;; mutex with any other thread trying to read this thread's data. + (let ((sprof-data (sb-vm::current-thread-offset-sap sb-vm:thread-sprof-data-slot))) + (unless (= (sap-int sprof-data) 0) + (setf (sap-ref-word (descriptor-sap c-thread) + (ash sb-vm:thread-sprof-data-slot sb-vm:word-shift)) + 0) + ;; Operation on the global list must be atomic. + (sb-ext:atomic-push (cons sprof-data thread) *sprof-data*))) + (barrier (:write))) + ;; After making the thread dead, remove from session. If this were done first, + ;; we'd just waste time moving the thread into SESSION-THREADS (if it wasn't there) + ;; only to remove it right away. + (when *session* + (%delete-thread-from-session thread)) + (cond + ;; If possible, logically remove from *ALL-THREADS* by flipping a bit. + ;; Foreign threads remove themselves. They don't have an exit semaphore, + ;; so that's how we know which is which. + (sem + ;; Tree pruning is the responsibility of thread creators, not dying threads. + ;; Creators have to manipulate the tree anyway, and they need access to the old + ;; structure to grab the memory. + (let ((old (sb-ext:cas (thread-%visible thread) 1 -1))) + ;; now (LIST-ALL-THREADS) won't see it + (aver (eql old 1))) + (sb-ext:atomic-push thread *joinable-threads*)) + (t ; otherwise, physically remove from *ALL-THREADS* + ;; The memory allocation/deallocation is handled in C. + ;; I would like to combine the recycle bin for foreign and lisp threads though. + (delete-from-all-threads (get-lisp-obj-address c-thread)))) + (when sem + (setf (thread-semaphore thread) nil) ; nobody needs to wait on it now + ;; + ;; We go out of our way to support something pthreads don't: + ;; "The results of multiple simultaneous calls to pthread_join() + ;; specifying the same target thread are undefined." + ;; - https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_join.html + ;; and for std::thread + ;; "No synchronization is performed on *this itself. Concurrently calling join() + ;; on the same thread object from multiple threads constitutes a data race + ;; that results in undefined behavior." + ;; - https://en.cppreference.com/w/cpp/thread/thread/join + ;; That's because (among other reasons), pthread_join deallocates memory. + ;; But in so far as our join does not equate to resource freeing, and our exit flag is + ;; our own kind of semaphore, we simply signal it using an arbitrarily huge count. + ;; See the comment in 'thread-structs.lisp' about why this isn't CONDITION-BROADCAST + ;; on a condition var. (Good luck trying to make this many threads) + (signal-semaphore sem 1000000)))) + +;;; The "funny fixnum" address format would do no good - AVL-FIND and AVL-DELETE +;;; expect normal happy lisp integers, even if a bignum. +(defun delete-from-all-threads (addr) + (declare (type sb-vm:word addr)) + (barrier (:read)) + (let ((old *all-threads*)) + (loop + (aver (avl-find addr old)) + (let ((new (avl-delete addr old))) + (when (eq old (setq old (sb-ext:cas *all-threads* old new))) + (return))))))) (defvar sb-ext:*invoke-debugger-hook* nil "This is either NIL or a designator for a function of two arguments, @@ -1386,14 +1587,14 @@ on this semaphore, then N of them is woken up." called by BREAK.") (defun %exit-other-threads () - ;; Grabbing this lock prevents new threads from - ;; being spawned, and guarantees that *ALL-THREADS* - ;; is up to date. (with-deadline (:seconds nil :override t) - (sb-impl::finalizer-thread-stop) + ;; Grabbing this lock prevents new threads from + ;; being spawned, and guarantees that *ALL-THREADS* + ;; is up to date. (grab-mutex *make-thread-lock*) + #+sb-thread (sb-impl::finalizer-thread-stop) (let ((timeout sb-ext:*exit-timeout*) - (code *exit-in-process*) + (code *exit-in-progress*) (current *current-thread*) (joinees nil) (main nil)) @@ -1418,12 +1619,14 @@ on this semaphore, then N of them is woken up." ;; Need to defer till others have joined, because when main ;; thread exits, we're gone. Can't use TERMINATE-THREAD -- would ;; get the exit code wrong. + ;; This isn't a problem if *forcibly-terminate-threads-on-exit* is NIL - + ;; the thread that calls EXIT provides the exit code. It's that simple. (when main (handler-case (interrupt-thread main (lambda () - (setf *exit-in-process* (list code)) + (setf *exit-in-progress* (list code)) (throw 'sb-impl::%end-of-the-world t))) (interrupt-thread-error ())) ;; Normally this never finishes, as once the main-thread unwinds we @@ -1432,6 +1635,7 @@ on this semaphore, then N of them is woken up." ;; to calling OS-EXIT. (join-thread main :default t :timeout (time-left))))))) +;;; Pretty much don't use this. It has the same problems as %EXIT-OTHER-THREADS. (defun terminate-session () "Kill all threads in session except for this one. Does nothing if current thread is not the foreground thread." @@ -1552,46 +1756,165 @@ session." ;;;; The beef - +#+sb-thread +(progn +;;; Return T if the thread was created +(defun os-thread-create (thread thread-sap) + (aver (memq thread *starting-threads*)) + #+(or arm mips) + (bug "This and many other things will crash on MIPS/ARM either + until they do linkage tables like everyone else, or until all those + things can deal with either way of doing linkage.") + #+win32 + (/= 0 (alien-funcall (extern-alien "create_thread" + (function unsigned system-area-pointer)) + thread-sap)) + #-win32 + (let ((attr (foreign-symbol-sap "new_lisp_thread_attr" t)) + (c-tramp + (foreign-symbol-sap #+os-thread-stack "new_thread_trampoline_switch_stack" + #-os-thread-stack "new_thread_trampoline"))) + (and (= 0 #+os-thread-stack + (alien-funcall (extern-alien "pthread_attr_setstacksize" + (function int system-area-pointer unsigned)) + attr sb-unix::pthread-min-stack) + #-os-thread-stack + (with-alien ((setstack (function int system-area-pointer system-area-pointer + unsigned) :extern "pthread_attr_setstack")) + #+c-stack-is-control-stack + (alien-funcall setstack attr + (sap-ref-sap thread-sap (ash sb-vm::thread-control-stack-start-slot + sb-vm:word-shift)) + (extern-alien "thread_control_stack_size" unsigned)) + #-c-stack-is-control-stack + (alien-funcall setstack attr + (sap-ref-sap thread-sap (ash sb-vm::thread-alien-stack-start-slot + sb-vm:word-shift)) + (extern-alien "thread_alien_stack_size" unsigned)))) + ;; From "Workaround a problem ... on NetBSD" (git rev af8c4a2933) + ;; If I had to guess, it wrongly assumed existence of memory outside of + ;; the exactly provided stack bounds. + #+netbsd + (= 0 (with-alien ((setguard (function int system-area-pointer unsigned) + :extern "pthread_attr_setguardsize")) + (alien-funcall setguard attr 0))) + (with-pinned-objects (thread) + (= 0 (alien-funcall + (extern-alien "pthread_create" + (function int system-area-pointer system-area-pointer + system-area-pointer system-area-pointer)) + (struct-slot-sap thread thread os-thread) attr c-tramp thread-sap)))))) + +(defmacro free-thread-struct (memory) + `(alien-funcall (extern-alien "free_thread_struct" (function void system-area-pointer)) + ,memory)) + +(defun primitive-join (thread dispose) + ;; It's safe to read from the other thread's memory, because the current thread + ;; has ownership of that memory now. And we can't call this on a FOREIGN-THREAD. + (let ((c-thread (descriptor-sap (thread-startup-info thread)))) + (setf (thread-startup-info thread) 0) + ;; Clean up *ALL-THREADS* + (delete-from-all-threads (sap-int c-thread)) + ;; Release the OS and/or pthread resources + #+win32 + (with-alien ((wait (function unsigned unsigned unsigned) :extern "WaitForSingleObject") + (close (function int unsigned) :extern "CloseHandle")) + (let ((os-thread (sap-ref-word c-thread + (ash sb-vm::thread-os-thread-slot sb-vm::word-shift)))) + (alien-funcall wait os-thread #xffffffff) + (alien-funcall close os-thread))) + #-win32 + (with-alien ((join (function int unsigned unsigned) :extern "pthread_join")) + (alien-funcall join (thread-os-thread thread) 0) ; no result pointer + (setf (thread-os-thread thread) 0)) + (cond (dispose + (free-thread-struct c-thread) + nil) + (t ; Return the originally mapped address + (sap-ref-sap c-thread (ash sb-vm::thread-os-address-slot sb-vm:word-shift)))))) + +;;; Helper for SB-POSIX:FORK so that the child starts with no joinable threads. +;;; It might work to just set *JOINABLE-THREADS* to NIL in the child, but it's better to prune +;;; the *ALL-THREADS* tree as well. Must be called with the *MAKE-THREAD-LOCK* held +;;; or interrupts inhibited or both. +;;; Heuristic decides when to stop trying to free. Passing in #'IDENTITY means that +;;; all joinables should be processed. Passing in #'CDR or #'CDDR returns early if there +;;; are not at least 1 or 2 threads respectively that could be joined. +(export '%dispose-thread-structs) +(defun %dispose-thread-structs (&key (retain 0)) + (loop (unless (nthcdr retain *joinable-threads*) (return)) + (let ((item (sb-ext:atomic-pop *joinable-threads*))) + (if item (primitive-join item t) (return))))) + +;;; Allocate lisp thread memory, attempting first to join any exited +;;; threads, freeing their memory. Possibly reuse the memory from one of +;;; the exited threads, +;;; Why do it this way instead of having JOIN-THREAD just defer to pthread_join() ? +;;; Because the interface would be less lispy. e.g. what happens if you don't join +;;; a thread - do you leak the memory?; That's bad. GC doesn't clean up threads. +;;; It could if we used finalizers, but finalizers have an additional problem: +;;; if the user does call JOIN-THREAD then the finalizer should do nothing. +;;; But there's no "atomic pthread_join + cancel-finalization", short of blocking +;;; signals around the join perhaps. +;;; One more thing- it's illegal to pthread_join() a thread more than once, +;;; but we allow JOIN-THREAD more than one. I think that's a bug. +;;; Ours has the meaning of "get result if done, otherwise wait" +;;; which is not the same as deallocation of the thread's OS resources. +(defun allocate-thread-memory () + (let ((reuse (let ((corpse (sb-ext:atomic-pop *joinable-threads*))) + (when corpse (primitive-join corpse nil))))) + ;; If there is more than 1 more joinable, join all but 1. + ;; Two threads could both find > 1 thread to join, and both do + ;; a join, leaving 0 to join. That's ok. + (%dispose-thread-structs :retain 1) + (let ((thread-sap (alien-funcall (extern-alien "alloc_thread_struct" + (function system-area-pointer + system-area-pointer)) + (or reuse (int-sap 0))))) + (when (and (not reuse) (/= (sap-int thread-sap) 0)) + ;; these would have been done already if reusing the memory + ;; of a completed thread. + (macrolet ((prot (fun) + `(alien-funcall (extern-alien ,fun (function void int + system-area-pointer)) + 1 thread-sap))) + (prot "protect_control_stack_guard_page") + (prot "protect_binding_stack_guard_page") + (prot "protect_alien_stack_guard_page"))) + (unless (= (sap-int thread-sap) 0) thread-sap)))) + +(defmacro thread-trampoline-defining-macro (&body body) ; NEW WAY + `(defun run () + (macrolet ((apply-real-function () + '(apply (svref (thread-startup-info *current-thread*) 2) + (prog1 (svref (thread-startup-info *current-thread*) 3) + (setf (thread-startup-info *current-thread*) 0))))) + (flet ((unmask-signals () + (let ((mask (svref (thread-startup-info *current-thread*) 4))) + (if mask + ;; If the original mask (at thread creation time) was provided, + ;; then restore exactly that mask. + (with-pinned-objects (mask) + (sb-unix::pthread-sigmask sb-unix::SIG_SETMASK mask nil)) + ;; Otherwise just do the usual thing + (sb-unix::pthread-sigmask sb-unix::SIG_UNBLOCK + (foreign-symbol-sap "thread_start_sigset" t) + nil))))) + ;; notinline keeps array off the call stack by getting it out of the curent frame + (declare (notinline unmask-signals)) + ;; Signals other than stop-for-GC are masked. The WITH/WITHOUT noise is + ;; pure cargo-cultism. + (without-interrupts (with-local-interrupts ,@body)))))) +) ; end PROGN ;;; All threads other than the initial thread start via this function. #+sb-thread -(defun new-lisp-thread-trampoline (thread setup-sem real-function arguments) - (init-thread-local-storage thread) - ;; Can't initiate GC before *current-thread* is set, otherwise the - ;; locks grabbed by SUB-GC wouldn't function. - ;; Other threads can GC with impunity. - (setf (thread-os-thread thread) (current-thread-os-thread) - (thread-stack-end thread) (get-lisp-obj-address sb-vm:*control-stack-end*) - (thread-primitive-thread thread) (sap-int (current-thread-sap))) - ;; *ALLOC-SIGNAL* is made thread-local by create_thread_struct() - ;; so this assigns into TLS, not the global value. - (setf sb-vm:*alloc-signal* *default-alloc-signal*) - #+linux (setf (thread-os-tid thread) (sb-gettid)) - (with-mutex ((thread-result-lock thread)) - (with-all-threads-lock - (let ((addr (get-lisp-obj-address sb-vm:*control-stack-start*))) - ;; If ADDR exists, then we have a bug in the thread exit handler. - ;; The workaround here would be to delete the old thread first, - ;; but I'd rather find out about the bug than bury it. - (aver (not (avl-find addr *all-threads*))) - (setq *all-threads* (avl-insert *all-threads* addr thread)))) - (let ((session *session*) - (session-cons (list thread))) - (with-session-lock (session) - (setf (cdr session-cons) (session-threads session) - (session-threads session) session-cons))) - (setf (thread-%alive-p thread) t) - - (when setup-sem - (signal-semaphore setup-sem) - ;; setup-sem was dx-allocated, set it to NIL so that the - ;; backtrace doesn't get confused - (setf setup-sem nil)) - +(thread-trampoline-defining-macro + (set-thread-control-stack-slots *current-thread*) ;; Using handling-end-of-the-world would be a bit tricky ;; due to other catches and interrupts, so we essentially ;; re-implement it here. Once and only once more. - (catch 'sb-impl::toplevel-catcher + (catch 'sb-impl::toplevel-catcher (catch 'sb-impl::%end-of-the-world (catch '%abort-thread (restart-bind ((abort @@ -1604,34 +1927,43 @@ session." (without-interrupts (unwind-protect (with-local-interrupts - (sb-unix::unblock-deferrable-signals) - (setf (thread-result thread) - (prog1 - (multiple-value-list + ;; New threads should start with SIGPROF blocked if profiling is enabled + ;; on just a subset of threads. Ideally we'd add to the blocked mask + ;; right now, but it suffices to just leave the enabling bit at its default + ;; of 0; at worst, one undesired signal would be received. + (when (eq *profiled-threads* :all) + (setf (sap-ref-8 (current-thread-sap) ; state_word.sprof_enable + (1+ (ash sb-vm:thread-state-word-slot sb-vm:word-shift))) + 1)) + (unmask-signals) + (let ((list + (multiple-value-list (unwind-protect (catch '%return-from-thread (sb-c::inspect-unwinding - (apply real-function arguments) + (apply-real-function) #'sb-di::catch-runaway-unwind)) - (when *exit-in-process* - (sb-impl::call-exit-hooks)))) - #+sb-safepoint - (sb-kernel::gc-safepoint)))) + (when (and *exit-in-progress* + (not (thread-ephemeral-p *current-thread*))) + (sb-impl::call-exit-hooks)))))) + #+sb-safepoint (sb-kernel::gc-safepoint) + (setf (thread-result *current-thread*) list))) ;; we're going down, can't handle interrupts ;; sanely anymore. gc remains enabled. - (block-deferrable-signals) + (with-alien ((%block (function int system-area-pointer) + :extern "block_deferrable_signals")) + (alien-funcall %block (int-sap 0))) ;; we don't want to run interrupts in a dead ;; thread when we leave without-interrupts. ;; this potentially causes important ;; interupts to be lost: sigint comes to ;; mind. (setq *interrupt-pending* nil) - #+sb-thruption + #+sb-safepoint (setq *thruption-pending* nil) - (handle-thread-exit thread - (get-lisp-obj-address - sb-vm:*control-stack-start*))))))))) - (values)) + (handle-thread-exit))))))) + ;; this returns to C, so return a single value + 0) (defun make-thread (function &key name arguments) "Create a new thread of NAME that runs FUNCTION with the argument @@ -1646,71 +1978,143 @@ See also: RETURN-FROM-THREAD, ABORT-THREAD." #-sb-thread (declare (ignore function name arguments)) #-sb-thread (error "Not supported in unithread builds.") #+sb-thread - (progn (assert (or (atom arguments) - (null (cdr (last arguments)))) - (arguments) - "Argument passed to ~S, ~S, is an improper list." - 'make-thread arguments) - (run-thread (%make-thread :name name) function arguments))) + (let ((name (when name (possibly-base-stringize name)))) + (assert (or (atom arguments) (null (cdr (last arguments)))) + (arguments) + "Argument passed to ~S, ~S, is an improper list." + 'make-thread arguments) + (start-thread (%make-thread name nil (make-semaphore :name name)) + (coerce function 'function) + (ensure-list arguments)))) ;;; System-internal use only #+sb-thread -(defun make-ephemeral-thread (name function arguments) - (run-thread (%make-thread :name name :%ephemeral-p t) function arguments)) - -;;; The purpose of splitting out RUN-THREAD from MAKE-THREAD is that when -;;; starting the finalizer thread, we might be able to do: -;;; (let ((thread (%make-thread :name "finalizer" :%ephemeral-p t))) -;;; (when (cas *finalizer-thread* nil thread) -;;; (run-thread thread ...) -;;; which is possibly an improvement in two ways: - -;;; (1) it ensures that there is no hidden state in the transition diagram -;;; when we are invisibly starting the finalizer thread but have not made it -;;; known to FINALIZER-THREAD-STOP that we are doing so. There would be a -;;; thread object published or not - and no "maybe starting" state. -;;; (2) imagine two threads, each of which actually GC'd - so the 'gc_happened' -;;; flag in gc-common.c is T for both - and each wants to start the finalizer. -;;; They both get all the way into NEW-LISP-THREAD-TRAMPOLINE, only for one -;;; to lose the CAS on *FINALIZER-THREAD*. It's a lot of overhead to start -;;; a thread that does nothing and then exits. -;;; -;;; But it's not all fun and games, because we'd have to figure out how to -;;; get FINALIZER-THREAD-STOP _not_ to attempt to join a thread that has not -;;; yet sprung into being as an OS-level thread. - +(defun make-system-thread (name function arguments symbol) + (let ((thread (%make-thread name t (make-semaphore :name name)))) + (when symbol + (aver (not (symbol-value symbol))) + (set symbol thread)) + (start-thread thread function arguments))) + +;;; This is the faster variant of RUN-THREAD that does not wait for the new +;;; thread to start executing before returning. #+sb-thread -(defun run-thread (thread function arguments) - (declare (inline make-semaphore - make-waitqueue - make-mutex)) - (let* ((setup-sem (make-semaphore :name "Thread setup semaphore")) - (real-function (coerce function 'function)) - (arguments (ensure-list arguments)) - #+(or win32 darwin) - (fp-modes (dpb 0 sb-vm:float-sticky-bits ;; clear accrued bits - (sb-vm:floating-point-modes)))) - (declare (dynamic-extent setup-sem)) - (dx-flet ((start-routine () - ;; Inherit parent thread's FP modes - #+(or win32 darwin) - (setf (sb-vm:floating-point-modes) fp-modes) - ;; As it is, this lambda must not cons until we are - ;; ready to run GC. Be careful. - (new-lisp-thread-trampoline thread setup-sem - real-function arguments))) - ;; Holding mutexes or waiting on sempahores inside WITHOUT-GCING will lock up - (aver (not *gc-inhibit*)) - ;; Keep INITIAL-FUNCTION in the dynamic extent until the child - ;; thread is initialized properly. Wrap the whole thing in - ;; WITHOUT-INTERRUPTS (via WITH-SYSTEM-MUTEX) because we pass - ;; INITIAL-FUNCTION to another thread. - ;; (Does WITHOUT-INTERRUPTS really matter now that it's DXed?) - (with-system-mutex (*make-thread-lock*) - (if (zerop (%create-thread (get-lisp-obj-address #'start-routine))) - (setf thread nil) - (wait-on-semaphore setup-sem))))) - (or thread (error "Could not create a new thread."))) +(defun start-thread (thread function arguments) + (let* ((trampoline + (lambda (arg) + ;; If an error occurs prior to getting the thread into a consistent lisp state, + ;; there's no chance of debugging anything anyway. + (declare (optimize (safety 0))) + (let ((new-thread + (%make-lisp-obj (logior (get-lisp-obj-address arg) + sb-vm:instance-pointer-lowtag)))) + ;; Now that this thread is known to GC, NEW-THREAD is either implicitly + ;; pinned (on conservative gc) or movable. It can hance be deleted from + ;; *STARTING-THREADS* list which occurs lazily on the next MAKE-THREAD. + ;; To avoid unnecessary GC work meanwhile, smash the cell in *STARTING-THREADS* + ;; that points to NEW-THREAD. That cell is pointed to by the startup-info. + (rplaca (svref (thread-startup-info new-thread) 1) 0) + (init-thread-local-storage new-thread) ; assign *CURRENT-THREAD* + ;; Expose this thread in *ALL-THREADS*. + ;; Why not set this before calling pthread_create() ? If it fails there should + ;; be no transient effect on the list of all threads. But it's indeterminate + ;; whether the creating or created thread will make progress first, + ;; so they both do this assignment. + (setf (thread-%visible new-thread) 1) + ;; Foreign threads don't pass the saved FP modes, so the modes have to be + ;; restored here and not in RUN. + #+(or win32 darwin freebsd) + (setf (sb-vm:floating-point-modes) + (svref (thread-startup-info *current-thread*) 5))) + (run))) + (saved-sigmask (make-array (* sb-unix::sizeof-sigset_t sb-vm:n-byte-bits) + :element-type 'bit :initial-element 0)) + (child-sigmask (make-array (* sb-unix::sizeof-sigset_t sb-vm:n-byte-bits) + :element-type 'bit :initial-element 0)) + (created)) + (declare (truly-dynamic-extent saved-sigmask child-sigmask)) + (with-pinned-objects (saved-sigmask child-sigmask) ; if not stack-allocated + ;; Block deferrables to ensure that the new thread is unaffected by signals + ;; before the various interrupt-related special vars are set up. + ;; Preserve the current mask into SAVED-SIGMASK and CHILD-SIGMASK. + (sb-unix::pthread-sigmask sb-unix::SIG_BLOCK + (foreign-symbol-sap "thread_start_sigset" t) + saved-sigmask) + (replace child-sigmask saved-sigmask) + ;; Ensure that timers and interrupt-thread are directed only to "user" threads. + #+unix + (when (thread-ephemeral-p thread) + (with-alien ((sigaddset (function int system-area-pointer int) :extern "sigaddset")) + ;; It is essentially impossible to call INTERRUPT-THREAD on the finalizer + ;; thread, as it spends most of its time with interrupts disabled. + ;; So it doesn't much matter if SIGURG is added to the signal mask here. + ;; Unfortunately, this means that SB-INTROSPECT's MAP-ROOTS will hang + ;; if you give it the finalizer thread. + ;; The right answer may be that introspect needs to utilize some kind + ;; of stop-the-thread API that it shares in common with stop-the-world. + (alien-funcall sigaddset (vector-sap child-sigmask) sb-unix:sigalrm)))) + (binding* ((thread-sap (allocate-thread-memory) :EXIT-IF-NULL) + (cell (list thread)) + (startup-info + (vector trampoline cell function arguments + (if (position 1 child-sigmask) ; if there are any signals masked + (copy-seq child-sigmask) ; heap-allocate to pass to the new thread + nil) ; otherwise, don't pass the saved mask + ;; pass fp modes if neccessary, clearing the accrued exception bits + (+ #+(or win32 darwin freebsd) + (dpb 0 sb-vm:float-sticky-bits (sb-vm:floating-point-modes)))))) + (setf (thread-primitive-thread thread) (sap-int thread-sap) + (thread-startup-info thread) startup-info) + ;; Add new thread to *ALL-THREADS* now so that if the creator asserts + ;; something about "all" threads, it can find the new thread. + ;; But there is a slight ploy involved: the thread does not appear in + ;; (LIST-ALL-THREADS) until a POSIX thread is successfully started. + (setf (thread-%visible thread) 0) + (update-all-threads (sap-int thread-sap) thread) + (when *session* + (sb-ext:atomic-push thread (session-new-enrollees *session*))) + ;; Absence of the startup semaphore notwithstanding, creation is synchronized + ;; so that we can prevent new threads from starting, typically in SB-POSIX:FORK + ;; or SAVE-LISP-AND-DIE. + ;; The locks also guards access to *STARTING-THREADS* - a lockfree list wouldn't + ;; improve concurrency, as long as creation is synchronized anyway. + (dx-flet ((thunk () + ;; Consing THREAD into *STARTING-THREADS* pins it as well as some elements + ;; of startup-info. Consequently those objects can be safely manipulated + ;; from C before inserting the thread into 'all_threads'. + ;; Assuming that new threads are scheduled by the OS as fast as we can create + ;; them, there should usually be only one item to delete from *STARTING-THREADS*. + (let ((old (delete 0 *starting-threads*))) + (setf *starting-threads* (rplacd cell old)) + (barrier (:write)) + ;; Assign the thread's *CURRENT-THREAD*. This is GC-safe because + ;; the thread instance is pinned via *STARTING-THREADS*. + (setf (sap-ref-lispobj thread-sap (ash sb-vm::thread-lisp-thread-slot + sb-vm:word-shift)) + thread) + (setq created (os-thread-create thread thread-sap)) + (cond (created + ;; Still holding the MAKE-THREAD-LOCK, expose the thread in *all-threads*. + ;; In this manner, anyone who acquires the MAKE-THREAD-LOCK can be sure that + ;; (list-all-threads) enumerates every running thread. + ;; On CPUs where CAS can spuriously fail, this probably needs to loop and retry. + ;; It's ok if the thread changed 0 -> {1 | -1}, then failure here is correct. + (sb-ext:cas (thread-%visible thread) 0 1)) + (t ; unlikely. Out of memory perhaps? + (setq *starting-threads* old)))))) + ;; System threads are created with the mutex already held + (if (thread-ephemeral-p thread) + (thunk) + (sb-thread::call-with-system-mutex #'thunk *make-thread-lock*))) + (unless created ; Remove side-effects of trying to create + (delete-from-all-threads (sap-int thread-sap)) + (when *session* + (%delete-thread-from-session thread)) + (free-thread-struct thread-sap))) + (with-pinned-objects (saved-sigmask) + (sb-unix::pthread-sigmask sb-unix::SIG_SETMASK saved-sigmask nil)) + (if created thread (error "Could not create new OS thread.")))) + (defun join-thread (thread &key (default nil defaultp) timeout) "Suspend current thread until THREAD exits. Return the result values @@ -1733,30 +2137,44 @@ Trying to join the main thread causes JOIN-THREAD to block until TIMEOUT occurs or the process exits: when the main thread exits, the entire process exits. +Users should not rely on the ability to join a chosen THREAD from more +than one other thread simultaneously. Future changes to JOIN-THREAD may +directly call the underlying thread library, and not all threading +implementations consider such usage to be well-defined. + NOTE: Return convention in case of a timeout is experimental and subject to change." (when (eq thread *current-thread*) (error 'join-thread-error :thread thread :problem :self-join)) - (let ((lock (thread-result-lock thread)) - (got-it nil) - (problem :timeout)) - (without-interrupts - (unwind-protect - (cond - ((not (setf got-it - (allow-with-interrupts - ;; Don't use the timeout if the thread is - ;; not alive anymore. - (grab-mutex lock :timeout (and (thread-alive-p thread) - timeout)))))) - ((listp (thread-result thread)) - (return-from join-thread - (values-list (thread-result thread)))) - (t - (setf problem :abort))) - (when got-it - (release-mutex lock)))) + ;; First, free up the pthread resources of any thread(s), not necessarily + ;; one we're tryinng to join. + #+sb-thread + (when (cddr *joinable-threads*) ; if strictly > 2 are joinable, + (without-interrupts (%dispose-thread-structs :retain 2))) + ;; No result semaphore indicates that there's nothing to wait for- + ;; the thread is either a foreign-thread, or finished running. + (let* ((semaphore (thread-semaphore thread)) + (problem + (cond (semaphore + (if (wait-on-semaphore semaphore :timeout timeout) nil :timeout)) + ((typep thread 'foreign-thread) :foreign)))) + (unless problem + (cond ((listp (thread-result thread)) + ;; Implementation note, were this to become a native pthread semaphore- + ;; we would need a sem_post() here to support concurrent join of THREAD + ;; from N>1 other threads, because the hypothetical sem_post() in HANDLE-THREAD-EXIT + ;; will only bump the count up by 1, and so at most 1 waiter would execute. + ;; [Alternatively - still hypothetically - HANDLE-THREAD-EXIT could sem_post() + ;; as many times as there are currently running threads, which seems iffy] + ;; And though it's potentially poor style to wait on a chosen thread from N>1 other + ;; threads, it happens, and users might rely on it, though POSIX specifically + ;; precludes that in the spec of pthread_join() which this isn't exactly. + ;; Also for what it's worth, the win32 WaitOnSingleObject and GetExitCodeThread + ;; APIs have no such prohibition as long as the object handle remains valid. + (return-from join-thread (values-list (thread-result thread)))) + (t + (setq problem :abort)))) (if defaultp (values default problem) (error 'join-thread-error :thread thread :problem problem)))) @@ -1764,33 +2182,30 @@ subject to change." (defun destroy-thread (thread) (terminate-thread thread)) -#-sb-xc-host (declaim (sb-ext:deprecated :late ("SBCL" "1.2.15") (function destroy-thread :replacement terminate-thread))) -(defmacro with-interruptions-lock ((thread) &body body) - `(with-system-mutex ((thread-interruptions-lock ,thread)) - ,@body)) - ;;; Called from the signal handler. -#-(or sb-thruption win32) +#-(or sb-safepoint win32) (defun run-interruption () - (let ((interruption (with-interruptions-lock (*current-thread*) + (let ((interruption (with-deathlok (*current-thread*) (pop (thread-interruptions *current-thread*))))) ;; If there is more to do, then resignal and let the normal ;; interrupt deferral mechanism take care of the rest. From the ;; OS's point of view the signal we are in the handler for is no ;; longer pending, so the signal will not be lost. (when (thread-interruptions *current-thread*) - (kill-safely (thread-os-thread *current-thread*) sb-unix:sigpipe)) + (sb-unix:raise sb-unix:sigurg)) + ;; FIXME: does this really respect the promised ordering of interruptions? + ;; It looks backwards to raise first and run the popped function second. (when interruption (funcall interruption)))) -#+sb-thruption +#+sb-safepoint (defun run-interruption (*current-internal-error-context*) (in-interruption () ;the non-thruption code does this in the signal handler - (let ((interruption (with-interruptions-lock (*current-thread*) + (let ((interruption (with-deathlok (*current-thread*) (pop (thread-interruptions *current-thread*))))) (when interruption (funcall interruption) @@ -1813,7 +2228,19 @@ subject to change." ;; -- DFL (setf *thruption-pending* t))))) +#+linux +(defun thread-os-tid (thread) + (declare (ignorable thread)) + (if (eq *current-thread* thread) + (my-kernel-thread-id) + (with-deathlok (thread c-thread) + (unless (= c-thread 0) + (sap-ref-32 (int-sap c-thread) + (+ (ash sb-vm::thread-os-kernel-tid-slot sb-vm:word-shift) + #+(and 64-bit big-endian) 4)))))) + (defun interrupt-thread (thread function) + (declare (ignorable thread)) "Interrupt THREAD and make it run FUNCTION. The interrupt is asynchronous, and can occur anywhere with the exception of @@ -1866,35 +2293,40 @@ the state of a thread: (interrupt-thread thread #'break) Short version: be careful out there." - #+(and (not sb-thread) win32) - #+(and (not sb-thread) win32) - (declare (ignore thread)) - (with-interrupt-bindings - (with-interrupts (funcall function))) - #-(and (not sb-thread) win32) - (let ((os-thread (thread-os-thread thread))) - (cond ((= os-thread (ldb (byte sb-vm:n-word-bits 0) -1)) - (error 'interrupt-thread-error :thread thread)) - (t - (let (invoked) - (with-interruptions-lock (thread) - ;; Append to the end of the interruptions queue. It's - ;; O(N), but it does not hurt to slow interruptors down a - ;; bit when the queue gets long. - (setf (thread-interruptions thread) - (append (thread-interruptions thread) - (list (lambda () - (setf invoked t) - (barrier (:memory)) - (without-interrupts - (allow-with-interrupts - (funcall function)))))))) - (when (and (minusp (wake-thread os-thread)) - ;; The interrupt queue has been processed by - ;; some other interrupt. - (progn (barrier (:memory)) - (not invoked))) - (error 'interrupt-thread-error :thread thread))))))) + ;; POSIX says: + ;; "If an application attempts to use a thread ID whose lifetime has ended, + ;; the behavior is undefined." + ;; so we use the death lock to keep the thread alive, unless it already isn't. + ;; + (when (with-deathlok (thread c-thread) + ;; Return T if couldn't interrupt. + (cond ((eql c-thread 0) t) + (t (%interrupt-thread thread function) nil))) + (error 'interrupt-thread-error :thread thread))) + +(defun %interrupt-thread (thread function) + ;; Append to the end of the interruptions queue. It's + ;; O(N), but it does not hurt to slow interruptors down a + ;; bit when the queue gets long. + (setf (thread-interruptions thread) + (append (thread-interruptions thread) + ;; It seems to me that this junk should be in RUN-INTERRUPTION, + ;; but it doesn't really matter where it goes. + (list (lambda () + (barrier (:memory)) ; why??? + (without-interrupts (allow-with-interrupts (funcall function))))))) + ;; We use SIGURG because it satisfies a lot of requirements that + ;; other people have thought about more than we have. + ;; See https://golang.org/src/runtime/signal_unix.go where they describe + ;; which signal works best for their sigPreempt. + ;; It's basically the same use-case as here. + #-sb-safepoint (sb-unix:pthread-kill (thread-os-thread thread) sb-unix:sigurg) + #+sb-safepoint + (with-alien ((wake (function void system-area-pointer) :extern "wake_thread")) + (with-pinned-objects (thread) + (alien-funcall wake (sap+ (int-sap (get-lisp-obj-address thread)) + (- sb-vm:instance-pointer-lowtag))))) + nil) (defun terminate-thread (thread) "Terminate the thread identified by THREAD, by interrupting it and @@ -1947,34 +2379,28 @@ assume that unknown code can safely be terminated using TERMINATE-THREAD." ;;; should probably discuss with a professional psychiatrist first #+sb-thread (progn - (sb-ext:define-load-time-global sb-vm::*free-tls-index* 0) - (defun %symbol-value-in-thread (symbol thread) - ;; Prevent the thread from dying completely while we look for the TLS - ;; area... - (with-all-threads-lock - (if (thread-alive-p thread) - (let ((val (sap-ref-lispobj (int-sap (thread-primitive-thread thread)) - (symbol-tls-index symbol)))) - (case (get-lisp-obj-address val) - (#.sb-vm:no-tls-value-marker-widetag (values nil :no-tls-value)) - (#.sb-vm:unbound-marker-widetag (values nil :unbound-in-thread)) - (t (values val :ok)))) + (defun %symbol-value-in-thread (symbol thread &aux (tlsindex (symbol-tls-index symbol))) + (with-deathlok (thread c-thread) + (if (/= c-thread 0) + ;; Avoid loading not-really-an-object markers into a descriptor register. + (macrolet ((read-using (reader) `(,reader (int-sap c-thread) tlsindex))) + (let ((bits (read-using sap-ref-word))) + (cond ((eql bits sb-vm:no-tls-value-marker) (values nil :no-tls-value)) + ((eql (logand bits sb-vm:widetag-mask) sb-vm:unbound-marker-widetag) + (values nil :unbound-in-thread)) + (t (values (read-using sap-ref-lispobj) :ok))))) (values nil :thread-dead)))) (defun %set-symbol-value-in-thread (symbol thread value) - ;; Prevent the thread from dying completely while we look for the TLS - ;; area... - (with-all-threads-lock - (if (thread-alive-p thread) + (with-deathlok (thread c-thread) + (if (/= c-thread 0) (let ((offset (symbol-tls-index symbol))) (cond ((zerop offset) (values nil :no-tls-value)) (t - (setf (sap-ref-lispobj (int-sap (thread-primitive-thread thread)) - offset) - value) + (setf (sap-ref-lispobj (int-sap c-thread) offset) value) (values value :ok)))) (values nil :thread-dead)))) @@ -1987,20 +2413,23 @@ assume that unknown code can safely be terminated using TERMINATE-THREAD." ;; (raw value) manifesting in Lisp as a fixnum. ;; The sign bit of sb-vm::*free-tls-index* is a semaphore, ;; except on PPC where it isn't, but masking is fine in any case. - (do ((index (- (ash (logand sb-vm::*free-tls-index* sb-xc:most-positive-fixnum) + (do ((index (- (ash (logand sb-vm::*free-tls-index* most-positive-fixnum) sb-vm:n-fixnum-tag-bits) sb-vm:n-word-bytes) (- index sb-vm:n-word-bytes)) - ;; (There's no reason this couldn't work on any thread now.) - (sap (int-sap (thread-primitive-thread *current-thread*))) + ;; (There's almost no reason this couldn't work on any thread.) + (sap (current-thread-sap)) (list)) ((< index (ash sb-vm::primitive-thread-object-length sb-vm:word-shift)) list) - (let ((obj (sap-ref-lispobj sap index))) - (when (and obj ; don't bother returning NIL - (sb-vm:is-lisp-pointer (get-lisp-obj-address obj)) - (not (memq obj list))) - (push obj list)))))) + ;; NO-TLS-VALUE-MARKER may or may not satisfy IS-LISP-POINTER, + ;; so be sure to exclude it in case it does. + (unless (eql (sap-ref-word sap index) sb-vm:no-tls-value-marker) + (let ((obj (sap-ref-lispobj sap index))) + (when (and obj ; don't bother returning NIL + (sb-vm:is-lisp-pointer (get-lisp-obj-address obj)) + (not (memq obj list))) + (push obj list))))))) (defun symbol-value-in-thread (symbol thread &optional (errorp t)) "Return the local value of SYMBOL in THREAD, and a secondary value of T @@ -2067,57 +2496,42 @@ mechanism for inter-thread communication." ;;; Here's the problem: Some of the backends implement those semantics as dictated ;;; by globaldb - assigning into TLS even if the current TLS value is NO_TLS_VALUE; ;;; while others do not make use of that information, and will therefore assign into -;;; the global value if the TLS value is NO_TLS_VALUE. +;;; the symbol-global-value if the TLS value is NO_TLS_VALUE. ;;; This can not be "corrected" by genesis - there is no TLS when genesis executes. -;;; The only way to do this reliably is to compute the address of the thread-local -;;; storage slot, and use (SETF SAP-REF-LISPOBJ) -;;; (Nor is #+(vop-translates ensure-symbol-tls-index) a reliable indicator that the +;;; The only way to do this uniformly for all the platforms is to compute the address +;;; of the thread-local storage slot, and use (SETF SAP-REF-LISPOBJ) on that. +;;; (Existence of a vop for ENSURE-SYMBOL-TLS-INDEX is not an indicator that the ;;; SET vop will assign into a thread-local symbol that currently has no TLS value.) - -;;; Note also that this is called by REINIT, which _should_ reinitialize -;;; the *CURRENT-THREAD* but should _NOT_ reinitialize anything else. -;;; That's actually kind of weird, but it's necessary to ensure that *RESTART-CLUSTERS* -;;; does not get clobbered if there were any restarts available. -;;; There's a SAVE-LISP-AND-DIE test which asserts that you can resume -;;; from a failed save. -;;; It might behoove us to pass in a flag as to whether this is coming from REINIT, -;;; but INIT-INITIAL-THREAD doesn't know either. We'd have to plumb a new flag -;;; down all the way from SAVE. (defun init-thread-local-storage (thread) ;; In addition to wanting the expressly unsafe variant of SYMBOL-VALUE, any error ;; signaled such as invalid-arg-count would just go totally wrong at this point. (declare (optimize (safety 0))) #-sb-thread - ;; *CURRENT-THREAD* is known always bound, so BOUNDP would be T - ;; We need to see whether it's really boundp. - (if (unbound-marker-p *current-thread*) - (macrolet ((expand () - `(setf ,@(apply #'append (cdr *thread-local-specials*))))) - (expand)) - (setf *current-thread* thread)) + (macrolet ((expand () `(setf ,@(apply #'append (cdr *thread-local-specials*))))) + (expand)) ;; See %SET-SYMBOL-VALUE-IN-THREAD for comparison's sake #+sb-thread (let ((sap (current-thread-sap))) (macrolet ((expand () - `(if (= (sap-ref-word sap ,(info :variable :wired-tls '*current-thread*)) - sb-vm:no-tls-value-marker-widetag) - (setf ,@(loop for (var form) in (cdr *thread-local-specials*) - for index = (info :variable :wired-tls var) - append `((sap-ref-lispobj sap ,index) ,form))) - (setf *current-thread* thread)))) + `(setf ,@(loop for (var form) in (cdr *thread-local-specials*) + for index = (info :variable :wired-tls var) + append `((sap-ref-lispobj sap ,index) ,form))))) (expand))) - nil) + ;; Straightforwardly assign *current-thread* because it's never the NO-TLS-VALUE marker. + ;; I wonder how to to prevent user code from doing this, but it isn't a new problem per se. + ;; Perhaps this should be symbol-macro with a vop behind it and no setf expander. + (setf *current-thread* thread) + thread) (eval-when (:compile-toplevel) ;; Inform genesis of the index <-> symbol mapping made by DEFINE-THREAD-LOCAL - (with-open-file (output (sb-cold:stem-object-path "tls-init.lisp-expr" - '(:extra-artifact) :target-compile) + (with-open-file (output (sb-cold:find-bootstrap-file "output/tls-init.lisp-expr" t) :direction :output :if-exists :supersede) (let ((list (mapcar (lambda (x &aux (symbol (car x))) (cons (info :variable :wired-tls symbol) symbol)) (cdr *thread-local-specials*))) (*package* *keyword-package*)) - (write list :stream output :readably t) + (write list :stream output :readably t :pretty nil) (terpri output))) ;; Prevent further use of DEFINE-THREAD-LOCAL after compiling this file ;; because the definition of INIT-THREAD-LOCAL-STORAGE is now frozen. @@ -2136,44 +2550,49 @@ mechanism for inter-thread communication." ;;;; Diagnostic tool -#+(and sb-thread sb-devel) +#+sb-devel (defun dump-thread () - (let* ((primobj (find 'sb-vm::thread sb-vm:*primitive-objects* - :key #'sb-vm::primitive-object-name)) + (let* ((primobj (sb-vm::primitive-object 'sb-vm::thread)) (slots (sb-vm::primitive-object-slots primobj)) (sap (current-thread-sap)) (thread-obj-len (sb-vm::primitive-object-length primobj)) (names (make-array thread-obj-len :initial-element ""))) - (dolist (slot slots) - (setf (aref names (sb-vm::slot-offset slot)) (sb-vm::slot-name slot))) - (flet ((safely-read (sap offset) - (let ((word (sap-ref-word sap offset))) - (cond ((= word sb-vm:no-tls-value-marker-widetag) :no-tls-value) - ((= word sb-vm:unbound-marker-widetag) :unbound) - (t (sap-ref-lispobj sap offset))))) - (show (tlsindex val &optional thread-slot-p) - (if thread-slot-p - (format t " ~3d ~30a : #x~x~%" - (ash tlsindex (- sb-vm:word-shift)) - (aref names (ash tlsindex (- sb-vm:word-shift))) - val) - (let ((*print-right-margin* 128) - (*print-lines* 4)) - (format t " ~3d ~30a : ~s~%" - (ash tlsindex (- sb-vm:word-shift)) - ;; FIND-SYMBOL-FROM-TLS-INDEX uses MAP-ALLOCATED-OBJECTS - ;; which is not defined during cross-compilation. - (funcall 'sb-ext::find-symbol-from-tls-index tlsindex) - val))))) + (loop for slot across slots + do + (setf (aref names (sb-vm::slot-offset slot)) (sb-vm::slot-name slot))) + (flet ((safely-read (sap offset &aux (bits (sap-ref-word sap offset))) + (cond ((eql bits sb-vm:no-tls-value-marker) :no-tls-value) + ((eql (logand bits sb-vm:widetag-mask) sb-vm:unbound-marker-widetag) :unbound) + (t (sap-ref-lispobj sap offset)))) + (show (sym val) + (let ((*print-right-margin* 128) + (*print-lines* 4)) + (format t " ~3d ~30a : ~s~%" + #+sb-thread (ash sym (- sb-vm:word-shift)) + #-sb-thread 0 + ;; FIND-SYMBOL-FROM-TLS-INDEX uses MAP-ALLOCATED-OBJECTS + ;; which is not defined during cross-compilation. + #+sb-thread (funcall 'sb-impl::find-symbol-from-tls-index sym) + #-sb-thread sym + val)))) (format t "~&TLS: (base=~x)~%" (sap-int sap)) (loop for tlsindex from sb-vm:n-word-bytes below - (ash sb-vm::*free-tls-index* sb-vm:n-fixnum-tag-bits) + #+sb-thread (ash sb-vm::*free-tls-index* sb-vm:n-fixnum-tag-bits) + #-sb-thread (ash thread-obj-len sb-vm:word-shift) by sb-vm:n-word-bytes - do (if (< tlsindex (ash thread-obj-len sb-vm:word-shift)) - (show tlsindex (sap-ref-word sap tlsindex) t) - (let ((val (safely-read sap tlsindex))) - (unless (eq val :no-tls-value) - (show tlsindex val))))) + do + (unless (<= sb-vm::thread-obj-size-histo-slot + (ash tlsindex (- sb-vm:word-shift)) + (+ sb-vm::thread-obj-size-histo-slot (1- sb-vm:n-word-bits))) + (let ((thread-slot-name + (if (< tlsindex (ash thread-obj-len sb-vm:word-shift)) + (aref names (ash tlsindex (- sb-vm:word-shift)))))) + (if (and thread-slot-name (neq thread-slot-name 'sb-vm::lisp-thread)) + (format t " ~3d ~30a : #x~x~%" (ash tlsindex (- sb-vm:word-shift)) + thread-slot-name (sap-ref-word sap tlsindex)) + (let ((val (safely-read sap tlsindex))) + (unless (eq val :no-tls-value) + (show tlsindex val))))))) (let ((from (descriptor-sap sb-vm:*binding-stack-start*)) (to (binding-stack-pointer-sap))) (format t "~%Binding stack: (depth ~d)~%" @@ -2181,6 +2600,83 @@ mechanism for inter-thread communication." (loop (when (sap>= from to) (return)) (let ((val (safely-read from 0)) - (tlsindex (sap-ref-word from sb-vm:n-word-bytes))) - (show tlsindex val)) + (sym #+sb-thread (sap-ref-word from sb-vm:n-word-bytes) ; a TLS index + #-sb-thread (sap-ref-lispobj from sb-vm:n-word-bytes))) + (show sym val)) (setq from (sap+ from (* sb-vm:binding-size sb-vm:n-word-bytes)))))))) + +#+allocator-metrics +(macrolet ((histogram-value (c-thread index) + `(sap-ref-word (int-sap ,c-thread) + (ash (+ sb-vm::thread-obj-size-histo-slot ,index) + sb-vm:word-shift))) + (metric (c-thread slot) + `(sap-ref-word (int-sap ,c-thread) + (ash ,slot sb-vm:word-shift)))) +(export '(print-allocator-histogram reset-allocator-histogram)) +(defun allocator-histogram (&optional (thread *current-thread*)) + (if (eq thread :all) + (labels ((vector-sum (a b) + (let ((result (make-array (max (length a) (length b)) + :element-type 'fixnum))) + (dotimes (i (length result) result) + (setf (aref result i) + (+ (if (< i (length a)) (aref a i) 0) + (if (< i (length b)) (aref b i) 0)))))) + (sum (a b) + (cond ((null a) b) + ((null b) a) + (t (cons (vector-sum (car a) (car b)) + (mapcar #'+ (cdr a) (cdr b))))))) + (reduce #'sum + ;; what about the finalizer thread? + (mapcar 'allocator-histogram (list-all-threads)))) + (with-deathlok (thread c-thread) + (unless (= c-thread 0) + (dx-let ((a (make-array (+ sb-vm::histogram-small-bins sb-vm:n-word-bits) + :element-type 'fixnum))) + (dotimes (i (length a)) + (setf (aref a i) (histogram-value c-thread i))) + (list (subseq a 0 (1+ (or (position 0 a :from-end t :test #'/=) -1))) + (metric c-thread sb-vm::thread-tot-bytes-alloc-boxed-slot) + (metric c-thread sb-vm::thread-tot-bytes-alloc-unboxed-slot) + (metric c-thread sb-vm::thread-slow-path-allocs-slot) + (metric c-thread sb-vm::thread-et-allocator-mutex-acq-slot) + (metric c-thread sb-vm::thread-et-find-freeish-page-slot) + (metric c-thread sb-vm::thread-et-bzeroing-slot))))))) + +(defun reset-allocator-histogram (&optional (thread *current-thread*)) + (with-deathlok (thread c-thread) + (unless (= c-thread 0) + (setf (metric c-thread sb-vm::thread-tot-bytes-alloc-boxed-slot) 0 + (metric c-thread sb-vm::thread-tot-bytes-alloc-unboxed-slot) 0 + (metric c-thread sb-vm::thread-slow-path-allocs-slot) 0) + (dotimes (i (+ sb-vm::histogram-small-bins sb-vm:n-word-bits)) + (setf (histogram-value c-thread i) 0))))) + +(defun print-allocator-histogram (&optional (thread *current-thread*)) + (destructuring-bind (bins tot-bytes-boxed tot-bytes-unboxed n-slow-path lock find clear) + (allocator-histogram thread) + (let ((total-objects (reduce #'+ bins)) + (cumulative 0)) + (format t "~& Size Count Cum%~%") + (loop for index from 0 + for count across bins + for size-exact-p = (< index sb-vm::histogram-small-bins) + for size = (if size-exact-p + (* (1+ index) 2 sb-vm:n-word-bytes) + (ash 1 (+ (- index sb-vm::histogram-small-bins) 10))) + do + (incf cumulative count) + (format t "~& ~10@a : ~8d ~6,2,2f~%" + (cond (size-exact-p size) + ((< size 1048576) (format nil "< ~d" size)) + (t (format nil "< 2^~d" (1- (integer-length size))))) + count (/ cumulative total-objects)) + (setq size (* size 2))) + (when (plusp total-objects) + (format t "Total: ~D+~D bytes, ~D objects, ~,2,2f% fast path~%" + tot-bytes-boxed tot-bytes-unboxed total-objects + (/ (- total-objects n-slow-path) total-objects))) + (format t "Times (sec): lock=~,,-9f find=~,,-9f clear=~,,-9f~%" + lock find clear))))) diff --git a/src/code/target-unicode.lisp b/src/code/target-unicode.lisp index 4beaec55b4..1868bc39e5 100644 --- a/src/code/target-unicode.lisp +++ b/src/code/target-unicode.lisp @@ -11,60 +11,40 @@ (in-package "SB-UNICODE") -(declaim (type simple-vector **special-numerics**)) -(sb-ext:define-load-time-global **special-numerics** - #.(sb-cold:read-from-file "output/numerics.lisp-expr")) - -(macrolet ((unicode-property-init () - (let ((confusable-sets - (sb-cold:read-from-file "output/confusables.lisp-expr")) - (bidi-mirroring-list - (sb-cold:read-from-file "output/bidi-mirrors.lisp-expr"))) - `(progn - (sb-ext:define-load-time-global **proplist-properties** nil) - (sb-ext:define-load-time-global **confusables** - ',confusable-sets) - (sb-ext:define-load-time-global **bidi-mirroring-glyphs** - ',bidi-mirroring-list) - (defun !unicode-properties-cold-init () - ;; - (let ((hash (make-hash-table :test 'eq)) - (list ',(sb-cold:read-from-file - "output/misc-properties.lisp-expr"))) - (setq **proplist-properties** hash) - (loop for (symbol ranges) on list by #'cddr - do (setf (gethash symbol hash) - (coerce ranges '(vector (unsigned-byte 32)))))) - ;; - (let* ((data ',confusable-sets) - (hash (make-hash-table :test #'eq - #+sb-unicode :size #+sb-unicode (length data)))) - (loop for (source . target) in data - when (and #-sb-unicode - (< source sb-xc:char-code-limit)) - do (flet ((minimize (x) - (case (length x) - (1 - (elt x 0)) - (2 - (pack-3-codepoints (elt x 0) (elt x 1))) - (3 - (pack-3-codepoints (elt x 0) (elt x 1) (elt x 2))) - (t - (logically-readonlyize - (possibly-base-stringize - (map 'string #'code-char x))))))) - - (setf (gethash (code-char source) hash) - (minimize target)))) - (setf **confusables** hash)) - ;; - (let* ((list ',bidi-mirroring-list) - (hash (make-hash-table :test #'eq :size (length list)))) - (loop for (k v) in list do - (setf (gethash k hash) v)) - (setf **bidi-mirroring-glyphs** hash))))))) - (unicode-property-init)) +(eval-when (:compile-toplevel) + (defun plist-to-alist (list) + (loop for (key value) on list by #'cddr collect (cons key value)))) +(eval-when (:compile-toplevel :load-toplevel :execute) + (defparameter *proplist-properties* + (mapcar (lambda (x) (cons (car x) (sb-xc:coerce (cdr x) '(vector (unsigned-byte 32))))) + '#.(plist-to-alist (sb-cold:read-from-file "output/misc-properties.lisp-expr"))))) + +(sb-ext:define-load-time-global **confusables** + (let ((data '#.(sb-cold:read-from-file "output/confusables.lisp-expr"))) + (sb-impl::%stuff-hash-table + (make-hash-table :test #'eq #+sb-unicode :size #+sb-unicode (length data)) + (loop for (source . target) in data + when (and #-sb-unicode (< source char-code-limit)) + collect (flet ((minimize (x) + (case (length x) + (1 + (elt x 0)) + (2 + (pack-3-codepoints (elt x 0) (elt x 1))) + (3 + (pack-3-codepoints (elt x 0) (elt x 1) (elt x 2))) + (t + (logically-readonlyize + (possibly-base-stringize (map 'string #'code-char x))))))) + (cons (code-char source) (minimize target)))) + t))) + +(sb-ext:define-load-time-global **bidi-mirroring-glyphs** + (let ((list '#.(sb-cold:read-from-file "output/bidi-mirrors.lisp-expr"))) + (sb-impl::%stuff-hash-table + (make-hash-table :test #'eq :size (length list)) + (loop for (k v) in list collect (cons k v)) + t))) ;;; Unicode property access (defun ordered-ranges-member (item vector) @@ -114,8 +94,19 @@ "Returns T if CHARACTER has the specified PROPERTY. PROPERTY is a keyword representing one of the properties from PropList.txt, with underscores replaced by dashes." - (ordered-ranges-member (char-code character) - (gethash property **proplist-properties**))) + (macrolet ((get-ub32-vector () + ;; This ECASE gets optimized into parallel arrays, + ;; and does not depend on jump tables + `(ecase property ,@(mapcar (lambda (x) (list (car x) (cdr x))) + *proplist-properties*)))) + (ordered-ranges-member (char-code character) (get-ub32-vector)))) + +(define-compiler-macro proplist-p (&whole form character property) + (if (keywordp property) + `(ordered-ranges-member (char-code ,character) + ,(or (cdr (assoc property *proplist-properties*)) + (error "No such property ~S" property))) + form)) (eval-when (:compile-toplevel) (defvar *slurped-random-constants* @@ -143,12 +134,12 @@ with underscores replaced by dashes." :Bn (svref-or-null #.(read-ucd-constant '*bidi-classes*) - (aref **character-misc-database** (1+ (misc-index character)))))) + (aref +character-misc-database+ (1+ (misc-index character)))))) (declaim (inline combining-class)) (defun combining-class (character) "Returns the canonical combining class (CCC) of CHARACTER" - (aref **character-misc-database** (+ 2 (misc-index character)))) + (aref +character-misc-database+ (+ 2 (misc-index character)))) (defun decimal-value (character) "Returns the decimal digit value associated with CHARACTER or NIL if @@ -168,7 +159,7 @@ All characters with decimal digit values have the same digit value, but there are characters (such as digits of number systems without a 0 value) that have a digit value but no decimal digit value" (let ((%digit (clear-flag 6 - (aref **character-misc-database** + (aref +character-misc-database+ (+ 3 (misc-index character)))))) (if (< %digit 10) %digit nil))) @@ -176,14 +167,22 @@ that have a digit value but no decimal digit value" "Returns the numeric value of CHARACTER or NIL if there is no such value. Numeric value is the most general of the Unicode numeric properties. The only constraint on the numeric value is that it be a rational number." - (or (double-vector-binary-search (char-code character) - **special-numerics**) + (or (gethash character + (load-time-value + (let ((list '#.(sb-cold:read-from-file "output/numerics.lisp-expr"))) + (sb-impl::%stuff-hash-table + (make-hash-table :test #'eq :size (length list)) + (loop for (k . v) in list + when (< k char-code-limit) + collect (cons (code-char k) v)) + t)) + t)) (digit-value character))) (defun mirrored-p (character) "Returns T if CHARACTER needs to be mirrored in bidirectional text. Otherwise, returns NIL." - (logbitp 5 (aref **character-misc-database** + (logbitp 5 (aref +character-misc-database+ (+ 5 (misc-index character))))) (defun bidi-mirroring-glyph (character) @@ -199,14 +198,14 @@ one of the keywords :N (Narrow), :A (Ambiguous), :H (Halfwidth), :W (Wide), :F (Fullwidth), or :NA (Not applicable)" (svref-or-null #.(read-ucd-constant '*east-asian-widths*) (ldb (byte 3 0) - (aref **character-misc-database** + (aref +character-misc-database+ (+ 5 (misc-index character)))))) (defun script (character) "Returns the Script property of CHARACTER as a keyword. If CHARACTER does not have a known script, returns :UNKNOWN" (svref-or-null #.(read-ucd-constant '*scripts*) - (aref **character-misc-database** (+ 6 (misc-index character))))) + (aref +character-misc-database+ (+ 6 (misc-index character))))) (defun char-block (character) "Returns the Unicode block in which CHARACTER resides as a keyword. @@ -214,7 +213,7 @@ If CHARACTER does not have a known block, returns :NO-BLOCK" (let* ((code (char-code character)) (block-index (ordered-ranges-position code - #.(sb-xc:coerce (sb-cold:read-from-file "output/block-ranges.lisp-expr") + #.(coerce (sb-cold:read-from-file "output/block-ranges.lisp-expr") '(vector (unsigned-byte 32)))))) (if block-index (aref #.(sb-cold:read-from-file "output/block-names.lisp-expr") block-index) @@ -227,15 +226,15 @@ This property has been officially obsoleted by the Unicode standard, and is only included for backwards compatibility." (let* ((char-code (char-code character)) (h-code (double-vector-binary-search char-code - **unicode-1-char-name-database**))) + +unicode-1-char-name-database+))) (when h-code - (huffman-decode h-code **unicode-character-name-huffman-tree**)))) + (huffman-decode h-code +unicode-character-name-huffman-tree+)))) (defun age (character) "Returns the version of Unicode in which CHARACTER was assigned as a pair of values, both integers, representing the major and minor version respectively. If CHARACTER is not assigned in Unicode, returns NIL for both values." - (let* ((value (aref **character-misc-database** (+ 8 (misc-index character)))) + (let* ((value (aref +character-misc-database+ (+ 8 (misc-index character)))) (major (ash value -3)) (minor (ldb (byte 3 0) value))) (if (zerop value) (values nil nil) (values major minor)))) @@ -261,15 +260,15 @@ If the character is not a Hangul syllable or Jamo, returns NIL" (defun line-break-class (character &key resolve) "Returns the line breaking class of CHARACTER, as specified in UAX #14. If :RESOLVE is NIL, returns the character class found in the property file. -If :RESOLVE is non-NIL, centain line-breaking classes will be mapped to othec -classes as specified in the applicable standards. Addinionally, if :RESOLVE +If :RESOLVE is non-NIL, certain line-breaking classes will be mapped to other +classes as specified in the applicable standards. Additionally, if :RESOLVE is :EAST-ASIAN, Ambigious (class :AI) characters will be mapped to the Ideographic (:ID) class instead of Alphabetic (:AL)." (when (and resolve (listp character)) (setf character (car character))) (when (and resolve (not character)) (return-from line-break-class :nil)) (let ((raw-class (svref-or-null #.(read-ucd-constant '*line-break-classes*) - (aref **character-misc-database** (+ 7 (misc-index character))))) + (aref +character-misc-database+ (+ 7 (misc-index character))))) (syllable-type (hangul-syllable-type character))) (when syllable-type (setf raw-class @@ -279,9 +278,9 @@ Ideographic (:ID) class instead of Alphabetic (:AL)." (when resolve (setf raw-class (case raw-class - (:ai (if (eql resolve :east-asion) :ID :AL)) + (:ai (if (eql resolve :east-asian) :ID :AL)) ; If we see :CM when resolving, we have a CM that isn't subject - ; to LB9, so we do LB10 + ; to LB9, so we do LB10 (:ZWJ handled in LINE-BREAK-ANNOTATE) ((:xx :cm) :al) (:sa (if (member (general-category character) '(:Mn :Mc)) :CM :AL)) @@ -347,7 +346,7 @@ disappears when accents are placed on top of it. and NIL otherwise" (eval-when (:compile-toplevel) (sb-xc:defmacro coerce-to-ordered-ranges (array) - (sb-xc:coerce array '(vector (unsigned-byte 32))))) + (coerce array '(vector (unsigned-byte 32))))) (defun default-ignorable-p (character) "Returns T if CHARACTER is a Default_Ignorable_Code_Point" @@ -367,7 +366,7 @@ disappears when accents are placed on top of it. and NIL otherwise" ;;; Implements UAX#15: Normalization Forms (declaim (inline char-decomposition-info)) (defun char-decomposition-info (char) - (let ((value (aref **character-misc-database** + (let ((value (aref +character-misc-database+ (+ 4 (misc-index char))))) (values (clear-flag 7 value) (logbitp 7 value)))) @@ -376,10 +375,10 @@ disappears when accents are placed on top of it. and NIL otherwise" ;; Caller should have gotten length from char-decomposition-info (let* ((cp (char-code char)) (cp-high (ash cp -8)) - (decompositions **character-decompositions**) - (high-page (aref **character-high-pages** cp-high)) + (decompositions +character-decompositions+) + (high-page (aref +character-high-pages+ cp-high)) (index (unless (logbitp 15 high-page) ;; Hangul syllable - (aref **character-low-pages** + (aref +character-low-pages+ (+ 1 (* 2 (+ (ldb (byte 8 0) cp) (ash high-page 8)))))))) (cond ((= length 1) (funcall callback (code-char (aref decompositions index)))) @@ -454,8 +453,7 @@ disappears when accents are placed on top of it. and NIL otherwise" (nreverse chars)))) (defun primary-composition (char1 char2) - (flet ((maybe (fn x) (when x (funcall fn x))) - (composition-hangul-syllable-type (cp) + (flet ((composition-hangul-syllable-type (cp) (cond ((and (<= #x1100 cp) (<= cp #x1112)) :L) ((and (<= #x1161 cp) (<= cp #x1175)) :V) @@ -465,19 +463,25 @@ disappears when accents are placed on top of it. and NIL otherwise" (declare (inline composition-hangul-syllable-type)) (let ((c1 (char-code char1)) (c2 (char-code char2))) - (maybe - #'code-char (cond ((gethash (dpb c1 (byte 21 21) c2) - **character-primary-compositions**)) + (load-time-value + (let ((data '#.(sb-cold:read-from-file "output/comp.lisp-expr"))) + (sb-impl::%stuff-hash-table + (make-hash-table :size (length data) #+64-bit :test #+64-bit #'eq) + (loop for pair across data + when (< (cdr pair) char-code-limit) ; Why is this even defined if #-sb-unicode? + collect (cons (car pair) (code-char (cdr pair)))) + t)) + t))) ((and (eql (composition-hangul-syllable-type c1) :L) (eql (composition-hangul-syllable-type c2) :V)) (let ((lindex (- c1 #x1100)) (vindex (- c2 #x1161))) - (+ #xac00 (* lindex 588) (* vindex 28)))) + (code-char (+ #xac00 (* lindex 588) (* vindex 28))))) ((and (eql (composition-hangul-syllable-type c1) :LV) (eql (composition-hangul-syllable-type c2) :T)) - (+ c1 (- c2 #x11a7)))))))) + (code-char (+ c1 (- c2 #x11a7)))))))) (defun canonically-compose (list) (let* ((result list) @@ -582,7 +586,7 @@ only characters for which it returns T are collected." (defun has-case-p (char) ;; Bit 6 is the Unicode case flag, as opposed to the Common Lisp one - (logbitp 6 (aref **character-misc-database** (+ 5 (misc-index char))))) + (logbitp 6 (aref +character-misc-database+ (+ 5 (misc-index char))))) (defun char-uppercase (char) (if (has-case-p char) @@ -788,10 +792,70 @@ The result is not guaranteed to have the same length as the input." ;;; In all the breaking methods: ;;; (brk) establishes a break between `first` and `second` ;;; (nobrk) prevents a break between `first` and `second` -;;; Setting flag=T/state=:nobrk-next prevents a break between `second` and `htird` +;;; Setting flag=T/state=:nobrk-next prevents a break between `second` and `third` + +;;; Unicode 9.0-10.0 only: obsoleted in 11.0 +(defun emoji-grapheme-break-class (char) + (let ((code (char-code char)) + (e-base + #(#x261D + #x26F9 + #x270A #x270B #x270C #x270D + #x1F385 + #x1F3C2 #x1F3C3 #x1F3C4 + #x1F3C7 + #x1F3CA #x1F3CB #x1F3CC + #x1F442 #x1F443 + #x1F446 #x1F447 #x1F448 #x1F449 #x1F44A #x1F44B #x1F44C #x1F44D #x1F44E #x1F44F #x1F450 + #x1F46E + #x1F470 #x1F471 #x1F472 #x1F473 #x1F474 #x1F475 #x1F476 #x1F477 #x1F478 + #x1F47C + #x1F481 #x1F482 #x1F483 + #x1F485 #x1F486 #x1F487 + #x1F4AA + #x1F574 #x1F575 + #x1F57A + #x1F590 + #x1F595 #x1F596 + #x1F645 #x1F646 #x1F647 + #x1F64B #x1F64C #x1F64D #x1F64E #x1F64F + #x1F6A3 + #x1F6B4 #x1F6B5 #x1F6B6 + #x1F6C0 + #x1F6CC + #x1F918 #x1F919 #x1F91A #x1F91B #x1F91C + #x1F91E #x1F91F + #x1F926 + #x1F930 #x1F931 #x1F932 #x1F933 #x1F934 #x1F935 #x1F936 #x1F937 #x1F938 #x1F939 + #x1F93D #x1F93E + #x1F9D1 #x1F9D2 #x1F9D3 #x1F9D4 #x1F9D5 #x1F9D6 #x1F9D7 #x1F9D8 #x1F9D9 #x1F9DA #x1F9DB #x1F9DC #x1F9DD)) + (glue-after-zwj + #(#x2640 + #x2642 + #x2695 #x2696 + #x2708 + #x2764 + #x1F308 + #x1F33E + #x1F373 + #x1F393 + #x1F3A4 + #x1F3A8 + #x1F3EB + #x1F3ED + #x1F48B + #x1F4BB #x1F4BC + #x1F527 + #x1F52C + #x1F5E8 + #x1F680 + #x1F692))) + (cond + ((binary-search code e-base) :e-base) + ((<= #x1F3FB code #x1F3FF) :e-modifier) + ((binary-search code glue-after-zwj) :glue-after-zwj) + ((<= #x1F466 code #x1F469) :e-base-gaz)))) -;; Word breaking sets this to make their algorithms less tricky -(defvar *other-break-special-graphemes* nil) (defun grapheme-break-class (char) "Returns the grapheme breaking class of CHARACTER, as specified in UAX #29." (let ((cp (when char (char-code char))) @@ -806,36 +870,53 @@ The result is not guaranteed to have the same length as the input." ((not char) nil) ((= cp 10) :LF) ((= cp 13) :CR) - ((or (member gc '(:Mn :Me)) - (proplist-p char :other-grapheme-extend) - (and *other-break-special-graphemes* - (member gc '(:Mc :Cf)) (not (<= #x200B cp #x200D)))) - :extend) - ((or (member gc '(:Zl :Zp :Cc :Cs :Cf)) + ((or (and (member gc '(:Zl :Zp :Cc :Cs :Cf)) + (not (proplist-p char :prepended-concatenation-mark)) + (not (<= #x200C cp #x200D)) + ;; not documented but in the normative file + (not (<= #xE0020 cp #xE007F))) ;; From Cn and Default_Ignorable_Code_Point (eql cp #x2065) (eql cp #xE0000) (<= #xFFF0 cp #xFFF8) (<= #xE0002 cp #xE001F) (<= #xE0080 cp #xE00FF) (<= #xE01F0 cp #xE0FFF)) :control) + ((or (member gc '(:Mn :Me)) + (proplist-p char :other-grapheme-extend)) + :extend) + ((= cp #x200D) :zwj) ((<= #x1F1E6 cp #x1F1FF) :regional-indicator) + ((or + ;; Consonant_Preceding_Repha + (= cp #x0D4E) (= cp #x11941) (= cp #x11D46) + ;; Consonant_Prefixed + (<= #x111C2 cp #x111C3) (= cp #x1193F) (= cp #x11A3A) (<= #x11A84 cp #x11A89) + (proplist-p char :prepended-concatenation-mark)) + :prepend) ((and (or (eql gc :Mc) (eql cp #x0E33) (eql cp #x0EB3)) (not (binary-search cp not-spacing-mark))) :spacing-mark) - (t (hangul-syllable-type char))))) + ((hangul-syllable-type char)) + ((emoji-grapheme-break-class char))))) (macrolet ((def (name extendedp) `(defun ,name (function string) - (do ((length (length string)) - (start 0) - (end 1 (1+ end)) - (c1 nil) - (c2 (and (> (length string) 0) (grapheme-break-class (char string 0))))) - ((>= end length) - (if (= end length) (progn (funcall function string start end) nil))) + (do* ((length (length string)) + (start 0) + (end 1 (1+ end)) + (c1 nil) + (c2 (and (> (length string) 0) (grapheme-break-class (char string 0)))) + (emoji-modifier-sequence-p nil) + (nri (if (eql c2 :regional-indicator) 1 0))) + ((>= end length) + (if (= end length) (progn (funcall function string start end) nil))) (flet ((brk () (funcall function string start end) (setf start end))) (declare (truly-dynamic-extent #'brk)) (shiftf c1 c2 (grapheme-break-class (char string end))) + (if (eql c2 :regional-indicator) (incf nri) (setf nri 0)) + (setf emoji-modifier-sequence-p + (or (member c1 '(:e-base :e-base-gaz)) + (and emoji-modifier-sequence-p (eql c1 :extend)))) (cond ((and (eql c1 :cr) (eql c2 :lf))) ((or (member c1 '(:control :cr :lf)) @@ -845,10 +926,12 @@ The result is not guaranteed to have the same length as the input." (and (or (eql c1 :v) (eql c1 :lv)) (or (eql c2 :v) (eql c2 :t))) (and (eql c2 :t) (or (eql c1 :lvt) (eql c1 :t))))) - ((and (eql c1 :regional-indicator) (eql c2 :regional-indicator))) - ((eql c2 :extend)) + ((member c2 '(:extend :zwj))) ,@(when extendedp - `(((or (eql c2 :spacing-mark) (eql c1 :prepend))))) + `(((or (eql c2 :spacing-mark) (eql c1 :prepend))))) + ((and emoji-modifier-sequence-p (eql c2 :e-modifier))) + ((and (eql c1 :zwj) (member c2 '(:glue-after-zwj :e-base-gaz)))) + ((and (eql c1 :regional-indicator) (eql c2 :regional-indicator) (evenp nri))) (t (brk)))))))) (def map-legacy-grapheme-boundaries nil) (def map-grapheme-boundaries t)) @@ -884,6 +967,11 @@ grapheme breaking rules specified in UAX #29, returning a list of strings." #(#x3031 #x3035 #x309B #x309C #x30A0 #x30A0 #x30FC #x30FC #xFF70 #xFF70))) + (also-aletter + #(#x02C2 #x02C3 #x02C4 #x02C5 #x02D2 #x02D3 #x02D4 #x02D5 #x02D6 #x02D7 + #x02DE #x02DF #x02ED #x02EF #x02F0 #x02F1 #x02F2 #x02F3 #x02F4 #x02F5 + #x02F6 #x02F7 #x02F8 #x02F9 #x02FA #x02FB #x02FC #x02FD #x02FE #x02FF + #x05F3 #xA720 #xA721 #xA789 #xA78A #xAB5B)) (midnumlet #(#x002E #x2018 #x2019 #x2024 #xFE52 #xFF07 #xFF0E)) (midletter #(#x003A #x00B7 #x002D7 #x0387 #x05F4 #x2027 #xFE13 #xFE55 #xFF1A)) @@ -895,26 +983,28 @@ grapheme breaking rules specified in UAX #29, returning a list of strings." ((not char) nil) ((= cp 10) :LF) ((= cp 13) :CR) - ((= cp #x27) :single-quote) - ((= cp #x22) :double-quote) ((ordered-ranges-member cp newlines) :newline) ((or (eql (grapheme-break-class char) :extend) - (eql gc :mc)) :extend) + (and (eql gc :mc) (not (= cp #x200D)))) :extend) + ((= cp #x200D) :zwj) ((<= #x1F1E6 cp #x1F1FF) :regional-indicator) ((and (eql gc :Cf) (not (<= #x200B cp #x200D))) :format) ((or (eql (script char) :katakana) (ordered-ranges-member cp also-katakana)) :katakana) ((and (eql (script char) :Hebrew) (eql gc :lo)) :hebrew-letter) - ((and (or (alphabetic-p char) (= cp #x05F3)) + ((and (or (alphabetic-p char) (binary-search cp also-aletter)) (not (or (ideographic-p char) (eql (line-break-class char) :sa) (eql (script char) :hiragana)))) :aletter) + ((= cp #x27) :single-quote) + ((= cp #x22) :double-quote) ((binary-search cp midnumlet) :midnumlet) ((binary-search cp midletter) :midletter) ((binary-search cp midnum) :midnum) ((or (and (eql gc :Nd) (not (<= #xFF10 cp #xFF19))) ;Fullwidth digits (eql cp #x066B)) :numeric) - ((eql gc :Pc) :extendnumlet) + ((or (eql gc :Pc) (= cp #x202F)) :extendnumlet) + ((emoji-grapheme-break-class char)) (t nil)))) (defmacro flatpush (thing list) @@ -928,28 +1018,52 @@ grapheme breaking rules specified in UAX #29, returning a list of strings." (defun words (string) "Breaks STRING into words according to the default word breaking rules specified in UAX #29. Returns a list of strings" - (let ((chars (mapcar - #'(lambda (s) - (let ((l (coerce s 'list))) - (if (cdr l) l (car l)))) - (let ((*other-break-special-graphemes* t)) (graphemes string)))) - words word flag) + (let ((chars (coerce string 'list)) + words word flag) (flatpush (car chars) word) (do ((first (car chars) second) (tail (cdr chars) (cdr tail)) - (second (cadr chars) (cadr tail))) + (second (cadr chars) (cadr tail)) + (nri 0)) ((not first) (nreverse (mapcar #'(lambda (l) (coerce l 'string)) words))) - (flet ((brk () (push (nreverse word) words) (setf word nil) (flatpush second word)) + (flet ((extended-word-break-class (list) + (loop for tail on list + for thing = (car tail) + for class = (word-break-class thing) + while thing + unless (or (eql class :format) (eql class :extend) (eql class :zwj)) + return class)) + (brk () (push (nreverse word) words) (setf word nil) (flatpush second word)) (nobrk () (flatpush second word))) (let ((c1 (word-break-class first)) (c2 (word-break-class second)) - (c3 (when (and tail (cdr tail)) (word-break-class (cadr tail))))) + (c3 (extended-word-break-class (cdr tail)))) + (when (eql c1 :regional-indicator) + (incf nri (if (atom first) 1 (count :regional-indicator first :key #'word-break-class)))) (cond - (flag (nobrk) (setf flag nil)) + ;; handle multiple no-breaks + (flag + (nobrk) + (unless (or (eql c2 :format) (eql c2 :extend) (eql c2 :zwj)) + (setf flag nil))) + ((and (eql c1 :cr) (eql c2 :lf)) (nobrk)) ;; CR+LF are bound together by the grapheme clustering ((or (eql c1 :newline) (eql c1 :cr) (eql c1 :lf) (eql c2 :newline) (eql c2 :cr) (eql c2 :lf)) (brk)) - ((or (eql c2 :format) (eql c2 :extend)) (nobrk)) + ((and (eql c1 :zwj) + (or (eql c2 :glue-after-zwj) (eql c2 :e-base-gaz))) + (nobrk)) + ((or (eql c2 :format) (eql c2 :extend) (eql c2 :zwj)) + ;; handle Any x (Format|Extend|ZWJ) + (nobrk) + ;; handle "Ignore except after sot, CR, LF, Newline [and ZWJ]" + (unless (member c1 '(:cr :lf :newline :zwj)) + ;; so that the next iteration preserves first: + (setf second first) + ;; so that we don't spuriously count the preserved first + ;; as a new regional-indicator: + (when (eql c1 :regional-indicator) + (decf nri (if (atom first) 1 (count :regional-indicator first :key #'word-break-class)))))) ((and (or (eql c1 :aletter) (eql c1 :hebrew-letter)) (or (eql c2 :aletter) (eql c2 :hebrew-letter))) (nobrk)) ((and (or (eql c1 :aletter) (eql c1 :hebrew-letter)) @@ -975,7 +1089,11 @@ word breaking rules specified in UAX #29. Returns a list of strings" '(:aletter :hebrew-letter :katakana :numeric :extendnumlet)) (eql c1 :extendnumlet))) (nobrk)) - ((and (eql c1 :regional-indicator) (eql c2 :regional-indicator)) (nobrk)) + ((and (or (eql c1 :e-base) (eql c1 :e-base-gaz)) + (eql c2 :e-modifier)) + (nobrk)) + ((and (eql c1 :regional-indicator) (eql c2 :regional-indicator) (oddp nri)) + (nobrk)) (t (brk)))))))) (defun sentence-break-class (char) @@ -993,6 +1111,7 @@ word breaking rules specified in UAX #29. Returns a list of strings" ((= cp 10) :LF) ((= cp 13) :CR) ((or (eql (grapheme-break-class char) :extend) + (= cp #x200D) (eql gc :mc)) :extend) ((or (eql cp #x0085) (<= #x2028 cp #x2029)) :sep) ((and (eql gc :Cf) (not (<= #x200C cp #x200D))) :format) @@ -1004,7 +1123,7 @@ word breaking rules specified in UAX #29. Returns a list of strings" (<= #x066B cp #x066C)) :numeric) ((binary-search cp aterms) :aterm) ((binary-search cp scontinues) :scontinue) - ((proplist-p char :sterm) :sterm) + ((proplist-p char :sentence-terminal) :sterm) ((and (or (member gc '(:Po :Ps :Pe :Pf :Pi)) (eql (line-break-class char) :qu))) :close) @@ -1120,14 +1239,15 @@ sentence breaking rules specified in UAX #29" (when (and cluster (or - (not (eql type :cm)) - (and (eql type :cm) + (not (or (eql type :cm) (eql type :zwj))) + (and (or (eql type :cm) (eql type :zwj)) (member last-seen '(nil :BK :CR :LF :NL :SP :ZW))))) (if (cdr cluster) (push (nreverse cluster) clusters) (push (car cluster) clusters)) (setf cluster nil)) - (unless (eql type :cm) (setf last-seen type)) + (unless (or (eql type :cm) (eql type :zwj)) + (setf last-seen type)) (push char cluster)) (if (cdr cluster) (push (nreverse cluster) clusters) @@ -1137,7 +1257,7 @@ sentence breaking rules specified in UAX #29" (defun line-break-annotate (string) (let ((chars (line-prebreak string)) first second t1 t2 tail (ret (list :cant)) - state after-spaces) + state after-spaces nri) (macrolet ((cmpush (thing) (let ((gthing (gensym))) `(let ((,gthing ,thing)) @@ -1149,7 +1269,9 @@ sentence breaking rules specified in UAX #29" (between (a b action) (let ((atest (if (eql a :any) t (if (listp a) - `(member t1 ,a) + (if (eql (car a) 'not) + `(not (member t1 ,(cadr a))) + `(member t1 ,a)) `(eql t1 ,a)))) (btest (if (eql b :any) t (if (listp b) @@ -1189,73 +1311,78 @@ sentence breaking rules specified in UAX #29" (setf first (car chars)) (setf tail (cdr chars)) (setf second (car tail)) + (setf nri 0) (tagbody - top + top (when (not first) (go end)) (setf t1 (line-break-class first :resolve t)) (setf t2 (line-break-class second :resolve t)) - (between :any :nil :must) + (if (and (eql t1 :ri) (eql t2 :ri)) (incf nri) (setf nri 0)) + (between :any :nil :must) ; LB3 (when (and (eql state :eat-spaces) (eql t2 :sp)) - (cmpush :cant) (cmpush second) (go tail)) - (between :bk :any :must) - (between :cr :lf :cant) - (between '(:cr :lf :nl) :any :must) - (between :any '(:zw :bk :cr :lf :nl) :cant) + (cmpush :cant) (cmpush second) (go tail)) + (between :bk :any :must) ; LB4 + (between :cr :lf :cant) ; LB5 + (between '(:cr :lf :nl) :any :must) ; LB5 + (between :any '(:zw :bk :cr :lf :nl) :cant) ; LB6, LB7 (when after-spaces (cmpush after-spaces) (cmpush second) (setf state nil after-spaces nil) (go tail)) - (after-spaces :zw :any :can) - (between :any :wj :cant) - (between :wj :any :cant) - (between :gl :any :cant) - (between '(:ZW :WJ :SY :SG :SA :RI :QU :PR :PO :OP :NU :NS :NL - :LF :IS :IN :ID :HL :GL :EX :CR :CP :CM :CL :CJ :CB - :BK :BB :B2 :AL :AI :JL :JV :JT :H2 :H3 :XX) - :gl :cant) - (between :any '(:cl :cp :ex :is :sy) :cant) - (after-spaces :op :any :cant) - (after-spaces :qu :op :cant) - (after-spaces '(:cl :cp) :ns :cant) - (after-spaces :b2 :b2 :cant) - (between :any :sp :cant) ;; Goes here to deal with after-spaces - (between :sp :any :can) - (between :any :qu :cant) - (between :qu :any :cant) - (between :any :cb :can) - (between :cb :any :can) + (after-spaces :zw :any :can) ; LB8 + (between :zwj '(:id :eb :em) :cant) ; LB8a + ;; LB9 and LB10 (for CM) handled in LINE-BREAK-CLASS / LINE-PREBREAK + (when (eql t1 :zwj) (setf t1 :al)) ; LB10 (for ZWJ) + (when (eql t2 :zwj) (setf t2 :al)) ; LB10 (for ZWJ) + (between :any :wj :cant) ; LB11 + (between :wj :any :cant) ; LB11 + (between :gl :any :cant) ; LB12 + (between (not '(:sp :ba :hy)) :gl :cant) ; LB12a + (between :any '(:cl :cp :ex :is :sy) :cant) ; LB13 + (after-spaces :op :any :cant) ; LB14 + (after-spaces :qu :op :cant) ; LB15 + (after-spaces '(:cl :cp) :ns :cant) ; LB16 + (after-spaces :b2 :b2 :cant) ; LB17 + (between :any :sp :cant) ; LB7, here after all AFTER-SPACES calls + (between :sp :any :can) ; LB18 + (between :any :qu :cant) ; LB19 + (between :qu :any :cant) ; LB19 + (between :any :cb :can) ; LB20 + (between :cb :any :can) ; LB20 (when (and (eql t1 :hl) (member t2 '(:hy :ba))) (cmpush :cant) (cmpush second) (setf first second tail (cdr tail)) (setf second (car tail)) (cmpush (if second :cant :must)) (cmpush second) - (setf after-spaces :can) (go tail)) - (between :any '(:ba :hy :ns) :cant) - (between :bb :any :cant) - (between :sy :hl :cant) - (between '(:al :hl :ex :id :in :nu) :in :cant) - (between :id :po :cant) - (between '(:al :hl) :nu :cant) - (between '(:nu :po) '(:al :hl) :cant) - (between :pr '(:id :al :hl) :cant) - (between '(:cl :cp :nu) '(:po :pr) :cant) - (between :nu '(:po :pr :nu) :cant) - (between '(:po :pr) :op :cant) - (between '(:po :pr :hy :is :sy) :nu :cant) - (between :jl '(:jl :jv :h2 :h3) :cant) - (between '(:jv :h2) '(:jv :jt) :cant) - (between '(:jt :h3) :jt :cant) - (between '(:jl :jv :jt :h2 :h3) '(:in :po) :cant) - (between :pr '(:jl :jv :jt :h2 :h3) :cant) - (between '(:al :hl :is) '(:al :hl) :cant) - (between '(:al :hl :nu) :op :cant) - (between :cp '(:al :hl :nu) :cant) - (between :ri :ri :cant) - (between :any :any :can) - tail + (setf after-spaces :can) (go tail)) ; LB21a + (between :any '(:ba :hy :ns) :cant) ; LB21 + (between :bb :any :cant) ; LB21 + (between :sy :hl :cant) ; LB21b + (between '(:al :hl :ex :id :eb :em :in :nu) :in :cant) ; LB22 + (between '(:al :hl) :nu :cant) ; LB23 + (between :nu '(:al :hl) :cant) ; LB23 + (between :pr '(:id :eb :em) :cant) ; LB23a + (between '(:id :eb :em) :po :cant) ; LB23a + (between '(:pr :po) '(:al :hl) :cant) ; LB24 + (between '(:al :hl) '(:pr :po) :cant) ; LB24 + (between '(:cl :cp :nu) '(:po :pr) :cant) ; LB25, first six cases + (between '(:po :pr) :op :cant) ; LB25, two ? x OP cases + (between '(:po :pr :hy :is :sy :nu) :nu :cant) ; LB25, six ? x NU cases + (between :jl '(:jl :jv :h2 :h3) :cant) ; LB26 + (between '(:jv :h2) '(:jv :jt) :cant) ; LB26 + (between '(:jt :h3) :jt :cant) ; LB26 + (between '(:jl :jv :jt :h2 :h3) '(:in :po) :cant) ; LB27 + (between :pr '(:jl :jv :jt :h2 :h3) :cant) ; LB27 + (between '(:al :hl :is) '(:al :hl) :cant) ; LB28, LB29 + (between '(:al :hl :nu) :op :cant) ; LB30 + (between :cp '(:al :hl :nu) :cant) ; LB30 + (between :ri :ri (if (oddp nri) :cant :can)) ; LB30a + (between :eb :em :cant) + (between :any :any :can) ; LB31 + tail (setf first second) (setf tail (cdr tail)) (setf second (car tail)) (go top) - end) + end) ;; LB3 satisfied by (:any :nil) -> :must (setf ret (nreverse ret)) ret))) @@ -1332,6 +1459,15 @@ it defaults to 80 characters" (defun variable-p (x) (<= 1 x +maximum-variable-primary-element+)) +(macrolet ((collations-hash-table () + (let ((data (let ((*read-base* 16)) + (sb-cold:read-from-file "output/collation.lisp-expr")))) + #+64-bit (dovector (item data) (aver (fixnump (car item)))) + `(load-time-value + (sb-impl::%stuff-hash-table + (make-hash-table :size ,(length data) #+64-bit :test #+64-bit 'eq) + ',data t) + t)))) (defun collation-key (string start end) (let (char1 (char2 (code-char 0)) @@ -1346,26 +1482,27 @@ it defaults to 80 characters" (t ;; There are never more than three characters in a contraction, right? (return-from collation-key nil))) - (let ((packed-key (gethash (pack-3-codepoints - (char-code char1) - (char-code char2) - (char-code char3)) - **character-collations**))) + (let* ((code1 (char-code char1)) + (packed-key (gethash (pack-3-codepoints code1 (char-code char2) (char-code char3)) + (collations-hash-table)))) (if packed-key (unpack-collation-key packed-key) (when (char= (code-char 0) char2 char3) - (let* ((cp (char-code char1)) + (let* ((unified-ideograph-p (proplist-p char1 :unified-ideograph)) + (tangut-p (<= #x17000 code1 #x18AFF)) + (nushu-p (<= #x1B170 code1 #x1B2FF)) + (boffset 0) (base - (cond ((not (proplist-p char1 :unified-ideograph)) - #xFBC0) - ((or (<= #x4E00 cp #x9FFF) - (<= #xF900 cp #xFAFF)) + (cond ((and unified-ideograph-p + (or (<= #x4E00 code1 #x9FFF) (<= #xF900 code1 #xFAFF))) #xFB40) - (t - #xFB80))) - (a (+ base (ash cp -15))) - (b (logior #.(ash 1 15) (logand cp #x7FFFF)))) - (list (list a #x20 #x2) (list b 0 0)))))))) + (unified-ideograph-p #xFB80) + (tangut-p (setq boffset #x17000) #xFB00) + (nushu-p (setq boffset #x1B170) #xFB01) + (t #xFBC0))) + (a (+ base (if (or tangut-p nushu-p) 0 (ash code1 -15)))) + (b (logior #x8000 (if (or tangut-p nushu-p) (- code1 boffset) (logand code1 #x7FFF))))) + (list (list a #x20 #x2) (list b 0 0))))))))) (defun sort-key (string) (let* ((str (normalize-string string :nfd)) @@ -1384,7 +1521,6 @@ it defaults to 80 characters" new-i index)))) (loop for index from new-i below len for char = (char str index) - for previous-combining-class = combining-class for combining-class = (combining-class char) until (eql combining-class 0) unless (and (>= (- index new-i) 1) @@ -1446,7 +1582,7 @@ If :STRICT is NIL, UNICODE= tests compatibility equavalence instead." (defun unicode-equal (string1 string2 &key (start1 0) end1 (start2 0) end2 (strict t)) "Determines whether STRING1 and STRING2 are canonically equivalent after -casefoldin8 (that is, ignoring case differences) according to Unicode. The +casefolding (that is, ignoring case differences) according to Unicode. The START and END arguments behave like the arguments to STRING=. If :STRICT is NIL, UNICODE= tests compatibility equavalence instead." (let ((str1 (normalize-string (subseq string1 start1 end1) (if strict :nfd :nfkd))) @@ -1457,7 +1593,7 @@ NIL, UNICODE= tests compatibility equavalence instead." (defun unicode< (string1 string2 &key (start1 0) end1 (start2 0) end2) "Determines whether STRING1 sorts before STRING2 using the Unicode Collation -Algorithm, The function uses an untailored Default Unicode Collation Element Table +Algorithm. The function uses an untailored Default Unicode Collation Element Table to produce the sort keys. The function uses the Shifted method for dealing with variable-weight characters, as described in UTS #10" (let* ((s1 (subseq string1 start1 end1)) @@ -1513,3 +1649,5 @@ according to the IDNA confusableSummary.txt table" (skeleton1 (normalize-string (canonically-deconfuse str1) form)) (skeleton2 (normalize-string (canonically-deconfuse str2) form))) (string= skeleton1 skeleton2))) + +(clear-info :function :compiler-macro-function 'proplist-p) diff --git a/src/code/thread-structs.lisp b/src/code/thread-structs.lisp new file mode 100644 index 0000000000..dfdb8dd37b --- /dev/null +++ b/src/code/thread-structs.lisp @@ -0,0 +1,170 @@ +;;;; support for threads needed at cross-compile time + +;;;; This software is part of the SBCL system. See the README file for +;;;; more information. +;;;; +;;;; This software is derived from the CMU CL system, which was +;;;; written at Carnegie Mellon University and released into the +;;;; public domain. The software is in the public domain and is +;;;; provided with absolutely no warranty. See the COPYING and CREDITS +;;;; files for more information. + +(in-package "SB-THREAD") + +;;; It's possible to make futex/non-futex switchable at runtime by ensuring that +;;; these synchronization primitive structs contain all the slots for the union +;;; of any kind of backing object. Some of the #+sb-futex/#-sb-futex cases in +;;; target-thread also have to be changed to a COND rather than a compile-time test. +;;; Among the uses of this would be to test real posix mutexes (with a finalizer on +;;; each lisp-side proxy) or support older C APIs. Posix mutexes work nicely now +;;; because finalizers are more efficient than they were, and when many threads +;;; compete for a mutex, the pthread code seems to do a better job at reducing +;;; cycles spent in the OS. + +;;; N.B.: If you alter this definition, then you need to verify that FOP-FUNCALL +;;; in genesis can properly emulate MAKE-MUTEX for the altered structure, +;;; or even better, make sure that genesis can emulate any constructor, +;;; provided that it is sufficiently trivial. +(sb-xc:defstruct (mutex (:constructor make-mutex (&key name)) + (:copier nil)) + "Mutex type." + #+sb-futex (state 0 :type sb-vm:word) + ;; If adding slots between STATE and NAME, please see futex_name() in linux_os.c + ;; which attempts to divine a string from a futex word address. + (name nil :type (or null simple-string)) + ;; The owner is a non-pointer so that GC pages containing mutexes do not get dirtied + ;; with mutex ownership change. The natural representation of this is SB-VM:WORD + ;; but the "funny fixnum" representation - i.e. N_WORD_BITS bits of significance, but + ;; cast as fixnum when read - avoids consing on 32-bit builds, and also not all of them + ;; implement RAW-INSTANCE-CAS which would be otherwise needed. + (%owner 0 :type fixnum)) + +(sb-xc:defstruct (waitqueue (:copier nil) (:constructor make-waitqueue (&key name))) + "Waitqueue type." + ;; futex words are actually 32-bits, but it needs to be a raw slot and we don't have + ;; 32-bit raw slots on 64-bit machines. + #+sb-futex (token 0 :type sb-ext:word) + ;; If adding slots between TOKEN and NAME, please see futex_name() in linux_os.c + ;; which attempts to divine a string from a futex word address. + (name nil :type (or null string)) + ;; For WITH-CAS-LOCK: because CONDITION-WAIT must be able to call + ;; %WAITQUEUE-WAKEUP without re-aquiring the mutex, we need a separate + ;; lock. In most cases this should be uncontested thanks to the mutex -- + ;; the only case where that might not be true is when CONDITION-WAIT + ;; unwinds and %WAITQUEUE-DROP is called. + . #+sb-futex nil + #-sb-futex (%owner %head %tail)) + +(sb-xc:defstruct (semaphore (:copier nil) + (:constructor %make-semaphore (%count mutex queue))) + "Semaphore type. The fact that a SEMAPHORE is a STRUCTURE-OBJECT +should be considered an implementation detail, and may change in the +future." + (%count 0 :type (integer 0)) + (waitcount 0 :type sb-vm:word) + (mutex nil :read-only t :type mutex) + (queue nil :read-only t :type waitqueue)) + +(declaim (sb-ext:freeze-type waitqueue semaphore)) + +(sb-ext:define-load-time-global *profiled-threads* :all) +(declaim (type (or (eql :all) list) *profiled-threads*)) + +(sb-xc:defstruct (thread (:constructor %make-thread (name %ephemeral-p semaphore)) + (:copier nil)) + "Thread type. Do not rely on threads being structs as it may change +in future versions." + (name nil :type (or null simple-string)) ; C code could read this + (%ephemeral-p nil :type boolean :read-only t) + ;; This is one of a few different views of a lisp thread: + ;; 1. the memory space (thread->os_addr in C) + ;; 2. 'struct thread' at some offset into the memory space, coinciding + ;; with the SB-VM::THREAD primitive object + ;; 3. a pthread, which may reside anywhere, possibly the high end of the lisp stack + ;; (above the SP given to your entrypoint), whatever the pthread library chooses. + ;; 4. the THREAD instance (this structure) + ;; This value is 0 if the thread is not considered alive, though the pthread + ;; may be running its termination code (unlinking from all_threads etc) + (primitive-thread 0 :type sb-vm:word) + ;; This is a redundant copy of the pthread identifier from the primitive thread. + ;; It's needed in the SB-THREAD:THREAD as well because there are valid reasons to + ;; manipulate the new thread before it has assigned 'th->os_thread = pthread_self()'. + ;; While we always have access to the C struct thread from Lisp, apparently the C + ;; code can't pass "&th->os_thread" as the first argument to pthread_create() for the + ;; incredible reason that the word might be written *after* the memory pointed at + ;; by 'th' has already been freed. Such action might seem to violate: + ;; "Before returning, a successful call to pthread_create() stores the ID of the + ;; new thread in the buffer pointed to by thread" + ;; (https://man7.org/linux/man-pages/man3/pthread_create.3.html) + ;; but that's not exactly what POSIX says, which is only: + ;; "Upon successful completion, pthread_create() stores the ID of the created thread + ;; in the location referenced by thread." + ;; (https://pubs.opengroup.org/onlinepubs/007908799/xsh/pthread_create.html) + ;; so there seems to be some leeway, and linux + glibc provides more of a guarantee. + ;; Technically we should have only one authoritative source of the pthread identifier, + ;; but it's not too critical, it's just annoying that there are two sources of + ;; the same value. + ;; The slot is somewhat poorly named (for consistency with C) because though it may + ;; correspond to an OS thread, it could be the case that the threading model has + ;; user-visible threads that do not map directly to OSs threads (or LWPs). + ;; Any use of THREAD-OS-THREAD from lisp should take care to ensure validity of + ;; the thread id by holding the INTERRUPTIONS-LOCK. + ;; Not needed for win32 threads. + #-win32 (os-thread 0 :type sb-vm:word) + ;; Keep a copy of the stack range for use in SB-EXT:STACK-ALLOCATED-P so that + ;; we don't have to read it from the primitive thread which is unsafe for any + ;; thread other than the current thread. + ;; Usually this is a fixed amount below PRIMITIVE-THREAD, but the exact offset + ;; varies by build configuration, and if #+win32 it is not related in any way. + (control-stack-start 0 :type sb-vm:word) + (control-stack-end 0 :type sb-vm:word) + ;; At the beginning of the thread's life, this is a vector of data required + ;; to start the user code. At the end, is it pointer to the 'struct thread' + ;; so that it can be either freed or reused. + (startup-info 0 :type (or fixnum (simple-vector 6))) + ;; Whether this thread should be returned in LIST-ALL-THREADS. + ;; This is almost-but-not-quite the same as what formerly + ;; might have been known as the %ALIVE-P flag. + (%visible 1 :type fixnum) + (interruptions nil :type list) + (interruptions-lock + (make-mutex :name "thread interruptions lock") + :type mutex :read-only t) + + ;; Per-thread memoization of GET-INTERNAL-REAL-TIME, for race-free update. + ;; This might be a bignum, which is why we bother. + #-64-bit (observed-internal-real-time-delta-sec 0 :type sb-vm:word) + #-64-bit (observed-internal-real-time-delta-millisec + ;; This needs a sentinel that can not possibly match an actual delta. + ;; I have seen threads start up where 0 and 0 do match sec,msec + ;; respectively, and then we'd return the cached NIL as if it were + ;; the time. Forcing mismatch avoids putting in an extra test for NIL. + (ash sb-ext:most-positive-word -1) + :type sb-vm:signed-word) + #-64-bit (internal-real-time) + + ;; On succesful execution of the thread's lambda, a list of values. + (result 0) + ;; The completion condition _could_ be manifested as a condition var, but a difficulty + ;; in doing so is that condition vars can always experience a spurious wakeup. + ;; Dealing with timeouts becomes troublesome then. But we can utilize the fact that + ;; WAIT-ON-SEMPAHORE implements a timeout, though as its comment says, the timeout + ;; doesn't account for re-acquiring the internal mutex if that takes nontrivial time, + ;; which it shouldn't since it guards very little work. + ;; At any rate, the semaphore abstraction is never subject to spurious wakeup. + (semaphore nil :type (or null semaphore)) + waiting-for) + +(sb-xc:defstruct (foreign-thread + (:copier nil) + (:include thread (name "callback")) + (:constructor make-foreign-thread ()) + (:conc-name "THREAD-")) + "Type of native threads which are attached to the runtime as Lisp threads +temporarily.") + +(declaim (sb-ext:freeze-type mutex thread)) +#-sb-xc-host +(progn + (defvar *current-thread*) + (declaim (type thread *current-thread*))) diff --git a/src/code/thread.lisp b/src/code/thread.lisp index 5dd8c67661..a90477389c 100644 --- a/src/code/thread.lisp +++ b/src/code/thread.lisp @@ -11,93 +11,64 @@ (in-package "SB-THREAD") -;;; N.B.: If you alter this definition, then you need to verify that FOP-FUNCALL -;;; in genesis can properly emulate MAKE-MUTEX for the altered structure, -;;; or even better, make sure that genesis can emulate any constructor, -;;; provided that it is sufficiently trivial. -(defstruct (mutex (:constructor make-mutex (&key name)) - (:copier nil)) - "Mutex type." - ;; C code could (but doesn't currently) access the name - #+(and sb-thread sb-futex) - (state 0 :type fixnum) - ;; If adding slots between STATE and NAME, please see futex_name() in linux_os.c - ;; which attempts to divine a string from a futex word address. - (name nil :type (or null simple-string)) - (%owner nil :type (or null thread))) - -(defstruct (thread (:constructor %make-thread (&key name %alive-p %ephemeral-p)) - (:copier nil)) - "Thread type. Do not rely on threads being structs as it may change -in future versions." - (name nil :type (or null simple-string)) ; C code could read this - (%alive-p nil :type boolean) - (%ephemeral-p nil :type boolean :read-only t) - ;; 0 is used on thread-less builds - (os-thread (ldb (byte sb-vm:n-word-bits 0) -1) :type sb-vm:word) - ;; Keep a copy of CONTROL-STACK-END from the "primitive" thread (C memory). - ;; Reading that memory for any thread except *CURRENT-THREAD* is not safe - ;; due to possible unmapping on thread death. Technically this is a fixed amount - ;; below PRIMITIVE-THREAD, but the exact offset varies by build configuration. - (stack-end 0 :type sb-vm:word) - ;; Points to the SB-VM::THREAD primitive object. - ;; Yes, there are three different thread structures. - (primitive-thread 0 :type sb-vm:word) - (interruptions nil :type list) - ;; Gotta have half a dozen or more different ways to identify a thread. - #+linux (os-tid 0 :type (unsigned-byte 32)) - ;; On succesful execution of the thread's lambda a list of values. - (result 0) - (interruptions-lock - (make-mutex :name "thread interruptions lock") - :type mutex :read-only t) - (result-lock - (make-mutex :name "thread result lock") - :type mutex :read-only t) - waiting-for) - (declaim (inline thread-alive-p)) (defun thread-alive-p (thread) "Return T if THREAD is still alive. Note that the return value is potentially stale even before the function returns, as the thread may exit at any time." - (thread-%alive-p thread)) + (declare (ignorable thread)) + (barrier (:read)) + #+sb-thread (/= (thread-primitive-thread thread) 0) + #-sb-thread t) -(sb-impl::define-thread-local *current-thread* - ;; This initform is magical - DEFINE-THREAD-LOCAL stuffs the initial - ;; value form into a SETQ in INIT-THREAD-LOCAL-STORAGE, and the name - ;; of its first and only argument is THREAD. - thread +(setf (documentation '*current-thread* 'variable) "Bound in each thread to the thread itself.") -(declaim (type thread *current-thread*)) - -(defstruct (foreign-thread - (:copier nil) - (:include thread) - (:conc-name "THREAD-")) - "Type of native threads which are attached to the runtime as Lisp threads -temporarily.") - -#+(and sb-safepoint-strictly (not win32)) -(defstruct (signal-handling-thread - (:copier nil) - (:include foreign-thread) - (:conc-name "THREAD-")) - "Asynchronous signal handling thread." - (signal-number nil :type integer)) - -(declaim (sb-ext:freeze-type mutex thread)) (defun mutex-value (mutex) "Current owner of the mutex, NIL if the mutex is free. May return a stale value, use MUTEX-OWNER instead." - (mutex-%owner mutex)) + (mutex-owner-lookup (mutex-%owner mutex))) + +(declaim (inline current-thread-sap)) +(defun current-thread-sap () + #+sb-thread (sb-vm::current-thread-offset-sap sb-vm::thread-this-slot) + #-sb-thread (extern-alien "all_threads" system-area-pointer)) + +#-sb-thread +(progn + (declaim (inline sb-vm::current-thread-offset-sap)) + (defun sb-vm::current-thread-offset-sap (n) + (sap-ref-sap (current-thread-sap) (* n sb-vm:n-word-bytes)))) + +(defmacro current-thread-sap-int () `(sap-int (current-thread-sap))) +;;; This is the same as thread-primitive-thread but using the "funny fixnum" +;;; representation so that on 32-bit builds we never cons when reading the slot. +;;; I'm not sure where consing was happening, but it did, which caused +;;; failure of the (:no-consing :mutex) test. +(defmacro current-vmthread-id () + '(sb-ext:truly-the fixnum (%make-lisp-obj (current-thread-sap-int)))) +(defmacro vmthread-id->addr (x) `(get-lisp-obj-address ,x)) + +(declaim (inline holding-mutex-p)) (defun holding-mutex-p (mutex) "Test whether the current thread is holding MUTEX." ;; This is about the only use for which a stale value of owner is ;; sufficient. - (eq sb-thread:*current-thread* (mutex-%owner mutex))) + (= (mutex-%owner mutex) (current-vmthread-id))) + +(declaim (inline mutex-owner)) +(defun mutex-owner (mutex) + "Current owner of the mutex, NIL if the mutex is free. Naturally, +this is racy by design (another thread may acquire the mutex after +this function returns), it is intended for informative purposes. For +testing whether the current thread is holding a mutex see +HOLDING-MUTEX-P." + ;; Make sure to get the current value. + (let ((vmthread (sb-ext:compare-and-swap (mutex-%owner mutex) 0 0))) + (cond ((= vmthread (current-vmthread-id)) *current-thread*) + ((= vmthread 0) nil) + (t (mutex-owner-lookup vmthread))))) (defsetf mutex-value set-mutex-value) @@ -143,6 +114,10 @@ stale value, use MUTEX-OWNER instead." (function with-recursive-spinlock :replacement with-recursive-lock) (function with-spinlock :replacement with-mutex))) +;;; Needed to pacify deadlock detection if inerrupting wait-for-mutex, +;;; otherwise it would appear that if there is a lock grabbed inside +;;; of BODY it would appear backwards--waiting on a lock while holding +;;; the new one, which looks like a deadlock. (defmacro without-thread-waiting-for ((&key already-without-interrupts) &body body) (with-unique-names (thread prev) (let ((without (if already-without-interrupts @@ -170,7 +145,7 @@ stale value, use MUTEX-OWNER instead." (barrier (:write))))) (exec))))))) -(defmacro with-mutex ((mutex &key (wait-p t) timeout value) +(defmacro with-mutex ((mutex &key (wait-p t) timeout (value nil valuep)) &body body) "Acquire MUTEX for the dynamic scope of BODY. If WAIT-P is true (the default), and the MUTEX is not immediately available, sleep until it is available. @@ -192,9 +167,20 @@ current thread." (call-with-mutex #'with-mutex-thunk ,mutex - ,value ,wait-p - ,timeout))) + ;; Users should not pass VALUE. If they do, the overhead of validity checking + ;; is at the call site so that normal invocations of CALL-WITH-MUTEX receive + ;; only the useful arguments. + ;; And as is true of so many macros, strict left-to-right evaluation of args + ;; is not promised, but let's try to be consistent with the order in the lambda list. + ;; (i.e. You don't know if the source form was ":value me :wait-p nil") + ,(if valuep + `(prog1 ,timeout + (let ((value ,value)) + (unless (or (null value) (eq *current-thread* value)) + (error "~S called with non-nil :VALUE that isn't the current thread." + 'with-mutex)))) + timeout)))) (defmacro with-recursive-lock ((mutex &key (wait-p t) timeout) &body body) "Acquire MUTEX for the dynamic scope of BODY. @@ -247,12 +233,9 @@ held mutex, WITH-RECURSIVE-LOCK allows recursive lock attempts to succeed." #-sb-thread (progn - (defun call-with-mutex (function mutex value waitp timeout) + (defun call-with-mutex (function mutex waitp timeout) (declare (ignore mutex waitp timeout) (function function)) - (unless (or (null value) (eq *current-thread* value)) - (error "~S called with non-nil :VALUE that isn't the current thread." - 'with-mutex)) (funcall function)) (defun call-with-recursive-lock (function mutex waitp timeout) @@ -267,12 +250,9 @@ held mutex, WITH-RECURSIVE-LOCK allows recursive lock attempts to succeed." #+sb-thread (progn - (defun call-with-mutex (function mutex value waitp timeout) + (defun call-with-mutex (function mutex waitp timeout) (declare (function function)) (declare (dynamic-extent function)) - (unless (or (null value) (eq *current-thread* value)) - (error "~S called with non-nil :VALUE that isn't the current thread." - 'with-mutex)) (let ((got-it nil)) (without-interrupts (unwind-protect @@ -286,13 +266,13 @@ held mutex, WITH-RECURSIVE-LOCK allows recursive lock attempts to succeed." (defun call-with-recursive-lock (function mutex waitp timeout) (declare (function function)) (declare (dynamic-extent function)) - (let ((inner-lock-p (eq (mutex-%owner mutex) *current-thread*)) + (let ((had-it (holding-mutex-p mutex)) (got-it nil)) (without-interrupts (unwind-protect - (when (or inner-lock-p (setf got-it (allow-with-interrupts - (grab-mutex mutex :waitp waitp - :timeout timeout)))) + (when (or had-it + (setf got-it (allow-with-interrupts + (grab-mutex mutex :waitp waitp :timeout timeout)))) (with-local-interrupts (funcall function))) (when got-it (release-mutex mutex)))))) @@ -301,11 +281,12 @@ held mutex, WITH-RECURSIVE-LOCK allows recursive lock attempts to succeed." (declare (function function)) (declare (dynamic-extent function)) (without-interrupts - (let ((inner-lock-p (eq *current-thread* (mutex-owner lock))) + (let ((had-it (holding-mutex-p lock)) (got-it nil)) (unwind-protect - (when (or inner-lock-p - (setf got-it (grab-mutex lock))) + (when (or had-it (setf got-it (grab-mutex lock))) (funcall function)) (when got-it (release-mutex lock))))))) + +(sb-ext:define-load-time-global *make-thread-lock* nil) diff --git a/src/code/time.lisp b/src/code/time.lisp index 6831c753c8..eacabded32 100644 --- a/src/code/time.lisp +++ b/src/code/time.lisp @@ -11,9 +11,6 @@ (in-package "SB-IMPL") -(defun time-reinit () - (reinit-internal-real-time)) - ;;; Implemented in unix.lisp and win32.lisp. (setf (documentation 'get-internal-real-time 'function) "Return the real time (\"wallclock time\") since startup in the internal @@ -193,14 +190,15 @@ format." (truncate years 100)) (truncate (+ years 300) 400)))) -(defconstant +days-before-month+ +(defconstant-eqx +days-before-month+ #.(let ((reversed-result nil) (sum 0)) (push nil reversed-result) (dolist (days-in-month '(31 28 31 30 31 30 31 31 30 31 30 31)) (push sum reversed-result) (incf sum days-in-month)) - (coerce (nreverse reversed-result) 'simple-vector))) + (coerce (nreverse reversed-result) 'simple-vector)) + #'equalp) (defun encode-universal-time (second minute hour date month year &optional time-zone) @@ -431,12 +429,8 @@ EXPERIMENTAL: Interface subject to change." old-page-faults new-page-faults real-time-overhead - run-utime-overhead - run-stime-overhead - page-faults-overhead old-bytes-consed new-bytes-consed - cons-overhead (fun (if (functionp function) function (fdefinition function)))) (declare (function fun)) ;; Calculate the overhead... @@ -450,14 +444,10 @@ EXPERIMENTAL: Interface subject to change." (multiple-value-setq (new-run-utime new-run-stime new-page-faults new-bytes-consed) (time-get-sys-info)) - (setq run-utime-overhead (- new-run-utime old-run-utime)) - (setq run-stime-overhead (- new-run-stime old-run-stime)) - (setq page-faults-overhead (- new-page-faults old-page-faults)) (setq old-real-time (get-internal-real-time)) (setq old-real-time (get-internal-real-time)) (setq new-real-time (get-internal-real-time)) (setq real-time-overhead (- new-real-time old-real-time)) - (setq cons-overhead (- new-bytes-consed old-bytes-consed)) ;; Now get the initial times. (multiple-value-setq (old-run-utime old-run-stime old-page-faults old-bytes-consed) @@ -467,7 +457,6 @@ EXPERIMENTAL: Interface subject to change." (*eval-calls* 0) (sb-c::*lambda-conversions* 0) (aborted t)) - (declare (special *eval-calls* sb-c::*lambda-conversions*)) (multiple-value-bind (h0 l0) (read-cycle-counter) (unwind-protect (multiple-value-prog1 (apply fun arguments) @@ -496,8 +485,10 @@ EXPERIMENTAL: Interface subject to change." (note :processor-cycles cycles #'zerop)) (note :lambdas-converted sb-c::*lambda-conversions* #'zerop) (note :eval-calls *eval-calls* #'zerop) - (note :gc-run-time-ms gc-internal-run-time) + (note :gc-run-time-ms (floor gc-internal-run-time + (/ internal-time-units-per-second 1000))) (note :system-run-time-us system-run-time) (note :user-run-time-us user-run-time) - (note :real-time-ms real-time)) + (note :real-time-ms (floor real-time + (/ internal-time-units-per-second 1000)))) (apply timer plist)))))))))) diff --git a/src/code/timer.lisp b/src/code/timer.lisp index dd324598e2..cd5c3126a9 100644 --- a/src/code/timer.lisp +++ b/src/code/timer.lisp @@ -188,7 +188,7 @@ from now. For timers with a repeat interval it returns true." (defmacro with-scheduler-lock ((&optional) &body body) ;; Don't let the SIGALRM handler mess things up. - `(sb-thread::with-system-mutex (*scheduler-lock*) + `(with-system-mutex (*scheduler-lock*) ,@body)) (defun under-scheduler-lock-p () @@ -205,7 +205,7 @@ from now. For timers with a repeat interval it returns true." ;;; real time conversion (defun delta->real (delta) - (floor (* delta sb-xc:internal-time-units-per-second))) + (floor (* delta internal-time-units-per-second))) ;;; Public interface @@ -344,13 +344,10 @@ triggers." ;;; win32 waitable timers using a timerfd-like portability layer in ;;; the runtime. -#+sb-wtimer -(define-alien-type wtimer - #+win32 system-area-pointer ;HANDLE, but that's not defined yet - #+sunos system-area-pointer ;struct os_wtimer * - #+(or android linux bsd) int) +#+win32 +(define-alien-type wtimer system-area-pointer) ;HANDLE, but that's not defined yet -#+sb-wtimer +#+win32 (progn (define-alien-routine "os_create_wtimer" wtimer) (define-alien-routine "os_wait_for_wtimer" int (wt wtimer)) @@ -370,7 +367,7 @@ triggers." (prog1 (setf *waitable-timer-handle* (os-create-wtimer)) (setf *timer-thread* - (sb-thread::make-ephemeral-thread + (sb-thread::make-system-thread "System timer watchdog thread" (lambda () (loop while @@ -378,7 +375,7 @@ triggers." (os-wait-for-wtimer *waitable-timer-handle*)) *waitable-timer-handle*) doing (run-expired-timers))) - nil))))) + nil nil))))) (defun itimer-emulation-deinit () (with-scheduler-lock () @@ -403,15 +400,15 @@ triggers." (let ((min-nsec 100000)) (if (minusp time) (values 0 min-nsec) - (multiple-value-bind (s u) (floor time sb-xc:internal-time-units-per-second) - (setf u (floor (* (/ u sb-xc:internal-time-units-per-second) + (multiple-value-bind (s u) (floor time internal-time-units-per-second) + (setf u (floor (* (/ u internal-time-units-per-second) #.(expt 10 9)))) (if (and (= 0 s) (< u min-nsec)) ;; 0 0 means "shut down the timer" for setitimer (values 0 min-nsec) (values s u)))))) -#-(or sb-wtimer win32) +#+unix (progn (defun %set-system-timer (sec nsec) (sb-unix:unix-setitimer :real 0 0 sec (ceiling nsec 1000))) diff --git a/src/code/toplevel.lisp b/src/code/toplevel.lisp index 15d9f1a583..83432d7ea8 100644 --- a/src/code/toplevel.lisp +++ b/src/code/toplevel.lisp @@ -58,7 +58,7 @@ been specified on the command-line.") (%exit))))) (define-load-time-global *exit-lock* nil) -(define-thread-local *exit-in-process* nil) +(define-thread-local *exit-in-progress* nil) (declaim (type (or null real) *exit-timeout*)) (defvar *exit-timeout* 60 "Default amount of seconds, if any, EXIT should wait for other @@ -67,21 +67,86 @@ means to wait indefinitely.") (defun os-exit-handler (condition) (declare (ignore condition)) - (os-exit *exit-in-process* :abort t)) + (os-exit *exit-in-progress* :abort t)) (defvar *exit-error-handler* #'os-exit-handler) (defun call-exit-hooks () - (unless *exit-in-process* - (setf *exit-in-process* 0)) + (unless *exit-in-progress* + (setf *exit-in-progress* 0)) (handler-bind ((serious-condition *exit-error-handler*)) (call-hooks "exit" *exit-hooks* :on-error :warn))) +;;; TERMINATE-THREAD as it exists is basically unsuitable for anything other than +;;; interactive use, because it uses INTERRUPT-THREAD to unwind through user code. +;;; It is only slightly ok to call INTERRUPT-THREAD on a thread when you know +;;; exactly what it is doing. But even if you know what it's doing, you don't know +;;; when, so even if it's your code, it might be calling an alien destructor. +;;; It says right in the docstring of INTERRUPT-THREAD not to call it, +;;; and then what do we do? We go full steam ahead and call it. +;;; https://www.dictionary.com/e/slang/i-cant-even/ +;;; +;;; The full story here is that some users seem to think that EXIT is responsible +;;; for stopping any threads. There was a not-insignificant amount of discussion +;;; in https://groups.google.com/g/sbcl-devel/c/6Xj_d1dM1k0/m/G9OPAbOueDsJ +;;; But the mechanism employed for %EXIT-OTHER-THREADS is TERMINATE-THREAD, +;;; and that's just horrible. No matter how well the SBCL code is constructed, +;;; this approach can cause lockup. +;;; +;;; The *EXIT-HOOKS* are fine, but we can't assume that users call JOIN-THREAD in +;;; the exit hooks - they might ask threads to stop by assigning a global polled +;;; flag or by CONDITION-BROADCAST. They may do nothing. It's arbitrary. +;;; So maybe the threads are stopping "peacefully" and would finish on their own +;;; and we {could,should} just call JOIN-THREAD on them. But there's no way to know. +;;; Instead we just abort random threads with INTERRUPT-THREAD. +;;; Some of those threads that we forcibly terminate might have already been +;;; halfway through cleanly unwinding, which very possibly (or even likely) +;;; involves calling free() to release resources. When we interrupt a thread +;;; in the midst of its voluntary call to free(), no matter how clever free() is, +;;; we can presume that it will acquire a global lock. +;;; +;;; And there you have it - some dead thread owned a global lock that can't become +;;; available because we just punched that thread in the guts and killed it. +;;; Hence *all* threads (including non-Lisp) are permanently stuck waiting on +;;; a lock that is not owned by any running thread. +;;; +;;; I tried to remedy this by having the SIGURG signal handler silently discard +;;; a signal if interrupted at a non-Lisp program counter, but that presumes the +;;; call stack is never Lisp -> C -> Lisp, which first of all means that the handler +;;; needs to be entirely in C (if called from TERMINATE-THREAD) and secondly requires +;;; TERMINATE-THREAD to keep trying to send a signal if it thinks the signal was dropped. +;;; And you can't figure out whether a signal got purposely discard because then you'd +;;; need to wait an arbitrary amount of time to decide whether it might have been. +;;; Or invent a synchronized technique to see whether the asynchronous mechanism worked. +;;; +;;; So then the solution occurred to me: +;;; --> just don't terminate threads by force. Problem solved. <-- +;;; +;;; Therefore, if you want EXIT to be as near to the C exit() call as possible, +;;; after doing the lisp exit hooks, just set this global flag to NIL. +;;; Or leave it as T if you're fine with the old lockup-prone behavior. +;;; +;;; And if you think it's up to the Lisp environment to try to make threads stop +;;; by hook or by crook as a precondition to calling OS-EXIT (with which I disagree), +;;; the right solution is possibly modeled on pthread_cancel() which has specified +;;; cancelation points (system and C library calls) which check for cancelation, +;;; perform whatever cleanups were pushed by pthread_cleanup_push() and then stop. +;;; +;;; P.S. To see that #+sb-safepoint is no magic fix - suppose you have a stack +;;; with Lisp -> C -> -> Lisp where C acquired a resource and the currently +;;; top-of-stack Lisp function took a safepoint trap. It would be fine if all it +;;; wanted to do was GC, but is not safe in general. +;;; Hence #+sb-safepoint paints a dangerously attractive veneer over an unsafe +;;; concept, making it more subtly bad instead of very obviously bad. +;;; +;;; So this is a bad default. Bad bad bad. But it's backward-compatible. +(define-load-time-global *forcibly-terminate-threads-on-exit* t) + (defun %exit () ;; If anything goes wrong, we will exit immediately and forcibly. (handler-bind ((serious-condition *exit-error-handler*)) (let ((ok nil) - (code *exit-in-process*)) + (code *exit-in-progress*)) (if (consp code) ;; Another thread called EXIT, and passed the buck to us -- only ;; final call left to do. @@ -89,7 +154,11 @@ means to wait indefinitely.") (unwind-protect (progn (flush-standard-output-streams) - (sb-thread::%exit-other-threads) + (if *forcibly-terminate-threads-on-exit* + (sb-thread::%exit-other-threads) + (with-deadline (:seconds nil :override t) + #+sb-thread (finalizer-thread-stop) + (sb-thread:grab-mutex sb-thread::*make-thread-lock*))) (setf ok t)) (os-exit code :abort (not ok))))))) @@ -119,9 +188,9 @@ means to wait indefinitely.") $1f9))))))) (declare (inline split-float)) (typecase seconds - ((single-float $0f0 #.(float sb-xc:most-positive-fixnum $1f0)) + ((single-float $0f0 #.(float most-positive-fixnum $1f0)) (split-float)) - ((double-float $0d0 #.(float sb-xc:most-positive-fixnum $1d0)) + ((double-float $0d0 #.(float most-positive-fixnum $1d0)) (split-float)) (ratio (split-ratio-for-sleep seconds)) @@ -181,11 +250,11 @@ any non-negative real number." ;; use the largest representable value in that case. (timeout (or (seconds-to-maybe-internal-time seconds) (* safe-internal-seconds-limit - sb-xc:internal-time-units-per-second)))) + internal-time-units-per-second)))) (labels ((sleep-for-a-bit (remaining) (multiple-value-bind (timeout-sec timeout-usec stop-sec stop-usec deadlinep) - (decode-timeout (/ remaining sb-xc:internal-time-units-per-second)) + (decode-timeout (/ remaining internal-time-units-per-second)) (declare (ignore stop-sec stop-usec)) ;; Sleep until either the timeout or the deadline ;; expires. @@ -246,31 +315,28 @@ any non-negative real number." ;;; Flush anything waiting on one of the ANSI Common Lisp standard ;;; output streams before proceeding. (defun flush-standard-output-streams () - (let ((null (make-broadcast-stream))) - (dolist (name '(*debug-io* - *error-output* - *query-io* - *standard-output* - *trace-output* - *terminal-io*)) ;; 0. Pull out the underlying stream, so we know what it is. ;; 1. Handle errors on it. We're doing this on entry to ;; debugger, so we don't want recursive errors here. ;; 2. Rebind the stream symbol in case some poor sod sees ;; a broken stream here while running with *BREAK-ON-ERRORS*. - (let ((stream (stream-output-stream (symbol-value name)))) - ;; This is kind of crummy because it checks in globaldb for each - ;; stream symbol whether it can be bound to a stream. The translator - ;; for PROGV could skip ABOUT-TO-MODIFY-SYMBOL-VALUE based on - ;; an aspect of a policy, but if users figure that out they could - ;; do something horrible like rebind T and NIL. - (progv (list name) (list null) - (handler-bind ((stream-error - (lambda (c) - (when (eq stream (stream-error-stream c)) - (go :next))))) - (force-output stream)))) - :next)) + (flet ((flush (stream) + (let ((stream (stream-output-stream stream))) + (handler-bind ((stream-error + (lambda (c) + (when (eq (stream-error-stream c) stream) + (return-from flush))))) + (force-output stream))))) + (let ((null-stream (load-time-value *null-broadcast-stream* t))) + (macrolet ((flush-all (&rest streamvars) + `(progn + ,@(mapcar (lambda (streamvar) + `(let ((stream ,streamvar) + (,streamvar null-stream)) + (flush stream))) + streamvars)))) + (flush-all *debug-io* *error-output* *query-io* *standard-output* + *trace-output* *terminal-io*)))) (values)) (defun process-eval/load-options (options) @@ -336,6 +402,14 @@ any non-negative real number." args) (exit :code 1)) + +(defconstant-eqx +runtime-options+ + #("--noinform" "--core" "--help" "--version" "--dynamic-space-size" + "--control-stack-size" "--tls" + "--debug-environment" "--disable-ldb" "--lose-on-corruption" + "--end-runtime-options" "--merge-core-pages" "--no-merge-core-pages") + #'equalp) + ;;; the default system top level function (defun toplevel-init () (/show0 "entering TOPLEVEL-INIT") @@ -431,6 +505,9 @@ any non-negative real number." ((string= option "--end-toplevel-options") (pop-option) (return)) + ((find option +runtime-options+ :test #'string=) + (startup-error "C runtime option ~a in the middle of Lisp options." + option)) (t ;; Anything we don't recognize as a toplevel ;; option must be the start of user-level @@ -483,9 +560,9 @@ any non-negative real number." (pathname it)) :if-does-not-exist nil) (cond (stream - (dx-flet ((thunk () - (load-as-source stream :context kind))) - (sb-fasl::call-with-load-bindings #'thunk stream))) + (sb-fasl::call-with-load-bindings + (lambda (stream kind) (load-as-source stream :context kind)) + stream kind stream)) (specified-pathname (cerror "Ignore missing init file" "The specified ~A file ~A was not found." @@ -652,3 +729,67 @@ that provides the REPL for the system. Assumes that *STANDARD-INPUT* and ;;; a convenient way to get into the assembly-level debugger (defun %halt () (%primitive sb-c:halt)) + + +;;;; Examples of why NEVER NEVER NEVER to call TERMINATE-THREAD in production. + +#| +Example 1. Stuck somewhere in free() and in JOIN-THREAD. +[stuck at https://github.com/google/tcmalloc/blob/master/tcmalloc/cpu_cache.cc#L204] + Thread "A": + 0x98e697c [AbslInternalSpinLockDelay] + 0x9898287 [tcmalloc::CPUCache::UpdateCapacity(int, unsigned long, unsigned long, bool, tcmalloc::CPUCache::ObjectClass*, unsigned long*)] + 0x9898b38 [tcmalloc::CPUCache::Overflow(void*, unsigned long, int)] + 0x9891f39 [(anonymous namespace)::do_free_no_hooks(void*)] + 0x988cea1 [MallocBlock::ProcessFreeQueue(MallocBlock*, unsigned long, int)] + 0x26f490a [CFFI::FOREIGN-ARRAY-FREE] + Thread "main thread": + 0x9877f23 [futex_wait] + 0x32f32c8 [(FLET SB-UNIX::BODY :IN SB-THREAD::FUTEX-WAIT)] + 0x32f301f [SB-THREAD::%%WAIT-FOR-MUTEX] + 0x2f97f5d [SB-THREAD::%WAIT-FOR-MUTEX] + 0x2f287be [SB-THREAD::JOIN-THREAD] + +Example 2. Stuck somewhere else in free() and in JOIN-THREAD. + Thread "A": + 0x7f657d1a7cb9 [syscall] + 0x98e697c [AbslInternalSpinLockDelay] + 0x995e9e7 [absl::base_internal::SpinLock::SlowLock()] + 0x988d63b [MallocBlock::CheckAndClear(int)] + 0x9a8511f [__libc_free] + 0x26f490a [CFFI::FOREIGN-ARRAY-FREE] + Thread "main thread": + 0x9877f23 [futex_wait] + 0x32f32c8 [(FLET SB-UNIX::BODY :IN SB-THREAD::FUTEX-WAIT)] + 0x32f301f [SB-THREAD::%%WAIT-FOR-MUTEX] + 0x2f97f5d [SB-THREAD::%WAIT-FOR-MUTEX] + 0x2f287be [SB-THREAD::JOIN-THREAD] + +Example 3. main thread stuck in a C library exit handler: + 0x98e697c [AbslInternalSpinLockDelay] + 0x995e9e7 [absl::base_internal::SpinLock::SlowLock()] + 0x98a43cf [tcmalloc::HugePageAwareAllocator::LockAndAlloc(unsigned long, bool*)] + 0x98a423f [tcmalloc::HugePageAwareAllocator::New(unsigned long)] + 0x9896ee8 [tcmalloc::CentralFreeList::Populate()] + 0x9896c69 [tcmalloc::CentralFreeList::RemoveRange(void**, int)] + 0x9897e74 [tcmalloc::CPUCache::Refill(int, unsigned long)] + 0x989221b [tcmalloc::dbg_do_malloc(unsigned long, unsigned long*)] + 0x9a85045 [__libc_malloc] + 0x7f25a8ad5772 [__run_exit_handlers] + 0x7f25a8ad57c5 [exit] + 0x2fa99a3 [SB-SYS::OS-EXIT] + +Example 4. main thread stuck in a different C library exit handler: + 0x992ecfe [absl::synchronization_internal::Waiter::Wait(absl::synchronization_internal::KernelTimeout)] + 0x98e6865 [AbslInternalPerThreadSemWait] + 0x992fd4d [absl::Mutex::Block(absl::base_internal::PerThreadSynch*)] + 0x99324a0 [absl::Mutex::LockSlowLoop(absl::SynchWaitParams*, int)] + 0x9930b0e [absl::Mutex::LockSlow(absl::MuHowS const*, absl::Condition const*, int)] + 0x9930346 [absl::Mutex::Lock()] + 0x97ca6c0 [thread::local::internal::Var::~Var()] + 0x7fcf3fde0772 [__run_exit_handlers] + 0x7fcf3fde07c5 [exit] + 0x2fa99a3 [SB-SYS::OS-EXIT] + +There are plenty more where those came from. +|# diff --git a/src/code/traceroot.lisp b/src/code/traceroot.lisp index e8af618bb2..e3daac7cab 100644 --- a/src/code/traceroot.lisp +++ b/src/code/traceroot.lisp @@ -7,11 +7,12 @@ ;;;; provided with absolutely no warranty. See the COPYING and CREDITS ;;;; files for more information. -(in-package "SB-EXT") +(in-package "SB-IMPL") ;;; Not loaded until warm build. package-data-list only affects symbols ;;; that are visible to genesis. -(export '(search-roots)) +(eval-when (:compile-toplevel :load-toplevel :execute) + (export '(sb-ext::search-roots) 'sb-ext)) (define-alien-variable "gc_object_watcher" unsigned) (define-alien-variable "gc_traceroot_criterion" int) @@ -33,13 +34,6 @@ :all)) 0) -(defun find-lisp-thread-from-thread-struct (addr) - ;; It is of course possible to do this without consing the list - ;; of all threads, but I don't care. - (dolist (thread (sb-thread:list-all-threads)) - (when (= (sb-thread::thread-primitive-thread thread) addr) - (return thread)))) - ;;; Convert each path to (TARGET . NODES) ;;; where the first node in NODES is one of: ;;; @@ -55,33 +49,59 @@ ;; ;;; The rest of the path is a list of (OBJECT . WORD-INDEX). (defun preprocess-traceroot-results (inputs outputs &aux results) - (dovector (path outputs (nreverse results)) - (let ((target (weak-pointer-value (pop inputs)))) - (when (and target (listp path)) - (setq path (nreverse path)) - (let* ((root (car path)) - (root-kind (car root))) - (if (eq root-kind 0) ; heap object - (rplaca path :static) - (let* ((thread (find-lisp-thread-from-thread-struct - (ash (cadr root) sb-vm:n-fixnum-tag-bits))) - (extra (cddr root)) - (symbol - (unless (eql root-kind 1) - #+sb-thread - (find-symbol-from-tls-index (ash extra sb-vm:n-fixnum-tag-bits)) - #-sb-thread - extra))) - (awhen (and thread (sb-thread:thread-name thread)) - (setq thread it)) ; if nameless, just show as #<thread ...> - (rplaca path (ecase root-kind - (1 ; control stack - (if thread - `(,thread ,extra) - :pinned)) - (2 `(,thread ,symbol nil)) ; binding stack - (3 `(,thread ,symbol t))))))) ; TLS - (push (cons target path) results))))) + (flet ((collapse-lists (input) + (let* ((path (coerce input 'vector)) + (path-length (length path)) + (index (- path-length 2))) + ;; Combine successive CDR operations by scanning right-to-left + ;; for adjacent entries that represent two CDR operations. + ;; Repeat until nothing else can be spliced out. + ;; This entails just 1 linear scan. A left-to-right algorithm + ;; would be less efficient. + (loop + (when (< index 1) + (return (coerce (subseq path 0 path-length) 'list))) + (let* ((this-node (aref path index)) + (this-object (car this-node)) + (successor-index (1+ index)) + (successor-node (aref path successor-index)) + (successor-object (car successor-node))) + (when (and (consp this-object) + (consp successor-object) + (eql (cdr this-node) 1) ; operation is CDR + (>= (cdr successor-node) 1)) ; operation is 1 or more CDRs + (setf (cdr this-node) (1+ (cdr successor-node))) + (replace path path :start1 successor-index :start2 (1+ successor-index)) + (decf path-length)) + (decf index)))))) + (dovector (path outputs (nreverse results)) + (let ((target (weak-pointer-value (pop inputs)))) + (when (and target (listp path)) + (setq path (nreverse path)) + (let* ((root (car path)) + (root-kind (car root))) + (if (eq root-kind 0) ; heap object + (rplaca path :static) + (let* ((thread (sap-ref-lispobj + (sb-int:descriptor-sap (cadr root)) + (ash sb-vm::thread-lisp-thread-slot sb-vm:word-shift))) + (extra (cddr root)) + (symbol + (unless (eql root-kind 1) + #+sb-thread + (find-symbol-from-tls-index (ash extra sb-vm:n-fixnum-tag-bits)) + #-sb-thread + extra))) + (awhen (and thread (sb-thread:thread-name thread)) + (setq thread it)) ; if nameless, just show as #<thread ...> + (rplaca path (ecase root-kind + (1 ; control stack + (if thread + `(,thread ,extra) + :pinned)) + (2 `(,thread ,symbol nil)) ; binding stack + (3 `(,thread ,symbol t))))))) ; TLS + (push (cons target (collapse-lists path)) results)))))) (defun print-traceroot-path (path &key (stream *standard-output*) (multiline t)) (destructuring-bind (target root . rest) path @@ -117,7 +137,11 @@ pathname sb-impl::host hash-table) (format stream "~S~%" obj)) (t - (format stream "a ~(~a~)~%" (type-of obj)))))))) + (format stream "a ~(~a~)" (type-of obj)) + (when (consp obj) + (write-string " = " stream) + (write obj :stream stream :level 1 :length 3 :pretty nil)) + (terpri))))))) (t (let ((*print-pretty* nil)) (when (consp root) @@ -141,9 +165,11 @@ &key (:criterion (member :oldest :pseudo-static :static)) (:gc t) + (:ignore list) (:print (or boolean (eql :verbose))))) search-roots)) -(defun search-roots (weak-pointers &key (criterion :oldest) (gc nil) (print t)) +(defun search-roots (weak-pointers &key (criterion :oldest) (gc nil) + (ignore nil) (print t)) "Find roots keeping the targets of WEAK-POINTERS alive. WEAK-POINTERS must be a single SB-EXT:WEAK-POINTER or a list of those, @@ -178,6 +204,10 @@ to be considered. Possible values are: To find a root of an image-backed object, you want to stop only at a truly :STATIC object. +IGNORE is a list of objects to treat as if nonexistent in the heap. +It can often be useful for finding a path to an interned symbol other than +through its package by specifying the package as an ignored object. + PRINT controls whether discovered paths should be returned or printed. Possible values are @@ -222,7 +252,9 @@ printed. Possible values are Experimental: subject to change without prior notice." (let* ((input (ensure-list weak-pointers)) (output (make-array (length input))) - (param (cons input (cons :result output))) + (param (vector input + (if ignore (coerce ignore 'simple-vector) 0) + (cons :result output))) (criterion-value (ecase criterion (:oldest 0) (:pseudo-static 1) @@ -235,12 +267,12 @@ Experimental: subject to change without prior notice." (setf gc-object-watcher 0)) (t (sb-sys:without-gcing - (sb-vm::close-current-gc-region) + (sb-vm::close-thread-alloc-region) (alien-funcall (extern-alien "prove_liveness" (function int unsigned int)) (sb-kernel:get-lisp-obj-address param) criterion-value)))) - (case (cadr param) + (case (car (elt param 2)) (-1 (error "Input is not a proper list of weak pointers."))) (let ((paths (preprocess-traceroot-results input output))) (cond (print diff --git a/src/code/type-class.lisp b/src/code/type-class.lisp index fad80a7b04..c165b448ac 100644 --- a/src/code/type-class.lisp +++ b/src/code/type-class.lisp @@ -42,31 +42,22 @@ (make-array 32 :element-type 'bit :initial-element 0))) #+sb-xc -(macrolet ((def () - (let ((classes (make-array 32 :initial-element nil)) - ;; A curiosity observed with CLISP: if GENERATOR-STATE is not bound - ;; to a variable, but instead inserted with read-time-eval - ;; as "#.(sb-xc:make-array ...)" then DUMP-VECTOR fails to find the - ;; array in SB-COLD::*ARRAY-TO-SPECIALIZATION* even though it's there. - ;; Somehow between the read-time-eval and macroexpansion of DEF, - ;; CLISP seems to copy the array. It's as if READ did not return the - ;; object produced by "#." and I can't imagine how that's legal, - ;; let alone possible. - (generator-state - (sb-xc:make-array 1 :element-type '(and fixnum unsigned-byte) - :initial-element 0))) +(macrolet ((def (name init-form) `(progn - (declaim (type (simple-array (and fixnum unsigned-byte) (1)) - *ctype-hash-state*) - (type (simple-vector 32) *type-classes*)) - ;; Strictly speaking these array are immutable, as with all literals - ;; appearing in code. We mutate them anyway. Avoiding that minor infraction - ;; would require FOPCOMPILE to emit the MAKE-ARRAY expression to be executed - ;; in genesis; which is more of a project than I want to tackle. - (!define-load-time-global *ctype-hash-state* ,generator-state) - (!define-load-time-global *type-classes* ,classes) - (!cold-init-forms (fill *type-classes* (make-type-class :name :bogus))))))) - (def)) + (define-load-time-global ,name ,init-form) + (!cold-init-forms (setq ,name ,init-form))))) + (declaim (type (simple-array (and fixnum unsigned-byte) (1)) + *ctype-hash-state*) + (type (simple-vector 32) *type-classes*) + (type fixnum *type-cache-nonce*)) + (def *ctype-hash-state* (make-array 1 :element-type '(and fixnum unsigned-byte) + :initial-element 0)) + (def *type-classes* (make-array 32 :initial-element nil)) + ;; This is for "observers" who want to know if type names have been added. + ;; Rather than registering listeners, they can detect changes by comparing + ;; their stored nonce to the current nonce. Additionally the observers + ;; can detect whether function definitions have occurred. + (def *type-cache-nonce* 0)) #-sb-xc-host (define-compiler-macro type-class-or-lose (&whole form name) @@ -209,7 +200,7 @@ (coerce :type (or symbol null)) |# ) -#-sb-fluid (declaim (freeze-type type-class)) +(declaim (freeze-type type-class)) (defun type-class-or-lose (name) (or (find name *type-classes* :key #'type-class-name) @@ -265,6 +256,10 @@ ;; But it's consistent for genesis to treat it always as a raw slot. (%bits (missing-arg) :type sb-vm:word :read-only t)) +(defmethod print-object ((ctype ctype) stream) + (print-unreadable-object (ctype stream :type t) + (prin1 (type-specifier ctype) stream))) + ;;; take 27 low bits but exclude bits 20 and 21 ;;; [Our MASK-FIELD can't be folded, and I didn't feel like fixing that.] (defconstant +type-hash-mask+ @@ -364,16 +359,30 @@ (defmacro define-type-method ((class method &rest more-methods) lambda-list &body body) - (let ((name (symbolicate class "-" method "-TYPE-METHOD")) - (arg-restriction + (let* ((name (symbolicate class "-" method "-TYPE-METHOD")) + (arg-type (case class - (classoid 'classoid) - (number 'numeric-type) - (function 'fun-type) - (alien 'alien-type-type) - ;; hairy could reparse the specifier into anything - (hairy (if (eq method :simple-subtypep) t 'hairy-type)) - (t (symbolicate class "-TYPE"))))) + (classoid 'classoid) + (number 'numeric-type) + (function 'fun-type) + (alien 'alien-type-type) + (t (symbolicate class "-TYPE")))) + (first (car lambda-list)) + (second (cadr lambda-list)) + ;; make-host-1 verifies that type methods are invoked correctly, + ;; but afterwards we assume that they are + (operator #+sb-xc-host 'the #-sb-xc-host 'truly-the) + (rebind + (unless more-methods + (case method + ((:complex-subtypep-arg1 :unparse :negate :singleton-p) + `((,first (,operator ,arg-type ,first)))) + ((:complex-subtypep-arg2) + `((,first ,first) ; because there might be a DECLARE IGNORE on it + (,second (,operator ,arg-type ,second)))) + ((:simple-intersection2 :simple-union2 :simple-subtypep :simple-=) + `((,first (,operator ,arg-type ,first)) + (,second (,operator ,arg-type ,second)))))))) `(progn #+sb-xc-host (when (plusp (bit *type-class-was-inherited* (type-class-name->id ',class))) @@ -381,14 +390,7 @@ ;; both an ancestor and its descendants on some method. ;; Too bad for you- this throws the baby out with the bathwater. (error "Can't define-type-method for class ~s: already inherited" ',class)) - (defun ,name ,lambda-list - ,@(cond ((member method '(:unparse :negate :singleton-p)) - `((declare (type ,arg-restriction ,(car lambda-list))))) - ((and (member method '(:simple-intersection2 :simple-union2 - :simple-subtypep :simple-=)) - (not more-methods)) - `((declare (type ,arg-restriction ,(car lambda-list) ,(cadr lambda-list)))))) - ,@body) + (defun ,name ,lambda-list ,@(if rebind `((let ,rebind ,@body)) body)) (!cold-init-forms ,@(mapcar (lambda (method) `(setf (,(type-class-fun-slot method) @@ -532,16 +534,40 @@ (funcall (the function method-fun) type1 type2) (values subtypep win)))) -;;; KLUDGE: This function is dangerous, as its overuse could easily -;;; cause stack exhaustion through unbounded recursion. We only use -;;; it in one place; maybe it ought not to be a function at all? +(defvar *invoked-complex-=-other-method* nil) (defun invoke-complex-=-other-method (type1 type2) (let* ((type-class (type-class type1)) (method-fun (type-class-complex-= type-class))) - (if method-fun - (funcall (the function method-fun) type2 type1) + (if (and method-fun (not *invoked-complex-=-other-method*)) + (let ((*invoked-complex-=-other-method* t)) + (funcall (the function method-fun) type2 type1)) (values nil t)))) +;; The following macros expand into either constructor calls, +;; if building the cross-compiler, or forms which reference +;; previously constructed objects, if running the cross-compiler. +#+sb-xc-host +(progn + (defmacro literal-ctype (constructor &optional specifier) + (declare (ignore specifier)) + `(load-time-value ,constructor)) + + (defmacro literal-ctype-vector (var) + `(load-time-value ,var nil))) + +;; Omitting the specifier works only if the unparser method has been +;; defined in time to use it, and you're sure that constructor's result +;; can be unparsed - some unparsers may be confused if called on a +;; non-canonical object, such as an instance of (CONS T T) that is +;; not EQ to the interned instance. +#-sb-xc-host +(progn + (defmacro literal-ctype (constructor &optional (specifier nil specifier-p)) + (if specifier-p (specifier-type specifier) (symbol-value constructor))) + + (defmacro literal-ctype-vector (var) + (symbol-value var))) + ;;;; miscellany ;;; Hash two things (types) down to a target fixnum. In CMU CL this was an EQ @@ -552,13 +578,13 @@ ;;; FIXME: This was a macro in CMU CL, and is now an INLINE function. Is ;;; it important for it to be INLINE, or could be become an ordinary ;;; function without significant loss? -- WHN 19990413 -#-sb-fluid (declaim (inline type-cache-hash)) +(declaim (inline type-cache-hash)) (declaim (ftype (function (ctype ctype) (signed-byte #.sb-vm:n-fixnum-bits)) type-cache-hash)) (defun type-cache-hash (type1 type2) (logxor (ash (type-hash-value type1) -3) (type-hash-value type2))) -#-sb-fluid (declaim (inline type-list-cache-hash)) +(declaim (inline type-list-cache-hash)) (declaim (ftype (function (list) (signed-byte #.sb-vm:n-fixnum-bits)) type-list-cache-hash)) (defun type-list-cache-hash (types) @@ -567,8 +593,7 @@ do (setq res (logxor (ash res -1) (type-hash-value type))) finally (return res))) -;;; A few type representations need to be defined slightly earlier than -;;; 'early-type' is compiled, so they're defined here. +;;;; representations of types ;;; The NAMED-TYPE is used to represent *, T and NIL, the standard ;;; special cases, as well as other special cases needed to @@ -584,6 +609,31 @@ (:copier nil)) (name nil :type symbol :read-only t)) +;;; A HAIRY-TYPE represents anything too weird to be described +;;; reasonably or to be useful, such as NOT, SATISFIES, unknown types, +;;; and unreasonably complicated types involving AND. We just remember +;;; the original type spec. +;;; A possible improvement would be for HAIRY-TYPE to have a subtype +;;; named SATISFIES-TYPE for the hairy types which are specifically +;;; of the form (SATISFIES pred) so that we don't have to examine +;;; the sexpr repeatedly to decide whether it takes that form. +;;; And as a further improvement, we might want a table that maps +;;; predicates to their exactly recognized type when possible. +;;; We have such a table in fact - *BACKEND-PREDICATE-TYPES* +;;; as a starting point. But something like PLUSP isn't in there. +;;; On the other hand, either of these points may not be sources of +;;; inefficiency, and the latter if implemented might have undesirable +;;; user-visible ramifications, though it seems unlikely. +(defstruct (hairy-type (:include ctype) + (:constructor %make-hairy-type + (specifier &aux (%bits (pack-ctype-bits hairy)))) + (:constructor !make-interned-hairy-type + (specifier &aux (%bits (pack-interned-ctype-bits 'hairy)))) + (:copier nil)) + ;; the Common Lisp type-specifier of the type we represent. + ;; For other than an unknown type, this must be a (SATISFIES f) expression. + (specifier nil :type t :read-only t)) + ;;; A MEMBER-TYPE represent a use of the MEMBER type specifier. We ;;; bother with this at this level because MEMBER types are fairly ;;; important and union and intersection are well defined. @@ -671,6 +721,23 @@ (enumerable types)) (:copier nil))) +(defstruct (alien-type-type + (:include ctype (%bits (pack-ctype-bits alien))) + (:constructor %make-alien-type-type (alien-type)) + (:copier nil)) + (alien-type nil :type alien-type :read-only t)) + +(defstruct (negation-type (:include ctype (%bits (pack-ctype-bits negation))) + (:copier nil) + (:constructor make-negation-type (type))) + (type (missing-arg) :type ctype :read-only t)) + +;;; An UNKNOWN-TYPE is a type not known to the type system (not yet +;;; defined). We make this distinction since we don't want to complain +;;; about types that are hairy but defined. +(defstruct (unknown-type (:include hairy-type (%bits (pack-ctype-bits hairy))) + (:copier nil))) + ;;; a list of all the float "formats" (i.e. internal representations; ;;; nothing to do with #'FORMAT), in order of decreasing precision (defglobal *float-formats* @@ -728,34 +795,6 @@ (car-type (missing-arg) :type ctype :read-only t) (cdr-type (missing-arg) :type ctype :read-only t)) -(in-package "SB-ALIEN") -(def!struct (alien-type - (:copier nil) - (:constructor make-alien-type - (&key class bits alignment - &aux (alignment - (or alignment (guess-alignment bits)))))) - (class 'root :type symbol :read-only t) - (bits nil :type (or null unsigned-byte)) - (alignment nil :type (or null unsigned-byte))) -(!set-load-form-method alien-type (:xc :target)) - -(in-package "SB-KERNEL") -(defstruct (alien-type-type - (:include ctype (%bits (pack-ctype-bits alien))) - (:constructor %make-alien-type-type (alien-type)) - (:copier nil)) - (alien-type nil :type alien-type :read-only t)) - -;;; the description of a &KEY argument -(defstruct (key-info #-sb-xc-host (:pure t) - (:copier nil)) - ;; the key (not necessarily a keyword in ANSI Common Lisp) - (name (missing-arg) :type symbol :read-only t) - ;; the type of the argument value - (type (missing-arg) :type ctype :read-only t)) -(declaim (freeze-type key-info)) - ;;; ARGS-TYPE objects are used both to represent VALUES types and ;;; to represent FUNCTION types. (defstruct (args-type (:include ctype) @@ -773,6 +812,22 @@ ;; true if other &KEY arguments are allowed (allowp nil :type boolean :read-only t)) +;;; the description of a &KEY argument +(defstruct (key-info #-sb-xc-host (:pure t) + (:copier nil)) + ;; the key (not necessarily a keyword in ANSI Common Lisp) + (name (missing-arg) :type symbol :read-only t) + ;; the type of the argument value + (type (missing-arg) :type ctype :read-only t)) +(declaim (freeze-type key-info)) + +(defstruct (values-type + (:include args-type (%bits (pack-ctype-bits values))) + (:constructor %make-values-type) + (:copier nil))) + +(declaim (freeze-type values-type)) + ;;; (SPECIFIER-TYPE 'FUNCTION) and its subtypes (defstruct (fun-type (:include args-type (%bits (pack-ctype-bits function))) (:copier nil) @@ -795,6 +850,38 @@ (:constructor make-fun-designator-type (required optional rest keyp keywords allowp wild-args returns)))) + +;;; The CONSTANT-TYPE structure represents a use of the CONSTANT-ARG +;;; "type specifier", which is only meaningful in function argument +;;; type specifiers used within the compiler. (It represents something +;;; that the compiler knows to be a constant.) +(defstruct (constant-type + (:include ctype (%bits (pack-ctype-bits constant))) + (:copier nil)) + ;; The type which the argument must be a constant instance of for this type + ;; specifier to win. + (type (missing-arg) :type ctype :read-only t)) + + +;;; A SIMD-PACK-TYPE is used to represent a SIMD-PACK type. +#+sb-simd-pack +(defstruct (simd-pack-type + (:include ctype (%bits (pack-ctype-bits simd-pack))) + (:constructor %make-simd-pack-type (element-type)) + (:copier nil)) + (element-type (missing-arg) + :type (simple-bit-vector #.(length *simd-pack-element-types*)) + :read-only t)) + +#+sb-simd-pack-256 +(defstruct (simd-pack-256-type + (:include ctype (%bits (pack-ctype-bits simd-pack-256))) + (:constructor %make-simd-pack-256-type (element-type)) + (:copier nil)) + (element-type (missing-arg) + :type (simple-bit-vector #.(length *simd-pack-element-types*)) + :read-only t)) + (declaim (ftype (sfunction (ctype ctype) (values t t)) csubtypep)) ;;; Look for nice relationships for types that have nice relationships ;;; only when one is a hierarchical subtype of the other. @@ -817,18 +904,6 @@ ((csubtypep type2 type1) type1) (t nil))) -;; KLUDGE: putting this here satisfies CMUCL for an inexplicable reason. -;; It should suffice to put it anywhere before %MAKE-CHARACTER-SET-TYPE -;; is actually called. -;; -;; all character-set types are enumerable, but it's not possible -;; for one to be TYPE= to a MEMBER type because (MEMBER #\x) -;; is not internally represented as a MEMBER type. -;; So in case it wasn't clear already ENUMERABLE-P does not mean -;; "possibly a MEMBER type in the Lisp-theoretic sense", -;; but means "could be implemented in SBCL as a MEMBER type". -(define-type-class character-set :enumerable nil - :might-contain-other-types nil) (!defun-from-collected-cold-init-forms !type-class-cold-init) ;;; CAUTION: unhygienic macro specifically designed to expand into body code @@ -901,7 +976,7 @@ (values nil nil)))) ; can't decide (test-character-type (type) (when (characterp ,thing) - (let ((code (sb-xc:char-code ,thing))) + (let ((code (char-code ,thing))) (dolist (pair (character-set-type-pairs type) nil) (destructuring-bind (low . high) pair (when (<= low code high) @@ -909,7 +984,7 @@ ;; It should always work to dispatch by class-id, but ALIEN-TYPE-TYPE ;; is a problem in the cross-compiler due to not having a type-class-id ;; when 'src/code/cross-type' is compiled. I briefly tried moving - ;; it later, but then class-init failed to compile. + ;; it later, but then type-init failed to compile. #+sb-xc-host (etypecase type ,@clauses) #-sb-xc-host diff --git a/src/code/type-init.lisp b/src/code/type-init.lisp index a9c3e6bad8..ea46d36d3e 100644 --- a/src/code/type-init.lisp +++ b/src/code/type-init.lisp @@ -1,10 +1,10 @@ ;;;; When this file's top level forms are run, it precomputes the ;;;; translations for commonly used type specifiers. This stuff is ;;;; split off from the other type stuff to get around problems with -;;;; everything needing to be loaded before everything else. This -;;;; stuff is also somewhat implementation-dependent in that -;;;; implementations may want to precompute other types which are -;;;; important to them. +;;;; everything needing to be loaded before everything else. This file +;;;; is the first to exercise the type machinery. This stuff is also +;;;; somewhat implementation-dependent in that implementations may +;;;; want to precompute other types which are important to them. ;;;; This software is part of the SBCL system. See the README file for ;;;; more information. @@ -17,11 +17,36 @@ (in-package "SB-KERNEL") +;;; built-in classes +(/show0 "beginning type-init.lisp") +#+sb-xc-host +(dolist (x *builtin-classoids*) + (destructuring-bind (name &key (translation nil trans-p) &allow-other-keys) + x + (/show "doing class with" name) + (when trans-p + (let ((classoid (classoid-cell-classoid (find-classoid-cell name :create t))) + (type (specifier-type translation))) + (when (typep (built-in-classoid-translation classoid) 'ctype) + (aver (eq (built-in-classoid-translation classoid) type))) + (setf (built-in-classoid-translation classoid) type) + (setf (info :type :builtin name) type))))) + +;;; the Common Lisp defined type spec symbols +(defconstant-eqx +!standard-type-names+ + '(array atom bignum bit bit-vector character compiled-function + complex cons double-float extended-char fixnum float function + hash-table integer keyword list long-float nil null number package + pathname random-state ratio rational real readtable sequence + short-float simple-array simple-bit-vector simple-string simple-vector + single-float standard-char stream string base-char symbol t vector) + #'equal) + ;;; built-in symbol type specifiers ;;; Predefined types that are of kind :INSTANCE can't have their ;;; :BUILTIN property set, so we cull them out. This used to operate -;;; on all *!STANDARD-TYPE-NAMES* because !PRECOMPUTE-TYPES was ok to +;;; on all +!STANDARD-TYPE-NAMES+ because !PRECOMPUTE-TYPES was ok to ;;; call on unknown types. This relied upon the knowledge that ;;; VALUES-SPECIFIER-TYPE avoided signaling a PARSE-UNKNOWN-TYPE ;;; condition while in cold-init. This is terrible! It means that @@ -38,7 +63,7 @@ (remove-if (lambda (x) (memq x '(compiled-function hash-table package pathname random-state readtable))) - *!standard-type-names*)) + +!standard-type-names+)) #+sb-xc-host (setf *type-system-initialized* t) diff --git a/src/code/late-type.lisp b/src/code/type.lisp similarity index 65% rename from src/code/late-type.lisp rename to src/code/type.lisp index 07dd939cb6..aa83c7633c 100644 --- a/src/code/late-type.lisp +++ b/src/code/type.lisp @@ -2,8 +2,7 @@ ;;;; subtypes of interesting BUILT-IN-CLASSes) and the interfaces to ;;;; the type system. Common Lisp type specifiers are parsed into a ;;;; somewhat canonical internal type representation that supports -;;;; type union, intersection, etc. (Except that ALIEN types have -;;;; moved out..) +;;;; type union, intersection, etc. ;;;; This software is part of the SBCL system. See the README file for ;;;; more information. @@ -16,8 +15,6 @@ (in-package "SB-KERNEL") -(/show0 "late-type.lisp 19") - (!begin-collecting-cold-init-forms) ;;; ### Remaining incorrectnesses: @@ -86,6 +83,26 @@ (sb-c:compiler-warn "Invalid :TYPE for slot ~S in ~S ~S: ~A." slot-name operator class-name condition)))))) +(defun maybe-reparse-specifier (type) + (when (unknown-type-p type) + (let* ((spec (unknown-type-specifier type)) + (name (if (consp spec) + (car spec) + spec))) + (when (info :type :kind name) + (let ((new-type (specifier-type spec))) + (unless (unknown-type-p new-type) + new-type)))))) + +;;; Evil macro. +(defmacro maybe-reparse-specifier! (type) + (aver (symbolp type)) + (with-unique-names (new-type) + `(let ((,new-type (maybe-reparse-specifier ,type))) + (when ,new-type + (setf ,type ,new-type) + t)))) + ;;; These functions are used as method for types which need a complex ;;; subtypep method to handle some superclasses, but cover a subtree ;;; of the type graph (i.e. there is no simple way for any other type @@ -203,10 +220,10 @@ (specifier-type guard))))) (return (or (eq type2 (car x)) - (let ((inherits (layout-inherits - (classoid-layout (car x))))) + (let ((inherits (wrapper-inherits + (classoid-wrapper (car x))))) (dotimes (i (length inherits) nil) - (when (eq type2 (layout-classoid (svref inherits i))) + (when (eq type2 (wrapper-classoid (svref inherits i))) (return t)))))))))) t)))) @@ -257,6 +274,46 @@ ;;;; -- Many of the places that can be annotated with real types can ;;;; also be annotated with function or values types. +(define-type-class values :enumerable nil :might-contain-other-types nil) + +(defun-cached (make-values-type-cached + :hash-bits 8 + :hash-function + (lambda (req opt rest allowp) + (logxor (type-list-cache-hash req) + (type-list-cache-hash opt) + (if rest + (type-hash-value rest) + 42) + ;; Results (logand #xFF (sxhash t/nil)) + ;; hardcoded to avoid relying on the xc host. + ;; [but (logand (sxhash nil) #xff) => 2 + ;; for me, so the code and comment disagree, + ;; but not in a way that matters.] + (if allowp + 194 + 11)))) + ((required equal-but-no-car-recursion) + (optional equal-but-no-car-recursion) + (rest eq) + (allowp eq)) + (%make-values-type :required required + :optional optional + :rest rest + :allowp allowp)) + +(defun make-values-type (&key required optional rest allowp) + (multiple-value-bind (required optional rest) + (canonicalize-args-type-args required optional rest) + (cond ((and (null required) + (null optional) + (eq rest *universal-type*)) + *wild-type*) + ((memq *empty-type* required) + *empty-type*) + (t (make-values-type-cached required optional + rest allowp))))) + (define-type-method (values :simple-subtypep :complex-subtypep-arg1) (type1 type2) (declare (ignore type2)) @@ -304,10 +361,9 @@ ;;; a flag that we can bind to cause complex function types to be ;;; unparsed as FUNCTION. This is useful when we want a type that we ;;; can pass to TYPEP. -(defparameter *unparse-fun-type-simplify* nil) ; initialized by genesis -;;; A flag to prevent TYPE-OF calls by user applications from returning -;;; (NOT x). TYPE-SPECIFIER usually allows it to preserve information. -(defparameter *unparse-allow-negation* t) ; initialized by genesis +(defvar *unparse-fun-type-simplify* nil) + +(define-type-class function :enumerable nil :might-contain-other-types nil) (define-type-method (function :negate) (type) (make-negation-type type)) @@ -469,6 +525,42 @@ (values t t)) (t (type=-args type1 type2))))))) +#+sb-xc-host +(defvar *interned-fun-types* + (flet ((fun-type (n) + (!make-interned-fun-type (pack-interned-ctype-bits 'function) + (make-list n :initial-element *universal-type*) + nil nil nil nil nil nil *wild-type*))) + (vector (fun-type 0) (fun-type 1) (fun-type 2) (fun-type 3)))) + +(defun make-fun-type (&key required optional rest + keyp keywords allowp + wild-args returns + designator) + (let ((rest (if (eq rest *empty-type*) nil rest)) + (n (length required))) + (cond (designator + (make-fun-designator-type required optional rest keyp keywords + allowp wild-args returns)) + ((and + (<= n 3) + (not optional) (not rest) (not keyp) + (not keywords) (not allowp) (not wild-args) + (eq returns *wild-type*) + (not (find *universal-type* required :test #'neq))) + (svref (literal-ctype-vector *interned-fun-types*) n)) + (t + (%make-fun-type required optional rest keyp keywords + allowp wild-args returns))))) + +;; This seems to be used only by cltl2, and within 'cross-type', +;; where it is never used, which makes sense, since pretty much we +;; never want this object, but instead the classoid FUNCTION +;; if we know nothing about a function's signature. +;; Maybe this should not exist unless cltl2 is loaded??? +(define-load-time-global *universal-fun-type* + (make-fun-type :wild-args t :returns *wild-type*)) + (define-type-class constant :inherits values) (define-type-method (constant :negate) (type) @@ -483,6 +575,80 @@ (def-type-translator constant-arg ((:context context) type) (make-constant-type :type (single-value-specifier-type type context))) +(defun canonicalize-args-type-args (required optional rest &optional keyp) + (when (eq rest *empty-type*) + ;; or vice-versa? + (setq rest nil)) + (loop with last-not-rest = nil + for i from 0 + for opt in optional + do (cond ((eq opt *empty-type*) + (return (values required (subseq optional 0 i) rest))) + ((and (not keyp) (neq opt rest)) + (setq last-not-rest i))) + finally (return (values required + (cond (keyp + optional) + (last-not-rest + (subseq optional 0 (1+ last-not-rest)))) + rest)))) + +;;; CONTEXT is the cookie passed down from the outermost surrounding call +;;; of BASIC-PARSE-TYPE. INNER-CONTEXT-KIND is an indicator of whether +;;; we are currently parsing a FUNCTION or a VALUES compound type specifier. +;;; If the entire LAMBDA-LISTY-THING is *, we do not call this function at all. +;;; If an element of it is *, that constitutes an error, as is clear +;;; for VALUES: "The symbol * may not be among the value-types." +;;; http://www.lispworks.com/documentation/HyperSpec/Body/t_values.htm +;;; and the FUNCTION compound type, for which the grammar is: +;;; function [arg-typespec [value-typespec]] +;;; arg-typespec::= (typespec* [&optional typespec*] [&rest typespec];[&key (keyword typespec)*]) +;;; typespec --- a type specifier. +;;; where the glossary says: "type specifier: n. an expression that denotes a type." +;;; which of course * does not denote, and is made all the more clear by the fact +;;; that the AND, OR, and NOT combinators explicitly preclude * as an element. +(defun parse-args-types (context lambda-listy-thing inner-context-kind) + (multiple-value-bind (llks required optional rest keys) + (parse-lambda-list + lambda-listy-thing + :context inner-context-kind + :accept (ecase inner-context-kind + (:values-type (lambda-list-keyword-mask '(&optional &rest))) + (:function-type (lambda-list-keyword-mask + '(&optional &rest &key &allow-other-keys)))) + :silent t) + (labels ((parse-list (list) (mapcar #'parse-one list)) + (parse-one (x) + (specifier-type x context + (case inner-context-kind + (:function-type 'function) + (t 'values))))) + (let ((required (parse-list required)) + (optional (parse-list optional)) + (rest (when rest (parse-one (car rest)))) + (keywords + (collect ((key-info)) + (dolist (key keys) + (unless (proper-list-of-length-p key 2) + (error "Keyword type description is not a two-list: ~S." key)) + (let ((kwd (first key))) + (when (find kwd (key-info) :key #'key-info-name) + (error (sb-format:tokens + "~@<repeated keyword ~S in lambda list: ~2I~_~ + ~/sb-impl:print-lambda-list/~:>") + kwd lambda-listy-thing)) + (key-info + (make-key-info + ;; MAKE-KEY-INFO will complain if KWD is not a symbol. + ;; That's good enough - we don't need an extra check here. + :name kwd + :type (single-value-specifier-type (second key) context))))) + (key-info)))) + (multiple-value-bind (required optional rest) + (canonicalize-args-type-args required optional rest + (ll-kwds-keyp llks)) + (values llks required optional rest keywords)))))) + ;;; Return the lambda-list-like type specification corresponding ;;; to an ARGS-TYPE. (declaim (ftype (function (args-type) list) unparse-args-types)) @@ -581,11 +747,11 @@ (etypecase type (named-type (ecase (named-type-name type) - ((t *) sb-xc:call-arguments-limit) + ((t *) call-arguments-limit) ((nil) 0))) (values-type (if (values-type-rest type) - sb-xc:call-arguments-limit + call-arguments-limit (+ (length (values-type-optional type)) (length (values-type-required type))))))) @@ -596,15 +762,13 @@ ;;; VALUES type with a single value. (defun type-single-value-p (type) - (and (%values-type-p type) + (and (values-type-p type) (not (values-type-rest type)) (null (values-type-optional type)) (singleton-p (values-type-required type)))) ;;; Return the type of the first value indicated by TYPE. This is used ;;; by people who don't want to have to deal with VALUES types. -#-sb-fluid (declaim (freeze-type values-type)) -; (inline single-value-type)) (defun single-value-type (type) (declare (type ctype type)) (cond ((eq type *wild-type*) @@ -928,6 +1092,14 @@ (do ((t1 types1 (rest t1)) (t2 types2 (rest t2))) ((null t2) + (loop named loop + for type in t1 + do (multiple-value-bind (res win) + (csubtypep type rest2) + (unless win + (return (values nil nil))) + (unless res + (return (values nil t))))) (csubtypep rest1 rest2)) (multiple-value-bind (res win-p) (csubtypep (first t1) (first t2)) @@ -975,7 +1147,7 @@ ;;; type specifiers (or their expansions) are EQUAL." ;;; i.e. though it is not longer technically a MUST, it suggests that EQUAL is ;;; in fact a valid implementation, at least where it computes T. -(defun sb-xc:subtypep (type1 type2 &optional environment) +(defun subtypep (type1 type2 &optional environment) "Return two values indicating the relationship between type1 and type2. If values are T and T, type1 definitely is a subtype of type2. If values are NIL and T, type1 definitely is not a subtype of type2. @@ -993,7 +1165,6 @@ (defun ctype-interned-p (ctype) (logtest (type-hash-value ctype) +type-internedp+)) -#-sb-devel (declaim (start-block)) ;;; If two types are definitely equivalent, return true. The second @@ -1181,31 +1352,361 @@ (declare (type ctype type)) (funcall (type-class-unparse (type-class type)) type)) -;;; Don't try to define a print method until it's actually gonna work! -;;; (Otherwise this would be near the DEFSTRUCT) -(defmethod print-object ((ctype ctype) stream) - (print-unreadable-object (ctype stream :type t) - (prin1 (type-specifier ctype) stream))) -(defun-cached (type-negation :hash-function #'type-hash-value - :hash-bits 8 - :values 1) - ((type eq)) - (declare (type ctype type)) - (funcall (type-class-negate (type-class type)) type)) +;;; Return the type structure corresponding to a type specifier. +;;; +;;; Note: VALUES-SPECIFIER-TYPE-CACHE-CLEAR must be called whenever a +;;; type is defined (or redefined). +;;; +;;; As I understand things, :FORTHCOMING-DEFCLASS-TYPE behaves contrarily +;;; to the CLHS intent, which is to make the type known to the compiler. +;;; If we compile in one file: +;;; (DEFCLASS FRUITBAT () ()) +;;; (DEFUN FRUITBATP (X) (TYPEP X 'FRUITBAT)) +;;; we see that it emits a call to %TYPEP with the symbol FRUITBAT as its +;;; argument, whereas it should involve CLASSOID-CELL-TYPEP and LAYOUT-OF, +;;; which (correctly) signals an error if the class were not defined by the +;;; time of the call. Delayed re-parsing of FRUITBAT into any random specifier +;;; at call time is wrong. +;;; +;;; FIXME: symbols which are :PRIMITIVE are inconsistently accepted as singleton +;;; lists. e.g. (BIT) and (ATOM) are considered legal, but (FIXNUM) and +;;; (CHARACTER) are not. It has to do with whether the primitive is actually +;;; a DEFTYPE. The CLHS glossary implies that the singleton is *always* legal. +;;; "For every atomic type specifier, x, there is an _equivalent_ [my emphasis] +;;; compound type specifier with no arguments supplied, (x)." +;;; By that same reasonining, is (x) accepted if x names a class? +;;; -(defun-cached (type-singleton-p :hash-function #'type-hash-value - :hash-bits 8 - :values 2) - ((type eq)) - (declare (type ctype type)) - (let ((function (type-class-singleton-p (type-class type)))) - (if function - (funcall function type) - (values nil nil)))) +;;; The xc host uses an ordinary hash table for memoization. +#+sb-xc-host +(let ((table (make-hash-table :test 'equal))) + (defun !values-specifier-type-memo-wrapper (thunk specifier) + (multiple-value-bind (type yesp) (gethash specifier table) + (if yesp + type + (setf (gethash specifier table) (funcall thunk))))) + (defun values-specifier-type-cache-clear () + (clrhash table))) +;;; This cache is sized extremely generously, which has payoff +;;; elsewhere: it improves the TYPE= and CSUBTYPEP functions, +;;; since EQ types are an immediate win. +#-sb-xc-host +(sb-impl::!define-hash-cache values-specifier-type + ((orig equal-but-no-car-recursion)) () + :hash-function #'sxhash :hash-bits 10) + +(declaim (inline make-type-context)) +(defstruct (type-context + (:constructor make-type-context + (spec &optional proto-classoid (options 0))) + (:copier nil) + (:predicate nil)) + (spec nil :read-only t) + (proto-classoid nil :read-only t) + (options 0 :type fixnum)) +(defconstant +type-parse-cache-inhibit+ 1) +(defconstant +type-parse-signal-inhibit+ 2) +(defmacro type-context-cacheable (x) + `(not (logtest (type-context-options ,x) +type-parse-cache-inhibit+))) + +;;; Maintain a table of symbols designating unknown types that have any references +;;; to them, making it easy to inquire whether such things exist. This is at a lower +;;; layer than the parser cache - it's a cache of the constructor itself - so we'll +;;; sitll signal that an unknown specifier is unknown on each reparse of the same. +;;; But as long as any reference enlivens the relevant CTYPE, we'll return that object. +(defglobal **unknown-type-atoms** + ;; This table is specified as unsynchronized because we need to wrap the lock + ;; around a read/modify/write. GETHASH and PUTHASH can't do that themselves. + (sb-impl::make-system-hash-table :test 'eq :weakness :value :synchronized nil)) + +#-sb-xc-host +(progn (declaim (inline class-classoid)) + (defun class-classoid (class) + (wrapper-classoid (sb-pcl::class-wrapper class)))) + +;;; Parsing of type specifiers comes in many variations: +;;; SINGLE-VALUE-SPECIFIER-TYPE: +;;; disallow VALUES even if single value, but allow * +;;; SPECIFIER-TYPE: +;;; disallow (VALUES ...) even if single value, and disallow * +;;; VALUES-SPECIFIER-TYPE: +;;; allow VALUES, disallow * +;;; TYPE-OR-NIL-IF-UNKNOWN: +;;; like SPECIFIER-TYPE, but return NIL if contains unknown +;;; all the above are funneled through BASIC-PARSE-TYPESPEC. + +;;; The recursive %PARSE-TYPE function is used for nested invocations +;;; of type spec parsing, passing the outermost context through on each call. +;;; Callers should use the BASIC-PARSE-TYPESPEC interface. + +;;; Hint for when you bork this and/or bork the :UNPARSE methods - do: +;;; (remove-method #'print-object (find-method #'print-object nil +;;; (list (find-class 'ctype) (find-class 't)))) +;;; so that 'backtrace' doesn't encounter an infinite chain of errors. + +(macrolet ((fail (spec) + `(error "bad thing to be a type specifier: ~/sb-impl:print-type-specifier/" + ,spec))) +(defun %parse-type (spec context) + (declare (type type-context context)) + (prog* ((head (if (listp spec) (car spec) spec)) + (builtin (if (symbolp head) + (info :type :builtin head) + (return (fail spec))))) + (when (deprecated-thing-p 'type head) + (setf (type-context-options context) + (logior (type-context-options context) +type-parse-cache-inhibit+)) + (signal 'parse-deprecated-type :specifier spec)) + (when (atom spec) + ;; If spec is non-atomic, the :BUILTIN value is inapplicable. + ;; There used to be compound builtins, but not any more. + (when builtin (return builtin)) + ;; Any spec that apparently refers to a defstruct form + ;; that's being macroexpanded should refer to that type. + (awhen (type-context-proto-classoid context) + (when (eq (classoid-name it) spec) (return it))) + (case (info :type :kind spec) + (:instance (return (find-classoid spec))) + (:forthcoming-defclass-type (go unknown)))) + ;; Expansion brings up an interesting question - should the cache + ;; contain entries for intermediary types? Say A -> B -> REAL. + ;; As it stands, we cache the ctype corresponding to A but not B. + (awhen (info :type :expander head) + (when (listp it) ; The function translates directly to a CTYPE. + (return (or (funcall (car it) context spec) (fail spec)))) + ;; The function produces a type expression. + (let ((expansion (funcall it (ensure-list spec)))) + (return (if (typep expansion 'instance) + (basic-parse-typespec expansion context) + (%parse-type expansion context))))) + ;; If the spec is (X ...) and X has neither a translator + ;; nor expander, and is a builtin, such as FIXNUM, fail now. + ;; But - see FIXME at top - it would be consistent with + ;; DEFTYPE to reject spec only if not a singleton. + (when builtin (return (fail spec))) + ;; SPEC has a legal form, so return an unknown type. + (unless (logtest (type-context-options context) +type-parse-signal-inhibit+) + (signal 'parse-unknown-type :specifier spec)) + UNKNOWN + (setf (type-context-options context) + (logior (type-context-options context) +type-parse-cache-inhibit+)) + (return (if (atom spec) + (let ((table **unknown-type-atoms**)) + (with-system-mutex ((hash-table-lock table)) + (or (gethash spec table) + (progn #+sb-xc-host + (when cl:*compile-print* + (format t "~&; NEW UNKNOWN-TYPE ~S~%" spec)) + (setf (gethash spec table) + (make-unknown-type :specifier spec)))))) + (make-unknown-type :specifier spec))))) + +;;; BASIC-PARSE-TYPESPEC can grok some simple cases that involve turning an object +;;; used as a type specifier into an internalized type object (which might be +;;; the selfsame object, in the case of a CLASSOID). +(defun basic-parse-typespec (type-specifier context) + (declare (type type-context context)) + (when (typep type-specifier 'instance) + ;; An instance never needs the type parser cache, because it almost always + ;; represents itself or a slot in itself. + (flet ((classoid-to-ctype (classoid) + ;; A few classoids have translations, + ;; e.g. the classoid CONS is a CONS-TYPE. + ;; Hmm, perhaps this should signal PARSE-UNKNOWN-TYPE + ;; if CLASSOID is an instance of UNDEFINED-CLASSOID ? + ;; Can that happen? + (or (and (built-in-classoid-p classoid) + (built-in-classoid-translation classoid)) + classoid))) + (return-from basic-parse-typespec + (cond ((classoid-p type-specifier) (classoid-to-ctype type-specifier)) + ;; Avoid TYPEP on SB-MOP:EQL-SPECIALIZER and CLASS because + ;; the fake metaobjects do not allow type analysis, and + ;; would cause a compiler error as it tries to decide + ;; whether any clause of this COND subsumes another. + ;; Moreover, we don't require the host to support MOP. + #-sb-xc-host + ((sb-pcl::classp type-specifier) + ;; A CLOS class is translated to its CLASSOID, or the classoid's translation. + (classoid-to-ctype (sb-pcl::class-classoid type-specifier))) + #-sb-xc-host + ((sb-pcl::eql-specializer-p type-specifier) + ;; EQL specializers are are seldom used and not 100% portable, + ;; though they are part of the AMOP. + ;; See https://sourceforge.net/p/sbcl/mailman/message/11217378/ + ;; We implement the notion that an EQL-SPECIALIZER has-a CTYPE. + ;; You might think that a cleverer way would be to say that + ;; EQL-SPECIALIZER is-a CTYPE, i.e. incorporating EQL-SPECIALIZER + ;; objects into the type machinary. Well, that's a problem - + ;; it would mess up admissibility of the TYPE= optimization. + ;; We don't want to create another way of representing + ;; the type NULL = (MEMBER NIL), for example. + (sb-pcl::eql-specializer-to-ctype type-specifier)) + ((wrapper-p type-specifier) + (wrapper-classoid type-specifier)) + (t (fail type-specifier)))))) + (when (atom type-specifier) + ;; Try to bypass the cache, which avoids using a cache line for standard + ;; atomic specifiers. This is a trade-off- cache seek might be faster, + ;; but this solves the problem that a full call to (TYPEP #\A 'FIXNUM) + ;; consed a cache line every time the cache missed on FIXNUM (etc). + (awhen (info :type :builtin type-specifier) + (return-from basic-parse-typespec it))) + + ;; If CONTEXT was non-cacheable as supplied, the cache is bypassed + ;; for any nested lookup, and we don't insert the result. + (if (not (type-context-cacheable context)) + (%parse-type (uncross type-specifier) context) + ;; Otherwise, try for a cache hit first, and usually update the cache. + (!values-specifier-type-memo-wrapper + (lambda () + (let ((answer (%parse-type (uncross type-specifier) context))) + (if (type-context-cacheable context) + answer + ;; Lookup was cacheable, but result isn't. + ;; Non-caching ensures that we see every occurrence of an unknown + ;; type no matter how deeply nested it is in the expression. + ;; e.g. (OR UNKNOWN-FOO CONS) and (OR INTEGER UNKNOWN-FOO) + ;; should both signal the PARSE-UNKNOWN condition, which would + ;; not happen if the first cached UNKNOWN-FOO. + + ;; During make-host-2 I'm seeing the types &OPTIONAL-AND-&KEY-IN-LAMBDA-LIST, + ;; SIMPLE-ERROR, DISASSEM-STATE as non-cacheable, + ;; and much, much more during make-target-2. + ;; The condition types are obvious, because we mention them before + ;; defining them. + ;; DISASSEM-STATE comes from building **TYPE-SPEC-INTERR-SYMBOLS** + ;; where we have a fixed list of types which get assigned single-byte + ;; error codes. + (progn + #+nil + (unless (type-context-cacheable context) + (format t "~&non-cacheable: ~S ~%" type-specifier)) + (return-from basic-parse-typespec answer))))) + type-specifier))) +) ; end MACROLET + +;;; This takes no CONTEXT (which implies lack of recursion) because +;;; you can't reasonably place a VALUES type inside another type. +(defun values-specifier-type (type-specifier) + ;; This catches uses of literal '* where it shouldn't appear, but it + ;; accidentally lets other uses slip through. We'd have to catch '* + ;; post-type-expansion to be more strict, but it isn't very important. + (cond ((eq type-specifier '*) + (warn "* is not permitted as a type specifier") + *universal-type*) + (t + (dx-let ((context (make-type-context type-specifier))) + (basic-parse-typespec type-specifier context))))) + +;;; This is like VALUES-SPECIFIER-TYPE, except that we guarantee to +;;; never return a VALUES type. +;;; CONTEXT is either an instance of TYPE-CONTEXT or NIL. +;;; SUBCONTEXT is a symbol denoting the head of the current expression, or NIL. +(defun specifier-type (type-specifier &optional context subcontext) + (let* ((ctype + (if context + (basic-parse-typespec type-specifier context) + (dx-let ((context (make-type-context type-specifier))) + (basic-parse-typespec type-specifier context)))) + (wildp (eq ctype *wild-type*))) + ;; We have to see how it was spelled to give an intelligent message. + ;; If it's instance of VALUES-TYPE, then it was spelled as VALUES + ;; whereas if it isn't, the user either spelled it as (VALUES) or *. + ;; The case where this heuristic doesn't work is a DEFTYPE that expands + ;; to *, but that's not worth worrying about. + (cond ((or (values-type-p ctype) + (and wildp (consp type-specifier))) + (error "VALUES type illegal in this context:~% ~ + ~/sb-impl:print-type-specifier/" + type-specifier)) + (wildp + (when context + (setf (type-context-options context) + (logior (type-context-options context) + +type-parse-cache-inhibit+))) + (if subcontext + (warn "* is not permitted as an argument to the ~S type specifier" + subcontext) + (warn "* is not permitted as a type specifier~@[ in the context ~S~]" + ;; If the entire surrounding context is * then there's not much + ;; else to say. Otherwise, show the original expression. + (when (and context (neq (type-context-spec context) '*)) + (type-context-spec context)))) + *universal-type*) + (t + ctype)))) + +(defun single-value-specifier-type (x &optional context) + (if (eq x '*) + *universal-type* + (specifier-type x context))) -;;; (VALUES-SPECIFIER-TYPE and SPECIFIER-TYPE moved from here to -;;; early-type.lisp by WHN ca. 19990201.) +;;; When cross-compiling SPECIFIER-TYPE with a quoted argument, +;;; it can be rendered as a literal object unless it mentions +;;; certain classoids. +;;; +;;; This is important for type system initialization. +;;; +;;; After the target is built, we remove this transform, both because calls +;;; to SPECIFIER-TYPE do not arise organically through user code, +;;; and because it is possible that user changes to types could make parsing +;;; return a different thing, e.g. changing a DEFTYPE to a DEFCLASS. +;;; +#+sb-xc-host +(labels ((xform (type-spec env parser) + (if (not (constantp type-spec env)) + (values nil t) + (let* ((expr (constant-form-value type-spec env)) + (parse (funcall parser expr))) + (if (cold-dumpable-type-p parse) + parse + (values nil t))))) + (cold-dumpable-type-p (ctype) + (when (contains-unknown-type-p ctype) + (bug "SPECIFIER-TYPE transform parsed an unknown type: ~S" ctype)) + (map-type (lambda (type) + (when (and (classoid-p type) (eq (classoid-name type) 'class)) + (return-from cold-dumpable-type-p nil))) + ctype) + t)) + (sb-c:define-source-transform specifier-type (type-spec &environment env) + (xform type-spec env #'specifier-type)) + (sb-c:define-source-transform values-specifier-type (type-spec &environment env) + (xform type-spec env #'values-specifier-type))) + +(defun typexpand-1 (type-specifier &optional env) + "Takes and expands a type specifier once like MACROEXPAND-1. +Returns two values: the expansion, and a boolean that is true when +expansion happened." + (declare (type type-specifier type-specifier)) + (declare (type lexenv-designator env) (ignore env)) + (let* ((spec type-specifier) + (atom (if (listp spec) (car spec) spec)) + (expander (and (symbolp atom) (info :type :expander atom)))) + ;; We do not expand builtins even though it'd be + ;; possible to do so sometimes (e.g. STRING) for two + ;; reasons: + ;; + ;; a) From a user's point of view, CL types are opaque. + ;; + ;; b) so (EQUAL (TYPEXPAND 'STRING) (TYPEXPAND-ALL 'STRING)) + (if (and (functionp expander) (not (info :type :builtin atom))) + (values (funcall expander (if (symbolp spec) (list spec) spec)) t) + (values type-specifier nil)))) + +(defun typexpand (type-specifier &optional env) + "Takes and expands a type specifier repeatedly like MACROEXPAND. +Returns two values: the expansion, and a boolean that is true when +expansion happened." + ;; TYPE-SPECIFIER is of type TYPE-SPECIFIER, but it is preferable to + ;; defer to TYPEXPAND-1 for the typecheck. Similarly for ENV. + (multiple-value-bind (expansion expanded) + (typexpand-1 type-specifier env) + (if expanded + (values (typexpand expansion env) t) + (values expansion expanded)))) ;;; Take a list of type specifiers, computing the translation of each ;;; specifier and defining it as a builtin type. @@ -1231,6 +1732,37 @@ (setf (info :type :builtin spec) res) (setf (info :type :kind spec) :primitive)))) (values)) + +;;; Parse TYPE-SPECIFIER, returning NIL if any sub-part of it is unknown +(defun type-or-nil-if-unknown (type-specifier &optional allow-values) + (dx-let ((context (make-type-context type-specifier))) + (let ((result (if allow-values + (basic-parse-typespec type-specifier context) + (specifier-type type-specifier context)))) + ;; If it was non-cacheable, either it contained a deprecated type + ;; or unknown type, or was a pending defstruct definition. + (if (and (not (type-context-cacheable context)) + (contains-unknown-type-p result)) + nil + result)))) + +(defun-cached (type-negation :hash-function #'type-hash-value + :hash-bits 8 + :values 1) + ((type eq)) + (declare (type ctype type)) + (funcall (type-class-negate (type-class type)) type)) + +(defun-cached (type-singleton-p :hash-function #'type-hash-value + :hash-bits 8 + :values 2) + ((type eq)) + (declare (type ctype type)) + (let ((function (type-class-singleton-p (type-class type)))) + (if function + (funcall function type) + (values nil nil)))) + ;;;; general TYPE-UNION and TYPE-INTERSECTION operations ;;;; @@ -1412,6 +1944,34 @@ ;; named type in disguise, TYPE2 is not a superset of TYPE1. (values nil t)))) +;;; Return T if members of this classoid certainly have INSTANCE-POINTER-LOWTAG. +;;; Logically it is the near opposite of CLASSOID-NON-INSTANCE-P, but not quite. +;;; CTYPEs which are not represented as a classoid return NIL for both predicates +;;; as do PCL types which may be either funcallable or non-funcallable. +;;; +;;; But some of that generality seems wrong. I don't think it would be allowed +;;; to have (as merely an example) an EQL-SPECIALIZER which is funcallable, +;;; having FUN-POINTER-LOWTAG instead of INSTANCE-POINTER-LOWTAG). Yet we think +;;; it could happen, because the parse of the type (AND EQL-SPECIALIZER INSTANCE) +;;; yields #<INTERSECTION-TYPE (AND SB-MOP:EQL-SPECIALIZER INSTANCE)> +;;; versus simplifying down to EQL-SPECIALIZER. +#| (loop for c being each hash-key of (classoid-subclasses (find-classoid 't)) + do (let ((not-i (classoid-non-instance-p c)) + (i (classoid-definitely-instancep c))) + (unless (eq (not not-i) i) (format t "~S -> ~A and ~A~%" c not-i i)))) |# +(defun classoid-definitely-instancep (x) + (or (structure-classoid-p x) + (condition-classoid-p x) + ;; PATHNAMEs are INSTANCEs based on the lowtag criterion + (or (eq x (specifier-type 'logical-pathname)) + (eq x (specifier-type 'pathname))))) +(eval-when (:compile-toplevel :execute) + (pushnew 'classoid-definitely-instancep sb-vm::*backend-cross-foldable-predicates*)) + +(defun classoid-is-or-inherits (sub super) + (or (classoid-inherits-from sub super) + (eq sub (find-classoid super)))) + (define-type-method (named :complex-subtypep-arg2) (type1 type2) (aver (not (eq type2 *wild-type*))) ; * isn't really a type. (cond ((eq type2 *universal-type*) @@ -1432,17 +1992,13 @@ ((and (eq type2 *extended-sequence-type*) (classoid-p type1)) (values (if (classoid-inherits-from type1 'sequence) t nil) t)) ((and (eq type2 *instance-type*) (classoid-p type1)) - (cond - ((classoid-non-instance-p type1) - (values nil t)) - ((classoid-inherits-from type1 'function) - (values nil t)) - ((eq type1 (find-classoid 'function)) - (values nil t)) - ((or (structure-classoid-p type1) - (condition-classoid-p type1)) - (values t t)) - (t (values nil nil)))) + (cond ((or (classoid-non-instance-p type1) + (classoid-is-or-inherits type1 'function)) + (values nil t)) + ((classoid-definitely-instancep type1) + (values t t)) + (t + (values nil nil)))) ((and (eq type2 *funcallable-instance-type*) (classoid-p type1)) (if (and (not (classoid-non-instance-p type1)) (classoid-inherits-from type1 'function)) @@ -1479,22 +2035,21 @@ (cond ((eq type2 *extended-sequence-type*) (typecase type1 - ((or structure-classoid condition-classoid) *empty-type*) + ((satisfies classoid-definitely-instancep) *empty-type*) ; dubious! (classoid (cond ((classoid-non-instance-p type1) *empty-type*) ((classoid-inherits-from type1 'sequence) type1))) (t (empty-unless-hairy type1)))) ((eq type2 *instance-type*) (typecase type1 - ((or structure-classoid condition-classoid) type1) + ((satisfies classoid-definitely-instancep) type1) (classoid (when (or (classoid-non-instance-p type1) - (eq type1 (find-classoid 'function)) - (classoid-inherits-from type1 'function)) + (classoid-is-or-inherits type1 'function)) *empty-type*)) (t (empty-unless-hairy type1)))) ((eq type2 *funcallable-instance-type*) (typecase type1 - ((or structure-classoid condition-classoid) *empty-type*) + ((satisfies classoid-definitely-instancep) *empty-type*) (classoid (cond ((classoid-non-instance-p type1) *empty-type*) @@ -1542,7 +2097,30 @@ (named-type-name x)) ;;;; hairy and unknown types -;;;; DEFINE-TYPE-CLASS HAIRY is in 'early-type' + +;; ENUMERABLE-P is T because a hairy type could be equivalent to a MEMBER type. +;; e.g. any SATISFIES with a predicate returning T over a finite domain. +;; But in practice there's nothing that can be done with this information, +;; because we don't call random predicates when performing operations on types +;; as objects, only when checking for inclusion of something in the type. +(define-type-class hairy :enumerable t :might-contain-other-types t) + +;;; Without some special HAIRY cases, we massively pollute the type caches +;;; with objects that are all equivalent to *EMPTY-TYPE*. e.g. +;;; (AND (SATISFIES LEGAL-FUN-NAME-P) (SIMPLE-ARRAY CHARACTER (*))) and +;;; (AND (SATISFIES KEYWORDP) CONS). Since the compiler doesn't know +;;; that they're just *EMPTY-TYPE*, its keeps building more and more complex +;;; expressions involving them. I'm not sure why those two are so prevalent +;;; but they definitely seem to be. We can improve performance by reducing +;;; them to *EMPTY-TYPE* which means we need a way to recognize those hairy +;;; types in order reason about them. Interning them is how we recognize +;;; them, as they can be compared by EQ. +#+sb-xc-host +(progn + (defvar *satisfies-keywordp-type* + (!make-interned-hairy-type '(satisfies keywordp))) + (defvar *fun-name-type* + (!make-interned-hairy-type '(satisfies legal-fun-name-p)))) (define-type-method (hairy :negate) (x) (make-negation-type x)) @@ -1625,6 +2203,43 @@ (values t t) (values nil nil))) +;;; This list exists so that we can turn builtin (SATISFIES fn) types into types +;;; amenable to algebra, because apparently there are some masochistic users +;;; who expect (SUBTYPEP 'COMPLEX '(AND NUMBER (SATISFIES REALP))) => NIL and T. +;;; There are possibly other entries that could go here, +;;; e.g. (SATISFIES ARRAY-HEADER-P) is something involving the AND, NOT, OR +;;; combinators. But it might render the expression too hairy to operate on. +(dolist (pair '((arrayp array) + (atom atom) + (bit-vector-p bit-vector) + (characterp character) + (compiled-function-p compiled-function) + (complexp complex) + (consp cons) + (floatp float) + (functionp function) + (hash-table-p hash-table) + (integerp integer) + ;; KEYWORD is (SATISFIES KEYWORDP), so we can't turn + ;; the predicate into KEYWORD + (listp list) + (numberp number) + (packagep package) + (pathnamep pathname) + (random-state-p random-state) + (rationalp rational) + (readtablep readtable) + (realp real) + (simple-bit-vector-p simple-bit-vector) + (simple-string-p simple-string) + (simple-vector-p simple-vector) + (streamp stream) + (stringp string) + (symbolp symbol) + (vectorp vector))) + (destructuring-bind (function type) pair + (setf (info :function :predicate-for function) type))) + (def-type-translator satisfies :list (&whole whole predicate-name) ;; "* may appear as the argument to a SATISFIES type specifier, but it ;; indicates the literal symbol *" (which in practice is not useful) @@ -1638,10 +2253,19 @@ (keywordp (literal-ctype *satisfies-keywordp-type*)) (legal-fun-name-p (literal-ctype *fun-name-type*)) (adjustable-array-p (specifier-type '(and array (not simple-array)))) - (t (%make-hairy-type whole)))) + (t (let ((type (info :function :predicate-for predicate-name))) + (if type + (specifier-type type) + (%make-hairy-type whole)))))) ;;;; negation types +;; Former comment was: +;; FIXME: is this right? It's what they had before, anyway +;; But I think the reason it's right is that "enumerable :t" is equivalent +;; to "maybe" which is actually the conservative assumption, same as HAIRY. +(define-type-class negation :enumerable t :might-contain-other-types t) + (define-type-method (negation :negate) (x) (negation-type-type x)) @@ -1772,17 +2396,30 @@ nil)))) (defun maybe-complex-array-refinement (type1 type2) + ;; a :MAYBE complex array <type> intersected with (NOT <type'>) + ;; where <type'> is the same in all aspects as <type> except that + ;; its complexp value is in {T,NIL} should return <type> altered + ;; with its COMPLEXP being the negation of the value from <type'>. + ;; As a particular case which is no longer special in handling it, + ;; the righthand side could be TYPE= to (NOT SIMPLE-ARRAY) + ;; which will match any lefthand side and do what it always did. (let* ((ntype (negation-type-type type2)) (ndims (array-type-dimensions ntype)) (ncomplexp (array-type-complexp ntype)) (nseltype (array-type-specialized-element-type ntype)) (neltype (array-type-element-type ntype))) - (if (and (eql ndims '*) (null ncomplexp) - (eq neltype *wild-type*) (eq nseltype *wild-type*)) - (make-array-type (array-type-dimensions type1) - :complexp t - :element-type (array-type-element-type type1) - :specialized-element-type (array-type-specialized-element-type type1))))) + (when (and (eq (array-type-complexp type1) :maybe) + (neq ncomplexp :maybe) + (or (eql ndims '*) + (equal (array-type-dimensions type1) ndims)) + (or (eq nseltype *wild-type*) + (eq (array-type-specialized-element-type type1) nseltype)) + (or (eq neltype *wild-type*) + (type= (array-type-element-type type1) neltype))) + (make-array-type (array-type-dimensions type1) + :complexp (not (array-type-complexp ntype)) + :specialized-element-type (array-type-specialized-element-type type1) + :element-type (array-type-element-type type1))))) (define-type-method (negation :complex-intersection2) (type1 type2) (cond @@ -1827,6 +2464,8 @@ (eq (numeric-type-format type1) (numeric-type-format type2)) (eq (numeric-type-complexp type1) (numeric-type-complexp type2)))) +(define-type-class number :enumerable #'numeric-type-enumerable :might-contain-other-types nil) + (define-type-method (number :simple-=) (type1 type2) ;; TODO: construct the hash bits for NUMBER types using a deterministic hash of ;; the low + high bounds. Then TYPE= can be true only if the hashes are =. @@ -1836,6 +2475,10 @@ (equalp (numeric-type-high type1) (numeric-type-high type2))) t)) +(declaim (inline bounds-unbounded-p)) +(defun bounds-unbounded-p (low high) + (and (null low) (eq high low))) + (define-type-method (number :negate) (type) (let ((low (numeric-type-low type)) (high (numeric-type-high type))) @@ -1885,8 +2528,8 @@ `(unsigned-byte ,high-length)) (t `(mod ,(1+ high))))) - ((and (= low sb-xc:most-negative-fixnum) - (= high sb-xc:most-positive-fixnum)) + ((and (= low most-negative-fixnum) + (= high most-positive-fixnum)) 'fixnum) ((and (= low (lognot high)) (= high-count high-length) @@ -1917,10 +2560,249 @@ (if (and low (eql low high) (eql (numeric-type-complexp type) :real) - (member (numeric-type-class type) '(integer rational float))) - (values t (numeric-type-low type)) + (if (eq (numeric-type-class type) 'float) + ;; (float 0.0 0.0) fits both -0.0 and 0.0 + (not (zerop low)) + (member (numeric-type-class type) '(integer rational)))) + (values t low) (values nil nil)))) +(defun interned-numeric-type (specifier &rest args) + (apply '%make-numeric-type + :%bits (pack-interned-ctype-bits + 'number nil + (when specifier (sb-vm::saetp-index-or-lose specifier))) + args)) + +#+sb-xc-host +(progn + ;; Work around an ABCL bug. This fails to load: + ;; (macrolet ((foo-it (x) `(- ,x))) (defvar *var* (foo-it 3))) + (defvar *interned-signed-byte-types*) + (defvar *interned-unsigned-byte-types*) + (macrolet ((int-type (low high) + `(interned-numeric-type (when (sb-c::find-saetp spec) spec) + :class 'integer :enumerable t + :low ,low :high ,high))) + (setq *interned-signed-byte-types* + (do ((v (make-array sb-vm:n-word-bits)) + (i 1 (1+ i)) + (j -1)) + ((> i sb-vm:n-word-bits) v) + (let ((spec (if (= i sb-vm:n-fixnum-bits) + 'fixnum + `(signed-byte ,i)))) + (setf (svref v (1- i)) (int-type j (lognot j)) + j (ash j 1))))) + (setq *interned-unsigned-byte-types* + (let ((v (make-array (1+ sb-vm:n-word-bits)))) + (dotimes (i (length v) v) + (let ((spec (if (= i 1) 'bit `(unsigned-byte ,i)))) + (setf (svref v i) (int-type 0 (1- (ash 1 i)))))))))) + +;;; Coerce a numeric type bound to the given type while handling +;;; exclusive bounds. +(defun coerce-numeric-bound (bound type) + (flet ((c (thing) + #+sb-xc-host (declare (ignore thing)) + (case type + (rational + #+sb-xc-host (return-from coerce-numeric-bound) + #-sb-xc-host (if (and (floatp thing) (float-infinity-p thing)) + (return-from coerce-numeric-bound nil) + (rational thing))) + ((float single-float) + (cond #-sb-xc-host + ((<= most-negative-single-float thing most-positive-single-float) + (coerce thing 'single-float)) + (t + (return-from coerce-numeric-bound nil)))) + (double-float + (cond #-sb-xc-host + ((<= most-negative-double-float thing most-positive-double-float) + (coerce thing 'double-float)) + (t + (return-from coerce-numeric-bound nil))))))) + (when bound + (if (consp bound) + (list (c (car bound))) + (c bound))))) + +(defun %make-union-numeric-type (class format complexp low high enumerable) + (declare (type (member integer rational float nil) class)) + (macrolet ((unionize (&rest specs) + `(type-union + ,@(loop for (class format coerce simple-coerce) in specs + collect `(make-numeric-type + :class ',class + :format ',format + :complexp complexp + :low ,(if simple-coerce + `(coerce low ',coerce) + `(coerce-numeric-bound low ',coerce)) + :high ,(if simple-coerce + `(coerce high ',coerce) + `(coerce-numeric-bound high ',coerce)) + :enumerable enumerable))))) + (cond ((and (null class) (member complexp '(:real :complex))) + (cond ((not (bounds-unbounded-p low high)) + (cond ((and (floatp low) (float-infinity-p low) + (eql low high)) + ;; low and high are some float + ;; infinity. not representable as a + ;; rational. + (let ((complexp :real)) ; TODO what if complexp was :complex? + (unionize (float single-float single-float t) + (float double-float double-float t)))) + (t + (unionize (rational nil rational) + (float single-float single-float) + (float double-float double-float))))) + ((eq complexp :complex) + (specifier-type 'complex)) + (t + (specifier-type 'real)))) + ((and (eq class 'float) (member complexp '(:real :complex)) + (eq format nil)) + (cond ((not (bounds-unbounded-p low high)) + (if (and (floatp low) (float-infinity-p low) + (eql low high)) + (let ((complexp :real)) + (unionize (float single-float single-float t) + (float double-float double-float t) + #+long-float((error "long-float")))) + (unionize (float single-float single-float) + (float double-float double-float) + #+long-float((error "long-float"))))) + ((eq complexp :complex) + (specifier-type '(complex float))) + (t + (specifier-type 'float)))) + ((and (null complexp) + (or class format low high)) + (type-union (make-numeric-type :class class :format format :complexp :complex + :low low :high high :enumerable enumerable) + (make-numeric-type :class class :format format :complexp :real + :low low :high high :enumerable enumerable)))))) + +;;; Impose canonicalization rules for NUMERIC-TYPE. Note that in some +;;; cases, despite the name, we return *EMPTY-TYPE* or a UNION-TYPE instead of a +;;; NUMERIC-TYPE. +;;; +;;; FIXME: The ENUMERABLE flag is unexpectedly NIL for types that +;;; come from parsing MEMBER. But bounded integer ranges, +;;; however large, are enumerable: +;;; (TYPE-ENUMERABLE (SPECIFIER-TYPE '(SIGNED-BYTE 99))) => T +;;; (TYPE-ENUMERABLE (SPECIFIER-TYPE '(COMPLEX (SIGNED-BYTE 99)))) => T +;;; but, in contrast, +;;; (TYPE-ENUMERABLE (SPECIFIER-TYPE '(EQL 5))) => NIL. +;;; I can't figure out whether this is supposed to matter. +;;; Moreover, it seems like this function should be responsible +;;; for figuring out the right value so that callers don't have to. +(defun make-numeric-type (&key class format (complexp :real) low high + enumerable) + (declare (type (member integer rational float nil) class)) + (let ((union-type (%make-union-numeric-type + class format complexp low high enumerable))) + (when union-type (return-from make-numeric-type union-type))) + (multiple-value-bind (low high) + (case class + (integer + ;; INTEGER types always have their LOW and HIGH bounds + ;; represented as inclusive, not exclusive values. + (values (if (consp low) (1+ (type-bound-number low)) low) + (if (consp high) (1- (type-bound-number high)) high))) + (t + ;; no canonicalization necessary + (values low high))) + ;; if interval is empty + (when (and low high + (if (or (consp low) (consp high)) ; if either bound is exclusive + (sb-xc:>= (type-bound-number low) (type-bound-number high)) + (sb-xc:> low high))) + (return-from make-numeric-type *empty-type*)) + (when (and (eq class 'rational) (integerp low) (eql low high)) + (setf class 'integer)) + ;; Either lookup the canonical interned object for + ;; a point in the type lattice, or construct a new one. + (or (case class + (float + (macrolet ((float-type (fmt complexp + &aux (spec (if (eq complexp :complex) + `(complex ,fmt) fmt))) + `(literal-ctype (interned-numeric-type ',spec + :class 'float :complexp ,complexp + :format ',fmt :enumerable nil) + ,spec))) + (when (bounds-unbounded-p low high) + (ecase format + (single-float + (case complexp + (:real (float-type single-float :real)) + (:complex (float-type single-float :complex)))) + (double-float + (case complexp + (:real (float-type double-float :real)) + (:complex (float-type double-float :complex)))))))) + (integer + (macrolet ((int-type (low high) + `(literal-ctype + (interned-numeric-type nil + :class 'integer :low ,low :high ,high + :enumerable (if (and ,low ,high) t nil)) + (integer ,(or low '*) ,(or high '*))))) + (cond ((neq complexp :real) nil) + ((and (eql low 0) (eql high (1- array-dimension-limit))) + (int-type 0 #.(1- array-dimension-limit))) ; INDEX type + ((null high) + (cond ((not low) (int-type nil nil)) + ((eql low 0) (int-type 0 nil)) + ((eql low (1+ most-positive-fixnum)) + ;; positive bignum + (int-type #.(1+ most-positive-fixnum) nil)))) + ((or (eql high most-positive-word) + ;; is (1+ high) a power-of-2 ? + (and (typep high 'word) (zerop (logand (1+ high) high)))) + (cond ((eql low 0) + (svref (literal-ctype-vector *interned-unsigned-byte-types*) + (integer-length (truly-the word high)))) + ((and (< high most-positive-word) (eql low (lognot high))) + (svref (literal-ctype-vector *interned-signed-byte-types*) + (integer-length (truly-the word high)))))) + ((and (not low) (eql high (1- most-negative-fixnum))) + ;; negative bignum + (int-type nil #.(1- most-negative-fixnum)))))) + (rational + (cond ((and (eq complexp :real) (bounds-unbounded-p low high)) + (literal-ctype (interned-numeric-type nil :class 'rational) + rational)) + ((and (eq complexp :complex) (bounds-unbounded-p low high)) + (literal-ctype (interned-numeric-type nil :complexp :complex + :class 'rational) + (complex rational))))) + ((nil) + (and (not format) + (not complexp) + (bounds-unbounded-p low high) + (literal-ctype (interned-numeric-type nil :complexp nil) number)))) + (%make-numeric-type :class class :format format :complexp complexp + :low low :high high :enumerable enumerable)))) + +(defun modified-numeric-type (base + &key + (class (numeric-type-class base)) + (format (numeric-type-format base)) + (complexp (numeric-type-complexp base)) + (low (numeric-type-low base)) + (high (numeric-type-high base)) + (enumerable (type-enumerable base))) + (make-numeric-type :class class + :format format + :complexp complexp + :low low + :high high + :enumerable enumerable)) + ;;; Return true if X is "less than or equal" to Y, taking open bounds ;;; into consideration. CLOSED is the predicate used to test the bound ;;; on a closed interval (e.g. <=), and OPEN is the predicate used on @@ -2042,8 +2924,7 @@ ;; Calling (EQL (- X) Y) might cons. Using = would be almost the same ;; but not cons, however I prefer not to assume that the caller has ;; already checked for matching float formats. EQL enforces that. - ;; Change to use SB-XC:- here if anything requires it. - (and (fp-zero-p x) (fp-zero-p y) (eql (- x) y))))) + (and (fp-zero-p x) (fp-zero-p y) (eql (sb-xc:- x) y))))) (cond ((not (and low-bound high-bound)) nil) ((and (consp low-bound) (consp high-bound)) nil) ((consp low-bound) (float-zeros-eqlish (car low-bound) high-bound)) @@ -2062,6 +2943,88 @@ ;;; creating absurdly complex unions of numeric types. (defvar *approximate-numeric-unions* nil) +(defun rational-integer-union (rational integer) + (let ((formatr (numeric-type-format rational)) + (formati (numeric-type-format integer)) + (complexpr (numeric-type-complexp rational)) + (complexpi (numeric-type-complexp integer)) + (lowi (numeric-type-low integer)) + (highi (numeric-type-high integer)) + (lowr (numeric-type-low rational)) + (highr (numeric-type-high rational))) + (when (and (eq formatr formati) (eq complexpr complexpi)) + (cond + ;; handle the special-case that a single integer expands the + ;; rational interval. + ((and (integerp lowi) (integerp highi) (= lowi highi) + (or *approximate-numeric-unions* + (numeric-types-adjacent integer rational) + (numeric-types-adjacent rational integer))) + (make-numeric-type + :class 'rational :format formatr :complexp complexpr + :low (numeric-bound-max lowr lowi <= < t) + :high (numeric-bound-max highr highi >= > t))) + ;; the general case: + ;; + ;; 1. expand the integer type by those integers contained by + ;; the rational type, if possible. + ;; + ;; 2. turn open bounds in the rational contained in the + ;; integer type into closed ones. + ;; + ;; (if neither of these applies, return NIL) + (t + (let* ((integers-of-rational + (make-numeric-type + :class 'integer :format formatr :complexp complexpr + :low (round-numeric-bound lowr 'integer formatr t) + :high (round-numeric-bound highr 'integer formatr nil))) + (new-integer + (and (numeric-type-p integers-of-rational) + (or *approximate-numeric-unions* + (numeric-types-intersect integers-of-rational integer) + (numeric-types-adjacent integers-of-rational integer) + (numeric-types-adjacent integer integers-of-rational)) + (let ((new-lowi (numeric-bound-max + lowi + (numeric-type-low integers-of-rational) + <= < t)) + (new-highi (numeric-bound-max + highi + (numeric-type-high integers-of-rational) + >= > t))) + (and (or (not (eql new-lowi lowi)) + (not (eql new-highi highi))) + (make-numeric-type + :class 'integer :format formatr :complexp complexpr + :low new-lowi :high new-highi))))) + (new-lowr + (and (consp lowr) + (integerp (car lowr)) + (let ((low-integer + (make-numeric-type + :class 'integer :format formati :complexp complexpi + :low (car lowr) :high (car lowr)))) + (and (numeric-types-intersect integer low-integer) + (numeric-type-low low-integer))))) + (new-highr + (and (consp highr) (integerp (car highr)) + (let ((high-integer + (make-numeric-type + :class 'integer :format formati :complexp complexpi + :low (car highr) :high (car highr)))) + (and (numeric-types-intersect integer high-integer) + (numeric-type-high high-integer))))) + (new-rational + (and (or new-lowr new-highr) + (make-numeric-type + :class 'rational :format formatr :complexp complexpr + :low (or new-lowr lowr) :high (or new-highr highr))))) + (cond + ((or new-integer new-rational) + (make-union-type nil (list (or new-integer integer) (or new-rational rational)))) + (t nil)))))))) + (define-type-method (number :simple-union2) (type1 type2) (declare (type numeric-type type1 type2)) (cond ((csubtypep type1 type2) type2) @@ -2091,48 +3054,11 @@ :high (numeric-bound-max (numeric-type-high type1) (numeric-type-high type2) >= > t))) - ;; FIXME: These two clauses are almost identical, and the - ;; consequents are in fact identical in every respect. - ((and (eq class1 'rational) - (eq class2 'integer) - (eq format1 format2) - (eq complexp1 complexp2) - (integerp (numeric-type-low type2)) - (integerp (numeric-type-high type2)) - (= (numeric-type-low type2) (numeric-type-high type2)) - (or *approximate-numeric-unions* - (numeric-types-adjacent type1 type2) - (numeric-types-adjacent type2 type1))) - (make-numeric-type - :class 'rational - :format format1 - :complexp complexp1 - :low (numeric-bound-max (numeric-type-low type1) - (numeric-type-low type2) - <= < t) - :high (numeric-bound-max (numeric-type-high type1) - (numeric-type-high type2) - >= > t))) - ((and (eq class1 'integer) - (eq class2 'rational) - (eq format1 format2) - (eq complexp1 complexp2) - (integerp (numeric-type-low type1)) - (integerp (numeric-type-high type1)) - (= (numeric-type-low type1) (numeric-type-high type1)) - (or *approximate-numeric-unions* - (numeric-types-adjacent type1 type2) - (numeric-types-adjacent type2 type1))) - (make-numeric-type - :class 'rational - :format format1 - :complexp complexp1 - :low (numeric-bound-max (numeric-type-low type1) - (numeric-type-low type2) - <= < t) - :high (numeric-bound-max (numeric-type-high type1) - (numeric-type-high type2) - >= > t))) + + ((and (eq class1 'rational) (eq class2 'integer)) + (rational-integer-union type1 type2)) + ((and (eq class1 'integer) (eq class2 'rational)) + (rational-integer-union type2 type1)) (t nil)))))) @@ -2261,10 +3187,6 @@ used for a COMPLEX component.~:@>" ;;; problems, we can go back and rip out support for separate FLOAT ;;; and REAL flavors of NUMERIC-TYPE. The new way was added in ;;; sbcl-0.6.11.22, 2001-03-21. -;;; -;;; FIXME: It's probably necessary to do something to fix the -;;; analogous problem with INTEGER and RATIONAL types. Perhaps -;;; bounded RATIONAL types should be represented as (OR RATIO INTEGER). (defun coerce-bound (bound type upperp inner-coerce-bound-fun) (declare (type function inner-coerce-bound-fun)) (if (eq bound '*) @@ -2276,8 +3198,8 @@ used for a COMPLEX component.~:@>" (if (listp bound) (list coerced) coerced)))) (defun inner-coerce-real-bound (bound type upperp) - (let ((nl sb-xc:most-negative-long-float) - (pl sb-xc:most-positive-long-float)) + (let ((nl most-negative-long-float) + (pl most-positive-long-float)) (let ((nbound (if (listp bound) (car bound) bound))) (ecase type (rational @@ -2297,10 +3219,10 @@ used for a COMPLEX component.~:@>" (make-bound (coerce nbound 'long-float))))))))) (defun inner-coerce-float-bound (bound type upperp) - (let ((nd sb-xc:most-negative-double-float) - (pd sb-xc:most-positive-double-float) - (ns sb-xc:most-negative-single-float) - (ps sb-xc:most-positive-single-float)) + (let ((nd most-negative-double-float) + (pd most-positive-double-float) + (ns most-negative-single-float) + (ps most-positive-single-float)) (let ((nbound (if (listp bound) (car bound) bound))) (ecase type (single-float @@ -2421,11 +3343,11 @@ used for a COMPLEX component.~:@>" (let ((res (cond ((and format (subtypep format 'double-float)) - (if (sb-xc:<= sb-xc:most-negative-double-float cx sb-xc:most-positive-double-float) + (if (sb-xc:<= most-negative-double-float cx most-positive-double-float) (coerce cx format) nil)) (t - (if (sb-xc:<= sb-xc:most-negative-single-float cx sb-xc:most-positive-single-float) + (if (sb-xc:<= most-negative-single-float cx most-positive-single-float) ;; FIXME: bug #389 (coerce cx (or format 'single-float)) nil))))) @@ -2459,27 +3381,33 @@ used for a COMPLEX component.~:@>" ((nil) class2) ((integer float) class1) (rational (if (eq class2 'integer) - 'integer - 'rational)))) + 'integer + 'rational)))) (format (or (numeric-type-format type1) - (numeric-type-format type2)))) + (numeric-type-format type2))) + (low1 (numeric-type-low type1)) + (high1 (numeric-type-high type1)) + (infinity1 (and (floatp low1) (float-infinity-p low1) (eql low1 high1))) + (low2 (numeric-type-low type2)) + (high2 (numeric-type-high type2)) + (infinity2 (and (floatp low2) (float-infinity-p low2) (eql low2 high2)))) (make-numeric-type :class class :format format :complexp (or (numeric-type-complexp type1) (numeric-type-complexp type2)) - :low (numeric-bound-max - (round-numeric-bound (numeric-type-low type1) - class format t) - (round-numeric-bound (numeric-type-low type2) - class format t) - > >= nil) - :high (numeric-bound-max - (round-numeric-bound (numeric-type-high type1) - class format nil) - (round-numeric-bound (numeric-type-high type2) - class format nil) - < <= nil))) + :low (cond (infinity1 low1) + (infinity2 low2) + (t (numeric-bound-max + (round-numeric-bound low1 class format t) + (round-numeric-bound low2 class format t) + > >= nil))) + :high (cond (infinity1 high1) + (infinity2 high2) + (t (numeric-bound-max + (round-numeric-bound high1 class format nil) + (round-numeric-bound high2 class format nil) + < <= nil))))) *empty-type*)) ;;; Given two float formats, return the one with more precision. If @@ -2491,15 +3419,16 @@ used for a COMPLEX component.~:@>" (return f))))) ;;; Return the result of an operation on TYPE1 and TYPE2 according to -;;; the rules of numeric contagion. This is always NUMBER, some float -;;; format (possibly complex) or RATIONAL. Due to rational -;;; canonicalization, there isn't much we can do here with integers or -;;; rational complex numbers. +;;; the rules of numeric contagion. This is NUMBER, some float +;;; format (possibly complex) or RATIONAL or a UNION-TYPE of +;;; these. Due to rational canonicalization, there isn't much we can +;;; do here with integers or rational complex numbers. ;;; ;;; If either argument is not a NUMERIC-TYPE, then return NUMBER. This ;;; is useful mainly for allowing types that are technically numbers, ;;; but not a NUMERIC-TYPE. -(defun numeric-contagion (type1 type2) +(defun numeric-contagion (type1 type2 &key (rational t) + unsigned) (if (and (numeric-type-p type1) (numeric-type-p type2)) (let ((class1 (numeric-type-class type1)) (class2 (numeric-type-class type2)) @@ -2507,10 +3436,7 @@ used for a COMPLEX component.~:@>" (format2 (numeric-type-format type2)) (complexp1 (numeric-type-complexp type1)) (complexp2 (numeric-type-complexp type2))) - (cond ((or (null complexp1) - (null complexp2)) - (specifier-type 'number)) - ((eq class1 'float) + (cond ((eq class1 'float) (make-numeric-type :class 'float :format (ecase class2 @@ -2529,21 +3455,183 @@ used for a COMPLEX component.~:@>" (if (eq format1 'long-float) 'long-float nil))) - :complexp (if (or (eq complexp1 :complex) - (eq complexp2 :complex)) - :complex - :real))) + :complexp (cond ((and (eq complexp1 :real) + (eq complexp2 :real)) + :real) + ((or (null complexp1) (null complexp2)) + nil) + (t :complex)))) ((eq class2 'float) (numeric-contagion type2 type1)) ((and (eq complexp1 :real) (eq complexp2 :real)) - (make-numeric-type - :class (and class1 class2 'rational) - :complexp :real)) + (if (or rational + (or (neq class1 'integer) + (neq class2 'integer))) + (make-numeric-type + :class (and class1 class2 'rational) + :complexp :real) + (make-numeric-type + :class 'integer + :complexp :real + :low (and unsigned + (typep (numeric-type-low type1) 'unsigned-byte) + (typep (numeric-type-low type2) 'unsigned-byte) + 0)))) (t (specifier-type 'number)))) (specifier-type 'number))) ;;;; array types +(define-type-class array :enumerable nil :might-contain-other-types nil) + +;; All character-set types are enumerable, but it's not possible for +;; one to be TYPE= to a MEMBER type because (MEMBER #\x) is not +;; internally represented as a MEMBER type. So in case it wasn't +;; clear already ENUMERABLE-P does not mean "possibly a MEMBER type in +;; the Lisp-theoretic sense", but means "could be implemented in SBCL +;; as a MEMBER type". +(eval-when (#+sb-xc-host :compile-toplevel :load-toplevel :execute) + ;; may not get executed before LITERAL-CTYPE = LOAD-TIME-VALUE on + ;; host, since LOAD-TIME-VALUE execution order with respect to top + ;; level forms is unspecified. + (define-type-class character-set :enumerable nil :might-contain-other-types nil)) + +(defun make-character-set-type (pairs) + ; (aver (equal (mapcar #'car pairs) + ; (sort (mapcar #'car pairs) #'<))) + ;; aver that the cars of the list elements are sorted into increasing order + (when pairs + (do ((p pairs (cdr p))) + ((null (cdr p))) + (aver (<= (caar p) (caadr p))))) + (let ((pairs (let (result) + (do ((pairs pairs (cdr pairs))) + ((null pairs) (nreverse result)) + (destructuring-bind (low . high) (car pairs) + (loop for (low1 . high1) in (cdr pairs) + if (<= low1 (1+ high)) + do (progn (setf high (max high high1)) + (setf pairs (cdr pairs))) + else do (return nil)) + (cond + ((>= low char-code-limit)) + ((< high 0)) + (t (push (cons (max 0 low) + (min high (1- char-code-limit))) + result)))))))) + (unless pairs + (return-from make-character-set-type *empty-type*)) + (unless (cdr pairs) + (macrolet ((range (low high &optional saetp-index) + `(return-from make-character-set-type + (literal-ctype (!make-interned-character-set-type + (pack-interned-ctype-bits 'character-set nil ,saetp-index) + '((,low . ,high))) + (character-set ((,low . ,high))))))) + (let* ((pair (car pairs)) + (low (car pair)) + (high (cdr pair))) + (cond ((eql high (1- char-code-limit)) + (cond ((eql low 0) + (range 0 #.(1- char-code-limit) + (sb-vm::saetp-index-or-lose 'character))) + #+sb-unicode + ((eql low base-char-code-limit) + (range #.base-char-code-limit + #.(1- char-code-limit))))) + #+sb-unicode + ((and (eql low 0) (eql high (1- base-char-code-limit))) + (range 0 #.(1- base-char-code-limit) + (sb-vm::saetp-index-or-lose 'base-char))))))) + (%make-character-set-type pairs))) + +;; For all ctypes which are the element types of specialized arrays, +;; 3 ctype objects are stored for the rank-1 arrays of that specialization, +;; one for each of simple, maybe-simple, and non-simple (in that order), +;; and 2 ctype objects for unknown-rank arrays, one each for simple +;; and maybe-simple. (Unknown rank, known-non-simple isn't important) +#+sb-xc-host +(progn +(defvar *interned-array-types* + (labels ((make-1 (type-index dims complexp type) + (aver (= (type-saetp-index type) type-index)) + (!make-interned-array-type (pack-interned-ctype-bits 'array) + dims complexp type type)) + (make-all (element-type type-index array) + (replace array + (list (make-1 type-index '(*) nil element-type) + (make-1 type-index '(*) :maybe element-type) + (make-1 type-index '(*) t element-type) + (make-1 type-index '* nil element-type) + (make-1 type-index '* :maybe element-type)) + :start1 (* type-index 5))) + (integer-range (low high) + (make-numeric-type :class 'integer :complexp :real + :enumerable t :low low :high high))) + (let ((array (make-array (* 32 5))) + (index 0)) + ;; Index 31 is available to store *WILD-TYPE* + ;; because there are fewer than 32 array widetags. + (make-all *wild-type* 31 array) + (dovector (saetp sb-vm:*specialized-array-element-type-properties* + (progn (aver (< index 31)) array)) + (make-all + (let ((x (sb-vm:saetp-specifier saetp))) + ;; Produce element-type representation without parsing a spec. + ;; (SPECIFIER-TYPE doesn't work when bootstrapping.) + ;; The MAKE- constructors return an interned object as appropriate. + (etypecase x + ((cons (eql unsigned-byte)) + (integer-range 0 (1- (ash 1 (second x))))) + ((cons (eql signed-byte)) + (let ((lim (ash 1 (1- (second x))))) + (integer-range (- lim) (1- lim)))) + ((eql bit) (integer-range 0 1)) + ;; FIXNUM is its own thing, why? See comment in vm-array + ;; saying to "See the comment in PRIMITIVE-TYPE-AUX" + ((eql fixnum) ; One good kludge deserves another. + (integer-range most-negative-fixnum + most-positive-fixnum)) + ((member single-float double-float) + (make-numeric-type :class 'float :format x :complexp :real)) + ((cons (eql complex)) + (make-numeric-type :class 'float :format (cadr x) + :complexp :complex)) + ((eql character) + (make-character-set-type `((0 . ,(1- char-code-limit))))) + #+sb-unicode + ((eql base-char) + (make-character-set-type `((0 . ,(1- base-char-code-limit))))) + ((eql t) *universal-type*) + ((eql nil) *empty-type*))) + index + array) + (incf index))))) +(defvar *parsed-specialized-array-element-types* + (let ((a (make-array (length sb-vm:*specialized-array-element-type-properties*)))) + (loop for i below (length a) + do (setf (aref a i) (array-type-specialized-element-type + (aref *interned-array-types* (* i 5))))) + a))) + +(declaim (ftype (sfunction (t &key (:complexp t) + (:element-type t) + (:specialized-element-type t)) + ctype) make-array-type)) +(defun make-array-type (dimensions &key (complexp :maybe) element-type + (specialized-element-type *wild-type*)) + (if (and (eq element-type specialized-element-type) + (or (and (eq dimensions '*) (neq complexp t)) + (typep dimensions '(cons (eql *) null)))) + (let ((res (svref (literal-ctype-vector *interned-array-types*) + (+ (* (type-saetp-index element-type) 5) + (if (listp dimensions) 0 3) + (ecase complexp ((nil) 0) ((:maybe) 1) ((t) 2)))))) + (aver (eq (array-type-element-type res) element-type)) + res) + (%make-array-type dimensions + complexp element-type specialized-element-type))) + (define-type-method (array :simple-=) (type1 type2) (cond ((not (and (equal (array-type-dimensions type1) (array-type-dimensions type2)) @@ -2600,8 +3688,6 @@ used for a COMPLEX component.~:@>" dtype stype))) (complexp (array-type-complexp type))) - (if (and (eq complexp t) (not *unparse-allow-negation*)) - (setq complexp :maybe)) (cond ((eq dims '*) (if (eq eltype '*) (ecase complexp @@ -2813,12 +3899,14 @@ used for a COMPLEX component.~:@>" (wild1 (eq eltype1 *wild-type*)) (wild2 (eq eltype2 *wild-type*))) (cond - ((type= eltype1 eltype2) + ((and wild1 wild2) (values eltype1 stype1 t)) (wild1 (values eltype1 stype1 type1)) (wild2 (values eltype2 stype2 type2)) + ((type= eltype1 eltype2) + (values eltype1 stype1 t)) ((not (type= stype1 stype2)) ;; non-wild types that don't share UAET don't unite (values :incompatible nil nil)) @@ -2897,17 +3985,17 @@ used for a COMPLEX component.~:@>" (integer (when (minusp dims) (error "Arrays can't have a negative number of dimensions: ~S" dims)) - (when (>= dims sb-xc:array-rank-limit) + (when (>= dims array-rank-limit) (error "array type with too many dimensions: ~S" dims)) (make-list dims :initial-element '*)) (list - (when (>= (length dims) sb-xc:array-rank-limit) + (when (>= (length dims) array-rank-limit) (error "array type with too many dimensions: ~S" dims)) (dolist (dim dims) (unless (eq dim '*) (unless (and (integerp dim) (>= dim 0) - (< dim sb-xc:array-dimension-limit)) + (< dim array-dimension-limit)) (error "bad dimension in array type: ~S" dim)))) dims) (t @@ -2915,6 +4003,102 @@ used for a COMPLEX component.~:@>" ;;;; MEMBER types + +(define-type-class member :enumerable t + :might-contain-other-types nil) + +(declaim (ftype (sfunction (xset list) ctype) make-member-type)) +(defun member-type-from-list (members) + (let ((xset (alloc-xset)) + (fp-zeroes)) + (dolist (elt members (make-member-type xset fp-zeroes)) + (if (fp-zero-p elt) + (pushnew elt fp-zeroes) + (add-to-xset elt xset))))) +(defun make-eql-type (elt) (member-type-from-list (list elt))) +;; Return possibly a union of a MEMBER type and a NUMERIC type, +;; or just one or the other, or *EMPTY-TYPE* depending on what's in the XSET +;; and the FP-ZEROES. XSET should not contains characters or real numbers. +(defun make-member-type (xset fp-zeroes) + ;; if we have a pair of zeros (e.g. 0.0d0 and -0.0d0), then we can + ;; canonicalize to (DOUBLE-FLOAT 0.0d0 0.0d0), because numeric + ;; ranges are compared by arithmetic operators (while MEMBERship is + ;; compared by EQL). -- CSR, 2003-04-23 + (let ((presence 0) + (unpaired nil) + (float-types nil)) + (when fp-zeroes ; avoid doing two passes of nothing + (dotimes (pass 2) + (dolist (z fp-zeroes) + (let ((sign (float-sign-bit z)) + (pair-idx + (etypecase z + (single-float 0) + (double-float 2 + #+long-float (long-float 4))))) + (if (= pass 0) + (setf (ldb (byte 1 (+ pair-idx sign)) presence) 1) + (if (= (ldb (byte 2 pair-idx) presence) #b11) + (when (= sign 0) + (push (ctype-of z) float-types)) + (push z unpaired))))))) + (let ((member-type + (block nil + (unless unpaired + (macrolet ((member-type (&rest elts) + `(literal-ctype + (!make-interned-member-type + (pack-interned-ctype-bits 'member) (xset-from-list ',elts) nil) + (member ,@elts)))) + (let ((elts (xset-data xset))) + (when (singleton-p elts) + (case (first elts) + ((nil) (return (member-type nil))) + ((t) (return (member-type t))))) + (when (or (equal elts '(t nil)) (equal elts '(nil t))) + ;; Semantically this is fine - XSETs + ;; are not order-preserving except by accident + ;; (when not represented as a hash-table). + (return (member-type t nil)))))) + (when (or unpaired (not (xset-empty-p xset))) + (%make-member-type xset unpaired))))) + ;; The actual member-type contains the XSET (with no FP zeroes), + ;; and a list of unpaired zeroes. + (if float-types + (make-union-type t (if member-type + (cons member-type float-types) + float-types)) + (or member-type *empty-type*))))) + +(defun member-type-size (type) + (+ (length (member-type-fp-zeroes type)) + (xset-count (member-type-xset type)))) + +(defun member-type-member-p (x type) + (if (fp-zero-p x) + (and (member x (member-type-fp-zeroes type)) t) + (xset-member-p x (member-type-xset type)))) + +(defun mapcar-member-type-members (function type) + (declare (function function)) + (collect ((results)) + (map-xset (lambda (x) + (results (funcall function x))) + (member-type-xset type)) + (dolist (zero (member-type-fp-zeroes type)) + (results (funcall function zero))) + (results))) + +(defun mapc-member-type-members (function type) + (declare (function function)) + (map-xset function (member-type-xset type)) + (dolist (zero (member-type-fp-zeroes type)) + (funcall function zero))) + +(defun member-type-members (type) + (append (member-type-fp-zeroes type) + (xset-members (member-type-xset type)))) + (define-type-method (member :negate) (type) (let ((xset (member-type-xset type)) (fp-zeroes (member-type-fp-zeroes type))) @@ -2951,7 +4135,7 @@ used for a COMPLEX component.~:@>" (define-type-method (member :simple-subtypep) (type1 type2) (values (and (xset-subset-p (member-type-xset type1) - (member-type-xset type2)) + (member-type-xset type2)) (subsetp (member-type-fp-zeroes type1) (member-type-fp-zeroes type2))) t)) @@ -3011,13 +4195,10 @@ used for a COMPLEX component.~:@>" (member-type-fp-zeroes type2)))) (define-type-method (member :simple-=) (type1 type2) - (let ((xset1 (member-type-xset type1)) - (xset2 (member-type-xset type2)) - (l1 (member-type-fp-zeroes type1)) + (let ((l1 (member-type-fp-zeroes type1)) (l2 (member-type-fp-zeroes type2))) - (values (and (eql (xset-count xset1) (xset-count xset2)) - (xset-subset-p xset1 xset2) - (xset-subset-p xset2 xset1) + (values (and (xset= (member-type-xset type1) + (member-type-xset type2)) (subsetp l1 l2) (subsetp l2 l1)) t))) @@ -3080,10 +4261,16 @@ used for a COMPLEX component.~:@>" ;;; mechanically unparsed. (define-type-method (intersection :unparse) (type) (declare (type ctype type)) - ;; If perhaps the magic intersection types were interned, then - ;; we could compare by EQ here instead of parsing in order to unparse. - (or (find type '(ratio keyword compiled-function) :key #'specifier-type :test #'type=) - `(and ,@(mapcar #'type-specifier (intersection-type-types type))))) + ;; If magic intersection types were interned, then + ;; we could compare by EQ here instead of calling TYPE= + (cond ((type= type (literal-ctype (specifier-type 'keyword) keyword)) + 'keyword) + ((type= type (literal-ctype (specifier-type 'ratio) ratio)) + 'ratio) + ((type= type (literal-ctype (specifier-type 'compiled-function) compiled-function)) + 'compiled-function) + (t + `(and ,@(mapcar #'type-specifier (intersection-type-types type)))))) (define-type-method (intersection :singleton-p) (type) (loop for constituent in (intersection-type-types type) @@ -3111,10 +4298,39 @@ used for a COMPLEX component.~:@>" ;;; instead, since SUBTYPEP is the usual relationship that we care ;;; most about, so it would be good to leverage any ingenuity there ;;; in this more obscure method? +;;; +;;; Possibly yes, but then the SUBTYPEP methods would have to be +;;; rewritten not to use TYPE= (see the discussion around UNION +;;; :SIMPLE=) (define-type-method (intersection :simple-=) (type1 type2) (type=-set (intersection-type-types type1) (intersection-type-types type2))) +(define-type-method (intersection :complex-=) (type1 type2) + (let ((seen-uncertain nil)) + (dolist (itype (intersection-type-types type2) + (if seen-uncertain + (values nil nil) + (invoke-complex-=-other-method type1 type2))) + (let ((trial-intersection (type-intersection2 type1 itype))) + (if (null trial-intersection) + (setq seen-uncertain (type-might-contain-other-types-p itype)) + ;; C != (Ai n Aj...) if (C n Ai) < C. + ;; + ;; (CSUBTYPEP (AND C Ai) C) is T, T by construction. + ;; We ask (SUBTYPEP C (AND C Ai)): + ;; + ;; T , T : OK, continue -- C = (AND C Ai) + ;; NIL, T : return early -- C > (AND C Ai) + ;; NIL, NIL: don't know! If we get to the end, return NIL, NIL, but + ;; give other types in the intersection a chance to return + ;; early. + (multiple-value-bind (subtype certain?) + (csubtypep type1 trial-intersection) + (cond + ((not certain?) (setq seen-uncertain t)) + ((not subtype) (return (values nil t)))))))))) + (defun %intersection-complex-subtypep-arg1 (type1 type2) (type= type1 (type-intersection type1 type2))) @@ -3284,50 +4500,100 @@ used for a COMPLEX component.~:@>" (determine type)) types)) -(defun unparse-string-type (ctype string-type) - (let ((string-ctype (specifier-type string-type))) - (and (union-type-p ctype) - (csubtypep ctype string-ctype) - (let ((types (copy-list (union-type-types string-ctype)))) - (and (loop for type in (union-type-types ctype) - for matching = (and (array-type-p type) - (neq (array-type-complexp type) t) - (find type types - :test #'csubtypep)) - always matching - do (setf types (delete matching types))) - (null types))) - (let ((dimensions (ctype-array-dimensions ctype))) - (cond ((and (singleton-p dimensions) - (integerp (car dimensions))) - `(,string-type ,@dimensions))))))) - -;;; The LIST, FLOAT and REAL types have special names. Other union -;;; types just get mechanically unparsed. +;;; Union unparsing involves looking for certain important type atoms in our +;;; internal representation - a/k/a "interned types" - those which have a unique +;;; object that models them; and then deciding whether some conjunction of +;;; particular atoms unparses to a prettier symbolic type. +(eval-when (:compile-toplevel :load-toplevel :execute) + (defparameter *special-union-types* + ;; This is order-sensitive. Prefer to recognize SEQUENCE + ;; and extract 4 components (NULL,CONS,VECTOR,EXTENDED-SEQUENCE) + ;; before considering LIST and extracting 2, etc. + '(sequence list real float complex bignum))) + (define-type-method (union :unparse) (type) - (declare (type ctype type)) - (cond - ((type= type (specifier-type 'list)) 'list) - ((type= type (specifier-type 'float)) 'float) - ((type= type (specifier-type 'real)) 'real) - ((type= type (specifier-type 'sequence)) 'sequence) - ((type= type (specifier-type 'bignum)) 'bignum) - ((type= type (specifier-type 'simple-string)) 'simple-string) - ((type= type (specifier-type 'string)) 'string) - ((unparse-string-type type 'simple-string)) - ((unparse-string-type type 'string)) - ((type= type (specifier-type 'complex)) 'complex) - (t - ;; If NULL is in the union, and deleting it reduces the union to either an atom - ;; or a list whose head is [SIMPLE-]STRING, then return (OR X NULL). - ;; This simplifies (OR FLOAT NULL) and other things in the above exceptions. - (let ((type-without-null - (when (find (specifier-type 'null) (union-type-types type)) - (type-specifier (type-difference type (specifier-type 'null)))))) - (if (or (and (atom type-without-null) type-without-null) - (typep type-without-null '(cons (member string simple-string)))) - `(or ,type-without-null null) - `(or ,@(mapcar #'type-specifier (union-type-types type)))))))) + ;; This logic diverges between +/- sb-xc-host because the machinery + ;; to parse types is obviously not usable here during make-host-1, + ;; so the macro has to generate code that is lazier about parsing. + (collect ((recognized)) + (let ((remainder (copy-list (union-type-types type)))) + #+sb-xc-host + ;; Try to recognize each special type in order. + ;; Don't use SUBTYPEP here; compare atoms instead. We're not trying + ;; to answer complicated questions - only see whether the argument TYPE + ;; contains (at least) each of the exact same things in SPECIAL. + (dolist (special *special-union-types*) + (let ((parts (union-type-types (specifier-type special)))) + (when (every (lambda (part) (memq part remainder)) parts) + ;; Remove the parts from the remainder + (dolist (part parts) (setq remainder (delq1 part remainder))) + (recognized special)))) ; add to the output + #-sb-xc-host + (macrolet + ((generator () + (let* ((constituent-types + (mapcar (lambda (type-specifier) + (union-type-types (specifier-type type-specifier))) + *special-union-types*)) + ;; Get the set of atoms that we need to pick out + (atoms (remove-duplicates (apply #'append constituent-types)))) + (labels ((atom->bit (atom) (ash 1 (position atom atoms))) + (compute-mask (parts) (apply #'+ (mapcar #'atom->bit parts)))) + `(let ((bits 0)) + (dolist (part remainder) + (setq bits + (logior bits + (cond ,@(mapcar (lambda (atom) + `((eq part ,atom) ,(atom->bit atom))) + atoms) + (t 0))))) + ;; Now we have a bitmask of all the interesting type atoms in the + ;; compound type. Try to match sets of bits, and remember it is + ;; possible to match more than one set, + ;; e.g. (OR STRING FLOAT BIGNUM) matches 3 pairs of bits. + ,@(mapcar (lambda (name parts &aux (mask (compute-mask parts))) + `(when (= (logand bits ,mask) ,mask) ; is all of these + (setq bits (logand bits ,(lognot mask))) ; Subtract the bits + ,@(mapcar (lambda (atom) + `(setq remainder (delq1 ,atom remainder))) + parts) + (recognized ',name))) ; add to the output + *special-union-types* constituent-types)))))) + (generator)) + ;; See if we can pair any two constituent types that resolve to + ;; ({STRING|SIMPLE-STRING|non-SIMPLE-STRING} n). + ;; Repeat until there are no more pairs. This is a kludge. + #+sb-unicode + (loop for tail on remainder + do (let* ((x (car tail)) + (peer + (and (array-type-p x) ; If X is a CHARACTER vector + (eq (array-type-element-type x) (specifier-type 'character)) + (singleton-p (array-type-dimensions x)) + ;; And can be matched with a BASE-CHAR vector + (member-if (lambda (y) + (and (array-type-p y) + (eq (array-type-element-type y) + (specifier-type 'base-char)) + (eq (array-type-complexp y) + (array-type-complexp x)) + (equal (array-type-dimensions y) + (array-type-dimensions x)))) + (cdr tail))))) + (when peer ; then together they comprise a subtype of STRING + (let* ((dim (car (array-type-dimensions x))) + (string-type + (if (array-type-complexp x) + (if (eq dim '*) 'string `(string ,dim)) + (if (eq dim '*) 'simple-string `(simple-string ,dim))))) + (recognized (if (eq (array-type-complexp x) 't) + `(and ,string-type (not simple-array)) + string-type))) + (rplaca tail nil) ; We'll delete these list elements later + (rplaca peer nil)))) + (let ((list (nconc (recognized) + (mapcar #'type-specifier (delete nil remainder))))) + (if (cdr list) `(or ,@list) (car list)))))) ;;; Two union types are equal if they are each subtypes of each ;;; other. We need to be this clever because our complex subtypep @@ -3349,8 +4615,7 @@ used for a COMPLEX component.~:@>" (values nil t) (multiple-value-bind (subtype certain?) (csubtypep type2 type1) - (declare (ignore subtype)) - (values nil certain?)))))) + (values nil (and (not subtype) certain?))))))) (define-type-method (union :complex-=) (type1 type2) (declare (ignore type1)) @@ -3480,6 +4745,46 @@ used for a COMPLEX component.~:@>" (if (union-type-p type) (sb-kernel::simplify-array-unions type) type))) + + +;;;; ALIEN-TYPE types + +(define-type-class alien :enumerable nil :might-contain-other-types nil) + +(define-type-method (alien :negate) (type) (make-negation-type type)) + +(define-type-method (alien :unparse) (type) + `(alien ,(unparse-alien-type (alien-type-type-alien-type type)))) + +(define-type-method (alien :simple-subtypep) (type1 type2) + (values (alien-subtype-p (alien-type-type-alien-type type1) + (alien-type-type-alien-type type2)) + t)) + +(define-type-method (alien :simple-=) (type1 type2) + (let ((alien-type-1 (alien-type-type-alien-type type1)) + (alien-type-2 (alien-type-type-alien-type type2))) + (values (or (eq alien-type-1 alien-type-2) + (alien-type-= alien-type-1 alien-type-2)) + t))) + +(def-type-translator alien (&optional (alien-type nil)) + (typecase alien-type + (null + (make-alien-type-type)) + (alien-type + (make-alien-type-type alien-type)) + (t + (make-alien-type-type (parse-alien-type alien-type (make-null-lexenv)))))) + +(defun make-alien-type-type (&optional alien-type) + (if alien-type + (let ((lisp-rep-type (compute-lisp-rep-type alien-type))) + (if lisp-rep-type + (single-value-specifier-type lisp-rep-type) + (%make-alien-type-type alien-type))) + *universal-type*)) + ;;;; CONS types @@ -3489,6 +4794,36 @@ used for a COMPLEX component.~:@>" (cdr-type (single-value-specifier-type cdr-type-spec context))) (make-cons-type car-type cdr-type))) +(define-type-class cons :enumerable nil :might-contain-other-types nil) + +#+sb-xc-host +(declaim (ftype (sfunction (ctype ctype) (values t t)) type=)) +(defun make-cons-type (car-type cdr-type) + (aver (not (or (eq car-type *wild-type*) + (eq cdr-type *wild-type*)))) + (cond ((or (eq car-type *empty-type*) + (eq cdr-type *empty-type*)) + *empty-type*) + ;; It's not a requirement that (CONS T T) be interned, + ;; but it improves the hit rate in the function caches. + ((and (type= car-type *universal-type*) + (type= cdr-type *universal-type*)) + (literal-ctype (!make-interned-cons-type (pack-interned-ctype-bits 'cons) + *universal-type* + *universal-type*) + cons)) + (t + (%make-cons-type car-type cdr-type)))) + +;;; Return TYPE converted to canonical form for a situation where the +;;; "type" '* (which SBCL still represents as a type even though ANSI +;;; CL defines it as a related but different kind of placeholder) is +;;; equivalent to type T. +(defun type-*-to-t (type) + (if (type= type *wild-type*) + *universal-type* + type)) + (define-type-method (cons :negate) (type) (if (and (eq (cons-type-car-type type) *universal-type*) (eq (cons-type-cdr-type type) *universal-type*)) @@ -3563,34 +4898,68 @@ used for a COMPLEX component.~:@>" car-not1 car-not2) ;; UGH. -- CSR, 2003-02-24 - (macrolet ((frob-car (car1 car2 cdr1 cdr2 - &optional not1) - `(let ((intersection (type-intersection ,car2 - ,(or not1 - `(type-negation ,car1))))) - (unless (type= intersection ,car2) - (type-union - (make-cons-type ,car1 (type-union ,cdr1 ,cdr2)) - (make-cons-type intersection ,cdr2)))))) + (macrolet ((frob-car (car1 car2 cdr1 cdr2 &optional not1) + `(let ((intersection (type-intersection ,car2 + ,(or not1 `(type-negation ,car1))))) + (unless (type= intersection ,car2) + (type-union + (make-cons-type ,car1 (type-union ,cdr1 ,cdr2)) + (make-cons-type intersection ,cdr2)))))) (cond ((type= car-type1 car-type2) (make-cons-type car-type1 (type-union cdr-type1 cdr-type2))) ((type= cdr-type1 cdr-type2) (make-cons-type (type-union car-type1 car-type2) cdr-type1)) + ;; (or (cons A1 D1) (cons A2 D2)) + ;; + ;; if A1 is a subtype of A2, this is equivalent to + ;; + ;; (or (cons A1 (or D1 D2)) (cons (and A2 (not A1)) D2)) ((csubtypep car-type1 car-type2) (frob-car car-type1 car-type2 cdr-type1 cdr-type2)) ((csubtypep car-type2 car-type1) (frob-car car-type2 car-type1 cdr-type2 cdr-type1)) - ;; more general case of the above, but harder to compute + ;; in general + ;; + ;; (or (cons A1 D1) (cons A2 D2)) + ;; + ;; is + ;; + ;; (or (cons (and A1 A2) (or D1 D2)) + ;; (cons (and A1 (not A2)) D1) + ;; (cons (and (not A1) A2) D2)) + ;; + ;; (or (cons (integer 0 8) (integer 5 15)) + ;; (cons (integer 3 15) (integer 4 14)) + ;; + ;; -> + ;; + ;; (or (cons (integer 3 8) (integer 4 15)) + ;; (cons (integer 0 2) (integer 5 15)) + ;; (cons (integer 9 15) (integer 4 14)) + ;; + ;; if A1 and A2 are disjoint no further simplification is + ;; possible. However, if they are not disjoint, and we + ;; can tell that they are not disjoint, we should be able + ;; to break the type up into smaller pieces. ((multiple-value-bind (yes win) (csubtypep car-type2 (setf car-not1 (type-negation car-type1))) (and (not yes) win)) - (frob-car car-type1 car-type2 cdr-type1 cdr-type2 car-not1)) + (let ((cdr-union (type-union cdr-type1 cdr-type2))) + (setf car-not2 (type-negation car-type2)) + (type-union + (make-cons-type (type-intersection car-type1 car-type2) cdr-union) + (make-cons-type (type-intersection car-type1 car-not2) cdr-type1) + (make-cons-type (type-intersection car-not1 car-type2) cdr-type2)))) ((multiple-value-bind (yes win) (csubtypep car-type1 (setf car-not2 (type-negation car-type2))) (and (not yes) win)) - (frob-car car-type2 car-type1 cdr-type2 cdr-type1 car-not2)) + (let ((cdr-union (type-union cdr-type1 cdr-type2))) + (type-union + (make-cons-type (type-intersection car-type1 car-type2) cdr-union) + (make-cons-type (type-intersection car-type1 car-not2) cdr-type1) + (make-cons-type (type-intersection car-not1 car-type2) cdr-type2)))) ;; Don't put these in -- consider the effect of taking the ;; union of (CONS (INTEGER 0 2) (INTEGER 5 7)) and ;; (CONS (INTEGER 0 3) (INTEGER 5 6)). @@ -3623,19 +4992,19 @@ used for a COMPLEX component.~:@>" ;;;; CHARACTER-SET types (def-type-translator character-set - (&optional (pairs `((0 . ,(1- sb-xc:char-code-limit))))) + (&optional (pairs `((0 . ,(1- char-code-limit))))) (make-character-set-type pairs)) (define-type-method (character-set :negate) (type) (let ((pairs (character-set-type-pairs type))) (if (and (= (length pairs) 1) (= (caar pairs) 0) - (= (cdar pairs) (1- sb-xc:char-code-limit))) + (= (cdar pairs) (1- char-code-limit))) (make-negation-type type) (let ((not-character (make-negation-type (make-character-set-type - `((0 . ,(1- sb-xc:char-code-limit))))))) + `((0 . ,(1- char-code-limit))))))) (type-union not-character (make-character-set-type @@ -3646,9 +5015,9 @@ used for a COMPLEX component.~:@>" (high1 (cdar tail) (cdar tail)) (low2 (caadr tail) (caadr tail))) ((null (cdr tail)) - (when (< (cdar tail) (1- sb-xc:char-code-limit)) + (when (< (cdar tail) (1- char-code-limit)) (push (cons (1+ (cdar tail)) - (1- sb-xc:char-code-limit)) + (1- char-code-limit)) not-pairs)) (nreverse not-pairs)) (push (cons (1+ high1) (1- low2)) not-pairs))))))))) @@ -3669,7 +5038,7 @@ used for a COMPLEX component.~:@>" (chars (loop named outer for (low . high) in pairs nconc (loop for code from low upto high - collect (sb-xc:code-char code) + collect (code-char code) when (minusp (decf count)) do (return-from outer t))))) (if (eq chars t) @@ -3799,119 +5168,174 @@ used for a COMPLEX component.~:@>" eltype)))) ;;;; SIMD-PACK types + +#+sb-simd-pack +(defun make-simd-pack-type (element-type) + (aver (neq element-type *wild-type*)) + (if (eq element-type *empty-type*) + *empty-type* + (%make-simd-pack-type + (do* ((i 0 (1+ i)) + (pack-types *simd-pack-element-types* (cdr pack-types)) + (pack-type (car pack-types) (car pack-types))) + ((null pack-types) + (error "~S element type must be a subtype of ~ + ~{~/sb-impl:print-type-specifier/~#[~;, or ~ + ~:;, ~]~}." + 'simd-pack *simd-pack-element-types*)) + (when (csubtypep element-type (specifier-type pack-type)) + (let ((bv (make-array (length *simd-pack-element-types*) + :element-type 'bit :initial-element 0))) + (setf (sbit bv i) 1) + (return bv))))))) + +#+sb-simd-pack-256 +(defun make-simd-pack-256-type (element-type) + (aver (neq element-type *wild-type*)) + (if (eq element-type *empty-type*) + *empty-type* + (%make-simd-pack-256-type + (do* ((i 0 (1+ i)) + (pack-types *simd-pack-element-types* (cdr pack-types)) + (pack-type (car pack-types) (car pack-types))) + ((null pack-types) + (error "~S element type must be a subtype of ~ + ~{~/sb-impl:print-type-specifier/~#[~;, or ~ + ~:;, ~]~}." + 'simd-pack-256 *simd-pack-element-types*)) + (when (csubtypep element-type (specifier-type pack-type)) + (let ((bv (make-array (length *simd-pack-element-types*) + :element-type 'bit :initial-element 0))) + (setf (sbit bv i) 1) + (return bv))))))) + #+sb-simd-pack (progn - (define-type-class simd-pack :enumerable nil - :might-contain-other-types nil) + (define-type-class simd-pack :enumerable nil :might-contain-other-types nil) ;; Though this involves a recursive call to parser, parsing context need not ;; be passed down, because an unknown-type condition is an immediate failure. (def-type-translator simd-pack (&optional (element-type-spec '*)) - (if (eql element-type-spec '*) - (%make-simd-pack-type *simd-pack-element-types*) - (make-simd-pack-type (single-value-specifier-type element-type-spec)))) + (if (eql element-type-spec '*) + (%make-simd-pack-type (make-array (length *simd-pack-element-types*) + :element-type 'bit :initial-element 1)) + (make-simd-pack-type (single-value-specifier-type element-type-spec)))) (define-type-method (simd-pack :negate) (type) - (let ((remaining (set-difference *simd-pack-element-types* - (simd-pack-type-element-type type))) + (let* ((element-type (simd-pack-type-element-type type)) + (remaining (and (/= (count 0 element-type) 0) (bit-not element-type))) (not-simd-pack (make-negation-type (specifier-type 'simd-pack)))) - (if remaining - (type-union not-simd-pack (%make-simd-pack-type remaining)) - not-simd-pack))) + (if remaining + (type-union not-simd-pack (%make-simd-pack-type remaining)) + not-simd-pack))) (define-type-method (simd-pack :unparse) (type) - (let ((eltypes (simd-pack-type-element-type type))) - (cond ((equal eltypes *simd-pack-element-types*) - 'simd-pack) - ((= 1 (length eltypes)) - `(simd-pack ,(first eltypes))) - (t - `(or ,@(mapcar (lambda (eltype) - `(simd-pack ,eltype)) - eltypes)))))) + (let* ((eltypes (simd-pack-type-element-type type))) + (cond + ((= (count 0 eltypes) 0) 'simd-pack) + ((= (count 1 eltypes) 1) + (let ((pos (position 1 eltypes))) + (if pos + `(simd-pack ,(elt *simd-pack-element-types* pos)) + (bug "bad simd-pack")))) + (t + `(or + ,@(loop for x from 0 + for bit across eltypes + if (= bit 1) + collect `(simd-pack ,(elt *simd-pack-element-types* x)))))))) (define-type-method (simd-pack :simple-=) (type1 type2) - (declare (type simd-pack-type type1 type2)) - (values - (null (set-exclusive-or (simd-pack-type-element-type type1) - (simd-pack-type-element-type type2))) - t)) + (declare (type simd-pack-type type1 type2)) + (values + (= 0 (count 1 (bit-xor (simd-pack-type-element-type type1) + (simd-pack-type-element-type type2)))) + t)) (define-type-method (simd-pack :simple-subtypep) (type1 type2) - (declare (type simd-pack-type type1 type2)) - (subsetp (simd-pack-type-element-type type1) - (simd-pack-type-element-type type2))) + (declare (type simd-pack-type type1 type2)) + (values + (= 0 (count 1 (bit-andc2 (simd-pack-type-element-type type1) + (simd-pack-type-element-type type2)))) + t)) (define-type-method (simd-pack :simple-union2) (type1 type2) - (declare (type simd-pack-type type1 type2)) - (%make-simd-pack-type (union (simd-pack-type-element-type type1) - (simd-pack-type-element-type type2)))) + (declare (type simd-pack-type type1 type2)) + (%make-simd-pack-type (bit-ior (simd-pack-type-element-type type1) + (simd-pack-type-element-type type2)))) (define-type-method (simd-pack :simple-intersection2) (type1 type2) - (declare (type simd-pack-type type1 type2)) - (let ((intersection (intersection (simd-pack-type-element-type type1) - (simd-pack-type-element-type type2)))) - (if intersection - (%make-simd-pack-type intersection) - *empty-type*))) + (declare (type simd-pack-type type1 type2)) + (let ((intersection (bit-and (simd-pack-type-element-type type1) + (simd-pack-type-element-type type2)))) + (if (find 1 intersection) + (%make-simd-pack-type intersection) + *empty-type*))) (!define-superclasses simd-pack ((simd-pack)) !cold-init-forms)) #+sb-simd-pack-256 (progn - (define-type-class simd-pack-256 :enumerable nil - :might-contain-other-types nil) + (define-type-class simd-pack-256 :enumerable nil :might-contain-other-types nil) ;; Though this involves a recursive call to parser, parsing context need not ;; be passed down, because an unknown-type condition is an immediate failure. (def-type-translator simd-pack-256 (&optional (element-type-spec '*)) - (if (eql element-type-spec '*) - (%make-simd-pack-256-type *simd-pack-element-types*) - (make-simd-pack-256-type (single-value-specifier-type element-type-spec)))) + (if (eql element-type-spec '*) + (%make-simd-pack-256-type (make-array (length *simd-pack-element-types*) + :element-type 'bit :initial-element 1)) + (make-simd-pack-256-type (single-value-specifier-type element-type-spec)))) (define-type-method (simd-pack-256 :negate) (type) - (let ((remaining (set-difference *simd-pack-element-types* - (simd-pack-256-type-element-type type))) + (let* ((element-type (simd-pack-256-type-element-type type)) + (remaining (and (/= (count 0 element-type) 0) (bit-not element-type))) (not-simd-pack-256 (make-negation-type (specifier-type 'simd-pack-256)))) - (if remaining - (type-union not-simd-pack-256 (%make-simd-pack-256-type remaining)) - not-simd-pack-256))) + (if remaining + (type-union not-simd-pack-256 (%make-simd-pack-256-type remaining)) + not-simd-pack-256))) (define-type-method (simd-pack-256 :unparse) (type) - (let ((eltypes (simd-pack-256-type-element-type type))) - (cond ((equal eltypes *simd-pack-element-types*) - 'simd-pack-256) - ((= 1 (length eltypes)) - `(simd-pack-256 ,(first eltypes))) - (t - `(or ,@(mapcar (lambda (eltype) - `(simd-pack-256 ,eltype)) - eltypes)))))) + (let* ((eltypes (simd-pack-256-type-element-type type))) + (cond + ((= (count 0 eltypes) 0) 'simd-pack-256) + ((= (count 1 eltypes) 1) + (let ((pos (position 1 eltypes))) + (if pos + `(simd-pack-256 ,(elt *simd-pack-element-types* pos)) + (bug "bad simd-pack-256")))) + (t + `(or + ,@(loop for x from 0 + for bit across eltypes + if (= bit 1) + collect `(simd-pack-256 ,(elt *simd-pack-element-types* x)))))))) (define-type-method (simd-pack-256 :simple-=) (type1 type2) - (declare (type simd-pack-256-type type1 type2)) - (values - (null (set-exclusive-or (simd-pack-256-type-element-type type1) - (simd-pack-256-type-element-type type2))) - t)) + (declare (type simd-pack-256-type type1 type2)) + (values + (= 0 (count 1 (bit-xor (simd-pack-256-type-element-type type1) + (simd-pack-256-type-element-type type2)))) + t)) (define-type-method (simd-pack-256 :simple-subtypep) (type1 type2) - (declare (type simd-pack-256-type type1 type2)) - (subsetp (simd-pack-256-type-element-type type1) - (simd-pack-256-type-element-type type2))) + (declare (type simd-pack-256-type type1 type2)) + (values + (= 0 (count 1 (bit-andc2 (simd-pack-256-type-element-type type1) + (simd-pack-256-type-element-type type2)))) + t)) (define-type-method (simd-pack-256 :simple-union2) (type1 type2) - (declare (type simd-pack-256-type type1 type2)) - (%make-simd-pack-256-type (union (simd-pack-256-type-element-type type1) - (simd-pack-256-type-element-type type2)))) + (declare (type simd-pack-256-type type1 type2)) + (%make-simd-pack-256-type (bit-ior (simd-pack-256-type-element-type type1) + (simd-pack-256-type-element-type type2)))) (define-type-method (simd-pack-256 :simple-intersection2) (type1 type2) - (declare (type simd-pack-256-type type1 type2)) - (let ((intersection (intersection (simd-pack-256-type-element-type type1) - (simd-pack-256-type-element-type type2)))) - (if intersection - (%make-simd-pack-256-type intersection) - *empty-type*))) + (declare (type simd-pack-256-type type1 type2)) + (let ((intersection (bit-and (simd-pack-256-type-element-type type1) + (simd-pack-256-type-element-type type2)))) + (if (find 1 intersection) + (%make-simd-pack-256-type intersection) + *empty-type*))) (!define-superclasses simd-pack-256 ((simd-pack-256)) !cold-init-forms)) @@ -3954,13 +5378,21 @@ used for a COMPLEX component.~:@>" ;;; This messy case of CTYPE for NUMBER is shared between the ;;; cross-compiler and the target system. +;;; I'm not sure whether NaNs should be numeric types versus MEMBER (like +;;; sigleton signed zero without the "other" sign), but it may not matter. +;;; At a bare minimum this prevents crashing in min/max. (defun ctype-of-number (x) (let ((num (if (complexp x) (realpart x) x))) (multiple-value-bind (complexp low high) - (if (complexp x) - (let ((imag (imagpart x))) - (values :complex (sb-xc:min num imag) (sb-xc:max num imag))) - (values :real num num)) + (cond ((complexp x) + (let ((imag (imagpart x))) + (if (and (floatp num) (or (float-nan-p num) (float-nan-p imag))) + (values :complex nil nil) + (values :complex (sb-xc:min num imag) (sb-xc:max num imag))))) + ((and (floatp num) (float-nan-p num)) + (values :real nil nil)) + (t + (values :real num num))) (make-numeric-type :class (etypecase num (integer (if (complexp x) (if (integerp (imagpart x)) @@ -4025,7 +5457,7 @@ used for a COMPLEX component.~:@>" ;;; We represent sets as a pair of (negate-p finite-set) in order to ;;; support negation types. -(declaim (inline generic-abstract-type-function)) +(declaim (maybe-inline generic-abstract-type-function)) (defun generic-abstract-type-function (type overapproximate union intersection difference @@ -4166,17 +5598,155 @@ used for a COMPLEX component.~:@>" (funcall under type) (default nil)))))))) (multiple-value-call #'normalize (walk type overapproximate)))) -(declaim (notinline generic-abstract-type-function)) ;;; Standard list representation of sets. Use CL:* for the universe. (defun list-abstract-type-function (type over &key under (overapproximate t)) - (declare (inline generic-abstract-type-function)) + #-sb-xc-host (declare (inline generic-abstract-type-function)) (generic-abstract-type-function type overapproximate #'union #'intersection #'set-difference '* nil over under)) -(!defun-from-collected-cold-init-forms !late-type-cold-init) -(/show0 "late-type.lisp end of file") +;;; This decides if two type expressions are equal ignoring the order of terms +;;; in AND and OR. It doesn't decide equivalence, but it's good enough +;;; to do some sanity checking in type.before-xc and genesis. +(defun brute-force-type-specifier-equalp (a b) + (labels ((compare (a b) + (if (symbolp a) + (eq a b) + (or (equal a b) + (and (listp b) + (eq (car a) (car b)) + (case (car a) + ((and or) + (order-insensitive-equal (cdr a) (cdr b))) + ((not) + (compare (cadr a) (cadr b)))))))) + (order-insensitive-equal (a b) + (and (= (length a) (length b)) + (every (lambda (elt) (member elt b :test #'compare)) a) + (every (lambda (elt) (member elt a :test #'compare)) b)))) + (compare a b))) + +;;;; miscellaneous interfaces + +;;; Clear memoization of all type system operations that can be +;;; altered by type definition/redefinition. +;;; +(defun clear-type-caches () + ;; FIXME: We would like to differentiate between different cache + ;; kinds, but at the moment all our caches pretty much are type + ;; caches. + (drop-all-hash-caches) + (values)) + +;;; This is like TYPE-OF, only we return a CTYPE structure instead of +;;; a type specifier, and we try to return the type most useful for +;;; type checking, rather than trying to come up with the one that the +;;; user might find most informative. +;;; +;;; To avoid inadvertent memory retention we avoid using arrays +;;; and functions as keys. +;;; During cross-compilation, the CTYPE-OF function is not memoized. +;;; Constants get their type stored in their LEAF, so it's ok. +#-sb-xc-host +(defun-cached (ctype-of :hash-bits 7 :hash-function #'sxhash + :memoizer memoize) +;; an unfortunate aspect of using EQ is that several appearances +;; of the = double-float can be in the cache, but it's +;; probably more efficient overall to use object identity. + ((x eq)) + (flet ((try-cache (x) + (memoize + ;; For functions, the input is a type specifier + ;; of the form (FUNCTION (...) ...) + (cond ((listp x) (specifier-type x)) ; NIL can't occur + ((symbolp x) (make-eql-type x)) + (t (ctype-of-number x)))))) + (typecase x + (function + (if (funcallable-instance-p x) + (classoid-of x) + (let ((type (sb-impl::%fun-ftype x))) + (if (typep type '(cons (eql function))) ; sanity test + (try-cache type) + (classoid-of x))))) + (symbol (if x (try-cache x) (specifier-type 'null))) + (number (try-cache x)) + (array (ctype-of-array x)) + (cons (specifier-type 'cons)) + (character + (typecase x + (standard-char (specifier-type 'standard-char)) + (base-char (specifier-type 'base-char)) + ;; If the last case were expressed as EXTENDED-CHAR, + ;; we wrongly get "this is not a (VALUES CTYPE): NIL" + ;; because the compiler is too naive to see that + ;; the last 2 cases partition CHARACTER. + (t (specifier-type 'extended-char)))) + #+sb-simd-pack + (simd-pack + (let ((tag (%simd-pack-tag x))) + (svref (load-time-value + (coerce (cons (specifier-type 'simd-pack) + (mapcar (lambda (x) (specifier-type `(simd-pack ,x))) + *simd-pack-element-types*)) + 'vector) + t) + (if (<= 0 tag #.(1- (length *simd-pack-element-types*))) + (1+ tag) + 0)))) + #+sb-simd-pack-256 + (simd-pack-256 + (let ((tag (%simd-pack-256-tag x))) + (svref (load-time-value + (coerce (cons (specifier-type 'simd-pack-256) + (mapcar (lambda (x) (specifier-type `(simd-pack-256 ,x))) + *simd-pack-element-types*)) + 'vector) + t) + (if (<= 0 tag #.(1- (length *simd-pack-element-types*))) + (1+ tag) + 0)))) + (t + (classoid-of x))))) + +;; Helper function that implements (CTYPE-OF x) when X is an array. +#-sb-xc-host +(defun-cached (ctype-of-array + :values (ctype) ; Bind putative output to this when probing. + :hash-bits 7 + :hash-function (lambda (a &aux (hash cookie)) + (if header-p + (dotimes (axis rank hash) + (mixf hash (%array-dimension a axis))) + (mixf hash (length a))))) + ;; "type-key" is a perfect hash of rank + widetag + simple-p. + ;; If it matches, then compare dims, which are read from the output. + ;; The hash of the type-key + dims can have collisions. + ((array (lambda (array type-key) + (and (eq type-key cookie) + (let ((dims (array-type-dimensions ctype))) + (if header-p + (dotimes (axis rank t) + (unless (eq (pop (truly-the list dims)) + (%array-dimension array axis)) + (return nil))) + (eq (length array) (car dims)))))) + cookie) ; Store COOKIE as the single key. + &aux (rank (array-rank array)) + (simple-p (if (simple-array-p array) 1 0)) + (header-p (array-header-p array)) ; non-simple or rank <> 1 or both + (cookie (the fixnum (logior (ash (logior (ash rank 1) simple-p) + sb-vm:n-widetag-bits) + (array-underlying-widetag array))))) + ;; The value computed on cache miss. + (let ((etype (sb-vm::array-element-ctype array))) + (make-array-type (array-dimensions array) + :complexp (not (simple-array-p array)) + :element-type etype + :specialized-element-type etype))) + +(!defun-from-collected-cold-init-forms !type-cold-init) diff --git a/src/code/typep.lisp b/src/code/typep.lisp index 36f6af82af..b8f0f77b81 100644 --- a/src/code/typep.lisp +++ b/src/code/typep.lisp @@ -9,7 +9,7 @@ (in-package "SB-KERNEL") -#-sb-devel(declaim (start-block)) +(declaim (start-block)) ;;; (Note that when cross-compiling, SB-XC:TYPEP is interpreted as a ;;; test that the host Lisp object OBJECT translates to a target SBCL @@ -74,21 +74,19 @@ (type-specifier type)) t) (or (eq (array-type-specialized-element-type type) *wild-type*) + ;; FIXME: see whether this TYPE= can be reduced to EQ. + ;; (Each specialized element type should be an interned ctype) (values (type= (array-type-specialized-element-type type) - ;; FIXME: not the most efficient. - (specifier-type (array-element-type - object))))))) + (sb-vm::array-element-ctype object)))))) (member-type (when (member-type-member-p object type) t)) (classoid - ;; It might be more efficient to check that OBJECT is either INSTANCEP - ;; or FUNCALLABLE-INSTANCE-P before making this call. - ;; But doing that would change the behavior if %%TYPEP were ever called - ;; with a built-in classoid whose members are not instances. - ;; e.g. (%%typep (find-fdefn 'car) (specifier-type 'fdefn)) - ;; I'm not sure if that can happen. - (classoid-typep (layout-of object) type object)) + (if (built-in-classoid-p type) + (funcall (built-in-classoid-predicate type) object) + (and (or (%instancep object) + (functionp object)) + (classoid-typep (wrapper-of object) type object)))) (union-type (some (lambda (union-type-type) (recurse object union-type-type)) (union-type-types type))) @@ -102,15 +100,13 @@ #+sb-simd-pack (simd-pack-type (and (simd-pack-p object) - (let* ((tag (%simd-pack-tag object)) - (name (nth tag *simd-pack-element-types*))) - (not (not (member name (simd-pack-type-element-type type))))))) + (let* ((tag (%simd-pack-tag object))) + (= (sbit (simd-pack-type-element-type type) tag) 1)))) #+sb-simd-pack-256 (simd-pack-256-type (and (simd-pack-256-p object) - (let* ((tag (%simd-pack-256-tag object)) - (name (nth tag *simd-pack-element-types*))) - (not (not (member name (simd-pack-256-type-element-type type))))))) + (let* ((tag (%simd-pack-256-tag object))) + (= (sbit (simd-pack-256-type-element-type type) tag) 1)))) (character-set-type (test-character-type type)) (negation-type @@ -135,7 +131,7 @@ ((functionp) (functionp object)) ; least strict ((nil) ; medium strict (and (functionp object) - (csubtypep (specifier-type (sb-impl::%fun-type object)) type))) + (csubtypep (specifier-type (sb-impl::%fun-ftype object)) type))) (t ; strict (error "Function types are not a legal argument to TYPEP:~% ~S" (type-specifier type)))))))) @@ -156,9 +152,8 @@ (block nil (classoid-typep (typecase object - (instance (%instance-layout object)) - (funcallable-instance - (%fun-layout object)) + (instance (%instance-wrapper object)) + (funcallable-instance (%fun-wrapper object)) (t (return))) (cdr (truly-the cons cache)) object))) @@ -180,24 +175,27 @@ (unless classoid (error "The class ~S has not yet been defined." (classoid-cell-name cell))) - (classoid-typep layout classoid object))) + (classoid-typep (layout-friend layout) classoid object))) ;;; Return true of any object which is either a funcallable-instance, ;;; or an ordinary instance that is not a structure-object. (declaim (inline %pcl-instance-p)) (defun %pcl-instance-p (x) - ;; The COND is more efficient than LAYOUT-OF. - (layout-for-pcl-obj-p (cond ((%instancep x) (%instance-layout x)) - ((function-with-layout-p x) (%fun-layout x)) - (t (return-from %pcl-instance-p nil))))) + ;; read-time eval so that vop-existsp isn't part of the inline expansion + #.(if (sb-c::vop-existsp :translate %instanceoid-layout) + '(logtest (layout-flags (%instanceoid-layout x)) +pcl-object-layout-flag+) + ;; The COND is slightly more efficient than LAYOUT-OF. + '(layout-for-pcl-obj-p + (cond ((%instancep x) (%instance-layout x)) + ((function-with-layout-p x) (%fun-layout x)) + (t (return-from %pcl-instance-p nil)))))) ;;; Try to ensure that the object's layout is up-to-date only if it is an instance ;;; or funcallable-instance of other than a static or structure classoid type. -;;; LAYOUT is the *expected* type, not the the layout currently in OBJECT. -(defun update-object-layout-or-invalid (object layout) - (if (%pcl-instance-p object) - (sb-pcl::check-wrapper-validity object) - (sb-c::%layout-invalid-error object layout))) +(defun update-object-layout (object) + (wrapper-friend (if (%pcl-instance-p object) + (sb-pcl::check-wrapper-validity object) + (wrapper-of object)))) ;;; Test whether OBJ-LAYOUT is from an instance of CLASSOID. @@ -208,14 +206,14 @@ ;;; could be done in either order, * HOWEVER * it is less racy to perform ;;; them in this exact order. Consider the case that OBJ-LAYOUT is T ;;; for a class that satisfies CLASS-FINALIZED-P and suppose these operations were -;;; reversed from the order below. UPDATE-OBJECT-LAYOUT-OR-INVALID is going to make +;;; reversed from the order below. CHECK-WRAPPER-VALIDITY is going to make ;;; a new layout, registering it and installing into the classoid. ;;; Then %ENSURE-CLASSOID-VALID is going to call %FORCE-CACHE-FLUSHES which is going ;;; to make yet another new layout. The "transitivity of wrapper updates" usually ;;; causes the first new layout to automatically update to the second new layout, ;;; except that the other thread has already fetched the old layout. ;;; But by using the order below, there will not be two new layouts made, only one, -;;; because UPDATE-OBJECT-LAYOUT-OR-INVALID is able to use the layout +;;; because CHECK-WRAPPER-VALIDITY is able to use the layout ;;; that was updated into the classoid by %ENSURE-CLASSOID-VALID. ;;; All other things being equal, one new layout is better than two. ;;; At least I think that's what happens. @@ -229,6 +227,7 @@ ;;; of thousands of iterations of 'classoid-typep.impure.lisp' (defun classoid-typep (obj-layout classoid object) + (declare (type wrapper obj-layout)) ;; FIXME & KLUDGE: We could like to grab the *WORLD-LOCK* here (to ensure that ;; class graph doesn't change while we're doing the typep test), but in ;; practice that causes trouble -- deadlocking against the compiler @@ -238,18 +237,29 @@ ;; locking here makes Slime unusable with :SPAWN in post *WORLD-LOCK* world. So... ;; -- NS 2008-12-16 (multiple-value-bind (obj-layout layout) - (do ((layout (classoid-layout classoid) (classoid-layout classoid)) - (i 0 (+ i 1)) - (obj-layout obj-layout)) - ((and (not (layout-invalid obj-layout)) - (not (layout-invalid layout))) - (values obj-layout layout)) - (aver (< i 2)) - (%ensure-classoid-valid classoid layout "typep") - (when (zerop (layout-clos-hash obj-layout)) - (setq obj-layout (update-object-layout-or-invalid object layout)))) + (cond ((not (layout-for-pcl-obj-p obj-layout)) + ;; If the object is a structure or condition, just ensure validity of the class + ;; that we're testing against. Whether obj-layout is "valid" has no relevance. + ;; This is racy though because %ENSURE-CLASSOID-VALID should return + ;; the most up-to-date layout for the classoid, but it doesn't. Oh well. + (%ensure-classoid-valid classoid (classoid-wrapper classoid) "typep") + (values obj-layout (classoid-wrapper classoid))) + (t + ;; And this case is even more racy, naturally. + (do ((layout (classoid-wrapper classoid) (classoid-wrapper classoid)) + (i 0 (+ i 1)) + (obj-layout obj-layout)) + ((and (not (wrapper-invalid obj-layout)) + (not (wrapper-invalid layout))) + (values obj-layout layout)) + (aver (< i 2)) + (%ensure-classoid-valid classoid layout "typep") + (when (zerop (wrapper-clos-hash obj-layout)) + (setq obj-layout (sb-pcl::check-wrapper-validity object)))))) + ;; FIXME: if LAYOUT is for a structure, use the STRUCTURE-IS-A test + ;; which avoids iterating. (or (eq obj-layout layout) - (let ((obj-inherits (layout-inherits obj-layout))) + (let ((obj-inherits (wrapper-inherits obj-layout))) (dotimes (i (length obj-inherits) nil) (when (eq (svref obj-inherits i) layout) (return t))))))) @@ -282,11 +292,14 @@ (values (%%typep obj type) t))) (classoid (if (built-in-classoid-p type) - (values (%%typep obj type) t) + (values (funcall (built-in-classoid-predicate type) obj) t) + ;; Hmm, if the classoid is a subtype of STRUCTURE-OBJECT, + ;; can we not decide this _now_ ? In fact, even for STANDARD-OBJECT, the spec + ;; says the compiler may assume inheritance not to change at runtime. (if (if (csubtypep type (specifier-type 'function)) (funcallable-instance-p obj) (%instancep obj)) - (if (eq (classoid-layout type) + (if (eq (classoid-wrapper type) (info :type :compiler-layout (classoid-name type))) (values (sb-xc:typep obj type) t) (values nil nil)) @@ -333,124 +346,6 @@ ;;; That's an unfortunate side-effect; this macro is done being used now. (fmakunbound 'typep-impl-macro) -;;;; miscellaneous interfaces - -;;; Clear memoization of all type system operations that can be -;;; altered by type definition/redefinition. -;;; -(defun clear-type-caches () - ;; FIXME: We would like to differentiate between different cache - ;; kinds, but at the moment all our caches pretty much are type - ;; caches. - (drop-all-hash-caches) - (values)) - -;;; This is like TYPE-OF, only we return a CTYPE structure instead of -;;; a type specifier, and we try to return the type most useful for -;;; type checking, rather than trying to come up with the one that the -;;; user might find most informative. -;;; -;;; To avoid inadvertent memory retention we avoid using arrays -;;; and functions as keys. -;;; During cross-compilation, the CTYPE-OF function is not memoized. -;;; Constants get their type stored in their LEAF, so it's ok. - -(defun-cached (ctype-of :hash-bits 7 :hash-function #'sxhash - :memoizer memoize) -;; an unfortunate aspect of using EQ is that several appearances -;; of the = double-float can be in the cache, but it's -;; probably more efficient overall to use object identity. - ((x eq)) - (flet ((try-cache (x) - (memoize - ;; For functions, the input is a type specifier - ;; of the form (FUNCTION (...) ...) - (cond ((listp x) (specifier-type x)) ; NIL can't occur - ((symbolp x) (make-eql-type x)) - (t (ctype-of-number x)))))) - (typecase x - (function - (if (funcallable-instance-p x) - (classoid-of x) - (let ((type (sb-impl::%fun-type x))) - (if (typep type '(cons (eql function))) ; sanity test - (try-cache type) - (classoid-of x))))) - (symbol (if x (try-cache x) (specifier-type 'null))) - (number (try-cache x)) - (array (ctype-of-array x)) - (cons (specifier-type 'cons)) - (character - (typecase x - (standard-char (specifier-type 'standard-char)) - (base-char (specifier-type 'base-char)) - ;; If the last case were expressed as EXTENDED-CHAR, - ;; we wrongly get "this is not a (VALUES CTYPE): NIL" - ;; because the compiler is too naive to see that - ;; the last 2 cases partition CHARACTER. - (t (specifier-type 'extended-char)))) - #+sb-simd-pack - (simd-pack - (let ((tag (%simd-pack-tag x))) - (svref (load-time-value - (coerce (cons (specifier-type 'simd-pack) - (mapcar (lambda (x) (specifier-type `(simd-pack ,x))) - *simd-pack-element-types*)) - 'vector) - t) - (if (<= 0 tag #.(1- (length *simd-pack-element-types*))) - (1+ tag) - 0)))) - #+sb-simd-pack-256 - (simd-pack-256 - (let ((tag (%simd-pack-256-tag x))) - (svref (load-time-value - (coerce (cons (specifier-type 'simd-pack-256) - (mapcar (lambda (x) (specifier-type `(simd-pack-256 ,x))) - *simd-pack-element-types*)) - 'vector) - t) - (if (<= 0 tag #.(1- (length *simd-pack-element-types*))) - (1+ tag) - 0)))) - (t - (classoid-of x))))) - -;; Helper function that implements (CTYPE-OF x) when X is an array. -(defun-cached (ctype-of-array - :values (ctype) ; Bind putative output to this when probing. - :hash-bits 7 - :hash-function (lambda (a &aux (hash cookie)) - (if header-p - (dotimes (axis rank hash) - (mixf hash (%array-dimension a axis))) - (mixf hash (length a))))) - ;; "type-key" is a perfect hash of rank + widetag + simple-p. - ;; If it matches, then compare dims, which are read from the output. - ;; The hash of the type-key + dims can have collisions. - ((array (lambda (array type-key) - (and (eq type-key cookie) - (let ((dims (array-type-dimensions ctype))) - (if header-p - (dotimes (axis rank t) - (unless (eq (pop (truly-the list dims)) - (%array-dimension array axis)) - (return nil))) - (eq (length array) (car dims)))))) - cookie) ; Store COOKIE as the single key. - &aux (rank (array-rank array)) - (simple-p (if (simple-array-p array) 1 0)) - (header-p (array-header-p array)) ; non-simple or rank <> 1 or both - (cookie (the fixnum (logior (ash (logior (ash rank 1) simple-p) - sb-vm:n-widetag-bits) - (array-underlying-widetag array))))) - ;; The value computed on cache miss. - (let ((etype (specifier-type (array-element-type array)))) - (make-array-type (array-dimensions array) - :complexp (not (simple-array-p array)) - :element-type etype - :specialized-element-type etype))) - ;;;; Some functions for examining the type system ;;;; which are not needed during self-build. diff --git a/src/code/uncross.lisp b/src/code/uncross.lisp index 1c067b3c0b..1cff68dc75 100644 --- a/src/code/uncross.lisp +++ b/src/code/uncross.lisp @@ -19,23 +19,8 @@ ;;; In the target system's compiler, uncrossing is just identity. #-sb-xc-host (progn - #-sb-fluid (declaim (inline uncross)) + (declaim (inline uncross)) (defun uncross (x) x)) -;;; In the cross-compiler, uncrossing is slightly less trivial. - -;;; This condition is only a STYLE-WARNING because generally it isn't important -;;; in practice to recurse through anything except CONSes anyway. -#| -#+sb-show -(define-condition uncross-rcr-failure (style-warning) - ((form :initarg :form :reader uncross-rcr-failure-form)) - (:report (lambda (c s) - (format s - "UNCROSS couldn't recurse through ~S~%~ - (which is OK as long as there are no SB-XC symbols ~ - down there)" - (uncross-rcr-failure-form c))))) -|# ;;; When cross-compiling, EVAL-WHEN :COMPILE-TOPLEVEL code is executed ;;; in the host Common Lisp, not the target. A certain amount of @@ -49,73 +34,23 @@ ;;; In order to make the dancing happen, we need to make a distinction ;;; between SB-XC and COMMON-LISP when we're executing a form at ;;; compile time (i.e. within EVAL-WHEN :COMPILE-TOPLEVEL) but we need -;;; to treat SB-XC as synonymous with COMMON-LISP otherwise. This -;;; can't be done by making SB-XC a nickname of COMMON-LISP, because -;;; the reader processes things before EVAL-WHEN, so by the time -;;; EVAL-WHEN :COMPILE-TOPLEVEL saw a form, the distinction it needs -;;; would be lost. Instead, we read forms preserving this distinction -;;; (treating SB-XC as a separate package), and only when we're about -;;; to process them (for any situation other than EVAL-WHEN -;;; (:COMPILE-TOPLEVEL)) do we call UNCROSS on them to obliterate the -;;; distinction. +;;; to treat SB-XC as synonymous with COMMON-LISP otherwise. #+sb-xc-host -(let ((;; KLUDGE: We don't currently try to handle circular program - ;; structure, but we do at least detect it and complain about - ;; it.. - inside? (make-hash-table))) - (defun uncross (form) - (labels ((uncross-symbol (symbol) - ;; If SYMBOL's logical home package is CL: (meaning that its physical - ;; home package is XC-STRICT-CL or SB-XC or CL, or depending on - ;; the host's design, some other package exposed via CL:), - ;; then return the symbol as found via XC-STRICT-CL. - ;; This ensures that symbols that are used for their identity and - ;; not function compare as EQ after uncrossing, which they would not - ;; if for example, we altered (EQ (FLONUM-FORMAT x) 'SHORT-FLOAT) - ;; to compare against CL:SHORT-FLOAT. - (if (eq (sb-xc:symbol-package symbol) *cl-package*) - (find-symbol (symbol-name symbol) "XC-STRICT-CL") - symbol)) - (rcr (form) ; recursive part - (cond ((symbolp form) - (uncross-symbol form)) - ((or (numberp form) - (characterp form) - (stringp form)) - form) - (t - ;; If we reach here, FORM is something with - ;; internal structure which could include - ;; symbols in the SB-XC package. - (when (gethash form inside?) - (let ((*print-circle* t)) - ;; This code could probably be generalized - ;; to work on circular structure, but it - ;; seems easier just to avoid putting any - ;; circular structure into the bootstrap - ;; code. - (error "circular structure in ~S" form))) - (setf (gethash form inside?) t) - (unwind-protect - (typecase form - (cons - (recons form (rcr (car form)) (rcr (cdr form)))) - (t - ;; KLUDGE: There are other types - ;; (especially (ARRAY T) and - ;; STRUCTURE-OBJECT, but also HASH-TABLE - ;; and perhaps others) which could hold - ;; symbols. In principle we should handle - ;; those types as well. Failing that, we - ;; could give warnings for them. However, - ;; the current system works for - ;; bootstrapping in practice (because we - ;; don't use those constructs that way) - ;; and the warnings more annoying than - ;; useful, so I simply turned the - ;; warnings off. -- WHN 20001105 - #+nil (warn 'uncross-rcr-failure :form form) - form)) - (remhash form inside?)))))) - (clrhash inside?) - (rcr form)))) +(defun uncross (form) + (labels ((rcr (form) ; recursive part + (cond ((symbolp form) + ;; If SYMBOL's logical home package is CL: (meaning that its physical + ;; home package is XC-STRICT-CL or SB-XC or CL, or depending on + ;; the host's design, some other package exposed via CL:), + ;; then return the symbol as found via XC-STRICT-CL. + ;; This ensures that symbols that are used for their identity and + ;; not function compare as EQ after uncrossing, which they would not + ;; if for example, we altered (EQ (FLONUM-FORMAT x) 'SHORT-FLOAT) + ;; to compare against CL:SHORT-FLOAT. + (if (eq (sb-xc:symbol-package form) *cl-package*) + (find-symbol (symbol-name form) #.(find-package "XC-STRICT-CL")) + form)) + ((consp form) + (recons form (rcr (car form)) (rcr (cdr form)))) + (t form)))) + (rcr form))) diff --git a/src/code/unix-foreign-load.lisp b/src/code/unix-foreign-load.lisp index 862c8bd232..73d9953a47 100644 --- a/src/code/unix-foreign-load.lisp +++ b/src/code/unix-foreign-load.lisp @@ -65,21 +65,15 @@ (defun find-dynamic-foreign-symbol-address (symbol) (dlerror) ; clear old errors - (unless *runtime-dlhandle* - (bug "Cannot resolve foreign symbol: lost *runtime-dlhandle*")) ;; On real ELF & dlsym platforms the EXTERN-ALIEN-NAME is a no-op, ;; but on platforms where dlsym is simulated we use the mangled name. - (let* ((extern (extern-alien-name symbol)) - (result (sap-int (dlsym *runtime-dlhandle* extern))) - (err (dlerror))) - (if (or (not (zerop result)) (not err)) + (let ((extern (extern-alien-name symbol)) result - (dolist (obj *shared-objects*) - (let ((sap (shared-object-handle obj))) - (when sap - (setf result (sap-int (dlsym sap extern)) - err (dlerror)) - (when (or (not (zerop result)) (not err)) - (return result)))))))) - - + err) + (dolist (handle (cons *runtime-dlhandle* + (mapcar #'shared-object-handle *shared-objects*))) + (when handle + (setf result (sap-int (dlsym handle extern)) + err (dlerror)) + (when (or (not (zerop result)) (not err)) + (return result)))))) diff --git a/src/code/unix-pathname.lisp b/src/code/unix-pathname.lisp index 6e3846893b..9a11b0b3c7 100644 --- a/src/code/unix-pathname.lisp +++ b/src/code/unix-pathname.lisp @@ -162,7 +162,7 @@ (seperator-after-directory-p (or (pathname-component-present-p (pathname-name pathname)) (not as-file)))) - (with-simple-output-to-string (s) + (%with-output-to-string (s) (when directory (ecase (pop directory) (:absolute diff --git a/src/code/unix.lisp b/src/code/unix.lisp index 88ebcc74fa..5cb21d01cf 100644 --- a/src/code/unix.lisp +++ b/src/code/unix.lisp @@ -32,7 +32,7 @@ (defun c-strings->string-list (c-strings) (declare (type (alien (* c-string)) c-strings)) (let ((reversed-result nil)) - (dotimes (i sb-xc:most-positive-fixnum (error "argh! can't happen")) + (dotimes (i most-positive-fixnum) (declare (type index i)) (let ((c-string (deref c-strings i))) (if c-string @@ -42,7 +42,7 @@ ;;;; Lisp types used by syscalls (deftype unix-pathname () 'simple-string) -(deftype unix-fd () `(integer 0 ,sb-xc:most-positive-fixnum)) +(deftype unix-fd () `(integer 0 ,most-positive-fixnum)) (deftype unix-file-mode () '(unsigned-byte 32)) (deftype unix-pid () '(unsigned-byte 32)) @@ -53,13 +53,25 @@ (/show0 "unix.lisp 74") -;;; FIXME: The various FOO-SYSCALL-BAR macros, and perhaps some other -;;; macros in this file, are only used in this file, and could be -;;; implemented using SB-XC:DEFMACRO wrapped in EVAL-WHEN. -;;; -;;; SB-EXECUTABLE, at least, uses one of these macros; other libraries -;;; and programs have been known to use them as well. Perhaps they -;;; should live in SB-SYS or even SB-EXT? +(eval-when (:compile-toplevel :load-toplevel :execute) + (defun libc-name-for (x) + (assert (stringp x)) + ;; This function takes a possibly-wrapped C name and strips off "sb_" + ;; if it doesn't need a wrapper. The list of functions that can be + ;; called directly is listed explicitly, because there are also others + ;; that might want to be wrapped even if they don't need to be, + ;; like sb_opendir and sb_closedir. Why are those wrapped in fact? + #+netbsd x + #-netbsd (if (member x '("sb_getrusage" ; syscall* + "sb_gettimeofday" ;syscall* + "sb_select" ; int-syscall + "sb_getitimer" ; syscall* + "sb_setitimer" ; syscall* + "sb_clock_gettime" ; alien-funcall + "sb_utimes") ; posix + :test #'string=) + (subseq x 3) + x))) (defmacro syscall ((name &rest arg-types) success-form &rest args) (when (eql 3 (mismatch "[_]" name)) @@ -67,7 +79,8 @@ (concatenate 'string #+win32 "_" (subseq name 3)))) `(locally (declare (optimize (sb-c::float-accuracy 0))) - (let ((result (alien-funcall (extern-alien ,name (function int ,@arg-types)) + (let ((result (alien-funcall (extern-alien ,(libc-name-for name) + (function int ,@arg-types)) ,@args))) (if (minusp result) (values nil (get-errno)) @@ -79,14 +92,15 @@ (defmacro syscall* ((name &rest arg-types) success-form &rest args) `(locally (declare (optimize (sb-c::float-accuracy 0))) - (let ((result (alien-funcall (extern-alien ,name (function int ,@arg-types)) + (let ((result (alien-funcall (extern-alien ,(libc-name-for name) + (function int ,@arg-types)) ,@args))) (if (minusp result) (error "Syscall ~A failed: ~A" ,name (strerror)) ,success-form)))) (defmacro int-syscall ((name &rest arg-types) &rest args) - `(syscall (,name ,@arg-types) (values result 0) ,@args)) + `(syscall (,(libc-name-for name) ,@arg-types) (values result 0) ,@args)) (defmacro with-restarted-syscall ((&optional (value (gensym)) (errno (gensym))) @@ -165,11 +179,13 @@ corresponds to NAME, or NIL if there is none." #+win32 (sb-win32:unixlike-open path flags :overlapped overlapped) #-win32 (with-restarted-syscall (value errno) - (int-syscall ("open" c-string int int) - path - (logior #+largefile o_largefile - flags) - mode))) + (locally + (declare (optimize (sb-c::float-accuracy 0))) + (let ((result (alien-funcall (extern-alien "open" (function int c-string int &optional int)) + path (logior flags) mode))) + (if (minusp result) + (values nil (get-errno)) + (values result 0)))))) ;;; UNIX-CLOSE accepts a file descriptor and attempts to close the file ;;; associated with it. @@ -387,17 +403,17 @@ corresponds to NAME, or NIL if there is none." ;; ;; Signal an error at compile-time, since it's needed for the ;; runtime to start up - #-(or android linux openbsd freebsd netbsd sunos darwin hpux dragonfly haiku) + #-(or android linux openbsd freebsd netbsd sunos darwin dragonfly haiku) #.(error "POSIX-GETCWD is not implemented.") (or - #+(or linux openbsd freebsd netbsd sunos darwin hpux dragonfly haiku) + #+(or linux openbsd freebsd netbsd sunos darwin dragonfly haiku) (newcharstar-string (alien-funcall (extern-alien "getcwd" (function (* char) (* char) size-t)) nil #+(or linux openbsd freebsd netbsd darwin dragonfly haiku) 0 - #+(or sunos hpux) 1025)) + #+(or sunos) 1025)) #+android (with-alien ((ptr (array char #.path-max))) ;; Older bionic versions do not have the above feature. @@ -537,26 +553,6 @@ avoiding atexit(3) hooks, etc. Otherwise exit(2) is called." ;;;; sys/resource.h -;;; FIXME: All we seem to need is the RUSAGE_SELF version of this. -;;; -;;; This is like getrusage(2), except it returns only the system and -;;; user time, and returns the seconds and microseconds as separate -;;; values. -#-win32 (declaim (inline unix-fast-getrusage)) -#-win32 -(defun unix-fast-getrusage (who) - (declare (values (member t) - unsigned-byte fixnum - unsigned-byte fixnum)) - (with-alien ((usage (struct rusage))) - (syscall* ("sb_getrusage" int (* (struct rusage))) - (values t - (slot (slot usage 'ru-utime) 'tv-sec) - (slot (slot usage 'ru-utime) 'tv-usec) - (slot (slot usage 'ru-stime) 'tv-sec) - (slot (slot usage 'ru-stime) 'tv-usec)) - who (addr usage)))) - ;;; Return information about the resource usage of the process ;;; specified by WHO. WHO can be either the current process ;;; (rusage_self) or all of the terminated child processes @@ -660,8 +656,6 @@ avoiding atexit(3) hooks, etc. Otherwise exit(2) is called." (declare (type (integer 0 #.fd-setsize) ,n)) ,@body)) -;;;; FIXME: Why have both UNIX-SELECT and UNIX-FAST-SELECT? - ;;; Perform the UNIX select(2) system call. (declaim (inline unix-fast-select)) (defun unix-fast-select (num-descriptors @@ -687,69 +681,7 @@ avoiding atexit(3) hooks, etc. Otherwise exit(2) is called." (note-dangerous-wait "select(2)")) (select (int-sap 0))))))) -;;; UNIX-SELECT accepts sets of file descriptors and waits for an event -;;; to happen on one of them or to time out. -(declaim (inline num-to-fd-set fd-set-to-num)) -(defun num-to-fd-set (fdset num) - (typecase num - (fixnum - (setf (deref (slot fdset 'fds-bits) 0) num) - (loop for index from 1 below (/ fd-setsize - sb-vm:n-machine-word-bits) - do (setf (deref (slot fdset 'fds-bits) index) 0))) - (t - (loop for index from 0 below (/ fd-setsize - sb-vm:n-machine-word-bits) - do (setf (deref (slot fdset 'fds-bits) index) - (ldb (byte sb-vm:n-machine-word-bits - (* index sb-vm:n-machine-word-bits)) - num)))))) - -(defun fd-set-to-num (nfds fdset) - (if (<= nfds sb-vm:n-machine-word-bits) - (deref (slot fdset 'fds-bits) 0) - (loop for index below (/ fd-setsize - sb-vm:n-machine-word-bits) - sum (ash (deref (slot fdset 'fds-bits) index) - (* index sb-vm:n-machine-word-bits))))) - -;;; Examine the sets of descriptors passed as arguments to see whether -;;; they are ready for reading and writing. See the UNIX Programmer's -;;; Manual for more information. -(defun unix-select (nfds rdfds wrfds xpfds to-secs &optional (to-usecs 0)) - (declare (muffle-conditions compiler-note)) - (declare (type integer nfds) - (type unsigned-byte rdfds wrfds xpfds) - (type (or (unsigned-byte 31) null) to-secs) - (type (unsigned-byte 31) to-usecs) - (optimize (speed 3) (safety 0))) - (with-fd-setsize (nfds) - (with-alien ((tv (struct timeval)) - (rdf (struct fd-set)) - (wrf (struct fd-set)) - (xpf (struct fd-set))) - (cond (to-secs - (setf (slot tv 'tv-sec) to-secs - (slot tv 'tv-usec) to-usecs)) - ((not *interrupts-enabled*) - (note-dangerous-wait "select(2)"))) - (num-to-fd-set rdf rdfds) - (num-to-fd-set wrf wrfds) - (num-to-fd-set xpf xpfds) - (macrolet ((frob (lispvar alienvar) - `(if (zerop ,lispvar) - (int-sap 0) - (alien-sap (addr ,alienvar))))) - (syscall ("sb_select" int (* (struct fd-set)) (* (struct fd-set)) - (* (struct fd-set)) (* (struct timeval))) - (values result - (fd-set-to-num nfds rdf) - (fd-set-to-num nfds wrf) - (fd-set-to-num nfds xpf)) - nfds (frob rdfds rdf) (frob wrfds wrf) (frob xpfds xpf) - (if to-secs (alien-sap (addr tv)) (int-sap 0))))))) - -;;; Lisp-side implmentations of FD_FOO macros. +;;; Lisp-side implementations of FD_FOO macros. (declaim (inline fd-set fd-clr fd-isset fd-zero)) (defun fd-set (offset fd-set) (multiple-value-bind (word bit) (floor offset @@ -1003,14 +935,13 @@ avoiding atexit(3) hooks, etc. Otherwise exit(2) is called." #-win32 (defun unix-setitimer (which int-secs int-usec val-secs val-usec) - "UNIX-SETITIMER sets the INTERVAL and VALUE slots of one of - three system timers (:real :virtual or :profile). A SIGALRM signal - will be delivered VALUE <seconds+microseconds> from now. INTERVAL, - when non-zero, is <seconds+microseconds> to be loaded each time - the timer expires. Setting INTERVAL and VALUE to zero disables - the timer. See the Unix man page for more details. On success, - unix-setitimer returns the old contents of the INTERVAL and VALUE - slots as in unix-getitimer." + "UNIX-SETITIMER sets the INTERVAL and VALUE slots of one of three system + timers (:real :virtual or :profile). A SIGALRM, SIGVTALRM, or SIGPROF + respectively will be delivered in VALUE <seconds+microseconds> from now. + INTERVAL, when non-zero, is reloaded into the timer on each expiration. + Setting VALUE to zero disables the timer. See the Unix man page for more + details. On success, unix-setitimer returns the + old contents of the INTERVAL and VALUE slots as in unix-getitimer." (declare (type (member :real :virtual :profile) which) (type unsigned-byte int-secs val-secs) (type (integer 0 (1000000)) int-usec val-usec) @@ -1027,13 +958,13 @@ avoiding atexit(3) hooks, etc. Otherwise exit(2) is called." (slot (slot itvn 'it-interval) 'tv-usec) int-usec (slot (slot itvn 'it-value ) 'tv-sec ) val-secs (slot (slot itvn 'it-value ) 'tv-usec) val-usec) - (syscall* ("sb_setitimer" int (* (struct timeval))(* (struct timeval))) + (syscall* ("sb_setitimer" int (* (struct timeval)) (* (struct timeval))) (values t (slot (slot itvo 'it-interval) 'tv-sec) (slot (slot itvo 'it-interval) 'tv-usec) (slot (slot itvo 'it-value) 'tv-sec) (slot (slot itvo 'it-value) 'tv-usec)) - which (alien-sap (addr itvn))(alien-sap (addr itvo)))))) + which (alien-sap (addr itvn)) (alien-sap (addr itvo)))))) ;;; FIXME: Many Unix error code definitions were deleted from the old @@ -1043,41 +974,65 @@ avoiding atexit(3) hooks, etc. Otherwise exit(2) is called." ;;; enough of them all in one place here that they should probably be ;;; removed by hand. -(defconstant micro-seconds-per-internal-time-unit - (/ 1000000 sb-xc:internal-time-units-per-second)) +(defconstant microseconds-per-internal-time-unit + (/ 1000000 internal-time-units-per-second)) +(defconstant nanoseconds-per-internal-time-unit + (* microseconds-per-internal-time-unit 1000)) ;;; UNIX specific code, that has been cleanly separated from the ;;; Windows build. #-win32 (progn + (declaim (inline clock-gettime)) + (defun clock-gettime (clockid) + (declare (type (signed-byte 32) clockid)) + (with-alien ((ts (struct timespec))) + (alien-funcall (extern-alien #.(libc-name-for "sb_clock_gettime") + (function int int (* (struct timespec)))) + clockid (addr ts)) + ;; 'seconds' is definitely a fixnum for 64-bit, because most-positive-fixnum + ;; can express 1E11 years in seconds. + (values #+64-bit (truly-the fixnum (slot ts 'tv-sec)) + #-64-bit (slot ts 'tv-sec) + (truly-the (integer 0 #.(expt 10 9)) (slot ts 'tv-nsec))))) + (declaim (inline get-time-of-day)) (defun get-time-of-day () "Return the number of seconds and microseconds since the beginning of the UNIX epoch (January 1st 1970.)" (with-alien ((tv (struct timeval))) - (syscall* ("sb_gettimeofday" (* (struct timeval))) + (syscall* ("sb_gettimeofday" (* (struct timeval)) system-area-pointer) (values (slot tv 'tv-sec) (slot tv 'tv-usec)) - (addr tv)))) - - (declaim (inline system-internal-run-time - system-real-time-values)) - (defun system-real-time-values () - (multiple-value-bind (sec usec) (get-time-of-day) - (declare (type unsigned-byte sec) (type (unsigned-byte 31) usec)) - (values sec (truncate usec micro-seconds-per-internal-time-unit)))) - - ;; There are two optimizations here that actually matter (on 32-bit - ;; systems): substract the epoch from seconds and milliseconds - ;; separately, as those should remain fixnums for the first 17 years - ;; or so of runtime. Also, avoid doing consing a new bignum if the - ;; result would be = to the last result given. - ;; - ;; Note: the next trick would be to spin a separate thread to update - ;; a global value once per internal tick, so each individual call to - ;; get-internal-real-time would be just a memory read... but that is - ;; probably best left for user-level code. ;) + (addr tv) (int-sap 0)))) + + ;; The "optimizations that actually matter" don't actually matter for 64-bit. + ;; Microseconds can express at least 1E5 years of uptime: + ;; (float (/ most-positive-fixnum (* 1000000 60 60 24 (+ 365 1/4)))) + ;; = microseconds-per-second * seconds-per-minute * minutes-per-hour + ;; * hours-per-day * days-per-year + + (defun get-internal-real-time () + (with-alien ((base (struct timespec) :extern "lisp_init_time")) + (multiple-value-bind (c-sec c-nsec) + ;; By scaling down we end up with far less resolution than clock-realtime + ;; offers, and COARSE is about twice as fast, so use that, but only for linux. + ;; BSD has something similar. + (clock-gettime #+linux clock-monotonic-coarse #-linux clock-monotonic) + + #+64-bit ;; I know that my math is valid for 64-bit. + (declare (optimize (sb-c::type-check 0))) + #+64-bit + (let ((delta-sec (the fixnum (- c-sec (the fixnum (slot base 'tv-sec))))) + (delta-nsec (the fixnum (- c-nsec (the fixnum (slot base 'tv-nsec)))))) + (the sb-kernel:internal-time + (+ (the fixnum (* delta-sec internal-time-units-per-second)) + (truncate delta-nsec nanoseconds-per-internal-time-unit)))) + + ;; There are two optimizations here that actually matter on 32-bit systems: + ;; (1) subtract the epoch from seconds and milliseconds separately, + ;; (2) avoid consing a new bignum if the result is unchanged. ;; ;; Thanks to James Anderson for the optimization hint. ;; @@ -1085,60 +1040,40 @@ the UNIX epoch (January 1st 1970.)" ;; bound. ;; ;; --NS 2007-04-05 - (let ((e-sec 0) - (e-msec 0) - (c-sec 0) - (c-msec 0) - (now 0)) - (declare (type sb-kernel:internal-seconds e-sec c-sec) - (type sb-kernel:internal-seconds e-msec c-msec) - (type sb-kernel:internal-time now)) - (defun reinit-internal-real-time () - (setf (values e-sec e-msec) (system-real-time-values) - c-sec 0 - c-msec 0)) - ;; If two threads call this at the same time, we're still safe, I - ;; believe, as long as NOW is updated before either of C-MSEC or - ;; C-SEC. Same applies to interrupts. --NS - ;; - ;; I believe this is almost correct with x86/x86-64 cache - ;; coherency, but if the new value of C-SEC, C-MSEC can become - ;; visible to another CPU without NOW doing the same then it's - ;; unsafe. It's `almost' correct on x86 because writes by other - ;; processors may become visible in any order provided transitity - ;; holds. With at least three cpus, C-MSEC and C-SEC may be from - ;; different threads and an incorrect value may be returned. - ;; Considering that this failure is not detectable by the caller - - ;; it looks like time passes a bit slowly - and that it should be - ;; an extremely rare occurance I'm inclinded to leave it as it is. - ;; --MG - (defun get-internal-real-time () - (multiple-value-bind (sec msec) (system-real-time-values) - (unless (and (= msec c-msec) (= sec c-sec)) - (setf now (+ (* (- sec e-sec) - sb-xc:internal-time-units-per-second) - (- msec e-msec)) - c-msec msec - c-sec sec)) - now))) - + #-64-bit + (symbol-macrolet ((observed-sec + (sb-thread::thread-observed-internal-real-time-delta-sec thr)) + (observed-msec + (sb-thread::thread-observed-internal-real-time-delta-millisec thr)) + (time (sb-thread::thread-internal-real-time thr))) + (let* ((delta-sec (- c-sec (slot base 'tv-sec))) + ;; I inadvertently had too many THE casts in here, so I'd prefer + ;; to err on the side of caution rather than cause GC lossage + ;; (which I accidentally did). So assert that nanoseconds are <= 10^9 + ;; and the compiler will do as best it can with that information. + (delta-nsec (- c-nsec (the (integer 0 #.(expt 10 9)) + (slot base 'tv-nsec)))) + ;; ROUND, FLOOR? Who cares, it's a number that's going to change. + ;; More math = more self-induced jitter. + (delta-millisec (floor delta-nsec 1000000)) + (thr sb-thread:*current-thread*)) + (if (and (= delta-sec observed-sec) (= delta-millisec observed-msec)) + time + (let ((current (+ (* delta-sec internal-time-units-per-second) + ;; ASSUMPTION: delta-millisec = delta-itu + delta-millisec))) + (setf time current + observed-msec delta-millisec + observed-sec delta-sec) + current))))))) + + (declaim (inline system-internal-run-time)) + #-sunos ; defined in sunos-os (defun system-internal-run-time () - (multiple-value-bind (ignore utime-sec utime-usec stime-sec stime-usec) - (unix-fast-getrusage rusage_self) - (declare (ignore ignore) - (type unsigned-byte utime-sec stime-sec) - ;; (Classic CMU CL had these (MOD 1000000) instead, but - ;; at least in Linux 2.2.12, the type doesn't seem to - ;; be documented anywhere and the observed behavior is - ;; to sometimes return 1000000 exactly.) - (type fixnum utime-usec stime-usec)) - (let ((result (+ (* (+ utime-sec stime-sec) - sb-xc:internal-time-units-per-second) - (floor (+ utime-usec - stime-usec - (floor micro-seconds-per-internal-time-unit 2)) - micro-seconds-per-internal-time-unit)))) - result)))) + (multiple-value-bind (sec nsec) (clock-gettime clock-process-cputime-id) + (+ (* sec internal-time-units-per-second) + (floor (+ nsec (floor nanoseconds-per-internal-time-unit 2)) + nanoseconds-per-internal-time-unit))))) ;;; FIXME, KLUDGE: GET-TIME-OF-DAY used to be UNIX-GETTIMEOFDAY, and had a ;;; primary return value indicating sucess, and also returned timezone diff --git a/src/code/warm-error.lisp b/src/code/warm-error.lisp index 84aa610437..9422f076e3 100644 --- a/src/code/warm-error.lisp +++ b/src/code/warm-error.lisp @@ -19,13 +19,18 @@ ;; that needs to know what the unknown type is, and tries to re-parse. ;; Also, there are some unknowns in there already. How on earth did that happen??? (do-all-symbols (s) - (let ((info (sb-int:info :function :type s))) - (when (consp info) - (let ((parsed (specifier-type info))) - (setf (sb-int:info :function :type s) parsed))))) + (unless (macro-function s) + (let ((info (sb-int:info :function :type s))) + (when (consp info) + (let ((parsed (specifier-type info))) + (setf (sb-int:info :function :type s) parsed)))))) ;; One good kludge deserves another. ;; This is OK only because it's the very first file compiled in warm build. - (assert (<= (length sb-c::*undefined-warnings*) 2)) + (let ((disallowed-undefineds + (remove-if (lambda (x) (member x '(class sb-pcl::condition-class))) + (mapcar #'sb-c::undefined-warning-name + sb-c::*undefined-warnings*)))) + (assert (not disallowed-undefineds))) (setf sb-c::*undefined-warnings* nil)) ;;; Moved from 'cold-error' to this file because of (at least) these reasons: @@ -40,7 +45,7 @@ (superclassoid-name (classoid-name super))) ;; CONDITION is necessarily an INSTANCE, ;; but pedantry requires it be the right subtype of instance. - (unless (classoid-typep (%instance-layout condition) + (unless (classoid-typep (%instance-wrapper condition) super condition) (error 'simple-type-error :datum datum :expected-type superclassoid-name diff --git a/src/code/warm-mswin.lisp b/src/code/warm-mswin.lisp index 8d1417a1d5..f4be4e0406 100644 --- a/src/code/warm-mswin.lisp +++ b/src/code/warm-mswin.lisp @@ -32,8 +32,17 @@ (stdout handle) (stderr handle))) +(defconstant +startf-use-show-window+ #x001) (defconstant +startf-use-std-handles+ #x100) +(defconstant +sw-hide+ 0) +(defconstant +sw-show-normal+ 1) +(defconstant +sw-show-minimized+ 2) +(defconstant +sw-show-maximized+ 3) +(defconstant +sw-show-no-activate+ 4) +(defconstant +sw-show-min-no-active+ 7) +(defconstant +sw-show-na+ 8) + (define-alien-routine ("CreateProcessW" create-process) lispbool (application-name system-string) (command-line system-string) @@ -46,8 +55,6 @@ (startup-info (* t)) (process-information (* t))) - - (defun search-path (partial-name) "Searh executable using the system path" (with-alien ((pathname-buffer pathname-buffer)) @@ -76,17 +83,23 @@ (process handle) (exit-code uint)) -(defun mswin-spawn (program argv stdin stdout stderr searchp envp directory) +(defun zero-alien (alien type) + `(alien-funcall (extern-alien "memset" (function void system-area-pointer int unsigned)) + (alien-sap ,alien) 0 (alien-size ,type :bytes))) + +(defun mswin-spawn (program argv stdin stdout stderr searchp envp directory window preserve-handles) (let ((std-handles (multiple-value-list (get-std-handles))) (inheritp nil)) (flet ((maybe-std-handle (arg) (let ((default (pop std-handles))) (case arg (-1 default) (otherwise (setf inheritp t) arg))))) + (when preserve-handles + (setf inheritp t) + (loop for handle in preserve-handles + do (setf (inheritable-handle-p handle) t))) (with-alien ((process-information process-information) (startup-info startup-info)) - (sb-kernel:system-area-ub8-fill - 0 (alien-sap startup-info) - 0 (alien-size startup-info :bytes)) + (zero-alien startup-info startup-info) (setf (slot startup-info 'cb) (alien-size startup-info :bytes) (slot startup-info 'stdin) (maybe-std-handle stdin) (slot startup-info 'stdout) (maybe-std-handle stdout) @@ -94,7 +107,18 @@ (slot startup-info 'reserved1) nil (slot startup-info 'reserved2) 0 (slot startup-info 'reserved3) nil - (slot startup-info 'flags) (if inheritp +startf-use-std-handles+ 0)) + (slot startup-info 'show-window) (ecase window + (:hide +sw-hide+) + (:show-normal +sw-show-normal+) + (:show-maximized +sw-show-maximized+) + (:show-minimized +sw-show-minimized+) + (:show-no-activate +sw-show-no-activate+) + (:show-min-no-active +sw-show-min-no-active+) + (:show-na +sw-show-na+) + ((nil) 0)) + (slot startup-info 'flags) (logior (if inheritp +startf-use-std-handles+ 0) + (if window +startf-use-show-window+ 0))) + (without-interrupts ;; KLUDGE: pass null image file name when searchp is true. ;; This way, file extension gets resolved by OS if omitted. @@ -137,7 +161,7 @@ (defvar *console-control-enabled* nil) (defvar *console-control-spec* nil) -(sb-alien::define-alien-callback *alien-console-control-handler* (:stdcall int) +(define-alien-callable alien-console-control-handler (:stdcall int) ((event-code int)) (if (ignore-errors (funcall *console-control-handler* event-code)) 1 0)) @@ -159,7 +183,7 @@ true to stop searching)." *console-control-spec*) (setf *console-control-enabled* nil)) ((or symbol function) (setf *console-control-handler* new-handler) - (aver (plusp (set-console-ctrl-handler *alien-console-control-handler* 1))))) + (aver (plusp (set-console-ctrl-handler (alien-callable-function 'alien-console-control-handler) 1))))) (setf *console-control-spec* new-handler)) (defun initialize-console-control-handler (&optional reset-to-default-p) @@ -248,11 +272,6 @@ true to stop searching)." *console-control-spec*) (defconstant +copier-buffer+ 256) -(defmacro zero-alien (alien type) - `(sb-kernel:system-area-ub8-fill - 0 (alien-sap ,alien) - 0 (alien-size ,type :bytes))) - (defun setup-copiers (copiers) (let ((result (make-array (length copiers)))) (loop for copier in copiers diff --git a/src/code/weak.lisp b/src/code/weak.lisp index a30f8d51e6..be1370fb5f 100644 --- a/src/code/weak.lisp +++ b/src/code/weak.lisp @@ -15,7 +15,7 @@ "Allocate and return a weak pointer which points to OBJECT." (make-weak-pointer object)) -#-sb-fluid (declaim (inline weak-pointer-value)) +(declaim (inline weak-pointer-value)) (defun weak-pointer-value (weak-pointer) "If WEAK-POINTER is valid, return the value of WEAK-POINTER and T. If the referent of WEAK-POINTER has been garbage collected, diff --git a/src/code/win32-foreign-load.lisp b/src/code/win32-foreign-load.lisp index 690fd15904..08332cfa6e 100644 --- a/src/code/win32-foreign-load.lisp +++ b/src/code/win32-foreign-load.lisp @@ -106,8 +106,8 @@ (n-names (sap-ref-32 export-data 24)) (functions-sap (sap+ image-base (sap-ref-32 export-data 28))) (names-sap (sap+ image-base (sap-ref-32 export-data 32)))) - (loop repeat (min n-functions n-names) - for offset from 0 by #.sb-vm::n-word-bytes + (loop for offset from 0 by #.sb-vm::n-word-bytes + repeat (min n-functions n-names) collect (cons (sap-int (sap+ image-base (sap-ref-32 functions-sap offset))) diff --git a/src/code/win32-pathname.lisp b/src/code/win32-pathname.lisp index 2517b036d4..ddd399f75f 100644 --- a/src/code/win32-pathname.lisp +++ b/src/code/win32-pathname.lisp @@ -259,7 +259,7 @@ (make-pathname :defaults pathname :directory (substitute :back :up directory)))))) (coerce - (with-simple-output-to-string (s) + (%with-output-to-string (s) (when absolutep (write-string (case device (:unc +unc-file-name-prefix+) diff --git a/src/code/win32.lisp b/src/code/win32.lisp index 05cc9c2e17..9d7dc62f35 100644 --- a/src/code/win32.lisp +++ b/src/code/win32.lisp @@ -128,7 +128,9 @@ (nevents (* dword))) (define-alien-routine "socket_input_available" int - (socket handle)) + (socket handle) + (time long) + (utime long)) (define-alien-routine "console_handle_p" boolean (handle handle)) @@ -139,17 +141,19 @@ ;;; introspect it, so we have to try various things until we find ;;; something that works. Returns true if there could be input ;;; available, or false if there is not. -(defun handle-listen (handle) +(defun handle-listen (handle &optional (time 0) (utime 0)) (cond ((console-handle-p handle) (alien-funcall (extern-alien "win32_tty_listen" (function boolean handle)) handle)) (t (with-alien ((avail dword)) - - (unless (zerop (peek-named-pipe handle nil 0 nil (addr avail) nil)) - (return-from handle-listen (plusp avail)))) - (let ((res (socket-input-available handle))) + (let* ((res (peek-named-pipe handle nil 0 nil (addr avail) nil)) + (code (get-last-error))) + (cond + ((not (zerop res)) (return-from handle-listen (plusp avail))) + ((= code error-broken-pipe) (return-from handle-listen t))))) + (let ((res (socket-input-available handle time utime))) (unless (zerop res) (return-from handle-listen (= res 1)))) t))) @@ -312,11 +316,13 @@ (values result (if result 0 (get-last-error))) name nil)) +(defconstant +movefile-replace-existing+ 1) + (defun sb-unix:unix-rename (name1 name2) (declare (type sb-unix:unix-pathname name1 name2)) - (syscall (("MoveFile" t) lispbool system-string system-string) + (syscall (("MoveFileEx" t) lispbool system-string system-string dword) (values result (if result 0 (get-last-error))) - name1 name2)) + name1 name2 +movefile-replace-existing+)) (defun sb-unix::posix-getenv (name) (declare (type simple-string name)) @@ -343,7 +349,7 @@ ;;;; Process time information (defconstant 100ns-per-internal-time-unit - (/ 10000000 sb-xc:internal-time-units-per-second)) + (/ 10000000 internal-time-units-per-second)) ;; FILETIME ;; The FILETIME structure is a 64-bit value representing the number of @@ -376,6 +382,12 @@ (addr ,kernel-time) (addr ,user-time)))) +#+64-bit +(progn + (defun reinit-internal-real-time () nil) + (defun get-internal-real-time () + (alien-funcall (extern-alien "get_monotonic_time" (function unsigned))))) +#-64-bit (let ((epoch 0)) (declare (unsigned-byte epoch)) ;; FIXME: For optimization ideas see the unix implementation. @@ -427,7 +439,6 @@ (defconstant +filetime-unit+ 10000000) (defconstant +common-lisp-epoch-filetime-seconds+ 9435484800) -#-sb-fluid (declaim (inline get-time-of-day)) (defun get-time-of-day () "Return the number of seconds and microseconds since the beginning of the @@ -889,7 +900,7 @@ absense." (defun windows-pipe () (multiple-value-bind (created read-handle write-handle) - (create-pipe nil 256) + (create-pipe nil 0) (if created (values read-handle write-handle) (win32-error 'create-pipe)))) diff --git a/src/code/x86-64-simd.lisp b/src/code/x86-64-simd.lisp new file mode 100644 index 0000000000..451490035c --- /dev/null +++ b/src/code/x86-64-simd.lisp @@ -0,0 +1,641 @@ +;;;; This software is part of the SBCL system. See the README file for +;;;; more information. +;;;; +;;;; This software is derived from the CMU CL system, which was +;;;; written at Carnegie Mellon University and released into the +;;;; public domain. The software is in the public domain and is +;;;; provided with absolutely no warranty. See the COPYING and CREDITS +;;;; files for more information. + +(in-package "SB-VM") + +(eval-when (:compile-toplevel :load-toplevel :execute) + (define-vop () + (:translate vector-ref-128) + (:args (vector :scs (descriptor-reg)) + (index :scs (any-reg))) + (:arg-types * tagged-num) + (:results (res :scs (int-sse-reg))) + (:result-types simd-pack-ub32) + (:policy :fast-safe) + (:generator 3 + (inst movdqa res + (ea (- (* vector-data-offset n-word-bytes) other-pointer-lowtag) + vector + index + (index-scale (* n-word-bytes 2) index))))) + + (define-vop (set-vector-ref-128) + (:translate (setf vector-ref-128)) + (:args (value :scs (int-sse-reg)) + (vector :scs (descriptor-reg)) + (index :scs (any-reg))) + (:arg-types simd-pack-ub32 * tagged-num) + (:policy :fast-safe) + (:generator 3 + (inst movdqa (ea (- (* vector-data-offset n-word-bytes) other-pointer-lowtag) + vector + index + (index-scale (* n-word-bytes 2) index)) + value)))) + +;;; Cross compilation doesn't understand simd-pack constants. +(defmacro simd-mask (value) + `(inline-vop + (((:info value) ,(logior value + (ash value 32) + (ash value 64) + (ash value 96)))) + ((res int-sse-reg simd-pack-ub32)) + (inst movdqa res (register-inline-constant :sse value)))) + +(defmacro simd-string-case (a source destination index fallback) + `(let ((ascii-p (simd-mask 192)) + (a-mask (simd-mask ,(+ (expt 2 31) (char-code a)))) + (z-mask (simd-mask ,(+ (expt 2 31) 25))) + (flip (simd-mask #x20))) + (declare (optimize sb-c::preserve-single-use-debug-variables)) + (loop for ,index below (ceiling length (/ 128 32)) + do + (let ((bits (vector-ref-128 ,source ,index))) + (unless (zerop (inline-vop + (((bits int-sse-reg simd-pack-ub32 :target temp) bits) + ((ascii-p int-sse-reg simd-pack-ub32 :to :save) ascii-p) + ((temp))) + ((res unsigned-reg unsigned-num)) + (move temp bits) + (inst pcmpgtd temp ascii-p) + (inst pmovmskb res temp))) + (return ,fallback)) + (setf (vector-ref-128 ,destination ,index) + (inline-vop + (((bits int-sse-reg simd-pack-ub32 :target res) bits) + ((a-mask int-sse-reg simd-pack-ub32 :to :save) a-mask) + ((z-mask) z-mask) + ((flip) flip) + ((temp))) + ((res int-sse-reg simd-pack-ub32)) + (move temp bits) + (inst psubd temp a-mask) + (inst pcmpgtd temp z-mask) + (inst pandn temp flip) + (move res bits) + (inst pxor res temp))))))) + +(defun simd-nreverse8 (result vector start end) + (declare ((simple-array * (*)) vector) + (fixnum start end) + (optimize speed (safety 0))) + (with-pinned-objects (vector) + (inline-vop (((left sap-reg t) (vector-sap vector)) + ((start any-reg tagged-num) start) + ((end) end) + ((right signed-reg signed-num)) + ((l)) + ((r))) + () + (inst shr end 1) + (inst shr start 1) + (inst lea right (ea left end)) + (inst add left start) + (inst mov l right) + (inst sub l left) + (inst cmp l 16) + (inst jmp :b BYTE) + (inst sub right 8) + + LOOP + (inst mov l (ea left)) + (inst mov r (ea right)) + (inst bswap l) + (inst bswap r) + (inst mov (ea left) r) + (inst mov (ea right) l) + (inst add left 8) + (inst sub right 8) + (inst cmp left right) + (inst jmp :b LOOP) + + (inst add right 8) + + BYTE + (inst dec right) + (inst cmp right left) + (inst jmp :b DONE) + + ;; After the 16-element copy above there are at most 15 + ;; elements, have to swap 14 elements with one staying in the + ;; middle. + (loop repeat 7 + do + (inst mov :byte l (ea left)) + (inst mov :byte r (ea right)) + (inst mov :byte (ea left) r) + (inst mov :byte (ea right) l) + (inst inc left) + (inst dec right) + (inst cmp left right) + (inst jmp :ge DONE)) + DONE)) + result) + +(eval-when (:compile-toplevel :load-toplevel :execute) + (defun concat-ub8 (ub8s) + (let ((result 0)) + (loop for ub8 in ub8s + do (setf result (logior (ash result 8) ub8))) + result)) + + (defun concat-ub32 (ub32s) + (let ((result 0)) + (loop for ub32 in ub32s + do (setf result (logior (ash result 32) ub32))) + result))) + +(def-variant simd-nreverse8 :avx2 (result vector start end) + (declare (optimize speed (safety 0))) + (with-pinned-objects (vector) + (inline-vop (((left sap-reg t) (vector-sap vector)) + ((start any-reg tagged-num) start) + ((end) end) + ((right signed-reg signed-num)) + ((l)) + ((r)) + ((vl int-avx2-reg)) + ((vr)) + ((reverse-mask)) + ((reverse-mask-xmm int-sse-reg)) + ((vl-xmm)) + ((vr-xmm))) + () + (let ((reverse-mask-c (register-inline-constant :avx2 (concat-ub8 (loop for i below 32 collect i))))) + (assemble () + (inst shr end 1) + (inst shr start 1) + (inst lea right (ea left end)) + (inst add left start) + (inst mov l right) + (inst sub l left) + (inst cmp l 64) + (inst jmp :b XMM) + (inst sub right 32) + + (inst vmovdqu reverse-mask reverse-mask-c) + LOOP + (inst vmovdqu vl (ea left)) + (inst vmovdqu vr (ea right)) + (inst vperm2i128 vl vl vl 1) + (inst vperm2i128 vr vr vr 1) + (inst vpshufb vl vl reverse-mask) + (inst vpshufb vr vr reverse-mask) + (inst vmovdqu (ea left) vr) + (inst vmovdqu (ea right) vl) + (inst add left 32) + (inst sub right 32) + (inst cmp left right) + (inst jmp :b LOOP) + + (inst vzeroupper) + (inst add right 32) + + (inst mov l right) + (inst sub l left) + XMM + (inst cmp l 32) + (inst jmp :l WORD) + (inst sub right 16) + (inst vmovdqu reverse-mask-xmm reverse-mask-c) + (inst vmovdqu vl-xmm (ea left)) + (inst vmovdqu vr-xmm (ea right)) + (inst vpshufb vl-xmm vl-xmm reverse-mask-c) + (inst vpshufb vr-xmm vr-xmm reverse-mask-c) + (inst vmovdqu (ea left) vr-xmm) + (inst vmovdqu (ea right) vl-xmm) + (inst add left 16) + + + (inst mov l right) + (inst sub l left) + WORD + + (inst cmp l 16) + (inst jmp :l BYTE) + + (inst sub right 8) + (inst mov l (ea left)) + (inst mov r (ea right)) + (inst bswap l) + (inst bswap r) + (inst mov (ea left) r) + (inst mov (ea right) l) + (inst add left 8) + + BYTE + (inst dec right) + (inst cmp right left) + (inst jmp :b DONE) + + (loop repeat 7 + do + (inst mov :byte l (ea left)) + (inst mov :byte r (ea right)) + (inst mov :byte (ea left) r) + (inst mov :byte (ea right) l) + (inst inc left) + (inst dec right) + (inst cmp left right) + (inst jmp :ge DONE)) + + DONE)))) + result) + +(defun simd-nreverse32 (result vector start end) + (declare (optimize speed (safety 0))) + (with-pinned-objects (vector) + (inline-vop (((left sap-reg t) (vector-sap vector)) + ((start any-reg tagged-num) start) + ((end) end) + ((right signed-reg signed-num)) + ((l)) + ((r))) + () + (inst shl end 1) + (inst shl start 1) + (inst lea right (ea left end)) + (inst add left start) + (inst mov l right) + (inst sub l left) + (inst cmp l 16) + (inst jmp :b SCALAR) + (inst sub right 8) + + LOOP + (inst mov l (ea left)) + (inst mov r (ea right)) + (inst ror l 32) + (inst ror r 32) + (inst mov (ea left) r) + (inst mov (ea right) l) + (inst add left 8) + (inst sub right 8) + (inst cmp left right) + (inst jmp :b LOOP) + + (inst add right 8) + + SCALAR + (inst sub right 4) + (inst cmp right left) + (inst jmp :b DONE) + + (inst mov :dword l (ea left)) + (inst mov :dword r (ea right)) + (inst mov :dword (ea left) r) + (inst mov :dword (ea right) l) + DONE)) + result) + +(def-variant simd-nreverse32 :avx2 (result vector start end) + (declare (optimize speed (safety 0))) + (with-pinned-objects (vector) + (inline-vop (((left sap-reg t) (vector-sap vector)) + ((start any-reg tagged-num) start) + ((end) end) + ((right signed-reg signed-num)) + ((l)) + ((r)) + ((vl int-avx2-reg)) + ((vr)) + ((reverse-mask)) + ((vl-xmm int-sse-reg)) + ((vr-xmm))) + () + (inst shl end 1) + (inst shl start 1) + (inst lea right (ea left end)) + (inst add left start) + (inst mov l right) + (inst sub l left) + (inst cmp l 64) + (inst jmp :b XMM) + (inst sub right 32) + + (inst vmovdqu reverse-mask (register-inline-constant :avx2 (concat-ub32 (loop for i to 7 collect i)))) + LOOP + (inst vmovdqu vl (ea left)) + (inst vmovdqu vr (ea right)) + (inst vpermd vl reverse-mask vl) + (inst vpermd vr reverse-mask vr) + + (inst vmovdqu (ea left) vr) + (inst vmovdqu (ea right) vl) + (inst add left 32) + (inst sub right 32) + (inst cmp left right) + (inst jmp :b LOOP) + + (inst vzeroupper) + (inst add right 32) + + (inst mov l right) + (inst sub l left) + XMM + (inst cmp l 32) + (inst jmp :l WORD) + + (inst sub right 16) + (inst vmovdqu vl-xmm (ea left)) + (inst vmovdqu vr-xmm (ea right)) + (inst vpshufd vl-xmm vl-xmm 27) + (inst vpshufd vr-xmm vr-xmm 27) + (inst vmovdqu (ea left) vr-xmm) + (inst vmovdqu (ea right) vl-xmm) + (inst add left 16) + + (inst mov l right) + (inst sub l left) + WORD + (inst cmp l 16) + (inst jmp :l SCALAR) + + (inst sub right 8) + (inst mov l (ea left)) + (inst mov r (ea right)) + (inst ror l 32) + (inst ror r 32) + (inst mov (ea left) r) + (inst mov (ea right) l) + (inst add left 8) + + SCALAR + (inst sub right 4) + (inst cmp right left) + (inst jmp :b DONE) + + (inst mov :dword l (ea left)) + (inst mov :dword r (ea right)) + (inst mov :dword (ea left) r) + (inst mov :dword (ea right) l) + DONE)) + result) + +(defun simd-reverse8 (target source start length) + (declare (optimize speed (safety 0))) + (with-pinned-objects (target source) + (inline-vop (((source sap-reg t) (vector-sap source)) + ((target sap-reg t) (vector-sap target)) + ((start any-reg tagged-num) start) + ((length) length) + ((s-i signed-reg signed-num)) + ((t-i)) + ((g))) + () + (inst shr start 1) + (inst add source start) + (zeroize t-i) + (inst mov s-i length) + (inst shr s-i 1) + (inst cmp s-i 8) + (inst jmp :b SCALAR) + (inst sub s-i 8) + + LOOP + (inst mov g (ea source s-i)) + (inst bswap g) + (inst mov (ea target t-i) g) + + (inst add t-i 8) + (inst sub s-i 8) + (inst jmp :ge LOOP) + (inst add s-i 8) + + SCALAR + (inst sub s-i 1) + (inst jmp :b DONE) + + (loop repeat 7 + do + (inst mov :byte g (ea source s-i)) + (inst mov :byte (ea target t-i) g) + (inst inc t-i) + (inst sub s-i 1) + (inst jmp :b DONE)) + DONE)) + target) + +(def-variant simd-reverse8 :avx2 (target source start length) + (declare (optimize speed (safety 0))) + (with-pinned-objects (target source) + (inline-vop (((source sap-reg t) (vector-sap source)) + ((target sap-reg t) (vector-sap target)) + ((start any-reg tagged-num) start) + ((length) length) + ((s-i signed-reg signed-num)) + ((t-i)) + ((g)) + ((v int-avx2-reg)) + ((reverse-mask)) + ((reverse-mask-xmm int-sse-reg)) + ((v-xmm))) + () + (let ((reverse-mask-c (register-inline-constant :avx2 (concat-ub8 (loop for i below 32 collect i))))) + (assemble () + (inst shr start 1) + (inst add source start) + (zeroize t-i) + (inst mov s-i length) + (inst shr s-i 1) + (inst cmp s-i 32) + (inst jmp :b XMM) + (inst sub s-i 32) + + (inst vmovdqu reverse-mask reverse-mask-c) + LOOP + (inst vmovdqu v (ea source s-i)) + (inst vperm2i128 v v v 1) + (inst vpshufb v v reverse-mask) + (inst vmovdqu (ea target t-i) v) + (inst add t-i 32) + (inst sub s-i 32) + (inst jmp :ge LOOP) + (inst vzeroupper) + (inst add s-i 32) + + XMM + (inst cmp s-i 16) + (inst jmp :b WORD) + + (inst sub s-i 16) + (inst vmovdqu reverse-mask-xmm reverse-mask-c) + (inst vmovdqu v-xmm (ea source s-i)) + (inst vpshufb v-xmm v-xmm reverse-mask-c) + (inst vmovdqu (ea target t-i) v-xmm) + (inst add t-i 16) + + WORD + (inst cmp s-i 8) + (inst jmp :b BYTE) + + (inst sub s-i 8) + (inst mov g (ea source s-i)) + (inst bswap g) + (inst mov (ea target t-i) g) + (inst add t-i 8) + + BYTE + (inst sub s-i 1) + (inst jmp :b DONE) + + (loop repeat 7 + do + (inst mov :byte g (ea source s-i)) + (inst mov :byte (ea target t-i) g) + (inst inc t-i) + (inst sub s-i 1) + (inst jmp :b DONE)) + DONE)))) + target) + +(defun simd-reverse32 (target source start length) + (declare (optimize speed (safety 0))) + (with-pinned-objects (target source) + (inline-vop (((source sap-reg t) (vector-sap source)) + ((target sap-reg t) (vector-sap target)) + ((start any-reg tagged-num) start) + ((length) length) + ((s-i signed-reg signed-num)) + ((t-i)) + ((g))) + () + (inst shl start 1) + (inst add source start) + (zeroize t-i) + (inst mov s-i length) + (inst shl s-i 1) + (inst cmp s-i 8) + (inst jmp :b SCALAR) + (inst sub s-i 8) + + LOOP + (inst mov g (ea source s-i)) + (inst ror g 32) + (inst mov (ea target t-i) g) + + (inst add t-i 8) + (inst sub s-i 8) + (inst jmp :ge LOOP) + (inst add s-i 8) + + SCALAR + (inst sub s-i 4) + (inst jmp :b DONE) + + (inst mov :dword g (ea source s-i)) + (inst mov :dword (ea target t-i) g) + DONE)) + target) + +(def-variant simd-reverse32 :avx2 (target source start length) + (declare (optimize speed (safety 0))) + (with-pinned-objects (source target) + (inline-vop (((source sap-reg t) (vector-sap source)) + ((target sap-reg t) (vector-sap target)) + ((start any-reg tagged-num) start) + ((length) length) + ((s-i signed-reg signed-num)) + ((t-i)) + ((g)) + ((v int-avx2-reg)) + ((reverse-mask)) + ((v-xmm int-sse-reg))) + () + (inst shl start 1) + (inst add source start) + (zeroize t-i) + (inst mov s-i length) + (inst shl s-i 1) + (inst cmp s-i 32) + (inst jmp :b XMM) + (inst sub s-i 32) + + (inst vmovdqu reverse-mask (register-inline-constant :avx2 (concat-ub32 (loop for i to 7 collect i)))) + LOOP + (inst vmovdqu v (ea source s-i)) + (inst vpermd v reverse-mask v) + (inst vmovdqu (ea target t-i) v) + (inst add t-i 32) + (inst sub s-i 32) + (inst jmp :ge LOOP) + (inst vzeroupper) + (inst add s-i 32) + + XMM + (inst cmp s-i 16) + (inst jmp :b WORD) + + (inst sub s-i 16) + (inst vmovdqu v-xmm (ea source s-i)) + (inst vpshufd v-xmm v-xmm 27) + (inst vmovdqu (ea target t-i) v-xmm) + (inst add t-i 16) + + WORD + (inst cmp s-i 8) + (inst jmp :b SCALAR) + + (inst sub s-i 8) + (inst mov g (ea source s-i)) + (inst ror g 32) + (inst mov (ea target t-i) g) + (inst add t-i 8) + + SCALAR + (inst sub s-i 4) + (inst jmp :b DONE) + + (inst mov :dword g (ea source s-i)) + (inst mov :dword (ea target t-i) g) + DONE)) + target) + +(defun simd-cmp-8-32 (byte-array 32-bit-array length) + (declare (optimize speed (safety 0))) + (with-pinned-objects (byte-array 32-bit-array) + (inline-vop (((byte-array sap-reg t) (vector-sap byte-array)) + ((32-bit-array sap-reg t) (vector-sap 32-bit-array)) + ((end)) + ((length any-reg) length) + ((cmp unsigned-reg)) + ((bytes int-sse-reg)) + ((32-bits)) + ((zero))) + ((res descriptor-reg t :from :load)) + (load-symbol res t) + (inst test length length) + (inst jmp :z DONE) + (inst pxor zero zero) + (inst shr length 1) + (inst lea end (ea length byte-array)) + + LOOP + (inst movd bytes (ea byte-array)) + (inst movdqa 32-bits (ea 32-bit-array)) + (inst add byte-array 4) + (inst add 32-bit-array 16) + ;; Interleaving with zero widens bytes to halfwords, and then + ;; again to words. + ;; PMOVZXBD from SSE4.1 doesn't seem to be faster. + (inst punpcklbw bytes zero) + (inst punpcklwd bytes zero) + (inst pcmpeqd bytes 32-bits) + (inst pmovmskb cmp bytes) + (inst cmp :dword cmp #xFFFF) + (inst jmp :ne FALSE) + + (inst cmp byte-array end) + (inst jmp :b LOOP) + (inst jmp DONE) + + FALSE + (load-symbol res nil) + DONE))) diff --git a/src/code/x86-64-vm.lisp b/src/code/x86-64-vm.lisp index f6e3936810..722ef60c08 100644 --- a/src/code/x86-64-vm.lisp +++ b/src/code/x86-64-vm.lisp @@ -13,64 +13,7 @@ (defun machine-type () "Return a string describing the type of the local machine." "X86-64") - -;;;; :CODE-OBJECT fixups -;;; This gets called by LOAD to resolve newly positioned objects -;;; with things (like code instructions) that have to refer to them. -;;; Return KIND if the fixup needs to be recorded in %CODE-FIXUPS. -;;; The code object we're fixing up is pinned whenever this is called. -(defun fixup-code-object (code offset fixup kind flavor) - (declare (type index offset) (ignorable flavor)) - (let* ((sap (code-instructions code)) - (fixup (+ (if (eq kind :absolute64) - (signed-sap-ref-64 sap offset) - (signed-sap-ref-32 sap offset)) - fixup))) - (ecase kind - (:absolute64 - ;; Word at sap + offset contains a value to be replaced by - ;; adding that value to fixup. - (setf (sap-ref-64 sap offset) fixup)) - (:absolute - ;; Word at sap + offset contains a value to be replaced by - ;; adding that value to fixup. - (setf (sap-ref-32 sap offset) fixup)) - (:relative - ;; Fixup is the actual address wanted. - ;; Replace word with value to add to that loc to get there. - ;; In the #-immobile-code case, there's nothing to assert. - ;; Relative fixups don't exist with movable code. - #+immobile-code - (unless (immobile-space-obj-p code) - (error "Can't compute fixup relative to movable object ~S" code)) - (setf (signed-sap-ref-32 sap offset) - ;; JMP/CALL are relative to the next instruction, - ;; so add 4 bytes for the size of the displacement itself. - (- fixup (sap-int (sap+ sap (+ offset 4)))))))) - ;; An absolute fixup is stored in the code header's %FIXUPS slot if it - ;; references an immobile-space (but not static-space) object. - ;; Note that: - ;; (1) Call fixups occur in both :RELATIVE and :ABSOLUTE kinds. - ;; We can ignore the :RELATIVE kind, except for foreign call, - ;; as those point to the linkage table which has an absolute address - ;; and therefore might change in displacement from the call site - ;; if the immobile code space is relocated on startup. - ;; (2) :STATIC-CALL fixups point to immobile space, not static space. - #+immobile-space - (return-from fixup-code-object - (case flavor - ((:named-call :layout :immobile-symbol :symbol-value ; -> fixedobj subspace - :assembly-routine :assembly-routine* :static-call) ; -> varyobj subspace - (if (eq kind :absolute) :absolute)) - (:foreign - ;; linkage-table calls using the "CALL rel32" format need to be saved, - ;; because the linkage table resides at a fixed address. - ;; Space defragmentation can handle the fixup automatically, - ;; but core relocation can't - it can't find all the call sites. - (if (eq kind :relative) :relative)))) - nil) ; non-immobile-space builds never record code fixups - #+(or darwin linux openbsd win32 sunos (and freebsd x86-64)) (define-alien-routine ("os_context_float_register_addr" context-float-register-addr) (* unsigned) (context (* os-context-t)) (index int)) @@ -96,7 +39,49 @@ (sap-ref-single sap 4))) (complex-double-float (complex (sap-ref-double sap 0) - (sap-ref-double sap 8)))))) + (sap-ref-double sap 8))) + #+sb-simd-pack + (simd-pack-int + (%make-simd-pack-ub64 + (sap-ref-64 sap 0) + (sap-ref-64 sap 8))) + #+sb-simd-pack + (simd-pack-single + (%make-simd-pack-single + (sap-ref-single sap 0) + (sap-ref-single sap 4) + (sap-ref-single sap 8) + (sap-ref-single sap 12))) + #+sb-simd-pack + (simd-pack-double + (%make-simd-pack-double + (sap-ref-double sap 0) + (sap-ref-double sap 8))) + #+sb-simd-pack-256 + (simd-pack-256-int + (%make-simd-pack-256-ub64 + (sap-ref-64 sap 0) + (sap-ref-64 sap 8) + (sap-ref-64 sap 16) + (sap-ref-64 sap 24))) + #+sb-simd-pack-256 + (simd-pack-256-single + (%make-simd-pack-256-single + (sap-ref-single sap 0) + (sap-ref-single sap 4) + (sap-ref-single sap 8) + (sap-ref-single sap 12) + (sap-ref-single sap 16) + (sap-ref-single sap 20) + (sap-ref-single sap 24) + (sap-ref-single sap 28))) + #+sb-simd-pack-256 + (simd-pack-256-double + (%make-simd-pack-256-double + (sap-ref-double sap 0) + (sap-ref-double sap 8) + (sap-ref-double sap 16) + (sap-ref-double sap 24)))))) (defun %set-context-float-register (context index format value) (declare (ignorable context index format)) @@ -120,7 +105,49 @@ (locally (declare (type (complex double-float) value)) (setf (sap-ref-double sap 0) (realpart value) - (sap-ref-double sap 8) (imagpart value))))))) + (sap-ref-double sap 8) (imagpart value)))) + #+sb-simd-pack + (simd-pack-int + (multiple-value-bind (a b) (%simd-pack-ub64s value) + (setf (sap-ref-64 sap 0) a + (sap-ref-64 sap 8) b))) + #+sb-simd-pack + (simd-pack-single + (multiple-value-bind (a b c d) (%simd-pack-singles value) + (setf (sap-ref-single sap 0) a + (sap-ref-single sap 4) b + (sap-ref-single sap 8) c + (sap-ref-single sap 12) d))) + #+sb-simd-pack + (simd-pack-double + (multiple-value-bind (a b) (%simd-pack-doubles value) + (setf (sap-ref-double sap 0) a + (sap-ref-double sap 8) b))) + #+sb-simd-pack-256 + (simd-pack-256-int + (multiple-value-bind (a b c d) (%simd-pack-256-ub64s value) + (setf (sap-ref-64 sap 0) a + (sap-ref-64 sap 8) b + (sap-ref-64 sap 16) c + (sap-ref-64 sap 24) d))) + #+sb-simd-pack-256 + (simd-pack-256-single + (multiple-value-bind (a b c d e f g h) (%simd-pack-256-singles value) + (setf (sap-ref-single sap 0) a + (sap-ref-single sap 4) b + (sap-ref-single sap 8) c + (sap-ref-single sap 12) d + (sap-ref-single sap 16) e + (sap-ref-single sap 20) f + (sap-ref-single sap 24) g + (sap-ref-single sap 28) h))) + #+sb-simd-pack-256 + (simd-pack-256-double + (multiple-value-bind (a b c d) (%simd-pack-256-doubles value) + (setf (sap-ref-double sap 0) a + (sap-ref-double sap 8) b + (sap-ref-double sap 16) c + (sap-ref-double sap 24) d)))))) ;;; Given a signal context, return the floating point modes word in ;;; the same format as returned by FLOATING-POINT-MODES. @@ -163,45 +190,53 @@ (let* ((data (sap-ref-8 pc 1)) ; encodes dst register and size (value (sb-vm:context-register context (ash data -2))) (nbytes (ash 1 (logand data #b11))) - ;; EMIT-SAP-REF always loads the EA into TEMP-REG-TN - ;; which points to the shadow, not the user memory now. - (ea (logxor (sb-vm:context-register - context (tn-offset sb-vm::temp-reg-tn)) + ;; EMIT-SAP-REF wires the EA to a predetermined register, + ;; which now points to the shadow space, not the user memory. + (ea (logxor (sb-vm:context-register context msan-temp-reg-number) msan-mem-to-shadow-xor-const))) `(:raw ,ea ,nbytes ,value))))) (t (sb-kernel::decode-internal-error-args (sap+ pc 1) trap-number))))) +(defun write-funinstance-prologue (fin) + ;; Encode: MOV RAX,[RIP+9] / JMP [RAX-3] / NOP / MOV EBX, #x0 + ;; and the #x0 is replaced with a hash code. + (declare (ignorable fin)) + #-immobile-space (return-from write-funinstance-prologue) + (with-pinned-objects (fin) + (let* ((sap (sap+ (int-sap (get-lisp-obj-address fin)) + (- (ash 2 word-shift) fun-pointer-lowtag)))) + ;; Scavenging these words when you shouldn't is actually harmless + ;; because by a stroke of luck, they all look fixnum-tagged. + (setf (sap-ref-sap sap -8) sap + (sap-ref-word sap 0) #xFF00000009058B48 + (sap-ref-word sap 8) #x00000000BB90FD60))) + (update-dynamic-space-code-tree fin) + fin) + +#+immobile-space +(defun alloc-immobile-fdefn () + (alloc-immobile-fixedobj fdefn-size + (logior (ash undefined-fdefn-header 16) + fdefn-widetag))) ; word 0 + #+immobile-code (progn (defconstant trampoline-entry-offset n-word-bytes) (defun make-simplifying-trampoline (fun) - (let ((code (truly-the (values code-component &optional) - (allocate-code-object :dynamic 0 3 24)))) ; KLUDGE + ;; 'alloc' is compiled after this file so we don't see the derived type. + ;; But slam found a conflict on recompile. + (let ((code (truly-the (values code-component (integer 0) &optional) + (allocate-code-object :dynamic 3 24)))) ; KLUDGE (setf (%code-debug-info code) fun) - (let ((sap (sap+ (code-instructions code) trampoline-entry-offset)) - (ea (+ (logandc2 (get-lisp-obj-address code) lowtag-mask) - (ash code-debug-info-slot word-shift)))) - ;; For a funcallable-instance, the instruction sequence is: - ;; MOV RAX, [RIP-n] ; load the function - ;; MOV RAX, [RAX+5] ; load the funcallable-instance-fun - ;; JMP [RAX-3] - ;; Otherwise just instructions 1 and 3 will do. - ;; We could use the #xA1 opcode to save a byte, but that would - ;; be another headache do deal with when relocating this code. - ;; There's precedent for this style of hand-assembly, - ;; in arch_write_linkage_table_entry() and arch_do_displaced_inst(). - (setf (sap-ref-32 sap 0) #x058B48 ; REX MOV [RIP-n] - (signed-sap-ref-32 sap 3) (- ea (+ (sap-int sap) 7))) ; disp - (let ((i (if (/= (fun-subtype fun) funcallable-instance-widetag) - 7 - (let ((disp8 (- (ash funcallable-instance-function-slot - word-shift) - fun-pointer-lowtag))) ; = 5 - (setf (sap-ref-32 sap 7) (logior (ash disp8 24) #x408B48)) - 11)))) - (setf (sap-ref-32 sap i) #xFD60FF))) ; JMP [RAX-3] + (with-pinned-objects (code) + (let ((sap (sap+ (code-instructions code) trampoline-entry-offset)) + (ea (+ (logandc2 (get-lisp-obj-address code) lowtag-mask) + (ash code-debug-info-slot word-shift)))) + (setf (sap-ref-32 sap 0) #x058B48 ; REX MOV [RIP-n] + (signed-sap-ref-32 sap 3) (- ea (+ (sap-int sap) 7)); disp + (sap-ref-32 sap 7) #xFD60FF))) ; JMP [RAX-3] ;; Verify that the jump table size reads as 0. (aver (zerop (code-jump-table-words code))) ;; It is critical that there be a trailing 'uint16' of 0 in this object @@ -211,87 +246,6 @@ (aver (zerop (code-n-entries code))) code)) -;;; Return T if FUN can't be called without loading RAX with its descriptor. -;;; This is true of any funcallable instance which is not a GF, and closures. -(defun fun-requires-simplifying-trampoline-p (fun) - (let ((kind (fun-subtype fun))) - (or (and (eql kind sb-vm:funcallable-instance-widetag) - ;; if the FIN has no raw words then it has no internal trampoline - (eql (layout-bitmap (%fun-layout fun)) - sb-kernel:+layout-all-tagged+)) - (eql kind sb-vm:closure-widetag)))) - -(defconstant sb-pcl::+machine-code-embedding-fsc-instance-bitmap+ - (logxor (1- (ash 1 funcallable-instance-info-offset)) - (ash 1 (1- funcallable-instance-trampoline-slot)))) - -;;; This allocator is in its own function because the immobile allocator -;;; VOPs are impolite (i.e. bad) and trash all registers. -;;; Since there are no callee-saved registers, this makes it legit' -;;; to put in a separate function. -#+immobile-code -(defun alloc-immobile-funinstance () - (values (%primitive alloc-immobile-fixedobj fun-pointer-lowtag 6 ; kludge - (logior (ash 5 n-widetag-bits) funcallable-instance-widetag)))) - -;; TODO: put a trampoline in all fins and allocate them anywhere. -;; Revision e7cd2bd40f5b9988 caused some FINs to go in dynamic space -;; which is fine, but those fins need to have a default bitmap of -1 instead -;; of a special bitmap because we examine the bitmap when deciding whether -;; the FIN can be installed into an FDEFN without needing an external trampoline. -;; The easiest way to achieve this intent is to default all bitmaps to -1, -;; then change it in the layout when writing raw words. A better fix would -;; try to allocate all FINs in immobile space until it is exhausted, then fallback -;; to dynamic space. The address of the fin is no longer an issue, since fdefns -;; can point to the entire address space, but the fixed-size immobile object -;; allocator doesn't returns 0 - it calls the monitor if it fails. - -;; So ideally, all funcallable instances would resemble simple-funs for a -;; small added cost of 2 words per object. It will be necessary to have the GC -;; treat ambiguous interior pointers to the unboxed words in the same way as -;; any code pointer. Placing FINs on pages marked as containing code will allow -;; the conservative root check to be skipped for obviously non-code objects. - -;; Also we will need to write the embedded trampoline either in a word index -;; that differs based on length of the FIN, or place the boxed slots after -;; the trampoline. As of now, this can only deal with standard GFs. -;; The primitive object has 2 descriptor slots (fin-fun and CLOS slot vector) -;; and 2 non-descriptor slots containing machine instructions, after the -;; self-pointer (trampoline) slot. Scavenging the self-pointer is unnecessary -;; though harmless. This intricate and/or obfuscated calculation of #b110 -;; is insensitive to the index of the trampoline slot, probably. -#+immobile-code -(defun make-immobile-funinstance (layout slot-vector) - (let ((gf (truly-the funcallable-instance (alloc-immobile-funinstance)))) - ;; Assert that raw bytes will not cause GC invariant lossage - (aver (/= (layout-bitmap layout) +layout-all-tagged+)) - ;; Set layout prior to writing raw slots - (setf (%fun-layout gf) layout) - ;; just being pedantic - liveness is preserved by the stack reference. - (with-pinned-objects (gf) - (let* ((addr (logandc2 (get-lisp-obj-address gf) lowtag-mask)) - (sap (int-sap addr)) - (insts-offs (ash (1+ funcallable-instance-info-offset) word-shift))) - (setf (sap-ref-word sap (ash funcallable-instance-trampoline-slot word-shift)) - (truly-the word (+ addr insts-offs)) - (sap-ref-word sap insts-offs) #xFFFFFFE9058B48 ; MOV RAX,[RIP-23] - (sap-ref-32 sap (+ insts-offs 7)) #x00FD60FF))) ; JMP [RAX-3] - (%set-funcallable-instance-info gf 0 slot-vector) - gf)) - -#+immobile-space -(defun alloc-immobile-fdefn () - (or #+nil ; Avoid creating new objects in the text segment for now - (and (= (alien-funcall (extern-alien "lisp_code_in_elf" (function int))) 1) - (allocate-immobile-obj (* fdefn-size n-word-bytes) - (logior (ash undefined-fdefn-header 16) - fdefn-widetag) ; word 0 - 0 other-pointer-lowtag nil)) ; word 1, lowtag, errorp - (values (%primitive alloc-immobile-fixedobj other-pointer-lowtag - fdefn-size - (logior (ash undefined-fdefn-header 16) - fdefn-widetag))))) ; word 0 - (defun fdefn-has-static-callers (fdefn) (declare (type fdefn fdefn)) (with-pinned-objects (fdefn) @@ -310,7 +264,7 @@ (values function)) (when (fdefn-has-static-callers fdefn) (remove-static-links fdefn)) - (let ((trampoline (when (fun-requires-simplifying-trampoline-p fun) + (let ((trampoline (when (closurep fun) (make-simplifying-trampoline fun)))) ; a newly made CODE object (with-pinned-objects (fdefn trampoline fun) (let* ((jmp-target @@ -323,7 +277,7 @@ ;; But the result is shifted by N-FIXNUM-TAG-BITS because ;; CELL-REF yields a descriptor-reg, not an unsigned-reg. (get-lisp-obj-address (%closure-callee fun))))) - (%primitive set-fdefn-fun fdefn fun jmp-target)))) + (%primitive sb-vm::set-direct-callable-fdefn-fun fdefn fun jmp-target)))) fun) ) ; end PROGN @@ -379,23 +333,26 @@ (return (loop (cond ((>= (incf i) len) (return t)) ((eq thing (svref things i)) (return nil)))))))) -;;; Allocate a code object. -(defun alloc-dynamic-space-code (total-words) - (values (%primitive alloc-dynamic-space-code (the fixnum total-words)))) +(define-load-time-global *static-linker-lock* (sb-thread:make-mutex :name "static linker")) -;;; Remove calls via fdefns from CODE when compiling into memory. -(defun statically-link-code-obj (code fixups) - (declare (ignorable code fixups)) - (unless (immobile-space-obj-p code) - (return-from statically-link-code-obj code)) +(define-load-time-global *never-statically-link* '(find-package)) +;;; Remove calls via fdefns from CODE. This is called after compiling +;;; to memory, or when saving a core. +;;; Do not replace globally notinline functions, because notinline has +;;; an extra connotation of ensuring that replacement of the function +;;; under that name always works. It usually works to replace a statically +;;; linked function, but with a caveat: un-statically-linking requires calling +;;; MAP-OBJECTS-IN-RANGE, which is unreliable in the presence of +;;; multiple threads. Unfortunately, some users dangerously redefine +;;; builtin functions, and moreover, while there are multiple threads. +(defun statically-link-code-obj (code fixups &optional observable-fdefns) + (declare (ignorable code fixups observable-fdefns)) #+immobile-code - (let* ((fdefns-start (+ code-constants-offset - (* code-slots-per-simple-fun (code-n-entries code)))) - (fdefns-count (code-n-named-calls code)) - (replacements (make-array fdefns-count :initial-element nil)) - (ambiguous (make-array fdefns-count :initial-element 0 :element-type 'bit)) - (any-replacements) - (any-ambiguous)) + (binding* (((fdefns-start fdefns-count) (code-header-fdefn-range code)) + (replacements (make-array fdefns-count :initial-element nil)) + (ambiguous (make-array fdefns-count :initial-element 0 :element-type 'bit)) + (any-replacements nil) + (any-ambiguous nil)) ;; For each fdefn, decide two things: ;; * whether the fdefn can be replaced by its function - possible only when ;; that function is in immobile space and needs no trampoline. @@ -406,7 +363,9 @@ (let* ((fdefn (code-header-ref code (+ fdefns-start i))) (fun (when (fdefn-p fdefn) (fdefn-fun fdefn)))) (when (and (immobile-space-obj-p fun) - (not (fun-requires-simplifying-trampoline-p fun))) + (not (closurep fun)) + (not (member (fdefn-name fdefn) *never-statically-link* :test 'equal)) + (neq (info :function :inlinep (fdefn-name fdefn)) 'notinline)) (setf any-replacements t (aref replacements i) fun)))) (dotimes (i fdefns-count) (when (and (aref replacements i) @@ -439,13 +398,13 @@ (setf (aref replacements fdefn-index) nil)))) (let ((stored-locs (if any-ambiguous (make-array fdefns-count :initial-element nil)))) - (sb-thread::with-system-mutex (sb-c::*static-linker-lock*) + (with-system-mutex (*static-linker-lock*) (dolist (fixup fixups) (binding* ((fdefn-index (car fixup) :exit-if-null) (offset (cdr fixup)) (fdefn (code-header-ref code (+ fdefns-start fdefn-index))) (fun (aref replacements fdefn-index))) - (when fun + (when (and fun (/= (bit ambiguous fdefn-index) 1)) ;; Set the statically-linked flag (sb-vm::set-fdefn-has-static-callers fdefn 1) (when (= (bit ambiguous fdefn-index) 1) @@ -457,6 +416,7 @@ (setf (signed-sap-ref-32 insts offset) (sap- entry (sap+ insts (+ offset 4)))))))) ;; Replace ambiguous elements of the code header while still holding the lock + #+statically-link-if-ambiguous ; never enabled (dotimes (i fdefns-count) (when (= (bit ambiguous i) 1) (let ((wordindex (+ fdefns-start i)) @@ -464,3 +424,16 @@ (setf (code-header-ref code wordindex) (cons (code-header-ref code wordindex) locs))))))))) code) + +(sb-c::when-vop-existsp (:translate sb-c::unsigned+) + (defconstant cf-bit 0) + (defconstant sf-bit 7) + (defconstant of-bit 11) + + (defun context-overflow-carry-flags (context) + (let ((flags (context-flags context))) + (values (logbitp of-bit flags) + (logbitp cf-bit flags))))) + +(def-cpu-feature :avx2 + (plusp (sb-alien:extern-alien "avx2_supported" int))) diff --git a/src/code/x86-vm.lisp b/src/code/x86-vm.lisp index 3afbd63751..240290d881 100644 --- a/src/code/x86-vm.lisp +++ b/src/code/x86-vm.lisp @@ -14,47 +14,7 @@ (defun machine-type () "Return a string describing the type of the local machine." "X86") - -;;;; :CODE-OBJECT fixups -;;; This gets called by LOAD to resolve newly positioned objects -;;; with things (like code instructions) that have to refer to them. -;;; Return T if and only if the fixup needs to be recorded in %CODE-FIXUPS -(defun fixup-code-object (code offset fixup kind flavor) - (declare (type index offset)) - (declare (ignorable flavor)) - (let* ((obj-start-addr (logandc2 (get-lisp-obj-address code) sb-vm:lowtag-mask)) - (sap (code-instructions code)) - (code-end-addr (+ (sap-int sap) (%code-code-size code)))) - (ecase kind - (:absolute - ;; Word at sap + offset contains a value to be replaced by - ;; adding that value to fixup. - (let ((final-val (+ fixup (sap-ref-32 sap offset)))) - (setf (sap-ref-32 sap offset) final-val) - ;; Record absolute fixups that point into CODE itself, with one - ;; exception: fixups within the range of unboxed words containing - ;; jump tables are automatically adjusted if the code moves. - (let ((n-jump-table-words - (the (unsigned-byte 16) - (get-lisp-obj-address - (code-header-ref code (code-header-words code)))))) - (and (< obj-start-addr final-val code-end-addr) - (>= offset (ash n-jump-table-words word-shift)))))) - (:relative - ;; Fixup is the actual address wanted. - ;; Replace word with value to add to that loc to get there. - (let* ((loc-sap (+ (sap-int sap) offset)) - ;; Use modular arithmetic so that if the offset - ;; doesn't fit into signed-byte-32 it'll wrap around - ;; when added to EIP - (rel-val (ldb (byte 32 0) (- fixup loc-sap n-word-bytes)))) - (declare (type (unsigned-byte 32) loc-sap rel-val)) - (setf (sap-ref-32 sap offset) rel-val)) - ;; Relative fixups point outside of this object. Keep them all. - (aver (or (< fixup obj-start-addr) (> fixup code-end-addr))) - t)))) - ;;;; low-level signal context access functions ;;;; ;;;; Note: In CMU CL, similar functions were hardwired to access diff --git a/src/code/xset.lisp b/src/code/xset.lisp index 99de7b4928..0629a13974 100644 --- a/src/code/xset.lisp +++ b/src/code/xset.lisp @@ -89,9 +89,11 @@ (defun xset-member-p (elt xset) (let ((data (xset-data xset))) - (if (listp data) - (member elt data :test #'eql) - (gethash elt data)))) + (if (if (listp data) + (member elt data :test #'eql) + (gethash elt data)) + t + nil))) (defun xset-members (xset) (let ((data (xset-data xset))) @@ -135,6 +137,21 @@ xset1)) t)) -#-sb-fluid (declaim (inline xset-empty-p)) +(defun xset= (xset1 xset2) + (declare (inline subsetp)) + (when (= (xset-count xset1) (xset-count xset2)) + (let ((data1 (xset-data xset1)) + (data2 (xset-data xset2))) + (if (listp data1) + (return-from xset= (subsetp data1 data2)) + (maphash + (lambda (k v) + (declare (ignore v)) + (unless (gethash k data2) + (return-from xset= nil))) + data1))) + t)) + +(declaim (inline xset-empty-p)) (defun xset-empty-p (xset) (not (xset-data xset))) diff --git a/base-target-features.lisp-expr b/src/cold/base-target-features.lisp-expr similarity index 89% rename from base-target-features.lisp-expr rename to src/cold/base-target-features.lisp-expr index 74b887f66b..2fab7ac39c 100644 --- a/base-target-features.lisp-expr +++ b/src/cold/base-target-features.lisp-expr @@ -51,12 +51,6 @@ ;; our dialect :sbcl - ;; Douglas Thomas Crosher's conservative generational GC (the only one - ;; we currently support for X86). - ;; :gencgc used to be here; CSR moved it into - ;; local-target-features.lisp-expr via make-config.sh, as alpha, - ;; sparc and ppc ports don't currently support it. -- CSR, 2002-02-21 - ;; ;; features present in this particular build ;; @@ -116,20 +110,11 @@ ; :sb-show-assem ;; Compile the C runtime with support for low-level debugging output - ;; through FSHOW and FSHOW_SIGNAL. If enabled, this feature allows + ;; through FSHOW. If enabled, this feature allows ;; users to turn on such debugging output using environment variables at ;; run-time. ; :sb-qshow - ;; Setting this makes SBCL more "fluid", i.e. more amenable to - ;; modification at runtime, by suppressing various INLINE declarations, - ;; compiler macro definitions, FREEZE-TYPE declarations; and by - ;; suppressing various burning-our-ships-behind-us actions after - ;; initialization is complete; and so forth. This tends to clobber the - ;; performance of the system, so unless you have some special need for - ;; this when hacking SBCL itself, you don't want this set. - ; :sb-fluid - ;; Enable code for collecting statistics on usage of various operations, ;; useful for performance tuning of the SBCL system itself. This code ;; is probably pretty stale (having not been tested since the fork from @@ -214,12 +199,6 @@ ;; ; :sb-futex - ;; On some operating systems the FS segment register (used for SBCL's - ;; thread local storage) is not reliably preserved in signal - ;; handlers, so we need to restore its value from the pthread thread - ;; local storage. - ; :restore-fs-segment-register-from-tls - ;; Support for detection of unportable code (when applied to the ;; COMMON-LISP package, or SBCL-internal pacakges) or bad-neighbourly ;; code (when applied to user-level packages), relating to material @@ -255,6 +234,14 @@ ;; This doesn't affect the build at all, merely declares how things are. :package-local-nicknames + ;; CLHS says that *LOAD-TRUENAME* has to be bound whenever *LOAD-PATHNAME* is, + ;; because obviously the spec wanted to mandate that one system call turn into + ;; an unlimited number. At least you're correct in saying + ;; "it's not my code, it's the OS that's slow." + ;; Remove this feature if you want to ignore the technical requirement + ;; that *LOAD-TRUENAME* be a variable (as opposed to a symbol-macro). + :ansi-compliant-load-truename + ;; This is set in classic CMU CL, and presumably there it means ;; that the floating point arithmetic implementation ;; conforms to IEEE's standard. Here it definitely means that the @@ -290,9 +277,9 @@ ;; foreign code that uses a 32-bit off_t. ; :largefile - ;; SBCL has optional support for zlib-based compressed core files. Enable + ;; SBCL has optional support for zstd-based compressed core files. Enable ;; this feature to compile it in. Obviously, doing so adds a dependency - ;; on zlib. + ;; on zstd. ; :sb-core-compression ;; On certain thread-enabled platforms, synchronization between threads @@ -302,19 +289,6 @@ ;; (Replaces use of SIG_STOP_FOR_GC.) ; :sb-safepoint - ;; When compiling with safepoints, the INTERRUPT-THREAD mechanism can - ;; also use safepoints to roll the target thread to a point at which it - ;; can be interrupted safely, instead of using a signal for this - ;; purpose. Enable this feature in addition to :SB-SAFEPOINT to enable - ;; such behaviour. - ;; (Replaces use of SIGPIPE, except to wake up syscalls.) - ; :sb-thruption - - ;; When compiling with safepoints and thruptions, the TIMER facility - ;; can replace its use of setitimer with a background thread. - ;; (Replaces use of SIGALRM.) - ; :sb-wtimer - ;; ;; miscellaneous notes on other things which could have special significance ;; in the *FEATURES* list @@ -358,16 +332,12 @@ ;; any Intel 386 or better, or compatibles like the AMD K6 or K7 ;; :x86-64 ;; any x86-64 CPU running in 64-bit mode - ;; :alpha - ;; DEC/Compaq Alpha CPU ;; :sparc ;; any Sun UltraSPARC (possibly also non-Ultras -- currently untested) ;; :ppc ;; any PowerPC CPU ;; :ppc64 ;; 64-bit PowerPC CPU, ISA 2.06 (POWER7) or later - ;; :hppa - ;; any PA-RISC CPU ;; :mips ;; any MIPS CPU (in little-endian mode with :little-endian) ;; :arm @@ -401,9 +371,6 @@ ;; just parameterized by #+X86, but it'd probably be better to ;; use new flags like :CONTROL-STACK-CONTAINS-C-STACK. ;; - ;; :stack-allocatable-closures - ;; The compiler can allocate dynamic-extent closures on stack. - ;; ;; :alien-callbacks ;; Alien callbacks have been implemented for this platform. ;; @@ -425,6 +392,5 @@ ;; :darwin = We're intended to run under Darwin (including MacOS X). ;; :sunos = We're intended to run under Solaris user environment ;; with the SunOS kernel. - ;; :hpux = We're intended to run under HP-UX 11.11 or later ;; :win32 = We're intended to under some version of Microsoft Windows. ) diff --git a/build-order.lisp-expr b/src/cold/build-order.lisp-expr similarity index 68% rename from build-order.lisp-expr rename to src/cold/build-order.lisp-expr index 695ce478cc..b84ef11747 100644 --- a/build-order.lisp-expr +++ b/src/cold/build-order.lisp-expr @@ -40,9 +40,7 @@ ( ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; miscellaneous - ;; This comes as early as possible, so that we catch the source locations - ;; for everything. - ("src/code/early-source-location" :c-headers) + ("src/code/cross-early" :c-headers :not-target) ;; This comes early because it's useful for debugging everywhere. @@ -50,14 +48,14 @@ ("src/compiler/early-constantp" :c-headers) ("src/code/defsetfs" :not-host) - ;; Declare all target special variables defined by ANSI + ;; Declare all target special variables defined by ANSI ("src/code/cl-specials" :not-host) ;; Things like DX-FLET and AWHEN are available for use in both the ;; host and target very early. ("src/code/primordial-extensions" :c-headers) ("src/code/cold-init-helper-macros" :c-headers) - ("src/code/early-defmethod" :not-host) + ("src/code/initial-method" :not-host) ;; ASAP we replace the host's backquote reader with our own, to avoid leaking ;; details of the host into the target. This is not a concern in make-host-2 @@ -101,20 +99,18 @@ ("src/code/defbangtype" :c-headers) ("src/code/early-constants" :c-headers) - ("src/compiler/deftype" :c-headers) ; on host for SB-XC:DEFTYPE - ("src/compiler/early-lexenv" :c-headers) - ("src/compiler/early-globaldb" :c-headers) + ("src/compiler/vop-existsp" :c-headers) ;; comes early so that stuff can reason about function names ("src/code/function-names" :c-headers) + ("src/compiler/early-globaldb" :c-headers) ;; for various constants e.g. SB-XC:MOST-POSITIVE-FIXNUM and - ;; SB-VM:N-LOWTAG-BITS, needed by "early-objdef" and others + ;; SB-VM:N-LOWTAG-BITS, needed by "early-objdef" and others. ("src/compiler/generic/parms" :c-headers) - ("src/compiler/target/parms" :c-headers) + ("src/compiler/{arch}/parms" :c-headers) ("src/compiler/generic/early-vm" :c-headers) ("src/compiler/generic/early-objdef" :c-headers) - ("src/code/early-array" :c-headers) ; needs "early-vm" numbers ;; This has the BARRIER stuff that the threading support needs, ;; required for some code in 'early-extensions' @@ -122,35 +118,24 @@ ("src/code/parse-body" :c-headers) ; on host for PARSE-BODY ("src/compiler/policy" :c-headers) #+sb-fasteval ("src/interpreter/basic-env") - ;; PARSE-{UNKNOWN,DEPRECATED}-TYPE and other things should be known - ;; condition subtypes as soon as possible - ("src/code/condition-boot" :not-host) - ("src/code/early-extensions" :c-headers) ; on host for COLLECT, SYMBOLICATE, etc. - ("src/compiler/parse-lambda-list" :c-headers) - ("src/code/restart" :not-host) ; %DEFCONSTANT can bind a restart - ("src/code/early-cl") - ("src/code/ansi-stream" :not-host) - ("src/code/early-fasl" :c-headers) + ("src/code/early-extensions" :c-headers) ; on host for COLLECT, SYMBOLICATE, etc. ("src/code/defbangstruct" :c-headers :not-target) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; basic machinery for the target Lisp. Note that although most of these ;;; files are flagged :NOT-HOST, a few might not be. - ("src/code/early-print" :not-host) + ("src/code/ansi-stream" :not-host) + ("src/code/restart" :not-host) ("src/code/early-pprint" :not-host) ("src/code/early-impl" :not-host) - ("src/code/target-extensions" :not-host) - ;; Needed before the first use of WITH-SINGLE-PACKAGE-LOCKED-ERROR. ("src/code/early-package" :not-host) ("src/code/early-raw-slots" :c-headers) - ("src/code/funutils" :not-host) - ("src/code/maphash" :not-host) ("src/code/xset" :c-headers) ; for representation of MEMBER type ;; This needs DEF!STRUCT, and is itself needed early so that structure @@ -159,145 +144,75 @@ ("src/code/type-class" :c-headers) ("src/code/cas" :not-host) + ("src/code/thread-structs" :c-headers #-sb-devel :block-compile) ; some defstructs for genesis ("src/compiler/early-c" :c-headers) - ("src/compiler/fun-info" :c-headers) - ("src/pcl/slot-name") ; for calls from 'info-vector' - ;; 'info-vector' is needed at least as early as 'fdefinition' so that the - ;; inlined INFO-VECTOR-FDEFINITION is available to %COERCE-CALLABLE-TO-FUN. - ("src/code/signal" :not-host) + ("src/pcl/slot-name") + ("src/code/sysmacs" :not-host) - ("src/code/target-lfhash" :not-host) - ("src/compiler/info-vector" :c-headers) - ("src/compiler/globaldb" :c-headers) - ("src/compiler/generic/vm-array" :c-headers) - ("src/code/string-hash" :c-headers) - ("src/code/primordial-type" :c-headers) ("src/code/early-classoid" :c-headers) - ("src/code/early-alieneval" :c-headers) ; for funs and vars needed at build and run time - ("src/code/target-error" :not-host) - ;; "src/code/toplevel.lisp" is the first to need this. It's generated - ;; automatically by grovel_headers.c, i.e. it's not under source control. - ("output/stuff-groveled-from-headers" :not-host) + ("src/compiler/generic/pinned-objects" :not-host) + ("src/compiler/generic/layout-ids" :c-headers) + ("src/code/signal" :not-host) ("src/code/cold-error" :not-host) ;; Define at most one INTERPRETED-FUNCTION type based on target features #+sb-eval ("src/code/early-full-eval" :not-host) #+sb-fasteval ("src/interpreter/function" :not-host) - ("src/code/fdefinition" :not-host) - ("src/code/weak" :not-host) - ;; 'target-alieneval' needs FILL-POINTER which is defined in 'array' - ("src/code/array" :not-host) ; needs WEAK-POINTER-VALUE ("src/code/debug-var-io") - ("src/code/target-alieneval" :not-host) - ("src/code/target-c-call" :not-host) - ("src/code/target-allocate" :not-host) - - ;; This needs DEFINE-ALIEN-ROUTINE from target-alieneval. - ("src/code/misc-aliens" :not-host) - ("src/code/early-float") - ("src/code/pred" :not-host) - ("src/compiler/generic/pinned-objects" :not-host) - - ("src/code/list" :not-host) - ("src/code/seq" :not-host) ; "code/seq" should come after "code/list". - ("src/code/coerce" :not-host) ("src/code/huffman") - ("src/code/target-char" :not-host) - ("src/code/target-unicode" :not-host) - ("src/code/string" :not-host) - ("src/code/mipsstrops" :not-host) + ;; 32-bit implementation of GET-INTERNAL-REAL-TIME needs some thread slots ("src/code/early-time" :c-headers) - ("src/code/unix" :not-host) - #+win32 ("src/code/win32" :not-host) - - #+android ("src/code/android-os" :not-host) - #+sunos ("src/code/sunos-os" :not-host) - #+hpux ("src/code/hpux-os" :not-host) - #+bsd ("src/code/bsd-os" :not-host) - #+linux ("src/code/linux-os" :not-host) - #+haiku ("src/code/haiku-os" :not-host) - #+win32 ("src/code/win32-os" :not-host) - - ("src/code/share-vm" :not-host) - - ("src/code/thread" :not-host :block-compile) ; provides *CURRENT-THREAD* for target-signal - ("src/code/target-signal-common" :not-host) - - ("src/code/bignum" :not-host) - ("src/code/numbers" :not-host) - ("src/code/float-trap" :not-host) - ("src/code/float" :not-host) - ("src/code/irrat" :not-host) ("src/code/misc" :c-headers) - - ("src/code/symbol" :not-host) - ("src/code/late-cas" :not-host) - ("src/code/fd-stream" :not-host) - ("src/code/stream" :not-host) - ("src/code/early-format") - - ("src/code/common-os" :not-host) - - ("src/code/deadline" :not-host) - ("src/code/serve-event" :not-host) - - ("src/code/query" :not-host) - - ("src/code/sort" :not-host) - ("src/code/time" :not-host) + ("src/code/target-error" :not-host) + ("src/code/target-extensions" :not-host) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; compiler (and a few miscellaneous files whose dependencies make it ;;; convenient to stick them here) + ("src/compiler/parse-lambda-list" :c-headers) + ("src/compiler/macros" :c-headers) + ("src/compiler/fun-info" :c-headers) + ("src/compiler/generic/vm-macs" :c-headers) ("src/compiler/policies") - ("src/compiler/macros" :c-headers) + ("src/code/target-lfhash" :not-host) + ("src/compiler/info-vector" :c-headers) + ("src/compiler/globaldb" :c-headers) + ("src/compiler/generic/objdef" :c-headers) - ("src/compiler/constantp" :c-headers) - ("src/compiler/info-functions" :c-headers) + ("src/compiler/generic/vm-array" :c-headers) + ("src/code/string-hash" :c-headers) + ("src/code/primordial-type" :c-headers) ("src/code/specializable-array" :not-target) - ("src/compiler/generic/vm-macs" :c-headers) - ("src/compiler/generic/objdef" :c-headers) - - ;; needed by "compiler/vop" ("src/compiler/sset" :c-headers) - ("src/code/early-type" :c-headers) - ;; sparc-vm and ppc-vm need sc+offset defined to get at internal - ;; error args. This file contains stuff previously in - ;; debug-info.lisp. Should it therefore be :not-host? -- CSR, - ;; 2002-02-05 - ("src/code/sc-offset" :c-headers) - ;; for e.g. BLOCK-ANNOTATION, needed by "compiler/vop" ("src/compiler/node" :c-headers :block-compile) - ;; RECONSTRUCT-LEXENV needs types GLOBAL-VAR and DEFINED-FUN - ("src/compiler/lexenv") - ;; This has ASSEMBLY-UNIT-related stuff needed by core.lisp. ;; and LABEL, needed by IR2-NLX-INFO ("src/compiler/early-assem") - ;; for e.g. PRIMITIVE-TYPE, needed by "vmdef" ("src/compiler/vop" :c-headers :block-compile) - - ;; needed by "vm" and "primtype" ("src/compiler/backend" :c-headers) + ;; sparc-vm and ppc-vm need sc+offset defined to get at internal + ;; error args. This file contains stuff previously in + ;; debug-info.lisp. Should it therefore be :not-host? -- CSR, + ;; 2002-02-05 + ("src/code/sc-offset" :c-headers) + ;; for e.g. MAX-VOP-TN-REFS, needed by "meta-vmdef" ("src/compiler/vmdef" :c-headers) ("src/code/defmacro" :c-headers) - ("src/code/destructuring-bind" :c-headers) - ;; for e.g. !DEF-PRIMITIVE-TYPE, needed by primtype.lisp, and ;; DEFINE-STORAGE-CLASS, needed by target/vm.lisp ("src/compiler/meta-vmdef" :c-headers) @@ -306,21 +221,25 @@ ("src/compiler/generic/core") ; for CORE-OBJECT-P, needed by x86-64/vm ;; for e.g. DESCRIPTOR-REG, needed by primtype.lisp - ("src/compiler/target/vm" :c-headers) + ("src/compiler/{arch}/vm" :c-headers) - ;; KLUDGE: I'd prefer to have this done with a "code/target" softlink - ;; instead of a bunch of reader macros. -- WHN 19990308 - #+sparc ("src/code/sparc-vm") - #+hppa ("src/code/hppa-vm") - #+x86 ("src/code/x86-vm" :not-host) - #+x86-64("src/code/x86-64-vm" :not-host) - #+(or ppc ppc64) - ("src/code/ppc-vm") - #+alpha ("src/code/alpha-vm") - #+mips ("src/code/mips-vm") - #+arm ("src/code/arm-vm") - #+arm64 ("src/code/arm64-vm") - #+riscv ("src/code/riscv-vm") + ("src/code/alieneval" :c-headers) + ;; This is generated automatically by grovel_headers.c, i.e. it's not + ;; under source control. + ("output/stuff-groveled-from-headers" :not-host) + ("src/code/target-alieneval" :not-host) + ("src/code/target-c-call" :not-host) + + ("src/code/weak" :not-host) + ("src/code/array" :not-host) + + ("src/code/list" :not-host) + ("src/code/seq" :not-host) ; "code/seq" should come after "code/list". + ("src/code/coerce" :not-host) + + ;; This needs DEFINE-ALIEN-ROUTINE from target-alieneval. + ("src/code/misc-aliens" :not-host) + ("src/code/thread" :not-host #-sb-devel :block-compile) ; provides *CURRENT-THREAD* for target-signal ;; RANDOM-LAYOUT-CLOS-HASH (in 'class') uses RANDOM, the transform for which ;; uses GENERATE-RANDOM-EXPR-FOR-POWER-OF-2 which becomes BIG-RANDOM-CHUNK, @@ -333,80 +252,51 @@ ;; around the compilation of "code/class". Why? ("src/code/class" :c-headers) ("src/pcl/pre-warm") + ("src/code/number-dispatch" :not-host) + ("src/code/float-inf-nan" :not-host) + ("src/code/pathname" :not-host) ("src/code/target-sxhash" :not-host) ; needs most-fooative-foo-float constants - ("src/code/debug-info" :c-headers - #.(cl:if (and (cl:find :sb-xc-host cl:*features*) - (cl:find :cmucl cl:*features*)) ; gets fatal warnings in CMUCL 20c - :ignore-failure-p)) + ("src/code/debug-info" :c-headers) ("src/code/source-location") - ("src/code/early-class") - ("src/code/condition" :not-host) - #-win32 ("src/code/target-signal" :not-host) ; needs OS-CONTEXT-T from share-vm - #+win32 ("src/code/target-exception" :not-host) - ("src/code/toplevel" :not-host) - ("src/code/parse-defmacro-errors") - ("src/code/format-directive") - ;; Target-only stuff should usually be compiled late unless it has - ;; compile-time side-effects. This file could probably be later, - ;; but should certainly be no earlier than the definitions - ;; of FORMAT-ERROR and FORMAT-DIRECTIVE. - ("src/code/target-format" :not-host) - ("src/compiler/generic/primtype" :c-headers) + ("src/compiler/proclaim" :c-headers) - ;; for DEFSTRUCT ALIEN-TYPE, needed by host-type.lisp - ("src/code/host-alieneval") + ("src/compiler/constantp" :c-headers) + ("src/compiler/deftype" :c-headers) ; on host for SB-XC:DEFTYPE + ("src/code/type" :c-headers) + ("src/compiler/generic/vm-type" :c-headers) + ("src/code/pred" :not-host) - ;; can't be done until definition of e.g. DEFINE-ALIEN-TYPE-CLASS in - ;; host-alieneval.lisp - ("src/code/host-c-call") + ("src/compiler/generic/primtype" :c-headers) - ;; SB-XC:DEFTYPE is needed in order to compile late-type - ;; in the host Common Lisp, and in order to run, it needs - ;; %COMPILER-DEFTYPE. - ("src/compiler/compiler-deftype" :c-headers) + ;; stuff needed by "code/defstruct" + ("src/code/cross-type" :c-headers :not-target) - ;; These appear here in the build sequence because they require - ;; * the macro INFO, defined in globaldb.lisp, and - ;; * the function PARSE-DEFMACRO, defined in parse-defmacro.lisp, - ;; and because they define - ;; * the function SPECIFIER-TYPE, which is used in fndb.lisp. - ("src/code/late-type" :c-headers) ;; Compile target-only stuff after all defglobals like *CONS-T-T-TYPE* ;; and all type-classes are defined. ("src/code/deftypes-for-target" :c-headers) - ;; defines IR1-ATTRIBUTES macro, needed by proclaim.lisp - ("src/compiler/knownfun") + ("src/code/type-init" :c-headers) - ;; stuff needed by "code/defstruct" - ("src/code/cross-type" :c-headers :not-target) - ("src/compiler/generic/vm-type" :c-headers) - ("src/compiler/proclaim" :c-headers) - - ("src/code/class-init" :c-headers) - - ;; The DEFSTRUCT machinery needs SB-XC:SUBTYPEP, defined in - ;; "code/late-type", and SB-XC:TYPEP, defined in "code/cross-type", + ;; The DEFSTRUCT machinery needs SUBTYPEP, defined in + ;; "code/type", and SB-XC:TYPEP, defined in "code/cross-type", ;; and SPECIALIZE-ARRAY-TYPE, defined in "compiler/generic/vm-type", - ;; and SB-XC:PROCLAIM, defined in "src/compiler/proclaim" + ;; and PROCLAIM, defined in "src/compiler/proclaim" ("src/code/defstruct" :c-headers) - ("src/code/target-defstruct" :not-host) ;; ALIEN-VALUE has to be defined as a class (done by DEFSTRUCT ;; machinery) before we can set its superclasses here. ("src/code/alien-type") - ;; This needs not just the SB-XC:DEFSTRUCT machinery, but also - ;; the TYPE= stuff defined in late-type.lisp, and the - ;; CHECK-FUN-NAME defined in proclaim.lisp. + ;; This needs not just the SB-XC:DEFSTRUCT machinery, but also the + ;; TYPE= stuff defined in type.lisp, and the CHECK-FUN-NAME defined + ;; in proclaim.lisp. ("src/code/force-delayed-defbangstructs" :c-headers :not-target) ("src/compiler/compiler-error") - ("src/code/type-init") ;; Now that the type system is initialized, fix up UNKNOWN types that ;; have crept in. ("src/compiler/fixup-type") @@ -417,9 +307,10 @@ ("src/code/random") ("src/code/hash-table" :c-headers) ("src/code/readtable") - ("src/code/pathname") - ("src/code/host-pprint") ; defines QUEUED-OP needed by 'pprint' + ("src/code/host-pprint") + ("src/compiler/knownfun") + ("src/compiler/ctype") ("src/compiler/fndb") ("src/compiler/generic/vm-fndb") @@ -429,53 +320,61 @@ ("src/compiler/bit-util") + ("src/code/foreign" :not-host) + ("src/code/unix" :not-host) + ("src/code/symbol" :not-host) + ("src/code/bignum" :not-host #-(or bignum-assertions sb-devel) :block-compile) + ("src/code/numbers" :not-host) + ("src/code/float-trap" :not-host) + ("src/code/float" :not-host) + ("src/code/irrat" :not-host) + + ("src/code/fd-stream" :not-host) + ("src/code/target-char" :not-host) + ("src/code/stream" :not-host) ("src/code/load") + ("src/code/deadline" :not-host) + ("src/code/common-os" :not-host) + + ("src/code/format-directive") + + ("src/code/c-call") - #+linkage-table ("src/code/linkage-table" :not-host) - ("src/code/foreign" :not-host) #+os-provides-dlopen ("src/code/foreign-load" :not-host) #+(and os-provides-dlopen (not win32)) ("src/code/unix-foreign-load" :not-host) #+(and os-provides-dlopen win32) ("src/code/win32-foreign-load" :not-host) - ("src/code/fop") ; needs macros from code/load.lisp + #+sb-dyncount ("src/compiler/dyncount") + #+sb-dyncount ("src/code/dyncount") - ("src/compiler/ctype") ("src/compiler/disassem") ("src/compiler/assem") - ;; Compiling this requires fop definitions from code/fop.lisp and + ;; Compiling this requires fop definitions from code/load.lisp. ("src/compiler/dump") ("src/compiler/target-dump" :not-host) ; needs stuff from compiler/dump.lisp ("src/compiler/ir1report") ; for COMPILER-ERROR-CONTEXT - ("src/code/target-pathname" :not-host) ; needs "code/pathname" ("src/compiler/main") ; needs DEFSTRUCT FASL-OUTPUT from dump.lisp ("src/compiler/xref") ("src/compiler/target-main" :not-host) ("src/compiler/ir1tran") ("src/compiler/ir1tran-lambda") - ("src/compiler/ir1-translators" - ;; workaround for ABCL warnings that are not of type STYLE-WARNING: - ;; "Unable to compile function IR1-CONVERT-TAGBODY. Using interpreted form instead." - #.(cl:if (and (cl:find :sb-xc-host cl:*features*) - (cl:find :abcl cl:*features*)) - :ignore-failure-p)) + ("src/compiler/ir1-translators") ("src/compiler/ir1util") ("src/compiler/callable-args") + ("src/compiler/locall") ("src/compiler/ir1opt") ("src/compiler/loop") - ("src/compiler/ir1final") ("src/compiler/constraint") ("src/compiler/equality-constraints") - ("src/compiler/array-tran") - ("src/compiler/seqtran") ("src/compiler/saptran") ("src/compiler/modarith") ("src/compiler/sxhash") ("src/code/quantifiers") ("src/compiler/bitops-derive-type") - ("src/compiler/locall") + ("src/compiler/dfo") ("src/compiler/dce") ("src/compiler/checkgen") @@ -485,85 +384,67 @@ ("src/compiler/debug-dump") ("src/compiler/generic/utils" :c-headers) - ("src/compiler/fopcompile") ("src/assembly/assemfile" :not-target) ("src/compiler/target-dstate" :not-host) ("src/compiler/asm-target/insts") - #+avx2 - ("src/compiler/target/avx2-insts") - ("src/compiler/target/macros") - ("src/compiler/generic/early-type-vops") - - ("src/assembly/target/support") - - ("src/compiler/target/move") - ("src/compiler/target/float") - #+sb-simd-pack - ("src/compiler/target/simd-pack") - #+sb-simd-pack-256 - ("src/compiler/target/simd-pack-256") - ("src/compiler/target/sap") - ("src/compiler/target/system") - ("src/compiler/target/char") - ("src/compiler/target/memory") - ("src/compiler/target/arith" - ;; KLUDGE: for ppc and sparc this appears to be necessary, as it - ;; used to be for array VOPs for X86 until ca. 0.8.5.24 when CSR's - ;; patch for that architecture was finally committed - ;; - ;; old (0.8.5.23) comment on the array-VOP hack for X86: - ;; x Compiling this file for X86 raises alarming warnings of - ;; x the form - ;; x Argument FOO to VOP CHECK-BOUND has SC restriction - ;; x DESCRIPTOR-REG which is not allowed by the operand type: - ;; x (:OR POSITIVE-FIXNUM) - ;; x This seems not to be something that I broke, but rather a "feature" - ;; x inherited from classic CMU CL. (Debian cmucl_2.4.8.deb compiling - ;; x Debian cmucl_2.4.8.tar.gz raises the same warning). Thus, even though - ;; x these warnings are severe enough that they would ordinarily abort - ;; x compilation, for now we blithely ignore them and press on to more - ;; x pressing problems. Someday, though, it would be nice to figure out - ;; x what the problem is and fix it. - #+(or ppc ppc64) :ignore-failure-p) - ("src/compiler/target/pred") + #+avx2 ("src/compiler/{arch}/avx2-insts") + ("src/compiler/{arch}/macros") + + ("src/assembly/{arch}/support") + + ("src/compiler/{arch}/move") + ("src/compiler/{arch}/float") + #+sb-simd-pack ("src/compiler/{arch}/simd-pack") + #+sb-simd-pack-256 ("src/compiler/{arch}/simd-pack-256") + ("src/compiler/{arch}/sap") + ("src/compiler/{arch}/system") + ("src/compiler/{arch}/char") + ("src/compiler/{arch}/memory") + ("src/compiler/{arch}/arith") + ("src/compiler/{arch}/pred") ;; this file defines the INTERVAL struct which is also used in 'srctran' ("src/compiler/float-tran") + ("src/compiler/array-tran") + ("src/compiler/ir1final") + ("src/compiler/generic/vm-tran") + ("src/compiler/type-vop-macros") + ("src/compiler/{arch}/type-vops") + ("src/compiler/generic/type-vops") + ;; This is a terrible name for a file that contains type derivers ;; and IR1 transforms. Maybe split it up into more appropriately named pieces. ("src/compiler/srctran") - ("src/compiler/generic/vm-tran") - ("src/compiler/generic/late-type-vops") - ("src/compiler/target/type-vops") + ("src/compiler/seqtran") ("src/compiler/typetran") ("src/compiler/generic/vm-typetran") ("src/code/cross-modular" :not-target) - ("src/compiler/target/subprim") - ("src/compiler/target/debug") - ("src/compiler/target/c-call") - ("src/compiler/target/cell") - ("src/compiler/target/values") - ("src/compiler/target/alloc") - ("src/compiler/target/call") - ("src/compiler/target/nlx") + ("src/compiler/{arch}/subprim") + ("src/compiler/{arch}/debug") + ("src/compiler/{arch}/c-call") + ("src/compiler/{arch}/cell") + ("src/compiler/{arch}/values") + ("src/compiler/{arch}/alloc") + ("src/compiler/{arch}/call") + ("src/compiler/{arch}/nlx") ("src/compiler/generic/late-nlx") - ("src/compiler/target/show") - ("src/compiler/target/array") + ("src/compiler/{arch}/show") + ("src/compiler/{arch}/array") ("src/compiler/generic/type-error") - ("src/compiler/physenvanal") + ("src/compiler/envanal") ;; KLUDGE: The assembly files need to be compiled twice: once as ;; normal lisp files, and once by sb-c:assemble-file. We use a ;; different suffix / "file type" for the :assem versions to make ;; sure we don't scribble over anything we shouldn't. - ("src/assembly/target/assem-rtns") - ("src/assembly/target/array") - ("src/assembly/target/arith") - ("src/assembly/target/alloc") + ("src/assembly/{arch}/assem-rtns") + ("src/assembly/{arch}/array") + ("src/assembly/{arch}/arith") + ("src/assembly/{arch}/alloc") ;; assembly files are all loaded by genesis before any compiled files. ("src/assembly/master" :assem :not-host) @@ -571,6 +452,7 @@ ("src/compiler/aliencomp") + ("src/compiler/coverage") ("src/compiler/ltv") ("src/compiler/gtn") ("src/compiler/ltn") @@ -589,43 +471,84 @@ ("src/compiler/codegen") ("src/compiler/debug") - #+sb-dyncount ("src/compiler/dyncount") - #+sb-dyncount ("src/code/dyncount") - ("src/code/format-time" :not-host) ;; needed by various unhappy-path cases in the cross-compiler ("src/code/error") - - ;; This wasn't in classic CMU CL "comcom.lisp", but it has some stuff - ;; that Python-as-cross-compiler has turned out to need. - ("src/code/macroexpand") + ("src/code/parse-defmacro-errors") ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; files which depend in some way (directly or indirectly) on stuff ;; compiled as part of the compiler + ("src/code/macroexpand") + ("src/code/funutils" :not-host) + + #+win32 ("src/code/win32" :not-host) + #+android ("src/code/android-os" :not-host) + #+sunos ("src/code/sunos-os" :not-host) + #+bsd ("src/code/bsd-os" :not-host) + #+linux ("src/code/linux-os" :not-host) + #+haiku ("src/code/haiku-os" :not-host) + #+win32 ("src/code/win32-os" :not-host) + + ("src/code/share-vm" :not-host) + + ;; KLUDGE: I'd prefer to have this done with a "code/target" softlink + ;; instead of a bunch of reader macros. -- WHN 19990308 + #+sparc ("src/code/sparc-vm" :not-host) + #+x86 ("src/code/x86-vm" :not-host) + #+x86-64("src/code/x86-64-vm" :not-host) + #+(or ppc ppc64) ("src/code/ppc-vm" :not-host) + #+mips ("src/code/mips-vm" :not-host) + #+arm ("src/code/arm-vm" :not-host) + #+arm64 ("src/code/arm64-vm" :not-host) + #+riscv ("src/code/riscv-vm" :not-host) + + #+(or arm64 x86-64) + ("src/code/simd-fndb") + #+x86-64 + ("src/code/x86-64-simd" :not-host) + #+arm64 + ("src/code/arm64-simd" :not-host) + ("src/code/target-unicode" :not-host) + ("src/code/mipsstrops" :not-host) + ("src/code/string" :not-host) + + ("src/code/target-signal-common" :not-host) + #+unix ("src/code/target-signal" :not-host) ; needs OS-CONTEXT-T from share-vm + #+win32 ("src/code/target-exception" :not-host) + ("src/code/serve-event" :not-host) + ("src/code/late-extensions") ; needs condition system ("src/compiler/generic/target-core" :not-host) ; uses stuff from ; "compiler/generic/core" ("src/code/alloc" :not-host) ; needs foo-SPACE-START + ("src/code/brothertree" :not-host) + #+metaspace ("src/code/metaspace" :not-host) ("src/code/simple-fun" :not-host) ; function slot accessors ("src/code/eval" :not-host) ; uses INFO, wants compiler macro + ("src/code/toplevel" :not-host) + ("src/code/time" :not-host) ("src/code/target-package" :not-host) ; needs "code/package" ("src/code/bignum-random" :not-host) ; needs "code/random" and ; "code/bignum" ("src/code/target-hash-table" :not-host) ; needs "code/hash-table" + ("src/code/fdefinition" :not-host) + ("src/code/query" :not-host) + ("src/code/sort" :not-host) ("src/code/final" :not-host) - ("src/code/pprint" :not-host) ; defines WITH-PRETTY-STREAM needed by 'print' ("src/code/reader" :not-host) ; needs "code/readtable" ("src/code/print" :not-host) + ("src/code/pprint" :not-host) + + ("src/code/target-defstruct" :not-host) ("src/code/target-stream" :not-host) ; needs WHITESPACEP from "code/reader" - #-win32 - ("src/code/unix-pathname" :not-host) - #+win32 - ("src/code/win32-pathname" :not-host) + ("src/code/target-pathname" :not-host) + #-win32 ("src/code/unix-pathname" :not-host) + #+win32 ("src/code/win32-pathname" :not-host) ("src/code/filesys" :not-host) ; needs HOST from "code/pathname" ("src/code/target-misc" :not-host) ; dribble-stream, used by "save" @@ -648,54 +571,50 @@ ;; target-only assemblerish stuff ("src/compiler/target-disassem" :not-host) ("src/compiler/asm-target/target-insts" :not-host) - #+avx2 - ("src/compiler/target/target-avx2-insts" :not-host) + #+avx2 ("src/compiler/{arch}/target-avx2-insts" :not-host) ("src/code/debug" :not-host) ("src/code/octets" :not-host) ("src/code/external-formats/enc-basic" :not-host) - #+sb-unicode - ("src/code/external-formats/enc-ucs" :not-host) ; win32 needs this + #+sb-unicode ("src/code/external-formats/enc-ucs" :not-host) ; win32 needs this - #+sb-eval - ("src/code/full-eval" :not-host) ; uses INFO, ARG-COUNT-ERROR + ("src/code/bit-bash" :not-host) ; needs %NEGATE from assembly/{arch}/arith - ("src/code/bit-bash" :not-host) ; needs %NEGATE from assembly/target/arith + #-(or x86 x86-64) ("src/compiler/generic/sanctify" :not-host) - #-(or x86 x86-64) - ("src/compiler/generic/sanctify" :not-host) + ;;; PCL things. This stuff used to happen in the warm load, but now + ;;; as PCL gets more integrated into the system, we'd like to + ;;; bootstrap things like classes at the same time as the rest of the + ;;; type system. + ("src/pcl/walk") + ("src/pcl/low" :not-host) + ("src/pcl/macros" :not-host) + ("src/pcl/ecd" :not-host) + ("src/pcl/compiler-support" :not-host) + ("src/pcl/defs" :not-host) + ("src/pcl/wrapper" :not-host) + ("src/pcl/class-init" :not-host) ("src/code/cold-init" :not-host) ; needs (SETF EXTERN-ALIEN) macroexpansion ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; target macros and DECLAIMs installed at build-the-cross-compiler time - ;; FIXME: here? earlier? can probably be as late as possible. Also - ;; maybe call it FORCE-DELAYED-PROCLAIMS? - ("src/compiler/late-proclaim") - ("src/code/setf") ("src/code/macros") ("src/code/loop") + ("src/pcl/defclass") + ("src/code/early-defmethod") ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; other target-code-building stuff which can't be processed until ;; machinery like SB-XC:DEFMACRO exists - ("src/code/late-format" ; needs SB-XC:DEFMACRO - #.(cl:if (and (cl:find :sb-xc-host cl:*features*) - (cl:find :cmucl cl:*features*)) ; gets fatal warnings in CMUCL 20c - :ignore-failure-p)) + ("src/code/format") ; needs SB-XC:DEFMACRO + ("src/code/target-format" :not-host) - ("src/code/late-globaldb" :not-host) - ("src/code/redblack" :not-host) - ;; This file, which must be last, contains sanity-checks of the cross-compile. - ;; The inputs and outputs of certain functions (currently just SXHASH) are stored - ;; in global symbols. Relying on the fact that data are easily dumped as constants - ;; (assuming we don't have a genesis bug), the forms in this file can audit - ;; whether things came out right. - ("src/code/last-file" :not-host)) + ("src/code/late-globaldb" :not-host)) ;;; make-target-2 build steps (("src/code/early-ntrace" ; lets PCL hook into tracing @@ -705,12 +624,8 @@ ;; The definition in cold-error is good enough for self-build. "src/code/warm-error" "src/code/icf" - ;; We re-nickname SB-SEQUENCE as SEQUENCE now. - ;; It could be done in genesis, but not earlier, - ;; since the host has a package of that name. "src/code/defpackage" - "src/code/target-lflist" - "src/pcl/walk") ; needs DEFPACKAGE + "src/code/target-lflist") #+sb-fasteval ("src/interpreter/macros" @@ -721,8 +636,12 @@ "src/interpreter/eval" "src/interpreter/debug") - ("src/code/external-formats/enc-ebcdic") - #+sb-unicode + ;; For an easy core size decreases by 3.5% put :UNICODE-LITE in features to exclude + ;; a few external-formats that you'll probably never need. + ;; Even better would be if they were all demand-loadable. + #+sb-unicode ("src/code/external-formats/enc-utf") + #-unicode-lite ("src/code/external-formats/enc-ebcdic") + #+(and sb-unicode (not unicode-lite)) ("src/code/external-formats/enc-cyr" "src/code/external-formats/enc-dos" "src/code/external-formats/enc-iso" @@ -732,8 +651,7 @@ "src/code/external-formats/enc-cn-tbl" "src/code/external-formats/enc-cn" "src/code/external-formats/enc-jpn-tbl" - "src/code/external-formats/enc-jpn" - "src/code/external-formats/enc-utf") + "src/code/external-formats/enc-jpn") ("src/code/stubs") @@ -743,13 +661,7 @@ ;; (arbitrary) linearization of the declared build ;; order dependencies from the old PCL defsys.lisp ;; dependency database. - ("src/pcl/low" - "src/pcl/macros" - "src/pcl/compiler-support" - "src/pcl/defclass" - "src/pcl/defs" - "src/pcl/fngen" - "src/pcl/wrapper" + ("src/pcl/fngen" "src/pcl/cache" "src/pcl/dlisp" "src/pcl/boot" @@ -768,6 +680,7 @@ "src/pcl/fsc" "src/pcl/methods" "src/pcl/fixup" + "src/pcl/call-next-method" "src/pcl/defcombin" "src/pcl/ctypes" "src/pcl/env" @@ -777,6 +690,8 @@ "src/pcl/precom2" "src/code/ntrace") + #+sb-eval ("src/code/full-eval") + ("src/code/setf-funs" ;; miscellaneous functionality which depends on CLOS "src/code/late-condition" @@ -798,7 +713,7 @@ "src/code/describe-policy" "src/code/inspect" "src/code/profile" - #+(and x86-64 sb-thread) "src/code/aprof" ; precise allocation profiler + #+(and x86-64 sb-thread (not gs-seg)) "src/code/aprof" ; precise allocation profiler "src/code/step" "src/code/warm-lib" "src/code/alien-callback" diff --git a/src/cold/chill.lisp b/src/cold/chill.lisp index 307c3cd561..43c5abdc19 100644 --- a/src/cold/chill.lisp +++ b/src/cold/chill.lisp @@ -21,16 +21,15 @@ (setq *features* (union *features* sb-impl:+internal-features+)) -(defstruct package-data name doc shadow export reexport import-from use) (export 'package-data) -(dolist (data (with-open-file (f (merge-pathnames "../../package-data-list.lisp-expr" - *load-pathname*)) - (read f))) - (labels ((flatten (tree) - (mapcan (lambda (x) (if (listp x) (flatten x) (list x))) - tree))) - (let ((*package* (find-package (package-data-name data)))) - (export (mapcar 'intern (flatten (package-data-export data))))))) +(defmacro defpackage* (name &rest options) + `(let ((*package* (find-package ,name))) + (dolist (x ',(loop for option in options + when (eq (first option) :export) + append (rest option))) + (let ((symbol (intern x))) + (ignore-errors (export symbol)))))) +(load (merge-pathnames "exports.lisp" *load-pathname*)) (sb-ext:unlock-package "CL") (rename-package "COMMON-LISP" "COMMON-LISP" @@ -41,26 +40,13 @@ (when (sb-int:system-package-p (find-package name)) (sb-ext:unlock-package package)))) -;;; Define this first to avoid a style-warning from 'shebang' +;;; Restore target floating-point number syntax (defun read-target-float (stream char) (declare (ignore stream char)) (values)) ; ignore the $ as if it weren't there (compile 'read-target-float) -;;; We need the #! readtable modifications. -(load (merge-pathnames "shebang.lisp" *load-pathname*)) -;;; ... applied to the default readtable -(set-dispatch-macro-character #\# #\+ #'read-targ-feature-expr) -(set-dispatch-macro-character #\# #\- #'read-targ-feature-expr) (set-macro-character #\$ #'read-target-float t) -;;; Just in case we want to play with the initial value of -;;; backend-subfeatures -(setf sb-cold:*shebang-backend-subfeatures* sb-c:*backend-subfeatures*) - -;; Restore !DEFINE-LOAD-TIME-GLOBAL macro -(setf (macro-function 'sb-int::!define-load-time-global) - (macro-function 'sb-ext:define-load-time-global)) - (unless (fboundp 'sb-int:!cold-init-forms) (defmacro sb-int:!cold-init-forms (&rest forms) `(progn ,@forms))) @@ -71,3 +57,5 @@ (setf (macro-function 'sb-int:/noshow) (macro-function 'sb-int:/show) (macro-function 'sb-int:/show0) (macro-function 'sb-int:/show) (macro-function 'sb-int:/noshow0) (macro-function 'sb-int:/show))) + +(load "SYS:src;compiler;vop-existsp.lisp") diff --git a/common-lisp-exports.lisp-expr b/src/cold/common-lisp-exports.lisp-expr similarity index 100% rename from common-lisp-exports.lisp-expr rename to src/cold/common-lisp-exports.lisp-expr diff --git a/src/cold/compile-cold-sbcl.lisp b/src/cold/compile-cold-sbcl.lisp index 9ff4482b29..7ff723b491 100644 --- a/src/cold/compile-cold-sbcl.lisp +++ b/src/cold/compile-cold-sbcl.lisp @@ -13,8 +13,17 @@ (in-package "SB-COLD") +;;; FIXME: I think it's a mistake that we load muffler twice in +;;; make-host-2 (once for the host, once for XC), because the host +;;; should produce no new warnings, and because it's really hard +;;; to think straight when you figure that we're using the host's +;;; SIGNAL and type system but mixing it with our types. +;;; We can just bake in some behavior to the cross-compiler never to warn +;;; about sh*t that we think isn't warning-worthy. +;;; (i.e. do it in source code using #[-+]sb-xc-host). +;;; The target compiler will still get everything as usual. (let ((*features* (cons :sb-xc *features*))) - (load "src/cold/muffler.lisp")) + (load (sb-cold:find-bootstrap-file "^muffler"))) ;;; Ordinarily the types carried around as "handled conditions" while compiling ;;; have been parsed into internal CTYPE objects. However, using parsed objects @@ -76,8 +85,7 @@ ;; optimizations. (ANSI says users aren't supposed to ;; redefine our functions anyway; and developers can ;; fend for themselves.) - (sb-ext:*derive-function-types* - (if (find :sb-fluid sb-xc:*features*) nil t)) + (sb-ext:*derive-function-types* t) ;; Let the target know that we're the cross-compiler. (sb-xc:*features* (cons :sb-xc sb-xc:*features*)) (*readtable* sb-cold:*xc-readtable*)) @@ -101,6 +109,14 @@ (setq sb-c::*track-full-called-fnames* :minimal) ; Change this as desired +;;; Need to get access these sb-sys symbols unqualified from sb-assem +;;; during make-host-2. Make-host-1 would have already converted its +;;; code via DEFSETF so it should be insensitive to this substitution. +(unintern 'sb-assem::sap-ref-16 'sb-assem) +(unintern 'sb-assem::sap-ref-32 'sb-assem) +(import '(sb-sys:sap-ref-16 sb-sys:sap-ref-32) 'sb-assem) + +(read-undefined-fun-allowlist) (defun parallel-make-host-2 (max-jobs) (let ((subprocess-count 0) (subprocess-list nil) @@ -181,14 +197,31 @@ (let ((sb-xc:*compile-print* nil)) (if (make-host-2-parallelism) (funcall 'parallel-make-host-2 (make-host-2-parallelism)) - (let ((total + (let ((total-files (count-if (lambda (x) (not (find :not-target (cdr x)))) (get-stems-and-flags 2))) + (total-time 0) (n 0) (sb-xc:*compile-verbose* nil)) + ;; Workaround memory exhaustion in SB-FASTEVAL. + ;; In SB-EVAL the default evaluator-mode is :compile, + ;; but it also would exhaust memory if interpreting. + #+sbcl (setq host-sb-ext:*evaluator-mode* :compile) (with-math-journal (do-stems-and-flags (stem flags 2) (unless (position :not-target flags) - (format t "~&[~D/~D] ~A" (incf n) total (stem-remap-target stem)) - (target-compile-stem stem flags) - (terpri))))))))) + (format t "~&[~3D/~3D] ~40A" (incf n) total-files (stem-remap-target stem)) + (let ((start (get-internal-real-time))) + (target-compile-stem stem flags) + (let ((elapsed (/ (- (get-internal-real-time) start) + internal-time-units-per-second))) + (format t " (~f sec)~%" elapsed) + (incf total-time elapsed))) + ;; The specialized array registry has file-wide scope. Hacking that aspect + ;; into the xc build scaffold seemed slightly easier than hacking the + ;; compiler (i.e. making the registry a slot of the fasl-output struct) + (clear-specialized-array-registry))) + (format t "~&~50t ~f~%" total-time)) + (sb-c::dump/restore-interesting-types 'write))) + (sb-kernel::write-structure-definitions-as-text + (sb-cold:find-bootstrap-file "output/defstructs.lisp-expr" t))))) diff --git a/src/cold/defun-load-or-cload-xcompiler.lisp b/src/cold/defun-load-or-cload-xcompiler.lisp index 04bfdc43d5..dd30f35b72 100644 --- a/src/cold/defun-load-or-cload-xcompiler.lisp +++ b/src/cold/defun-load-or-cload-xcompiler.lisp @@ -97,6 +97,12 @@ (sb-cold::exit-process 1))))) (format t "~&; Parallel build: Skipping fasl load~%")) +;;; Read the version file once and once only, +;;; or not at all if you've otherwise defined this. +(defvar *target-sbcl-version* (read-from-file "version.lisp-expr")) + +#+ccl (declaim (ftype function warn-when-cl-snapshot-diff)) ; silly compiler + ;;; Either load or compile-then-load the cross-compiler into the ;;; cross-compilation host Common Lisp. (defun load-or-cload-xcompiler (load-or-cload-stem) @@ -113,6 +119,8 @@ (if (and (make-host-1-parallelism) (eq load-or-cload-stem #'host-cload-stem)) (progn + ;; FIXME: muffler not working in forked children? + (setq *fail-on-warnings* nil) ;; Multiprocess build uses the in-memory math ops cache but not ;; the persistent cache file because we don't need each child ;; to be forced to read the file. Moreover, newly inserted values @@ -135,26 +143,16 @@ (with-math-journal (do-stems-and-flags (stem flags 1) (unless (find :not-host flags) + ;; Enforce naming convention: target-* files are not for make-host-1 + (assert (not (search "code/target-" stem))) (funcall load-or-cload-stem stem flags) (when (member :sb-show sb-xc:*features*) (funcall 'warn-when-cl-snapshot-diff *cl-snapshot*)))))) - ;; If the cross-compilation host is SBCL itself, we can use the - ;; PURIFY extension to freeze everything in place, reducing the - ;; amount of work done on future GCs. In machines with limited - ;; memory, this could help, by reducing the amount of memory which - ;; needs to be juggled in a full GC. And it can hardly hurt, since - ;; (in the ordinary build procedure anyway) essentially everything - ;; which is reachable at this point will remain reachable for the - ;; entire run. - ;; - ;; (Except that purifying actually slows down GENCGC). -- JES, 2006-05-30 - #+(and sbcl (not gencgc)) - (host-sb-ext:purify) - ;; Let's check that the type system, and various other things, are ;; reasonably sane. (It's easy to spend a long time wandering around ;; confused trying to debug cross-compilation if it isn't.) + (funcall 'sb-c::check-vop-existence-correctness) (let ((*readtable* *xc-readtable*) (*load-verbose* t)) (with-math-journal diff --git a/src/cold/exports.lisp b/src/cold/exports.lisp new file mode 100644 index 0000000000..613dac269b --- /dev/null +++ b/src/cold/exports.lisp @@ -0,0 +1,3582 @@ +;;;; All the stuff necessary to export various symbols from various packages. + +;;;; This software is part of the SBCL system. See the README file for +;;;; more information. +;;;; +;;;; This software is derived from the CMU CL system, which was +;;;; written at Carnegie Mellon University and released into the +;;;; public domain. The software is in the public domain and is +;;;; provided with absolutely no warranty. See the COPYING and CREDITS +;;;; files for more information. + +;;;; the specifications of target packages, except for a few things +;;;; which are handled elsewhere by other mechanisms: +;;;; * some SHADOWing and nickname hackery; +;;;; * the standard, non-SBCL-specific packages COMMON-LISP, +;;;; COMMON-LISP-USER, and KEYWORD. +;;;; + +;;;; NOTE: +;;;; All uses of #+ and #- reader macros within this file refer to +;;;; the chosen target features, and not CL:*FEATURES*, but +;;;; it is generally not necessary to use reader conditionals +;;;; within this file. If A-NICE-FUNCTION is external in SB-KERNEL +;;;; but not defined for a particular backend, it will not get +;;;; interned during cold load, and hence will not exist in the target. +;;;; This is exactly as desired - it is not necessary for the writer +;;;; of architecture-specific code to clutter up the list of package +;;;; definitions to avoid exporting some stuff. You just export what you +;;;; need, and genesis will do the right thing. Most of the pre-existing +;;;; conditionals are historical baggage, and should be removed. +;;;; EXCEPTION: packages whose symbols are created mainly during +;;;; warm load might have a reason to use reader conditionals. +;;;; For those packages, all symbols listed here are interned during +;;;; genesis, since otherwise the symbols would all disappear, +;;;; and then warm load would intern them as internals, not externals. +;;;; This list of exceptional packages can be found in the +;;;; definition of the FINISH-SYMBOLS function. + +(in-package "SB-COLD") + +(defpackage* "SB-LOOP" + (:documentation "private: implementation details of LOOP") + (:use "CL" "SB-INT" "SB-KERNEL")) + +(defpackage* "SB-UNIX" + (:documentation + "private: a wrapper layer for SBCL itself to use when talking with +an underlying Unix-y operating system. This was a public package in +CMU CL, but that was different. CMU CL's UNIX package tried to +provide a comprehensive, stable Unix interface suitable for the end +user. This package only tries to implement what happens to be needed +by the current implementation of SBCL, and makes no guarantees of +interface stability.") + (:use "CL" "SB-ALIEN" "SB-EXT" "SB-INT" "SB-SYS") + (:export + ;; wrappers around Unix stuff to give just what Lisp needs + "NANOSLEEP" + "UID-USERNAME" + "UID-HOMEDIR" + "USER-HOMEDIR" + "SB-MKSTEMP" + "UNIX-OFFSET" + "FD-TYPE" + + "SIZE-T" + "OFF-T" + ;; Most of this is random detritus worthy of deletion, + ;; and the ordering is not alphabetical or anything sane. + + ;; stuff with a one-to-one mapping to Unix constructs + + "DEV-T" + "F_OK" "GID-T" + "INO-T" "UNIX-ACCESS" "UNIX-SETITIMER" "UNIX-GETITIMER" + "L_INCR" "L_SET" "L_XTND" "O_APPEND" "O_CREAT" "O_NOCTTY" "O_EXCL" + "O_RDONLY" "O_RDWR" "O_TRUNC" "O_WRONLY" "POSIX-GETCWD" + "POSIX-GETCWD/" + "RU-IDRSS" "RU-INBLOCK" "RU-ISRSS" "RU-IXRSS" + "RU-MAJFLT" "RU-MAXRSS" "RU-MINFLT" "RU-MSGRCV" "RU-MSGSND" + "RU-NIVCSW" "RU-NSIGNALS" "RU-NSWAP" "RU-NVCSW" "RU-OUBLOCK" + "RU-STIME" "RU-UTIME" "RUSAGE_CHILDREN" "RUSAGE_SELF" + "R_OK" "S-IFDIR" "S-IFLNK" "S-IFMT" + "S-IFREG" + "ST-ATIME" "ST-BLKSIZE" "ST-BLOCKS" + "ST-CTIME" "ST-DEV" "ST-GID" "ST-MODE" "ST-MTIME" "ST-NLINK" + "ST-RDEV" "ST-SIZE" "ST-UID" "STAT" "TIME-T" + "TIMEVAL" "TIMEZONE" + "TIOCGPGRP" + "TV-SEC" "TV-USEC" + "TZ-DSTTIME" "TZ-MINUTESWEST" "UID-T" "UNIX-CLOSE" + "UNIX-CLOSEDIR" "UNIX-DIRENT-NAME" "UNIX-DUP" + "UNIX-FILE-MODE" "UNIX-FSTAT" + "UNIX-GETHOSTNAME" "UNIX-GETPID" "UNIX-GETRUSAGE" + "UNIX-GETTIMEOFDAY" "UNIX-GETUID" "UNIX-GID" + "UNIX-EXIT" + "UNIX-IOCTL" + "UNIX-ISATTY" "UNIX-LSEEK" "UNIX-LSTAT" "UNIX-MKDIR" + "UNIX-OPEN" "UNIX-OPENDIR" "UNIX-PATHNAME" "UNIX-PID" + "UNIX-PIPE" "UNIX-POLL" "UNIX-SIMPLE-POLL" + "UNIX-READ" "UNIX-READDIR" "UNIX-READLINK" "UNIX-REALPATH" + "UNIX-RENAME" "UNIX-STAT" "UNIX-UID" + "UNIX-UNLINK" "UNIX-WRITE" + "WCONTINUED" "WNOHANG" "WUNTRACED" + "W_OK" "X_OK" + "SC-NPROCESSORS-ONLN" + "VOID-SYSCALL" + "CLOCK-THREAD-CPUTIME-ID" + "CLOCK-PROCESS-CPUTIME-ID" + "CLOCK-REALTIME" + + ;; signals + + "SIGALRM" "SIGBUS" "SIGCHLD" "SIGCONT" "SIGEMT" "SIGFPE" + "SIGHUP" "SIGILL" "SIGINT" "SIGIO" "SIGKILL" + "SIGPIPE" "SIGPROF" "SIGQUIT" "SIGSEGV" "SIGSTOP" "SIGSYS" + "SIGTERM" "SIGTRAP" "SIGTSTP" "SIGTTIN" "SIGTTOU" "SIGURG" + "SIGUSR1" "SIGUSR2" "SIGVTALRM" "SIGWINCH" + "SIGXCPU" "SIGXFSZ" + + ;; errors + + "EAGAIN" "EBADF" "EEXIST" "EINTR" "EIO" "ELOOP" "ENOENT" + "EPIPE" "ESPIPE" "EWOULDBLOCK" + + "POLLFD" "POLLIN" "POLLOUT" "POLLHUP" "POLLNVAL" "POLLERR" + "FD" "EVENTS" "REVENTS" + "FD-ISSET" "FD-SET" "UNIX-FAST-SELECT" + "PTHREAD-KILL" "RAISE" "UNIX-KILL" "UNIX-KILLPG" + "FD-ZERO" "FD-CLR" + "FD-SETSIZE")) + +#+win32 +(defpackage* "SB-WIN32" + (:documentation "private: a wrapper layer for Win32 functions needed by +SBCL itself") + (:use "CL" "SB-ALIEN" "SB-EXT" "SB-INT" "SB-SYS") + (:export "BOOL" + "CLOSE-HANDLE" + "CREATE-FILE" + "CREATE-FILE-MAPPING" + "CRYPT-GEN-RANDOM" + "DWORD" + "EXCEPTION" + "EXCEPTION-RECORD" + "EXCEPTION-CONTEXT" + "EXCEPTION-CODE" + "FILE-CREATE-ALWAYS" + "FILE-CREATE-NEW" + "FILE-OPEN-ALWAYS" + "FILE-OPEN-EXISTING" + "FILE-TRUNCATE-EXISTING" + "FLUSH-CONSOLE-INPUT-BUFFER" + "FLUSH-VIEW-OF-FILE" + "FORMAT-SYSTEM-MESSAGE" + "GET-FILE-ATTRIBUTES" + "GET-FILE-SIZE-EX" + "GET-FILE-TYPE" + "GET-LAST-ERROR" + "GET-OSFHANDLE" + "GET-VERSION-EX" + "HANDLE" + "HANDLE-CLEAR-INPUT" + "HANDLE-LISTEN" + "INT-PTR" + "INVALID-HANDLE" + "LSEEKI64" + "MAP-VIEW-OF-FILE" + "MILLISLEEP" + "PEEK-CONSOLE-INPUT" + "PEEK-NAMED-PIPE" + "READ-FILE" + "UNIXLIKE-CLOSE" + "UNIXLIKE-OPEN" + "UNMAP-VIEW-OF-FILE" + "WAIT-OBJECT-OR-SIGNAL" + "WRITE-FILE" + "WITH-PROCESS-TIMES")) + +(defpackage* "SB-FORMAT" + (:documentation "private: implementation of FORMAT and friends") + (:use "CL" "SB-EXT" "SB-INT" "SB-KERNEL") + (:export "%COMPILER-WALK-FORMAT-STRING" "FORMAT-ERROR" "TOKENS")) + +(defpackage* "SB-BIGNUM" + (:documentation "private: bignum implementation") + (:use "CL" "SB-KERNEL" "SB-INT" "SB-EXT" "SB-ALIEN" "SB-SYS") + (:export "%ADD-WITH-CARRY" + "%ALLOCATE-BIGNUM" "%ASHL" "%ASHR" + "%BIGNUM-LENGTH" "%BIGNUM-REF" "%BIGNUM-REF-WITH-OFFSET" + "%BIGNUM-SET" + #+bignum-assertions "%%BIGNUM-SET" + "%BIGNUM-SET-LENGTH" "%DIGIT-0-OR-PLUSP" + "%DIGIT-LOGICAL-SHIFT-RIGHT" + "%FIXNUM-DIGIT-WITH-CORRECT-SIGN" "%FIXNUM-TO-DIGIT" + "%BIGFLOOR" "%LOGAND" "%LOGIOR" "%LOGNOT" "%LOGXOR" + "%MULTIPLY" "%MULTIPLY-AND-ADD" + "%SUBTRACT-WITH-BORROW" "ADD-BIGNUMS" + "BIGNUM-ASHIFT-LEFT" "BIGNUM-ASHIFT-LEFT-FIXNUM" + "BIGNUM-ASHIFT-RIGHT" + "BIGNUM-COMPARE" + "BIGNUM-ELEMENT-TYPE" "BIGNUM-GCD" "BIGNUM-INDEX" + "BIGNUM-LENGTH" + "BIGNUM-INTEGER-LENGTH" + "BIGNUM-LOGBITP" + "BIGNUM-LOGCOUNT" "BIGNUM-LOGICAL-AND" + "BIGNUM-LOGICAL-IOR" "BIGNUM-LOGICAL-NOT" + "BIGNUM-LOGICAL-XOR" "BIGNUM-PLUS-P" + "BIGNUM-TO-FLOAT" "BIGNUM-TRUNCATE" "BIGNUM-TRUNCATE-SINGLE-DIGIT" + "MAKE-SMALL-BIGNUM" + "MULTIPLY-BIGNUM-AND-FIXNUM" "MULTIPLY-BIGNUMS" + "MULTIPLY-FIXNUMS" "NEGATE-BIGNUM" + "%RANDOM-BIGNUM" "SUBTRACT-BIGNUM" "SXHASH-BIGNUM" + "HALF-BIGNUM-ELEMENT-TYPE" "HALF-BIGNUM-INDEX" "HALF-BIGNUM-LENGTH" + "%HALF-BIGNUM-REF" "%HALF-BIGFLOOR")) + +;; This package is a grab bag for things which used to be internal +;; symbols in package COMMON-LISP. Lots of these symbols are accessed +;; with explicit SB-IMPL:: prefixes in the code. It would be nice to +;; reduce the use of this practice, so if symbols from here which are +;; accessed that way are found to belong more appropriately in an +;; existing package (e.g. SB-KERNEL or SB-SYS or SB-EXT or SB-FASL), +;; I (WHN 19990223) encourage maintainers to move them there.. +(defpackage* "SB-IMPL" + (:documentation "private: a grab bag of implementation details") + (:import-from "SB-KERNEL" "*PACKAGE-NAMES*") + (:export "FORMAT-MICROSECONDS" "FORMAT-MILLISECONDS" ; for ~/fmt/ + + "PRINT-TYPE" "PRINT-TYPE-SPECIFIER" + "PRINT-LAMBDA-LIST" + ;; protect from tree shaker so we can test this function + + "EXPAND-SYMBOL-CASE" + ;; symbols used by sb-simple-streams + + "ANSI-STREAM-CLEAR-INPUT" + "ANSI-STREAM-LISTEN" + "ANSI-STREAM-READ-BYTE" "ANSI-STREAM-READ-CHAR" + "ANSI-STREAM-READ-CHAR-NO-HANG" "ANSI-STREAM-READ-LINE" + "ANSI-STREAM-READ-SEQUENCE" "ANSI-STREAM-PEEK-CHAR" + "ANSI-STREAM-UNREAD-CHAR" + "DISPATCH-TABLES" "CHARACTER-MACRO-HASH-TABLE" "CHARACTER-MACRO-ARRAY" + "TOKEN-DELIMITERP" "WHITESPACE[2]P" "WITH-READ-BUFFER" + ;; other + + "%MAKUNBOUND") + (:use "CL" "SB-ALIEN" "SB-BIGNUM" "SB-DEBUG" "SB-EXT" + "SB-FASL" "SB-GRAY" "SB-INT" "SB-KERNEL" "SB-SYS")) + +(defpackage* "SB-SEQUENCE" + (:nicknames "SEQUENCE") + (:documentation "semi-public: implements something which might eventually +be submitted as a CDR") + (:export "PROTOCOL-UNIMPLEMENTED" + "PROTOCOL-UNIMPLEMENTED-OPERATION" + + "DOSEQUENCE" + + "MAKE-SEQUENCE-ITERATOR" "MAKE-SIMPLE-SEQUENCE-ITERATOR" + + "ITERATOR-STEP" "ITERATOR-ENDP" "ITERATOR-ELEMENT" + "ITERATOR-INDEX" "ITERATOR-COPY" + + "WITH-SEQUENCE-ITERATOR" "WITH-SEQUENCE-ITERATOR-FUNCTIONS" + + "CANONIZE-TEST" "CANONIZE-KEY" + + "EMPTYP" "LENGTH" "ELT" + "MAKE-SEQUENCE-LIKE" "ADJUST-SEQUENCE" + + "MAP" + "COUNT" "COUNT-IF" "COUNT-IF-NOT" + "FIND" "FIND-IF" "FIND-IF-NOT" + "POSITION" "POSITION-IF" "POSITION-IF-NOT" + "SUBSEQ" "COPY-SEQ" "FILL" + "NSUBSTITUTE" "NSUBSTITUTE-IF" "NSUBSTITUTE-IF-NOT" + "SUBSTITUTE" "SUBSTITUTE-IF" "SUBSTITUTE-IF-NOT" + "REPLACE" "REVERSE" "NREVERSE" "CONCATENATE" "REDUCE" + "MISMATCH" "SEARCH" + "DELETE" "DELETE-IF" "DELETE-IF-NOT" + "REMOVE" "REMOVE-IF" "REMOVE-IF-NOT" + "DELETE-DUPLICATES" "REMOVE-DUPLICATES" + + "SORT" "STABLE-SORT" "MERGE")) + +#+sb-eval +(defpackage* "SB-EVAL" + (:documentation "internal: the evaluator implementation used to execute code without compiling it.") + (:use "CL" "SB-KERNEL" "SB-EXT" "SB-INT") + (:export "INTERPRETED-FUNCTION-NAME" + "INTERPRETED-FUNCTION-DEBUG-NAME" + "INTERPRETED-FUNCTION-LAMBDA-LIST" + "INTERPRETED-FUNCTION-DEBUG-LAMBDA-LIST" + "INTERPRETED-FUNCTION-DECLARATIONS" + "INTERPRETED-FUNCTION-DOCUMENTATION" + "INTERPRETED-FUNCTION-BODY" + "INTERPRETED-FUNCTION-SOURCE-LOCATION" + "EVAL-IN-ENVIRONMENT" + "MAKE-NULL-ENVIRONMENT" + "EVAL-IN-NATIVE-ENVIRONMENT" + "*EVAL-LEVEL*")) + +#+sb-fasteval +(defpackage* "SB-INTERPRETER" + (:documentation "internal: a new EVAL implementation with semantic preprocessing.") + (:use "CL" "SB-KERNEL" "SB-EXT" "SB-INT") + (:import-from "SB-C" + "PARSE-EVAL-WHEN-SITUATIONS" + "MAKE-GLOBAL-VAR" "MAKE-LAMBDA-VAR" + "*LEXENV*") + (:import-from "SB-ALIEN" "%HEAP-ALIEN" "ALIEN-VALUE") + (:import-from "SB-KERNEL" "%%TYPEP") + (:export "BASIC-ENV" + "ENV-POLICY" + "EVAL-IN-ENVIRONMENT" + "FIND-LEXICAL-FUN" + "FIND-LEXICAL-VAR" + "FUN-LAMBDA-EXPRESSION" + "FUN-LAMBDA-LIST" + "FUN-PROTO-FN" + "FUN-SOURCE-LOCATION" + "%FUN-FTYPE" + "LEXENV-FROM-ENV" + "LIST-LOCALS" + "PROTO-FN-DOCSTRING" + "PROTO-FN-NAME" + "PROTO-FN-PRETTY-ARGLIST" + "TYPE-CHECK")) + +(defpackage* "SB-VM" + (:documentation + "internal: the default place to hide information about the hardware and data +structure representations") + (:use "CL" "SB-ALIEN" "SB-ALIEN-INTERNALS" "SB-ASSEM" "SB-C" + "SB-EXT" "SB-FASL" "SB-INT" "SB-KERNEL" "SB-SYS" "SB-UNIX") + (:import-from "SB-C" "VOP-ARGS" "VOP-RESULTS") + (:export "*PRIMITIVE-OBJECTS*" + "+HIGHEST-NORMAL-GENERATION+" + "+PSEUDO-STATIC-GENERATION+" + "+ARRAY-FILL-POINTER-P+" + "+VECTOR-SHAREABLE+" + "+VECTOR-SHAREABLE-NONSTD+" + "%COMPILER-BARRIER" "%DATA-DEPENDENCY-BARRIER" + "%MEMORY-BARRIER" "%READ-BARRIER" "%WRITE-BARRIER" + "AFTER-BREAKPOINT-TRAP" + #+(and gencgc sparc) "ALLOCATION-TRAP" + "ANY-REG-SC-NUMBER" "ARRAY-DATA-SLOT" "ARRAY-DIMENSIONS-OFFSET" + "ARRAY-DISPLACED-P-SLOT" "ARRAY-DISPLACEMENT-SLOT" + "ARRAY-DISPLACED-FROM-SLOT" + "ARRAY-ELEMENTS-SLOT" + "ARRAY-FILL-POINTER-SLOT" + "ARRAY-RANK-POSITION" "ARRAY-FLAGS-POSITION" + "ARRAY-FLAGS-DATA-POSITION" + "CHARACTER-REG-SC-NUMBER" + "CHARACTER-STACK-SC-NUMBER" "CHARACTER-WIDETAG" + "BIGNUM-DIGITS-OFFSET" "BIGNUM-WIDETAG" "BINDING-SIZE" + "BINDING-SYMBOL-SLOT" "BINDING-VALUE-SLOT" "BREAKPOINT-TRAP" + "N-BYTE-BITS" + "CATCH-BLOCK-CODE-SLOT" + "CATCH-BLOCK-CFP-SLOT" "CATCH-BLOCK-UWP-SLOT" + "CATCH-BLOCK-ENTRY-PC-SLOT" "CATCH-BLOCK-PREVIOUS-CATCH-SLOT" + "CATCH-BLOCK-SC-NUMBER" "CATCH-BLOCK-SIZE" + "CATCH-BLOCK-TAG-SLOT" "CERROR-TRAP" + "CLOSURE-FUN-SLOT" + "CLOSURE-WIDETAG" + "CLOSURE-INFO-OFFSET" + "CODE-BOXED-SIZE-SLOT" + "CODE-CONSTANTS-OFFSET" "CODE-SLOTS-PER-SIMPLE-FUN" + "CODE-DEBUG-INFO-SLOT" + "CODE-HEADER-SIZE-SHIFT" + "CODE-HEADER-WIDETAG" "COMPLEX-ARRAY-WIDETAG" + "COMPLEX-BIT-VECTOR-WIDETAG" "COMPLEX-DOUBLE-FLOAT-FILLER-SLOT" + "COMPLEX-DOUBLE-FLOAT-IMAG-SLOT" "COMPLEX-DOUBLE-FLOAT-REAL-SLOT" + "COMPLEX-DOUBLE-FLOAT-SIZE" "COMPLEX-DOUBLE-FLOAT-WIDETAG" + "COMPLEX-DOUBLE-REG-SC-NUMBER" "COMPLEX-DOUBLE-STACK-SC-NUMBER" + "COMPLEX-IMAG-SLOT" "COMPLEX-REAL-SLOT" + #+long-float "COMPLEX-LONG-FLOAT-IMAG-SLOT" + #+long-float "COMPLEX-LONG-FLOAT-REAL-SLOT" + #+long-float "COMPLEX-LONG-FLOAT-SIZE" + #+long-float "COMPLEX-LONG-FLOAT-WIDETAG" + #+long-float "COMPLEX-LONG-REG-SC-NUMBER" + #+long-float "COMPLEX-LONG-STACK-SC-NUMBER" + #-64-bit "COMPLEX-SINGLE-FLOAT-IMAG-SLOT" + #-64-bit "COMPLEX-SINGLE-FLOAT-REAL-SLOT" + #+64-bit "COMPLEX-SINGLE-FLOAT-DATA-SLOT" + "COMPLEX-SINGLE-FLOAT-SIZE" "COMPLEX-SINGLE-FLOAT-WIDETAG" + "COMPLEX-SINGLE-REG-SC-NUMBER" "COMPLEX-SINGLE-STACK-SC-NUMBER" + "COMPLEX-SIZE" "COMPLEX-BASE-STRING-WIDETAG" + #+sb-unicode "COMPLEX-CHARACTER-STRING-WIDETAG" + "COMPLEX-WIDETAG" + "COMPLEX-VECTOR-WIDETAG" "CONS-CAR-SLOT" "CONS-CDR-SLOT" + "CONS-SIZE" "CONSTANT-SC-NUMBER" + "CONTEXT-FLOATING-POINT-MODES" "CONTEXT-FLOAT-REGISTER" + "CONTEXT-PC" "CONTEXT-REGISTER" "BOXED-CONTEXT-REGISTER" + "CONTROL-STACK-SC-NUMBER" + #+sb-safepoint "CSP-SAFEPOINT-TRAP" + "*CURRENT-CATCH-BLOCK*" + "CURRENT-FLOAT-TRAP" + "DESCRIPTOR-REG-SC-NUMBER" + "DO-REFERENCED-OBJECT" + "DOUBLE-FLOAT-BIAS" + "DOUBLE-FLOAT-DIGITS" "DOUBLE-FLOAT-EXPONENT-BYTE" + "DOUBLE-FLOAT-HIDDEN-BIT" + "DOUBLE-FLOAT-NORMAL-EXPONENT-MAX" + "DOUBLE-FLOAT-NORMAL-EXPONENT-MIN" "DOUBLE-FLOAT-SIGNIFICAND-BYTE" + "DOUBLE-FLOAT-SIZE" + "DOUBLE-FLOAT-WIDETAG" "DOUBLE-FLOAT-VALUE-SLOT" + "DOUBLE-REG-SC-NUMBER" + "DOUBLE-STACK-SC-NUMBER" + "DSD-INDEX-SHIFT" + "DSD-RAW-TYPE-MASK" + "EMIT-LONG-NOP" "ERROR-TRAP" "EVEN-FIXNUM-LOWTAG" + "FDEFN-FUN-SLOT" "FDEFN-NAME-SLOT" "FDEFN-RAW-ADDR-SLOT" + "FDEFN-SIZE" "FDEFN-WIDETAG" + "FILLER-WIDETAG" + "FIXNUMIZE" + "FIXNUM-TAG-MASK" + "FIXUP-CODE-OBJECT" "FLOAT-DENORMAL-TRAP-BIT" + "FLOAT-DIVIDE-BY-ZERO-TRAP-BIT" + "FLOAT-INVALID-TRAP-BIT" + "FLOAT-OVERFLOW-TRAP-BIT" "FLOAT-SIGN-SHIFT" + "FLOAT-UNDERFLOW-TRAP-BIT" "FLOATING-POINT-MODES" + "FLOAT-STICKY-BITS" + "FLOAT-TRAPS-BYTE" + "FP-CONSTANT-SC-NUMBER" + "FP-DOUBLE-ZERO-SC-NUMBER" "FP-SINGLE-ZERO-SC-NUMBER" + "FUNCALLABLE-INSTANCE-TRAMPOLINE-SLOT" + "FUNCALLABLE-INSTANCE-WIDETAG" + "FUNCALLABLE-INSTANCE-INFO-OFFSET" + "SIMPLE-FUN-ARGLIST-SLOT" "SIMPLE-FUN-INSTS-OFFSET" + "FUN-END-BREAKPOINT-TRAP" + "SIMPLE-FUN-WIDETAG" + "SIMPLE-FUN-NAME-SLOT" + "SIMPLE-FUN-ENTRY-SAP" + "FUN-POINTER-LOWTAG" + "FUNCTION-LAYOUT" + "SIMPLE-FUN-INFO-SLOT" + "SIMPLE-FUN-SELF-SLOT" + "SIMPLE-FUN-SOURCE-SLOT" + "GENCGC-CARD-BYTES" + "GENCGC-PAGE-BYTES" + "GENCGC-ALLOC-GRANULARITY" + "GENCGC-RELEASE-GRANULARITY" + #+(or arm64 ppc ppc64 sparc riscv) "PSEUDO-ATOMIC-INTERRUPTED-FLAG" + #+(or arm64 ppc ppc64 sparc riscv) "PSEUDO-ATOMIC-FLAG" + #+sb-safepoint "GLOBAL-SAFEPOINT-TRAP" + "HALT-TRAP" "IGNORE-ME-SC-NUMBER" + "IMMEDIATE-SC-NUMBER" + "CANONICALIZE-INLINE-CONSTANT" + "INLINE-CONSTANT-VALUE" + "SORT-INLINE-CONSTANTS" + "EMIT-INLINE-CONSTANT" + "HEXDUMP" + "INSTANCE-DATA-START" + "INSTANCE-WIDETAG" "INSTANCE-POINTER-LOWTAG" + "INSTANCE-SLOTS-OFFSET" "INSTANCE-USAGE" + "INTERIOR-REG-SC-NUMBER" "INTERNAL-ERROR-ARGS" + "IS-LISP-POINTER" + #+gencgc "LARGE-OBJECT-SIZE" + "LAYOUT" + "LDB-MONITOR" + "LIST-ALLOCATED-OBJECTS" "LIST-POINTER-LOWTAG" + ;; FIXME: Possibly these other parameters (see + ;; compiler/{x86,sparc}/parms.lisp) should be defined + ;; conditionally on #+LONG-FLOAT) + + "LONG-FLOAT-BIAS" "LONG-FLOAT-DIGITS" "LONG-FLOAT-EXPONENT-BYTE" + "LONG-FLOAT-HIDDEN-BIT" "LONG-FLOAT-NORMAL-EXPONENT-MAX" + "LONG-FLOAT-NORMAL-EXPONENT-MIN" "LONG-FLOAT-SIGNIFICAND-BYTE" + #+long-float "LONG-FLOAT-SIZE" + "LONG-FLOAT-TRAPPING-NAN-BIT" + #+long-float "LONG-FLOAT-WIDETAG" + #+long-float "LONG-FLOAT-VALUE-SLOT" + #+long-float "LONG-REG-SC-NUMBER" + #+long-float "LONG-STACK-SC-NUMBER" + "LOWTAG-LIMIT" "LOWTAG-MASK" + "LRA-SAVE-OFFSET" + "MAP-ALLOCATED-OBJECTS" + "MAP-CODE-OBJECTS" + "MAX-INTERRUPTS" + #+c-stack-is-control-stack "MEMORY-FAULT-EMULATION-TRAP" + "UNINITIALIZED-LOAD-TRAP" + "METASPACE-SLAB-SIZE" + "MEMORY-USAGE" + "N-LOWTAG-BITS" + "N-FIXNUM-TAG-BITS" + "N-FIXNUM-BITS" + "N-POSITIVE-FIXNUM-BITS" + "NIL-VALUE" + "NFP-SAVE-OFFSET" + "NON-DESCRIPTOR-REG-SC-NUMBER" + "NULL-SC-NUMBER" + "OCFP-SAVE-OFFSET" + "ODD-FIXNUM-LOWTAG" + "OTHER-IMMEDIATE-0-LOWTAG" + "OTHER-IMMEDIATE-1-LOWTAG" + "OTHER-IMMEDIATE-2-LOWTAG" + "OTHER-IMMEDIATE-3-LOWTAG" + "OTHER-POINTER-LOWTAG" + "PAD0-LOWTAG" "PAD1-LOWTAG" "PAD2-LOWTAG" + "PAD3-LOWTAG" "PAD4-LOWTAG" "PAD5-LOWTAG" + "PAD-DATA-BLOCK" "PENDING-INTERRUPT-TRAP" + "PRIMITIVE-OBJECT" "PRIMITIVE-OBJECT-WIDETAG" + "PRIMITIVE-OBJECT-LOWTAG" "PRIMITIVE-OBJECT-NAME" + "PRIMITIVE-OBJECT-P" + "PRIMITIVE-OBJECT-LENGTH" "PRIMITIVE-OBJECT-SLOTS" + "PRIMITIVE-OBJECT-VARIABLE-LENGTH-P" + "PRINT-ALLOCATED-OBJECTS" + "RATIO-DENOMINATOR-SLOT" "RATIO-NUMERATOR-SLOT" + "RATIO-SIZE" "RATIO-WIDETAG" + "*READ-ONLY-SPACE-FREE-POINTER*" + "RETURN-PC-WIDETAG" + "RETURN-PC-RETURN-POINT-OFFSET" "RETURN-PC-SAVE-OFFSET" + "SAETP-CTYPE" "SAETP-INITIAL-ELEMENT-DEFAULT" + "SAETP-N-BITS" "SAETP-TYPECODE" "SAETP-PRIMITIVE-TYPE-NAME" + "SAETP-N-PAD-ELEMENTS" "SAETP-N-BITS-SHIFT" + "SAETP-SPECIFIER" + "SAETP-COMPLEX-TYPECODE" + "SAETP-FIXNUM-P" + "VALID-BIT-BASH-SAETP-P" + "*SPECIALIZED-ARRAY-ELEMENT-TYPE-PROPERTIES*" + "SANCTIFY-FOR-EXECUTION" + "SAP-POINTER-SLOT" "SAP-REG-SC-NUMBER" "SAP-SIZE" + "SAP-STACK-SC-NUMBER" "SAP-WIDETAG" + "SC-NUMBER-LIMIT" "SC-NUMBER-BITS" ; SC-NUMBER in package "SB-C" + + "SC-OFFSET-LIMIT" "SC-OFFSET-BITS" "SC-OFFSET" + "FINITE-SC-OFFSET-LIMIT" "FINITE-SC-OFFSET-BITS" "FINITE-SC-OFFSET" + "FINITE-SC-OFFSET-MAP" + "SHORT-HEADER-MAX-WORDS" + "SIGFPE-HANDLER" "SIGNED-REG-SC-NUMBER" "SIGNED-STACK-SC-NUMBER" + "SIGNED-WORD" + "SIMPLE-ARRAY-COMPLEX-DOUBLE-FLOAT-WIDETAG" + #+long-float "SIMPLE-ARRAY-COMPLEX-LONG-FLOAT-WIDETAG" + "SIMPLE-ARRAY-COMPLEX-SINGLE-FLOAT-WIDETAG" + "SIMPLE-ARRAY-DOUBLE-FLOAT-WIDETAG" + #+long-float "SIMPLE-ARRAY-LONG-FLOAT-WIDETAG" + "SIMPLE-ARRAY-NIL-WIDETAG" + "SIMPLE-ARRAY-SINGLE-FLOAT-WIDETAG" + "SIMPLE-ARRAY-WIDETAG" + "SIMPLE-ARRAY-UNSIGNED-BYTE-15-WIDETAG" + "SIMPLE-ARRAY-UNSIGNED-BYTE-16-WIDETAG" + "SIMPLE-ARRAY-UNSIGNED-BYTE-2-WIDETAG" + "SIMPLE-ARRAY-UNSIGNED-FIXNUM-WIDETAG" + "SIMPLE-ARRAY-UNSIGNED-BYTE-31-WIDETAG" + "SIMPLE-ARRAY-UNSIGNED-BYTE-32-WIDETAG" + "SIMPLE-ARRAY-UNSIGNED-BYTE-63-WIDETAG" + "SIMPLE-ARRAY-UNSIGNED-BYTE-64-WIDETAG" + "SIMPLE-ARRAY-UNSIGNED-BYTE-4-WIDETAG" + "SIMPLE-ARRAY-UNSIGNED-BYTE-7-WIDETAG" + "SIMPLE-ARRAY-UNSIGNED-BYTE-8-WIDETAG" + "SIMPLE-ARRAY-SIGNED-BYTE-16-WIDETAG" + "SIMPLE-ARRAY-FIXNUM-WIDETAG" + "SIMPLE-ARRAY-SIGNED-BYTE-32-WIDETAG" + "SIMPLE-ARRAY-SIGNED-BYTE-64-WIDETAG" + "SIMPLE-ARRAY-SIGNED-BYTE-8-WIDETAG" + "SIMPLE-BIT-VECTOR-WIDETAG" + "SIMPLE-BASE-STRING-WIDETAG" + #+sb-unicode "SIMPLE-CHARACTER-STRING-WIDETAG" + "SIMPLE-VECTOR-WIDETAG" "SINGLE-FLOAT-BIAS" + "SINGLE-FLOAT-DIGITS" "SINGLE-FLOAT-EXPONENT-BYTE" + "SINGLE-FLOAT-HIDDEN-BIT" "SINGLE-FLOAT-NORMAL-EXPONENT-MAX" + "SINGLE-FLOAT-NORMAL-EXPONENT-MIN" "SINGLE-FLOAT-SIGNIFICAND-BYTE" + "SINGLE-FLOAT-SIZE" + "SINGLE-FLOAT-WIDETAG" + #-64-bit "SINGLE-FLOAT-VALUE-SLOT" + "SINGLE-REG-SC-NUMBER" "SINGLE-STACK-SC-NUMBER" + "SINGLE-STEP-AROUND-TRAP" + "SINGLE-STEP-BEFORE-TRAP" + "SINGLE-STEP-BREAKPOINT-TRAP" + "INVALID-ARG-COUNT-TRAP" + "SINGLE-VALUE-RETURN-BYTE-OFFSET" + "SLOT-NAME" "SLOT-OFFSET" + "SLOT-SPECIAL" + "+STATIC-FDEFNS+" "STATIC-FUN-OFFSET" + "%SPACE-BOUNDS" "SPACE-BYTES" + "STABLE-HASH-REQUIRED-FLAG" + "HASH-SLOT-PRESENT-FLAG" + "STATIC-SYMBOL-OFFSET" "STATIC-SYMBOL-P" + "+STATIC-SYMBOLS+" + "SYMBOL-HASH-SLOT" "SYMBOL-WIDETAG" "SYMBOL-NAME-SLOT" + "SYMBOL-PACKAGE-ID-SLOT" "SYMBOL-INFO-SLOT" "SYMBOL-FDEFN-SLOT" + "SYMBOL-SIZE" "SYMBOL-VALUE-SLOT" "SYMBOL-TLS-INDEX-SLOT" + "*BINDING-STACK-START*" + "*CONTROL-STACK-START*" "*CONTROL-STACK-END*" + "CONTROL-STACK-POINTER-VALID-P" + "DYNAMIC-SPACE-START" + #+gencgc "MAX-DYNAMIC-SPACE-END" + #+gencgc "PAGE-TABLE" + #+gencgc "FIND-PAGE-INDEX" + #+gencgc "NEXT-FREE-PAGE" + #-gencgc "DYNAMIC-0-SPACE-START" + #-gencgc "DYNAMIC-0-SPACE-END" + "READ-ONLY-SPACE-START" "READ-ONLY-SPACE-END" + "STATIC-SPACE-START" "STATIC-SPACE-END" "*STATIC-SPACE-FREE-POINTER*" + "STATIC-CODE-SPACE-START" "STATIC-CODE-SPACE-END" "*STATIC-CODE-SPACE-FREE-POINTER*" + "ALIEN-LINKAGE-TABLE-SPACE-START" + "ALIEN-LINKAGE-TABLE-SPACE-SIZE" + "ALIEN-LINKAGE-TABLE-ENTRY-SIZE" + #+sb-safepoint "GC-SAFEPOINT-PAGE-ADDR" + #+sb-safepoint "GC-SAFEPOINT-TRAP-OFFSET" + "THREAD-STATE-WORD-SLOT" + "THREAD-SPROF-DATA-SLOT" + "TLS-SIZE" "N-WIDETAG-BITS" "WIDETAG-MASK" + "INSTANCE-LENGTH-SHIFT" + "INSTANCE-LENGTH-MASK" + "UNBOUND-MARKER-WIDETAG" + "UNDEFINED-FUNCTION-TRAP" + "NO-TLS-VALUE-MARKER" + "UNSIGNED-REG-SC-NUMBER" "UNSIGNED-STACK-SC-NUMBER" + "UNWIND-BLOCK-CODE-SLOT" "UNWIND-BLOCK-CFP-SLOT" + "UNWIND-BLOCK-UWP-SLOT" "UNWIND-BLOCK-ENTRY-PC-SLOT" + "UNWIND-BLOCK-SIZE" "VALUE-CELL-WIDETAG" "VALUE-CELL-SIZE" + "VALUE-CELL-VALUE-SLOT" "VECTOR-DATA-OFFSET" "VECTOR-LENGTH-SLOT" + "VECTOR-WEAK-FLAG" + "VECTOR-WEAK-VISITED-FLAG" + "VECTOR-HASHING-FLAG" + "VECTOR-ADDR-HASHING-FLAG" + #+(and win32 x86-64) "WIN64-SEH-DATA-ADDR" + "WEAK-POINTER-NEXT-SLOT" + "WEAK-POINTER-SIZE" "WEAK-POINTER-WIDETAG" + "WEAK-POINTER-VALUE-SLOT" + "N-WORD-BITS" "N-WORD-BYTES" "N-MACHINE-WORD-BITS" "N-MACHINE-WORD-BYTES" + "WORD" "WORD-REG-SC-NUMBER" "WORD-SHIFT" + #+win32 "CONTEXT-RESTORE-TRAP" + "ZERO-SC-NUMBER") + #+immobile-space + (:export + "IMMOBILE-CARD-BYTES" + "FIXEDOBJ-SPACE-START" + "FIXEDOBJ-SPACE-SIZE" + "TEXT-SPACE-START" + "TEXT-SPACE-SIZE" + "*FIXEDOBJ-SPACE-FREE-POINTER*" + "*TEXT-SPACE-FREE-POINTER*") + #+sb-simd-pack + (:export + "SIMD-PACK-TAG-SLOT" + "SIMD-PACK-HI-VALUE-SLOT" + "SIMD-PACK-LO-VALUE-SLOT" + "SIMD-PACK-SIZE" + "SIMD-PACK-WIDETAG") + #+sb-simd-pack-256 + (:export + "SIMD-PACK-256-TAG-SLOT" + "SIMD-PACK-256-P0-SLOT" + "SIMD-PACK-256-P1-SLOT" + "SIMD-PACK-256-P2-SLOT" + "SIMD-PACK-256-P3-SLOT" + "SIMD-PACK-256-SIZE" + "SIMD-PACK-256-WIDETAG")) + +(defpackage* "SB-DISASSEM" + (:documentation "private: stuff related to the implementation of the disassembler") + (:use "CL" "SB-EXT" "SB-INT" "SB-SYS" "SB-KERNEL" "SB-DI") + (:export "*DISASSEM-NOTE-COLUMN*" "*DISASSEM-OPCODE-COLUMN-WIDTH*" + "*DISASSEM-LOCATION-COLUMN-WIDTH*" + "ALIGN" ;; prevent it from being removed, older Slime versions are using it + + "ARG-VALUE" "DISASSEM-STATE" + "DISASSEMBLE-CODE-COMPONENT" + "DISASSEMBLE-FUN" "DISASSEMBLE-MEMORY" + "DISASSEMBLE-INSTRUCTION" + "DISASSEMBLE-SEGMENT" "DISASSEMBLE-SEGMENTS" + "DSTATE-BYTE-ORDER" + "DSTATE-GETPROP" + "DSTATE-SETPROP" + "DSTATE-SEGMENT-SAP" + "DSTATE-OPERANDS" + "FIND-INST" + "GET-CODE-SEGMENTS" "GET-FUN-SEGMENTS" + "GET-INST-SPACE" "HANDLE-BREAK-ARGS" + "LABEL-SEGMENTS" + "MAYBE-NOTE-ASSEMBLER-ROUTINE" + "MAYBE-NOTE-ASSOCIATED-STORAGE-REF" + "MAYBE-NOTE-NIL-INDEXED-OBJECT" + "MAYBE-NOTE-NIL-INDEXED-SYMBOL-SLOT-REF" + "MAYBE-NOTE-SINGLE-STORAGE-REF" + "MAYBE-NOTE-STATIC-SYMBOL" + "NOTE" + "NOTE-CODE-CONSTANT" + "OPERAND" + "PRIN1-QUOTED-SHORT" + "PRIN1-SHORT" "PRINT-BYTES" + "PRINT-CURRENT-ADDRESS" "PRINT-INST" + "PRINT-NOTES-AND-NEWLINE" + "SAP-REF-INT" + "SEG-CODE" "SEG-LENGTH" "SEGMENT" + "SIGN-EXTEND" + "MAKE-DSTATE" + "DEFINE-ARG-TYPE" + "READ-SIGNED-SUFFIX" + "MAKE-MEMORY-SEGMENT" + "MAKE-SEGMENT" "SEG-VIRTUAL-LOCATION" + "DCHUNK" "DCHUNK-ZERO" "*DEFAULT-DSTATE-HOOKS*" + "MAKE-CODE-SEGMENT" "MAKE-OFFS-HOOK" + "DSTATE-SEGMENT" "DSTATE-CUR-OFFS" + "PRINC16" "INSTRUCTION" "DEFINE-INSTRUCTION-FORMAT" + "DSTATE-NEXT-OFFS" + "SEG-SAP-MAKER" "DISASSEMBLE-ASSEM-SEGMENT" + "READ-SUFFIX" + "MAP-SEGMENT-INSTRUCTIONS" + "SET-LOCATION-PRINTING-RANGE" "MAKE-VECTOR-SEGMENT" + "DSTATE-CUR-ADDR" "DSTATE-NEXT-ADDR" + "SNARF-ERROR-JUNK")) + +(defpackage* "SB-DEBUG" + (:documentation + "sorta public: Eventually this should become the debugger interface, with +basic stuff like BACKTRACE and ARG. For now, the actual supported interface +is still mixed indiscriminately with low-level internal implementation stuff +like *STACK-TOP-HINT* and unsupported stuff like *TRACED-FUN-LIST*.") + (:use "CL" "SB-EXT" "SB-INT" "SB-SYS" "SB-KERNEL" "SB-DI") + (:export "*BACKTRACE-FRAME-COUNT*" + "*DEBUG-BEGINNER-HELP-P*" + "*DEBUG-CONDITION*" + "*DEBUG-READTABLE*" "*DEBUG-HELP-STRING*" + "*DEBUG-PRINT-VARIABLE-ALIST*" + "*FLUSH-DEBUG-ERRORS*" "*IN-THE-DEBUGGER*" + "*METHOD-FRAME-STYLE*" + "*TRACE-INDENTATION-STEP*" "*MAX-TRACE-INDENTATION*" + "ARG" + "INTERNAL-DEBUG" "VAR" + "*STACK-TOP-HINT*" + "*TRACE-ENCAPSULATE-DEFAULT*" + "*TRACE-REPORT-DEFAULT*" + "FRAME-HAS-DEBUG-TAG-P" + "UNWIND-TO-FRAME-AND-CALL" + ;; Deprecated + + "BACKTRACE" "BACKTRACE-AS-LIST" + ;; Replaced by + + "PRINT-BACKTRACE" "LIST-BACKTRACE")) + +(defpackage* "SB-EXT" + (:documentation "public: miscellaneous supported extensions to the ANSI Lisp spec") + (:use "CL" "SB-ALIEN" "SB-INT" "SB-SYS" "SB-GRAY") + (:import-from "SB-VM" "WORD") + (:import-from "SB-DEBUG" "*DEBUG-PRINT-VARIABLE-ALIST*") + (:export + ;; Information about how the program was invoked is + ;; nonstandard but very useful. + "*POSIX-ARGV*" "*CORE-PATHNAME*" "*RUNTIME-PATHNAME*" + "POSIX-GETENV" "POSIX-ENVIRON" + + ;; Customizing initfile locations + + "*USERINIT-PATHNAME-FUNCTION*" + "*SYSINIT-PATHNAME-FUNCTION*" + + "*DEFAULT-EXTERNAL-FORMAT*" + "*DEFAULT-C-STRING-EXTERNAL-FORMAT*" + + ;; Compare and Swap support + + "CAS" + "COMPARE-AND-SWAP" + "DEFCAS" + "GET-CAS-EXPANSION" + + ;; Other atomic operations and types related to them + + "ATOMIC-INCF" + "ATOMIC-DECF" + "ATOMIC-UPDATE" + "ATOMIC-PUSH" + "ATOMIC-POP" + "WORD" + "MOST-POSITIVE-WORD" + + ;; Not an atomic operation, but should be used with them + + "SPIN-LOOP-HINT" + + ;; Waiting for arbitrary events. + + "WAIT-FOR" + + ;; Time related things + + "CALL-WITH-TIMING" + "GET-TIME-OF-DAY" + + ;; People have various good reasons to mess with the GC. + + "HEAP-ALLOCATED-P" + "STACK-ALLOCATED-P" + "*AFTER-GC-HOOKS*" + "BYTES-CONSED-BETWEEN-GCS" + "GC" "GET-BYTES-CONSED" + "*GC-RUN-TIME*" + "PURIFY" + "DYNAMIC-SPACE-SIZE" + ;; Gencgc only, but symbols exist for manual building + ;; convenience on all platforms. + + "GENERATION-AVERAGE-AGE" + "GENERATION-BYTES-ALLOCATED" + "GENERATION-BYTES-CONSED-BETWEEN-GCS" + "GENERATION-MINIMUM-AGE-BEFORE-GC" + "GENERATION-NUMBER-OF-GCS" + "GENERATION-NUMBER-OF-GCS-BEFORE-PROMOTION" + "GC-LOGFILE" + + ;; Stack allocation control + + "*STACK-ALLOCATE-DYNAMIC-EXTENT*" + + ;; Customizing printing of compiler and debugger messages + + "*COMPILER-PRINT-VARIABLE-ALIST*" + "*DEBUG-PRINT-VARIABLE-ALIST*" + "COMPILE-FILE-LINE" + "COMPILE-FILE-POSITION" + + ;; Hooks into init & save sequences + + "*INIT-HOOKS*" "*SAVE-HOOKS*" "*EXIT-HOOKS*" + "*FORCIBLY-TERMINATE-THREADS-ON-EXIT*" + + ;; Controlling exiting other threads. + + "*EXIT-TIMEOUT*" + + ;; There is no one right way to report progress on + ;; hairy compiles. + + "*COMPILE-PROGRESS*" + + ;; The default behavior for block compilation. + + "*BLOCK-COMPILE-DEFAULT*" + + ;; It can be handy to be able to evaluate expressions involving + ;; the thing under examination by CL:INSPECT. + + "*INSPECTED*" + + ;; There is no one right way to do efficiency notes. + + "*EFFICIENCY-NOTE-COST-THRESHOLD*" "*EFFICIENCY-NOTE-LIMIT*" + + ;; There's no one right way to report errors. + + "*ENCLOSING-SOURCE-CUTOFF*" + "*UNDEFINED-WARNING-LIMIT*" + + ;; and for dedicated users who really want to customize + ;; error reporting, we have + + "DEFINE-SOURCE-CONTEXT" + "WITH-CURRENT-SOURCE-FORM" + + ;; and given how many users dislike strict treatment of + ;; DEFCONSTANT, let's give them enough rope to escape by + + "DEFCONSTANT-UNEQL" "DEFCONSTANT-UNEQL-NAME" + "DEFCONSTANT-UNEQL-NEW-VALUE" "DEFCONSTANT-UNEQL-OLD-VALUE" + + ;; global lexicals, access to global symbol values + + "DEFGLOBAL" + "DEFINE-LOAD-TIME-GLOBAL" + "SYMBOL-GLOBAL-VALUE" + + "FILE-EXISTS" + "FILE-DOES-NOT-EXIST" + "DELETE-FILE-ERROR" + "SUPERSEDE" + "OVERWRITE" + "RENAME" + "CREATE" + "RETRY" + + ;; package extensions + ;; + ;; locks + + "PACKAGE-LOCKED-P" + "LOCK-PACKAGE" + "UNLOCK-PACKAGE" + "PACKAGE-IMPLEMENTED-BY-LIST" + "PACKAGE-IMPLEMENTS-LIST" + "ADD-IMPLEMENTATION-PACKAGE" + "REMOVE-IMPLEMENTATION-PACKAGE" + "WITH-UNLOCKED-PACKAGES" + "PACKAGE-LOCK-VIOLATION" + "PACKAGE-LOCKED-ERROR" + "SYMBOL-PACKAGE-LOCKED-ERROR" + "PACKAGE-LOCKED-ERROR-SYMBOL" + "WITHOUT-PACKAGE-LOCKS" + "DISABLE-PACKAGE-LOCKS" + "ENABLE-PACKAGE-LOCKS" + ;; local nicknames + + "ADD-PACKAGE-LOCAL-NICKNAME" + "REMOVE-PACKAGE-LOCAL-NICKNAME" + "PACKAGE-LOCAL-NICKNAMES" + "PACKAGE-LOCALLY-NICKNAMED-BY-LIST" + + "PACKAGE-DOES-NOT-EXIST" "READER-PACKAGE-DOES-NOT-EXIST" + ;; behaviour on DEFPACKAGE* variance + + "*ON-PACKAGE-VARIANCE*" + + ;; Custom conditions & condition accessors for users to handle. + + "CODE-DELETION-NOTE" + "COMPILER-NOTE" + "IMPLICIT-GENERIC-FUNCTION-NAME" + "IMPLICIT-GENERIC-FUNCTION-WARNING" + "INVALID-FASL" + + "NAME-CONFLICT" "NAME-CONFLICT-FUNCTION" + "NAME-CONFLICT-DATUM" "NAME-CONFLICT-SYMBOLS" + "RESOLVE-CONFLICT" + + ;; Deprecation stuff + + "DEPRECATED" ; declaration + + "DEPRECATION-CONDITION" + "DEPRECATION-CONDITION-NAMESPACE" + "DEPRECATION-CONDITION-NAME" + "DEPRECATION-CONDITION-SOFTWARE" + "DEPRECATION-CONDITION-VERSION" + "DEPRECATION-CONDITION-REPLACEMENTS" + "DEPRECATION-CONDITION-RUNTIME-ERROR" + "EARLY-DEPRECATION-WARNING" + "LATE-DEPRECATION-WARNING" + "FINAL-DEPRECATION-WARNING" + "DEPRECATION-ERROR" ; condition and function + + + "PRINT-UNREADABLY" + + ;; Readtable normalization control + + "READTABLE-BASE-CHAR-PREFERENCE" + "READTABLE-NORMALIZATION" + + ;; and a mechanism for controlling same at compile time + + "MUFFLE-CONDITIONS" "UNMUFFLE-CONDITIONS" + + ;; and one for controlling same at runtime + + "*MUFFLED-WARNINGS*" + + ;; specification which print errors to ignore ala *break-on-signal* + + "*SUPPRESS-PRINT-ERRORS*" + + ;; extended declarations.. + + "ALWAYS-BOUND" "FREEZE-TYPE" "GLOBAL" "INHIBIT-WARNINGS" + "MAYBE-INLINE" "START-BLOCK" "END-BLOCK" + + ;; ..and variables to control compiler policy + + "*INLINE-EXPANSION-LIMIT*" + "*DERIVE-FUNCTION-TYPES*" + + ;; ..and inspector of compiler policy + + "DESCRIBE-COMPILER-POLICY" + "RESTRICT-COMPILER-POLICY" + "SET-MACRO-POLICY" + "FOLD-IDENTICAL-CODE" ; this is a verb, not a compiler policy + + ;; a special form for breaking out of our "declarations + ;; are assertions" default + + "TRULY-THE" + + ;; Misc. array and vector tools. + + "ARRAY-STORAGE-VECTOR" + "PRIMITIVE-OBJECT-SIZE" + + ;; This is something which must exist inside any Common + ;; Lisp implementation, and which someone writing a + ;; customized toplevel might well want. It seems perverse + ;; to hide it from them.. + + "INTERACTIVE-EVAL" + + ;; Used by LOAD and EVAL-WHEN to pass toplevel indexes + ;; to compiler. + + "EVAL-TLF" + + ;; weak pointers and finalization + + "CANCEL-FINALIZATION" + "FINALIZE" + "MAKE-WEAK-POINTER" + "WEAK-POINTER" + "WEAK-POINTER-P" + "WEAK-POINTER-VALUE" + "MAKE-WEAK-VECTOR" + "WEAK-VECTOR-P" + + ;; Hash table extensions + + "DEFINE-HASH-TABLE-TEST" + "HASH-TABLE-SYNCHRONIZED-P" + "HASH-TABLE-WEAKNESS" + "WITH-LOCKED-HASH-TABLE" + + ;; If the user knows we're doing IEEE, he might reasonably + ;; want to do this stuff. + + "FLOAT-DENORMALIZED-P" + "FLOAT-NAN-P" "FLOAT-TRAPPING-NAN-P" + "FLOAT-INFINITY-P" + "SHORT-FLOAT-NEGATIVE-INFINITY" + "SHORT-FLOAT-POSITIVE-INFINITY" + "SINGLE-FLOAT-NEGATIVE-INFINITY" + "SINGLE-FLOAT-POSITIVE-INFINITY" + "DOUBLE-FLOAT-NEGATIVE-INFINITY" + "DOUBLE-FLOAT-POSITIVE-INFINITY" + "LONG-FLOAT-NEGATIVE-INFINITY" + "LONG-FLOAT-POSITIVE-INFINITY" + + ;; saving Lisp images + + "SAVE-LISP-AND-DIE" + + ;; provided for completeness to make it more convenient + ;; to use command-line --disable-debugger functionality + ;; in oddball situations (like building core files using + ;; scripts which run unattended, when the core files are + ;; intended for interactive use) + + "DISABLE-DEBUGGER" + "ENABLE-DEBUGGER" + + ;; the mechanism by which {en,dis}able-debugger works is + ;; also exported for people writing alternative toplevels + ;; (Emacs, CLIM interfaces, etc) + + "*INVOKE-DEBUGGER-HOOK*" + + ;; miscellaneous useful supported extensions + + "QUIT" "EXIT" + "*ED-FUNCTIONS*" + "*MODULE-PROVIDER-FUNCTIONS*" + "MAP-DIRECTORY" + "WITH-TIMEOUT" "TIMEOUT" + "SEED-RANDOM-STATE" + "TYPEXPAND-1" "TYPEXPAND" "TYPEXPAND-ALL" + "DEFINED-TYPE-NAME-P" "VALID-TYPE-SPECIFIER-P" + "DELETE-DIRECTORY" + "SET-SBCL-SOURCE-LOCATION" + "*DISASSEMBLE-ANNOTATE*" + "PRINT-SYMBOL-WITH-PREFIX" + "*PRINT-VECTOR-LENGTH*" + "DECIMAL-WITH-GROUPED-DIGITS-WIDTH" + ;;"OBJECT-SIZE" + + ;; stepping interface + + "STEP-CONDITION" "STEP-FORM-CONDITION" "STEP-FINISHED-CONDITION" + "STEP-VALUES-CONDITION" + "STEP-CONDITION-FORM" "STEP-CONDITION-RESULT" + "STEP-CONTINUE" "STEP-NEXT" "STEP-INTO" + "STEP-CONDITION-ARGS" "*STEPPER-HOOK*" "STEP-OUT" + + ;; RUN-PROGRAM is not only useful for users, but also + ;; useful to implement parts of SBCL itself, so we're + ;; going to have to implement it anyway, so we might + ;; as well support it. And then once we're committed + ;; to implementing RUN-PROGRAM, it's nice to have it + ;; return a PROCESS object with operations defined on + ;; that object. + + "RUN-PROGRAM" + "PROCESS-ALIVE-P" "PROCESS-CLOSE" + "PROCESS-CORE-DUMPED" "PROCESS-ERROR" "PROCESS-EXIT-CODE" + "PROCESS-INPUT" "PROCESS-KILL" "PROCESS-OUTPUT" "PROCESS-P" + "PROCESS-PID" "PROCESS-PLIST" "PROCESS-PTY" "PROCESS-STATUS" + "PROCESS-STATUS-HOOK" "PROCESS-WAIT" + + ;; pathnames + + "NATIVE-PATHNAME" + "PARSE-NATIVE-NAMESTRING" + "NATIVE-NAMESTRING" + + ;; external-format support + + "OCTETS-TO-STRING" "STRING-TO-OCTETS" + + ;; Whether to use the interpreter or the compiler for EVAL + + "*EVALUATOR-MODE*" + + ;; timer + + "TIMER" "MAKE-TIMER" "TIMER-NAME" "TIMER-SCHEDULED-P" + "SCHEDULE-TIMER" "UNSCHEDULE-TIMER" "LIST-ALL-TIMERS" + + ;; versioning utility + + "ASSERT-VERSION->=" + "UNKNOWN-KEYWORD-ARGUMENT" + "UNKNOWN-KEYWORD-ARGUMENT-NAME") + ;; SIMD pack + #+sb-simd-pack + (:export + "SIMD-PACK" + "SIMD-PACK-P" + "%MAKE-SIMD-PACK-UB32" + "%MAKE-SIMD-PACK-UB64" + "%MAKE-SIMD-PACK-DOUBLE" + "%MAKE-SIMD-PACK-SINGLE" + "%SIMD-PACK-UB8S" + "%SIMD-PACK-UB16S" + "%SIMD-PACK-UB32S" + "%SIMD-PACK-UB64S" + "%SIMD-PACK-SB8S" + "%SIMD-PACK-SB16S" + "%SIMD-PACK-SB32S" + "%SIMD-PACK-SB64S" + "%SIMD-PACK-DOUBLES" + "%SIMD-PACK-SINGLES") + #+sb-simd-pack-256 + (:export + "SIMD-PACK-256" + "SIMD-PACK-256-P" + "%MAKE-SIMD-PACK-256-UB32" + "%MAKE-SIMD-PACK-256-UB64" + "%MAKE-SIMD-PACK-256-DOUBLE" + "%MAKE-SIMD-PACK-256-SINGLE" + "%SIMD-PACK-256-UB8S" + "%SIMD-PACK-256-UB16S" + "%SIMD-PACK-256-UB32S" + "%SIMD-PACK-256-UB64S" + "%SIMD-PACK-256-SB8S" + "%SIMD-PACK-256-SB16S" + "%SIMD-PACK-256-SB32S" + "%SIMD-PACK-256-SB64S" + "%SIMD-PACK-256-DOUBLES" + "%SIMD-PACK-256-SINGLES")) + +(defpackage* "SB-DI" + (:documentation "private: primitives used to write debuggers") + (:use "CL" "SB-EXT" "SB-INT" "SB-KERNEL" "SB-SYS" "SB-VM") + (:import-from "SB-C" + "DEBUG-SOURCE" "DEBUG-SOURCE-NAMESTRING" + "DEBUG-SOURCE-CREATED" "DEBUG-SOURCE-P" + "DEBUG-SOURCE-START-POSITIONS" "MAKE-DEBUG-SOURCE" + "CORE-DEBUG-SOURCE" "CORE-DEBUG-SOURCE-P" + "CORE-DEBUG-SOURCE-FORM") + (:export "ACTIVATE-BREAKPOINT" + "AMBIGUOUS-DEBUG-VARS" "AMBIGUOUS-VAR-NAME" "BREAKPOINT" + "BREAKPOINT-ACTIVE-P" "BREAKPOINT-HOOK-FUN" "BREAKPOINT-INFO" + "BREAKPOINT-KIND" "BREAKPOINT-P" "BREAKPOINT-WHAT" "CODE-LOCATION" + "CODE-LOCATION-DEBUG-BLOCK" "CODE-LOCATION-DEBUG-FUN" + "CODE-LOCATION-DEBUG-SOURCE" "CODE-LOCATION-FORM-NUMBER" + "CODE-LOCATION-P" "CODE-LOCATION-TOPLEVEL-FORM-OFFSET" + "CODE-LOCATION-CONTEXT" + "CODE-LOCATION-UNKNOWN-P" "CODE-LOCATION=" "DEACTIVATE-BREAKPOINT" + "DEBUG-BLOCK" "DEBUG-BLOCK-ELSEWHERE-P" "DEBUG-BLOCK-P" + "DEBUG-CONDITION" "DEBUG-ERROR" + "DEBUG-FUN" "DEBUG-FUN-FUN" "DEBUG-FUN-KIND" + "DEBUG-FUN-LAMBDA-LIST" "DEBUG-FUN-NAME" "DEBUG-FUN-CLOSURE-NAME" + "DEBUG-FUN-P" "DEBUG-FUN-START-LOCATION" + "DEBUG-FUN-SYMBOL-VARS" "DEBUG-SOURCE" + "DEBUG-SOURCE-CREATED" "DEBUG-SOURCE-NAMESTRING" + "DEBUG-SOURCE-P" "DEBUG-SOURCE-START-POSITIONS" + "DEBUG-VAR" "DEBUG-VAR-ID" "DEBUG-VAR-INFO-AVAILABLE" + "DEBUG-VAR-SYMBOL-NAME" "DEBUG-VAR-P" "DEBUG-VAR-PACKAGE-NAME" + "DEBUG-VAR-SYMBOL" "DEBUG-VAR-VALID-VALUE" + "DEBUG-VAR-VALIDITY" "DEBUG-VAR-VALUE" + "DELETE-BREAKPOINT" + "DO-DEBUG-BLOCK-LOCATIONS" "DO-DEBUG-FUN-BLOCKS" + "DO-DEBUG-FUN-VARS" + "ERROR-CONTEXT" + "FORM-NUMBER-TRANSLATIONS" + "FRAME" "FRAME-CATCHES" "FRAME-CODE-LOCATION" + "FRAME-DEBUG-FUN" "FRAME-DOWN" + "FRAME-FUN-MISMATCH" "FRAME-NUMBER" "FRAME-P" "FRAME-UP" + "GET-TOPLEVEL-FORM" + "REPLACE-FRAME-CATCH-TAG" + "FUN-DEBUG-FUN" "FUN-END-COOKIE-VALID-P" + "INVALID-CONTROL-STACK-POINTER" "INVALID-VALUE" + "LAMBDA-LIST-UNAVAILABLE" "MAKE-BREAKPOINT" "NO-DEBUG-BLOCKS" + "NO-DEBUG-FUN-RETURNS" "PREPROCESS-FOR-EVAL" + "EVAL-IN-FRAME" "RETURN-FROM-FRAME" "SOURCE-PATH-CONTEXT" + "TOP-FRAME" "UNHANDLED-DEBUG-CONDITION" + "UNKNOWN-DEBUG-VAR" + "CODE-LOCATION-KIND" "FLUSH-FRAMES-ABOVE")) + +#+sb-dyncount +(defpackage* "SB-DYNCOUNT" + (:documentation "private: some somewhat-stale code for collecting runtime statistics") + (:use "CL" "SB-ALIEN-INTERNALS" "SB-ALIEN" "SB-BIGNUM" + "SB-EXT" "SB-INT" "SB-KERNEL" "SB-ASSEM" "SB-SYS") + (:export "*COLLECT-DYNAMIC-STATISTICS*" + "COUNT-ME" + "DYNCOUNT-INFO-COUNTS" "DYNCOUNT-INFO-COSTS" + "IR2-COMPONENT-DYNCOUNT-INFO" + "DYNCOUNT-INFO" "DYNCOUNT-INFO-P")) + +(defpackage* "SB-FASL" + (:documentation "private: stuff related to FASL load/dump logic (and GENESIS)") + (:use "CL" "SB-ALIEN" "SB-ASSEM" "SB-BIGNUM" "SB-C" + "SB-EXT" "SB-INT" "SB-KERNEL" "SB-SYS") + (:import-from "SB-VM" "+FIXUP-KINDS+") + (:import-from "SB-IMPL" "FIND-OR-MAYBE-MAKE-DEFERRED-PACKAGE" "WITH-LOADER-PACKAGE-NAMES") + (:export "*ASSEMBLER-ROUTINES*" + "GET-ASM-ROUTINE" + "+BACKEND-FASL-FILE-IMPLEMENTATION+" + "*FASL-FILE-TYPE*" + "CLOSE-FASL-OUTPUT" + "DUMP-ASSEMBLER-ROUTINES" + "DUMP-FOP" "DUMP-OBJECT" + "FASL-CONSTANT-ALREADY-DUMPED-P" + "+FASL-FILE-VERSION+" + "FASL-DUMP-COMPONENT" + "FASL-DUMP-LOAD-TIME-VALUE-LAMBDA" + "FASL-DUMP-PARTIAL-SOURCE-INFO" + "FASL-DUMP-SOURCE-INFO" "FASL-DUMP-TOPLEVEL-LAMBDA-CALL" + "FASL-NOTE-HANDLE-FOR-CONSTANT" + "FASL-OUTPUT" "FASL-OUTPUT-P" + "FASL-OUTPUT-ENTRY-TABLE" "FASL-OUTPUT-STREAM" + "FASL-VALIDATE-STRUCTURE" + "FASL-NOTE-INSTANCE-SAVES-SLOTS" + "*!LOAD-TIME-VALUES*" + "OPEN-FASL-OUTPUT" + "*!COLD-TOPLEVELS*" + "COLD-CONS" "COLD-INTERN" "COLD-PUSH")) + +(defpackage* "SB-C" + (:documentation "private: implementation of the compiler") + ;; (It seems strange to have the compiler USE SB-ALIEN-INTERNALS, + ;; but the point seems to be to be able to express things like + ;; SB-C:DEFTRANSFORM SB-ALIEN-INTERNALS:MAKE-LOCAL-ALIEN without + ;; having to use a bunch of package prefixes, by putting them + ;; in the SB-C package. Maybe it'd be tidier to define an SB-ALIEN-COMP + ;; package for this? But it seems like a fairly low priority.) + ;; (Probably the same considerations also explain why BIGNUM is + ;;in the USE list.) + (:use "CL" "SB-ALIEN-INTERNALS" "SB-ALIEN" "SB-ASSEM" "SB-BIGNUM" + #+sb-dyncount "SB-DYNCOUNT" "SB-EXT" "SB-FASL" "SB-INT" + "SB-KERNEL" "SB-SYS") + (:export "%ALIEN-FUNCALL" + "%CATCH-BREAKUP" "%CONTINUE-UNWIND" "%UNWIND" + "%LISTIFY-REST-ARGS" "%MORE-ARG" "%MORE-ARG-VALUES" + "%UNWIND-PROTECT-BREAKUP" + + "*BACKEND-BYTE-ORDER*" + "+BACKEND-INTERNAL-ERRORS+" "+BACKEND-PAGE-BYTES+" + "*BACKEND-REGISTER-SAVE-PENALTY*" + "*BACKEND-SBS*" ; storage bases + + "*BACKEND-SC-NAMES*" "*BACKEND-SC-NUMBERS*" + "*BACKEND-SUBFEATURES*" + "*BACKEND-T-PRIMITIVE-TYPE*" + + "*COMPILATION*" + "*COMPILE-TO-MEMORY-SPACE*" + "*LEXENV*" + "*SUPPRESS-VALUES-DECLARATION*" + + #+x86 "SET-FPU-WORD-FOR-C" + #+x86 "SET-FPU-WORD-FOR-LISP" + "ALIGN-STACK-POINTER" + "ALIEN-FUNCALL-SAVES-FP-AND-PC" + "ALLOC-ALIEN-STACK-SPACE" "ALLOC-NUMBER-STACK-SPACE" + "ALLOCATE-CODE-OBJECT" "ALLOCATE-FRAME" + "ALLOCATE-FULL-CALL-FRAME" + "ALWAYS-TRANSLATABLE" + "ANCESTOR-FRAME-REF" "ANCESTOR-FRAME-SET" + "ANY" "ASSEMBLE-FILE" + "ATTRIBUTES" "ATTRIBUTES-INTERSECTION" "ATTRIBUTES-UNION" + "ATTRIBUTES=" + "BRANCH" + "CALL" "CALL-LOCAL" "CALL-NAMED" "CALL-VARIABLE" + "CALL-OUT" "CALL-OUT-NAMED" + "CALLEE-NFP-TN" "CALLEE-RETURN-PC-TN" + "CATCH-BLOCK" "UNWIND-BLOCK" + "CLOSURE-INIT" "CLOSURE-REF" "CLOSURE-INIT-FROM-FP" + "COMPARE-AND-SWAP-SLOT" + "COMPILE-IN-LEXENV" + "COMPILE-FILES" + "COMPILED-DEBUG-FUN-FORM-NUMBER" + "%COMPILER-DEFUN" "COMPILER-ERROR" "FATAL-COMPILER-ERROR" + "COMPILER-NOTIFY" + "COMPILER-STYLE-WARN" "COMPILER-WARN" + "COMPONENT" "COMPONENT-HEADER-LENGTH" + "COMPONENT-INFO" "COMPONENT-LIVE-TN" + "COMPONENT-N-JUMP-TABLE-ENTRIES" + "COMPUTE-FUN" "COMPUTE-OLD-NFP" "COPY-MORE-ARG" + "CURRENT-BINDING-POINTER" "CURRENT-NFP-TN" + "CURRENT-STACK-POINTER" + "*ALIEN-STACK-POINTER*" + "CURRENT-NSP" "SET-NSP" + "DEALLOC-NUMBER-STACK-SPACE" + "DEBUG-CATCH-TAG" + "DEF-IR1-TRANSLATOR" + "!DEF-PRIMITIVE-TYPE" "!DEF-PRIMITIVE-TYPE-ALIAS" + "DEFINE-SOURCE-TRANSFORM" + "DEFINITION-SOURCE-LOCATION" + "DEFINITION-SOURCE-LOCATION-NAMESTRING" + "DEFINITION-SOURCE-LOCATION-TOPLEVEL-FORM-NUMBER" + "DEFINITION-SOURCE-LOCATION-FORM-NUMBER" + "DEFINITION-SOURCE-LOCATION-PLIST" + "DEFINE-MODULAR-FUN" + "DEFINE-MOVE-FUN" + "DEFINE-MOVE-VOP" "!DEFINE-STORAGE-BASES" + "!DEFINE-STORAGE-CLASS" "DEFINE-VOP" + "DEFKNOWN" "DEFOPTIMIZER" + "DEFTRANSFORM" "DERIVE-TYPE" + "DIS" + "DO-FORMS-FROM-INFO" + "EMIT-BLOCK-HEADER" + "ENVIRONMENT-DEBUG-LIVE-TN" "ENVIRONMENT-LIVE-TN" + "FAST-SYMBOL-VALUE" + "FAST-SYMBOL-GLOBAL-VALUE" + "FIXUP-NOTE-KIND" + "FIXUP-NOTE-FIXUP" + "FIXUP-NOTE-POSITION" + "FLUSHABLE" "FOLDABLE" + "FORCE-TN-TO-STACK" + "FUN-INFO-DERIVE-TYPE" "FUN-INFO-IR2-CONVERT" + "FUN-INFO-LTN-ANNOTATE" "FUN-INFO-OPTIMIZER" + "GET-TOPLEVELISH-FILE-INFO" + "HALT" + "IF-EQ" + "CONSTANT-LVAR-P" + "CONSTANT-TN-P" + "INSERT-SAFEPOINTS" + "COMPILER-MACRO-APPLICATION-MISSED-WARNING" + "INLINING-DEPENDENCY-FAILURE" + "INSERT-ARRAY-BOUNDS-CHECKS" + "INSERT-STEP-CONDITIONS" + "INSTRUMENT-CONSING" + "IR2-COMPONENT-CONSTANTS" "IR2-CONVERT" + "IR2-ENVIRONMENT-NUMBER-STACK-P" + "KNOWN-CALL-LOCAL" "KNOWN-RETURN" + "LAMBDA-VAR-IGNOREP" + "LAMBDA-WITH-LEXENV" "LEXENV-FIND" + "LOCATION=" "LTN-ANNOTATE" + "LVAR-VALUE" + "MACRO-POLICY-DECLS" + "MAKE-ALIAS-TN" "MAKE-CATCH-BLOCK" + "MAKE-CLOSURE" "MAKE-CONSTANT-TN" + "MAKE-FIXUP-NOTE" + "MAKE-LOAD-TIME-CONSTANT-TN" "MAKE-N-TNS" "MAKE-NORMAL-TN" + "MAKE-RANDOM-TN" + "MAKE-REPRESENTATION-TN" "MAKE-RESTRICTED-TN" + "MAKE-STACK-POINTER-TN" "MAKE-TN-REF" "MAKE-UNWIND-BLOCK" + "MAKE-WIRED-TN" "MAYBE-COMPILER-NOTIFY" + "INLINE-SYNTACTIC-CLOSURE-LAMBDA" + "MSAN-UNPOISON" + "MOVABLE" "MOVE" "MULTIPLE-CALL" + "MULTIPLE-CALL-LOCAL" "MULTIPLE-CALL-NAMED" + "MULTIPLE-CALL-VARIABLE" + "%%NIP-VALUES" + "NLX-ENTRY" "NLX-ENTRY-MULTIPLE" "NLX-ENTRY-SINGLE" + "NODE-STACK-ALLOCATE-P" + "NON-DESCRIPTOR-STACK" "NOTE-ENVIRONMENT-START" + "NOTE-THIS-LOCATION" "*LOCATION-CONTEXT*" + "MAKE-RESTART-LOCATION" + "OPTIMIZER" + "PACK-CODE-FIXUP-LOCS" + "PARSE-EVAL-WHEN-SITUATIONS" + "POLICY" + "PRIMITIVE-TYPE" "PRIMITIVE-TYPE-OF" + "PRIMITIVE-TYPE-OR-LOSE" + "PRIMITIVE-TYPE-NAME" + "PRIMITIVE-TYPE-INDIRECT-CELL-TYPE" + "PROCLAIM-FTYPE" "PROCLAIM-TYPE" + "PUSH-VALUES" + "READ-PACKED-BIT-VECTOR" + "READ-VAR-INTEGER" "READ-VAR-INTEGERF" + "SAP-READ-VAR-INTEGER" "SAP-READ-VAR-INTEGERF" + "READ-VAR-STRING" + "REFERENCE-TN" "REFERENCE-TN-LIST" + "REGISTER-INLINE-CONSTANT" + "RESET-STACK-POINTER" "RESTORE-DYNAMIC-STATE" + "RETURN-MULTIPLE" "SAVE-DYNAMIC-STATE" "STORAGE-BASE" + "SB-ALLOCATED-SIZE" "SB-NAME" "SB-OR-LOSE" + "STORAGE-CLASS" "SC-CASE" "SC-OPERAND-SIZE" + "SC-IS" "SC-NAME" "SC-NUMBER" "SC-SB" + "SC-OR-LOSE" "SC-NUMBER-OR-LOSE" + "SC+OFFSET" "MAKE-SC+OFFSET" "SC+OFFSET-OFFSET" "SC+OFFSET-SCN" + "SET-UNWIND-PROTECT" + "SETUP-CLOSURE-ENVIRONMENT" + "SOURCE-LOCATION" + "SPECIFY-SAVE-TN" + "STATIC-CALL-NAMED" "STATIC-MULTIPLE-CALL-NAMED" "STATIC-TAIL-CALL-NAMED" + "STORE-COVERAGE-DATA" "STORE-SOURCE-FORM" + "TAIL-CALL" "TAIL-CALL-NAMED" + "TAIL-CALL-VARIABLE" "TEMPLATE-OR-LOSE" + "TN" "TN-OFFSET" "TN-P" "TN-REF" "TN-REF-ACROSS" "TN-REF-LOAD-TN" + "TN-REF-NEXT" "TN-REF-NEXT-REF" "TN-REF-P" "TN-REF-TARGET" + "TN-REF-TN" "TN-REF-TYPE" "TN-REF-VOP" "TN-REF-WRITE-P" "TN-SC" + "TN-REF-MEMORY-ACCESS" + "TN-KIND" "TN-VALUE" + "TYPE-CHECK-ERROR" "UNBIND" "UNBIND-N" "UNBIND-TO-HERE" + "UNSAFE" "UNSAFELY-FLUSHABLE" "UNWIND" "UWP-ENTRY" + "UNPACK-CODE-FIXUP-LOCS" + "VERIFY-ARG-COUNT" "WRITE-PACKED-BIT-VECTOR" + "WRITE-VAR-INTEGER" "WRITE-VAR-STRING" "XEP-ALLOCATE-FRAME" + "XEP-SETUP-SP" + "LABEL-ID" "FIXUP" "FIXUP-FLAVOR" "FIXUP-NAME" "FIXUP-OFFSET" + "FIXUP-P" "MAKE-FIXUP" + "SLOT" + "DEF-ALLOC" + "VAR-ALLOC" + "SAFE-FDEFN-FUN" + "NOTE-FIXUP" + "DEF-CASSER" + "DEF-REFFER" + "EMIT-CONSTANT" + "EMIT-NOP" + "DEF-SETTER" + "FIXED-ALLOC" + "MAKE-FUNCALLABLE-INSTANCE-TRAMP" + "RETURN-SINGLE" + "NOTE-NEXT-INSTRUCTION" + "SET-SLOT" + "LOCATION-NUMBER" + "*COMPONENT-BEING-COMPILED*" + "BLOCK-NUMBER" + "IR2-BLOCK-BLOCK" + "VOP-BLOCK" + "VOP-NEXT" "NEXT-VOP-IS" "REPLACE-VOPS" + "VOP-NAME" "VOP-CODEGEN-INFO" + + "IMMEDIATE-CONSTANT-SC" + "BOXED-IMMEDIATE-SC-P" + "COMBINATION-IMPLEMENTATION-STYLE" + "CONVERT-CONDITIONAL-MOVE-P" + "LOCATION-PRINT-NAME" + "MAKE-CALL-OUT-TNS" + "STANDARD-ARG-LOCATION" + "STANDARD-ARG-LOCATION-SC" + "ARG-COUNT-SC" + "CLOSURE-SC" + "MAKE-RETURN-PC-PASSING-LOCATION" + "MAKE-OLD-FP-PASSING-LOCATION" + "MAKE-OLD-FP-SAVE-LOCATION" + "RETURN-PC-PASSING-OFFSET" + "OLD-FP-PASSING-OFFSET" + "MAKE-RETURN-PC-SAVE-LOCATION" + "MAKE-ARG-COUNT-LOCATION" + "MAKE-NFP-TN" + "MAKE-NUMBER-STACK-POINTER-TN" + "MAKE-UNKNOWN-VALUES-LOCATIONS" + "MAKE-NLX-SP-TN" + "MAKE-DYNAMIC-STATE-TNS" + "MAKE-NLX-ENTRY-ARG-START-LOCATION" + "GENERATE-CALL-SEQUENCE" + "GENERATE-RETURN-SEQUENCE" + "WITH-COMPILER-ERROR-RESIGNALLING" + "XDEFUN" ; extended defun for defstruct + + + "BRANCH-IF" "MULTIWAY-BRANCH-IF-EQ" + + ;; for SB-COVER + + "*CODE-COVERAGE-INFO*" "CODE-COVERAGE-RECORD-MARKED" + "CLEAR-CODE-COVERAGE" "RESET-CODE-COVERAGE" + "+CODE-COVERAGE-UNMARKED+" + ;; for SB-INTROSPECT + + "MAP-PACKED-XREF-DATA" "MAP-SIMPLE-FUNS" + + "DO-BLOCKS" "DO-BLOCKS-BACKWARDS" + "DO-NODES" "DO-NODES-BACKWARDS" + "DO-IR2-BLOCKS")) + +(defpackage* "SB-REGALLOC" + (:documentation "private: implementation of the compiler's register allocator") + (:use "CL" "SB-ALIEN-INTERNALS" "SB-ALIEN" "SB-ASSEM" "SB-BIGNUM" + #+sb-dyncount "SB-DYNCOUNT" "SB-EXT" "SB-FASL" "SB-INT" + "SB-KERNEL" "SB-SYS" + "SB-C") + (:import-from "SB-C" + "*LOOP-ANALYZE*" + "BLOCK-INFO" "BLOCK-LAST" "BLOCK-LOOP" "BLOCK-NEXT" + "CLEAR-BIT-VECTOR" "COMPONENT-HEAD" "COMPONENT-TAIL" + "DEFEVENT" "DELETE-VOP" "DO-IR2-BLOCKS" "DO-LIVE-TNS" + "EMIT-LOAD-TEMPLATE" "EVENT" "FIND-IN" + "FINITE-SB" "FINITE-SB-ALWAYS-LIVE" + "FINITE-SB-WIRED-MAP" "FINITE-SB-CONFLICTS" + "FINITE-SB-CURRENT-SIZE" "FINITE-SB-LAST-BLOCK-COUNT" + "FINITE-SB-LAST-OFFSET" "FINITE-SB-LIVE-TNS" + "FINITE-SB-SIZE-ALIGNMENT" "FINITE-SB-SIZE-INCREMENT" + "GET-OPERAND-INFO" "GLOBAL-CONFLICTS-BLOCK" + "GLOBAL-CONFLICTS-CONFLICTS" "GLOBAL-CONFLICTS-KIND" + "GLOBAL-CONFLICTS-NEXT-TNWISE" "GLOBAL-CONFLICTS-NUMBER" + "GLOBAL-CONFLICTS-NEXT-BLOCKWISE" "GLOBAL-CONFLICTS-TN" + "IR2-BLOCK" "IR2-BLOCK-COUNT" "IR2-BLOCK-GLOBAL-TNS" + "IR2-BLOCK-LAST-VOP" "IR2-BLOCK-LIVE-IN" + "IR2-BLOCK-LOCAL-TN-COUNT" "IR2-BLOCK-LOCAL-TNS" + "IR2-BLOCK-NEXT" "IR2-BLOCK-NUMBER" "IR2-BLOCK-PREV" + "IR2-BLOCK-START-VOP" "IR2-COMPONENT" + "IR2-COMPONENT-GLOBAL-TN-COUNTER" + "IR2-COMPONENT-NORMAL-TNS" "IR2-COMPONENT-RESTRICTED-TNS" + "IR2-COMPONENT-SPILLED-TNS" "IR2-COMPONENT-SPILLED-VOPS" + "IR2-COMPONENT-WIRED-TNS" + "LAMBDA-PARENT" "LEXENV-LAMBDA" "LISTIFY-RESTRICTIONS" + "LOCAL-TN-BIT-VECTOR" "LOCAL-TN-COUNT" "LOCAL-TN-LIMIT" + "LOCAL-TN-NUMBER" "LOCAL-TN-VECTOR" + "LOOP-DEPTH" "MAKE-TN" "MOVE-OPERAND" "NODE" "NODE-LEXENV" + "OPERAND-PARSE-NAME" "POSITION-IN" + "PRIMITIVE-TYPE-SCS" "PRINT-TN-GUTS" + "SB-KIND" "SB-SIZE" + "SC-LOCATIONS" "MAKE-SC-LOCATIONS" "SC-OFFSET-TO-SC-LOCATIONS" + "SC-LOCATIONS-COUNT" "SC-LOCATIONS-FIRST" "SC-LOCATIONS-MEMBER" + "DO-SC-LOCATIONS" + "SC-ALIGNMENT" "SC-ALLOWED-BY-PRIMITIVE-TYPE" + "SC-ALTERNATE-SCS" "SC-CONSTANT-SCS" "SC-ELEMENT-SIZE" + "SC-LOCATIONS" "SC-MOVE-FUNS" "SC-RESERVE-LOCATIONS" + "SC-SAVE-P" "SC-VECTOR" + "SET-BIT-VECTOR" + "TEMPLATE-NAME" + "TN" "TN-COST" "TN-GLOBAL-CONFLICTS" "TN-KIND" "TN-LEAF" + "TN-LOCAL" "TN-LOCAL-CONFLICTS" "TN-LOCAL-NUMBER" + "TN-NEXT" "TN-NUMBER" "TN-PRIMITIVE-TYPE" + "TN-READS" "TN-SAVE-TN" "TN-VERTEX" "TN-WRITES" + "TNS-CONFLICT" "TNS-CONFLICT-GLOBAL-GLOBAL" + "TNS-CONFLICT-LOCAL-GLOBAL" + "VOP" "VOP-ARGS" "VOP-INFO" "VOP-INFO-ARG-LOAD-SCS" + "VOP-INFO-MOVE-ARGS" "VOP-NAME" + "VOP-INFO-RESULT-LOAD-SCS" "VOP-INFO-SAVE-P" + "VOP-NODE" + "VOP-PARSE-OR-LOSE" "VOP-PARSE-TEMPS" "VOP-PREV" + "VOP-REFS" "VOP-RESULTS" "VOP-SAVE-SET" "VOP-TEMPS") + (:export "PACK" "TARGET-IF-DESIRABLE" "*REGISTER-ALLOCATION-METHOD*" + "*PACK-ITERATIONS*" + "*PACK-ASSIGN-COSTS*" "*PACK-OPTIMIZE-SAVES*" + "*TN-WRITE-COST*" "*TN-LOOP-DEPTH-MULTIPLIER*")) + +(defpackage* "SB-PRETTY" + (:documentation "private: implementation of pretty-printing") + (:use "CL" "SB-EXT" "SB-INT" "SB-KERNEL") + (:export "OUTPUT-PRETTY-OBJECT" + "PRETTY-STREAM" "PRETTY-STREAM-P" + "PPRINT-DISPATCH-TABLE" + "*PPRINT-QUOTE-WITH-SYNTACTIC-SUGAR*" + "!PPRINT-COLD-INIT")) + +(defpackage* "SB-SYS" + (:documentation + "private: In theory, this \"contains functions and information +necessary for system interfacing\" (said cmu-user.tex at the time +of the SBCL code fork). That probably was and is a good idea, but in +practice, the distinctions between this package and SB-KERNEL +and even SB-VM seem to have become somewhat blurred over the years. +Some anomalies (e.g. FIND-IF-IN-CLOSURE being in SB-SYS instead of +SB-KERNEL) have been undone, but probably more remain.") + (:use "CL" "SB-EXT" "SB-INT") + (:export + ;; FIXME: %PRIMITIVE shouldn't be here. (I now know that %SYS + ;; is for OS-dependent stuff. %PRIMITIVE should probably be in + ;; SB-KERNEL.) + "%PRIMITIVE" + "%STANDARD-CHAR-P" + "*EXIT-ERROR-HANDLER*" + "*EXIT-IN-PROGRESS*" + "*ALLOW-WITH-INTERRUPTS*" + "*INTERRUPTS-ENABLED*" + "*INTERRUPT-PENDING*" + #+sb-safepoint "*THRUPTION-PENDING*" + "*LINKAGE-INFO*" + "*LONG-SITE-NAME*" "*SHORT-SITE-NAME*" + "*MACHINE-VERSION*" + "*PERIODIC-POLLING-FUNCTION*" + "*PERIODIC-POLLING-PERIOD*" + "*RUNTIME-DLHANDLE*" + "*SHARED-OBJECTS*" + "*STDERR*" "*STDIN*" + "*STDOUT*" + "*TTY*" + "ADD-FD-HANDLER" + "ALLOCATE-SYSTEM-MEMORY" + "ALLOW-WITH-INTERRUPTS" + "BEEP" + "BREAKPOINT-ERROR" + "CANCEL-DEADLINE" + "CLOSE-SHARED-OBJECTS" + "DEADLINE-TIMEOUT" + "DEALLOCATE-SYSTEM-MEMORY" + "DECODE-TIMEOUT" + "DECODE-INTERNAL-TIME" + "DEFER-DEADLINE" + "DLOPEN-OR-LOSE" + "ENABLE-INTERRUPT" + "EXTERN-ALIEN-NAME" + "EXIT-CODE" + "FD-STREAM" "FD-STREAM-FD" "FD-STREAM-P" + "FIND-DYNAMIC-FOREIGN-SYMBOL-ADDRESS" + "FIND-FOREIGN-SYMBOL-ADDRESS" + "FIND-FOREIGN-SYMBOL-IN-TABLE" + "FIND-LINKAGE-TABLE-FOREIGN-SYMBOL-ADDRESS" + "FIXUP-PRELINKED-LINKAGE-TABLE-ENTRIES" + #+(and win32 x86-64) "FOREIGN-HEAP-CORRUPTION" + "FOREIGN-SYMBOL-SAP" + "FOREIGN-SYMBOL-ADDRESS" + "FOREIGN-SYMBOL-DATAREF-SAP" + "GET-MACHINE-VERSION" "GET-SYSTEM-INFO" + "IN-INTERRUPTION" + "INTERACTIVE-INTERRUPT" + "INT-SAP" + "INVALIDATE-DESCRIPTOR" + "INVOKE-INTERRUPTION" + "IO-TIMEOUT" + "LINKAGE-TABLE-ADDRESS" + "LINKAGE-TABLE-INDEX" + "MACRO" "MAKE-FD-STREAM" + "MEMORY-FAULT-ERROR" + "MEMMOVE" + "NLX-PROTECT" + "OS-EXIT" + "OS-COLD-INIT-OR-REINIT" "OS-DEINIT" + "OS-CONTEXT-T" + "READ-CYCLE-COUNTER" "ELAPSED-CYCLES" + "READ-N-BYTES" + "REMOVE-FD-HANDLER" + "REOPEN-SHARED-OBJECTS" + "SAP+" "SAP-" + "SAP-FOREIGN-SYMBOL" + "SAP-INT" + "SAP-REF-16" "SAP-REF-32" "SAP-REF-64" "SAP-REF-WORD" + "SAP-REF-8" + "SAP-REF-DOUBLE" "SAP-REF-LISPOBJ" "SAP-REF-LONG" + "SAP-REF-SAP" "SAP-REF-SINGLE" + "SAP<" "SAP<=" "SAP=" "SAP>" "SAP>=" + "SCRUB-CONTROL-STACK" "SERVE-ALL-EVENTS" + "SIGNAL-DEADLINE" + "SERVE-EVENT" + "SIGNED-SAP-REF-16" "SIGNED-SAP-REF-32" + "SIGNED-SAP-REF-64" "SIGNED-SAP-REF-WORD" "SIGNED-SAP-REF-8" + "SYSTEM-AREA-POINTER" "SYSTEM-AREA-POINTER-P" + "SYSTEM-CONDITION" "SYSTEM-CONDITION-ADDRESS" + "SYSTEM-CONDITION-CONTEXT" + "REINIT-INTERNAL-REAL-TIME" + "SYSTEM-INTERNAL-RUN-TIME" + "UPDATE-ALIEN-LINKAGE-TABLE" "VECTOR-SAP" + "WAIT-UNTIL-FD-USABLE" + "WITH-CODE-PAGES-PINNED" + "WITH-DEADLINE" + "WITH-FD-HANDLER" + "WITH-INTERRUPTS" "WITH-LOCAL-INTERRUPTS" + "WITH-PINNED-OBJECTS" "WITHOUT-GCING" + "WITHOUT-INTERRUPTS" + "WITH-INTERRUPT-BINDINGS")) + +(defpackage* "SB-ALIEN" + ;; FIXME: This nickname is a deprecated hack for backwards + ;; compatibility with code which assumed the CMU-CL-style + ;; SB-ALIEN/SB-C-CALL split. That split went away and was deprecated + ;; in 0.7.0, so we should get rid of this nickname after a while. + (:nicknames "SB-C-CALL") + (:documentation "public: the ALIEN foreign function interface (If you're +porting CMU CL code, note that this package corresponds roughly to a union +of the packages ALIEN and C-CALL at the time of the SBCL fork. SB-C-CALL +is a deprecated nickname to help ease the transition from older versions +of SBCL which maintained the CMU-CL-style split into two packages.)") + (:use "CL" "SB-EXT" "SB-INT" "SB-SYS" "SB-ALIEN-INTERNALS") + (:import-from "CL" "*" "ARRAY" "CHAR" "DOUBLE-FLOAT" "FLOAT" "FUNCTION" + "BOOLEAN" "INTEGER" "LONG-FLOAT" "SINGLE-FLOAT" "UNION" "VALUES") + (:import-from "SB-SYS" "SYSTEM-AREA-POINTER") + (:import-from "SB-UNIX" "OFF-T" "SIZE-T") + (:export "*" "ADDR" "ALIEN" "ALIEN-FUNCALL" "ALIEN-SAP" + "ALIEN-SIZE" "ARRAY" "BOOLEAN" "CAST" "CHAR" "C-STRING" + "DEFINE-ALIEN-ROUTINE" "DEFINE-ALIEN-TYPE" "DEFINE-ALIEN-VARIABLE" + "DEREF" "DOUBLE-FLOAT" "DOUBLE" "ENUM" "EXTERN-ALIEN" + "FLOAT" "FREE-ALIEN" "FUNCTION" + "LONG-FLOAT" + "GET-ERRNO" + "INT" + "INTEGER" + "LOAD-1-FOREIGN" "LOAD-FOREIGN" "LOAD-SHARED-OBJECT" "LONG" "LONG-LONG" + "MAKE-ALIEN" + "MAKE-ALIEN-STRING" + "NULL-ALIEN" + "OFF-T" + "SAP-ALIEN" "SHORT" "SIGNED" + "SINGLE-FLOAT" + "SIZE-T" "SSIZE-T" + "SLOT" "STRUCT" + "SYSTEM-AREA-POINTER" + "UNDEFINED-ALIEN-ERROR" + "UNION" + "UNLOAD-SHARED-OBJECT" + "UNSIGNED" + "UNSIGNED-CHAR" "UNSIGNED-INT" "UNSIGNED-LONG" "UNSIGNED-LONG-LONG" "UNSIGNED-SHORT" + "UTF8-STRING" + "VALUES" + "VOID" + "WITH-ALIEN")) + +(defpackage* "SB-ALIEN-INTERNALS" + (:documentation "private: stuff for implementing ALIENs and friends") + (:use "CL") + (:export "%ALIEN-VALUE" + "%CAST" + "%DEREF-ADDR" "%HEAP-ALIEN" "%HEAP-ALIEN-ADDR" + "%LOCAL-ALIEN-ADDR" "%LOCAL-ALIEN-FORCED-TO-MEMORY-P" "%SAP-ALIEN" + "%SET-DEREF" "%SET-HEAP-ALIEN" "%SET-LOCAL-ALIEN" "%SET-SLOT" + "%SLOT-ADDR" "*SAVED-FP*" "*VALUES-TYPE-OKAY*" + "ALIEN-ARRAY-TYPE" + "ALIEN-ARRAY-TYPE-DIMENSIONS" "ALIEN-ARRAY-TYPE-ELEMENT-TYPE" + "ALIEN-ARRAY-TYPE-P" "ALIEN-BOOLEAN-TYPE" "ALIEN-BOOLEAN-TYPE-P" + "ALIEN-CALLBACK" + "ALIEN-CALLBACK-ACCESSOR-FORM" + "ALIEN-CALLBACK-ASSEMBLER-WRAPPER" + "ALIEN-DOUBLE-FLOAT-TYPE" "ALIEN-DOUBLE-FLOAT-TYPE-P" + "ALIEN-ENUM-TYPE" "ALIEN-ENUM-TYPE-P" "ALIEN-FLOAT-TYPE" + "ALIEN-FLOAT-TYPE-P" "ALIEN-FUN-TYPE" + "ALIEN-FUN-TYPE-ARG-TYPES" "ALIEN-FUN-TYPE-P" + "ALIEN-FUN-TYPE-RESULT-TYPE" "ALIEN-INTEGER-TYPE" + "ALIEN-INTEGER-TYPE-P" "ALIEN-INTEGER-TYPE-SIGNED" + "ALIEN-LONG-FLOAT-TYPE" "ALIEN-LONG-FLOAT-TYPE-P" + "ALIEN-POINTER-TYPE" "ALIEN-POINTER-TYPE-P" + "ALIEN-POINTER-TYPE-TO" "ALIEN-RECORD-FIELD" + "ALIEN-RECORD-FIELD-NAME" "ALIEN-RECORD-FIELD-OFFSET" + "ALIEN-RECORD-FIELD-P" "ALIEN-RECORD-FIELD-TYPE" + "ALIEN-RECORD-TYPE" "ALIEN-RECORD-TYPE-FIELDS" + "ALIEN-RECORD-TYPE-P" "ALIEN-SINGLE-FLOAT-TYPE" + "ALIEN-SINGLE-FLOAT-TYPE-P" "ALIEN-SUBTYPE-P" "ALIEN-TYPE" + "ALIEN-TYPE-=" "ALIEN-TYPE-ALIGNMENT" "ALIEN-TYPE-BITS" + "ALIEN-TYPE-P" "ALIEN-TYPEP" + "ALIEN-VALUE" + "ALIEN-VALUE-TYPE" + "ALIEN-VALUE-TYPEP" + "ALIEN-VALUE-SAP" "ALIEN-VALUE-P" + "ALIEN-VALUES-TYPE" "ALIEN-VALUES-TYPE-P" + "ALIEN-VALUES-TYPE-VALUES" "ALIGN-OFFSET" "ALIEN-VOID-TYPE-P" + "COMPUTE-ALIEN-REP-TYPE" "COMPUTE-DEPORT-ALLOC-LAMBDA" + "COMPUTE-DEPORT-LAMBDA" "COMPUTE-DEPOSIT-LAMBDA" + "COMPUTE-EXTRACT-LAMBDA" "COMPUTE-LISP-REP-TYPE" + "COMPUTE-NATURALIZE-LAMBDA" "DEFINE-ALIEN-TYPE-CLASS" + "DEFINE-ALIEN-TYPE-METHOD" "DEFINE-ALIEN-TYPE-TRANSLATOR" + "DEPORT" "DEPORT-ALLOC" + "ENTER-ALIEN-CALLBACK" + "HEAP-ALIEN-INFO" "HEAP-ALIEN-INFO-P" "HEAP-ALIEN-INFO-SAP-FORM" + "HEAP-ALIEN-INFO-TYPE" "INVOKE-ALIEN-TYPE-METHOD" + "INVOKE-WITH-SAVED-FP" "LOCAL-ALIEN" + "LOCAL-ALIEN-INFO" "LOCAL-ALIEN-INFO-FORCE-TO-MEMORY-P" + "LOCAL-ALIEN-INFO-P" "LOCAL-ALIEN-INFO-TYPE" + "MAKE-ALIEN-FUN-TYPE" "MAKE-ALIEN-POINTER-TYPE" + "MAYBE-WITH-PINNED-OBJECTS" + "MAKE-LOCAL-ALIEN" "NATURALIZE" + "NOTE-LOCAL-ALIEN-TYPE" + "PARSE-ALIEN-TYPE" "UNPARSE-ALIEN-TYPE")) + +#+(and x86-64 sb-thread) +(defpackage* "SB-APROF" + (:documentation "public: the interface to the deterministic consing profiler") + (:use "CL" "SB-EXT" "SB-INT" "SB-KERNEL" "SB-ALIEN" "SB-SYS")) + +(defpackage* "SB-PROFILE" + (:documentation "public: the interface to the profiler") + (:use "CL" "SB-EXT" "SB-INT" "SB-KERNEL") + (:export "PROFILE" "REPORT" "RESET" "UNPROFILE")) + +;;; FIXME: This package is awfully huge. It'd probably be good to +;;; split it. There's at least one natural way to split it: the +;;; implementation of the Lisp type system (e.g. TYPE-INTERSECTION and +;;; SPECIFIER-TYPE) could move to a separate package SB-TYPE. (There's +;;; lots of stuff which currently uses the SB-KERNEL package which +;;; doesn't actually use the type system stuff.) And maybe other +;;; possible splits too: +;;; * Pull GC stuff (*GC-INHIBIT*, *GC-PENDING*, etc.) +;;; out into SB-GC. +;;; * Pull special case implementations of sequence functions (e.g. +;;; %MAP-TO-LIST-ARITY-1 and %FIND-POSITION-IF-NOT) and +;;; other sequence function implementation grot into SB-SEQ. +;;; * Pull all the math stuff (%ACOS, %COSH, WORD-LOGICAL-AND...) +;;; into SB-MATH. +;;; * Pull all the array stuff (%ARRAY-DATA, +;;; WITH-ARRAY-DATA, ALLOCATE-VECTOR, HAIRY-DATA-VECTOR-REF...) +;;; into SB-ARRAY. +;;; * Pull all the streams stuff out into SB-STREAM. +;;; * Pull all the OBJECT-NOT-FOO symbols out. Maybe we could even +;;; figure out a way to stop exporting them? Failing that, +;;; they could be in SB-INTERR. +;;; Or better still, since error names are basically meaningless except +;;; for the ~18 errors that are _not_ object-not-<x>, stop naming them. +;;; C just needs a map from number -> string-to-show. +(defpackage* "SB-KERNEL" + (:documentation + "private: Theoretically this 'hides state and types used for package +integration' (said CMU CL architecture.tex) and that probably was and +is a good idea, but see SB-SYS re. blurring of boundaries.") + (:use "CL" "SB-ALIEN" "SB-ALIEN-INTERNALS" "SB-BIGNUM" + "SB-EXT" "SB-FASL" "SB-INT" "SB-SYS" "SB-GRAY") + #+sb-simd-pack + (:import-from "SB-EXT" + "SIMD-PACK" + "SIMD-PACK-P" + "%MAKE-SIMD-PACK-UB32" + "%MAKE-SIMD-PACK-UB64" + "%MAKE-SIMD-PACK-DOUBLE" + "%MAKE-SIMD-PACK-SINGLE" + "%SIMD-PACK-UB32S" + "%SIMD-PACK-UB64S" + "%SIMD-PACK-DOUBLES" + "%SIMD-PACK-SINGLES") + (:export "%%DATA-VECTOR-REFFERS%%" + "%%DATA-VECTOR-SETTERS%%" + "%ACOS" + "%ACOSH" + "%ADJOIN" + "%ADJOIN-EQ" + "%ADJOIN-KEY" + "%ADJOIN-KEY-EQ" + "%ADJOIN-KEY-TEST" + "%ADJOIN-KEY-TEST-NOT" + "%ADJOIN-TEST" + "%ADJOIN-TEST-NOT" + "%ARRAY-AVAILABLE-ELEMENTS" + "%ARRAY-DATA" + "%ARRAY-DATA-VECTOR" ; DO NOT USE !!! + + "%ARRAY-DIMENSION" "%ARRAY-DISPLACED-P" + "%ARRAY-DISPLACED-FROM" + "%ARRAY-DISPLACEMENT" "%ARRAY-FILL-POINTER" + "%ARRAY-RANK" "%ARRAY-RANK=" + "SIMPLE-ARRAY-HEADER-OF-RANK-P" + "%ARRAY-ATOMIC-INCF/WORD" + "%ASH/RIGHT" + "%ASSOC" + "%ASSOC-EQ" + "%ASSOC-IF" + "%ASSOC-IF-KEY" + "%ASSOC-IF-NOT" + "%ASSOC-IF-NOT-KEY" + "%ASSOC-KEY" + "%ASSOC-KEY-EQ" + "%ASSOC-KEY-TEST" + "%ASSOC-KEY-TEST-NOT" + "%ASSOC-TEST" + "%ASSOC-TEST-NOT" + "%ASIN" "%ASINH" + "%ATAN" "%ATAN2" "%ATANH" + "%ATOMIC-DEC-CAR" "%ATOMIC-INC-CAR" + "%ATOMIC-DEC-CDR" "%ATOMIC-INC-CDR" + "%ATOMIC-DEC-SYMBOL-GLOBAL-VALUE" + "%ATOMIC-INC-SYMBOL-GLOBAL-VALUE" + "%CALLER-FRAME" + "%CALLER-PC" + "%CHECK-BOUND" "CHECK-BOUND" + "%CHECK-GENERIC-SEQUENCE-BOUNDS" + "%CHECK-VECTOR-SEQUENCE-BOUNDS" + "%CAS-SYMBOL-GLOBAL-VALUE" + "%COPY-INSTANCE" "%COPY-INSTANCE-SLOTS" + "%COMPARE-AND-SWAP-CAR" + "%COMPARE-AND-SWAP-CDR" + "%COMPARE-AND-SWAP-SVREF" + "%COMPARE-AND-SWAP-SYMBOL-VALUE" + "%CONCATENATE-TO-BASE-STRING" + "%CONCATENATE-TO-STRING" + "%CONCATENATE-TO-SIMPLE-VECTOR" + "%CONCATENATE-TO-LIST" "%CONCATENATE-TO-VECTOR" + "CONTAINS-UNKNOWN-TYPE-P" + "%COS" "%COS-QUICK" + "%COSH" "%DATA-VECTOR-AND-INDEX" "%DEPOSIT-FIELD" + "%DOUBLE-FLOAT" "%DPB" "%EQL" "%EQL/INTEGER" + "%EXIT" + "%EXP" "%EXPM1" + "%FIND-POSITION" + "%FIND-POSITION-VECTOR-MACRO" "%FIND-POSITION-IF" + "%FIND-POSITION-IF-VECTOR-MACRO" "%FIND-POSITION-IF-NOT" + "%FIND-POSITION-IF-NOT-VECTOR-MACRO" + "FIXNUM-MOD-P" + "%HYPOT" + "%INSTANCE-CAS" + "%LDB" "%LOG" "%LOGB" "%LOG10" + "%LAST0" + "%LAST1" + "%LASTN/FIXNUM" + "%LASTN/BIGNUM" + "%LOG1P" + #+long-float "%LONG-FLOAT" + "%MAKE-ARRAY" + "%MAKE-COMPLEX" "%MAKE-FUNCALLABLE-INSTANCE" + "%MAKE-FUNCALLABLE-STRUCTURE-INSTANCE-ALLOCATOR" + "%MAKE-INSTANCE" "%MAKE-INSTANCE/MIXED" + "%MAKE-LISP-OBJ" + "%MAKE-LIST" + "%MAKE-RATIO" + #+sb-simd-pack "%MAKE-SIMD-PACK" + #+sb-simd-pack-256 "%MAKE-SIMD-PACK-256" + "%MAKE-STRUCTURE-INSTANCE" + "%MAKE-STRUCTURE-INSTANCE-ALLOCATOR" + "%MAP" "%MAP-FOR-EFFECT-ARITY-1" + "%MAP-TO-LIST-ARITY-1" "%MAP-TO-SIMPLE-VECTOR-ARITY-1" + "%MASK-FIELD" + "%MEMBER" + "%MEMBER-EQ" + "%MEMBER-IF" + "%MEMBER-IF-KEY" + "%MEMBER-IF-NOT" + "%MEMBER-IF-NOT-KEY" + "%MEMBER-KEY" + "%MEMBER-KEY-EQ" + "%MEMBER-KEY-TEST" + "%MEMBER-KEY-TEST-NOT" + "%MEMBER-TEST" + "%MEMBER-TEST-NOT" + "%MULTIPLY-HIGH" "%SIGNED-MULTIPLY-HIGH" + "%NEGATE" "%POW" + "%NEW-INSTANCE" + "%OTHER-POINTER-WIDETAG" + "%PCL-INSTANCE-P" + "%PUTHASH" + "%RASSOC" + "%RASSOC-EQ" + "%RASSOC-IF" + "%RASSOC-IF-KEY" + "%RASSOC-IF-NOT" + "%RASSOC-IF-NOT-KEY" + "%RASSOC-KEY" + "%RASSOC-KEY-EQ" + "%RASSOC-KEY-TEST" + "%RASSOC-KEY-TEST-NOT" + "%RASSOC-TEST" + "%RASSOC-TEST-NOT" + "%VECTOR-RAW-BITS" + "%SCALB" "%SCALBN" + "%RAW-INSTANCE-ATOMIC-INCF/WORD" + "%RAW-INSTANCE-CAS/WORD" "%RAW-INSTANCE-XCHG/WORD" + "%RAW-INSTANCE-REF/WORD" "%RAW-INSTANCE-SET/WORD" + "%RAW-INSTANCE-CAS/SIGNED-WORD" + "%RAW-INSTANCE-REF/SIGNED-WORD" "%RAW-INSTANCE-SET/SIGNED-WORD" + "%RAW-INSTANCE-REF/SINGLE" "%RAW-INSTANCE-SET/SINGLE" + "%RAW-INSTANCE-REF/DOUBLE" "%RAW-INSTANCE-SET/DOUBLE" + "%RAW-INSTANCE-REF/COMPLEX-SINGLE" + "%RAW-INSTANCE-SET/COMPLEX-SINGLE" + "%RAW-INSTANCE-REF/COMPLEX-DOUBLE" + "%RAW-INSTANCE-SET/COMPLEX-DOUBLE" + "ROUND-DOUBLE" "ROUND-SINGLE" + "%SET-ARRAY-DIMENSION" "%SET-FUNCALLABLE-INSTANCE-INFO" + "%SET-VECTOR-RAW-BITS" + "%SET-SAP-REF-16" "%SET-SAP-REF-32" "%SET-SAP-REF-64" + "%SET-SAP-REF-WORD" "%SET-SAP-REF-8" "%SET-SAP-REF-DOUBLE" + "%SET-SAP-REF-LISPOBJ" "%SET-SAP-REF-LONG" "%SET-SAP-REF-SAP" + "%SET-SAP-REF-SINGLE" "%SET-SIGNED-SAP-REF-16" + "%SET-SIGNED-SAP-REF-32" "%SET-SIGNED-SAP-REF-64" + "%SET-SIGNED-SAP-REF-WORD" + "%SET-SIGNED-SAP-REF-8" "%SET-STACK-REF" + "%SET-SYMBOL-HASH" + "%SIN" "%SIN-QUICK" "%SINGLE-FLOAT" + "%SINH" "%SQRT" + "%SXHASH-BIT-VECTOR" "%SXHASH-SIMPLE-BIT-VECTOR" + "%SXHASH-STRING" "%SXHASH-SIMPLE-STRING" + "%SXHASH-SIMPLE-SUBSTRING" "%TAN" "%TAN-QUICK" "%TANH" + "THE*" + "%UNARY-ROUND" + "%UNARY-TRUNCATE" "UNARY-TRUNCATE" + "%UNARY-TRUNCATE/SINGLE-FLOAT" + "%UNARY-TRUNCATE/DOUBLE-FLOAT" + "%UNARY-FTRUNCATE" + "UNARY-TRUNCATE-SINGLE-FLOAT-TO-BIGNUM" + "UNARY-TRUNCATE-DOUBLE-FLOAT-TO-BIGNUM" + "%UNARY-TRUNCATE-SINGLE-FLOAT-TO-BIGNUM" + "%UNARY-TRUNCATE-DOUBLE-FLOAT-TO-BIGNUM" + "SXHASH-BIGNUM-DOUBLE-FLOAT" "SXHASH-BIGNUM-SINGLE-FLOAT" + + "%WITH-ARRAY-DATA" + "%WITH-ARRAY-DATA/FP" + "%WITH-ARRAY-DATA-MACRO" + "*APPROXIMATE-NUMERIC-UNIONS*" + "*CURRENT-INTERNAL-ERROR-CONTEXT*" + "*CURRENT-LEVEL-IN-PRINT*" + "*EMPTY-TYPE*" + "*EVAL-CALLS*" + "*GC-INHIBIT*" "*GC-PENDING*" + "*GC-PIN-CODE-PAGES*" + #+sb-thread "*STOP-FOR-GC-PENDING*" + "*IN-WITHOUT-GCING*" + "*UNIVERSAL-TYPE*" + "*UNIVERSAL-FUN-TYPE*" "*UNPARSE-FUN-TYPE-SIMPLIFY*" + "*WILD-TYPE*" "WORD-LOGICAL-AND" "WORD-LOGICAL-ANDC1" + "WORD-LOGICAL-ANDC2" "WORD-LOGICAL-EQV" + "WORD-LOGICAL-NAND" "WORD-LOGICAL-NOR" "WORD-LOGICAL-NOT" + "WORD-LOGICAL-OR" "WORD-LOGICAL-ORC1" "WORD-LOGICAL-ORC2" + "WORD-LOGICAL-XOR" + "ALLOW-NON-RETURNING-TAIL-CALL" + "ALIEN-TYPE-TYPE" "ALIEN-TYPE-TYPE-ALIEN-TYPE" "ALIEN-TYPE-TYPE-P" + "ALLOCATE-VECTOR" "ALLOCATE-STATIC-VECTOR" + "ASSERT-SYMBOL-HOME-PACKAGE-UNLOCKED" + "BUILD-RATIO" + "PROGRAM-ASSERT-SYMBOL-HOME-PACKAGE-UNLOCKED" + "DISABLED-PACKAGE-LOCKS" + "WITH-SINGLE-PACKAGE-LOCKED-ERROR" + "ARGS-TYPE" "ARGS-TYPE-ALLOWP" "ARGS-TYPE-KEYP" + "ARGS-TYPE-KEYWORDS" "ARGS-TYPE-OPTIONAL" "ARGS-TYPE-P" + "ARGS-TYPE-REQUIRED" "ARGS-TYPE-REST" + "ARRAY-HEADER-P" "SIMPLE-ARRAY-HEADER-P" + "ARRAY-TYPE" "ARRAY-TYPE-COMPLEXP" + "ARRAY-TYPE-DIMENSIONS" "ARRAY-TYPE-ELEMENT-TYPE" + "ARRAY-TYPE-P" "ARRAY-TYPE-SPECIALIZED-ELEMENT-TYPE" + "ARRAY-UNDERLYING-WIDETAG" + "ASSERT-ERROR" + #+sb-unicode "BASE-CHAR-P" + "BASE-STRING-P" + "BIND" "BINDING-STACK-POINTER-SAP" "BIT-INDEX" + "BOGUS-ARG-TO-VALUES-LIST-ERROR" "BOOLE-CODE" + "BOUNDING-INDICES-BAD-ERROR" "BYTE-SPECIFIER" "%BYTE-BLT" + "FUNCTION-DESIGNATOR" + "CAR-EQ-IF-LISTP" + "CASE-BODY-ERROR" + "CHARACTER-SET" "CHARACTER-SET-TYPE" + "CHARACTER-SET-TYPE-PAIRS" + #+sb-unicode "CHARACTER-STRING-P" + "CHARPOS" + "CHECK-FOR-CIRCULARITY" "CHECK-TYPE-ERROR" "CLOSED-FLAME" + "CLASS-CLASSOID" + "CODE-COMPONENT" "CODE-COMPONENT-P" + "CODE-HEADER-REF" "CODE-HEADER-SET" "CODE-HEADER-WORDS" + "CODE-JUMP-TABLE-WORDS" + "CODE-INSTRUCTIONS" "CODE-N-UNBOXED-DATA-BYTES" + "CODE-OBJECT-SIZE" "CODE-TRAILER-REF" + "COERCE-SYMBOL-TO-FUN" + "COERCE-TO-FUN" "COERCE-TO-LEXENV" "COERCE-TO-LIST" + "COERCE-TO-VALUES" "COERCE-TO-VECTOR" + "COMPLEX-DOUBLE-FLOAT" "COMPLEX-DOUBLE-FLOAT-P" + "COMPLEX-FLOAT-P" + #+long-float ("COMPLEX-LONG-FLOAT" "COMPLEX-LONG-FLOAT-P") + "COMPLEX-RATIONAL-P" + "COMPLEX-SINGLE-FLOAT" "COMPLEX-SINGLE-FLOAT-P" + "COMPLEX-VECTOR-P" "COMPOUND-TYPE" "COMPOUND-TYPE-P" + "COMPOUND-TYPE-TYPES" + "CONDITION-DESIGNATOR-HEAD" + "CONS-TYPE" "CONS-TYPE-CAR-TYPE" + "CONS-TYPE-CDR-TYPE" "CONS-TYPE-P" "CONSED-SEQUENCE" + "CONSTANT" "CONSTANT-TYPE" "CONSTANT-TYPE-P" + "CONSTANT-TYPE-TYPE" "CONTAINING-INTEGER-TYPE" + "CONTROL-STACK-POINTER-SAP" + "CSUBTYPEP" "CTYPE" "TYPE-HASH-VALUE" "CTYPE-OF" + "CTYPE-P" "CTYPEP" + "CTYPE-ARRAY-DIMENSIONS" "CTYPE-ARRAY-SPECIALIZED-ELEMENT-TYPES" + "CURRENT-FP" "CURRENT-SP" + "DATA-NIL-VECTOR-REF" + "DATA-VECTOR-REF" "DATA-VECTOR-REF-WITH-OFFSET" + "DATA-VECTOR-SET" "DATA-VECTOR-SET-WITH-OFFSET" + "DECLARATION-TYPE-CONFLICT-ERROR" + "DECODE-DOUBLE-FLOAT" + #+long-float "DECODE-LONG-FLOAT" + "DECODE-SINGLE-FLOAT" + "DEFINE-STRUCTURE-SLOT-ADDRESSOR" + "DEFINED-FTYPE-MATCHES-DECLARED-FTYPE-P" + "!DEFSTRUCT-WITH-ALTERNATE-METACLASS" "DESCEND-INTO" + "DIVISION-BY-ZERO-ERROR" + "DO-REST-ARG" + "DO-INSTANCE-TAGGED-SLOT" + "DO-LAYOUT-BITMAP" + "DOUBLE-FLOAT-EXPONENT" + "DOUBLE-FLOAT-BITS" + "DOUBLE-FLOAT-HIGH-BITS" "DOUBLE-FLOAT-INT-EXPONENT" + "DOUBLE-FLOAT-LOW-BITS" "DOUBLE-FLOAT-SIGNIFICAND" + "DSD-ACCESSOR-NAME" "DSD-ALWAYS-BOUNDP" "DSD-DEFAULT" "DSD-INDEX" + "DSD-NAME" "DSD-RAW-TYPE" "DSD-READ-ONLY" "DSD-TYPE" + "DYNBIND" + "FLOAT-WAIT" "DYNAMIC-SPACE-FREE-POINTER" "DYNAMIC-USAGE" + "EFFECTIVE-FIND-POSITION-TEST" + "EFFECTIVE-FIND-POSITION-KEY" + "ENSURE-SYMBOL-HASH" + "ENSURE-SYMBOL-TLS-INDEX" + "ERROR-NUMBER-OR-LOSE" + "EXTERNAL-FORMAT-DESIGNATOR" + "FAST-&REST-NTH" + "FILENAME" + "FILL-ARRAY" + "FILL-DATA-VECTOR" + "FIND-DEFSTRUCT-DESCRIPTION" + "FIND-OR-CREATE-FDEFN" + "FLOAT-EXPONENT" + "FLOAT-FORMAT-DIGITS" "FLOAT-FORMAT-NAME" + "FLOAT-FORMAT-MAX" "FLOAT-INT-EXPONENT" + "FLOAT-INFINITY-OR-NAN-P" + "FLOAT-SIGN-BIT" + "FLOATING-POINT-EXCEPTION" "FORM" "FORMAT-CONTROL" + "*FREE-INTERRUPT-CONTEXT-INDEX*" "FUNCALLABLE-INSTANCE-P" + "FSC-INSTANCE-HASH" + "%FUN-CODE-OFFSET" "FUN-CODE-HEADER" + "FUN-DESIGNATOR-TYPE" "FUN-DESIGNATOR-TYPE-P" + "FUN-TYPE" "FUN-TYPE-ALLOWP" + "FUN-TYPE-KEYP" "FUN-TYPE-KEYWORDS" "FUN-TYPE-NARGS" + "FUN-TYPE-OPTIONAL" "FUN-TYPE-P" "FUN-TYPE-REQUIRED" + "FUN-TYPE-REST" "FUN-TYPE-RETURNS" "FUN-TYPE-WILD-ARGS" + "GENERALIZED-BOOLEAN" + "GENERIC-ABSTRACT-TYPE-FUNCTION" + "GET-CLOSURE-LENGTH" "GET-HEADER-DATA" + "FUNCTION-HEADER-WORD" + "INSTANCE-HEADER-WORD" + "GET-LISP-OBJ-ADDRESS" "GENERATION-OF" "OBJECT-CARD-MARKS" + "LOWTAG-OF" "WIDETAG-OF" "WIDETAG=" + "HAIRY-DATA-VECTOR-REF" + "HAIRY-DATA-VECTOR-REF/CHECK-BOUNDS" "HAIRY-DATA-VECTOR-SET" + "HAIRY-DATA-VECTOR-SET/CHECK-BOUNDS" + "HAIRY-TYPE" "HAIRY-TYPE-P" "HAIRY-TYPE-SPECIFIER" + "HANDLE-CIRCULARITY" "HOST" "ILL-BIN" + "ILL-BOUT" "ILL-IN" "ILL-OUT" "INDEX-OR-MINUS-1" + "INDEX-TOO-LARGE-ERROR" "*!INITIAL-ASSEMBLER-ROUTINES*" + "*!INITIAL-SYMBOLS*" + "INTEGER-DECODE-DOUBLE-FLOAT" + #+long-float "INTEGER-DECODE-LONG-FLOAT" + "INTEGER-DECODE-SINGLE-FLOAT" "INTERNAL-ERROR" + #+win32 "HANDLE-WIN32-EXCEPTION" + "INTERNAL-TIME" "INTERNAL-SECONDS" + "INTERNAL-SECONDS-LIMIT" "SAFE-INTERNAL-SECONDS-LIMIT" + "INTERPRETED-FUNCTION" + "INTERSECTION-TYPE" "INTERSECTION-TYPE-P" + "INTERSECTION-TYPE-TYPES" "INVALID-ARG-COUNT-ERROR" + "LOCAL-INVALID-ARG-COUNT-ERROR" + "INVALID-UNWIND-ERROR" + "IRRATIONAL" "KEY-INFO" + "KEY-INFO-NAME" "KEY-INFO-P" "KEY-INFO-TYPE" + "BITMAP-NWORDS" + "LAYOUT-DEPTHOID" + "LAYOUT-ID" + "LAYOUT-FOR-PCL-OBJ-P" + "WRAPPER-BITMAP" + "WRAPPER-CLASSOID-NAME" + "WRAPPER-DEPTHOID" "WRAPPER-EQUALP-IMPL" + "WRAPPER-SLOT-TABLE" + "WRAPPER-FRIEND" "LAYOUT-FRIEND" + #+(or x86-64 x86) "%LEA" + "LEXENV" "LEXENV-DESIGNATOR" "LINE-LENGTH" + "LIST-ABSTRACT-TYPE-FUNCTION" + "LIST-COPY-SEQ*" + "LIST-FILL*" + "LIST-SUBSEQ*" + "ANSI-STREAM" + "ANSI-STREAM-BIN" "ANSI-STREAM-BOUT" + "ANSI-STREAM-IN" + "ANSI-STREAM-IN-BUFFER" "ANSI-STREAM-IN-INDEX" + "ANSI-STREAM-MISC" + "ANSI-STREAM-N-BIN" + "ANSI-STREAM-OUT" "ANSI-STREAM-SOUT" + "COMPLEX-VECTOR" + "LIST-TO-VECTOR*" + "LOGICAL-HOST" "LOGICAL-HOST-DESIGNATOR" + "LRA" "LRA-CODE-HEADER" "LRA-P" + "MAKE-ALIEN-TYPE-TYPE" + "MAKE-ARRAY-HEADER" "MAKE-ARRAY-TYPE" "MAKE-CONS-TYPE" + "%MAKE-DOUBLE-FLOAT" + "MAKE-DOUBLE-FLOAT" "MAKE-FUN-TYPE" "MAKE-KEY-INFO" + "MAKE-LISP-OBJ" + #+long-float "MAKE-LONG-FLOAT" + "MAKE-MEMBER-TYPE" "MAKE-NULL-LEXENV" + "MAKE-EQL-TYPE" "MEMBER-TYPE-FROM-LIST" + "MAKE-NEGATION-TYPE" "TYPE-NEGATION" + "MAKE-NUMERIC-TYPE" + "MAKE-SINGLE-FLOAT" + "MAKE-UNBOUND-MARKER" + "MAKE-SHORT-VALUES-TYPE" "MAKE-SINGLE-VALUE-TYPE" + "MAKE-VALUE-CELL" "MAKE-VALUES-TYPE" + "MAPC-MEMBER-TYPE-MEMBERS" "MAPCAR-MEMBER-TYPE-MEMBERS" + "MAXIMUM-BIGNUM-LENGTH" + "MEMBER-TYPE" "MEMBER-TYPE-MEMBERS" "MEMBER-TYPE-P" + "MEMBER-TYPE-SIZE" + "MODIFIED-NUMERIC-TYPE" + "MOST-NEGATIVE-EXACTLY-DOUBLE-FLOAT-FIXNUM" + "MOST-NEGATIVE-EXACTLY-SINGLE-FLOAT-FIXNUM" + "MOST-POSITIVE-EXACTLY-DOUBLE-FLOAT-FIXNUM" + "MOST-POSITIVE-EXACTLY-SINGLE-FLOAT-FIXNUM" + "NAMED-TYPE" "NAMED-TYPE-NAME" "NAMED-TYPE-P" + "NEGATE" "NEGATION-TYPE" "NEGATION-TYPE-TYPE" + "NIL-ARRAY-ACCESSED-ERROR" + "NIL-FUN-RETURNED-ERROR" + "NON-NULL-SYMBOL-P" + "NUMERIC-CONTAGION" "NUMERIC-TYPE" + "NUMERIC-TYPE-CLASS" "NUMERIC-TYPE-COMPLEXP" + "NUMERIC-TYPE-EQUAL" "NUMERIC-TYPE-FORMAT" + "NUMERIC-TYPE-HIGH" "NUMERIC-TYPE-LOW" "NUMERIC-TYPE-P" + "OBJECT-NOT-ARRAY-ERROR" "OBJECT-NOT-CHARACTER-ERROR" + "OBJECT-NOT-BASE-STRING-ERROR" "OBJECT-NOT-BIGNUM-ERROR" + "OBJECT-NOT-BIT-VECTOR-ERROR" + #+sb-unicode "OBJECT-NOT-CHARACTER-STRING-ERROR" + "OBJECT-NOT-COMPLEX-ERROR" + "OBJECT-NOT-COMPLEX-FLOAT-ERROR" + "OBJECT-NOT-COMPLEX-SINGLE-FLOAT-ERROR" + #+long-float "OBJECT-NOT-COMPLEX-LONG-FLOAT-ERROR" + "OBJECT-NOT-COMPLEX-DOUBLE-FLOAT-ERROR" + "OBJECT-NOT-COMPLEX-RATIONAL-ERROR" + ;; FIXME: It's confusing using "complex" to mean both + ;; "not on the real number line" and "not of a + ;; SIMPLE-ARRAY nature". Perhaps we could rename all the + ;; uses in the second sense as "hairy" instead? + + "OBJECT-NOT-COMPLEX-VECTOR-ERROR" "OBJECT-NOT-CONS-ERROR" + "OBJECT-NOT-DOUBLE-FLOAT-ERROR" "OBJECT-NOT-FIXNUM-ERROR" + "OBJECT-NOT-FLOAT-ERROR" "OBJECT-NOT-FUNCTION-ERROR" + "OBJECT-NOT-INSTANCE-ERROR" "OBJECT-NOT-INTEGER-ERROR" + "OBJECT-NOT-LIST-ERROR" + #+long-float "OBJECT-NOT-LONG-FLOAT-ERROR" + "OBJECT-NOT-NUMBER-ERROR" "OBJECT-NOT-RATIO-ERROR" + "OBJECT-NOT-RATIONAL-ERROR" "OBJECT-NOT-REAL-ERROR" + "OBJECT-NOT-SAP-ERROR" "OBJECT-NOT-SIGNED-BYTE-32-ERROR" + "OBJECT-NOT-SIGNED-BYTE-64-ERROR" + "OBJECT-NOT-SIMPLE-ARRAY-COMPLEX-DOUBLE-FLOAT-ERROR" + #+long-float + "OBJECT-NOT-SIMPLE-ARRAY-COMPLEX-LONG-FLOAT-ERROR" + #+sb-simd-pack + "OBJECT-NOT-SIMD-PACK-ERROR" + #+sb-simd-pack-256 + "OBJECT-NOT-SIMD-PACK-256-ERROR" + "OBJECT-NOT-SIMPLE-ARRAY-COMPLEX-SINGLE-FLOAT-ERROR" + "OBJECT-NOT-SIMPLE-ARRAY-DOUBLE-FLOAT-ERROR" + "OBJECT-NOT-SIMPLE-ARRAY-ERROR" + #+long-float "OBJECT-NOT-SIMPLE-ARRAY-LONG-FLOAT-ERROR" + "OBJECT-NOT-SIMPLE-ARRAY-NIL-ERROR" + "OBJECT-NOT-SIMPLE-ARRAY-SINGLE-FLOAT-ERROR" + "OBJECT-NOT-SIMPLE-ARRAY-UNSIGNED-BYTE-15-ERROR" + "OBJECT-NOT-SIMPLE-ARRAY-UNSIGNED-BYTE-16-ERROR" + "OBJECT-NOT-SIMPLE-ARRAY-UNSIGNED-BYTE-2-ERROR" + ;; KLUDGE: 32-bit and 64-bit ports implement a different + ;; set of specialized array types. Various bits of code + ;; in SBCL assume that symbols connected to the + ;; specialized array types are exported. But there's not + ;; a good way at this point to know whether the port for + ;; which we're building is 32-bit or 64-bit. Granted, we + ;; could hardcode the particulars (or even come up with a + ;; special :64BIT feature), but that seems a little + ;; inelegant. For now, we brute-force the issue by + ;; always exporting all the names required for both + ;; 32-bit and 64-bit ports. Other bits connected to the + ;; same issue are noted throughout the code below with + ;; the tag "32/64-bit issues". --njf, 2004-08-09 + + "OBJECT-NOT-SIMPLE-ARRAY-UNSIGNED-FIXNUM-ERROR" + "OBJECT-NOT-SIMPLE-ARRAY-UNSIGNED-BYTE-31-ERROR" + "OBJECT-NOT-SIMPLE-ARRAY-UNSIGNED-BYTE-32-ERROR" + "OBJECT-NOT-SIMPLE-ARRAY-UNSIGNED-BYTE-4-ERROR" + "OBJECT-NOT-SIMPLE-ARRAY-UNSIGNED-BYTE-63-ERROR" + "OBJECT-NOT-SIMPLE-ARRAY-UNSIGNED-BYTE-64-ERROR" + "OBJECT-NOT-SIMPLE-ARRAY-UNSIGNED-BYTE-7-ERROR" + "OBJECT-NOT-SIMPLE-ARRAY-UNSIGNED-BYTE-8-ERROR" + "OBJECT-NOT-SIMPLE-ARRAY-SIGNED-BYTE-16-ERROR" + "OBJECT-NOT-SIMPLE-ARRAY-FIXNUM-ERROR" + "OBJECT-NOT-SIMPLE-ARRAY-SIGNED-BYTE-32-ERROR" + "OBJECT-NOT-SIMPLE-ARRAY-SIGNED-BYTE-64-ERROR" + "OBJECT-NOT-SIMPLE-ARRAY-SIGNED-BYTE-8-ERROR" + "OBJECT-NOT-SIMPLE-BIT-VECTOR-ERROR" + "OBJECT-NOT-SIMPLE-BASE-STRING-ERROR" + #+sb-unicode "OBJECT-NOT-SIMPLE-CHARACTER-STRING-ERROR" + "OBJECT-NOT-SIMPLE-STRING-ERROR" + "OBJECT-NOT-SIMPLE-VECTOR-ERROR" + "OBJECT-NOT-SINGLE-FLOAT-ERROR" "OBJECT-NOT-STRING-ERROR" + "OBJECT-NOT-SYMBOL-ERROR" + "OBJECT-NOT-TYPE-ERROR" + "OBJECT-NOT-UNSIGNED-BYTE-32-ERROR" + "OBJECT-NOT-UNSIGNED-BYTE-64-ERROR" + "OBJECT-NOT-VECTOR-ERROR" + "OBJECT-NOT-VECTOR-NIL-ERROR" + "OBJECT-NOT-WEAK-POINTER-ERROR" + "ODD-KEY-ARGS-ERROR" "OUTPUT-OBJECT" "OUTPUT-UGLY-OBJECT" + "PACKAGE-DESIGNATOR" "PACKAGE-DOC-STRING" + "PACKAGE-HASHTABLE-SIZE" "PACKAGE-HASHTABLE-FREE" + "PACKAGE-INTERNAL-SYMBOLS" "PACKAGE-EXTERNAL-SYMBOLS" + "PARSE-UNKNOWN-TYPE" + "PARSE-UNKNOWN-TYPE-SPECIFIER" + "PATHNAME-DESIGNATOR" "PATHNAME-COMPONENT-CASE" + "POINTER-HASH" + "POINTERP" + #+(or x86 x86-64) "*PSEUDO-ATOMIC-BITS*" + "PUNT-PRINT-IF-TOO-LONG" + "READER-IMPOSSIBLE-NUMBER-ERROR" + "READER-EOF-ERROR" + "RESTART-DESIGNATOR" + "RUN-PENDING-FINALIZERS" + "SCALE-DOUBLE-FLOAT" + #+long-float "SCALE-LONG-FLOAT" + "SCALE-SINGLE-FLOAT" + "SCHWARTZIAN-STABLE-SORT-LIST" "SCHWARTZIAN-STABLE-SORT-VECTOR" + "SCRUB-POWER-CACHE" + "SEQUENCEP" "SEQUENCE-COUNT" "SEQUENCE-END" + "SEQUENCE-OF-CHECKED-LENGTH-GIVEN-TYPE" + "SET-ARRAY-HEADER" "SET-HEADER-DATA" + "ASSIGN-VECTOR-FLAGS" "LOGIOR-HEADER-BITS" "RESET-HEADER-BITS" + "LOGIOR-ARRAY-FLAGS" "RESET-ARRAY-FLAGS" + "TEST-HEADER-DATA-BIT" + "SHIFT-TOWARDS-END" + "SHIFT-TOWARDS-START" "SHRINK-VECTOR" "%SHRINK-VECTOR" + "SIGNED-BYTE-8-P" "SIGNED-BYTE-16-P" + "SIGNED-BYTE-32-P" "SIGNED-BYTE-64-P" + "SIMPLE-RANK-1-ARRAY-*-P" + "SIMPLE-ARRAY-COMPLEX-DOUBLE-FLOAT-P" + #+long-float "SIMPLE-ARRAY-COMPLEX-LONG-FLOAT-P" + "SIMPLE-ARRAY-COMPLEX-SINGLE-FLOAT-P" + "SIMPLE-ARRAY-DOUBLE-FLOAT-P" + #+long-float "SIMPLE-ARRAY-LONG-FLOAT-P" + "SIMPLE-ARRAY-NIL-P" "SIMPLE-ARRAY-P" + "SIMPLE-ARRAY-SINGLE-FLOAT-P" + "SIMPLE-ARRAY-UNSIGNED-BYTE-15-P" + "SIMPLE-ARRAY-UNSIGNED-BYTE-16-P" + "SIMPLE-ARRAY-UNSIGNED-BYTE-2-P" + "SIMPLE-ARRAY-UNSIGNED-FIXNUM-P" + "SIMPLE-ARRAY-UNSIGNED-BYTE-31-P" + "SIMPLE-ARRAY-UNSIGNED-BYTE-32-P" + "SIMPLE-ARRAY-UNSIGNED-BYTE-4-P" + "SIMPLE-ARRAY-UNSIGNED-BYTE-63-P" + "SIMPLE-ARRAY-UNSIGNED-BYTE-64-P" + "SIMPLE-ARRAY-UNSIGNED-BYTE-7-P" + "SIMPLE-ARRAY-UNSIGNED-BYTE-8-P" + "SIMPLE-ARRAY-SIGNED-BYTE-16-P" + "SIMPLE-ARRAY-FIXNUM-P" + "SIMPLE-ARRAY-SIGNED-BYTE-32-P" + "SIMPLE-ARRAY-SIGNED-BYTE-64-P" + "SIMPLE-ARRAY-SIGNED-BYTE-8-P" "SIMPLE-BASE-STRING-P" + "SIMPLE-CHARACTER-STRING" + #+sb-unicode "SIMPLE-CHARACTER-STRING-P" + "SIMPLE-PACKAGE-ERROR" "SIMPLE-UNBOXED-ARRAY" + "SINGLE-FLOAT-BITS" "SINGLE-FLOAT-EXPONENT" + "SINGLE-FLOAT-INT-EXPONENT" "SINGLE-FLOAT-SIGNIFICAND" + "SINGLE-FLOAT-SIGN" "SINGLE-FLOAT-COPYSIGN" + "SINGLE-VALUE-TYPE" "SINGLE-VALUE-SPECIFIER-TYPE" + "SPECIFIER-TYPE" + "STACK-REF" "STREAM-DESIGNATOR" "STRING-DESIGNATOR" + "STRING-FILL*" + "STRUCT-SLOT-SAP" + "STRUCTURE-CTOR-LAMBDA-PARTS" + "STRUCTURE-INSTANCE-ACCESSOR-P" + "SUB-GC" + "SYMBOL-TLS-INDEX" + "SYMBOLS-DESIGNATOR" + "%INSTANCE-LENGTH" + "%INSTANCE-REF" "%INSTANCE-REF-EQ" + "%INSTANCE-SET" + "TESTABLE-TYPE-P" + "TLS-EXHAUSTED-ERROR" + "*TOP-LEVEL-FORM-P*" + "TWO-ARG-*" "TWO-ARG-+" "TWO-ARG--" "TWO-ARG-/" + "TWO-ARG-/=" "TWO-ARG-<" "TWO-ARG-<=" "TWO-ARG-=" + "TWO-ARG->" "TWO-ARG->=" "TWO-ARG-AND" "TWO-ARG-EQV" + "TWO-ARG-GCD" "TWO-ARG-IOR" "TWO-ARG-LCM" "TWO-ARG-XOR" + "TWO-ARG-STRING=" "TWO-ARG-STRING-EQUAL" "TWO-ARG-STRING<" + "TWO-ARG-STRING>" "TWO-ARG-STRING<=" "TWO-ARG-STRING>=" + "TWO-ARG-STRING/=" "TWO-ARG-STRING-LESSP" "TWO-ARG-STRING-GREATERP" + "TWO-ARG-STRING-NOT-LESSP" "TWO-ARG-STRING-NOT-GREATERP" "TWO-ARG-STRING-NOT-EQUAL" + "TYPE-*-TO-T" + "TYPE-DIFFERENCE" "TYPE-INTERSECTION" + "TYPE-INTERSECTION2" "TYPE-APPROX-INTERSECTION2" + "TYPE-SINGLETON-P" + "TYPE-SINGLE-VALUE-P" "TYPE-SPECIFIER" "TYPE-UNION" + "TYPE/=" "TYPE=" "TYPES-EQUAL-OR-INTERSECT" + "TYPE-OR-NIL-IF-UNKNOWN" + "TYPE-ERROR-DATUM-STORED-TYPE" + "UNBOUND-SYMBOL-ERROR" "UNBOXED-ARRAY" + "UNDEFINED-FUN-ERROR" "UNDEFINED-ALIEN-FUN-ERROR" + "UNION-TYPE" "UNION-TYPE-P" + "UNION-TYPE-TYPES" "UNKNOWN-ERROR" + "UNINITIALIZED-ELEMENT-ERROR" ; for Lisp arrays + + "UNINITIALIZED-MEMORY-ERROR" ; for SAPs + + "UNKNOWN-KEY-ARG-ERROR" "UNKNOWN-TYPE" "UNKNOWN-TYPE-P" + "UNKNOWN-TYPE-SPECIFIER" "UNSEEN-THROW-TAG-ERROR" + "UNSIGNED-BYTE-32-P" "UNSIGNED-BYTE-64-P" + "UPDATE-OBJECT-LAYOUT" + "VALID-MACROEXPAND-HOOK" + "VALUE-CELL-REF" "VALUE-CELL-SET" "VALUES-SPECIFIER-TYPE" + "VALUES-SPECIFIER-TYPE-CACHE-CLEAR" "VALUES-SUBTYPEP" + "VALUES-TYPE" "VALUES-TYPE-IN" + "VALUES-TYPE-INTERSECTION" + "VALUES-TYPE-MIN-VALUE-COUNT" "VALUES-TYPE-MAX-VALUE-COUNT" + "VALUES-TYPE-MAY-BE-SINGLE-VALUE-P" "VALUES-TYPE-OPTIONAL" + "VALUES-TYPE-OUT" "VALUES-TYPE-P" "VALUES-TYPE-REQUIRED" + "VALUES-TYPE-REST" "VALUES-TYPE-UNION" + "VALUES-TYPE-TYPES" "VALUES-TYPES" + "VALUES-TYPES-EQUAL-OR-INTERSECT" + + "*VECTOR-WITHOUT-COMPLEX-TYPECODE-INFOS*" + "VECTOR-SINGLE-FLOAT-P" "VECTOR-DOUBLE-FLOAT-P" + "VECTOR-UNSIGNED-BYTE-2-P" "VECTOR-UNSIGNED-BYTE-4-P" + "VECTOR-UNSIGNED-BYTE-7-P" "VECTOR-UNSIGNED-BYTE-8-P" + "VECTOR-UNSIGNED-BYTE-15-P" "VECTOR-UNSIGNED-BYTE-16-P" + "VECTOR-UNSIGNED-BYTE-31-P" "VECTOR-UNSIGNED-BYTE-32-P" + "VECTOR-UNSIGNED-BYTE-63-P" "VECTOR-UNSIGNED-BYTE-64-P" + "VECTOR-SIGNED-BYTE-8-P" "VECTOR-SIGNED-BYTE-16-P" + "VECTOR-FIXNUM-P" "VECTOR-SIGNED-BYTE-32-P" + "VECTOR-SIGNED-BYTE-64-P" "VECTOR-COMPLEX-SINGLE-FLOAT-P" + "VECTOR-COMPLEX-DOUBLE-FLOAT-P" "VECTOR-T-P" + + "VECTOR-NIL-P" + "VECTOR-FILL*" "VECTOR-FILL/T" + "VECTOR-SUBSEQ*" + "VECTOR-TO-VECTOR*" + "VECTOR-OF-CHECKED-LENGTH-GIVEN-LENGTH" "WITH-ARRAY-DATA" + "WITH-CIRCULARITY-DETECTION" + "WITH-WORLD-LOCK" + + ;; bit bash fillers + + "UB1-BASH-FILL" + "UB2-BASH-FILL" + "UB4-BASH-FILL" + "UB8-BASH-FILL" + "UB16-BASH-FILL" + "UB32-BASH-FILL" + "UB64-BASH-FILL" + + "UB1-BASH-FILL-WITH-UB1" "UB1-BASH-FILL-WITH-SB1" + "UB2-BASH-FILL-WITH-UB2" "UB2-BASH-FILL-WITH-SB2" + "UB4-BASH-FILL-WITH-UB4" "UB4-BASH-FILL-WITH-SB4" + "UB8-BASH-FILL-WITH-UB8" "UB8-BASH-FILL-WITH-SB8" + "UB16-BASH-FILL-WITH-UB16" "UB16-BASH-FILL-WITH-SB16" + "UB32-BASH-FILL-WITH-UB32" "UB32-BASH-FILL-WITH-SB32" + "UB64-BASH-FILL-WITH-SB64" + "UB32-BASH-FILL-WITH-FIXNUM" "UB64-BASH-FILL-WITH-FIXNUM" + "UB32-BASH-FILL-WITH-SINGLE-FLOAT" + "UB64-BASH-FILL-WITH-DOUBLE-FLOAT" + "UB64-BASH-FILL-WITH-COMPLEX-SINGLE-FLOAT" + + ;; bit bash copiers + + "SYSTEM-AREA-UB8-COPY" + "COPY-UB8-TO-SYSTEM-AREA" "COPY-UB8-FROM-SYSTEM-AREA" + "UB1-BASH-COPY" + "UB2-BASH-COPY" + "UB4-BASH-COPY" + "UB8-BASH-COPY" + "UB16-BASH-COPY" + "UB32-BASH-COPY" + "UB64-BASH-COPY" + + ;; Bit bashing position for bit-vectors + + "%BIT-POSITION" "%BIT-POS-FWD" "%BIT-POS-REV" + "%BIT-POSITION/0" "%BIT-POS-FWD/0" "%BIT-POS-REV/0" + "%BIT-POSITION/1" "%BIT-POS-FWD/1" "%BIT-POS-REV/1" + + ;; SIMPLE-FUN type and accessors + + "SIMPLE-FUN" + "SIMPLE-FUN-P" + "%SIMPLE-FUN-ARGLIST" + "%SIMPLE-FUN-DOC" + "%SIMPLE-FUN-INFO" + "%SIMPLE-FUN-LEXPR" + "%SIMPLE-FUN-NAME" + "%SIMPLE-FUN-TEXT-LEN" + "%SIMPLE-FUN-SOURCE" + "%SIMPLE-FUN-TYPE" + "%SIMPLE-FUN-XREFS" + + ;; CLOSURE type and accessors + + "CLOSURE" + "CLOSUREP" + "DO-CLOSURE-VALUES" + "%CLOSURE-FUN" + "%CLOSURE-INDEX-REF" + "%CLOSURE-INDEX-SET" + "%CLOSURE-VALUES" + + ;; Abstract function accessors + + "%FUN-FUN" + "%FUN-LAMBDA-LIST" + "%FUN-NAME" + + "FDEFN" "MAKE-FDEFN" "FDEFN-P" "FDEFN-NAME" "FDEFN-FUN" + "FDEFN-MAKUNBOUND" + "%COERCE-CALLABLE-TO-FUN" + "%COERCE-CALLABLE-FOR-CALL" + "%FUN-POINTER-WIDETAG" + "*MAXIMUM-ERROR-DEPTH*" "%SET-SYMBOL-PLIST" + "INFINITE-ERROR-PROTECT" + "FIND-CALLER-OF-NAMED-FRAME" + "FIND-CALLER-FRAME" + "FIND-INTERRUPTED-FRAME" + "%SET-SYMBOL-VALUE" "%SET-SYMBOL-GLOBAL-VALUE" "%SET-SYMBOL-PACKAGE" + "SET-SYMBOL-GLOBAL-VALUE" + "OUTPUT-SYMBOL" "%COERCE-NAME-TO-FUN" + "DEFAULT-STRUCTURE-PRINT" + "WRAPPER" "WRAPPER-LENGTH" + "DEFSTRUCT-DESCRIPTION" "UNDECLARE-STRUCTURE" + "UNDEFINE-FUN-NAME" "DD-TYPE" "CLASSOID-STATE" "INSTANCE" + "*TYPE-SYSTEM-INITIALIZED*" "FIND-LAYOUT" + "%TYPEP" "%%TYPEP" "DD-FLAGS" "DD-NAME" "CLASSOID-SUBCLASSES" + "+DD-VARYLEN+" + "CLASSOID-LAYOUT" "CLASSOID-NAME" "CLASSOID-P" "CLASSOID-WRAPPER" + "NOTE-NAME-DEFINED" + "%CODE-CODE-SIZE" "%CODE-TEXT-SIZE" + "%CODE-SERIALNO" + "DD-SLOTS" "DD-HAS-RAW-SLOT-P" "DD-INCLUDE" "SLOT-SETTER-LAMBDA-FORM" + "SLOT-ACCESS-TRANSFORM" + "%IMAGPART" "%CODE-DEBUG-INFO" + "WRAPPER-CLASSOID" "WRAPPER-INVALID" + "WRAPPER-FLAGS" + "LAYOUT-FLAGS" + "%INSTANCEP" "DEFSTRUCT-SLOT-DESCRIPTION" + "DD-PREDICATE-NAME" + "CLASSOID-PROPER-NAME" "%NOTE-TYPE-DEFINED" "WRAPPER-INFO" + "WRAPPER-DD" + "%SET-INSTANCE-LAYOUT" + "DD-CONSTRUCTORS" "DD-DEFAULT-CONSTRUCTOR" + "WRAPPER-OF" + "%REALPART" + "STRUCTURE-CLASSOID" "STRUCTURE-CLASSOID-P" + "GET-DSD-INDEX" + "%INSTANCE-LAYOUT" "LAYOUT-CLOS-HASH" "%INSTANCEOID-LAYOUT" + "WRAPPER-CLOS-HASH" + "%INSTANCE-WRAPPER" "%FUN-WRAPPER" + "PROCLAIM-AS-FUN-NAME" "BECOME-DEFINED-FUN-NAME" + "%NUMERATOR" "CLASSOID-TYPEP" + "WRAPPER-INHERITS" "DD-LENGTH" + "SET-LAYOUT-INHERITS" + "%CODE-ENTRY-POINT" + "%CODE-FUN-OFFSET" + "CODE-N-ENTRIES" + "CODE-N-NAMED-CALLS" + "%DENOMINATOR" + "%OTHER-POINTER-P" + "%OTHER-POINTER-SUBTYPE-P" + "IMMOBILE-SPACE-ADDR-P" + "IMMOBILE-SPACE-OBJ-P" + + "STANDARD-CLASSOID" "CLASSOID-OF" + "MAKE-STANDARD-CLASSOID" + "CLASSOID-CELL-CLASSOID" + "CLASSOID-CELL-NAME" + "CLASSOID-CELL-PCL-CLASS" + "CLASSOID-CELL-TYPEP" + "%CLEAR-CLASSOID" + "FIND-CLASSOID-CELL" + "%RANDOM-DOUBLE-FLOAT" + #+long-float "%RANDOM-LONG-FLOAT" + "%RANDOM-SINGLE-FLOAT" "STATIC-CLASSOID" + "%FUNCALLABLE-INSTANCE-INFO" "RANDOM-CHUNK" "BIG-RANDOM-CHUNK" + "N-RANDOM-CHUNK-BITS" + "BUILT-IN-CLASSOID-DIRECT-SUPERCLASSES" + "BUILT-IN-CLASSOID-TRANSLATION" "HASH-LAYOUT-NAME" + "CLASSOID-PCL-CLASS" "FUNCALLABLE-STRUCTURE" + "FUNCTION-WITH-LAYOUT-P" + "%FUN-LAYOUT" "%SET-FUN-LAYOUT" + "REGISTER-LAYOUT" + "FUNCALLABLE-INSTANCE" + "MAKE-STATIC-CLASSOID" + "%MAKE-SYMBOL" + "%FUNCALLABLE-INSTANCE-FUN" "SYMBOL-HASH" "SYMBOL-HASH*" + "SYMBOL-%INFO" "SYMBOL-DBINFO" "%INFO-REF" + "%SYMBOL-FUNCTION" + + "EXTENDED-SEQUENCE" "*EXTENDED-SEQUENCE-TYPE*" + "EXTENDED-SEQUENCE-P" + + "BUILT-IN-CLASSOID" "CONDITION-CLASSOID-P" + "CONDITION-CLASSOID-SLOTS" "MAKE-UNDEFINED-CLASSOID" + "FIND-CLASSOID" "CLASSOID" "CLASSOID-DIRECT-SUPERCLASSES" + "MAKE-LAYOUT" + "INSURED-FIND-CLASSOID" "ORDER-LAYOUT-INHERITS" + "STD-COMPUTE-CLASS-PRECEDENCE-LIST" + "+STRUCTURE-LAYOUT-FLAG+" + "+PCL-OBJECT-LAYOUT-FLAG+" + "+CONDITION-LAYOUT-FLAG+" + "+PATHNAME-LAYOUT-FLAG+" + "+STREAM-LAYOUT-FLAG+" + "+SIMPLE-STREAM-LAYOUT-FLAG+" + "+FILE-STREAM-LAYOUT-FLAG+" + "+STRING-STREAM-LAYOUT-FLAG+" + "+SEQUENCE-LAYOUT-FLAG+" + "+STRICTLY-BOXED-FLAG+" + "+LAYOUT-ALL-TAGGED+" + "**PRIMITIVE-OBJECT-LAYOUTS**" + + "*HANDLER-CLUSTERS*" "*RESTART-CLUSTERS*" + "WITH-SIMPLE-CONDITION-RESTARTS" + "CASE-FAILURE" "ECASE-FAILURE" "ETYPECASE-FAILURE" + "NAMESTRING-PARSE-ERROR" + "NAMESTRING-PARSE-ERROR-OFFSET" + "NO-NAMESTRING-ERROR" "NO-NATIVE-NAMESTRING-ERROR" + "MAKE-RESTART" "RESTART-ASSOCIATED-CONDITIONS" + "COERCE-TO-CONDITION" + + "ALLOCATE-CONDITION" + + "CONDITION-SLOT-VALUE" + "SET-CONDITION-SLOT-VALUE" + + "CONDITION-SLOT-ALLOCATION" + "CONDITION-SLOT-DOCUMENTATION" + "CONDITION-SLOT-INITARGS" + "CONDITION-SLOT-INITFORM" + "CONDITION-SLOT-INITFORM-P" + "CONDITION-SLOT-INITFUNCTION" + "CONDITION-SLOT-NAME" "CONDITION-SLOT-READERS" + "CONDITION-SLOT-WRITERS" + + "REDEFINITION-WARNING" + "REDEFINITION-WITH-DEFUN" + "REDEFINITION-WITH-DEFMACRO" + "REDEFINITION-WITH-DEFGENERIC" + "REDEFINITION-WITH-DEFMETHOD" + "UNINTERESTING-ORDINARY-FUNCTION-REDEFINITION-P" + "UNINTERESTING-GENERIC-FUNCTION-REDEFINITION-P" + "UNINTERESTING-METHOD-REDEFINITION-P" + "UNINTERESTING-REDEFINITION" + "REDEFINITION-WITH-DEFTRANSFORM" + + "DUBIOUS-ASTERISKS-AROUND-VARIABLE-NAME" + "ASTERISKS-AROUND-LEXICAL-VARIABLE-NAME" + "ASTERISKS-AROUND-CONSTANT-VARIABLE-NAME" + "&OPTIONAL-AND-&KEY-IN-LAMBDA-LIST" + "UNDEFINED-ALIEN-STYLE-WARNING" + "LEXICAL-ENVIRONMENT-TOO-COMPLEX" + "CHARACTER-DECODING-ERROR-IN-COMMENT" + "DEPRECATED-EVAL-WHEN-SITUATIONS" + "PROCLAMATION-MISMATCH" + "PROCLAMATION-MISMATCH-NAME" + "PROCLAMATION-MISMATCH-NEW" + "PROCLAMATION-MISMATCH-OLD" + "TYPE-PROCLAMATION-MISMATCH" + "TYPE-PROCLAMATION-MISMATCH-WARNING" + "TYPE-PROCLAMATION-MISMATCH-WARN" + "FTYPE-PROCLAMATION-MISMATCH" + "FTYPE-PROCLAMATION-MISMATCH-WARNING" + "FTYPE-PROCLAMATION-MISMATCH-WARN" + "FTYPE-PROCLAMATION-MISMATCH-ERROR" + + "!COLD-INIT" + "!TYPE-CLASS-COLD-INIT" + "!CLASSES-COLD-INIT" + "!TYPE-COLD-INIT" + "!FIXUP-TYPE-COLD-INIT" + "!RANDOM-COLD-INIT" + "!LOADER-COLD-INIT" + "!POLICY-COLD-INIT-OR-RESANIFY" + "!LATE-PROCLAIM-COLD-INIT" "!CLASS-FINALIZE" + + "FLOAT-COLD-INIT-OR-REINIT" + "GC-REINIT" + "TIME-REINIT" + "SIGNAL-COLD-INIT-OR-REINIT" + "STREAM-COLD-INIT-OR-RESET" + + ;; Cleanups to run before saving a core + + "FLOAT-DEINIT" + "FOREIGN-DEINIT" + "PROFILE-DEINIT" + + ;; Note: These are out of lexicographical order + ;; because in CMU CL they were defined as + ;; internal symbols in package "CL" imported + ;; into package "C", as opposed to what we're + ;; doing here, defining them as external symbols + ;; in a package which is used by both "SB-C" and + ;; "SB-IMPL". (SBCL's "SB-C" is directly + ;; analogous to CMU CL's "C"; and for this + ;; purpose, SBCL's "SB-IMPL" is analogous to CMU + ;; CL's "CL".) As far as I know there's nothing + ;; special about them, so they could be merged + ;; into the same order as everything else in the + ;; in this package. -- WHN 19990911 + + "STRING>=*" "STRING>*" "STRING=*" "STRING<=*" + "STRING<*" "STRING/=*" "%SVSET" + "SIMPLE-BASE-STRING=" #+sb-unicode "SIMPLE-CHARACTER-STRING=" + "%SP-STRING-COMPARE" "%SP-STRING=" + "%SETNTH" "%SETELT" + "%SET-ROW-MAJOR-AREF" "%SET-FILL-POINTER" + "%SET-FDEFINITION" "%SCHARSET" + "%RPLACD" "%RPLACA" "%PUT" "%CHARSET" + "%WITH-OUTPUT-TO-STRING" + "INLINE-VOP") + #+sb-simd-pack + (:export "SIMD-PACK" + "SIMD-PACK-P" + "%MAKE-SIMD-PACK-UB32" + "%MAKE-SIMD-PACK-UB64" + "%MAKE-SIMD-PACK-DOUBLE" + "%MAKE-SIMD-PACK-SINGLE" + "%SIMD-PACK-UB32S" + "%SIMD-PACK-UB64S" + "%SIMD-PACK-DOUBLES" + "%SIMD-PACK-SINGLES") + #+sb-simd-pack + (:export "%SIMD-PACK-TAG" + "%SIMD-PACK-LOW" + "%SIMD-PACK-HIGH") + #+sb-simd-pack-256 + (:export "%SIMD-PACK-256-TAG" + "%SIMD-PACK-256-0" "%SIMD-PACK-256-1" + "%SIMD-PACK-256-2" "%SIMD-PACK-256-3") + #+sb-simd-pack + (:export "SIMD-PACK-SINGLE" + "SIMD-PACK-DOUBLE" + "SIMD-PACK-INT" + "SIMD-PACK-TYPE" + "SIMD-PACK-TYPE-ELEMENT-TYPE" + "*SIMD-PACK-ELEMENT-TYPES*") + #+sb-simd-pack-256 + (:export "SIMD-PACK-256-SINGLE" + "SIMD-PACK-256-DOUBLE" + "SIMD-PACK-256-INT" + "SIMD-PACK-256-TYPE" + "SIMD-PACK-256-TYPE-ELEMENT-TYPE") + #+long-float + (:export "LONG-FLOAT-EXPONENT" "LONG-FLOAT-EXP-BITS" + "LONG-FLOAT-HIGH-BITS" "LONG-FLOAT-LOW-BITS" + "LONG-FLOAT-MID-BITS")) + +(defpackage* "SB-ASSEM" + (:documentation "private: the assembler, used by the compiler") + (:use "CL" "SB-EXT" "SB-INT") + (:import-from "SB-C" "BRANCH" "FLUSHABLE") + (:export "ASSEMBLY-UNIT" + "ASSEMBLY-UNIT-BITS" + "+INST-ALIGNMENT-BYTES+" + + "ASSEM-SCHEDULER-P" + "+ASSEM-MAX-LOCATIONS+" + + "*ASMSTREAM*" "MAKE-ASMSTREAM" + "ASMSTREAM-DATA-SECTION" + "ASMSTREAM-CODE-SECTION" + "ASMSTREAM-ELSEWHERE-SECTION" + "ASMSTREAM-ELSEWHERE-LABEL" + "ASMSTREAM-CONSTANT-TABLE" + "ASMSTREAM-CONSTANT-VECTOR" + "APPEND-SECTIONS" "ASSEMBLE-SECTIONS" + "EMIT" ".ALIGN" ".BYTE" ".LISPWORD" ".SKIP" + ".COMMENT" + "EMIT-ALIGNMENT" "EMIT-BYTE" "EMIT-BACK-PATCH" + "EMIT-CHOOSER" "DEFINE-BITFIELD-EMITTER" + "DEFINE-INSTRUCTION" "DEFINE-INSTRUCTION-MACRO" + "EMIT-POSTIT" + "ANY-ALIGNMENT-BETWEEN-P" + + "MAKE-SEGMENT" "SEGMENT-ORIGIN" "ASSEMBLE" + "SEGMENT-BUFFER" + "SEGMENT-ENCODER-STATE" + "SEGMENT-HEADER-SKEW" + "INST" "INST*" "LABEL" "LABEL-P" "GEN-LABEL" + "EMIT-LABEL" "LABEL-POSITION" "LABEL-USEDP" + "FINALIZE-SEGMENT" + "SEGMENT-CONTENTS-AS-VECTOR" "WRITE-SEGMENT-CONTENTS" + "READS" "WRITES" "SEGMENT" + "WITHOUT-SCHEDULING" + "VARIABLE-LENGTH" + "SEGMENT-COLLECT-DYNAMIC-STATISTICS" + "SECTION-START" + "STMT-LABELS" "STMT-MNEMONIC" "STMT-OPERANDS" + "STMT-PLIST" + "STMT-PREV" "STMT-NEXT" + "ADD-STMT-LABELS" "DELETE-STMT" + "LABELED-STATEMENT-P" + "DEFPATTERN")) + +(defpackage* "SB-THREAD" + (:documentation "public (but low-level): native thread support") + (:use "CL" "SB-ALIEN" "SB-INT" "SB-SYS" "SB-KERNEL") + (:export "*CURRENT-THREAD*" + "DESTROY-THREAD" + "INTERRUPT-THREAD" + "INTERRUPT-THREAD-ERROR" + "INTERRUPT-THREAD-ERROR-THREAD" + "RETURN-FROM-THREAD" + "ABORT-THREAD" + "MAIN-THREAD-P" + "MAIN-THREAD" + "JOIN-THREAD" + "JOIN-THREAD-ERROR" + "JOIN-THREAD-ERROR-THREAD" + "LIST-ALL-THREADS" + "MAKE-THREAD" + "SYMBOL-VALUE-IN-THREAD" + "SYMBOL-VALUE-IN-THREAD-ERROR" + "TERMINATE-THREAD" + "THREAD" + "THREAD-DEADLOCK" + "THREAD-DEADLOCK-CYCLE" + "THREAD-ERROR" + "THREAD-ERROR-THREAD" + "THREAD-ALIVE-P" + "THREAD-EPHEMERAL-P" + "THREAD-NAME" + "THREAD-OS-TID" + "THREAD-YIELD" + "FOREIGN-THREAD" + ;; Memory barrier + + "BARRIER" + ;; Mutexes + + "GET-MUTEX" + "GRAB-MUTEX" + "HOLDING-MUTEX-P" + "MAKE-MUTEX" + "MUTEX" + "MUTEX-NAME" + "MUTEX-OWNER" + "MUTEX-VALUE" + "RELEASE-MUTEX" + "WITH-MUTEX" + "WITH-RECURSIVE-LOCK" + ;; Condition variables + + "CONDITION-BROADCAST" + "CONDITION-NOTIFY" + "CONDITION-WAIT" + "MAKE-WAITQUEUE" + "WAITQUEUE" + "WAITQUEUE-NAME" + ;; Sessions + + "MAKE-LISTENER-THREAD" + "RELEASE-FOREGROUND" + "WITH-NEW-SESSION" + ;; Semaphores + + "MAKE-SEMAPHORE" + "SEMAPHORE" + "SEMAPHORE-NAME" + "SEMAPHORE-COUNT" + "SIGNAL-SEMAPHORE" + "TRY-SEMAPHORE" + "WAIT-ON-SEMAPHORE" + ;; Semaphore notification objects + + "CLEAR-SEMAPHORE-NOTIFICATION" + "MAKE-SEMAPHORE-NOTIFICATION" + "SEMAPHORE-NOTIFICATION" + "SEMAPHORE-NOTIFICATION-STATUS")) + +(defpackage* "SB-WALKER" + (:documentation "internal: a code walker used by PCL") + (:use "CL" "SB-INT" "SB-EXT") + (:shadow "RECONS") + (:export "DEFINE-WALKER-TEMPLATE" + "MACROEXPAND-ALL" + "WALK-FORM" + "*WALK-FORM-EXPAND-MACROS-P*" + "VAR-LEXICAL-P" "VAR-SPECIAL-P" + "VAR-GLOBALLY-SPECIAL-P" + "VAR-DECLARATION")) + +(defpackage* "SB-UNICODE" + (:documentation "public: algorithms for Unicode data") + (:use "CL" "SB-INT") + (:export "GENERAL-CATEGORY" + "BIDI-CLASS" + "COMBINING-CLASS" + "DECIMAL-VALUE" + "DIGIT-VALUE" + "NUMERIC-VALUE" + "MIRRORED-P" + "BIDI-MIRRORING-GLYPH" + "AGE" + "HANGUL-SYLLABLE-TYPE" + "EAST-ASIAN-WIDTH" + "SCRIPT" + "CHAR-BLOCK" + "UNICODE-1-NAME" + "LINE-BREAK-CLASS" + "PROPLIST-P" + "UPPERCASE-P" + "LOWERCASE-P" + "CASED-P" + "CASE-IGNORABLE-P" + "ALPHABETIC-P" + "IDEOGRAPHIC-P" + "MATH-P" + "WHITESPACE-P" + "HEX-DIGIT-P" + "SOFT-DOTTED-P" + "DEFAULT-IGNORABLE-P" + "NORMALIZE-STRING" + "NORMALIZED-P" + "UPPERCASE" + "LOWERCASE" + "TITLECASE" + "CASEFOLD" + "GRAPHEME-BREAK-CLASS" + "WORD-BREAK-CLASS" + "SENTENCE-BREAK-CLASS" + "GRAPHEMES" + "WORDS" + "SENTENCES" + "LINES" + "UNICODE=" + "UNICODE-EQUAL" + "UNICODE<" + "UNICODE<=" + "UNICODE>" + "UNICODE>=" + "CONFUSABLE-P")) + +(defpackage* "SB-GRAY" + (:documentation + "public: an implementation of the stream-definition-by-user +Lisp extension proposal by David N. Gray") + (:use "CL" "SB-EXT" "SB-INT" "SB-KERNEL") + (:export "FUNDAMENTAL-BINARY-STREAM" + "FUNDAMENTAL-BINARY-INPUT-STREAM" + "FUNDAMENTAL-BINARY-OUTPUT-STREAM" "FUNDAMENTAL-CHARACTER-STREAM" + "FUNDAMENTAL-CHARACTER-INPUT-STREAM" + "FUNDAMENTAL-CHARACTER-OUTPUT-STREAM" + "FUNDAMENTAL-INPUT-STREAM" "FUNDAMENTAL-OUTPUT-STREAM" + "FUNDAMENTAL-STREAM" + "STREAM-ADVANCE-TO-COLUMN" "STREAM-CLEAR-INPUT" + "STREAM-CLEAR-OUTPUT" "STREAM-FILE-POSITION" "STREAM-FINISH-OUTPUT" "STREAM-FORCE-OUTPUT" + "STREAM-FRESH-LINE" "STREAM-LINE-COLUMN" "STREAM-LINE-LENGTH" + "STREAM-LISTEN" "STREAM-PEEK-CHAR" "STREAM-READ-BYTE" + "STREAM-READ-CHAR" "STREAM-READ-CHAR-NO-HANG" "STREAM-READ-LINE" + "STREAM-READ-SEQUENCE" "STREAM-START-LINE-P" "STREAM-TERPRI" + "STREAM-UNREAD-CHAR" + "STREAM-WRITE-BYTE" "STREAM-WRITE-CHAR" "STREAM-WRITE-SEQUENCE" + "STREAM-WRITE-STRING")) + +(defpackage* "SB-INT" + (:documentation + "private: miscellaneous unsupported extensions to the ANSI spec. Much of +the stuff in here originated in CMU CL's EXTENSIONS package and is retained, +possibly temporarily, because it might be used internally.") + (:use "CL" "SB-ALIEN" "SB-GRAY" "SB-FASL" "SB-SYS") + (:export ;; lambda list keyword extensions + "&MORE" + + ;; utilities for floating point zero handling + + "FP-ZERO-P" + + ;; Advice to the compiler that it doesn't need to assert types. + + "EXPLICIT-CHECK" + ;; Stack allocation without any questions asked + + "TRULY-DYNAMIC-EXTENT" + + "WITH-SYSTEM-MUTEX" + "HASH-TABLE-LOCK" + + ;; generic set implementation backed by a list that upgrades + ;; to a hashtable if a certain size is exceeded. + + "ADD-TO-XSET" + "ALLOC-XSET" + "MAP-XSET" + "XSET" + "XSET-COUNT" + "XSET-EMPTY-P" + "XSET-INTERSECTION" + "XSET-MEMBER-P" + "XSET-MEMBERS" + "XSET-SUBSET-P" + "XSET-UNION" + "XSET=" + + ;; sparse set implementation backed by a lightweight hashtable + + "COPY-SSET" + "DO-SSET-ELEMENTS" + "MAKE-SSET" + "SSET" "SSET-ELEMENT" + "SSET-ADJOIN" "SSET-DELETE" "SSET-EMPTY" "SSET-COUNT" + "SSET-MEMBER" + + ;; communication between the runtime and Lisp + + "*CORE-STRING*" + + ;; INFO stuff doesn't belong in a user-visible package, we + ;; should be able to change it without apology. + + "*INFO-ENVIRONMENT*" + "*RECOGNIZED-DECLARATIONS*" + "+INFOS-PER-WORD+" + "+FDEFN-INFO-NUM+" + "PACKED-INFO" + "+NIL-PACKED-INFOS+" + "ATOMIC-SET-INFO-VALUE" + "CALL-WITH-EACH-GLOBALDB-NAME" + "CLEAR-INFO" + "CLEAR-INFO-VALUES" + "DEFINE-INFO-TYPE" + "FIND-FDEFN" + "GET-INFO-VALUE-INITIALIZING" + "GLOBALDB-SXHASHOID" + "GLOBAL-FTYPE" + "INFO" + "INFO-FIND-AUX-KEY/PACKED" + "INFO-GETHASH" + "INFO-MAPHASH" + "INFO-NUMBER" + "INFO-NUMBER-BITS" + "PACKED-INFO-FDEFN" + "MAKE-INFO-HASHTABLE" + "META-INFO" + "META-INFO-NUMBER" + "PACKED-INFO-FIELD" + "PACKED-INFO-INSERT" + "PCL-METHODFN-NAME-P" + "SET-INFO-VALUE" + "SHOW-INFO" + "UPDATE-SYMBOL-INFO" + "WITH-GLOBALDB-NAME" + "%BOUNDP" + + ;; Calling a list of hook functions, plus error handling. + + "CALL-HOOKS" + ;; Constant form evaluation + + "CONSTANT-FORM-VALUE" + + ;; stepping control + + "*STEPPING*" + + ;; packages grabbed once and for all + + "*KEYWORD-PACKAGE*" "*CL-PACKAGE*" + + ;; hash mixing operations + + "MIX" "MIXF" "WORD-MIX" + "GOOD-HASH-WORD->FIXNUM" + + ;; Macroexpansion that doesn't touch special forms + + "%MACROEXPAND" + "%MACROEXPAND-1" + + "*SETF-COMPILER-MACRO-FUNCTION-HOOK*" + "*SETF-FDEFINITION-HOOK*" + "*SETF-MACRO-FUNCTION-HOOK*" + + ;; error-reporting facilities + + "ARGUMENTS-OUT-OF-DOMAIN-ERROR" + "CLOSED-STREAM-ERROR" "CLOSED-SAVED-STREAM-ERROR" + "COMPILED-PROGRAM-ERROR" + "COMPILER-MACRO-KEYWORD-PROBLEM" + "ENCAPSULATED-CONDITION" + "INVALID-ARRAY-ERROR" + "INVALID-ARRAY-INDEX-ERROR" + "INVALID-ARRAY-P" + "SIMPLE-CONTROL-ERROR" "SIMPLE-FILE-ERROR" + "SIMPLE-PARSE-ERROR" + "SIMPLE-PROGRAM-ERROR" "%PROGRAM-ERROR" + "SIMPLE-READER-ERROR" + "SIMPLE-READER-PACKAGE-ERROR" + "SIMPLE-REFERENCE-ERROR" + "SIMPLE-REFERENCE-WARNING" + "SIMPLE-STREAM-ERROR" + "SIMPLE-STORAGE-CONDITION" + "SIMPLE-STYLE-WARNING" + "STREAM-ERROR-POSITION-INFO" + "TRY-RESTART" + + "BROKEN-PIPE" + + ;; error-signalling facilities + + "STANDARD-READTABLE-MODIFIED-ERROR" + "STANDARD-PPRINT-DISPATCH-TABLE-MODIFIED-ERROR" + "ARRAY-BOUNDING-INDICES-BAD-ERROR" + "CIRCULAR-LIST-ERROR" + "SEQUENCE-BOUNDING-INDICES-BAD-ERROR" + "SPECIAL-FORM-FUNCTION" + "STYLE-WARN" "SIMPLE-COMPILER-NOTE" + "TWO-ARG-CHAR-EQUAL" "TWO-ARG-CHAR-NOT-EQUAL" + "TWO-ARG-CHAR-LESSP" "TWO-ARG-CHAR-NOT-LESSP" + "TWO-ARG-CHAR-GREATERP" "TWO-ARG-CHAR-NOT-GREATERP" + "CHAR-CASE-INFO" + ;; FIXME: potential SB-EXT exports + + "CHARACTER-CODING-ERROR" + "CHARACTER-DECODING-ERROR" "CHARACTER-DECODING-ERROR-OCTETS" + "CHARACTER-ENCODING-ERROR" "CHARACTER-ENCODING-ERROR-CODE" + "STREAM-DECODING-ERROR" "STREAM-ENCODING-ERROR" + "C-STRING-ENCODING-ERROR" + "C-STRING-DECODING-ERROR" + "ATTEMPT-RESYNC" "FORCE-END-OF-FILE" + + ;; bootstrapping magic, to make things happen both in + ;; the cross-compilation host compiler's environment and + ;; in the cross-compiler's environment + + "DEF!STRUCT" "DEF!TYPE" + "*!REMOVABLE-SYMBOLS*" + + ;; bootstrapping macro whose effect is to delay until warm load. + + "!SET-LOAD-FORM-METHOD" + + ;; stuff for hinting to the compiler + + "NAMED-DS-BIND" + "NAMED-LAMBDA" + + ;; other variations on DEFFOO stuff useful for bootstrapping + ;; and cross-compiling + + "DEFCONSTANT-EQX" + "DEFINE-UNSUPPORTED-FUN" + + ;; messing with PATHNAMEs + + "MAKE-TRIVIAL-DEFAULT-PATHNAME" + "MAKE-TRIVIAL-DEFAULT-LOGICAL-PATHNAME" + "PHYSICALIZE-PATHNAME" + "SANE-DEFAULT-PATHNAME-DEFAULTS" + "SBCL-HOMEDIR-PATHNAME" + "SIMPLIFY-NAMESTRING" + "DEBUG-SOURCE-NAMESTRING" + "DEBUG-SOURCE-CREATED" + + "*N-BYTES-FREED-OR-PURIFIED*" + + ;; Deprecating stuff + + "DEFINE-DEPRECATED-FUNCTION" + "DEFINE-DEPRECATED-VARIABLE" + "DEPRECATION-STATE" + "DEPRECATION-INFO" "MAKE-DEPRECATION-INFO" + "DEPRECATION-INFO-STATE" + "DEPRECATION-INFO-SOFTWARE" + "DEPRECATION-INFO-VERSION" + "DEPRECATION-INFO-REPLACEMENTS" + "PRINT-DEPRECATION-MESSAGE" + "CHECK-DEPRECATED-THING" "CHECK-DEPRECATED-TYPE" + "DEPRECATED-THING-P" + "DEPRECATION-WARN" + "LOADER-DEPRECATION-WARN" + + ;; miscellaneous non-standard but handy user-level functions.. + + "ASSQ" "DELQ" "DELQ1" "MEMQ" "POSQ" "NEQ" + "ADJUST-LIST" + "ALIGN-UP" + "%FIND-PACKAGE-OR-LOSE" "FIND-UNDELETED-PACKAGE-OR-LOSE" + "SANE-PACKAGE" + "COALESCE-TREE-P" + "COMPOUND-OBJECT-P" + "SWAPPED-ARGS-FUN" + "AND/TYPE" "NOT/TYPE" + "ANY/TYPE" "EVERY/TYPE" + "EQUAL-BUT-NO-CAR-RECURSION" + "TYPE-BOUND-NUMBER" "COERCE-NUMERIC-BOUND" + "CONSTANTLY-T" "CONSTANTLY-NIL" "CONSTANTLY-0" + "PSXHASH" + "%BREAK" + "BIT-VECTOR-=" + "PATHNAME=" + "%HASH-TABLE-ALIST" + "HASH-TABLE-EQUALP" + "READ-EVALUATED-FORM" "READ-EVALUATED-FORM-OF-TYPE" + "PICK-BEST-SXHASH-BITS" + + "MAKE-UNPRINTABLE-OBJECT" + "POSSIBLY-BASE-STRINGIZE" + "POWER-OF-TWO-CEILING" + "PRINT-NOT-READABLE-ERROR" + "HASH-TABLE-REPLACE" + "RECONS" + "SET-CLOSURE-NAME" + + ;; ..and macros.. + + "COLLECT" + "COPY-LIST-MACRO" + "DO-ANONYMOUS" "DOVECTOR" "DOHASH" "DOPLIST" + "ENSURE-GETHASH" + "GET-SIMILAR" + "NAMED-LET" + "ONCE-ONLY" + "DEFENUM" + "DEFPRINTER" + "*PRINT-IR-NODES-PRETTY*" + "AVER" + "DX-FLET" "DX-LET" + "AWHEN" "ACOND" "IT" + "BINDING*" "EXTRACT-VAR-DECLS" + "!DEF-BOOLEAN-ATTRIBUTE" + "FUNARG-BIND/CALL-FORMS" + "QUASIQUOTE" + "COMMA-P" + "COMMA-EXPR" + "COMMA-KIND" + "UNQUOTE" + "PACKAGE-HASHTABLE" + "PACKAGE-ITER-STEP" + "WITH-REBOUND-IO-SYNTAX" + "WITH-SANE-IO-SYNTAX" + "WITH-PROGRESSIVE-TIMEOUT" + + ;; ..and CONDITIONs.. + + "BUG" + "UNSUPPORTED-OPERATOR" + + "BOOTSTRAP-PACKAGE-NAME" + "BOOTSTRAP-PACKAGE-NOT-FOUND" + "DEBOOTSTRAP-PACKAGE" + "SYSTEM-PACKAGE-P" + + "REFERENCE-CONDITION" "REFERENCE-CONDITION-REFERENCES" + "*PRINT-CONDITION-REFERENCES*" + + "DUPLICATE-DEFINITION" "DUPLICATE-DEFINITION-NAME" + "SAME-FILE-REDEFINITION-WARNING" + "PACKAGE-AT-VARIANCE" + "PACKAGE-AT-VARIANCE-ERROR" + "ARRAY-INITIAL-ELEMENT-MISMATCH" + "INITIAL-ELEMENT-MISMATCH-STYLE-WARNING" + "TYPE-WARNING" "TYPE-STYLE-WARNING" + "SLOT-INITFORM-TYPE-STYLE-WARNING" + "LOCAL-ARGUMENT-MISMATCH" + "FORMAT-ARGS-MISMATCH" "FORMAT-TOO-FEW-ARGS-WARNING" + "FORMAT-TOO-MANY-ARGS-WARNING" "EXTENSION-FAILURE" + "STRUCTURE-INITARG-NOT-KEYWORD" "CONSTANT-MODIFIED" + + ;; ..and DEFTYPEs.. + + "HASH-CODE" + "INDEX" "LOAD/STORE-INDEX" + "SIGNED-BYTE-WITH-A-BITE-OUT" + "UNSIGNED-BYTE-WITH-A-BITE-OUT" + "SFUNCTION" "UNSIGNED-BYTE*" + "CONSTANT-DISPLACEMENT" + "EXTENDED-FUNCTION-DESIGNATOR" + "EXTENDED-FUNCTION-DESIGNATOR-P" + ;; ..and type predicates + + "DOUBLE-FLOAT-P" + "LOGICAL-PATHNAME-P" + "LONG-FLOAT-P" + "SHORT-FLOAT-P" + "SINGLE-FLOAT-P" + "FIXNUMP" + "BIGNUMP" + "RATIOP" + "UNBOUND-MARKER-P" + + ;; encapsulation + + "ENCAPSULATE" "ENCAPSULATED-P" + "UNENCAPSULATE" + "ENCAPSULATE-FUNOBJ" + + ;; various CHAR-CODEs + + "BACKSPACE-CHAR-CODE" "BELL-CHAR-CODE" "ESCAPE-CHAR-CODE" + "FORM-FEED-CHAR-CODE" "LINE-FEED-CHAR-CODE" + "RETURN-CHAR-CODE" "RUBOUT-CHAR-CODE" "TAB-CHAR-CODE" + + ;; symbol-hacking idioms + + "GENSYMIFY" "GENSYMIFY*" "KEYWORDICATE" "SYMBOLICATE" + "INTERNED-SYMBOL-P" "PACKAGE-SYMBOLICATE" + "LOGICALLY-READONLYIZE" + + ;; certainly doesn't belong in public extensions + ;; FIXME: maybe belongs in %KERNEL with other typesystem stuff? + + "CONSTANT-ARG" + + ;; various internal defaults + + "*LOAD-SOURCE-DEFAULT-TYPE*" "BASE-CHAR-CODE-LIMIT" + + ;; hash caches + + "DEFUN-CACHED" + "DROP-ALL-HASH-CACHES" + + ;; time + + "FORMAT-DECODED-TIME" + "FORMAT-UNIVERSAL-TIME" + + ;; used for FORMAT tilde paren + + "MAKE-CASE-FROB-STREAM" + + ;; helpers for C library calls + + "STRERROR" "SIMPLE-PERROR" + + ;; debuggers' little helpers + + #+sb-show "*/SHOW*" + #+sb-show "HEXSTR" + "/SHOW" "/NOSHOW" + "/SHOW0" "/NOSHOW0" + + ;; cross-compilation bootstrap hacks which turn into + ;; placeholders in a target system + + "UNCROSS" + "!UNCROSS-FORMAT-CONTROL" + + ;; might as well be shared among the various files which + ;; need it: + + "*EOF-OBJECT*" + + ;; allocation to static space + + "MAKE-STATIC-VECTOR" + + ;; alien interface utilities + + "C-STRINGS->STRING-LIST" + + ;; misc. utilities used internally + + "ADDRESS-BASED-COUNTER-VAL" + "DEFINE-FUNCTION-NAME-SYNTAX" "VALID-FUNCTION-NAME-P" ; should be SB-EXT? + + "LEGAL-VARIABLE-NAME-P" + "LEGAL-FUN-NAME-P" "LEGAL-FUN-NAME-OR-TYPE-ERROR" + "LEGAL-CLASS-NAME-P" + "FUN-NAME-BLOCK-NAME" + "FUN-NAME-INLINE-EXPANSION" + "LISTEN-SKIP-WHITESPACE" + "PACKAGE-INTERNAL-SYMBOL-COUNT" "PACKAGE-EXTERNAL-SYMBOL-COUNT" + "PARSE-BODY" "PARSE-LAMBDA-LIST" "MAKE-LAMBDA-LIST" + "CHECK-DESIGNATOR" + "CHECK-LAMBDA-LIST-NAMES" + "LAMBDA-LIST-KEYWORD-MASK" + "PARSE-KEY-ARG-SPEC" "PARSE-OPTIONAL-ARG-SPEC" + "LL-KWDS-RESTP" "LL-KWDS-KEYP" "LL-KWDS-ALLOWP" + "MAKE-MACRO-LAMBDA" + "PROPER-LIST-OF-LENGTH-P" "PROPER-LIST-P" + "LIST-OF-LENGTH-AT-LEAST-P" "SEQUENCE-OF-LENGTH-AT-LEAST-P" + "SINGLETON-P" "ENSURE-LIST" + "MISSING-ARG" + "FEATUREP" + "FLUSH-STANDARD-OUTPUT-STREAMS" + "WITH-UNIQUE-NAMES" "MAKE-GENSYM-LIST" + "ABOUT-TO-MODIFY-SYMBOL-VALUE" + "SELF-EVALUATING-P" + "PRINT-PRETTY-ON-STREAM-P" + "ARRAY-READABLY-PRINTABLE-P" + "LOOKS-LIKE-NAME-OF-SPECIAL-VAR-P" + "POSITIVE-PRIMEP" + "EVAL-IN-LEXENV" + "SIMPLE-EVAL-IN-LEXENV" + "FORCE" "DELAY" "PROMISE-READY-P" + "FIND-RESTART-OR-CONTROL-ERROR" + "LOAD-AS-SOURCE" + "DESCRIPTOR-SAP" + "DO-PACKED-VARINTS" + + "CLOSURE-EXTRA-VALUES" + "PACK-CLOSURE-EXTRA-VALUES" + "SET-CLOSURE-EXTRA-VALUES" + "+CLOSURE-NAME-INDEX+" + + ;; These could be moved back into SB-EXT if someone has + ;; compelling reasons, but hopefully we can get by + ;; without supporting them, at least not as publicly + ;; accessible things with fixed interfaces. + + "GET-FLOATING-POINT-MODES" + "SET-FLOATING-POINT-MODES" + "WITH-FLOAT-TRAPS-MASKED" + + ;; a sort of quasi-unbound tag for use in hash tables + + "+EMPTY-HT-SLOT+" + + ;; low-level i/o stuff + + "DONE-WITH-FAST-READ-CHAR" + "FAST-READ-BYTE" + "FAST-READ-BYTE-REFILL" + "FAST-READ-CHAR" + "FAST-READ-CHAR-REFILL" + "FAST-READ-S-INTEGER" + "FAST-READ-U-INTEGER" + "FAST-READ-VAR-U-INTEGER" + "FILE-NAME" + "FORM-TRACKING-STREAM" + "FORM-TRACKING-STREAM-OBSERVER" + "FORM-TRACKING-STREAM-P" + "FORM-TRACKING-STREAM-FORM-START-BYTE-POS" + "FORM-TRACKING-STREAM-FORM-START-CHAR-POS" + "LINE/COL-FROM-CHARPOS" + "%INTERN" + "WITH-FAST-READ-BYTE" + "PREPARE-FOR-FAST-READ-CHAR" + "OUT-STREAM-FROM-DESIGNATOR" + "STRINGIFY-OBJECT" + "%WRITE" + + ;; hackery to help set up for cold init + + "!BEGIN-COLLECTING-COLD-INIT-FORMS" + "!COLD-INIT-FORMS" + "!DEFUN-FROM-COLLECTED-COLD-INIT-FORMS" + + ;; catch tags + + "TOPLEVEL-CATCHER" + + ;; hooks for contrib/ stuff we're insufficiently sure + ;; about to add to SB-EXT + + "*REPL-PROMPT-FUN*" + "*REPL-READ-FORM-FUN*" + + ;; Character database access + + "MISC-INDEX" + "CLEAR-FLAG" + "PACK-3-CODEPOINTS" + + ;; Huffman trees + + "HUFFMAN-ENCODE" + "HUFFMAN-DECODE" + "BINARY-SEARCH" + "DOUBLE-VECTOR-BINARY-SEARCH")) + +(defpackage* "SB-MOP" + (:documentation + "public: the MetaObject Protocol interface, as defined by +The Art of the Metaobject Protocol, by Kiczales, des Rivieres and Bobrow: +ISBN 0-262-61074-4, with exceptions as noted in the User Manual.") + (:use "CL") + (:import-from "CL" + "ADD-METHOD" + "ALLOCATE-INSTANCE" + "CLASS-NAME" "COMPUTE-APPLICABLE-METHODS" + "ENSURE-GENERIC-FUNCTION" "MAKE-INSTANCE" + "METHOD-QUALIFIERS" "REMOVE-METHOD" + "BUILT-IN-CLASS" "CLASS" + "FUNCTION" "GENERIC-FUNCTION" + "METHOD" "METHOD-COMBINATION" + "STANDARD-CLASS" "STANDARD-GENERIC-FUNCTION" + "STANDARD-METHOD" "STANDARD-OBJECT" "T") + (:export "ADD-DEPENDENT" + "ADD-DIRECT-METHOD" + "ADD-DIRECT-SUBCLASS" + "ADD-METHOD" + "ALLOCATE-INSTANCE" + "BUILT-IN-CLASS" + "CLASS" + "CLASS-DEFAULT-INITARGS" + "CLASS-DIRECT-DEFAULT-INITARGS" + "CLASS-DIRECT-SLOTS" + "CLASS-DIRECT-SUBCLASSES" + "CLASS-DIRECT-SUPERCLASSES" + "CLASS-FINALIZED-P" + "CLASS-NAME" + "CLASS-PRECEDENCE-LIST" + "CLASS-PROTOTYPE" + "CLASS-SLOTS" + "COMPUTE-APPLICABLE-METHODS" + "COMPUTE-APPLICABLE-METHODS-USING-CLASSES" + "COMPUTE-CLASS-PRECEDENCE-LIST" + "COMPUTE-DEFAULT-INITARGS" + "COMPUTE-DISCRIMINATING-FUNCTION" + "COMPUTE-EFFECTIVE-METHOD" + "COMPUTE-EFFECTIVE-SLOT-DEFINITION" + "COMPUTE-SLOTS" + "DIRECT-SLOT-DEFINITION" + "DIRECT-SLOT-DEFINITION-CLASS" + "EFFECTIVE-SLOT-DEFINITION" + "EFFECTIVE-SLOT-DEFINITION-CLASS" + "ENSURE-CLASS" + "ENSURE-CLASS-USING-CLASS" + "ENSURE-GENERIC-FUNCTION" + "ENSURE-GENERIC-FUNCTION-USING-CLASS" + "EQL-SPECIALIZER" + "EQL-SPECIALIZER-OBJECT" + "EXTRACT-LAMBDA-LIST" + "EXTRACT-SPECIALIZER-NAMES" + "FINALIZE-INHERITANCE" + "FIND-METHOD-COMBINATION" + "FORWARD-REFERENCED-CLASS" + "FUNCALLABLE-STANDARD-CLASS" + "FUNCALLABLE-STANDARD-INSTANCE-ACCESS" + "FUNCALLABLE-STANDARD-OBJECT" + "FUNCTION" + "GENERIC-FUNCTION-ARGUMENT-PRECEDENCE-ORDER" + "GENERIC-FUNCTION" + "GENERIC-FUNCTION-DECLARATIONS" + "GENERIC-FUNCTION-LAMBDA-LIST" + "GENERIC-FUNCTION-METHOD-CLASS" + "GENERIC-FUNCTION-METHOD-COMBINATION" + "GENERIC-FUNCTION-METHODS" + "GENERIC-FUNCTION-NAME" + "INTERN-EQL-SPECIALIZER" + "MAKE-INSTANCE" + "MAKE-METHOD-LAMBDA" + "MAP-DEPENDENTS" + "METAOBJECT" + "METHOD" + "METHOD-COMBINATION" + "METHOD-FUNCTION" + "METHOD-GENERIC-FUNCTION" + "METHOD-LAMBDA-LIST" + "METHOD-QUALIFIERS" + "METHOD-SPECIALIZERS" + "ACCESSOR-METHOD-SLOT-DEFINITION" + "READER-METHOD-CLASS" + "REMOVE-DEPENDENT" + "REMOVE-DIRECT-METHOD" + "REMOVE-DIRECT-SUBCLASS" + "REMOVE-METHOD" + "SET-FUNCALLABLE-INSTANCE-FUNCTION" + "SLOT-BOUNDP-USING-CLASS" + "SLOT-DEFINITION" + "SLOT-DEFINITION-ALLOCATION" + "SLOT-DEFINITION-INITARGS" + "SLOT-DEFINITION-INITFORM" + "SLOT-DEFINITION-INITFUNCTION" + "SLOT-DEFINITION-LOCATION" + "SLOT-DEFINITION-NAME" + "SLOT-DEFINITION-READERS" + "SLOT-DEFINITION-WRITERS" + "SLOT-DEFINITION-TYPE" + "SLOT-MAKUNBOUND-USING-CLASS" + "SLOT-VALUE-USING-CLASS" + "SPECIALIZER" + "SPECIALIZER-DIRECT-GENERIC-FUNCTIONS" + "SPECIALIZER-DIRECT-METHODS" + "STANDARD-ACCESSOR-METHOD" + "STANDARD-CLASS" + "STANDARD-DIRECT-SLOT-DEFINITION" + "STANDARD-EFFECTIVE-SLOT-DEFINITION" + "STANDARD-GENERIC-FUNCTION" + "STANDARD-INSTANCE-ACCESS" + "STANDARD-METHOD" + "STANDARD-OBJECT" + "STANDARD-READER-METHOD" + "STANDARD-SLOT-DEFINITION" + "STANDARD-WRITER-METHOD" + "T" + "UPDATE-DEPENDENT" + "VALIDATE-SUPERCLASS" + "WRITER-METHOD-CLASS")) + +(defpackage* "SB-PCL" + (:documentation + "semi-public: This package includes useful meta-object protocol +extensions, but even they are not guaranteed to be present in later +versions of SBCL, and the other stuff in here is definitely not +guaranteed to be present in later versions of SBCL. Use of this +package is deprecated in favour of SB-MOP.") + (:use "CL" "SB-MOP" "SB-INT" "SB-EXT" "SB-WALKER" "SB-KERNEL") + ;; experimental SBCL-only (for now) symbols + (:export "SYSTEM-CLASS" + + "MAKE-METHOD-LAMBDA-USING-SPECIALIZERS" + "MAKE-METHOD-SPECIALIZERS-FORM" + + "SPECIALIZER-TYPE-SPECIFIER" + "MAKE-SPECIALIZER-FORM-USING-CLASS" + "PARSE-SPECIALIZER-USING-CLASS" + "UNPARSE-SPECIALIZER-USING-CLASS" + + "+SLOT-UNBOUND+" + + "ENSURE-CLASS-FINALIZED" + + "ILLEGAL-CLASS-NAME-ERROR" + "CLASS-NOT-FOUND-ERROR" + "SPECIALIZER-NAME-SYNTAX-ERROR")) + +(defpackage* "SB-BROTHERTREE" + (:use "CL" "SB-EXT" "SB-INT") + (:documentation "internal: 1-2-Brother tree") + (:shadow "DELETE") + (:export "INSERT" "DELETE")) + +(defpackage* "SB-LOCKLESS" + (:documentation "internal: lockfree lists") + (:use "CL" "SB-INT" "SB-EXT" "SB-SYS" "SB-KERNEL") + (:shadow "ENDP")) diff --git a/src/cold/muffler.lisp b/src/cold/muffler.lisp index efbbecb7d4..1eadd20bcd 100644 --- a/src/cold/muffler.lisp +++ b/src/cold/muffler.lisp @@ -26,7 +26,15 @@ (and (typep (car args) '(cons string)) (search "forced to do" (caar args))))))))) +#+sbcl +(defvar *optional-and-key-warning-condition* + (find-symbol "&OPTIONAL-AND-&KEY-IN-LAMBDA-LIST" "SB-KERNEL")) + (defun optional+key-style-warning-p (condition) + #+sbcl + (when *optional-and-key-warning-condition* + (return-from optional+key-style-warning-p + (typep condition *optional-and-key-warning-condition*))) (and (typep condition '(and simple-condition style-warning)) (let ((fc (simple-condition-format-control condition))) (and (stringp fc) diff --git a/src/cold/set-up-cold-packages.lisp b/src/cold/set-up-cold-packages.lisp index d776cd19c3..d69a013e8d 100644 --- a/src/cold/set-up-cold-packages.lisp +++ b/src/cold/set-up-cold-packages.lisp @@ -135,37 +135,25 @@ ;;; ;;; We make no attempt to be fully general; our table doesn't need to be ;;; able to express features which we don't happen to use. -(export '(genesis - package-data - make-package-data - package-data-name - package-data-export - package-data-reexport - package-data-import-from - package-data-use)) +(export '(genesis)) (defstruct package-data ;; a string designator for the package name (name (error "missing PACKAGE-DATA-NAME datum")) ;; a doc string - (doc (error "missing PACKAGE-DOC datum")) + (documentation (error "missing PACKAGE-DOCUMENATION datum")) + ;; a list of nicknames + nicknames ;; a list of string designators for shadowing symbols shadow - ;; a tree containing names for exported symbols which'll be set up at package - ;; creation time, and NILs, which are ignored. (This is a tree in order to - ;; allow constructs like '("ENOSPC" #+LINUX ("EDQUOT" "EISNAM" "ENAVAIL" - ;; "EREMOTEIO")) to be used in initialization. NIL entries in the tree are - ;; ignored for the same reason of notational convenience.) + ;; a list of string designators for exported symbols which'll be set + ;; up at package creation time. export - ;; a list of string designators for exported symbols which don't necessarily - ;; originate in this package (so their EXPORT operations should be handled - ;; after USE operations have been done, so that duplicates aren't created) - reexport ;; a list of sublists describing imports. Each sublist has the format as an ;; IMPORT-FROM list in DEFPACKAGE: the first element is the name of the ;; package to import from, and the remaining elements are the names of ;; symbols to import. import-from - ;; a tree of string designators for package names of other packages + ;; a list of string designators for package names of other packages ;; which this package uses use) @@ -201,7 +189,102 @@ ;; "BYTE" "BYTE-POSITION" "BYTE-SIZE" "DPB" "LDB" "LDB-TEST" - "DEPOSIT-FIELD" "MASK-FIELD")) + "DEPOSIT-FIELD" "MASK-FIELD" + ;; + ;; the constants (except for T and NIL which have + ;; a specially hacked correspondence between + ;; cross-compilation host Lisp and target Lisp) + + ;; We include these here since there is no reason to reference + ;; host constants. + "ARRAY-DIMENSION-LIMIT" + "ARRAY-RANK-LIMIT" + "ARRAY-TOTAL-SIZE-LIMIT" + "BOOLE-1" + "BOOLE-2" + "BOOLE-AND" + "BOOLE-ANDC1" + "BOOLE-ANDC2" + "BOOLE-C1" + "BOOLE-C2" + "BOOLE-CLR" + "BOOLE-EQV" + "BOOLE-IOR" + "BOOLE-NAND" + "BOOLE-NOR" + "BOOLE-ORC1" + "BOOLE-ORC2" + "BOOLE-SET" + "BOOLE-XOR" + "CALL-ARGUMENTS-LIMIT" + "CHAR-CODE-LIMIT" + "DOUBLE-FLOAT-EPSILON" + "DOUBLE-FLOAT-NEGATIVE-EPSILON" + "INTERNAL-TIME-UNITS-PER-SECOND" + "LAMBDA-LIST-KEYWORDS" + "LAMBDA-PARAMETERS-LIMIT" + "LEAST-NEGATIVE-DOUBLE-FLOAT" + "LEAST-NEGATIVE-LONG-FLOAT" + "LEAST-NEGATIVE-NORMALIZED-DOUBLE-FLOAT" + "LEAST-NEGATIVE-NORMALIZED-LONG-FLOAT" + "LEAST-NEGATIVE-NORMALIZED-SHORT-FLOAT" + "LEAST-NEGATIVE-NORMALIZED-SINGLE-FLOAT" + "LEAST-NEGATIVE-SHORT-FLOAT" + "LEAST-NEGATIVE-SINGLE-FLOAT" + "LEAST-POSITIVE-DOUBLE-FLOAT" + "LEAST-POSITIVE-LONG-FLOAT" + "LEAST-POSITIVE-NORMALIZED-DOUBLE-FLOAT" + "LEAST-POSITIVE-NORMALIZED-LONG-FLOAT" + "LEAST-POSITIVE-NORMALIZED-SHORT-FLOAT" + "LEAST-POSITIVE-NORMALIZED-SINGLE-FLOAT" + "LEAST-POSITIVE-SHORT-FLOAT" + "LEAST-POSITIVE-SINGLE-FLOAT" + "LONG-FLOAT-EPSILON" + "LONG-FLOAT-NEGATIVE-EPSILON" + "MOST-NEGATIVE-DOUBLE-FLOAT" + "MOST-NEGATIVE-FIXNUM" + "MOST-NEGATIVE-LONG-FLOAT" + "MOST-NEGATIVE-SHORT-FLOAT" + "MOST-NEGATIVE-SINGLE-FLOAT" + "MOST-POSITIVE-DOUBLE-FLOAT" + "MOST-POSITIVE-FIXNUM" + "MOST-POSITIVE-LONG-FLOAT" + "MOST-POSITIVE-SHORT-FLOAT" + "MOST-POSITIVE-SINGLE-FLOAT" + "MULTIPLE-VALUES-LIMIT" + "PI" + "SHORT-FLOAT-EPSILON" + "SHORT-FLOAT-NEGATIVE-EPSILON" + "SINGLE-FLOAT-EPSILON" + "SINGLE-FLOAT-NEGATIVE-EPSILON" + + ;; The cross-compiler itself shouldn't really need to use the host + ;; versions of these in target code except in exceptional cases. + "CHAR-CODE" + "CODE-CHAR" + "COMPILE-FILE" + "COMPILE-FILE-PATHNAME" + "*COMPILE-FILE-PATHNAME*" + "*COMPILE-FILE-TRUENAME*" + "*COMPILE-PRINT*" + "*COMPILE-VERBOSE*" + "COMPILER-MACRO-FUNCTION" + "CONSTANTP" + "GET-SETF-EXPANSION" + "GENSYM" + "*GENSYM-COUNTER*" + "LISP-IMPLEMENTATION-TYPE" "LISP-IMPLEMENTATION-VERSION" + "MACRO-FUNCTION" + "MACROEXPAND" "MACROEXPAND-1" "*MACROEXPAND-HOOK*" + "MAKE-LOAD-FORM" + "MAKE-LOAD-FORM-SAVING-SLOTS" + "PROCLAIM" + "SPECIAL-OPERATOR-P" + "SUBTYPEP" + "UPGRADED-ARRAY-ELEMENT-TYPE" + "UPGRADED-COMPLEX-PART-TYPE" + "WITH-COMPILATION-UNIT" + )) ;;; A symbol in the "dual personality" list refers to the symbol in CL unless ;;; package-prefixed with SB-XC:. The main reason for not putting these @@ -237,6 +320,7 @@ ;;; see by default, so that using them by accident fails. (defparameter *undefineds* '("SYMBOL-PACKAGE" + "PACKAGE-NAME" ;; Float decoding: don't want to see these used either. "DECODE-FLOAT" "INTEGER-DECODE-FLOAT" "FLOAT-DIGITS" "FLOAT-PRECISION" "FLOAT-RADIX" @@ -251,105 +335,16 @@ ;; compilation of the target. ;; (let ((package-name "SB-XC")) - (dolist (name (append (append *undefineds* *dual-personality-math-symbols*))) + (dolist (name (append *undefineds* *dual-personality-math-symbols*)) (export (intern name package-name) package-name)) - (dolist (name '(;; the constants (except for T and NIL which have - ;; a specially hacked correspondence between - ;; cross-compilation host Lisp and target Lisp) - "ARRAY-DIMENSION-LIMIT" - "ARRAY-RANK-LIMIT" - "ARRAY-TOTAL-SIZE-LIMIT" - "BOOLE-1" - "BOOLE-2" - "BOOLE-AND" - "BOOLE-ANDC1" - "BOOLE-ANDC2" - "BOOLE-C1" - "BOOLE-C2" - "BOOLE-CLR" - "BOOLE-EQV" - "BOOLE-IOR" - "BOOLE-NAND" - "BOOLE-NOR" - "BOOLE-ORC1" - "BOOLE-ORC2" - "BOOLE-SET" - "BOOLE-XOR" - "CALL-ARGUMENTS-LIMIT" - "CHAR-CODE-LIMIT" - "DOUBLE-FLOAT-EPSILON" - "DOUBLE-FLOAT-NEGATIVE-EPSILON" - "INTERNAL-TIME-UNITS-PER-SECOND" - "LAMBDA-LIST-KEYWORDS" - "LAMBDA-PARAMETERS-LIMIT" - "LEAST-NEGATIVE-DOUBLE-FLOAT" - "LEAST-NEGATIVE-LONG-FLOAT" - "LEAST-NEGATIVE-NORMALIZED-DOUBLE-FLOAT" - "LEAST-NEGATIVE-NORMALIZED-LONG-FLOAT" - "LEAST-NEGATIVE-NORMALIZED-SHORT-FLOAT" - "LEAST-NEGATIVE-NORMALIZED-SINGLE-FLOAT" - "LEAST-NEGATIVE-SHORT-FLOAT" - "LEAST-NEGATIVE-SINGLE-FLOAT" - "LEAST-POSITIVE-DOUBLE-FLOAT" - "LEAST-POSITIVE-LONG-FLOAT" - "LEAST-POSITIVE-NORMALIZED-DOUBLE-FLOAT" - "LEAST-POSITIVE-NORMALIZED-LONG-FLOAT" - "LEAST-POSITIVE-NORMALIZED-SHORT-FLOAT" - "LEAST-POSITIVE-NORMALIZED-SINGLE-FLOAT" - "LEAST-POSITIVE-SHORT-FLOAT" - "LEAST-POSITIVE-SINGLE-FLOAT" - "LONG-FLOAT-EPSILON" - "LONG-FLOAT-NEGATIVE-EPSILON" - "MOST-NEGATIVE-DOUBLE-FLOAT" - "MOST-NEGATIVE-FIXNUM" - "MOST-NEGATIVE-LONG-FLOAT" - "MOST-NEGATIVE-SHORT-FLOAT" - "MOST-NEGATIVE-SINGLE-FLOAT" - "MOST-POSITIVE-DOUBLE-FLOAT" - "MOST-POSITIVE-FIXNUM" - "MOST-POSITIVE-LONG-FLOAT" - "MOST-POSITIVE-SHORT-FLOAT" - "MOST-POSITIVE-SINGLE-FLOAT" - "MULTIPLE-VALUES-LIMIT" - "PI" - "SHORT-FLOAT-EPSILON" - "SHORT-FLOAT-NEGATIVE-EPSILON" - "SINGLE-FLOAT-EPSILON" - "SINGLE-FLOAT-NEGATIVE-EPSILON" - "*READ-DEFAULT-FLOAT-FORMAT*" - + (dolist (name '("*READ-DEFAULT-FLOAT-FORMAT*" "ARRAY-ELEMENT-TYPE" - "CHAR-CODE" - "CODE-CHAR" - "COMPILE-FILE" - "COMPILE-FILE-PATHNAME" - "*COMPILE-FILE-PATHNAME*" - "*COMPILE-FILE-TRUENAME*" - "*COMPILE-PRINT*" - "*COMPILE-VERBOSE*" - "COMPILER-MACRO-FUNCTION" - "CONSTANTP" - "DEFCONSTANT" - "DEFINE-MODIFY-MACRO" - "DEFINE-SETF-EXPANDER" - "DEFMACRO" "DEFSETF" "DEFSTRUCT" "DEFTYPE" - "GENSYM" "*GENSYM-COUNTER*" - "GET-SETF-EXPANSION" - "LISP-IMPLEMENTATION-TYPE" "LISP-IMPLEMENTATION-VERSION" - "MACRO-FUNCTION" - "MACROEXPAND" "MACROEXPAND-1" "*MACROEXPAND-HOOK*" + "DEFMACRO" "DEFSTRUCT" "DEFTYPE" "MAKE-ARRAY" - "MAKE-LOAD-FORM" - "MAKE-LOAD-FORM-SAVING-SLOTS" - "PROCLAIM" "SIMPLE-VECTOR" - "SPECIAL-OPERATOR-P" - "SUBTYPEP" - "TYPE-OF" "TYPEP" - "UPGRADED-ARRAY-ELEMENT-TYPE" - "UPGRADED-COMPLEX-PART-TYPE" - "WITH-COMPILATION-UNIT")) - (export (intern name package-name) package-name))) + "TYPEP" + )) + (export (intern name package-name) package-name))) (defun count-symbols (pkg) (let ((n 0)) @@ -359,7 +354,7 @@ ;;; Build a new package that exports a not-necessarily-strict subset of ;;; what the host CL exports. This deals with hosts that have too many -;;; symbols exported froM CL. +;;; symbols exported from CL. (let ((cl-model-package (make-package "XC-STRICT-CL" :use nil))) (flet ((new-external (x package &aux (s (intern x package))) (export s package) @@ -368,7 +363,7 @@ (import x cl-model-package) (export x cl-model-package))) (reexport (list nil)) - (dolist (string (read-from-file "common-lisp-exports.lisp-expr")) + (dolist (string (read-from-file "^common-lisp-exports.lisp-expr")) (unless (string= string "NIL") ; already done (cond ((member string *undefineds* :test #'string=) (new-external string cl-model-package)) @@ -391,94 +386,78 @@ (assert (equal *package-symbol-counts* (compute-cl-package-symbol-counts)))) (defun create-target-packages (package-data-list) - (labels ((flatten (tree) - (let ((result (mapcan (lambda (x) (if (listp x) (flatten x) (list x))) - tree))) - (when (< (length (remove-duplicates result :test 'equal)) - (length result)) - (error "Duplicates in package-data-list: ~a~%" - (mapcon (lambda (x) - (when (member (car x) (cdr x) :test 'equal) - (list (car x)))) - result))) - result))) + (hide-host-packages) + + ;; Build all packages that we need, and initialize them as far as we + ;; can without referring to any other packages. + (dolist (package-data package-data-list) + (let ((package (make-package (package-data-name package-data) + :use nil + :nicknames (package-data-nicknames package-data)))) + (dolist (string (package-data-shadow package-data)) + (shadow string package)) + (setf (documentation package t) (package-data-documentation package-data)))) + ;; Now that all packages exist, we can set up package-package + ;; references. + (dolist (package-data package-data-list) + (use-package (substitute "XC-STRICT-CL" "CL" + (package-data-use package-data) + :test 'string=) + (package-data-name package-data)) + ;; Note: Unlike plain-old DEFPACKAGE, this IMPORT-FROM does + ;; potentially intern NAME into the FROM-PACKAGE to make forward + ;; references work. + (dolist (sublist (package-data-import-from package-data)) + (let* ((from-package (first sublist)) + (from-package (if (string= from-package "CL") + "XC-STRICT-CL" + from-package))) + (import (mapcar (lambda (name) (intern name from-package)) + (rest sublist)) + (package-data-name package-data)))) + (dolist (string (package-data-export package-data)) + (export (intern string (package-data-name package-data)) + (package-data-name package-data)))) - (hide-host-packages) + (unhide-host-format-funs)) - ;; Build all packages that we need, and initialize them as far as we - ;; can without referring to any other packages. - (dolist (package-data package-data-list) - (let* ((name (package-data-name package-data)) - (package (make-package name :use nil))) - ;; Walk the tree of shadowing names - (dolist (string (flatten (package-data-shadow package-data))) - (shadow string package)) - ;; Walk the tree of exported names, exporting each name. - (dolist (string (flatten (package-data-export package-data))) - (export (intern string package) package)))) +(export '*undefined-fun-allowlist*) +(defvar *undefined-fun-allowlist* (make-hash-table :test 'equal)) - ;; Now that all packages exist, we can set up package-package - ;; references. - (dolist (package-data package-data-list) - (use-package (substitute "XC-STRICT-CL" "CL" - (package-data-use package-data) - :test 'string=) - (package-data-name package-data)) - (dolist (sublist (package-data-import-from package-data)) - (let ((from-package (first sublist))) - (import (mapcar (lambda (name) (intern name from-package)) - (rest sublist)) - (package-data-name package-data))))) +(defparameter *package-data-list* '()) - (unhide-host-format-funs) +;;; Like DEFPACKAGE, but does some special stuff to make forward +;;; references work. +(defmacro defpackage* (name &rest options) + (let ((flattened-options '())) + (dolist (option options) + (destructuring-bind (kind . args) option + (ecase kind + ((:use :export :shadow :nicknames) + (let ((existing-option (assoc kind flattened-options))) + (if existing-option + (setf (second (second existing-option)) + (append (second (second existing-option)) args)) + (push (list kind (list 'quote args)) flattened-options)))) + ((:import-from) + (let ((existing-option (assoc kind flattened-options))) + (if existing-option + (push args (second (second existing-option))) + (push (list kind (list 'quote (list args))) flattened-options)))) + ((:documentation) + (push option flattened-options))))) + `(push (make-package-data :name ',name ,@(mapcan #'identity flattened-options)) + *package-data-list*))) - ;; Now that all package-package references exist, we can handle - ;; REEXPORT operations. (We have to wait until now because they - ;; interact with USE operations.) This code handles dependencies - ;; properly, but is somewhat ugly. - (let (done) - (labels - ((reexport (package-data) - (let ((package (find-package (package-data-name package-data)))) - (cond - ((member package done)) - ((null (package-data-reexport package-data)) - (push package done)) - (t - (mapcar #'reexport - (remove-if-not - (lambda (x) - (member x (package-data-use package-data) - :test #'string=)) - package-data-list - :key #'package-data-name)) - (dolist (symbol-name - (flatten (package-data-reexport package-data))) - (multiple-value-bind (symbol status) - (find-symbol symbol-name package) - (unless status - (error "No symbol named ~S is accessible in ~S." - symbol-name package)) - (when (eq (symbol-package symbol) package) - (error - "~S is not inherited/imported, but native to ~S." - symbol-name package)) - (export symbol package))) - (push package done)))))) - (dolist (x package-data-list) - (reexport x)) - (assert (= (length done) (length package-data-list))))))) +(let ((*readtable* *xc-readtable*)) + (load (find-bootstrap-file "^exports.lisp")) + (create-target-packages *package-data-list*)) -(export '*undefined-fun-whitelist*) -(defvar *undefined-fun-whitelist* (make-hash-table :test 'equal)) -(let ((list - (with-open-file (data (prepend-genfile-path "package-data-list.lisp-expr")) - ;; There's no need to use the precautionary READ-FROM-FILE function - ;; with package-data-list because it is not a customization file. - (create-target-packages (let ((*readtable* *xc-readtable*)) (read data))) - (let ((*readtable* *xc-readtable*)) (read data))))) - (dolist (name (apply #'append list)) - (setf (gethash name *undefined-fun-whitelist*) t))) +(defun read-undefined-fun-allowlist () + (with-open-file (data (find-bootstrap-file "^undefined-fun-allowlist.lisp-expr")) + (let ((*readtable* *xc-readtable*)) + (dolist (name (apply #'append (read data))) + (setf (gethash name *undefined-fun-allowlist*) t))))) (defvar *asm-package-use-list* '("SB-ASSEM" "SB-DISASSEM" @@ -503,19 +482,11 @@ ;; so that they can co-exist. (make-assembler-package (backend-asm-package-name)) -(defun package-list-for-genesis () - (append (let ((*readtable* *xc-readtable*)) - (read-from-file "package-data-list.lisp-expr" nil)) - (let ((asm-package (backend-asm-package-name))) - (list (make-package-data :name asm-package - :use (list* "CL" *asm-package-use-list*) - :doc nil))))) - ;;; Not all things shown by this are actually unused. Some get removed ;;; by the tree-shaker as intended. #+nil (defun show-unused-exports (&aux nonexistent uninteresting) - (dolist (entry (with-open-file (f "package-data-list.lisp-expr") (read f))) + (dolist (entry *package-data-list*) (let ((pkg (find-package (package-data-name entry)))) (dolist (string (mapcan (lambda (x) (if (stringp x) (list x) x)) (package-data-export entry))) @@ -524,7 +495,7 @@ (cond ((not s) (push (cons pkg string) nonexistent)) ((and (not (boundp s)) - (not (sb-kernel:symbol-info s)) + (not (sb-kernel:symbol-%info s)) (not (gethash s sb-c::*backend-parsed-vops*))) (push s uninteresting)))))))) (format t "~&Nonexistent:~%") diff --git a/src/cold/shared.lisp b/src/cold/shared.lisp index ce0493d582..5f9827c3f9 100644 --- a/src/cold/shared.lisp +++ b/src/cold/shared.lisp @@ -21,6 +21,10 @@ ;;; and running the cross-compiler to produce target FASL files). (defpackage "SB-COLD" (:use "CL")) +#+nil ; change to #+sbcl if desired, but at your own risk! +(when (sb-sys:find-dynamic-foreign-symbol-address "show_gc_generation_throughput") + (setf (extern-alien "show_gc_generation_throughput" int) 1)) + (in-package "SB-COLD") (defun parse-make-host-parallelism (str) @@ -44,6 +48,7 @@ value2))))) (defvar *make-host-parallelism* nil) +(defvar *fail-on-warnings* t) (defun make-host-1-parallelism () (car *make-host-parallelism*)) (defun make-host-2-parallelism () (cdr *make-host-parallelism*)) @@ -163,24 +168,47 @@ (rename-file x path))) (compile 'rename-file-a-la-unix) -(export '(prepend-genfile-path read-from-file *generated-sources-root*)) +(export '(*target-sbcl-version* *generated-sources-root* + *build-dependent-generated-sources-root* + stem-source-path find-bootstrap-file read-from-file)) +(defvar *sources-root* "") (defvar *generated-sources-root* "") +(defvar *build-dependent-generated-sources-root* "") +(defvar *src-cold-shared-pathname* *load-pathname*) ;;; See remark in COMPILE-STEM about strings vs. The Common Lisp Way -(defun prepend-genfile-path (namestring) - (concatenate 'string - ;; if exact match to "output/", or mismatch at the next character - (if (member (mismatch "output/" namestring) '(nil 7)) - *generated-sources-root* - "") - namestring)) -(compile 'prepend-genfile-path) ; seems in vogue to compile everything in this file +(defun find-bootstrap-file (namestring &optional build-dependent) + (cond ((char= (char namestring 0) #\^) + ;; If it starts with a "^" then it means "src/cold/..." + (let ((this *src-cold-shared-pathname*) + (name (subseq namestring 1))) + (make-pathname :host (pathname-host this) + :device (pathname-device this) + :directory (pathname-directory this) + :name (pathname-name name) + :type (or (pathname-type name) (pathname-type this))))) + ((find #\/ namestring) + ;; Otherwise if it contains a slash, then it's a source file which is either + ;; in the tree as checked in, or generated by a prior build step. + (concatenate 'string + (if (eql (mismatch "output/" namestring) 7) ; a generated source + (if build-dependent + *build-dependent-generated-sources-root* + *generated-sources-root*) + *sources-root*) + namestring)) + (t + ;; Else, it's an optional user-supplied customization file, + ;; or a generated data file in the root directory such as "version.lisp-expr" + namestring))) +(compile 'find-bootstrap-file) ; seems in vogue to compile everything in this file ;;; Return an expression read from the file named NAMESTRING. ;;; For user-supplied inputs, protect against more than one expression -;;; appearing in the file. With trusted inputs we needn't bother. -(defun read-from-file (namestring &optional (enforce-single-expr t)) - (with-open-file (s (prepend-genfile-path namestring)) +;;; appearing in the file. (Our ^build-order.lisp-expr file has more than +;;; one expression in it, so we need to be able to not enforce.) +(defun read-from-file (namestring &key (enforce-single-expr t) build-dependent) + (with-open-file (s (find-bootstrap-file namestring build-dependent)) (let* ((result (read s)) (eof-result (cons nil nil))) (unless enforce-single-expr @@ -197,11 +225,11 @@ (unuse-package ext "CL-USER"))) #+cmu -(setq *compile-print* nil) ; too much noise, can't see the actual warnings +(setq cl:*compile-print* nil) ; too much noise, can't see the actual warnings #+sbcl (progn - (setq *compile-print* nil) - (load "src/cold/muffler.lisp") + (setq cl:*compile-print* nil) + (load (find-bootstrap-file "^muffler")) ;; Let's just say we never care to see these. (declaim (sb-ext:muffle-conditions (satisfies unable-to-optimize-note-p) @@ -211,7 +239,17 @@ ;;;; special read-macros for building the cold system (and even for ;;;; building some of our tools for building the cold system) -(load "src/cold/shebang.lisp") +(load (find-bootstrap-file "^shebang")) + +;;; Subfeatures could be assigned as late as the beginning of make-host-2, +;;; but I don't want to introduce another mechanism for delaying reading +;;; of the customizer just because we can. +;;; But it's not well-advertised; does it really merit a customization file? +(export 'backend-subfeatures) +(defvar backend-subfeatures + (let ((customizer-file-name "customize-backend-subfeatures.lisp")) + (when (probe-file customizer-file-name) + (copy-list (funcall (compile nil (read-from-file customizer-file-name)) nil))))) ;;; When cross-compiling, the *FEATURES* set for the target Lisp is ;;; not in general the same as the *FEATURES* set for the host Lisp. @@ -227,40 +265,59 @@ ;;; The compromise is to examine a variable specifying a path ;;; (and it can't go in SB-COLD because the package is not made soon enough) (setf sb-xc:*features* - (let* ((pathname (let ((var 'cl-user::*sbcl-target-features-file*)) + (let* ((pathname (let ((var 'cl-user::*sbcl-local-target-features-file*)) (if (boundp var) (symbol-value var) "local-target-features.lisp-expr"))) (default-features (funcall (compile nil (read-from-file pathname)) - (read-from-file "base-target-features.lisp-expr"))) + (read-from-file "^base-target-features.lisp-expr"))) (customizer-file-name "customize-target-features.lisp") (customizer (if (probe-file customizer-file-name) (compile nil (read-from-file customizer-file-name)) #'identity)) - (target-feature-list (funcall customizer default-features)) + ;; Bind temporarily so that TARGET-FEATUREP and TARGET-PLATFORM-KEYWORD + ;; can see the tentative list. + (sb-xc:*features* (funcall customizer default-features)) (gc (find-if (lambda (x) (member x '(:cheneygc :gencgc))) - target-feature-list)) - (arch (target-platform-keyword target-feature-list))) + sb-xc:*features*)) + (arch (target-platform-keyword))) + ;; Win32 conditionally adds :sb-futex in grovel-features.sh + (when (target-featurep '(:and :sb-thread (:or :linux :freebsd))) + (pushnew :sb-futex sb-xc:*features*)) + (when (target-featurep :immobile-space) + (pushnew :compact-instance-header sb-xc:*features*) + (pushnew :immobile-code sb-xc:*features*)) + (when (target-featurep :64-bit) + (push :compact-symbol sb-xc:*features*)) + (when (target-featurep '(:and :sb-thread (:or :darwin :openbsd))) + (push :os-thread-stack sb-xc:*features*)) + (when (target-featurep '(:and :x86 :int4-breakpoints)) + ;; 0xCE is a perfectly good 32-bit instruction, + ;; unlike on x86-64 where it is illegal. It's therefore + ;; confusing to allow this feature in a 32-bit build. + ;; But it's annoying to have a build script that otherwise works + ;; for a native x86/x86-64 build except for needing one change. + ;; Just print something and go on with life. + (setq sb-xc:*features* (remove :int4-breakpoints sb-xc:*features*)) + (warn "Removed :INT4-BREAKPOINTS from target features")) + (when (or (target-featurep :arm64) + (and (target-featurep :x86-64) + (member :sse4 backend-subfeatures))) + (push :round-float sb-xc:*features*)) + (when (target-featurep '(:and :arm64 :darwin)) + (push :arm-v8.1 backend-subfeatures)) + ;; Putting arch and gc choice first is visually convenient, versus ;; having to parse a random place in the line to figure out the value ;; of a binary choice {cheney vs gencgc} and architecture. ;; De-duplicate the rest of the symbols because the command line ;; can add redundant --with-mumble options. (list* arch gc (sort (remove-duplicates - (remove arch (remove gc target-feature-list))) + (remove arch (remove gc sb-xc:*features*))) #'string<)))) -(defvar *shebang-backend-subfeatures* - (let* ((default-subfeatures nil) - (customizer-file-name "customize-backend-subfeatures.lisp") - (customizer (if (probe-file customizer-file-name) - (compile nil - (read-from-file customizer-file-name)) - #'identity))) - (funcall customizer default-subfeatures))) - ;;; Call for effect of signaling an error if no target picked. (target-platform-keyword) @@ -276,26 +333,23 @@ (let ((feature-compatibility-tests '(("(and sb-thread (not gencgc))" ":SB-THREAD requires :GENCGC") + ("(and sb-safepoint (not sb-thread))" ":SB-SAFEPOINT requires :SB-THREAD") ("(and sb-thread (not (or riscv ppc ppc64 x86 x86-64 arm64)))" ":SB-THREAD not supported on selected architecture") + ("(and (not sb-thread) (or arm64 ppc64))" + "The selected architecture requires :SB-THREAD") ("(and gencgc cheneygc)" ":GENCGC and :CHENEYGC are incompatible") - ("(and cheneygc (not (or alpha arm arm64 hppa mips ppc riscv sparc)))" - ":CHENEYGC not supported on selected architecture") - ("(and gencgc (not (or sparc ppc ppc64 x86 x86-64 arm arm64 riscv)))" - ":GENCGC not supported on selected architecture") ("(not (or gencgc cheneygc))" "One of :GENCGC or :CHENEYGC must be enabled") - ("(and sb-safepoint (not (or arm64 ppc x86 x86-64)))" - ":SB-SAFEPOINT not supported on selected architecture") - ("(and sb-safepoint-strictly (not sb-safepoint))" - ":SB-SAFEPOINT-STRICTLY requires :SB-SAFEPOINT") + ("(and sb-safepoint (not (and (or arm64 x86 x86-64) (or darwin linux win32))))" + ":SB-SAFEPOINT not supported on selected arch/OS") ("(not (or elf mach-o win32))" "No execute object file format feature defined") ("(and cons-profiling (not sb-thread))" ":CONS-PROFILING requires :SB-THREAD") - ("(and sb-linkable-runtime (not (or x86 x86-64)))" + ("(and sb-linkable-runtime (not (or arm arm64 x86 x86-64 ppc ppc64)))" ":SB-LINKABLE-RUNTIME not supported on selected architecture") - ("(and sb-linkable-runtime (not (or darwin linux win32)))" + ("(and sb-linkable-runtime (not (or darwin freebsd linux win32)))" ":SB-LINKABLE-RUNTIME not supported on selected operating system") ("(and sb-eval sb-fasteval)" ;; It sorta kinda works to have both, but there should be no need, @@ -309,14 +363,14 @@ ":IMMOBILE-CODE requires :IMMOBILE-SPACE feature") ("(and immobile-symbols (not immobile-space))" ":IMMOBILE-SYMBOLS requires :IMMOBILE-SPACE feature") - ("(and int4-breakpoints x86)" - ;; 0xCE is a perfectly good 32-bit instruction, - ;; unlike on x86-64 where it is illegal. It's therefore - ;; confusing to allow this feature in a 32-bit build. - ":INT4-BREAKPOINTS are incompatible with x86") + ("(and sb-futex (not sb-thread))" + "Can't enable SB-FUTEX on platforms lacking thread support") ;; There is still hope to make multithreading on DragonFly x86-64 ("(and sb-thread x86 dragonfly)" - ":SB-THREAD not supported on selected architecture"))) + ":SB-THREAD not supported on selected architecture") + ;; We need SOME way to fill the linkage table... + ("(and (not os-provides-dlopen) (not sb-prelink-linkage-table))" + "Can't disable both os-provides-dlopen and sb-prelink-linkage-table"))) (failed-test-descriptions nil)) (dolist (test feature-compatibility-tests) (let ((*readtable* *xc-readtable*)) @@ -324,7 +378,7 @@ (push (second test) failed-test-descriptions)))) (when failed-test-descriptions (error "Feature compatibility check failed, ~S" - failed-test-descriptions))) + (reverse failed-test-descriptions)))) ;;;; cold-init-related PACKAGE and SYMBOL tools @@ -336,7 +390,7 @@ ;;; All code depending on this is itself dependent on #+SB-SHOW. (defvar *cl-snapshot*) (when (member :sb-show sb-xc:*features*) - (load "src/cold/snapshot.lisp") + (load (find-bootstrap-file "^snapshot")) (setq *cl-snapshot* (take-snapshot "COMMON-LISP"))) ;;;; master list of source files and their properties @@ -372,14 +426,6 @@ ;; :NOT-HOST is also set, since the SBCL assembler doesn't exist ;; while the cross-compiler is being built in the host ANSI Lisp.) :assem - ;; meaning: The #'COMPILE-STEM argument called :IGNORE-FAILURE-P - ;; should be true. (This is a KLUDGE: I'd like to get rid of it. - ;; For now, it exists so that compilation can proceed through the - ;; legacy warnings in src/compiler/x86/array.lisp, which I've - ;; never figured out but which were apparently acceptable in CMU - ;; CL. Eventually, it would be great to just get rid of all - ;; warnings and remove support for this flag. -- WHN 19990323) - :ignore-failure-p ;; meaning: ignore this flag. ;; This works around nonstandard behavior of "#." in certain hosts. ;; When the evaluated form yields 0 values, ECL and CLISP treat it @@ -396,21 +442,15 @@ ;; just to avoid that ugly mess. nil)) -;;; The specialized array registry has file-wide scope. Hacking that aspect -;;; into the xc build scaffold seemed slightly easier than hacking the -;;; compiler (i.e. making the registry a slot of the fasl-output struct) -(defvar *array-to-specialization* (make-hash-table :test #'eq)) - (defmacro do-stems-and-flags ((stem flags build-phase) &body body) (let ((stem-and-flags (gensym "STEM-AND-FLAGS"))) `(dolist (,stem-and-flags (get-stems-and-flags ,build-phase)) (let ((,stem (first ,stem-and-flags)) (,flags (rest ,stem-and-flags))) - ,@body - (clrhash *array-to-specialization*))))) + ,@body)))) -;;; Given a STEM, remap the path component "/target/" to a suitable -;;; target directory. +;;; Given a STEM, remap the path components "/{arch}/" and "/asm-target/" +;;; to suitable directories. (defun stem-remap-target (stem) (flet ((try-replacing (this that) (let ((position (search this stem))) @@ -419,20 +459,20 @@ (subseq stem 0 (1+ position)) (string-downcase that) (subseq stem (+ position (length this) -1))))))) - (or (try-replacing "/target/" (target-platform-keyword)) + (or (try-replacing "/{arch}/" (target-platform-keyword)) (try-replacing "/asm-target/" (backend-assembler-target-name)) stem))) (compile 'stem-remap-target) ;;; Determine the source path for a stem by remapping from the abstract name -;;; if it contains "/target/" and appending a ".lisp" suffix. +;;; if it contains "/{arch}/" and appending a ".lisp" suffix. ;;; Assume that STEM is source-tree-relative unless it starts with "output/" ;;; in which case it could be elsewhere, if you prefer to keep the sources ;;; devoid of compilation artifacts. (The production of out-of-tree artifacts ;;; is not actually implemented in the generic build, however if your build ;;; system does that by itself, then hooray for you) (defun stem-source-path (stem) - (concatenate 'string (prepend-genfile-path (stem-remap-target stem)) ".lisp")) + (concatenate 'string (find-bootstrap-file (stem-remap-target stem)) ".lisp")) (compile 'stem-source-path) ;;; Determine the object path for a stem/flags/mode combination. @@ -450,8 +490,7 @@ (pathname-type (compile-file-pathname stem))))) (:target-compile (values *target-obj-prefix* - (cond ((find :extra-artifact flags) "") - ((find :assem flags) *target-assem-obj-suffix*) + (cond ((find :assem flags) *target-assem-obj-suffix*) (t *target-obj-suffix*))))) (concatenate 'string obj-prefix (stem-remap-target stem) obj-suffix))) (compile 'stem-object-path) @@ -472,7 +511,7 @@ ;; to produce warnings as a bug workaround. (let ((cl:*features* (cons feature cl:*features*)) (*readtable* *xc-readtable*)) - (read-from-file "build-order.lisp-expr" nil)))) + (read-from-file "^build-order.lisp-expr" :enforce-single-expr nil)))) (setf *stems-and-flags* (cons build-phase list))) ;; Now check for duplicate stems and bogus flags. (let ((stems (make-hash-table :test 'equal))) @@ -511,34 +550,46 @@ ;;; STEM and FLAGS are as per DO-STEMS-AND-FLAGS. MODE is one of ;;; :HOST-COMPILE and :TARGET-COMPILE. (defun compile-stem (stem flags mode) - - (let* (;; KLUDGE: Note that this CONCATENATE 'STRING stuff is not The Common - ;; Lisp Way, although it works just fine for common UNIX environments. - ;; Should it come to pass that the system is ported to environments - ;; where version numbers and so forth become an issue, it might become - ;; urgent to rewrite this using the fancy Common Lisp PATHNAME - ;; machinery instead of just using strings. In the absence of such a - ;; port, it might or might be a good idea to do the rewrite. - ;; -- WHN 19990815 - (src (stem-source-path stem)) + (let* ((src (stem-source-path stem)) (obj (stem-object-path stem flags mode)) ;; Compile-for-effect happens simultaneously with a forked compile, ;; so we need the for-effect output not to stomp on the real output. (tmp-obj - (concatenate 'string obj - (if *compile-for-effect-only* "-scratch" "-tmp"))) - + (concatenate 'string obj + (if *compile-for-effect-only* "-scratch" "-tmp"))) (compile-file (ecase mode - (:host-compile #'compile-file) + (:host-compile + #+abcl ; ABCL complains about its own deficiency and then returns T + ;; for warnings and failure. "Unable to compile function" is not our problem, + ;; but I tried everything to muffle it, and nothing worked; so if it occurs, + ;; treat the file as a success despite any actual problems that may exist. + (lambda (&rest args) + (let (compiler-bug) + ;; Even though COMPILER-UNSUPPORTED-FEATURE-ERROR is a condition class, + ;; HANDLER-BIND seems unable to match it. What the hell? Bugs all the way down. + (handler-bind ((condition + (lambda (c) + (when (search "Using interpreted form" (princ-to-string c)) + (setq compiler-bug t))))) + (multiple-value-bind (fasl warn err) (apply #'compile-file args) + (if compiler-bug (values fasl nil nil) (values fasl warn err)))))) + #+ccl ; CCL doesn't like NOTINLINE on unknown functions + (lambda (&rest args) + (handler-bind ((ccl:compiler-warning + (lambda (c) + (when (eq (ccl::compiler-warning-warning-type c) + :unknown-declaration-function) + (muffle-warning c))))) + (apply #'compile-file args))) + #-(or abcl ccl) #'compile-file) (:target-compile (if (find :assem flags) *target-assemble-file* *target-compile-file*)))) (trace-file (if (find :trace-file flags) t nil)) - (block-compile (if (find :block-compile flags) t :specified)) - (ignore-failure-p (find :ignore-failure-p flags))) + (block-compile (if (find :block-compile flags) t :specified))) (declare (type function compile-file)) - (ensure-directories-exist obj :verbose *compile-print*) ; host's value + (ensure-directories-exist obj :verbose cl:*compile-print*) ; host's value ;; We're about to set about building a new object file. First, we ;; delete any preexisting object file in order to avoid confusing @@ -586,24 +637,27 @@ retry-compile-file (multiple-value-bind (output-truename warnings-p failure-p) (restart-case - (funcall compile-file src :output-file tmp-obj - ;; if tracing, also show high-level progress - :trace-file trace-file - :print trace-file - :block-compile (and ;; Block compilation was - ;; completely broken - ;; from the beginning of - ;; SBCL history until - ;; version 2.0.2. - #+sbcl - (or (eq mode :target-compile) - (and (find-symbol "SPLIT-VERSION-STRING" "SB-C") - (funcall (find-symbol "VERSION>=" "SB-C") - (funcall (find-symbol "SPLIT-VERSION-STRING" "SB-C") - (lisp-implementation-version)) - '(2 0 2)))) - block-compile) - :allow-other-keys t) + (apply compile-file src + :output-file tmp-obj + :block-compile (and + ;; Block compilation was + ;; completely broken from the + ;; beginning of SBCL history + ;; until version 2.0.2. + #+sbcl + (or (eq mode :target-compile) + (and (find-symbol "SPLIT-VERSION-STRING" "HOST-SB-C") + (funcall (find-symbol "VERSION>=" "HOST-SB-C") + (funcall (find-symbol "SPLIT-VERSION-STRING" "HOST-SB-C") + (lisp-implementation-version)) + '(2 0 2)))) + block-compile) + :allow-other-keys t + ;; If tracing, also print, but don't specify :PRINT unless specifying + ;; :TRACE-FILE so that whatever the default is for *COMPILE-PRINT* + ;; prevails, insensitively to whether it's the SB-XC: or CL: symbol. + (when trace-file + '(:trace-file t :print t))) (recompile () :report report-recompile-restart (go retry-compile-file))) @@ -611,23 +665,20 @@ (cond ((not output-truename) (error "couldn't compile ~S" src)) (failure-p - (if ignore-failure-p - (warn "ignoring FAILURE-P return value from compilation of ~S" - src) - (unwind-protect - (restart-case - (error "FAILURE-P was set when creating ~S." - obj) - (recompile () - :report report-recompile-restart - (go retry-compile-file)) - (continue () - :report report-continue-restart - (setf failure-p nil))) - ;; Don't leave failed object files lying around. - (when (and failure-p (probe-file tmp-obj)) - (delete-file tmp-obj) - (format t "~&deleted ~S~%" tmp-obj))))) + (unwind-protect + (restart-case + (error "FAILURE-P was set when creating ~S." + obj) + (recompile () + :report report-recompile-restart + (go retry-compile-file)) + (continue () + :report report-continue-restart + (setf failure-p nil))) + ;; Don't leave failed object files lying around. + (when (and failure-p (probe-file tmp-obj)) + (delete-file tmp-obj) + (format t "~&deleted ~S~%" tmp-obj)))) ;; Otherwise: success, just fall through. (t nil))))) @@ -636,7 +687,7 @@ (cond ((not *compile-for-effect-only*) (rename-file-a-la-unix tmp-obj obj)) ((probe-file tmp-obj) - (delete-file tmp-obj))) ; clean up the trash + (delete-file tmp-obj))) ; clean up the trash ;; nice friendly traditional return value (pathname obj))) @@ -645,6 +696,7 @@ (defparameter *host-quirks* (or #+cmu '(:host-quirks-cmu) #+ecl '(:host-quirks-ecl) + #+ccl '(:host-quirks-ccl) #+sbcl '(:host-quirks-sbcl))) ; not so much a "quirk", but consistent anyway ;;; Execute function FN in an environment appropriate for compiling the @@ -712,6 +764,8 @@ ;;;; Floating-point number reader interceptor (defvar *choke-on-host-irrationals* t) +;;; FIXME: this gets stuck on forms which contain literal CTYPE objects +;;; because of infinite recursion. (defun install-read-interceptor () ;; Intercept READ to catch inadvertent use of host floating-point literals. ;; This prevents regressions in the portable float logic and allows passing @@ -749,7 +803,7 @@ ((and structure-object (not package)) (let ((type-name (string (type-of x)))) ;; This "LAYOUT" refers to *our* object, not host-sb-kernel:layout. - (unless (member type-name '("LAYOUT" "FLOAT" "COMPLEXNUM") + (unless (member type-name '("WRAPPER" "LAYOUT" "FLOAT" "COMPLEXNUM") :test #'string=) ;(Format t "visit a ~/host-sb-ext:print-symbol-with-prefix/~%" (type-of x)) ;; This generalizes over any structure. I need it because we diff --git a/src/cold/shebang.lisp b/src/cold/shebang.lisp index bf379ed73c..4edafcbf8a 100644 --- a/src/cold/shebang.lisp +++ b/src/cold/shebang.lisp @@ -24,16 +24,25 @@ (declaim (type list sb-xc:*features*)) (defvar sb-xc:*features*) -(defun target-platform-keyword (&optional (features sb-xc:*features*)) - (let ((arch (intersection '(:alpha :arm :arm64 :hppa :mips :ppc :ppc64 :riscv :sparc :x86 :x86-64) +(defun target-platform-keyword (&aux (features sb-xc:*features*)) + (let ((arch (intersection '(:arm :arm64 :mips :ppc :ppc64 :riscv :sparc :x86 :x86-64) features))) (cond ((not arch) (error "No architecture selected")) ((> (length arch) 1) (error "More than one architecture selected"))) (car arch))) +(defun compatible-vector-raw-bits () ; T if the host and target match on word size and endianness + (flet ((endianness (features) + (let ((result (intersection '(:little-endian :big-endian) features))) + (assert (and result (not (cdr result)))) + (car result))) + (wordsize (features) + (if (member :64-bit features) 64 32))) + (and (eq (endianness sb-xc:*features*) (endianness cl:*features*)) + (= (wordsize sb-xc:*features*) (wordsize cl:*features*))))) + ;;; Not necessarily the logical place to define BACKEND-ASM-PACKAGE-NAME, -;;; but a convenient one, because sb-xc:*features* needs to have been -;;; DEFVARed, and because 'chill' loads this and only this file. +;;; but a convenient one. (defun backend-assembler-target-name () (let ((keyword (target-platform-keyword))) (case keyword @@ -42,80 +51,19 @@ (defun backend-asm-package-name () (concatenate 'string "SB-" (string (backend-assembler-target-name)) "-ASM")) -(defun any-vop-named-p (vop-name) - (let ((ht (symbol-value (find-symbol "*BACKEND-PARSED-VOPS*" "SB-C")))) - (not (null (gethash vop-name ht))))) - -(defun any-vop-translates-p (fun-name) - (let ((f (intern "INFO" "SB-INT"))) - (when (fboundp f) - (let ((info (funcall f :function :info fun-name))) - (if info - (let ((f (intern "FUN-INFO-TEMPLATES" "SB-C"))) - (and (fboundp f) (not (null (funcall f info)))))))))) - -(defvar *feature-eval-results-file* "output/feature-tests.lisp-expr") -(defvar *feature-evaluation-results*) - -(defun recording-feature-eval (expression value) - ;; This safety check does not work for parallel build, but that produces - ;; different code anyway due to missing derived types in any file that would - ;; have been compiled in the serial order but was interpreted instead. - (when (boundp '*feature-evaluation-results*) - ; (format t "~&FEATURE EXPR: ~S -> ~S~%" expression value) - (push (cons expression value) *feature-evaluation-results*)) - value) - -(defun write-feature-eval-results () - (with-open-file (f *feature-eval-results-file* - :direction :output - :if-exists :supersede :if-does-not-exist :create) - (let ((*print-readably* t)) - (format f "(~{~S~^~% ~})~%" *feature-evaluation-results*)))) - -(defun sanity-check-feature-evaluation () - (flet ((check (phase list) - (dolist (x list) - (let ((answer - (ecase (caar x) - (:vop-named (any-vop-named-p (cadar x))) - (:vop-translates (any-vop-translates-p (cadar x)))))) - (unless (eq answer (cdr x)) - (error "make-host-~D DEFINE-VOP ordering bug:~@ - ~S should be ~S, was ~S at xc time" phase x answer (cdr x))))))) - (check 1 (with-open-file (f *feature-eval-results-file*) (read f))) - (check 2 *feature-evaluation-results*))) - -;;; We should never call this with a selector of :HOST any more, -;;; but I'm keeping it in case of emergency. -(defun feature-in-list-p (feature selector - &aux (list (ecase selector - (:host cl:*features*) - (:target sb-xc:*features*)))) +;;; Like the real FEATUREP but using SB-XC:*FEATURES* instead of CL:*FEATURES* +(defun target-featurep (feature) (etypecase feature (symbol - (if (and (string= feature "SBCL") (eq selector :target)) + (if (string= feature "SBCL") (error "Testing SBCL as a target feature is obviously bogus") - (member feature list :test #'eq))) - (cons (flet ((subfeature-in-list-p (subfeature) - (feature-in-list-p subfeature selector))) - (ecase (first feature) - (:or (some #'subfeature-in-list-p (rest feature))) - (:and (every #'subfeature-in-list-p (rest feature))) - (:not (destructuring-bind (subexpr) (cdr feature) - (not (subfeature-in-list-p subexpr)))) - ((:vop-named :vop-translates) - (when (eq selector :host) - (error "Invalid host feature test: ~S" feature)) - (destructuring-bind (subexpr) (cdr feature) - (case (first feature) - (:vop-named - (recording-feature-eval feature - (any-vop-named-p subexpr))) - (:vop-translates - (recording-feature-eval - feature (any-vop-translates-p subexpr))))))))))) -(compile 'feature-in-list-p) + (member feature sb-xc:*features* :test #'eq))) + (cons (ecase (first feature) + (:or (some #'target-featurep (rest feature))) + (:and (every #'target-featurep (rest feature))) + (:not (destructuring-bind (subexpr) (cdr feature) + (not (target-featurep subexpr)))))))) +(compile 'target-featurep) (defun read-targ-feature-expr (stream sub-character infix-parameter) (when infix-parameter @@ -123,7 +71,7 @@ (if (char= (if (let* ((*package* (find-package "KEYWORD")) (*read-suppress* nil) (feature (read stream t nil t))) - (feature-in-list-p feature :target)) + (target-featurep feature)) #\+ #\-) sub-character) (read stream t nil t) @@ -144,19 +92,6 @@ t ; non-terminating so that symbols may contain a dollar sign *xc-readtable*) -;;;; variables like SB-XC:*FEATURES* but different - -;;; This variable is declared here (like SB-XC:*FEATURES*) so that -;;; things like chill.lisp work (because the variable has properties -;;; similar to SB-XC:*FEATURES*, and chill.lisp was set up to work -;;; for that). For an explanation of what it really does, look -;;; elsewhere. -;;; FIXME: Can we just assign SB-C:*BACKEND-SUBFEATURES* directly? -;;; (This has nothing whatsoever to do with the so-called "shebang" reader) -(export '*shebang-backend-subfeatures*) -(declaim (type list *shebang-backend-subfeatures*)) -(defvar *shebang-backend-subfeatures*) - ;;;; string checker, for catching non-portability early ;;; A note about CLISP compatibility: diff --git a/src/cold/slam.lisp b/src/cold/slam.lisp index 344f48e7fc..c954d915f9 100644 --- a/src/cold/slam.lisp +++ b/src/cold/slam.lisp @@ -46,7 +46,7 @@ ;;; :trace-file as a flag. (setf *stems-and-flags* (let ((*readtable* *xc-readtable*)) - (read-from-file "build-order.lisp-expr" nil))) + (read-from-file "^build-order.lisp-expr" :enforce-single-expr nil))) ;;; Don't care about deftransforms that get redefined. ;;; The target condition is defined in 'condition' which is a :not-host file. @@ -76,7 +76,7 @@ (target-compile-stem stem flags))))) (when (and (eq (car sb-thread::*thread-local-specials*) :not-final) - (not (equal (cdr sb-thread::*thread-local-specials*) + (not (equal (cdr sb-thread::*thread-local-specials*) *original-thread-local-specials*))) (sb-int:style-warn "Detected modified thread-local-specials. Slam may not have recompiled everything as required.")) diff --git a/src/cold/snapshot.lisp b/src/cold/snapshot.lisp index 1670f377ee..53e942ffcf 100644 --- a/src/cold/snapshot.lisp +++ b/src/cold/snapshot.lisp @@ -108,6 +108,7 @@ / // /// + ++ +++ - + *break-on-signals* *gensym-counter* ;; These are bound when compiling and/or loading: *package* diff --git a/src/cold/undefined-fun-allowlist.lisp-expr b/src/cold/undefined-fun-allowlist.lisp-expr new file mode 100644 index 0000000000..77eb827430 --- /dev/null +++ b/src/cold/undefined-fun-allowlist.lisp-expr @@ -0,0 +1,186 @@ +;;;; -*- Lisp -*- + +;;;; This software is part of the SBCL system. See the README file for +;;;; more information. +;;;; +;;;; This software is derived from the CMU CL system, which was +;;;; written at Carnegie Mellon University and released into the +;;;; public domain. The software is in the public domain and is +;;;; provided with absolutely no warranty. See the COPYING and CREDITS +;;;; files for more information. + +;;; The following symbols may be referenced without seeing a definition +;;; during make-host-2. No warning will result. +;;; This list is read after target packages are created. +((;; CL, EXT, KERNEL + allocate-instance + compute-applicable-methods + slot-makunbound + make-load-form-saving-slots + sb-vm:map-allocated-objects + sb-ext:primitive-object-size + sb-vm::remove-static-links) + ;; CLOS implementation + (sb-mop:class-finalized-p + sb-mop:class-prototype + sb-mop:class-slots + sb-pcl::eql-specializer-to-ctype + sb-pcl::try-finalize-inheritance + sb-mop:finalize-inheritance + sb-mop:generic-function-name + sb-pcl::%obsolete-instance-trap + sb-mop:ensure-class + sb-pcl::instance-structure-protocol-error + make-instance + sb-pcl::make-arg-info + sb-pcl::make-structure-class-defstruct-form + (setf sb-mop:generic-function-name) + sb-mop:slot-definition-allocation + sb-mop:slot-definition-name + sb-pcl::slot-accessor-std-p + slot-unbound + sb-pcl::specializer-applicable-using-type-p + sb-pcl::specializer-class-or-nil + sb-pcl::method-p + sb-mop:method-function + sb-pcl::%force-cache-flushes + sb-pcl::check-wrapper-validity + sb-pcl::class-has-a-forward-referenced-superclass-p + sb-pcl::class-wrapper + sb-pcl::compute-gf-ftype + sb-pcl::definition-source + sb-pcl::ensure-accessor + sb-pcl:ensure-class-finalized) + ;; CLOS-based packages + (sb-gray:stream-clear-input + sb-gray:stream-clear-output + sb-gray:stream-file-position + sb-gray:stream-finish-output + sb-gray:stream-force-output + sb-gray:stream-fresh-line + sb-gray:stream-line-column + sb-gray:stream-line-length + sb-gray:stream-listen + sb-gray:stream-peek-char + sb-gray:stream-read-byte + sb-gray:stream-read-char + sb-gray:stream-read-char-no-hang + sb-gray:stream-read-line + sb-gray:stream-read-sequence + sb-gray:stream-terpri + sb-gray:stream-unread-char + sb-gray:stream-write-byte + sb-gray:stream-write-char + sb-gray:stream-write-sequence + sb-gray:stream-write-string + sb-sequence:concatenate + sb-sequence:copy-seq + sb-sequence:count + sb-sequence:count-if + sb-sequence:count-if-not + sb-sequence:delete + sb-sequence:delete-duplicates + sb-sequence:delete-if + sb-sequence:delete-if-not + (setf sb-sequence:elt) + sb-sequence:elt + sb-sequence:emptyp + sb-sequence:fill + sb-sequence:find + sb-sequence:find-if + sb-sequence:find-if-not + (setf sb-sequence:iterator-element) + sb-sequence:iterator-endp + sb-sequence:iterator-step + sb-sequence:length + sb-sequence:make-sequence-iterator + sb-sequence:make-sequence-like + sb-sequence:map + sb-sequence:merge + sb-sequence:mismatch + sb-sequence:nreverse + sb-sequence:nsubstitute + sb-sequence:nsubstitute-if + sb-sequence:nsubstitute-if-not + sb-sequence:position + sb-sequence:position-if + sb-sequence:position-if-not + sb-sequence:reduce + sb-sequence:remove + sb-sequence:remove-duplicates + sb-sequence:remove-if + sb-sequence:remove-if-not + sb-sequence:replace + sb-sequence:reverse + sb-sequence:search + sb-sequence:sort + sb-sequence:stable-sort + sb-sequence:subseq + sb-sequence:substitute + sb-sequence:substitute-if + sb-sequence:substitute-if-not) + #+sb-eval + (sb-eval:eval-in-environment + sb-eval:eval-in-native-environment) + ;; Fast interpreter + #+sb-fasteval + (sb-interpreter:%fun-ftype + sb-interpreter:env-policy + sb-interpreter:eval-in-environment + sb-interpreter:find-lexical-fun + sb-interpreter:find-lexical-var + sb-interpreter::flush-everything + sb-interpreter::fun-lexically-notinline-p + sb-interpreter:lexenv-from-env + sb-interpreter::lexically-unlocked-symbol-p + sb-interpreter:list-locals + sb-interpreter::reconstruct-syntactic-closure-env) + ;; Simple-streams symbols in SB-IMPL + (sb-impl::s-%charpos + sb-impl::s-%clear-output + sb-impl::s-%file-length + sb-impl::s-%file-name + sb-impl::s-%file-position + sb-impl::s-%file-string-length + sb-impl::s-%finish-output + sb-impl::s-%force-output + sb-impl::s-%fresh-line + sb-impl::s-%line-length + sb-impl::s-%peek-char + sb-impl::s-%read-byte + sb-impl::s-%read-char + sb-impl::s-%read-char-no-hang + sb-impl::s-%read-line + sb-impl::s-%stream-external-format + sb-impl::s-%terpri + sb-impl::s-%unread-char + sb-impl::s-%write-byte + sb-impl::s-%write-char + sb-impl::s-%write-line + sb-impl::s-%write-sequence + sb-impl::s-%write-string) + ;; Other + (sb-debug::find-interrupted-name-and-frame + sb-impl::encapsulate-generic-function + sb-impl::encapsulated-generic-function-p + sb-impl::get-processes-status-changes + sb-impl::step-form + sb-impl::step-values + sb-impl::unencapsulate-generic-function) + ;; The following functions are in fact defined during make-host-2 + ;; but they are non-toplevel so they appear to be undefined. + (sb-int:gensymify* + sb-int:keywordicate + sb-int:package-symbolicate + sb-int:symbolicate + sb-kernel::preinform-compiler-about-accessors + sb-kernel::preinform-compiler-about-slot-functions + sb-impl::bytes-per-utf8-character-aref + sb-impl::bytes-per-utf8-character-sap-ref-8 + sb-impl::user-homedir-namestring + sb-c::apply-core-fixups + sb-c::compiled-debug-info-char-offset + sb-c::compiled-debug-info-tlf-number + sb-c::pack-xref-data + sb-c::prepare-for-compile + sb-sys:reinit-internal-real-time)) diff --git a/src/cold/warm.lisp b/src/cold/warm.lisp index ee6c64f908..d54b7ebd1a 100644 --- a/src/cold/warm.lisp +++ b/src/cold/warm.lisp @@ -13,6 +13,18 @@ ;;;; general warm init compilation policy +;;; First things first, bootstrap the WARNING handler. +sb-kernel:: +(setq **initial-handler-clusters** + `(((,(find-classoid-cell 'warning) . + ,(named-lambda "MAYBE-MUFFLE" (warning) + (when (muffle-warning-p warning) + (muffle-warning warning)))) + (,(find-classoid-cell 'step-condition) . sb-impl::invoke-stepper)))) +;;;; And now a trick: splice those into the oldest *HANDLER-CLUSTERS* +;;;; which had a placeholder NIL reserved for this purpose. +sb-kernel::(rplaca (last *handler-clusters*) (car **initial-handler-clusters**)) + ;;;; Use the same settings as PROCLAIM-TARGET-OPTIMIZATION ;;;; I could not think of a trivial way to ensure that this stays functionally ;;;; identical to the corresponding code in 'compile-cold-sbcl'. @@ -33,8 +45,10 @@ ;; whatever it is that show would have shown. Comment this out if you need. (when s (set s nil)))) -(assert (zerop (deref (extern-alien "lowtag_for_widetag" (array char 64)) - (ash sb-vm:character-widetag -2)))) +(let ((byte (deref (extern-alien "widetag_lowtag" (array char 256)) + sb-vm:character-widetag))) + (assert (not (logbitp 7 byte))) ; not a headered object + (assert (= (logand byte sb-vm:lowtag-mask) sb-vm:list-pointer-lowtag))) (gc :full t) ;;; Verify that all defstructs except for one were compiled in a null lexical @@ -66,7 +80,17 @@ ;; in case there is more than one set of floating-point formats. (assert (eq (read stream) :default)) (sb-kernel::with-float-traps-masked (:overflow :divide-by-zero) - (let ((*package* (find-package "SB-KERNEL"))) + (let ((*readtable* (copy-readtable)) + (*package* (find-package "SB-KERNEL"))) + (set-dispatch-macro-character + #\# #\. (lambda (stream subchar arg) + (declare (igore subchar arg)) + (let ((expr (read stream t nil t))) + (ecase (car expr) + (sb-kernel:make-single-float + (sb-kernel:make-single-float (second expr))) + (sb-kernel:make-double-float + (sb-kernel:make-double-float (second expr) (third expr))))))) (dolist (expr (read stream)) (destructuring-bind (fun args . result) expr (let ((result (if (eq (first result) 'sb-kernel::&values) @@ -113,8 +137,8 @@ ;;; ((:or :macro (:match "$EARLY-") (:match "$BOOT-")) ;;; (declare (optimize (speed 0)))))) ;;; -(let ((sources (with-open-file (f (merge-pathnames "../../build-order.lisp-expr" - *load-pathname*)) +(defvar *sbclroot* "") +(let ((sources (with-open-file (f (merge-pathnames "build-order.lisp-expr" *load-pathname*)) (read f) ; skip over the make-host-{1,2} input files (read f))) (sb-c::*handled-conditions* sb-c::*handled-conditions*)) @@ -129,7 +153,8 @@ ;; a literal (when compiling in the LOAD step) t)) (output - (compile-file-pathname stem + (compile-file-pathname + (concatenate 'string *sbclroot* stem) :output-file (merge-pathnames (concatenate @@ -143,9 +168,22 @@ retry-compile-file (multiple-value-bind (output-truename warnings-p failure-p) (ecase (if (boundp '*compile-files-p*) *compile-files-p* t) - ((t) (let ((sb-c::*source-namestring* fullname)) - (ensure-directories-exist output) - (compile-file stem :output-file output))) + ((t) + (let ((sb-c::*source-namestring* fullname) + (sb-ext:*derive-function-types* + (if (search "/pcl/" stem) + :same-file + t))) + (ensure-directories-exist output) + ;; Like PROCLAIM-TARGET-OPTIMIZATION in 'compile-cold-sbcl' + ;; We should probably stash a copy of the POLICY instance from + ;; make-host-2 in a global var and apply it here. + (proclaim '(optimize + (safety 2) (speed 2) + (sb-c:insert-step-conditions 0) + (sb-c:alien-funcall-saves-fp-and-pc #+x86 3 #-x86 0))) + (compile-file (concatenate 'string *sbclroot* stem) + :output-file output))) ((nil) output)) (cond ((not output-truename) (error "COMPILE-FILE of ~S failed." stem)) @@ -174,13 +212,20 @@ ((sb-kernel:redefinition-with-defgeneric #'muffle-warning)) (let ((sb-c::*source-namestring* fullname)) - (load output-truename))) + ;; RISCV is slow, I'd like to see it doing something + ;; rather than appearing to go out to lunch + (load output-truename :verbose (or #+riscv t)))) (error "LOAD of ~S failed." output-truename)) (sb-int:/show "done loading" output-truename)))))))) - (let ((*compile-print* nil)) + (let ((cl:*compile-print* nil)) (dolist (group sources) - (handler-bind ((#+x86-64 warning #-x86-64 simple-warning + ;; For the love of god, what are we trying to do here??? + ;; It's gone through so many machinations that I can't figure it out. + ;; The goal should be to build warning-free, not layer one + ;; kludge upon another so that it can be allowed not to. + (handler-bind (((and #+x86-64 warning #-x86-64 simple-warning + (not sb-kernel:redefinition-warning)) (lambda (c) ;; escalate "undefined variable" warnings to errors. ;; There's no reason to allow them in our code. @@ -188,14 +233,26 @@ (search "undefined variable" (write-to-string c :escape nil))) (cerror "Finish warm compile ignoring the problem" c))))) - (with-compilation-unit () (do-srcs group))))))) + (with-compilation-unit () + (do-srcs group))))))) +(sb-c::dump/restore-interesting-types 'write) (when (hash-table-p sb-c::*static-vop-usage-counts*) (with-open-file (output "output/warm-vop-usage.txt" :direction :output :if-exists :supersede) (let (list) (sb-int:dohash ((name vop) sb-c::*backend-parsed-vops*) (declare (ignore vop)) - (push (cons (gethash name sb-c::*static-vop-usage-counts* 0) name) list)) + (unless (char= (char (string name) 0) #\!) + (push (cons (gethash name sb-c::*static-vop-usage-counts* 0) name) list))) (dolist (cell (sort list #'> :key #'car)) (format output "~7d ~s~%" (car cell) (cdr cell)))))) + +(when (sb-sys:find-dynamic-foreign-symbol-address "tot_gc_nsec") + (let* ((run-sec (/ (get-internal-real-time) internal-time-units-per-second)) + (gc-nsec (extern-alien "tot_gc_nsec" unsigned)) + (gc-msec (/ (float gc-nsec) 1000000))) + (format t "~&Done with warm.lisp. INTERNAL-REAL-TIME=~Fs~@[, GC=~Fms (~,1,2f%)~]~%" + run-sec + (if (plusp gc-msec) gc-msec) ; timing wasn't enabled if this is 0 + (/ gc-msec (* 1000 run-sec))))) diff --git a/src/compiler/aliencomp.lisp b/src/compiler/aliencomp.lisp index 0be88a50b9..2c4de45129 100644 --- a/src/compiler/aliencomp.lisp +++ b/src/compiler/aliencomp.lisp @@ -66,7 +66,7 @@ (defknown (setf %alien-value) (t system-area-pointer unsigned-byte alien-type) t ()) -(defknown alien-funcall (alien-value &rest *) * +(defknown alien-funcall (alien-value &rest t) * (any recursive)) (defknown sb-alien::string-to-c-string (simple-string t) (or (simple-array (unsigned-byte 8) (*)) @@ -236,7 +236,6 @@ #+nil ;; Shouldn't be necessary. (defoptimizer (deref derive-type) ((alien &rest noise)) - (declare (ignore noise)) (block nil (catch 'give-up-ir1-transform (return (make-alien-type-type (find-deref-element-type alien)))) @@ -252,7 +251,6 @@ #+nil ;; ### Again, the value might be coerced. (defoptimizer (%set-deref derive-type) ((alien value &rest noise)) - (declare (ignore noise)) (block nil (catch 'give-up-ir1-transform (let ((type (make-alien-type-type @@ -272,7 +270,6 @@ value)))) (defoptimizer (%deref-addr derive-type) ((alien &rest noise)) - (declare (ignore noise)) (block nil (catch 'give-up-ir1-transform (return (make-alien-type-type @@ -321,7 +318,7 @@ (return type)))) *wild-type*)) -(deftransform %set-heap-alien ((info value) (heap-alien-info *) *) +(deftransform %set-heap-alien ((info value) (heap-alien-info t) *) (multiple-value-bind (sap type) (heap-alien-sap-and-type info) `(setf (%alien-value ,sap 0 ',type) value))) @@ -414,7 +411,6 @@ '(error "This should be eliminated as dead code.")))) (defoptimizer (%local-alien-addr derive-type) ((info var)) - (declare (ignore var)) (if (constant-lvar-p info) (let* ((info (lvar-value info)) (alien-type (local-alien-info-type info))) @@ -433,7 +429,6 @@ ;;;; %CAST (defoptimizer (%cast derive-type) ((alien type)) - (declare (ignore alien)) (or (when (constant-lvar-p type) (let ((alien-type (lvar-value type))) (when (alien-type-p alien-type) @@ -466,7 +461,6 @@ (give-up-ir1-transform))))) (defoptimizer (%sap-alien derive-type) ((sap type)) - (declare (ignore sap)) (if (constant-lvar-p type) (make-alien-type-type (lvar-value type)) *wild-type*)) @@ -503,7 +497,7 @@ ;;;; ALIEN-FUNCALL support (deftransform alien-funcall ((function &rest args) - ((alien (* t)) &rest *) *) + ((alien (* t)) &rest t) *) (let ((names (make-gensym-list (length args)))) (/noshow "entering first DEFTRANSFORM ALIEN-FUNCALL" function args) `(lambda (function ,@names) @@ -594,19 +588,16 @@ ,body))))))) (defoptimizer (%alien-funcall derive-type) ((function type &rest args)) - (declare (ignore function args)) (unless (and (constant-lvar-p type) (alien-fun-type-p (lvar-value type))) (error "Something is broken.")) - (let ((type (lvar-value type))) - (values-specifier-type - (compute-alien-rep-type - (alien-fun-type-result-type type) - :result)))) + (let ((spec (compute-alien-rep-type + (alien-fun-type-result-type (lvar-value type)) + :result))) + (if (eq spec '*) *wild-type* (values-specifier-type spec)))) (defoptimizer (%alien-funcall ltn-annotate) - ((function type &rest args) node ltn-policy) - (declare (ignore type ltn-policy)) + ((function type &rest args) node) (setf (basic-combination-info node) :funny) (setf (node-tail-p node) nil) (unless (and (constant-lvar-p function) @@ -651,66 +642,75 @@ ;; KLUDGE: This is where the second half of the ARM ;; register-pressure change lives (see above). (dolist (tn #-arm arg-tns #+arm (reverse arg-tns)) - ;; On PPC, TN might be a list. This is used to indicate - ;; something special needs to happen. See below. - ;; - ;; FIXME: We should implement something better than this. - (let* ((first-tn (if (listp tn) (car tn) tn)) - (arg (pop args)) - (sc (tn-sc first-tn)) - (scn (sc-number sc)) - (move-arg-vops (svref (sc-move-arg-vops sc) scn))) - (aver arg) - (unless (= (length move-arg-vops) 1) - (error "no unique move-arg-vop for moves in SC ~S" (sc-name sc))) - #+(or x86 x86-64) (emit-move-arg-template call - block - (first move-arg-vops) - (lvar-tn call block arg) - nsp - first-tn) - #-(or x86 x86-64) - (cond - #+arm-softfp - ((and (proper-list-of-length-p tn 3) - (symbolp (third tn))) - (emit-template call block - (template-or-lose (third tn)) - (reference-tn (lvar-tn call block arg) nil) - (reference-tn-list (butlast tn) t))) - (t - (let ((temp-tn (make-representation-tn - (tn-primitive-type first-tn) scn))) - (emit-move call - block - (lvar-tn call block arg) - temp-tn) - (emit-move-arg-template call - block - (first move-arg-vops) - temp-tn - nsp - first-tn)))) - #+(and ppc darwin) - (when (listp tn) - ;; This means that we have a float arg that we need to - ;; also copy to some int regs. The list contains the TN - ;; for the float as well as the TNs to use for the int - ;; arg. - (destructuring-bind (float-tn i1-tn &optional i2-tn) - tn - (if i2-tn - (vop sb-vm::move-double-to-int-arg call block - float-tn i1-tn i2-tn) - (vop sb-vm::move-single-to-int-arg call block - float-tn i1-tn)))))) + (if (functionp tn) + (funcall tn (pop args) call block nsp) + ;; On PPC, TN might be a list. This is used to indicate + ;; something special needs to happen. See below. + ;; + ;; FIXME: We should implement something better than this. + (let* ((first-tn (if (listp tn) (car tn) tn)) + (arg (pop args)) + (sc (tn-sc first-tn)) + (scn (sc-number sc)) + (move-arg-vops (svref (sc-move-arg-vops sc) scn))) + (aver arg) + (unless (= (length move-arg-vops) 1) + (error "no unique move-arg-vop for moves in SC ~S" (sc-name sc))) + + (cond + #+arm-softfp + ((and (listp tn) + (symbolp (car (last tn)))) + (emit-template call block + (template-or-lose (car (last tn))) + (reference-tn (lvar-tn call block arg) nil) + (reference-tn-list (butlast tn) t))) + (t + (when (eq (sb-kind (sc-sb sc)) :unbounded) ;; stacks are unbounded + ;; Avoid allocating this TN on the caller's stack + (setf (tn-kind first-tn) :arg-pass)) + #+(or x86 x86-64) + (emit-move-arg-template call + block + (first move-arg-vops) + (lvar-tn call block arg) + nsp + first-tn) + #-(or x86 x86-64) + (let* ((primitive-type (tn-primitive-type first-tn)) + ;; If the destination is a stack TN make sure + ;; the temporary TN is a register. + (scn (if (sc-number-stack-p sc) + (car (primitive-type-scs primitive-type)) + scn)) + (temp-tn (make-representation-tn primitive-type scn))) + (emit-move call block (lvar-tn call block arg) temp-tn) + (emit-move-arg-template call + block + (first move-arg-vops) + temp-tn + nsp + first-tn)))) + #+(and ppc darwin) + (when (listp tn) + ;; This means that we have a float arg that we need to + ;; also copy to some int regs. The list contains the TN + ;; for the float as well as the TNs to use for the int + ;; arg. + (destructuring-bind (float-tn i1-tn &optional i2-tn) + tn + (if i2-tn + (vop sb-vm::move-double-to-int-arg call block + float-tn i1-tn i2-tn) + (vop sb-vm::move-single-to-int-arg call block + float-tn i1-tn))))))) (aver (null args)) (let* ((result-tns (ensure-list result-tns)) (arg-operands (reference-tn-list (remove-if-not #'tn-p (flatten-list arg-tns)) nil)) (result-operands (reference-tn-list (remove-if-not #'tn-p result-tns) t))) - (cond #+(vop-named sb-vm::call-out-named) + (cond #+#.(cl:if (sb-c::vop-existsp :named sb-vm::call-out-named) '(and) '(or)) ((and (constant-lvar-p function) (stringp (lvar-value function))) (vop* call-out-named call block (arg-operands) (result-operands) (lvar-value function) @@ -728,12 +728,12 @@ (cond #+arm-softfp ((and lvar - (fourth result-tns)) + (symbolp (car (last result-tns)))) (emit-template call block - (template-or-lose (fourth result-tns)) + (template-or-lose (car (last result-tns))) (reference-tn-list (butlast result-tns 2) nil) - (reference-tn (third result-tns) t)) - (move-lvar-result call block (list (third result-tns)) lvar)) + (reference-tn (car (last result-tns 2)) t)) + (move-lvar-result call block (list (car (last result-tns 2))) lvar)) (t (move-lvar-result call block result-tns lvar))))))) diff --git a/src/compiler/alpha/alloc.lisp b/src/compiler/alpha/alloc.lisp deleted file mode 100644 index 408b475592..0000000000 --- a/src/compiler/alpha/alloc.lisp +++ /dev/null @@ -1,182 +0,0 @@ -;;;; allocation VOPs for the Alpha port - -;;;; This software is part of the SBCL system. See the README file for -;;;; more information. -;;;; -;;;; This software is derived from the CMU CL system, which was -;;;; written at Carnegie Mellon University and released into the -;;;; public domain. The software is in the public domain and is -;;;; provided with absolutely no warranty. See the COPYING and CREDITS -;;;; files for more information. - -(in-package "SB-VM") - -;;;; LIST and LIST* -(define-vop (list-or-list*) - (:args (things :more t)) - (:temporary (:scs (descriptor-reg)) ptr) - (:temporary (:scs (descriptor-reg)) temp) - (:temporary (:scs (descriptor-reg) :to (:result 0) :target result) - res) - (:info num) - (:results (result :scs (descriptor-reg))) - (:variant-vars star) - (:policy :safe) - (:node-var node) - (:generator 0 - (cond ((zerop num) - (move null-tn result)) - ((and star (= num 1)) - (move (tn-ref-tn things) result)) - (t - (macrolet - ((store-car (tn list &optional (slot cons-car-slot)) - `(let ((reg - (sc-case ,tn - ((any-reg descriptor-reg) ,tn) - (zero zero-tn) - (null null-tn) - (control-stack - (load-stack-tn temp ,tn) - temp)))) - (storew reg ,list ,slot list-pointer-lowtag)))) - (let* ((dx-p (node-stack-allocate-p node)) - (cons-cells (if star (1- num) num)) - (space (* (pad-data-block cons-size) cons-cells))) - (pseudo-atomic (:extra (if dx-p 0 space)) - (cond (dx-p - (align-csp res) - (inst bis csp-tn list-pointer-lowtag res) - (inst lda csp-tn space csp-tn)) - (t - (inst bis alloc-tn list-pointer-lowtag res))) - (move res ptr) - (dotimes (i (1- cons-cells)) - (store-car (tn-ref-tn things) ptr) - (setf things (tn-ref-across things)) - (inst lda ptr (pad-data-block cons-size) ptr) - (storew ptr ptr - (- cons-cdr-slot cons-size) - list-pointer-lowtag)) - (store-car (tn-ref-tn things) ptr) - (cond (star - (setf things (tn-ref-across things)) - (store-car (tn-ref-tn things) ptr cons-cdr-slot)) - (t - (storew null-tn ptr - cons-cdr-slot list-pointer-lowtag))) - (aver (null (tn-ref-across things))) - (move res result)))))))) - -(define-vop (list list-or-list*) - (:variant nil)) - -(define-vop (list* list-or-list*) - (:variant t)) - -;;;; special purpose inline allocators - -(define-vop (make-fdefn) - (:policy :fast-safe) - (:translate make-fdefn) - (:args (name :scs (descriptor-reg) :to :eval)) - (:temporary (:scs (non-descriptor-reg)) temp) - (:results (result :scs (descriptor-reg) :from :argument)) - (:generator 37 - (with-fixed-allocation (result temp fdefn-widetag fdefn-size) - (storew name result fdefn-name-slot other-pointer-lowtag) - (storew null-tn result fdefn-fun-slot other-pointer-lowtag) - (inst li (make-fixup 'undefined-tramp :assembly-routine) temp) - (storew temp result fdefn-raw-addr-slot other-pointer-lowtag)))) - -(define-vop (make-closure) - (:args (function :to :save :scs (descriptor-reg))) - (:info label length stack-allocate-p) - (:ignore label) - (:temporary (:scs (non-descriptor-reg)) temp) - (:results (result :scs (descriptor-reg))) - (:generator 10 - (let* ((size (+ length closure-info-offset)) - (alloc-size (pad-data-block size))) - (inst li - (logior (ash (1- size) n-widetag-bits) closure-widetag) - temp) - (pseudo-atomic (:extra (if stack-allocate-p 0 alloc-size)) - (cond (stack-allocate-p - (align-csp result) - (inst bis csp-tn fun-pointer-lowtag result) - (inst lda csp-tn alloc-size csp-tn)) - (t - (inst bis alloc-tn fun-pointer-lowtag result))) - (storew temp result 0 fun-pointer-lowtag) - (storew function result closure-fun-slot fun-pointer-lowtag))))) - -;;; The compiler likes to be able to directly make value cells. -(define-vop (make-value-cell) - (:args (value :to :save :scs (descriptor-reg any-reg null zero))) - (:temporary (:scs (non-descriptor-reg)) temp) - (:info stack-allocate-p) - (:ignore stack-allocate-p) - (:results (result :scs (descriptor-reg))) - (:generator 10 - (with-fixed-allocation - (result temp value-cell-widetag value-cell-size) - (storew value result value-cell-value-slot other-pointer-lowtag)))) - -;;;; automatic allocators for primitive objects - -(define-vop (make-unbound-marker) - (:args) - (:results (result :scs (descriptor-reg any-reg))) - (:generator 1 - (inst li unbound-marker-widetag result))) - -(define-vop (make-funcallable-instance-tramp) - (:args) - (:results (result :scs (any-reg))) - (:generator 1 - (inst li (make-fixup 'funcallable-instance-tramp :assembly-routine) result))) - -(define-vop (fixed-alloc) - (:args) - (:info name words type lowtag stack-allocate-p) - (:ignore name) - (:results (result :scs (descriptor-reg))) - (:temporary (:scs (non-descriptor-reg)) temp) - (:generator 4 - (pseudo-atomic (:extra (if stack-allocate-p - 0 - (pad-data-block words))) - (cond (stack-allocate-p - (align-csp result) - (inst bis csp-tn lowtag result) - (inst addq csp-tn (pad-data-block words) csp-tn)) - (t - (inst bis alloc-tn lowtag result))) - (when type - (inst li (logior (ash (1- words) (length-field-shift type)) type) temp) - (storew temp result 0 lowtag))))) - -(define-vop (var-alloc) - (:args (extra :scs (any-reg))) - (:arg-types positive-fixnum) - (:info name words type lowtag stack-allocate-p) - (:ignore name stack-allocate-p) - (:results (result :scs (descriptor-reg))) - (:temporary (:scs (non-descriptor-reg)) header) - (:temporary (:scs (non-descriptor-reg)) bytes) - (:generator 6 - (inst lda bytes (* (1+ words) n-word-bytes) extra) - (inst sll bytes (- (length-field-shift type) 2) header) - ;; The specified EXTRA value is the exact value placed in the header - ;; as the word count when allocating code. - (cond ((= type code-header-widetag) - (inst lda header type header)) - (t - (inst lda header (+ (ash -2 (length-field-shift type)) type) header) - (inst srl bytes n-lowtag-bits bytes) - (inst sll bytes n-lowtag-bits bytes))) - (pseudo-atomic () - (inst bis alloc-tn lowtag result) - (storew header result 0 lowtag) - (inst addq alloc-tn bytes alloc-tn)))) diff --git a/src/compiler/alpha/arith.lisp b/src/compiler/alpha/arith.lisp deleted file mode 100644 index 31adf157fb..0000000000 --- a/src/compiler/alpha/arith.lisp +++ /dev/null @@ -1,823 +0,0 @@ -;;;; the VM definition arithmetic VOPs for the Alpha - -;;;; This software is part of the SBCL system. See the README file for -;;;; more information. -;;;; -;;;; This software is derived from the CMU CL system, which was -;;;; written at Carnegie Mellon University and released into the -;;;; public domain. The software is in the public domain and is -;;;; provided with absolutely no warranty. See the COPYING and CREDITS -;;;; files for more information. - -(in-package "SB-VM") - -;;;; unary operations - -(define-vop (fixnum-unop) - (:args (x :scs (any-reg))) - (:results (res :scs (any-reg))) - (:note "inline fixnum arithmetic") - (:arg-types tagged-num) - (:result-types tagged-num) - (:policy :fast-safe)) - -(define-vop (signed-unop) - (:args (x :scs (signed-reg))) - (:results (res :scs (signed-reg))) - (:note "inline (signed-byte 64) arithmetic") - (:arg-types signed-num) - (:result-types signed-num) - (:policy :fast-safe)) - -(define-vop (fast-negate/fixnum fixnum-unop) - (:translate %negate) - (:generator 1 - (inst subq zero-tn x res))) - -(define-vop (fast-negate/signed signed-unop) - (:translate %negate) - (:generator 2 - (inst subq zero-tn x res))) - -(define-vop (fast-lognot/fixnum fixnum-unop) - (:translate lognot) - (:generator 1 - (inst eqv x fixnum-tag-mask res))) - -(define-vop (fast-lognot/signed signed-unop) - (:translate lognot) - (:generator 2 - (inst not x res))) - -;;;; binary fixnum operations - -;;; Assume that any constant operand is the second arg... - -(define-vop (fast-fixnum-binop) - (:args (x :target r :scs (any-reg)) - (y :target r :scs (any-reg))) - (:arg-types tagged-num tagged-num) - (:results (r :scs (any-reg))) - (:result-types tagged-num) - (:note "inline fixnum arithmetic") - (:policy :fast-safe)) - -(define-vop (fast-unsigned-binop) - (:args (x :target r :scs (unsigned-reg)) - (y :target r :scs (unsigned-reg))) - (:arg-types unsigned-num unsigned-num) - (:results (r :scs (unsigned-reg))) - (:result-types unsigned-num) - (:note "inline (unsigned-byte 64) arithmetic") - (:policy :fast-safe)) - -(define-vop (fast-signed-binop) - (:args (x :target r :scs (signed-reg)) - (y :target r :scs (signed-reg))) - (:arg-types signed-num signed-num) - (:results (r :scs (signed-reg))) - (:result-types signed-num) - (:note "inline (signed-byte 64) arithmetic") - (:policy :fast-safe)) - -(define-vop (fast-fixnum-c-binop fast-fixnum-binop) - (:args (x :target r :scs (any-reg))) - (:info y) - (:arg-types tagged-num (:constant integer))) - -(define-vop (fast-signed-c-binop fast-signed-binop) - (:args (x :target r :scs (signed-reg))) - (:info y) - (:arg-types signed-num (:constant integer))) - -(define-vop (fast-unsigned-c-binop fast-unsigned-binop) - (:args (x :target r :scs (unsigned-reg))) - (:info y) - (:arg-types unsigned-num (:constant integer))) - -(defmacro define-binop (translate cost untagged-cost op - tagged-type untagged-type - &optional arg-swap restore-fixnum-mask) - `(progn - (define-vop (,(symbolicate "FAST-" translate "/FIXNUM=>FIXNUM") - fast-fixnum-binop) - ,@(when restore-fixnum-mask - `((:temporary (:sc non-descriptor-reg) temp))) - (:args (x ,@(unless restore-fixnum-mask `(:target r)) :scs (any-reg)) - (y ,@(unless restore-fixnum-mask `(:target r)) :scs (any-reg))) - (:translate ,translate) - (:generator ,(1+ cost) - ,(if arg-swap - `(inst ,op y x ,(if restore-fixnum-mask 'temp 'r)) - `(inst ,op x y ,(if restore-fixnum-mask 'temp 'r))) - ,@(when restore-fixnum-mask - `((inst bic temp #.(ash lowtag-mask -1) r))))) - (define-vop (,(symbolicate "FAST-" translate "/SIGNED=>SIGNED") - fast-signed-binop) - (:args (x :target r :scs (signed-reg)) - (y :target r :scs (signed-reg))) - (:translate ,translate) - (:generator ,(1+ untagged-cost) - ,(if arg-swap - `(inst ,op y x r) - `(inst ,op x y r)))) - (define-vop (,(symbolicate "FAST-" translate "/UNSIGNED=>UNSIGNED") - fast-unsigned-binop) - (:args (x :target r :scs (unsigned-reg)) - (y :target r :scs (unsigned-reg))) - (:translate ,translate) - (:generator ,(1+ untagged-cost) - ,(if arg-swap - `(inst ,op y x r) - `(inst ,op x y r)))) - ,@(when (and tagged-type (not arg-swap)) - `((define-vop (,(symbolicate "FAST-" translate "-C/FIXNUM=>FIXNUM") - fast-fixnum-c-binop) - (:args (x ,@(unless restore-fixnum-mask `(:target r)) - :scs (any-reg))) - (:arg-types tagged-num (:constant ,tagged-type)) - ,@(when restore-fixnum-mask - `((:temporary (:sc non-descriptor-reg) temp))) - (:translate ,translate) - (:generator ,cost - (inst ,op x (fixnumize y) ,(if restore-fixnum-mask 'temp 'r)) - ,@(when restore-fixnum-mask - `((inst bic temp #.(ash lowtag-mask -1) r))))))) - ,@(when (and untagged-type (not arg-swap)) - `((define-vop (,(symbolicate "FAST-" translate "-C/SIGNED=>SIGNED") - fast-signed-c-binop) - (:arg-types signed-num (:constant ,untagged-type)) - (:translate ,translate) - (:generator ,untagged-cost - (inst ,op x y r))) - (define-vop (,(symbolicate "FAST-" translate - "-C/UNSIGNED=>UNSIGNED") - fast-unsigned-c-binop) - (:arg-types unsigned-num (:constant ,untagged-type)) - (:translate ,translate) - (:generator ,untagged-cost - (inst ,op x y r))))))) - -(define-binop + 1 5 addq (unsigned-byte 6) (unsigned-byte 8)) -(define-binop - 1 5 subq (unsigned-byte 6) (unsigned-byte 8)) -(define-binop logand 1 3 and (unsigned-byte 6) (unsigned-byte 8)) -(define-binop logandc1 1 3 bic (unsigned-byte 6) (unsigned-byte 8) t) -(define-binop logandc2 1 3 bic (unsigned-byte 6) (unsigned-byte 8)) -(define-binop logior 1 3 bis (unsigned-byte 6) (unsigned-byte 8)) -(define-binop logorc1 1 3 ornot (unsigned-byte 6) (unsigned-byte 8) t t) -(define-binop logorc2 1 3 ornot (unsigned-byte 6) (unsigned-byte 8) nil t) -(define-binop logxor 1 3 xor (unsigned-byte 6) (unsigned-byte 8)) -(define-binop logeqv 1 3 eqv (unsigned-byte 6) (unsigned-byte 8) nil t) - -;;; special cases for LOGAND where we can use a mask operation -(define-vop (fast-logand-c-mask/unsigned=>unsigned fast-unsigned-c-binop) - (:translate logand) - (:arg-types unsigned-num - (:constant (or (integer #xffffffff #xffffffff) - (integer #xffffffff00000000 #xffffffff00000000)))) - (:generator 1 - (ecase y - (#xffffffff (inst mskll x 4 r)) - (#xffffffff00000000 (inst mskll x 0 r))))) - -;;;; shifting - -(define-vop (fast-ash/unsigned=>unsigned) - (:note "inline ASH") - (:args (number :scs (unsigned-reg) :to :save) - (amount :scs (signed-reg))) - (:arg-types unsigned-num signed-num) - (:results (result :scs (unsigned-reg))) - (:result-types unsigned-num) - (:translate ash) - (:policy :fast-safe) - (:temporary (:sc non-descriptor-reg) ndesc) - (:temporary (:sc non-descriptor-reg) temp) - (:generator 3 - (inst bge amount positive) - (inst subq zero-tn amount ndesc) - (inst cmplt ndesc 64 temp) - (inst srl number ndesc result) - ;; FIXME: this looks like a candidate for a conditional move -- - ;; CSR, 2003-09-10 - (inst bne temp done) - (move zero-tn result) - (inst br zero-tn done) - - POSITIVE - (inst sll number amount result) - - DONE)) - -(define-vop (fast-ash/signed=>signed) - (:note "inline ASH") - (:args (number :scs (signed-reg) :to :save) - (amount :scs (signed-reg))) - (:arg-types signed-num signed-num) - (:results (result :scs (signed-reg))) - (:result-types signed-num) - (:translate ash) - (:policy :fast-safe) - (:temporary (:sc non-descriptor-reg) ndesc) - (:temporary (:sc non-descriptor-reg) temp) - (:generator 3 - (inst bge amount positive) - (inst subq zero-tn amount ndesc) - (inst cmplt ndesc 63 temp) - (inst sra number ndesc result) - (inst bne temp done) - (inst sra number 63 result) - (inst br zero-tn done) - - POSITIVE - (inst sll number amount result) - - DONE)) - -(define-vop (fast-ash-c/signed=>signed) - (:policy :fast-safe) - (:translate ash) - (:note nil) - (:args (number :scs (signed-reg))) - (:info count) - (:arg-types signed-num (:constant integer)) - (:results (result :scs (signed-reg))) - (:result-types signed-num) - (:generator 1 - (cond - ((< count 0) (inst sra number (min 63 (- count)) result)) - ((> count 0) (inst sll number (min 63 count) result)) - (t (bug "identity ASH not transformed away"))))) - -(define-vop (fast-ash-c/unsigned=>unsigned) - (:policy :fast-safe) - (:translate ash) - (:note nil) - (:args (number :scs (unsigned-reg))) - (:info count) - (:arg-types unsigned-num (:constant integer)) - (:results (result :scs (unsigned-reg))) - (:result-types unsigned-num) - (:generator 1 - (cond - ((< count -63) (move zero-tn result)) - ((< count 0) (inst sra number (- count) result)) - ((> count 0) (inst sll number (min 63 count) result)) - (t (bug "identity ASH not transformed away"))))) - -(macrolet ((def (name sc-type type result-type cost) - `(define-vop (,name) - (:note "inline ASH") - (:translate ash) - (:args (number :scs (,sc-type)) - (amount :scs (signed-reg unsigned-reg immediate))) - (:arg-types ,type positive-fixnum) - (:results (result :scs (,result-type))) - (:result-types ,type) - (:policy :fast-safe) - (:generator ,cost - (sc-case amount - ((signed-reg unsigned-reg) - (inst sll number amount result)) - (immediate - (let ((amount (tn-value amount))) - (aver (> amount 0)) - (inst sll number amount result)))))))) - (def fast-ash-left/fixnum=>fixnum any-reg tagged-num any-reg 2) - (def fast-ash-left/signed=>signed signed-reg signed-num signed-reg 3) - (def fast-ash-left/unsigned=>unsigned unsigned-reg unsigned-num unsigned-reg 3)) - -(define-vop (signed-byte-64-len) - (:translate integer-length) - (:note "inline (signed-byte 64) integer-length") - (:policy :fast-safe) - (:args (arg :scs (signed-reg) :to (:argument 1))) - (:arg-types signed-num) - (:results (res :scs (any-reg))) - (:result-types positive-fixnum) - (:temporary (:scs (non-descriptor-reg) :from (:argument 0)) shift) - (:generator 30 - (inst not arg shift) - (inst cmovge arg arg shift) - (inst subq zero-tn (fixnumize 1) res) - (inst sll shift 1 shift) - LOOP - (inst addq res (fixnumize 1) res) - (inst srl shift 1 shift) - (inst bne shift loop))) - -(define-vop (unsigned-byte-64-count) - (:translate logcount) - (:note "inline (unsigned-byte 64) logcount") - (:policy :fast-safe) - (:args (arg :scs (unsigned-reg))) - (:arg-types unsigned-num) - (:results (res :scs (unsigned-reg))) - (:result-types positive-fixnum) - (:guard (member :cix *backend-subfeatures*)) - (:generator 1 - (inst ctpop zero-tn arg res))) - -(define-vop (unsigned-byte-64-count) - (:translate logcount) - (:note "inline (unsigned-byte 64) logcount") - (:policy :fast-safe) - (:args (arg :scs (unsigned-reg) :target num)) - (:arg-types unsigned-num) - (:results (res :scs (unsigned-reg))) - (:result-types positive-fixnum) - (:temporary (:scs (non-descriptor-reg) :from (:argument 0) :to (:result 0) - :target res) num) - (:temporary (:scs (non-descriptor-reg)) mask temp) - (:generator 60 - ;; FIXME: now this looks expensive, what with these 64bit loads. - ;; Maybe a loop and count would be faster? -- CSR, 2003-09-10 - (inst li #x5555555555555555 mask) - (inst srl arg 1 temp) - (inst and arg mask num) - (inst and temp mask temp) - (inst addq num temp num) - (inst li #x3333333333333333 mask) - (inst srl num 2 temp) - (inst and num mask num) - (inst and temp mask temp) - (inst addq num temp num) - (inst li #x0f0f0f0f0f0f0f0f mask) - (inst srl num 4 temp) - (inst and num mask num) - (inst and temp mask temp) - (inst addq num temp num) - (inst li #x00ff00ff00ff00ff mask) - (inst srl num 8 temp) - (inst and num mask num) - (inst and temp mask temp) - (inst addq num temp num) - (inst li #x0000ffff0000ffff mask) - (inst srl num 16 temp) - (inst and num mask num) - (inst and temp mask temp) - (inst addq num temp num) - (inst li #x00000000ffffffff mask) - (inst srl num 32 temp) - (inst and num mask num) - (inst and temp mask temp) - (inst addq num temp res))) - -;;;; multiplying - -(define-vop (fast-*/fixnum=>fixnum fast-fixnum-binop) - (:temporary (:scs (non-descriptor-reg)) temp) - (:translate *) - (:generator 4 - (inst sra y n-fixnum-tag-bits temp) - (inst mulq x temp r))) - -(define-vop (fast-*/signed=>signed fast-signed-binop) - (:translate *) - (:generator 3 - (inst mulq x y r))) - -(define-vop (fast-*/unsigned=>unsigned fast-unsigned-binop) - (:translate *) - (:generator 3 - (inst mulq x y r))) - -;;;; Modular functions: -(define-modular-fun lognot-mod64 (x) lognot :untagged nil 64) -(define-vop (lognot-mod64/unsigned=>unsigned) - (:translate lognot-mod64) - (:args (x :scs (unsigned-reg))) - (:arg-types unsigned-num) - (:results (res :scs (unsigned-reg))) - (:result-types unsigned-num) - (:policy :fast-safe) - (:generator 1 - (inst not x res))) - -(define-vop (fast-ash-left-mod64-c/unsigned=>unsigned - fast-ash-c/unsigned=>unsigned) - (:translate ash-left-mod64)) -(define-vop (fast-ash-left-mod64/unsigned=>unsigned - fast-ash-left/unsigned=>unsigned)) -(deftransform ash-left-mod64 ((integer count) - ((unsigned-byte 64) (unsigned-byte 6))) - (when (sb-c::constant-lvar-p count) - (sb-c::give-up-ir1-transform)) - '(%primitive fast-ash-left-mod64/unsigned=>unsigned integer count)) - -(macrolet - ((define-modular-backend (fun &optional constantp) - (let ((mfun-name (symbolicate fun '-mod64)) - (modvop (symbolicate 'fast- fun '-mod64/unsigned=>unsigned)) - (modcvop (symbolicate 'fast- fun '-mod64-c/unsigned=>unsigned)) - (vop (symbolicate 'fast- fun '/unsigned=>unsigned)) - (cvop (symbolicate 'fast- fun '-c/unsigned=>unsigned))) - `(progn - (define-modular-fun ,mfun-name (x y) ,fun :untagged nil 64) - (define-vop (,modvop ,vop) - (:translate ,mfun-name)) - ,@(when constantp - `((define-vop (,modcvop ,cvop) - (:translate ,mfun-name)))))))) - (define-modular-backend + t) - (define-modular-backend - t) - (define-modular-backend logeqv t) - (define-modular-backend logandc1) - (define-modular-backend logandc2 t) - (define-modular-backend logorc1) - (define-modular-backend logorc2 t)) - -(define-source-transform lognand (x y) - `(lognot (logand ,x ,y))) -(define-source-transform lognor (x y) - `(lognot (logior ,x ,y))) - -;;;; binary conditional VOPs - -(define-vop (fast-conditional) - (:conditional) - (:info target not-p) - (:temporary (:scs (non-descriptor-reg)) temp) - (:policy :fast-safe)) - -(define-vop (fast-conditional/fixnum fast-conditional) - (:args (x :scs (any-reg)) - (y :scs (any-reg))) - (:arg-types tagged-num tagged-num) - (:note "inline fixnum comparison")) - -(define-vop (fast-conditional-c/fixnum fast-conditional/fixnum) - (:args (x :scs (any-reg))) - (:arg-types tagged-num (:constant (unsigned-byte-with-a-bite-out 6 4))) - (:info target not-p y)) - -(define-vop (fast-conditional/signed fast-conditional) - (:args (x :scs (signed-reg)) - (y :scs (signed-reg))) - (:arg-types signed-num signed-num) - (:note "inline (signed-byte 64) comparison")) - -(define-vop (fast-conditional-c/signed fast-conditional/signed) - (:args (x :scs (signed-reg))) - (:arg-types signed-num (:constant (unsigned-byte-with-a-bite-out 8 1))) - (:info target not-p y)) - -(define-vop (fast-conditional/unsigned fast-conditional) - (:args (x :scs (unsigned-reg)) - (y :scs (unsigned-reg))) - (:arg-types unsigned-num unsigned-num) - (:note "inline (unsigned-byte 64) comparison")) - -(define-vop (fast-conditional-c/unsigned fast-conditional/unsigned) - (:args (x :scs (unsigned-reg))) - (:arg-types unsigned-num (:constant (unsigned-byte-with-a-bite-out 8 1))) - (:info target not-p y)) - - -(defmacro define-conditional-vop (translate &rest generator) - `(progn - ,@(mapcar (lambda (suffix cost signed) - (unless (and (member suffix '(/fixnum -c/fixnum)) - (eq translate 'eql)) - `(define-vop (,(intern (format nil "~:@(FAST-IF-~A~A~)" - translate suffix)) - ,(intern - (format nil "~:@(FAST-CONDITIONAL~A~)" - suffix))) - (:translate ,translate) - (:generator ,cost - (let* ((signed ,signed) - (-c/fixnum ,(eq suffix '-c/fixnum)) - (y (if -c/fixnum (fixnumize y) y))) - ,@generator))))) - '(/fixnum -c/fixnum /signed -c/signed /unsigned -c/unsigned) - '(3 2 5 4 5 4) - '(t t t t nil nil)))) - -(define-conditional-vop < - (cond ((and signed (eql y 0)) - (if not-p - (inst bge x target) - (inst blt x target))) - (t - (if signed - (inst cmplt x y temp) - (inst cmpult x y temp)) - (if not-p - (inst beq temp target) - (inst bne temp target))))) - -(define-conditional-vop > - (cond ((and signed (eql y 0)) - (if not-p - (inst ble x target) - (inst bgt x target))) - ((integerp y) - (let ((y (+ y (if -c/fixnum (fixnumize 1) 1)))) - (if signed - (inst cmplt x y temp) - (inst cmpult x y temp)) - (if not-p - (inst bne temp target) - (inst beq temp target)))) - (t - (if signed - (inst cmplt y x temp) - (inst cmpult y x temp)) - (if not-p - (inst beq temp target) - (inst bne temp target))))) - -;;; EQL/FIXNUM is funny because the first arg can be of any type, not -;;; just a known fixnum. - -(define-conditional-vop eql - (declare (ignore signed)) - (when (integerp y) - (inst li y temp) - (setf y temp)) - (inst cmpeq x y temp) - (if not-p - (inst beq temp target) - (inst bne temp target))) - -;;; These versions specify a fixnum restriction on their first arg. We -;;; have also generic-eql/fixnum VOPs which are the same, but have no -;;; restriction on the first arg and a higher cost. The reason for -;;; doing this is to prevent fixnum specific operations from being -;;; used on word integers, spuriously consing the argument. -(define-vop (fast-eql/fixnum fast-conditional) - (:args (x :scs (any-reg)) - (y :scs (any-reg))) - (:arg-types tagged-num tagged-num) - (:note "inline fixnum comparison") - (:translate eql) - (:generator 3 - (cond ((equal y zero-tn) - (if not-p - (inst bne x target) - (inst beq x target))) - (t - (inst cmpeq x y temp) - (if not-p - (inst beq temp target) - (inst bne temp target)))))) - -;;; -(define-vop (generic-eql/fixnum fast-eql/fixnum) - (:args (x :scs (any-reg descriptor-reg)) - (y :scs (any-reg))) - (:arg-types * tagged-num) - (:variant-cost 7)) - -(define-vop (fast-eql-c/fixnum fast-conditional/fixnum) - (:args (x :scs (any-reg))) - (:arg-types tagged-num (:constant (signed-byte 6))) - (:temporary (:scs (non-descriptor-reg)) temp) - (:info target not-p y) - (:translate eql) - (:generator 2 - (let ((y (cond ((eql y 0) zero-tn) - (t - (inst li (fixnumize y) temp) - temp)))) - (inst cmpeq x y temp) - (if not-p - (inst beq temp target) - (inst bne temp target))))) -;;; -(define-vop (generic-eql-c/fixnum fast-eql-c/fixnum) - (:args (x :scs (any-reg descriptor-reg))) - (:arg-types * (:constant (signed-byte 6))) - (:variant-cost 6)) - - -;;;; 32-bit logical operations - -(define-vop (shift-towards-someplace) - (:policy :fast-safe) - (:args (num :scs (unsigned-reg)) - (amount :scs (signed-reg))) - (:arg-types unsigned-num tagged-num) - (:results (r :scs (unsigned-reg))) - (:result-types unsigned-num)) - -(define-vop (shift-towards-start shift-towards-someplace) - (:translate shift-towards-start) - (:note "SHIFT-TOWARDS-START") - (:temporary (:sc non-descriptor-reg) temp) - (:generator 1 - (inst and amount #x1f temp) - (inst srl num temp r))) - -(define-vop (shift-towards-end shift-towards-someplace) - (:translate shift-towards-end) - (:note "SHIFT-TOWARDS-END") - (:temporary (:sc non-descriptor-reg) temp) - (:generator 1 - (inst and amount #x1f temp) - (inst sll num temp r))) - -;;;; bignum stuff - -(define-vop (bignum-length get-header-data) - (:translate sb-bignum:%bignum-length) - (:policy :fast-safe)) - -(define-vop (bignum-set-length set-header-data) - (:translate sb-bignum:%bignum-set-length) - (:policy :fast-safe)) - -(define-full-reffer bignum-ref * bignum-digits-offset other-pointer-lowtag - (unsigned-reg) unsigned-num sb-bignum:%bignum-ref) - -(define-full-setter bignum-set * bignum-digits-offset other-pointer-lowtag - (unsigned-reg) unsigned-num sb-bignum:%bignum-set #+gengc nil) - -(define-vop (digit-0-or-plus) - (:translate sb-bignum:%digit-0-or-plusp) - (:policy :fast-safe) - (:args (digit :scs (unsigned-reg))) - (:arg-types unsigned-num) - (:temporary (:sc non-descriptor-reg) temp) - (:conditional) - (:info target not-p) - (:generator 2 - (inst sll digit 32 temp) - (if not-p - (inst blt temp target) - (inst bge temp target)))) - -(define-vop (add-w/carry) - (:translate sb-bignum:%add-with-carry) - (:policy :fast-safe) - (:args (a :scs (unsigned-reg)) - (b :scs (unsigned-reg)) - (c :scs (unsigned-reg))) - (:arg-types unsigned-num unsigned-num positive-fixnum) - (:results (result :scs (unsigned-reg) :from :load) - (carry :scs (unsigned-reg) :from :eval)) - (:result-types unsigned-num positive-fixnum) - (:generator 5 - (inst addq a b result) - (inst addq result c result) - (inst sra result 32 carry) - (inst mskll result 4 result))) - -(define-vop (sub-w/borrow) - (:translate sb-bignum:%subtract-with-borrow) - (:policy :fast-safe) - (:args (a :scs (unsigned-reg)) - (b :scs (unsigned-reg)) - (c :scs (unsigned-reg))) - (:arg-types unsigned-num unsigned-num positive-fixnum) - (:results (result :scs (unsigned-reg) :from :load) - (borrow :scs (unsigned-reg) :from :eval)) - (:result-types unsigned-num positive-fixnum) - (:generator 4 - (inst xor c 1 result) - (inst subq a result result) - (inst subq result b result) - (inst srl result 63 borrow) - (inst xor borrow 1 borrow) - (inst mskll result 4 result))) - -(define-vop (bignum-mult-and-add-3-arg) - (:translate sb-bignum:%multiply-and-add) - (:policy :fast-safe) - (:args (x :scs (unsigned-reg)) - (y :scs (unsigned-reg)) - (carry-in :scs (unsigned-reg) :to :save)) - (:arg-types unsigned-num unsigned-num unsigned-num) - (:results (hi :scs (unsigned-reg)) - (lo :scs (unsigned-reg))) - (:result-types unsigned-num unsigned-num) - (:generator 6 - (inst mulq x y lo) - (inst addq lo carry-in lo) - (inst srl lo 32 hi) - (inst mskll lo 4 lo))) - - -(define-vop (bignum-mult-and-add-4-arg) - (:translate sb-bignum:%multiply-and-add) - (:policy :fast-safe) - (:args (x :scs (unsigned-reg)) - (y :scs (unsigned-reg)) - (prev :scs (unsigned-reg)) - (carry-in :scs (unsigned-reg) :to :save)) - (:arg-types unsigned-num unsigned-num unsigned-num unsigned-num) - (:results (hi :scs (unsigned-reg)) - (lo :scs (unsigned-reg))) - (:result-types unsigned-num unsigned-num) - (:generator 9 - (inst mulq x y lo) - (inst addq lo prev lo) - (inst addq lo carry-in lo) - (inst srl lo 32 hi) - (inst mskll lo 4 lo))) - -(define-vop (bignum-mult) - (:translate sb-bignum:%multiply) - (:policy :fast-safe) - (:args (x :scs (unsigned-reg)) - (y :scs (unsigned-reg))) - (:arg-types unsigned-num unsigned-num) - (:results (hi :scs (unsigned-reg)) - (lo :scs (unsigned-reg))) - (:result-types unsigned-num unsigned-num) - (:generator 3 - (inst mulq x y lo) - (inst srl lo 32 hi) - (inst mskll lo 4 lo))) - -(define-vop (bignum-lognot) - (:translate sb-bignum:%lognot) - (:policy :fast-safe) - (:args (x :scs (unsigned-reg))) - (:arg-types unsigned-num) - (:results (r :scs (unsigned-reg))) - (:result-types unsigned-num) - (:generator 1 - (inst not x r) - (inst mskll r 4 r))) - -(define-vop (fixnum-to-digit) - (:translate sb-bignum:%fixnum-to-digit) - (:policy :fast-safe) - (:args (fixnum :scs (any-reg))) - (:arg-types tagged-num) - (:results (digit :scs (unsigned-reg))) - (:result-types unsigned-num) - (:generator 1 - (inst sra fixnum n-fixnum-tag-bits digit))) - -(define-vop (bignum-floor) - (:translate sb-bignum:%bigfloor) - (:policy :fast-safe) - (:args (num-high :scs (unsigned-reg)) - (num-low :scs (unsigned-reg)) - (denom-arg :scs (unsigned-reg) :target denom)) - (:arg-types unsigned-num unsigned-num unsigned-num) - (:temporary (:scs (unsigned-reg) :from (:argument 2)) denom) - (:temporary (:scs (unsigned-reg) :from (:eval 0)) temp) - (:results (quo :scs (unsigned-reg) :from (:eval 0)) - (rem :scs (unsigned-reg) :from (:argument 0))) - (:result-types unsigned-num unsigned-num) - (:generator 325 ; number of inst assuming targeting works. - (inst sll num-high 32 rem) - (inst bis rem num-low rem) - (inst sll denom-arg 32 denom) - (inst cmpule denom rem quo) - (inst beq quo shift1) - (inst subq rem denom rem) - SHIFT1 - (dotimes (i 32) - (let ((shift2 (gen-label))) - (inst srl denom 1 denom) - (inst cmpule denom rem temp) - (inst sll quo 1 quo) - (inst beq temp shift2) - (inst subq rem denom rem) - (inst bis quo 1 quo) - (emit-label shift2))))) - -(define-vop (signify-digit) - (:translate sb-bignum:%fixnum-digit-with-correct-sign) - (:policy :fast-safe) - (:args (digit :scs (unsigned-reg) :target res)) - (:arg-types unsigned-num) - (:results (res :scs (any-reg signed-reg))) - (:result-types signed-num) - (:generator 2 - (sc-case res - (any-reg - (inst sll digit 34 res) - (inst sra res 32 res)) - (signed-reg - (inst sll digit 32 res) - (inst sra res 32 res))))) - - -(define-vop (digit-ashr) - (:translate sb-bignum:%ashr) - (:policy :fast-safe) - (:args (digit :scs (unsigned-reg)) - (count :scs (unsigned-reg))) - (:arg-types unsigned-num positive-fixnum) - (:results (result :scs (unsigned-reg) :from (:argument 0))) - (:result-types unsigned-num) - (:generator 1 - (inst sll digit 32 result) - (inst sra result count result) - (inst srl result 32 result))) - -(define-vop (digit-lshr digit-ashr) - (:translate sb-bignum:%digit-logical-shift-right) - (:generator 1 - (inst srl digit count result))) - -(define-vop (digit-ashl digit-ashr) - (:translate sb-bignum:%ashl) - (:generator 1 - (inst sll digit count result))) diff --git a/src/compiler/alpha/array.lisp b/src/compiler/alpha/array.lisp deleted file mode 100644 index 99239ca8e4..0000000000 --- a/src/compiler/alpha/array.lisp +++ /dev/null @@ -1,534 +0,0 @@ -;;;; the Alpha definitions for array operations - -;;;; This software is part of the SBCL system. See the README file for -;;;; more information. -;;;; -;;;; This software is derived from the CMU CL system, which was -;;;; written at Carnegie Mellon University and released into the -;;;; public domain. The software is in the public domain and is -;;;; provided with absolutely no warranty. See the COPYING and CREDITS -;;;; files for more information. - -(in-package "SB-VM") - -;;;; allocator for the array header -(define-vop (make-array-header) - (:policy :fast-safe) - (:translate make-array-header) - (:args (type :scs (any-reg)) - (rank :scs (any-reg))) - (:arg-types positive-fixnum positive-fixnum) - (:temporary (:scs (any-reg)) bytes) - (:temporary (:scs (non-descriptor-reg)) header) - (:results (result :scs (descriptor-reg))) - (:generator 13 - (inst addq rank (+ (* array-dimensions-offset n-word-bytes) - lowtag-mask) - bytes) - (inst li (lognot lowtag-mask) header) - (inst and bytes header bytes) - (inst addq rank (fixnumize (1- array-dimensions-offset)) header) - (inst sll header n-widetag-bits header) - (inst bis header type header) - (inst srl header n-fixnum-tag-bits header) - (pseudo-atomic () - (inst bis alloc-tn other-pointer-lowtag result) - (storew header result 0 other-pointer-lowtag) - (inst addq alloc-tn bytes alloc-tn)))) - -;;;; additional accessors and setters for the array header -(define-full-reffer %array-dimension * - array-dimensions-offset other-pointer-lowtag - (any-reg) positive-fixnum %array-dimension) - -(define-full-setter %set-array-dimension * - array-dimensions-offset other-pointer-lowtag - (any-reg) positive-fixnum %set-array-dimension #+gengc nil) - -(define-vop (array-rank-vop) - (:translate %array-rank) - (:policy :fast-safe) - (:args (x :scs (descriptor-reg))) - (:temporary (:scs (non-descriptor-reg)) temp) - (:results (res :scs (any-reg descriptor-reg))) - (:generator 6 - (loadw temp x 0 other-pointer-lowtag) - (inst sra temp n-widetag-bits temp) - (inst subq temp (1- array-dimensions-offset) temp) - (inst sll temp n-fixnum-tag-bits res))) - -;;;; bounds checking routine -(define-vop (check-bound) - (:translate %check-bound) - (:policy :fast-safe) - (:args (array :scs (descriptor-reg)) - (bound :scs (any-reg descriptor-reg)) - (index :scs (any-reg descriptor-reg))) - (:temporary (:scs (non-descriptor-reg)) temp) - (:vop-var vop) - (:save-p :compute-only) - (:generator 5 - (let ((error (generate-error-code vop 'invalid-array-index-error - array bound index))) - (%test-fixnum index temp error t) - (inst cmpult index bound temp) - (inst beq temp error)))) - -;;;; accessors/setters - -;;; Variants built on top of word-index-ref, etc. I.e. those vectors -;;; whose elements are represented in integer registers and are built -;;; out of 8, 16, or 32 bit elements. -(macrolet ((def-full-data-vector-frobs (type element-type &rest scs) - `(progn - (define-full-reffer ,(symbolicate "DATA-VECTOR-REF/" type) - ,type - vector-data-offset other-pointer-lowtag - ,(remove-if (lambda (x) (member x '(null zero))) scs) - ,element-type - data-vector-ref) - (define-full-setter ,(symbolicate "DATA-VECTOR-SET/" type) - ,type - vector-data-offset other-pointer-lowtag ,scs ,element-type - data-vector-set #+gengc ,(if (member 'descriptor-reg scs) - t - nil)))) - - (def-partial-data-vector-frobs - (type element-type size signed &rest scs) - `(progn - (define-partial-reffer ,(symbolicate "DATA-VECTOR-REF/" type) - ,type - ,size ,signed vector-data-offset other-pointer-lowtag ,scs - ,element-type data-vector-ref) - (define-partial-setter ,(symbolicate "DATA-VECTOR-SET/" type) - ,type - ,size vector-data-offset other-pointer-lowtag ,scs - ,element-type data-vector-set))) - (def-small-data-vector-frobs (type bits) - (let* ((elements-per-word (floor n-word-bits bits)) - (bit-shift (1- (integer-length elements-per-word)))) - `(progn - (define-vop (,(symbolicate 'data-vector-ref/ type)) - (:note "inline array access") - (:translate data-vector-ref) - (:policy :fast-safe) - (:args (object :scs (descriptor-reg)) - (index :scs (unsigned-reg))) - (:arg-types ,type positive-fixnum) - (:results (value :scs (any-reg))) - (:result-types positive-fixnum) - (:temporary (:scs (interior-reg)) lip) - (:temporary (:scs (non-descriptor-reg) :to (:result 0)) - temp result) - (:generator 20 - (inst srl index ,bit-shift temp) - (inst sll temp n-fixnum-tag-bits temp) - (inst addq object temp lip) - (inst ldl result - (- (* vector-data-offset n-word-bytes) - other-pointer-lowtag) - lip) - (inst and index ,(1- elements-per-word) temp) - ,@(unless (= bits 1) - `((inst sll temp - ,(1- (integer-length bits)) temp))) - (inst srl result temp result) - (inst and result ,(1- (ash 1 bits)) result) - (inst sll result n-fixnum-tag-bits value))) - (define-vop (,(symbolicate 'data-vector-ref-c/ type)) - (:translate data-vector-ref) - (:policy :fast-safe) - (:args (object :scs (descriptor-reg))) - (:arg-types ,type - (:constant - (integer 0 - ,(1- (* (1+ (- (floor (+ #x7fff - other-pointer-lowtag) - n-word-bytes) - vector-data-offset)) - elements-per-word))))) - (:info index) - (:results (result :scs (unsigned-reg))) - (:result-types positive-fixnum) - (:generator 15 - (multiple-value-bind (word extra) - (floor index ,elements-per-word) - (loadw result object (+ word - vector-data-offset) - other-pointer-lowtag) - (unless (zerop extra) - (inst srl result (* extra ,bits) result)) - (unless (= extra ,(1- elements-per-word)) - (inst and result ,(1- (ash 1 bits)) - result))))) - (define-vop (,(symbolicate 'data-vector-set/ type)) - (:note "inline array store") - (:translate data-vector-set) - (:policy :fast-safe) - (:args (object :scs (descriptor-reg)) - (index :scs (unsigned-reg) :target shift) - (value :scs (unsigned-reg zero immediate) - :target result)) - (:arg-types ,type positive-fixnum positive-fixnum) - (:results (result :scs (unsigned-reg))) - (:result-types positive-fixnum) - (:temporary (:scs (interior-reg)) lip) - (:temporary (:scs (non-descriptor-reg)) temp old) - (:temporary (:scs (non-descriptor-reg) - :from (:argument 1)) shift) - (:generator 25 - (inst srl index ,bit-shift temp) - (inst sll temp n-fixnum-tag-bits temp) - (inst addq object temp lip) - (inst ldl old - (- (* vector-data-offset n-word-bytes) - other-pointer-lowtag) - lip) - (inst and index ,(1- elements-per-word) shift) - ,@(unless (= bits 1) - `((inst sll shift ,(1- (integer-length - bits)) - shift))) - (unless (and (sc-is value immediate) - (= (tn-value value) - ,(1- (ash 1 bits)))) - (inst li ,(1- (ash 1 bits)) temp) - (inst sll temp shift temp) - (inst not temp temp) - (inst and old temp old)) - (unless (sc-is value zero) - (sc-case value - (immediate - (inst li - (logand (tn-value value) - ,(1- (ash 1 bits))) - temp)) - (unsigned-reg - (inst and value - ,(1- (ash 1 bits)) - temp))) - (inst sll temp shift temp) - (inst bis old temp old)) - (inst stl old - (- (* vector-data-offset n-word-bytes) - other-pointer-lowtag) - lip) - (sc-case value - (immediate - (inst li (tn-value value) result)) - (zero - (move zero-tn result)) - (unsigned-reg - (move value result))))) - (define-vop (,(symbolicate 'data-vector-set-c/ type)) - (:translate data-vector-set) - (:policy :fast-safe) - (:args (object :scs (descriptor-reg)) - (value :scs (unsigned-reg zero immediate) - :target result)) - (:arg-types ,type - (:constant - (integer 0 - ,(1- (* (1+ (- (floor (+ #x7fff - other-pointer-lowtag) - n-word-bytes) - vector-data-offset)) - elements-per-word)))) - positive-fixnum) - (:info index) - (:results (result :scs (unsigned-reg))) - (:result-types positive-fixnum) - (:temporary (:scs (non-descriptor-reg)) temp old) - (:generator 20 - (multiple-value-bind (word extra) - (floor index ,elements-per-word) - (inst ldl old - (- (* (+ word vector-data-offset) - n-word-bytes) - other-pointer-lowtag) - object) - (unless (and (sc-is value immediate) - (= (tn-value value) - ,(1- (ash 1 bits)))) - (cond #+#.(cl:if - (cl:= sb-vm:n-word-bits sb-vm:n-machine-word-bits) - '(and) '(or)) - ((= extra ,(1- elements-per-word)) - (inst sll old ,bits old) - (inst srl old ,bits old)) - (t - (inst li - (lognot (ash ,(1- (ash 1 - bits)) - (* extra ,bits))) - temp) - (inst and old temp old)))) - (sc-case value - (zero) - (immediate - (let ((value - (ash (logand (tn-value - value) - ,(1- (ash 1 - bits))) - (* extra - ,bits)))) - (cond ((< value #x100) - (inst bis old value old)) - (t - (inst li value temp) - (inst bis old temp old))))) - (unsigned-reg - (inst sll value (* extra ,bits) - temp) - (inst bis old temp old))) - (inst stl old - (- (* (+ word vector-data-offset) - n-word-bytes) - other-pointer-lowtag) - object) - (sc-case value - (immediate - (inst li (tn-value value) result)) - (zero - (move zero-tn result)) - (unsigned-reg - (move value result)))))))))) - (def-full-data-vector-frobs simple-vector * - descriptor-reg any-reg null zero) - - (def-partial-data-vector-frobs simple-base-string character :byte nil - character-reg) - #+sb-unicode ; FIXME: what about when a word is 64 bits? - (def-full-data-vector-frobs simple-character-string character character-reg) - - (def-partial-data-vector-frobs simple-array-unsigned-byte-7 positive-fixnum - :byte nil unsigned-reg signed-reg) - (def-partial-data-vector-frobs simple-array-unsigned-byte-8 positive-fixnum - :byte nil unsigned-reg signed-reg) - - (def-partial-data-vector-frobs simple-array-unsigned-byte-15 positive-fixnum - :short nil unsigned-reg signed-reg) - (def-partial-data-vector-frobs simple-array-unsigned-byte-16 positive-fixnum - :short nil unsigned-reg signed-reg) - - (def-full-data-vector-frobs simple-array-unsigned-byte-31 unsigned-num - unsigned-reg) - (def-full-data-vector-frobs simple-array-unsigned-byte-32 unsigned-num - unsigned-reg) - - (def-partial-data-vector-frobs simple-array-signed-byte-8 tagged-num - :byte t signed-reg) - - (def-partial-data-vector-frobs simple-array-signed-byte-16 tagged-num - :short t signed-reg) - - (def-full-data-vector-frobs simple-array-unsigned-fixnum positive-fixnum - any-reg) - (def-full-data-vector-frobs simple-array-fixnum tagged-num any-reg) - - (def-full-data-vector-frobs simple-array-signed-byte-32 signed-num - signed-reg) - - ;; Integer vectors whos elements are smaller than a byte. I.e. bit, - ;; 2-bit, and 4-bit vectors. - (def-small-data-vector-frobs simple-bit-vector 1) - (def-small-data-vector-frobs simple-array-unsigned-byte-2 2) - (def-small-data-vector-frobs simple-array-unsigned-byte-4 4)) - -;;; and the float variants.. - -(define-vop (data-vector-ref/simple-array-single-float) - (:note "inline array access") - (:translate data-vector-ref) - (:policy :fast-safe) - (:args (object :scs (descriptor-reg)) - (index :scs (any-reg))) - (:arg-types simple-array-single-float positive-fixnum) - (:results (value :scs (single-reg))) - (:result-types single-float) - (:temporary (:scs (interior-reg)) lip) - (:generator 20 - (inst addq object index lip) - (inst lds value - (- (* vector-data-offset n-word-bytes) - other-pointer-lowtag) - lip))) - -(define-vop (data-vector-set/simple-array-single-float) - (:note "inline array store") - (:translate data-vector-set) - (:policy :fast-safe) - (:args (object :scs (descriptor-reg)) - (index :scs (any-reg)) - (value :scs (single-reg) :target result)) - (:arg-types simple-array-single-float positive-fixnum single-float) - (:results (result :scs (single-reg))) - (:result-types single-float) - (:temporary (:scs (interior-reg)) lip) - (:generator 20 - (inst addq object index lip) - (inst sts value - (- (* vector-data-offset n-word-bytes) - other-pointer-lowtag) - lip) - (unless (location= result value) - (inst fmove value result)))) - -(define-vop (data-vector-ref/simple-array-double-float) - (:note "inline array access") - (:translate data-vector-ref) - (:policy :fast-safe) - (:args (object :scs (descriptor-reg)) - (index :scs (any-reg))) - (:arg-types simple-array-double-float positive-fixnum) - (:results (value :scs (double-reg))) - (:result-types double-float) - (:temporary (:scs (interior-reg)) lip) - (:generator 20 - (inst addq object index lip) - (inst addq lip index lip) - (inst ldt value - (- (* vector-data-offset n-word-bytes) - other-pointer-lowtag) - lip))) - -(define-vop (data-vector-set/simple-array-double-float) - (:note "inline array store") - (:translate data-vector-set) - (:policy :fast-safe) - (:args (object :scs (descriptor-reg)) - (index :scs (any-reg)) - (value :scs (double-reg) :target result)) - (:arg-types simple-array-double-float positive-fixnum double-float) - (:results (result :scs (double-reg))) - (:result-types double-float) - (:temporary (:scs (interior-reg)) lip) - (:generator 20 - (inst addq object index lip) - (inst addq lip index lip) - (inst stt value - (- (* vector-data-offset n-word-bytes) - other-pointer-lowtag) lip) - (unless (location= result value) - (inst fmove value result)))) - -;;; complex float arrays - -(define-vop (data-vector-ref/simple-array-complex-single-float) - (:note "inline array access") - (:translate data-vector-ref) - (:policy :fast-safe) - (:args (object :scs (descriptor-reg)) - (index :scs (any-reg))) - (:arg-types simple-array-complex-single-float positive-fixnum) - (:results (value :scs (complex-single-reg))) - (:temporary (:scs (interior-reg)) lip) - (:result-types complex-single-float) - (:generator 5 - (let ((real-tn (complex-single-reg-real-tn value))) - (inst addq object index lip) - (inst addq lip index lip) - (inst lds real-tn - (- (* vector-data-offset n-word-bytes) other-pointer-lowtag) - lip)) - (let ((imag-tn (complex-single-reg-imag-tn value))) - (inst lds imag-tn - (- (* (1+ vector-data-offset) n-word-bytes) other-pointer-lowtag) - lip)))) - -(define-vop (data-vector-set/simple-array-complex-single-float) - (:note "inline array store") - (:translate data-vector-set) - (:policy :fast-safe) - (:args (object :scs (descriptor-reg)) - (index :scs (any-reg)) - (value :scs (complex-single-reg) :target result)) - (:arg-types simple-array-complex-single-float positive-fixnum - complex-single-float) - (:results (result :scs (complex-single-reg))) - (:result-types complex-single-float) - (:temporary (:scs (interior-reg)) lip) - (:generator 5 - (let ((value-real (complex-single-reg-real-tn value)) - (result-real (complex-single-reg-real-tn result))) - (inst addq object index lip) - (inst addq lip index lip) - (inst sts value-real - (- (* vector-data-offset n-word-bytes) other-pointer-lowtag) - lip) - (unless (location= result-real value-real) - (inst fmove value-real result-real))) - (let ((value-imag (complex-single-reg-imag-tn value)) - (result-imag (complex-single-reg-imag-tn result))) - (inst sts value-imag - (- (* (1+ vector-data-offset) n-word-bytes) other-pointer-lowtag) - lip) - (unless (location= result-imag value-imag) - (inst fmove value-imag result-imag))))) - -(define-vop (data-vector-ref/simple-array-complex-double-float) - (:note "inline array access") - (:translate data-vector-ref) - (:policy :fast-safe) - (:args (object :scs (descriptor-reg)) - (index :scs (any-reg))) - (:arg-types simple-array-complex-double-float positive-fixnum) - (:results (value :scs (complex-double-reg))) - (:result-types complex-double-float) - (:temporary (:scs (interior-reg)) lip) - (:generator 7 - (let ((real-tn (complex-double-reg-real-tn value))) - (inst addq object index lip) - (inst addq lip index lip) - (inst addq lip index lip) - (inst addq lip index lip) - (inst ldt real-tn - (- (* vector-data-offset n-word-bytes) other-pointer-lowtag) - lip)) - (let ((imag-tn (complex-double-reg-imag-tn value))) - (inst ldt imag-tn - (- (* (+ vector-data-offset 2) n-word-bytes) other-pointer-lowtag) - lip)))) - -(define-vop (data-vector-set/simple-array-complex-double-float) - (:note "inline array store") - (:translate data-vector-set) - (:policy :fast-safe) - (:args (object :scs (descriptor-reg)) - (index :scs (any-reg)) - (value :scs (complex-double-reg) :target result)) - (:arg-types simple-array-complex-double-float positive-fixnum - complex-double-float) - (:results (result :scs (complex-double-reg))) - (:result-types complex-double-float) - (:temporary (:scs (interior-reg)) lip) - (:generator 20 - (let ((value-real (complex-double-reg-real-tn value)) - (result-real (complex-double-reg-real-tn result))) - (inst addq object index lip) - (inst addq lip index lip) - (inst addq lip index lip) - (inst addq lip index lip) - (inst stt value-real - (- (* vector-data-offset n-word-bytes) other-pointer-lowtag) - lip) - (unless (location= result-real value-real) - (inst fmove value-real result-real))) - (let ((value-imag (complex-double-reg-imag-tn value)) - (result-imag (complex-double-reg-imag-tn result))) - (inst stt value-imag - (- (* (+ vector-data-offset 2) n-word-bytes) other-pointer-lowtag) - lip) - (unless (location= result-imag value-imag) - (inst fmove value-imag result-imag))))) - - -;;; These vops are useful for accessing the bits of a vector irrespective of -;;; what type of vector it is. -;;; -(define-full-reffer vector-raw-bits * vector-data-offset other-pointer-lowtag - (unsigned-reg) unsigned-num %vector-raw-bits) -(define-full-setter set-vector-raw-bits * vector-data-offset other-pointer-lowtag - (unsigned-reg) unsigned-num %set-vector-raw-bits) diff --git a/src/compiler/alpha/c-call.lisp b/src/compiler/alpha/c-call.lisp deleted file mode 100644 index 907af7d48d..0000000000 --- a/src/compiler/alpha/c-call.lisp +++ /dev/null @@ -1,199 +0,0 @@ -;;;; VOPs and other machine-specific support routines for call-out to C - -;;;; This software is part of the SBCL system. See the README file for -;;;; more information. -;;;; -;;;; This software is derived from the CMU CL system, which was -;;;; written at Carnegie Mellon University and released into the -;;;; public domain. The software is in the public domain and is -;;;; provided with absolutely no warranty. See the COPYING and CREDITS -;;;; files for more information. - -(in-package "SB-VM") - -(defstruct arg-state - (stack-frame-size 0)) - -(define-alien-type-method (integer :arg-tn) (type state) - (let ((stack-frame-size (arg-state-stack-frame-size state))) - (setf (arg-state-stack-frame-size state) (1+ stack-frame-size)) - (multiple-value-bind - (ptype reg-sc stack-sc) - (if (alien-integer-type-signed type) - (values 'signed-byte-64 signed-reg-sc-number signed-stack-sc-number) - (values 'unsigned-byte-64 unsigned-reg-sc-number unsigned-stack-sc-number)) - (if (< stack-frame-size 4) - (make-wired-tn* ptype reg-sc (+ stack-frame-size nl0-offset)) - (make-wired-tn* ptype stack-sc (* 2 (- stack-frame-size 4))))))) - -(define-alien-type-method (system-area-pointer :arg-tn) (type state) - (declare (ignore type)) - (let ((stack-frame-size (arg-state-stack-frame-size state))) - (setf (arg-state-stack-frame-size state) (1+ stack-frame-size)) - (if (< stack-frame-size 4) - (make-wired-tn* 'system-area-pointer sap-reg-sc-number - (+ stack-frame-size nl0-offset)) - (make-wired-tn* 'system-area-pointer sap-stack-sc-number - (* 2 (- stack-frame-size 4)))))) - -(define-alien-type-method (double-float :arg-tn) (type state) - (declare (ignore type)) - (let ((stack-frame-size (arg-state-stack-frame-size state))) - (setf (arg-state-stack-frame-size state) (1+ stack-frame-size)) - (if (< stack-frame-size 6) - (make-wired-tn* 'double-float double-reg-sc-number - (+ stack-frame-size nl0-offset)) - (make-wired-tn* 'double-float double-stack-sc-number - (* 2 (- stack-frame-size 4)))))) - -(define-alien-type-method (single-float :arg-tn) (type state) - (declare (ignore type)) - (let ((stack-frame-size (arg-state-stack-frame-size state))) - (setf (arg-state-stack-frame-size state) (1+ stack-frame-size)) - (if (< stack-frame-size 6) - (make-wired-tn* 'single-float single-reg-sc-number - (+ stack-frame-size nl0-offset)) - (make-wired-tn* 'single-float single-stack-sc-number - (* 2 (- stack-frame-size 4)))))) - -(define-alien-type-method (integer :result-tn) (type state) - (declare (ignore state)) - (multiple-value-bind - (ptype reg-sc) - (if (alien-integer-type-signed type) - (values 'signed-byte-64 signed-reg-sc-number) - (values 'unsigned-byte-64 unsigned-reg-sc-number)) - (make-wired-tn* ptype reg-sc lip-offset))) - -(define-alien-type-method (integer :naturalize-gen) (type alien) - (if (<= (alien-type-bits type) 32) - (if (alien-integer-type-signed type) - `(sign-extend ,alien ,(alien-type-bits type)) - `(logand ,alien ,(1- (ash 1 (alien-type-bits type))))) - alien)) - -(define-alien-type-method (system-area-pointer :result-tn) (type state) - (declare (ignore type state)) - (make-wired-tn* 'system-area-pointer sap-reg-sc-number lip-offset)) - -(define-alien-type-method (double-float :result-tn) (type state) - (declare (ignore type state)) - (make-wired-tn* 'double-float double-reg-sc-number lip-offset)) - -(define-alien-type-method (single-float :result-tn) (type state) - (declare (ignore type state)) - (make-wired-tn* 'single-float single-reg-sc-number lip-offset)) - -(define-alien-type-method (values :result-tn) (type state) - (let ((values (alien-values-type-values type))) - (when (cdr values) - (error "Too many result values from c-call.")) - (when values - (invoke-alien-type-method :result-tn (car values) state)))) - -(defun make-call-out-tns (type) - (let ((arg-state (make-arg-state))) - (collect ((arg-tns)) - (dolist (arg-type (alien-fun-type-arg-types type)) - (arg-tns (invoke-alien-type-method :arg-tn arg-type arg-state))) - (values (make-wired-tn* 'positive-fixnum any-reg-sc-number nsp-offset) - (* (max (- (logandc2 (1+ (arg-state-stack-frame-size arg-state)) 1) 4) 2) - n-word-bytes - #.(floor n-machine-word-bits n-word-bits)) - (arg-tns) - (invoke-alien-type-method :result-tn - (alien-fun-type-result-type type) - nil))))) - -(defknown sign-extend ((signed-byte 64) t) fixnum - (foldable flushable movable)) - -(define-vop (sign-extend) - (:translate sign-extend) - (:policy :fast-safe) - (:args (val :scs (signed-reg) :target res)) - (:arg-types signed-num (:constant fixnum)) - (:info size) - (:results (res :scs (signed-reg))) - (:result-types fixnum) - (:generator 1 - (ecase size - (8 - ;;(inst sextb val res) ;; Under what circumstances can we use this? - (inst sll val 56 res) - (inst sra res 56 res)) - (16 - ;;(inst sextw val res) ;; Under what circumstances can we use this? - (inst sll val 48 res) - (inst sra res 48 res)) - (32 - (inst sll val 32 res) - (inst sra res 32 res))))) - -#-sb-xc-host -(defun sign-extend (x size) - (declare (type (signed-byte 64) x)) - (ecase size - (8 (sign-extend x size)) - (16 (sign-extend x size)) - (32 (sign-extend x size)))) - -(define-vop (foreign-symbol-sap) - (:translate foreign-symbol-sap) - (:policy :fast-safe) - (:args) - (:arg-types (:constant simple-string)) - (:info foreign-symbol) - (:results (res :scs (sap-reg))) - (:result-types system-area-pointer) - (:generator 2 - (inst li (make-fixup foreign-symbol :foreign) res))) - -(define-vop (call-out) - (:args (function :scs (sap-reg) :target cfunc) - (args :more t)) - (:results (results :more t)) - (:ignore args results) - (:save-p t) - (:temporary (:sc any-reg :offset cfunc-offset - :from (:argument 0) :to (:result 0)) cfunc) - (:temporary (:sc control-stack :offset nfp-save-offset) nfp-save) - (:temporary (:scs (non-descriptor-reg)) temp) - (:vop-var vop) - (:generator 0 - (let ((cur-nfp (sb-c:current-nfp-tn vop))) - (when cur-nfp - (store-stack-tn nfp-save cur-nfp)) - (move function cfunc) - (inst li (make-fixup "call_into_c" :foreign) temp) - (inst jsr lip-tn temp (make-fixup "call_into_c" :foreign)) - (when cur-nfp - (maybe-load-stack-nfp-tn cur-nfp nfp-save temp))))) - -(define-vop (alloc-number-stack-space) - (:info amount) - (:results (result :scs (sap-reg any-reg))) - (:result-types system-area-pointer) - (:temporary (:scs (unsigned-reg) :to (:result 0)) temp) - (:generator 0 - (unless (zerop amount) - (let ((delta (logandc2 (+ amount 7) 7))) - (cond ((< delta (ash 1 15)) - (inst lda nsp-tn (- delta) nsp-tn)) - (t - (inst li delta temp) - (inst subq nsp-tn temp nsp-tn))))) - (move nsp-tn result))) - -(define-vop (dealloc-number-stack-space) - (:info amount) - (:policy :fast-safe) - (:temporary (:scs (unsigned-reg) :to (:result 0)) temp) - (:generator 0 - (unless (zerop amount) - (let ((delta (logandc2 (+ amount 7) 7))) - (cond ((< delta (ash 1 15)) - (inst lda nsp-tn delta nsp-tn)) - (t - (inst li delta temp) - (inst addq nsp-tn temp nsp-tn))))))) diff --git a/src/compiler/alpha/call.lisp b/src/compiler/alpha/call.lisp deleted file mode 100644 index 969e6171c4..0000000000 --- a/src/compiler/alpha/call.lisp +++ /dev/null @@ -1,1214 +0,0 @@ -;;;; the VM definition of function call for the Alpha - -;;;; This software is part of the SBCL system. See the README file for -;;;; more information. -;;;; -;;;; This software is derived from the CMU CL system, which was -;;;; written at Carnegie Mellon University and released into the -;;;; public domain. The software is in the public domain and is -;;;; provided with absolutely no warranty. See the COPYING and CREDITS -;;;; files for more information. - -(in-package "SB-VM") - -(defconstant arg-count-sc (make-sc+offset immediate-arg-scn nargs-offset)) -(defconstant closure-sc (make-sc+offset descriptor-reg-sc-number lexenv-offset)) - -;;; Make a passing location TN for a local call return PC. If standard -;;; is true, then use the standard (full call) location, otherwise use -;;; any legal location. Even in the non-standard case, this may be -;;; restricted by a desire to use a subroutine call instruction. -(defun make-return-pc-passing-location (standard) - (if standard - (make-wired-tn *backend-t-primitive-type* descriptor-reg-sc-number lra-offset) - (make-restricted-tn *backend-t-primitive-type* descriptor-reg-sc-number))) - -;;; This is similar to MAKE-RETURN-PC-PASSING-LOCATION, but makes a -;;; location to pass OLD-FP in. This is (obviously) wired in the -;;; standard convention, but is totally unrestricted in non-standard -;;; conventions, since we can always fetch it off of the stack using -;;; the arg pointer. -(defun make-old-fp-passing-location () - (make-wired-tn *fixnum-primitive-type* immediate-arg-scn ocfp-offset)) - -(defconstant old-fp-passing-offset - (make-sc+offset descriptor-reg-sc-number ocfp-offset)) - -;;; These functions make the TNs used to hold Old-FP and Return-PC -;;; within the current function. We treat these specially so that the -;;; debugger can find them at a known location. -(defun make-old-fp-save-location (env) - (specify-save-tn - (physenv-debug-live-tn (make-normal-tn *fixnum-primitive-type*) env) - (make-wired-tn *fixnum-primitive-type* - control-stack-arg-scn - ocfp-save-offset))) -(defun make-return-pc-save-location (env) - (let ((ptype *backend-t-primitive-type*)) - (specify-save-tn - (physenv-debug-live-tn (make-normal-tn ptype) env) - (make-wired-tn ptype control-stack-arg-scn lra-save-offset)))) - -;;; Make a TN for the standard argument count passing location. We -;;; only need to make the standard location, since a count is never -;;; passed when we are using non-standard conventions. -(defun make-arg-count-location () - (make-wired-tn *fixnum-primitive-type* immediate-arg-scn nargs-offset)) - -;;;; frame hackery - -;;; Return the number of bytes needed for the current non-descriptor -;;; stack frame. Non-descriptor stack frames must be multiples of 16 -;;; bytes to preserve alien stack alignment. -(defun bytes-needed-for-non-descriptor-stack-frame () - (* (logandc2 (+ 3 (sb-allocated-size 'non-descriptor-stack)) 3) - n-word-bytes)) - -;;; This is used for setting up the Old-FP in local call. -(define-vop (current-fp) - (:results (val :scs (any-reg))) - (:generator 1 - (move cfp-tn val))) - -;;; This is used for computing the caller's NFP for use in -;;; known-values return. It only works assuming there is no variable -;;; size stuff on the nstack. -(define-vop (compute-old-nfp) - (:results (val :scs (any-reg))) - (:vop-var vop) - (:generator 1 - (let ((nfp (current-nfp-tn vop))) - (when nfp - (inst lda val (bytes-needed-for-non-descriptor-stack-frame) nfp))))) - -;;; Accessing a slot from an earlier stack frame is definite hackery. -(define-vop (ancestor-frame-ref) - (:args (frame-pointer :scs (descriptor-reg)) - (variable-home-tn :load-if nil)) - (:results (value :scs (descriptor-reg any-reg))) - (:policy :fast-safe) - (:generator 4 - (aver (sc-is variable-home-tn control-stack)) - (loadw value frame-pointer (tn-offset variable-home-tn)))) -(define-vop (ancestor-frame-set) - (:args (frame-pointer :scs (descriptor-reg)) - (value :scs (descriptor-reg any-reg))) - (:results (variable-home-tn :load-if nil)) - (:policy :fast-safe) - (:generator 4 - (aver (sc-is variable-home-tn control-stack)) - (storew value frame-pointer (tn-offset variable-home-tn)))) - -(define-vop (xep-allocate-frame) - (:info start-lab) - (:temporary (:scs (non-descriptor-reg)) temp) - (:generator 1 - ;; Make sure the function is aligned, and drop a label pointing to - ;; this function header. - (emit-alignment n-lowtag-bits) - (emit-label start-lab) - ;; Allocate function header. - (inst simple-fun-header-word) - (inst .skip (* (1- simple-fun-insts-offset) n-word-bytes)) - ;; The start of the actual code. - ;; Compute CODE from the address of this entry point. - (let ((entry-point (gen-label))) - (emit-label entry-point) - (inst compute-code-from-lip code-tn lip-tn entry-point temp) - ;; ### We should also save it on the stack so that the garbage - ;; collector won't forget about us if we call anyone else. - ))) - -(define-vop (xep-setup-sp) - (:vop-var vop) - (:generator 1 - (inst lda - csp-tn - (* n-word-bytes (sb-allocated-size 'control-stack)) - cfp-tn) - (let ((nfp (current-nfp-tn vop))) - (when nfp - (inst lda nsp-tn (- (bytes-needed-for-non-descriptor-stack-frame)) nsp-tn) - (move nsp-tn nfp))))) - -(define-vop (allocate-frame) - (:results (res :scs (any-reg)) - (nfp :scs (any-reg))) - (:info callee) - (:generator 2 - (move csp-tn res) - (inst lda - csp-tn - (* n-word-bytes (sb-allocated-size 'control-stack)) - csp-tn) - (when (ir2-physenv-number-stack-p callee) - (inst lda nsp-tn (- (bytes-needed-for-non-descriptor-stack-frame)) nsp-tn) - (move nsp-tn nfp)))) - -;;; Allocate a partial frame for passing stack arguments in a full -;;; call. NARGS is the number of arguments passed. If no stack -;;; arguments are passed, then we don't have to do anything. -(define-vop (allocate-full-call-frame) - (:info nargs) - (:results (res :scs (any-reg))) - (:generator 2 - (when (> nargs register-arg-count) - (move csp-tn res) - (inst lda csp-tn (* nargs n-word-bytes) csp-tn)))) - -;;; Emit code needed at the return-point from an unknown-values call -;;; for a fixed number of values. Values is the head of the TN-REF -;;; list for the locations that the values are to be received into. -;;; Nvals is the number of values that are to be received (should -;;; equal the length of Values). -;;; -;;; Move-Temp is a Descriptor-Reg TN used as a temporary. -;;; -;;; This code exploits the fact that in the unknown-values convention, -;;; a single value return returns at the return PC + 8, whereas a -;;; return of other than one value returns directly at the return PC. -;;; -;;; If 0 or 1 values are expected, then we just emit an instruction to -;;; reset the SP (which will only be executed when other than 1 value -;;; is returned.) -;;; -;;; In the general case, we have to do three things: -;;; -- Default unsupplied register values. This need only be done when a -;;; single value is returned, since register values are defaulted by the -;;; called in the non-single case. -;;; -- Default unsupplied stack values. This needs to be done whenever there -;;; are stack values. -;;; -- Reset SP. This must be done whenever other than 1 value is returned, -;;; regardless of the number of values desired. -;;; -;;; The general-case code looks like this: -#| - b regs-defaulted ; Skip if MVs - nop - - move a1 null-tn ; Default register values - ... - loadi nargs 1 ; Force defaulting of stack values - move ocfp csp ; Set up args for SP resetting - -regs-defaulted - subu temp nargs register-arg-count - - bltz temp default-value-7 ; jump to default code - addu temp temp -1 - loadw move-temp ocfp-tn 6 ; Move value to correct location. - store-stack-tn val4-tn move-temp - - bltz temp default-value-8 - addu temp temp -1 - loadw move-temp ocfp-tn 7 - store-stack-tn val5-tn move-temp - - ... - -defaulting-done - move sp ocfp ; Reset SP. -<end of code> - -<elsewhere> -default-value-7 - store-stack-tn val4-tn null-tn ; Nil out 7'th value. (first on stack) - -default-value-8 - store-stack-tn val5-tn null-tn ; Nil out 8'th value. - - ... - - br defaulting-done - nop -|# -(defun default-unknown-values (vop values nvals move-temp temp lra-label) - (declare (type (or tn-ref null) values) - (type unsigned-byte nvals) (type tn move-temp temp)) - (if (<= nvals 1) - (progn - ;; Note that this is a single-value return point. This is - ;; actually the multiple-value entry point for a single - ;; desired value, but the code location has to be here, or the - ;; debugger backtrace gets confused. - (without-scheduling () - (note-this-location vop :single-value-return) - (move ocfp-tn csp-tn) - (inst nop)) - (when lra-label - (inst compute-code-from-lra code-tn code-tn lra-label temp))) - (let ((regs-defaulted (gen-label)) - (defaulting-done (gen-label)) - (default-stack-vals (gen-label))) - (without-scheduling () - ;; Note that this is an unknown-values return point. - (note-this-location vop :unknown-return) - ;; If there are no stack results, clear the stack now. - (if (> nvals register-arg-count) - (inst subq nargs-tn (fixnumize register-arg-count) temp) - (move ocfp-tn csp-tn)) - ;; Branch off to the MV case. - (inst br zero-tn regs-defaulted)) - - ;; Do the single value case. - (do ((i 1 (1+ i)) - (val (tn-ref-across values) (tn-ref-across val))) - ((= i (min nvals register-arg-count))) - (move null-tn (tn-ref-tn val))) - (when (> nvals register-arg-count) - (move csp-tn ocfp-tn) - (inst br zero-tn default-stack-vals)) - - (emit-label regs-defaulted) - - (when (> nvals register-arg-count) - ;; If there are stack results, we have to default them - ;; and clear the stack. - (collect ((defaults)) - (do ((i register-arg-count (1+ i)) - (val (do ((i 0 (1+ i)) - (val values (tn-ref-across val))) - ((= i register-arg-count) val)) - (tn-ref-across val))) - ((null val)) - - (let ((default-lab (gen-label)) - (tn (tn-ref-tn val))) - (defaults (cons default-lab tn)) - - (inst ble temp default-lab) - (inst ldl move-temp (* i n-word-bytes) ocfp-tn) - (inst subq temp (fixnumize 1) temp) - (store-stack-tn tn move-temp))) - - (emit-label defaulting-done) - (move ocfp-tn csp-tn) - - (let ((defaults (defaults))) - (aver defaults) - (assemble (:elsewhere) - (emit-label default-stack-vals) - (do ((remaining defaults (cdr remaining))) - ((null remaining)) - (let ((def (car remaining))) - (emit-label (car def)) - (store-stack-tn (cdr def) null-tn))) - (inst br zero-tn defaulting-done))))) - - (when lra-label - (inst compute-code-from-lra code-tn code-tn lra-label temp)))) - (values)) - -;;;; unknown values receiving - -;;; Emit code needed at the return point for an unknown-values call -;;; for an arbitrary number of values. -;;; -;;; We do the single and non-single cases with no shared code: there -;;; doesn't seem to be any potential overlap, and receiving a single -;;; value is more important efficiency-wise. -;;; -;;; When there is a single value, we just push it on the stack, -;;; returning the old SP and 1. -;;; -;;; When there is a variable number of values, we move all of the -;;; argument registers onto the stack, and return Args and Nargs. -;;; -;;; Args and Nargs are TNs wired to the named locations. We must -;;; explicitly allocate these TNs, since their lifetimes overlap with -;;; the results Start and Count (also, it's nice to be able to target -;;; them). -(defun receive-unknown-values (args nargs start count lra-label temp) - (declare (type tn args nargs start count temp)) - (let ((variable-values (gen-label)) - (done (gen-label))) - (without-scheduling () - (inst br zero-tn variable-values) - (inst nop)) - - (when lra-label - (inst compute-code-from-lra code-tn code-tn lra-label temp)) - (inst addq csp-tn 4 csp-tn) - (storew (first *register-arg-tns*) csp-tn -1) - (inst subq csp-tn 4 start) - (inst li (fixnumize 1) count) - - (emit-label done) - - (assemble (:elsewhere) - (emit-label variable-values) - (when lra-label - (inst compute-code-from-lra code-tn code-tn lra-label temp)) - (do ((arg *register-arg-tns* (rest arg)) - (i 0 (1+ i))) - ((null arg)) - (storew (first arg) args i)) - (move args start) - (move nargs count) - (inst br zero-tn done))) - (values)) - -;;; a VOP that can be inherited by unknown values receivers. The main -;;; thing this handles is allocation of the result temporaries. -(define-vop (unknown-values-receiver) - (:results - (start :scs (any-reg)) - (count :scs (any-reg))) - (:temporary (:sc descriptor-reg :offset ocfp-offset - :from :eval :to (:result 0)) - values-start) - (:temporary (:sc any-reg :offset nargs-offset - :from :eval :to (:result 1)) - nvals) - (:temporary (:scs (non-descriptor-reg)) temp)) - -;;; This hook by the codegen lets us insert code before fall-thru entry points, -;;; local-call entry points, and tail-call entry points. The default does -;;; nothing. -(defun emit-block-header (start-label trampoline-label fall-thru-p alignp) - (declare (ignore fall-thru-p alignp)) - (when trampoline-label - (emit-label trampoline-label)) - (emit-label start-label)) - - -;;;; local call with unknown values convention return - -;;; Non-TR local call for a fixed number of values passed according to the -;;; unknown values convention. -;;; -;;; Args are the argument passing locations, which are specified only to -;;; terminate their lifetimes in the caller. -;;; -;;; Values are the return value locations (wired to the standard passing -;;; locations). -;;; -;;; Save is the save info, which we can ignore since saving has been -;;; done. Return-PC is the TN that the return PC should be passed in. -;;; Target is a continuation pointing to the start of the called -;;; function. Nvals is the number of values received. -;;; -;;; Note: we can't use normal load-tn allocation for the fixed args, -;;; since all registers may be tied up by the more operand. Instead, -;;; we use MAYBE-LOAD-STACK-TN. -(define-vop (call-local) - (:args (fp) - (nfp) - (args :more t)) - (:results (values :more t)) - (:save-p t) - (:move-args :local-call) - (:info arg-locs callee target nvals) - (:vop-var vop) - (:temporary (:scs (descriptor-reg) :from :eval) move-temp) - (:temporary (:scs (non-descriptor-reg)) temp) - (:temporary (:sc control-stack :offset nfp-save-offset) nfp-save) - (:temporary (:sc any-reg :offset ocfp-offset :from :eval) ocfp) - (:ignore arg-locs args ocfp) - (:generator 5 - (let ((label (gen-label)) - (cur-nfp (current-nfp-tn vop))) - (when cur-nfp - (store-stack-tn nfp-save cur-nfp)) - (let ((callee-nfp (callee-nfp-tn callee))) - (maybe-load-stack-nfp-tn callee-nfp nfp temp)) - (maybe-load-stack-tn cfp-tn fp) - (inst compute-lra-from-code - (callee-return-pc-tn callee) code-tn label temp) - (note-this-location vop :call-site) - (inst br zero-tn target) - (emit-return-pc label) - (default-unknown-values vop values nvals move-temp temp label) - (maybe-load-stack-nfp-tn cur-nfp nfp-save temp)))) - - -;;; Non-TR local call for a variable number of return values passed -;;; according to the unknown values convention. The results are the -;;; start of the values glob and the number of values received. -;;; -;;; Note: we can't use normal load-tn allocation for the fixed args, -;;; since all registers may be tied up by the more operand. Instead, -;;; we use MAYBE-LOAD-STACK-TN. -(define-vop (multiple-call-local unknown-values-receiver) - (:args (fp) - (nfp) - (args :more t)) - (:save-p t) - (:move-args :local-call) - (:info save callee target) - (:ignore args save) - (:vop-var vop) - (:temporary (:sc control-stack :offset nfp-save-offset) nfp-save) - (:temporary (:scs (non-descriptor-reg)) temp) - (:generator 20 - (let ((label (gen-label)) - (cur-nfp (current-nfp-tn vop))) - (when cur-nfp - (store-stack-tn nfp-save cur-nfp)) - (let ((callee-nfp (callee-nfp-tn callee))) - (maybe-load-stack-nfp-tn callee-nfp nfp temp)) - (maybe-load-stack-tn cfp-tn fp) - (inst compute-lra-from-code - (callee-return-pc-tn callee) code-tn label temp) - (note-this-location vop :call-site) - (inst bsr zero-tn target) - (emit-return-pc label) - (note-this-location vop :unknown-return) - (receive-unknown-values values-start nvals start count label temp) - (maybe-load-stack-nfp-tn cur-nfp nfp-save temp)))) - - -;;;; local call with known values return - -;;; Non-TR local call with known return locations. Known-value return -;;; works just like argument passing in local call. -;;; -;;; Note: we can't use normal load-tn allocation for the fixed args, since all -;;; registers may be tied up by the more operand. Instead, we use -;;; MAYBE-LOAD-STACK-TN. -(define-vop (known-call-local) - (:args (fp) - (nfp) - (args :more t)) - (:results (res :more t)) - (:move-args :local-call) - (:save-p t) - (:info save callee target) - (:ignore args res save) - (:vop-var vop) - (:temporary (:sc control-stack :offset nfp-save-offset) nfp-save) - (:temporary (:scs (non-descriptor-reg)) temp) - (:generator 5 - (let ((label (gen-label)) - (cur-nfp (current-nfp-tn vop))) - (when cur-nfp - (store-stack-tn nfp-save cur-nfp)) - (let ((callee-nfp (callee-nfp-tn callee))) - (maybe-load-stack-nfp-tn callee-nfp nfp temp)) - (maybe-load-stack-tn cfp-tn fp) - (inst compute-lra-from-code - (callee-return-pc-tn callee) code-tn label temp) - (note-this-location vop :call-site) - (inst bsr zero-tn target) - (emit-return-pc label) - (note-this-location vop :known-return) - (maybe-load-stack-nfp-tn cur-nfp nfp-save temp)))) - -;;; Return from known values call. We receive the return locations as -;;; arguments to terminate their lifetimes in the returning function. -;;; We restore FP and CSP and jump to the Return-PC. -;;; -;;; Note: we can't use normal load-tn allocation for the fixed args, -;;; since all registers may be tied up by the more operand. Instead, -;;; we use MAYBE-LOAD-STACK-TN. -(define-vop (known-return) - (:args (ocfp :target ocfp-temp) - (return-pc :target return-pc-temp) - (vals :more t)) - (:temporary (:sc any-reg :from (:argument 0)) ocfp-temp) - (:temporary (:sc any-reg :from (:argument 1)) - return-pc-temp) - (:temporary (:scs (interior-reg)) lip) - (:move-args :known-return) - (:info val-locs) - (:ignore val-locs vals) - (:vop-var vop) - (:generator 6 - (maybe-load-stack-tn ocfp-temp ocfp) - (maybe-load-stack-tn return-pc-temp return-pc) - (move cfp-tn csp-tn) - (let ((cur-nfp (current-nfp-tn vop))) - (when cur-nfp - (inst lda nsp-tn (bytes-needed-for-non-descriptor-stack-frame) - cur-nfp))) - (inst subq return-pc-temp (- other-pointer-lowtag n-word-bytes) lip) - (move ocfp-temp cfp-tn) - (inst ret zero-tn lip 1))) - -;;;; full call: -;;;; -;;;; There is something of a cross-product effect with full calls. -;;;; Different versions are used depending on whether we know the -;;;; number of arguments or the name of the called function, and -;;;; whether we want fixed values, unknown values, or a tail call. -;;;; -;;;; In full call, the arguments are passed creating a partial frame on -;;;; the stack top and storing stack arguments into that frame. On -;;;; entry to the callee, this partial frame is pointed to by FP. If -;;;; there are no stack arguments, we don't bother allocating a partial -;;;; frame, and instead set FP to SP just before the call. - -;;; This macro helps in the definition of full call VOPs by avoiding -;;; code replication in defining the cross-product VOPs. -;;; -;;; Name is the name of the VOP to define. -;;; -;;; Named is true if the first argument is a symbol whose global -;;; function definition is to be called. -;;; -;;; Return is either :FIXED, :UNKNOWN or :TAIL: -;;; -- If :FIXED, then the call is for a fixed number of values, returned -;;; in the standard passing locations (passed as result operands). -;;; -- If :UNKNOWN, then the result values are pushed on the stack, and -;;; the result values are specified by the Start and Count as in the -;;; unknown-values continuation representation. -;;; -- If :TAIL, then do a tail-recursive call. No values are returned. -;;; The Ocfp and Return-PC are passed as the second and third arguments. -;;; -;;; In non-tail calls, the pointer to the stack arguments is passed as -;;; the last fixed argument. If Variable is false, then the passing -;;; locations are passed as a more arg. Variable is true if there are -;;; a variable number of arguments passed on the stack. Variable -;;; cannot be specified with :TAIL return. TR variable argument call -;;; is implemented separately. -;;; -;;; In tail call with fixed arguments, the passing locations are -;;; passed as a more arg, but there is no new-FP, since the arguments -;;; have been set up in the current frame. -(defmacro define-full-call (name named return variable) - (aver (not (and variable (eq return :tail)))) - `(define-vop (,name - ,@(when (eq return :unknown) - '(unknown-values-receiver))) - (:args - ,@(unless (eq return :tail) - '((new-fp :scs (any-reg) :to :eval))) - ,@(case named - ((nil) - '((arg-fun :target lexenv))) - (:direct) - (t - '((name :target name-pass)))) - - ,@(when (eq return :tail) - '((ocfp :target ocfp-pass) - (return-pc :target return-pc-pass))) - - ,@(unless variable '((args :more t :scs (descriptor-reg))))) - - ,@(when (eq return :fixed) - '((:results (values :more t)))) - - (:save-p ,(if (eq return :tail) :compute-only t)) - - ,@(unless (or (eq return :tail) variable) - '((:move-args :full-call))) - - (:vop-var vop) - (:info ,@(unless (or variable (eq return :tail)) '(arg-locs)) - ,@(unless variable '(nargs)) - ,@(when (eq named :direct) '(fun)) - ,@(when (eq return :fixed) '(nvals)) - step-instrumenting) - - (:ignore #+gengc ,@(unless (eq return :tail) '(return-pc-pass)) - ,@(unless (or variable (eq return :tail)) '(arg-locs)) - ,@(unless variable '(args)) - ;; Step instrumentation for full calls not implemented yet. - ;; See the PPC backend for an example. - step-instrumenting) - - (:temporary (:sc descriptor-reg - :offset ocfp-offset - :from (:argument 1) - ,@(unless (eq return :fixed) - '(:to :eval))) - ocfp-pass) - - (:temporary (:sc descriptor-reg - :offset #-gengc lra-offset #+gengc ra-offset - :from (:argument ,(if (eq return :tail) 2 1)) - :to :eval) - return-pc-pass) - - ,@(case named - ((t) - `((:temporary (:sc descriptor-reg :offset fdefn-offset - :from (:argument ,(if (eq return :tail) 0 1)) - :to :eval) - name-pass))) - ((nil) - `((:temporary (:sc descriptor-reg :offset lexenv-offset - :from (:argument ,(if (eq return :tail) 0 1)) - :to :eval) - lexenv) - #-gengc - (:temporary (:scs (descriptor-reg) :from (:argument 0) :to :eval) - function)))) - - (:temporary (:sc any-reg :offset nargs-offset :to :eval) - nargs-pass) - - ,@(when variable - (mapcar (lambda (name offset) - `(:temporary (:sc descriptor-reg - :offset ,offset - :to :eval) - ,name)) - register-arg-names *register-arg-offsets*)) - ,@(when (eq return :fixed) - '((:temporary (:scs (descriptor-reg) :from :eval) move-temp))) - - ,@(unless (eq return :tail) - '((:temporary (:scs (non-descriptor-reg)) temp) - (:temporary (:sc control-stack :offset nfp-save-offset) nfp-save))) - - (:temporary (:sc interior-reg :offset lip-offset) entry-point) - - (:generator ,(+ (if named 5 0) - (if variable 19 1) - (if (eq return :tail) 0 10) - 15 - (if (eq return :unknown) 25 0)) - (let* ((cur-nfp (current-nfp-tn vop)) - ,@(unless (eq return :tail) - '((lra-label (gen-label)))) - (filler - (remove nil - (list :load-nargs - ,@(if (eq return :tail) - '((unless (location= ocfp ocfp-pass) - :load-ocfp) - (unless (location= return-pc - return-pc-pass) - :load-return-pc) - (when cur-nfp - :frob-nfp)) - '(#-gengc - :comp-lra - (when cur-nfp - :frob-nfp) - :save-fp - :load-fp)))))) - (flet ((do-next-filler () - (let* ((next (pop filler)) - (what (if (consp next) (car next) next))) - (ecase what - (:load-nargs - ,@(if variable - `((inst subq csp-tn new-fp nargs-pass) - ,@(let ((index -1)) - (mapcar (lambda (name) - `(inst ldl ,name - ,(ash (incf index) - word-shift) - new-fp)) - register-arg-names))) - '((inst li (fixnumize nargs) nargs-pass)))) - ,@(if (eq return :tail) - '((:load-ocfp - (sc-case ocfp - (any-reg - (inst move ocfp ocfp-pass)) - (control-stack - (inst ldl ocfp-pass - (ash (tn-offset ocfp) - word-shift) - cfp-tn)))) - (:load-return-pc - (sc-case return-pc - (#-gengc descriptor-reg #+gengc any-reg - (inst move return-pc return-pc-pass)) - (control-stack - (inst ldl return-pc-pass - (ash (tn-offset return-pc) - word-shift) - cfp-tn)))) - (:frob-nfp - (inst lda nsp-tn - (bytes-needed-for-non-descriptor-stack-frame) - cur-nfp))) - `(#-gengc - (:comp-lra - (inst compute-lra-from-code - return-pc-pass code-tn lra-label temp)) - (:frob-nfp - (store-stack-tn nfp-save cur-nfp)) - (:save-fp - (inst move cfp-tn ocfp-pass)) - (:load-fp - ,(if variable - '(move new-fp cfp-tn) - '(if (> nargs register-arg-count) - (move new-fp cfp-tn) - (move csp-tn cfp-tn)))))) - ((nil)))))) - ,@(case named - ((t) - `((sc-case name - (descriptor-reg (move name name-pass)) - (control-stack - (inst ldl name-pass - (tn-byte-offset name) cfp-tn) - (do-next-filler)) - (constant - (inst ldl name-pass - (- (tn-byte-offset name) - other-pointer-lowtag) code-tn) - (do-next-filler))) - (inst ldl entry-point - (- (ash fdefn-raw-addr-slot word-shift) - other-pointer-lowtag) name-pass) - (do-next-filler))) - ((nil) - `((sc-case arg-fun - (descriptor-reg (move arg-fun lexenv)) - (control-stack - (inst ldl lexenv - (tn-byte-offset arg-fun) cfp-tn) - (do-next-filler)) - (constant - (inst ldl lexenv - (- (tn-byte-offset arg-fun) - other-pointer-lowtag) code-tn) - (do-next-filler))) - #-gengc - (inst ldl function - (- (ash closure-fun-slot word-shift) - fun-pointer-lowtag) lexenv) - #-gengc - (do-next-filler) - #-gengc - (inst addq function - (- (ash simple-fun-insts-offset word-shift) - fun-pointer-lowtag) entry-point) - #+gengc - (inst ldl entry-point - (- (ash closure-entry-point-slot word-shift) - fun-pointer-lowtag) lexenv) - #+gengc - (do-next-filler))) - (:direct - `((inst ldl entry-point (static-fun-offset fun) null-tn)))) - (loop - (if (cdr filler) - (do-next-filler) - (return))) - - (note-this-location vop :call-site) - (do-next-filler) - (inst jsr zero-tn entry-point)) - - ,@(ecase return - (:fixed - '((emit-return-pc lra-label) - (default-unknown-values vop values nvals - move-temp temp lra-label) - (maybe-load-stack-nfp-tn cur-nfp nfp-save temp))) - (:unknown - '((emit-return-pc lra-label) - (note-this-location vop :unknown-return) - (receive-unknown-values values-start nvals start count - lra-label temp) - (maybe-load-stack-nfp-tn cur-nfp nfp-save temp))) - (:tail)))))) - -(define-full-call call nil :fixed nil) -(define-full-call call-named t :fixed nil) -(define-full-call static-call-named :direct :fixed nil) -(define-full-call multiple-call nil :unknown nil) -(define-full-call multiple-call-named t :unknown nil) -(define-full-call static-multiple-call-named :direct :unknown nil) -(define-full-call tail-call nil :tail nil) -(define-full-call tail-call-named t :tail nil) -(define-full-call static-tail-call-named :direct :tail nil) - -(define-full-call call-variable nil :fixed t) -(define-full-call multiple-call-variable nil :unknown t) - -;;; This is defined separately, since it needs special code that blits -;;; the arguments down. -(define-vop (tail-call-variable) - (:args - (args-arg :scs (any-reg) :target args) - (function-arg :scs (descriptor-reg) :target lexenv) - (ocfp-arg :scs (any-reg) :target ocfp) - (lra-arg :scs (#-gengc descriptor-reg #+gengc any-reg) :target lra)) - - (:temporary (:sc any-reg :offset nl0-offset :from (:argument 0)) args) - (:temporary (:sc any-reg :offset lexenv-offset :from (:argument 1)) lexenv) - (:temporary (:sc any-reg :offset ocfp-offset :from (:argument 2)) ocfp) - (:temporary (:sc any-reg :offset #-gengc lra-offset #+gengc ra-offset - :from (:argument 3)) lra) - (:temporary (:scs (non-descriptor-reg)) temp) - - (:vop-var vop) - - (:generator 75 - - ;; Move these into the passing locations if they are not already there. - (move args-arg args) - (move function-arg lexenv) - (move ocfp-arg ocfp) - (move lra-arg lra) - - ;; Clear the number stack if anything is there. - (let ((cur-nfp (current-nfp-tn vop))) - (when cur-nfp - (inst lda nsp-tn (bytes-needed-for-non-descriptor-stack-frame) - cur-nfp))) - - ;; And jump to the assembly-routine that does the bliting. - (inst li (make-fixup 'tail-call-variable :assembly-routine) temp) - (inst jmp zero-tn temp))) - -;;;; unknown values return - -;;; Return a single value using the unknown-values convention. -(define-vop (return-single) - (:args (ocfp :scs (any-reg)) - #-gengc (return-pc :scs (descriptor-reg)) - #+gengc (return-pc :scs (any-reg) :target ra) - (value)) - (:ignore value) - #-gengc (:temporary (:scs (interior-reg)) lip) - #+gengc (:temporary (:sc any-reg :offset ra-offset :from (:argument 1)) ra) - #+gengc (:temporary (:scs (any-reg) :from (:argument 1)) temp) - (:vop-var vop) - (:generator 6 - ;; Clear the number stack. - (let ((cur-nfp (current-nfp-tn vop))) - (when cur-nfp - (inst lda nsp-tn (bytes-needed-for-non-descriptor-stack-frame) - cur-nfp))) - ;; Clear the control stack, and restore the frame pointer. - (move cfp-tn csp-tn) - (move ocfp cfp-tn) - ;; Out of here. - #-gengc (lisp-return return-pc lip :offset 2) - #+gengc - (progn - (inst addq return-pc (* 2 n-word-bytes) temp) - (unless (location= ra return-pc) - (inst move ra return-pc)) - (inst ret zero-tn temp 1)))) - -;;; Do unknown-values return of a fixed number of values. The Values -;;; are required to be set up in the standard passing locations. Nvals -;;; is the number of values returned. -;;; -;;; If returning a single value, then deallocate the current frame, -;;; restore FP and jump to the single-value entry at Return-PC + 8. -;;; -;;; If returning other than one value, then load the number of values -;;; returned, NIL out unsupplied values registers, restore FP and -;;; return at Return-PC. When there are stack values, we must -;;; initialize the argument pointer to point to the beginning of the -;;; values block (which is the beginning of the current frame.) -(define-vop (return) - (:args (ocfp :scs (any-reg)) - (return-pc :scs (#-gengc descriptor-reg #+gengc any-reg) - :to (:eval 1) - #+gengc :target #+gengc ra) - (values :more t)) - (:ignore values) - (:info nvals) - (:temporary (:sc descriptor-reg :offset a0-offset :from (:eval 0)) a0) - (:temporary (:sc descriptor-reg :offset a1-offset :from (:eval 0)) a1) - (:temporary (:sc descriptor-reg :offset a2-offset :from (:eval 0)) a2) - (:temporary (:sc descriptor-reg :offset a3-offset :from (:eval 0)) a3) - (:temporary (:sc descriptor-reg :offset a4-offset :from (:eval 0)) a4) - (:temporary (:sc descriptor-reg :offset a5-offset :from (:eval 0)) a5) - (:temporary (:sc any-reg :offset nargs-offset) nargs) - (:temporary (:sc any-reg :offset ocfp-offset) val-ptr) - #-gengc (:temporary (:scs (interior-reg)) lip) - #+gengc (:temporary (:sc any-reg :offset ra-offset :from (:eval 1)) ra) - (:vop-var vop) - (:generator 6 - ;; Clear the number stack. - (let ((cur-nfp (current-nfp-tn vop))) - (when cur-nfp - (inst lda nsp-tn (bytes-needed-for-non-descriptor-stack-frame) - cur-nfp))) - ;; Establish the values pointer and values count. - (move cfp-tn val-ptr) - (inst li (fixnumize nvals) nargs) - ;; restore the frame pointer and clear as much of the control - ;; stack as possible. - (move ocfp cfp-tn) - ;; ADDQ only accepts immediates of type (UNSIGNED-BYTE 8). Here, - ;; instead of adding (* NVALS N-WORD-BYTES), we use NARGS that - ;; we've carefully set up, but protect ourselves by averring that - ;; FIXNUMIZEation and multiplication by N-WORD-BYTES is the same. - (aver (= (* nvals n-word-bytes) (fixnumize nvals))) - (inst addq val-ptr nargs csp-tn) - ;; pre-default any argument register that need it. - (when (< nvals register-arg-count) - (dolist (reg (subseq (list a0 a1 a2 a3 a4 a5) nvals)) - (move null-tn reg))) - ;; And away we go. - (lisp-return return-pc lip))) - -;;; Do unknown-values return of an arbitrary number of values (passed -;;; on the stack.) We check for the common case of a single return -;;; value, and do that inline using the normal single value return -;;; convention. Otherwise, we branch off to code that calls an -;;; assembly-routine. -(define-vop (return-multiple) - (:args (ocfp-arg :scs (any-reg) :target ocfp) - #-gengc (lra-arg :scs (descriptor-reg) :target lra) - #+gengc (return-pc :scs (any-reg) :target ra) - (vals-arg :scs (any-reg) :target vals) - (nvals-arg :scs (any-reg) :target nvals)) - - (:temporary (:sc any-reg :offset nl1-offset :from (:argument 0)) ocfp) - #-gengc - (:temporary (:sc descriptor-reg :offset lra-offset :from (:argument 1)) lra) - #+gengc - (:temporary (:sc any-reg :offset ra-offset :from (:argument 1)) ra) - (:temporary (:sc any-reg :offset nl0-offset :from (:argument 2)) vals) - (:temporary (:sc any-reg :offset nargs-offset :from (:argument 3)) nvals) - (:temporary (:sc descriptor-reg :offset a0-offset) a0) - (:temporary (:scs (non-descriptor-reg)) temp) - #-gengc (:temporary (:scs (interior-reg)) lip) - #+gengc (:temporary (:scs (any-reg) :from (:argument 0)) temp) - - (:vop-var vop) - - (:generator 13 - (let ((not-single (gen-label))) - ;; Clear the number stack. - (let ((cur-nfp (current-nfp-tn vop))) - (when cur-nfp - (inst lda nsp-tn (bytes-needed-for-non-descriptor-stack-frame) - cur-nfp))) - - ;; Check for the single case. - (inst li (fixnumize 1) a0) - (inst cmpeq nvals-arg a0 temp) - (inst ldl a0 0 vals-arg) - (inst beq temp not-single) - - ;; Return with one value. - (move cfp-tn csp-tn) - (move ocfp-arg cfp-tn) - (lisp-return lra-arg lip :offset 2) - - ;; Nope, not the single case. - (emit-label not-single) - (move ocfp-arg ocfp) - (move lra-arg lra) - (move vals-arg vals) - (move nvals-arg nvals) - (inst li (make-fixup 'return-multiple :assembly-routine) temp) - (inst jmp zero-tn temp)))) - -;;;; XEP hackery - -;;; Get the lexical environment from its passing location. -(define-vop (setup-closure-environment) - (:temporary (:sc descriptor-reg :offset lexenv-offset :target closure - :to (:result 0)) - lexenv) - (:results (closure :scs (descriptor-reg))) - (:info label) - (:ignore label) - (:generator 6 - ;; Get result. - (move lexenv closure))) - -;;; Copy a &MORE arg from the argument area to the end of the current -;;; frame. FIXED is the number of non-&MORE arguments. -(define-vop (copy-more-arg) - (:temporary (:sc any-reg :offset nl0-offset) result) - (:temporary (:sc any-reg :offset nl1-offset) count) - (:temporary (:sc any-reg :offset nl2-offset) src) - (:temporary (:sc any-reg :offset nl4-offset) dst) - (:temporary (:sc descriptor-reg :offset l0-offset) temp) - (:info fixed) - (:generator 20 - (let ((loop (gen-label)) - (do-regs (gen-label)) - (done (gen-label))) - (when (< fixed register-arg-count) - ;; Save a pointer to the results so we can fill in register - ;; args. We don't need this if there are more fixed args than - ;; reg args. - (move csp-tn result)) - ;; Allocate the space on the stack. - (cond ((zerop fixed) - (inst addq csp-tn nargs-tn csp-tn) - (inst beq nargs-tn done)) - (t - (inst subq nargs-tn (fixnumize fixed) count) - (inst ble count done) - (inst addq csp-tn count csp-tn))) - (when (< fixed register-arg-count) - ;; We must stop when we run out of stack args, not when we run - ;; out of &MORE args. - (inst subq nargs-tn (fixnumize register-arg-count) count)) - ;; Initialize dst to be end of stack. - (move csp-tn dst) - ;; Everything of interest in registers. - (inst ble count do-regs) - ;; Initialize SRC to be end of args. - (inst addq cfp-tn nargs-tn src) - - (emit-label loop) - ;; *--dst = *--src, --count - (inst subq src n-word-bytes src) - (inst subq count (fixnumize 1) count) - (loadw temp src) - (inst subq dst n-word-bytes dst) - (storew temp dst) - (inst bgt count loop) - - (emit-label do-regs) - (when (< fixed register-arg-count) - ;; Now we have to deposit any more args that showed up in - ;; registers. We know there is at least one &MORE arg, - ;; otherwise we would have branched to DONE up at the top. - (inst subq nargs-tn (fixnumize (1+ fixed)) count) - (do ((i fixed (1+ i))) - ((>= i register-arg-count)) - ;; Store it relative to the pointer saved at the start. - (storew (nth i *register-arg-tns*) result (- i fixed)) - ;; Is this the last one? - (inst beq count done) - ;; Decrement count. - (inst subq count (fixnumize 1) count))) - (emit-label done)))) - -;;; &MORE args are stored consecutively on the stack, starting -;;; immediately at the context pointer. The context pointer is not -;;; typed, so the lowtag is 0. - -(define-vop (more-arg) - (:translate %more-arg) - (:policy :fast-safe) - (:args (context :scs (descriptor-reg)) (index :scs (any-reg))) - (:arg-types * tagged-num) - (:temporary (:scs (any-reg)) temp) - (:results (value :scs (descriptor-reg any-reg))) - (:result-types *) - (:generator 5 - (inst addq context index temp) - (inst ldl value 0 temp))) -(define-vop (more-arg-c) - (:translate %more-arg) - (:policy :fast-safe) - (:args (context :scs (descriptor-reg))) - (:info index) - (:arg-types * (:constant (load/store-index 8 0 0))) - (:results (value :scs (descriptor-reg any-reg))) - (:result-types *) - (:generator 4 - (inst ldl value (* index n-word-bytes) context))) - -;;; Turn &MORE arg (context, count) into a list. -(define-vop () - (:args (context-arg :target context :scs (descriptor-reg)) - (count-arg :target count :scs (any-reg))) - (:arg-types * tagged-num) - (:temporary (:scs (any-reg) :from (:argument 0)) context) - (:temporary (:scs (any-reg) :from (:argument 1)) count) - (:temporary (:scs (descriptor-reg) :from :eval) temp dst) - (:results (result :scs (descriptor-reg))) - (:translate %listify-rest-args) - (:policy :safe) - (:node-var node) - (:generator 20 - (let* ((enter (gen-label)) - (loop (gen-label)) - (done (gen-label)) - (dx-p (node-stack-allocate-p node)) - (alloc-area-tn (if dx-p csp-tn alloc-tn))) - (move context-arg context) - (move count-arg count) - ;; Check to see if there are any arguments. - (move null-tn result) - (inst beq count done) - - ;; We need to do this atomically. - (pseudo-atomic () - ;; align CSP - (when dx-p (align-csp temp)) - ;; Allocate a cons (2 words) for each item. - (inst bis alloc-area-tn list-pointer-lowtag result) - (move result dst) - (inst sll count 1 temp) - (inst addq alloc-area-tn temp alloc-area-tn) - (inst br zero-tn enter) - - ;; Store the current cons in the cdr of the previous cons. - (emit-label loop) - (inst addq dst (* 2 n-word-bytes) dst) - (storew dst dst -1 list-pointer-lowtag) - - (emit-label enter) - ;; Grab one value. - (loadw temp context) - (inst addq context n-word-bytes context) - - ;; Store the value in the car (in delay slot) - (storew temp dst 0 list-pointer-lowtag) - - ;; Decrement count, and if != zero, go back for more. - (inst subq count (fixnumize 1) count) - (inst bne count loop) - - ;; NIL out the last cons. - (storew null-tn dst 1 list-pointer-lowtag)) - (emit-label done)))) - -;;; Return the location and size of the &MORE arg glob created by -;;; COPY-MORE-ARG. Supplied is the total number of arguments supplied -;;; (originally passed in NARGS.) Fixed is the number of non-&rest -;;; arguments. -;;; -;;; We must duplicate some of the work done by COPY-MORE-ARG, since at -;;; that time the environment is in a pretty brain-damaged state, -;;; preventing this info from being returned as values. What we do is -;;; compute supplied - fixed, and return a pointer that many words -;;; below the current stack top. -(define-vop () - (:policy :fast-safe) - (:translate sb-c::%more-arg-context) - (:args (supplied :scs (any-reg))) - (:arg-types tagged-num (:constant fixnum)) - (:info fixed) - (:results (context :scs (descriptor-reg)) - (count :scs (any-reg))) - (:result-types t tagged-num) - (:note "more-arg-context") - (:generator 5 - (inst subq supplied (fixnumize fixed) count) - (inst subq csp-tn count context))) - -(define-vop (verify-arg-count) - (:policy :fast-safe) - (:args (nargs :scs (any-reg))) - (:arg-types positive-fixnum (:constant t) (:constant t)) - (:info min max) - (:temporary (:scs (unsigned-reg)) temp) - (:vop-var vop) - (:save-p :compute-only) - (:generator 3 - (let ((err-lab - (generate-error-code vop 'invalid-arg-count-error nargs))) - (cond ((not min) - (cond ((zerop max) - (inst bne nargs err-lab)) - (t - (inst subq nargs (fixnumize max) temp) - (inst bne temp err-lab)))) - (max - (when (plusp min) - (inst li (fixnumize min) temp) - (inst cmpult nargs temp temp) - (inst bne temp err-lab)) - (inst li (fixnumize max) temp) - (inst cmpult temp nargs temp) - (inst bne temp err-lab)) - ((plusp min) - (inst li (fixnumize min) temp) - (inst cmpult nargs temp temp) - (inst bne temp err-lab)))))) - -;;; Single-stepping -(define-vop (step-instrument-before-vop) - (:policy :fast-safe) - (:vop-var vop) - (:generator 3 - ;; Stub! See the PPC backend for an example. - (note-this-location vop :internal-error))) diff --git a/src/compiler/alpha/cell.lisp b/src/compiler/alpha/cell.lisp deleted file mode 100644 index 998aa7c8bf..0000000000 --- a/src/compiler/alpha/cell.lisp +++ /dev/null @@ -1,632 +0,0 @@ -;;;; the VM definition of various primitive memory access VOPs for the -;;;; Alpha - -;;;; This software is part of the SBCL system. See the README file for -;;;; more information. -;;;; -;;;; This software is derived from the CMU CL system, which was -;;;; written at Carnegie Mellon University and released into the -;;;; public domain. The software is in the public domain and is -;;;; provided with absolutely no warranty. See the COPYING and CREDITS -;;;; files for more information. - -(in-package "SB-VM") - -;;;; data object ref/set stuff - -(define-vop (slot) - (:args (object :scs (descriptor-reg))) - (:info name offset lowtag) - (:ignore name) - (:results (result :scs (descriptor-reg any-reg))) - (:generator 1 - (loadw result object offset lowtag))) - -(define-vop (set-slot) - (:args (object :scs (descriptor-reg)) - (value :scs (descriptor-reg any-reg null zero))) - (:info name offset lowtag #+gengc remember) - (:ignore name) - (:results) - (:generator 1 - #+gengc - (if remember - (storew-and-remember-slot value object offset lowtag) - (storew value object offset lowtag)) - #-gengc - (storew value object offset lowtag))) - -(define-vop (init-slot set-slot) - (:info name dx-p offset lowtag) - (:ignore name dx-p)) - -;;;; symbol hacking VOPs - -;;; The compiler likes to be able to directly SET symbols. -(define-vop (set cell-set) - (:variant symbol-value-slot other-pointer-lowtag)) - -;;; Do a cell ref with an error check for being unbound. -(define-vop (checked-cell-ref) - (:args (object :scs (descriptor-reg) :target obj-temp)) - (:results (value :scs (descriptor-reg any-reg))) - (:policy :fast-safe) - (:vop-var vop) - (:save-p :compute-only) - (:temporary (:scs (non-descriptor-reg)) temp) - (:temporary (:scs (descriptor-reg) :from (:argument 0)) obj-temp)) - -;;; With SYMBOL-VALUE, we check that the value isn't the trap object. -;;; So SYMBOL-VALUE of NIL is NIL. -(define-vop (symbol-value checked-cell-ref) - (:translate symeval) - (:generator 9 - (move object obj-temp) - (loadw value obj-temp symbol-value-slot other-pointer-lowtag) - (let ((err-lab (generate-error-code vop 'unbound-symbol-error obj-temp))) - (inst xor value unbound-marker-widetag temp) - (inst beq temp err-lab)))) - -;;; like CHECKED-CELL-REF, only we are a predicate to see if the cell -;;; is bound -(define-vop (boundp-frob) - (:args (object :scs (descriptor-reg))) - (:conditional) - (:info target not-p) - (:policy :fast-safe) - (:temporary (:scs (descriptor-reg)) value) - (:temporary (:scs (non-descriptor-reg)) temp)) - -(define-vop (boundp boundp-frob) - (:translate boundp) - (:generator 9 - (loadw value object symbol-value-slot other-pointer-lowtag) - (inst xor value unbound-marker-widetag temp) - (if not-p - (inst beq temp target) - (inst bne temp target)))) - -(define-vop (fast-symbol-value cell-ref) - (:variant symbol-value-slot other-pointer-lowtag) - (:policy :fast) - (:translate symeval)) - -(define-vop (symbol-hash) - (:policy :fast-safe) - (:translate symbol-hash) - (:args (symbol :scs (descriptor-reg))) - (:results (res :scs (any-reg))) - (:result-types positive-fixnum) - (:generator 2 - ;; The symbol-hash slot of NIL holds NIL because it is also the - ;; cdr slot, so we have to strip off the two low bits to make sure - ;; it is a fixnum. The lowtag selection magic that is required to - ;; ensure this is explained in the comment in objdef.lisp - (loadw res symbol symbol-hash-slot other-pointer-lowtag) - (inst bic res #.(ash lowtag-mask -1) res))) - -;;; On unithreaded builds these are just copies of the non-global versions. -(define-vop (%set-symbol-global-value set)) -(define-vop (symbol-global-value symbol-value) - (:translate sym-global-val)) -(define-vop (fast-symbol-global-value fast-symbol-value) - (:translate sym-global-val)) - -;;;; fdefinition (FDEFN) objects - -(define-vop (fdefn-fun cell-ref) - (:variant fdefn-fun-slot other-pointer-lowtag)) - -(define-vop (safe-fdefn-fun) - (:translate safe-fdefn-fun) - (:policy :fast-safe) - (:args (object :scs (descriptor-reg) :target obj-temp)) - (:results (value :scs (descriptor-reg any-reg))) - (:vop-var vop) - (:save-p :compute-only) - (:temporary (:scs (descriptor-reg) :from (:argument 0)) obj-temp) - (:temporary (:scs (non-descriptor-reg)) temp) - (:generator 10 - (move object obj-temp) - (loadw value obj-temp fdefn-fun-slot other-pointer-lowtag) - (let ((err-lab (generate-error-code vop 'undefined-fun-error obj-temp))) - (inst cmpeq value null-tn temp) - (inst bne temp err-lab)))) - -(define-vop (set-fdefn-fun) - (:policy :fast-safe) - (:translate (setf fdefn-fun)) - (:args (function :scs (descriptor-reg) :target result) - (fdefn :scs (descriptor-reg))) - (:temporary (:scs (interior-reg)) lip) - (:temporary (:scs (non-descriptor-reg)) type) - (:results (result :scs (descriptor-reg))) - (:generator 38 - (let ((normal-fn (gen-label))) - (load-type type function (- fun-pointer-lowtag)) - (inst xor type simple-fun-widetag type) - (inst addq function - (- (ash simple-fun-insts-offset word-shift) fun-pointer-lowtag) - lip) - (inst beq type normal-fn) - (inst li (make-fixup 'closure-tramp :assembly-routine) lip) - (emit-label normal-fn) - (storew lip fdefn fdefn-raw-addr-slot other-pointer-lowtag) - (storew function fdefn fdefn-fun-slot other-pointer-lowtag) - (move function result)))) - - -(define-vop (fdefn-makunbound) - (:policy :fast-safe) - (:translate fdefn-makunbound) - (:args (fdefn :scs (descriptor-reg) :target result)) - (:temporary (:scs (non-descriptor-reg)) temp) - (:results (result :scs (descriptor-reg))) - (:generator 38 - (storew null-tn fdefn fdefn-fun-slot other-pointer-lowtag) - (inst li (make-fixup 'undefined-tramp :assembly-routine) temp) - (move fdefn result) - (storew temp fdefn fdefn-raw-addr-slot other-pointer-lowtag))) - -;;;; binding and Unbinding - -;;; Establish VAL as a binding for SYMBOL. Save the old value and the -;;; symbol on the binding stack and stuff the new value into the symbol. -;;; -;;; See the "Chapter 9: Specials" of the SBCL Internals Manual. - -(define-vop (dynbind) - (:args (val :scs (any-reg descriptor-reg)) - (symbol :scs (descriptor-reg))) - (:temporary (:scs (descriptor-reg)) temp) - (:generator 5 - (loadw temp symbol symbol-value-slot other-pointer-lowtag) - (inst addq bsp-tn (* 2 n-word-bytes) bsp-tn) - (storew temp bsp-tn (- binding-value-slot binding-size)) - (storew symbol bsp-tn (- binding-symbol-slot binding-size)) - (#+gengc storew-and-remember-slot #-gengc storew - val symbol symbol-value-slot other-pointer-lowtag))) - - -(define-vop (unbind) - (:temporary (:scs (descriptor-reg)) symbol value) - (:generator 0 - (loadw symbol bsp-tn (- binding-symbol-slot binding-size)) - (loadw value bsp-tn (- binding-value-slot binding-size)) - (#+gengc storew-and-remember-slot #-gengc storew - value symbol symbol-value-slot other-pointer-lowtag) - (storew zero-tn bsp-tn (- binding-symbol-slot binding-size)) - (storew zero-tn bsp-tn (- binding-value-slot binding-size)) - (inst subq bsp-tn (* 2 n-word-bytes) bsp-tn))) - - -(define-vop (unbind-to-here) - (:args (arg :scs (descriptor-reg any-reg) :target where)) - (:temporary (:scs (any-reg) :from (:argument 0)) where) - (:temporary (:scs (descriptor-reg)) symbol value) - (:temporary (:scs (non-descriptor-reg)) temp) - (:generator 0 - (let ((loop (gen-label)) - (skip (gen-label)) - (done (gen-label))) - (move arg where) - (inst cmpeq where bsp-tn temp) - (inst bne temp done) - - (emit-label loop) - (loadw symbol bsp-tn (- binding-symbol-slot binding-size)) - (loadw value bsp-tn (- binding-value-slot binding-size)) - (inst beq symbol skip) - (#+gengc storew-and-remember-slot #-gengc storew - value symbol symbol-value-slot other-pointer-lowtag) - (storew zero-tn bsp-tn (- binding-symbol-slot binding-size)) - - (emit-label skip) - (storew zero-tn bsp-tn (- binding-value-slot binding-size)) - (inst subq bsp-tn (* 2 n-word-bytes) bsp-tn) - (inst cmpeq where bsp-tn temp) - (inst beq temp loop) - - (emit-label done)))) - -;;;; closure indexing - -(define-full-reffer closure-index-ref * - closure-info-offset fun-pointer-lowtag - (descriptor-reg any-reg) * %closure-index-ref) - -(define-full-setter set-funcallable-instance-info * - funcallable-instance-info-offset fun-pointer-lowtag - (descriptor-reg any-reg null zero) * %set-funcallable-instance-info) - -(define-full-reffer funcallable-instance-info * - funcallable-instance-info-offset fun-pointer-lowtag - (descriptor-reg any-reg) * %funcallable-instance-info) - -(define-vop (closure-ref) - (:args (object :scs (descriptor-reg))) - (:results (value :scs (descriptor-reg any-reg))) - (:info offset) - (:generator 4 - (loadw value object (+ closure-info-offset offset) fun-pointer-lowtag))) - -(define-vop (closure-init) - (:args (object :scs (descriptor-reg)) - (value :scs (descriptor-reg any-reg))) - (:info offset) - (:generator 4 - (storew value object (+ closure-info-offset offset) fun-pointer-lowtag))) - -(define-vop (closure-init-from-fp) - (:args (object :scs (descriptor-reg))) - (:info offset) - (:generator 4 - (storew cfp-tn object (+ closure-info-offset offset) fun-pointer-lowtag))) - -;;;; value cell hackery - -(define-vop (value-cell-ref cell-ref) - (:variant value-cell-value-slot other-pointer-lowtag)) - -(define-vop (value-cell-set cell-set) - (:variant value-cell-value-slot other-pointer-lowtag)) - -;;;; instance hackery - -(define-vop () - (:policy :fast-safe) - (:translate %instance-length) - (:args (struct :scs (descriptor-reg))) - (:results (res :scs (unsigned-reg))) - (:result-types positive-fixnum) - (:generator 4 - (loadw res struct 0 instance-pointer-lowtag) - (inst srl res instance-length-shift res))) - -(define-full-reffer instance-index-ref * instance-slots-offset - instance-pointer-lowtag (descriptor-reg any-reg) * %instance-ref) - -(define-full-setter instance-index-set * instance-slots-offset - instance-pointer-lowtag (descriptor-reg any-reg null zero) * %instance-set) - -;;;; code object frobbing - -(define-full-reffer code-header-ref * 0 other-pointer-lowtag - (descriptor-reg any-reg) * code-header-ref) - -(define-full-setter code-header-set * 0 other-pointer-lowtag - (descriptor-reg any-reg null zero) * code-header-set) - -;;;; mutator accessing - -#+gengc -(progn - -(eval-when (:compile-toplevel :load-toplevel :execute) - ;; SBCL has never had GENGC. Now that we have Alpha support, it - ;; would probably be nice to restore GENGC support so that the Alpha - ;; doesn't have to crawl along with stop'n'copy. When we do, the CMU - ;; CL code below will need updating to the SBCL way of looking at - ;; things, e.g. at least using "SB-KERNEL" or "SB-KERNEL" instead of - ;; :KERNEL. -- WHN 2001-05-08 - (error "This code is stale as of sbcl-0.6.12.")) - -(define-vop (mutator-ub32-ref) - (:policy :fast-safe) - (:args) - (:results (res :scs (unsigned-reg))) - (:result-types unsigned-num) - (:variant-vars slot) - (:generator 2 - (loadw res mutator-tn slot))) - -(define-vop (mutator-descriptor-ref mutator-ub32-ref) - (:results (res :scs (any-reg descriptor-reg))) - (:result-types *)) - -(define-vop (mutator-sap-ref mutator-ub32-ref) - (:results (res :scs (sap-reg))) - (:result-types system-area-pointer)) - - -(define-vop (mutator-ub32-set) - (:policy :fast-safe) - (:args (arg :scs (unsigned-reg) :target res)) - (:arg-types unsigned-num) - (:results (res :scs (unsigned-reg))) - (:result-types unsigned-num) - (:variant-vars slot) - (:generator 2 - (storew arg mutator-tn slot) - (move res arg))) - -(define-vop (mutator-descriptor-set mutator-ub32-set) - (:args (arg :scs (any-reg descriptor-reg null zero) :target res)) - (:arg-types *) - (:results (res :scs (any-reg descriptor-reg))) - (:result-types *)) - -(define-vop (mutator-sap-set mutator-ub32-set) - (:args (arg :scs (sap-reg) :target res)) - (:arg-types system-area-pointer) - (:results (res :scs (sap-reg))) - (:result-types system-area-pointer)) - - -(macrolet ((define-mutator-accessors (slot type writable) - (let ((ref (symbolicate "MUTATOR-" slot "-REF")) - (set (and writable (symbolicate "MUTATOR-" slot "-SET"))) - (offset (symbolicate "MUTATOR-" slot "-SLOT")) - (fn - (let ((*package* (find-package :kernel))) - (symbolicate "MUTATOR-" slot)))) - (multiple-value-bind - (lisp-type ref-vop set-vop) - (ecase type - (:des - (values t - 'mutator-descriptor-ref - 'mutator-descriptor-set)) - (:ub32 - (values '(unsigned-byte 32) - 'mutator-ub32-ref - 'mutator-ub32-set)) - (:sap - (values 'system-area-pointer - 'mutator-sap-ref - 'mutator-sap-set))) - `(progn - (export ',fn :kernel) - (defknown ,fn () ,lisp-type (flushable)) - (define-vop (,ref ,ref-vop) - (:translate ,fn) - (:variant ,offset)) - ,@(when writable - `((defknown ((setf ,fn)) (,lisp-type) ,lisp-type - ()) - (define-vop (,set ,set-vop) - (:translate (setf ,fn)) - (:variant ,offset))))))))) - (define-mutator-accessors thread :des t) - (define-mutator-accessors suspends-disabled-count :ub32 t) - (define-mutator-accessors suspend-pending :ub32 t) - (define-mutator-accessors control-stack-base :sap nil) - (define-mutator-accessors control-stack-end :sap nil) - (define-mutator-accessors current-unwind-protect :sap nil) - (define-mutator-accessors current-catch-block :sap nil) - (define-mutator-accessors binding-stack-base :sap nil) - (define-mutator-accessors binding-stack-end :sap nil) - (define-mutator-accessors number-stack-base :sap nil) - (define-mutator-accessors number-stack-end :sap nil) - (define-mutator-accessors nursery-start :sap nil) - (define-mutator-accessors nursery-end :sap nil) - (define-mutator-accessors storebuf-start :sap nil) - (define-mutator-accessors storebuf-end :sap nil) - (define-mutator-accessors words-consed :ub32 nil)) - -); #+gengc progn - - - -;;;; raw instance slot accessors - -(macrolet ((def (signedp sc result-type) - `(progn - (define-vop () - (:translate ,(symbolicate "%RAW-INSTANCE-REF/" signedp "WORD")) - (:policy :fast-safe) - (:args (object :scs (descriptor-reg)) - (index :scs (any-reg))) - (:arg-types * positive-fixnum) - (:results (value :scs (,sc))) - (:temporary (:scs (interior-reg)) lip) - (:result-types ,result-type) - (:generator 5 - (inst addq object index lip) - (inst ldl - value - (- (* instance-slots-offset n-word-bytes) - instance-pointer-lowtag) - lip) - (inst mskll value 4 value))) - - (define-vop (raw-instance-set/word) - (:translate ,(symbolicate "%RAW-INSTANCE-SET/" signedp "WORD")) - (:policy :fast-safe) - (:args (object :scs (descriptor-reg)) - (index :scs (any-reg)) - (value :scs (,sc))) - (:arg-types * positive-fixnum ,result-type) - (:results (result :scs (,sc))) - (:temporary (:scs (interior-reg)) lip) - (:result-types ,result-type) - (:generator 5 - (inst addq object index lip) - (inst stl - value - (- (* instance-slots-offset n-word-bytes) - instance-pointer-lowtag) - lip) - (move value result)))))) - (def "" unsigned-reg unsigned-num) - (def "SIGNED-" signed-reg signed-num)) - -(define-vop (raw-instance-ref/single) - (:translate %raw-instance-ref/single) - (:policy :fast-safe) - (:args (object :scs (descriptor-reg)) - (index :scs (any-reg))) - (:arg-types * positive-fixnum) - (:results (value :scs (single-reg))) - (:temporary (:scs (interior-reg)) lip) - (:result-types single-float) - (:generator 5 - (inst addq object index lip) - (inst lds - value - (- (* instance-slots-offset n-word-bytes) - instance-pointer-lowtag) - lip))) - -(define-vop (raw-instance-set/single) - (:translate %raw-instance-set/single) - (:policy :fast-safe) - (:args (object :scs (descriptor-reg)) - (index :scs (any-reg)) - (value :scs (single-reg))) - (:arg-types * positive-fixnum single-float) - (:results (result :scs (single-reg))) - (:temporary (:scs (interior-reg)) lip) - (:result-types single-float) - (:generator 5 - (inst addq object index lip) - (inst sts - value - (- (* instance-slots-offset n-word-bytes) - instance-pointer-lowtag) - lip) - (unless (location= result value) - (inst fmove value result)))) - -(define-vop (raw-instance-ref/double) - (:translate %raw-instance-ref/double) - (:policy :fast-safe) - (:args (object :scs (descriptor-reg)) - (index :scs (any-reg))) - (:arg-types * positive-fixnum) - (:results (value :scs (double-reg))) - (:temporary (:scs (interior-reg)) lip) - (:result-types double-float) - (:generator 5 - (inst addq object index lip) - (inst ldt - value - (- (* instance-slots-offset n-word-bytes) - instance-pointer-lowtag) - lip))) - -(define-vop (raw-instance-set/double) - (:translate %raw-instance-set/double) - (:policy :fast-safe) - (:args (object :scs (descriptor-reg)) - (index :scs (any-reg)) - (value :scs (double-reg))) - (:arg-types * positive-fixnum double-float) - (:results (result :scs (double-reg))) - (:temporary (:scs (interior-reg)) lip) - (:result-types double-float) - (:generator 5 - (inst addq object index lip) - (inst stt - value - (- (* instance-slots-offset n-word-bytes) - instance-pointer-lowtag) - lip) - (unless (location= result value) - (inst fmove value result)))) - -(define-vop (raw-instance-ref/complex-single) - (:translate %raw-instance-ref/complex-single) - (:policy :fast-safe) - (:args (object :scs (descriptor-reg)) - (index :scs (any-reg))) - (:arg-types * positive-fixnum) - (:results (value :scs (complex-single-reg))) - (:temporary (:scs (interior-reg)) lip) - (:result-types complex-single-float) - (:generator 5 - (inst addq object index lip) - (inst lds - (complex-double-reg-real-tn value) - (- (* instance-slots-offset n-word-bytes) - instance-pointer-lowtag) - lip) - (inst lds - (complex-double-reg-imag-tn value) - (- (* (1+ instance-slots-offset) n-word-bytes) - instance-pointer-lowtag) - lip))) - -(define-vop (raw-instance-set/complex-single) - (:translate %raw-instance-set/complex-single) - (:policy :fast-safe) - (:args (object :scs (descriptor-reg)) - (index :scs (any-reg)) - (value :scs (complex-single-reg))) - (:arg-types * positive-fixnum complex-single-float) - (:results (result :scs (complex-single-reg))) - (:temporary (:scs (interior-reg)) lip) - (:result-types complex-single-float) - (:generator 5 - (inst addq object index lip) - (let ((value-real (complex-single-reg-real-tn value)) - (result-real (complex-single-reg-real-tn result))) - (inst sts - value-real - (- (* instance-slots-offset n-word-bytes) - instance-pointer-lowtag) - lip) - (unless (location= result-real value-real) - (inst fmove value-real result-real))) - (let ((value-imag (complex-single-reg-imag-tn value)) - (result-imag (complex-single-reg-imag-tn result))) - (inst sts - value-imag - (- (* (1+ instance-slots-offset) n-word-bytes) - instance-pointer-lowtag) - lip) - (unless (location= result-imag value-imag) - (inst fmove value-imag result-imag))))) - -(define-vop (raw-instance-ref/complex-double) - (:translate %raw-instance-ref/complex-double) - (:policy :fast-safe) - (:args (object :scs (descriptor-reg)) - (index :scs (any-reg))) - (:arg-types * positive-fixnum) - (:results (value :scs (complex-double-reg))) - (:temporary (:scs (interior-reg)) lip) - (:result-types complex-double-float) - (:generator 5 - (inst addq object index lip) - (inst ldt - (complex-double-reg-real-tn value) - (- (* instance-slots-offset n-word-bytes) - instance-pointer-lowtag) - lip) - (inst ldt - (complex-double-reg-imag-tn value) - (- (* (+ instance-slots-offset 2) n-word-bytes) - instance-pointer-lowtag) - lip))) - -(define-vop (raw-instance-set/complex-double) - (:translate %raw-instance-set/complex-double) - (:policy :fast-safe) - (:args (object :scs (descriptor-reg)) - (index :scs (any-reg)) - (value :scs (complex-double-reg))) - (:arg-types * positive-fixnum complex-double-float) - (:results (result :scs (complex-double-reg))) - (:temporary (:scs (interior-reg)) lip) - (:result-types complex-double-float) - (:generator 5 - (inst addq object index lip) - (let ((value-real (complex-double-reg-real-tn value)) - (result-real (complex-double-reg-real-tn result))) - (inst stt - value-real - (- (* instance-slots-offset n-word-bytes) - instance-pointer-lowtag) - lip) - (unless (location= result-real value-real) - (inst fmove value-real result-real))) - (let ((value-imag (complex-double-reg-imag-tn value)) - (result-imag (complex-double-reg-imag-tn result))) - (inst stt - value-imag - (- (* (+ instance-slots-offset 2) n-word-bytes) - instance-pointer-lowtag) - lip) - (unless (location= result-imag value-imag) - (inst fmove value-imag result-imag))))) diff --git a/src/compiler/alpha/char.lisp b/src/compiler/alpha/char.lisp deleted file mode 100644 index 7b76715896..0000000000 --- a/src/compiler/alpha/char.lisp +++ /dev/null @@ -1,155 +0,0 @@ -;;;; the Alpha VM definition of character operations - -;;;; This software is part of the SBCL system. See the README file for -;;;; more information. -;;;; -;;;; This software is derived from the CMU CL system, which was -;;;; written at Carnegie Mellon University and released into the -;;;; public domain. The software is in the public domain and is -;;;; provided with absolutely no warranty. See the COPYING and CREDITS -;;;; files for more information. - -(in-package "SB-VM") - -;;;; moves and coercions - -;;; Move a tagged char to an untagged representation. -(define-vop (move-to-character) - (:args (x :scs (any-reg descriptor-reg))) - (:results (y :scs (character-reg))) - (:generator 1 - (inst srl x n-widetag-bits y))) -(define-move-vop move-to-character :move - (any-reg descriptor-reg) (character-reg)) - -;;; Move an untagged char to a tagged representation. -(define-vop (move-from-character) - (:args (x :scs (character-reg))) - (:results (y :scs (any-reg descriptor-reg))) - (:generator 1 - (inst sll x n-widetag-bits y) - (inst bis y character-widetag y))) -(define-move-vop move-from-character :move - (character-reg) (any-reg descriptor-reg)) - -;;; Move untagged character values. -(define-vop (character-move) - (:args (x :target y - :scs (character-reg) - :load-if (not (location= x y)))) - (:results (y :scs (character-reg) - :load-if (not (location= x y)))) - (:generator 0 - (move x y))) -(define-move-vop character-move :move - (character-reg) (character-reg)) - -;;; Move untagged character arguments/return-values. -(define-vop (move-character-arg) - (:args (x :target y - :scs (character-reg)) - (fp :scs (any-reg) - :load-if (not (sc-is y character-reg)))) - (:results (y)) - (:generator 0 - (sc-case y - (character-reg - (move x y)) - (character-stack - (storew x fp (tn-offset y)))))) -(define-move-vop move-character-arg :move-arg - (any-reg character-reg) (character-reg)) - -;;; Use standard MOVE-ARG + coercion to move an untagged character -;;; to a descriptor passing location. -;;; -(define-move-vop move-arg :move-arg - (character-reg) (any-reg descriptor-reg)) - -;;;; other operations -(define-vop (char-code) - (:translate char-code) - (:policy :fast-safe) - (:args (ch :scs (character-reg) :target res)) - (:arg-types character) - (:results (res :scs (any-reg))) - (:result-types positive-fixnum) - (:generator 1 - (inst sll ch n-fixnum-tag-bits res))) - -(define-vop (code-char) - (:translate code-char) - (:policy :fast-safe) - (:args (code :scs (any-reg) :target res)) - (:arg-types positive-fixnum) - (:results (res :scs (character-reg))) - (:result-types character) - (:generator 1 - (inst srl code n-fixnum-tag-bits res))) - -;;;; comparison of CHARACTERs - -(define-vop (character-compare) - (:args (x :scs (character-reg)) - (y :scs (character-reg))) - (:arg-types character character) - (:temporary (:scs (non-descriptor-reg)) temp) - (:conditional) - (:info target not-p) - (:policy :fast-safe) - (:note "inline comparison") - (:variant-vars cond) - (:generator 3 - (ecase cond - (:eq (inst cmpeq x y temp)) - (:lt (inst cmplt x y temp)) - (:gt (inst cmplt y x temp))) - (if not-p - (inst beq temp target) - (inst bne temp target)))) - -(define-vop (fast-char=/character character-compare) - (:translate char=) - (:variant :eq)) - -(define-vop (fast-char</character character-compare) - (:translate char<) - (:variant :lt)) - -(define-vop (fast-char>/character character-compare) - (:translate char>) - (:variant :gt)) - -(define-vop (character-compare/c) - (:args (x :scs (character-reg))) - (:arg-types character (:constant (character-set ((0 . #xFF))))) - (:temporary (:scs (non-descriptor-reg)) temp) - (:conditional) - (:info target not-p y) - (:policy :fast-safe) - (:note "inline constant comparison") - (:variant-vars cond) - (:generator 2 - (ecase cond - (:eq (inst cmpeq x (sb-xc:char-code y) temp)) - (:lt (inst cmplt x (sb-xc:char-code y) temp)) - (:gt (inst cmple x (sb-xc:char-code y) temp))) - (if not-p - (if (eq cond :gt) - (inst bne temp target) - (inst beq temp target)) - (if (eq cond :gt) - (inst beq temp target) - (inst bne temp target))))) - -(define-vop (fast-char=/character/c character-compare/c) - (:translate char=) - (:variant :eq)) - -(define-vop (fast-char</character/c character-compare/c) - (:translate char<) - (:variant :lt)) - -(define-vop (fast-char>/character/c character-compare/c) - (:translate char>) - (:variant :gt)) diff --git a/src/compiler/alpha/debug.lisp b/src/compiler/alpha/debug.lisp deleted file mode 100644 index e96c705ab5..0000000000 --- a/src/compiler/alpha/debug.lisp +++ /dev/null @@ -1,118 +0,0 @@ -;;;; Alpha compiler support for the new whizzy debugger - -;;;; This software is part of the SBCL system. See the README file for -;;;; more information. -;;;; -;;;; This software is derived from the CMU CL system, which was -;;;; written at Carnegie Mellon University and released into the -;;;; public domain. The software is in the public domain and is -;;;; provided with absolutely no warranty. See the COPYING and CREDITS -;;;; files for more information. - -(in-package "SB-VM") - -(define-vop () - (:translate current-sp) - (:policy :fast-safe) - (:results (res :scs (sap-reg))) - (:result-types system-area-pointer) - (:generator 1 - (move csp-tn res))) - -(define-vop () - (:translate current-fp) - (:policy :fast-safe) - (:results (res :scs (sap-reg))) - (:result-types system-area-pointer) - (:generator 1 - (move cfp-tn res))) - -(define-vop () - (:translate stack-ref) - (:policy :fast-safe) - (:args (object :scs (sap-reg) :target sap) - (offset :scs (any-reg))) - (:arg-types system-area-pointer positive-fixnum) - (:temporary (:scs (sap-reg) :from :eval) sap) - (:results (result :scs (descriptor-reg))) - (:result-types *) - (:generator 5 - (inst addq object offset sap) - (inst ldl result 0 sap))) - -(define-vop () - (:translate %set-stack-ref) - (:policy :fast-safe) - (:args (object :scs (sap-reg) :target sap) - (offset :scs (any-reg)) - (value :scs (descriptor-reg) :target result)) - (:arg-types system-area-pointer positive-fixnum *) - (:results (result :scs (descriptor-reg))) - (:result-types *) - (:temporary (:scs (sap-reg) :from (:argument 1)) sap) - (:generator 2 - (inst addq object offset sap) - (inst stl value 0 sap) - (move value result))) - -(define-vop (code-from-mumble) - (:policy :fast-safe) - (:args (thing :scs (descriptor-reg))) - (:results (code :scs (descriptor-reg))) - (:temporary (:scs (non-descriptor-reg)) temp) - (:variant-vars lowtag) - (:generator 5 - (let ((bogus (gen-label)) - (done (gen-label))) - (loadw temp thing 0 lowtag) - (inst srl temp n-widetag-bits temp) - (inst beq temp bogus) - (inst sll temp word-shift temp) - (unless (= lowtag other-pointer-lowtag) - (inst subq temp (- other-pointer-lowtag lowtag) temp)) - (inst subq thing temp code) - (emit-label done) - (assemble (:elsewhere) - (emit-label bogus) - (move null-tn code) - (inst br zero-tn done))))) - -(define-vop (code-from-lra code-from-mumble) - (:translate lra-code-header) - (:variant other-pointer-lowtag)) - -(define-vop (code-from-function code-from-mumble) - (:translate fun-code-header) - (:variant fun-pointer-lowtag)) - -(define-vop (%make-lisp-obj) - (:policy :fast-safe) - (:translate %make-lisp-obj) - (:args (value :scs (unsigned-reg) :target result)) - (:arg-types unsigned-num) - (:results (result :scs (descriptor-reg))) - (:generator 1 - (move value result))) - -(define-vop (get-lisp-obj-address) - (:policy :fast-safe) - (:translate get-lisp-obj-address) - (:args (thing :scs (descriptor-reg any-reg) :target result)) - (:results (result :scs (unsigned-reg))) - (:result-types unsigned-num) - (:generator 1 - (move thing result))) - -(defknown make-number-stack-pointer ((unsigned-byte 32)) system-area-pointer - (movable foldable flushable)) - -(define-vop (make-number-stack-pointer) - (:policy :fast-safe) - (:translate make-number-stack-pointer) - (:args (arg :scs (unsigned-reg) :to (:argument 1))) - (:arg-types unsigned-num) - (:results (res :scs (sap-reg) :from (:argument 0))) - (:result-types system-area-pointer) - (:generator 5 - (inst mskll nsp-tn 0 res) - (inst bis res arg res))) diff --git a/src/compiler/alpha/float.lisp b/src/compiler/alpha/float.lisp deleted file mode 100644 index f46dbd8790..0000000000 --- a/src/compiler/alpha/float.lisp +++ /dev/null @@ -1,865 +0,0 @@ -;;;; floating point support for the Alpha - -;;;; This software is part of the SBCL system. See the README file for -;;;; more information. -;;;; -;;;; This software is derived from the CMU CL system, which was -;;;; written at Carnegie Mellon University and released into the -;;;; public domain. The software is in the public domain and is -;;;; provided with absolutely no warranty. See the COPYING and CREDITS -;;;; files for more information. - -(in-package "SB-VM") - -;;;; float move functions - -(define-move-fun (load-fp-zero 1) (vop x y) - ((fp-single-zero) (single-reg) - (fp-double-zero) (double-reg)) - (inst fmove x y)) - -(define-move-fun (load-single 1) (vop x y) - ((single-stack) (single-reg)) - (inst lds y (tn-byte-offset x) (current-nfp-tn vop))) - -(define-move-fun (store-single 1) (vop x y) - ((single-reg) (single-stack)) - (inst sts x (tn-byte-offset y) (current-nfp-tn vop))) - -(define-move-fun (load-double 2) (vop x y) - ((double-stack) (double-reg)) - (let ((nfp (current-nfp-tn vop)) - (offset (tn-byte-offset x))) - (inst ldt y offset nfp))) - -(define-move-fun (store-double 2) (vop x y) - ((double-reg) (double-stack)) - (let ((nfp (current-nfp-tn vop)) - (offset (tn-byte-offset y))) - (inst stt x offset nfp))) - -;;;; float move VOPs - -(macrolet ((frob (vop sc) - `(progn - (define-vop (,vop) - (:args (x :scs (,sc) - :target y - :load-if (not (location= x y)))) - (:results (y :scs (,sc) - :load-if (not (location= x y)))) - (:note "float move") - (:generator 0 - (unless (location= y x) - (inst fmove x y)))) - (define-move-vop ,vop :move (,sc) (,sc))))) - (frob single-move single-reg) - (frob double-move double-reg)) - - -(define-vop (move-from-float) - (:args (x :to :save)) - (:results (y)) - (:temporary (:scs (non-descriptor-reg)) ndescr) - (:variant-vars double-p size type data) - (:note "float to pointer coercion") - (:generator 13 - (with-fixed-allocation (y ndescr type size) - (if double-p - (inst stt x (- (* data n-word-bytes) other-pointer-lowtag) y) - (inst sts x (- (* data n-word-bytes) other-pointer-lowtag) y))))) - -(macrolet ((frob (name sc &rest args) - `(progn - (define-vop (,name move-from-float) - (:args (x :scs (,sc) :to :save)) - (:results (y :scs (descriptor-reg))) - (:variant ,@args)) - (define-move-vop ,name :move (,sc) (descriptor-reg))))) - (frob move-from-single single-reg - nil single-float-size single-float-widetag single-float-value-slot) - (frob move-from-double double-reg - t double-float-size double-float-widetag double-float-value-slot)) - -(macrolet ((frob (name sc double-p value) - `(progn - (define-vop (,name) - (:args (x :scs (descriptor-reg))) - (:results (y :scs (,sc))) - (:note "pointer to float coercion") - (:generator 2 - ,@(if double-p - `((inst ldt y (- (* ,value n-word-bytes) - other-pointer-lowtag) - x)) - `((inst lds y (- (* ,value n-word-bytes) - other-pointer-lowtag) - x))))) - (define-move-vop ,name :move (descriptor-reg) (,sc))))) - (frob move-to-single single-reg nil single-float-value-slot) - (frob move-to-double double-reg t double-float-value-slot)) - - -(macrolet ((frob (name sc stack-sc double-p) - `(progn - (define-vop (,name) - (:args (x :scs (,sc) :target y) - (nfp :scs (any-reg) - :load-if (not (sc-is y ,sc)))) - (:results (y)) - (:note "float argument move") - (:generator ,(if double-p 2 1) - (sc-case y - (,sc - (unless (location= x y) - (inst fmove x y))) - (,stack-sc - (let ((offset (tn-byte-offset y))) - ,@(if double-p - '((inst stt x offset nfp)) - '((inst sts x offset nfp)))))))) - (define-move-vop ,name :move-arg - (,sc descriptor-reg) (,sc))))) - (frob move-single-float-arg single-reg single-stack nil) - (frob move-double-float-arg double-reg double-stack t)) - -;;;; complex float move functions - -(defun complex-single-reg-real-tn (x) - (make-random-tn :kind :normal :sc (sc-or-lose 'single-reg ) - :offset (tn-offset x))) -(defun complex-single-reg-imag-tn (x) - (make-random-tn :kind :normal :sc (sc-or-lose 'single-reg ) - :offset (1+ (tn-offset x)))) - -(defun complex-double-reg-real-tn (x) - (make-random-tn :kind :normal :sc (sc-or-lose 'double-reg ) - :offset (tn-offset x))) -(defun complex-double-reg-imag-tn (x) - (make-random-tn :kind :normal :sc (sc-or-lose 'double-reg ) - :offset (1+ (tn-offset x)))) - - -(define-move-fun (load-complex-single 2) (vop x y) - ((complex-single-stack) (complex-single-reg)) - (let ((nfp (current-nfp-tn vop)) - (offset (tn-byte-offset x))) - (let ((real-tn (complex-single-reg-real-tn y))) - (inst lds real-tn offset nfp)) - (let ((imag-tn (complex-single-reg-imag-tn y))) - (inst lds imag-tn (+ offset n-word-bytes) nfp)))) - -(define-move-fun (store-complex-single 2) (vop x y) - ((complex-single-reg) (complex-single-stack)) - (let ((nfp (current-nfp-tn vop)) - (offset (tn-byte-offset y))) - (let ((real-tn (complex-single-reg-real-tn x))) - (inst sts real-tn offset nfp)) - (let ((imag-tn (complex-single-reg-imag-tn x))) - (inst sts imag-tn (+ offset n-word-bytes) nfp)))) - - -(define-move-fun (load-complex-double 4) (vop x y) - ((complex-double-stack) (complex-double-reg)) - (let ((nfp (current-nfp-tn vop)) - (offset (tn-byte-offset x))) - (let ((real-tn (complex-double-reg-real-tn y))) - (inst ldt real-tn offset nfp)) - (let ((imag-tn (complex-double-reg-imag-tn y))) - (inst ldt imag-tn (+ offset (* 2 n-word-bytes)) nfp)))) - -(define-move-fun (store-complex-double 4) (vop x y) - ((complex-double-reg) (complex-double-stack)) - (let ((nfp (current-nfp-tn vop)) - (offset (tn-byte-offset y))) - (let ((real-tn (complex-double-reg-real-tn x))) - (inst stt real-tn offset nfp)) - (let ((imag-tn (complex-double-reg-imag-tn x))) - (inst stt imag-tn (+ offset (* 2 n-word-bytes)) nfp)))) - -;;; -;;; complex float register to register moves. -;;; -(define-vop (complex-single-move) - (:args (x :scs (complex-single-reg) :target y - :load-if (not (location= x y)))) - (:results (y :scs (complex-single-reg) :load-if (not (location= x y)))) - (:note "complex single float move") - (:generator 0 - (unless (location= x y) - ;; Note the complex-float-regs are aligned to every second - ;; float register so there is not need to worry about overlap. - (let ((x-real (complex-single-reg-real-tn x)) - (y-real (complex-single-reg-real-tn y))) - (inst fmove x-real y-real)) - (let ((x-imag (complex-single-reg-imag-tn x)) - (y-imag (complex-single-reg-imag-tn y))) - (inst fmove x-imag y-imag))))) -;;; -(define-move-vop complex-single-move :move - (complex-single-reg) (complex-single-reg)) - -(define-vop (complex-double-move) - (:args (x :scs (complex-double-reg) - :target y :load-if (not (location= x y)))) - (:results (y :scs (complex-double-reg) :load-if (not (location= x y)))) - (:note "complex double float move") - (:generator 0 - (unless (location= x y) - ;; Note the complex-float-regs are aligned to every second - ;; float register so there is not need to worry about overlap. - (let ((x-real (complex-double-reg-real-tn x)) - (y-real (complex-double-reg-real-tn y))) - (inst fmove x-real y-real)) - (let ((x-imag (complex-double-reg-imag-tn x)) - (y-imag (complex-double-reg-imag-tn y))) - (inst fmove x-imag y-imag))))) -;;; -(define-move-vop complex-double-move :move - (complex-double-reg) (complex-double-reg)) - -;;; -;;; Move from a complex float to a descriptor register allocating a -;;; new complex float object in the process. -;;; -(define-vop (move-from-complex-single) - (:args (x :scs (complex-single-reg) :to :save)) - (:results (y :scs (descriptor-reg))) - (:temporary (:scs (non-descriptor-reg)) ndescr) - (:note "complex single float to pointer coercion") - (:generator 13 - (with-fixed-allocation (y ndescr complex-single-float-widetag - complex-single-float-size) - (let ((real-tn (complex-single-reg-real-tn x))) - (inst sts real-tn (- (* complex-single-float-real-slot - n-word-bytes) - other-pointer-lowtag) - y)) - (let ((imag-tn (complex-single-reg-imag-tn x))) - (inst sts imag-tn (- (* complex-single-float-imag-slot - n-word-bytes) - other-pointer-lowtag) - y))))) -;;; -(define-move-vop move-from-complex-single :move - (complex-single-reg) (descriptor-reg)) - -(define-vop (move-from-complex-double) - (:args (x :scs (complex-double-reg) :to :save)) - (:results (y :scs (descriptor-reg))) - (:temporary (:scs (non-descriptor-reg)) ndescr) - (:note "complex double float to pointer coercion") - (:generator 13 - (with-fixed-allocation (y ndescr complex-double-float-widetag - complex-double-float-size) - (let ((real-tn (complex-double-reg-real-tn x))) - (inst stt real-tn (- (* complex-double-float-real-slot - n-word-bytes) - other-pointer-lowtag) - y)) - (let ((imag-tn (complex-double-reg-imag-tn x))) - (inst stt imag-tn (- (* complex-double-float-imag-slot - n-word-bytes) - other-pointer-lowtag) - y))))) -;;; -(define-move-vop move-from-complex-double :move - (complex-double-reg) (descriptor-reg)) - -;;; -;;; Move from a descriptor to a complex float register. -;;; -(define-vop (move-to-complex-single) - (:args (x :scs (descriptor-reg))) - (:results (y :scs (complex-single-reg))) - (:note "pointer to complex float coercion") - (:generator 2 - (let ((real-tn (complex-single-reg-real-tn y))) - (inst lds real-tn (- (* complex-single-float-real-slot - n-word-bytes) - other-pointer-lowtag) - x)) - (let ((imag-tn (complex-single-reg-imag-tn y))) - (inst lds imag-tn (- (* complex-single-float-imag-slot - n-word-bytes) - other-pointer-lowtag) - x)))) -(define-move-vop move-to-complex-single :move - (descriptor-reg) (complex-single-reg)) - -(define-vop (move-to-complex-double) - (:args (x :scs (descriptor-reg))) - (:results (y :scs (complex-double-reg))) - (:note "pointer to complex float coercion") - (:generator 2 - (let ((real-tn (complex-double-reg-real-tn y))) - (inst ldt real-tn (- (* complex-double-float-real-slot - n-word-bytes) - other-pointer-lowtag) - x)) - (let ((imag-tn (complex-double-reg-imag-tn y))) - (inst ldt imag-tn (- (* complex-double-float-imag-slot - n-word-bytes) - other-pointer-lowtag) - x)))) -(define-move-vop move-to-complex-double :move - (descriptor-reg) (complex-double-reg)) - -;;; -;;; complex float MOVE-ARG VOP -;;; -(define-vop (move-complex-single-float-arg) - (:args (x :scs (complex-single-reg) :target y) - (nfp :scs (any-reg) :load-if (not (sc-is y complex-single-reg)))) - (:results (y)) - (:note "complex single float argument move") - (:generator 1 - (sc-case y - (complex-single-reg - (unless (location= x y) - (let ((x-real (complex-single-reg-real-tn x)) - (y-real (complex-single-reg-real-tn y))) - (inst fmove x-real y-real)) - (let ((x-imag (complex-single-reg-imag-tn x)) - (y-imag (complex-single-reg-imag-tn y))) - (inst fmove x-imag y-imag)))) - (complex-single-stack - (let ((offset (tn-byte-offset y))) - (let ((real-tn (complex-single-reg-real-tn x))) - (inst sts real-tn offset nfp)) - (let ((imag-tn (complex-single-reg-imag-tn x))) - (inst sts imag-tn (+ offset n-word-bytes) nfp))))))) -(define-move-vop move-complex-single-float-arg :move-arg - (complex-single-reg descriptor-reg) (complex-single-reg)) - -(define-vop (move-complex-double-float-arg) - (:args (x :scs (complex-double-reg) :target y) - (nfp :scs (any-reg) :load-if (not (sc-is y complex-double-reg)))) - (:results (y)) - (:note "complex double float argument move") - (:generator 2 - (sc-case y - (complex-double-reg - (unless (location= x y) - (let ((x-real (complex-double-reg-real-tn x)) - (y-real (complex-double-reg-real-tn y))) - (inst fmove x-real y-real)) - (let ((x-imag (complex-double-reg-imag-tn x)) - (y-imag (complex-double-reg-imag-tn y))) - (inst fmove x-imag y-imag)))) - (complex-double-stack - (let ((offset (tn-byte-offset y))) - (let ((real-tn (complex-double-reg-real-tn x))) - (inst stt real-tn offset nfp)) - (let ((imag-tn (complex-double-reg-imag-tn x))) - (inst stt imag-tn (+ offset (* 2 n-word-bytes)) nfp))))))) -(define-move-vop move-complex-double-float-arg :move-arg - (complex-double-reg descriptor-reg) (complex-double-reg)) - - -(define-move-vop move-arg :move-arg - (single-reg double-reg complex-single-reg complex-double-reg) - (descriptor-reg)) - - -;;;; float arithmetic VOPs - -(define-vop (float-op) - (:args (x) (y)) - (:results (r)) - (:policy :fast-safe) - (:note "inline float arithmetic") - (:vop-var vop) - (:save-p :compute-only)) - -;;; We need to insure that ops that can cause traps do not clobber an -;;; argument register with invalid results. This so the software trap -;;; handler can re-execute the instruction and produce correct IEEE -;;; result. The :from :load hopefully does that. -(macrolet ((frob (name sc ptype) - `(define-vop (,name float-op) - (:args (x :scs (,sc)) - (y :scs (,sc))) - (:results (r :scs (,sc) :from :load)) - (:arg-types ,ptype ,ptype) - (:result-types ,ptype)))) - (frob single-float-op single-reg single-float) - (frob double-float-op double-reg double-float)) - -;; This is resumption-safe with underflow traps enabled, -;; with software handling and (notyet) dynamic rounding mode. -(macrolet ((frob (op sinst sname scost dinst dname dcost) - `(progn - (define-vop (,sname single-float-op) - (:translate ,op) - (:variant-cost ,scost) - (:generator ,scost - (inst ,sinst x y r) - (note-this-location vop :internal-error) - (inst trapb))) - (define-vop (,dname double-float-op) - (:translate ,op) - (:variant-cost ,dcost) - (:generator ,dcost - (inst ,dinst x y r) - (note-this-location vop :internal-error) - (inst trapb)))))) - ;; Not sure these cost number are right. +*- about same / is 4x - (frob + adds_su +/single-float 1 addt_su +/double-float 1) - (frob - subs_su -/single-float 1 subt_su -/double-float 1) - (frob * muls_su */single-float 1 mult_su */double-float 1) - (frob / divs_su //single-float 4 divt_su //double-float 4)) - -(macrolet ((frob (name inst translate sc type) - `(define-vop (,name) - (:args (x :scs (,sc) :target y)) - (:results (y :scs (,sc))) - (:translate ,translate) - (:policy :fast-safe) - (:arg-types ,type) - (:result-types ,type) - (:note "inline float arithmetic") - (:vop-var vop) - (:save-p :compute-only) - (:generator 1 - (note-this-location vop :internal-error) - (inst ,inst x y))))) - (frob abs/single-float fabs abs single-reg single-float) - (frob abs/double-float fabs abs double-reg double-float) - (frob %negate/single-float fneg %negate single-reg single-float) - (frob %negate/double-float fneg %negate double-reg double-float)) - - -;;;; float comparison - -(define-vop (float-compare) - (:args (x) (y)) - (:conditional) - (:info target not-p) - (:variant-vars eq complement) - (:temporary (:scs (single-reg)) temp) - (:policy :fast-safe) - (:note "inline float comparison") - (:vop-var vop) - (:save-p :compute-only) - (:generator 3 - (note-this-location vop :internal-error) - (inst cmptun x y temp) - (inst fbne temp (if not-p target fall-through)) - (if eq - (inst cmpteq x y temp) - (if complement - (inst cmptle x y temp) - (inst cmptlt x y temp))) - (inst trapb) - (if (if complement (not not-p) not-p) - (inst fbeq temp target) - (inst fbne temp target)) - FALL-THROUGH)) - -(macrolet ((frob (name sc ptype) - `(define-vop (,name float-compare) - (:args (x :scs (,sc)) - (y :scs (,sc))) - (:arg-types ,ptype ,ptype)))) - (frob single-float-compare single-reg single-float) - (frob double-float-compare double-reg double-float)) - -(macrolet ((frob (translate complement sname dname eq) - `(progn - (define-vop (,sname single-float-compare) - (:translate ,translate) - (:variant ,eq ,complement)) - (define-vop (,dname double-float-compare) - (:translate ,translate) - (:variant ,eq ,complement))))) - (frob < nil </single-float </double-float nil) - (frob > t >/single-float >/double-float nil) - (frob = nil =/single-float =/double-float t)) - - -;;;; float conversion - -(macrolet - ((frob (name translate inst ld-inst to-sc to-type) - `(define-vop (,name) - (:args (x :scs (signed-reg) :target temp - :load-if (not (sc-is x signed-stack)))) - (:temporary (:scs (,to-sc)) freg1) - (:temporary (:scs (,to-sc)) freg2) - (:temporary (:scs (single-stack)) temp) - - (:results (y :scs (,to-sc))) - (:arg-types signed-num) - (:result-types ,to-type) - (:policy :fast-safe) - (:note "inline float coercion") - (:translate ,translate) - (:vop-var vop) - (:save-p :compute-only) - (:generator 5 - (let ((stack-tn - (sc-case x - (signed-reg - (inst stl x - (* (tn-offset temp) - n-word-bytes) - (current-nfp-tn vop)) - temp) - (signed-stack - x)))) - (inst ,ld-inst freg1 - (tn-byte-offset stack-tn) - (current-nfp-tn vop)) - (note-this-location vop :internal-error) - (inst cvtlq freg1 freg2) - (inst ,inst freg2 y) - (inst excb) - ))))) - (frob %single-float/signed %single-float cvtqs_sui lds single-reg single-float) - (frob %double-float/signed %double-float cvtqt_sui lds double-reg double-float)) - -;;; see previous comment about software trap handlers: also applies here -(macrolet ((frob (name translate inst from-sc from-type to-sc to-type) - `(define-vop (,name) - (:args (x :scs (,from-sc))) - (:results (y :scs (,to-sc) :from :load)) - (:arg-types ,from-type) - (:result-types ,to-type) - (:policy :fast-safe) - (:note "inline float coercion") - (:translate ,translate) - (:vop-var vop) - (:save-p :compute-only) - (:generator 2 - (note-this-location vop :internal-error) - (inst ,inst x y) - (inst excb) - )))) - (frob %single-float/double-float %single-float cvtts_su - double-reg double-float single-reg single-float) - (frob %double-float/single-float %double-float fmove - single-reg single-float double-reg double-float)) - -(macrolet - ((frob (trans from-sc from-type inst &optional single) - (declare (ignorable single)) - `(define-vop (,(symbolicate trans "/" from-type)) - (:args (x :scs (,from-sc) :target temp)) - (:temporary (:from :load ;(:argument 0) - :sc single-reg) temp) - (:temporary (:scs (signed-stack)) stack-temp) - (:results (y :scs (signed-reg) - :load-if (not (sc-is y signed-stack)))) - (:arg-types ,from-type) - (:result-types signed-num) - (:translate ,trans) - (:policy :fast-safe) - (:note "inline float truncate") - (:vop-var vop) - (:save-p :compute-only) - (:generator 5 - (note-this-location vop :internal-error) - (inst ,inst x temp) - (sc-case y - (signed-stack - (inst stt temp - (tn-byte-offset y) - (current-nfp-tn vop))) - (signed-reg - (inst stt temp - (* (tn-offset stack-temp) - n-word-bytes) - (current-nfp-tn vop)) - (inst ldq y - (tn-byte-offset stack-temp) - (current-nfp-tn vop)))) - (inst excb) - )))) - (frob %unary-truncate/single-float single-reg single-float cvttq/c_sv t) - (frob %unary-truncate/double-float double-reg double-float cvttq/c_sv) - (frob %unary-round single-reg single-float cvttq_sv t) - (frob %unary-round double-reg double-float cvttq_sv)) - -(define-vop (make-single-float) - (:args (bits :scs (signed-reg) :target res - :load-if (not (sc-is bits signed-stack)))) - (:results (res :scs (single-reg) - :load-if (not (sc-is res single-stack)))) - (:temporary (:scs (signed-reg) :from (:argument 0) :to (:result 0)) temp) - (:temporary (:scs (signed-stack)) stack-temp) - (:arg-types signed-num) - (:result-types single-float) - (:translate make-single-float) - (:policy :fast-safe) - (:vop-var vop) - (:generator 4 - (sc-case bits - (signed-reg - (sc-case res - (single-reg - (inst stl bits - (tn-byte-offset stack-temp) - (current-nfp-tn vop)) - (inst lds res - (tn-byte-offset stack-temp) - (current-nfp-tn vop))) - (single-stack - (inst stl bits - (tn-byte-offset res) - (current-nfp-tn vop))))) - (signed-stack - (sc-case res - (single-reg - (inst lds res - (tn-byte-offset bits) - (current-nfp-tn vop))) - (single-stack - (unless (location= bits res) - (inst ldl temp - (tn-byte-offset bits) - (current-nfp-tn vop)) - (inst stl temp - (tn-byte-offset res) - (current-nfp-tn vop))))))))) - -(define-vop (make-double-float) - (:args (hi-bits :scs (signed-reg)) - (lo-bits :scs (unsigned-reg))) - (:results (res :scs (double-reg) - :load-if (not (sc-is res double-stack)))) - (:temporary (:scs (double-stack)) temp) - (:arg-types signed-num unsigned-num) - (:result-types double-float) - (:translate make-double-float) - (:policy :fast-safe) - (:vop-var vop) - (:generator 2 - (let ((stack-tn (sc-case res - (double-stack res) - (double-reg temp)))) - (inst stl hi-bits - (* (1+ (tn-offset stack-tn)) n-word-bytes) - (current-nfp-tn vop)) - (inst stl lo-bits - (tn-byte-offset stack-tn) - (current-nfp-tn vop))) - (when (sc-is res double-reg) - (inst ldt res - (tn-byte-offset temp) - (current-nfp-tn vop))))) - -(define-vop (single-float-bits) - (:args (float :scs (single-reg descriptor-reg) - :load-if (not (sc-is float single-stack)))) - (:results (bits :scs (signed-reg) - :load-if (or (sc-is float descriptor-reg single-stack) - (not (sc-is bits signed-stack))))) - (:temporary (:scs (signed-stack)) stack-temp) - (:arg-types single-float) - (:result-types signed-num) - (:translate single-float-bits) - (:policy :fast-safe) - (:vop-var vop) - (:generator 4 - (sc-case bits - (signed-reg - (sc-case float - (single-reg - (inst sts float - (tn-byte-offset stack-temp) - (current-nfp-tn vop)) - (inst ldl bits - (tn-byte-offset stack-temp) - (current-nfp-tn vop))) - (single-stack - (inst ldl bits - (tn-byte-offset float) - (current-nfp-tn vop))) - (descriptor-reg - (loadw bits float single-float-value-slot - other-pointer-lowtag)))) - (signed-stack - (sc-case float - (single-reg - (inst sts float - (tn-byte-offset bits) - (current-nfp-tn vop)))))))) - -(define-vop (double-float-high-bits) - (:args (float :scs (double-reg descriptor-reg) - :load-if (not (sc-is float double-stack)))) - (:results (hi-bits :scs (signed-reg))) - (:temporary (:scs (double-stack)) stack-temp) - (:arg-types double-float) - (:result-types signed-num) - (:translate double-float-high-bits) - (:policy :fast-safe) - (:vop-var vop) - (:generator 5 - (sc-case float - (double-reg - (inst stt float - (tn-byte-offset stack-temp) - (current-nfp-tn vop)) - (inst ldl hi-bits - (* (1+ (tn-offset stack-temp)) n-word-bytes) - (current-nfp-tn vop))) - (double-stack - (inst ldl hi-bits - (* (1+ (tn-offset float)) n-word-bytes) - (current-nfp-tn vop))) - (descriptor-reg - (loadw hi-bits float (1+ double-float-value-slot) - other-pointer-lowtag))))) - -(define-vop (double-float-low-bits) - (:args (float :scs (double-reg descriptor-reg) - :load-if (not (sc-is float double-stack)))) - (:results (lo-bits :scs (unsigned-reg))) - (:temporary (:scs (double-stack)) stack-temp) - (:arg-types double-float) - (:result-types unsigned-num) - (:translate double-float-low-bits) - (:policy :fast-safe) - (:vop-var vop) - (:generator 5 - (sc-case float - (double-reg - (inst stt float - (tn-byte-offset stack-temp) - (current-nfp-tn vop)) - (inst ldl lo-bits - (tn-byte-offset stack-temp) - (current-nfp-tn vop))) - (double-stack - (inst ldl lo-bits - (tn-byte-offset float) - (current-nfp-tn vop))) - (descriptor-reg - (loadw lo-bits float double-float-value-slot - other-pointer-lowtag))) - (inst mskll lo-bits 4 lo-bits))) - - -;;;; float mode hackery has moved to alpha-vm.lisp - - -;;;; complex float VOPs - -(define-vop (make-complex-single-float) - (:translate complex) - (:args (real :scs (single-reg) :target r) - (imag :scs (single-reg) :to :save)) - (:arg-types single-float single-float) - (:results (r :scs (complex-single-reg) :from (:argument 0) - :load-if (not (sc-is r complex-single-stack)))) - (:result-types complex-single-float) - (:note "inline complex single-float creation") - (:policy :fast-safe) - (:vop-var vop) - (:generator 5 - (sc-case r - (complex-single-reg - (let ((r-real (complex-single-reg-real-tn r))) - (unless (location= real r-real) - (inst fmove real r-real))) - (let ((r-imag (complex-single-reg-imag-tn r))) - (unless (location= imag r-imag) - (inst fmove imag r-imag)))) - (complex-single-stack - (let ((nfp (current-nfp-tn vop)) - (offset (tn-byte-offset r))) - (inst sts real offset nfp) - (inst sts imag (+ offset n-word-bytes) nfp)))))) - -(define-vop (make-complex-double-float) - (:translate complex) - (:args (real :scs (double-reg) :target r) - (imag :scs (double-reg) :to :save)) - (:arg-types double-float double-float) - (:results (r :scs (complex-double-reg) :from (:argument 0) - :load-if (not (sc-is r complex-double-stack)))) - (:result-types complex-double-float) - (:note "inline complex double-float creation") - (:policy :fast-safe) - (:vop-var vop) - (:generator 5 - (sc-case r - (complex-double-reg - (let ((r-real (complex-double-reg-real-tn r))) - (unless (location= real r-real) - (inst fmove real r-real))) - (let ((r-imag (complex-double-reg-imag-tn r))) - (unless (location= imag r-imag) - (inst fmove imag r-imag)))) - (complex-double-stack - (let ((nfp (current-nfp-tn vop)) - (offset (tn-byte-offset r))) - (inst stt real offset nfp) - (inst stt imag (+ offset (* 2 n-word-bytes)) nfp)))))) - -(define-vop (complex-single-float-value) - (:args (x :scs (complex-single-reg) :target r - :load-if (not (sc-is x complex-single-stack)))) - (:arg-types complex-single-float) - (:results (r :scs (single-reg))) - (:result-types single-float) - (:variant-vars slot) - (:policy :fast-safe) - (:vop-var vop) - (:generator 3 - (sc-case x - (complex-single-reg - (let ((value-tn (ecase slot - (:real (complex-single-reg-real-tn x)) - (:imag (complex-single-reg-imag-tn x))))) - (unless (location= value-tn r) - (inst fmove value-tn r)))) - (complex-single-stack - (inst lds r (* (+ (ecase slot (:real 0) (:imag 1)) (tn-offset x)) - n-word-bytes) - (current-nfp-tn vop)))))) - -(define-vop (realpart/complex-single-float complex-single-float-value) - (:translate realpart) - (:note "complex single float realpart") - (:variant :real)) - -(define-vop (imagpart/complex-single-float complex-single-float-value) - (:translate imagpart) - (:note "complex single float imagpart") - (:variant :imag)) - -(define-vop (complex-double-float-value) - (:args (x :scs (complex-double-reg) :target r - :load-if (not (sc-is x complex-double-stack)))) - (:arg-types complex-double-float) - (:results (r :scs (double-reg))) - (:result-types double-float) - (:variant-vars slot) - (:policy :fast-safe) - (:vop-var vop) - (:generator 3 - (sc-case x - (complex-double-reg - (let ((value-tn (ecase slot - (:real (complex-double-reg-real-tn x)) - (:imag (complex-double-reg-imag-tn x))))) - (unless (location= value-tn r) - (inst fmove value-tn r)))) - (complex-double-stack - (inst ldt r (* (+ (ecase slot (:real 0) (:imag 2)) (tn-offset x)) - n-word-bytes) - (current-nfp-tn vop)))))) - -(define-vop (realpart/complex-double-float complex-double-float-value) - (:translate realpart) - (:note "complex double float realpart") - (:variant :real)) - -(define-vop (imagpart/complex-double-float complex-double-float-value) - (:translate imagpart) - (:note "complex double float imagpart") - (:variant :imag)) - diff --git a/src/compiler/alpha/insts.lisp b/src/compiler/alpha/insts.lisp deleted file mode 100644 index 59f28f2bca..0000000000 --- a/src/compiler/alpha/insts.lisp +++ /dev/null @@ -1,693 +0,0 @@ -;;; the instruction set definition for the Alpha - -;;;; This software is part of the SBCL system. See the README file for -;;;; more information. -;;;; -;;;; This software is derived from the CMU CL system, which was -;;;; written at Carnegie Mellon University and released into the -;;;; public domain. The software is in the public domain and is -;;;; provided with absolutely no warranty. See the COPYING and CREDITS -;;;; files for more information. - -(in-package "SB-ALPHA-ASM") - -(eval-when (:compile-toplevel :load-toplevel :execute) - ;; Imports from this package into SB-VM - (import '(reg-tn-encoding) "SB-VM") - ;; Imports from SB-VM into this package - (import '(sb-vm::zero sb-vm::fp-single-zero sb-vm::fp-double-zero - sb-vm::registers sb-vm::float-registers - sb-vm::zero-tn sb-vm::fp-single-zero-tn sb-vm::fp-double-zero-tn - sb-vm::zero-offset sb-vm::null-offset sb-vm::code-offset))) - - -;;;; utility functions - -(defun reg-tn-encoding (tn) - (declare (type tn tn) - (values (unsigned-byte 5))) - (sc-case tn - (zero zero-offset) - (null null-offset) - (t - (aver (eq (sb-name (sc-sb (tn-sc tn))) 'registers)) - (tn-offset tn)))) - -(defun fp-reg-tn-encoding (tn) - (declare (type tn tn)) - (sc-case tn - (fp-single-zero (tn-offset fp-single-zero-tn)) - (fp-double-zero (tn-offset fp-double-zero-tn)) - (t - (unless (eq (sb-name (sc-sb (tn-sc tn))) 'float-registers) - (error "~S isn't a floating-point register." tn)) - (tn-offset tn)))) - -;;;; initial disassembler setup - -(defvar *disassem-use-lisp-reg-names* t) - -(defparameter reg-symbols - (map 'vector - (lambda (name) - (cond ((null name) nil) - (t (make-symbol (concatenate 'string "$" name))))) - sb-vm::*register-names*)) - -(define-arg-type reg - :printer (lambda (value stream dstate) - (declare (stream stream) (fixnum value)) - (let ((regname (aref reg-symbols value))) - (princ regname stream) - (maybe-note-associated-storage-ref - value - 'registers - regname - dstate)))) - -(define-arg-type memory-address-annotation - :printer (lambda (value stream dstate) - (declare (ignore stream)) - (destructuring-bind (reg offset) value - (cond - ((= reg code-offset) - (note-code-constant offset dstate)) - ((= reg null-offset) - (maybe-note-nil-indexed-object offset dstate)))))) - -(defparameter float-reg-symbols - #.(coerce - (loop for n from 0 to 31 collect (make-symbol (format nil "~D" n))) - 'vector)) - -(define-arg-type fp-reg - :printer (lambda (value stream dstate) - (declare (stream stream) (fixnum value)) - (let ((regname (aref float-reg-symbols value))) - (princ regname stream) - (maybe-note-associated-storage-ref - value - 'float-registers - regname - dstate)))) - -(define-arg-type relative-label - :sign-extend t - :use-label (lambda (value dstate) - (declare (type (signed-byte 21) value) - (type disassem-state dstate)) - (+ 4 (ash value 2) (dstate-cur-addr dstate)))) - -;;;; DEFINE-INSTRUCTION-FORMATs for the disassembler - -(define-instruction-format (memory 32 - :default-printer '(:name :tab ra "," disp "(" rb ")" - memory-address-annotation)) - (op :field (byte 6 26)) - (ra :field (byte 5 21) :type 'reg) - (rb :field (byte 5 16) :type 'reg) - (disp :field (byte 16 0) :sign-extend t) - (memory-address-annotation :fields (list (byte 5 16) (byte 16 0)) - :type 'memory-address-annotation)) - -(define-instruction-format (jump 32 - :default-printer '(:name :tab ra ",(" rb ")," hint)) - (op :field (byte 6 26)) - (ra :field (byte 5 21) :type 'reg) - (rb :field (byte 5 16) :type 'reg) - (subop :field (byte 2 14)) - (hint :field (byte 14 0))) - -(define-instruction-format (branch 32 - :default-printer '(:name :tab ra "," disp)) - (op :field (byte 6 26)) - (ra :field (byte 5 21) :type 'reg) - (disp :field (byte 21 0) :type 'relative-label)) - -(define-instruction-format (reg-operate 32 - :default-printer '(:name :tab ra "," rb "," rc)) - (op :field (byte 6 26)) - (ra :field (byte 5 21) :type 'reg) - (rb :field (byte 5 16) :type 'reg) - (sbz :field (byte 3 13)) - (f :field (byte 1 12) :value 0) - (fn :field (byte 7 5)) - (rc :field (byte 5 0) :type 'reg)) - -(define-instruction-format (lit-operate 32 - :default-printer '(:name :tab ra "," lit "," rc)) - (op :field (byte 6 26)) - (ra :field (byte 5 21) :type 'reg) - (lit :field (byte 8 13)) - (f :field (byte 1 12) :value 1) - (fn :field (byte 7 5)) - (rc :field (byte 5 0) :type 'reg)) - -(define-instruction-format (fp-operate 32 - :default-printer '(:name :tab fa "," fb "," fc)) - (op :field (byte 6 26)) - (fa :field (byte 5 21) :type 'fp-reg) - (fb :field (byte 5 16) :type 'fp-reg) - (fn :field (byte 11 5)) - (fc :field (byte 5 0) :type 'fp-reg)) - -(define-instruction-format (call-pal 32 - :default-printer '('call_pal :tab 'pal_ :name)) - (op :field (byte 6 26) :value 0) - (palcode :field (byte 26 0))) - -(define-instruction-format (bugchk 32 - :default-printer '('call_pal :tab 'pal_bugchk "," code)) - (op :field (byte 6 26) :value 0) - (palcode :field (byte 26 0) :value #x81) - ;; We use CALL-PAL BUGCHK as part of our trap logic. It is invariably - ;; followed by a trap-code word, which we pick out with the - ;; semi-traditional prefilter approach. - (code :prefilter (lambda (dstate) (read-suffix 32 dstate)) - :reader bugchk-trap-code)) - -;;;; emitters - -(define-bitfield-emitter emit-word 16 - (byte 16 0)) - -(define-bitfield-emitter emit-lword 32 - (byte 32 0)) - -(define-bitfield-emitter emit-qword 64 - (byte 64 0)) - -(define-bitfield-emitter emit-memory 32 - (byte 6 26) (byte 5 21) (byte 5 16) (byte 16 0)) - -(define-bitfield-emitter emit-branch 32 - (byte 6 26) (byte 5 21) (byte 21 0)) - -(define-bitfield-emitter emit-reg-operate 32 - (byte 6 26) (byte 5 21) (byte 5 16) (byte 3 13) (byte 1 12) (byte 7 5) - (byte 5 0)) - -(define-bitfield-emitter emit-lit-operate 32 - (byte 6 26) (byte 5 21) (byte 8 13) (byte 1 12) (byte 7 5) (byte 5 0)) - -(define-bitfield-emitter emit-fp-operate 32 - (byte 6 26) (byte 5 21) (byte 5 16) (byte 11 5) (byte 5 0)) - -(define-bitfield-emitter emit-pal 32 - (byte 6 26) (byte 26 0)) - -;;;; macros for instructions - -(macrolet ((define-memory (name op &optional fixup float) - `(define-instruction ,name (segment ra disp rb ,@(if fixup - '(&optional type))) - (:declare (type tn ra rb) - ,@(if fixup ; ### unsigned-byte 16 bad idea? - '((type (or (unsigned-byte 16) (signed-byte 16) fixup) - disp)) - '((type (or (unsigned-byte 16) (signed-byte 16)) disp)))) - (:printer memory ((op ,op)) - ,@(when fixup - ;; Don't try to parse a constant - ;; reference if we're doing LDA or LDAH - ;; against $CODE. - '('(:name :tab ra "," disp "(" rb ")")))) - (:emitter - ,@(when fixup - `((when (fixup-p disp) - (note-fixup segment (or type ,fixup) disp) - (setf disp 0)))) - (emit-memory segment ,op ,@(if float - '((fp-reg-tn-encoding ra)) - '((reg-tn-encoding ra))) - (reg-tn-encoding rb) - disp))))) - (define-memory lda #x08 :lda) - (define-memory ldah #x09 :ldah) - (define-memory ldbu #x0a) ; BWX extension - (define-memory ldwu #x0c) ; BWX extension - (define-memory ldl #x28) - (define-memory ldq #x29) - (define-memory ldl_l #x2a) - (define-memory ldq_q #x2b) - (define-memory ldq_u #x0b) - (define-memory stw #x0d) ; BWX extension - (define-memory stb #x0e) ; BWX extension - (define-memory stl #x2c) - (define-memory stq #x2d) - (define-memory stl_c #x2e) - (define-memory stq_c #x2f) - (define-memory stq_u #x0f) - (define-memory ldf #x20 nil t) - (define-memory ldg #x21 nil t) - (define-memory lds #x22 nil t) - (define-memory ldt #x23 nil t) - (define-memory stf #x24 nil t) - (define-memory stg #x25 nil t) - (define-memory sts #x26 nil t) - (define-memory stt #x27 nil t)) - -(macrolet ((define-jump (name subop) - `(define-instruction ,name (segment ra rb &optional (hint 0)) - (:declare (type tn ra rb) - (type (or (unsigned-byte 14) fixup) hint)) - (:printer jump ((op #x1a) (subop ,subop))) - (:emitter - (when (fixup-p hint) - (note-fixup segment :jmp-hint hint) - (setf hint 0)) - (emit-memory segment #x1a (reg-tn-encoding ra) (reg-tn-encoding rb) - (logior (ash ,subop 14) hint)))))) - (define-jump jmp 0) - (define-jump jsr 1) - (define-jump ret 2) - (define-jump jsr-coroutine 3)) - - -(macrolet ((define-branch (name op &optional (float nil)) - `(define-instruction ,name (segment ra target) - (:declare (type tn ra) - (type label target)) - (:printer branch ((op ,op) - ,@(when float - '((ra nil :type 'fp-reg))))) - (:emitter - (emit-back-patch segment 4 - (lambda (segment posn) - (emit-branch segment ,op - ,@(if float - '((fp-reg-tn-encoding ra)) - '((reg-tn-encoding ra))) - (ash (- (label-position target) - (+ posn 4)) - -2)))))))) - (define-branch br #x30) - (define-branch bsr #x34) - (define-branch blbc #x38) - (define-branch blbs #x3c) - (define-branch fbeq #x31 t) - (define-branch fbne #x35 t) - (define-branch beq #x39) - (define-branch bne #x3d) - (define-branch fblt #x32 t) - (define-branch fbge #x36 t) - (define-branch blt #x3a) - (define-branch bge #x3e) - (define-branch fble #x33 t) - (define-branch fbgt #x37 t) - (define-branch ble #x3b) - (define-branch bgt #x3f)) - -(macrolet ((define-operate (name op fn) - `(define-instruction ,name (segment ra rb rc) - (:declare (type tn ra rc) - (type (or tn (unsigned-byte 8)) rb)) - (:printer reg-operate ((op ,op) (fn ,fn))) - (:printer lit-operate ((op ,op) (fn ,fn))) - ,@(when (and (= op #x11) (= fn #x20)) - `((:printer reg-operate ((op ,op) (fn ,fn) (ra 31)) - '('move :tab rb "," rc)) - (:printer reg-operate ((op ,op) (fn ,fn) (ra 31) (rb 31) (rc 31)) - '('nop)))) - (:emitter - (etypecase rb - (tn - (emit-reg-operate segment ,op (reg-tn-encoding ra) - (reg-tn-encoding rb) 0 0 ,fn (reg-tn-encoding rc))) - (number - (emit-lit-operate segment ,op (reg-tn-encoding ra) rb 1 ,fn - (reg-tn-encoding rc)))))))) - (define-operate addl #x10 #x00) - (define-operate addl/v #x10 #x40) - (define-operate addq #x10 #x20) - (define-operate addq/v #x10 #x60) - (define-operate cmpule #x10 #x3d) - (define-operate cmpbge #x10 #x0f) - (define-operate subl #x10 #x09) - (define-operate subl/v #x10 #x49) - (define-operate subq #x10 #x29) - (define-operate subq/v #x10 #x69) - (define-operate cmpeq #x10 #x2d) - (define-operate cmplt #x10 #x4d) - (define-operate cmple #x10 #x6d) - (define-operate cmpult #x10 #x1d) - (define-operate s4addl #x10 #x02) - (define-operate s4addq #x10 #x22) - (define-operate s4subl #x10 #x0b) - (define-operate s4subq #x10 #x2b) - (define-operate s8addl #x10 #x12) - (define-operate s8addq #x10 #x32) - (define-operate s8subl #x10 #x1b) - (define-operate s8subq #x10 #x3b) - - (define-operate and #x11 #x00) - (define-operate bic #x11 #x08) - (define-operate cmoveq #x11 #x24) - (define-operate cmovne #x11 #x26) - (define-operate cmovlbs #x11 #x14) - (define-operate bis #x11 #x20) - (define-operate ornot #x11 #x28) - (define-operate cmovlt #x11 #x44) - (define-operate cmovge #x11 #x46) - (define-operate cmovlbc #x11 #x16) - (define-operate xor #x11 #x40) - (define-operate eqv #x11 #x48) - (define-operate cmovle #x11 #x64) - (define-operate cmovgt #x11 #x66) - - (define-operate sll #x12 #x39) - (define-operate extbl #x12 #x06) - (define-operate extwl #x12 #x16) - (define-operate extll #x12 #x26) - (define-operate extql #x12 #x36) - (define-operate extwh #x12 #x5a) - (define-operate extlh #x12 #x6a) - (define-operate extqh #x12 #x7a) - (define-operate sra #x12 #x3c) - (define-operate insbl #x12 #x0b) - (define-operate inswl #x12 #x1b) - (define-operate insll #x12 #x2b) - (define-operate insql #x12 #x3b) - (define-operate inswh #x12 #x57) - (define-operate inslh #x12 #x67) - (define-operate insqh #x12 #x77) - (define-operate srl #x12 #x34) - (define-operate mskbl #x12 #x02) - (define-operate mskwl #x12 #x12) - (define-operate mskll #x12 #x22) - (define-operate mskql #x12 #x32) - (define-operate mskwh #x12 #x52) - (define-operate msklh #x12 #x62) - (define-operate mskqh #x12 #x72) - (define-operate zap #x12 #x30) - (define-operate zapnot #x12 #x31) - - (define-operate mull #x13 #x00) - (define-operate mulq/v #x13 #x60) - (define-operate mull/v #x13 #x40) - (define-operate umulh #x13 #x30) - (define-operate mulq #x13 #x20) - - (define-operate ctpop #x1c #x30) ; CIX extension - (define-operate ctlz #x1c #x32) ; CIX extension - (define-operate cttz #x1c #x33)) ; CIX extension - - -(macrolet ((define-fp-operate (name op fn &optional (args 3)) - `(define-instruction ,name (segment ,@(when (= args 3) '(fa)) fb fc) - (:declare (type tn ,@(when (= args 3) '(fa)) fb fc)) - (:printer fp-operate ((op ,op) (fn ,fn) ,@(when (= args 2) '((fa 31)))) - ,@(when (= args 2) - '('(:name :tab fb "," fc)))) - ,@(when (and (= op #x17) (= fn #x20)) - `((:printer fp-operate ((op ,op) (fn ,fn) (fa 31)) - '('fabs :tab fb "," fc)))) - (:emitter - (emit-fp-operate segment ,op ,@(if (= args 3) - '((fp-reg-tn-encoding fa)) - '(31)) - (fp-reg-tn-encoding fb) ,fn (fp-reg-tn-encoding fc)))))) - (define-fp-operate cpys #x17 #x020) - (define-fp-operate mf_fpcr #x17 #x025) - (define-fp-operate cpysn #x17 #x021) - (define-fp-operate mt_fpcr #x17 #x024) - (define-fp-operate cpyse #x17 #x022) - (define-fp-operate cvtql/sv #x17 #x530 2) - (define-fp-operate cvtlq #x17 #x010 2) - (define-fp-operate cvtql #x17 #x030 2) - (define-fp-operate cvtql/v #x17 #x130 2) - (define-fp-operate fcmoveq #x17 #x02a) - (define-fp-operate fcmovne #x17 #x02b) - (define-fp-operate fcmovlt #x17 #x02c) - (define-fp-operate fcmovge #x17 #x02d) - (define-fp-operate fcmovle #x17 #x02e) - (define-fp-operate fcmovgt #x17 #x02f) - - (define-fp-operate cvtqs #x16 #x0bc 2) - (define-fp-operate cvtqt #x16 #x0be 2) - (define-fp-operate cvtts #x16 #x0ac 2) - (define-fp-operate cvttq #x16 #x0af 2) - (define-fp-operate cvttq/c #x16 #x02f 2) - (define-fp-operate cmpteq #x16 #x5a5) - (define-fp-operate cmptlt #x16 #x5a6) - (define-fp-operate cmptle #x16 #x5a7) - (define-fp-operate cmptun #x16 #x5a4) - (define-fp-operate adds #x16 #x080) - (define-fp-operate addt #x16 #x0a0) - (define-fp-operate divs #x16 #x083) - (define-fp-operate divt #x16 #x0a3) - (define-fp-operate muls #x16 #x082) - (define-fp-operate mult #x16 #x0a2) - (define-fp-operate subs #x16 #x081) - (define-fp-operate subt #x16 #x0a1) - -;;; IEEE support - (defconstant +su+ #x500) ; software, underflow enabled - (defconstant +sui+ #x700) ; software, inexact & underflow enabled - (defconstant +sv+ #x500) ; software, interger overflow enabled - (defconstant +svi+ #x700) - (defconstant +rnd+ #x0c0) ; dynamic rounding mode - (defconstant +sud+ #x5c0) - (defconstant +svid+ #x7c0) - (defconstant +suid+ #x7c0) - - (define-fp-operate cvtqs_su #x16 (logior +su+ #x0bc) 2) - (define-fp-operate cvtqs_sui #x16 (logior +sui+ #x0bc) 2) - (define-fp-operate cvtqt_su #x16 (logior +su+ #x0be) 2) - (define-fp-operate cvtqt_sui #x16 (logior +sui+ #x0be) 2) - (define-fp-operate cvtts_su #x16 (logior +su+ #x0ac) 2) - - (define-fp-operate cvttq_sv #x16 (logior +su+ #x0af) 2) - (define-fp-operate cvttq/c_sv #x16 (logior +su+ #x02f) 2) - - (define-fp-operate adds_su #x16 (logior +su+ #x080)) - (define-fp-operate addt_su #x16 (logior +su+ #x0a0)) - (define-fp-operate divs_su #x16 (logior +su+ #x083)) - (define-fp-operate divt_su #x16 (logior +su+ #x0a3)) - (define-fp-operate muls_su #x16 (logior +su+ #x082)) - (define-fp-operate mult_su #x16 (logior +su+ #x0a2)) - (define-fp-operate subs_su #x16 (logior +su+ #x081)) - (define-fp-operate subt_su #x16 (logior +su+ #x0a1))) - -(define-instruction excb (segment) - (:emitter (emit-lword segment #x63ff0400))) - -(define-instruction trapb (segment) - (:emitter (emit-lword segment #x63ff0000))) - -(define-instruction imb (segment) - (:emitter (emit-lword segment #x00000086))) - -(define-instruction gentrap (segment code) - (:printer bugchk () :default - :control #'bugchk-trap-control) - (:emitter - (emit-lword segment #x000081) ;actually bugchk - (emit-lword segment code))) - -(define-instruction-macro move (src dst) - `(inst bis zero-tn ,src ,dst)) - -(define-instruction-macro not (src dst) - `(inst ornot zero-tn ,src ,dst)) - -(define-instruction-macro fmove (src dst) - `(inst cpys ,src ,src ,dst)) - -(define-instruction-macro fabs (src dst) - `(inst cpys fp-single-zero-tn ,src ,dst)) - -(define-instruction-macro fneg (src dst) - `(inst cpysn ,src ,src ,dst)) - -(define-instruction-macro nop () - `(inst bis zero-tn zero-tn zero-tn)) - -(defun %li (value reg) - (etypecase value - ((signed-byte 16) - (inst lda reg value zero-tn)) - ((signed-byte 32) - (flet ((se (x n) - (let ((x (logand x (lognot (ash -1 n))))) - (if (logbitp (1- n) x) - (logior (ash -1 (1- n)) x) - x)))) - (let* ((value (se value 32)) - (low (ldb (byte 16 0) value)) - (tmp1 (- value (se low 16))) - (high (ldb (byte 16 16) tmp1)) - (tmp2 (- tmp1 (se (ash high 16) 32))) - (extra 0)) - (unless (= tmp2 0) - (setf extra #x4000) - (setf tmp1 (- tmp1 #x40000000)) - (setf high (ldb (byte 16 16) tmp1))) - (inst lda reg low zero-tn) - (unless (= extra 0) - (inst ldah reg extra reg)) - (unless (= high 0) - (inst ldah reg high reg))))) - ((or (unsigned-byte 32) (signed-byte 64) (unsigned-byte 64)) - ;; Since it took NJF and CSR a good deal of puzzling to work out - ;; (a) what a previous version of this was doing and (b) why it - ;; was wrong: - ;; - ;; write VALUE = a_63 * 2^63 + a_48-62 * 2^48 - ;; + a_47 * 2^47 + a_32-46 * 2^32 - ;; + a_31 * 2^31 + a_16-30 * 2^16 - ;; + a_15 * 2^15 + a_0-14 - ;; - ;; then, because of the wonders of sign-extension and - ;; twos-complement arithmetic modulo 2^64, if a_15 is set, LDA - ;; (which sign-extends its argument) will add - ;; - ;; (a_15 * 2^15 + a_0-14 - 65536). - ;; - ;; So we need to add that 65536 back on, which is what this - ;; LOGBITP business is doing. The same applies for bits 31 and - ;; 47 (bit 63 is taken care of by the fact that all of this - ;; arithmetic is mod 2^64 anyway), but we have to be careful that - ;; we consider the altered value, not the original value. - ;; - ;; I think, anyway. -- CSR, 2003-09-26 - (let* ((value1 (if (logbitp 15 value) (+ value (ash 1 16)) value)) - (value2 (if (logbitp 31 value1) (+ value1 (ash 1 32)) value1)) - (value3 (if (logbitp 47 value2) (+ value2 (ash 1 48)) value2))) - (inst lda reg (ldb (byte 16 32) value2) zero-tn) - ;; FIXME: Don't yet understand these conditionals. If I'm - ;; right, surely we can just consider the zeroness of the - ;; particular bitfield, not the zeroness of the whole thing? - ;; -- CSR, 2003-09-26 - (unless (= value3 0) - (inst ldah reg (ldb (byte 16 48) value3) reg)) - (unless (and (= value2 0) (= value3 0)) - (inst sll reg 32 reg)) - (unless (= value 0) - (inst lda reg (ldb (byte 16 0) value) reg)) - (unless (= value1 0) - (inst ldah reg (ldb (byte 16 16) value1) reg)))) - (fixup - (inst lda reg value zero-tn :bits-47-32) - (inst ldah reg value reg :bits-63-48) - (inst sll reg 32 reg) - (inst lda reg value reg) - (inst ldah reg value reg)))) - -(define-instruction-macro li (value reg) - `(%li ,value ,reg)) - - -;;;; - -(define-instruction lword (segment lword) - (:declare (type (or (unsigned-byte 32) (signed-byte 32) fixup) lword)) - (:cost 0) - (:emitter - (etypecase lword - (fixup - (note-fixup segment :absolute32 lword) - (emit-lword segment 0)) - (integer - (emit-lword segment lword))))) - -(define-instruction short (segment word) - (:declare (type (or (unsigned-byte 16) (signed-byte 16)) word)) - (:cost 0) - (:emitter - (emit-word segment word))) - -(define-instruction byte (segment byte) - (:declare (type (or (unsigned-byte 8) (signed-byte 8)) byte)) - (:cost 0) - (:emitter - (emit-byte segment byte))) - -(defun emit-header-data (segment type) - (emit-back-patch - segment 4 - (lambda (segment posn) - (emit-lword segment - (logior type - (ash (+ posn (component-header-length)) - (- n-widetag-bits word-shift))))))) - -(define-instruction simple-fun-header-word (segment) - (:cost 0) - (:emitter - (emit-header-data segment simple-fun-widetag))) - -(define-instruction lra-header-word (segment) - (:cost 0) - (:emitter - (emit-header-data segment return-pc-widetag))) - -(defun emit-compute-inst (segment vop dst src label temp calc) - (declare (ignore temp)) - (emit-chooser - ;; We emit either 12 or 4 bytes, so we maintain 8 byte alignments. - segment 12 3 - (lambda (segment chooser posn delta-if-after) - (declare (ignore chooser)) - (let ((delta (funcall calc label posn delta-if-after))) - (when (<= (- (ash 1 15)) delta (1- (ash 1 15))) - (emit-back-patch segment 4 - (lambda (segment posn) - (assemble (segment vop) - (inst lda dst - (funcall calc label posn 0) - src)))) - t))) - (lambda (segment posn) - (assemble (segment vop) - (flet ((se (x n) - (let ((x (logand x (lognot (ash -1 n))))) - (if (logbitp (1- n) x) - (logior (ash -1 (1- n)) x) - x)))) - (let* ((value (se (funcall calc label posn 0) 32)) - (low (ldb (byte 16 0) value)) - (tmp1 (- value (se low 16))) - (high (ldb (byte 16 16) tmp1)) - (tmp2 (- tmp1 (se (ash high 16) 32))) - (extra 0)) - (unless (= tmp2 0) - (setf extra #x4000) - (setf tmp1 (- tmp1 #x40000000)) - (setf high (ldb (byte 16 16) tmp1))) - (inst lda dst low src) - (inst ldah dst extra dst) - (inst ldah dst high dst))))))) - -;; code = lip - header - label-offset + other-pointer-tag -(define-instruction compute-code-from-lip (segment dst src label temp) - (:declare (type tn dst src temp) (type label label)) - (:vop-var vop) - (:emitter - (emit-compute-inst segment vop dst src label temp - (lambda (label posn delta-if-after) - (- other-pointer-lowtag - (label-position label posn delta-if-after) - (component-header-length)))))) - -;; code = lra - other-pointer-tag - header - label-offset + other-pointer-tag -;; = lra - (header + label-offset) -(define-instruction compute-code-from-lra (segment dst src label temp) - (:declare (type tn dst src temp) (type label label)) - (:vop-var vop) - (:emitter - (emit-compute-inst segment vop dst src label temp - (lambda (label posn delta-if-after) - (- (+ (label-position label posn delta-if-after) - (component-header-length))))))) - -;; lra = code + other-pointer-tag + header + label-offset - other-pointer-tag -;; = code + header + label-offset -(define-instruction compute-lra-from-code (segment dst src label temp) - (:declare (type tn dst src temp) (type label label)) - (:vop-var vop) - (:emitter - (emit-compute-inst segment vop dst src label temp - (lambda (label posn delta-if-after) - (+ (label-position label posn delta-if-after) - (component-header-length)))))) diff --git a/src/compiler/alpha/macros.lisp b/src/compiler/alpha/macros.lisp deleted file mode 100644 index e67d20373c..0000000000 --- a/src/compiler/alpha/macros.lisp +++ /dev/null @@ -1,488 +0,0 @@ -;;;; various useful macros for generating Alpha code - -;;;; This software is part of the SBCL system. See the README file for -;;;; more information. -;;;; -;;;; This software is derived from the CMU CL system, which was -;;;; written at Carnegie Mellon University and released into the -;;;; public domain. The software is in the public domain and is -;;;; provided with absolutely no warranty. See the COPYING and CREDITS -;;;; files for more information. - -(in-package "SB-VM") - -;;; a handy macro for defining top level forms that depend on the -;;; compile environment -(defmacro expand (expr) - (let ((gensym (gensym))) - `(macrolet - ((,gensym () - ,expr)) - (,gensym)))) - -;;; instruction-like macros - -;;; c.f. x86 backend: -;;(defmacro move (dst src) -;; "Move SRC into DST unless they are location=." -;; (once-only ((n-dst dst) -;; (n-src src)) -;; `(unless (location= ,n-dst ,n-src) -;; (inst mov ,n-dst ,n-src)))) - -(defmacro move (src dst) - "Move SRC into DST unless they are location=." - (once-only ((n-src src) (n-dst dst)) - `(unless (location= ,n-src ,n-dst) - (inst move ,n-src ,n-dst)))) - -(defmacro loadw (result base &optional (offset 0) (lowtag 0)) - (once-only ((result result) (base base)) - `(inst ldl ,result (- (ash ,offset word-shift) ,lowtag) ,base))) - -(defmacro loadq (result base &optional (offset 0) (lowtag 0)) - (once-only ((result result) (base base)) - `(inst ldq ,result (- (ash ,offset word-shift) ,lowtag) ,base))) - -(defmacro storew (value base &optional (offset 0) (lowtag 0)) - (once-only ((value value) (base base) (offset offset) (lowtag lowtag)) - `(inst stl ,value (- (ash ,offset word-shift) ,lowtag) ,base))) - -(defmacro storeq (value base &optional (offset 0) (lowtag 0)) - (once-only ((value value) (base base) (offset offset) (lowtag lowtag)) - `(inst stq ,value (- (ash ,offset word-shift) ,lowtag) ,base))) - -(defmacro load-symbol (reg symbol) - (once-only ((reg reg) (symbol symbol)) - `(inst lda ,reg (static-symbol-offset ,symbol) null-tn))) - -(defmacro load-symbol-value (reg symbol) - `(inst ldl ,reg - (+ (static-symbol-offset ',symbol) - (ash symbol-value-slot word-shift) - (- other-pointer-lowtag)) - null-tn)) - -(defmacro store-symbol-value (reg symbol) - `(inst stl ,reg - (+ (static-symbol-offset ',symbol) - (ash symbol-value-slot word-shift) - (- other-pointer-lowtag)) - null-tn)) - -(defmacro load-type (target source &optional (offset 0)) - "Loads the type bits of a pointer into target independent of - byte-ordering issues." - (once-only ((n-target target) - (n-source source) - (n-offset offset)) - `(progn - (inst ldl ,n-target ,n-offset ,n-source) - (inst and ,n-target #xff ,n-target)))) - -;;; macros to handle the fact that we cannot use the machine native -;;; call and return instructions - -(defmacro lisp-jump (function lip) - "Jump to the lisp function FUNCTION. LIP is an interior-reg temporary." - `(progn - (inst lda ,lip (- (ash simple-fun-insts-offset word-shift) - fun-pointer-lowtag) - ,function) - (move ,function code-tn) - (inst jsr zero-tn ,lip 1))) - -(defmacro lisp-return (return-pc lip &key (offset 0) (frob-code t)) - "Return to RETURN-PC. LIP is an interior-reg temporary." - `(progn - (inst lda ,lip - (- (* (1+ ,offset) n-word-bytes) other-pointer-lowtag) - ,return-pc) - ,@(when frob-code - `((move ,return-pc code-tn))) - (inst ret zero-tn ,lip 1))) - - -(defmacro emit-return-pc (label) - "Emit a return-pc header word. LABEL is the label to use for this - return-pc." - `(progn - (emit-alignment n-lowtag-bits) - (emit-label ,label) - (inst lra-header-word))) - - - -;;;; stack TN's - -;;; Move a stack TN to a register and vice-versa. -(defmacro load-stack-tn (reg stack) - `(let ((reg ,reg) - (stack ,stack)) - (let ((offset (tn-offset stack))) - (sc-case stack - ((control-stack) - (loadw reg cfp-tn offset)))))) -(defmacro store-stack-tn (stack reg) - `(let ((stack ,stack) - (reg ,reg)) - (let ((offset (tn-offset stack))) - (sc-case stack - ((control-stack) - (storew reg cfp-tn offset)))))) - -;;; Move the TN Reg-Or-Stack into Reg if it isn't already there. -(defmacro maybe-load-stack-tn (reg reg-or-stack) - (once-only ((n-reg reg) - (n-stack reg-or-stack)) - `(sc-case ,n-reg - ((any-reg descriptor-reg) - (sc-case ,n-stack - ((any-reg descriptor-reg) - (move ,n-stack ,n-reg)) - ((control-stack) - (loadw ,n-reg cfp-tn (tn-offset ,n-stack)))))))) - -;;; Move the TN Reg-Or-Stack into Reg if it isn't already there. -(defmacro maybe-load-stack-nfp-tn (reg reg-or-stack temp) - (once-only ((n-reg reg) - (n-stack reg-or-stack)) - `(when ,reg - (sc-case ,n-reg - ((any-reg descriptor-reg) - (sc-case ,n-stack - ((any-reg descriptor-reg) - (move ,n-stack ,n-reg)) - ((control-stack) - (loadw ,n-reg cfp-tn (tn-offset ,n-stack)) - (inst mskll nsp-tn 0 ,temp) - (inst bis ,temp ,n-reg ,n-reg)))))))) - -;;;; storage allocation - -;;; Do stuff to allocate an other-pointer object of fixed SIZE with a -;;; single word header having the specified WIDETAG value. The result is -;;; placed in RESULT-TN, Flag-Tn must be wired to NL3-OFFSET, and -;;; Temp-TN is a non- descriptor temp (which may be randomly used by -;;; the body.) The body is placed inside the PSEUDO-ATOMIC, and -;;; presumably initializes the object. -(defmacro with-fixed-allocation ((result-tn temp-tn widetag size) - &body body) - (unless body - (bug "empty &body in WITH-FIXED-ALLOCATION")) - (once-only ((result-tn result-tn) (temp-tn temp-tn) (size size)) - `(pseudo-atomic (:extra (pad-data-block ,size)) - (inst bis alloc-tn other-pointer-lowtag ,result-tn) - (inst li (compute-object-header ,size ,widetag) ,temp-tn) - (storew ,temp-tn ,result-tn 0 other-pointer-lowtag) - ,@body))) - -(defun align-csp (temp) - ;; is used for stack allocation of dynamic-extent objects - (let ((aligned (gen-label))) - (inst and csp-tn lowtag-mask temp) - (inst beq temp aligned) - (inst addq csp-tn n-word-bytes csp-tn) - (storew zero-tn csp-tn -1) - (emit-label aligned))) - -;;;; error code -(defun emit-error-break (vop kind code values) - (assemble () - (when vop - (note-this-location vop :internal-error)) - (emit-internal-error kind code values - :trap-emitter (lambda (tramp-number) - (inst gentrap tramp-number))) - (emit-alignment word-shift))) - -(defun generate-error-code (vop error-code &rest values) - "Generate-Error-Code Error-code Value* - Emit code for an error with the specified Error-Code and context Values." - (assemble (:elsewhere) - (let ((start-lab (gen-label))) - (emit-label start-lab) - (apply #'error-call vop error-code values) - start-lab))) - -;;; a handy macro for making sequences look atomic -(defmacro pseudo-atomic ((&key (extra 0)) &rest forms) - `(progn - (inst addq alloc-tn 1 alloc-tn) - ,@forms - (inst lda alloc-tn (1- ,extra) alloc-tn) - (inst stl zero-tn 0 alloc-tn))) - -;;;; memory accessor vop generators - -(sb-xc:deftype load/store-index (scale lowtag min-offset - &optional (max-offset min-offset)) - `(integer ,(- (truncate (+ (ash 1 16) - (* min-offset sb-vm:n-word-bytes) - (- lowtag)) - scale)) - ,(truncate (- (+ (1- (ash 1 16)) lowtag) - (* max-offset sb-vm:n-word-bytes)) - scale))) - -(defmacro define-full-reffer (name type offset lowtag scs el-type - &optional translate) - `(progn - (define-vop (,name) - ,@(when translate - `((:translate ,translate))) - (:policy :fast-safe) - (:args (object :scs (descriptor-reg)) - (index :scs (any-reg))) - (:arg-types ,type tagged-num) - (:temporary (:scs (interior-reg)) lip) - (:results (value :scs ,scs)) - (:result-types ,el-type) - (:generator 5 - (inst addq object index lip) - (inst ldl value (- (* ,offset n-word-bytes) ,lowtag) lip) - ,@(when (equal scs '(unsigned-reg)) - '((inst mskll value 4 value))))) - (define-vop (,(symbolicate name "-C")) - ,@(when translate - `((:translate ,translate))) - (:policy :fast-safe) - (:args (object :scs (descriptor-reg))) - (:info index) - (:arg-types ,type - (:constant (load/store-index ,n-word-bytes ,(eval lowtag) - ,(eval offset)))) - (:results (value :scs ,scs)) - (:result-types ,el-type) - (:generator 4 - (inst ldl value (- (* (+ ,offset index) n-word-bytes) ,lowtag) - object) - ,@(when (equal scs '(unsigned-reg)) - '((inst mskll value 4 value))))))) - -(defmacro define-full-setter (name type offset lowtag scs el-type - &optional translate #+gengc (remember t)) - `(progn - (define-vop (,name) - ,@(when translate - `((:translate ,translate))) - (:policy :fast-safe) - (:args (object :scs (descriptor-reg)) - (index :scs (any-reg)) - (value :scs ,scs :target result)) - (:arg-types ,type tagged-num ,el-type) - (:temporary (:scs (interior-reg)) lip) - (:results (result :scs ,scs)) - (:result-types ,el-type) - (:generator 2 - (inst addq index object lip) - (inst stl value (- (* ,offset n-word-bytes) ,lowtag) lip) - (move value result))) - (define-vop (,(symbolicate name "-C")) - ,@(when translate - `((:translate ,translate))) - (:policy :fast-safe) - (:args (object :scs (descriptor-reg)) - (value :scs ,scs)) - (:info index) - (:arg-types ,type - (:constant (load/store-index ,n-word-bytes ,(eval lowtag) - ,(eval offset))) - ,el-type) - (:results (result :scs ,scs)) - (:result-types ,el-type) - (:generator 1 - (inst stl value (- (* (+ ,offset index) n-word-bytes) ,lowtag) - object) - (move value result))))) - - -(defmacro define-partial-reffer (name type size signed offset lowtag scs - el-type &optional translate) - (let ((scale (ecase size (:byte 1) (:short 2)))) - `(progn - (define-vop (,name) - ,@(when translate - `((:translate ,translate))) - (:policy :fast-safe) - (:args (object :scs (descriptor-reg)) - (index :scs (unsigned-reg))) - (:arg-types ,type positive-fixnum) - (:results (value :scs ,scs)) - (:result-types ,el-type) - (:temporary (:scs (interior-reg)) lip) - (:temporary (:sc non-descriptor-reg) temp) - (:temporary (:sc non-descriptor-reg) temp1) - (:generator 5 - (inst addq object index lip) - ,@(when (eq size :short) - '((inst addq index lip lip))) - ,@(ecase size - (:byte - (if signed - `((inst ldq_u temp (- (* ,offset n-word-bytes) ,lowtag) - lip) - (inst lda temp1 (1+ (- (* ,offset n-word-bytes) ,lowtag)) - lip) - (inst extqh temp temp1 temp) - (inst sra temp 56 value)) - `((inst ldq_u - temp - (- (* ,offset n-word-bytes) ,lowtag) - lip) - (inst lda temp1 (- (* ,offset n-word-bytes) ,lowtag) - lip) - (inst extbl temp temp1 value)))) - (:short - (if signed - `((inst ldq_u temp (- (* ,offset n-word-bytes) ,lowtag) - lip) - (inst lda temp1 (- (* ,offset n-word-bytes) ,lowtag) - lip) - (inst extwl temp temp1 temp) - (inst sll temp 48 temp) - (inst sra temp 48 value)) - `((inst ldq_u temp (- (* ,offset n-word-bytes) ,lowtag) - lip) - (inst lda temp1 (- (* ,offset n-word-bytes) ,lowtag) lip) - (inst extwl temp temp1 value))))))) - (define-vop (,(symbolicate name "-C")) - ,@(when translate - `((:translate ,translate))) - (:policy :fast-safe) - (:args (object :scs (descriptor-reg))) - (:info index) - (:arg-types ,type - (:constant (load/store-index ,scale - ,(eval lowtag) - ,(eval offset)))) - (:results (value :scs ,scs)) - (:result-types ,el-type) - (:temporary (:sc non-descriptor-reg) temp) - (:temporary (:sc non-descriptor-reg) temp1) - (:generator 4 - ,@(ecase size - (:byte - (if signed - `((inst ldq_u temp (- (+ (* ,offset n-word-bytes) - (* index ,scale)) ,lowtag) - object) - (inst lda temp1 (1+ (- (+ (* ,offset n-word-bytes) - (* index ,scale)) ,lowtag)) - object) - (inst extqh temp temp1 temp) - (inst sra temp 56 value)) - `((inst ldq_u temp (- (+ (* ,offset n-word-bytes) - (* index ,scale)) ,lowtag) - object) - (inst lda temp1 (- (+ (* ,offset n-word-bytes) - (* index ,scale)) ,lowtag) - object) - (inst extbl temp temp1 value)))) - (:short - (if signed - `((inst ldq_u temp (- (+ (* ,offset n-word-bytes) - (* index ,scale)) ,lowtag) - object) - (inst lda temp1 (- (+ (* ,offset n-word-bytes) - (* index ,scale)) ,lowtag) - object) - (inst extwl temp temp1 temp) - (inst sll temp 48 temp) - (inst sra temp 48 value)) - `((inst ldq_u temp (- (+ (* ,offset n-word-bytes) - (* index ,scale)) ,lowtag) - object) - (inst lda temp1 (- (+ (* ,offset n-word-bytes) - (* index ,scale)) ,lowtag) - object) - (inst extwl temp temp1 value)))))))))) - -(defmacro define-partial-setter (name type size offset lowtag scs el-type - &optional translate) - (let ((scale (ecase size (:byte 1) (:short 2)))) - `(progn - (define-vop (,name) - ,@(when translate - `((:translate ,translate))) - (:policy :fast-safe) - (:args (object :scs (descriptor-reg)) - (index :scs (unsigned-reg)) - (value :scs ,scs :target result)) - (:arg-types ,type positive-fixnum ,el-type) - (:temporary (:scs (interior-reg)) lip) - (:temporary (:sc non-descriptor-reg) temp) - (:temporary (:sc non-descriptor-reg) temp1) - (:temporary (:sc non-descriptor-reg) temp2) - (:results (result :scs ,scs)) - (:result-types ,el-type) - (:generator 5 - (inst addq object index lip) - ,@(when (eq size :short) - '((inst addq lip index lip))) - ,@(ecase size - (:byte - `((inst lda temp (- (* ,offset n-word-bytes) ,lowtag) lip) - (inst ldq_u temp1 (- (* ,offset n-word-bytes) ,lowtag) lip) - (inst insbl value temp temp2) - (inst mskbl temp1 temp temp1) - (inst bis temp1 temp2 temp1) - (inst stq_u temp1 (- (* ,offset n-word-bytes) ,lowtag) lip))) - (:short - `((inst lda temp (- (* ,offset n-word-bytes) ,lowtag) lip) - (inst ldq_u temp1 (- (* ,offset n-word-bytes) ,lowtag) lip) - (inst mskwl temp1 temp temp1) - (inst inswl value temp temp2) - (inst bis temp1 temp2 temp) - (inst stq_u temp (- (* ,offset n-word-bytes) ,lowtag) lip)))) - (move value result))) - (define-vop (,(symbolicate name "-C")) - ,@(when translate - `((:translate ,translate))) - (:policy :fast-safe) - (:args (object :scs (descriptor-reg)) - (value :scs ,scs :target result)) - (:info index) - (:arg-types ,type - (:constant (load/store-index ,scale - ,(eval lowtag) - ,(eval offset))) - ,el-type) - (:temporary (:sc non-descriptor-reg) temp) - (:temporary (:sc non-descriptor-reg) temp1) - (:temporary (:sc non-descriptor-reg) temp2) - (:results (result :scs ,scs)) - (:result-types ,el-type) - (:generator 4 - ,@(ecase size - (:byte - `((inst lda temp (- (+ (* ,offset n-word-bytes) - (* index ,scale)) - ,lowtag) - object) - (inst ldq_u temp1 (- (+ (* ,offset n-word-bytes) - (* index ,scale)) - ,lowtag) - object) - (inst insbl value temp temp2) - (inst mskbl temp1 temp temp1) - (inst bis temp1 temp2 temp1) - (inst stq_u temp1 (- (+ (* ,offset n-word-bytes) - (* index ,scale)) - ,lowtag) object))) - (:short - `((inst lda temp (- (+ (* ,offset n-word-bytes) - (* index ,scale)) - ,lowtag) - object) - (inst ldq_u temp1 (- (+ (* ,offset n-word-bytes) - (* index ,scale)) - ,lowtag) - object) - (inst mskwl temp1 temp temp1) - (inst inswl value temp temp2) - (inst bis temp1 temp2 temp) - (inst stq_u temp (- (+ (* ,offset n-word-bytes) - (* index ,scale)) - ,lowtag) object)))) - (move value result)))))) diff --git a/src/compiler/alpha/memory.lisp b/src/compiler/alpha/memory.lisp deleted file mode 100644 index 7ef8470611..0000000000 --- a/src/compiler/alpha/memory.lisp +++ /dev/null @@ -1,30 +0,0 @@ -;;;; the Alpha definitions of some general purpose memory reference -;;;; VOPs inherited by basic memory reference operations - -;;;; This software is part of the SBCL system. See the README file for -;;;; more information. -;;;; -;;;; This software is derived from the CMU CL system, which was -;;;; written at Carnegie Mellon University and released into the -;;;; public domain. The software is in the public domain and is -;;;; provided with absolutely no warranty. See the COPYING and CREDITS -;;;; files for more information. - -(in-package "SB-VM") - -;;; Cell-Ref and Cell-Set are used to define VOPs like CAR, where the -;;; offset to be read or written is a property of the VOP used. -(define-vop (cell-ref) - (:args (object :scs (descriptor-reg))) - (:results (value :scs (descriptor-reg any-reg))) - (:variant-vars offset lowtag) - (:policy :fast-safe) - (:generator 4 - (loadw value object offset lowtag))) -(define-vop (cell-set) - (:args (object :scs (descriptor-reg)) - (value :scs (descriptor-reg any-reg null zero))) - (:variant-vars offset lowtag) - (:policy :fast-safe) - (:generator 4 - (storew value object offset lowtag))) diff --git a/src/compiler/alpha/move.lisp b/src/compiler/alpha/move.lisp deleted file mode 100644 index f54b15faf2..0000000000 --- a/src/compiler/alpha/move.lisp +++ /dev/null @@ -1,317 +0,0 @@ -;;;; the Alpha VM definition of operand loading/saving and the Move VOP - -;;;; This software is part of the SBCL system. See the README file for -;;;; more information. -;;;; -;;;; This software is derived from the CMU CL system, which was -;;;; written at Carnegie Mellon University and released into the -;;;; public domain. The software is in the public domain and is -;;;; provided with absolutely no warranty. See the COPYING and CREDITS -;;;; files for more information. - -(in-package "SB-VM") - -(define-move-fun (load-immediate 1) (vop x y) - ((null zero immediate) - (any-reg descriptor-reg)) - (let ((val (tn-value x))) - (etypecase val - (integer - (inst li (fixnumize val) y)) - (null - (move null-tn y)) - (symbol - (load-symbol y val)) - (character - (inst li (logior (ash (char-code val) n-widetag-bits) character-widetag) - y))))) - -(define-move-fun (load-number 1) (vop x y) - ((zero immediate) - (signed-reg unsigned-reg)) - (inst li (tn-value x) y)) - -(define-move-fun (load-character 1) (vop x y) - ((immediate) (character-reg)) - (inst li (char-code (tn-value x)) y)) - -(define-move-fun (load-system-area-pointer 1) (vop x y) - ((immediate) (sap-reg)) - (inst li (sap-int (tn-value x)) y)) - -(define-move-fun (load-constant 5) (vop x y) - ((constant) (descriptor-reg any-reg)) - (loadw y code-tn (tn-offset x) other-pointer-lowtag)) - -(define-move-fun (load-stack 5) (vop x y) - ((control-stack) (any-reg descriptor-reg)) - (load-stack-tn y x)) - -(define-move-fun (load-number-stack 5) (vop x y) - ((character-stack) (character-reg)) - (let ((nfp (current-nfp-tn vop))) - (loadw y nfp (tn-offset x)))) - -(define-move-fun (load-number-stack-64 5) (vop x y) - ((sap-stack) (sap-reg) - (signed-stack) (signed-reg) - (unsigned-stack) (unsigned-reg)) - (let ((nfp (current-nfp-tn vop))) - (loadq y nfp (tn-offset x)))) - -(define-move-fun (store-stack 5) (vop x y) - ((any-reg descriptor-reg null zero) (control-stack)) - (store-stack-tn y x)) - -(define-move-fun (store-number-stack 5) (vop x y) - ((character-reg) (character-stack)) - (let ((nfp (current-nfp-tn vop))) - (storew x nfp (tn-offset y)))) - -(define-move-fun (store-number-stack-64 5) (vop x y) - ((sap-reg) (sap-stack) - (signed-reg) (signed-stack) - (unsigned-reg) (unsigned-stack)) - (let ((nfp (current-nfp-tn vop))) - (storeq x nfp (tn-offset y)))) - -;;;; the MOVE VOP - -(define-vop (move) - (:args (x :target y - :scs (any-reg descriptor-reg zero null) - :load-if (not (location= x y)))) - (:results (y :scs (any-reg descriptor-reg control-stack) - :load-if (not (location= x y)))) - (:generator 0 - (unless (location= x y) - (sc-case y - ((any-reg descriptor-reg) - (inst move x y)) - (control-stack - (store-stack-tn y x)))))) - -(define-move-vop move :move - (any-reg descriptor-reg zero null) - (any-reg descriptor-reg)) - -;;; The MOVE-ARG VOP is used for moving descriptor values into -;;; another frame for argument or known value passing. -(define-vop (move-arg) - (:args (x :target y - :scs (any-reg descriptor-reg null zero)) - (fp :scs (any-reg) - :load-if (not (sc-is y any-reg descriptor-reg)))) - (:results (y)) - (:generator 0 - (sc-case y - ((any-reg descriptor-reg) - (move x y)) - (control-stack - (storew x fp (tn-offset y)))))) -;;; -(define-move-vop move-arg :move-arg - (any-reg descriptor-reg null zero) - (any-reg descriptor-reg)) - -;;;; moves and coercions -;;;; -;;;; These MOVE-TO-WORD VOPs move a tagged integer to a raw full-word -;;;; representation. Similarly, the MOVE-FROM-WORD VOPs converts a raw -;;;; integer to a tagged bignum or fixnum. - -;;; ARG is a fixnum, so just shift it. We need a type restriction -;;; because some possible arg SCs (control-stack) overlap with -;;; possible bignum arg SCs. -(define-vop (move-to-word/fixnum) - (:args (x :scs (any-reg descriptor-reg))) - (:results (y :scs (signed-reg unsigned-reg))) - (:arg-types tagged-num) - (:note "fixnum untagging") - (:generator 1 - (inst sra x n-fixnum-tag-bits y))) -(define-move-vop move-to-word/fixnum :move - (any-reg descriptor-reg) (signed-reg unsigned-reg)) - -;;; ARG is a non-immediate constant, load it. -(define-vop (move-to-word-c) - (:args (x :scs (constant))) - (:results (y :scs (signed-reg unsigned-reg))) - (:note "constant load") - (:generator 1 - (cond ((sb-c::tn-leaf x) - (inst li (tn-value x) y)) - (t - (loadw y code-tn (tn-offset x) other-pointer-lowtag) - (inst sra y n-fixnum-tag-bits y))))) -(define-move-vop move-to-word-c :move - (constant) (signed-reg unsigned-reg)) - -;;; ARG is a fixnum or bignum, figure out which and load if necessary. -(define-vop (move-to-word/integer) - (:args (x :scs (descriptor-reg))) - (:results (y :scs (signed-reg unsigned-reg))) - (:note "integer to untagged word coercion") - (:temporary (:sc non-descriptor-reg) header) - (:temporary (:scs (non-descriptor-reg)) temp) - (:generator 3 - (inst and x fixnum-tag-mask temp) - (inst sra x n-fixnum-tag-bits y) - (inst beq temp done) - - (loadw header x 0 other-pointer-lowtag) - (inst srl header (1+ n-widetag-bits) header) - (loadw y x bignum-digits-offset other-pointer-lowtag) - (inst beq header one) - - (loadw header x (1+ bignum-digits-offset) other-pointer-lowtag) - (inst sll header 32 header) - (inst mskll y 4 y) - (inst bis header y y) - (inst br zero-tn done) - ONE - (when (sc-is y unsigned-reg) - (inst mskll y 4 y)) - DONE)) -(define-move-vop move-to-word/integer :move - (descriptor-reg) (signed-reg unsigned-reg)) - -;;; RESULT is a fixnum, so we can just shift. We need the result type -;;; restriction because of the control-stack ambiguity noted above. -(define-vop (move-from-word/fixnum) - (:args (x :scs (signed-reg unsigned-reg))) - (:results (y :scs (any-reg descriptor-reg))) - (:result-types tagged-num) - (:note "fixnum tagging") - (:generator 1 - (inst sll x n-fixnum-tag-bits y))) -(define-move-vop move-from-word/fixnum :move - (signed-reg unsigned-reg) (any-reg descriptor-reg)) - -;;; RESULT may be a bignum, so we have to check. Use a worst-case cost -;;; to make sure people know they may be number consing. -(define-vop (move-from-signed) - (:args (arg :scs (signed-reg unsigned-reg) :target x)) - (:results (y :scs (any-reg descriptor-reg))) - (:temporary (:scs (non-descriptor-reg) :from (:argument 0)) x temp) - (:temporary (:sc non-descriptor-reg) header) - (:note "signed word to integer coercion") - (:generator 18 - (move arg x) - (inst sra x n-positive-fixnum-bits temp) - (inst sll x n-fixnum-tag-bits y) - (inst beq temp done) - (inst not temp temp) - (inst beq temp done) - - (inst li 2 header) - (inst sra x 31 temp) - (inst cmoveq temp 1 header) - (inst not temp temp) - (inst cmoveq temp 1 header) - (inst sll header n-widetag-bits header) - (inst bis header bignum-widetag header) - - (pseudo-atomic (:extra (pad-data-block (+ bignum-digits-offset 3))) - (inst bis alloc-tn other-pointer-lowtag y) - (storew header y 0 other-pointer-lowtag) - (storew x y bignum-digits-offset other-pointer-lowtag) - (inst srl x 32 temp) - (storew temp y (1+ bignum-digits-offset) other-pointer-lowtag)) - DONE)) -(define-move-vop move-from-signed :move - (signed-reg) (descriptor-reg)) - -(define-vop (move-from-fixnum+1) - (:args (x :scs (signed-reg unsigned-reg))) - (:results (y :scs (any-reg descriptor-reg))) - (:temporary (:scs (non-descriptor-reg)) temp) - (:vop-var vop) - (:generator 4 - (inst sra x n-positive-fixnum-bits temp) - (inst sll x n-fixnum-tag-bits y) - (inst beq temp done) - (inst not temp temp) - (inst beq temp done) - (load-constant vop (emit-constant (1+ sb-xc:most-positive-fixnum)) - y) - DONE)) - -(define-vop (move-from-fixnum-1 move-from-fixnum+1) - (:generator 4 - (inst sra x n-positive-fixnum-bits temp) - (inst sll x n-fixnum-tag-bits y) - (inst beq temp done) - (inst not temp temp) - (inst beq temp done) - (load-constant vop (emit-constant (1- sb-xc:most-negative-fixnum)) - y) - DONE)) - -;;; Check for fixnum, and possibly allocate one or two word bignum -;;; result. Use a worst-case cost to make sure people know they may be -;;; number consing. -(define-vop (move-from-unsigned) - (:args (arg :scs (signed-reg unsigned-reg) :target x)) - (:results (y :scs (any-reg descriptor-reg))) - (:temporary (:scs (non-descriptor-reg) :from (:argument 0)) x temp) - (:temporary (:sc non-descriptor-reg) temp1) - (:note "unsigned word to integer coercion") - (:generator 20 - (move arg x) - (inst srl x n-positive-fixnum-bits temp) - (inst sll x n-fixnum-tag-bits y) - (inst beq temp done) - - (inst li 3 temp) - (inst cmovge x 2 temp) - (inst srl x 31 temp1) - (inst cmoveq temp1 1 temp) - (inst sll temp n-widetag-bits temp) - (inst bis temp bignum-widetag temp) - - (pseudo-atomic (:extra (pad-data-block (+ bignum-digits-offset 3))) - (inst bis alloc-tn other-pointer-lowtag y) - (storew temp y 0 other-pointer-lowtag) - (storew x y bignum-digits-offset other-pointer-lowtag) - (inst srl x 32 temp) - (storew temp y (1+ bignum-digits-offset) other-pointer-lowtag)) - DONE)) -(define-move-vop move-from-unsigned :move - (unsigned-reg) (descriptor-reg)) - -;;; Move untagged numbers. -(define-vop (word-move) - (:args (x :target y - :scs (signed-reg unsigned-reg) - :load-if (not (location= x y)))) - (:results (y :scs (signed-reg unsigned-reg) - :load-if (not (location= x y)))) - (:note "word integer move") - (:generator 0 - (move x y))) -(define-move-vop word-move :move - (signed-reg unsigned-reg) (signed-reg unsigned-reg)) - -;;; Move untagged number arguments/return-values. -(define-vop (move-word-arg) - (:args (x :target y - :scs (signed-reg unsigned-reg)) - (fp :scs (any-reg) - :load-if (not (sc-is y signed-reg unsigned-reg)))) - (:results (y)) - (:note "word integer argument move") - (:generator 0 - (sc-case y - ((signed-reg unsigned-reg) - (move x y)) - ((signed-stack unsigned-stack) - (storeq x fp (tn-offset y)))))) -(define-move-vop move-word-arg :move-arg - (descriptor-reg any-reg signed-reg unsigned-reg) (signed-reg unsigned-reg)) - - -;;; Use standard MOVE-ARG + coercion to move an untagged number -;;; to a descriptor passing location. -(define-move-vop move-arg :move-arg - (signed-reg unsigned-reg) (any-reg descriptor-reg)) diff --git a/src/compiler/alpha/nlx.lisp b/src/compiler/alpha/nlx.lisp deleted file mode 100644 index 8d78ac9864..0000000000 --- a/src/compiler/alpha/nlx.lisp +++ /dev/null @@ -1,261 +0,0 @@ -;;;; the definitions of VOPs used for non-local exit (THROW, lexical -;;;; exit, etc.) - -;;;; This software is part of the SBCL system. See the README file for -;;;; more information. -;;;; -;;;; This software is derived from the CMU CL system, which was -;;;; written at Carnegie Mellon University and released into the -;;;; public domain. The software is in the public domain and is -;;;; provided with absolutely no warranty. See the COPYING and CREDITS -;;;; files for more information. - -(in-package "SB-VM") - -;;; Make a TN for the argument count passing location for a -;;; non-local entry. -(defun make-nlx-entry-arg-start-location () - (make-wired-tn *fixnum-primitive-type* immediate-arg-scn ocfp-offset)) - -;;;; save and restoring the dynamic environment -;;;; -;;;; These VOPs are used in the reentered function to restore the -;;;; appropriate dynamic environment. Currently we only save the -;;;; CURRENT-CATCH and binding stack pointer. We don't need to -;;;; save/restore the current UNWIND-PROTECT, since UNWIND-PROTECTS -;;;; are implicitly processed during unwinding. If there were any -;;;; additional stacks (as e.g. there was an interpreter "eval stack" -;;;; before sbcl-0.7.0), then this would be the place to restore the -;;;; top pointers. - -(define-vop (save-dynamic-state) - (:results (catch :scs (descriptor-reg)) - (nfp :scs (descriptor-reg)) - (nsp :scs (descriptor-reg))) - (:vop-var vop) - (:generator 13 - (load-symbol-value catch *current-catch-block*) - (let ((cur-nfp (current-nfp-tn vop))) - (when cur-nfp - (inst mskll cur-nfp 4 nfp))) - (inst mskll nsp-tn 4 nsp))) - -(define-vop (restore-dynamic-state) - (:args (catch :scs (descriptor-reg)) - (nfp :scs (descriptor-reg)) - (nsp :scs (descriptor-reg))) - (:vop-var vop) - (:temporary (:sc any-reg) temp) - (:generator 10 - (store-symbol-value catch *current-catch-block*) - (inst mskll nsp-tn 0 temp) - (let ((cur-nfp (current-nfp-tn vop))) - (when cur-nfp - (inst bis nfp temp cur-nfp))) - (inst bis nsp temp nsp-tn))) - -(define-vop (current-stack-pointer) - (:results (res :scs (any-reg descriptor-reg))) - (:generator 1 - (move csp-tn res))) - -(define-vop (current-binding-pointer) - (:results (res :scs (any-reg descriptor-reg))) - (:generator 1 - (move bsp-tn res))) - -(define-vop (current-nsp) - (:results (res :scs (any-reg descriptor-reg))) - (:generator 1 - (move res nsp-tn))) - -(define-vop (set-nsp) - (:args (nsp :scs (any-reg descriptor-reg))) - (:generator 1 - (move nsp-tn nsp))) - -;;;; unwind block hackery - -;;; Compute the address of the catch block from its TN, then store -;;; into the block the current Fp, Env, Unwind-Protect, and the entry PC. -(define-vop (make-unwind-block) - (:args (tn)) - (:info entry-label) - (:results (block :scs (any-reg))) - (:temporary (:scs (descriptor-reg)) temp) - (:temporary (:scs (non-descriptor-reg)) ndescr) - (:generator 22 - (inst lda block (tn-byte-offset tn) cfp-tn) - (load-symbol-value temp *current-unwind-protect-block*) - (storew temp block unwind-block-uwp-slot) - (storew cfp-tn block unwind-block-cfp-slot) - (storew code-tn block unwind-block-code-slot) - (inst compute-lra-from-code temp code-tn entry-label ndescr) - (storew temp block catch-block-entry-pc-slot))) - - -;;; This is like Make-Unwind-Block, except that we also store in the -;;; specified tag, and link the block into the Current-Catch list. -(define-vop (make-catch-block) - (:args (tn) - (tag :scs (any-reg descriptor-reg))) - (:info entry-label) - (:results (block :scs (any-reg))) - (:temporary (:scs (descriptor-reg)) temp) - (:temporary (:scs (descriptor-reg) :target block :to (:result 0)) result) - (:temporary (:scs (non-descriptor-reg)) ndescr) - (:generator 44 - (inst lda result (tn-byte-offset tn) cfp-tn) - (load-symbol-value temp *current-unwind-protect-block*) - (storew temp result catch-block-uwp-slot) - (storew cfp-tn result catch-block-cfp-slot) - (storew code-tn result catch-block-code-slot) - (inst compute-lra-from-code temp code-tn entry-label ndescr) - (storew temp result catch-block-entry-pc-slot) - - (storew tag result catch-block-tag-slot) - (load-symbol-value temp *current-catch-block*) - (storew temp result catch-block-previous-catch-slot) - (store-symbol-value result *current-catch-block*) - - (move result block))) - -;;; Just set the current unwind-protect to UWP. This -;;; instantiates an unwind block as an unwind-protect. -(define-vop (set-unwind-protect) - (:args (uwp :scs (any-reg))) - (:generator 7 - (store-symbol-value uwp *current-unwind-protect-block*))) - -(define-vop (%catch-breakup) - (:args (current-block)) - (:ignore current-block) - (:temporary (:scs (any-reg)) block) - (:policy :fast-safe) - (:generator 17 - (load-symbol-value block *current-catch-block*) - (loadw block block catch-block-previous-catch-slot) - (store-symbol-value block *current-catch-block*))) - -(define-vop (%unwind-protect-breakup) - (:args (current-block)) - (:ignore current-block) - (:temporary (:scs (any-reg)) block) - (:policy :fast-safe) - (:generator 17 - (load-symbol-value block *current-unwind-protect-block*) - (loadw block block unwind-block-uwp-slot) - (store-symbol-value block *current-unwind-protect-block*))) - -;;;; NLX entry VOPs - -(define-vop (nlx-entry) - (:args (sp) ; Note: we can't list an sc-restriction, 'cause any load vops - ; would be inserted before the LRA. - (start) - (count)) - (:results (values :more t)) - (:temporary (:scs (descriptor-reg)) move-temp) - (:temporary (:sc non-descriptor-reg) temp) - (:info label nvals) - (:save-p :force-to-stack) - (:vop-var vop) - (:generator 30 - (emit-return-pc label) - (note-this-location vop :non-local-entry) - (cond ((zerop nvals)) - ((= nvals 1) - (let ((no-values (gen-label))) - (move null-tn (tn-ref-tn values)) - (inst beq count no-values) - (loadw (tn-ref-tn values) start) - (emit-label no-values))) - (t - (collect ((defaults)) - (do ((i 0 (1+ i)) - (tn-ref values (tn-ref-across tn-ref))) - ((null tn-ref)) - (let ((default-lab (gen-label)) - (tn (tn-ref-tn tn-ref))) - (defaults (cons default-lab tn)) - - (inst move count temp) - (inst lda count (fixnumize -1) count) - (inst beq temp default-lab) - (sc-case tn - ((descriptor-reg any-reg) - (loadw tn start i)) - (control-stack - (loadw move-temp start i) - (store-stack-tn tn move-temp))))) - - (let ((defaulting-done (gen-label))) - - (emit-label defaulting-done) - - (assemble (:elsewhere) - (dolist (def (defaults)) - (emit-label (car def)) - (let ((tn (cdr def))) - (sc-case tn - ((descriptor-reg any-reg) - (move null-tn tn)) - (control-stack - (store-stack-tn tn null-tn))))) - (inst br zero-tn defaulting-done)))))) - (load-stack-tn csp-tn sp))) - -(define-vop (nlx-entry-multiple) - (:args (top :target dst) (start :target src) (count :target num)) - ;; Again, no SC restrictions for the args, 'cause the loading would - ;; happen before the entry label. - (:info label) - (:temporary (:scs (any-reg) :from (:argument 0)) dst) - (:temporary (:scs (any-reg) :from (:argument 1)) src) - (:temporary (:scs (any-reg) :from (:argument 2)) num) - (:temporary (:scs (descriptor-reg)) temp) - (:results (new-start) (new-count)) - (:save-p :force-to-stack) - (:vop-var vop) - (:generator 30 - (emit-return-pc label) - (note-this-location vop :non-local-entry) - (let ((loop (gen-label)) - (done (gen-label))) - - ;; Copy args. - (load-stack-tn dst top) - (move start src) - (move count num) - - ;; Establish results. - (sc-case new-start - (any-reg (move dst new-start)) - (control-stack (store-stack-tn new-start dst))) - (sc-case new-count - (any-reg (inst move num new-count)) - (control-stack (store-stack-tn new-count num))) - (inst beq num done) - - ;; Copy stuff on stack. - (emit-label loop) - (loadw temp src) - (inst lda src n-word-bytes src) - (storew temp dst) - (inst lda num (fixnumize -1) num) - (inst lda dst n-word-bytes dst) - (inst bne num loop) - - (emit-label done) - (inst move dst csp-tn)))) - -;;; This VOP is just to force the TNs used in the cleanup onto the stack. -(define-vop (uwp-entry) - (:info label) - (:save-p :force-to-stack) - (:results (block) (start) (count)) - (:ignore block start count) - (:vop-var vop) - (:generator 0 - (emit-return-pc label) - (note-this-location vop :non-local-entry))) diff --git a/src/compiler/alpha/parms.lisp b/src/compiler/alpha/parms.lisp deleted file mode 100644 index 99e334d9eb..0000000000 --- a/src/compiler/alpha/parms.lisp +++ /dev/null @@ -1,190 +0,0 @@ -;;;; This software is part of the SBCL system. See the README file for -;;;; more information. -;;;; -;;;; This software is derived from the CMU CL system, which was -;;;; written at Carnegie Mellon University and released into the -;;;; public domain. The software is in the public domain and is -;;;; provided with absolutely no warranty. See the COPYING and CREDITS -;;;; files for more information. - -(in-package "SB-VM") - -(defconstant sb-assem:assem-scheduler-p nil) -(defconstant sb-assem:+inst-alignment-bytes+ 4) - -(defconstant +backend-fasl-file-implementation+ :alpha) - -(defconstant +backend-page-bytes+ 8192) - -(eval-when (:compile-toplevel :load-toplevel :execute) - -;;; number of bits per word where a word holds one lisp descriptor -(defconstant n-word-bits 32) - -;;; the natural width of a machine word (as seen in e.g. register width, -;;; address space) -(defconstant n-machine-word-bits 64) - -(defconstant float-sign-shift 31) - -(defconstant single-float-bias 126) -(defconstant-eqx single-float-exponent-byte (byte 8 23) #'equalp) -(defconstant-eqx single-float-significand-byte (byte 23 0) #'equalp) -(defconstant single-float-normal-exponent-min 1) -(defconstant single-float-normal-exponent-max 254) -(defconstant single-float-hidden-bit (ash 1 23)) - -(defconstant double-float-bias 1022) -(defconstant-eqx double-float-exponent-byte (byte 11 20) #'equalp) -(defconstant-eqx double-float-significand-byte (byte 20 0) #'equalp) -(defconstant double-float-normal-exponent-min 1) -(defconstant double-float-normal-exponent-max #x7FE) -(defconstant double-float-hidden-bit (ash 1 20)) - -(defconstant single-float-digits - (+ (byte-size single-float-significand-byte) 1)) - -(defconstant double-float-digits - (+ (byte-size double-float-significand-byte) n-word-bits 1)) - -;;; These values are originally from the DEC Assembly Language -;;; Programmers guide. Where possible we read/write the software -;;; fp_control word, which apparently is necessary for the OS FPU -;;; completion (OS handler which fixes up non-IEEE answers that the -;;; hardware occasionally gives us) to work properly. The rounding -;;; mode, however, can't be set that way, so we have to deal with that -;;; directly. (FIXME: we actually don't suport setting the rounding mode -;;; at the moment anyway) - -;;; Short guide to floating point trap terminology: an "exception" is -;;; cheap and can happen at almost any time. An exception will only -;;; generate a trap if that trap is enabled, otherwise a default value -;;; will be substituted. A "trap" will end up somewhere in the -;;; kernel, which may play by its own rules, (on Alpha it allegedly -;;; actually fixes up some non-IEEE compliant results to get the -;;; _right_ answer) but if something is really wrong will eventually -;;; signal SIGFPE and let us sort it out. - -;;; Old comment follows: The active bits are actually in (byte 12 52) -;;; of the fpcr. (byte 6 52) contain the exception flags. Bit 63 is the -;;; bitwise logor of all exceptions. The enable and exception bytes -;;; are in a software control word manipulated via OS functions and the -;;; bits in the SCP match those defs. This mapping follows -;;; <machine/fpu.h> - -;;; trap enables are set in software (fp_control) -(defconstant float-inexact-trap-bit (ash 1 4)) ; rw -(defconstant float-underflow-trap-bit (ash 1 3)) ; rw -(defconstant float-overflow-trap-bit (ash 1 2)) ; ro -(defconstant float-divide-by-zero-trap-bit (ash 1 1)) ; ro -(defconstant float-invalid-trap-bit (ash 1 0)) ; ro -(defconstant-eqx float-traps-byte (byte 6 1) #'equalp) - -;;; exceptions are also read/written in software (by syscalls, no less). -;;; This is kind of dumb, but has to be done -(defconstant-eqx float-sticky-bits (byte 6 17) #'equalp) ; fp_control - -;;; (We don't actually _have_ "current exceptions" on Alpha; the -;;; hardware only ever sets bits. So, set this the same as accrued -;;; exceptions) -(defconstant-eqx float-exceptions-byte (byte 6 17) #'equalp) - -;;; Rounding modes can only be set by frobbing the hardware fpcr directly -(defconstant float-round-to-zero 0) -(defconstant float-round-to-negative 1) -(defconstant float-round-to-nearest 2) -(defconstant float-round-to-positive 3) -(defconstant-eqx float-rounding-mode (byte 2 58) #'equalp) - -;;; Miscellaneous stuff - I think it's far to say that you deserve -;;; what you get if you ask for fast mode. -(defconstant float-fast-bit 0) - -); eval-when - - - -;;;; Description of the target address space. - -;;; Where to put the different spaces. -;;; - -(defconstant linkage-table-space-start #x1000) -(defconstant linkage-table-space-end linkage-table-space-start) ; 0 size - -#+linux -(progn - (defconstant read-only-space-start #x20000000) - (defconstant read-only-space-end #x24000000)) - -(defconstant static-space-start #x28000000) -(defconstant static-space-end #x2c000000) - -(defparameter dynamic-0-space-start #x30000000) -(defparameter dynamic-0-space-end #x3fff0000) - -;;; FIXME nothing refers to either of these in alpha or x86 cmucl -;;; backend, so they could probably be removed. - -;; The space-register holding the lisp heap. -(defconstant lisp-heap-space 4) - -;; The space-register holding the C text segment. -(defconstant c-text-space 4) - - -;;;; other miscellaneous constants - -(defenum (:start 8) - halt-trap - pending-interrupt-trap - cerror-trap - breakpoint-trap - fun-end-breakpoint-trap - single-step-breakpoint-trap - ;; Stepper actually not implemented on Alpha, but these constants - ;; are still needed to avoid undefined variable warnings during sbcl - ;; build. - single-step-around-trap - single-step-before-trap - error-trap) - -;;;; static symbols - -;;; These symbols are loaded into static space directly after NIL so -;;; that the system can compute their address by adding a constant -;;; amount to NIL. -;;; -;;; The fdefn objects for the static functions are loaded into static -;;; space directly after the static symbols. That way, the raw-addr -;;; can be loaded directly out of them by indirecting relative to NIL. -;;; -(defconstant-eqx +static-symbols+ - `#(,@+common-static-symbols+) - #'equalp) - -(defconstant-eqx +static-fdefns+ - #(length - two-arg-+ - two-arg-- - two-arg-* - two-arg-/ - two-arg-< - two-arg-> - two-arg-= - ;; FIXME: Is this - ;; probably need the following as they are defined in - ;; arith.lisp: two-arg-<= two-arg->= two-arg-/= - ;; a comment from old CMU CL or old old CMU CL or - ;; the SBCL alpha port or what? Do we need to worry about it, - ;; or can we delete it? - two-arg-/= - eql - %negate - two-arg-and - two-arg-ior - two-arg-xor - two-arg-eqv - two-arg-gcd - two-arg-lcm) - #'equalp) diff --git a/src/compiler/alpha/pred.lisp b/src/compiler/alpha/pred.lisp deleted file mode 100644 index 9152ebe5af..0000000000 --- a/src/compiler/alpha/pred.lisp +++ /dev/null @@ -1,55 +0,0 @@ -;;;; the VM definition of predicate VOPs for the Alpha - -;;;; This software is part of the SBCL system. See the README file for -;;;; more information. -;;;; -;;;; This software is derived from the CMU CL system, which was -;;;; written at Carnegie Mellon University and released into the -;;;; public domain. The software is in the public domain and is -;;;; provided with absolutely no warranty. See the COPYING and CREDITS -;;;; files for more information. - -(in-package "SB-VM") - -;;;; the Branch VOP - -;;; The unconditional branch, emitted when we can't drop through to -;;; the desired destination. Dest is the continuation we transfer -;;; control to. -(define-vop (branch) - (:info dest) - (:generator 5 - (inst br zero-tn dest))) - - -;;;; Generic conditional VOPs - -;;; The generic conditional branch, emitted immediately after test -;;; VOPs that only set flags. - -(define-vop (branch-if) - (:info dest flags not-p) - (:ignore dest flags not-p) - (:generator 0 - (error "BRANCH-IF not yet implemented"))) - -(defun convert-conditional-move-p (node dst-tn x-tn y-tn) - (declare (ignore node dst-tn x-tn y-tn)) - nil) - - -;;;; conditional VOPs - -(define-vop (if-eq) - (:args (x :scs (any-reg descriptor-reg zero null)) - (y :scs (any-reg descriptor-reg zero null))) - (:conditional) - (:temporary (:scs (non-descriptor-reg)) temp) - (:info target not-p) - (:policy :fast-safe) - (:translate eq) - (:generator 3 - (inst cmpeq x y temp) - (if not-p - (inst beq temp target) - (inst bne temp target)))) diff --git a/src/compiler/alpha/sap.lisp b/src/compiler/alpha/sap.lisp deleted file mode 100644 index ab88552b52..0000000000 --- a/src/compiler/alpha/sap.lisp +++ /dev/null @@ -1,355 +0,0 @@ -;;;; the Alpha VM definition of SAP operations - -;;;; This software is part of the SBCL system. See the README file for -;;;; more information. -;;;; -;;;; This software is derived from the CMU CL system, which was -;;;; written at Carnegie Mellon University and released into the -;;;; public domain. The software is in the public domain and is -;;;; provided with absolutely no warranty. See the COPYING and CREDITS -;;;; files for more information. - -(in-package "SB-VM") - -;;;; moves and coercions - -;;; Move a tagged SAP to an untagged representation. -(define-vop (move-to-sap) - (:args (x :scs (descriptor-reg))) - (:results (y :scs (sap-reg))) - (:note "system area pointer indirection") - (:generator 1 - (loadq y x sap-pointer-slot other-pointer-lowtag))) -(define-move-vop move-to-sap :move - (descriptor-reg) (sap-reg)) - -;;; Move an untagged SAP to a tagged representation. -(define-vop (move-from-sap) - (:args (x :scs (sap-reg) :target sap)) - (:temporary (:scs (sap-reg) :from (:argument 0)) sap) - (:temporary (:scs (non-descriptor-reg)) ndescr) - (:results (y :scs (descriptor-reg))) - (:note "system area pointer allocation") - (:generator 20 - (move x sap) - (with-fixed-allocation (y ndescr sap-widetag sap-size) - (storeq sap y sap-pointer-slot other-pointer-lowtag)))) -(define-move-vop move-from-sap :move - (sap-reg) (descriptor-reg)) - -;;; Move untagged SAP values. -(define-vop (sap-move) - (:args (x :target y - :scs (sap-reg) - :load-if (not (location= x y)))) - (:results (y :scs (sap-reg) - :load-if (not (location= x y)))) - (:generator 0 - (move x y))) -(define-move-vop sap-move :move - (sap-reg) (sap-reg)) - -;;; Move untagged SAP arguments/return-values. -(define-vop (move-sap-arg) - (:args (x :target y - :scs (sap-reg)) - (fp :scs (any-reg) - :load-if (not (sc-is y sap-reg)))) - (:results (y)) - (:generator 0 - (sc-case y - (sap-reg - (move x y)) - (sap-stack - (storeq x fp (tn-offset y)))))) -(define-move-vop move-sap-arg :move-arg - (descriptor-reg sap-reg) (sap-reg)) - -;;; Use standard MOVE-ARG + coercion to move an untagged sap to a -;;; descriptor passing location. -(define-move-vop move-arg :move-arg - (sap-reg) (descriptor-reg)) - -;;;; SAP-INT and INT-SAP - -(define-vop (sap-int) - (:args (sap :scs (sap-reg) :target int)) - (:arg-types system-area-pointer) - (:results (int :scs (unsigned-reg))) - (:result-types unsigned-num) - (:translate sap-int) - (:policy :fast-safe) - (:generator 1 - (move sap int))) - -(define-vop (int-sap) - (:args (int :scs (unsigned-reg) :target sap)) - (:arg-types unsigned-num) - (:results (sap :scs (sap-reg))) - (:result-types system-area-pointer) - (:translate int-sap) - (:policy :fast-safe) - (:generator 1 - (move int sap))) - -;;;; POINTER+ and POINTER- - -(define-vop (pointer+) - (:translate sap+) - (:args (ptr :scs (sap-reg)) - (offset :scs (signed-reg immediate))) - (:arg-types system-area-pointer signed-num) - (:results (res :scs (sap-reg))) - (:result-types system-area-pointer) - (:policy :fast-safe) - (:generator 1 - (sc-case offset - (signed-reg - (inst addq offset ptr res)) - (immediate - (inst lda res (tn-value offset) ptr))))) - -(define-vop (pointer-) - (:translate sap-) - (:args (ptr1 :scs (sap-reg)) - (ptr2 :scs (sap-reg))) - (:arg-types system-area-pointer system-area-pointer) - (:policy :fast-safe) - (:results (res :scs (signed-reg))) - (:result-types signed-num) - (:generator 1 - (inst subq ptr1 ptr2 res))) - -;;;; mumble-SYSTEM-REF and mumble-SYSTEM-SET - -(macrolet ((def-system-ref-and-set - (ref-name set-name sc type size &optional signed) - (let ((ref-name-c (symbolicate ref-name "-C")) - (set-name-c (symbolicate set-name "-C"))) - `(progn - (define-vop (,ref-name) - (:translate ,ref-name) - (:policy :fast-safe) - (:args (object :scs (sap-reg) :target sap) - (offset :scs (signed-reg))) - (:arg-types system-area-pointer signed-num) - ,@(when (or (eq size :byte) (eq size :short)) - `((:temporary (:sc non-descriptor-reg) temp) - (:temporary (:sc non-descriptor-reg) temp1))) - (:results (result :scs (,sc))) - (:result-types ,type) - (:temporary (:scs (sap-reg) :from (:argument 0)) sap) - (:generator 5 - (inst addq object offset sap) - ,@(ecase size - (:byte - (if signed - '((inst ldq_u temp 0 sap) - (inst lda temp1 1 sap) - (inst extqh temp temp1 temp) - (inst sra temp 56 result)) - '((inst ldq_u temp 0 sap) - (inst lda temp1 0 sap) - (inst extbl temp temp1 result)))) - (:short - (if signed - '((inst ldq_u temp 0 sap) - (inst lda temp1 0 sap) - (inst extwl temp temp1 temp) - (inst sll temp 48 temp) - (inst sra temp 48 result)) - '((inst ldq_u temp 0 sap) - (inst lda temp1 0 sap) - (inst extwl temp temp1 result)))) - (:long - `((inst ldl result 0 sap) - ,@(unless signed - '((inst mskll result 4 result))))) - (:quad - '((inst ldq result 0 sap))) - (:single - '((inst lds result 0 sap))) - (:double - '((inst ldt result 0 sap)))))) - (define-vop (,ref-name-c) - (:translate ,ref-name) - (:policy :fast-safe) - (:args (object :scs (sap-reg))) - (:arg-types system-area-pointer - (:constant ,(if (eq size :double) - ;; We need to be able to add 4. - `(integer ,(- (ash 1 16)) - ,(- (ash 1 16) 5)) - '(signed-byte 16)))) - ,@(when (or (eq size :byte) (eq size :short)) - `((:temporary (:scs (non-descriptor-reg)) temp) - (:temporary (:sc non-descriptor-reg) temp1))) - (:info offset) - (:results (result :scs (,sc))) - (:result-types ,type) - (:generator 4 - ,@(ecase size - (:byte - (if signed - '((inst ldq_u temp offset object) - (inst lda temp1 (1+ offset) object) - (inst extqh temp temp1 temp) - (inst sra temp 56 result)) - '((inst ldq_u temp offset object) - (inst lda temp1 offset object) - (inst extbl temp temp1 result)))) - (:short - (if signed - '((inst ldq_u temp offset object) - (inst lda temp1 offset object) - (inst extwl temp temp1 temp) - (inst sll temp 48 temp) - (inst sra temp 48 result)) - '((inst ldq_u temp offset object) - (inst lda temp1 offset object) - (inst extwl temp temp1 result)))) - (:long - `((inst ldl result offset object) - ,@(unless signed - '((inst mskll result 4 result))))) - (:quad - '((inst ldq result offset object))) - (:single - '((inst lds result offset object))) - (:double - '((inst ldt result offset object)))))) - (define-vop (,set-name) - (:translate ,set-name) - (:policy :fast-safe) - (:args (object :scs (sap-reg) :target sap) - (offset :scs (signed-reg)) - (value :scs (,sc) :target result)) - (:arg-types system-area-pointer signed-num ,type) - (:results (result :scs (,sc))) - (:result-types ,type) - (:temporary (:scs (sap-reg) :from (:argument 0)) sap) - ,@(when (or (eq size :byte) (eq size :short)) - `((:temporary (:sc non-descriptor-reg) temp) - (:temporary (:sc non-descriptor-reg) temp1) - (:temporary (:sc non-descriptor-reg) temp2))) - (:generator 5 - (inst addq object offset sap) - ,@(ecase size - (:byte - '((inst lda temp 0 sap) - (inst ldq_u temp1 0 sap) - (inst insbl value temp temp2) - (inst mskbl temp1 temp temp1) - (inst bis temp1 temp2 temp1) - (inst stq_u temp1 0 sap) - (inst move value result))) - (:short - '((inst lda temp 0 sap) - (inst ldq_u temp1 0 sap) - (inst mskwl temp1 temp temp1) - (inst inswl value temp temp2) - (inst bis temp1 temp2 temp) - (inst stq_u temp 0 sap) - (inst move value result))) - (:long - '((inst stl value 0 sap) - (move value result))) - (:quad - '((inst stq value 0 sap) - (move value result))) - (:single - '((unless (location= result value) - (inst fmove value result)) - (inst sts value 0 sap))) - (:double - '((unless (location= result value) - (inst fmove value result)) - (inst stt value 0 sap)))))) - (define-vop (,set-name-c) - (:translate ,set-name) - (:policy :fast-safe) - (:args (object :scs (sap-reg)) - (value :scs (,sc) :target result)) - (:arg-types system-area-pointer - (:constant ,(if (eq size :double) - ;; We need to be able to add 4. - `(integer ,(- (ash 1 16)) - ,(- (ash 1 16) 5)) - '(signed-byte 16))) - ,type) - ,@(when (or (eq size :byte) (eq size :short)) - `((:temporary (:sc non-descriptor-reg) temp) - (:temporary (:sc non-descriptor-reg) temp1) - (:temporary (:sc non-descriptor-reg) temp2))) - (:info offset) - (:results (result :scs (,sc))) - (:result-types ,type) - (:generator 5 - ,@(ecase size - (:byte - '((inst lda temp offset object) - (inst ldq_u temp1 offset object) - (inst insbl value temp temp2) - (inst mskbl temp1 temp temp1) - (inst bis temp1 temp2 temp1) - (inst stq_u temp1 offset object) - (inst move value result))) - (:short - '((inst lda temp offset object) - (inst ldq_u temp1 offset object) - (inst mskwl temp1 temp temp1) - (inst inswl value temp temp2) - (inst bis temp1 temp2 temp) - (inst stq_u temp offset object) - (inst move value result))) - (:long - '((inst stl value offset object) - (move value result))) - (:quad - '((inst stq value offset object) - (move value result))) - (:single - '((unless (location= result value) - (inst fmove value result)) - (inst sts value offset object))) - (:double - '((unless (location= result value) - (inst fmove value result)) - (inst stt value offset object)))))))))) - (def-system-ref-and-set sap-ref-8 %set-sap-ref-8 - unsigned-reg positive-fixnum :byte nil) - (def-system-ref-and-set signed-sap-ref-8 %set-signed-sap-ref-8 - signed-reg tagged-num :byte t) - (def-system-ref-and-set sap-ref-16 %set-sap-ref-16 - unsigned-reg positive-fixnum :short nil) - (def-system-ref-and-set signed-sap-ref-16 %set-signed-sap-ref-16 - signed-reg tagged-num :short t) - (def-system-ref-and-set sap-ref-32 %set-sap-ref-32 - unsigned-reg unsigned-num :long nil) - (def-system-ref-and-set signed-sap-ref-32 %set-signed-sap-ref-32 - signed-reg signed-num :long t) - (def-system-ref-and-set sap-ref-64 %set-sap-ref-64 - unsigned-reg unsigned-num :quad nil) - (def-system-ref-and-set signed-sap-ref-64 %set-signed-sap-ref-64 - signed-reg signed-num :quad t) - (def-system-ref-and-set sap-ref-sap %set-sap-ref-sap - sap-reg system-area-pointer :quad) - (def-system-ref-and-set sap-ref-lispobj %set-sap-ref-lispobj - descriptor-reg * :long) - (def-system-ref-and-set sap-ref-single %set-sap-ref-single - single-reg single-float :single) - (def-system-ref-and-set sap-ref-double %set-sap-ref-double - double-reg double-float :double)) - -;;; noise to convert normal Lisp data objects into SAPs - -(define-vop (vector-sap) - (:translate vector-sap) - (:policy :fast-safe) - (:args (vector :scs (descriptor-reg))) - (:results (sap :scs (sap-reg))) - (:result-types system-area-pointer) - (:generator 2 - (inst lda sap - (- (* vector-data-offset n-word-bytes) other-pointer-lowtag) - vector))) diff --git a/src/compiler/alpha/show.lisp b/src/compiler/alpha/show.lisp deleted file mode 100644 index 98137b54d5..0000000000 --- a/src/compiler/alpha/show.lisp +++ /dev/null @@ -1,34 +0,0 @@ -;;;; temporary printing utilities and similar noise - -;;;; This software is part of the SBCL system. See the README file for -;;;; more information. -;;;; -;;;; This software is derived from the CMU CL system, which was -;;;; written at Carnegie Mellon University and released into the -;;;; public domain. The software is in the public domain and is -;;;; provided with absolutely no warranty. See the COPYING and CREDITS -;;;; files for more information. - -(in-package "SB-VM") - -(define-vop (print) - (:args (object :scs (descriptor-reg) :target a0)) - (:results (result :scs (descriptor-reg))) - (:save-p t) - (:temporary (:sc any-reg :offset cfunc-offset :target result :to (:result 0)) - cfunc) - (:temporary (:sc descriptor-reg :offset nl0-offset :from (:argument 0)) a0) - (:temporary (:sc control-stack :offset nfp-save-offset) nfp-save) - (:temporary (:scs (non-descriptor-reg)) temp) - (:vop-var vop) - (:generator 0 - (let ((cur-nfp (current-nfp-tn vop))) - (move object a0) - (when cur-nfp - (store-stack-tn nfp-save cur-nfp)) - (inst li (make-fixup "debug_print" :foreign) cfunc) - (inst li (make-fixup "call_into_c" :foreign) temp) - (inst jsr lip-tn temp (make-fixup "call_into_c" :foreign)) - (when cur-nfp - (maybe-load-stack-nfp-tn cur-nfp nfp-save temp)) - (move cfunc result)))) diff --git a/src/compiler/alpha/subprim.lisp b/src/compiler/alpha/subprim.lisp deleted file mode 100644 index 24e4f6b80a..0000000000 --- a/src/compiler/alpha/subprim.lisp +++ /dev/null @@ -1,49 +0,0 @@ -;;;; linkage information for standard static functions, and random vops - -;;;; This software is part of the SBCL system. See the README file for -;;;; more information. -;;;; -;;;; This software is derived from the CMU CL system, which was -;;;; written at Carnegie Mellon University and released into the -;;;; public domain. The software is in the public domain and is -;;;; provided with absolutely no warranty. See the COPYING and CREDITS -;;;; files for more information. - -(in-package "SB-VM") - -;;;; LENGTH - -(define-vop (length/list) - (:translate length) - (:args (object :scs (descriptor-reg) :target ptr)) - (:arg-types list) - (:temporary (:scs (descriptor-reg) :from (:argument 0)) ptr) - (:temporary (:scs (non-descriptor-reg)) temp) - (:temporary (:scs (any-reg) :to (:result 0) :target result) - count) - (:results (result :scs (any-reg descriptor-reg))) - (:policy :fast-safe) - (:vop-var vop) - (:save-p :compute-only) - (:generator 50 - (move object ptr) - (move zero-tn count) - - LOOP - - (inst cmpeq ptr null-tn temp) - (inst bne temp done) - - (inst and ptr lowtag-mask temp) - (inst xor temp list-pointer-lowtag temp) - (inst bne temp not-list) - - (loadw ptr ptr cons-cdr-slot list-pointer-lowtag) - (inst addq count (fixnumize 1) count) - (inst br zero-tn loop) - - NOT-LIST - (cerror-call vop 'object-not-list-error ptr) - - DONE - (move count result))) diff --git a/src/compiler/alpha/system.lisp b/src/compiler/alpha/system.lisp deleted file mode 100644 index 989d2fdb9e..0000000000 --- a/src/compiler/alpha/system.lisp +++ /dev/null @@ -1,208 +0,0 @@ -;;;; Alpha VM definitions of various system hacking operations - -;;;; This software is part of the SBCL system. See the README file for -;;;; more information. -;;;; -;;;; This software is derived from the CMU CL system, which was -;;;; written at Carnegie Mellon University and released into the -;;;; public domain. The software is in the public domain and is -;;;; provided with absolutely no warranty. See the COPYING and CREDITS -;;;; files for more information. - -(in-package "SB-VM") - -;;;; type frobbing VOPs - -(define-vop (widetag-of) - (:translate widetag-of) - (:policy :fast-safe) - (:args (object :scs (descriptor-reg))) - (:temporary (:scs (non-descriptor-reg)) ndescr) - (:results (result :scs (unsigned-reg))) - (:result-types positive-fixnum) - (:generator 6 - ;; Pick off objects with headers. - (inst and object lowtag-mask result) - (inst cmpeq result other-pointer-lowtag ndescr) - (inst bne ndescr other-ptr) - (inst cmpeq result fun-pointer-lowtag ndescr) - (inst bne ndescr function-ptr) - - ;; Pick off structure and list pointers. - (inst blbs object done) - - ;; Pick off fixnums. - (inst and object fixnum-tag-mask result) - (inst beq result done) - - ;; Must be an other immediate. - (inst and object widetag-mask result) - (inst br zero-tn done) - - FUNCTION-PTR - (load-type result object (- fun-pointer-lowtag)) - (inst br zero-tn done) - - OTHER-PTR - (load-type result object (- other-pointer-lowtag)) - - DONE)) - -(define-vop (%other-pointer-widetag) - (:translate %other-pointer-widetag) - (:policy :fast-safe) - (:args (object :scs (descriptor-reg))) - (:results (result :scs (unsigned-reg))) - (:result-types positive-fixnum) - (:generator 6 - (load-type result object (- other-pointer-lowtag)))) - -(define-vop (fun-subtype) - (:translate fun-subtype) - (:policy :fast-safe) - (:args (function :scs (descriptor-reg))) - (:results (result :scs (unsigned-reg))) - (:result-types positive-fixnum) - (:generator 6 - (load-type result function (- fun-pointer-lowtag)))) - -(define-vop (get-header-data) - (:translate get-header-data) - (:policy :fast-safe) - (:args (x :scs (descriptor-reg))) - (:results (res :scs (unsigned-reg))) - (:result-types positive-fixnum) - (:generator 6 - (loadw res x 0 other-pointer-lowtag) - (inst srl res n-widetag-bits res))) - -(define-vop (set-header-data) - (:translate set-header-data) - (:policy :fast-safe) - (:args (x :scs (descriptor-reg) :target res) - (data :scs (any-reg immediate zero))) - (:arg-types * positive-fixnum) - (:results (res :scs (descriptor-reg))) - (:temporary (:scs (non-descriptor-reg)) t1 t2) - (:generator 6 - (loadw t1 x 0 other-pointer-lowtag) - (inst and t1 widetag-mask t1) - (sc-case data - (any-reg - (inst sll data (- n-widetag-bits n-fixnum-tag-bits) t2) - (inst bis t1 t2 t1)) - (immediate - (let ((c (ash (tn-value data) n-widetag-bits))) - (cond ((<= 0 c (1- (ash 1 8))) - (inst bis t1 c t1)) - (t - (inst li c t2) - (inst bis t1 t2 t1))))) - (zero)) - (storew t1 x 0 other-pointer-lowtag) - (move x res))) - -(define-vop (pointer-hash) - (:translate pointer-hash) - (:args (ptr :scs (any-reg descriptor-reg))) - (:results (res :scs (any-reg descriptor-reg))) - (:policy :fast-safe) - (:generator 1 - ;; FIXME: It would be better if this would mask the lowtag, - ;; and shift the result into a positive fixnum like on x86. - (inst sll ptr 35 res) - (inst srl res 33 res))) - - -;;;; allocation - -(define-vop (dynamic-space-free-pointer) - (:results (int :scs (sap-reg))) - (:result-types system-area-pointer) - (:translate dynamic-space-free-pointer) - (:policy :fast-safe) - (:generator 1 - (move alloc-tn int))) - -(define-vop (binding-stack-pointer-sap) - (:results (int :scs (sap-reg))) - (:result-types system-area-pointer) - (:translate binding-stack-pointer-sap) - (:policy :fast-safe) - (:generator 1 - (move bsp-tn int))) - -(define-vop (control-stack-pointer-sap) - (:results (int :scs (sap-reg))) - (:result-types system-area-pointer) - (:translate control-stack-pointer-sap) - (:policy :fast-safe) - (:generator 1 - (move csp-tn int))) - - -;;;; code object frobbing - -(define-vop (code-instructions) - (:translate code-instructions) - (:policy :fast-safe) - (:args (code :scs (descriptor-reg))) - (:temporary (:scs (non-descriptor-reg)) ndescr) - (:results (sap :scs (sap-reg))) - (:result-types system-area-pointer) - (:generator 10 - (loadw ndescr code 0 other-pointer-lowtag) - (inst srl ndescr n-widetag-bits ndescr) - (inst sll ndescr word-shift ndescr) - (inst subq ndescr other-pointer-lowtag ndescr) - (inst addq code ndescr sap))) - -(define-vop (compute-fun) - (:args (code :scs (descriptor-reg)) - (offset :scs (signed-reg unsigned-reg))) - (:arg-types * positive-fixnum) - (:results (func :scs (descriptor-reg))) - (:temporary (:scs (non-descriptor-reg)) ndescr) - (:generator 10 - (loadw ndescr code code-boxed-size-slot other-pointer-lowtag) - (inst addq ndescr offset ndescr) - (inst subq ndescr (- other-pointer-lowtag fun-pointer-lowtag) ndescr) - (inst addq code ndescr func))) - -;;;; other random VOPs. - -(defknown sb-unix::receive-pending-interrupt () (values)) -(define-vop (sb-unix::receive-pending-interrupt) - (:policy :fast-safe) - (:translate sb-unix::receive-pending-interrupt) - (:generator 1 - (inst gentrap pending-interrupt-trap))) - - -(define-vop (halt) - (:generator 1 - (inst gentrap halt-trap))) - -(define-vop (istream-memory-barrier) - (:generator 1 - (inst imb))) - -;;;; dynamic vop count collection support - -(define-vop (count-me) - (:args (count-vector :scs (descriptor-reg))) - (:info index) - (:temporary (:scs (non-descriptor-reg)) count) - (:generator 1 - (let ((offset - (- (* (+ index vector-data-offset) n-word-bytes) - other-pointer-lowtag))) - (inst ldl count offset count-vector) - (inst addq count 1 count) - (inst stl count offset count-vector)))) - -;;;; Dummy definition for a spin-loop hint VOP -(define-vop () - (:translate spin-loop-hint) - (:policy :fast-safe) - (:generator 0)) diff --git a/src/compiler/alpha/target-insts.lisp b/src/compiler/alpha/target-insts.lisp deleted file mode 100644 index fe7879977b..0000000000 --- a/src/compiler/alpha/target-insts.lisp +++ /dev/null @@ -1,38 +0,0 @@ -;;;; This file is for stuff which was in CMU CL's insts.lisp -;;;; file, but which in the SBCL build process can't be compiled -;;;; into code for the cross-compilation host. - -;;;; This software is part of the SBCL system. See the README file for -;;;; more information. -;;;; -;;;; This software is derived from the CMU CL system, which was -;;;; written at Carnegie Mellon University and released into the -;;;; public domain. The software is in the public domain and is -;;;; provided with absolutely no warranty. See the COPYING and CREDITS -;;;; files for more information. - -(in-package "SB-ALPHA-ASM") - -(defun bugchk-trap-control (chunk inst stream dstate) - (declare (ignore inst)) - (flet ((nt (x) (if stream (note x dstate)))) - (let ((trap (bugchk-trap-code chunk dstate))) - (case trap - (#.halt-trap - (nt "Halt trap")) - (#.pending-interrupt-trap - (nt "Pending interrupt trap")) - (#.breakpoint-trap - (nt "Breakpoint trap")) - (#.fun-end-breakpoint-trap - (nt "Function end breakpoint trap")) - (#.single-step-breakpoint-trap - (nt "Single step breakpoint trap")) - (#.single-step-around-trap - (nt "Single step around trap")) - (#.single-step-before-trap - (nt "Single step before trap")) - (t - (when (or (and (= trap cerror-trap) (progn (nt "cerror trap") t)) - (>= trap-number error-trap)) - (handle-break-args #'snarf-error-junk trap stream dstate))))))) diff --git a/src/compiler/alpha/type-vops.lisp b/src/compiler/alpha/type-vops.lisp deleted file mode 100644 index 0fff267d51..0000000000 --- a/src/compiler/alpha/type-vops.lisp +++ /dev/null @@ -1,189 +0,0 @@ -;;;; type testing and checking VOPs for the Alpha VM - -;;;; This software is part of the SBCL system. See the README file for -;;;; more information. -;;;; -;;;; This software is derived from the CMU CL system, which was -;;;; written at Carnegie Mellon University and released into the -;;;; public domain. The software is in the public domain and is -;;;; provided with absolutely no warranty. See the COPYING and CREDITS -;;;; files for more information. - -(in-package "SB-VM") - -(defun %test-fixnum (value temp target not-p) - (assemble () - (inst and value fixnum-tag-mask temp) - (if not-p - (inst bne temp target) - (inst beq temp target)))) - -(defun %test-fixnum-and-headers (value temp target not-p headers &key value-tn-ref) - (let ((drop-through (gen-label))) - (assemble () - (inst and value fixnum-tag-mask temp) - (inst beq temp (if not-p drop-through target))) - (%test-headers value temp target not-p nil headers - :drop-through drop-through - :value-tn-ref value-tn-ref))) - -(defun %test-immediate (value temp target not-p immediate) - (assemble () - (inst and value 255 temp) - (inst xor temp immediate temp) - (if not-p - (inst bne temp target) - (inst beq temp target)))) - -(defun %test-lowtag (value temp target not-p lowtag) - (assemble () - (inst and value lowtag-mask temp) - (inst xor temp lowtag temp) - (if not-p - (inst bne temp target) - (inst beq temp target)))) - -(defun %test-headers (value temp target not-p function-p headers - &key (drop-through (gen-label)) value-tn-ref) - (declare (ignore value-tn-ref)) - (let ((lowtag (if function-p fun-pointer-lowtag other-pointer-lowtag))) - (multiple-value-bind - (when-true when-false) - ;; WHEN-TRUE and WHEN-FALSE are the labels to branch to when - ;; we know it's true and when we know it's false respectively. - (if not-p - (values drop-through target) - (values target drop-through)) - (assemble () - (%test-lowtag value temp when-false t lowtag) - (load-type temp value (- lowtag)) - (let ((delta 0)) - (do ((remaining headers (cdr remaining))) - ((null remaining)) - (let ((header (car remaining)) - (last (null (cdr remaining)))) - (cond - ((atom header) - (inst subq temp (- header delta) temp) - (setf delta header) - (if last - (if not-p - (inst bne temp target) - (inst beq temp target)) - (inst beq temp when-true))) - (t - (let ((start (car header)) - (end (cdr header))) - (unless (= start bignum-widetag) - (inst subq temp (- start delta) temp) - (setf delta start) - (inst blt temp when-false)) - (inst subq temp (- end delta) temp) - (setf delta end) - (if last - (if not-p - (inst bgt temp target) - (inst ble temp target)) - (inst ble temp when-true)))))))) - (emit-label drop-through))))) - -;;;; Other integer ranges. - -;;; A (signed-byte 32) can be represented with either fixnum or a bignum with -;;; exactly one digit. -(define-vop (signed-byte-32-p type-predicate) - (:translate signed-byte-32-p) - (:temporary (:scs (non-descriptor-reg)) temp1) - (:generator 45 - (multiple-value-bind - (yep nope) - (if not-p - (values not-target target) - (values target not-target)) - (assemble () - (inst and value fixnum-tag-mask temp) - (inst beq temp yep) - (inst and value lowtag-mask temp) - (inst xor temp other-pointer-lowtag temp) - (inst bne temp nope) - (loadw temp value 0 other-pointer-lowtag) - (inst li (+ (ash 1 n-widetag-bits) bignum-widetag) temp1) - (inst xor temp temp1 temp) - (if not-p - (inst bne temp target) - (inst beq temp target)))) - NOT-TARGET)) - -;;; An (unsigned-byte 32) can be represented with either a positive fixnum, a -;;; bignum with exactly one positive digit, or a bignum with exactly two digits -;;; and the second digit all zeros. - -(define-vop (unsigned-byte-32-p type-predicate) - (:translate unsigned-byte-32-p) - (:temporary (:scs (non-descriptor-reg)) temp1) - (:generator 45 - (multiple-value-bind (yep nope) - (if not-p - (values not-target target) - (values target not-target)) - (assemble () - ;; Is it a fixnum? - (inst and value fixnum-tag-mask temp1) - (inst move value temp) - (inst beq temp1 fixnum) - - ;; If not, is it an other pointer? - (inst and value lowtag-mask temp) - (inst xor temp other-pointer-lowtag temp) - (inst bne temp nope) - ;; Get the header. - (loadw temp value 0 other-pointer-lowtag) - ;; Is it one? - (inst li (+ (ash 1 n-widetag-bits) bignum-widetag) temp1) - (inst xor temp temp1 temp) - (inst beq temp single-word) - ;; If it's other than two, we can't be an (unsigned-byte 32) - (inst li (logxor (+ (ash 1 n-widetag-bits) bignum-widetag) - (+ (ash 2 n-widetag-bits) bignum-widetag)) - temp1) - (inst xor temp temp1 temp) - (inst bne temp nope) - ;; Get the second digit. - (loadw temp value (1+ bignum-digits-offset) other-pointer-lowtag) - ;; All zeros, its an (unsigned-byte 32). - (inst beq temp yep) - (inst br zero-tn nope) - - SINGLE-WORD - ;; Get the single digit. - (loadw temp value bignum-digits-offset other-pointer-lowtag) - - ;; positive implies (unsigned-byte 32). - FIXNUM - (if not-p - (inst blt temp target) - (inst bge temp target)))) - NOT-TARGET)) - -;;;; List/symbol types: -;;; -;;; symbolp (or symbol (eq nil)) -;;; consp (and list (not (eq nil))) - -(define-vop (symbolp type-predicate) - (:translate symbolp) - (:temporary (:scs (non-descriptor-reg)) temp) - (:generator 12 - (inst cmpeq value null-tn temp) - (inst bne temp (if not-p drop-thru target)) - (test-type value temp target not-p (symbol-widetag)) - DROP-THRU)) - -(define-vop (consp type-predicate) - (:translate consp) - (:temporary (:scs (non-descriptor-reg)) temp) - (:generator 8 - (inst cmpeq value null-tn temp) - (inst bne temp (if not-p target drop-thru)) - (test-type value temp target not-p (list-pointer-lowtag)) - DROP-THRU)) diff --git a/src/compiler/alpha/values.lisp b/src/compiler/alpha/values.lisp deleted file mode 100644 index 4bafc5f0cb..0000000000 --- a/src/compiler/alpha/values.lisp +++ /dev/null @@ -1,156 +0,0 @@ -;;;; the Alpha implementation of unknown-values VOPs - -;;;; This software is part of the SBCL system. See the README file for -;;;; more information. -;;;; -;;;; This software is derived from the CMU CL system, which was -;;;; written at Carnegie Mellon University and released into the -;;;; public domain. The software is in the public domain and is -;;;; provided with absolutely no warranty. See the COPYING and CREDITS -;;;; files for more information. - -(in-package "SB-VM") - -(define-vop (reset-stack-pointer) - (:args (ptr :scs (any-reg))) - (:generator 1 - (move ptr csp-tn))) - -(define-vop (%%nip-values) - (:args (last-nipped-ptr :scs (any-reg) :target dest) - (last-preserved-ptr :scs (any-reg) :target src) - (moved-ptrs :scs (any-reg) :more t)) - (:results (r-moved-ptrs :scs (any-reg) :more t)) - (:temporary (:sc any-reg) src) - (:temporary (:sc any-reg) dest) - (:temporary (:sc non-descriptor-reg) cmp-temp) - (:temporary (:sc descriptor-reg) temp) - (:ignore r-moved-ptrs) - (:generator 1 - (move last-nipped-ptr dest) - (move last-preserved-ptr src) - (inst cmple csp-tn src cmp-temp) - (inst bne cmp-temp DONE) - LOOP - (loadw temp src) - (inst addq dest n-word-bytes dest) - (inst addq src n-word-bytes src) - (storew temp dest -1) - (inst cmple csp-tn src cmp-temp) - (inst beq cmp-temp LOOP) - DONE - (inst lda csp-tn 0 dest) - (inst subq src dest src) - (loop for moved = moved-ptrs then (tn-ref-across moved) - while moved - do (sc-case (tn-ref-tn moved) - ((descriptor-reg any-reg) - (inst subq (tn-ref-tn moved) src (tn-ref-tn moved))) - ((control-stack) - (load-stack-tn temp (tn-ref-tn moved)) - (inst subq temp src temp) - (store-stack-tn (tn-ref-tn moved) temp)))))) - -;;; Push some values onto the stack, returning the start and number of -;;; values pushed as results. It is assumed that the Vals are wired to -;;; the standard argument locations. Nvals is the number of values to -;;; push. -;;; -;;; The generator cost is pseudo-random. We could get it right by -;;; defining a bogus SC that reflects the costs of the -;;; memory-to-memory moves for each operand, but this seems -;;; unworthwhile. -(define-vop (push-values) - (:args - (vals :more t)) - (:results - (start :scs (any-reg)) - (count :scs (any-reg))) - (:info nvals) - (:temporary (:scs (descriptor-reg)) temp) - (:temporary (:scs (descriptor-reg) - :to (:result 0) - :target start) - start-temp) - (:generator 20 - (move csp-tn start-temp) - (inst lda csp-tn (* nvals n-word-bytes) csp-tn) - (do ((val vals (tn-ref-across val)) - (i 0 (1+ i))) - ((null val)) - (let ((tn (tn-ref-tn val))) - (sc-case tn - (descriptor-reg - (storew tn start-temp i)) - (control-stack - (load-stack-tn temp tn) - (storew temp start-temp i))))) - (move start-temp start) - (inst li (fixnumize nvals) count))) - -;;; Push a list of values on the stack, returning Start and Count as -;;; used in unknown values continuations. -(define-vop (values-list) - (:args (arg :scs (descriptor-reg) :target list)) - (:arg-types list) - (:policy :fast-safe) - (:results (start :scs (any-reg)) - (count :scs (any-reg))) - (:temporary (:scs (descriptor-reg) :from (:argument 0)) list) - (:temporary (:scs (non-descriptor-reg)) temp) - (:temporary (:scs (non-descriptor-reg)) ndescr) - (:vop-var vop) - (:save-p :compute-only) - (:generator 0 - (move arg list) - (move csp-tn start) - - LOOP - (inst cmpeq list null-tn temp) - (inst bne temp done) - (loadw temp list cons-car-slot list-pointer-lowtag) - (loadw list list cons-cdr-slot list-pointer-lowtag) - (inst lda csp-tn n-word-bytes csp-tn) - (storew temp csp-tn -1) - (inst and list lowtag-mask ndescr) - (inst xor ndescr list-pointer-lowtag ndescr) - (inst beq ndescr loop) - (cerror-call vop 'bogus-arg-to-values-list-error list) - - DONE - (inst subq csp-tn start count))) - -;;; Copy the &MORE arg block to the top of the stack so we can use -;;; them as function arguments. -(define-vop (%more-arg-values) - (:args (context :scs (descriptor-reg any-reg) :target src) - (skip :scs (any-reg zero immediate)) - (num :scs (any-reg) :target count)) - (:arg-types * positive-fixnum positive-fixnum) - (:temporary (:sc any-reg :from (:argument 0)) src) - (:temporary (:sc any-reg :from (:argument 2)) dst) - (:temporary (:sc descriptor-reg :from (:argument 1)) temp) - (:temporary (:sc non-descriptor-reg) temp1) - (:results (start :scs (any-reg)) - (count :scs (any-reg))) - (:generator 20 - (sc-case skip - (zero - (move context src)) - (immediate - (inst lda src (* (tn-value skip) n-word-bytes) context)) - (any-reg - (inst addq context skip src))) - (move num count) - (inst move csp-tn start) - (inst beq num done) - (inst move csp-tn dst) - (inst addq csp-tn count csp-tn) - LOOP - (inst ldl temp 0 src) - (inst addq src 4 src) - (inst addq dst 4 dst) - (inst stl temp -4 dst) - (inst cmpeq dst csp-tn temp1) - (inst beq temp1 loop) - DONE)) diff --git a/src/compiler/alpha/vm.lisp b/src/compiler/alpha/vm.lisp deleted file mode 100644 index 36b8af3343..0000000000 --- a/src/compiler/alpha/vm.lisp +++ /dev/null @@ -1,347 +0,0 @@ -;;;; miscellaneous VM definition noise for the Alpha - -;;;; This software is part of the SBCL system. See the README file for -;;;; more information. -;;;; -;;;; This software is derived from the CMU CL system, which was -;;;; written at Carnegie Mellon University and released into the -;;;; public domain. The software is in the public domain and is -;;;; provided with absolutely no warranty. See the COPYING and CREDITS -;;;; files for more information. - -(in-package "SB-VM") - -;;;; defining the registers - -(eval-when (:compile-toplevel :load-toplevel :execute) - (defvar *register-names* (make-array 32 :initial-element nil))) - -(macrolet ((defreg (name offset) - (let ((offset-sym (symbolicate name "-OFFSET"))) - `(eval-when (:compile-toplevel :load-toplevel :execute) - (defconstant ,offset-sym ,offset) - (setf (svref *register-names* ,offset-sym) - ,(symbol-name name))))) - (defregset (name &rest regs) - `(eval-when (:compile-toplevel :load-toplevel :execute) - (defparameter ,name - (list ,@(mapcar (lambda (name) - (symbolicate name "-OFFSET")) - regs)))))) - ;; c.f. src/runtime/alpha-lispregs.h - - ;; Ra - (defreg lip 0) - ;; Caller saved 0-7 - (defreg a0 1) - (defreg a1 2) - (defreg a2 3) - (defreg a3 4) - (defreg a4 5) - (defreg a5 6) - (defreg l0 7) - (defreg nargs 8) - ;; Callee saved 0-6 - (defreg csp 9) - (defreg cfp 10) - (defreg ocfp 11) - (defreg bsp 12) - (defreg lexenv 13) - (defreg code 14) - (defreg null 15) - ;; Arg 0-5 - (defreg nl0 16) - (defreg nl1 17) - (defreg nl2 18) - (defreg nl3 19) - (defreg nl4 20) - (defreg nl5 21) - ;; Caller saved 8-11 - (defreg alloc 22) - (defreg fdefn 23) - (defreg cfunc 24) - (defreg nfp 25) - ;; Ra - (defreg lra 26) - ;; Caller saved 12 - (defreg l1 27) - ;; Assembler temp (at) - (defreg l2 28) - ;; Global pointer (gp) - (defreg gp 29) - ;; Stack pointer - (defreg nsp 30) - ;; Wired zero - (defreg zero 31) - - (defregset non-descriptor-regs - nl0 nl1 nl2 nl3 nl4 nl5 nfp cfunc) - - (defregset descriptor-regs - fdefn lexenv nargs ocfp lra a0 a1 a2 a3 a4 a5 l0 l1 l2) - - (defregset boxed-regs - code fdefn lexenv nargs ocfp lra - a0 a1 a2 a3 a4 a5 - l0 l1 l2) - - (defregset *register-arg-offsets* - a0 a1 a2 a3 a4 a5) - (defparameter register-arg-names '(a0 a1 a2 a3 a4 a5))) - -(!define-storage-bases -(define-storage-base registers :finite :size 32) -(define-storage-base float-registers :finite :size 64) -(define-storage-base control-stack :unbounded :size 8) -(define-storage-base non-descriptor-stack :unbounded :size 0) -(define-storage-base constant :non-packed) -(define-storage-base immediate-constant :non-packed) -) - -(!define-storage-classes - - ;; non-immediate constants in the constant pool - (constant constant) - - ;; ZERO and NULL are in registers. - (zero immediate-constant) - (null immediate-constant) - (fp-single-zero immediate-constant) - (fp-double-zero immediate-constant) - - ;; Anything else that can be an immediate. - (immediate immediate-constant) - - - ;; **** The stacks. - - ;; The control stack. (Scanned by GC) - (control-stack control-stack) - - ;; We put ANY-REG and DESCRIPTOR-REG early so that their SC-NUMBER - ;; is small and therefore the error trap information is smaller. - ;; Moving them up here from their previous place down below saves - ;; ~250K in core file size. --njf, 2006-01-27 - - ;; Immediate descriptor objects. Don't have to be seen by GC, but nothing - ;; bad will happen if they are. (fixnums, characters, header values, etc). - (any-reg - registers - :locations #.(append non-descriptor-regs descriptor-regs) - :constant-scs (zero immediate) - :save-p t - :alternate-scs (control-stack)) - - ;; Pointer descriptor objects. Must be seen by GC. - (descriptor-reg registers - :locations #.descriptor-regs - :constant-scs (constant null immediate) - :save-p t - :alternate-scs (control-stack)) - - ;; The non-descriptor stacks. - (signed-stack non-descriptor-stack - :element-size 2 :alignment 2) ; (signed-byte 64) - (unsigned-stack non-descriptor-stack - :element-size 2 :alignment 2) ; (unsigned-byte 64) - (character-stack non-descriptor-stack) ; non-descriptor characters. - (sap-stack non-descriptor-stack - :element-size 2 :alignment 2) ; System area pointers. - (single-stack non-descriptor-stack) ; single-floats - (double-stack non-descriptor-stack - :element-size 2 :alignment 2) ; double floats. - (complex-single-stack non-descriptor-stack :element-size 2) - (complex-double-stack non-descriptor-stack :element-size 4 :alignment 2) - - - ;; **** Things that can go in the integer registers. - - ;; Non-Descriptor characters - (character-reg registers - :locations #.non-descriptor-regs - :constant-scs (immediate) - :save-p t - :alternate-scs (character-stack)) - - ;; Non-Descriptor SAP's (arbitrary pointers into address space) - (sap-reg registers - :locations #.non-descriptor-regs - :constant-scs (immediate) - :save-p t - :alternate-scs (sap-stack)) - - ;; Non-Descriptor (signed or unsigned) numbers. - (signed-reg registers - :locations #.non-descriptor-regs - :constant-scs (zero immediate) - :save-p t - :alternate-scs (signed-stack)) - (unsigned-reg registers - :locations #.non-descriptor-regs - :constant-scs (zero immediate) - :save-p t - :alternate-scs (unsigned-stack)) - - ;; Random objects that must not be seen by GC. Used only as temporaries. - (non-descriptor-reg registers - :locations #.non-descriptor-regs) - - ;; Pointers to the interior of objects. Used only as an temporary. - (interior-reg registers - :locations (#.lip-offset)) - - - ;; **** Things that can go in the floating point registers. - - ;; Non-Descriptor single-floats. - (single-reg float-registers - :locations #.(loop for i from 4 to 30 collect i) - :constant-scs (fp-single-zero) - :save-p t - :alternate-scs (single-stack)) - - ;; Non-Descriptor double-floats. - (double-reg float-registers - :locations #.(loop for i from 4 to 30 collect i) - :constant-scs (fp-double-zero) - :save-p t - :alternate-scs (double-stack)) - - (complex-single-reg float-registers - :locations #.(loop for i from 4 to 28 by 2 collect i) - :element-size 2 - :constant-scs () - :save-p t - :alternate-scs (complex-single-stack)) - - (complex-double-reg float-registers - :locations #.(loop for i from 4 to 28 by 2 collect i) - :element-size 2 - :constant-scs () - :save-p t - :alternate-scs (complex-double-stack)) - - (catch-block control-stack :element-size catch-block-size) - (unwind-block control-stack :element-size unwind-block-size)) - -;;; Make some random tns for important registers. -(macrolet ((defregtn (name sc) - (let ((offset-sym (symbolicate name "-OFFSET")) - (tn-sym (symbolicate name "-TN"))) - `(defparameter ,tn-sym - (make-random-tn :kind :normal - :sc (sc-or-lose ',sc) - :offset ,offset-sym))))) - - ;; These, we access by foo-TN only - - (defregtn zero any-reg) - (defregtn null descriptor-reg) - (defregtn code descriptor-reg) - (defregtn alloc any-reg) - (defregtn bsp any-reg) - (defregtn csp any-reg) - (defregtn cfp any-reg) - (defregtn nsp any-reg) - - ;; These alias regular locations, so we have to make sure we don't bypass - ;; the register allocator when using them. - (defregtn nargs any-reg) - (defregtn ocfp any-reg) - (defregtn lip interior-reg)) - -;; and some floating point values.. -(defparameter fp-single-zero-tn - (make-random-tn :kind :normal - :sc (sc-or-lose 'single-reg) - :offset 31)) -(defparameter fp-double-zero-tn - (make-random-tn :kind :normal - :sc (sc-or-lose 'double-reg) - :offset 31)) - -;;; If value can be represented as an immediate constant, then return -;;; the appropriate SC number, otherwise return NIL. -(defun immediate-constant-sc (value) - (typecase value - ((integer 0 0) - zero-sc-number) - (null - null-sc-number) - ((or (integer #.sb-xc:most-negative-fixnum #.sb-xc:most-positive-fixnum) - character) - immediate-sc-number) - (symbol - (if (static-symbol-p value) - immediate-sc-number - nil)) - (single-float - (if (eql value $0f0) - fp-single-zero-sc-number - nil)) - (double-float - (if (eql value $0d0) - fp-double-zero-sc-number - nil)))) - -(defun boxed-immediate-sc-p (sc) - (or (eql sc zero-sc-number) - (eql sc null-sc-number) - (eql sc immediate-sc-number))) - - -;;;; function call parameters - -;;; the SC numbers for register and stack arguments/return values -(defconstant immediate-arg-scn any-reg-sc-number) -(defconstant control-stack-arg-scn control-stack-sc-number) - -(eval-when (:compile-toplevel :load-toplevel :execute) - -;;; offsets of special stack frame locations -(defconstant ocfp-save-offset 0) -(defconstant lra-save-offset 1) -(defconstant nfp-save-offset 2) - -;;; the number of arguments/return values passed in registers -(defconstant register-arg-count 6) - -;;; (Names to use for the argument registers would go here, but there -;;; are none.) - -); EVAL-WHEN - -;;; a list of TN's describing the register arguments -(defparameter *register-arg-tns* - (mapcar (lambda (n) - (make-random-tn :kind :normal - :sc (sc-or-lose 'descriptor-reg) - :offset n)) - *register-arg-offsets*)) - -;;; This is used by the debugger. -(defconstant single-value-return-byte-offset 4) - -;;; This function is called by debug output routines that want a -;;; pretty name for a TN's location. It returns a thing that can be -;;; printed with PRINC. -(defun location-print-name (tn) -; (declare (type tn tn)) - (let ((sb (sb-name (sc-sb (tn-sc tn)))) - (offset (tn-offset tn))) - (ecase sb - (registers (or (svref *register-names* offset) - (format nil "R~D" offset))) - (float-registers (format nil "F~D" offset)) - (control-stack (format nil "CS~D" offset)) - (non-descriptor-stack (format nil "NS~D" offset)) - (constant (format nil "Const~D" offset)) - (immediate-constant "Immed")))) - -(defun combination-implementation-style (node) - (declare (type sb-c::combination node) (ignore node)) - (values :default nil)) - -(defun primitive-type-indirect-cell-type (ptype) - (declare (ignore ptype)) - nil) diff --git a/src/compiler/arm/alloc.lisp b/src/compiler/arm/alloc.lisp index d2f671699e..461d86e2e5 100644 --- a/src/compiler/arm/alloc.lisp +++ b/src/compiler/arm/alloc.lisp @@ -11,26 +11,18 @@ (in-package "SB-VM") -(define-vop (list-or-list*) - (:args (things :more t :scs (control-stack))) +(define-vop (list) + (:args (things :more t :scs (any-reg descriptor-reg null control-stack))) (:temporary (:scs (descriptor-reg)) ptr) (:temporary (:scs (any-reg)) temp) (:temporary (:scs (descriptor-reg) :to (:result 0) :target result) res) (:temporary (:sc non-descriptor-reg :offset ocfp-offset) pa-flag) - (:info num) + (:info star cons-cells) (:results (result :scs (descriptor-reg))) - (:variant-vars star) - (:policy :fast-safe) (:node-var node) (:generator 0 - (cond ((zerop num) - (move result null-tn)) - ((and star (= num 1)) - (move result (tn-ref-tn things))) - (t - (macrolet - ((maybe-load (tn) + (macrolet ((maybe-load (tn) (once-only ((tn tn)) `(sc-case ,tn ((any-reg descriptor-reg null) @@ -38,9 +30,8 @@ (control-stack (load-stack-tn temp ,tn) temp))))) - (let* ((cons-cells (if star (1- num) num)) - (alloc (* (pad-data-block cons-size) cons-cells))) - (pseudo-atomic (pa-flag) + (let ((alloc (* (pad-data-block cons-size) cons-cells))) + (pseudo-atomic (pa-flag) (allocation 'list alloc list-pointer-lowtag res :flag-tn pa-flag :stack-allocate-p (node-stack-allocate-p node)) @@ -59,13 +50,7 @@ (maybe-load (tn-ref-tn (tn-ref-across things))) null-tn) ptr cons-cdr-slot list-pointer-lowtag)) - (move result res))))))) - -(define-vop (list list-or-list*) - (:variant nil)) - -(define-vop (list* list-or-list*) - (:variant t)) + (move result res))))) ;;;; Special purpose inline allocators. diff --git a/src/compiler/arm/arith.lisp b/src/compiler/arm/arith.lisp index a58c834f07..0001b31a56 100644 --- a/src/compiler/arm/arith.lisp +++ b/src/compiler/arm/arith.lisp @@ -436,28 +436,22 @@ (inst bic result temp fixnum-tag-mask))) ;;; Only the lower 5 bits of the shift amount are significant. -(define-vop (shift-towards-someplace) - (:policy :fast-safe) - (:args (num :scs (unsigned-reg)) - (amount :scs (signed-reg))) - (:arg-types unsigned-num tagged-num) - (:temporary (:sc signed-reg) temp) - (:results (r :scs (unsigned-reg))) - (:result-types unsigned-num)) - -(define-vop (shift-towards-start shift-towards-someplace) - (:translate shift-towards-start) - (:note "SHIFT-TOWARDS-START") - (:generator 1 - (inst and temp amount #b11111) - (inst mov r (lsr num temp)))) - -(define-vop (shift-towards-end shift-towards-someplace) - (:translate shift-towards-end) - (:note "SHIFT-TOWARDS-END") - (:generator 1 - (inst and temp amount #b11111) - (inst mov r (lsl num temp)))) +(macrolet ((define (translate operation) + `(define-vop () + (:translate ,translate) + (:note ,(string translate)) + (:policy :fast-safe) + (:args (num :scs (unsigned-reg)) + (amount :scs (signed-reg))) + (:arg-types unsigned-num tagged-num) + (:temporary (:sc signed-reg) temp) + (:results (r :scs (unsigned-reg))) + (:result-types unsigned-num) + (:generator 1 + (inst and temp amount #b11111) + (inst mov r (,operation num temp)))))) + (define shift-towards-start lsr) + (define shift-towards-end lsl)) (define-vop (signed-byte-32-len) (:translate integer-length) diff --git a/src/compiler/arm/array.lisp b/src/compiler/arm/array.lisp index 0ba87085ed..05fbda262f 100644 --- a/src/compiler/arm/array.lisp +++ b/src/compiler/arm/array.lisp @@ -33,35 +33,14 @@ (allocation nil ndescr other-pointer-lowtag header :flag-tn pa-flag) ;; Now that we have the space allocated, compute the header ;; value. - (inst add ndescr rank (fixnumize (1- array-dimensions-offset))) - (inst mov ndescr (lsl ndescr (- n-widetag-bits n-fixnum-tag-bits))) - (inst orr ndescr ndescr (lsr type n-fixnum-tag-bits)) + ;; See ENCODE-ARRAY-RANK. + (inst sub ndescr rank (fixnumize 1)) + (inst and ndescr ndescr (fixnumize array-rank-mask)) + (inst orr ndescr type (lsl ndescr array-rank-position)) + (inst mov ndescr (lsr ndescr n-fixnum-tag-bits)) ;; And store the header value. (storew ndescr header 0 other-pointer-lowtag)) (move result header))) - -(define-vop (make-array-header/c) - (:translate make-array-header) - (:policy :fast-safe) - (:arg-types (:constant t) (:constant t)) - (:info type rank) - (:temporary (:scs (descriptor-reg) :to (:result 0) :target result) header) - (:temporary (:sc non-descriptor-reg :offset ocfp-offset) pa-flag) - (:results (result :scs (descriptor-reg))) - (:generator 4 - (let* ((header-size (+ rank - (1- array-dimensions-offset))) - (bytes (logandc2 (+ (* (1+ header-size) n-word-bytes) - lowtag-mask) - lowtag-mask)) - (header-bits (logior (ash header-size - n-widetag-bits) - type))) - (pseudo-atomic (pa-flag) - (allocation nil bytes other-pointer-lowtag header :flag-tn pa-flag) - (load-immediate-word pa-flag header-bits) - (storew pa-flag header 0 other-pointer-lowtag))) - (move result header))) ;;;; Additional accessors and setters for the array header. (define-full-reffer %array-dimension * @@ -72,17 +51,19 @@ array-dimensions-offset other-pointer-lowtag (any-reg) positive-fixnum sb-kernel:%set-array-dimension) -(define-vop (array-rank-vop) - (:translate sb-kernel:%array-rank) +(define-vop () + (:translate %array-rank) (:policy :fast-safe) (:args (x :scs (descriptor-reg))) - (:temporary (:scs (non-descriptor-reg)) temp) - (:results (res :scs (any-reg descriptor-reg))) + (:results (res :scs (unsigned-reg))) + (:result-types positive-fixnum) (:generator 6 - (loadw temp x 0 other-pointer-lowtag) - (inst mov temp (asr temp n-widetag-bits)) - (inst sub temp temp (1- array-dimensions-offset)) - (inst mov res (lsl temp n-fixnum-tag-bits)))) + ;; convert ARRAY-RANK-POSITION to byte index and compensate for endianness + ;; ASSUMPTION: n-widetag-bits = 8 and rank is adjacent to widetag + (inst ldrb res (@ x #+little-endian (- 1 other-pointer-lowtag) + #+big-endian (- 2 other-pointer-lowtag))) + (inst add res res 1) + (inst and res res array-rank-mask))) ;;;; Bounds checking routine. (define-vop (check-bound) @@ -204,10 +185,8 @@ (:policy :fast-safe) (:args (object :scs (descriptor-reg)) (index :scs (unsigned-reg) :target shift) - (value :scs (unsigned-reg immediate) :target result)) + (value :scs (unsigned-reg immediate))) (:arg-types ,type positive-fixnum positive-fixnum) - (:results (result :scs (unsigned-reg))) - (:result-types positive-fixnum) (:temporary (:scs (interior-reg)) lip) (:temporary (:scs (non-descriptor-reg)) temp old) (:temporary (:scs (non-descriptor-reg) :from (:argument 1)) shift) @@ -231,7 +210,7 @@ (= (tn-value value) ,(1- (ash 1 bits)))) (inst mov temp ,(1- (ash 1 bits))) (inst bic old old (lsl temp shift))) - ;; LOGIOR in the new value (shifted appropriatly). + ;; LOGIOR in the new value (shifted appropriately). (sc-case value (immediate (inst mov temp (logand (tn-value value) ,(1- (ash 1 bits))))) @@ -241,13 +220,7 @@ ;; Write the altered word back to the array. (inst str old (@ lip (- (* vector-data-offset n-word-bytes) - other-pointer-lowtag))) - ;; And present the result properly. - (sc-case value - (immediate - (inst mov result (tn-value value))) - (unsigned-reg - (move result value))))))))) + other-pointer-lowtag))))))))) (def-small-data-vector-frobs simple-bit-vector 1) (def-small-data-vector-frobs simple-array-unsigned-byte-2 2) (def-small-data-vector-frobs simple-array-unsigned-byte-4 4)) @@ -276,18 +249,14 @@ (:policy :fast-safe) (:args (object :scs (descriptor-reg)) (index :scs (any-reg)) - (value :scs (single-reg) :target result)) + (value :scs (single-reg))) (:arg-types simple-array-single-float positive-fixnum single-float) - (:results (result :scs (single-reg))) - (:result-types single-float) (:temporary (:scs (interior-reg)) lip) (:generator 5 (inst add lip object (- (* vector-data-offset n-word-bytes) other-pointer-lowtag)) (inst add lip lip index) - (inst fsts value (@ lip)) - (unless (location= result value) - (inst fcpys result value)))) + (inst fsts value (@ lip)))) (define-vop (data-vector-ref/simple-array-double-float) (:note "inline array access") @@ -311,18 +280,14 @@ (:policy :fast-safe) (:args (object :scs (descriptor-reg)) (index :scs (any-reg)) - (value :scs (double-reg) :target result)) + (value :scs (double-reg))) (:arg-types simple-array-double-float positive-fixnum double-float) - (:results (result :scs (double-reg))) - (:result-types double-float) (:temporary (:scs (interior-reg)) lip) (:generator 20 (inst add lip object (- (* vector-data-offset n-word-bytes) other-pointer-lowtag)) (inst add lip lip (lsl index 1)) - (inst fstd value (@ lip)) - (unless (location= result value) - (inst fcpyd result value)))) + (inst fstd value (@ lip)))) ;;; Complex float arrays. @@ -351,26 +316,16 @@ (:policy :fast-safe) (:args (object :scs (descriptor-reg) :to :result) (index :scs (any-reg)) - (value :scs (complex-single-reg) :target result)) + (value :scs (complex-single-reg))) (:arg-types simple-array-complex-single-float positive-fixnum complex-single-float) - (:results (result :scs (complex-single-reg))) - (:result-types complex-single-float) (:temporary (:scs (interior-reg)) lip) (:generator 5 - (let ((value-real (complex-single-reg-real-tn value)) - (result-real (complex-single-reg-real-tn result))) - (inst add lip object (- (* vector-data-offset n-word-bytes) - other-pointer-lowtag)) - (inst add lip lip (lsl index 1)) - (inst fsts value-real (@ lip)) - (unless (location= result-real value-real) - (inst fcpys result-real value-real))) - (let ((value-imag (complex-single-reg-imag-tn value)) - (result-imag (complex-single-reg-imag-tn result))) - (inst fsts value-imag (@ lip n-word-bytes)) - (unless (location= result-imag value-imag) - (inst fcpys result-imag value-imag))))) + (inst add lip object (- (* vector-data-offset n-word-bytes) + other-pointer-lowtag)) + (inst add lip lip (lsl index 1)) + (inst fsts (complex-single-reg-real-tn value) (@ lip)) + (inst fsts (complex-single-reg-imag-tn value) (@ lip n-word-bytes)))) (define-vop (data-vector-ref/simple-array-complex-double-float) (:note "inline array access") @@ -397,26 +352,16 @@ (:policy :fast-safe) (:args (object :scs (descriptor-reg) :to :result) (index :scs (any-reg)) - (value :scs (complex-double-reg) :target result)) + (value :scs (complex-double-reg))) (:arg-types simple-array-complex-double-float positive-fixnum complex-double-float) - (:results (result :scs (complex-double-reg))) - (:result-types complex-double-float) (:temporary (:scs (interior-reg)) lip) (:generator 20 - (let ((value-real (complex-double-reg-real-tn value)) - (result-real (complex-double-reg-real-tn result))) - (inst add lip object (- (* vector-data-offset n-word-bytes) - other-pointer-lowtag)) - (inst add lip lip (lsl index 2)) - (inst fstd value-real (@ lip)) - (unless (location= result-real value-real) - (inst fcpyd result-real value-real))) - (let ((value-imag (complex-double-reg-imag-tn value)) - (result-imag (complex-double-reg-imag-tn result))) - (inst fstd value-imag (@ lip (* 2 n-word-bytes))) - (unless (location= result-imag value-imag) - (inst fcpyd result-imag value-imag))))) + (inst add lip object (- (* vector-data-offset n-word-bytes) + other-pointer-lowtag)) + (inst add lip lip (lsl index 2)) + (inst fstd (complex-double-reg-real-tn value) (@ lip)) + (inst fstd (complex-double-reg-imag-tn value) (@ lip (* 2 n-word-bytes))))) ;;; These vops are useful for accessing the bits of a vector irrespective of ;;; what type of vector it is. diff --git a/src/compiler/arm/c-call.lisp b/src/compiler/arm/c-call.lisp index 16d59bf17f..9d45806801 100644 --- a/src/compiler/arm/c-call.lisp +++ b/src/compiler/arm/c-call.lisp @@ -55,7 +55,17 @@ #+arm-softfp (define-alien-type-method (single-float :arg-tn) (type state) (declare (ignore type)) - (int-arg state 'single-float unsigned-reg-sc-number single-stack-sc-number)) + (let ((register (arg-state-num-register-args state))) + (cond ((>= register +max-register-args+) + (let ((frame-size (arg-state-stack-frame-size state))) + (incf (arg-state-stack-frame-size state)) + (make-wired-tn* 'single-float single-stack-sc-number frame-size))) + (t + (incf (arg-state-num-register-args state)) + (list + (make-wired-tn* 'unsigned-byte-32 unsigned-reg-sc-number + (register-args-offset register)) + 'move-single-to-int-args))))) #-arm-softfp (define-alien-type-method (single-float :arg-tn) (type state) @@ -123,7 +133,9 @@ #+arm-softfp (define-alien-type-method (single-float :result-tn) (type state) (declare (ignore type state)) - (make-wired-tn* 'single-float unsigned-reg-sc-number nargs-offset)) + (list (make-wired-tn* 'unsigned-byte-32 unsigned-reg-sc-number nargs-offset) + (make-normal-tn (primitive-type-or-lose 'single-float)) + 'move-int-args-to-single)) #-arm-softfp (define-alien-type-method (single-float :result-tn) (type state) @@ -247,31 +259,51 @@ ;;; #+arm-softfp -(define-vop (move-double-to-int-args) - (:args (double :scs (double-reg))) - (:results (lo-bits :scs (unsigned-reg)) - (hi-bits :scs (unsigned-reg))) - (:arg-types double-float) - (:result-types unsigned-num unsigned-num) - (:policy :fast-safe) - (:generator 1 - (inst fmrrd lo-bits hi-bits double))) - -#+arm-softfp -(define-vop (move-int-args-to-double) - (:args (lo-bits :scs (unsigned-reg)) - (hi-bits :scs (unsigned-reg))) - (:results (double :scs (double-reg))) - (:arg-types unsigned-num unsigned-num) - (:result-types double-float) - (:policy :fast-safe) - (:generator 1 - (inst fmdrr double lo-bits hi-bits))) +(progn + (define-vop (move-double-to-int-args) + (:args (double :scs (double-reg))) + (:results (lo-bits :scs (unsigned-reg)) + (hi-bits :scs (unsigned-reg))) + (:arg-types double-float) + (:result-types unsigned-num unsigned-num) + (:policy :fast-safe) + (:generator 1 + (inst fmrrd lo-bits hi-bits double))) + + + (define-vop (move-int-args-to-double) + (:args (lo-bits :scs (unsigned-reg)) + (hi-bits :scs (unsigned-reg))) + (:results (double :scs (double-reg))) + (:arg-types unsigned-num unsigned-num) + (:result-types double-float) + (:policy :fast-safe) + (:generator 1 + (inst fmdrr double lo-bits hi-bits))) + + (define-vop (move-single-to-int-args) + (:args (single :scs (single-reg))) + (:results (bits :scs (unsigned-reg))) + (:arg-types single-float) + (:result-types unsigned-num) + (:policy :fast-safe) + (:generator 1 + (inst fmrs bits single))) + + + (define-vop (move-int-args-to-single) + (:args (bits :scs (unsigned-reg))) + (:results (single :scs (single-reg))) + (:arg-types unsigned-num) + (:result-types single-float) + (:policy :fast-safe) + (:generator 1 + (inst fmsr single bits)))) ;;; long-long support (deftransform %alien-funcall ((function type &rest args) * * :node node) - (aver (sb-c::constant-lvar-p type)) - (let* ((type (sb-c::lvar-value type)) + (aver (sb-c:constant-lvar-p type)) + (let* ((type (sb-c:lvar-value type)) (env (sb-c::node-lexenv node)) (arg-types (alien-fun-type-arg-types type)) (result-type (alien-fun-type-result-type type))) diff --git a/src/compiler/arm/call.lisp b/src/compiler/arm/call.lisp index 1c5f66cef9..7d207359e3 100644 --- a/src/compiler/arm/call.lisp +++ b/src/compiler/arm/call.lisp @@ -14,48 +14,31 @@ (defconstant arg-count-sc (make-sc+offset immediate-arg-scn nargs-offset)) (defconstant closure-sc (make-sc+offset descriptor-reg-sc-number lexenv-offset)) -;;; Always wire the return PC location to the stack in its standard -;;; location. -(defun make-return-pc-passing-location (standard) - (declare (ignore standard)) - (make-wired-tn *backend-t-primitive-type* control-stack-sc-number - lra-save-offset)) - (defconstant return-pc-passing-offset (make-sc+offset control-stack-sc-number lra-save-offset)) -;;; This is similar to MAKE-RETURN-PC-PASSING-LOCATION, but makes a -;;; location to pass OLD-FP in. -;;; -;;; This is wired in both the standard and the local-call conventions, -;;; because we want to be able to assume it's always there. Besides, -;;; the ARM doesn't have enough registers to really make it profitable -;;; to pass it in a register. -(defun make-old-fp-passing-location () - (make-wired-tn *fixnum-primitive-type* control-stack-sc-number - ocfp-save-offset)) - (defconstant old-fp-passing-offset (make-sc+offset control-stack-sc-number ocfp-save-offset)) ;;; Make the TNs used to hold OLD-FP and RETURN-PC within the current ;;; function. We treat these specially so that the debugger can find ;;; them at a known location. -(defun make-old-fp-save-location (env) +(defun make-old-fp-save-location () ;; Unlike the other backends, ARM function calling is designed to ;; pass OLD-FP within the stack frame rather than in a register. As ;; such, in order for lifetime analysis not to screw up, we need it ;; to be a stack TN wired to the save offset, not a normal TN with a ;; wired SAVE-TN. - (physenv-debug-live-tn (make-wired-tn *fixnum-primitive-type* - control-stack-arg-scn - ocfp-save-offset) - env)) -(defun make-return-pc-save-location (physenv) - (physenv-debug-live-tn - (make-wired-tn *backend-t-primitive-type* control-stack-sc-number - lra-save-offset) - physenv)) + (let ((tn (make-wired-tn *fixnum-primitive-type* + control-stack-arg-scn + ocfp-save-offset))) + (setf (tn-kind tn) :environment) + tn)) +(defun make-return-pc-save-location () + (let ((tn (make-wired-tn *backend-t-primitive-type* control-stack-sc-number + lra-save-offset))) + (setf (tn-kind tn) :environment) + tn)) ;;; Make a TN for the standard argument count passing location. We ;;; only need to make the standard location, since a count is never @@ -151,7 +134,7 @@ (* (max 1 (sb-allocated-size 'control-stack)) n-word-bytes)) (store-csp nfp) - (when (ir2-physenv-number-stack-p callee) + (when (ir2-environment-number-stack-p callee) (let* ((nbytes (bytes-needed-for-non-descriptor-stack-frame))) (inst sub nfp nsp-tn nbytes) (inst mov nsp-tn nfp))))) @@ -309,8 +292,7 @@ values-start) (:temporary (:sc any-reg :offset nargs-offset :from :eval :to (:result 1)) - nvals) - (:temporary (:scs (non-descriptor-reg)) temp)) + nvals)) ;;; This hook in the codegen pass lets us insert code before fall-thru entry ;;; points, local-call entry points, and tail-call entry points. The default diff --git a/src/compiler/arm/cell.lisp b/src/compiler/arm/cell.lisp index 5bbd2857d1..681328b423 100644 --- a/src/compiler/arm/cell.lisp +++ b/src/compiler/arm/cell.lisp @@ -30,10 +30,6 @@ (:results) (:generator 1 (storew value object offset lowtag))) - -(define-vop (init-slot set-slot) - (:info name dx-p offset lowtag) - (:ignore name dx-p)) ;;;; Symbol hacking VOPs: @@ -52,11 +48,10 @@ (:save-p :compute-only) (:temporary (:scs (descriptor-reg) :from (:argument 0)) obj-temp)) -;;; With Symbol-Value, we check that the value isn't the trap object. So -;;; Symbol-Value of NIL is NIL. +;;; With Symbol-Value, we check that the value isn't the trap object. ;;; (define-vop (symbol-value checked-cell-ref) - (:translate symeval) + (:translate symbol-value) (:generator 9 (move obj-temp object) (loadw value obj-temp symbol-value-slot other-pointer-lowtag) @@ -65,14 +60,12 @@ (inst b :eq err-lab)))) ;;; Like CHECKED-CELL-REF, only we are a predicate to see if the cell is bound. -(define-vop (boundp-frob) +(define-vop (boundp) (:args (object :scs (descriptor-reg))) (:conditional) (:info target not-p) (:policy :fast-safe) - (:temporary (:scs (descriptor-reg)) value)) - -(define-vop (boundp boundp-frob) + (:temporary (:scs (descriptor-reg)) value) (:translate boundp) (:generator 9 (loadw value object symbol-value-slot other-pointer-lowtag) @@ -82,7 +75,7 @@ (define-vop (fast-symbol-value cell-ref) (:variant symbol-value-slot other-pointer-lowtag) (:policy :fast) - (:translate symeval)) + (:translate symbol-value)) (define-vop (symbol-hash) (:policy :fast-safe) @@ -102,9 +95,9 @@ ;;; On unithreaded builds these are just copies of the non-global versions. (define-vop (%set-symbol-global-value set)) (define-vop (symbol-global-value symbol-value) - (:translate sym-global-val)) + (:translate symbol-global-value)) (define-vop (fast-symbol-global-value fast-symbol-value) - (:translate sym-global-val)) + (:translate symbol-global-value)) ;;;; Fdefinition (fdefn) objects. @@ -150,10 +143,9 @@ (define-vop (fdefn-makunbound) (:policy :fast-safe) (:translate fdefn-makunbound) - (:args (fdefn :scs (descriptor-reg) :target result)) + (:args (fdefn :scs (descriptor-reg))) (:temporary (:scs (non-descriptor-reg)) temp) (:temporary (:scs (interior-reg)) lip) - (:results (result :scs (descriptor-reg))) (:generator 38 (let ((undefined-tramp-fixup (gen-label))) (assemble (:elsewhere) @@ -161,9 +153,7 @@ (inst word (make-fixup 'undefined-tramp :assembly-routine))) (storew null-tn fdefn fdefn-fun-slot other-pointer-lowtag) (inst load-from-label temp lip undefined-tramp-fixup) - (storew temp fdefn fdefn-raw-addr-slot other-pointer-lowtag) - (move result fdefn)))) - + (storew temp fdefn fdefn-raw-addr-slot other-pointer-lowtag)))) ;;;; Binding and Unbinding. @@ -234,9 +224,9 @@ closure-info-offset fun-pointer-lowtag (descriptor-reg any-reg) * %closure-index-ref) -(define-full-setter set-funcallable-instance-info * - funcallable-instance-info-offset fun-pointer-lowtag - (descriptor-reg any-reg null) * %set-funcallable-instance-info) +(define-full-setter %closure-index-set * + closure-info-offset fun-pointer-lowtag + (descriptor-reg any-reg null) * %closure-index-set) (define-full-reffer funcallable-instance-info * funcallable-instance-info-offset fun-pointer-lowtag @@ -293,8 +283,49 @@ (define-full-reffer code-header-ref * 0 other-pointer-lowtag (descriptor-reg any-reg) * code-header-ref) -(define-full-setter code-header-set * 0 other-pointer-lowtag - (descriptor-reg any-reg null) * code-header-set) +(define-vop (code-header-set) + (:translate code-header-set) + (:policy :fast-safe) + (:args (object :scs (descriptor-reg)) + (index :scs (any-reg)) + (value :scs (any-reg descriptor-reg))) + (:arg-types * tagged-num *) + (:temporary (:scs (non-descriptor-reg)) temp #+gencgc card) + #+gencgc (:temporary (:scs (interior-reg)) lip) + #+gencgc (:temporary (:sc non-descriptor-reg) pa-flag) + (:generator 10 + #+cheneygc + (progn (inst sub temp index other-pointer-lowtag) + (inst str value (@ object temp))) + #+gencgc + (let ((mask-fixup-label (gen-label)) + (table-fixup-label (gen-label))) + (inst load-from-label temp lip mask-fixup-label) + (inst ldr temp (@ temp)) + (inst ldr temp (@ temp)) + (pseudo-atomic (pa-flag) + ;; Compute card mark index + (inst mov card (lsr object gencgc-card-shift)) + (inst and card card temp) + ;; Load mark table base + (inst load-from-label temp lip table-fixup-label) + (inst ldr temp (@ temp)) + (inst ldr temp (@ temp)) + ;; Touch the card mark byte. + (inst strb null-tn (@ temp card)) + ;; set 'written' flag in the code header + ;; If two threads get here at the same time, they'll write the same byte. + (let ((byte (- #+little-endian 3 other-pointer-lowtag))) + (inst ldrb temp (@ object byte)) + (inst orr temp temp #x40) + (inst strb temp (@ object byte))) + (inst sub temp index other-pointer-lowtag) + (inst str value (@ object temp))) + (assemble (:elsewhere) + (emit-label mask-fixup-label) + (inst word (make-fixup "gc_card_table_mask" :foreign-dataref)) + (emit-label table-fixup-label) + (inst word (make-fixup "gc_card_mark" :foreign-dataref)))))) ;;;; raw instance slot accessors @@ -311,11 +342,9 @@ `((inst ,instruction value (@ object offset)))) ,@(when move-result `((,move-macro result value)))))) - (let ((ref-vop (symbolicate "RAW-INSTANCE-REF/" name)) - (set-vop (symbolicate "RAW-INSTANCE-SET/" name))) `(progn - (define-vop (,ref-vop) - (:translate ,(symbolicate "%" ref-vop)) + (define-vop () + (:translate ,(symbolicate "%RAW-INSTANCE-REF/" name)) (:policy :fast-safe) (:args (object :scs (descriptor-reg)) (index :scs (any-reg))) @@ -325,18 +354,16 @@ (:temporary (:scs (non-descriptor-reg)) offset) ,@(when use-lip '((:temporary (:scs (interior-reg)) lip))) (:generator 5 ,@(emit-generator ref-inst nil))) - (define-vop (,set-vop) - (:translate ,(symbolicate "%" set-vop)) + (define-vop () + (:translate ,(symbolicate "%RAW-INSTANCE-SET/" name)) (:policy :fast-safe) (:args (object :scs (descriptor-reg)) (index :scs (any-reg)) - (value :scs (,value-sc) :target result)) + (value :scs (,value-sc))) (:arg-types * positive-fixnum ,value-primtype) - (:results (result :scs (,value-sc))) - (:result-types ,value-primtype) (:temporary (:scs (non-descriptor-reg)) offset) ,@(when use-lip '((:temporary (:scs (interior-reg)) lip))) - (:generator 5 ,@(emit-generator set-inst t)))))))) + (:generator 5 ,@(emit-generator set-inst nil))))))) (define-raw-slot-vops word ldr str unsigned-num unsigned-reg) (define-raw-slot-vops signed-word ldr str signed-num signed-reg) (define-raw-slot-vops single flds fsts single-float single-reg diff --git a/src/compiler/arm/debug.lisp b/src/compiler/arm/debug.lisp index f687b1f18d..7c7e88dc95 100644 --- a/src/compiler/arm/debug.lisp +++ b/src/compiler/arm/debug.lisp @@ -19,7 +19,7 @@ (:generator 1 (load-csp res))) -(define-vop () +(define-vop (current-fp-sap) (:translate current-fp) (:policy :fast-safe) (:results (res :scs (sap-reg))) @@ -43,13 +43,10 @@ (:policy :fast-safe) (:args (sap :scs (sap-reg)) (offset :scs (any-reg)) - (value :scs (descriptor-reg) :target result)) + (value :scs (descriptor-reg))) (:arg-types system-area-pointer positive-fixnum *) - (:results (result :scs (descriptor-reg))) - (:result-types *) (:generator 5 - (inst str value (@ sap offset)) - (move result value))) + (inst str value (@ sap offset)))) (define-vop (code-from-mumble) (:policy :fast-safe) @@ -59,7 +56,7 @@ (:variant-vars lowtag) (:generator 5 (loadw temp thing 0 lowtag) - ;; SLEAZY ASSUMPTION: THE WIDETAG HAS TWO HIGH ZERO BITS + (inst bic temp temp widetag-mask) (inst mov temp (lsr temp (- n-widetag-bits word-shift))) (inst cmp temp 0) (unless (= lowtag other-pointer-lowtag) diff --git a/src/compiler/arm/insts.lisp b/src/compiler/arm/insts.lisp index b8ed214fce..3afb611888 100644 --- a/src/compiler/arm/insts.lisp +++ b/src/compiler/arm/insts.lisp @@ -14,7 +14,7 @@ (eval-when (:compile-toplevel :load-toplevel :execute) ;; Imports from this package into SB-VM - (import '(conditional-opcode emit-word + (import '(conditional-opcode negate-condition emit-word composite-immediate-instruction encodable-immediate lsl lsr asr ror cpsr @) "SB-VM") ;; Imports from SB-VM into this package @@ -40,15 +40,18 @@ (:le . 13) (:al . 14)) #'equal) -(defconstant-eqx sb-vm::+condition-name-vec+ - #.(let ((vec (make-array 16 :initial-element nil))) - (dolist (cond +conditions+ vec) - (when (null (aref vec (cdr cond))) - (setf (aref vec (cdr cond)) (car cond))))) +(defconstant-eqx +condition-name-vec+ + (let ((vec (make-array 16 :initial-element nil))) + (dolist (cond +conditions+ vec) + (when (null (aref vec (cdr cond))) + (setf (aref vec (cdr cond)) (car cond))))) #'equalp) (defun conditional-opcode (condition) (cdr (assoc condition +conditions+ :test #'eq))) +(defun negate-condition (name) + (let ((code (logxor 1 (conditional-opcode name)))) + (aref +condition-name-vec+ code))) ;;;; disassembler field definitions @@ -716,6 +719,31 @@ (define-data-processing-instruction movs #x1b t nil) (define-data-processing-instruction mvn #x1e t nil) (define-data-processing-instruction mvns #x1f t nil) + +(define-instruction-format (movw-format 32 + :default-printer '(:name :tab rd ", #" immediate)) + (cond :field (byte 4 28) :type 'condition-code) + (opcode-8 :field (byte 8 20)) + (immediate :fields (list (byte 4 16) (byte 12 0)) + :prefilter (lambda (dstate high low) + (declare (ignore dstate)) + (logior (ash high 12) low))) + (rd :field (byte 4 12) :type 'reg)) + +(macrolet ((mov-imm-16 (segment rd imm half) + `(emit-dp-instruction ,segment 14 #b00 #b1 + ,(ecase half + (:low #b10000) + (:high #b10100)) + (ldb (byte 4 12) ,imm) + (tn-offset ,rd) + (ldb (byte 12 0) ,imm)))) +(define-instruction movw (segment rd imm) ; move wide (zero-extend) + (:printer movw-format ((opcode-8 #b00110000))) + (:emitter (mov-imm-16 segment rd imm :low))) +(define-instruction movt (segment rd imm) ; move top bits (and keep bottom) + (:printer movw-format ((opcode-8 #b00110100))) + (:emitter (mov-imm-16 segment rd imm :high)))) ;;;; Exception-generating instructions @@ -752,10 +780,10 @@ ;;; generation instruction, or breakpoint. (define-instruction debug-trap (segment) (:printer debug-trap ((opcode-32 #+linux #xe7f001f0 - #+netbsd #xe7ffdefe)) + #+(or netbsd openbsd) #xe7ffdefe)) :default :control #'debug-trap-control) (:emitter - (emit-word segment #+linux #xe7f001f0 #+netbsd #xe7ffdefe))) + (emit-word segment #+linux #xe7f001f0 #+(or netbsd openbsd) #xe7ffdefe))) ;;;; Miscellaneous arithmetic instructions @@ -1177,7 +1205,7 @@ (:vop-var vop) (:emitter (emit-back-patch - segment 12 + segment 16 (lambda (segment position) (assemble (segment vop) ;; Calculate the address of the code component. This is an @@ -1193,11 +1221,9 @@ other-pointer-lowtag))) ;; Next, we read the function header. (inst ldr temp (@ lip (- other-pointer-lowtag))) + (inst bic temp temp widetag-mask) ;; And finally we use the header value (a count in words), - ;; plus the fact that the top two bits of the widetag are - ;; clear (SIMPLE-FUN-WIDETAG is #x2A and - ;; RETURN-PC-WIDETAG is #x36) to compute the boxed - ;; address of the code component. + ;; to compute the boxed address of the code component. (inst sub code lip (lsr temp (- 8 word-shift)))))))) ;;; Compute the address of a nearby LRA object by dead reckoning from @@ -1283,6 +1309,9 @@ (define-instruction load-from-label (segment &rest args) (:vop-var vop) (:emitter + ;; ISTM this use of an interior-pointer is unnecessary. Since we know the + ;; displacement of the label from the base of the CODE, we could load + ;; either from [code+X] or [PC+X] where X is in an unsigned-reg. (with-condition-defaulted (args (condition dest lip label)) ;; We can load the word addressed by a label in a single ;; instruction if the overall offset puts it to within a 12-bit @@ -1734,3 +1763,47 @@ (define-two-reg-transfer-fp-instruction fmrrs :single :to-arm) (define-two-reg-transfer-fp-instruction fmdrr :double :from-arm) (define-two-reg-transfer-fp-instruction fmrrd :double :to-arm) + +(sb-assem::%def-inst-encoder + '.layout-id + (lambda (segment layout) + (sb-c:note-fixup segment :layout-id (sb-c:make-fixup layout :layout-id)))) + +(defun sb-vm:fixup-code-object (code offset value kind flavor) + (declare (type index offset) (ignore flavor)) + (unless (zerop (rem offset sb-assem:+inst-alignment-bytes+)) + (error "Unaligned instruction? offset=#x~X." offset)) + (let ((sap (code-instructions code))) + (ecase kind + (:layout-id + (aver (typep value '(unsigned-byte 24))) + (setf (sap-ref-word sap offset) + (dpb (ldb (byte 8 16) value) (byte 8 0) (sap-ref-word sap offset)) + (sap-ref-word sap (+ offset 4)) + (dpb (ldb (byte 8 8) value) (byte 8 0) (sap-ref-word sap (+ offset 4))) + (sap-ref-word sap (+ offset 8)) + (dpb (ldb (byte 8 0) value) (byte 8 0) (sap-ref-word sap (+ offset 8))))) + (:absolute + (setf (sap-ref-32 sap offset) value)))) + nil) + +(define-instruction store-coverage-mark (segment mark-index temp) + (:emitter + ;; No backpatch is needed to compute the offset into the code header + ;; because COMPONENT-HEADER-LENGTH is known at this point. + (let* ((offset (+ (component-header-length) + ;; skip over jump table word and entries + (* (1+ (component-n-jump-table-entries)) + n-word-bytes) + mark-index + (- other-pointer-lowtag))) + (addr + (@ sb-vm::code-tn + (etypecase offset + ((integer 0 4095) offset) + ((unsigned-byte 31) + (inst* segment 'movw temp (logand offset #xffff)) + (when (ldb-test (byte 16 16) offset) + (inst* segment 'movt temp (ldb (byte 16 16) offset))) + temp))))) + (inst* segment 'strb sb-vm::null-tn addr)))) diff --git a/src/compiler/arm/macros.lisp b/src/compiler/arm/macros.lisp index 6f1a435b45..1e143e688e 100644 --- a/src/compiler/arm/macros.lisp +++ b/src/compiler/arm/macros.lisp @@ -209,7 +209,7 @@ (ash 1 (tn-offset lr-tn)))) ;; select the C function index as per *LINKAGE-SPACE-PREDEFINED-ENTRIES* (let ((index (if (eq type 'list) 1 0))) - (inst ldr alloc-tn (@ null-tn (- (linkage-table-entry-address index) + (inst ldr alloc-tn (@ null-tn (- (alien-linkage-table-entry-address index) nil-value)))) (inst blx alloc-tn) (inst word (logior #xe8bd0000 ; POP {rN, lr} @@ -231,28 +231,18 @@ ;; stack pointer has been stored. (storew null-tn result-tn -1 0 :ne) (inst orr result-tn result-tn lowtag)) - #-gencgc (t - (load-symbol-value flag-tn *allocation-pointer*) - (inst add result-tn flag-tn lowtag) - (if (integerp size) - (composite-immediate-instruction add flag-tn flag-tn size) - (inst add flag-tn flag-tn size)) - (store-symbol-value flag-tn *allocation-pointer*)) - #+gencgc - (t - (let ((boxed-region (- (+ static-space-start (* 2 n-word-bytes)) - nil-value)) + (let ((region-disp (- mixed-region nil-value)) (alloc (gen-label)) (back-from-alloc (gen-label))) - (inst ldr result-tn (@ null-tn boxed-region)) ; free ptr - (inst ldr flag-tn (@ null-tn (+ boxed-region n-word-bytes))) ; end ptr + (inst ldr result-tn (@ null-tn region-disp)) ; free ptr + (inst ldr flag-tn (@ null-tn (+ region-disp n-word-bytes))) ; end ptr (if (integerp size) (composite-immediate-instruction add result-tn result-tn size) (inst add result-tn result-tn size)) (inst cmp result-tn flag-tn) (inst b :hi ALLOC) - (inst str result-tn (@ null-tn boxed-region)) ; free ptr + (inst str result-tn (@ null-tn region-disp)) ; free ptr (if (integerp size) (composite-immediate-instruction sub result-tn result-tn size) @@ -281,9 +271,8 @@ (allocation nil (pad-data-block ,size) ,lowtag ,result-tn :flag-tn ,flag-tn :stack-allocate-p ,stack-allocate-p) - (when ,type-code - (load-immediate-word ,flag-tn (compute-object-header ,size ,type-code)) - (storew ,flag-tn ,result-tn 0 ,lowtag)) + (load-immediate-word ,flag-tn (compute-object-header ,size ,type-code)) + (storew ,flag-tn ,result-tn 0 ,lowtag) ,@body))) ;;;; Error Code @@ -357,15 +346,12 @@ (:policy :fast-safe) (:args (object :scs (descriptor-reg)) (index :scs (any-reg)) - (value :scs ,scs :target result)) + (value :scs ,scs)) (:arg-types ,type tagged-num ,el-type) (:temporary (:scs (interior-reg)) lip) - (:results (result :scs ,scs)) - (:result-types ,el-type) (:generator 2 (inst add lip object index) - (storew value lip ,offset ,lowtag) - (move result value)))) + (storew value lip ,offset ,lowtag)))) (defmacro define-partial-reffer (name type size signed offset lowtag scs el-type &optional translate) @@ -396,15 +382,12 @@ (:policy :fast-safe) (:args (object :scs (descriptor-reg)) (index :scs (unsigned-reg)) - (value :scs ,scs :target result)) + (value :scs ,scs)) (:arg-types ,type positive-fixnum ,el-type) (:temporary (:scs (interior-reg)) lip) - (:results (result :scs ,scs)) - (:result-types ,el-type) (:generator 5 ,(if (eq size :byte) '(inst add lip object index) '(inst add lip object (lsl index 1))) (inst ,(ecase size (:byte 'strb) (:short 'strh)) - value (@ lip (- (* ,offset n-word-bytes) ,lowtag))) - (move result value)))) + value (@ lip (- (* ,offset n-word-bytes) ,lowtag)))))) diff --git a/src/compiler/arm/move.lisp b/src/compiler/arm/move.lisp index 7bc0a60dbb..0b16a52c79 100644 --- a/src/compiler/arm/move.lisp +++ b/src/compiler/arm/move.lisp @@ -20,7 +20,7 @@ ;;; This should be put into composite-immediate-instruction, but that ;;; macro is too scary. (defun load-repeating-pattern (dest val) - (declare (type (signed-byte 32) val)) + (declare (type (unsigned-byte 32) val)) (inst mov dest (ldb (byte 8 0) val)) (inst orr dest dest (mask-field (byte 8 8) val)) (inst orr dest dest (lsl dest 16))) @@ -237,7 +237,7 @@ (inst adds temp x x) (inst adds :vc y temp temp) (inst b :vc DONE) - (load-constant vop (emit-constant (1+ sb-xc:most-positive-fixnum)) + (load-constant vop (emit-constant (1+ most-positive-fixnum)) y) DONE)) @@ -246,7 +246,7 @@ (inst adds temp x x) (inst adds :vc y temp temp) (inst b :vc DONE) - (load-constant vop (emit-constant (1- sb-xc:most-negative-fixnum)) + (load-constant vop (emit-constant (1- most-negative-fixnum)) y) DONE)) diff --git a/src/compiler/arm/nlx.lisp b/src/compiler/arm/nlx.lisp index ed6848f67b..f62b286a16 100644 --- a/src/compiler/arm/nlx.lisp +++ b/src/compiler/arm/nlx.lisp @@ -182,6 +182,21 @@ (load-stack-tn move-temp sp) (store-csp move-temp))) +(define-vop (nlx-entry-single) + (:args (sp) + (value)) + (:results (res :from :load)) + (:temporary (:scs (descriptor-reg)) move-temp) + (:info label) + (:save-p :force-to-stack) + (:vop-var vop) + (:generator 30 + (emit-return-pc label) + (note-this-location vop :non-local-entry) + (move res value) + (load-stack-tn move-temp sp) + (store-csp move-temp))) + (define-vop (nlx-entry-multiple) (:args (top :target result) (src) (count)) ;; Again, no SC restrictions for the args, 'cause the loading would diff --git a/src/compiler/arm/parms.lisp b/src/compiler/arm/parms.lisp index 4ea344303d..3f1df27c10 100644 --- a/src/compiler/arm/parms.lisp +++ b/src/compiler/arm/parms.lisp @@ -19,12 +19,12 @@ (defconstant +backend-fasl-file-implementation+ :arm) ;; Minumum observed value, not authoritative. -(defconstant +backend-page-bytes+ #+linux 4096 #+netbsd 8192) +(defconstant +backend-page-bytes+ #-netbsd 4096 #+netbsd 8192) ;;; The size in bytes of GENCGC cards, i.e. the granularity at which ;;; writes to old generations are logged. With mprotect-based write ;;; barriers, this must be a multiple of the OS page size. -(defconstant gencgc-card-bytes +backend-page-bytes+) +(defconstant gencgc-page-bytes +backend-page-bytes+) ;;; The minimum size of new allocation regions. While it doesn't ;;; currently make a lot of sense to have a card size lower than ;;; the alloc granularity, it will, once we are smarter about finding @@ -41,34 +41,6 @@ ;;; address space) (defconstant n-machine-word-bits 32) -;;; Floating-point related constants, both format descriptions and FPU -;;; control register descriptions. These don't exactly match up with -;;; what the machine manuals say because the Common Lisp standard -;;; defines floating-point values somewhat differently than the IEEE -;;; standard does. - -(defconstant float-sign-shift 31) - -(defconstant single-float-bias 126) -(defconstant-eqx single-float-exponent-byte (byte 8 23) #'equalp) -(defconstant-eqx single-float-significand-byte (byte 23 0) #'equalp) -(defconstant single-float-normal-exponent-min 1) -(defconstant single-float-normal-exponent-max 254) -(defconstant single-float-hidden-bit (ash 1 23)) - -(defconstant double-float-bias 1022) -(defconstant-eqx double-float-exponent-byte (byte 11 20) #'equalp) -(defconstant-eqx double-float-significand-byte (byte 20 0) #'equalp) -(defconstant double-float-normal-exponent-min 1) -(defconstant double-float-normal-exponent-max #x7FE) -(defconstant double-float-hidden-bit (ash 1 20)) - -(defconstant single-float-digits - (+ (byte-size single-float-significand-byte) 1)) - -(defconstant double-float-digits - (+ (byte-size double-float-significand-byte) n-word-bits 1)) - #+arm-vfp (progn (defconstant float-invalid-trap-bit (ash 1 0)) @@ -98,34 +70,20 @@ ;;;; Where to put the different spaces. -;;; On non-gencgc we need large dynamic and static spaces for PURIFY -#-gencgc (progn - (defconstant read-only-space-start #x04000000) - (defconstant read-only-space-end #x07ff8000) - (defconstant static-space-start #x08000000) - (defconstant static-space-end #x097fff00) + #+(or linux netbsd) + (!gencgc-space-setup #x04000000 :dynamic-space-start #x4f000000) + #+openbsd + (!gencgc-space-setup #x04000000 :dynamic-space-start #x10000000)) - (defconstant linkage-table-space-start #x0a000000) - (defconstant linkage-table-space-end #x0b000000)) - -#+gencgc -(!gencgc-space-setup #x04000000 :dynamic-space-start #x4f000000) - -(defconstant linkage-table-growth-direction :down) -(defconstant linkage-table-entry-size 16) +(defconstant alien-linkage-table-growth-direction :down) +(defconstant alien-linkage-table-entry-size 16) ;;; Link these as data entries so that we store only the address of the ;;; handwritten assembly code in the linkage able, and not a trampoline ;;; to the trampoline. The ALLOCATION macro just wants an address. (setq *linkage-space-predefined-entries* '(("alloc_tramp" t) ("list_alloc_tramp" t))) -#+(or linux netbsd) -(progn - #-gencgc - (progn - (defparameter dynamic-0-space-start #x4f000000) - (defparameter dynamic-0-space-end #x66fff000))) ;;;; other miscellaneous constants @@ -151,8 +109,6 @@ ;;; (defconstant-eqx +static-symbols+ `#(,@+common-static-symbols+ - *allocation-pointer* - *control-stack-pointer* *binding-stack-pointer* *interrupted-control-stack-pointer* @@ -178,5 +134,3 @@ ;;; The number of bits per element in the assemblers code vector. ;;; (defparameter *assembly-unit-length* 8) - -(defvar *allocation-pointer*) diff --git a/src/compiler/arm/pred.lisp b/src/compiler/arm/pred.lisp index d0abfd9818..4393b962c9 100644 --- a/src/compiler/arm/pred.lisp +++ b/src/compiler/arm/pred.lisp @@ -30,15 +30,12 @@ (define-vop (branch-if) (:info dest not-p flags) (:generator 0 - (flet ((negate-condition (name) - (let ((code (logxor 1 (conditional-opcode name)))) - (aref +condition-name-vec+ code)))) (aver (null (rest flags))) (inst b (if not-p (negate-condition (first flags)) (first flags)) - dest)))) + dest))) (defun convert-conditional-move-p (node dst-tn x-tn y-tn) (declare (ignore node dst-tn x-tn y-tn)) diff --git a/src/compiler/arm/sap.lisp b/src/compiler/arm/sap.lisp index 0cc462cf1e..a3ba504062 100644 --- a/src/compiler/arm/sap.lisp +++ b/src/compiler/arm/sap.lisp @@ -151,15 +151,12 @@ ;; be sign-magnitude encoded. FIXME: Figure these ;; things out, and re-enable the VOPs. (ref-name set-name sc type size &key signed use-lip) - (let ((ref-name-c (symbolicate ref-name "-C")) - (set-name-c (symbolicate set-name "-C"))) - (declare (ignorable ref-name-c set-name-c)) - `(progn + `(progn (define-vop (,ref-name) (:translate ,ref-name) (:policy :fast-safe) (:args (sap :scs (sap-reg)) - (offset :scs (signed-reg))) + (offset :scs (signed-reg))) (:arg-types system-area-pointer signed-num) (:results (result :scs (,sc))) (:result-types ,type) @@ -178,8 +175,8 @@ '(@ lip) '(@ sap offset))))) #+(or) - (define-vop (,ref-name-c) - (:translate ,ref-name) + (define-vop (,(symbolicate ref-name "-C")) + (:translate ,ref-name) (:policy :fast-safe) (:args (sap :scs (sap-reg))) (:arg-types system-area-pointer (:constant (signed-byte 16))) @@ -195,14 +192,12 @@ (:double 'fldd)) result (@ sap offset)))) (define-vop (,set-name) - (:translate ,set-name) + (:translate ,set-name) (:policy :fast-safe) - (:args (sap :scs (sap-reg)) - (offset :scs (signed-reg)) - (value :scs (,sc) :target result)) - (:arg-types system-area-pointer signed-num ,type) - (:results (result :scs (,sc))) - (:result-types ,type) + (:args (value :scs (,sc)) + (sap :scs (sap-reg)) + (offset :scs (signed-reg))) + (:arg-types ,type system-area-pointer signed-num) ,@(when use-lip '((:temporary (:sc interior-reg) lip))) (:generator 5 @@ -216,25 +211,15 @@ (:double 'fstd)) value ,(if use-lip '(@ lip) - '(@ sap offset))) - (unless (location= result value) - ,@(case size - (:single - '((inst fcpys result value))) - (:double - '((inst fcpyd result value))) - (t - '((inst mov result value))))))) + '(@ sap offset))))) #+(or) - (define-vop (,set-name-c) - (:translate ,set-name) + (define-vop (,(symbolicate set-name "-C")) + (:translate ,set-name) (:policy :fast-safe) - (:args (sap :scs (sap-reg)) - (value :scs (,sc) :target result)) - (:arg-types system-area-pointer (:constant (signed-byte 16)) ,type) + (:args (value :scs (,sc)) + (sap :scs (sap-reg))) + (:arg-types ,type system-area-pointer (:constant (signed-byte 16))) (:info offset) - (:results (result :scs (,sc))) - (:result-types ,type) (:generator 4 (inst ,(ecase size (:byte 'strb) @@ -242,15 +227,7 @@ (:long 'str) (:single 'fsts) (:double 'fstd)) - value (@ sap offset)) - (unless (location= result value) - ,@(case size - (:single - '((inst fcpys result value))) - (:double - '((inst fcpyd result value))) - (t - '((inst mov result value))))))))))) + value (@ sap offset))))))) (def-system-ref-and-set sap-ref-8 %set-sap-ref-8 unsigned-reg positive-fixnum :byte :signed nil) (def-system-ref-and-set signed-sap-ref-8 %set-signed-sap-ref-8 diff --git a/src/compiler/arm/system.lisp b/src/compiler/arm/system.lisp index e8055a7b13..ef33013f15 100644 --- a/src/compiler/arm/system.lisp +++ b/src/compiler/arm/system.lisp @@ -59,6 +59,30 @@ ;; And, finally, pick out the widetag from the header. (inst ldrb :ne result (@ object (- result))))) +(define-vop () + (:translate sb-c::%structure-is-a) + (:args (x :scs (descriptor-reg))) + (:arg-types * (:constant t)) + (:policy :fast-safe) + (:conditional :eq) + (:info test-layout) + (:temporary (:sc unsigned-reg) this-id) + (:generator 4 + (let ((test-id (layout-id test-layout)) + (offset (+ (id-bits-offset) + (ash (- (wrapper-depthoid test-layout) 2) 2) + (- instance-pointer-lowtag)))) + (inst ldr this-id (@ x offset)) + ;; 8-bit IDs are permanently assigned, so no fixup ever needed for those. + (cond ((typep test-id '(and (unsigned-byte 8) (not (eql 0)))) + (inst cmp this-id test-id)) + (t + (inst .layout-id test-layout) + ;; The fixupper will rewrite these three instructions. + (inst eor this-id this-id (ash 255 16)) + (inst eor this-id this-id (ash 255 8)) + (inst cmp this-id 255)))))) + (define-vop (%other-pointer-widetag) (:translate %other-pointer-widetag) (:policy :fast-safe) @@ -68,8 +92,8 @@ (:generator 6 (load-type result object (- other-pointer-lowtag)))) -(define-vop (fun-subtype) - (:translate fun-subtype) +(define-vop () + (:translate %fun-pointer-widetag) (:policy :fast-safe) (:args (function :scs (descriptor-reg))) (:results (result :scs (unsigned-reg))) @@ -90,10 +114,9 @@ (define-vop (set-header-data) (:translate set-header-data) (:policy :fast-safe) - (:args (x :scs (descriptor-reg) :target res) + (:args (x :scs (descriptor-reg)) (data :scs (any-reg immediate))) (:arg-types * positive-fixnum) - (:results (res :scs (descriptor-reg))) (:temporary (:scs (non-descriptor-reg)) t1) (:generator 6 (load-type t1 x (- other-pointer-lowtag)) @@ -106,8 +129,7 @@ ;; See SYS:SRC;COMPILER;ARM;MOVE.LISP for a partial fix... And ;; maybe it should be promoted to an instruction-macro? (inst orr t1 t1 (ash (tn-value data) n-widetag-bits)))) - (storew t1 x 0 other-pointer-lowtag) - (move res x))) + (storew t1 x 0 other-pointer-lowtag))) (define-vop (pointer-hash) @@ -120,14 +142,6 @@ ;;;; Allocation -(define-vop (dynamic-space-free-pointer) - (:results (int :scs (sap-reg))) - (:result-types system-area-pointer) - (:translate dynamic-space-free-pointer) - (:policy :fast-safe) - (:generator 1 - (load-symbol-value int *allocation-pointer*))) - (define-vop (binding-stack-pointer-sap) (:results (int :scs (sap-reg))) (:result-types system-area-pointer) @@ -194,9 +208,9 @@ (inst sub ndescr ndescr (- other-pointer-lowtag fun-pointer-lowtag)) (inst add func code ndescr))) ;;; -(define-vop (symbol-info-vector) +(define-vop (symbol-dbinfo) (:policy :fast-safe) - (:translate symbol-info-vector) + (:translate symbol-dbinfo) (:args (x :scs (descriptor-reg))) (:results (res :scs (descriptor-reg))) (:temporary (:sc unsigned-reg) temp) @@ -206,19 +220,6 @@ (inst and temp res lowtag-mask) (inst cmp temp list-pointer-lowtag) (loadw res res cons-cdr-slot list-pointer-lowtag :eq))) - -(define-vop (symbol-plist) - (:policy :fast-safe) - (:translate symbol-plist) - (:args (x :scs (descriptor-reg))) - (:results (res :scs (descriptor-reg))) - (:generator 1 - (loadw res x symbol-info-slot other-pointer-lowtag) - ;; Instruction pun: (CAR x) is the same as (VECTOR-LENGTH x) - ;; so if the info slot holds a vector, this gets a fixnum- it's not a plist. - (loadw res res cons-car-slot list-pointer-lowtag) - (inst tst res fixnum-tag-mask) - (inst mov :eq res null-tn))) ;;;; other miscellaneous VOPs @@ -247,3 +248,11 @@ (:translate spin-loop-hint) (:policy :fast-safe) (:generator 0)) + +(define-vop (sb-c::mark-covered) + (:info x) + (:temporary (:sc unsigned-reg) tmp) + (:generator 4 + ;; Can't compute code-tn-relative index until the boxed header length + ;; is known. Some vops emit new boxed words via EMIT-CONSTANT. + (inst store-coverage-mark x tmp))) diff --git a/src/compiler/arm/target-insts.lisp b/src/compiler/arm/target-insts.lisp index 8c2aca7a2b..dbb473fc7e 100644 --- a/src/compiler/arm/target-insts.lisp +++ b/src/compiler/arm/target-insts.lisp @@ -46,7 +46,7 @@ (fixnum value) (ignore dstate)) (unless (= value 14) ;; Don't print :al - (princ (aref sb-vm::+condition-name-vec+ value) stream))) + (princ (aref +condition-name-vec+ value) stream))) (defun print-reg (value stream dstate) (declare (type stream stream) diff --git a/src/compiler/arm/type-vops.lisp b/src/compiler/arm/type-vops.lisp index fe219f7cc2..5301004cb6 100644 --- a/src/compiler/arm/type-vops.lisp +++ b/src/compiler/arm/type-vops.lisp @@ -127,7 +127,7 @@ (define-vop (signed-byte-32-p type-predicate) (:translate signed-byte-32-p) - (:generator 45 + (:generator 10 (let ((not-target (gen-label))) (signed-byte-32-test value temp not-p target not-target) (emit-label not-target)))) @@ -181,7 +181,7 @@ (define-vop (unsigned-byte-32-p type-predicate) (:translate unsigned-byte-32-p) - (:generator 45 + (:generator 10 (let ((not-target (gen-label))) (unsigned-byte-32-test value temp not-p target not-target) (emit-label not-target)))) diff --git a/src/compiler/arm/values.lisp b/src/compiler/arm/values.lisp index f353ad9be2..f697a615c6 100644 --- a/src/compiler/arm/values.lisp +++ b/src/compiler/arm/values.lisp @@ -61,7 +61,7 @@ ;;; operand, but this seems unworthwhile. ;;; (define-vop (push-values) - (:args (vals :more t)) + (:args (vals :more t :scs (descriptor-reg any-reg control-stack))) (:results (start :scs (any-reg) :from :load) (count :scs (any-reg))) (:info nvals) @@ -75,7 +75,7 @@ ((null val)) (let ((tn (tn-ref-tn val))) (sc-case tn - (descriptor-reg + ((descriptor-reg any-reg) (storew tn start i)) (control-stack (load-stack-tn temp tn) @@ -121,22 +121,15 @@ ;;; as function arguments. ;;; (define-vop (%more-arg-values) - (:args (context :scs (descriptor-reg any-reg) :target src) - (skip :scs (any-reg immediate)) + (:args (context :scs (descriptor-reg any-reg) :to :save) (num :scs (any-reg) :target count)) - (:arg-types * positive-fixnum positive-fixnum) - (:temporary (:sc any-reg :from (:argument 0)) src) + (:arg-types * positive-fixnum) (:temporary (:sc any-reg :from (:argument 2)) dst) (:temporary (:sc descriptor-reg :from (:argument 1)) temp) (:temporary (:sc any-reg) i) (:results (start :scs (any-reg)) (count :scs (any-reg))) (:generator 20 - (sc-case skip - (immediate - (inst add src context (* (tn-value skip) n-word-bytes))) - (any-reg - (inst add src context skip))) (inst adds count num 0) (load-csp start) (inst b :eq DONE) @@ -147,7 +140,7 @@ LOOP (inst cmp i 4) (inst sub i i 4) - (inst ldr temp (@ src i)) + (inst ldr temp (@ context i)) (inst str temp (@ dst i)) (inst b :ne LOOP) DONE)) diff --git a/src/compiler/arm/vm.lisp b/src/compiler/arm/vm.lisp index f8de20212d..a32f98599b 100644 --- a/src/compiler/arm/vm.lisp +++ b/src/compiler/arm/vm.lisp @@ -11,6 +11,7 @@ (in-package "SB-VM") +(defconstant-eqx +fixup-kinds+ #(:absolute :layout-id) #'equalp) ;;;; register specs @@ -229,7 +230,7 @@ (typecase value (null null-sc-number) - ((or (integer #.sb-xc:most-negative-fixnum #.sb-xc:most-positive-fixnum) + ((or (integer #.most-negative-fixnum #.most-positive-fixnum) character) immediate-sc-number) (symbol diff --git a/src/compiler/arm64/alloc.lisp b/src/compiler/arm64/alloc.lisp index c5e2417712..78b46bdb96 100644 --- a/src/compiler/arm64/alloc.lisp +++ b/src/compiler/arm64/alloc.lisp @@ -11,114 +11,116 @@ (in-package "SB-VM") -(define-vop (list-or-list*) - (:args (things :more t :scs (control-stack))) - (:temporary (:scs (descriptor-reg)) ptr) +(define-vop (list) + (:args (things :more t :scs (descriptor-reg any-reg control-stack constant immediate))) + (:temporary (:scs (descriptor-reg)) ptr temp) (:temporary (:scs (descriptor-reg) :to (:result 0) :target result) res) - (:temporary (:sc non-descriptor-reg) pa-flag temp) - (:temporary (:scs (interior-reg)) lip) - (:info num) + (:temporary (:scs (non-descriptor-reg) :offset lr-offset) lr) + (:info star cons-cells) (:results (result :scs (descriptor-reg))) - (:variant-vars star) - (:policy :fast-safe) (:node-var node) + (:vop-var vop) (:generator 0 - (cond ((zerop num) - (move result null-tn)) - ((and star (= num 1)) - (move result (tn-ref-tn things))) - (t - (macrolet - ((maybe-load (tn) + (let ((alloc (* (pad-data-block cons-size) cons-cells)) + (dx (node-stack-allocate-p node)) + (prev-constant)) + (macrolet ((maybe-load (tn &optional (temp 'temp)) (once-only ((tn tn)) `(sc-case ,tn ((any-reg descriptor-reg) ,tn) + ((immediate constant) + (cond ((eql (tn-value ,tn) 0) + zr-tn) + ((or (eql prev-constant (tn-value ,tn)) + (progn + (setf prev-constant (tn-value ,tn)) + nil)) + temp) + ((sc-is ,tn constant) + (load-constant vop ,tn ,temp) + ,temp) + (t + (load-immediate vop ,tn ,temp) + ,temp))) (control-stack - (load-stack-tn temp ,tn) - temp))))) - (let* ((cons-cells (if star (1- num) num)) - (alloc (* (pad-data-block cons-size) cons-cells))) - (pseudo-atomic (pa-flag :sync nil) - (allocation 'list alloc list-pointer-lowtag res - :flag-tn pa-flag - :stack-allocate-p (node-stack-allocate-p node) - :lip lip) - (move ptr res) - (dotimes (i (1- cons-cells)) - (storew (maybe-load (tn-ref-tn things)) ptr - cons-car-slot list-pointer-lowtag) - (setf things (tn-ref-across things)) - (inst add ptr ptr (pad-data-block cons-size)) - (storew ptr ptr - (- cons-cdr-slot cons-size) - list-pointer-lowtag)) - (storew (maybe-load (tn-ref-tn things)) ptr - cons-car-slot list-pointer-lowtag) - (storew (if star - (maybe-load (tn-ref-tn (tn-ref-across things))) - null-tn) - ptr cons-cdr-slot list-pointer-lowtag)) - (move result res))))))) - -(define-vop (list list-or-list*) - (:variant nil)) - -(define-vop (list* list-or-list*) - (:variant t)) + (setf prev-constant nil) + (load-stack-tn ,temp ,tn) + ,temp))))) + (pseudo-atomic (lr :sync nil :elide-if dx) + (allocation 'list alloc list-pointer-lowtag res + :flag-tn lr + :stack-allocate-p dx) + (cond ((= cons-cells 1) + (inst stp (maybe-load (tn-ref-tn things)) + (if star + (maybe-load (tn-ref-tn (tn-ref-across things)) ptr) + null-tn) + (@ tmp-tn))) + (t + (move ptr res) + (dotimes (i (1- cons-cells)) + (storew (maybe-load (tn-ref-tn things)) ptr + cons-car-slot list-pointer-lowtag) + (setf things (tn-ref-across things)) + (inst add ptr ptr (pad-data-block cons-size)) + (storew ptr ptr + (- cons-cdr-slot cons-size) + list-pointer-lowtag)) + (storew (maybe-load (tn-ref-tn things)) ptr + cons-car-slot list-pointer-lowtag) + (storew (if star + (maybe-load (tn-ref-tn (tn-ref-across things))) + null-tn) + ptr cons-cdr-slot list-pointer-lowtag)))) + (move result res))))) ;;;; Special purpose inline allocators. (define-vop (make-fdefn) (:args (name :scs (descriptor-reg) :to :eval)) - (:temporary (:sc non-descriptor-reg) pa-flag temp) - (:temporary (:scs (interior-reg)) lip) + (:temporary (:sc non-descriptor-reg) temp) + (:temporary (:scs (non-descriptor-reg) :offset lr-offset) lr) (:results (result :scs (descriptor-reg) :from :argument)) (:policy :fast-safe) (:translate make-fdefn) (:generator 37 - (with-fixed-allocation (result pa-flag fdefn-widetag fdefn-size :lip lip) - (load-inline-constant temp '(:fixup undefined-tramp :assembly-routine) lip) + (with-fixed-allocation (result lr fdefn-widetag fdefn-size) + (load-inline-constant temp '(:fixup undefined-tramp :assembly-routine)) (storew name result fdefn-name-slot other-pointer-lowtag) (storew null-tn result fdefn-fun-slot other-pointer-lowtag) (storew temp result fdefn-raw-addr-slot other-pointer-lowtag)))) (define-vop (make-closure) - (:args (function :to :save :scs (descriptor-reg))) (:info label length stack-allocate-p) - (:ignore label) - (:temporary (:sc non-descriptor-reg) pa-flag) - (:temporary (:scs (interior-reg)) lip) + (:temporary (:scs (non-descriptor-reg)) temp) + (:temporary (:scs (non-descriptor-reg) :offset lr-offset) lr) (:results (result :scs (descriptor-reg))) (:generator 10 (let* ((size (+ length closure-info-offset)) (alloc-size (pad-data-block size))) - (pseudo-atomic (pa-flag) + (pseudo-atomic (lr :elide-if stack-allocate-p) (allocation nil alloc-size fun-pointer-lowtag result - :flag-tn pa-flag - :stack-allocate-p stack-allocate-p - :lip lip) - (load-immediate-word pa-flag - (logior - (ash (1- size) n-widetag-bits) - closure-widetag)) - (storew pa-flag result 0 fun-pointer-lowtag) - (storew function result closure-fun-slot fun-pointer-lowtag))))) + :flag-tn lr + :stack-allocate-p stack-allocate-p) + (load-immediate-word temp + (logior (ash (1- size) n-widetag-bits) closure-widetag)) + (inst adr lr label (ash simple-fun-insts-offset word-shift)) + (storew-pair temp 0 lr closure-fun-slot tmp-tn))))) ;;; The compiler likes to be able to directly make value cells. ;;; (define-vop (make-value-cell) (:args (value :to :save :scs (descriptor-reg any-reg))) - (:temporary (:sc non-descriptor-reg) pa-flag) - (:temporary (:scs (interior-reg)) lip) + (:temporary (:scs (non-descriptor-reg) :offset lr-offset) lr) (:info stack-allocate-p) (:results (result :scs (descriptor-reg))) (:generator 10 - (with-fixed-allocation (result pa-flag value-cell-widetag + (with-fixed-allocation (result lr value-cell-widetag value-cell-size :stack-allocate-p stack-allocate-p - :lip lip) - (storew value result value-cell-value-slot other-pointer-lowtag)))) + :store-type-code nil) + (storew-pair lr 0 value value-cell-value-slot tmp-tn)))) ;;;; Automatic allocators for primitive objects. @@ -130,23 +132,20 @@ (define-vop (make-funcallable-instance-tramp) (:args) - (:temporary (:scs (interior-reg)) lip) (:results (result :scs (any-reg))) (:generator 1 - (load-inline-constant result '(:fixup funcallable-instance-tramp :assembly-routine) lip))) + (load-inline-constant result '(:fixup funcallable-instance-tramp :assembly-routine)))) (define-vop (fixed-alloc) (:args) (:info name words type lowtag stack-allocate-p) (:ignore name) (:results (result :scs (descriptor-reg))) - (:temporary (:sc non-descriptor-reg) pa-flag) - (:temporary (:scs (interior-reg)) lip) + (:temporary (:scs (non-descriptor-reg) :offset lr-offset) lr) (:generator 4 - (with-fixed-allocation (result pa-flag type words + (with-fixed-allocation (result lr type words :lowtag lowtag - :stack-allocate-p stack-allocate-p - :lip lip)))) + :stack-allocate-p stack-allocate-p)))) (define-vop (var-alloc) (:args (extra :scs (any-reg))) @@ -155,8 +154,8 @@ (:ignore name stack-allocate-p) (:results (result :scs (descriptor-reg))) (:temporary (:scs (any-reg) :from :argument) bytes) - (:temporary (:sc non-descriptor-reg) pa-flag header) - (:temporary (:scs (interior-reg)) lip) + (:temporary (:sc non-descriptor-reg) header) + (:temporary (:scs (non-descriptor-reg) :offset lr-offset) lr) (:generator 6 ;; Build the object header, assuming that the header was in WORDS ;; but should not be in the header @@ -169,6 +168,6 @@ (inst add bytes bytes (* 2 n-word-bytes)) (inst and bytes bytes (bic-mask lowtag-mask)) ;; Allocate the object and set its header - (pseudo-atomic (pa-flag) - (allocation nil bytes lowtag result :flag-tn pa-flag :lip lip) + (pseudo-atomic (lr) + (allocation nil bytes lowtag result :flag-tn lr) (storew header result 0 lowtag)))) diff --git a/src/compiler/arm64/arith.lisp b/src/compiler/arm64/arith.lisp index 5316fa82ac..302e0a105e 100644 --- a/src/compiler/arm64/arith.lisp +++ b/src/compiler/arm64/arith.lisp @@ -48,7 +48,7 @@ (inst neg res x))) (define-vop (fast-negate/unsigned signed-unop) - (:args (x :scs (unsigned-reg) :target res)) + (:args (x :scs (unsigned-reg))) (:arg-types unsigned-num) (:translate %negate) (:generator 3 @@ -61,6 +61,21 @@ (:generator 3 (inst neg res x))) +(define-modular-fun %negate-mod64 (x) %negate :untagged nil 64) +(define-vop (%negate-mod64) + (:translate %negate-mod64) + (:policy :fast-safe) + (:args (x :scs (unsigned-reg))) + (:arg-types unsigned-num) + (:results (r :scs (unsigned-reg))) + (:result-types unsigned-num) + (:generator 3 + (inst neg r x))) + +(define-modular-fun %negate-modfx (x) %negate :tagged t #.n-fixnum-bits) +(define-vop (%negate-modfx fast-negate/fixnum) + (:translate %negate-modfx)) + (define-vop (fast-lognot/fixnum fixnum-unop) (:args (x :scs (any-reg))) (:arg-types tagged-num) @@ -79,45 +94,45 @@ ;;; Assume that any constant operand is the second arg... (define-vop (fast-fixnum-binop fast-safe-arith-op) - (:args (x :target r :scs (any-reg)) - (y :target r :scs (any-reg))) + (:args (x :scs (any-reg)) + (y :scs (any-reg))) (:arg-types tagged-num tagged-num) (:results (r :scs (any-reg))) (:result-types tagged-num) (:note "inline fixnum arithmetic")) (define-vop (fast-unsigned-binop fast-safe-arith-op) - (:args (x :target r :scs (unsigned-reg)) - (y :target r :scs (unsigned-reg))) + (:args (x :scs (unsigned-reg)) + (y :scs (unsigned-reg))) (:arg-types unsigned-num unsigned-num) (:results (r :scs (unsigned-reg))) (:result-types unsigned-num) (:note "inline (unsigned-byte 64) arithmetic")) (define-vop (fast-signed-binop fast-safe-arith-op) - (:args (x :target r :scs (signed-reg)) - (y :target r :scs (signed-reg))) + (:args (x :scs (signed-reg)) + (y :scs (signed-reg))) (:arg-types signed-num signed-num) (:results (r :scs (signed-reg))) (:result-types signed-num) (:note "inline (signed-byte 64) arithmetic")) (define-vop (fast-fixnum-binop-c fast-safe-arith-op) - (:args (x :target r :scs (any-reg))) + (:args (x :scs (any-reg))) (:info y) (:results (r :scs (any-reg))) (:result-types tagged-num) (:note "inline fixnum arithmetic")) (define-vop (fast-unsigned-binop-c fast-safe-arith-op) - (:args (x :target r :scs (unsigned-reg))) + (:args (x :scs (unsigned-reg))) (:info y) (:results (r :scs (unsigned-reg))) (:result-types unsigned-num) (:note "inline (unsigned-byte 64) arithmetic")) (define-vop (fast-signed-binop-c fast-safe-arith-op) - (:args (x :target r :scs (signed-reg))) + (:args (x :scs (signed-reg))) (:info y) (:results (r :scs (signed-reg))) (:result-types signed-num) @@ -196,6 +211,13 @@ (define-binop logior 2 orr) (define-binop logxor 2 eor) +(define-vop (fast--/unsigned=>signed fast-unsigned-binop) + (:translate -) + (:results (r :scs (signed-reg))) + (:result-types signed-num) + (:generator 5 + (inst sub r x y))) + (define-binop logandc1 2 bic :swap t :constant-test bic-encode-immediate :constant-fixnum-test bic-fixnum-encode-immediate @@ -220,7 +242,7 @@ (define-vop (fast-logior-unsigned-signed=>signed fast-safe-arith-op) (:args (x :scs (unsigned-reg)) - (y :target r :scs (signed-reg))) + (y :scs (signed-reg))) (:arg-types unsigned-num signed-num) (:results (r :scs (signed-reg) :from (:argument 1))) (:result-types signed-num) @@ -230,7 +252,7 @@ (inst orr r x y))) (define-vop (fast-logior-signed-unsigned=>signed fast-safe-arith-op) - (:args (x :target r :scs (signed-reg)) + (:args (x :scs (signed-reg)) (y :scs (unsigned-reg))) (:arg-types signed-num unsigned-num) (:results (r :scs (signed-reg) :from (:argument 0))) @@ -244,7 +266,7 @@ (define-vop (fast-*/fixnum=>fixnum fast-fixnum-binop) (:args (x :scs (signed-reg)) ;; one operand needs to be untagged - (y :target r :scs (any-reg))) + (y :scs (any-reg))) (:translate *) (:generator 2 (inst mul r x y))) @@ -265,34 +287,44 @@ (:args (x :scs (signed-reg) :to :result) (y :scs (signed-reg) :to :result)) (:arg-types signed-num signed-num) + (:args-var args) (:results (quo :scs (signed-reg) :from :eval) (rem :scs (signed-reg) :from :eval)) + (:optional-results rem) (:result-types signed-num signed-num) (:note "inline (signed-byte 64) arithmetic") (:vop-var vop) (:save-p :compute-only) (:generator 33 - (let ((zero (generate-error-code vop 'division-by-zero-error x y))) - (inst cbz y zero)) + (when (types-equal-or-intersect (tn-ref-type (tn-ref-across args)) + (specifier-type '(eql 0))) + (let ((zero (generate-error-code vop 'division-by-zero-error x y))) + (inst cbz y zero))) (inst sdiv quo x y) - (inst msub rem quo y x))) + (unless (eq (tn-kind rem) :unused) + (inst msub rem quo y x)))) (define-vop (fast-truncate/unsigned=>unsigned fast-safe-arith-op) (:translate truncate) (:args (x :scs (unsigned-reg) :to :result) (y :scs (unsigned-reg) :to :result)) (:arg-types unsigned-num unsigned-num) + (:args-var args) (:results (quo :scs (unsigned-reg) :from :eval) (rem :scs (unsigned-reg) :from :eval)) + (:optional-results rem) (:result-types unsigned-num unsigned-num) (:note "inline (unsigned-byte 64) arithmetic") (:vop-var vop) (:save-p :compute-only) (:generator 33 - (let ((zero (generate-error-code vop 'division-by-zero-error x y))) - (inst cbz y zero)) + (when (types-equal-or-intersect (tn-ref-type (tn-ref-across args)) + (specifier-type '(eql 0))) + (let ((zero (generate-error-code vop 'division-by-zero-error x y))) + (inst cbz y zero))) (inst udiv quo x y) - (inst msub rem quo y x))) + (unless (eq (tn-kind rem) :unused) + (inst msub rem quo y x)))) ;;; (define-vop (fast-lognor/fixnum=>fixnum fast-fixnum-binop) @@ -304,11 +336,25 @@ (inst eor r r (lognot fixnum-tag-mask)))) (define-vop (fast-logand/signed-unsigned=>unsigned fast-logand/unsigned=>unsigned) - (:args (x :scs (signed-reg) :target r) - (y :scs (unsigned-reg) :target r)) + (:args (x :scs (signed-reg)) + (y :scs (unsigned-reg))) (:arg-types signed-num unsigned-num) (:translate logand)) +(defun logical-immediate-or-word-mask (x) + (and (integerp x) + (or (encode-logical-immediate x) + (= x most-positive-word)))) + +(define-vop (fast-logand-c/signed-unsigned=>unsigned fast-logand-c/unsigned=>unsigned) + (:args (x :scs (signed-reg))) + (:arg-types signed-num (:constant (satisfies logical-immediate-or-word-mask))) + (:translate logand) + (:generator 2 + (if (= y most-positive-word) + (move r x) + (inst and r x y)))) + (define-source-transform logeqv (&rest args) (if (oddp (length args)) `(logxor ,@args) @@ -320,24 +366,10 @@ ;;; Shifting -(define-vop (fast-ash-left-c/fixnum=>fixnum) - (:translate ash) - (:policy :fast-safe) - (:args (number :scs (any-reg) :target result)) - (:info amount) - (:arg-types tagged-num (:constant unsigned-byte)) - (:results (result :scs (any-reg))) - (:result-types tagged-num) - (:note "inline ASH") - (:generator 1 - (if (< amount 64) - (inst lsl result number amount) - (inst mov result 0)))) - (define-vop (fast-ash-right-c/fixnum=>fixnum) (:translate ash) (:policy :fast-safe) - (:args (number :scs (any-reg) :target result)) + (:args (number :scs (any-reg))) (:info amount) (:arg-types tagged-num (:constant (integer * -1))) (:results (result :scs (any-reg))) @@ -351,7 +383,7 @@ (define-vop (fast-ash-c/unsigned=>unsigned) (:translate ash) (:policy :fast-safe) - (:args (number :scs (unsigned-reg) :target result)) + (:args (number :scs (unsigned-reg))) (:info amount) (:arg-types unsigned-num (:constant integer)) (:results (result :scs (unsigned-reg))) @@ -368,7 +400,7 @@ (define-vop (fast-ash-c/signed=>signed) (:translate ash) (:policy :fast-safe) - (:args (number :scs (signed-reg) :target result)) + (:args (number :scs (signed-reg))) (:info amount) (:arg-types signed-num (:constant integer)) (:results (result :scs (signed-reg))) @@ -391,27 +423,86 @@ (:results (result)) (:policy :fast-safe) (:temporary (:sc non-descriptor-reg) temp) + (:args-var args) (:variant-vars variant) (:generator 5 (inst subs temp amount zr-tn) (inst b :ge LEFT) (inst neg temp temp) - (inst cmp temp n-word-bits) - ;; Only the first 6 bits count for shifts. - ;; This sets all bits to 1 if AMOUNT is larger than 63, - ;; cutting the amount to 63. - (inst csinv temp temp zr-tn :lt) - DO - (ecase variant - (:signed (inst asr result number temp)) - (:unsigned (inst lsr result number temp))) + (cond ((csubtypep (tn-ref-type (tn-ref-across args)) + (specifier-type `(integer -63 *))) + (ecase variant + (:signed (inst asr result number temp)) + (:unsigned (inst lsr result number temp)))) + (t + (inst cmp temp n-word-bits) + (ecase variant + (:signed + ;; Only the first 6 bits count for shifts. + ;; This sets all bits to 1 if AMOUNT is larger than 63, + ;; cutting the amount to 63. + (inst csinv temp temp zr-tn :lo) + (inst asr result number temp)) + (:unsigned + (inst csel result number zr-tn :lo) + (inst lsr result result temp))))) + (inst b END) LEFT - (inst cmp temp n-word-bits) - (inst csel result number zr-tn :lt) - (inst lsl result result temp) + (cond ((csubtypep (tn-ref-type (tn-ref-across args)) + (specifier-type `(integer * 63))) + (inst lsl result number temp)) + (t + (inst cmp temp n-word-bits) + (inst csel result number zr-tn :lo) + (inst lsl result result temp))) END)) +(define-vop (fast-ash-modfx/signed/unsigned=>fixnum) + (:note "inline ASH") + (:translate ash-modfx) + (:args (number :scs (signed-reg unsigned-reg) :to :save) + (amount :scs (signed-reg) :to :save :target temp)) + (:arg-types (:or signed-num unsigned-num) signed-num) + (:results (result :scs (any-reg))) + (:args-var args) + (:result-types tagged-num) + (:policy :fast-safe) + (:temporary (:sc non-descriptor-reg) temp temp-result) + (:generator 5 + (inst subs temp amount zr-tn) + (inst b :ge LEFT) + (inst neg temp temp) + (cond ((csubtypep (tn-ref-type (tn-ref-across args)) + (specifier-type `(integer -63 *))) + (sc-case number + (signed-reg (inst asr temp-result number temp)) + (unsigned-reg (inst lsr temp-result number temp)))) + (t + (inst cmp temp n-word-bits) + (sc-case number + (signed-reg + ;; Only the first 6 bits count for shifts. + ;; This sets all bits to 1 if AMOUNT is larger than 63, + ;; cutting the amount to 63. + (inst csinv temp temp zr-tn :lo) + (inst asr temp-result number temp)) + (unsigned-reg + (inst csel temp-result number zr-tn :lo) + (inst lsr temp-result temp-result temp))))) + + (inst b END) + LEFT + (cond ((csubtypep (tn-ref-type (tn-ref-across args)) + (specifier-type `(integer * 63))) + (inst lsl temp-result number temp)) + (t + (inst cmp temp n-word-bits) + (inst csel temp-result number zr-tn :lo) + (inst lsl temp-result temp-result temp))) + END + (inst lsl result temp-result n-fixnum-tag-bits))) + (define-vop (fast-ash/signed=>signed fast-ash/signed/unsigned) (:args (number :scs (signed-reg) :to :save) (amount :scs (signed-reg) :to :save :target temp)) @@ -430,39 +521,56 @@ (:translate ash) (:variant :unsigned)) -(macrolet ((def (name sc-type type result-type cost) - `(define-vop (,name) - (:note "inline ASH") - (:translate ash) - (:args (number :scs (,sc-type)) - (amount :scs (signed-reg unsigned-reg))) - ;; For modular variants - (:variant-vars cut) - (:arg-types ,type positive-fixnum) - (:results (result :scs (,result-type))) - (:result-types ,type) - (:policy :fast-safe) - (:generator ,cost - (cond (cut - (inst cmp amount n-word-bits) - (cond ((location= amount result) - (inst csel tmp-tn number zr-tn :lt) - (inst lsl result tmp-tn amount)) - (t - (inst csel result number zr-tn :lt) - (inst lsl result result amount)))) - (t - (inst lsl result number amount))))))) +(macrolet ((def (name name-c sc-type type result-type cost) + `(progn + (define-vop (,name) + (:note "inline ASH") + (:translate ash) + (:args (number :scs (,sc-type)) + (amount :scs (signed-reg unsigned-reg))) + ;; For modular variants + (:variant-vars cut) + (:arg-types ,type positive-fixnum) + (:args-var args) + (:results (result :scs (,result-type))) + (:result-types ,type) + (:policy :fast-safe) + (:generator ,cost + (cond ((and cut + (not (csubtypep (tn-ref-type (tn-ref-across args)) ;; amount + (specifier-type `(mod ,n-word-bits))))) + (inst cmp amount n-word-bits) + (cond ((location= amount result) + (inst csel tmp-tn number zr-tn :lo) + (inst lsl result tmp-tn amount)) + (t + (inst csel result number zr-tn :lo) + (inst lsl result result amount)))) + (t + (inst lsl result number amount))))) + (define-vop (,name-c) + (:note "inline ASH") + (:translate ash) + (:args (number :scs (,sc-type))) + (:info amount) + (:arg-types ,type (:constant unsigned-byte)) + (:results (result :scs (,result-type))) + (:result-types ,type) + (:policy :fast-safe) + (:generator ,(1- cost) + (if (< amount 64) + (inst lsl result number amount) + (inst mov result 0))))))) ;; FIXME: There's the opportunity for a sneaky optimization here, I ;; think: a FAST-ASH-LEFT-C/FIXNUM=>SIGNED vop. -- CSR, 2003-09-03 - (def fast-ash-left/fixnum=>fixnum any-reg tagged-num any-reg 2) - (def fast-ash-left/signed=>signed signed-reg signed-num signed-reg 3) - (def fast-ash-left/unsigned=>unsigned unsigned-reg unsigned-num unsigned-reg 3)) + (def fast-ash-left/fixnum=>fixnum fast-ash-left-c/fixnum=>fixnum any-reg tagged-num any-reg 2) + (def fast-ash-left/signed=>signed fast-ash-left-c/signed=>signed signed-reg signed-num signed-reg 3) + (def fast-ash-left/unsigned=>unsigned fast-ash-left-c/unsigned=>unsigned unsigned-reg unsigned-num unsigned-reg 3)) (define-vop (fast-%ash/right/unsigned) (:translate %ash/right) (:policy :fast-safe) - (:args (number :scs (unsigned-reg) :target result) + (:args (number :scs (unsigned-reg)) (amount :scs (unsigned-reg))) (:arg-types unsigned-num unsigned-num) (:results (result :scs (unsigned-reg) :from (:argument 0))) @@ -473,7 +581,7 @@ (define-vop (fast-%ash/right/signed) (:translate %ash/right) (:policy :fast-safe) - (:args (number :scs (signed-reg) :target result) + (:args (number :scs (signed-reg)) (amount :scs (unsigned-reg))) (:arg-types signed-num unsigned-num) (:results (result :scs (signed-reg) :from (:argument 0))) @@ -484,7 +592,7 @@ (define-vop (fast-%ash/right/fixnum) (:translate %ash/right) (:policy :fast-safe) - (:args (number :scs (any-reg) :target result) + (:args (number :scs (any-reg)) (amount :scs (unsigned-reg) :target temp)) (:arg-types tagged-num unsigned-num) (:results (result :scs (any-reg) :from (:argument 0))) @@ -517,33 +625,43 @@ (:variant t) (:translate ash-left-mod64)) +(define-vop (fast-ash-left-mod64-c/unsigned=>unsigned + fast-ash-left-c/unsigned=>unsigned) + (:translate ash-left-mod64)) + (define-vop (fast-ash-left-mod64-c/unsigned=>unsigned fast-ash-c/unsigned=>unsigned) (:translate ash-left-mod64)) -;;; Only the lower 6 bits of the shift amount are significant. -(define-vop (shift-towards-someplace) - (:policy :fast-safe) - (:args (num :scs (unsigned-reg)) - (amount :scs (signed-reg))) - (:arg-types unsigned-num tagged-num) - (:temporary (:sc signed-reg) temp) - (:results (r :scs (unsigned-reg))) - (:result-types unsigned-num)) +(define-vop (fast-ash-modfx/signed=>signed + fast-ash/signed=>signed) + (:translate ash-modfx)) -(define-vop (shift-towards-start shift-towards-someplace) - (:translate shift-towards-start) - (:note "SHIFT-TOWARDS-START") - (:generator 1 - (inst and temp amount #b111111) - (inst lsr r num temp))) +(define-vop (fast-ash-mod64/signed=>unsigned + fast-ash/signed=>signed) + (:results (result :scs (unsigned-reg))) + (:result-types unsigned-num) + (:translate ash-mod64)) -(define-vop (shift-towards-end shift-towards-someplace) - (:translate shift-towards-end) - (:note "SHIFT-TOWARDS-END") - (:generator 1 - (inst and temp amount #b111111) - (inst lsl r num temp))) +(define-vop (fast-ash-mod64/unsigned=>unsigned + fast-ash/unsigned=>unsigned) + (:translate ash-mod64)) + +;;; Only the lower 6 bits of the shift amount are significant. +(macrolet ((define (translate operation) + `(define-vop () + (:translate ,translate) + (:note ,(string translate)) + (:policy :fast-safe) + (:args (num :scs (unsigned-reg)) + (amount :scs (signed-reg))) + (:arg-types unsigned-num tagged-num) + (:results (r :scs (unsigned-reg))) + (:result-types unsigned-num) + (:generator 1 + (inst ,operation r num amount))))) + (define shift-towards-start lsr) + (define shift-towards-end lsl)) (define-vop (signed-byte-64-len) (:translate integer-length) @@ -575,46 +693,41 @@ (inst mov res (fixnumize 64)) (inst sub res res (lsl temp n-fixnum-tag-bits)))) + (define-vop (unsigned-byte-64-count) (:translate logcount) (:note "inline (unsigned-byte 64) logcount") (:policy :fast-safe) - (:args (arg :scs (unsigned-reg) :target num)) - (:arg-types unsigned-num) + (:args (arg :scs (unsigned-reg any-reg))) + (:arg-types (:or unsigned-num positive-fixnum)) (:results (res :scs (unsigned-reg))) (:result-types positive-fixnum) - (:temporary (:scs (non-descriptor-reg) :from (:argument 0) :to (:result 0) - :target res) num) - (:temporary (:scs (non-descriptor-reg)) mask temp) + (:temporary (:scs (double-reg)) v) (:variant-vars signed) - (:generator 30 + (:generator 29 (when signed - (inst cmp arg 0) - (inst csinv num arg arg :ge) - (setf arg num)) - (load-immediate-word mask #x5555555555555555) - (inst and temp mask (lsr arg 1)) - (inst and num arg mask) - (inst add num num temp) - (load-immediate-word mask #x3333333333333333) - (inst and temp mask (lsr num 2)) - (inst and num num mask) - (inst add num num temp) - (load-immediate-word mask #x0f0f0f0f0f0f0f0f) - (inst and temp mask (lsr num 4)) - (inst and num num mask) - (inst add num num temp) - (inst add num num (lsr num 8)) - (inst add num num (lsr num 16)) - (inst add num num (lsr num 32)) - (inst and res num #xff))) + (sc-case arg + (any-reg + ;; Don't invert the tag bit + (inst asr res arg n-fixnum-tag-bits) + (setf arg res)) + (t)) + ;; Invert when negative + (inst eor res arg (asr arg 63)) + (setf arg res)) + (inst fmov v arg) + (inst cnt v v :8b) + ;; GCC uses (inst addv v :b v :8b) + ;; but clang uses: + (inst uaddlv v :h v :8b) + (inst fmov res v))) (define-vop (signed-byte-64-count unsigned-byte-64-count) - (:note "inline (signed-byte 64) logcount") - (:args (arg :scs (signed-reg) :target num)) - (:arg-types signed-num) - (:variant t) - (:variant-cost 29)) + (:note "inline (signed-byte 64) logcount") + (:args (arg :scs (signed-reg any-reg))) + (:arg-types (:or signed-num fixnum)) + (:variant t) + (:variant-cost 30)) (defknown %%ldb (integer unsigned-byte unsigned-byte) unsigned-byte (movable foldable flushable always-translatable)) @@ -626,6 +739,14 @@ (defun %%ldb (integer size posn) (%ldb size posn integer)) +(deftransform %%ldb ((integer size posn) (unsigned-byte t (constant-arg (integer #.n-word-bits))) * + :important nil) + 0) + +(deftransform %%ldb ((integer size posn) ((integer * -1) t (constant-arg (integer #.n-word-bits))) * + :important nil) + 1) + (defun %%dpb (newbyte size posn integer) (%dpb newbyte size posn integer)) @@ -639,7 +760,15 @@ (:result-types unsigned-num) (:policy :fast-safe) (:generator 2 - (inst ubfm res x (1+ posn) (+ posn size)))) + (cond ((<= (+ posn size) n-fixnum-bits) + (inst ubfm res x (1+ posn) (+ posn size))) + ((= size 1) + (inst lsr res x n-fixnum-bits)) + (t + ;; Can't constrain two constant args to avoid this VOP and + ;; go to the signed variant, so do it manually. + (inst asr res x (1+ posn)) + (inst and res res (ash most-positive-word (- size sb-vm:n-word-bits))))))) (define-vop (ldb-c) (:translate %%ldb) @@ -651,7 +780,10 @@ (:result-types unsigned-num) (:policy :fast-safe) (:generator 3 - (inst ubfm res x posn (+ posn size -1)))) + (if (and (>= (+ posn size) n-word-bits) + (= size 1)) + (inst lsr res x (1- n-word-bits)) + (inst ubfm res x posn (+ posn size -1))))) (define-vop (dpb-c/fixnum) (:translate %%dpb) @@ -716,7 +848,7 @@ (defmacro define-mod-binop ((name prototype) function) `(define-vop (,name ,prototype) - (:args (x :target r :scs (unsigned-reg signed-reg)) + (:args (x :scs (unsigned-reg signed-reg)) (y :scs (unsigned-reg signed-reg))) (:arg-types untagged-num untagged-num) (:results (r :scs (unsigned-reg signed-reg) :from (:argument 0))) @@ -725,7 +857,7 @@ (defmacro define-mod-binop-c ((name prototype) function) `(define-vop (,name ,prototype) - (:args (x :target r :scs (unsigned-reg signed-reg))) + (:args (x :scs (unsigned-reg signed-reg))) (:info y) (:arg-types untagged-num (:constant (satisfies add-sub-immediate-p))) (:results (r :scs (unsigned-reg signed-reg) :from (:argument 0))) @@ -746,8 +878,7 @@ (vopfxcf (symbolicate "FAST-" name "-MODFX-C/FIXNUM=>FIXNUM"))) `(progn (define-modular-fun ,fun64 (x y) ,name :untagged nil 64) - (define-modular-fun ,funfx (x y) ,name :tagged t - #.(- n-word-bits n-fixnum-tag-bits)) + (define-modular-fun ,funfx (x y) ,name :tagged t ,n-fixnum-bits) (define-mod-binop (,vop64u ,vopu) ,fun64) (define-vop (,vop64f ,vopf) (:translate ,fun64)) (define-vop (,vopfxf ,vopf) (:translate ,funfx)) @@ -791,138 +922,190 @@ (:arg-types tagged-num tagged-num) (:note "inline fixnum comparison")) -(define-vop (fast-conditional-c/fixnum fast-conditional/fixnum) - (:args (x :scs (any-reg))) - (:arg-types tagged-num (:constant (satisfies fixnum-abs-add-sub-immediate-p))) - (:info y)) - (define-vop (fast-conditional/signed fast-conditional) (:args (x :scs (signed-reg)) (y :scs (signed-reg))) (:arg-types signed-num signed-num) (:note "inline (signed-byte 64) comparison")) -(define-vop (fast-conditional-c/signed fast-conditional/signed) - (:args (x :scs (signed-reg))) - (:arg-types signed-num (:constant (satisfies abs-add-sub-immediate-p))) - (:info y)) - (define-vop (fast-conditional/unsigned fast-conditional) (:args (x :scs (unsigned-reg)) (y :scs (unsigned-reg))) (:arg-types unsigned-num unsigned-num) (:note "inline (unsigned-byte 64) comparison")) -(define-vop (fast-conditional-c/unsigned fast-conditional/unsigned) - (:args (x :scs (unsigned-reg))) - (:arg-types unsigned-num (:constant (satisfies abs-add-sub-immediate-p))) - (:info y)) - -(defmacro define-conditional-vop (tran cond unsigned) +(defmacro define-conditional-vop (tran signed unsigned &optional addend addend-signed addend-unsigned) `(progn - ,@(loop for (suffix cost signed constant) in + ,@(loop for (suffix cost signed-p) in '((/fixnum 4 t) - (-c/fixnum 3 t t) (/signed 6 t) - (-c/signed 5 t t) - (/unsigned 6 nil) - (-c/unsigned 5 nil t)) - for value = (if (eq suffix '-c/fixnum) - '(fixnumize y) - 'y) + (/unsigned 6 nil)) collect `(define-vop (,(intern (format nil "~:@(FAST-IF-~A~A~)" tran suffix)) ,(intern (format nil "~:@(FAST-CONDITIONAL~A~)" suffix))) (:translate ,tran) - (:conditional ,(if signed cond unsigned)) + (:conditional ,(if signed-p signed unsigned)) (:generator ,cost - ,(if constant - `(let ((value ,value)) - (if (minusp value) - (inst cmn x (abs value)) - (if (add-sub-immediate-p value) - (inst cmp x value) - (inst cmn x (ldb (byte n-word-bits 0) (- value)))))) - `(inst cmp x ,value))))))) - -(define-conditional-vop < :lt :lo) -(define-conditional-vop > :gt :hi) + (inst cmp x y)))) + + (define-vop (,(symbolicate "FAST-IF-" tran "-INTEGER/C") ) + (:translate ,tran) + (:args (x :scs (any-reg signed-reg unsigned-reg))) + (:arg-types (:or tagged-num signed-num unsigned-num) + (:constant (or signed-word word))) + (:info y) + (:vop-var vop) + (:policy :fast-safe) + ,(if (eq signed unsigned) + `(:conditional ,signed) + `(:conditional + :after-sc-selection + (flet ((try (y) + (let ((y (if (sc-is x any-reg) + (fixnumize y) + y))) + (flet ((try (constant) + (add-sub-immediate-p constant))) + (or (try y) + (try (ldb (byte 64 0) (- y)))))))) + (cond ((and (not (try y)) + (try (+ y ,addend))) + (setf (car (vop-codegen-info vop)) + (+ y ,addend)) + (if (sc-is x unsigned-reg) + ,addend-unsigned + ,addend-signed)) + (t + (if (sc-is x unsigned-reg) + ,unsigned + ,signed)))))) + (:generator 2 + (let ((y (if (sc-is x any-reg) + (fixnumize y) + y))) + (flet ((try (constant negate) + (when (add-sub-immediate-p constant) + (if negate + (inst cmn x constant) + (inst cmp x constant)) + t))) + (or (try y nil) + (try (ldb (byte 64 0) (- y)) t) + (inst cmp x (load-immediate-word tmp-tn y))))))))) + +(define-conditional-vop < :lt :lo -1 :le :ls) +(define-conditional-vop > :gt :hi 1 :ge :hs) (define-conditional-vop eql :eq :eq) -;;; EQL/FIXNUM is funny because the first arg can be of any type, not -;;; just a known fixnum. +(define-vop (<-unsigned-signed) + (:translate <) + (:args (unsigned :scs (unsigned-reg)) + (signed :scs (signed-reg))) + (:arg-types unsigned-num signed-num) + (:conditional :lo) + (:policy :fast-safe) + (:generator 7 + (inst cmp signed 0) + (inst ccmp unsigned signed :ge #b0010))) + +(define-vop (>-unsigned-signed <-unsigned-signed) + (:translate >) + (:conditional :hi)) + +(define-vop (<-signed-unsigned) + (:translate <) + (:args (signed :scs (signed-reg)) + (unsigned :scs (unsigned-reg))) + (:arg-types signed-num unsigned-num) + (:conditional :lo) + (:policy :fast-safe) + (:generator 7 + (inst cmp signed 0) + (inst ccmp signed unsigned :ge #b0000))) -;;; These versions specify a fixnum restriction on their first arg. -;;; We have also generic-eql/fixnum VOPs which are the same, but have -;;; no restriction on the first arg and a higher cost. The reason for -;;; doing this is to prevent fixnum specific operations from being -;;; used on word integers, spuriously consing the argument. +(define-vop (>-signed-unsigned <-signed-unsigned) + (:translate >) + (:conditional :hi)) -(define-vop (fast-eql/fixnum) - (:args (x :scs (any-reg)) - (y :scs (any-reg))) - (:arg-types tagged-num tagged-num) - (:note "inline fixnum comparison") +(define-vop (eql-unsigned-signed) (:translate eql) + (:args (unsigned :scs (unsigned-reg)) + (signed :scs (signed-reg))) + (:arg-types unsigned-num signed-num) (:conditional :eq) (:policy :fast-safe) - (:generator 4 - (inst cmp x y))) + (:generator 7 + (inst cmp signed 0) + (inst ccmp unsigned signed :ge #b0000))) + +(define-vop (eql-signed-unsigned eql-unsigned-signed) + (:args (signed :scs (signed-reg)) + (unsigned :scs (unsigned-reg))) + (:arg-types signed-num unsigned-num)) + +(define-vop (eq-unsigned-signed eql-unsigned-signed) + (:variant-cost 6) + (:translate eq)) -(define-vop (generic-eql/fixnum fast-eql/fixnum) +(define-vop (eq-signed-unsigned eql-signed-unsigned) + (:variant-cost 6) + (:translate eq)) + +(define-vop (generic-eql/fixnum fast-if-eql/fixnum) (:args (x :scs (any-reg descriptor-reg)) (y :scs (any-reg))) (:arg-types * tagged-num) (:variant-cost 7)) -(define-vop (fast-eql-c/fixnum) - (:args (x :scs (any-reg))) - (:arg-types tagged-num (:constant (satisfies fixnum-abs-add-sub-immediate-p))) - (:info y) - (:translate eql) - (:policy :fast-safe) - (:conditional :eq) - (:generator 3 - (if (minusp y) - (inst cmn x (fixnumize (abs y))) - (inst cmp x (fixnumize y))))) - -(define-vop (generic-eql-c/fixnum fast-eql-c/fixnum) +(define-vop (generic-eql-c/fixnum fast-if-eql-integer/c) (:args (x :scs (any-reg descriptor-reg))) (:arg-types * (:constant (satisfies fixnum-add-sub-immediate-p))) (:variant-cost 6)) (macrolet ((define-logtest-vops () `(progn - ,@(loop for suffix in '(/fixnum -c/fixnum - /signed -c/signed - /unsigned -c/unsigned) - for cost in '(4 3 6 5 6 5) - for arg-types in '(nil - (fixnum - (:constant - (satisfies fixnum-encode-logical-immediate))) - nil - (signed-num - (:constant - (satisfies encode-logical-immediate))) - nil - (unsigned-num - (:constant (satisfies encode-logical-immediate)))) + ,@(loop for suffix in '(/fixnum /signed /unsigned) + for cost in '(4 6 6) collect `(define-vop (,(symbolicate "FAST-LOGTEST" suffix) ,(symbolicate "FAST-CONDITIONAL" suffix)) (:translate logtest) (:conditional :ne) - ,@(and arg-types - `((:arg-types ,@arg-types))) (:generator ,cost - (inst tst x - ,(if (eq suffix '-c/fixnum) - '(fixnumize y) - 'y)))))))) + (inst tst x y))))))) (define-logtest-vops)) +(define-vop (fast-logtest-c) + (:translate logtest) + (:args (x :scs (any-reg signed-reg unsigned-reg))) + (:arg-types (:or tagged-num signed-num unsigned-num) + (:constant (or signed-word word))) + (:info y) + (:policy :fast-safe) + (:conditional :ne) + (:generator 2 + (block nil + (if (= y most-positive-word) + (inst cmp x 0) + (let ((y (if (sc-is x any-reg) + (cond ((fixnump y) + (fixnumize y)) + ((let ((y (ldb (byte 64 0) y))) + ;; Only a negative fixnum will match that bit, + ;; so if the next bit is also 1 it can be shifted left. + (when (and (= (ldb (byte 1 62) y) 1) + (encode-logical-immediate + (ldb (byte 64 0) (ash y 1)))) + (return (inst tst x (ldb (byte 64 0) (ash y 1))))))) + (t + (return + (inst tst (load-immediate-word tmp-tn y) + (asr x n-fixnum-tag-bits))))) + y))) + (if (encode-logical-immediate y) + (inst tst x y) + (inst tst x (load-immediate-word tmp-tn y)))))))) + (define-source-transform lognand (x y) `(lognot (logand ,x ,y))) @@ -933,33 +1116,24 @@ (defun %logbitp (integer index) (logbitp index integer)) -(define-vop (fast-logbitp-c/fixnum fast-conditional-c/fixnum) - (:translate %logbitp) - (:conditional :ne) - (:arg-types tagged-num (:constant (mod #.n-word-bits))) - (:generator 4 - (inst tst x (ash 1 (min (+ y n-fixnum-tag-bits) - (1- n-word-bits)))))) - -(define-vop (fast-logbitp-c/signed fast-conditional-c/signed) - (:translate %logbitp) - (:conditional :ne) - (:arg-types signed-num (:constant (mod #.n-word-bits))) - (:generator 5 - (inst tst x (ash 1 y)))) - -(define-vop (fast-logbitp-c/unsigned fast-conditional-c/unsigned) +(define-vop () (:translate %logbitp) + (:policy :fast-safe) + (:args (x :scs (any-reg signed-reg unsigned-reg))) + (:info y) + (:arg-types (:or tagged-num signed-num unsigned-num) (:constant (mod #.n-word-bits))) (:conditional :ne) - (:arg-types unsigned-num (:constant (mod #.n-word-bits))) - (:generator 5 - (inst tst x (ash 1 y)))) + (:generator 2 + (inst tst x (ash 1 (min (if (sc-is x any-reg) + (+ y n-fixnum-tag-bits) + y) + (1- n-word-bits)))))) ;; Specialised mask-signed-field VOPs. (define-vop (mask-signed-field-word/c) (:translate sb-c::mask-signed-field) (:policy :fast-safe) - (:args (x :scs (signed-reg unsigned-reg) :target r)) + (:args (x :scs (signed-reg unsigned-reg))) (:arg-types (:constant (integer 0 64)) untagged-num) (:results (r :scs (signed-reg))) (:result-types signed-num) @@ -974,7 +1148,7 @@ (define-vop (mask-signed-field-bignum/c) (:translate sb-c::mask-signed-field) (:policy :fast-safe) - (:args (x :scs (descriptor-reg) :target r)) + (:args (x :scs (descriptor-reg))) (:arg-types (:constant (integer 0 64)) bignum) (:results (r :scs (signed-reg))) (:result-types signed-num) @@ -1037,6 +1211,17 @@ (define-full-setter bignum-set * bignum-digits-offset other-pointer-lowtag (unsigned-reg) unsigned-num sb-bignum:%bignum-set) +(define-partial-reffer sb-c::%half-bignum-ref bignum + :word nil bignum-digits-offset other-pointer-lowtag (unsigned-reg signed-reg) + positive-fixnum + sb-bignum:%half-bignum-ref) + +(define-partial-setter sb-c::%half-bignum-set bignum + :word bignum-digits-offset other-pointer-lowtag (unsigned-reg signed-reg) + positive-fixnum + (setf sb-bignum:%half-bignum-ref)) + + (define-vop (digit-0-or-plus) (:translate sb-bignum:%digit-0-or-plusp) (:policy :fast-safe) @@ -1045,8 +1230,8 @@ (:conditional) (:info target not-p) (:generator 2 - (inst cmp digit 0) - (inst b (if not-p :lt :ge) target))) + (inst cmp digit 0) + (inst b (if not-p :lt :ge) target))) (define-vop (add-w/carry) (:translate sb-bignum:%add-with-carry) @@ -1057,11 +1242,13 @@ (:arg-types unsigned-num unsigned-num positive-fixnum) (:results (result :scs (unsigned-reg)) (carry :scs (unsigned-reg) :from :eval)) + (:optional-results carry) (:result-types unsigned-num positive-fixnum) (:generator 3 (inst cmp c 1) ;; Set carry if (fixnum 0 or 1) c=0, else clear. (inst adcs result a b) - (inst cset carry :cs))) + (unless (eq (tn-kind carry) :unused) + (inst cset carry :cs)))) (define-vop (sub-w/borrow) (:translate sb-bignum:%subtract-with-borrow) @@ -1072,11 +1259,13 @@ (:arg-types unsigned-num unsigned-num positive-fixnum) (:results (result :scs (unsigned-reg)) (borrow :scs (unsigned-reg) :from :eval)) + (:optional-results borrow) (:result-types unsigned-num positive-fixnum) (:generator 4 (inst cmp c 1) ;; Set carry if (fixnum 0 or 1) c=0, else clear. (inst sbcs result a b) - (inst cset borrow :cs))) + (unless (eq (tn-kind borrow) :unused) + (inst cset borrow :cs)))) (define-vop (bignum-mult-and-add-3-arg) (:translate sb-bignum:%multiply-and-add) @@ -1129,7 +1318,7 @@ (define-vop (mulhi) (:translate %multiply-high) (:policy :fast-safe) - (:args (x :scs (unsigned-reg) :target hi) + (:args (x :scs (unsigned-reg)) (y :scs (unsigned-reg))) (:arg-types unsigned-num unsigned-num) (:results (hi :scs (unsigned-reg))) @@ -1140,7 +1329,7 @@ (define-vop (mulhi/fx) (:translate %multiply-high) (:policy :fast-safe) - (:args (x :scs (any-reg) :target hi) + (:args (x :scs (any-reg)) (y :scs (unsigned-reg))) (:arg-types positive-fixnum unsigned-num) (:temporary (:sc unsigned-reg) temp) @@ -1150,6 +1339,17 @@ (inst umulh temp x y) (inst and hi temp (bic-mask fixnum-tag-mask)))) +(define-vop () + (:translate %signed-multiply-high) + (:policy :fast-safe) + (:args (x :scs (signed-reg)) + (y :scs (signed-reg))) + (:arg-types signed-num signed-num) + (:results (hi :scs (signed-reg))) + (:result-types signed-num) + (:generator 20 + (inst smulh hi x y))) + (define-vop (bignum-lognot lognot-mod64/unsigned=>unsigned) (:translate sb-bignum:%lognot)) @@ -1176,10 +1376,22 @@ (unless (= i 64) (inst adc rem rem rem)))))) +(define-vop (half-bignum-floor bignum-floor) + (:translate sb-bignum:%half-bigfloor) + (:args (div-high :scs (unsigned-reg) :to :save) + (div-low :scs (unsigned-reg) :target x) + (divisor :scs (unsigned-reg) :to (:result 1))) + (:temporary (:sc unsigned-reg :from (:argument 1)) x) + (:generator 30 + (move x div-low) + (inst bfm x div-high 32 31) + (inst udiv quo x divisor) + (inst msub rem quo divisor x))) + (define-vop (signify-digit) (:translate sb-bignum:%fixnum-digit-with-correct-sign) (:policy :fast-safe) - (:args (digit :scs (unsigned-reg) :target res)) + (:args (digit :scs (unsigned-reg))) (:arg-types unsigned-num) (:results (res :scs (any-reg signed-reg))) (:result-types signed-num) @@ -1209,3 +1421,450 @@ (:generator 1 (inst lsl result digit count))) +(define-vop () + (:translate sb-c::fixnum*) + (:args (x :scs (any-reg)) + (y :scs (signed-reg immediate))) + (:arg-types tagged-num tagged-num (:constant t)) + (:info type) + (:temporary (:sc signed-reg) high) + (:results (r :scs (any-reg) :from :load)) + (:result-types tagged-num) + (:policy :fast-safe) + (:vop-var vop) + (:generator 2 + (let* ((*location-context* (unless (eq type 'fixnum) + type)) + (error (generate-error-code vop 'sb-kernel::mul-overflow-error r high))) + (let (value) + (when (sc-is y immediate) + (load-immediate-word high (setf value (tn-value y))) + (setf y high)) + (if (and value + (plusp value) + (= (logcount value) 1)) + (inst lsl r x (1- (integer-length value))) + (inst mul r x y)) + (inst smulh high x y)) + (inst cmp high (asr r 63)) + (inst b :ne error)))) + +(define-vop () + (:translate sb-c::signed*) + (:args (x :scs (signed-reg)) + (y :scs (signed-reg immediate))) + (:arg-types signed-num signed-num (:constant t)) + (:info type) + (:temporary (:sc signed-reg) high) + (:results (r :scs (signed-reg) :from :load)) + (:result-types signed-num) + (:policy :fast-safe) + (:vop-var vop) + (:generator 2 + (let* ((*location-context* (unless (eq type 'fixnum) + type)) + (error (generate-error-code vop 'sb-kernel::mul-overflow-error r high))) + (let (value) + (when (sc-is y immediate) + (load-immediate-word high (setf value (tn-value y))) + (setf y high)) + (if (and value + (plusp value) + (= (logcount value) 1)) + (inst lsl r x (1- (integer-length value))) + (inst mul r x y)) + (inst smulh high x y)) + (inst cmp high (asr r 63)) + (inst b :ne error)))) + +(define-vop () + (:translate sb-c::unsigned*) + (:args (x :scs (unsigned-reg)) + (y :scs (unsigned-reg immediate))) + (:arg-types unsigned-num unsigned-num (:constant t)) + (:info type) + (:temporary (:sc unsigned-reg) high) + (:results (r :scs (unsigned-reg) :from :load)) + (:result-types unsigned-num) + (:policy :fast-safe) + (:vop-var vop) + (:generator 2 + (let* ((*location-context* (unless (eq type 'fixnum) + type)) + (error (generate-error-code vop 'sb-kernel::mul-overflow-error r high))) + (let ((value (and (sc-is y immediate) + (tn-value y)))) + + (cond ((and value + (plusp value) + (= (logcount value) 1)) + (let ((shift (1- (integer-length value)))) + (inst lsl r x shift) + (inst lsr high x (- n-word-bits shift)))) + (t + (when (sc-is y immediate) + (load-immediate-word high value) + (setf y high)) + (inst mul r x y) + (inst umulh high x y)))) + (inst cbnz high error)))) + +(define-vop (*/signed=>integer) + (:translate *) + (:args (x :scs (signed-reg)) + (y :scs (signed-reg immediate))) + (:arg-types signed-num signed-num) + (:temporary (:sc signed-reg) high low) + (:temporary (:sc signed-reg :from (:argument 2)) header) + (:temporary (:scs (non-descriptor-reg) :offset lr-offset) lr) + (:results (r :scs (descriptor-reg))) + (:policy :fast-safe) + (:vop-var vop) + (:generator 10 + (let (value) + (when (sc-is y immediate) + (load-immediate-word high (setf value (tn-value y))) + (setf y high)) + (if (and value + (plusp value) + (= (logcount value) 1)) + (inst lsl low x (1- (integer-length value))) + (inst mul low x y)) + (inst smulh high x y)) + (inst mov header (bignum-header-for-length 2)) + (inst cmp high (asr low 63)) + (inst b :ne allocate) + (inst adds r low low) + (inst b :vc done) + (inst mov header (bignum-header-for-length 1)) + #+bignum-assertions + (inst mov high 0) + allocate + (with-fixed-allocation + (r lr nil (+ 2 bignum-digits-offset)) + (storew-pair header 0 low bignum-digits-offset tmp-tn) + (storew high tmp-tn 2)) + DONE)) + +(define-vop (*/unsigned=>integer) + (:translate *) + (:args (x :scs (unsigned-reg)) + (y :scs (unsigned-reg immediate))) + (:arg-types unsigned-num unsigned-num) + (:temporary (:sc unsigned-reg) high low) + (:temporary (:sc unsigned-reg :from (:argument 2)) header) + (:temporary (:scs (non-descriptor-reg) :offset lr-offset) lr) + (:results (r :scs (descriptor-reg))) + (:policy :fast-safe) + (:vop-var vop) + (:generator 12 + (let ((value (and (sc-is y immediate) + (tn-value y)))) + (cond ((and value + (plusp value) + (= (logcount value) 1)) + (let ((shift (1- (integer-length value)))) + (inst lsl low x shift) + (inst lsr high x (- n-word-bits shift)))) + (t + (when (sc-is y immediate) + (load-immediate-word high value) + (setf y high)) + (inst mul low x y) + (inst umulh high x y)))) + (inst mov header (bignum-header-for-length 3)) + (inst tbnz high 63 allocate) + (inst mov header (bignum-header-for-length 2)) + (inst cbnz high allocate) + (inst tbnz low 63 allocate) + (inst adds r low low) + (inst b :vc done) + (inst mov header (bignum-header-for-length 1)) + allocate + (with-fixed-allocation + (r lr nil (+ 2 bignum-digits-offset)) + (storew-pair header 0 low bignum-digits-offset tmp-tn) + (storew high tmp-tn 2)) + DONE)) + +(define-vop (+/signed=>integer) + (:translate +) + (:args (x :scs (signed-reg)) + (y :scs (signed-reg immediate))) + (:arg-types signed-num signed-num) + (:temporary (:sc signed-reg) high low) + (:temporary (:sc signed-reg :from (:argument 2)) header) + (:temporary (:scs (non-descriptor-reg) :offset lr-offset) lr) + (:results (r :scs (descriptor-reg))) + (:policy :fast-safe) + (:vop-var vop) + (:generator 10 + (if (sc-is y immediate) + (let ((y (tn-value y))) + (if (minusp y) + (inst subs low x (add-sub-immediate (- y) high)) + (inst adds low x (add-sub-immediate y high)))) + (inst adds low x y)) + (inst csetm high :cs) + (inst mov header (bignum-header-for-length 2)) + (inst b :vs allocate) + (inst adds r low low) + (inst b :vc done) + (inst mov header (bignum-header-for-length 1)) + allocate + (with-fixed-allocation + (r lr nil (+ 2 bignum-digits-offset)) + (storew-pair header 0 low bignum-digits-offset tmp-tn) + (storew high tmp-tn 2)) + DONE)) + +(define-vop (-/signed=>integer) + (:translate -) + (:args (x :scs (signed-reg)) + (y :scs (signed-reg immediate))) + (:arg-types signed-num signed-num) + (:temporary (:sc signed-reg) high low) + (:temporary (:sc signed-reg :from (:argument 2)) header) + (:temporary (:scs (non-descriptor-reg) :offset lr-offset) lr) + (:results (r :scs (descriptor-reg))) + (:policy :fast-safe) + (:vop-var vop) + (:generator 10 + (if (sc-is y immediate) + (let ((y (tn-value y))) + (if (minusp y) + (inst adds low x (add-sub-immediate (- y) high)) + (inst subs low x (add-sub-immediate y high)))) + (inst subs low x y)) + (inst csetm high :cs) + (inst mov header (bignum-header-for-length 2)) + (inst b :vs allocate) + (inst adds r low low) + (inst b :vc done) + (inst mov header (bignum-header-for-length 1)) + allocate + (with-fixed-allocation + (r lr nil (+ 2 bignum-digits-offset)) + (storew-pair header 0 low bignum-digits-offset tmp-tn) + (storew high tmp-tn 2)) + DONE)) + +(define-vop (+/unsigned=>integer) + (:translate +) + (:args (x :scs (unsigned-reg)) + (y :scs (unsigned-reg immediate))) + (:arg-types unsigned-num unsigned-num) + (:temporary (:sc unsigned-reg) high low) + (:temporary (:sc unsigned-reg :from (:argument 2)) header) + (:temporary (:scs (non-descriptor-reg) :offset lr-offset) lr) + (:results (r :scs (descriptor-reg))) + (:policy :fast-safe) + (:vop-var vop) + (:generator 10 + (inst adds low x (if (sc-is y immediate) + (add-sub-immediate (tn-value y) high) + y)) + (inst mov header (bignum-header-for-length 2)) + (inst cset high :cs) + (inst b :cs allocate) + (inst b :mi allocate) + (inst adds r low low) + (inst b :vc done) + (inst mov header (bignum-header-for-length 1)) + allocate + (with-fixed-allocation + (r lr nil (+ 2 bignum-digits-offset)) + (storew-pair header 0 low bignum-digits-offset tmp-tn) + (storew high tmp-tn 2)) + DONE)) + +(define-vop (-/unsigned=>integer) + (:translate -) + (:args (x :scs (unsigned-reg)) + (y :scs (unsigned-reg immediate))) + (:arg-types unsigned-num unsigned-num) + (:temporary (:sc unsigned-reg) high low) + (:temporary (:sc unsigned-reg :from (:argument 2)) header) + (:temporary (:scs (non-descriptor-reg) :offset lr-offset) lr) + (:results (r :scs (descriptor-reg))) + (:policy :fast-safe) + (:vop-var vop) + (:generator 10 + (inst subs low x (if (sc-is y immediate) + (add-sub-immediate (tn-value y) high) + y)) + (inst mov header (bignum-header-for-length 2)) + (inst csetm high :cc) + (inst b :cc negative) + (inst b :mi allocate) + (inst b positive) + negative + (inst b :pl allocate) + positive + (inst adds r low low) + (inst b :vc done) + (inst mov header (bignum-header-for-length 1)) + allocate + (with-fixed-allocation + (r lr nil (+ 2 bignum-digits-offset)) + (storew-pair header 0 low bignum-digits-offset tmp-tn) + (storew high tmp-tn 2)) + DONE)) + +(define-vop () + (:translate sb-c::signed+) + (:args (x :scs (signed-reg)) + (y :scs (signed-reg immediate))) + (:arg-types signed-num signed-num (:constant t)) + (:info type) + (:results (r :scs (signed-reg))) + (:result-types signed-num) + (:policy :fast-safe) + (:vop-var vop) + (:generator 2 + (let* ((*location-context* (unless (eq type 'fixnum) + type)) + (error (generate-error-code vop 'sb-kernel::add-sub-overflow-error r))) + (if (sc-is y immediate) + (let ((y (tn-value y))) + (if (minusp y) + (inst subs r x (add-sub-immediate (- y))) + (inst adds r x (add-sub-immediate y)))) + (inst adds r x y)) + (inst b :vs error)))) + +(define-vop () + (:translate sb-c::signed-) + (:args (x :scs (signed-reg)) + (y :scs (signed-reg immediate))) + (:arg-types signed-num signed-num (:constant t)) + (:info type) + (:results (r :scs (signed-reg))) + (:result-types signed-num) + (:policy :fast-safe) + (:vop-var vop) + (:generator 2 + (let* ((*location-context* (unless (eq type 'fixnum) + type)) + (error (generate-error-code vop 'sb-kernel::add-sub-overflow-error r))) + (if (sc-is y immediate) + (let ((y (tn-value y))) + (if (minusp y) + (inst adds r x (add-sub-immediate (- y))) + (inst subs r x (add-sub-immediate y)))) + (inst subs r x y)) + (inst b :vs error)))) + +(define-vop () + (:translate sb-c::unsigned+) + (:args (x :scs (unsigned-reg)) + (y :scs (unsigned-reg immediate))) + (:arg-types unsigned-num unsigned-num (:constant t)) + (:info type) + (:results (r :scs (unsigned-reg))) + (:result-types unsigned-num) + (:policy :fast-safe) + (:vop-var vop) + (:generator 2 + (let* ((*location-context* (unless (eq type 'fixnum) + type)) + (error (generate-error-code vop 'sb-kernel::add-sub-overflow-error r))) + (when (sc-is y immediate) + (setf y (add-sub-immediate (tn-value y)))) + (inst adds r x y) + (inst b :cs error)))) + +(define-vop () + (:translate sb-c::unsigned-) + (:args (x :scs (unsigned-reg)) + (y :scs (unsigned-reg immediate))) + (:arg-types unsigned-num unsigned-num (:constant t)) + (:info type) + (:results (r :scs (unsigned-reg))) + (:result-types unsigned-num) + (:policy :fast-safe) + (:vop-var vop) + (:generator 2 + (let* ((*location-context* (unless (eq type 'fixnum) + type)) + (error (generate-error-code vop 'sb-kernel::add-sub-overflow-error r))) + (when (sc-is y immediate) + (setf y (add-sub-immediate (tn-value y)))) + (inst subs r x y) + (inst b :cc error)))) + +(define-vop () + (:translate sb-c::unsigned+signed) + (:args (x :scs (unsigned-reg) :to :result) + (y :scs (signed-reg immediate))) + (:arg-types unsigned-num signed-num (:constant t)) + (:info type) + (:results (r :scs (unsigned-reg))) + (:temporary (:scs (unsigned-reg) :from (:argument 2)) temp) + (:result-types unsigned-num) + (:policy :fast-safe) + (:vop-var vop) + (:generator 2 + (let* ((*location-context* (unless (eq type 'fixnum) + type)) + (error (generate-error-code vop 'sb-kernel::add-sub-overflow-error r))) + (if (sc-is y immediate) + (assemble () + (let ((value (tn-value y))) + (setf y (add-sub-immediate (abs value))) + (cond ((plusp value) + (inst adds r x y) + (inst b :cs error)) + (t + (inst subs r x y) + (inst b :cc error))))) + (assemble () + (when (sc-is y immediate) + (setf y (add-sub-immediate (tn-value y)))) + (inst tbnz y 63 neg) + (inst adds r x y) + (inst b :cs error) + (inst b done) + neg + (inst neg temp y) + (inst subs r x temp) + (inst b :cc error) + done))))) + +(define-vop () + (:translate sb-c::unsigned-signed) + (:args (x :scs (unsigned-reg) :to :result) + (y :scs (signed-reg immediate))) + (:arg-types unsigned-num signed-num (:constant t)) + (:info type) + (:results (r :scs (unsigned-reg))) + (:temporary (:scs (unsigned-reg) :from (:argument 2)) temp) + (:result-types unsigned-num) + (:policy :fast-safe) + (:vop-var vop) + (:generator 2 + (let* ((*location-context* (unless (eq type 'fixnum) + type)) + (error (generate-error-code vop 'sb-kernel::add-sub-overflow-error r))) + (if (sc-is y immediate) + (assemble () + (let ((value (tn-value y))) + (setf y (add-sub-immediate (abs value))) + (cond ((minusp value) + (inst adds r x y) + (inst b :cs error)) + (t + (inst subs r x y) + (inst b :cc error))))) + (assemble () + (when (sc-is y immediate) + (setf y (add-sub-immediate (tn-value y)))) + (inst tbz y 63 pos) + (inst neg temp y) + (inst adds r x temp) + (inst b :cs error) + (inst b done) + pos + (inst subs r x y) + (inst b :cc error) + done))))) diff --git a/src/compiler/arm64/array.lisp b/src/compiler/arm64/array.lisp index a91fd2e332..4a614b9628 100644 --- a/src/compiler/arm64/array.lisp +++ b/src/compiler/arm64/array.lisp @@ -21,8 +21,8 @@ (rank :scs (any-reg))) (:arg-types tagged-num tagged-num) (:temporary (:scs (descriptor-reg) :to (:result 0) :target result) header) - (:temporary (:sc non-descriptor-reg) pa-flag ndescr) - (:temporary (:scs (interior-reg)) lip) + (:temporary (:sc non-descriptor-reg) ndescr) + (:temporary (:scs (non-descriptor-reg) :offset lr-offset) lr) (:results (result :scs (descriptor-reg))) (:generator 5 ;; Compute the allocation size. @@ -30,40 +30,18 @@ (inst add ndescr ndescr (+ (* array-dimensions-offset n-word-bytes) lowtag-mask)) (inst and ndescr ndescr (bic-mask lowtag-mask)) - (pseudo-atomic (pa-flag) - (allocation nil ndescr other-pointer-lowtag header :flag-tn pa-flag :lip lip) + (pseudo-atomic (lr) + (allocation nil ndescr other-pointer-lowtag header :flag-tn lr) ;; Now that we have the space allocated, compute the header ;; value. - (inst lsl ndescr rank (- n-widetag-bits n-fixnum-tag-bits)) - (inst add ndescr ndescr (ash (1- array-dimensions-offset) n-widetag-bits)) - (inst orr ndescr ndescr (lsr type n-fixnum-tag-bits)) + ;; See ENCODE-ARRAY-RANK. + (inst sub ndescr rank (fixnumize 1)) + (inst and ndescr ndescr (fixnumize array-rank-mask)) + (inst orr ndescr type (lsl ndescr array-rank-position)) + (inst lsr ndescr ndescr n-fixnum-tag-bits) ;; And store the header value. (storew ndescr header 0 other-pointer-lowtag)) (move result header))) - -(define-vop (make-array-header/c) - (:translate make-array-header) - (:policy :fast-safe) - (:arg-types (:constant t) (:constant t)) - (:info type rank) - (:temporary (:scs (descriptor-reg) :to (:result 0) :target result) header) - (:temporary (:sc non-descriptor-reg) pa-flag) - (:temporary (:scs (interior-reg)) lip) - (:results (result :scs (descriptor-reg))) - (:generator 4 - (let* ((header-size (+ rank - (1- array-dimensions-offset))) - (bytes (logandc2 (+ (* (1+ header-size) n-word-bytes) - lowtag-mask) - lowtag-mask)) - (header-bits (logior (ash header-size - n-widetag-bits) - type))) - (pseudo-atomic (pa-flag) - (allocation nil bytes other-pointer-lowtag header :flag-tn pa-flag :lip lip) - (load-immediate-word pa-flag header-bits) - (storew pa-flag header 0 other-pointer-lowtag))) - (move result header))) ;;;; Additional accessors and setters for the array header. (define-full-reffer %array-dimension * @@ -74,17 +52,50 @@ array-dimensions-offset other-pointer-lowtag (any-reg) positive-fixnum sb-kernel:%set-array-dimension) -(define-vop (array-rank-vop) - (:translate sb-kernel:%array-rank) +(define-vop () + (:translate %array-rank) (:policy :fast-safe) (:args (x :scs (descriptor-reg))) - (:temporary (:scs (non-descriptor-reg)) temp) - (:results (res :scs (any-reg descriptor-reg))) + (:results (res :scs (unsigned-reg))) + (:result-types positive-fixnum) (:generator 6 - (loadw temp x 0 other-pointer-lowtag) - (inst asr temp temp n-widetag-bits) - (inst sub temp temp (1- array-dimensions-offset)) - (inst lsl res temp n-fixnum-tag-bits))) + (inst ldrsb res (@ x (- (/ array-rank-position n-byte-bits) + other-pointer-lowtag))) + (inst add res res 1))) + +(define-vop () + (:translate %array-rank=) + (:policy :fast-safe) + (:args (array :scs (descriptor-reg))) + (:temporary (:scs (unsigned-reg)) x) + (:info rank) + (:arg-types * (:constant t)) + (:conditional :eq) + (:generator 2 + (inst ldrb x (@ array (- (/ array-rank-position n-byte-bits) + other-pointer-lowtag))) + (inst cmp x (add-sub-immediate (encode-array-rank rank))))) + +(define-vop (simple-array-header-of-rank-p type-predicate) + (:translate sb-c::simple-array-header-of-rank-p) + (:info target not-p rank) + (:arg-types * (:constant t)) + (:generator 2 + (unless (other-pointer-tn-ref-p args) + (%test-lowtag value temp (if not-p + target + drop-through) + t other-pointer-lowtag)) + (inst ldrh temp (@ value (- other-pointer-lowtag))) + (inst cmp temp (add-sub-immediate + (dpb (encode-array-rank rank) + (byte 8 array-rank-position) + simple-array-widetag))) + (inst b (if not-p + :ne + :eq) + target) + drop-through)) ;;;; Bounds checking routine. (define-vop (check-bound) @@ -140,6 +151,8 @@ (cond ((integerp bound) (inst cmp index bound) (inst b :hs error)) + ((eql index 0) + (inst cbz bound error)) (t (inst cmp bound index) (inst b :ls error)))))))) @@ -170,72 +183,52 @@ ;;; Variants built on top of word-index-ref, etc. I.e. those vectors whos ;;; elements are represented in integer registers and are built out of ;;; 8, 16, 32, or 64 bit elements. -(macrolet ((def-full-data-vector-frobs (type element-type &rest scs) - `(progn - (define-full-reffer ,(symbolicate "DATA-VECTOR-REF/" type) ,type - vector-data-offset other-pointer-lowtag - ,scs - ,element-type - data-vector-ref) - (define-full-setter ,(symbolicate "DATA-VECTOR-SET/" type) ,type - vector-data-offset other-pointer-lowtag ,scs ,element-type - data-vector-set))) - - (def-partial-data-vector-frobs (type element-type size signed &rest scs) - `(progn - (define-partial-reffer ,(symbolicate "DATA-VECTOR-REF/" type) ,type - ,size ,signed vector-data-offset other-pointer-lowtag ,scs - ,element-type data-vector-ref) - (define-partial-setter ,(symbolicate "DATA-VECTOR-SET/" type) ,type - ,size vector-data-offset other-pointer-lowtag ,scs - ,element-type data-vector-set)))) - - (def-full-data-vector-frobs simple-vector * - descriptor-reg any-reg) - - (def-partial-data-vector-frobs simple-base-string character - :byte nil character-reg) +(macrolet ((full (type element-type &rest scs) + `(progn + (define-full-reffer ,(symbolicate "DATA-VECTOR-REF/" type) ,type + vector-data-offset other-pointer-lowtag + ,scs + ,element-type + data-vector-ref) + (define-full-setter ,(symbolicate "DATA-VECTOR-SET/" type) ,type + vector-data-offset other-pointer-lowtag ,scs ,element-type + data-vector-set))) + + (partial (type element-type size signed &rest scs) + `(progn + (define-partial-reffer ,(symbolicate "DATA-VECTOR-REF/" type) ,type + ,size ,signed vector-data-offset other-pointer-lowtag ,scs + ,element-type data-vector-ref) + (define-partial-setter ,(symbolicate "DATA-VECTOR-SET/" type) ,type + ,size vector-data-offset other-pointer-lowtag ,scs + ,element-type data-vector-set)))) + + (full simple-vector * descriptor-reg any-reg) + (full simple-array-unsigned-byte-63 unsigned-num unsigned-reg) + (full simple-array-unsigned-byte-64 unsigned-num unsigned-reg) + (full simple-array-unsigned-fixnum positive-fixnum any-reg) + (full simple-array-fixnum tagged-num any-reg) + (full simple-array-signed-byte-64 signed-num signed-reg) + + (partial simple-base-string character :byte nil character-reg) #+sb-unicode - (def-partial-data-vector-frobs simple-character-string character - :word nil character-reg) - - (def-partial-data-vector-frobs simple-array-unsigned-byte-7 positive-fixnum - :byte nil unsigned-reg signed-reg) - (def-partial-data-vector-frobs simple-array-unsigned-byte-8 positive-fixnum - :byte nil unsigned-reg signed-reg) - - (def-partial-data-vector-frobs simple-array-unsigned-byte-15 positive-fixnum - :short nil unsigned-reg signed-reg) - (def-partial-data-vector-frobs simple-array-unsigned-byte-16 positive-fixnum - :short nil unsigned-reg signed-reg) + (partial simple-character-string character :word nil character-reg) - (def-partial-data-vector-frobs simple-array-unsigned-byte-31 positive-fixnum - :word nil unsigned-reg signed-reg) - (def-partial-data-vector-frobs simple-array-unsigned-byte-32 positive-fixnum - :word nil unsigned-reg signed-reg) + (partial simple-array-unsigned-byte-7 positive-fixnum :byte nil unsigned-reg signed-reg) + (partial simple-array-unsigned-byte-8 positive-fixnum :byte nil unsigned-reg signed-reg) - (def-full-data-vector-frobs simple-array-unsigned-byte-63 unsigned-num - unsigned-reg) + (partial simple-array-unsigned-byte-15 positive-fixnum :short nil unsigned-reg signed-reg) + (partial simple-array-unsigned-byte-16 positive-fixnum :short nil unsigned-reg signed-reg) - (def-full-data-vector-frobs simple-array-unsigned-byte-64 unsigned-num - unsigned-reg) + (partial simple-array-unsigned-byte-31 positive-fixnum :word nil unsigned-reg signed-reg) + (partial simple-array-unsigned-byte-32 positive-fixnum :word nil unsigned-reg signed-reg) - (def-partial-data-vector-frobs simple-array-signed-byte-8 tagged-num - :byte t signed-reg) + (partial simple-array-signed-byte-8 tagged-num :byte t signed-reg) + (partial simple-array-signed-byte-16 tagged-num :short t signed-reg) + (partial simple-array-signed-byte-32 tagged-num :word t signed-reg) - (def-partial-data-vector-frobs simple-array-signed-byte-16 tagged-num - :short t signed-reg) - - (def-partial-data-vector-frobs simple-array-signed-byte-32 tagged-num - :word t signed-reg) - - (def-full-data-vector-frobs simple-array-unsigned-fixnum positive-fixnum - any-reg) - (def-full-data-vector-frobs simple-array-fixnum tagged-num - any-reg) - - (def-full-data-vector-frobs simple-array-signed-byte-64 signed-num - signed-reg)) + (partial simple-array-single-float single-float :single-float nil single-reg) + (full simple-array-double-float double-float double-reg)) ;;; Integer vectors whose elements are smaller than a byte. I.e. bit, 2-bit, ;;; and 4-bit vectors. @@ -248,22 +241,23 @@ (:translate data-vector-ref) (:policy :fast-safe) (:args (object :scs (descriptor-reg)) - (index :scs (unsigned-reg))) + (index :scs (unsigned-reg) :to :save)) (:arg-types ,type positive-fixnum) - (:results (value :scs (any-reg))) + (:results (result :scs (unsigned-reg))) (:result-types positive-fixnum) - (:temporary (:scs (interior-reg)) lip) - (:temporary (:scs (non-descriptor-reg) :to (:result 0)) temp result) + (:temporary (:scs (non-descriptor-reg)) temp) (:generator 20 ;; Compute the offset for the word we're interested in. (inst lsr temp index ,bit-shift) ;; Load the word in question. - (inst add lip object (lsl temp word-shift)) - (inst ldr result (@ lip + (inst add temp object (lsl temp word-shift)) + (inst ldr result (@ temp (- (* vector-data-offset n-word-bytes) other-pointer-lowtag))) ;; Compute the position of the bitfield we need. - (inst and temp index ,(1- elements-per-word)) + ,(if (= bits 1) + `(setf temp index) + `(inst and temp index ,(1- elements-per-word))) ,@(when (eq *backend-byte-order* :big-endian) `((inst eor temp temp ,(1- elements-per-word)))) ,@(unless (= bits 1) @@ -271,9 +265,7 @@ ;; Shift the field we need to the low bits of RESULT. (inst lsr result result temp) ;; Mask out the field we're interested in. - (inst and result result ,(1- (ash 1 bits))) - ;; And fixnum-tag the result. - (inst lsl value result n-fixnum-tag-bits))) + (inst and result result ,(1- (ash 1 bits))))) (define-vop (,(symbolicate "DATA-VECTOR-REF/" type "-C")) (:note "inline array access") (:translate data-vector-ref) @@ -281,9 +273,8 @@ (:args (object :scs (descriptor-reg))) (:info index) (:arg-types ,type (:constant index)) - (:results (value :scs (any-reg))) + (:results (result :scs (unsigned-reg))) (:result-types positive-fixnum) - (:temporary (:scs (non-descriptor-reg) :to (:result 0)) result) (:generator 15 (multiple-value-bind (index bit) (floor index ,elements-per-word) (inst ldr result (@ object @@ -291,133 +282,120 @@ (+ (* index n-word-bytes) (- (* vector-data-offset n-word-bytes) other-pointer-lowtag))))) - (inst ubfm result result (* bit ,bits) (+ (* bit ,bits) (1- ,bits))) - (inst lsl value result n-fixnum-tag-bits)))) + (inst ubfm result result (* bit ,bits) (+ (* bit ,bits) (1- ,bits)))))) + (define-vop (,(symbolicate "DATA-VECTOR-SET/" type "-C")) + (:note "inline array store") + (:translate data-vector-set) + (:policy :fast-safe) + (:args (object :scs (descriptor-reg)) + (value :scs (unsigned-reg) + :load-if (not (and (sc-is value immediate) + (memq (tn-value value) + '(0 ,(1- (ash 1 bits)))))))) + (:info index) + (:arg-types ,type (:constant index) positive-fixnum) + (:temporary (:scs (non-descriptor-reg)) old) + (:generator 20 + (multiple-value-bind (index bit) (floor index ,elements-per-word) + (inst ldr old (@ object + (load-store-offset + (+ (* index n-word-bytes) + (- (* vector-data-offset n-word-bytes) + other-pointer-lowtag))))) + (cond ((not (sc-is value immediate)) + (inst bfm old value (mod (- n-word-bits (* bit ,bits)) n-word-bits) (1- ,bits))) + ((zerop (tn-value value)) + (inst and old old (lognot (ash (1- (ash 1 ,bits)) (* bit ,bits))))) + (t + (inst orr old old (ash (1- (ash 1 ,bits)) (* bit ,bits))))) + (inst str old (@ object + (load-store-offset + (+ (* index n-word-bytes) + (- (* vector-data-offset n-word-bytes) + other-pointer-lowtag)))))))) (define-vop (,(symbolicate "DATA-VECTOR-SET/" type)) (:note "inline array store") (:translate data-vector-set) (:policy :fast-safe) (:args (object :scs (descriptor-reg)) - (index :scs (unsigned-reg) :target shift) - (value :scs (unsigned-reg immediate) :target result)) + (index :scs (unsigned-reg) + ,@(unless (= bits 1) + '(:target shift))) + (value :scs (unsigned-reg immediate))) (:arg-types ,type positive-fixnum positive-fixnum) - (:results (result :scs (unsigned-reg))) - (:result-types positive-fixnum) - (:temporary (:scs (interior-reg)) lip) + (:temporary (:scs (non-descriptor-reg)) lip) (:temporary (:scs (non-descriptor-reg)) temp old) - (:temporary (:scs (non-descriptor-reg) :from (:argument 1)) shift) + ,@(unless (= bits 1) + '((:temporary (:scs (non-descriptor-reg) :from (:argument 1)) shift))) (:generator 25 - ;; Compute the offset for the word we're interested in. - (inst lsr temp index ,bit-shift) - ;; Load the word in question. - (inst add lip object (lsl temp word-shift)) - (inst ldr old (@ lip - (- (* vector-data-offset n-word-bytes) - other-pointer-lowtag))) - ;; Compute the position of the bitfield we need. - (inst and shift index ,(1- elements-per-word)) - ,@(when (eq *backend-byte-order* :big-endian) - `((inst eor shift ,(1- elements-per-word)))) - ,@(unless (= bits 1) - `((inst lsl shift shift ,(1- (integer-length bits))))) - ;; Clear the target bitfield. - (unless (and (sc-is value immediate) - (= (tn-value value) ,(1- (ash 1 bits)))) - (inst mov temp ,(1- (ash 1 bits))) - (inst lsl temp temp shift) - (inst bic old old temp)) - ;; LOGIOR in the new value (shifted appropriatly). - (sc-case value - (immediate - (inst mov temp (logand (tn-value value) ,(1- (ash 1 bits))))) - (unsigned-reg - (inst and temp value ,(1- (ash 1 bits))))) - (inst lsl temp temp shift) - (inst orr old old temp) - ;; Write the altered word back to the array. - (inst str old (@ lip - (- (* vector-data-offset n-word-bytes) - other-pointer-lowtag))) - ;; And present the result properly. - (sc-case value - (immediate - (inst mov result (tn-value value))) - (unsigned-reg - (move result value))))))))) + (let ((shift ,(if (= bits 1) + 'index + 'shift))) + ;; Compute the offset for the word we're interested in. + (inst lsr temp index ,bit-shift) + ;; Load the word in question. + (inst add lip object (lsl temp word-shift)) + (inst ldr old (@ lip + (- (* vector-data-offset n-word-bytes) + other-pointer-lowtag))) + ;; Compute the position of the bitfield we need. + ,@(unless (= bits 1) + `((inst and shift index ,(1- elements-per-word)))) + ,@(when (eq *backend-byte-order* :big-endian) + `((inst eor shift ,(1- elements-per-word)))) + ,@(unless (= bits 1) + `((inst lsl shift shift ,(1- (integer-length bits))))) + ;; Clear the target bitfield. + (unless (and (sc-is value immediate) + (= (tn-value value) ,(1- (ash 1 bits)))) + (inst mov temp ,(1- (ash 1 bits))) + (inst lsl temp temp shift) + (inst bic old old temp)) + (unless (and (sc-is value immediate) + (= (tn-value value) 0)) + ;; LOGIOR in the new value (shifted appropriately). + (sc-case value + (immediate + (inst mov temp (logand (tn-value value) ,(1- (ash 1 bits)))) + (inst lsl temp temp shift)) + (unsigned-reg + (inst lsl temp value shift))) + (inst orr old old temp)) + ;; Write the altered word back to the array. + (inst str old (@ lip + (- (* vector-data-offset n-word-bytes) + other-pointer-lowtag)))))))))) (def-small-data-vector-frobs simple-bit-vector 1) (def-small-data-vector-frobs simple-array-unsigned-byte-2 2) (def-small-data-vector-frobs simple-array-unsigned-byte-4 4)) -;;; And the float variants. -(define-vop (data-vector-ref/simple-array-single-float) - (:note "inline array access") - (:translate data-vector-ref) - (:policy :fast-safe) - (:args (object :scs (descriptor-reg)) - (index :scs (any-reg))) - (:arg-types simple-array-single-float positive-fixnum) - (:results (value :scs (single-reg))) - (:temporary (:scs (non-descriptor-reg) :from (:argument 1)) offset) - (:result-types single-float) - (:generator 5 - (inst lsl offset index (1- (- word-shift n-fixnum-tag-bits))) - (inst add offset offset (- (* vector-data-offset n-word-bytes) - other-pointer-lowtag)) - (inst ldr value (@ object offset)))) - -(define-vop (data-vector-set/simple-array-single-float) - (:note "inline array store") - (:translate data-vector-set) +(define-vop (data-vector-ref/simple-bit-vector-eq) (:policy :fast-safe) - (:args (object :scs (descriptor-reg)) - (index :scs (any-reg)) - (value :scs (single-reg) :target result)) - (:arg-types simple-array-single-float positive-fixnum single-float) - (:results (result :scs (single-reg))) - (:result-types single-float) - (:temporary (:scs (non-descriptor-reg) :from (:argument 1)) offset) - (:generator 5 - (inst lsl offset index (1- (- word-shift n-fixnum-tag-bits))) - (inst add offset offset (- (* vector-data-offset n-word-bytes) - other-pointer-lowtag)) - (inst str value (@ object offset)) - (unless (location= result value) - (inst fmov result value)))) + (:args (object :scs (descriptor-reg)) (index :scs (unsigned-reg))) + (:arg-types simple-bit-vector positive-fixnum) + (:conditional :eq) + (:temporary (:scs (non-descriptor-reg)) temp x) + (:generator 20 + (inst lsr temp index 6) + (inst add temp object (lsl temp word-shift)) + (inst ldr x (@ temp (- (* vector-data-offset n-word-bytes) other-pointer-lowtag))) + (inst lsr x x index) + (inst tst x 1))) -(define-vop (data-vector-ref/simple-array-double-float) - (:note "inline array access") - (:translate data-vector-ref) +(define-vop (data-vector-ref/simple-bit-vector-c-eq) (:policy :fast-safe) - (:args (object :scs (descriptor-reg)) - (index :scs (any-reg))) - (:arg-types simple-array-double-float positive-fixnum) - (:results (value :scs (double-reg))) - (:result-types double-float) - (:temporary (:scs (non-descriptor-reg) :from (:argument 1)) offset) - (:generator 7 - (inst lsl offset index (- word-shift n-fixnum-tag-bits)) - (inst add offset offset (- (* vector-data-offset n-word-bytes) - other-pointer-lowtag)) - (inst ldr value (@ object offset)))) + (:args (object :scs (descriptor-reg))) + (:info index) + (:arg-types simple-bit-vector (:constant index)) + (:conditional :eq) + (:temporary (:scs (non-descriptor-reg)) x) + (:generator 15 + (multiple-value-bind (index bit) + (floor index 64) + (inst ldr x (@ object (load-store-offset (+ (* index n-word-bytes) + (- (* vector-data-offset n-word-bytes) other-pointer-lowtag))))) + (inst tst x (ash 1 bit))))) -(define-vop (data-vector-set/simple-array-double-float) - (:note "inline array store") - (:translate data-vector-set) - (:policy :fast-safe) - (:args (object :scs (descriptor-reg)) - (index :scs (any-reg)) - (value :scs (double-reg) :target result)) - (:arg-types simple-array-double-float positive-fixnum double-float) - (:results (result :scs (double-reg))) - (:result-types double-float) - (:temporary (:scs (non-descriptor-reg) :from (:argument 1)) offset) - (:generator 20 - (inst lsl offset index (- word-shift n-fixnum-tag-bits)) - (inst add offset offset (- (* vector-data-offset n-word-bytes) - other-pointer-lowtag)) - (inst str value (@ object offset)) - (unless (location= result value) - (inst fmov result value)))) ;;; Complex float arrays. @@ -434,7 +412,7 @@ (:generator 5 (inst lsl offset index (- word-shift n-fixnum-tag-bits)) (inst add offset offset (- (* vector-data-offset n-word-bytes) - other-pointer-lowtag)) + other-pointer-lowtag)) (inst ldr value (@ object offset)))) (define-vop (data-vector-set/simple-array-complex-single-float) @@ -443,19 +421,15 @@ (:policy :fast-safe) (:args (object :scs (descriptor-reg) :to :result) (index :scs (any-reg)) - (value :scs (complex-single-reg) :target result)) + (value :scs (complex-single-reg))) (:arg-types simple-array-complex-single-float positive-fixnum complex-single-float) - (:results (result :scs (complex-single-reg))) - (:result-types complex-single-float) (:temporary (:scs (non-descriptor-reg) :from (:argument 1)) offset) (:generator 5 (inst lsl offset index (- word-shift n-fixnum-tag-bits)) (inst add offset offset (- (* vector-data-offset n-word-bytes) other-pointer-lowtag)) - (inst str value (@ object offset)) - (unless (location= result value) - (inst fmov result value)))) + (inst str value (@ object offset)))) (define-vop (data-vector-ref/simple-array-complex-double-float) (:note "inline array access") @@ -479,19 +453,15 @@ (:policy :fast-safe) (:args (object :scs (descriptor-reg) :to :result) (index :scs (any-reg)) - (value :scs (complex-double-reg) :target result)) + (value :scs (complex-double-reg))) (:arg-types simple-array-complex-double-float positive-fixnum complex-double-float) - (:results (result :scs (complex-double-reg))) - (:result-types complex-double-float) (:temporary (:scs (non-descriptor-reg) :from (:argument 1)) offset) (:generator 5 (inst lsl offset index (1+ (- word-shift n-fixnum-tag-bits))) (inst add offset offset (- (* vector-data-offset n-word-bytes) other-pointer-lowtag)) - (inst str value (@ object offset)) - (unless (location= result value) - (inst s-mov result value)))) + (inst str value (@ object offset)))) ;;; These vops are useful for accessing the bits of a vector irrespective of ;;; what type of vector it is. @@ -518,7 +488,7 @@ (:result-types unsigned-num) (:temporary (:sc unsigned-reg) offset) (:temporary (:sc non-descriptor-reg) sum) - (:temporary (:sc interior-reg) lip) + (:temporary (:sc non-descriptor-reg) lip) (:generator 4 (inst lsl offset index (- word-shift n-fixnum-tag-bits)) (inst add offset offset (- (* vector-data-offset n-word-bytes) @@ -532,3 +502,22 @@ (inst stlxr tmp-tn sum lip) (inst cbnz tmp-tn LOOP) (inst dmb))) + +(define-vop (array-atomic-incf/word-v8.1) + (:translate %array-atomic-incf/word) + (:policy :fast-safe) + (:args (object :scs (descriptor-reg)) + (index :scs (any-reg) :target offset) + (diff :scs (unsigned-reg))) + (:arg-types * positive-fixnum unsigned-num) + (:results (result :scs (unsigned-reg) :from :load)) + (:result-types unsigned-num) + (:temporary (:sc unsigned-reg) offset) + (:temporary (:sc non-descriptor-reg) lip) + (:guard (member :arm-v8.1 *backend-subfeatures*)) + (:generator 3 + (inst lsl offset index (- word-shift n-fixnum-tag-bits)) + (inst add offset offset (- (* vector-data-offset n-word-bytes) + other-pointer-lowtag)) + (inst add lip object offset) + (inst ldaddal diff result lip))) diff --git a/src/compiler/arm64/c-call.lisp b/src/compiler/arm64/c-call.lisp index e92514252b..bee27d8d81 100644 --- a/src/compiler/arm64/c-call.lisp +++ b/src/compiler/arm64/c-call.lisp @@ -33,30 +33,73 @@ nl7-offset) index)) -(defun int-arg (state prim-type reg-sc stack-sc) +(define-vop (move-word-arg-stack) + (:args (x :scs (signed-reg unsigned-reg single-reg)) + (fp :scs (any-reg))) + (:info size offset) + (:generator 0 + (let ((addr (@ fp (load-store-offset offset)))) + (ecase size + (1 + (inst strb x addr)) + (2 + (inst strh x addr)) + (4 + (inst str (if (sc-is x single-reg) + x + (32-bit-reg x)) + addr)))))) + +(defun move-to-stack-location (value size offset prim-type sc node block nsp) + (let ((temp-tn (sb-c:make-representation-tn + (primitive-type-or-lose prim-type) + sc))) + (sb-c::emit-move node + block + (sb-c::lvar-tn node block value) + temp-tn) + (sb-c::vop move-word-arg-stack node block temp-tn nsp size offset))) + +(defun int-arg (state prim-type reg-sc stack-sc &optional (size 8)) (let ((reg-args (arg-state-num-register-args state))) (cond ((< reg-args +max-register-args+) (setf (arg-state-num-register-args state) (1+ reg-args)) (make-wired-tn* prim-type reg-sc (register-args-offset reg-args))) (t - (let ((frame-size (arg-state-stack-frame-size state))) - (setf (arg-state-stack-frame-size state) (1+ frame-size)) - (make-wired-tn* prim-type stack-sc frame-size)))))) - -(defun float-arg (state prim-type reg-sc stack-sc) + (let ((frame-size (align-up (arg-state-stack-frame-size state) size))) + (setf (arg-state-stack-frame-size state) (+ frame-size size)) + (cond #+darwin + ((/= size n-word-bytes) + (lambda (value node block nsp) + (move-to-stack-location value size frame-size + prim-type reg-sc node block nsp))) + (t + (make-wired-tn* prim-type stack-sc (truncate frame-size size))))))))) + +(defun float-arg (state prim-type reg-sc stack-sc &optional (size 8)) (let ((reg-args (arg-state-fp-registers state))) (cond ((< reg-args +max-register-args+) (setf (arg-state-fp-registers state) (1+ reg-args)) (make-wired-tn* prim-type reg-sc reg-args)) (t - (let ((frame-size (arg-state-stack-frame-size state))) - (setf (arg-state-stack-frame-size state) (1+ frame-size)) - (make-wired-tn* prim-type stack-sc frame-size)))))) + (let ((frame-size (align-up (arg-state-stack-frame-size state) size))) + (setf (arg-state-stack-frame-size state) (+ frame-size size)) + (cond #+darwin + ((/= size n-word-bytes) + (lambda (value node block nsp) + (move-to-stack-location value size frame-size + prim-type reg-sc node block nsp))) + (t + (make-wired-tn* prim-type stack-sc (truncate frame-size size))))))))) (define-alien-type-method (integer :arg-tn) (type state) - (if (alien-integer-type-signed type) - (int-arg state 'signed-byte-64 signed-reg-sc-number signed-stack-sc-number) - (int-arg state 'unsigned-byte-64 unsigned-reg-sc-number unsigned-stack-sc-number))) + (let ((size #+darwin (truncate (alien-type-bits type) n-byte-bits) + #-darwin n-word-bytes)) + (if (alien-integer-type-signed type) + (int-arg state 'signed-byte-64 signed-reg-sc-number signed-stack-sc-number + size) + (int-arg state 'unsigned-byte-64 unsigned-reg-sc-number unsigned-stack-sc-number + size)))) (define-alien-type-method (system-area-pointer :arg-tn) (type state) (declare (ignore type)) @@ -64,7 +107,7 @@ (define-alien-type-method (single-float :arg-tn) (type state) (declare (ignore type)) - (float-arg state 'single-float single-reg-sc-number single-stack-sc-number)) + (float-arg state 'single-float single-reg-sc-number single-stack-sc-number #+darwin 4)) (define-alien-type-method (double-float :arg-tn) (type state) (declare (ignore type)) @@ -135,10 +178,17 @@ (defun make-call-out-tns (type) (let ((arg-state (make-arg-state))) (collect ((arg-tns)) - (dolist (arg-type (alien-fun-type-arg-types type)) - (arg-tns (invoke-alien-type-method :arg-tn arg-type arg-state))) + (let (#+darwin (variadic (sb-alien::alien-fun-type-varargs type))) + (loop for i from 0 + for arg-type in (alien-fun-type-arg-types type) + do + #+darwin + (when (eql i variadic) + (setf (arg-state-num-register-args arg-state) +max-register-args+ + (arg-state-fp-registers arg-state) +max-register-args+)) + (arg-tns (invoke-alien-type-method :arg-tn arg-type arg-state)))) (values (make-normal-tn *fixnum-primitive-type*) - (* (arg-state-stack-frame-size arg-state) n-word-bytes) + (arg-state-stack-frame-size arg-state) (arg-tns) (invoke-alien-type-method :result-tn (alien-fun-type-result-type type) @@ -150,11 +200,10 @@ (:args) (:arg-types (:constant simple-string)) (:info foreign-symbol) - (:temporary (:scs (interior-reg)) lip) (:results (res :scs (sap-reg))) (:result-types system-area-pointer) (:generator 2 - (load-inline-constant res `(:fixup ,foreign-symbol :foreign) lip))) + (load-inline-constant res `(:fixup ,foreign-symbol :foreign)))) (define-vop (foreign-symbol-dataref-sap) (:translate foreign-symbol-dataref-sap) @@ -162,37 +211,94 @@ (:args) (:arg-types (:constant simple-string)) (:info foreign-symbol) - (:temporary (:scs (interior-reg)) lip) (:results (res :scs (sap-reg))) (:result-types system-area-pointer) (:generator 2 - (load-inline-constant res `(:fixup ,foreign-symbol :foreign-dataref) lip) + (load-inline-constant res `(:fixup ,foreign-symbol :foreign-dataref)) (inst ldr res (@ res)))) +(defun emit-c-call (vop nfp-save temp temp2 cfunc function) + (let ((cur-nfp (current-nfp-tn vop))) + (when cur-nfp + (store-stack-tn nfp-save cur-nfp)) + (if (stringp function) + (load-inline-constant cfunc `(:fixup ,function :foreign)) + (sc-case function + (sap-reg (move cfunc function)) + (sap-stack + (load-stack-offset cfunc cur-nfp function)))) + (assemble () + #+sb-thread + (progn + (inst add temp csp-tn (* 2 n-word-bytes)) + ;; Build a new frame to stash a pointer to the current code object + ;; for the GC to see. + (inst adr temp2 return) + (inst stp cfp-tn temp2 (@ csp-tn)) + (storew-pair csp-tn thread-control-frame-pointer-slot temp thread-control-stack-pointer-slot thread-tn) + (inst blr cfunc) + + (loop for reg in (list r0-offset r1-offset r2-offset r3-offset + r4-offset r5-offset r6-offset r7-offset + #-darwin r8-offset) + do + (inst mov + (make-random-tn + :kind :normal + :sc (sc-or-lose 'descriptor-reg) + :offset reg) + 0)) + (storew zr-tn thread-tn thread-control-stack-pointer-slot)) + return + #-sb-thread + (progn + temp2 + (load-inline-constant temp '(:fixup "call_into_c" :foreign)) + (inst blr temp)) + (when cur-nfp + (load-stack-tn cur-nfp nfp-save))))) + +(eval-when (#-sb-xc :compile-toplevel :load-toplevel :execute) + (defun destroyed-c-registers () + (let ((gprs (list nl0-offset nl1-offset nl2-offset nl3-offset + nl4-offset nl5-offset nl6-offset nl7-offset nl8-offset nl9-offset + r0-offset r1-offset r2-offset r3-offset + r4-offset r5-offset r6-offset r7-offset + #-darwin r8-offset + #-sb-thread r11-offset)) + (vars)) + (append + (loop for gpr in gprs + collect `(:temporary (:sc any-reg :offset ,gpr :from :eval :to :result) + ,(car (push (gensym) vars)))) + (loop for float to 31 + collect `(:temporary (:sc single-reg :offset ,float :from :eval :to :result) + ,(car (push (gensym) vars)))) + `((:ignore ,@vars)))))) + (define-vop (call-out) (:args (function :scs (sap-reg sap-stack)) (args :more t)) (:results (results :more t)) - (:ignore args results) - (:save-p t) - (:temporary (:sc any-reg :offset r8-offset + (:ignore args results lr) + (:temporary (:sc non-descriptor-reg :offset lr-offset) lr) + (:temporary (:sc any-reg :offset r9-offset :from (:argument 0) :to (:result 0)) cfunc) (:temporary (:sc control-stack :offset nfp-save-offset) nfp-save) - (:temporary (:sc any-reg :offset r9-offset) temp) - (:temporary (:scs (interior-reg)) lip) + (:temporary (:sc any-reg :offset #+darwin r8-offset #-darwin r10-offset) temp) + (:temporary (:sc any-reg :offset lexenv-offset) temp2) (:vop-var vop) (:generator 0 - (let ((cur-nfp (current-nfp-tn vop))) - (when cur-nfp - (store-stack-tn nfp-save cur-nfp)) - (load-inline-constant temp '(:fixup "call_into_c" :foreign) lip) - (sc-case function - (sap-reg (move cfunc function)) - (sap-stack - (load-stack-offset cfunc cur-nfp function))) - (inst blr temp) - (when cur-nfp - (load-stack-tn cur-nfp nfp-save))))) + (emit-c-call vop nfp-save temp temp2 cfunc function)) + . + #. (destroyed-c-registers)) + +;;; Manually load the fixup instead of using foreign-symbol-sap, +;;; because it wants to go to r9, which is not compatible with sap-reg. +(define-vop (call-out-named call-out) + (:args (args :more t)) + (:info function variadic) + (:ignore args results variadic lr)) (define-vop (alloc-number-stack-space) (:info amount) @@ -216,8 +322,8 @@ ;;; long-long support ;; (deftransform %alien-funcall ((function type &rest args) * * :node node) -;; (aver (sb-c::constant-lvar-p type)) -;; (let* ((type (sb-c::lvar-value type)) +;; (aver (sb-c:constant-lvar-p type)) +;; (let* ((type (sb-c:lvar-value type)) ;; (env (sb-c::node-lexenv node)) ;; (arg-types (alien-fun-type-arg-types type)) ;; (result-type (alien-fun-type-result-type type))) @@ -310,7 +416,7 @@ ;; How many arguments have been copied (arg-count 0) ;; How many arguments have been copied from the stack - (stack-argument-count 0) + (stack-argument-bytes 0) (r0-tn (make-tn 0)) (r1-tn (make-tn 1)) (r2-tn (make-tn 2)) @@ -333,9 +439,8 @@ ;; Copy arguments (dolist (type argument-types) (let ((target-tn (@ nsp-tn (* arg-count n-word-bytes))) - ;; A TN pointing to the stack location that contains - ;; the next argument passed on the stack. - (stack-arg-tn (@ nsp-save-tn (* stack-argument-count n-word-bytes)))) + (size #+darwin (truncate (alien-type-bits type) n-byte-bits) + #-darwin n-word-bytes)) (cond ((or (alien-integer-type-p type) (alien-pointer-type-p type) (alien-type-= #.(parse-alien-type 'system-area-pointer nil) @@ -344,9 +449,30 @@ (cond (gpr (inst str gpr target-tn)) (t - (incf stack-argument-count) - (inst ldr temp-tn stack-arg-tn) - (inst str temp-tn target-tn)))) + (setf stack-argument-bytes + (align-up stack-argument-bytes size)) + (let ((addr (@ nsp-save-tn stack-argument-bytes))) + (cond #+darwin + ((/= size 8) + (let ((signed (and (alien-integer-type-p type) + (alien-integer-type-signed type)))) + (ecase size + (1 + (if signed + (inst ldrsb temp-tn addr) + (inst ldrb temp-tn addr))) + (2 + (if signed + (inst ldrsh temp-tn addr) + (inst ldrh temp-tn addr))) + (4 + (if signed + (inst ldrsw (32-bit-reg temp-tn) addr) + (inst ldr (32-bit-reg temp-tn) addr)))))) + (t + (inst ldr temp-tn addr))) + (inst str temp-tn target-tn)) + (incf stack-argument-bytes size)))) (incf arg-count)) ((alien-float-type-p type) (cond ((< fp-registers 8) @@ -356,9 +482,18 @@ 'double-reg)) target-tn)) (t - (incf stack-argument-count) - (inst ldr temp-tn stack-arg-tn) - (inst str temp-tn target-tn))) + (setf stack-argument-bytes + (align-up stack-argument-bytes size)) + (case size + #+darwin + (4 + (let ((reg (32-bit-reg temp-tn))) + (inst ldr reg (@ nsp-save-tn stack-argument-bytes)) + (inst str reg target-tn))) + (t + (inst ldr temp-tn (@ nsp-save-tn stack-argument-bytes)) + (inst str temp-tn target-tn))) + (incf stack-argument-bytes size))) (incf fp-registers) (incf arg-count)) (t @@ -404,9 +539,13 @@ ;; Now that the segment is done, convert it to a static ;; vector we can point foreign code to. (let* ((buffer (sb-assem:segment-buffer segment)) - (vector (make-static-vector (length buffer) + (vector #-darwin-jit + (make-static-vector (length buffer) :element-type '(unsigned-byte 8) - :initial-contents buffer)) + :initial-contents buffer) + #+darwin-jit + (make-static-code-vector (length buffer) + buffer)) (sap (vector-sap vector))) (alien-funcall (extern-alien "os_flush_icache" diff --git a/src/compiler/arm64/call.lisp b/src/compiler/arm64/call.lisp index 80d8442b88..d3e44c742f 100644 --- a/src/compiler/arm64/call.lisp +++ b/src/compiler/arm64/call.lisp @@ -14,51 +14,31 @@ (defconstant arg-count-sc (make-sc+offset immediate-arg-scn nargs-offset)) (defconstant closure-sc (make-sc+offset descriptor-reg-sc-number lexenv-offset)) -;;; Make a passing location TN for a local call return PC. If -;;; standard is true, then use the standard (full call) location, -;;; otherwise use any legal location. Even in the non-standard case, -;;; this may be restricted by a desire to use a subroutine call -;;; instruction. -(defun make-return-pc-passing-location (standard) - (declare (ignore standard)) - (make-wired-tn *backend-t-primitive-type* control-stack-sc-number - lra-save-offset)) - (defconstant return-pc-passing-offset (make-sc+offset control-stack-sc-number lra-save-offset)) -;;; This is similar to MAKE-RETURN-PC-PASSING-LOCATION, but makes a -;;; location to pass OLD-FP in. -;;; -;;; This is wired in both the standard and the local-call conventions, -;;; because we want to be able to assume it's always there. Besides, -;;; the ARM doesn't have enough registers to really make it profitable -;;; to pass it in a register. -(defun make-old-fp-passing-location () - (make-wired-tn *fixnum-primitive-type* control-stack-sc-number - ocfp-save-offset)) - (defconstant old-fp-passing-offset (make-sc+offset control-stack-sc-number ocfp-save-offset)) ;;; Make the TNs used to hold OLD-FP and RETURN-PC within the current ;;; function. We treat these specially so that the debugger can find ;;; them at a known location. -(defun make-old-fp-save-location (env) +(defun make-old-fp-save-location () ;; Unlike the other backends, ARM function calling is designed to ;; pass OLD-FP within the stack frame rather than in a register. As ;; such, in order for lifetime analysis not to screw up, we need it ;; to be a stack TN wired to the save offset, not a normal TN with a ;; wired SAVE-TN. - (physenv-debug-live-tn (make-wired-tn *fixnum-primitive-type* - control-stack-arg-scn - ocfp-save-offset) - env)) -(defun make-return-pc-save-location (physenv) - (physenv-debug-live-tn - (make-wired-tn *backend-t-primitive-type* control-stack-sc-number - lra-save-offset) - physenv)) + (let ((tn (make-wired-tn *fixnum-primitive-type* + control-stack-arg-scn + ocfp-save-offset))) + (setf (tn-kind tn) :environment) + tn)) +(defun make-return-pc-save-location () + (let ((tn (make-wired-tn *backend-t-primitive-type* control-stack-sc-number + lra-save-offset))) + (setf (tn-kind tn) :environment) + tn)) ;;; Make a TN for the standard argument count passing location. We ;;; only need to make the standard location, since a count is never @@ -112,8 +92,8 @@ (store-stack-offset value frame-pointer variable-home-tn))) (define-vop (xep-allocate-frame) + (:temporary (:sc non-descriptor-reg :offset lr-offset) lr) (:info start-lab) - (:temporary (:scs (interior-reg)) lip) (:generator 1 ;; Make sure the function is aligned, and drop a label pointing to this ;; function header. @@ -122,7 +102,7 @@ ;; Allocate function header. (inst simple-fun-header-word) (inst .skip (* (1- simple-fun-insts-offset) n-word-bytes)) - (inst compute-code code-tn lip start-lab))) + (inst str lr (@ cfp-tn (* lra-save-offset n-word-bytes))))) (define-vop (xep-setup-sp) (:vop-var vop) @@ -141,9 +121,13 @@ (:info callee) (:generator 2 (move res csp-tn) - (inst add csp-tn csp-tn (add-sub-immediate - (* (max 1 (sb-allocated-size 'control-stack)) n-word-bytes))) - (when (ir2-physenv-number-stack-p callee) + (let ((size (add-sub-immediate (* (max 1 (sb-allocated-size 'control-stack)) n-word-bytes)))) + (cond ((typep size '(signed-byte 9)) + (inst str cfp-tn (@ csp-tn size :post-index))) + (t + (inst add csp-tn csp-tn size) + (storew cfp-tn res ocfp-save-offset)))) + (when (ir2-environment-number-stack-p callee) (inst sub nfp nsp-tn (add-sub-immediate (bytes-needed-for-non-descriptor-stack-frame))) (inst mov-sp nsp-tn nfp)))) @@ -151,18 +135,21 @@ ;;; Allocate a partial frame for passing stack arguments in a full call. Nargs ;;; is the number of arguments passed. If no stack arguments are passed, then ;;; we don't have to do anything. +;;; LR and CFP are always saved on the stack, but it's safe to have two words above CSP. (define-vop (allocate-full-call-frame) (:info nargs) (:results (res :scs (any-reg))) (:generator 2 - ;; Unlike most other backends, we store the "OCFP" at frame - ;; allocation time rather than at function-entry time, largely due - ;; to a lack of usable registers. - ;; Our minimum caller frame size is two words, one for the frame - ;; link and one for the LRA. - (move res csp-tn) - (inst add csp-tn csp-tn (add-sub-immediate (* (max 2 nargs) n-word-bytes))) - (storew cfp-tn res ocfp-save-offset))) + (if (<= nargs register-arg-count) + ;; Don't touch RES, the call vops would use CSP-TN in this case. + (storew cfp-tn csp-tn ocfp-save-offset) + (let ((size (add-sub-immediate (* nargs n-word-bytes)))) + (move res csp-tn) + (cond ((typep size '(signed-byte 9)) + (inst str cfp-tn (@ csp-tn size :post-index))) + (t + (inst add csp-tn csp-tn size) + (storew cfp-tn res ocfp-save-offset))))))) ;;; Emit code needed at the return-point from an unknown-values call ;;; for a fixed number of values. VALUES is the head of the TN-REF @@ -190,14 +177,15 @@ ;;; -- Reset SP. This must be done whenever other than 1 value is returned, ;;; regardless of the number of values desired. -(defun default-unknown-values (vop values nvals move-temp lip lra-label) +(defun default-unknown-values (vop values nvals move-temp node) (declare (type (or tn-ref null) values) (type unsigned-byte nvals) (type tn move-temp)) - (let ((expecting-values-on-stack (> nvals register-arg-count))) + (let* ((type (sb-c::node-derived-type node)) + (min-values (values-type-min-value-count type)) + (expecting-values-on-stack (> nvals register-arg-count))) (note-this-location vop (if (<= nvals 1) :single-value-return :unknown-return)) - (inst compute-code code-tn lip lra-label) ;; Pick off the single-value case first. (sb-assem:without-scheduling () @@ -209,13 +197,22 @@ (val (tn-ref-across values) (tn-ref-across val))) ((= i (min nvals register-arg-count))) (unless (eq (tn-kind (tn-ref-tn val)) :unused) - (inst csel (tn-ref-tn val) null-tn (tn-ref-tn val) :ne)))) + (cond + ((and min-values + (> min-values i))) + (t + (inst csel (tn-ref-tn val) null-tn (tn-ref-tn val) :ne)))))) ;; If we're not expecting values on the stack, all that ;; remains is to clear the stack frame (for the multiple- ;; value return case). - (unless expecting-values-on-stack - (inst csel csp-tn ocfp-tn csp-tn :eq)) + (unless (or expecting-values-on-stack + (type-single-value-p type)) + (cond ((values-type-may-be-single-value-p type) + (inst csel csp-tn ocfp-tn csp-tn :eq)) + ((eq type *empty-type*)) + (t + (inst mov csp-tn ocfp-tn)))) ;; If we ARE expecting values on the stack, we need to ;; either move them to their result location or to set their @@ -225,9 +222,10 @@ ;; For the single-value return case, fake up NARGS and ;; OCFP so that we don't screw ourselves with the ;; defaulting and stack clearing logic. - (inst csel ocfp-tn csp-tn ocfp-tn :ne) - (inst mov tmp-tn (fixnumize 1)) - (inst csel nargs-tn tmp-tn nargs-tn :ne) + (unless (> min-values 1) + (inst csel ocfp-tn csp-tn ocfp-tn :ne) + (inst mov tmp-tn (fixnumize 1)) + (inst csel nargs-tn tmp-tn nargs-tn :ne)) ;; For each expected stack value... (do ((i register-arg-count (1+ i)) @@ -238,22 +236,64 @@ (tn-ref-across val))) ((null val)) (let ((tn (tn-ref-tn val))) - (if (eq (tn-kind tn) :unused) - (incf decrement (fixnumize 1)) - (assemble () - ;; ... Load it if there is a stack value available, or - ;; default it if there isn't. - (inst subs nargs-tn nargs-tn decrement) - (setf decrement (fixnumize 1)) - (inst b :lt NONE) - (loadw move-temp ocfp-tn i 0) - NONE - (sc-case tn - (control-stack - (inst csel move-temp null-tn move-temp :lt) - (store-stack-tn tn move-temp)) - (t - (inst csel tn null-tn move-temp :lt))))))) + (cond ((eq (tn-kind tn) :unused) + (incf decrement (fixnumize 1))) + ((< i min-values) + (incf decrement (fixnumize 1)) + (sc-case tn + (control-stack + (let* ((next (and (< (1+ i) min-values) + (tn-ref-across val))) + (next-tn (and next + (tn-ref-tn next)))) + (cond ((and next-tn + (not (sc-is next-tn control-stack)) + (neq (tn-kind next-tn) :unused) + (ldp-stp-offset-p (* i n-word-bytes) n-word-bits)) + (inst ldp move-temp next-tn + (@ ocfp-tn (* i n-word-bytes))) + (store-stack-tn tn move-temp) + (setf val next) + (incf i) + (incf decrement (fixnumize 1))) + (t + (loadw move-temp ocfp-tn i) + (store-stack-tn tn move-temp))))) + (t + (let* ((next (and (< (1+ i) min-values) + (tn-ref-across val))) + (next-tn (and next + (tn-ref-tn next)))) + (cond ((and next-tn + (neq (tn-kind next-tn) :unused) + (ldp-stp-offset-p (* i n-word-bytes) n-word-bits)) + (let ((stack (sc-is next-tn control-stack))) + (inst ldp tn (if stack + move-temp + next-tn) + (@ ocfp-tn (* i n-word-bytes))) + (when stack + (store-stack-tn next-tn move-temp))) + (setf val next) + (incf i) + (incf decrement (fixnumize 1))) + (t + (loadw tn ocfp-tn i))))))) + (t + (assemble () + ;; ... Load it if there is a stack value available, or + ;; default it if there isn't. + (inst subs nargs-tn nargs-tn decrement) + (setf decrement (fixnumize 1)) + (inst b :lt NONE) + (loadw move-temp ocfp-tn i) + NONE + (sc-case tn + (control-stack + (inst csel move-temp null-tn move-temp :lt) + (store-stack-tn tn move-temp)) + (t + (inst csel tn null-tn move-temp :lt)))))))) ;; Deallocate the callee stack frame. (move csp-tn ocfp-tn)))) (values)) @@ -276,26 +316,38 @@ ;;; Args and Nargs are TNs wired to the named locations. We must ;;; explicitly allocate these TNs, since their lifetimes overlap with the ;;; results Start and Count (also, it's nice to be able to target them). -(defun receive-unknown-values (args nargs start count lra-label lip) +(defun receive-unknown-values (node args nargs start count) (declare (type tn args nargs start count)) - (assemble () - (inst compute-code code-tn lip lra-label) - (inst b :eq MULTIPLE) - (move start csp-tn) - (inst add csp-tn csp-tn n-word-bytes) - (inst str (first *register-arg-tns*) (@ start)) - (inst mov count (fixnumize 1)) - (inst b DONE) - MULTIPLE - #.(assert (evenp register-arg-count)) - (do ((arg *register-arg-tns* (cddr arg)) - (i 0 (+ i 2))) - ((null arg)) - (inst stp (first arg) (second arg) - (@ args (* i n-word-bytes)))) - (move start args) - (move count nargs) - DONE)) + (let ((unused-count-p (eq (tn-kind count) :unused)) + (unused-start-p (eq (tn-kind start) :unused)) + (type (sb-c::node-derived-type node))) + (if (type-single-value-p type) + (assemble () + (unless unused-start-p + (move start csp-tn)) + (unless unused-count-p + (inst mov count (fixnumize 1))) + (inst str (first *register-arg-tns*) (@ csp-tn n-word-bytes :post-index))) + (assemble () + (inst b :eq MULTIPLE) + (unless unused-start-p + (move start csp-tn)) + (inst str (first *register-arg-tns*) (@ csp-tn n-word-bytes :post-index)) + (unless unused-count-p + (inst mov count (fixnumize 1))) + (inst b DONE) + MULTIPLE + #.(assert (evenp register-arg-count)) + (do ((arg *register-arg-tns* (cddr arg)) + (i 0 (+ i 2))) + ((null arg)) + (inst stp (first arg) (second arg) + (@ args (* i n-word-bytes)))) + (unless unused-start-p + (move start args)) + (unless unused-count-p + (move count nargs)) + DONE)))) ;;; VOP that can be inherited by unknown values receivers. The main ;;; thing this handles is allocation of the result temporaries. @@ -312,9 +364,12 @@ ;;; points, local-call entry points, and tail-call entry points. The default ;;; does nothing. (defun emit-block-header (start-label trampoline-label fall-thru-p alignp) - (declare (ignore fall-thru-p alignp)) + (declare (ignore alignp)) + (when (and fall-thru-p trampoline-label) + (inst b start-label)) (when trampoline-label - (emit-label trampoline-label)) + (emit-label trampoline-label) + (inst str lr-tn (@ cfp-tn (* lra-save-offset n-word-bytes)))) (emit-label start-label)) @@ -344,7 +399,7 @@ ;; NARGS is live. FP has been set up by the caller, SP is ;; protecting our stack arguments, but is otherwise not set up. NFP ;; is not yet set up. CODE and NULL are set up. SP and NFP must be - ;; correctly set up by the time we're done, and OCFP and R8 are + ;; correctly set up by the time we're done, and OCFP and R9 are ;; available for use as temporaries. If we were any more register ;; constrained, we'd be spilling registers manually (rather than ;; allowing PACK to do it for us). -- AJB, 2012-Oct-30 @@ -355,7 +410,7 @@ ;; live). (:temporary (:sc any-reg :offset ocfp-offset :to :eval) count) (:temporary (:sc any-reg :offset ocfp-offset :from :eval) dest) - (:temporary (:sc descriptor-reg :offset r8-offset) temp) + (:temporary (:sc descriptor-reg :offset r9-offset) temp) (:info fixed) (:generator 20 ;; We open up with a LET to obtain a TN for NFP. We'll call it @@ -368,8 +423,6 @@ :sc (sc-or-lose 'any-reg) :offset nfp-offset)) (delta (- (sb-allocated-size 'control-stack) fixed))) - ;; And we use ASSEMBLE here so that we get "implcit labels" - ;; rather than having to use GEN-LABEL and EMIT-LABEL. (assemble () ;; Compute the end of the fixed stack frame (start of the MORE ;; arg area) into RESULT. @@ -429,17 +482,20 @@ DO-REGS (when (< fixed register-arg-count) ;; Now we have to deposit any more args that showed up in registers. - (inst subs count nargs-tn (fixnumize fixed)) - (do ((i fixed (1+ i))) - ((>= i register-arg-count)) - ;; Don't deposit any more than there are. - (inst b :eq DONE) - (inst subs count count (fixnumize 1)) - ;; Store it into the space reserved to it, by displacement - ;; from the frame pointer. - (storew (nth i *register-arg-tns*) - cfp-tn (+ (sb-allocated-size 'control-stack) - (- i fixed))))) + (loop with i = fixed + for offset = (+ delta i) + do + (cond ((and (< (1+ i) register-arg-count) + (ldp-stp-offset-p (* offset n-word-bytes) n-word-bits)) + (inst stp + (nth i *register-arg-tns*) + (nth (1+ i) *register-arg-tns*) + (@ cfp-tn (* offset n-word-bytes))) + (incf i 2)) + (t + (storew (nth i *register-arg-tns*) cfp-tn offset) + (incf i))) + while (< i register-arg-count))) DONE ;; Now that we're done with the &MORE args, we can set up the @@ -472,6 +528,20 @@ (inst add temp context (lsl index (- word-shift n-fixnum-tag-bits))) (loadw value temp))))) +(define-vop () + (:translate sb-c::%more-keyword-pair) + (:policy :fast-safe) + (:args (context :scs (descriptor-reg)) + (index :scs (any-reg))) + (:arg-types * tagged-num) + (:temporary (:scs (any-reg)) temp) + (:results (keyword :scs (descriptor-reg any-reg)) + (value :scs (descriptor-reg any-reg))) + (:result-types * *) + (:generator 5 + (inst add temp context (lsl index (- word-shift n-fixnum-tag-bits))) + (inst ldp keyword value (@ temp)))) + (define-vop (more-arg-or-nil) (:policy :fast-safe) (:args (object :scs (descriptor-reg) :to (:result 1)) @@ -499,12 +569,11 @@ (:args (context-arg :target context :scs (descriptor-reg)) (count-arg :target count :scs (any-reg))) (:arg-types * tagged-num) - (:temporary (:scs (any-reg) :from (:argument 0)) context) + (:temporary (:scs (descriptor-reg) :from (:argument 0)) context) (:temporary (:scs (any-reg) :from (:argument 1)) count) (:temporary (:scs (descriptor-reg) :from :eval) temp) (:temporary (:scs (any-reg) :from :eval) dst) - (:temporary (:sc non-descriptor-reg) pa-flag) - (:temporary (:scs (interior-reg)) lip) + (:temporary (:sc non-descriptor-reg :offset lr-offset) lr) (:results (result :scs (descriptor-reg))) (:policy :safe) (:node-var node) @@ -515,40 +584,48 @@ (move result null-tn) (inst cbz count DONE) - ;; We need to do this atomically. - (pseudo-atomic (pa-flag :sync nil) - ;; Allocate a cons (2 words) for each item. - (let* ((dx-p (node-stack-allocate-p node)) - (size (cond (dx-p - (lsl count (1+ (- word-shift n-fixnum-tag-bits)))) - (t - (inst lsl temp count (1+ (- word-shift n-fixnum-tag-bits))) - temp)))) - (allocation 'list size list-pointer-lowtag dst - :flag-tn pa-flag - :stack-allocate-p dx-p - :lip lip)) - (move result dst) - - (inst b ENTER) - - ;; Compute the next cons and store it in the current one. - LOOP - (inst add dst dst (* 2 n-word-bytes)) - (storew dst dst -1 list-pointer-lowtag) - - ;; Grab one value. - ENTER - (inst ldr temp (@ context n-word-bytes :post-index)) - - ;; Dec count, and if != zero, go back for more. - (inst subs count count (fixnumize 1)) - ;; Store the value into the car of the current cons. - (storew temp dst 0 list-pointer-lowtag) - (inst b :gt LOOP) - - ;; NIL out the last cons. - (storew null-tn dst 1 list-pointer-lowtag)) + (let ((dx-p (node-stack-allocate-p node)) + (leave-pa (gen-label))) + (pseudo-atomic (lr :sync nil :elide-if dx-p) + ;; Allocate a cons (2 words) for each item. + (let ((size (cond (dx-p + (lsl count (1+ (- word-shift n-fixnum-tag-bits)))) + (t + (inst lsl temp count (1+ (- word-shift n-fixnum-tag-bits))) + temp)))) + (allocation 'list size list-pointer-lowtag dst + :flag-tn lr + :stack-allocate-p dx-p + :overflow + (lambda () + ;; The size will be computed by subtracting from CSP + (inst mov tmp-tn context) + (load-inline-constant lr `(:fixup listify-&rest :assembly-routine)) + (inst blr lr) + (inst mov result tmp-tn) + (inst b leave-pa)))) + (move result dst) + + (inst b ENTER) + + ;; Compute the next cons and store it in the current one. + LOOP + (inst add dst dst (* 2 n-word-bytes)) + (storew dst dst -1 list-pointer-lowtag) + + ;; Grab one value. + ENTER + (inst ldr temp (@ context n-word-bytes :post-index)) + + ;; Dec count, and if != zero, go back for more. + (inst subs count count (fixnumize 1)) + ;; Store the value into the car of the current cons. + (storew temp dst 0 list-pointer-lowtag) + (inst b :gt LOOP) + + ;; NIL out the last cons. + (storew null-tn dst 1 list-pointer-lowtag) + (emit-label LEAVE-PA))) DONE)) ;;; Return the location and size of the more arg glob created by @@ -581,29 +658,30 @@ (:arg-types positive-fixnum (:constant t) (:constant t)) (:info min max) (:vop-var vop) + (:temporary (:sc unsigned-reg :offset nl0-offset) temp) (:save-p :compute-only) (:generator 3 (let ((err-lab (generate-error-code vop 'invalid-arg-count-error))) (labels ((load-immediate (x) - (add-sub-immediate (fixnumize x))) - (check-min () - (cond ((= min 1) - (inst cbz nargs err-lab)) - ((plusp min) - (inst cmp nargs (load-immediate min)) - (inst b :lo err-lab))))) + (add-sub-immediate (fixnumize x)))) (cond ((eql max 0) (inst cbnz nargs err-lab)) ((not min) (inst cmp nargs (load-immediate max)) (inst b :ne err-lab)) (max - (check-min) - (inst cmp nargs (load-immediate max)) + (if (zerop min) + (setf temp nargs) + (inst sub temp nargs (load-immediate min))) + (inst cmp temp (load-immediate (- max min))) (inst b :hi err-lab)) (t - (check-min))))))) + (cond ((= min 1) + (inst cbz nargs err-lab)) + ((plusp min) + (inst cmp nargs (load-immediate min)) + (inst b :lo err-lab))))))))) ;;;; Local call with unknown values convention return: @@ -633,26 +711,22 @@ (:move-args :local-call) (:info arg-locs callee target nvals) (:vop-var vop) + (:node-var node) (:temporary (:scs (descriptor-reg) :from (:eval 0)) move-temp) (:temporary (:sc control-stack :offset nfp-save-offset) nfp-save) (:temporary (:sc any-reg :offset ocfp-offset :from (:eval 0)) ocfp) - (:temporary (:scs (interior-reg)) lip) (:ignore arg-locs args ocfp) (:generator 5 - (let ((label (gen-label)) - (cur-nfp (current-nfp-tn vop))) + (let ((cur-nfp (current-nfp-tn vop))) (when cur-nfp (store-stack-tn nfp-save cur-nfp)) (let ((callee-nfp (callee-nfp-tn callee))) (when callee-nfp (maybe-load-stack-tn callee-nfp nfp))) (maybe-load-stack-tn cfp-tn fp) - (inst compute-lra lip lip label) - (store-stack-tn (callee-return-pc-tn callee) lip) (note-this-location vop :call-site) - (inst b target) - (emit-return-pc label) - (default-unknown-values vop values nvals move-temp lip label) + (inst bl target) + (default-unknown-values vop values nvals move-temp node) (when cur-nfp (load-stack-tn cur-nfp nfp-save))))) @@ -673,11 +747,10 @@ (:info save callee target) (:ignore args save r0-temp) (:vop-var vop) + (:node-var node) (:temporary (:sc control-stack :offset nfp-save-offset) nfp-save) - (:temporary (:scs (interior-reg)) lip) (:generator 20 - (let ((label (gen-label)) - (cur-nfp (current-nfp-tn vop))) + (let ((cur-nfp (current-nfp-tn vop))) (when cur-nfp (store-stack-tn nfp-save cur-nfp)) (let ((callee-nfp (callee-nfp-tn callee))) @@ -685,13 +758,10 @@ (when callee-nfp (maybe-load-stack-tn callee-nfp nfp))) (maybe-load-stack-tn cfp-tn fp) - (inst compute-lra lip lip label) - (store-stack-tn (callee-return-pc-tn callee) lip) (note-this-location vop :call-site) - (inst b target) - (emit-return-pc label) + (inst bl target) (note-this-location vop :unknown-return) - (receive-unknown-values values-start nvals start count label lip) + (receive-unknown-values node values-start nvals start count) (when cur-nfp (load-stack-tn cur-nfp nfp-save))))) @@ -714,21 +784,16 @@ (:ignore args res save) (:vop-var vop) (:temporary (:sc control-stack :offset nfp-save-offset) nfp-save) - (:temporary (:scs (interior-reg)) lip) (:generator 5 - (let ((label (gen-label)) - (cur-nfp (current-nfp-tn vop))) + (let ((cur-nfp (current-nfp-tn vop))) (when cur-nfp (store-stack-tn nfp-save cur-nfp)) (let ((callee-nfp (callee-nfp-tn callee))) (when callee-nfp (maybe-load-stack-tn callee-nfp nfp))) (maybe-load-stack-tn cfp-tn fp) - (inst compute-lra lip lip label) - (store-stack-tn (callee-return-pc-tn callee) lip) (note-this-location vop :call-site) - (inst b target) - (emit-return-pc label) + (inst bl target) (note-this-location vop :known-return) (when cur-nfp (load-stack-tn cur-nfp nfp-save))))) @@ -741,26 +806,22 @@ ;;; registers may be tied up by the more operand. Instead, we use ;;; MAYBE-LOAD-STACK-TN. (define-vop (known-return) - (:args (old-fp :target old-fp-temp) - (return-pc :target return-pc-temp) + (:args (old-fp) + (return-pc) (vals :more t)) - (:temporary (:sc any-reg :from (:argument 0)) old-fp-temp) - (:temporary (:sc descriptor-reg :from (:argument 1)) return-pc-temp) - (:temporary (:scs (interior-reg)) lip) + (:temporary (:sc non-descriptor-reg :offset lr-offset) lr) (:move-args :known-return) (:info val-locs) - (:ignore val-locs vals) + (:ignore old-fp return-pc val-locs vals) (:vop-var vop) (:generator 6 - (maybe-load-stack-tn old-fp-temp old-fp) - (maybe-load-stack-tn return-pc-temp return-pc) (move csp-tn cfp-tn) + (loadw-pair cfp-tn ocfp-save-offset lr lra-save-offset cfp-tn) (let ((cur-nfp (current-nfp-tn vop))) (when cur-nfp (inst add nsp-tn cur-nfp (add-sub-immediate (bytes-needed-for-non-descriptor-stack-frame))))) - (move cfp-tn old-fp-temp) - (lisp-return return-pc-temp lip :known))) + (lisp-return lr :known))) ;;;; Full call: ;;; @@ -801,7 +862,7 @@ ;;; In tail call with fixed arguments, the passing locations are passed as a ;;; more arg, but there is no new-FP, since the arguments have been set up in ;;; the current frame. -(defmacro define-full-call (name named return variable) +(defmacro define-full-call (name named return variable &optional args) (aver (not (and variable (eq return :tail)))) `(define-vop (,name ,@(when (eq return :unknown) @@ -811,48 +872,54 @@ '((new-fp :scs (any-reg) :to :eval))) ,@(case named - ((nil) - '((arg-fun :target lexenv))) - (:direct) - (t - '((name :target name-pass)))) + ((nil) + '((arg-fun :target lexenv))) + (:direct) + (t + '((name :target name-pass)))) ,@(when (eq return :tail) '((old-fp) (return-pc))) - ,@(unless variable '((args :more t :scs (descriptor-reg))))) + ,@(unless variable `((args :more t ,@(unless (eq args :fixed) + '(:scs (descriptor-reg))))))) ,@(when (eq return :fixed) '((:results (values :more t)))) (:save-p ,(if (eq return :tail) :compute-only t)) - ,@(unless (or (eq return :tail) variable) - '((:move-args :full-call))) + ,@(unless (or (eq return :tail) + variable) + `((:move-args ,(if (eq args :fixed) + :fixed + :full-call)))) + (:vop-var vop) + (:node-var node) (:info ,@(unless (or variable (eq return :tail)) '(arg-locs)) ,@(unless variable '(nargs)) ,@(when (eq named :direct) '(fun)) ,@(when (eq return :fixed) '(nvals)) - step-instrumenting) + step-instrumenting + ,@(unless named + '(fun-type))) (:ignore ,@(unless (or variable (eq return :tail)) '(arg-locs)) ,@(unless variable '(args)) - ,(ecase return - (:fixed 'ocfp-temp) - (:tail 'old-fp) - (:unknown 'r0-temp))) + ,@(ecase return + (:fixed '(ocfp-temp)) + (:tail '(old-fp return-pc node)) + (:unknown '(r0-temp)))) ,@(unless (eq named :direct) `((:temporary (:sc descriptor-reg :offset lexenv-offset :from (:argument ,(if (eq return :tail) 0 1)) :to :eval) - ,(if named 'name-pass 'lexenv)) - (:temporary (:scs (descriptor-reg) :to :eval) - function))) + ,(if named 'name-pass 'lexenv)))) (:temporary (:sc any-reg :offset nargs-offset :to ,(if (eq return :fixed) @@ -865,7 +932,7 @@ `(:temporary (:sc descriptor-reg :offset ,offset :to :result) - ,name)) + ,name)) *register-arg-names* *register-arg-offsets*)) ,@(when (eq return :fixed) '((:temporary (:scs (descriptor-reg) :from :eval) move-temp) @@ -874,150 +941,133 @@ ,@(unless (eq return :tail) '((:temporary (:sc control-stack :offset nfp-save-offset) nfp-save))) - (:temporary (:scs (interior-reg)) lip) + (:temporary (:sc non-descriptor-reg :offset lr-offset) lr) (:generator ,(+ (if named 5 0) (if variable 19 1) (if (eq return :tail) 0 10) 15 (if (eq return :unknown) 25 0)) - (let* ((cur-nfp (current-nfp-tn vop)) - ,@(unless (eq return :tail) - '((lra-label (gen-label)))) - (filler - (remove nil - (list ,@(if (eq return :tail) - '(:load-nargs - (unless (location= return-pc - (make-random-tn :kind :normal - :sc (sc-or-lose 'control-stack) - :offset lra-save-offset)) - :load-return-pc) - (when cur-nfp - :frob-nfp)) - '(:load-nargs - :comp-lra - (when cur-nfp - :frob-nfp) - :load-fp)))))) - (flet ((do-next-filler () - (let* ((next (pop filler)) - (what (if (consp next) (car next) next))) - (ecase what - (:load-nargs - ,@(if variable - `((move nargs-pass csp-tn) - ;; The variable args are on the stack - ;; and become the frame, but there may - ;; be <4 args and 2 stack slots are - ;; assumed allocate on the call. So - ;; need to ensure there are at least 2 - ;; slots. This just adds 2 more. - (inst add csp-tn nargs-pass (* 2 n-word-bytes)) - (inst sub nargs-pass nargs-pass new-fp) - (inst asr nargs-pass nargs-pass (- word-shift n-fixnum-tag-bits)) - ,@(do ((arg *register-arg-names* (cddr arg)) - (i 0 (+ i 2)) - (insts)) - ((null arg) (nreverse insts)) - #.(assert (evenp register-arg-count)) - (push `(inst ldp ,(first arg) ,(second arg) - (@ new-fp ,(* i n-word-bytes))) - insts)) - (storew cfp-tn new-fp ocfp-save-offset)) - '((load-immediate-word nargs-pass (fixnumize nargs))))) - ,@(if (eq return :tail) - '((:load-return-pc - (error "RETURN-PC not in its passing location")) - (:frob-nfp - (inst add nsp-tn cur-nfp (add-sub-immediate - (bytes-needed-for-non-descriptor-stack-frame))))) - `((:comp-lra - (inst compute-lra lip lip lra-label) - (inst str lip (@ new-fp (* lra-save-offset - n-word-bytes)))) - (:frob-nfp - (store-stack-tn nfp-save cur-nfp)) - (:load-fp - (move cfp-tn new-fp)))) - ((nil))))) - (insert-step-instrumenting () - ;; Conditionally insert a conditional trap: - (when step-instrumenting - (assemble () - #-sb-thread - (load-symbol-value tmp-tn sb-impl::*stepping*) - #+sb-thread - (loadw tmp-tn thread-tn thread-stepping-slot) - (inst cbz tmp-tn step-done-label) - ;; CONTEXT-PC will be pointing here when the - ;; interrupt is handled, not after the - ;; DEBUG-TRAP. - (note-this-location vop :internal-error) - (inst brk single-step-around-trap) - STEP-DONE-LABEL)))) - (declare (ignorable #'insert-step-instrumenting)) - ,@(case named - ((t) - `((sc-case name - (descriptor-reg (move name-pass name)) - (control-stack - (load-stack-tn name-pass name) - (do-next-filler)) - (constant - (load-constant vop name name-pass) - (do-next-filler))) - (do-next-filler) - (insert-step-instrumenting))) - ((nil) - `((sc-case arg-fun - (descriptor-reg (move lexenv arg-fun)) - (control-stack - (load-stack-tn lexenv arg-fun) - (do-next-filler)) - (constant - (load-constant vop arg-fun lexenv) - (do-next-filler))) - (insert-step-instrumenting) - (loadw function lexenv closure-fun-slot - fun-pointer-lowtag) - (do-next-filler)))) - (loop - (if filler - (do-next-filler) - (return))) - ,@(ecase named - ;; raw-addr is an untagged pointer to the function, - ;; need to pair it up with the tagged pointer for the GC to see - ((t) - `((loadw function name-pass fdefn-fun-slot - other-pointer-lowtag) - (loadw lip name-pass fdefn-raw-addr-slot - other-pointer-lowtag))) - (:direct - `((inst ldr lip (@ null-tn (load-store-offset (static-fun-offset fun)))))) - ((nil) - `((inst add lip function - (- (ash simple-fun-insts-offset word-shift) - fun-pointer-lowtag))))) - - (note-this-location vop :call-site) - (inst br lip)) - - ,@(ecase return - (:fixed - '((emit-return-pc lra-label) - (default-unknown-values vop values nvals move-temp lip lra-label) - (when cur-nfp - (load-stack-tn cur-nfp nfp-save)))) - (:unknown - '((emit-return-pc lra-label) - (note-this-location vop :unknown-return) - (receive-unknown-values values-start nvals start count - lra-label lip) - (when cur-nfp - (load-stack-tn cur-nfp nfp-save)))) - (:tail)))))) + (let* ((cur-nfp (current-nfp-tn vop)) + (filler + (remove nil + (list ,@(if (eq return :tail) + '(:load-nargs + (when cur-nfp + :frob-nfp)) + '(:load-nargs + (when cur-nfp + :frob-nfp) + :load-fp)))))) + (flet ((do-next-filler () + (let* ((next (pop filler)) + (what (if (consp next) (car next) next))) + (ecase what + (:load-nargs + ,@(if variable + `((inst sub nargs-pass csp-tn new-fp) + (inst asr nargs-pass nargs-pass (- word-shift n-fixnum-tag-bits)) + ,@(do ((arg *register-arg-names* (cddr arg)) + (i 0 (+ i 2)) + (insts)) + ((null arg) (nreverse insts)) + #.(assert (evenp register-arg-count)) + (push `(inst ldp ,(first arg) ,(second arg) + (@ new-fp ,(* i n-word-bytes))) + insts)) + (storew cfp-tn new-fp ocfp-save-offset)) + '((unless (consp nargs) + (load-immediate-word nargs-pass (fixnumize nargs)))))) + ,@(if (eq return :tail) + '((:frob-nfp + (inst add nsp-tn cur-nfp (add-sub-immediate + (bytes-needed-for-non-descriptor-stack-frame))))) + `((:frob-nfp + (store-stack-tn nfp-save cur-nfp)) + (:load-fp + (move cfp-tn (cond ,@(and + (not variable) + '(((<= (if (consp nargs) + (car nargs) + nargs) register-arg-count) + csp-tn))) + (t + new-fp)))))) + ((nil))))) + (insert-step-instrumenting () + ;; Conditionally insert a conditional trap: + (when step-instrumenting + (assemble () + #-sb-thread + (load-symbol-value tmp-tn sb-impl::*stepping*) + #+sb-thread + (loadw tmp-tn thread-tn thread-stepping-slot) + (inst cbz tmp-tn step-done-label) + ;; CONTEXT-PC will be pointing here when the + ;; interrupt is handled, not after the + ;; DEBUG-TRAP. + (note-this-location vop :internal-error) + (inst brk single-step-around-trap) + STEP-DONE-LABEL)))) + (declare (ignorable #'insert-step-instrumenting)) + ,@(case named + ((t) + `((sc-case name + (descriptor-reg (move name-pass name)) + (control-stack + (load-stack-tn name-pass name) + (do-next-filler)) + (constant + (load-constant vop name name-pass) + (do-next-filler))) + (do-next-filler) + (insert-step-instrumenting))) + ((nil) + `((sc-case arg-fun + (descriptor-reg (move lexenv arg-fun)) + (control-stack + (load-stack-tn lexenv arg-fun) + (do-next-filler)) + (constant + (load-constant vop arg-fun lexenv) + (do-next-filler))) + (insert-step-instrumenting) + (do-next-filler)))) + (loop + (if filler + (do-next-filler) + (return))) + ,@(case named + ((t) + `((loadw lr name-pass fdefn-raw-addr-slot other-pointer-lowtag) + ,(if (eq return :tail) + `(inst add lr lr 4)))) + (:direct + `((inst ldr lr (@ null-tn (load-store-offset (static-fun-offset fun)))) + ,(if (eq return :tail) + `(inst add lr lr 4))))) + + (note-this-location vop :call-site) + + ,(if named + (if (eq return :tail) + `(inst br lr) + `(inst blr lr)) + (if (eq return :tail) + `(tail-call-unnamed lexenv lr fun-type) + `(call-unnamed lexenv lr fun-type)))) + + ,@(ecase return + (:fixed + '((default-unknown-values vop values nvals move-temp node) + (when cur-nfp + (load-stack-tn cur-nfp nfp-save)))) + (:unknown + '((note-this-location vop :unknown-return) + (receive-unknown-values node values-start nvals start count) + (when cur-nfp + (load-stack-tn cur-nfp nfp-save)))) + (:tail)))))) (define-full-call call nil :fixed nil) (define-full-call call-named t :fixed nil) @@ -1032,6 +1082,8 @@ (define-full-call call-variable nil :fixed t) (define-full-call multiple-call-variable nil :unknown t) +(define-full-call fixed-call-named t :fixed nil :fixed) +(define-full-call fixed-tail-call-named t :tail nil :fixed) ;;; Defined separately, since needs special code that BLT's the ;;; arguments down. (define-vop (tail-call-variable) @@ -1040,9 +1092,9 @@ (function-arg :scs (descriptor-reg) :target lexenv) (old-fp-arg :scs (any-reg) :load-if nil) (lra-arg :scs (descriptor-reg) :load-if nil)) + (:info fun-type) (:temporary (:sc any-reg :offset nl2-offset :from (:argument 0)) args) (:temporary (:sc descriptor-reg :offset lexenv-offset :from (:argument 1)) lexenv) - (:temporary (:scs (interior-reg)) lip) (:ignore old-fp-arg lra-arg) (:vop-var vop) (:generator 75 @@ -1054,18 +1106,59 @@ (when cur-nfp (inst add nsp-tn cur-nfp (add-sub-immediate (bytes-needed-for-non-descriptor-stack-frame))))) - (load-inline-constant tmp-tn '(:fixup tail-call-variable :assembly-routine) lip) + (load-inline-constant tmp-tn + (if (eq fun-type :function) + '(:fixup tail-call-variable :assembly-routine) + '(:fixup tail-call-callable-variable :assembly-routine))) (inst br tmp-tn))) + +;;; Invoke the function-designator FUN. +(defun tail-call-unnamed (lexenv lr type) + (case type + (:symbol + (load-inline-constant tmp-tn '(:fixup tail-call-symbol :assembly-routine)) + (inst br tmp-tn)) + (t + (assemble () + (when (eq type :designator) + (inst and tmp-tn lexenv lowtag-mask) + (inst cmp tmp-tn fun-pointer-lowtag) + (inst b :eq call) + (load-inline-constant tmp-tn '(:fixup tail-call-symbol :assembly-routine)) + (inst br tmp-tn)) + call + (loadw lr lexenv closure-fun-slot fun-pointer-lowtag) + (inst add lr lr 4) + (inst br lr))))) + +(defun call-unnamed (lexenv lr type) + (case type + (:symbol + (load-inline-constant tmp-tn '(:fixup call-symbol :assembly-routine)) + (inst blr tmp-tn)) + (t + (assemble () + (when (eq type :designator) + (inst and tmp-tn lexenv lowtag-mask) + (inst cmp tmp-tn fun-pointer-lowtag) + (inst b :eq call) + (load-inline-constant tmp-tn '(:fixup call-symbol :assembly-routine)) + (inst blr tmp-tn) + (inst b ret)) + call + (loadw lr lexenv closure-fun-slot fun-pointer-lowtag) + (inst blr lr) + ret)))) ;;;; Unknown values return: ;;; Return a single value using the unknown-values convention. (define-vop (return-single) - (:args (old-fp :scs (any-reg) :to :eval) - (return-pc :scs (descriptor-reg)) + (:args (old-fp) + (return-pc) (value)) - (:temporary (:scs (interior-reg)) lip) - (:ignore value) + (:temporary (:sc non-descriptor-reg :offset lr-offset) lr) + (:ignore value old-fp return-pc) (:vop-var vop) (:generator 6 ;; Clear the number stack. @@ -1073,12 +1166,14 @@ (when cur-nfp (inst add nsp-tn cur-nfp (add-sub-immediate (bytes-needed-for-non-descriptor-stack-frame))))) - ;; Clear the control stack, and restore the frame pointer. + ;; Interrupts leave two words of space for the new frame, so it's safe + ;; to deallocate the frame before accessing OCFP/LR. (move csp-tn cfp-tn) - (move cfp-tn old-fp) + (loadw-pair cfp-tn ocfp-save-offset lr lra-save-offset cfp-tn) + ;; Clear the control stack, and restore the frame pointer. ;; Out of here. - (lisp-return return-pc lip :single-value))) + (lisp-return lr :single-value))) ;;; Do unknown-values return of a fixed number of values. The Values are ;;; required to be set up in the standard passing locations. Nvals is the @@ -1094,16 +1189,16 @@ ;;; current frame.) (define-vop (return) (:args - (old-fp :scs (any-reg)) - (return-pc :scs (descriptor-reg) :to (:eval 1)) + (old-fp) + (return-pc) (values :more t)) - (:ignore values) + (:ignore values old-fp return-pc) (:info nvals) (:temporary (:sc descriptor-reg :offset r0-offset :from (:eval 0)) r0) (:temporary (:sc descriptor-reg :offset r1-offset :from (:eval 0)) r1) (:temporary (:sc descriptor-reg :offset r2-offset :from (:eval 0)) r2) (:temporary (:sc descriptor-reg :offset r3-offset :from (:eval 0)) r3) - (:temporary (:sc interior-reg) lip) + (:temporary (:sc non-descriptor-reg :offset lr-offset) lr) (:temporary (:sc any-reg :offset nargs-offset) nargs) (:temporary (:sc any-reg :offset ocfp-offset) val-ptr) (:vop-var vop) @@ -1116,15 +1211,15 @@ (cond ((= nvals 1) ;; Clear the control stack, and restore the frame pointer. (move csp-tn cfp-tn) - (move cfp-tn old-fp) + (loadw-pair cfp-tn ocfp-save-offset lr lra-save-offset cfp-tn) ;; Out of here. - (lisp-return return-pc lip :single-value)) + (lisp-return lr :single-value)) (t ;; Establish the values pointer. (move val-ptr cfp-tn) ;; restore the frame pointer and clear as much of the control ;; stack as possible. - (move cfp-tn old-fp) + (loadw-pair cfp-tn ocfp-save-offset lr lra-save-offset cfp-tn) (inst add csp-tn val-ptr (add-sub-immediate (* nvals n-word-bytes))) ;; Establish the values count. (load-immediate-word nargs (fixnumize nvals)) @@ -1133,7 +1228,7 @@ (dolist (reg (subseq (list r0 r1 r2 r3) nvals)) (move reg null-tn))) ;; And away we go. - (lisp-return return-pc lip :multiple-values))))) + (lisp-return lr :multiple-values))))) ;;; Do unknown-values return of an arbitrary number of values (passed ;;; on the stack.) We check for the common case of a single return @@ -1143,18 +1238,17 @@ (define-vop (return-multiple) (:args (old-fp-arg :scs (any-reg) :to (:eval 1)) - (lra-arg :scs (descriptor-reg) :to (:eval 1)) + (lra-arg) (vals-arg :scs (any-reg) :target vals) (nvals-arg :scs (any-reg) :target nvals)) (:temporary (:sc any-reg :offset nl2-offset :from (:argument 0)) old-fp) - (:temporary (:sc descriptor-reg :offset r6-offset :from (:argument 1)) lra) (:temporary (:sc any-reg :offset nl1-offset :from (:argument 2)) vals) (:temporary (:sc any-reg :offset nargs-offset :from (:argument 3)) nvals) (:temporary (:sc descriptor-reg :offset r0-offset) r0) - (:temporary (:sc interior-reg) lip) + (:temporary (:sc non-descriptor-reg :offset lr-offset) lr) (:vop-var vop) (:generator 13 - (move lra lra-arg) + (maybe-load-stack-tn lr lra-arg) ;; Clear the number stack. (let ((cur-nfp (current-nfp-tn vop))) (when cur-nfp @@ -1169,13 +1263,13 @@ (inst ldr r0 (@ vals-arg)) (move csp-tn cfp-tn) (move cfp-tn old-fp-arg) - (lisp-return lra lip :single-value) + (lisp-return lr :single-value) NOT-SINGLE (move old-fp old-fp-arg) (move vals vals-arg) (move nvals nvals-arg) - (load-inline-constant tmp-tn '(:fixup return-multiple :assembly-routine) lip) + (load-inline-constant tmp-tn '(:fixup return-multiple :assembly-routine)) (inst br tmp-tn))) ;;; Single-stepping @@ -1196,3 +1290,4 @@ ;; single-step-before-trap. (inst brk single-step-before-trap) DONE)) + diff --git a/src/compiler/arm64/cell.lisp b/src/compiler/arm64/cell.lisp index 99ac038c28..feb0e0c520 100644 --- a/src/compiler/arm64/cell.lisp +++ b/src/compiler/arm64/cell.lisp @@ -24,37 +24,38 @@ (define-vop (set-slot) (:args (object :scs (descriptor-reg)) - (value :scs (descriptor-reg any-reg))) + (value :scs (descriptor-reg any-reg zero))) (:info name offset lowtag) (:ignore name) (:results) (:generator 1 (storew value object offset lowtag))) -(define-vop (init-slot set-slot) - (:info name dx-p offset lowtag) - (:ignore name dx-p)) - (define-vop (compare-and-swap-slot) (:args (object :scs (descriptor-reg)) (old :scs (descriptor-reg any-reg)) (new :scs (descriptor-reg any-reg))) (:info name offset lowtag) (:ignore name) - (:temporary (:sc interior-reg) lip) + (:temporary (:sc non-descriptor-reg) lip) (:results (result :scs (descriptor-reg any-reg) :from :load)) (:generator 5 - (inst dsb) (inst add-sub lip object (- (* offset n-word-bytes) lowtag)) - LOOP - (inst ldxr result lip) - (inst cmp result old) - (inst b :ne EXIT) - (inst stlxr tmp-tn new lip) - (inst cbnz tmp-tn LOOP) - EXIT - (inst clrex) - (inst dmb))) + (cond ((member :arm-v8.1 *backend-subfeatures*) + (move result old) + (inst casal result new lip)) + (t + (assemble () + (inst dsb) + LOOP + (inst ldxr result lip) + (inst cmp result old) + (inst b :ne EXIT) + (inst stlxr tmp-tn new lip) + (inst cbnz tmp-tn LOOP) + EXIT + (inst clrex) + (inst dmb)))))) ;;;; Symbol hacking VOPs: @@ -66,74 +67,91 @@ (:policy :fast-safe) (:vop-var vop) (:save-p :compute-only)) -;;; Like CHECKED-CELL-REF, only we are a predicate to see if the cell is bound. -(define-vop (boundp-frob) - (:args (object :scs (descriptor-reg))) - (:conditional) - (:info target not-p) - (:policy :fast-safe) - (:temporary (:scs (descriptor-reg)) value)) -;;; With Symbol-Value, we check that the value isn't the trap object. So -;;; Symbol-Value of NIL is NIL. +;;; With Symbol-Value, we check that the value isn't the trap object. #+sb-thread (progn + (eval-when (:compile-toplevel) + ;; Assert that "CMN reg, 1" is the same as "CMP reg, NO-TLS-VALUE-MARKER" + (aver (= (ldb (byte 64 0) -1) no-tls-value-marker))) + (defmacro compare-to-no-tls-value-marker (x) `(inst cmn ,x 1)) (define-vop (set) - (:args (object :scs (descriptor-reg)) - (value :scs (descriptor-reg any-reg))) + (:args (object :scs (descriptor-reg) + :load-if (not (and (sc-is object constant) + (symbol-always-has-tls-value-p (tn-value object))))) + (value :scs (descriptor-reg any-reg zero))) (:temporary (:sc any-reg) tls-index) (:generator 4 - (inst ldr (32-bit-reg tls-index) (tls-index-of object)) - (inst ldr tmp-tn (@ thread-tn tls-index)) - (inst cmp tmp-tn no-tls-value-marker-widetag) - (inst b :ne LOCAL) - (storew value object symbol-value-slot other-pointer-lowtag) - (inst b DONE) - LOCAL - (inst str value (@ thread-tn tls-index)) - DONE)) + (sc-case object + (constant + (inst str value (@ thread-tn (make-fixup (tn-value object) :symbol-tls-index)))) + (t + (assemble () + (inst ldr (32-bit-reg tls-index) (tls-index-of object)) + (inst ldr tmp-tn (@ thread-tn tls-index)) + (compare-to-no-tls-value-marker tmp-tn) + (inst b :ne LOCAL) + (storew value object symbol-value-slot other-pointer-lowtag) + (inst b DONE) + LOCAL + (inst str value (@ thread-tn tls-index)) + DONE))))) (define-vop (symbol-value checked-cell-ref) - (:translate symeval) + (:translate symbol-value) + (:args (symbol :scs (descriptor-reg) :to :save + :load-if (not (and (sc-is symbol constant) + (or (symbol-always-has-tls-value-p (tn-value symbol)) + (symbol-always-has-tls-index-p (tn-value symbol))))))) + (:args-var symbol-tn-ref) (:temporary (:sc any-reg) tls-index) (:variant-vars check-boundp) (:variant t) (:generator 9 - (inst ldr (32-bit-reg tls-index) (tls-index-of object)) - (inst ldr value (@ thread-tn tls-index)) - (inst cmp value no-tls-value-marker-widetag) - (inst b :ne LOCAL) - (loadw value object symbol-value-slot other-pointer-lowtag) - LOCAL + (let* ((known-symbol-p (sc-is symbol constant)) + (known-symbol (and known-symbol-p (tn-value symbol))) + (fixup (and known-symbol + (make-fixup known-symbol :symbol-tls-index)))) + (cond + ((symbol-always-has-tls-value-p known-symbol) + (inst ldr value (@ thread-tn fixup))) + (t + (cond + (known-symbol ; e.g. CL:*PRINT-BASE* + ;; Known nonzero TLS index, but possibly no per-thread value. + ;; The TLS value and global value can be loaded independently. + (inst ldr value (@ thread-tn fixup))) + (t + (inst ldr (32-bit-reg tls-index) (tls-index-of symbol)) + (inst ldr value (@ thread-tn tls-index)))) + + (assemble () + (compare-to-no-tls-value-marker value) + (inst b :ne LOCAL) + (when known-symbol + (load-constant vop symbol (setf symbol (tn-ref-load-tn symbol-tn-ref)))) + (loadw value symbol symbol-value-slot other-pointer-lowtag) + LOCAL)))) + (when check-boundp - (let ((err-lab (generate-error-code vop 'unbound-symbol-error object))) - (inst cmp value unbound-marker-widetag) - (inst b :eq err-lab))))) + (assemble () + (let* ((*location-context* (make-restart-location RETRY value)) + (err-lab (generate-error-code vop 'unbound-symbol-error symbol))) + (inst cmp value unbound-marker-widetag) + (inst b :eq err-lab)) + RETRY)))) (define-vop (fast-symbol-value symbol-value) (:policy :fast) (:variant nil) - (:variant-cost 5)) - - (define-vop (boundp boundp-frob) - (:translate boundp) - (:temporary (:sc any-reg) tls-index) - (:generator 9 - (inst ldr (32-bit-reg tls-index) (tls-index-of object)) - (inst ldr value (@ thread-tn tls-index)) - (inst cmp value no-tls-value-marker-widetag) - (inst b :ne LOCAL) - (loadw value object symbol-value-slot other-pointer-lowtag) - LOCAL - (inst cmp value unbound-marker-widetag) - (inst b (if not-p :eq :ne) target)))) + (:variant-cost 5))) #-sb-thread (progn (define-vop (set cell-set) (:variant symbol-value-slot other-pointer-lowtag)) (define-vop (symbol-value checked-cell-ref) - (:translate symeval) + (:translate symbol-value) (:generator 9 (loadw value object symbol-value-slot other-pointer-lowtag) (let ((err-lab (generate-error-code vop 'unbound-symbol-error object))) @@ -142,14 +160,30 @@ (define-vop (fast-symbol-value cell-ref) (:variant symbol-value-slot other-pointer-lowtag) (:policy :fast) - (:translate symeval)) + (:translate symbol-value))) - (define-vop (boundp boundp-frob) - (:translate boundp) - (:generator 9 +(define-vop (boundp) + (:args (object :scs (descriptor-reg))) + (:conditional) + (:info target not-p) + (:policy :fast-safe) + (:temporary (:scs (descriptor-reg)) value) + (:translate boundp) + #+sb-thread + (:generator 9 + (inst ldr (32-bit-reg value) (tls-index-of object)) + (inst ldr value (@ thread-tn value)) + (compare-to-no-tls-value-marker value) + (inst b :ne LOCAL) (loadw value object symbol-value-slot other-pointer-lowtag) + LOCAL (inst cmp value unbound-marker-widetag) - (inst b (if not-p :eq :ne) target)))) + (inst b (if not-p :eq :ne) target)) + #-sb-thread + (:generator 9 + (loadw value object symbol-value-slot other-pointer-lowtag) + (inst cmp value unbound-marker-widetag) + (inst b (if not-p :eq :ne) target))) (define-vop (%set-symbol-global-value cell-set) (:variant symbol-value-slot other-pointer-lowtag)) @@ -157,11 +191,11 @@ (define-vop (fast-symbol-global-value cell-ref) (:variant symbol-value-slot other-pointer-lowtag) (:policy :fast) - (:translate sym-global-val)) + (:translate symbol-global-value)) (define-vop (symbol-global-value) (:policy :fast-safe) - (:translate sym-global-val) + (:translate symbol-global-value) (:args (object :scs (descriptor-reg) :to (:result 1))) (:results (value :scs (descriptor-reg any-reg))) (:vop-var vop) @@ -176,7 +210,7 @@ (:policy :fast-safe) (:translate symbol-hash) (:args (symbol :scs (descriptor-reg))) - (:temporary (:scs (non-descriptor-reg)) temp) + (:args-var args) (:results (res :scs (any-reg))) (:result-types positive-fixnum) (:generator 2 @@ -184,8 +218,29 @@ ;; car slot, so we have to strip off the fixnum-tag-mask to make sure ;; it is a fixnum. The lowtag selection magic that is required to ;; ensure this is explained in the comment in objdef.lisp - (loadw temp symbol symbol-hash-slot other-pointer-lowtag) - (inst and res temp (bic-mask fixnum-tag-mask)))) + (loadw res symbol symbol-hash-slot other-pointer-lowtag) + (unless (not-nil-tn-ref-p args) + (inst and res res (bic-mask fixnum-tag-mask))))) + +(define-vop () + (:args (symbol :scs (descriptor-reg))) + (:results (result :scs (unsigned-reg))) + (:result-types positive-fixnum) + (:translate sb-impl::symbol-package-id) + (:policy :fast-safe) + (:generator 1 + #.(assert (= sb-impl::package-id-bits 16)) + (inst ldrh result (@ symbol (+ (ash symbol-name-slot word-shift) + (- other-pointer-lowtag) + 6))))) ; little-endian +(define-vop () + (:policy :fast-safe) + (:translate symbol-name) + (:args (symbol :scs (descriptor-reg))) + (:results (result :scs (descriptor-reg))) + (:generator 5 + (loadw tmp-tn symbol symbol-name-slot other-pointer-lowtag) + (inst and result tmp-tn (1- (ash 1 sb-impl::symbol-name-bits))))) (define-vop (%compare-and-swap-symbol-value) (:translate %compare-and-swap-symbol-value) @@ -195,7 +250,7 @@ (:results (result :scs (descriptor-reg any-reg) :from :load)) #+sb-thread (:temporary (:sc any-reg) tls-index) - (:temporary (:sc interior-reg) lip) + (:temporary (:sc non-descriptor-reg) lip) (:policy :fast-safe) (:vop-var vop) (:generator 15 @@ -210,7 +265,7 @@ (inst str new (@ thread-tn tls-index)) DONT-STORE-TLS - (inst cmp result no-tls-value-marker-widetag) + (compare-to-no-tls-value-marker result) (inst b :ne CHECK-UNBOUND)) (inst add-sub lip symbol (- (* symbol-value-slot n-word-bytes) other-pointer-lowtag)) @@ -228,6 +283,40 @@ (inst dmb) (inst cmp result unbound-marker-widetag) (inst b :eq (generate-error-code vop 'unbound-symbol-error symbol)))) + +(define-vop (%compare-and-swap-symbol-value-v8.1) + (:translate %compare-and-swap-symbol-value) + (:args (symbol :scs (descriptor-reg)) + (old :scs (descriptor-reg any-reg)) + (new :scs (descriptor-reg any-reg))) + (:results (result :scs (descriptor-reg any-reg) :from :load)) + #+sb-thread + (:temporary (:sc any-reg) tls-index) + (:temporary (:sc non-descriptor-reg) lip) + (:policy :fast-safe) + (:vop-var vop) + (:guard (member :arm-v8.1 *backend-subfeatures*)) + (:generator 14 + #+sb-thread + (assemble () + (inst ldr (32-bit-reg tls-index) (tls-index-of symbol)) + ;; Thread-local area, no synchronization needed. + (inst ldr result (@ thread-tn tls-index)) + (inst cmp result old) + (inst b :ne DONT-STORE-TLS) + (inst str new (@ thread-tn tls-index)) + DONT-STORE-TLS + + (compare-to-no-tls-value-marker result) + (inst b :ne CHECK-UNBOUND)) + (inst add-sub lip symbol (- (* symbol-value-slot n-word-bytes) + other-pointer-lowtag)) + (move result old) + (inst casal result new lip) + CHECK-UNBOUND + (inst cmp result unbound-marker-widetag) + (inst b :eq (generate-error-code vop 'unbound-symbol-error symbol)))) + ;;;; Fdefinition (fdefn) objects. @@ -254,7 +343,7 @@ (:translate (setf fdefn-fun)) (:args (function :scs (descriptor-reg) :target result) (fdefn :scs (descriptor-reg))) - (:temporary (:scs (interior-reg)) lip) + (:temporary (:scs (non-descriptor-reg)) lip) (:temporary (:scs (non-descriptor-reg)) type) (:results (result :scs (descriptor-reg))) (:generator 38 @@ -263,7 +352,7 @@ (load-type type function (- fun-pointer-lowtag)) (inst cmp type simple-fun-widetag) (inst b :eq SIMPLE-FUN) - (load-inline-constant lip '(:fixup closure-tramp :assembly-routine) lip) + (load-inline-constant lip '(:fixup closure-tramp :assembly-routine)) SIMPLE-FUN (storew lip fdefn fdefn-raw-addr-slot other-pointer-lowtag) (storew function fdefn fdefn-fun-slot other-pointer-lowtag) @@ -272,16 +361,12 @@ (define-vop (fdefn-makunbound) (:policy :fast-safe) (:translate fdefn-makunbound) - (:args (fdefn :scs (descriptor-reg) :target result)) + (:args (fdefn :scs (descriptor-reg))) (:temporary (:scs (non-descriptor-reg)) temp) - (:temporary (:scs (interior-reg)) lip) - (:results (result :scs (descriptor-reg))) (:generator 38 (storew null-tn fdefn fdefn-fun-slot other-pointer-lowtag) - (load-inline-constant temp '(:fixup undefined-tramp :assembly-routine) lip) - (storew temp fdefn fdefn-raw-addr-slot other-pointer-lowtag) - (move result fdefn))) - + (load-inline-constant temp '(:fixup undefined-tramp :assembly-routine)) + (storew temp fdefn fdefn-raw-addr-slot other-pointer-lowtag))) ;;;; Binding and Unbinding. @@ -292,30 +377,43 @@ #+sb-thread (progn (define-vop (dynbind) - (:args (value :scs (any-reg descriptor-reg) :to :save) - (symbol :scs (descriptor-reg))) - (:temporary (:sc descriptor-reg) value-temp) - (:temporary (:sc descriptor-reg :offset r0-offset :from (:argument 1)) alloc-tls-symbol) + (:args (value :scs (any-reg descriptor-reg zero) :to :save) + (symbol :scs (descriptor-reg) + :load-if (not (and (sc-is symbol constant) + (or (symbol-always-has-tls-value-p (tn-value symbol)) + (symbol-always-has-tls-index-p (tn-value symbol))))) + :target alloc-tls-symbol)) + (:temporary (:sc descriptor-reg :offset r8-offset :from (:argument 1)) alloc-tls-symbol) (:temporary (:sc non-descriptor-reg :offset nl0-offset) tls-index) (:temporary (:sc non-descriptor-reg :offset nl1-offset) free-tls-index) - (:temporary (:sc interior-reg) lip) + (:temporary (:sc non-descriptor-reg :offset lr-offset) lr) (:ignore free-tls-index) (:temporary (:scs (any-reg)) bsp) (:generator 5 (load-binding-stack-pointer bsp) - (inst ldr (32-bit-reg tls-index) (tls-index-of symbol)) (inst add bsp bsp (* binding-size n-word-bytes)) (store-binding-stack-pointer bsp) - (inst cbnz (32-bit-reg tls-index) TLS-INDEX-VALID) - (move alloc-tls-symbol symbol) - (load-inline-constant value-temp '(:fixup alloc-tls-index :assembly-routine) lip) - (inst blr value-temp) - TLS-INDEX-VALID - - (inst ldr value-temp (@ thread-tn tls-index)) - (inst stp value-temp tls-index (@ bsp (* (- binding-value-slot binding-size) - n-word-bytes))) - (inst str value (@ thread-tn tls-index)))) + (let* ((known-symbol-p (sc-is symbol constant)) + (known-symbol (and known-symbol-p (tn-value symbol))) + (tls-index-reg tls-index) + (tls-index (if known-symbol + (make-fixup known-symbol :symbol-tls-index) + tls-index))) + (assemble () + (cond (known-symbol + (inst movz tls-index-reg tls-index)) + (t + (inst ldr (32-bit-reg tls-index) (tls-index-of symbol)) + (inst cbnz (32-bit-reg tls-index) TLS-INDEX-VALID) + (move alloc-tls-symbol symbol) + (load-inline-constant lr '(:fixup alloc-tls-index :assembly-routine)) + (inst blr lr))) + TLS-INDEX-VALID + (inst ldr alloc-tls-symbol (@ thread-tn tls-index)) + (inst stp alloc-tls-symbol tls-index-reg + (@ bsp (* (- binding-value-slot binding-size) + n-word-bytes))) + (inst str value (@ thread-tn tls-index)))))) (define-vop (unbind-n) (:info symbols) @@ -407,9 +505,9 @@ closure-info-offset fun-pointer-lowtag (descriptor-reg any-reg) * %closure-index-ref) -(define-full-setter set-funcallable-instance-info * - funcallable-instance-info-offset fun-pointer-lowtag - (descriptor-reg any-reg) * %set-funcallable-instance-info) +(define-full-setter %closure-index-set * + closure-info-offset fun-pointer-lowtag + (descriptor-reg any-reg) * %closure-index-set) (define-full-reffer funcallable-instance-info * funcallable-instance-info-offset fun-pointer-lowtag @@ -466,14 +564,65 @@ (:translate %instance-cas) (:variant instance-slots-offset instance-pointer-lowtag) (:arg-types instance tagged-num * *)) +(define-vop (%raw-instance-cas/word %instance-cas) + (:args (object) + (index) + (old-value :scs (unsigned-reg)) + (new-value :scs (unsigned-reg))) + (:arg-types * tagged-num unsigned-num unsigned-num) + (:results (result :scs (unsigned-reg) :from :load)) + (:result-types unsigned-num) + (:translate %raw-instance-cas/word)) + +(define-vop (%raw-instance-cas/signed-word %instance-cas) + (:args (object) + (index) + (old-value :scs (signed-reg)) + (new-value :scs (signed-reg))) + (:arg-types * tagged-num signed-num signed-num) + (:results (result :scs (signed-reg) :from :load)) + (:result-types signed-num) + (:translate %raw-instance-cas/signed-word)) + ;;;; Code object frobbing. (define-full-reffer code-header-ref * 0 other-pointer-lowtag (descriptor-reg any-reg) * code-header-ref) -(define-full-setter code-header-set * 0 other-pointer-lowtag - (descriptor-reg any-reg) * code-header-set) +#-darwin-jit +(define-vop (code-header-set) + (:translate code-header-set) + (:policy :fast-safe) + (:args (object :scs (descriptor-reg)) + (index :scs (any-reg)) + (value :scs (any-reg descriptor-reg))) + (:arg-types * tagged-num *) + (:temporary (:scs (non-descriptor-reg)) temp card) + (:temporary (:sc non-descriptor-reg) pa-flag) + (:generator 10 + (load-inline-constant temp `(:fixup "gc_card_table_mask" :foreign-dataref)) + (inst ldr temp (@ temp)) + (inst ldr (32-bit-reg temp) (@ temp)) ; 4-byte int + (pseudo-atomic (pa-flag) + ;; Compute card mark index + (inst lsr card object gencgc-card-shift) + (inst and card card temp) + ;; Load mark table base + (load-inline-constant temp `(:fixup "gc_card_mark" :foreign-dataref)) + (inst ldr temp (@ temp)) + (inst ldr temp (@ temp)) + ;; Touch the card mark byte. + (inst strb null-tn (@ temp card)) + ;; set 'written' flag in the code header + ;; If two threads get here at the same time, they'll write the same byte. + (let ((byte (- #+big-endian 4 #+little-endian 3 other-pointer-lowtag))) + (inst ldrb temp (@ object byte)) + (inst orr temp temp #x40) + (inst strb temp (@ object byte))) + (inst lsl temp index (- word-shift n-fixnum-tag-bits)) + (inst sub temp temp other-pointer-lowtag) + (inst str value (@ object temp))))) ;;;; raw instance slot accessors @@ -497,11 +646,9 @@ (inst ,instruction value (@ object offset)))) ,@(when move-result `((,move-macro result value)))))) - (let ((ref-vop (symbolicate "RAW-INSTANCE-REF/" name)) - (set-vop (symbolicate "RAW-INSTANCE-SET/" name))) `(progn - (define-vop (,ref-vop) - (:translate ,(symbolicate "%" ref-vop)) + (define-vop () + (:translate ,(symbolicate "%RAW-INSTANCE-REF/" name)) (:policy :fast-safe) (:args (object :scs (descriptor-reg)) (index :scs (any-reg immediate))) @@ -510,17 +657,15 @@ (:result-types ,value-primtype) (:temporary (:scs (non-descriptor-reg)) offset) (:generator 5 ,@(emit-generator 'ldr nil))) - (define-vop (,set-vop) - (:translate ,(symbolicate "%" set-vop)) + (define-vop () + (:translate ,(symbolicate "%RAW-INSTANCE-SET/" name)) (:policy :fast-safe) (:args (object :scs (descriptor-reg)) (index :scs (any-reg immediate)) - (value :scs (,value-sc) :target result)) + (value :scs (,value-sc))) (:arg-types * positive-fixnum ,value-primtype) - (:results (result :scs (,value-sc))) - (:result-types ,value-primtype) (:temporary (:scs (non-descriptor-reg)) offset) - (:generator 5 ,@(emit-generator 'str t)))))))) + (:generator 5 ,@(emit-generator 'str nil))))))) (define-raw-slot-vops word unsigned-num unsigned-reg) (define-raw-slot-vops signed-word signed-num signed-reg) (define-raw-slot-vops single single-float single-reg @@ -540,7 +685,7 @@ (diff :scs (unsigned-reg))) (:arg-types * positive-fixnum unsigned-num) (:temporary (:sc non-descriptor-reg) sum) - (:temporary (:sc interior-reg) lip) + (:temporary (:sc non-descriptor-reg) lip) (:results (result :scs (unsigned-reg) :from :load)) (:result-types unsigned-num) (:generator 4 @@ -556,3 +701,22 @@ (inst stlxr tmp-tn sum lip) (inst cbnz tmp-tn LOOP) (inst dmb))) + +(define-vop (raw-instance-atomic-incf/word-v8.1) + (:translate %raw-instance-atomic-incf/word) + (:policy :fast-safe) + (:args (object :scs (descriptor-reg)) + (index :scs (any-reg)) + (diff :scs (unsigned-reg))) + (:arg-types * positive-fixnum unsigned-num) + (:temporary (:sc non-descriptor-reg) lip) + (:results (result :scs (unsigned-reg) :from :load)) + (:result-types unsigned-num) + (:guard (member :arm-v8.1 *backend-subfeatures*)) + (:generator 3 + (inst add lip object (lsl index (- word-shift n-fixnum-tag-bits))) + (inst add lip lip (- (* instance-slots-offset + n-word-bytes) + instance-pointer-lowtag)) + + (inst ldaddal diff result lip))) diff --git a/src/compiler/arm64/char.lisp b/src/compiler/arm64/char.lisp index e201d31437..9d36f987d7 100644 --- a/src/compiler/arm64/char.lisp +++ b/src/compiler/arm64/char.lisp @@ -73,7 +73,7 @@ (define-vop (char-code) (:translate char-code) (:policy :fast-safe) - (:args (ch :scs (character-reg) :target res)) + (:args (ch :scs (character-reg))) (:arg-types character) (:results (res :scs (any-reg))) (:result-types positive-fixnum) @@ -83,7 +83,7 @@ (define-vop (code-char) (:translate code-char) (:policy :fast-safe) - (:args (code :scs (any-reg) :target res)) + (:args (code :scs (any-reg))) (:arg-types positive-fixnum) (:results (res :scs (character-reg))) (:result-types character) @@ -113,7 +113,7 @@ (defun char-immediate-p (char) (and (characterp char) - (add-sub-immediate-p (sb-xc:char-code char)))) + (add-sub-immediate-p (char-code char)))) (define-vop (character-compare/c) (:args (x :scs (character-reg))) @@ -122,7 +122,7 @@ (:policy :fast-safe) (:note "inline constant comparison") (:generator 2 - (inst cmp x (sb-xc:char-code y)))) + (inst cmp x (char-code y)))) (define-vop (fast-char=/character/c character-compare/c) (:translate char=) @@ -167,3 +167,29 @@ (:policy :fast-safe) (:generator 2 (inst cmp value base-char-code-limit))) + +(defoptimizer (sb-c::vop-optimize move-to-character) (vop) + (when (sb-c:next-vop-is vop 'char-code) + (sb-c:replace-vops 2 vop 'tagged-char-code))) + +;;; Exploit the fact that the MSB of character-widetag is 0 and that n-fixnum-tag-bits is 1. +(eval-when (:compile-toplevel) + (assert (not (logbitp 7 character-widetag)))) +(define-vop (tagged-char-code) + (:args (x :scs (any-reg descriptor-reg))) + (:results (y :scs (any-reg descriptor-reg))) + (:note "character untagging") + (:generator 1 + (inst lsr y x (- n-widetag-bits n-fixnum-tag-bits)))) + +(defoptimizer (sb-c::vop-optimize code-char) (vop) + (when (sb-c:next-vop-is vop 'move-from-character) + (sb-c:replace-vops 2 vop 'tagged-code-char))) + +(define-vop (tagged-code-char) + (:args (x :scs (any-reg descriptor-reg))) + (:results (y :scs (any-reg descriptor-reg))) + (:note "character tagging") + (:generator 1 + (inst lsl y x (- n-widetag-bits n-fixnum-tag-bits)) + (inst add y y character-widetag))) diff --git a/src/compiler/arm64/debug.lisp b/src/compiler/arm64/debug.lisp index c065c0edb6..bb2c671d46 100644 --- a/src/compiler/arm64/debug.lisp +++ b/src/compiler/arm64/debug.lisp @@ -19,7 +19,7 @@ (:generator 1 (move res csp-tn))) -(define-vop () +(define-vop (current-fp-sap) (:translate current-fp) (:policy :fast-safe) (:results (res :scs (sap-reg))) @@ -45,15 +45,12 @@ (:policy :fast-safe) (:args (sap :scs (sap-reg)) (offset :scs (any-reg) :target temp) - (value :scs (descriptor-reg) :target result)) + (value :scs (descriptor-reg))) (:arg-types system-area-pointer positive-fixnum *) (:temporary (:scs (any-reg)) temp) - (:results (result :scs (descriptor-reg))) - (:result-types *) (:generator 5 (inst lsl temp offset (- word-shift n-fixnum-tag-bits)) - (inst str value (@ sap temp)) - (move result value))) + (inst str value (@ sap temp)))) (define-vop (code-from-mumble) (:policy :fast-safe) @@ -72,10 +69,6 @@ (inst sub code thing temp) DONE)) -(define-vop (code-from-lra code-from-mumble) - (:translate sb-di::lra-code-header) - (:variant other-pointer-lowtag)) - (define-vop (code-from-fun code-from-mumble) (:translate sb-di::fun-code-header) (:variant fun-pointer-lowtag)) diff --git a/src/compiler/arm64/float.lisp b/src/compiler/arm64/float.lisp index e275496dba..b9e669a144 100644 --- a/src/compiler/arm64/float.lisp +++ b/src/compiler/arm64/float.lisp @@ -28,6 +28,24 @@ (define-move-fun (store-double 2) (vop x y) ((double-reg) (double-stack)) (storew x (current-nfp-tn vop) (tn-offset y))) + +(define-move-fun (load-fp-immediate 1) (vop x y) + ((single-immediate) (single-reg) + (double-immediate) (double-reg)) + (let ((x (tn-value x))) + (cond ((or (eql x $0f0) + (eql x $0d0)) + (inst fmov y zr-tn)) + ((encode-fp-immediate x) + (inst fmov y x)) + ((load-immediate-word tmp-tn (if (double-float-p x) + (double-float-bits x) + (single-float-bits x)) + t) + (inst fmov y tmp-tn)) + (t + (load-inline-constant y x))))) + ;;;; Move VOPs: @@ -63,15 +81,13 @@ (:args (x :scs (double-reg) :to :save)) (:results (y)) (:note "float to pointer coercion") - (:temporary (:sc non-descriptor-reg) flag) - (:temporary (:scs (interior-reg)) lip) + (:temporary (:scs (non-descriptor-reg) :offset lr-offset) lr) (:results (y :scs (descriptor-reg))) (:generator 13 - (with-fixed-allocation (y flag - double-float-widetag - double-float-value-slot - :lip lip) - (storew x y double-float-value-slot other-pointer-lowtag)))) + (with-fixed-allocation (y lr + double-float-widetag + double-float-value-slot) + (storew x y double-float-value-slot other-pointer-lowtag)))) (define-move-vop move-from-double :move (double-reg) (descriptor-reg)) @@ -144,7 +160,7 @@ (:results (y :scs (complex-single-reg) :load-if (not (location= x y)))) (:note "complex single float move") (:generator 0 - (inst s-mov y x))) + (move-complex-double y x))) (define-move-vop complex-single-move :move (complex-single-reg) (complex-single-reg)) @@ -154,7 +170,7 @@ (:results (y :scs (complex-double-reg) :load-if (not (location= x y)))) (:note "complex double float move") (:generator 0 - (inst s-mov y x))) + (move-complex-double y x))) (define-move-vop complex-double-move :move (complex-double-reg) (complex-double-reg)) @@ -166,34 +182,31 @@ (define-vop (move-from-complex-single) (:args (x :scs (complex-single-reg) :to :save)) (:results (y :scs (descriptor-reg))) - (:temporary (:sc non-descriptor-reg) pa-flag) - (:temporary (:scs (interior-reg)) lip) + (:temporary (:scs (non-descriptor-reg) :offset lr-offset) lr) (:note "complex single float to pointer coercion") (:generator 13 - (with-fixed-allocation (y pa-flag complex-single-float-widetag - complex-single-float-size :lip lip) - (inst str x (@ y (- (* complex-single-float-data-slot - n-word-bytes) - other-pointer-lowtag)))))) + (with-fixed-allocation (y lr complex-single-float-widetag + complex-single-float-size) + (inst str x (@ y (- (* complex-single-float-data-slot + n-word-bytes) + other-pointer-lowtag)))))) (define-move-vop move-from-complex-single :move (complex-single-reg) (descriptor-reg)) (define-vop (move-from-complex-double) (:args (x :scs (complex-double-reg) :to :save)) (:results (y :scs (descriptor-reg))) - (:temporary (:sc non-descriptor-reg) pa-flag) - (:temporary (:scs (interior-reg)) lip) + (:temporary (:scs (non-descriptor-reg) :offset lr-offset) lr) (:note "complex double float to pointer coercion") (:generator 13 - (with-fixed-allocation (y pa-flag complex-double-float-widetag - complex-double-float-size :lip lip) - (inst str x (@ y (- (* complex-double-float-real-slot - n-word-bytes) - other-pointer-lowtag)))))) + (with-fixed-allocation (y lr complex-double-float-widetag + complex-double-float-size) + (inst str x (@ y (- (* complex-double-float-real-slot + n-word-bytes) + other-pointer-lowtag)))))) (define-move-vop move-from-complex-double :move (complex-double-reg) (descriptor-reg)) - ;;; ;;; Move from a descriptor to a complex float register ;;; @@ -243,7 +256,7 @@ (:generator 2 (sc-case y (complex-double-reg - (inst s-mov y x)) + (move-complex-double y x)) (complex-double-stack (storew x nfp (tn-offset y)))))) (define-move-vop move-complex-double-float-arg :move-arg @@ -468,7 +481,9 @@ single-reg single-float double-reg double-float)) (macrolet ((frob (trans from-sc from-type inst) - `(define-vop (,(symbolicate trans "/" from-type)) + `(define-vop (,(if (find #\/ (string trans)) + trans + (symbolicate trans "/" from-type))) (:args (x :scs (,from-sc))) (:results (y :scs (signed-reg))) (:arg-types ,from-type) @@ -694,7 +709,7 @@ (complex-single-reg (unless (eql (tn-offset r) (tn-offset real)) (inst s-mov r real)) - (inst s-ins r 1 imag 0 :s)) + (inst ins r 1 imag 0 :s)) (complex-single-stack (let ((nfp (current-nfp-tn vop)) (offset (tn-offset r))) @@ -725,7 +740,7 @@ (complex-double-reg (unless (eql (tn-offset r) (tn-offset real)) (inst s-mov r real)) - (inst s-ins r 1 imag 0 :d)) + (inst ins r 1 imag 0 :d)) (complex-double-stack (let ((nfp (current-nfp-tn vop)) (offset (tn-offset r))) @@ -750,7 +765,7 @@ (:generator 3 (sc-case x (complex-single-reg - (inst s-ins r 0 x (ecase slot + (inst ins r 0 x (ecase slot (:real 0) (:imag 1)) :s)) @@ -785,7 +800,7 @@ (:generator 3 (sc-case x (complex-double-reg - (inst s-ins r 0 x (ecase slot + (inst ins r 0 x (ecase slot (:real 0) (:imag 1)) :d)) @@ -802,3 +817,33 @@ (:translate imagpart) (:note "complex double float imagpart") (:variant :imag)) + +(define-vop () + (:translate round-double) + (:policy :fast-safe) + (:args (x :scs (double-reg) :target r)) + (:arg-types double-float (:constant symbol)) + (:info mode) + (:results (r :scs (double-reg))) + (:result-types double-float) + (:generator 2 + (ecase mode + (:round (inst frintn r x)) + (:floor (inst frintm r x)) + (:ceiling (inst frintp r x)) + (:truncate (inst frintz r x))))) + +(define-vop () + (:translate round-single) + (:policy :fast-safe) + (:args (x :scs (single-reg) :target r)) + (:arg-types single-float (:constant symbol)) + (:info mode) + (:results (r :scs (single-reg))) + (:result-types single-float) + (:generator 2 + (ecase mode + (:round (inst frintn r x)) + (:floor (inst frintm r x)) + (:ceiling (inst frintp r x)) + (:truncate (inst frintz r x))))) diff --git a/src/compiler/arm64/insts.lisp b/src/compiler/arm64/insts.lisp index ddf2ac1bc8..6d03e90e5a 100644 --- a/src/compiler/arm64/insts.lisp +++ b/src/compiler/arm64/insts.lisp @@ -14,12 +14,12 @@ (eval-when (:compile-toplevel :load-toplevel :execute) ;; Imports from this package into SB-VM - (import '(conditional-opcode + (import '(conditional-opcode negate-condition add-sub-immediate-p fixnum-add-sub-immediate-p negative-add-sub-immediate-p encode-logical-immediate fixnum-encode-logical-immediate ldr-str-offset-encodable ldp-stp-offset-p - bic-mask extend lsl lsr asr ror @) "SB-VM") + bic-mask extend lsl lsr asr ror @ encode-fp-immediate) "SB-VM") ;; Imports from SB-VM into this package (import '(sb-vm::*register-names* sb-vm::add-sub-immediate @@ -32,8 +32,8 @@ (defconstant-eqx +conditions+ '((:eq . 0) (:ne . 1) - (:cs . 2) (:hs . 2) - (:cc . 3) (:lo . 3) + (:hs . 2) (:cs . 2) + (:lo . 3) (:cc . 3) (:mi . 4) (:pl . 5) (:vs . 6) @@ -47,18 +47,18 @@ (:al . 14)) #'equal) -(defconstant-eqx sb-vm::+condition-name-vec+ - #.(let ((vec (make-array 16 :initial-element nil))) - (dolist (cond +conditions+ vec) - (when (null (aref vec (cdr cond))) - (setf (aref vec (cdr cond)) (car cond))))) +(defconstant-eqx +condition-name-vec+ + (let ((vec (make-array 16 :initial-element nil))) + (dolist (cond +conditions+ vec) + (when (null (aref vec (cdr cond))) + (setf (aref vec (cdr cond)) (car cond))))) #'equalp) (defun conditional-opcode (condition) (cdr (assoc condition +conditions+ :test #'eq))) -(defun invert-condition (condition) - (aref sb-vm::+condition-name-vec+ +(defun negate-condition (condition) + (aref +condition-name-vec+ (logxor 1 (conditional-opcode condition)))) ;;;; disassembler field definitions @@ -99,21 +99,35 @@ (define-arg-type reg-sp :printer #'print-reg-sp) + (define-arg-type sized-reg :printer #'print-sized-reg) + (define-arg-type reg-float-reg :printer #'print-reg-float-reg) (define-arg-type float-reg :printer #'print-float-reg) + (define-arg-type vbhs :printer #'print-vbhs) + (define-arg-type vhsd :printer #'print-vhsd) + (define-arg-type vx.t :printer #'print-vx.t) (define-arg-type simd-reg :printer #'print-simd-reg) (define-arg-type simd-copy-reg :printer #'print-simd-copy-reg) + (define-arg-type simd-immh-reg :printer #'print-simd-immh-reg) + (define-arg-type simd-modified-imm :printer #'print-simd-modified-imm) + (define-arg-type simd-reg-cmode :printer #'print-simd-reg-cmode) + + (define-arg-type fp-imm :printer #'print-fp-imm) + (define-arg-type sys-reg :printer #'print-sys-reg) (define-arg-type cond :printer #'print-cond) + (define-arg-type negated-cond :printer #'print-negated-cond) (define-arg-type ldr-str-annotation :printer #'annotate-ldr-str-imm) + (define-arg-type ldr-str-pair-annotation :printer #'annotate-ldr-str-pair) (define-arg-type ldr-str-reg-annotation :printer #'annotate-ldr-str-reg) + (define-arg-type ldr-literal-annotation :printer #'annotate-ldr-literal :sign-extend t) (define-arg-type label :sign-extend t :use-label #'use-label)) @@ -140,25 +154,15 @@ 0 1)) -(defmacro assert-same-size (&rest things) - `(assert (= ,@(loop for thing in things - collect `(reg-size ,thing))) - ,things - "Registers should have the same size: ~@{~a~%, ~}" ,@things)) +(defun reg-offset (tn) + (aver (or (register-p tn) + (fp-register-p tn))) + (tn-offset tn)) (define-instruction byte (segment byte) (:emitter (emit-byte segment byte))) -(define-instruction word (segment word) - (:emitter - (etypecase word - (fixup - (note-fixup segment :absolute word) - (emit-word segment 0)) - (integer - (emit-word segment word))))) - (define-instruction dword (segment word) (:emitter (etypecase word @@ -168,24 +172,18 @@ (integer (emit-dword segment word))))) -(defun emit-header-data (segment type) - (emit-back-patch segment - 8 - (lambda (segment posn) - (emit-dword segment - (logior type - (ash (+ posn - (component-header-length)) - (- n-widetag-bits - word-shift))))))) - (define-instruction simple-fun-header-word (segment) (:emitter - (emit-header-data segment simple-fun-widetag))) + (emit-back-patch segment + 8 + (lambda (segment posn) + (emit-dword segment + (logior simple-fun-widetag + (ash (+ posn + (component-header-length)) + (- n-widetag-bits + word-shift)))))))) -(define-instruction lra-header-word (segment) - (:emitter - (emit-header-data segment return-pc-widetag))) ;;;; Addressing mode 1 support @@ -297,7 +295,7 @@ ;;;; Data-processing instructions -(defmacro def-emitter (name &rest specs) +(defmacro def-emitter (name &body specs) (collect ((arg-names) (arg-types)) (let* ((total-bits 32) (overall-mask (ash -1 total-bits)) @@ -473,30 +471,23 @@ (cond ((or (register-p rm) (shifter-operand-p rm)) (multiple-value-bind (shift amount rm) (encode-shifted-register rm) - (assert-same-size rd rn rm) - (emit-add-sub-shift-reg segment size ,op shift (tn-offset rm) - amount (tn-offset rn) (tn-offset rd)))) + (emit-add-sub-shift-reg segment size ,op shift (reg-offset rm) + amount (reg-offset rn) (reg-offset rd)))) ((extend-p rm) - (let* ((shift 0) + (let* ((shift (extend-operand rm)) (extend (ecase (extend-kind rm) (:uxtb #b00) (:uxth #b001) (:uxtw #b010) - (:lsl - (aver (or (= (extend-operand rm) 0) - (= (extend-operand rm) 3))) - (setf shift 1) - #b011) - (:uxtx #b011) + ((:lsl :uxtx) #b011) (:sxtb #b100) (:sxth #b101) (:sxtw #b110) (:sxtx #b111))) (rm (extend-register rm))) - (assert-same-size rd rn rm) (emit-add-sub-ext-reg segment size ,op - (tn-offset rm) - extend shift (tn-offset rn) (tn-offset rd)))) + (reg-offset rm) + extend shift (reg-offset rn) (reg-offset rd)))) (t (let ((imm rm) (shift 0)) @@ -505,12 +496,15 @@ (not (ldb-test (byte 12 0) imm))) (setf imm (ash imm -12) shift 1)) - (assert-same-size rn rd) (emit-add-sub-imm segment size ,op shift imm - (tn-offset rn) (tn-offset rd))))))))) + (reg-offset rn) (reg-offset rd))))))))) (def-add-sub add #b00 (:printer add-sub-imm ((op #b00))) + (:printer add-sub-imm ((op #b00) (rd #.nsp-offset) (imm 0)) + '('mov :tab rd ", " rn)) + (:printer add-sub-imm ((op #b00) (rn #.nsp-offset) (imm 0)) + '('mov :tab rd ", " rn)) (:printer add-sub-ext-reg ((op #b00))) (:printer add-sub-shift-reg ((op #b00)))) @@ -542,6 +536,8 @@ '('cmp :tab rn ", " rm extend)) (:printer add-sub-shift-reg ((op #b11) (rd #b11111)) '('cmp :tab rn ", " rm shift)) + (:printer add-sub-shift-reg ((op #b11) (rn #b11111) (rd #b11111)) + '('cmp :tab rn ", " rm shift)) (:printer add-sub-shift-reg ((op #b11) (rn #b11111)) '('negs :tab rd ", " rm shift))) @@ -600,7 +596,7 @@ :default-printer '(:name :tab rd ", " rn ", " rm)) (op2 :field (byte 8 21) :value #b11010000) (rm :field (byte 5 16) :type 'reg) - (op :field (byte 6 10) :value 0) + (op3 :field (byte 6 10) :value 0) (rn :type 'reg) (rd :type 'reg)) @@ -608,8 +604,10 @@ `(define-instruction ,name (segment rd rn rm) (:printer add-sub-carry ((op ,opc))) (:emitter - (emit-add-sub-carry segment +64-bit-size+ ,opc - (tn-offset rm) (tn-offset rn) (tn-offset rd))))) + (emit-add-sub-carry segment + (reg-size rd) + ,opc + (reg-offset rm) (reg-offset rn) (reg-offset rd))))) (def-add-sub-carry adc #b00) (def-add-sub-carry adcs #b01) @@ -753,13 +751,15 @@ (when (shifter-operand-p rm) (setf shift (shifter-operand-function-code rm) amount (shifter-operand-operand rm))) - (emit-logical-reg segment +64-bit-size+ opc - shift n (tn-offset + (emit-logical-reg segment + (reg-size rd) + opc + shift n (reg-offset (if (shifter-operand-p rm) (shifter-operand-register rm) rm)) amount - (tn-offset rn) (tn-offset rd)))) + (reg-offset rn) (reg-offset rd)))) (defmacro def-logical-imm-and-reg (name opc &rest printers) `(define-instruction ,name (segment rd rn rm) @@ -772,7 +772,7 @@ (encode-logical-immediate rm) (unless n (error 'cannot-encode-immediate-operand :value rm)) - (emit-logical-imm segment +64-bit-size+ ,opc n immr imms (tn-offset rn) (tn-offset rd))))))) + (emit-logical-imm segment +64-bit-size+ ,opc n immr imms (reg-offset rn) (reg-offset rd))))))) (def-logical-imm-and-reg and #b00 (:printer logical-imm ((op #b00) (n 0))) @@ -843,7 +843,7 @@ (imms :field (byte 6 10) :type 'unsigned-immediate) (rn :field (byte 5 5) :type 'reg) (rd :field (byte 5 0) :type 'reg) - (lsl-alias :fields (list (byte 6 16) (byte 6 10)))) + (ubfm-alias :fields (list (byte 6 16) (byte 6 10)))) (define-instruction sbfm (segment rd rn immr imms) @@ -852,13 +852,13 @@ '('asr :tab rd ", " rn ", " immr)) (:emitter (emit-bitfield segment +64-bit-size+ 0 +64-bit-size+ - immr imms (tn-offset rn) (tn-offset rd)))) + immr imms (reg-offset rn) (reg-offset rd)))) (define-instruction bfm (segment rd rn immr imms) (:printer bitfield ((op 1))) (:emitter (emit-bitfield segment +64-bit-size+ 1 +64-bit-size+ - immr imms (tn-offset rn) (tn-offset rd)))) + immr imms (reg-offset rn) (reg-offset rd)))) (define-instruction ubfm (segment rd rn immr imms) (:printer bitfield ((op #b10) (imms #b111111)) @@ -866,12 +866,12 @@ (:printer bitfield ((op #b10)) ;; This ought to have a better solution. ;; The whole disassembler ought to be better... - '((:using #'print-lsl-alias-name lsl-alias) + '((:using #'print-ubfm-alias-name ubfm-alias) :tab rd ", " rn ", " - (:using #'print-lsl-alias lsl-alias))) + (:using #'print-ubfm-alias ubfm-alias))) (:emitter (emit-bitfield segment +64-bit-size+ #b10 +64-bit-size+ - immr imms (tn-offset rn) (tn-offset rd)))) + immr imms (reg-offset rn) (reg-offset rd)))) (define-instruction-macro asr (rd rn shift) `(let ((rd ,rd) @@ -936,13 +936,12 @@ (t :name)) :tab rd ", " rn (:unless (:same-as rn) ", " rm) ", " imm)) (:emitter - (assert-same-size rd rn rm) (let ((size (reg-size rd))) (emit-extract segment size size - (tn-offset rm) + (reg-offset rm) lsb - (tn-offset rn) - (tn-offset rd))))) + (reg-offset rn) + (reg-offset rd))))) ;;; @@ -976,19 +975,26 @@ (:printer move-wide ((op #b00))) (:emitter (aver (not (ldb-test (byte 4 0) shift))) - (emit-move-wide segment +64-bit-size+ #b00 (/ shift 16) imm (tn-offset rd)))) + (emit-move-wide segment +64-bit-size+ #b00 (/ shift 16) imm (reg-offset rd)))) (define-instruction movz (segment rd imm &optional (shift 0)) (:printer move-wide ((op #b10))) (:emitter (aver (not (ldb-test (byte 4 0) shift))) - (emit-move-wide segment +64-bit-size+ #b10 (/ shift 16) imm (tn-offset rd)))) + (emit-move-wide segment +64-bit-size+ #b10 (/ shift 16) + (cond ((and (fixup-p imm) + (eq (fixup-flavor imm) :symbol-tls-index)) + (note-fixup segment :move-wide imm) + 0) + (t + imm)) + (reg-offset rd)))) (define-instruction movk (segment rd imm &optional (shift 0)) (:printer move-wide ((op #b11))) (:emitter (aver (not (ldb-test (byte 4 0) shift))) - (emit-move-wide segment +64-bit-size+ #b11 (/ shift 16) imm (tn-offset rd)))) + (emit-move-wide segment +64-bit-size+ #b11 (/ shift 16) imm (reg-offset rd)))) ;;; @@ -1019,23 +1025,25 @@ (op2 ,op2))) ,@printers (:emitter - (emit-cond-select segment +64-bit-size+ ,op (tn-offset rm) (conditional-opcode cond) - ,op2 (tn-offset rn) (tn-offset rd))))) + (emit-cond-select segment +64-bit-size+ ,op (reg-offset rm) (conditional-opcode cond) + ,op2 (reg-offset rn) (reg-offset rd))))) (def-cond-select csel 0 0) (def-cond-select csinc 0 1 - (:printer cond-select ((op 0) (op2 1) (rn 31) (rm 31)) + (:printer cond-select ((op 0) (op2 1) (rn 31) (rm 31) + (cond nil :type 'negated-cond)) '('cset :tab rd ", " cond))) (def-cond-select csinv 1 0 - (:printer cond-select ((op 1) (op2 0) (rn 31) (rm 31)) + (:printer cond-select ((op 1) (op2 0) (rn 31) (rm 31) + (cond nil :type 'negated-cond)) '('csetm :tab rd ", " cond))) (def-cond-select csneg 1 1) (define-instruction-macro cset (rd cond) - `(inst csinc ,rd zr-tn zr-tn (invert-condition ,cond))) + `(inst csinc ,rd zr-tn zr-tn (negate-condition ,cond))) (define-instruction-macro csetm (rd cond) - `(inst csinv ,rd zr-tn zr-tn (invert-condition ,cond))) + `(inst csinv ,rd zr-tn zr-tn (negate-condition ,cond))) ;;; (def-emitter cond-compare @@ -1050,18 +1058,34 @@ (0 1 4) (nzcv 4 0)) +(define-instruction-format + (cond-compare 32 + :default-printer '(:name :tab rn ", " rm ", " nzcv ", " cond)) + (op :field (byte 1 30)) + (op2 :field (byte 9 21) :value #b111010010) + (rm :field (byte 5 16) :type 'reg) + (cond :field (byte 4 12) :type 'cond) + (imm-p :field (byte 1 11)) + (op3 :field (byte 1 10) :value 0) + (rn :field (byte 5 5) :type 'reg) + (op4 :field (byte 1 4) :value 0) + (nzcv :field (byte 4 0) :type 'unsigned-immediate)) + (defmacro def-cond-compare (name op) `(define-instruction ,name (segment rn rm-imm cond &optional (nzcv 0)) + (:printer cond-compare ((op ,op) (imm-p 0))) + (:printer cond-compare ((op ,op) (imm-p 1) + (rm nil :type 'unsigned-immediate))) (:emitter (emit-cond-compare segment +64-bit-size+ ,op (if (integerp rm-imm) rm-imm - (tn-offset rm-imm)) + (reg-offset rm-imm)) (conditional-opcode cond) (if (integerp rm-imm) 1 0) - (tn-offset rn) nzcv)))) + (reg-offset rn) nzcv)))) (def-cond-compare ccmn #b0) (def-cond-compare ccmp #b1) @@ -1077,25 +1101,53 @@ (define-instruction-format (data-processing-1 32 :default-printer '(:name :tab rd ", " rn)) + (size :field (byte 1 31)) (op2 :field (byte 18 13) :value #b101101011000000000) (op :field (byte 3 10)) (rn :field (byte 5 5) :type 'reg) (rd :field (byte 5 0) :type 'reg)) -(defmacro def-data-processing-1 (name opc) +(defmacro def-data-processing-1 (name opc &optional 32-bit-opcode) `(define-instruction ,name (segment rd rn) (:printer data-processing-1 ((op ,opc))) (:emitter - (emit-data-processing-1 segment +64-bit-size+ - ,opc (tn-offset rn) (tn-offset rd))))) + (emit-data-processing-1 segment + (reg-size rd) + ,(if 32-bit-opcode + `(sc-case rd + (32-bit-reg + ,32-bit-opcode) + (t + ,opc)) + opc) + (reg-offset rn) + (reg-offset rd))))) (def-data-processing-1 rbit #b000) (def-data-processing-1 rev16 #b001) -(def-data-processing-1 rev32 #b010) -(def-data-processing-1 rev #b011) (def-data-processing-1 clz #b100) (def-data-processing-1 cls #b101) +(define-instruction rev32 (segment rd rn) + (:printer data-processing-1 ((size 1) (op #b10))) + (:emitter + (emit-data-processing-1 segment + (reg-size rd) + #b10 + (reg-offset rn) + (reg-offset rd)))) + +(define-instruction rev (segment rd rn) + (:printer data-processing-1 ((size #b1) (op #b11))) + (:printer data-processing-1 ((size #b0) (op #b10))) + (:emitter + (emit-data-processing-1 segment (reg-size rd) + (sc-case rd + (32-bit-reg #b10) + (t #b11)) + (reg-offset rn) + (reg-offset rd)))) + ;;; (def-emitter data-processing-2 @@ -1121,10 +1173,9 @@ ,@(and alias `('(',alias :tab rd ", " rn ", " rm)))) (:emitter - (assert-same-size rd rn rm) (emit-data-processing-2 segment (reg-size rd) - (tn-offset rm) - ,opc (tn-offset rn) (tn-offset rd))))) + (reg-offset rm) + ,opc (reg-offset rn) (reg-offset rd))))) (def-data-processing-2 asrv #b001010 asr) (def-data-processing-2 lslv #b001000 lsl) @@ -1163,9 +1214,11 @@ (:printer data-processing-3 ((op31 ,op31) (o0 ,o0))) ,@printers (:emitter - (emit-data-processing-3 segment +64-bit-size+ ,op31 - (tn-offset rm) - ,o0 (tn-offset ra) (tn-offset rn) (tn-offset rd))))) + (emit-data-processing-3 segment + (reg-size rd) + ,op31 + (reg-offset rm) + ,o0 (reg-offset ra) (reg-offset rn) (reg-offset rd))))) (def-data-processing-3 madd #b000 0 (:printer data-processing-3 ((op31 #b000) (o0 0) (ra 31)) @@ -1189,15 +1242,15 @@ (:printer data-processing-3 ((op31 #b010) (o0 0) (ra 31)) '(:name :tab rd ", " rn ", " rm)) (:emitter - (emit-data-processing-3 segment +64-bit-size+ #b010 (tn-offset rm) - 0 31 (tn-offset rn) (tn-offset rd)))) + (emit-data-processing-3 segment (reg-size rd) #b010 (reg-offset rm) + 0 31 (reg-offset rn) (reg-offset rd)))) (define-instruction umulh (segment rd rn rm) (:printer data-processing-3 ((op31 #b110) (o0 0) (ra 31)) '(:name :tab rd ", " rn ", " rm)) (:emitter - (emit-data-processing-3 segment +64-bit-size+ #b110 (tn-offset rm) - 0 31 (tn-offset rn) (tn-offset rd)))) + (emit-data-processing-3 segment (reg-size rd) #b110 (reg-offset rm) + 0 31 (reg-offset rn) (reg-offset rd)))) ;;; (define-instruction-format (ldr-str 32) @@ -1272,6 +1325,7 @@ (op4 :field (byte 1 21) :value 1) (rm :field (byte 5 16) :type 'reg) (option :fields (list (byte 3 13) (byte 1 12)) :type 'ldr-str-extend) + (op5 :field (byte 2 10) :value #b10) (ldr-str-annotation :field (byte 5 16) :type 'ldr-str-reg-annotation)) (def-emitter ldr-literal @@ -1283,11 +1337,12 @@ (rt 5 0)) (define-instruction-format (ldr-literal 32 - :default-printer '(:name :tab rt ", " label) + :default-printer '(:name :tab rt ", " label literal-annotation) :include ldr-str) (op2 :value #b011) (label :field (byte 19 5) :type 'label) - (rt :fields (list (byte 2 30) (byte 5 0)))) + (rt :fields (list (byte 2 30) (byte 5 0))) + (literal-annotation :field (byte 19 5) :type 'ldr-literal-annotation)) (defun ldr-str-offset-encodable (offset &optional (size 64)) (or (typep offset '(signed-byte 9)) @@ -1299,7 +1354,8 @@ (let* ((base (memory-operand-base address)) (offset (memory-operand-offset address)) (mode (memory-operand-mode address)) - (index-encoding (position mode '(:offset :post-index 0 :pre-index))) + (index-encoding (or (position mode '(:offset :post-index 0 :pre-index)) + (error "Bad addressing mode"))) (fp (fp-register-p dst)) (v (if fp 1 @@ -1320,42 +1376,45 @@ (logior (ash (ldb (byte 1 1) opc) 2) size) size)) - (dst (tn-offset dst))) - (cond ((and (typep offset 'unsigned-byte) - (not (ldb-test (byte scale 0) offset)) - (typep (ash offset (- scale)) '(unsigned-byte 12)) + (dst (reg-offset dst))) + (cond ((and (or + (and (fixup-p offset) + (eq (fixup-flavor offset) :symbol-tls-index)) + (and (typep offset 'unsigned-byte) + (not (ldb-test (byte scale 0) offset)) + (typep (ash offset (- scale)) '(unsigned-byte 12)))) (register-p base) (eq mode :offset)) (emit-ldr-str-unsigned-imm segment size v opc - (ash offset (- scale)) - (tn-offset base) + (cond ((fixup-p offset) + (note-fixup segment :ldr-str offset) + 0) + (t + (ash offset (- scale)))) + (reg-offset base) dst)) ((and (eq mode :offset) (or (register-p offset) (extend-p offset))) - (let* ((register (if (extend-p offset) - (extend-register offset) - offset)) - (shift (cond ((extend-p offset) - (aver (or (= (extend-operand offset) 0) - (= (extend-operand offset) 3))) - (ash (extend-operand offset) -1)) - (t - 0))) - (extend (if (extend-p offset) - (ecase (extend-kind offset) - (:uxtw #b010) - (:lsl - #b011) - (:sxtw #b110) - (:sxtx #b111)) - #b011))) + (multiple-value-bind + (register shift extend) + (if (extend-p offset) + (values (extend-register offset) + (if (> (extend-operand offset) 0) + 1 + 0) + (ecase (extend-kind offset) + (:uxtw #b010) + (:lsl #b011) + (:sxtw #b110) + (:sxtx #b111))) + (values offset 0 #b011)) (emit-ldr-str-reg segment size v opc - (tn-offset register) + (reg-offset register) extend shift - (tn-offset base) + (reg-offset base) dst))) ((and (typep offset '(signed-byte 9)) (or (register-p base) @@ -1363,7 +1422,7 @@ (emit-ldr-str-unscaled-imm segment size v opc offset index-encoding - (tn-offset base) dst)) + (reg-offset base) dst)) (t (error "Invalid STR/LDR arguments: ~s ~s" dst address))))) @@ -1412,7 +1471,7 @@ 1 0) (ash (- (label-position address) posn) -2) - (tn-offset dst)))) + (reg-offset dst)))) (emit-load-store nil 1 segment dst address)))) (def-emitter ldr-str-pair @@ -1429,7 +1488,7 @@ (define-instruction-format (ldr-str-pair 32 - :default-printer '(:name :tab rt ", " rt2 ", [" rn pair-imm-writeback) + :default-printer '(:name :tab rt ", " rt2 ", [" rn pair-imm-writeback ldr-str-annotation) :include ldr-str) (size :field (byte 2 30)) (op2 :value #b101) @@ -1439,7 +1498,8 @@ (pair-imm-writeback :fields (list (byte 2 23) (byte 2 30) (byte 7 15) (byte 1 26)) :type 'pair-imm-writeback) (rt2 :fields (list (byte 2 30) (byte 5 10)) :type 'reg-float-reg) - (rt :fields (list (byte 2 30) (byte 5 0)))) + (rt :fields (list (byte 2 30) (byte 5 0))) + (ldr-str-annotation :fields (list (byte 5 5) (byte 7 15)) :type 'ldr-str-pair-annotation)) (defun ldp-stp-offset-p (offset size) (multiple-value-bind (quot rem) (truncate offset (ecase size @@ -1483,7 +1543,7 @@ (:offset #b10)) l (ash offset (- size)) - (tn-offset rt2) (tn-offset base) (tn-offset rt1)))) + (reg-offset rt2) (reg-offset base) (reg-offset rt1)))) (define-instruction stp (segment rt1 rt2 address) (:printer ldr-str-pair ((l 0))) @@ -1517,52 +1577,204 @@ (o1 :field (byte 1 21)) (rs :field (byte 5 16) :type 'w-reg) (o0 :field (byte 1 15)) - (rt2 :field (byte 5 5) :type 'reg) + (rt2 :field (byte 5 10) :type 'reg) (rn :field (byte 5 5) :type 'x-reg-sp) (rt :field (byte 5 0) :type 'reg)) -(defmacro def-store-exclusive (name o0 o1 o2 rs &rest printers) +(defmacro def-store-exclusive (name o0 o1 o2 rs) `(define-instruction ,name (segment ,@(and rs '(rs)) rt rn) (:printer ldr-str-exclusive ((o0 ,o0) (o1 ,o1) (o2 ,o2) (l 0)) '(:name :tab ,@(and rs '(rs ", ")) rt ", [" rn "]")) - ,@printers (:emitter (emit-ldr-str-exclusive segment (logior #b10 (reg-size rt)) ,o2 0 ,o1 ,(if rs - '(tn-offset rs) + '(reg-offset rs) 31) ,o0 31 - (tn-offset rn) - (tn-offset rt))))) + (reg-offset rn) + (reg-offset rt))))) (def-store-exclusive stxr 0 0 0 t) (def-store-exclusive stlxr 1 0 0 t) (def-store-exclusive stlr 1 0 1 nil) -(defmacro def-load-exclusive (name o0 o1 o2 &rest printers) +(defmacro def-load-exclusive (name o0 o1 o2) `(define-instruction ,name (segment rt rn) (:printer ldr-str-exclusive ((o0 ,o0) (o1 ,o1) (o2 ,o2) (l 1)) '(:name :tab rt ", [" rn "]")) - ,@printers (:emitter (emit-ldr-str-exclusive segment (logior #b10 (reg-size rt)) ,o2 1 ,o1 31 ,o0 31 - (tn-offset rn) - (tn-offset rt))))) + (reg-offset rn) + (reg-offset rt))))) (def-load-exclusive ldxr 0 0 0) (def-load-exclusive ldaxr 1 0 0) (def-load-exclusive ldar 1 0 1) +(define-instruction-format (cas 32) + (size1 :field (byte 1 31) :value 1) + (size :field (byte 1 30)) + (op2 :field (byte 6 24) :value #b001000) + (o2 :field (byte 1 23) :value 1) + (l :field (byte 1 22)) + (o1 :field (byte 1 21) :value 1) + (rs :fields (list (byte 1 30) (byte 5 16)) :type 'sized-reg) + (o0 :field (byte 1 15)) + (rt2 :field (byte 5 10) :value #b11111) + (rn :field (byte 5 5) :type 'x-reg-sp) + (rt :fields (list (byte 1 30) (byte 5 0)) :type 'sized-reg)) + +(define-instruction-format (casb 32) + (size :field (byte 2 30)) + (op2 :field (byte 6 24) :value #b001000) + (o2 :field (byte 1 23) :value 1) + (l :field (byte 1 22)) + (o1 :field (byte 1 21) :value 1) + (rs :field (byte 5 16) :type 'w-reg) + (o0 :field (byte 1 15)) + (rt2 :field (byte 5 10) :value #b11111) + (rn :field (byte 5 5) :type 'x-reg-sp) + (rt :field (byte 5 0) :type 'w-reg)) + +(defmacro def-cas (name o0 l) + `(define-instruction ,name (segment rs rt rn) + (:printer cas ((o0 ,o0) (l ,l)) + '(:name :tab rs ", " rt ", [" rn "]")) + (:emitter + (emit-ldr-str-exclusive segment + (logior #b10 (reg-size rt)) + 1 + ,l + 1 + (reg-offset rs) + ,o0 + 31 + (reg-offset rn) + (reg-offset rt))))) + +(def-cas cas 0 0) +(def-cas casa 0 1) +(def-cas casal 1 1) +(def-cas casl 1 0) + +(defmacro def-casb (name size o0 l) + `(define-instruction ,name (segment rs rt rn) + (:printer casb ((size ,size) (o0 ,o0) (l ,l)) + '(:name :tab rs ", " rt ", [" rn "]")) + (:emitter + (emit-ldr-str-exclusive segment + ,size + 1 + ,l + 1 + (reg-offset rs) + ,o0 + 31 + (reg-offset rn) + (reg-offset rt))))) +(def-casb casb 0 0 0) +(def-casb casab 0 0 1) +(def-casb casalb 0 1 1) +(def-casb caslb 0 1 0) + +(def-casb cash 1 0 0) +(def-casb casah 1 0 1) +(def-casb casalh 1 1 1) +(def-casb caslh 1 1 0) + +;;; + +(def-emitter ldatomic + (size 2 30) + (#b111000 6 24) + (a 1 23) + (r 1 22) + (#b1 1 21) + (rs 5 16) + (opc 6 10) + (rn 5 5) + (rt 5 0)) + +(define-instruction-format (ldatomic 32) + (size1 :field (byte 1 31) :value #b1) + (size :field (byte 1 30)) + (op2 :field (byte 6 24) :value #b111000) + (a :field (byte 1 23)) + (r :field (byte 1 22)) + (o1 :field (byte 1 21) :value #b1) + (rs :fields (list (byte 1 30) (byte 5 16)) :type 'sized-reg) + (opc :field (byte 6 10)) + (rn :field (byte 5 5) :type 'x-reg-sp) + (rt :fields (list (byte 1 30) (byte 5 0)) :type 'sized-reg)) + +(defmacro def-ldatomic (name opc a r) + `(define-instruction ,name (segment rs rt rn) + (:printer ldatomic ((a ,a) (r ,r) (opc ,opc)) + '(:name :tab rs ", " rt ", [" rn "]")) + (:emitter + (emit-ldatomic segment + (logior #b10 (reg-size rt)) + ,a + ,r + (reg-offset rs) + ,opc + (reg-offset rn) + (reg-offset rt))))) + +(def-ldatomic ldadd 0 0 0) +(def-ldatomic ldadda 0 1 0) +(def-ldatomic ldaddal 0 1 1) + +(def-ldatomic ldeor #b001000 0 0) +(def-ldatomic ldeora #b001000 1 0) +(def-ldatomic ldeoral #b001000 1 1) + +(def-ldatomic ldset #b001100 0 0) +(def-ldatomic ldseta #b001100 1 0) +(def-ldatomic ldsetal #b001100 1 1) + +(define-instruction-format (ldaddb 32) + (size :field (byte 2 30)) + (op2 :field (byte 6 24) :value #b111000) + (a :field (byte 1 23)) + (r :field (byte 1 22)) + (o1 :field (byte 1 21) :value #b1) + (rs :field (byte 5 16) :type 'w-reg) + (opc :field (byte 6 10) :value #b0) + (rn :field (byte 5 5) :type 'x-reg-sp) + (rt :field (byte 5 0) :type 'w-reg)) + +(defmacro def-ldaddb (name size a r) + `(define-instruction ,name (segment rs rt rn) + (:printer ldaddb ((size ,size) (a ,a) (r ,r)) + '(:name :tab rs ", " rt ", [" rn "]")) + (:emitter + (emit-ldatomic segment + ,size + ,a + ,r + 0 + (reg-offset rs) + (reg-offset rn) + (reg-offset rt))))) + +(def-ldaddb ldaddb 0 0 0) +(def-ldaddb ldaddab 0 1 0) +(def-ldaddb ldaddalb 0 1 1) +(def-ldaddb ldaddh 1 0 0) +(def-ldaddb ldaddah 1 1 0) +(def-ldaddb ldaddalh 1 1 1) + ;;; (def-emitter cond-branch - (#b01010100 8 24) + (#b01010100 8 24) (imm 19 5) (#b0 1 4) (cond 4 0)) @@ -1593,7 +1805,7 @@ (not label)) (note-fixup segment :uncond-branch cond-or-label) (emit-uncond-branch segment 0 0)) - ((and (fixup-p label)) + ((fixup-p label) (note-fixup segment :cond-branch cond-or-label) (emit-cond-branch segment 0 (conditional-opcode cond-or-label))) (t @@ -1614,7 +1826,7 @@ (define-instruction bl (segment label) (:printer uncond-branch ((op 1))) (:emitter - (ecase label + (etypecase label (fixup (note-fixup segment :uncond-branch label) (emit-uncond-branch segment 1 0)) @@ -1643,19 +1855,19 @@ (define-instruction br (segment register) (:printer uncond-branch-reg ((op 0))) (:emitter - (emit-uncond-branch-reg segment 0 (tn-offset register)))) + (emit-uncond-branch-reg segment 0 (reg-offset register)))) (define-instruction blr (segment register) (:printer uncond-branch-reg ((op 1))) (:emitter - (emit-uncond-branch-reg segment 1 (tn-offset register)))) + (emit-uncond-branch-reg segment 1 (reg-offset register)))) (define-instruction ret (segment &optional (register sb-vm::lr-tn)) (:printer uncond-branch-reg ((op #b10))) (:printer uncond-branch-reg ((op #b10) (rn sb-vm::lr-offset)) '(:name)) (:emitter - (emit-uncond-branch-reg segment #b10 (tn-offset register)))) + (emit-uncond-branch-reg segment #b10 (reg-offset register)))) ;;; @@ -1684,7 +1896,7 @@ +64-bit-size+ 0 (ash (- (label-position label) posn) -2) - (tn-offset rt)))))) + (reg-offset rt)))))) (define-instruction cbnz (segment rt label) (:printer compare-branch-imm ((op 1))) @@ -1696,7 +1908,7 @@ (reg-size rt) 1 (ash (- (label-position label) posn) -2) - (tn-offset rt)))))) + (reg-offset rt)))))) (def-emitter test-branch-imm (b5 1 31) @@ -1726,7 +1938,7 @@ 0 (ldb (byte 5 0) bit) (ash (- (label-position label) posn) -2) - (tn-offset rt)))))) + (reg-offset rt)))))) (define-instruction tbnz (segment rt bit label) (:printer test-branch-imm ((op 1))) @@ -1740,10 +1952,78 @@ 1 (ldb (byte 5 0) bit) (ash (- (label-position label) posn) -2) - (tn-offset rt)))))) + (reg-offset rt)))))) + +(define-instruction tbnz* (segment rt bit label) + (:emitter + (aver (label-p label)) + (check-type bit (integer 0 63)) + (labels ((compute-delta (position &optional magic-value) + (- (label-position label + (when magic-value position) + magic-value) + position)) + (multi-instruction-emitter (segment position) + (declare (ignore position)) + (assemble (segment) + (inst tst rt (ash 1 bit)) + (inst b :ne label))) + (one-instruction-emitter (segment posn) + (emit-test-branch-imm segment + (ldb (byte 1 5) bit) + 1 + (ldb (byte 5 0) bit) + (ash (- (label-position label) posn) -2) + (reg-offset rt))) + (multi-instruction-maybe-shrink (segment chooser posn magic-value) + (declare (ignore chooser)) + (let ((delta (compute-delta posn magic-value))) + (when (typep delta '(signed-byte 14)) + (emit-back-patch segment 4 + #'one-instruction-emitter) + t)))) + (emit-chooser + segment 8 2 + #'multi-instruction-maybe-shrink + #'multi-instruction-emitter)))) + +(define-instruction tbz* (segment rt bit label) + (:emitter + (aver (label-p label)) + (check-type bit (integer 0 63)) + (labels ((compute-delta (position &optional magic-value) + (- (label-position label + (when magic-value position) + magic-value) + position)) + (multi-instruction-emitter (segment position) + (declare (ignore position)) + (assemble (segment) + (inst tst rt (ash 1 bit)) + (inst b :eq label))) + (one-instruction-emitter (segment posn) + (emit-test-branch-imm segment + (ldb (byte 1 5) bit) + 0 + (ldb (byte 5 0) bit) + (ash (- (label-position label) posn) -2) + (reg-offset rt))) + (multi-instruction-maybe-shrink (segment chooser posn magic-value) + (declare (ignore chooser)) + (let ((delta (compute-delta posn magic-value))) + (when (typep delta '(signed-byte 14)) + (emit-back-patch segment 4 + #'one-instruction-emitter) + t)))) + (emit-chooser + segment 8 2 + #'multi-instruction-maybe-shrink + #'multi-instruction-emitter)))) + + ;;; (def-emitter exception - (#b11010100 8 24) + (#b11010100 8 24) (opc 3 21) (imm 16 5) (#b000 3 2) @@ -1794,7 +2074,7 @@ op (ldb (byte 2 0) offset) (ldb (byte 19 2) offset) - (tn-offset rd)))))) + (reg-offset rd)))))) (define-instruction adr (segment rd label &optional (offset 0)) (:printer pc-relative ((op 0))) @@ -1825,24 +2105,26 @@ (#b1101101000010000 :nzcv) (#b1101101000100000 :fpcr) (#b1101101000100001 :fpsr) - (#b1101110011101000 :ccnt))) + (#b1101110011101000 :ccnt) + (#b1101111010000011 :tpidrro_el0))) (defun encode-sys-reg (reg) (ecase reg (:nzcv #b1101101000010000) (:fpcr #b1101101000100000) (:fpsr #b1101101000100001) - (:ccnt #b1101110011101000))) + (:ccnt #b1101110011101000) + (:tpidrro_el0 #b1101111010000011))) (define-instruction msr (segment sys-reg rt) (:printer sys-reg ((l 0)) '(:name :tab sys-reg ", " rt)) (:emitter - (emit-system-reg segment 0 (encode-sys-reg sys-reg) (tn-offset rt)))) + (emit-system-reg segment 0 (encode-sys-reg sys-reg) (reg-offset rt)))) (define-instruction mrs (segment rt sys-reg) (:printer sys-reg ((l 1)) '(:name :tab rt ", " sys-reg)) (:emitter - (emit-system-reg segment 1 (encode-sys-reg sys-reg) (tn-offset rt)))) + (emit-system-reg segment 1 (encode-sys-reg sys-reg) (reg-offset rt)))) ;;; @@ -1964,8 +2246,8 @@ (fp-reg-type rn) (if (eql rm 0) 0 - (tn-offset rm)) - (tn-offset rn) + (reg-offset rm)) + (reg-offset rn) ,op (if (eql rm 0) 1 @@ -2030,7 +2312,7 @@ (fp-data-processing-3 32 :include fp-data-processing :default-printer '(:name :tab rd ", " rn ", " rm ", " ra)) - (op4 :field (byte 9 23) :value #b000011110) + (op4 :field (byte 9 23) :value #b000111110) (op1 :field (byte 1 21)) (op2 :field (byte 1 15)) (rm :field (byte 5 16) :type 'float-reg) @@ -2066,8 +2348,8 @@ (emit-fp-data-processing-1 segment (fp-reg-type rn) ,op - (tn-offset rn) - (tn-offset rd))))) + (reg-offset rn) + (reg-offset rd))))) (def-fp-data-processing-1 fabs #b0001) (def-fp-data-processing-1 fneg #b0010) @@ -2093,8 +2375,8 @@ (emit-fp-data-processing-1 segment (fp-reg-type rn) (logior #b100 (fp-reg-type rd)) - (tn-offset rn) - (tn-offset rd)))) + (reg-offset rn) + (reg-offset rd)))) (defmacro def-fp-data-processing-2 (name op) `(define-instruction ,name (segment rd rn rm) @@ -2108,10 +2390,10 @@ "Arguments should have the same FP storage class: ~s ~s ~s." rd rn rm) (emit-fp-data-processing-2 segment (fp-reg-type rn) - (tn-offset rm) + (reg-offset rm) ,op - (tn-offset rn) - (tn-offset rd))))) + (reg-offset rn) + (reg-offset rd))))) (def-fp-data-processing-2 fmul #b0000) (def-fp-data-processing-2 fdiv #b0001) @@ -2138,11 +2420,11 @@ (emit-fp-data-processing-3 segment (fp-reg-type rn) ,o1 - (tn-offset rm) + (reg-offset rm) ,o2 - (tn-offset ra) - (tn-offset rn) - (tn-offset rd))))) + (reg-offset ra) + (reg-offset rn) + (reg-offset rd))))) (def-fp-data-processing-3 fmadd 0 0) (def-fp-data-processing-3 fmsub 0 1) @@ -2177,8 +2459,8 @@ 'rd 'rn)) ,op - (tn-offset rn) - (tn-offset rd))))) + (reg-offset rn) + (reg-offset rd))))) (def-fp-conversion fcvtns #b00000) (def-fp-conversion fcvtnu #b00001) @@ -2193,20 +2475,90 @@ (def-fp-conversion fcvtzs #b11000) (def-fp-conversion fcvtzu #b11001) +(defun encode-fp-immediate (float) + (typecase float + (double-float + (let* ((bits (double-float-bits float)) + (sign (ldb (byte 1 63) bits)) + (exp (ldb (byte 11 52) bits)) + (frac (ldb (byte 52 0) bits))) + (when (and (zerop (ldb (byte 48 0) frac)) + (= + (ldb (byte 8 2) exp) + (if (zerop (ldb (byte 1 10) exp)) + (ldb (byte 8 0) -1) + 0))) + (logior (ash sign 7) + (ash (logandc1 (ldb (byte 1 10) exp) 1) 6) + (ash (ldb (byte 2 0) exp) 4) + (ldb (byte 4 48) frac))))) + (single-float + (let* ((bits (single-float-bits float)) + (sign (ldb (byte 1 31) bits)) + (exp (ldb (byte 8 23) bits)) + (frac (ldb (byte 23 0) bits))) + (when (and (zerop (ldb (byte 19 0) frac)) + (= (ldb (byte 5 2) exp) + (if (zerop (ldb (byte 1 7) exp)) + (ldb (byte 5 0) -1) + 0))) + (logior (ash sign 7) + (ash (logandc1 (ldb (byte 1 7) exp) 1) 6) + (ash (ldb (byte 2 0) exp) 4) + (ldb (byte 4 19) frac))))))) + +(def-emitter fp-immediate + (m 1 31) + (#b0 1 30) + (s 1 29) + (#b11110 5 24) + (type 2 22) + (#b1 1 21) + (imm8 8 13) + (#b100 3 10) + (imm5 5 5) + (rd 5 0)) + +(define-instruction-format (fp-immediate 32 + :default-printer '(:name :tab rd ", " imm)) + (#b0 :field (byte 1 31)) + (#b0 :field (byte 1 30)) + (#b0 :field (byte 1 29)) + (#b11110 :field (byte 5 24)) + (#b1 :field (byte 1 21)) + (imm :fields (list (byte 2 22) (byte 8 13)) :type 'fp-imm) + (#b100 :field (byte 3 10)) + (#b0 :field (byte 5 5)) + (rd :field (byte 5 0) :type 'float-reg)) + (define-instruction fmov (segment rd rn) (:printer fp-conversion ((op #b110) (rd nil :type 'reg))) (:printer fp-conversion ((op #b111) (rn nil :type 'reg))) (:printer fp-data-processing-1 ((op #b0))) + (:printer fp-immediate ()) (:emitter - (cond ((or (sc-is rd complex-double-reg complex-single-reg) - (sc-is rn complex-double-reg complex-single-reg))) + (cond ((double-float-p rn) + (aver (sc-is rd double-reg)) + (emit-fp-immediate segment 0 0 #b01 + (encode-fp-immediate rn) + 0 + (reg-offset rd))) + ((single-float-p rn) + (aver (sc-is rd single-reg)) + (emit-fp-immediate segment 0 0 #b00 + (encode-fp-immediate rn) + 0 + (reg-offset rd))) + ((or (sc-is rd complex-double-reg complex-single-reg) + (sc-is rn complex-double-reg complex-single-reg)) + (break "Implement")) ((and (fp-register-p rd) (fp-register-p rn)) (assert (and (eq (tn-sc rd) (tn-sc rn))) (rd rn) "Arguments should have the same fp storage class: ~s ~s." rd rn) (emit-fp-data-processing-1 segment (fp-reg-type rn) 0 - (tn-offset rn) (tn-offset rd))) + (reg-offset rn) (reg-offset rd))) ((and (register-p rd) (fp-register-p rn)) (let* ((type (fp-reg-type rn)) @@ -2218,7 +2570,7 @@ (if 128-p #b01111 #b110) - (tn-offset rn) (tn-offset rd)))) + (reg-offset rn) (reg-offset rd)))) ((and (register-p rn) (fp-register-p rd)) (let* ((type (fp-reg-type rd)) @@ -2230,72 +2582,8 @@ (if 128-p #b01111 #b111) - (tn-offset rn) (tn-offset rd))))))) + (reg-offset rn) (reg-offset rd))))))) -;;;; Boxed-object computation instructions (for LRA and CODE) - -;;; Compute the address of a CODE object by parsing the header of a -;;; nearby LRA or SIMPLE-FUN. - -(defun emit-compute (segment vop dest lip compute-delta) - (labels ((multi-instruction-emitter (segment position) - (let* ((delta (funcall compute-delta position)) - (negative (minusp delta)) - (delta (abs delta)) - (low (* (if negative -1 1) - (ldb (byte 19 0) delta))) - (high (ldb (byte 16 19) delta))) - ;; ADR - (emit-pc-relative segment 0 - (ldb (byte 2 0) low) - (ldb (byte 19 2) low) - (tn-offset lip)) - (assemble (segment vop) - (inst movz tmp-tn high 16) - (if negative - (inst sub dest lip (lsl tmp-tn 3)) - (inst add dest lip (lsl tmp-tn 3)))))) - (one-instruction-emitter (segment position) - (let ((delta (funcall compute-delta position))) - ;; ADR - (emit-pc-relative segment 0 - (ldb (byte 2 0) delta) - (ldb (byte 19 2) delta) - (tn-offset dest)))) - (multi-instruction-maybe-shrink (segment chooser posn magic-value) - (declare (ignore chooser)) - (when (typep (funcall compute-delta posn magic-value) - '(signed-byte 21)) - (emit-back-patch segment 4 - #'one-instruction-emitter) - t))) - (emit-chooser - segment 12 2 - #'multi-instruction-maybe-shrink - #'multi-instruction-emitter))) - -(define-instruction compute-code (segment code lip object-label) - (:vop-var vop) - (:declare (ignore object-label)) - (:emitter - (emit-compute segment vop code lip - (lambda (position &optional magic-value) - (declare (ignore magic-value)) - (- other-pointer-lowtag - position - (component-header-length)))))) - -(define-instruction compute-lra (segment dest lip lra-label) - (:vop-var vop) - (:emitter - (emit-compute segment vop dest lip - (lambda (position &optional magic-value) - (- (+ (label-position lra-label - (when magic-value position) - magic-value) - other-pointer-lowtag) - position))))) - (define-instruction load-from-label (segment dest label &optional lip) (:vop-var vop) (:emitter @@ -2313,19 +2601,72 @@ (emit-pc-relative segment 0 (ldb (byte 2 0) low) (ldb (byte 19 2) low) - (tn-offset lip)) + (reg-offset lip)) (assemble (segment vop) - (inst movz tmp-tn high 16) - (inst ldr dest (@ lip (extend tmp-tn (if negative - :sxtw - :lsl) + (inst movz dest high 16) + (inst ldr dest (@ lip (extend dest (if negative + :sxtw + :lsl) 3)))))) (one-instruction-emitter (segment position) (emit-ldr-literal segment - #b01 0 + (sc-case dest + ((32-bit-reg single-reg) #b00) + (complex-double-reg #b10) + (t #b01)) + (if (fp-register-p dest) + 1 + 0) + (ldb (byte 19 0) + (ash (compute-delta position) -2)) + (reg-offset dest))) + (multi-instruction-maybe-shrink (segment chooser posn magic-value) + (declare (ignore chooser)) + (let ((delta (compute-delta posn magic-value))) + (when (typep delta '(signed-byte 21)) + (emit-back-patch segment 4 + #'one-instruction-emitter) + t)))) + (if lip + (emit-chooser + segment 12 2 + #'multi-instruction-maybe-shrink + #'multi-instruction-emitter) + (emit-back-patch segment 4 #'one-instruction-emitter))))) + +(define-instruction load-constant (segment dest index &optional lip) + (:vop-var vop) + (:emitter + (labels ((compute-delta (position &optional magic-value) + (+ (- (label-position (segment-origin segment) + (when magic-value position) + magic-value) + (component-header-length) + position) + index)) + (multi-instruction-emitter (segment position) + (let* ((delta (compute-delta position)) + (negative (minusp delta)) + (low (ldb (byte 19 0) delta)) + (high (ldb (byte 16 19) delta))) + ;; ADR + (emit-pc-relative segment 0 + (ldb (byte 2 0) low) + (ldb (byte 19 2) low) + (reg-offset lip)) + (assemble (segment vop) + (inst movz dest high 16) + (inst ldr dest (@ lip (extend dest (if negative + :sxtw + :lsl) + 3)))))) + (one-instruction-emitter (segment position) + (emit-ldr-literal segment + #b01 + 0 (ldb (byte 19 0) (ash (compute-delta position) -2)) - (tn-offset dest))) + (reg-offset dest))) (multi-instruction-maybe-shrink (segment chooser posn magic-value) (declare (ignore chooser)) (let ((delta (compute-delta posn magic-value))) @@ -2342,7 +2683,7 @@ ;;; SIMD (def-emitter simd-three-diff - (#b0 1 31) + (#b0 1 31) (q 1 30) (u 1 29) (#b01110 5 24) @@ -2380,26 +2721,22 @@ (rn :fields (list (byte 1 30) (byte 5 5)) :type 'simd-reg) (rd :fields (list (byte 1 30) (byte 5 0)) :type 'simd-reg)) -(defun decode-vector-size (size) - (ecase size - (:8b 0) - (:16b 1))) +(define-instruction-format (simd-three-same-sized 32 + :include simd-three-same + :default-printer '(:name :tab rd ", " rn ", " rm)) + (rm :fields (list (byte 1 30) (byte 2 22) (byte 5 16)) :type 'simd-reg) + (rn :fields (list (byte 1 30) (byte 2 22) (byte 5 5)) :type 'simd-reg) + (rd :fields (list (byte 1 30) (byte 2 22) (byte 5 0)) :type 'simd-reg)) -(define-instruction s-orr (segment rd rn rm &optional (size :16b)) - (:printer simd-three-same ((u #b0) (size #b10) (op #b00011)) - '((:cond - ((rn :same-as rm) 'mov) - (t 'orr)) - :tab rd ", " rn (:unless (:same-as rn) "," rm))) - (:emitter - (emit-simd-three-same segment - (decode-vector-size size) - #b0 - #b10 - (tn-offset rm) - #b00011 - (tn-offset rn) - (tn-offset rd)))) +(defun encode-vector-size (size) + (ecase size + (:8b (values 0 0)) + (:16b (values 1 0)) + (:4h (values 0 #b01)) + (:8h (values 1 #b01)) + (:2s (values 0 #b10)) + (:4s (values 1 #b10)) + (:2d (values 1 #b11)))) (define-instruction-macro s-mov (rd rn &optional (size :16b)) `(let ((rd ,rd) @@ -2407,6 +2744,72 @@ (size ,size)) (inst s-orr rd rn rn size))) +(macrolet ((def (name u size op &rest printer) + `(define-instruction ,name (segment rd rn rm &optional (size :16b)) + (:printer simd-three-same ((u ,u) (size ,size) (op ,op)) + ,@printer) + (:emitter + (emit-simd-three-same segment + (encode-vector-size size) + ,u + ,size + (reg-offset rm) + ,op + (reg-offset rn) + (reg-offset rd)))))) + (def s-orr #b0 #b10 #b00011 + '((:cond + ((rn :same-as rm) 'mov) + (t 'orr)) + :tab rd ", " rn (:unless (:same-as rn) ", " rm))) + (def s-and #b0 #b00 #b00011) + (def s-eor #b1 #b00 #b00011)) + +(macrolet ((def (name u op) + `(define-instruction ,name (segment rd rn rm &optional (size :16b)) + (:printer simd-three-same-sized ((u ,u) (op ,op))) + (:emitter + (multiple-value-bind (q size) (encode-vector-size size) + (emit-simd-three-same segment + q + ,u + size + (reg-offset rm) + ,op + (reg-offset rn) + (reg-offset rd))))))) + (def s-sub #b1 #b10000) + (def cmeq #b1 #b10001) + (def cmgt #b0 #b00110) + (def cmge #b0 #b00111) + (def cmhi #b1 #b00110) + (def cmhs #b1 #b00111)) + +(def-emitter simd-scalar-three-same + (#b01 2 30) + (u 1 29) + (#b11110 5 24) + (size 2 22) + (#b1 1 21) + (rm 5 16) + (opc 5 11) + (#b1 1 10) + (rn 5 5) + (rd 5 0)) + +(define-instruction-format (simd-scalar-three-same 32 + :default-printer '(:name :tab rd ", " rn ", " rm)) + (op3 :field (byte 2 30) :value #b1) + (u :field (byte 1 29)) + (op4 :field (byte 5 24) :value #b11110) + (size :field (byte 2 22)) + (op5 :field (byte 1 21) :value #b1) + (rm :fields (list (byte 1 30) (byte 5 16)) :type 'simd-reg) + (op :field (byte 5 11)) + (op6 :field (byte 1 10) :value #b1) + (rn :fields (list (byte 1 30) (byte 5 5)) :type 'simd-reg) + (rd :fields (list (byte 1 30) (byte 5 0)) :type 'simd-reg)) + ;;; (def-emitter simd-extract @@ -2420,14 +2823,24 @@ (rn 5 5) (rd 5 0)) -(define-instruction s-ext (segment rd rn rm index &optional (size :16b)) +(define-instruction-format (simd-extract 32 + :default-printer '(:name :tab rd ", " rn ", " rm)) + (op3 :field (byte 1 31) :value #b0) + (op4 :field (byte 9 21) :value #b101110000) + (rm :fields (list (byte 1 30) (byte 5 16)) :type 'simd-reg) + (op6 :field (byte 1 15) :value #b0) + (rn :fields (list (byte 1 30) (byte 5 5)) :type 'simd-reg) + (rd :fields (list (byte 1 30) (byte 5 0)) :type 'simd-reg)) + +(define-instruction ext (segment rd rn rm index &optional (size :16b)) + (:printer simd-extract ()) (:emitter (emit-simd-extract segment - (decode-vector-size size) - (tn-offset rm) + (encode-vector-size size) + (reg-offset rm) index - (tn-offset rn) - (tn-offset rd)))) + (reg-offset rn) + (reg-offset rd)))) ;;; @@ -2449,24 +2862,297 @@ (q :field (byte 1 30)) (op :field (byte 1 29)) (op4 :field (byte 8 21) :value #b01110000) + (imm5 :field (byte 5 16)) (op5 :field (byte 1 15) :value #b0) + (imm4 :field (byte 4 11)) (op6 :field (byte 1 10) :value #b1) (rn :fields (list (byte 5 5) (byte 5 16) (byte 4 11)) :type 'simd-copy-reg) (rd :fields (list (byte 5 0) (byte 5 16)) :type 'simd-copy-reg)) -(define-instruction s-ins (segment rd index1 rn index2 size) - (:printer simd-copy ((q 1) (op 1)) - '('ins :tab rd ", " rn)) +(define-instruction ins (segment rd index1 rn index2 size) + (:printer simd-copy ((q 1) (op 1))) (:emitter (let ((size (position size '(:B :H :S :D)))) (emit-simd-copy segment - 1 - 1 - (logior (ash index1 (1+ size)) - (ash 1 size)) - (ash index2 size) - (tn-offset rn) - (tn-offset rd))))) + 1 + 1 + (logior (ash index1 (1+ size)) + (ash 1 size)) + (ash index2 size) + (reg-offset rn) + (reg-offset rd))))) + +(define-instruction-format (simd-copy-to-general 32 + :include simd-copy + :default-printer '(:name :tab rd ", " rn)) + (rn :fields (list (byte 5 5) (byte 5 16)) :type 'simd-copy-reg) + (rd :fields (list (byte 1 30) (byte 5 0)) :type 'sized-reg)) + +(define-instruction umov (segment rd rn index size) + (:printer simd-copy-to-general ((op 0) (imm4 #b0111))) + (:emitter + (let ((size (position size '(:B :H :S :D)))) + (emit-simd-copy segment + (case size + (:d 1) + (t 0)) + 0 + (logior (ash index (1+ size)) + (ash 1 size)) + #b0111 + (reg-offset rn) + (reg-offset rd))))) + +(def-emitter simd-across-lanes + (#b0 1 31) + (q 1 30) + (u 1 29) + (#b01110 5 24) + (size 2 22) + (#b11000 5 17) + (op 5 12) + (#b10 2 10) + (rn 5 5) + (rd 5 0)) + +(define-instruction-format (simd-across-lanes 32 + :default-printer '(:name :tab rd ", " rn)) + (o1 :field (byte 1 31) :value #b0) + (q :field (byte 1 30)) + (u :field (byte 1 29)) + (op2 :field (byte 5 24) :value #b01110) + (size :field (byte 2 22)) + (op3 :field (byte 5 17) :value #b11000) + (op :field (byte 5 12)) + (op4 :field (byte 2 10) :value #b10) + (rn :fields (list (byte 1 30) (byte 2 22) (byte 5 5)) :type 'vx.t) + (rd :fields (list (byte 2 22) (byte 5 0)) :type 'vbhs)) + + +(def-emitter simd-two-misc + (#b0 1 31) + (q 1 30) + (u 1 29) + (#b01110 5 24) + (size 2 22) + (#b10000 5 17) + (op 5 12) + (#b10 2 10) + (rn 5 5) + (rd 5 0)) + +(define-instruction addv (segment rd sized rn sizen) + (:printer simd-across-lanes ((u 0) (op #b11011))) + (:emitter + (emit-simd-across-lanes + segment + (ecase sizen + (:8b 0) + (:16b 1) + (:4h 0) + (:8h 1) + (:4s 1)) + 0 + (ecase sized + (:b 0) + (:h 1) + (:s 2)) + #b11011 + (reg-offset rn) + (reg-offset rd)))) + +(define-instruction uaddlv (segment rd sized rn sizen) + (:printer simd-across-lanes ((u 1) (op #b00011) + (rd nil :type 'vhsd))) + (:emitter + (emit-simd-across-lanes + segment + (ecase sizen + (:8b 0) + (:16b 1) + (:4h 0) + (:8h 1) + (:4s 1)) + 1 + (ecase sized + (:h 0) + (:s 1) + (:d 2)) + #b00011 + (reg-offset rn) + (reg-offset rd)))) + +(macrolet ((def (name u op) + `(define-instruction ,name (segment rd rn size) + (:printer simd-across-lanes ((u ,u) (op ,op) + (rd nil :type 'vhsd))) + (:emitter + (multiple-value-bind (q size) (encode-vector-size size) + (emit-simd-across-lanes + segment + q + ,u + size + ,op + (reg-offset rn) + (reg-offset rd))))))) + (def uminv 1 #b11010) + (def umaxv 1 #b01010)) + +(define-instruction-format (simd-two-misc 32 + :default-printer '(:name :tab rd ", " rn)) + (o1 :field (byte 1 31) :value #b0) + (q :field (byte 1 30)) + (u :field (byte 1 29)) + (op2 :field (byte 5 24) :value #b01110) + (size :field (byte 2 22)) + (op3 :field (byte 5 17) :value #b10000) + (op :field (byte 4 12)) + (op4 :field (byte 2 10) :value #b10) + (rn :fields (list (byte 1 30) (byte 2 22) (byte 5 5)) :type 'simd-reg) + (rd :fields (list (byte 1 30) (byte 2 22) (byte 5 0)) :type 'simd-reg)) + +(macrolet + ((def (name u op &optional (sizes '(:8b :16b))) + `(define-instruction ,name (segment rd rn &optional (size :16b)) + (:printer simd-two-misc ((u ,u) (op ,op))) + (:emitter + (check-type size (member ,@sizes)) + (multiple-value-bind (q size) (encode-vector-size size) + (emit-simd-two-misc segment + q + ,u + size + ,op + (reg-offset rn) + (reg-offset rd))))))) + (def cnt #b0 #b00101) + (def s-rev16 #b0 #b00001) + (def s-rev32 #b1 #b00000 (:8b :16b :4h :8h)) + (def rev64 #b0 #b00000 (:8b :16b :4h :8h :2s :4s)) + (def not #b1 #b00101)) + +(def-emitter simd-shift-by-imm + (#b0 1 31) + (q 1 30) + (u 1 29) + (#b011110 6 23) + (immh 4 19) + (immb 3 16) + (op 5 11) + (#b1 1 10) + (rn 5 5) + (rd 5 0)) + +(define-instruction-format (simd-shift-by-imm 32 + :default-printer '(:name :tab rd ", " rn)) + (o1 :field (byte 1 31) :value #b0) + (q :field (byte 1 30)) + (u :field (byte 1 29)) + (op2 :field (byte 6 23) :value #b011110) + (immh :field (byte 4 19)) + (immb :field (byte 3 16)) + (op :field (byte 5 11)) + (op3 :field (byte 1 10) :value #b1) + (rn :fields (list (byte 1 30) (byte 4 19) (byte 5 5)) :type 'simd-immh-reg) + (rd :fields (list (byte 4 19) (byte 5 0)) :type 'simd-immh-reg)) + +(macrolet + ((def (name q u op) + `(define-instruction ,name (segment rd sized rn sizen shift) + (:printer simd-shift-by-imm ((q ,q) (u ,u) (op ,op))) + (:emitter + (let ((immh 0) + (immb 0)) + (ecase sized + (:8h + (aver (eq sizen + (if (zerop ,q) + :8B + :16B))) + (setf immh #b1)) + (:4s + (aver (eq sizen + (if (zerop ,q) + :4H + :8H))) + (setf immh #b10) + (setf (ldb (byte 1 0) immh) (ldb (byte 1 3) shift))) + (:2d + (aver (eq sizen + (if (zerop ,q) + :2S + :4S))) + (setf immh #b100) + (setf (ldb (byte 2 0) immh) (ldb (byte 2 3) shift)))) + (setf immb (ldb (byte 3 0) shift)) + (emit-simd-shift-by-imm segment + ,q + ,u + immh + immb + ,op + (reg-offset rn) + (reg-offset rd))))))) + (def ushll #b0 #b1 #b10100) + (def ushll2 #b1 #b1 #b10100)) + +(def-emitter simd-modified-imm + (#b0 1 31) + (q 1 30) + (op 1 29) + (#b0111100000 10 19) + (abc 3 16) + (cmode 4 12) + (o2 1 11) + (#b1 1 10) + (defgh 5 5) + (rd 5 0)) + +(define-instruction-format (simd-modified-imm 32 + :default-printer '(:name :tab rd ", " imm)) + (o1 :field (byte 1 31) :value #b0) + (q :field (byte 1 30)) + (op :field (byte 1 29)) + (op2 :field (byte 10 19) :value #b0111100000) + (cmode :field (byte 4 12)) + (o2 :field (byte 1 11)) + (op3 :field (byte 1 10) :value #b1) + (imm :fields (list (byte 3 16) (byte 4 12) (byte 5 5)) :type 'simd-modified-imm) + (rd :fields (list (byte 1 30) (byte 4 12) (byte 5 0)) :type 'simd-reg-cmode)) + +(macrolet + ((def (name o2) + `(define-instruction ,name (segment rd imm size &optional (shift 0)) + ;; 8-bit + (:printer simd-modified-imm ((o2 ,o2) (op 0))) + (:emitter + (let ((abc 0) + (defgh 0) + (cmode 0) + (op 0)) + (setf abc (ldb (byte 3 5) imm) + defgh (ldb (byte 5 0) imm)) + (ecase size + ((:8b :16b) + (setf cmode #b1110)) + ((:2s :4s) + (setf cmode + (ash (ecase shift + (0 0) + (8 1) + (16 2) + (24 3)) + 1)))) + (emit-simd-modified-imm segment + (encode-vector-size size) + op + abc + cmode + ,o2 + defgh + (reg-offset rd))))))) + (def movi 0)) ;;; Inline constants (defun canonicalize-inline-constant (constant) @@ -2494,9 +3180,10 @@ (setf constant (list :complex-double-float first))))) (destructuring-bind (type value) constant (ecase type - ((:byte :word :dword :qword) - (aver (integerp value)) - (cons type value)) + ((:byte :word :dword :qword :oword) + (etypecase value + ((or integer (cons (eql :layout-id))) + (cons type value)))) (:base-char #+sb-unicode (aver (typep value 'base-char)) (cons :byte (char-code value))) @@ -2536,6 +3223,9 @@ (defun size-nbyte (size) (ecase size (:byte 1) + ;; These keywords are completely wrong for AARCH64 but I don't want to touch them. + ;; The correct definitions would have :HWORD (halfword) for 2 bytes, :WORD for 4, + ;; :DWORD for 8, and :QWORD for 16. (:word 2) (:dword 4) ((:qword :fixup) 8) @@ -2545,20 +3235,392 @@ (stable-sort constants #'> :key (lambda (constant) (size-nbyte (caar constant))))) +(sb-assem::%def-inst-encoder + '.layout-id + (lambda (segment layout) + (sb-c:note-fixup segment :layout-id (sb-c:make-fixup layout :layout-id)) + (sb-assem::%emit-skip segment 4))) + (defun emit-inline-constant (section constant label) (let* ((type (car constant)) + (val (cdr constant)) (size (size-nbyte type))) (emit section `(.align ,(integer-length (1- size))) label - (let ((val (cdr constant))) - (case type - (:fixup - ;; Use the WORD emitter which knows how to emit fixups - `(word ,(apply #'make-fixup val))) - (t + (cond ((typep val '(cons (eql :layout-id))) + `(.layout-id ,(cadr val))) + ((eql type :fixup) + ;; Use the DWORD emitter which knows how to emit fixups + `(dword ,(apply #'make-fixup val))) + (t ;; Could add pseudo-ops for .WORD, .INT, .QUAD, .OCTA just like gcc has. ;; But it works fine to emit as a sequence of bytes + ;; FIXME: missing support for big-endian. Do we care? `(.byte ,@(loop repeat size collect (prog1 (ldb (byte 8 0) val) - (setf val (ash val -8))))))))))) + (setf val (ash val -8)))))))))) + +(defun sb-vm:fixup-code-object (code offset value kind flavor) + (declare (type index offset) (ignore flavor)) + (unless (zerop (rem offset sb-assem:+inst-alignment-bytes+)) + (error "Unaligned instruction? offset=#x~X." offset)) + (let ((sap (code-instructions code))) + (ecase kind + (:absolute + (setf (sap-ref-word sap offset) value)) + (:layout-id + (setf (signed-sap-ref-32 sap offset) value)) + (:cond-branch + (setf (ldb (byte 19 5) (sap-ref-32 sap offset)) + (ash (- value (+ (sap-int sap) offset)) -2))) + (:uncond-branch + (setf (ldb (byte 26 0) (sap-ref-32 sap offset)) + (ash (- value (+ (sap-int sap) offset)) -2))) + (:ldr-str + (setf (ldb (byte 12 10) (sap-ref-32 sap offset)) + (ash (the (unsigned-byte #.(+ 12 word-shift)) value) + (- word-shift)))) + (:move-wide + (setf (ldb (byte 16 5) (sap-ref-32 sap offset)) + (the (unsigned-byte 16) value))))) + nil) + +;;; Even though non darwin-jit arm64 targets can store directly in the +;;; code object, having two codepaths is cumbersome and, now that +;;; there's no reg-code, STRB needs to load a literal first, which +;;; isn't clearly a win compared to using a vector. +(define-instruction store-coverage-mark (segment mark-index temp vector) + (:emitter + ;; No backpatch is needed to compute the offset into the code header + ;; because COMPONENT-HEADER-LENGTH is known at this point. + segment mark-index temp vector + (flet ((encode-index (offset &optional word) + (cond + ((if word + (typep offset '(integer 0 255)) + (typep offset '(integer 0 4095))) + offset) + ((typep offset '(unsigned-byte 16)) + (inst* segment 'movz temp offset 0) + temp) + ((typep offset '(unsigned-byte 32)) + (inst* segment 'movz temp (ldb (byte 16 16) offset) 16) + (inst* segment 'movk temp (ldb (byte 16 0) offset) 0) + temp) + (t + (error "Bad offset ~a" offset))))) + (let* ((vector-offset (* n-word-bytes + (- (length (ir2-component-constants + (component-info *component-being-compiled*))) + 2))) + (offset (+ (* sb-vm:vector-data-offset n-word-bytes) + mark-index + (- other-pointer-lowtag))) + (addr + (@ vector (encode-index offset)))) + (inst* segment 'load-constant vector vector-offset) + (inst* segment 'strb sb-vm::null-tn addr))))) + +(defun conditional-branch-p (stmt) + (and (eq (stmt-mnemonic stmt) 'b) + (= (length (stmt-operands stmt)) 2))) + +(defpattern "cmp 0 + branch" ((subs) (b)) (stmt next) + (let ((next-next (stmt-next next))) + (when (and (not (stmt-labels next)) + next-next + (not (conditional-branch-p next-next))) + (destructuring-bind (target value cmp) (stmt-operands stmt) + (when (and (eql cmp 0) + (eq target zr-tn)) + (destructuring-bind (flag label) (stmt-operands next) + (unless (eq (sb-assem::label-comment label) :merged-ifs) + (when (case flag + (:eq + (setf (stmt-mnemonic stmt) 'cbz + (stmt-operands stmt) + (list value label))) + (:ne + (setf (stmt-mnemonic stmt) 'cbnz + (stmt-operands stmt) + (list value label))) + (:ge + (setf (stmt-mnemonic stmt) 'tbz* + (stmt-operands stmt) + (list value (1- n-word-bits) label))) + (:lt + (setf (stmt-mnemonic stmt) 'tbnz* + (stmt-operands stmt) + (list value (1- n-word-bits) label)))) + (delete-stmt next) + next-next)))))))) + +(defpattern "tst one bit + branch" ((ands) (b)) (stmt next) + (let ((next-next (stmt-next next))) + (when (and (not (stmt-labels next)) + next-next + (not (conditional-branch-p next-next))) + (destructuring-bind (target value mask) (stmt-operands stmt) + (when (and (integerp mask) + (= (logcount (ldb (byte n-word-bits 0) mask)) 1) + (eq target zr-tn)) + (destructuring-bind (flag label) (stmt-operands next) + (when (case flag + (:eq + (setf (stmt-mnemonic stmt) 'tbz + (stmt-operands stmt) + (list value (1- (integer-length mask)) label))) + (:ne + (setf (stmt-mnemonic stmt) 'tbnz + (stmt-operands stmt) + (list value (1- (integer-length mask)) label)))) + (delete-stmt next) + next-next))))))) + +(defun stmt-delete-safe-p (dst1 dst2 &optional safe-translates + safe-vops) + (or (location= dst1 dst2) + (and + (not (tn-ref-next (sb-c::tn-reads dst1))) + (let ((vop (tn-ref-vop (sb-c::tn-reads dst1)))) + (and vop + (or (not safe-vops) + (memq (vop-name vop) safe-vops)) + (or (not safe-translates) + (and vop + (memq (car (sb-c::vop-parse-translate + (sb-c::vop-parse-or-lose (vop-name vop)))) + safe-translates)))))))) + +(defun tagged-mask-p (x) + (and (integerp x) + (plusp x) + (zerop (ldb (byte 1 0) x)) + (let ((untag (ash x -1))) + (= (integer-length untag) + (logcount untag))))) + +(defun untagged-mask-p (x) + (and (integerp x) + (plusp x) + (= (integer-length x) + (logcount x)))) + +;;; Tagging and applying a tagged mask can be done in one step. +(defpattern "lsl + and -> ubfiz" ((ubfm) (and)) (stmt next) + (destructuring-bind (dst1 src1 immr imms) (stmt-operands stmt) + (destructuring-bind (dst2 src2 mask) (stmt-operands next) + (when (and (location= dst1 src2) + (tagged-mask-p mask) + (= immr 63) + (= imms 62) + (stmt-delete-safe-p dst1 dst2 '(logand))) + (setf (stmt-mnemonic next) 'ubfm + (stmt-operands next) (list dst2 src1 63 (1- (logcount mask)))) + (add-stmt-labels next (stmt-labels stmt)) + (delete-stmt stmt) + next)))) + +;;; Helps with SBIT +(defpattern "and + lsl -> ubfiz" ((and) (ubfm)) (stmt next) + (destructuring-bind (dst1 src1 mask) (stmt-operands stmt) + (destructuring-bind (dst2 src2 immr imms) (stmt-operands next) + (when (and (location= dst1 src2) + (untagged-mask-p mask) + (= immr 63) + (= imms 62) + (stmt-delete-safe-p dst1 dst2 nil '(sb-vm::move-from-word/fixnum))) + (setf (stmt-mnemonic next) 'ubfm + (stmt-operands next) (list dst2 src1 63 (1- (logcount mask)))) + (add-stmt-labels next (stmt-labels stmt)) + (delete-stmt stmt) + next)))) + +;;; If the sign bit gets cut off it can be done with just a logical shift. +(defpattern "asr + and -> lsr" ((sbfm) (and)) (stmt next) + (destructuring-bind (dst1 src1 immr imms) (stmt-operands stmt) + (destructuring-bind (dst2 src2 mask) (stmt-operands next) + (when (and (location= dst1 src2) + (untagged-mask-p mask) + (= (integer-length mask) 63) + (= immr 1) + (= imms 63) + (stmt-delete-safe-p dst1 dst2 '(logand))) + (setf (stmt-mnemonic next) 'ubfm + (stmt-operands next) (list dst2 src1 immr imms)) + (add-stmt-labels next (stmt-labels stmt)) + (delete-stmt stmt) + next)))) + +;;; Applying a tagged mask and untagging +(defpattern "and + asr -> ubfx" ((and) (sbfm)) (stmt next) + (destructuring-bind (dst1 src1 mask) (stmt-operands stmt) + (destructuring-bind (dst2 src2 immr imms) (stmt-operands next) + (when (and (location= dst1 src2) + (tagged-mask-p mask) + (= immr 1) + (= imms 63) + (stmt-delete-safe-p dst1 dst2 nil '(sb-vm::move-to-word/fixnum))) + ;; Leave the ASR if the sign bit is left, + ;; but the AND is not needed. + (if (= (integer-length mask) 64) + (setf (stmt-operands next) (list dst2 src1 immr imms)) + (setf (stmt-mnemonic next) 'ubfm + (stmt-operands next) (list dst2 src1 1 (logcount mask)))) + (add-stmt-labels next (stmt-labels stmt)) + (delete-stmt stmt) + next)))) + +(defpattern "and + and -> and" ((and) (and)) (stmt next) + (destructuring-bind (dst1 src1 mask1) (stmt-operands stmt) + (destructuring-bind (dst2 src2 mask2) (stmt-operands next) + (when + (and (location= dst1 src2) + (integerp mask1) + (integerp mask2) + (stmt-delete-safe-p dst1 dst2 '(logand))) + (let ((mask (logand mask1 mask2))) + (when (or (zerop mask) + (encode-logical-immediate mask)) + (if (zerop mask) + (setf (stmt-mnemonic next) 'orr + (stmt-operands next) (list dst2 zr-tn zr-tn)) + (setf (stmt-operands next) (list dst2 src1 mask))) + (add-stmt-labels next (stmt-labels stmt)) + (delete-stmt stmt) + next)))))) + +(defpattern "lsl + arith -> arith" ((ubfm) (add and orr eor)) (stmt next) + (destructuring-bind (dst1 src1 immr imms) (stmt-operands stmt) + (destructuring-bind (dst2 srcn srcm) (stmt-operands next) + (when (and (/= imms 63) + (= (1+ imms) immr) + (tn-p srcm) + (or + (location= dst1 srcm) + (location= dst1 srcn)) + (not (location= srcn srcm)) + (stmt-delete-safe-p dst1 dst2 + '(+ sb-vm::+-mod64 sb-vm::+-modfx + logand logior logxor))) + (setf (stmt-operands next) (list dst2 (if (location= dst1 srcm) + srcn + srcm) + (lsl src1 (- 63 imms)))) + (add-stmt-labels next (stmt-labels stmt)) + (delete-stmt stmt) + next)))) + +(defpattern "lsl + sub -> sub" ((ubfm) (sub)) (stmt next) + (destructuring-bind (dst1 src1 immr imms) (stmt-operands stmt) + (destructuring-bind (dst2 srcn srcm) (stmt-operands next) + (when (and (/= imms 63) + (= (1+ imms) immr) + (tn-p srcm) + (location= dst1 srcm) + (not (location= srcn srcm)) + (stmt-delete-safe-p dst1 dst2 + '(- sb-vm::--mod64 sb-vm::--modfx))) + (setf (stmt-operands next) (list dst2 srcn (lsl src1 (- 63 imms)))) + (add-stmt-labels next (stmt-labels stmt)) + (delete-stmt stmt) + next)))) + +(defpattern "lsl + lsl -> lsl" ((ubfm) (ubfm)) (stmt next) + (destructuring-bind (dst1 src1 immr1 imms1) (stmt-operands stmt) + (destructuring-bind (dst2 src2 immr2 imms2) (stmt-operands next) + (when (and (/= imms1 63) + (/= imms2 63) + (= (1+ imms1) immr1) + (= (1+ imms2) immr2) + (location= dst1 src2) + (stmt-delete-safe-p dst1 dst2 + '(ash + sb-vm::ash-left-mod64 + sb-vm::ash-left-modfx))) + (let ((shift (+ (- 63 imms1) + (- 63 imms2)))) + (when (<= shift 63) + (setf (stmt-operands next) (list dst2 src1 (mod (- shift) 64) (- 63 shift))) + (add-stmt-labels next (stmt-labels stmt)) + (delete-stmt stmt) + next)))))) + +(defpattern "asr + asr -> asr" ((sbfm) (sbfm)) (stmt next) + (destructuring-bind (dst1 src1 immr1 imms1) (stmt-operands stmt) + (destructuring-bind (dst2 src2 immr2 imms2) (stmt-operands next) + (when (and (= imms1 imms2 63) + (location= dst1 src2) + (stmt-delete-safe-p dst1 dst2 + nil '(sb-vm::move-to-word/fixnum))) + (setf (stmt-operands next) + (list dst2 src1 (min (+ immr1 immr2) 63) 63)) + (add-stmt-labels next (stmt-labels stmt)) + (delete-stmt stmt) + next)))) + +;;; An even number can be shifted right and then negated, +;;; and fixnums are even. +(defpattern "neg + asr -> neg" ((sub) (sbfm)) (stmt next) + (destructuring-bind (dst1 srcn srcm) (stmt-operands stmt) + (destructuring-bind (dst2 src2 immr imms) (stmt-operands next) + (when (and (= imms 63) + (= immr 1) + (tn-p srcm) + (sc-is srcm sb-vm::any-reg) + (location= srcn zr-tn) + (location= dst1 src2) + (stmt-delete-safe-p dst1 dst2 nil '(sb-vm::move-to-word/fixnum))) + (setf (stmt-mnemonic next) 'sub + (stmt-operands next) (list dst2 srcn (asr srcm 1))) + (add-stmt-labels next (stmt-labels stmt)) + (delete-stmt stmt) + next)))) + +(defpattern "mul + sub -> msub" ((madd) (sub)) (stmt next) + (destructuring-bind (dst1 srcn1 srcm1 srca) (stmt-operands stmt) + (destructuring-bind (dst2 srcn2 srcm2) (stmt-operands next) + (when (and (tn-p srcm2) + (location= dst1 srcm2) + (location= srca zr-tn) + (not (location= srcn2 srcm2)) + (stmt-delete-safe-p dst1 dst2 + '(- sb-vm::--mod64 sb-vm::--modfx))) + (setf (stmt-mnemonic next) 'msub + (stmt-operands next) (list dst2 srcn1 srcm1 srcn2)) + (add-stmt-labels next (stmt-labels stmt)) + (delete-stmt stmt) + next)))) + +(defpattern "mul + add -> madd" ((madd) (add)) (stmt next) + (destructuring-bind (dst1 srcn1 srcm1 srca) (stmt-operands stmt) + (destructuring-bind (dst2 srcn2 srcm2) (stmt-operands next) + (when (and (tn-p srcm2) + (location= srca zr-tn) + (not (location= srcn2 srcm2)) + (or (location= dst1 srcm2) + (location= dst1 srcn2)) + (stmt-delete-safe-p dst1 dst2 + '(+ sb-vm::+-mod64 sb-vm::+-modfx))) + (setf (stmt-mnemonic next) 'madd + (stmt-operands next) (list dst2 + srcn1 srcm1 + (if (location= dst1 srcm2) + srcn2 + srcm2))) + (add-stmt-labels next (stmt-labels stmt)) + (delete-stmt stmt) + next)))) + +(defpattern "fmul + fsub -> fmsub" ((fmul) (fsub)) (stmt next) + (destructuring-bind (dst1 srcn1 srcm1) (stmt-operands stmt) + (destructuring-bind (dst2 srcn2 srcm2) (stmt-operands next) + (when (and (location= dst1 srcm2) + (not (location= srcn2 srcm2)) + (stmt-delete-safe-p dst1 dst2 '(-))) + (setf (stmt-mnemonic next) 'fmsub + (stmt-operands next) (list dst2 srcn1 srcm1 srcn2)) + (add-stmt-labels next (stmt-labels stmt)) + (delete-stmt stmt) + next)))) diff --git a/src/compiler/arm64/macros.lisp b/src/compiler/arm64/macros.lisp index 814d6d4110..5d2e90b144 100644 --- a/src/compiler/arm64/macros.lisp +++ b/src/compiler/arm64/macros.lisp @@ -90,42 +90,20 @@ #+big-endian `(+ ,n-offset (1- n-word-bytes)))) `(inst ldrb ,n-target (@ ,n-source ,target-offset))))) -;;; Macros to handle the fact that our stack pointer isn't actually in -;;; a register (or won't be, by the time we're done). - -;;; Macros to handle the fact that we cannot use the machine native call and -;;; return instructions. - -(defmacro lisp-jump (function lip) - "Jump to the lisp lip LIP." - `(let ((function ,function) - (lip ,lip)) - (aver (sc-is lip interior-reg)) - (inst add lip function - (- (ash simple-fun-insts-offset word-shift) - fun-pointer-lowtag)) - (inst br lip))) - -(defmacro lisp-return (function lip return-style) +(defmacro lisp-jump (lr) + `(progn + (inst add ,lr ,lr 4) + (inst br ,lr))) + +(defmacro lisp-return (lr return-style) "Return to RETURN-PC." - `(let* ((function ,function) - (lip ,lip)) - (aver (sc-is lip interior-reg)) + `(progn ;; Indicate a single-valued return by clearing the Z flag ,@(ecase return-style (:single-value '((inst cmp null-tn 0))) (:multiple-values '((inst cmp zr-tn zr-tn))) (:known)) - (inst sub lip function (- other-pointer-lowtag 8)) - (inst ret lip))) - -(defmacro emit-return-pc (label) - "Emit a return-pc header word. LABEL is the label to use for this return-pc." - `(progn - (emit-alignment n-lowtag-bits) - (emit-label ,label) - (inst lra-header-word))) - + (inst ret ,lr))) ;;;; Stack TN's @@ -156,7 +134,7 @@ (once-only ((n-reg reg) (n-stack reg-or-stack)) `(sc-case ,n-reg - ((any-reg descriptor-reg) + ((any-reg descriptor-reg non-descriptor-reg) (sc-case ,n-stack ((any-reg descriptor-reg) (move ,n-reg ,n-stack)) @@ -181,80 +159,62 @@ ;;; P-A FLAG-TN is also acceptable here. #+gencgc -(defun allocation-tramp (type alloc-tn size back-label return-in-tmp lip) - (unless (eq size tmp-tn) - (inst mov tmp-tn size)) +(defun allocation-tramp (type alloc-tn size back-label) + (if (integerp size) + (load-immediate-word tmp-tn size) + (inst mov tmp-tn size)) (let ((asm-routine (if (eq type 'list) 'list-alloc-tramp 'alloc-tramp))) - (load-inline-constant alloc-tn `(:fixup ,asm-routine :assembly-routine) lip)) + (load-inline-constant alloc-tn `(:fixup ,asm-routine :assembly-routine))) (inst blr alloc-tn) - (unless return-in-tmp - (move alloc-tn tmp-tn)) (inst b back-label)) +;;; Leaves the untagged pointer in TMP-TN, +;;; Allowing it to be used with STP later. (defun allocation (type size lowtag result-tn - &key flag-tn - stack-allocate-p - (lip (if stack-allocate-p nil (missing-arg)))) - (declare (ignorable type lip)) + &key flag-tn + stack-allocate-p + overflow) + (declare (ignorable type)) ;; Normal allocation to the heap. (if stack-allocate-p (assemble () - (move result-tn csp-tn) - (inst tst result-tn lowtag-mask) - (inst b :eq ALIGNED) - (inst add result-tn result-tn n-word-bytes) - ALIGNED - (inst add csp-tn result-tn (add-sub-immediate size)) - ;; :ne is from TST above, this needs to be done after the - ;; stack pointer has been stored. - (inst b :eq ALIGNED2) - (storew zr-tn result-tn -1 0) - ALIGNED2 - (when lowtag - (inst add result-tn result-tn lowtag))) - #-gencgc - (progn - (load-symbol-value flag-tn *allocation-pointer*) - (inst add result-tn flag-tn lowtag) - (inst add flag-tn flag-tn (add-sub-immediate size)) - (store-symbol-value flag-tn *allocation-pointer*)) - #+gencgc - (let ((alloc (gen-label)) (back-from-alloc (gen-label))) + (inst add tmp-tn csp-tn lowtag-mask) + (inst and tmp-tn tmp-tn (lognot lowtag-mask)) + (inst add csp-tn tmp-tn (add-sub-immediate size result-tn)) + (inst add result-tn tmp-tn lowtag)) + (let ((alloc (gen-label)) + #+sb-thread (tlab (if (eq type 'list) thread-cons-tlab-slot thread-mixed-tlab-slot)) + #-sb-thread (region (if (eq type 'list) cons-region mixed-region)) + (back-from-alloc (gen-label))) #-sb-thread (progn ;; load-pair can't base off null-tn because the displacement ;; has to be a multiple of 8 - (load-immediate-word flag-tn static-space-start) - (inst ldp result-tn flag-tn (@ flag-tn (* 2 n-word-bytes)))) + (load-immediate-word flag-tn region) + (inst ldp result-tn flag-tn (@ flag-tn 0))) #+sb-thread - (inst ldp result-tn flag-tn (@ thread-tn (* n-word-bytes thread-alloc-region-slot))) - (setf size (add-sub-immediate size)) - (inst add result-tn result-tn size) + (inst ldp tmp-tn flag-tn (@ thread-tn (* n-word-bytes tlab))) + (inst add result-tn tmp-tn (add-sub-immediate size result-tn)) (inst cmp result-tn flag-tn) (inst b :hi ALLOC) - #-sb-thread (inst str result-tn (@ null-tn (- (+ static-space-start (* 2 n-word-bytes)) - nil-value))) - #+sb-thread (storew result-tn thread-tn thread-alloc-region-slot) - ;; alloc_tramp uses tmp-tn for returning the result, - ;; save on a move when possible - (inst sub (if lowtag tmp-tn result-tn) result-tn size) + #-sb-thread (inst str result-tn (@ null-tn (load-store-offset (- region nil-value)))) + #+sb-thread (storew result-tn thread-tn tlab) + (emit-label BACK-FROM-ALLOC) - (when lowtag - (inst add result-tn tmp-tn lowtag)) + (inst add result-tn tmp-tn lowtag) (assemble (:elsewhere) (emit-label ALLOC) - (allocation-tramp type - result-tn - size - BACK-FROM-ALLOC - ;; see the comment above aboout alloc_tramp - lowtag - lip))))) + (if overflow + (funcall overflow) + (allocation-tramp type + result-tn + size + BACK-FROM-ALLOC)))))) (defmacro with-fixed-allocation ((result-tn flag-tn type-code size &key (lowtag other-pointer-lowtag) stack-allocate-p - (lip (missing-arg))) + (store-type-code t)) &body body) "Do stuff to allocate an other-pointer object of fixed Size with a single word header having the specified Type-Code. The result is placed in @@ -263,29 +223,57 @@ initializes the object." (once-only ((result-tn result-tn) (flag-tn flag-tn) (type-code type-code) (size size) (lowtag lowtag) - (stack-allocate-p stack-allocate-p) - (lip lip)) - `(pseudo-atomic (,flag-tn :sync ,type-code) + (stack-allocate-p stack-allocate-p)) + `(pseudo-atomic (,flag-tn :sync ,type-code + :elide-if ,stack-allocate-p) (allocation nil (pad-data-block ,size) ,lowtag ,result-tn :flag-tn ,flag-tn - :stack-allocate-p ,stack-allocate-p - :lip ,lip) + :stack-allocate-p ,stack-allocate-p) (when ,type-code (load-immediate-word ,flag-tn (compute-object-header ,size ,type-code)) - (storew ,flag-tn ,result-tn 0 ,lowtag)) + ,@(and store-type-code + `((storew ,flag-tn ,result-tn 0 ,lowtag)))) ,@body))) ;;;; Error Code +;;;; BRK accepts a 16-bit immediate +;;;; Encode the error kind in the first byte. +;;;; If KIND is ERROR-TRAP, then add CODE to that first byte. +;;;; Otherwise CODE goes into the byte following BRK. +;;;; The arguments are normally encoded by ENCODE-INTERNAL-ERROR-ARGS, +;;;; except for the first argument if it's a descriptor-reg or +;;;; any-reg, then it goes into the second byte of the BRK instruction +;;;; immediate. +;;;; Otherwise that second byte is 31 (the ZR register). (defun emit-error-break (vop kind code values) (assemble () (when vop (note-this-location vop :internal-error)) - ;; Encode both kind and code as an argument to BRK - (inst brk (dpb code (byte 8 8) kind)) - ;; NARGS is implicitely assumed for invalid-arg-count - (unless (= kind invalid-arg-count-trap) - (encode-internal-error-args values) - (emit-alignment 2)))) + (cond ((= kind invalid-arg-count-trap) + ;; NARGS is implicitly assumed for invalid-arg-count + (inst brk kind) + (return-from emit-error-break)) + (t + (let ((first-value (car values))) + (inst brk (dpb (cond ((and (tn-p first-value) + (sc-is first-value descriptor-reg any-reg unsigned-reg signed-reg)) + (pop values) + (dpb (sc-case first-value + (unsigned-reg 1) + (signed-reg 2) + (t 0)) + (byte 2 5) + (tn-offset first-value))) + (t + zr-offset)) + (byte 8 8) + (if (= kind error-trap) + (+ kind code) + kind))) + (unless (= kind error-trap) + (inst byte code))))) + (encode-internal-error-args values) + (emit-alignment 2))) (defun generate-error-code (vop error-code &rest values) "Generate-Error-Code Error-code Value* @@ -309,42 +297,42 @@ other-pointer-lowtag))))) ;;; handy macro for making sequences look atomic -(defmacro pseudo-atomic ((flag-tn &key (sync t)) &body forms) +(defmacro pseudo-atomic ((flag-tn &key elide-if (sync t)) &body forms) (declare (ignorable sync)) - #+sb-safepoint-strictly + #+sb-safepoint `(progn ,@forms (emit-safepoint)) - #-sb-safepoint-strictly + #-sb-safepoint `(progn - (without-scheduling () - #-sb-thread - (store-symbol-value csp-tn *pseudo-atomic-atomic*) - #+sb-thread - (inst str (32-bit-reg null-tn) - (@ thread-tn - (* n-word-bytes thread-pseudo-atomic-bits-slot)))) + (unless ,elide-if + (without-scheduling () + #-sb-thread + (store-symbol-value csp-tn *pseudo-atomic-atomic*) + #+sb-thread + (inst str (32-bit-reg null-tn) + (@ thread-tn + (* n-word-bytes thread-pseudo-atomic-bits-slot))))) (assemble () ,@forms) - (without-scheduling () - #-sb-thread - (progn - (store-symbol-value null-tn *pseudo-atomic-atomic*) - (load-symbol-value ,flag-tn *pseudo-atomic-interrupted*)) - #+sb-thread - (progn - (when ,sync - (inst dmb)) - (inst str (32-bit-reg zr-tn) - (@ thread-tn - (* n-word-bytes thread-pseudo-atomic-bits-slot))) - (inst ldr (32-bit-reg ,flag-tn) - (@ thread-tn - (+ (* n-word-bytes thread-pseudo-atomic-bits-slot) 4)))) - (let ((not-interrputed (gen-label))) - (inst cbz ,flag-tn not-interrputed) - (inst brk pending-interrupt-trap) - (emit-label not-interrputed)) - #+sb-safepoint - (emit-safepoint)))) + (unless ,elide-if + (without-scheduling () + #-sb-thread + (progn + (store-symbol-value null-tn *pseudo-atomic-atomic*) + (load-symbol-value ,flag-tn *pseudo-atomic-interrupted*)) + #+sb-thread + (progn + (when ,sync + (inst dmb)) + (inst str (32-bit-reg zr-tn) + (@ thread-tn + (* n-word-bytes thread-pseudo-atomic-bits-slot))) + (inst ldr (32-bit-reg ,flag-tn) + (@ thread-tn + (+ (* n-word-bytes thread-pseudo-atomic-bits-slot) 4)))) + (let ((not-interrputed (gen-label))) + (inst cbz ,flag-tn not-interrputed) + (inst brk pending-interrupt-trap) + (emit-label not-interrputed)))))) ;;;; memory accessor vop generators @@ -357,7 +345,7 @@ (:args (object :scs (descriptor-reg)) (index :scs (any-reg immediate))) (:arg-types ,type tagged-num) - (:temporary (:scs (interior-reg)) lip) + (:temporary (:scs (non-descriptor-reg)) lip) (:results (value :scs ,scs)) (:result-types ,el-type) (:generator 5 @@ -378,11 +366,9 @@ (:policy :fast-safe) (:args (object :scs (descriptor-reg)) (index :scs (any-reg immediate)) - (value :scs ,scs :target result)) + (value :scs (,@scs zero))) (:arg-types ,type tagged-num ,el-type) - (:temporary (:scs (interior-reg)) lip) - (:results (result :scs ,scs)) - (:result-types ,el-type) + (:temporary (:scs (non-descriptor-reg)) lip) (:generator 2 (sc-case index (immediate @@ -391,8 +377,7 @@ ,lowtag))))) (t (inst add lip object (lsl index (- word-shift n-fixnum-tag-bits))) - (storew value lip ,offset ,lowtag))) - (move result value)))) + (storew value lip ,offset ,lowtag)))))) (defmacro define-partial-reffer (name type size signed offset lowtag scs el-type &optional translate) @@ -405,7 +390,7 @@ (:arg-types ,type tagged-num) (:results (value :scs ,scs)) (:result-types ,el-type) - (:temporary (:scs (interior-reg)) lip) + (:temporary (:scs (non-descriptor-reg)) lip) (:generator 5 ,@(multiple-value-bind (op shift) (ecase size @@ -414,7 +399,9 @@ (:short (values (if signed 'ldrsh 'ldrh) 1)) (:word - (values (if signed 'ldrsw 'ldr) 2))) + (values (if signed 'ldrsw 'ldr) 2)) + (:single-float + (values 'ldr 2))) (let ((value (if (and (eq size :word) (not signed)) '(32-bit-reg value) @@ -438,52 +425,60 @@ (defmacro define-partial-setter (name type size offset lowtag scs el-type &optional translate) - `(define-vop (,name) - ,@(when translate - `((:translate ,translate))) - (:policy :fast-safe) - (:args (object :scs (descriptor-reg)) - (index :scs (any-reg unsigned-reg immediate)) - (value :scs ,scs :target result)) - (:arg-types ,type tagged-num ,el-type) - (:temporary (:scs (interior-reg)) lip) - (:results (result :scs ,scs)) - (:result-types ,el-type) - (:generator 5 - ,@(multiple-value-bind (op shift) - (ecase size - (:byte - (values 'strb 0)) - (:short - (values 'strh 1)) - (:word - (values 'str 2))) - (let ((value (if (eq size :word) - '(32-bit-reg value) - 'value))) - `((sc-case index - (immediate - (inst ,op ,value (@ object (load-store-offset - (+ - (ash (tn-value index) ,shift) - (- (* ,offset n-word-bytes) ,lowtag)))))) - (t - (let ((shift ,shift)) - (sc-case index - (any-reg - (decf shift n-fixnum-tag-bits))) - (inst add lip object (if (minusp shift) - (asr index (- shift)) - (lsl index shift))) - (inst ,op - ,value (@ lip (- (* ,offset n-word-bytes) ,lowtag))))))))) - (move result value)))) - -(defun load-inline-constant (dst value &optional lip) - (destructuring-bind (size . label) (register-inline-constant value) - (ecase size - (:qword - (inst load-from-label dst label lip))))) + (let ((value `((value :scs ,scs + :load-if (not (and (sc-is value immediate) + (eql (tn-value value) 0)))))) + (setf-p (typep translate '(cons (eql setf))))) + `(define-vop (,name) + ,@(when translate + `((:translate ,translate))) + (:policy :fast-safe) + (:args ,@(when setf-p + value) + (object :scs (descriptor-reg)) + (index :scs (any-reg unsigned-reg immediate)) + ,@(unless setf-p + value)) + (:arg-types ,@(when setf-p + `(,el-type)) + ,type + tagged-num + ,@(unless setf-p + `(,el-type))) + (:temporary (:scs (non-descriptor-reg)) lip) + (:generator 5 + (when (sc-is value immediate) + (setf value zr-tn)) + ,@(multiple-value-bind (op shift) + (ecase size + (:byte + (values 'strb 0)) + (:short + (values 'strh 1)) + ((:word :single-float) + (values 'str 2))) + (let ((value (if (eq size :word) + '(32-bit-reg value) + 'value))) + `((sc-case index + (immediate + (inst ,op ,value (@ object (load-store-offset + (+ + (ash (tn-value index) ,shift) + (- (* ,offset n-word-bytes) ,lowtag)))))) + (t + (let ((shift ,shift)) + (sc-case index + (any-reg + (decf shift n-fixnum-tag-bits))) + (inst add lip object (if (minusp shift) + (asr index (- shift)) + (lsl index shift))) + (inst ,op + ,value (@ lip (- (* ,offset n-word-bytes) ,lowtag))))))))))))) + +(defun load-inline-constant (dst &rest constant-descriptor) + (inst load-from-label dst (cdr (apply #'register-inline-constant constant-descriptor)))) ;;; diff --git a/src/compiler/arm64/memory.lisp b/src/compiler/arm64/memory.lisp index d93c16b946..d754111f38 100644 --- a/src/compiler/arm64/memory.lisp +++ b/src/compiler/arm64/memory.lisp @@ -38,7 +38,7 @@ (old-value :scs (any-reg descriptor-reg)) (new-value :scs (any-reg descriptor-reg))) (:arg-types * tagged-num * *) - (:temporary (:sc interior-reg) lip) + (:temporary (:sc non-descriptor-reg) lip) (:results (result :scs (any-reg descriptor-reg) :from :load)) (:result-types *) (:variant-vars offset lowtag) @@ -46,18 +46,22 @@ (:generator 5 (inst add lip object (lsl index (- word-shift n-fixnum-tag-bits))) (inst add-sub lip lip (- (* offset n-word-bytes) lowtag)) - - (inst dsb) - LOOP - ;; If this were 'ldaxr' instead of 'ldxr' maybe we wouldn't need the 'dsb' ? - (inst ldxr result lip) - (inst cmp result old-value) - (inst b :ne EXIT) - (inst stlxr tmp-tn new-value lip) - (inst cbnz (32-bit-reg tmp-tn) LOOP) - EXIT - (inst clrex) - (inst dmb))) + (cond ((member :arm-v8.1 *backend-subfeatures*) + (move result old-value) + (inst casal result new-value lip)) + (t + (assemble () + (inst dsb) + LOOP + ;; If this were 'ldaxr' instead of 'ldxr' maybe we wouldn't need the 'dsb' ? + (inst ldxr result lip) + (inst cmp result old-value) + (inst b :ne EXIT) + (inst stlxr tmp-tn new-value lip) + (inst cbnz (32-bit-reg tmp-tn) LOOP) + EXIT + (inst clrex) + (inst dmb)))))) (define-vop (set-instance-hashed) (:args (object :scs (descriptor-reg))) @@ -66,7 +70,11 @@ (:generator 5 (inst sub baseptr object instance-pointer-lowtag) LOOP - (inst ldaxr header baseptr) - (inst orr header header (ash 1 stable-hash-required-flag)) - (inst stlxr tmp-tn header baseptr) - (inst cbnz (32-bit-reg tmp-tn) LOOP))) + (cond ((member :arm-v8.1 *backend-subfeatures*) + (inst movz header (ash 1 stable-hash-required-flag)) + (inst ldset header header baseptr)) + (t + (inst ldaxr header baseptr) + (inst orr header header (ash 1 stable-hash-required-flag)) + (inst stlxr tmp-tn header baseptr) + (inst cbnz (32-bit-reg tmp-tn) LOOP))))) diff --git a/src/compiler/arm64/move.lisp b/src/compiler/arm64/move.lisp index 34f65e13b2..d7d514f307 100644 --- a/src/compiler/arm64/move.lisp +++ b/src/compiler/arm64/move.lisp @@ -11,41 +11,103 @@ (in-package "SB-VM") -(defun load-immediate-word (y val) - (cond ((typep val '(unsigned-byte 16)) - (inst movz y val)) - ((typep val '(and (signed-byte 16) (integer * -1))) - (inst movn y (lognot val))) - ((typep (ldb (byte 64 0) (lognot val)) '(unsigned-byte 16)) - (inst movn y (ldb (byte 64 0) (lognot val)))) - ((encode-logical-immediate val) - (inst orr y zr-tn val)) - ((loop for i below 64 by 16 - for part = (ldb (byte 16 i) val) - for zeroed = (dpb 0 (byte 16 i) val) - thereis (cond ((encode-logical-immediate zeroed) - (inst orr y zr-tn zeroed) - (inst movk y part i) - t)))) - ((minusp val) - (loop with first = t - for i below 64 by 16 - for part = (ldb (byte 16 i) val) - unless (= part #xFFFF) - do - (if (shiftf first nil) - (inst movn y (ldb (byte 16 0) (lognot part)) i) - (inst movk y part i)))) - (t - (loop with first = t - for i below 64 by 16 - for part = (ldb (byte 16 i) val) - when (plusp part) - do - (if (shiftf first nil) - (inst movz y part i) - (inst movk y part i))))) - y) +(defun load-immediate-word (y val &optional single-instruction) + (let (single-mov + ffff-count + zero-count + (val (ldb (byte 64 0) val))) + (flet ((single-mov () + (loop for i below 64 by 16 + for part = (ldb (byte 16 i) val) + count (/= part #xFFFF) into ffff + count (plusp part) into zero + finally + (setf ffff-count ffff + zero-count zero + single-mov (or (= ffff 1) + (= zero 1)))))) + (cond ((typep val '(unsigned-byte 16)) + (inst movz y val) + y) + ((typep (ldb (byte 64 0) (lognot val)) '(unsigned-byte 16)) + (inst movn y (ldb (byte 64 0) (lognot val))) + y) + ((encode-logical-immediate val) + (inst orr y zr-tn val) + y) + ((and + (not (single-mov)) + (not single-instruction) + (let ((descriptorp (memq (tn-offset y) descriptor-regs))) + (flet ((try (i part fill) + (let ((filled (dpb fill (byte 16 i) val))) + (cond ((and (encode-logical-immediate filled) + (not (and descriptorp + (logtest filled fixnum-tag-mask)))) + (inst orr y zr-tn filled) + (inst movk y part i) + t))))) + (loop for i below 64 by 16 + for part = (ldb (byte 16 i) val) + thereis (or (try i part #xFFFF) + (try i part 0) + (try i part + (ldb (byte 16 (mod (+ i 16) 64)) + val))))))) + y) + ((and (not single-mov) + (not single-instruction) + (let ((a (ldb (byte 16 0) val)) + (b (ldb (byte 16 16) val)) + (c (ldb (byte 16 32) val)) + (d (ldb (byte 16 48) val))) + (let ((descriptorp (memq (tn-offset y) descriptor-regs))) + (flet ((try (part val1 hole1 val2 hole2) + (let* ((whole (dpb part (byte 16 16) part)) + (whole (dpb whole (byte 32 32) whole))) + (when (and (encode-logical-immediate whole) + (not (and descriptorp + (logtest whole fixnum-tag-mask)))) + (inst orr y zr-tn whole) + (inst movk y val1 hole1) + (inst movk y val2 hole2) + t)))) + (cond ((= a b) + (try a c 32 d 48)) + ((= a c) + (try a b 16 d 48)) + ((= a d) + (try a b 16 c 32)) + ((= b c) + (try b a 0 d 48)) + ((= b d) + (try b a 0 c 32)) + ((= c d) + (try c a 0 b 16))))))) + y) + ((and (< ffff-count zero-count) + (or single-mov + (not single-instruction))) + (loop with first = t + for i below 64 by 16 + for part = (ldb (byte 16 i) val) + unless (= part #xFFFF) + do + (if (shiftf first nil) + (inst movn y (ldb (byte 16 0) (lognot part)) i) + (inst movk y part i))) + y) + ((or single-mov + (not single-instruction)) + (loop with first = t + for i below 64 by 16 + for part = (ldb (byte 16 i) val) + when (plusp part) + do + (if (shiftf first nil) + (inst movz y part i) + (inst movk y part i))) + y))))) (defun add-sub-immediate (x &optional (temp tmp-tn)) (cond ((not (integerp x)) @@ -66,8 +128,12 @@ (load-immediate-word y (fixnumize val))) (character (let* ((codepoint (char-code val)) - (encoded-character (dpb codepoint (byte 24 8) character-widetag))) - (load-immediate-word y encoded-character))) + (tagged (dpb codepoint (byte 24 8) character-widetag))) + (load-immediate-word y tagged))) + (single-float + (let* ((bits (single-float-bits val)) + (tagged (dpb bits (byte 32 32) single-float-widetag))) + (load-immediate-word y tagged))) (symbol (load-symbol y val))))) @@ -90,13 +156,7 @@ (define-move-fun (load-constant 5) (vop x y) ((constant) (descriptor-reg)) - (let ((offset (- (tn-byte-offset x) other-pointer-lowtag))) - (cond - ((ldr-str-offset-encodable offset) - (inst ldr y (@ code-tn offset))) - (t - (load-immediate-word tmp-tn offset) - (inst ldr y (@ code-tn tmp-tn)))))) + (inst load-constant y (tn-byte-offset x))) (define-move-fun (load-stack 5) (vop x y) ((control-stack) (any-reg descriptor-reg)) @@ -127,6 +187,7 @@ :scs (any-reg descriptor-reg) :load-if (not (or (location= x y) (and (sc-is x immediate) + (sc-is y control-stack) (eql (tn-value x) 0)))))) (:results (y :scs (any-reg descriptor-reg control-stack) :load-if (not (location= x y)))) @@ -149,7 +210,10 @@ ;;; frame for argument or known value passing. (define-vop (move-arg) (:args (x :target y - :scs (any-reg descriptor-reg)) + :scs (any-reg descriptor-reg) + :load-if (not (and (sc-is x immediate) + (sc-is y control-stack) + (eql (tn-value x) 0)))) (fp :scs (any-reg) :load-if (not (sc-is y any-reg descriptor-reg)))) (:results (y)) @@ -158,7 +222,11 @@ ((any-reg descriptor-reg) (move y x)) (control-stack - (store-stack-offset x fp y))))) + (store-stack-offset (if (and (sc-is x immediate) + (eql (tn-value x) 0)) + zr-tn + x) + fp y))))) ;;; (define-move-vop move-arg :move-arg (any-reg descriptor-reg) @@ -175,11 +243,11 @@ (and (tn-p tn) (sc-is tn control-stack))) (source (vop) - (tn-ref-tn (sb-c::vop-args vop))) + (tn-ref-tn (vop-args vop))) (dest (vop) - (tn-ref-tn (sb-c::vop-results vop))) + (tn-ref-tn (vop-results vop))) (load-tn (vop) - (tn-ref-load-tn (sb-c::vop-args vop))) + (tn-ref-load-tn (vop-args vop))) (suitable-offsets-p (tn1 tn2) (and (= (abs (- (tn-offset tn1) (tn-offset tn2))) @@ -287,8 +355,8 @@ '(load-stack store-stack))) (do-moves (source vop1) (source vop2) (dest vop1) (dest vop2))))) (move-arg - (let ((fp1 (tn-ref-tn (tn-ref-across (sb-c::vop-args vop1)))) - (fp2 (tn-ref-tn (tn-ref-across (sb-c::vop-args vop2)))) + (let ((fp1 (tn-ref-tn (tn-ref-across (vop-args vop1)))) + (fp2 (tn-ref-tn (tn-ref-across (vop-args vop2)))) (dest1 (dest vop1)) (dest2 (dest vop2))) (when (eq fp1 fp2) @@ -297,7 +365,7 @@ (stack-p dest2)) fp1 cfp-tn) - (tn-ref-load-tn (tn-ref-across (sb-c::vop-args vop1))))))))))) + (tn-ref-load-tn (tn-ref-across (vop-args vop1))))))))))) ;;;; ILLEGAL-MOVE @@ -351,18 +419,18 @@ ;;; ARG is a fixnum or bignum; figure out which and load if necessary. (define-vop (move-to-word/integer) (:args (x :scs (descriptor-reg))) + (:results-var results) (:results (y :scs (signed-reg unsigned-reg))) (:note "integer to untagged word coercion") (:generator 4 #.(assert (= fixnum-tag-mask 1)) - (inst tbnz x 0 BIGNUM) - (sc-case y - (signed-reg - (inst asr y x n-fixnum-tag-bits)) - (unsigned-reg - (inst lsr y x n-fixnum-tag-bits))) - (inst b DONE) - BIGNUM + (when (types-equal-or-intersect (tn-ref-type results) (specifier-type 'fixnum)) + (sc-case y + (signed-reg + (inst asr y x n-fixnum-tag-bits)) + (unsigned-reg + (inst lsr y x n-fixnum-tag-bits))) + (inst tbz x 0 DONE)) (loadw y x bignum-digits-offset other-pointer-lowtag) DONE)) @@ -388,15 +456,18 @@ (:args (arg :scs (signed-reg unsigned-reg) :target x)) (:results (y :scs (any-reg descriptor-reg))) (:temporary (:scs (non-descriptor-reg) :from (:argument 0)) x) - (:temporary (:sc non-descriptor-reg) pa-flag) - (:temporary (:scs (interior-reg)) lip) + (:temporary (:sc non-descriptor-reg :offset lr-offset) lr) (:note "signed word to integer coercion") (:generator 20 (move x arg) (inst adds y x x) (inst b :vc DONE) - (with-fixed-allocation (y pa-flag bignum-widetag (1+ bignum-digits-offset) :lip lip) - (storew x y bignum-digits-offset other-pointer-lowtag)) + (with-fixed-allocation (y lr bignum-widetag (1+ bignum-digits-offset) + :store-type-code nil) + ;; TMP-TN has the untagged address coming from ALLOCATION + ;; that way STP can be used on an aligned address. + ;; LR has the widetag computed by WITH-FIXED-ALLOCATION + (storew-pair lr 0 x bignum-digits-offset tmp-tn)) DONE)) (define-move-vop move-from-signed :move (signed-reg) (descriptor-reg)) @@ -408,7 +479,7 @@ (:generator 4 (inst adds y x x) (inst b :vc DONE) - (load-constant vop (emit-constant (1+ sb-xc:most-positive-fixnum)) + (load-constant vop (emit-constant (1+ most-positive-fixnum)) y) DONE)) @@ -416,7 +487,7 @@ (:generator 4 (inst adds y x x) (inst b :vc DONE) - (load-constant vop (emit-constant (1- sb-xc:most-negative-fixnum)) + (load-constant vop (emit-constant (1- most-negative-fixnum)) y) DONE)) @@ -427,8 +498,7 @@ (:args (arg :scs (signed-reg unsigned-reg) :target x)) (:results (y :scs (any-reg descriptor-reg))) (:temporary (:scs (non-descriptor-reg) :from (:argument 0)) x) - (:temporary (:sc non-descriptor-reg) pa-flag) - (:temporary (:scs (interior-reg)) lip) + (:temporary (:sc non-descriptor-reg :offset lr-offset) lr) (:note "unsigned word to integer coercion") (:generator 20 (move x arg) @@ -439,18 +509,18 @@ (inst b :eq DONE) (with-fixed-allocation - (y pa-flag bignum-widetag (+ 2 bignum-digits-offset) :lip lip) + (y lr bignum-widetag (+ 2 bignum-digits-offset) + :store-type-code nil) ;; WITH-FIXED-ALLOCATION, when using a supplied type-code, - ;; leaves PA-FLAG containing the computed header value. In our + ;; leaves LR containing the computed header value. In our ;; case, configured for a 2-word bignum. If the sign bit in the ;; value we're boxing is CLEAR, we need to shrink the bignum by ;; one word, hence the following: - (inst tst x x) - (inst b :mi STORE) - (inst sub pa-flag pa-flag #x100) - (storew pa-flag y 0 other-pointer-lowtag) + (inst tbnz x (1- n-word-bits) STORE) + (load-immediate-word lr (bignum-header-for-length 1)) STORE - (storew x y bignum-digits-offset other-pointer-lowtag)) + ;; See the comment in move-from-signed + (storew-pair lr 0 x bignum-digits-offset tmp-tn)) DONE)) (define-move-vop move-from-unsigned :move (unsigned-reg) (descriptor-reg)) @@ -491,3 +561,13 @@ ;;; descriptor passing location. (define-move-vop move-arg :move-arg (signed-reg unsigned-reg) (any-reg descriptor-reg)) + +(define-vop (move-conditional-result) + (:results (res :scs (descriptor-reg))) + (:info true) + (:generator 1 + (move res null-tn) + (inst b done) + (emit-label true) + (load-symbol res t) + done)) diff --git a/src/compiler/arm64/nlx.lisp b/src/compiler/arm64/nlx.lisp index 591e455549..94766259e0 100644 --- a/src/compiler/arm64/nlx.lisp +++ b/src/compiler/arm64/nlx.lisp @@ -15,7 +15,7 @@ ;;; Make a TN for the argument count passing location for a ;;; non-local entry. (defun make-nlx-entry-arg-start-location () - (make-wired-tn *fixnum-primitive-type* immediate-arg-scn r8-offset)) + (make-wired-tn *fixnum-primitive-type* immediate-arg-scn r9-offset)) ;;; Save and restore dynamic environment. (define-vop (current-stack-pointer) @@ -48,14 +48,13 @@ (:info entry-label) (:results (block :scs (any-reg))) (:temporary (:scs (descriptor-reg)) temp) - (:temporary (:scs (interior-reg)) lip) (:vop-var vop) (:generator 22 (inst add block cfp-tn (add-sub-immediate (tn-byte-offset tn))) (load-tl-symbol-value temp *current-unwind-protect-block*) (storew-pair temp unwind-block-uwp-slot cfp-tn unwind-block-cfp-slot block) - (inst compute-lra temp lip entry-label) - (storew-pair code-tn unwind-block-code-slot temp unwind-block-entry-pc-slot block) + (inst adr temp entry-label) + (storew temp block unwind-block-entry-pc-slot) #+sb-thread (loadw-pair temp (/ (info :variable :wired-tls '*binding-stack-pointer*) n-word-bytes) @@ -67,9 +66,12 @@ (load-tl-symbol-value tmp-tn *current-catch-block*)) (storew-pair temp unwind-block-bsp-slot tmp-tn unwind-block-current-catch-slot block) (inst mov-sp temp nsp-tn) - (storew-pair (or (current-nfp-tn vop) zr-tn) unwind-block-nfp-slot - temp unwind-block-nsp-slot - block))) + (let ((nfp (current-nfp-tn vop))) + (if nfp + (storew-pair nfp unwind-block-nfp-slot + temp unwind-block-nsp-slot + block) + (storew temp block unwind-block-nsp-slot))))) ;;; Like Make-Unwind-Block, except that we also store in the specified tag, and ;;; link the block into the Current-Catch list. @@ -79,14 +81,13 @@ (:info entry-label) (:results (block :scs (any-reg))) (:temporary (:scs (descriptor-reg)) temp) - (:temporary (:scs (interior-reg)) lip) (:vop-var vop) (:generator 44 (inst add block cfp-tn (add-sub-immediate (tn-byte-offset tn))) (load-tl-symbol-value temp *current-unwind-protect-block*) (storew-pair temp catch-block-uwp-slot cfp-tn catch-block-cfp-slot block) - (inst compute-lra temp lip entry-label) - (storew-pair code-tn catch-block-code-slot temp catch-block-entry-pc-slot block) + (inst adr temp entry-label) + (storew temp block catch-block-entry-pc-slot) #+sb-thread (loadw-pair @@ -100,9 +101,12 @@ (storew-pair tmp-tn catch-block-previous-catch-slot tag catch-block-tag-slot block) (storew temp block catch-block-bsp-slot) (inst mov-sp temp nsp-tn) - (storew-pair (or (current-nfp-tn vop) zr-tn) unwind-block-nfp-slot - temp unwind-block-nsp-slot - block) + (let ((nfp (current-nfp-tn vop))) + (if nfp + (storew-pair nfp unwind-block-nfp-slot + temp unwind-block-nsp-slot + block) + (storew temp block unwind-block-nsp-slot))) (store-tl-symbol-value block *current-catch-block*))) ;;; Just set the current unwind-protect to UWP. This @@ -136,7 +140,7 @@ (define-vop (nlx-entry) (:args (sp) ; Note: we can't list an sc-restriction, 'cause any load vops - ; would be inserted before the LRA. + ; would be inserted before the label. (start) (count)) (:results (values :more t :from :load)) @@ -145,7 +149,7 @@ (:save-p :force-to-stack) (:vop-var vop) (:generator 30 - (emit-return-pc label) + (emit-label label) (note-this-location vop :non-local-entry) (cond ((zerop nvals)) ((= nvals 1) @@ -176,12 +180,24 @@ (store-stack-tn tn move-temp)))))))) (load-stack-tn csp-tn sp))) +(define-vop (nlx-entry-single) + (:args (sp) + (value)) + (:results (res :from :load)) + (:info label) + (:save-p :force-to-stack) + (:vop-var vop) + (:generator 30 + (emit-label label) + (note-this-location vop :non-local-entry) + (inst mov res value) + (load-stack-tn csp-tn sp))) + (define-vop (nlx-entry-multiple) - (:args (top :target result) - (src) + (:args (top :target result + :scs (any-reg)) + (src :to :save) (count :target count-words)) - ;; Again, no SC restrictions for the args, 'cause the loading would - ;; happen before the entry label. (:info label) (:temporary (:scs (any-reg)) dst) (:temporary (:scs (descriptor-reg)) temp) @@ -190,12 +206,17 @@ (num :scs (any-reg) :from (:argument 0))) (:save-p :force-to-stack) (:vop-var vop) + (:before-load + (emit-label label) + (note-this-location vop :non-local-entry)) (:generator 30 - (emit-return-pc label) - (note-this-location vop :non-local-entry) ;; Setup results, and test for the zero value case. - (load-stack-tn result top) + (if (eq (tn-kind result) :unused) + (setf result top) + (move result top)) + (when (eq (tn-kind num) :unused) + (setf num tmp-tn)) (inst mov num 0) ;; Shift and check for zero in one go (inst adds count-words zr-tn (lsl count (- word-shift n-fixnum-tag-bits))) @@ -216,41 +237,51 @@ ;; Reset the CSP. DONE (inst add csp-tn result num) - (inst lsr num num (- word-shift n-fixnum-tag-bits)))) + (unless (eq (tn-kind num) :unused) + (inst lsr num num (- word-shift n-fixnum-tag-bits))))) ;;; This VOP is just to force the TNs used in the cleanup onto the stack. ;;; (define-vop (uwp-entry) (:info label) (:save-p :force-to-stack) - (:results (block) (start) (count)) - (:ignore block start count) (:vop-var vop) (:generator 0 - (emit-return-pc label) + (emit-label label) (note-this-location vop :non-local-entry))) -;;; Doesn't handle NSP and is disabled. +(define-vop (uwp-entry-block) + (:info label) + (:save-p :force-to-stack) + (:results (block)) + (:vop-var vop) + (:generator 0 + (emit-label label) + (note-this-location vop :non-local-entry) + ;; Get the block saved in UNWIND + (inst ldr block (@ csp-tn (* -4 n-word-bytes))))) + #+unwind-to-frame-and-call-vop (define-vop (unwind-to-frame-and-call) (:args (ofp :scs (descriptor-reg)) (uwp :scs (descriptor-reg)) (function :scs (descriptor-reg) :to :load :target saved-function) (bsp :scs (any-reg descriptor-reg)) + (nsp :scs (any-reg descriptor-reg)) (catch-block :scs (any-reg descriptor-reg))) - (:arg-types system-area-pointer system-area-pointer t t t) + (:arg-types system-area-pointer system-area-pointer t t t t) (:temporary (:sc unsigned-reg) temp) - (:temporary (:sc descriptor-reg :offset r8-offset) saved-function) + (:temporary (:sc descriptor-reg :offset r9-offset) saved-function) (:temporary (:sc unsigned-reg :offset r0-offset) block) (:temporary (:sc descriptor-reg :offset lexenv-offset) lexenv) - (:temporary (:scs (interior-reg)) lip) + (:temporary (:scs (non-descriptor-reg) :offset lr-offset) lr) (:temporary (:sc descriptor-reg :offset nargs-offset) nargs) (:vop-var vop) (:generator 22 (let ((entry-label (gen-label))) ;; Store the function into a non-stack location, since we'll be ;; unwinding the stack and destroying register contents before we - ;; use it. It turns out that R8 is preserved as part of the + ;; use it. It turns out that R9 is preserved as part of the ;; normal multiple-value handling of an unwind, so use that. (move saved-function function) @@ -265,22 +296,21 @@ (loadw temp ofp sap-pointer-slot other-pointer-lowtag) (storew temp block unwind-block-cfp-slot) (storew bsp block unwind-block-bsp-slot) + (storew nsp block unwind-block-nsp-slot) (storew catch-block block unwind-block-current-catch-slot) - ;; Don't need to save code at unwind-block-code-slot since - ;; it's not going to be used and will be overwritten after the - ;; function call - (inst compute-lra temp lip entry-label) + (inst adr temp entry-label) (storew temp block catch-block-entry-pc-slot) ;; Run any required UWPs. - (load-inline-constant tmp-tn '(:fixup unwind :assembly-routine) lip) + (load-inline-constant tmp-tn '(:fixup unwind :assembly-routine)) (inst br tmp-tn) - (emit-return-pc ENTRY-LABEL) + (emit-label ENTRY-LABEL) (inst mov nargs 0) (move lexenv saved-function) - (loadw saved-function lexenv closure-fun-slot fun-pointer-lowtag) - (lisp-jump saved-function lip)))) + (loadw lr lexenv closure-fun-slot fun-pointer-lowtag) + (lisp-jump lr)))) + diff --git a/src/compiler/arm64/parms.lisp b/src/compiler/arm64/parms.lisp index 0c70da8ffa..b3c43ceb94 100644 --- a/src/compiler/arm64/parms.lisp +++ b/src/compiler/arm64/parms.lisp @@ -24,7 +24,7 @@ ;;; The size in bytes of GENCGC cards, i.e. the granularity at which ;;; writes to old generations are logged. With mprotect-based write ;;; barriers, this must be a multiple of the OS page size. -(defconstant gencgc-card-bytes +backend-page-bytes+) +(defconstant gencgc-page-bytes +backend-page-bytes+) ;;; The minimum size of new allocation regions. While it doesn't ;;; currently make a lot of sense to have a card size lower than ;;; the alloc granularity, it will, once we are smarter about finding @@ -41,35 +41,6 @@ ;;; address space) (defconstant n-machine-word-bits 64) -;;; Floating-point related constants, both format descriptions and FPU -;;; control register descriptions. These don't exactly match up with -;;; what the machine manuals say because the Common Lisp standard -;;; defines floating-point values somewhat differently than the IEEE -;;; standard does. - -(defconstant float-sign-shift 31) - -(defconstant single-float-bias 126) -(defconstant-eqx single-float-exponent-byte (byte 8 23) #'equalp) -(defconstant-eqx single-float-significand-byte (byte 23 0) #'equalp) -(defconstant single-float-normal-exponent-min 1) -(defconstant single-float-normal-exponent-max 254) -(defconstant single-float-hidden-bit (ash 1 23)) - -(defconstant double-float-bias 1022) -(defconstant-eqx double-float-exponent-byte (byte 11 20) #'equalp) -(defconstant-eqx double-float-significand-byte (byte 20 0) #'equalp) -(defconstant double-float-normal-exponent-min 1) -(defconstant double-float-normal-exponent-max #x7FE) -(defconstant double-float-hidden-bit (ash 1 20)) - -(defconstant single-float-digits - (+ (byte-size single-float-significand-byte) 1)) - -(defconstant double-float-digits - (+ (byte-size double-float-significand-byte) 32 1)) - - (progn (defconstant float-invalid-trap-bit (ash 1 0)) (defconstant float-divide-by-zero-trap-bit (ash 1 1)) @@ -93,26 +64,15 @@ ;;;; Where to put the different spaces. -;;; On non-gencgc we need large dynamic and static spaces for PURIFY -#-gencgc -(progn - (defconstant read-only-space-start #x04000000) - (defconstant read-only-space-end #x07ff8000) - (defconstant static-space-start #x08000000) - (defconstant static-space-end #x097fff00) - - (defconstant linkage-table-space-start #x0a000000) - (defconstant linkage-table-space-end #x0b000000) - #+linux - (progn - (defparameter dynamic-0-space-start #x4f000000) - (defparameter dynamic-0-space-end #x66fff000))) - -#+gencgc -(!gencgc-space-setup #xF0000000 :dynamic-space-start #x1000000000) - -(defconstant linkage-table-growth-direction :up) -(defconstant linkage-table-entry-size 16) +(!gencgc-space-setup #+(or linux openbsd freebsd) #xF0000000 + #+darwin #x300000000 + #+netbsd #x2F0000000 + :dynamic-space-start + #-darwin #x1000000000 + #+darwin #x7003000000) + +(defconstant alien-linkage-table-growth-direction :up) +(defconstant alien-linkage-table-entry-size 16) ;;;; other miscellaneous constants @@ -142,7 +102,6 @@ ,@'(*binding-stack-pointer* *pseudo-atomic-atomic* *pseudo-atomic-interrupted*) - *allocation-pointer* ;; interrupt handling ,@+common-static-symbols+) #'equalp) @@ -163,5 +122,3 @@ ;;; The number of bits per element in the assemblers code vector. ;;; (defparameter *assembly-unit-length* 8) - -(defvar *allocation-pointer*) diff --git a/src/compiler/arm64/pred.lisp b/src/compiler/arm64/pred.lisp index 699a171f9c..853af0468c 100644 --- a/src/compiler/arm64/pred.lisp +++ b/src/compiler/arm64/pred.lisp @@ -30,19 +30,87 @@ (define-vop (branch-if) (:info dest not-p flags) (:generator 0 - (flet ((negate-condition (name) - (let ((code (logxor 1 (conditional-opcode name)))) - (aref +condition-name-vec+ code)))) (aver (null (rest flags))) (inst b (if not-p (negate-condition (first flags)) (first flags)) - dest)))) + dest))) + +(define-load-time-global *cmov-ptype-representation-vop* + (mapcan (lambda (entry) + (destructuring-bind (ptypes &optional sc vop) + entry + (mapcar (if (and vop sc) + (lambda (ptype) + (list ptype sc vop)) + #'list) + (ensure-list ptypes)))) + '((t descriptor-reg move-if/descriptor) + ((fixnum positive-fixnum) any-reg move-if/descriptor) + ((unsigned-byte-64 unsigned-byte-63) unsigned-reg move-if/word) + (signed-byte-64 signed-reg move-if/word) + (character character-reg move-if/char) + ((single-float complex-single-float + double-float complex-double-float)) + (system-area-pointer sap-reg move-if/sap)))) (defun convert-conditional-move-p (node dst-tn x-tn y-tn) - (declare (ignore node dst-tn x-tn y-tn)) - nil) + (declare (ignore node)) + (let* ((ptype (sb-c::tn-primitive-type dst-tn)) + (name (sb-c:primitive-type-name ptype)) + (param (cdr (or (assoc name *cmov-ptype-representation-vop*) + '(t descriptor-reg move-if/descriptor))))) + (when param + (destructuring-bind (representation vop) param + (let ((scn (sc-number-or-lose representation))) + (labels ((make-tn (tn) + (cond ((and (tn-sc tn) + (or + (and + (sc-is tn immediate) + (eq (tn-value tn) 0)) + (and + (sc-is tn descriptor-reg) + (eql (tn-offset tn) null-offset)))) + tn) + (t + (make-representation-tn ptype scn))))) + (values vop + (make-tn x-tn) (make-tn y-tn) + (make-tn dst-tn) + nil))))))) + + +(define-vop (move-if) + (:args (then) (else)) + (:results (res)) + (:info flags) + (:generator 0 + (let ((not-p (eq (first flags) 'not))) + (when not-p (pop flags)) + (cond ((null (rest flags)) + (inst csel res then else (if not-p + (negate-condition (car flags)) + (car flags)))) + (not-p + (dolist (flag flags) + (inst csel res else then flag))) + (t + (dolist (flag flags) + (inst csel res then else flag))))))) + +(macrolet ((def-move-if (name type reg) + `(define-vop (,name move-if) + (:args (then :scs ,reg) + (else :scs ,reg)) + (:arg-types ,type ,type) + (:results (res :scs ,reg)) + (:result-types ,type)))) + (def-move-if move-if/descriptor * (descriptor-reg any-reg zero)) + (def-move-if move-if/word (:or unsigned-num signed-num) (unsigned-reg signed-reg zero)) + (def-move-if move-if/char character (character-reg zero)) + (def-move-if move-if/sap system-area-pointer (sap-reg zero))) ;;;; Conditional VOPs: @@ -53,25 +121,29 @@ :load-if (sc-case y ((any-reg descriptor-reg)) (immediate - (not (fixnum-add-sub-immediate-p (tn-value y)))) + (not (or + (eql (tn-value y) $0f0) + (and (integerp (tn-value y)) + (abs-add-sub-immediate-p (fixnumize (tn-value y))))))) (t t)))) - (:conditional) - (:info target not-p) + (:conditional :eq) (:policy :fast-safe) (:translate eq) - (:generator 6 - (cond ((not (and (sc-is y immediate) - (eql 0 (tn-value y)))) - (inst cmp x - (sc-case y + (:generator 7 + (let ((value (sc-case y (immediate - (fixnumize (tn-value y))) - (t y))) - (inst b (if not-p :ne :eq) target)) - (not-p - (inst cbnz x target)) - (t - (inst cbz x target))))) + (let ((value (tn-value y))) + (if (eql value $0f0) + single-float-widetag + (fixnumize (tn-value y))))) + (t y)))) + (cond ((or (not (integerp value)) + (add-sub-immediate-p value)) + (inst cmp x value)) + ((minusp value) + (inst cmn x (- value))) + (t + (inst cmn x (ldb (byte n-word-bits 0) (- value)))))))) (macrolet ((def (eq-name eql-name cost) `(define-vop (,eq-name ,eql-name) @@ -79,9 +151,7 @@ (:variant-cost ,cost)))) (def fast-if-eq-character fast-char=/character 3) (def fast-if-eq-character/c fast-char=/character/c 2) - (def fast-if-eq-fixnum fast-eql/fixnum 3) - (def fast-if-eq-fixnum/c fast-eql-c/fixnum 2) + (def fast-if-eq-fixnum fast-if-eql/fixnum 3) + (def fast-if-eq-integer/c fast-if-eql-integer/c 2) (def fast-if-eq-signed fast-if-eql/signed 5) - (def fast-if-eq-signed/c fast-if-eql-c/signed 4) - (def fast-if-eq-unsigned fast-if-eql/unsigned 5) - (def fast-if-eq-unsigned/c fast-if-eql-c/unsigned 4)) + (def fast-if-eq-unsigned fast-if-eql/unsigned 5)) diff --git a/src/compiler/arm64/sap.lisp b/src/compiler/arm64/sap.lisp index 447c842238..731695b1f4 100644 --- a/src/compiler/arm64/sap.lisp +++ b/src/compiler/arm64/sap.lisp @@ -29,13 +29,13 @@ ;;; Move an untagged SAP to a tagged representation. (define-vop (move-from-sap) (:args (sap :scs (sap-reg) :to :save)) - (:temporary (:sc non-descriptor-reg) pa-flag) - (:temporary (:scs (interior-reg)) lip) + (:temporary (:scs (non-descriptor-reg) :offset lr-offset) lr) (:results (res :scs (descriptor-reg))) (:note "SAP to pointer coercion") (:generator 20 - (with-fixed-allocation (res pa-flag sap-widetag sap-size :lip lip) - (storew sap res sap-pointer-slot other-pointer-lowtag)))) + (with-fixed-allocation (res lr sap-widetag sap-size + :store-type-code nil) + (storew-pair lr 0 sap sap-pointer-slot tmp-tn)))) (define-move-vop move-from-sap :move (sap-reg) (descriptor-reg)) @@ -157,39 +157,65 @@ (:results (result :scs (,sc))) (:result-types ,type) (:generator 5 - (inst ,(case size - (:byte (if signed 'ldrsb 'ldrb)) - (:short (if signed 'ldrsh 'ldrh)) - (:word (if signed 'ldrsw 'ldr)) - (t 'ldr)) - ,(if (eq size :word) - '(32-bit-reg result) - 'result) - (@ sap offset)))) + (inst ,(case size + (:byte (if signed 'ldrsb 'ldrb)) + (:short (if signed 'ldrsh 'ldrh)) + (:word (if signed 'ldrsw 'ldr)) + (t 'ldr)) + ,(if (eq size :word) + '(32-bit-reg result) + 'result) + (@ sap offset)))) (define-vop (,set-name) (:translate ,set-name) (:policy :fast-safe) - (:args (sap :scs (sap-reg)) - (offset :scs (signed-reg)) - (value :scs (,sc) :target result)) - (:arg-types system-area-pointer signed-num ,type) - (:results (result :scs (,sc))) - (:result-types ,type) + (:args (value :scs (,sc zero)) + (sap :scs (sap-reg)) + (offset :scs (signed-reg))) + (:arg-types ,type system-area-pointer signed-num) (:generator 5 - (inst ,(case size - (:byte 'strb) - (:short 'strh) - (t 'str)) - ,(if (eq size :word) - '(32-bit-reg value) - 'value) - (@ sap offset)) - (unless (location= result value) - ,@(case size - ((:single :double) - '((inst fmov result value))) - (t - '((inst mov result value)))))))))) + (inst ,(case size + (:byte 'strb) + (:short 'strh) + (t 'str)) + ,(if (eq size :word) + '(32-bit-reg value) + 'value) + (@ sap offset)))) + (define-vop (,(symbolicate ref-name "-C")) + (:translate ,ref-name) + (:policy :fast-safe) + (:args (sap :scs (sap-reg))) + (:info offset) + (:arg-types system-area-pointer (:constant (satisfies ldr-str-offset-encodable))) + (:RESULTS (result :scs (,sc))) + (:result-types ,type) + (:generator 4 + (inst ,(case size + (:byte (if signed 'ldrsb 'ldrb)) + (:short (if signed 'ldrsh 'ldrh)) + (:word (if signed 'ldrsw 'ldr)) + (t 'ldr)) + ,(if (eq size :word) + '(32-bit-reg result) + 'result) + (@ sap offset)))) + (define-vop (,(symbolicate set-name "-C")) + (:translate ,set-name) + (:policy :fast-safe) + (:args (value :scs (,sc zero)) + (sap :scs (sap-reg))) + (:info offset) + (:arg-types ,type system-area-pointer (:constant (satisfies ldr-str-offset-encodable))) + (:generator 4 + (inst ,(case size + (:byte 'strb) + (:short 'strh) + (t 'str)) + ,(if (eq size :word) + '(32-bit-reg value) + 'value) + (@ sap offset))))))) (def-system-ref-and-set sap-ref-8 %set-sap-ref-8 unsigned-reg positive-fixnum :byte :signed nil) (def-system-ref-and-set signed-sap-ref-8 %set-signed-sap-ref-8 diff --git a/src/compiler/arm64/show.lisp b/src/compiler/arm64/show.lisp index 8435b35b5c..02945a2a34 100644 --- a/src/compiler/arm64/show.lisp +++ b/src/compiler/arm64/show.lisp @@ -12,15 +12,13 @@ (in-package "SB-VM") - (define-vop (print) (:args (object :scs (descriptor-reg any-reg) :target nl0)) (:results (result :scs (descriptor-reg))) (:save-p t) (:temporary (:sc any-reg :offset nl0-offset :from (:argument 0)) nl0) - (:temporary (:sc any-reg :offset r8-offset) cfunc) - (:temporary (:scs (non-descriptor-reg)) temp) - (:temporary (:scs (interior-reg)) lip) + (:temporary (:sc any-reg :offset r9-offset) cfunc) + (:temporary (:sc non-descriptor-reg :offset lr-offset) lr) (:temporary (:sc control-stack :offset nfp-save-offset) nfp-save) (:vop-var vop) (:generator 100 @@ -28,9 +26,9 @@ (when cur-nfp (store-stack-tn nfp-save cur-nfp)) (move nl0 object) - (load-inline-constant temp '(:fixup "call_into_c" :foreign) lip) - (load-inline-constant cfunc '(:fixup "debug_print" :foreign) lip) - (inst blr temp) + (load-inline-constant lr '(:fixup "call_into_c" :foreign)) + (load-inline-constant cfunc '(:fixup "debug_print" :foreign)) + (inst blr lr) (when cur-nfp (load-stack-tn cur-nfp nfp-save)) (move result nl0)))) diff --git a/src/compiler/arm64/subprim.lisp b/src/compiler/arm64/subprim.lisp index 8977e56b24..e845d4777f 100644 --- a/src/compiler/arm64/subprim.lisp +++ b/src/compiler/arm64/subprim.lisp @@ -40,7 +40,7 @@ (loadw ptr ptr cons-cdr-slot list-pointer-lowtag) (inst add count count (fixnumize 1)) - (test-type ptr temp loop nil (list-pointer-lowtag)) + (inst b loop) (emit-label not-list) diff --git a/src/compiler/arm64/system.lisp b/src/compiler/arm64/system.lisp index 206fa38d69..18165b0cc8 100644 --- a/src/compiler/arm64/system.lisp +++ b/src/compiler/arm64/system.lisp @@ -83,8 +83,8 @@ (:generator 6 (load-type result object (- other-pointer-lowtag)))) -(define-vop (fun-subtype) - (:translate fun-subtype) +(define-vop () + (:translate %fun-pointer-widetag) (:policy :fast-safe) (:args (function :scs (descriptor-reg))) (:results (result :scs (unsigned-reg))) @@ -105,10 +105,9 @@ (define-vop (set-header-data) (:translate set-header-data) (:policy :fast-safe) - (:args (x :scs (descriptor-reg) :target res) + (:args (x :scs (descriptor-reg)) (data :scs (any-reg immediate))) (:arg-types * positive-fixnum) - (:results (res :scs (descriptor-reg))) (:temporary (:scs (non-descriptor-reg)) t1) (:generator 6 (load-type t1 x (- other-pointer-lowtag)) @@ -117,8 +116,23 @@ (inst orr t1 t1 (lsl data (- n-widetag-bits n-fixnum-tag-bits)))) (immediate (inst orr t1 t1 (logical-mask (ash (tn-value data) n-widetag-bits))))) - (storew t1 x 0 other-pointer-lowtag) - (move res x))) + (storew t1 x 0 other-pointer-lowtag))) + +(define-vop () + (:translate test-header-data-bit) + (:policy :fast-safe) + (:args (array :scs (descriptor-reg))) + (:info mask) + (:arg-types t (:constant t)) + (:conditional :ne) + (:generator 1 + (let ((byte 1)) + (when (> mask #xff) + (aver (zerop (ldb (byte 8 0) mask))) + (setf mask (ash mask -8) + byte 2)) + (inst ldrb tmp-tn (@ array (- byte other-pointer-lowtag))) + (inst tst tmp-tn mask)))) (define-vop (pointer-hash) (:translate pointer-hash) @@ -130,14 +144,6 @@ ;;;; Allocation -(define-vop (dynamic-space-free-pointer) - (:results (int :scs (sap-reg))) - (:result-types system-area-pointer) - (:translate dynamic-space-free-pointer) - (:policy :fast-safe) - (:generator 1 - (load-symbol-value int *allocation-pointer*))) - (define-vop (binding-stack-pointer-sap) (:results (int :scs (sap-reg))) (:result-types system-area-pointer) @@ -194,34 +200,35 @@ (inst add ndescr offset ndescr) (inst sub ndescr ndescr (- other-pointer-lowtag fun-pointer-lowtag)) (inst add func code ndescr))) -;;; -(define-vop (symbol-info-vector) + +(define-vop (%closure-fun) (:policy :fast-safe) - (:translate symbol-info-vector) - (:args (x :scs (descriptor-reg))) - (:results (res :scs (descriptor-reg))) - (:temporary (:sc unsigned-reg) temp) - (:generator 1 - (loadw res x symbol-info-slot other-pointer-lowtag) - ;; If RES has list-pointer-lowtag, take its CDR. If not, use it as-is. - (inst and temp res lowtag-mask) + (:translate %closure-fun) + (:args (function :scs (descriptor-reg))) + (:results (result :scs (descriptor-reg))) + (:generator 3 + (loadw result function closure-fun-slot fun-pointer-lowtag) + (inst add-sub result result (- fun-pointer-lowtag (* simple-fun-insts-offset n-word-bytes))))) +;;; + +(defun load-symbol-dbinfo (result symbol temp) + (assemble () + (loadw result symbol symbol-info-slot other-pointer-lowtag) + ;; If RESULT has list-pointer-lowtag, take its CDR. If not, use it as-is. + (inst and temp result lowtag-mask) (inst cmp temp list-pointer-lowtag) (inst b :ne NE) - (loadw res res cons-cdr-slot list-pointer-lowtag) + (loadw result result cons-cdr-slot list-pointer-lowtag) NE)) -(define-vop (symbol-plist) +(define-vop (symbol-dbinfo) (:policy :fast-safe) - (:translate symbol-plist) + (:translate symbol-dbinfo) (:args (x :scs (descriptor-reg))) (:results (res :scs (descriptor-reg))) + (:temporary (:sc unsigned-reg) temp) (:generator 1 - (loadw res x symbol-info-slot other-pointer-lowtag) - ;; Instruction pun: (CAR x) is the same as (VECTOR-LENGTH x) - ;; so if the info slot holds a vector, this gets a fixnum- it's not a plist. - (loadw res res cons-car-slot list-pointer-lowtag) - (inst tst res fixnum-tag-mask) - (inst csel res null-tn res :eq))) + (load-symbol-dbinfo res x temp))) ;;;; other miscellaneous VOPs @@ -254,10 +261,10 @@ (:result-types system-area-pointer) (:translate current-thread-offset-sap) (:info n) - (:arg-types (:constant (satisfies ldr-str-offset-encodable))) + (:arg-types (:constant (satisfies ldr-str-word-offset-encodable))) (:policy :fast-safe) (:generator 1 - (inst ldr sap (@ thread-tn (ash n word-shift))))) + (inst ldr sap (@ thread-tn (ash n word-shift))))) (define-vop (current-thread-offset-sap) (:results (sap :scs (sap-reg))) @@ -267,7 +274,7 @@ (:arg-types signed-num) (:policy :fast-safe) (:generator 2 - (inst ldr sap (@ thread-tn (extend n :lsl word-shift)))))) + (inst ldr sap (@ thread-tn (extend n :lsl word-shift)))))) ;;; Barriers (define-vop (%compiler-barrier) @@ -297,3 +304,12 @@ (:policy :fast-safe) (:translate %data-dependency-barrier) (:generator 3)) + +(define-vop (sb-c::mark-covered) + (:info index) + (:temporary (:sc unsigned-reg) tmp) + (:temporary (:sc descriptor-reg) vector) + (:generator 4 + ;; Can't compute code-tn-relative index until the boxed header length + ;; is known. Some vops emit new boxed words via EMIT-CONSTANT. + (inst store-coverage-mark index tmp vector))) diff --git a/src/compiler/arm64/target-insts.lisp b/src/compiler/arm64/target-insts.lisp index 9f2a951e86..ae16e54a73 100644 --- a/src/compiler/arm64/target-insts.lisp +++ b/src/compiler/arm64/target-insts.lisp @@ -9,22 +9,28 @@ (defun 32-bit-register-p (dstate) (not (logbitp 31 (current-instruction dstate)))) -(defun print-lsl-alias-name (value stream dstate) +(defun print-ubfm-alias-name (value stream dstate) (declare (ignore dstate)) (destructuring-bind (immr imms) value - (princ (if (and (/= imms 63) - (= (1+ imms) immr)) - 'lsl - 'ubfm) + (princ (cond ((and (/= imms 63) + (= (1+ imms) immr)) + 'lsl) + ((< imms immr) + 'ubfiz) + (t + 'ubfm)) stream))) -(defun print-lsl-alias (value stream dstate) +(defun print-ubfm-alias (value stream dstate) (declare (ignore dstate)) (destructuring-bind (immr imms) value - (if (and (/= imms 63) - (= (1+ imms) immr)) - (format stream "#~d" (- 63 imms)) - (format stream "#~d, #~d" immr imms)))) + (cond ((and (/= imms 63) + (= (1+ imms) immr)) + (format stream "#~d" (- 63 imms))) + ((< imms immr) + (format stream "#~d, #~d" (- 64 immr) (1+ imms))) + (t + (format stream "#~d, #~d" immr imms))))) (defun print-mem-bar-kind (value stream dstate) (declare (ignore dstate)) @@ -101,7 +107,7 @@ (defun print-test-branch-immediate (value stream dstate) (declare (ignore dstate)) (format stream "#~D" - (dpb (car value) (byte 1 5) (car value)))) + (dpb (car value) (byte 1 5) (cadr value)))) (defun decode-scaled-immediate (value) (destructuring-bind (size opc value simd) value @@ -178,6 +184,13 @@ (princ "NSP" stream) (princ (aref *register-names* value) stream))) +(defun print-sized-reg (value stream dstate) + (declare (ignore dstate)) + (destructuring-bind (size reg) value + (when (zerop size) + (princ "W" stream)) + (princ (svref *register-names* reg) stream))) + (defun print-reg-float-reg (value stream dstate) (let* ((inst (current-instruction dstate)) (v (ldb (byte 1 26) inst))) @@ -224,13 +237,155 @@ "S") value))) +(defun decode-vector-size (q size) + (case q + (0 + (case size + (#b00 "8B") + (#b01 "4H") + (#b10 "2S"))) + (1 + (case size + (#b00 "16B") + (#b01 "8H") + (#b10 "4S") + (#b11 "2D"))))) + (defun print-simd-reg (value stream dstate) (declare (ignore dstate)) - (destructuring-bind (size offset) value + (multiple-value-bind (q size offset) + (if (= (length value) 3) + (destructuring-bind (q size offset) value + (values q size offset)) + (destructuring-bind (q offset) value + (values q 0 offset))) + (format stream "V~d.~a" offset + (decode-vector-size q size)))) + +(defun print-simd-immh-reg (value stream dstate) + (declare (ignore dstate)) + (if (= (length value) 2) + (destructuring-bind (immh offset) value + (format stream "V~d.~a" offset + (cond ((logbitp 0 immh) + "8H") + ((logbitp 1 immh) + "4S") + ((logbitp 2 immh) + "2D")))) + (destructuring-bind (q immh offset) value + (format stream "V~d.~a" offset + (cond ((logbitp 0 immh) + (if (zerop q) + "8B" + "16B")) + ((logbitp 1 immh) + (if (zerop q) + "4H" + "8H")) + ((logbitp 2 immh) + (if (zerop q) + "2S" + "4S"))))))) + +(defun print-simd-reg-cmode (value stream dstate) + (declare (ignore dstate)) + (destructuring-bind (q cmode offset) value (format stream "V~d.~a" offset - (if (zerop size) - "8B" - "16B")))) + (cond ((eq cmode #b1110) + (if (zerop q) + "8B" + "16B")) + ((zerop (logand cmode #b1001)) + (if (zerop q) + "2S" + "4S")))))) + +(defun print-simd-modified-imm (value stream dstate) + (declare (ignore dstate)) + (destructuring-bind (abc cmode defgh) value + (let ((shift + (cond ((eq cmode #b1110) + 0) + ((zerop (logand cmode #b1001)) + (ash cmode 2))))) + (princ (dpb abc (byte 3 5) defgh) stream) + (when (plusp shift) + (format stream ", LSL #~d" shift))))) + +(defun decode-fp-immediate (imm type) + (let ((sign (ldb (byte 1 7) imm)) + (exp (ldb (byte 3 4) imm)) + (frac (ldb (byte 4 0) imm))) + (case type + (double-float + (sb-kernel::double-from-bits + sign + (logior (ash (logandc1 (ldb (byte 1 2) exp) 1) 10) + (ash (if (zerop (ldb (byte 1 2) exp)) + 0 + (ldb (byte 8 0) -1)) + 2) + (ldb (byte 2 0) exp)) + (ash frac 48))) + (single-float + (sb-kernel::single-from-bits + sign + (logior (ash (logandc1 (ldb (byte 1 2) exp) 1) 7) + (ash (if (zerop (ldb (byte 1 2) exp)) + 0 + (ldb (byte 5 0) -1)) + 2) + (ldb (byte 2 0) exp)) + (ash frac 19)))))) + +(defun print-fp-imm (value stream dstate) + (declare (ignore dstate)) + (destructuring-bind (type imm) value + (format stream "#~a" (decode-fp-immediate imm (if (= type 0) + 'single-float + 'double-float))))) + +(defun print-vbhs (value stream dstate) + (declare (ignore dstate)) + (destructuring-bind (size offset) value + (format stream "~a~d" + (case size + (#b00 "B") + (#b01 "H") + (#b10 "S")) + offset))) + +(defun print-vhsd (value stream dstate) + (declare (ignore dstate)) + (destructuring-bind (size offset) value + (format stream "~a~d" + (case size + (#b00 "H") + (#b01 "S") + (#b10 "D")) + offset))) + +(defun print-vx.t (value stream dstate) + (declare (ignore dstate)) + (destructuring-bind (q size offset) value + (format stream "V~d.~a" + offset + (cond ((and (= size 0) + (= q 0)) + "8B") + ((and (= size 0) + (= q 1)) + "16B") + ((and (= size 1) + (= q 0)) + "4H") + ((and (= size 1) + (= q 1)) + "8H") + ((and (= size 2) + (= q 1)) + "4S"))))) (defun lowest-set-bit-index (integer-value) (max 0 (1- (integer-length (logand integer-value (- integer-value)))))) @@ -251,7 +406,10 @@ (defun print-cond (value stream dstate) (declare (ignore dstate)) - (princ (svref sb-vm::+condition-name-vec+ value) stream)) + (princ (svref +condition-name-vec+ value) stream)) + +(defun print-negated-cond (value stream dstate) + (print-cond (logxor 1 value) stream dstate)) (defun use-label (value dstate) (let* ((value (if (consp value) @@ -267,26 +425,37 @@ (defun annotate-ldr-str (register offset dstate) (case register - (#.sb-vm::code-offset - (note-code-constant offset dstate)) (#.sb-vm::null-offset (let ((offset (+ sb-vm:nil-value offset))) - (maybe-note-assembler-routine offset nil dstate) - (maybe-note-static-symbol (logior offset other-pointer-lowtag) - dstate))) + (or (maybe-note-static-symbol (logior offset other-pointer-lowtag) + dstate) + (maybe-note-assembler-routine offset nil dstate)))) #+sb-thread (#.sb-vm::thread-offset (let* ((thread-slots - (load-time-value - (primitive-object-slots - (find 'sb-vm::thread *primitive-objects* - :key #'primitive-object-name)) t)) - (slot (find (ash offset (- word-shift)) thread-slots - :key #'slot-offset))) - (when slot - (note (lambda (stream) - (format stream "thread.~(~A~)" (slot-name slot))) - dstate)))))) + (load-time-value + (primitive-object-slots (primitive-object 'sb-vm::thread)) + t)) + (slot (find (ash offset (- word-shift)) thread-slots :key #'slot-offset))) + (if slot + (note (lambda (stream) + (format stream "~(~A~)" (slot-name slot))) + dstate) + (flet ((guess-symbol (predicate) + (binding* ((code-header (seg-code (dstate-segment dstate)) :exit-if-null) + (header-n-words (code-header-words code-header))) + (loop for word-num from code-constants-offset below header-n-words + for obj = (code-header-ref code-header word-num) + when (and (symbolp obj) (funcall predicate obj)) + do (return obj))))) + (let ((symbol (or (guess-symbol + (lambda (s) (= (symbol-tls-index s) offset))) + ;; static symbols aren't in the code header + (find offset +static-symbols+ + :key #'symbol-tls-index)))) + (when symbol + (note (lambda (stream) (format stream "tls: ~S" symbol)) + dstate))))))))) (defun find-value-from-previos-inst (register dstate) ;; Needs to be MOVZ REGISTER, imm, LSL #0 @@ -317,25 +486,100 @@ value) dstate)))) +(defun annotate-ldr-str-pair (value stream dstate) + (declare (ignore stream) (ignorable dstate)) + (destructuring-bind (reg offset) value + (declare (ignorable offset)) + (case reg + #+sb-thread + (#.sb-vm::thread-offset + (let* ((thread-slots + (load-time-value + (primitive-object-slots (primitive-object 'sb-vm::thread)) + t)) + (slot1 (find offset thread-slots :key #'slot-offset)) + (slot2 (find (1+ offset) thread-slots :key #'slot-offset))) + (when slot1 + (note (lambda (stream) + (if (memq (slot-name slot1) '(sb-vm::mixed-tlab + sb-vm::cons-tlab + sb-vm::unboxed-tlab)) + (format stream "~(~a~).{free-pointer, end-addr}" (slot-name slot1)) + (format stream "~(~A, ~A~)" (slot-name slot1) (slot-name slot2)))) + dstate))))))) + +(defun annotate-ldr-literal (value stream dstate) + (declare (ignore stream)) + (let* ((value (* 4 value)) + (seg (dstate-segment dstate)) + (code (seg-code seg)) + (inst (current-instruction dstate)) + (v (ldb (byte 1 26) inst)) + (addr (+ (dstate-cur-addr dstate) value))) + (when code + (if (plusp v) + (when (sb-disassem::points-to-code-constant-p addr code) + (case (ldb (byte 2 30) inst) + (#b00 + (note (lambda (stream) + (format stream "~a" (sap-ref-single (int-sap addr) 0))) + dstate)) + (#b01 + (note + (lambda (stream) + (format stream "~a" (sap-ref-double (int-sap addr) 0))) + dstate)) + (#b10 + (note + (lambda (stream) + (format stream "~x ~x"(sap-ref-double (int-sap addr) 0) + (sap-ref-double (int-sap addr) 8))) + dstate)))) + (or (note-code-constant (sb-disassem::segment-offs-to-code-offs + (+ (dstate-cur-offs dstate) value) seg) + dstate) + (and (sb-disassem::points-to-code-constant-p addr code) + (maybe-note-assembler-routine (sap-ref-word (int-sap addr) 0) + nil dstate))))))) + ;;;; special magic to support decoding internal-error and related traps +;;; See EMIT-ERROR-BREAK for the scheme (defun snarf-error-junk (sap offset trap-number &optional length-only) - (declare (ignore trap-number)) (let* ((inst (sap-ref-32 sap (- offset 4))) - (error-number (ldb (byte 8 13) inst)) + (error-number (cond + ((>= trap-number sb-vm:error-trap) + (prog1 + (- trap-number sb-vm:error-trap) + (setf trap-number sb-vm:error-trap))) + (t + (prog1 (sap-ref-8 sap offset) + (incf offset))))) + (first-arg (ldb (byte 8 13) inst)) + (first-offset (ldb (byte 5 0) first-arg)) + (first-sc (ldb (byte 2 5) first-arg)) (length (sb-kernel::error-length error-number)) (index offset)) (declare (type sb-sys:system-area-pointer sap) (type (unsigned-byte 8) length)) + (unless (or (= first-arg sb-vm::zr-offset) + (zerop length)) + (decf length)) (cond (length-only (loop repeat length do (sb-c:sap-read-var-integerf sap index)) (values 0 (- index offset) nil nil)) (t (collect ((sc+offsets) (lengths)) + (unless (= first-offset sb-vm::zr-offset) + (sc+offsets (make-sc+offset (case first-sc + (1 sb-vm:unsigned-reg-sc-number) + (2 sb-vm:signed-reg-sc-number) + (t sb-vm:descriptor-reg-sc-number)) first-offset)) + (lengths 0)) (loop repeat length do - (let ((old-index index)) - (sc+offsets (sb-c:sap-read-var-integerf sap index)) - (lengths (- index old-index)))) + (let ((old-index index)) + (sc+offsets (sb-c:sap-read-var-integerf sap index)) + (lengths (- index old-index)))) (values error-number (- index offset) (sc+offsets) @@ -345,7 +589,9 @@ (declare (ignore inst chunk)) (let ((code (ldb (byte 8 5) (current-instruction dstate)))) (flet ((nt (x) (if stream (note x dstate)))) - (case code + (case (if (> code error-trap) + error-trap + code) (#.halt-trap (nt "Halt trap")) (#.pending-interrupt-trap diff --git a/src/compiler/arm64/type-vops.lisp b/src/compiler/arm64/type-vops.lisp index fa496052a2..fdbbe2f833 100644 --- a/src/compiler/arm64/type-vops.lisp +++ b/src/compiler/arm64/type-vops.lisp @@ -14,14 +14,16 @@ (defun %test-fixnum (value temp target not-p) (declare (ignore temp)) (assemble () - (inst tst value fixnum-tag-mask) - (inst b (if not-p :ne :eq) target))) + #.(assert (= fixnum-tag-mask 1)) + (if not-p + (inst tbnz* value 0 target) + (inst tbz* value 0 target)))) (defun %test-fixnum-immediate-and-headers (value temp target not-p immediate headers &key value-tn-ref) (let ((drop-through (gen-label))) - (inst tst value fixnum-tag-mask) - (inst b :eq (if not-p drop-through target)) + #.(assert (= fixnum-tag-mask 1)) + (inst tbz* value 0 (if not-p drop-through target)) (%test-immediate-and-headers value temp target not-p immediate headers :drop-through drop-through :value-tn-ref value-tn-ref))) @@ -29,9 +31,11 @@ (defun %test-immediate-and-headers (value temp target not-p immediate headers &key (drop-through (gen-label)) value-tn-ref) - - (inst mov temp immediate) - (inst cmp temp (extend value :uxtb)) + (cond ((= immediate single-float-widetag) + (inst cmp (32-bit-reg value) single-float-widetag)) + (t + (inst mov temp immediate) + (inst cmp temp (extend value :uxtb)))) (inst b :eq (if not-p drop-through target)) (%test-headers value temp target not-p nil headers :drop-through drop-through @@ -41,8 +45,8 @@ &key value-tn-ref) (let ((drop-through (gen-label))) (assemble () - (inst ands temp value fixnum-tag-mask) - (inst b :eq (if not-p drop-through target))) + #.(assert (= fixnum-tag-mask 1)) + (inst tbz* value 0 (if not-p drop-through target))) (%test-headers value temp target not-p nil headers :drop-through drop-through :value-tn-ref value-tn-ref))) @@ -61,75 +65,97 @@ (inst cmp temp lowtag) (inst b (if not-p :ne :eq) target))) -(defun %test-headers (value temp target not-p function-p headers +(defun %test-headers (value widetag target not-p function-p headers &key (drop-through (gen-label)) value-tn-ref) - (let ((lowtag (if function-p fun-pointer-lowtag other-pointer-lowtag))) - (multiple-value-bind (when-true when-false) - (if not-p - (values drop-through target) - (values target drop-through)) - (assemble () - (unless (and value-tn-ref - (eq lowtag other-pointer-lowtag) - (other-pointer-tn-ref-p value-tn-ref)) - (%test-lowtag value temp when-false t lowtag)) - (load-type temp value (- lowtag)) - (do ((remaining headers (cdr remaining))) - ((null remaining)) - (let ((header (car remaining)) - (last (null (cdr remaining)))) - (cond - ((atom header) - (cond - ((and (not last) (null (cddr remaining)) - (atom (cadr remaining)) - (= (logcount (logxor header (cadr remaining))) 1)) - (inst and temp temp (logical-mask - (ldb (byte 8 0) (logeqv header (cadr remaining))))) - (inst cmp temp (ldb (byte 8 0) (logand header (cadr remaining)))) - (inst b (if not-p :ne :eq) target) - (return)) - (t - (inst cmp temp header) - (if last - (inst b (if not-p :ne :eq) target) - (inst b :eq when-true))))) - (t - (let ((start (car header)) - (end (cdr header))) + (let ((lowtag (if function-p fun-pointer-lowtag other-pointer-lowtag)) + (temp widetag)) + (flet ((%logical-mask (x) + (cond ((encode-logical-immediate x) + x) + ;; The remaining bits of the widetag are zero, no + ;; need to mask them off. Possible to encode more + ;; values that way. + ((let ((extend (dpb x (byte 8 0) most-positive-word))) + (and (encode-logical-immediate extend) + extend))) + (t + (logical-mask x))))) + (multiple-value-bind (when-true when-false) + (if not-p + (values drop-through target) + (values target drop-through)) + (assemble () + (cond (widetag + (unless (and value-tn-ref + (eq lowtag other-pointer-lowtag) + (other-pointer-tn-ref-p value-tn-ref)) + (%test-lowtag value widetag when-false t lowtag)) + (load-type widetag value (- lowtag))) + (t + (setf widetag value + temp tmp-tn))) + (do ((remaining headers (cdr remaining))) + ((null remaining)) + (let ((header (car remaining)) + (last (null (cdr remaining)))) + (cond + ((atom header) (cond - ((and last (not (= start bignum-widetag)) - (= (+ start 4) end) - (= (logcount (logxor start end)) 1)) - (inst and temp temp (logical-mask - (ldb (byte 8 0) (logeqv start end)))) - (inst cmp temp (ldb (byte 8 0) (logand start end))) - (inst b (if not-p :ne :eq) target)) ((and (not last) (null (cddr remaining)) - (= (+ start 4) end) (= (logcount (logxor start end)) 1) - (listp (cadr remaining)) - (= (+ (caadr remaining) 4) (cdadr remaining)) - (= (logcount (logxor (caadr remaining) (cdadr remaining))) 1) - (= (logcount (logxor (caadr remaining) start)) 1)) - (inst and temp temp (ldb (byte 8 0) (logeqv start (cdadr remaining)))) - (inst cmp temp (ldb (byte 8 0) (logand start (cdadr remaining)))) + (atom (cadr remaining)) + (= (logcount (logxor header (cadr remaining))) 1)) + (inst and temp widetag (%logical-mask + (ldb (byte 8 0) (logeqv header (cadr remaining))))) + (inst cmp temp (ldb (byte 8 0) (logand header (cadr remaining)))) (inst b (if not-p :ne :eq) target) (return)) (t - (unless (= start bignum-widetag) - (inst cmp temp start) - (if (= end complex-array-widetag) - (progn - (aver last) - (inst b (if not-p :lt :ge) target)) - (inst b :lt when-false))) - (unless (= end complex-array-widetag) - (inst cmp temp end) - (if last - (inst b (if not-p :gt :le) target) - (inst b :le when-true)))))))))) - (emit-label drop-through))))) + (inst cmp widetag header) + (if last + (inst b (if not-p :ne :eq) target) + (inst b :eq when-true))))) + (t + (let ((start (car header)) + (end (cdr header))) + (cond + ((and last (not (= start bignum-widetag)) + (= (+ start 4) end) + (= (logcount (logxor start end)) 1)) + (inst and temp widetag (%logical-mask + (ldb (byte 8 0) (logeqv start end)))) + (inst cmp temp (ldb (byte 8 0) (logand start end))) + (inst b (if not-p :ne :eq) target)) + ((and (not last) (null (cddr remaining)) + (= (+ start 4) end) (= (logcount (logxor start end)) 1) + (listp (cadr remaining)) + (= (+ (caadr remaining) 4) (cdadr remaining)) + (= (logcount (logxor (caadr remaining) (cdadr remaining))) 1) + (= (logcount (logxor (caadr remaining) start)) 1)) + (inst and temp widetag (ldb (byte 8 0) (logeqv start (cdadr remaining)))) + (inst cmp temp (ldb (byte 8 0) (logand start (cdadr remaining)))) + (inst b (if not-p :ne :eq) target) + (return)) + ((and last + (/= start bignum-widetag) + (/= end complex-array-widetag)) + (inst sub temp widetag start) + (inst cmp temp (- end start)) + (inst b (if not-p :hi :ls) target)) + (t + (unless (= start bignum-widetag) + (inst cmp widetag start) + (if (= end complex-array-widetag) + (progn + (aver last) + (inst b (if not-p :lt :ge) target)) + (inst b :lt when-false))) + (unless (= end complex-array-widetag) + (inst cmp widetag end) + (if last + (inst b (if not-p :gt :le) target) + (inst b :le when-true)))))))))) + (emit-label drop-through)))))) ;;;; Other integer ranges. @@ -137,67 +163,83 @@ ;;; exactly one digit. (define-vop (signed-byte-64-p type-predicate) (:translate signed-byte-64-p) - (:generator 45 - (multiple-value-bind (yep nope) - (if not-p - (values not-target target) - (values target not-target)) - (assemble () - (inst ands temp value fixnum-tag-mask) - (inst b :eq yep) - (test-type value temp nope t (other-pointer-lowtag)) - (loadw temp value 0 other-pointer-lowtag) - (inst cmp temp (+ (ash 1 n-widetag-bits) bignum-widetag)) - (inst b (if not-p :ne :eq) target))) + (:generator 10 + (let ((fixnum-p (types-equal-or-intersect (tn-ref-type args) (specifier-type 'fixnum)))) + (multiple-value-bind (yep nope) + (if not-p + (values not-target target) + (values target not-target)) + (assemble () + (when fixnum-p + (inst tbz* value 0 yep)) + (unless (fixnum-or-other-pointer-tn-ref-p args) + (test-type value temp nope t (other-pointer-lowtag))) + (loadw temp value 0 other-pointer-lowtag) + (inst cmp temp (+ (ash 1 n-widetag-bits) bignum-widetag)) + (inst b (if not-p :ne :eq) target)))) not-target)) +(define-vop (signed-byte-64-p/unsigned) + (:args (value :scs (unsigned-reg))) + (:arg-types unsigned-num) + (:conditional :eq) + (:policy :fast-safe) + (:translate signed-byte-64-p) + (:generator 5 + (inst tst value (ash 1 (1- n-word-bits))))) + ;;; An (UNSIGNED-BYTE 64) can be represented with either a positive ;;; fixnum, a bignum with exactly one positive digit, or a bignum with ;;; exactly two digits and the second digit all zeros. (define-vop (unsigned-byte-64-p type-predicate) (:translate unsigned-byte-64-p) - (:generator 45 - (let ((single-word (gen-label)) - (fixnum (gen-label))) - (multiple-value-bind (yep nope) - (if not-p - (values not-target target) - (values target not-target)) - (assemble () - ;; Is it a fixnum? - (move temp value) - (%test-fixnum temp nil fixnum nil) - - ;; If not, is it an other pointer? - (test-type value temp nope t (other-pointer-lowtag)) - ;; Get the header. - (loadw temp value 0 other-pointer-lowtag) - ;; Is it one? - (inst cmp temp (+ (ash 1 n-widetag-bits) bignum-widetag)) - (inst b :eq single-word) - ;; If it's other than two, it can't be an (unsigned-byte 64) - (inst cmp temp (+ (ash 2 n-widetag-bits) bignum-widetag)) - (inst b :ne nope) - ;; Get the second digit. - (loadw temp value (1+ bignum-digits-offset) other-pointer-lowtag) - ;; All zeros, it's an (unsigned-byte 64). - (inst cbz temp yep) - (inst b nope) - - (emit-label single-word) - ;; Get the single digit. - (loadw temp value bignum-digits-offset other-pointer-lowtag) - - ;; positive implies (unsigned-byte 64). - (emit-label fixnum) - (inst cmp temp 0) - (if not-p - (inst b :lt target) - (inst b :ge target)))) - (values)) - NOT-TARGET)) - -(define-vop (fixnump/unsigned-byte-64) + (:generator 10 + (let ((fixnum-p (types-equal-or-intersect (tn-ref-type args) (specifier-type 'fixnum))) + (other-pointer-p (fixnum-or-other-pointer-tn-ref-p args))) + (multiple-value-bind (yep nope) + (if not-p + (values not-target target) + (values target not-target)) + (assemble () + (cond ((not other-pointer-p) + ;; Move to a temporary and mask off the lowtag, + ;; but leave the sign bit for testing for positive fixnums. + ;; When using 32-bit registers that bit will not be visible. + (inst and temp value (logior (ash 1 (1- n-word-bits)) lowtag-mask))) + (fixnum-p + (move temp value))) + (when fixnum-p + (%test-fixnum temp nil fixnum nil)) + (unless other-pointer-p + (inst cmp (32-bit-reg temp) other-pointer-lowtag) + (inst b :ne nope)) + ;; Get the header. + (loadw temp value 0 other-pointer-lowtag) + ;; Is it one? + (inst cmp temp (+ (ash 1 n-widetag-bits) bignum-widetag)) + (inst b :eq single-word) + ;; If it's other than two, it can't be an (unsigned-byte 64) + (inst cmp temp (+ (ash 2 n-widetag-bits) bignum-widetag)) + (inst b :ne nope) + ;; Get the second digit. + (loadw temp value (1+ bignum-digits-offset) other-pointer-lowtag) + ;; All zeros, it's an (unsigned-byte 64). + (inst cbz temp yep) + (inst b nope) + + single-word + ;; Get the single digit. + (loadw temp value bignum-digits-offset other-pointer-lowtag) + + ;; positive implies (unsigned-byte 64). + fixnum + (if not-p + (inst tbnz* temp (1- n-word-bits) target) + (inst tbz* temp (1- n-word-bits) target)))) + (values)) + NOT-TARGET)) + +(define-vop (fixnump/unsigned) (:policy :fast-safe) (:args (value :scs (unsigned-reg))) (:arg-types unsigned-num) @@ -208,14 +250,128 @@ n-positive-fixnum-bits))) n-positive-fixnum-bits)))) -(define-vop (fixnump/signed-byte-64 type-predicate) +(define-vop (fixnump/signed) (:args (value :scs (signed-reg))) + (:policy :fast-safe) (:conditional :vc) (:info) (:arg-types signed-num) (:translate fixnump) (:generator 3 - (inst adds temp value value))) + (inst adds zr-tn value value))) + +(define-vop (>-integer-fixnum) + (:translate >) + (:args (integer :scs (descriptor-reg)) + (fixnum :scs (immediate any-reg))) + (:arg-types (:or integer bignum) tagged-num) + (:temporary (:sc non-descriptor-reg) temp) + (:conditional) + (:info target not-p) + (:args-var args) + (:policy :fast-safe) + (:variant-vars comparison) + (:variant :gt) + (:generator 10 + (unless (sc-is (tn-ref-tn args) descriptor-reg control-stack) + (setf args (tn-ref-across args))) + (let* ((integer-p (csubtypep (tn-ref-type args) (specifier-type 'integer))) + (other-pointer-p (fixnum-or-other-pointer-tn-ref-p args)) + negative-p + (fixnum (if (sc-is fixnum immediate) + (let* ((value (fixnumize (tn-value fixnum))) + (abs (abs value))) + (cond ((add-sub-immediate-p abs) + (when (minusp value) + (setf negative-p t)) + abs) + (t + (add-sub-immediate value)))) + fixnum))) + (multiple-value-bind (yep nope) + (if not-p + (values not-target target) + (values target not-target)) + (assemble () + (when (types-equal-or-intersect (tn-ref-type args) (specifier-type 'fixnum)) + (cond ((or other-pointer-p + (not (and (eql fixnum 0) + (eq comparison :ge)))) + (inst tbnz integer 0 bignum) + (cond + ((and (eql fixnum 0) + (case comparison + (:lt + (inst tbnz* integer 63 yep) + t) + (:ge + (inst tbz* integer 63 yep) + t)))) + ((and (eql fixnum -1) + (case comparison + (:le + (inst tbnz* integer 63 yep) + t) + (:gt + (inst tbz* integer 63 yep) + t)))) + (negative-p + (inst cmn integer fixnum) + (inst b comparison yep)) + (t + (inst cmp integer fixnum) + (inst b comparison yep))) + (inst b nope)) + (t + (inst tst integer (lognot (fixnumize most-positive-fixnum))) + (inst b :eq yep)))) + bignum + (unless other-pointer-p + (test-type integer temp nope t (other-pointer-lowtag))) + (loadw temp integer 0 other-pointer-lowtag) + (unless integer-p + (inst and tmp-tn temp widetag-mask) + (inst cmp tmp-tn bignum-widetag) + (inst b :ne nope)) + #.(assert (= (integer-length bignum-widetag) 5)) + (inst add temp integer (lsr temp 5)) + (inst ldr temp (@ temp (- other-pointer-lowtag))) + (if (case comparison + ((:gt :ge) not-p) + (t (not not-p))) + (inst tbnz* temp (1- n-word-bits) target) + (inst tbz* temp (1- n-word-bits) target))))) + not-target)) + +(define-vop (<-integer-fixnum >-integer-fixnum) + (:translate <) + (:variant :lt)) + +(define-vop (>-fixnum-integer >-integer-fixnum) + (:translate >) + (:args (fixnum :scs (immediate any-reg)) + (integer :scs (descriptor-reg))) + (:arg-types tagged-num (:or integer bignum)) + (:variant :lt)) + +(define-vop (<-fixnum-integer >-fixnum-integer) + (:translate <) + (:variant :gt)) + +;;; For integerp+cmp +(define-vop (<=-integer-fixnum >-integer-fixnum) + (:translate) + (:variant :le)) +(define-vop (>=-integer-fixnum <-integer-fixnum) + (:translate) + (:variant :ge)) +(define-vop (<=-fixnum-integer >-fixnum-integer) + (:translate) + (:variant :ge)) +(define-vop (>=-fixnum-integer <-fixnum-integer) + (:translate) + (:variant :le)) + ;;; MOD type checks (defun power-of-two-limit-p (x) @@ -237,6 +393,16 @@ (fixnumize hi)))) (inst tst value (lognot fixnum-hi))))) +(defun add-sub-immediate-p+1 (x) + (add-sub-immediate-p (1+ x))) + +(defun fixnum-add-sub-immediate-p+1 (x) + (fixnum-add-sub-immediate-p (1+ x))) + +(defun fixnum-add-sub-immediate-p/+1 (x) + (or (fixnum-add-sub-immediate-p x) + (fixnum-add-sub-immediate-p (1+ x)))) + (define-vop (test-fixnum-mod-signed-unsigned-imm) (:args (value :scs (unsigned-reg signed-reg))) (:arg-types (:or unsigned-num signed-num) @@ -246,7 +412,14 @@ (:info hi) (:policy :fast-safe) (:generator 3 - (inst cmp value hi))) + (inst cmp value hi))) + +(define-vop (test-fixnum-mod-signed-unsigned-imm+1 test-fixnum-mod-signed-unsigned-imm) + (:arg-types (:or unsigned-num signed-num) + (:constant (satisfies add-sub-immediate-p+1))) + (:conditional :lo) + (:generator 3 + (inst cmp value (1+ hi)))) (define-vop (test-fixnum-mod-tagged-imm) (:args (value :scs (any-reg))) @@ -259,6 +432,49 @@ (:generator 3 (inst cmp value (fixnumize hi)))) +(define-vop (test-fixnum-mod-tagged-imm+1 test-fixnum-mod-tagged-imm) + (:arg-types tagged-num + (:constant (satisfies fixnum-add-sub-immediate-p+1))) + (:conditional :lo) + (:generator 3 + (inst cmp value (fixnumize (1+ hi))))) + +(define-vop (test-fixnum-mod-signed-unsigned-imm) + (:args (value :scs (unsigned-reg signed-reg))) + (:arg-types (:or unsigned-num signed-num) + (:constant (satisfies add-sub-immediate-p))) + (:translate fixnum-mod-p) + (:conditional :ls) + (:info hi) + (:policy :fast-safe) + (:generator 3 + (inst cmp value hi))) + +(define-vop (test-fixnum-mod-signed-unsigned-imm+1 test-fixnum-mod-signed-unsigned-imm) + (:arg-types (:or unsigned-num signed-num) + (:constant (satisfies add-sub-immediate-p+1))) + (:conditional :lo) + (:generator 3 + (inst cmp value (1+ hi)))) + +(define-vop (test-fixnum-mod-tagged-imm) + (:args (value :scs (any-reg))) + (:arg-types tagged-num + (:constant (satisfies fixnum-add-sub-immediate-p))) + (:translate fixnum-mod-p) + (:conditional :ls) + (:info hi) + (:policy :fast-safe) + (:generator 3 + (inst cmp value (fixnumize hi)))) + +(define-vop (test-fixnum-mod-tagged-imm+1 test-fixnum-mod-tagged-imm) + (:arg-types tagged-num + (:constant (satisfies fixnum-add-sub-immediate-p+1))) + (:conditional :lo) + (:generator 3 + (inst cmp value (fixnumize (1+ hi))))) + (define-vop (test-fixnum-mod-tagged-unsigned) (:args (value :scs (any-reg unsigned-reg signed-reg))) (:arg-types (:or tagged-num unsigned-num signed-num) @@ -269,32 +485,30 @@ (:info hi) (:policy :fast-safe) (:generator 4 - (let ((fixnum-hi (if (sc-is value unsigned-reg signed-reg) - hi - (fixnumize hi)))) - (load-immediate-word temp fixnum-hi) - (inst cmp value temp)))) + (let ((fixnum-hi (if (sc-is value unsigned-reg signed-reg) + hi + (fixnumize hi)))) + (load-immediate-word temp fixnum-hi) + (inst cmp value temp)))) (define-vop (test-fixnum-mod-*-imm) (:args (value :scs (any-reg descriptor-reg))) - (:arg-types * (:constant (satisfies fixnum-add-sub-immediate-p))) + (:arg-types * (:constant (satisfies fixnum-add-sub-immediate-p/+1))) (:translate fixnum-mod-p) (:conditional) (:info target not-p hi) (:policy :fast-safe) (:generator 5 - (let ((fixnum-hi (fixnumize hi))) + (let* ((1+ (not (fixnum-add-sub-immediate-p hi))) + (fixnum-hi (fixnumize (if 1+ + (1+ hi) + hi)))) #.(assert (= fixnum-tag-mask 1)) - (cond (not-p - (inst tst value fixnum-tag-mask) - ;; TBNZ can't jump as far as B. - (inst b :ne target)) - (t - (inst tbnz value 0 skip))) + (inst tbnz* value 0 (if not-p target skip)) (inst cmp value fixnum-hi) (inst b (if not-p - :hi - :ls) + (if 1+ :hs :hi) + (if 1+ :lo :ls)) target)) skip)) @@ -308,12 +522,7 @@ (:policy :fast-safe) (:generator 6 #.(assert (= fixnum-tag-mask 1)) - (cond (not-p - (inst tst value fixnum-tag-mask) - ;; TBNZ can't jump as far as B. - (inst b :ne target)) - (t - (inst tbnz value 0 skip))) + (inst tbnz* value 0 (if not-p target skip)) (let ((condition (if not-p :hi :ls))) (load-immediate-word temp (fixnumize hi)) (inst cmp value temp) @@ -328,19 +537,197 @@ (define-vop (symbolp type-predicate) (:translate symbolp) (:generator 12 - (let* ((drop-thru (gen-label)) - (is-symbol-label (if not-p drop-thru target))) - (inst cmp value null-tn) - (inst b :eq is-symbol-label) - (test-type value temp target not-p (symbol-widetag)) - (emit-label drop-thru)))) + (inst cmp value null-tn) + (inst b :eq (if not-p drop-thru target)) + (test-type value temp target not-p (symbol-widetag)) + drop-thru)) (define-vop (consp type-predicate) (:translate consp) + (:conditional :ne) + (:info) (:generator 8 - (let* ((drop-thru (gen-label)) - (is-not-cons-label (if not-p target drop-thru))) - (inst cmp value null-tn) - (inst b :eq is-not-cons-label) - (test-type value temp target not-p (list-pointer-lowtag)) - (emit-label drop-thru)))) + (inst and temp value lowtag-mask) + (inst cmp temp list-pointer-lowtag) + (inst ccmp value null-tn :eq 4))) + +(define-vop (single-float-p) + (:args (value :scs (any-reg descriptor-reg))) + (:conditional :eq) + (:policy :fast-safe) + (:translate single-float-p) + (:generator 7 + (inst cmp (32-bit-reg value) single-float-widetag))) + +(define-vop (load-other-pointer-widetag) + (:args (value :scs (any-reg descriptor-reg))) + (:args-var args) + (:info not-other-pointer-label null-label) + (:results (r :scs (unsigned-reg))) + (:result-types unsigned-num) + (:generator 1 + (unless (other-pointer-tn-ref-p args) + (when null-label + (inst cmp value null-tn) + (inst b :eq null-label)) + (inst and r value lowtag-mask) + (inst cmp r other-pointer-lowtag) + (inst b :ne not-other-pointer-label)) + (load-type r value (- other-pointer-lowtag)))) + +(define-vop (test-widetag) + (:args (value :scs (unsigned-reg))) + (:info target not-p type-codes) + (:generator 1 + (%test-headers value nil target not-p nil type-codes))) + +(define-vop (load-instance-layout) + (:args (object :scs (any-reg descriptor-reg))) + (:args-var args) + (:info not-instance) + (:results (r :scs (descriptor-reg))) + (:generator 1 + (unless (instance-tn-ref-p args) + (inst and tmp-tn object lowtag-mask) + (inst cmp tmp-tn instance-pointer-lowtag) + (inst b :ne not-instance)) + (loadw r object instance-slots-offset instance-pointer-lowtag))) + +(defun structure-is-a (layout temp this-id test-layout &optional desc-temp target not-p done) + (cond ((integerp test-layout) + (inst ldrsw temp + (@ layout + (- (ash (+ instance-slots-offset + (get-dsd-index layout sb-kernel::flags)) + word-shift) + instance-pointer-lowtag))) + (inst tst temp test-layout)) + ((and desc-temp + (neq (tn-kind desc-temp) :unused)) + (inst load-constant desc-temp + (tn-byte-offset (emit-constant test-layout))) + (inst cmp layout desc-temp)) + (t + (let* ((test-id (layout-id test-layout)) + (depthoid (wrapper-depthoid test-layout)) + (offset (+ (id-bits-offset) + (ash (- depthoid 2) 2) + (- instance-pointer-lowtag)))) + (when (and target + (> depthoid sb-kernel::layout-id-vector-fixed-capacity)) + (inst ldrsw temp + (@ layout + (- (+ #+little-endian 4 + (ash (+ instance-slots-offset + (get-dsd-index layout sb-kernel::flags)) + word-shift)) + instance-pointer-lowtag))) + (inst cmp temp (add-sub-immediate (fixnumize depthoid))) + (inst b :lt (if not-p target done))) + (inst ldr (32-bit-reg this-id) (@ layout offset)) + ;; 8-bit IDs are permanently assigned, so no fixup ever needed for those. + (cond ((typep test-id '(and (signed-byte 8) (not (eql 0)))) + (if (minusp test-id) + (inst cmn (32-bit-reg this-id) (- test-id)) + (inst cmp (32-bit-reg this-id) test-id))) + (t + (destructuring-bind (size . label) + ;; This uses the bogus definition of :dword, the one which + ;; emits 4 bytes. _technically_ dword should be 8 bytes. + (register-inline-constant :dword `(:layout-id ,test-layout)) + (declare (ignore size)) + (inst load-from-label (32-bit-reg temp) label)) + (inst cmp (32-bit-reg this-id) (32-bit-reg temp)))))))) + +;;; This could be split into two vops to avoid wasting an allocation for 'temp' +;;; when the immediate form is used. +(define-vop () + (:translate sb-c::%structure-is-a) + (:args (x :scs (descriptor-reg))) + (:arg-types * (:constant t)) + (:policy :fast-safe) + (:conditional :eq) + (:info test-layout) + (:temporary (:sc unsigned-reg) this-id temp) + (:generator 4 + (structure-is-a x temp this-id test-layout))) + +(define-vop () + (:translate sb-c::structure-typep) + (:args (object :scs (descriptor-reg))) + (:arg-types * (:constant t)) + (:args-var args) + (:policy :fast-safe) + (:conditional) + (:info target not-p test-layout) + (:temporary (:sc descriptor-reg) layout) + (:temporary (:sc unsigned-reg + :unused-if + (and (instance-tn-ref-p args) + #1=(and (not (integerp test-layout)) + (let ((classoid (wrapper-classoid test-layout))) + (and (eq (classoid-state classoid) :sealed) + (not (classoid-subclasses classoid))))))) + temp) + (:temporary (:sc unsigned-reg + :unused-if (or (integerp test-layout) + #1#)) + this-id) + (:temporary (:sc descriptor-reg + :unused-if (not #1#)) + desc-temp) + (:generator 4 + (unless (instance-tn-ref-p args) + (inst and temp object lowtag-mask) + (inst cmp temp instance-pointer-lowtag) + (inst b :ne (if not-p target done))) + (loadw layout object instance-slots-offset instance-pointer-lowtag) + (structure-is-a layout temp this-id test-layout desc-temp target not-p done) + (inst b (if (if (integerp test-layout) + (not not-p) + not-p) + :ne :eq) target) + done)) + +(define-vop (structure-typep*) + (:args (layout :scs (descriptor-reg))) + (:arg-types * (:constant t)) + (:policy :fast-safe) + (:conditional) + (:info target not-p test-layout) + (:temporary (:sc unsigned-reg + :unused-if + #1=(and (not (integerp test-layout)) + (let ((classoid (wrapper-classoid test-layout))) + (and (eq (classoid-state classoid) :sealed) + (not (classoid-subclasses classoid)))))) + temp) + (:temporary (:sc unsigned-reg + :unused-if (or (integerp test-layout) + #1#)) + this-id) + (:temporary (:sc descriptor-reg + :unused-if (not #1#)) + desc-temp) + (:generator 4 + (structure-is-a layout temp this-id test-layout desc-temp target not-p done) + (inst b (if (if (integerp test-layout) + (not not-p) + not-p) + :ne :eq) target) + done)) + +(define-vop (keywordp type-predicate) + (:translate keywordp) + (:args-var args-ref) + (:generator 3 + #.(assert (= sb-impl::package-id-bits 16)) + (unless (csubtypep (tn-ref-type args-ref) (specifier-type 'symbol)) + (test-type value temp (if not-p target not-target) t (symbol-widetag) + :value-tn-ref args-ref)) + (inst ldrh temp (@ value (+ (ash symbol-name-slot word-shift) + (- other-pointer-lowtag) + 6))) + (inst cmp temp sb-impl::+package-id-keyword+) + (inst b (if not-p :ne :eq) target) + not-target)) diff --git a/src/compiler/arm64/values.lisp b/src/compiler/arm64/values.lisp index 353cbd3531..69a0455879 100644 --- a/src/compiler/arm64/values.lisp +++ b/src/compiler/arm64/values.lisp @@ -59,29 +59,51 @@ ;;; operand, but this seems unworthwhile. ;;; (define-vop (push-values) - (:args (vals :more t)) + (:args (vals :more t :scs (descriptor-reg any-reg immediate control-stack constant))) (:results (start :scs (any-reg) :from :load) (count :scs (any-reg))) (:info nvals) (:temporary (:scs (descriptor-reg)) temp) + (:vop-var vop) (:generator 20 - (move start csp-tn) - (inst add csp-tn csp-tn (* nvals n-word-bytes)) - (do ((val vals (tn-ref-across val)) - (i 0 (1+ i))) - ((null val)) - (let ((tn (tn-ref-tn val))) - (sc-case tn - (descriptor-reg - (storew tn start i)) - (control-stack - (load-stack-tn temp tn) - (storew temp start i))))) - (inst mov count (fixnumize nvals)))) + (unless (eq (tn-kind start) :unused) + (move start csp-tn)) + (let (prev-constant) + (flet ((load-tn (tn-ref) + (let ((tn (tn-ref-tn tn-ref))) + (sc-case tn + ((descriptor-reg any-reg) + tn) + ((immediate constant) + (cond ((eql (tn-value tn) 0) + zr-tn) + ((or (eql prev-constant (tn-value tn)) + (progn + (setf prev-constant (tn-value tn)) + nil)) + temp) + ((sc-is tn constant) + (load-constant vop tn temp) + temp) + (t + (load-immediate vop tn temp) + temp))) + (control-stack + (setf prev-constant nil) + (load-stack-tn temp tn) + temp))))) + (cond ((= nvals 1) + (inst str (load-tn vals) (@ csp-tn n-word-bytes :post-index))) + (t + (do ((val vals (tn-ref-across val)) + (i 0 (1+ i))) + ((null val)) + (inst str (load-tn val) (@ csp-tn n-word-bytes :post-index))))))) + (unless (eq (tn-kind count) :unused) + (inst mov count (fixnumize nvals))))) ;;; Push a list of values on the stack, returning Start and Count as used in ;;; unknown values continuations. -;;; (define-vop (values-list) (:args (arg :scs (descriptor-reg) :target list)) (:arg-types list) @@ -95,7 +117,9 @@ (:save-p :compute-only) (:generator 0 (move list arg) - (move start csp-tn) + + (unless (eq (tn-kind start) :unused) + (move start csp-tn)) LOOP (inst cmp list null-tn) @@ -108,39 +132,36 @@ (cerror-call vop 'bogus-arg-to-values-list-error list) DONE - (inst sub count csp-tn start) - (inst asr count count (- word-shift n-fixnum-tag-bits)))) + (unless (eq (tn-kind count) :unused) + (inst sub count csp-tn start) + (inst asr count count (- word-shift n-fixnum-tag-bits))))) ;;; Copy the more arg block to the top of the stack so we can use them ;;; as function arguments. -;;; (define-vop (%more-arg-values) - (:args (context :scs (descriptor-reg any-reg) :target src) - (skip :scs (any-reg immediate)) - (num :scs (any-reg) :target count)) - (:arg-types * positive-fixnum positive-fixnum) - (:temporary (:sc any-reg :from (:argument 0)) src) - (:temporary (:sc any-reg :from (:argument 2)) dst) - (:temporary (:sc descriptor-reg :from (:argument 1)) temp) + (:args (context :scs (descriptor-reg any-reg) :to :save) + (num :scs (any-reg) :target count :to (:result 1))) + (:arg-types * positive-fixnum) + (:temporary (:sc descriptor-reg) temp) (:temporary (:sc any-reg) i) (:results (start :scs (any-reg)) (count :scs (any-reg))) (:generator 20 - (sc-case skip - (immediate - (inst add src context (* (tn-value skip) n-word-bytes))) - (any-reg - (inst add src context (lsl skip (- word-shift n-fixnum-tag-bits))))) - (inst adds count num 0) + (cond ((eq (tn-kind count) :unused) + (setf count num)) + (t + (move count num))) + (when (eq (tn-kind start) :unused) + (setf start tmp-tn)) (move start csp-tn) + ;; Shift and check for zero in one go + (inst adds i zr-tn (lsl count (- word-shift n-fixnum-tag-bits))) (inst b :eq DONE) - (inst mov dst start) - (inst lsl i count (- word-shift n-fixnum-tag-bits)) - (inst add csp-tn start i) + (inst add csp-tn csp-tn i) LOOP (inst subs i i n-word-bytes) - (inst ldr temp (@ src i)) - (inst str temp (@ dst i)) + (inst ldr temp (@ context i)) + (inst str temp (@ start i)) (inst b :ne LOOP) DONE)) diff --git a/src/compiler/arm64/vm.lisp b/src/compiler/arm64/vm.lisp index 5bb0ccb6d6..9254b3dbcd 100644 --- a/src/compiler/arm64/vm.lisp +++ b/src/compiler/arm64/vm.lisp @@ -11,23 +11,25 @@ (in-package "SB-VM") +(defconstant-eqx +fixup-kinds+ #(:absolute :cond-branch :uncond-branch :layout-id + :ldr-str :move-wide) + #'equalp) + ;;;; register specs -(eval-when (:compile-toplevel :load-toplevel :execute) - (defvar *register-names* (make-array 32 :initial-element nil))) +(defvar *register-names* (make-array 32 :initial-element nil)) (macrolet ((defreg (name offset) (let ((offset-sym (symbolicate name "-OFFSET"))) - `(eval-when (:compile-toplevel :load-toplevel :execute) + `(progn (defconstant ,offset-sym ,offset) (setf (svref *register-names* ,offset-sym) ,(symbol-name name))))) (defregset (name &rest regs) - `(eval-when (:compile-toplevel :load-toplevel :execute) - (defparameter ,name + `(defglobal ,name (list ,@(mapcar #'(lambda (name) - (symbolicate name "-OFFSET")) regs)))))) + (symbolicate name "-OFFSET")) regs))))) (defreg nl0 0) (defreg nl1 1) @@ -48,40 +50,40 @@ (defreg r5 15) (defreg r6 16) (defreg r7 17) - (defreg r8 18) + (defreg #-darwin r8 #+darwin reserved 18) (defreg r9 19) + (defreg #+darwin r8 #-darwin r10 20) #+sb-thread - (defreg thread 20) + (defreg thread 21) #-sb-thread - (defreg r10 20) - - (defreg lexenv 21) - - (defreg nargs 22) - (defreg nfp 23) - (defreg ocfp 24) - (defreg cfp 25) - (defreg csp 26) - (defreg tmp 27) - (defreg null 28) - (defreg code 29) + (defreg r11 21) + + (defreg lexenv 22) + + (defreg nargs 23) + (defreg nfp 24) + (defreg ocfp 25) + (defreg cfp 26) + (defreg csp 27) + (defreg tmp 28) + (defreg null 29) (defreg lr 30) (defreg nsp 31) (defreg zr 31) (defregset system-regs - null cfp nsp lr code) + null cfp nsp lr) (defregset descriptor-regs - r0 r1 r2 r3 r4 r5 r6 r7 r8 r9 #-sb-thread r10 lexenv) + r0 r1 r2 r3 r4 r5 r6 r7 r8 r9 #-darwin r10 #-sb-thread r11 lexenv) (defregset non-descriptor-regs - nl0 nl1 nl2 nl3 nl4 nl5 nl6 nl7 nl8 nl9 nargs nfp ocfp) + nl0 nl1 nl2 nl3 nl4 nl5 nl6 nl7 nl8 nl9 nargs nfp ocfp lr) (defregset boxed-regs r0 r1 r2 r3 r4 r5 r6 - r7 r8 r9 #-sb-thread r10 #+sb-thread thread lexenv code) + r7 r8 r9 #-darwin r10 #-sb-thread r11 #+sb-thread thread lexenv) ;; registers used to pass arguments ;; @@ -89,7 +91,10 @@ (defconstant register-arg-count 4) ;; names and offsets for registers used to pass arguments (defregset *register-arg-offsets* r0 r1 r2 r3) - (defparameter *register-arg-names* '(r0 r1 r2 r3))) + (defparameter *register-arg-names* '(r0 r1 r2 r3)) + (defregset *descriptor-args* r0 r1 r2 r3 r4 r5 r6 r7 r8 r9) + (defregset *non-descriptor-args* nl0 nl1 nl2 nl3 nl4 nl5 nl6 nl7 nl8 nl9) + (defglobal *float-regs* (loop for i below 32 collect i))) ;;;; SB and SC definition: @@ -110,7 +115,6 @@ ;; Anything else that can be an immediate. (immediate immediate-constant) - ;; **** The stacks. ;; The control stack. (Scanned by GC) @@ -182,23 +186,19 @@ (non-descriptor-reg registers :locations #.non-descriptor-regs) - ;; Pointers to the interior of objects. Used only as a temporary. - (interior-reg registers - :locations (#.lr-offset)) - ;; **** Things that can go in the floating point registers. - ;; Non-Descriptor single-floats. + (single-immediate immediate-constant) + (double-immediate immediate-constant) + (single-reg float-registers :locations #.(loop for i below 32 collect i) - :constant-scs () + :constant-scs (single-immediate) :save-p t :alternate-scs (single-stack)) - - ;; Non-Descriptor double-floats. (double-reg float-registers :locations #.(loop for i below 32 collect i) - :constant-scs () + :constant-scs (double-immediate) :save-p t :alternate-scs (double-stack)) @@ -215,7 +215,8 @@ :alternate-scs (complex-double-stack)) (catch-block control-stack :element-size catch-block-size) - (unwind-block control-stack :element-size unwind-block-size)) + (unwind-block control-stack :element-size unwind-block-size) + (zero immediate-constant)) ;;;; Make some random tns for important registers. @@ -229,7 +230,6 @@ (defregtn null descriptor-reg) (defregtn lexenv descriptor-reg) - (defregtn code descriptor-reg) (defregtn tmp any-reg) (defregtn nargs any-reg) @@ -238,9 +238,9 @@ (defregtn zr any-reg) (defregtn cfp any-reg) (defregtn csp any-reg) - (defregtn lr interior-reg) + (defregtn lr any-reg) #+sb-thread - (defregtn thread interior-reg)) + (defregtn thread any-reg)) ;;; If VALUE can be represented as an immediate constant, then return the ;;; appropriate SC number, otherwise return NIL. @@ -248,13 +248,17 @@ (typecase value (null (values descriptor-reg-sc-number null-offset)) - ((or (integer #.sb-xc:most-negative-fixnum #.sb-xc:most-positive-fixnum) + ((or (integer #.most-negative-fixnum #.most-positive-fixnum) character) immediate-sc-number) (symbol (if (static-symbol-p value) immediate-sc-number - nil)))) + nil)) + (double-float + double-immediate-sc-number) + (single-float + single-immediate-sc-number))) (defun boxed-immediate-sc-p (sc) (eql sc immediate-sc-number)) @@ -325,20 +329,21 @@ (%logbitp integer index)))) (t (values :default nil)))) (%ldb - (flet ((validp (type width) - (and (valid-funtype `((constant-arg (integer 1 ,(1- width))) - (constant-arg (mod ,width)) + (flet ((validp (type) + (and (valid-funtype `((constant-arg (integer 1 ,(1- n-word-bits))) + (constant-arg integer) ,type) 'unsigned-byte) (destructuring-bind (size posn integer) (sb-c::basic-combination-args node) (declare (ignore integer)) - (and (plusp (sb-c::lvar-value posn)) - (<= (+ (sb-c::lvar-value size) - (sb-c::lvar-value posn)) - width)))))) - (if (or (validp 'word (1- n-word-bits)) - (validp 'signed-word (1- n-word-bits))) + (and (plusp (sb-c:lvar-value posn)) + (or (= (sb-c:lvar-value size) 1) + (<= (+ (sb-c:lvar-value size) + (sb-c:lvar-value posn)) + n-word-bits))))))) + (if (or (validp 'word) + (validp 'signed-word)) (values :transform '(lambda (size posn integer) (%%ldb integer size posn))) (values :default nil)))) @@ -383,4 +388,6 @@ sb-arm64-asm::encode-logical-immediate sb-arm64-asm::fixnum-encode-logical-immediate bic-encode-immediate - bic-fixnum-encode-immediate)) + bic-fixnum-encode-immediate + logical-immediate-or-word-mask + sb-arm64-asm::ldr-str-offset-encodable)) diff --git a/src/compiler/array-tran.lisp b/src/compiler/array-tran.lisp index 4b65a64007..b0177f6880 100644 --- a/src/compiler/array-tran.lisp +++ b/src/compiler/array-tran.lisp @@ -31,6 +31,10 @@ ;;; known supertype of the upgraded-array-element-type, if if the exact ;;; U-A-E-T is not known. (If it is NIL, the primary return value is as good ;;; as it gets.) +;;; FIXME: poorly named, it sounds like an accessor on an instance of ARRAY-TYPE, +;;; but unfortunately UPGRADED-ARRAY-ELEMENT-TYPE is a CL: symbol +;;; and %UPGRADED-ARRAY-ELEMENT-TYPE is already a thing as well. +;;; Perhaps ARRAY-IMPLIED-ELEMENT-TYPE would be less misleading? (defun array-type-upgraded-element-type (type) (typecase type ;; Note that this IF mightn't be satisfied even if the runtime @@ -109,7 +113,14 @@ ;; 2002-08-21 (values *wild-type* nil)))) -(defun array-type-declared-element-type (type) +(defun type-array-element-type (type) + (if (csubtypep type (specifier-type 'array)) + (multiple-value-bind (upgraded other) + (array-type-upgraded-element-type type) + (or other upgraded)) + *wild-type*)) + +(defun declared-array-element-type (type) (if (array-type-p type) (array-type-element-type type) *wild-type*)) @@ -127,14 +138,6 @@ :aref))) (lvar-type new-value)) -;;; Return true if ARG is NIL, or is a constant-lvar whose -;;; value is NIL, false otherwise. -(defun unsupplied-or-nil (arg) - (declare (type (or lvar null) arg)) - (or (not arg) - (and (constant-lvar-p arg) - (not (lvar-value arg))))) - (defun supplied-and-true (arg) (and arg (constant-lvar-p arg) @@ -144,9 +147,7 @@ ;;;; DERIVE-TYPE optimizers (defun derive-aref-type (array) - (multiple-value-bind (uaet other) - (array-type-upgraded-element-type (lvar-type array)) - (or other uaet))) + (type-array-element-type (lvar-type array))) (deftransform array-in-bounds-p ((array &rest subscripts)) (block nil @@ -223,64 +224,51 @@ (give-up)))))))) (defoptimizer (aref derive-type) ((array &rest subscripts)) - (declare (ignore subscripts)) (derive-aref-type array)) (defoptimizer ((setf aref) derive-type) ((new-value array &rest subscripts)) - (declare (ignore subscripts)) (assert-new-value-type new-value array)) -(macrolet ((define (name) - `(defoptimizer (,name derive-type) ((array index)) - (declare (ignore index)) - (derive-aref-type array)))) - (define hairy-data-vector-ref) - (define hairy-data-vector-ref/check-bounds) - (define data-vector-ref)) +(defoptimizers derive-type + (hairy-data-vector-ref hairy-data-vector-ref/check-bounds + data-vector-ref) + ((array index)) + (derive-aref-type array)) #+(or x86 x86-64) (defoptimizer (data-vector-ref-with-offset derive-type) ((array index offset)) - (declare (ignore index offset)) (derive-aref-type array)) (defoptimizer (vector-pop derive-type) ((array)) (derive-aref-type array)) -(macrolet ((define (name) - `(defoptimizer (,name derive-type) ((array index new-value)) - (declare (ignore index)) - (assert-new-value-type new-value array)))) - (define hairy-data-vector-set) - (define hairy-data-vector-set/check-bounds) - (define data-vector-set)) - -#+(or x86 x86-64) -(defoptimizer (data-vector-set-with-offset derive-type) ((array index offset new-value)) - (declare (ignore index offset)) +(defoptimizers derive-type + (hairy-data-vector-set + hairy-data-vector-set/check-bounds) + ;; DATA-VECTOR-SET is never used for value, so it doesn't need a type deriver. + ((array index new-value)) (assert-new-value-type new-value array)) ;;; Figure out the type of the data vector if we know the argument ;;; element type. (defun derive-%with-array-data/mumble-type (array) (let ((atype (lvar-type array))) - (when (array-type-p atype) - (specifier-type - `(simple-array ,(type-specifier - (array-type-specialized-element-type atype)) - (*)))))) + (cond ((array-type-p atype) + (specifier-type + `(simple-array ,(type-specifier + (array-type-specialized-element-type atype)) + (*)))) + ((csubtypep atype (specifier-type 'string)) + (specifier-type 'simple-string))))) (defoptimizer (%with-array-data derive-type) ((array start end)) - (declare (ignore start end)) (derive-%with-array-data/mumble-type array)) (defoptimizer (%with-array-data/fp derive-type) ((array start end)) - (declare (ignore start end)) (derive-%with-array-data/mumble-type array)) (defoptimizer (row-major-aref derive-type) ((array index)) - (declare (ignore index)) (derive-aref-type array)) (defoptimizer (%set-row-major-aref derive-type) ((array index new-value)) - (declare (ignore index)) (assert-new-value-type new-value array)) (defun check-array-dimensions (dims node) @@ -300,36 +288,35 @@ (unsupplied-or-nil displaced-to) (unsupplied-or-nil fill-pointer))) (spec - (or `(,(if simple 'simple-array 'array) - ;; element-type is usually an LVAR or nil, - ;; but MAKE-WEAK-VECTOR derive-type passes in 'T. - ,(cond ((or (not element-type) (eq element-type 't)) - t) - ((ctype-p element-type) - (type-specifier element-type)) - ((constant-lvar-p element-type) - (let ((ctype (careful-specifier-type - (lvar-value element-type)))) - (cond - ((or (null ctype) (contains-unknown-type-p ctype)) '*) - (t (sb-xc:upgraded-array-element-type - (lvar-value element-type)))))) - (t - '*)) - ,(cond ((constant-lvar-p dims) - (let* ((val (lvar-value dims)) - (cdims (ensure-list val))) - (unless (check-array-dimensions val node) - (return-from derive-make-array-type)) - (if simple - cdims - (length cdims)))) - ((csubtypep (lvar-type dims) - (specifier-type 'integer)) - '(*)) - (t - '*))) - 'array))) + `(,(if simple 'simple-array 'array) + ;; element-type is usually an LVAR or nil, + ;; but MAKE-WEAK-VECTOR derive-type passes in 'T. + ,(cond ((or (not element-type) (eq element-type 't)) + t) + ((ctype-p element-type) + (type-specifier element-type)) + ((constant-lvar-p element-type) + (let ((ctype (careful-specifier-type + (lvar-value element-type)))) + (cond + ((or (null ctype) (contains-unknown-type-p ctype)) '*) + (t (upgraded-array-element-type + (lvar-value element-type)))))) + (t + '*)) + ,(cond ((constant-lvar-p dims) + (let* ((val (lvar-value dims)) + (cdims (ensure-list val))) + (unless (check-array-dimensions val node) + (return-from derive-make-array-type)) + (if simple + cdims + (length cdims)))) + ((csubtypep (lvar-type dims) + (specifier-type 'integer)) + '(*)) + (t + '*))))) (if (and (not simple) (or (supplied-and-true adjustable) (supplied-and-true displaced-to) @@ -346,11 +333,10 @@ node)) (defoptimizer (make-array-header* derive-type) ((&rest inits)) - (let* ((data-position #.(sb-vm:slot-offset - (find 'sb-vm::data (sb-vm:primitive-object-slots - (find 'array sb-vm:*primitive-objects* - :key 'sb-vm:primitive-object-name)) - :key 'sb-vm:slot-name))) + (let* ((data-position + #.(sb-vm:slot-offset + (sb-vm::primitive-object-slot (sb-vm::primitive-object 'array) + 'sb-vm::data))) (data (nth data-position inits)) (type (lvar-type data))) (when (array-type-p type) @@ -361,7 +347,6 @@ ((dims widetag n-bits &key adjustable fill-pointer displaced-to &allow-other-keys) node) - (declare (ignore n-bits)) (let ((saetp (and (constant-lvar-p widetag) (find (lvar-value widetag) sb-vm:*specialized-array-element-type-properties* @@ -379,14 +364,27 @@ (define-source-transform vector (&rest elements) `(make-array ,(length elements) :initial-contents (list ,@elements))) -;;; Just convert it into a MAKE-ARRAY. -(deftransform make-string ((length &key - (element-type 'character) - (initial-element (code-char 0)))) - `(the simple-string (make-array (the index length) - :element-type element-type - ,@(when initial-element - '(:initial-element initial-element))))) +;;; Convert it into a MAKE-ARRAY if the element-type is known at compile-time. +;;; Otherwise, don't. This prevents allocating memory for a million element +;;; array of things that are not characters, and then signaling an error. +(deftransform make-string ((length &key element-type initial-element)) + (let ((elt-ctype + (cond ((not element-type) (specifier-type 'character)) + ((constant-lvar-p element-type) + (ir1-transform-specifier-type (lvar-value element-type)))))) + (when (or (not elt-ctype) + (eq elt-ctype *empty-type*) ; silly, don't do it + (contains-unknown-type-p elt-ctype)) + (give-up-ir1-transform)) + (multiple-value-bind (subtypep certainp) + (csubtypep elt-ctype (specifier-type 'character)) + (if (not certainp) (give-up-ir1-transform)) ; could be valid, don't know + (if (not subtypep) + (abort-ir1-transform "~S is not a valid :ELEMENT-TYPE for MAKE-STRING" + (lvar-value element-type)))) + `(the simple-string (make-array (the index length) + ,@(when initial-element '(:initial-element initial-element)) + :element-type ',(type-specifier elt-ctype))))) ;; Traverse the :INTIAL-CONTENTS argument to an array constructor call, ;; changing the skeleton of the data to be constructed by calls to LIST @@ -405,7 +403,7 @@ ;; optimizing `#(#(foo bar) #(,x ,y)) we convert the whole expression ;; into (VECTOR 'FOO 'BAR X Y), whereas in the unidimensional case ;; it never makes sense to turn #(FOO BAR) into (VECTOR 'FOO 'BAR). - (when (or (and (= rank 1) (sb-xc:constantp initial-contents env)) + (when (or (and (= rank 1) (constantp initial-contents env)) ;; If you inhibit inlining these - game over. (fun-lexically-notinline-p 'vector env) (fun-lexically-notinline-p 'list env) @@ -413,12 +411,12 @@ (return-from rewrite-initial-contents (values nil nil))) (let ((dimensions (make-array rank :initial-element nil)) (output)) - (named-let recurse ((form (handler-case (sb-xc:macroexpand initial-contents env) + (named-let recurse ((form (handler-case (macroexpand initial-contents env) (error () (return-from rewrite-initial-contents)))) (axis 0)) (flet ((make-list-ctor (tail &optional (prefix nil prefixp) &aux val) - (when (and (sb-xc:constantp tail) + (when (and (constantp tail) (or (proper-list-p (setq val (constant-form-value tail env))) (and (vectorp val) (not prefixp)))) (setq form @@ -435,7 +433,7 @@ (unless (and (typep form '(cons (member list vector))) (do ((items (cdr form)) (length 0 (1+ length)) - (fun (let ((axis (the (mod #.sb-xc:array-rank-limit) (1+ axis)))) + (fun (let ((axis (the (mod #.array-rank-limit) (1+ axis)))) (if (= axis rank) (lambda (item) (push item output)) (lambda (item) (recurse item axis)))))) @@ -458,16 +456,16 @@ ;; If the unaltered INITIAL-CONTENTS were constant, then the flattened ;; form must be too. Turning it back to a self-evaluating object ;; is essential to avoid compile-time blow-up on huge vectors. - (if (sb-xc:constantp initial-contents env) + (if (constantp initial-contents env) (map 'vector (lambda (x) (constant-form-value x env)) output) (let ((f (if (singleton-p output) 'list 'vector))) `(locally (declare (notinline ,f)) (,f ,@(mapcar (lambda (x) (cond ((and (symbolp x) (not (nth-value - 1 (sb-xc:macroexpand-1 x env)))) + 1 (macroexpand-1 x env)))) x) - ((sb-xc:constantp x env) + ((constantp x env) `',(constant-form-value x env)) (t `(locally (declare (inline ,f)) ,x)))) @@ -484,13 +482,13 @@ ;;; in this path, mainly due to complications in picking the right widetag. (define-source-transform make-array (dims-form &rest rest &environment env &aux dims dims-constp) - (cond ((and (sb-xc:constantp dims-form env) + (cond ((and (constantp dims-form env) (proper-list-p (setq dims (constant-form-value dims-form env))) (not (singleton-p dims)) (every (lambda (x) (typep x 'index)) dims)) (setq dims-constp t)) ((and (cond ((typep (setq dims (handler-case - (sb-xc:macroexpand dims-form env) + (macroexpand dims-form env) (error () (return-from make-array (values nil t))))) '(cons (eql list))) @@ -499,7 +497,7 @@ ;; `(,X 2 1) -> (LIST* X '(2 1)) for example ((typep dims '(cons (eql list*) cons)) (let ((last (car (last dims)))) - (when (sb-xc:constantp last env) + (when (constantp last env) (let ((lastval (constant-form-value last env))) (when (listp lastval) (setq dims (append (butlast (cdr dims)) lastval)) @@ -507,7 +505,7 @@ (proper-list-p dims) (not (singleton-p dims))) ;; If you spell '(2 2) as (LIST 2 2), it is constant for purposes of MAKE-ARRAY. - (when (every (lambda (x) (sb-xc:constantp x env)) dims) + (when (every (lambda (x) (constantp x env)) dims) (let ((values (mapcar (lambda (x) (constant-form-value x env)) dims))) (when (every (lambda (x) (typep x 'index)) values) (setq dims values dims-constp t))))) @@ -539,7 +537,7 @@ (case k (:element-type (unless (eq et unsupplied) (return nil)) - (setq et (car v) et-constp (sb-xc:constantp et env))) + (setq et (car v) et-constp (constantp et env))) (:initial-element (when (or contents element) (return nil)) (setq element v)) @@ -589,6 +587,7 @@ (t '*)) ,(if dims-constp dims (length dims))) (make-array-header* + sb-vm:simple-array-widetag ,@(sb-vm::make-array-header-inits `(make-array ,size ,@keys) size dims))))) `(let* (,@axis-bindings ,@et-binding (,size (the index (* ,@dims)))) @@ -608,13 +607,13 @@ `(fill-array ,(car contents) ,alloc-form))))))) (define-source-transform coerce (x type &environment env) - (if (and (sb-xc:constantp type env) + (if (and (constantp type env) (proper-list-p x) (memq (car x) '(sb-impl::|List| list sb-impl::|Vector| vector))) (let* ((type (constant-form-value type env)) (length (1- (length x))) - (ctype (careful-values-specifier-type type))) + (ctype (careful-specifier-type type))) (if (and ctype (neq ctype *empty-type*) (csubtypep ctype (specifier-type '(array * (*))))) @@ -636,34 +635,126 @@ (proper-list-p sequence) (typep sequence 'sequence))) +;;; Numeric sizes which are smaller than a word, or an even multiple of a byte, +;;; do not need zero-fill because you can't produce a bogus object by reading +;;; an element. But odd sizes such as (UNSIGNED-BYTE 7) should be zero-filled. +;;; CHARACTER too because it's it's 21 bits taking up the space of 32 bits. +;;; Technically the floating-point types should probably be zero-filled because +;;; there may otherwise be trapping NaNs. +(defun should-zerofill-p (saetp &aux (spec (sb-vm:saetp-specifier saetp)) + (ctype (sb-vm:saetp-ctype saetp))) + (or (eq spec 't) + (and (numeric-type-p ctype) + (> (sb-vm:saetp-n-bits saetp) 1) + (consp spec) + (not (eql (second spec) (sb-vm:saetp-n-bits saetp)))) + ;; Actually, nothing bad seems to happen by seeing char codes over CHAR-CODE-LIMIT + ;; (and (eq spec 'character) (= bits 32)) + )) + +(declaim (inline calc-nwords-form)) +(defun calc-nwords-form (saetp const-length + &aux (n-bits (sb-vm:saetp-n-bits saetp)) + (n-pad-elements (sb-vm:saetp-n-pad-elements saetp))) + (when const-length + (return-from calc-nwords-form + (if (typep const-length 'index) + (ceiling (* (+ const-length n-pad-elements) n-bits) sb-vm:n-word-bits)))) + (let ((padded-length-form (if (zerop n-pad-elements) + '%length + `(+ %length ,n-pad-elements)))) + (cond ((= n-bits 0) 0) + ((= n-bits sb-vm:n-word-bits) padded-length-form) + ((> n-bits sb-vm:n-word-bits) ; e.g. double-float on 32-bit + (let ((n-words-per-element + (the fixnum (/ n-bits sb-vm:n-word-bits)))) ; i.e., not RATIO + #+64-bit `(* ,padded-length-form ,n-words-per-element) + #-64-bit `(the fixnum (* ,padded-length-form ,n-words-per-element)))) + (t + ;; This would have to change if we ever implement Unicode strings + ;; using 3 bytes per char (as has been suggested by xof) which makes + ;; the number of elements per word a fraction. + (let ((n-elements-per-word + (the fixnum (/ sb-vm:n-word-bits n-bits)))) ; i.e., not RATIO + ;; Use the standard algorithm for integer division rounding up, + ;; but with right-shift as the divide operator, i.e. + ;; (NTH-VALUE 0 (CEILING length n-elements-per-word)) without going + ;; through the ceiling transform, because that needs a few extra + ;; machinations to eliminate the un-needed second return value. + `(ash (+ (truly-the index ,padded-length-form) ,(1- n-elements-per-word)) + ,(- (1- (integer-length n-elements-per-word))))))))) + +;;; TODO: "initial-element #\space" for strings would be nice to handle. +(declaim (inline splat-value-p)) +(defun splat-value-p (elt-ctype initial-element default-initial-element) + (declare (ignorable elt-ctype)) + ;; If the initial-element is specified and equivalent to 0-fill + ;; then use SPLAT. + (if (constant-lvar-p initial-element) + (cond ((eql (lvar-value initial-element) default-initial-element) + 0) + ;; If SPLAT is not always a no-op - which it is for everything + ;; but x86-64 - then also use it to store NIL or unbound-marker, + ;; which is better than QUICKFILL on small arrays. Arguably it is + ;; a defect of the FILL transforms that they can't do as well. + #+x86-64 + ((eq (lvar-value initial-element) nil) + sb-vm:nil-value)) + ;; This case should not be architecture-dependent, and it isn't, + ;; except that the other architectures lack the ability + ;; to convert SPLAT via a vop. + ;; I feel that it would be a lot easier if unbound-marker manifested + ;; itself as a compile-time literal, but there's no lisp type for it + ;; and I guess we don't like that. + ;; So why not just return T from ctype-of for that object? + #+x86-64 + (when (eq elt-ctype *universal-type*) + (let ((node (lvar-uses initial-element))) + (when (and (combination-p node) + (lvar-fun-is (combination-fun node) '(%%primitive)) + (let* ((args (combination-args node)) + (arg (car args)) + (leaf (when (ref-p (lvar-uses arg)) + (ref-leaf (lvar-uses arg))))) + (and (constant-p leaf) ; (I think it has to be) + (eq (constant-value leaf) 'make-unbound-marker)))) + ;; don't need to look at the other codegen arg which is + ;; surely NIL. + :unbound))))) + ;;; This baby is a bit of a monster, but it takes care of any MAKE-ARRAY ;;; call which creates a vector with a known element type -- and tries ;;; to do a good job with all the different ways it can happen. (defun transform-make-array-vector (length element-type initial-element initial-contents call - &key adjustable fill-pointer) - (let* ((c-length (if (lvar-p length) - (if (constant-lvar-p length) (lvar-value length)) - length)) - (complex (cond ((and (or - (not fill-pointer) - (and (constant-lvar-p fill-pointer) - (null (lvar-value fill-pointer)))) - (or - (not adjustable) - (and - (constant-lvar-p adjustable) - (null (lvar-value adjustable))))) - nil) - ((and (constant-lvar-p adjustable) - (lvar-value adjustable))) - ((and fill-pointer - (constant-lvar-p fill-pointer) - (lvar-value fill-pointer))) - (t - ;; Deciding between complex and simple at - ;; run-time would be too much hassle - (give-up-ir1-transform)))) + &key adjustable fill-pointer + &aux c-length) + (when (and initial-contents initial-element) + (abort-ir1-transform "Both ~S and ~S specified." + :initial-contents :initial-element)) + (setq c-length (if (lvar-p length) ; some callers pass an integer per se + (if (constant-lvar-p length) (lvar-value length)) + length)) + (when (and (integerp c-length) ; 'bad-code.pure' tries to pass ((("foo"))) e.g. + fill-pointer + (csubtypep (lvar-type fill-pointer) (specifier-type 'index)) + (not (types-equal-or-intersect (lvar-type fill-pointer) + (specifier-type `(integer 0 ,c-length))))) + (abort-ir1-transform "Invalid fill-pointer ~s for a vector of length ~s." + (type-specifier (lvar-type fill-pointer)) + c-length)) + (let* ((expressly-adjustable (cond ((not adjustable) nil) + ((not (constant-lvar-p adjustable)) :maybe) + (t (and (lvar-value adjustable) t)))) + (has-fill-pointer (cond ((not fill-pointer) nil) + ((numeric-type-p (lvar-type fill-pointer)) t) + ((constant-lvar-p fill-pointer) + (not (null (lvar-value fill-pointer)))) + (t :maybe))) + (array-header-p (cond ((or (eq expressly-adjustable t) (eq has-fill-pointer t)) t) + ((or (eq expressly-adjustable :maybe) (eq has-fill-pointer :maybe)) + ;; Picking between simple and nonsimple at runtime is hard + (give-up-ir1-transform)))) (elt-spec (if element-type (lvar-value element-type) ; enforces const-ness. t)) @@ -675,55 +766,14 @@ (give-up-ir1-transform)) (t (find-saetp-by-ctype elt-ctype)))) + (n-words-form (or (calc-nwords-form saetp c-length) (give-up-ir1-transform))) (default-initial-element (sb-vm:saetp-initial-element-default saetp)) - (n-bits (sb-vm:saetp-n-bits saetp)) - (typecode (sb-vm:saetp-typecode saetp)) - (n-pad-elements (sb-vm:saetp-n-pad-elements saetp)) - (n-words-form - (cond ((not c-length) - (let ((padded-length-form (if (zerop n-pad-elements) - 'length - `(+ length ,n-pad-elements)))) - (cond - ((= n-bits 0) 0) - ((>= n-bits sb-vm:n-word-bits) - `(* ,padded-length-form - ;; i.e., not RATIO - ,(the fixnum (/ n-bits sb-vm:n-word-bits)))) - (t - (let ((n-elements-per-word (/ sb-vm:n-word-bits n-bits))) - (declare (type index n-elements-per-word)) ; i.e., not RATIO - `(ceiling (truly-the index ,padded-length-form) - ,n-elements-per-word)))))) - ((and (fixnump c-length) - (>= c-length 0)) - (ceiling (* (+ c-length n-pad-elements) n-bits) - sb-vm:n-word-bits)) - (t - (give-up-ir1-transform)))) - (data-result-spec - `(simple-array ,(sb-vm:saetp-specifier saetp) (,(or c-length '*)))) - (result-spec - (if complex - `(and (array ,(sb-vm:saetp-specifier saetp) (*)) - (not simple-array)) - `(simple-array - ,(sb-vm:saetp-specifier saetp) (,(or c-length '*))))) (data-alloc-form - `(truly-the ,data-result-spec - (allocate-vector ,typecode - ;; If LENGTH is a singleton list, - ;; we want to avoid reading it. - (the index ,(or c-length 'length)) - ,n-words-form)))) - (when (and c-length - fill-pointer - (csubtypep (lvar-type fill-pointer) (specifier-type 'index)) - (not (types-equal-or-intersect (lvar-type fill-pointer) - (specifier-type `(integer 0 ,c-length))))) - (abort-ir1-transform "Invalid fill-pointer ~s for a vector of length ~s." - (type-specifier (lvar-type fill-pointer)) - c-length)) + `(truly-the + (simple-array ,(sb-vm:saetp-specifier saetp) (,(or c-length '*))) + (allocate-vector #+ubsan ,(not (or initial-contents initial-element)) + ,(sb-vm:saetp-typecode saetp) %length nwords)))) + (flet ((eliminate-keywords () (eliminate-keyword-args call 1 @@ -732,81 +782,131 @@ (:initial-element initial-element) (:adjustable adjustable) (:fill-pointer fill-pointer)))) - (with-alloc-form (&optional data-wrapper) - (cond (complex - (let* ((constant-fill-pointer-p (constant-lvar-p fill-pointer)) - (fill-pointer-value (and constant-fill-pointer-p - (lvar-value fill-pointer)))) - `(let ((%length (the index ,(or c-length 'length)))) - (truly-the - ,result-spec - (make-array-header* ,(or (sb-vm:saetp-complex-typecode saetp) - sb-vm:complex-vector-widetag) - ;; fill-pointer - ,(cond ((eq fill-pointer-value t) - '%length) - (fill-pointer-value) - ((and fill-pointer - (not constant-fill-pointer-p)) - `(cond ((or (eq fill-pointer t) - (null fill-pointer)) - %length) - ((> fill-pointer %length) - (error "Invalid fill-pointer ~a" fill-pointer)) - (t - fill-pointer))) - (t - '%length)) - ;; fill-pointer-p - ,(and fill-pointer - `(and fill-pointer t)) - ;; elements - %length - ;; data - (let ((data ,data-alloc-form)) - ,(or data-wrapper 'data)) - ;; displacement - 0 - ;; displaced-p - nil - ;; displaced-from - nil - ;; dimensions - %length))))) - (data-wrapper - (subst data-alloc-form 'data data-wrapper)) - (t - data-alloc-form)))) - (cond ((and initial-element initial-contents) - (abort-ir1-transform "Both ~S and ~S specified." - :initial-contents :initial-element)) - ;; Case (1) - ;; :INITIAL-CONTENTS (LIST ...), (VECTOR ...) and `(1 1 ,x) with a - ;; constant LENGTH. - ((and initial-contents c-length - (lvar-matches initial-contents - ;; FIXME: probably don't need all 4 of these now? - :fun-names '(list vector - sb-impl::|List| sb-impl::|Vector|) - :arg-count c-length)) - (let ((parameters (eliminate-keywords)) - (elt-vars (make-gensym-list c-length)) - (lambda-list '(length))) - (splice-fun-args initial-contents :any c-length) - (dolist (p parameters) - (setf lambda-list - (append lambda-list - (if (eq p 'initial-contents) - elt-vars - (list p))))) + (wrap (underlying) + `(let* ((%length ,(or c-length '(the index length))) + (nwords ,n-words-form)) + (declare (flushable sb-vm::splat)) + ,(if (not array-header-p) + underlying ; was already cast using TRULY-THE + (let* ((constant-fill-pointer-p (and fill-pointer + (constant-lvar-p fill-pointer))) + (fill-pointer-value (and constant-fill-pointer-p + (lvar-value fill-pointer))) + (length-expr + (cond ((eq fill-pointer-value t) '%length) + (fill-pointer-value) + ((and fill-pointer (not constant-fill-pointer-p)) + `(cond ((or (eq fill-pointer t) (null fill-pointer)) + %length) + ((> fill-pointer %length) + (error "Invalid fill-pointer ~a" fill-pointer)) + (t fill-pointer))) + (t '%length))) + ;; MAKE-ARRAY-HEADER* demands a constant, not an expression + ;; for the the header word. + (header-bits + (logior (if (eq has-fill-pointer t) ; (i.e. can't handle :maybe) + (ash sb-vm:+array-fill-pointer-p+ sb-vm:array-flags-position) + 0) + (or (sb-vm:saetp-complex-typecode saetp) + sb-vm:complex-vector-widetag))) + (array-header + `(truly-the + ;; A constant length must not be part of the result type. + (and (array ,(sb-vm:saetp-specifier saetp) (*)) + (not simple-array)) + (make-array-header* ,header-bits + ,length-expr ; fill-pointer + %length ; total number of elements + ,underlying + 0 ; displacement + nil ; displaced-p + nil ; displaced-from + %length)))) ; dimensions + (if (eq has-fill-pointer :maybe) + `(let ((%array ,array-header)) + (when fill-pointer + (logior-array-flags %array sb-vm:+array-fill-pointer-p+)) + %array) + array-header)))))) + (cond ;; Case (1) - :INITIAL-ELEMENT + (initial-element + ;; If the specified initial element is equivalent to zero-filling, + ;; then use SPLAT, which is elidable for heap allocations. + ;; Also pick off (at least 2) other common cases for SPLAT: NIL and + ;; unbound-marker. The latter helps PCL ctors not to call FILL. + (let ((splat (splat-value-p elt-ctype initial-element + default-initial-element)) + (init (if (constant-lvar-p initial-element) + (list 'quote (lvar-value initial-element)) + 'initial-element)) + (lambda-list `(length ,@(eliminate-keywords)))) `(lambda ,lambda-list - (declare (type ,elt-spec ,@elt-vars) - (ignorable ,@lambda-list)) - ,(with-alloc-form - `(initialize-vector data ,@elt-vars))))) - ;; Case (2) - ;; constant :INITIAL-CONTENTS and LENGTH - ((and initial-contents c-length + (declare (ignorable ,@lambda-list)) + ,(wrap (cond ((not splat) + `(quickfill ,data-alloc-form + ,(if (eq elt-spec t) init + `(the ,elt-spec ,init)))) + ((or (eq splat :unbound) + (and (constant-lvar-p initial-element) + (testable-type-p elt-ctype) + (ctypep (lvar-value initial-element) elt-ctype))) + ;; all good + `(sb-vm::splat ,data-alloc-form nwords ,splat)) + (t + ;; uncertain if initial-element is type-correct + `(progn (the ,elt-spec ,init) ; check en passant + (sb-vm::splat ,data-alloc-form nwords + ,splat)))))))) + + ;; Case (2) - neither element nor contents specified. + ((not initial-contents) + ;; The implicit default is to zero-fill, but DX arrays could be initialized + ;; with the unbound-marker. Either way it's worth a style-warning + ;; if it looks wrong for the specified element type. + ;; This situation arises e.g. in (MAKE-ARRAY 4 :ELEMENT-TYPE '(INTEGER 1 5)) + ;; ANSI's definition of MAKE-ARRAY says "If INITIAL-ELEMENT is not supplied, + ;; the consequences of later reading an uninitialized element of new-array + ;; are undefined," so this could be legal code as long as the user plans to + ;; write before he reads, and if he doesn't we're free to do anything we like. + ;; But in case the user doesn't know to write elements before he reads elements + ;; (or to read manuals before he writes code:-), we'll signal a STYLE-WARNING + ;; in case he didn't realize this. + #-sb-xc-host + (when (and ;; Warn only if any array elements are initialized using the default. + (not (eql c-length 0)) + ;; If it's coming from the source transform, + ;; then fill-array means it was supplied initial-contents + (not (lvar-matches-calls (combination-lvar call) + '(make-array-header* fill-array))) + (testable-type-p elt-ctype) + ;; I really don't want to style-warn about + ;; (MAKE-ARRAY 1 :ELEMENT-TYPE 'STANDARD-CHAR) even though technically + ;; the default fill of #\nul is wrong because it must match the specified + ;; element type, not the upgraded array type, and #\nul isn't standard. + (not (ctypep default-initial-element + (if (and (eq elt-spec 'standard-char) (not initial-element)) + (sb-vm:saetp-ctype saetp) + elt-ctype)))) + (compiler-style-warn 'initial-element-mismatch-style-warning + :format-control "The default initial element ~S is not a ~S." + :format-arguments (list default-initial-element elt-spec))) + (let ((lambda-list `(length ,@(eliminate-keywords)))) + `(lambda ,lambda-list + (declare (ignorable ,@lambda-list)) + ,(wrap (cond ((eql (sb-vm:saetp-typecode saetp) sb-vm:simple-vector-widetag) + `(sb-vm::splat ,data-alloc-form nwords + ;; uninitialized reads are trapped regardless of safety + ;; if #+ubsan + #+ubsan :trap + #-ubsan 0)) + (t + ;; otherwise, reading an element can't cause an invalid bit pattern + ;; to be observed, but the bits could be random. + data-alloc-form)))))) + + ;; Case (3) - constant :INITIAL-CONTENTS and LENGTH + ((and c-length (constant-lvar-p initial-contents) ;; As a practical matter, the initial-contents should not be ;; too long, otherwise the compiler seems to spend forever @@ -824,84 +924,58 @@ (let ((lambda-list `(length ,@(eliminate-keywords)))) `(lambda ,lambda-list (declare (ignorable ,@lambda-list)) - ,(with-alloc-form - `(initialize-vector data - ,@(map 'list (lambda (elt) - `(the ,elt-spec ',elt)) - contents))))))) - ;; Case (3) - ;; any other :INITIAL-CONTENTS - (initial-contents - (let ((lambda-list `(length ,@(eliminate-keywords)))) - `(lambda ,lambda-list - (declare (ignorable ,@lambda-list)) - (unless (= (length initial-contents) ,(or c-length 'length)) - (error "~S has ~D elements, vector length is ~D." - :initial-contents (length initial-contents) - ,(or c-length 'length))) - ,(with-alloc-form - `(replace data initial-contents))))) + ,(wrap `(initialize-vector + ,data-alloc-form + ,@(map 'list + (if (eq elt-spec t) ; THE would be pure noise + (lambda (elt) `',elt) + (lambda (elt) `(the ,elt-spec ',elt))) + contents))))))) + ;; Case (4) - ;; :INITIAL-ELEMENT, not EQL to the default - ((and initial-element - (or (not (constant-lvar-p initial-element)) - (not (eql default-initial-element (lvar-value initial-element))))) - (let ((lambda-list `(length ,@(eliminate-keywords))) - (init (if (constant-lvar-p initial-element) - (list 'quote (lvar-value initial-element)) - 'initial-element))) + ;; :INITIAL-CONTENTS (LIST ...), (VECTOR ...) and `(1 1 ,x) with constant LENGTH. + ((and c-length + (lvar-matches initial-contents + ;; FIXME: probably don't need all 4 of these now? + :fun-names '(list vector + sb-impl::|List| sb-impl::|Vector|) + :arg-count c-length)) + (let ((parameters (eliminate-keywords)) + (elt-vars (make-gensym-list c-length)) + (lambda-list '(length))) + (splice-fun-args initial-contents :any c-length) + (dolist (p parameters) + (setf lambda-list + (append lambda-list + (if (eq p 'initial-contents) + elt-vars + (list p))))) `(lambda ,lambda-list - (declare (ignorable ,@lambda-list)) - ,(with-alloc-form - `(fill data (the ,elt-spec ,init)))))) - ;; Case (5) - ;; just :ELEMENT-TYPE, or maybe with :INITIAL-ELEMENT EQL to the - ;; default + (declare ,@(unless (eq elt-spec t) `((type ,elt-spec ,@elt-vars))) + (ignorable ,@lambda-list)) + ,(wrap `(initialize-vector ,data-alloc-form ,@elt-vars))))) + + ;; Case (5) - :INITIAL-CONTENTS and indeterminate length (t - #-sb-xc-host - (and (and (testable-type-p elt-ctype) - (neq elt-ctype *empty-type*) - (not (ctypep default-initial-element elt-ctype))) - ;; This situation arises e.g. in (MAKE-ARRAY 4 :ELEMENT-TYPE - ;; '(INTEGER 1 5)) ANSI's definition of MAKE-ARRAY says "If - ;; INITIAL-ELEMENT is not supplied, the consequences of later - ;; reading an uninitialized element of new-array are undefined," - ;; so this could be legal code as long as the user plans to - ;; write before he reads, and if he doesn't we're free to do - ;; anything we like. But in case the user doesn't know to write - ;; elements before he reads elements (or to read manuals before - ;; he writes code:-), we'll signal a STYLE-WARNING in case he - ;; didn't realize this. - (cond - (initial-element - (compiler-warn "~S ~S is not a ~S" - :initial-element default-initial-element - elt-spec)) - ;; For the default initial element, only warn if - ;; any array elements are initialized using it. - ((and (not (eql c-length 0)) - ;; If it's coming from the source transform, - ;; then fill-array means it was supplied initial-contents - (not (lvar-matches-calls (combination-lvar call) - '(make-array-header* fill-array)))) - (compiler-style-warn "The default initial element ~S is not a ~S." - default-initial-element - elt-spec)))) (let ((lambda-list `(length ,@(eliminate-keywords)))) `(lambda ,lambda-list (declare (ignorable ,@lambda-list)) - ,(with-alloc-form)))))))) + (let ((content-length (length initial-contents))) + (unless (= content-length ,(or c-length 'length)) + (sb-vm::initial-contents-error content-length ,(or c-length 'length)))) + ,(wrap `(replace ,data-alloc-form initial-contents))))))))) ;;; IMPORTANT: The order of these three MAKE-ARRAY forms matters: the least ;;; specific must come first, otherwise suboptimal transforms will result for ;;; some forms. +;;; 3rd choice (deftransform make-array ((dims &key initial-element initial-contents element-type adjustable fill-pointer displaced-to displaced-index-offset) - (t &rest *) * + (t &rest t) * :node node) (delay-ir1-transform node :constraint) (when (and initial-contents initial-element) @@ -968,10 +1042,14 @@ ,@(maybe-arg fill-pointer) ,@(maybe-arg displaced-to) ,@(maybe-arg displaced-index-offset)))) - (cond ((or (not initial-element) - (and (constant-lvar-p initial-element) - (eql (lvar-value initial-element) - (sb-vm:saetp-initial-element-default saetp)))) + (cond ((not initial-element) creation-form) + ;; with ubsan the call to %MAKE-ARRAY needs to see the :INITIAL-ELEMENT + ;; even if it looks like the default, otherwise %MAKE-ARRAY reserves the right + ;; to scribble on the array. Same for allocators that don't prezero + #-ubsan + ((and (constant-lvar-p initial-element) + (eql (lvar-value initial-element) + (sb-vm:saetp-initial-element-default saetp))) creation-form) (t ;; error checking for target, disabled on the host because @@ -992,11 +1070,14 @@ (type-specifier (sb-vm:saetp-ctype saetp)) 'upgraded-array-element-type eltype))) - ((not (ctypep value eltype-type)) - ;; this case will not cause an error at runtime, but + ((multiple-value-bind (typep surep) + (ctypep value eltype-type) + (and (not typep) surep)) + ;; This case will not cause an error at runtime, but ;; it's still worth STYLE-WARNing about. - (compiler-style-warn "~S is not a ~S." - value eltype))))) + (compiler-style-warn 'initial-element-mismatch-style-warning + :format-control "~S is not a ~S." + :format-arguments (list value eltype)))))) `(let ((array ,creation-form)) (multiple-value-bind (vector) (%data-vector-and-index array 0) @@ -1006,6 +1087,7 @@ ;;; The list type restriction does not ensure that the result will be a ;;; multi-dimensional array. But the lack of adjustable, fill-pointer, ;;; and displaced-to keywords ensures that it will be simple. +;;; 2nd choice (deftransform make-array ((dims &key element-type initial-element initial-contents adjustable fill-pointer) @@ -1018,34 +1100,35 @@ * :node call) (block make-array - ;; If lvar-use of DIMS is a call to LIST, then it must mean that LIST - ;; was declared notinline - because if it weren't, then it would have been - ;; source-transformed into CONS - which gives us reason NOT to optimize - ;; this call to MAKE-ARRAY. So look for CONS instead of LIST, - ;; which means that LIST was *not* declared notinline. - (when (and (lvar-matches dims :fun-names '(cons) :arg-count 2) - (let ((cdr (second (combination-args (lvar-uses dims))))) - (and (constant-lvar-p cdr) (null (lvar-value cdr))))) - (let* ((args (splice-fun-args dims :any 2)) ; the args to CONS - (dummy (cadr args))) - (flush-dest dummy) + ;; Recognize vector construction where the length is spelled as (LIST n) + ;; or (LIST* n nil). Don't care if FUN-LEXICALLY-NOTINLINE-P on those because + ;; you can't portably observe whether they're called (tracing them isn't allowed). + ;; XXX: minor OAOO problem, see similar logic in (VALUES-LIST OPTIMIZER). + (awhen (cond ((and (lvar-matches dims :fun-names '(list) :arg-count 1)) + (car (splice-fun-args dims :any 1))) + ((and (lvar-matches dims :fun-names '(list*) :arg-count 2) + (lvar-value-is-nil (second (combination-args (lvar-uses dims))))) + (let* ((args (splice-fun-args dims :any 2)) ; the args to LIST* + (dummy (cadr args))) + (flush-dest dummy) + (setf (combination-args call) (delete dummy (combination-args call))) + (car args)))) ;; Don't want (list (list x)) to become a valid dimension specifier. - (assert-lvar-type (car args) (specifier-type 'index) - (%coerce-to-policy call)) - (setf (combination-args call) (delete dummy (combination-args call))) + (assert-lvar-type it (specifier-type 'index) (%coerce-to-policy call)) (return-from make-array - (transform-make-array-vector (car args) + (transform-make-array-vector it element-type initial-element initial-contents call :adjustable adjustable - :fill-pointer fill-pointer)))) + :fill-pointer fill-pointer))) (unless (constant-lvar-p dims) (give-up-ir1-transform "The dimension list is not constant; cannot open code array creation.")) (let ((dims (lvar-value dims)) - (element-type-ctype (and (constant-lvar-p element-type) + (element-type-ctype (and element-type + (constant-lvar-p element-type) (ir1-transform-specifier-type (lvar-value element-type))))) (when (or (contains-unknown-type-p element-type-ctype) @@ -1058,10 +1141,7 @@ initial-element initial-contents call :adjustable adjustable :fill-pointer fill-pointer)) - ((and fill-pointer - (not (and - (constant-lvar-p fill-pointer) - (null (lvar-value fill-pointer))))) + ((and fill-pointer (not (lvar-value-is-nil fill-pointer))) (give-up-ir1-transform)) (t (let* ((total-size (reduce #'* dims)) @@ -1075,7 +1155,7 @@ 'simple-array) ,(cond ((null element-type) t) (element-type-ctype - (sb-xc:upgraded-array-element-type + (upgraded-array-element-type (lvar-value element-type))) (t '*)) ,(make-list rank :initial-element '*)))) @@ -1085,8 +1165,6 @@ sb-vm:simple-array-widetag) ;; fill-pointer ,total-size - ;; fill-pointer-p - nil ;; elements ,total-size ;; data @@ -1108,6 +1186,7 @@ ;; dimensions ,@dims)))))))) +;;; 1st choice (deftransform make-array ((dims &key element-type initial-element initial-contents adjustable fill-pointer) (integer &key @@ -1155,10 +1234,53 @@ :displaced-to displaced-to ,@(and displaced-index-offset '(:displaced-index-offset displacement))))))) + +(defoptimizer (adjust-array derive-type) ((array dims &key + fill-pointer + displaced-to + displaced-index-offset + &allow-other-keys) + node) + (let* ((array-type (lvar-type array)) + (complex (conservative-array-type-complexp array-type)) + (simple (null complex)) + (complex (eq complex t)) + (dims (if (constant-lvar-p dims) + (let ((value (lvar-value dims))) + (if (check-array-dimensions value node) + value + (return-from adjust-array-derive-type-optimizer))) + '*))) + (unless complex + (let ((null (specifier-type 'null))) + (flet ((simple (lvar) + (when lvar + (cond ((not (type= (lvar-type lvar) null)) + (setf simple nil)) + ((not (types-equal-or-intersect (lvar-type lvar) null)) + (setf simple nil + complex t)))))) + (simple fill-pointer) + (simple displaced-to) + (simple displaced-index-offset)))) + (let ((int (type-intersection (strip-array-dimensions-and-complexity array-type) + (make-array-type (if (integerp dims) + (list dims) + dims) + :complexp (cond ((eq complex t)) + ((not simple) :maybe)) + :element-type *wild-type*)))) + (if (eq int *empty-type*) + (let ((*compiler-error-context* node)) + (setf (combination-kind node) :error) + (compiler-warn "New dimensions ~s do not match the rank of ~a" + dims + (type-specifier array-type))) + int)))) ;;;; miscellaneous properties of arrays -;;; Transforms for various array properties. If the property is know +;;; Transforms for various array properties. If the property is known ;;; at compile time because of a type spec, use that constant value. ;;; Most of this logic may end up belonging in code/late-type.lisp; @@ -1233,14 +1355,22 @@ ;; reduction. (deftransform array-rank ((array) (array) * :node node) (let ((array-type (lvar-type array))) - (cond ((eq t (and (array-type-p array-type) - (array-type-complexp array-type))) + (cond ((and (array-type-p array-type) + (listp (array-type-dimensions array-type))) + (length (array-type-dimensions array-type))) + ;; We need an extra case in here to best handle a known vector, because + ;; if we try to add a transform on ARRAY-HEADER-P (returning false for + ;; known simple-array of rank 1), that would fail to optimize where we know + ;; the thing is a vector but possibly non-simple. So then the IF below + ;; would still have both if its consequents considered plausible. + ((csubtypep array-type (specifier-type 'vector)) + 1) + ((and (array-type-p array-type) + (eq (array-type-complexp array-type) t)) '(%array-rank array)) (t - (delay-ir1-transform node :constraint) - `(if (array-header-p array) - (%array-rank array) - 1))))) + (delay-ir1-transform node :constraint) ; Why? + `(%array-rank array))))) (defun derive-array-rank (ctype) (let ((array (specifier-type 'array))) @@ -1357,12 +1487,11 @@ ;;; compile-time constant. (deftransform vector-length ((vector)) (let* ((vtype (lvar-type vector)) - (dim (first (array-type-dimensions-or-give-up vtype)))) - (when (eq dim '*) - (give-up-ir1-transform)) - (when (conservative-array-type-complexp vtype) + (dim (array-type-dimensions-or-give-up vtype))) + (when (or (not (typep dim '(cons integer))) + (conservative-array-type-complexp vtype)) (give-up-ir1-transform)) - dim)) + (first dim))) (defoptimizer (vector-length derive-type) ((vector)) (let ((array-type (lvar-conservative-type vector)) @@ -1403,38 +1532,61 @@ (t `(%array-available-elements array))))) -;;; Only complex vectors have fill pointers. -(deftransform array-has-fill-pointer-p ((array)) +(unless-vop-existsp (:translate test-header-data-bit) + (define-source-transform test-header-data-bit (array mask) + `(logtest (get-header-data ,array) ,mask))) + +;;; Any array can be tested for a fill-pointer now, using the header bit. +;;; Only a non-simple vector could possibly return true. +;;; If the input is known simple, we have to avoid doing the logtest because there's +;;; no constraint that says that the logtest will return false, and style-warnings +;;; will result from MAP-INTO and other things which have +;; (if (array-has-fill-pointer-p a) (setf (fill-pointer a) ...)) +;; where the compiler knows that the input is simple. +(deftransform array-has-fill-pointer-p ((array) * * :node node) (let* ((array-type (lvar-type array)) - (dims (array-type-dimensions-or-give-up array-type))) - (if (and (listp dims) (not (= (length dims) 1))) - nil - (ecase (conservative-array-type-complexp array-type) - ((t) - t) - ((nil) - nil) - ((:maybe) - (give-up-ir1-transform - "The array type is ambiguous; must call ~ - ARRAY-HAS-FILL-POINTER-P at runtime.")))))) - -(deftransform %check-bound ((array dimension index) ((simple-array * (*)) * *)) + (dims (array-type-dimensions-or-give-up array-type)) + complexp) + ;; If a vector and possibly non-simple, then perform the bit test, + ;; otherwise the answer is definitely NIL. + (cond ((and (listp dims) (/= (length dims) 1)) nil) ; dims = * is possibly a vector + ((eq (setf complexp (conservative-array-type-complexp array-type)) nil) nil) + (t + (when (eq complexp :maybe) + ;; Delay as much as possible so that this transform and + ;; the CONSTRAINT-PROPAGATE-IF optimizer have the most + ;; chances to run. + (delay-ir1-transform node :ir1-phases)) + `(test-header-data-bit array + (ash sb-vm:+array-fill-pointer-p+ sb-vm:array-flags-data-position)))))) + +(define-source-transform fill-pointer (vector) + (let ((vector-sym (gensym "VECTOR"))) + `(let ((,vector-sym ,vector)) + (if (and (array-header-p ,vector-sym) + (array-has-fill-pointer-p ,vector-sym)) + (%array-fill-pointer ,vector-sym) + (sb-vm::fill-pointer-error ,vector-sym))))) + +(deftransform %check-bound ((array dimension index) ((simple-array * (*)) t t)) (let ((array-ref (lvar-uses array)) (index-ref (lvar-uses index))) (unless (and (ref-p array-ref) (ref-p index-ref) (or - (let ((index-leaf (ref-leaf index-ref))) + (let* ((index-leaf (ref-leaf index-ref)) + (index-value (and (constant-p index-leaf) + (constant-value index-leaf))) + (index-value (and (integerp index-value) + index-value))) (loop for constraint in (ref-constraints array-ref) for y = (constraint-y constraint) thereis (and (eq (constraint-kind constraint) 'array-in-bounds-p) - (if (constant-p index-leaf) + (if index-value (and (constant-p y) - (<= (constant-value index-leaf) - (constant-value y))) + (<= index-value (constant-value y))) (eq index-leaf y))))) (loop for constraint in (ref-constraints index-ref) thereis (and (eq (constraint-kind constraint) 'array-in-bounds-p) @@ -1632,46 +1784,13 @@ (define-source-transform ,setter (a i v) `(setf (aref (the ,',type ,a) ,i) ,v))))) (define-frob schar %scharset simple-string) - (define-frob char %charset string)) + (define-frob char %charset string) + (define-frob svref %svset simple-vector)) -;;; We transform SVREF and %SVSET directly into DATA-VECTOR-REF/SET: this is -;;; around 100 times faster than going through the general-purpose AREF -;;; transform which ends up doing a lot of work -- and introducing many -;;; intermediate lambdas, each meaning a new trip through the compiler -- to -;;; get the same result. -;;; -;;; FIXME: [S]CHAR, and [S]BIT above would almost certainly benefit from a similar -;;; treatment. -(define-source-transform svref (vector index) - (let ((elt-type (or (when (symbolp vector) - (let ((var (lexenv-find vector vars))) - (when (lambda-var-p var) - (type-specifier - (array-type-declared-element-type (lambda-var-type var)))))) - t))) - (with-unique-names (n-vector) - `(let ((,n-vector ,vector)) - (the ,elt-type (data-vector-ref - (the simple-vector ,n-vector) - (check-bound ,n-vector (length ,n-vector) ,index))))))) - -(define-source-transform %svset (vector index value) - (let ((elt-type (or (when (symbolp vector) - (let ((var (lexenv-find vector vars))) - (when (lambda-var-p var) - (type-specifier - (array-type-declared-element-type (lambda-var-type var)))))) - t))) - (with-unique-names (n-vector) - `(let ((,n-vector ,vector)) - (truly-the ,elt-type (data-vector-set - (the simple-vector - (with-annotations - (,(make-lvar-modified-annotation :caller - '(setf svref))) - ,n-vector)) - (check-bound ,n-vector (length ,n-vector) ,index) - (the ,elt-type ,value))))))) +(defun the-unwild (type expr) + (if (or (null type) (eq type *wild-type*)) expr `(the ,type ,expr))) +(defun truly-the-unwild (type expr) + (if (or (null type) (eq type *wild-type*)) expr `(truly-the ,type ,expr))) (macrolet (;; This is a handy macro for computing the row-major index ;; given a set of indices. We wrap each index with a call @@ -1747,13 +1866,13 @@ (null (array-type-complexp type)) (neq element-ctype *wild-type*) (eql (length (array-type-dimensions type)) 1)) - (let* ((declared-element-ctype (array-type-declared-element-type type)) + (let* ((declared-element-ctype (array-type-element-type type)) (bare-form `(data-vector-ref array (check-bound array (array-dimension array 0) index)))) (if (type= declared-element-ctype element-ctype) bare-form - `(the ,(type-specifier declared-element-ctype) ,bare-form)))) + `(the ,declared-element-ctype ,bare-form)))) ((policy node (zerop insert-array-bounds-checks)) `(hairy-data-vector-ref array index)) (t `(hairy-data-vector-ref/check-bounds array index))))) @@ -1766,13 +1885,11 @@ ;;; But if we find out later that there's some useful type information ;;; available, switch back to the normal one to give other transforms ;;; a stab at it. -(macrolet ((define (name transform-to extra extra-type) - (declare (ignore extra-type)) - `(deftransform ,name ((array index ,@extra)) +(macrolet ((define (name args expr) + `(deftransform ,name ,args (let* ((type (lvar-type array)) (element-type (array-type-upgraded-element-type type)) - (declared-type (type-specifier - (array-type-declared-element-type type)))) + (declared-type (declared-array-element-type type))) ;; If an element type has been declared, we want to ;; use that information it for type checking (even ;; if the access can't be optimized due to the array @@ -1788,22 +1905,17 @@ (not (null (array-type-complexp type)))) (give-up-ir1-transform "Upgraded element type of array is not known at compile time."))) - ,(if extra - ``(truly-the ,declared-type - (,',transform-to array - (check-bound array - (array-dimension array 0) - index) - (the ,declared-type ,@',extra))) - ``(the ,declared-type - (,',transform-to array - (check-bound array - (array-dimension array 0) - index)))))))) - (define hairy-data-vector-ref/check-bounds - hairy-data-vector-ref nil nil) - (define hairy-data-vector-set/check-bounds - hairy-data-vector-set (new-value) (*))) + ,expr)))) + (define hairy-data-vector-ref/check-bounds ((array index)) + (the-unwild declared-type + `(hairy-data-vector-ref + array (check-bound array (array-dimension array 0) index)))) + (define hairy-data-vector-set/check-bounds ((array index new-value)) + (truly-the-unwild declared-type + `(hairy-data-vector-set + array + (check-bound array (array-dimension array 0) index) + ,(the-unwild declared-type 'new-value))))) ;;; Just convert into a HAIRY-DATA-VECTOR-REF (or ;;; HAIRY-DATA-VECTOR-SET) after checking that the index is inside the @@ -1880,11 +1992,11 @@ nil))))))) (defoptimizer (array-header-p constraint-propagate-if) - ((array) node gen) - (declare (ignore gen)) + ((array)) (values array (specifier-type '(and array (not (simple-array * (*))))))) -(defoptimizer (%array-fill-pointer-p constraint-propagate-if) - ((array) node gen) - (declare (ignore gen)) +;;; If ARRAY-HAS-FILL-POINTER-P returns true, then ARRAY +;;; is of the specified type. +(defoptimizer (array-has-fill-pointer-p constraint-propagate-if) + ((array)) (values array (specifier-type '(and vector (not simple-array))))) diff --git a/src/compiler/assem.lisp b/src/compiler/assem.lisp index 5f24191877..d9700192f1 100644 --- a/src/compiler/assem.lisp +++ b/src/compiler/assem.lisp @@ -257,13 +257,13 @@ ;; (second) instruction. ;; ;; instructions whose writes this instruction tries to read - (read-dependencies (make-sset) :type sset) + (read-dependencies (make-sset) :type sset :read-only t) ;; instructions whose writes or reads are overwritten by this instruction - (write-dependencies (make-sset) :type sset) + (write-dependencies (make-sset) :type sset :read-only t) ;; instructions which write what we read or write - (write-dependents (make-sset) :type sset) + (write-dependents (make-sset) :type sset :read-only t) ;; instructions which read what we write - (read-dependents (make-sset) :type sset)) + (read-dependents (make-sset) :type sset :read-only t)) (declaim (freeze-type instruction)) #+sb-show-assem (defvar *inst-ids* (make-hash-table :test 'eq)) #+sb-show-assem (defvar *next-inst-id* 0) @@ -321,17 +321,36 @@ (data-section (make-section) :read-only t) (code-section (make-section) :read-only t) (elsewhere-section (make-section) :read-only t) + (data-origin-label (gen-label "data start") :read-only t) + (text-origin-label (gen-label "text start") :read-only t) (elsewhere-label (gen-label "elsewhere start") :read-only t) (inter-function-padding :normal :type (member :normal :nop)) ;; for collecting unique "unboxed constants" prior to placing them ;; into the data section (constant-table (make-hash-table :test #'equal) :read-only t) (constant-vector (make-array 16 :adjustable t :fill-pointer 0) :read-only t) + ;; for deterministic allocation profiler (or possibly other tooling) + ;; that wants to monkey patch the instructions at runtime. + (alloc-points) + ;; for shrinking the size of the code fixups, we can choose to emit at most one call + ;; from a dynamic space code component to a given assembly routine. The call goes + ;; through an extra indirection in the component. + ;; This table is stored as an alist of (NAME . LABEL). + (indirection-table) ;; tracking where we last wrote an instruction so that SB-C::TRACE-INSTRUCTION ;; can print "in the {x} section" whenever it changes. (tracing-state (list nil nil) :read-only t)) ; segment and vop (declaim (freeze-type asmstream)) +(defvar *asmstream*) +(declaim (type asmstream *asmstream*)) + +(defun get-allocation-points (asmstream) + ;; Convert the label positions to a packed integer + ;; Utilize PACK-CODE-FIXUP-LOCS to perform compression. + (awhen (mapcar 'label-posn (asmstream-alloc-points asmstream)) + (sb-c:pack-code-fixup-locs it nil nil))) + ;;; Insert STMT after PREDECESSOR. (defun insert-stmt (stmt predecessor) (let ((successor (stmt-next predecessor))) @@ -363,7 +382,7 @@ (if (singleton-p list) (car list) list)))) ;;; This is used only to keep track of which vops emit which insts. -(defvar **current-vop**) +(defvar *current-vop*) ;;; Return the final statement emitted. (defun emit (section &rest things) @@ -372,7 +391,7 @@ ;; - a list (mnemonic . operands) for a machine instruction or assembler directive ;; - a function to emit a postit (let ((last (section-tail section)) - (vop (if (boundp '**current-vop**) **current-vop**))) + (vop (if (boundp '*current-vop*) *current-vop*))) (dolist (thing things (setf (section-tail section) last)) (if (label-p thing) ; Accumulate multiple labels until the next instruction (if (stmt-mnemonic last) @@ -382,7 +401,7 @@ (if (label-p old) (cons old new) (nconc old new))))) (multiple-value-bind (mnemonic operands) (if (consp thing) (values (car thing) (cdr thing)) thing) - (unless (member mnemonic '(.align .byte .skip .coverage-mark)) + (unless (member mnemonic '(.align .byte .skip)) ;; This automatically gets the .QWORD pseudo-op which we use on x86-64 ;; to create jump tables, but it's sort of unfortunate that the mnemonic ;; is specific to that backend. It should probably be .LISPWORD instead. @@ -435,8 +454,7 @@ (:code '(asmstream-code-section *asmstream*)) (:elsewhere '(asmstream-elsewhere-section *asmstream*)) (t dest))))) - ,@(when vop - `((**current-vop** ,vop))) + ,@(when vop `((*current-vop* ,vop))) ,@(mapcar (lambda (name) `(,name (gen-label))) new-labels)) @@ -1346,11 +1364,22 @@ ;;;; interface to the rest of the compiler +;;; Map of opcode symbol to function that emits it into the byte stream +;;; (or with the schedulding assembler, into the queue) +;;; Key is a symbol. Value is either #<function> or (#<function>), +;;; the latter if function wants to receive prefix arguments. +(defglobal *inst-encoder* (make-hash-table)) ; keys are symbols + ;;; Return T only if STATEMENT has a label which is potentially a branch ;;; target, and not merely labeled to store a location of interest. (defun labeled-statement-p (statement &aux (labels (stmt-labels statement))) (if (listp labels) (some #'label-usedp labels) (label-usedp labels))) +#-x86-64 +(progn + (defun extract-prefix-keywords (x) x) + (defun decode-prefix (args) args)) + (defun dump-symbolic-asm (section stream &aux last-vop all-labels (n 0)) (format stream "~2&Assembler input:~%") (do ((statement (stmt-next (section-start section)) (stmt-next statement)) @@ -1359,7 +1388,7 @@ (incf n) (binding* ((vop (stmt-vop statement) :exit-if-null)) (unless (eq vop last-vop) - (format stream "## ~A~%" (sb-c::vop-info-name (sb-c::vop-info vop)))) + (format stream "## ~A~%" (sb-c::vop-name vop))) (setq last-vop vop)) (let ((op (stmt-mnemonic statement)) (eol-comment "")) @@ -1376,7 +1405,11 @@ (if (functionp op) (format stream "# postit ~S~A~%" op eol-comment) (format stream " ~:@(~A~) ~{~A~^, ~}~A~%" - op (stmt-operands statement) eol-comment)))) + op + (if (consp (gethash op *inst-encoder*)) + (decode-prefix (stmt-operands statement)) + (stmt-operands statement)) + eol-comment)))) (let ((*print-length* nil) (*print-pretty* t) (*print-right-margin* 80)) @@ -1400,13 +1433,9 @@ (setf (section-tail first) last-stmt)) first) -;;; Map of opcode symbol to function that emits it into the byte stream -;;; (or with the schedulding assembler, into the queue) -(defglobal *inst-encoder* (make-hash-table :test 'eq)) - ;;; Combine INPUTS into one assembly stream and assemble into SEGMENT (defun %assemble (segment section) - (let ((**current-vop** nil) + (let ((*current-vop* nil) (in-without-scheduling) (was-scheduling)) ;; HEADER-SKEW is 1 word (in bytes) if the boxed code header word count is odd. @@ -1431,9 +1460,9 @@ (dump-symbolic-asm section sb-c::*compiler-trace-output*)) (do ((statement (stmt-next (section-start section)) (stmt-next statement))) ((null statement)) - (awhen (stmt-vop statement) (setq **current-vop** it)) + (awhen (stmt-vop statement) (setq *current-vop* it)) (dolist (label (ensure-list (stmt-labels statement))) - (%emit-label segment **current-vop** label)) + (%emit-label segment *current-vop* label)) (let ((mnemonic (stmt-mnemonic statement)) (operands (stmt-operands statement))) (if (functionp mnemonic) @@ -1454,9 +1483,10 @@ ((nil)) ; ignore (t (let ((encoder (gethash mnemonic *inst-encoder*))) - (cond ((functionp encoder) + (cond (encoder (instruction-hooks segment) - (apply encoder segment + (apply (the function (if (listp encoder) (car encoder) encoder)) + segment (perform-operand-lowering operands))) (t (bug "No encoder for ~S" mnemonic)))))))))) @@ -1478,32 +1508,17 @@ `(.skip ,trailer-len) `(.align ,sb-vm:n-lowtag-bits)) section))) - (octets (segment-buffer (%assemble segment combined)))) - (flet ((store-ub16 (index val) - (multiple-value-bind (b0 b1) - #+little-endian - (values (ldb (byte 8 0) val) (ldb (byte 8 8) val)) - #+big-endian - (values (ldb (byte 8 8) val) (ldb (byte 8 0) val)) - (setf (aref octets (+ index 0)) b0 - (aref octets (+ index 1)) b1))) - (store-ub32 (index val) - (multiple-value-bind (b0 b1 b2 b3) - #+little-endian - (values (ldb (byte 8 0) val) (ldb (byte 8 8) val) - (ldb (byte 8 16) val) (ldb (byte 8 24) val)) - #+big-endian - (values (ldb (byte 8 24) val) (ldb (byte 8 16) val) - (ldb (byte 8 8) val) (ldb (byte 8 0) val)) - (setf (aref octets (+ index 0)) b0 - (aref octets (+ index 1)) b1 - (aref octets (+ index 2)) b2 - (aref octets (+ index 3)) b3)))) - (let ((index (length octets)) - (fun-offsets)) - ;; Total size of the code object must be multiple of 2 lispwords - (aver (not (logtest (+ (segment-header-skew segment) index) - sb-vm:lowtag-mask))) + (fun-offsets) + (octets (segment-buffer (%assemble segment combined))) + (index (length octets))) + ;; N-ENTRIES is packed into a uint16 with 5 other bits + (declare (type (unsigned-byte 11) n-entries)) + + ;; Total size of the code object must be multiple of 2 lispwords + (aver (not (logtest (+ (segment-header-skew segment) index) + sb-vm:lowtag-mask))) + (sb-sys:with-pinned-objects (octets) + (let ((sap (sb-sys:vector-sap octets))) ;; TODO: as the comment in GENERATE-CODE suggests, we would like to align ;; code objects to 16 bytes for 32-bit x86. That's simple - all we have to do ;; is ensure that each code blob is a multiple of 16 bytes in size. @@ -1515,10 +1530,12 @@ (- index trailer-len (label-position end-text))))) (unless (and (typep trailer-len '(unsigned-byte 16)) (typep n-entries '(unsigned-byte 12)) + ;; Padding must be representable in 4 bits at assembly time, + ;; but CODE-HEADER/TRAILER-ADJUST can increase the padding. (typep padding '(unsigned-byte 4))) (bug "Oversized code component?")) - (store-ub16 (- index 2) trailer-len) - (store-ub16 (- index 4) (logior (ash n-entries 4) padding))) + (setf (sap-ref-16 sap (- index 2)) trailer-len) + (setf (sap-ref-16 sap (- index 4)) (logior (ash n-entries 5) padding))) (decf index trailer-len) ;; Iteration over label positions occurs from numerically highest ;; to lowest, which is right because the 0th indexed simple-fun @@ -1530,13 +1547,13 @@ (dolist (label simple-fun-labels) (let ((val (label-position label))) (push val fun-offsets) - (store-ub32 index val) - (incf index 4))) - (aver (= index (- (length octets) 4))) - (values segment - (label-position end-text) - (segment-fixup-notes segment) - fun-offsets))))) + (setf (sap-ref-32 sap index) val) + (incf index 4))))) + (aver (= index (- (length octets) 4))) + (values segment + (label-position end-text) + (segment-fixup-notes segment) + fun-offsets))) ;;; Most backends do not convert register TNs into a different type of ;;; internal object prior to handing the operands off to the emitter. @@ -1552,7 +1569,7 @@ (if (eq section (asmstream-code-section asmstream)) :regular :elsewhere))) - (sb-c::trace-instruction section-name **current-vop** mnemonic operands + (sb-c::trace-instruction section-name *current-vop* mnemonic operands (asmstream-tracing-state asmstream))))) (defmacro inst (&whole whole mnemonic &rest args) @@ -1588,21 +1605,34 @@ ;;; As such, we must detect that we are emitting directly to machine code. ;;; (defun inst* (mnemonic &rest operands) - (declare (symbol mnemonic)) - (let ((action (gethash mnemonic *inst-encoder*)) - (dest *current-destination*)) + (let ((dest + (etypecase mnemonic + (symbol + ;; If called by a vop, the first argument is a mnemonic. + *current-destination*) + (segment + ;; If called by an instruction encoder to encode other instructions, + ;; the first argument is a SEGMENT. This facilitates a different kind of + ;; macro-instruction, one which decides only at encoding time what other + ;; instructions to emit. Similar results could be achievedy by factoring + ;; out other emitters into callable functions, though the INST macro + ;; tends to be a more convenient interface. + (prog1 mnemonic (setq mnemonic (the symbol (pop operands))))))) + (action (gethash mnemonic *inst-encoder*))) (unless action ; try canonicalizing again (setq mnemonic (find-symbol (string mnemonic) *backend-instruction-set-package*) action (gethash mnemonic *inst-encoder*)) (aver action)) + (when (listp action) (setq operands (extract-prefix-keywords operands))) (typecase dest (cons ; streaming in to the assembler (trace-inst dest mnemonic operands) (emit dest (cons mnemonic operands))) (segment ; streaming out of the assembler (instruction-hooks dest) - (apply action dest (perform-operand-lowering operands)))))) + (apply (the function (if (listp action) (car action) action)) + dest (perform-operand-lowering operands)))))) (defun emit-label (label) "Emit LABEL at this location in the current section." @@ -1693,12 +1723,12 @@ total-bits assembly-unit-bits)) quo)) (bytes (make-array num-bytes :initial-element nil)) - (segment-arg (sb-xc:gensym "SEGMENT-"))) + (segment-arg (gensym "SEGMENT-"))) (dolist (byte-spec-expr byte-specs) (let* ((byte-spec (eval byte-spec-expr)) (byte-size (byte-size byte-spec)) (byte-posn (byte-position byte-spec)) - (arg (sb-xc:gensym (format nil "~:@(ARG-FOR-~S-~)" byte-spec-expr)))) + (arg (gensym (format nil "~:@(ARG-FOR-~S-~)" byte-spec-expr)))) (when (ldb-test (byte byte-size byte-posn) overall-mask) (error "The byte spec ~S either overlaps another byte spec, or ~ extends past the end." @@ -1765,9 +1795,16 @@ (:little-endian (nreverse forms)) (:big-endian forms))))))) -(defun %def-inst-encoder (symbol &optional thing) - (setf (gethash symbol *inst-encoder*) - (or thing (gethash symbol *inst-encoder*)))) +(defun %def-inst-encoder (symbol thing &optional accept-prefixes) + (let ((function + (or thing ; load-time effect passes the definition + ;; (where compile-time doesn't). + ;; Otherwise, take what we already had so that a compile-time + ;; effect doesn't clobber an already-working hash-table entry + ;; if re-evaluating a define-instruction form. + (car (ensure-list (gethash symbol *inst-encoder*)))))) + (setf (gethash symbol *inst-encoder*) + (if accept-prefixes (cons function t) function)))) (defmacro define-instruction (name lambda-list &rest options) (binding* ((fun-name (intern (symbol-name name) *backend-instruction-set-package*)) @@ -1865,13 +1902,18 @@ (setf (get ',fun-name 'sb-disassem::instruction-flavors) (list ,@pdefs)) ,@(when emitter - `((eval-when (:compile-toplevel) (%def-inst-encoder ',fun-name)) - (%def-inst-encoder - ',fun-name - (named-lambda ,(string fun-name) (,segment-name ,@(cdr lambda-list)) - (declare ,@decls) - (let ,(and vop-name `((,vop-name **current-vop**))) - (block ,fun-name ,@emitter)))))) + (let* ((operands (cdr lambda-list)) + (accept-prefixes (eq (car operands) '&prefix))) + (when accept-prefixes (setf operands (cdr operands))) + `((eval-when (:compile-toplevel) + (%def-inst-encoder ',fun-name nil ',accept-prefixes)) + (%def-inst-encoder + ',fun-name + (named-lambda ,(string fun-name) (,segment-name ,@operands) + (declare ,@decls) + (let ,(and vop-name `((,vop-name *current-vop*))) + (block ,fun-name ,@emitter))) + ',accept-prefixes)))) ',fun-name))) (defun instruction-hooks (segment) @@ -1895,14 +1937,10 @@ (%def-inst-encoder '.align (lambda (segment bits &optional (pattern 0)) - (%emit-alignment segment **current-vop** bits pattern))) + (%emit-alignment segment *current-vop* bits pattern))) (%def-inst-encoder '.byte (lambda (segment &rest bytes) (dolist (byte bytes) (emit-byte segment byte)))) -(%def-inst-encoder '.coverage-mark - (lambda (segment &rest junk) - (declare (ignore segment junk)) - (error "Can't get here"))) (%def-inst-encoder '.skip (lambda (segment n-bytes &optional (pattern 0)) (%emit-skip segment n-bytes pattern))) @@ -1920,13 +1958,12 @@ (cond ((label-p val) ;; note a fixup prior to writing the backpatch so that the fixup's ;; position is the location counter at the patch point - ;; (i.e. prior to skipping 8 bytes) + ;; (i.e. prior to skipping N-WORD-BYTES bytes) ;; This fixup is *not* recorded in code->fixups. Instead, trans_code() ;; will fixup a counted initial subsequence of unboxed words. ;; Q: why are fixup notes a "compiler" abstractions? ;; They seem pretty assembler-related to me. - (sb-c:note-fixup segment (or #+64-bit :absolute64 :absolute) - (sb-c:make-fixup nil :code-object 0)) + (sb-c:note-fixup segment :absolute (sb-c:make-fixup nil :code-object 0)) (emit-back-patch segment sb-vm:n-word-bytes diff --git a/src/compiler/backend.lisp b/src/compiler/backend.lisp index b636f17870..e691795927 100644 --- a/src/compiler/backend.lisp +++ b/src/compiler/backend.lisp @@ -45,18 +45,13 @@ (defglobal *backend-sbs* #()) (declaim (type simple-vector *backend-sbs*)) -;;; translation from template names to template structures -(defglobal *backend-template-names* (make-hash-table :test 'eq)) -(declaim (type hash-table *backend-template-names*)) - ;;; hashtables mapping from SC and SB names to the corresponding structures -(defglobal *backend-sc-names* (make-hash-table :test 'eq)) +(defglobal *backend-sc-names* (make-hash-table)) (declaim (type hash-table *backend-sc-names*)) ;;; translations from primitive type names to the corresponding ;;; primitive-type structure. -(defglobal *backend-primitive-type-names* - (make-hash-table :test 'eq)) +(defglobal *backend-primitive-type-names* (make-hash-table)) ; keys are symbols (declaim (type hash-table *backend-primitive-type-names*)) ;;; This establishes a convenient handle on primitive type unions, or @@ -72,22 +67,23 @@ ;;; representation. ;;; ;;; The T primitive-type is kept in this variable so that people who -;;; have to special-case it can get at it conveniently. This variable -;;; has to be set by the machine-specific VM definition, since the -;;; !DEF-PRIMITIVE-TYPE for T must specify the SCs that boxed objects -;;; can be allocated in. +;;; have to special-case it can get at it conveniently. (define-symbol-macro *backend-t-primitive-type* (the primitive-type (load-time-value (primitive-type-or-lose t) t))) ;;; a hashtable translating from VOP names to the corresponding VOP-PARSE ;;; structures. This information is only used at meta-compile time. -(defglobal *backend-parsed-vops* (make-hash-table :test 'eq)) +(defglobal *backend-parsed-vops* (make-hash-table)) ; keys are symbols (declaim (type hash-table *backend-parsed-vops*)) +;;; Mapping of predicate name (a symbol) to a type. +;;; This is an EQL table so that it uses symbol-hash. +(defglobal *backend-predicate-types* (make-hash-table)) ;;; mappings between CTYPE structures and the corresponding predicate. ;;; The type->predicate mapping is implemented as an alist because ;;; there is no such thing as a TYPE= hash table. -(defglobal *backend-predicate-types* (make-hash-table :test 'eq)) +;;; (But if we could make all the types use as keys in this table +;;; into interned types, could it become an EQ table perhaps?) (defglobal *backend-type-predicates* nil) (declaim (type hash-table *backend-predicate-types*)) (declaim (type list *backend-type-predicates*)) @@ -164,12 +160,9 @@ conditionalization. |# ;;; The default value of NIL means use only unguarded VOPs. The -;;; initial value is customizeable via -;;; customize-backend-subfeatures.lisp -(eval-when (:compile-toplevel :load-toplevel :execute) - (defvar *backend-subfeatures* - '#.(sort (copy-list sb-cold:*shebang-backend-subfeatures*) #'string<))) -(declaim (always-bound *backend-subfeatures*)) +;;; initial value is customizeable via customize-backend-subfeatures.lisp +(defvar *backend-subfeatures* '#.(sort sb-cold:backend-subfeatures #'string<)) +#-sb-xc-host (declaim (always-bound *backend-subfeatures*)) ;;; possible *BACKEND-SUBFEATURES* values: ;;; diff --git a/src/compiler/bit-util.lisp b/src/compiler/bit-util.lisp index 9a25b30fbd..7424eb918b 100644 --- a/src/compiler/bit-util.lisp +++ b/src/compiler/bit-util.lisp @@ -12,7 +12,6 @@ (in-package "SB-C") -#-sb-fluid (declaim (inline clear-bit-vector set-bit-vector bit-vector-replace bit-vector-copy)) diff --git a/src/compiler/bitops-derive-type.lisp b/src/compiler/bitops-derive-type.lisp index 1204571fb4..ad805b5254 100644 --- a/src/compiler/bitops-derive-type.lisp +++ b/src/compiler/bitops-derive-type.lisp @@ -139,10 +139,14 @@ (defun logand-derive-type-aux (x y &optional same-leaf) (when same-leaf (return-from logand-derive-type-aux x)) + (flet ((minus-one (x y) + (when (eql (nth-value 1 (type-singleton-p x)) + -1) + (return-from logand-derive-type-aux y)))) + (minus-one x y) + (minus-one y x)) (multiple-value-bind (x-len x-pos x-neg) (integer-type-length x) - (declare (ignore x-pos)) (multiple-value-bind (y-len y-pos y-neg) (integer-type-length y) - (declare (ignore y-pos)) (if (not x-neg) ;; X must be positive. (if (not y-neg) @@ -171,23 +175,15 @@ ;; Either might be negative. (if (and x-len y-len) ;; The result is bounded. - (specifier-type `(signed-byte ,(1+ (max x-len y-len)))) - ;; We can't tell squat about the result. - (specifier-type 'integer))))))) - -(defun make-modular-fun-type-deriver (prototype kind width signedp) - (declare (ignore kind)) - (let ((info (fun-info-or-lose prototype)) - (mask-type (specifier-type - (ecase signedp - ((nil) (let ((mask (1- (ash 1 width)))) - `(integer ,mask ,mask))) - ((t) `(signed-byte ,width)))))) - (lambda (call) - (let ((res (funcall (fun-info-derive-type info) call))) - (when (and res - (not signedp)) - (logand-derive-type-aux res mask-type)))))) + (if (and (not y-pos) + (not x-pos)) + (specifier-type `(and (signed-byte ,(1+ (max x-len y-len))) + (integer * -1))) + (specifier-type `(signed-byte ,(1+ (max x-len y-len))))) + (if (and (not y-pos) + (not x-pos)) + (specifier-type '(integer * -1)) + (specifier-type 'integer)))))))) (defun logior-derive-unsigned-bounds (x y) (let* ((a (numeric-type-low x)) diff --git a/src/compiler/callable-args.lisp b/src/compiler/callable-args.lisp index 05464cb661..34367a8f38 100644 --- a/src/compiler/callable-args.lisp +++ b/src/compiler/callable-args.lisp @@ -1,4 +1,4 @@ -;;;; Type checking of higher order function. +;;;; Type checking of higher order functions. ;;;; ;;;; This software is part of the SBCL system. See the README file for ;;;; more information. @@ -31,8 +31,6 @@ :deps deps :type type))) (when (add-annotation lvar annotation) - (loop for lvar in deps - do (push annotation (lvar-dependent-annotations lvar))) (assert-lvar-type lvar (specifier-type 'function-designator) policy)))))) @@ -51,7 +49,8 @@ (incf arg-position)) (handle-keys (options) (loop for (key value*) on options by #'cddr - for value = (if (eq key :key) + for value = (if (or (eq key :key) + (eq key :value)) (let ((lvar (getf (nthcdr positional-count lvars) value*))) (and lvar (record-lvar lvar))) @@ -192,6 +191,7 @@ (functional-type entry-fun)) ((and (not (fun-type-p lvar-type)) (lambda-p entry-fun) + (null (lambda-kind entry-fun)) (lambda-tail-set entry-fun)) (make-fun-type :wild-args t :returns @@ -199,7 +199,8 @@ (t lvar-type))) (fun-name (cond ((or (fun-type-p lvar-type) - (functional-p leaf)) + (functional-p leaf) + (global-var-p leaf)) (cond ((or (constant-lvar-p lvar) ;; A constant may fail some checks in constant-lvar-p (constant-p leaf)) @@ -222,8 +223,10 @@ (type (cond ((fun-type-p lvar-type) lvar-type) ((symbolp fun-name) - (if (fun-lexically-notinline-p fun-name - (node-lexenv (lvar-dest lvar))) + (if (or defined-here + declared-only + (fun-lexically-notinline-p fun-name + (node-lexenv (lvar-dest lvar)))) lvar-type (global-ftype fun-name))) ((functional-p leaf) @@ -294,9 +297,16 @@ (labels ((%process-arg (spec) (destructuring-bind (nth-arg . options) spec (let* ((arg (nth nth-arg deps)) + (value-nth (getf options :value)) (key-nth (getf options :key)) + (value (and value-nth + (nth value-nth deps))) (key (and key-nth (nth key-nth deps))) - (key-return-type (cond ((not key) + (key-return-type (cond (value-nth + (if (lvar-p value) + (lvar-type value) + *universal-type*)) + ((not key) nil) ((lvar-p key) (multiple-value-bind (type name) (lvar-fun-type key) @@ -405,82 +415,102 @@ "The function ~s is called with odd number of keyword arguments." callee))))))) +(defun disable-arg-count-checking (leaf type arg-count) + (when (lambda-p leaf) + (multiple-value-bind (min max) (fun-type-arg-limits type) + (when (and min + (if max + (<= min arg-count max) + (<= min arg-count))) + (setf (lambda-lexenv leaf) + (make-lexenv :default (lambda-lexenv leaf) + :policy (augment-policy verify-arg-count 0 + (lexenv-policy (lambda-lexenv leaf))))))))) + ;;; This can provide better errors and better handle OR types than a ;;; simple type intersection. (defun check-function-designator-lvar (lvar annotation) (multiple-value-bind (type name leaf) (lvar-fun-type lvar) - (when (fun-type-p type) - ;; If the destination is a combination-fun that means the function - ;; is called here and not passed somewhere else, there's no longer a - ;; need to check the function type, the arguments to the call will - ;; do the same job. - (unless (let* ((dest (and lvar - (lvar-dest lvar)))) - (and (basic-combination-p dest) - (eq (basic-combination-fun dest) lvar))) - (multiple-value-bind (args results) - (function-designator-lvar-types annotation) - (let* ((condition (callable-argument-lossage-kind name - leaf - 'simple-style-warning - 'simple-warning)) - (type-condition (case condition - (simple-style-warning - 'type-style-warning) - (t - 'type-warning))) - (caller (lvar-function-designator-annotation-caller annotation)) - (arg-count (length args))) - (or (report-arg-count-mismatch name caller - type - arg-count - condition) - (let ((param-types (fun-type-n-arg-types arg-count type))) - (block nil - ;; Need to check each OR seperately, a UNION could - ;; intersect with the function parameters - (labels ((hide-ors (current-or or-part) - (loop for spec in args - collect (cond ((eq spec current-or) - or-part) - ((typep spec '(cons (eql or))) - (sb-kernel::%type-union (cdr spec))) - (t - spec)))) - (check (arg param &optional - current-spec) - (when (eq (type-intersection param arg) *empty-type*) - (warn type-condition - :format-control - "The function ~S is called by ~S with ~S but it accepts ~S." - :format-arguments - (list - name - caller - (mapcar #'type-specifier (hide-ors current-spec arg)) - (mapcar #'type-specifier param-types))) - (return t)))) - (loop for arg-type in args - for param-type in param-types - if (typep arg-type '(cons (eql or))) - do (loop for type in (cdr arg-type) - do (check type param-type arg-type)) - else do (check arg-type param-type))))) - (let ((returns (single-value-type (fun-type-returns type)))) - (when (and (neq returns *wild-type*) - (neq returns *empty-type*) - (neq results *wild-type*) - (eq (type-intersection returns results) *empty-type*)) - (warn type-condition - :format-control - "The function ~S called by ~S returns ~S but ~S is expected" - :format-arguments - (list - name - caller - (type-specifier returns) - (type-specifier results))))))))) - t))) + (cond + ((and name + (valid-function-name-p name) + (memq (info :function :kind name) '(:macro :special-form))) + (compiler-warn "~(~a~) ~s where a function is expected" + (info :function :kind name) name)) + ((fun-type-p type) + ;; If the destination is a combination-fun that means the function + ;; is called here and not passed somewhere else, there's no longer a + ;; need to check the function type, the arguments to the call will + ;; do the same job. + (unless (let* ((dest (lvar-dest lvar))) + (and (basic-combination-p dest) + (eq (basic-combination-fun dest) lvar))) + (multiple-value-bind (args results) + (function-designator-lvar-types annotation) + (let* ((condition (callable-argument-lossage-kind name + leaf + 'simple-style-warning + 'simple-warning)) + (type-condition (case condition + (simple-style-warning + 'type-style-warning) + (t + 'type-warning))) + (caller (lvar-function-designator-annotation-caller annotation)) + (arg-count (length args))) + (or (report-arg-count-mismatch name caller + type + arg-count + condition) + (let ((param-types (fun-type-n-arg-types arg-count type))) + (unless (and (eq caller 'reduce) + (eql arg-count 2)) + (disable-arg-count-checking leaf type arg-count)) + (block nil + ;; Need to check each OR seperately, a UNION could + ;; intersect with the function parameters + (labels ((hide-ors (current-or or-part) + (loop for spec in args + collect (cond ((eq spec current-or) + or-part) + ((typep spec '(cons (eql or))) + (sb-kernel::%type-union (cdr spec))) + (t + spec)))) + (check (arg param &optional + current-spec) + (when (eq (type-intersection param arg) *empty-type*) + (warn type-condition + :format-control + "The function ~S is called by ~S with ~S but it accepts ~S." + :format-arguments + (list + name + caller + (mapcar #'type-specifier (hide-ors current-spec arg)) + (mapcar #'type-specifier param-types))) + (return t)))) + (loop for arg-type in args + for param-type in param-types + if (typep arg-type '(cons (eql or))) + do (loop for type in (cdr arg-type) + do (check type param-type arg-type)) + else do (check arg-type param-type))))) + (let ((returns (single-value-type (fun-type-returns type)))) + (when (and (neq returns *wild-type*) + (neq returns *empty-type*) + (neq results *wild-type*) + (eq (type-intersection returns results) *empty-type*)) + (warn type-condition + :format-control + "The function ~S called by ~S returns ~S but ~S is expected" + :format-arguments + (list + name + caller + (type-specifier returns) + (type-specifier results))))))))) + t)))) (defun check-function-lvar (lvar annotation) (let ((atype (lvar-function-annotation-type annotation))) diff --git a/src/compiler/checkgen.lisp b/src/compiler/checkgen.lisp index 88241fffab..efd9b1e1fb 100644 --- a/src/compiler/checkgen.lisp +++ b/src/compiler/checkgen.lisp @@ -312,6 +312,9 @@ (let* ((lvar (node-lvar cast)) (dest (and lvar (lvar-dest lvar)))) (and (combination-p dest) + (or (not (combination-fun-info dest)) + ;; fixed-args functions do not check their arguments. + (not (ir1-attributep (fun-info-attributes (combination-fun-info dest)) fixed-args))) ;; The theory is that the type assertion is from a declaration on the ;; callee, so the callee should be able to do the check. We want to ;; let the callee do the check, because it is possible that by the @@ -334,8 +337,19 @@ ;; deemed unreachable? (and (almost-immediately-used-p lvar cast) - (values (values-subtypep (lvar-externally-checkable-type lvar) - (cast-type-to-check cast))))))) + (if (and (lvar-fun-is (combination-fun dest) + '(hairy-data-vector-set/check-bounds + hairy-data-vector-ref/check-bounds + hairy-data-vector-ref + hairy-data-vector-set)) + (eql (car (combination-args dest)) + lvar)) + ;; These functions work on all arrays, but the error + ;; message is about vectors, which is used more frequently. + (csubtypep (specifier-type 'vector) + (single-value-type (cast-type-to-check cast))) + (values-subtypep (lvar-externally-checkable-type lvar) + (cast-type-to-check cast))))))) ;; Type specifiers handled by the general-purpose MAKE-TYPE-CHECK-FORM are often ;; trivial enough to have an internal error number assigned to them that can be @@ -453,28 +467,35 @@ ;;; source level because our fixed-values conventions are optimized ;;; for the common MV-BIND case. (defun make-type-check-form (types cast) - (let ((temps (make-gensym-list (length types)))) - `(multiple-value-bind ,temps 'dummy - ,@(mapcar - (lambda (temp %type) - (destructuring-bind (not type-to-check - type-to-report) %type - (let* ((spec - (let ((*unparse-fun-type-simplify* t)) - (type-specifier type-to-check))) - (test (if not `(not ,spec) spec))) - `(unless - ,(with-ir1-environment-from-node cast ;; it performs its own inlining of SATISFIES - (%source-transform-typep temp test)) - ,(internal-type-error-call temp - (if (fun-designator-type-p type-to-report) - ;; Simplify - (specifier-type 'function-designator) - type-to-report) - (cast-context cast)))))) - temps - types) - (values ,@temps)))) + (let* ((temps (make-gensym-list (length types))) + (context (cast-context cast)) + (restart (and (eq context :restart) + (setf context (make-restart-location))))) + (lambda (dummy) + `(multiple-value-bind ,temps ,dummy + ,@(mapcar + (lambda (temp %type) + (destructuring-bind (not type-to-check + type-to-report) %type + (let* ((spec + (let ((*unparse-fun-type-simplify* t)) + (type-specifier type-to-check))) + (test (if not `(not ,spec) spec))) + `(progn + (unless + ,(with-ir1-environment-from-node cast ;; it performs its own inlining of SATISFIES + (%source-transform-typep temp test)) + ,(internal-type-error-call temp + (if (fun-designator-type-p type-to-report) + ;; Simplify + (specifier-type 'function-designator) + type-to-report) + context)) + ,@(and restart + `((restart-point ,restart))))))) + temps + types) + (values ,@temps))))) ;;; Splice in explicit type check code immediately before CAST. This ;;; code receives the value(s) that were being passed to CAST-VALUE, @@ -494,39 +515,35 @@ (let* ((lvar (node-lvar cast)) (dest (and lvar (lvar-dest lvar))) (value (cast-value cast)) - (atype (cast-asserted-type cast)) - (condition 'type-warning) - (not-ok-uses '())) + (atype (cast-asserted-type cast))) (do-uses (use value) (let ((dtype (node-derived-type use))) - (if (values-types-equal-or-intersect dtype atype) - (setf condition 'type-style-warning) - (push use not-ok-uses)))) - (dolist (use (nreverse not-ok-uses)) - (let* ((*compiler-error-context* use) - (dtype (node-derived-type use)) - (what (when (and (combination-p dest) - (eq (combination-kind dest) :local)) - (let ((lambda (combination-lambda dest)) - (pos (position-or-lose - lvar (combination-args dest)))) - (format nil "~:[A possible~;The~] binding of ~S" - (and (lvar-has-single-use-p lvar) - (eq (functional-kind lambda) :let)) - (leaf-source-name (elt (lambda-vars lambda) - pos))))))) - (cond ((and (ref-p use) (constant-p (ref-leaf use))) - (warn condition - :format-control "~:[This~;~:*~A~] is not a ~ + (unless (or (values-types-equal-or-intersect dtype atype) + (cast-mismatch-from-inlined-p cast use)) + (let* ((*compiler-error-context* use) + (dtype (node-derived-type use)) + (what (when (and (combination-p dest) + (eq (combination-kind dest) :local)) + (let ((lambda (combination-lambda dest)) + (pos (position-or-lose + lvar (combination-args dest)))) + (format nil "~:[A possible~;The~] binding of ~S" + (and (lvar-has-single-use-p lvar) + (eq (functional-kind lambda) :let)) + (leaf-source-name (elt (lambda-vars lambda) + pos))))))) + (cond ((and (ref-p use) (constant-p (ref-leaf use))) + (warn 'type-style-warning + :format-control "~:[This~;~:*~A~] is not a ~ ~<~%~9T~:;~/sb-impl:print-type/:~>~% ~S" - :format-arguments - (list what atype (constant-value (ref-leaf use))))) - (t - (warn condition - :format-control - "~:[Result~;~:*~A~] is a ~/sb-impl:print-type/, ~ + :format-arguments + (list what atype (constant-value (ref-leaf use))))) + (t + (warn 'type-style-warning + :format-control + "~:[Result~;~:*~A~] is a ~/sb-impl:print-type/, ~ ~<~%~9T~:;not a ~/sb-impl:print-type/.~>" - :format-arguments (list what dtype atype))))))) + :format-arguments (list what dtype atype))))))))) (values)) ;;; Loop over all blocks in COMPONENT that have TYPE-CHECK set, diff --git a/src/compiler/codegen.lisp b/src/compiler/codegen.lisp index 89f3f5f0f3..7fcf1536d1 100644 --- a/src/compiler/codegen.lisp +++ b/src/compiler/codegen.lisp @@ -16,26 +16,25 @@ ;;;; utilities used during code generation -;;; the number of bytes used by the code object header - -#-sb-xc-host -(defun component-header-length (&optional - (component *component-being-compiled*)) - (let* ((2comp (component-info component)) - (constants (ir2-component-constants 2comp))) - (ash (align-up (length constants) code-boxed-words-align) sb-vm:word-shift))) - ;;; KLUDGE: the assembler can not emit backpatches comprising jump tables without ;;; knowing the boxed code header length. But there is no compiler IR2 metaobject, ;;; for SB-FASL:*ASSEMBLER-ROUTINES*. We have to return a fixed answer for that. -#+sb-xc-host +(defun asm-routines-boxed-header-nwords () + (align-up (+ sb-vm:code-constants-offset + #+x86-64 1) ; KLUDGE: make room for 1 boxed constant + 2)) +;;; the number of bytes used by the code object header (defun component-header-length () - (if (boundp '*component-being-compiled*) - (let ((component *component-being-compiled*)) - (let* ((2comp (component-info component)) - (constants (ir2-component-constants 2comp))) - (ash (align-up (length constants) code-boxed-words-align) sb-vm:word-shift))) - (* sb-vm:n-word-bytes 4))) + (cond #+sb-xc-host ((not (boundp '*component-being-compiled*)) + (* sb-vm:n-word-bytes (asm-routines-boxed-header-nwords))) + (t + (let* ((2comp (component-info *component-being-compiled*)) + (constants (ir2-component-constants 2comp))) + (ash (align-up (length constants) code-boxed-words-align) + sb-vm:word-shift))))) + +(defun component-n-jump-table-entries (&optional (component *component-being-compiled*)) + (ir2-component-n-jump-table-entries (component-info component))) ;;; the size of the NAME'd SB in the currently compiled component. ;;; This is useful mainly for finding the size for allocating stack @@ -48,9 +47,9 @@ (defun current-nfp-tn (vop) (unless (zerop (sb-allocated-size 'non-descriptor-stack)) (let ((block (ir2-block-block (vop-block vop)))) - (when (ir2-physenv-number-stack-p - (physenv-info - (block-physenv block))) + (when (ir2-environment-number-stack-p + (environment-info + (block-environment block))) (ir2-component-nfp (component-info (block-component block))))))) ;;; the TN that is used to hold the number stack frame-pointer in the @@ -58,13 +57,13 @@ ;;; allocated (defun callee-nfp-tn (2env) (unless (zerop (sb-allocated-size 'non-descriptor-stack)) - (when (ir2-physenv-number-stack-p 2env) + (when (ir2-environment-number-stack-p 2env) (ir2-component-nfp (component-info *component-being-compiled*))))) ;;; the TN used for passing the return PC in a local call to the function ;;; designated by 2ENV (defun callee-return-pc-tn (2env) - (ir2-physenv-return-pc-pass 2env)) + (ir2-environment-return-pc-pass 2env)) ;;;; noise to emit an instruction trace @@ -125,25 +124,29 @@ ;;; to get handles (as returned by sb-vm:inline-constant-value) from constant ;;; descriptors. ;;; -#+(or x86 x86-64 arm64 ppc ppc64) +#+(or arm64 mips ppc ppc64 x86 x86-64) (defun register-inline-constant (&rest constant-descriptor) - (declare (dynamic-extent constant-descriptor)) + ;; N.B.: Please do not think yourself so clever as to declare DYNAMIC-EXTENT on + ;; CONSTANT-DESCRIPTOR. Giving the list indefinite extent allows backends to simply + ;; return it as the key to the hash-table in the most trivial possible implementation. + ;; The cost of listifying a &REST arg is unnoticeable here. (let ((asmstream *asmstream*) (constant (sb-vm:canonicalize-inline-constant constant-descriptor))) - (ensure-gethash - constant - (asmstream-constant-table asmstream) - (multiple-value-bind (label value) (sb-vm:inline-constant-value constant) - (vector-push-extend (cons constant label) - (asmstream-constant-vector asmstream)) - value)))) -#-(or x86 x86-64 arm64 ppc ppc64) + (values ; kill the second value + (ensure-gethash + constant + (asmstream-constant-table asmstream) + (multiple-value-bind (label value) (sb-vm:inline-constant-value constant) + (vector-push-extend (cons constant label) + (asmstream-constant-vector asmstream)) + value))))) +#-(or arm64 mips ppc ppc64 x86 x86-64) (progn (defun sb-vm:sort-inline-constants (constants) constants) (defun sb-vm:emit-inline-constant (&rest args) (error "EMIT-INLINE-CONSTANT called with ~S" args))) ;;; Emit the subset of inline constants which represent jump tables ;;; and remove those constants so that they don't get emitted again. -(defun emit-jump-tables () +(defun emit-jump-tables (ir2-component) ;; Other backends will probably need relative jump tables instead ;; of absolute tables because of the problem of needing to load ;; the LIP register prior to loading an arbitrary PC. @@ -167,6 +170,7 @@ ;; is a jump table. I don't think that's worth the trouble. (emit section `(.lispword ,(1+ nwords))) (when (plusp nwords) + (setf (ir2-component-n-jump-table-entries ir2-component) nwords) (dolist (constant (jump-tables)) (sb-vm:emit-inline-constant section (car constant) (cdr constant))) (let ((nremaining (length (other)))) @@ -264,12 +268,16 @@ (defglobal *static-vop-usage-counts* nil) (defparameter *do-instcombine-pass* t) -(defun generate-code (component) +(defun generate-code (component &aux (ir2-component (component-info component))) + (declare (type ir2-component ir2-component)) (when *compiler-trace-output* - (format *compiler-trace-output* - "~|~%assembly code for ~S~2%" - component)) + (let ((*print-pretty* nil)) ; force 1 line + (format *compiler-trace-output* "~|~%assembly code for ~S~2%" component))) (let* ((prev-env nil) + (sb-vm::*adjustable-vectors* nil) + ;; The first function's alignment word is zero-filled, but subsequent + ;; ones can use a NOP which helps the disassembler not lose sync. + (filler-pattern 0) (asmstream (make-asmstream)) (*asmstream* asmstream)) @@ -294,15 +302,16 @@ (not (loop-info cloop))) ;; Mark the loop as aligned by saving the IR1 block aligned. (setf (loop-info cloop) 1block) - t)))) + filler-pattern)))) + (setf filler-pattern :long-nop) (emit-block-header (block-label 1block) (ir2-block-%trampoline-label block) (ir2-block-dropped-thru-to block) alignp))) - (let ((env (block-physenv 1block))) + (let ((env (block-environment 1block))) (unless (eq env prev-env) - (let ((lab (gen-label "physenv elsewhere start"))) - (setf (ir2-physenv-elsewhere-start (physenv-info env)) + (let ((lab (gen-label "environment elsewhere start"))) + (setf (ir2-environment-elsewhere-start (environment-info env)) lab) (emit (asmstream-elsewhere-section asmstream) lab)) (setq prev-env env))))) @@ -310,7 +319,7 @@ ((null vop)) (let ((gen (vop-info-generator-function (vop-info vop)))) (awhen *static-vop-usage-counts* - (let ((name (vop-info-name (vop-info vop)))) + (let ((name (vop-name vop))) (incf (gethash name it 0)))) (assemble (:code vop) (cond ((not gen) @@ -328,33 +337,48 @@ (funcall gen vop))))))) (when *do-instcombine-pass* - #+x86-64 + #+(or arm64 x86-64) (sb-assem::combine-instructions (asmstream-code-section asmstream))) + (emit (asmstream-data-section asmstream) + (sb-assem::asmstream-data-origin-label asmstream)) ;; Jump tables precede the coverage mark bytes to simplify locating ;; them in trans_code(). - (emit-jump-tables) - ;; Todo: can we implement the flow-based aspect of coverage mark compression - ;; in IR2 instead of waiting until assembly generation? - (coverage-mark-lowering-pass component asmstream) + (emit-jump-tables ir2-component) + (let ((coverage-map (ir2-component-coverage-map ir2-component))) + (unless (zerop (length coverage-map)) + ;; Nothing depends on the length of the constant vector at this + ;; phase (codegen has not made use of component-header-length), + ;; so extending can be done with impunity. + #+arm64 + (vector-push-extend (cons :coverage-marks (length coverage-map)) + (ir2-component-constants ir2-component)) + (vector-push-extend + (make-constant (cons 'coverage-map + (map-into coverage-map #'car coverage-map))) + (ir2-component-constants ir2-component)) + ;; Allocate space in the data section for coverage marks. + #-arm64 + (emit (asmstream-data-section asmstream) + `(.skip ,(length coverage-map) #-(or x86 x86-64) #xff)))) + (emit-inline-constants) - (let* ((info (component-info component)) - (simple-fun-labels - (mapcar #'entry-info-offset (ir2-component-entries info))) - (n-boxed (length (ir2-component-constants info))) + (let* ((n-boxed (length (ir2-component-constants ir2-component))) ;; Skew is either 0 or N-WORD-BYTES depending on whether the boxed ;; header length is even or odd (skew (if (and (= code-boxed-words-align 1) (oddp n-boxed)) sb-vm:n-word-bytes 0))) (multiple-value-bind (segment text-length fixup-notes fun-table) - (assemble-sections asmstream - simple-fun-labels - (make-segment :header-skew skew - :run-scheduler (default-segment-run-scheduler))) + (assemble-sections + asmstream + (mapcar #'entry-info-offset (ir2-component-entries ir2-component)) + (make-segment :header-skew skew + :run-scheduler (default-segment-run-scheduler))) (values segment text-length fun-table - (asmstream-elsewhere-label asmstream) fixup-notes))))) + (asmstream-elsewhere-label asmstream) fixup-notes + (sb-assem::get-allocation-points asmstream)))))) (defun label-elsewhere-p (label-or-posn kind) (let ((elsewhere (label-position *elsewhere-label*)) @@ -369,60 +393,3 @@ ;; We're interested in what precedes the return, not after (< elsewhere label) (<= elsewhere label)))) - -;;; Translate .COVERAGE-MARK pseudo-op into machine assembly language, -;;; combining any number of consecutive operations with no intervening -;;; control flow into a single operation. -;;; FIXME: this pass runs even if no coverage instrumentation was generated. -(defun coverage-mark-lowering-pass (component asmstream) - (declare (ignorable component asmstream)) - #+(or x86-64 x86) - (let ((label (gen-label)) - ;; vector of lists of original source paths covered - (src-paths (make-array 10 :fill-pointer 0)) - (previous-mark)) - (do ((statement (stmt-next (section-start (asmstream-code-section asmstream))) - (stmt-next statement))) - ((null statement)) - (dolist (item (ensure-list (stmt-labels statement))) - (when (label-usedp item) ; control can transfer to here - (setq previous-mark nil))) - (let ((mnemonic (stmt-mnemonic statement))) - (typecase mnemonic - (function ; this can do anything, who knows - (setq previous-mark nil)) - (string) ; a comment can be ignored - (t - (cond ((branch-opcode-p mnemonic) ; control flow kills mark combining - (setq previous-mark nil)) - ((eq mnemonic '.coverage-mark) - (let ((path (car (stmt-operands statement)))) - (cond ((not previous-mark) ; record a new path - (let ((mark-index - (vector-push-extend (list path) src-paths))) - ;; have the backend lower it into a real instruction - (replace-coverage-instruction statement label mark-index)) - (setq previous-mark statement)) - (t ; record that the already-emitted mark pertains - ;; to an additional source path - (push path (elt src-paths (1- (fill-pointer src-paths)))) - ;; Clobber this statement. Do not try to remove it and - ;; combine its labels into the previous statement. - ;; Doing that could move a label into an earlier IR2 block - ;; which crashes when dumping locations. - (setf (stmt-mnemonic statement) nil - (stmt-operands statement) nil)))))))))) - - ;; Allocate space in the data section for coverage marks - (let ((mark-index (length src-paths))) - (when (plusp mark-index) - (setf (label-usedp label) t) - (let ((v (ir2-component-constants (component-info component)))) - ;; Nothing depends on the length of the constant vector at this - ;; phase (codegen has not made use of component-header-length), - ;; so extending can be done with impunity. - (vector-push-extend - (make-constant (cons 'coverage-map - (coerce src-paths 'simple-vector))) - v)) - (emit (asmstream-data-section asmstream) label `(.skip ,mark-index)))))) diff --git a/src/compiler/compiler-deftype.lisp b/src/compiler/compiler-deftype.lisp deleted file mode 100644 index f98ce2cb14..0000000000 --- a/src/compiler/compiler-deftype.lisp +++ /dev/null @@ -1,57 +0,0 @@ -;;;; that part of DEFTYPE which runs within the compiler itself - -;;;; This software is part of the SBCL system. See the README file for -;;;; more information. -;;;; -;;;; This software is derived from the CMU CL system, which was -;;;; written at Carnegie Mellon University and released into the -;;;; public domain. The software is in the public domain and is -;;;; provided with absolutely no warranty. See the COPYING and CREDITS -;;;; files for more information. - -(in-package "SB-IMPL") - -(/show0 "compiler-deftype.lisp 14") - -(defun %compiler-deftype (name expander source-location &optional doc) - (declare (ignorable doc)) - (with-single-package-locked-error - (:symbol name "defining ~A as a type specifier")) - (ecase (info :type :kind name) - (:primitive - ;; Detecting illegal redefinition in the cross-compiler - ;; adds unnecessary complexity, so don't bother. - #-sb-xc-host - (when *type-system-initialized* - (error "illegal to redefine standard type: ~S" name))) - (:instance - (warn "The class ~S is being redefined to be a DEFTYPE." name) - (undeclare-structure (find-classoid name) t) - ;; FIXME: shouldn't this happen only at eval-time? - (setf (classoid-cell-classoid (find-classoid-cell name :create t)) nil) - (clear-info :type :compiler-layout name) - (setf (info :type :kind name) :defined)) - (:defined - ;; Note: It would be nice to warn here when a type is being - ;; incompatibly redefined, but it's hard to tell, since type - ;; expanders are often function objects which can't easily be - ;; compared for equivalence. And just warning on redefinition - ;; isn't good, since DEFTYPE necessarily does its thing once at - ;; compile time and again at load time, so that it's very common - ;; and normal for types to be defined twice. So since there - ;; doesn't seem to be anything simple and obvious to do, and - ;; since mistakenly redefining a type isn't a common error - ;; anyway, we just don't worry about trying to warn about it. - ) - ((nil :forthcoming-defclass-type) - (setf (info :type :kind name) :defined))) - (setf (info :type :expander name) expander) - (when source-location - (setf (info :type :source-location name) source-location)) - #-sb-xc-host - (when doc - (setf (documentation name 'type) doc)) - (sb-c::%note-type-defined name) - name) - -(/show0 "compiler-deftype.lisp end of file") diff --git a/src/compiler/constantp.lisp b/src/compiler/constantp.lisp index 269eb6eb7e..9989baf9eb 100644 --- a/src/compiler/constantp.lisp +++ b/src/compiler/constantp.lisp @@ -11,7 +11,7 @@ (in-package "SB-C") -(defparameter *special-constant-variables* nil) +(defvar *special-constant-variables* nil) (defun %constantp (form environment envp) ;; Pick off quasiquote prior to macroexpansion. diff --git a/src/compiler/constraint.lisp b/src/compiler/constraint.lisp index 0e598a3c62..0d0c11ea83 100644 --- a/src/compiler/constraint.lisp +++ b/src/compiler/constraint.lisp @@ -417,6 +417,19 @@ ;;; equality or emptiness testing. There's also union, but that's only an ;;; optimisation to avoid useless copies in ADD-TEST-CONSTRAINTS and ;;; FIND-BLOCK-TYPE-CONSTRAINTS. +(defmacro do-conset-elements ((constraint conset &optional result) &body body) + (let ((index (gensym "INDEX")) + (conset-vector (gensym "CONSET-VECTOR")) + (universe (gensym "UNIVERSE"))) + `(let ((,conset-vector (conset-vector ,conset)) + (,universe *constraint-universe*)) + (declare (optimize speed)) + (loop for ,index from (conset-min ,conset) below (conset-max ,conset) + do (when (plusp (sbit ,conset-vector ,index)) + (let ((,constraint (aref ,universe ,index))) + ,@body)) + finally (return ,result))))) + (defmacro do-conset-constraints-intersection ((symbol (conset constraints) &optional result) &body body) (let ((min (gensym "MIN")) @@ -426,18 +439,17 @@ `(flet ((body (,symbol) (declare (type constraint ,symbol)) ,@body)) + (declare (optimize speed) + (inline body)) (when ,constraints (let ((,min (conset-min ,conset)) (,max (conset-max ,conset))) - (declare (optimize speed)) - (map nil (lambda (constraint) - (declare (type constraint constraint)) - (let ((number (constraint-number constraint))) - (when (and (<= ,min number) - (< number ,max) - (conset-member constraint ,conset)) - (body constraint)))) - ,constraints))) + (loop for constraint across ,constraints + do (let ((number (constraint-number (the constraint constraint)))) + (when (and (<= ,min number) + (< number ,max) + (conset-member constraint ,conset)) + (body constraint)))))) ,result)))) (defmacro do-eql-vars ((symbol (var constraints) &optional result) &body body) @@ -547,7 +559,7 @@ ;;; If REF is to a LAMBDA-VAR with CONSTRAINTs (i.e. we can do flow ;;; analysis on it), then return the LAMBDA-VAR, otherwise NIL. -#-sb-fluid (declaim (inline ok-ref-lambda-var)) +(declaim (inline ok-ref-lambda-var)) (defun ok-ref-lambda-var (ref) (declare (type ref ref)) (let ((leaf (ref-leaf ref))) @@ -668,7 +680,7 @@ (let ((use (principal-lvar-ref-use length-lvar))) (and (combination-p use) (lvar-fun-is (combination-fun use) - '(vector-length)) + '(vector-length length)) (car (combination-args use)))))) (when (and (or index-var index-constant) array-lvar) @@ -745,7 +757,7 @@ (add 'eql var1 var2 nil)) ((constant-lvar-p arg2) (add 'eql var1 - (find-constant (lvar-value arg2)) + (nth-value 1 (lvar-value arg2)) nil)) (t (add-test-constraint quick-p @@ -932,6 +944,94 @@ ((xset-member-p 0 xset) (make-numeric-type :class 'integer :low 0 :high 0)))) +;;; Compute the tightest type possible for a variable given a set of +;;; CONSTRAINTS. +(defun type-from-constraints (variable constraints initial-type) + ;; FIXME: Try to share some of this logic with CONSTRAIN-REF. It was + ;; copied out of that. + (let ((type initial-type) + ;; FIXME: see the comment in CONSTRAIN-REF-TYPES. This makes + ;; LINE-BREAK-ANNOTATE compile a lot slower in self + ;; build. Reconsider whether we want this policy dependent and + ;; have that function add LINE-BREAK-ANNOTATE once we merge + ;; the functions. + (constrain-symbols nil) + (not-type *empty-type*) + (not-set nil) + (not-numeric nil) + (not-fpz '())) + (flet ((note-not (x) + (if (fp-zero-p x) + (push x not-fpz) + (when (or constrain-symbols (null x) (not (symbolp x))) + (when (null not-set) + (setf not-set (alloc-xset))) + (add-to-xset x not-set)))) + (intersect-result (other-type) + (setf type (type-approx-intersection2 type other-type)))) + (declare (inline intersect-result)) + (do-propagatable-constraints (con (constraints variable)) + (let* ((kind (constraint-kind con)) + (x (constraint-x con)) + (y (constraint-y con)) + (not-p (constraint-not-p con)) + (other (if (eq x variable) y x))) + (case kind + (typep + (cond ((not not-p) + (intersect-result other)) + ((member-type-p other) + (mapc-member-type-members #'note-not other)) + (t + (setq not-type (type-union not-type other))))) + (eql + (let ((other-type (leaf-type other))) + (cond ((not not-p) + (intersect-result other-type)) + ((constant-p other) + (cond ((member-type-p other-type) + (note-not (constant-value other))) + ;; Numeric types will produce interesting + ;; negations, other than just "not equal" + ;; which can be handled by the equality + ;; constraints. + ((numeric-type-p other-type) + (when (null not-numeric) + (setf not-numeric (alloc-xset))) + (add-to-xset (constant-value other) not-numeric))))))) + ((< >) + (let* ((greater (eq kind '>)) + (greater (if not-p (not greater) greater))) + (cond ((and (integer-type-p type) (integer-type-p y)) + (setf type (constrain-integer-type type y greater not-p))) + ((and (float-type-p type) (float-type-p y)) + (setf type (constrain-float-type type y greater not-p))) + ((integer-type-p y) + (let ((real-type (constrain-real-to-integer y greater not-p))) + (when real-type (intersect-result real-type))))))) + (= + (when (and (numeric-type-p y) + (not not-p)) + (let* ((low (numeric-type-low y)) + (high (numeric-type-high y)) + (real (make-numeric-type :low low :high high)) + (complex (make-numeric-type :complexp :complex :low low :high high))) + (intersect-result (type-union real complex))))))))) + (let* ((negated not-type) + (negated (if (and (null not-set) (null not-fpz)) + negated + (let ((excluded (make-member-type + (or not-set (alloc-xset)) not-fpz))) + (type-union negated excluded)))) + (numeric (when not-numeric + (contiguous-numeric-set-type not-numeric))) + (negated (if numeric + (type-union negated numeric) + negated))) + (if (eq negated *empty-type*) + type + (type-difference type negated))))) + ;;; Given the set of CONSTRAINTS for a variable and the current set of ;;; restrictions from flow analysis IN, set the type for REF ;;; accordingly. @@ -980,7 +1080,7 @@ (if (member-type-p other) (mapc-member-type-members #'note-not other) (setq not-res (type-union not-res other))) - (setq res (type-approx-intersection2 res other)))) + (setq res (type-intersection res other)))) (array-in-bounds-p (unless (eq (ref-constraints ref) (pushnew con (ref-constraints ref))) @@ -1009,8 +1109,7 @@ (change-ref-leaf ref other) (when (constant-p other) (return))) (t - (setq res (type-approx-intersection2 - res other-type)))))))) + (setq res (type-intersection res other-type)))))))) ((< >) (let* ((greater (eq kind '>)) (greater (if not-p (not greater) greater))) @@ -1025,17 +1124,17 @@ (let ((type (constrain-real-to-integer y greater not-p))) (when type (setf res - (type-approx-intersection2 res type)))))))) + (type-intersection res type)))))))) (= (when (and (numeric-type-p y) (not not-p)) (setf res - (type-approx-intersection2 res - (type-union (make-numeric-type :low (numeric-type-low y) - :high (numeric-type-high y)) - (make-numeric-type :complexp :complex - :low (numeric-type-low y) - :high (numeric-type-high y))))))))))) + (type-intersection res + (type-union (make-numeric-type :low (numeric-type-low y) + :high (numeric-type-high y)) + (make-numeric-type :complexp :complex + :low (numeric-type-low y) + :high (numeric-type-high y))))))))))) (cond ((and (if-p (node-dest ref)) (or (xset-member-p nil not-set) (csubtypep (specifier-type 'null) not-res))) @@ -1047,8 +1146,8 @@ (make-member-type not-set not-fpz))) (numeric (contiguous-numeric-set-type not-numeric)) (type (type-difference res - (if numeric - (type-union union numeric) + (if numeric + (type-union union numeric) union)))) ;; CHANGE-CLASS can change the type, lower down to standard-object, ;; type propagation for classes is not as important anyway. @@ -1265,7 +1364,41 @@ (if-alternative-constraints last)))) (block-out pred)))) -(defun compute-block-in (block) +;;; Join the constraints coming from the predecessors of BLOCK on +;;; every constrained variable into the constraint set IN. +(defun join-type-constraints (in block) + (let ((vars '())) + ;; Find some set of constrained variables in the predecessors. + (dolist (pred (block-pred block)) + (let ((out (block-out-for-successor pred block))) + (when out + (do-conset-elements (con out) + (let ((kind (constraint-kind con)) + (y (constraint-y con)) + (not-p (constraint-not-p con))) + (when (or (member kind '(typep < >)) + (and (eq kind 'eql) (or (not not-p) + (constant-p y))) + (and (eq kind '=) (and (numeric-type-p y) + (not not-p)))) + (pushnew (constraint-x con) vars)))) + (return)))) + (dolist (var vars) + (let ((in-var-type *empty-type*)) + (dolist (pred (block-pred block)) + (let ((out (block-out-for-successor pred block))) + (when out + (setq in-var-type + (type-union in-var-type + (type-from-constraints var out *universal-type*)))))) + (unless (eq in-var-type *universal-type*) + (conset-adjoin (find-or-create-constraint 'typep + var + in-var-type + nil) + in)))))) + +(defun compute-block-in (block join-types-p) (let ((in nil)) (dolist (pred (block-pred block)) ;; If OUT has not been calculated, assume it to be the universal @@ -1275,10 +1408,12 @@ (if in (conset-intersection in out) (setq in (copy-conset out)))))) + (when join-types-p + (join-type-constraints in block)) (or in (make-conset)))) -(defun update-block-in (block) - (let ((in (compute-block-in block))) +(defun update-block-in (block join-types-p) + (let ((in (compute-block-in block join-types-p))) (cond ((and (block-in block) (conset= in (block-in block))) nil) (t @@ -1286,39 +1421,25 @@ ;;; Return two lists: one of blocks that precede all loops and ;;; therefore require only one constraint propagation pass and the -;;; rest. This implementation does not find all such blocks. -;;; -;;; A more complete implementation would be: -;;; -;;; (do-blocks (block component) -;;; (if (every #'(lambda (pred) -;;; (or (member pred leading-blocks) -;;; (eq pred head))) -;;; (block-pred block)) -;;; (push block leading-blocks) -;;; (push block rest-of-blocks))) +;;; rest. ;;; ;;; Trailing blocks that succeed all loops could be found and handled ;;; similarly. In practice though, these more complex solutions are ;;; slightly worse performancewise. (defun leading-component-blocks (component) (declare (type component component)) - (flet ((loopy-p (block) - (let ((n (block-number block))) - (dolist (pred (block-pred block)) - (unless (< n (block-number pred)) - (return t)))))) - (let ((leading-blocks ()) - (rest-of-blocks ()) - (seen-loop-p ())) - (do-blocks (block component) + (collect ((leading-blocks) (rest-of-blocks)) + (do-blocks (block component) + (let ((leading t)) + (dolist (pred (block-pred block)) + (unless (block-flag pred) + (setq leading nil))) + (setf (block-flag block) leading) (when (block-type-check block) - (when (and (not seen-loop-p) (loopy-p block)) - (setq seen-loop-p t)) - (if seen-loop-p - (push block rest-of-blocks) - (push block leading-blocks)))) - (values (nreverse leading-blocks) (nreverse rest-of-blocks))))) + (if leading + (leading-blocks block) + (rest-of-blocks block))))) + (values (leading-blocks) (rest-of-blocks)))) ;;; Append OBJ to the end of LIST as if by NCONC but only if it is not ;;; a member already. @@ -1339,6 +1460,7 @@ (dolist (block blocks) (when (block-type-check block) (setq blocks-to-process (nconc-new block blocks-to-process)))))) + (clear-flags component) (multiple-value-bind (leading-blocks rest-of-blocks) (leading-component-blocks component) ;; Update every block once to account for changes in the @@ -1346,20 +1468,30 @@ ;; after the first pass so we might as well use them and skip ;; USE-RESULT-CONSTRAINTS later. (dolist (block leading-blocks) - (setf (block-in block) (compute-block-in block)) + (setf (block-in block) (compute-block-in block t)) (find-block-type-constraints block t)) - (setq blocks-to-process (copy-list rest-of-blocks)) - ;; The rest of the blocks. - (dolist (block rest-of-blocks) - (aver (eq block (pop blocks-to-process))) - (setf (block-in block) (compute-block-in block)) - (enqueue (find-block-type-constraints block nil))) - ;; Propagate constraints - (loop for block = (pop blocks-to-process) - while block do - (unless (eq block (component-tail component)) - (when (update-block-in block) - (enqueue (find-block-type-constraints block nil))))) + ;; We can only start joining types on blocks in which + ;; constraint propagation might have to run multiple times (to + ;; fixpoint) once all type constraints are definitely + ;; correct. They may not be the first time around because EQL + ;; constraint propagation is optimistic, i.e. un-EQL variables + ;; may be considered EQL before constraint propagation is + ;; done, hence any inherited type constraints from such + ;; constraints will be wrong as well. + (dolist (join-types-p '(nil t)) + (setq blocks-to-process (copy-list rest-of-blocks)) + ;; The rest of the blocks. + (dolist (block rest-of-blocks) + (aver (eq block (pop blocks-to-process))) + (setf (block-in block) (compute-block-in block join-types-p)) + (enqueue (find-block-type-constraints block nil))) + ;; Propagate constraints + (loop for block = (pop blocks-to-process) + while block do + (unless (eq block (component-tail component)) + (when (update-block-in block join-types-p) + (enqueue (find-block-type-constraints block nil)))))) + rest-of-blocks)))) (defun constraint-propagate (component) diff --git a/src/compiler/control.lisp b/src/compiler/control.lisp index 2bd47a269a..8f1f154024 100644 --- a/src/compiler/control.lisp +++ b/src/compiler/control.lisp @@ -66,15 +66,15 @@ (defun find-rotated-loop-head (block) (declare (type cblock block)) (let* ((num (block-number block)) - (env (block-physenv block)) + (env (block-environment block)) (pred (dolist (pred (block-pred block) nil) (when (and (not (block-flag pred)) - (eq (block-physenv pred) env) + (eq (block-environment pred) env) (< (block-number pred) num)) (return pred))))) (cond ((and pred - (not (physenv-nlx-info env)) + (not (environment-nlx-info env)) (not (eq (lambda-block (block-home-lambda block)) block)) (null (cdr (block-succ pred)))) (let ((current pred) @@ -85,7 +85,7 @@ (when (eq pred block) (return-from DONE)) (when (and (not (block-flag pred)) - (eq (block-physenv pred) env) + (eq (block-environment pred) env) (> (block-number pred) current-num)) (setq current pred current-num (block-number pred)) (return))))) @@ -94,8 +94,36 @@ (t block)))) +;;; Attempt to walk blocks that are in the same loop first, so that +;;; they are more likely to be the fall-through case. This causes a +;;; conditional branch that leaves a loop (and probably branches +;;; forwards) to fall through most of the time, which is generally +;;; faster and has better locality of reference. Without this change, +;;; the successors would always be traversed in the order they appear +;;; in the list, so some loops would look like +;;; L0: conditionally branch to L1 if the loop should continue +;;; break out of loop somehow +;;; L1: loop body +;;; jump to L0 +;;; which needlessly takes the conditional branch on every loop +;;; iteration. +(defun control-relevance-to (pred succ) + (declare (type cblock pred succ)) + (cond + ((or (null (block-loop pred)) (null (block-loop succ))) 1) + ((>= (loop-depth (block-loop succ)) (loop-depth (block-loop pred))) 2) + (t 0))) + +(defun control-order-successors (block successors) + (if (and (= (length successors) 2) + (< (control-relevance-to block (first successors)) + (control-relevance-to block (second successors)))) + (list (second successors) (first successors)) + successors)) + ;;; Do a graph walk linking blocks into the emit order as we go. We -;;; call FIND-ROTATED-LOOP-HEAD to do while-loop optimization. +;;; call FIND-ROTATED-LOOP-HEAD to do while-loop optimization, and +;;; CONTROL-ORDER-SUCCESSORS to optimize other sorts of loops. ;;; ;;; We treat blocks ending in tail local calls to other environments ;;; specially. We can't walked the called function immediately, since @@ -127,14 +155,14 @@ (let ((last (block-last block))) (cond ((and (combination-p last) (node-tail-p last) (eq (basic-combination-kind last) :local) - (not (eq (node-physenv last) - (lambda-physenv (combination-lambda last))))) + (not (eq (node-environment last) + (lambda-environment (combination-lambda last))))) (combination-lambda last)) (t (let ((component-tail (component-tail (block-component block))) (block-succ (block-succ block)) (fun nil)) - (dolist (succ block-succ) + (dolist (succ (control-order-successors block block-succ)) (unless (eq (first (block-succ succ)) component-tail) (let ((res (control-analyze-block succ tail))) (when res (setq fun res))))) @@ -160,7 +188,7 @@ (prev-block (block-annotation-prev tail-block)) (bind-block (node-block (lambda-bind fun)))) (unless (block-flag bind-block) - (dolist (nlx (physenv-nlx-info (lambda-physenv fun))) + (dolist (nlx (environment-nlx-info (lambda-environment fun))) (control-analyze-block (nlx-info-target nlx) tail-block)) (cond ((block-flag bind-block) diff --git a/src/compiler/copyprop.lisp b/src/compiler/copyprop.lisp index a824c179a4..c38e83ef9d 100644 --- a/src/compiler/copyprop.lisp +++ b/src/compiler/copyprop.lisp @@ -74,11 +74,13 @@ (not (tn-sc tn)) ; Not wired or restricted. (and writes (null (tn-ref-next writes))) (let ((vop (tn-ref-vop writes))) - (and (eq (vop-info-name (vop-info vop)) 'move) + (and (eq (vop-name vop) 'move) (let ((arg-tn (tn-ref-tn (vop-args vop)))) (and (or (not (tn-sc arg-tn)) (eq (tn-kind arg-tn) :constant)) (or + (subsetp (primitive-type-scs (tn-primitive-type tn)) + (primitive-type-scs (tn-primitive-type arg-tn))) (let ((reads (tn-reads tn))) ;; For moves to another moves the SC does ;; not matter, the intermediate SC will @@ -86,11 +88,11 @@ ;; performed based on the SC. (and reads (null (tn-ref-next reads)) - (eq (vop-info-name (vop-info (tn-ref-vop reads))) 'move))) - (subsetp (primitive-type-scs - (tn-primitive-type tn)) - (primitive-type-scs - (tn-primitive-type arg-tn)))) + (eq (vop-name (tn-ref-vop reads)) 'move) + ;; Except for fixnums which may benifit from improved representation selection + ;; if there is a way to go through an any-reg "adapter" + (not (memq sb-vm:any-reg-sc-number (primitive-type-scs (tn-primitive-type tn)))) + (not (memq sb-vm:any-reg-sc-number (primitive-type-scs (tn-primitive-type arg-tn))))))) (let ((leaf (tn-leaf tn))) (or (not leaf) (and @@ -99,7 +101,7 @@ (or (not (cl:symbol-package (leaf-debug-name leaf))) (policy (vop-node vop) - (or (= speed 3) (< debug 2)))) + (= preserve-single-use-debug-variables 0))) ;; arguments of local functions have hidden write (not (and (lambda-var-p leaf) (memq (functional-kind (lambda-var-home leaf)) @@ -113,7 +115,7 @@ ;; MOVEs can be chained and read in other blocks. This is done ;; not for correctness but for memory usage reduction, so there ;; is no need to follow all the chains, just be conservative. - (when (or (eq (vop-info-name (vop-info vop)) 'move) + (when (or (eq (vop-name vop) 'move) (neq (ir2-block-block (vop-block vop)) block)) (return))))) @@ -128,7 +130,7 @@ (out (make-sset))) (do ((vop (ir2-block-start-vop (block-info block)) (vop-next vop))) ((null vop)) - (unless (and (eq (vop-info-name (vop-info vop)) 'move) + (unless (and (eq (vop-name vop) 'move) (let ((y (tn-ref-tn (vop-results vop)))) (when (tn-is-copy-of y) (unless (reads-within-block-p y block) @@ -141,7 +143,7 @@ (do ((read (tn-reads res-tn) (tn-ref-next read))) ((null read)) (let ((read-vop (tn-ref-vop read))) - (when (eq (vop-info-name (vop-info read-vop)) 'move) + (when (eq (vop-name read-vop) 'move) (let ((y (tn-ref-tn (vop-results read-vop)))) (when (tn-is-copy-of y) (sset-delete y out) @@ -232,7 +234,7 @@ (block-kill block) nil) (do ((vop (ir2-block-start-vop (block-info block)) (vop-next vop))) ((null vop)) - (let ((this-copy (and (eq (vop-info-name (vop-info vop)) 'move) + (let ((this-copy (and (eq (vop-name vop) 'move) (let ((y (tn-ref-tn (vop-results vop)))) (when (tn-is-copy-of y) y))))) ;; Substitute copied TN for copy when we find a reference to a copy. diff --git a/src/compiler/coverage.lisp b/src/compiler/coverage.lisp new file mode 100644 index 0000000000..e6f436ce9b --- /dev/null +++ b/src/compiler/coverage.lisp @@ -0,0 +1,96 @@ +;;;; code coverage + +;;;; This software is part of the SBCL system. See the README file for +;;;; more information. +;;;; +;;;; This software is derived from the CMU CL system, which was +;;;; written at Carnegie Mellon University and released into the +;;;; public domain. The software is in the public domain and is +;;;; provided with absolutely no warranty. See the COPYING and CREDITS +;;;; files for more information. + +(in-package "SB-C") + +(defknown %mark-covered (cons) t (always-translatable)) + +;;; Check the policy for whether we should generate code coverage +;;; instrumentation. If not, just return the original START +;;; ctran. Otherwise insert code coverage instrumentation after +;;; START, and return the new ctran. +(defun instrument-coverage (start mode form + &aux (metadata (coverage-metadata *compilation*))) + ;; We don't actually use FORM for anything, it's just convenient to + ;; have around when debugging the instrumentation. + (declare (ignore form)) + (if (and metadata + (policy *lexenv* (> store-coverage-data 0)) + *allow-instrumenting*) + (let ((path (source-path-original-source *current-path*))) + (when mode + (push mode path)) + ;; If this source path has already been instrumented in this + ;; block, don't instrument it again. + (if (member (ctran-block start) + (gethash path (code-coverage-blocks metadata))) + start + (let ((next (make-ctran)) + (*allow-instrumenting* nil)) + (setf (gethash path (code-coverage-records metadata)) t) + (push (ctran-block start) + (gethash path (code-coverage-blocks metadata))) + (ir1-convert start next nil `(%mark-covered ',path)) + next))) + start)) + +;;; In contexts where we don't have a source location for FORM +;;; e.g. due to it not being a cons, but where we have a source +;;; location for the enclosing cons, use the latter source location if +;;; available. This works pretty well in practice, since many PROGNish +;;; macroexpansions will just directly splice a block of forms into +;;; some enclosing form with `(progn ,@body), thus retaining the +;;; EQness of the conses. +(defun maybe-instrument-progn-like (start forms form) + (or (when (and *allow-instrumenting* + (not (get-source-path form))) + (let ((*current-path* (get-source-path forms))) + (when *current-path* + (instrument-coverage start nil form)))) + start)) + +;;; Emit a coverage mark for NODE if there is a possibility that +;;; marking a previous coverage mark does not entail NODE's +;;; evaluation. We scan backwards in the block, looking for any +;;; intervening combinations between this node and another +;;; %MARK-COVERED. If the intervening combination is a combination for +;;; a LET or ASSIGNMENT lambda, then we don't need to emit a coverage +;;; mark, as the control flow has been made explicit in the CFG. +;;; KLUDGE: Technically we should stick with merging strictly adjacent +;;; emitted coverage marks in the IR2, as that would make coverage +;;; instrumentation interrupt safe as well. However, doing it this way +;;; produces much less instrumentation. +(defoptimizer (%mark-covered ir2-convert) ((path) node block) + (aver (constant-lvar-p path)) + (do ((prev (ctran-use (node-prev node)) + (ctran-use (node-prev prev))) + (start-node (block-start-node (ir2-block-block block)))) + ((eq prev start-node)) + (when (basic-combination-p prev) + (let ((kind (basic-combination-kind prev))) + (when (case kind + (:known + (when (eq (lvar-fun-name (basic-combination-fun prev) t) + '%mark-covered) + (return)) + t) + (:local + (not (functional-somewhat-letlike-p (combination-lambda prev)))) + (t t)) + (setf (ir2-block-covered-paths-ref block) + (list nil)))))) + (let ((2comp (component-info (node-component node)))) + (unless (car (ir2-block-covered-paths-ref block)) + (vop mark-covered node block + (vector-push-extend (ir2-block-covered-paths-ref blocK) + (ir2-component-coverage-map 2comp)))) + (push (lvar-value path) (car (ir2-block-covered-paths-ref block))) + (values))) diff --git a/src/compiler/ctype.lisp b/src/compiler/ctype.lisp index 17ac8bfc80..acd36b38a8 100644 --- a/src/compiler/ctype.lisp +++ b/src/compiler/ctype.lisp @@ -69,6 +69,17 @@ (values)) +(defun node-asserted-type (node) + (let ((dtype (node-derived-type node))) + (or + (binding* ((lvar (node-lvar node) :exit-if-null) + (dest (lvar-dest lvar))) + (when (and (cast-p dest) + (eq (cast-type-to-check dest) *wild-type*)) + (values-type-intersection + dtype (cast-asserted-type dest)))) + dtype))) + ;;;; stuff for checking a call against a function type ;;; Determine whether a use of a function is consistent with its type. @@ -117,28 +128,20 @@ (caller (loop for annotation in (lvar-annotations fun) when (typep annotation 'lvar-function-designator-annotation) do (setf *compiler-error-context* annotation) - (return (lvar-function-designator-annotation-caller annotation))))) + (return (lvar-function-designator-annotation-caller annotation)))) + (name (nth-value 1 (lvar-fun-type fun)))) (cond - ((report-arg-count-mismatch (nth-value 1 (lvar-fun-type fun)) + ((report-arg-count-mismatch name caller type nargs nil :lossage-fun #'note-lossage)) (t (check-fixed-and-rest args (append required optional) rest) (when (and keyp - (check-key-args args max-args type)) + (check-key-args name args max-args type)) (setf unknown-keys t)))) (when result-test - (let* ((dtype (node-derived-type call)) - (out-type (or - (binding* ((lvar (node-lvar call) :exit-if-null) - (dest (lvar-dest lvar))) - (when (and (cast-p dest) - (eq (cast-type-to-check dest) *wild-type*) - (immediately-used-p lvar call)) - (values-type-intersection - dtype (cast-asserted-type dest)))) - dtype)) + (let* ((out-type (node-asserted-type call)) (return-type (fun-type-returns type))) (multiple-value-bind (int win) (funcall result-test out-type return-type) (cond ((not win) @@ -207,7 +210,7 @@ (dsd-default slot)))) ;; Return T if value-form definitely does not satisfy ;; the type-check for DSD. Return NIL if we can't decide. - (when (if (sb-xc:constantp initform) + (when (if (constantp initform) (not (sb-xc:typep (constant-form-value initform) (dsd-type slot))) ;; Find uses of nil-returning functions as defaults, @@ -268,8 +271,8 @@ and no value was provided for it." name)))))))))) ;;; Check that each of the type of each supplied argument intersects ;;; with the type specified for that argument. If we can't tell, then ;;; we can complain about the absence of manifest winnage. -(declaim (ftype (function (list list (or ctype null)) (values)) check-fixed-and-rest)) (defun check-fixed-and-rest (args types rest) + (declare (list args types) (type (or ctype null) rest)) (do ((arg args (cdr arg)) (type types (cdr type)) (n 1 (1+ n))) @@ -286,8 +289,9 @@ and no value was provided for it." name)))))))))) ;;; be known and the corresponding argument should be of the correct ;;; type. If the key isn't a constant, then we can't tell, so we can ;;; complain about absence of manifest winnage. -(declaim (ftype (function (list fixnum fun-type) boolean) check-key-args)) -(defun check-key-args (args pre-key type) +(defun check-key-args (name args pre-key type) + (declare (list args) (fixnum pre-key) (fun-type type)) + (declare (ignorable name)) (let (lossages allow-other-keys unknown-keys) (do ((key (nthcdr pre-key args) (cddr key)) @@ -325,20 +329,27 @@ and no value was provided for it." name)))))))))) (1+ n))))))))) (when (and lossages (member allow-other-keys '(nil :no))) (setf lossages (nreverse lossages)) - (if (cdr lossages) - (note-lossage "~@<~{~S~^, ~} and ~S are not a known argument keywords.~:@>" - (butlast lossages) - (car (last lossages))) - (note-lossage "~S is not a known argument keyword." - (car lossages)))) + + (cond #-sb-xc-host + ((or (eq (info :function :type name) :generic-function) + (eq (info :function :where-from name) :defined-method)) + (note-key-arg-mismatch name lossages)) + ((cdr lossages) + (note-lossage "~@<~{~S~^, ~} and ~S are not a known argument keywords.~:@>" + (butlast lossages) + (car (last lossages)))) + (t + (note-lossage "~S is not a known argument keyword." + (car lossages))))) unknown-keys)) ;;; Construct a function type from a definition. ;;; ;;; Due to the lack of a (LIST X) type specifier, we can't reconstruct ;;; the &REST type. -(declaim (ftype (sfunction (functional) fun-type) definition-type)) (defun definition-type (functional) + (declare (type functional functional) + #-sb-xc-host (values fun-type)) (if (lambda-p functional) (make-fun-type :required (mapcar #'leaf-type (lambda-vars functional)) @@ -392,10 +403,10 @@ and no value was provided for it." name)))))))))) (defstruct (approximate-fun-type (:copier nil)) ;; the smallest and largest numbers of arguments that this function ;; has been called with. - (min-args sb-xc:call-arguments-limit - :type (integer 0 #.sb-xc:call-arguments-limit)) + (min-args call-arguments-limit + :type (integer 0 #.call-arguments-limit)) (max-args 0 - :type (integer 0 #.sb-xc:call-arguments-limit)) + :type (integer 0 #.call-arguments-limit)) ;; a list of lists of the all the types that have been used in each ;; argument position (types () :type list) @@ -413,7 +424,7 @@ and no value was provided for it." name)))))))))) ;; The position at which this keyword appeared. 0 if it appeared as the ;; first argument, etc. (position (missing-arg) - :type (integer 0 #.sb-xc:call-arguments-limit)) + :type (integer 0 #.call-arguments-limit)) ;; a list of all the argument types that have been used with this keyword (types nil :type list) ;; true if this keyword has appeared only in calls with an obvious @@ -423,11 +434,11 @@ and no value was provided for it." name)))))))))) ;;; Return an APPROXIMATE-FUN-TYPE representing the context of ;;; CALL. If TYPE is supplied and not null, then we merge the ;;; information into the information already accumulated in TYPE. -(declaim (ftype (function (combination - &optional (or approximate-fun-type null)) - approximate-fun-type) - note-fun-use)) (defun note-fun-use (call &optional type) + (declare (type combination call) + (type (or approximate-fun-type null) type) + #-sb-xc-host + (values approximate-fun-type)) (let* ((type (or type (make-approximate-fun-type))) (types (approximate-fun-type-types type)) (args (combination-args call)) @@ -488,16 +499,17 @@ and no value was provided for it." name)))))))))) ;;; This is similar to VALID-FUN-USE, but checks an ;;; APPROXIMATE-FUN-TYPE against a real function type. -(declaim (ftype (function (approximate-fun-type fun-type - &optional function function function) - (values boolean boolean)) - valid-approximate-type)) (defun valid-approximate-type (call-type type &optional (*ctype-test-fun* #'types-equal-or-intersect) (*lossage-fun* #'compiler-style-warn) (*unwinnage-fun* #'compiler-notify)) + (declare (type approximate-fun-type call-type) + (type fun-type type) + (function *ctype-test-fun* *lossage-fun* *unwinnage-fun*) + #-sb-xc-host + (values boolean boolean)) (let* ((*lossage-detected* nil) (*unwinnage-detected* nil) (required (fun-type-required type)) @@ -541,10 +553,10 @@ and no value was provided for it." name)))))))))) ;;; Check that each of the types used at each arg position is ;;; compatible with the actual type. -(declaim (ftype (function (approximate-fun-type list (or ctype null)) - (values)) - check-approximate-fixed-and-rest)) (defun check-approximate-fixed-and-rest (call-type fixed rest) + (declare (type approximate-fun-type call-type) + (list fixed) + (type (or ctype null) rest)) (do ((types (approximate-fun-type-types call-type) (cdr types)) (n 1 (1+ n)) (arg fixed (cdr arg))) @@ -556,9 +568,8 @@ and no value was provided for it." name)))))))))) ;;; Check that each of the call-types is compatible with DECL-TYPE, ;;; complaining if not or if we can't tell. -(declaim (ftype (function (list ctype string &rest t) (values)) - check-approximate-arg-type)) (defun check-approximate-arg-type (call-types decl-type context &rest args) + (declare (list call-types) (type ctype decl-type) (string context)) (when *ctype-test-fun* (let ((losers *empty-type*)) (dolist (ctype call-types) @@ -647,20 +658,10 @@ and no value was provided for it." name)))))))))) ;;; defaults. Returning the actual vars allows us to use the right ;;; variable name in warnings. ;;; -;;; A slightly subtle point: with keywords and optionals, the type in -;;; the function type is only an assertion on calls --- it doesn't -;;; constrain the type of default values. So we have to union in the -;;; type of the default. With optionals, we can't do any assertion -;;; unless the default is constant. -;;; -;;; With keywords, we exploit our knowledge about how hairy keyword -;;; defaulting is done when computing the type assertion to put on the -;;; main-entry argument. In the case of hairy keywords, the default -;;; has been clobbered with NIL, which is the value of the main-entry -;;; arg in the unsupplied case, whatever the actual default value is. -;;; So we can just assume the default is constant, effectively -;;; unioning in NULL, and not totally blow off doing any type -;;; assertion. +;; Despite FTYPE proclamations affecting only the calls and not the +;; function itself, it would be very weird to see a default of &key or +;; &optional be different from the proclaimed type. Accept NULL only +;; when there's no default form. (defun find-optional-dispatch-types (od type where) (declare (type optional-dispatch od) (type fun-type type) @@ -711,47 +712,50 @@ and no value was provided for it." name)))))))))) (arglist (optional-dispatch-arglist od))) (dolist (arg arglist) (cond - ((lambda-var-arg-info arg) - (let* ((info (lambda-var-arg-info arg)) - (default (arg-info-default info)) - (def-type (when (sb-xc:constantp default) - (ctype-of (constant-form-value default))))) - (ecase (arg-info-kind info) - (:keyword - (let* ((key (arg-info-key info)) - (kinfo (find key keys :key #'key-info-name))) - (cond - (kinfo - (res (type-union (key-info-type kinfo) - (or def-type (specifier-type 'null))))) - (t - (note-lossage - "Defining a ~S keyword not present in ~A." - key where) - (res *universal-type*))))) - (:required (res (pop type-required))) - (:optional - ;; We can exhaust TYPE-OPTIONAL when the type was - ;; simplified as described above. - (res (type-union (or (pop type-optional) - *universal-type*) - (or def-type *universal-type*)))) - (:rest - (when (fun-type-rest type) - (res (specifier-type 'list)))) - (:more-context - (when (fun-type-rest type) - (res *universal-type*))) - (:more-count - (when (fun-type-rest type) - (res (specifier-type 'fixnum))))) - (vars arg) - (when (arg-info-supplied-p info) - (res *universal-type*) - (vars (arg-info-supplied-p info))))) - (t - (res (pop type-required)) - (vars arg)))) + ((lambda-var-arg-info arg) + (let* ((info (lambda-var-arg-info arg)) + (default-p (arg-info-default-p info))) + (ecase (arg-info-kind info) + (:keyword + (let* ((key (arg-info-key info)) + (kinfo (find key keys :key #'key-info-name))) + (cond + (kinfo + (res (if default-p + (key-info-type kinfo) + (type-union (key-info-type kinfo) + (specifier-type 'null))))) + (t + (note-lossage + "Defining a ~S keyword not present in ~A." + key where) + (res *universal-type*))))) + (:required (res (pop type-required))) + (:optional + ;; We can exhaust TYPE-OPTIONAL when the type was + ;; simplified as described above. + (res (let ((type (or (pop type-optional) + *universal-type*))) + (if default-p + type + (type-union type + (specifier-type 'null)))))) + (:rest + (when (fun-type-rest type) + (res (specifier-type 'list)))) + (:more-context + (when (fun-type-rest type) + (res *universal-type*))) + (:more-count + (when (fun-type-rest type) + (res (specifier-type 'fixnum))))) + (vars arg) + (when (arg-info-supplied-p info) + (res *universal-type*) + (vars (arg-info-supplied-p info))))) + (t + (res (pop type-required)) + (vars arg)))) (dolist (key keys) (unless (find (key-info-name key) arglist @@ -1143,7 +1147,8 @@ and no value was provided for it." name)))))))))) ((eq cast-context :ftype) (warn condition :format-control - "~@<Derived type of ~S is ~2I~_~S, ~ + "~@<Derived type of ~/sb-impl:print-type-specifier/ is ~ + ~2I~_~/sb-impl:print-type-specifier/, ~ ~I~_conflicting with the declared function return type ~ ~2I~_~/sb-impl:print-type-specifier/.~@:>" :format-arguments (list detail dtype atype))) @@ -1158,7 +1163,8 @@ and no value was provided for it." name)))))))))) :format-arguments (list (constant-form-value detail) atype)) (warn condition :format-control - "~@<Derived type of ~S is ~2I~_~S, ~ + "~@<Derived type of ~/sb-impl:print-type-specifier/ is ~ + ~2I~_~/sb-impl:print-type-specifier/, ~ ~I~_conflicting with its asserted type ~ ~2I~_~/sb-impl:print-type-specifier/.~@:>" :format-arguments (list detail dtype atype))))) @@ -1172,30 +1178,3 @@ and no value was provided for it." name)))))))))) ~2I~_~/sb-impl:print-type-specifier/.~@:>" :format-arguments (list (rest detail) (first detail) dtype atype)))))) - - -(defoptimizer (%compile-time-type-error ir2-convert) - ((objects atype dtype detail code-context cast-context) node block) - (declare (ignore objects code-context)) - ;; Remove %COMPILE-TIME-TYPE-ERROR bits - (setf (node-source-path node) - (cdr (node-source-path node))) - (%compile-time-type-error-warn node - (lvar-value atype) - (lvar-value dtype) - (lvar-value detail) - :cast-context (lvar-value cast-context)) - (ir2-convert-full-call node block)) - -(defoptimizer (%compile-time-type-style-warn ir2-convert) - ((objects atype dtype detail code-context cast-context) node block) - (declare (ignore objects code-context block)) - ;; Remove %COMPILE-TIME-TYPE-ERROR bits - (setf (node-source-path node) - (cddr (node-source-path node))) - (%compile-time-type-error-warn node - (lvar-value atype) - (lvar-value dtype) - (lvar-value detail) - :cast-context (lvar-value cast-context) - :condition 'type-style-warning)) diff --git a/src/compiler/dce.lisp b/src/compiler/dce.lisp index cbd9e0d048..282ed712a6 100644 --- a/src/compiler/dce.lisp +++ b/src/compiler/dce.lisp @@ -9,7 +9,7 @@ ;;; A CLAMBDA is deemed to be "externally referenced" if: ;;; - It is of KIND :TOPLEVEL (a toplevel CLAMBDA). ;;; - It is LAMBDA-HAS-EXTERNAL-REFERENCES-P true (from COMPILE -;;; or from the fopcompiler, possibly other causes). +;;; or possibly other causes). ;;; - It has a REF which has a NODE-COMPONENT other than the ;;; LAMBDA-COMPONENT of the CLAMBDA. ;;; diff --git a/src/compiler/debug-dump.lisp b/src/compiler/debug-dump.lisp index 6bc69775b4..068735d014 100644 --- a/src/compiler/debug-dump.lisp +++ b/src/compiler/debug-dump.lisp @@ -17,7 +17,8 @@ (declaim (type byte-buffer *byte-buffer*)) (defvar *contexts*) (declaim (type (vector t) *contexts*)) - +(defvar *local-call-context*) +(defvar *location-context* nil) ;;;; debug blocks @@ -43,6 +44,7 @@ (:copier nil)) (label nil :type (or null label)) (tn nil :type (or null tn) :read-only t)) +(!set-load-form-method restart-location (:xc :target) :ignore-it) ;;; This is called during code generation in places where there is an ;;; "interesting" location: someplace where we are likely to end up @@ -77,10 +79,10 @@ (- posn (segment-header-skew segment)))))) (values)) -#-sb-fluid (declaim (inline ir2-block-physenv)) -(defun ir2-block-physenv (2block) +(declaim (inline ir2-block-environment)) +(defun ir2-block-environment (2block) (declare (type ir2-block 2block)) - (block-physenv (ir2-block-block 2block))) + (block-environment (ir2-block-block 2block))) (defun make-lexenv-var-cache (lexenv) (or (lexenv-var-cache lexenv) @@ -104,6 +106,37 @@ (defun leaf-visible-to-debugger-p (leaf node) (gethash leaf (make-lexenv-var-cache (node-lexenv node)))) +(defun optional-leaf-p (leaf) + (let ((home (lambda-var-home leaf))) + (case (functional-kind home) + (:external + (let ((entry (lambda-entry-fun home))) + (when (optional-dispatch-p entry) + (let ((pos (position leaf (lambda-vars home)))) + (and pos + (>= (1- pos) (optional-dispatch-min-args entry)))))))))) + +;;; Type checks of the arguments in an external function happen before +;;; all the &optionals are initialized. PROPAGATE-TO-ARGS marks such +;;; locations with the entry point, which allows to deduce if an +;;; optional is alive at that point. +(defun optional-processed (leaf) + (let ((home (lambda-var-home leaf))) + (case (functional-kind home) + (:external + (let ((entry (lambda-entry-fun home))) + (if (and (optional-dispatch-p entry) + *local-call-context*) + (let ((pos (position leaf (lambda-vars home))) + (entry-pos (position *local-call-context* + (optional-dispatch-entry-points entry) + :key #'force))) + (not (and pos + entry-pos + (>= (1- pos) (+ (optional-dispatch-min-args entry) entry-pos))))) + t))) + (t t)))) + ;;; Given a local conflicts vector and an IR2 block to represent the ;;; set of live TNs, and the VAR-LOCS hash-table representing the ;;; variables dumped, compute a bit-vector representing the set of @@ -126,9 +159,11 @@ '(:environment :debug-environment))) (leaf-visible-to-debugger-p leaf node)) (or (null spilled) - (not (member tn spilled)))) + (not (member tn spilled))) + (optional-processed leaf)) (let ((num (gethash leaf var-locs))) (when num + (setf (sbit res num) 1)))))) res)) @@ -163,16 +198,22 @@ ;;; the code/source map and live info. If true, VOP is the VOP ;;; associated with this location, for use in determining whether TNs ;;; are spilled. -(defun dump-1-location (node block kind label live var-locs vop +(defun dump-1-location (node block kind tlf-num label live var-locs vop &optional context) (declare (type node node) (type ir2-block block) (type (or null local-tn-bit-vector) live) (type (or label index) label) - (type location-kind kind) + (type location-kind kind) (type (or index null) tlf-num) (type hash-table var-locs) (type (or vop null) vop)) (let* ((byte-buffer *byte-buffer*) (stepping (and (combination-p node) (combination-step-info node))) + (*local-call-context* + (if (local-call-context-p context) + (local-call-context-fun context))) + (context (if (local-call-context-p context) + (local-call-context-var context) + context)) (live (and live (compute-live-vars live node block var-locs vop))) (anything-alive (and live @@ -215,6 +256,8 @@ (write-var-integer (- loc *previous-location*) byte-buffer) (setq *previous-location* loc) + (unless tlf-num + (write-var-integer (source-path-tlf-number path) byte-buffer)) (unless (zerop form-number) (setf *previous-form-number* form-number) (write-var-integer form-number byte-buffer)) @@ -234,13 +277,14 @@ ;;; Extract context info from a Location-Info structure and use it to ;;; dump a compiled code-location. -(defun dump-location-from-info (loc var-locs) - (declare (type location-info loc) +(defun dump-location-from-info (loc tlf-num var-locs) + (declare (type location-info loc) (type (or index null) tlf-num) (type hash-table var-locs)) (let ((vop (location-info-vop loc))) (dump-1-location (vop-node vop) (vop-block vop) (location-info-kind loc) + tlf-num (location-info-label loc) (vop-save-set vop) var-locs @@ -248,21 +292,44 @@ (location-info-context loc))) (values)) +;;; Scan all the blocks, determining if all locations are in the same +;;; TLF, and returning it or NIL. +(defun find-tlf-number (fun) + (declare (type clambda fun)) + (let ((res (source-path-tlf-number (node-source-path (lambda-bind fun))))) + (declare (type (or index null) res)) + (do-environment-ir2-blocks (2block (lambda-environment fun)) + (let ((block (ir2-block-block 2block))) + (when (eq (block-info block) 2block) + (unless (eql (source-path-tlf-number + (node-source-path + (block-start-node block))) + res) + (setq res nil))) + + (dolist (loc (ir2-block-locations 2block)) + (unless (eql (source-path-tlf-number + (node-source-path + (vop-node (location-info-vop loc)))) + res) + (setq res nil))))) + res)) + ;;; Dump out the number of locations and the locations for Block. -(defun dump-block-locations (block locations var-locs) +(defun dump-block-locations (block locations tlf-num var-locs) (declare (type cblock block) (list locations)) (unless (and locations (eq (location-info-kind (first locations)) :non-local-entry)) (let ((2block (block-info block))) (dump-1-location (block-start-node block) - 2block :block-start + 2block :block-start tlf-num (ir2-block-%label 2block) (ir2-block-live-out 2block) var-locs nil))) (dolist (loc locations) - (dump-location-from-info loc var-locs)) + (dump-location-from-info loc tlf-num var-locs)) (values)) ;;; Return a vector and an integer (or null) suitable for use as the @@ -272,18 +339,19 @@ (let ((*previous-location* 0) *previous-live* *previous-form-number* - (physenv (lambda-physenv fun)) + (tlf-num (find-tlf-number fun)) + (env (lambda-environment fun)) (byte-buffer *byte-buffer*) prev-block locations elsewhere-locations) (setf (fill-pointer byte-buffer) 0) - (do-physenv-ir2-blocks (2block physenv) + (do-environment-ir2-blocks (2block env) (let ((block (ir2-block-block 2block))) (when (eq (block-info block) 2block) (when prev-block (dump-block-locations prev-block (nreverse (shiftf locations nil)) - var-locs)) + tlf-num var-locs)) (setf prev-block block))) (dolist (loc (ir2-block-locations 2block)) (if (label-elsewhere-p (location-info-label loc) @@ -291,13 +359,15 @@ (push loc elsewhere-locations) (push loc locations)))) - (dump-block-locations prev-block (nreverse locations) var-locs) + (dump-block-locations prev-block (nreverse locations) + tlf-num var-locs) (when elsewhere-locations (dolist (loc (nreverse elsewhere-locations)) - (dump-location-from-info loc var-locs))) + (dump-location-from-info loc tlf-num var-locs))) ;; lz-compress accept any array of octets and returns a simple-array - (logically-readonlyize (lz-compress byte-buffer)))) + (values (logically-readonlyize (lz-compress byte-buffer)) + tlf-num))) ;;; Return DEBUG-SOURCE structure containing information derived from ;;; INFO. @@ -305,19 +375,21 @@ (declare (type source-info info)) (let ((file-info (get-toplevelish-file-info info))) (multiple-value-call - (if function #'sb-c::make-core-debug-source #'make-debug-source) + (if function 'sb-di::make-core-debug-source 'make-debug-source) :namestring (or *source-namestring* (make-file-info-namestring (let ((pathname (case *name-context-file-path-selector* - (pathname (file-info-untruename file-info)) - (truename (file-info-name file-info))))) + (pathname (file-info-pathname file-info)) + (truename (file-info-truename file-info))))) (if (pathnamep pathname) pathname)) file-info)) - :created (file-info-write-date file-info) + :created (file-info-write-date file-info) + :start-positions (coerce-to-smallest-eltype + (file-info-positions file-info)) (if function (values :form (let ((direct-file-info (source-info-file-info info))) - (when (eq :lisp (file-info-name direct-file-info)) + (when (eq :lisp (file-info-truename direct-file-info)) (elt (file-info-forms direct-file-info) 0))) :function function) (values))))) @@ -365,12 +437,12 @@ (if (zerop length) #() (logically-readonlyize - (sb-xc:coerce seq - `(simple-array - ,(smallest-element-type (max max-positive - (1- max-negative)) - (plusp max-negative)) - 1))))))) + (coerce seq + `(simple-array + ,(smallest-element-type (max max-positive + (1- max-negative)) + (plusp max-negative)) + 1))))))) (defun compact-vector (sequence) (cond ((and (= (length sequence) 1) @@ -405,12 +477,12 @@ (info (lambda-var-arg-info var)) (indirect (and (lambda-var-indirect var) (not (lambda-var-explicit-value-cell var)) - (neq (lambda-physenv fun) - (lambda-physenv (lambda-var-home var))))) + (neq (lambda-environment fun) + (lambda-environment (lambda-var-home var))))) ;; Keep this condition in sync with PARSE-COMPILED-DEBUG-VARS - (large-fixnums (>= (integer-length sb-xc:most-positive-fixnum) 62)) + (large-fixnums (>= (integer-length most-positive-fixnum) 62)) more) - (declare (type index flags)) + (declare (type (and sb-xc:fixnum unsigned-byte) flags)) (when minimal (setq flags (logior flags compiled-debug-var-minimal-p)) (unless (and tn (tn-offset tn)) @@ -421,7 +493,8 @@ (not (gethash tn (ir2-component-spilled-tns (component-info *component-being-compiled*)))) (lexenv-contains-lambda fun - (lambda-lexenv (lambda-var-home var)))) + (lambda-lexenv (lambda-var-home var))) + (not (optional-leaf-p var))) ;; not always initialized (setq flags (logior flags compiled-debug-var-environment-live))) (when save-tn (setq flags (logior flags compiled-debug-var-save-loc-p))) @@ -509,7 +582,7 @@ (frob-leaf leaf (leaf-info leaf) gensym-p)))) (frob-lambda fun t) (when (>= level 1) - (dolist (x (ir2-physenv-closure (physenv-info (lambda-physenv fun)))) + (dolist (x (ir2-environment-closure (environment-info (lambda-environment fun)))) (let ((thing (car x))) (when (lambda-var-p thing) (frob-leaf thing (cdr x) (>= level 2))))) @@ -619,7 +692,7 @@ ;;; Return a C-D-F structure with all the mandatory slots filled in. (defun dfun-from-fun (fun) (declare (type clambda fun)) - (let* ((2env (physenv-info (lambda-physenv fun))) + (let* ((2env (environment-info (lambda-environment fun))) (dispatch (lambda-optional-dispatch fun)) (main-p (and dispatch (eq fun (optional-dispatch-main-entry dispatch)))) @@ -642,26 +715,26 @@ (funcall (compiled-debug-fun-ctor kind) :name name #-fp-and-pc-standard-save :return-pc - #-fp-and-pc-standard-save (tn-sc+offset (ir2-physenv-return-pc 2env)) + #-fp-and-pc-standard-save (tn-sc+offset (ir2-environment-return-pc 2env)) #-fp-and-pc-standard-save :return-pc-pass - #-fp-and-pc-standard-save (tn-sc+offset (ir2-physenv-return-pc-pass 2env)) + #-fp-and-pc-standard-save (tn-sc+offset (ir2-environment-return-pc-pass 2env)) #-fp-and-pc-standard-save :old-fp - #-fp-and-pc-standard-save (tn-sc+offset (ir2-physenv-old-fp 2env)) + #-fp-and-pc-standard-save (tn-sc+offset (ir2-environment-old-fp 2env)) :encoded-locs (cdf-encode-locs - (label-position (ir2-physenv-environment-start 2env)) - (label-position (ir2-physenv-elsewhere-start 2env)) + (label-position (ir2-environment-environment-start 2env)) + (label-position (ir2-environment-elsewhere-start 2env)) (source-path-form-number (node-source-path (lambda-bind fun))) (label-position (block-label (lambda-block fun))) - (when (ir2-physenv-closure-save-tn 2env) - (tn-sc+offset (ir2-physenv-closure-save-tn 2env))) + (when (ir2-environment-closure-save-tn 2env) + (tn-sc+offset (ir2-environment-closure-save-tn 2env))) #+unwind-to-frame-and-call-vop - (when (ir2-physenv-bsp-save-tn 2env) - (tn-sc+offset (ir2-physenv-bsp-save-tn 2env))) + (when (ir2-environment-bsp-save-tn 2env) + (tn-sc+offset (ir2-environment-bsp-save-tn 2env))) #-fp-and-pc-standard-save - (label-position (ir2-physenv-lra-saved-pc 2env)) + (label-position (ir2-environment-lra-saved-pc 2env)) #-fp-and-pc-standard-save - (label-position (ir2-physenv-cfp-saved-pc 2env)))))) + (label-position (ir2-environment-cfp-saved-pc 2env)))))) ;;; Return a complete C-D-F structure for FUN. This involves ;;; determining the DEBUG-INFO level and filling in optional slots as @@ -687,9 +760,13 @@ (compute-vars fun level var-locs)) (setf (compiled-debug-fun-arguments dfun) (compute-args fun var-locs)))) - (when (>= level 1) - (setf (compiled-debug-fun-blocks dfun) - (compute-debug-blocks fun var-locs))) + + (if (>= level 1) + (multiple-value-bind (blocks tlf-num) + (compute-debug-blocks fun var-locs) + (setf (compiled-debug-fun-blocks dfun) blocks + (compiled-debug-fun-tlf-number dfun) tlf-num)) + (setf (compiled-debug-fun-tlf-number dfun) (find-tlf-number fun))) (if (xep-p fun) (setf (compiled-debug-fun-returns dfun) :standard) (let ((info (tail-set-info (lambda-tail-set fun)))) @@ -720,8 +797,8 @@ (eq start (ir2-block-last-vop 2block)) (eq (vop-name start) 'note-environment-start) next - (neq (ir2-block-physenv 2block) - (ir2-block-physenv next))))) + (neq (ir2-block-environment 2block) + (ir2-block-environment next))))) ;;; Return a DEBUG-INFO structure describing COMPONENT. This has to be ;;; called after assembly so that source map information is available. @@ -735,18 +812,12 @@ :adjustable t)) (*contexts* (make-array 10 :fill-pointer 0 - :adjustable t)) - component-tlf-num) + :adjustable t))) (dolist (lambda (component-lambdas component)) (unless (empty-fun-p lambda) - (clrhash var-locs) - (let ((tlf-num (source-path-tlf-number - (node-source-path (lambda-bind lambda))))) - (if component-tlf-num - (aver (or (block-compile *compilation*) - (= component-tlf-num tlf-num))) - (setf component-tlf-num tlf-num)) - (push (compute-1-debug-fun lambda var-locs) dfuns)))) + (clrhash var-locs) + (push (compute-1-debug-fun lambda var-locs) + dfuns))) (let* ((sorted (sort dfuns #'< :key #'compiled-debug-fun-offset)) (fun-map (compute-debug-fun-map sorted))) (make-compiled-debug-info @@ -760,12 +831,6 @@ (sb-c::entry-info-name (car entries))) (component-name component))) :fun-map fun-map - :tlf-num+offset (pack-tlf-num+offset - component-tlf-num - (and component-tlf-num - (aref (file-info-positions - (source-info-file-info *source-info*)) - component-tlf-num))) :contexts (compact-vector *contexts*))))) ;;; Write BITS out to BYTE-BUFFER in backend byte order. The length of diff --git a/src/compiler/debug.lisp b/src/compiler/debug.lisp index 92f05ab5fd..d400d3d6c6 100644 --- a/src/compiler/debug.lisp +++ b/src/compiler/debug.lisp @@ -69,6 +69,7 @@ (unless (or (eq block tail) (eq (block-component block) c)) (barf "~S is not in ~S." block c))) + #+(or) (let ((component-outer-loop (component-outer-loop c))) (when (or (loop-blocks component-outer-loop) (loop-inferiors component-outer-loop)) @@ -107,7 +108,7 @@ (barf "strange CONSTANTS entry: ~S" v)) (dolist (n (leaf-refs v)) (check-node-reached n))) - (eq-constants ns)) + (eql-constants ns)) (maphash (lambda (k v) (declare (ignore k)) @@ -498,6 +499,11 @@ (dolist (exit (entry-exits node)) (unless (node-deleted exit) (check-node-reached node)))) + (enclose + (dolist (fun (enclose-funs node)) + (let ((enclose (functional-enclose fun))) + (unless (eq node enclose) + (barf "~S is not the ENCLOSE for its FUN ~S." node enclose))))) (exit (let ((entry (exit-entry node)) (value (exit-value node))) @@ -756,14 +762,8 @@ (defun check-block-conflicts (component) (do-ir2-blocks (block component) (do ((conf (ir2-block-global-tns block) - (global-conflicts-next-blockwise conf)) - (prev nil conf)) + (global-conflicts-next-blockwise conf))) ((null conf)) - (when prev - (unless (> (tn-number (global-conflicts-tn conf)) - (tn-number (global-conflicts-tn prev))) - (barf "~S and ~S out of order in ~S" prev conf block))) - (unless (find-in #'global-conflicts-next-tnwise conf (tn-global-conflicts @@ -785,13 +785,13 @@ ;;; TNs to access the full call passing locations. (defun check-environment-lifetimes (component) (dolist (fun (component-lambdas component)) - (let* ((env (lambda-physenv fun)) - (2env (physenv-info env)) + (let* ((env (lambda-environment fun)) + (2env (environment-info env)) (vars (lambda-vars fun)) - (closure (ir2-physenv-closure 2env)) - (pc (ir2-physenv-return-pc-pass 2env)) - (fp (ir2-physenv-old-fp 2env)) - (2block (block-info (lambda-block (physenv-lambda env))))) + (closure (ir2-environment-closure 2env)) + (pc (ir2-environment-return-pc-pass 2env)) + (fp (ir2-environment-old-fp 2env)) + (2block (block-info (lambda-block (environment-lambda env))))) (do ((conf (ir2-block-global-tns 2block) (global-conflicts-next-blockwise conf))) ((null conf)) @@ -920,14 +920,19 @@ (constant (format stream "'~S" (constant-value leaf))) (global-var (format stream "~S {~A}" (leaf-debug-name leaf) (global-var-kind leaf))) + (clambda + (format stream "lambda ~@[~S ~]~:S" + (and (leaf-has-source-name-p leaf) + (functional-debug-name leaf)) + (mapcar #'leaf-debug-name (lambda-vars leaf)))) + (optional-dispatch + (format stream "optional-dispatch ~S" (mapcar #'leaf-debug-name (optional-dispatch-arglist leaf)))) (functional - (format stream "~S ~S ~S" (type-of leaf) (functional-debug-name leaf) - (mapcar #'leaf-debug-name - (typecase leaf - (clambda - (lambda-vars leaf)) - (optional-dispatch - (optional-dispatch-arglist leaf)))))))) + (case (functional-kind leaf) + (:toplevel-xep + (format stream "TL-XEP ~S" (entry-info-name (leaf-info leaf)))) + (t + (format stream "~S ~S" (type-of leaf) (functional-debug-name leaf))))))) ;;; Attempt to find a block given some thing that has to do with it. (declaim (ftype (sfunction (t) cblock) block-or-lose)) @@ -940,7 +945,7 @@ (ctran (ctran-block thing)) (node (node-block thing)) (component (component-head thing)) -#| (cloop (loop-head thing))|# + (cloop (loop-head thing)) (integer (ctran-block (num-cont thing))) (functional (lambda-block (main-entry thing))) (null (error "Bad thing: ~S." thing)) @@ -953,7 +958,11 @@ (values)) (defun print-lvar (cont) (declare (type lvar cont)) - (format t "v~D " (cont-num cont)) + (if (and (lvar-info cont) + (eq (ir2-lvar-kind (lvar-info cont)) + :unknown)) + (format t "uv~D " (cont-num cont)) + (format t "v~D " (cont-num cont))) (values)) (defun print-lvar-stack (stack &optional (stream *standard-output*)) @@ -961,6 +970,8 @@ do (format stream "~:[u~;d~]v~D~@[ ~]" (lvar-dynamic-extent lvar) (cont-num lvar) rest))) +(defvar *debug-print-types* nil) + ;;; Print out the nodes in BLOCK in a format oriented toward ;;; representing what the code does. (defun print-nodes (block) @@ -1024,11 +1035,15 @@ ((:dynamic-extent) (format t "entry DX~{ v~D~}" (mapcar (lambda (lvar-or-cell) - (if (consp lvar-or-cell) - (cons (car lvar-or-cell) - (cont-num (cdr lvar-or-cell))) - (cont-num lvar-or-cell))) - (cleanup-info cleanup)))) + (typecase lvar-or-cell + (cons + (cons (car lvar-or-cell) + (cont-num (cdr lvar-or-cell)))) + (enclose + lvar-or-cell) + (t + (cont-num lvar-or-cell)))) + (cleanup-nlx-info cleanup)))) (t (format t "entry ~S" (entry-exits node)))))) (exit @@ -1040,14 +1055,24 @@ (format t "exit <no value>")) (t (format t "exit <degenerate>"))))) + (delay + (write-string "delay ") + (print-lvar (delay-value node))) (cast (let ((value (cast-value node))) (format t "cast v~D ~A[~S -> ~S]" (cont-num value) (if (cast-%type-check node) #\+ #\-) (cast-type-to-check node) (cast-asserted-type node)))) - (no-op - (princ "no-op"))) + (enclose + (write-string "enclose ") + (dolist (leaf (enclose-funs node)) + (print-leaf leaf) + (write-char #\space)))) + (when (and *debug-print-types* + (valued-node-p node)) + (write-char #\space) + (princ (type-specifier (node-derived-type node)))) (pprint-newline :mandatory))) (awhen (block-info block) @@ -1073,7 +1098,13 @@ (format stream "t~D" (tn-id tn)))) (when (and (tn-sc tn) (tn-offset tn)) (format stream "[~A]" (location-print-name tn))) - (format stream " ~s" (tn-kind tn)))) + (format stream " ~s~@[ ~a~]~@[ ~a~]" (tn-kind tn) + (and *debug-print-types* + (and (tn-sc tn) + (sc-name (tn-sc tn)))) + (and *debug-print-types* + (and (tn-primitive-type tn) + (primitive-type-name (tn-primitive-type tn))))))) ;;; Print the TN-REFs representing some operands to a VOP, linked by ;;; TN-REF-ACROSS. @@ -1084,6 +1115,7 @@ ((null ref)) (let ((tn (tn-ref-tn ref)) (ltn (tn-ref-load-tn ref))) + (awhen (tn-ref-memory-access ref) (format t "@~A" it)) (cond ((not ltn) (print-tn-guts tn)) (t @@ -1097,7 +1129,7 @@ ;;; necessary. (defun print-vop (vop) (pprint-logical-block (*standard-output* nil) - (princ (vop-info-name (vop-info vop))) + (princ (vop-name vop)) (princ #\space) (pprint-indent :current 0) (print-operands (vop-args vop)) @@ -1107,14 +1139,14 @@ (multiway-branch-if-eq (princ (vop-codegen-info vop))) (t - (princ (with-simple-output-to-string (stream) + (princ (%with-output-to-string (stream) ;; Current print depth varies based on whether PRINT-VOP ;; is called by DESCRIBE-IR2-COMPONENT or TRACE-INSTRUCTION, ;; so any fixed value of *PRINT-LEVEL* changes its effect ;; depending on the call context. Resetting depth to 0 seems ;; like the best way to get consistent output. ;; We shouldn't bind the printer limits to NIL, because - ;; hairy internal objects such as PHYSENV can be printed. + ;; hairy internal objects such as ENVIRONMENT can be printed. ;; See also the comment above FUNCALL-WITH-DEBUG-IO-SYNTAX. (let (#-sb-xc-host (*current-level-in-print* 0) (*print-level* 2) @@ -1295,31 +1327,101 @@ (vop (ir2-block-start-vop block) (vop-next vop))) ((= i n) vop)))) +(defun show-transform-p (showp fun-name) + (or (and (listp showp) (member fun-name showp :test 'equal)) + (eq showp t))) + +(defun show-transform (kind name new-form &optional combination) + (let ((*print-length* 100) + (*print-level* 50) + (*print-right-margin* 128)) + (format *trace-output* "~&xform (~a) ~S ~% -> ~S~%" + kind + (if combination + (cons name + (loop for arg in (combination-args combination) + collect (if (constant-lvar-p arg) + (lvar-value arg) + (type-specifier (lvar-type arg))))) + name) + new-form))) + +(defun show-type-derivation (combination type) + (let ((*print-length* 100) + (*print-level* 50) + (*print-right-margin* 128)) + (unless (type= (node-derived-type combination) + (coerce-to-values type)) + (format *trace-output* "~&~a derived to ~a" + (cons (combination-fun-source-name combination) + (loop for arg in (combination-args combination) + collect (if (constant-lvar-p arg) + (lvar-value arg) + (type-specifier (lvar-type arg))))) + (type-specifier type))))) + +;;;; producing a graphviz file + +(defun replace-all (string part replacement &key (test #'char=)) + "Returns a new string in which all the occurences of the part +is replaced with replacement." + (with-output-to-string (out) + (loop with part-length = (length part) + for old-pos = 0 then (+ pos part-length) + for pos = (search part string + :start2 old-pos + :test test) + do (write-string string out + :start old-pos + :end (or pos (length string))) + when pos do (write-string replacement out) + while pos))) + (defun ir1-to-dot (component output-file) (with-open-file (stream output-file :if-exists :supersede :if-does-not-exist :create :direction :output) (write-line "digraph G {" stream) - (do-blocks (block component) - (when (typep (block-out block) '(cons (eql :graph) cons)) - (format stream "~a[style=filled color=~a];~%" - (block-number block) - (case (cadr (block-out block)) - (:marked "green") - (:remarked "aquamarine") - (:start "lightblue") - (:end "red")))) - (let ((succ (block-pred block))) - (when succ - (loop for succ in succ - for attr = "[style=bold]" then "" - do - (format stream "~a -> ~a~a;~%" - (block-number block) - (block-number succ) - attr))) - (when (nle-block-p block) - (format stream "~a -> ~a [style=dotted];~%" - (block-number block) - (block-number (nle-block-entry-block block)))))) + (write-line "node [fontname = \"monospace\"];" stream) + (write-line "node [shape=box];" stream) + ;; Give a unique label to every block, since BLOCK-NUMBERs may be + ;; uninitialized during optimization. + (let ((label 0) + (block-labels (make-hash-table :test #'eq))) + (do-blocks (block component :both) + (setf (gethash block block-labels) label) + (incf label)) + (flet ((block-label (block) + (gethash block block-labels))) + (do-blocks (block component :both) + (cond ((eq block (component-head component)) + (format stream "~a [label=\"head of component ~a\"];" + (block-label block) + (component-name component))) + ((eq block (component-tail component)) + (format stream "~a [label=tail];" + (block-label block))) + (t + (format stream "~a [label=\"~a\"];~%" + (block-label block) + (replace-all + (replace-all (with-output-to-string (*standard-output*) + (print-nodes block)) + (string #\Newline) + "\\l") + "\"" + "\\")))) + (let ((succ (block-succ block))) + (when succ + (loop for succ in succ + for attr = "[style=bold]" then "" + do + (format stream "~a -> ~a~a;~%" + (block-label block) + (block-label succ) + attr))) + (when (nle-block-p block) + (format stream "~a -> ~a [style=dotted];~%" + (block-label block) + (block-label (nle-block-entry-block block)))))))) (write-line "}" stream))) diff --git a/src/compiler/deftype.lisp b/src/compiler/deftype.lisp index cd71f226c8..b3fe09d88f 100644 --- a/src/compiler/deftype.lisp +++ b/src/compiler/deftype.lisp @@ -9,10 +9,6 @@ (in-package "SB-IMPL") -;;; Has the type system been properly initialized? (I.e. is it OK to -;;; use it?) -(!define-load-time-global *type-system-initialized* nil) - (defun constant-type-expander (name expansion) (declare (optimize safety)) ;; Dummy implementation of SET-CLOSURE-NAME for the host. @@ -34,14 +30,14 @@ (defmacro sb-xc:deftype (name lambda-list &body body &environment env) "Define a new type, with syntax like DEFMACRO." (declare (ignore env)) - (check-designator name deftype) + (check-designator name 'deftype) (multiple-value-bind (expander-form doc source-location-form) (multiple-value-bind (forms decls doc) (parse-body body t) (acond ((and (not lambda-list) (not decls) (let ((expr `(progn ,@forms))) ;; While CONSTANTP works early, %MACROEXPAND does not, ;; so we can't pass ENV because it'd try to macroexpand. - (if (sb-xc:constantp expr) expr))) + (if (constantp expr) expr))) #-sb-xc-host (check-deprecated-type (constant-form-value it)) (values `(constant-type-expander ',name ,it) doc @@ -59,5 +55,46 @@ #+(and (not sb-doc) sb-xc-host) (setq doc nil) `(progn (eval-when (:compile-toplevel :load-toplevel :execute) - (%compiler-deftype ',name ,expander-form ,source-location-form - ,@(when doc `(,doc))))))) + (%deftype ',name ,expander-form ,source-location-form + ,@(when doc `(,doc))))))) + +(defun %deftype (name expander source-location &optional doc) + (declare (ignorable doc)) + (with-single-package-locked-error + (:symbol name "defining ~A as a type specifier")) + (ecase (info :type :kind name) + (:primitive + ;; Detecting illegal redefinition in the cross-compiler + ;; adds unnecessary complexity, so don't bother. + #-sb-xc-host + (when *type-system-initialized* + (error "illegal to redefine standard type: ~S" name))) + (:instance + (warn "The class ~S is being redefined to be a DEFTYPE." name) + (undeclare-structure (find-classoid name) t) + ;; FIXME: shouldn't this happen only at eval-time? + (setf (classoid-cell-classoid (find-classoid-cell name :create t)) nil) + (clear-info :type :compiler-layout name) + (setf (info :type :kind name) :defined)) + (:defined + ;; Note: It would be nice to warn here when a type is being + ;; incompatibly redefined, but it's hard to tell, since type + ;; expanders are often function objects which can't easily be + ;; compared for equivalence. And just warning on redefinition + ;; isn't good, since DEFTYPE necessarily does its thing once at + ;; compile time and again at load time, so that it's very common + ;; and normal for types to be defined twice. So since there + ;; doesn't seem to be anything simple and obvious to do, and + ;; since mistakenly redefining a type isn't a common error + ;; anyway, we just don't worry about trying to warn about it. + ) + ((nil :forthcoming-defclass-type) + (setf (info :type :kind name) :defined))) + (setf (info :type :expander name) expander) + (when source-location + (setf (info :type :source-location name) source-location)) + #-sb-xc-host + (when doc + (setf (documentation name 'type) doc)) + (sb-c::%note-type-defined name) + name) diff --git a/src/compiler/dfo.lisp b/src/compiler/dfo.lisp index 5adea3b994..92a573524a 100644 --- a/src/compiler/dfo.lisp +++ b/src/compiler/dfo.lisp @@ -92,18 +92,6 @@ (setf (block-flag block) t) (dolist (succ (block-succ block)) (find-dfo-aux succ head component)) - (when (component-nlx-info-generated-p component) - ;; FIXME: We also need (and do) this walk before physenv - ;; analysis, but at that time we are probably not very - ;; interested in the actual DF order. - ;; - ;; TODO: It is probable that one of successors have the same (or - ;; similar) set of NLXes; try to shorten the walk (but think - ;; about a loop, the only exit from which is non-local). - (map-block-nlxes (lambda (nlx-info) - (let ((nle (nlx-info-target nlx-info))) - (find-dfo-aux nle head component))) - block)) (remove-from-dfo block) (add-to-dfo block head)) (values)) @@ -200,10 +188,10 @@ ;;; If CLAMBDA is already in COMPONENT, just return that ;;; component. Otherwise, move the code for CLAMBDA and all lambdas it -;;; physically depends on (either because of calls or because of -;;; closure relationships) into COMPONENT, or possibly into another -;;; COMPONENT that we find to be related. Return whatever COMPONENT we -;;; actually merged into. +;;; depends on (either because of calls or because of closure +;;; relationships) into COMPONENT, or possibly into another COMPONENT +;;; that we find to be related. Return whatever COMPONENT we actually +;;; merged into. ;;; ;;; (Note: The analogous CMU CL code only scavenged call-based ;;; dependencies, not closure dependencies. That seems to've been by @@ -277,8 +265,8 @@ ;; CLAMBDA, then the home lambda should be in the ;; same component as CLAMBDA. (sbcl-0.6.13, and CMU ;; CL, didn't do this, leading to the occasional - ;; failure when physenv analysis, which is local to - ;; each component, would bogusly conclude that a + ;; failure when environment analysis, which is local + ;; to each component, would bogusly conclude that a ;; closed-over variable was unused and thus delete ;; it. See e.g. cmucl-imp 2001-11-29.) (scavenge-closure-var (var) @@ -315,9 +303,8 @@ ;;; resulting components. Components with a :TOPLEVEL lambda, but no ;;; normal XEPs or potential non-local exits are marked as :TOPLEVEL. ;;; If there is a :TOPLEVEL lambda, and also a normal XEP, then we -;;; treat the component as normal, but also return such components in -;;; a list as the third value. Components with no entry of any sort -;;; are deleted. +;;; treat the component as normal. Components with no entry of any +;;; sort are deleted. (defun separate-toplevelish-components (components) (declare (list components)) (collect ((non-top) @@ -356,55 +343,45 @@ (delete-component component)))))) (values (non-top) (top)))) -;;; Given a list of top level lambdas, return -;;; (VALUES NONTOP-COMPONENTS TOP-COMPONENTS): -;;; NONTOP-COMPONENTS = non-top-level-ish COMPONENTs; -;;; TOP-COMPONENTS = top-level-ish COMPONENTs; +;;; Given a list of top level lambdas, return two lists of components +;;; representing the actual component division. The first value is the +;;; non-top-level components, and the second is the top-level ones. ;;; ;;; We assign the DFO for each component, and delete any unreachable ;;; blocks. We assume that the FLAGS have already been cleared. -(defun find-initial-dfo (toplevel-lambdas) - (declare (list toplevel-lambdas)) +;;; +;;; We iterate over the lambdas in each initial component, trying +;;; to put each function in its own component, but joining it to +;;; an existing component if we find that there are references +;;; between them. Any code that is left in an initial component +;;; must be unreachable, so we can delete it. Stray links to the +;;; initial component tail (due to NIL function terminated blocks) +;;; are moved to the appropriate new component tail. +(defun find-initial-dfo (top-level-lambdas) + (declare (list top-level-lambdas)) (collect ((components)) - ;; We iterate over the lambdas in each initial component, trying - ;; to put each function in its own component, but joining it to - ;; an existing component if we find that there are references - ;; between them. Any code that is left in an initial component - ;; must be unreachable, so we can delete it. Stray links to the - ;; initial component tail (due to NIL function terminated blocks) - ;; are moved to the appropriate new component tail. - (dolist (toplevel-lambda toplevel-lambdas) - (let* ((old-component (lambda-component toplevel-lambda)) - (old-component-lambdas (component-lambdas old-component)) - (new-component nil)) - (aver (member toplevel-lambda old-component-lambdas)) - (dolist (component-lambda old-component-lambdas) - (aver (member (functional-kind component-lambda) - '(:optional :external :toplevel nil :escape - :cleanup))) - (unless new-component - (setf new-component (make-empty-component)) - (setf (component-name new-component) - ;; This isn't necessarily an ideal name for the - ;; component, since it might end up with multiple - ;; lambdas in it, not just this one, but it does - ;; seem a better name than just "<unknown>". - (leaf-debug-name component-lambda))) - (let ((res (dfo-scavenge-dependency-graph component-lambda - new-component))) - (when (eq res new-component) - (aver (not (position new-component (components)))) - (components new-component) - (setq new-component nil)))) - (when (eq (component-kind old-component) :initial) - (aver (null (component-lambdas old-component))) - (let ((tail (component-tail old-component))) + (let ((new (make-empty-component))) + (dolist (initial-component (mapcar #'lambda-component top-level-lambdas)) + (unless (eq (component-kind initial-component) :deleted) + (dolist (component-lambda (component-lambdas initial-component)) + (aver (member (functional-kind component-lambda) + '(:optional :external :toplevel nil :escape + :cleanup))) + (let ((res (dfo-scavenge-dependency-graph component-lambda + new))) + (when (eq res new) + (aver (not (member new (components)))) + (components new) + (setq new (make-empty-component))))) + (aver (eq (component-kind initial-component) :initial)) + (aver (null (component-lambdas initial-component))) + (let ((tail (component-tail initial-component))) (dolist (pred (block-pred tail)) (let ((pred-component (block-component pred))) - (unless (eq pred-component old-component) + (unless (eq pred-component initial-component) (unlink-blocks pred tail) (link-blocks pred (component-tail pred-component)))))) - (delete-component old-component)))) + (delete-component initial-component)))) ;; When we are done, we assign DFNs. (dolist (component (components)) @@ -424,7 +401,7 @@ (setf (functional-kind lambda) :deleted) (dolist (let (lambda-lets lambda)) (setf (lambda-home let) result-lambda) - (setf (lambda-physenv let) (lambda-physenv result-lambda)) + (setf (lambda-environment let) (lambda-environment result-lambda)) (push let (lambda-lets result-lambda))) (setf (lambda-entries result-lambda) (nconc (lambda-entries result-lambda) diff --git a/src/compiler/disassem.lisp b/src/compiler/disassem.lisp index 638621259b..175ac447a1 100644 --- a/src/compiler/disassem.lisp +++ b/src/compiler/disassem.lisp @@ -67,7 +67,6 @@ ;;;; KLUDGE: It's not clear that using bit-vectors would be any more efficient. ;;;; Perhaps the abstraction could go away. -- WHN 19991124 -#-sb-fluid (declaim (inline dchunk-or dchunk-and dchunk-clear dchunk-not dchunk-make-mask dchunk-make-field dchunk-extract @@ -241,7 +240,7 @@ (defmacro define-instruction-format ((format-name length-in-bits &key default-printer include) - &rest arg-specs) + &body arg-specs) #+sb-xc-host (declare (ignore default-printer)) "DEFINE-INSTRUCTION-FORMAT (Name Length {Format-Key Value}*) Arg-Def* Define an instruction format NAME for the disassembler's use. LENGTH is @@ -261,6 +260,8 @@ Each ARG-DEF defines one argument in the format, and is of the form (Arg-Name {Arg-Key Value}*) + If ARG-NAME is an integer it is the same as (#.(gensym) :value arg-name ...). + Possible ARG-KEYs (the values are evaluated unless otherwise specified): :FIELDS byte-spec-list @@ -343,16 +344,20 @@ (seen)) (dolist (arg-spec arg-specs) (let* ((arg-name (car arg-spec)) - (properties (cdr arg-spec)) - (cell (member arg-name args :key #'arg-name))) - (aver (not (memq arg-name seen))) - (push arg-name seen) - (cond ((not cell) - (setq args (nconc args (list (apply #'modify-arg (%make-arg arg-name) - length properties))))) - (properties - (rplaca cell (apply #'modify-arg (copy-structure (car cell)) - length properties)))))) + (properties (cdr arg-spec))) + (when (integerp arg-name) + (setf properties (list* :value arg-name + properties) + arg-name (gensym))) + (let ((cell (member arg-name args :key #'arg-name))) + (aver (not (memq arg-name seen))) + (push arg-name seen) + (cond ((not cell) + (setq args (nconc args (list (apply #'modify-arg (%make-arg arg-name) + length properties))))) + (properties + (rplaca cell (apply #'modify-arg (copy-structure (car cell)) + length properties))))))) (setf (get name 'inst-format) (make-inst-format name (bits-to-bytes length) printer args)))) @@ -559,7 +564,7 @@ `((lookup-label ,(maybe-listify numeric-forms))) numeric-forms))))) -#-sb-fluid (declaim (inline bytes-to-bits)) +(declaim (inline bytes-to-bits)) (defun bytes-to-bits (bytes) (declare (type disassem-length bytes)) diff --git a/src/compiler/dump.lisp b/src/compiler/dump.lisp index b5b2864776..5179a4c539 100644 --- a/src/compiler/dump.lisp +++ b/src/compiler/dump.lisp @@ -36,11 +36,19 @@ ;; can get them from the table rather than dumping them again. The ;; SIMILAR-TABLE is used for lists and strings, and the EQ-TABLE is ;; used for everything else. We use a separate EQ table to avoid - ;; performance pathologies with objects for which EQUAL degenerates - ;; to EQL. Everything entered in the SIMILAR table is also entered in - ;; the EQ table. - (similar-table (make-hash-table :test 'equal) :type hash-table) - (eq-table (make-hash-table :test 'eq) :type hash-table) + ;; performance pathologies with objects for which SIMILAR + ;; degenerates to EQL. Everything entered in the SIMILAR table is + ;; also entered in the EQ table. The NAMED-CONSTANT is used for + ;; named constants whose references are dumped as load time values + ;; of SYMBOL-GLOBAL-VALUE. + (similar-table (make-similarity-table) :type hash-table :read-only t) + (eq-table (make-hash-table :test 'eq) :type hash-table :read-only t) + ;; the INSTANCE table maps dumpable instances to unique IDs for calculating + ;; a similarity hash of composite objects that contain instances. + ;; A user-defined hash function can not use address-based hashing, and it is + ;; better not to add a new lazy stable hash slot to instances as a + ;; side-effect of compiling. + (instance-id-table (make-hash-table :test 'eq) :type hash-table :read-only t) ;; the CONS table is an additional EQ table, used for storing CDRs ;; of dumped lists which will not have their own direct identity as ;; a dumped constant, but which might nevertheless be EQ to some @@ -48,13 +56,13 @@ ;; The hash table entry, if present, is a reference to its parent ;; list object (which will have a direct entity as a dumped ;; constant) along with an index of how many CDRs to take. - (cons-table (make-hash-table :test 'eq) :type hash-table) + (cons-table (make-hash-table :test 'eq) :type hash-table :read-only t) ;; Hashtable mapping a string to a list of fop-table indices of ;; symbols whose name is that string. For any name as compared ;; by STRING= there can be a symbol whose name is a base string ;; and/or a symbol whose name is not a base string. (string=-table (make-hash-table :test 'equal) :type hash-table) - ;; the table's current free pointer: the next offset to be used + ;; the fasloader table's current free pointer: the next offset to be used (table-free 0 :type index) ;; an alist (PACKAGE . OFFSET) of the table offsets for each package ;; we have currently located. @@ -68,6 +76,10 @@ ;; is the offset in the table of the code object needing to be ;; patched, and <offset> is the offset that must be patched. (patch-table (make-hash-table :test 'eq) :type hash-table) + ;; a list of the table handles for all of the DEBUG-INFO structures + ;; dumped in this file. These structures must be back-patched with + ;; source location information when the compilation is complete. + (debug-info () :type list) ;; This is used to keep track of objects that we are in the process ;; of dumping so that circularities can be preserved. The key is the ;; object that we have previously seen, and the value is the object @@ -80,18 +92,137 @@ ;; a hash table of structures that are allowed to be dumped. If we ;; try to dump a structure that isn't in this hash table, we lose. (valid-structures (make-hash-table :test 'eq) :type hash-table) - ;; DEBUG-SOURCE written at the very beginning - (source-info nil :type (or null sb-c::debug-source))) + ;; a hash table of slots to be saved when dumping an instance. + (saved-slot-names (make-hash-table :test 'eq) :type hash-table)) (declaim (freeze-type fasl-output)) +;;; Similarity hash table logic. +;;; It really seems bogus to me that we do similarity checking in both +;;; the IR1 namespace and the fasl dumper, even going so far as to use +;;; two different ways to decide that an object is "harmless" to look up +;;; (i.e. has no cyclic references). + +#-sb-xc-host +(progn +(defun similarp (x y) + ;; Do almost the same thing that EQUAL does, but: + ;; - consider strings to be dissimilar if their element types differ. + ;; - scan elements of all specialized numeric vectors (BIT is done by EQUAL) + (named-let recurse ((x x) (y y)) + (or (%eql x y) + (typecase x + (cons + (and (consp y) + (recurse (car x) (car y)) + (recurse (cdr x) (cdr y)))) + (string + ;; Incidentally, if we want to preserve non-simpleness of dumped arrays + ;; (which is permissible but not required), this case (and below for arrays) + ;; would be where to do it by returning non-similar. + (and (stringp y) + ;; (= (widetag-of ...)) would be too strict, because a simple string + ;; can be be similar to a non-simple string. + (eq (array-element-type x) + (array-element-type y)) + (string= x y))) + ((or pathname bit-vector) ; fall back to EQUAL + ;; This could be slightly wrong, but so it always was, because we use + ;; (and have used) EQUAL for PATHNAME in SB-C::FIND-CONSTANT, but: + ;; "Two pathnames S and C are similar if all corresponding pathname components are similar." + ;; and we readily admit that similarity of strings requires equal element types. + ;; So this is slightly dubious: + ;; (EQUAL (MAKE-PATHNAME :NAME (COERCE "A" 'SB-KERNEL:SIMPLE-CHARACTER-STRING)) + ;; (MAKE-PATHNAME :NAME (COERCE "A" 'BASE-STRING))) => T + ;; On the other hand, nothing says that the pathname constructors such as + ;; MAKE-PATHNAME and MERGE-PATHNAMES don't convert to a canonical representation + ;; which renders them EQUAL when all strings are STRING=. + ;; This area of the language spec seems to have been a clusterfsck. + (equal x y)) + ;; We would need to enhance COALESCE-TREE-P to detect cycles involving + ;; SIMPLE-VECTOR before recursing, otherwise this could exhaust stack. + ((unboxed-array (*)) + (and (sb-xc:typep y '(simple-array * 1)) + (= (length x) (length y)) + (equal (sb-xc:array-element-type x) (sb-xc:array-element-type y)) + (or (typep x '(array nil (*))) + (dotimes (i (length x) t) + (unless (= (aref x i) (aref y i)) (return nil)))))) + ;; How do SIMPLE-VECTOR and other array types get here? + ;; Answer: COALESCE-TREE-P is "weaker than" the the local COALESCE-P function in FIND-CONSTANT, + ;; so it may return T on trees that contain atoms that COALESCE-P would have returned NIL on. + ;; Therefore DUMP-NON-IMMEDIATE-OBJECT may call SIMILARP on an object for which COALESCE-P + ;; would have said NIL. + ;; As mentioned at the top of this file, this seems incredibly bad, + ;; But users do not tend to have object cycles involving SIMPLE-VECTOR and such, I guess? + ;; Anyway, the answer has to be "no" for everything else: un-EQL objects are not similar. + (t nil))))) +;; This hash function is an amalgam of SXHASH and PSHASH with the following properties: +;; - numbers must have the same type to be similar (same as SXHASH) +;; - instances must be EQ to be similar (same as SXHASH) +;; - strings and characters are compared case-sensitively (same as SXHASH) +;; - arrays must have the same type to be similar +;; Unlike EQUAL-HASH, we never call EQ-HASH, because there is generally no reason +;; to try to look up an object that lacks a content-based hash value. +(defun similar-hash (x) + (declare (special sb-c::*compile-object*)) + (named-let recurse ((x x)) + ;; There is no depth cutoff - X must not be circular, + ;; which was already determined as a precondition to calling this, + ;; except that as pointed out, we must not descend into simple-vector + ;; because there was no circularity checking done for arrays. + (typecase x + (list (do ((hash 0)) + ((atom x) (mix (if x (recurse x) #xD00F) hash)) + ;; mix the hash of the CARs only, without consuming stack + ;; proportional to list length. + (setf hash (mix (recurse (car x)) hash) + x (cdr x)))) + (symbol (sxhash x)) + (number (sb-impl::number-sxhash x)) + (pathname (sb-impl::pathname-sxhash x)) + (instance + (let ((idmap (fasl-output-instance-id-table sb-c::*compile-object*))) + (values (ensure-gethash x idmap + (let ((c (1+ (hash-table-count idmap)))) + (mix c c)))))) + ;; Arrays disregard simplicity. + ((array nil (*)) #xdead) ; don't access the data in these bastards + ((unboxed-array (*)) + (let* ((simple-array (coerce x '(simple-array * (*)))) + (widetag (%other-pointer-widetag simple-array)) + (saetp (find widetag sb-vm:*specialized-array-element-type-properties* + :key #'sb-vm:saetp-typecode)) + (n-data-words (ceiling (sb-vm::vector-n-data-octets simple-array saetp) + sb-vm:n-word-bytes)) + (hash (word-mix (length x) widetag))) + (declare (word hash)) + (dotimes (i n-data-words (logand hash most-positive-fixnum)) + ;; FIXME: the last word of {1,2,4}-bit-per-element vectors + ;; needs to be masked. At worst, this fails to coalesce + ;; similar vectors, so it's not fatal. + (setq hash (word-mix hash (%vector-raw-bits x i)))))) + (character (char-code x)) + (t 0)))) +(defun make-similarity-table () + (make-hash-table :hash-function #'similar-hash :test #'similarp)) +) ; end PROGN + +;;; When cross-compiling, it's good enough to approximate similarity as EQUAL. +#+sb-xc-host +(defun make-similarity-table () (make-hash-table :test 'equal)) + +(defmacro get-similar (key table) `(gethash ,key ,table)) + ;;; This structure holds information about a circularity. (defstruct (circularity (:copier nil)) ;; the kind of modification to make to create circularity - (type (missing-arg) :type (member :rplaca :rplacd :svset :struct-set)) + (type (missing-arg) :type (member :rplaca :rplacd :svset :struct-set :slot-set)) ;; the object containing circularity object ;; index in object for circularity (index (missing-arg) :type index) + ;; slot name in object for circularity + (slot-name nil :type symbol) ;; the object to be stored at INDEX in OBJECT. This is that the key ;; that we were using when we discovered the circularity. value @@ -197,13 +328,9 @@ ;;; otherwise NIL. (defun similar-check-table (x fasl-output) (declare (type fasl-output fasl-output)) - (let ((handle - (dolist (candidate (gethash x (fasl-output-similar-table fasl-output))) - (when (sb-c::similarp (car candidate) x) - (return (cdr candidate)))))) - (cond - (handle (dump-push handle fasl-output) t) - (t nil)))) + (awhen (get-similar x (fasl-output-similar-table fasl-output)) + (dump-push it fasl-output) + t)) ;;; These functions are called after dumping an object to save the ;;; object in the table. The object (also passed in as X) must already @@ -216,7 +343,7 @@ (defun similar-save-object (x fasl-output) (declare (type fasl-output fasl-output)) (let ((handle (dump-to-table fasl-output))) - (push (cons x handle) (gethash x (fasl-output-similar-table fasl-output))) + (setf (get-similar x (fasl-output-similar-table fasl-output)) handle) (setf (gethash x (fasl-output-eq-table fasl-output)) handle)) (values)) ;;; Record X in File's CIRCULARITY-TABLE. This is called on objects @@ -272,8 +399,8 @@ compiled from ~S~% ~ using ~A version ~A~%" where - (sb-xc:lisp-implementation-type) - (sb-xc:lisp-implementation-version)))) + (lisp-implementation-type) + (lisp-implementation-version)))) stream) (dump-byte +fasl-header-string-stop-char-code+ res) ;; Finish the header by outputting fasl file implementation, @@ -289,7 +416,7 @@ (dump-byte (char-code (aref string i)) res)))) (dump-counted-string (symbol-name +backend-fasl-file-implementation+)) (dump-word +fasl-file-version+ res) - (dump-counted-string (sb-xc:lisp-implementation-version)) + (dump-counted-string (lisp-implementation-version)) (dump-counted-string (compute-features-affecting-fasl-format))) res))) @@ -316,7 +443,7 @@ ;;; dumping them. If the object is in the EQ-TABLE, then we push it, ;;; otherwise, we do a type dispatch to a type specific dumping ;;; function. The type specific branches do any appropriate -;;; EQUAL-TABLE check and table entry. +;;; SIMILAR-TABLE check and table entry. ;;; ;;; When we go to dump the object, we enter it in the CIRCULARITY-TABLE. (defun dump-non-immediate-object (x file) @@ -333,8 +460,8 @@ ((not (similar-check-table x file)) (dump-list x file t) (similar-save-object x file)))) - (layout - (dump-layout x file) + (wrapper + (dump-wrapper x file) (eq-save-object x file)) #+sb-xc-host (ctype @@ -348,11 +475,15 @@ ((eq x sb-c::*debug-name-ellipsis*) 2) (t (bug "Bogus debug name marker"))))) (instance - (dump-structure x file) + (multiple-value-bind (slot-names slot-names-p) + (gethash x (fasl-output-saved-slot-names file)) + (if slot-names-p + (dump-instance-saving-slots x slot-names file) + (dump-structure x file))) (eq-save-object x file)) (array ;; DUMP-ARRAY (and its callees) are responsible for - ;; updating the EQ and EQUAL hash tables. + ;; updating the EQ and SIMILAR hash tables. (dump-array x file)) (number (unless (similar-check-table x file) @@ -385,7 +516,7 @@ #+(and (not sb-xc-host) sb-simd-pack-256) (defun dump-simd-pack-256 (x file) (dump-fop 'fop-simd-pack file) - (dump-integer-as-n-bytes (logior (%simd-pack-256-tag x) 4) 8 file) + (dump-integer-as-n-bytes (logior (%simd-pack-256-tag x) (ash 1 6)) 8 file) (dump-integer-as-n-bytes (%simd-pack-256-0 x) 8 file) (dump-integer-as-n-bytes (%simd-pack-256-1 x) 8 file) (dump-integer-as-n-bytes (%simd-pack-256-2 x) 8 file) @@ -409,7 +540,14 @@ (dump-fop 'fop-truth file) (dump-non-immediate-object x file))) ((fixnump x) (dump-integer x file)) - ((characterp x) (dump-character x file)) + ((characterp x) + (dump-fop 'fop-character file (char-code x))) + ((packagep x) + (dump-push (dump-package x file) file)) + #-sb-xc-host + ((system-area-pointer-p x) + (dump-fop 'fop-word-pointer file) + (dump-integer-as-n-bytes (sap-int x) sb-vm:n-word-bytes file)) (t (dump-non-immediate-object x file)))) @@ -436,7 +574,10 @@ (:rplaca #.(get 'fop-rplaca 'opcode)) (:rplacd #.(get 'fop-rplacd 'opcode)) (:svset #.(get 'fop-svset 'opcode)) - (:struct-set #.(get 'fop-structset 'opcode))) + (:struct-set #.(get 'fop-structset 'opcode)) + (:slot-set + (dump-object (circularity-slot-name info) file) + #.(get 'fop-slotset 'opcode))) file) (dump-varint (gethash (circularity-object info) table) file) (dump-varint (circularity-index info) file)))) @@ -449,6 +590,7 @@ ;;; We peek at the object type so that we only pay the circular ;;; detection overhead on types of objects that might be circular. (defun dump-object (x file) + #+(and metaspace sb-xc-host) (when (cl:typep x 'sb-vm:layout) (error "can't dump sb-vm:layout")) (if (compound-object-p x) (let ((*circularities-detected* ()) (circ (fasl-output-circularity-table file))) @@ -463,16 +605,13 @@ ;;; Emit a funcall of the function and return the handle for the ;;; result. -(defun fasl-dump-load-time-value-lambda (fun file no-skip) +(defun fasl-dump-load-time-value-lambda (fun file) (declare (type sb-c::clambda fun) (type fasl-output file)) (let ((handle (gethash (sb-c::leaf-info fun) (fasl-output-entry-table file)))) (aver handle) (dump-push handle file) - ;; Can't skip MAKE-LOAD-FORM due to later references - (if no-skip - (dump-fop 'fop-funcall-no-skip file 0) - (dump-fop 'fop-funcall file 0))) + (dump-fop 'fop-funcall file 0)) (dump-pop file)) ;;; Return T iff CONSTANT has already been dumped. It's been dumped if @@ -496,9 +635,15 @@ ;;; Note that the specified structure can just be dumped by ;;; enumerating the slots. -(defun fasl-note-dumpable-instance (structure file) +(defun fasl-validate-structure (structure file) (setf (gethash structure (fasl-output-valid-structures file)) t) (values)) + +;;; Note that the specified standard object can just be dumped by +;;; saving its slot values. +(defun fasl-note-instance-saves-slots (instance slot-names file) + (setf (gethash instance (fasl-output-saved-slot-names file)) slot-names) + (values)) ;;;; number dumping @@ -581,7 +726,7 @@ (declare (inline assoc)) (cond ((cdr (assoc pkg (fasl-output-packages file) :test #'eq))) (t - (let ((s (package-name pkg))) + (let ((s (sb-xc:package-name pkg))) (dump-fop 'fop-named-package-save file (length s)) ;; Package names are always dumped as varint-encoded character strings ;; except on non-unicode builds. @@ -720,13 +865,13 @@ #+sb-xc-host (bug "Can't dump multi-dim array"))) ;;; Dump the vector object. If it's not simple, then actually dump a -;;; simple realization of it. But we enter the original in the EQ or EQUAL +;;; simple realization of it. But we enter the original in the EQ or SIMILAR ;;; tables. (defun dump-vector (x file) (let ((simple-version (if (array-header-p x) - (sb-xc:coerce x `(simple-array - ,(array-element-type x) - (*))) + (coerce x `(simple-array + ,(array-element-type x) + (*))) x))) (typecase simple-version ;; On the host, take all strings to be simple-base-string. @@ -749,8 +894,9 @@ (dump-simple-vector simple-version file) (eq-save-object x file)) (t - (dump-specialized-vector simple-version file) - (eq-save-object x file))))) + (unless (similar-check-table x file) + (dump-specialized-vector simple-version file) + (similar-save-object x file)))))) ;;; Dump a SIMPLE-VECTOR, handling any circularities. (defun dump-simple-vector (v file) @@ -789,9 +935,11 @@ #-sb-xc-host (declare (type (simple-unboxed-array (*)) vector)) (let* ((length (length vector)) (widetag (%other-pointer-widetag vector)) - (bits-per-length (aref **saetp-bits-per-length** widetag))) - (aver (< bits-per-length 255)) + (bits-per-elt (sb-vm::simple-array-widetag->bits-per-elt widetag))) (unless data-only + ;; fop-spec-vector doesn't grok trailing #\null convention. + (aver (and (/= widetag sb-vm:simple-base-string-widetag) + (/= widetag sb-vm:simple-vector-widetag))) (dump-fop 'fop-spec-vector file length) (dump-byte widetag file)) @@ -806,22 +954,19 @@ (sb-impl::buffer-output (fasl-output-stream file) vector 0 - (ceiling (* length bits-per-length) sb-vm:n-byte-bits) - #+sb-xc-host bits-per-length)))) + (ceiling (* length bits-per-elt) sb-vm:n-byte-bits) + #+sb-xc-host bits-per-elt)))) -;;; Dump characters and string-ish things. - -(defun dump-character (char file) - (dump-fop 'fop-character file (sb-xc:char-code char))) +;;; Dump string-ish things. ;;; Dump a SIMPLE-STRING. (defun dump-chars (s fasl-output base-string-p) (declare (type simple-string s)) (if (or base-string-p #-sb-unicode t) ; if non-unicode, every char is 1 byte (dovector (c s) - (dump-byte (sb-xc:char-code c) fasl-output)) + (dump-byte (char-code c) fasl-output)) (dovector (c s) ; varint (a/k/a LEB128) is better for this than UTF-8. - (dump-varint (sb-xc:char-code c) fasl-output)))) + (dump-varint (char-code c) fasl-output)))) ;;; If we get here, it is assumed that the symbol isn't in the table, ;;; but we are responsible for putting it there when appropriate. @@ -855,8 +1000,9 @@ (dump-fop 'fop-keyword-symbol-save file length+flag)) (t (let ((pkg-index (dump-package pkg file))) - (dump-fop 'fop-symbol-in-package-save file - length+flag pkg-index)))) + (if (eq (find-symbol pname pkg) :inherited) + (dump-fop 'fop-symbol-in-package-save file length+flag pkg-index) + (dump-fop 'fop-symbol-in-package-internal-save file length+flag pkg-index))))) (unless dumped-as-copy (dump-chars pname file base-string-p) @@ -887,52 +1033,85 @@ (assert (<= (length +fixup-kinds+) 8))) ; fixup-kind fits in 3 bits (defconstant-eqx +fixup-flavors+ - #(:assembly-routine :assembly-routine* :asm-routine-nil-offset - :symbol-tls-index - :foreign :foreign-dataref :code-object - :layout :immobile-symbol :named-call :static-call - :symbol-value) + #(:assembly-routine :assembly-routine* + :gc-barrier :symbol-tls-index + :alien-code-linkage-index :alien-data-linkage-index + :foreign :foreign-dataref + :code-object + :layout :immobile-symbol :fdefn-call :static-call + :symbol-value + :layout-id) #'equalp) ;;; Pack the aspects of a fixup into an integer. +;;; DATA is for asm routine fixups. The routine can be represented in 7 bits, +;;; so the fixup can be reduced to one word instead of an integer and a symbol. (declaim (inline !pack-fixup-info)) -(defun !pack-fixup-info (offset kind flavor) - ;; ARM gets "error during constant folding" - #+arm (declare (notinline position)) - (logior (ash (the (mod 16) (or (position flavor +fixup-flavors+) - (error "Bad fixup flavor ~s" flavor))) - 3) +(defun !pack-fixup-info (offset kind flavor data) + (logior ;; 3 bits (the (mod 8) (or (position kind +fixup-kinds+) (error "Bad fixup kind ~s" kind))) - (ash offset 7))) + ;; 4 bits + (ash (the (mod 16) (or (position flavor +fixup-flavors+) + (error "Bad fixup flavor ~s" flavor))) + 3) + ;; 7 bits + (ash (the (mod 128) data) 7) + ;; whatever it needs + (ash offset 14))) ;;; Unpack an integer from DUMP-FIXUPs. Shared by genesis and target fasloader (declaim (inline !unpack-fixup-info)) -(defun !unpack-fixup-info (packed-info) ; Return (VALUES offset kind flavor) - ;; ARM gets "error during constant folding" - #+arm (declare (notinline aref)) - (values (ash packed-info -7) +(defun !unpack-fixup-info (packed-info) ; Return (VALUES offset kind flavor data) + (values (ash packed-info -14) (aref +fixup-kinds+ (ldb (byte 3 0) packed-info)) - (aref +fixup-flavors+ (ldb (byte 4 3) packed-info)))) + (aref +fixup-flavors+ (ldb (byte 4 3) packed-info)) + (ldb (byte 7 7) packed-info))) + +#+(or arm arm64 riscv sparc) ; these don't have any retained packed fixups (yet) +(defun sb-c::pack-retained-fixups (fixup-notes) + (declare (ignore fixup-notes)) + 0) ; as if from PACK-CODE-FIXUP-LOCS ;;; Dump all the fixups. ;;; - foreign (C) symbols: named by a string ;;; - code object references: don't need a name. ;;; - everything else: a symbol for the name. -(defun dump-fixups (fixups fasl-output &aux (n 0)) - (declare (list fixups) (type fasl-output fasl-output)) - (dolist (note fixups n) +(defun dump-fixups (fixup-notes alloc-points fasl-output &aux (nelements 2)) + (declare (type list fixup-notes) (type fasl-output fasl-output)) + ;; "retained" fixups are those whose offset in the code needs to be + ;; remembered for subsequent reapplication by the garbage collector, + ;; or in some cases, on core startup. + (dump-object (sb-c::pack-retained-fixups fixup-notes) fasl-output) + (dump-object alloc-points fasl-output) + (dolist (note fixup-notes nelements) (let* ((fixup (fixup-note-fixup note)) (name (fixup-name fixup)) (flavor (fixup-flavor fixup)) - (info (!pack-fixup-info (fixup-note-position note) - (fixup-note-kind note) - flavor)) + (named (not (member flavor '(:code-object :gc-barrier)))) + (data + (or #-sb-xc-host ; ASM routine indices aren't known to the cross-compiler + (when (member flavor '(:assembly-routine :assembly-routine*)) + (setq named nil) + (the (integer 1 *) ; data can't be 0 + (cddr (gethash name (%code-debug-info *assembler-routines*))))) + 0)) + (info + (!pack-fixup-info (fixup-note-position note) (fixup-note-kind note) + flavor data)) (operand (ecase flavor - (:code-object (the null name)) - (:layout (if (symbolp name) name (layout-classoid-name name))) - ((:assembly-routine :assembly-routine* :asm-routine-nil-offset + ((:code-object :gc-barrier) (the null name)) + (:layout + (if (symbolp name) + name + (wrapper-classoid-name + (cond #+metaspace + ((sb-kernel::layout-p name) (layout-friend name)) + (t name))))) + (:layout-id + (the wrapper name)) + ((:assembly-routine :assembly-routine* :symbol-tls-index ;; Only #+immobile-space can use the following two flavors. ;; An :IMMOBILE-SYMBOL fixup references the symbol itself, @@ -941,11 +1120,12 @@ ;; but its global value must be an immobile object. :immobile-symbol :symbol-value) (the symbol name)) - ((:foreign #+linkage-table :foreign-dataref) (the string name)) - ((:named-call :static-call) name)))) - (dump-object operand fasl-output) - (dump-integer info fasl-output)) - (incf n))) + ((:alien-code-linkage-index :alien-data-linkage-index + :foreign :foreign-dataref) (the string name)) + ((:fdefn-call :static-call) name)))) + (dump-object info fasl-output) + (incf nelements (cond (named (dump-object operand fasl-output) 2) + (t 1)))))) ;;; Dump out the constant pool and code-vector for component, push the ;;; result in the table, and return the offset. @@ -959,23 +1139,27 @@ ;;; constants. ;;; ;;; We dump trap objects in any unused slots or forward referenced slots. -(defun dump-code-object (component code-segment code-length fixups fasl-output) +(defun dump-code-object (component code-segment code-length fixups alloc-points fasl-output) (declare (type component component) (type index code-length) (type fasl-output fasl-output)) - (let* ((n-fixups (dump-fixups fixups fasl-output)) - (2comp (component-info component)) + (let* ((2comp (component-info component)) (constants (sb-c:ir2-component-constants 2comp)) (header-length (length constants)) - (n-named-calls 0)) - (collect ((patches)) + (n-fdefns 0)) + (collect ((patches) + (named-constants)) ;; Dump the constants, noting any :ENTRY constants that have to ;; be patched. (loop for i from sb-vm:code-constants-offset below header-length do (let ((entry (aref constants i))) (etypecase entry (constant - (dump-object (sb-c::constant-value entry) fasl-output)) + (cond ((sb-c::leaf-has-source-name-p entry) + (named-constants (cons (sb-c::leaf-source-name entry) i)) + (dump-fop 'fop-misc-trap fasl-output)) + (t + (dump-object (sb-c::constant-value entry) fasl-output)))) (cons (ecase (car entry) (:constant ; anything that has not been wrapped in a #<CONSTANT> @@ -994,29 +1178,45 @@ (dump-fop 'fop-misc-trap fasl-output))))) (:load-time-value (dump-push (cadr entry) fasl-output)) - ((:named-call :fdefinition) - (when (eq (car entry) :named-call) (incf n-named-calls)) + (:fdefinition + ;; It's possible for other fdefns to be found in the header, but they can't + ;; have resulted from IR2 conversion. They would have had to come from + ;; something like (load-time-value (find-or-create-fdefn ...)) + ;; which is fine, but they don't count for this purpose. + (incf n-fdefns) (dump-object (cadr entry) fasl-output) (dump-fop 'fop-fdefn fasl-output)) (:known-fun (dump-object (cadr entry) fasl-output) - (dump-fop 'fop-known-fun fasl-output)))) + (dump-fop 'fop-known-fun fasl-output)) + (:coverage-marks + ;; Avoid the coalescence done by DUMP-VECTOR + (dump-specialized-vector (make-array (cdr entry) + :element-type '(unsigned-byte 8) + :initial-element #xFF) + fasl-output)))) (null (dump-fop 'fop-misc-trap fasl-output))))) ;; Dump the debug info. (let ((info (sb-c::debug-info-for-component component))) - (setf (sb-c::debug-info-source info) - (fasl-output-source-info fasl-output)) - (dump-object info fasl-output)) - - (dump-fop 'fop-load-code fasl-output - (logior (ash header-length 1) - (if (sb-c::code-immobile-p component) 1 0)) - code-length n-fixups) + (fasl-validate-structure info fasl-output) + (dump-object info fasl-output) + (push (dump-to-table fasl-output) + (fasl-output-debug-info fasl-output))) + + (let ((n-fixup-elts (dump-fixups fixups alloc-points fasl-output))) + (dump-fop 'fop-load-code fasl-output + (logior (ash header-length 1) + (if (sb-c::code-immobile-p component) 1 0)) + code-length + n-fixup-elts)) ;; Fasl dumper/loader convention allows at most 3 integer args. ;; Others have to be written with explicit calls. - (dump-integer-as-n-bytes (the (unsigned-byte 22) n-named-calls) + (dump-integer-as-n-bytes (length (sb-c::ir2-component-entries 2comp)) + 4 ; output 4 bytes + fasl-output) + (dump-integer-as-n-bytes (the (unsigned-byte 22) n-fdefns) 4 ; output 4 bytes fasl-output) (dump-segment code-segment code-length fasl-output) @@ -1026,12 +1226,16 @@ (push (cons handle (cdr patch)) (gethash (car patch) (fasl-output-patch-table fasl-output)))) + (dolist (named-constant (named-constants)) + (dump-object (car named-constant) fasl-output) + (dump-push handle fasl-output) + (dump-fop 'fop-named-constant-set fasl-output (cdr named-constant))) handle)))) ;;; This is only called from assemfile, which doesn't exist in the target. #+sb-xc-host -(defun dump-assembler-routines (code-segment octets fixups routines file) - (let ((n-fixups (dump-fixups fixups file))) +(defun dump-assembler-routines (code-segment octets fixups alloc-points routines file) + (let ((n-fixup-elts (dump-fixups fixups alloc-points file))) ;; The name -> address table has to be created before applying fixups ;; because a fixup may refer to an entry point in the same code component. ;; So these go on the stack last, i.e. nearest the top. @@ -1039,12 +1243,12 @@ ;; except possibly when there are multiple entry points to one routine (dolist (routine (reverse routines)) (dump-object (car routine) file) - (dump-integer (+ (label-position (cadr routine)) - (caddr routine)) + (dump-integer (+ (label-position (cadr routine)) (caddr routine)) file)) (dump-fop 'fop-assembler-code file) - (dolist (word (list (length octets) (length routines) n-fixups)) - (dump-word word file)) + (dump-word (length routines) file) + (dump-word (length octets) file) + (dump-word n-fixup-elts file) (write-segment-contents code-segment (fasl-output-stream file)) (dump-pop file))) @@ -1060,11 +1264,7 @@ ;;; Dump the code, constants, etc. for component. We pass in the ;;; assembler fixups, code vector and node info. -(defun fasl-dump-component (component - code-segment - code-length - fixups - file) +(defun fasl-dump-component (component code-segment code-length fixups alloc-points file) (declare (type component component)) (declare (type fasl-output file)) @@ -1073,30 +1273,31 @@ #+sb-dyncount (let ((info (sb-c::ir2-component-dyncount-info (component-info component)))) (when info - (fasl-note-dumpable-instance info file))) + (fasl-validate-structure info file))) (let* ((2comp (component-info component)) (entries (sb-c::ir2-component-entries 2comp)) (nfuns (length entries)) (code-handle - ;; fill in the placeholder elements of constants - ;; with the NAME, ARGLIST, TYPE, INFO slots of each simple-fun. - (let ((constants (sb-c:ir2-component-constants 2comp)) - (wordindex (+ sb-vm:code-constants-offset - (* sb-vm:code-slots-per-simple-fun nfuns)))) - (dolist (entry entries) - ;; Process in reverse order of ENTRIES. - ;; See also MAKE-CORE-COMPONENT which does the same thing. - (decf wordindex 4) - (setf (aref constants (+ wordindex sb-vm:simple-fun-name-slot)) - `(:constant ,(sb-c::entry-info-name entry)) - (aref constants (+ wordindex sb-vm:simple-fun-arglist-slot)) - `(:constant ,(sb-c::entry-info-arguments entry)) - (aref constants (+ wordindex sb-vm:simple-fun-source-slot)) - `(:constant ,(sb-c::entry-info-form/doc entry)) - (aref constants (+ wordindex sb-vm:simple-fun-info-slot)) - `(:constant ,(sb-c::entry-info-type/xref entry)))) - (dump-code-object component code-segment code-length fixups file))) + ;; fill in the placeholder elements of constants + ;; with the NAME, ARGLIST, TYPE, INFO slots of each simple-fun. + (let ((constants (sb-c:ir2-component-constants 2comp)) + (wordindex (+ sb-vm:code-constants-offset + (* sb-vm:code-slots-per-simple-fun nfuns)))) + (dolist (entry entries) + ;; Process in reverse order of ENTRIES. + ;; See also MAKE-CORE-COMPONENT which does the same thing. + (decf wordindex sb-vm:code-slots-per-simple-fun) + (setf (aref constants (+ wordindex sb-vm:simple-fun-name-slot)) + `(:constant ,(sb-c::entry-info-name entry)) + (aref constants (+ wordindex sb-vm:simple-fun-arglist-slot)) + `(:constant ,(sb-c::entry-info-arguments entry)) + (aref constants (+ wordindex sb-vm:simple-fun-source-slot)) + `(:constant ,(sb-c::entry-info-form/doc entry)) + (aref constants (+ wordindex sb-vm:simple-fun-info-slot)) + `(:constant ,(sb-c::entry-info-type/xref entry)))) + (dump-code-object component code-segment code-length fixups + alloc-points file))) (fun-index nfuns)) (dolist (entry entries) @@ -1106,16 +1307,25 @@ ;; When cross compiling, if the entry is a DEFUN, then we also ;; dump a FOP-FSET so that the cold loader can instantiate the ;; definition at cold-load time, allowing forward references - ;; to functions in top-level forms. + ;; to functions in top-level forms. If the entry is a + ;; DEFMETHOD, we dump a FOP-MSET so that the cold loader + ;; recognizes the method definition. #+sb-xc-host (let ((name (sb-c::entry-info-name entry))) - ;; At the moment, we rely on the fopcompiler to do linking - ;; for DEFUNs that are not block compiled. - (when (and (eq (sb-c::block-compile sb-c::*compilation*) t) - (sb-c::legal-fun-name-p name)) - (dump-object name file) - (dump-push entry-handle file) - (dump-fop 'fop-fset file))) + (cond ((sb-c::legal-fun-name-p name) + (dump-object name file) + (dump-push entry-handle file) + (dump-fop 'fop-fset file)) + ((and (listp name) + (eq (first name) 'sb-pcl::fast-method)) + (let ((method (second name)) + (qualifiers (butlast (cddr name))) + (specializers (first (last name)))) + (dump-object method file) + (dump-object qualifiers file) + (dump-object specializers file) + (dump-push entry-handle file) + (dump-fop 'fop-mset file))))) (setf (gethash entry (fasl-output-entry-table file)) entry-handle) (let ((old (gethash entry (fasl-output-patch-table file)))) (when old @@ -1142,53 +1352,55 @@ (dump-push-previously-dumped-fun fun fasl-output) (dump-fop 'fop-funcall-for-effect fasl-output 0) (values)) + +;;; Dump some information to allow partial reconstruction of the +;;; DEBUG-SOURCE structure. +(defun fasl-dump-partial-source-info (info file) + (declare (type sb-c::source-info info) (type fasl-output file)) + (let ((partial (sb-c::debug-source-for-info info))) + (dump-object (sb-c::debug-source-namestring partial) file) + (dump-object (sb-c::debug-source-created partial) file) + (dump-object (sb-c::debug-source-plist partial) file) + (dump-fop 'fop-note-partial-source-info file))) + +;;; Compute the correct list of DEBUG-SOURCE structures and backpatch +;;; all of the dumped DEBUG-INFO structures. We clear the +;;; FASL-OUTPUT-DEBUG-INFO, so that subsequent components with +;;; different source info may be dumped. +(defun fasl-dump-source-info (info file) + (declare (type sb-c::source-info info) (type fasl-output file)) + (let ((res (sb-c::debug-source-for-info info))) + (fasl-validate-structure res file) + (dump-object res file) + (let ((res-handle (dump-pop file))) + (dolist (info-handle (fasl-output-debug-info file)) + (dump-push res-handle file) + (symbol-macrolet + ((debug-info-source-index + (let ((dd (find-defstruct-description 'sb-c::debug-info))) + (dsd-index (find 'source (dd-slots dd) + :key #'dsd-name :test 'string=))))) + (dump-fop 'fop-structset file info-handle debug-info-source-index))))) + + (setf (fasl-output-debug-info file) nil) + (values)) ;;;; dumping structures -;;; Even as late as calling DUMP-STRUCTURE we might have to deduce that a -;;; user's "custom" MAKE-LOAD-FORM amounts to MAKE-LOAD-FORM-SAVING-SLOTS -;;; with the default of all slots. Why: suppose you have some structure -;;; (DEFSTRUCT MYSTRUCT A) -;;; and a macro that returns literal instances of the structure: -;;; (DEFMACRO FUNNYMAC (N) (MAKE-MYSTRUCT :A N)) -;;; and a DEFVAR that uses the structure: -;;; (DEFVAR *A* (FUNNYMAC 1)) -;;; -;;; Now, because the fopcompiler expands macros more than once - at least once -;;; in FOPCOMPILABLE-P and then again in FOPCOMPILE - we see _different_ -;;; instances of MYSTRUCT each of those times. We don't memoize the expansion. -;;; The two structures are similar but not EQ, and only the instance produced -;;; during FOPCOMPILABLE-P was entered in the FASL-OUTPUT-VALID-STRUCTURES table. -;;; The other structure instance isn't there, but we need it to be legal to dump. -;;; -;;; This problem is not just theoretical. We ourselves do just that, e.g.: -;;; (defvar *cpus* (... (sb-alien:alien-funcall ...))) -;;; and the expansion of alien-funcall involves an ALIEN-TYPE literal -;;; which gets multiply expanded exactly as described above. - -(defun load-form-is-default-mlfss-p (struct) - (eq (nth-value 1 (sb-c::%make-load-form struct)) 'fop-struct)) - -;; Having done nothing more than load all files in obj/from-host, the -;; cross-compiler running under any host Lisp begins life able to access -;; SBCL-format metadata for any structure that is a subtype of STRUCTURE!OBJECT. -;; But if it learns a layout by cross-compiling a DEFSTRUCT, that's ok too. (defun dump-structure (struct file) (unless (or (gethash struct (fasl-output-valid-structures file)) - (typep struct - '(or sb-c::debug-info sb-c::debug-fun sb-c::debug-source - sb-c:definition-source-location sb-c::debug-name-marker)) - (load-form-is-default-mlfss-p struct)) + ;; Assume that DEBUG-FUNs are always valid to dump. + (typep struct 'sb-c::debug-fun)) (error "attempt to dump invalid structure:~% ~S~%How did this happen?" struct)) (note-potential-circularity struct file) (do* ((length (%instance-length struct)) - (layout (%instance-layout struct)) - (bitmap (layout-bitmap layout)) + (wrapper (%instance-wrapper struct)) + (bitmap (wrapper-bitmap wrapper)) (circ (fasl-output-circularity-table file)) (index sb-vm:instance-data-start (1+ index))) ((>= index length) - (dump-non-immediate-object layout file) + (dump-non-immediate-object wrapper file) (dump-fop 'fop-struct file length)) (let* ((obj (if (logbitp index bitmap) (%instance-ref struct index) @@ -1205,14 +1417,14 @@ (t obj)) file)))) -(defun dump-layout (obj file) - (when (layout-invalid obj) +(defun dump-wrapper (obj file &aux (flags (wrapper-flags obj))) + (when (wrapper-invalid obj) (compiler-error "attempt to dump reference to obsolete class: ~S" - (layout-classoid obj))) + (wrapper-classoid obj))) ;; STANDARD-OBJECT could in theory be dumpable, but nothing else, ;; because all its subclasses can evolve to have new layouts. - (aver (not (logtest (layout-flags obj) +pcl-object-layout-flag+))) - (let ((name (layout-classoid-name obj))) + (aver (not (logtest flags +pcl-object-layout-flag+))) + (let ((name (wrapper-classoid-name obj))) ;; Q: Shouldn't we aver that NAME is the proper name for its classoid? (unless name (compiler-error "dumping anonymous layout: ~S" obj)) @@ -1222,11 +1434,45 @@ #-sb-xc-host (let ((fop (known-layout-fop name))) (when fop - (return-from dump-layout (dump-byte fop file)))) + (return-from dump-wrapper (dump-byte fop file)))) (dump-object name file)) - (sub-dump-object (layout-bitmap obj) file) - (sub-dump-object (layout-inherits obj) file) + (sub-dump-object (wrapper-bitmap obj) file) + (sub-dump-object (wrapper-inherits obj) file) (dump-fop 'fop-layout file - (1+ (layout-depthoid obj)) ; non-stack args can't be negative - (logand (layout-flags obj) sb-kernel::layout-flags-mask) - (layout-length obj))) + (1+ (wrapper-depthoid obj)) ; non-stack args can't be negative + (logand flags sb-kernel::layout-flags-mask) + (wrapper-length obj))) + +;;;; dumping instances which just save their slots + +(defun dump-instance-saving-slots (object slot-names file) + (note-potential-circularity object file) + (let ((circ (fasl-output-circularity-table file))) + (dolist (slot-name slot-names) + (if (slot-boundp object slot-name) + (let* ((value (slot-value object slot-name)) + (ref (gethash value circ))) + (cond (ref + (push (make-circularity :type :slot-set + :object object + :index 0 + :slot-name slot-name + :value value + :enclosing-object ref) + *circularities-detected*) + (sub-dump-object nil file)) + (t + (sub-dump-object value file)))) + (dump-fop 'fop-misc-trap file)) + (sub-dump-object slot-name file))) + (sub-dump-object (class-name (class-of object)) file) + (dump-fop 'fop-instance file (length slot-names))) + +;;;; code coverage + +(defun dump-code-coverage-records (namestring cc file) + (declare (type string namestring) + (type list cc)) + (dump-object namestring file) + (dump-object cc file) + (dump-fop 'fop-record-code-coverage file)) diff --git a/src/compiler/early-assem.lisp b/src/compiler/early-assem.lisp index 3ae82133e7..a9641812ff 100644 --- a/src/compiler/early-assem.lisp +++ b/src/compiler/early-assem.lisp @@ -11,8 +11,6 @@ (in-package "SB-ASSEM") -(defvar *asmstream*) - ;;; common supertype for all the different kinds of annotations (defstruct (annotation (:constructor nil) (:copier nil)) diff --git a/src/compiler/early-c.lisp b/src/compiler/early-c.lisp index 6988900b54..378d993ba3 100644 --- a/src/compiler/early-c.lisp +++ b/src/compiler/early-c.lisp @@ -15,68 +15,21 @@ (in-package "SB-C") -;;; An OPAQUE-BOX instance is used to pass data from IR1 to IR2 as -;;; a quoted object in a "source form" (not user-written) such that the -;;; contained object is in a for-evaluation position but ignored by -;;; the compiler's constant-dumping logic. -(defstruct (opaque-box (:constructor opaquely-quote (value)) - (:copier nil) - (:predicate opaque-box-p)) - value) -(declaim (freeze-type opaque-box)) - ;;; ANSI limits on compilation -(defconstant sb-xc:call-arguments-limit sb-xc:most-positive-fixnum +(defconstant call-arguments-limit most-positive-fixnum "The exclusive upper bound on the number of arguments which may be passed to a function, including &REST args.") -(defconstant sb-xc:lambda-parameters-limit sb-xc:most-positive-fixnum +(defconstant lambda-parameters-limit most-positive-fixnum "The exclusive upper bound on the number of parameters which may be specified in a given lambda list. This is actually the limit on required and &OPTIONAL parameters. With &KEY and &AUX you can get more.") -(defconstant sb-xc:multiple-values-limit sb-xc:most-positive-fixnum +(defconstant multiple-values-limit most-positive-fixnum "The exclusive upper bound on the number of multiple VALUES that you can return.") -;;;; cross-compiler-only versions of CL special variables, so that we -;;;; don't have weird interactions with the host compiler -(defvar sb-xc:*compile-file-pathname*) -(defvar sb-xc:*compile-file-truename*) -(defvar sb-xc:*compile-print*) -(defvar sb-xc:*compile-verbose*) - ;;;; miscellaneous types used both in the cross-compiler and on the target -;;;; FIXME: The INDEX and LAYOUT-DEPTHOID definitions probably belong -;;;; somewhere else, not "early-c", since they're after all not part -;;;; of the compiler. - -;;; the type of LAYOUT-DEPTHOID and LAYOUT-LENGTH values. -;;; Each occupies two bytes of the %BITS slot when possible, -;;; otherwise a slot unto itself. -(def!type layout-depthoid () '(integer -1 #x7FFF)) -(def!type layout-length () '(integer 0 #xFFFF)) -(def!type layout-bitmap () - ;; FIXME: Probably should exclude negative bignum - #+compact-instance-header 'integer - #-compact-instance-header '(and integer (not (eql 0)))) - -;;; An INLINEP value describes how a function is called. The values -;;; have these meanings: -;;; NIL No declaration seen: do whatever you feel like, but don't -;;; dump an inline expansion. -;;; NOTINLINE NOTINLINE declaration seen: always do full function call. -;;; INLINE INLINE declaration seen: save expansion, expanding to it -;;; if policy favors. -;;; MAYBE-INLINE -;;; Retain expansion, but only use it opportunistically. -;;; MAYBE-INLINE is quite different from INLINE. As explained -;;; by APD on #lisp 2005-11-26: "MAYBE-INLINE lambda is -;;; instantiated once per component, INLINE - for all -;;; references (even under #'without FUNCALL)." -(deftype inlinep () - '(member inline maybe-inline notinline nil)) - (defstruct (dxable-args (:constructor make-dxable-args (list)) (:predicate nil) (:copier nil)) @@ -88,23 +41,33 @@ (expansion nil :read-only t)) (declaim (freeze-type dxable-args)) +;;; FREE-VARS translates from the names of variables referenced +;;; globally to the LEAF structures for them. FREE-FUNS is like +;;; FREE-VARS, only it deals with function names. +;;; +;;; We must preserve the property that a proclamation for a global +;;; thing only affects the code after it. This takes some work, since +;;; a proclamation may appear in the middle of a block being +;;; compiled. If there are references before the proclaim, then we +;;; copy the current entry before modifying it. Code converted before +;;; the proclaim sees the old Leaf, while code after it sees the new +;;; LEAF. (defstruct (ir1-namespace (:conc-name "") (:copier nil) (:predicate nil)) - ;; FREE-VARS translates from the names of variables referenced - ;; globally to the LEAF structures for them. (free-vars (make-hash-table :test 'eq) :read-only t :type hash-table) - ;; FREE-FUNS is like FREE-VARS, only it deals with function names. - (free-funs (make-hash-table :test 'equal) :read-only t :type hash-table) + (free-funs (make-hash-table :test #'equal) :read-only t :type hash-table) ;; These hashtables translate from constants to the LEAFs that ;; represent them. - ;; Table 1: one entry for each distinct constant (according to object identity) - (eq-constants (make-hash-table :test 'eq) :read-only t :type hash-table) - ;; Table 2: one hash-table entry per EQUAL constant, + ;; Table 1: one entry per named constant + (named-constants (make-hash-table :test 'eq) :read-only t :type hash-table) + ;; Table 2: one entry for each unnamed constant as compared by EQL + (eql-constants (make-hash-table :test 'eql) :read-only t :type hash-table) + ;; Table 3: one key per EQUAL constant, ;; with the caveat that lookups must discriminate amongst constants that ;; are EQUAL but not similar. The value in the hash-table is a list of candidates ;; (#<constant1> #<constant2> ... #<constantN>) such that CONSTANT-VALUE ;; of each is EQUAL to the key for the hash-table entry, but dissimilar ;; from each other. Notably, strings of different element types can't be similar. - (similar-constants (make-hash-table :test 'equal) :read-only t :type hash-table)) + (similar-constants (sb-fasl::make-similarity-table) :read-only t :type hash-table)) (declaim (freeze-type ir1-namespace)) (sb-impl::define-thread-local *ir1-namespace*) @@ -117,137 +80,29 @@ (defvar *allow-instrumenting*) ;;; miscellaneous forward declarations -#+sb-dyncount (defvar *collect-dynamic-statistics*) (defvar *component-being-compiled*) (defvar *compiler-error-context*) -(defvar *compiler-error-count*) -(defvar *compiler-warning-count*) -(defvar *compiler-style-warning-count*) -(defvar *compiler-note-count*) ;;; Bind this to a stream to capture various internal debugging output. (defvar *compiler-trace-output* nil) ;;; These are the default, but the list can also include -;;; :pre-ir2-optimize and :symbolic-asm. +;;; :pre-ir2-optimize, :symbolic-asm, and :sb-graph. (defvar *compile-trace-targets* '(:ir1 :ir2 :vop :symbolic-asm :disassemble)) -(defvar *constraint-universe*) (defvar *current-path*) (defvar *current-component*) -(defvar *delayed-ir1-transforms*) -#+sb-dyncount -(defvar *dynamic-counts-tn*) (defvar *elsewhere-label*) -(defvar *event-note-threshold*) -(defvar *failure-p*) (defvar *source-info*) (defvar *source-plist*) (defvar *source-namestring*) -(defvar *undefined-warnings*) -(defvar *warnings-p*) -(defvar *lambda-conversions*) -(defvar *compile-object* nil) -(defvar *location-context* nil) - -(defvar *stack-allocate-dynamic-extent* t - "If true (the default), the compiler respects DYNAMIC-EXTENT declarations -and stack allocates otherwise inaccessible parts of the object whenever -possible. Potentially long (over one page in size) vectors are, however, not -stack allocated except in zero SAFETY code, as such a vector could overflow -the stack without triggering overflow protection.") -;;; *BLOCK-COMPILE-ARGUMENT* holds the original value of the :BLOCK-COMPILE -;;; argument, which overrides any internal declarations. -(defvar *block-compile-argument*) -(declaim (type (member nil t :specified) - *block-compile-default* *block-compile-argument*)) +(defvar *handled-conditions* nil) +(defvar *disabled-package-locks* nil) -;;; This lock is seized in the compiler, and related areas -- like the -;;; classoid/layout/class system. -;;; Assigning a literal object enables genesis to dump and load it -;;; without need of a cold-init function. -#-sb-xc-host -(!define-load-time-global **world-lock** (sb-thread:make-mutex :name "World Lock")) - -#-sb-xc-host -(define-load-time-global *static-linker-lock* - (sb-thread:make-mutex :name "static linker")) - -(defmacro with-world-lock (() &body body) - #+sb-xc-host `(progn ,@body) - #-sb-xc-host `(sb-thread:with-recursive-lock (**world-lock**) ,@body)) ;;;; miscellaneous utilities -;;; This is for "observers" who want to know if type names have been added. -;;; Rather than registering listeners, they can detect changes by comparing -;;; their stored nonce to the current nonce. Additionally the observers -;;; can detect whether function definitions have occurred. -#-sb-xc-host -(progn (declaim (fixnum *type-cache-nonce*)) - (!define-load-time-global *type-cache-nonce* 0)) - -(defstruct (undefined-warning - (:print-object (lambda (x s) - (print-unreadable-object (x s :type t) - (prin1 (undefined-warning-name x) s)))) - (:copier nil)) - ;; the name of the unknown thing - (name nil :type (or symbol list)) - ;; the kind of reference to NAME - (kind (missing-arg) :type (member :function :type :variable)) - ;; the number of times this thing was used - (count 0 :type unsigned-byte) - ;; a list of COMPILER-ERROR-CONTEXT structures describing places - ;; where this thing was used. Note that we only record the first - ;; *UNDEFINED-WARNING-LIMIT* calls. - (warnings () :type list)) -(declaim (freeze-type undefined-warning)) - -;;; Delete any undefined warnings for NAME and KIND. This is for the -;;; benefit of the compiler, but it's sometimes called from stuff like -;;; type-defining code which isn't logically part of the compiler. -(declaim (ftype (function ((or symbol cons) keyword) (values)) - note-name-defined)) -(defun note-name-defined (name kind) - #-sb-xc-host (atomic-incf *type-cache-nonce*) - ;; We do this BOUNDP check because this function can be called when - ;; not in a compilation unit (as when loading top level forms). - (when (boundp '*undefined-warnings*) - (let ((name (uncross name))) - (setq *undefined-warnings* - (delete-if (lambda (x) - (and (equal (undefined-warning-name x) name) - (eq (undefined-warning-kind x) kind))) - *undefined-warnings*)))) - (values)) - -;;; to be called when a variable is lexically bound -(declaim (ftype (function (symbol) (values)) note-lexical-binding)) -(defun note-lexical-binding (symbol) - ;; This check is intended to protect us from getting silently - ;; burned when we define - ;; foo.lisp: - ;; (DEFVAR *FOO* -3) - ;; (DEFUN FOO (X) (+ X *FOO*)) - ;; bar.lisp: - ;; (DEFUN BAR (X) - ;; (LET ((*FOO* X)) - ;; (FOO 14))) - ;; and then we happen to compile bar.lisp before foo.lisp. - (when (looks-like-name-of-special-var-p symbol) - ;; FIXME: should be COMPILER-STYLE-WARNING? - (style-warn 'asterisks-around-lexical-variable-name - :format-control - "using the lexical binding of the symbol ~ - ~/sb-ext:print-symbol-with-prefix/, not the~@ - dynamic binding" - :format-arguments (list symbol))) - (values)) - -;;; This is DEF!STRUCT so that when SB-C:DUMPABLE-LEAFLIKE-P invokes -;;; SB-XC:TYPEP in make-host-2, it does not need need to signal PARSE-UNKNOWN -;;; for each and every constant seen up until this structure gets defined. -(def!struct (debug-name-marker (:print-function print-debug-name-marker) - (:copier nil))) +(defstruct (debug-name-marker (:print-function print-debug-name-marker) + (:copier nil))) +(declaim (freeze-type debug-name-marker)) (defvar *debug-name-level* 4) (defvar *debug-name-length* 12) @@ -291,6 +146,8 @@ the stack without triggering overflow protection.") ((or symbol number string) x) (t + ;; wtf?? This looks like a source of sensitivity to the cross-compiler host + ;; in addition to which it seems generally a stupid idea. (type-of x))))) (let ((name (list* type (walk thing) (when context (name-context))))) (when (legal-fun-name-p name) @@ -304,30 +161,6 @@ the stack without triggering overflow protection.") #-immobile-code (defmacro code-immobile-p (thing) `(progn ,thing nil)) -;;; Various error-code generating helpers -(defvar *adjustable-vectors*) - -(defmacro with-adjustable-vector ((var) &rest body) - `(let ((,var (or (pop *adjustable-vectors*) - (make-array 16 - :element-type '(unsigned-byte 8) - :fill-pointer 0 - :adjustable t)))) - ;; Don't declare the length - if it gets adjusted and pushed back - ;; onto the freelist, it's anyone's guess whether it was expanded. - ;; This code was wrong for >12 years, so nobody must have needed - ;; more than 16 elements. Maybe we should make it nonadjustable? - (declare (type (vector (unsigned-byte 8)) ,var)) - (setf (fill-pointer ,var) 0) - ;; No UNWIND-PROTECT here - semantics are unaffected by nonlocal exit, - ;; and this macro is about speeding up the compiler, not slowing it down. - ;; GC will clean up any debris, and since the vector does not point - ;; to anything, even an accidental promotion to a higher generation - ;; will not cause transitive garbage retention. - (prog1 (progn ,@body) - (push ,var *adjustable-vectors*)))) - - ;;; The allocation quantum for boxed code header words. ;;; 2 implies an even length boxed header; 1 implies no restriction. (defconstant code-boxed-words-align (+ 2 #+(or x86 x86-64) -1)) @@ -387,7 +220,14 @@ the stack without triggering overflow protection.") ;; level lambdas resulting from compiling subforms. (In reverse ;; order.) (toplevel-lambdas nil :type list) - + ;; We build a list of top-level lambdas, and then periodically smash them + ;; together into a single component and compile it. + (pending-toplevel-lambdas nil :type list) + ;; We record whether the package environment has changed during the + ;; compilation of some sequence top level forms. This allows the + ;; compiler to dump symbols in such a way that the loader can + ;; reconstruct them in the correct package. + (package-environment-changed nil :type boolean) ;; Bidrectional map between IR1/IR2/assembler abstractions and a corresponding ;; small integer or string identifier. One direction could be done by adding ;; the ID as slot to each object, but we want both directions. @@ -402,24 +242,12 @@ the stack without triggering overflow protection.") (objmap-id-to-ir2block nil :type (or null id-array)) ; number -> IR2-BLOCK (objmap-id-to-tn nil :type (or null id-array)) ; number -> TN (objmap-id-to-label nil :type (or null id-array)) ; number -> LABEL - ) + deleted-source-paths) (declaim (freeze-type compilation)) (sb-impl::define-thread-local *compilation*) (declaim (type compilation *compilation*)) -(in-package "SB-ALIEN") - -;;; Information describing a heap-allocated alien. -(def!struct (heap-alien-info (:copier nil)) - ;; The type of this alien. - (type (missing-arg) :type alien-type) - ;; Its name. - (alien-name (missing-arg) :type simple-string) - ;; Data or code? - (datap (missing-arg) :type boolean)) -(!set-load-form-method heap-alien-info (:xc :target)) - ;; from 'llvm/projects/compiler-rt/lib/msan/msan.h': ;; "#define MEM_TO_SHADOW(mem) (((uptr)(mem)) ^ 0x500000000000ULL)" #+linux ; shadow space differs by OS diff --git a/src/compiler/early-constantp.lisp b/src/compiler/early-constantp.lisp index 408fd2414e..231be6c83b 100644 --- a/src/compiler/early-constantp.lisp +++ b/src/compiler/early-constantp.lisp @@ -13,27 +13,19 @@ ;;; Subtypes of this show up as the environment argument to inquiry functions. (defstruct (abstract-lexenv - (:constructor nil) (:copier nil) (:predicate nil))) + (:constructor nil) (:copier nil) (:predicate nil))) -#-sb-fluid (declaim (inline sb-xc:constantp)) -(defun sb-xc:constantp (form &optional (environment nil envp)) +(declaim (inline constantp)) +(defun constantp (form &optional (environment nil envp)) "True of any FORM that has a constant value: self-evaluating objects, keywords, defined constants, quote forms. Additionally the constant-foldability of some function calls and special forms is recognized. If ENVIRONMENT is provided, the FORM is first macroexpanded in it." (%constantp form environment envp)) -#-sb-fluid (declaim (inline constant-form-value)) +(declaim (inline constant-form-value)) (defun constant-form-value (form &optional (environment nil envp)) "Returns the value of the constant FORM in ENVIRONMENT. Behaviour is undefined unless CONSTANTP has been first used to determine the constantness of the FORM in ENVIRONMENT." (%constant-form-value form environment envp)) - -(declaim (inline constant-typep)) -(defun constant-typep (form type &optional (environment nil envp)) - (and (%constantp form environment envp) - ;; FIXME: We probably should be passing the environment to - ;; TYPEP too, but (1) our XC version of typep AVERs that the - ;; environment is null (2) our real version ignores it anyhow. - (sb-xc:typep (%constant-form-value form environment envp) type))) diff --git a/src/compiler/early-globaldb.lisp b/src/compiler/early-globaldb.lisp index be964cba4c..5e12c6dc7a 100644 --- a/src/compiler/early-globaldb.lisp +++ b/src/compiler/early-globaldb.lisp @@ -21,7 +21,7 @@ ((or (atom result) (not (eq (car result) 'values))) `(values ,result &optional)) - ((intersection (cdr result) sb-xc:lambda-list-keywords) + ((intersection (cdr result) lambda-list-keywords) result) (t `(values ,@(cdr result) &optional))))) `(function ,args ,result))) @@ -35,6 +35,49 @@ #-sb-xc-host (declaim (ftype (sfunction (t) ctype) global-ftype)) +;;; A bit about the physical representation of the packed info format: +;;; With #+compact-instance-header it is possible to represent a vector of N things +;;; in a structure using (ALIGN-UP (1+ N) 2) words of memory. This is a saving +;;; of 1 word on average when compared to SIMPLE-VECTOR which needs +;;; (ALIGN-UP (+ N 2) 2) words. Granted that either might have a padding word, +;;; but I've observed 5% to 10% space reduction by eliminating one slot. +;;; Without compact-instance-header, we'e indifferent, in terms of space, +;;; as to whether this is an INSTANCE or a SIMPLE-VECTOR. For consistency, +;;; we use an INSTANCE regardless of presence of the compact-header feature. +;;; This makes assembly routines (e.g. CALL-SYMBOL) slightly less sensitive +;;; to the feature's absence. + +;;; Since variable-length instances aren't portably a thing, +;;; we use a structure of one slot holding a vector. +#+sb-xc-host (defstruct (packed-info + (:constructor %make-packed-info (cells)) + (:copier nil)) + ;; These objects are immutable. + (cells #() :type simple-vector :read-only t)) +;;; Some abstractions for host/target compatibility of all the defuns. +#+sb-xc-host +(progn + (defmacro make-packed-info (n) `(%make-packed-info (make-array ,n))) + (defmacro copy-packed-info (info) + `(%make-packed-info (copy-seq (packed-info-cells ,info)))) + (defmacro packed-info-len (info) + `(length (packed-info-cells ,info))) + (defmacro %info-ref (info index) `(svref (packed-info-cells ,info) ,index))) +#-sb-xc-host +(progn + #+nil + (defmethod print-object ((obj packed-info) stream) + (format stream "[~{~W~^ ~}]" + (loop for i below (%instance-length obj) + collect (%instance-ref obj i)))) + (defmacro packed-info-len (info) + `(- (%instance-length ,info) #.sb-vm:instance-data-start)) + (defmacro %info-ref (v i) + `(%instance-ref ,v (+ ,i #.sb-vm:instance-data-start))) + (defmethod print-object ((self packed-info) stream) + (print-unreadable-object (self stream :type t :identity t) + (format stream "len=~d" (packed-info-len self))))) + ;;; At run time, we represent the type of a piece of INFO in the globaldb ;;; by a small integer between 1 and 63. [0 is reserved for internal use.] ;;; CLISP, and maybe others, need EVAL-WHEN because without it, the constant @@ -46,9 +89,7 @@ ;;; A map from info-number to its META-INFO object. ;;; The reverse mapping is obtained by reading the META-INFO. (declaim (type (simple-vector #.(ash 1 info-number-bits)) *info-types*)) -(!define-load-time-global *info-types* - ;; Must be dumped as a literal for cold-load. - #.(make-array (ash 1 info-number-bits) :initial-element nil)) +(define-load-time-global *info-types* (make-array (ash 1 info-number-bits) :initial-element nil)) (defstruct (meta-info (:constructor @@ -81,37 +122,24 @@ (defconstant +info-metainfo-type-num+ 0) ;; Refer to info-vector.lisp for the meaning of this constant. -(defconstant +no-auxilliary-key+ 0) +(defconstant +no-auxiliary-key+ 0) ;;; Return the globaldb info for SYMBOL. With respect to the state diagram ;;; presented at the definition of SYMBOL-PLIST, if the object in SYMBOL's ;;; info slot is LISTP, it is in state 1 or 3. Either way, take the CDR. ;;; Otherwise, it is in state 2 so return the value as-is. -;;; In terms of this function being named "-vector", implying always a vector, -;;; it is understood that NIL is a proxy for +NIL-PACKED-INFOS+, a vector. +;;; NIL is an acceptable substitute for +NIL-PACKED-INFOS+, +;;; but I might change that. ;;; -;;; Define SYMBOL-INFO-VECTOR as an inline function unless a vop translates it. +;;; Define SYMBOL-INFO as an inline function unless a vop translates it. ;;; (Inlining occurs first, which would cause the vop not to be used.) -;;; Also note that we have to guard the appearance of VOP-TRANSLATES here -;;; so that it does not get tested when building the cross-compiler. -;;; This was the best way I could see to work around a spurious warning -;;; about a wrongly ordered VM definition in make-host-1. -;;; The #+/- reader can't see that a VOP-TRANSLATES term is not for the -;;; host compiler unless the whole thing is one expression. -#-(or sb-xc-host (vop-translates sb-kernel:symbol-info-vector)) -(progn -(declaim (inline symbol-info-vector)) -(defun symbol-info-vector (symbol) - (let ((info-holder (symbol-info symbol))) - (truly-the (or null simple-vector) - (if (listp info-holder) (cdr info-holder) info-holder))))) - -;;; SYMBOL-INFO is a primitive object accessor defined in 'objdef.lisp' -;;; But in the host Lisp, there is no such thing as a symbol-info slot. -;;; Instead, symbol-info is kept in the host symbol's plist. -;;; This must be a SETFable place. -#+sb-xc-host -(defmacro symbol-info-vector (symbol) `(get ,symbol :sb-xc-globaldb-info)) +#-sb-xc-host +(sb-c::unless-vop-existsp (:translate sb-kernel:symbol-dbinfo) + (declaim (inline symbol-dbinfo)) + (defun symbol-dbinfo (symbol) + (let ((info-holder (symbol-%info symbol))) + (truly-the (or null instance) + (if (listp info-holder) (cdr info-holder) info-holder))))) ;; Perform the equivalent of (GET-INFO-VALUE KIND +INFO-METAINFO-TYPE-NUM+) ;; but skipping the defaulting logic. @@ -119,19 +147,21 @@ ;; - though not always - a unique identifier for the (:TYPE :KIND) pair. ;; Note that bypassing of defaults is critical for bootstrapping, ;; since INFO is used to retrieve its own META-INFO at system-build time. -(defmacro !get-meta-infos (kind) - `(let* ((info-vector (symbol-info-vector ,kind)) - (index (if info-vector - (packed-info-value-index info-vector +no-auxilliary-key+ +(defmacro get-meta-infos (kind) + `(let* ((packed-info (symbol-dbinfo ,kind)) + (index (if packed-info + (packed-info-value-index packed-info +no-auxiliary-key+ +info-metainfo-type-num+)))) - (if index (svref info-vector index)))) + (if index (%info-ref packed-info index)))) -;; (UNSIGNED-BYTE 16) is an arbitrarily generous limit on the number of -;; cells in an info-vector. Most vectors have a fewer than a handful of things, +;; (UNSIGNED-BYTE 11) is an arbitrarily generous limit on the number of +;; cells in a packed-info. Most packed-infos have fewer than a handful of things, ;; and performance would need to be re-thought if more than about a dozen ;; cells were in use. (It would want to become hash-based probably) -(declaim (ftype (function (simple-vector (or (eql 0) symbol) info-number) - (or null (unsigned-byte 16))) +;; It has to be smaller than INSTANCE_LENGTH_MASK certainly, +;; plus leaving room for a layout slot if #-compact-instance-header. +(declaim (ftype (function (packed-info (or (eql 0) symbol) info-number) + (or null (unsigned-byte 11))) packed-info-value-index)) ;; Return the META-INFO object for CATEGORY and KIND, signaling an error @@ -144,7 +174,7 @@ ;; through, whereas typically no more than 3 or 4 items have the same KIND. ;; (defun meta-info (category kind &optional (errorp t)) - (or (let ((metadata (!get-meta-infos kind))) + (or (let ((metadata (get-meta-infos kind))) (cond ((listp metadata) ; conveniently handles NIL (dolist (info metadata nil) ; FIND is slower :-( (when (eq (meta-info-category (truly-the meta-info info)) @@ -152,7 +182,7 @@ (return info)))) ((eq (meta-info-category (truly-the meta-info metadata)) category) metadata))) - ;; !GET-META-INFOS enforces that KIND is a symbol, therefore + ;; GET-META-INFOS enforces that KIND is a symbol, therefore ;; if a metaobject was found, CATEGORY was necessarily a symbol too. ;; Otherwise, if the caller wants no error to be signaled on missing info, ;; we must nevertheless enforce that CATEGORY was actually a symbol. @@ -258,97 +288,3 @@ (meta-info-number (meta-info category kind)) `(meta-info-number (meta-info ,category ,kind))) ,name #',proc)))) - -;;;; boolean attribute utilities -;;;; -;;;; We need to maintain various sets of boolean attributes for known -;;;; functions and VOPs. To save space and allow for quick set -;;;; operations, we represent the attributes as bits in a fixnum. - -(in-package "SB-C") -(deftype attributes () 'fixnum) - -;;; Given a list of attribute names and an alist that translates them -;;; to masks, return the OR of the masks. -(defun encode-attribute-mask (names universe) - (loop for name in names - for pos = (position name universe) - sum (if pos (ash 1 pos) (error "unknown attribute name: ~S" name)))) - -(defun decode-attribute-mask (bits universe) - (loop for name across universe - for mask = 1 then (ash mask 1) - when (logtest mask bits) collect name)) - -;;; Define a new class of boolean attributes, with the attributes -;;; having the specified ATTRIBUTE-NAMES. NAME is the name of the -;;; class, which is used to generate some macros to manipulate sets of -;;; the attributes: -;;; -;;; NAME-attributep attributes attribute-name* -;;; Return true if one of the named attributes is present, false -;;; otherwise. When set with SETF, updates the place Attributes -;;; setting or clearing the specified attributes. -;;; -;;; NAME-attributes attribute-name* -;;; Return a set of the named attributes. -(defmacro !def-boolean-attribute (name &rest attribute-names) - (let ((vector (coerce attribute-names 'vector)) - (constructor (symbolicate name "-ATTRIBUTES")) - (test-name (symbolicate name "-ATTRIBUTEP"))) - `(progn - (defmacro ,constructor (&rest attribute-names) - "Automagically generated boolean attribute creation function. - See !DEF-BOOLEAN-ATTRIBUTE." - (encode-attribute-mask attribute-names ,vector)) - (defun ,(symbolicate "DECODE-" name "-ATTRIBUTES") (attributes) - (decode-attribute-mask attributes ,vector)) - (defmacro ,test-name (attributes &rest attribute-names) - "Automagically generated boolean attribute test function. - See !DEF-BOOLEAN-ATTRIBUTE." - `(logtest (the attributes ,attributes) - (,',constructor ,@attribute-names))) - (define-setf-expander ,test-name (place &rest attributes - &environment env) - "Automagically generated boolean attribute setter. See - !DEF-BOOLEAN-ATTRIBUTE." - (multiple-value-bind (temps values stores setter getter) - (#+sb-xc-host get-setf-expansion - #-sb-xc-host sb-xc:get-setf-expansion place env) - (when (cdr stores) - (error "multiple store variables for ~S" place)) - (let ((newval (sb-xc:gensym)) - (n-place (sb-xc:gensym)) - (mask (encode-attribute-mask attributes ,vector))) - (values `(,@temps ,n-place) - `(,@values ,getter) - `(,newval) - `(let ((,(first stores) - (if ,newval - (logior ,n-place ,mask) - (logandc2 ,n-place ,mask)))) - ,setter - ,newval) - `(,',test-name ,n-place ,@attributes)))))))) - -;;; And now for some gratuitous pseudo-abstraction... -;;; -;;; ATTRIBUTES-UNION -;;; Return the union of all the sets of boolean attributes which are its -;;; arguments. -;;; ATTRIBUTES-INTERSECTION -;;; Return the intersection of all the sets of boolean attributes which -;;; are its arguments. -;;; ATTRIBUTES= -;;; True if the attributes present in ATTR1 are identical to -;;; those in ATTR2. -(defmacro attributes-union (&rest attributes) - `(the attributes - (logior ,@(mapcar (lambda (x) `(the attributes ,x)) attributes)))) -(defmacro attributes-intersection (&rest attributes) - `(the attributes - (logand ,@(mapcar (lambda (x) `(the attributes ,x)) attributes)))) -(declaim (ftype (function (attributes attributes) boolean) attributes=)) -#-sb-fluid (declaim (inline attributes=)) -(defun attributes= (attr1 attr2) - (eql attr1 attr2)) diff --git a/src/compiler/early-lexenv.lisp b/src/compiler/early-lexenv.lisp deleted file mode 100644 index 14cfdee61c..0000000000 --- a/src/compiler/early-lexenv.lisp +++ /dev/null @@ -1,166 +0,0 @@ -;;;; This file contains early compiler-related structure definitions. - -;;;; This software is part of the SBCL system. See the README file for -;;;; more information. -;;;; -;;;; This software is derived from the CMU CL system, which was -;;;; written at Carnegie Mellon University and released into the -;;;; public domain. The software is in the public domain and is -;;;; provided with absolutely no warranty. See the COPYING and CREDITS -;;;; files for more information. - -(in-package "SB-C") - -(defconstant-eqx +policy-primary-qualities+ - #(;; ANSI standard qualities - compilation-speed - debug - safety - space - speed - ;; SBCL extensions - ;; - ;; FIXME: INHIBIT-WARNINGS is a misleading name for this. - ;; Perhaps BREVITY would be better. But the ideal name would - ;; have connotations of suppressing not warnings but only - ;; optimization-related notes, which is already mostly the - ;; behavior, and should probably become the exact behavior. - ;; Perhaps INHIBIT-NOTES? - inhibit-warnings) - #'equalp) - -(eval-when (:compile-toplevel :load-toplevel :execute) - (defconstant n-policy-primary-qualities (length +policy-primary-qualities+)) - ;; 1 bit per quality is stored to indicate whether it was explicitly given - ;; a value in a lexical policy. In addition to the 5 ANSI-standard qualities, - ;; SBCL defines one more "primary" quality and 16 dependent qualities. - ;; Both kinds take up 1 bit in the mask of specified qualities. - (defconstant max-policy-qualities 32)) - -;; Each primary and dependent quality policy is assigned a small integer index. -;; The POLICY struct represents a set of policies in an order-insensitive way -;; that facilitates quicker lookup than scanning an alist. -(defstruct (policy (:constructor make-policy - (primary-qualities &optional - presence-bits dependent-qualities))) - ;; Mask with a 1 for each quality that has an explicit value in this policy. - ;; Primary qualities fill the mask from left-to-right and dependent qualities - ;; from right-to-left. - ;; xc has trouble folding this MASK-FIELD, but it works when host-evaluated. - (presence-bits #.(mask-field - (byte n-policy-primary-qualities - (- max-policy-qualities n-policy-primary-qualities)) - -1) - :type (unsigned-byte #.max-policy-qualities)) - ;; For efficiency, primary qualities are segregated because there are few - ;; enough of them to fit in a fixnum. - (primary-qualities 0 :type (unsigned-byte #.(* 2 n-policy-primary-qualities))) - ;; 2 bits per dependent quality is a fixnum on 64-bit build, not on 32-bit. - ;; It would certainly be possible to constrain this to storing exactly - ;; the 16 currently defined dependent qualities, - ;; but that would be overly limiting. - (dependent-qualities 0 - :type (unsigned-byte #.(* (- max-policy-qualities n-policy-primary-qualities) - 2)))) -(declaim (freeze-type policy)) - -(defvar *handled-conditions* nil) -(defvar *disabled-package-locks* nil) - -;;; The LEXENV represents the lexical environment used for IR1 conversion. -;;; (This is also what shows up as an ENVIRONMENT value in macroexpansion.) -#-sb-fluid (declaim (inline internal-make-lexenv)) ; only called in one place -(defstruct (lexenv - (:include abstract-lexenv) - (:print-function - (lambda (lexenv stream depth) - (if (null-lexenv-p lexenv) - (print-unreadable-object (lexenv stream) - (write-string "NULL-LEXENV" stream)) - (default-structure-print lexenv stream depth)))) - (:copier nil) - (:constructor make-null-lexenv ()) - (:constructor make-almost-null-lexenv (%policy handled-conditions - flushable lambda parent)) - (:constructor make-package-lock-lexenv - (disabled-package-locks %policy - &aux (handled-conditions nil))) - (:constructor internal-make-lexenv - (funs vars blocks tags - type-restrictions - flushable - lambda cleanup handled-conditions - disabled-package-locks %policy user-data - parent))) - ;; an alist of (NAME . WHAT), where WHAT is either a FUNCTIONAL (a - ;; local function), a DEFINED-FUN, representing an - ;; INLINE/NOTINLINE declaration, or a list (MACRO . <function>) (a - ;; local macro, with the specifier expander). Note that NAME may be - ;; a (SETF <name>) list, not necessarily a single symbol. - (funs nil :type list) - ;; an alist translating variable names to LEAF structures. A special - ;; binding is indicated by a :SPECIAL GLOBAL-VAR leaf. Each special - ;; binding within the code gets a distinct leaf structure, as does - ;; the current "global" value on entry to the code compiled. - ;; (locally (special ...)) is handled by adding the most recent - ;; special binding to the front of the list. - ;; - ;; If the CDR is (MACRO . <exp>), then <exp> is the expansion of a - ;; symbol macro. - (vars nil :type list) - ;; BLOCKS and TAGS are alists from block and go-tag names to 2-lists - ;; of the form (<entry> <continuation>), where <continuation> is the - ;; continuation to exit to, and <entry> is the corresponding ENTRY - ;; node. - (blocks nil :type list) - (tags nil :type list) - ;; an alist (THING . CTYPE) which is used to keep track of - ;; "pervasive" type declarations. When THING is a leaf, this is for - ;; type declarations that pertain to the type in a syntactic extent - ;; which does not correspond to a binding of the affected name. - (type-restrictions nil :type list) - ;; the lexically enclosing lambda, if any - ;; - ;; FIXME: This should be :TYPE (OR CLAMBDA NULL), but it was too hard - ;; to get CLAMBDA defined in time for the cross-compiler. - (lambda nil) - ;; the lexically enclosing cleanup, or NIL if none enclosing within LAMBDA - (cleanup nil) - ;; condition types we handle with a handler around the compiler - (handled-conditions *handled-conditions*) - ;; lexically disabled package locks (list of symbols) - (disabled-package-locks *disabled-package-locks*) - ;; the current OPTIMIZE policy. this is null in the null environment, - ;; and the global policy is stored in *POLICY*. (Because we want to - ;; be able to affect it from :WITH-COMPILATION-UNIT.) NIL here also - ;; works as a convenient null-lexenv identifier. - (%policy nil :type (or null policy)) - ;; A list associating extra user info to symbols. The entries - ;; are of the form (:declare name . value), - ;; (:variable name key . value), or (:function name key . value) - (user-data nil :type list) - (parent nil) - ;; Cache of all visible variables, including the ones coming from - ;; (call-lexenv lambda) - ;; Used for LEAF-VISIBLE-TO-DEBUGGER-P - (var-cache nil :type (or null hash-table)) - ;; A list of functions that can be removed when unused. - ;; Similar to the FLUSHABLE attribute in DEFKNOWN, but can applied - ;; locally to things that are generally not flushable but can be - ;; flushed in some circumstances. - (flushable nil :type list)) - -;;; the lexical environment we are currently converting in -(defvar *lexenv*) -(declaim (type lexenv *lexenv*)) - -;;; an object suitable for input to standard functions that accept -;;; "environment objects" (of the ANSI glossary) -(def!type lexenv-designator () '(or abstract-lexenv null)) - -(defvar *policy*) -(defun lexenv-policy (lexenv) - (or (lexenv-%policy lexenv) *policy*)) - -(defun null-lexenv-p (lexenv) - (not (lexenv-%policy lexenv))) diff --git a/src/compiler/entry.lisp b/src/compiler/entry.lisp index c7a56cd7b4..b0784c2d92 100644 --- a/src/compiler/entry.lisp +++ b/src/compiler/entry.lisp @@ -14,7 +14,7 @@ (in-package "SB-C") ;;; This phase runs before IR2 conversion, initializing each XEP's -;;; ENTRY-INFO structure. If there was a forward reference to a function, +;;; ENTRY-INFO structure. If there was a forward reference to a function, ;;; then the ENTRY-INFO will already exist, but will be uninitialized. (defun entry-analyze (component) (let ((2comp (component-info component))) @@ -52,7 +52,7 @@ (let ((bind (lambda-bind fun)) (internal-fun (functional-entry-fun fun))) (setf (entry-info-closure-tn info) - (if (physenv-closure (lambda-physenv fun)) + (if (environment-closure (lambda-environment fun)) (make-normal-tn *backend-t-primitive-type*) nil)) (setf (entry-info-offset info) (gen-label)) @@ -60,7 +60,7 @@ (leaf-debug-name internal-fun)) (setf (entry-info-xref info) (pack-xref-data (functional-xref internal-fun))) (let* ((inline-expansion (functional-inline-expansion internal-fun)) - (form (if (fasl-output-p *compile-object*) + (form (if (producing-fasl-file) ;; If compiling to a file, we only store sources if the STORE-SOURCE ;; quality value is 3. If to memory, any nonzero value will do. (and (policy bind (= store-source-form 3)) @@ -90,8 +90,9 @@ missing MAKE-LOAD-FORM methods?") (compiler-style-warn "Can't preserve function source: ~A" (princ-to-string c))) - (return nil)))) - (constant-value (find-constant inline-expansion))))) + (return nil)))) + (maybe-emit-make-load-forms inline-expansion) + inline-expansion))) (and (policy bind (> store-source-form 0)) inline-expansion))) (doc (functional-documentation internal-fun))) @@ -103,8 +104,9 @@ missing MAKE-LOAD-FORM methods?") ;; points will be dumped. If they contain values that need ;; make-load-form processing then we need to do it now (bug ;; 310132). - (setf (entry-info-arguments info) - (constant-value (find-constant args)))) + (when (producing-fasl-file) + (maybe-emit-make-load-forms args)) + (setf (entry-info-arguments info) args)) ;; Arguably we should not parse/unparse if the type was obtained from ;; a proclamation. On the other hand, this preserves exact semantics ;; if a later DEFTYPE changes something. Be that as it may, storing @@ -112,12 +114,15 @@ missing MAKE-LOAD-FORM methods?") (let ((spec (type-specifier (leaf-type internal-fun))) (result)) (setf (entry-info-type info) - (if (and (listp spec) - (typep (setq result (third spec)) - '(cons (eql values) - (cons t (cons (eql &optional) null))))) - `(sfunction ,(cadr spec) ,(cadr result)) - spec))))) + (let ((type (if (and (listp spec) + (typep (setq result (third spec)) + '(cons (eql values) + (cons t (cons (eql &optional) null))))) + `(sfunction ,(cadr spec) ,(cadr result)) + spec))) + (when (producing-fasl-file) + (maybe-emit-make-load-forms type)) + type))))) (values)) ;;; Replace all references to COMPONENT's non-closure XEPs that appear @@ -154,7 +159,7 @@ missing MAKE-LOAD-FORM methods?") ;; It may have been deleted due to none of ;; the optional entries reaching it. (neq (functional-kind main-entry) :deleted) - (physenv-closure (lambda-physenv main-entry))))) + (environment-closure (lambda-environment main-entry))))) (dolist (ref (leaf-refs lambda)) (let ((ref-component (node-component ref))) (cond ((eq ref-component component)) diff --git a/src/compiler/physenvanal.lisp b/src/compiler/envanal.lisp similarity index 76% rename from src/compiler/physenvanal.lisp rename to src/compiler/envanal.lisp index b37ff1f733..c5f474cbcf 100644 --- a/src/compiler/physenvanal.lisp +++ b/src/compiler/envanal.lisp @@ -1,8 +1,8 @@ ;;;; This file implements the environment analysis phase for the ;;;; compiler. This phase annotates IR1 with a hierarchy environment -;;;; structures, determining the physical environment that each LAMBDA +;;;; structures, determining the environment that each LAMBDA ;;;; allocates its variables and finding what values are closed over -;;;; by each physical environment. +;;;; by each environment. ;;;; This software is part of the SBCL system. See the README file for ;;;; more information. @@ -17,16 +17,16 @@ ;;; Do environment analysis on the code in COMPONENT. This involves ;;; various things: -;;; 1. Make a PHYSENV structure for each non-LET LAMBDA, assigning -;;; the LAMBDA-PHYSENV for all LAMBDAs. +;;; 1. Make an ENVIRONMENT structure for each non-LET LAMBDA, assigning +;;; the LAMBDA-ENVIRONMENT for all LAMBDAs. ;;; 2. Find all values that need to be closed over by each -;;; physical environment. +;;; environment. ;;; 3. Scan the blocks in the component closing over non-local-exit ;;; continuations. ;;; 4. Delete all non-top-level functions with no references. This ;;; should only get functions with non-NULL kinds, since normal ;;; functions are deleted when their references go to zero. -(defun physenv-analyze (component) +(defun environment-analyze (component) (declare (type component component)) (aver (every (lambda (x) (eq (functional-kind x) :deleted)) @@ -50,31 +50,24 @@ (setf (functional-kind fun) nil) (delete-functional fun))))) - (setf (component-nlx-info-generated-p component) t) (values)) -;;; If CLAMBDA has a PHYSENV, return it, otherwise assign an empty one -;;; and return that. -(defun get-lambda-physenv (clambda) - (declare (type clambda clambda)) - (let ((homefun (lambda-home clambda))) - (or (lambda-physenv homefun) - (let ((res (make-physenv :lambda homefun))) - (setf (lambda-physenv homefun) res) - ;; All the LETLAMBDAs belong to HOMEFUN, and share the same - ;; PHYSENV. Thus, (1) since HOMEFUN's PHYSENV was NIL, - ;; theirs should be NIL too, and (2) since we're modifying - ;; HOMEFUN's PHYSENV, we should modify theirs, too. - (dolist (letlambda (lambda-lets homefun)) - (aver (eql (lambda-home letlambda) homefun)) - (aver (null (lambda-physenv letlambda))) - (setf (lambda-physenv letlambda) res)) +;;; If FUN has an environment, return it, otherwise assign an empty +;;; one and return that. +(defun get-lambda-environment (fun) + (declare (type clambda fun)) + (let ((fun (lambda-home fun))) + (or (lambda-environment fun) + (let ((res (make-environment :lambda fun))) + (setf (lambda-environment fun) res) + (dolist (lambda (lambda-lets fun)) + (setf (lambda-environment lambda) res)) res)))) ;;; Get NODE's environment, assigning one if necessary. -(defun get-node-physenv (node) +(defun get-node-environment (node) (declare (type node node)) - (get-lambda-physenv (node-home-lambda node))) + (get-lambda-environment (node-home-lambda node))) ;;; private guts of ADD-LAMBDA-VARS-AND-LET-VARS-TO-CLOSURES ;;; @@ -86,17 +79,17 @@ ;;; variables, not only the LAMBDA-VARS of CLAMBDA itself but also ;;; the LAMBDA-VARS of CLAMBDA's LAMBDA-LETS. (defun %add-lambda-vars-to-closures (clambda) - (let ((physenv (get-lambda-physenv clambda)) + (let ((env (get-lambda-environment clambda)) (did-something nil)) (note-unreferenced-fun-vars clambda) (dolist (var (lambda-vars clambda)) (dolist (ref (leaf-refs var)) - (let ((ref-physenv (get-node-physenv ref))) - (unless (eq ref-physenv physenv) + (let ((ref-env (get-node-environment ref))) + (unless (eq ref-env env) (when (lambda-var-sets var) (setf (lambda-var-indirect var) t)) (setq did-something t) - (close-over var ref-physenv physenv)))) + (close-over var ref-env env)))) (dolist (set (basic-var-sets var)) ;; Variables which are set but never referenced can be @@ -109,11 +102,11 @@ ;; here.) (unless (null (leaf-refs var)) - (let ((set-physenv (get-node-physenv set))) - (unless (eq set-physenv physenv) + (let ((set-env (get-node-environment set))) + (unless (eq set-env env) (setf did-something t (lambda-var-indirect var) t) - (close-over var set-physenv physenv)))))) + (close-over var set-env env)))))) did-something)) ;;; Find any variables in CLAMBDA -- either directly in LAMBDA-VARS or @@ -137,32 +130,30 @@ (setf did-something t))) did-something)) -(defun xep-allocator (xep) +(defun xep-enclose (xep) (let ((entry (functional-entry-fun xep))) - (functional-allocator entry))) + (functional-enclose entry))) -;;; Make sure that THING is closed over in REF-PHYSENV and in all -;;; PHYSENVs for the functions that reference REF-PHYSENV's function -;;; (not just calls). HOME-PHYSENV is THING's home environment. When we +;;; Make sure that THING is closed over in REF-ENV and in all +;;; environments for the functions that reference REF-ENV's function +;;; (not just calls). HOME-ENV is THING's home environment. When we ;;; reach the home environment, we stop propagating the closure. -(defun close-over (thing ref-physenv home-physenv) - (declare (type physenv ref-physenv home-physenv)) - (let ((flooded-physenvs nil)) - (labels ((flood (flooded-physenv) - (unless (or (eql flooded-physenv home-physenv) - (member flooded-physenv flooded-physenvs)) - (push flooded-physenv flooded-physenvs) - (unless (memq thing (physenv-closure flooded-physenv)) - (push thing (physenv-closure flooded-physenv)) - (let ((lambda (physenv-lambda flooded-physenv))) +(defun close-over (thing ref-env home-env) + (declare (type environment ref-env home-env)) + (let ((flooded-envs nil)) + (labels ((flood (flooded-env) + (unless (or (eql flooded-env home-env) + (member flooded-env flooded-envs)) + (push flooded-env flooded-envs) + (unless (memq thing (environment-closure flooded-env)) + (push thing (environment-closure flooded-env)) + (let ((lambda (environment-lambda flooded-env))) (cond ((eq (functional-kind lambda) :external) - (let* ((alloc-node (xep-allocator lambda)) - (alloc-lambda (node-home-lambda alloc-node)) - (alloc-physenv (get-lambda-physenv alloc-lambda))) - (flood alloc-physenv) + (let ((enclose-env (get-node-environment (xep-enclose lambda)))) + (flood enclose-env) (dolist (ref (leaf-refs lambda)) (close-over lambda - (get-node-physenv ref) alloc-physenv)))) + (get-node-environment ref) enclose-env)))) (t (dolist (ref (leaf-refs lambda)) ;; FIXME: This assertion looks ;; reasonable, but does not work for @@ -171,8 +162,8 @@ (let ((dest (node-dest ref))) (aver (basic-combination-p dest)) (aver (eq (basic-combination-kind dest) :local))) - (flood (get-node-physenv ref)))))))))) - (flood ref-physenv))) + (flood (get-node-environment ref)))))))))) + (flood ref-env))) (values)) ;;; Find LAMBDA-VARs that are marked as needing to support indirect @@ -206,7 +197,7 @@ ;; off the non-XEP case here. (not entry-fun) (leaf-dynamic-extent entry-fun)) - (let ((closure (physenv-closure (lambda-physenv fun)))) + (let ((closure (environment-closure (lambda-environment fun)))) (dolist (var closure) (when (and (lambda-var-p var) (lambda-var-indirect var)) @@ -281,7 +272,7 @@ t))) ;;; Insert the entry stub before the original exit target, and add a -;;; new entry to the PHYSENV-NLX-INFO. The %NLX-ENTRY call in the +;;; new entry to the ENVIRONMENT-NLX-INFO. The %NLX-ENTRY call in the ;;; stub is passed the NLX-INFO as an argument so that the back end ;;; knows what entry is being done. ;;; @@ -297,15 +288,15 @@ ;;; actually exiting the scope (i.e. a BLOCK), and will also do any ;;; other cleanups that may have to be done on the way. (defun insert-nlx-entry-stub (exit env) - (declare (type physenv env) (type exit exit)) + (declare (type environment env) (type exit exit)) (let* ((exit-block (node-block exit)) (next-block (first (block-succ exit-block))) (entry (exit-entry exit)) (cleanup (entry-cleanup entry)) - (info (make-nlx-info cleanup exit)) + (info (make-nlx-info cleanup (first (block-succ exit-block)))) (new-block (insert-cleanup-code (list exit-block) next-block entry - `(%nlx-entry ,(opaquely-quote info)) + `(%nlx-entry ',info) cleanup)) (component (block-component new-block))) (unlink-blocks exit-block new-block) @@ -315,8 +306,8 @@ (setf (exit-nlx-info exit) info) (setf (nlx-info-target info) new-block) (setf (nlx-info-safe-p info) (exit-should-check-tag-p exit)) - (push info (physenv-nlx-info env)) - (push info (cleanup-info cleanup)) + (push info (environment-nlx-info env)) + (push info (cleanup-nlx-info cleanup)) (when (member (cleanup-kind cleanup) '(:catch :unwind-protect)) (setf (node-lexenv (block-last new-block)) (node-lexenv entry)))) @@ -341,7 +332,7 @@ ;;; will be a use to represent the NLX use; 2) make life easier for ;;; the stack analysis. (defun note-non-local-exit (env exit) - (declare (type physenv env) (type exit exit)) + (declare (type environment env) (type exit exit)) (let ((lvar (node-lvar exit)) (exit-fun (node-home-lambda exit)) (info (find-nlx-info exit))) @@ -358,12 +349,12 @@ (insert-nlx-entry-stub exit env) (setq info (exit-nlx-info exit)) (aver info))) - (close-over info (node-physenv exit) env) + (close-over info (node-environment exit) env) (when (eq (functional-kind exit-fun) :escape) (mapc (lambda (x) (setf (node-derived-type x) *wild-type*)) (leaf-refs exit-fun)) - (substitute-leaf (find-constant (opaquely-quote info)) exit-fun)) + (substitute-leaf (find-constant info) exit-fun)) (when lvar (let ((node (block-last (nlx-info-target info)))) (unless (node-lvar node) @@ -379,10 +370,10 @@ (let ((*functional-escape-info* nil)) (dolist (lambda (component-lambdas component)) (dolist (entry (lambda-entries lambda)) - (let ((target-physenv (node-physenv entry))) + (let ((target-env (node-environment entry))) (dolist (exit (entry-exits entry)) - (aver (neq (node-physenv exit) target-physenv)) - (note-non-local-exit target-physenv exit)))))) + (aver (neq (node-environment exit) target-env)) + (note-non-local-exit target-env exit)))))) (values)) ;;;; final decision on stack allocation of dynamic-extent structures @@ -390,50 +381,48 @@ (declare (type component component)) (let (*dx-combination-p-check-local*) ;; catch unconverted combinations (dolist (lambda (component-lambdas component)) - (loop for entry in (lambda-entries lambda) - for cleanup = (entry-cleanup entry) - do (when (eq (cleanup-kind cleanup) :dynamic-extent) - (collect ((real-dx-lvars)) - (loop for what in (cleanup-info cleanup) - do (etypecase what - (cons - (let ((dx (car what)) - (lvar (cdr what))) - (cond ((lvar-good-for-dx-p lvar dx component) - ;; Since the above check does deep - ;; checks. we need to deal with the deep - ;; results in here as well. - (dolist (cell (handle-nested-dynamic-extent-lvars - dx lvar component)) - (let ((real (principal-lvar (cdr cell)))) - (setf (lvar-dynamic-extent real) cleanup) - (real-dx-lvars real)))) - (t - (note-no-stack-allocation lvar) - (setf (lvar-dynamic-extent lvar) nil))))) - (node ; DX closure - (let* ((call what) - (arg (first (basic-combination-args call))) - (funs (lvar-value arg)) - (dx nil)) - (dolist (fun funs) - (binding* ((() (leaf-dynamic-extent fun) - :exit-if-null) - (xep (functional-entry-fun fun) - :exit-if-null) - (closure (physenv-closure - (get-lambda-physenv xep)))) - (cond (closure - (setq dx t)) - (t - (setf (leaf-extent fun) nil))))) - (when dx - (setf (lvar-dynamic-extent arg) cleanup) - (real-dx-lvars arg)))))) - (let ((real-dx-lvars (delete-duplicates (real-dx-lvars)))) - (setf (cleanup-info cleanup) real-dx-lvars) - (setf (component-dx-lvars component) - (append real-dx-lvars (component-dx-lvars component))))))))) + ;; If this FUNCTIONAL is marked dynamic extent and also a + ;; closure, mark its ENCLOSE as DX by making it use an LVAR if + ;; it doesn't have one already. + (let ((fun (if (eq (lambda-kind lambda) :optional) + (lambda-optional-dispatch lambda) + lambda))) + (when (leaf-dynamic-extent fun) + (let ((xep (functional-entry-fun fun))) + (when (and xep (environment-closure (get-lambda-environment xep))) + (let ((enclose (functional-enclose fun))) + (when (and enclose (not (node-lvar enclose))) + (let ((lvar (make-lvar))) + (use-lvar enclose lvar) + (let ((cleanup (node-enclosing-cleanup (ctran-next (node-next enclose))))) + (aver (eq (cleanup-mess-up cleanup) enclose)) + (setf (lvar-dynamic-extent lvar) cleanup) + (setf (cleanup-nlx-info cleanup) (list lvar))) + (push lvar (component-dx-lvars component))))))))) + (dolist (entry (lambda-entries lambda)) + (let* ((cleanup (entry-cleanup entry)) + (*dx-lexenv* (node-lexenv (cleanup-mess-up cleanup)))) + (when (eq (cleanup-kind cleanup) :dynamic-extent) + (let ((real-dx-lvars '())) + (dolist (what (cleanup-nlx-info cleanup)) + (declare (type cons what)) + (let ((dx (car what)) + (lvar (cdr what))) + (cond ((lvar-good-for-dx-p lvar dx) + ;; Since the above check does deep + ;; checks. we need to deal with the deep + ;; results in here as well. + (dolist (cell (handle-nested-dynamic-extent-lvars + dx lvar)) + (let ((real (principal-lvar (cdr cell)))) + (setf (lvar-dynamic-extent real) cleanup) + (pushnew real real-dx-lvars)))) + (t + (note-no-stack-allocation lvar) + (setf (lvar-dynamic-extent lvar) nil))))) + (setf (cleanup-nlx-info cleanup) real-dx-lvars) + (setf (component-dx-lvars component) + (append real-dx-lvars (component-dx-lvars component))))))))) (values)) ;;;; cleanup emission @@ -466,26 +455,25 @@ (basic-combination-args node)))) (ecase (cleanup-kind cleanup) (:special-bind - (code `(%special-unbind ',(lvar-value (car args))))) + (code `(%special-unbind ',(leaf-source-name (lvar-value (car args)))))) (:catch - (code `(%catch-breakup ,(opaquely-quote (car (cleanup-info cleanup)))))) + (code `(%catch-breakup ',(car (cleanup-nlx-info cleanup))))) (:unwind-protect - (code `(%unwind-protect-breakup ,(opaquely-quote (car (cleanup-info cleanup))))) + (code `(%unwind-protect-breakup ',(car (cleanup-nlx-info cleanup)))) (let ((fun (ref-leaf (lvar-uses (second args))))) (when (functional-p fun) (reanalyze-funs fun) (code `(%funcall ,fun))))) ((:block :tagbody) - (dolist (nlx (cleanup-info cleanup)) - (code `(%lexical-exit-breakup ,(opaquely-quote nlx))))) + (dolist (nlx (cleanup-nlx-info cleanup)) + (code `(%lexical-exit-breakup ',nlx)))) (:dynamic-extent - (when (cleanup-info cleanup) + (when (cleanup-nlx-info cleanup) (code `(%cleanup-point)))) (:restore-nsp (code `(%primitive set-nsp ,(ref-leaf node)))))))) (flet ((coalesce-unbinds (code) - code - #+(vop-named sb-c:unbind-n) + (if (vop-existsp :named sb-c:unbind-n) (loop with cleanup while code do (setf cleanup (pop code)) @@ -495,7 +483,8 @@ ,@(loop while (eq (caar code) '%special-unbind) collect (cadar code) do (pop code))) - cleanup)))) + cleanup)) + code))) (when (code) (aver (not (node-tail-p (block-last (car pred-blocks))))) (insert-cleanup-code @@ -514,11 +503,11 @@ (declare (type component component)) (do-blocks (block1 component) (unless (block-to-be-deleted-p block1) - (let ((env1 (block-physenv block1)) + (let ((env1 (block-environment block1)) (cleanup1 (block-end-cleanup block1))) (dolist (block2 (block-succ block1)) (when (block-start block2) - (let ((env2 (block-physenv block2)) + (let ((env2 (block-environment block2)) (cleanup2 (block-start-cleanup block2))) (unless (or (not (eq env2 env1)) (eq cleanup1 cleanup2) @@ -536,7 +525,7 @@ (and (block-start pred) (eq (block-end-cleanup pred) cleanup1) - (eq (block-physenv pred) env2))) + (eq (block-environment pred) env2))) collect pred) block2)))))))) (values)) diff --git a/src/compiler/equality-constraints.lisp b/src/compiler/equality-constraints.lisp index 0855947569..ad0f9e504d 100644 --- a/src/compiler/equality-constraints.lisp +++ b/src/compiler/equality-constraints.lisp @@ -60,7 +60,7 @@ (let* ((x (ok-lvar-lambda-var (first args) constraints)) (second (second args)) (y (if (constant-lvar-p second) - (find-constant (lvar-value second)) + (nth-value 1 (lvar-value second)) (ok-lvar-lambda-var second constraints)))) (when (and x y) ;; TODO: inherit constraints @@ -204,3 +204,35 @@ (equality-constraint eql inverse) (equality-constraint = inverse)) result)) + +(defoptimizer (- equality-constraint) ((x y) node) + (let ((integer (specifier-type 'integer))) + (when (and (csubtypep (lvar-type x) integer) + (csubtypep (lvar-type y) integer)) + (macrolet ((f (op x y pos) + `(let ((constr (find-ref-equality-constraint ',op ,x ,y nil))) + (when constr + (if (constraint-not-p constr) + ,@(if pos + `((go GTEZ) (go LTZ)) + `((go LTEZ) (go GTZ))))))) + (derive (type) + `(progn + (derive-node-type node (specifier-type ',type)) + (go DONE)))) + (tagbody + (f < x y t) + (f > x y nil) + (f > y x t) + (f < y x nil) + (go DONE) + GTZ + (derive (integer (0))) + LTZ + (derive (integer * (0))) + GTEZ + (derive (integer 0)) + LTEZ + (derive (integer * 0)) + DONE)))) + :give-up) diff --git a/src/compiler/fixup-type.lisp b/src/compiler/fixup-type.lisp index 63231424fa..10f15d0548 100644 --- a/src/compiler/fixup-type.lisp +++ b/src/compiler/fixup-type.lisp @@ -5,7 +5,10 @@ (define-load-time-global *!initial-parsed-types* nil) (!cold-init-forms (dovector (saetp sb-vm:*specialized-array-element-type-properties*) - (setf (sb-vm:saetp-ctype saetp) (specifier-type (sb-vm:saetp-specifier saetp)))) + (setf (sb-vm:saetp-ctype saetp) (specifier-type (sb-vm:saetp-specifier saetp))) + #-sb-xc-host + (setf (aref sb-vm::*saetp-widetag-ctype* (ash (- (sb-vm:saetp-typecode saetp) 128) -2)) + (sb-vm:saetp-ctype saetp))) ;; This seems so weird and random. I really wanted to remove it, but ;; adding the :BUILTIN property makes sense because without it, the type ;; does not have a unique parse. Probably a missing entry in one of the @@ -26,6 +29,16 @@ (dovector (pair *!initial-parsed-types*) (destructuring-bind (spec . parse) pair (drop-all-hash-caches) ; start from a relative vacuum - (aver (equal (type-specifier parse) spec))))) + (unless (sb-kernel::brute-force-type-specifier-equalp (type-specifier parse) spec) + (let ((*print-length* nil)) + (write-string "parse/unparse: ") + (terpri) + (write spec) + (terpri) + (write parse) + (terpri) + (write (type-specifier parse)) + (terpri) + (bug "type parsed->unparse round-trip fail")))))) (!defun-from-collected-cold-init-forms !fixup-type-cold-init) diff --git a/src/compiler/fixup.lisp b/src/compiler/fixup.lisp index 6fe22f4eab..7f138f4e69 100644 --- a/src/compiler/fixup.lisp +++ b/src/compiler/fixup.lisp @@ -20,6 +20,10 @@ ;; assumptions about the contents of these fields; their semantics ;; are imposed by the dumper. (name nil :read-only t) + ;; FIXME: "-flavor" and "-kind" are completedly devoid of meaning. + ;; They former should probably be "fixup-referent-type" or "fixup-source" + ;; to indicate that it denotes a namespace for NAME, and latter should be + ;; "fixup-how" as it conveys a manner in which to modify encoded bytes. (flavor nil :read-only t) ;; OFFSET is an optional offset from whatever external label this ;; fixup refers to. Or in the case of the :CODE-OBJECT flavor of @@ -31,10 +35,12 @@ (offset 0 :type (or sb-vm:signed-word label) :read-only t)) +;;; A FIXUP-NOTE tells you where the assembly patch is to be performed (defstruct (fixup-note (:constructor make-fixup-note (kind fixup position)) (:copier nil)) - kind - fixup - position) + ;; KIND is architecture-dependent (see the various 'vm' files) + (kind nil :type symbol) + (fixup (missing-arg) :type fixup) + (position 0 :type fixnum)) (declaim (freeze-type fixup fixup-note)) diff --git a/src/compiler/float-tran.lisp b/src/compiler/float-tran.lisp index 4bd2ed5b25..2813ea7d23 100644 --- a/src/compiler/float-tran.lisp +++ b/src/compiler/float-tran.lisp @@ -15,10 +15,10 @@ ;;;; coercions -(deftransform float ((n f) (* single-float) *) +(deftransform float ((n f) (t single-float) *) '(%single-float n)) -(deftransform float ((n f) (* double-float) *) +(deftransform float ((n f) (t double-float) *) '(%double-float n)) (deftransform float ((n) *) @@ -29,13 +29,25 @@ (deftransform %single-float ((n) (single-float) *) 'n) +(deftransform %single-float ((n) (ratio) *) + '(sb-kernel::float-ratio n 'single-float)) + +(deftransform %single-float ((n) (bignum) *) + '(bignum-to-float n 'single-float)) + (deftransform %double-float ((n) (double-float) *) 'n) +(deftransform %double-float ((n) (ratio) *) + '(sb-kernel::float-ratio n 'double-float)) + +(deftransform %double-float ((n) (bignum) *) + '(bignum-to-float n 'double-float)) + ;;; RANDOM (macrolet ((frob (fun type) `(deftransform random ((num &optional state) - (,type &optional *) *) + (,type &optional t) *) "Use inline float operations." '(,fun num (or state *random-state*))))) (frob %random-single-float single-float) @@ -67,7 +79,7 @@ ;;; a division to get the random value into the desired range. (deftransform random ((num &optional state) ((constant-arg (integer 1 #.(expt 2 sb-vm:n-word-bits))) - &optional *) + &optional t) * :policy (and (> speed compilation-speed) (> speed space))) @@ -147,16 +159,15 @@ ;;; when given a signaling NaN. (deftransform float-sign ((float &optional float2) (single-float &optional single-float) *) - #+(vop-translates sb-kernel:single-float-copysign) - (if float2 - `(single-float-copysign float float2) - `(single-float-sign float)) - #-(vop-translates sb-kernel:single-float-copysign) - (if float2 - (let ((temp (gensym))) - `(let ((,temp (abs float2))) - (if (minusp (single-float-bits float)) (- ,temp) ,temp))) - '(if (minusp (single-float-bits float)) $-1f0 $1f0))) + (if (vop-existsp :translate single-float-copysign) + (if float2 + `(single-float-copysign float float2) + `(single-float-sign float)) + (if float2 + (let ((temp (gensym))) + `(let ((,temp (abs float2))) + (if (minusp (single-float-bits float)) (- ,temp) ,temp))) + '(if (minusp (single-float-bits float)) $-1f0 $1f0)))) (deftransform float-sign ((float &optional float2) (double-float &optional double-float) *) @@ -169,6 +180,21 @@ `(let ((,temp (abs float2))) (if (minusp ,bits) (- ,temp) ,temp))) `(if (minusp ,bits) $-1d0 $1d0)))) + +;;; This doesn't deal with complex at the moment. +(deftransform signum ((x) (number)) + (let* ((ctype (lvar-type x)) + (result-type + (dolist (x '(single-float double-float rational)) + (when (csubtypep ctype (specifier-type x)) + (return x))))) + ;; SB-XC:COERCE doesn't like RATIONAL for some reason. + (when (eq result-type 'rational) (setq result-type 'integer)) + (if result-type + `(cond ((zerop x) x) + ((plusp x) ,(sb-xc:coerce 1 result-type)) + (t ,(sb-xc:coerce -1 result-type))) + (give-up-ir1-transform)))) ;;;; DECODE-FLOAT, INTEGER-DECODE-FLOAT, and SCALE-FLOAT @@ -206,7 +232,7 @@ (deftransform integer-decode-float ((x) (double-float) *) '(integer-decode-double-float x)) -(deftransform scale-float ((f ex) (single-float *) *) +(deftransform scale-float ((f ex) (single-float t) *) (cond #+x86 ((csubtypep (lvar-type ex) (specifier-type '(signed-byte 32))) @@ -214,7 +240,7 @@ (t '(scale-single-float f ex)))) -(deftransform scale-float ((f ex) (double-float *) *) +(deftransform scale-float ((f ex) (double-float t) *) (cond #+x86 ((csubtypep (lvar-type ex) (specifier-type '(signed-byte 32))) @@ -225,7 +251,7 @@ ;;; Given a number X, create a form suitable as a bound for an ;;; interval. Make the bound open if OPEN-P is T. NIL remains NIL. ;;; FIXME: as this is a constructor, shouldn't it be named MAKE-BOUND? -#-sb-fluid (declaim (inline set-bound)) +(declaim (inline set-bound)) (defun set-bound (x open-p) (if (and x open-p) (list x) x)) @@ -305,9 +331,20 @@ (type-error () nil))))))) (frob %single-float single-float - sb-xc:most-negative-single-float sb-xc:most-positive-single-float) + most-negative-single-float most-positive-single-float) (frob %double-float double-float - sb-xc:most-negative-double-float sb-xc:most-positive-double-float)) + most-negative-double-float most-positive-double-float)) + +(defoptimizer (float derive-type) ((number prototype)) + (let ((type (lvar-type prototype))) + (unless (or (csubtypep type (specifier-type 'double-float)) + (csubtypep type (specifier-type 'single-float))) + (handler-case + (type-union + (one-arg-derive-type number #'%single-float-derive-type-aux #'%single-float) + (one-arg-derive-type number #'%double-float-derive-type-aux #'%double-float)) + (type-error () + nil))))) ;;;; float contagion @@ -324,33 +361,63 @@ ;;; Do some stuff to recognize when the loser is doing mixed float and ;;; rational arithmetic, or different float types, and fix it up. If -;;; we don't, he won't even get so much as an efficiency note. +;;; we don't, we won't even get so much as an efficiency note. ;;; Unfortunately this produces unnecessarily bad code for something ;;; as simple as (ZEROP (THE FLOAT X)) because we _know_ that the thing ;;; is a float, but the ZEROP transform injected a rational 0, ;;; which we then go to the trouble of coercing to a float. -(deftransform float-contagion-arg1 ((x y) * * :defun-only t :node node) - (if (or (not (types-equal-or-intersect (lvar-type y) (specifier-type 'single-float))) - (safe-ctype-for-single-coercion-p (lvar-type x))) - `(,(lvar-fun-name (basic-combination-fun node)) - (float x y) y) - (give-up-ir1-transform))) -(deftransform float-contagion-arg2 ((x y) * * :defun-only t :node node) - (if (or (not (types-equal-or-intersect (lvar-type x) (specifier-type 'single-float))) - (safe-ctype-for-single-coercion-p (lvar-type y))) - `(,(lvar-fun-name (basic-combination-fun node)) - x (float y x)) - (give-up-ir1-transform))) - -(dolist (x '(+ * / -)) - (%deftransform x '(function (rational float) *) #'float-contagion-arg1) - (%deftransform x '(function (float rational) *) #'float-contagion-arg2)) - -(dolist (x '(= < > <= >= + * / -)) - (%deftransform x '(function (single-float double-float) *) - #'float-contagion-arg1) - (%deftransform x '(function (double-float single-float) *) - #'float-contagion-arg2)) +(progn + (deftransform real-float-contagion-arg1 ((x y) * * :defun-only t :node node) + "open-code float conversion in mixed numeric operation" + (if (or (not (types-equal-or-intersect (lvar-type y) (specifier-type 'single-float))) + (safe-ctype-for-single-coercion-p (lvar-type x))) + `(,(lvar-fun-name (basic-combination-fun node)) (float x y) y) + (give-up-ir1-transform #1="the first argument cannot safely be converted to SINGLE-FLOAT"))) + (deftransform complex-float-contagion-arg1 ((x y) * * :defun-only t :node node) + "open-code float conversion in mixed numeric operation" + (if (or (not (types-equal-or-intersect + (lvar-type y) (specifier-type '(complex single-float)))) + (safe-ctype-for-single-coercion-p (lvar-type x))) + `(,(lvar-fun-name (basic-combination-fun node)) + (float x (realpart y)) y) + (give-up-ir1-transform #1#))) + (deftransform real-float-contagion-arg2 ((x y) * * :defun-only t :node node) + "open-code float conversion in mixed numeric operation" + (if (or (not (types-equal-or-intersect (lvar-type x) (specifier-type 'single-float))) + (safe-ctype-for-single-coercion-p (lvar-type y))) + `(,(lvar-fun-name (basic-combination-fun node)) x (float y x)) + (give-up-ir1-transform #2="the second argument cannot safely be converted to SINGLE-FLOAT"))) + (deftransform complex-float-contagion-arg2 ((x y) * * :defun-only t :node node) + "open-code float conversion in mixed numeric operation" + (if (or (not (types-equal-or-intersect (lvar-type x) (specifier-type '(complex single-float)))) + (safe-ctype-for-single-coercion-p (lvar-type y))) + `(,(lvar-fun-name (basic-combination-fun node)) + x (float y (realpart x))) + (give-up-ir1-transform #2#)))) + +(flet ((def (operator float-type other-type complexp argument) + (multiple-value-bind (type1 type2 function) + (ecase argument + (1 (if complexp + (values other-type `(complex ,float-type) #'complex-float-contagion-arg1) + (values other-type float-type #'real-float-contagion-arg1))) + (2 (if complexp + (values `(complex ,float-type) other-type #'complex-float-contagion-arg2) + (values float-type other-type #'real-float-contagion-arg2)))) + (%deftransform operator nil `(function (,type1 ,type2) *) function)))) + + (dolist (operator '(+ * / -)) + (def operator 'float 'rational nil 1) + (def operator 'float 'rational nil 2) + (def operator 'float 'rational t 1) + (def operator 'float 'rational t 2)) + + (dolist (operator '(= < > <= >= + * / -)) + (def operator 'double-float 'single-float nil 1) + (def operator 'double-float 'single-float nil 2) + (when (member operator '(= + * / -)) + (def operator 'double-float 'single-float t 1) + (def operator 'double-float 'single-float t 2)))) (macrolet ((def (type &rest args) `(deftransform * ((x y) (,type (constant-arg (member ,@args))) * @@ -435,10 +502,17 @@ (give-up-ir1-transform "The RATIONAL value isn't known at compile time.")) (let ((val (lvar-value y))) - (unless (eql (rational (float val)) val) - (give-up-ir1-transform - "~S doesn't have a precise float representation." - val))) + (multiple-value-bind (low high type) + (if (csubtypep (lvar-type x) (specifier-type 'double-float)) + (values most-negative-double-float most-positive-double-float + 'double-float) + (values most-negative-single-float most-positive-single-float + 'single-float)) + (unless (and (sb-xc:<= low val high) + (eql (rational (coerce val type)) val)) + (give-up-ir1-transform + "~S doesn't have a precise float representation." + val)))) `(,',op x (float y ,',(if complex '(realpart x) 'x)))))) @@ -513,15 +587,15 @@ (deftransform atan ((x y) (double-float double-float) *) `(%atan2 x y)) -(deftransform expt ((x y) ((single-float $0f0) single-float) *) +(deftransform expt ((x y) (single-float single-float) single-float) `(coerce (%pow (coerce x 'double-float) (coerce y 'double-float)) - 'single-float)) -(deftransform expt ((x y) ((double-float $0d0) double-float) *) + 'single-float)) +(deftransform expt ((x y) (double-float double-float) double-float) `(%pow x y)) -(deftransform expt ((x y) ((single-float $0f0) (signed-byte 32)) *) +(deftransform expt ((x y) (single-float integer) single-float) `(coerce (%pow (coerce x 'double-float) (coerce y 'double-float)) 'single-float)) -(deftransform expt ((x y) ((double-float $0d0) (signed-byte 32)) *) +(deftransform expt ((x y) (double-float integer) double-float) `(%pow x (coerce y 'double-float))) ;;; ANSI says log with base zero returns zero. @@ -548,7 +622,7 @@ (deftransform phase ((x) ((float)) float) '(if (minusp (float-sign x)) - (float sb-xc:pi x) + (float pi x) (float 0 x))) ;;; The number is of type REAL. @@ -575,15 +649,21 @@ ;;; should be the right kind of float. Allow bounds for the float ;;; part too. (defun float-or-complex-float-type (arg &optional lo hi) - (declare (type numeric-type arg)) - (let* ((format (case (numeric-type-class arg) - ((integer rational) 'single-float) - (t (numeric-type-format arg)))) - (float-type (or format 'float)) - (lo (coerce-numeric-bound lo float-type)) - (hi (coerce-numeric-bound hi float-type))) - (specifier-type `(or (,float-type ,(or lo '*) ,(or hi '*)) - (complex ,float-type))))) + (cond + ((numeric-type-p arg) + (let* ((format (case (numeric-type-class arg) + ((integer rational) 'single-float) + (t (numeric-type-format arg)))) + (float-type (or format 'float)) + (lo (coerce-numeric-bound lo float-type)) + (hi (coerce-numeric-bound hi float-type))) + (specifier-type `(or (,float-type ,(or lo '*) ,(or hi '*)) + (complex ,float-type))))) + ((union-type-p arg) + (apply #'type-union + (loop for type in (union-type-types arg) + collect (float-or-complex-float-type type lo hi)))) + (t (specifier-type 'number)))) (eval-when (:compile-toplevel :execute) ;; So the problem with this hack is that it's actually broken. If @@ -733,10 +813,10 @@ ;; These functions are only defined for part of the real line. The ;; condition selects the desired part of the line. - (frob asin $-1d0 $1d0 (sb-xc:- (sb-xc:/ sb-xc:pi 2)) (sb-xc:/ sb-xc:pi 2)) + (frob asin $-1d0 $1d0 (sb-xc:- (sb-xc:/ pi 2)) (sb-xc:/ pi 2)) ;; Acos is monotonic decreasing, so we need to swap the function ;; values at the lower and upper bounds of the input domain. - (frob acos $-1d0 $1d0 0 sb-xc:pi :increasingp nil) + (frob acos $-1d0 $1d0 0 pi :increasingp nil) (frob acosh $1d0 nil nil nil) (frob atanh $-1d0 $1d0 -1 1) ;; Kahan says that (sqrt -0.0) is -0.0, so use a specifier that @@ -787,7 +867,7 @@ (list (interval-expt-> x y-) (interval-expt-> x y+)))))) -;;; Handle the case when x <= 1 +;;; Handle the case when 0 <= x <= 1 (defun interval-expt-< (x y) (case (interval-range-info x $0d0) (+ @@ -818,9 +898,13 @@ (interval-expt-< x y+)))))) (- ;; The case where x <= 0. Y MUST be an INTEGER for this to work! - ;; The calling function must insure this! For now we'll just - ;; return the appropriate unbounded float type. - (list (make-interval :low nil :high nil))) + ;; The calling function must insure this! + (loop for interval in (flatten-list (interval-expt (interval-neg x) y)) + for low = (interval-low interval) + for high = (interval-high interval) + collect interval + when (or high low) + collect (interval-neg interval))) (t (destructuring-bind (neg pos) (interval-split 0 x t t) @@ -853,11 +937,20 @@ ;; Positive integer to an integer power is either an ;; integer or a rational. (let ((lo (or (interval-low bnd) '*)) - (hi (or (interval-high bnd) '*))) - (if (and (interval-low y-int) - (>= (type-bound-number (interval-low y-int)) 0)) - (specifier-type `(integer ,lo ,hi)) - (specifier-type `(rational ,lo ,hi))))) + (hi (or (interval-high bnd) '*)) + (y-lo (interval-low y-int)) + (y-hi (interval-high y-int))) + (cond ((and (eq lo '*) + (eql y-lo y-hi) + (typep y-lo 'unsigned-byte) + (evenp y-lo)) + (specifier-type `(integer 0 ,hi))) + ((and (interval-low y-int) + (>= (type-bound-number y-lo) 0)) + + (specifier-type `(integer ,lo ,hi))) + (t + (specifier-type `(rational ,lo ,hi)))))) (rational ;; Positive integer to rational power is either a rational ;; or a single-float. @@ -959,19 +1052,27 @@ (fixup-interval-expt type x-int y-int x y)) (flatten-list (interval-expt x-int y-int))))) +(defun integer-float-p (float) + (and (floatp float) + (or + #-sb-xc-host + (multiple-value-bind (significand exponent) (integer-decode-float float) + (or (plusp exponent) + (<= (- exponent) (sb-kernel::first-bit-set significand))))))) + (defun expt-derive-type-aux (x y same-arg) (declare (ignore same-arg)) (cond ((or (not (numeric-type-real-p x)) (not (numeric-type-real-p y))) ;; Use numeric contagion if either is not real. (numeric-contagion x y)) - ((csubtypep y (specifier-type 'integer)) + ((or (csubtypep y (specifier-type 'integer)) + (integer-float-p (nth-value 1 (type-singleton-p y)))) ;; A real raised to an integer power is well-defined. (merged-interval-expt x y)) ;; A real raised to a non-integral power can be a float or a ;; complex number. - ((or (csubtypep x (specifier-type '(rational 0))) - (csubtypep x (specifier-type '(float ($0d0))))) + ((csubtypep x (specifier-type '(real 0))) ;; But a positive real to any power is well-defined. (merged-interval-expt x y)) ((and (csubtypep x (specifier-type 'rational)) @@ -1009,7 +1110,7 @@ (one-arg-derive-type x #'log-derive-type-aux-1 #'log))) (defun atan-derive-type-aux-1 (y) - (elfun-derive-type-simple y #'atan nil nil (sb-xc:- (sb-xc:/ sb-xc:pi 2)) (sb-xc:/ sb-xc:pi 2))) + (elfun-derive-type-simple y #'atan nil nil (sb-xc:- (sb-xc:/ pi 2)) (sb-xc:/ pi 2))) (defun atan-derive-type-aux-2 (y x same-arg) (declare (ignore same-arg)) @@ -1026,8 +1127,8 @@ (make-numeric-type :class 'float :format format :complexp :real - :low (coerce (sb-xc:- sb-xc:pi) bound-format) - :high (coerce sb-xc:pi bound-format)))) + :low (coerce (sb-xc:- pi) bound-format) + :high (coerce pi bound-format)))) (t ;; The result is a float or a complex number (float-or-complex-float-type result-type))))) @@ -1067,8 +1168,8 @@ (make-numeric-type :class 'float :format format :complexp :real - :low (coerce sb-xc:pi bound-type) - :high (coerce sb-xc:pi bound-type))) + :low (coerce pi bound-type) + :high (coerce pi bound-type))) (t ;; We can't tell. The result is 0 or pi. Use a union ;; type for this. @@ -1081,16 +1182,16 @@ (make-numeric-type :class 'float :format format :complexp :real - :low (coerce sb-xc:pi bound-type) - :high (coerce sb-xc:pi bound-type)))))) + :low (coerce pi bound-type) + :high (coerce pi bound-type)))))) (t ;; We have a complex number. The answer is the range -pi ;; to pi. (-pi is included because we have -0.) (make-numeric-type :class 'float :format format :complexp :real - :low (coerce (sb-xc:- sb-xc:pi) bound-type) - :high (coerce sb-xc:pi bound-type)))))) + :low (coerce (sb-xc:- pi) bound-type) + :high (coerce pi bound-type)))))) (defoptimizer (phase derive-type) ((num)) (one-arg-derive-type num #'phase-derive-type-aux #'phase)) @@ -1227,8 +1328,7 @@ ;; of whether all the operations below are translated by vops. ;; We could be more fine-grained, but it seems reasonable that ;; they be implemented on an all-or-none basis. - #-(vop-named sb-vm::%negate/complex-double-float) - (progn + (unless (vop-existsp :named sb-vm::%negate/complex-double-float) ;; negation (deftransform %negate ((z) ((complex ,type)) *) '(complex (%negate (realpart z)) (%negate (imagpart z)))) @@ -1284,55 +1384,53 @@ ;; Divide two complex numbers. (deftransform / ((x y) ((complex ,type) (complex ,type)) *) - #-(vop-translates sb-vm::swap-complex) - '(let* ((rx (realpart x)) - (ix (imagpart x)) - (ry (realpart y)) - (iy (imagpart y))) - (if (> (abs ry) (abs iy)) - (let* ((r (/ iy ry)) - (dn (+ ry (* r iy)))) - (complex (/ (+ rx (* ix r)) dn) - (/ (- ix (* rx r)) dn))) - (let* ((r (/ ry iy)) - (dn (+ iy (* r ry)))) - (complex (/ (+ (* rx r) ix) dn) - (/ (- (* ix r) rx) dn))))) - #+(vop-translates sb-vm::swap-complex) - `(let* ((cs (conjugate (sb-vm::swap-complex x))) - (ry (realpart y)) - (iy (imagpart y))) - (if (> (abs ry) (abs iy)) - (let* ((r (/ iy ry)) - (dn (+ ry (* r iy)))) - (/ (+ x (* cs r)) dn)) - (let* ((r (/ ry iy)) - (dn (+ iy (* r ry)))) - (/ (+ (* x r) cs) dn))))) + (if (vop-existsp :translate sb-vm::swap-complex) + '(let* ((cs (conjugate (sb-vm::swap-complex x))) + (ry (realpart y)) + (iy (imagpart y))) + (if (> (abs ry) (abs iy)) + (let* ((r (/ iy ry)) + (dn (+ ry (* r iy)))) + (/ (+ x (* cs r)) dn)) + (let* ((r (/ ry iy)) + (dn (+ iy (* r ry)))) + (/ (+ (* x r) cs) dn)))) + '(let* ((rx (realpart x)) + (ix (imagpart x)) + (ry (realpart y)) + (iy (imagpart y))) + (if (> (abs ry) (abs iy)) + (let* ((r (/ iy ry)) + (dn (+ ry (* r iy)))) + (complex (/ (+ rx (* ix r)) dn) + (/ (- ix (* rx r)) dn))) + (let* ((r (/ ry iy)) + (dn (+ iy (* r ry)))) + (complex (/ (+ (* rx r) ix) dn) + (/ (- (* ix r) rx) dn))))))) ;; Divide a real by a complex. (deftransform / ((x y) (,type (complex ,type)) *) - #-(vop-translates sb-vm::swap-complex) - '(let* ((ry (realpart y)) - (iy (imagpart y))) - (if (> (abs ry) (abs iy)) - (let* ((r (/ iy ry)) - (dn (+ ry (* r iy)))) - (complex (/ x dn) - (/ (- (* x r)) dn))) - (let* ((r (/ ry iy)) - (dn (+ iy (* r ry)))) - (complex (/ (* x r) dn) - (/ (- x) dn))))) - #+(vop-translates sb-vm::swap-complex) - '(let* ((ry (realpart y)) - (iy (imagpart y))) - (if (> (abs ry) (abs iy)) - (let* ((r (/ iy ry)) - (dn (+ ry (* r iy)))) - (/ (complex x (- (* x r))) dn)) - (let* ((r (/ ry iy)) - (dn (+ iy (* r ry)))) - (/ (complex (* x r) (- x)) dn))))) + (if (vop-existsp :translate sb-vm::swap-complex) + '(let* ((ry (realpart y)) + (iy (imagpart y))) + (if (> (abs ry) (abs iy)) + (let* ((r (/ iy ry)) + (dn (+ ry (* r iy)))) + (/ (complex x (- (* x r))) dn)) + (let* ((r (/ ry iy)) + (dn (+ iy (* r ry)))) + (/ (complex (* x r) (- x)) dn)))) + '(let* ((ry (realpart y)) + (iy (imagpart y))) + (if (> (abs ry) (abs iy)) + (let* ((r (/ iy ry)) + (dn (+ ry (* r iy)))) + (complex (/ x dn) + (/ (- (* x r)) dn))) + (let* ((r (/ ry iy)) + (dn (+ iy (* r ry)))) + (complex (/ (* x r) dn) + (/ (- x) dn))))))) ;; CIS (deftransform cis ((z) ((,type)) *) '(complex (cos z) (sin z))) @@ -1395,7 +1493,7 @@ ;; Derive the bounds if the arg is in [-pi/2, pi/2]. (trig-derive-type-aux arg - (specifier-type `(float ,(sb-xc:- (sb-xc:/ sb-xc:pi 2)) ,(sb-xc:/ sb-xc:pi 2))) + (specifier-type `(float ,(sb-xc:- (sb-xc:/ pi 2)) ,(sb-xc:/ pi 2))) #'sin -1 1)) #'sin)) @@ -1406,7 +1504,7 @@ (lambda (arg) ;; Derive the bounds if the arg is in [0, pi]. (trig-derive-type-aux arg - (specifier-type `(float $0d0 ,sb-xc:pi)) + (specifier-type `(float $0d0 ,pi)) #'cos -1 1 nil)) @@ -1418,8 +1516,8 @@ (lambda (arg) ;; Derive the bounds if the arg is in [-pi/2, pi/2]. (trig-derive-type-aux arg - (specifier-type `(float ,(sb-xc:- (sb-xc:/ sb-xc:pi 2)) - ,(sb-xc:/ sb-xc:pi 2))) + (specifier-type `(float ,(sb-xc:- (sb-xc:/ pi 2)) + ,(sb-xc:/ pi 2))) #'tan nil nil)) #'tan)) @@ -1455,23 +1553,107 @@ ;;;; TRUNCATE, FLOOR, CEILING, and ROUND - -(macrolet ((define-frobs (fun ufun) - `(deftransform ,fun ((x &optional by) - (* &optional (constant-arg (member 1)))) - '(let ((res (,ufun x))) - (values res (locally - (declare (flushable %single-float - %double-float)) - (- x res))))))) - (define-frobs truncate %unary-truncate) - (define-frobs round %unary-round)) +(deftransform truncate ((x &optional by) + (t &optional (constant-arg (member 1)))) + '(unary-truncate x)) + +(deftransform round ((x &optional by) + (t &optional (constant-arg (member 1)))) + '(let ((res (%unary-round x))) + (values res (locally + (declare (flushable %single-float + %double-float)) + (- x res))))) (deftransform %unary-truncate ((x) (single-float)) `(%unary-truncate/single-float x)) (deftransform %unary-truncate ((x) (double-float)) `(%unary-truncate/double-float x)) +(defun value-within-numeric-type (type) + (labels ((try (x) + (when (ctypep x type) + (return-from value-within-numeric-type x))) + #-sb-xc-host + (next-float (float) + (multiple-value-bind (frac exp sign) + (integer-decode-float float) + (* (scale-float (float (1+ frac) float) exp) + sign))) + #-sb-xc-host + (prev-float (float) + (multiple-value-bind (frac exp sign) + (integer-decode-float float) + (* (scale-float (float (1- frac) float) exp) + sign))) + (next (x) + (typecase x + (integer + (1+ x)) + #-sb-xc-host + (float + (next-float x)) + (t + 0))) + (prev (x) + (typecase x + (integer + (1- x)) + #-sb-xc-host + (float + (prev-float x)) + (t + 0))) + (ratio-between (low high) + (+ low (/ (- high low) 2))) + (numeric (x) + (when (numeric-type-p x) + (let ((lo (numeric-type-low x)) + (hi (numeric-type-high x))) + (when (numberp lo) + (try lo)) + (when (numberp hi) + (try hi)) + (when (consp lo) + (try (next (car lo)))) + (when (consp hi) + (try (prev (car hi)))) + (when (and (typep lo '(cons rational)) + (typep hi '(cons rational))) + (try (ratio-between (car lo) (car hi)))) + (when (csubtypep x (specifier-type 'rational)) + (try 0)) + (when (csubtypep x (specifier-type 'double-float)) + (try $0d0)) + (when (csubtypep x (specifier-type 'single-float)) + (try $0f0)))))) + (typecase type + (numeric-type (numeric type)) + (union-type (mapc #'numeric (union-type-types type)))) + (error "Couldn't come up with a value for ~s" type))) + +(deftransform unary-truncate ((x) * * :result result :node node) + (unless (lvar-single-value-p result) + (give-up-ir1-transform)) + (let ((rem-type (second (values-type-required (node-derived-type node))))) + `(values (%unary-truncate x) + ,(value-within-numeric-type rem-type)))) + +(macrolet ((def (type) + `(deftransform unary-truncate ((number) (,type)) + '(if (typep number + '(,type + ,(symbol-value (package-symbolicate :sb-kernel 'most-negative-fixnum- type)) + ,(symbol-value (package-symbolicate :sb-kernel 'most-positive-fixnum- type)))) + (let ((truncated (truly-the fixnum (%unary-truncate number)))) + (declare (flushable ,(symbolicate "%" type))) + (values truncated + (- number + (coerce truncated ',type)))) + (,(symbolicate 'unary-truncate- type '-to-bignum) number))))) + (def single-float) + (def double-float)) + ;;; Convert (TRUNCATE x y) to the obvious implementation. ;;; ;;; ...plus hair: Insert explicit coercions to appropriate float types: Python @@ -1484,33 +1666,47 @@ ;;; depending on FLOAT-ACCURACY. Finally, leave out the secondary value when ;;; we know it is unused: COERCE is not flushable. (macrolet ((def (type other-float-arg-types) - (let ((unary (symbolicate "%UNARY-TRUNCATE/" type)) - (coerce (symbolicate "%" type))) + (let* ((unary (symbolicate "%UNARY-TRUNCATE/" type)) + (unary-to-bignum (symbolicate '%unary-truncate- type '-to-bignum)) + (coerce (symbolicate "%" type)) + (unary `(lambda (number) + (if (typep number + '(,type + ,(symbol-value (package-symbolicate :sb-kernel 'most-negative-fixnum- type)) + ,(symbol-value (package-symbolicate :sb-kernel 'most-positive-fixnum- type)))) + (truly-the fixnum (,unary number)) + (,unary-to-bignum number))))) `(deftransform truncate ((x &optional y) (,type &optional (or ,type ,@other-float-arg-types integer)) * :result result) (let* ((result-type (and result (lvar-derived-type result))) - (compute-all (and (values-type-p result-type) + (compute-all (and (or (eq result-type *wild-type*) + (values-type-p result-type)) (not (type-single-value-p result-type))))) (if (or (not y) (and (constant-lvar-p y) (= 1 (lvar-value y)))) (if compute-all - `(let ((res (,',unary x))) - (values res (- x (locally - ;; Can be flushed as it will produce no errors. - (declare (flushable ,',coerce)) - (,',coerce res))))) + `(unary-truncate x) `(let ((res (,',unary x))) ;; Dummy secondary value! (values res x))) (if compute-all `(let* ((f (,',coerce y)) - (res (,',unary (/ x f)))) - (values res (- x (* f (locally - (declare (flushable ,',coerce)) - (,',coerce res)))))) + (div (/ x f)) + (res (,',unary div))) + (values res + (- x (* f + #+round-float + (,',(ecase type + (double-float 'round-double) + (single-float 'round-single)) + div :truncate) + #-round-float + (locally + (declare (flushable ,',coerce)) + (,',coerce res)))))) `(let* ((f (,',coerce y)) (res (,',unary (/ x f)))) ;; Dummy secondary value! @@ -1518,62 +1714,62 @@ (def single-float ()) (def double-float (single-float))) -(defknown %unary-ftruncate (real) float (movable foldable flushable)) -(defknown %unary-ftruncate/single (single-float) single-float - (movable foldable flushable)) -(defknown %unary-ftruncate/double (double-float) double-float - (movable foldable flushable)) - -#-sb-xc-host -(defun %unary-ftruncate/single (x) - (declare (muffle-conditions compiler-note)) - (declare (type single-float x)) - (declare (optimize speed (safety 0))) - (let* ((bits (single-float-bits x)) - (exp (ldb sb-vm:single-float-exponent-byte bits)) - (biased (the single-float-exponent - (- exp sb-vm:single-float-bias)))) - (declare (type (signed-byte 32) bits)) - (cond - ((= exp sb-vm:single-float-normal-exponent-max) x) - ((<= biased 0) (* x $0f0)) - ((>= biased (float-digits x)) x) - (t - (let ((frac-bits (- (float-digits x) biased))) - (setf bits (logandc2 bits (- (ash 1 frac-bits) 1))) - (make-single-float bits)))))) - -#-sb-xc-host -(defun %unary-ftruncate/double (x) - (declare (muffle-conditions compiler-note)) - (declare (type double-float x)) - (declare (optimize speed (safety 0))) - (let* ((high (double-float-high-bits x)) - (low (double-float-low-bits x)) - (exp (ldb sb-vm:double-float-exponent-byte high)) - (biased (the double-float-exponent - (- exp sb-vm:double-float-bias)))) - (declare (type (signed-byte 32) high) - (type (unsigned-byte 32) low)) - (cond - ((= exp sb-vm:double-float-normal-exponent-max) x) - ((<= biased 0) (* x $0d0)) - ((>= biased (float-digits x)) x) - (t - (let ((frac-bits (- (float-digits x) biased))) - (cond ((< frac-bits 32) - (setf low (logandc2 low (- (ash 1 frac-bits) 1)))) - (t - (setf low 0) - (setf high (logandc2 high (- (ash 1 (- frac-bits 32)) 1))))) - (make-double-float high low)))))) - -(macrolet - ((def (float-type fun) - `(deftransform %unary-ftruncate ((x) (,float-type)) - '(,fun x)))) - (def single-float %unary-ftruncate/single) - (def double-float %unary-ftruncate/double)) +#-round-float +(progn + (defknown %unary-ftruncate (real) float (movable foldable flushable)) + (defknown %unary-ftruncate/single (single-float) single-float + (movable foldable flushable)) + (defknown %unary-ftruncate/double (double-float) double-float + (movable foldable flushable)) + + (deftransform %unary-ftruncate ((x) (single-float)) + `(cond ((or (typep x '(single-float ($-1f0) ($0f0))) + (eql x $-0f0)) + $-0f0) + ((typep x '(single-float ,(float (- (expt 2 sb-vm:single-float-digits)) $1f0) + ,(float (1- (expt 2 sb-vm:single-float-digits)) $1f0))) + (float (truncate x) $1f0)) + (t + x))) + + #-32-bit + (deftransform %unary-ftruncate ((x) (double-float)) + `(cond ((or (typep x '(double-float ($-1d0) ($0d0))) + (eql x $-0d0)) + $-0d0) + ((typep x '(double-float ,(float (- (expt 2 sb-vm:double-float-digits)) $1d0) + ,(float (1- (expt 2 sb-vm:double-float-digits)) $1d0))) + (float (truncate x) $1d0)) + (t + x))) + + #+(and (not sb-xc-host) 32-bit) + (defun %unary-ftruncate/double (x) + (declare (muffle-conditions compiler-note)) + (declare (type double-float x)) + (declare (optimize speed (safety 0))) + (let* ((high (double-float-high-bits x)) + (low (double-float-low-bits x)) + (exp (ldb sb-vm:double-float-exponent-byte high)) + (biased (the double-float-exponent + (- exp sb-vm:double-float-bias)))) + (declare (type (signed-byte 32) high) + (type (unsigned-byte 32) low)) + (cond + ((= exp sb-vm:double-float-normal-exponent-max) x) + ((<= biased 0) (* x $0d0)) + ((>= biased (float-digits x)) x) + (t + (let ((frac-bits (- (float-digits x) biased))) + (cond ((< frac-bits 32) + (setf low (logandc2 low (- (ash 1 frac-bits) 1)))) + (t + (setf low 0) + (setf high (logandc2 high (- (ash 1 (- frac-bits 32)) 1))))) + (make-double-float high low)))))) + #+32-bit + (deftransform %unary-ftruncate ((x) (double-float)) + `(%unary-ftruncate/double x))) ;;;; TESTS @@ -1585,8 +1781,8 @@ ;;; For 32-bit big-endian machines, the bit patterns were those of subnormals. ;;; So thank goodness for that - it allowed detection of the problem. (defun test-ctype-involving-double-float () - (specifier-type '(double-float #.sb-xc:pi))) -(assert (sb-xc:= (numeric-type-low (test-ctype-involving-double-float)) sb-xc:pi)) + (specifier-type '(double-float #.pi))) +(assert (sb-xc:= (numeric-type-low (test-ctype-involving-double-float)) pi)) ;;; Dummy functions to test that complex number are dumped correctly in genesis. (defun try-folding-complex-single () @@ -1620,3 +1816,23 @@ (complex single-float-negative-infinity single-float-positive-infinity) (complex single-float-negative-infinity single-float-negative-infinity) (complex single-float-positive-infinity single-float-negative-infinity))) + +#+round-float +(deftransform fround ((number &optional divisor) (double-float t)) + (if (or (not divisor) + (and (constant-lvar-p divisor) + (= (lvar-value divisor) 1))) + `(let ((res (round-double number :round))) + (values res (- number res))) + `(let ((res (round-double (/ number (%double-float divisor)) :round))) + (values res (- number (* res divisor)))))) + +#+round-float +(deftransform fround ((number &optional divisor) (single-float (or null single-float rational))) + (if (or (not divisor) + (and (constant-lvar-p divisor) + (= (lvar-value divisor) 1))) + `(let ((res (round-single number :round))) + (values res (- number res))) + `(let ((res (round-single (/ number (%single-float divisor)) :round))) + (values res (- number (* res divisor)))))) diff --git a/src/compiler/fndb.lisp b/src/compiler/fndb.lisp index 00df18673b..3a9456c161 100644 --- a/src/compiler/fndb.lisp +++ b/src/compiler/fndb.lisp @@ -19,13 +19,13 @@ ;; Note: ;; This is not FLUSHABLE because it's defined to signal errors. (movable) - ;; :DERIVE-TYPE RESULT-TYPE-SPEC-NTH-ARG 2 ? Nope... (COERCE 1 'COMPLEX) + ;; :DERIVE-TYPE RESULT-TYPE-SPEC-NTH-ARG 1 ? Nope... (COERCE 1 'COMPLEX) ;; returns REAL/INTEGER, not COMPLEX. ) ;; These each check their input sequence for type-correctness, ;; but not the output type specifier, because MAKE-SEQUENCE will do that. -(defknown list-to-vector* (list type-specifier) vector ()) -(defknown vector-to-vector* (vector type-specifier) vector ()) +(defknown list-to-vector* (list type-specifier) vector (no-verify-arg-count)) +(defknown vector-to-vector* (vector type-specifier) vector (no-verify-arg-count)) ;; FIXME: Is this really FOLDABLE? A counterexample seems to be: ;; (LET ((S :S)) (VALUES (TYPE-OF S) (UNINTERN S 'KEYWORD) (TYPE-OF S) S)) @@ -37,7 +37,7 @@ (foldable flushable)) ;;; These can be affected by type definitions, so they're not FOLDABLE. -(defknown (sb-xc:upgraded-complex-part-type sb-xc:upgraded-array-element-type) +(defknown (upgraded-complex-part-type upgraded-array-element-type) (type-specifier &optional lexenv-designator) (or list symbol) (unsafely-flushable)) @@ -89,7 +89,7 @@ #+(or x86 x86-64 arm arm64) (defknown fixnum-mod-p (t fixnum) boolean - (movable foldable flushable always-translatable)) + (movable flushable always-translatable)) ;;;; classes @@ -98,9 +98,12 @@ (defknown find-classoid (name-for-class &optional t) (or classoid null) ()) (defknown classoid-of (t) classoid (flushable)) -(defknown layout-of (t) layout (flushable)) -#+64-bit (defknown layout-depthoid (layout) fixnum (flushable always-translatable)) -(defknown layout-depthoid-gt (layout integer) boolean (flushable)) +(defknown wrapper-of (t) wrapper (flushable)) +(defknown wrapper-depthoid (wrapper) layout-depthoid (flushable)) +#+64-bit (defknown layout-depthoid (sb-vm:layout) layout-depthoid (flushable always-translatable)) +#+(or x86 x86-64) (defknown (layout-depthoid-ge) (sb-vm:layout integer) boolean (flushable)) +(defknown %structure-is-a (instance t) boolean (foldable flushable)) +(defknown structure-typep (t t) boolean (foldable flushable)) (defknown copy-structure (structure-object) structure-object (flushable) :derive-type #'result-type-first-arg) @@ -109,8 +112,8 @@ ;;; This is not FLUSHABLE, since it's required to signal an error if ;;; unbound. -(defknown (symbol-value symeval) (symbol) t () - :derive-type #'symeval-derive-type) +(defknown symbol-value (symbol) t () + :derive-type #'symbol-value-derive-type) (defknown about-to-modify-symbol-value (symbol t &optional t t) null ()) ;;; From CLHS, "If the symbol is globally defined as a macro or a @@ -119,18 +122,18 @@ ;;; either a macro or a special operator, and if the symbol is fbound, ;;; a function object is returned". Our objects of ;;; implementation-dependent nature happen to be functions. -(defknown (symbol-function) (symbol) function ()) +(defknown (symbol-function) (symbol) function (unsafely-flushable)) (defknown boundp (symbol) boolean (flushable)) -(defknown fboundp ((or symbol cons)) boolean (unsafely-flushable)) +(defknown fboundp ((or symbol cons)) (or null function) (unsafely-flushable)) (defknown special-operator-p (symbol) t ;; The set of special operators never changes. (movable foldable flushable)) (defknown set (symbol t) t () :derive-type #'result-type-last-arg) (defknown fdefinition ((or symbol cons)) function ()) -(defknown %set-fdefinition ((or symbol cons) function) function () - :derive-type #'result-type-last-arg) +(defknown ((setf fdefinition)) (function (or symbol cons)) function () + :derive-type #'result-type-first-arg) (defknown makunbound (symbol) symbol () :derive-type #'result-type-first-arg) (defknown fmakunbound ((or symbol cons)) (or symbol cons) @@ -175,7 +178,7 @@ ;;;; from the "Symbols" chapter: (defknown get (symbol t &optional t) t (flushable)) -(defknown sb-impl::get3 (symbol t t) t (flushable)) +(defknown sb-impl::get3 (symbol t t) t (flushable no-verify-arg-count)) (defknown remprop (symbol t) t) (defknown symbol-plist (symbol) list (flushable)) (defknown getf (list t &optional t) t (foldable flushable)) @@ -264,23 +267,27 @@ (defknown (two-arg-* two-arg-+ two-arg-- two-arg-/) (number number) number - ()) + (no-verify-arg-count)) + +(defknown sb-kernel::integer-/-integer + (integer integer) rational + (no-verify-arg-count unsafely-flushable)) (defknown (two-arg-< two-arg-= two-arg->) - (number number) boolean - ()) + (number number) boolean + (no-verify-arg-count)) (defknown (two-arg-gcd two-arg-lcm two-arg-and two-arg-ior two-arg-xor two-arg-eqv) (integer integer) integer - ()) + (no-verify-arg-count)) (defknown conjugate (number) number (movable foldable flushable)) (defknown gcd (&rest integer) unsigned-byte (movable foldable flushable)) -(defknown sb-kernel::fixnum-gcd (fixnum fixnum) (integer 0 #.(1+ sb-xc:most-positive-fixnum)) - (movable foldable flushable)) +(defknown sb-kernel::fixnum-gcd (fixnum fixnum) (integer 0 #.(1+ most-positive-fixnum)) + (movable foldable flushable no-verify-arg-count)) (defknown lcm (&rest integer) unsigned-byte (movable foldable flushable)) @@ -338,11 +345,41 @@ (real &optional real) (values integer real) (movable foldable flushable recursive)) +(defknown unary-truncate (real) (values integer real) + (movable foldable flushable no-verify-arg-count)) + +(defknown unary-truncate-single-float-to-bignum (single-float) (values bignum (eql $0f0)) + (foldable movable flushable fixed-args)) +(defknown unary-truncate-double-float-to-bignum (double-float) + (values #+64-bit bignum #-64-bit integer + (and + #+(and 64-bit + (not (or riscv ppc64))) ;; they can't survive cold-init + (eql $0d0) + double-float)) + (foldable movable flushable fixed-args)) + +(defknown %unary-truncate-single-float-to-bignum (single-float) bignum + (foldable movable flushable fixed-args)) +(defknown %unary-truncate-double-float-to-bignum (double-float) bignum + (foldable movable flushable fixed-args)) + +(defknown sxhash-bignum-double-float (double-float) hash-code + (foldable movable flushable fixed-args)) +(defknown sxhash-bignum-single-float (single-float) hash-code + (foldable movable flushable fixed-args)) + (defknown %multiply-high (word word) word (movable foldable flushable)) +(defknown multiply-fixnums (fixnum fixnum) integer + (movable foldable flushable no-verify-arg-count)) + +(defknown %signed-multiply-high (sb-vm:signed-word sb-vm:signed-word) sb-vm:signed-word + (movable foldable flushable)) + (defknown (mod rem) (real real) real - (movable foldable flushable)) + (movable foldable flushable)) (defknown (ffloor fceiling fround ftruncate) (real &optional real) (values float real) @@ -362,7 +399,18 @@ ;;; e.g. the behavior if the first arg is a NaN is well-defined as we have it, ;;; but what about the second arg? We need some test cases around this. (defknown float-sign (float &optional float) float - (movable foldable unsafely-flushable)) + (movable foldable unsafely-flushable) + :derive-type (lambda (call &aux (args (combination-args call)) + (type (unless (cdr args) (lvar-type (first args))))) + (cond ((and type (csubtypep type (specifier-type 'single-float))) + (specifier-type '(member $1f0 $-1f0))) + ((and type (csubtypep type (specifier-type 'double-float))) + (specifier-type '(member $1d0 $-1d0))) + (type + (specifier-type '(member $1f0 $-1f0 $1d0 $-1d0))) + (t + (specifier-type 'float))))) + (defknown (float-digits float-precision) (float) float-digits (movable foldable unsafely-flushable)) (defknown integer-decode-float (float) @@ -454,14 +502,16 @@ (character &rest character) boolean (movable foldable flushable)) (defknown (two-arg-char-equal) - (character character) boolean (movable foldable flushable commutative)) + (character character) boolean + (movable foldable flushable commutative no-verify-arg-count)) (defknown (two-arg-char-not-equal two-arg-char-lessp two-arg-char-not-lessp two-arg-char-greaterp two-arg-char-not-greaterp) - (character character) boolean (movable foldable flushable)) + (character character) boolean + (movable foldable flushable no-verify-arg-count)) (defknown character (t) character (movable foldable unsafely-flushable)) (defknown char-code (character) char-code (movable foldable flushable)) @@ -492,15 +542,15 @@ (flushable)) (defknown copy-seq (proper-sequence) consed-sequence (flushable) - :derive-type (sequence-result-nth-arg 1 :preserve-dimensions t)) + :derive-type (sequence-result-nth-arg 0 :preserve-dimensions t)) (defknown length (proper-sequence) index (foldable flushable dx-safe)) (defknown reverse (proper-sequence) consed-sequence (flushable) - :derive-type (sequence-result-nth-arg 1 :preserve-dimensions t)) + :derive-type (sequence-result-nth-arg 0 :preserve-dimensions t)) (defknown nreverse ((modifying sequence)) sequence (important-result) - :derive-type (sequence-result-nth-arg 1 :preserve-dimensions t + :derive-type (sequence-result-nth-arg 0 :preserve-dimensions t :preserve-vector-type t)) (defknown make-sequence (type-specifier index @@ -508,35 +558,36 @@ (:initial-element t)) consed-sequence (movable) - :derive-type (creation-result-type-specifier-nth-arg 1)) + :derive-type (creation-result-type-specifier-nth-arg 0)) (defknown concatenate (type-specifier &rest proper-sequence) consed-sequence () - :derive-type (creation-result-type-specifier-nth-arg 1)) + :derive-type (creation-result-type-specifier-nth-arg 0)) (defknown %concatenate-to-string (&rest sequence) simple-string - (flushable)) + (flushable no-verify-arg-count)) (defknown %concatenate-to-base-string (&rest sequence) simple-base-string - (flushable)) + (flushable no-verify-arg-count)) (defknown %concatenate-to-list (&rest sequence) list - (flushable)) + (flushable no-verify-arg-count)) (defknown %concatenate-to-simple-vector (&rest sequence) simple-vector - (flushable)) + (flushable no-verify-arg-count)) (defknown %concatenate-to-vector ((unsigned-byte #.sb-vm:n-widetag-bits) &rest sequence) vector - (flushable)) + (flushable no-verify-arg-count)) (defknown map (type-specifier (function-designator ((nth-arg 2 :sequence t) (rest-args :sequence t)) (nth-arg 0 :sequence-type t)) proper-sequence &rest proper-sequence) - consed-sequence (call) -; :DERIVE-TYPE 'TYPE-SPEC-ARG1 ? Nope... (MAP NIL ...) returns NULL, not NIL. - ) -(defknown %map (type-specifier function-designator &rest sequence) consed-sequence (call)) -(defknown %map-for-effect-arity-1 (function-designator sequence) null (call)) -(defknown %map-to-list-arity-1 ((function-designator ((nth-arg 1 :sequence t))) sequence) list (flushable call)) + consed-sequence (call)) +(defknown %map (type-specifier function-designator &rest sequence) consed-sequence + (call no-verify-arg-count)) +(defknown %map-for-effect-arity-1 (function-designator sequence) null + (call no-verify-arg-count)) +(defknown %map-to-list-arity-1 ((function-designator ((nth-arg 1 :sequence t))) sequence) list + (flushable call no-verify-arg-count)) (defknown %map-to-simple-vector-arity-1 ((function-designator ((nth-arg 1 :sequence t))) sequence) simple-vector - (flushable call)) + (flushable call no-verify-arg-count)) (defknown map-into ((modifying sequence) (function-designator ((rest-args :sequence t)) @@ -544,7 +595,8 @@ &rest proper-sequence) sequence (call) - :derive-type #'result-type-first-arg) + :derive-type (sequence-result-nth-arg 0 :preserve-dimensions t + :preserve-vector-type t)) (defknown #.(loop for info across sb-vm:*specialized-array-element-type-properties* collect @@ -553,7 +605,7 @@ :sb-impl)) (simple-array index index function list) index - (call)) + (call no-verify-arg-count)) ;;; returns the result from the predicate... (defknown some (function-designator proper-sequence &rest proper-sequence) t @@ -562,7 +614,7 @@ (defknown (every notany notevery) (function-designator proper-sequence &rest proper-sequence) boolean (foldable unsafely-flushable call)) -(defknown reduce ((function-designator ((nth-arg 1 :sequence t :key :key) +(defknown reduce ((function-designator ((nth-arg 1 :sequence t :key :key :value :initial-value) (nth-arg 1 :sequence t :key :key))) proper-sequence &rest t &key (:from-end t) (:start (inhibit-flushing index 0)) @@ -575,13 +627,28 @@ (defknown fill ((modifying sequence) t &rest t &key (:start index) (:end sequence-end)) sequence () + :derive-type (sequence-result-nth-arg 0 :preserve-dimensions t + :preserve-vector-type t) + :result-arg 0) +;;; Like FILL but with no keyword argument parsing +(defknown quickfill ((modifying (simple-array * 1)) t) (simple-array * 1) () + :derive-type #'result-type-first-arg + :result-arg 0) +;;; Special case of FILL that takes either a machine word with which to fill, +;;; or a keyword indicating a certain behavior to compute the word. +;;; In either case the supplied count is lispwords, not elements. +;;; This might be a no-op depending on whether memory is prezeroized. +(defknown sb-vm::splat ((modifying (simple-array * 1)) index (or symbol sb-vm:word)) + (simple-array * 1) + (always-translatable) :derive-type #'result-type-first-arg :result-arg 0) (defknown replace ((modifying sequence) proper-sequence &rest t &key (:start1 index) (:end1 sequence-end) (:start2 index) (:end2 sequence-end)) sequence () - :derive-type #'result-type-first-arg + :derive-type (sequence-result-nth-arg 0 :preserve-dimensions t + :preserve-vector-type t) :result-arg 0) (defknown remove @@ -594,7 +661,7 @@ (:key (function-designator ((nth-arg 1 :sequence t))))) consed-sequence (flushable call) - :derive-type (sequence-result-nth-arg 2)) + :derive-type (sequence-result-nth-arg 1)) (defknown substitute (t t proper-sequence &rest t &key (:from-end t) @@ -606,7 +673,7 @@ (:key (function-designator ((nth-arg 2 :sequence t))))) consed-sequence (flushable call) - :derive-type (sequence-result-nth-arg 3)) + :derive-type (sequence-result-nth-arg 2)) (defknown (remove-if remove-if-not) ((function-designator ((nth-arg 1 :sequence t :key :key))) proper-sequence @@ -617,7 +684,7 @@ (:key (function-designator ((nth-arg 1 :sequence t))))) consed-sequence (flushable call) - :derive-type (sequence-result-nth-arg 2)) + :derive-type (sequence-result-nth-arg 1)) (defknown (substitute-if substitute-if-not) (t (function-designator ((nth-arg 2 :sequence t :key :key))) proper-sequence @@ -628,7 +695,7 @@ (:key (function-designator ((nth-arg 2 :sequence t))))) consed-sequence (flushable call) - :derive-type (sequence-result-nth-arg 3)) + :derive-type (sequence-result-nth-arg 2)) (defknown delete (t (modifying sequence) &rest t &key (:from-end t) @@ -639,7 +706,7 @@ (:key (function-designator ((nth-arg 1 :sequence t))))) sequence (call important-result) - :derive-type (sequence-result-nth-arg 2)) + :derive-type (sequence-result-nth-arg 1)) (defknown nsubstitute (t t (modifying sequence) &rest t &key (:from-end t) @@ -650,7 +717,7 @@ (:key (function-designator ((nth-arg 2 :sequence t))))) sequence (call) - :derive-type (sequence-result-nth-arg 3)) + :derive-type (sequence-result-nth-arg 2)) (defknown (delete-if delete-if-not) ((function-designator ((nth-arg 1 :sequence t :key :key))) (modifying sequence) @@ -659,7 +726,7 @@ (:key (function-designator ((nth-arg 1 :sequence t))))) sequence (call important-result) - :derive-type (sequence-result-nth-arg 2)) + :derive-type (sequence-result-nth-arg 1)) (defknown (nsubstitute-if nsubstitute-if-not) (t (function-designator ((nth-arg 2 :sequence t :key :key))) (modifying sequence) @@ -668,7 +735,7 @@ (:key (function-designator ((nth-arg 2 :sequence t))))) sequence (call) - :derive-type (sequence-result-nth-arg 3)) + :derive-type (sequence-result-nth-arg 2)) (defknown remove-duplicates (proper-sequence &rest t &key @@ -682,7 +749,7 @@ (:key (function-designator ((nth-arg 0 :sequence t))))) consed-sequence (flushable call) - :derive-type (sequence-result-nth-arg 1)) + :derive-type (sequence-result-nth-arg 0)) (defknown delete-duplicates ((modifying sequence) @@ -696,7 +763,7 @@ (:key (function-designator ((nth-arg 0 :sequence t))))) sequence (call important-result) - :derive-type (sequence-result-nth-arg 1)) + :derive-type (sequence-result-nth-arg 0)) (defknown find (t proper-sequence &rest t &key @@ -726,7 +793,7 @@ (:end (inhibit-flushing sequence-end nil)) (:from-end t) (:key (function-designator ((nth-arg 1 :sequence t))))) - (or (mod #.(1- sb-xc:array-dimension-limit)) null) + (or (mod #.(1- array-dimension-limit)) null) (foldable flushable call)) (defknown (position-if position-if-not) @@ -735,22 +802,22 @@ (:start (inhibit-flushing index 0)) (:end (inhibit-flushing sequence-end nil)) (:key (function-designator ((nth-arg 1 :sequence t))))) - (or (mod #.(1- sb-xc:array-dimension-limit)) null) + (or (mod #.(1- array-dimension-limit)) null) (foldable flushable call)) (defknown (%bit-position/0 %bit-position/1) (simple-bit-vector t index index) - (or (mod #.(1- sb-xc:array-dimension-limit)) null) - (foldable flushable)) + (or (mod #.(1- array-dimension-limit)) null) + (foldable flushable no-verify-arg-count)) (defknown (%bit-pos-fwd/0 %bit-pos-fwd/1 %bit-pos-rev/0 %bit-pos-rev/1) (simple-bit-vector index index) - (or (mod #.(1- sb-xc:array-dimension-limit)) null) - (foldable flushable)) + (or (mod #.(1- array-dimension-limit)) null) + (foldable flushable no-verify-arg-count)) (defknown %bit-position (t simple-bit-vector t index index) - (or (mod #.(1- sb-xc:array-dimension-limit)) null) - (foldable flushable)) + (or (mod #.(1- array-dimension-limit)) null) + (foldable flushable no-verify-arg-count)) (defknown (%bit-pos-fwd %bit-pos-rev) (t simple-bit-vector index index) - (or (mod #.(1- sb-xc:array-dimension-limit)) null) - (foldable flushable)) + (or (mod #.(1- array-dimension-limit)) null) + (foldable flushable no-verify-arg-count)) (defknown count (t proper-sequence &rest t &key @@ -794,22 +861,23 @@ &key (:key (function-designator ((nth-arg 0 :sequence t))))) sequence (call) - :derive-type #'result-type-first-arg) + :derive-type (sequence-result-nth-arg 0 :preserve-dimensions t + :preserve-vector-type t)) (defknown sb-impl::stable-sort-list (list function function) list - (call important-result)) + (call important-result no-verify-arg-count)) (defknown sb-impl::sort-vector (vector index index function (or function null)) * ; SORT-VECTOR works through side-effect - (call)) + (call no-verify-arg-count)) (defknown sb-impl::stable-sort-vector (vector function (or function null)) vector - (call)) + (call no-verify-arg-count)) (defknown sb-impl::stable-sort-simple-vector (simple-vector function (or function null)) simple-vector - (call)) + (call no-verify-arg-count)) (defknown merge (type-specifier (modifying sequence) (modifying sequence) (function-designator ((nth-arg 1 :sequence t :key :key) @@ -818,7 +886,7 @@ (nth-arg 2 :sequence t)))))) sequence (call important-result) - :derive-type (creation-result-type-specifier-nth-arg 1)) + :derive-type (creation-result-type-specifier-nth-arg 0)) (defknown read-sequence ((modifying sequence) stream &key @@ -843,7 +911,7 @@ ;; Correct argument type restrictions for these functions are ;; complicated, so we just declare them to accept LISTs and suppress -;; flushing is safe code. +;; flushing in safe code. (defknown (caar cadr cdar cddr caaar caadr cadar caddr cdaar cdadr cddar cdddr caaaar caaadr caadar caaddr cadaar cadadr caddar cadddr @@ -866,27 +934,37 @@ (defknown nthcdr (unsigned-byte list) t (foldable unsafely-flushable)) (defknown last (list &optional unsigned-byte) t (foldable flushable)) -(defknown %last0 (list) t (foldable flushable)) -(defknown %last1 (list) t (foldable flushable)) -(defknown %lastn/fixnum (list (and unsigned-byte fixnum)) t (foldable flushable)) -(defknown %lastn/bignum (list (and unsigned-byte bignum)) t (foldable flushable)) +(defknown %last0 (list) t (foldable flushable no-verify-arg-count)) +(defknown %last1 (list) t (foldable flushable no-verify-arg-count)) +(defknown %lastn/fixnum (list (and unsigned-byte fixnum)) t (foldable flushable no-verify-arg-count)) +(defknown %lastn/bignum (list (and unsigned-byte bignum)) t (foldable flushable no-verify-arg-count)) (defknown list (&rest t) list (movable flushable)) (defknown list* (t &rest t) t (movable flushable)) -(defknown make-list (index &key (:initial-element t)) list +;;; The length constraint on MAKE-LIST is such that: +;;; - not every byte of addressable memory can be used up. +;;; - the number of bytes to allocate should be a fixnum +;;; - type-checking can use use efficient bit-masking approach +;;; to combine the fixnum + range test into one instruction +(eval-when (:compile-toplevel :load-toplevel :execute) + (defconstant make-list-limit + (ash most-positive-fixnum (- (+ sb-vm:word-shift 1))))) +(defknown make-list ((integer 0 #.make-list-limit) &key (:initial-element t)) list (movable flushable)) -(defknown %make-list (index t) list (movable flushable)) +(defknown %make-list ((integer 0 #.make-list-limit) t) list + (movable flushable no-verify-arg-count)) -(defknown sb-impl::|List| (&rest t) list (movable flushable foldable)) -(defknown sb-impl::|List*| (t &rest t) t (movable flushable foldable)) -(defknown sb-impl::|Append| (&rest t) t (flushable foldable)) -(defknown sb-impl::|Vector| (&rest t) simple-vector (flushable foldable)) +(defknown sb-impl::|List| (&rest t) list (movable flushable)) +(defknown sb-impl::|List*| (t &rest t) t (movable flushable)) +(defknown sb-impl::|Append| (&rest t) t (movable flushable)) +(defknown sb-impl::|Vector| (&rest t) simple-vector (movable flushable)) ;;; All but last must be of type LIST, but there seems to be no way to ;;; express that in this syntax. (defknown append (&rest t) t (flushable) :call-type-deriver #'append-call-type-deriver) -(defknown sb-impl::append2 (list t) t (flushable) +(defknown sb-impl::append2 (list t) t + (flushable no-verify-arg-count) :call-type-deriver #'append-call-type-deriver) (defknown copy-list (proper-or-dotted-list) list (flushable)) @@ -1022,12 +1100,14 @@ (:synchronized t)) hash-table (flushable)) +(defknown sb-impl::make-hash-table-using-defaults (integer) hash-table (flushable)) (defknown hash-table-p (t) boolean (movable foldable flushable)) (defknown gethash (t hash-table &optional t) (values t boolean) (flushable)) ; not FOLDABLE, since hash table contents can change (defknown sb-impl::gethash3 (t hash-table t) (values t boolean) - (flushable)) ; not FOLDABLE, since hash table contents can change -(defknown %puthash (t (modifying hash-table) t) t () + (flushable no-verify-arg-count)) ; not FOLDABLE, since hash table contents can change +(defknown %puthash (t (modifying hash-table) t) t + (no-verify-arg-count) :derive-type #'result-type-last-arg) (defknown remhash (t (modifying hash-table)) boolean ()) (defknown maphash ((function-designator (t t)) hash-table) null (flushable call)) @@ -1038,9 +1118,10 @@ (defknown hash-table-rehash-threshold (hash-table) (single-float ($0.0) $1.0) (foldable flushable)) (defknown hash-table-size (hash-table) index (flushable)) -(defknown hash-table-test (hash-table) symbol (foldable flushable)) +(defknown hash-table-test (hash-table) function-designator (foldable flushable)) (defknown (sxhash psxhash) (t) hash-code (foldable flushable)) (defknown hash-table-equalp (hash-table hash-table) boolean (foldable flushable)) +(defknown sb-impl::install-hash-table-lock (hash-table) sb-thread:mutex ()) ;; To avoid emitting code to test for nil-function-returned (defknown (sb-impl::signal-corrupt-hash-table sb-impl::signal-corrupt-hash-table-bucket) @@ -1070,9 +1151,9 @@ (:fill-pointer (or index boolean)) (:displaced-to (or array null)) (:displaced-index-offset index)) - array (flushable)) - -(defknown fill-data-vector (vector list sequence) vector () + array (flushable no-verify-arg-count)) +(defknown sb-vm::initial-contents-error (t t) nil (no-verify-arg-count)) +(defknown fill-data-vector (vector list sequence) vector (no-verify-arg-count) :result-arg 0) ;; INITIAL-CONTENTS is the first argument to FILL-ARRAY because @@ -1091,7 +1172,8 @@ ;; second way shown above, we would have to bind INITIAL-CONTENTS, ;; to ensure its evaluation before the allocation, ;; causing difficulty if doing any futher macro-like processing. -(defknown fill-array (sequence simple-array) (simple-array) (flushable) +(defknown fill-array (sequence simple-array) (simple-array) + (flushable no-verify-arg-count) :result-arg 1) (defknown vector (&rest t) simple-vector (flushable)) @@ -1137,13 +1219,14 @@ #|:derive-type #'result-type-last-arg|#) (defknown bit-vector-= (bit-vector bit-vector) boolean - (movable foldable flushable)) + (movable foldable flushable no-verify-arg-count)) (defknown array-has-fill-pointer-p (array) boolean (movable foldable flushable)) (defknown fill-pointer (complex-vector) index (unsafely-flushable)) -(defknown sb-impl::fill-pointer-error (t &optional t) nil) + +(defknown sb-vm::fill-pointer-error (t) nil (no-verify-arg-count)) (defknown vector-push (t (modifying complex-vector)) (or index null) ()) (defknown vector-push-extend (t (modifying complex-vector) &optional (and index (integer 1))) index @@ -1151,15 +1234,15 @@ (defknown vector-pop ((modifying complex-vector)) t ()) ;;; FIXME: complicated MODIFYING -;;; Also, an important-result warning could be provided if the array -;;; is known to be not expressly adjustable. (defknown adjust-array (array (or index list) &key (:element-type type-specifier) (:initial-element t) (:initial-contents t) (:fill-pointer (or index boolean)) (:displaced-to (or array null)) (:displaced-index-offset index)) - array ()) + ;; This is a special case in CHECK-IMPORTANT-RESULT because it is not + ;; necessary to use the result if the array is adjustable. + array (important-result)) ; :derive-type 'result-type-arg1) Not even close... ;;;; from the "Strings" chapter: @@ -1186,14 +1269,14 @@ (defknown (two-arg-string= two-arg-string-equal) (string-designator string-designator) boolean - (foldable flushable)) + (foldable flushable no-verify-arg-count)) (defknown (two-arg-string< two-arg-string> two-arg-string<= two-arg-string>= two-arg-string/= two-arg-string-lessp two-arg-string-greaterp two-arg-string-not-lessp two-arg-string-not-greaterp two-arg-string-not-equal) (string-designator string-designator) (or index null) - (foldable flushable)) + (foldable flushable no-verify-arg-count)) (defknown make-string (index &key (:element-type type-specifier) (:initial-element character)) @@ -1206,7 +1289,8 @@ (string-designator &key (:start (inhibit-flushing index 0)) (:end (inhibit-flushing sequence-end nil))) - simple-string (flushable)) + simple-string (flushable) + :derive-type (sequence-result-nth-arg 0 :preserve-dimensions t)) (defknown (nstring-upcase nstring-downcase nstring-capitalize) ((modifying string) &key (:start index) (:end sequence-end)) @@ -1222,14 +1306,28 @@ (inhibit-flushing index 0) (inhibit-flushing sequence-end nil) (inhibit-flushing index 0) (inhibit-flushing sequence-end nil)) (or index null) - (foldable flushable)) + (foldable flushable no-verify-arg-count)) (defknown string=* (string-designator string-designator (inhibit-flushing index 0) (inhibit-flushing sequence-end nil) (inhibit-flushing index 0) (inhibit-flushing sequence-end nil)) boolean - (foldable flushable)) + (foldable flushable no-verify-arg-count)) + +(defknown simple-base-string= + (simple-base-string simple-base-string + (inhibit-flushing index 0) (inhibit-flushing sequence-end nil) + (inhibit-flushing index 0) (inhibit-flushing sequence-end nil)) + boolean + (foldable flushable no-verify-arg-count)) + +(defknown simple-character-string= + (simple-character-string simple-character-string + (inhibit-flushing index 0) (inhibit-flushing sequence-end nil) + (inhibit-flushing index 0) (inhibit-flushing sequence-end nil)) + boolean + (foldable flushable no-verify-arg-count)) ;;;; from the "Eval" chapter: @@ -1250,12 +1348,14 @@ (defknown sb-impl::%init-string-input-stream (instance string &optional index sequence-end) (values sb-impl::string-input-stream index &optional) (flushable)) +(defknown sb-impl::%init-string-output-stream (instance t t) sb-impl::string-output-stream + ;; Not flushable, for two reasons: + ;; - possibly need to verify that the second arg is a type specifier + ;; - if you don't initialize the stream, then GET-OUTPUT-STRING-STREAM will crash + (no-verify-arg-count)) (defknown make-string-output-stream (&key (:element-type type-specifier)) sb-impl::string-output-stream (flushable)) -;; FIXME: sb-impl::string-output-stream as the result type causes a few -;; "CROSS-TYPEP uncertain: CTYPEP T #<UNKNOWN-TYPE STRING-OUTPUT-STREAM>" -;; warnings which need to be resolved. (defknown get-output-stream-string (stream) simple-string ()) (defknown streamp (t) boolean (movable foldable flushable)) (defknown stream-element-type (stream) type-specifier ; can it return a CLASS? @@ -1387,7 +1487,7 @@ :derive-type #'result-type-first-arg) (defknown output-object (t stream) null (any)) -(defknown %write (t stream-designator) t (any)) +(defknown %write (t stream-designator) t (any no-verify-arg-count)) (defknown (pprint) (t &optional stream-designator) (values) ()) @@ -1422,7 +1522,7 @@ (unsafely-flushable))) (defknown (prin1-to-string princ-to-string) (t) simple-string (unsafely-flushable)) -(defknown sb-impl::stringify-object (t) simple-string) +(defknown sb-impl::stringify-object (t) simple-string (no-verify-arg-count)) (defknown write-char (character &optional stream-designator) character () :derive-type #'result-type-first-arg) @@ -1616,7 +1716,7 @@ null) ;;; and analogous SBCL extension: -(defknown sb-impl::%failed-aver (t) nil) +(defknown sb-impl::%failed-aver (t) nil (no-verify-arg-count)) (defknown sb-impl::unreachable () nil) (defknown bug (t &rest t) nil) ; never returns (defknown simple-reader-error (stream string &rest t) nil) @@ -1633,16 +1733,13 @@ &key ;; ANSI options - (:output-file (or pathname-designator - null - ;; FIXME: This last case is a non-ANSI hack. - (member t))) + (:output-file pathname-designator) (:verbose t) (:print t) (:external-format external-format-designator) - (:progress t) ;; extensions + (:progress t) (:trace-file t) (:block-compile t) (:entry-points list) @@ -1662,7 +1759,7 @@ &key (:stream stream) (:use-labels t)) null) -(defknown describe (t &optional (or stream (member t nil))) (values)) +(defknown describe (t &optional stream-designator) (values)) (defknown function-lambda-expression (function) (values t boolean t)) (defknown inspect (t) (values)) (defknown room (&optional (member t nil :default)) (values)) @@ -1724,8 +1821,8 @@ ;;;; miscellaneous extensions -(defknown (symbol-global-value sym-global-val) (symbol) t () - :derive-type #'symeval-derive-type) +(defknown symbol-global-value (symbol) t () + :derive-type #'symbol-value-derive-type) (defknown set-symbol-global-value (symbol t) t () :derive-type #'result-type-last-arg) @@ -1744,13 +1841,16 @@ (defknown %rest-null (t t t t) * (always-translatable)) (defknown %rest-true (t t t) * (always-translatable)) -(defknown %unary-truncate/single-float (single-float) integer (movable foldable flushable)) -(defknown %unary-truncate/double-float (double-float) integer (movable foldable flushable)) +(defknown %unary-truncate/single-float (single-float) integer + (movable foldable flushable no-verify-arg-count)) +(defknown %unary-truncate/double-float (double-float) integer + (movable foldable flushable no-verify-arg-count)) ;;; We can't fold this in general because of SATISFIES. There is a ;;; special optimizer anyway. -(defknown %typep (t (or type-specifier ctype)) boolean (movable flushable)) -(defknown %instance-typep (t (or type-specifier ctype layout)) boolean +(defknown %typep (t (or type-specifier ctype)) boolean + (movable flushable no-verify-arg-count)) +(defknown %instance-typep (t (or type-specifier ctype wrapper)) boolean (movable flushable always-translatable)) ;;; We should never emit a call to %typep-wrapper (defknown %typep-wrapper (t t (or type-specifier ctype)) t @@ -1763,12 +1863,13 @@ (movable flushable always-translatable) :derive-type #'result-type-first-arg) -(defknown %cleanup-point (&rest t) t) +(defknown %cleanup-point (&rest t) t (reoptimize-when-unlinking)) (defknown %special-bind (t t) t) (defknown %special-unbind (&rest symbol) t) (defknown %listify-rest-args (t index) list (flushable)) (defknown %more-arg-context (t t) (values t index) (flushable)) -(defknown %more-arg (t index) t) +(defknown %more-arg (t index) t (flushable)) +(defknown %more-keyword-pair (t fixnum) (values t t) (flushable)) #+stack-grows-downward-not-upward ;;; FIXME: The second argument here should really be NEGATIVE-INDEX, but doing that ;;; breaks the build, and I cannot seem to figure out why. --NS 2006-06-29 @@ -1791,11 +1892,10 @@ (defknown %pop-values (t) t) (defknown %nip-values (t t &rest t) (values)) (defknown %dummy-dx-alloc (t t) t) -(defknown %allocate-closures (t) *) (defknown %type-check-error (t t t) nil) (defknown %type-check-error/c (t t t) nil) -;; FIXME: This function does not return, but due to the implementation +;; %compile-time-type-error does not return, but due to the implementation ;; of FILTER-LVAR we cannot write it here. (defknown (%compile-time-type-error %compile-time-type-style-warn) (t t t t t t) *) (defknown (etypecase-failure ecase-failure) (t t) nil) @@ -1803,34 +1903,36 @@ (defknown %odd-key-args-error () nil) (defknown %unknown-key-arg-error (t t) nil) (defknown (%ldb %mask-field) (bit-index bit-index integer) unsigned-byte - (movable foldable flushable)) + (movable foldable flushable no-verify-arg-count)) (defknown (%dpb %deposit-field) (integer bit-index bit-index integer) integer - (movable foldable flushable)) -(defknown %negate (number) number (movable foldable flushable)) + (movable foldable flushable no-verify-arg-count)) +(defknown %negate (number) number + (movable foldable flushable no-verify-arg-count)) (defknown (%check-bound check-bound) (array index t) index (dx-safe)) (defknown data-vector-ref (simple-array index) t - (foldable unsafely-flushable always-translatable)) + (foldable flushable always-translatable)) (defknown data-vector-ref-with-offset (simple-array fixnum fixnum) t - (foldable unsafely-flushable always-translatable)) + (foldable flushable always-translatable)) (defknown data-nil-vector-ref (simple-array index) nil (always-translatable)) -(defknown data-vector-set (array index t) t - (always-translatable)) -(defknown data-vector-set-with-offset (array fixnum fixnum t) t - (always-translatable)) -(defknown hairy-data-vector-ref (array index) t (foldable)) -(defknown hairy-data-vector-set (array index t) t ()) -(defknown hairy-data-vector-ref/check-bounds (array index) t (foldable)) -(defknown hairy-data-vector-set/check-bounds (array index t) t ()) +;;; The lowest-level vector SET operators should not return a value. +;;; Functions built upon them may return the input value. +(defknown data-vector-set (array index t) (values) (dx-safe always-translatable)) +(defknown data-vector-set-with-offset (array fixnum fixnum t) (values) + (dx-safe always-translatable)) +(defknown hairy-data-vector-ref (array index) t (foldable no-verify-arg-count)) +(defknown hairy-data-vector-set (array index t) t (no-verify-arg-count)) +(defknown hairy-data-vector-ref/check-bounds (array index) t (foldable no-verify-arg-count)) +(defknown hairy-data-vector-set/check-bounds (array index t) t (no-verify-arg-count)) (defknown %caller-frame () t (flushable)) (defknown %caller-pc () system-area-pointer (flushable)) (defknown %with-array-data (array index (or index null)) (values (simple-array * (*)) index index index) - (foldable flushable)) + (foldable flushable no-verify-arg-count)) (defknown %with-array-data/fp (array index (or index null)) (values (simple-array * (*)) index index index) - (foldable flushable)) + (foldable flushable no-verify-arg-count)) (defknown %set-symbol-package (symbol t) t ()) (defknown (%coerce-callable-to-fun %coerce-callable-for-call) (function-designator) @@ -1844,7 +1946,7 @@ (defknown (%find-position-if %find-position-if-not) (function sequence t index sequence-end function) (values t (or index null)) - (call)) + (call no-verify-arg-count)) (defknown effective-find-position-test (function-designator function-designator) function (flushable foldable)) @@ -1855,60 +1957,60 @@ (defknown (%adjoin %adjoin-eq) (t list) list - (flushable)) + (flushable no-verify-arg-count)) (defknown (%member %member-eq %assoc %assoc-eq %rassoc %rassoc-eq) (t list) list - (foldable flushable)) + (foldable flushable no-verify-arg-count)) (defknown (%adjoin-key %adjoin-key-eq) (t list (function (t))) list - (flushable call)) + (flushable call no-verify-arg-count)) (defknown (%member-key %member-key-eq %assoc-key %assoc-key-eq %rassoc-key %rassoc-key-eq) (t list (function (t))) list - (foldable flushable call)) + (foldable flushable call no-verify-arg-count)) (defknown (%assoc-if %assoc-if-not %rassoc-if %rassoc-if-not %member-if %member-if-not) ((function (t)) list) list - (foldable flushable call)) + (foldable flushable call no-verify-arg-count)) (defknown (%assoc-if-key %assoc-if-not-key %rassoc-if-key %rassoc-if-not-key %member-if-key %member-if-not-key) ((function (t)) list (function (t))) list - (foldable flushable call)) + (foldable flushable call no-verify-arg-count)) (defknown (%adjoin-test %adjoin-test-not) (t list (function (t t))) list - (flushable call)) + (flushable call no-verify-arg-count)) (defknown (%member-test %member-test-not %assoc-test %assoc-test-not %rassoc-test %rassoc-test-not) (t list (function (t t))) list - (foldable flushable call)) + (foldable flushable call no-verify-arg-count)) (defknown (%adjoin-key-test %adjoin-key-test-not) (t list (function (t)) (function (t t))) list - (flushable call)) + (flushable call no-verify-arg-count)) (defknown (%member-key-test %member-key-test-not %assoc-key-test %assoc-key-test-not %rassoc-key-test %rassoc-key-test-not) (t list (function (t)) (function (t t))) list - (foldable flushable call)) + (foldable flushable call no-verify-arg-count)) (defknown %check-vector-sequence-bounds (vector index sequence-end) index @@ -1924,7 +2026,7 @@ (array-call-type-deriver call trusted t t))) (defknown (%rplaca %rplacd) ((modifying cons) t) t () :derive-type #'result-type-last-arg) -(defknown %put (symbol t t) t ()) +(defknown %put (symbol t t) t (no-verify-arg-count)) (defknown %setelt ((modifying sequence) index t) t () :derive-type #'result-type-last-arg) (defknown %svset ((modifying simple-vector) index t) t ()) @@ -1934,8 +2036,12 @@ (defknown %scharset ((modifying simple-string) index character) character ()) (defknown %set-symbol-value (symbol t) t ()) (defknown (setf symbol-function) (function symbol) function ()) -(defknown %set-symbol-plist (symbol list) list () - :derive-type #'result-type-last-arg) +;; Does this really need a type deriver? It's inline, and returns its 1st arg, +;; i.e. we know exactly what object it returns, which is more precise than +;; just knowing the type. +(defknown (setf symbol-plist) (list symbol) list () + :derive-type #'result-type-first-arg) +(defknown (setf documentation) ((or string null) t symbol) (or string null) ()) (defknown %setnth (unsigned-byte (modifying list) t) t () :derive-type #'result-type-last-arg) (defknown %set-fill-pointer ((modifying complex-vector) index) index () @@ -1943,14 +2049,14 @@ ;;;; ALIEN and call-out-to-C stuff -(defknown %alien-funcall ((or string system-area-pointer) alien-type &rest *) *) +(defknown %alien-funcall ((or string system-area-pointer) alien-type &rest t) *) ;; Used by WITH-PINNED-OBJECTS -#+(or x86 x86-64) (defknown sb-vm::touch-object (t) (values) (always-translatable)) -#+linkage-table +(defknown sb-vm::touch-object-identity (t) t + (always-translatable)) (defknown foreign-symbol-dataref-sap (simple-string) system-area-pointer (movable flushable)) @@ -1989,10 +2095,10 @@ ;;; Unfortunately it prints that noise at each call site. ;;; Using DEFKNOWN we can make the proclamation effective when ;;; running the cross-compiler but not when building it. -;;; Alternatively we could use SB-XC:PROCLAIM, except that that +;;; Alternatively we could use PROCLAIM, except that that ;;; doesn't exist soon enough, and would need conditionals guarding ;;; it, which is sort of the very thing this is trying to avoid. -(defknown missing-arg () nil) +(defknown missing-arg () nil (no-verify-arg-count)) (defknown give-up-ir1-transform (&rest t) nil) (defknown coerce-to-condition ((or condition symbol string function) @@ -2002,7 +2108,7 @@ (defknown coerce-symbol-to-fun (symbol) function - ()) + (no-verify-arg-count)) (defknown sc-number-or-lose (symbol) sc-number (foldable)) @@ -2026,6 +2132,10 @@ (defknown sb-kernel::gc-safepoint () (values) ()) ;;;; atomic ops +;;; the CAS functions are transformed to something else rather than "translated". +;;; either way, they should not be called. +(defknown (cas svref) (t t simple-vector index) t (always-translatable)) +(defknown (cas symbol-value) (t t symbol) t (always-translatable)) (defknown %compare-and-swap-svref (simple-vector index t t) t ()) (defknown (%compare-and-swap-symbol-value @@ -2044,8 +2154,8 @@ ;;; Avoid a ton of FBOUNDP checks in the string stream constructors etc, ;;; by wiring in the needed functions instead of dereferencing their fdefns. (defknown (ill-in ill-bin ill-out ill-bout - sb-impl::string-inch sb-impl::string-in-misc - sb-impl::string-ouch sb-impl::string-sout sb-impl::string-out-misc + sb-impl::string-in-misc + sb-impl::string-sout sb-impl::finite-base-string-ouch sb-impl::finite-base-string-out-misc sb-impl::fill-pointer-ouch sb-impl::fill-pointer-sout sb-impl::fill-pointer-misc @@ -2073,10 +2183,51 @@ (defknown class-name (class) symbol (flushable)) (defknown finalize - (t (function-designator () * :no-function-conversion t) &key (:dont-save t)) + (t (function-designator () *) &key (:dont-save t)) *) +(defknown (sb-impl::%with-standard-io-syntax + sb-impl::%with-rebound-io-syntax + sb-impl::call-with-sane-io-syntax) + (function) *) +(defknown sb-debug::funcall-with-debug-io-syntax (function &rest t) *) +(defknown sb-impl::%print-unreadable-object (t t t &optional function) null) + #+sb-thread -(defknown sb-thread::call-with-recursive-lock (function t t t) *) -#+sb-thread -(defknown sb-thread::call-with-mutex (function t t t t) *) +(progn +(defknown (sb-thread::call-with-mutex sb-thread::call-with-recursive-lock) + (function t t t) *) +(defknown (sb-thread::call-with-system-mutex + sb-thread::call-with-system-mutex/allow-with-interrupts + sb-thread::call-with-system-mutex/without-gcing + sb-thread::call-with-recursive-system-lock) + (function t) *)) + +#+round-float +(progn + (defknown round-double (double-float #1=(member :round :floor :ceiling :truncate)) + double-float + (foldable flushable movable always-translatable)) + + (defknown round-single (single-float #1#) single-float + (foldable flushable movable always-translatable))) + +(defknown fixnum* + (fixnum fixnum t) + fixnum + (movable foldable always-translatable)) + +(defknown (signed* signed+ signed-) + (sb-vm:signed-word sb-vm:signed-word t) + sb-vm:signed-word + (movable foldable commutative always-translatable)) + +(defknown (unsigned* unsigned+ unsigned-) + (word word t) + word + (movable foldable commutative always-translatable)) + +(defknown (unsigned+signed unsigned-signed) + (word sb-vm:signed-word t) + word + (movable foldable commutative always-translatable)) diff --git a/src/compiler/fopcompile.lisp b/src/compiler/fopcompile.lisp deleted file mode 100644 index 9cd16e9daf..0000000000 --- a/src/compiler/fopcompile.lisp +++ /dev/null @@ -1,549 +0,0 @@ -;;;; A compiler from simple top-level forms to FASL operations. - -;;;; This software is part of the SBCL system. See the README file for -;;;; more information. -;;;; -;;;; This software is derived from the CMU CL system, which was -;;;; written at Carnegie Mellon University and released into the -;;;; public domain. The software is in the public domain and is -;;;; provided with absolutely no warranty. See the COPYING and CREDITS -;;;; files for more information. - -(in-package "SB-C") - -;;; SBCL has no proper byte compiler (having ditched the rather -;;; ambitious and slightly flaky byte compiler inherited from CMU CL) -;;; but its FOPs are a sort of byte code which is expressive enough -;;; that we can compile some simple toplevel forms directly to them, -;;; including very common operations like the forms that DEFVARs and -;;; DECLAIMs macroexpand into. -;;; -;;; FIXME: The expexnasion problem. -;;; FOPCOMPILE and FOPCOMPILABLE-P cause multiple expansion of macros, -;;; which may be problematic with side-effecting macros. When -;;; FOPCOMPILABLE-P succeeds, FOPCOMPILE is called, resulting in -;;; double macroexpansion. When FOPCOMPILABLE-P fails, -;;; IR1-CONVERT-FUNCTOID expands already expanded macros for a second -;;; time. -;;; And an edge case, when the top-level call has a complier-macro -;;; which returns &whole it gets expanded three times, two times by -;;; FOPCOMPILABLE-P and FOPCOMPILE, and one time by -;;; PROCESS-TOPLEVEL-FORM, because unlike other macros, the expanded -;;; form is still a macro-form. That's what the EXPAND optional -;;; parameter solves, PROCESS-TOPLEVEL-FORM passes NIL, expanding -;;; compiler macros at most once. -;;; The instances of double expansion still remain, e.g. (fun (macro)), -;;; since PROCESS-TOPLEVEL-FORM only expands the macros at the first -;;; position. - -(flet ((setq-fopcompilable-p (args) - (loop for (name value) on args by #'cddr - always (and (symbolp name) - (member (info :variable :kind name) - '(:special :global)) - (fopcompilable-p value))))) - - #-sb-xc-host - (defun fopcompilable-p (form &optional (expand t)) - ;; We'd like to be able to handle - ;; -- simple funcalls, nested recursively, e.g. - ;; (SET '*PACKAGE* (FIND-PACKAGE "CL-USER")) - ;; -- common self-evaluating forms like strings and keywords and - ;; fixnums, which are important for terminating - ;; the recursion of the simple funcalls above - ;; -- quoted lists (which are important for PROCLAIMs, which are - ;; common toplevel forms) - ;; -- fopcompilable stuff wrapped around non-fopcompilable expressions, - ;; e.g. - ;; (%DEFUN 'FOO (LAMBDA () ...) ...) - ;; -- the IF special form, to support things like (DEFVAR *X* 0) - ;; expanding into (UNLESS (BOUNDP '*X*) (SET '*X* 0)) - ;; - ;; Special forms which we don't currently handle, but might consider - ;; supporting in the future are LOCALLY (with declarations), - ;; MACROLET, SYMBOL-MACROLET and THE. - ;; Also, if (FLET ((F () ...)) (DEFUN A () ...) (DEFUN B () ...)) - ;; were handled, then it would probably automatically work in - ;; the cold loader too, providing definitions for A and B before - ;; executing all other toplevel forms. - (flet ((expand (form) - (if expand - (handler-case - (%macroexpand form *lexenv*) - (error () (return-from fopcompilable-p))) - (values form nil))) - (expand-cm (form) - (if expand - (expand-compiler-macro form) - (values form nil)))) - (or (and (self-evaluating-p form) - (constant-fopcompilable-p form)) - (and (symbolp form) - (multiple-value-bind (macroexpansion macroexpanded-p) - (expand form) - (if macroexpanded-p - (fopcompilable-p macroexpansion) - ;; Punt on :ALIEN variables - (let ((kind (info :variable :kind form))) - (member kind '(:special :constant :global :unknown)))))) - (and (listp form) - (ignore-errors (list-length form)) - (let ((macroexpansion (expand-cm form))) - (if (neq macroexpansion form) - (return-from fopcompilable-p (fopcompilable-p macroexpansion)) - t)) - (multiple-value-bind (macroexpansion macroexpanded-p) - (expand form) - (if macroexpanded-p - (fopcompilable-p macroexpansion) - (destructuring-bind (operator &rest args) form - (case operator - ;; Special operators that we know how to cope with - ((progn) - (every #'fopcompilable-p args)) - ((quote) - (and (= (length args) 1) - (constant-fopcompilable-p (car args)))) - ((function) - (and (= (length args) 1) - ;; #'(LAMBDA ...), #'(NAMED-LAMBDA ...), etc. These - ;; are not fopcompileable as such, but we can compile - ;; the lambdas with the real compiler, and the rest - ;; of the expression with the fop-compiler. - (or (and (lambda-form-p (car args)) - ;; The lambda might be closing over some - ;; variable, punt. As a further improvement, - ;; we could analyze the lambda body to - ;; see whether it really closes over any - ;; variables. One place where even simple - ;; analysis would be useful are the PCL - ;; slot-definition type-check-functions - ;; -- JES, 2007-01-13 - (notany (lambda (binding) - (lambda-var-p (cdr binding))) - (lexenv-vars *lexenv*))) - ;; #'FOO, #'(SETF FOO), etc - (legal-fun-name-p (car args))))) - ((if) - (and (<= 2 (length args) 3) - (every #'fopcompilable-p args))) - ;; Allow SETQ only on special or global variables - ((setq) - (setq-fopcompilable-p args)) - ;; The real toplevel form processing has already been - ;; done, so EVAL-WHEN handling will be easy. - ((eval-when) - (and (>= (length args) 1) - (eq (set-difference (car args) - '(:compile-toplevel - compile - :load-toplevel - load - :execute - eval)) - nil) - (every #'fopcompilable-p (cdr args)))) - ;; A LET or LET* that introduces only lexical - ;; bindings might be fopcompilable, depending on - ;; whether something closes over the bindings. - ;; (And whether there are declarations in the body, - ;; see below) - ((let let*) - (let-fopcompilable-p operator args)) - ((locally) - (every #'fopcompilable-p args)) - (otherwise - ;; ordinary function calls - (and (symbolp operator) - ;; If a LET/LOCALLY tries to introduce - ;; declarations, we'll detect it here, and - ;; disallow fopcompilation. This is safe, - ;; since defining a function/macro named - ;; DECLARE would violate a package lock. - (not (eq operator 'declare)) - (not (special-operator-p operator)) - (not (macro-function operator)) ; redundant check - (every #'fopcompilable-p args))))))))))) - - ;; Special version of FOPCOMPILABLE-P which recognizes toplevel calls - ;; that the cold loader is able to perform in the host to create the - ;; desired effect upon the target core. - ;; If an effect should occur "sooner than cold-init", - ;; this is probably where you need to make it happen. - #+sb-xc-host - (defun fopcompilable-p (form &optional (expand t)) - (declare (ignore expand)) - (or (and (self-evaluating-p form) - (constant-fopcompilable-p form)) - ;; Arbitrary computed constants aren't supported because we don't know - ;; where in FOPCOMPILE's recursion it should stop recursing and just dump - ;; whatever the constant piece is. For example in (cons `(a ,(+ 1 2)) (f)) - ;; the CAR is built wholly from foldable operators but the CDR is not. - ;; Constant symbols and QUOTE forms are generally fine to use though. - (and (symbolp form) - (eq (info :variable :kind form) :constant)) - (and (typep form '(cons (eql quote) (cons t null))) - (constant-fopcompilable-p (constant-form-value form))) - (and (listp form) - (let ((function (car form))) - ;; Certain known functions have a special way of checking - ;; their fopcompilability in the cross-compiler. - (or ;; allow %DEFUN, also ensuring that any inline lambda gets - ;; its constant structures (possibly containing COMMAs) noted - ;; as dumpable literals. - (and (eq function 'sb-impl::%defun) (fopcompilable-p (fourth form))) - (member function '(sb-pcl::!trivial-defmethod - sb-kernel::%defstruct - sb-thread:make-mutex)) - ;; allow DEF{CONSTANT,PARAMETER} only if the value form is ok - (and (member function '(%defconstant sb-impl::%defparameter)) - (fopcompilable-p (third form))) - (and (symbolp function) ; no ((lambda ...) ...) - (get-properties (symbol-plist function) - '(:sb-cold-funcall-handler/for-effect - :sb-cold-funcall-handler/for-value))) - (and (eq function 'setf) - (fopcompilable-p (%macroexpand form *lexenv*))) - (and (eq function 'sb-kernel:%svset) - (destructuring-bind (thing index value) (cdr form) - (and (symbolp thing) - (integerp index) - (eq (info :variable :kind thing) :global) - (typep value - '(cons (member lambda function named-lambda)))))) - (and (eq function 'setq) - (setq-fopcompilable-p (cdr form)))))))) -) ; end FLET - -(defun let-fopcompilable-p (operator args) - (when (>= (length args) 1) - (multiple-value-bind (body decls) (parse-body (cdr args) nil) - (declare (ignore body)) - (let* ((orig-lexenv *lexenv*) - (*lexenv* (make-lexenv))) - ;; We need to check for declarations - ;; first. Otherwise the fake lexenv we're - ;; constructing might be invalid. - (and (null decls) - (loop for binding in (car args) - for name = (if (consp binding) - (first binding) - binding) - for value = (if (consp binding) - (second binding) - nil) - ;; Only allow binding locals, since special bindings can't - ;; be easily expressed with fops. - always (and (eq (info :variable :kind name) - :unknown) - (let ((*lexenv* (ecase operator - (let orig-lexenv) - (let* *lexenv*)))) - (fopcompilable-p value))) - do (progn - (setf *lexenv* (make-lexenv)) - (push (cons name - (make-lambda-var :%source-name name)) - (lexenv-vars *lexenv*)))) - (every #'fopcompilable-p (cdr args))))))) - -(defun lambda-form-p (form) - (and (consp form) - (member (car form) - '(lambda named-lambda lambda-with-lexenv)))) - -;;; Return T if and only if OBJ's nature as an externalizable thing renders -;;; it a leaf for dumping purposes. Symbols are leaflike despite havings slots -;;; containing pointers; similarly (COMPLEX RATIONAL) and RATIO. -(defun dumpable-leaflike-p (obj) - (or (sb-xc:typep obj '(or symbol number character unboxed-array - debug-name-marker - #+sb-simd-pack simd-pack - #+sb-simd-pack-256 simd-pack-256)) - ;; The cross-compiler wants to dump CTYPE instances as leaves, - ;; but CLASSOIDs are excluded since they have a MAKE-LOAD-FORM method. - #+sb-xc-host (cl:typep obj '(and ctype (not classoid))) - (sb-fasl:dumpable-layout-p obj))) - -;;; Check that a literal form is fopcompilable. It would not be, for example, -;;; when the form contains structures with funny MAKE-LOAD-FORMS. -;;; In particular, pathnames are not trivially dumpable because the HOST slot -;;; might need to be dumped as a reference to the *PHYSICAL-HOST* symbol. -;;; This function is nowhere near as OAOO-violating as it once was - it no -;;; longer has local knowledge of the set of leaf types, nor how to test for -;;; non-trivial instances. Sharing more code with MAYBE-EMIT-MAKE-LOAD-FORMS -;;; might be a nice goal, but it seems relatively impossible to achieve. -(defun constant-fopcompilable-p (constant) - (declare (optimize (debug 1))) ;; TCO - (let ((xset (alloc-xset)) - (dumpable-instances)) - (named-let grovel ((value constant)) - ;; Unless VALUE is an object which which obviously - ;; can't contain other objects - (unless (dumpable-leaflike-p value) - (if (xset-member-p value xset) - (return-from grovel nil) - (add-to-xset value xset)) - (typecase value - (cons - (grovel (car value)) - (grovel (cdr value))) - (simple-vector - (dotimes (i (length value)) - (grovel (svref value i)))) - ((vector t) - (dotimes (i (length value)) - (grovel (aref value i)))) - ((simple-array t) - ;; Even though the (ARRAY T) branch does the exact - ;; same thing as this branch we do this separately - ;; so that the compiler can use faster versions of - ;; array-total-size and row-major-aref. - (dotimes (i (array-total-size value)) - (grovel (row-major-aref value i)))) - ((array t) - (dotimes (i (array-total-size value)) - (grovel (row-major-aref value i)))) - (instance - ;; Almost always, a make-load-form method will call - ;; MAKE-LOAD-FORM-SAVING-SLOTS for all slots. If so, - ;; then this structure is amenable to FOPCOMPILE. - ;; If not, then it isn't, which is not strictly true- - ;; the method might have returned a fopcompilable - ;; creation form and no init form. (Handling of - ;; circularity is best left to the main compiler.) - (unless (sb-fasl:load-form-is-default-mlfss-p value) - (return-from constant-fopcompilable-p nil)) - (do-instance-tagged-slot (i value) - (grovel (%instance-ref value i))) - (push value dumpable-instances)) - (t - (return-from constant-fopcompilable-p nil))))) - (dolist (instance dumpable-instances) - (fasl-note-dumpable-instance instance *compile-object*)) - t)) - -;;; FOR-VALUE-P is true if the value will be used (i.e., pushed onto -;;; FOP stack), or NIL if any value will be discarded. FOPCOMPILABLE-P -;;; has already ensured that the form can be fopcompiled. -;;; -;;; See the expansion problem FIXME above fopcompilable-p. -(defun fopcompile (form path for-value-p &optional (expand t)) - (let ((path (or (get-source-path form) (cons form path))) - (fasl *compile-object*)) - (flet ((expand (form) - (if expand - (%macroexpand form *lexenv*) - (values form nil))) - (expand-cm (form) - (if expand - (expand-compiler-macro form) - (values form nil)))) - (cond ((self-evaluating-p form) - (fopcompile-constant fasl form for-value-p)) - ((symbolp form) - (multiple-value-bind (macroexpansion macroexpanded-p) - (expand form) - (if macroexpanded-p - ;; Symbol macro - (fopcompile macroexpansion path for-value-p) - (let ((kind (info :variable :kind form))) - (cond - ((eq :special kind) - ;; Special variable - (fopcompile `(symbol-value ',form) path for-value-p)) - - ((member kind '(:global :constant)) - ;; Global variable or constant. - (fopcompile `(symbol-global-value ',form) path for-value-p)) - (t - ;; Lexical - (let* ((var (cdr (assoc form (lexenv-vars *lexenv*)))) - (handle (and (lambda-var-p var) - (lambda-var-fop-value var)))) - (cond (handle - (setf (lambda-var-ever-used var) t) - (when for-value-p - (sb-fasl::dump-push handle fasl))) - (t - (unless var - ;; Undefined variable. Signal a warning, and - ;; treat it as a special variable reference, like - ;; the real compiler does -- do not elide even if - ;; the value is unused. - (note-undefined-reference form :variable)) - (fopcompile `(symbol-value ',form) - path - for-value-p)))))))))) - ((listp form) - (let ((macroexpansion (expand-cm form))) - (if (neq macroexpansion form) - ;; could expand into an atom, so start from the top - (return-from fopcompile - (fopcompile macroexpansion path for-value-p)))) - (multiple-value-bind (macroexpansion macroexpanded-p) - (expand form) - (if macroexpanded-p - (fopcompile macroexpansion path for-value-p) - (destructuring-bind (operator &rest args) form - (case operator - ;; The QUOTE special operator is worth handling: very - ;; easy and very common at toplevel. - ((quote) - (fopcompile-constant fasl (second form) for-value-p)) - ;; A FUNCTION needs to be compiled properly, but doesn't - ;; need to prevent the fopcompilation of the whole form. - ;; We just compile it, and emit an instruction for pushing - ;; the function handle on the FOP stack. - ((function) - (fopcompile-function fasl (second form) path for-value-p)) - ;; KLUDGE! SB-C:SOURCE-LOCATION calls are normally handled - ;; by a compiler-macro. But if SPACE > DEBUG we choose not - ;; to record locations, which is strange because the main - ;; compiler does not have similar logic afaict. - ((source-location) - ;; FIXME: since the fopcompiler expands compiler-macros, - ;; this case should probably be killed. It can't execute. - (if (policy *policy* (and (> space 1) - (> space debug))) - (fopcompile-constant fasl nil for-value-p) - (fopcompile (let ((*current-path* path)) - (make-definition-source-location)) - path - for-value-p))) - ((if) - (fopcompile-if fasl args path for-value-p)) - ((progn locally) - (if (and for-value-p (endp args)) - (fopcompile nil path t) - (loop for (arg . next) on args - do (fopcompile arg path - (if next nil for-value-p))))) - ((setq) - (if (and for-value-p (endp args)) - (fopcompile nil path t) - (loop for (name value . next) on args by #'cddr - do (fopcompile `(set ',name ,value) path - (if next nil for-value-p))))) - ((eval-when) - (destructuring-bind (situations &body body) args - (if (or (member :execute situations) - (member 'eval situations)) - (fopcompile (cons 'progn body) path for-value-p) - (fopcompile nil path for-value-p)))) - ((let let*) - (let ((orig-lexenv *lexenv*) - (*lexenv* (make-lexenv :default *lexenv*)) - vars) - (loop for binding in (car args) - for name = (if (consp binding) - (first binding) - binding) - for value = (if (consp binding) - (second binding) - nil) - do - (let ((*lexenv* (if (eql operator 'let) - orig-lexenv - *lexenv*))) - (fopcompile value path t)) - (let* ((obj (sb-fasl::dump-pop fasl)) - (var (make-lambda-var - :%source-name name - :fop-value obj))) - (push var vars) - (setf *lexenv* - (make-lexenv - :vars (list (cons name var)))))) - (fopcompile (cons 'progn (cdr args)) path for-value-p) - (when (and vars - (and *source-info* path)) - (let* ((tlf (source-path-tlf-number path)) - (file-info (source-info-file-info *source-info*)) - (*compiler-error-context* - (make-compiler-error-context - :original-form form - :file-name (file-info-name file-info) - :initialized t - :file-position - (nth-value 1 (find-source-root tlf *source-info*)) - :original-source-path (source-path-original-source path) - :handled-conditions - (lexenv-handled-conditions *lexenv*)))) - (note-unreferenced-vars vars *policy*))))) - ;; Otherwise it must be an ordinary funcall. - (otherwise - (cond - ;; Special hack: there's already a fop for - ;; find-undeleted-package-or-lose, so use it. - ;; (We could theoretically do the same for - ;; other operations, but I don't see any good - ;; candidates in a quick read-through of - ;; src/code/fop.lisp.) - ((and (eq operator 'find-undeleted-package-or-lose) - (= 1 (length args)) - for-value-p) - (fopcompile (first args) path t) - (dump-fop 'sb-fasl::fop-package fasl)) - (t - (when (eq (info :function :where-from operator) :assumed) - (note-undefined-reference operator :function)) - (fopcompile-constant fasl operator t) - (let ((n 0)) - (dolist (arg args) - (incf n) - (fopcompile arg path t)) - (if for-value-p - (dump-fop 'sb-fasl::fop-funcall fasl n) - (dump-fop 'sb-fasl::fop-funcall-for-effect - fasl n))))))))))) - (t - (bug "looks unFOPCOMPILEable: ~S" form)))))) - -(defun fopcompile-function (fasl form path for-value-p) - (cond ((lambda-form-p form) - ;; Lambda forms are compiled with the real compiler - (let ((handle (%compile form fasl :path path))) - (when for-value-p - (sb-fasl::dump-push handle fasl)))) - ;; While function names are translated to a call to FDEFINITION. - ((legal-fun-name-p form) - (fopcompile `(fdefinition ',form) path for-value-p)) - (t - (compiler-error "~S is not a legal function name." form)))) - -(defun fopcompile-if (fasl args path for-value-p) - (destructuring-bind (condition then &optional else) args - (let ((else-label (incf *fopcompile-label-counter*)) - (end-label (incf *fopcompile-label-counter*))) - (fopcompile condition path t) - ;; If condition was false, skip to the ELSE - (dump-fop 'sb-fasl::fop-skip-if-false fasl else-label) - (fopcompile then path for-value-p) - ;; The THEN branch will have produced a value even if we were - ;; currently skipping to the ELSE branch (or over this whole - ;; IF). This is done to ensure that the stack effects are - ;; balanced properly when dealing with operations that are - ;; executed even when skipping over code. But this particular - ;; value will be bogus, so we drop it. - (when for-value-p - (dump-fop 'sb-fasl::fop-drop-if-skipping fasl)) - ;; Now skip to the END - (dump-fop 'sb-fasl::fop-skip fasl end-label) - ;; Start of the ELSE branch - (dump-fop 'sb-fasl::fop-maybe-stop-skipping fasl else-label) - (fopcompile else path for-value-p) - ;; As before - (when for-value-p - (dump-fop 'sb-fasl::fop-drop-if-skipping fasl)) - ;; End of IF - (dump-fop 'sb-fasl::fop-maybe-stop-skipping fasl end-label) - ;; If we're still skipping, we must've triggered both of the - ;; drop-if-skipping fops. To keep the stack balanced, push a - ;; dummy value if needed. - (when for-value-p - (dump-fop 'sb-fasl::fop-push-nil-if-skipping fasl))))) - -(defun fopcompile-constant (fasl form for-value-p) - (when for-value-p - (dump-object form fasl))) diff --git a/src/compiler/fun-info.lisp b/src/compiler/fun-info.lisp index f63eb04bab..f076905b64 100644 --- a/src/compiler/fun-info.lisp +++ b/src/compiler/fun-info.lisp @@ -87,9 +87,20 @@ ;; as a consistency checking mechanism inside the compiler during IR2 ;; transformation. always-translatable + ;; Function's funarg can safely skip its argument count check. + callee-omit-arg-count-check ;; If a function is called with two arguments and the first one is a ;; constant, then the arguments will be swapped. - commutative) + commutative + ;; Reoptimize this function if the node that follows it gets unlinked. + reoptimize-when-unlinking + ;; The function does not verify the arg count and must be always + ;; called with the right arguments and can avoid passing NARGS. + no-verify-arg-count + ;; Arguments are can be passed unboxed, no type checking on entry is + ;; performed, and the number of arguments passed in registers can be + ;; greater than the standard number. Only fixed arguments can be used. + fixed-args) (defstruct (fun-info (:copier nil) #-sb-xc-host (:pure t)) diff --git a/src/compiler/generic/core.lisp b/src/compiler/generic/core.lisp index b7273ed918..2870c8af92 100644 --- a/src/compiler/generic/core.lisp +++ b/src/compiler/generic/core.lisp @@ -11,6 +11,13 @@ (in-package "SB-C") +;;; Unique number assigned into high 4 bytes of 64-bit code size slot +;;; so that we can sort the contents of text space in a more-or-less +;;; predictable manner based on the order in which code was loaded. +;;; This wraps around at 32 bits, but it's still deterministic. +(define-load-time-global *code-serialno* 0) +(declaim (fixnum *code-serialno*)) + ;;; A CORE-OBJECT structure holds the state needed to resolve cross-component ;;; references during in-core compilation. (defstruct (core-object @@ -22,10 +29,6 @@ ;; A hashtable translating ENTRY-INFO structures to the corresponding actual ;; FUNCTIONs for functions in this compilation. (entry-table (make-hash-table :test 'eq) :type hash-table) - ;; A hashtable translating ENTRY-INFO structures to a list of pairs - ;; (<code object> . <offset>) describing the places that need to be - ;; backpatched to point to the function for ENTRY-INFO. - (patch-table (make-hash-table :test 'eq) :type hash-table) ;; A list of all the DEBUG-INFO objects created, kept so that we can ;; backpatch with the source info. (debug-info () :type list)) diff --git a/src/compiler/generic/early-objdef.lisp b/src/compiler/generic/early-objdef.lisp index 292f8767d4..ffe1f31e17 100644 --- a/src/compiler/generic/early-objdef.lisp +++ b/src/compiler/generic/early-objdef.lisp @@ -20,15 +20,8 @@ ;;; * LIST-POINTER-LOWTAG + N-WORD-BYTES = OTHER-POINTER-LOWTAG: NIL ;;; is both a cons and a symbol (at the same address) and depends on this. ;;; See the definition of SYMBOL in objdef.lisp -;;; * OTHER-POINTER-LOWTAG > 4: Some code in the SPARC backend, -;;; which uses bit 2 of the ALLOC register to indicate that -;;; PSEUDO-ATOMIC is on, doesn't strip the low bits of reg_ALLOC -;;; before ORing in OTHER-POINTER-LOWTAG within a PSEUDO-ATOMIC -;;; section. ;;; * OTHER-IMMEDIATE-0-LOWTAG are spaced 4 apart: various code wants to -;;; iterate through these -;;; * Allocation code on Alpha wants lowtags for heap-allocated -;;; objects to be odd. +;;; iterate through these. (This is not true on PPC64) ;;; (These are just the ones we know about as of sbcl-0.7.1.22. There ;;; might easily be more, since these values have stayed highly ;;; constrained for more than a decade, an inviting target for @@ -103,28 +96,9 @@ other-immediate-1-lowtag other-pointer-lowtag)) -(defconstant nil-value - (+ static-space-start - ;; boxed_region precedes NIL - ;; 8 is the number of words to reserve at the beginning of static space - ;; prior to the words of NIL. - ;; If you change this, then also change MAKE-NIL-DESCRIPTOR in genesis. - #+(and gencgc (not sb-thread)) (ash 8 word-shift) - (* 2 n-word-bytes) - list-pointer-lowtag)) - (defconstant-eqx fixnum-lowtags - #.(let ((fixtags nil)) - (do-external-symbols (sym "SB-VM") - (let* ((name (symbol-name sym)) - (len (length name))) - (when (and (boundp sym) - (integerp (symbol-value sym)) - (> len 7) - (string= name "-LOWTAG" :start1 (- len 7)) - (zerop (logand (symbol-value sym) fixnum-tag-mask))) - (push sym fixtags)))) - `',(sort fixtags #'string< :key #'symbol-name)) + '#.(loop for i from 0 to lowtag-mask + when (zerop (logand i fixnum-tag-mask)) collect i) #'equal) ;;; the heap types, stored in 8 bits of the header of an object on the @@ -152,7 +126,7 @@ ;;; ;;; * SIMPLE-ARRAY-* = (SIMPLE-ARRAY * (*)) ;;; -;;; * SIMPLE-ARRAY-NIL + SIMPLE-BASE-STRING = SIMPLE-STRING +;;; * SIMPLE-CHARACTER-STRING + SIMPLE-BASE-STRING = SIMPLE-STRING ;;; ;;; * SIMPLE-ARRAY + COMPLEX-ARRAYOID = (SATISFIES ARRAY-HEADER-P) ;;; @@ -172,7 +146,6 @@ ;;; At present on 64-bit target with unicode we have: ;;; (logcount (logxor complex-character-string-widetag simple-character-string-widetag)) = 2 ;;; (logcount (logxor complex-base-string-widetag simple-base-string-widetag)) = 2 -;;; (logcount (logxor complex-vector-nil-widetag simple-array-nil-widetag)) = 3 ;;; (logcount (logxor complex-bit-vector-widetag simple-bit-vector-widetag)) = 1 ;;; and we have one winner. The situation is slightly different for 32-bit. @@ -191,134 +164,232 @@ ;; SIMPLE-VECTOR means the latter doesn't make it right for SBCL internals. (defconstant widetag-spacing 4) +#+64-bit (defconstant unbound-marker-widetag 9) (eval-when (:compile-toplevel :load-toplevel :execute) (defenum (;; The first widetag must be greater than SB-VM:LOWTAG-LIMIT ;; otherwise code in generic/early-type-vops will suffer ;; a long, horrible death. --njf, 2004-08-09 :start #.(+ (ash 1 n-lowtag-bits) other-immediate-0-lowtag) :step 4) - ; +unicode -unicode -;; Word bits ; 32 | 64 32 | 64 - ;------------------ - ; [ all numbers are hex ] - bignum-widetag ; 0A 11 0A 11 - ratio-widetag ; 0E 15 0E 15 - single-float-widetag ; 12 19 12 19 - double-float-widetag ; 16 1D 16 1D - complex-widetag ; 1A 21 1A 21 - complex-single-float-widetag ; 1E 25 1E 25 - complex-double-float-widetag ; 22 29 22 29 - - code-header-widetag ; 26 2D 26 2D - - simple-fun-widetag ; 2A 31 2A 31 - closure-widetag ; 2E 35 2E 35 - funcallable-instance-widetag ; 32 39 32 39 - - ;; x86[-64] does not have objects with this widetag, - #+(or x86 x86-64) unused00-widetag - #-(or x86 x86-64) - return-pc-widetag ; 36 3D 36 3D - - value-cell-widetag ; 3A 41 3A 41 - symbol-widetag ; 3E 45 3E 45 - character-widetag ; 42 49 42 49 - sap-widetag ; 46 4D 46 4D - unbound-marker-widetag ; 4A 51 4A 51 - weak-pointer-widetag ; 4E 55 4E 55 - instance-widetag ; 52 59 52 59 - fdefn-widetag ; 56 5D 56 5D - - no-tls-value-marker-widetag ; 5A 61 5A 61 - #-sb-simd-pack - unused01-widetag ; 5E 5E - #+sb-simd-pack - simd-pack-widetag ; 65 65 - #-sb-simd-pack-256 - unused03-widetag ; 62 69 62 69 - #+sb-simd-pack-256 - simd-pack-256-widetag ; 62 69 62 69 - filler-widetag ; 66 6D 66 6D - unused04-widetag ; 6A 71 6A 71 - unused05-widetag ; 6E 75 6E 75 - unused06-widetag ; 72 79 72 79 - unused07-widetag ; 76 7D 76 7D - #-64-bit - unused08-widetag ; 7A 7A - #-64-bit - unused09-widetag ; 7E 7E +;; Word bits ; 32 | 64 + ;--------- + ; [ all numbers are hex ] - simple-array-widetag ; 82 81 82 81 - simple-array-unsigned-byte-2-widetag ; 86 85 86 85 - simple-array-unsigned-byte-4-widetag ; 8A 89 8A 89 - simple-array-unsigned-byte-7-widetag ; 8E 8D 8E 8D - simple-array-unsigned-byte-8-widetag ; 92 91 92 91 - simple-array-unsigned-byte-15-widetag ; 96 95 96 95 - simple-array-unsigned-byte-16-widetag ; 9A 99 9A 99 + ;; NOTE: If changing the widetags bracketed by the comment about EQL-hash, + ;; check that the definition of stable_eql_hash_p() in gc-common is correct. + ;; FIXME: EQL-HASH should treat SAP like a number + ;; -- start of numeric widetags -- + bignum-widetag ; 0A 11 \ + ratio-widetag ; 0E 15 | + single-float-widetag ; 12 19 | + double-float-widetag ; 16 1D | EQL-hash picks off this + complex-widetag ; 1A 21 | range of widetags. + complex-single-float-widetag ; 1E 25 | + complex-double-float-widetag ; 22 29 | + ;; -- end of numeric widetags -- | + symbol-widetag ; 26 2D / + sap-widetag ; 2A 31 - #-64-bit - simple-array-unsigned-fixnum-widetag ; 9E A5 9E A5 - simple-array-unsigned-byte-31-widetag ; A2 9D A2 9D - simple-array-unsigned-byte-32-widetag ; A6 A1 A6 A1 - #+64-bit - simple-array-unsigned-fixnum-widetag ; 9E A5 9E A5 - #+64-bit - simple-array-unsigned-byte-63-widetag ; A9 A9 - #+64-bit - simple-array-unsigned-byte-64-widetag ; AD AD - simple-array-signed-byte-8-widetag ; AA B1 AA B1 - simple-array-signed-byte-16-widetag ; AE B5 AE B5 - #-64-bit - simple-array-fixnum-widetag ; B2 BD B2 BD - simple-array-signed-byte-32-widetag ; B6 B9 B6 B9 - #+64-bit - simple-array-fixnum-widetag ; B2 BD B2 BD - #+64-bit - simple-array-signed-byte-64-widetag ; C1 C1 - simple-array-single-float-widetag ; BA C5 BA C5 - simple-array-double-float-widetag ; BE C9 BE C9 - simple-array-complex-single-float-widetag ; C2 CD C2 CD - simple-array-complex-double-float-widetag ; C6 D1 C6 D1 - simple-bit-vector-widetag ; CA D5 CA D5 - simple-vector-widetag ; CE D9 CE D9 - - ;; Strings - simple-array-nil-widetag ; D2 DD D2 DD - simple-base-string-widetag ; D6 E1 D6 E1 - #+sb-unicode - simple-character-string-widetag ; DA E5 - #+sb-unicode - complex-character-string-widetag ; DE E9 - complex-base-string-widetag ; E2 ED DA E5 - complex-vector-nil-widetag ; E6 F1 DE E9 - - complex-bit-vector-widetag ; EA F5 E2 ED - complex-vector-widetag ; EE F9 E6 F1 - complex-array-widetag ; F2 FD EA F5 + code-header-widetag ; 2E 35 + instance-widetag ; 32 39 + funcallable-instance-widetag ; 36 3D + simple-fun-widetag ; 3A 41 + closure-widetag ; 3E 45 + + #-(or x86 x86-64 arm64 riscv) return-pc-widetag ; 42 49 + #+(or x86 x86-64 arm64 riscv) lra-widetag-notused + + value-cell-widetag ; 46 4D + character-widetag ; 4A 51 + #-64-bit unbound-marker-widetag ; 4E 55 + #+64-bit unused00-widetag + weak-pointer-widetag ; 52 59 + fdefn-widetag ; 56 5D + + unused-widetag ; 5A 61 + #+sb-simd-pack simd-pack-widetag ; 65 + #-sb-simd-pack unused01-widetag ; 5E + #+sb-simd-pack-256 simd-pack-256-widetag ; 69 + #-sb-simd-pack-256 unused03-widetag ; 62 + filler-widetag ; 66 6D + unused04-widetag ; 6A 71 + unused05-widetag ; 6E 75 + unused06-widetag ; 72 79 + unused07-widetag ; 76 7D + #-64-bit unused08-widetag ; 7A + #-64-bit unused09-widetag ; 7E + + simple-array-widetag ; 82 81 + ;; NIL element type is not in the contiguous range of widetags + ;; corresponding to SIMPLE-UNBOXED-ARRAY + simple-array-nil-widetag ; 86 + + ;; IF YOU CHANGE THIS ORDER, THEN MANUALLY VERIFY CORRECTNESS OF: + ;; - leaf_obj_widetag_p() + ;; - readonly_unboxed_obj_p() + ;; - conservative_root_p() + ;; - anything else I forgot to mention + simple-vector-widetag ; 8A + simple-bit-vector-widetag ; 8E + simple-array-unsigned-byte-2-widetag ; 92 + simple-array-unsigned-byte-4-widetag ; 96 + simple-array-unsigned-byte-7-widetag ; 9A + simple-array-unsigned-byte-8-widetag ; 9E + simple-array-unsigned-byte-15-widetag ; A2 + simple-array-unsigned-byte-16-widetag ; A6 + + #-64-bit simple-array-unsigned-fixnum-widetag ; + simple-array-unsigned-byte-31-widetag ; + simple-array-unsigned-byte-32-widetag ; + #+64-bit simple-array-unsigned-fixnum-widetag ; + #+64-bit simple-array-unsigned-byte-63-widetag ; + #+64-bit simple-array-unsigned-byte-64-widetag ; + simple-array-signed-byte-8-widetag ; + simple-array-signed-byte-16-widetag ; + #-64-bit simple-array-fixnum-widetag ; + simple-array-signed-byte-32-widetag ; + #+64-bit simple-array-fixnum-widetag ; + #+64-bit simple-array-signed-byte-64-widetag ; + simple-array-single-float-widetag ; + simple-array-double-float-widetag ; + simple-array-complex-single-float-widetag ; + simple-array-complex-double-float-widetag ; + + ;; WARNING: If you change the order of anything here, + ;; be sure to examine COMPUTE-OBJECT-HEADER to see that it works + ;; properly for all non-simple array headers. + simple-base-string-widetag ; D6 E1 \ + #+sb-unicode simple-character-string-widetag ; DA E5 | Strings + #-sb-unicode unused-simple-char-string ; | + ;; From here down commence the non-simple array types | + complex-base-string-widetag ; DE E9 | + #+sb-unicode complex-character-string-widetag ; E2 ED / + #-sb-unicode unused-complex-char-string + + complex-bit-vector-widetag ; E6 F1 + complex-vector-widetag ; EA F5 + complex-array-widetag ; EE F9 + unused-array-widetag ; F2 FD )) +;;; A filler cons whose first word is all 1s looks like this marker pattern, +;;; but there's no ambiguity, because no-tls-value can't appear in an object +;;; on the heap. +(defconstant no-tls-value-marker most-positive-word) + +;;; Map each widetag symbol to a string to go in 'tagnames.h'. +;;; I didn't want to mess with the formatting of the table above. +(defparameter *widetag-string-alist* + `((bignum-widetag "bignum") + (ratio-widetag "ratio") + (single-float-widetag "sfloat") + (double-float-widetag "dfloat") + (complex-widetag "cplxnum") + (complex-single-float-widetag "cplx-sfloat") + (complex-double-float-widetag "cplx-dfloat") + (symbol-widetag "symbol") + (instance-widetag "instance") + (funcallable-instance-widetag "funinstance") + (simple-fun-widetag "simplefun") + (closure-widetag "closure") + (code-header-widetag "codeblob") + (return-pc-widetag "LRA") + (value-cell-widetag "value-cell") + (character-widetag "char") + (sap-widetag "sap") + (unbound-marker-widetag "unbound-marker") + (weak-pointer-widetag "weakptr") + (fdefn-widetag "fdefn") + (simd-pack-widetag "SIMD-pack") + (simd-pack-256-widetag "SIMD-pack256") + (filler-widetag "filler") + (simple-array-widetag "simple-array") + (simple-array-nil-widetag "simple-array-NIL") + (simple-vector-widetag "simple-vec") + (simple-bit-vector-widetag "simple-bit-vec") + (simple-array-fixnum-widetag "fixnum-vec") + (simple-array-unsigned-fixnum-widetag "Ufixnum-vec") + ;; Autogenerate the arrays. Not all values of N are used, but it's OK + ,@(loop for n in '("2" "4" "7" "8" "15" "16" "31" "32" "63" "64") + append `((,(symbolicate "SIMPLE-ARRAY-UNSIGNED-BYTE-" n "-WIDETAG") + ,(concatenate 'string "UB" n "-vec")) + (,(symbolicate "SIMPLE-ARRAY-SIGNED-BYTE-" n "-WIDETAG") + ,(concatenate 'string "SB" n "-vec")))) + (simple-array-single-float-widetag "sfloat-vec") + (simple-array-double-float-widetag "dfloat-vec") + (simple-array-complex-single-float-widetag "cplx-sfloat-vec") + (simple-array-complex-double-float-widetag "cplx-dfloat-vec") + (simple-base-string-widetag "simple-base-str") + (simple-character-string-widetag "simple-char-str") + ;; I proposed on sbcl-devel some years ago to rename "complex" to "fancy" + ;; to avoid confusion with complex numbers. That never gained traction. + (complex-base-string-widetag "fancy-base-str") + (complex-character-string-widetag "fancy-char-str") + (complex-bit-vector-widetag "fancy-bit-vec") + (complex-vector-widetag "fancy-vec") + (complex-array-widetag "fancy-array"))) + +(defun widetag-string-name (symbol) + ;; Asserting found + (the string (second (assoc symbol *widetag-string-alist*)))) + +;;; Check that INSTANCE and FUNCALLABLE-INSTANCE differ at exactly 1 bit +;;; and that FUNCALLABLE-INSTANCE is the larger of the two widetags. +(eval-when (:compile-toplevel) + (assert (= (logcount (logand (logxor instance-widetag funcallable-instance-widetag) + lowtag-mask)) + 1)) + ;; Note: you must adjust FUNINSTANCE_SELECTOR_BIT_NUMBER (= 2) if the widetags change + (assert (= funcallable-instance-widetag + (logior instance-widetag (ash 1 2))))) + (defconstant-eqx +function-widetags+ '#.(list funcallable-instance-widetag simple-fun-widetag closure-widetag) #'equal) -;;; the different vector subtypes, can be ORed together. -(defconstant vector-normal-subtype 0) -;; Weak vectors that are NOT hash-table backing vectors use this bit to track -;; whether we've already recorded the vector for deferred scavenging. -;; Hash-tables use an entirely different mechanism. Flag bit used only in C. -(defconstant vector-weak-visited-subtype 8) -;; All hash-table backing vectors are marked with this bit. -;; Essentially it informs GC that the vector has a high-water mark. -(defconstant vector-hashing-subtype 4) -;; Set if hash-table contains address-sensitive keys and possibly -;; an associated vector of 32-bit hashes. -;; When upsizing a table, both the old and new vector may have this bit set. -(defconstant vector-addr-hashing-subtype 2) -;; Set if vector is weak. Weak hash tables have both this AND the hashing bit. -(defconstant vector-weak-subtype 1) +;;; the different vector flags can be ORed together. + +;;; Byte index: 3 2 1 0 +;;; +-----------------------------------+-----------+ +;;; | extra | flags | rank | widetag | +;;; +-----------+-----------+-----------+-----------+ +;;; |<---------- HEADER DATA ---------->| + +;;; "extra" contain the following fields: +;;; - generation number for immobile space (4 low bits of extra) +;;; - fullcgc mark bit (header bit index 31), not used by Lisp +;;; - VISITED bit (header bit index 30) for weak vectors, not used by Lisp +;;; - ALLOC-DYNAMIC-EXTENT (bit index 29), not used by lisp +;;; - ALLOC-MIXED-REGION (bit index 28), not used by Lisp + +;; When I finish implementing "highly unsafe" dynamic-extent allocation, allowing +;; uninitialized SIMPLE-VECTORs on the stack, _correct_ Lisp code won't be affected +;; (it's an error to read before writing an element), nor will conservative GC. +;; But in order to make printing (Lisp and/or ldb) not crashy, we may need to act +;; as though *PRINT-ARRAY* were NIL on those. +;; (I don't know what to do if such a vector insists on being printed readably) +(defconstant +vector-alloc-dynamic-extent-bit+ (ash 1 29)) + +;; A vector with ALLOC-MIXED-REGION can never be moved to a purely boxed page, +;; and vectors not so marked could be. This would allow small simple-vectors +;; to benefit from the same GC optimization as large ones, wherein we scan +;; only their marked cards without regard to object base address. +;; A hash-table vector must not move to a pure boxed page, but we can't indicate +;; a vector as hashing until after it has been properly initialized. +;; The table algorithms expects to see certain values in the first and last elements, +;; and shoving all the initialization into pseudo-atomic would be nontrivial. +;; So we need a different flag bit that can be set immediately on creation, +;; just in case GC occurs before a hash table vector is flagged as hashing. +;; Note: ALLOCATE-VECTOR on 32-bit wants its first argument to be POSITIVE-FIXNUM. +;; so this is the highest bit index that can be used satisfying that restriction. +;; Once set, this bit can never be cleared. +(defconstant +vector-alloc-mixed-region-bit+ (ash 1 28)) -;;; These next two constants must not occupy the same byte of a -;;; vector header word as the values in the preceding defenum. +;;; Rank and widetag adjacent lets SIMPLE-ARRAY-HEADER-OF-RANK-P be just one comparison. +(defconstant array-rank-position 8) +(defconstant array-flags-position 16) + +(defconstant array-flags-data-position (- array-flags-position n-widetag-bits)) ;; A vector tagged as +VECTOR-SHAREABLE+ is logically readonly, ;; and permitted to be shared with another vector per the CLHS standard @@ -326,7 +397,7 @@ ;; often the print-name of a symbol, or was a literal in source code ;; and loaded from a fasl, or used in a few others situations ;; which warrant sharing. -(defconstant +vector-shareable+ #x100) +(defconstant +vector-shareable+ #x20) ;; A vector tagged as +VECTOR-SHAREABLE-NONSTD+ is logically readonly, ;; and *not* technically permitted by the standard to be shared. @@ -335,7 +406,19 @@ ;; into memory, where the requirement is that the machine code ;; reference "the same" object as appeared in source, but where, ;; nonetheless, opportunities for sharing abound. -(defconstant +vector-shareable-nonstd+ #x200) +(defconstant +vector-shareable-nonstd+ #x10) + +;; All arrays have a fill-pointer bit, but only vectors can have a 1 here. +(defconstant +array-fill-pointer-p+ #x80) +;; All hash-table backing vectors are marked with this bit. +;; Essentially it informs GC that the vector has a high-water mark. +(defconstant vector-hashing-flag #x04) +;; Set if hash-table contains address-sensitive keys and possibly +;; an associated vector of 32-bit hashes. +;; When upsizing a table, both the old and new vector may have this bit set. +(defconstant vector-addr-hashing-flag #x02) +;; Set if vector is weak. Weak hash tables have both this AND the hashing bit. +(defconstant vector-weak-flag #x01) ;;; This header bit is set for symbols which were present in the pristine core. ;;; The backend may emit different code when referencing such symbols. @@ -357,7 +440,7 @@ (defglobal function-layout 0)) ; set by genesis #| -;; Run this in the SB-VM or SB-VM package once for each target feature combo. +;; Run this in the SB-VM package once for each target feature combo. (defun rewrite-widetag-comments () (rename-file "src/compiler/generic/early-objdef.lisp" "early-objdef.old") (with-open-file (in "src/compiler/generic/early-objdef.old") diff --git a/src/compiler/generic/early-vm.lisp b/src/compiler/generic/early-vm.lisp index 79927abad2..3fcb3fc47c 100644 --- a/src/compiler/generic/early-vm.lisp +++ b/src/compiler/generic/early-vm.lisp @@ -61,10 +61,10 @@ ;;; a mask to extract the type from a data block header word (defconstant widetag-mask (1- (ash 1 n-widetag-bits))) -(defconstant sb-xc:most-positive-fixnum +(defconstant most-positive-fixnum (1- (ash 1 n-positive-fixnum-bits)) "the fixnum closest in value to positive infinity") -(defconstant sb-xc:most-negative-fixnum +(defconstant most-negative-fixnum (ash -1 n-positive-fixnum-bits) "the fixnum closest in value to negative infinity") @@ -72,11 +72,42 @@ "The most positive integer that is of type SB-EXT:WORD.") (defconstant maximum-bignum-length - ;; Compute number of bits in the maximum length's representation - ;; leaving one bit for a GC mark bit. - (ldb (byte (- n-word-bits n-widetag-bits 1) 0) -1)) - -(defconstant sb-xc:char-code-limit #-sb-unicode 256 #+sb-unicode #x110000 + ;; 32-bit: leave one bit for a GC mark bit + #-64-bit (ldb (byte (- n-word-bits n-widetag-bits 1) 0) -1) + ;; 64-bit: restrict to a reasonably large theoretical size of 32GiB per bignum. + ;; I haven't exercised our math routines to anywhere near that limit. + #+64-bit #xFFFFFFFF) + +;;; The ANSI-specified minimum is 8. +;;; Since the array rank is stored as rank-1 in the array header, +;;; having it stop at 128 ensures that adding 1 produces an unsigned +;;; result. +(defconstant array-rank-limit 129 + "the exclusive upper bound on the rank of an array") + +;;; FIXME: these limits are wrong at the most basic level according to the spec, +;;; because if there are different limits for different element types, then +;;; this constant should be the _smallest_ of the limits for any element type. +;;; The largest element size is (COMPLEX DOUBLE-FLOAT) taking 16 bytes per element. +;;; If you had an array of this size on 32-bit machines, it would consume about +;;; 8GB of payload. So not only is it larger than a fixnum - a problem for the +;;; allocator vops - it exceeds the address space. +#-ubsan ; usual way +(progn +;;; - 2 to leave space for the array header +(defconstant array-dimension-limit (- most-positive-fixnum 2) + "the exclusive upper bound on any given dimension of an array") + +(defconstant array-total-size-limit (- most-positive-fixnum 2) + "the exclusive upper bound on the total number of elements in an array") +) + +#+ubsan ; only supported if 64-bit +(progn +(defconstant array-dimension-limit (ash 1 30)) +(defconstant array-total-size-limit (ash 1 30))) + +(defconstant char-code-limit #-sb-unicode 256 #+sb-unicode #x110000 "the upper exclusive bound on values produced by CHAR-CODE") (defconstant base-char-code-limit #-sb-unicode 256 #+sb-unicode 128) @@ -94,13 +125,13 @@ (defconstant sb-kernel::internal-time-bits 61) (defconstant most-positive-exactly-single-float-fixnum - (min (expt 2 single-float-digits) sb-xc:most-positive-fixnum)) + (min (expt 2 single-float-digits) most-positive-fixnum)) (defconstant most-negative-exactly-single-float-fixnum - (max (- (expt 2 single-float-digits)) sb-xc:most-negative-fixnum)) + (max (- (expt 2 single-float-digits)) most-negative-fixnum)) (defconstant most-positive-exactly-double-float-fixnum - (min (expt 2 double-float-digits) sb-xc:most-positive-fixnum)) + (min (expt 2 double-float-digits) most-positive-fixnum)) (defconstant most-negative-exactly-double-float-fixnum - (max (- (expt 2 double-float-digits)) sb-xc:most-negative-fixnum)) + (max (- (expt 2 double-float-digits)) most-negative-fixnum)) ;;;; Point where continuous area starting at dynamic-space-start bumps into ;;;; next space. Computed for genesis/constants.h, not used in Lisp. @@ -109,8 +140,7 @@ (let ((stop (1- (ash 1 n-word-bits))) (start dynamic-space-start)) (dolist (other-start (list read-only-space-start static-space-start - #+linkage-table - linkage-table-space-start)) + alien-linkage-table-space-start)) (declare (notinline <)) ; avoid dead code note (when (< start other-start) (setf stop (min stop other-start)))) @@ -132,6 +162,11 @@ ;;; which can be expressed in 8 bits. (defconstant short-header-max-words #x7fff) +#+gencgc +(defconstant max-conses-per-page + (floor (* gencgc-page-bytes n-byte-bits) + (1+ (* n-word-bytes 2 n-byte-bits)))) ; 1 extra bit per cons + ;;; Amount to righ-shift an instance header to get the length. ;;; Similar consideration as above with regard to use of generation# byte. (defconstant instance-length-shift 10) @@ -141,31 +176,7 @@ #+sb-xc-host (defun fixnump (x) (and (integerp x) - (<= sb-xc:most-negative-fixnum x sb-xc:most-positive-fixnum))) - -;;; Helper macro for defining FIXUP-CODE-OBJECT so that its body -;;; can be the same between the host and target. -;;; In the target, the byte offset supplied is relative to CODE-INSTRUCTIONS. -;;; Genesis works differently - it adjusts the offset so that it is relative -;;; to the containing gspace since that's what bvref requires. -(defmacro !with-bigvec-or-sap (&body body) - `(macrolet #-sb-xc-host () - #+sb-xc-host - ((code-instructions (code) `(sb-fasl::descriptor-mem ,code)) - (sap-int (sap) - ;; KLUDGE: SAP is a bigvec; it doesn't know its address. - ;; Note that this shadows the uncallable stub function for SAP-INT - ;; that placates the host when compiling 'compiler/*/move.lisp'. - (declare (ignore sap)) - `(locally - (declare (notinline sb-fasl::descriptor-gspace)) ; fwd ref - (sb-fasl::gspace-byte-address - (sb-fasl::descriptor-gspace code)))) ; use CODE, not SAP - (sap-ref-8 (sap offset) `(sb-fasl::bvref-8 ,sap ,offset)) - (sap-ref-32 (sap offset) `(sb-fasl::bvref-32 ,sap ,offset)) - (sap-ref-64 (sap offset) `(sb-fasl::bvref-64 ,sap ,offset)) - (sap-ref-word (sap offset) `(sb-fasl::bvref-word ,sap ,offset))) - ,@body)) + (<= most-negative-fixnum x most-positive-fixnum))) #+sb-safepoint ;;; The offset from the fault address reported to the runtime to the @@ -173,3 +184,58 @@ (defconstant gc-safepoint-trap-offset n-word-bytes) #+sb-xc-host (deftype sb-xc:fixnum () `(signed-byte ,n-fixnum-bits)) + +;;; Supporting code for LAYOUT allocated in metadata space a/k/a "metaspace". +;;; These objects are manually allocated and freed. +;;; Tracts are the unit of allocation requested from the OS. +;;; Following the nomenclature in https://en.wikipedia.org/wiki/Slab_allocation +;;; - A slab is the quantum requested within a tract. +;;; - Chunks are the units of allocation ("objects") within a slab. + +(defconstant metaspace-tract-size (* 2 1024 1024)) ; 2 MiB +(defconstant metaspace-slab-size 2048) ; 2 KiB + +;;; Chunks are all the same size per slab, which makes finding the next available +;;; slot simply a pop from a freelist. The object stored in the chunk can be anything +;;; not to exceed the chunk size. (You can't span chunks with one object) +;;; All slabs of a given size with any available space are kept in a doubly-linked +;;; list for the slab's chunk size. A slab is removed from the doubly-linked list and +;;; moved to the slab recycle list when all chunks within it become free. +;;; +;;; There are 4 words of overhead per slab. +;;; At present only 64-bit word size is supported, so we assume +;;; that pointer-sized words in the slab header consume 8 bytes. +;;; word 0: 2 bytes : sizeclass (as a FIXNUM) +;;; 2 bytes : capacity in objects +;;; 2 bytes : chunk size +;;; 2 bytes : number of objects allocated in it +;;; word 1: head of freelist +;;; word 2: next slab with any holes in the same sizeclass +;;; word 3: previous slab with any holes in the same sizeclass +;;; +;;; The FIXNUM representation of sizeclass causes the entire lispword +;;; to read as a fixnum, which makes it possible to map-allocated-objects +;;; over the slabs in a chunk without fuss. The slab heade appears +;;; just like 2 conses. (The next/prev pointers look like fixnums) +;;; +;;; #+big-endian will need to flip the positions of these sub-fields +;;; to make the lispword read as fixnum. + +;;; Keep in sync with the structure definition in src/runtime/alloc.c +(defconstant slab-overhead-words 4) +(defmacro slab-sizeclass (slab) `(sap-ref-16 ,slab 0)) +(defmacro slab-capacity (slab) `(sap-ref-16 ,slab 2)) +(defmacro slab-chunk-size (slab) `(sap-ref-16 ,slab 4)) +(defmacro slab-usage (slab) `(sap-ref-16 ,slab 6)) +(defmacro slab-freelist (slab) `(sap-ref-sap ,slab 8)) +(defmacro slab-next (slab) `(sap-ref-sap ,slab 16)) +(defmacro slab-prev (slab) `(sap-ref-sap ,slab 24)) +(defmacro slab-usable-range-start (slab) `(sap+ ,slab (* 4 n-word-bytes))) + +(defmacro init-slab-header (slab sizeclass chunksize capacity) + `(setf (slab-sizeclass ,slab) (ash ,sizeclass n-fixnum-tag-bits) + (slab-capacity ,slab) ,capacity + (slab-chunk-size ,slab) ,chunksize)) + +#+gencgc +(defconstant gencgc-page-words (/ gencgc-page-bytes n-word-bytes)) diff --git a/src/compiler/generic/genesis.lisp b/src/compiler/generic/genesis.lisp index a27d8653b6..a9a233fb82 100644 --- a/src/compiler/generic/genesis.lisp +++ b/src/compiler/generic/genesis.lisp @@ -28,8 +28,26 @@ (in-package "SB-FASL") +;;; Some build systems frown upon excessive use (or any use) of "-I" options +;;; on the C compiler invocation. So depending on the current working directory +;;; when generating headers and when building, the pathname where we produce +;;; headers may differ from the string specified in #include lines. +;;; The :C-HEADER-DIR-NAME keyword to genesis specifies the output path, +;;; and this symbol (which is normally unbound) specifies the #include prefix. +;;; The normal build is done within src/runtime and does not need +;;; anything done to set this. +(defun genesis-header-prefix () + (if (boundp 'cl-user::*genesis-header-prefix*) + (symbol-value 'cl-user::*genesis-header-prefix*) + "genesis")) +;;; By the same reasoning as above, lispobj.h is either in "." or a relative path. +(defun lispobj-dot-h () + (if (boundp 'cl-user::*lispobj-h-namestring*) + (symbol-value 'cl-user::*lispobj-h-namestring*) + "lispobj.h")) + (eval-when (:compile-toplevel :load-toplevel :execute) - (use-package "SB-COREFILE")) ; not SB-COREFILE + (use-package "SB-COREFILE")) (defun round-up (number size) "Round NUMBER up to be an integral multiple of SIZE." @@ -98,29 +116,53 @@ (* (length (bigvec-outer-vector bigvec)) +smallvec-length+)) +(defparameter *bigvec-for-write-words* (%make-bigvec)) +(defun write-words (stream &rest words) + (let ((bigvec *bigvec-for-write-words*) + (offset 0)) + (dolist (word words) + (setf (bvref-word bigvec offset) (the sb-vm:word word)) + (incf offset sb-vm:n-word-bytes)) + (write-sequence (elt (bigvec-outer-vector bigvec) 0) stream :end offset))) + ;;; analogous to WRITE-SEQUENCE, but for a BIGVEC -(defun write-bigvec-as-sequence (bigvec stream &key (start 0) end pad-with-zeros) - (let* ((bvlength (bvlength bigvec)) - (data-length (min (or end bvlength) bvlength))) - (loop for i of-type index from start below data-length do - (write-byte (bvref bigvec i) - stream)) +(defun write-bigvec-as-sequence (bigvec stream &key end pad-with-zeros) + (binding* ((bvlength (bvlength bigvec)) + (data-length (min (or end bvlength) bvlength)) + ;; Compute the coordinates of the final byte to be written + ((outer-index inner-index) + (if (zerop data-length) + (values 0 -1) + (floor (1- data-length) +smallvec-length+)))) + ;; Each SMALLVEC prior to the one indexed by outer-index is written in its entirety + (dotimes (i outer-index) + (write-sequence (elt (bigvec-outer-vector bigvec) i) stream)) + ;; The SMALLVEC at OUTER-INDEX is written up to and including INNER-INDEX + (write-sequence (elt (bigvec-outer-vector bigvec) outer-index) stream + :end (1+ inner-index)) + ;; FIXME: This logic from rev 243d0f6f59 says it's needed if +SMALLVEC-LENGTH+ is + ;; less than backend page bytes, but if that were true (which it never is) + ;; we should just increase +SMALLVEC-LENGTH+. And how can could it be right even in + ;; that case? DATA-LENGTH is not larger than BVLENGTH, because it it were, + ;; you asked to write more than the vector holds. Istm this is garbage + ;; but I'm afraid to remove it. (when (and pad-with-zeros (< bvlength data-length)) (loop repeat (- data-length bvlength) do (write-byte 0 stream))))) ;;; analogous to READ-SEQUENCE-OR-DIE, but for a BIGVEC -(defun read-bigvec-as-sequence-or-die (bigvec stream &key (start 0) end) - (loop for i of-type index from start below (or end (bvlength bigvec)) do - (setf (bvref bigvec i) - (read-byte stream)))) - -(defun read-n-bytes (stream vector start end) - (aver (zerop start)) - (let* ((start (+ (descriptor-byte-offset vector) - (ash sb-vm:vector-data-offset sb-vm:word-shift))) - (end (+ start end))) - (read-bigvec-as-sequence-or-die (descriptor-mem vector) - stream :start start :end end))) +;;; FIXME: should signal error on EOF +(defun read-into-bigvec (bigvec stream start nbytes) + ;; compute the coordinates of the start and end + (binding* (((start-outer start-inner) (floor start +smallvec-length+)) + ;; this the INCLUSIVE bound on the ending element + (end-outer (floor (+ start nbytes -1) +smallvec-length+))) + ;; if it's all into a single outer vector, take the quick route + (if (= start-outer end-outer) + (read-sequence (elt (bigvec-outer-vector bigvec) start-outer) stream + :start start-inner :end (+ start-inner nbytes)) + ;; KISS - use the slow algorithm rather than any "partial read" cleverness + (loop for i of-type index from start repeat nbytes + do (setf (bvref bigvec i) (read-byte stream)))))) ;;; Grow BIGVEC (exponentially, so that large increases in size have ;;; asymptotic logarithmic cost per byte). @@ -155,24 +197,56 @@ for i from 0 collect `(ash (bvref bigvec ,index) ,(* i 8))))) (defun (setf ,name) (new-value bigvec byte-index) - ;; We don't carefully distinguish between signed and unsigned, - ;; since there's only one setter function per byte size. - (declare (type (or (signed-byte ,n) (unsigned-byte ,n)) - new-value)) + (declare (type (unsigned-byte ,n) new-value)) (setf ,@(loop for index in le-octet-indices for i from 0 append `((bvref bigvec ,index) - (ldb (byte 8 ,(* i 8)) new-value))))))))) + (ldb (byte 8 ,(* i 8)) new-value)))) + new-value))))) (make-bvref-n 8) (make-bvref-n 16) (make-bvref-n 32) (make-bvref-n 64)) +(defun (setf bvref-s32) (newval bv index) + (setf (bvref-32 bv index) (ldb (byte 32 0) (the (signed-byte 32) newval))) + newval) + +#+host-quirks-sbcl +(progn + (declaim (inline native-bvref-word (setf native-bvref-word))) + (defun native-bvref-word (bigvec byte-index) + (multiple-value-bind (outer-index inner-index) (floor byte-index +smallvec-length+) + (host-sb-kernel:%vector-raw-bits + (the smallvec (svref (bigvec-outer-vector bigvec) outer-index)) + (ash inner-index (- sb-vm:word-shift))))) + (defun (setf native-bvref-word) (newval bigvec byte-index) + (multiple-value-bind (outer-index inner-index) (floor byte-index +smallvec-length+) + (setf (host-sb-kernel:%vector-raw-bits + (the smallvec (svref (bigvec-outer-vector bigvec) outer-index)) + (ash inner-index (- sb-vm:word-shift))) + newval)))) + ;; lispobj-sized word, whatever that may be ;; hopefully nobody ever wants a 128-bit SBCL... -(macrolet ((acc (bv index) `(#+64-bit bvref-64 #-64-bit bvref-32 ,bv ,index))) - (defun (setf bvref-word) (new-val bytes index) (setf (acc bytes index) new-val)) - (defun bvref-word (bytes index) (acc bytes index))) +(macrolet ((access (bv index &optional alignedp) + (cond ((and alignedp + (and (member :sbcl cl:*features*) + (sb-cold::compatible-vector-raw-bits))) + `(native-bvref-word ,bv ,index)) + (t + `(#+64-bit bvref-64 #-64-bit bvref-32 ,bv ,index))))) + (defun (setf bvref-word-unaligned) (new-val bytes index) + (declare (type sb-xc:fixnum index)) + (setf (access bytes index) new-val)) + (defun (setf bvref-word) (new-val bytes index) + (declare (type sb-xc:fixnum index)) + (aver (not (logtest index (ash sb-vm:lowtag-mask -1)))) + (setf (access bytes index t) new-val)) + (defun bvref-word (bytes index) + (declare (type sb-xc:fixnum index)) + (aver (not (logtest index (ash sb-vm:lowtag-mask -1)))) + (access bytes index t))) ;;;; representation of spaces in the core @@ -182,18 +256,23 @@ (defvar *dynamic*) (defvar *static*) (defvar *read-only*) +(defvar core-file-name) #+immobile-space (progn + (defvar *asm-routine-vector*) (defvar *immobile-fixedobj*) - (defvar *immobile-varyobj*) + (defvar *immobile-text*) (defvar *immobile-space-map* nil)) -(defconstant max-core-space-id (+ 3 #+immobile-space 2)) +;;; This ignores alien-linkage-table-core-space-id +;;; which is never present in the core file. +(defconstant max-core-space-id (+ 3 #+immobile-space 2 + #+darwin-jit 1)) (defstruct page - (type nil :type (member nil :code :mixed)) - (bytes-used 0) + (type nil :type (member nil :code :list :mixed)) + (words-used 0) scan-start) ; byte offset from base of the space ;;; a GENESIS-time representation of a memory space (e.g. read-only @@ -203,16 +282,20 @@ ;; name and identifier for this GSPACE (name (missing-arg) :type symbol :read-only t) (identifier (missing-arg) :type fixnum :read-only t) - ;; the word address where the data will be loaded - (word-address (missing-arg) :type unsigned-byte :read-only t) + ;; the address where the data will be loaded + (byte-address (missing-arg) :type unsigned-byte :read-only t) ;; the gspace contents as a BIGVEC (data (make-bigvec) :type bigvec :read-only t) (page-table nil) ; for dynamic space + (cons-region) ; (word-index . limit) ;; lists of holes created by the allocator to segregate code from data. ;; Doesn't matter for cheneygc; does for gencgc. ;; Each free-range is (START . LENGTH) in words. (code-free-ranges (list nil)) (non-code-free-ranges (list nil)) + ;; for metaspace + #+metaspace + current-slab ;; Address of every object created in this space. (objects (or #+sb-devel (make-array 700000 :fill-pointer 0 :adjustable t))) ;; the index of the next unwritten word (i.e. chunk of @@ -221,14 +304,15 @@ ;; index into DATA, thus must be multiplied by SB-VM:N-WORD-BYTES. (free-word-index 0)) -(defun gspace-byte-address (gspace) - (ash (gspace-word-address gspace) sb-vm:word-shift)) +(defun gspace-upper-bound (gspace) + (+ (gspace-byte-address gspace) + (ash (gspace-free-word-index gspace) sb-vm:word-shift))) (cl:defmethod print-object ((gspace gspace) stream) (print-unreadable-object (gspace stream :type t) (format stream "@#x~X ~S" (gspace-byte-address gspace) (gspace-name gspace)))) -(defun make-gspace (name identifier byte-address) +(defun make-gspace (name identifier byte-address &rest rest) ;; Genesis should be agnostic of space alignment except in so far as it must ;; be a multiple of the backend page size. We used to care more, in that ;; descriptor-bits were composed of a high half and low half for the @@ -241,17 +325,46 @@ (unless (zerop (rem byte-address target-space-alignment)) (error "The byte address #X~X is not aligned on a #X~X-byte boundary." byte-address target-space-alignment))) - (%make-gspace :name name + (apply #'%make-gspace :name name :identifier identifier ;; Track page usage :page-table (if (= identifier dynamic-core-space-id) (make-array 100 :adjustable t :initial-element nil)) - :word-address (ash byte-address (- sb-vm:word-shift)) + :byte-address byte-address :free-word-index (cond #+immobile-space ((= identifier immobile-fixedobj-core-space-id) (/ sb-vm:immobile-card-bytes sb-vm:n-word-bytes)) (t - 0)))) + 0)) + rest)) + +(defstruct (model-sap (:constructor make-model-sap (address gspace))) + (address 0 :type sb-vm:word) + (gspace nil :type gspace)) +(defun sap-int (x) (model-sap-address x)) +(defun sap+ (sap x) + (make-model-sap (+ (model-sap-address sap) x) + (model-sap-gspace sap))) +(macrolet ((access (name) + `(,name (gspace-data (model-sap-gspace sap)) + (- (+ (model-sap-address sap) offset) + (gspace-byte-address (model-sap-gspace sap)))))) + (defun sap-ref-8 (sap offset) (access bvref-8)) + (defun sap-ref-16 (sap offset) (access bvref-16)) + (defun sap-ref-32 (sap offset) (access bvref-32)) + (defun sap-ref-64 (sap offset) (access bvref-64)) + (defun signed-sap-ref-32 (sap offset) + (sb-disassem:sign-extend (access bvref-32) 32)) + (defun signed-sap-ref-64 (sap offset) + (sb-disassem:sign-extend (access bvref-64) 64)) + (defun (setf sap-ref-16) (newval sap offset) + (setf (access bvref-16) newval)) + (defun (setf sap-ref-32) (newval sap offset) + (setf (access bvref-32) newval)) + (defun (setf signed-sap-ref-32) (newval sap offset) + (setf (access bvref-32) (ldb (byte 32 0) (the (signed-byte 32) newval)))) + (defun (setf sap-ref-64) (newval sap offset) + (setf (access bvref-64) newval))) ;;;; representation of descriptors @@ -267,12 +380,13 @@ (= (logand lowtag 3) sb-vm:other-immediate-0-lowtag)) (defstruct (descriptor - (:constructor make-descriptor (bits &optional gspace word-offset)) + (:constructor make-descriptor (bits &optional gspace byte-offset)) (:copier nil)) ;; the GSPACE that this descriptor is allocated in, or NIL if not set yet. (gspace nil :type (or gspace null)) - ;; the offset in words from the start of GSPACE, or NIL if not set yet - (word-offset nil :type (or sb-vm:word null)) + ;; the offset in bytes (discounting the lowtag) from the start of GSPACE, + ;; or NIL if not set yet + (byte-offset nil :type (or sb-vm:word null)) (bits 0 :read-only t :type (unsigned-byte #.sb-vm:n-machine-word-bits))) (declaim (inline descriptor=)) @@ -286,36 +400,76 @@ "the lowtag bits for DES" (logand (descriptor-bits des) sb-vm:lowtag-mask)) +(defun descriptor-base-address (des) + (logandc2 (descriptor-bits des) sb-vm:lowtag-mask)) (defmethod print-object ((des descriptor) stream) - (let ((gspace (descriptor-gspace des)) - (bits (descriptor-bits des)) - (lowtag (descriptor-lowtag des))) - (print-unreadable-object (des stream :type t) - (cond ((is-fixnum-lowtag lowtag) - (format stream "for fixnum: ~W" (descriptor-fixnum des))) - ((is-other-immediate-lowtag lowtag) - (format stream - "for other immediate: #X~X, type #b~8,'0B" - (ash bits (- sb-vm:n-widetag-bits)) - (logand bits sb-vm:widetag-mask))) - (t - (format stream - "for pointer: #X~X, lowtag #b~v,'0B, ~A" - (logandc2 bits sb-vm:lowtag-mask) - sb-vm:n-lowtag-bits lowtag - (if gspace (gspace-name gspace) "unknown"))))))) + (print-unreadable-object (des stream :type t) + (let ((lowtag (descriptor-lowtag des)) + (bits (descriptor-bits des))) + (multiple-value-call 'format stream + (cond ((is-fixnum-lowtag lowtag) + (values "for fixnum: ~W" (descriptor-fixnum des))) + ((is-other-immediate-lowtag lowtag) + (values "for other immediate: #X~X, type #b~8,'0B" + (ash bits (- sb-vm:n-widetag-bits)) + (logand bits sb-vm:widetag-mask))) + ((descriptor-gspace des) + (values "for pointer: #X~X, lowtag #b~v,'0B, ~A" + (descriptor-base-address des) + sb-vm:n-lowtag-bits lowtag + (gspace-name (descriptor-gspace des)))) + (t + (values "bits: #X~X" bits))))))) + +;;; Emulate the slab allocator. +;;; If the current slab (at the head of METASPACE-SLABS) +;;; has room, then use it. Otherwise allocate a new slab +;;; at a lower address. +#+metaspace +(defun allocate-metaspace-layout (gspace nbytes) + (aver (= nbytes (* 8 sb-vm:n-word-bytes))) + (let ((slab (gspace-current-slab gspace))) + (flet ((init (slab) + (let ((bytes-avail (- sb-vm:metaspace-slab-size + (* sb-vm::slab-overhead-words sb-vm:n-word-bytes)))) + (sb-vm::init-slab-header + slab + 1 ; sizeclass + nbytes + ;; FIXME: Technically this should use the chunk size of the sizeclass, + ;; not the object size. But they happen to be the same in sizeclass 1. + (floor bytes-avail nbytes))) + (setf (gspace-current-slab gspace) slab))) + (unless slab + (let ((space-size (- sb-vm:read-only-space-end sb-vm:read-only-space-start)) + (slab-base (- sb-vm:read-only-space-end sb-vm:metaspace-slab-size))) + (expand-bigvec (gspace-data gspace) space-size) + (setf slab (init (make-model-sap slab-base gspace))))) + (when (= (sb-vm::slab-usage slab) (sb-vm::slab-capacity slab)) + (format t "~&Slab @ ~x is full~%" (sap-int slab)) + (setf slab (init (sap+ slab (- sb-vm:metaspace-slab-size))))) + (let* ((count (incf (sb-vm::slab-usage slab))) + (ptr (+ (sap-int slab) + (- sb-vm:metaspace-slab-size + (* count (sb-vm::slab-chunk-size slab)))))) + (make-descriptor (logior ptr sb-vm:instance-pointer-lowtag) + gspace + (- ptr (gspace-byte-address gspace))))))) ;;; Return a descriptor for a block of LENGTH bytes out of GSPACE. The ;;; free word index is boosted as necessary, and if additional memory ;;; is needed, we grow the GSPACE. The descriptor returned is a ;;; pointer of type LOWTAG. -(defun allocate-cold-descriptor (gspace length lowtag &optional page-attributes) - (let* ((word-index - (gspace-claim-n-bytes gspace length page-attributes)) - (ptr (+ (gspace-word-address gspace) word-index)) - (des (make-descriptor (logior (ash ptr sb-vm:word-shift) lowtag) - gspace - word-index))) +(defun allocate-cold-descriptor (gspace length lowtag &optional (page-type :mixed)) + (let* ((relative-ptr (ash (gspace-claim-n-bytes gspace length page-type) + sb-vm:word-shift)) + (ptr (+ (gspace-byte-address gspace) relative-ptr)) + (des (if (and (eq gspace *read-only*) (eq lowtag sb-vm:instance-pointer-lowtag)) + #+metaspace + (allocate-metaspace-layout gspace length) + #-metaspace + (error "Shouldn't happen.") + (make-descriptor (logior ptr lowtag) gspace relative-ptr)))) (awhen (gspace-objects gspace) (vector-push-extend des it)) des)) @@ -328,136 +482,133 @@ (setf (gspace-free-word-index gspace) new-free-word-index) old-free-word-index)) -;; Special case for dynamic space code/data segregation +(defconstant min-usable-hole-size 10) ; semi-arbitrary constant to speed up the allocator +;; Place conses and code on their respective page type. #+gencgc -(defun dynamic-space-claim-n-words (gspace n-words page-type) - (let* ((words-per-page (/ sb-vm:gencgc-card-bytes sb-vm:n-word-bytes)) - (holder (ecase page-type - (:code (gspace-code-free-ranges gspace)) - (:mixed (gspace-non-code-free-ranges gspace)))) - (found (find-if (lambda (x) (>= (cdr x) n-words)) - (cdr holder)))) ; dummy cons cell simplifies writeback - (labels ((alignedp (word-index) ; T if WORD-INDEX aligns to a GC page boundary - (not (logtest (* word-index sb-vm:n-word-bytes) - (1- sb-vm:gencgc-card-bytes)))) - (page-index (word-index) - (values (floor word-index words-per-page))) - (pte (index) ; create on demand - (or (aref (gspace-page-table gspace) index) - (setf (aref (gspace-page-table gspace) index) (make-page)))) - (assign-page-types (page-type start-word-index count) - ;; CMUCL incorrectly warns that the result of ADJUST-ARRAY - ;; must not be discarded. - #+host-quirks-cmu (declare (notinline adjust-array)) - (let ((start-page (page-index start-word-index)) - (end-page (page-index (+ start-word-index (1- count))))) - (unless (> (length (gspace-page-table gspace)) end-page) - (adjust-array (gspace-page-table gspace) (1+ end-page) - :initial-element nil)) - (loop for page-index from start-page to end-page - for pte = (pte page-index) - do (if (null (page-type pte)) - (setf (page-type pte) page-type) - (assert (eq (page-type pte) page-type)))))) - (note-it (start-word-index) - (let* ((start-page (page-index start-word-index)) - (end-word-index (+ start-word-index n-words)) - (end-page (page-index (1- end-word-index)))) - ;; pages from start to end (exclusive) must be full - (loop for index from start-page below end-page - do (setf (page-bytes-used (pte index)) sb-vm:gencgc-card-bytes)) - ;; Compute the difference between the word-index at the start of - ;; end-page and the end-word. - (setf (page-bytes-used (pte end-page)) - (* sb-vm:n-word-bytes - (- end-word-index (* end-page words-per-page)))) - ;; update the scan start of any page without it set - (loop for index from start-page to end-page - do (let ((pte (pte index))) - (unless (page-scan-start pte) - (setf (page-scan-start pte) start-word-index))))) - start-word-index) - (get-frontier-page-type () - (page-type (pte (page-index (1- (gspace-free-word-index gspace))))))) - (when found ; Case 1: always try to backfill first if possible +(defun dynamic-space-claim-n-words (gspace n-words page-type + &aux (words-per-page + (/ sb-vm:gencgc-page-bytes sb-vm:n-word-bytes))) + (labels ((alignedp (word-index) ; T if WORD-INDEX aligns to a GC page boundary + (not (logtest (* word-index sb-vm:n-word-bytes) + (1- sb-vm:gencgc-page-bytes)))) + (page-index (word-index) + (values (floor word-index words-per-page))) + (pte (index) ; create on demand + (or (aref (gspace-page-table gspace) index) + (setf (aref (gspace-page-table gspace) index) (make-page)))) + (assign-page-type (page-type start-word-index count) + ;; CMUCL incorrectly warns that the result of ADJUST-ARRAY + ;; must not be discarded. + #+host-quirks-cmu (declare (notinline adjust-array)) + (let ((start-page (page-index start-word-index)) + (end-page (page-index (+ start-word-index (1- count))))) + (unless (> (length (gspace-page-table gspace)) end-page) + (adjust-array (gspace-page-table gspace) (1+ end-page) + :initial-element nil)) + (loop for page-index from start-page to end-page + for pte = (pte page-index) + do (if (null (page-type pte)) + (setf (page-type pte) page-type) + (aver (eq (page-type pte) page-type)))))) + (note-words-used (start-word-index) + (let* ((start-page (page-index start-word-index)) + (end-word-index (+ start-word-index n-words)) + (end-page (page-index (1- end-word-index)))) + ;; pages from start to end (exclusive) must be full + (loop for index from start-page below end-page + do (setf (page-words-used (pte index)) words-per-page)) + ;; Compute the difference between the word-index at the start of + ;; end-page and the end-word. + (setf (page-words-used (pte end-page)) + (- end-word-index (* end-page words-per-page))) + ;; update the scan start of any page without it set + (loop for index from start-page to end-page + do (let ((pte (pte index))) + (unless (page-scan-start pte) + (setf (page-scan-start pte) start-word-index))))) + start-word-index) + (get-frontier-page-type () + (page-type (pte (page-index (1- (gspace-free-word-index gspace)))))) + (realign-frontier () + ;; Align the frontier to a page, putting the empty space onto a free list + (let* ((free-ptr (gspace-free-word-index gspace)) + (avail (- (align-up free-ptr words-per-page) free-ptr)) + (other-type (get-frontier-page-type)) ; before extending frontier + (word-index (gspace-claim-n-words gspace avail))) + ;; the space we got should be exactly what we thought it should be + (aver (= word-index free-ptr)) + (aver (alignedp (gspace-free-word-index gspace))) + (aver (= (gspace-free-word-index gspace) (+ free-ptr avail))) + (when (>= avail min-usable-hole-size) + ;; allocator is first-fit; space goes to the tail of the other freelist. + (nconc (ecase other-type + (:code (gspace-code-free-ranges gspace)) + (:mixed (gspace-non-code-free-ranges gspace))) + (list (cons word-index avail))))))) + (when (eq page-type :list) ; Claim whole pages at a time + (let* ((region + (or (gspace-cons-region gspace) + (progn + (unless (alignedp (gspace-free-word-index gspace)) + (realign-frontier)) + (let ((word-index (gspace-claim-n-words gspace words-per-page))) + (assign-page-type page-type word-index sb-vm:cons-size) + (let ((pte (pte (page-index word-index)))) + (setf (page-scan-start pte) word-index)) + (setf (gspace-cons-region gspace) + (cons word-index + (+ word-index (* (1- sb-vm::max-conses-per-page) + sb-vm:cons-size)))))))) + (result (car region))) + (incf (page-words-used (pte (page-index result))) sb-vm:cons-size) + (when (= (incf (car region) sb-vm:cons-size) (cdr region)) + (setf (gspace-cons-region gspace) nil)) + (return-from dynamic-space-claim-n-words result))) + (let* ((holder (ecase page-type + (:code (gspace-code-free-ranges gspace)) + (:mixed (gspace-non-code-free-ranges gspace)))) + (found (find-if (lambda (x) (>= (cdr x) n-words)) + (cdr holder)))) ; dummy cons cell simplifies writeback + (when found ; always try to backfill holes first if possible (let ((word-index (car found))) - (if (zerop (decf (cdr found) n-words)) - (rplacd holder (delete found (cdr holder) :count 1)) + (if (< (decf (cdr found) n-words) min-usable-hole-size) ; discard this hole now? + (rplacd holder (delete found (cdr holder) :count 1)) ; yup (incf (car found) n-words)) - (return-from dynamic-space-claim-n-words (note-it word-index)))) - (when (or (alignedp (gspace-free-word-index gspace)) - (eq (get-frontier-page-type) page-type)) - ;; Case 2: extend the frontier - (let ((word-index (gspace-claim-n-words gspace n-words))) - ;; could optimize this out if we don't go onto a new page - (assign-page-types page-type word-index n-words) - (return-from dynamic-space-claim-n-words (note-it word-index)))) - ;; Align the frontier to a page, add some more pages for good measure, - ;; and stuff that empty space onto a free list. Then start a new new page. - (let* ((free-ptr (gspace-free-word-index gspace)) - ;; avoid waste by always giving some more slack to the other - ;; type of page before starting a new page - (reserve-extra-pages 4) ; a random heuristic - (reserve (+ (- (align-up free-ptr words-per-page) free-ptr) - (* words-per-page reserve-extra-pages))) - (other-type (get-frontier-page-type)) ; before extending frontier - (word-index (gspace-claim-n-words gspace reserve))) - ;; the space we got should be exactly what we thought it should be - (aver (= word-index free-ptr)) - (aver (alignedp (gspace-free-word-index gspace))) - (aver (= (gspace-free-word-index gspace) (+ free-ptr reserve))) - ;; those pages all have the other type (the one we don't want) - (assign-page-types other-type word-index reserve) - ;; allocator is first-fit; space goes to the tail of the other freelist. - (nconc (ecase other-type - (:code (gspace-code-free-ranges gspace)) - (:mixed (gspace-non-code-free-ranges gspace))) - (list (cons word-index reserve)))) - ;; Reduced to case 2 now + (return-from dynamic-space-claim-n-words (note-words-used word-index)))) + ;; Avoid switching between :CODE and :MIXED on a page + (unless (or (alignedp (gspace-free-word-index gspace)) + (eq (get-frontier-page-type) page-type)) + (realign-frontier)) (let ((word-index (gspace-claim-n-words gspace n-words))) - (assign-page-types page-type word-index n-words) - (note-it word-index))))) - -;; layoutp is true if we need to force objects on this page to LAYOUT-ALIGN -;; boundaries. This doesn't need to be generalized - everything of type -;; INSTANCE is either on its natural alignment, or the layout alignment. -;; [See doc/internals-notes/compact-instance for why you might want it at all] -;; PAGE-KIND is a heuristic for placement of symbols -;; based on being interned/uninterned/likely-special-variable. -(defun make-page-attributes (layoutp page-kind) - (declare (type (or null (integer 0 3)) page-kind)) - (logior (ash (or page-kind 0) 1) (if layoutp 1 0))) - -(defun gspace-claim-n-bytes (gspace specified-n-bytes page-attributes) - (declare (ignorable page-attributes)) + (assign-page-type page-type word-index n-words) + (note-words-used word-index))))) + +(defun gspace-claim-n-bytes (gspace specified-n-bytes &optional (page-type :mixed)) + (declare (ignorable page-type)) (let* ((n-bytes (round-up specified-n-bytes (ash 1 sb-vm:n-lowtag-bits))) (n-words (ash n-bytes (- sb-vm:word-shift)))) (aver (evenp n-words)) (cond #+immobile-space ((eq gspace *immobile-fixedobj*) - (aver page-attributes) - ;; An immobile fixedobj page can only have one value of object-spacing - ;; and size for all objects on it. Different widetags are ok. - (let* ((key (cons specified-n-bytes page-attributes)) - (found (cdr (assoc key *immobile-space-map* :test 'equal))) - (page-n-words (/ sb-vm:immobile-card-bytes sb-vm:n-word-bytes))) + ;; There can be at most 1 page in progress for each distinct N-WORDS. + ;; Try to find the one which matches. + (let* ((found (cdr (assoc n-words *immobile-space-map*))) + (words-per-page (/ sb-vm:immobile-card-bytes sb-vm:n-word-bytes))) (unless found ; grab one whole GC page from immobile space - (let ((free-word-index - (gspace-claim-n-words gspace page-n-words))) + (let ((free-word-index (gspace-claim-n-words gspace words-per-page))) (setf found (cons 0 free-word-index)) - (push (cons key found) *immobile-space-map*))) + (push (cons n-words found) *immobile-space-map*))) (destructuring-bind (page-word-index . page-base-index) found (let ((next-word (+ page-word-index n-words))) - (if (> next-word (- page-n-words n-words)) - ;; no more objects fit on this page + (if (> next-word (- words-per-page n-words)) + ;; no more objects will fit on this page (setf *immobile-space-map* - (delete key *immobile-space-map* :key 'car :test 'equal)) + (delete n-words *immobile-space-map* :key 'car)) (setf (car found) next-word))) (+ page-word-index page-base-index)))) #+gencgc ((eq gspace *dynamic*) - (dynamic-space-claim-n-words - gspace n-words (if (eq page-attributes :code) :code :mixed))) + (dynamic-space-claim-n-words gspace n-words page-type)) (t (gspace-claim-n-words gspace n-words))))) @@ -470,32 +621,28 @@ (logior bits (ash -1 (1+ sb-vm:n-positive-fixnum-bits))) bits))) -(defun descriptor-word-sized-integer (des) - ;; Extract an (unsigned-byte 32), from either its fixnum or bignum - ;; representation. - (let ((lowtag (descriptor-lowtag des))) - (if (is-fixnum-lowtag lowtag) - (make-random-descriptor (descriptor-fixnum des)) - (read-wordindexed des 1)))) +(defun descriptor-integer (des) + (cond ((is-fixnum-lowtag (descriptor-lowtag des)) + (descriptor-fixnum des)) + ((= (logand (read-bits-wordindexed des 0) sb-vm:widetag-mask) + sb-vm:bignum-widetag) + (bignum-from-core des)))) ;;; common idioms (defun descriptor-mem (des) (gspace-data (descriptor-intuit-gspace des))) -(defun descriptor-byte-offset (des) - (ash (descriptor-word-offset des) sb-vm:word-shift)) ;;; If DESCRIPTOR-GSPACE is already set, just return that. Otherwise, ;;; figure out a GSPACE which corresponds to DES, set it into ;;; (DESCRIPTOR-GSPACE DES), set a consistent value into -;;; (DESCRIPTOR-WORD-OFFSET DES), and return the GSPACE. +;;; (DESCRIPTOR-BYTE-OFFSET DES), and return the GSPACE. (declaim (ftype (function (descriptor) gspace) descriptor-intuit-gspace)) (defun descriptor-intuit-gspace (des) (or (descriptor-gspace des) ;; gspace wasn't set, now we have to search for it. (let* ((lowtag (descriptor-lowtag des)) - (abs-word-addr (ash (- (descriptor-bits des) lowtag) - (- sb-vm:word-shift)))) + (abs-addr (- (descriptor-bits des) lowtag))) ;; Non-pointer objects don't have a gspace. (unless (or (eql lowtag sb-vm:fun-pointer-lowtag) @@ -506,20 +653,23 @@ (dolist (gspace (list *dynamic* *static* *read-only* #+immobile-space *immobile-fixedobj* - #+immobile-space *immobile-varyobj*) + #+immobile-space *immobile-text*) (error "couldn't find a GSPACE for ~S" des)) ;; Bounds-check the descriptor against the allocated area ;; within each gspace. - (when (and (<= (gspace-word-address gspace) - abs-word-addr - (+ (gspace-word-address gspace) - (gspace-free-word-index gspace)))) + (when (or (<= (gspace-byte-address gspace) abs-addr (gspace-upper-bound gspace)) + (and (eq gspace *read-only*) ; KLUDGE + (<= sb-vm:read-only-space-start abs-addr + sb-vm:read-only-space-end))) ;; Update the descriptor with the correct gspace and the ;; offset within the gspace and return the gspace. - (setf (descriptor-word-offset des) - (- abs-word-addr (gspace-word-address gspace))) + (setf (descriptor-byte-offset des) + (- abs-addr (gspace-byte-address gspace))) (return (setf (descriptor-gspace des) gspace))))))) +(defun descriptor-gspace-name (des) + (gspace-name (descriptor-intuit-gspace des))) + (defun %fixnum-descriptor-if-possible (num) (and (typep num `(signed-byte ,sb-vm:n-fixnum-bits)) (make-random-descriptor (ash num sb-vm:n-fixnum-tag-bits)))) @@ -550,22 +700,15 @@ ;;; ;;; Each TOPLEVEL-THING can be a function to be executed or a fixup or ;;; loadtime value, represented by (CONS KEYWORD ..). -(declaim (special *!cold-toplevels* *!cold-defsymbols* - *!cold-defuns* *cold-methods*)) +(declaim (special *!cold-toplevels* *cold-methods*)) ;;;; miscellaneous stuff to read and write the core memory - -;; Like above, but the list is held in the target's image of the host symbol, -;; not the host's value of the symbol. -(defun cold-target-push (cold-thing host-symbol) - (cold-set host-symbol (cold-cons cold-thing (cold-symbol-value host-symbol)))) - (declaim (ftype (function (descriptor sb-vm:word) descriptor) read-wordindexed)) (macrolet ((read-bits () `(bvref-word (descriptor-mem address) - (ash (+ index (descriptor-word-offset address)) - sb-vm:word-shift)))) + (+ (descriptor-byte-offset address) + (ash index sb-vm:word-shift))))) (defun read-bits-wordindexed (address index) (read-bits)) (defun read-wordindexed (address index) @@ -574,12 +717,12 @@ (defstruct (ltv-patch (:copier nil) (:constructor make-ltv-patch (index))) (index 0 :read-only t)) -(declaim (ftype (function (descriptor sb-vm:word (or symbol descriptor ltv-patch))) +(declaim (ftype (function (descriptor sb-vm:word (or symbol package descriptor ltv-patch))) write-wordindexed)) (macrolet ((write-bits (bits) `(setf (bvref-word (descriptor-mem address) - (ash (+ index (descriptor-word-offset address)) - sb-vm:word-shift)) + (+ (descriptor-byte-offset address) + (ash index sb-vm:word-shift))) ,bits))) (defun write-wordindexed (address index value) "Write VALUE displaced INDEX words from ADDRESS." @@ -595,9 +738,11 @@ (bug "Can't patch load-time-value into ~S" address)) sb-vm:unbound-marker-widetag) (t - ;; If we're passed a symbol as a value then it needs to be interned. - (descriptor-bits (cond ((symbolp value) (cold-intern value)) - (t value))))))) + (descriptor-bits + ;; If we're passed a symbol as a value then it needs to be interned. + (cond ((symbolp value) (cold-intern value)) + ((packagep value) (cdr (cold-find-package-info (sb-xc:package-name value)))) + (t value))))))) (defun write-wordindexed/raw (address index bits) (declare (type descriptor address) (type sb-vm:word index) @@ -610,9 +755,9 @@ ;; In immobile space, all objects start life as pseudo-static as if by 'save'. (let* ((gen (or #+immobile-space (let ((gspace (descriptor-intuit-gspace des))) - (assert gspace) + (aver gspace) (when (or (eq gspace *immobile-fixedobj*) - (eq gspace *immobile-varyobj*)) + (eq gspace *immobile-text*)) sb-vm:+pseudo-static-generation+)) 0)) (widetag (logand header-word sb-vm:widetag-mask)) @@ -620,27 +765,20 @@ (gen-shift (if (= widetag sb-vm:fdefn-widetag) 8 24))) (write-wordindexed/raw des 0 (logior (ash gen gen-shift) header-word)))) -(defun write-code-header-words (descriptor boxed unboxed n-named-calls) - (declare (ignorable n-named-calls)) +(defun write-code-header-words (descriptor boxed unboxed n-fdefns) + (declare (ignorable n-fdefns)) (let ((total-words (align-up (+ boxed (ceiling unboxed sb-vm:n-word-bytes)) 2))) (write-header-word descriptor (logior (ash total-words sb-vm:code-header-size-shift) sb-vm:code-header-widetag))) (write-wordindexed/raw - descriptor - 1 - (logior #+64-bit (ash n-named-calls 32) - (* boxed sb-vm:n-word-bytes)))) + descriptor 1 + (logior #+64-bit (ash n-fdefns 32) (* boxed sb-vm:n-word-bytes)))) (defun write-header-data+tag (des header-data widetag) (write-header-word des (logior (ash header-data sb-vm:n-widetag-bits) widetag))) -(defun set-header-data (object data) - (write-header-data+tag object data (ldb (byte sb-vm:n-widetag-bits 0) - (read-bits-wordindexed object 0))) - object) ; return the object itself, like SB-KERNEL:SET-HEADER-DATA - (defun get-header-data (object) (ash (read-bits-wordindexed object 0) (- sb-vm:n-widetag-bits))) @@ -652,132 +790,180 @@ ;;; the length. ;;; * Vector objects: There is a header word with the type, then a word for ;;; the length, then the data. -(defun allocate-object (gspace length lowtag &optional layoutp) +(defun allocate-object (gspace length lowtag) "Allocate LENGTH words in GSPACE and return a new descriptor of type LOWTAG pointing to them." - (allocate-cold-descriptor gspace (ash length sb-vm:word-shift) lowtag - (make-page-attributes layoutp 0))) -(defun allocate-header+object (gspace length widetag) - "Allocate LENGTH words plus a header word in GSPACE and - return an ``other-pointer'' descriptor to them. Initialize the header word - with the resultant length and WIDETAG." - (let ((des (allocate-cold-descriptor - gspace (ash (1+ length) sb-vm:word-shift) - sb-vm:other-pointer-lowtag - (make-page-attributes nil 0)))) + (allocate-cold-descriptor gspace (ash length sb-vm:word-shift) lowtag)) +(defun allocate-otherptr (gspace length widetag) + "Allocate LENGTH words in GSPACE and return an ``other-pointer'' descriptor. + LENGTH must count the header word itself as 1 word. The header word is + initialized with the payload size as (1- LENGTH), and WIDETAG." + (let ((des (allocate-cold-descriptor gspace (ash length sb-vm:word-shift) + sb-vm:other-pointer-lowtag))) ;; FDEFNs don't store a length, freeing up a header byte for other use - (when (= widetag sb-vm:fdefn-widetag) - (setq length 0)) - (write-header-data+tag des length widetag) + (write-header-data+tag des (if (= widetag sb-vm:fdefn-widetag) 0 (1- length)) + widetag) des)) +(defvar *simple-vector-0-descriptor*) (defun allocate-vector (widetag length words &optional (gspace *dynamic*)) ;; Allocate a vector with WORDS payload words (excluding the header+length). ;; WORDS may be an odd number. ;; Store WIDETAG in the header and LENGTH in the length slot. - (let ((des (allocate-cold-descriptor gspace - (sb-vm:pad-data-block - (+ words sb-vm:vector-data-offset)) - sb-vm:other-pointer-lowtag))) - (write-header-data+tag des 0 widetag) - (write-wordindexed des - sb-vm:vector-length-slot - (make-fixnum-descriptor length)) - des)) + (when (and (= widetag sb-vm:simple-vector-widetag) + (= length 0) + *simple-vector-0-descriptor*) + (return-from allocate-vector *simple-vector-0-descriptor*)) + (emplace-vector (allocate-cold-descriptor + gspace + (sb-vm:pad-data-block (+ words sb-vm:vector-data-offset)) + sb-vm:other-pointer-lowtag) + widetag length)) +(defun emplace-vector (des widetag length) + #+ubsan + (write-header-word des (logior (ash length (+ 32 sb-vm:n-fixnum-tag-bits)) + widetag)) + #-ubsan + (progn (write-header-data+tag des 0 widetag) + (write-wordindexed des sb-vm:vector-length-slot (make-fixnum-descriptor length))) + des) +;;; The COLD-LAYOUT is a reflection of or proxy for the words stored +;;; in the core for a cold layout, so that we don't have to extract +;;; them out of the core to compare cold layouts for validity. (defstruct (cold-layout (:constructor %make-cold-layout)) - depthoid length bitmap flags inherits descriptor) - -;;; the hosts's representation of LAYOUT-of-LAYOUT -(defvar *host-layout-of-layout* (find-layout 'layout)) + id name depthoid length bitmap flags inherits descriptor) ;;; a map from name as a host symbol to the descriptor of its target layout (defvar *cold-layouts*) (defun cold-layout-descriptor-bits (name) (descriptor-bits (cold-layout-descriptor (gethash name *cold-layouts*)))) -;;; Instances whose layout needs to be backpatched -(defvar *layout-deferred-instances*) +#+compact-instance-header +(progn + ;; This is called to backpatch layout-of-layout into the primordial layouts. + (defun set-instance-layout (thing layout) + ;; High half of the header points to the layout + (write-wordindexed/raw thing 0 (logior (ash (descriptor-bits layout) 32) + (read-bits-wordindexed thing 0)))) + (defun get-instance-layout (thing) + (make-random-descriptor (ash (read-bits-wordindexed thing 0) -32)))) +#-compact-instance-header +(progn + (defun set-instance-layout (thing layout) + ;; Word following the header is the layout + (write-wordindexed thing sb-vm:instance-slots-offset layout)) + (defun get-instance-layout (thing) + (read-wordindexed thing sb-vm:instance-slots-offset))) ;; Make a structure and set the header word and layout. ;; NWORDS is the payload length (= DD-LENGTH = LAYOUT-LENGTH) -(defun allocate-struct (nwords type &optional (gspace *dynamic*) is-layout) +(defun allocate-struct (nwords layout &optional (gspace *dynamic*)) ;; Add +1 for the header word when allocating. - (let* ((object (allocate-object gspace (1+ nwords) - sb-vm:instance-pointer-lowtag is-layout)) - (layout - (if (symbolp type) - (let ((layout (gethash type *cold-layouts*))) - (cond (layout - (cold-layout-descriptor layout)) - (t - (push object (gethash type *layout-deferred-instances*)) - (make-fixnum-descriptor 0)))) - type))) + (let ((object (allocate-object gspace (1+ nwords) sb-vm:instance-pointer-lowtag))) ;; Length as stored in the header is the exact number of useful words ;; that follow, as is customary. A padding word, if any is not "useful" - (write-header-word - object - (logior #+compact-instance-header (ash (descriptor-bits layout) 32) - (ash nwords sb-vm:instance-length-shift) - sb-vm:instance-widetag)) - #-compact-instance-header - (write-wordindexed object sb-vm:instance-slots-offset layout) + (write-header-word object (logior (ash nwords sb-vm:instance-length-shift) + sb-vm:instance-widetag)) + (set-instance-layout object layout) object)) +(defun type-dd-slots-or-lose (type) + (or (car (get type 'dd-proxy)) (error "NO DD-SLOTS: ~S" type))) +;;; Return the value to supply as the first argument to ALLOCATE-STRUCT +(defun struct-size (thing) + ;; ASSUMPTION: all slots consume 1 storage word + (+ sb-vm:instance-data-start (length (type-dd-slots-or-lose thing)))) (defun allocate-struct-of-type (type) - (allocate-struct (struct-size type) type)) + (allocate-struct (struct-size type) + (cold-layout-descriptor (gethash type *cold-layouts*)))) ;;;; copying simple objects into the cold core -(defun base-string-to-core (string &optional (gspace *dynamic*)) +(defun cold-simple-vector-p (obj) + (and (= (descriptor-lowtag obj) sb-vm:other-pointer-lowtag) + (= (logand (read-bits-wordindexed obj 0) sb-vm:widetag-mask) + sb-vm:simple-vector-widetag))) + +(declaim (inline cold-vector-len)) +(defun cold-vector-len (vector) + #+ubsan (ash (read-bits-wordindexed vector 0) (- -32 sb-vm:n-fixnum-tag-bits)) + #-ubsan (descriptor-fixnum (read-wordindexed vector sb-vm:vector-length-slot))) + +(macrolet ((vector-data (vector-descriptor) + `(+ (descriptor-byte-offset ,vector-descriptor) + (* sb-vm:vector-data-offset sb-vm:n-word-bytes)))) +(defun base-string-to-core (string) "Copy STRING (which must only contain STANDARD-CHARs) into the cold core and return a descriptor to it." ;; (Remember that the system convention for storage of strings leaves an ;; extra null byte at the end to aid in call-out to C.) (let* ((length (length string)) (des (allocate-vector sb-vm:simple-base-string-widetag + ;; add SAETP-N-PAD-ELEMENT length (ceiling (1+ length) sb-vm:n-word-bytes) - gspace)) - (bytes (gspace-data gspace)) - (offset (+ (* sb-vm:vector-data-offset sb-vm:n-word-bytes) - (descriptor-byte-offset des)))) - (dotimes (i length) - (setf (bvref bytes (+ offset i)) - (sb-xc:char-code (aref string i)))) - (setf (bvref bytes (+ offset length)) - 0) ; null string-termination character for C - des)) + *dynamic*)) + (mem (descriptor-mem des)) + (byte-base (vector-data des))) + (dotimes (i length des) ; was prezeroed, so automatically null-terminated + (setf (bvref mem (+ byte-base i)) (char-code (aref string i)))))) (defun base-string-from-core (descriptor) - (let* ((len (descriptor-fixnum - (read-wordindexed descriptor sb-vm:vector-length-slot))) - (str (make-string len)) - (bytes (descriptor-mem descriptor))) + (let* ((mem (descriptor-mem descriptor)) + (byte-base (vector-data descriptor)) + (len (cold-vector-len descriptor)) + (str (make-string len))) (dotimes (i len str) - (setf (aref str i) - (code-char (bvref bytes - (+ (descriptor-byte-offset descriptor) - (* sb-vm:vector-data-offset sb-vm:n-word-bytes) - i))))))) - -(defun bignum-to-core (n) + (setf (aref str i) (code-char (bvref mem (+ byte-base i))))))) + +(defun bit-vector-to-core (bit-vector &optional (gspace *dynamic*)) + (let* ((length (length bit-vector)) + (nwords (ceiling length sb-vm:n-word-bits)) + (des (allocate-vector sb-vm:simple-bit-vector-widetag length nwords gspace)) + (mem (descriptor-mem des)) + (base (vector-data des))) + (let ((byte 0)) + (dotimes (i length) + (let ((byte-bit (rem i 8))) + (setf (ldb (byte 1 byte-bit) byte) (bit bit-vector i)) + (when (= byte-bit 7) + (setf (bvref mem (+ base (floor i 8))) byte)))) + (when (/= 0 (rem length 8)) + (setf (bvref mem (+ base (floor length 8))) byte)) + des)))) + +;;; I would think that all strings we dump are readonly. Maybe not? +(defun string-literal-to-core (s) (set-readonly (base-string-to-core s))) + +;;; Write the bits of INT to core as if a bignum, i.e. words are ordered from +;;; least to most significant regardless of machine endianness. +(defun integer-bits-to-core (int descriptor start nwords) + (declare (fixnum nwords)) + (do ((index 0 (1+ index)) + (remainder int (ash remainder (- sb-vm:n-word-bits)))) + ((>= index nwords) + (unless (zerop (integer-length remainder)) + (error "Nonzero remainder after writing ~D using ~D words" int nwords))) + (write-wordindexed/raw descriptor + (+ start index) + (logand remainder sb-ext:most-positive-word)))) + +(defun bignum-to-core (n &optional (space *dynamic*)) "Copy a bignum to the cold core." (let* ((words (ceiling (1+ (integer-length n)) sb-vm:n-word-bits)) (handle - (allocate-header+object *dynamic* words sb-vm:bignum-widetag))) - (declare (fixnum words)) - (do ((index 1 (1+ index)) - (remainder n (ash remainder (- sb-vm:n-word-bits)))) - ((> index words) - (unless (zerop (integer-length remainder)) - ;; FIXME: Shouldn't this be a fatal error? - (warn "~W words of ~W were written, but ~W bits were left over." - words n remainder))) - (write-wordindexed/raw handle index - (ldb (byte sb-vm:n-word-bits 0) remainder))) + #-bignum-assertions (allocate-otherptr space (1+ words) sb-vm:bignum-widetag) + #+bignum-assertions + (let* ((aligned-words (1+ (logior words 1))) ; round to odd, slap on a header + (physical-words (* aligned-words 2)) + (handle (allocate-otherptr space physical-words sb-vm:bignum-widetag))) + ;; rewrite the header to indicate the logical size + (write-wordindexed/raw handle 0 (logior (ash words 8) sb-vm:bignum-widetag)) + handle))) + (integer-bits-to-core n handle sb-vm:bignum-digits-offset words) + (aver (= (bignum-from-core handle) n)) handle)) (defun bignum-from-core (descriptor) - (let ((n-words (get-header-data descriptor)) + (let ((n-words (logand (get-header-data descriptor) #x7fffff)) (val 0)) (dotimes (i n-words val) (let ((bits (read-bits-wordindexed descriptor @@ -789,7 +975,7 @@ core and return a descriptor to it." (defun number-pair-to-core (first second type) "Makes a number pair of TYPE (ratio or complex) and fills it in." - (let ((des (allocate-header+object *dynamic* 2 type))) + (let ((des (allocate-otherptr *dynamic* 3 type))) (write-wordindexed des 1 first) (write-wordindexed des 2 second) des)) @@ -815,15 +1001,13 @@ core and return a descriptor to it." #+64-bit ; 64-bit platforms have immediate single-floats (make-random-descriptor (logior (ash bits 32) sb-vm:single-float-widetag)) #-64-bit - (let ((des (allocate-header+object *dynamic* - (1- sb-vm:single-float-size) - sb-vm:single-float-widetag))) + (let ((des (allocate-otherptr *dynamic* sb-vm:single-float-size + sb-vm:single-float-widetag))) (write-wordindexed/raw des sb-vm:single-float-value-slot bits) des))) (double-float - (let ((des (allocate-header+object *dynamic* - (1- sb-vm:double-float-size) - sb-vm:double-float-widetag))) + (let ((des (allocate-otherptr *dynamic* sb-vm:double-float-size + sb-vm:double-float-widetag))) (write-double-float-bits des sb-vm:double-float-value-slot x))))) (defun unsigned-bits-to-single-float (bits) @@ -844,20 +1028,18 @@ core and return a descriptor to it." (number-pair-to-core (number-to-core r) (number-to-core i) sb-vm:complex-widetag) (ecase (sb-impl::flonum-format r) (single-float - (let* ((des (allocate-header+object *dynamic* - (1- sb-vm:complex-single-float-size) - sb-vm:complex-single-float-widetag)) - (where (ash (+ #+64-bit sb-vm:complex-single-float-data-slot + (let* ((des (allocate-otherptr *dynamic* sb-vm:complex-single-float-size + sb-vm:complex-single-float-widetag)) + (where (+ (descriptor-byte-offset des) + (ash #+64-bit sb-vm:complex-single-float-data-slot #-64-bit sb-vm:complex-single-float-real-slot - (descriptor-word-offset des)) - sb-vm:word-shift))) - (setf (bvref-32 (descriptor-mem des) where) (single-float-bits r) - (bvref-32 (descriptor-mem des) (+ where 4)) (single-float-bits i)) + sb-vm:word-shift)))) + (setf (bvref-s32 (descriptor-mem des) where) (single-float-bits r) + (bvref-s32 (descriptor-mem des) (+ where 4)) (single-float-bits i)) des)) (double-float - (let ((des (allocate-header+object *dynamic* - (1- sb-vm:complex-double-float-size) - sb-vm:complex-double-float-widetag))) + (let ((des (allocate-otherptr *dynamic* sb-vm:complex-double-float-size + sb-vm:complex-double-float-widetag))) (write-double-float-bits des sb-vm:complex-double-float-real-slot r) (write-double-float-bits des sb-vm:complex-double-float-imag-slot i) des))))) @@ -876,14 +1058,15 @@ core and return a descriptor to it." ;;; Allocate a cons cell in GSPACE and fill it in with CAR and CDR. (defun cold-cons (car cdr &optional (gspace *dynamic*)) - (let ((dest (allocate-object gspace 2 sb-vm:list-pointer-lowtag))) + (let ((cons (allocate-cold-descriptor gspace (ash 2 sb-vm:word-shift) + sb-vm:list-pointer-lowtag :list))) (let* ((objs (gspace-objects gspace)) (n (1- (length objs)))) (when objs (setf (aref objs n) (list (aref objs n))))) - (write-wordindexed dest sb-vm:cons-car-slot car) - (write-wordindexed dest sb-vm:cons-cdr-slot cdr) - dest)) + (write-wordindexed cons sb-vm:cons-car-slot car) + (write-wordindexed cons sb-vm:cons-cdr-slot cdr) + cons)) (defun list-to-core (list) (let ((head *nil-descriptor*) (tail nil)) @@ -913,18 +1096,22 @@ core and return a descriptor to it." (write-wordindexed result (+ index sb-vm:vector-data-offset) (pop objects))))) +(defun word-vector (objects &optional (gspace *dynamic*)) + (let* ((size (length objects)) + (result (allocate-vector #+64-bit sb-vm:simple-array-unsigned-byte-64-widetag + #-64-bit sb-vm:simple-array-unsigned-byte-32-widetag + size size gspace))) + (dotimes (index size result) + (write-wordindexed/raw result (+ index sb-vm:vector-data-offset) (pop objects))))) + (defun cold-svset (vector index value) (let ((i (if (integerp index) index (descriptor-fixnum index)))) (write-wordindexed vector (+ i sb-vm:vector-data-offset) value))) -(setf (get 'vector :sb-cold-funcall-handler/for-value) - (lambda (&rest args) (vector-in-core args))) - -(declaim (inline cold-vector-len cold-svref)) -(defun cold-vector-len (vector) - (descriptor-fixnum (read-wordindexed vector sb-vm:vector-length-slot))) +(declaim (inline cold-svref)) (defun cold-svref (vector i) (declare (type index i)) + (aver (< i (cold-vector-len vector))) (read-wordindexed vector (+ i sb-vm:vector-data-offset))) (defun vector-from-core (descriptor &optional (transform #'identity)) (let* ((len (cold-vector-len descriptor)) @@ -934,6 +1121,7 @@ core and return a descriptor to it." ;;;; symbol magic +(defvar *tls-index-to-symbol*) #+sb-thread (progn ;; Simulate *FREE-TLS-INDEX*. This is a word count, not a displacement. @@ -942,6 +1130,7 @@ core and return a descriptor to it." ;; This is a backend support routine, but the style within this file ;; is to conditionalize by the target features. (defun cold-assign-tls-index (symbol index) + (push (list index (warm-symbol symbol)) *tls-index-to-symbol*) #+64-bit (write-wordindexed/raw symbol 0 (logior (ash index 32) (read-bits-wordindexed symbol 0))) @@ -952,11 +1141,8 @@ core and return a descriptor to it." ;; choosing a new index if it doesn't have one yet. (defun ensure-symbol-tls-index (symbol) (let* ((cold-sym (cold-intern symbol)) - (tls-index - #+64-bit - (ldb (byte 32 32) (read-bits-wordindexed cold-sym 0)) - #-64-bit - (read-bits-wordindexed cold-sym sb-vm:symbol-tls-index-slot))) + (tls-index #+64-bit (ldb (byte 32 32) (read-bits-wordindexed cold-sym 0)) + #-64-bit (read-bits-wordindexed cold-sym sb-vm:symbol-tls-index-slot))) (unless (plusp tls-index) (let ((next (prog1 *genesis-tls-counter* (incf *genesis-tls-counter*)))) (setq tls-index (ash next sb-vm:word-shift)) @@ -964,17 +1150,33 @@ core and return a descriptor to it." tls-index))) (defvar *cold-symbol-gspace* (or #+immobile-space '*immobile-fixedobj* '*dynamic*)) +(defun encode-symbol-name (package-id name) + (logior (ash package-id sb-impl::symbol-name-bits) (descriptor-bits name))) ;;; Allocate (and initialize) a symbol. -(defun allocate-symbol (size name &key (gspace (symbol-value *cold-symbol-gspace*))) +;;; Even though all symbols are the same size now, I still envision the possibility +;;; of reducing gensyms to 4 words, though I'm not sure what to do if information +;;; is later attached (function, value, plist) +(defun allocate-symbol (size cold-package name &key (gspace (symbol-value *cold-symbol-gspace*))) (declare (simple-string name)) - (let ((symbol (allocate-header+object gspace (1- size) sb-vm:symbol-widetag))) - (write-wordindexed symbol sb-vm:symbol-value-slot *unbound-marker*) - (write-wordindexed symbol sb-vm:symbol-hash-slot (make-fixnum-descriptor 0)) - (write-wordindexed symbol sb-vm:symbol-info-slot *nil-descriptor*) - (write-wordindexed symbol sb-vm:symbol-name-slot - (set-readonly (base-string-to-core name *dynamic*))) - (write-wordindexed symbol sb-vm:symbol-package-slot *nil-descriptor*) + (let ((symbol (allocate-otherptr gspace size sb-vm:symbol-widetag))) + (when core-file-name + (let* ((cold-name (string-literal-to-core name)) + (pkg-id (if cold-package + (descriptor-fixnum (read-slot cold-package :id)) + sb-impl::+package-id-none+)) + (hash (make-fixnum-descriptor + (if core-file-name (sb-c::symbol-name-hash name) 0)))) + (write-wordindexed symbol sb-vm:symbol-value-slot *unbound-marker*) + (write-wordindexed symbol sb-vm:symbol-hash-slot hash) + (write-wordindexed symbol sb-vm:symbol-info-slot *nil-descriptor*) + #+compact-symbol + (write-wordindexed/raw symbol sb-vm:symbol-name-slot + (encode-symbol-name pkg-id cold-name)) + #-compact-symbol + (progn (write-wordindexed symbol sb-vm:symbol-package-id-slot + (make-fixnum-descriptor pkg-id)) + (write-wordindexed symbol sb-vm:symbol-name-slot cold-name)))) symbol)) ;;; Set the cold symbol value of SYMBOL-OR-SYMBOL-DES, which can be either a @@ -989,54 +1191,27 @@ core and return a descriptor to it." (defun cold-symbol-value (symbol) (let ((val (read-wordindexed (cold-intern symbol) sb-vm:symbol-value-slot))) (if (= (descriptor-bits val) sb-vm:unbound-marker-widetag) - (unbound-cold-symbol-handler symbol) + (error "Symbol value of ~a is unbound." symbol) val))) (defun cold-fdefn-fun (cold-fdefn) (read-wordindexed cold-fdefn sb-vm:fdefn-fun-slot)) -(defun unbound-cold-symbol-handler (symbol) - (awhen (and (eq (sb-xc:symbol-package symbol) *cl-package*) - (find-symbol (string symbol) "SB-XC")) - (setq symbol it)) - (let ((host-val (and (boundp symbol) (symbol-value symbol)))) - (etypecase host-val - (number - ;; This case is intended to handle - ;; (DEFCONSTANT SB-XC:LEAST-POSITIVE-NORMALIZED-SHORT-FLOAT - ;; SB-XC:LEAST-POSITIVE-NORMALIZED-SINGLE-FLOAT) ; etc - ;; Several uses of MOST-POSITIVE-FIXNUM come through here as well - ;; due to (DEFCONSTANT SB-XC:mumble-LIMIT sb-xc:most-positive-fixnum). - ;; That seems weird but doesn't seem to be a problem. - ;; (i.e. why don't we just dump the fixnum?) - (number-to-core host-val)) - (named-type - (let ((target-val (ctype-to-core (named-type-name host-val) host-val))) - ;; Though it looks complicated to assign cold symbols on demand, - ;; it avoids writing code to build the layout of NAMED-TYPE in the - ;; way we build other primordial stuff such as layout-of-layout. - (cold-set symbol target-val) - target-val))))) ;;;; layouts and type system pre-initialization ;;; Since we want to be able to dump structure constants and ;;; predicates with reference layouts, we need to create layouts at ;;; cold-load time. We use the name to intern layouts by, and dump a -;;; list of all cold layouts in *!INITIAL-LAYOUTS* so that type system +;;; list of all cold layouts in *!INITIAL-WRAPPERS* so that type system ;;; initialization can find them. The only thing that's tricky [sic -- ;;; WHN 19990816] is initializing layout's layout, which must point to ;;; itself. -;;; a map from DESCRIPTOR-BITS of cold layouts to the name, for inverting -;;; mapping -(defvar *cold-layout-names*) - -;;; the descriptor for layout's layout (needed when making layouts) -(defvar *layout-layout*) - -(defvar *known-structure-classoids*) +;;; a map from DESCRIPTOR-BITS of cold layouts (as descriptors) +;;; to the host's COLD-LAYOUT proxy for that layout. +(defvar *cold-layout-by-addr*) -;;; Trivial methods [sic] require that we sort possible methods by the depthoid. +;;; Initial methods require that we sort possible methods by the depthoid. ;;; Most of the objects printed in cold-init are ordered hierarchically in our ;;; type lattice; the major exceptions are ARRAY and VECTOR at depthoid -1. ;;; Of course we need to print VECTORs because a STRING is a vector, @@ -1055,43 +1230,39 @@ core and return a descriptor to it." (acond ((gethash class-name *cold-layouts*) (cold-layout-depthoid it)) ((info :type :compiler-layout class-name) - (layout-depthoid it)) + (wrapper-depthoid it)) (t (error "Unknown depthoid for ~S" class-name)))))) -(defun type-dd-slots-or-lose (type) - (or (car (get type 'dd-proxy)) (error "NO DD-SLOTS: ~S" type))) -;;; Return the value to supply as the first argument to ALLOCATE-STRUCT -(defun struct-size (thing) - ;; ASSUMPTION: all slots consume 1 storage word - (+ sb-vm:instance-data-start (length (type-dd-slots-or-lose thing)))) - -(declaim (ftype function read-slot write-slots)) -(flet ((get-slots (host-layout-or-type) - (etypecase host-layout-or-type - (layout (dd-slots (layout-info host-layout-or-type))) - (symbol (type-dd-slots-or-lose host-layout-or-type)))) +(declaim (ftype function read-slot %write-slots write-slots)) +(flet ((infer-metadata (x) + (type-dd-slots-or-lose + (cold-layout-name (gethash (descriptor-bits (get-instance-layout x)) + *cold-layout-by-addr*)))) (find-slot (slots initarg) - (let ((dsd (find initarg slots - :test (lambda (x y) (eq x (keywordicate (dsd-name y))))))) + (let ((dsd (or (find initarg slots + :test (lambda (x y) (eq x (keywordicate (dsd-name y))))) + (error "No slot for ~S in ~S" initarg slots)))) (values (+ sb-vm:instance-slots-offset (dsd-index dsd)) (dsd-raw-type dsd))))) - (defun write-slots (cold-object host-layout-or-type &rest assignments) + (defun %write-slots (metadata cold-object &rest assignments) (aver (evenp (length assignments))) - (let ((slots (get-slots host-layout-or-type))) - (loop for (initarg value) on assignments by #'cddr - do (multiple-value-bind (index repr) (find-slot slots initarg) - (ecase repr - ((t) (write-wordindexed cold-object index value)) - ((word sb-vm:signed-word) - (write-wordindexed/raw cold-object index value)))))) + (loop for (initarg value) on assignments by #'cddr + do (multiple-value-bind (index repr) (find-slot metadata initarg) + (ecase repr + ((t) (write-wordindexed cold-object index value)) + ((word sb-vm:signed-word) + (write-wordindexed/raw cold-object index value))))) cold-object) + (defun write-slots (cold-object &rest assignments) + (apply #'%write-slots (infer-metadata cold-object) cold-object assignments)) + ;; For symmetry, the reader takes an initarg, not a slot name. - (defun read-slot (cold-object host-layout-or-type slot-initarg) + (defun read-slot (cold-object slot-initarg) (multiple-value-bind (index repr) - (find-slot (get-slots host-layout-or-type) slot-initarg) + (find-slot (infer-metadata cold-object) slot-initarg) (ecase repr ((t) (read-wordindexed cold-object index)) (word (read-bits-wordindexed cold-object index)) @@ -1118,79 +1289,110 @@ core and return a descriptor to it." :depthoid (cadr flags+depthoid+inherits) :inherits (cddr flags+depthoid+inherits)))))))) -(defvar *simple-vector-0-descriptor*) (defvar *vacuous-slot-table*) -(defvar *cold-layout-gspace* (or #+immobile-space '*immobile-fixedobj* '*dynamic*)) -(declaim (ftype (function (symbol layout-depthoid integer index descriptor descriptor) +(defvar *cold-layout-gspace* (or #+metaspace '*read-only* + #+immobile-space '*immobile-fixedobj* + '*dynamic*)) +(declaim (ftype (function (symbol layout-depthoid integer index integer descriptor) descriptor) make-cold-layout)) + +(defun cold-wrapper-id (wrapper-descriptor) + (let* ((layout-descriptor (->layout wrapper-descriptor)) + (proxy (gethash (descriptor-bits layout-descriptor) *cold-layout-by-addr*))) + (cold-layout-id proxy))) + (defun make-cold-layout (name depthoid flags length bitmap inherits) - ;; Can't call STRUCT-SIZE in first genesis - no metadata yet - (let ((result (allocate-struct (dd-length (find-defstruct-description 'layout)) - *layout-layout* - (symbol-value *cold-layout-gspace*) t))) - #+64-bit - (write-slots result *host-layout-of-layout* - :flags (sb-kernel::pack-layout-flags depthoid length flags)) - #-64-bit - (write-slots result *host-layout-of-layout* - :depthoid (make-fixnum-descriptor depthoid) - :length (make-fixnum-descriptor length) - :flags flags) - - ;; Set other slot values. - ;; leave CLASSOID uninitialized for now - (write-slots result *host-layout-of-layout* - :clos-hash (make-fixnum-descriptor (sb-impl::hash-layout-name name)) - :invalid *nil-descriptor* - :inherits inherits - :info *nil-descriptor* - :bitmap bitmap - ;; Nothing in cold-init needs to call EQUALP on a structure with raw slots, - ;; but for type-correctness this slot needs to be a simple-vector. - :equalp-tests *simple-vector-0-descriptor* - :slot-list *nil-descriptor*) - - (awhen (gethash name *layout-deferred-instances*) - (dolist (instance it (remhash name *layout-deferred-instances*)) - (set-instance-layout instance result))) - - (when (member name '(null list symbol)) - ;; Assign an empty slot-table. Why this is done only for three - ;; classoids is ... too complicated to explain here in a few words, - ;; but revision 18c239205d9349abc017b07e7894a710835c5205 broke it. - ;; Keep this in sync with MAKE-SLOT-TABLE in pcl/slots-boot. - (write-slots result *host-layout-of-layout* - :slot-table (if (boundp '*vacuous-slot-table*) - *vacuous-slot-table* - (setq *vacuous-slot-table* - (host-constant-to-core '#(1 nil)))))) - - (when (and (logtest flags +structure-layout-flag+) (> depthoid 2)) - (loop with dsd-index = (get-dsd-index sb-kernel:layout sb-kernel::ancestor_2) - for i from 2 to (min (1- depthoid) sb-c::layout-inherits-max-optimized-depth) - do (write-wordindexed result - (+ sb-vm:instance-slots-offset dsd-index) - (cold-svref inherits i)) - (incf dsd-index))) - - (setf (gethash (descriptor-bits result) *cold-layout-names*) name - (gethash name *cold-layouts*) (%make-cold-layout :depthoid depthoid - :length length - :bitmap bitmap - :flags flags - :inherits inherits - :descriptor result)) + ;; Layouts created in genesis can't vary in length due to the number of ancestor + ;; types in the IS-A vector. They may vary in length due to the bitmap word count. + ;; But we can at least assert that there is one less thing to worry about. + (aver (<= depthoid sb-kernel::layout-id-vector-fixed-capacity)) + (aver (cold-simple-vector-p inherits)) + (let* ((fixed-words (sb-kernel::type-dd-length sb-vm:layout)) + (bitmap-words (ceiling (1+ (integer-length bitmap)) sb-vm:n-word-bits)) + (result (allocate-struct (+ fixed-words bitmap-words) + (or (awhen (gethash #+metaspace 'sb-vm:layout + #-metaspace 'wrapper *cold-layouts*) + (cold-layout-descriptor it)) + (make-fixnum-descriptor 0)) + (symbol-value *cold-layout-gspace*))) + (wrapper + #-metaspace result ; WRAPPER and LAYOUT are synonymous in this case + #+metaspace (allocate-struct (sb-kernel::type-dd-length wrapper) + (or (awhen (gethash 'wrapper *cold-layouts*) + (cold-layout-descriptor it)) + (make-fixnum-descriptor 0)))) + (this-id (sb-kernel::choose-layout-id name (logtest flags +condition-layout-flag+))) + (hash (make-fixnum-descriptor (sb-impl::hash-layout-name name)))) + + (let ((proxy (%make-cold-layout :id this-id + :name name + :depthoid depthoid + :length length + :bitmap bitmap + :flags flags + :inherits inherits + :descriptor result))) + ;; Make two different ways to look up the proxy object - + ;; by name or by descriptor-bits. + (setf (gethash (descriptor-bits result) *cold-layout-by-addr*) proxy + (gethash name *cold-layouts*) proxy)) + (unless core-file-name (return-from make-cold-layout result)) + + ;; Can't use the easier WRITE-SLOTS unfortunately because bootstrapping is hard + (let* ((wrapper-metadata (type-dd-slots-or-lose 'wrapper)) + (layout-metadata #-metaspace wrapper-metadata + #+metaspace (type-dd-slots-or-lose 'sb-vm:layout))) + + #+64-bit + (%write-slots layout-metadata result + :flags (sb-kernel::pack-layout-flags depthoid length flags)) + #-64-bit + (%write-slots layout-metadata result + :depthoid (make-fixnum-descriptor depthoid) + :length (make-fixnum-descriptor length) + :flags flags) + + (%write-slots wrapper-metadata wrapper + :clos-hash hash + :invalid *nil-descriptor* + :inherits inherits + :%info *nil-descriptor*) + + (when (member name '(null list symbol pathname)) + ;; Assign an empty slot-table. Why this is done only for four + ;; classoids is ... too complicated to explain here in a few words, + ;; but revision 18c239205d9349abc017b07e7894a710835c5205 broke it. + ;; Keep this in sync with MAKE-SLOT-TABLE in pcl/slots-boot. + (%write-slots wrapper-metadata wrapper + :slot-table (if (boundp '*vacuous-slot-table*) + *vacuous-slot-table* + (setq *vacuous-slot-table* + (host-constant-to-core '#(1 nil)))))) + + ;; If wrappers are used, the wrapper has a copy of the hash, + ;; and also the two friends point to each other. + #+metaspace + (progn (%write-slots layout-metadata result :clos-hash hash :friend wrapper) + (%write-slots wrapper-metadata wrapper :friend result)) + + (let ((byte-offset (+ (descriptor-byte-offset result) (sb-vm::id-bits-offset)))) + (when (logtest flags +structure-layout-flag+) + (loop for i from 2 below (cold-vector-len inherits) + do (setf (bvref-s32 (descriptor-mem result) byte-offset) + (cold-wrapper-id (cold-svref inherits i))) + (incf byte-offset 4))) + (setf (bvref-s32 (descriptor-mem result) byte-offset) this-id))) + + (integer-bits-to-core bitmap result (1+ fixed-words) bitmap-words) + result)) (defun predicate-for-specializer (type-name) (let ((classoid (find-classoid type-name nil))) (typecase classoid (structure-classoid - (cond ((dd-predicate-name (layout-info (classoid-layout classoid)))) - ;; All early INSTANCEs should be STRUCTURE-OBJECTs. - ;; Except: see hack for CONDITIONs in CLASS-DEPTHOID. - ((eq type-name 'structure-object) '%instancep))) + (dd-predicate-name (sb-kernel::wrapper-%info (classoid-wrapper classoid)))) (built-in-classoid (let ((translation (specifier-type type-name))) (aver (not (contains-unknown-type-p translation))) @@ -1198,13 +1400,9 @@ core and return a descriptor to it." :test #'type= :key #'car))) (cond (predicate (cdr predicate)) ((eq type-name 'stream) 'streamp) + ((eq type-name 'pathname) 'pathnamep) ((eq type-name 't) 'constantly-t) - (t (error "No predicate for builtin: ~S" type-name)))))) - (null - #+nil (format t "~&; PREDICATE-FOR-SPECIALIZER: no classoid for ~S~%" - type-name) - (case type-name - (condition 'sb-kernel::!condition-p)))))) + (t (error "No predicate for builtin: ~S" type-name))))))))) ;;; Convert SPECIFIER (equivalently OBJ) to its representation as a ctype ;;; in the cold core. @@ -1214,8 +1412,8 @@ core and return a descriptor to it." (declare (type ctype obj)) (if (classoid-p obj) (let* ((cell (cold-find-classoid-cell (classoid-name obj) :create t)) - (cold-classoid - (read-slot cell (find-layout 'sb-kernel::classoid-cell) :classoid))) + (cold-classoid (read-slot cell :classoid))) + (aver (not (sb-kernel::undefined-classoid-p obj))) (unless (cold-null cold-classoid) (return-from ctype-to-core cold-classoid))) ;; CTYPEs can't be TYPE=-hashed, but specifiers can be EQUAL-hashed. @@ -1233,8 +1431,7 @@ core and return a descriptor to it." (if (classoid-p obj) ;; Place this classoid into its clasoid-cell. (let ((cell (cold-find-classoid-cell (classoid-name obj) :create t))) - (write-slots cell (find-layout 'sb-kernel::classoid-cell) - :classoid result)) + (write-slots cell :classoid result)) ;; Otherwise put it in the general cache (setf (gethash specifier *ctype-cache*) result)) result)) @@ -1248,12 +1445,21 @@ core and return a descriptor to it." ;; trivially dumpable constant in lieu of whatever complicated ;; substructure it currently holds. (typecase obj - (classoid - `((,(get-dsd-index built-in-classoid sb-kernel::subclasses) . nil) - ;; Even though (gethash (classoid-name obj) *cold-layouts*) may exist, - ;; we nonetheless must set LAYOUT to NIL or else warm build fails - ;; in the twisty maze of class initializations. - (,(get-dsd-index built-in-classoid layout) . nil))))) + (classoid + (let ((slots-to-omit + `(;; :predicate will be patched in during cold init. + (,(get-dsd-index built-in-classoid sb-kernel::predicate) . + ,(make-random-descriptor sb-vm:unbound-marker-widetag)) + (,(get-dsd-index classoid sb-kernel::subclasses) . nil) + ;; Even though (gethash (classoid-name obj) *cold-layouts*) may exist, + ;; we nonetheless must set LAYOUT to NIL or else warm build fails + ;; in the twisty maze of class initializations. + (,(get-dsd-index classoid wrapper) . nil)))) + (if (typep obj 'built-in-classoid) + slots-to-omit + ;; :predicate is not a slot. Don't mess up the object + ;; by omitting a slot at the same index as it. + (cdr slots-to-omit)))))) (dd-slots (type-dd-slots-or-lose host-type)) ;; ASSUMPTION: all slots consume 1 storage word (dd-len (+ sb-vm:instance-data-start (length dd-slots))) @@ -1262,57 +1468,59 @@ core and return a descriptor to it." (do ((index sb-vm:instance-data-start (1+ index))) ((= index dd-len) result) (let* ((dsd (find index dd-slots :key #'dsd-index)) - (host-val (funcall (dsd-accessor-name dsd) obj)) - (override (assq index simple-slots))) + (override (assq index simple-slots)) + (reader (dsd-accessor-name dsd))) (ecase (dsd-raw-type dsd) ((t) (write-wordindexed result (+ sb-vm:instance-slots-offset index) (if override (or (cdr override) *nil-descriptor*) - (host-constant-to-core host-val obj-to-core-helper)))) + (host-constant-to-core (funcall reader obj) + obj-to-core-helper)))) ((word sb-vm:signed-word) (write-wordindexed/raw result (+ sb-vm:instance-slots-offset index) - (or (cdr override) host-val)))))))) + (or (cdr override) (funcall reader obj))))))))) -;; This is called to backpatch two small sets of objects: -;; - layouts created before layout-of-layout is made (3 counting LAYOUT itself) -;; - a small number of classoid-cells (~ 4). -(defun set-instance-layout (thing layout) - #+compact-instance-header - ;; High half of the header points to the layout - (write-wordindexed/raw thing 0 (logior (ash (descriptor-bits layout) 32) - (read-bits-wordindexed thing 0))) - #-compact-instance-header - ;; Word following the header is the layout - (write-wordindexed thing sb-vm:instance-slots-offset layout)) +;;; Convert a layout to a wrapper and back. +;;; Each points to the other through its first data word. +(defun ->wrapper (x) #+metaspace (read-wordindexed x 1) #-metaspace x) +(defun ->layout (x) #+metaspace (read-wordindexed x 1) #-metaspace x) (defun initialize-layouts () - (setq *layout-layout* (make-fixnum-descriptor 0)) (flet ((chill-layout (name &rest inherits) ;; Check that the number of specified INHERITS matches ;; the length of the layout's inherits in the cross-compiler. - (let ((warm-layout (info :type :compiler-layout name))) - (assert (eql (length (layout-inherits warm-layout)) - (length inherits))) - (make-cold-layout name - (layout-depthoid warm-layout) - (layout-flags warm-layout) - (layout-length warm-layout) - (number-to-core (layout-bitmap warm-layout)) - (vector-in-core inherits))))) + (let ((wrapper (info :type :compiler-layout name))) + (aver (eql (length (wrapper-inherits wrapper)) (length inherits))) + (->wrapper + (make-cold-layout name + (wrapper-depthoid wrapper) + (wrapper-flags wrapper) + (wrapper-length wrapper) + (wrapper-bitmap wrapper) + (vector-in-core inherits)))))) + ;; The variables are named foo-LAYOUT but are actually foo-WRAPPER. (let* ((t-layout (chill-layout 't)) - (s-o-layout (chill-layout 'structure-object t-layout))) - (setf *layout-layout* (chill-layout 'layout t-layout s-o-layout)) - (dolist (layout (list t-layout s-o-layout *layout-layout*)) - (set-instance-layout layout *layout-layout*)) + (s-o-layout (chill-layout 'structure-object t-layout)) + #+metaspace (layout-layout (chill-layout 'sb-vm:layout t-layout s-o-layout)) + (wrapper-layout (chill-layout 'wrapper t-layout s-o-layout))) + (when core-file-name + #-metaspace + (dolist (instance (list t-layout s-o-layout wrapper-layout)) + (set-instance-layout instance wrapper-layout)) + #+metaspace + (progn (dolist (instance (list t-layout s-o-layout layout-layout wrapper-layout)) + (set-instance-layout instance (->layout wrapper-layout)) + (set-instance-layout (->layout instance) (->layout layout-layout))))) (chill-layout 'function t-layout) (chill-layout 'sb-kernel::classoid-cell t-layout s-o-layout) (chill-layout 'package t-layout s-o-layout) (let* ((sequence (chill-layout 'sequence t-layout)) (list (chill-layout 'list t-layout sequence)) (symbol (chill-layout 'symbol t-layout))) - (chill-layout 'null t-layout sequence list symbol))))) + (chill-layout 'null t-layout sequence list symbol)) + (chill-layout 'stream t-layout)))) ;;;; interning symbols in the cold image @@ -1321,113 +1529,110 @@ core and return a descriptor to it." (defvar *cold-package-symbols*) (declaim (type hash-table *cold-package-symbols*)) -(setf (get 'find-package :sb-cold-funcall-handler/for-value) - (lambda (descriptor &aux (name (base-string-from-core descriptor))) - (or (cdr (gethash name *cold-package-symbols*)) - (error "Genesis could not find a target package named ~S" name)))) +;;; preincrement on use. the first non-preassigned ID is 5 +(defvar *package-id-count* 4) + +;;; Initialize the cold package named by NAME. The information is +;;; usually derived from the host package of the same name, except +;;; where the host package does not reflect the target package +;;; information, as for COMMON-LISP, KEYWORD, and COMMON-LISP-USER. +(defun initialize-cold-package (cold-package name) + (multiple-value-bind (nicknames docstring id shadow use-list) + (cond ((string= name "COMMON-LISP") + (values '("CL") + "public: home of symbols defined by the ANSI language specification" + sb-impl::+package-id-lisp+ + '() + '())) + ((string= name "KEYWORD") + (values '() + "public: home of keywords" + sb-impl::+package-id-keyword+ + '() + '())) + ((string= name "COMMON-LISP-USER") + (values '("CL-USER") + "public: the default package for user code and data" + sb-impl::+package-id-user+ + '() + ;; ANSI encourages us to put extension packages in + ;; the USE list of COMMON-LISP-USER. + '("COMMON-LISP" "SB-ALIEN" "SB-DEBUG" + "SB-EXT" "SB-GRAY" "SB-PROFILE"))) + (t + (let ((package (find-package name))) + (values (package-nicknames package) + (documentation package t) + (if (string= name "SB-KERNEL") + sb-impl::+package-id-kernel+ + (incf *package-id-count*)) + (sort (package-shadowing-symbols package) #'string<) + ;; SB-COREFILE is not actually part of + ;; the use list for SB-FASL. It's + ;; just needed for Genesis. + (if (string= name "SB-FASL") + (remove (find-package "SB-COREFILE") + (package-use-list package)) + (package-use-list package)))))) + (write-slots cold-package + :id (make-fixnum-descriptor id) + :%name (string-literal-to-core name) + :%nicknames (list-to-core + (mapcar #'string-literal-to-core nicknames)) + :%bits (make-fixnum-descriptor + (if (system-package-p name) + sb-impl::+initial-package-bits+ + 0)) + :doc-string (if (and docstring #-sb-doc nil) + (string-literal-to-core docstring) + *nil-descriptor*) + :%use-list (list-to-core + (mapcar (lambda (use) + (cdr (cold-find-package-info + (sb-xc:package-name use)))) + use-list))) + (dolist (use use-list) + ;; Push onto the "used-by" list. + (let ((cold (cdr (cold-find-package-info (sb-xc:package-name use))))) + (write-slots cold + :%used-by-list (cold-cons cold-package + (read-slot cold :%used-by-list))))) + ;; COLD-INTERN AVERs that the package has an ID, so delay writing + ;; the shadowing-symbols until the package is ready. + (write-slots cold-package + :%shadowing-symbols (list-to-core + (mapcar 'cold-intern shadow))))) + +(defun cold-find-package-info (package-name) + ;; Create package info on demand. + (or (gethash package-name *cold-package-symbols*) + (let* ((cold-package (allocate-struct-of-type 'package)) + (info (cons (cons nil nil) cold-package))) + (write-slots cold-package :%used-by-list *nil-descriptor*) + (setf (gethash package-name *cold-package-symbols*) info) + (initialize-cold-package cold-package package-name) + info))) (defvar *classoid-cells*) (defun cold-find-classoid-cell (name &key create) (aver (eq create t)) (or (gethash name *classoid-cells*) - (let ((host-layout (find-layout 'sb-kernel::classoid-cell))) - (setf (gethash name *classoid-cells*) - (write-slots (allocate-struct-of-type 'sb-kernel::classoid-cell) - host-layout - :name name - :pcl-class *nil-descriptor* - :classoid *nil-descriptor*))))) - -(setf (get 'find-classoid-cell :sb-cold-funcall-handler/for-value) - #'cold-find-classoid-cell) + (setf (gethash name *classoid-cells*) + (write-slots (allocate-struct-of-type 'sb-kernel::classoid-cell) + :name name + :pcl-class *nil-descriptor* + :classoid *nil-descriptor*)))) ;;; a map from descriptors to symbols, so that we can back up. The key ;;; is the address in the target core. (defvar *cold-symbols*) (declaim (type hash-table *cold-symbols*)) -(defun set-readonly (string) (set-header-data string sb-vm:+vector-shareable+)) - -(defun initialize-packages () - (let ((package-data-list - ;; docstrings are set in src/cold/warm. It would work to do it here, - ;; but seems preferable not to saddle Genesis with such responsibility. - (list* (sb-cold:make-package-data :name "COMMON-LISP" :doc nil) - (sb-cold:make-package-data :name "KEYWORD" :doc nil) - ;; ANSI encourages us to put extension packages - ;; in the USE list of COMMON-LISP-USER. - (sb-cold:make-package-data - :name "COMMON-LISP-USER" :doc nil - :use '("COMMON-LISP" "SB-ALIEN" "SB-DEBUG" "SB-EXT" "SB-GRAY" "SB-PROFILE")) - (sb-cold::package-list-for-genesis))) - (package-layout (find-layout 'package)) - (target-pkg-list nil)) - (labels ((init-cold-package (name &optional docstring) - (let ((cold-package (allocate-struct-of-type 'package))) - (setf (gethash name *cold-package-symbols*) - (cons (cons nil nil) cold-package)) - ;; Initialize string slots - (write-slots cold-package package-layout - :%name (set-readonly - (base-string-to-core name)) - :%nicknames (chill-nicknames name) - :%bits (make-fixnum-descriptor - (if (system-package-p name) - sb-impl::+initial-package-bits+ 0)) - :doc-string (if docstring - (set-readonly - (base-string-to-core docstring)) - *nil-descriptor*) - :%use-list *nil-descriptor*) - ;; the cddr of this will accumulate the 'used-by' package list - (push (list name cold-package) target-pkg-list))) - (chill-nicknames (pkg-name) - ;; Make the package nickname lists for the standard packages - ;; be the minimum specified by ANSI, regardless of what value - ;; the cross-compilation host happens to use. - ;; For packages other than the standard packages, the nickname - ;; list was specified by our package setup code, and we can just - ;; propagate the current state into the target. - (list-to-core - (mapcar #'base-string-to-core - (cond ((string= pkg-name "COMMON-LISP") '("CL")) - ((string= pkg-name "COMMON-LISP-USER") - '("CL-USER")) - ((string= pkg-name "KEYWORD") '()) - (t - ;; 'package-data-list' contains no nicknames. - ;; (See comment in 'set-up-cold-packages') - (aver (null (package-nicknames - (find-package pkg-name)))) - nil))))) - (find-cold-package (name) - (cadr (find-package-cell name))) - (find-package-cell (name) - (or (assoc (if (string= name "CL") "COMMON-LISP" name) - target-pkg-list :test #'string=) - (error "No cold package named ~S" name)))) - ;; pass 1: make all proto-packages - (dolist (pd package-data-list) - (init-cold-package (sb-cold:package-data-name pd) - #+sb-doc(sb-cold::package-data-doc pd))) - ;; pass 2: set the 'use' lists and collect the 'used-by' lists - (dolist (pd package-data-list) - (let ((this (find-cold-package (sb-cold:package-data-name pd))) - (use nil)) - (dolist (that (sb-cold:package-data-use pd)) - (let ((cell (find-package-cell that))) - (push (cadr cell) use) - (push this (cddr cell)))) - (write-slots this package-layout - :%use-list (list-to-core (nreverse use))))) - ;; pass 3: set the 'used-by' lists - (dolist (cell target-pkg-list) - (write-slots (cadr cell) package-layout - :%used-by-list (list-to-core (cddr cell)))) - ;; finally, assign *PACKAGE* since it supposed to be always-bound - ;; and various things assume that it is. e.g. FIND-PACKAGE has an - ;; (IF (BOUNDP '*PACKAGE*)) test which the compiler elides. - (cold-set '*package* (find-cold-package "COMMON-LISP-USER"))))) +(defun set-readonly (vector) + (write-wordindexed/raw vector 0 (logior (read-bits-wordindexed vector 0) + (ash sb-vm:+vector-shareable+ + sb-vm:array-flags-position))) + vector) (defvar *uninterned-symbol-table* (make-hash-table :test #'equal)) ;; This coalesces references to uninterned symbols, which is allowed because @@ -1437,7 +1642,7 @@ core and return a descriptor to it." ;; - the target compiler doesn't and couldn't - but here it doesn't matter. (defun get-uninterned-symbol (name) (ensure-gethash name *uninterned-symbol-table* - (allocate-symbol sb-vm:symbol-size name))) + (allocate-symbol sb-vm:symbol-size nil name))) ;;; Dump the target representation of HOST-VALUE, ;;; the type of which is in a restrictive set. @@ -1459,6 +1664,7 @@ core and return a descriptor to it." (get-uninterned-symbol (string value)))) (number (number-to-core value)) (string (base-string-to-core value)) + (simple-bit-vector (bit-vector-to-core value)) (cons (cold-cons (target-representation (car value)) (target-representation (cdr value)))) (simple-vector @@ -1470,15 +1676,16 @@ core and return a descriptor to it." ;; Look up the target's descriptor for #'FUN where FUN is a host symbol. (defun cold-symbol-function (symbol &optional (errorp t)) - (declare (symbol symbol)) - (let ((f (cold-fdefn-fun (cold-fdefinition-object symbol)))) + (let* ((symbol (if (symbolp symbol) + symbol + (warm-symbol symbol))) + (f (cold-fdefn-fun (ensure-cold-fdefn symbol)))) (cond ((not (cold-null f)) f) (errorp (error "Expected a definition for ~S in cold load" symbol)) (t nil)))) ;;; Return a handle on an interned symbol. If necessary allocate the ;;; symbol and record its home package. -(defvar core-file-name) (defun cold-intern (symbol &key (access nil) (gspace (symbol-value *cold-symbol-gspace*)) @@ -1494,7 +1701,7 @@ core and return a descriptor to it." (cond ((eq package *cl-package*) (setq symbol (find-symbol name (canonical-home-package name)))) ((not (or (eq package *keyword-package*) - (= (mismatch (package-name package) "SB-") 3))) + (= (mismatch (cl:package-name package) "SB-") 3))) (bug "~S in bad package for target: ~A" symbol package))) (or (get symbol 'cold-intern-info) @@ -1503,12 +1710,12 @@ core and return a descriptor to it." ;; any symbol naming such a macro, though things still work if the slot ;; doesn't exist, as long as only a deferred interpreter processor is used ;; and not an immediate processor. - (let ((handle (allocate-symbol - (if (or (eq (info :function :kind symbol) :special-form) - (member symbol '(sb-sys:with-pinned-objects))) - sb-vm:extended-symbol-size - sb-vm:symbol-size) - name :gspace gspace))) + (let* ((pkg-info + (when core-file-name (cold-find-package-info (sb-xc:package-name package)))) + (handle (allocate-symbol sb-vm:symbol-size + (cdr pkg-info) name :gspace gspace))) + (when pkg-info + (aver (not (zerop (descriptor-fixnum (read-slot (cdr pkg-info) :id)))))) (setf (get symbol 'cold-intern-info) handle) ;; maintain reverse map from target descriptor to host symbol (setf (gethash (descriptor-bits handle) *cold-symbols*) symbol) @@ -1518,15 +1725,8 @@ core and return a descriptor to it." (cold-assign-tls-index handle index))) ;; Steps that only make sense when writing a core file (when core-file-name - ;; All interned symbols need a hash - (write-wordindexed handle sb-vm:symbol-hash-slot - (make-fixnum-descriptor (sb-xc:sxhash symbol))) - (let ((pkg-info (or (gethash (package-name package) *cold-package-symbols*) - (error "No target package descriptor for ~S" package)))) - (write-wordindexed handle sb-vm:symbol-package-slot (cdr pkg-info)) - (record-accessibility - (or access (nth-value 1 (find-symbol name package))) - pkg-info handle package symbol)) + (record-accessibility (or access (nth-value 1 (find-symbol name package))) + pkg-info handle package symbol) (when (eq package *keyword-package*) (cold-set handle handle))) handle))) @@ -1539,76 +1739,98 @@ core and return a descriptor to it." (:internal (push symbol-descriptor (cdr access-lists))) (t (error "~S inaccessible in package ~S" host-symbol host-package))))) +;;; a hash table mapping from fdefinition names to descriptors of cold +;;; objects +;;; +;;; Note: Since fdefinition names can be lists like '(SETF FOO), and +;;; we want to have only one entry per name, this must be an 'EQUAL +;;; hash table, not the default 'EQL. +(defvar *cold-fdefn-objects*) + ;;; Construct and return a value for use as *NIL-DESCRIPTOR*. ;;; It might be nice to put NIL on a readonly page by itself to prevent unsafe ;;; code from destroying the world with (RPLACx nil 'kablooey) (defun make-nil-descriptor () - ;; 8 words are placed prior to NIL to contain the 'struct alloc_region'. + ;; 10 words prior to NIL is an array of three 'struct alloc_region'. + ;; The lisp objects begin at STATIC_SPACE_OBJECTS_START. ;; See also (DEFCONSTANT NIL-VALUE) in early-objdef. - #+(and gencgc (not sb-thread)) - (allocate-vector #-64-bit sb-vm:simple-array-signed-byte-32-widetag - #+64-bit sb-vm:simple-array-signed-byte-64-widetag - 6 6 *static*) - (let* ((des (allocate-header+object *static* sb-vm:symbol-size 0)) + #+(and gencgc (not sb-thread)) (gspace-claim-n-words *static* 10) + #+64-bit (setf (gspace-free-word-index *static*) (/ 256 sb-vm:n-word-bytes)) + (let* ((des (allocate-otherptr *static* (1+ sb-vm:symbol-size) 0)) (nil-val (make-descriptor (+ (descriptor-bits des) - (* 2 sb-vm:n-word-bytes) - (- sb-vm:list-pointer-lowtag - ;; ALLOCATE-HEADER+OBJECT always adds in - ;; OTHER-POINTER-LOWTAG, so subtract it. - sb-vm:other-pointer-lowtag)))) - (header (make-other-immediate-descriptor 0 sb-vm:symbol-widetag)) - (initial-info (cold-cons nil-val nil-val)) - ;; NIL's name is in dynamic space because any extra bytes allocated - ;; in static space need to be accounted for by STATIC-SYMBOL-OFFSET. - (name (set-readonly (base-string-to-core "NIL" *dynamic*)))) + (* 2 sb-vm:n-word-bytes) + (- sb-vm:list-pointer-lowtag + ;; ALLOCATE-OTHERPTR always adds in + ;; OTHER-POINTER-LOWTAG, so subtract it. + sb-vm:other-pointer-lowtag)))) + (initial-info (cold-cons nil-val nil-val))) (aver (= (descriptor-bits nil-val) sb-vm:nil-value)) + (setf *nil-descriptor* nil-val + (gethash (descriptor-bits nil-val) *cold-symbols*) nil + (get nil 'cold-intern-info) nil-val) + ;; Alter the first word to 0 instead of the symbol size. It reads as a fixnum, - ;; but is meaningless. Not only that, the widetag is relatively meaningless too, - ;; even though you can access memory at [NIL - other-pointer-lowtag]. - ;; In practice, you can never utilize the fact that NIL has a widetag, - ;; and therefore any use of NIL-as-symbol must pre-check for NIL. Consider: - ;; 50100000: 0000000000000000 = 0 - ;; 50100008: 0000000000000045 - ;; 50100010: 0000000050100017 = NIL <-- base address of NIL - ;; 50100018: 0000000050100017 = NIL - ;; 50100020: 0000001000000007 = (NIL ..) - ;; 50100028: 000000100000800F = "NIL" - ;; 50100030: 0000001000000013 = #<PACKAGE "COMMON-LISP"> - ;; 50100038: 0000000000000000 = 0 + ;; but is meaningless. In practice, Lisp code can not utilize the fact that NIL + ;; has a widetag; any use of NIL-as-symbol must pre-check for NIL. Consider: + ;; 50100100: 0000000000000000 = 0 + ;; 50100108: 000000000000052D <- 5 words follow, widetag = #x2D + ;; 50100110: 0000000050100117 + ;; 50100118: 0000000050100117 + ;; 50100120: 0000001000000007 = (NIL . #<SB-INT:PACKED-INFO len=3 {1000002FF3}>) + ;; 50100128: 000100100000400F + ;; 50100130: 0000000000000000 = 0 ;; - ;; Indeed *(char*)(NIL-0xf) = *(char*)0x50100008 = 0x45, /* if little-endian */ + ;; Indeed *(char*)(NIL-0xf) = #x2D, /* if little-endian */ ;; so why can't we exploit this to improve SYMBOLP? Hypothetically: ;; if (((ptr & 7) == 7) && *(char*)(ptr-15) == SYMBOL_WIDETAG) { } ;; which is true of NIL and all other symbols, but wrong, because it assumes ;; that _any_ cons cell could be accessed at a negative displacement from its ;; base address. Only NIL (viewed as a cons) has this property. - ;; Performing that test on a cons at the first word of a page following an - ;; unreadable page would fault. Moreover, the word preceding a random cons would - ;; not necessarily be a widetag - it could be raw bits of a struct. Finally, + ;; Otherwise we would be reading random bytes or inaccessible memory. Finally, ;; the above sequence would not necessarily decrease the instruction count! + ;; Those points aside, gencgc correctly calls scav_symbol() on NIL. - (write-wordindexed des 0 (make-fixnum-descriptor 0)) - (write-wordindexed des 1 header) - (write-wordindexed des (+ 1 sb-vm:symbol-value-slot) nil-val) - (write-wordindexed des (+ 1 sb-vm:symbol-hash-slot) nil-val) - (write-wordindexed des (+ 1 sb-vm:symbol-info-slot) initial-info) - (write-wordindexed des (+ 1 sb-vm:symbol-name-slot) name) - (setf (gethash (descriptor-bits nil-val) *cold-symbols*) nil - (get nil 'cold-intern-info) nil-val))) + (when core-file-name + (let ((name (string-literal-to-core "NIL"))) + (write-wordindexed des 0 (make-fixnum-descriptor 0)) + ;; The header-word for NIL "as a symbol" contains a length + widetag. + (write-wordindexed des 1 (make-other-immediate-descriptor (1- sb-vm:symbol-size) + sb-vm:symbol-widetag)) + (write-wordindexed des (+ 1 sb-vm:symbol-value-slot) nil-val) + (write-wordindexed des (+ 1 sb-vm:symbol-hash-slot) nil-val) + (write-wordindexed des (+ 1 sb-vm:symbol-info-slot) initial-info) + (write-wordindexed des (+ 1 sb-vm:symbol-name-slot) name) + #+ppc64 + (progn + ;; We don't usually create an FDEFN for NIL, however on PP64 there is one + ;; made now. Due to unique lowtagging on that architectures, it doesn't magically + ;; work to access slots of NIL as a symbol the way the vops expect. + ;; There are hacks in the symbol slot reading vops, but not the writing vops, + ;; because nothing should write to slots of NIL. The sole exception would be that + ;; if someone tries to funcall NIL there can be an undefined tramp, + ;; so we make one here without adding complications to the lisp side. + (write-wordindexed des (+ 1 sb-vm:symbol-fdefn-slot) (ensure-cold-fdefn nil)) + (remhash nil *cold-fdefn-objects*)) + #+compact-symbol + (write-wordindexed/raw des (+ 1 sb-vm:symbol-name-slot) + (encode-symbol-name sb-impl::+package-id-lisp+ name)) + #-compact-symbol (write-wordindexed des (+ 1 sb-vm:symbol-name-slot) name))) + nil)) ;;; Since the initial symbols must be allocated before we can intern ;;; anything else, we intern those here. We also set the value of T. (defun initialize-static-space (tls-init) "Initialize the cold load symbol-hacking data structures." (declare (ignorable tls-init)) - ;; NIL did not have its package assigned. Do that now. - (let ((target-cl-pkg-info (gethash "COMMON-LISP" *cold-package-symbols*))) - ;; -1 is magic having to do with nil-as-cons vs. nil-as-symbol - (write-wordindexed *nil-descriptor* (- sb-vm:symbol-package-slot 1) - (cdr target-cl-pkg-info)) - (when core-file-name - (record-accessibility :external target-cl-pkg-info *nil-descriptor*))) + ;; -1 is magic having to do with nil-as-cons vs. nil-as-symbol + #-compact-symbol + (write-wordindexed *nil-descriptor* (- sb-vm:symbol-package-id-slot 1) + (make-fixnum-descriptor sb-impl::+package-id-lisp+)) + (when core-file-name + ;; NIL did not have its package assigned. Do that now. + (record-accessibility :external (cold-find-package-info "COMMON-LISP") + *nil-descriptor*)) ;; Intern the others. (dovector (symbol sb-vm:+static-symbols+) (let* ((des (cold-intern symbol :gspace *static*)) @@ -1625,7 +1847,7 @@ core and return a descriptor to it." ;; Assign TLS indices of C interface symbols #+sb-thread (progn - (dolist (binding sb-vm::!per-thread-c-interface-symbols) + (dolist (binding sb-vm::per-thread-c-interface-symbols) (ensure-symbol-tls-index (car (ensure-list binding)))) ;; Assign other known TLS indices (dolist (pair tls-init) @@ -1642,7 +1864,10 @@ core and return a descriptor to it." sb-vm:symbol-value-slot (ash (cold-layout-descriptor-bits 'function) 32)) - #+immobile-space + #+metaspace + (cold-set '**primitive-object-layouts** + (allocate-vector sb-vm:simple-vector-widetag 256 256 *read-only*)) + #+(and immobile-space (not metaspace)) (cold-set '**primitive-object-layouts** (let ((filler (make-random-descriptor @@ -1654,14 +1879,11 @@ core and return a descriptor to it." sb-vm:immobile-card-bytes (* (+ 2 256) (- sb-vm:n-word-bytes))) sb-vm:other-pointer-lowtag)))) - (write-header-word filler sb-vm:simple-array-fixnum-widetag) - (write-wordindexed filler 1 - (make-fixnum-descriptor - (- (/ sb-vm:immobile-card-bytes sb-vm:n-word-bytes) - ;; subtract 2 object headers + 256 words - (+ 4 256)))) - (write-header-word vector sb-vm:simple-vector-widetag) - (write-wordindexed vector 1 (make-fixnum-descriptor 256)) + (emplace-vector filler sb-vm:simple-array-fixnum-widetag + (- (/ sb-vm:immobile-card-bytes sb-vm:n-word-bytes) + ;; subtract 2 object headers + 256 words + (+ 4 256))) + (emplace-vector vector sb-vm:simple-vector-widetag 256) vector)) ;; Immobile code prefers all FDEFNs adjacent so that code can be located @@ -1671,21 +1893,24 @@ core and return a descriptor to it." ;; and code resides above 4GB. But as the Fundamental Theorem says: ;; any problem can be solved by adding another indirection. #+immobile-code + (progn (setf *c-callable-fdefn-vector* (vector-in-core (make-list (length sb-vm::+c-callable-fdefns+) :initial-element *nil-descriptor*) *static*)) + (setf *asm-routine-vector* (word-vector (make-list 70 :initial-element 0) + *static*))) #-immobile-code (dolist (sym sb-vm::+c-callable-fdefns+) - (cold-fdefinition-object sym *static*)) + (ensure-cold-fdefn sym *static*)) ;; With immobile-code, static-fdefns as a concept are useful - ;; the implication is that the function's definition will not change. ;; But the fdefn per se is not useful - callers refer to callees directly. #-immobile-code (dovector (sym sb-vm:+static-fdefns+) - (let* ((fdefn (cold-fdefinition-object sym *static*)) + (let* ((fdefn (ensure-cold-fdefn sym *static*)) (offset (- (+ (- (descriptor-bits fdefn) sb-vm:other-pointer-lowtag) (* sb-vm:fdefn-raw-addr-slot sb-vm:n-word-bytes)) @@ -1703,13 +1928,18 @@ core and return a descriptor to it." ;;; Establish initial values for magic symbols. ;;; (defun finish-symbols () - (cold-set '*!initial-layouts* + (cold-set 'sb-kernel::*!initial-wrappers* (vector-in-core (mapcar (lambda (pair) (cold-cons (cold-intern (car pair)) - (cold-layout-descriptor (cdr pair)))) + (->wrapper (cold-layout-descriptor (cdr pair))))) (sort-cold-layouts)))) - + ;; MAKE-LAYOUT uses ATOMIC-INCF which returns the value in the cell prior to + ;; increment, so we need to add 1 to get to the next value for it because + ;; we always pre-increment *general-layout-uniqueid-counter* when reading it. + (cold-set 'sb-kernel::*layout-id-generator* + (cold-list (make-fixnum-descriptor + (1+ sb-kernel::*general-layout-uniqueid-counter*)))) (cold-set 'sb-c::*!initial-parsed-types* (vector-in-core (mapcar (lambda (x) @@ -1718,17 +1948,57 @@ core and return a descriptor to it." (sort (%hash-table-alist *ctype-cache*) #'< :key (lambda (x) (descriptor-bits (cdr x))))))) + ;; Consume the rest of read-only-space as metaspace + #+metaspace + (let* ((space *read-only*) + (slab (gspace-current-slab space))) + (cold-set 'sb-vm::*metaspace-tracts* + (word-vector (list (+ sb-vm::read-only-space-start 32768) ; KLUDGE + (sap-int slab) + sb-vm:read-only-space-end + 0)))) + #+sb-thread (cold-set 'sb-vm::*free-tls-index* (make-descriptor (ash *genesis-tls-counter* sb-vm:word-shift))) - (cold-set '*code-serialno* (make-fixnum-descriptor (1+ *code-serialno*))) + (cold-set 'sb-c::*code-serialno* (make-fixnum-descriptor (1+ sb-c::*code-serialno*))) + + (cold-set 'sb-impl::*setf-fdefinition-hook* *nil-descriptor*) + (cold-set 'sb-impl::*user-hash-table-tests* *nil-descriptor*) ;; Put the C-callable fdefns into the static-fdefn vector if #+immobile-code. #+immobile-code - (loop for i from 0 for sym in sb-vm::+c-callable-fdefns+ - do (cold-svset *c-callable-fdefn-vector* i - (cold-fdefinition-object sym))) + (let* ((space *immobile-text*) + (wordindex (gspace-free-word-index space)) + (words-per-page (/ sb-vm:immobile-card-bytes sb-vm:n-word-bytes))) + (cold-set 'sb-fasl::*asm-routine-vector* *asm-routine-vector*) + (loop for i from 0 for sym in sb-vm::+c-callable-fdefns+ + do (cold-svset *c-callable-fdefn-vector* i + (ensure-cold-fdefn sym))) + (let* ((objects (gspace-objects space)) + (count (length objects))) + (let ((remainder (rem wordindex words-per-page))) + (unless (zerop remainder) + (let* ((fill-nwords (- words-per-page remainder)) + (des + ;; technically FILLER_WIDETAG has no valid lowtag because it's not an object + ;; that lisp can address. But WRITE-WORDINDEXED requires a pointer descriptor + (allocate-cold-descriptor space (* fill-nwords sb-vm:n-word-bytes) + sb-vm:other-pointer-lowtag))) + (aver (zerop (rem (gspace-free-word-index space) words-per-page))) + (write-header-word des (logior (ash fill-nwords 32) sb-vm:filler-widetag))))) + ;; Construct a ub32 array of object offsets. + (let* ((n-data-words (ceiling count 2)) ; lispword = 2 ub32s + (vect (allocate-vector sb-vm:simple-array-unsigned-byte-32-widetag + count n-data-words)) + (data-ptr (+ (descriptor-byte-offset vect) + (ash sb-vm:vector-data-offset sb-vm:word-shift)))) + (dotimes (i count) + (setf (bvref-32 (descriptor-mem vect) data-ptr) + (descriptor-byte-offset (aref objects i))) + (incf data-ptr 4)) + (cold-set 'sb-vm::*immobile-codeblob-vector* vect)))) ;; Symbols for which no call to COLD-INTERN would occur - due to not being ;; referenced until warm init - must be artificially cold-interned. @@ -1751,48 +2021,59 @@ core and return a descriptor to it." (cold-set 'sb-impl::*!initial-symbols* - (list-to-core - (mapcar - (lambda (pkgcons) - (destructuring-bind (pkg-name . pkg-info) pkgcons - (let ((shadow - ;; Record shadowing symbols (except from SB-XC) in SB- packages. - (when (eql (mismatch pkg-name "SB-") 3) - ;; Be insensitive to the host's ordering. - (sort (remove (find-package "SB-XC") - (package-shadowing-symbols (find-package pkg-name)) - :key #'cl:symbol-package) - #'string<)))) - (write-slots (cdr pkg-info) ; package - (find-layout 'package) - :%shadowing-symbols (list-to-core - (mapcar 'cold-intern shadow)))) - (unless (member pkg-name '("COMMON-LISP" "COMMON-LISP-USER" "KEYWORD") - :test 'string=) - (let ((host-pkg (find-package pkg-name)) - syms) - ;; Now for each symbol directly present in this host-pkg, - ;; i.e. accessible but not :INHERITED, figure out if the symbol - ;; came from a different package, and if so, make a note of it. - (with-package-iterator (iter host-pkg :internal :external) - (loop (multiple-value-bind (foundp sym accessibility) (iter) - (unless foundp (return)) - (unless (eq (cl:symbol-package sym) host-pkg) - (push (cons sym accessibility) syms))))) - (dolist (symcons (sort syms #'string< :key #'car)) - (destructuring-bind (sym . accessibility) symcons - (record-accessibility accessibility pkg-info (cold-intern sym) - host-pkg sym))))) - (cold-list (cdr pkg-info) - (vector-in-core (caar pkg-info)) - (vector-in-core (cdar pkg-info))))) - (sort (%hash-table-alist *cold-package-symbols*) - #'string< :key #'car)))) ; Sort by package-name - - (dump-symbol-info-vectors + (cold-cons + (let (uninterned) + (maphash (lambda (key val) (declare (ignore key)) (push val uninterned)) + *uninterned-symbol-table*) + (vector-in-core (sort uninterned #'< :key #'descriptor-bits))) + (list-to-core + (mapcar + (lambda (pkgcons) + (destructuring-bind (pkg-name . pkg-info) pkgcons + (unless (member pkg-name '("COMMON-LISP" "COMMON-LISP-USER" "KEYWORD") + :test 'string=) + (let ((host-pkg (find-package pkg-name)) + syms) + ;; Now for each symbol directly present in this host-pkg, + ;; i.e. accessible but not :INHERITED, figure out if the symbol + ;; came from a different package, and if so, make a note of it. + (with-package-iterator (iter host-pkg :internal :external) + (loop (multiple-value-bind (foundp sym accessibility) (iter) + (unless foundp (return)) + (unless (eq (cl:symbol-package sym) host-pkg) + (push (cons sym accessibility) syms))))) + (dolist (symcons (sort syms #'string< :key #'car)) + (destructuring-bind (sym . accessibility) symcons + (record-accessibility accessibility pkg-info (cold-intern sym) + host-pkg sym))))) + (cold-list (cdr pkg-info) + (vector-in-core (caar pkg-info)) + (vector-in-core (cdar pkg-info))))) + (sort (%hash-table-alist *cold-package-symbols*) + #'string< :key #'car))))) ; Sort by package-name + + ;; assign *PACKAGE* since it supposed to be always-bound + ;; and various things assume that it is. e.g. FIND-PACKAGE has an + ;; (IF (BOUNDP '*PACKAGE*)) test which the compiler elides. + (cold-set '*package* (cdr (cold-find-package-info "COMMON-LISP-USER"))) + + (dump-symbol-infos (attach-fdefinitions-to-symbols (attach-classoid-cells-to-symbols (make-hash-table :test #'eq)))) + #+x86-64 ; Dump a popular constant + (let ((array + ;; Embed the constant in an unboxed array. This shouldn't be necessary, + ;; because the start of the scanned space is STATIC_SPACE_OBJECTS_START, + ;; but not all uses strictly follow that rule. (They should though) + ;; This must not conflict with the alloc regions at the start of the space. + (make-random-descriptor (logior (- sb-vm::non-negative-fixnum-mask-constant-wired-address + (* 2 sb-vm:n-word-bytes)) + sb-vm:other-pointer-lowtag)))) + (write-wordindexed/raw array 0 sb-vm:simple-array-unsigned-byte-64-widetag) + (write-wordindexed array 1 (make-fixnum-descriptor 1)) + (write-wordindexed/raw array 2 sb-vm::non-negative-fixnum-mask-constant)) + #+x86 (progn (cold-set 'sb-vm::*fp-constant-0d0* (number-to-core $0d0)) @@ -1802,14 +2083,6 @@ core and return a descriptor to it." ;;;; functions and fdefinition objects -;;; a hash table mapping from fdefinition names to descriptors of cold -;;; objects -;;; -;;; Note: Since fdefinition names can be lists like '(SETF FOO), and -;;; we want to have only one entry per name, this must be an 'EQUAL -;;; hash table, not the default 'EQL. -(defvar *cold-fdefn-objects*) - ;;; Given a cold representation of a symbol, return a warm ;;; representation. (defun warm-symbol (des) @@ -1870,13 +2143,13 @@ core and return a descriptor to it." (write-wordindexed fdefn sb-vm:fdefn-fun-slot *nil-descriptor*) (write-wordindexed/raw fdefn sb-vm:fdefn-raw-addr-slot (lookup-assembler-reference 'sb-vm::undefined-tramp :direct))) -(defun cold-fdefinition-object (cold-name &optional +(defun ensure-cold-fdefn (cold-name &optional (gspace #+immobile-space *immobile-fixedobj* #-immobile-space *dynamic*)) (declare (type (or symbol descriptor) cold-name)) (let ((warm-name (warm-fun-name cold-name))) (or (gethash warm-name *cold-fdefn-objects*) - (let ((fdefn (allocate-header+object gspace (1- sb-vm:fdefn-size) sb-vm:fdefn-widetag))) + (let ((fdefn (allocate-otherptr gspace sb-vm:fdefn-size sb-vm:fdefn-widetag))) (setf (gethash warm-name *cold-fdefn-objects*) fdefn) #+x86-64 (write-wordindexed/raw ; write an INT instruction into the header @@ -1884,6 +2157,8 @@ core and return a descriptor to it." (read-bits-wordindexed fdefn 0))) (write-wordindexed fdefn sb-vm:fdefn-name-slot cold-name) (when core-file-name + (when (typep warm-name '(and symbol (not null))) + (write-wordindexed (cold-intern warm-name) sb-vm:symbol-fdefn-slot fdefn)) (if *cold-assembler-obj* (fdefn-makunbound fdefn) (push (lambda () @@ -1900,94 +2175,106 @@ core and return a descriptor to it." (- sb-vm:fun-pointer-lowtag) (ash sb-vm:simple-fun-insts-offset sb-vm:word-shift))) -;;; Handle a DEFUN in cold-load. -(defun cold-fset (name function &optional inline-expansion dxable-args) - (binding* (((cold-name warm-name) - ;; (SETF f) was descriptorized when dumped, symbols were not. - (if (symbolp name) - (values (cold-intern name) name) - (values name (warm-fun-name name)))) - (fdefn (cold-fdefinition-object cold-name))) - (unless (cold-null (cold-fdefn-fun fdefn)) - (error "Duplicate DEFUN for ~S" warm-name)) - ;; There can't be any closures or funcallable instances. - (aver (= (logand (read-bits-wordindexed function 0) sb-vm:widetag-mask) - sb-vm:simple-fun-widetag)) - (push (cold-list cold-name inline-expansion dxable-args) *!cold-defuns*) +(defun cold-fset (name function) + (aver (= (logand (read-bits-wordindexed function 0) sb-vm:widetag-mask) + sb-vm:simple-fun-widetag)) + (let ((fdefn (ensure-cold-fdefn + ;; (SETF f) was descriptorized when dumped, symbols were not. + (if (symbolp name) + (cold-intern name) + name)))) + (let ((existing (read-wordindexed fdefn sb-vm:fdefn-fun-slot))) + (unless (or (cold-null existing) (descriptor= existing function)) + (error "Function multiply defined: ~S. Was ~x is ~x" name + (descriptor-bits existing) + (descriptor-bits function)))) (write-wordindexed fdefn sb-vm:fdefn-fun-slot function) - (let ((fun-entry-addr - (+ (logandc2 (descriptor-bits function) sb-vm:lowtag-mask) - (ash sb-vm:simple-fun-insts-offset sb-vm:word-shift)))) - (declare (ignorable fun-entry-addr)) ; sparc and arm don't need - #+x86-64 - (write-wordindexed/raw ; write a JMP instruction into the header - fdefn 0 (dpb #x1025FF (byte 24 16) (read-bits-wordindexed fdefn 0))) - (write-wordindexed/raw - fdefn sb-vm:fdefn-raw-addr-slot - (or #+(or sparc arm riscv) ; raw addr is the function descriptor - (descriptor-bits function) - ;; For all others raw addr is the starting address - fun-entry-addr))) + #+x86-64 + (write-wordindexed/raw ; write a JMP instruction into the header + fdefn 0 (dpb #x1025FF (byte 24 16) (read-bits-wordindexed fdefn 0))) + (write-wordindexed/raw + fdefn sb-vm:fdefn-raw-addr-slot + (or #+(or sparc arm riscv) ; raw addr is the function descriptor + (descriptor-bits function) + ;; For all others raw addr is the starting address + (+ (logandc2 (descriptor-bits function) sb-vm:lowtag-mask) + (ash sb-vm:simple-fun-insts-offset sb-vm:word-shift)))) fdefn)) -;;; Handle a DEFMETHOD in cold-load. "Very easily done". Right. -(defun cold-defmethod (method-class name &rest stuff) - (declare (ignore method-class)) - (let ((gf (assoc name *cold-methods*))) - (unless gf - (setq gf (cons name nil)) - (push gf *cold-methods*)) - (push stuff (cdr gf)))) - (defun attach-classoid-cells-to-symbols (hashtable) - (let ((num (sb-c::meta-info-number (sb-c::meta-info :type :classoid-cell))) - (layout (cold-layout-descriptor - (gethash 'sb-kernel::classoid-cell *cold-layouts*)))) - (when (plusp (hash-table-count *classoid-cells*)) - (aver layout)) - ;; Iteration order is immaterial. The symbols will get sorted later. - (maphash (lambda (symbol cold-classoid-cell) - (setf (gethash symbol hashtable) - (packed-info-insert - (gethash symbol hashtable +nil-packed-infos+) - sb-impl::+no-auxilliary-key+ num cold-classoid-cell))) - *classoid-cells*)) + (when (plusp (hash-table-count *classoid-cells*)) + (aver (gethash 'sb-kernel::classoid-cell *cold-layouts*)) + (let ((type-classoid-cell-info + (sb-c::meta-info-number (sb-c::meta-info :type :classoid-cell))) + (type-kind-info + (sb-c::meta-info-number (sb-c::meta-info :type :kind)))) + ;; Iteration order is immaterial. The symbols will get sorted later. + (maphash (lambda (symbol cold-classoid-cell) + (let ((packed-info + (packed-info-insert + (gethash symbol hashtable +nil-packed-infos+) + sb-impl::+no-auxiliary-key+ + type-classoid-cell-info cold-classoid-cell))) + ;; an instance classoid won't be returned from %PARSE-TYPE + ;; unless the :KIND is set, but we can't set the kind + ;; to :INSTANCE unless the classoid is present in the cell. + (when (and (eq (info :type :kind symbol) :instance) + (not (cold-null (read-slot cold-classoid-cell :classoid)))) + (setf packed-info + (packed-info-insert + packed-info sb-impl::+no-auxiliary-key+ + type-kind-info (cold-intern :instance)))) + (setf (gethash symbol hashtable) packed-info))) + *classoid-cells*))) hashtable) ;; Create pointer from SYMBOL and/or (SETF SYMBOL) to respective fdefinition ;; (defun attach-fdefinitions-to-symbols (hashtable) - ;; Collect fdefinitions that go with one symbol, e.g. CAR and (SETF CAR), - ;; using the host's code for manipulating a packed info-vector. - (maphash (lambda (warm-name cold-fdefn) + ;; Collect fdefinitions that go with one symbol, e.g. (SETF CAR) and (CAS CAR) + ;; using the host's code for manipulating a packed-info. + ;; Do not add fdefns for symbols to the info. It goes in a slot. + (maphash (lambda (warm-name cold-fdefn) + (unless (symbolp warm-name) (with-globaldb-name (key1 key2) warm-name :hairy (error "Hairy fdefn name in genesis: ~S" warm-name) - :simple - (setf (gethash key1 hashtable) - (packed-info-insert - (gethash key1 hashtable +nil-packed-infos+) - key2 +fdefn-info-num+ cold-fdefn)))) - *cold-fdefn-objects*) - hashtable) - -(defun dump-symbol-info-vectors (hashtable) - ;; Emit in the same order symbols reside in core to avoid - ;; sensitivity to the iteration order of host's maphash. - (loop for (warm-sym . info) - in (sort (%hash-table-alist hashtable) #'< - :key (lambda (x) (descriptor-bits (cold-intern (car x))))) - do (write-wordindexed - (cold-intern warm-sym) sb-vm:symbol-info-slot - ;; Each vector will have one fixnum, possibly the symbol SETF, - ;; and one or two #<fdefn> objects in it, and/or a classoid-cell. - (vector-in-core - (map 'list (lambda (elt) - (etypecase elt - (symbol (cold-intern elt)) - (fixnum (make-fixnum-descriptor elt)) - (descriptor elt))) - info))))) + :simple (setf (gethash key1 hashtable) + (packed-info-insert + (gethash key1 hashtable +nil-packed-infos+) + key2 +fdefn-info-num+ cold-fdefn))))) + *cold-fdefn-objects*) + hashtable) +(defun dump-packed-info (list) + ;; Payload length is the element count + LAYOUT slot if necessary. + ;; Header word is added automatically by ALLOCATE-STRUCT + (let ((s (allocate-struct (+ sb-vm:instance-data-start (length list)) + (cold-layout-descriptor (gethash 'packed-info *cold-layouts*))))) + (loop for i from (+ sb-vm:instance-slots-offset sb-vm:instance-data-start) + for elt in list do (write-wordindexed s i elt)) + s)) +(defun dump-symbol-infos (hashtable) + (cold-set 'sb-impl::+nil-packed-infos+ + (dump-packed-info (list (make-fixnum-descriptor 0)))) + ;; Emit in the same order symbols reside in core to avoid + ;; sensitivity to the iteration order of host's maphash. + (loop for (warm-sym . info) + in (sort (%hash-table-alist hashtable) #'< + :key (lambda (x) (descriptor-bits (cold-intern (car x))))) + do (aver warm-sym) ; enforce that NIL was specially dealt with already + (aver (> (sb-impl::packed-info-len info) 1)) + (write-wordindexed + (cold-intern warm-sym) + sb-vm:symbol-info-slot + (dump-packed-info + ;; Each packed-info will have one fixnum, possibly the symbol SETF, + ;; and zero, one, or two #<fdefn>, and/or a classoid-cell. + (map 'list (lambda (elt) + (etypecase elt + (symbol (cold-intern elt)) + (sb-xc:fixnum (make-fixnum-descriptor elt)) + (descriptor elt))) + (sb-impl::packed-info-cells info)))))) ;;;; fixups and related stuff @@ -1995,68 +2282,6 @@ core and return a descriptor to it." (defvar *cold-foreign-symbol-table*) (declaim (type hash-table *cold-foreign-symbol-table*)) -;; Read the sbcl.nm file to find the addresses for foreign-symbols in -;; the C runtime. -#-linkage-table -(defun load-cold-foreign-symbol-table (filename) - (with-open-file (file filename) - (loop for line = (read-line file nil nil) - while line do - ;; UNIX symbol tables might have tabs in them, and tabs are - ;; not in Common Lisp STANDARD-CHAR, so there seems to be no - ;; nice portable way to deal with them within Lisp, alas. - ;; Fortunately, it's easy to use UNIX command line tools like - ;; sed to remove the problem, so it's not too painful for us - ;; to push responsibility for converting tabs to spaces out to - ;; the caller. - ;; - ;; Other non-STANDARD-CHARs are problematic for the same reason. - ;; Make sure that there aren't any.. - (let ((ch (find-if (lambda (char) - (not (typep char 'standard-char))) - line))) - (when ch - (error "non-STANDARD-CHAR ~S found in foreign symbol table:~%~S" - ch - line))) - (setf line (string-trim '(#\space) line)) - (let ((p1 (position #\space line :from-end nil)) - (p2 (position #\space line :from-end t))) - (if (not (and p1 p2 (< p1 p2))) - ;; KLUDGE: It's too messy to try to understand all - ;; possible output from nm, so we just punt the lines we - ;; don't recognize. We realize that there's some chance - ;; that might get us in trouble someday, so we warn - ;; about it. - (warn "ignoring unrecognized line ~S in ~A" line filename) - (multiple-value-bind (value name) - (if (string= "0x" line :end2 2) - (values (parse-integer line :start 2 :end p1 :radix 16) - (subseq line (1+ p2))) - (values (parse-integer line :end p1 :radix 16) - (subseq line (1+ p2)))) - (multiple-value-bind (old-value found) - (gethash name *cold-foreign-symbol-table*) - (when (and found - (not (= old-value value))) - (warn "redefining ~S from #X~X to #X~X" - name old-value value))) - (setf (gethash name *cold-foreign-symbol-table*) value)))))) - (values)) ;; PROGN - -#-linkage-table -(defun cold-foreign-symbol-address (name) - (declare (ignorable name)) - #+crossbuild-test #xf00fa8 ; any random 4-octet-aligned value should do - #-crossbuild-test - (or (find-foreign-symbol-in-table name *cold-foreign-symbol-table*) - (progn - (format *error-output* "~&The foreign symbol table is:~%") - (maphash (lambda (k v) - (format *error-output* "~&~S = #X~8X~%" k v)) - *cold-foreign-symbol-table*) - (error "The foreign symbol ~S is undefined." name)))) - (defvar *cold-assembler-routines*) (defvar *cold-static-call-fixups*) @@ -2071,6 +2296,11 @@ core and return a descriptor to it." (defun code-header-words (code-object) ; same, but expressed in words (ash (code-header-bytes code-object) (- sb-vm:word-shift))) +(defun code-instructions (code) + (make-model-sap (- (+ (descriptor-bits code) (code-header-bytes code)) + sb-vm:other-pointer-lowtag) + (descriptor-gspace code))) + ;;; These are fairly straightforward translations of the similarly named accessor ;;; from src/code/simple-fun.lisp (defun code-trailer-ref (code offset) @@ -2089,14 +2319,11 @@ Legal values for OFFSET are -4, -8, -12, ..." #+little-endian (ldb (byte 16 0) word) #+big-endian (ldb (byte 16 16) word))) -;;; These three are literally identical between cross-compiler and target. +;;; These are literally identical between cross-compiler and target. ;;; TODO: Maybe put them somewhere that gets defined for both? ;;; (Minor problem of CODE-COMPONENT not being a primitive type though) (defun code-n-entries (code) - (ash (code-fun-table-count code) -4)) -(defun code-fdefns-start-index (code) - (+ sb-vm:code-constants-offset - (* (code-n-entries code) sb-vm:code-slots-per-simple-fun))) + (ash (code-fun-table-count code) -5)) (defun %code-fun-offset (code fun-index) ;; The 4-byte quantity at "END" - 4 is the trailer count, the word at -8 is ;; the offset to the 0th simple-fun, -12 is the next, etc... @@ -2105,102 +2332,36 @@ Legal values for OFFSET are -4, -8, -12, ..." (defun lookup-assembler-reference (symbol &optional (mode :direct)) (let* ((code-component *cold-assembler-obj*) (list *cold-assembler-routines*) + (insts (+ (logandc2 (descriptor-bits code-component) sb-vm:lowtag-mask) + (code-header-bytes code-component))) (offset (or (cdr (assq symbol list)) - (error "Assembler routine ~S not defined." symbol)))) - (+ (logandc2 (descriptor-bits code-component) sb-vm:lowtag-mask) - (code-header-bytes code-component) - (ecase mode - (:direct - offset) - (:indirect - ;; add 1 for the prefix word that counts the absolute fixups - (ash (1+ (count-if (lambda (x) (< (cdr x) offset)) list)) - sb-vm:word-shift)))))) + (error "Assembler routine ~S not defined." symbol))) + (addr (+ insts offset))) + (ecase mode + (:direct addr) + #+(or ppc ppc64) (:indirect (- addr sb-vm:nil-value)) + #+(or x86 x86-64) + (:indirect + (let ((index (count-if (lambda (x) (< (cdr x) offset)) list))) + #-immobile-space + (+ insts (ash (1+ index) sb-vm:word-shift)) ; add 1 for the jump table count + #+immobile-space + (+ (logandc2 (descriptor-bits *asm-routine-vector*) sb-vm:lowtag-mask) + (ash (+ sb-vm:vector-data-offset index) sb-vm:word-shift))))))) ;;; Unlike in the target, FOP-KNOWN-FUN sometimes has to backpatch. (defvar *deferred-known-fun-refs*) -;;; In case we need to store code fixups in code objects. -;;; At present only the x86 backends use this -(defvar *code-fixup-notes*) -(defvar *allocation-point-fixup-notes*) - (defun code-jump-table-words (code) (ldb (byte 14 0) (read-bits-wordindexed code (code-header-words code)))) -(declaim (ftype (sfunction (descriptor sb-vm:word sb-vm:word keyword keyword) +(declaim (ftype (sfunction (descriptor sb-vm:word (or sb-vm:word + sb-vm:signed-word) + keyword keyword) descriptor) cold-fixup)) (defun cold-fixup (code-object after-header value kind flavor) - (declare (ignorable flavor)) - (let* ((offset-within-code-object - (+ (code-header-bytes code-object) after-header)) - (gspace-byte-offset (+ (descriptor-byte-offset code-object) - offset-within-code-object))) - #-(or x86 x86-64) - (sb-vm:fixup-code-object code-object gspace-byte-offset value kind flavor) - - #+(or x86 x86-64) - (let* ((gspace-data (descriptor-mem code-object)) - (obj-start-addr (logandc2 (descriptor-bits code-object) sb-vm:lowtag-mask)) - (code-end-addr (+ obj-start-addr (code-object-size code-object))) - (gspace-base (gspace-byte-address (descriptor-gspace code-object))) - (in-dynamic-space - (= (gspace-identifier (descriptor-intuit-gspace code-object)) - dynamic-core-space-id)) - (addr (+ value - (sb-vm::sign-extend (bvref-32 gspace-data gspace-byte-offset) - 32)))) - - (declare (ignorable code-end-addr in-dynamic-space)) - (assert (= obj-start-addr - (+ gspace-base (descriptor-byte-offset code-object)))) - - ;; FIXME: every other backend has the code factored out nicely into - ;; {target}-vm.lisp, but x86 doesn't. Is it really so impossible? - ;; See FIXUP-CODE-OBJECT in x86-vm.lisp and x86-64-vm.lisp. - ;; Except for the use of saps, this is nearly identical. - (when (ecase kind - (:absolute - (setf (bvref-32 gspace-data gspace-byte-offset) - (the (unsigned-byte 32) addr)) - #+x86 - (let ((n-jump-table-words (code-jump-table-words code-object))) - ;; Absolute fixups are recorded if within the object for x86. - (and in-dynamic-space - (< obj-start-addr addr code-end-addr) - ;; Except for an initial sequence of unboxed words - (>= after-header (ash n-jump-table-words sb-vm:word-shift)))) - ;; Absolute fixups on x86-64 do not refer to this code component, - ;; because we have RIP-relative addressing, but references to - ;; other immobile-space objects must be recorded. - ;; FIXME: unfortunately OAOO-violating with x86-64-vm.lisp - #+x86-64 - (member flavor '(:named-call :static-call :layout :immobile-symbol - :symbol-value :assembly-routine :assembly-routine*))) - #+x86-64 - (:absolute64 - (setf (bvref-64 gspace-data gspace-byte-offset) - (the (unsigned-byte 64) addr)) - ;; Never record it. These fixups are used only for jump table entries, - ;; which are automatically adjusted if core relocation happens. - nil) - (:relative ; (used for arguments to X86 relative CALL instruction) - (let ((diff (- addr (+ gspace-base gspace-byte-offset 4)))) ; 4 = size of rel32off - (setf (bvref-32 gspace-data gspace-byte-offset) - ;; 32-bit: use modular arithmetic since the address space is 32 bits - #+x86 (ldb (byte 32 0) diff) - ;; 64-bit: ensure that the fixup actually fits in the size - ;; encodable in the instruction, or we're screwed - #+x86-64 (the (signed-byte 32) diff))) - ;; Relative fixups are recorded if outside of the object. - ;; Except that read-only space contains calls to asm routines, - ;; and we don't record those fixups. - #+x86 (and in-dynamic-space - (not (< obj-start-addr addr code-end-addr))) - #+x86-64 (eq flavor :foreign))) - (push (cons kind after-header) - (gethash (descriptor-bits code-object) *code-fixup-notes*))))) + (sb-vm:fixup-code-object code-object after-header value kind flavor) code-object) (defun resolve-static-call-fixups () @@ -2210,45 +2371,21 @@ Legal values for OFFSET are -4, -8, -12, ..." (cold-fun-entry-addr (cold-symbol-function name)) kind :static-call)))) -;;; Save packed lists of absolute and relative fixups. -;;; (cf. FINISH-FIXUPS in generic/target-core.) -(defun repack-fixups (list) - (collect ((relative) (absolute)) - (dolist (item list) - (ecase (car item) - ;; There should be no absolute64 fixups to preserve - (:relative (relative (cdr item))) - (:absolute (absolute (cdr item))))) - (number-to-core (sb-c:pack-code-fixup-locs (absolute) (relative))))) - -#+linkage-table -(defun linkage-table-note-symbol (symbol-name datap) +(defun alien-linkage-table-note-symbol (symbol-name datap) "Register a symbol and return its address in proto-linkage-table." - (sb-vm::linkage-table-entry-address + (sb-vm::alien-linkage-table-entry-address (ensure-gethash (if datap (list symbol-name) symbol-name) *cold-foreign-symbol-table* (hash-table-count *cold-foreign-symbol-table*)))) -;;; *COLD-FOREIGN-SYMBOL-TABLE* becomes *!INITIAL-FOREIGN-SYMBOLS* in -;;; the core. When the core is loaded, !LOADER-COLD-INIT uses this to -;;; create *STATIC-FOREIGN-SYMBOLS*, which the code in -;;; target-load.lisp refers to. (defun foreign-symbols-to-core () (flet ((to-core (list transducer target-symbol) (cold-set target-symbol (vector-in-core (mapcar transducer list))))) - #-linkage-table - ;; Sort by name - (to-core (sort (%hash-table-alist *cold-foreign-symbol-table*) #'string< :key #'car) - (lambda (symbol) - (cold-cons (set-readonly (base-string-to-core (car symbol))) - (number-to-core (cdr symbol)))) - '*!initial-foreign-symbols*) - #+linkage-table ;; Sort by index into linkage table (to-core (sort (%hash-table-alist *cold-foreign-symbol-table*) #'< :key #'cdr) (lambda (pair &aux (key (car pair)) - (sym (set-readonly (base-string-to-core - (if (listp key) (car key) key))))) + (sym (string-literal-to-core + (if (listp key) (car key) key)))) (if (listp key) (cold-list sym) sym)) 'sb-vm::+required-foreign-symbols+) (cold-set (cold-intern '*assembler-routines*) *cold-assembler-obj*) @@ -2257,6 +2394,44 @@ Legal values for OFFSET are -4, -8, -12, ..." (cold-cons (cold-intern (first rtn)) (make-fixnum-descriptor (cdr rtn)))) '*!initial-assembler-routines*))) +#+sb-prelink-linkage-table +(defun foreign-symbols-to-c (output-pathname) + (with-open-file (output output-pathname + :direction :output + :if-exists :supersede) + (let ((sorted-pairs (sort (%hash-table-alist *cold-foreign-symbol-table*) #'< :key #'cdr))) + ;; Needed for uintptr_t. We use the raw uintptr_t as we don't want to have + ;; to include any SBCL headers just to get at lispobj. + (format output "#include <stdint.h>~%~%") + + ;; Write out the extern definitions. Everything is a void function (even + ;; variables) because compilers don't like void variables. Remove + ;; lisp_linkage_values as we need to write to it, so we should use the + ;; actual type. + (format output "extern void ~{~A()~^, ~};~%~%" + (remove "lisp_linkage_values" + (mapcar (lambda (x) + (if (listp (car x)) + (caar x) + (car x))) + sorted-pairs) + :test #'equal)) + + #-win32 + (format output "uintptr_t __attribute__((weak)) lisp_linkage_values[] = {~%") + #+win32 + (format output "uintptr_t lisp_linkage_values[] = {~%") + + (format output " ~D,~%" (length sorted-pairs)) + (dolist (pair sorted-pairs) + (when (listp (car pair)) + ;; This is data, put -1 in to indicate that. + (format output " (uintptr_t)-1,~%")) + (format output " (uintptr_t)&~A,~%" (if (listp (car pair)) + (caar pair) + (car pair)))) + (format output "};~%")))) + ;;;; general machinery for cold-loading FASL files @@ -2314,44 +2489,39 @@ Legal values for OFFSET are -4, -8, -12, ..." (define-cold-fop (fop-misc-trap) *unbound-marker*) (define-cold-fop (fop-struct (size)) ; n-words incl. layout, excluding header - (let* ((layout (pop-stack)) + (let* ((layout (->layout (pop-stack))) (result (allocate-struct size layout)) - (bitmap (descriptor-fixnum - (read-slot layout *host-layout-of-layout* :bitmap)))) - ;; Raw slots can not possibly work because dump-struct uses - ;; %RAW-INSTANCE-REF/WORD which does not exist in the cross-compiler. - ;; Remove this assertion if that problem is somehow circumvented. - (unless (eql bitmap sb-kernel:+layout-all-tagged+) - (error "Raw slots not working in genesis.")) - (loop for index downfrom (1- size) to sb-vm:instance-data-start - for val = (pop-stack) then (pop-stack) - do (write-wordindexed result - (+ index sb-vm:instance-slots-offset) - (if (logbitp index bitmap) - val - (descriptor-word-sized-integer val)))) - result)) - + (bitmap (cold-layout-bitmap (gethash (descriptor-bits layout) *cold-layout-by-addr*))) + (stack (%fasl-input-stack (fasl-input))) + (n-data-words (- size sb-vm:instance-data-start))) + (do ((stack-index (fop-stack-pop-n stack n-data-words) (1+ stack-index)) + (dsd-index sb-vm:instance-data-start (1+ dsd-index))) + ((>= dsd-index size)) + (let ((val (svref stack stack-index))) + (if (logbitp dsd-index bitmap) + (write-wordindexed result (+ sb-vm:instance-slots-offset dsd-index) val) + (write-wordindexed/raw result (+ sb-vm:instance-slots-offset dsd-index) + (the sb-vm:word (descriptor-integer val)))))) + result)) + +(defun find-in-inherits (typename inherits) + (binding* ((proxy (gethash typename *cold-layouts*) :exit-if-null) + (layout (->wrapper (cold-layout-descriptor proxy)))) + (dotimes (i (cold-vector-len inherits)) + (when (descriptor= (cold-svref inherits i) layout) + (return t))))) + +;;; Always return a WRAPPER if #+metaspace (define-cold-fop (fop-layout (depthoid flags length)) (decf depthoid) ; was bumped by 1 since non-stack args can't encode negatives (let* ((inherits (pop-stack)) - (bitmap (pop-stack)) + (bitmap-descriptor (pop-stack)) + (bitmap-value (descriptor-integer bitmap-descriptor)) (name (pop-stack)) (existing-layout (gethash name *cold-layouts*))) - (declare (type descriptor bitmap inherits)) + (declare (type descriptor bitmap-descriptor inherits)) (declare (type symbol name)) - (setq flags - ;; Nothing tests layout-flags at cross-compile time, - ;; so we can set them just-in-time for the cold core. - (logior flags - (cond ((member name '(pathname logical-pathname)) - sb-kernel:+pathname-layout-flag+) - ;; This layout flag would have to plumbed all the way through - ;; DEFSTRUCT-WITH-ALTERNATE-METACLASS and ENSURE-STRUCTURE-CLASS - ;; in order to set it for the root CONDITION type. - ((eq name 'condition) +condition-layout-flag+) - (t 0)))) - ;; parameter have to match an existing FOP-LAYOUT invocation if there was one + ;; parameters have to match an existing FOP-LAYOUT invocation if there was one (when existing-layout (let ((old-flags (cold-layout-flags existing-layout)) (old-depthoid (cold-layout-depthoid existing-layout)) @@ -2361,7 +2531,7 @@ Legal values for OFFSET are -4, -8, -12, ..." (unless (and (= flags old-flags) (= depthoid old-depthoid) (= length old-length) - (= (descriptor-fixnum bitmap) (descriptor-fixnum old-bitmap)) + (= bitmap-value old-bitmap) (eql (cold-vector-len inherits) (cold-vector-len old-inherits)) (dotimes (i (cold-vector-len inherits) t) (unless (descriptor= (cold-svref inherits i) @@ -2369,13 +2539,16 @@ Legal values for OFFSET are -4, -8, -12, ..." (return nil)))) ;; Users will never see this. (format t "old=(flags=~d depthoid=~d length=~d bitmap=~d inherits=~s)~%" - old-flags old-depthoid old-length old-bitmap old-inherits) + old-flags old-depthoid old-length old-bitmap + (vector-from-core old-inherits)) (format t "new=(flags=~d depthoid=~d length=~d bitmap=~d inherits=~s)~%" - flags depthoid length (descriptor-fixnum bitmap) inherits) + flags depthoid length bitmap-value + (vector-from-core inherits)) (bug "Messed up fop-layout for ~s" name)))) - (if existing-layout - (cold-layout-descriptor existing-layout) - (make-cold-layout name depthoid flags length bitmap inherits)))) + (->wrapper + (if existing-layout + (cold-layout-descriptor existing-layout) + (make-cold-layout name depthoid flags length bitmap-value inherits))))) ;;;; cold fops for loading symbols @@ -2405,6 +2578,10 @@ Legal values for OFFSET are -4, -8, -12, ..." (cold-load-symbol length+flag (ref-fop-table (fasl-input) pkg-index) (fasl-input))) +(define-cold-fop (fop-symbol-in-package-internal-save (length+flag pkg-index)) + (cold-load-symbol length+flag (ref-fop-table (fasl-input) pkg-index) + (fasl-input))) + (define-cold-fop (fop-lisp-symbol-save (length+flag)) (cold-load-symbol length+flag *cl-package* (fasl-input))) @@ -2416,13 +2593,15 @@ Legal values for OFFSET are -4, -8, -12, ..." (read-string-as-bytes (fasl-input-stream) name) (push-fop-table (get-uninterned-symbol name) (fasl-input)))) +(defun read-cold-symbol-name (symbol) + (base-string-from-core (read-wordindexed symbol sb-vm:symbol-name-slot))) + (define-cold-fop (fop-copy-symbol-save (index)) (let* ((symbol (ref-fop-table (fasl-input) index)) (name (if (symbolp symbol) (symbol-name symbol) - (base-string-from-core - (read-wordindexed symbol sb-vm:symbol-name-slot))))) + (read-cold-symbol-name symbol)))) ;; Genesis performs additional coalescing of uninterned symbols (push-fop-table (get-uninterned-symbol name) (fasl-input)))) @@ -2438,24 +2617,21 @@ Legal values for OFFSET are -4, -8, -12, ..." (define-cold-fop (fop-base-string (len)) (let ((string (make-string len))) (read-string-as-bytes (fasl-input-stream) string) - (set-readonly (base-string-to-core string)))) + (string-literal-to-core string))) #+sb-unicode (define-cold-fop (fop-character-string (len)) (bug "CHARACTER-STRING[~D] dumped by cross-compiler." len)) (define-cold-fop (fop-vector (size)) - (if (zerop size) - *simple-vector-0-descriptor* - (let ((result (allocate-vector sb-vm:simple-vector-widetag - size size *dynamic*))) - (do ((index (1- size) (1- index))) - ((minusp index)) - (declare (fixnum index)) - (write-wordindexed result - (+ index sb-vm:vector-data-offset) - (pop-stack))) - (set-readonly result)))) + (do* ((stack (%fasl-input-stack (fasl-input))) + (stackptr (fop-stack-pop-n stack size) (1+ stackptr)) + (result (allocate-vector sb-vm:simple-vector-widetag + size size *dynamic*)) + (index sb-vm:vector-data-offset (1+ index)) + (end (+ sb-vm:vector-data-offset size))) + ((= index end) (set-readonly result)) + (write-wordindexed result index (svref stack stackptr)))) ; (not-cold-fop fop-array) ; the syntax doesn't work #+nil @@ -2490,76 +2666,24 @@ Legal values for OFFSET are -4, -8, -12, ..." ;;;; cold fops for calling (or not calling) -(not-cold-fop fop-eval) -(not-cold-fop fop-eval-for-effect) - (defvar *load-time-value-counter*) -(flet ((pop-args (argc fasl-input) - (let ((args) - (stack (%fasl-input-stack fasl-input))) - (dotimes (i argc (values (pop-fop-stack stack) args)) - (push (pop-fop-stack stack) args)))) - (call (fun-name handler-name args) - (acond ((get fun-name handler-name) (apply it args)) - (t (error "Can't ~S ~S in cold load" handler-name fun-name))))) - - (define-cold-fop (fop-funcall (n)) - (multiple-value-bind (fun args) (pop-args n (fasl-input)) - (if args - (case fun - (fdefinition - ;; Special form #'F fopcompiles into `(FDEFINITION ,f) - (aver (and (singleton-p args) (symbolp (car args)))) - (cold-symbol-function (car args))) - (cons (cold-cons (first args) (second args))) - (symbol-global-value (cold-symbol-value (first args))) - (values-specifier-type - (let* ((des (first args)) - (spec (if (descriptor-p des) (host-object-from-core des) des))) - (ctype-to-core spec (funcall fun spec)))) - (sb-thread:make-mutex - (aver (eq (car args) :name)) - (write-slots (allocate-struct-of-type 'sb-thread:mutex) - 'sb-thread:mutex - :name (cadr args) - :%owner *nil-descriptor*)) - (t - (call fun :sb-cold-funcall-handler/for-value args))) - (let ((counter *load-time-value-counter*)) - (push (cold-list (cold-intern :load-time-value) fun - (number-to-core counter)) *!cold-toplevels*) - (setf *load-time-value-counter* (1+ counter)) - (make-ltv-patch counter))))) - - (define-cold-fop (fop-funcall-for-effect (n)) - (multiple-value-bind (fun args) (pop-args n (fasl-input)) - (if (not args) - (push fun *!cold-toplevels*) - (case fun - (sb-impl::%defun (apply #'cold-fset args)) - (sb-pcl::!trivial-defmethod (apply #'cold-defmethod args)) - (sb-kernel::%defstruct - (push args *known-structure-classoids*) - (push (apply #'cold-list (cold-intern 'defstruct) args) - *!cold-toplevels*)) - ((sb-c::%defconstant sb-impl::%defparameter) - (destructuring-bind (name val . rest) args - (cold-set name (if (symbolp val) (cold-intern val) val)) - (push (apply #'cold-list (cold-intern fun) (cold-intern name) rest) - *!cold-defsymbols*))) - (set - (aver (= (length args) 2)) - (cold-set (first args) - (let ((val (second args))) - (if (symbolp val) (cold-intern val) val)))) - (%svset (apply 'cold-svset args)) - (t (call fun :sb-cold-funcall-handler/for-effect args))))))) - -;;; Needed for certain L-T-V lambdas that use the -NO-SKIP variant of funcall. -#-c-headers-only -(setf (svref **fop-funs** (get 'fop-funcall-no-skip 'opcode)) - (svref **fop-funs** (get 'fop-funcall 'opcode))) +(define-cold-fop (fop-funcall (n)) + (if (= n 0) + (let ((counter *load-time-value-counter*)) + (push (cold-list (cold-intern :load-time-value) + (pop-stack) + (number-to-core counter)) *!cold-toplevels*) + (setf *load-time-value-counter* (1+ counter)) + (make-ltv-patch counter)) + (let ((des (pop-stack))) + (unless (and (= n 1) + (eq (pop-stack) 'values-specifier-type)) + (error "Can't FOP-FUNCALL random stuff in cold load.")) + (let ((spec (if (descriptor-p des) (host-object-from-core des) des))) + (ctype-to-core spec (if (eq spec '*) + *wild-type* + (values-specifier-type spec))))))) (defun finalize-load-time-value-noise () (cold-set '*!load-time-values* @@ -2567,6 +2691,18 @@ Legal values for OFFSET are -4, -8, -12, ..." *load-time-value-counter* *load-time-value-counter*))) +(define-cold-fop (fop-funcall-for-effect (n)) + (if (= n 0) + (push (pop-stack) *!cold-toplevels*) + (error "Can't FOP-FUNCALL-FOR-EFFECT random stuff in cold load"))) + +(define-cold-fop (fop-named-constant-set (index)) + (push (cold-list (cold-intern :named-constant) + (pop-stack) + (number-to-core index) + (pop-stack)) + *!cold-toplevels*)) + ;;;; cold fops for fixing up circularities @@ -2601,8 +2737,53 @@ Legal values for OFFSET are -4, -8, -12, ..." (name (pop-stack))) (cold-fset name fn))) +(define-cold-fop (fop-mset) + (let ((fn (pop-stack)) + (specializers (pop-stack)) + (qualifiers (pop-stack)) + (name (pop-stack))) + ;; Methods that are qualified or are specialized on more than + ;; one argument do not work on start-up, since our start-up + ;; implementation of method dispatch is single dispatch only. + (when (and (null qualifiers) + (= 1 (count-if-not (lambda (x) (eq x t)) (host-object-from-core specializers)))) + (push (list (cold-car specializers) fn) + (cdr (or (assoc name *cold-methods*) + (car (push (list name) *cold-methods*)))))))) + +;;; Order all initial methods so that the first one whose guard +;;; returns T is the most specific method. LAYOUT-DEPTHOID is a valid +;;; sort key for this because we don't have multiple inheritance in +;;; the system object type lattice. +(defun sort-initial-methods () + (cold-set + 'sb-pcl::*!initial-methods* + (list-to-core + (loop for (gf-name . methods) in *cold-methods* + collect + (cold-cons + (cold-intern gf-name) + (vector-in-core + (loop for (class fun) + ;; Methods must be sorted because we invoke + ;; only the first applicable one. + in (stable-sort methods #'> ; highest depthoid first + :key (lambda (method) + (class-depthoid (warm-symbol (car method))))) + collect + (vector-in-core + (let ((class-symbol (warm-symbol class))) + (list (cold-intern + (predicate-for-specializer class-symbol)) + (acond ((gethash class-symbol *cold-layouts*) + (->wrapper (cold-layout-descriptor it))) + (t + (aver (predicate-for-specializer class-symbol)) + class)) + fun)))))))))) + (define-cold-fop (fop-fdefn) - (cold-fdefinition-object (pop-stack))) + (ensure-cold-fdefn (pop-stack))) (define-cold-fop (fop-known-fun) (let ((name (pop-stack))) @@ -2619,56 +2800,84 @@ Legal values for OFFSET are -4, -8, -12, ..." sb-vm:other-pointer-lowtag)) #-untagged-fdefns (write-wordindexed code index fdefn)) -(define-cold-fop (fop-load-code (header code-size n-fixups)) - (let* ((n-named-calls (read-unsigned-byte-32-arg (fasl-input-stream))) +(define-cold-fop (fop-load-code (header n-code-bytes n-fixup-elts)) + (let* ((n-simple-funs (read-unsigned-byte-32-arg (fasl-input-stream))) + (n-fdefns (read-unsigned-byte-32-arg (fasl-input-stream))) + (n-boxed-words (ash header -1)) + (n-constants (- n-boxed-words sb-vm:code-constants-offset)) + (stack-elts-consumed (+ n-constants 1 n-fixup-elts)) + (immobile (oddp header)) ; decode the representation used by dump ;; The number of constants is rounded up to even (if required) ;; to ensure that the code vector will be properly aligned. - (n-boxed-words (ash header -1)) (aligned-n-boxed-words (align-up n-boxed-words sb-c::code-boxed-words-align)) - (debug-info (pop-stack)) + (stack (%fasl-input-stack (fasl-input))) + (stack-index (fop-stack-pop-n stack stack-elts-consumed)) (des (allocate-cold-descriptor - (or #+immobile-code (and (oddp header) *immobile-varyobj*) + (or #+immobile-code (and immobile *immobile-text*) *dynamic*) - (+ (ash aligned-n-boxed-words sb-vm:word-shift) code-size) + (+ (ash aligned-n-boxed-words sb-vm:word-shift) n-code-bytes) sb-vm:other-pointer-lowtag :code))) - (write-code-header-words des aligned-n-boxed-words code-size n-named-calls) - (write-wordindexed des sb-vm:code-debug-info-slot debug-info) - - (let* ((start (+ (descriptor-byte-offset des) - (ash aligned-n-boxed-words sb-vm:word-shift))) - (end (+ start code-size))) - (read-bigvec-as-sequence-or-die (descriptor-mem des) (fasl-input-stream) - :start start :end end) + (declare (ignorable immobile)) + (write-code-header-words des aligned-n-boxed-words n-code-bytes n-fdefns) + (write-wordindexed des sb-vm:code-debug-info-slot + (svref stack (+ stack-index n-constants))) + + (let ((start (+ (descriptor-byte-offset des) + (ash aligned-n-boxed-words sb-vm:word-shift)))) + (read-into-bigvec (descriptor-mem des) (fasl-input-stream) start n-code-bytes) + (aver (= (code-n-entries des) n-simple-funs)) (let ((jumptable-word (read-bits-wordindexed des aligned-n-boxed-words))) (aver (zerop (ash jumptable-word -14))) ;; assign serialno - (write-wordindexed/raw des aligned-n-boxed-words - (logior (ash (incf *code-serialno*) 14) jumptable-word))) + (write-wordindexed/raw + des aligned-n-boxed-words + (logior (ash (incf sb-c::*code-serialno*) (byte-position sb-vm::code-serialno-byte)) + jumptable-word))) (when *show-pre-fixup-code-p* (format *trace-output* "~&LOAD-CODE: ~d header words, ~d code bytes.~%" - n-boxed-words code-size) - (do ((i start (+ i sb-vm:n-word-bytes))) - ((>= i end)) + n-boxed-words n-code-bytes) + (do ((i start (+ i sb-vm:n-word-bytes)) + (count (floor n-code-bytes sb-vm:n-word-bytes) (1- count))) + ((zerop count)) (format *trace-output* " ~X: ~V,'.X~%" (+ i (gspace-byte-address (descriptor-gspace des))) (* 2 sb-vm:n-word-bytes) (bvref-word (descriptor-mem des) i))))) - (let* ((fdefns-start (code-fdefns-start-index des)) - (fdefns-end (1- (+ fdefns-start n-named-calls)))) ; inclusive bound - (do ((index (1- n-boxed-words) (1- index))) - ((< index sb-vm:code-constants-offset)) - (let ((obj (pop-stack))) - (cond ((and (consp obj) (eq (car obj) :known-fun)) - (push (list* (cdr obj) des index) *deferred-known-fun-refs*)) - ((<= fdefns-start index fdefns-end) - (store-named-call-fdefn des index obj)) - (t - (write-wordindexed des index obj)))))) - - (apply-fixups (%fasl-input-stack (fasl-input)) des n-fixups))) + (apply-fixups des stack (+ stack-index (1+ n-constants)) n-fixup-elts) + (let ((header-index sb-vm:code-constants-offset)) + (declare (type index header-index stack-index)) + (dotimes (fun-index (code-n-entries des)) + (let ((fn (%code-entry-point des fun-index))) + #+compact-instance-header + (write-wordindexed/raw fn 0 (logior (ash (cold-layout-descriptor-bits 'function) 32) + (read-bits-wordindexed fn 0))) + #+(or x86 x86-64 arm64) ; store a machine-native pointer to the function entry + ;; note that the bit pattern looks like fixnum due to alignment + (write-wordindexed/raw fn sb-vm:simple-fun-self-slot + (+ (- (descriptor-bits fn) sb-vm:fun-pointer-lowtag) + (ash sb-vm:simple-fun-insts-offset sb-vm:word-shift))) + #-(or x86 x86-64 arm64) ; store a pointer back to the function itself in 'self' + (write-wordindexed fn sb-vm:simple-fun-self-slot fn)) + (dotimes (i sb-vm:code-slots-per-simple-fun) + (write-wordindexed des header-index (svref stack stack-index)) + (incf header-index) + (incf stack-index))) + (dotimes (i n-fdefns) + (store-named-call-fdefn des header-index (svref stack stack-index)) + (incf header-index) + (incf stack-index)) + (do () ((>= header-index n-boxed-words)) + (let ((constant (svref stack stack-index))) + (cond ((and (consp constant) (eq (car constant) :known-fun)) + (push (list* (cdr constant) des header-index) *deferred-known-fun-refs*)) + (t + (write-wordindexed des header-index constant)))) + (incf header-index) + (incf stack-index))) + des)) (defun resolve-deferred-known-funs () (dolist (item *deferred-known-fun-refs*) @@ -2676,43 +2885,21 @@ Legal values for OFFSET are -4, -8, -12, ..." (place (cdr item))) (write-wordindexed (car place) (cdr place) fun)))) -(defun compute-fun (code-object fun-index) - (let* ((code-instructions - (+ (descriptor-bits code-object) - (- sb-vm:other-pointer-lowtag) - (code-header-bytes code-object))) - (fun (+ code-instructions (%code-fun-offset code-object fun-index)))) +(defun %code-entry-point (code-object fun-index) + (let ((fun (sap-int (sap+ (code-instructions code-object) + (%code-fun-offset code-object fun-index))))) (unless (zerop (logand fun sb-vm:lowtag-mask)) (error "unaligned function entry ~S ~S" code-object fun-index)) (make-descriptor (logior fun sb-vm:fun-pointer-lowtag)))) -(define-cold-fop (fop-fun-entry (fun-index)) - (let* ((code-object (pop-stack)) - (fn (compute-fun code-object fun-index))) - #+compact-instance-header - (write-wordindexed/raw - fn 0 (logior (descriptor-bits (cold-symbol-value 'sb-vm:function-layout)) - (read-bits-wordindexed fn 0))) - #+(or x86 x86-64) ; store a machine-native pointer to the function entry - ;; note that the bit pattern looks like fixnum due to alignment - (write-wordindexed/raw fn sb-vm:simple-fun-self-slot - (+ (- (descriptor-bits fn) sb-vm:fun-pointer-lowtag) - (ash sb-vm:simple-fun-insts-offset sb-vm:word-shift))) - #-(or x86 x86-64) ; store a pointer back to the function itself in 'self' - (write-wordindexed fn sb-vm:simple-fun-self-slot fn) - fn)) - (define-cold-fop (fop-assembler-code) (aver (not *cold-assembler-obj*)) - (let* ((length (read-word-arg (fasl-input-stream))) - (n-routines (read-word-arg (fasl-input-stream))) - (n-fixups (read-word-arg (fasl-input-stream))) + (let* ((n-routines (read-word-arg (fasl-input-stream))) + (length (read-word-arg (fasl-input-stream))) + (n-fixup-elts (read-word-arg (fasl-input-stream))) (rounded-length (round-up length (* 2 sb-vm:n-word-bytes))) - (header-n-words - ;; Note: we round the number of constants up to ensure that - ;; the code vector will be properly aligned. - (round-up sb-vm:code-constants-offset 2)) - (space (or #+immobile-space *immobile-varyobj* + (header-n-words (sb-c::asm-routines-boxed-header-nwords)) + (space (or #+(and immobile-code (not metaspace)) *immobile-text* ;; If there is a read-only space, use it, else use static space. (if (> sb-vm:read-only-space-end sb-vm:read-only-space-start) *read-only* @@ -2720,16 +2907,19 @@ Legal values for OFFSET are -4, -8, -12, ..." (asm-code (allocate-cold-descriptor space - (+ (ash header-n-words sb-vm:word-shift) length) + (+ (ash header-n-words sb-vm:word-shift) rounded-length) sb-vm:other-pointer-lowtag))) (setf *cold-assembler-obj* asm-code) (write-code-header-words asm-code header-n-words rounded-length 0) (let ((start (+ (descriptor-byte-offset asm-code) (ash header-n-words sb-vm:word-shift)))) - (read-bigvec-as-sequence-or-die (descriptor-mem asm-code) - (fasl-input-stream) - :start start - :end (+ start length))) + (read-into-bigvec (descriptor-mem asm-code) (fasl-input-stream) start length)) + ;; Write a bignum reference into the boxed constants. + ;; All the backends should do this, as its avoids consing in GENERIC-NEGATE + ;; when the argument is MOST-NEGATIVE-FIXNUM. + #+x86-64 (write-wordindexed asm-code sb-vm:code-constants-offset + (bignum-to-core (- most-negative-fixnum) + #-immobile-space *static*)) ;; Update the name -> address table. (let (table) (dotimes (i n-routines) @@ -2740,62 +2930,82 @@ Legal values for OFFSET are -4, -8, -12, ..." ;; at assembly time, they can all be sorted at this point. ;; We used to combine them with some magic in genesis. (setq *cold-assembler-routines* (sort table #'< :key #'cdr))) + (let ((stack (%fasl-input-stack (fasl-input)))) + (apply-fixups asm-code stack (fop-stack-pop-n stack n-fixup-elts) n-fixup-elts)) #+(or x86 x86-64) ; fill in the indirect call table - (let ((index (code-header-words asm-code))) + (let ((base (code-header-words asm-code)) + (index 0)) (dolist (item *cold-assembler-routines*) - ;; Preincrement because we skip 1 word for the word containing - ;; the number of absolute fixups that follow. - (write-wordindexed/raw asm-code (incf index) - (lookup-assembler-reference (car item))))) - (apply-fixups (%fasl-input-stack (fasl-input)) asm-code n-fixups))) + ;; Word 0 of code-instructions is the jump table count (the asm routine entrypoints + ;; look to GC exactly like a jump table in any other codeblob) + (let ((entrypoint (lookup-assembler-reference (car item)))) + (write-wordindexed/raw asm-code (+ base index 1) entrypoint) + #+immobile-space + (unless (member (car item) ; these can't be called from compiled Lisp + '(sb-vm::fpr-save sb-vm::save-xmm sb-vm::save-ymm + sb-vm::fpr-restore sb-vm::restore-xmm sb-vm::restore-ymm)) + (write-wordindexed/raw *asm-routine-vector* + (+ sb-vm:vector-data-offset index) entrypoint))) + (incf index))))) + +;; The partial source info is not needed during the cold load, since +;; it can't be interrupted. +(define-cold-fop (fop-note-partial-source-info) + (pop-stack) + (pop-stack) + (pop-stack) + (values)) ;;; Target variant of this is defined in 'target-load' -(defun apply-fixups (fop-stack code-obj n-fixups) - (dotimes (i n-fixups code-obj) - (binding* ((info (descriptor-fixnum (pop-fop-stack fop-stack))) - (sym (pop-fop-stack fop-stack)) - ((offset kind flavor) (!unpack-fixup-info info))) +(defun apply-fixups (code-obj fixups index count &aux (end (1- (+ index count)))) + (let ((retained-fixups (svref fixups index))) + (write-wordindexed code-obj sb-vm::code-fixups-slot retained-fixups) + (incf index)) + (binding* ((alloc-points (svref fixups index) :exit-if-null)) + (cold-set 'sb-c::*!cold-allocation-patch-point* + (cold-cons (cold-cons code-obj alloc-points) + (cold-symbol-value 'sb-c::*!cold-allocation-patch-point*)))) + (loop + (when (>= index end) (return)) + (binding* (((offset kind flavor) + (!unpack-fixup-info (descriptor-integer (svref fixups (incf index))))) + (name (cond ((member flavor '(:code-object :gc-barrier)) nil) + (t (svref fixups (incf index))))) + (string + (when (descriptor-p name) + (let ((widetag (logand (read-bits-wordindexed name 0) sb-vm:widetag-mask))) + (when (= widetag sb-vm:simple-base-string-widetag) + (base-string-from-core name)))))) (if (eq flavor :static-call) - (push (list sym kind code-obj offset) *cold-static-call-fixups*) + (push (list name kind code-obj offset) *cold-static-call-fixups*) (cold-fixup code-obj offset (ecase flavor - (:assembly-routine (lookup-assembler-reference sym)) - (:assembly-routine* (lookup-assembler-reference sym :indirect)) - (:asm-routine-nil-offset - (- (lookup-assembler-reference sym) sb-vm:nil-value)) - (:foreign - (let ((sym (base-string-from-core sym))) - #+linkage-table (linkage-table-note-symbol sym nil) - #-linkage-table (cold-foreign-symbol-address sym))) - (:foreign-dataref - (let ((sym (base-string-from-core sym))) - #+linkage-table (linkage-table-note-symbol sym t) - #-linkage-table - (progn (maphash (lambda (k v) - (format *error-output* "~&~S = #X~8X~%" k v)) - *cold-foreign-symbol-table*) - (error "shared foreign symbol in cold load: ~S (~S)" sym kind)))) + (:assembly-routine (lookup-assembler-reference name)) + (:assembly-routine* (lookup-assembler-reference name :indirect)) + (:foreign (alien-linkage-table-note-symbol string nil)) + (:foreign-dataref (alien-linkage-table-note-symbol string t)) (:code-object (descriptor-bits code-obj)) #+sb-thread ; ENSURE-SYMBOL-TLS-INDEX isn't defined otherwise - (:symbol-tls-index (ensure-symbol-tls-index sym)) - (:layout (cold-layout-descriptor-bits sym)) + (:symbol-tls-index (ensure-symbol-tls-index name)) + (:layout (cold-layout-descriptor-bits name)) + (:layout-id ; SYM is a #<WRAPPER> + (cold-layout-id (gethash (descriptor-bits (->layout name)) + *cold-layout-by-addr*))) + ;; The machine-dependent code decides how to patch in 'nbits' + #+gencgc (:gc-barrier sb-vm::gencgc-card-table-index-nbits) (:immobile-symbol ;; an interned symbol is represented by its host symbol, ;; but an uninterned symbol is a descriptor. - (descriptor-bits (if (symbolp sym) (cold-intern sym) sym))) - (:symbol-value - (descriptor-bits (cold-symbol-value sym))) - (:named-call - (+ (descriptor-bits (cold-fdefinition-object sym)) + (descriptor-bits (if (symbolp name) (cold-intern name) name))) + (:symbol-value (descriptor-bits (cold-symbol-value name))) + (:fdefn-call ; x86-64 only + (+ (descriptor-bits (ensure-cold-fdefn name)) + ;; this jumps to the jump instruction embedded within an fdefn. + ;; (It's a terrible technique which I plan to remove.) (- 2 sb-vm:other-pointer-lowtag)))) - kind flavor)) - (when (and (member sym '(sb-vm::enable-alloc-counter - sb-vm::enable-sized-alloc-counter)) - ;; Ignore symbol fixups naming these assembly routines! - (member flavor '(:assembly-routine :assembly-routine*))) - (push (cold-cons code-obj (make-fixnum-descriptor offset)) - *allocation-point-fixup-notes*))))) + kind flavor)))) + code-obj) ;;;; sanity checking space layouts @@ -2806,7 +3016,7 @@ Legal values for OFFSET are -4, -8, -12, ..." (when (= start end) ; 0 size is allowed (return-from check)) (unless (< start end) - (error "Bogus space: ~A" space)) + (error "Space bounds look bad: ~A = ~X..~X" space start end)) (let ((type (specifier-type `(integer ,start (,end))))) (dolist (other types) (unless (eq *empty-type* (type-intersection (cdr other) type)) @@ -2821,12 +3031,12 @@ Legal values for OFFSET are -4, -8, -12, ..." #+immobile-space ;; Must be a multiple of 32 because it makes the math a nicer ;; when computing word and bit index into the 'touched' bitmap. - (assert (zerop (rem sb-vm:fixedobj-space-size - (* 32 sb-vm:immobile-card-bytes)))) + (aver (zerop (rem sb-vm:fixedobj-space-size (* 32 sb-vm:immobile-card-bytes)))) #-gencgc (check sb-vm:dynamic-0-space-start sb-vm:dynamic-0-space-end :dynamic-0) - #+linkage-table - (check sb-vm:linkage-table-space-start sb-vm:linkage-table-space-end :linkage-table)))) + #-immobile-space + (let ((end (+ sb-vm:alien-linkage-table-space-start sb-vm:alien-linkage-table-space-size))) + (check sb-vm:alien-linkage-table-space-start end :linkage-table))))) ;;;; emitting C header file @@ -2872,6 +3082,8 @@ Legal values for OFFSET are -4, -8, -12, ..." (format t "#define LISP_FEATURE_~A~%" target-feature-name)) (terpri) ;; and miscellaneous constants + (format t "#define SBCL_TARGET_ARCHITECTURE_STRING ~S~%" + (substitute #\_ #\- (string-downcase (sb-cold::target-platform-keyword)))) (format t "#define SBCL_VERSION_STRING ~S~%" (sb-xc:lisp-implementation-version)) (format t "#define CORE_MAGIC 0x~X~%" core-magic) @@ -2887,124 +3099,115 @@ Legal values for OFFSET are -4, -8, -12, ..." #-(and win32 x86-64) "LU") ; "long" is 64 bits (defun write-constants-h (*standard-output*) - ;; writing entire families of named constants (let ((constants nil)) - (dolist (package-name '("SB-VM" - ;; We also propagate magic numbers - ;; related to file format, - ;; which live here instead of SB-VM. - "SB-FASL" - ;; Home package of some constants which aren't - ;; in the target Lisp but are propagated to C. - "SB-COREFILE")) - (do-external-symbols (symbol (find-package package-name)) - (when (constantp symbol) - (let ((name (symbol-name symbol))) - (labels ( ;; shared machinery - (record (string priority suffix) - (push (list string - priority - (symbol-value symbol) - suffix - (documentation symbol 'variable)) - constants)) - ;; machinery for old-style CMU CL Lisp-to-C - ;; arbitrary renaming, being phased out in favor of - ;; the newer systematic RECORD-WITH-TRANSLATED-NAME - ;; renaming - (record-with-munged-name (prefix string priority) - (record (concatenate - 'simple-string - prefix - (delete #\- (string-capitalize string))) - priority - "")) - (maybe-record-with-munged-name (tail prefix priority) - (when (tailwise-equal name tail) - (record-with-munged-name prefix - (subseq name 0 - (- (length name) - (length tail))) - priority))) - ;; machinery for new-style SBCL Lisp-to-C naming - (record-with-translated-name (priority large) - (record (c-name name) priority - (if large +c-literal-64bit+ ""))) - (maybe-record-with-translated-name (suffixes priority &key large) - (when (some (lambda (suffix) - (tailwise-equal name suffix)) - suffixes) - (record-with-translated-name priority large)))) - (maybe-record-with-translated-name '("-LOWTAG" "-ALIGN") 0) - (maybe-record-with-translated-name '("-WIDETAG" "-SHIFT") 1) - (maybe-record-with-munged-name "-FLAG" "flag_" 2) - (maybe-record-with-munged-name "-TRAP" "trap_" 3) - (maybe-record-with-munged-name "-SUBTYPE" "subtype_" 4) - (maybe-record-with-translated-name '("SHAREABLE+" "SHAREABLE-NONSTD+") 4) - (maybe-record-with-munged-name "-SC-NUMBER" "sc_" 5) - (maybe-record-with-translated-name '("-SIZE" "-INTERRUPTS") 6) - (maybe-record-with-translated-name '("-START" "-END" "-PAGE-BYTES" - "-CARD-BYTES" "-GRANULARITY") - 7 :large t) - (maybe-record-with-translated-name '("-CORE-ENTRY-TYPE-CODE") 8) - (maybe-record-with-translated-name '("-CORE-SPACE-ID") 9) - (maybe-record-with-translated-name '("-CORE-SPACE-ID-FLAG") 9) - (maybe-record-with-translated-name '("-GENERATION+") 10)))))) - ;; KLUDGE: these constants are sort of important, but there's no - ;; pleasing way to inform the code above about them. So we fake - ;; it for now. nikodemus on #lisp (2004-08-09) suggested simply - ;; exporting every numeric constant from SB-VM; that would work, - ;; but the C runtime would have to be altered to use Lisp-like names - ;; rather than the munged names currently exported. --njf, 2004-08-09 - (dolist (c '(sb-vm:n-word-bits sb-vm:n-word-bytes - sb-vm:n-lowtag-bits sb-vm:lowtag-mask - sb-vm:n-widetag-bits sb-vm:widetag-mask - sb-vm:n-fixnum-tag-bits sb-vm:fixnum-tag-mask - sb-vm:short-header-max-words)) - (push (list (c-symbol-name c) - -1 ; invent a new priority - (symbol-value c) - "" - nil) - constants)) - ;; One more symbol that doesn't fit into the code above. - (let ((c 'sb-impl::+magic-hash-vector-value+)) - (push (list (c-symbol-name c) 9 (symbol-value c) +c-literal-64bit+ nil) - constants)) - ;; And still one more - #+64-bit - (let ((c 'sb-vm::immediate-widetags-mask)) - (push (list (c-symbol-name c) - 1 - (logior (ash 1 (ash sb-vm:character-widetag -2)) - (ash 1 (ash sb-vm:single-float-widetag -2)) - (ash 1 (ash sb-vm:unbound-marker-widetag -2))) - "LU" - nil) - constants)) + (flet ((record (string priority symbol suffix) + (push (list string priority (symbol-value symbol) suffix) + constants))) + ;; writing entire families of named constants + (dolist (package-name '("SB-VM" + ;; We also propagate magic numbers + ;; related to file format, + ;; which live here instead of SB-VM. + "SB-FASL" + ;; Home package of some constants which aren't + ;; in the target Lisp but are propagated to C. + "SB-COREFILE")) + (do-external-symbols (symbol (find-package package-name)) + (when (cl:constantp symbol) + (let ((name (symbol-name symbol))) + ;; Older naming convention + (labels ((record-camelcased (prefix string priority) + (record (concatenate 'simple-string + prefix + (delete #\- (string-capitalize string))) + priority symbol "")) + (maybe-record (tail prefix priority) + (when (tailwise-equal name tail) + (record-camelcased prefix + (subseq name 0 + (- (length name) (length tail))) + priority)))) + (maybe-record "-FLAG" "flag_" 2) + (maybe-record "-TRAP" "trap_" 3) + (maybe-record "-SC-NUMBER" "sc_" 5)) + ;; Newer naming convention + (labels ((record-translated (priority large) + (record (c-name name) priority symbol + (if large +c-literal-64bit+ ""))) + (maybe-record (suffixes priority &key large) + (when (some (lambda (suffix) (tailwise-equal name suffix)) + suffixes) + (record-translated priority large)))) + (maybe-record '("-LOWTAG" "-ALIGN") 0) + (maybe-record '("-WIDETAG" "-SHIFT") 1) + (maybe-record '("SHAREABLE+" "SHAREABLE-NONSTD+") 4) + (maybe-record '("-SIZE" "-INTERRUPTS") 6) + (maybe-record '("-START" "-END" "-PAGE-BYTES" + "-CARD-BYTES" "-GRANULARITY") + 7 :large t) + (maybe-record '("-CORE-ENTRY-TYPE-CODE") 8) + (maybe-record '("-CORE-SPACE-ID") 9) + (maybe-record '("-CORE-SPACE-ID-FLAG") 9) + (maybe-record '("-GENERATION+") 10)))))) + (dolist (c '(sb-impl::+package-id-none+ + sb-impl::+package-id-keyword+ + sb-impl::+package-id-lisp+ + sb-impl::+package-id-user+ + sb-impl::+package-id-kernel+ + sb-impl::symbol-name-bits)) + (record (c-symbol-name c) 3/2 #| arb |# c "")) + ;; Other constants that aren't necessarily grouped into families. + (dolist (c '(sb-kernel:maximum-bignum-length + sb-vm:n-word-bits sb-vm:n-word-bytes + sb-vm:n-lowtag-bits sb-vm:lowtag-mask + sb-vm:n-widetag-bits sb-vm:widetag-mask + sb-vm:n-fixnum-tag-bits sb-vm:fixnum-tag-mask + sb-vm:instance-length-mask + sb-vm:dsd-raw-type-mask + sb-vm:short-header-max-words + sb-vm:array-flags-position + sb-vm:array-rank-position)) + (record (c-symbol-name c) -1 c "")) + ;; More symbols that doesn't fit into the pattern above. + (dolist (c '(sb-impl::+magic-hash-vector-value+ + ;; These next two flags bits use different naming conventions unfortunately, + ;; but one's a vector header bit, the other a layout flag bit. + sb-vm::+vector-alloc-mixed-region-bit+ + sb-kernel::+strictly-boxed-flag+ + sb-vm::nil-symbol-slots-start + sb-vm::nil-symbol-slots-end + sb-vm::static-space-objects-start)) + (record (c-symbol-name c) 7 #| arb |# c +c-literal-64bit+))) + ;; Sort by <priority, value, alpha> which is TOO COMPLICATED imho. + ;; Priority and then alphabetical would suffice. (setf constants (sort constants (lambda (const1 const2) - (if (= (second const1) (second const2)) - (if (= (third const1) (third const2)) + (if (= (second const1) (second const2)) ; priority + (if (= (third const1) (third const2)) ; value (string< (first const1) (first const2)) (< (third const1) (third const2))) (< (second const1) (second const2)))))) (let ((prev-priority (second (car constants)))) (dolist (const constants) - (destructuring-bind (name priority value suffix doc) const + (destructuring-bind (name priority value suffix) const (unless (= prev-priority priority) (terpri) (setf prev-priority priority)) (when (minusp value) (error "stub: negative values unsupported")) - (format t "#define ~A ~A~A /* 0x~X ~@[ -- ~A ~]*/~%" name value suffix value doc)))) + (format t "#define ~A ~A~A /* 0x~X */~%" name value suffix value)))) (terpri)) + ;; backend-page-bytes doesn't really mean much any more. + ;; It's the granularity at which we can map the core file pages. (format t "#define BACKEND_PAGE_BYTES ~D~%" sb-c:+backend-page-bytes+) - #+gencgc ; value never needed in Lisp, so therefore not a defconstant - (format t "#define GENCGC_CARD_SHIFT ~D~%" - (1- (integer-length sb-vm:gencgc-card-bytes))) + #+gencgc ; values never needed in Lisp, so therefore not a defconstant + (progn + (format t "#define MAX_CONSES_PER_PAGE ~D~%" sb-vm::max-conses-per-page) + (format t "#define CARDS_PER_PAGE ~D~%#define GENCGC_CARD_SHIFT ~D~%" + sb-vm::cards-per-page ; this is the "GC" page, not "backend" page + sb-vm::gencgc-card-shift)) (let ((size #+cheneygc (- sb-vm:dynamic-0-space-end sb-vm:dynamic-0-space-start) #+gencgc sb-vm::default-dynamic-space-size)) @@ -3024,6 +3227,10 @@ Legal values for OFFSET are -4, -8, -12, ..." (terpri) + #+(and win32 x86-64) + (format t "#define WIN64_SEH_DATA_ADDR ((void*)~DUL) /* ~:*0x~X */~%" + sb-vm:win64-seh-data-addr) + ;; FIXME: The SPARC has a PSEUDO-ATOMIC-TRAP that differs between ;; platforms. If we export this from the SB-VM package, it gets ;; written out as #define trap_PseudoAtomic, which is confusing as @@ -3097,6 +3304,9 @@ Legal values for OFFSET are -4, -8, -12, ..." (format stream "#define INTERNAL_ERROR_NARGS {~{~S~^, ~}}~2%" (map 'list #'cddr sb-c:+backend-internal-errors+))) +(eval-when (:compile-toplevel :load-toplevel :execute) + (import 'sb-vm::primitive-object-variable-length-p)) + (defun write-tagnames-h (out) (labels ((pretty-name (symbol strip) @@ -3105,36 +3315,41 @@ Legal values for OFFSET are -4, -8, -12, ..." (subseq name 0 (- (length name) (length strip)))))) (list-sorted-tags (tail) (loop for symbol being the external-symbols of "SB-VM" - when (and (constantp symbol) + when (and (cl:constantp symbol) (tailwise-equal (string symbol) tail)) collect symbol into tags finally (return (sort tags #'< :key #'symbol-value)))) (write-tags (visibility kind limit ash-count) + ;; KIND is the string "-LOWTAG" or "-WIDETAG" (format out "~%~Aconst char *~(~A~)_names[] = {~%" visibility (subseq kind 1)) (let ((tags (list-sorted-tags kind))) (dotimes (i limit) - (if (eql i (ash (or (symbol-value (first tags)) -1) ash-count)) - (format out " \"~A\"" (pretty-name (pop tags) kind)) - (format out " \"unknown [~D]\"" i)) + (let ((known (eql i (ash (or (symbol-value (first tags)) -1) ash-count)))) + (if known + (if (string= kind "-WIDETAG") + (format out " ~S" (sb-vm::widetag-string-name (pop tags))) + (format out " \"~A\"" (pretty-name (pop tags) kind))) + (format out " \"unknown [~D]\"" i))) (unless (eql i (1- limit)) (write-string "," out)) (terpri out))) (write-line "};" out))) + (format out "#include <stddef.h>~%") ; for NULL (write-tags "static " "-LOWTAG" sb-vm:lowtag-limit 0) ;; this -2 shift depends on every OTHER-IMMEDIATE-?-LOWTAG ;; ending with the same 2 bits. (#b10) (write-tags "" "-WIDETAG" (ash (1+ sb-vm:widetag-mask) -2) -2)) - (dolist (prim-obj '(symbol ratio complex sb-vm::code simple-fun - closure funcallable-instance - weak-pointer fdefn sb-vm::value-cell)) + (dolist (name '(symbol ratio complex sb-vm::code simple-fun + closure funcallable-instance + weak-pointer fdefn sb-vm::value-cell)) (format out "static char *~A_slots[] = {~%~{ \"~A: \",~} NULL~%};~%" - (c-name (string-downcase prim-obj)) - (mapcar (lambda (x) (c-name (string-downcase (sb-vm:slot-name x)))) - (remove-if 'sb-vm:slot-rest-p - (sb-vm:primitive-object-slots - (find prim-obj sb-vm:*primitive-objects* - :key 'sb-vm:primitive-object-name)))))) + (c-name (string-downcase name)) + (map 'list (lambda (x) (c-name (string-downcase (sb-vm:slot-name x)))) + (let* ((obj (sb-vm::primitive-object name)) + (slots (coerce (sb-vm:primitive-object-slots obj) 'list))) + (butlast slots + (if (primitive-object-variable-length-p obj) 1 0)))))) (values)) (defun write-c-print-dispatch (out) @@ -3151,9 +3366,40 @@ Legal values for OFFSET are -4, -8, -12, ..." (format out "static void (*~a_fns[])(lispobj obj) = {~ ~{~% ~a, ~a, ~a, ~a~^,~}~%};~%" flavor (coerce a 'list))))) -(defun write-cast-operator (name c-name lowtag) - (format t "static inline struct ~A* ~A(lispobj obj) { - return (struct ~A*)(obj - ~D);~%}~%" c-name name c-name lowtag)) +(defun write-cast-operator (operator-name c-name lowtag stream) + (format stream "static inline struct ~A* ~A(lispobj obj) { + return (struct ~A*)(obj - ~D);~%}~%" c-name operator-name c-name lowtag) + (case operator-name + (fdefn + (format stream "#define StaticSymbolFunction(x) FdefnFun(x##_FDEFN) +/* Return 'fun' given a tagged pointer to an fdefn. */ +static inline lispobj FdefnFun(lispobj fdefn) { return FDEFN(fdefn)->fun; }~%")) + (symbol + (format stream " +lispobj symbol_function(struct symbol* symbol); +#include \"~A/vector.h\" +struct vector *symbol_name(struct symbol*);~% +lispobj symbol_package(struct symbol*);~%" (genesis-header-prefix)) + (format stream "static inline int symbol_package_id(struct symbol* s) { return ~A; }~%" + #+compact-symbol (format nil "s->name >> ~D" sb-impl::symbol-name-bits) + #-compact-symbol "fixnum_value(s->package_id)") + #+compact-symbol + (progn (format stream "#define decode_symbol_name(ptr) (ptr & (uword_t)0x~X)~%" + (mask-field (byte sb-impl::symbol-name-bits 0) -1)) + (format stream "static inline void set_symbol_name(struct symbol*s, lispobj name) { + s->name = (s->name & (uword_t)0x~X) | name;~%}~%" + (mask-field (byte sb-impl::package-id-bits sb-impl::symbol-name-bits) -1))) + #-compact-symbol + (progn (format stream "#define decode_symbol_name(ptr) ptr~%") + (format stream "static inline void set_symbol_name(struct symbol*s, lispobj name) { + s->name = name;~%}~%"))))) + +(defun mangle-c-slot-name (obj-name slot-name) + ;; For data hiding purposes, change the name of vector->length to vector->length_. + ;; This helped me catch some erroneous C code. + (if (and (eq obj-name 'vector) (eq slot-name 'length)) + "length_" + (c-name (string-downcase slot-name)))) (defun write-primitive-object (obj *standard-output*) (let* ((name (sb-vm:primitive-object-name obj)) @@ -3161,41 +3407,71 @@ Legal values for OFFSET are -4, -8, -12, ..." (slots (sb-vm:primitive-object-slots obj)) (lowtag (or (symbol-value (sb-vm:primitive-object-lowtag obj)) 0))) ;; writing primitive object layouts - (format t "#ifndef __ASSEMBLER__~2%") - (when (eq name 'sb-vm::thread) - (format t "#define THREAD_HEADER_SLOTS ~d~%" sb-vm::thread-header-slots) - (dolist (x sb-vm::*thread-header-slot-names*) - (let ((s (package-symbolicate "SB-VM" "THREAD-" x "-SLOT"))) - (format t "#define ~a ~d~%" - (c-name (string s)) (symbol-value s)))) - (terpri)) - (format t "struct ~A {~%" c-name) - (when (sb-vm:primitive-object-widetag obj) - (format t " lispobj header;~%")) - (dolist (slot slots) - (format t " ~A ~A~@[[1]~];~%" - (getf (sb-vm:slot-options slot) :c-type "lispobj") - (c-name (string-downcase (sb-vm:slot-name slot))) - (sb-vm:slot-rest-p slot))) - (format t "};~%") - (when (member name '(cons vector symbol fdefn)) - (write-cast-operator name c-name lowtag)) - (format t "~%#else /* __ASSEMBLER__ */~2%") - (format t "/* These offsets are SLOT-OFFSET * N-WORD-BYTES - LOWTAG~%") - (format t " * so they work directly on tagged addresses. */~2%") - (dolist (slot slots) - (format t "#define ~A_~A_OFFSET ~D~%" - (c-symbol-name name) - (c-symbol-name (sb-vm:slot-name slot)) - (- (* (sb-vm:slot-offset slot) sb-vm:n-word-bytes) lowtag))) - (format t "#define ~A_SIZE ~d~%" - (string-upcase c-name) (sb-vm:primitive-object-length obj))) - (format t "~%#endif /* __ASSEMBLER__ */~2%")) - -(defun write-structure-object (dd *standard-output*) + (flet ((output-c () + (when (eq name 'sb-vm::code) + (format t "#define CODE_SLOTS_PER_SIMPLE_FUN ~d~2%" + sb-vm:code-slots-per-simple-fun)) + (when (eq name 'sb-vm::thread) + (format t "#define INIT_THREAD_REGIONS(x) \\~%") + (let ((tlabs (map 'list + (lambda (x) (c-name (string-downcase (second x)))) + (remove-if-not (lambda (x) + (tailwise-equal (string (second x)) "-TLAB")) + slots)))) + (format t "~{ gc_init_region(&x->~A)~^,\\~%~}~2%" tlabs)) + (when (find 'sb-vm::pseudo-atomic-bits slots :key #'sb-vm:slot-name) + (format t "#define HAVE_THREAD_PSEUDO_ATOMIC_BITS_SLOT 1~2%") + #+(or sparc ppc ppc64) (format t "typedef char pa_bits_t[~d];~2%" sb-vm:n-word-bytes) + #-(or sparc ppc ppc64) (format t "typedef lispobj pa_bits_t;~2%"))) + (format t "struct ~A {~%" c-name) + (when (sb-vm:primitive-object-widetag obj) + (format t " lispobj header;~%")) + (dovector (slot slots) + (format t " ~A ~A~@[[1]~];~%" + (getf (cddr slot) :c-type "lispobj") + (mangle-c-slot-name name (sb-vm:slot-name slot)) + (and (primitive-object-variable-length-p obj) + (eq slot (aref slots (1- (length slots))))))) + (format t "};~%") + (when (eq name 'vector) + ;; This is 'sword_t' because we formerly would call fixnum_value() which + ;; is a signed int, but it isn't really; except that I made all C vars + ;; signed to avoid comparison mismatch, and don't want to change back. + (format t "static inline sword_t vector_len(struct vector* v) {") + #+ubsan (format t " return v->header >> ~d; }~%" + (+ 32 sb-vm:n-fixnum-tag-bits)) + #-ubsan (format t " return v->length_ >> ~d; }~%" + sb-vm:n-fixnum-tag-bits)) + (when (member name '(cons vector symbol fdefn instance)) + (write-cast-operator name c-name lowtag *standard-output*))) + (output-asm () + (format t "/* These offsets are SLOT-OFFSET * N-WORD-BYTES - LOWTAG~%") + (format t " * so they work directly on tagged addresses. */~2%") + (dovector (slot slots) + (format t "#define ~A_~A_OFFSET ~D~%" + (c-symbol-name name) + (c-symbol-name (sb-vm:slot-name slot)) + (- (* (sb-vm:slot-offset slot) sb-vm:n-word-bytes) lowtag))) + (format t "#define ~A_SIZE ~d~%" + (string-upcase c-name) (sb-vm:primitive-object-length obj)))) + (when (eq name 'sb-vm::thread) + (format t "#define THREAD_HEADER_SLOTS ~d~%" sb-vm::thread-header-slots) + (dovector (x sb-vm::+thread-header-slot-names+) + (let ((s (package-symbolicate "SB-VM" "THREAD-" x "-SLOT"))) + (format t "#define ~a ~d~%" (c-name (string s)) (symbol-value s)))) + (terpri)) + (format t "#ifdef __ASSEMBLER__~2%") + (output-asm) + (format t "~%#else /* __ASSEMBLER__ */~2%") + (format t "#include ~S~%" (lispobj-dot-h)) + (output-c) + (format t "~%#endif /* __ASSEMBLER__ */~%")))) + +(defun write-structure-object (dd *standard-output* &optional structname) (flet ((cstring (designator) (c-name (string-downcase designator)))) (format t "#ifndef __ASSEMBLER__~2%") - (format t "struct ~A {~%" (cstring (dd-name dd))) + (format t "#include ~S~%" (lispobj-dot-h)) + (format t "struct ~A {~%" (or structname (cstring (dd-name dd)))) (format t " lispobj header; // = word_0_~%") ;; "self layout" slots are named '_layout' instead of 'layout' so that ;; classoid's expressly declared layout isn't renamed as a special-case. @@ -3210,38 +3486,40 @@ Legal values for OFFSET are -4, -8, -12, ..." (dolist (slot (dd-slots dd)) (let ((cell (aref names (- (dsd-index slot) sb-vm:instance-data-start))) (name (cstring (dsd-name slot)))) - (if (member (dsd-raw-type slot) '(t sb-vm:word sb-vm:signed-word)) - (rplaca cell name) - (rplacd cell name)))) + (case (dsd-raw-type slot) + ((t) (rplaca cell name)) + ;; remind C programmers which slots are untagged + (sb-vm:signed-word (rplaca cell (format nil "sw_~a" name))) + (sb-vm:word (rplaca cell (format nil "uw_~a" name))) + (t (rplacd cell name))))) (loop for slot across names - do (format t " lispobj ~A;~@[ // ~A~]~%" (car slot) (cdr slot)))) + do (format t " lispobj ~A;~@[ // ~A~]~%" + ;; reserved word + (if (string= (car slot) "default") "_default" (car slot)) + (cdr slot)))) (format t "};~%") - (when (member (dd-name dd) '(layout)) - (write-cast-operator (dd-name dd) (cstring (dd-name dd)) - sb-vm:instance-pointer-lowtag)) (format t "~%#endif /* __ASSEMBLER__ */~2%"))) (defun write-thread-init (stream) - (dolist (binding sb-vm::!per-thread-c-interface-symbols) + (dolist (binding sb-vm::per-thread-c-interface-symbols) (format stream "INITIALIZE_TLS(~A, ~A);~%" (c-symbol-name (if (listp binding) (car binding) binding) "*") - (if (listp binding) (second binding))))) + (let ((val (if (listp binding) (second binding)))) + (if (eq val 't) "LISP_T" val))))) (defun write-static-symbols (stream) (dolist (symbol (cons nil (coerce sb-vm:+static-symbols+ 'list))) - ;; FIXME: It would be nice to use longer names than NIL and - ;; (particularly) T in #define statements. (format stream "#define ~A LISPOBJ(0x~X)~%" ;; FIXME: It would be nice not to need to strip anything ;; that doesn't get stripped always by C-SYMBOL-NAME. - (c-symbol-name symbol "%*.!") + (if (eq symbol 't) "LISP_T" (c-symbol-name symbol "%*.!")) (if *static* ; if we ran GENESIS ;; We actually ran GENESIS, use the real value. (descriptor-bits (cold-intern symbol)) (+ sb-vm:nil-value (if symbol (sb-vm:static-symbol-offset symbol) 0))))) #+sb-thread - (dolist (binding sb-vm::!per-thread-c-interface-symbols) + (dolist (binding sb-vm::per-thread-c-interface-symbols) (let* ((symbol (car (ensure-list binding))) (c-symbol (c-symbol-name symbol "*"))) (unless (member symbol sb-vm::+common-static-symbols+) @@ -3250,10 +3528,12 @@ Legal values for OFFSET are -4, -8, -12, ..." (format stream "#define ~A_tlsindex 0x~X~%" c-symbol (ensure-symbol-tls-index symbol)))) ;; This #define is relative to the start of the fixedobj space to allow heap relocation. - #+immobile-space - (format stream "~@{#define LAYOUT_OF_~A (lispobj)(FIXEDOBJ_SPACE_START+0x~x)~%~}" - "FUNCTION" (- (cold-layout-descriptor-bits 'function) - (gspace-byte-address *immobile-fixedobj*))) + #+(or immobile-space metaspace) + (format stream "~@{#define LAYOUT_OF_~A (lispobj)(~A_SPACE_START+0x~x)~%~}" + "FUNCTION" + #+metaspace "READ_ONLY" #-metaspace "FIXEDOBJ" + (- (cold-layout-descriptor-bits 'function) + (gspace-byte-address (symbol-value *cold-layout-gspace*)))) ;; For immobile code, define a constant for the address of the vector of ;; C-callable fdefns, and then fdefns in terms of indices to that vector. #+immobile-code @@ -3274,7 +3554,7 @@ Legal values for OFFSET are -4, -8, -12, ..." (c-symbol-name symbol) (if *static* ; if we ran GENESIS ;; We actually ran GENESIS, use the real value. - (descriptor-bits (cold-fdefinition-object symbol)) + (descriptor-bits (ensure-cold-fdefn symbol)) ;; We didn't run GENESIS, so guess at the address. (+ sb-vm:nil-value (* (length sb-vm:+static-symbols+) @@ -3308,47 +3588,7 @@ Legal values for OFFSET are -4, -8, -12, ..." ;;; information is subject to change due to relocating GC, but even so ;;; it can be very handy when attempting to troubleshoot the early ;;; stages of cold load. -(defun write-map (*standard-output*) - (let ((*print-pretty* nil) - (*print-case* :upcase)) - (format t "Table of contents~%") - (format t "=================~%") - (let ((sections '("assembler routines" - "defined functions" - "undefined functions" - "classoids" - "layouts" - "type specifiers" - "symbols" - #+linkage-table "linkage table"))) - (dotimes (i (length sections)) - (format t "~4<~@R~>. ~A~%" (1+ i) (nth i sections)))) - (format t "=================~2%") - (format t "I. assembler routines defined in core image:~2%") - (dolist (routine *cold-assembler-routines*) - (let ((name (car routine))) - (format t "~8,'0X: ~S~%" (lookup-assembler-reference name) name))) - (let ((funs nil) - (undefs nil)) - (maphash (lambda (name fdefn &aux (fun (cold-fdefn-fun fdefn))) - (let ((fdefn-bits (descriptor-bits fdefn))) - (if (cold-null fun) - (push `(,fdefn-bits ,name) undefs) - (push `(,fdefn-bits ,(descriptor-bits fun) ,name) funs)))) - *cold-fdefn-objects*) - (format t "~%~|~%II.A. defined functions (alphabetically): - - FDEFN FUNCTION NAME -========== ========== ====~:{~%~10,'0X ~10,'0X ~S~}~%" - (sort (copy-list funs) #'string< - :key (lambda (x) (fun-name-block-name (caddr x))))) - (format t "~%~|~%II.B. defined functions (numerically): - - FDEFN FUNCTION NAME -========== ========== ====~:{~%~10,'0X ~10,'0X ~S~}~%" - (sort (copy-list funs) #'< :key #'second)) - - (format t "~%~| +(defparameter *boilerplate-text* " (a note about initially undefined function references: These functions are referred to by code which is installed by GENESIS, but they are not installed by GENESIS. This is not necessarily a problem; functions can @@ -3357,81 +3597,164 @@ loaded at warm init, or elsewhere. As long as they are defined before they are called, everything should be OK. Things are also OK if the cross-compiler knew their inline definition and used that everywhere that they were called before the out-of-line definition is installed, -as is fairly common for structure accessors.) +as is fairly common for structure accessors.)") + +(defun write-map (*standard-output* &aux (*print-pretty* nil) + (*print-case* :upcase)) + (format t "Table of contents~%") + (format t "=================~%") + (let ((sections '("assembler routines" "defined functions" "undefined functions" + "classoids" "layouts" + "packages" "symbols" + "type specifiers" + "linkage table" #+sb-thread "TLS map"))) + (dotimes (i (length sections)) + (format t "~4<~@R~>. ~A~%" (1+ i) (nth i sections)))) + (format t "=================~2%") + + (format t "I. assembler routines defined in core image: (base=~x)~2%" + (descriptor-bits *cold-assembler-obj*)) + (dolist (routine *cold-assembler-routines*) + (let ((name (car routine))) + (format t "~8,'0X: ~S~%" (lookup-assembler-reference name) name))) + + (let ((funs nil) (undefs nil)) + (maphash (lambda (name fdefn &aux (fun (cold-fdefn-fun fdefn))) + (let ((fdefn-bits (descriptor-bits fdefn))) + (if (cold-null fun) + (push `(,fdefn-bits ,name) undefs) + (push `(,fdefn-bits ,(descriptor-bits fun) ,name) funs)))) + *cold-fdefn-objects*) + (format t "~%~|~%II.A. defined functions (alphabetically): + + FDEFN FUNCTION NAME +========== ========== ====~:{~%~10,'0X ~10,'0X ~S~}~%" + (sort (copy-list funs) #'string< + :key (lambda (x) (fun-name-block-name (caddr x))))) + (format t "~%~|~%II.B. defined functions (numerically): + + FDEFN FUNCTION NAME +========== ========== ====~:{~%~10,'0X ~10,'0X ~S~}~%" + (sort (copy-list funs) #'< :key #'second)) + (format t "~%~|~A~% III. initially undefined function references (alphabetically): FDEFN NAME ========== ====~:{~%~10,'0X ~S~}~%" - (sort undefs - (lambda (a b &aux (pkg-a (package-name (sb-xc:symbol-package a))) - (pkg-b (package-name (sb-xc:symbol-package b)))) + *boilerplate-text* + (sort undefs + (lambda (a b &aux (pkg-a (sb-xc:package-name (sb-xc:symbol-package a))) + (pkg-b (sb-xc:package-name (sb-xc:symbol-package b)))) (cond ((string< pkg-a pkg-b) t) ((string> pkg-a pkg-b) nil) (t (string< a b)))) :key (lambda (x) (fun-name-block-name (cadr x)))))) - (format t "~%~|~%IV. classoids: + (format t "~%~|~%IV. classoids: CELL CLASSOID NAME ========== ========== ====~%") - - (dolist (x (sort (%hash-table-alist *classoid-cells*) #'string< :key #'car)) - (destructuring-bind (name . cell) x - (format t "~10,'0x ~:[ ~;~:*~10,'0X~] ~S~%" - (descriptor-bits cell) - (let ((classoid - (read-slot cell (find-layout 'sb-kernel::classoid-cell) :classoid))) - (unless (cold-null classoid) (descriptor-bits classoid))) - name))) - - (format t "~%~|~%V. layout names:~2%") - (dolist (pair (sort-cold-layouts)) - (let* ((descriptor (cold-layout-descriptor (cdr pair))) - (addr (descriptor-bits descriptor))) - (format t "~8,'0X: ~S[~D]~%" - addr (car pair) (cold-layout-length (cdr pair))))) - - (format t "~%~|~%VI. parsed type specifiers:~2%") - (mapc (lambda (cell) - (format t "~X: [~vx] ~S~%" - (descriptor-bits (cdr cell)) - (* 2 sb-vm:n-word-bytes) - (read-slot (cdr cell) 'sb-kernel:ctype :%bits) - (car cell))) - (sort (%hash-table-alist *ctype-cache*) #'< - :key (lambda (x) (descriptor-bits (cdr x)))))) + (let ((dumped-classoids)) + (dolist (x (sort (%hash-table-alist *classoid-cells*) #'string< :key #'car)) + (destructuring-bind (name . cell) x + (format t "~10,'0x ~:[ ~;~:*~10,'0X~] ~S~%" + (descriptor-bits cell) + (let ((classoid (read-slot cell :classoid))) + (unless (cold-null classoid) + (push classoid dumped-classoids) + (descriptor-bits classoid))) + name))) + ;; Things sometimes go wrong with dumped classoids, so show a memory dump too + (terpri) + (dolist (classoid dumped-classoids) + (let ((nwords (logand (ash (read-bits-wordindexed classoid 0) + (- sb-vm:instance-length-shift)) + sb-vm:instance-length-mask))) + (format t "Classoid @ ~x, ~d words:~%" (descriptor-bits classoid) (1+ nwords)) + (dotimes (i (1+ nwords)) ; include the header word in output + (format t "~2d: ~10x~%" i (read-bits-wordindexed classoid i))) + (terpri)))) + + (format t "~%~|~%V. layout names:~2%") + (format t "~28tBitmap Depth ID Name [Length]~%") + (dolist (pair (sort-cold-layouts)) + (let* ((proxy (cdr pair)) + (descriptor (cold-layout-descriptor proxy)) + (addr (descriptor-bits descriptor))) + (format t "~10,'0X -> ~10,'0X: ~8d ~2D ~5D ~S [~D]~%" + addr + #+metaspace (descriptor-bits (->wrapper descriptor)) + #-metaspace " " + (cold-layout-bitmap proxy) + (cold-layout-depthoid proxy) + (cold-layout-id proxy) + (car pair) + (cold-layout-length proxy)))) + + (format t "~%~|~%VI. packages:~2%") + (dolist (pair (sort (%hash-table-alist *cold-package-symbols*) #'< + :key (lambda (x) (descriptor-bits (cddr x))))) + (let ((pkg (cddr pair))) + (format t "~x = ~a (ID=~d)~%" (descriptor-bits pkg) (car pair) + (descriptor-fixnum (read-slot pkg :id))))) (format t "~%~|~%VII. symbols (numerically):~2%") - (mapc (lambda (cell) (format t "~X: ~S~%" (car cell) (cdr cell))) + (mapc (lambda (cell) + (let* ((addr (car cell)) + (host-sym (cdr cell)) + (val + (unless (or (keywordp host-sym) (null host-sym)) + (read-bits-wordindexed (cold-intern host-sym) + sb-vm:symbol-value-slot)))) + (format t "~X: ~S~@[ = ~X~]~%" addr host-sym + (unless (eql val sb-vm:unbound-marker-widetag) val)))) (sort (%hash-table-alist *cold-symbols*) #'< :key #'car)) - #+linkage-table - (progn - (format t "~%~|~%VIII. linkage table:~2%") - (dolist (entry (sort (sb-int:%hash-table-alist *cold-foreign-symbol-table*) - #'< :key #'cdr)) - (let ((name (car entry))) - (format t " ~:[ ~;(D)~] ~8x = ~a~%" - (listp name) - (sb-vm::linkage-table-entry-address (cdr entry)) - (car (ensure-list name)))))) + (format t "~%~|~%VIII. parsed type specifiers:~2%") + (format t " [Hash]~%") + (mapc (lambda (cell) + (format t "~X: [~vx] ~S~%" + (descriptor-bits (cdr cell)) + (* 2 sb-vm:n-word-bytes) + (read-slot (cdr cell) :%bits) + (car cell))) + (sort (%hash-table-alist *ctype-cache*) #'< + :key (lambda (x) (descriptor-bits (cdr x))))) + + (format t "~%~|~%IX. linkage table:~2%") + (dolist (entry (sort (sb-int:%hash-table-alist *cold-foreign-symbol-table*) + #'< :key #'cdr)) + (let ((name (car entry))) + (format t " ~:[ ~;(D)~] ~8x = ~a~%" + (listp name) + (sb-vm::alien-linkage-table-entry-address (cdr entry)) + (car (ensure-list name))))) + + #+sb-thread + (format t "~%~|~%X. TLS map:~2%~:{~4x ~s~%~}" + (sort *tls-index-to-symbol* #'< :key #'car)) (values)) ;;;; writing core file -(defun output-gspace (gspace data-page core-file write-word verbose) +(defun output-gspace (gspace data-page core-file verbose) (force-output core-file) (let* ((posn (file-position core-file)) - (bytes (* (gspace-free-word-index gspace) sb-vm:n-word-bytes)) - (pages (ceiling bytes sb-c:+backend-page-bytes+)) - (total-bytes (* pages sb-c:+backend-page-bytes+))) + (bytes (cond + #+metaspace + ((eq (gspace-identifier gspace) read-only-core-space-id) + (- sb-vm:read-only-space-end sb-vm:read-only-space-start)) + (t + (* (gspace-free-word-index gspace) sb-vm:n-word-bytes)))) + (page-count (ceiling bytes sb-c:+backend-page-bytes+)) + (total-bytes (* page-count sb-c:+backend-page-bytes+))) (file-position core-file (* sb-c:+backend-page-bytes+ (1+ data-page))) (when verbose (format t "writing ~S byte~:P [~S page~:P] from ~S~%" - total-bytes pages gspace)) + total-bytes page-count gspace)) ;; Note: It is assumed that the GSPACE allocation routines always ;; allocate whole pages (of size +backend-page-bytes+) and that any @@ -3446,133 +3769,109 @@ III. initially undefined function references (alphabetically): (force-output core-file) (file-position core-file posn) - ;; Write part of a (new) directory entry which looks like this: - ;; GSPACE IDENTIFIER - ;; WORD COUNT - ;; DATA PAGE - ;; ADDRESS - ;; PAGE COUNT - (funcall write-word (gspace-identifier gspace)) - (funcall write-word (gspace-free-word-index gspace)) - (funcall write-word data-page) - (funcall write-word (gspace-byte-address gspace)) - (funcall write-word pages) + ;; Write the directory entry. + (write-words core-file (gspace-identifier gspace) (gspace-free-word-index gspace) + data-page (gspace-byte-address gspace) page-count) - (+ data-page pages))) + (+ data-page page-count))) #+gencgc -(defun output-page-table (gspace data-page core-file write-word verbose) +(defun output-page-table (gspace data-page core-file verbose) ;; Write as many PTEs as there are pages used. - ;; A corefile PTE is { uword_t scan_start_offset; page_bytes_t bytes_used; } + ;; A corefile PTE is { uword_t scan_start_offset; page_words_t words_used; } (let* ((data-bytes (* (gspace-free-word-index gspace) sb-vm:n-word-bytes)) - (n-ptes (ceiling data-bytes sb-vm:gencgc-card-bytes)) - (sizeof-usage ; see similar expression in 'src/code/room' - (if (typep sb-vm:gencgc-card-bytes '(unsigned-byte 16)) 2 4)) - (sizeof-corefile-pte (+ sb-vm:n-word-bytes sizeof-usage)) + (n-ptes (ceiling data-bytes sb-vm:gencgc-page-bytes)) + (sizeof-corefile-pte (+ sb-vm:n-word-bytes 2)) (pte-bytes (round-up (* sizeof-corefile-pte n-ptes) sb-vm:n-word-bytes)) (n-code 0) + (n-cons 0) (n-mixed 0) (ptes (make-bigvec))) (expand-bigvec ptes pte-bytes) (dotimes (page-index n-ptes) (let* ((pte-offset (* page-index sizeof-corefile-pte)) (pte (aref (gspace-page-table gspace) page-index)) - (usage (page-bytes-used pte)) + (usage (page-words-used pte)) (sso (if (plusp usage) - (- (* page-index sb-vm:gencgc-card-bytes) + (- (* page-index sb-vm:gencgc-page-bytes) (* (page-scan-start pte) sb-vm:n-word-bytes)) 0)) (type-bits (if (plusp usage) (ecase (page-type pte) - (:code (incf n-code) #b11) - (:mixed (incf n-mixed) #b01)) + (:code (incf n-code) #b111) + (:list (incf n-cons) #b101) + (:mixed (incf n-mixed) #b011)) 0))) - (setf (bvref-word ptes pte-offset) (logior sso type-bits)) - (macrolet ((setter () - ;; KLUDGE to avoid compiler note about one or the other - ;; branch of this IF being unreachable. - (declare (notinline typep)) - (if (typep sb-vm:gencgc-card-bytes '(unsigned-byte 16)) - '#'(setf bvref-16) - '#'(setf bvref-32)))) - (funcall (setter) usage ptes (+ pte-offset sb-vm:n-word-bytes))))) + (setf (bvref-word-unaligned ptes pte-offset) (logior sso type-bits)) + (setf (bvref-16 ptes (+ pte-offset sb-vm:n-word-bytes)) usage))) (when verbose - (format t "movable dynamic space: ~d boxed pages, ~d code pages~%" n-mixed n-code)) + (format t "movable dynamic space: ~d + ~d + ~d cons/code/mixed pages~%" + n-cons n-code n-mixed)) (force-output core-file) (let ((posn (file-position core-file))) (file-position core-file (* sb-c:+backend-page-bytes+ (1+ data-page))) (write-bigvec-as-sequence ptes core-file :end pte-bytes) (force-output core-file) (file-position core-file posn)) - (mapc write-word ; 5 = number of words in this core header entry - `(,page-table-core-entry-type-code 5 ,n-ptes ,pte-bytes ,data-page)))) + (write-words core-file + page-table-core-entry-type-code + 6 ; = number of words in this core header entry + sb-vm::gencgc-card-table-index-nbits + n-ptes pte-bytes data-page))) ;;; Create a core file created from the cold loaded image. (This is ;;; the "initial core file" because core files could be created later -;;; by executing SAVE-LISP in a running system, perhaps after we've +;;; by executing SAVE-LISP-AND-DIE in a running system, perhaps after we've ;;; added some functionality to the system.) -(defun write-initial-core-file (filename verbose) - +(defun write-initial-core-file (filename build-id verbose) (when verbose (let ((*print-length* nil) (*print-level* nil)) (format t "~&SB-XC:*FEATURES* =~&~S~%" sb-xc:*features*)) (format t "[building initial core file in ~S: ~%" filename)) - (with-open-file (core-file (namestring filename) ; why NAMESTRING? dunno - :direction :output - :element-type '(unsigned-byte 8) - :if-exists :rename-and-delete) - (let ((bv (%make-bigvec)) - (data-page 0)) - (flet ((write-word (word) - (setf (bvref-word bv 0) (the sb-vm:word word)) - (write-sequence (elt (bigvec-outer-vector bv) 0) core-file - :start 0 :end sb-vm:n-word-bytes))) + (with-open-file (core-file filename :direction :output + :element-type '(unsigned-byte 8) + :if-exists :rename-and-delete) + (let ((data-page 0)) ;; Write the magic number. - (write-word core-magic) + (write-words core-file core-magic) ;; Write the build ID, which contains a generated string ;; plus a suffix identifying a certain configuration of the C compiler. (binding* ((build-id (concatenate 'string - (with-open-file (s "output/build-id.inc") (read s)) + (or build-id + (with-open-file (s "output/build-id.inc") (read s))) (if (member :msan sb-xc:*features*) "-msan" ""))) ((nwords padding) (ceiling (length build-id) sb-vm:n-word-bytes))) (declare (type simple-string build-id)) ;; Write BUILD-ID-CORE-ENTRY-TYPE-CODE, the length of the header, ;; length of the string, then base string chars + maybe padding. - (write-word build-id-core-entry-type-code) - (write-word (+ 3 nwords)) ; 3 = fixed overhead including this word - (write-word (length build-id)) - (dovector (char build-id) (write-byte (sb-xc:char-code char) core-file)) + (write-words core-file build-id-core-entry-type-code + (+ 3 nwords) ; 3 = fixed overhead including this word + (length build-id)) + (dovector (char build-id) (write-byte (char-code char) core-file)) (dotimes (j (- padding)) (write-byte #xff core-file))) ;; Write the Directory entry header. - (write-word directory-core-entry-type-code) - (let ((spaces (nconc (list *read-only* *static*) - #+immobile-space - (list *immobile-fixedobj* *immobile-varyobj*) - (list *dynamic*)))) + (write-words core-file directory-core-entry-type-code) + (let ((spaces `(,*static* + #+immobile-space ,@`(,*immobile-fixedobj* ,*immobile-text*) + ,*dynamic* ,*read-only*))) ;; length = (5 words/space) * N spaces + 2 for header. - (write-word (+ (* (length spaces) 5) 2)) + (write-words core-file (+ (* (length spaces) 5) 2)) (dolist (space spaces) - (setq data-page (output-gspace space data-page - core-file #'write-word verbose)))) - #+gencgc (output-page-table *dynamic* data-page - core-file #'write-word verbose) + (setq data-page (output-gspace space data-page core-file verbose)))) + #+gencgc (output-page-table *dynamic* data-page core-file verbose) ;; Write the initial function. - (write-word initial-fun-core-entry-type-code) - (write-word 3) (let ((initial-fun (descriptor-bits (cold-symbol-function '!cold-init)))) - (when verbose - (format t "~&/INITIAL-FUN=#X~X~%" initial-fun)) - (write-word initial-fun)) + (when verbose (format t "~&/INITIAL-FUN=#X~X~%" initial-fun)) + (write-words core-file initial-fun-core-entry-type-code 3 initial-fun)) ;; Write the End entry. - (write-word end-core-entry-type-code) - (write-word 2)))) + (write-words core-file end-core-entry-type-code 2))) (when verbose (format t "done]~%") @@ -3597,11 +3896,16 @@ III. initially undefined function references (alphabetically): ;;; CORE-FILE-NAME gets a Lisp core. ;;; C-HEADER-DIR-NAME gets the path in which to place generated headers ;;; MAP-FILE-NAME gets the name of the textual 'cold-sbcl.map' file +;;; LINKAGE-TABLE-PREFILL-INFO-C-NAME gets a .c file used to store the +;;; data used to link the runtime before entering Lisp. (defun sb-cold:genesis (&key object-file-names tls-init defstruct-descriptions + build-id core-file-name c-header-dir-name map-file-name - symbol-table-file-name (verbose t)) - (declare (ignorable symbol-table-file-name)) + symbol-table-file-name (verbose t) + linkage-table-prefill-info-c-name + extra-linkage-table-entries) + (declare (ignorable symbol-table-file-name linkage-table-prefill-info-c-name)) (when verbose (format t @@ -3618,12 +3922,10 @@ III. initially undefined function references (alphabetically): ;; Prefill some linkage table entries perhaps (loop for (name datap) in sb-vm::*linkage-space-predefined-entries* - do (linkage-table-note-symbol name datap)) - #-(or linkage-table crossbuild-test) - (when core-file-name - (if symbol-table-file-name - (load-cold-foreign-symbol-table symbol-table-file-name) - (error "can't output a core file without symbol table file input"))) + do (alien-linkage-table-note-symbol name datap)) + (loop for (name datap undefinedp) in extra-linkage-table-entries + unless undefinedp + do (alien-linkage-table-note-symbol name datap)) ;; Now that we've successfully read our only input file (by ;; loading the symbol table, if any), it's a good time to ensure @@ -3659,9 +3961,10 @@ III. initially undefined function references (alphabetically): immobile-fixedobj-core-space-id sb-vm:fixedobj-space-start)) #+immobile-space - (*immobile-varyobj* (make-gspace :immobile-varyobj - immobile-varyobj-core-space-id - sb-vm:varyobj-space-start)) + (*immobile-text* (make-gspace :immobile-text + immobile-text-core-space-id + sb-vm:text-space-start + :objects (make-array 20000 :fill-pointer 0 :adjustable t))) (*dynamic* (make-gspace :dynamic dynamic-core-space-id #+gencgc sb-vm:dynamic-space-start @@ -3669,14 +3972,11 @@ III. initially undefined function references (alphabetically): (*nil-descriptor*) (*simple-vector-0-descriptor*) (*c-callable-fdefn-vector*) - (*known-structure-classoids* nil) - (*layout-deferred-instances* (make-hash-table :test 'eq)) (*classoid-cells* (make-hash-table :test 'eq)) (*ctype-cache* (make-hash-table :test 'equal)) (*cold-layouts* (make-hash-table :test 'eq)) ; symbol -> cold-layout - (*cold-layout-names* (make-hash-table :test 'eql)) ; addr -> symbol - (*!cold-defsymbols* nil) - (*!cold-defuns* nil) + (*cold-layout-by-addr* (make-hash-table :test 'eql)) ; addr -> cold-layout + (*tls-index-to-symbol* nil) ;; '*COLD-METHODS* is never seen in the target, so does not need ;; to adhere to the #\! convention for automatic uninterning. (*cold-methods* nil) @@ -3685,24 +3985,25 @@ III. initially undefined function references (alphabetically): *cold-assembler-routines* *cold-assembler-obj* *deferred-undefined-tramp-refs* - (*code-fixup-notes* (make-hash-table)) - (*allocation-point-fixup-notes* nil) (*deferred-known-fun-refs* nil)) - (setf *nil-descriptor* (make-nil-descriptor) - *simple-vector-0-descriptor* (vector-in-core nil)) + (make-nil-descriptor) + (setf *simple-vector-0-descriptor* (vector-in-core nil)) + (when core-file-name + (read-structure-definitions defstruct-descriptions)) ;; Prepare for cold load. (initialize-layouts) - (when core-file-name - (read-structure-definitions defstruct-descriptions) - (initialize-packages)) (initialize-static-space tls-init) + (cold-set 'sb-c::*!cold-allocation-patch-point* *nil-descriptor*) ;; Load all assembler code (flet ((assembler-file-p (name) (tailwise-equal (namestring name) ".assem-obj"))) - (dolist (file-name (remove-if-not #'assembler-file-p object-file-names)) - (cold-load file-name verbose)) + (let ((files (remove-if-not #'assembler-file-p object-file-names))) + ;; There should be exactly 1 assembler file, and 1 code object in it. + (when files ; But it's present only in 2nd genesis. + (aver (singleton-p files)) + (cold-load (car files) verbose))) (setf object-file-names (remove-if #'assembler-file-p object-file-names))) (mapc 'funcall *deferred-undefined-tramp-refs*) (makunbound '*deferred-undefined-tramp-refs*) @@ -3716,21 +4017,14 @@ III. initially undefined function references (alphabetically): (cold-cons z z (ecase (gspace-name (descriptor-gspace *cold-assembler-obj*)) ((:read-only :static) *static*) - (:immobile-varyobj *dynamic*))))) + (:immobile-text *dynamic*))))) (init-runtime-routines)) ;; Initialize the *COLD-SYMBOLS* system with the information - ;; from common-lisp-exports.lisp-expr. - ;; Packages whose names match SB-THING were set up on the host according - ;; to "package-data-list.lisp-expr" which expresses the desired target - ;; package configuration, so we can just mirror the host into the target. - ;; But by waiting to observe calls to COLD-INTERN that occur during the - ;; loading of the cross-compiler's outputs, it is possible to rid the - ;; target of accidental leftover symbols, not that it wouldn't also be - ;; a good idea to clean up package-data-list once in a while. - (dolist (exported-name - (sb-cold:read-from-file "common-lisp-exports.lisp-expr")) - (cold-intern (intern exported-name *cl-package*) :access :external)) + ;; from XC-STRICT-CL. + (do-external-symbols (symbol (find-package "XC-STRICT-CL")) + (cold-intern (intern (symbol-name symbol) *cl-package*) + :access :external)) ;; Make LOGICALLY-READONLYIZE no longer a no-op (setf (symbol-function 'logically-readonlyize) @@ -3738,68 +4032,28 @@ III. initially undefined function references (alphabetically): ;; Cold load. (dolist (file-name object-file-names) + (push (cold-cons :begin-file (string-literal-to-core file-name)) + *!cold-toplevels*) (cold-load file-name verbose)) (sb-cold::check-no-new-cl-symbols) - (when *known-structure-classoids* - (let ((dd-layout (find-layout 'defstruct-description))) - (dolist (defstruct-args *known-structure-classoids*) - (let* ((dd (first defstruct-args)) - (name (warm-symbol (read-slot dd dd-layout :name))) - (layout (gethash name *cold-layouts*))) - (aver layout) - (write-slots (cold-layout-descriptor layout) *host-layout-of-layout* - :info dd)))) - (when verbose - (format t "~&; SB-Loader: (~D~@{+~D~}) structs/vars/funs/methods/other~%" - (length *known-structure-classoids*) - (length *!cold-defsymbols*) - (length *!cold-defuns*) - (reduce #'+ *cold-methods* :key (lambda (x) (length (cdr x)))) - (length *!cold-toplevels*)))) - - (dolist (symbol '(*!cold-defsymbols* *!cold-defuns* *!cold-toplevels*)) - (cold-set symbol (list-to-core (nreverse (symbol-value symbol)))) - (makunbound symbol)) ; so no further PUSHes can be done - - ;;; Order all trivial methods so that the first one whose guard - ;;; returns T is the most specific method. LAYOUT-DEPTHOID is a valid - ;;; sort key for this because we don't have multiple inheritance in - ;;; the system object type lattice. - (cold-set - 'sb-pcl::*!trivial-methods* - (list-to-core - (loop for (gf-name . methods) in *cold-methods* - collect - (cold-cons - (cold-intern gf-name) - (vector-in-core - (loop for (class qual lambda-list fun source-loc) - ;; Methods must be sorted because we invoke - ;; only the first applicable one. - in (stable-sort methods #'> ; highest depthoid first - :key (lambda (method) - (class-depthoid (car method)))) - collect - (vector-in-core - (list (cold-intern - (and (null qual) (predicate-for-specializer class))) - (cold-intern qual) - (cold-intern class) - fun - lambda-list source-loc)))))))) + (when (and verbose core-file-name) + (format t "~&; SB-Loader: (~D~@{+~D~}) methods/other~%" + (reduce #'+ *cold-methods* :key (lambda (x) (length (cdr x)))) + (length *!cold-toplevels*))) + + (cold-set '*!cold-toplevels* (list-to-core (nreverse *!cold-toplevels*))) + (makunbound '*!cold-toplevels*) ; so no further PUSHes can be done ;; Tidy up loose ends left by cold loading. ("Postpare from cold load?") + (sort-initial-methods) (resolve-deferred-known-funs) (resolve-static-call-fixups) (foreign-symbols-to-core) - #+(or x86 immobile-space) - (dolist (pair (sort (%hash-table-alist *code-fixup-notes*) #'< :key #'car)) - (write-wordindexed (make-random-descriptor (car pair)) - sb-vm::code-fixups-slot (repack-fixups (cdr pair)))) - (cold-set 'sb-c::*!cold-allocation-point-fixups* - (vector-in-core *allocation-point-fixup-notes*)) + #+sb-prelink-linkage-table + (when linkage-table-prefill-info-c-name + (foreign-symbols-to-c linkage-table-prefill-info-c-name)) (when core-file-name (finish-symbols)) (finalize-load-time-value-noise) @@ -3830,31 +4084,90 @@ III. initially undefined function references (alphabetically): (with-open-file (stream map-file-name :direction :output :if-exists :supersede) (write-map stream))) (when core-file-name - (write-initial-core-file core-file-name verbose)) + (write-initial-core-file core-file-name build-id verbose)) (unless c-header-dir-name (return-from sb-cold:genesis)) (let ((filename (format nil "~A/Makefile.features" c-header-dir-name))) (ensure-directories-exist filename) (with-open-file (stream filename :direction :output :if-exists :supersede) (write-makefile-features stream))) + (write-c-headers c-header-dir-name)))) - (macrolet ((out-to (name &body body) ; write boilerplate and inclusion guard - (let ((headerp (if (and (stringp name) (position #\. name)) nil ".h"))) - `(with-open-file (stream (format nil "~A/~A~@[~A~]" - c-header-dir-name ,name ,headerp) - :direction :output :if-exists :supersede) - (write-boilerplate stream) - ,(when headerp - `(format stream - "#ifndef SBCL_GENESIS_~A~%#define SBCL_GENESIS_~:*~A~%" - (c-name (string-upcase ,name)))) - ,@body - ,(when headerp `(format stream "#endif~%")))))) +#+gencgc +(defun write-mark-array-operators (stream &optional (ncards sb-vm::cards-per-page)) + #-soft-card-marks + (progn + (aver (= ncards 1)) + (format stream "static inline int cardseq_all_marked_nonsticky(long card) { + return gc_card_mark[card] == CARD_MARKED;~%}~%") + (format stream "static inline int cardseq_any_marked(long card) { + return gc_card_mark[card] != CARD_UNMARKED;~%}~%") + (format stream "static inline int cardseq_any_sticky_mark(long card) { + return gc_card_mark[card] == STICKY_MARK;~%}~%")) + #+soft-card-marks + ;; In general we have to be wary of wraparound of the card index bits + ;; - see example in comment above the definition of addr_to_card_index() - + ;; but it's OK to treat marks as linearly addressable within a page. + ;; The 'card' argument as supplied to these predicates will be + ;; a page-aligned card, i.e. the first card for its page. + (let* ((n-markwords + ;; This is how many words (of N_WORD_BYTES) of marks there are for the + ;; cards on a page. + (cond ((and (= sb-vm:n-word-bytes 8) (= ncards 32)) 4) + ((and (= sb-vm:n-word-bytes 8) (= ncards 16)) 2) + ((and (= sb-vm:n-word-bytes 8) (= ncards 8)) 1) + ((and (= sb-vm:n-word-bytes 4) (= ncards 8)) 2) + (t (error "bad cards-per-page")))) + (indices (loop for i below n-markwords collect i))) + (format stream "static inline int cardseq_all_marked_nonsticky(long card) { + uword_t* mark = (uword_t*)&gc_card_mark[card]; + return (~{mark[~d]~^ | ~}) == 0;~%}~%" indices) + (format stream "static inline int cardseq_any_marked(long card) { + uword_t* mark = (uword_t*)&gc_card_mark[card]; + return (~{mark[~d]~^ & ~}) != (uword_t)-1;~%}~%" indices) + (format stream "static inline int cardseq_any_sticky_mark(long card) { + uword_t* mark = (uword_t*)&gc_card_mark[card]; + return ~{word_has_stickymark(mark[~d])~^ || ~};~%}~%" indices))) + +(defun write-c-headers (c-header-dir-name) + (macrolet ((out-to (name &body body) ; write boilerplate and inclusion guard + `(actually-out-to ,name (lambda (stream) ,@body)))) + (flet ((actually-out-to (name lambda) + ;; A file gets a '.inc' extension, not '.h' for either or both + ;; of two reasons: + ;; - if it isn't self-contained, meaning that in order to #include it, + ;; the consumer of it has to know something about which other headers + ;; need to be #included first. + ;; - it is not intended to be directly consumed because any use would + ;; typically need to wrap each slot in some small calculation + ;; such as native_pointer(), but we don't want to embed the wrapper + ;; accessors into the autogenerated header. So there would instead be + ;; a "src/runtime/foo.h" which includes "src/runtime/genesis/foo.inc" + ;; 'thread.h' and 'gc-tables.h' violate the naming convention + ;; by being non-self-contained. + (let* ((extension + (cond ((and (stringp name) (position #\. name)) nil) + (t ".h"))) + (inclusion-guardp + (string= extension ".h"))) + (with-open-file (stream (format nil "~A/~A~@[~A~]" + c-header-dir-name name extension) + :direction :output :if-exists :supersede) + (write-boilerplate stream) + (when inclusion-guardp + (format stream + "#ifndef SBCL_GENESIS_~A~%#define SBCL_GENESIS_~:*~A~%" + (c-name (string-upcase name)))) + (funcall lambda stream) + (when inclusion-guardp + (format stream "#endif~%")))))) (out-to "config" (write-config-h stream)) (out-to "constants" (write-constants-h stream)) (out-to "regnames" (write-regnames-h stream)) (out-to "errnames" (write-errnames-h stream)) (out-to "gc-tables" (sb-vm::write-gc-tables stream)) + #+soft-card-marks + (out-to "cardmarks" (write-mark-array-operators stream)) (out-to "tagnames" (write-tagnames-h stream)) (out-to "print.inc" (write-c-print-dispatch stream)) (let ((structs (sort (copy-list sb-vm:*primitive-objects*) #'string< @@ -3866,22 +4179,45 @@ III. initially undefined function references (alphabetically): (dolist (obj structs) (format stream "~&#include \"~A.h\"~%" (string-downcase (sb-vm:primitive-object-name obj)))))) - (dolist (class '(classoid defstruct-description hash-table layout package - sb-thread::avlnode + (out-to "layout" + #-metaspace + (write-structure-object (wrapper-info (find-layout 'wrapper)) stream + "layout") + #+metaspace + (progn + (write-structure-object (wrapper-info (find-layout 'sb-vm:layout)) stream) + (write-structure-object (wrapper-info (find-layout 'wrapper)) stream) + (write-cast-operator 'wrapper "wrapper" sb-vm:instance-pointer-lowtag stream)) + (write-cast-operator 'layout "layout" sb-vm:instance-pointer-lowtag stream)) + ;; For purposes of the C code, cast all hash tables as general_hash_table + ;; even if they lack the slots for weak tables. + (out-to "hash-table" + (write-structure-object (wrapper-info (find-layout 'sb-impl::general-hash-table)) + stream "hash_table")) + (dolist (class '(defstruct-description defstruct-slot-description + classoid + package + sb-thread::avlnode sb-thread::mutex sb-c::compiled-debug-info sb-c::compiled-debug-fun)) (out-to (string-downcase class) - (write-structure-object (layout-info (find-layout class)) stream))) + (write-structure-object (wrapper-info (find-layout class)) + stream))) + (out-to "thread-instance" + (write-structure-object (wrapper-info (find-layout 'sb-thread::thread)) + stream "thread_instance")) (with-open-file (stream (format nil "~A/thread-init.inc" c-header-dir-name) :direction :output :if-exists :supersede) (write-boilerplate stream) ; no inclusion guard, it's not a ".h" file (write-thread-init stream)) (out-to "static-symbols" (write-static-symbols stream)) - (out-to "sc-offset" (write-sc+offset-coding stream)))))) + (out-to "sc-offset" (write-sc+offset-coding stream))))) ;;; Invert the action of HOST-CONSTANT-TO-CORE. If STRICTP is given as NIL, ;;; then we can produce a host object even if it is not a faithful rendition. (defun host-object-from-core (descriptor &optional (strictp t)) (named-let recurse ((x descriptor)) + (when (symbolp x) + (return-from recurse x)) (when (cold-null x) (return-from recurse nil)) (when (is-fixnum-lowtag (descriptor-lowtag x)) @@ -3910,8 +4246,7 @@ III. initially undefined function references (alphabetically): (if strictp (warm-symbol x) (or (gethash (descriptor-bits x) *cold-symbols*) ; first try - (make-symbol - (recurse (read-wordindexed x sb-vm:symbol-name-slot)))))) + (make-symbol (read-cold-symbol-name x))))) (#.sb-vm:simple-base-string-widetag (base-string-from-core x)) (#.sb-vm:simple-vector-widetag (vector-from-core x #'recurse)) #-64-bit @@ -3920,3 +4255,10 @@ III. initially undefined function references (alphabetically): (#.sb-vm:double-float-widetag (double-float-from-core x)) (#.sb-vm:bignum-widetag (bignum-from-core x)))))))) + +;;; This is for FOP-SPEC-VECTOR which always supplies 0 for the start +(defun read-n-bytes (stream vector start nbytes) + (aver (zerop start)) + (let ((start (+ (descriptor-byte-offset vector) + (ash sb-vm:vector-data-offset sb-vm:word-shift)))) + (read-into-bigvec (descriptor-mem vector) stream start nbytes))) diff --git a/src/compiler/generic/interr.lisp b/src/compiler/generic/interr.lisp index 24be59b11f..867b5766fc 100644 --- a/src/compiler/generic/interr.lisp +++ b/src/compiler/generic/interr.lisp @@ -55,9 +55,10 @@ (type-specifier (specifier-type `(simple-array ,(sb-vm:saetp-specifier saetp) (*))))) - (remove t sb-vm:*specialized-array-element-type-properties* - :key 'sb-vm:saetp-specifier)))) - `(((integer 0 ,sb-xc:array-dimension-limit) + (remove-if (lambda (x) (member x '(nil t))) + sb-vm:*specialized-array-element-type-properties* + :key 'sb-vm:saetp-specifier)))) + `(((mod ,(1+ array-dimension-limit)) object-not-array-dimension) ;; Union of all unboxed array specializations, ;; for type-checking the argument to VECTOR-SAP @@ -72,16 +73,20 @@ ;; Error number must be of type (unsigned-byte 8). (assert (<= (length list) 256)) `(defconstant-eqx sb-c:+backend-internal-errors+ - ,(map 'vector - (lambda (x) + ,(map 'vector + (lambda (x) + (flet ((normalize-type (type) + (if (stringp type) + type + (type-specifier (specifier-type type))))) (if (symbolp x) - (list* x (symbolicate "OBJECT-NOT-" x "-ERROR") 1) - (list* (car x) (symbolicate (second x) "-ERROR") + (list* (normalize-type x) (symbolicate "OBJECT-NOT-" x "-ERROR") 1) + (list* (normalize-type (car x)) (symbolicate (second x) "-ERROR") (if (stringp (car x)) (third x) - 1)))) - list) - #'equalp)))) + 1))))) + list) + #'equalp)))) (compute-it ;; Keep the following two subsets of internal errors in this order: ;; @@ -109,13 +114,18 @@ ("odd number of &KEY arguments" odd-key-args 0) ("unknown &KEY argument" unknown-key-arg 1) ("invalid array index" invalid-array-index 3) + ("invalid vector index" invalid-vector-index 2) + ("uninitialized element" uninitialized-element 2) ("A function with declared result type NIL returned." nil-fun-returned 1) ("An array with element-type NIL was accessed." nil-array-accessed 1) ("Object layout is invalid. (indicates obsolete instance)" layout-invalid 2) ("Thread local storage exhausted." tls-exhausted 0) ("Unreachable code reached" unreachable 0) - ("Failed aver" failed-aver 1)) - + ("Failed aver" failed-aver 1) + ("Multiplication overflow" mul-overflow 2) + ("Addition overflow" add-sub-overflow 1) + #+x86-64 + ("Subtraction overflow" sub-overflow 1)) ;; (II) All the type specifiers X for which there is a unique internal ;; error code corresponding to a primitive object-not-X-error. function @@ -185,7 +195,7 @@ sb-c::vop sb-c::basic-combination sb-sys:fd-stream - layout + wrapper (sb-assem:segment object-not-assem-segment) sb-c::cblock sb-disassem:disassem-state @@ -231,20 +241,3 @@ (if (array-in-bounds-p sb-c:+backend-internal-errors+ error-number) (cddr (svref sb-c:+backend-internal-errors+ error-number)) 0)) - -#-sb-xc-host ; no SB-C:SAP-READ-VAR-INTEGERF -(defun decode-internal-error-args (sap trap-number &optional error-number) - (let ((error-number (cond (error-number) - ((>= trap-number sb-vm:error-trap) - (prog1 - (- trap-number sb-vm:error-trap) - (setf trap-number sb-vm:error-trap))) - (t - (prog1 (sap-ref-8 sap 0) - (setf sap (sap+ sap 1))))))) - (let ((length (sb-kernel::error-length error-number))) - (declare (type (unsigned-byte 8) length)) - (values error-number - (loop repeat length with index = 0 - collect (sb-c:sap-read-var-integerf sap index)) - trap-number)))) diff --git a/src/compiler/generic/late-objdef.lisp b/src/compiler/generic/late-objdef.lisp index 68d28c031e..c1eff84fd0 100644 --- a/src/compiler/generic/late-objdef.lisp +++ b/src/compiler/generic/late-objdef.lisp @@ -14,35 +14,33 @@ #-c-headers-only (macrolet ((frob () `(progn ,@*!late-primitive-object-forms*))) - (frob) - (defknown symbol-extra (t) t (flushable)) - (def-reffer 'symbol-extra symbol-size other-pointer-lowtag) - (defknown (setf symbol-extra) (t t) t ()) - (def-setter '(setf symbol-extra) symbol-size other-pointer-lowtag)) - -(defconstant extended-symbol-size (1+ symbol-size)) + (frob)) #+sb-thread -(dolist (slot (primitive-object-slots - (find 'thread *primitive-objects* :key #'primitive-object-name))) +(dovector (slot (primitive-object-slots (primitive-object 'thread))) (when (slot-special slot) (setf (info :variable :wired-tls (slot-special slot)) (ash (slot-offset slot) word-shift)))) #+gencgc -(defconstant large-object-size - (* 4 (max +backend-page-bytes+ gencgc-card-bytes - gencgc-alloc-granularity))) - +(progn +;;; don't change allocation granularity +(assert (= gencgc-alloc-granularity 0)) +;;; cards are not larger than pages +(assert (<= gencgc-page-bytes +backend-page-bytes+)) +;;; largeness does not depend on the hardware page size +(defconstant large-object-size (* 4 gencgc-page-bytes))) ;;; Keep this (mostly) lined up with 'early-objdef' for sanity's sake! +;;; The "transport" function is used only if the object is an OTHER-POINTER +;;; (which goes through the dispatch table). #+sb-xc-host (defparameter *scav/trans/size* (mapcar (lambda (entry) (cons (symbol-value (symbolicate (car entry) "-WIDETAG")) (cdr entry))) - `((bignum "unboxed" "bignum" "bignum") + `((bignum "bignum") (ratio "boxed" "ratio_or_complex" "boxed") (single-float ,(or #+64-bit "immediate" "unboxed")) (double-float "unboxed") @@ -50,42 +48,38 @@ (complex-single-float "unboxed") (complex-double-float "unboxed") - (code-header "code_header") - ;; For all 3 function subtypes, the transporter is "lose" - ;; because functions are not OTHER pointer objects. - ;; The scavenge function for fun-header is basically "lose", - ;; but it's only defined on non-x86 platforms for some reason. - ;; The sizer is "lose" because it's an error if a function is encountered - ;; in a heap scan. - (simple-fun ,(or #+(or x86 x86-64) "lose" "fun_header") "lose" "lose") + (code-header "code_blob") + ;; For simple-fun, all three methods are "lose": "scav" is because you can't + ;; encounter a simple-fun in heap scanning; "trans" is because it's not an OTHER pointer, + ;; and "size" is because you can't take the size of a simple-fun by itself. + (simple-fun "lose") ;; The closure scavenge function needs to know if the "self" slot ;; has pointer nature though it be fixnum tagged, as on x86. ;; The sizer is short_boxed. - (closure ,(or #+(or x86 x86-64) "closure" "short_boxed") "lose" "short_boxed") + (closure ,(or #+(or x86 x86-64 arm64) "closure" "short_boxed") "lose" "short_boxed") ;; Like closure, but these can also have a layout pointer in the high header bytes. - (funcallable-instance ,(or #+compact-instance-header "funinstance" "short_boxed") - "lose" "short_boxed") + (funcallable-instance "funinstance" "lose" "short_boxed") ;; These have a scav and trans function, but no size function. - #-(or x86 x86-64) (return-pc "return_pc_header" "return_pc_header" "lose") + #-(or x86 x86-64 arm64 riscv) + (return-pc "return_pc_header" "return_pc_header" "lose") (value-cell "boxed") - (symbol "tiny_boxed") + (symbol "symbol" + "tiny_mixed" "tiny_boxed") ; trans and size respectively ;; Can't transport characters as "other" pointer objects. ;; It should be a cons cell half which would go through trans_list() (character "immediate") (sap "unboxed") (unbound-marker "immediate") - (weak-pointer "weak_pointer" "weak_pointer" "boxed") + (weak-pointer "weakptr") (instance "instance" "lose" "instance") (fdefn "fdefn") - (no-tls-value-marker "immediate") - #+sb-simd-pack (simd-pack "unboxed") #+sb-simd-pack-256 (simd-pack-256 "unboxed") - (filler "unboxed") + (filler "filler" "lose" "filler") - (simple-array "boxed") + (simple-array "array") (simple-array-unsigned-byte-2 "vector_unsigned_byte_2") (simple-array-unsigned-byte-4 "vector_unsigned_byte_4") (simple-array-unsigned-byte-7 "vector_unsigned_byte_8") @@ -112,21 +106,23 @@ (simple-array-complex-double-float "vector_unsigned_byte_128") (simple-bit-vector "vector_bit") - (simple-vector "vector") + (simple-vector "vector_t") (simple-array-nil "vector_nil") (simple-base-string "base_string") - #+sb-unicode (simple-character-string "character_string") - #+sb-unicode (complex-character-string "boxed") - (complex-base-string "boxed") - (complex-vector-nil "boxed") + ;; UB32 works fine for character string, unless we decide to reimplement + ;; using 3 octets per code point. + #+sb-unicode (simple-character-string "vector_unsigned_byte_32") + #+sb-unicode (complex-character-string "array") + (complex-base-string "array") - (complex-bit-vector "boxed") - (complex-vector "boxed") - (complex-array "boxed")))) + (complex-bit-vector "array") + (complex-vector "array") + (complex-array "array")))) #+sb-xc-host (defun write-gc-tables (stream) + (format stream "#include ~S~%" (sb-fasl::lispobj-dot-h)) ;; Compute a bitmask of all specialized vector types, ;; not including array headers, for maybe_adjust_large_object(). (let ((min #xff) (bits 0)) @@ -135,45 +131,58 @@ (let ((widetag (saetp-typecode saetp))) (setf min (min widetag min) bits (logior bits (ash 1 (ash widetag -2))))))) - (format stream "static inline boolean specialized_vector_widetag_p(unsigned char widetag) { + (format stream "static inline int specialized_vector_widetag_p(unsigned char widetag) { return widetag>=0x~X && (0x~8,'0XU >> ((widetag-0x80)>>2)) & 1;~%}~%" min (ldb (byte 32 32) bits)) ;; Union in the bits for other unboxed object types. (dolist (entry *scav/trans/size*) - (when (string= (second entry) "unboxed") + (when (member (second entry) '("bignum" "unboxed" "filler") :test 'string=) (setf bits (logior bits (ash 1 (ash (car entry) -2)))))) - (format stream "static inline boolean leaf_obj_widetag_p(unsigned char widetag) {~%") + (format stream "static inline int leaf_obj_widetag_p(unsigned char widetag) {~%") #+64-bit (format stream " return (0x~XLU >> (widetag>>2)) & 1;" bits) #-64-bit (format stream " int bit = widetag>>2; return (bit<32 ? 0x~XU >> bit : 0x~XU >> (bit-32)) & 1;" (ldb (byte 32 0) bits) (ldb (byte 32 32) bits)) (format stream "~%}~%")) - (format stream "extern unsigned char lowtag_for_widetag[64]; + (format stream "extern unsigned char widetag_lowtag[256]; static inline lispobj compute_lispobj(lispobj* base_addr) { - lispobj header = *base_addr; - return make_lispobj(base_addr, - is_cons_half(header) ? LIST_POINTER_LOWTAG : - lowtag_for_widetag[header_widetag(header)>>2]);~%}~%") + return make_lispobj(base_addr, LOWTAG_FOR_WIDETAG(*base_addr & WIDETAG_MASK));~%}~%") (format stream "~%#ifdef WANT_SCAV_TRANS_SIZE_TABLES~%") - (let ((a (make-array 64 :initial-element 0))) + (let ((lowtag-tbl (make-array 256 :initial-element 0))) + ;; Build a table translating from the from low byte of first word of any + ;; heap object to that object's lowtag when pointed to by a tagged pointer. + ;; If the first word is {immediate | pointer} then the object is a cons, + ;; otherwise the object is a headered object. + (dotimes (byte 256) + (when (or (eql 0 (logand byte fixnum-tag-mask)) + (member (logand byte lowtag-mask) + `(,instance-pointer-lowtag + ,list-pointer-lowtag + ,fun-pointer-lowtag + ,other-pointer-lowtag)) + (member byte `(#+64-bit ,single-float-widetag + ,character-widetag + ,unbound-marker-widetag))) + ;; gotta be a CONS + (setf (svref lowtag-tbl byte) list-pointer-lowtag))) (dolist (entry *scav/trans/size*) (destructuring-bind (widetag scav &rest ignore) entry (declare (ignore ignore)) (unless (string= scav "immediate") - (setf (aref a (ash widetag -2)) - (case widetag - (#.instance-widetag instance-pointer-lowtag) - (#.+function-widetags+ fun-pointer-lowtag) - (t other-pointer-lowtag)))))) - (let ((contents (format nil "~{0x~x,~} " (coerce a 'list)))) - (format stream - "unsigned char lowtag_for_widetag[64] = {~{~% ~A~}~%};~%" - ;; write 4 characters per widetag ("0xN,"), 16 per line - (loop for i from 0 by 64 repeat 4 - ;; trailing comma on the last item is OK in C - collect (subseq contents i (+ i 64)))))) + (setf (svref lowtag-tbl widetag) + (+ #x80 (case widetag + (#.instance-widetag instance-pointer-lowtag) + (#.+function-widetags+ fun-pointer-lowtag) + (#.filler-widetag 0) + (t other-pointer-lowtag))))))) + (format stream "unsigned char widetag_lowtag[256] = {") + (dotimes (line 16) + (format stream "~%~:{ ~:[0x~2,'0x~;~4d~],~}" + (mapcar (lambda (x) (list (member x `(0 ,sb-vm:list-pointer-lowtag)) x)) + (coerce (subseq lowtag-tbl (* line 16) (* (1+ line) 16)) 'list)))) + (format stream "~%};~%")) (let ((scavtab (make-array 256 :initial-element nil)) (ptrtab (make-list #+ppc64 16 #-ppc64 4)) (transtab (make-array 64 :initial-element nil)) @@ -197,6 +206,8 @@ static inline lispobj compute_lispobj(lispobj* base_addr) { #+ppc64 (progn (fill ptrtab "scav_lose") + (setf (aref scavtab #xff) "consfiller" + (aref sizetab #xff) "consfiller") (setf (nth instance-pointer-lowtag ptrtab) "scav_instance_pointer" (nth list-pointer-lowtag ptrtab) "scav_list_pointer" (nth fun-pointer-lowtag ptrtab) "scav_fun_pointer" @@ -226,10 +237,12 @@ static inline lispobj compute_lispobj(lispobj* base_addr) { = {~{~% (void(*)(lispobj*,lispobj))~A~^,~}~%};~%" (length ptrtab) ptrtab) (write-table "static lispobj (*transother[64])(lispobj object)" "trans_" transtab) - (format stream "#define size_pointer size_immediate~%") + (format stream "#define size_pointer (sizerfn)0~%") + (format stream "#define size_immediate (sizerfn)0~%") (format stream "#define size_unboxed size_boxed~%") (write-table "sword_t (*sizetab[256])(lispobj *where)" "size_" sizetab) + (format stream "#undef size_immediate~%") (format stream "#undef size_pointer~%") (format stream "#undef size_unboxed~%"))) (format stream "#endif~%")) diff --git a/src/compiler/generic/layout-ids.lisp b/src/compiler/generic/layout-ids.lisp new file mode 100644 index 0000000000..86e19fb265 --- /dev/null +++ b/src/compiler/generic/layout-ids.lisp @@ -0,0 +1,276 @@ +;;; This is a semi-machine-generated file + +;;;; This software is part of the SBCL system. See the README file for +;;;; more information. +;;;; +;;;; This software is derived from the CMU CL system, which was +;;;; written at Carnegie Mellon University and released into the +;;;; public domain. The software is in the public domain and is +;;;; provided with absolutely no warranty. See the COPYING and CREDITS +;;;; files for more information. + +(in-package "SB-KERNEL") + +;;; These are the most commonly occurring structure-object subtypes sorted in +;;; in descending dynamic frequency of occurrence of the typep test of the type. +;;; The list was obtained from a regression run containing a modified +;;; 'structure-is-a' vop which counts executions in the manner of :SB-DYNCOUNT. +;;; Presumably this correlates well with the number of "static" insertions of +;;; each type test also. So it can decrease code size and increase instruction +;;; decode throughput since these all get IDs that encode as imm8 for x86. + +;;; [Some manual editing here was necessary due to not having all the packages +;;; in all build configurations.] +(defparameter *popular-structure-types* (mapcar 'list '( +SB-KERNEL:CTYPE +HASH-TABLE +SB-IMPL::GENERAL-HASH-TABLE +SB-C::NODE +SB-C::GLOBAL-CONFLICTS +SB-C::GLOBAL-VAR +SB-C::FUNCTIONAL +SB-C::LEAF +SB-KERNEL:ANSI-STREAM +SB-C::IR2-BLOCK +SB-C::VALUED-NODE +RANDOM-STATE +CAST +SB-KERNEL::TYPE-CONTEXT +SB-KERNEL:VALUES-TYPE +SB-SYS:FD-STREAM +SB-C::BASIC-COMBINATION +SB-INT:SSET-ELEMENT +SB-C:TN-REF +SB-KERNEL:ARGS-TYPE +SB-C::VOP +SB-C:STORAGE-BASE +SB-C:STORAGE-CLASS +SB-KERNEL:LEXENV +SB-ASSEM::ANNOTATION +SB-KERNEL:INTERSECTION-TYPE +SB-C:PRIMITIVE-TYPE +#+sb-fasteval SB-INTERPRETER:BASIC-ENV +SB-KERNEL:NUMERIC-TYPE +SB-KERNEL:CLASSOID +SB-KERNEL:UNION-TYPE +SB-C::CONSTRAINT +SB-C::TEMPLATE +SB-ASSEM:LABEL +SB-C::IR2-COMPONENT +SB-C::VOP-INFO +SB-C::IR2-LVAR +SB-IMPL::INFO-HASHTABLE +SB-INT:FORM-TRACKING-STREAM +SB-PRETTY:PRETTY-STREAM +SB-C::CONSET +SB-KERNEL:ARRAY-TYPE +SB-KERNEL:COMPOUND-TYPE +SB-KERNEL:NEGATION-TYPE +SB-REGALLOC::VERTEX +SB-THREAD:THREAD +SB-THREAD::AVLNODE +SB-C::ABSTRACT-LEXENV +SB-KERNEL:UNKNOWN-TYPE +SB-KERNEL:CONS-TYPE +SB-C::IR2-ENVIRONMENT +SB-C::BASIC-VAR +SB-KERNEL:FUN-DESIGNATOR-TYPE +SB-PRETTY::QUEUED-OP +SB-C::BLOCK-ANNOTATION +SB-KERNEL:MEMBER-TYPE +SB-C::FUN-INFO +SB-C::COMPILED-DEBUG-FUN +SB-C::LOCATION-INFO +SB-C::TRANSFORM +SB-PRETTY::SECTION-START +SB-KERNEL:NAMED-TYPE +SB-C::CORE-OBJECT +SB-C::EQUALITY-CONSTRAINT +SB-C::ENTRY-INFO +SB-DI::COMPILED-CODE-LOCATION +SB-C::RETURN-INFO +SB-C::SOURCE-INFO +SB-KERNEL:HOST +TWO-WAY-STREAM +SB-ALIEN-INTERNALS:ALIEN-TYPE +SB-DI:FRAME +SB-C::COMPILED-DEBUG-INFO +SB-DI::COMPILED-DEBUG-FUN +SB-C::FUN-TYPE-ANNOTATION +SB-C::CLOOP +SB-DI:DEBUG-FUN +SB-C::COMPILED-DEBUG-FUN-OPTIONAL +SB-C::COMPILED-DEBUG-FUN-MORE +SB-C::COMPILED-DEBUG-FUN-EXTERNAL +SB-ALIEN::ALIEN-TYPE-CLASS +SB-PCL::CACHE +SB-KERNEL::CONDITION-SLOT +SB-PCL::CLASS-PRECEDENCE-DESCRIPTION +SB-KERNEL:FUN-TYPE +SB-C::FILE-INFO +SB-KERNEL:CHARACTER-SET-TYPE +SB-IMPL::PATTERN +SB-C::LVAR-ANNOTATION +SB-DI::COMPILED-DEBUG-BLOCK +SB-C::ARG-INFO +SB-C::COMPILED-DEBUG-FUN-TOPLEVEL +SB-C::COMPILED-DEBUG-FUN-CLEANUP +SB-DI::COMPILED-FRAME +SB-DISASSEM:SEGMENT +SB-ALIEN-INTERNALS:ALIEN-POINTER-TYPE +SB-C::DEBUG-SOURCE +SB-C::DEBUG-INFO +SB-ALIEN-INTERNALS:ALIEN-RECORD-TYPE +SB-C::LVAR-PROPER-SEQUENCE-ANNOTATION +SB-DI:CODE-LOCATION +SB-KERNEL:STRUCTURE-CLASSOID +SB-C::LVAR-FUNCTION-DESIGNATOR-ANNOTATION +SB-LOCKLESS::LINKED-LIST +SB-C::LVAR-MODIFIED-ANNOTATION +SB-DI::BOGUS-DEBUG-FUN +#+sb-simd-pack SB-KERNEL:SIMD-PACK-TYPE +#+sb-simd-pack-256 SB-KERNEL:SIMD-PACK-256-TYPE +#+sb-fasteval SB-INTERPRETER::SEXPR +SB-C::MODULAR-CLASS +SB-DI:DEBUG-BLOCK +SB-C::LVAR-HOOK +SB-KERNEL:HAIRY-TYPE +#+sb-fasteval SB-INTERPRETER::FRAME +SB-C::LOCAL-CALL-CONTEXT +SB-C::IR2-NLX-INFO +SB-C::LVAR-FUNCTION-ANNOTATION +SB-C::DEBUG-NAME-MARKER +SB-C::CORE-DEBUG-SOURCE +SB-REGALLOC::INTERFERENCE-GRAPH +SB-C::RESTART-LOCATION +#+sb-fasteval SB-INTERPRETER::LAMBDA-FRAME +SB-C::LVAR-LAMBDA-VAR-ANNOTATION +SB-KERNEL::UNDEFINED-CLASSOID +SB-ALIEN-INTERNALS:ALIEN-INTEGER-TYPE +SB-C::LVAR-TYPE-ANNOTATION +SB-C:DEFINITION-SOURCE-LOCATION +SB-DI:DEBUG-VAR +SB-DI::COMPILED-DEBUG-VAR +SB-ALIEN-INTERNALS:ALIEN-FUN-TYPE +SB-PCL::DFUN-INFO +TIMER +#+sb-fasteval SB-INTERPRETER::DECL-SCOPE +SB-C::UNDEFINED-WARNING +SB-C::MODULAR-FUN-INFO +SB-KERNEL:DEFSTRUCT-DESCRIPTION +SB-PCL::ACCESSOR-DFUN-INFO +SB-C::COMPILER-ERROR-CONTEXT +SB-C::DEFINITION-SOURCE-LOCATION+PLIST +SB-KERNEL:ALIEN-TYPE-TYPE +SB-KERNEL:DEFSTRUCT-SLOT-DESCRIPTION +SB-VM:PRIMITIVE-OBJECT +SB-PCL::ONE-INDEX-DFUN-INFO +SB-C::DEBUG-FUN +SB-ALIEN::ALIEN-C-STRING-TYPE +SB-DISASSEM:INSTRUCTION +SB-C::APPROXIMATE-KEY-INFO +SB-ALIEN-INTERNALS:ALIEN-RECORD-FIELD +SB-KERNEL:CONSTANT-TYPE +SB-ALIEN-INTERNALS:ALIEN-FLOAT-TYPE +SB-C::APPROXIMATE-FUN-TYPE +SB-ALIEN-INTERNALS:LOCAL-ALIEN-INFO +SB-ALIEN-INTERNALS:ALIEN-ARRAY-TYPE +SB-KERNEL::CONDITION-CLASSOID +SB-IMPL::ENCAPSULATION-INFO +SB-C::VOP-PARSE +SB-ALIEN-INTERNALS:ALIEN-VALUES-TYPE +SB-DISASSEM::SOURCE-FORM-CACHE +SB-IMPL::SHARP-EQUAL-WRAPPER +SB-DISASSEM::LOCATION-GROUP +SB-FASL::CIRCULARITY +SB-LOOP::LOOP-COLLECTOR +SB-IMPL::COMMA +SB-ALIEN-INTERNALS:ALIEN-SINGLE-FLOAT-TYPE +SB-DEBUG::TRACE-INFO +SB-ALIEN-INTERNALS:ALIEN-DOUBLE-FLOAT-TYPE +SB-VM::SPECIALIZED-ARRAY-ELEMENT-TYPE-PROPERTIES +SB-DI:BREAKPOINT +SB-KERNEL:LOGICAL-HOST +RESTART +SB-ALIEN-INTERNALS:HEAP-ALIEN-INFO +SB-DI::BREAKPOINT-DATA +SB-PRETTY::PPRINT-DISPATCH-ENTRY +SB-IMPL::EXTERNAL-FORMAT +SB-PCL::METHOD-COMBINATION-INFO +SB-KERNEL::LIST-NODE +SB-ALIEN-INTERNALS:ALIEN-ENUM-TYPE +#+sb-fasteval SB-INTERPRETER::SYMBOL-MACRO-SCOPE +SB-INT:DEPRECATION-INFO +SB-DI::FUN-END-COOKIE +SB-ALIEN::SHARED-OBJECT +SB-PCL::FAST-METHOD-CALL +SB-C::DXABLE-ARGS +))) + +;;; The rationale for using (signed-byte 8) for small IDs on the x86 +;;; is that imm8 operands are sign-extended. +;;; The rationale for using (unsigned-byte 8) for small IDs on ARM +;;; is that imm8 operands are NOT sign-extended. +;;; This condition should probably be x86[-64] and everybody else. +;;; I suspect that nobody else benefits from sign-extended immediates. + +(defconstant layout-id-type + #+(or arm mips) 'unsigned-byte + #-(or arm mips) 'signed-byte) + +;;; There are a few wired IDs: +;;; 0 = T +;;; 1 = STRUCTURE-OBJECT +;;; 2 = WRAPPER if #+metaspace, unused if #-metaspace +;;; 3 = SB-VM:LAYOUT if #+metaspace, WRAPPER if #-metaspace +;;; 4 = SB-LOCKLESS::LIST-NODE +;;; 5 = SB-BROTHERTREE::UNARY-NODE +(ecase layout-id-type + (unsigned-byte + ;; Assign all the above an (UNSIGNED-BYTE 8) layout-id. + (let ((id 5)) ; pre-increment when using + (dolist (item *popular-structure-types*) + ;; Because of (MAPCAR #'LIST ...) it is ok to modify this list. + (rplacd item (incf id))))) + (signed-byte + ;; Assign all the above a (SIGNED-BYTE 8) layout-id. + ;; There is room for more types that are encodable as one byte. + ;; It might be interesting to figure out a way to allow user code + ;; to avail itself of some of that encoding space. + (let ((id -128)) + (dolist (item *popular-structure-types*) + ;; Because of (MAPCAR #'LIST ...) it is ok to modify this list. + (rplacd item id) + (setq id (if (= id -1) 6 ; hop over the wired IDs + (1+ id))))))) + +(defvar *general-layout-uniqueid-counter* ; incremented before use + (ecase sb-kernel::layout-id-type + (signed-byte 127) ; predefined IDs range from -128 to 127 + (unsigned-byte 255))) ; all IDs are unsigned integers +;;; Conditions are numbered from -128 downward, +;;; but only if layout IDs can be negative. +(defvar *condition-layout-uniqueid-counter* -128) ; decremented before use + +(defun choose-layout-id (name conditionp) + ;; If you change these, then also change src/runtime/gc-private.h + ;; The ID of T is irrelevant since we'll never try to compare to it. + (case name + ((t) 0) + (structure-object 1) + #+metaspace (wrapper 2) + (#+metaspace sb-vm:layout #-metaspace wrapper 3) + (sb-lockless::list-node 4) + (sb-brothertree::unary-node 5) + (t (or (cdr (assq name sb-kernel::*popular-structure-types*)) + (ecase sb-kernel::layout-id-type + (unsigned-byte + (incf *general-layout-uniqueid-counter*)) + (signed-byte + (if conditionp + ;; It doesn't really matter what ID is assigned to a CONDITION subtype + ;; because we don't use the IDs for type testing. Nor for standard-object. + ;; But I'd like to a have a quick visual scan of the IDs assigned during + ;; genesis by giving them negative values which can't otherwise occur. + (decf *condition-layout-uniqueid-counter*) + (incf *general-layout-uniqueid-counter*)))))))) diff --git a/src/compiler/generic/objdef.lisp b/src/compiler/generic/objdef.lisp index f86c6478d2..253f62e6d2 100644 --- a/src/compiler/generic/objdef.lisp +++ b/src/compiler/generic/objdef.lisp @@ -21,7 +21,7 @@ ;;;; existence of slots, and whether they should be scavenged, is ;;;; not automatically propagated. Thus e.g. if you add a ;;;; SIMPLE-FUN-DEBUG-INFO slot holding a tagged object which needs -;;;; to be GCed, you need to tweak scav_code_header() and +;;;; to be GCed, you need to tweak scav_code_blob() and ;;;; verify_space() in gencgc.c, and the corresponding code in gc.c. ;;;; * Various code (e.g. STATIC-FSET in genesis.lisp) is hard-wired ;;;; to know the name of the last slot of the object the code works @@ -32,9 +32,7 @@ ;;;; the primitive objects themselves -(define-primitive-object (cons :type cons - :lowtag list-pointer-lowtag - :alloc-trans cons) +(define-primitive-object (cons :type cons :lowtag list-pointer-lowtag) (car :ref-trans car :set-trans %rplaca :init :arg :cas-trans %compare-and-swap-car) (cdr :ref-trans cdr :set-trans %rplacd :init :arg @@ -48,7 +46,7 @@ (define-primitive-object (bignum :lowtag other-pointer-lowtag :widetag bignum-widetag :alloc-trans sb-bignum:%allocate-bignum) - (digits :rest-p t :c-type #-alpha "sword_t" #+alpha "u32")) + (digits :rest-p t :c-type "sword_t")) (define-primitive-object (ratio :type ratio :lowtag other-pointer-lowtag @@ -98,32 +96,27 @@ ;; VECTOR -- see SHRINK-VECTOR. (fill-pointer :type index :ref-trans %array-fill-pointer - :ref-known (flushable foldable) + :ref-known (flushable) :set-trans (setf %array-fill-pointer) :set-known ()) - (fill-pointer-p :type (member t nil) - :ref-trans %array-fill-pointer-p - :ref-known (flushable foldable) - :set-trans (setf %array-fill-pointer-p) - :set-known ()) (elements :type index :ref-trans %array-available-elements - :ref-known (flushable foldable) + :ref-known (flushable) :set-trans (setf %array-available-elements) :set-known ()) (data :type array :ref-trans %array-data ; might be a vector, might not be - :ref-known (flushable foldable) + :ref-known (flushable) :set-trans (setf %array-data) :set-known ()) (displacement :type index :ref-trans %array-displacement - :ref-known (flushable foldable) + :ref-known (flushable) :set-trans (setf %array-displacement) :set-known ()) (displaced-p :type t :ref-trans %array-displaced-p - :ref-known (flushable foldable) + :ref-known (flushable) :set-trans (setf %array-displaced-p) :set-known ()) (displaced-from :type list @@ -140,7 +133,7 @@ ;; VECTOR -- see SHRINK-VECTOR. (length :ref-trans sb-c::vector-length :type index) - (data :rest-p t :c-type #-alpha "uword_t" #+alpha "u32")) + (data :rest-p t :c-type "uword_t")) #| Code header representation: @@ -187,7 +180,7 @@ during backtrace. ;;; hidden dependencies on primitive object sizes for the most part, ;;; 'ppc-assem.S' contains a literal constant that relies on knowing ;;; the precise size of a code object. Yes, there is a FIXME there :-) -;;; So, if you touch this, then fix that. +;;; So, if you touch this, then fix that. REALLY REALLY. (define-primitive-object (code :type code-component :lowtag other-pointer-lowtag :widetag code-header-widetag) @@ -197,20 +190,21 @@ during backtrace. (boxed-size :type fixnum ; see above figure :ref-known (flushable movable) :ref-trans %code-boxed-size) + ;; This slot usually holds an instance of SB-C::COMPILED-DEBUG-FUN + ;; but the debugger can replace it with a cons of that and something else. + ;; It could also be the symbol :BPT-LRA, or, as a special case + ;; for the assembler code component, a cons holding a hash-table. + ;; (the cons points from read-only to static space, but the hash-table + ;; wants to be in dynamic space) + ;; The corresponding SETF function is defined using code-header-set + ;; on the slot index; and there's a special variant if #+darwin-jit. (debug-info :type t :ref-known (flushable) - :ref-trans %code-debug-info - :set-known () - :set-trans (setf %code-debug-info)) - ;; Define this slot if the architecture might ever use fixups. - ;; x86-64 doesn't necessarily use them, depending on the feature set, - ;; but this keeps things consistent. - #+(or x86 x86-64) - (fixups :type t - :ref-known (flushable) - :ref-trans %code-fixups - :set-known () - :set-trans (setf %code-fixups)) + :ref-trans %%code-debug-info) + ;; Not all architectures use fixups. The slot is always present for consistency. + ;; The corresponding SETF function is defined using code-header-set + ;; on the slot index. + (fixups :type t :ref-known (flushable) :ref-trans %code-fixups) (constants :rest-p t)) (define-primitive-object (fdefn :type fdefn @@ -224,12 +218,13 @@ during backtrace. ;; unless the function is non-simple, in which case ;; they store a descriptorized (fun-pointer lowtag) ;; pointer to the closure tramp - ;; - x86-64 with immobile-code feature stores a JMP instruction - ;; to the function entry address. Special considerations - ;; pertain to undefined functions, FINs, and closures. ;; - all others store a native pointer to the function entry address - ;; or closure tramp - (raw-addr :c-type #-alpha "char *" #+alpha "u32")) + ;; or closure tramp. x86-64 with immobile-code constrains this + ;; to holding the address of a SIMPLE-FUN or an object that + ;; has the simple-fun call convention- either a generic-function with + ;; a self-contained trampoline, or closure or funcallable-instance + ;; wrapped in a simplifying trampoline. + (raw-addr :c-type "char *")) ;;; a simple function (as opposed to hairier things like closures ;;; which are also subtypes of Common Lisp's FUNCTION type) @@ -238,7 +233,7 @@ during backtrace. :widetag simple-fun-widetag) ;; All three function primitive-objects have the first word after the header ;; as some kind of entry point, either the address to jump to, in the case - ;; of x86, or the Lisp function to jump to, for everybody else. + ;; of x86oids and arm64, or the Lisp function to jump to, for everybody else. (self :set-known () :set-trans (setf %simple-fun-self)) ;; This slot used to be named CODE, but that was misleaing because the @@ -257,19 +252,23 @@ during backtrace. (defconstant simple-fun-source-slot 2) ; form and/or docstring (defconstant simple-fun-info-slot 3) ; type and possibly xref -#-(or x86 x86-64) +#-(or x86 x86-64 arm64 riscv) (define-primitive-object (return-pc :lowtag other-pointer-lowtag :widetag t) (return-point :c-type "unsigned char" :rest-p t)) (define-primitive-object (closure :lowtag fun-pointer-lowtag - :widetag closure-widetag - ;; This allocator is used when renaming or cloning - ;; a closure. The compiler has its own way of making - ;; closures which requires that the length be - ;; a compile-time constant. - :alloc-trans %alloc-closure) - (fun :init :arg :ref-trans #+(or x86 x86-64) %closure-callee - #-(or x86 x86-64) %closure-fun) + :widetag closure-widetag + ;; This allocator is used when renaming or cloning + ;; a closure. The compiler has its own way of making + ;; closures which requires that the length be + ;; a compile-time constant. + :alloc-trans %alloc-closure) + (fun :init :arg :ref-trans #+(or x86 x86-64 arm64) %closure-callee + #-(or x86 x86-64 arm64) %closure-fun) + ;; 'fun' is an interior pointer to code, but we also need the base pointer + ;; for MPS. I'm trying to figure out how to avoid this word of overhead, + ;; but it works for the time being. + #+metaspace (code :ref-known (flushable) :ref-trans %closure-code) (info :rest-p t)) (define-primitive-object (funcallable-instance @@ -277,12 +276,9 @@ during backtrace. :widetag funcallable-instance-widetag :alloc-trans %make-funcallable-instance) (trampoline :init :funcallable-instance-tramp) - ;; TODO: if we can switch places of 'function' and 'fsc-instance-slots' - ;; (at least for the builds with compact-instance-header) - ;; then for both funcallable and non-funcallable instances, - ;; the CLOS slot vector will be in the word 5 bytes past the tagged pointer. - ;; This shouldn't be too hard to arrange, since nothing needs to know where - ;; the tagged function lives except the funcallable instance trampoline. + #-compact-instance-header (layout :set-trans %set-fun-layout :ref-trans %fun-layout) + #+compact-instance-header (instword1) + #+compact-instance-header (instword2) (function :type function :ref-known (flushable) :ref-trans %funcallable-instance-fun :set-known () :set-trans (setf %funcallable-instance-fun)) @@ -310,7 +306,8 @@ during backtrace. :alloc-trans make-weak-pointer) (value :ref-trans %weak-pointer-value :ref-known (flushable) :init :arg) - (next :c-type #-alpha "struct weak_pointer *" #+alpha "u32")) + ;; 64-bit uses spare header bytes to store the 'next' link + #-64-bit (next :c-type "struct weak_pointer *")) ;;;; other non-heap data blocks @@ -319,9 +316,9 @@ during backtrace. symbol) ;; on sb-thread, this is actually a tls-index (define-primitive-object (unwind-block) - (uwp :c-type #-alpha "struct unwind_block *" #+alpha "u32") - (cfp :c-type #-alpha "lispobj *" #+alpha "u32") - #-(or x86 x86-64) code + (uwp :c-type "struct unwind_block *") + (cfp :c-type "lispobj *") + #-(or x86 x86-64 arm64) code entry-pc #+(and win32 x86) next-seh-frame #+(and win32 x86) seh-frame-handler @@ -331,16 +328,16 @@ during backtrace. #+unbind-in-unwind current-catch) (define-primitive-object (catch-block) - (uwp :c-type #-alpha "struct unwind_block *" #+alpha "u32") - (cfp :c-type #-alpha "lispobj *" #+alpha "u32") - #-(or x86 x86-64) code + (uwp :c-type "struct unwind_block *") + (cfp :c-type "lispobj *") + #-(or x86 x86-64 arm64) code entry-pc #+(and win32 x86) next-seh-frame #+(and win32 x86) seh-frame-handler #+(and unbind-in-unwind (not c-stack-is-control-stack)) nfp #+(and unbind-in-unwind (not c-stack-is-control-stack)) nsp #+unbind-in-unwind bsp - (previous-catch :c-type #-alpha "struct catch_block *" #+alpha "u32") + (previous-catch :c-type "struct catch_block *") tag) ;;;; symbols @@ -375,16 +372,33 @@ during backtrace. :set-trans %set-symbol-global-value :set-known ()) - (info :ref-trans symbol-info :ref-known (flushable) - :set-trans (setf symbol-info) - :set-known () - :cas-trans %compare-and-swap-symbol-info - :type (or simple-vector list) + ;; This slot holds an FDEFN. It's almost unnecessary to have FDEFNs at all + ;; for symbols. If we ensured that any function bound to a symbol had a + ;; call convention rendering it callable in the manner of a SIMPLE-FUN, + ;; then we would only need to store that function's raw entry address here, + ;; thereby removing the FDEFN for any global symbol. Any closure assigned + ;; to a symbol would need a tiny trampoline, which is already the case + ;; for #+immobile-code. + (fdefn :ref-trans %symbol-fdefn :ref-known () + :cas-trans cas-symbol-fdefn) + ;; The private accessor for INFO reads the slot verbatim. + ;; In contrast, the SYMBOL-INFO function always returns a PACKED-INFO + ;; instance (see info-vector.lisp) or NIL. The slot itself may hold a cons + ;; of the user's PLIST and a PACKED-INFO or just a PACKED-INFO. + ;; It can't hold a PLIST alone without wrapping in an extra cons cell. + (info :ref-trans symbol-%info :ref-known (flushable) + ;; IR2-CONVERT-CASSER only knows the arg order as (OBJECT OLD NEW), + ;; so as much as I'd like to name this (CAS SYMBOL-%INFO), + ;; it can't be that, because it'd need args of (OLD NEW OBJECT). + ;; This is a pretty close approximation of the desired name. + :cas-trans sb-impl::cas-symbol-%info + :type (or instance list) :init :null) - (name :ref-trans symbol-name :init :arg) - (package :ref-trans sb-xc:symbol-package - :set-trans %set-symbol-package - :init :null) + (name :init :arg #-compact-symbol :ref-trans #-compact-symbol symbol-name) + #-compact-symbol + (package-id :type index ; actually 16 bits. (Could go in the header) + :ref-trans sb-impl::symbol-package-id + :set-trans sb-impl::set-symbol-package-id :set-known ()) ;; 0 tls-index means no tls-index is allocated ;; 64-bit put the tls-index in the header word. ;; For the 32-bit architectures, reading this slot as a descriptor @@ -445,24 +459,30 @@ during backtrace. ;;; These slots hold frequently-referenced constants. ;;; If we can't do that for some reason - like, say, the safepoint page ;;; is located prior to 'struct thread', then these just become ordinary slots. -(defglobal *thread-header-slot-names* - (append '(msan-xor-constant) - #+immobile-space '(function-layout - varyobj-space-addr - varyobj-card-count - varyobj-card-marks))) - -#+sb-safepoint -(defglobal *thread-trailer-slots* (mapcar #'list *thread-header-slot-names*)) -#-sb-safepoint +(defconstant-eqx +thread-header-slot-names+ + `#(#+x86-64 + ,@'(t-nil-constants + alien-linkage-table-base + msan-xor-constant + ;; The following slot's existence must NOT be conditional on #+msan + msan-param-tls) ; = &__msan_param_tls + #+immobile-space + ,@'(function-layout + text-space-addr + text-card-count + text-card-marks)) + #'equalp) + (macrolet ((assign-header-slot-indices () (let ((i 0)) `(progn - ,@(mapcar (lambda (x) - `(defconstant ,(symbolicate "THREAD-" x "-SLOT") ,(decf i))) - *thread-header-slot-names*))))) - (assign-header-slot-indices) - (defglobal *thread-trailer-slots* nil)) + ,@(map 'list (lambda (x) + `(defconstant ,(symbolicate "THREAD-" x "-SLOT") ,(decf i))) + +thread-header-slot-names+))))) + (assign-header-slot-indices)) + +(eval-when (:compile-toplevel :load-toplevel :execute) +(defconstant histogram-small-bins 32)) ; for consing size histogram ;;; this isn't actually a lisp object at all, it's a c structure that lives ;;; in c-land. However, we need sight of so many parts of it from Lisp that @@ -471,15 +491,11 @@ during backtrace. (define-primitive-object (thread :size primitive-thread-object-length) ;; no_tls_value_marker is borrowed very briefly at thread startup to ;; pass the address of the start routine into new_thread_trampoline. - ;; tls[0] = NO_TLS_VALUE_MARKER_WIDETAG because a the tls index slot + ;; tls[0] = NO_TLS_VALUE_MARKER because a the tls index slot ;; of a symbol is initialized to zero (no-tls-value-marker) - ;; Technically this slot violates our requirement that the size of the thread - ;; primitive object be computable by assuming one word per slot. POSIX says - ;; "IEEE Std 1003.1-2001/Cor 2-2004, item XBD/TC2/D6/26 is applied, - ;; adding pthread_t to the list of types that are not required to be arithmetic - ;; types, thus allowing pthread_t to be defined as a structure." - (os-thread :c-type "os_thread_t") + + (stepping) ;; Keep this first bunch of slots from binding-stack-pointer through alloc-region ;; near the beginning of the structure so that x86[-64] assembly code @@ -495,20 +511,17 @@ during backtrace. (current-catch-block :special *current-catch-block*) #+(and (or riscv x86-64 arm64) sb-thread) (current-unwind-protect-block :special *current-unwind-protect-block*) - #+sb-thread (pseudo-atomic-bits #+(or x86 x86-64) :special #+(or x86 x86-64) *pseudo-atomic-bits*) + #+(or sb-thread sparc ppc) + (pseudo-atomic-bits #+(or x86 x86-64) :special #+(or x86 x86-64) *pseudo-atomic-bits* + :c-type "pa_bits_t") (alien-stack-pointer :c-type "lispobj *" :pointer t :special *alien-stack-pointer*) - (stepping) - ;; The following slot's existence must NOT be conditional on #+msan - #+x86-64 (msan-param-tls) ; = &__msan_param_tls - (dynspace-addr) - (dynspace-card-count) - (dynspace-pte-base) ;; Deterministic consing profile recording area. (profile-data :c-type "uword_t *" :pointer t) - ;; Lisp needs only the first two fields of the alloc_region, so it's OK if the - ;; final 2 fields have offsets >= 128 from the base of the thread structure. - #+gencgc (alloc-region :c-type "struct alloc_region" :length 4) + ;; Thread-local allocation buffers + (boxed-tlab :c-type "struct alloc_region" :length 3) + (cons-tlab :c-type "struct alloc_region" :length 3) + (mixed-tlab :c-type "struct alloc_region" :length 3) ;; END of slots to keep near the beginning. ;; This is the original address at which the memory was allocated, @@ -516,6 +529,18 @@ during backtrace. ;; Kept here so that when the thread dies we can release the whole ;; memory we reserved. (os-address :c-type "void *" :pointer t) + ;; Technically this slot violates our requirement that the size of the thread + ;; primitive object be computable by assuming one word per slot. POSIX says + ;; "IEEE Std 1003.1-2001/Cor 2-2004, item XBD/TC2/D6/26 is applied, + ;; adding pthread_t to the list of types that are not required to be arithmetic + ;; types, thus allowing pthread_t to be defined as a structure." + ;; + ;; Furthermore, it is technically possibly for a pthread_t to be smaller than a word + ;; (a 4-byte identifier, not a pointer, on 64-bit) but that seems not to be true + ;; for any system that we care about. + (os-thread :c-type #+(or win32 (not sb-thread)) "lispobj" ; actually is HANDLE + #-(or win32 (not sb-thread)) "pthread_t") + (os-kernel-tid) ; the kernel's thread identifier, 32 bits on linux ;; These aren't accessed (much) from Lisp, so don't really care ;; if it takes a 4-byte displacement. @@ -523,37 +548,26 @@ during backtrace. (binding-stack-start :c-type "lispobj *" :pointer t :special *binding-stack-start*) - #+(and sb-thread (not sb-safepoint)) - (state-sem :c-type "os_sem_t *" :pointer t) - #+(and sb-thread (not sb-safepoint)) - (state-not-running-sem :c-type "os_sem_t *" :pointer t) - #+(and sb-thread (not sb-safepoint)) - (state-not-running-waitcount :c-type "int" :length 1) - #+(and sb-thread (not sb-safepoint)) - (state-not-stopped-sem :c-type "os_sem_t *" :pointer t) - #+(and sb-thread (not sb-safepoint)) - (state-not-stopped-waitcount :c-type "int" :length 1) (control-stack-start :c-type "lispobj *" :pointer t :special *control-stack-start*) (control-stack-end :c-type "lispobj *" :pointer t :special *control-stack-end*) - (control-stack-guard-page-protected) - #+win32 (private-events :c-type "struct private_events" :length 2) (this :c-type "struct thread *" :pointer t) (prev :c-type "struct thread *" :pointer t) (next :c-type "struct thread *" :pointer t) - ;; starting, running, suspended, dead - (state :c-type "lispobj") + ;; a struct containing {starting, running, suspended, dead} + ;; and some other state fields. + (state-word :c-type "struct thread_state_word") + ;; Statistical CPU profiler data recording buffer + (sprof-data) #+x86 (tls-cookie) ; LDT index #+sb-thread (tls-size) - (interrupt-data :c-type "struct interrupt_data *" - :pointer t) ;; For various reasons related to pseudo-atomic and interrupt ;; handling, we need to know if the machine context is in Lisp code ;; or not. On non-threaded targets, this is a global variable in ;; the runtime, but it's clearly a per-thread value. - #+sb-thread + #+(and sb-thread (not arm64)) (foreign-function-call-active :c-type "boolean") ;; Same as above for the location of the current control stack frame. #+(and sb-thread (not (or x86 x86-64))) @@ -563,23 +577,31 @@ during backtrace. ;; print an approximation of the CSP as needed. #+sb-thread (control-stack-pointer :c-type "lispobj *") - #+mach-exception-handler - (mach-port-name :c-type "mach_port_name_t") - ;; Context base pointer for running on top of system libraries built using - ;; -fomit-frame-pointer. Currently truly required and implemented only - ;; for (and win32 x86-64), but could be generalized to other platforms if - ;; needed: - #+win32 (carried-base-pointer :c-type "os_context_register_t") - #+sb-safepoint (csp-around-foreign-call :c-type "lispobj *") - #+win32 (synchronous-io-handle-and-flag :c-type "HANDLE" :length 1) - #+(and sb-safepoint-strictly (not win32)) - (sprof-alloc-region :c-type "struct alloc_region" :length 4) - ;; If we need the header slots, but they can't precede this structure - ;; for technical reasons having to do with no writable memory being there, - ;; then stuff them at the end, for lack of any place better. - . #.*thread-trailer-slots*) + #+ppc64 (card-table) + + ;; A few extra thread-local allocation buffers for special purposes + ;; #-sb-thread probably won't use these, to be determined... + (symbol-tlab :c-type "struct alloc_region" :length 3) + (sys-mixed-tlab :c-type "struct alloc_region" :length 3) + (sys-cons-tlab :c-type "struct alloc_region" :length 3) + ;; allocation instrumenting + (tot-bytes-alloc-boxed) + (tot-bytes-alloc-unboxed) + (slow-path-allocs) + (et-allocator-mutex-acq) ; elapsed times + (et-find-freeish-page) + (et-bzeroing) + (obj-size-histo :c-type "size_histogram" + :length #.(+ histogram-small-bins sb-vm:n-word-bits)) + + ;; The *current-thread* MUST be the last slot in the C thread structure. + ;; It it the only slot that needs to be noticed by the garbage collector. + (lisp-thread :pointer t :special sb-thread:*current-thread*)) (defconstant code-header-size-shift #+64-bit 32 #-64-bit n-widetag-bits) +(defconstant-eqx code-serialno-byte + #+64-bit (byte 32 32) #-64-bit (byte 18 14) + #'equalp) (declaim (inline code-object-size code-header-words %code-code-size)) #-sb-xc-host (progn @@ -619,6 +641,91 @@ during backtrace. (if (eql (code-header-ref code code-boxed-size-slot) 0) 0 (with-pinned-objects (code) - (ldb (byte 18 14) (sap-ref-word (code-instructions code) 0))))) + (ldb code-serialno-byte (sap-ref-word (code-instructions code) 0))))) ) ; end PROGN + +;;; The definitions below want to use ALIGN-UP, which is not defined +;;; in time to put these in early-objdef, but it turns out that we don't +;;; need them there. +(defconstant nil-value + (+ static-space-start + ;; mixed_region precedes NIL + ;; 10 is the number of words to reserve at the beginning of static space + ;; prior to the words of NIL. + ;; If you change this, then also change MAKE-NIL-DESCRIPTOR in genesis, + ;; and zero_all_free_ranges() in gencgc. + #+(and gencgc (not sb-thread) (not 64-bit)) (ash 10 word-shift) + ;; This offset of #x100 has to do with some edge cases where a vop + ;; might treat UNBOUND-MARKER as a pointer. So it has an address + ;; that is somewhere near NIL which makes it sort of "work" + ;; to dereference it. See git rev f1a956a6a771 for more info. + #+64-bit #x100 + ;; magic padding because of NIL's symbol/cons-like duality + (* 2 n-word-bytes) + list-pointer-lowtag)) + +;;; MIXED-REGION is at the beginning of static space +;;; Be sure to update "#define main_thread_mixed_region" etc +;;; if these get changed. +#-sb-thread +(progn (defconstant mixed-region static-space-start) + (defconstant cons-region (+ mixed-region (* 3 n-word-bytes))) + (defconstant boxed-region (+ cons-region (* 3 n-word-bytes)))) + +;;; Start of static objects: +;;; +;;; 32-bit w/threads | 32-bit no threads | 64-bit +;;; -------------------- | -------------------- | --------------------- +;;; padding | padding | padding +;;; NIL: header (#x07__) | NIL: header (#x06__) | NIL: header (#x05__) +;;; hash | hash | hash +;;; value | value | value +;;; info | info | info +;;; name | name | name +;;; fdefn | fdefn | fdefn +;;; package | package | (unused) +;;; tls_index | T: header | T: header +;;; (unused) | | +;;; T: header | | +;;; ------------------- | -------------------- | --------------------- +;;; SYMBOL_SIZE=8 | SYMBOL_SIZE=7 | SYMBOL_SIZE=6 +;;; NIL is 10 words | NIL is 8 words | NIL is 8 words + +;;; This constant is the address at which to scan NIL as a root. +;;; To ensure that scav_symbol is invoked, we have to see the widetag +;;; in the 0th word, which is at 1 word prior to the word containing the CAR of +;;; nil-as-a-list. So subtract the lowtag and then go back one more word. +;;; This address is NOT double-lispword-aligned, but the scavenge method +;;; does not assert that. +(defconstant nil-symbol-slots-start + (- nil-value list-pointer-lowtag n-word-bytes)) + +;;; NIL as a symbol contains the usual number of words for a symbol, +;;; aligned to a double-lispword. This will NOT end at a double-lispword boundary. +;;; In all 3 scenarios depicted above, the number of slots that the 'scav' function +;;; returns suggests that it would examine the header word of the *next* symbol. +;;; But it does not, because it confines itself to looking only at the number of +;;; words indicated in the symbol header of NIL. But we have to pass in the aligned +;;; count because of the assertion in heap_scavenge that the scan ends as expected, +;;; and scavenge methods must return an even number because nothing can be smaller +;;; than 1 cons cell or not a multiple thereof. +(defconstant nil-symbol-slots-end + (+ nil-symbol-slots-start (ash (align-up symbol-size 2) word-shift))) + +;;; This constant is the number of words to report that NIL consumes +;;; when Lisp asks for its primitive-object-size. So we say that it consumes +;;; all words from the start of static-space objects up to the next object. +(defconstant sizeof-nil-in-words (+ 2 (sb-int:align-up (1- sb-vm:symbol-size) 2))) + +;;; Address at which to start scanning static symbols when heap-walking. +;;; Basically skip over MIXED-REGION (if it's in static space) and NIL. +;;; Or: go to NIL's header word, subtract 1 word, and add in the physical +;;; size of NIL in bytes that we report for primitive-object-size. +(defconstant static-space-objects-start + (+ nil-symbol-slots-start (ash (1- sizeof-nil-in-words) word-shift))) + +#-sb-xc-host +(progn +(declaim (inline lowtag-of)) +(defun lowtag-of (x) (logand (get-lisp-obj-address x) sb-vm:lowtag-mask))) diff --git a/src/compiler/generic/parms.lisp b/src/compiler/generic/parms.lisp index 43f86ea500..4f62af8285 100644 --- a/src/compiler/generic/parms.lisp +++ b/src/compiler/generic/parms.lisp @@ -37,6 +37,9 @@ (* number mult)))))) #-sb-xc-host (symbol-value 'default-dynamic-space-size)) +;; By happenstance this is the same as small-space-size. +(defconstant alien-linkage-table-space-size #x100000) + #+gencgc ;; Define START/END constants for GENCGC spaces. ;; Assumptions: @@ -63,10 +66,12 @@ ;; And of course, don't use them if unsupported. ((:fixedobj-space-start fixedobj-space-start*)) ((:fixedobj-space-size fixedobj-space-size*) (* 24 1024 1024)) - ((:varyobj-space-start varyobj-space-start*)) - ((:varyobj-space-size varyobj-space-size*) (* 104 1024 1024)) + ((:text-space-start text-space-start*)) + ((:text-space-size text-space-size*) (* 104 1024 1024)) (small-space-size #x100000) - ((:read-only-space-size ro-space-size) small-space-size)) + ((:read-only-space-size ro-space-size) + #+darwin-jit small-space-size + #-darwin-jit 0)) (declare (ignorable dynamic-space-start*)) ; might be unused in make-host-2 (flet ((defconstantish (relocatable symbol value) (if (not relocatable) ; easy case @@ -79,23 +84,28 @@ ))) (let* ((spaces (append `((read-only ,ro-space-size) - (linkage-table ,small-space-size) + #+(and win32 x86-64) + (seh-data ,(symbol-value '+backend-page-bytes+) win64-seh-data-addr) + #-immobile-space (alien-linkage-table ,alien-linkage-table-space-size) #+sb-safepoint ;; Must be just before NIL. (safepoint ,(symbol-value '+backend-page-bytes+) gc-safepoint-page-addr) - (static ,small-space-size)) + (static ,small-space-size) + #+darwin-jit + (static-code ,small-space-size)) #+immobile-space `((fixedobj ,fixedobj-space-size*) - (varyobj ,varyobj-space-size*)))) + (alien-linkage-table ,alien-linkage-table-space-size) + (text ,text-space-size*)))) (ptr small-spaces-start) (small-space-forms (loop for (space size var-name) in spaces appending (let* ((relocatable - ;; TODO: linkage-table could move with code, if the CPU - ;; prefers PC-relative jumps, and we emit better code - ;; (which we don't- for x86 we jmp via RBX always) - (member space '(fixedobj varyobj))) + ;; READONLY is usually movable now. + (member space '(fixedobj text + #+immobile-space alien-linkage-table + #-darwin-jit read-only))) (start ptr) (end (+ ptr size))) (setf ptr end) @@ -105,14 +115,15 @@ ;; Allow expressly given addresses / sizes for immobile space. ;; The addresses are for testing only - you should not need them. (case space - (varyobj (setq start (or varyobj-space-start* start) - end (+ start varyobj-space-size*))) + (text (setq start (or text-space-start* start) + end (+ start text-space-size*))) (fixedobj (setq start (or fixedobj-space-start* start) end (+ start fixedobj-space-size*)))) `(,(defconstantish relocatable start-sym start) - ,(cond ((not relocatable) + ,(cond ((eq space 'alien-linkage-table)) ; nothing for the -END + ((not relocatable) `(defconstant ,(symbolicate space "-SPACE-END") ,end)) - #-sb-xc-host ((eq space 'varyobj)) ; don't emit anything + #-sb-xc-host ((eq space 'text)) ; don't emit anything (t `(defconstant ,(symbolicate space "-SPACE-SIZE") ,(- end start))))))))))) @@ -127,7 +138,25 @@ (or ,(or (!read-dynamic-space-size) dynamic-space-size*) (ecase n-word-bits (32 (expt 2 29)) - (64 (expt 2 30))))))))) + (64 (expt 2 30))))) + ;; an arbitrary value to avoid kludging genesis + #+(and sb-xc-host (not darwin-jit)) + (defparameter read-only-space-end read-only-space-start) + #-soft-card-marks (defconstant cards-per-page 1) + (defconstant gencgc-card-bytes (/ gencgc-page-bytes cards-per-page)) + (defconstant gencgc-card-shift + (integer-length (1- gencgc-card-bytes))) + ;; This is a constant during build, but a different value + ;; can be patched directly into the affected machine code + ;; when the core is loaded based on dynamic-space-size. + ;; I think the C runtime does a floor operation rather than ceiling, + ;; but firstly there's probably no difference, and secondly it's better + ;; to be safe than sorry - using too many bits rather than too few. + (defconstant gencgc-card-table-index-nbits + (integer-length (1- (ceiling default-dynamic-space-size + gencgc-card-bytes)))) + (defconstant gencgc-card-table-index-mask + (1- (ash 1 gencgc-card-table-index-nbits))))))) (defconstant-eqx +c-callable-fdefns+ '(sub-gc @@ -145,34 +174,31 @@ sb-di::handle-breakpoint sb-di::handle-single-step-trap #+win32 sb-kernel::handle-win32-exception - #+sb-thruption sb-thread::run-interruption + #+sb-safepoint sb-thread::run-interruption enter-alien-callback - #+sb-thread sb-thread::enter-foreign-callback - #+(and sb-safepoint-strictly (not win32)) - sb-unix::signal-handler-callback) + #+sb-thread sb-thread::enter-foreign-callback) #'equal) -;;; (potentially) static symbols that C code must be able to assign to, +;;; (potentially) static symbols that C code must be able to set/get ;;; as contrasted with static for other reasons such as: ;;; - garbage collections roots (namely NIL) ;;; - other symbols that Lisp codegen must hardwire (T) ;;; - static for efficiency of access but need not be ;;; On #+sb-thread builds, these are not static, because access to them ;;; is via the TLS, not the symbol. -(defconstant-eqx !per-thread-c-interface-symbols +(defconstant-eqx per-thread-c-interface-symbols `((*free-interrupt-context-index* 0) (sb-sys:*allow-with-interrupts* t) (sb-sys:*interrupts-enabled* t) - *alloc-signal* sb-sys:*interrupt-pending* - #+sb-thruption sb-sys:*thruption-pending* + #+sb-safepoint sb-sys:*thruption-pending* *in-without-gcing* *gc-inhibit* *gc-pending* #+sb-safepoint sb-impl::*in-safepoint* #+sb-thread *stop-for-gc-pending* - ;; non-x86oid gencgc object pinning - #+(and gencgc (not (or x86 x86-64))) *pinned-objects* + *pinned-objects* + #+gencgc (*gc-pin-code-pages* 0) ;; things needed for non-local-exit (*current-catch-block* 0) (*current-unwind-protect-block* 0) @@ -184,7 +210,7 @@ ;; These symbols are accessed from C only through TLS, ;; never the symbol-value slot #-sb-thread ,@(mapcar (lambda (x) (car (ensure-list x))) - !per-thread-c-interface-symbols) + per-thread-c-interface-symbols) ;; NLX variables are thread slots on x86-64 and RISC-V. A static sym is needed ;; for arm64, ppc, and x86 because we haven't implemented TLS index fixups, ;; so must lookup the TLS index given the symbol. @@ -192,13 +218,10 @@ ,@'(*current-catch-block* *current-unwind-protect-block*) - ;; sb-safepoint in addition to accessing this symbol via TLS, - ;; uses the symbol itself as a value. Kinda weird. - #+(and sb-safepoint sb-thread) *in-without-gcing* - - #+immobile-space *immobile-freelist* ; not per-thread (yet...) - - #+hpux *c-lra* + #+metaspace *metaspace-tracts* + *immobile-codeblob-tree* ; for generations 0 through 5 inclusive + *immobile-codeblob-vector* ; for pseudo-static-generation + *dynspace-codeblob-tree* ;; stack pointers #-sb-thread *binding-stack-start* ; a thread slot if #+sb-thread @@ -208,10 +231,11 @@ #-sb-thread *stepping* ;; threading support - #+sb-thread *free-tls-index* + #+sb-thread ,@'(sb-thread::*starting-threads* *free-tls-index*) - ;; dynamic runtime linking support - #+linkage-table +required-foreign-symbols+ + ;; runtime linking of lisp->C calls (regardless of whether + ;; the C function is in a dynamic shared object or not) + +required-foreign-symbols+ ;;; The following symbols aren't strictly required to be static ;;; - they are not accessed from C - but we make them static in order @@ -230,14 +254,31 @@ ;;; Refer to the lengthy comment in 'src/runtime/interrupt.h' about ;;; the choice of this number. Rather than have to two copies ;;; of the comment, please see that file before adjusting this. -(defconstant max-interrupts 1024) +;;; I think most of the need for a ridiculously large value stemmed from +;;; receive-pending-interrupt after a pseudo-atomic code section. +;;; If that trapped into GC, and then ran finalizers in POST-GC (while still +;;; in a signal handler), which consed, which caused the need for another GC, +;;; you'd receive a nested interrupt, as the GC trap was still on the stack +;;; not having returned to "user" code yet. [See example in src/code/final] +;;; +;;; But now that #+sb-thread creates a dedicated finalizer thread, nesting +;;; seems unlikely to occur, because "your" code doesn't get a chance to run again +;;; until after the interrupt returns. And the finalizer thread won't invoke +;;; run-pending-finalizers in post-GC, it will just pick up the next finalizer +;;; in due turn. You could potentially force a nested GC by consing a lot in +;;; a post-GC hook, but if you do that, your hook function is badly behaved +;;; and you should fix it. +(defconstant max-interrupts + #+sb-thread 8 ; reasonable value + #-sb-thread 1024) ; crazy value + ;;; Thread slots accessed at negative indices relative to struct thread. -;;; These slots encroach on the interrupt contexts- the maximum that -;;; can actually be stored is decreased by this amount. -;;; sb-safepoint puts the safepoint page immediately preceding the -;;; thread structure, so this trick doesn't work. (defconstant thread-header-slots - (+ #+(and x86-64 (not sb-safepoint)) 16)) + ;; This seems to need to be an even number. + ;; I'm not sure what the constraint on that stems from. + #+(and x86-64 sb-safepoint) 14 ; the safepoint trap page is at word index -15 + #+(and x86-64 (not sb-safepoint)) 16 + #-x86-64 0) #+gencgc (progn @@ -247,5 +288,47 @@ (defparameter *runtime-asm-routines* nil) (defparameter *linkage-space-predefined-entries* nil) +;;; Floating-point related constants, both format descriptions and FPU +;;; control register descriptions. These don't exactly match up with +;;; what the machine manuals say because the Common Lisp standard +;;; defines floating-point values somewhat differently than the IEEE +;;; standard does. + +;;; We can currently manipulate only IEEE single and double precision. +;;; Machine-specific formats (such as x86 80-bit and PPC double-double) +;;; are unsupported. + +#+ieee-floating-point +(progn +(defconstant float-sign-shift 31) + +;;; The exponent bias is the amount up by which the true exponent is +;;; incremented for storage purposes. +;;; (Wikipedia entry for single-float: "an exponent value of 127 represents the actual zero") +;;; 126 works for us because we actually want an exponent of -1 and not 0 +;;; when using DECODE-FLOAT. -1 is correct because the implied 1 bit in a normalized +;;; float is the _left_ of of the binary point, so the powers of 2 for the first represented +;;; bit is 2^-1. Similarly for double-float. +(defconstant single-float-bias 126) +(defconstant-eqx single-float-exponent-byte (byte 8 23) #'equalp) +(defconstant-eqx single-float-significand-byte (byte 23 0) #'equalp) +(defconstant single-float-normal-exponent-min 1) +(defconstant single-float-normal-exponent-max 254) +(defconstant single-float-hidden-bit (ash 1 23)) + +(defconstant double-float-bias 1022) +(defconstant-eqx double-float-exponent-byte (byte 11 20) #'equalp) +(defconstant-eqx double-float-significand-byte (byte 20 0) #'equalp) +(defconstant double-float-normal-exponent-min 1) +(defconstant double-float-normal-exponent-max #x7FE) +(defconstant double-float-hidden-bit (ash 1 20)) + +(defconstant single-float-digits + (+ (byte-size single-float-significand-byte) 1)) + +(defconstant double-float-digits + (+ (byte-size double-float-significand-byte) 32 1)) +) + (push '("SB-VM" +c-callable-fdefns+ +common-static-symbols+) *!removable-symbols*) diff --git a/src/compiler/generic/pinned-objects.lisp b/src/compiler/generic/pinned-objects.lisp index 66c0347cb7..86c773bf8b 100644 --- a/src/compiler/generic/pinned-objects.lisp +++ b/src/compiler/generic/pinned-objects.lisp @@ -27,7 +27,7 @@ garbage collection." #+(and gencgc (or x86 x86-64)) (if objects (let ((pins (make-gensym-list (length objects))) - (wpo (sb-xc:gensym "WITH-PINNED-OBJECTS-THUNK"))) + (wpo (gensym "WITH-PINNED-OBJECTS-THUNK"))) ;; BODY is stuffed in a function to preserve the lexical ;; environment. `(flet ((,wpo () (progn ,@body))) @@ -39,7 +39,8 @@ garbage collection." ;; unfathomable reason decides to allocate value-cells ;; for them -- since we have DX value-cells on x86oid ;; platforms this still forces them on the stack. - (dx-let ,(mapcar #'list pins objects) + (dx-let ,(mapcar (lambda (n v) + (list n `(touch-object-identity ,v))) pins objects) (multiple-value-prog1 (,wpo) ;; TOUCH-OBJECT has a VOP with an empty body: compiler ;; thinks we're using the argument and doesn't flush @@ -50,3 +51,44 @@ garbage collection." `(touch-object ,pin)) pins))))) `(progn ,@body))) + +(defmacro with-pinned-object-iterator ((name) &body body) + #-gencgc + `(macrolet ((,name (arg) (declare (ignore arg)) nil)) ,@body) + #+(and gencgc (not (or x86 x86-64))) + `(dx-let ((.cell. (cons nil *pinned-objects*))) + (let ((*pinned-objects* .cell.)) + (macrolet ((,name (arg) `(rplaca .cell. ,arg))) ,@body))) + #+(and gencgc (or x86 x86-64)) + `(dx-let ((.cell. (cons nil nil))) + (macrolet ((,name (arg) `(rplaca .cell. ,arg))) ,@body))) + +;;; Allow GC within the body, but pin (for some definition of "pin") all code. +;;; There are two different behaviors: +;;; +;;; - If SPACE is :DYNAMIC, then no code object in the dynamic-space may move or die, +;;; but immobile-space code objects may die, in the absence of any (ambiguous or exact) +;;; reference. This mode of pinning prevents object movement, which only implies +;;; preventing death in as much as those are inextricably the same concept. +;;; +;;; - If SPACE is :IMMOBILE, then the GC is not allowed to do anything that affects the +;;; freelists in the mark-and-sweep code space. This prevents death, and of course +;;; the non-movement is implicit. Dynamic-space code is unnaffected. +;;; The use-case it to provide mutual exclusion of the allocator and collector. +;;; ** THIS MODE IS NOT IMPLEMENTED YET *** +;;; +;;; The two may not be specified simultaneously, however, nesting may occur, and +;;; should behave as expected, taking the union of the requests into account. +;;; e.g. one could imagine that during a backtrace - hence with :DYNAMIC space +;;; code pinned - it might be necessary to JIT-compile a method for PRINT-OBJECT +;;; which might pin :IMMOBILE space code. +;;; +(defmacro with-code-pages-pinned ((space) &body body) + #+cheneygc (declare (ignore space)) + #+gencgc `(let ((*gc-pin-code-pages* + (logior *gc-pin-code-pages* + ,(ecase space + (:dynamic 1) + #+immobile-space (:immobile 2))))) + ,@body) + #+cheneygc `(without-gcing ,@body)) diff --git a/src/compiler/generic/primtype.lisp b/src/compiler/generic/primtype.lisp index d9464e959d..a091174b7b 100644 --- a/src/compiler/generic/primtype.lisp +++ b/src/compiler/generic/primtype.lisp @@ -51,16 +51,17 @@ (/show0 "primtype.lisp 53") (!def-primitive-type-alias tagged-num '(:or positive-fixnum fixnum)) -(multiple-value-bind (unsigned signed) +(multiple-value-bind (unsigned signed untagged) (case sb-vm:n-machine-word-bits (64 (values '(unsigned-byte-64 unsigned-byte-63 positive-fixnum) - '(signed-byte-64 fixnum unsigned-byte-63 positive-fixnum))) + '(signed-byte-64 fixnum unsigned-byte-63 positive-fixnum) + '(signed-byte-64 unsigned-byte-64 unsigned-byte-63 fixnum positive-fixnum))) (32 (values '(unsigned-byte-32 unsigned-byte-31 positive-fixnum) - '(signed-byte-32 fixnum unsigned-byte-31 positive-fixnum)))) + '(signed-byte-32 fixnum unsigned-byte-31 positive-fixnum) + '(signed-byte-32 unsigned-byte-32 unsigned-byte-31 fixnum positive-fixnum)))) (!def-primitive-type-alias unsigned-num `(:or ,@unsigned)) (!def-primitive-type-alias signed-num `(:or ,@signed)) - (!def-primitive-type-alias untagged-num - `(:or ,@(sort (copy-list (union unsigned signed)) #'string<)))) + (!def-primitive-type-alias untagged-num `(:or ,@untagged))) ;;; other primitive immediate types (/show0 "primtype.lisp 68") @@ -99,20 +100,66 @@ :type (simd-pack single-float)) (!def-primitive-type simd-pack-double (double-sse-reg descriptor-reg) :type (simd-pack double-float)) - (!def-primitive-type simd-pack-int (int-sse-reg descriptor-reg) - :type (simd-pack integer)) + (!def-primitive-type simd-pack-ub8 (int-sse-reg descriptor-reg) + :type (simd-pack (unsigned-byte 8))) + (!def-primitive-type simd-pack-ub16 (int-sse-reg descriptor-reg) + :type (simd-pack (unsigned-byte 16))) + (!def-primitive-type simd-pack-ub32 (int-sse-reg descriptor-reg) + :type (simd-pack (unsigned-byte 32))) + (!def-primitive-type simd-pack-ub64 (int-sse-reg descriptor-reg) + :type (simd-pack (unsigned-byte 64))) + (!def-primitive-type simd-pack-sb8 (int-sse-reg descriptor-reg) + :type (simd-pack (signed-byte 8))) + (!def-primitive-type simd-pack-sb16 (int-sse-reg descriptor-reg) + :type (simd-pack (signed-byte 16))) + (!def-primitive-type simd-pack-sb32 (int-sse-reg descriptor-reg) + :type (simd-pack (signed-byte 32))) + (!def-primitive-type simd-pack-sb64 (int-sse-reg descriptor-reg) + :type (simd-pack (signed-byte 64))) (!def-primitive-type-alias simd-pack - '(:or simd-pack-single simd-pack-double simd-pack-int))) + '(:or simd-pack-single + simd-pack-double + simd-pack-ub8 + simd-pack-ub16 + simd-pack-ub32 + simd-pack-ub64 + simd-pack-sb8 + simd-pack-sb16 + simd-pack-sb32 + simd-pack-sb64))) #+sb-simd-pack-256 (progn (!def-primitive-type simd-pack-256-single (single-avx2-reg descriptor-reg) :type (simd-pack-256 single-float)) (!def-primitive-type simd-pack-256-double (double-avx2-reg descriptor-reg) :type (simd-pack-256 double-float)) - (!def-primitive-type simd-pack-256-int (int-avx2-reg descriptor-reg) - :type (simd-pack-256 integer)) + (!def-primitive-type simd-pack-256-ub8 (int-avx2-reg descriptor-reg) + :type (simd-pack-256 (unsigned-byte 8))) + (!def-primitive-type simd-pack-256-ub16 (int-avx2-reg descriptor-reg) + :type (simd-pack-256 (unsigned-byte 16))) + (!def-primitive-type simd-pack-256-ub32 (int-avx2-reg descriptor-reg) + :type (simd-pack-256 (unsigned-byte 32))) + (!def-primitive-type simd-pack-256-ub64 (int-avx2-reg descriptor-reg) + :type (simd-pack-256 (unsigned-byte 64))) + (!def-primitive-type simd-pack-256-sb8 (int-avx2-reg descriptor-reg) + :type (simd-pack-256 (signed-byte 8))) + (!def-primitive-type simd-pack-256-sb16 (int-avx2-reg descriptor-reg) + :type (simd-pack-256 (signed-byte 16))) + (!def-primitive-type simd-pack-256-sb32 (int-avx2-reg descriptor-reg) + :type (simd-pack-256 (signed-byte 32))) + (!def-primitive-type simd-pack-256-sb64 (int-avx2-reg descriptor-reg) + :type (simd-pack-256 (signed-byte 64))) (!def-primitive-type-alias simd-pack-256 - '(:or simd-pack-256-single simd-pack-256-double simd-pack-256-int))) + '(:or simd-pack-256-single + simd-pack-256-double + simd-pack-256-ub8 + simd-pack-256-ub16 + simd-pack-256-ub32 + simd-pack-256-ub64 + simd-pack-256-sb8 + simd-pack-256-sb16 + simd-pack-256-sb32 + simd-pack-256-sb64))) ;;; primitive other-pointer array types (/show0 "primtype.lisp 96") @@ -142,13 +189,12 @@ ;;; Return the most restrictive primitive type that contains OBJECT. (/show0 "primtype.lisp 147") (defun primitive-type-of (object) - (let ((type (ctype-of object))) - (cond ((not (member-type-p type)) (primitive-type type)) - ((and (eql 1 (member-type-size type)) - (equal (member-type-members type) '(nil))) - (primitive-type-or-lose 'list)) - (t - *backend-t-primitive-type*)))) + (if (null object) + (load-time-value (primitive-type-or-lose 'list) t) + (let ((type (ctype-of object))) + (if (member-type-p type) + *backend-t-primitive-type* + (primitive-type type))))) ;;; Return the primitive type corresponding to a type descriptor ;;; structure. The second value is true when the primitive type is @@ -234,7 +280,7 @@ (integer (cond ((and hi lo) (dolist (spec - `((positive-fixnum 0 ,sb-xc:most-positive-fixnum) + `((positive-fixnum 0 ,most-positive-fixnum) ,@(ecase n-machine-word-bits (32 `((unsigned-byte-31 @@ -246,8 +292,8 @@ 0 ,(1- (ash 1 63))) (unsigned-byte-64 0 ,(1- (ash 1 64)))))) - (fixnum ,sb-xc:most-negative-fixnum - ,sb-xc:most-positive-fixnum) + (fixnum ,most-negative-fixnum + ,most-positive-fixnum) ,(ecase n-machine-word-bits (32 `(signed-byte-32 ,(ash -1 31) @@ -255,8 +301,8 @@ (64 `(signed-byte-64 ,(ash -1 63) ,(1- (ash 1 63)))))) - (if (or (< hi sb-xc:most-negative-fixnum) - (> lo sb-xc:most-positive-fixnum)) + (if (or (< hi most-negative-fixnum) + (> lo most-positive-fixnum)) (part-of bignum) (part-of integer))) (let ((type (car spec)) @@ -266,8 +312,8 @@ (return (values (primitive-type-or-lose type) (and (= lo min) (= hi max)))))))) - ((or (and hi (< hi sb-xc:most-negative-fixnum)) - (and lo (> lo sb-xc:most-positive-fixnum))) + ((or (and hi (< hi most-negative-fixnum)) + (and lo (> lo most-positive-fixnum))) (part-of bignum)) (t (part-of integer)))) @@ -390,35 +436,70 @@ (part-of character))) #+sb-simd-pack (simd-pack-type - (let ((eltypes (simd-pack-type-element-type type))) - (cond ((member 'integer eltypes) - (exactly simd-pack-int)) - ((member 'single-float eltypes) + (let* ((eltypes (simd-pack-type-element-type type)) + (count (count 1 eltypes)) + (position (position 1 eltypes))) + (if (= count 1) + (cond + ((eql position (position '(unsigned-byte 8) *simd-pack-element-types* :test #'equal)) + (exactly simd-pack-ub8)) + ((eql position (position '(unsigned-byte 16) *simd-pack-element-types* :test #'equal)) + (exactly simd-pack-ub16)) + ((eql position (position '(unsigned-byte 32) *simd-pack-element-types* :test #'equal)) + (exactly simd-pack-ub32)) + ((eql position (position '(unsigned-byte 64) *simd-pack-element-types* :test #'equal)) + (exactly simd-pack-ub64)) + ((eql position (position '(signed-byte 8) *simd-pack-element-types* :test #'equal)) + (exactly simd-pack-sb8)) + ((eql position (position '(signed-byte 16) *simd-pack-element-types* :test #'equal)) + (exactly simd-pack-sb16)) + ((eql position (position '(signed-byte 32) *simd-pack-element-types* :test #'equal)) + (exactly simd-pack-sb32)) + ((eql position (position '(signed-byte 64) *simd-pack-element-types* :test #'equal)) + (exactly simd-pack-sb64)) + ((eql position (position 'single-float *simd-pack-element-types* :test #'equal)) (exactly simd-pack-single)) - ((member 'double-float eltypes) - (exactly simd-pack-double))))) + ((eql position (position 'double-float *simd-pack-element-types* :test #'equal)) + (exactly simd-pack-double)) + (t (any))) + (any)))) #+sb-simd-pack-256 (simd-pack-256-type - (let ((eltypes (simd-pack-256-type-element-type type))) - (cond ((member 'integer eltypes) - (exactly simd-pack-256-int)) - ((member 'single-float eltypes) + (let* ((eltypes (simd-pack-256-type-element-type type)) + (count (count 1 eltypes)) + (position (position 1 eltypes))) + (if (= count 1) + (cond + ((eql position (position '(unsigned-byte 8) *simd-pack-element-types* :test #'equal)) + (exactly simd-pack-256-ub8)) + ((eql position (position '(unsigned-byte 16) *simd-pack-element-types* :test #'equal)) + (exactly simd-pack-256-ub16)) + ((eql position (position '(unsigned-byte 32) *simd-pack-element-types* :test #'equal)) + (exactly simd-pack-256-ub32)) + ((eql position (position '(unsigned-byte 64) *simd-pack-element-types* :test #'equal)) + (exactly simd-pack-256-ub64)) + ((eql position (position '(signed-byte 8) *simd-pack-element-types* :test #'equal)) + (exactly simd-pack-256-sb8)) + ((eql position (position '(signed-byte 16) *simd-pack-element-types* :test #'equal)) + (exactly simd-pack-256-sb16)) + ((eql position (position '(signed-byte 32) *simd-pack-element-types* :test #'equal)) + (exactly simd-pack-256-sb32)) + ((eql position (position '(signed-byte 64) *simd-pack-element-types* :test #'equal)) + (exactly simd-pack-256-sb64)) + ((eql position (position 'single-float *simd-pack-element-types* :test #'equal)) (exactly simd-pack-256-single)) - ((member 'double-float eltypes) - (exactly simd-pack-256-double))))) + ((eql position (position 'double-float *simd-pack-element-types* :test #'equal)) + (exactly simd-pack-256-double)) + (t (any))) + (any)))) + (cons-type + (part-of list)) (built-in-classoid (case (classoid-name type) - #+sb-simd-pack - ;; Can't tell what specific type; assume integers. - (simd-pack - (exactly simd-pack-int)) - #+sb-simd-pack-256 - (simd-pack-256 - (exactly simd-pack-256-int)) ((complex function system-area-pointer weak-pointer) (values (primitive-type-or-lose (classoid-name type)) t)) - (cons-type - (part-of list)) + ((pathname logical-pathname) + (part-of instance)) (t (any)))) (fun-designator-type diff --git a/src/compiler/generic/target-core.lisp b/src/compiler/generic/target-core.lisp index d674941a93..1199499e81 100644 --- a/src/compiler/generic/target-core.lisp +++ b/src/compiler/generic/target-core.lisp @@ -18,13 +18,11 @@ ;;; Map of code-component -> list of PC offsets at which allocations occur. ;;; This table is needed in order to enable allocation profiling. -(define-load-time-global *allocation-point-fixups* +(define-load-time-global *allocation-patch-points* (make-hash-table :test 'eq :weakness :key :synchronized t)) #-x86-64 (progn -(defun convert-alloc-point-fixups (dummy1 dummy2) - (declare (ignore dummy1 dummy2))) (defun sb-vm::statically-link-code-obj (code fixups) (declare (ignore code fixups)))) @@ -37,7 +35,7 @@ (defun sb-vm::function-raw-address (name &aux (fun (fdefinition name))) (cond ((not (immobile-space-obj-p fun)) (error "Can't statically link to ~S: code is movable" name)) - ((neq (fun-subtype fun) sb-vm:simple-fun-widetag) + ((neq (%fun-pointer-widetag fun) sb-vm:simple-fun-widetag) (error "Can't statically link to ~S: non-simple function" name)) (t (let ((addr (get-lisp-obj-address fun))) @@ -55,78 +53,66 @@ ;;; Point FUN's 'self' slot to FUN. ;;; FUN must be pinned when calling this. -(declaim (inline assign-simple-fun-self)) -(defun assign-simple-fun-self (fun) - (setf (%simple-fun-self fun) - ;; x86 backends store the address of the entrypoint in 'self' - #+(or x86 x86-64) - (%make-lisp-obj - (truly-the word (+ (get-lisp-obj-address fun) - (ash sb-vm:simple-fun-insts-offset sb-vm:word-shift) - (- sb-vm:fun-pointer-lowtag)))) - ;; non-x86 backends store the function itself (what else?) in 'self' - #-(or x86 x86-64) fun)) +#-darwin-jit ; done entirely by C for #+darwin-jit +(defmacro assign-simple-fun-self (fun) + `(let* ((fun ,fun) + (self + ;; a few architectures store the untagged address of the entrypoint in 'self' + #+(or x86 x86-64 arm64) + (%make-lisp-obj + (truly-the word (+ (get-lisp-obj-address fun) + (ash sb-vm:simple-fun-insts-offset sb-vm:word-shift) + (- sb-vm:fun-pointer-lowtag)))) + ;; all others store the function itself (what else?) in 'self' + #-(or x86 x86-64 arm64) fun)) + (setf (sb-vm::%simple-fun-self fun) self))) -(flet ((fixup (code-obj offset sym kind flavor preserved-lists statically-link-p) - (declare (ignorable statically-link-p)) +(define-load-time-global sb-fasl::*asm-routine-index-to-name* #()) +(declaim (simple-vector sb-fasl::*asm-routine-index-to-name*)) + +(flet ((fixup (code-obj offset name kind flavor preserved-lists statically-link-p + real-code-obj) + (declare (ignorable statically-link-p preserved-lists)) + ;; NAME depends on the kind and flavor of fixup. ;; PRESERVED-LISTS is a vector of lists of locations (by kind) ;; at which fixup must be re-applied after code movement. ;; CODE-OBJ must already be pinned in order to legally call this. ;; One call site that reaches here is below at MAKE-CORE-COMPONENT ;; and the other is LOAD-CODE, both of which pin the code. - ;; SYM is a little bit of a misnomer - it may be a generalized function name. - (when (sb-vm:fixup-code-object + (sb-vm:fixup-code-object code-obj offset (ecase flavor - ((:assembly-routine :assembly-routine* :asm-routine-nil-offset) - (- (or (get-asm-routine sym (eq flavor :assembly-routine*)) - (error "undefined assembler routine: ~S" sym)) - (if (eq flavor :asm-routine-nil-offset) sb-vm:nil-value 0))) - (:foreign (foreign-symbol-address sym)) - (:foreign-dataref (foreign-symbol-address sym t)) - (:code-object (get-lisp-obj-address code-obj)) - #+sb-thread (:symbol-tls-index (ensure-symbol-tls-index sym)) + ((:assembly-routine :assembly-routine*) + (or (get-asm-routine name (eq flavor :assembly-routine*)) + (error "undefined assembler routine: ~S" name))) + (:alien-code-linkage-index (sb-impl::ensure-alien-linkage-index name nil)) + (:alien-data-linkage-index (sb-impl::ensure-alien-linkage-index name t)) + (:foreign (foreign-symbol-address name)) + (:foreign-dataref (foreign-symbol-address name t)) + (:code-object (get-lisp-obj-address real-code-obj)) + #+sb-thread (:symbol-tls-index (ensure-symbol-tls-index name)) (:layout (get-lisp-obj-address - (if (symbolp sym) (find-layout sym) sym))) - (:immobile-symbol (get-lisp-obj-address sym)) - (:symbol-value (get-lisp-obj-address (symbol-global-value sym))) + (wrapper-friend (if (symbolp name) (find-layout name) name)))) + (:layout-id (layout-id name)) + #+gencgc (:gc-barrier (extern-alien "gc_card_table_nbits" int)) + (:immobile-symbol (get-lisp-obj-address name)) + ;; It is legal to take the address of symbol-value only if the + ;; value is known to be an immobile object + ;; (whose address we don't want to wire in). + (:symbol-value (get-lisp-obj-address (symbol-global-value name))) #+immobile-code - (:named-call - (prog1 (sb-vm::fdefn-entry-address sym) ; creates if didn't exist + (:fdefn-call + (prog1 (sb-vm::fdefn-entry-address name) ; creates if didn't exist (when statically-link-p - (push (cons offset (find-fdefn sym)) (elt preserved-lists 0))))) - #+immobile-code (:static-call (sb-vm::function-raw-address sym))) - kind flavor) - (ecase kind - (:relative (push offset (elt preserved-lists 1))) - (:absolute (push offset (elt preserved-lists 2))) - (:absolute64 (push offset (elt preserved-lists 3))))) - ;; These won't exist except for x86-64, but it doesn't matter. - (when (member sym '(sb-vm::enable-alloc-counter - sb-vm::enable-sized-alloc-counter)) - (push offset (elt preserved-lists 4)))) + (push (cons offset (find-fdefn name)) (elt preserved-lists 0))))) + #+immobile-code (:static-call (sb-vm::function-raw-address name))) + kind flavor)) (finish-fixups (code-obj preserved-lists) - (declare (ignorable code-obj preserved-lists)) - ;; clip to 18 significant bits for serialno regardless of machine word size - (let* ((serialno (ldb (byte 18 0) (atomic-incf sb-fasl::*code-serialno*))) - (insts (code-instructions code-obj)) - (jumptable-word (sap-ref-word insts 0))) - (aver (zerop (ash jumptable-word -14))) - ;; insert serialno - (setf (sap-ref-word insts 0) (logior (ash serialno 14) jumptable-word))) - #+(or x86 x86-64) - (let ((rel-fixups (elt preserved-lists 1)) - (abs-fixups (elt preserved-lists 2)) - (abs64-fixups (elt preserved-lists 3))) - (aver (not abs64-fixups)) ; no preserved 64-bit fixups - (when (or abs-fixups rel-fixups) - (setf (sb-vm::%code-fixups code-obj) - (sb-c:pack-code-fixup-locs abs-fixups rel-fixups)))) - (awhen (elt preserved-lists 4) - (setf (gethash code-obj *allocation-point-fixups*) - (convert-alloc-point-fixups code-obj it))) - ;; Assign all SIMPLE-FUN-SELF slots + (declare (ignorable code-obj)) + ;; Assign all SIMPLE-FUN-SELF slots unless #+darwin-jit in which case the simple-funs + ;; are assigned by jit_memcpy_codeblob() + #-darwin-jit (dotimes (i (code-n-entries code-obj)) (let ((fun (%code-entry-point code-obj i))) (assign-simple-fun-self fun) @@ -135,24 +121,39 @@ (setf (sap-ref-32 (int-sap (get-lisp-obj-address fun)) (- 4 sb-vm:fun-pointer-lowtag)) (truly-the (unsigned-byte 32) - (get-lisp-obj-address #.(find-layout 'function)))))) - ;; And finally, make the memory range executable - #-(or x86 x86-64) (sb-vm:sanctify-for-execution code-obj) + (get-lisp-obj-address (wrapper-friend #.(find-layout 'function))))))) + ;; And finally, make the memory range executable. + ;; x86 doesn't need it, and darwin-jit doesn't do it because the + ;; temporary object is not executable. + #-(or x86 x86-64 darwin-jit) (sb-vm:sanctify-for-execution code-obj) ;; Return fixups amenable to static linking (aref preserved-lists 0))) - (defun apply-fasl-fixups (fop-stack code-obj n-fixups &aux (top (svref fop-stack 0))) + (defun apply-fasl-fixups (code-obj fixups index count real-code-obj &aux (end (1- (+ index count)))) (dx-let ((preserved (make-array 5 :initial-element nil))) - (macrolet ((pop-fop-stack () `(prog1 (svref fop-stack top) (decf top)))) - (dotimes (i n-fixups (setf (svref fop-stack 0) top)) - (multiple-value-bind (offset kind flavor) - (sb-fasl::!unpack-fixup-info (pop-fop-stack)) - (fixup code-obj offset (pop-fop-stack) kind flavor - preserved nil)))) + (let ((retained-fixups (svref fixups index))) + (incf index) + (unless (eql retained-fixups 0) + (setf (sb-vm::%code-fixups code-obj) retained-fixups))) + (awhen (svref fixups index) + (setf (gethash code-obj *allocation-patch-points*) it)) + (loop + (when (>= index end) (return)) + (binding* (((offset kind flavor data) + (sb-fasl::!unpack-fixup-info (svref fixups (incf index)))) + (name + (cond ((member flavor '(:code-object :gc-barrier)) nil) + ((and (plusp data) + (member flavor '(:assembly-routine :assembly-routine*))) + (aref sb-fasl::*asm-routine-index-to-name* data)) + (t (svref fixups (incf index)))))) + (fixup code-obj offset name kind flavor preserved nil real-code-obj))) (finish-fixups code-obj preserved))) - (defun apply-core-fixups (fixup-notes code-obj) + (defun apply-core-fixups (code-obj fixup-notes retained-fixups real-code-obj) (declare (list fixup-notes)) + (unless (eql retained-fixups 0) + (setf (sb-vm::%code-fixups code-obj) retained-fixups)) (dx-let ((preserved (make-array 5 :initial-element nil))) (dolist (note fixup-notes) (let ((fixup (fixup-note-fixup note)) @@ -161,10 +162,16 @@ (fixup-name fixup) (fixup-note-kind note) (fixup-flavor fixup) - preserved t))) + preserved t + real-code-obj))) (finish-fixups code-obj preserved)))) -;;; Return a behaviorally identical copy of CODE. +;;; Return a behaviorally identical copy of CODE which is used for TRACE +;;; in "funobj encapsulation" mode where we just switch an entry point +;;; so that it jumps to a tracing routine and then back again. +;;; The code that gets copied is just the tracing wrapper. +;;; See the example at COMPILE-FUNOBJ-ENCAPSULATION in ntrace +#+(or x86 x86-64) (defun copy-code-object (code) ;; Must have one simple-fun (aver (= (code-n-entries code) 1)) @@ -174,11 +181,11 @@ #+x86-64 (aver (not (nth-value 1 (sb-c:unpack-code-fixup-locs (sb-vm::%code-fixups code))))) + (aver (zerop (nth-value 1 (sb-vm::code-header-fdefn-range code)))) (let* ((nbytes (code-object-size code)) (boxed (code-header-words code)) ; word count (unboxed (- nbytes (ash boxed sb-vm:word-shift))) ; byte count - (copy (allocate-code-object - :dynamic (code-n-named-calls code) boxed unboxed))) + (copy (allocate-code-object :dynamic boxed unboxed))) (with-pinned-objects (code copy) (%byte-blt (code-instructions code) 0 (code-instructions copy) 0 unboxed) ;; copy boxed constants so that the fixup step (if needed) sees the 'fixups' @@ -193,33 +200,6 @@ (assign-simple-fun-self (%code-entry-point copy 0))) copy)) -;;; Note the existence of FUNCTION. -(defun note-fun (info function object) - (declare (type function function) - (type core-object object)) - (let ((patch-table (core-object-patch-table object))) - (dolist (patch (gethash info patch-table)) - (setf (code-header-ref (car patch) (the index (cdr patch))) function)) - (remhash info patch-table)) - (setf (gethash info (core-object-entry-table object)) function) - (values)) - -;;; Stick a reference to the function FUN in CODE-OBJECT at index I. If the -;;; function hasn't been compiled yet, make a note in the patch table. -(defun reference-core-fun (code-obj i fun object) - (declare (type core-object object) (type functional fun) - (type index i)) - (let* ((info (leaf-info fun)) - (found (gethash info (core-object-entry-table object)))) - ;; A core component should not have cross-component references. - ;; If it could, then the entries would have placed into one component. - (aver found) - (if found - (setf (code-header-ref code-obj i) found) - (push (cons code-obj i) - (gethash info (core-object-patch-table object))))) - (values)) - ;;; Dump a component to core. We pass in the assembler fixups, code ;;; vector and node info. @@ -245,96 +225,162 @@ ;;; are 0, so the jump table count is 0. ;;; Similar considerations pertain to x86[-64] fixups within the machine code. -(defun make-core-component (component segment length fixup-notes object) +(defun code-header/trailer-adjust (code-obj expected-nwords n-fdefns) + (declare (ignorable expected-nwords n-fdefns)) + ;; Serial# shares a word with the jump-table word count, + ;; so we can't assign serial# until after all raw bytes are copied in. + ;; Do we need unique IDs on the various strange kind of code blobs? These would + ;; include code from MAKE-SIMPLIFYING-TRAMPOLINE, ENCAPSULATE-FUNOBJ, MAKE-BPT-LRA. + (let* ((serialno (ldb (byte (byte-size sb-vm::code-serialno-byte) 0) + (atomic-incf *code-serialno*))) + (insts (code-instructions code-obj)) + (jumptable-word (sap-ref-word insts 0))) + (aver (zerop (ash jumptable-word -14))) + (setf (sap-ref-word insts 0) ; insert serialno + (logior (ash serialno (byte-position sb-vm::code-serialno-byte)) + jumptable-word))) + #+64-bit + (let ((base (sap+ (int-sap (get-lisp-obj-address code-obj)) (- sb-vm:other-pointer-lowtag))) + (physical-nwords ; upper 4 bytes of the header word + (ash (get-header-data code-obj) -24))) + (setf (sap-ref-32 base (+ (ash sb-vm:code-boxed-size-slot sb-vm:word-shift) + #+little-endian 4)) + n-fdefns) + (when (/= physical-nwords expected-nwords) + ;; Oversized allocation must be exactly 2 words more than requested + (aver (= (- physical-nwords 2) expected-nwords)) + ;; Point just beyond the trailer word (physically and where it should be) + (let* ((new-trailer (sap+ base (ash physical-nwords sb-vm:word-shift))) + (old-trailer (sap+ base (ash (- physical-nwords 2) sb-vm:word-shift))) + (trailer-length (sap-ref-16 old-trailer -2)) ; in bytes + (trailer-nelements (floor trailer-length 4))) + ;; this is a memmove() and memset() + (dotimes (i trailer-nelements) + ;; Transfer 4 bytes per element (uint32_t), highest address first + ;; since we're moving upward in memory. + (let ((offset (* (1+ i) -4))) + (setf (sap-ref-32 new-trailer offset) (sap-ref-32 old-trailer offset) ))) + ;; Zeroize at most 4 elements in the "old" trailer. These will be the + ;; items at the lowest addresses (the highest indices in negative order). + ;; If there are fewer than 4 elements, then only zeroize that many. + (loop for offset from (* trailer-nelements -4) by 4 + repeat (min trailer-nelements 4) + do (setf (sap-ref-32 old-trailer offset) 0)) + ;; Increase the trailer length by 2 lispwords + (incf (sap-ref-16 new-trailer -2) (* 2 sb-vm:n-word-bytes))))) + ;; Enforce that the final unboxed data word is published to memory + ;; before the debug-info is set. + (sb-thread:barrier (:write))) + +#+darwin-jit +(defun assign-code-constants (code data) + (let* ((sb-vm::*pinned-objects* ; Pin DATA plus every element of it. + (list* code data (nconc (coerce data 'list) sb-vm::*pinned-objects*)))) + (sb-vm::jit-copy-code-constants (get-lisp-obj-address code) + (get-lisp-obj-address data)))) + +(defun make-core-component (component segment length fixup-notes alloc-points object) (declare (type component component) (type segment segment) (type index length) (list fixup-notes) (type core-object object)) - (let* ((debug-info (debug-info-for-component component)) + (binding* + ((debug-info (debug-info-for-component component)) (2comp (component-info component)) (constants (ir2-component-constants 2comp)) - (nboxed (align-up (length constants) sb-c::code-boxed-words-align)) - (code-obj (allocate-code-object - (component-mem-space component) - (count-if (lambda (x) (typep x '(cons (eql :named-call)))) - constants) - nboxed length)) - (named-call-fixups - ;; The following operations need the code pinned: - ;; 1. copying into code-instructions (a SAP) - ;; 2. apply-core-fixups and sanctify-for-execution - ;; A very specific store order is necessary to allow using uninitialized memory - ;; pages for code. Storing of the debug-info slot does not need the code pinned, - ;; but that store must occur between steps 1 and 2. - (with-pinned-objects (code-obj) - (let ((bytes (the (simple-array assembly-unit 1) - (segment-contents-as-vector segment)))) - ;; Note that this does not have to take care to ensure atomicity - ;; of the store to the final word of unboxed data. Even if BYTE-BLT were - ;; interrupted in between the store of any individual byte, this code - ;; is GC-safe because we no longer need to know where simple-funs are embedded - ;; within the object to trace pointers. We *do* need to know where the funs - ;; are when transporting the object, but it's currently pinned. - (%byte-blt bytes 0 (code-instructions code-obj) 0 (length bytes))) - ;; Enforce that the final unboxed data word is published to memory - ;; before the debug-info is set. - (sb-thread:barrier (:write)) - ;; Until debug-info is assigned, it is illegal to create a simple-fun pointer - ;; into this object, because the C code assumes that the fun table is in an - ;; invalid/incomplete state (i.e. can't be read) until the code has debug-info. - ;; That is, C code can't deal with an interior code pointer until the fun-table - ;; is valid. This store must occur prior to calling %CODE-ENTRY-POINT, and - ;; applying fixups calls %CODE-ENTRY-POINT, so we have to do this before that. - (setf (%code-debug-info code-obj) debug-info) - (apply-core-fixups fixup-notes code-obj)))) + (n-boxed-words (length constants)) + (boxed-data + ;; <header, boxed_size, debug_info, fixups> are absent from the simple-vector + (or #+darwin-jit + (make-array (- n-boxed-words sb-vm:code-constants-offset) :initial-element 0))) + (const-patch-start-index + (+ sb-vm:code-constants-offset (* (length (ir2-component-entries 2comp)) + sb-vm:code-slots-per-simple-fun))) + ;; Pre-scan for all fdefinitions to ensure their existence, which guarantees that + ;; storing them into the boxed words can't can't create an old->young pointer. + ;; This is essential since gencgc will miss them when scanning the code header + ;; for such tagged pointers. + (n-fdefns + (do ((count 0) + (index const-patch-start-index (1+ index))) + ((>= index n-boxed-words) count) + (let ((const (aref constants index))) + (when (typep const '(cons (eql :fdefinition))) + (incf count) + (setf (second const) (find-or-create-fdefn (second const))))))) + (retained-fixups (pack-retained-fixups fixup-notes)) + ((code-obj total-nwords) + (allocate-code-object (component-mem-space component) + (align-up n-boxed-words code-boxed-words-align) + length)) + (bytes + (the (simple-array assembly-unit 1) (segment-contents-as-vector segment))) + (n-simple-funs (length (ir2-component-entries 2comp))) + (named-call-fixups nil) + (real-code-obj code-obj)) + (declare (ignorable boxed-data)) + (sb-fasl::with-writable-code-instructions + (code-obj total-nwords debug-info n-fdefns n-simple-funs) + :copy (%byte-blt bytes 0 (code-instructions code-obj) 0 (length bytes)) + :fixup (setq named-call-fixups + (apply-core-fixups code-obj fixup-notes retained-fixups real-code-obj))) - ;; Don't need code pinned now - ;; (It will implicitly be pinned on the conservatively scavenged backends) - (let* ((entries (ir2-component-entries 2comp)) - (fun-index (length entries))) - (dolist (entry-info entries) - (let ((fun (%code-entry-point code-obj (decf fun-index))) - (w (+ sb-vm:code-constants-offset - (* sb-vm:code-slots-per-simple-fun fun-index)))) - (setf (code-header-ref code-obj (+ w sb-vm:simple-fun-name-slot)) - (entry-info-name entry-info) - (code-header-ref code-obj (+ w sb-vm:simple-fun-arglist-slot)) - (entry-info-arguments entry-info) - (code-header-ref code-obj (+ w sb-vm:simple-fun-source-slot)) - (entry-info-form/doc entry-info) - (code-header-ref code-obj (+ w sb-vm:simple-fun-info-slot)) - (entry-info-type/xref entry-info)) - (note-fun entry-info fun object)))) + (when alloc-points + #+(and x86-64 sb-thread) + (if (= (extern-alien "alloc_profiling" int) 0) ; record the object for later + (setf (gethash code-obj *allocation-patch-points*) alloc-points) + (funcall 'sb-aprof::patch-code code-obj alloc-points))) (push debug-info (core-object-debug-info object)) - (do ((index (+ sb-vm:code-constants-offset - (* (length (ir2-component-entries 2comp)) - sb-vm:code-slots-per-simple-fun)) - (1+ index))) - ((>= index (length constants))) - (let* ((const (aref constants index)) - (kind (if (listp const) (car const) const))) - (case kind - (:entry - (reference-core-fun code-obj index (cadr const) object)) - ((nil)) - (t - (let ((referent - (etypecase kind - ((member :named-call :fdefinition) - (find-or-create-fdefn (cadr const))) - ((eql :known-fun) - (%coerce-name-to-fun (cadr const))) - (constant - (constant-value const))))) - (if (eq kind :named-call) - (set-code-fdefn code-obj index referent) - (setf (code-header-ref code-obj index) referent))))))) - (when named-call-fixups + ;; Don't need code pinned now + ;; (It will implicitly be pinned on the conservatively scavenged backends) + (macrolet ((set-boxed-word (i val &optional fdefnp) + (declare (ignorable fdefnp)) + ;; Thankfully we don't mix untagged fdefns with darwin-jit + #+darwin-jit + `(setf (svref boxed-data (- ,i ,sb-vm:code-constants-offset)) ,val) + #-darwin-jit + (if (not fdefnp) ; statically not an fdefn + `(setf (code-header-ref code-obj ,i) ,val) + `(if ,fdefnp ; else choose which setter to use + (set-code-fdefn code-obj ,i ,val) + (setf (code-header-ref code-obj ,i) ,val))))) + + (let* ((entries (ir2-component-entries 2comp)) + (fun-index (length entries))) + (dolist (entry-info entries) + (let ((fun (%code-entry-point code-obj (decf fun-index))) + (w (+ sb-vm:code-constants-offset + (* sb-vm:code-slots-per-simple-fun fun-index)))) + (aver (functionp fun)) ; in case %CODE-ENTRY-POINT returns NIL + (set-boxed-word (+ w sb-vm:simple-fun-name-slot) (entry-info-name entry-info)) + (set-boxed-word (+ w sb-vm:simple-fun-arglist-slot) (entry-info-arguments entry-info)) + (set-boxed-word (+ w sb-vm:simple-fun-source-slot) (entry-info-form/doc entry-info)) + (set-boxed-word (+ w sb-vm:simple-fun-info-slot) (entry-info-type/xref entry-info)) + (setf (gethash entry-info (core-object-entry-table object)) fun)))) + + (do ((index const-patch-start-index (1+ index))) + ((>= index n-boxed-words)) + (let* ((const (aref constants index)) + (kind (if (listp const) (car const) const))) + (set-boxed-word + index + (etypecase kind + ((eql :entry) + (the function (gethash (leaf-info (cadr const)) + (core-object-entry-table object)))) + ((eql :fdefinition) (cadr const)) + ((eql :known-fun) (%coerce-name-to-fun (cadr const))) + (constant (constant-value const))) + (eq kind :fdefinition)))) + + #+darwin-jit (assign-code-constants code-obj boxed-data)) + + (when (and named-call-fixups (immobile-space-obj-p code-obj)) (sb-vm::statically-link-code-obj code-obj named-call-fixups)) - code-obj)) + (sb-fasl::possibly-log-new-code code-obj "core"))) (defun set-code-fdefn (code index fdefn) #+untagged-fdefns @@ -351,7 +397,6 @@ (defun fix-core-source-info (info object &optional function) (declare (type core-object object)) (declare (type (or null function) function)) - (aver (zerop (hash-table-count (core-object-patch-table object)))) (let ((source (debug-source-for-info info :function function))) (dolist (info (core-object-debug-info object)) (setf (debug-info-source info) source))) diff --git a/src/compiler/generic/type-error.lisp b/src/compiler/generic/type-error.lisp index acc2794591..ca7671f32d 100644 --- a/src/compiler/generic/type-error.lisp +++ b/src/compiler/generic/type-error.lisp @@ -44,26 +44,7 @@ (index :scs (unsigned-reg)) (value :scs (descriptor-reg))) (:arg-types simple-array-nil positive-fixnum *) - (:results (result :scs (descriptor-reg))) - (:result-types *) - (:ignore index value result) - (:vop-var vop) - (:save-p :compute-only) - (:generator 1 - (error-call vop 'nil-array-accessed-error object))) - -(define-vop (data-vector-set/simple-array-nil) - (:translate data-vector-set) - (:policy :fast-safe) - (:args (object :scs (descriptor-reg)) - (index :scs (unsigned-reg)) - (value :scs (descriptor-reg))) - (:info offset) - (:arg-types simple-array-nil positive-fixnum * - (:constant (integer 0 0))) - (:results (result :scs (descriptor-reg))) - (:result-types *) - (:ignore index value result offset) + (:ignore index value) (:vop-var vop) (:save-p :compute-only) (:generator 1 @@ -90,7 +71,7 @@ (cond ((sc-is thing immediate) (let ((obj (tn-value thing))) (typecase obj - (layout nil) + (wrapper nil) ;; non-static symbols can be referenced as error-break args ;; because they appear in the code constants. ;; static symbols can't be referenced as error-break args @@ -126,7 +107,6 @@ (def "INVALID-ARG-COUNT" sb-c::%arg-count-error nil nargs) (def "LOCAL-INVALID-ARG-COUNT" sb-c::%local-arg-count-error nil nargs fname) (def "OBJECT-NOT-TYPE" sb-c::%type-check-error t object ptype) - (def "LAYOUT-INVALID" sb-c::%layout-invalid-error nil object layout) (def "ODD-KEY-ARGS" sb-c::%odd-key-args-error nil) (def "UNKNOWN-KEY-ARG" sb-c::%unknown-key-arg-error t key) (def "ECASE-FAILURE" ecase-failure nil value keys) @@ -136,22 +116,19 @@ (def "FAILED-AVER" sb-impl::%failed-aver nil form)) -(defun emit-internal-error (kind code values &key trap-emitter - (compact-error-trap t)) - (let ((trap-number (if (and (eq kind error-trap) - compact-error-trap) +(defun emit-internal-error (kind code values &key trap-emitter) + (let ((trap-number (if (eq kind error-trap) (+ kind code) kind))) (if trap-emitter (funcall trap-emitter trap-number) (inst byte trap-number))) - (unless (and (eq kind error-trap) - compact-error-trap) + (unless (eq kind error-trap) (inst byte code)) (encode-internal-error-args values)) (defun encode-internal-error-args (values) - (sb-c::with-adjustable-vector (vector) + (with-adjustable-vector (vector) (dolist (where values) (write-var-integer ;; WHERE can be either a TN or a packed SC number + offset @@ -162,7 +139,7 @@ (make-sc+offset immediate-sc-number (tn-value where))) (t (make-sc+offset (if (and (sc-is where immediate) - (typep (tn-value where) '(or symbol layout))) + (typep (tn-value where) '(or symbol wrapper))) constant-sc-number (sc-number (tn-sc where))) (or (tn-offset where) 0)))) diff --git a/src/compiler/generic/late-type-vops.lisp b/src/compiler/generic/type-vops.lisp similarity index 55% rename from src/compiler/generic/late-type-vops.lisp rename to src/compiler/generic/type-vops.lisp index 6b1e559f55..1c6f7bbd2e 100644 --- a/src/compiler/generic/late-type-vops.lisp +++ b/src/compiler/generic/type-vops.lisp @@ -11,83 +11,63 @@ (in-package "SB-VM") -;;; FIXME: backend-specific junk doesn't belong in compiler/generic. - -#+(or x86 x86-64) -(progn -(define-vop (type-predicate) - (:args (value :scs (any-reg descriptor-reg))) - ;; x86 code has to avoid 'esi' and 'edi' for the temp - ;; since they can't be accessed as an 8-bit byte. - ;; x86-64 being more regular, any reg can serve as the temp. - ;; In all likelihood, it'll get rax anyway just because. - (:temporary (:sc unsigned-reg #+x86 :offset #+x86 eax-offset) temp) - (:conditional) - (:info target not-p) - (:args-var args) - (:policy :fast-safe)) -(define-vop (simple-type-predicate) - (:args (value :scs (any-reg descriptor-reg control-stack))) - (:conditional) - (:info target not-p) - (:args-var args) - (:policy :fast-safe)) -;; A vop that accepts a computed set of widetags. -(define-vop (%other-pointer-subtype-p type-predicate) - (:translate %other-pointer-subtype-p) - (:info target not-p widetags) - (:arg-types * (:constant t)) ; voodoo - 'target' and 'not-p' are absent - (:generator 15 ; arbitrary - (multiple-value-bind (headers except) (canonicalize-widetags+exceptions widetags) - (%test-headers value temp target not-p nil headers :except except - :value-tn-ref args))))) - -#-(or x86 x86-64) -(progn -(define-vop (type-predicate) - (:args (value :scs (any-reg descriptor-reg))) - (:temporary (:sc non-descriptor-reg) temp) - (:conditional) - (:info target not-p) - (:args-var args) - (:policy :fast-safe)) -;; A vop that accepts a computed set of widetags. -(define-vop (%other-pointer-subtype-p type-predicate) - (:translate %other-pointer-subtype-p) - (:info target not-p widetags) - (:arg-types * (:constant t)) ; voodoo - 'target' and 'not-p' are absent - (:args-var args) - (:generator 15 ; arbitrary - (%test-headers value temp target not-p nil (canonicalize-widetags widetags) - :value-tn-ref args)))) - -(defmacro define-type-vop (pred-name type-codes - &optional (inherit 'type-predicate)) +(defvar *other-pointer-type-vops* + ;; A special case due to NIL + `(symbolp (,symbol-widetag))) + +;;; We use a default definition of the vop for PRED-NAME only if it was not +;;; already defined by the backend in {arch}/type-vops. DEFINE-VOP has a compile-time +;;; effect of storing the vop name in *BACKEND-PARSED-VOPS*, so it's correct to +;;; look in that hash-table at macroexpansion time here. +;;; But due to multiple processing passes, the vop could exist in the table +;;; from its default definition, so that's gotta be allowed, or else make-host-2 +;;; would produce a null expansion for every type-vop. +(defmacro define-type-vop (pred-name type-codes) + ;; This EVAL is a bit sloppy but it (somewhat surprisingly) serves a real purpose + ;; in that you can gives the set of types code as symbols and/or integers. (let ((cost (if (> (reduce #'max type-codes :key #'eval) lowtag-limit) 7 4))) - `(define-vop (,pred-name ,inherit) - (:translate ,pred-name) - (:generator ,cost - (test-type value - ,(if (eq inherit 'simple-type-predicate) nil 'temp) - target not-p ,type-codes - :value-tn-ref args))))) - -(define-type-vop fixnump - #.fixnum-lowtags - #+(or x86-64 x86) simple-type-predicate) ;; save a register + `(progn + (let ((type-codes (list ,@type-codes))) + (when (loop for type in type-codes + never (or (< type lowtag-limit) + (memq type +immediate-types+) + (memq type +function-widetags+))) + (setf (getf *other-pointer-type-vops* ',pred-name) + (canonicalize-widetags type-codes)))) + ,(unless (awhen (gethash pred-name sb-c::*backend-parsed-vops*) + (string/= (sb-c::vop-parse-note it) "defaulted")) + `(define-vop (,pred-name type-predicate) + (:translate ,pred-name) + (:note "defaulted") + (:generator ,cost + (test-type value temp target not-p ,type-codes :value-tn-ref args))))))) + +(define-type-vop unbound-marker-p (unbound-marker-widetag)) + +(define-type-vop characterp (character-widetag)) + +(define-type-vop single-float-p (single-float-widetag)) + +(define-type-vop fixnump #.fixnum-lowtags) (define-type-vop functionp (fun-pointer-lowtag)) (define-type-vop listp (list-pointer-lowtag)) -(define-type-vop non-null-symbol-p (symbol-widetag)) - (define-type-vop %instancep (instance-pointer-lowtag)) (define-type-vop %other-pointer-p (other-pointer-lowtag)) +(define-type-vop non-null-symbol-p (symbol-widetag)) + +(define-type-vop closurep (closure-widetag)) + +(define-type-vop simple-fun-p (simple-fun-widetag)) + +(define-type-vop funcallable-instance-p (funcallable-instance-widetag)) + (define-type-vop bignump (bignum-widetag)) (define-type-vop ratiop (ratio-widetag)) @@ -106,13 +86,11 @@ (define-type-vop complex-double-float-p (complex-double-float-widetag)) -(define-type-vop single-float-p (single-float-widetag)) - (define-type-vop double-float-p (double-float-widetag)) (define-type-vop simple-string-p (#+sb-unicode simple-character-string-widetag - simple-base-string-widetag simple-array-nil-widetag)) + simple-base-string-widetag)) (macrolet ((define-simple-array-type-vops () @@ -126,14 +104,8 @@ *specialized-array-element-type-properties*)))) (define-simple-array-type-vops)) -(macrolet - ((def () - `(define-type-vop simple-rank-1-array-*-p - ,(map 'list #'saetp-typecode - *specialized-array-element-type-properties*)))) - (def)) ; simple-rank-1-array-*-p - -(define-type-vop characterp (character-widetag)) +;;; Stupid name for this because SIMPLE-VECTOR means something else. +(define-type-vop simple-rank-1-array-*-p #.+simple-rank-1-array-widetags+) (define-type-vop system-area-pointer-p (sap-widetag)) @@ -141,30 +113,21 @@ (define-type-vop code-component-p (code-header-widetag)) -#-(or x86 x86-64) (define-type-vop lra-p (return-pc-widetag)) +#-(or x86 x86-64 arm64 riscv) +(define-type-vop lra-p (return-pc-widetag)) (define-type-vop fdefn-p (fdefn-widetag)) -(define-type-vop closurep (closure-widetag)) - -(define-type-vop simple-fun-p (simple-fun-widetag)) - -(define-type-vop funcallable-instance-p (funcallable-instance-widetag)) - (define-type-vop array-header-p (simple-array-widetag #+sb-unicode complex-character-string-widetag complex-base-string-widetag complex-bit-vector-widetag - complex-vector-widetag complex-array-widetag complex-vector-nil-widetag)) + complex-vector-widetag complex-array-widetag)) (define-type-vop simple-array-header-p (simple-array-widetag)) -(define-type-vop stringp - (#+sb-unicode simple-character-string-widetag - #+sb-unicode complex-character-string-widetag - simple-base-string-widetag complex-base-string-widetag - simple-array-nil-widetag complex-vector-nil-widetag)) +(define-type-vop stringp #.+string-widetags+) (define-type-vop base-string-p (simple-base-string-widetag complex-base-string-widetag)) @@ -172,23 +135,11 @@ (define-type-vop bit-vector-p (simple-bit-vector-widetag complex-bit-vector-widetag)) -(define-type-vop vector-nil-p - (simple-array-nil-widetag complex-vector-nil-widetag)) - #+sb-unicode (define-type-vop character-string-p (simple-character-string-widetag complex-character-string-widetag)) -(define-type-vop vectorp - (complex-vector-widetag . - #.(append - (map 'list - #'saetp-typecode - *specialized-array-element-type-properties*) - (mapcan (lambda (saetp) - (when (saetp-complex-typecode saetp) - (list (saetp-complex-typecode saetp)))) - (coerce *specialized-array-element-type-properties* 'list))))) +(define-type-vop vectorp #.+vector-widetags+) ;;; Note that this "type VOP" is sort of an oddball; it doesn't so ;;; much test for a Lisp-level type as just expose a low-level type @@ -202,24 +153,9 @@ ;;; ordinary type VOPs. (define-type-vop complex-vector-p (complex-vector-widetag)) -(define-type-vop simple-array-p - (simple-array-widetag . - #.(map 'list - #'saetp-typecode - *specialized-array-element-type-properties*))) +(define-type-vop simple-array-p #.+simple-array-widetags+) -(define-type-vop arrayp - (simple-array-widetag - complex-array-widetag - complex-vector-widetag . - #.(append - (map 'list - #'saetp-typecode - *specialized-array-element-type-properties*) - (mapcan (lambda (saetp) - (when (saetp-complex-typecode saetp) - (list (saetp-complex-typecode saetp)))) - (coerce *specialized-array-element-type-properties* 'list))))) +(define-type-vop arrayp #.+array-widetags+) (define-type-vop numberp (bignum-widetag @@ -255,8 +191,6 @@ #+sb-simd-pack-256 (define-type-vop simd-pack-256-p (simd-pack-256-widetag)) -(define-type-vop unbound-marker-p (unbound-marker-widetag)) - ;;; Not type vops, but generic over all backends (macrolet ((def (name lowtag) `(define-vop () diff --git a/src/compiler/generic/utils.lisp b/src/compiler/generic/utils.lisp index eabf8e6b0f..ae1ec34d77 100644 --- a/src/compiler/generic/utils.lisp +++ b/src/compiler/generic/utils.lisp @@ -49,20 +49,22 @@ (- list-pointer-lowtag))) 0)) +(symbol-macrolet ((alien-linkage-table-space-end + (+ alien-linkage-table-space-start alien-linkage-table-space-size))) ;;; the address of the linkage table entry for table index I. -#+linkage-table -(defun linkage-table-entry-address (i) - (ecase linkage-table-growth-direction - (:up (+ (* i linkage-table-entry-size) linkage-table-space-start)) - (:down (- linkage-table-space-end (* (1+ i) linkage-table-entry-size))))) - -#+linkage-table -(defun linkage-table-index-from-address (addr) - (ecase linkage-table-growth-direction +(defun alien-linkage-table-entry-address (i) + (ecase alien-linkage-table-growth-direction + (:up (+ (* i alien-linkage-table-entry-size) alien-linkage-table-space-start)) + (:down (- alien-linkage-table-space-end (* (1+ i) alien-linkage-table-entry-size))))) + +#-sb-xc-host +(defun alien-linkage-table-index-from-address (addr) + (ecase alien-linkage-table-growth-direction (:up - (floor (- addr linkage-table-space-start) linkage-table-entry-size)) + (floor (- addr alien-linkage-table-space-start) alien-linkage-table-entry-size)) (:down - (1- (floor (- linkage-table-space-end addr) linkage-table-space-end))))) + (1- (floor (- alien-linkage-table-space-end addr) alien-linkage-table-space-end))))) +) (defconstant-eqx +all-static-fdefns+ #.(concatenate 'vector +c-callable-fdefns+ +static-fdefns+) #'equalp) @@ -92,6 +94,29 @@ (- other-pointer-lowtag) (* fdefn-raw-addr-slot n-word-bytes))) +;;; Various error-code generating helpers +(defvar *adjustable-vectors*) + +(defmacro with-adjustable-vector ((var) &rest body) + `(let ((,var (or (pop *adjustable-vectors*) + (make-array 16 + :element-type '(unsigned-byte 8) + :fill-pointer 0 + :adjustable t)))) + ;; Don't declare the length - if it gets adjusted and pushed back + ;; onto the freelist, it's anyone's guess whether it was expanded. + ;; This code was wrong for >12 years, so nobody must have needed + ;; more than 16 elements. Maybe we should make it nonadjustable? + (declare (type (vector (unsigned-byte 8)) ,var)) + (setf (fill-pointer ,var) 0) + ;; No UNWIND-PROTECT here - semantics are unaffected by nonlocal exit, + ;; and this macro is about speeding up the compiler, not slowing it down. + ;; GC will clean up any debris, and since the vector does not point + ;; to anything, even an accidental promotion to a higher generation + ;; will not cause transitive garbage retention. + (prog1 (progn ,@body) + (push ,var *adjustable-vectors*)))) + ;;;; interfaces to IR2 conversion ;;; Return a wired TN describing the N'th full call argument passing @@ -121,6 +146,38 @@ (nth n *register-arg-offsets*)) (make-sc+offset control-stack-sc-number n))) +(defstruct fixed-call-args-state + (descriptors -1 :type fixnum) + #-c-stack-is-control-stack + (non-descriptors -1 :type fixnum) + (float -1 :type fixnum)) + +(declaim (#+sb-xc-host special + #-sb-xc-host sb-ext:global + *float-regs* *descriptor-args* + #-c-stack-is-control-stack *non-descriptor-args*)) + +(defun fixed-call-arg-location (type state) + (let* ((primtype (primitive-type type)) + (sc (find descriptor-reg-sc-number (sb-c::primitive-type-scs primtype) :test-not #'eql))) + (case (primitive-type-name primtype) + ((double-float single-float) + (make-wired-tn primtype + sc + (elt *float-regs* (incf (fixed-call-args-state-float state))))) + ((unsigned-byte-64 signed-byte-64) + (make-wired-tn primtype + sc + (elt #-c-stack-is-control-stack *non-descriptor-args* + #+c-stack-is-control-stack *descriptor-args* + (incf (#-c-stack-is-control-stack fixed-call-args-state-non-descriptors + #+c-stack-is-control-stack fixed-call-args-state-descriptors + state))))) + (t + (make-wired-tn primtype + descriptor-reg-sc-number + (elt *descriptor-args* (incf (fixed-call-args-state-descriptors state)))))))) + ;;; Make a TN to hold the number-stack frame pointer. This is allocated ;;; once per component, and is component-live. (defun make-nfp-tn () @@ -132,7 +189,7 @@ ;;; Make an environment-live stack TN for saving the SP for NLX entry. (defun make-nlx-sp-tn (env) - (physenv-live-tn + (environment-live-tn (make-representation-tn *fixnum-primitive-type* any-reg-sc-number) env)) @@ -151,13 +208,14 @@ ;;; continuation within a function. (defun make-unknown-values-locations (&optional unused-count unused-sp) (declare (ignorable unused-count unused-sp)) - (list (cond #+x86-64 - ;; needs support from receive-unknown-values, push-values, %more-arg-values + (list (cond #+(or arm64 x86-64) + ;; needs support from receive-unknown-values, push-values, %more-arg-values, values-list, + ;; nlx-entry-multiple (unused-sp (sb-c::make-unused-tn)) (t (make-stack-pointer-tn))) - (cond #+x86-64 + (cond #+(or arm64 x86-64) (unused-count (sb-c::make-unused-tn)) (t @@ -181,7 +239,6 @@ ;;; Does the TN definitely hold *any* of the 4 pointer types (defun pointer-tn-ref-p (tn-ref) (and (sc-is (tn-ref-tn tn-ref) descriptor-reg) - (tn-ref-type tn-ref) (not (types-equal-or-intersect (tn-ref-type tn-ref) (specifier-type '(or fixnum @@ -197,7 +254,6 @@ ;;; Does the TN definitely hold an OTHER pointer (defun other-pointer-tn-ref-p (tn-ref) (and (sc-is (tn-ref-tn tn-ref) descriptor-reg) - (tn-ref-type tn-ref) (not (types-equal-or-intersect (tn-ref-type tn-ref) (specifier-type '(or fixnum @@ -207,13 +263,136 @@ instance character)))))) +(defun fixnum-or-other-pointer-tn-ref-p (tn-ref) + (and (sc-is (tn-ref-tn tn-ref) descriptor-reg) + (not (types-equal-or-intersect + (tn-ref-type tn-ref) + (specifier-type '(or #+64-bit single-float + function + list + instance + character)))))) + +(defun not-nil-tn-ref-p (tn-ref) + (not (types-equal-or-intersect (tn-ref-type tn-ref) + (specifier-type '(eql nil))))) + +(defun instance-tn-ref-p (tn-ref) + (csubtypep (tn-ref-type tn-ref) (specifier-type 'instance))) + +(defun stack-consed-p (object) + (let ((write (sb-c::tn-writes object))) ; list of write refs + (when (or (not write) ; grrrr, the only write is from a LOAD tn + ; and we don't know the corresponding normal TN? + (tn-ref-next write)) ; can't determine if > 1 write + (return-from stack-consed-p nil)) + (let ((vop (tn-ref-vop write))) + (when (not vop) ; wat? + (return-from stack-consed-p nil)) + (when (eq (vop-name vop) 'allocate-vector-on-stack) + (return-from stack-consed-p t)) + (when (and (eq (vop-name vop) 'fixed-alloc) + (fifth (vop-codegen-info vop))) ; STACK-ALLOCATE-P + (return-from stack-consed-p t)) + ;; Should we try to detect a stack-consed LIST also? + ;; I don't think that will work. + ;; (And is there anything else interesting to try?) + (unless (member (vop-name vop) '(splat-word splat-small splat-any)) + (return-from stack-consed-p nil)) + (let* ((splat-input (vop-args vop)) + (splat-input-source + (tn-ref-vop (sb-c::tn-writes (tn-ref-tn splat-input))))) + ;; How in the heck can there NOT be a vop??? Well, sometimes there isn't. + (when (and splat-input-source + (eq (vop-name splat-input-source) + 'allocate-vector-on-stack)) + (return-from stack-consed-p t))))) + nil) + +;;; Just gathering some data to see where we can improve +(define-load-time-global *store-barriers-potentially-emitted* 0) +(define-load-time-global *store-barriers-emitted* 0) + +(defun require-gc-store-barrier-p (object value-tn-ref value-tn) + (incf *store-barriers-potentially-emitted*) + ;; If OBJECT is stack-allocated, elide the barrier + (when (stack-consed-p object) + (return-from require-gc-store-barrier-p nil)) + (flet ((potential-heap-pointer-p (tn tn-ref) + (when (sc-is tn any-reg) ; must be fixnum + (return-from potential-heap-pointer-p nil)) + ;; If stack-allocated, elide the barrier + (when (stack-consed-p tn) + (return-from potential-heap-pointer-p nil)) + ;; If immediate non-pointer, elide the barrier + (when (sc-is tn immediate) + (let ((value (tn-value tn))) + (when (sb-xc:typep value '(or character sb-xc:fixnum boolean + #+64-bit single-float)) + (return-from potential-heap-pointer-p nil)))) + (when (sb-c::unbound-marker-tn-p tn) + (return-from potential-heap-pointer-p nil)) + ;; And elide for things like (OR FIXNUM NULL) + (let ((type (tn-ref-type tn-ref))) + (when (csubtypep type (specifier-type '(or character sb-xc:fixnum boolean + #+64-bit single-float))) + (return-from potential-heap-pointer-p nil))) + t)) + (cond (value-tn + (unless (eq (tn-ref-tn value-tn-ref) value-tn) + (aver (eq (tn-ref-load-tn value-tn-ref) value-tn))) + (unless (potential-heap-pointer-p value-tn value-tn-ref) + (return-from require-gc-store-barrier-p nil))) + (value-tn-ref ; a list of refs linked through TN-REF-ACROSS + ;; (presumably from INSTANCE-SET-MULTIPLE) + (let ((any-pointer + (do ((ref value-tn-ref (tn-ref-across ref))) + ((null ref)) + (when (potential-heap-pointer-p (tn-ref-tn ref) ref) + (return t))))) + (unless any-pointer + (return-from require-gc-store-barrier-p nil)))))) + (incf *store-barriers-emitted*) + t) + +(defun vop-nth-arg (n vop) + (let ((ref (vop-args vop))) + (dotimes (i n ref) (setq ref (tn-ref-across ref))))) + (defun length-field-shift (widetag) (if (= widetag instance-widetag) instance-length-shift n-widetag-bits)) -(defun compute-object-header (size widetag) - (logior (case widetag - (#.fdefn-widetag 0) - (t (ash (1- size) (length-field-shift widetag)))) - widetag)) +(defconstant array-rank-mask 255) +;;; Rank is encoded as a (UNSIGNED-BYTE 8) minus one. +;;; Initialization of simple rank 1 array header words is completely unaffected- +;;; they store 0 for the rank, which is the correct encoding for 1. +;;; The encoding 1 means 2, encoding 2 means 3, and so on. +;;; Decoding is just an addition and bitwise AND. +(defun encode-array-rank (rank) + (declare (type (unsigned-byte 8) rank)) + (logand (1- rank) array-rank-mask)) + +(defun compute-object-header (nwords widetag-or-metadata) + (let* ((widetag (if (typep widetag-or-metadata '(or wrapper defstruct-description)) + instance-widetag + widetag-or-metadata)) + (array-header-p + (or (= widetag simple-array-widetag) + (>= widetag complex-base-string-widetag)))) + (logior (if array-header-p + (let ((rank (- nwords array-dimensions-offset))) + (ash (encode-array-rank rank) array-rank-position)) + (case widetag + (#.fdefn-widetag 0) + (t (ash (1- nwords) (length-field-shift widetag))))) + widetag))) + +;;; Convert # of "big digits" (= words, sometimes called "limbs") to a header value. +(defmacro bignum-header-for-length (n) + (logior (ash n n-widetag-bits) bignum-widetag)) + +(defmacro id-bits-offset () + (let ((slot (get-dsd-index layout sb-kernel::id-word0))) + (ash (+ sb-vm:instance-slots-offset slot) sb-vm:word-shift))) diff --git a/src/compiler/generic/vm-array.lisp b/src/compiler/generic/vm-array.lisp index 152cce42f6..e99cf73352 100644 --- a/src/compiler/generic/vm-array.lisp +++ b/src/compiler/generic/vm-array.lisp @@ -60,25 +60,23 @@ (apply #'!make-saetp args)) `(;; Erm. Yeah. There aren't a lot of things that make sense ;; for an initial element for (ARRAY NIL). -- CSR, 2002-03-07 - (nil #:mu 0 simple-array-nil - :complex-typecode #.complex-vector-nil-widetag) + (nil #:mu 0 simple-array-nil) #-sb-unicode - (character ,(code-char 0) 8 simple-base-string + (character ,(cl:code-char 0) 8 simple-base-string ;; (SIMPLE-BASE-STRINGs are stored with an extra ;; trailing #\NULL for convenience in calling out ;; to C.) :n-pad-elements 1 :complex-typecode #.complex-base-string-widetag) #+sb-unicode - (base-char ,(code-char 0) 8 simple-base-string + (base-char ,(cl:code-char 0) 8 simple-base-string ;; (SIMPLE-BASE-STRINGs are stored with an extra ;; trailing #\NULL for convenience in calling out ;; to C.) :n-pad-elements 1 :complex-typecode #.complex-base-string-widetag) #+sb-unicode - (character ,(code-char 0) 32 simple-character-string - :n-pad-elements 1 + (character ,(cl:code-char 0) 32 simple-character-string :complex-typecode #.complex-character-string-widetag) (single-float $0.0f0 32 simple-array-single-float) (double-float $0.0d0 64 simple-array-double-float) @@ -172,16 +170,89 @@ #-sb-xc-host '#.*vector-without-complex-typecode-infos*) -;;; Return the shift amount needed to turn length into bits +;;; Return the shift amount needed to turn length as number of elements +;;; into length as number of bits. (defun saetp-n-bits-shift (saetp) (max (1- (integer-length (saetp-n-bits saetp))) 0)) ;; because of NIL +#-sb-xc-host ; not computable as constant in make-host-1 +(defconstant-eqx %%simple-array-n-bits-shifts%% + #.(let ((a (sb-xc:make-array (1+ widetag-mask) :initial-element -1 ; "illegal" + :retain-specialization-for-after-xc-core t ; what a kludge! + :element-type '(signed-byte 8)))) + (dovector (saetp *specialized-array-element-type-properties* a) + (setf (aref a (saetp-typecode saetp)) (saetp-n-bits-shift saetp)))) + #'equalp) +(defun simple-array-widetag->bits-per-elt (widetag) + #+sb-xc-host (saetp-n-bits (find widetag *specialized-array-element-type-properties* + :key #'saetp-typecode)) + #-sb-xc-host (if (= widetag simple-array-nil-widetag) + 0 + (ash 1 (aref %%simple-array-n-bits-shifts%% widetag)))) + (defun saetp-index-or-lose (element-type) (or (position element-type sb-vm:*specialized-array-element-type-properties* :key #'sb-vm:saetp-specifier :test #'equal) (error "No saetp for ~S" element-type))) +;;; I don't understand why we didn't use this more often, instead of +;;; having introduced special cases. Oh well, what's done is done. +;;; At least you can grep for SAETP-N-PAD-ELEMENTS in the comments +;;; as a signal that the padding is calculated in yet another place. +(defun vector-n-data-octets (vector saetp) + (declare (type (simple-array * (*)) vector)) + (let* ((length (+ (length vector) (saetp-n-pad-elements saetp))) + (n-bits (saetp-n-bits saetp)) + (alignment-pad (floor 7 n-bits))) + ;; This math confuses me. So there's a self-test + ;; against the C code which is known good. + (if (>= n-bits 8) + (* length (ash n-bits -3)) + (ash (* (+ length alignment-pad) n-bits) -3)))) + +;;; Access the shadow bits for a simple rank-1 array +;;; It is important that the pointer to these bits be a normal full-lispword +;;; pointer, because otherwise update_page_write_prot() would fail to see +;;; the pointer to the shadow bits. +;;; Alternatively we could place them in malloc()'ed memory +;;; but then we'd need a finalizer per array. +#+ubsan +(progn +(export '(vector-extra-data)) +(defmacro vector-extra-data (vector) + `(%primitive slot ,vector 'length 1 other-pointer-lowtag)) +(defmacro set-vector-extra-data (vector data) + `(%primitive set-slot ,vector ,data 'length 1 other-pointer-lowtag)) +(defmacro unpoison (vector) + `(set-vector-extra-data ,vector 0))) +#-ubsan +(defmacro unpoison (vector) + (declare (ignore vector))) + +;;; Return T if arrays with the given WIDETAG may contain random data +;;; initially unless expressly initialized. +;;; Some types such as SB-VM:SIMPLE-ARRAY-FIXNUM-WIDETAG must not have +;;; random bits in them because a 1 in the LSB of a word would not be +;;; a fixnum, and could lead to corruption on use. +(defun array-may-contain-random-bits-p (widetag) + (if (member widetag + `(,simple-bit-vector-widetag + ,simple-base-string-widetag + #+sb-unicode ,simple-character-string-widetag + ,simple-array-unsigned-byte-2-widetag + ,simple-array-unsigned-byte-4-widetag + ,simple-array-unsigned-byte-8-widetag + ,simple-array-unsigned-byte-16-widetag + ,simple-array-unsigned-byte-32-widetag + #+64-bit ,simple-array-unsigned-byte-64-widetag + ,simple-array-signed-byte-8-widetag + ,simple-array-signed-byte-16-widetag + ,simple-array-signed-byte-32-widetag + #+64-bit ,simple-array-signed-byte-64-widetag)) + t + nil)) + (in-package "SB-C") (defun find-saetp (element-type) diff --git a/src/compiler/generic/vm-fndb.lisp b/src/compiler/generic/vm-fndb.lisp index 4215d269d4..e11da354e7 100644 --- a/src/compiler/generic/vm-fndb.lisp +++ b/src/compiler/generic/vm-fndb.lisp @@ -28,7 +28,7 @@ array-header-p simple-array-header-p sequencep extended-sequence-p - simple-array-p simple-array-nil-p vector-nil-p + simple-array-p simple-array-nil-p simple-array-unsigned-byte-2-p simple-array-unsigned-byte-4-p simple-array-unsigned-byte-7-p simple-array-unsigned-byte-8-p simple-array-unsigned-byte-15-p @@ -56,14 +56,11 @@ #+long-float simple-array-complex-long-float-p simple-rank-1-array-*-p system-area-pointer-p realp - ;; #-64-bit + signed-byte-8-p signed-byte-16-p unsigned-byte-32-p - ;; #-64-bit signed-byte-32-p - #+64-bit - unsigned-byte-64-p - #+64-bit - signed-byte-64-p + #+64-bit unsigned-byte-64-p + #+64-bit signed-byte-64-p weak-pointer-p code-component-p lra-p sb-int:unbound-marker-p pointerp @@ -74,10 +71,7 @@ non-null-symbol-p) (t) boolean (movable foldable flushable)) -(defknown (fixnump-instance-ref) (instance index) boolean - (flushable always-translatable)) -(defknown (fixnump-car fixnump-cdr) (list) boolean - (flushable always-translatable)) +(defknown car-eq-if-listp (t t) boolean (movable foldable flushable)) (defknown #.(loop for (name) in *vector-without-complex-typecode-infos* collect name) @@ -100,16 +94,31 @@ (defknown pointer-hash (t) fixnum (flushable)) (defknown %sp-string-compare - (simple-string index (or null index) simple-string index (or null index)) + (simple-string simple-string index (or null index) index (or null index)) (values index fixnum) - (foldable flushable)) - + (foldable flushable no-verify-arg-count)) +(defknown %sp-string= + (simple-string simple-string index (or null index) index (or null index)) + boolean + (foldable flushable no-verify-arg-count)) + +(defknown (sb-impl::instance-sxhash sb-impl::%instance-sxhash) + (instance) hash-code (flushable)) +;;; SXHASH values on numbers and strings are predictable, therefore the next batch +;;; of functions are flushable. Perhaps not entirely obviously, symbol hashes are +;;; predictable because we hash by name. And while ENSURE-SYMBOL-HASH is not +;;; - strictly speaking - a side-effectless operation, it has no effect as far as +;;; user-written code is concerned. i.e. nothing portably expressed can discern +;;; whether memoization of the hash occurred. (I feel like we would have a cleaner +;;; implementation if we just eagerly compute the hash anyway. Practically all +;;; symbols eventually get hashed) +(defknown sb-impl::number-sxhash (number) hash-code (foldable flushable)) (defknown %sxhash-string (string) hash-code (foldable flushable)) (defknown %sxhash-simple-string (simple-string) hash-code (foldable flushable)) (defknown (%sxhash-simple-substring) (simple-string index index) hash-code (foldable flushable)) -(defknown (compute-symbol-hash) (simple-string index) hash-code +(defknown sb-impl::compute-symbol-hash (simple-string index) hash-code (foldable flushable)) (defknown (symbol-hash ensure-symbol-hash) (symbol) hash-code @@ -127,7 +136,15 @@ (defknown %set-symbol-hash (symbol hash-code) t ()) -(defknown symbol-info-vector (symbol) (or null simple-vector)) +;;; SYMBOL-PACKAGE-ID for #+compact-symbol demands a vop which avoids loading +;;; a raw bit value in a descriptor register (the SLOT vop returns a descriptor) +(defknown sb-impl::symbol-package-id (symbol) (unsigned-byte 16)) +;;; TODO: I'd like to eliminate the (OR NULL) from this return type. +;;; For that to happen, I probably need +nil-packed-infos+ to become +;;; placed in static space because assembly routines may need it. +;;; On the other hand, they may not, because there is no special case +;;; code needed when reading from it, which is entire point. +(defknown symbol-dbinfo (symbol) (or null packed-info)) (defknown initialize-vector ((simple-array * (*)) &rest t) (simple-array * (*)) @@ -135,7 +152,7 @@ :result-arg 0) (defknown (vector-fill* vector-fill/t) (t t t t) vector - () + (no-verify-arg-count) :result-arg 0) ;;; Return the length of VECTOR. @@ -162,48 +179,64 @@ (defknown (function-header-word) (function) sb-vm:word (flushable)) (defknown (instance-header-word) (instance) sb-vm:word (flushable)) -;;; This unconventional setter returns its first arg, not the newval. (defknown set-header-data - (t (unsigned-byte #.(- sb-vm:n-word-bits sb-vm:n-widetag-bits))) t) -;;; Perform a bitwise OR or AND-not of the existing header data with -;;; the new bits and return no value. -(defknown (set-header-bits unset-header-bits) - (t (unsigned-byte #.(- sb-vm:n-word-bits sb-vm:n-widetag-bits))) (values) - ()) + (t (unsigned-byte #.(- sb-vm:n-word-bits sb-vm:n-widetag-bits))) (values)) +;;; Like SET-HEADER-DATA, but instead of writing the entire header, +;;; LOGIOR of the specified value into the "data" portion of the word. +;;; Returns the first argument, *not* the modified header data. +(defknown logior-header-bits (t (unsigned-byte 16)) t + (#+x86-64 always-translatable)) +;;; ASSIGN-VECTOR-FLAGSS assign all and only the flags byte. +;;; RESET- performs LOGANDC2 and returns no value. +(defknown (assign-vector-flags reset-header-bits) + (t (unsigned-byte 16)) (values) + (#+x86-64 always-translatable)) +;;; test bits of "HeaderData" which start 8 bits over from the lsb +(defknown (test-header-data-bit) + (t (unsigned-byte #.(- sb-vm:n-word-bits sb-vm:n-widetag-bits))) (boolean) + (flushable)) (defknown %array-dimension (array index) index (flushable)) -(defknown %set-array-dimension (array index index) index +(defknown %set-array-dimension (array index index) (values) ()) (defknown %array-rank (array) array-rank (flushable)) -#+x86-64 +#+(or x86 x86-64 arm64) (defknown (%array-rank= widetag=) (t t) boolean (flushable)) +(defknown simple-array-header-of-rank-p (t array-rank) boolean + (flushable)) (defknown sb-kernel::check-array-shape (simple-array list) (simple-array) - (flushable) + (flushable no-verify-arg-count) :result-arg 0) -(defknown %make-instance (index) instance +(defknown (%make-instance %make-instance/mixed) (index) instance (flushable)) (defknown %make-structure-instance (defstruct-description list &rest t) instance (flushable always-translatable)) (defknown (%copy-instance %copy-instance-slots) (instance instance) instance () :result-arg 0) -(defknown %instance-layout (instance) layout - (foldable flushable)) +(defknown %instance-layout (instance) sb-vm:layout (foldable flushable)) +(defknown %instance-wrapper (instance) wrapper (foldable flushable)) ;;; %FUN-LAYOUT is to %INSTANCE-LAYOUT as FUN-POINTER-LOWTAG is to INSTANCE-POINTER-LOWTAG (defknown %fun-layout (#-compact-instance-header funcallable-instance #+compact-instance-header function) - layout + sb-vm:layout (foldable flushable)) +(defknown %fun-wrapper (#-compact-instance-header funcallable-instance + #+compact-instance-header function) + wrapper (foldable flushable)) -(defknown %set-instance-layout (instance layout) layout - ()) -(defknown %set-funcallable-instance-layout (funcallable-instance layout) layout - ()) +(defknown %set-instance-layout (instance sb-vm:layout) (values) ()) +;;; %SET-FUN-LAYOUT should only called on FUNCALLABLE-INSTANCE +(defknown %set-fun-layout (funcallable-instance sb-vm:layout) (values) ()) +;;; Layout getter that accepts any object, and if it has INSTANCE- or FUN- +;;; POINTER-LOWTAG returns the layout, otherwise some agreed-upon layout. +(defknown %instanceoid-layout (t) sb-vm:layout (flushable)) +(defknown layout-eq ((or instance function) t (mod 16)) boolean (flushable)) ;;; Caution: This is not exactly the same as instance_length() in C. ;;; The C one is the same as SB-VM::INSTANCE-LENGTH. (defknown %instance-length (instance) (unsigned-byte 14) (foldable flushable)) @@ -212,39 +245,31 @@ (flushable always-translatable)) (defknown (%instance-ref-eq) (instance index t) boolean (flushable always-translatable)) -(defknown %instance-set (instance index t) t - (always-translatable) - :derive-type #'result-type-last-arg) -(defknown %layout-invalid-error (t layout) nil) -(defknown update-object-layout-or-invalid (t layout) layout) +(defknown %instance-set (instance index t) (values) (always-translatable)) +(defknown update-object-layout (t) sb-vm:layout) -#+(or x86 x86-64 riscv) +#+(or arm64 ppc ppc64 riscv x86 x86-64) (defknown %raw-instance-cas/word (instance index sb-vm:word sb-vm:word) sb-vm:word ()) -#+riscv +#+(or arm64 riscv x86 x86-64) (defknown %raw-instance-cas/signed-word (instance index sb-vm:signed-word sb-vm:signed-word) sb-vm:signed-word ()) - -#.`(progn - ,@(map 'list - (lambda (rsd) - (let* ((reader (sb-kernel::raw-slot-data-accessor-name rsd)) - (name (copy-seq (string reader))) - (writer (intern (replace name "-SET/" - :start1 (search "-REF/" name)))) - (type (sb-kernel::raw-slot-data-raw-type rsd))) - `(progn - (defknown ,reader (instance index) ,type - (flushable always-translatable)) - (defknown ,writer (instance index ,type) ,type - (always-translatable) :derive-type #'result-type-last-arg) - ;; Interpreter stubs, harmless but unnecessary on host - #-sb-xc-host - (progn (defun ,reader (instance index) - (,reader instance index)) - (defun ,writer (instance index new-value) - (,writer instance index new-value)))))) - sb-kernel::*raw-slot-data*)) +(defknown %raw-instance-xchg/word (instance index sb-vm:word) sb-vm:word ()) + +(macrolet ((define-raw-slot-defknowns () + `(progn + ,@(map 'list + (lambda (rsd) + (let* ((reader (sb-kernel::raw-slot-data-reader-name rsd)) + (writer (sb-kernel::raw-slot-data-writer-name rsd)) + (type (sb-kernel::raw-slot-data-raw-type rsd))) + `(progn + (defknown ,reader (instance index) ,type + (flushable always-translatable)) + (defknown ,writer (instance index ,type) (values) + (always-translatable))))) + sb-kernel::*raw-slot-data*)))) + (define-raw-slot-defknowns)) #+compare-and-swap-vops (defknown %raw-instance-atomic-incf/word (instance index sb-vm:word) sb-vm:word @@ -256,15 +281,23 @@ ;;; These two are mostly used for bit-bashing operations. (defknown %vector-raw-bits (t index) sb-vm:word (flushable)) -(defknown (%set-vector-raw-bits) (t index sb-vm:word) sb-vm:word - ()) +(defknown (%set-vector-raw-bits) (t index sb-vm:word) (values) ()) ;;; Allocate an unboxed, non-fancy vector with type code TYPE, length LENGTH, ;;; and WORDS words long. Note: it is your responsibility to ensure that the ;;; relation between LENGTH and WORDS is correct. -;;; The extra bit beyond N_WIDETAG_BITS is for the vector weakness flag. -(defknown allocate-vector ((unsigned-byte 9) index +;;; Note that in almost all situations the first argument (TYPE) is a constant. +;;; There are only 3 places that it can be non-constant, and not at all +;;; after self-build is complete. The three non-constant places are from: +;;; - ALLOCATE-VECTOR-WITH-WIDETAG in src/code/array +;;; - ALLOCATE-VECTOR (which is basically a stub) in src/code/array +;;; - FOP-SPEC-VECTOR which calls allocate-vector +;;; Apart from those, user code that does not have a compile-time-determined +;;; vector type will usuallly end up calling allocate-vector-with-widetag +;;; via %MAKE-ARRAY. +(defknown allocate-vector (#+ubsan boolean + word index ;; The number of words is later converted ;; to bytes, make sure it fits. (and index @@ -281,7 +314,7 @@ (flushable movable)) ;;; Allocate an array header with type code TYPE and rank RANK. -(defknown make-array-header ((unsigned-byte 8) (mod #.sb-xc:array-rank-limit)) array +(defknown make-array-header ((unsigned-byte 8) (mod #.array-rank-limit)) array (flushable movable)) (defknown make-array-header* (&rest t) array (flushable movable)) @@ -319,14 +352,30 @@ (flushable movable foldable)) (defknown %make-simd-pack-ub32 ((unsigned-byte 32) (unsigned-byte 32) (unsigned-byte 32) (unsigned-byte 32)) - (simd-pack integer) - (flushable movable foldable)) + (simd-pack (unsigned-byte 32)) + (flushable movable #-sb-xc-host foldable)) (defknown %make-simd-pack-ub64 ((unsigned-byte 64) (unsigned-byte 64)) - (simd-pack integer) - (flushable movable foldable)) + (simd-pack (unsigned-byte 64)) + (flushable movable #-sb-xc-host foldable)) (defknown (%simd-pack-low %simd-pack-high) (simd-pack) (unsigned-byte 64) (flushable movable foldable)) + (defknown %simd-pack-ub8s (simd-pack) + (values (unsigned-byte 8) (unsigned-byte 8) + (unsigned-byte 8) (unsigned-byte 8) + (unsigned-byte 8) (unsigned-byte 8) + (unsigned-byte 8) (unsigned-byte 8) + (unsigned-byte 8) (unsigned-byte 8) + (unsigned-byte 8) (unsigned-byte 8) + (unsigned-byte 8) (unsigned-byte 8) + (unsigned-byte 8) (unsigned-byte 8)) + (flushable movable foldable)) + (defknown %simd-pack-ub16s (simd-pack) + (values (unsigned-byte 16) (unsigned-byte 16) + (unsigned-byte 16) (unsigned-byte 16) + (unsigned-byte 16) (unsigned-byte 16) + (unsigned-byte 16) (unsigned-byte 16)) + (flushable movable foldable)) (defknown %simd-pack-ub32s (simd-pack) (values (unsigned-byte 32) (unsigned-byte 32) (unsigned-byte 32) (unsigned-byte 32)) @@ -334,6 +383,29 @@ (defknown %simd-pack-ub64s (simd-pack) (values (unsigned-byte 64) (unsigned-byte 64)) (flushable movable foldable)) + (defknown %simd-pack-sb8s (simd-pack) + (values (signed-byte 8) (signed-byte 8) + (signed-byte 8) (signed-byte 8) + (signed-byte 8) (signed-byte 8) + (signed-byte 8) (signed-byte 8) + (signed-byte 8) (signed-byte 8) + (signed-byte 8) (signed-byte 8) + (signed-byte 8) (signed-byte 8) + (signed-byte 8) (signed-byte 8)) + (flushable movable foldable)) + (defknown %simd-pack-sb16s (simd-pack) + (values (signed-byte 16) (signed-byte 16) + (signed-byte 16) (signed-byte 16) + (signed-byte 16) (signed-byte 16) + (signed-byte 16) (signed-byte 16)) + (flushable movable foldable)) + (defknown %simd-pack-sb32s (simd-pack) + (values (signed-byte 32) (signed-byte 32) + (signed-byte 32) (signed-byte 32)) + (flushable movable foldable)) + (defknown %simd-pack-sb64s (simd-pack) + (values (signed-byte 64) (signed-byte 64)) + (flushable movable foldable)) (defknown %simd-pack-singles (simd-pack) (values single-float single-float single-float single-float) (flushable movable foldable)) @@ -358,14 +430,30 @@ (flushable movable foldable)) (defknown %make-simd-pack-256-ub32 ((unsigned-byte 32) (unsigned-byte 32) (unsigned-byte 32) (unsigned-byte 32) (unsigned-byte 32) (unsigned-byte 32) (unsigned-byte 32) (unsigned-byte 32)) - (simd-pack-256 integer) + (simd-pack-256 (unsigned-byte 32)) (flushable movable foldable)) (defknown %make-simd-pack-256-ub64 ((unsigned-byte 64) (unsigned-byte 64) (unsigned-byte 64) (unsigned-byte 64)) - (simd-pack-256 integer) + (simd-pack-256 (unsigned-byte 64)) (flushable movable foldable)) (defknown (%simd-pack-256-0 %simd-pack-256-1 %simd-pack-256-2 %simd-pack-256-3) (simd-pack-256) (unsigned-byte 64) (flushable movable foldable)) + (defknown %simd-pack-256-ub8s (simd-pack-256) + (values (unsigned-byte 8) (unsigned-byte 8) (unsigned-byte 8) (unsigned-byte 8) + (unsigned-byte 8) (unsigned-byte 8) (unsigned-byte 8) (unsigned-byte 8) + (unsigned-byte 8) (unsigned-byte 8) (unsigned-byte 8) (unsigned-byte 8) + (unsigned-byte 8) (unsigned-byte 8) (unsigned-byte 8) (unsigned-byte 8) + (unsigned-byte 8) (unsigned-byte 8) (unsigned-byte 8) (unsigned-byte 8) + (unsigned-byte 8) (unsigned-byte 8) (unsigned-byte 8) (unsigned-byte 8) + (unsigned-byte 8) (unsigned-byte 8) (unsigned-byte 8) (unsigned-byte 8) + (unsigned-byte 8) (unsigned-byte 8) (unsigned-byte 8) (unsigned-byte 8)) + (flushable movable foldable)) + (defknown %simd-pack-256-ub16s (simd-pack-256) + (values (unsigned-byte 16) (unsigned-byte 16) (unsigned-byte 16) (unsigned-byte 16) + (unsigned-byte 16) (unsigned-byte 16) (unsigned-byte 16) (unsigned-byte 16) + (unsigned-byte 16) (unsigned-byte 16) (unsigned-byte 16) (unsigned-byte 16) + (unsigned-byte 16) (unsigned-byte 16) (unsigned-byte 16) (unsigned-byte 16)) + (flushable movable foldable)) (defknown %simd-pack-256-ub32s (simd-pack-256) (values (unsigned-byte 32) (unsigned-byte 32) (unsigned-byte 32) (unsigned-byte 32) (unsigned-byte 32) (unsigned-byte 32) (unsigned-byte 32) (unsigned-byte 32)) @@ -373,6 +461,29 @@ (defknown %simd-pack-256-ub64s (simd-pack-256) (values (unsigned-byte 64) (unsigned-byte 64) (unsigned-byte 64) (unsigned-byte 64)) (flushable movable foldable)) + (defknown %simd-pack-256-sb8s (simd-pack-256) + (values (signed-byte 8) (signed-byte 8) (signed-byte 8) (signed-byte 8) + (signed-byte 8) (signed-byte 8) (signed-byte 8) (signed-byte 8) + (signed-byte 8) (signed-byte 8) (signed-byte 8) (signed-byte 8) + (signed-byte 8) (signed-byte 8) (signed-byte 8) (signed-byte 8) + (signed-byte 8) (signed-byte 8) (signed-byte 8) (signed-byte 8) + (signed-byte 8) (signed-byte 8) (signed-byte 8) (signed-byte 8) + (signed-byte 8) (signed-byte 8) (signed-byte 8) (signed-byte 8) + (signed-byte 8) (signed-byte 8) (signed-byte 8) (signed-byte 8)) + (flushable movable foldable)) + (defknown %simd-pack-256-sb16s (simd-pack-256) + (values (signed-byte 16) (signed-byte 16) (signed-byte 16) (signed-byte 16) + (signed-byte 16) (signed-byte 16) (signed-byte 16) (signed-byte 16) + (signed-byte 16) (signed-byte 16) (signed-byte 16) (signed-byte 16) + (signed-byte 16) (signed-byte 16) (signed-byte 16) (signed-byte 16)) + (flushable movable foldable)) + (defknown %simd-pack-256-sb32s (simd-pack-256) + (values (signed-byte 32) (signed-byte 32) (signed-byte 32) (signed-byte 32) + (signed-byte 32) (signed-byte 32) (signed-byte 32) (signed-byte 32)) + (flushable movable foldable)) + (defknown %simd-pack-256-sb64s (simd-pack-256) + (values (signed-byte 64) (signed-byte 64) (signed-byte 64) (signed-byte 64)) + (flushable movable foldable)) (defknown %simd-pack-256-singles (simd-pack-256) (values single-float single-float single-float single-float single-float single-float single-float single-float) @@ -400,8 +511,10 @@ system-area-pointer (flushable)) (defknown (current-sp current-fp) () system-area-pointer (flushable)) (defknown current-fp-fixnum () fixnum (flushable)) +;; STACK-REF is pretty nearly just SAP-REF-LISPOBJ except that +;; it takes a word index, not a byte displacement from the SAP. (defknown stack-ref (system-area-pointer index) t (flushable)) -(defknown %set-stack-ref (system-area-pointer index t) t ()) +(defknown %set-stack-ref (system-area-pointer index t) (values) ()) (defknown lra-code-header (t) t (movable flushable)) ;; FUN-CODE-HEADER returns NIL for assembly routines that have a simple-fun header ;; with 0 as the data value. We should probably ensure that assembly routines @@ -431,62 +544,102 @@ ;;;; bignum operations (defknown %allocate-bignum (bignum-length) bignum - (flushable)) + (flushable #-bignum-assertions always-translatable)) -(defknown %bignum-length (bignum) bignum-length - (foldable flushable)) +(defknown %bignum-length (bignum) (and (integer 1) bignum-length) + (foldable flushable always-translatable)) -(defknown %bignum-set-length (bignum bignum-length) bignum - ()) +;;; Change the length of bignum to be newlen. Newlen must be the same or +;;; smaller than the old length, and any elements beyond newlen must be zeroed. +(defknown %bignum-set-length (bignum bignum-length) (values) + (always-translatable)) (defknown %bignum-ref (bignum bignum-index) bignum-element-type - (flushable)) + (flushable #-bignum-assertions always-translatable)) + #+(or x86 x86-64) (defknown %bignum-ref-with-offset (bignum fixnum (signed-byte 24)) bignum-element-type (flushable always-translatable)) -(defknown %bignum-set (bignum bignum-index bignum-element-type) - bignum-element-type - ()) +(defknown (%bignum-set #+bignum-assertions %%bignum-set) (bignum bignum-index bignum-element-type) + (values) + (#-bignum-assertions always-translatable)) + +(defknown %half-bignum-ref (bignum sb-kernel::half-bignum-index) sb-kernel::half-bignum-element-type + (flushable #-bignum-assertions always-translatable)) +(defknown (setf %half-bignum-ref) (sb-kernel::half-bignum-element-type bignum sb-kernel::half-bignum-index) + (values) + (#-bignum-assertions always-translatable)) + +;;; Return T if digit is positive, or NIL if negative. (defknown %digit-0-or-plusp (bignum-element-type) boolean - (foldable flushable movable)) + (foldable flushable movable always-translatable)) +;;; %ADD-WITH-CARRY returns a bignum digit and a carry resulting from adding +;;; together a, b, and an incoming carry. +;;; %SUBTRACT-WITH-BOROW returns a bignum digit and a borrow resulting from +;;; subtracting b from a, and subtracting a possible incoming borrow. (defknown (%add-with-carry %subtract-with-borrow) - (bignum-element-type bignum-element-type (mod 2)) - (values bignum-element-type (mod 2)) - (foldable flushable movable)) - + (bignum-element-type bignum-element-type (mod 2)) + (values bignum-element-type (mod 2)) + (foldable flushable movable always-translatable)) + +;;; This multiplies x-digit and y-digit, producing high and low digits +;;; manifesting the result. Then it adds the low digit, res-digit, and +;;; carry-in-digit. Any carries (note, you still have to add two digits +;;; at a time possibly producing two carries) from adding these three +;;; digits get added to the high digit from the multiply, producing the +;;; next carry digit. Res-digit is optional since two uses of this +;;; primitive multiplies a single digit bignum by a multiple digit +;;; bignum, and in this situation there is no need for a result buffer +;;; accumulating partial results which is where the res-digit comes +;;; from. (defknown %multiply-and-add - (bignum-element-type bignum-element-type bignum-element-type - &optional bignum-element-type) - (values bignum-element-type bignum-element-type) - (foldable flushable movable)) + (bignum-element-type bignum-element-type bignum-element-type + &optional bignum-element-type) + (values bignum-element-type bignum-element-type) + (foldable flushable movable always-translatable)) +;;; Multiply two digit-size numbers, returning a 2*digit-size result +;;; split into two digit-size quantities. (defknown %multiply (bignum-element-type bignum-element-type) - (values bignum-element-type bignum-element-type) - (foldable flushable movable)) + (values bignum-element-type bignum-element-type) + (foldable flushable movable always-translatable)) (defknown %lognot (bignum-element-type) bignum-element-type - (foldable flushable movable)) + (foldable flushable movable always-translatable)) (defknown (%logand %logior %logxor) (bignum-element-type bignum-element-type) bignum-element-type (foldable flushable movable)) (defknown %fixnum-to-digit (fixnum) bignum-element-type - (foldable flushable movable)) + (foldable flushable movable #-(or arm arm64) always-translatable)) +;;; This takes three digits and returns the FLOOR'ed result of +;;; dividing the first two as a 2*digit-size integer by the third. (defknown %bigfloor (bignum-element-type bignum-element-type bignum-element-type) (values bignum-element-type bignum-element-type) - (foldable flushable movable)) + (foldable flushable movable always-translatable)) + +(defknown %half-bigfloor (half-bignum-element-type half-bignum-element-type half-bignum-element-type) + (values half-bignum-element-type half-bignum-element-type) + (foldable flushable movable always-translatable)) +;;; Convert the input, a BIGNUM-ELEMENT-TYPE, to a signed word. +;;; FIXME: considering that both the input and output have N-WORD-BITS significant bits, +;;; this is really a bad name for the operation. (defknown %fixnum-digit-with-correct-sign (bignum-element-type) sb-vm:signed-word - (foldable flushable movable)) + (foldable flushable movable always-translatable)) +;;; %ASHR- take a digit-size quantity and shift it to the left, +;;; returning a digit-size quantity. +;;; %ASHR- Do an arithmetic shift right of data even though bignum-element-type is +;;; unsigned. (defknown (%ashl %ashr %digit-logical-shift-right) (bignum-element-type (mod #.sb-vm:n-word-bits)) bignum-element-type - (foldable flushable movable)) + (foldable flushable movable always-translatable)) ;;;; bit-bashing routines @@ -530,13 +683,13 @@ ;;; Extract the INDEXth element from the header of CODE-OBJ. Can be ;;; set with SETF. (defknown code-header-ref (code-component index) t (flushable)) -(defknown code-header-set (code-component index t) t ()) +(defknown code-header-set (code-component index t) (values) ()) ;;; Extract a 4-byte element relative to the end of CODE-OBJ. ;;; The index should be strictly negative and a multiple of 4. (defknown code-trailer-ref (code-component fixnum) (unsigned-byte 32) - (flushable #-(or sparc alpha hppa ppc64) always-translatable)) + (flushable #-(or sparc ppc64) always-translatable)) -(defknown fun-subtype (function) (member . #.sb-vm::+function-widetags+) +(defknown %fun-pointer-widetag (function) (member . #.sb-vm::+function-widetags+) (flushable)) (defknown make-fdefn (t) fdefn (flushable movable)) @@ -544,17 +697,18 @@ (defknown fdefn-name (fdefn) t (foldable flushable)) (defknown fdefn-fun (fdefn) (or function null) (flushable)) (defknown (setf fdefn-fun) (function fdefn) t ()) -(defknown fdefn-makunbound (fdefn) t ()) +(defknown fdefn-makunbound (fdefn) (values) ()) ;;; FDEFN -> FUNCTION, trapping if not FBOUNDP (defknown safe-fdefn-fun (fdefn) function ()) (defknown %simple-fun-type (function) t (flushable)) -#+(or x86 x86-64) (defknown sb-vm::%closure-callee (function) fixnum (flushable)) +#+(or x86 x86-64 arm64) (defknown sb-vm::%closure-callee (function) fixnum (flushable)) (defknown %closure-fun (function) function (flushable)) (defknown %closure-index-ref (function index) t (flushable)) +(defknown %closure-index-set (function index t) (values) ()) ;; T argument is for the 'fun' slot. (defknown sb-vm::%alloc-closure (index t) function (flushable)) @@ -565,7 +719,8 @@ ()) (defknown %funcallable-instance-info (function index) t (flushable)) -(defknown %set-funcallable-instance-info (function index t) t ()) +(defknown (setf %funcallable-instance-info) (t function index) t ()) +(defknown %set-funcallable-instance-info (function index t) (values) ()) #+sb-fasteval (defknown sb-interpreter:fun-proto-fn (interpreted-function) @@ -580,8 +735,15 @@ ;;; formerly in 'float-tran' -(defknown %single-float (real) single-float (movable foldable)) -(defknown %double-float (real) double-float (movable foldable)) +(defknown %single-float (real) single-float + (movable foldable no-verify-arg-count)) +(defknown %double-float (real) double-float + (movable foldable no-verify-arg-count)) + +(defknown bignum-to-float (bignum symbol) float + (movable foldable no-verify-arg-count)) +(defknown sb-kernel::float-ratio (ratio symbol) float + (movable foldable no-verify-arg-count)) (defknown make-single-float ((signed-byte 32)) single-float (movable flushable)) @@ -615,12 +777,12 @@ (defknown (%asin %atan) (double-float) - (double-float #.(coerce (sb-xc:- (sb-xc:/ sb-xc:pi 2)) 'double-float) - #.(coerce (sb-xc:/ sb-xc:pi 2) 'double-float)) + (double-float #.(coerce (sb-xc:- (sb-xc:/ pi 2)) 'double-float) + #.(coerce (sb-xc:/ pi 2) 'double-float)) (movable foldable flushable)) (defknown (%acos) - (double-float) (double-float $0.0d0 #.(coerce sb-xc:pi 'double-float)) + (double-float) (double-float $0.0d0 #.(coerce pi 'double-float)) (movable foldable flushable)) (defknown (%cosh) @@ -645,8 +807,8 @@ (defknown (%atan2) (double-float double-float) - (double-float #.(coerce (sb-xc:- sb-xc:pi) 'double-float) - #.(coerce sb-xc:pi 'double-float)) + (double-float #.(coerce (sb-xc:- pi) 'double-float) + #.(coerce pi 'double-float)) (movable foldable flushable)) (defknown (%scalb) @@ -662,4 +824,4 @@ (movable foldable flushable)) (defknown (%unary-truncate %unary-round) (real) integer - (movable foldable flushable)) + (movable foldable flushable no-verify-arg-count)) diff --git a/src/compiler/generic/vm-ir2tran.lisp b/src/compiler/generic/vm-ir2tran.lisp index 21fec0c61e..89566fd68d 100644 --- a/src/compiler/generic/vm-ir2tran.lisp +++ b/src/compiler/generic/vm-ir2tran.lisp @@ -12,32 +12,34 @@ (def-alloc '%make-structure-instance 1 :structure-alloc sb-vm:instance-widetag sb-vm:instance-pointer-lowtag nil) +(def-alloc '%make-instance/mixed 1 :var-alloc + sb-vm:instance-widetag sb-vm:instance-pointer-lowtag nil) -#+stack-allocatable-fixed-objects (defoptimizer (%make-structure-instance stack-allocate-result) - ((defstruct-description &rest args) node dx) - (declare (ignore args dx)) + ((defstruct-description &rest args)) (aver (constant-lvar-p defstruct-description)) ;; A structure instance can be stack-allocated if it has no raw ;; slots, or if we're on a target with a conservatively-scavenged ;; stack. We have no reader conditional for stack conservation, but ;; it turns out that the only time stack conservation is in play is - ;; when we're on GENCGC (since CHENEYGC doesn't have conservation) - ;; and C-STACK-IS-CONTROL-STACK (otherwise, the C stack is the + ;; C-STACK-IS-CONTROL-STACK (otherwise, the C stack is the ;; number stack, and we precisely-scavenge the control stack). - #-(and :gencgc :c-stack-is-control-stack) - (every (lambda (x) (eq (dsd-raw-type x) t)) - (dd-slots (lvar-value defstruct-description))) - #+(and :gencgc :c-stack-is-control-stack) - t) -#+(or x86 x86-64) + (or #+c-stack-is-control-stack t + (not (dd-has-raw-slot-p (lvar-value defstruct-description))))) + (defoptimizer (%make-instance stack-allocate-result) ((n) node dx) - (declare (ignore n dx)) - t) + (eq dx 'truly-dynamic-extent)) +#+(and gencgc c-stack-is-control-stack) +(defoptimizer (%make-instance/mixed stack-allocate-result) ((n) node dx) + (eq dx 'truly-dynamic-extent)) +(defoptimizer (%make-funcallable-instance stack-allocate-result) ((n) node dx) + (eq dx 'truly-dynamic-extent)) (defoptimizer ir2-convert-reffer ((object) node block name offset lowtag) (let* ((lvar (node-lvar node)) - (locs (lvar-result-tns lvar (list *universal-type*))) + (locs (lvar-result-tns lvar (list (if lvar + (lvar-type lvar) + *universal-type*)))) (res (first locs))) (vop slot node block (lvar-tn node block object) name offset lowtag res) @@ -71,12 +73,7 @@ res) (move-lvar-result node block locs lvar))) -(eval-when (:compile-toplevel) - ;; Assert correctness of build order. (Need not be exhaustive) - #+(and x86-64 (not (vop-named sb-vm::raw-instance-init/word))) - (error "Expected raw-instance-init vops")) - -(defun emit-inits (node block name object lowtag inits args) +(defun emit-inits (node block object lowtag inits args) (let ((unbound-marker-tn nil) (funcallable-instance-tramp-tn nil) (dx-p (node-stack-allocate-p node))) @@ -90,12 +87,6 @@ (slot (cdr init))) (case kind (:slot - ;; FIXME: the only reason INIT-SLOT raw variants exist is to avoid - ;; an extra MOVE - setters return a value, but INITers don't. - ;; It would probably produce better code by not assuming that - ;; setters return a value, because as things are, if you call - ;; 8 setters in a row, then you probably produce 7 extraneous moves, - ;; because not all of them can deliver a value to the final result. (let ((raw-type (pop slot)) (arg (pop args))) (unless (and (or (eq raw-type t) @@ -103,31 +94,30 @@ (zero-init-p arg)) (let ((arg-tn (lvar-tn node block arg))) (macrolet - ((make-case (&optional rsd-list) + ((make-case (&aux (rsd-list sb-kernel::*raw-slot-data*)) `(ecase raw-type ((t) - (vop init-slot node block object arg-tn - name dx-p (+ sb-vm:instance-slots-offset slot) lowtag)) + (vop set-slot node block object arg-tn + :allocator (+ sb-vm:instance-slots-offset slot) lowtag)) ,@(map 'list (lambda (rsd) `(,(sb-kernel::raw-slot-data-raw-type rsd) - (vop ,(sb-kernel::raw-slot-data-init-vop rsd) - node block object arg-tn slot))) - (symbol-value rsd-list))))) - (make-case #+(vop-named sb-vm::raw-instance-init/word) - sb-kernel::*raw-slot-data*)))))) + (vop ,(sb-kernel::raw-slot-data-writer-name rsd) + node block object (emit-constant slot) arg-tn))) + rsd-list)))) + (make-case)))))) + ;; compact header passes the layout to EMIT-FIXED-ALLOC + ;; which generates the instruction to set the header. + #-compact-instance-header (:dd - (vop init-slot node block object + (vop set-slot node block object (emit-constant (sb-kernel::dd-layout-or-lose slot)) - name dx-p - ;; Layout has no index if compact headers. - (or #+compact-instance-header :layout sb-vm:instance-slots-offset) - lowtag)) + :allocator sb-vm:instance-slots-offset lowtag)) (otherwise (if (and (eq kind :arg) (zero-init-p (car args))) (pop args) - (vop init-slot node block object + (vop set-slot node block object (ecase kind (:arg (aver args) @@ -154,16 +144,25 @@ nil sb-vm:any-reg-sc-number))) (vop make-funcallable-instance-tramp node block tn) tn))))) - name dx-p slot lowtag)))))))) + :allocator slot lowtag)))))))) (unless (null args) (bug "Leftover args: ~S" args))) +(defun unbound-marker-tn-p (tn) + (let ((writes (tn-writes tn))) + (and writes + (not (tn-ref-next writes)) ; is never changed + (let ((vop (tn-ref-vop writes))) + (and vop (eq (vop-name vop) 'make-unbound-marker)))))) + (defun emit-fixed-alloc (node block name words type lowtag result lvar) (let ((stack-allocate-p (and lvar (lvar-dynamic-extent lvar)))) - (when stack-allocate-p - (vop current-stack-pointer node block - (ir2-lvar-stack-pointer (lvar-info lvar)))) - (vop fixed-alloc node block name words type lowtag stack-allocate-p result))) + (cond (stack-allocate-p + (vop current-stack-pointer node block + (ir2-lvar-stack-pointer (lvar-info lvar))) + (vop fixed-alloc-to-stack node block name words type lowtag t result)) + (t + (vop fixed-alloc node block name words type lowtag nil result))))) (defoptimizer ir2-convert-fixed-allocation ((&rest args) node block name words type lowtag inits) @@ -171,7 +170,7 @@ (locs (lvar-result-tns lvar (list *universal-type*))) (result (first locs))) (emit-fixed-alloc node block name words type lowtag result lvar) - (emit-inits node block name result lowtag inits args) + (emit-inits node block result lowtag inits args) (move-lvar-result node block locs lvar))) (defoptimizer ir2-convert-variable-allocation @@ -188,27 +187,33 @@ (ir2-lvar-stack-pointer (lvar-info lvar)))) (vop var-alloc node block (lvar-tn node block extra) name words type lowtag stack-allocate-p result))) - (emit-inits node block name result lowtag inits args) + (emit-inits node block result lowtag inits args) (move-lvar-result node block locs lvar))) (defoptimizer ir2-convert-structure-allocation - ((dd slot-specs &rest args) node block name words type lowtag inits) - (declare (ignore inits)) + ((dd slot-specs &rest args) node block name words type lowtag) (let* ((lvar (node-lvar node)) (locs (lvar-result-tns lvar (list *universal-type*))) (result (first locs))) (aver (and (constant-lvar-p dd) (constant-lvar-p slot-specs) (= words 1))) + (aver (= type sb-vm:instance-widetag)) (let* ((c-dd (lvar-value dd)) (c-slot-specs (lvar-value slot-specs)) (words (+ (dd-length c-dd) words))) - #+compact-instance-header - (progn (aver (= type sb-vm:instance-widetag)) - (emit-constant (setq type (sb-kernel::dd-layout-or-lose c-dd)))) - (emit-fixed-alloc node block name words type lowtag result lvar) - (emit-inits node block name result lowtag + (let ((metadata #+compact-instance-header + (let ((layout (sb-kernel::dd-layout-or-lose c-dd))) + (emit-constant layout) + layout) + #-compact-instance-header + c-dd)) + (emit-fixed-alloc node block name words metadata lowtag result lvar)) + (emit-inits node block result lowtag `(#-compact-instance-header (:dd . ,c-dd) ,@c-slot-specs) args) (move-lvar-result node block locs lvar)))) +;;; FIXME: this causes emission of GC store barriers, but it should not. +;;; The vector is freshly consed, so anything being stored into it +;;; is at least as old. (defoptimizer (initialize-vector ir2-convert) ((vector &rest initial-contents) node block) (let* ((vector-ctype (lvar-type vector)) @@ -216,46 +221,55 @@ (array-type-specialized-element-type vector-ctype) (bug "Unknown vector type in IR2 conversion for ~S." 'initialize-vector))) + (bit-vector-p (type= elt-ctype (specifier-type 'bit))) + (simple-vector-p (type= elt-ctype (specifier-type 't))) (saetp (find-saetp-by-ctype elt-ctype)) (lvar (node-lvar node)) (locs (lvar-result-tns lvar (list vector-ctype))) (result (first locs)) (elt-ptype (primitive-type elt-ctype)) (tmp (make-normal-tn elt-ptype))) + (declare (ignorable bit-vector-p simple-vector-p)) (emit-move node block (lvar-tn node block vector) result) (flet ((compute-setter () + ;; Such cringe. I had no idea why all the "-C" vops were mandatory. + ;; Too bad we can't let the backend decide how it would like to do things. + ;; Not to mention, this code is confusing because RESULT is the argument, + ;; and TN - the value to store - is the result, and an argument. + ;; Also note that the constant-index vops want the operands to the + ;; VOP macro as (VECTOR VALUE INDEX OFFSET) + (RESULT) + ;; but the non-constant want (VECTOR INDEX VALUE OFFSET) + (RESULT). + ;; They could totally have been made the same. (macrolet ((frob () - (let ((*package* (find-package :sb-vm)) - (clauses nil)) - (map nil (lambda (s) - (when (sb-vm:saetp-specifier s) - (push - `(,(sb-vm:saetp-typecode s) - (lambda (index tn) - #+x86-64 - (vop ,(symbolicate "DATA-VECTOR-SET-WITH-OFFSET/" - (sb-vm:saetp-primitive-type-name s) - "-C") - node block result tn index 0 tn) - #+x86 - (vop ,(symbolicate "DATA-VECTOR-SET-WITH-OFFSET/" - (sb-vm:saetp-primitive-type-name s)) - node block result index tn 0 tn) - #-(or x86 x86-64) - (vop ,(symbolicate "DATA-VECTOR-SET/" - (sb-vm:saetp-primitive-type-name s)) - node block result index tn tn))) - clauses))) - sb-vm:*specialized-array-element-type-properties*) - `(ecase (sb-vm:saetp-typecode saetp) - ,@(nreverse clauses))))) + `(ecase (sb-vm:saetp-typecode saetp) + ,@(map 'list + (lambda (s &aux (ptype (sb-vm:saetp-primitive-type-name s)) + (*package* (find-package "SB-VM"))) + `(,(sb-vm:saetp-typecode s) + (lambda (index tn) + #+x86-64 + ,(if (eq ptype 'simple-bit-vector) ; no "-C" setter exists + `(vop ,(symbolicate "DATA-VECTOR-SET-WITH-OFFSET/" ptype) + node block result index tn 0) + `(vop ,(symbolicate "DATA-VECTOR-SET-WITH-OFFSET/" ptype "-C") + node block result tn index 0)) + #+x86 + (vop ,(symbolicate "DATA-VECTOR-SET-WITH-OFFSET/" ptype) + node block result index tn 0) + #-(or x86 x86-64) + (vop ,(symbolicate "DATA-VECTOR-SET/" ptype) + node block result index tn)))) + (remove nil sb-vm:*specialized-array-element-type-properties* + :key #'sb-vm:saetp-specifier))))) (frob))) (tnify (index) #-x86-64 (emit-constant index) #+x86-64 - index)) + (if bit-vector-p ; moar cringe + (emit-constant index) + index))) (let ((setter (compute-setter)) (length (length initial-contents)) (dx-p (and lvar @@ -270,20 +284,33 @@ (if character (eql (char-code (lvar-value value)) 0) (eql (lvar-value value) 0))) - (emit-move node block (lvar-tn node block value) tmp) - (funcall setter (tnify i) tmp)))))) + ;; With SIMPLE-BIT-VECTOR, prefer to pass a constant TN if we can, as it emits + ;; better code (at least on x86-64) by using the constant to discern between + ;; the BTS or BTR opcode. However, a new suboptimality comes from that, + ;; which is that by not passing a LOCATION= TN for the output, the final MOVE + ;; in the setter thinks that it has to do something. + ;; Nonetheless it's far better than it was. In all other scenarios, don't pass + ;; a constant TN, because we don't know that generated code is better. + (cond #+x86-64 ; still moar cringe + ((and (or bit-vector-p simple-vector-p) (constant-lvar-p value) + ;; check for constant named-ness to not + ;; trigger load form processing. + (not (leaf-has-source-name-p (nth-value 1 (lvar-value value))))) + (funcall setter (tnify i) (emit-constant (lvar-value value)))) + (t + ;; FIXME: for simple-vector, fixnums should get stored via an ANY-REG + ;; so that data-vector-set doesn't emit a store barrier. + ;; (TMP is a descriptor-reg because ELT-CTYPE is T) + ;; Or just fix this optimizer - as commented above - to somehow elide + ;; the barrier for all elements. + (emit-move node block (lvar-tn node block value) tmp) + (funcall setter (tnify i) tmp)))))))) (move-lvar-result node block locs lvar))) -(defun vector-initialized-p (call) - (let ((lvar (node-lvar call))) - (when lvar - (let ((dest (principal-lvar-dest lvar))) - (and (basic-combination-p dest) - (lvar-fun-is (basic-combination-fun dest) '(initialize-vector))))))) - ;;; An array header for simple non-unidimensional arrays is a fixed alloc, ;;; because the rank has to be known. ;;; (There are no compile-time optimizations for unknown rank arrays) +;;; WIDETAG may have ORed into it 1 bit for +ARRAY-FILL-POINTER-P+ (defoptimizer (make-array-header* ir2-convert) ((widetag &rest args) node block) (let ((n-args (length args))) ;; Remove the widetag lvar @@ -314,14 +341,10 @@ node block (list value-tn) (node-lvar node)))))))) ;;; Stack allocation optimizers per platform support -#+stack-allocatable-vectors -(progn - (defoptimizer (make-array-header* stack-allocate-result) ((&rest args) node dx) - args dx - t) - (defoptimizer (allocate-vector stack-allocate-result) - ((type length words) node dx) - (declare (ignorable type) (ignore length)) +(defoptimizer (make-array-header* stack-allocate-result) ((&rest args)) + t) +(defoptimizer (allocate-vector stack-allocate-result) + ((#+ubsan poisoned type length words) node dx) (and ;; Can't put unboxed data on the stack unless we scavenge it ;; conservatively. @@ -339,14 +362,15 @@ (specifier-type `(integer 0 ,(- (/ +backend-page-bytes+ sb-vm:n-word-bytes) sb-vm:vector-data-offset))))))) +(defoptimizer (allocate-vector ltn-annotate) + ((#+ubsan poisoned type length words) call ltn-policy) + (vectorish-ltn-annotate-helper call ltn-policy + (if (sb-c:msan-unpoison sb-c:*compilation*) + 'sb-vm::allocate-vector-on-stack+msan-unpoison + 'sb-vm::allocate-vector-on-stack) + 'sb-vm::allocate-vector-on-heap)) - (defoptimizer (allocate-vector ltn-annotate) ((type length words) call ltn-policy) - (declare (ignore type length words)) - (vectorish-ltn-annotate-helper call ltn-policy - 'sb-vm::allocate-vector-on-stack - 'sb-vm::allocate-vector-on-heap)) - - (defun vectorish-ltn-annotate-helper (call ltn-policy dx-template not-dx-template) +(defun vectorish-ltn-annotate-helper (call ltn-policy dx-template not-dx-template) (let* ((args (basic-combination-args call)) (template-name (if (node-stack-allocate-p call) dx-template @@ -355,43 +379,31 @@ (dolist (arg args) (setf (lvar-info arg) (make-ir2-lvar (primitive-type (lvar-type arg))))) - (unless (is-ok-template-use template call (ltn-policy-safe-p ltn-policy)) - (ltn-default-call call) - (return-from vectorish-ltn-annotate-helper (values))) + (aver (is-ok-template-use template call (ltn-policy-safe-p ltn-policy))) (setf (basic-combination-info call) template) (setf (node-tail-p call) nil) - (dolist (arg args) - (annotate-1-value-lvar arg))))) + (annotate-1-value-lvar arg)))) ;;; ...lists -#+stack-allocatable-lists -(progn - (defoptimizer (list stack-allocate-result) ((&rest args) node dx) - (declare (ignore dx)) - (not (null args))) - (defoptimizer (list* stack-allocate-result) ((&rest args) node dx) - (declare (ignore dx)) - (not (null (rest args)))) - (defoptimizer (%listify-rest-args stack-allocate-result) ((&rest args) node dx) - (declare (ignore args dx)) - t)) + +(defoptimizer (list stack-allocate-result) ((&rest args)) + (not (null args))) +(defoptimizer (list* stack-allocate-result) ((&rest args)) + (not (null (rest args)))) +(defoptimizer (%listify-rest-args stack-allocate-result) ((&rest args)) + t) ;;; ...conses -#+stack-allocatable-fixed-objects -(progn - (defoptimizer (cons stack-allocate-result) ((&rest args) node dx) - (declare (ignore args dx)) - t) - (defoptimizer (%make-complex stack-allocate-result) ((&rest args) node dx) - (declare (ignore args dx)) - t)) +(defoptimizer (cons stack-allocate-result) ((&rest args)) + t) +(defoptimizer (%make-complex stack-allocate-result) ((&rest args)) + t) ;;; MAKE-LIST optimizations #+x86-64 (progn (defoptimizer (%make-list stack-allocate-result) ((length element) node dx) - (declare (ignore element)) (or (eq dx 'truly-dynamic-extent) (zerop (policy node safety)) ;; At most one page (this is more paranoid than %listify-rest-args). @@ -403,44 +415,85 @@ (specifier-type `(integer 0 ,(/ +backend-page-bytes+ sb-vm:n-word-bytes 2)))))) (defoptimizer (%make-list ltn-annotate) ((length element) call ltn-policy) - (declare (ignore length element)) (vectorish-ltn-annotate-helper call ltn-policy 'sb-vm::allocate-list-on-stack 'sb-vm::allocate-list-on-heap))) +;;; Return the vop that wrote the TN referenced by TN-REF, +;;; but look through MOVEs. +(defun producer-vop (tn-ref) + (let ((vop (tn-ref-vop (tn-writes (tn-ref-tn tn-ref))))) + (if (neq (vop-name vop) 'move) + vop + (tn-ref-vop (tn-writes (tn-ref-tn (vop-args vop))))))) + +(defun elide-zero-fill (vop) + (let* ((writer (producer-vop (vop-args vop))) + ;; Take the last of the info arguments + ;; in case WORDS is also an info argument. + (value + (the (or sb-vm:word + (member :trap :unbound :safe-default :unsafe-default)) + (car (last (vop-codegen-info vop))))) + (elidep + (ecase (vop-name writer) + (sb-vm::allocate-vector-on-heap + (member value '(0 :safe-default :unsafe-default))) + ((sb-vm::allocate-vector-on-stack + sb-vm::allocate-vector-on-stack+msan-unpoison) + ;; For most specialized vectors, any random bits can + ;; be regarded as a :SAFE-DEFAULT. If :UNSAFE-DEFAULT, then random + ;; bits are OK (even for SIMPLE-VECTOR if not using precise gencgc). + (eq value :unsafe-default))))) + (when elidep ; change it to a MOVE + (let ((new (emit-and-insert-vop (vop-node vop) (vop-block vop) + (template-or-lose 'move) + (reference-tn (tn-ref-tn (vop-args vop)) nil) + (reference-tn (tn-ref-tn (vop-results vop)) t) + vop))) + (delete-vop vop) + new)))) (in-package "SB-VM") ;;; Return a list of parameters with which to call MAKE-ARRAY-HEADER* ;;; given the mandatory slots for a simple array of rank 0 or > 1. (defun make-array-header-inits (storage n-elements dimensions) - (macrolet ((expand () - `(list* sb-vm:simple-array-widetag - ,@(mapcar (lambda (slot) - (ecase (slot-name slot) - (data 'storage) - (fill-pointer 'n-elements) - (elements 'n-elements) - (fill-pointer-p nil) - (displacement 0) - (displaced-p nil) - (displaced-from nil))) - (butlast (primitive-object-slots - (find 'array *primitive-objects* - :key 'primitive-object-name)))) - dimensions))) - (expand))) + (let ((primitive-obj (load-time-value (primitive-object 'array) t))) + (nconc (loop with slots = (primitive-object-slots primitive-obj) + for i from 0 below (1- (length slots)) + collect + (let ((slot (svref slots i))) + (ecase (slot-name slot) + (data storage) + (fill-pointer n-elements) + (elements n-elements) + (displacement 0) + (displaced-p nil) + (displaced-from nil)))) + dimensions))) ;;; This order is used by SB-C::TRANSFORM-MAKE-ARRAY-VECTOR -(assert (equal (mapcar #'slot-name - (primitive-object-slots - (find 'array *primitive-objects* - :key 'primitive-object-name))) - '(fill-pointer fill-pointer-p elements data +;;; The slot formerly known as FILL-POINTER-P is 1 bit in the header now. +(assert (equal (map 'list #'slot-name + (primitive-object-slots (primitive-object 'array))) + '(fill-pointer elements data displacement displaced-p displaced-from dimensions))) -(defun emit-code-page-write-barrier-p (fun-name) - (and (listp fun-name) - (eq (car fun-name) 'setf) - (member (cadr fun-name) - '(%code-debug-info %code-fixups)) - t)) +(define-vop (touch-object) + (:translate touch-object) + (:args (object)) + (:ignore object) + (:policy :fast-safe) + (:arg-types t) + (:generator 0)) + +#+(or x86 x86-64) +(define-vop () + (:translate touch-object-identity) + (:args (object :scs (descriptor-reg any-reg sap-reg + signed-reg unsigned-reg) + :target res)) + (:policy :fast-safe) + (:results (res :scs (descriptor-reg))) + (:generator 0 + (move res object))) diff --git a/src/compiler/generic/vm-macs.lisp b/src/compiler/generic/vm-macs.lisp index 685dfa1e94..74c6ddd6db 100644 --- a/src/compiler/generic/vm-macs.lisp +++ b/src/compiler/generic/vm-macs.lisp @@ -32,30 +32,25 @@ (list* (car options) (cadr options) (remove-keywords (cddr options) keywords))))) -(defstruct (prim-object-slot - (:constructor make-slot (name rest-p offset special options)) - (:copier nil) - (:conc-name slot-)) - (name nil :type symbol :read-only t) - (rest-p nil :type (member t nil) :read-only t) - (offset 0 :type fixnum :read-only t) - (options nil :type list :read-only t) - ;; On some targets (e.g. x86-64) slots of the thread structure are - ;; referenced as special variables, this slot holds the name of that variable. - (special nil :type symbol :read-only t)) - (defstruct (primitive-object (:copier nil)) (name nil :type symbol :read-only t) (widetag nil :type symbol :read-only t) (lowtag nil :type symbol :read-only t) - (options nil :type list :read-only t) - (slots nil :type list :read-only t) (length 0 :type fixnum :read-only t) - (variable-length-p nil :type (member t nil) :read-only t)) + (variable-length-p nil :type boolean :read-only t) + (slots #() :type vector :read-only t)) + +(defun slot-offset (slot) (car slot)) +(defun slot-name (slot) (cadr slot)) +(defun slot-special (slot) (getf (cddr slot) :special)) -(declaim (freeze-type prim-object-slot primitive-object)) +(declaim (freeze-type primitive-object)) (define-load-time-global *primitive-objects* nil) +(defun primitive-object (name) + (find name *primitive-objects* :key #'primitive-object-name)) +(defun primitive-object-slot (obj name) + (find name (primitive-object-slots obj) :key #'slot-name)) (defun !%define-primitive-object (primobj) (let ((name (primitive-object-name primobj))) @@ -88,25 +83,16 @@ pointer &allow-other-keys) (if (atom spec) (list spec) spec) - #-alpha (declare (ignorable pointer)) - #+alpha - (when pointer - ;; Pointer values on ALPHA are 64 bits wide, and - ;; double-word aligned. We may also wish to have such a - ;; mode for other 64-bit hardware outside of any defined - ;; 32-on-64 ABI (which would presumably have 32-bit - ;; pointers in the first place, obviating the alignment - ;; and size requirements). - (unless rest-p - (setf length 2)) - (when (oddp offset) - (incf offset))) - (slots `(make-slot ',slot-name ,rest-p ,offset ',special - ',(remove-keywords options '(:rest-p :length)))) + (slots (list* offset slot-name + (remove-keywords + options + `(#+sb-xc :c-type :rest-p ,@(if (= length 1) '(:length)))))) (let ((offset-sym (symbolicate name "-" slot-name (if rest-p "-OFFSET" "-SLOT")))) - (constants `(defconstant ,offset-sym ,offset)) + (constants + `(progn (defconstant ,offset-sym ,offset) + (setf (info :variable :kind ',offset-sym) :constant))) (when special (specials `(progn (defvar ,special) @@ -152,7 +138,7 @@ (make-primitive-object :name ',name :widetag ',widetag :lowtag ',lowtag - :slots (list ,@(slots)) + :slots ,(coerce (slots) 'vector) :length ,offset :variable-length-p ,variable-length-p)) ,@(constants) @@ -194,8 +180,8 @@ (deftype sc-offset () `(integer 0 (,sc-offset-limit))) (defconstant finite-sc-offset-limit - #-(or sparc alpha hppa) 32 - #+(or sparc alpha hppa) 64) + #-(or sparc) 32 + #+(or sparc) 64) (defconstant finite-sc-offset-bits (integer-length (1- finite-sc-offset-limit))) (deftype finite-sc-offset () `(integer 0 (,finite-sc-offset-limit))) diff --git a/src/compiler/generic/vm-tran.lisp b/src/compiler/generic/vm-tran.lisp index a8055874cf..e51de20e83 100644 --- a/src/compiler/generic/vm-tran.lisp +++ b/src/compiler/generic/vm-tran.lisp @@ -33,14 +33,8 @@ (deftransform make-symbol ((string) (simple-string)) `(%make-symbol 0 string)) -#-immobile-space -(define-source-transform %make-symbol (kind string) - (declare (ignore kind)) - ;; Set "logically read-only" bit in pname. - `(sb-vm::%%make-symbol (set-header-data ,string ,sb-vm:+vector-shareable+))) - ;;; We don't want to clutter the bignum code. -#+(or x86 x86-64) +#+(and (or x86 x86-64) (not bignum-assertions)) (define-source-transform sb-bignum:%bignum-ref (bignum index) ;; KLUDGE: We use TRULY-THE here because even though the bignum code ;; is (currently) compiled with (SAFETY 0), the compiler insists on @@ -55,6 +49,15 @@ #+(or x86 x86-64) (defun fold-index-addressing (fun-name element-size lowtag data-offset index offset &optional setter-p) + ;; UNINITIALIZED-ELEMENT-ERROR does not take the ADDEND, + ;; so we need to make sure that it's always 0 for #+ubsan. + ;; #-ubsan has a minor problem in terms of error-reporting. + ;; The condition report method does not try to show the index of the + ;; trapping element, so we're at least not wrong. A good solution might be + ;; to have separate 2-arg and 3-arg variants of UNINITIALIZED-ELEMENT, + ;; or else always emit the addend even if zero. As things are, a 0 in the + ;; error payload eats 4 bytes due to design choices in sc+offset encoding. + #+ubsan (give-up-ir1-transform) (multiple-value-bind (func index-args) (extract-fun-args index '(+ -) 2) (destructuring-bind (x constant) index-args (unless (and (constant-lvar-p constant) @@ -84,6 +87,18 @@ sb-vm:bignum-digits-offset index offset)) +;;; When copying a structure, try to make the best decision possible +;;; as to placement. This matters in a few circumstances: +;;; - when the "system" mixed TLAB is different from the "user" mixed TLAB. +;;; - when we distinguish boxed from mixed allocation to generation 0. +;;; GIVE-UP-IR1-TRANSFORM might put the allocation in the wrong TLAB, +;;; as the general fallback doesn't make the same distinctions. +;;; Unfortunately the DEFSTRUCT-defined copiers were not inlining even when +;;; explicitly requested, because COPY-SOMESTRUCT always transforms into +;;; COPY-STRUCTURE, so we've lost any declared inline-ness of COPY-SOMESTRUCT. +;;; Therefore we just try to infer it based on whether this transform is +;;; "acting as" COPY-SOMESTRUCT for a particular struct whose copier +;;; was requested to be inline. (deftransform copy-structure ((instance) * * :result result :node node) (let* ((classoid (lvar-type instance)) (name (and (structure-classoid-p classoid) (classoid-name classoid))) @@ -95,19 +110,22 @@ (class-eq (and name (eq (classoid-state classoid) :sealed) (not (classoid-subclasses classoid)))) - (dd (and class-eq (layout-info layout))) + (dd (and class-eq (wrapper-info layout))) + (dd-copier (and dd (sb-kernel::dd-copier-name dd))) (max-inlined-words 5)) (unless (and result ; could be unused result (but entire call wasn't flushed?) layout - ;; And don't copy if raw slots are present on the precisely GCed backends. - ;; To enable that, we'd want variants for {"all-raw", "all-boxed", "mixed"} + ;; Fail if raw slots are present on the precisely GCed backends. ;; Also note that VAR-ALLOC can not cope with dynamic-extent except where ;; support has been added (x86oid so far); so requiring an exact type here ;; causes VAR-ALLOC to become FIXED-ALLOC which works on more architectures. - #-c-stack-is-control-stack - (and dd (eql (layout-bitmap layout) sb-kernel:+layout-all-tagged+)) + #-c-stack-is-control-stack (and dd (not (dd-has-raw-slot-p dd))) + ;; Definitely do this if copying to stack + ;; (Allocation has to be inlined, otherwise there's no way to DX it) (or (lvar-dynamic-extent result) + (and dd-copier + (eq (sb-int:info :function :inlinep dd-copier) 'inline)) ;; Or if it's a small fixed number of words ;; and speed at least as important as size. (and class-eq @@ -117,48 +135,65 @@ ;; There are some benefits to using the simple case for a known exact type: ;; - the layout can be wired in which might or might not save 1 instruction ;; depending on whether layouts are in immobile space. - ;; - all backends can do this (subject to stack-allocatable-fixed-objects) ;; - for a small number of slots, copying them is inlined (cond ((not dd) ; it's going to be some subtype of NAME - `(%copy-instance (%make-instance (%instance-length instance)) instance)) - ((<= (dd-length dd) max-inlined-words) - `(let ((copy (%make-structure-instance ,dd nil))) - ;; ASSUMPTION: either %INSTANCE-REF is the correct accessor for this word, - ;; or the GC will treat random bit patterns as conservative pointers - ;; (i.e. not alter them if %INSTANCE-REF is not the correct accessor) - (setf ,@(loop for i from sb-vm:instance-data-start below (dd-length dd) - append `((%instance-ref copy ,i) (%instance-ref instance ,i)))) - copy)) - (t - `(%copy-instance-slots (%make-structure-instance ,dd nil) instance))))) + ;; pessimistically assume MIXED rather than choosing at runtime + `(%copy-instance (%make-instance/mixed (%instance-length instance)) instance)) + ((not (logtest (dd-flags dd) +dd-varylen+)) ; fixed length + ;; ASSUMPTION: either %INSTANCE-REF is the correct accessor for this word, + ;; or the GC will treat random bit patterns as conservative pointers + ;; (i.e. not alter them if %INSTANCE-REF is not the correct accessor) + (if (> (dd-length dd) max-inlined-words) + `(%copy-instance-slots (%make-structure-instance ,dd nil) instance) + `(let ((copy (%make-structure-instance ,dd nil))) + ,@(loop for i from sb-vm:instance-data-start below (dd-length dd) + collect `(%instance-set copy ,i (%instance-ref instance ,i))) + copy))) + (t ; variable-length + `(let ((copy (,(if (dd-has-raw-slot-p dd) '%make-instance/mixed '%make-instance) + (%instance-length instance)))) + (%set-instance-layout copy (%instance-layout instance)) + (%copy-instance-slots copy instance)))))) + +(defun varying-length-struct-p (classoid) + (let ((dd (find-defstruct-description (classoid-name classoid)))) + (logtest (dd-flags dd) +dd-varylen+))) (deftransform %instance-length ((instance)) (let ((classoid (lvar-type instance))) (if (and (structure-classoid-p classoid) (sb-kernel::compiler-layout-ready-p (classoid-name classoid)) (eq (classoid-state classoid) :sealed) + (not (varying-length-struct-p classoid)) ;; TODO: if sealed with subclasses which add no slots, use the fixed length (not (classoid-subclasses classoid))) - (dd-length (layout-info (sb-kernel::compiler-layout-or-lose (classoid-name classoid)))) + (dd-length (wrapper-dd (sb-kernel::compiler-layout-or-lose (classoid-name classoid)))) (give-up-ir1-transform)))) -;;; The layout is stored in slot 0. -;;; *** These next two transforms should be the only code, aside from -;;; some parts of the C runtime, with knowledge of the layout index. +;;; This doesn't help a whole lot, but it does fire during compilation of 'info-vector' +;;; which uses variable-length instances of PACKED-INFO, having no slot transforms. +(define-source-transform (setf %instance-ref) (newval instance index) + `(let ((.newval. ,newval) + (.instance. ,instance) + (.index. ,index)) + (%instance-set .instance. .index. .newval.) + .newval.)) + +(define-source-transform %instance-wrapper (x) `(layout-friend (%instance-layout ,x))) +(define-source-transform %fun-wrapper (x) `(layout-friend (%fun-layout ,x))) + +;;; *** These transforms should be the only code, aside from the C runtime +;;; with knowledge of the layout index. #+compact-instance-header (define-source-transform function-with-layout-p (x) `(functionp ,x)) #-compact-instance-header (progn (define-source-transform %instance-layout (x) - `(truly-the layout (%instance-ref ,x 0))) - (define-source-transform %set-instance-layout (x val) - `(%instance-set ,x 0 (the layout ,val))) + `(truly-the sb-vm:layout (%instance-ref ,x 0))) + (define-source-transform %set-instance-layout (instance layout) + `(%instance-set ,instance 0 (the sb-vm:layout ,layout))) (define-source-transform function-with-layout-p (x) - `(funcallable-instance-p ,x)) - (define-source-transform %fun-layout (x) - `(truly-the layout (%funcallable-instance-info ,x 0))) - (define-source-transform %set-funcallable-instance-layout (x val) - `(setf (%funcallable-instance-info ,x 0) (the layout ,val)))) + `(funcallable-instance-p ,x))) ;;;; simplifying HAIRY-DATA-VECTOR-REF and HAIRY-DATA-VECTOR-SET @@ -172,9 +207,7 @@ (data-vector-ref string index)) #+sb-unicode ((simple-array base-char (*)) - (data-vector-ref string index)) - ((simple-array nil (*)) - (data-nil-vector-ref string index)))))) + (data-vector-ref string index)))))) ;;; This and the corresponding -SET transform work equally well on non-simple ;;; arrays, but after benchmarking (on x86), Nikodemus didn't find any cases @@ -184,7 +217,7 @@ "avoid runtime dispatch on array element type" (let* ((type (lvar-type array)) (element-ctype (array-type-upgraded-element-type type)) - (declared-element-ctype (array-type-declared-element-type type))) + (declared-element-ctype (declared-array-element-type type))) (declare (type ctype element-ctype)) (when (eq *wild-type* element-ctype) (give-up-ir1-transform @@ -203,8 +236,7 @@ ((type= element-ctype declared-element-ctype) bare-form) (t - `(the ,(type-specifier declared-element-ctype) - ,bare-form)))))))) + (the-unwild declared-element-ctype bare-form)))))))) ;;; Transform multi-dimensional array to one dimensional data vector ;;; access. @@ -257,16 +289,18 @@ (if (array-type-p ctype) ;; the other transform will kick in, so that's OK (give-up-ir1-transform) + ;; HAIRY-DATA-VECTOR-SET returns a value but DATA-VECTOR-SET does not, + ;; so explicitly return the NEW-VALUE `(typecase string ((simple-array character (*)) - (data-vector-set string index (the* (character :context :aref) new-value))) + (let ((c (the* (character :context :aref) new-value))) + (data-vector-set string index c) + c)) #+sb-unicode ((simple-array base-char (*)) - (data-vector-set string index (the* (base-char :context :aref - :silent-conflict t) - new-value))) - (t - (%type-check-error/c string 'nil-array-accessed-error nil)))))) + (let ((c (the* (base-char :context :aref :silent-conflict t) new-value))) + (data-vector-set string index c) + c)))))) ;;; This and the corresponding -REF transform work equally well on non-simple ;;; arrays, but after benchmarking (on x86), Nikodemus didn't find any cases @@ -278,7 +312,7 @@ "avoid runtime dispatch on array element type" (let* ((type (lvar-type array)) (element-ctype (array-type-upgraded-element-type type)) - (declared-element-ctype (array-type-declared-element-type type))) + (declared-element-ctype (declared-array-element-type type))) (declare (type ctype element-ctype)) (when (eq *wild-type* element-ctype) (give-up-ir1-transform @@ -289,11 +323,11 @@ (declare (type (simple-array ,element-type-specifier 1) array) (type ,element-type-specifier new-value)) ,(if (type= element-ctype declared-element-ctype) - '(data-vector-set array index new-value) - `(truly-the ,(type-specifier declared-element-ctype) - (data-vector-set array index - (the ,(type-specifier declared-element-ctype) - new-value)))))))) + '(progn (data-vector-set array index new-value) + new-value) + `(progn (data-vector-set array index + ,(the-unwild declared-element-ctype 'new-value)) + ,(truly-the-unwild declared-element-ctype 'new-value))))))) ;;; Transform multi-dimensional array to one dimensional data vector ;;; access. @@ -385,7 +419,7 @@ ,(if (and (integer-type-p index-type) (numeric-type-low index-type)) `(integer ,(numeric-type-low index-type) - (,sb-xc:array-dimension-limit)) + (,array-dimension-limit)) `index)))))) (deftransform %data-vector-and-index ((%array %index) @@ -414,52 +448,37 @@ ;;;; BIT-VECTOR hackery ;;; SIMPLE-BIT-VECTOR bit-array operations are transformed to a word -;;; loop that does 32 bits at a time. -;;; -;;; FIXME: This is a lot of repeatedly macroexpanded code. It should -;;; be a function call instead. -(macrolet ((def (bitfun wordfun) - `(deftransform ,bitfun ((bit-array-1 bit-array-2 result-bit-array) - (simple-bit-vector - simple-bit-vector - simple-bit-vector) - * - :node node :policy (>= speed space)) - `(progn - ,@(unless (policy node (zerop safety)) - '((unless (= (length bit-array-1) - (length bit-array-2) - (length result-bit-array)) - (error "Argument and/or result bit arrays are not the same length:~ +;;; loop that does N-WORD-BITS bits at a time. +;;; Note that all of these array operations cause the unused bits +;;; of the last word to be operated on, so they are effectively +;;; in an indeterminate state which is why equality testing, COUNT, +;;; and FIND have to ignore them. +(deftransform bit-op->word-op ((bit-array-1 bit-array-2 result-bit-array) + (simple-bit-vector simple-bit-vector simple-bit-vector) + * + :node node :defun-only t :info wordfun) + `(let ((length (vector-length result-bit-array))) + ,@(unless (policy node (zerop safety)) + `((unless (= length + ,@(unless (same-leaf-ref-p bit-array-1 result-bit-array) + '((vector-length bit-array-1))) + (vector-length bit-array-2)) + (error "Argument and/or result bit arrays are not the same length:~ ~% ~S~% ~S ~% ~S" - bit-array-1 - bit-array-2 - result-bit-array)))) - (let ((length (length result-bit-array))) - (if (= length 0) - ;; We avoid doing anything to 0-length - ;; bit-vectors, or rather, the memory that - ;; follows them. Other divisible-by-32 cases - ;; are handled by the (1- length), below. - ;; CSR, 2002-04-24 - result-bit-array - (do ((index 0 (1+ index)) - ;; bit-vectors of length 1-32 need - ;; precisely one (SETF %VECTOR-RAW-BITS), - ;; done here in the epilogue. - CSR, - ;; 2002-04-24 - (end-1 (truncate (truly-the index (1- length)) - sb-vm:n-word-bits))) - ((>= index end-1) - (setf (%vector-raw-bits result-bit-array index) - (,',wordfun (%vector-raw-bits bit-array-1 index) - (%vector-raw-bits bit-array-2 index))) - result-bit-array) - (declare (optimize (speed 3) (safety 0)) - (type index index end-1)) - (setf (%vector-raw-bits result-bit-array index) - (,',wordfun (%vector-raw-bits bit-array-1 index) - (%vector-raw-bits bit-array-2 index)))))))))) + bit-array-1 bit-array-2 result-bit-array)))) + (dotimes (index (ceiling length sb-vm:n-word-bits)) + (declare (optimize (speed 3) (safety 0)) (type index index)) + (setf (%vector-raw-bits result-bit-array index) + (,wordfun (%vector-raw-bits bit-array-1 index) + (%vector-raw-bits bit-array-2 index)))) + result-bit-array)) + +(flet ((policy-test (node) (policy node (>= speed space)))) +(macrolet ((def (bitfun wordfun) + `(%deftransform ',bitfun #'policy-test + '(function (simple-bit-vector simple-bit-vector simple-bit-vector) + *) + (cons #'bit-op->word-op ',wordfun)))) (def bit-and word-logical-and) (def bit-ior word-logical-or) (def bit-xor word-logical-xor) @@ -469,176 +488,109 @@ (def bit-andc1 word-logical-andc1) (def bit-andc2 word-logical-andc2) (def bit-orc1 word-logical-orc1) - (def bit-orc2 word-logical-orc2)) + (def bit-orc2 word-logical-orc2))) (deftransform bit-not ((bit-array result-bit-array) (simple-bit-vector simple-bit-vector) * :node node :policy (>= speed space)) `(progn - ,@(unless (policy node (zerop safety)) - '((unless (= (length bit-array) - (length result-bit-array)) + ,@(unless (or (policy node (zerop safety)) + (same-leaf-ref-p bit-array result-bit-array)) + '((unless (= (vector-length bit-array) + (vector-length result-bit-array)) (error "Argument and result bit arrays are not the same length:~ ~% ~S~% ~S" bit-array result-bit-array)))) - (let ((length (length result-bit-array))) - (if (= length 0) - ;; We avoid doing anything to 0-length bit-vectors, or rather, - ;; the memory that follows them. Other divisible-by - ;; n-word-bits cases are handled by the (1- length), below. - ;; CSR, 2002-04-24 - result-bit-array - (do ((index 0 (1+ index)) - ;; bit-vectors of length 1 to n-word-bits need precisely - ;; one (SETF %VECTOR-RAW-BITS), done here in the - ;; epilogue. - CSR, 2002-04-24 - (end-1 (truncate (truly-the index (1- length)) - sb-vm:n-word-bits))) - ((>= index end-1) - (setf (%vector-raw-bits result-bit-array index) - (word-logical-not (%vector-raw-bits bit-array index))) - result-bit-array) - (declare (optimize (speed 3) (safety 0)) - (type index index end-1)) - (setf (%vector-raw-bits result-bit-array index) - (word-logical-not (%vector-raw-bits bit-array index)))))))) - + (let ((length (vector-length result-bit-array))) + (dotimes (index (ceiling length sb-vm:n-word-bits)) + (declare (optimize (speed 3) (safety 0)) (type index index)) + (setf (%vector-raw-bits result-bit-array index) + (word-logical-not (%vector-raw-bits bit-array index)))) + result-bit-array))) + +;;; This transform has to deal with the fact that unused bits +;;; in the last data word of a simple-bit-vector can be random. (deftransform bit-vector-= ((x y) (simple-bit-vector simple-bit-vector)) - `(and (= (length x) (length y)) - (let ((length (length x))) - (or (= length 0) - (do* ((i 0 (+ i 1)) - (end-1 (floor (1- length) sb-vm:n-word-bits))) - ((>= i end-1) - (let* ((extra (1+ (mod (1- length) sb-vm:n-word-bits))) - ;; Why do we need to mask anything? Do we allow use of - ;; the extra bits to record data steganographically? - ;; Or maybe we didn't zero-fill trailing bytes of stack-allocated - ;; bit-vectors? - (mask (ash sb-ext:most-positive-word (- extra sb-vm:n-word-bits))) - (numx - (logand - (ash mask - ,(ecase sb-c:*backend-byte-order* - (:little-endian 0) - (:big-endian - '(- sb-vm:n-word-bits extra)))) - (%vector-raw-bits x i))) - (numy - (logand - (ash mask - ,(ecase sb-c:*backend-byte-order* - (:little-endian 0) - (:big-endian - '(- sb-vm:n-word-bits extra)))) - (%vector-raw-bits y i)))) - (declare (type (integer 1 #.sb-vm:n-word-bits) extra) - (type sb-vm:word mask numx numy)) - (= numx numy))) - (declare (type index i end-1)) - (let ((numx (%vector-raw-bits x i)) - (numy (%vector-raw-bits y i))) - (declare (type sb-vm:word numx numy)) - (unless (= numx numy) - (return nil)))))))) - + ;; TODO: unroll if length is known and not more than a few words + `(let ((length (vector-length x))) + (and (= (vector-length y) length) + (let ((words (floor length sb-vm:n-word-bits))) + (and (dotimes (i words t) + (unless (= (%vector-raw-bits x i) (%vector-raw-bits y i)) + (return nil))) + (let ((remainder (mod length sb-vm:n-word-bits))) + (or (zerop remainder) + ;; - To examine 1 bit, shift over 63 bits, 0-filling on the other side + ;; - To examine 2 bits, shift over 62 bits, etc + ;; SHIFT-TOWARDS-END accepts a negative shift COUNT which is + ;; congruent to desired shift modulo the maximum shift. + (zerop (shift-towards-end (logxor (%vector-raw-bits x words) + (%vector-raw-bits y words)) + (- remainder)))))))))) + +;;; This transform has to deal with the fact that unused bits +;;; in the last data word of a simple-bit-vector can be random. (deftransform count ((item sequence) (bit simple-bit-vector) * :policy (>= speed space)) - `(let ((length (length sequence))) - (if (zerop length) - 0 - (do ((index 0 (1+ index)) - (count 0) - (end-1 (truncate (truly-the index (1- length)) - sb-vm:n-word-bits))) - ((>= index end-1) - ;; "(mod (1- length) ...)" is the bit index within the word - ;; of the array index of the ultimate bit to be examined. - ;; "1+" it is the number of bits in that word. - ;; But I don't get why people are allowed to store random data that - ;; we mask off, as if we could accomodate all possible ways that - ;; unsafe code can spew bits where they don't belong. - ;; Does it have to do with %shrink-vector, perhaps? - ;; Some rationale would be nice... - (let* ((extra (1+ (mod (1- length) sb-vm:n-word-bits))) - (mask (ash most-positive-word (- extra sb-vm:n-word-bits))) - ;; The above notwithstanding, for big-endian wouldn't it - ;; be possible to write this expression as a single shift? - ;; (LOGAND MOST-POSITIVE-WORD (ASH most-positive-word (- n-word-bits extra))) - ;; rather than a right-shift to fill in zeros on the left - ;; then by a left-shift to left-align the 1s? - (bits (logand (ash mask - ,(ecase sb-c:*backend-byte-order* - (:little-endian 0) - (:big-endian - '(- sb-vm:n-word-bits extra)))) - (%vector-raw-bits sequence index)))) - (declare (type (integer 1 #.sb-vm:n-word-bits) extra)) - (declare (type sb-vm:word mask bits)) - (incf count (logcount bits)) - ,(if (constant-lvar-p item) - (if (zerop (lvar-value item)) - '(- length count) - 'count) - '(if (zerop item) - (- length count) - count)))) - (declare (type index index count end-1) - (optimize (speed 3) (safety 0))) - (incf count (logcount (%vector-raw-bits sequence index))))))) - -(deftransform fill ((sequence item) (simple-bit-vector bit) * + `(let* ((length (vector-length sequence)) + (count 0) + (words (floor length sb-vm:n-word-bits))) + (declare (index count)) + (declare (optimize (speed 3) (safety 0))) + (dotimes (i words) + (incf count (logcount (%vector-raw-bits sequence i)))) + (let ((remainder (mod length sb-vm:n-word-bits))) + (unless (zerop remainder) + (incf count (logcount (shift-towards-end (%vector-raw-bits sequence words) + (- sb-vm:n-word-bits remainder)))))) + ,(if (constant-lvar-p item) + (if (zerop (lvar-value item)) '(- length count) 'count) + '(if (zerop item) (- length count) count)))) + +;;; This transform does not require that ITEM be derived as BIT, +;;; but at runtime it has to be. +(deftransform fill ((sequence item) (simple-bit-vector t) * :policy (>= speed space)) - (let ((value (if (constant-lvar-p item) - (if (= (lvar-value item) 0) - 0 - most-positive-word) - `(if (= item 0) 0 ,most-positive-word)))) - `(let ((length (length sequence)) - (value ,value)) - (if (= length 0) - sequence - (do ((index 0 (1+ index)) - ;; bit-vectors of length 1 to n-word-bits need precisely - ;; one (SETF %VECTOR-RAW-BITS), done here in the - ;; epilogue. - CSR, 2002-04-24 - (end-1 (truncate (truly-the index (1- length)) - sb-vm:n-word-bits))) - ((>= index end-1) - (setf (%vector-raw-bits sequence index) value) - sequence) - (declare (optimize (speed 3) (safety 0)) - (type index index end-1)) - (setf (%vector-raw-bits sequence index) value)))))) - -(deftransform fill ((sequence item) (simple-base-string base-char) * - :policy (>= speed space)) - (let ((value (if (constant-lvar-p item) - (let* ((char (lvar-value item)) - (code (sb-xc:char-code char)) - (accum 0)) - (dotimes (i sb-vm:n-word-bytes accum) - (setf accum (logior accum (ash code (* 8 i)))))) - `(let ((code (sb-xc:char-code item))) - (setf code (dpb code (byte 8 8) code)) - (setf code (dpb code (byte 16 16) code)) - (dpb code (byte 32 32) code))))) - `(let ((length (length sequence)) - (value ,value)) - (multiple-value-bind (times rem) - (truncate length sb-vm:n-word-bytes) - (do ((index 0 (1+ index)) - (end times)) - ((>= index end) - (let ((place (* times sb-vm:n-word-bytes))) - (declare (fixnum place)) - (dotimes (j rem sequence) - (declare (index j)) - (setf (schar sequence (the index (+ place j))) item)))) - (declare (optimize (speed 3) (safety 0)) - (type index index)) - (setf (%vector-raw-bits sequence index) value)))))) + `(let ((value (logand (- (the bit item)) most-positive-word))) + ;; Unlike for the SIMPLE-BASE-STRING case, we are allowed to touch + ;; bits beyond LENGTH with impunity. + (dotimes (index (ceiling (vector-length sequence) sb-vm:n-word-bits)) + (declare (optimize (speed 3) (safety 0)) + (type index index)) + (setf (%vector-raw-bits sequence index) value)) + sequence)) + +(deftransform fill ((sequence item) (simple-base-string t) * + :policy (>= speed space)) + (let ((multiplier (logand #x0101010101010101 most-positive-word))) + `(let* ((value ,(if (and (constant-lvar-p item) + (typep (lvar-value item) 'base-char)) + (* multiplier (char-code (lvar-value item))) + ;; Use multiplication if it's known to be cheap + #+(or x86 x86-64) + `(* ,multiplier (char-code (the base-char item))) + #-(or x86 x86-64) + '(let ((code (char-code (the base-char item)))) + (setf code (dpb code (byte 8 8) code)) + (setf code (dpb code (byte 16 16) code)) + #+64-bit (dpb code (byte 32 32) code)))) + (len (vector-length sequence)) + (words (truncate len sb-vm:n-word-bytes))) + (dotimes (index words) + (declare (optimize (speed 3) (safety 0)) + (type index index)) + (setf (%vector-raw-bits sequence index) value)) + ;; For 64-bit: + ;; if 1 more byte should be written, then shift-towards-start 56 + ;; if 2 more bytes ... then shift-towards-start 48 + ;; etc + ;; This correctly rewrites the trailing null in its proper place. + (let ((bits (ash (mod len sb-vm:n-word-bytes) 3))) + (when (plusp bits) + (setf (%vector-raw-bits sequence words) + (shift-towards-start value (- bits))))) + sequence))) ;;;; %BYTE-BLT @@ -687,15 +639,15 @@ (values))) ;;;; transforms for EQL of floating point values -#-(vop-named sb-vm::eql/single-float) +(unless (vop-existsp :named sb-vm::eql/single-float) (deftransform eql ((x y) (single-float single-float)) - '(= (single-float-bits x) (single-float-bits y))) + '(= (single-float-bits x) (single-float-bits y)))) -#-(vop-named sb-vm::eql/double-float) +(unless (vop-existsp :named sb-vm::eql/double-float) (deftransform eql ((x y) (double-float double-float)) #-64-bit '(and (= (double-float-low-bits x) (double-float-low-bits y)) (= (double-float-high-bits x) (double-float-high-bits y))) - #+64-bit '(= (double-float-bits x) (double-float-bits y))) + #+64-bit '(= (double-float-bits x) (double-float-bits y)))) ;;;; modular functions @@ -769,6 +721,8 @@ ;;; position of the last set bit. We can't use this second method when ;;; the high order bit is bit 31 because shifting by 32 doesn't work ;;; too well. +;;; This is used only for ppc + sparc. +;;; FIXME: ppc64 should have a UB64-STRENGTH-REDUCE- (defun ub32-strength-reduce-constant-multiply (arg num) (declare (type (unsigned-byte 32) num)) (let ((adds 0) (shifts 0) @@ -821,14 +775,29 @@ (logior sb-vm:character-widetag (ash (char-code (lvar-value obj)) sb-vm:n-widetag-bits))) +;;; FIXME: The following should really be done by defining +;;; UNBOUND-MARKER as a primitive object. ;; So that the PCL code walker doesn't observe any use of %PRIMITIVE, ;; MAKE-UNBOUND-MARKER is an ordinary function, not a macro. #-sb-xc-host (defun make-unbound-marker () ; for interpreters (sb-sys:%primitive make-unbound-marker)) -;; Get the main compiler to transform MAKE-UNBOUND-MARKER -;; without the fopcompiler seeing it - the fopcompiler does -;; expand compiler-macros, but not source-transforms - -;; because %PRIMITIVE is not generally fopcompilable. +;; Get the main compiler to transform MAKE-UNBOUND-MARKER. (sb-c:define-source-transform make-unbound-marker () `(sb-sys:%primitive make-unbound-marker)) + +(deftransform (cas symbol-value) ((old new symbol)) + (let ((cname (and (constant-lvar-p symbol) (lvar-value symbol)))) + (case (and cname (info :variable :kind cname)) + ((:special :global) + (let ((type (info :variable :type cname))) + `(truly-the ,type + (%compare-and-swap-symbol-value ',cname old (the ,type new))))) + (t + `(progn + (about-to-modify-symbol-value symbol 'compare-and-swap new) + (%compare-and-swap-symbol-value symbol old new)))))) + +(deftransform (cas svref) ((old new vector index)) + '(let ((v (the simple-vector vector))) + (%compare-and-swap-svref v (check-bound v (length v) index) old new))) diff --git a/src/compiler/generic/vm-type.lisp b/src/compiler/generic/vm-type.lisp index 154392ae14..30d04d2778 100644 --- a/src/compiler/generic/vm-type.lisp +++ b/src/compiler/generic/vm-type.lisp @@ -56,13 +56,17 @@ (sb-xc:deftype internal-time () `(unsigned-byte ,internal-time-bits)) (defconstant internal-seconds-limit - (floor (ash 1 internal-time-bits) sb-xc:internal-time-units-per-second)) + (floor (ash 1 internal-time-bits) internal-time-units-per-second)) (sb-xc:deftype internal-seconds () `(integer 0 ,internal-seconds-limit)) (sb-xc:deftype bignum-element-type () 'sb-vm:word) (sb-xc:deftype bignum-index () `(mod ,maximum-bignum-length)) (sb-xc:deftype bignum-length () `(mod ,(1+ maximum-bignum-length))) +(sb-xc:deftype half-bignum-element-type () `(unsigned-byte ,(/ sb-vm:n-word-bits 2))) +(sb-xc:deftype half-bignum-index () `(mod ,(* maximum-bignum-length 2))) +(sb-xc:deftype half-bignum-length () `(mod ,(1+ (* maximum-bignum-length 2)))) + ;;; an index into an integer (sb-xc:deftype bit-index () `(integer 0 ,(* (1- (ash 1 (- sb-vm:n-word-bits sb-vm:n-widetag-bits))) @@ -71,14 +75,20 @@ ;;;; hooks into the type system +;;; Typically the use for UNBOXED-ARRAY is with foreign APIs where we want to +;;; require that the array being passed has byte nature, and is not SIMPLE-VECTOR. +;;; But (VECTOR NIL) contains no data, so surely there is no reason for +;;; passing it to foreign code. (sb-xc:deftype unboxed-array (&optional dims) (cons 'or (mapcar (lambda (type) `(array ,type ,dims)) - '#.(delete t (map 'list 'sb-vm:saetp-specifier - sb-vm:*specialized-array-element-type-properties*))))) + '#.(delete-if (lambda (x) (member x '(nil t))) + (map 'list 'sb-vm:saetp-specifier + sb-vm:*specialized-array-element-type-properties*))))) (sb-xc:deftype simple-unboxed-array (&optional dims) (cons 'or (mapcar (lambda (type) `(simple-array ,type ,dims)) - '#.(delete t (map 'list 'sb-vm:saetp-specifier - sb-vm:*specialized-array-element-type-properties*))))) + '#.(delete-if (lambda (x) (member x '(nil t))) + (map 'list 'sb-vm:saetp-specifier + sb-vm:*specialized-array-element-type-properties*))))) (sb-xc:deftype complex-vector (&optional element-type length) `(and (vector ,element-type ,length) (not simple-array))) @@ -106,7 +116,7 @@ (when (csubtypep eltype stype) (return stype))))) -(defun sb-xc:upgraded-array-element-type (spec &optional environment) +(defun upgraded-array-element-type (spec &optional environment) "Return the element type that will actually be used to implement an array with the specifier :ELEMENT-TYPE Spec." (declare (type lexenv-designator environment) (ignore environment)) @@ -119,7 +129,7 @@ (t (type-specifier (%upgraded-array-element-type type)))))) -(defun sb-xc:upgraded-complex-part-type (spec &optional environment) +(defun upgraded-complex-part-type (spec &optional environment) "Return the element type of the most specialized COMPLEX number type that can hold parts of type SPEC." (declare (type lexenv-designator environment) (ignore environment)) @@ -265,26 +275,48 @@ (push disjunct output))))) (t input))))) ; no change +;;; If TYPE is such that its entirety is represented by 1 widetag +;;; - and that widetag can represent nothing else - then return the widetag. +;;; This is almost but not exactly in correspondence with (SB-C:PRIMITIVE-TYPE X). +;;; But a primitive type can be more specific than the type expressed by a widetag. +;;; e.g. (SB-C:PRIMITIVE-TYPE (SPECIFIER-TYPE '(SIMD-PACK-256 DOUBLE-FLOAT)))) +;;; => #<SB-C:PRIMITIVE-TYPE :NAME SIMD-PACK-256-DOUBLE> and T +;;; So I guess we don't have a predicate that returns T if and only if a CTYPE +;;; is exactly one and only one of the "most primitive" representations, +;;; hence this. The computation is just a best effort - it's generally OK to +;;; say NIL for anything nontrivial, even if there should be an exact answer. +(defun widetag-for-exactly-type (type) + (cond ((built-in-classoid-p type) + (case (classoid-name type) + (system-area-pointer sb-vm:sap-widetag) + (fdefn sb-vm:fdefn-widetag))) + ((numeric-type-p type) + (cond ((type= type (specifier-type '(complex single-float))) + sb-vm:complex-single-float-widetag) + ((type= type (specifier-type '(complex double-float))) + sb-vm:complex-double-float-widetag) + ((type= type (specifier-type '(complex rational))) + sb-vm:complex-widetag))) + #+sb-simd-pack + ((simd-pack-type-p type) + (cond ((type= type (specifier-type 'simd-pack)) + sb-vm:simd-pack-widetag))) + #+sb-simd-pack-256 + ((simd-pack-256-type-p type) + (cond ((type= type (specifier-type 'simd-pack-256)) + sb-vm:simd-pack-256-widetag))))) + ;; Given TYPES which is a list of types from a union type, decompose into ;; two unions, one being an OR over types representable as widetags ;; with other-pointer-lowtag, and the other being the difference ;; between the input TYPES and the widetags. -;; This is architecture-independent, but unfortunately the needed VOP can't -;; be defined using DEFINE-TYPE-VOPS, so return (VALUES NIL TYPES) for -;; unsupported backends which can't generate an arbitrary call to %TEST-HEADERS. (defun widetags-from-union-type (types) (setq types (simplify-array-unions types t)) - ;; This seems preferable to a reader-conditional in generic code. - ;; There is a unit test that the supported architectures don't generate - ;; excessively large code, so hopefully it'll not get broken. - (let ((info (info :function :info '%other-pointer-subtype-p))) - (unless (and info (sb-c::fun-info-templates info)) - (return-from widetags-from-union-type (values nil types)))) (let (widetags remainder) ;; A little optimization for (OR BIGNUM other). Without this, there would ;; be a two-sided GENERIC-{<,>} test plus whatever test(s) "other" entails. - (let ((neg-bignum (specifier-type `(integer * (,sb-xc:most-negative-fixnum)))) - (pos-bignum (specifier-type `(integer (,sb-xc:most-positive-fixnum) *)))) + (let ((neg-bignum (specifier-type `(integer * (,most-negative-fixnum)))) + (pos-bignum (specifier-type `(integer (,most-positive-fixnum) *)))) (when (and (member neg-bignum types :test #'type=) (member pos-bignum types :test #'type=)) (push sb-vm:bignum-widetag widetags) @@ -293,6 +325,7 @@ (dolist (x types) (let ((adjunct (cond + ((widetag-for-exactly-type x)) ; easiest case ((and (array-type-p x) (equal (array-type-dimensions x) '(*)) (type= (array-type-specialized-element-type x) @@ -314,10 +347,9 @@ (list* (sb-vm:saetp-complex-typecode saetp) (when (eq (array-type-complexp x) :maybe) (list (sb-vm:saetp-typecode saetp))))))))) - ((classoid-p x) + ((built-in-classoid-p x) (case (classoid-name x) - (symbol sb-vm:symbol-widetag) ; plus a hack for nil - (system-area-pointer sb-vm:sap-widetag)))))) + (symbol sb-vm:symbol-widetag)))))) ; plus a hack for nil (cond ((not adjunct) (push x remainder)) ((listp adjunct) (setq widetags (nconc adjunct widetags))) (t (push adjunct widetags))))) diff --git a/src/compiler/generic/vm-typetran.lisp b/src/compiler/generic/vm-typetran.lisp index 9ddacecd16..130997e05d 100644 --- a/src/compiler/generic/vm-typetran.lisp +++ b/src/compiler/generic/vm-typetran.lisp @@ -97,10 +97,16 @@ #+sb-unicode (define-type-predicate simple-character-string-p (simple-array character (*))) (define-type-predicate system-area-pointer-p system-area-pointer) + +(when-vop-existsp (:translate signed-byte-8-p) + (define-type-predicate signed-byte-8-p (signed-byte 8))) +(when-vop-existsp (:translate signed-byte-16-p) + (define-type-predicate signed-byte-16-p (signed-byte 16))) + #-64-bit (define-type-predicate unsigned-byte-32-p (unsigned-byte 32)) -#-64-bit -(define-type-predicate signed-byte-32-p (signed-byte 32)) +(when-vop-existsp (:translate signed-byte-32-p) + (define-type-predicate signed-byte-32-p (signed-byte 32))) #+64-bit (define-type-predicate unsigned-byte-64-p (unsigned-byte 64)) #+64-bit @@ -109,7 +115,6 @@ (define-type-predicate simd-pack-p simd-pack) #+sb-simd-pack-256 (define-type-predicate simd-pack-256-p simd-pack-256) -(define-type-predicate vector-nil-p (vector nil)) (define-type-predicate weak-pointer-p weak-pointer) (define-type-predicate code-component-p code-component) #-(or x86 x86-64) (define-type-predicate lra-p lra) @@ -123,11 +128,12 @@ ;;; accepting any type object. (define-type-predicate %standard-char-p standard-char) (define-type-predicate non-null-symbol-p (and symbol (not null))) + (defglobal *backend-type-predicates-grouped* (let (plist) (loop for (type . pred) in *backend-type-predicates* - for class = (#-sb-xc-host %instance-layout + for class = (#-sb-xc-host %instance-wrapper #+sb-xc-host type-of type) do (push type (getf plist class)) @@ -156,7 +162,7 @@ (declare (inline vector-getf)) (let ((group (truly-the (or simple-vector null) (vector-getf *backend-type-predicates-grouped* - (#-sb-xc-host %instance-layout + (#-sb-xc-host %instance-wrapper #+sb-xc-host type-of type) #'eq)))) (when group @@ -164,3 +170,32 @@ (sb-kernel::ctype-eq-comparable type)) (vector-getf (truly-the simple-vector group) type #'eq 1) (vector-getf (truly-the simple-vector group) type #'type= 1)))))) + +(defglobal *backend-union-type-predicates* + (let ((unions (sort + (loop for (type . pred) in *backend-type-predicates* + when (union-type-p type) + collect (cons type pred)) + #'> + :key (lambda (x) + (length (union-type-types (car x))))))) + (coerce (loop for (key . value) in unions + collect key + collect value) + 'vector))) +(declaim (simple-vector *backend-union-type-predicates*)) + +(defun split-union-type-tests (type) + (let ((predicates *backend-union-type-predicates*) + (types (union-type-types type))) + (loop for x below (length predicates) by 2 + for union-types = (union-type-types (aref predicates x)) + when (subsetp union-types types :test #'type=) + return (values (aref predicates (1+ x)) + (set-difference types union-types))))) + +(unless-vop-existsp (:translate keywordp) +(define-source-transform keywordp (x) + `(let ((object ,x)) + (and (non-null-symbol-p object) + (= (sb-impl::symbol-package-id object) ,sb-impl::+package-id-keyword+))))) diff --git a/src/compiler/globaldb.lisp b/src/compiler/globaldb.lisp index bce24dc45d..41bbd71ad7 100644 --- a/src/compiler/globaldb.lisp +++ b/src/compiler/globaldb.lisp @@ -51,9 +51,9 @@ ;;; sources partway through bootstrapping, tch tch, overwriting its ;;; version with our version would be unlikely to help, because that ;;; would make the cross-compiler very confused.) -(defun !register-meta-info (metainfo) +(defun register-meta-info (metainfo) (let* ((name (meta-info-kind metainfo)) - (list (!get-meta-infos name))) + (list (get-meta-infos name))) (set-info-value name +info-metainfo-type-num+ (cond ((not list) metainfo) ; unique, just store it ((listp list) (cons metainfo list)) ; prepend to the list @@ -67,26 +67,11 @@ (return-from !%define-info-type it)) ; do nothing (let ((id (or id (position nil *info-types* :start 1) (error "no more INFO type numbers available")))) - (!register-meta-info + (register-meta-info (setf (aref *info-types* id) (!make-meta-info id category kind type-spec type-checker validate-function default))))) -#-sb-xc -(setf (get '!%define-info-type :sb-cold-funcall-handler/for-effect) - (lambda (category kind type-spec checker validator default id) - ;; The SB-FASL: symbols are poor style, but the lesser evil. - ;; If exported, then they'll stick around in the target image. - ;; Perhaps SB-COLD should re-export some of these. - (sb-fasl::cold-svset - (sb-fasl::cold-symbol-value '*info-types*) - id - (sb-fasl::write-slots - (sb-fasl::allocate-struct-of-type 'meta-info) - 'meta-info ; pass the type name in lieu of layout - :category category :kind kind :type-spec type-spec - :type-checker checker :validate-function validator - :default default :number id)))) ;;;; info types, and type numbers, part II: what's ;;;; needed only at compile time, not at run time @@ -115,16 +100,17 @@ ;; There was formerly a remark that (COPY-TREE TYPE-SPEC) ensures repeatable ;; fasls. That's not true now, probably never was. A compiler is permitted to ;; coalesce EQUAL quoted lists and there's no defense against it, so why try? - `(!%define-info-type - ,category ,kind ',type-spec - ,(if (eq type-spec 't) - '#'identity - `(named-lambda "check-type" (x) (the ,type-spec x))) - ,validate-function ,default - ;; Rationale for hardcoding here is explained at INFO-VECTOR-FDEFN. - ,(or (and (eq category :function) (eq kind :definition) - +fdefn-info-num+) - #+sb-xc (meta-info-number (meta-info category kind))))) + `(!cold-init-forms + (!%define-info-type + ,category ,kind ',type-spec + ,(if (eq type-spec 't) + '#'identity + `(named-lambda "check-type" (x) (the ,type-spec x))) + ,validate-function ,default + ,(or (and (eq category :function) + (case kind + (:definition +fdefn-info-num+))) + #+sb-xc (meta-info-number (meta-info category kind)))))) ;; It's an external symbol of SB-INT so wouldn't be removed automatically (push '("SB-INT" define-info-type) *!removable-symbols*) @@ -186,26 +172,17 @@ (if old ;; if -REMOVE => nil, then update NEW but return OLD (or (setq new (packed-info-remove - old +no-auxilliary-key+ info-numbers)) + old +no-auxiliary-key+ info-numbers)) old)))) (info-puthash *info-environment* name #'clear-hairy))) (not (null new)))) -;;;; *INFO-ENVIRONMENT* - -(defun !globaldb-cold-init () - ;; Genesis writes the *INFO-TYPES* array, but setting up the mapping - ;; from keyword-pair to object is deferred until cold-init. - (dovector (x (the simple-vector *info-types*)) - (when x (!register-meta-info x))) - #-sb-xc-host (setq *info-environment* (make-info-hashtable))) - ;;;; GET-INFO-VALUE ;;; If non-nil, *GLOBALDB-OBSERVER*'s CAR is a bitmask over info numbers ;;; for which you'd like to call the function in the CDR whenever info ;;; of that number is queried. -(defparameter *globaldb-observer* nil) +(defvar *globaldb-observer* nil) (declaim (type (or (cons (unsigned-byte #.(ash 1 info-number-bits)) function) null) *globaldb-observer*)) #-sb-xc-host (declaim (always-bound *globaldb-observer*)) @@ -227,18 +204,18 @@ (hookp (and (and hook (not (eql 0 (car hook))) (logbitp info-number (car hook)))))) - (multiple-value-bind (vector aux-key) + (multiple-value-bind (packed-info aux-key) (let ((name (uncross name))) (with-globaldb-name (key1 key2) name ;; In the :simple branch, KEY1 is no doubt a symbol, ;; but constraint propagation isn't informing the compiler here. - :simple (values (symbol-info-vector (truly-the symbol key1)) key2) + :simple (values (symbol-dbinfo (truly-the symbol key1)) key2) :hairy (values (info-gethash name *info-environment*) - +no-auxilliary-key+))) - (when vector - (let ((index (packed-info-value-index vector aux-key info-number))) + +no-auxiliary-key+))) + (when packed-info + (let ((index (packed-info-value-index packed-info aux-key info-number))) (when index - (let ((answer (svref vector index))) + (let ((answer (%info-ref packed-info index))) (when hookp (funcall (truly-the function (cdr hook)) name info-number answer t)) @@ -249,8 +226,15 @@ (funcall (truly-the function (cdr hook)) name info-number answer nil)) (values answer nil)))) +(!begin-collecting-cold-init-forms) ;;;; ":FUNCTION" subsection - Data pertaining to globally known functions. -(define-info-type (:function :definition) :type-spec #-sb-xc-host (or fdefn null) #+sb-xc-host t) +;;; As a special case, this info stores the interpreter's handler for sb-fasteval. +;;; There is no ambiguity, because a symbol naming a function will never store +;;; its fdefn in packed-info. Therefore if :function :definition is present +;;; for a symbol, it must be the special-form handler. In that case it is a cons +;;; of the deferred and immediate handlers (in that order) +(define-info-type (:function :definition) :type-spec #-sb-xc-host (or fdefn list) + #+sb-xc-host t) ;;; the kind of functional object being described. If null, NAME isn't ;;; a known functional object. @@ -269,21 +253,32 @@ :function nil))) -;;; The deferred mode processor for fasteval special operators. -;;; Immediate processors are hung directly off symbols in a dedicated slot. -#+sb-fasteval -(define-info-type (:function :interpreter) :type-spec (or function null)) - ;;; Indicates whether the function is deprecated. (define-info-type (:function :deprecated) :type-spec (or null deprecation-info)) -;;; Why are these here? It seems like the wrong place. +;;; FIXME: Why are these here? It seems like the wrong place. (declaim (ftype (sfunction (t &optional t symbol) ctype) specifier-type) (ftype (sfunction (t) ctype) ctype-of sb-kernel::ctype-of-array)) +;;; The parsed or unparsed type for this function, or the symbol :GENERIC-FUNCTION. +;;; Ordinarily a parsed type is stored. Only if the parsed type contains +;;; an unknown type will the original specifier be stored; we attempt to reparse +;;; on each lookup, in the hope that the type becomes known at some point. +;;; If :GENERIC-FUNCTION, the info is recomputed from methods at the time of lookup +;;; and stored back. Method redefinition resets the value to :GENERIC-FUNCTION. +(define-info-type (:function :type) + :type-spec (or ctype (cons (eql function)) (member :generic-function)) + :default (lambda (name) + (declare (ignorable name)) + #+sb-xc-host (specifier-type 'function) + #-sb-xc-host (sb-c::ftype-from-definition name))) + ;;; the ASSUMED-TYPE for this function, if we have to infer the type ;;; due to not having a declaration or definition +;;; FIXME: It may be better to have this and/or :TYPE stored in a single +;;; property as either (:known . #<ctype>) or (:assumed . #<ctype>) +;;; rather than using two different properties. Do we ever use *both* ? (define-info-type (:function :assumed-type) ;; FIXME: The type-spec really should be ;; (or approximate-fun-type null)). @@ -321,7 +316,7 @@ ;;; If only (B) is stored, then this is a DXABLE-ARGS. ;;; If both, this is an INLINING-DATA. (define-info-type (:function :inlining-data) - :type-spec (or list sb-c::dxable-args sb-c::inlining-data)) + :type-spec (or list sb-c::dxable-args sb-c::inlining-data)) ;;; This specifies whether this function may be expanded inline. If ;;; null, we don't care. @@ -333,6 +328,22 @@ ;;; through some kind of transformation but were not. (define-info-type (:function :emitted-full-calls) :type-spec list) +;; Return the number of calls to NAME that IR2 emitted as full calls, +;; not counting calls via #'F that went untracked. +;; Return 0 if the answer is nonzero but a warning was already signaled +;; about any full calls were emitted. This return convention satisfies the +;; intended use of this statistic - to decide whether to generate a warning +;; about failure to inline NAME, which is shown at most once per name +;; to avoid unleashing a flood of identical warnings. +(defun emitted-full-call-count (name) + (let ((status (car (info :function :emitted-full-calls name)))) + (and (integerp status) + ;; Bit 0 tells whether any call was NOT in the presence of + ;; a 'notinline' declaration, thus eligible to be inline. + ;; Bit 1 tells whether any warning was emitted yet. + (= (logand status 3) #b01) + (ash status -2)))) ; the call count as tracked by IR2 + ;;; a macro-like function which transforms a call to this function ;;; into some other Lisp form. This expansion is inhibited if inline ;;; expansion is inhibited. @@ -367,6 +378,10 @@ ;;; For PCL code walker (define-info-type (:function :walker-template) :type-spec (or list symbol)) +;;; The exact type for which this function is the predicate. +;;; Applicable only for symbols in the CL package. +(define-info-type (:function :predicate-for) :type-spec t) + ;;; This is a type specifier <t> such that if an argument X to the function ;;; does not satisfy (TYPEP x <t>) then the function definitely returns NIL. ;;; When the named function is a predicate that appears in (SATISFIES p) @@ -395,15 +410,19 @@ ;;; the declared type for this variable (define-info-type (:variable :type) :type-spec ctype - :default #+sb-xc-host (lambda (x) - (declare (special *universal-type*) (ignore x)) - *universal-type*) - #-sb-xc-host *universal-type*) + :default (lambda (name) + (declare (ignore name) + #+sb-xc-host (special *universal-type*)) + *universal-type*)) ;;; where this type and kind information came from (define-info-type (:variable :where-from) :type-spec (member :declared :assumed :defined) :default :assumed) +;;; a list of forward references to this constant. +(define-info-type (:variable :forward-references) + :type-spec list) + ;;; the macro-expansion for symbol-macros (define-info-type (:variable :macro-expansion) :type-spec t) @@ -471,6 +490,13 @@ ;;; The classoid-cell for this type (define-info-type (:type :classoid-cell) :type-spec t) +;;; wrapper for this type being used by the compiler +(define-info-type (:type :compiler-layout) + :type-spec (or wrapper null) + :default (lambda (name) + (let ((class (find-classoid name nil))) + (and class (classoid-wrapper class))))) + ;;; DEFTYPE lambda-list ;; FIXME: remove this after making swank-fancy-inspector not use it. (define-info-type (:type :lambda-list) :type-spec t) @@ -508,6 +534,12 @@ (setq *recognized-declarations* (delete name *recognized-declarations*)))))) +(setf (sb-int:info :declaration :known 'sb-c::tlab) + (lambda (res spec vars fvars) + (declare (ignore vars fvars)) + (sb-c::make-lexenv :default res + :user-data `((:declare ,@spec))))) + ;;;; ":ALIEN-TYPE" subsection - Data pertaining to globally known alien-types. (define-info-type (:alien-type :kind) :type-spec (member :primitive :defined :unknown) @@ -523,9 +555,7 @@ :type-spec (or null sb-alien-internals:alien-type)) ;;;; ":SETF" subsection - Data pertaining to expansion of the omnipotent macro. -(define-info-type (:setf :documentation) :type-spec (or string null)) -(define-info-type (:setf :expander) - :type-spec (or symbol function (cons integer function) null)) +(define-info-type (:setf :expander) :type-spec (or function list)) ;;;; ":CAS" subsection - Like SETF but there are no "inverses", just expanders (define-info-type (:cas :expander) :type-spec (or function null)) @@ -551,9 +581,27 @@ (define-info-type (:source-location :declaration) :type-spec t) (define-info-type (:source-location :alien-type) :type-spec t) +;;; If we used the maximum number of IDs available, a package gets no ID. +;;; Any symbols in that package must use SYMBOL-DBINFO for their package. +;;; Technically we can't store NIL, because that would be package ID 0, +;;; i.e. directly represented in the symbol, but this type spec has to be +;;; correct for what INFO can return, not what it may store. +(define-info-type (:symbol :package) :type-spec (or package null)) + +(!defun-from-collected-cold-init-forms !info-type-cold-init) + +#-sb-xc-host +(defun !globaldb-cold-init () + (let ((h (make-info-hashtable))) + (setf (sb-thread:mutex-name (info-env-mutex h)) "globaldb") + (setq *info-environment* h)) + (setq *globaldb-observer* nil) + (setq *info-types* (make-array (ash 1 info-number-bits) :initial-element nil)) + (!info-type-cold-init)) + ;; This is for the SB-INTROSPECT contrib module, and debugging. (defun call-with-each-info (function symbol) - (awhen (symbol-info-vector symbol) + (awhen (symbol-dbinfo symbol) (%call-with-each-info function it symbol))) ;; This is for debugging at the REPL. diff --git a/src/compiler/gtn.lisp b/src/compiler/gtn.lisp index b3c403e008..d98f40957f 100644 --- a/src/compiler/gtn.lisp +++ b/src/compiler/gtn.lisp @@ -18,9 +18,15 @@ ;;; passing locations and return conventions and TNs for local variables. (defun gtn-analyze (component) (setf (component-info component) (make-ir2-component)) - (let ((funs (component-lambdas component))) + (let ((funs (component-lambdas component)) + #+fp-and-pc-standard-save + (old-fp (make-old-fp-save-location)) + #+fp-and-pc-standard-save + (old-pc (make-return-pc-save-location))) (dolist (fun funs) - (assign-ir2-physenv fun) + (assign-ir2-environment fun + #+fp-and-pc-standard-save old-fp + #+fp-and-pc-standard-save old-pc) (assign-ir2-nlx-info fun) (assign-lambda-var-tns fun nil) (dolist (let (lambda-lets fun)) @@ -29,7 +35,7 @@ (values)) ;;; We have to allocate the home TNs for variables before we can call -;;; ASSIGN-IR2-PHYSENV so that we can close over TNs that haven't +;;; ASSIGN-IR2-ENVIRONMENT so that we can close over TNs that haven't ;;; had their home environment assigned yet. Here we evaluate the ;;; DEBUG-INFO/SPEED tradeoff to determine how variables are ;;; allocated. If SPEED is 3, then all variables are subject to @@ -59,29 +65,36 @@ (not (lambda-var-explicit-value-cell var))) ;; Force closed-over indirect LAMBDA-VARs without explicit ;; VALUE-CELLs to the stack, and make sure that they are - ;; live over the dynamic contour of the physenv. + ;; live over the dynamic contour of the environment. (setf (tn-sc res) (if ptype-info (second ptype-info) (sc-or-lose 'sb-vm::control-stack))) - (physenv-live-tn res (lambda-physenv fun))) + (environment-live-tn res (lambda-environment fun))) (debug-variable-p - (physenv-debug-live-tn res (lambda-physenv fun)))) + ;; If it's a constant it may end up being never read, + ;; replaced by COERCE-FROM-CONSTANT. + ;; Yet it might get saved on the stack, but since it's + ;; never read no stack space is allocated for it in the + ;; callee frame. + (unless (type-singleton-p (leaf-type var)) + (environment-debug-live-tn res (lambda-environment fun))))) (setf (tn-leaf res) var) (setf (tn-type res) (leaf-type var)) (setf (leaf-info var) res)))) (values)) -;;; Give CLAMBDA an IR2-PHYSENV structure. (And in order to +;;; Give CLAMBDA an IR2-ENVIRONMENT structure. (And in order to ;;; properly initialize the new structure, we make the TNs which hold ;;; environment values and the old-FP/return-PC.) -(defun assign-ir2-physenv (clambda) +(defun assign-ir2-environment (clambda #+fp-and-pc-standard-save old-fp + #+fp-and-pc-standard-save old-pc) (declare (type clambda clambda)) - (let* ((lambda-physenv (lambda-physenv clambda)) + (let* ((lambda-environment (lambda-environment clambda)) (indirect-fp-tns) - (ir2-physenv-alist - (loop for thing in (physenv-closure lambda-physenv) + (ir2-environment-alist + (loop for thing in (environment-closure lambda-environment) collect (cons thing (etypecase thing @@ -90,11 +103,11 @@ (make-normal-tn (primitive-type (leaf-type thing)))) ((not (lambda-var-explicit-value-cell thing)) - (let ((physenv (lambda-physenv (lambda-var-home thing)))) - (or (getf indirect-fp-tns physenv) + (let ((env (lambda-environment (lambda-var-home thing)))) + (or (getf indirect-fp-tns env) (let ((tn (make-normal-tn *backend-t-primitive-type*))) (push tn indirect-fp-tns) - (push physenv indirect-fp-tns) + (push env indirect-fp-tns) tn)))) (t (make-normal-tn *backend-t-primitive-type*)))) @@ -102,15 +115,27 @@ (make-normal-tn *backend-t-primitive-type*)) (clambda (make-normal-tn *backend-t-primitive-type*))))))) - (let ((res (make-ir2-physenv - :closure ir2-physenv-alist - :return-pc-pass (make-return-pc-passing-location - (xep-p clambda))))) - (setf (physenv-info lambda-physenv) res) - (setf (ir2-physenv-old-fp res) - (make-old-fp-save-location lambda-physenv)) - (setf (ir2-physenv-return-pc res) - (make-return-pc-save-location lambda-physenv)))) + (let ((res (make-ir2-environment + :closure ir2-environment-alist + :return-pc-pass #+fp-and-pc-standard-save + old-pc + #-fp-and-pc-standard-save + (make-return-pc-passing-location (xep-p clambda))))) + (setf (environment-info lambda-environment) res) + (setf (ir2-environment-old-fp res) + #-fp-and-pc-standard-save + (make-old-fp-save-location lambda-environment) + #+fp-and-pc-standard-save + old-fp) + (setf (ir2-environment-return-pc res) + #-fp-and-pc-standard-save + (make-return-pc-save-location lambda-environment) + #+fp-and-pc-standard-save + old-pc) + #+fp-and-pc-standard-save + (progn + (push old-fp (ir2-environment-live-tns (environment-info lambda-environment))) + (push old-pc (ir2-environment-live-tns (environment-info lambda-environment)))))) (values)) @@ -226,8 +251,8 @@ ;;; isn't live afterwards. (defun assign-ir2-nlx-info (fun) (declare (type clambda fun)) - (let ((physenv (lambda-physenv fun))) - (dolist (nlx (physenv-nlx-info physenv)) + (let ((env (lambda-environment fun))) + (dolist (nlx (environment-nlx-info env)) (setf (nlx-info-info nlx) (make-ir2-nlx-info :home (when (member (cleanup-kind (nlx-info-cleanup nlx)) @@ -237,8 +262,8 @@ (make-stack-pointer-tn))) :save-sp (unless (eq (cleanup-kind (nlx-info-cleanup nlx)) :unwind-protect) - (make-nlx-sp-tn physenv)) - :block-tn (physenv-live-tn + (make-nlx-sp-tn env)) + :block-tn (environment-live-tn (make-normal-tn (primitive-type-or-lose (ecase (cleanup-kind (nlx-info-cleanup nlx)) @@ -246,5 +271,5 @@ 'catch-block) ((:unwind-protect :block :tagbody) 'unwind-block)))) - physenv))))) + env))))) (values)) diff --git a/src/compiler/hppa/alloc.lisp b/src/compiler/hppa/alloc.lisp deleted file mode 100644 index a3c968633f..0000000000 --- a/src/compiler/hppa/alloc.lisp +++ /dev/null @@ -1,224 +0,0 @@ -;;;; allocation VOPs for the HPPA - -;;;; This software is part of the SBCL system. See the README file for -;;;; more information. -;;;; -;;;; This software is derived from the CMU CL system, which was -;;;; written at Carnegie Mellon University and released into the -;;;; public domain. The software is in the public domain and is -;;;; provided with absolutely no warranty. See the COPYING and CREDITS -;;;; files for more information. - -(in-package "SB-VM") - -;;;; LIST and LIST* -(define-vop (list-or-list*) - (:args (things :more t)) - (:temporary (:scs (descriptor-reg)) ptr) - (:temporary (:scs (descriptor-reg)) temp) - (:temporary (:scs (descriptor-reg) :to (:result 0) :target result) - res) - (:info num) - (:results (result :scs (descriptor-reg))) - (:variant-vars star) - (:policy :safe) - (:node-var node) - (:generator 0 - (cond ((zerop num) - (move null-tn result)) - ((and star (= num 1)) - (move (tn-ref-tn things) result)) - (t - (macrolet - ((store-car (tn list &optional (slot cons-car-slot)) - `(let ((reg (sc-case ,tn - ((any-reg descriptor-reg zero null) ,tn) - (control-stack - (load-stack-tn temp ,tn) - temp)))) - (storew reg ,list ,slot list-pointer-lowtag)))) - (let* ((dx-p (node-stack-allocate-p node)) - (cons-cells (if star (1- num) num)) - (alloc (* (pad-data-block cons-size) cons-cells))) - (pseudo-atomic (:extra (if dx-p 0 alloc)) - (when dx-p - (align-csp res)) - (set-lowtag list-pointer-lowtag (if dx-p csp-tn alloc-tn) res) - (when dx-p - (if (typep alloc '(signed-byte 14)) - (inst ldo alloc csp-tn csp-tn) - ;; FIXME: We have TEMP available, so can do an - ;; LIDL / LDO / ADD sequence here instead of - ;; punting. - (error "VOP LIST-OR-LIST* can't stack-allocate more than 511 CONSes at once"))) - (move res ptr) - (dotimes (i (1- cons-cells)) - (store-car (tn-ref-tn things) ptr) - (setf things (tn-ref-across things)) - (inst addi (pad-data-block cons-size) ptr ptr) - (storew ptr ptr - (- cons-cdr-slot cons-size) - list-pointer-lowtag)) - (store-car (tn-ref-tn things) ptr) - (cond (star - (setf things (tn-ref-across things)) - (store-car (tn-ref-tn things) ptr cons-cdr-slot)) - (t - (storew null-tn ptr - cons-cdr-slot list-pointer-lowtag))) - (aver (null (tn-ref-across things))) - (move res result)))))))) - -(define-vop (list list-or-list*) - (:variant nil)) - -(define-vop (list* list-or-list*) - (:variant t)) - - -;;;; Special purpose inline allocators. -;;; ALLOCATE-VECTOR -(define-vop (allocate-vector-on-heap) - (:args (type :scs (unsigned-reg)) - (length :scs (any-reg)) - (words :scs (any-reg))) - (:arg-types positive-fixnum - positive-fixnum - positive-fixnum) - (:temporary (:sc non-descriptor-reg) bytes) - (:results (result :scs (descriptor-reg) :from :load)) - #-stack-allocatable-vectors - (:translate allocate-vector) - (:policy :fast-safe) - (:generator 100 - (inst addi (+ lowtag-mask - (* vector-data-offset n-word-bytes)) words bytes) - (inst dep 0 31 n-lowtag-bits bytes) - (pseudo-atomic () - (set-lowtag other-pointer-lowtag alloc-tn result) - (inst add bytes alloc-tn alloc-tn) - (storew type result 0 other-pointer-lowtag) - (storew length result vector-length-slot other-pointer-lowtag)))) - -(define-vop (allocate-vector-on-stack) - (:args (type :scs (unsigned-reg)) - (length :scs (any-reg)) - (words :scs (any-reg))) - (:arg-types positive-fixnum - positive-fixnum - positive-fixnum) - (:temporary (:sc non-descriptor-reg) bytes temp) - (:results (result :scs (descriptor-reg) :from :load)) - (:policy :fast-safe) - (:generator 100 - (inst addi (+ lowtag-mask - (* vector-data-offset n-word-bytes)) words bytes) - (inst dep 0 31 n-lowtag-bits bytes) - ;; FIXME: It would be good to check for stack overflow here. - (pseudo-atomic () - (align-csp temp) - (set-lowtag other-pointer-lowtag csp-tn result) - (inst addi (* vector-data-offset n-word-bytes) csp-tn temp) - (inst add bytes csp-tn csp-tn) - (storew type result 0 other-pointer-lowtag) - (storew length result vector-length-slot other-pointer-lowtag) - (let ((loop (gen-label))) - (emit-label loop) - (inst comb :<> temp csp-tn loop :nullify t) - (inst stwm zero-tn n-word-bytes temp))))) - -(define-vop (make-fdefn) - (:translate make-fdefn) - (:policy :fast-safe) - (:args (name :scs (descriptor-reg) :to :eval)) - (:temporary (:scs (non-descriptor-reg)) temp) - (:results (result :scs (descriptor-reg) :from :argument)) - (:generator 37 - (with-fixed-allocation (result nil temp fdefn-widetag fdefn-size nil) - (inst li (make-fixup 'undefined-tramp :assembly-routine) temp) - (storew name result fdefn-name-slot other-pointer-lowtag) - (storew null-tn result fdefn-fun-slot other-pointer-lowtag) - (storew temp result fdefn-raw-addr-slot other-pointer-lowtag)))) - -(define-vop (make-closure) - (:args (function :to :save :scs (descriptor-reg))) - (:info label length stack-allocate-p) - (:ignore label) - (:temporary (:scs (non-descriptor-reg)) temp) - (:results (result :scs (descriptor-reg))) - (:generator 10 - (with-fixed-allocation - (result nil temp closure-widetag - (+ length closure-info-offset) - stack-allocate-p :lowtag fun-pointer-lowtag) - (storew function result closure-fun-slot fun-pointer-lowtag)))) - -;;; The compiler likes to be able to directly make value cells. -(define-vop (make-value-cell) - (:args (value :to :save :scs (descriptor-reg any-reg))) - (:temporary (:scs (non-descriptor-reg)) temp) - (:results (result :scs (descriptor-reg))) - (:info stack-allocate-p) - (:generator 10 - (with-fixed-allocation - (result nil temp value-cell-widetag value-cell-size stack-allocate-p) - (storew value result value-cell-value-slot other-pointer-lowtag)))) - -;;;; Automatic allocators for primitive objects. - -(define-vop (make-unbound-marker) - (:args) - (:results (result :scs (descriptor-reg any-reg))) - (:generator 1 - (inst li unbound-marker-widetag result))) - -(define-vop (make-funcallable-instance-tramp) - (:args) - (:results (result :scs (any-reg))) - (:generator 1 - (inst li (make-fixup 'funcallable-instance-tramp :assembly-routine) - result))) - -(define-vop (fixed-alloc) - (:args) - (:info name words type lowtag stack-allocate-p) - (:ignore name) - (:results (result :scs (descriptor-reg))) - (:temporary (:scs (non-descriptor-reg)) temp) - (:generator 4 - (with-fixed-allocation - (result nil temp type words stack-allocate-p - :lowtag lowtag :maybe-write t)))) - -(define-vop (var-alloc) - (:args (extra :scs (any-reg))) - (:arg-types positive-fixnum) - (:info name words type lowtag stack-allocate-p) - (:ignore name stack-allocate-p) - (:results (result :scs (descriptor-reg))) - (:temporary (:scs (any-reg)) bytes) - (:temporary (:scs (non-descriptor-reg)) header) - (:generator 6 - (inst addi (* (1+ words) n-word-bytes) extra bytes) - (inst sll bytes (- n-widetag-bits 2) header) - ;; The specified EXTRA value is the exact value placed in the header - ;; as the word count when allocating code. - (cond ((= type code-header-widetag) - (inst addi type header header)) - (t - (cond ((> (length-field-shift type) n-widetag-bits) - ;; can't encode (+ (ash -2 n-widetag-bits) instance-widetag) - ;; as an immediate operand, so do what worked before. - (inst addi (+ (ash -2 n-widetag-bits) 0) header header) - ;; now shift left a few bits more - (inst sll header (- (length-field-shift type) n-widetag-bits) header) - ;; and add the widetag in - (inst addi type header header)) - (t - (inst addi (+ (ash -2 n-widetag-bits) type) header header))) - (inst dep 0 31 n-lowtag-bits bytes))) - (pseudo-atomic () - (set-lowtag lowtag alloc-tn result) - (storew header result 0 lowtag) - (inst add alloc-tn bytes alloc-tn)))) - diff --git a/src/compiler/hppa/arith.lisp b/src/compiler/hppa/arith.lisp deleted file mode 100644 index 8706e6d220..0000000000 --- a/src/compiler/hppa/arith.lisp +++ /dev/null @@ -1,932 +0,0 @@ -;;;; the VM definition arithmetic VOPs for HPPA - -;;;; This software is part of the SBCL system. See the README file for -;;;; more information. -;;;; -;;;; This software is derived from the CMU CL system, which was -;;;; written at Carnegie Mellon University and released into the -;;;; public domain. The software is in the public domain and is -;;;; provided with absolutely no warranty. See the COPYING and CREDITS -;;;; files for more information. - -(in-package "SB-VM") - -;;;; Unary operations. - -(define-vop (fast-safe-arith-op) - (:policy :fast-safe)) - -(define-vop (fixnum-unop fast-safe-arith-op) - (:args (x :scs (any-reg))) - (:results (res :scs (any-reg))) - (:note "inline fixnum arithmetic") - (:arg-types tagged-num) - (:result-types tagged-num)) - -(define-vop (signed-unop fast-safe-arith-op) - (:args (x :scs (signed-reg))) - (:results (res :scs (signed-reg))) - (:note "inline (signed-byte 32) arithmetic") - (:arg-types signed-num) - (:result-types signed-num)) - -(define-vop (fast-negate/fixnum fixnum-unop) - (:translate %negate) - (:generator 1 - (inst sub zero-tn x res))) - -(define-vop (fast-negate/signed signed-unop) - (:translate %negate) - (:generator 2 - (inst sub zero-tn x res))) - -(define-vop (fast-lognot/fixnum fixnum-unop) - (:translate lognot) - (:temporary (:scs (any-reg) :to (:result 0)) - temp) - (:generator 1 - (inst li (fixnumize -1) temp) - (inst xor x temp res))) - -(define-vop (fast-lognot/signed signed-unop) - (:translate lognot) - (:generator 2 - (inst uaddcm zero-tn x res))) - -;;;; Binary fixnum operations. - -;;; Assume that any constant operand is the second arg... - -(define-vop (fast-fixnum-binop fast-safe-arith-op) - (:args (x :target r :scs (any-reg zero)) - (y :target r :scs (any-reg zero))) - (:arg-types tagged-num tagged-num) - (:results (r :scs (any-reg))) - (:result-types tagged-num) - (:note "inline fixnum arithmetic")) - -(define-vop (fast-unsigned-binop fast-safe-arith-op) - (:args (x :target r :scs (unsigned-reg zero)) - (y :target r :scs (unsigned-reg zero))) - (:arg-types unsigned-num unsigned-num) - (:results (r :scs (unsigned-reg))) - (:result-types unsigned-num) - (:note "inline (unsigned-byte 32) arithmetic")) - -(define-vop (fast-signed-binop fast-safe-arith-op) - (:args (x :target r :scs (signed-reg zero)) - (y :target r :scs (signed-reg zero))) - (:arg-types signed-num signed-num) - (:results (r :scs (signed-reg))) - (:result-types signed-num) - (:note "inline (signed-byte 32) arithmetic")) - -(define-vop (fast-fixnum-c-binop fast-fixnum-binop) - (:args (x :target r :scs (any-reg))) - (:info y) - (:arg-types tagged-num (:constant integer))) - -(define-vop (fast-signed-c-binop fast-signed-binop) - (:args (x :target r :scs (signed-reg))) - (:info y) - (:arg-types tagged-num (:constant integer))) - -(define-vop (fast-unsigned-c-binop fast-unsigned-binop) - (:args (x :target r :scs (unsigned-reg))) - (:info y) - (:arg-types tagged-num (:constant integer))) - -(macrolet - ((define-binop (translate cost untagged-cost op arg-swap) - `(progn - (define-vop (,(symbolicate "FAST-" translate "/FIXNUM=>FIXNUM") - fast-fixnum-binop) - (:args (x :target r :scs (any-reg)) - (y :target r :scs (any-reg))) - (:translate ,translate) - (:generator ,(1+ cost) - ,(if arg-swap - `(inst ,op y x r) - `(inst ,op x y r)))) - (define-vop (,(symbolicate "FAST-" translate "/SIGNED=>SIGNED") - fast-signed-binop) - (:args (x :target r :scs (signed-reg)) - (y :target r :scs (signed-reg))) - (:translate ,translate) - (:generator ,(1+ untagged-cost) - ,(if arg-swap - `(inst ,op y x r) - `(inst ,op x y r)))) - (define-vop (,(symbolicate "FAST-" translate "/UNSIGNED=>UNSIGNED") - fast-unsigned-binop) - (:args (x :target r :scs (unsigned-reg)) - (y :target r :scs (unsigned-reg))) - (:translate ,translate) - (:generator ,(1+ untagged-cost) - ,(if arg-swap - `(inst ,op y x r) - `(inst ,op x y r))))))) - (define-binop + 1 5 add nil) - (define-binop - 1 5 sub nil) - (define-binop logior 1 2 or nil) - (define-binop logand 1 2 and nil) - (define-binop logandc1 1 2 andcm t) - (define-binop logandc2 1 2 andcm nil) - (define-binop logxor 1 2 xor nil)) - -(macrolet - ((define-c-binop (translate cost untagged-cost tagged-type untagged-type inst) - `(progn - (define-vop (,(symbolicate "FAST-" translate "-C/FIXNUM=>FIXNUM") - fast-fixnum-c-binop) - (:arg-types tagged-num (:constant ,tagged-type)) - (:translate ,translate) - (:generator ,cost - (let ((y (fixnumize y))) - ,inst))) - (define-vop (,(symbolicate "FAST-" translate "-C/SIGNED=>SIGNED") - fast-signed-c-binop) - (:arg-types signed-num (:constant ,untagged-type)) - (:translate ,translate) - (:generator ,untagged-cost - ,inst)) - (define-vop (,(symbolicate "FAST-" translate "-C/UNSIGNED=>UNSIGNED") - fast-unsigned-c-binop) - (:arg-types unsigned-num (:constant ,untagged-type)) - (:translate ,translate) - (:generator ,untagged-cost - ,inst))))) - - (define-c-binop + 1 3 (signed-byte 9) (signed-byte 11) - (inst addi y x r)) - (define-c-binop - 1 3 - (integer #.(- 1 (ash 1 8)) #.(ash 1 8)) - (integer #.(- 1 (ash 1 10)) #.(ash 1 10)) - (inst addi (- y) x r))) - -(define-vop (fast-lognor/fixnum=>fixnum fast-fixnum-binop) - (:translate lognor) - (:args (x :target r :scs (any-reg)) - (y :target r :scs (any-reg))) - (:temporary (:sc non-descriptor-reg) temp) - (:generator 4 - (inst or x y temp) - (inst uaddcm zero-tn temp temp) - (inst addi (- fixnum-tag-mask) temp r))) - -(define-vop (fast-lognor/signed=>signed fast-signed-binop) - (:translate lognor) - (:args (x :target r :scs (signed-reg)) - (y :target r :scs (signed-reg))) - (:generator 4 - (inst or x y r) - (inst uaddcm zero-tn r r))) - -(define-vop (fast-lognor/unsigned=>unsigned fast-unsigned-binop) - (:translate lognor) - (:args (x :target r :scs (unsigned-reg)) - (y :target r :scs (unsigned-reg))) - (:generator 4 - (inst or x y r) - (inst uaddcm zero-tn r r))) - -;;; Shifting -(macrolet - ((fast-ash (name reg num tag save) - `(define-vop (,name) - (:translate ash) - (:note "inline ASH") - (:policy :fast-safe) - (:args (number :scs (,reg) :to :save) - (count :scs (signed-reg))) - (:arg-types ,num ,tag) - (:results (result :scs (,reg))) - (:result-types ,num) - (:temporary (:scs (unsigned-reg) - ,@(unless save - '(:to (:result 0)))) temp) - (:generator 8 - (inst comb :>= count zero-tn positive :nullify t) - (inst sub zero-tn count temp) - ,@(if save - '(;; Unsigned case - (inst comiclr 31 temp result :>=) - (inst b done :nullify t) - (inst mtctl temp :sar) - (inst b done) - (inst shd zero-tn number :variable result)) - '(;; Signed case - (inst comiclr 31 temp zero-tn :>=) - (inst li 31 temp) - (inst mtctl temp :sar) - (inst extrs number 0 1 temp) - (inst b done) - (inst shd temp number :variable result))) - POSITIVE - (inst subi 31 count temp) - (inst mtctl temp :sar) - (inst zdep number :variable 32 result) - DONE)))) - (fast-ash fast-ash/unsigned=>unsigned unsigned-reg unsigned-num - tagged-num t) - (fast-ash fast-ash/signed=>signed signed-reg signed-num signed-num nil)) - -(define-vop (fast-ash-c/unsigned=>unsigned) - (:translate ash) - (:note "inline ASH") - (:policy :fast-safe) - (:args (number :scs (unsigned-reg))) - (:info count) - (:arg-types unsigned-num (:constant integer)) - (:results (result :scs (unsigned-reg))) - (:result-types unsigned-num) - (:generator 1 - (cond - ((< count -31) (move zero-tn result)) - ((< count 0) (inst srl number (min (- count) 31) result)) - ((> count 0) (inst sll number (min count 31) result)) - (t (bug "identity ASH not transformed away"))))) - -(define-vop (fast-ash-c/signed=>signed) - (:translate ash) - (:note "inline ASH") - (:policy :fast-safe) - (:args (number :scs (signed-reg))) - (:info count) - (:arg-types signed-num (:constant integer)) - (:results (result :scs (signed-reg))) - (:result-types signed-num) - (:generator 1 - (cond - ((< count 0) (inst sra number (min (- count) 31) result)) - ((> count 0) (inst sll number (min count 31) result)) - (t (bug "identity ASH not transformed away"))))) - -(macrolet ((def (name sc-type type result-type cost) - `(define-vop (,name) - (:translate ash) - (:note "inline ASH") - (:policy :fast-safe) - (:args (number :scs (,sc-type)) - (amount :scs (signed-reg unsigned-reg immediate))) - (:arg-types ,type positive-fixnum) - (:results (result :scs (,result-type))) - (:result-types ,type) - (:temporary (:scs (,sc-type) :to (:result 0)) temp) - (:generator ,cost - (sc-case amount - ((signed-reg unsigned-reg) - (inst subi 31 amount temp) - (inst mtctl temp :sar) - (inst zdep number :variable 32 result)) - (immediate - (let ((amount (tn-value amount))) - (aver (> amount 0)) - (inst sll number amount result)))))))) - (def fast-ash-left/fixnum=>fixnum any-reg tagged-num any-reg 2) - (def fast-ash-left/signed=>signed signed-reg signed-num signed-reg 3) - (def fast-ash-left/unsigned=>unsigned unsigned-reg unsigned-num unsigned-reg 3)) - -(define-vop (signed-byte-32-len) - (:translate integer-length) - (:note "inline (signed-byte 32) integer-length") - (:policy :fast-safe) - (:args (arg :scs (signed-reg) :target shift)) - (:arg-types signed-num) - (:results (res :scs (any-reg))) - (:result-types positive-fixnum) - (:temporary (:scs (non-descriptor-reg) :from (:argument 0)) shift) - (:generator 30 - (inst move arg shift :>=) - (inst uaddcm zero-tn shift shift) - (inst comb := shift zero-tn done) - (inst li 0 res) - LOOP - (inst srl shift 1 shift) - (inst comb :<> shift zero-tn loop) - (inst addi (fixnumize 1) res res) - DONE)) - -(define-vop (unsigned-byte-32-count) - (:translate logcount) - (:note "inline (unsigned-byte 32) logcount") - (:policy :fast-safe) - (:args (arg :scs (unsigned-reg) :target num)) - (:arg-types unsigned-num) - (:results (res :scs (unsigned-reg))) - (:result-types positive-fixnum) - (:temporary (:scs (non-descriptor-reg) :from (:argument 0) :to (:result 0) - :target res) num) - (:temporary (:scs (non-descriptor-reg)) mask temp) - (:generator 30 - (inst li #x55555555 mask) - (inst srl arg 1 temp) - (inst and arg mask num) - (inst and temp mask temp) - (inst add num temp num) - (inst li #x33333333 mask) - (inst srl num 2 temp) - (inst and num mask num) - (inst and temp mask temp) - (inst add num temp num) - (inst li #x0f0f0f0f mask) - (inst srl num 4 temp) - (inst and num mask num) - (inst and temp mask temp) - (inst add num temp num) - (inst li #x00ff00ff mask) - (inst srl num 8 temp) - (inst and num mask num) - (inst and temp mask temp) - (inst add num temp num) - (inst li #x0000ffff mask) - (inst srl num 16 temp) - (inst and num mask num) - (inst and temp mask temp) - (inst add num temp res))) - -;;; Multiply and Divide. - -(define-vop (fast-*/fixnum=>fixnum fast-fixnum-binop) - (:translate *) - (:args (x :scs (any-reg zero) :target x-pass) - (y :scs (any-reg zero) :target y-pass)) - (:temporary (:sc signed-reg :offset nl0-offset - :from (:argument 0) :to (:result 0)) x-pass) - (:temporary (:sc signed-reg :offset nl1-offset - :from (:argument 1) :to (:result 0)) y-pass) - (:temporary (:sc signed-reg :offset nl2-offset :target r - :from (:argument 1) :to (:result 0)) res-pass) - (:temporary (:sc signed-reg :offset nl3-offset :to (:result 0)) tmp) - (:temporary (:sc signed-reg :offset nl4-offset - :from (:argument 1) :to (:result 0)) sign) - (:temporary (:sc interior-reg :offset lip-offset) lip) - (:ignore lip sign) ; fix-lav: why dont we ignore tmp ? - (:generator 30 - ;; looking at the register setup above, not sure if both can clash - ;; maybe it is ok that x and x-pass share register ? like it was - (unless (location= y y-pass) - (inst sra x 2 x-pass)) - (let ((fixup (make-fixup 'multiply :assembly-routine))) - (inst ldil fixup tmp) - (inst ble fixup lisp-heap-space tmp)) - (if (location= y y-pass) - (inst sra x 2 x-pass) - (inst move y y-pass)) - (move res-pass r))) - -(define-vop (fast-*/signed=>signed fast-signed-binop) - (:translate *) - (:args (x :scs (signed-reg) :target x-pass) - (y :scs (signed-reg) :target y-pass)) - (:temporary (:sc signed-reg :offset nl0-offset - :from (:argument 0) :to (:result 0)) x-pass) - (:temporary (:sc signed-reg :offset nl1-offset - :from (:argument 1) :to (:result 0)) y-pass) - (:temporary (:sc signed-reg :offset nl2-offset :target r - :from (:argument 1) :to (:result 0)) res-pass) - (:temporary (:sc signed-reg :offset nl3-offset :to (:result 0)) tmp) - (:temporary (:sc signed-reg :offset nl4-offset - :from (:argument 1) :to (:result 0)) sign) - (:temporary (:sc interior-reg :offset lip-offset) lip) - (:ignore lip sign) - (:generator 31 - (let ((fixup (make-fixup 'multiply :assembly-routine))) - (move x x-pass) - (move y y-pass) - (inst ldil fixup tmp) - (inst ble fixup lisp-heap-space tmp) - (inst nop) - (move res-pass r)))) - -(define-vop (fast-*/unsigned=>unsigned fast-unsigned-binop) - (:translate *) - (:args (x :scs (unsigned-reg) :target x-pass) - (y :scs (unsigned-reg) :target y-pass)) - (:temporary (:sc unsigned-reg :offset nl0-offset - :from (:argument 0) :to (:result 0)) x-pass) - (:temporary (:sc unsigned-reg :offset nl1-offset - :from (:argument 1) :to (:result 0)) y-pass) - (:temporary (:sc unsigned-reg :offset nl2-offset :target r - :from (:argument 1) :to (:result 0)) res-pass) - (:temporary (:sc unsigned-reg :offset nl3-offset :to (:result 0)) tmp) - (:temporary (:sc unsigned-reg :offset nl4-offset - :from (:argument 1) :to (:result 0)) sign) - (:temporary (:sc interior-reg :offset lip-offset) lip) - (:ignore lip sign) - (:generator 31 - (let ((fixup (make-fixup 'multiply :assembly-routine))) - (move x x-pass) - (move y y-pass) - (inst ldil fixup tmp) - (inst ble fixup lisp-heap-space tmp) - (inst nop) - (move res-pass r)))) - -(define-vop (fast-truncate/fixnum fast-fixnum-binop) - (:translate truncate) - (:args (x :scs (any-reg) :target x-pass) - (y :scs (any-reg) :target y-pass)) - (:temporary (:sc signed-reg :offset nl0-offset - :from (:argument 0) :to (:result 0)) x-pass) - (:temporary (:sc signed-reg :offset nl1-offset - :from (:argument 1) :to (:result 0)) y-pass) - (:temporary (:sc signed-reg :offset nl2-offset :target q - :from (:argument 1) :to (:result 0)) q-pass) - (:temporary (:sc signed-reg :offset nl3-offset :target r - :from (:argument 1) :to (:result 1)) r-pass) - (:results (q :scs (any-reg)) - (r :scs (any-reg))) - (:result-types tagged-num tagged-num) - (:vop-var vop) - (:save-p :compute-only) - (:generator 30 - (let ((zero (generate-error-code vop 'division-by-zero-error x y))) - (inst bc := nil y zero-tn zero)) - (move x x-pass) - (move y y-pass) - (let ((fixup (make-fixup 'truncate :assembly-routine))) - (inst ldil fixup q-pass) - (inst ble fixup lisp-heap-space q-pass :nullify t)) - (inst nop) - (inst sll q-pass n-fixnum-tag-bits q) - ;(move q-pass q) - (move r-pass r))) - -#+(or) ;; This contains two largely-inexplicable hacks, and there's no - ;; equivalent VOP for either Alpha or ARM. Why is this even - ;; here? -- AB, 2015-11-19 -(define-vop (fast-truncate/unsigned fast-unsigned-binop) - (:translate truncate) - (:args (x :scs (unsigned-reg) :target x-pass) - (y :scs (unsigned-reg) :target y-pass)) - (:temporary (:sc unsigned-reg :offset nl0-offset - :from (:argument 0) :to (:result 0)) x-pass) - (:temporary (:sc unsigned-reg :offset nl1-offset - :from (:argument 1) :to (:result 0)) y-pass) - (:temporary (:sc unsigned-reg :offset nl2-offset :target q - :from (:argument 1) :to (:result 0)) q-pass) - (:temporary (:sc unsigned-reg :offset nl3-offset :target r - :from (:argument 1) :to (:result 1)) r-pass) - (:results (q :scs (unsigned-reg)) - (r :scs (unsigned-reg))) - (:result-types unsigned-num unsigned-num) - (:vop-var vop) - (:save-p :compute-only) - (:generator 35 - (let ((zero (generate-error-code vop 'division-by-zero-error x y))) - (inst bc := nil y zero-tn zero)) - (move x x-pass) - (move y y-pass) - ;; really dirty trick to avoid the bug truncate/unsigned vop - ;; followed by move-from/word->fixnum where the result from - ;; the truncate is 0xe39516a7 and move-from-word will treat - ;; the unsigned high number as an negative number. - ;; instead we clear the high bit in the input to truncate. - (inst li #x1fffffff q) - (inst comb :<> q y skip :nullify t) - (inst addi -1 zero-tn q) - (inst srl q 1 q) ; this should result in #7fffffff - (inst and x-pass q x-pass) - (inst and y-pass q y-pass) - SKIP - ;; fix bug#2 (truncate #xe39516a7 #x3) => #0xf687078d,#x0 - (inst li #x7fffffff q) - (inst and x-pass q x-pass) - (let ((fixup (make-fixup 'truncate :assembly-routine))) - (inst ldil fixup q-pass) - (inst ble fixup lisp-heap-space q-pass :nullify t)) - (inst nop) - (move q-pass q) - (move r-pass r))) - -(define-vop (fast-truncate/signed fast-signed-binop) - (:translate truncate) - (:args (x :scs (signed-reg) :target x-pass) - (y :scs (signed-reg) :target y-pass)) - (:temporary (:sc signed-reg :offset nl0-offset - :from (:argument 0) :to (:result 0)) x-pass) - (:temporary (:sc signed-reg :offset nl1-offset - :from (:argument 1) :to (:result 0)) y-pass) - (:temporary (:sc signed-reg :offset nl2-offset :target q - :from (:argument 1) :to (:result 0)) q-pass) - (:temporary (:sc signed-reg :offset nl3-offset :target r - :from (:argument 1) :to (:result 1)) r-pass) - (:results (q :scs (signed-reg)) - (r :scs (signed-reg))) - (:result-types signed-num signed-num) - (:vop-var vop) - (:save-p :compute-only) - (:generator 35 - (let ((zero (generate-error-code vop 'division-by-zero-error x y))) - (inst bc := nil y zero-tn zero)) - (move x x-pass) - (move y y-pass) - (let ((fixup (make-fixup 'truncate :assembly-routine))) - (inst ldil fixup q-pass) - (inst ble fixup lisp-heap-space q-pass :nullify t)) - (inst nop) - (move q-pass q) - (move r-pass r))) - - -;;;; Binary conditional VOPs: - -(define-vop (fast-conditional) - (:conditional) - (:info target not-p) - (:policy :fast-safe)) - -(define-vop (fast-conditional/fixnum fast-conditional) - (:args (x :scs (any-reg)) - (y :scs (any-reg))) - (:arg-types tagged-num tagged-num) - (:note "inline fixnum comparison")) - -(define-vop (fast-conditional-c/fixnum fast-conditional/fixnum) - (:args (x :scs (any-reg))) - (:arg-types tagged-num (:constant (signed-byte 9))) - (:info target not-p y)) - -(define-vop (fast-conditional/signed fast-conditional) - (:args (x :scs (signed-reg)) - (y :scs (signed-reg))) - (:arg-types signed-num signed-num) - (:note "inline (signed-byte 32) comparison")) - -(define-vop (fast-conditional-c/signed fast-conditional/signed) - (:args (x :scs (signed-reg))) - (:arg-types signed-num (:constant (signed-byte 11))) - (:info target not-p y)) - -(define-vop (fast-conditional/unsigned fast-conditional) - (:args (x :scs (unsigned-reg)) - (y :scs (unsigned-reg))) - (:arg-types unsigned-num unsigned-num) - (:note "inline (unsigned-byte 32) comparison")) - -(define-vop (fast-conditional-c/unsigned fast-conditional/unsigned) - (:args (x :scs (unsigned-reg))) - (:arg-types unsigned-num (:constant (signed-byte 11))) - (:info target not-p y)) - - -(defmacro define-conditional-vop (translate signed-cond unsigned-cond) - `(progn - ,@(mapcar #'(lambda (suffix cost signed imm) - (unless (and (member suffix '(/fixnum -c/fixnum)) - (eq translate 'eql)) - `(define-vop (,(intern (format nil "~:@(FAST-IF-~A~A~)" - translate suffix)) - ,(intern - (format nil "~:@(FAST-CONDITIONAL~A~)" - suffix))) - (:translate ,translate) - (:generator ,cost - (inst ,(if imm 'bci 'bc) - ,(if signed signed-cond unsigned-cond) - not-p - ,(if (eq suffix '-c/fixnum) - '(fixnumize y) - 'y) - x - target))))) - '(/fixnum -c/fixnum /signed -c/signed /unsigned -c/unsigned) - '(3 2 5 4 5 4) - '(t t t t nil nil) - '(nil t nil t nil t)))) - -;; We switch < and > because the immediate has to come first. - -(define-conditional-vop < :> :>>) -(define-conditional-vop > :< :<<) - -;;; EQL/FIXNUM is funny because the first arg can be of any type, not just a -;;; known fixnum. -;;; -(define-conditional-vop eql := :=) - -;;; These versions specify a fixnum restriction on their first arg. We have -;;; also generic-eql/fixnum VOPs which are the same, but have no restriction on -;;; the first arg and a higher cost. The reason for doing this is to prevent -;;; fixnum specific operations from being used on word integers, spuriously -;;; consing the argument. -;;; -(define-vop (fast-eql/fixnum fast-conditional) - (:args (x :scs (any-reg)) - (y :scs (any-reg))) - (:arg-types tagged-num tagged-num) - (:note "inline fixnum comparison") - (:translate eql) - (:generator 3 - (inst bc := not-p x y target))) -;;; -(define-vop (generic-eql/fixnum fast-eql/fixnum) - (:args (x :scs (any-reg descriptor-reg)) - (y :scs (any-reg))) - (:arg-types * tagged-num) - (:variant-cost 7)) - -(define-vop (fast-eql-c/fixnum fast-conditional/fixnum) - (:args (x :scs (any-reg))) - (:arg-types tagged-num (:constant (signed-byte 9))) - (:info target not-p y) - (:translate eql) - (:generator 2 - (inst bci := not-p (fixnumize y) x target))) -;;; -(define-vop (generic-eql-c/fixnum fast-eql-c/fixnum) - (:args (x :scs (any-reg descriptor-reg))) - (:arg-types * (:constant (signed-byte 9))) - (:variant-cost 6)) - - -;;;; modular functions -(define-modular-fun +-mod32 (x y) + :untagged nil 32) -(define-vop (fast-+-mod32/unsigned=>unsigned fast-+/unsigned=>unsigned) - (:translate +-mod32)) -(define-vop (fast-+-mod32-c/unsigned=>unsigned fast-+-c/unsigned=>unsigned) - (:translate +-mod32)) -(define-modular-fun --mod32 (x y) - :untagged nil 32) -(define-vop (fast---mod32/unsigned=>unsigned fast--/unsigned=>unsigned) - (:translate --mod32)) -(define-vop (fast---mod32-c/unsigned=>unsigned fast---c/unsigned=>unsigned) - (:translate --mod32)) - -(define-vop (fast-ash-left-mod32-c/unsigned=>unsigned - fast-ash-c/unsigned=>unsigned) - (:translate ash-left-mod32)) - -(define-vop (fast-ash-left-mod32/unsigned=>unsigned - fast-ash-left/unsigned=>unsigned)) -(deftransform ash-left-mod32 ((integer count) - ((unsigned-byte 32) (unsigned-byte 5))) - (when (sb-c::constant-lvar-p count) - (sb-c::give-up-ir1-transform)) - '(%primitive fast-ash-left-mod32/unsigned=>unsigned integer count)) - -;;; logical operations -(define-modular-fun lognot-mod32 (x) lognot :untagged nil 32) -(define-vop (lognot-mod32/unsigned=>unsigned) - (:translate lognot-mod32) - (:args (x :scs (unsigned-reg))) - (:arg-types unsigned-num) - (:results (res :scs (unsigned-reg))) - (:result-types unsigned-num) - (:policy :fast-safe) - (:generator 1 - (inst uaddcm zero-tn x res))) - -(define-modular-fun lognor-mod32 (x y) lognor :untagged nil 32) -(define-vop (fast-lognor-mod32/unsigned=>unsigned - fast-lognor/unsigned=>unsigned) - (:translate lognor-mod32)) - -(define-source-transform logeqv (&rest args) - (if (oddp (length args)) - `(logxor ,@args) - `(lognot (logxor ,@args)))) -(define-source-transform logorc1 (x y) - `(logior (lognot ,x) ,y)) -(define-source-transform logorc2 (x y) - `(logior ,x (lognot ,y))) -(define-source-transform lognand (x y) - `(lognot (logand ,x ,y))) -(define-source-transform lognor (x y) - `(lognot (logior ,x ,y))) - -(define-vop (shift-towards-someplace) - (:policy :fast-safe) - (:args (num :scs (unsigned-reg)) - (amount :scs (signed-reg))) - (:arg-types unsigned-num tagged-num) - (:results (r :scs (unsigned-reg))) - (:result-types unsigned-num)) - -(define-vop (shift-towards-start shift-towards-someplace) - (:translate shift-towards-start) - (:temporary (:scs (unsigned-reg) :to (:result 0)) temp) - (:note "SHIFT-TOWARDS-START") - (:generator 1 - (inst subi 31 amount temp) - (inst mtctl temp :sar) - (inst zdep num :variable 32 r))) - -(define-vop (shift-towards-end shift-towards-someplace) - (:translate shift-towards-end) - (:note "SHIFT-TOWARDS-END") - (:generator 1 - (inst mtctl amount :sar) - (inst shd zero-tn num :variable r))) - - - -;;;; Bignum stuff. - -(define-vop (bignum-length get-header-data) - (:translate sb-bignum:%bignum-length) - (:policy :fast-safe)) - -(define-vop (bignum-set-length set-header-data) - (:translate sb-bignum:%bignum-set-length) - (:policy :fast-safe)) - -(define-full-reffer bignum-ref * bignum-digits-offset other-pointer-lowtag - (unsigned-reg) unsigned-num sb-bignum:%bignum-ref) - -(define-full-setter bignum-set * bignum-digits-offset other-pointer-lowtag - (unsigned-reg) unsigned-num sb-bignum:%bignum-set) - -(define-vop (digit-0-or-plus) - (:translate sb-bignum:%digit-0-or-plusp) - (:policy :fast-safe) - (:args (digit :scs (unsigned-reg))) - (:arg-types unsigned-num) - (:conditional) - (:info target not-p) - (:generator 2 - (inst bc :>= not-p digit zero-tn target))) - -(define-vop (add-w/carry) - (:translate sb-bignum:%add-with-carry) - (:policy :fast-safe) - (:args (a :scs (unsigned-reg)) - (b :scs (unsigned-reg)) - (c :scs (any-reg))) - (:arg-types unsigned-num unsigned-num positive-fixnum) - (:results (result :scs (unsigned-reg)) - (carry :scs (unsigned-reg))) - (:result-types unsigned-num positive-fixnum) - (:generator 3 - (inst addi -1 c zero-tn) - (inst addc a b result) - (inst addc zero-tn zero-tn carry))) - -(define-vop (sub-w/borrow) - (:translate sb-bignum:%subtract-with-borrow) - (:policy :fast-safe) - (:args (a :scs (unsigned-reg)) - (b :scs (unsigned-reg)) - (c :scs (unsigned-reg))) - (:arg-types unsigned-num unsigned-num positive-fixnum) - (:results (result :scs (unsigned-reg)) - (borrow :scs (unsigned-reg))) - (:result-types unsigned-num positive-fixnum) - (:generator 4 - (inst addi -1 c zero-tn) - (inst subb a b result) - (inst addc zero-tn zero-tn borrow))) - -(define-vop (bignum-mult) - (:translate sb-bignum:%multiply) - (:policy :fast-safe) - (:args (x-arg :scs (unsigned-reg) :target x) - (y-arg :scs (unsigned-reg) :target y)) - (:arg-types unsigned-num unsigned-num) - (:temporary (:scs (signed-reg) :from (:argument 0)) x) - (:temporary (:scs (signed-reg) :from (:argument 1)) y) - (:temporary (:scs (signed-reg)) tmp) - (:results (hi :scs (unsigned-reg)) - (lo :scs (unsigned-reg))) - (:result-types unsigned-num unsigned-num) - (:generator 3 - ;; Make sure X is less then Y. - (inst comclr x-arg y-arg tmp :<<) - (inst xor x-arg y-arg tmp) - (inst xor x-arg tmp x) - (inst xor y-arg tmp y) - - ;; Blow out of here if the result is zero. - (inst li 0 hi) - (inst comb := x zero-tn done) - (inst li 0 lo) - (inst li 0 tmp) - - LOOP - (inst comb :ev x zero-tn next-bit) - (inst srl x 1 x) - (inst add lo y lo) - (inst addc hi tmp hi) - NEXT-BIT - (inst add y y y) - (inst comb :<> x zero-tn loop) - (inst addc tmp tmp tmp) - - DONE)) - -(define-source-transform sb-bignum:%multiply-and-add (x y carry &optional (extra 0)) - #+nil ;; This would be greate if it worked, but it doesn't. - (if (eql extra 0) - `(multiple-value-call #'sb-bignum:%dual-word-add - (sb-bignum:%multiply ,x ,y) - (values ,carry)) - `(multiple-value-call #'sb-bignum:%dual-word-add - (multiple-value-call #'sb-bignum:%dual-word-add - (sb-bignum:%multiply ,x ,y) - (values ,carry)) - (values ,extra))) - (with-unique-names (hi lo) - (if (eql extra 0) - `(multiple-value-bind (,hi ,lo) (sb-bignum:%multiply ,x ,y) - (sb-bignum::%dual-word-add ,hi ,lo ,carry)) - `(multiple-value-bind (,hi ,lo) (sb-bignum:%multiply ,x ,y) - (multiple-value-bind - (,hi ,lo) - (sb-bignum::%dual-word-add ,hi ,lo ,carry) - (sb-bignum::%dual-word-add ,hi ,lo ,extra)))))) - -(defknown sb-bignum::%dual-word-add - (sb-bignum:bignum-element-type sb-bignum:bignum-element-type sb-bignum:bignum-element-type) - (values sb-bignum:bignum-element-type sb-bignum:bignum-element-type) - (flushable movable)) - -(define-vop (dual-word-add) - (:policy :fast-safe) - (:translate sb-bignum::%dual-word-add) - (:args (hi :scs (unsigned-reg) :to (:result 1)) - (lo :scs (unsigned-reg)) - (extra :scs (unsigned-reg))) - (:arg-types unsigned-num unsigned-num unsigned-num) - (:results (hi-res :scs (unsigned-reg) :from (:result 1)) - (lo-res :scs (unsigned-reg) :from (:result 0))) - (:result-types unsigned-num unsigned-num) - (:generator 3 - (inst add lo extra lo-res) - (inst addc hi zero-tn hi-res))) - -(define-vop (bignum-lognot lognot-mod32/unsigned=>unsigned) - (:translate sb-bignum:%lognot)) - -(define-vop (fixnum-to-digit) - (:translate sb-bignum:%fixnum-to-digit) - (:policy :fast-safe) - (:args (fixnum :scs (any-reg))) - (:arg-types tagged-num) - (:results (digit :scs (unsigned-reg))) - (:result-types unsigned-num) - (:generator 1 - (inst sra fixnum n-fixnum-tag-bits digit))) - -(define-vop (bignum-floor) - (:translate sb-bignum:%bigfloor) - (:policy :fast-safe) - (:args (hi :scs (unsigned-reg) :to (:argument 1)) - (lo :scs (unsigned-reg) :to (:argument 0)) - (divisor :scs (unsigned-reg))) - (:arg-types unsigned-num unsigned-num unsigned-num) - (:temporary (:scs (unsigned-reg) :to (:argument 1)) temp) - (:results (quo :scs (unsigned-reg) :from (:argument 0)) - (rem :scs (unsigned-reg) :from (:argument 1))) - (:result-types unsigned-num unsigned-num) - (:generator 65 - (inst sub zero-tn divisor temp) - (inst ds zero-tn temp zero-tn) - (inst add lo lo quo) - (inst ds hi divisor rem) - (inst addc quo quo quo) - (dotimes (i 31) - (inst ds rem divisor rem) - (inst addc quo quo quo)) - (inst comclr rem zero-tn zero-tn :>=) - (inst add divisor rem rem))) - -(define-vop (signify-digit) - (:translate sb-bignum:%fixnum-digit-with-correct-sign) - (:policy :fast-safe) - (:args (digit :scs (unsigned-reg) :target res)) - (:arg-types unsigned-num) - (:results (res :scs (any-reg signed-reg))) - (:result-types signed-num) - (:generator 1 - (sc-case res - (any-reg - (inst sll digit n-fixnum-tag-bits res)) - (signed-reg - (move digit res))))) - -(define-vop (digit-lshr) - (:translate sb-bignum:%digit-logical-shift-right) - (:policy :fast-safe) - (:args (digit :scs (unsigned-reg)) - (count :scs (unsigned-reg))) - (:arg-types unsigned-num positive-fixnum) - (:results (result :scs (unsigned-reg))) - (:result-types unsigned-num) - (:generator 2 - (inst mtctl count :sar) - (inst shd zero-tn digit :variable result))) - -(define-vop (digit-ashr digit-lshr) - (:translate sb-bignum:%ashr) - (:temporary (:scs (unsigned-reg) :to (:result 0)) temp) - (:generator 1 - (inst extrs digit 0 1 temp) - (inst mtctl count :sar) - (inst shd temp digit :variable result))) - -(define-vop (digit-ashl digit-ashr) - (:translate sb-bignum:%ashl) - (:generator 1 - (inst subi 31 count temp) - (inst mtctl temp :sar) - (inst zdep digit :variable 32 result))) diff --git a/src/compiler/hppa/array.lisp b/src/compiler/hppa/array.lisp deleted file mode 100644 index ee5cc90d80..0000000000 --- a/src/compiler/hppa/array.lisp +++ /dev/null @@ -1,382 +0,0 @@ -;;;; the HPPA definitions for array operations - -;;;; This software is part of the SBCL system. See the README file for -;;;; more information. -;;;; -;;;; This software is derived from the CMU CL system, which was -;;;; written at Carnegie Mellon University and released into the -;;;; public domain. The software is in the public domain and is -;;;; provided with absolutely no warranty. See the COPYING and CREDITS -;;;; files for more information. - -(in-package "SB-VM") - -;;;; Allocator for the array header. -(define-vop (make-array-header) - (:translate make-array-header) - (:policy :fast-safe) - (:args (type :scs (any-reg)) - (rank :scs (any-reg))) - (:arg-types positive-fixnum positive-fixnum) - (:temporary (:scs (any-reg)) bytes) - (:temporary (:scs (non-descriptor-reg)) header) - (:results (result :scs (descriptor-reg))) - (:generator 13 - ;; Note: Cant use addi, the immediate is too large - (inst li (+ (* (1+ array-dimensions-offset) n-word-bytes) - lowtag-mask) header) - (inst add header rank bytes) - (inst li (lognot lowtag-mask) header) - (inst and bytes header bytes) - (inst addi (fixnumize (1- array-dimensions-offset)) rank header) - (inst sll header n-widetag-bits header) - (inst or header type header) - (inst srl header n-fixnum-tag-bits header) - (pseudo-atomic () - (set-lowtag other-pointer-lowtag alloc-tn result) - (storew header result 0 other-pointer-lowtag) - (inst add bytes alloc-tn alloc-tn)))) - - -;;;; Additional accessors and setters for the array header. -(define-full-reffer %array-dimension * - array-dimensions-offset other-pointer-lowtag - (any-reg) positive-fixnum %array-dimension) - -(define-full-setter %set-array-dimension * - array-dimensions-offset other-pointer-lowtag - (any-reg) positive-fixnum %set-array-dimension) - -(define-vop (array-rank-vop) - (:translate %array-rank) - (:policy :fast-safe) - (:args (x :scs (descriptor-reg))) - (:results (res :scs (any-reg descriptor-reg))) - (:generator 6 - (loadw res x 0 other-pointer-lowtag) - (inst sra res n-widetag-bits res) - (inst addi (- (1- array-dimensions-offset)) res res) - (inst sll res n-fixnum-tag-bits res))) - -;;;; Bounds checking routine. -(define-vop (check-bound) - (:translate %check-bound) - (:policy :fast-safe) - (:args (array :scs (descriptor-reg)) - (bound :scs (any-reg descriptor-reg)) - (index :scs (any-reg descriptor-reg))) - (:vop-var vop) - (:save-p :compute-only) - (:generator 5 - (let ((error (generate-error-code vop 'invalid-array-index-error - array bound index))) - (%test-fixnum index nil error t) - (inst bc :>>= nil index bound error)))) - - -;;;; Accessors/Setters - -;;; Variants built on top of word-index-ref, etc. I.e. those vectors whos -;;; elements are represented in integer registers and are built out of -;;; 8, 16, or 32 bit elements. -(macrolet ((def-full-data-vector-frobs (type element-type &rest scs) - `(progn - (define-full-reffer ,(symbolicate "DATA-VECTOR-REF/" type) ,type - vector-data-offset other-pointer-lowtag - ,(remove-if (lambda (x) (member x '(null zero))) scs) - ,element-type - data-vector-ref) - (define-full-setter ,(symbolicate "DATA-VECTOR-SET/" type) ,type - vector-data-offset other-pointer-lowtag ,scs ,element-type - data-vector-set))) - - (def-partial-data-vector-frobs - (type element-type size signed &rest scs) - `(progn - (define-partial-reffer ,(symbolicate "DATA-VECTOR-REF/" type) ,type - ,size ,signed vector-data-offset other-pointer-lowtag ,scs - ,element-type data-vector-ref) - (define-partial-setter ,(symbolicate "DATA-VECTOR-SET/" type) ,type - ,size vector-data-offset other-pointer-lowtag ,scs - ,element-type data-vector-set)))) - - (def-full-data-vector-frobs simple-vector * - descriptor-reg any-reg null zero) - - (def-partial-data-vector-frobs simple-base-string character - :byte nil character-reg) - #+sb-unicode - (def-full-data-vector-frobs simple-character-string character character-reg) - - (def-partial-data-vector-frobs simple-array-unsigned-byte-7 positive-fixnum - :byte nil unsigned-reg signed-reg) - (def-partial-data-vector-frobs simple-array-unsigned-byte-8 positive-fixnum - :byte nil unsigned-reg signed-reg) - - (def-partial-data-vector-frobs simple-array-unsigned-byte-15 positive-fixnum - :short nil unsigned-reg signed-reg) - (def-partial-data-vector-frobs simple-array-unsigned-byte-16 positive-fixnum - :short nil unsigned-reg signed-reg) - - (def-full-data-vector-frobs simple-array-unsigned-byte-31 unsigned-num - unsigned-reg) - (def-full-data-vector-frobs simple-array-unsigned-byte-32 unsigned-num - unsigned-reg) - - (def-partial-data-vector-frobs simple-array-signed-byte-8 tagged-num - :byte t signed-reg) - - (def-partial-data-vector-frobs simple-array-signed-byte-16 tagged-num - :short t signed-reg) - - (def-full-data-vector-frobs simple-array-unsigned-fixnum positive-fixnum - any-reg) - (def-full-data-vector-frobs simple-array-fixnum tagged-num - any-reg) - - (def-full-data-vector-frobs simple-array-signed-byte-32 signed-num - signed-reg)) - -;;; Integer vectors whose elements are smaller than a byte. I.e. bit, 2-bit, -;;; and 4-bit vectors. -(macrolet ((def-small-data-vector-frobs (type bits) - (let* ((elements-per-word (floor n-word-bits bits)) - (bit-shift (1- (integer-length elements-per-word)))) - `(progn - (define-vop (,(symbolicate 'data-vector-ref/ type)) - (:translate data-vector-ref) - (:note "inline array access") - (:policy :fast-safe) - (:args (object :scs (descriptor-reg)) - (index :scs (unsigned-reg))) - (:arg-types ,type positive-fixnum) - (:results (result :scs (any-reg))) - (:result-types positive-fixnum) - (:temporary (:scs (interior-reg)) lip) - (:temporary (:scs (non-descriptor-reg) :to (:result 0)) temp) - (:generator 20 - (inst srl index ,bit-shift temp) - (inst sh2add temp object lip) - (inst zdep index ,(- 32 (integer-length bits)) ,bit-shift temp) - ,@(unless (= bits 1) - `((inst addi ,(1- bits) temp temp))) - (inst mtctl temp :sar) - (loadw result lip vector-data-offset other-pointer-lowtag) - (inst extru result :variable ,bits result) - (inst sll result n-fixnum-tag-bits result))) - (define-vop (,(symbolicate 'data-vector-ref-c/ type)) - (:translate data-vector-ref) - (:policy :fast-safe) - (:args (object :scs (descriptor-reg))) - (:arg-types ,type (:constant index)) - (:info index) - (:results (result :scs (unsigned-reg))) - (:result-types positive-fixnum) - (:temporary (:scs (non-descriptor-reg) :to (:result 0)) temp) - (:generator 15 - (multiple-value-bind (word extra) (floor index ,elements-per-word) - (let ((offset (- (* (+ word vector-data-offset) n-word-bytes) - other-pointer-lowtag))) - (cond ((typep offset '(signed-byte 14)) - (inst ldw offset object result)) - (t - (inst li offset temp) - (inst ldwx object temp result)))) - (inst extru result (+ (* extra ,bits) ,(1- bits)) ,bits result)))) - (define-vop (,(symbolicate 'data-vector-set/ type)) - (:note "inline array store") - (:translate data-vector-set) - (:policy :fast-safe) - (:args (object :scs (descriptor-reg)) - (index :scs (unsigned-reg)) - (value :scs (unsigned-reg zero immediate) :target result)) - (:arg-types ,type positive-fixnum positive-fixnum) - (:results (result :scs (unsigned-reg))) - (:result-types positive-fixnum) - (:temporary (:scs (non-descriptor-reg) :to (:result 0)) temp) - (:temporary (:scs (non-descriptor-reg)) old) - (:temporary (:scs (interior-reg)) lip) - (:generator 25 - (inst srl index ,bit-shift temp) - (inst sh2add temp object lip) - (inst zdep index ,(- 32 (integer-length bits)) ,bit-shift temp) - ,@(unless (= bits 1) - `((inst addi ,(1- bits) temp temp))) - (inst mtctl temp :sar) - (loadw old lip vector-data-offset other-pointer-lowtag) - (inst dep (sc-case value (immediate (tn-value value)) (t value)) - :variable ,bits old) - (storew old lip vector-data-offset other-pointer-lowtag) - (sc-case value - (immediate - (inst li (tn-value value) result)) - (t - (move value result))))) - (define-vop (,(symbolicate 'data-vector-set-c/ type)) - (:translate data-vector-set) - (:policy :fast-safe) - (:args (object :scs (descriptor-reg)) - (value :scs (unsigned-reg zero immediate) :target result)) - (:arg-types ,type - (:constant index) - positive-fixnum) - (:info index) - (:results (result :scs (unsigned-reg))) - (:result-types positive-fixnum) - (:temporary (:scs (non-descriptor-reg)) old) - (:temporary (:scs (interior-reg)) lip) - (:generator 20 - (multiple-value-bind (word extra) (floor index ,elements-per-word) - (let ((offset (- (* (+ word vector-data-offset) n-word-bytes) - other-pointer-lowtag))) - (cond ((typep offset '(signed-byte 14)) - (inst ldw offset object old)) - (t - (inst li offset lip) - (inst add object lip lip) - (inst ldw 0 lip old))) - (inst dep (sc-case value - (immediate (tn-value value)) - (t value)) - (+ (* extra ,bits) ,(1- bits)) - ,bits - old) - (if (typep offset '(signed-byte 14)) - (inst stw old offset object) - (inst stw old (ldb (byte 11 0) offset) lip))) - (sc-case value - (immediate - (inst li (tn-value value) result)) - (t - (move value result)))))))))) - (def-small-data-vector-frobs simple-bit-vector 1) - (def-small-data-vector-frobs simple-array-unsigned-byte-2 2) - (def-small-data-vector-frobs simple-array-unsigned-byte-4 4)) - -;;; And the float variants. -(macrolet - ((data-vector ((type set cost) &body body) - (let* ((typen (case type (single 'single-float) - (double 'double-float) - (t type))) - (name (symbolicate "DATA-VECTOR-" (if set "SET" "REF") - "/SIMPLE-ARRAY-" typen)) - (reg-type (symbolicate type "-REG"))) - `(define-vop (,name) - (:translate ,(symbolicate "DATA-VECTOR-" (if set "SET" "REF"))) - (:note ,(concatenate 'string "inline array " - (if set "store" "access"))) - (:policy :fast-safe) - (:args (object :scs (descriptor-reg) :to (:argument 1)) - (index :scs (any-reg) :to (:argument 0) :target offset) - ,@(if set `((value :scs (,reg-type) :target result)))) - (:arg-types ,(symbolicate "SIMPLE-ARRAY-" typen) positive-fixnum - ,@(if set `(,typen))) - (:results (,(if set 'result 'value) :scs (,reg-type))) - (:temporary (:scs (non-descriptor-reg) :from (:argument 0)) offset) - (:result-types ,typen) - (:generator ,cost - ,@body))))) - (data-vector (single nil 5) - (inst addi (- (* vector-data-offset n-word-bytes) - other-pointer-lowtag) - index offset) - (inst fldx offset object value)) - (data-vector (single t 5) - (inst addi (- (* vector-data-offset n-word-bytes) other-pointer-lowtag) - index offset) - (inst fstx value offset object) - (unless (location= result value) - (inst funop :copy value result))) - (data-vector (double nil 7) - (inst sll index 1 offset) - (inst addi (- (* vector-data-offset n-word-bytes) other-pointer-lowtag) - offset offset) - (inst fldx offset object value)) - (data-vector (double t 7) - (inst sll index 1 offset) - (inst addi (- (* vector-data-offset n-word-bytes) other-pointer-lowtag) - offset offset) - (inst fstx value offset object) - (unless (location= result value) - (inst funop :copy value result)))) - -(macrolet - ((data-vector ((type set cost) &body body) - (let* ((typen (case type (complex-single 'complex-single-float) - (complex-double 'complex-double-float) - (t type))) - (name (symbolicate "DATA-VECTOR-" (if set "SET" "REF") - "/SIMPLE-ARRAY-" typen)) - (reg-type (symbolicate type "-REG"))) - `(define-vop (,name) - (:translate ,(symbolicate "DATA-VECTOR-" (if set "SET" "REF"))) - (:note ,(concatenate 'string "inline array " - (if set "store" "access"))) - (:policy :fast-safe) - (:args (object :scs (descriptor-reg) :to :result) - (index :scs (any-reg)) - ,@(if set `((value :scs (,reg-type) :target result)))) - (:arg-types ,(symbolicate "SIMPLE-ARRAY-" typen) positive-fixnum - ,@(if set `(,typen))) - (:results (,(if set 'result 'value) :scs (,reg-type))) - (:temporary (:scs (non-descriptor-reg) :from (:argument 1)) offset) - (:result-types ,typen) - (:generator ,cost - ,@body))))) - (data-vector (complex-single nil 5) - (inst sll index 1 offset) - (inst addi (- (* vector-data-offset n-word-bytes) other-pointer-lowtag) - offset offset) - (let ((real-tn (complex-single-reg-real-tn value))) - (inst fldx offset object real-tn)) - (let ((imag-tn (complex-single-reg-imag-tn value))) - (inst addi n-word-bytes offset offset) - (inst fldx offset object imag-tn))) - (data-vector (complex-single t 5) - (inst sll index 1 offset) - (inst addi (- (* vector-data-offset n-word-bytes) other-pointer-lowtag) - offset offset) - (let ((value-real (complex-single-reg-real-tn value)) - (result-real (complex-single-reg-real-tn result))) - (inst fstx value-real offset object) - (unless (location= result-real value-real) - (inst funop :copy value-real result-real))) - (let ((value-imag (complex-single-reg-imag-tn value)) - (result-imag (complex-single-reg-imag-tn result))) - (inst addi n-word-bytes offset offset) - (inst fstx value-imag offset object) - (unless (location= result-imag value-imag) - (inst funop :copy value-imag result-imag)))) - (data-vector (complex-double nil 7) - (inst sll index 2 offset) - (inst addi (- (* vector-data-offset n-word-bytes) other-pointer-lowtag) - offset offset) - (let ((real-tn (complex-double-reg-real-tn value))) - (inst fldx offset object real-tn)) - (let ((imag-tn (complex-double-reg-imag-tn value))) - (inst addi (* 2 n-word-bytes) offset offset) - (inst fldx offset object imag-tn))) - (data-vector (complex-double t 20) - (inst sll index 2 offset) - (inst addi (- (* vector-data-offset n-word-bytes) other-pointer-lowtag) - offset offset) - (let ((value-real (complex-double-reg-real-tn value)) - (result-real (complex-double-reg-real-tn result))) - (inst fstx value-real offset object) - (unless (location= result-real value-real) - (inst funop :copy value-real result-real))) - (let ((value-imag (complex-double-reg-imag-tn value)) - (result-imag (complex-double-reg-imag-tn result))) - (inst addi (* 2 n-word-bytes) offset offset) - (inst fstx value-imag offset object) - (unless (location= result-imag value-imag) - (inst funop :copy value-imag result-imag))))) - - -;;; These vops are useful for accessing the bits of a vector irrespective of -;;; what type of vector it is. -(define-full-reffer vector-raw-bits * vector-data-offset other-pointer-lowtag - (unsigned-reg) unsigned-num %vector-raw-bits) -(define-full-setter set-vector-raw-bits * vector-data-offset other-pointer-lowtag - (unsigned-reg) unsigned-num %set-vector-raw-bits) diff --git a/src/compiler/hppa/c-call.lisp b/src/compiler/hppa/c-call.lisp deleted file mode 100644 index 902a68966c..0000000000 --- a/src/compiler/hppa/c-call.lisp +++ /dev/null @@ -1,324 +0,0 @@ -;;;; VOPs and other machine-specific support routines for call-out to C - -;;;; This software is part of the SBCL system. See the README file for -;;;; more information. -;;;; -;;;; This software is derived from the CMU CL system, which was -;;;; written at Carnegie Mellon University and released into the -;;;; public domain. The software is in the public domain and is -;;;; provided with absolutely no warranty. See the COPYING and CREDITS -;;;; files for more information. - -(in-package "SB-VM") - -(defstruct arg-state - (stack-frame-size 0) - (float-args 0) - nargs) - -;;; beware that we deal alot here with register-offsets directly -;;; instead of their symbol-name in vm.lisp -;;; offset works differently depending on sc-type -(defun my-make-wired-tn (prim-type-name sc-name offset state) - (make-wired-tn (primitive-type-or-lose prim-type-name) - (sc-number-or-lose sc-name) - ;; try to utilize vm.lisp definitions of registers: - (ecase sc-name - ((any-reg sap-reg signed-reg unsigned-reg) - (ecase offset ; FIX: port to other arch ??? - ;(:nfp-offset offset) - (0 nl0-offset) ; On other arch we can - (1 nl1-offset) ; just add an offset to - (2 nl2-offset) ; beginning of args, but on - (3 nl3-offset) ; hppa c-args are spread. - (4 nl4-offset) ; These two are for - (5 nl5-offset))) ; c-return values - ((single-int-carg-reg double-int-carg-reg) - (ecase offset ; FIX: port to other arch ??? - (0 nl0-offset) - (1 nl1-offset) - (2 nl2-offset) - (3 nl3-offset))) - ((single-reg double-reg) ; only for return - (+ 4 offset)) - ;; A tn of stack type tells us that we have data on - ;; stack. This offset is current argument number so - ;; -1 points to the correct place to write that data - ((sap-stack signed-stack unsigned-stack) - (- (arg-state-nargs state) offset 8 1))))) - -(define-alien-type-method (integer :arg-tn) (type state) - (let ((stack-frame-size (arg-state-stack-frame-size state))) - (setf (arg-state-stack-frame-size state) (1+ stack-frame-size)) - (multiple-value-bind - (ptype reg-sc stack-sc) - (if (alien-integer-type-signed type) - (values 'signed-byte-32 'signed-reg 'signed-stack) - (values 'unsigned-byte-32 'unsigned-reg 'unsigned-stack)) - (if (< stack-frame-size 4) - (my-make-wired-tn ptype reg-sc stack-frame-size state) - (my-make-wired-tn ptype stack-sc stack-frame-size state))))) - -(define-alien-type-method (system-area-pointer :arg-tn) (type state) - (declare (ignore type)) - (let ((stack-frame-size (arg-state-stack-frame-size state))) - (setf (arg-state-stack-frame-size state) (1+ stack-frame-size)) - (if (< stack-frame-size 4) - (my-make-wired-tn 'system-area-pointer - 'sap-reg - stack-frame-size state) - (my-make-wired-tn 'system-area-pointer - 'sap-stack - stack-frame-size state)))) - -(define-alien-type-method (double-float :arg-tn) (type state) - (declare (ignore type)) - (let ((stack-frame-size (logandc2 (1+ (arg-state-stack-frame-size state)) 1)) - (float-args (arg-state-float-args state))) - (setf (arg-state-stack-frame-size state) (+ stack-frame-size 2)) - (setf (arg-state-float-args state) (+ 2 float-args)) - (cond ((>= stack-frame-size 4) - (my-make-wired-tn 'double-float - 'double-stack - stack-frame-size state)) - (t - (my-make-wired-tn 'double-float - 'double-reg - (1+ float-args) state))))) - -(define-alien-type-method (single-float :arg-tn) (type state) - (declare (ignore type)) - (let ((stack-frame-size (arg-state-stack-frame-size state)) - (float-args (arg-state-float-args state))) - (setf (arg-state-stack-frame-size state) (1+ stack-frame-size)) - (setf (arg-state-float-args state) (1+ float-args)) - (cond ((>= stack-frame-size 4) - (my-make-wired-tn 'single-float - 'single-stack - stack-frame-size state)) - (t - (my-make-wired-tn 'single-float - 'single-reg - float-args state))))) - -(defstruct result-state - (num-results 0)) - -(define-alien-type-method (integer :result-tn) (type state) - (let ((num-results (result-state-num-results state))) - (setf (result-state-num-results state) (1+ num-results)) - (multiple-value-bind (ptype reg-sc) - (if (alien-integer-type-signed type) - (values 'signed-byte-32 'signed-reg) - (values 'unsigned-byte-32 'unsigned-reg)) - (if (> num-results 1) (error "Too many result values from c-call.")) - (my-make-wired-tn ptype reg-sc (+ num-results 4) state)))) - -(define-alien-type-method (system-area-pointer :result-tn) (type state) - (declare (ignore type)) - (let ((num-results (result-state-num-results state))) - (setf (result-state-num-results state) (1+ num-results)) - (if (> num-results 1) (error "Too many result values from c-call.")) - (my-make-wired-tn 'system-area-pointer 'sap-reg (+ num-results 4) state))) - -(define-alien-type-method (double-float :result-tn) (type state) - (declare (ignore type)) - (let ((num-results (result-state-num-results state))) - (setf (result-state-num-results state) (1+ num-results)) - (my-make-wired-tn 'double-float 'double-reg (* num-results 2) state))) - -(define-alien-type-method (single-float :result-tn) (type state) - (declare (ignore type)) - (let ((num-results (result-state-num-results state))) - (setf (result-state-num-results state) (1+ num-results)) - (my-make-wired-tn 'single-float 'single-reg (* num-results 2) state))) - -(define-alien-type-method (values :result-tn) (type state) - (let ((values (alien-values-type-values type))) - (when (> (length values) 2) - (error "Too many result values from c-call.")) - (mapcar (lambda (type) - (invoke-alien-type-method :result-tn type state)) - values))) - -(defun make-call-out-tns (type) - (let ((arg-state (make-arg-state)) - (nargs 0)) - (dolist (arg-type (alien-fun-type-arg-types type)) - (cond - ((alien-double-float-type-p arg-type) - (incf nargs (logior (1+ nargs) 1))) - (t (incf nargs)))) - (setf (arg-state-nargs arg-state) (logandc2 (+ nargs 8 15) 15)) - (collect ((arg-tns)) - (dolist (arg-type (alien-fun-type-arg-types type)) - (arg-tns (invoke-alien-type-method :arg-tn arg-type arg-state))) - (values (make-normal-tn *fixnum-primitive-type*) - (* n-word-bytes (logandc2 (+ nargs 8 15) 15)) - (arg-tns) - (invoke-alien-type-method :result-tn - (alien-fun-type-result-type type) - (make-result-state)))))) - -(deftransform %alien-funcall ((function type &rest args)) - (aver (sb-c::constant-lvar-p type)) - (let* ((type (sb-c::lvar-value type)) - (env (make-null-lexenv)) - (arg-types (alien-fun-type-arg-types type)) - (result-type (alien-fun-type-result-type type))) - (aver (= (length arg-types) (length args))) - ;; We need to do something special for 64-bit integer arguments - ;; and results. - (if (or (some (lambda (type) - (and (alien-integer-type-p type) - (> (sb-alien::alien-integer-type-bits type) 32))) - arg-types) - (and (alien-integer-type-p result-type) - (> (sb-alien::alien-integer-type-bits result-type) 32))) - (collect ((new-args) (lambda-vars) (new-arg-types)) - (dolist (type arg-types) - (let ((arg (gensym))) - (lambda-vars arg) - (cond ((and (alien-integer-type-p type) - (> (sb-alien::alien-integer-type-bits type) 32)) - ;; 64-bit long long types are stored in - ;; consecutive locations, endian word order, - ;; aligned to 8 bytes. - (when (oddp (length (new-args))) - (new-args nil)) - (progn (new-args `(ash ,arg -32)) - (new-args `(logand ,arg #xffffffff)) - (if (oddp (length (new-arg-types))) - (new-arg-types (parse-alien-type '(unsigned 32) env))) - (if (alien-integer-type-signed type) - (new-arg-types (parse-alien-type '(signed 32) env)) - (new-arg-types (parse-alien-type '(unsigned 32) env))) - (new-arg-types (parse-alien-type '(unsigned 32) env)))) - (t - (new-args arg) - (new-arg-types type))))) - (cond ((and (alien-integer-type-p result-type) - (> (sb-alien::alien-integer-type-bits result-type) 32)) - (let ((new-result-type - (let ((sb-alien::*values-type-okay* t)) - (parse-alien-type - (if (alien-integer-type-signed result-type) - '(values (signed 32) (unsigned 32)) - '(values (unsigned 32) (unsigned 32))) - env)))) - `(lambda (function type ,@(lambda-vars)) - (declare (ignore type)) - (multiple-value-bind - (high low) - (%alien-funcall function - ',(make-alien-fun-type - :arg-types (new-arg-types) - :result-type new-result-type) - ,@(new-args)) - (logior low (ash high 32)))))) - (t - `(lambda (function type ,@(lambda-vars)) - (declare (ignore type)) - (%alien-funcall function - ',(make-alien-fun-type - :arg-types (new-arg-types) - :result-type result-type) - ,@(new-args)))))) - (sb-c::give-up-ir1-transform)))) - -(define-vop (foreign-symbol-sap) - (:translate foreign-symbol-sap) - (:policy :fast-safe) - (:args) - (:arg-types (:constant simple-string)) - (:info foreign-symbol) - (:results (res :scs (sap-reg))) - (:result-types system-area-pointer) - (:generator 2 - (inst li (make-fixup foreign-symbol :foreign) res))) - -#+linkage-table -(define-vop (foreign-symbol-dataref-sap) - (:translate foreign-symbol-dataref-sap) - (:policy :fast-safe) - (:args) - (:arg-types (:constant simple-string)) - (:info foreign-symbol) - (:results (res :scs (sap-reg))) - (:result-types system-area-pointer) - (:temporary (:scs (non-descriptor-reg)) addr) - (:generator 2 - (inst li (make-fixup foreign-symbol :foreign-dataref) addr) - (loadw res addr))) - -(define-vop (call-out) - (:args (function :scs (sap-reg) :target cfunc) - (args :more t)) - (:results (results :more t)) - (:ignore args results) - (:save-p t) - (:temporary (:sc any-reg :offset cfunc-offset - :from (:argument 0) :to (:result 0)) cfunc) - (:temporary (:sc control-stack :offset nfp-save-offset) nfp-save) - ;; Not sure if using nargs is safe ( have we saved it ). - ;; but we cant use any non-descriptor-reg because c-args nl-4 is of that type - (:temporary (:sc non-descriptor-reg :offset nargs-offset) temp) - (:vop-var vop) - (:generator 0 - (let ((cur-nfp (current-nfp-tn vop))) - (when cur-nfp - (store-stack-tn nfp-save cur-nfp)) - (let ((fixup (make-fixup "call_into_c" :foreign))) - (inst ldil fixup temp) - (inst ble fixup c-text-space temp) - (move function cfunc t)) - (when cur-nfp - (load-stack-tn cur-nfp nfp-save))))) - -(define-vop (alloc-number-stack-space) - (:info amount) - (:result-types system-area-pointer) - (:results (result :scs (sap-reg any-reg))) - (:temporary (:scs (unsigned-reg) :to (:result 0)) temp) - (:generator 0 - ;; Because stack grows to higher addresses, we have the result - ;; pointing to an lowerer address than nsp - (move nsp-tn result) - (unless (zerop amount) - ;; hp-ux stack grows towards larger addresses and stack must be - ;; allocated in blocks of 64 bytes - (let ((delta (+ 0 (logandc2 (+ amount 63) 63)))) ; was + 16 - (cond ((< delta (ash 1 10)) - (inst addi delta nsp-tn nsp-tn)) - (t - (inst li delta temp) - (inst add nsp-tn temp nsp-tn))))))) - -(define-vop (dealloc-number-stack-space) - (:info amount) - (:policy :fast-safe) - (:temporary (:scs (unsigned-reg) :to (:result 0)) temp) - (:generator 0 - (unless (zerop amount) - (let ((delta (+ 0 (logandc2 (+ amount 63) 63)))) ; was + 16 - (cond ((< delta (ash 1 10)) - (inst addi (- delta) nsp-tn nsp-tn)) - (t - (inst li (- delta) temp) - (inst sub nsp-tn temp nsp-tn))))))) - -#-sb-xc-host -(defun alien-callback-accessor-form (type sap offset) - (let ((parsed-type type)) - (if (alien-integer-type-p parsed-type) - (let ((bits (sb-alien::alien-integer-type-bits parsed-type))) - (let ((byte-offset - (cond ((< bits n-word-bits) - (- n-word-bytes - (ceiling bits n-byte-bits))) - (t 0)))) - `(deref (sap-alien (sap+ ,sap - ,(+ byte-offset offset)) - (* ,type))))) - `(deref (sap-alien (sap+ ,sap ,offset) (* ,type)))))) - diff --git a/src/compiler/hppa/call.lisp b/src/compiler/hppa/call.lisp deleted file mode 100644 index cc34f3e6b5..0000000000 --- a/src/compiler/hppa/call.lisp +++ /dev/null @@ -1,1226 +0,0 @@ -;;;; the VM definition of function call for HPPA - -;;;; This software is part of the SBCL system. See the README file for -;;;; more information. -;;;; -;;;; This software is derived from the CMU CL system, which was -;;;; written at Carnegie Mellon University and released into the -;;;; public domain. The software is in the public domain and is -;;;; provided with absolutely no warranty. See the COPYING and CREDITS -;;;; files for more information. - -(in-package "SB-VM") - -(defconstant arg-count-sc (make-sc+offset immediate-arg-scn nargs-offset)) -(defconstant closure-sc (make-sc+offset descriptor-reg-sc-number lexenv-offset)) - -;;; Make a passing location TN for a local call return PC. If standard is -;;; true, then use the standard (full call) location, otherwise use any legal -;;; location. Even in the non-standard case, this may be restricted by a -;;; desire to use a subroutine call instruction. -(defun make-return-pc-passing-location (standard) - (if standard - (make-wired-tn *backend-t-primitive-type* descriptor-reg-sc-number lra-offset) - (make-restricted-tn *backend-t-primitive-type* descriptor-reg-sc-number))) - -;;; This is similar to MAKE-RETURN-PC-PASSING-LOCATION, but makes a -;;; location to pass OLD-FP in. This is (obviously) wired in the -;;; standard convention, but is totally unrestricted in non-standard -;;; conventions, since we can always fetch it off of the stack using -;;; the arg pointer. -(defun make-old-fp-passing-location () - (make-wired-tn *fixnum-primitive-type* immediate-arg-scn ocfp-offset)) - -(defconstant old-fp-passing-offset - (make-sc+offset descriptor-reg-sc-number ocfp-offset)) - -;;; Make the TNs used to hold OLD-FP and RETURN-PC within the current -;;; function. We treat these specially so that the debugger can find -;;; them at a known location. -(defun make-old-fp-save-location (env) - (specify-save-tn - (physenv-debug-live-tn (make-normal-tn *fixnum-primitive-type*) env) - (make-wired-tn *fixnum-primitive-type* - control-stack-arg-scn - ocfp-save-offset))) - -(defun make-return-pc-save-location (env) - (let ((ptype *backend-t-primitive-type*)) - (specify-save-tn - (physenv-debug-live-tn (make-normal-tn ptype) env) - (make-wired-tn ptype control-stack-arg-scn lra-save-offset)))) - -;;; Make a TN for the standard argument count passing location. We only -;;; need to make the standard location, since a count is never passed when we -;;; are using non-standard conventions. -(defun make-arg-count-location () - (make-wired-tn *fixnum-primitive-type* immediate-arg-scn nargs-offset)) - -;;; bytes-needed-for-non-descriptor-stack-frame is the amount -;;; we grow or shrink the NSP/NFP stack. This stack is used -;;; by C-code so the convention (grow direction, grow size) -;;; is governed by the hpux+hppa ABI or linux+hppa ABI. -;;; Return the number of bytes needed for the current non-descriptor stack. -;;; We have to allocate multiples of 64 bytes -(defun bytes-needed-for-non-descriptor-stack-frame () - (logandc2 (+ (* (sb-allocated-size 'non-descriptor-stack) n-word-bytes) 63) - 63)) - -;;; Used for setting up the Old-FP in local call. -;;; -(define-vop (current-fp) - (:results (val :scs (any-reg))) - (:generator 1 - (move cfp-tn val))) - -;;; Used for computing the caller's NFP for use in known-values return. Only -;;; works assuming there is no variable size stuff on the nstack. -;;; -(define-vop (compute-old-nfp) - (:results (val :scs (any-reg))) - (:vop-var vop) - (:generator 1 - (let ((nfp (current-nfp-tn vop))) - (when nfp - (inst ldo (- (bytes-needed-for-non-descriptor-stack-frame)) - nfp val))))) - -;;; Accessing a slot from an earlier stack frame is definite hackery. -(define-vop (ancestor-frame-ref) - (:args (frame-pointer :scs (descriptor-reg)) - (variable-home-tn :load-if nil)) - (:results (value :scs (descriptor-reg any-reg))) - (:policy :fast-safe) - (:generator 4 - (aver (sc-is variable-home-tn control-stack)) - (loadw value frame-pointer (tn-offset variable-home-tn)))) -(define-vop (ancestor-frame-set) - (:args (frame-pointer :scs (descriptor-reg)) - (value :scs (descriptor-reg any-reg))) - (:results (variable-home-tn :load-if nil)) - (:policy :fast-safe) - (:generator 4 - (aver (sc-is variable-home-tn control-stack)) - (storew value frame-pointer (tn-offset variable-home-tn)))) - -(define-vop (xep-allocate-frame) - (:info start-lab) - ;; KLUDGE: Specify an explicit offset for TEMP because NARGS is a - ;; non-descriptor-reg, but is also live, yet the register allocator - ;; does not know that it is, and if TEMP collides NARGS and - ;; COMPUTE-CODE-FROM-LIP needs TEMP then we run into trouble very - ;; quickly. - (:temporary (:sc non-descriptor-reg :offset nl5-offset) temp) - (:generator 1 - ;; Make sure the function is aligned, and drop a label pointing to this - ;; function header. - (emit-alignment n-lowtag-bits) - (emit-label start-lab) - ;; Allocate function header. - (inst simple-fun-header-word) - (inst .skip (* (1- simple-fun-insts-offset) n-word-bytes)) - ;; The start of the actual code. - ;; Fix CODE, cause the function object was passed in. - (let ((entry-point (gen-label))) - (emit-label entry-point) - (inst compute-code-from-lip lip-tn entry-point temp code-tn) - ;; ### We should also save it on the stack so that the garbage - ;; collector won't forget about us if we call anyone else. - ))) - -(define-vop (xep-setup-sp) - (:vop-var vop) - (:generator 1 - (inst ldo (* n-word-bytes (sb-allocated-size 'control-stack)) - cfp-tn csp-tn) - (let ((nfp (current-nfp-tn vop))) - (when nfp - (move nsp-tn nfp) - (inst ldo (bytes-needed-for-non-descriptor-stack-frame) - nsp-tn nsp-tn))))) - -(define-vop (allocate-frame) - (:results (res :scs (any-reg)) - (nfp :scs (any-reg))) - (:info callee) - (:generator 2 - (move csp-tn res) - (inst ldo (* n-word-bytes (sb-allocated-size 'control-stack)) - csp-tn csp-tn) - (when (ir2-physenv-number-stack-p callee) - (move nsp-tn nfp) - (inst ldo (bytes-needed-for-non-descriptor-stack-frame) - nsp-tn nsp-tn)))) - -;;; Allocate a partial frame for passing stack arguments in a full call. Nargs -;;; is the number of arguments passed. If no stack arguments are passed, then -;;; we don't have to do anything. -;;; -(define-vop (allocate-full-call-frame) - (:info nargs) - (:results (res :scs (any-reg))) - (:generator 2 - (when (> nargs register-arg-count) - (move csp-tn res) - (inst ldo (* nargs n-word-bytes) csp-tn csp-tn)))) - - -;;; Fix: boil down below notes into something nicer -;;; Emit code needed at the return-point from an unknown-values call for a -;;; fixed number of values. VALUES is the head of the TN-REF list for the -;;; locations that the values are to be received into. NVALS is the number of -;;; values that are to be received (should equal the length of VALUES). -;;; -;;; MOVE-TEMP is a DESCRIPTOR-REG TN used as a temporary. -;;; -;;; This code exploits the fact that in the unknown-values convention, a -;;; single value return returns at the return PC + 8, whereas a return of other -;;; than one value returns directly at the return PC. -;;; -;;; If 0 or 1 values are expected, then we just emit an instruction to reset -;;; the SP (which will only be executed when other than 1 value is returned.) -;;; -;;; In the general case, we have to do three things: -;;; -- Default unsupplied register values. This need only be done when a -;;; single value is returned, since register values are defaulted by the -;;; called in the non-single case. -;;; -- Default unsupplied stack values. This needs to be done whenever there -;;; are stack values. -;;; -- Reset SP. This must be done whenever other than 1 value is returned, -;;; regardless of the number of values desired. -;;; -;;; The general-case code looks like this: -#| - b regs-defaulted ; Skip if MVs - nop - - move a1 null-tn ; Default register values - ... - loadi nargs 1 ; Force defaulting of stack values - move old-fp csp ; Set up args for SP resetting - -regs-defaulted - subu temp nargs register-arg-count - - bltz temp default-value-7 ; jump to default code - addu temp temp -1 - loadw move-temp old-fp-tn 6 ; Move value to correct location. - store-stack-tn val4-tn move-temp - - bltz temp default-value-8 - addu temp temp -1 - loadw move-temp old-fp-tn 7 - store-stack-tn val5-tn move-temp - - ... - -defaulting-done - move sp old-fp ; Reset SP. -<end of code> - -<elsewhere> -default-value-7 - store-stack-tn val4-tn null-tn ; Nil out 7'th value. (first on stack) - -default-value-8 - store-stack-tn val5-tn null-tn ; Nil out 8'th value. - - ... - - br defaulting-done - nop -|# - -(defun default-unknown-values (vop values nvals move-temp temp lra-label) - (declare (type (or tn-ref null) values) - (type unsigned-byte nvals) - (type tn move-temp temp)) - (cond - ((<= nvals 1) - ;; Note that this is a single-value return point. This is actually - ;; the multiple-value entry point for a single desired value, but - ;; the code location has to be here, or the debugger backtrace - ;; gets confused. - (without-scheduling () - (note-this-location vop :single-value-return) - (move ocfp-tn csp-tn t) - (inst nop)) - (when lra-label - (inst compute-code-from-lra code-tn lra-label temp code-tn))) - (t - (let ((regs-defaulted (gen-label)) - (defaulting-done (gen-label)) - (default-stack-vals (gen-label))) - (without-scheduling () - ;; Note that this is an unknown-values return point. - (note-this-location vop :unknown-return) - ;; Branch off to the MV case. - (inst b regs-defaulted) ; dont nullify - ;; If there are no stack results, clear the stack before branch. - (if (> nvals register-arg-count) ; what inst to late-branch-exec - (inst addi (fixnumize (- register-arg-count)) nargs-tn temp) - (move ocfp-tn csp-tn t))) - ;; Do the single value case. - (do ((i 1 (1+ i)) - (val (tn-ref-across values) (tn-ref-across val))) - ((= i (min nvals register-arg-count))) - (move null-tn (tn-ref-tn val))) - (when (> nvals register-arg-count) - (inst b default-stack-vals) - (move csp-tn ocfp-tn t)) - - (emit-label regs-defaulted) - - (when (> nvals register-arg-count) - ;; If there are stack results, we have to default them - ;; and clear the stack. - (collect ((defaults)) - (do ((i register-arg-count (1+ i)) - (val (do ((i 0 (1+ i)) - (val values (tn-ref-across val))) - ((= i register-arg-count) val)) - (tn-ref-across val))) - ((null val)) - - (let ((default-lab (gen-label)) - (tn (tn-ref-tn val))) - (defaults (cons default-lab tn)) - - (inst ldw (* i n-word-bytes) ocfp-tn move-temp) - (inst bc :<= nil temp zero-tn default-lab) - (inst addi (fixnumize -1) temp temp) - (store-stack-tn tn move-temp))) - - (emit-label defaulting-done) - (move ocfp-tn csp-tn) - - (let ((defaults (defaults))) - (aver defaults) - (assemble (:elsewhere) - (emit-label default-stack-vals) - (do ((remaining defaults (cdr remaining))) - ((null remaining)) - (let ((def (car remaining))) - (emit-label (car def)) - (when (null (cdr remaining)) - (inst b defaulting-done)) - (store-stack-tn (cdr def) null-tn))))))) - (when lra-label - (inst compute-code-from-lra code-tn lra-label temp code-tn))))) - (values)) - - -;;;; Unknown values receiving: - -;;; Emit code needed at the return point for an unknown-values call for an -;;; arbitrary number of values. -;;; -;;; We do the single and non-single cases with no shared code: there doesn't -;;; seem to be any potential overlap, and receiving a single value is more -;;; important efficiency-wise. -;;; -;;; When there is a single value, we just push it on the stack, returning -;;; the old SP and 1. -;;; -;;; When there is a variable number of values, we move all of the argument -;;; registers onto the stack, and return Args and Nargs. -;;; -;;; Args and Nargs are TNs wired to the named locations. We must -;;; explicitly allocate these TNs, since their lifetimes overlap with the -;;; results Start and Count (also, it's nice to be able to target them). -(defun receive-unknown-values (args nargs start count lra-label temp) - (declare (type tn args nargs start count temp)) - (let ((variable-values (gen-label)) - (done (gen-label))) - (without-scheduling () - (inst b variable-values :nullify t) - (inst nop)) ; nop because of emit-return-pc alignment - - (when lra-label - (inst compute-code-from-lra code-tn lra-label temp code-tn)) - (inst addi n-word-bytes csp-tn csp-tn) - (storew (first *register-arg-tns*) csp-tn -1) - (inst addi (- n-word-bytes) csp-tn start) - (inst li (fixnumize 1) count) - - (emit-label done) - - (assemble (:elsewhere) - (emit-label variable-values) - (when lra-label - (inst compute-code-from-lra code-tn lra-label temp code-tn)) - (do ((arg *register-arg-tns* (rest arg)) - (i 0 (1+ i))) - ((null arg)) - (storew (first arg) args i)) - (move args start) - (inst b done) - (move nargs count t))) - (values)) - -;;; VOP that can be inherited by unknown values receivers. The main thing this -;;; handles is allocation of the result temporaries. -;;; -(define-vop (unknown-values-receiver) - (:results (start :scs (any-reg)) - (count :scs (any-reg))) - (:temporary (:sc descriptor-reg :offset ocfp-offset - :from :eval :to (:result 0)) - values-start) - (:temporary (:sc any-reg :offset nargs-offset - :from :eval :to (:result 1)) - nvals) - (:temporary (:scs (non-descriptor-reg)) temp)) - - -;;; This hook in the codegen pass lets us insert code before fall-thru entry -;;; points, local-call entry points, and tail-call entry points. The default -;;; does nothing. -(defun emit-block-header (start-label trampoline-label fall-thru-p alignp) - (declare (ignore fall-thru-p alignp)) - (when trampoline-label - (emit-label trampoline-label)) - (emit-label start-label)) - - -;;;; Local call with unknown values convention return: - -;;; Non-TR local call for a fixed number of values passed according to the -;;; unknown values convention. -;;; -;;; Args are the argument passing locations, which are specified only to -;;; terminate their lifetimes in the caller. -;;; -;;; Values are the return value locations (wired to the standard passing -;;; locations). -;;; -;;; Save is the save info, which we can ignore since saving has been done. -;;; Return-PC is the TN that the return PC should be passed in. -;;; Target is a continuation pointing to the start of the called function. -;;; Nvals is the number of values received. -;;; -;;; Note: we can't use normal load-tn allocation for the fixed args, since all -;;; registers may be tied up by the more operand. Instead, we use -;;; MAYBE-LOAD-STACK-TN. -;;; -(define-vop (call-local) - (:args (cfp) - (nfp) - (args :more t)) - (:results (values :more t)) - (:save-p t) - (:move-args :local-call) - (:info arg-locs callee target nvals) - (:vop-var vop) - (:temporary (:scs (descriptor-reg) :from :eval) move-temp) - (:temporary (:scs (non-descriptor-reg)) temp) - (:temporary (:sc control-stack :offset nfp-save-offset) nfp-save) - (:temporary (:sc any-reg :offset ocfp-offset :from :eval) ocfp) - (:ignore arg-locs args ocfp) - (:generator 5 - (let ((label (gen-label)) - (cur-nfp (current-nfp-tn vop))) - (when cur-nfp - (store-stack-tn nfp-save cur-nfp)) - (let ((callee-nfp (callee-nfp-tn callee))) - (when callee-nfp - (maybe-load-stack-tn callee-nfp nfp))) - (maybe-load-stack-tn cfp-tn cfp) - (inst compute-lra-from-code code-tn label temp - (callee-return-pc-tn callee)) - (note-this-location vop :call-site) - (inst b target :nullify t) - (emit-return-pc label) - (default-unknown-values vop values nvals move-temp temp label) - (when cur-nfp - (load-stack-tn cur-nfp nfp-save))))) - -;;; Non-TR local call for a variable number of return values passed according -;;; to the unknown values convention. The results are the start of the values -;;; glob and the number of values received. -;;; -;;; Note: we can't use normal load-tn allocation for the fixed args, since all -;;; registers may be tied up by the more operand. Instead, we use -;;; MAYBE-LOAD-STACK-TN. -;;; -(define-vop (multiple-call-local unknown-values-receiver) - (:args (cfp) - (nfp) - (args :more t)) - (:save-p t) - (:move-args :local-call) - (:info save callee target) - (:ignore args save) - (:vop-var vop) - (:temporary (:sc control-stack :offset nfp-save-offset) nfp-save) - (:temporary (:scs (non-descriptor-reg)) temp) - (:generator 20 - (let ((label (gen-label)) - (cur-nfp (current-nfp-tn vop))) - (when cur-nfp - (store-stack-tn nfp-save cur-nfp)) - (let ((callee-nfp (callee-nfp-tn callee))) - (when callee-nfp - (maybe-load-stack-tn callee-nfp nfp))) - (maybe-load-stack-tn cfp-tn cfp) - (inst compute-lra-from-code code-tn label temp - (callee-return-pc-tn callee)) - (note-this-location vop :call-site) - (inst b target :nullify t) - (emit-return-pc label) - (note-this-location vop :unknown-return) - (receive-unknown-values values-start nvals start count label temp) - (when cur-nfp - (load-stack-tn cur-nfp nfp-save))))) - - -;;;; Local call with known values return: - -;;; Non-TR local call with known return locations. Known-value return works -;;; just like argument passing in local call. -;;; -;;; Note: we can't use normal load-tn allocation for the fixed args, since all -;;; registers may be tied up by the more operand. Instead, we use -;;; MAYBE-LOAD-STACK-TN. -;;; -(define-vop (known-call-local) - (:args (cfp) - (nfp) - (args :more t)) - (:results (res :more t)) - (:move-args :local-call) - (:save-p t) - (:info save callee target) - (:ignore args res save) - (:vop-var vop) - (:temporary (:sc control-stack :offset nfp-save-offset) nfp-save) - (:temporary (:scs (non-descriptor-reg)) temp) - (:generator 5 - (let ((label (gen-label)) - (cur-nfp (current-nfp-tn vop))) - (when cur-nfp - (store-stack-tn nfp-save cur-nfp)) - (let ((callee-nfp (callee-nfp-tn callee))) - (when callee-nfp - (maybe-load-stack-tn callee-nfp nfp))) - (maybe-load-stack-tn cfp-tn cfp) - (inst compute-lra-from-code code-tn label temp - (callee-return-pc-tn callee)) - (note-this-location vop :call-site) - (inst b target :nullify t) - (emit-return-pc label) - (note-this-location vop :known-return) - (when cur-nfp - (load-stack-tn cur-nfp nfp-save))))) - -;;; Return from known values call. We receive the return locations as -;;; arguments to terminate their lifetimes in the returning function. We -;;; restore FP and CSP and jump to the Return-PC. -;;; -;;; Note: we can't use normal load-tn allocation for the fixed args, since all -;;; registers may be tied up by the more operand. Instead, we use -;;; MAYBE-LOAD-STACK-TN. -;;; -(define-vop (known-return) - (:args (ocfp :target ocfp-temp) - (return-pc :target return-pc-temp) - (vals :more t)) - (:temporary (:sc any-reg :from (:argument 0)) ocfp-temp) - (:temporary (:sc descriptor-reg :from (:argument 1)) return-pc-temp) - (:temporary (:scs (interior-reg)) lip) - (:move-args :known-return) - (:info val-locs) - (:ignore val-locs vals) - (:vop-var vop) - (:generator 6 - (maybe-load-stack-tn ocfp-temp ocfp) - (maybe-load-stack-tn return-pc-temp return-pc) - (move cfp-tn csp-tn) - (let ((cur-nfp (current-nfp-tn vop))) - (when cur-nfp - (move cur-nfp nsp-tn))) - (inst addi (- n-word-bytes other-pointer-lowtag) return-pc-temp lip) - (inst bv lip) - (move ocfp-temp cfp-tn t))) - - -;;;; Full call: -;;; -;;; There is something of a cross-product effect with full calls. Different -;;; versions are used depending on whether we know the number of arguments or -;;; the name of the called function, and whether we want fixed values, unknown -;;; values, or a tail call. -;;; -;;; In full call, the arguments are passed creating a partial frame on the -;;; stack top and storing stack arguments into that frame. On entry to the -;;; callee, this partial frame is pointed to by FP. If there are no stack -;;; arguments, we don't bother allocating a partial frame, and instead set FP -;;; to SP just before the call. - -;;; This macro helps in the definition of full call VOPs by avoiding code -;;; replication in defining the cross-product VOPs. -;;; -;;; Name is the name of the VOP to define. -;;; -;;; Named is true if the first argument is a symbol whose global function -;;; definition is to be called. -;;; -;;; Return is either :Fixed, :Unknown or :Tail: -;;; -- If :Fixed, then the call is for a fixed number of values, returned in -;;; the standard passing locations (passed as result operands). -;;; -- If :Unknown, then the result values are pushed on the stack, and the -;;; result values are specified by the Start and Count as in the -;;; unknown-values continuation representation. -;;; -- If :Tail, then do a tail-recursive call. No values are returned. -;;; The Old-Fp and Return-PC are passed as the second and third arguments. -;;; -;;; In non-tail calls, the pointer to the stack arguments is passed as the last -;;; fixed argument. If Variable is false, then the passing locations are -;;; passed as a more arg. Variable is true if there are a variable number of -;;; arguments passed on the stack. Variable cannot be specified with :Tail -;;; return. TR variable argument call is implemented separately. -;;; -;;; In tail call with fixed arguments, the passing locations are passed as a -;;; more arg, but there is no new-FP, since the arguments have been set up in -;;; the current frame. -;;; -(macrolet ((define-full-call (name named return variable) - (aver (not (and variable (eq return :tail)))) - `(define-vop (,name - ,@(when (eq return :unknown) - '(unknown-values-receiver))) - (:args - ,@(unless (eq return :tail) - '((new-fp :scs (any-reg) :to :eval))) - ,@(case named - ((nil) - '((arg-fun :target lexenv))) - (:direct) - (t - '((name :target name-pass)))) - - ,@(when (eq return :tail) - '((ocfp :target ocfp-pass) - (return-pc :target return-pc-pass))) - - ,@(unless variable '((args :more t :scs (descriptor-reg))))) - - ,@(when (eq return :fixed) - '((:results (values :more t)))) - - (:save-p ,(if (eq return :tail) :compute-only t)) - - ,@(unless (or (eq return :tail) variable) - '((:move-args :full-call))) - - (:vop-var vop) - (:info ,@(unless (or variable (eq return :tail)) '(arg-locs)) - ,@(unless variable '(nargs)) - ,@(when (eq named :direct) '(fun)) - ,@(when (eq return :fixed) '(nvals)) - step-instrumenting) - - (:ignore - ,@(unless (or variable (eq return :tail)) '(arg-locs)) - ,@(unless variable '(args))) - - (:temporary (:sc descriptor-reg - :offset ocfp-offset - :from (:argument 1) - ,@(unless (eq return :fixed) - '(:to :eval))) - ocfp-pass) - - (:temporary (:sc descriptor-reg - :offset lra-offset - :from (:argument ,(if (eq return :tail) 2 1)) - :to :eval) - return-pc-pass) - - ,@(case named - ((t) - `((:temporary (:sc descriptor-reg :offset fdefn-offset - :from (:argument ,(if (eq return :tail) 0 1)) - :to :eval) - name-pass))) - ((nil) - `((:temporary (:sc descriptor-reg :offset lexenv-offset - :from (:argument ,(if (eq return :tail) 0 1)) - :to :eval) - lexenv) - (:temporary (:scs (descriptor-reg) :from (:argument 0) :to :eval) - function)))) - - (:temporary (:sc any-reg :offset nargs-offset :to :eval) - nargs-pass) - - ,@(when variable - (mapcar (lambda (name offset) - `(:temporary (:sc descriptor-reg - :offset ,offset - :to :eval) - ,name)) - register-arg-names *register-arg-offsets*)) - ,@(when (eq return :fixed) - '((:temporary (:scs (descriptor-reg) :from :eval) move-temp))) - - (:temporary (:scs (descriptor-reg) :to :eval) stepping) - - ,@(unless (eq return :tail) - '((:temporary (:scs (non-descriptor-reg)) temp) - (:temporary (:sc control-stack :offset nfp-save-offset) nfp-save))) - - (:temporary (:sc interior-reg :offset lip-offset) entry-point) - - (:generator ,(+ (if named 5 0) - (if variable 19 1) - (if (eq return :tail) 0 10) - 15 - (if (eq return :unknown) 25 0)) - (let* ((cur-nfp (current-nfp-tn vop)) - ,@(unless (eq return :tail) - '((lra-label (gen-label)))) - (step-done-label (gen-label)) - (filler - (remove nil - (list :load-nargs - ,@(if (eq return :tail) - '((unless (location= ocfp ocfp-pass) - :load-ocfp) - (unless (location= return-pc - return-pc-pass) - :load-return-pc) - (when cur-nfp - :frob-nfp)) - '(:comp-lra - (when cur-nfp - :frob-nfp) - :save-fp - :load-fp)))))) - (flet ((do-next-filler () - (let* ((next (pop filler)) - (what (if (consp next) (car next) next))) - (ecase what - (:load-nargs - ,@(if variable - `((inst sub csp-tn new-fp nargs-pass) - ,@(let ((index -1)) - (mapcar (lambda (name) - `(inst ldw ,(ash (incf index) - word-shift) - new-fp - ,name)) - register-arg-names))) - '((inst li (fixnumize nargs) nargs-pass)))) - ,@(if (eq return :tail) - '((:load-ocfp - (sc-case ocfp - (any-reg - (move ocfp ocfp-pass t)) - (control-stack - (inst ldw (ash (tn-offset ocfp) - word-shift) - cfp-tn ocfp-pass)))) - (:load-return-pc - (sc-case return-pc - (descriptor-reg - (move return-pc return-pc-pass t)) - (control-stack - (inst ldw (ash (tn-offset return-pc) - word-shift) - cfp-tn return-pc-pass)))) - (:frob-nfp - (inst ldo (- (bytes-needed-for-non-descriptor-stack-frame)) - nsp-tn nsp-tn))) - `((:comp-lra - (inst compute-lra-from-code code-tn lra-label - temp return-pc-pass)) - (:frob-nfp - (store-stack-tn nfp-save cur-nfp)) - (:save-fp - (move cfp-tn ocfp-pass t)) - (:load-fp - ,(if variable - '(move new-fp cfp-tn) - '(if (> nargs register-arg-count) - (move new-fp cfp-tn) - (move csp-tn cfp-tn)))))) - ((nil) - (inst nop))))) - (insert-step-instrumenting (callable-tn) - ;; Conditionally insert a conditional trap: - (when step-instrumenting - (load-symbol-value stepping sb-impl::*stepping*) - ;; If it's not zero, trap. - (inst comb := stepping zero-tn step-done-label :nullify t) - ;; CONTEXT-PC will be pointing here when the - ;; interrupt is handled, not after the BREAK. - (note-this-location vop :internal-error) - ;; Construct a trap code with the low bits from - ;; SINGLE-STEP-AROUND-TRAP and the high bits from - ;; the register number of CALLABLE-TN. - (inst break 0 (logior single-step-around-trap - (ash (reg-tn-encoding callable-tn) - 5))) - (emit-label step-done-label)))) - (declare (ignorable #'insert-step-instrumenting)) - ,@(case named - ((t) - `((sc-case name - (descriptor-reg (move name name-pass)) - (control-stack - (inst ldw (tn-byte-offset name) - cfp-tn name-pass) - (do-next-filler)) - (constant - (inst ldw (- (tn-byte-offset name) - other-pointer-lowtag) - code-tn name-pass) - (do-next-filler))) - ;; The step instrumenting must be done after - ;; FUNCTION is loaded, but before ENTRY-POINT is - ;; calculated. - (insert-step-instrumenting name-pass) - (inst ldw (- (ash fdefn-raw-addr-slot word-shift) - other-pointer-lowtag) - name-pass entry-point) - (do-next-filler))) - ((nil) - `((sc-case arg-fun - (descriptor-reg - (move arg-fun lexenv)) - (control-stack - (inst ldw (tn-byte-offset arg-fun) - cfp-tn lexenv) - (do-next-filler)) - (constant - (inst ldw - (- (tn-byte-offset arg-fun) - other-pointer-lowtag) code-tn lexenv) - (do-next-filler))) - (inst ldw (- (ash closure-fun-slot word-shift) - fun-pointer-lowtag) - lexenv function) - (do-next-filler) - ;; The step instrumenting must be done before - ;; after FUNCTION is loaded, but before ENTRY-POINT - ;; is calculated. - (insert-step-instrumenting function) - (inst addi (- (ash simple-fun-insts-offset word-shift) - fun-pointer-lowtag) - function entry-point))) - (:direct - `((inst ldw (static-fun-offset fun) null-tn entry-point)))) - (loop - (if (cdr filler) - (do-next-filler) - (return))) - - (do-next-filler) - (note-this-location vop :call-site) - (inst bv entry-point :nullify t)) - - ,@(ecase return - (:fixed - '((emit-return-pc lra-label) - (default-unknown-values vop values nvals - move-temp temp lra-label) - (when cur-nfp - (load-stack-tn cur-nfp nfp-save)))) - (:unknown - '((emit-return-pc lra-label) - (note-this-location vop :unknown-return) - (receive-unknown-values values-start nvals start count - lra-label temp) - (when cur-nfp - (load-stack-tn cur-nfp nfp-save)))) - (:tail))))))) - - (define-full-call call nil :fixed nil) - (define-full-call call-named t :fixed nil) - (define-full-call static-call-named :direct :fixed nil) - (define-full-call multiple-call nil :unknown nil) - (define-full-call multiple-call-named t :unknown nil) - (define-full-call static-multiple-call-named :direct :unknown nil) - (define-full-call tail-call nil :tail nil) - (define-full-call tail-call-named t :tail nil) - (define-full-call static-tail-call-named :direct :tail nil) - - (define-full-call call-variable nil :fixed t) - (define-full-call multiple-call-variable nil :unknown t)) - - -;;; Defined separately, since needs special code that blits the arguments -;;; down. -;;; -(define-vop (tail-call-variable) - (:args (args-arg :scs (any-reg) :target args) - (function-arg :scs (descriptor-reg) :target lexenv) - (ocfp-arg :scs (any-reg) :target ocfp) - (lra-arg :scs (descriptor-reg) :target lra)) - - (:temporary (:sc any-reg :offset nl0-offset :from (:argument 0)) args) - (:temporary (:sc any-reg :offset lexenv-offset :from (:argument 1)) lexenv) - (:temporary (:sc any-reg :offset ocfp-offset :from (:argument 2)) ocfp) - (:temporary (:sc any-reg :offset lra-offset :from (:argument 3)) lra) - (:temporary (:scs (any-reg) :from (:argument 3)) tmp) - (:vop-var vop) - (:generator 75 - ;; Move these into the passing locations if they are not already there. - (move args-arg args) - (move function-arg lexenv) - (move ocfp-arg ocfp) - (move lra-arg lra) - ;; And jump to the assembly-routine that does the bliting. - (let ((fixup (make-fixup 'tail-call-variable :assembly-routine))) - (inst ldil fixup tmp) - (inst be fixup lisp-heap-space tmp)) - ;; Pull the number stack if anything is there. - (let ((cur-nfp (current-nfp-tn vop))) - (if cur-nfp - ;;; NSP is restored by setting it to NSP, - ;;; because stack grows towards higher addresses. - (move cur-nfp nsp-tn) - (inst nop))))) - - -;;;; Unknown values return: - -;;; Return a single value using the unknown-values convention. -;;; -;;; NSP is restored by setting it to NSP, because stack grows -;;; towards higher addresses. -(define-vop (return-single) - (:args (ocfp :scs (any-reg)) - (return-pc :scs (descriptor-reg)) - (value)) - (:ignore value) - (:vop-var vop) - (:generator 6 - ;; Clear the number stack. - (let ((cur-nfp (current-nfp-tn vop))) - (when cur-nfp - (move cur-nfp nsp-tn))) - ;; Clear the control stack, and restore the frame pointer. - (move cfp-tn csp-tn) - (move ocfp cfp-tn) - ;; Out of here. - (lisp-return return-pc :offset 2))) - -;;; Do unknown-values return of a fixed number of values. The Values are -;;; required to be set up in the standard passing locations. Nvals is the -;;; number of values returned. -;;; -;;; If returning a single value, then deallocate the current frame, restore -;;; FP and jump to the single-value entry at Return-PC + 8. -;;; -;;; If returning other than one value, then load the number of values returned, -;;; NIL out unsupplied values registers, restore FP and return at Return-PC. -;;; When there are stack values, we must initialize the argument pointer to -;;; point to the beginning of the values block (which is the beginning of the -;;; current frame.) -;;; -(define-vop (return) - (:args (ocfp :scs (any-reg)) - (return-pc :scs (descriptor-reg) :to (:eval 1)) - (values :more t)) - (:ignore values) - (:info nvals) - (:temporary (:sc descriptor-reg :offset a0-offset :from (:eval 0)) a0) - (:temporary (:sc descriptor-reg :offset a1-offset :from (:eval 0)) a1) - (:temporary (:sc descriptor-reg :offset a2-offset :from (:eval 0)) a2) - (:temporary (:sc descriptor-reg :offset a3-offset :from (:eval 0)) a3) - (:temporary (:sc descriptor-reg :offset a4-offset :from (:eval 0)) a4) - (:temporary (:sc descriptor-reg :offset a5-offset :from (:eval 0)) a5) - (:temporary (:sc any-reg :offset nargs-offset) nargs) - (:temporary (:sc any-reg :offset ocfp-offset) val-ptr) - - (:vop-var vop) - (:generator 6 - ;; Clear the number stack. - (let ((cur-nfp (current-nfp-tn vop))) - (when cur-nfp - (move cur-nfp nsp-tn))) - (cond - ((= nvals 1) ;; Clear the control stack, and restore the frame pointer - (move cfp-tn csp-tn) - (move ocfp cfp-tn) - ;; Out of here. - (lisp-return return-pc :offset 2)) - (t - ;; Establish the values pointer and values count. - (move cfp-tn val-ptr) - (inst li (fixnumize nvals) nargs) - ;; restore the frame pointer and clear as much of the control - ;; stack as possible. - (move ocfp cfp-tn) - (inst ldo (* nvals n-word-bytes) val-ptr csp-tn) - (aver (= (* nvals n-word-bytes) (fixnumize nvals))) - ;; pre-default any argument register that need it. - (when (< nvals register-arg-count) - (dolist (reg (subseq (list a0 a1 a2 a3 a4 a5) nvals)) - (move null-tn reg))) - ;; And away we go. - (lisp-return return-pc))))) - -;;; Do unknown-values return of an arbitrary number of values (passed on the -;;; stack.) We check for the common case of a single return value, and do that -;;; inline using the normal single value return convention. Otherwise, we -;;; branch off to code that calls an assembly-routine. -;;; -(define-vop (return-multiple) - (:args (ocfp-arg :scs (any-reg) :target ocfp) - (lra-arg :scs (descriptor-reg) :target lra) - (vals-arg :scs (any-reg) :target vals) - (nvals-arg :scs (any-reg) :target nvals)) - - (:temporary (:sc any-reg :offset nl1-offset :from (:argument 0)) ocfp) - (:temporary (:sc descriptor-reg :offset lra-offset :from (:argument 1)) lra) - (:temporary (:sc any-reg :offset nl0-offset :from (:argument 2)) vals) - (:temporary (:sc any-reg :offset nargs-offset :from (:argument 3)) nvals) - (:temporary (:sc descriptor-reg :offset a0-offset) a0) - (:temporary (:scs (any-reg) :from (:eval 0)) tmp) - (:vop-var vop) - (:generator 13 - (let ((not-single (gen-label))) - ;; Clear the number stack. - (let ((cur-nfp (current-nfp-tn vop))) - (when cur-nfp - (move cur-nfp nsp-tn))) - ;; Check for the single case. - (inst comib :<> (fixnumize 1) nvals-arg not-single) - (loadw a0 vals-arg) - ;; Return with one value. - (move cfp-tn csp-tn) - (move ocfp-arg cfp-tn) - (lisp-return lra-arg :offset 2) - ;; Nope, not the single case. - (emit-label not-single) - ;; most of these moves will not be emitted and therefor - ;; isn't suitable to put in the delay slot below. But if - ;; you do, dont forget to force-emit as in (move src dst t) - (move ocfp-arg ocfp) - (move lra-arg lra) - (move vals-arg vals) - (move nvals-arg nvals) - (let ((fixup (make-fixup 'return-multiple :assembly-routine))) - (inst ldil fixup tmp) - (inst be fixup lisp-heap-space tmp :nullify t))))) - - -;;;; XEP hackery: - -;;; Get the lexical environment from its passing location. -;;; -(define-vop (setup-closure-environment) - (:temporary (:sc descriptor-reg :offset lexenv-offset :target closure - :to (:result 0)) - lexenv) - (:results (closure :scs (descriptor-reg))) - (:info label) - (:ignore label) - (:generator 6 - ;; Get result. - (move lexenv closure))) - -;;; Copy a more arg from the argument area to the end of the current frame. -;;; Fixed is the number of non-more arguments. -;;; FIXME-lav: old hppa code look smarter. -(define-vop (copy-more-arg) - (:temporary (:sc any-reg :offset nl0-offset) result) - (:temporary (:sc any-reg :offset nl1-offset) count) - (:temporary (:sc any-reg :offset nl2-offset) src) - (:temporary (:sc any-reg :offset nl3-offset) dst) - (:temporary (:sc descriptor-reg :offset l0-offset) temp) - (:info fixed) - (:generator 20 - (let ((loop (gen-label)) - (do-regs (gen-label)) - (done (gen-label))) - (when (< fixed register-arg-count) - ;; Save a pointer to the results so we can fill in register args. - ;; We don't need this if there are more fixed args than reg args. - (move csp-tn result)) - ;; Allocate the space on the stack. - (cond ((zerop fixed) - (inst comb := nargs-tn zero-tn done) - (inst add nargs-tn csp-tn csp-tn)) - (t - (inst addi (fixnumize (- fixed)) nargs-tn count) - (inst comb :<= count zero-tn done :nullify t) - (inst add count csp-tn csp-tn))) - (when (< fixed register-arg-count) - ;; We must stop when we run out of stack args, not when we run out of - ;; more args. - (inst addi (fixnumize (- register-arg-count)) nargs-tn count)) - ;; Everything of interest in registers. - (inst comb :<= count zero-tn do-regs) - ;; Initialize dst to be end of stack. - (move csp-tn dst t) - ;; Initialize src to be end of args. - (inst add nargs-tn cfp-tn src) - - (emit-label loop) - ;; decrease src, then load src into temp - (inst ldwm (- n-word-bytes) src temp) - ;; increase, compare if count >= to zero, if true, jump - (inst addib :>= (fixnumize -1) count loop) - ;; decrease dst, then store temp at dst - (inst stwm temp (- n-word-bytes) dst) - - (emit-label do-regs) - (when (< fixed register-arg-count) - ;; Now we have to deposit any more args that showed up in registers. - ;; We know there is at least one more arg, otherwise we would have - ;; branched to done up at the top. - (inst addi (- (fixnumize (1+ fixed))) nargs-tn count) - (do ((i fixed (1+ i))) - ((>= i register-arg-count)) - ;; Is this the last one? - (inst comb := count zero-tn done) - ;; Store it relative to the pointer saved at the start. - (storew (nth i *register-arg-tns*) result (- i fixed)) - ;; Decrement count. - (inst addi (- (fixnumize 1)) count count))) - (emit-label done)))) - -;;; More args are stored consequtively on the stack, starting immediately at -;;; the context pointer. The context pointer is not typed, so the lowtag is 0. -;;; -(define-vop (more-arg) - (:translate %more-arg) - (:policy :fast-safe) - (:args (context :scs (descriptor-reg)) - (index :scs (any-reg))) - (:arg-types * tagged-num) - (:temporary (:scs (any-reg)) temp) - (:results (value :scs (descriptor-reg any-reg))) - (:result-types *) - (:generator 5 - (inst add context index temp) - (loadw value temp))) -(define-vop (more-arg-c) - (:translate %more-arg) - (:policy :fast-safe) - (:args (context :scs (descriptor-reg))) - (:info index) - (:arg-types * (:constant (load/store-index 8 0 0))) - (:results (value :scs (descriptor-reg any-reg))) - (:result-types *) - (:generator 4 - (loadw value context index))) - -;;; Turn more arg (context, count) into a list. -(define-vop () - (:translate %listify-rest-args) - (:args (context-arg :target context :scs (descriptor-reg)) - (count-arg :target count :scs (any-reg))) - (:arg-types * tagged-num) - (:temporary (:scs (any-reg) :from (:argument 0)) context) - (:temporary (:scs (any-reg) :from (:argument 1)) count) - (:temporary (:scs (descriptor-reg) :from :eval) temp dst) - (:results (result :scs (descriptor-reg))) - (:policy :safe) - (:node-var node) - (:generator 20 - (let* ((enter (gen-label)) - (loop (gen-label)) - (done (gen-label)) - (dx-p (node-stack-allocate-p node)) - (alloc-area-tn (if dx-p csp-tn alloc-tn))) - (move context-arg context) - (move count-arg count) - ;; Check to see if there are any arguments. - (inst comb := count zero-tn done) - (move null-tn result t) - - ;; We need to do this atomically. - (pseudo-atomic () - (when dx-p - (align-csp temp)) - ;; Allocate a cons (2 words) for each item. - (set-lowtag list-pointer-lowtag alloc-area-tn result) - (move result dst) - (inst sll count 1 temp) - (inst b enter) - (inst add temp alloc-area-tn alloc-area-tn) - - ;; Store the current cons in the cdr of the previous cons. - (emit-label loop) - (inst addi (* 2 n-word-bytes) dst dst) - (storew dst dst -1 list-pointer-lowtag) - - (emit-label enter) - ;; Grab one value. - (inst ldwm n-word-bytes context temp) - ;; Dec count, and if != zero, go back for more. - (inst addib :<> (fixnumize -1) count loop) - ;; Store the value in the car (in delay slot) - (storew temp dst 0 list-pointer-lowtag) - - ;; NIL out the last cons. - (storew null-tn dst 1 list-pointer-lowtag)) - (emit-label done)))) - -;;; Return the location and size of the more arg glob created by Copy-More-Arg. -;;; Supplied is the total number of arguments supplied (originally passed in -;;; NARGS.) Fixed is the number of non-rest arguments. -;;; -;;; We must duplicate some of the work done by Copy-More-Arg, since at that -;;; time the environment is in a pretty brain-damaged state, preventing this -;;; info from being returned as values. What we do is compute -;;; supplied - fixed, and return a pointer that many words below the current -;;; stack top. -;;; -(define-vop () - (:policy :fast-safe) - (:translate sb-c::%more-arg-context) - (:args (supplied :scs (any-reg))) - (:arg-types tagged-num (:constant fixnum)) - (:info fixed) - (:results (context :scs (descriptor-reg)) - (count :scs (any-reg))) - (:result-types t tagged-num) - (:note "more-arg-context") - (:generator 5 - (inst addi (fixnumize (- fixed)) supplied count) - (inst sub csp-tn count context))) - -(define-vop (verify-arg-count) - (:policy :fast-safe) - (:args (nargs :scs (any-reg))) - (:arg-types positive-fixnum (:constant t) (:constant t)) - (:info min max) - (:vop-var vop) - (:save-p :compute-only) - (:generator 3 - (let ((err-lab - (generate-error-code vop 'invalid-arg-count-error nargs))) - (cond ((not min) - (if (zerop max) - (inst bc :<> nil nargs zero-tn err-lab) - (inst bci :<> nil (fixnumize max) nargs err-lab))) - (max - (when (plusp min) - (inst bci :> nil (fixnumize min) nargs err-lab)) - (inst bci :< nil (fixnumize max) nargs err-lab)) - ((plusp min) - (inst bci :> nil (fixnumize min) nargs err-lab)))))) - -;;; Single-stepping - -(define-vop (step-instrument-before-vop) - (:temporary (:scs (descriptor-reg)) stepping) - (:policy :fast-safe) - (:vop-var vop) - (:generator 3 - (load-symbol-value stepping sb-impl::*stepping*) - ;; If it's not zero, trap. - (inst comb := stepping zero-tn DONE :nullify t) - ;; CONTEXT-PC will be pointing here when the interrupt is handled, - ;; not after the BREAK. - (note-this-location vop :internal-error) - ;; CALLEE-REGISTER-OFFSET isn't needed for before-traps, so we - ;; can just use a bare SINGLE-STEP-BEFORE-TRAP as the code. - (inst break 0 single-step-before-trap) - DONE)) diff --git a/src/compiler/hppa/cell.lisp b/src/compiler/hppa/cell.lisp deleted file mode 100644 index 4686fd0ad6..0000000000 --- a/src/compiler/hppa/cell.lisp +++ /dev/null @@ -1,450 +0,0 @@ -;;;; the VM definition of various primitive memory access VOPs for -;;;; HPPA - -;;;; This software is part of the SBCL system. See the README file for -;;;; more information. -;;;; -;;;; This software is derived from the CMU CL system, which was -;;;; written at Carnegie Mellon University and released into the -;;;; public domain. The software is in the public domain and is -;;;; provided with absolutely no warranty. See the COPYING and CREDITS -;;;; files for more information. - -(in-package "SB-VM") - -;;;; Data object ref/set stuff. - -(define-vop (slot) - (:args (object :scs (descriptor-reg))) - (:info name offset lowtag) - (:ignore name) - (:results (result :scs (descriptor-reg any-reg))) - (:generator 1 - (loadw result object offset lowtag))) - -(define-vop (set-slot) - (:args (object :scs (descriptor-reg)) - (value :scs (descriptor-reg any-reg null zero))) - (:info name offset lowtag) - (:ignore name) - (:results) - (:generator 1 - (storew value object offset lowtag))) - -(define-vop (init-slot set-slot) - (:info name dx-p offset lowtag) - (:ignore name dx-p)) - -;;;; Symbol hacking VOPs: - -;;; The compiler likes to be able to directly SET symbols. -(define-vop (set cell-set) - (:variant symbol-value-slot other-pointer-lowtag)) - -;;; Do a cell ref with an error check for being unbound. -(define-vop (checked-cell-ref) - (:args (object :scs (descriptor-reg) :target obj-temp)) - (:results (value :scs (descriptor-reg any-reg))) - (:policy :fast-safe) - (:vop-var vop) - (:save-p :compute-only) - (:temporary (:scs (non-descriptor-reg)) temp) - (:temporary (:scs (descriptor-reg) :from (:argument 0)) obj-temp)) - -;;; With Symbol-Value, we check that the value isn't the trap object. So -;;; Symbol-Value of NIL is NIL. -(define-vop (symbol-value checked-cell-ref) - (:translate symeval) - (:generator 9 - (move object obj-temp) - (loadw value obj-temp symbol-value-slot other-pointer-lowtag) - (let ((err-lab (generate-error-code vop 'unbound-symbol-error obj-temp))) - (inst li unbound-marker-widetag temp) - (inst bc := nil value temp err-lab)))) - -;;; Like CHECKED-CELL-REF, only we are a predicate to see if the cell is bound. -(define-vop (boundp-frob) - (:args (object :scs (descriptor-reg))) - (:conditional) - (:info target not-p) - (:policy :fast-safe) - (:temporary (:scs (descriptor-reg)) value) - (:temporary (:scs (non-descriptor-reg)) temp)) - -(define-vop (boundp boundp-frob) - (:translate boundp) - (:generator 9 - (loadw value object symbol-value-slot other-pointer-lowtag) - (inst li unbound-marker-widetag temp) - (inst bc :<> not-p value temp target))) - -(define-vop (fast-symbol-value cell-ref) - (:variant symbol-value-slot other-pointer-lowtag) - (:policy :fast) - (:translate symeval)) - -(define-vop (symbol-hash) - (:policy :fast-safe) - (:translate symbol-hash) - (:args (symbol :scs (descriptor-reg))) - (:temporary (:scs (non-descriptor-reg)) temp) - (:results (res :scs (any-reg))) - (:result-types positive-fixnum) - (:generator 2 - (loadw temp symbol symbol-hash-slot other-pointer-lowtag) - (inst dep 0 31 n-fixnum-tag-bits temp) - ;; we must go through an temporary to avoid gc - (move temp res))) - -;;; On unithreaded builds these are just copies of the non-global versions. -(define-vop (%set-symbol-global-value set)) -(define-vop (symbol-global-value symbol-value) - (:translate sym-global-val)) -(define-vop (fast-symbol-global-value fast-symbol-value) - (:translate sym-global-val)) - -;;;; Fdefinition (fdefn) objects. - -(define-vop (fdefn-fun cell-ref) - (:variant fdefn-fun-slot other-pointer-lowtag)) - -(define-vop (safe-fdefn-fun) - (:translate safe-fdefn-fun) - (:policy :fast-safe) - (:args (object :scs (descriptor-reg) :target obj-temp)) - (:results (value :scs (descriptor-reg any-reg))) - (:vop-var vop) - (:save-p :compute-only) - (:temporary (:scs (descriptor-reg) :from (:argument 0)) obj-temp) - (:generator 10 - (move obj-temp object) - (loadw value obj-temp fdefn-fun-slot other-pointer-lowtag) - (let ((err-lab (generate-error-code vop 'undefined-fun-error obj-temp))) - (inst bc := nil value null-tn err-lab)))) - -(define-vop (set-fdefn-fun) - (:policy :fast-safe) - (:translate (setf fdefn-fun)) - (:args (function :scs (descriptor-reg) :target result) - (fdefn :scs (descriptor-reg))) - (:temporary (:scs (interior-reg)) lip) - (:temporary (:scs (non-descriptor-reg)) type) - (:results (result :scs (descriptor-reg))) - (:generator 38 - (let ((normal-fn (gen-label))) - (load-type type function (- fun-pointer-lowtag)) - (inst addi (- simple-fun-widetag) type type) - (inst comb := type zero-tn normal-fn) - (inst addi (- (ash simple-fun-insts-offset word-shift) fun-pointer-lowtag) - function lip) - (inst li (make-fixup 'closure-tramp :assembly-routine) lip) - (emit-label normal-fn) - (storew function fdefn fdefn-fun-slot other-pointer-lowtag) - (storew lip fdefn fdefn-raw-addr-slot other-pointer-lowtag) - (move function result)))) - -(define-vop (fdefn-makunbound) - (:policy :fast-safe) - (:translate fdefn-makunbound) - (:args (fdefn :scs (descriptor-reg) :target result)) - (:temporary (:scs (non-descriptor-reg)) temp) - (:results (result :scs (descriptor-reg))) - (:generator 38 - (storew null-tn fdefn fdefn-fun-slot other-pointer-lowtag) - (inst li (make-fixup 'undefined-tramp :assembly-routine) temp) - (storew temp fdefn fdefn-raw-addr-slot other-pointer-lowtag) - (move fdefn result))) - - -;;;; Binding and Unbinding. - -;;; BIND -- Establish VAL as a binding for SYMBOL. Save the old value and -;;; the symbol on the binding stack and stuff the new value into the -;;; symbol. -;;; -;;; See the "Chapter 9: Specials" of the SBCL Internals Manual. - -(define-vop (dynbind) - (:args (val :scs (any-reg descriptor-reg)) - (symbol :scs (descriptor-reg))) - (:temporary (:scs (descriptor-reg)) temp) - (:generator 5 - (loadw temp symbol symbol-value-slot other-pointer-lowtag) - (inst addi (* 2 n-word-bytes) bsp-tn bsp-tn) - (storew temp bsp-tn (- binding-value-slot binding-size)) - (storew symbol bsp-tn (- binding-symbol-slot binding-size)) - (storew val symbol symbol-value-slot other-pointer-lowtag))) - -(define-vop (unbind) - (:temporary (:scs (descriptor-reg)) symbol value) - (:generator 0 - (loadw symbol bsp-tn (- binding-symbol-slot binding-size)) - (loadw value bsp-tn (- binding-value-slot binding-size)) - (storew value symbol symbol-value-slot other-pointer-lowtag) - (storew zero-tn bsp-tn (- binding-symbol-slot binding-size)) - (storew zero-tn bsp-tn (- binding-value-slot binding-size)) - (inst addi (- (* 2 n-word-bytes)) bsp-tn bsp-tn))) - -(define-vop (unbind-to-here) - (:args (arg :scs (descriptor-reg any-reg) :target where)) - (:temporary (:scs (any-reg) :from (:argument 0)) where) - (:temporary (:scs (descriptor-reg)) symbol value) - (:generator 0 - (let ((loop (gen-label)) - (skip (gen-label)) - (done (gen-label))) - (move arg where) - (inst comb := where bsp-tn done :nullify t) - - (emit-label loop) - (loadw symbol bsp-tn (- binding-symbol-slot binding-size)) - (inst comb := symbol zero-tn skip) - (loadw value bsp-tn (- binding-value-slot binding-size)) - (storew value symbol symbol-value-slot other-pointer-lowtag) - (storew zero-tn bsp-tn (- binding-symbol-slot binding-size)) - - (emit-label skip) - (storew zero-tn bsp-tn (- binding-value-slot binding-size)) - (inst addi (* -2 n-word-bytes) bsp-tn bsp-tn) - (inst comb :<> where bsp-tn loop) - (inst nop) - (emit-label done)))) - - -;;;; Closure indexing. - -(define-full-reffer closure-index-ref * - closure-info-offset fun-pointer-lowtag - (descriptor-reg any-reg) * %closure-index-ref) - -(define-full-setter set-funcallable-instance-info * - funcallable-instance-info-offset fun-pointer-lowtag - (descriptor-reg any-reg null zero) * %set-funcallable-instance-info) - -(define-full-reffer funcallable-instance-info * - funcallable-instance-info-offset fun-pointer-lowtag - (descriptor-reg any-reg) * %funcallable-instance-info) - -(define-vop (closure-ref) - (:args (object :scs (descriptor-reg))) - (:results (value :scs (descriptor-reg any-reg))) - (:info offset) - (:generator 4 - (loadw value object (+ closure-info-offset offset) fun-pointer-lowtag))) - -(define-vop (closure-init) - (:args (object :scs (descriptor-reg)) - (value :scs (descriptor-reg any-reg))) - (:info offset) - (:generator 4 - (storew value object (+ closure-info-offset offset) fun-pointer-lowtag))) - -(define-vop (closure-init-from-fp) - (:args (object :scs (descriptor-reg))) - (:info offset) - (:generator 4 - (storew cfp-tn object (+ closure-info-offset offset) fun-pointer-lowtag))) - -;;;; Value Cell hackery. - -(define-vop (value-cell-ref cell-ref) - (:variant value-cell-value-slot other-pointer-lowtag)) - -(define-vop (value-cell-set cell-set) - (:variant value-cell-value-slot other-pointer-lowtag)) - - - -;;;; Instance hackery: - -(define-vop () - (:policy :fast-safe) - (:translate %instance-length) - (:args (struct :scs (descriptor-reg))) - (:results (res :scs (unsigned-reg))) - (:result-types positive-fixnum) - (:generator 4 - (loadw res struct 0 instance-pointer-lowtag) - (inst srl res instance-length-shift res))) - -(define-full-reffer instance-index-ref * instance-slots-offset - instance-pointer-lowtag (descriptor-reg any-reg) * %instance-ref) - -(define-full-setter instance-index-set * instance-slots-offset - instance-pointer-lowtag (descriptor-reg any-reg null zero) * %instance-set) - - - -;;;; Code object frobbing. - -(define-full-reffer code-header-ref * 0 other-pointer-lowtag - (descriptor-reg any-reg) * code-header-ref) - -(define-full-setter code-header-set * 0 other-pointer-lowtag - (descriptor-reg any-reg null zero) * code-header-set) - - -;;;; raw instance slot accessors -(macrolet ((lfloat (imm base dst &key side) - `(cond - ((< ,imm (ash 1 4)) - (inst flds ,imm ,base ,dst :side ,side)) - ((and (< ,imm (ash 1 13)) - (> ,imm 0)) - (progn - (inst li ,imm offset) - (inst fldx offset ,base ,dst :side ,side))) - (t - (error "inst fldx cant handle offset-register loaded with immediate ~s" ,imm)))) - (sfloat (src imm base &key side) - `(cond - ((< ,imm (ash 1 4)) - (inst fsts ,src ,imm ,base :side ,side)) - ((and (< ,imm (ash 1 13)) - (> ,imm 0)) - (progn - (inst ldo ,imm zero-tn offset) - (inst fstx ,src offset ,base :side ,side))) - (t - (error "inst fstx cant handle offset-register loaded with immediate ~s" ,imm)))) - (raw-instance ((type inc-offset-by set &optional complex) - &body body) - (declare (ignore inc-offset-by)) ; FIXME: remove - (let ((name (symbolicate "RAW-INSTANCE-" - (if set "SET/" "REF/") - (case type - (unsigned "WORD") - (signed "SIGNED-WORD") - (t (or complex type))))) - (type-num (cond - ((eq type 'single) - (if complex 'complex-single-float - 'single-float)) - ((eq type 'double) - (if complex 'complex-double-float - 'double-float)) - (t (symbolicate type "-NUM")))) - (type-reg (symbolicate (or complex type) "-REG"))) - `(define-vop (,name) - (:translate ,(symbolicate "%" name)) - (:policy :fast-safe) - (:args (object :scs (descriptor-reg)) - (index :scs (any-reg)) - ,@(if set - `((value :scs (,type-reg) :target result)))) - (:arg-types * positive-fixnum ,@(if set `(,type-num))) - (:results (,(if set 'result 'value) :scs (,type-reg))) - ;; Floating-point load/store might need an extra register - ;; since an immediate displacement is only 5 signed bits. - ,@(if (member type '(single double)) - '((:temporary (:scs (non-descriptor-reg)) offset))) - (:temporary (:scs (interior-reg)) lip) - (:result-types ,type-num) - (:generator 5 - (inst add index object lip) - ,@body))))) - (raw-instance (unsigned -1 nil) - (inst ldw (- (* instance-slots-offset n-word-bytes) - instance-pointer-lowtag) lip value)) - - (raw-instance (unsigned -1 t) - (inst stw value (- (* instance-slots-offset n-word-bytes) - instance-pointer-lowtag) lip) - (move value result)) - - (raw-instance (signed -1 nil) - (inst ldw (- (* instance-slots-offset n-word-bytes) - instance-pointer-lowtag) lip value)) - - (raw-instance (signed -1 t) - (inst stw value (- (* instance-slots-offset n-word-bytes) - instance-pointer-lowtag) lip) - (move value result)) - - (raw-instance (single -1 nil) - (let ((io (- (* instance-slots-offset n-word-bytes) - instance-pointer-lowtag))) - (lfloat io lip value))) - - (raw-instance (single -1 t) - (let ((io (- (* instance-slots-offset n-word-bytes) - instance-pointer-lowtag))) - (sfloat value io lip)) - (unless (location= result value) - (inst funop :copy value result))) - - (raw-instance (double -2 nil) - (let ((io (- (* instance-slots-offset n-word-bytes) - instance-pointer-lowtag))) - (lfloat io lip value))) - - (raw-instance (double -2 t) - (let ((io (- (* instance-slots-offset n-word-bytes) - instance-pointer-lowtag))) - (sfloat value io lip :side 0)) - (let ((io (- (* (1+ instance-slots-offset) n-word-bytes) - instance-pointer-lowtag))) - (sfloat value io lip :side 1)) - (unless (location= result value) - (inst funop :copy value result))) - - (raw-instance (single -2 nil complex-single) - (let ((io (- (* instance-slots-offset n-word-bytes) - instance-pointer-lowtag))) - (lfloat io lip (complex-single-reg-real-tn value))) - (let ((io (- (* (1+ instance-slots-offset) n-word-bytes) - instance-pointer-lowtag))) - (lfloat io lip (complex-single-reg-imag-tn value)))) - - (raw-instance (single -2 t complex-single) - (let ((value-real (complex-single-reg-real-tn value)) - (result-real (complex-single-reg-real-tn result)) - (io (- (* instance-slots-offset n-word-bytes) - instance-pointer-lowtag))) - - (sfloat value-real io lip) - (unless (location= result-real value-real) - (inst funop :copy value-real result-real))) - (let ((value-imag (complex-single-reg-imag-tn value)) - (result-imag (complex-single-reg-imag-tn result)) - (io (- (* (1+ instance-slots-offset) n-word-bytes) - instance-pointer-lowtag))) - (sfloat value-imag io lip) - (unless (location= result-imag value-imag) - (inst funop :copy value-imag result-imag)))) - - (raw-instance (double -4 nil complex-double) - (let ((r0 (- (* instance-slots-offset n-word-bytes) - instance-pointer-lowtag)) - (r1 (- (* (+ instance-slots-offset 1) n-word-bytes) - instance-pointer-lowtag)) - (i0 (- (* (+ instance-slots-offset 2) n-word-bytes) - instance-pointer-lowtag)) - (i1 (- (* (+ instance-slots-offset 3) n-word-bytes) - instance-pointer-lowtag))) - (lfloat r0 lip (complex-double-reg-real-tn value) :side 0) - (lfloat r1 lip (complex-double-reg-real-tn value) :side 1) - (lfloat i0 lip (complex-double-reg-imag-tn value) :side 0) - (lfloat i1 lip (complex-double-reg-imag-tn value) :side 1))) - - (raw-instance (double -4 t complex-double) - (let ((value-real (complex-double-reg-real-tn value)) - (result-real (complex-double-reg-real-tn result)) - (value-imag (complex-double-reg-imag-tn value)) - (result-imag (complex-double-reg-imag-tn result)) - (r0 (- (* instance-slots-offset n-word-bytes) - instance-pointer-lowtag)) - (r1 (- (* (+ instance-slots-offset 1) n-word-bytes) - instance-pointer-lowtag)) - (i0 (- (* (+ instance-slots-offset 2) n-word-bytes) - instance-pointer-lowtag)) - (i1 (- (* (+ instance-slots-offset 3) n-word-bytes) - instance-pointer-lowtag))) - (sfloat value-real r0 lip :side 0) - (sfloat value-real r1 lip :side 1) - (sfloat value-imag i0 lip :side 0) - (sfloat value-imag i1 lip :side 1) - (unless (location= result-real value-real) - (inst funop :copy value-real result-real)) - (unless (location= result-imag value-imag) - (inst funop :copy value-imag result-imag))))) diff --git a/src/compiler/hppa/char.lisp b/src/compiler/hppa/char.lisp deleted file mode 100644 index 73043be774..0000000000 --- a/src/compiler/hppa/char.lisp +++ /dev/null @@ -1,117 +0,0 @@ -;;;; the HPPA VM definition of character operations - -;;;; This software is part of the SBCL system. See the README file for -;;;; more information. -;;;; -;;;; This software is derived from the CMU CL system, which was -;;;; written at Carnegie Mellon University and released into the -;;;; public domain. The software is in the public domain and is -;;;; provided with absolutely no warranty. See the COPYING and CREDITS -;;;; files for more information. - -(in-package "SB-VM") - -;;;; Moves and coercions: - -;;; Move a tagged char to an untagged representation. -(define-vop (move-to-character) - (:note "character untagging") - (:args (x :scs (any-reg descriptor-reg))) - (:results (y :scs (character-reg))) - (:generator 1 - (inst srl x n-widetag-bits y))) -(define-move-vop move-to-character :move - (any-reg descriptor-reg) (character-reg)) - -;;; Move an untagged char to a tagged representation. -(define-vop (move-from-character) - (:note "character tagging") - (:args (x :scs (character-reg))) - (:results (y :scs (any-reg descriptor-reg))) - (:generator 1 - (inst sll x n-widetag-bits y) - (inst addi character-widetag y y))) -(define-move-vop move-from-character :move - (character-reg) (any-reg descriptor-reg)) - -;;; Move untagged character values. -(define-vop (character-move) - (:note "character move") - (:args (x :target y - :scs (character-reg) - :load-if (not (location= x y)))) - (:results (y :scs (character-reg) - :load-if (not (location= x y)))) - (:generator 0 - (move x y))) -(define-move-vop character-move :move - (character-reg) (character-reg)) - -;;; Move untagged character args/return-values. -(define-vop (move-character-arg) - (:note "character arg move") - (:args (x :target y - :scs (character-reg)) - (fp :scs (any-reg) - :load-if (not (sc-is y character-reg)))) - (:results (y)) - (:generator 0 - (sc-case y - (character-reg - (move x y)) - (character-stack - (storew x fp (tn-offset y)))))) -(define-move-vop move-character-arg :move-arg - (any-reg character-reg) (character-reg)) - -;;; Use standard MOVE-ARG + coercion to move an untagged character to -;;; a descriptor passing location. -(define-move-vop move-arg :move-arg - (character-reg) (any-reg descriptor-reg)) - -;;;; Other operations: -(define-vop (char-code) - (:translate char-code) - (:policy :fast-safe) - (:args (ch :scs (character-reg) :target res)) - (:arg-types character) - (:results (res :scs (any-reg))) - (:result-types positive-fixnum) - (:generator 1 - (inst sll ch 2 res))) - -(define-vop (code-char) - (:translate code-char) - (:policy :fast-safe) - (:args (code :scs (any-reg) :target res)) - (:arg-types positive-fixnum) - (:results (res :scs (character-reg))) - (:result-types character) - (:generator 1 - (inst srl code 2 res))) - -;;; Comparison of characters. -(define-vop (character-compare) - (:args (x :scs (character-reg)) - (y :scs (character-reg))) - (:arg-types character character) - (:conditional) - (:info target not-p) - (:policy :fast-safe) - (:note "inline comparison") - (:variant-vars cond) - (:generator 3 - (inst bc cond not-p x y target))) - -(define-vop (fast-char=/character character-compare) - (:translate char=) - (:variant :=)) - -(define-vop (fast-char</character character-compare) - (:translate char<) - (:variant :<<)) - -(define-vop (fast-char>/character character-compare) - (:translate char>) - (:variant :>>)) - diff --git a/src/compiler/hppa/debug.lisp b/src/compiler/hppa/debug.lisp deleted file mode 100644 index f5c00c33e6..0000000000 --- a/src/compiler/hppa/debug.lisp +++ /dev/null @@ -1,91 +0,0 @@ -(in-package "SB-VM") - -(define-vop () - (:translate current-sp) - (:policy :fast-safe) - (:results (res :scs (sap-reg))) - (:result-types system-area-pointer) - (:generator 1 - (move csp-tn res))) - -(define-vop () - (:translate current-fp) - (:policy :fast-safe) - (:results (res :scs (sap-reg))) - (:result-types system-area-pointer) - (:generator 1 - (move cfp-tn res))) - -(define-vop () - (:translate stack-ref) - (:policy :fast-safe) - (:args (object :scs (sap-reg)) - (offset :scs (any-reg))) - (:arg-types system-area-pointer positive-fixnum) - (:results (result :scs (descriptor-reg))) - (:result-types *) - (:generator 5 - (inst ldwx offset object result))) - -(define-vop () - (:translate %set-stack-ref) - (:policy :fast-safe) - (:args (object :scs (sap-reg) :target sap) - (offset :scs (any-reg)) - (value :scs (descriptor-reg) :target result)) - (:arg-types system-area-pointer positive-fixnum *) - (:results (result :scs (descriptor-reg))) - (:result-types *) - (:temporary (:scs (sap-reg) :from (:argument 1)) sap) - (:generator 2 - (inst add object offset sap) - (inst stw value 0 sap) - (move value result))) - -(define-vop (code-from-mumble) - (:policy :fast-safe) - (:args (thing :scs (descriptor-reg))) - (:results (code :scs (descriptor-reg))) - (:temporary (:scs (non-descriptor-reg)) temp) - (:variant-vars lowtag) - (:generator 5 - (let ((bogus (gen-label)) - (done (gen-label))) - (loadw temp thing 0 lowtag) - (inst srl temp n-widetag-bits temp) - (inst comb := zero-tn temp bogus) - (inst sll temp word-shift temp) - (unless (= lowtag other-pointer-lowtag) - (inst addi (- lowtag other-pointer-lowtag) temp temp)) - (inst sub thing temp code) - (emit-label done) - (assemble (:elsewhere) - (emit-label bogus) - (inst b done) - (move null-tn code t))))) - -(define-vop (code-from-lra code-from-mumble) - (:translate sb-di::lra-code-header) - (:variant other-pointer-lowtag)) - -(define-vop (code-from-fun code-from-mumble) - (:translate sb-di::fun-code-header) - (:variant fun-pointer-lowtag)) - -(define-vop (%make-lisp-obj) - (:policy :fast-safe) - (:translate %make-lisp-obj) - (:args (value :scs (unsigned-reg) :target result)) - (:arg-types unsigned-num) - (:results (result :scs (descriptor-reg))) - (:generator 1 - (move value result))) - -(define-vop (get-lisp-obj-address) - (:policy :fast-safe) - (:translate sb-di::get-lisp-obj-address) - (:args (thing :scs (descriptor-reg any-reg) :target result)) - (:results (result :scs (unsigned-reg))) - (:result-types unsigned-num) - (:generator 1 - (move thing result))) diff --git a/src/compiler/hppa/float.lisp b/src/compiler/hppa/float.lisp deleted file mode 100644 index bfdf21497b..0000000000 --- a/src/compiler/hppa/float.lisp +++ /dev/null @@ -1,996 +0,0 @@ -;;;; the HPPA VM definition of floating point operations - -;;;; This software is part of the SBCL system. See the README file for -;;;; more information. -;;;; -;;;; This software is derived from the CMU CL system, which was -;;;; written at Carnegie Mellon University and released into the -;;;; public domain. The software is in the public domain and is -;;;; provided with absolutely no warranty. See the COPYING and CREDITS -;;;; files for more information. - -(in-package "SB-VM") - -;;;; Move functions. -(define-move-fun (load-fp-zero 1) (vop x y) - ((fp-single-zero) (single-reg) - (fp-double-zero) (double-reg)) - (inst funop :copy x y)) - -(defun ld-float (offset base r) - (cond ((< offset (ash 1 4)) - (inst flds offset base r)) - ((and (< offset (ash 1 13)) - (> offset 0)) - (inst ldo offset zero-tn lip-tn) - (inst fldx lip-tn base r)) - (t - (error "ld-float: bad offset: ~s~%" offset)))) - -(define-move-fun (load-float 1) (vop x y) - ((single-stack) (single-reg) - (double-stack) (double-reg)) - (let ((offset (tn-byte-offset x))) - (ld-float offset (current-nfp-tn vop) y))) - -(defun str-float (x offset base) - (cond ((< offset (ash 1 4)) - ;(note-next-instruction vop :internal-error) - (inst fsts x offset base)) - ((and (< offset (ash 1 13)) - (> offset 0)) - ;; FIXME-lav, ok with GC to use lip-tn for arbitrary offsets ? - (inst ldo offset zero-tn lip-tn) - ;(note-next-instruction vop :internal-error) - (inst fstx x lip-tn base)) - (t - (error "str-float: bad offset: ~s~%" offset)))) - -(define-move-fun (store-float 1) (vop x y) - ((single-reg) (single-stack) - (double-reg) (double-stack)) - (let ((offset (tn-byte-offset y))) - (str-float x offset (current-nfp-tn vop)))) - -;;;; Move VOPs -(define-vop (move-float) - (:args (x :scs (single-reg double-reg) - :target y - :load-if (not (location= x y)))) - (:results (y :scs (single-reg double-reg) - :load-if (not (location= x y)))) - (:note "float move") - (:generator 0 - (unless (location= y x) - (inst funop :copy x y)))) -(define-move-vop move-float :move (single-reg) (single-reg)) -(define-move-vop move-float :move (double-reg) (double-reg)) - -(define-vop (move-from-float) - (:args (x :to :save)) - (:results (y :scs (descriptor-reg))) - (:temporary (:scs (non-descriptor-reg)) ndescr) - (:variant-vars size type data) - (:note "float to pointer coercion") - (:generator 13 - (with-fixed-allocation (y nil ndescr type size nil) - nil) - (inst fsts x (- (* data n-word-bytes) other-pointer-lowtag) y))) - -(macrolet ((frob (name sc &rest args) - `(progn - (define-vop (,name move-from-float) - (:args (x :scs (,sc) :to :save)) - (:variant ,@args)) - (define-move-vop ,name :move (,sc) (descriptor-reg))))) - (frob move-from-single single-reg - single-float-size single-float-widetag single-float-value-slot) - (frob move-from-double double-reg - double-float-size double-float-widetag double-float-value-slot)) - -(define-vop (move-to-float) - (:args (x :scs (descriptor-reg))) - (:results (y)) - (:variant-vars offset) - (:note "pointer to float coercion") - (:generator 2 - (inst flds (- (* offset n-word-bytes) other-pointer-lowtag) x y))) - -(macrolet ((frob (name sc offset) - `(progn - (define-vop (,name move-to-float) - (:results (y :scs (,sc))) - (:variant ,offset)) - (define-move-vop ,name :move (descriptor-reg) (,sc))))) - (frob move-to-single single-reg single-float-value-slot) - (frob move-to-double double-reg double-float-value-slot)) - -(define-vop (move-float-arg) - (:args (x :scs (single-reg double-reg) :target y) - (nfp :scs (any-reg) - :load-if (not (sc-is y single-reg double-reg)))) - (:results (y)) - (:note "float argument move") - (:generator 1 - (sc-case y - ((single-reg double-reg) - (unless (location= x y) - (inst funop :copy x y))) - ((single-stack double-stack) - (let ((offset (tn-byte-offset y))) - (str-float x offset nfp)))))) -(define-move-vop move-float-arg :move-arg - (single-reg descriptor-reg) (single-reg)) -(define-move-vop move-float-arg :move-arg - (double-reg descriptor-reg) (double-reg)) - -;;;; Complex float move functions -(defun complex-single-reg-real-tn (x) - (make-random-tn :kind :normal :sc (sc-or-lose 'single-reg) - :offset (tn-offset x))) -(defun complex-single-reg-imag-tn (x) - (make-random-tn :kind :normal :sc (sc-or-lose 'single-reg) - :offset (1+ (tn-offset x)))) - -(defun complex-double-reg-real-tn (x) - (make-random-tn :kind :normal :sc (sc-or-lose 'complex-double-reg) - :offset (tn-offset x))) -(defun complex-double-reg-imag-tn (x) - (make-random-tn :kind :normal :sc (sc-or-lose 'complex-double-reg) - :offset (1+ (tn-offset x)))) - -(macrolet - ((def-move-fun (dir type size from to) - `(define-move-fun (,(symbolicate dir "-" type) ,size) (vop x y) - ((,(symbolicate type "-" from)) (,(symbolicate type "-" to))) - (let ((nfp (current-nfp-tn vop)) - (offset (* (tn-offset ,(if (eq dir 'load) 'x 'y)) n-word-bytes))) - ,@(if (eq dir 'load) - `((let ((real-tn (,(symbolicate type "-REG-REAL-TN") y))) - (ld-float offset nfp real-tn)) - (let ((imag-tn (,(symbolicate type "-REG-IMAG-TN") y))) - (ld-float (+ offset (* ,(/ size 2) n-word-bytes)) nfp imag-tn))) - `((let ((real-tn (,(symbolicate type "-REG-REAL-TN") x))) - (str-float real-tn offset nfp)) - (let ((imag-tn (,(symbolicate type "-REG-IMAG-TN") x))) - (str-float imag-tn - (+ offset (* ,(/ size 2) n-word-bytes)) - nfp)))))))) - (def-move-fun load complex-single 2 stack reg) - (def-move-fun store complex-single 2 reg stack) - (def-move-fun load complex-double 4 stack reg) - (def-move-fun store complex-double 4 reg stack)) - -;;; Complex float register to register moves. -(define-vop (complex-single-move) - (:args (x :scs (complex-single-reg) :target y - :load-if (not (location= x y)))) - (:results (y :scs (complex-single-reg) :load-if (not (location= x y)))) - (:note "complex single float move") - (:generator 0 - (unless (location= x y) - ;; Note the complex-float-regs are aligned to every second - ;; float register so there is not need to worry about overlap. - (let ((x-real (complex-single-reg-real-tn x)) - (y-real (complex-single-reg-real-tn y))) - (inst funop :copy x-real y-real)) - (let ((x-imag (complex-single-reg-imag-tn x)) - (y-imag (complex-single-reg-imag-tn y))) - (inst funop :copy x-imag y-imag))))) -(define-move-vop complex-single-move :move - (complex-single-reg) (complex-single-reg)) - -(define-vop (complex-double-move) - (:args (x :scs (complex-double-reg) - :target y :load-if (not (location= x y)))) - (:results (y :scs (complex-double-reg) :load-if (not (location= x y)))) - (:note "complex double float move") - (:generator 0 - (unless (location= x y) - ;; Note the complex-float-regs are aligned to every second - ;; float register so there is not need to worry about overlap. - (let ((x-real (complex-double-reg-real-tn x)) - (y-real (complex-double-reg-real-tn y))) - (inst funop :copy x-real y-real)) - (let ((x-imag (complex-double-reg-imag-tn x)) - (y-imag (complex-double-reg-imag-tn y))) - (inst funop :copy x-imag y-imag))))) -(define-move-vop complex-double-move :move - (complex-double-reg) (complex-double-reg)) - -;;; Move from a complex float to a descriptor register allocating a -;;; new complex float object in the process. -(define-vop (move-from-complex-single) - (:args (x :scs (complex-single-reg) :to :save)) - (:results (y :scs (descriptor-reg))) - (:temporary (:scs (non-descriptor-reg)) ndescr) - (:note "complex single float to pointer coercion") - (:generator 13 - (with-fixed-allocation (y nil ndescr complex-single-float-widetag - complex-single-float-size nil) - nil) - (let ((real-tn (complex-single-reg-real-tn x))) - (inst fsts real-tn (- (* complex-single-float-real-slot n-word-bytes) - other-pointer-lowtag) y)) - (let ((imag-tn (complex-single-reg-imag-tn x))) - (inst fsts imag-tn (- (* complex-single-float-imag-slot n-word-bytes) - other-pointer-lowtag) y)))) -(define-move-vop move-from-complex-single :move - (complex-single-reg) (descriptor-reg)) - -(define-vop (move-from-complex-double) - (:args (x :scs (complex-double-reg) :to :save)) - (:results (y :scs (descriptor-reg))) - (:temporary (:scs (non-descriptor-reg)) ndescr) - (:note "complex double float to pointer coercion") - (:generator 13 - (with-fixed-allocation (y nil ndescr complex-double-float-widetag - complex-double-float-size nil) - nil) - (let ((real-tn (complex-double-reg-real-tn x))) - (inst fsts real-tn (- (* complex-double-float-real-slot n-word-bytes) - other-pointer-lowtag) y)) - (let ((imag-tn (complex-double-reg-imag-tn x))) - (inst fsts imag-tn (- (* complex-double-float-imag-slot n-word-bytes) - other-pointer-lowtag) y)))) -(define-move-vop move-from-complex-double :move - (complex-double-reg) (descriptor-reg)) - -;;; Move from a descriptor to a complex float register -(define-vop (move-to-complex-single) - (:args (x :scs (descriptor-reg))) - (:results (y :scs (complex-single-reg))) - (:note "pointer to complex float coercion") - (:generator 2 - (let ((real-tn (complex-single-reg-real-tn y))) - (inst flds (- (* complex-single-float-real-slot n-word-bytes) - other-pointer-lowtag) - x real-tn)) - (let ((imag-tn (complex-single-reg-imag-tn y))) - (inst flds (- (* complex-single-float-imag-slot n-word-bytes) - other-pointer-lowtag) - x imag-tn)))) -(define-move-vop move-to-complex-single :move - (descriptor-reg) (complex-single-reg)) - -(define-vop (move-to-complex-double) - (:args (x :scs (descriptor-reg))) - (:results (y :scs (complex-double-reg))) - (:note "pointer to complex float coercion") - (:generator 2 - (let ((real-tn (complex-double-reg-real-tn y))) - (inst flds (- (* complex-double-float-real-slot n-word-bytes) - other-pointer-lowtag) - x real-tn)) - (let ((imag-tn (complex-double-reg-imag-tn y))) - (inst flds (- (* complex-double-float-imag-slot n-word-bytes) - other-pointer-lowtag) - x imag-tn)))) -(define-move-vop move-to-complex-double :move - (descriptor-reg) (complex-double-reg)) - -;;; Complex float move-arg vop -(define-vop (move-complex-single-float-arg) - (:args (x :scs (complex-single-reg) :target y) - (nfp :scs (any-reg) :load-if (not (sc-is y complex-single-reg)))) - (:results (y)) - (:note "float argument move") - (:generator 1 - (sc-case y - (complex-single-reg - (unless (location= x y) - (let ((x-real (complex-single-reg-real-tn x)) - (y-real (complex-single-reg-real-tn y))) - (inst funop :copy x-real y-real)) - (let ((x-imag (complex-single-reg-imag-tn x)) - (y-imag (complex-single-reg-imag-tn y))) - (inst funop :copy x-imag y-imag)))) - (complex-single-stack - (let ((offset (tn-byte-offset y))) - (let ((real-tn (complex-single-reg-real-tn x))) - (str-float real-tn offset nfp)) - (let ((imag-tn (complex-single-reg-imag-tn x))) - (str-float imag-tn (+ offset n-word-bytes) nfp))))))) -(define-move-vop move-complex-single-float-arg :move-arg - (complex-single-reg descriptor-reg) (complex-single-reg)) - -(define-vop (move-complex-double-float-arg) - (:args (x :scs (complex-double-reg) :target y) - (nfp :scs (any-reg) :load-if (not (sc-is y complex-double-reg)))) - (:results (y)) - (:note "float argument move") - (:generator 1 - (sc-case y - (complex-double-reg - (unless (location= x y) - (let ((x-real (complex-double-reg-real-tn x)) - (y-real (complex-double-reg-real-tn y))) - (inst funop :copy x-real y-real)) - (let ((x-imag (complex-double-reg-imag-tn x)) - (y-imag (complex-double-reg-imag-tn y))) - (inst funop :copy x-imag y-imag)))) - (complex-double-stack - (let ((offset (tn-byte-offset y))) - (let ((real-tn (complex-double-reg-real-tn x))) - (str-float real-tn offset nfp)) - (let ((imag-tn (complex-double-reg-imag-tn x))) - (str-float imag-tn (+ offset (* 2 n-word-bytes)) nfp))))))) -(define-move-vop move-complex-double-float-arg :move-arg - (complex-double-reg descriptor-reg) (complex-double-reg)) - -(define-move-vop move-arg :move-arg - (single-reg double-reg complex-single-reg complex-double-reg) - (descriptor-reg)) - -;;;; stuff for c-call float-in-int-register arguments -(define-vop (move-to-single-int-reg) - (:note "pointer to float-in-int coercion") - (:args (x :scs (single-reg descriptor-reg))) - (:results (y :scs (single-int-carg-reg) :load-if nil)) - (:generator 1 - (sc-case x - (single-reg - (inst funop :copy x y)) - (descriptor-reg - (inst ldw (- (* single-float-value-slot n-word-bytes) - other-pointer-lowtag) x y))))) -(define-move-vop move-to-single-int-reg - :move (single-reg descriptor-reg) (single-int-carg-reg)) - -(define-vop (move-single-int-reg) - (:args (x :target y :scs (single-int-carg-reg) :load-if nil) - (fp :scs (any-reg) :load-if (not (sc-is y single-int-carg-reg)))) - (:results (y :scs (single-int-carg-reg) :load-if nil)) - (:ignore fp) - (:generator 1 - (unless (location= x y) - (error "Huh? why did it do that?")))) -(define-move-vop move-single-int-reg :move-arg - (single-int-carg-reg) (single-int-carg-reg)) - -; move contents of float register x to register y -(define-vop (move-to-double-int-reg) - (:note "pointer to float-in-int coercion") - (:args (x :scs (double-reg descriptor-reg))) - (:results (y :scs (double-int-carg-reg) :load-if nil)) - (:temporary (:scs (signed-stack) :to (:result 0)) temp) - (:temporary (:scs (signed-reg) :to (:result 0) :target y) old1) - (:temporary (:scs (signed-reg) :to (:result 0) :target y) old2) - (:vop-var vop) - (:save-p :compute-only) - (:generator 2 - (sc-case x - (double-reg - (let* ((nfp (current-nfp-tn vop)) - (stack-tn (sc-case y - (double-stack y) - (double-int-carg-reg temp))) - (offset (tn-byte-offset stack-tn))) - ;; save 8 bytes of stack to two register, - ;; write down float in stack and load it back - ;; into result register. Notice the result hack, - ;; we are writing to one extra register. - ;; Double float argument convention uses two registers, - ;; but we only know about one (thanks to c-call). - (inst ldw offset nfp old1) - (inst ldw (+ offset n-word-bytes) nfp old2) - (str-float x offset nfp) ; writes 8 bytes - (inst ldw offset nfp y) - (inst ldw (+ offset n-word-bytes) nfp - (make-wired-tn (primitive-type-or-lose 'unsigned-byte-32) - unsigned-reg-sc-number - (+ 1 (tn-offset y)))) - (inst stw old1 offset nfp) - (inst stw old2 (+ offset n-word-bytes) nfp))) - (descriptor-reg - (inst ldw (- (* double-float-value-slot n-word-bytes) - other-pointer-lowtag) x y) - (inst ldw (- (* (1+ double-float-value-slot) n-word-bytes) - other-pointer-lowtag) x - (make-wired-tn (primitive-type-or-lose 'unsigned-byte-32) - unsigned-reg-sc-number - (+ 1 (tn-offset y)))))))) -(define-move-vop move-to-double-int-reg - :move (double-reg descriptor-reg) (double-int-carg-reg)) - -(define-vop (move-double-int-reg) - (:args (x :target y :scs (double-int-carg-reg) :load-if nil) - (fp :scs (any-reg) :load-if (not (sc-is y double-int-carg-reg)))) - (:results (y :scs (double-int-carg-reg) :load-if nil)) - (:ignore fp) - (:generator 2 - (unless (location= x y) - (error "Huh? why did it do that?")))) -(define-move-vop move-double-int-reg :move-arg - (double-int-carg-reg) (double-int-carg-reg)) - -;;;; Arithmetic VOPs. - -(define-vop (float-op) - (:args (x) (y)) - (:results (r)) - (:variant-vars operation) - (:policy :fast-safe) - (:note "inline float arithmetic") - (:vop-var vop) - (:save-p :compute-only) - (:generator 0 - (note-this-location vop :internal-error) - (inst fbinop operation x y r))) - -(macrolet ((frob (name sc zero-sc ptype) - `(define-vop (,name float-op) - (:args (x :scs (,sc ,zero-sc)) - (y :scs (,sc ,zero-sc))) - (:results (r :scs (,sc))) - (:arg-types ,ptype ,ptype) - (:result-types ,ptype)))) - (frob single-float-op single-reg fp-single-zero single-float) - (frob double-float-op double-reg fp-double-zero double-float)) - -(macrolet ((frob (translate op sname scost dname dcost) - `(progn - (define-vop (,sname single-float-op) - (:translate ,translate) - (:variant ,op) - (:variant-cost ,scost)) - (define-vop (,dname double-float-op) - (:translate ,translate) - (:variant ,op) - (:variant-cost ,dcost))))) - (frob + :add +/single-float 2 +/double-float 2) - (frob - :sub -/single-float 2 -/double-float 2) - (frob * :mpy */single-float 4 */double-float 5) - (frob / :div //single-float 12 //double-float 19)) - -(macrolet ((frob (name translate sc type inst) - `(define-vop (,name) - (:args (x :scs (,sc))) - (:results (y :scs (,sc))) - (:translate ,translate) - (:policy :fast-safe) - (:arg-types ,type) - (:result-types ,type) - (:note "inline float arithmetic") - (:vop-var vop) - (:save-p :compute-only) - (:generator 1 - (note-this-location vop :internal-error) - ,inst)))) - (frob abs/single-float abs single-reg single-float - (inst funop :abs x y)) - (frob abs/double-float abs double-reg double-float - (inst funop :abs x y))) - -(macrolet ((frob (name translate sc type zero-tn) - `(define-vop (,name) - (:args (x :scs (,sc))) - (:results (y :scs (,sc))) - (:temporary (:scs (,sc)) float-temp) - (:temporary (:scs (signed-reg)) reg-temp) - (:temporary (:scs (signed-stack)) stack-temp) - (:translate ,translate) - (:policy :fast-safe) - (:arg-types ,type) - (:result-types ,type) - (:note "inline float arithmetic") - (:vop-var vop) - (:save-p :compute-only) - (:generator 1 - (note-this-location vop :internal-error) - ;; KLUDGE: Subtracting the input from zero fails to - ;; produce negative zero from positive zero. - ;; Multiplying by -1 causes overflow conditions on - ;; some inputs. The FNEG instruction is available - ;; in PA-RISC 2.0 only, and we're supposed to be - ;; PA-RISC 1.1 compatible. To do the negation as an - ;; integer operation requires writing out the value - ;; (or its high bits) to memory, reading them up - ;; into a non-descriptor-reg, flipping the sign bit - ;; (most likely requiring another unsigned-reg to - ;; hold a constant to XOR with), then getting the - ;; result back to the FPU via memory again. So - ;; instead we test for zeroness explicitly and - ;; decide which of the two FPU-based strategies to - ;; use. I feel unclean for having implemented this, - ;; but it seems to be the least dreadful option. - ;; Help? -- AB, 2015-11-26 - (inst fcmp #b00111 x ,zero-tn) - (inst ftest) - (inst b SUBTRACT-FROM-ZERO :nullify t) - - MULTIPLY-BY-NEGATIVE-ONE - (let ((nfp (current-nfp-tn vop)) - (short-float-temp (make-random-tn :kind :normal - :sc (sc-or-lose 'single-reg) - :offset (tn-offset reg-temp)))) - (inst li -1 reg-temp) - (storew reg-temp nfp (tn-offset stack-temp)) - (ld-float (tn-byte-offset stack-temp) nfp short-float-temp) - (inst fcnvxf short-float-temp float-temp) - (inst fbinop :mpy x float-temp y)) - (inst b DONE :nullify t) - - SUBTRACT-FROM-ZERO - (inst fbinop :sub ,zero-tn x y) - - DONE)))) - (frob %negate/single-float %negate single-reg single-float fp-single-zero-tn) - (frob %negate/double-float %negate double-reg double-float fp-double-zero-tn)) - -;;;; Comparison: - -(define-vop (float-compare) - (:args (x) (y)) - (:conditional) - (:info target not-p) - (:variant-vars condition complement) - (:policy :fast-safe) - (:note "inline float comparison") - (:vop-var vop) - (:save-p :compute-only) - (:generator 3 - (note-this-location vop :internal-error) - ;; This is the condition to nullify the branch, so it is inverted. - (inst fcmp (if not-p condition complement) x y) - (inst ftest) - (inst b target :nullify t))) - -(macrolet ((frob (name sc zero-sc ptype) - `(define-vop (,name float-compare) - (:args (x :scs (,sc ,zero-sc)) - (y :scs (,sc ,zero-sc))) - (:arg-types ,ptype ,ptype)))) - (frob single-float-compare single-reg fp-single-zero single-float) - (frob double-float-compare double-reg fp-double-zero double-float)) - -(macrolet ((frob (translate condition complement sname dname) - `(progn - (define-vop (,sname single-float-compare) - (:translate ,translate) - (:variant ,condition ,complement)) - (define-vop (,dname double-float-compare) - (:translate ,translate) - (:variant ,condition ,complement))))) - ;; FIXME-lav: let 'inst cmp' translate keywords into raw binary instead of giving it here - (frob < #b01001 #b10101 </single-float </double-float) - (frob > #b10001 #b01101 >/single-float >/double-float) - (frob = #b00101 #b11001 =/single-float =/double-float)) - - -;;;; Conversion: - -(macrolet ((frob (name translate from-sc from-type to-sc to-type) - `(define-vop (,name) - (:args (x :scs (,from-sc))) - (:results (y :scs (,to-sc))) - (:arg-types ,from-type) - (:result-types ,to-type) - (:policy :fast-safe) - (:note "inline float coercion") - (:translate ,translate) - (:vop-var vop) - (:save-p :compute-only) - (:generator 2 - (note-this-location vop :internal-error) - (inst fcnvff x y))))) - (frob %single-float/double-float %single-float - double-reg double-float - single-reg single-float) - (frob %double-float/single-float %double-float - single-reg single-float - double-reg double-float)) - -; convert register-integer to registersingle/double by -; putting it on single-float-stack and then float-loading it into -; an float register, and finally convert the float-register and -; storing the result into y -(macrolet ((frob (name translate to-sc to-type) - `(define-vop (,name) - (:args (x :scs (signed-reg) - :load-if (not (sc-is x signed-stack)) - :target stack-temp)) - (:arg-types signed-num) - (:results (y :scs (,to-sc))) - (:result-types ,to-type) - (:policy :fast-safe) - (:note "inline float coercion") - (:translate ,translate) - (:vop-var vop) - (:save-p :compute-only) - (:temporary (:scs (signed-stack) :from (:argument 0)) - stack-temp) - (:temporary (:scs (single-reg) :to (:result 0) :target y) - fp-temp) - (:temporary (:scs (any-reg) :from (:argument 0) - :to (:result 0)) index) - (:generator 5 - (let* ((nfp (current-nfp-tn vop)) - (stack-tn - (sc-case x - (signed-stack - x) - (signed-reg - (storew x nfp (tn-offset stack-temp)) - stack-temp))) - (offset (tn-byte-offset stack-tn))) - (cond ((< offset (ash 1 4)) - (inst flds offset nfp fp-temp)) - ((and (< offset (ash 1 13)) - (> offset 0)) - (inst ldo offset zero-tn index) - (inst fldx index nfp fp-temp)) - (t - (error "in vop ~s offset ~s is out-of-range" ',name offset))) - (note-this-location vop :internal-error) - (inst fcnvxf fp-temp y)))))) - (frob %single-float/signed %single-float - single-reg single-float) - (frob %double-float/signed %double-float - double-reg double-float)) - -(macrolet ((frob (trans from-sc from-type inst note) - `(define-vop (,(symbolicate trans "/" from-type)) - (:args (x :scs (,from-sc) - :target fp-temp)) - (:results (y :scs (signed-reg) - :load-if (not (sc-is y signed-stack)))) - (:arg-types ,from-type) - (:result-types signed-num) - (:translate ,trans) - (:policy :fast-safe) - (:note ,note) - (:vop-var vop) - (:save-p :compute-only) - (:temporary (:scs (single-reg) :from (:argument 0)) fp-temp) - (:temporary (:scs (signed-stack) :to (:result 0) :target y) - stack-temp) - (:temporary (:scs (any-reg) :from (:argument 0) - :to (:result 0)) index) - (:generator 3 - (let* ((nfp (current-nfp-tn vop)) - (stack-tn - (sc-case y - (signed-stack y) - (signed-reg stack-temp))) - (offset (tn-byte-offset stack-tn))) - (inst ,inst x fp-temp) - (cond ((< offset (ash 1 4)) - (note-next-instruction vop :internal-error) - (inst fsts fp-temp offset nfp)) - ((and (< offset (ash 1 13)) - (> offset 0)) - (inst ldo offset zero-tn index) - (note-next-instruction vop :internal-error) - (inst fstx fp-temp index nfp)) - (t - (error "unary error, ldo offset too high"))) - (unless (eq y stack-tn) - (loadw y nfp (tn-offset stack-tn)))))))) - (frob %unary-round single-reg single-float fcnvfx "inline float round") - (frob %unary-round double-reg double-float fcnvfx "inline float round") - (frob %unary-truncate/single-float single-reg single-float fcnvfxt - "inline float truncate") - (frob %unary-truncate/double-float double-reg double-float fcnvfxt - "inline float truncate")) - -(define-vop (make-single-float) - (:args (bits :scs (signed-reg) - :load-if (or (not (sc-is bits signed-stack)) - (sc-is res single-stack)) - :target res)) - (:results (res :scs (single-reg) - :load-if (not (sc-is bits single-stack)))) - (:arg-types signed-num) - (:result-types single-float) - (:translate make-single-float) - (:policy :fast-safe) - (:vop-var vop) - (:temporary (:scs (single-stack) :from (:argument 0) :to (:result 0)) temp) - (:temporary (:scs (any-reg) :from (:argument 0) :to (:result 0)) index) - (:generator 2 - (let ((nfp (current-nfp-tn vop))) - (sc-case bits - (signed-reg - (sc-case res - (single-reg - (let ((offset (tn-byte-offset temp))) - (inst stw bits offset nfp) - (cond ((< offset (ash 1 4)) - (inst flds offset nfp res)) - ((and (< offset (ash 1 13)) - (> offset 0)) - (inst ldo offset zero-tn index) - (inst fldx index nfp res)) - (t - (error "make-single-float error, ldo offset too large"))))) - (single-stack - (inst stw bits (tn-byte-offset res) nfp)))) - (signed-stack - (sc-case res - (single-reg - (let ((offset (tn-byte-offset bits))) - (cond ((< offset (ash 1 4)) - (inst flds offset nfp res)) - ((and (< offset (ash 1 13)) - (> offset 0)) - (inst ldo offset zero-tn index) - (inst fldx index nfp res)) - (t - (error "make-single-float error, ldo offset too large"))))))))))) - -(define-vop (make-double-float) - (:args (hi-bits :scs (signed-reg)) - (lo-bits :scs (unsigned-reg))) - (:results (res :scs (double-reg) - :load-if (not (sc-is res double-stack)))) - (:arg-types signed-num unsigned-num) - (:result-types double-float) - (:translate make-double-float) - (:policy :fast-safe) - (:temporary (:scs (double-stack) :to (:result 0)) temp) - (:temporary (:scs (any-reg) :from (:argument 0) :to (:result 0)) index) - (:vop-var vop) - (:generator 2 - (let* ((nfp (current-nfp-tn vop)) - (stack-tn (sc-case res - (double-stack res) - (double-reg temp))) - (offset (tn-byte-offset stack-tn))) - (inst stw hi-bits offset nfp) - (inst stw lo-bits (+ offset n-word-bytes) nfp) - (cond ((eq stack-tn res)) - ((< offset (ash 1 4)) - (inst flds offset nfp res)) - ((and (< offset (ash 1 13)) - (> offset 0)) - (inst ldo offset zero-tn index) - (inst fldx index nfp res)) - (t - (error "make-single-float error, ldo offset too large")))))) - -(macrolet - ((float-bits (name reg rreg stack rstack atype anum side offset) - `(define-vop (,name) - (:args (float :scs (,reg) - :load-if (not (sc-is float ,stack)))) - (:results (bits :scs (,rreg) - :load-if (or (not (sc-is bits ,rstack)) - (sc-is float ,stack)))) - (:arg-types ,atype) - (:result-types ,anum) - (:translate ,name) - (:policy :fast-safe) - (:vop-var vop) - (:temporary (:scs (signed-stack) :from (:argument 0) :to (:result 0)) temp) - (:temporary (:scs (any-reg) :from (:argument 0) :to (:result 0)) index) - (:generator 2 - (let ((nfp (current-nfp-tn vop))) - (sc-case float - (,reg - (sc-case bits - (,rreg - (let ((offset (tn-byte-offset temp))) - (cond ((< offset (ash 1 4)) - ,@(if side - `((inst fsts float offset nfp :side ,side)) - `((inst fsts float offset nfp)))) - ((and (< offset (ash 1 13)) - (> offset 0)) - (inst ldo offset zero-tn index) - ,@(if side - `((inst fstx float index nfp :side ,side)) - `((inst fstx float index nfp)))) - (t - (error ,(format nil "~s,~s: inst-LDO offset too large" - name rreg)))) - (inst ldw offset nfp bits))) - (,rstack - (let ((offset (tn-byte-offset bits))) - (cond ((< offset (ash 1 4)) - ,@(if side - `((inst fsts float offset nfp :side ,side)) - `((inst fsts float offset nfp)))) - ((and (< offset (ash 1 13)) - (> offset 0)) - (inst ldo offset zero-tn index) - ,@(if side - `((inst fstx float index nfp :side ,side)) - `((inst fstx float index nfp)))) - (t - (error ,(format nil "~s,~s: inst-LDO offset too large" - name rstack)))))))) - (,stack - (sc-case bits - (,rreg - (inst ldw (* (+ (tn-offset float) ,offset) n-word-bytes) - nfp bits)))))))))) - (float-bits single-float-bits single-reg signed-reg single-stack - signed-stack single-float signed-num nil 0) - (float-bits double-float-high-bits double-reg signed-reg - double-stack signed-stack double-float signed-num 0 0) - (float-bits double-float-low-bits double-reg unsigned-reg - double-stack unsigned-stack double-float unsigned-num 1 1)) - -;;;; Float mode hackery: - -(sb-xc:deftype float-modes () '(unsigned-byte 32)) -(defknown floating-point-modes () float-modes (flushable)) -(defknown ((setf floating-point-modes)) (float-modes) - float-modes) - -(define-vop (floating-point-modes) - (:results (res :scs (unsigned-reg))) - (:result-types unsigned-num) - (:translate floating-point-modes) - (:policy :fast-safe) - (:temporary (:scs (double-stack)) temp) - (:temporary (:scs (any-reg) :to (:result 0)) index) - (:vop-var vop) - (:generator 3 - (let* ((nfp (current-nfp-tn vop)) - (stack-tn (sc-case res - (unsigned-stack res) - (unsigned-reg temp))) - (offset (tn-byte-offset stack-tn))) - (cond ((< offset (ash 1 4)) - (inst fsts fp-double-zero-tn offset nfp)) - ((and (< offset (ash 1 13)) - (> offset 0)) - (inst ldo offset zero-tn index) - (inst fstx fp-double-zero-tn index nfp)) - (t - (error "floating-point-modes error, ldo offset too large"))) - (ecase *backend-byte-order* - (:big-endian - (inst ldw offset nfp res)) - (:little-endian - (inst ldw (+ offset 4) nfp res)))))) - -(define-vop (set-floating-point-modes) - (:args (new :scs (unsigned-reg) :target res)) - (:results (res :scs (unsigned-reg))) - (:arg-types unsigned-num) - (:result-types unsigned-num) - (:translate (setf floating-point-modes)) - (:policy :fast-safe) - (:temporary (:scs (double-stack)) stack-tn) - (:temporary (:scs (any-reg)) index) - (:vop-var vop) - (:generator 3 - (let* ((nfp (current-nfp-tn vop)) - (offset (tn-byte-offset stack-tn))) - (ecase *backend-byte-order* - (:big-endian - (inst stw new offset nfp) - (inst stw zero-tn (+ offset 4) nfp)) - (:little-endian - (inst stw zero-tn offset nfp) - (inst stw new (+ offset 4) nfp))) - (cond ((< offset (ash 1 4)) - (inst flds offset nfp fp-double-zero-tn)) - ((and (< offset (ash 1 13)) - (> offset 0)) - (inst ldo offset zero-tn index) - (inst fldx index nfp fp-double-zero-tn)) - (t - (error "set-floating-point-modes error, ldo offset too large"))) - (move new res)))) - -;;;; Complex float VOPs - -(define-vop (make-complex-single-float) - (:translate complex) - (:args (real :scs (single-reg) :target r) - (imag :scs (single-reg) :to :save)) - (:arg-types single-float single-float) - (:results (r :scs (complex-single-reg) :from (:argument 0) - :load-if (not (sc-is r complex-single-stack)))) - (:result-types complex-single-float) - (:note "inline complex single-float creation") - (:policy :fast-safe) - (:vop-var vop) - (:generator 5 - (sc-case r - (complex-single-reg - (let ((r-real (complex-single-reg-real-tn r))) - (unless (location= real r-real) - (inst funop :copy real r-real))) - (let ((r-imag (complex-single-reg-imag-tn r))) - (unless (location= imag r-imag) - (inst funop :copy imag r-imag)))) - (complex-single-stack - (let ((nfp (current-nfp-tn vop)) - (offset (tn-byte-offset r))) - (str-float real offset nfp) - (str-float imag (+ offset n-word-bytes) nfp)))))) - -(define-vop (make-complex-double-float) - (:translate complex) - (:args (real :scs (double-reg) :target r) - (imag :scs (double-reg) :to :save)) - (:arg-types double-float double-float) - (:results (r :scs (complex-double-reg) :from (:argument 0) - :load-if (not (sc-is r complex-double-stack)))) - (:result-types complex-double-float) - (:note "inline complex double-float creation") - (:policy :fast-safe) - (:vop-var vop) - (:generator 5 - (sc-case r - (complex-double-reg - (let ((r-real (complex-double-reg-real-tn r))) - (unless (location= real r-real) - (inst funop :copy real r-real))) - (let ((r-imag (complex-double-reg-imag-tn r))) - (unless (location= imag r-imag) - (inst funop :copy imag r-imag)))) - (complex-double-stack - (let ((nfp (current-nfp-tn vop)) - (offset (tn-byte-offset r))) - (str-float real offset nfp) - (str-float imag (+ offset (* 2 n-word-bytes)) nfp)))))) - -(define-vop (complex-single-float-value) - (:args (x :scs (complex-single-reg) :target r - :load-if (not (sc-is x complex-single-stack)))) - (:arg-types complex-single-float) - (:results (r :scs (single-reg))) - (:result-types single-float) - (:variant-vars slot) - (:policy :fast-safe) - (:vop-var vop) - (:generator 3 - (sc-case x - (complex-single-reg - (let ((value-tn (ecase slot - (:real (complex-single-reg-real-tn x)) - (:imag (complex-single-reg-imag-tn x))))) - (unless (location= value-tn r) - (inst funop :copy value-tn r)))) - (complex-single-stack - (ld-float (* (+ (ecase slot (:real 0) (:imag 1)) (tn-offset x)) - n-word-bytes) - (current-nfp-tn vop) r))))) - -(define-vop (realpart/complex-single-float complex-single-float-value) - (:translate realpart) - (:note "complex single float realpart") - (:variant :real)) - -(define-vop (imagpart/complex-single-float complex-single-float-value) - (:translate imagpart) - (:note "complex single float imagpart") - (:variant :imag)) - -(define-vop (complex-double-float-value) - (:args (x :scs (complex-double-reg) :target r - :load-if (not (sc-is x complex-double-stack)))) - (:arg-types complex-double-float) - (:results (r :scs (double-reg))) - (:result-types double-float) - (:variant-vars slot) - (:policy :fast-safe) - (:vop-var vop) - (:generator 3 - (sc-case x - (complex-double-reg - (let ((value-tn (ecase slot - (:real (complex-double-reg-real-tn x)) - (:imag (complex-double-reg-imag-tn x))))) - (unless (location= value-tn r) - (inst funop :copy value-tn r)))) - (complex-double-stack - (ld-float (* (+ (ecase slot (:real 0) (:imag 2)) (tn-offset x)) - n-word-bytes) - (current-nfp-tn vop) r))))) - -(define-vop (realpart/complex-double-float complex-double-float-value) - (:translate realpart) - (:note "complex double float realpart") - (:variant :real)) - -(define-vop (imagpart/complex-double-float complex-double-float-value) - (:translate imagpart) - (:note "complex double float imagpart") - (:variant :imag)) diff --git a/src/compiler/hppa/insts.lisp b/src/compiler/hppa/insts.lisp deleted file mode 100644 index 3aed626f39..0000000000 --- a/src/compiler/hppa/insts.lisp +++ /dev/null @@ -1,1629 +0,0 @@ -;;;; the instruction set definition for HPPA - -;;;; This software is part of the SBCL system. See the README file for -;;;; more information. -;;;; -;;;; This software is derived from the CMU CL system, which was -;;;; written at Carnegie Mellon University and released into the -;;;; public domain. The software is in the public domain and is -;;;; provided with absolutely no warranty. See the COPYING and CREDITS -;;;; files for more information. - -(in-package "SB-HPPA-ASM") - -(eval-when (:compile-toplevel :load-toplevel :execute) - ;; Imports from this package into SB-VM - (import '(reg-tn-encoding) "SB-VM") - ;; Imports from SB-VM into this package - (import '(sb-vm::zero sb-vm::registers sb-vm::float-registers - sb-vm::single-reg sb-vm::double-reg - sb-vm::complex-single-reg sb-vm::complex-double-reg - sb-vm::fp-single-zero sb-vm::fp-double-zero - sb-vm::zero-tn - sb-vm::null-offset sb-vm::code-offset sb-vm::zero-offset))) - - -;;;; Utility functions. - -(defun reg-tn-encoding (tn) - (declare (type tn tn)) - (sc-case tn - (null null-offset) - (zero zero-offset) - (t - (aver (eq (sb-name (sc-sb (tn-sc tn))) 'registers)) - (tn-offset tn)))) - -(defun fp-reg-tn-encoding (tn) - (declare (type tn tn)) - (sc-case tn - (fp-single-zero (values 0 nil)) - (single-reg (values (tn-offset tn) nil)) - (fp-double-zero (values 0 t)) - (double-reg (values (tn-offset tn) t)) - (complex-single-reg (values (tn-offset tn) nil)) - (complex-double-reg (values (tn-offset tn) t)))) - -(defconstant-eqx compare-conditions - '(:never := :< :<= :<< :<<= :sv :od :tr :<> :>= :> :>>= :>> :nsv :ev) - #'equalp) - -(deftype compare-condition () - `(member nil ,@compare-conditions)) - -(defun compare-condition (cond) - (declare (type compare-condition cond)) - (if cond - (let ((result (or (position cond compare-conditions :test #'eq) - (error "Bogus Compare/Subtract condition: ~S" cond)))) - (values (ldb (byte 3 0) result) - (logbitp 3 result))) - (values 0 nil))) - -(defconstant-eqx add-conditions - '(:never := :< :<= :nuv :znv :sv :od :tr :<> :>= :> :uv :vnz :nsv :ev) - #'equalp) - -(deftype add-condition () - `(member nil ,@add-conditions)) - -(defun add-condition (cond) - (declare (type add-condition cond)) - (if cond - (let ((result (or (position cond add-conditions :test #'eq) - (error "Bogus Add condition: ~S" cond)))) - (values (ldb (byte 3 0) result) - (logbitp 3 result))) - (values 0 nil))) - -(defconstant-eqx logical-conditions - '(:never := :< :<= nil nil nil :od :tr :<> :>= :> nil nil nil :ev) - #'equalp) - -(deftype logical-condition () - `(member nil ,@(remove nil logical-conditions))) - -(defun logical-condition (cond) - (declare (type logical-condition cond)) - (if cond - (let ((result (or (position cond logical-conditions :test #'eq) - (error "Bogus Logical condition: ~S" cond)))) - (values (ldb (byte 3 0) result) - (logbitp 3 result))) - (values 0 nil))) - -(defconstant-eqx unit-conditions - '(:never nil :sbz :shz :sdc :sbc :shc :tr nil :nbz :nhz :ndc :nbc :nhc) - #'equalp) - -(deftype unit-condition () - `(member nil ,@(remove nil unit-conditions))) - -(defun unit-condition (cond) - (declare (type unit-condition cond)) - (if cond - (let ((result (or (position cond unit-conditions :test #'eq) - (error "Bogus Unit condition: ~S" cond)))) - (values (ldb (byte 3 0) result) - (logbitp 3 result))) - (values 0 nil))) - -(defconstant-eqx extract/deposit-conditions - '(:never := :< :od :tr :<> :>= :ev) - #'equalp) - -(deftype extract/deposit-condition () - `(member nil ,@extract/deposit-conditions)) - -(defun extract/deposit-condition (cond) - (declare (type extract/deposit-condition cond)) - (if cond - (or (position cond extract/deposit-conditions :test #'eq) - (error "Bogus Extract/Deposit condition: ~S" cond)) - 0)) - - -(defun space-encoding (space) - (declare (type (unsigned-byte 3) space)) - (dpb (ldb (byte 2 0) space) - (byte 2 1) - (ldb (byte 1 2) space))) - - -;;;; Initial disassembler setup. - -(defvar *disassem-use-lisp-reg-names* t) - -; In each define-instruction the form (:dependencies ...) -; contains read and write howto that passed as LOC here. -; Example: (:dependencies (reads src) (writes dst) (writes temp)) -; src, dst and temp is passed each in loc, and can be a register -; immediate or anything else. -; this routine will return an location-number -; this number must be less than +assem-max-locations+ -(defun location-number (loc) - (etypecase loc - (null) - (number) - (label) - (fixup) - (tn - (ecase (sb-name (sc-sb (tn-sc loc))) - (immediate-constant - ;; Can happen if $ZERO or $NULL are passed in. - nil) - (registers - (unless (zerop (tn-offset loc)) - (tn-offset loc))))) - (symbol - (ecase loc - (:memory 0))))) - -(defparameter reg-symbols - (map 'vector - (lambda (name) - (cond ((null name) nil) - (t (make-symbol (concatenate 'string "$" name))))) - sb-vm::*register-names*)) - -(define-arg-type reg - :printer (lambda (value stream dstate) - (declare (stream stream) (fixnum value)) - (let ((regname (aref reg-symbols value))) - (princ regname stream) - (maybe-note-associated-storage-ref - value - 'registers - regname - dstate)))) - -(defparameter float-reg-symbols - #.(coerce - (loop for n from 0 to 31 collect (make-symbol (format nil "$F~d" n))) - 'vector)) - -(define-arg-type fp-reg - :printer (lambda (value stream dstate) - (declare (stream stream) (fixnum value)) - (let ((regname (aref float-reg-symbols value))) - (princ regname stream) - (maybe-note-associated-storage-ref - value - 'float-registers - regname - dstate)))) - -(define-arg-type fp-fmt-0c - :printer (lambda (value stream dstate) - (declare (ignore dstate) (stream stream) (fixnum value)) - (ecase value - (0 (format stream "~A" '\,SGL)) - (1 (format stream "~A" '\,DBL)) - (3 (format stream "~A" '\,QUAD))))) - -(defun low-sign-extend (x n) - (let ((normal (dpb x (byte 1 (1- n)) (ldb (byte (1- n) 1) x)))) - (if (logbitp 0 x) - (logior (ash -1 (1- n)) normal) - normal))) - -(defun assemble-bits (x list) - (let ((result 0) - (offset 0)) - (dolist (e (reverse list)) - (setf result (logior result (ash (ldb e x) offset))) - (incf offset (byte-size e))) - result)) - -(macrolet ((define-imx-decode (name bits) - `(define-arg-type ,name - :printer (lambda (value stream dstate) - (declare (ignore dstate) (stream stream) (fixnum value)) - (format stream "~S" (low-sign-extend value ,bits)))))) - (define-imx-decode im5 5) - (define-imx-decode im11 11) - (define-imx-decode im14 14)) - -(define-arg-type im3 - :printer (lambda (value stream dstate) - (declare (ignore dstate) (stream stream) (fixnum value)) - (format stream "~S" (assemble-bits value `(,(byte 1 0) - ,(byte 2 1)))))) - -(define-arg-type im21 - :printer (lambda (value stream dstate) - (declare (ignore dstate) (stream stream) (fixnum value)) - (format stream "~S" - (assemble-bits value `(,(byte 1 0) ,(byte 11 1) - ,(byte 2 14) ,(byte 5 16) - ,(byte 2 12)))))) - -(define-arg-type cp - :printer (lambda (value stream dstate) - (declare (ignore dstate) (stream stream) (fixnum value)) - (format stream "~S" (- 31 value)))) - -(define-arg-type clen - :printer (lambda (value stream dstate) - (declare (ignore dstate) (stream stream) (fixnum value)) - (format stream "~S" (- 32 value)))) - -(define-arg-type compare-condition - :printer #("" \,= \,< \,<= \,<< \,<<= \,SV \,OD \,TR \,<> \,>= - \,> \,>>= \,>> \,NSV \,EV)) - -(define-arg-type compare-condition-false - :printer #(\,TR \,<> \,>= \,> \,>>= \,>> \,NSV \,EV - "" \,= \,< \,<= \,<< \,<<= \,SV \,OD)) - -(define-arg-type add-condition - :printer #("" \,= \,< \,<= \,NUV \,ZNV \,SV \,OD \,TR \,<> \,>= \,> \,UV - \,VNZ \,NSV \,EV)) - -(define-arg-type add-condition-false - :printer #(\,TR \,<> \,>= \,> \,UV \,VNZ \,NSV \,EV - "" \,= \,< \,<= \,NUV \,ZNV \,SV \,OD)) - -(define-arg-type logical-condition - :printer #("" \,= \,< \,<= "" "" "" \,OD \,TR \,<> \,>= \,> "" "" "" \,EV)) - -(define-arg-type unit-condition - :printer #("" "" \,SBZ \,SHZ \,SDC \,SBC \,SHC \,TR "" \,NBZ \,NHZ \,NDC - \,NBC \,NHC)) - -(define-arg-type extract/deposit-condition - :printer #("" \,= \,< \,OD \,TR \,<> \,>= \,EV)) - -(define-arg-type extract/deposit-condition-false - :printer #(\,TR \,<> \,>= \,EV "" \,= \,< \,OD)) - -(define-arg-type nullify - :printer #("" \,N)) - -(define-arg-type fcmp-cond - :printer #(\FALSE? \FALSE \? \!<=> \= \=T \?= \!<> \!?>= \< \?< - \!>= \!?> \<= \?<= \!> \!?<= \> \?>\ \!<= \!?< \>= - \?>= \!< \!?= \<> \!= \!=T \!? \<=> \TRUE? \TRUE)) - -(define-arg-type integer - :printer (lambda (value stream dstate) - (declare (ignore dstate) (stream stream) (fixnum value)) - (format stream "~S" value))) - -(define-arg-type space - :printer #("" |1,| |2,| |3,|)) - -(define-arg-type memory-address-annotation - :printer (lambda (value stream dstate) - (declare (ignore stream)) - (destructuring-bind (reg raw-offset) value - (let ((offset (low-sign-extend raw-offset 14))) - (cond - ((= reg code-offset) - (note-code-constant offset dstate)) - ((= reg null-offset) - (maybe-note-nil-indexed-object offset dstate))))))) - - -;;;; Define-instruction-formats for disassembler. - -(define-instruction-format (load/store 32) - (op :field (byte 6 26)) - (b :field (byte 5 21) :type 'reg) - (t/r :field (byte 5 16) :type 'reg) - (s :field (byte 2 14) :type 'space) - (im14 :field (byte 14 0) :type 'im14) - (memory-address-annotation :fields (list (byte 5 21) (byte 14 0)) - :type 'memory-address-annotation)) - -(defconstant-eqx cmplt-index-print '((:cond ((u :constant 1) '\,S)) - (:cond ((m :constant 1) '\,M))) - #'equalp) - -(defconstant-eqx cmplt-disp-print '((:cond ((m :constant 1) - (:cond ((s :constant 0) '\,MA) - (t '\,MB))))) - #'equalp) - -(defconstant-eqx cmplt-store-print '((:cond ((s :constant 0) '\,B) - (t '\,E)) - (:cond ((m :constant 1) '\,M))) - #'equalp) - -(define-instruction-format (extended-load/store 32) - (op1 :field (byte 6 26) :value 3) - (b :field (byte 5 21) :type 'reg) - (x/im5/r :field (byte 5 16) :type 'reg) - (s :field (byte 2 14) :type 'space) - (u :field (byte 1 13)) - (op2 :field (byte 3 10)) - (ext4/c :field (byte 4 6)) - (m :field (byte 1 5)) - (t/im5 :field (byte 5 0) :type 'reg)) - -(define-instruction-format (ldil 32 :default-printer '(:name :tab im21 "," t)) - (op :field (byte 6 26)) - (t :field (byte 5 21) :type 'reg) - (im21 :field (byte 21 0) :type 'im21)) - -(define-instruction-format (branch17 32) - (op1 :field (byte 6 26)) - (t :field (byte 5 21) :type 'reg) - (w :fields `(,(byte 5 16) ,(byte 11 2) ,(byte 1 0)) - :use-label - (lambda (value dstate) - (declare (type disassem-state dstate) (list value)) - (let ((x (logior (ash (first value) 12) (ash (second value) 1) - (third value)))) - (+ (ash (sign-extend - (assemble-bits x `(,(byte 1 0) ,(byte 5 12) ,(byte 1 1) - ,(byte 10 2))) 17) 2) - (dstate-cur-addr dstate) 8)))) - (op2 :field (byte 3 13)) - (n :field (byte 1 1) :type 'nullify)) - -(define-instruction-format (branch12 32) - (op1 :field (byte 6 26)) - (r2 :field (byte 5 21) :type 'reg) - (r1 :field (byte 5 16) :type 'reg) - (w :fields `(,(byte 11 2) ,(byte 1 0)) - :use-label - (lambda (value dstate) - (declare (type disassem-state dstate) (list value)) - (let ((x (logior (ash (first value) 1) (second value)))) - (+ (ash (sign-extend - (assemble-bits x `(,(byte 1 0) ,(byte 1 1) ,(byte 10 2))) - 12) 2) - (dstate-cur-addr dstate) 8)))) - (c :field (byte 3 13)) - (n :field (byte 1 1) :type 'nullify)) - -(define-instruction-format (branch 32) - (op1 :field (byte 6 26)) - (t :field (byte 5 21) :type 'reg) - (x :field (byte 5 16) :type 'reg) - (op2 :field (byte 3 13)) - (x1 :field (byte 11 2)) - (n :field (byte 1 1) :type 'nullify) - (x2 :field (byte 1 0))) - -(define-instruction-format (r3-inst 32 - :default-printer '(:name c :tab r1 "," r2 "," t)) - (r3 :field (byte 6 26) :value 2) - (r2 :field (byte 5 21) :type 'reg) - (r1 :field (byte 5 16) :type 'reg) - (c :field (byte 3 13)) - (f :field (byte 1 12)) - (op :field (byte 7 5)) - (t :field (byte 5 0) :type 'reg)) - -(define-instruction-format (imm-inst 32 - :default-printer '(:name c :tab im11 "," r "," t)) - (op :field (byte 6 26)) - (r :field (byte 5 21) :type 'reg) - (t :field (byte 5 16) :type 'reg) - (c :field (byte 3 13)) - (f :field (byte 1 12)) - (o :field (byte 1 11)) - (im11 :field (byte 11 0) :type 'im11)) - -(define-instruction-format (extract/deposit-inst 32) - (op1 :field (byte 6 26)) - (r2 :field (byte 5 21) :type 'reg) - (r1 :field (byte 5 16) :type 'reg) - (c :field (byte 3 13) :type 'extract/deposit-condition) - (op2 :field (byte 3 10)) - (cp :field (byte 5 5) :type 'cp) - (t/clen :field (byte 5 0) :type 'clen)) - -(define-instruction-format (break 32 - :default-printer '(:name :tab im13 "," im5)) - (op1 :field (byte 6 26) :value 0) - (im13 :field (byte 13 13)) - (q2 :field (byte 8 5) :value 0) - (im5 :field (byte 5 0) :reader break-im5)) - -(define-instruction-format (system-inst 32) - (op1 :field (byte 6 26) :value 0) - (r1 :field (byte 5 21) :type 'reg) - (r2 :field (byte 5 16) :type 'reg) - (s :field (byte 3 13)) - (op2 :field (byte 8 5)) - (r3 :field (byte 5 0) :type 'reg)) - -(define-instruction-format (fp-load/store 32) - (op :field (byte 6 26)) - (b :field (byte 5 21) :type 'reg) - (x :field (byte 5 16) :type 'reg) - (s :field (byte 2 14) :type 'space) - (u :field (byte 1 13)) - (x1 :field (byte 1 12)) - (x2 :field (byte 2 10)) - (x3 :field (byte 1 9)) - (x4 :field (byte 3 6)) - (m :field (byte 1 5)) - (t :field (byte 5 0) :type 'fp-reg)) - -(define-instruction-format (fp-class-0-inst 32) - (op1 :field (byte 6 26)) - (r :field (byte 5 21) :type 'fp-reg) - (x1 :field (byte 5 16) :type 'fp-reg) - (op2 :field (byte 3 13)) - (fmt :field (byte 2 11) :type 'fp-fmt-0c) - (x2 :field (byte 2 9)) - (x3 :field (byte 3 6)) - (x4 :field (byte 1 5)) - (t :field (byte 5 0) :type 'fp-reg)) - -(define-instruction-format (fp-class-1-inst 32) - (op1 :field (byte 6 26)) - (r :field (byte 5 21) :type 'fp-reg) - (x1 :field (byte 4 17) :value 0) - (x2 :field (byte 2 15)) - (df :field (byte 2 13) :type 'fp-fmt-0c) - (sf :field (byte 2 11) :type 'fp-fmt-0c) - (x3 :field (byte 2 9) :value 1) - (x4 :field (byte 3 6) :value 0) - (x5 :field (byte 1 5) :value 0) - (t :field (byte 5 0) :type 'fp-reg)) - - - -;;;; Load and Store stuff. - -(define-bitfield-emitter emit-load/store 32 - (byte 6 26) - (byte 5 21) - (byte 5 16) - (byte 2 14) - (byte 14 0)) - -(defun encode-imm21 (segment value) - (declare (type (or fixup (signed-byte 32) (unsigned-byte 32)) value)) - (cond ((fixup-p value) - (note-fixup segment :hi value) - (aver (zerop (fixup-offset value))) - 0) - (t - (let ((hi (ldb (byte 21 11) value))) - (logior (ash (ldb (byte 5 2) hi) 16) - (ash (ldb (byte 2 7) hi) 14) - (ash (ldb (byte 2 0) hi) 12) - (ash (ldb (byte 11 9) hi) 1) - (ldb (byte 1 20) hi)))))) - -(defun encode-imm11 (value) - (declare (type (signed-byte 11) value)) - (dpb (ldb (byte 10 0) value) - (byte 10 1) - (ldb (byte 1 10) value))) - -(defun encode-imm11u (value) - (declare (type (or (signed-byte 32) (unsigned-byte 32)) value)) - (declare (type (unsigned-byte 11) value)) - (dpb (ldb (byte 11 0) value) - (byte 11 1) - 0)) - -(defun encode-imm14 (value) - (declare (type (signed-byte 14) value)) - (dpb (ldb (byte 13 0) value) - (byte 13 1) - (ldb (byte 1 13) value))) - -(defun encode-disp/fixup (segment disp imm-bits) - (cond - ((fixup-p disp) - (aver (zerop (fixup-offset disp))) - (if imm-bits - (note-fixup segment :load11u disp) - (note-fixup segment :load disp)) - 0) - (t - (if imm-bits - (encode-imm11u disp) - (encode-imm14 disp))))) - -; LDO can be used in two ways: to load an 14bit-signed value -; or load an 11bit-unsigned value. The latter is used for -; example in an LDIL/LDO pair. The key :unsigned specifies this. -(macrolet ((define-load-inst (name opcode &optional imm-bits) - (declare (ignore imm-bits)) ; what? - `(define-instruction ,name (segment disp base reg &key unsigned) - (:declare (type tn reg base) - (type (member t nil) unsigned) - (type (or fixup (signed-byte 14)) disp)) - (:delay 0) - (:printer load/store ((op ,opcode) (s 0)) - '(:name :tab im14 "(" s b ")," t/r memory-address-annotation)) - (:dependencies (reads base) (reads :memory) (writes reg)) - (:emitter - (emit-load/store segment ,opcode - (reg-tn-encoding base) (reg-tn-encoding reg) 0 - (if unsigned - (encode-disp/fixup segment disp t) - (encode-disp/fixup segment disp nil)))))) - (define-store-inst (name opcode &optional imm-bits) - `(define-instruction ,name (segment reg disp base) - (:declare (type tn reg base) - (type (or fixup (signed-byte 14)) disp)) - (:delay 0) - (:printer load/store ((op ,opcode) (s 0)) - '(:name :tab t/r "," im14 "(" s b ")" memory-address-annotation)) - (:dependencies (reads base) (reads reg) (writes :memory)) - (:emitter - (emit-load/store segment ,opcode - (reg-tn-encoding base) (reg-tn-encoding reg) 0 - (encode-disp/fixup segment disp ,imm-bits)))))) - (define-load-inst ldw #x12) - (define-load-inst ldh #x11) - (define-load-inst ldb #x10) - (define-load-inst ldwm #x13) - (define-load-inst ldo #x0D) - (define-store-inst stw #x1A) - (define-store-inst sth #x19) - (define-store-inst stb #x18) - (define-store-inst stwm #x1B)) - -(define-bitfield-emitter emit-extended-load/store 32 - (byte 6 26) (byte 5 21) (byte 5 16) (byte 2 14) (byte 1 13) - (byte 3 10) (byte 4 6) (byte 1 5) (byte 5 0)) - -(macrolet ((define-load-indexed-inst (name opcode) - `(define-instruction ,name (segment index base reg &key modify scale) - (:declare (type tn reg base index) - (type (member t nil) modify scale)) - (:delay 0) - (:dependencies (reads index) (reads base) (writes reg) (reads :memory)) - (:printer extended-load/store ((ext4/c ,opcode) (t/im5 nil :type 'reg) - (op2 0)) - `(:name ,@cmplt-index-print :tab x/im5/r - "(" s b ")" t/im5)) - (:emitter - (emit-extended-load/store - segment #x03 (reg-tn-encoding base) (reg-tn-encoding index) - 0 (if scale 1 0) 0 ,opcode (if modify 1 0) - (reg-tn-encoding reg)))))) - (define-load-indexed-inst ldwx 2) - (define-load-indexed-inst ldhx 1) - (define-load-indexed-inst ldbx 0) - (define-load-indexed-inst ldcwx 7)) - -(defun short-disp-encoding (segment disp) - (declare (type (or fixup (signed-byte 5)) disp)) - (cond ((fixup-p disp) - (note-fixup segment :load-short disp) - (aver (zerop (fixup-offset disp))) - 0) - (t - (dpb (ldb (byte 4 0) disp) - (byte 4 1) - (ldb (byte 1 4) disp))))) - -(macrolet ((define-load-short-inst (name opcode) - `(define-instruction ,name (segment base disp reg &key modify) - (:declare (type tn base reg) - (type (or fixup (signed-byte 5)) disp) - (type (member :before :after nil) modify)) - (:delay 0) - (:dependencies (reads base) (writes reg) (reads :memory)) - (:printer extended-load/store ((ext4/c ,opcode) (t/im5 nil :type 'im5) - (op2 4)) - `(:name ,@cmplt-disp-print :tab x/im5/r - "(" s b ")" t/im5)) - (:emitter - (multiple-value-bind - (m a) - (ecase modify - ((nil) (values 0 0)) - (:after (values 1 0)) - (:before (values 1 1))) - (emit-extended-load/store segment #x03 (reg-tn-encoding base) - (short-disp-encoding segment disp) - 0 a 4 ,opcode m - (reg-tn-encoding reg)))))) - (define-store-short-inst (name opcode) - `(define-instruction ,name (segment reg base disp &key modify) - (:declare (type tn reg base) - (type (or fixup (signed-byte 5)) disp) - (type (member :before :after nil) modify)) - (:delay 0) - (:dependencies (reads base) (reads reg) (writes :memory)) - (:printer extended-load/store ((ext4/c ,opcode) (t/im5 nil :type 'im5) - (op2 4)) - `(:name ,@cmplt-disp-print :tab x/im5/r - "," t/im5 "(" s b ")")) - (:emitter - (multiple-value-bind - (m a) - (ecase modify - ((nil) (values 0 0)) - (:after (values 1 0)) - (:before (values 1 1))) - (emit-extended-load/store segment #x03 (reg-tn-encoding base) - (short-disp-encoding segment disp) - 0 a 4 ,opcode m - (reg-tn-encoding reg))))))) - (define-load-short-inst ldws 2) - (define-load-short-inst ldhs 1) - (define-load-short-inst ldbs 0) - (define-load-short-inst ldcws 7) - - (define-store-short-inst stws 10) - (define-store-short-inst sths 9) - (define-store-short-inst stbs 8)) - -(define-instruction stbys (segment reg base disp where &key modify) - (:declare (type tn reg base) - (type (signed-byte 5) disp) - (type (member :begin :end) where) - (type (member t nil) modify)) - (:delay 0) - (:dependencies (reads base) (reads reg) (writes :memory)) - (:printer extended-load/store ((ext4/c #xC) (t/im5 nil :type 'im5) (op2 4)) - `(:name ,@cmplt-store-print :tab x/im5/r "," t/im5 "(" s b ")")) - (:emitter - (emit-extended-load/store segment #x03 (reg-tn-encoding base) - (reg-tn-encoding reg) 0 - (ecase where (:begin 0) (:end 1)) - 4 #xC (if modify 1 0) - (short-disp-encoding segment disp)))) - - -;;;; Immediate 21-bit Instructions. -;;; Note the heavy scrambling of the immediate value to instruction memory - -(define-bitfield-emitter emit-imm21 32 - (byte 6 26) - (byte 5 21) - (byte 21 0)) - -(define-instruction ldil (segment value reg) - (:declare (type tn reg) - (type (or (signed-byte 32) (unsigned-byte 32) fixup) value)) - (:delay 0) - (:dependencies (writes reg)) - (:printer ldil ((op #x08))) - (:emitter - (emit-imm21 segment #x08 (reg-tn-encoding reg) - (encode-imm21 segment value)))) - -; this one overwrites number stack ? -(define-instruction addil (segment value reg) - (:declare (type tn reg) - (type (or (signed-byte 32) (unsigned-byte 32) fixup) value)) - (:delay 0) - (:dependencies (writes reg)) - (:printer ldil ((op #x0A))) - (:emitter - (emit-imm21 segment #x0A (reg-tn-encoding reg) - (encode-imm21 segment value)))) - - -;;;; Branch instructions. - -(define-bitfield-emitter emit-branch 32 - (byte 6 26) (byte 5 21) (byte 5 16) (byte 3 13) - (byte 11 2) (byte 1 1) (byte 1 0)) - -(defun label-relative-displacement (label posn &optional delta-if-after) - (declare (type label label) (type index posn)) - (ash (- (if delta-if-after - (label-position label posn delta-if-after) - (label-position label)) - (+ posn 8)) -2)) - -(defun decompose-branch-disp (segment disp) - (declare (type (or fixup (signed-byte 17)) disp)) - (cond ((fixup-p disp) - (note-fixup segment :branch disp) - (aver (zerop (fixup-offset disp))) - (values 0 0 0)) - (t - (values (ldb (byte 5 11) disp) - (dpb (ldb (byte 10 0) disp) - (byte 10 1) - (ldb (byte 1 10) disp)) - (ldb (byte 1 16) disp))))) - -(defun emit-relative-branch (segment opcode link sub-opcode target nullify) - (declare (type (unsigned-byte 6) opcode) - (type (unsigned-byte 5) link) - (type (unsigned-byte 1) sub-opcode) - (type label target) - (type (member t nil) nullify)) - (emit-back-patch segment 4 - (lambda (segment posn) - (let ((disp (label-relative-displacement target posn))) - (aver (typep disp '(signed-byte 17))) - (multiple-value-bind - (w1 w2 w) - (decompose-branch-disp segment disp) - (emit-branch segment opcode link w1 sub-opcode w2 - (if nullify 1 0) w)))))) - -(define-instruction b (segment target &key nullify) - (:declare (type label target) (type (member t nil) nullify)) - (:delay 0) - (:emitter - (emit-relative-branch segment #x3A 0 0 target nullify))) - -(define-instruction bl (segment target reg &key nullify) - (:declare (type tn reg) (type label target) (type (member t nil) nullify)) - (:printer branch17 ((op1 #x3A) (op2 0)) '(:name n :tab w "," t)) - (:delay 0) - (:dependencies (writes reg)) - (:emitter - (emit-relative-branch segment #x3A (reg-tn-encoding reg) 0 target nullify))) - -(define-instruction gateway (segment target reg &key nullify) - (:declare (type tn reg) (type label target) (type (member t nil) nullify)) - (:printer branch17 ((op1 #x3A) (op2 1)) '(:name n :tab w "," t)) - (:delay 0) - (:dependencies (writes reg)) - (:emitter - (emit-relative-branch segment #x3A (reg-tn-encoding reg) 1 target nullify))) - -;;; BLR is useless because we have no way to generate the offset. - -(define-instruction bv (segment base &key nullify offset) - (:declare (type tn base) - (type (member t nil) nullify) - (type (or tn null) offset)) - (:delay 0) - (:dependencies (reads base)) - (:printer branch ((op1 #x3A) (op2 6)) '(:name n :tab x "(" t ")")) - (:emitter - (emit-branch segment #x3A (reg-tn-encoding base) - (if offset (reg-tn-encoding offset) 0) - 6 0 (if nullify 1 0) 0))) - -(define-instruction be (segment disp space base &key nullify) - (:declare (type (or fixup (signed-byte 17)) disp) - (type tn base) - (type (unsigned-byte 3) space) - (type (member t nil) nullify)) - (:delay 0) - (:dependencies (reads base)) - (:printer branch17 ((op1 #x38) (op2 nil :type 'im3)) - '(:name n :tab w "(" op2 "," t ")")) - (:emitter - (multiple-value-bind - (w1 w2 w) - (decompose-branch-disp segment disp) - (emit-branch segment #x38 (reg-tn-encoding base) w1 - (space-encoding space) w2 (if nullify 1 0) w)))) - -(define-instruction ble (segment disp space base &key nullify) - (:declare (type (or fixup (signed-byte 17)) disp) - (type tn base) - (type (unsigned-byte 3) space) - (type (member t nil) nullify)) - (:delay 0) - (:dependencies (reads base)) - (:printer branch17 ((op1 #x39) (op2 nil :type 'im3)) - '(:name n :tab w "(" op2 "," t ")")) - (:dependencies (writes lip-tn)) - (:emitter - (multiple-value-bind - (w1 w2 w) - (decompose-branch-disp segment disp) - (emit-branch segment #x39 (reg-tn-encoding base) w1 - (space-encoding space) w2 (if nullify 1 0) w)))) - -(defun emit-conditional-branch (segment opcode r2 r1 cond target nullify) - (emit-back-patch segment 4 - (lambda (segment posn) - (let ((disp (label-relative-displacement target posn))) - ; emit-conditional-branch is used by instruction emitters: MOVB, COMB, ADDB and BB - ; which assembles an immediate of total 12 bits (including sign bit). - (aver (typep disp '(signed-byte 12))) - (let ((w1 (logior (ash (ldb (byte 10 0) disp) 1) - (ldb (byte 1 10) disp))) - (w (ldb (byte 1 11) disp))) ; take out the sign bit - (emit-branch segment opcode r2 r1 cond w1 (if nullify 1 0) w)))))) - -(defun im5-encoding (value) - (declare (type (signed-byte 5) value) - #+nil (values (unsigned-byte 5))) - (dpb (ldb (byte 4 0) value) - (byte 4 1) - (ldb (byte 1 4) value))) - -(macrolet ((define-branch-inst (r-name r-opcode i-name i-opcode cond-kind - writes-reg) - (let* ((conditional (symbolicate cond-kind "-CONDITION")) - (false-conditional (symbolicate conditional "-FALSE"))) - `(progn - (define-instruction ,r-name (segment cond r1 r2 target &key nullify) - (:declare (type ,conditional cond) - (type tn r1 r2) - (type label target) - (type (member t nil) nullify)) - (:delay 0) - ,@(ecase writes-reg - (:write-reg - '((:dependencies (reads r1) (reads r2) (writes r2)))) - (:pinned - '(:pinned)) - (nil - '((:dependencies (reads r1) (reads r2))))) -; ,@(if writes-reg -; '((:dependencies (reads r1) (reads r2) (writes r2))) -; '((:dependencies (reads r1) (reads r2)))) - (:printer branch12 ((op1 ,r-opcode) (c nil :type ',conditional)) - '(:name c n :tab r1 "," r2 "," w)) - ,@(unless (= r-opcode #x32) - `((:printer branch12 ((op1 ,(+ 2 r-opcode)) - (c nil :type ',false-conditional)) - '(:name c n :tab r1 "," r2 "," w)))) - (:emitter - (multiple-value-bind - (cond-encoding false) - (,conditional cond) - (emit-conditional-branch - segment (if false ,(+ r-opcode 2) ,r-opcode) - (reg-tn-encoding r2) (reg-tn-encoding r1) - cond-encoding target nullify)))) - (define-instruction ,i-name (segment cond imm reg target &key nullify) - (:declare (type ,conditional cond) - (type (signed-byte 5) imm) - (type tn reg) - (type (member t nil) nullify)) - (:delay 0) -; ,@(if writes-reg -; '((:dependencies (reads reg) (writes reg))) -; '((:dependencies (reads reg)))) - ,@(ecase writes-reg - (:write-reg - '((:dependencies (reads r1) (reads r2) (writes r2)))) - (:pinned - '(:pinned)) - (nil - '((:dependencies (reads r1) (reads r2))))) - (:printer branch12 ((op1 ,i-opcode) (r1 nil :type 'im5) - (c nil :type ',conditional)) - '(:name c n :tab r1 "," r2 "," w)) - ,@(unless (= r-opcode #x32) - `((:printer branch12 ((op1 ,(+ 2 i-opcode)) (r1 nil :type 'im5) - (c nil :type ',false-conditional)) - '(:name c n :tab r1 "," r2 "," w)))) - (:emitter - (multiple-value-bind - (cond-encoding false) - (,conditional cond) - (emit-conditional-branch - segment (if false (+ ,i-opcode 2) ,i-opcode) - (reg-tn-encoding reg) (im5-encoding imm) - cond-encoding target nullify)))))))) - (define-branch-inst movb #x32 movib #x33 extract/deposit :write-reg) - (define-branch-inst comb #x20 comib #x21 compare :pinned) - (define-branch-inst addb #x28 addib #x29 add :write-reg)) - -(define-instruction bb (segment cond reg posn target &key nullify) - (:declare (type (member t nil) cond nullify) - (type tn reg) - (type (or (member :variable) (unsigned-byte 5)) posn)) - (:delay 0) - (:dependencies (reads reg)) - (:printer branch12 ((op1 30) (c nil :type 'extract/deposit-condition)) - '('BVB c n :tab r1 "," w)) - (:emitter - (multiple-value-bind - (opcode posn-encoding) - (if (eq posn :variable) - (values #x30 0) - (values #x31 posn)) - (emit-conditional-branch segment opcode posn-encoding - (reg-tn-encoding reg) - (if cond 2 6) target nullify)))) - - -;;;; Computation Instructions - -(define-bitfield-emitter emit-r3-inst 32 - (byte 6 26) (byte 5 21) (byte 5 16) (byte 3 13) - (byte 1 12) (byte 7 5) (byte 5 0)) - -(macrolet ((define-r3-inst (name cond-kind opcode &optional pinned) - `(define-instruction ,name (segment r1 r2 res &optional cond) - (:declare (type tn res r1 r2)) - (:delay 0) - ,@(if pinned - '(:pinned) - '((:dependencies (reads r1) (reads r2) (writes res)))) - (:printer r3-inst ((op ,opcode) (c nil :type ',(symbolicate - cond-kind - "-CONDITION")))) - ,@(when (eq name 'or) - `((:printer r3-inst ((op ,opcode) (r2 0) - (c nil :type ',(symbolicate cond-kind - "-CONDITION"))) - `('COPY :tab r1 "," t)))) - (:emitter - (multiple-value-bind - (cond false) - (,(symbolicate cond-kind "-CONDITION") cond) - (emit-r3-inst segment #x02 (reg-tn-encoding r2) (reg-tn-encoding r1) - cond (if false 1 0) ,opcode - (reg-tn-encoding res))))))) - (define-r3-inst add add #x30) - (define-r3-inst addl add #x50) - (define-r3-inst addo add #x70) - (define-r3-inst addc add #x38) - (define-r3-inst addco add #x78) - (define-r3-inst sh1add add #x32) - (define-r3-inst sh1addl add #x52) - (define-r3-inst sh1addo add #x72) - (define-r3-inst sh2add add #x34) - (define-r3-inst sh2addl add #x54) - (define-r3-inst sh2addo add #x74) - (define-r3-inst sh3add add #x36) - (define-r3-inst sh3addl add #x56) - (define-r3-inst sh3addo add #x76) - (define-r3-inst sub compare #x20) - (define-r3-inst subo compare #x60) - (define-r3-inst subb compare #x28) - (define-r3-inst subbo compare #x68) - (define-r3-inst subt compare #x26) - (define-r3-inst subto compare #x66) - (define-r3-inst ds compare #x22) - (define-r3-inst comclr compare #x44) - (define-r3-inst or logical #x12 t) ; as a nop it must be pinned - (define-r3-inst xor logical #x14) - (define-r3-inst and logical #x10) - (define-r3-inst andcm logical #x00) - (define-r3-inst uxor unit #x1C) - (define-r3-inst uaddcm unit #x4C) - (define-r3-inst uaddcmt unit #x4E) - (define-r3-inst dcor unit #x5C) - (define-r3-inst idcor unit #x5E)) - -(define-bitfield-emitter emit-imm-inst 32 - (byte 6 26) (byte 5 21) (byte 5 16) (byte 3 13) - (byte 1 12) (byte 1 11) (byte 11 0)) - -(macrolet ((define-imm-inst (name cond-kind opcode subcode &optional pinned) - (declare (ignorable pinned)) - `(define-instruction ,name (segment imm src dst &optional cond) - (:declare (type tn dst src) - (type (signed-byte 11) imm)) - (:delay 0) - (:printer imm-inst ((op ,opcode) (o ,subcode) - (c nil :type - ',(symbolicate cond-kind "-CONDITION")))) - (:dependencies (reads imm) (reads src) (writes dst)) - (:emitter - (multiple-value-bind (cond false) - (,(symbolicate cond-kind "-CONDITION") cond) - (emit-imm-inst segment ,opcode (reg-tn-encoding src) - (reg-tn-encoding dst) cond - (if false 1 0) ,subcode - (encode-imm11 imm))))))) - (define-imm-inst addi add #x2D 0) - (define-imm-inst addio add #x2D 1) - (define-imm-inst addit add #x2C 0) - (define-imm-inst addito add #x2C 1) - (define-imm-inst subi compare #x25 0) - (define-imm-inst subio compare #x25 1) - (define-imm-inst comiclr compare #x24 0)) - -(define-bitfield-emitter emit-extract/deposit-inst 32 - (byte 6 26) (byte 5 21) (byte 5 16) (byte 3 13) - (byte 3 10) (byte 5 5) (byte 5 0)) - -(define-instruction shd (segment r1 r2 count res &optional cond) - (:declare (type tn res r1 r2) - (type (or (member :variable) (integer 0 31)) count)) - (:delay 0) - :pinned - (:printer extract/deposit-inst ((op1 #x34) (op2 2) (t/clen nil :type 'reg)) - '(:name c :tab r1 "," r2 "," cp "," t/clen)) - (:printer extract/deposit-inst ((op1 #x34) (op2 0) (t/clen nil :type 'reg)) - '('VSHD c :tab r1 "," r2 "," t/clen)) - (:emitter - (etypecase count - ((member :variable) - (emit-extract/deposit-inst segment #x34 - (reg-tn-encoding r2) (reg-tn-encoding r1) - (extract/deposit-condition cond) - 0 0 (reg-tn-encoding res))) - ((integer 0 31) - (emit-extract/deposit-inst segment #x34 - (reg-tn-encoding r2) (reg-tn-encoding r1) - (extract/deposit-condition cond) - 2 (- 31 count) - (reg-tn-encoding res)))))) - -(macrolet ((define-extract-inst (name opcode) - `(define-instruction ,name (segment src posn len res &optional cond) - (:declare (type tn res src) - (type (or (member :variable) (integer 0 31)) posn) - (type (integer 1 32) len)) - (:delay 0) - (:dependencies (reads src) (writes res)) - (:printer extract/deposit-inst ((op1 #x34) (cp nil :type 'integer) - (op2 ,opcode)) - '(:name c :tab r2 "," cp "," t/clen "," r1)) - (:printer extract/deposit-inst ((op1 #x34) (op2 ,(- opcode 2))) - '('V :name c :tab r2 "," t/clen "," r1)) - (:emitter - (etypecase posn - ((member :variable) - (emit-extract/deposit-inst segment #x34 (reg-tn-encoding src) - (reg-tn-encoding res) - (extract/deposit-condition cond) - ,(- opcode 2) 0 (- 32 len))) - ((integer 0 31) - (emit-extract/deposit-inst segment #x34 (reg-tn-encoding src) - (reg-tn-encoding res) - (extract/deposit-condition cond) - ,opcode posn (- 32 len)))))))) - (define-extract-inst extru 6) - (define-extract-inst extrs 7)) - -(macrolet ((define-deposit-inst (name opcode) - `(define-instruction ,name (segment src posn len res &optional cond) - (:declare (type tn res) - (type (or tn (signed-byte 5)) src) - (type (or (member :variable) (integer 0 31)) posn) - (type (integer 1 32) len)) - (:delay 0) - (:dependencies (reads src) (writes res)) - (:printer extract/deposit-inst ((op1 #x35) (op2 ,opcode)) - ',(let ((base '('VDEP c :tab r1 "," t/clen "," r2))) - (if (= opcode 0) (cons ''Z base) base))) - (:printer extract/deposit-inst ((op1 #x35) (op2 ,(+ 2 opcode))) - ',(let ((base '('DEP c :tab r1 "," cp "," t/clen "," r2))) - (if (= opcode 0) (cons ''Z base) base))) - (:printer extract/deposit-inst ((op1 #x35) (r1 nil :type 'im5) - (op2 ,(+ 4 opcode))) - ',(let ((base '('VDEPI c :tab r1 "," t/clen "," r2))) - (if (= opcode 0) (cons ''Z base) base))) - (:printer extract/deposit-inst ((op1 #x35) (r1 nil :type 'im5) - (op2 ,(+ 6 opcode))) - ',(let ((base '('DEPI c :tab r1 "," cp "," t/clen "," r2))) - (if (= opcode 0) (cons ''Z base) base))) - (:emitter - (multiple-value-bind - (opcode src-encoding) - (etypecase src - (tn - (values ,opcode (reg-tn-encoding src))) - ((signed-byte 5) - (values ,(+ opcode 4) (im5-encoding src)))) - (multiple-value-bind - (opcode posn-encoding) - (etypecase posn - ((member :variable) - (values opcode 0)) - ((integer 0 31) - (values (+ opcode 2) (- 31 posn)))) - (emit-extract/deposit-inst segment #x35 (reg-tn-encoding res) - src-encoding - (extract/deposit-condition cond) - opcode posn-encoding (- 32 len)))))))) - - (define-deposit-inst dep 1) - (define-deposit-inst zdep 0)) - - - -;;;; System Control Instructions. - -(define-bitfield-emitter emit-break 32 - (byte 6 26) (byte 13 13) (byte 8 5) (byte 5 0)) - -(define-instruction break (segment &optional (im5 0) (im13 0)) - (:declare (type (unsigned-byte 13) im13) - (type (unsigned-byte 5) im5)) - (:cost 0) - (:delay 0) - :pinned - (:printer break () :default :control #'break-control) - (:emitter - (emit-break segment 0 im13 0 im5))) - -(define-bitfield-emitter emit-system-inst 32 - (byte 6 26) (byte 5 21) (byte 5 16) (byte 3 13) (byte 8 5) (byte 5 0)) - -(define-instruction ldsid (segment res base &optional (space 0)) - (:declare (type tn res base) - (type (integer 0 3) space)) - (:delay 0) - :pinned - (:printer system-inst ((op2 #x85) (c nil :type 'space) - (s nil :printer #(0 0 1 1 2 2 3 3))) - `(:name :tab "(" s r1 ")," r3)) - (:emitter - (emit-system-inst segment 0 (reg-tn-encoding base) 0 (ash space 1) #x85 - (reg-tn-encoding res)))) - -(define-instruction mtsp (segment reg space) - (:declare (type tn reg) (type (integer 0 7) space)) - (:delay 0) - :pinned - (:printer system-inst ((op2 #xC1)) '(:name :tab r2 "," s)) - (:emitter - (emit-system-inst segment 0 0 (reg-tn-encoding reg) (space-encoding space) - #xC1 0))) - -(define-instruction mfsp (segment space reg) - (:declare (type tn reg) (type (integer 0 7) space)) - (:delay 0) - :pinned - (:printer system-inst ((op2 #x25) (c nil :type 'space)) '(:name :tab s r3)) - (:emitter - (emit-system-inst segment 0 0 0 (space-encoding space) #x25 - (reg-tn-encoding reg)))) - -(deftype control-reg () - '(or (unsigned-byte 5) (member :sar))) - -(defun control-reg (reg) - (declare (type control-reg reg) - #+nil (values (unsigned-byte 32))) - (if (typep reg '(unsigned-byte 5)) - reg - (ecase reg - (:sar 11)))) - -(define-instruction mtctl (segment reg ctrl-reg) - (:declare (type tn reg) (type control-reg ctrl-reg)) - (:delay 0) - :pinned - (:printer system-inst ((op2 #xC2)) '(:name :tab r2 "," r1)) - (:emitter - (emit-system-inst segment 0 (control-reg ctrl-reg) (reg-tn-encoding reg) - 0 #xC2 0))) - -(define-instruction mfctl (segment ctrl-reg reg) - (:declare (type tn reg) (type control-reg ctrl-reg)) - (:delay 0) - :pinned - (:printer system-inst ((op2 #x45)) '(:name :tab r1 "," r3)) - (:emitter - (emit-system-inst segment 0 (control-reg ctrl-reg) 0 0 #x45 - (reg-tn-encoding reg)))) - - - -;;;; Floating point instructions. - -(define-bitfield-emitter emit-fp-load/store 32 - (byte 6 26) (byte 5 21) (byte 5 16) (byte 2 14) (byte 1 13) (byte 1 12) - (byte 2 10) (byte 1 9) (byte 3 6) (byte 1 5) (byte 5 0)) - -(define-instruction fldx (segment index base result &key modify scale side) - (:declare (type tn index base result) - (type (member t nil) modify scale) - (type (member nil 0 1) side)) - (:delay 0) - :pinned - (:printer fp-load/store ((op #x0b) (x1 0) (x2 0) (x3 0)) - `('FLDD ,@cmplt-index-print :tab x "(" s b ")" "," t)) - (:printer fp-load/store ((op #x09) (x1 0) (x2 0) (x3 0)) - `('FLDW ,@cmplt-index-print :tab x "(" s b ")" "," t)) - (:emitter - (multiple-value-bind - (result-encoding double-p) - (fp-reg-tn-encoding result) - (when side - (aver double-p) - (setf double-p nil)) - (emit-fp-load/store segment (if double-p #x0B #x09) (reg-tn-encoding base) - (reg-tn-encoding index) 0 (if scale 1 0) 0 0 0 - (or side 0) (if modify 1 0) result-encoding)))) - -(define-instruction fstx (segment value index base &key modify scale side) - (:declare (type tn index base value) - (type (member t nil) modify scale) - (type (member nil 0 1) side)) - (:delay 0) - :pinned - (:printer fp-load/store ((op #x0b) (x1 0) (x2 0) (x3 1)) - `('FSTD ,@cmplt-index-print :tab t "," x "(" s b ")")) - (:printer fp-load/store ((op #x09) (x1 0) (x2 0) (x3 1)) - `('FSTW ,@cmplt-index-print :tab t "," x "(" s b ")")) - (:emitter - (multiple-value-bind - (value-encoding double-p) - (fp-reg-tn-encoding value) - (when side - (aver double-p) - (setf double-p nil)) - (emit-fp-load/store segment (if double-p #x0B #x09) (reg-tn-encoding base) - (reg-tn-encoding index) 0 (if scale 1 0) 0 0 1 - (or side 0) (if modify 1 0) value-encoding)))) - -(define-instruction flds (segment disp base result &key modify side) - (:declare (type tn base result) - (type (signed-byte 5) disp) - (type (member :before :after nil) modify) - (type (member nil 0 1) side)) - (:delay 0) - :pinned - (:printer fp-load/store ((op #x0b) (x nil :type 'im5) (x1 1) (x2 0) (x3 0)) - `('FLDD ,@cmplt-disp-print :tab x "(" s b ")," t)) - (:printer fp-load/store ((op #x09) (x nil :type 'im5) (x1 1) (x2 0) (x3 0)) - `('FLDW ,@cmplt-disp-print :tab x "(" s b ")," t)) - (:emitter - (multiple-value-bind - (result-encoding double-p) - (fp-reg-tn-encoding result) - (when side - (aver double-p) - (setf double-p nil)) - (emit-fp-load/store segment (if double-p #x0B #x09) (reg-tn-encoding base) - (short-disp-encoding segment disp) 0 - (if (eq modify :before) 1 0) 1 0 0 - (or side 0) (if modify 1 0) result-encoding)))) - -(define-instruction fsts (segment value disp base &key modify side) - (:declare (type tn base value) - (type (signed-byte 5) disp) - (type (member :before :after nil) modify) - (type (member nil 0 1) side)) - (:delay 0) - :pinned - (:printer fp-load/store ((op #x0b) (x nil :type 'im5) (x1 1) (x2 0) (x3 1)) - `('FSTD ,@cmplt-disp-print :tab t "," x "(" s b ")")) - (:printer fp-load/store ((op #x09) (x nil :type 'im5) (x1 1) (x2 0) (x3 1)) - `('FSTW ,@cmplt-disp-print :tab t "," x "(" s b ")")) - (:emitter - (multiple-value-bind - (value-encoding double-p) - (fp-reg-tn-encoding value) - (when side - (aver double-p) - (setf double-p nil)) - (emit-fp-load/store segment (if double-p #x0B #x09) (reg-tn-encoding base) - (short-disp-encoding segment disp) 0 - (if (eq modify :before) 1 0) 1 0 1 - (or side 0) (if modify 1 0) value-encoding)))) - - -(define-bitfield-emitter emit-fp-class-0-inst 32 - (byte 6 26) (byte 5 21) (byte 5 16) (byte 3 13) (byte 2 11) (byte 2 9) - (byte 3 6) (byte 1 5) (byte 5 0)) - -(define-bitfield-emitter emit-fp-class-1-inst 32 - (byte 6 26) (byte 5 21) (byte 4 17) (byte 2 15) (byte 2 13) (byte 2 11) - (byte 2 9) (byte 3 6) (byte 1 5) (byte 5 0)) - -;;; Note: classes 2 and 3 are similar enough to class 0 that we don't need -;;; seperate emitters. - -(defconstant-eqx funops '(:copy :abs :sqrt :rnd) - #'equalp) - -(deftype funop () - `(member ,@funops)) - -(define-instruction funop (segment op from to) - (:declare (type funop op) - (type tn from to)) - (:delay 0) - :pinned - (:printer fp-class-0-inst ((op1 #x0C) (op2 2) (x2 0)) - '('FCPY fmt :tab r "," t)) - (:printer fp-class-0-inst ((op1 #x0C) (op2 3) (x2 0)) - '('FABS fmt :tab r "," t)) - (:printer fp-class-0-inst ((op1 #x0C) (op2 4) (x2 0)) - '('FSQRT fmt :tab r "," t)) - (:printer fp-class-0-inst ((op1 #x0C) (op2 5) (x2 0)) - '('FRND fmt :tab r "," t)) - (:emitter - (multiple-value-bind - (from-encoding from-double-p) - (fp-reg-tn-encoding from) - (multiple-value-bind - (to-encoding to-double-p) - (fp-reg-tn-encoding to) - (aver (eq from-double-p to-double-p)) - (emit-fp-class-0-inst segment #x0C from-encoding 0 - (+ 2 (or (position op funops) - (error "Bogus FUNOP: ~S" op))) - (if to-double-p 1 0) 0 0 0 to-encoding))))) - -(macrolet ((define-class-1-fp-inst (name subcode) - `(define-instruction ,name (segment from to) - (:declare (type tn from to)) - (:delay 0) - (:printer fp-class-1-inst ((op1 #x0C) (x2 ,subcode)) - '(:name sf df :tab r "," t)) - (:emitter - (multiple-value-bind - (from-encoding from-double-p) - (fp-reg-tn-encoding from) - (multiple-value-bind - (to-encoding to-double-p) - (fp-reg-tn-encoding to) - (emit-fp-class-1-inst segment #x0C from-encoding 0 ,subcode - (if to-double-p 1 0) (if from-double-p 1 0) - 1 0 0 to-encoding))))))) - - (define-class-1-fp-inst fcnvff 0) - (define-class-1-fp-inst fcnvxf 1) - (define-class-1-fp-inst fcnvfx 2) - (define-class-1-fp-inst fcnvfxt 3)) - -(define-instruction fcmp (segment cond r1 r2) - (:declare (type (unsigned-byte 5) cond) - (type tn r1 r2)) - (:delay 0) - :pinned - (:printer fp-class-0-inst ((op1 #x0C) (op2 0) (x2 2) (t nil :type 'fcmp-cond)) - '(:name fmt t :tab r "," x1)) - (:emitter - (multiple-value-bind - (r1-encoding r1-double-p) - (fp-reg-tn-encoding r1) - (multiple-value-bind - (r2-encoding r2-double-p) - (fp-reg-tn-encoding r2) - (aver (eq r1-double-p r2-double-p)) - (emit-fp-class-0-inst segment #x0C r1-encoding r2-encoding 0 - (if r1-double-p 1 0) 2 0 0 cond))))) - -(define-instruction ftest (segment) - (:delay 0) - :pinned - (:printer fp-class-0-inst ((op1 #x0c) (op2 1) (x2 2)) '(:name)) - (:emitter - (emit-fp-class-0-inst segment #x0C 0 0 1 0 2 0 1 0))) - -(defconstant-eqx fbinops '(:add :sub :mpy :div) - #'equalp) - -(deftype fbinop () - `(member ,@fbinops)) - -(define-instruction fbinop (segment op r1 r2 result) - (:declare (type fbinop op) - (type tn r1 r2 result)) - (:delay 0) - :pinned - (:printer fp-class-0-inst ((op1 #x0C) (op2 0) (x2 3)) - '('FADD fmt :tab r "," x1 "," t)) - (:printer fp-class-0-inst ((op1 #x0C) (op2 1) (x2 3)) - '('FSUB fmt :tab r "," x1 "," t)) - (:printer fp-class-0-inst ((op1 #x0C) (op2 2) (x2 3)) - '('FMPY fmt :tab r "," x1 "," t)) - (:printer fp-class-0-inst ((op1 #x0C) (op2 3) (x2 3)) - '('FDIV fmt :tab r "," x1 "," t)) - (:emitter - (multiple-value-bind - (r1-encoding r1-double-p) - (fp-reg-tn-encoding r1) - (multiple-value-bind - (r2-encoding r2-double-p) - (fp-reg-tn-encoding r2) - (aver (eq r1-double-p r2-double-p)) - (multiple-value-bind - (result-encoding result-double-p) - (fp-reg-tn-encoding result) - (aver (eq r1-double-p result-double-p)) - (emit-fp-class-0-inst segment #x0C r1-encoding r2-encoding - (or (position op fbinops) - (error "Bogus FBINOP: ~S" op)) - (if r1-double-p 1 0) 3 0 0 - result-encoding)))))) - - - -;;;; Instructions built out of other insts. - -(define-instruction-macro move (src dst &optional cond) - `(inst or ,src zero-tn ,dst ,cond)) - -(define-instruction-macro nop (&optional cond) - `(inst or zero-tn zero-tn zero-tn ,cond)) - -(define-instruction li (segment value reg) - (:declare (type tn reg) - (type (or fixup (signed-byte 32) (unsigned-byte 32)) value)) - (:delay 0) - (:dependencies (reads reg)) - (:vop-var vop) - (:emitter - (assemble (segment vop) - (etypecase value - (fixup - (inst ldil value reg) - (inst ldo value reg reg :unsigned t)) - ((signed-byte 14) - (inst ldo value zero-tn reg)) - ((or (signed-byte 32) (unsigned-byte 32)) - (let ((lo (ldb (byte 11 0) value))) - (inst ldil value reg) - (inst ldo lo reg reg :unsigned t))))))) - -(define-instruction-macro sll (src count result &optional cond) - (once-only ((result result) (src src) (count count) (cond cond)) - `(inst zdep ,src (- 31 ,count) (- 32 ,count) ,result ,cond))) - -(define-instruction-macro sra (src count result &optional cond) - (once-only ((result result) (src src) (count count) (cond cond)) - `(inst extrs ,src (- 31 ,count) (- 32 ,count) ,result ,cond))) - -(define-instruction-macro srl (src count result &optional cond) - (once-only ((result result) (src src) (count count) (cond cond)) - `(inst extru ,src (- 31 ,count) (- 32 ,count) ,result ,cond))) - -(defun maybe-negate-cond (cond negate) - (if negate - (multiple-value-bind - (value negate) - (compare-condition cond) - (if negate - (nth value compare-conditions) - (nth (+ value 8) compare-conditions))) - cond)) - -(define-instruction bc (segment cond not-p r1 r2 target) - (:declare (type compare-condition cond) - (type (member t nil) not-p) - (type tn r1 r2) - (type label target)) - (:delay 0) - (:dependencies (reads r1) (reads r2)) - (:vop-var vop) - (:emitter - (emit-chooser segment 8 2 - (lambda (segment chooser posn delta) - (declare (ignore chooser)) - (let ((disp (label-relative-displacement target posn delta))) - (when (<= 0 disp (1- (ash 1 11))) - (assemble (segment vop) - (inst comb (maybe-negate-cond cond not-p) r1 r2 target - :nullify t)) - t))) - (lambda (segment posn) - (let ((disp (label-relative-displacement target posn))) - (assemble (segment vop) - (cond ((typep disp '(signed-byte 12)) - (inst comb (maybe-negate-cond cond not-p) r1 r2 target) - (inst nop)) ; FIXME-lav, cant nullify when backward branch - (t - (inst comclr r1 r2 zero-tn - (maybe-negate-cond cond (not not-p))) - (inst b target :nullify t))))))))) - -(define-instruction bci (segment cond not-p imm reg target) - (:declare (type compare-condition cond) - (type (member t nil) not-p) - (type (signed-byte 11) imm) - (type tn reg) - (type label target)) - (:delay 0) - (:dependencies (reads reg)) - (:vop-var vop) - (:emitter - (emit-chooser segment 8 2 - (lambda (segment chooser posn delta-if-after) - (declare (ignore chooser)) - (let ((disp (label-relative-displacement target posn delta-if-after))) - (when (and (<= 0 disp (1- (ash 1 11))) - (typep imm '(signed-byte 5))) - (assemble (segment vop) - (inst comib (maybe-negate-cond cond not-p) imm reg target - :nullify t)) - t))) - (lambda (segment posn) - (let ((disp (label-relative-displacement target posn))) - (assemble (segment vop) - (cond ((and (typep disp '(signed-byte 12)) - (typep imm '(signed-byte 5))) - (inst comib (maybe-negate-cond cond not-p) imm reg target) - (inst nop)) - (t - (inst comiclr imm reg zero-tn - (maybe-negate-cond cond (not not-p))) - (inst b target :nullify t))))))))) - - -;;;; Instructions to convert between code ptrs, functions, and lras. - -(defun emit-header-data (segment type) - (emit-back-patch - segment 4 - (lambda (segment posn) - (emit-word segment - (logior type - (ash (+ posn (component-header-length)) - (- n-widetag-bits word-shift))))))) - -(define-instruction simple-fun-header-word (segment) - :pinned - (:cost 0) - (:delay 0) - (:emitter - (emit-header-data segment simple-fun-widetag))) - -(define-instruction lra-header-word (segment) - :pinned - (:cost 0) - (:delay 0) - (:emitter - (emit-header-data segment return-pc-widetag))) - - -(defun emit-compute-inst (segment vop src label temp dst calc) - (emit-chooser - ;; We emit either 12 or 4 bytes, so we maintain 3 byte alignments. - segment 12 3 - ;; This is the best-case that emits one instruction ( 4 bytes ) - (lambda (segment chooser posn delta-if-after) - (declare (ignore chooser)) - (let ((delta (funcall calc label posn delta-if-after))) - ;; WHEN, Why not AVER ? - (when (typep delta '(signed-byte 11)) - (emit-back-patch segment 4 - (lambda (segment posn) - (assemble (segment vop) - (inst addi (funcall calc label posn 0) src - dst)))) - t))) - ;; This is the worst-case that emits three instruction ( 12 bytes ) - (lambda (segment posn) - (let ((delta (funcall calc label posn 0))) - ;; FIXME-lav: why do we hit below check ? - ;; (when (<= (- (ash 1 10)) delta (1- (ash 1 10))) - ;; (error "emit-compute-inst selected worst-case, but is shrinkable, delta is ~s" delta)) - ;; Note: if we used addil/ldo to do this in 2 instructions then the - ;; intermediate value would be tagged but pointing into space. - ;; Does above note mean that the intermediate value would be - ;; a bogus pointer that would be GCed wrongly ? - ;; Also what I can see addil would also overwrite NFP (r1) ??? - (assemble (segment vop) - ;; Three instructions (4 * 3) this is the reason for 12 bytes - (inst ldil delta temp) - (inst ldo (ldb (byte 11 0) delta) temp temp :unsigned t) - (inst add src temp dst)))))) - -(macrolet ((compute ((name) &body body) - `(define-instruction ,name (segment src label temp dst) - (:declare (type tn src dst temp) (type label label)) - (:attributes variable-length) - (:dependencies (reads src) (writes dst) (writes temp)) - (:delay 0) - (:vop-var vop) - (:emitter - (emit-compute-inst segment vop src label temp dst - ,@body))))) - (compute (compute-code-from-lip) - (lambda (label posn delta-if-after) - (- other-pointer-lowtag - (label-position label posn delta-if-after) - (component-header-length)))) - (compute (compute-code-from-lra) - (lambda (label posn delta-if-after) - (- (+ (label-position label posn delta-if-after) - (component-header-length))))) - (compute (compute-lra-from-code) - (lambda (label posn delta-if-after) - (+ (label-position label posn delta-if-after) - (component-header-length))))) - -;;;; Data instructions. -(define-bitfield-emitter emit-word 32 - (byte 32 0)) - -(macrolet ((data (size type) - `(define-instruction ,size (segment ,size) - (:declare (type ,type ,size)) - (:cost 0) - (:delay 0) - :pinned - (:emitter - (etypecase ,size - ,@(when (eq size 'word) - '((fixup - (note-fixup segment :absolute word) - (emit-word segment 0)))) - (integer - (,(symbolicate "EMIT-" size) segment ,size))))))) - (data byte (or (unsigned-byte 8) (signed-byte 8))) - (data short (or (unsigned-byte 16) (signed-byte 16))) - (data word (or (unsigned-byte 32) (signed-byte 32) fixup))) diff --git a/src/compiler/hppa/macros.lisp b/src/compiler/hppa/macros.lisp deleted file mode 100644 index 061453551b..0000000000 --- a/src/compiler/hppa/macros.lisp +++ /dev/null @@ -1,386 +0,0 @@ -;;;; various useful macros for generating HPPA code - -;;;; This software is part of the SBCL system. See the README file for -;;;; more information. -;;;; -;;;; This software is derived from the CMU CL system, which was -;;;; written at Carnegie Mellon University and released into the -;;;; public domain. The software is in the public domain and is -;;;; provided with absolutely no warranty. See the COPYING and CREDITS -;;;; files for more information. -(in-package "SB-VM") - - - -(defmacro expand (expr) - (let ((gensym (gensym))) - `(macrolet - ((,gensym () - ,expr)) - (,gensym)))) - -;;; Instruction-like macros. -;;; FIXME-lav: add if always-emit-code-p is :e= then error if location= -(defmacro move (src dst &optional always-emit-code-p) - "Move SRC into DST (unless they are location= and ALWAYS-EMIT-CODE-P is nil)." - (once-only ((n-src src) - (n-dst dst)) - `(if (location= ,n-dst ,n-src) - (when ,always-emit-code-p - (inst nop)) - (inst move ,n-src ,n-dst)))) - -(defmacro loadw (result base &optional (offset 0) (lowtag 0)) - (once-only ((result result) (base base)) - `(inst ldw (- (ash ,offset word-shift) ,lowtag) ,base ,result))) - -(defmacro storew (value base &optional (offset 0) (lowtag 0)) - (once-only ((value value) (base base) (offset offset) (lowtag lowtag)) - `(inst stw ,value (- (ash ,offset word-shift) ,lowtag) ,base))) - -(defmacro load-symbol (reg symbol) - (once-only ((reg reg) (symbol symbol)) - `(let ((offset (static-symbol-offset ,symbol))) - (cond - ((typep offset '(signed-byte 11)) - (inst addi offset null-tn ,reg)) - (t - (inst ldil offset ,reg) - (inst ldo offset null-tn ,reg :unsigned t)))))) - -(defmacro load-symbol-value (reg symbol) - `(inst ldw - (+ (static-symbol-offset ',symbol) - (ash symbol-value-slot word-shift) - (- other-pointer-lowtag)) - null-tn ,reg)) - -(defmacro store-symbol-value (reg symbol) - `(inst stw ,reg (+ (static-symbol-offset ',symbol) - (ash symbol-value-slot word-shift) - (- other-pointer-lowtag)) - null-tn)) - -(defmacro load-type (target source &optional (offset 0)) - "Loads the type bits of a pointer into target independent of -byte-ordering issues." - (once-only ((n-target target) - (n-source source) - (n-offset offset)) - (ecase *backend-byte-order* - (:little-endian - `(inst ldb ,n-offset ,n-source ,n-target)) - (:big-endian - `(inst ldb (+ ,n-offset (1- n-word-bytes)) ,n-source ,n-target))))) - -(defmacro set-lowtag (tag src dst) - `(progn - (inst move ,src ,dst) - (inst dep ,tag 31 n-lowtag-bits ,dst))) - -;;; Macros to handle the fact that we cannot use the machine native call and -;;; return instructions. - -(defmacro lisp-jump (function) - "Jump to the lisp function FUNCTION." - `(progn - (inst addi (- (ash simple-fun-insts-offset word-shift) - fun-pointer-lowtag) ,function lip-tn) - (inst bv lip-tn) - (move ,function code-tn t))) - -(defmacro lisp-return (return-pc &key (offset 0) (frob-code t)) - "Return to RETURN-PC." - `(progn - (inst addi (- (* (1+ ,offset) n-word-bytes) other-pointer-lowtag) - ,return-pc lip-tn) - (inst bv lip-tn ,@(unless frob-code '(:nullify t))) - ,@(if frob-code - `((move ,return-pc code-tn t))))) - -(defmacro emit-return-pc (label) - "Emit a return-pc header word. LABEL is the label to use for this - return-pc." - `(progn - ;; alignment causes the return point to land on two address, - ;; where the first must be nop pad. - (emit-alignment n-lowtag-bits) - (emit-label ,label) - (inst lra-header-word))) - - -;;;; Stack TN's - -;;; Move a stack TN to a register and vice-versa. -(defmacro load-stack-tn (reg stack) - `(let ((reg ,reg) - (stack ,stack)) - (let ((offset (tn-offset stack))) - (sc-case stack - ((control-stack) - (loadw reg cfp-tn offset)))))) - -(defmacro store-stack-tn (stack reg) - `(let ((stack ,stack) - (reg ,reg)) - (let ((offset (tn-offset stack))) - (sc-case stack - ((control-stack) - (storew reg cfp-tn offset)))))) - -(defmacro maybe-load-stack-tn (reg reg-or-stack) - "Move the TN Reg-Or-Stack into Reg if it isn't already there." - (once-only ((n-reg reg) - (n-stack reg-or-stack)) - `(sc-case ,n-reg - ((any-reg descriptor-reg) - (sc-case ,n-stack - ((any-reg descriptor-reg) - (move ,n-stack ,n-reg)) - ((control-stack) - (loadw ,n-reg cfp-tn (tn-offset ,n-stack)))))))) - - -;;;; Storage allocation: - -(defmacro with-fixed-allocation ((result-tn flag-tn temp-tn type-code - size dynamic-extent-p - &key (lowtag other-pointer-lowtag) - maybe-write) - &body body) - "Do stuff to allocate an other-pointer object of fixed Size with a single -word header having the specified Type-Code. The result is placed in -Result-TN, and Temp-TN is a non-descriptor temp (which may be randomly used -by the body.) The body is placed inside the PSEUDO-ATOMIC, and presumably -initializes the object." - (declare (ignore flag-tn)) - (once-only ((result-tn result-tn) (temp-tn temp-tn) - (type-code type-code) (size size) - (lowtag lowtag)) - (let ((write-body `((inst li (compute-object-header ,size ,type-code) ,temp-tn) - (storew ,temp-tn ,result-tn 0 ,lowtag)))) - `(if ,dynamic-extent-p - (pseudo-atomic () - (align-csp ,temp-tn) - (set-lowtag ,lowtag csp-tn ,result-tn) - (inst addi (pad-data-block ,size) csp-tn csp-tn) - ,@(if maybe-write - `((when ,type-code ,@write-body)) - write-body) - ,@body) - (pseudo-atomic (:extra (pad-data-block ,size)) - (set-lowtag ,lowtag alloc-tn ,result-tn) - ,@(if maybe-write - `((when ,type-code ,@write-body)) - write-body) - ,@body))))) - -;;; is used for stack allocation of dynamic-extent objects -;;; FIXME-lav, if using defun, atleast surround in assembly-form ? macro better ? -(defun align-csp (temp) - (declare (ignore temp)) - (let ((aligned (gen-label))) - (inst extru csp-tn 31 n-lowtag-bits zero-tn :<>) - (inst b aligned :nullify t) - (inst addi n-word-bytes csp-tn csp-tn) - (storew zero-tn csp-tn -1) - (emit-label aligned))) - - -;;;; Error Code -(defun emit-error-break (vop kind code values) - (assemble () - (when vop - (note-this-location vop :internal-error)) - (emit-internal-error kind code values - :trap-emitter (lambda (trap-number) - (inst break trap-number)) - :compact-error-trap nil) - (emit-alignment word-shift))) - -(defun generate-error-code (vop error-code &rest values) - "Generate-Error-Code Error-code Value* - Emit code for an error with the specified Error-Code and context Values." - (assemble (:elsewhere) - (let ((start-lab (gen-label))) - (emit-label start-lab) - (apply #'error-call vop error-code values) - start-lab))) - -;;;; PSEUDO-ATOMIC - -;;; handy macro for making sequences look atomic -(defmacro pseudo-atomic ((&key (extra 0)) &rest forms) - (let ((n-extra (gensym))) - `(let ((,n-extra ,extra)) - (inst addi 4 alloc-tn alloc-tn) - ,@forms - (cond - ((typep ,n-extra '(signed-byte 11)) - (inst addit (- ,n-extra 4) alloc-tn alloc-tn :od)) - ((typep ,n-extra '(signed-byte 14)) - (inst ldo ,n-extra alloc-tn alloc-tn) - (inst addit -4 alloc-tn alloc-tn :od)) - (t - ;; FIXME: Make this case work, somehow - (error "EXTRA out-of-range in PSEUDO-ATOMIC")))))) - -;;;; indexed references - -(sb-xc:deftype load/store-index (scale lowtag min-offset - &optional (max-offset min-offset)) - `(integer ,(- (truncate (+ (ash 1 14) - (* min-offset n-word-bytes) - (- lowtag)) - scale)) - ,(truncate (- (+ (1- (ash 1 14)) lowtag) - (* max-offset n-word-bytes)) - scale))) - -(defmacro define-full-reffer (name type offset lowtag scs el-type - &optional translate) - `(progn - (define-vop (,name) - ,@(when translate - `((:translate ,translate))) - (:policy :fast-safe) - (:args (object :scs (descriptor-reg)) - (index :scs (any-reg))) - (:arg-types ,type tagged-num) - (:temporary (:scs (interior-reg)) lip) - (:results (value :scs ,scs)) - (:result-types ,el-type) - (:generator 5 - (inst add object index lip) - (loadw value lip ,offset ,lowtag))) - (define-vop (,(symbolicate name "-C")) - ,@(when translate - `((:translate ,translate))) - (:policy :fast-safe) - (:args (object :scs (descriptor-reg))) - (:info index) - (:arg-types ,type - (:constant (load/store-index ,n-word-bytes ,(eval lowtag) - ,(eval offset)))) - (:results (value :scs ,scs)) - (:result-types ,el-type) - (:generator 4 - (loadw value object (+ ,offset index) ,lowtag))))) - -(defmacro define-full-setter (name type offset lowtag scs el-type - &optional translate) - `(progn - (define-vop (,name) - ,@(when translate - `((:translate ,translate))) - (:policy :fast-safe) - (:args (object :scs (descriptor-reg)) - (index :scs (any-reg)) - (value :scs ,scs :target result)) - (:arg-types ,type tagged-num ,el-type) - (:temporary (:scs (interior-reg)) lip) - (:results (result :scs ,scs)) - (:result-types ,el-type) - (:generator 2 - (inst add object index lip) - (storew value lip ,offset ,lowtag) - (move value result))) - (define-vop (,(symbolicate name "-C")) - ,@(when translate - `((:translate ,translate))) - (:policy :fast-safe) - (:args (object :scs (descriptor-reg)) - (value :scs ,scs)) - (:info index) - (:arg-types ,type - (:constant (load/store-index ,n-word-bytes ,(eval lowtag) - ,(eval offset))) - ,el-type) - (:results (result :scs ,scs)) - (:result-types ,el-type) - (:generator 1 - (storew value object (+ ,offset index) ,lowtag) - (move value result))))) - - -(defmacro define-partial-reffer (name type size signed offset lowtag scs - el-type &optional translate) - (let ((scale (ecase size (:byte 1) (:short 2)))) - `(progn - (define-vop (,name) - ,@(when translate - `((:translate ,translate))) - (:policy :fast-safe) - (:args (object :scs (descriptor-reg) :to (:eval 0)) - (index :scs (unsigned-reg))) - (:arg-types ,type positive-fixnum) - (:results (value :scs ,scs)) - (:result-types ,el-type) - (:temporary (:scs (interior-reg)) lip) - (:generator 5 - (inst ,(ecase size (:byte 'add) (:short 'sh1add)) - index object lip) - (inst ,(ecase size (:byte 'ldb) (:short 'ldh)) - (- (* ,offset n-word-bytes) ,lowtag) lip value) - ,@(when signed - `((inst extrs value 31 ,(* scale n-byte-bits) value))))) - (define-vop (,(symbolicate name "-C")) - ,@(when translate - `((:translate ,translate))) - (:policy :fast-safe) - (:args (object :scs (descriptor-reg))) - (:info index) - (:arg-types ,type - (:constant (load/store-index ,scale - ,(eval lowtag) - ,(eval offset)))) - (:results (value :scs ,scs)) - (:result-types ,el-type) - (:generator 5 - (inst ,(ecase size (:byte 'ldb) (:short 'ldh)) - (- (+ (* ,offset n-word-bytes) (* index ,scale)) ,lowtag) - object value) - ,@(when signed - `((inst extrs value 31 ,(* scale n-byte-bits) value)))))))) - -(defmacro define-partial-setter (name type size offset lowtag scs el-type - &optional translate) - (let ((scale (ecase size (:byte 1) (:short 2)))) - `(progn - (define-vop (,name) - ,@(when translate - `((:translate ,translate))) - (:policy :fast-safe) - (:args (object :scs (descriptor-reg)) - (index :scs (unsigned-reg)) - (value :scs ,scs :target result)) - (:arg-types ,type positive-fixnum ,el-type) - (:temporary (:scs (interior-reg)) lip) - (:results (result :scs ,scs)) - (:result-types ,el-type) - (:generator 5 - (inst ,(ecase size (:byte 'add) (:short 'sh1add)) - index object lip) - (inst ,(ecase size (:byte 'stb) (:short 'sth)) - value (- (* ,offset n-word-bytes) ,lowtag) lip) - (move value result))) - (define-vop (,(symbolicate name "-C")) - ,@(when translate - `((:translate ,translate))) - (:policy :fast-safe) - (:args (object :scs (descriptor-reg)) - (value :scs ,scs :target result)) - (:info index) - (:arg-types ,type - (:constant (load/store-index ,scale - ,(eval lowtag) - ,(eval offset))) - ,el-type) - (:results (result :scs ,scs)) - (:result-types ,el-type) - (:generator 5 - (inst ,(ecase size (:byte 'stb) (:short 'sth)) - value - (- (+ (* ,offset n-word-bytes) (* index ,scale)) ,lowtag) - object) - (move value result)))))) diff --git a/src/compiler/hppa/memory.lisp b/src/compiler/hppa/memory.lisp deleted file mode 100644 index a31221daf3..0000000000 --- a/src/compiler/hppa/memory.lisp +++ /dev/null @@ -1,21 +0,0 @@ -(in-package "SB-VM") - -;;; Cell-Ref and Cell-Set are used to define VOPs like CAR, where the offset to -;;; be read or written is a property of the VOP used. Cell-Setf is similar to -;;; Cell-Set, but delivers the new value as the result. -;;; -(define-vop (cell-ref) - (:args (object :scs (descriptor-reg))) - (:results (value :scs (descriptor-reg any-reg))) - (:variant-vars offset lowtag) - (:policy :fast-safe) - (:generator 4 - (loadw value object offset lowtag))) -;;; -(define-vop (cell-set) - (:args (object :scs (descriptor-reg)) - (value :scs (descriptor-reg any-reg null zero))) - (:variant-vars offset lowtag) - (:policy :fast-safe) - (:generator 1 - (storew value object offset lowtag))) diff --git a/src/compiler/hppa/move.lisp b/src/compiler/hppa/move.lisp deleted file mode 100644 index ff2c85dc21..0000000000 --- a/src/compiler/hppa/move.lisp +++ /dev/null @@ -1,296 +0,0 @@ -;;;; the HPPA VM definition of operand loading/saving and the Move VOP - -;;;; This software is part of the SBCL system. See the README file for -;;;; more information. -;;;; -;;;; This software is derived from the CMU CL system, which was -;;;; written at Carnegie Mellon University and released into the -;;;; public domain. The software is in the public domain and is -;;;; provided with absolutely no warranty. See the COPYING and CREDITS -;;;; files for more information. - -(in-package "SB-VM") - -(define-move-fun (load-immediate 1) (vop x y) - ((null zero immediate) - (any-reg descriptor-reg)) - (let ((val (tn-value x))) - (etypecase val - (integer - (inst li (fixnumize val) y)) - (null - (move null-tn y)) - (symbol - (load-symbol y val)) - (character - (inst li (logior (ash (char-code val) n-widetag-bits) - character-widetag) y))))) - -(define-move-fun (load-number 1) (vop x y) - ((zero immediate) - (signed-reg unsigned-reg)) - (inst li (tn-value x) y)) - -(define-move-fun (load-character 1) (vop x y) - ((immediate) (character-reg)) - (inst li (char-code (tn-value x)) y)) - -(define-move-fun (load-system-area-pointer 1) (vop x y) - ((immediate) (sap-reg)) - (inst li (sap-int (tn-value x)) y)) - -(define-move-fun (load-constant 5) (vop x y) - ((constant) (descriptor-reg any-reg)) - (let ((offset (- (tn-byte-offset x) other-pointer-lowtag))) - (cond - ((typep offset '(signed-byte 11)) - (inst ldw offset code-tn y)) - (t - (inst li offset lip-tn) - (inst ldwx lip-tn code-tn y))))) - -(define-move-fun (load-stack 5) (vop x y) - ((control-stack) (any-reg descriptor-reg)) - (load-stack-tn y x)) - -(define-move-fun (load-number-stack 5) (vop x y) - ((character-stack) (character-reg) - (sap-stack) (sap-reg) - (signed-stack) (signed-reg) - (unsigned-stack) (unsigned-reg)) - (let ((nfp (current-nfp-tn vop))) - (loadw y nfp (tn-offset x)))) - -(define-move-fun (store-stack 5) (vop x y) - ((any-reg descriptor-reg null zero) (control-stack)) - (store-stack-tn y x)) - -(define-move-fun (store-number-stack 5) (vop x y) - ((character-reg) (character-stack) - (sap-reg) (sap-stack) - (signed-reg) (signed-stack) - (unsigned-reg) (unsigned-stack)) - (let ((nfp (current-nfp-tn vop))) - (storew x nfp (tn-offset y)))) - - -;;;; The Move VOP: -(define-vop (move) - (:args (x :target y - :scs (any-reg descriptor-reg zero null) - :load-if (not (location= x y)))) - (:results (y :scs (any-reg descriptor-reg control-stack) - :load-if (not (location= x y)))) - (:generator 0 - (unless (location= x y) - (sc-case y - ((any-reg descriptor-reg) - (inst move x y)) - (control-stack - (store-stack-tn y x)))))) - -(define-move-vop move :move - (any-reg descriptor-reg zero null) - (any-reg descriptor-reg)) - -;;; The MOVE-ARG VOP is used for moving descriptor values into another -;;; frame for argument or known value passing. -(define-vop (move-arg) - (:args (x :target y - :scs (any-reg descriptor-reg null zero)) - (fp :scs (any-reg) - :load-if (not (sc-is y any-reg descriptor-reg)))) - (:results (y)) - (:generator 0 - (sc-case y - ((any-reg descriptor-reg) - (move x y)) - (control-stack - (storew x fp (tn-offset y)))))) -(define-move-vop move-arg :move-arg - (any-reg descriptor-reg null zero) - (any-reg descriptor-reg)) - -;;;; Moves and coercions: - -;;; These MOVE-TO-WORD VOPs move a tagged integer to a raw full-word -;;; representation. Similarly, the MOVE-FROM-WORD VOPs converts a raw integer -;;; to a tagged bignum or fixnum. - -;;; ARG is a fixnum, so just shift it. We need a type restriction -;;; because some possible arg SCs (control-stack) overlap with -;;; possible bignum arg SCs. -(define-vop (move-to-word/fixnum) - (:args (x :scs (any-reg descriptor-reg))) - (:results (y :scs (signed-reg unsigned-reg))) - (:arg-types tagged-num) - (:note "fixnum untagging") - (:generator 1 - (inst sra x n-fixnum-tag-bits y))) - -(define-move-vop move-to-word/fixnum :move - (any-reg descriptor-reg) (signed-reg unsigned-reg)) - -;;; ARG is a non-immediate constant, load it. -(define-vop (move-to-word-c) - (:args (x :scs (constant))) - (:results (y :scs (signed-reg unsigned-reg))) - (:note "constant load") - (:generator 1 - (cond ((sb-c::tn-leaf x) - (inst li (tn-value x) y)) - (t - (loadw y code-tn (tn-offset x) other-pointer-lowtag) - (inst sra y n-fixnum-tag-bits y))))) - -(define-move-vop move-to-word-c :move - (constant) (signed-reg unsigned-reg)) - -;;; ARG is a fixnum or bignum, figure out which and load if necessary. -(define-vop (move-to-word/integer) - (:args (x :scs (descriptor-reg))) - (:results (y :scs (signed-reg unsigned-reg))) - (:note "integer to untagged word coercion") - (:generator 3 - (inst sra x n-fixnum-tag-bits y) - (inst extru x 31 2 zero-tn :=) - (loadw y x bignum-digits-offset other-pointer-lowtag))) - -(define-move-vop move-to-word/integer :move - (descriptor-reg) (signed-reg unsigned-reg)) - -;;; RESULT is a fixnum, so we can just shift. We need the result type -;;; restriction because of the control-stack ambiguity noted above. -(define-vop (move-from-word/fixnum) - (:args (x :scs (signed-reg unsigned-reg))) - (:results (y :scs (any-reg descriptor-reg))) - (:result-types tagged-num) - (:note "fixnum tagging") - (:generator 1 - (inst sll x n-fixnum-tag-bits y))) - -(define-move-vop move-from-word/fixnum :move - (signed-reg unsigned-reg) (any-reg descriptor-reg)) - -;;; RESULT may be a bignum, so we have to check. Use a worst-case -;;; cost to make sure people know they may be number consing. -(define-vop (move-from-signed) - (:args (arg :scs (signed-reg unsigned-reg) :target x)) - (:results (y :scs (any-reg descriptor-reg))) - (:temporary (:scs (non-descriptor-reg) :from (:argument 0)) x temp) - (:note "signed word to integer coercion") - (:generator 18 - (move arg x) - ;; Extract the top three bits. - (inst extrs x 2 3 temp :=) - ;; Invert them (unless they are already zero). - (inst uaddcm zero-tn temp temp) - ;; If we are left with zero, it will fit in a fixnum. So branch around - ;; the bignum-construction, doing the shift in the delay slot. - (inst comb := temp zero-tn done) - (inst sll x n-fixnum-tag-bits y) - ;; Make a single-digit bignum. - (with-fixed-allocation - (y nil temp bignum-widetag (1+ bignum-digits-offset) nil) - (storew x y bignum-digits-offset other-pointer-lowtag)) - DONE)) - -(define-move-vop move-from-signed :move - (signed-reg) (descriptor-reg)) - -(define-vop (move-from-fixnum+1) - (:args (x :scs (signed-reg unsigned-reg))) - (:results (y :scs (any-reg descriptor-reg))) - (:temporary (:scs (non-descriptor-reg)) temp) - (:vop-var vop) - (:generator 4 - ;; Extract the top three bits. - (inst extrs x 2 3 temp :=) - ;; Invert them (unless they are already zero). - (inst uaddcm zero-tn temp temp) - ;; If we are left with zero, it will fit in a fixnum. So branch around - ;; the bignum-construction, doing the shift in the delay slot. - (inst comb := temp zero-tn done) - (inst sll x n-fixnum-tag-bits y) - (load-constant vop (emit-constant (1+ sb-xc:most-positive-fixnum)) - y) - DONE)) - -(define-vop (move-from-fixnum-1 move-from-fixnum+1) - (:generator 4 - ;; Extract the top three bits. - (inst extrs x 2 3 temp :=) - ;; Invert them (unless they are already zero). - (inst uaddcm zero-tn temp temp) - ;; If we are left with zero, it will fit in a fixnum. So branch around - ;; the bignum-construction, doing the shift in the delay slot. - (inst comb := temp zero-tn done) - (inst sll x n-fixnum-tag-bits y) - (load-constant vop (emit-constant (1- sb-xc:most-negative-fixnum)) - y) - DONE)) - -;;; Check for fixnum, and possibly allocate one or two word bignum -;;; result. Use a worst-case cost to make sure people know they may -;;; be number consing. -(define-vop (move-from-unsigned) - (:note "unsigned word to integer coercion") - (:args (arg :scs (signed-reg unsigned-reg) :target x)) - (:results (y :scs (any-reg descriptor-reg))) - (:temporary (:scs (non-descriptor-reg) :from (:argument 0)) x temp) - (:generator 20 - (move arg x) - (inst srl x n-positive-fixnum-bits temp) - (inst comb := temp zero-tn done) - (inst sll x n-fixnum-tag-bits y) - (pseudo-atomic (:extra (pad-data-block (+ bignum-digits-offset 2))) - (set-lowtag other-pointer-lowtag alloc-tn y) - (inst xor temp temp temp) - (inst comclr x zero-tn zero-tn :>=) - (inst li 1 temp) - (inst sll temp n-widetag-bits temp) - (inst addi (logior (ash 1 n-widetag-bits) bignum-widetag) temp temp) - (storew temp y 0 other-pointer-lowtag)) - - (storew x y bignum-digits-offset other-pointer-lowtag) - DONE)) - -(define-move-vop move-from-unsigned :move - (unsigned-reg) (descriptor-reg)) - -;;; Move untagged numbers. -(define-vop (word-move) - (:args (x :target y - :scs (signed-reg unsigned-reg) - :load-if (not (location= x y)))) - (:results (y :scs (signed-reg unsigned-reg) - :load-if (not (location= x y)))) - (:note "word integer move") - (:generator 0 - (move x y))) - -(define-move-vop word-move :move - (signed-reg unsigned-reg) (signed-reg unsigned-reg)) - -;;; Move untagged number args/return-values. -(define-vop (move-word-arg) - (:args (x :target y - :scs (signed-reg unsigned-reg)) - (fp :scs (any-reg) - :load-if (not (sc-is y signed-reg unsigned-reg)))) - (:results (y)) - (:note "word integer argument move") - (:generator 0 - (sc-case y - ((signed-reg unsigned-reg) - (move x y)) - ((signed-stack unsigned-stack) - (storew x fp (tn-offset y)))))) - -(define-move-vop move-word-arg :move-arg - (descriptor-reg any-reg signed-reg unsigned-reg) (signed-reg unsigned-reg)) - -;;; Use standard MOVE-ARG + coercion to move an untagged number to a -;;; descriptor passing location. -(define-move-vop move-arg :move-arg - (signed-reg unsigned-reg) (any-reg descriptor-reg)) diff --git a/src/compiler/hppa/nlx.lisp b/src/compiler/hppa/nlx.lisp deleted file mode 100644 index f7b7464ef9..0000000000 --- a/src/compiler/hppa/nlx.lisp +++ /dev/null @@ -1,240 +0,0 @@ -(in-package "SB-VM") - -;;; Make a TN for the argument count passing location for a -;;; non-local entry. -(defun make-nlx-entry-arg-start-location () - (make-wired-tn *fixnum-primitive-type* immediate-arg-scn ocfp-offset)) - -;;; Save and restore dynamic environment. -;;; -;;; These VOPs are used in the reentered function to restore the appropriate -;;; dynamic environment. Currently we only save the Current-Catch and binding -;;; stack pointer. We don't need to save/restore the current unwind-protect, -;;; since unwind-protects are implicitly processed during unwinding. If there -;;; were any additional stacks, then this would be the place to restore the top -;;; pointers. - -(define-vop (save-dynamic-state) - (:results (catch :scs (descriptor-reg)) - (nfp :scs (descriptor-reg)) - (nsp :scs (descriptor-reg))) - (:vop-var vop) - (:generator 13 - (load-symbol-value catch *current-catch-block*) - (let ((cur-nfp (current-nfp-tn vop))) - (when cur-nfp - (move cur-nfp nfp))) - (move nsp-tn nsp))) - -(define-vop (restore-dynamic-state) - (:args (catch :scs (descriptor-reg)) - (nfp :scs (descriptor-reg)) - (nsp :scs (descriptor-reg))) - (:vop-var vop) - (:generator 10 - (store-symbol-value catch *current-catch-block*) - (let ((cur-nfp (current-nfp-tn vop))) - (when cur-nfp - (move nfp cur-nfp))) - (move nsp nsp-tn))) - -(define-vop (current-stack-pointer) - (:results (res :scs (any-reg descriptor-reg))) - (:generator 1 - (move csp-tn res))) - -(define-vop (current-binding-pointer) - (:results (res :scs (any-reg descriptor-reg))) - (:generator 1 - (move bsp-tn res))) - -(define-vop (current-nsp) - (:results (res :scs (any-reg descriptor-reg))) - (:generator 1 - (move res nsp-tn))) - -(define-vop (set-nsp) - (:args (nsp :scs (any-reg descriptor-reg))) - (:generator 1 - (move nsp-tn nsp))) - -;;;; Unwind block hackery: - -;;; Compute the address of the catch block from its TN, then store into the -;;; block the current Fp, Env, Unwind-Protect, and the entry PC. -;;; -(define-vop (make-unwind-block) - (:args (tn)) - (:info entry-label) - (:results (block :scs (any-reg))) - (:temporary (:scs (descriptor-reg)) temp) - (:temporary (:scs (non-descriptor-reg)) ndescr) - (:generator 22 - (inst ldo (tn-byte-offset tn) cfp-tn block) - (load-symbol-value temp *current-unwind-protect-block*) - (storew temp block unwind-block-uwp-slot) - (storew cfp-tn block unwind-block-cfp-slot) - (storew code-tn block unwind-block-code-slot) - (inst compute-lra-from-code code-tn entry-label ndescr temp) - (storew temp block catch-block-entry-pc-slot))) - -;;; Like Make-Unwind-Block, except that we also store in the specified tag, and -;;; link the block into the Current-Catch list. -;;; -(define-vop (make-catch-block) - (:args (tn) - (tag :scs (any-reg descriptor-reg))) - (:info entry-label) - (:results (block :scs (any-reg))) - (:temporary (:scs (descriptor-reg)) temp) - (:temporary (:scs (descriptor-reg) :target block :to (:result 0)) result) - (:temporary (:scs (non-descriptor-reg)) ndescr) - (:generator 44 - (inst ldo (tn-byte-offset tn) cfp-tn result) - (load-symbol-value temp *current-unwind-protect-block*) - (storew temp result catch-block-uwp-slot) - (storew cfp-tn result catch-block-cfp-slot) - (storew code-tn result catch-block-code-slot) - (inst compute-lra-from-code code-tn entry-label ndescr temp) - (storew temp result catch-block-entry-pc-slot) - - (storew tag result catch-block-tag-slot) - (load-symbol-value temp *current-catch-block*) - (storew temp result catch-block-previous-catch-slot) - (store-symbol-value result *current-catch-block*) - (move result block))) - -;;; Just set the current unwind-protect to UWP. This instantiates an -;;; unwind block as an unwind-protect. -;;; -(define-vop (set-unwind-protect) - (:args (uwp :scs (any-reg))) - (:generator 7 - (store-symbol-value uwp *current-unwind-protect-block*))) - - -(define-vop (%catch-breakup) - (:args (current-block)) - (:ignore current-block) - (:temporary (:scs (any-reg)) block) - (:policy :fast-safe) - (:generator 17 - (load-symbol-value block *current-catch-block*) - (loadw block block catch-block-previous-catch-slot) - (store-symbol-value block *current-catch-block*))) - -(define-vop (%unwind-protect-breakup) - (:args (current-block)) - (:ignore current-block) - (:temporary (:scs (any-reg)) block) - (:policy :fast-safe) - (:generator 17 - (load-symbol-value block *current-unwind-protect-block*) - (loadw block block unwind-block-uwp-slot) - (store-symbol-value block *current-unwind-protect-block*))) - - -;;;; NLX entry VOPs: - - -(define-vop (nlx-entry) - (:args (sp) ;; Note: we can't list an sc-restriction, 'cause any load vops - ;; would be inserted before the LRA. - (start) - (count)) - (:results (values :more t)) - (:temporary (:scs (descriptor-reg)) move-temp) - (:info label nvals) - (:save-p :force-to-stack) - (:vop-var vop) - (:generator 30 - (emit-return-pc label) - (note-this-location vop :non-local-entry) - (cond ((zerop nvals)) - ((= nvals 1) - (loadw (tn-ref-tn values) start) - (inst comclr count zero-tn zero-tn :<>) - (move null-tn (tn-ref-tn values) t)) - (t - (collect ((defaults)) - (do ((i 0 (1+ i)) - (tn-ref values (tn-ref-across tn-ref))) - ((null tn-ref)) - (let ((default-lab (gen-label)) - (tn (tn-ref-tn tn-ref))) - (defaults (cons default-lab tn)) - (inst comb := zero-tn count default-lab) - (inst addi (fixnumize -1) count count) - (sc-case tn - ((descriptor-reg any-reg) - (loadw tn start i)) - (control-stack - (loadw move-temp start i) - (store-stack-tn tn move-temp))))) - (let ((defaulting-done (gen-label))) - (emit-label defaulting-done) - (assemble (:elsewhere) - (dolist (def (defaults)) - (emit-label (car def)) - (let ((tn (cdr def))) - (sc-case tn - ((descriptor-reg any-reg) - (move null-tn tn)) - (control-stack - (store-stack-tn tn null-tn))))) - (inst b defaulting-done :nullify t)))))) - (load-stack-tn csp-tn sp))) - - -(define-vop (nlx-entry-multiple) - (:args (top :target dst) (start :target src) (count :target num)) - ;; Again, no SC restrictions for the args, 'cause the loading would - ;; happen before the entry label. - (:info label) - (:temporary (:scs (any-reg) :from (:argument 0)) dst) - (:temporary (:scs (any-reg) :from (:argument 1)) src) - (:temporary (:scs (any-reg) :from (:argument 2)) num) - (:temporary (:scs (descriptor-reg)) temp) - (:results (new-start) (new-count)) - (:save-p :force-to-stack) - (:vop-var vop) - (:generator 30 - (emit-return-pc label) - (note-this-location vop :non-local-entry) - (let ((loop (gen-label)) - (done (gen-label))) - - ;; Copy args. - (load-stack-tn dst top) - (move start src) - (move count num) - - ;; Establish results. - (sc-case new-start - (any-reg (move dst new-start)) - (control-stack (store-stack-tn new-start dst))) - (inst comb := num zero-tn done :nullify t) - (sc-case new-count - (any-reg (move num new-count)) - (control-stack (store-stack-tn new-count num))) - - ;; Copy stuff on stack. - (emit-label loop) - (inst ldwm n-word-bytes src temp) - (inst addib :<> (fixnumize -1) num loop) - (inst stwm temp n-word-bytes dst) - - (emit-label done) - (move dst csp-tn)))) - -;;; This VOP is just to force the TNs used in the cleanup onto the stack. -;;; -(define-vop (uwp-entry) - (:info label) - (:save-p :force-to-stack) - (:results (block) (start) (count)) - (:ignore block start count) - (:vop-var vop) - (:generator 0 - (emit-return-pc label) - (note-this-location vop :non-local-entry))) diff --git a/src/compiler/hppa/parms.lisp b/src/compiler/hppa/parms.lisp deleted file mode 100644 index 8bf3bbf7da..0000000000 --- a/src/compiler/hppa/parms.lisp +++ /dev/null @@ -1,143 +0,0 @@ -(in-package "SB-VM") - -; normally assem-scheduler-p is t, and nil if debugging the assembler -; but apparently we don't trust any of the instruction definitions. -(defconstant sb-assem:assem-scheduler-p nil) -(defconstant sb-assem:+inst-alignment-bytes+ 4) -(defconstant sb-assem:+assem-max-locations+ 68) ; see number-location - -(defconstant +backend-fasl-file-implementation+ :hppa) -(defconstant +backend-page-bytes+ 4096) - -;;;; Machine Architecture parameters: -(eval-when (:compile-toplevel :load-toplevel :execute) - -;;; number of bits per word where a word holds one lisp descriptor -(defconstant n-word-bits 32) - -;;; the natural width of a machine word (as seen in e.g. register width, -;;; address space) -(defconstant n-machine-word-bits 32) - -(defconstant float-sign-shift 31) - -(defconstant single-float-bias 126) -(defconstant-eqx single-float-exponent-byte (byte 8 23) #'equalp) -(defconstant-eqx single-float-significand-byte (byte 23 0) #'equalp) -(defconstant single-float-normal-exponent-min 1) -(defconstant single-float-normal-exponent-max 254) -(defconstant single-float-hidden-bit (ash 1 23)) - -(defconstant double-float-bias 1022) -(defconstant-eqx double-float-exponent-byte (byte 11 20) #'equalp) -(defconstant-eqx double-float-significand-byte (byte 20 0) #'equalp) -(defconstant double-float-normal-exponent-min 1) -(defconstant double-float-normal-exponent-max #x7FE) -(defconstant double-float-hidden-bit (ash 1 20)) - -(defconstant single-float-digits - (+ (byte-size single-float-significand-byte) 1)) - -(defconstant double-float-digits - (+ (byte-size double-float-significand-byte) n-word-bits 1)) - -(defconstant float-inexact-trap-bit (ash 1 0)) -(defconstant float-underflow-trap-bit (ash 1 1)) -(defconstant float-overflow-trap-bit (ash 1 2)) -(defconstant float-divide-by-zero-trap-bit (ash 1 3)) -(defconstant float-invalid-trap-bit (ash 1 4)) - -(defconstant float-round-to-nearest 0) -(defconstant float-round-to-zero 1) -(defconstant float-round-to-positive 2) -(defconstant float-round-to-negative 3) - -(defconstant-eqx float-rounding-mode (byte 2 7) #'equalp) -(defconstant-eqx float-sticky-bits (byte 5 27) #'equalp) -(defconstant-eqx float-traps-byte (byte 5 0) #'equalp) -(defconstant-eqx float-exceptions-byte (byte 5 27) #'equalp) -(defconstant-eqx float-condition-bit (ash 1 26) #'equalp) -(defconstant float-fast-bit 0) ; No fast mode on HPPA. - - - -;;;; Description of the target address space. - -;;; Where to put the different spaces. -;;; -(defconstant linkage-table-space-start #x1000) -(defconstant linkage-table-space-end linkage-table-space-start) ; 0 size - -(defconstant read-only-space-start #x4b000000) -(defconstant read-only-space-end #x4dff0000) - -(defconstant static-space-start #x4e000000) -(defconstant static-space-end #x4fff0000) - -(defparameter dynamic-0-space-start #x50000000) -(defparameter dynamic-0-space-end #x5fff0000) - -); eval-when - -;;; When doing external branching on hppa (e.g. inst ble) -;;; we must know which space we want to jump into (text, code) - -;; The space-register holding the lisp heap. -(defconstant lisp-heap-space 5) - -;; The space-register holding the C text heap. -(defconstant c-text-space 4) - - -;;;; Other random constants. - -(defenum () - atomic-flag - interrupted-flag) - -(defenum (:start 8) - halt-trap - pending-interrupt-trap - cerror-trap - breakpoint-trap - fun-end-breakpoint-trap - single-step-breakpoint-trap - single-step-around-trap - single-step-before-trap - single-step-after-trap - error-trap) - -;;;; Static symbols. - -;;; These symbols are loaded into static space directly after NIL so -;;; that the system can compute their address by adding a constant -;;; amount to NIL. -;;; -;;; The fdefn objects for the static functions are loaded into static -;;; space directly after the static symbols. That way, the raw-addr -;;; can be loaded directly out of them by indirecting relative to NIL. -(defconstant-eqx +static-symbols+ - `#(,@+common-static-symbols+) - #'equalp) - -(defconstant-eqx +static-fdefns+ - #(length - two-arg-+ - two-arg-- - two-arg-* - two-arg-/ - two-arg-< - two-arg-> - two-arg-= - two-arg-<= - two-arg->= - two-arg-/= - eql - %negate - two-arg-and - two-arg-ior - two-arg-xor - two-arg-gcd - two-arg-lcm) - #'equalp) - diff --git a/src/compiler/hppa/pred.lisp b/src/compiler/hppa/pred.lisp deleted file mode 100644 index be39072a87..0000000000 --- a/src/compiler/hppa/pred.lisp +++ /dev/null @@ -1,41 +0,0 @@ -(in-package "SB-VM") - - -;;;; The Branch VOP. - -;;; The unconditional branch, emitted when we can't drop through to the desired -;;; destination. Dest is the continuation we transfer control to. -;;; -(define-vop (branch) - (:info dest) - (:generator 5 - (inst b dest :nullify t))) - - -;;;; Generic conditional VOPs - -;;; The generic conditional branch, emitted immediately after test -;;; VOPs that only set flags. - -(define-vop (branch-if) - (:info dest not-p flags) - (:ignore dest not-p flags) - (:generator 0 - (error "BRANCH-IF not yet implemented"))) - -(defun convert-conditional-move-p (node dst-tn x-tn y-tn) - (declare (ignore node dst-tn x-tn y-tn)) - nil) - - -;;;; Conditional VOPs: - -(define-vop (if-eq) - (:args (x :scs (any-reg descriptor-reg zero null)) - (y :scs (any-reg descriptor-reg zero null))) - (:conditional) - (:info target not-p) - (:policy :fast-safe) - (:translate eq) - (:generator 3 - (inst bc := not-p x y target))) diff --git a/src/compiler/hppa/sap.lisp b/src/compiler/hppa/sap.lisp deleted file mode 100644 index b88ca1ca24..0000000000 --- a/src/compiler/hppa/sap.lisp +++ /dev/null @@ -1,252 +0,0 @@ -;;;; the HPPA VM definition of SAP operations - -;;;; This software is part of the SBCL system. See the README file for -;;;; more information. -;;;; -;;;; This software is derived from the CMU CL system, which was -;;;; written at Carnegie Mellon University and released into the -;;;; public domain. The software is in the public domain and is -;;;; provided with absolutely no warranty. See the COPYING and CREDITS -;;;; files for more information. - -(in-package "SB-VM") - -;;;; Moves and coercions: - -;;; Move a tagged SAP to an untagged representation. -(define-vop (move-to-sap) - (:args (x :scs (any-reg descriptor-reg))) - (:results (y :scs (sap-reg))) - (:note "system area pointer indirection") - (:generator 1 - (loadw y x sap-pointer-slot other-pointer-lowtag))) - -(define-move-vop move-to-sap :move - (descriptor-reg) (sap-reg)) - -;;; Move an untagged SAP to a tagged representation. -(define-vop (move-from-sap) - (:args (sap :scs (sap-reg) :to :save)) - (:temporary (:scs (non-descriptor-reg)) ndescr) - (:results (res :scs (descriptor-reg))) - (:note "system area pointer allocation") - (:generator 20 - (with-fixed-allocation (res nil ndescr sap-widetag sap-size nil) - (storew sap res sap-pointer-slot other-pointer-lowtag)))) - -(define-move-vop move-from-sap :move - (sap-reg) (descriptor-reg)) - -;;; Move untagged sap values. -(define-vop (sap-move) - (:args (x :target y - :scs (sap-reg) - :load-if (not (location= x y)))) - (:results (y :scs (sap-reg) - :load-if (not (location= x y)))) - (:note "SAP move") - (:generator 0 - (move x y))) - -(define-move-vop sap-move :move - (sap-reg) (sap-reg)) - -;;; Move untagged sap args/return-values. -(define-vop (move-sap-arg) - (:args (x :target y - :scs (sap-reg)) - (fp :scs (any-reg) - :load-if (not (sc-is y sap-reg)))) - (:results (y)) - (:note "SAP argument move") - (:generator 0 - (sc-case y - (sap-reg - (move x y)) - (sap-stack - (storew x fp (tn-offset y)))))) - -(define-move-vop move-sap-arg :move-arg - (descriptor-reg sap-reg) (sap-reg)) - -;;; Use standard MOVE-ARG + coercion to move an untagged sap to a -;;; descriptor passing location. -(define-move-vop move-arg :move-arg - (sap-reg) (descriptor-reg)) - -;;;; SAP-INT and INT-SAP -(define-vop (sap-int) - (:args (sap :scs (sap-reg) :target int)) - (:arg-types system-area-pointer) - (:results (int :scs (unsigned-reg))) - (:result-types unsigned-num) - (:translate sap-int) - (:policy :fast-safe) - (:generator 1 - (move sap int))) - -(define-vop (int-sap) - (:args (int :scs (unsigned-reg) :target sap)) - (:arg-types unsigned-num) - (:results (sap :scs (sap-reg))) - (:result-types system-area-pointer) - (:translate int-sap) - (:policy :fast-safe) - (:generator 1 - (move int sap))) - -;;;; POINTER+ and POINTER- -(define-vop (pointer+) - (:translate sap+) - (:args (ptr :scs (sap-reg)) - (offset :scs (signed-reg immediate))) - (:arg-types system-area-pointer signed-num) - (:results (res :scs (sap-reg))) - (:result-types system-area-pointer) - (:policy :fast-safe) - (:generator 1 - (sc-case offset - (signed-reg - (inst add ptr offset res)) - (immediate - (cond - ((and (< (tn-value offset) (ash 1 10)) - (> (tn-value offset) (- (ash 1 10)))) - (inst addi (tn-value offset) ptr res)) - (t - (inst li (tn-value offset) res) - (inst add ptr res res))))))) - -(define-vop (pointer-) - (:translate sap-) - (:args (ptr1 :scs (sap-reg)) - (ptr2 :scs (sap-reg))) - (:arg-types system-area-pointer system-area-pointer) - (:policy :fast-safe) - (:results (res :scs (signed-reg))) - (:result-types signed-num) - (:generator 1 - (inst sub ptr1 ptr2 res))) - -;;;; mumble-SYSTEM-REF and mumble-SYSTEM-SET -(macrolet ((def-system-ref-and-set - (ref-name set-name sc type size &optional signed) - (let ((ref-name-c (symbolicate ref-name "-C")) - (set-name-c (symbolicate set-name "-C"))) - `(progn - (define-vop (,ref-name) - (:translate ,ref-name) - (:policy :fast-safe) - (:args (object :scs (sap-reg)) - (offset :scs (signed-reg))) - (:arg-types system-area-pointer signed-num) - (:results (result :scs (,sc))) - (:result-types ,type) - (:generator 5 - (inst ,(ecase size - (:byte 'ldbx) - (:short 'ldhx) - (:long 'ldwx) - (:float 'fldx)) - offset object result) - ,@(when (and signed (not (eq size :long))) - `((inst extrs result 31 ,(ecase size - (:byte 8) - (:short 16)) - result))))) - (define-vop (,ref-name-c) - (:translate ,ref-name) - (:policy :fast-safe) - (:args (object :scs (sap-reg))) - (:arg-types system-area-pointer - (:constant ,(if (eq size :float) - '(signed-byte 5) - '(signed-byte 14)))) - (:info offset) - (:results (result :scs (,sc))) - (:result-types ,type) - (:generator 4 - (inst ,(ecase size - (:byte 'ldb) - (:short 'ldh) - (:long 'ldw) - (:float 'flds)) - offset object result) - ,@(when (and signed (not (eq size :long))) - `((inst extrs result 31 ,(ecase size - (:byte 8) - (:short 16)) - result))))) - (define-vop (,set-name) - (:translate ,set-name) - (:policy :fast-safe) - (:args (object :scs (sap-reg) - ,@(unless (eq size :float) '(:target sap))) - (offset :scs (signed-reg)) - (value :scs (,sc) :target result)) - (:arg-types system-area-pointer signed-num ,type) - (:results (result :scs (,sc))) - (:result-types ,type) - ,@(unless (eq size :float) - '((:temporary (:scs (sap-reg) :from (:argument 0)) sap))) - (:generator 5 - ,@(if (eq size :float) - `((inst fstx value offset object) - (unless (location= value result) - (inst funop :copy value result))) - `((inst add object offset sap) - (inst ,(ecase size (:byte 'stb) (:short 'sth) (:long 'stw)) - value 0 sap) - (move value result))))) - (define-vop (,set-name-c) - (:translate ,set-name) - (:policy :fast-safe) - (:args (object :scs (sap-reg)) - (value :scs (,sc) :target result)) - (:arg-types system-area-pointer - (:constant ,(if (eq size :float) - '(signed-byte 5) - '(signed-byte 14))) - ,type) - (:info offset) - (:results (result :scs (,sc))) - (:result-types ,type) - (:generator 5 - ,@(if (eq size :float) - `((inst fsts value offset object) - (unless (location= value result) - (inst funop :copy value result))) - `((inst ,(ecase size (:byte 'stb) (:short 'sth) (:long 'stw)) - value offset object) - (move value result))))))))) - (def-system-ref-and-set sap-ref-8 %set-sap-ref-8 - unsigned-reg positive-fixnum :byte nil) - (def-system-ref-and-set signed-sap-ref-8 %set-signed-sap-ref-8 - signed-reg tagged-num :byte t) - (def-system-ref-and-set sap-ref-16 %set-sap-ref-16 - unsigned-reg positive-fixnum :short nil) - (def-system-ref-and-set signed-sap-ref-16 %set-signed-sap-ref-16 - signed-reg tagged-num :short t) - (def-system-ref-and-set sap-ref-32 %set-sap-ref-32 - unsigned-reg unsigned-num :long nil) - (def-system-ref-and-set signed-sap-ref-32 %set-signed-sap-ref-32 - signed-reg signed-num :long t) - (def-system-ref-and-set sap-ref-sap %set-sap-ref-sap - sap-reg system-area-pointer :long) - (def-system-ref-and-set sap-ref-lispobj %set-sap-ref-lispobj - descriptor-reg * :long) - (def-system-ref-and-set sap-ref-single %set-sap-ref-single - single-reg single-float :float) - (def-system-ref-and-set sap-ref-double %set-sap-ref-double - double-reg double-float :float)) - -;;; Noise to convert normal lisp data objects into SAPs. -(define-vop (vector-sap) - (:translate vector-sap) - (:policy :fast-safe) - (:args (vector :scs (descriptor-reg))) - (:results (sap :scs (sap-reg))) - (:result-types system-area-pointer) - (:generator 2 - (inst addi (- (* vector-data-offset n-word-bytes) other-pointer-lowtag) - vector sap))) diff --git a/src/compiler/hppa/show.lisp b/src/compiler/hppa/show.lisp deleted file mode 100644 index 247ac80fe5..0000000000 --- a/src/compiler/hppa/show.lisp +++ /dev/null @@ -1,25 +0,0 @@ -(in-package "SB-VM") - -(define-vop (print) - (:args (object :scs (descriptor-reg any-reg) :target nl0)) - (:results) - (:save-p t) - (:temporary (:sc any-reg :offset nl0-offset :from (:argument 0)) nl0) - (:temporary (:sc any-reg :offset cfunc-offset) cfunc) - (:temporary (:sc control-stack :offset nfp-save-offset) nfp-save) - (:temporary (:scs (non-descriptor-reg)) temp) - (:vop-var vop) - (:generator 100 - (let ((cur-nfp (current-nfp-tn vop))) - (when cur-nfp - (store-stack-tn nfp-save cur-nfp)) - (move object nl0) - (inst li (make-fixup "debug_print" :foreign) cfunc) - (let ((fixup (make-fixup "call_into_c" :foreign))) - (inst ldil fixup temp) - (inst ble fixup c-text-space temp)) - (inst addi 64 nsp-tn nsp-tn) - (inst addi -64 nsp-tn nsp-tn) - (when cur-nfp - (load-stack-tn cur-nfp nfp-save))))) - diff --git a/src/compiler/hppa/subprim.lisp b/src/compiler/hppa/subprim.lisp deleted file mode 100644 index 01c638e474..0000000000 --- a/src/compiler/hppa/subprim.lisp +++ /dev/null @@ -1,39 +0,0 @@ -(in-package "SB-VM") - - - -;;;; Length - -(define-vop (length/list) - (:translate length) - (:args (object :scs (descriptor-reg) :target ptr)) - (:arg-types list) - (:temporary (:scs (descriptor-reg) :from (:argument 0)) ptr) - (:temporary (:scs (non-descriptor-reg)) temp) - (:temporary (:scs (any-reg) :to (:result 0) :target result) - count) - (:results (result :scs (any-reg descriptor-reg))) - (:policy :fast-safe) - (:vop-var vop) - (:save-p :compute-only) - (:generator 50 - (move object ptr) - (inst comb := ptr null-tn done) - (inst li 0 count) - - (inst extru ptr 31 3 temp) - (inst comib :<> list-pointer-lowtag temp lose :nullify t) - (loadw ptr ptr cons-cdr-slot list-pointer-lowtag) - - LOOP - (inst addi (fixnumize 1) count count) - (inst comb := ptr null-tn done :nullify t) - (inst extru ptr 31 3 temp) - (inst comib := list-pointer-lowtag temp loop :nullify t) - (loadw ptr ptr cons-cdr-slot list-pointer-lowtag) - - LOSE - (cerror-call vop 'object-not-list-error ptr) - - DONE - (move count result))) diff --git a/src/compiler/hppa/system.lisp b/src/compiler/hppa/system.lisp deleted file mode 100644 index edeec7cf89..0000000000 --- a/src/compiler/hppa/system.lisp +++ /dev/null @@ -1,228 +0,0 @@ -(in-package "SB-VM") - - -;;;; Type frobbing VOPs - -;FIX this vop got instruction-exploded after mips convert, look at old hppa -(define-vop (widetag-of) - (:translate widetag-of) - (:policy :fast-safe) - (:args (object :scs (descriptor-reg))) - (:temporary (:scs (non-descriptor-reg)) temp1 temp2) - (:results (result :scs (unsigned-reg))) - (:result-types positive-fixnum) - (:generator 6 - (inst li lowtag-mask temp1) - (inst li other-pointer-lowtag temp2) - (inst and temp1 object temp1) - (inst xor temp1 temp2 temp1) - (inst comb := temp1 zero-tn OTHER-PTR) - (inst li (logxor other-pointer-lowtag fun-pointer-lowtag) temp2) - (inst xor temp1 temp2 temp1) - (inst comb := temp1 zero-tn FUNCTION-PTR) - (inst li fixnum-tag-mask temp1) ; pick off fixnums - (inst li 1 temp2) - (inst and temp1 object result) - (inst comb := result zero-tn DONE) - - (inst and object temp2 result) - (inst comb :<> result zero-tn LOWTAG-ONLY :nullify t) - - ;; must be an other immediate - (inst li widetag-mask temp2) - (inst b DONE) - (inst and temp2 object result) - - FUNCTION-PTR - (load-type result object (- fun-pointer-lowtag)) - (inst b done :nullify t) - - LOWTAG-ONLY - (inst li lowtag-mask temp1) - (inst b done) - (inst and object temp1 result) - - OTHER-PTR - (load-type result object (- other-pointer-lowtag)) - - DONE)) - -(define-vop (%other-pointer-widetag) - (:translate %other-pointer-widetag) - (:policy :fast-safe) - (:args (object :scs (descriptor-reg))) - (:results (result :scs (unsigned-reg))) - (:result-types positive-fixnum) - (:generator 6 - (load-type result object (- other-pointer-lowtag)))) - -(define-vop (fun-subtype) - (:translate fun-subtype) - (:policy :fast-safe) - (:args (function :scs (descriptor-reg))) - (:results (result :scs (unsigned-reg))) - (:result-types positive-fixnum) - (:generator 6 - (load-type result function (- fun-pointer-lowtag)))) - -(define-vop (get-header-data) - (:translate get-header-data) - (:policy :fast-safe) - (:args (x :scs (descriptor-reg))) - (:results (res :scs (unsigned-reg))) - (:result-types positive-fixnum) - (:generator 6 - (loadw res x 0 other-pointer-lowtag) - (inst srl res n-widetag-bits res))) - -;;; FIXME-lav, not sure we need data of type immediate and zero, test without, -;;; if so revert to old hppa code -(define-vop (set-header-data) - (:translate set-header-data) - (:policy :fast-safe) - (:args (x :scs (descriptor-reg) :target res) - (data :scs (any-reg immediate zero))) - (:arg-types * positive-fixnum) - (:results (res :scs (descriptor-reg))) - (:temporary (:scs (non-descriptor-reg)) t1 t2) - (:generator 6 - (loadw t1 x 0 other-pointer-lowtag) - ;; replace below 2 inst with: (mask widetag-mask t1 t1) - (inst li widetag-mask t2) - (inst and t1 t2 t1) - (sc-case data - (any-reg - (inst sll data (- n-widetag-bits 2) t2) - (inst or t1 t2 t1)) - (immediate - (inst li (ash (tn-value data) n-widetag-bits) t2) - (inst or t1 t2 t1)) - (zero)) - - (storew t1 x 0 other-pointer-lowtag) - (move x res))) - -(define-vop (pointer-hash) - (:translate pointer-hash) - (:args (ptr :scs (any-reg descriptor-reg))) - (:results (res :scs (any-reg descriptor-reg))) - (:policy :fast-safe) - (:generator 1 - (inst zdep ptr n-positive-fixnum-bits n-positive-fixnum-bits res))) - -;;;; Allocation - -(define-vop (dynamic-space-free-pointer) - (:results (int :scs (sap-reg))) - (:result-types system-area-pointer) - (:translate dynamic-space-free-pointer) - (:policy :fast-safe) - (:generator 1 - (move alloc-tn int))) - -(define-vop (binding-stack-pointer-sap) - (:results (int :scs (sap-reg))) - (:result-types system-area-pointer) - (:translate binding-stack-pointer-sap) - (:policy :fast-safe) - (:generator 1 - (move bsp-tn int))) - -(define-vop (control-stack-pointer-sap) - (:results (int :scs (sap-reg))) - (:result-types system-area-pointer) - (:translate control-stack-pointer-sap) - (:policy :fast-safe) - (:generator 1 - (move csp-tn int))) - - -;;;; Code object frobbing. - -(define-vop (code-instructions) - (:translate code-instructions) - (:policy :fast-safe) - (:args (code :scs (descriptor-reg))) - (:temporary (:scs (non-descriptor-reg)) ndescr) - (:results (sap :scs (sap-reg))) - (:result-types system-area-pointer) - (:generator 10 - (loadw ndescr code 0 other-pointer-lowtag) - (inst srl ndescr n-widetag-bits ndescr) - (inst sll ndescr word-shift ndescr) - (inst addi (- other-pointer-lowtag) ndescr ndescr) - (inst add code ndescr sap))) - -(define-vop (compute-fun) - (:args (code :scs (descriptor-reg)) - (offset :scs (signed-reg unsigned-reg))) - (:arg-types * positive-fixnum) - (:results (func :scs (descriptor-reg))) - (:temporary (:scs (non-descriptor-reg)) ndescr) - (:generator 10 - (loadw ndescr code 0 other-pointer-lowtag) - ;; FIXME-lav: replace below two with DEPW - (inst srl ndescr n-widetag-bits ndescr) - (inst sll ndescr word-shift ndescr) - (inst add ndescr offset ndescr) - (inst addi (- fun-pointer-lowtag other-pointer-lowtag) ndescr ndescr) - (inst add ndescr code func))) - - -;;;; Other random VOPs. - - -(defknown sb-unix::receive-pending-interrupt () (values)) -(define-vop (sb-unix::receive-pending-interrupt) - (:policy :fast-safe) - (:translate sb-unix::receive-pending-interrupt) - (:generator 1 - (inst break pending-interrupt-trap))) - - -(define-vop (halt) - (:generator 1 - (inst break halt-trap))) - -#+hpux -(define-vop (setup-return-from-lisp-stub) - (:results) - (:save-p t) - (:temporary (:sc any-reg :offset nl0-offset) nl0) - (:temporary (:sc any-reg :offset cfunc-offset) cfunc) - (:temporary (:sc control-stack :offset nfp-save-offset) nfp-save) - (:temporary (:scs (non-descriptor-reg)) temp) - (:vop-var vop) - (:generator 100 - (let ((stub (make-fixup 'return-from-lisp-stub :assembly-routine))) - (inst li stub nl0)) - (let ((cur-nfp (current-nfp-tn vop))) - (when cur-nfp - (store-stack-tn nfp-save cur-nfp)) - (inst li (make-fixup "setup_return_from_lisp_stub" :foreign) cfunc) - (let ((fixup (make-fixup "call_into_c" :foreign))) - (inst ldil fixup temp) - (inst ble fixup c-text-space temp)) - (inst addi 64 nsp-tn nsp-tn) - (inst addi -64 nsp-tn nsp-tn) - (when cur-nfp - (load-stack-tn cur-nfp nfp-save))))) - -;;;; Dynamic vop count collection support - -(define-vop (count-me) - (:args (count-vector :scs (descriptor-reg))) - (:info index) - (:temporary (:scs (non-descriptor-reg)) count) - (:generator 1 - (let ((offset - (- (* (+ index vector-data-offset) n-word-bytes) other-pointer-lowtag))) - (inst ldw offset count-vector count) - (inst addi 1 count count) - (inst stw count offset count-vector)))) - -;;;; Dummy definition for a spin-loop hint VOP -(define-vop () - (:translate spin-loop-hint) - (:policy :fast-safe) - (:generator 0)) diff --git a/src/compiler/hppa/target-insts.lisp b/src/compiler/hppa/target-insts.lisp deleted file mode 100644 index cf1a188b23..0000000000 --- a/src/compiler/hppa/target-insts.lisp +++ /dev/null @@ -1,39 +0,0 @@ -;;;; This file is for stuff which was in CMU CL's insts.lisp -;;;; file, but which in the SBCL build process can't be compiled -;;;; into code for the cross-compilation host. - -;;;; This software is part of the SBCL system. See the README file for -;;;; more information. -;;;; -;;;; This software is derived from the CMU CL system, which was -;;;; written at Carnegie Mellon University and released into the -;;;; public domain. The software is in the public domain and is -;;;; provided with absolutely no warranty. See the COPYING and CREDITS -;;;; files for more information. - -(in-package "SB-HPPA-ASM") - -(defun break-control (chunk inst stream dstate) - (declare (ignore inst)) - (flet ((nt (x) (if stream (note x dstate)))) - (let ((trap (break-im5 chunk dstate))) - (case trap - (#.cerror-trap - (nt "Cerror trap") - (handle-break-args #'snarf-error-junk trap stream dstate)) - (#.breakpoint-trap - (nt "Breakpoint trap")) - (#.pending-interrupt-trap - (nt "Pending interrupt trap")) - (#.halt-trap - (nt "Halt trap")) - (#.fun-end-breakpoint-trap - (nt "Function end breakpoint trap")) - (#.single-step-around-trap - (nt "Single step around trap")) - (#.error-trap - (nt "Error trap") - (handle-break-args (lambda (sap offset trap &optional length-only) - (snarf-error-junk sap offset trap length-only nil)) - trap - stream dstate)))))) diff --git a/src/compiler/hppa/type-vops.lisp b/src/compiler/hppa/type-vops.lisp deleted file mode 100644 index 6fa5179dd6..0000000000 --- a/src/compiler/hppa/type-vops.lisp +++ /dev/null @@ -1,164 +0,0 @@ -;;;; type testing and checking VOPs for the HPPA VM - -;;;; This software is part of the SBCL system. See the README file for -;;;; more information. -;;;; -;;;; This software is derived from the CMU CL system, which was -;;;; written at Carnegie Mellon University and released into the -;;;; public domain. The software is in the public domain and is -;;;; provided with absolutely no warranty. See the COPYING and CREDITS -;;;; files for more information. - -(in-package "SB-VM") - -;;; Test generation utilities. -(defun %test-fixnum (value temp target not-p) - (declare (ignore temp)) - (assemble () - (inst extru value 31 2 zero-tn (if not-p := :<>)) - (inst b target :nullify t))) - -(defun %test-fixnum-and-headers (value temp target not-p headers &key value-tn-ref) - (let ((drop-through (gen-label))) - (assemble () - (inst extru value 31 2 zero-tn :<>) - (inst b (if not-p drop-through target) :nullify t)) - (%test-headers value temp target not-p nil headers - :drop-through drop-through - :value-tn-ref value-tn-ref))) - -(defun %test-immediate (value temp target not-p immediate) - (assemble () - (inst extru value 31 8 temp) - (inst bci := not-p immediate temp target))) - -(defun %test-lowtag (value temp target not-p lowtag &key temp-loaded) - (assemble () - (unless temp-loaded - (inst extru value 31 3 temp)) - (inst bci := not-p lowtag temp target))) - -(defun %test-headers (value temp target not-p function-p headers - &key (drop-through (gen-label)) temp-loaded - value-tn-ref) - (declare (ignore value-tn-ref)) - (let ((lowtag (if function-p fun-pointer-lowtag other-pointer-lowtag))) - (multiple-value-bind - (equal greater-or-equal when-true when-false) - ;; EQUAL and GREATER-OR-EQUAL are the conditions for branching to - ;; TARGET. WHEN-TRUE and WHEN-FALSE are the labels to branch to when - ;; we know it's true and when we know it's false respectively. - (if not-p - (values :<> :< drop-through target) - (values := :>= target drop-through)) - (assemble () - (%test-lowtag value temp when-false t lowtag - :temp-loaded temp-loaded) - (inst ldb (- 3 lowtag) value temp) - (do ((remaining headers (cdr remaining))) - ((null remaining)) - (let ((header (car remaining)) - (last (null (cdr remaining)))) - (cond - ((atom header) - (if last - (inst bci equal nil header temp target) - (inst bci := nil header temp when-true))) - (t - (let ((start (car header)) - (end (cdr header))) - (unless (= start bignum-widetag) - (inst bci :> nil start temp when-false)) - (if last - (inst bci greater-or-equal nil end temp target) - (inst bci :>= nil end temp when-true))))))) - (emit-label drop-through))))) - -;;;; Other integer ranges. - -;;; A (signed-byte 32) can be represented with either fixnum or a bignum with -;;; exactly one digit. -(defun signed-byte-32-test (value temp not-p target not-target) - (multiple-value-bind - (yep nope) - (if not-p - (values not-target target) - (values target not-target)) - (assemble () - (inst extru value 31 2 zero-tn :<>) - (inst b yep :nullify t) - (inst extru value 31 3 temp) - (inst bci :<> nil other-pointer-lowtag temp nope) - (loadw temp value 0 other-pointer-lowtag) - (inst bci := not-p (+ (ash 1 n-widetag-bits) bignum-widetag) temp target))) - (values)) - -(define-vop (signed-byte-32-p type-predicate) - (:translate signed-byte-32-p) - (:generator 45 - (signed-byte-32-test value temp not-p target not-target) - NOT-TARGET)) - -;;; An (unsigned-byte 32) can be represented with either a positive fixnum, a -;;; bignum with exactly one positive digit, or a bignum with exactly two digits -;;; and the second digit all zeros. -(defun unsigned-byte-32-test (value temp not-p target not-target) - (let ((nope (if not-p target not-target))) - (assemble () - ;; Is it a fixnum? - (inst extru value 31 2 zero-tn :<>) - (inst b fixnum) - (move value temp t) - - ;; If not, is it an other pointer? - (inst extru value 31 3 temp) - (inst bci :<> nil other-pointer-lowtag temp nope) - ;; Get the header. - (loadw temp value 0 other-pointer-lowtag) - ;; Is it one? - (inst bci := nil (+ (ash 1 n-widetag-bits) bignum-widetag) temp single-word) - ;; If it's other than two, we can't be an (unsigned-byte 32) - (inst bci :<> nil (+ (ash 2 n-widetag-bits) bignum-widetag) temp nope) - ;; Get the second digit. - (loadw temp value (1+ bignum-digits-offset) other-pointer-lowtag) - ;; All zeros, its an (unsigned-byte 32). - ;; Dont nullify comb here, because we cant guarantee target is forward - (inst comb (if not-p := :<>) temp zero-tn not-target) - (inst nop) - (inst b target) - - SINGLE-WORD - ;; Get the single digit. - (loadw temp value bignum-digits-offset other-pointer-lowtag) - - ;; positive implies (unsigned-byte 32). - FIXNUM - (inst bc :>= not-p temp zero-tn target))) - (values)) - -(define-vop (unsigned-byte-32-p type-predicate) - (:translate unsigned-byte-32-p) - (:generator 45 - (unsigned-byte-32-test value temp not-p target not-target) - NOT-TARGET)) - -;;;; List/symbol types: -;;; -;;; symbolp (or symbol (eq nil)) -;;; consp (and list (not (eq nil))) - -(define-vop (symbolp type-predicate) - (:translate symbolp) - (:generator 12 - (inst bc := nil value null-tn (if not-p drop-thru target)) - (test-type value temp target not-p (symbol-widetag)) - DROP-THRU)) - -(define-vop (consp type-predicate) - (:translate consp) - (:generator 8 - (inst bc := nil value null-tn (if not-p target drop-thru)) - (test-type value temp target not-p (list-pointer-lowtag)) - DROP-THRU)) - - diff --git a/src/compiler/hppa/values.lisp b/src/compiler/hppa/values.lisp deleted file mode 100644 index 2df3b9ad1d..0000000000 --- a/src/compiler/hppa/values.lisp +++ /dev/null @@ -1,136 +0,0 @@ -(in-package "SB-VM") - -(define-vop (reset-stack-pointer) - (:args (ptr :scs (any-reg))) - (:generator 1 - (move ptr csp-tn))) - -(define-vop (%%nip-values) - (:args (last-nipped-ptr :scs (any-reg) :target dest) - (last-preserved-ptr :scs (any-reg) :target src) - (moved-ptrs :scs (any-reg) :more t)) - (:results (r-moved-ptrs :scs (any-reg) :more t)) - (:temporary (:sc any-reg) src) - (:temporary (:sc any-reg) dest) - (:temporary (:sc descriptor-reg) temp) - (:ignore r-moved-ptrs) - (:generator 1 - (move last-preserved-ptr src) - (move last-nipped-ptr dest) - (inst comb :>= src csp-tn DONE :nullify t) - LOOP - (inst ldwm n-word-bytes src temp) - (inst addi n-word-bytes dest dest) - (storew temp dest -1) - (inst comb :> csp-tn src LOOP) - (inst nop) - DONE - (move dest csp-tn) - (inst sub src dest src) - (loop for moved = moved-ptrs then (tn-ref-across moved) - while moved do - (sc-case (tn-ref-tn moved) - ((descriptor-reg any-reg) - (inst sub (tn-ref-tn moved) src (tn-ref-tn moved))) - ((control-stack) - (load-stack-tn temp (tn-ref-tn moved)) - (inst sub temp src temp) - (store-stack-tn (tn-ref-tn moved) temp)))))) - -;;; Push some values onto the stack, returning the start and number of values -;;; pushed as results. It is assumed that the Vals are wired to the standard -;;; argument locations. Nvals is the number of values to push. -;;; -;;; The generator cost is pseudo-random. We could get it right by defining a -;;; bogus SC that reflects the costs of the memory-to-memory moves for each -;;; operand, but this seems unworthwhile. -;;; -(define-vop (push-values) - (:args - (vals :more t)) - (:results (start :scs (any-reg)) - (count :scs (any-reg))) - (:info nvals) - (:temporary (:scs (descriptor-reg)) temp) - (:temporary (:scs (descriptor-reg) - :to (:result 0) - :target start) - start-temp) - (:generator 20 - (move csp-tn start-temp) - (inst addi (* nvals n-word-bytes) csp-tn csp-tn) - (do ((val vals (tn-ref-across val)) - (i 0 (1+ i))) - ((null val)) - (let ((tn (tn-ref-tn val))) - (sc-case tn - (descriptor-reg - (storew tn start-temp i)) - (control-stack - (load-stack-tn temp tn) - (storew temp start-temp i))))) - (move start-temp start) - (inst li (fixnumize nvals) count))) - -;;; Push a list of values on the stack, returning Start and Count as used in -;;; unknown values continuations. -;;; -(define-vop (values-list) - (:args (arg :scs (descriptor-reg) :target list)) - (:arg-types list) - (:policy :fast-safe) - (:results (start :scs (any-reg)) - (count :scs (any-reg))) - (:temporary (:scs (descriptor-reg) :from (:argument 0)) list) - (:temporary (:scs (descriptor-reg)) temp) - (:temporary (:scs (non-descriptor-reg)) ndescr) - (:vop-var vop) - (:save-p :compute-only) - (:generator 0 - (move arg list) - (move csp-tn start) - LOOP - (inst comb := list null-tn done) - (loadw temp list cons-car-slot list-pointer-lowtag) - (loadw list list cons-cdr-slot list-pointer-lowtag) - (inst addi n-word-bytes csp-tn csp-tn) - (storew temp csp-tn -1) - (inst extru list 31 n-lowtag-bits ndescr) - (inst comib := list-pointer-lowtag ndescr loop) - (inst nop) - (cerror-call vop 'bogus-arg-to-values-list-error list) - DONE - (inst sub csp-tn start count))) - -;;; Copy the more arg block to the top of the stack so we can use them -;;; as function arguments. -;;; -(define-vop (%more-arg-values) - (:args (context :scs (descriptor-reg any-reg) :target src) - (skip :scs (any-reg zero immediate)) - (num :scs (any-reg) :target count)) - (:arg-types * positive-fixnum positive-fixnum) - (:temporary (:sc any-reg :from (:argument 0)) src) - (:temporary (:sc any-reg :from (:argument 2)) dst end) - (:temporary (:sc descriptor-reg :from (:argument 1)) temp) - (:results (start :scs (any-reg)) - (count :scs (any-reg))) - (:generator 20 - (sc-case skip - (zero - (move context src)) - (immediate - (inst addi (* (tn-value skip) n-word-bytes) context src)) - (any-reg - (inst add skip context src))) - (move num count) - (inst comb := num zero-tn done) - (move csp-tn start t) - (move csp-tn dst) - (inst add count csp-tn csp-tn) - (inst addi (- n-word-bytes) csp-tn end) - LOOP - (inst ldwm n-word-bytes src temp) - (inst comb :<> dst end loop) - (inst stwm temp n-word-bytes dst) - DONE)) diff --git a/src/compiler/hppa/vm.lisp b/src/compiler/hppa/vm.lisp deleted file mode 100644 index 096f4ad7b7..0000000000 --- a/src/compiler/hppa/vm.lisp +++ /dev/null @@ -1,381 +0,0 @@ -;;;; miscellaneous VM definition noise for HPPA - -;;;; This software is part of the SBCL system. See the README file for -;;;; more information. -;;;; -;;;; This software is derived from the CMU CL system, which was -;;;; written at Carnegie Mellon University and released into the -;;;; public domain. The software is in the public domain and is -;;;; provided with absolutely no warranty. See the COPYING and CREDITS -;;;; files for more information. - -(in-package "SB-VM") - - -;;;; Registers - -(eval-when (:compile-toplevel :load-toplevel :execute) - (defvar *register-names* (make-array 32 :initial-element nil))) - -(macrolet ((defreg (name offset) - (let ((offset-sym (symbolicate name "-OFFSET"))) - `(eval-when (:compile-toplevel :load-toplevel :execute) - (defconstant ,offset-sym ,offset) - (setf (svref *register-names* ,offset-sym) ,(symbol-name name))))) - (defregset (name &rest regs) - `(eval-when (:compile-toplevel :load-toplevel :execute) - (defparameter ,name - (list ,@(mapcar #'(lambda (name) (symbolicate name "-OFFSET")) regs)))))) - ;; Wired-zero - (defreg zero 0) - ;; This gets trashed by the C call convention. - (defreg nfp 1) ;; and saved by lisp before calling C - (defreg cfunc 2) - ;; These are the callee saves, so these registers are stay live over - ;; call-out. - (defreg csp 3) - (defreg cfp 4) - (defreg bsp 5) - (defreg null 6) - (defreg alloc 7) - (defreg code 8) - (defreg fdefn 9) - (defreg lexenv 10) - (defreg nargs 11) - (defreg ocfp 12) - (defreg lra 13) - (defreg a0 14) - (defreg a1 15) - (defreg a2 16) - (defreg a3 17) - (defreg a4 18) - ;; This is where the caller-saves registers start, but we don't - ;; really care because we need to clear the above after call-out to - ;; make sure no pointers into oldspace are kept around. - (defreg a5 19) - (defreg l0 20) - (defreg l1 21) - (defreg l2 22) - ;; These are the 4 C argument registers. - (defreg nl3 23) - (defreg nl2 24) - (defreg nl1 25) - (defreg nl0 26) - ;; The global Data Pointer. We just leave it alone, because we - ;; don't need it. - (defreg dp 27) - ;; These two are use for C return values. - (defreg nl4 28) - (defreg nl5 29) - (defreg nsp 30) - (defreg lip 31) - - (defregset non-descriptor-regs - nl0 nl1 nl2 nl3 nl4 nl5 cfunc nargs nfp) - - (defregset descriptor-regs - a0 a1 a2 a3 a4 a5 fdefn lexenv ocfp lra l0 l1 l2) - - (defregset boxed-regs - code fdefn lexenv ocfp lra - a0 a1 a2 a3 a4 a5 - l0 l1 l2 nfp) - - (defregset *register-arg-offsets* - a0 a1 a2 a3 a4 a5) - - (defregset reserve-descriptor-regs - fdefn lexenv) - - (defregset reserve-non-descriptor-regs - cfunc)) - -(!define-storage-bases -(define-storage-base registers :finite :size 32) -(define-storage-base float-registers :finite :size 64) -(define-storage-base control-stack :unbounded :size 8) -(define-storage-base non-descriptor-stack :unbounded :size 0) -(define-storage-base constant :non-packed) -(define-storage-base immediate-constant :non-packed) -) - -(!define-storage-classes - - ;; Non-immediate constants in the constant pool - (constant constant) - - ;; ZERO and NULL are in registers. - (zero immediate-constant) - (null immediate-constant) - (fp-single-zero immediate-constant) - (fp-double-zero immediate-constant) - - ;; Anything else that can be an immediate. - (immediate immediate-constant) - - - ;; **** The stacks. - - ;; The control stack. (Scanned by GC) - (control-stack control-stack) - - ;; We put ANY-REG and DESCRIPTOR-REG early so that their SC-NUMBER - ;; is small and therefore the error trap information is smaller. - ;; Moving them up here from their previous place down below saves - ;; ~250K in core file size. --njf, 2006-01-27 - - ;; Immediate descriptor objects. Don't have to be seen by GC, but nothing - ;; bad will happen if they are. (fixnums, characters, header values, etc). - (any-reg - registers - :locations #.(append non-descriptor-regs descriptor-regs) - :reserve-locations #.(append reserve-non-descriptor-regs - reserve-descriptor-regs) - :constant-scs (constant zero immediate) - :save-p t - :alternate-scs (control-stack)) - - ;; Pointer descriptor objects. Must be seen by GC. - (descriptor-reg registers - :locations #.descriptor-regs - :reserve-locations #.reserve-descriptor-regs - :constant-scs (constant null immediate) - :save-p t - :alternate-scs (control-stack)) - - ;; The non-descriptor stacks. - (signed-stack non-descriptor-stack) ; (signed-byte 32) - (unsigned-stack non-descriptor-stack) ; (unsigned-byte 32) - (character-stack non-descriptor-stack) ; non-descriptor characters. - (sap-stack non-descriptor-stack) ; System area pointers. - (single-stack non-descriptor-stack) ; single-floats - (double-stack non-descriptor-stack - :element-size 2 :alignment 2) ; double floats. - (complex-single-stack non-descriptor-stack :element-size 2) - (complex-double-stack non-descriptor-stack :element-size 4 :alignment 2) - - ;; **** Things that can go in the integer registers. - - ;; Non-Descriptor characters - (character-reg registers - :locations #.non-descriptor-regs - :reserve-locations #.reserve-non-descriptor-regs - :constant-scs (immediate) - :save-p t - :alternate-scs (character-stack)) - - ;; Non-Descriptor SAP's (arbitrary pointers into address space) - (sap-reg registers - :locations #.non-descriptor-regs - :reserve-locations #.reserve-non-descriptor-regs - :constant-scs (immediate) - :save-p t - :alternate-scs (sap-stack)) - - ;; Non-Descriptor (signed or unsigned) numbers. - (signed-reg registers - :locations #.non-descriptor-regs - :reserve-locations #.reserve-non-descriptor-regs - :constant-scs (zero immediate) - :save-p t - :alternate-scs (signed-stack)) - (unsigned-reg registers - :locations #.non-descriptor-regs - :reserve-locations #.reserve-non-descriptor-regs - :constant-scs (zero immediate) - :save-p t - :alternate-scs (unsigned-stack)) - - ;; Random objects that must not be seen by GC. Used only as temporaries. - (non-descriptor-reg registers - :locations #.non-descriptor-regs) - - ;; Pointers to the interior of objects. Used only as an temporary. - (interior-reg registers - :locations (#.lip-offset)) - - - ;; **** Things that can go in the floating point registers. - - ;; Non-Descriptor single-floats. - (single-reg float-registers - :locations #.(loop for i from 4 to 31 collect i) - :constant-scs (fp-single-zero) - :save-p t - :alternate-scs (single-stack)) - - ;; Non-Descriptor double-floats. - (double-reg float-registers - :locations #.(loop for i from 4 to 31 collect i) - :constant-scs (fp-double-zero) - :save-p t - :alternate-scs (double-stack)) - - (complex-single-reg float-registers - :locations #.(loop for i from 4 to 30 by 2 collect i) - :element-size 2 - :constant-scs () - :save-p t - :alternate-scs (complex-single-stack)) - - (complex-double-reg float-registers - :locations #.(loop for i from 4 to 30 by 2 collect i) - :element-size 2 - :constant-scs () - :save-p t - :alternate-scs (complex-double-stack)) - - (catch-block control-stack :element-size catch-block-size) - (unwind-block control-stack :element-size unwind-block-size) - - ;; floating point numbers temporarily stuck in integer registers for c-call - (single-int-carg-reg registers - :locations (26 25 24 23) - :alternate-scs () - :constant-scs ()) - (double-int-carg-reg registers - :locations (25 23) - :constant-scs () - :alternate-scs () -; :alignment 2 ;is this needed? -; :element-size 2 - )) - - -;;;; Make some random tns for important registers. - -;;; how can we address reg L0 through L0-offset when it is not -;;; defined here ? do all registers have an -offset and this is -;;; redundant work ? -;;; -;;; FIXME-lav: move this into arch-generic-helpers -(macrolet ((defregtn (name sc) - (let ((offset-sym (symbolicate name "-OFFSET")) - (tn-sym (symbolicate name "-TN"))) - `(defparameter ,tn-sym - (make-random-tn :kind :normal - :sc (sc-or-lose ',sc) - :offset ,offset-sym))))) - - ;; These, we access by foo-TN only - - (defregtn zero any-reg) - (defregtn nargs any-reg) - ;; FIXME-lav: 20080820: not a fix, but fdefn and lexenv is used in assembly-rtns - (defregtn fdefn descriptor-reg) ; FIXME-lav, not used - (defregtn lexenv descriptor-reg) ; FIXME-lav, not used - - (defregtn nfp descriptor-reg) ; why not descriptor-reg ? - (defregtn ocfp any-reg) ; why not descriptor-reg ? - - (defregtn null descriptor-reg) - - (defregtn bsp any-reg) - (defregtn cfp any-reg) - (defregtn csp any-reg) - (defregtn alloc any-reg) - (defregtn nsp any-reg) - - (defregtn code descriptor-reg) - (defregtn lip interior-reg)) - -;; And some floating point values. -(defparameter fp-single-zero-tn - (make-random-tn :kind :normal - :sc (sc-or-lose 'single-reg) - :offset 0)) -(defparameter fp-double-zero-tn - (make-random-tn :kind :normal - :sc (sc-or-lose 'double-reg) - :offset 0)) - - -;;; If VALUE can be represented as an immediate constant, then return -;;; the appropriate SC number, otherwise return NIL. -(defun immediate-constant-sc (value) - (typecase value - ((integer 0 0) - zero-sc-number) - (null - null-sc-number) - ((or (integer #.sb-xc:most-negative-fixnum #.sb-xc:most-positive-fixnum) - #-sb-xc-host system-area-pointer ; no object can be a SAP in the host - character) - immediate-sc-number) - (symbol - (if (static-symbol-p value) - immediate-sc-number - nil)) - (single-float - (if (eql value $0f0) - fp-single-zero-sc-number - nil)) - (double-float - (if (eql value $0d0) - fp-double-zero-sc-number - nil)))) - -(defun boxed-immediate-sc-p (sc) - (or (eql sc zero-sc-number) - (eql sc null-sc-number) - (eql sc immediate-sc-number))) - -;;;; Function Call Parameters - -;;; The SC numbers for register and stack arguments/return values. -;;; -(defconstant immediate-arg-scn any-reg-sc-number) -(defconstant control-stack-arg-scn control-stack-sc-number) - -(eval-when (:compile-toplevel :load-toplevel :execute) - -;;; Offsets of special stack frame locations -(defconstant ocfp-save-offset 0) -(defconstant lra-save-offset 1) -(defconstant nfp-save-offset 2) - -;;; The number of arguments/return values passed in registers. -;;; -(defconstant register-arg-count 6) - -;;; Names to use for the argument registers. -;;; -(defconstant-eqx register-arg-names '(a0 a1 a2 a3 a4 a5) #'equal) - -) ; EVAL-WHEN - - -;;; A list of TN's describing the register arguments. -;;; -(defparameter *register-arg-tns* - (mapcar (lambda (n) - (make-random-tn :kind :normal - :sc (sc-or-lose 'descriptor-reg) - :offset n)) - *register-arg-offsets*)) - -;;; This is used by the debugger. -(defconstant single-value-return-byte-offset 4) - -;;; This function is called by debug output routines that want a pretty name -;;; for a TN's location. It returns a thing that can be printed with PRINC. -(defun location-print-name (tn) - (declare (type tn tn)) - (let ((sb (sb-name (sc-sb (tn-sc tn)))) - (offset (tn-offset tn))) - (ecase sb - (registers (or (svref *register-names* offset) - (format nil "R~D" offset))) - (float-registers (format nil "F~D" offset)) - (control-stack (format nil "CS~D" offset)) - (non-descriptor-stack (format nil "NS~D" offset)) - (constant (format nil "Const~D" offset)) - (immediate-constant "Immed")))) - -(defun combination-implementation-style (node) - (declare (type sb-c::combination node) (ignore node)) - (values :default nil)) - -(defun primitive-type-indirect-cell-type (ptype) - (declare (ignore ptype)) - nil) diff --git a/src/compiler/info-functions.lisp b/src/compiler/info-functions.lisp deleted file mode 100644 index 1c04d7cc42..0000000000 --- a/src/compiler/info-functions.lisp +++ /dev/null @@ -1,266 +0,0 @@ -;;;; miscellaneous functions which use INFO -;;;; -;;;; (In CMU CL, these were in globaldb.lisp. They've been moved here -;;;; because references to INFO can't be compiled correctly until -;;;; globaldb initialization is complete, and the SBCL technique for -;;;; initializing the global database in the cross-compiler isn't -;;;; completed until load time.) - -;;;; This software is part of the SBCL system. See the README file for -;;;; more information. -;;;; -;;;; This software is derived from the CMU CL system, which was -;;;; written at Carnegie Mellon University and released into the -;;;; public domain. The software is in the public domain and is -;;;; provided with absolutely no warranty. See the COPYING and CREDITS -;;;; files for more information. - -(in-package "SB-C") - -;;;; internal utilities defined in terms of INFO - -(defun check-variable-name (name &key - (context "local variable") - (signal-via #'compiler-error)) - (unless (legal-variable-name-p name) - (funcall signal-via "~@<~S~[~; is a keyword and~; is not a symbol and~ - ~] cannot be used as a ~A.~@:>" - name - (typecase name - (null 0) - (keyword 1) - (t 2)) - context)) - name) - -;;; Check that NAME is a valid function name, returning the name if -;;; OK, and signalling an error if not. In addition to checking for -;;; basic well-formedness, we also check that symbol names are not NIL -;;; or the name of a special form. -(defun check-fun-name (name) - (typecase name - (list - (unless (legal-fun-name-p name) - (compiler-error "~@<Illegal function name: ~S.~@:>" name))) - (symbol - (when (eq (info :function :kind name) :special-form) - (compiler-error "~@<Special form is an illegal function name: ~S.~@:>" - name))) - (t - (compiler-error "~@<Illegal function name: ~S.~@:>" name))) - name) - -;;; Record a new function definition, and check its legality. -(defun proclaim-as-fun-name (name) - - ;; legal name? - (check-fun-name name) - - ;; KLUDGE: This can happen when eg. compiling a NAMED-LAMBDA, and isn't - ;; guarded against elsewhere -- so we want to assert package locks here. The - ;; reason we do it only when stomping on existing stuff is because we want - ;; to keep - ;; (WITHOUT-PACKAGE-LOCKS (DEFUN LOCKED:FOO ...)) - ;; viable, which requires no compile-time violations in the harmless cases. - (with-single-package-locked-error () - (flet ((assert-it () - (assert-symbol-home-package-unlocked name "proclaiming ~S as a function"))) - - (let ((kind (info :function :kind name))) - ;; scrubbing old data I: possible collision with a macro - (when (and (fboundp name) (eq :macro kind)) - (assert-it) - (compiler-style-warn "~S was previously defined as a macro." name) - (setf (info :function :where-from name) :assumed) - (clear-info :function :macro-function name)) - - (unless (eq :function kind) - (assert-it) - ;; There's no reason to store (:FUNCTION :KIND) for names which - ;; could only be of kind :FUNCTION if anything. - (unless (pcl-methodfn-name-p name) - (setf (info :function :kind name) :function)))))) - - ;; scrubbing old data II: dangling forward references - ;; - ;; (This could happen if someone executes PROCLAIM FTYPE at - ;; macroexpansion time, which is bad style, or at compile time, e.g. - ;; in EVAL-WHEN (:COMPILE) inside something like DEFSTRUCT, in which - ;; case it's reasonable style. Either way, NAME is no longer a free - ;; function.) - (when (boundp '*ir1-namespace*) ; when compiling - (unless (block-compile *compilation*) - (remhash name (free-funs *ir1-namespace*)))) - - (values)) - -;;; This is called to do something about SETF functions that overlap -;;; with SETF macros. Perhaps we should interact with the user to see -;;; whether the macro should be blown away, but for now just give a -;;; warning. Due to the weak semantics of the (SETF FUNCTION) name, we -;;; can't assume that they aren't just naming a function (SETF FOO) -;;; for the heck of it. NAME is already known to be well-formed. -(defun warn-if-setf-macro (name) - ;; Never warn about this situation when running the cross-compiler. - ;; SBCL provides expanders/inverses *and* functions for most SETFable things - ;; even when CLHS does not specifically state that #'(SETF x) exists. - #+sb-xc-host (declare (ignore name)) - #-sb-xc-host - (let ((stem (second name))) - (when (info :setf :expander stem) - (compiler-style-warn - "defining function ~S when ~S already has a SETF macro" - name stem))) - (values)) - -;;; Make NAME no longer be a function name: clear everything back to -;;; the default. -(defun undefine-fun-name (name) - (when name - (macrolet ((frob (&rest types) - `(clear-info-values - name ',(mapcar (lambda (x) - (meta-info-number (meta-info :function x))) - types)))) - ;; Note that this does not clear the :DEFINITION. - ;; That's correct, because if we lose the association between a - ;; symbol and its #<fdefn> object, it could lead to creation of - ;; a non-unique #<fdefn> for a name. - (frob :info - :type ; Hmm. What if it was proclaimed- shouldn't it stay? - :where-from ; Ditto. - :inlinep - :kind - :macro-function - :inlining-data - :source-transform - :assumed-type))) - (values)) - -;;; part of what happens with DEFUN, also with some PCL stuff: Make -;;; NAME known to be a function definition. -(defun become-defined-fun-name (name) - (proclaim-as-fun-name name) - (when (eq (info :function :where-from name) :assumed) - (setf (info :function :where-from name) :defined) - (if (info :function :assumed-type name) - (clear-info :function :assumed-type name)))) - -;;; Unpack (INFO :FUNCTION :INLINING-DATA FUN-NAME). If an explicit expansion -;;; is not stored but FUN-NAME is a structure constructor, reconstitute the -;;; expansion from the defstruct description. Secondary value is T if the expansion -;;; was explicit. See SAVE-INLINE-EXPANSION-P for why we care. -;;; (Essentially, once stored then always stored, lest inconsistency result) -;;; If we have just a DXABLE-ARGS, or nothing at all, return NIL and NIL. -;;; If called on a string or anything that is not a function designator, -;;; return NIL and NIL. -(declaim (ftype (sfunction (t) (values list boolean)) - fun-name-inline-expansion)) -(defun fun-name-inline-expansion (fun-name) - (multiple-value-bind (answer winp) (info :function :inlining-data fun-name) - (typecase answer - ;; an INLINING-DATA is a DXABLE-ARGS, so test it first - (inlining-data (setq answer (inlining-data-expansion answer))) - (dxable-args (setq answer nil winp nil))) - (when (and (not winp) (symbolp fun-name)) - (let ((info (info :function :source-transform fun-name))) - (when (typep info '(cons defstruct-description (eql :constructor))) - (let* ((dd (car info)) (spec (assq fun-name (dd-constructors dd)))) - (aver spec) - (setq answer `(lambda ,@(structure-ctor-lambda-parts dd (cdr spec)))))))) - (values answer winp))) -(defun fun-name-dx-args (fun-name) - (let ((answer (info :function :inlining-data fun-name))) - (when (typep answer 'dxable-args) - (dxable-args-list answer)))) - -;;;; ANSI Common Lisp functions which are defined in terms of the info -;;;; database - -(defun sb-xc:macro-function (symbol &optional env) - "If SYMBOL names a macro in ENV, returns the expansion function, -else returns NIL. If ENV is unspecified or NIL, use the global environment -only." - ;; local function definitions (ordinary) can shadow a global macro - (typecase env - #+(and sb-fasteval (not sb-xc-host)) - (sb-interpreter:basic-env - (multiple-value-bind (kind def) - (sb-interpreter:find-lexical-fun env symbol) - (when def - (return-from sb-xc:macro-function (when (eq kind :macro) def))))) - (lexenv - (let ((def (cdr (assoc symbol (lexenv-funs env))))) - (when def - (return-from sb-xc:macro-function - (when (typep def '(cons (eql macro))) (cdr def))))))) - (values (info :function :macro-function symbol))) - -(defun (setf sb-xc:macro-function) (function symbol &optional environment) - (declare (symbol symbol) (type function function)) - (when environment - ;; Note: Technically there could be an ENV optional argument to SETF - ;; MACRO-FUNCTION, but since ANSI says that the consequences of - ;; supplying a non-nil one are undefined, we don't allow it. - ;; (Thus our implementation of this unspecified behavior is to - ;; complain. SInce the behavior is unspecified, this is conforming.:-) - (error "Non-NIL environment argument in SETF of MACRO-FUNCTION ~S: ~S" - symbol environment)) - (when (eq (info :function :kind symbol) :special-form) - (error "~S names a special form." symbol)) - (with-single-package-locked-error (:symbol symbol "setting the macro-function of ~S") - (clear-info :function :type symbol) - (setf (info :function :kind symbol) :macro) - (setf (info :function :macro-function symbol) function) - #-sb-xc-host (install-guard-function symbol `(:macro ,symbol))) - function) - -(defun sb-xc:compiler-macro-function (name &optional env) - "If NAME names a compiler-macro in ENV, return the expansion function, else -return NIL. Can be set with SETF when ENV is NIL." - (legal-fun-name-or-type-error name) - ;; CLHS 3.2.2.1: Creating a lexical binding for the function name - ;; not only creates a new local function or macro definition, but - ;; also shadows[2] the compiler macro. - (unless (fun-locally-defined-p name env) - ;; Note: CMU CL used to return NIL here when a NOTINLINE - ;; declaration was in force. That's fairly logical, given the - ;; specified effect of NOTINLINE declarations on compiler-macro - ;; expansion. However, (1) it doesn't seem to be consistent with - ;; the ANSI spec for COMPILER-MACRO-FUNCTION, and (2) it would - ;; give surprising behavior for (SETF (COMPILER-MACRO-FUNCTION - ;; FOO) ...) in the presence of a (PROCLAIM '(NOTINLINE FOO)). So - ;; we don't do it. - (values (info :function :compiler-macro-function name)))) - -;;; FIXME: we don't generate redefinition warnings for these. -(defun (setf sb-xc:compiler-macro-function) (function name &optional env) - (declare (type (or symbol list) name) - (type (or function null) function)) - (when env - ;; ANSI says this operation is undefined. - (error "can't SETF COMPILER-MACRO-FUNCTION when ENV is non-NIL")) - (when (eq (info :function :kind name) :special-form) - (error "~S names a special form." name)) - (with-single-package-locked-error - (:symbol name "setting the compiler-macro-function of ~A") - (setf (info :function :compiler-macro-function name) function) - function)) - -;;;; a subset of DOCUMENTATION functionality for bootstrapping - -;; Return the number of calls to NAME that IR2 emitted as full calls, -;; not counting calls via #'F that went untracked. -;; Return 0 if the answer is nonzero but a warning was already signaled -;; about any full calls were emitted. This return convention satisfies the -;; intended use of this statistic - to decide whether to generate a warning -;; about failure to inline NAME, which is shown at most once per name -;; to avoid unleashing a flood of identical warnings. -(defun emitted-full-call-count (name) - (let ((status (car (info :function :emitted-full-calls name)))) - (and (integerp status) - ;; Bit 0 tells whether any call was NOT in the presence of - ;; a 'notinline' declaration, thus eligible to be inline. - ;; Bit 1 tells whether any warning was emitted yet. - (= (logand status 3) #b01) - (ash status -2)))) ; the call count as tracked by IR2 diff --git a/src/compiler/info-vector.lisp b/src/compiler/info-vector.lisp index 80819f54c0..647f288d24 100644 --- a/src/compiler/info-vector.lisp +++ b/src/compiler/info-vector.lisp @@ -44,35 +44,35 @@ ;;; * Names which are lists of length other than 2, or improper lists, ;;; or whose elements are not both symbols, are disqualified. -;;; Packed vector layout -;;; -------------------- +;;; Packed format +;;; ------------- ;;; Because the keys to the inner lists are integers in the range 0 to 63, ;;; either 5 or 10 keys will fit into a fixnum depending on word size. ;;; This permits one memory read to retrieve a collection of keys. In packed ;;; format, an ordered set of keys ("fields") is called a "descriptor". ;;; -;;; Descriptors are stored from element 0 upward in the packed vector, -;;; and data are indexed downward from the last element of the vector. +;;; Descriptors are stored from element 0 upward in the packed-info, +;;; and data are indexed downward from the last element. ;;; -;;; #(descriptor0 descriptor1 ... descriptorN valueN ... value1 value0) +;;; [descriptor0 descriptor1 ... descriptorN valueN ... value1 value0] ;;; -;;; e.g. The field at absolute index 3 - vector element 0, bit position 18 - +;;; e.g. The field at absolute index 3 (physical element 0, bit position 18) ;;; will find its data at index (- END 3). In this manner, it doesn't matter ;;; how many more descriptors exist. ;;; A "group" comprises all the info for a particular Name, and its list ;;; of types may may span descriptors, though rarely. -;;; An "auxilliary key" is the first element of a 2-list Name. It is interposed -;;; within the data portion of the vector after the preceding info group. +;;; An "auxiliary key" is the first element of a 2-list Name. It is interposed +;;; within the data portion of the packed-info after the preceding info group. ;;; Descriptors are self-delimiting in that the first field in a group ;;; indicates the number of additional fields in the group. -;;; Unpacked vector layout -;;; ---------------------- +;;; Unpacked format +;;; --------------- ;;; This representation is used transiently during insertion/deletion. ;;; It is a concatenation of plists as a vector, interposing at the splice -;;; points the auxilliary key for the group, except for the root name which -;;; does not store an auxilliary key. +;;; points the auxiliary key for the group, except for the root name which +;;; does not store an auxiliary key. ;;; ;;; Unpacked vector format looks like: ;;; @@ -82,13 +82,29 @@ ;;; ^ ;;; info group for the primary Name, a/k/a "root symbol", starts here ;;; -;;; One can envision that the first info group stores its auxilliary key +;;; One can envision that the first info group stores its auxiliary key ;;; at vector index -1 when thinking about the correctness of algorithms ;;; that process unpacked info-vectors. -;;; See !TEST-PACKIFY-INFOS for examples of each format. +;;; See TEST-PACKIFY-INFOS for examples of each format. ;;;;; Some stuff moved from 'globaldb.lisp': +;;; The structure constructor is never called +(sb-xc:defstruct (packed-info (:copier %copy-packed-info) (:predicate nil) (:constructor nil)) + cells) +(declaim (freeze-type packed-info)) +#-sb-xc-host +(eval-when (:compile-toplevel :load-toplevel :execute) + (let ((dd (find-defstruct-description 'packed-info))) + (setf (dd-flags dd) (logior (dd-flags dd) +dd-varylen+)))) +(eval-when (#-sb-xc-host :compile-toplevel) + (sb-xc:defmacro make-packed-info (n) + `(locally (declare (sb-c::tlab :system)) ; will be ignored if #-system-tlabs + (%new-instance ,(find-layout 'packed-info) (+ ,n ,sb-vm:instance-data-start)))) + (sb-xc:defmacro copy-packed-info (x) + `(locally (declare (sb-c::tlab :system)) + (%copy-packed-info ,x)))) + (defconstant info-num-mask (ldb (byte info-number-bits 0) -1)) ; #b111111 ;; Using 6 bits per packed field, 5 infos can be described in a 30-bit fixnum, @@ -101,20 +117,47 @@ (deftype info-descriptor () `(signed-byte ,sb-vm:n-fixnum-bits)) ;; An empty info-vector. Its 0th field describes that there are no more fields. -(defconstant-eqx +nil-packed-infos+ #(0) #'equalp) - -;; FDEFINITIONs have an info-number that admits slightly clever logic -;; for INFO-VECTOR-FDEFN. Do not change this constant without -;; careful examination of that function. +(defglobal +nil-packed-infos+ + (let ((v (make-packed-info 1))) + (setf (%info-ref v 0) 0) + v)) + +;;; %SYMBOL-INFO is a primitive object accessor defined in 'objdef.lisp' +;;; But in the host Lisp, there is no such thing. Instead, SYMBOL-%INFO +;;; is kept as a property on the host symbol. +;;; The compatible "primitive" accessor must be a SETFable place. +#+sb-xc-host +(progn + (declaim (inline symbol-%info)) + (defun symbol-%info (symbol) + (get symbol :sb-xc-globaldb-info)) + (defun symbol-dbinfo (symbol) (symbol-%info symbol)) + ;; In the target, UPDATE-SYMBOL-INFO is defined in 'symbol.lisp'. + (defun update-symbol-info (symbol update-fn) + ;; Never pass NIL to an update-fn. Pass the minimal info-vector instead, + ;; a vector describing 0 infos and 0 auxiliary keys. + (let ((newval (funcall update-fn (or (symbol-%info symbol) +nil-packed-infos+)))) + (when newval + (setf (get symbol :sb-xc-globaldb-info) newval)) + (values)))) + +;;; :DEFINITION has an info-number that admits slightly clever logic. +;;; * SB-INTERPRETER:SPECIAL-FORM-HANDLER only needs to decode the first +;;; info-number in a packed-info to test if :DEFINITION is present. +;;; * FIND-FDEFN only needs to extract one info-number after finding +;;; the proper auxiliary key {SETF, CAS, etc} in the data portion. +;;; Do not change this without careful examination of those functions. (defconstant +fdefn-info-num+ info-num-mask) ;; Extract a field from a packed info descriptor. ;; A field is either a count of info-numbers, or an info-number. (declaim (inline packed-info-field)) -(defun packed-info-field (vector desc-index field-index) +(defun packed-info-field (packed-info desc-index field-index) + ;; (declare (optimize (safety 0))) ; comment out when debugging (ldb (byte info-number-bits (* (the (mod #.+infos-per-word+) field-index) info-number-bits)) - (the info-descriptor (svref vector desc-index)))) + (the info-descriptor + (%info-ref (the packed-info packed-info) desc-index)))) ;; Compute the number of elements needed to hold unpacked VECTOR after packing. ;; This is not "compute-packed-info-size" since that could be misconstrued @@ -127,7 +170,7 @@ (declare (type index index end n-fields)) (loop ;; 'length' is the number of vector elements in this info group, - ;; including itself but not including its auxilliary key. + ;; including itself but not including its auxiliary key. (let ((length (the index (svref vector index)))) ;; Divide by 2 because we only count one field for the entry, but the ;; input vector had 2 cells per entry. Add 1 because the group's field @@ -150,7 +193,7 @@ (defmacro make-info-descriptor (val shift) (if (> sb-vm:n-fixnum-bits 30) `(ash ,val ,shift) - `(logior (if (logbitp (- 29 ,shift) ,val) sb-xc:most-negative-fixnum 0) + `(logior (if (logbitp (- 29 ,shift) ,val) most-negative-fixnum 0) (ash ,val ,shift)))) ;; Convert unpacked vector to packed vector. @@ -159,10 +202,10 @@ ;; (defun packify-infos (input &optional (end (length input))) (declare (simple-vector input)) - (let* ((output (make-array (compute-packified-info-size input end))) + (let* ((output (make-packed-info (compute-packified-info-size input end))) (i -1) ; input index: pre-increment to read the next datum (j -1) ; descriptor index: pre-increment to write - (k (length output)) ; data index: pre-decrement to write + (k (packed-info-len output)) ; data index: pre-decrement to write (field-shift 0) (word 0)) (declare (type index-or-minus-1 i j k end) @@ -174,19 +217,19 @@ (setq word (logior (make-info-descriptor val field-shift) word)) (if (< field-shift (* (1- +infos-per-word+) info-number-bits)) (incf field-shift info-number-bits) - (setf (svref output (incf j)) word field-shift 0 word 0)))) + (setf (%info-ref output (incf j)) word field-shift 0 word 0)))) ;; Truncating divide by 2: count = n-elements in the group @ 2 per entry, ;; +1 for count itself but not including its aux-key. (loop (let ((count (ash (the index (svref input (incf i))) -1))) (put-field count) ; how many infos to follow (dotimes (iter count) (put-field (svref input (incf i))) ; an info-number - (setf (svref output (decf k)) (svref input (incf i)))) ; value + (setf (%info-ref output (decf k)) (svref input (incf i)))) ; value (when (>= (incf i) end) (return)) - (setf (svref output (decf k)) (svref input i))))) ; an aux-key + (setf (%info-ref output (decf k)) (svref input i))))) ; an aux-key (unless (zerop field-shift) ; store the final descriptor word - (setf (svref output (incf j)) word)) + (setf (%info-ref output (incf j)) word)) (aver (eql (1+ j) k)) ; last descriptor must be adjacent final data cell output)) @@ -194,11 +237,11 @@ ;; returns the next field from a descriptor in INPUT-VAR, a packed vector. ;; The generator uses DESCRIPTOR-INDEX and updates it as a side-effect. ;; -(defmacro !with-packed-info-iterator ((generator input-var +(defmacro with-packed-info-iterator ((generator input-var &key descriptor-index) &body body) (with-unique-names (input word count) - `(let* ((,input (the simple-vector ,input-var)) + `(let* ((,input (the packed-info ,input-var)) (,descriptor-index -1) (,count 0) (,word 0)) @@ -208,21 +251,21 @@ (flet ((,generator () (when (zerop ,count) (incf ,descriptor-index) - (setq ,word (svref ,input ,descriptor-index) + (setq ,word (%info-ref ,input ,descriptor-index) ,count +infos-per-word+)) (prog1 (logand ,word info-num-mask) (setq ,word (ash ,word (- info-number-bits))) (decf ,count)))) ,@body)))) -;; Iterate over VECTOR, binding DATA-INDEX to the index of each aux-key in turn. +;; Iterate over PACKED-INFO, binding DATA-INDEX to the index of each aux-key in turn. ;; TOTAL-N-FIELDS is deliberately exposed to invoking code. ;; -(defmacro !do-packed-info-vector-aux-key ((vector &optional (data-index (gensym))) - step-form &optional result-form) - (with-unique-names (descriptor-idx field-idx) - (once-only ((vector vector)) - `(let ((,data-index (length ,vector)) +(defmacro do-packed-info-aux-key ((packed-info &optional (data-index (gensym))) + step-form &optional result-form) + (with-unique-names (descriptor-idx field-idx info) + `(let* ((,info ,packed-info) + (,data-index (packed-info-len ,info)) (,descriptor-idx 0) (,field-idx 0) (total-n-fields 0)) @@ -231,8 +274,7 @@ ;; Loop through the descriptors in random-access fashion. ;; Skip 1+ n-infos each time, because the 'n-infos' is itself a field ;; that is not accounted for in its own value. - (loop (let ((n (1+ (packed-info-field ,vector - ,descriptor-idx ,field-idx)))) + (loop (let ((n (1+ (packed-info-field ,info ,descriptor-idx ,field-idx)))) (incf total-n-fields n) (multiple-value-setq (,descriptor-idx ,field-idx) (floor total-n-fields +infos-per-word+)) @@ -240,36 +282,21 @@ ;; Done when the ascending index and descending index meet (unless (< ,descriptor-idx ,data-index) (return ,result-form)) - ,@(if step-form (list step-form))))))) - -;; Return all function names that are stored in SYMBOL's info-vector. -;; As an example, (INFO-VECTOR-NAME-LIST 'SB-PCL::DIRECT-SUPERCLASSES) => -;; ((SB-PCL::SLOT-ACCESSOR :GLOBAL SB-PCL::DIRECT-SUPERCLASSES SB-PCL::READER) -;; (SB-PCL::SLOT-ACCESSOR :GLOBAL SB-PCL::DIRECT-SUPERCLASSES BOUNDP) -;; (SB-PCL::SLOT-ACCESSOR :GLOBAL SB-PCL::DIRECT-SUPERCLASSES SB-PCL::WRITER)) -(defun info-vector-name-list (symbol) - (let ((vector (symbol-info-vector symbol)) - (list)) - (when vector - (!do-packed-info-vector-aux-key (vector key-index) - (push (construct-globaldb-name (svref vector key-index) symbol) - list)) - (nconc (and (plusp (packed-info-field vector 0 0)) (list symbol)) - (nreverse list))))) - -;; Compute the number of elements needed to hold packed VECTOR after unpacking. -;; The unpacked size is the number of auxilliary keys plus the number of entries + ,@(if step-form (list step-form)))))) + +;; Compute the number of elements needed to hold PACKED-INFO after unpacking. +;; The unpacked size is the number of auxiliary keys plus the number of entries ;; @ 2 cells per entry, plus the number of length cells which indicate the ;; number of data cells used (including length cells but not aux key cells). ;; Equivalently, it's the number of packed fields times 2 minus 1. ;; -(defun compute-unpackified-info-size (vector) - (declare (simple-vector vector)) - (!do-packed-info-vector-aux-key (vector) () - ;; off-by-one: the first info group's auxilliary key is imaginary +(defun compute-unpackified-info-size (packed-info) + (declare (packed-info packed-info)) + (do-packed-info-aux-key (packed-info) () + ;; off-by-one: the first info group's auxiliary key is imaginary (1- (truly-the fixnum (ash total-n-fields 1))))) -;; Convert packed INPUT vector to unpacked. +;; Convert packed INPUT to unpacked. ;; If optional OUTPUT is supplied, it is used, otherwise output is allocated. ;; For efficiency the OUTPUT should be provided as a dynamic-extent array. ;; @@ -277,28 +304,28 @@ (make-array (compute-unpackified-info-size input)) output-supplied-p)) - (declare (simple-vector input output)) - (let ((i (length input)) (j -1)) ; input index and output index respectively + (declare (type packed-info input) (simple-vector output)) + (let ((i (packed-info-len input)) (j -1)) ; input index and output index respectively (declare (type index-or-minus-1 i j)) - (!with-packed-info-iterator (next-field input :descriptor-index desc-idx) + (with-packed-info-iterator (next-field input :descriptor-index desc-idx) (loop ; over name (let ((n-infos (next-field))) ;; store the info group length, including the length cell in the length (setf (svref output (incf j)) (1+ (ash n-infos 1))) (dotimes (iter n-infos) ; over info-types (setf (svref output (incf j)) (next-field) ; type-num - (svref output (incf j)) (svref input (decf i))))) ; value + (svref output (incf j)) (%info-ref input (decf i))))) ; value (if (< desc-idx (decf i)) ; as long as the indices haven't met - (setf (svref output (incf j)) (svref input i)) ; copy next aux-key + (setf (svref output (incf j)) (%info-ref input i)) ; copy next aux-key (return (if output-supplied-p nil output))))))) ; else done ;; Return the index of the 'length' item for an info group having -;; auxilliary-key KEY in unpacked VECTOR bounded by END (exclusive), +;; auxiliary-key KEY in unpacked VECTOR bounded by END (exclusive), ;; or NIL if not found. ;; (defun info-find-aux-key/unpacked (key vector end) (declare (type index end)) - (if (eql key +no-auxilliary-key+) + (if (eql key +no-auxiliary-key+) 0 ; the first group's length (= end) is stored here always (let ((index 0)) (declare (type index index)) @@ -311,20 +338,20 @@ ((eq (svref vector (1- index)) key) (return index))))))) -;; In packed info VECTOR try to find the auxilliary key SYMBOL. +;; Try to find the auxiliary key SYMBOL in PACKED-INFO. ;; If found, return indices of its data, info descriptor word, and field. ;; If not found, the first value is NIL and the descriptor indices ;; arbitrarily point to the next available descriptor field. ;; -(defun info-find-aux-key/packed (vector symbol) +(defun info-find-aux-key/packed (packed-info symbol) ;; explicit bounds checking is done by the code below - (declare (optimize (safety 0))) - (aver (simple-vector-p vector)) - (let ((descriptor-idx 0) ; physical index to vector +; (declare (optimize (safety 0))) + (aver (typep packed-info 'packed-info)) + (let ((descriptor-idx 0) ; physical index to packed-info (field-idx 0) ; relative index within current descriptor ;; On each iteration DATA-IDX points to an aux-key cell ;; The first group's imaginary aux-key cell is past the end. - (data-idx (length (the simple-vector vector)))) + (data-idx (packed-info-len (the packed-info packed-info)))) (declare (type index descriptor-idx data-idx) (fixnum field-idx)) ; can briefly exceed +infos-per-word+ ;; Efficiently skip past N-INFOS infos. If decrementing the data index @@ -343,31 +370,31 @@ (declare (inline skip)) ;; While this could compare aux-keys with #'EQUAL, it is not obvious how ;; in general one would pick a symbol from the name as that which - ;; is delegated as the one to hold the info-vector. - (values (cond ((not (skip (packed-info-field vector 0 0))) nil) + ;; is delegated as the one to hold the packed-info + (values (cond ((not (skip (packed-info-field packed-info 0 0))) nil) ;; At least one aux key is present. - ((eq (aref vector data-idx) symbol) data-idx) ; yay + ((eq (%info-ref packed-info data-idx) symbol) data-idx) ; yay ;; aux-key order invariant allows early fail on SETF ((eq symbol 'setf) nil) (t (loop - (cond ((not (skip (packed-info-field vector descriptor-idx + (cond ((not (skip (packed-info-field packed-info descriptor-idx field-idx))) (return nil)) - ((eq (aref vector data-idx) symbol) + ((eq (%info-ref packed-info data-idx) symbol) (return data-idx)))))) descriptor-idx field-idx)))) ; can be ignored if 1st val is nil -;; Take a packed info-vector INPUT and insert (AUX-KEY,INFO-NUMBER,VALUE). +;; Take a packed-info INPUT and insert (AUX-KEY,INFO-NUMBER,VALUE). ;; Packed info-vectors are immutable. Any alteration must create a copy. ;; This is done by unpacking/repacking - it's easy enough and fairly ;; efficient since the temporary vector is stack-allocated. ;; (defun %packed-info-insert (input aux-key info-number value) - (declare (simple-vector input) (type info-number info-number)) + (declare (type packed-info input) (type info-number info-number)) (let* ((n-extra-elts ;; Test if the aux-key has been seen before or needs to be added. - (if (and (not (eql aux-key +no-auxilliary-key+)) + (if (and (not (eql aux-key +no-auxiliary-key+)) (not (info-find-aux-key/packed input aux-key))) 4 ; need space for [aux-key, length, type-num, value] 2)) ; only space for [type-num, value] @@ -394,9 +421,7 @@ aux-key new old-size))) ;; it had better be found - it was in the packed vector (aver data-start) - ;; fdefn must be the first piece of info for any name. - ;; This facilitates implementing SYMBOL-FUNCTION without - ;; without completely decoding the vector. + ;; :DEFINITION must be the first piece of info for any name. (insert-at (+ data-start (if (eql info-number +fdefn-info-num+) 1 (svref new data-start))) info-number value) @@ -410,73 +435,59 @@ ;; exactly one descriptor for the root name, space for >= 1 more field, ;; and no aux-keys. (declaim (inline info-quickly-insertable-p)) -(defun info-quickly-insertable-p (input) - (let ((n-infos (packed-info-field input 0 0))) +(defun info-quickly-insertable-p (packed-info) + (let ((n-infos (packed-info-field packed-info 0 0))) ;; We can easily determine if the no-aux-keys constraint is satisfied, ;; because a secondary name's info occupies at least two cells, ;; one for its aux-key and >= 1 for info values. (and (< n-infos (1- +infos-per-word+)) - (eql n-infos (1- (length input)))))) + (eql n-infos (1- (packed-info-len packed-info)))))) -;; Take a packed info-vector INPUT and return a new one with INFO-NUMBER/VALUE +;; Take a packed-info INPUT and return a new one with INFO-NUMBER/VALUE ;; added for the root name. The vector must satisfy INFO-QUICKLY-INSERTABLE-P. ;; This code is separate from PACKED-INFO-INSERT to facilitate writing ;; a unit test of this logic against the complete logic. ;; (defun quick-packed-info-insert (input info-number value) + (declare (type info-number info-number)) ;; Because INPUT contains 1 descriptor and its corresponding values, ;; the current length is exactly NEW-N, the new number of fields. - (let* ((descriptor (svref input 0)) - (new-n (truly-the info-number (length input))) - (new-vect (make-array (1+ new-n)))) - ;; Two cases: we're either inserting info for the fdefn, or not. - (cond ((eq info-number +fdefn-info-num+) - ;; fdefn, if present, must remain the first packed field. - ;; Replace the lowest field (the count) with +fdefn-info-num+, - ;; shift everything left 6 bits, then OR in the new count. - (setf (svref new-vect 0) - (logior (make-info-descriptor - (dpb +fdefn-info-num+ (byte info-number-bits 0) - descriptor) info-number-bits) new-n) - ;; Packed vectors are indexed "backwards". The first - ;; field's info is in the highest numbered cell. - (svref new-vect new-n) value) - (loop for i from 1 below new-n - do (setf (svref new-vect i) (svref input i)))) - (t - ;; Add a field on the high end and increment the count. - (setf (svref new-vect 0) - (logior (make-info-descriptor - info-number (* info-number-bits new-n)) - (1+ descriptor)) - (svref new-vect 1) value) - ;; Slide the old data up 1 cell. - (loop for i from 2 to new-n - do (setf (svref new-vect i) (svref input (1- i)))))) - new-vect)) + (let* ((descriptor (%info-ref input 0)) + (new-n (truly-the info-number (packed-info-len input))) + (output (make-packed-info (1+ new-n)))) + ;; Add a field on the high end and increment the count. + (setf (%info-ref output 0) + (logior (make-info-descriptor info-number (* info-number-bits new-n)) + (1+ descriptor)) + (%info-ref output 1) value) + ;; Slide the old data up 1 cell. + (loop for i from 2 to new-n + do (setf (%info-ref output i) (%info-ref input (1- i)))) + output)) (declaim (maybe-inline packed-info-insert)) -(defun packed-info-insert (vector aux-key info-number newval) - (if (and (eql aux-key +no-auxilliary-key+) - (info-quickly-insertable-p vector)) - (quick-packed-info-insert vector info-number newval) - (%packed-info-insert vector aux-key info-number newval))) +(defun packed-info-insert (packed-info aux-key info-number newval) + (if (and (eql aux-key +no-auxiliary-key+) + (not (eql info-number +fdefn-info-num+)) + (info-quickly-insertable-p packed-info)) + (quick-packed-info-insert packed-info info-number newval) + (%packed-info-insert packed-info aux-key info-number newval))) ;; Search packed VECTOR for AUX-KEY and INFO-NUMBER, returning ;; the index of the data if found, or NIL if not found. ;; -(defun packed-info-value-index (vector aux-key type-num) - (declare (optimize (safety 0))) ; vector bounds are AVERed - (let ((data-idx (length vector)) (descriptor-idx 0) (field-idx 0)) +(defun packed-info-value-index (packed-info aux-key type-num) + ;;(declare (optimize (safetya 0))) ; bounds are AVERed + (let ((data-idx (packed-info-len packed-info)) (descriptor-idx 0) (field-idx 0)) (declare (type index descriptor-idx) (type (mod #.+infos-per-word+) field-idx)) - (unless (eql aux-key +no-auxilliary-key+) + (unless (eql aux-key +no-auxiliary-key+) (multiple-value-setq (data-idx descriptor-idx field-idx) - (info-find-aux-key/packed vector aux-key)) + (info-find-aux-key/packed packed-info aux-key)) (unless data-idx (return-from packed-info-value-index nil))) ;; Fetch a descriptor and shift out trailing bits that won't be scanned. - (let* ((descriptor (ash (the info-descriptor (aref vector descriptor-idx)) + (let* ((descriptor (ash (the info-descriptor (%info-ref packed-info descriptor-idx)) (* (- info-number-bits) field-idx))) (n-infos (logand descriptor info-num-mask)) ;; Compute n things in this descriptor after extracting one field. e.g. @@ -500,11 +511,11 @@ (incf descriptor-idx) (decf data-idx swath) (aver (< descriptor-idx data-idx)) - (setq descriptor (svref vector descriptor-idx) + (setq descriptor (%info-ref packed-info descriptor-idx) swath (min n-infos +infos-per-word+)))))) ;; Helper for CLEAR-INFO-VALUES when Name has the efficient form. -;; Given packed info-vector INPUT and auxilliary key KEY2 +;; Given packed-info INPUT and auxiliary key KEY2 ;; return a new vector in which TYPE-NUMS are absent. ;; When none of TYPE-NUMs were present to begin with, return NIL. ;; @@ -512,9 +523,9 @@ ;; clearing does not happen often enough to warrant the pre-check. ;; (defun packed-info-remove (input key2 type-nums) - (declare (simple-vector input)) - (when (or (eql (length input) (length +nil-packed-infos+)) - (and (not (eql key2 +no-auxilliary-key+)) + (declare (type packed-info input)) + (when (or (eql (packed-info-len input) #.(packed-info-len +nil-packed-infos+)) + (and (not (eql key2 +no-auxiliary-key+)) (not (info-find-aux-key/packed input key2)))) (return-from packed-info-remove nil)) ; do nothing (let* ((end (compute-unpackified-info-size input)) @@ -533,7 +544,7 @@ return probe))) ;; N.B. the early termination checks aren't just optimizations, ;; they're requirements, because otherwise the loop could smash - ;; data that does not belong to this auxilliary key. + ;; data that does not belong to this auxiliary key. (cond ((not i)) ; not found - ignore ;; Squash out 2 cells if deleting an info for primary name, ;; or for secondary name with at least one more entry. @@ -602,27 +613,27 @@ ;; Call FUNCTION with each piece of info in packed VECT using ROOT-SYMBOL ;; as the primary name. FUNCTION must accept 3 values (NAME INFO-NUMBER VALUE). -(defun %call-with-each-info (function vect root-symbol) +(defun %call-with-each-info (function packed-info root-symbol) (let ((name root-symbol) - (data-idx (length vect))) + (data-idx (packed-info-len packed-info))) (declare (type index data-idx)) - (!with-packed-info-iterator (next-field vect :descriptor-index desc-idx) + (with-packed-info-iterator (next-field packed-info :descriptor-index desc-idx) (loop ; over name (dotimes (i (next-field)) ; number of infos for this name - (funcall function name (next-field) (svref vect (decf data-idx)))) + (funcall function name (next-field) (%info-ref packed-info (decf data-idx)))) (if (< desc-idx (decf data-idx)) (setq name - (construct-globaldb-name (svref vect data-idx) root-symbol)) + (construct-globaldb-name (%info-ref packed-info data-idx) root-symbol)) (return)))))) #| -Info packing example. This example has 2 auxilliary-keys: SETF and CAS. +Info packing example. This example has 2 auxiliary-keys: SETF and CAS. -(!test-packify-infos '(13 :XYZ 18 "nine" 28 :BAR 7 T) - '(SETF 8 NIL 17 :FGX) - '(CAS 6 :MUMBLE 2 :BAZ 47 :FOO)) +(test-packify-infos '(13 :XYZ 18 "nine" 28 :BAR 7 T) + '(SETF 8 NIL 17 :FGX) + '(CAS 6 :MUMBLE 2 :BAZ 47 :FOO)) => -#(109006134805865284 3010 :FOO :BAZ :MUMBLE CAS :FGX NIL SETF T :BAR "nine" :XYZ) +[109006134805865284 3010 :FOO :BAZ :MUMBLE CAS :FGX NIL SETF T :BAR "nine" :XYZ] (format nil "~4,'0o ~20,'0o" 3010 109006134805865284) => "5702 06032110020734221504" @@ -630,10 +641,10 @@ Reading from right-to-left, converting each 2-digit octal number to decimal: 4, 13, 18, 28, 7, 2, 8, 17, 3, 6, 2, 47 Which is interpreted as: 4 infos for the root name. type numbers: 13, 18, 28, 7 - 2 infos for SETF auxilliary-key. type numbers: 8, 17 - 3 infos for CAS auxilliary-key. type numbers: 6, 2, 47 + 2 infos for SETF auxiliary-key. type numbers: 8, 17 + 3 infos for CAS auxiliary-key. type numbers: 6, 2, 47 -(unpackify-infos (!test-packify-infos ...)) ; same input +(unpackify-infos (test-packify-infos ...)) ; same input => #(9 13 :XYZ 18 "nine" 28 :BAR 7 T SETF 5 8 NIL 17 :FGX CAS 7 6 :MUMBLE 2 :BAZ 47 :FOO) @@ -647,12 +658,12 @@ This is interpreted as ;; The info for a symbol's fdefn must precede other info-numbers. ;; and SETF must be the first aux key if other aux keys are present. ;; The test function does not enforce these invariants. -#+nil ; for debugging only -(defun !test-packify-infos (&rest lists) +(defun test-packify-infos (&rest lists) (flet ((check (plist) (and (evenp (length plist)) (loop for (indicator value) on plist by #'cddr - always (typep indicator 'info-number)))) + always (progn #+host-quirks-ccl value ; shut up the host + (typep indicator 'info-number))))) (add-length-prefix (list) ; computers count better than people (cons (1+ (length list)) list))) (unless (and (check (first lists)) @@ -677,12 +688,12 @@ This is interpreted as ;; If NAME is "simple", bind KEY2 and KEY1 to the elements ;; in that order, and execute the SIMPLE code, otherwise execute the HAIRY code. ;; If ALLOW-ATOM is T - the default - then NAME can be just a symbol -;; in which case its second component is +NO-AUXILLIARY-KEY+. +;; in which case its second component is +NO-AUXILIARY-KEY+. ;; (defmacro with-globaldb-name ((key1 key2 &optional (allow-atom t)) name &key simple hairy) (with-unique-names (rest) - `(let ((,key1 ,name) (,key2 +NO-AUXILLIARY-KEY+)) + `(let ((,key1 ,name) (,key2 +NO-AUXILIARY-KEY+)) (if (or ,@(if allow-atom `((symbolp ,key1))) (if (listp ,key1) (let ((,rest (cdr ,key1))) @@ -700,17 +711,6 @@ This is interpreted as ;;; Some of this stuff might belong in 'symbol.lisp', but can't be, ;;; because 'symbol.lisp' is :NOT-HOST in build-order. -;; In the target, UPDATE-SYMBOL-INFO is defined in 'symbol.lisp'. -#+sb-xc-host -(defun update-symbol-info (symbol update-fn) - ;; Never pass NIL to an update-fn. Pass the minimal info-vector instead, - ;; a vector describing 0 infos and 0 auxilliary keys. - (let ((newval (funcall update-fn (or (symbol-info-vector symbol) - +nil-packed-infos+)))) - (when newval - (setf (symbol-info-vector symbol) newval)) - (values))) - ;;; The current *INFO-ENVIRONMENT*, a structure of type INFO-HASHTABLE. ;;; Cheat by setting to nil before the type is proclaimed ;;; so that we can then also proclaim ALWAYS-BOUND. @@ -779,14 +779,14 @@ This is interpreted as (let ((name (uncross name))) ;; If the INFO-NUMBER already exists in VECT, then copy it and ;; alter one cell; otherwise unpack it, grow the vector, and repack. - (dx-flet ((augment (vect aux-key) ; VECT is a packed vector, never NIL - (declare (simple-vector vect)) + (dx-flet ((augment (packed-info aux-key) ; PACKED-INFO must not be NIL + (declare (type packed-info packed-info)) (let ((index - (packed-info-value-index vect aux-key info-number))) + (packed-info-value-index packed-info aux-key info-number))) (if (not index) - (packed-info-insert vect aux-key info-number new-value) - (let ((copy (copy-seq vect))) - (setf (svref copy index) new-value) + (packed-info-insert packed-info aux-key info-number new-value) + (let ((copy (copy-packed-info packed-info))) + (setf (%info-ref copy index) new-value) copy))))) (with-globaldb-name (key1 key2) name :simple @@ -796,8 +796,7 @@ This is interpreted as :hairy ;; INFO-PUTHASH supplies NIL for OLD-INFO if NAME was absent. (dx-flet ((hairy-name (old-info) - (augment (or old-info +nil-packed-infos+) - +no-auxilliary-key+))) + (augment (or old-info +nil-packed-infos+) +no-auxiliary-key+))) (info-puthash *info-environment* name #'hairy-name))))) new-value) @@ -813,20 +812,20 @@ This is interpreted as (when (pcl-methodfn-name-p name) (error "Can't SET-INFO-VALUE on PCL-internal function")) (let ((name (uncross name)) new-value) - (dx-flet ((augment (vect aux-key) ; VECT is a packed vector, never NIL - (declare (simple-vector vect)) + (dx-flet ((augment (packed-info aux-key) ; PACKED-INFO must not be NIL + (declare (type packed-info packed-info)) (let ((index - (packed-info-value-index vect aux-key info-number))) + (packed-info-value-index packed-info aux-key info-number))) (if (not index) (packed-info-insert - vect aux-key info-number + packed-info aux-key info-number (setq new-value (funcall new-value-fun nil nil))) - (let ((oldval (svref vect index))) + (let ((oldval (%info-ref packed-info index))) (setq new-value (funcall new-value-fun oldval t)) (if (eq new-value oldval) - vect ; return the old vector - (let ((copy (copy-seq vect))) - (setf (svref copy index) new-value) + packed-info ; return the old packed-info + (let ((copy (copy-packed-info packed-info))) + (setf (%info-ref copy index) new-value) copy))))))) (with-globaldb-name (key1 key2) name :simple @@ -837,7 +836,7 @@ This is interpreted as ;; INFO-PUTHASH supplies NIL for OLD-INFO if NAME was absent. (dx-flet ((hairy-name (old-info) (augment (or old-info +nil-packed-infos+) - +no-auxilliary-key+))) + +no-auxiliary-key+))) (info-puthash *info-environment* name #'hairy-name)))) new-value)) @@ -855,19 +854,19 @@ This is interpreted as (error "~D is not a legal INFO name." name)) (let ((name (uncross name)) result) - (dx-flet ((get-or-set (info-vect aux-key) + (dx-flet ((get-or-set (packed-info aux-key) (let ((index - (packed-info-value-index info-vect aux-key info-number))) + (packed-info-value-index packed-info aux-key info-number))) (cond (index - (setq result (svref info-vect index)) - nil) ; no update to info-vector + (setq result (%info-ref packed-info index)) + nil) ; no update (t ;; Update conflicts possibly for unrelated info-number ;; can force re-execution. (UNLESS result ...) tries ;; to avoid calling the thunk more than once. (unless result (setq result (funcall creation-thunk))) - (packed-info-insert info-vect aux-key info-number + (packed-info-insert packed-info aux-key info-number result)))))) (with-globaldb-name (key1 key2) name :simple @@ -877,10 +876,14 @@ This is interpreted as :hairy ;; INFO-PUTHASH supplies NIL for OLD-INFO if NAME was absent. (dx-flet ((hairy-name (old-info) - (or (get-or-set (or old-info +nil-packed-infos+) - +no-auxilliary-key+) + (or (get-or-set (or old-info +nil-packed-infos+) +no-auxiliary-key+) ;; Return OLD-INFO to elide writeback. Unlike for ;; UPDATE-SYMBOL-INFO, NIL is not a no-op marker. old-info))) (info-puthash *info-environment* name #'hairy-name)))) result)) + +;;; Disassembling these proves that SYS-ALLOC-TRAMP gets called +(export '(test-make-packed-info test-copy-packed-info)) +(defun test-make-packed-info (x) (make-packed-info (the (mod 100) x))) +(defun test-copy-packed-info (x) (copy-packed-info x)) diff --git a/src/compiler/integer-tran.lisp b/src/compiler/integer-tran.lisp index b51641b92d..dacb1a45a0 100644 --- a/src/compiler/integer-tran.lisp +++ b/src/compiler/integer-tran.lisp @@ -21,7 +21,7 @@ (if (numeric-type-p type) (let ((limit-high (numeric-type-high (lvar-type limit)))) (aver limit-high) - (if (<= limit-high (1+ sb-xc:most-positive-fixnum)) + (if (<= limit-high (1+ most-positive-fixnum)) '(%inclusive-random-fixnum (1- limit) (or state *random-state*)) '(%inclusive-random-integer (1- limit) diff --git a/src/compiler/ir1-translators.lisp b/src/compiler/ir1-translators.lisp index 8a81999741..7c614d5004 100644 --- a/src/compiler/ir1-translators.lisp +++ b/src/compiler/ir1-translators.lisp @@ -102,7 +102,6 @@ Evaluate the FORMS as a PROGN. Within the lexical scope of the body, RETURN-FROM can be used to exit the form." (unless (symbolp name) (compiler-error "The block name ~S is not a symbol." name)) - (start-block start) (ctran-starts-block next) (let* ((dummy (make-ctran)) (entry (make-entry)) @@ -116,7 +115,6 @@ RETURN-FROM can be used to exit the form." (let* ((env-entry (list entry next result)) (*lexenv* (make-lexenv :blocks (list (cons name env-entry)) :cleanup cleanup))) - (push env-entry (ctran-entries next)) (ir1-convert-progn-body dummy next result forms)))) (def-ir1-translator return-from ((name &optional value) start next result) @@ -201,7 +199,6 @@ TAGS, and NIL is returned. If a statement contains a GO to a defined TAG within the lexical scope of the form, then control is transferred to the next statement following that tag. A TAG must be an integer or a symbol. A STATEMENT must be a list. Other objects are illegal within the body." - (start-block start) (ctran-starts-block next) (let* ((dummy (make-ctran)) (entry (make-entry)) @@ -298,7 +295,7 @@ Evaluate the FORMS in the specified SITUATIONS (any of :COMPILE-TOPLEVEL, ;; Do this after processing, since the definitions can be malformed. (unless (= (length definitions) (length (remove-duplicates definitions :key #'first))) - (compiler-style-warn "Duplicate definitions in ~S" definitions)) + (compiler-warn "Duplicate definitions in ~S" definitions)) (funcall fun processed-definitions))) ;;; Tweak LEXENV to include the DEFINITIONS from a MACROLET, then @@ -327,25 +324,27 @@ Evaluate the FORMS in the specified SITUATIONS (any of :COMPILE-TOPLEVEL, (unless (listp arglist) (fail "The local macro argument list ~S is not a list." arglist)) - `(,name macro . - ;; I guess the reason we want to compile here rather than possibly - ;; using an interpreted lambda is that we generate the usual gamut - ;; of style-warnings and such. One might wonder if this could somehow - ;; go through the front-most part of the front-end, to deal with - ;; semantics, but then generate an interpreted function or something - ;; more quick to emit than machine code. - ,(compile-in-lexenv - (let (#-sb-xc-host - (*macro-policy* - ;; Make sure to save the sources if an - ;; inlined functions closes over this - ;; macro. - (process-optimize-decl - '(optimize (store-source-form 3)) - *macro-policy*))) - (make-macro-lambda nil arglist body 'macrolet name)) - lexenv - nil nil nil t nil))))))) ; name source-info tlf ephemeral errorp + (let (source-info + tlf) + #-sb-xc-host + (when (boundp '*source-paths*) + (push `(declare (source-form ,definition)) body) + (setf source-info *source-info* + tlf (let ((path (or (get-source-path definition) + (and (boundp '*current-path*) + *current-path*)))) + (source-path-tlf-number path)))) + `(,name macro . + ;; I guess the reason we want to compile here rather than possibly + ;; using an interpreted lambda is that we generate the usual gamut + ;; of style-warnings and such. One might wonder if this could somehow + ;; go through the front-most part of the front-end, to deal with + ;; semantics, but then generate an interpreted function or something + ;; more quick to emit than machine code. + ,(compile-in-lexenv + (make-macro-lambda nil arglist body 'macrolet name) + lexenv + nil source-info tlf t nil)))))))) (defun funcall-in-macrolet-lexenv (definitions fun context) (%funcall-in-foomacrolet-lexenv @@ -464,11 +463,40 @@ body, references to a NAME will effectively be replaced with the EXPANSION." (bug "%PRIMITIVE was used with an unknown values template.")) (ir1-convert start next result - `(%%primitive ',name + `(%%primitive ',template ',(eval-info-args (subseq args required min)) ,@(subseq args 0 required) ,@(subseq args min))))) + +(defmacro inline-%primitive (template &rest args) + (let* ((required (length (template-arg-types template))) + (info (template-info-arg-count template)) + (min (+ required info)) + (nargs (length args))) + (if (template-more-args-type template) + (when (< nargs min) + (bug "Primitive was called with ~R argument~:P, ~ + but wants at least ~R." + nargs + min)) + (unless (= nargs min) + (bug "Primitive was called with ~R argument~:P, ~ + but wants exactly ~R." + nargs + min))) + + (when (template-conditional-p template) + (bug "%PRIMITIVE was used with a conditional template.")) + + (when (template-more-results-type template) + (bug "%PRIMITIVE was used with an unknown values template.")) + + `(%%primitive ',template + ',(eval-info-args + (subseq args required min)) + ,@(subseq args 0 required) + ,@(subseq args min)))) ;;;; QUOTE @@ -516,6 +544,7 @@ Return VALUE without evaluating it." ;;; un-merged pathnames. I'm not daring enough to change it for everyone. ;;; It defaults to what it should, and is changed before saving the image. ;;; +;;; FIXME: can't we just get rid of this and _never_ use TRUENAME? (declaim (type (member pathname truename) *name-context-file-path-selector*)) (defglobal *name-context-file-path-selector* 'pathname) @@ -536,13 +565,36 @@ Return VALUE without evaluating it." (lexenv-blocks *lexenv*) :from-end t)) *source-namestring* (awhen (case *name-context-file-path-selector* - (pathname (or sb-xc:*compile-file-pathname* *load-pathname*)) - (truename (or sb-xc:*compile-file-truename* *load-truename*))) + (pathname (or *compile-file-pathname* *load-pathname*)) + (truename (or *compile-file-truename* *load-truename*))) (namestring it))))) (when context (list :in context)))) ;;;; FUNCTION and NAMED-LAMBDA + +;;; `(NAMED-LAMBDA ,NAME ,@REST) is like `(FUNCTION (LAMBDA ,@REST)), +;;; except that the value of NAME is passed to the compiler for use in +;;; creation of debug information for the resulting function. +;;; +;;; NAME can be a legal function name or some arbitrary other thing. +;;; +;;; If NAME is a legal function name, then the caller should be +;;; planning to set (FDEFINITION NAME) to the created function. +;;; (Otherwise the debug names will be inconsistent and thus +;;; unnecessarily confusing.) +;;; +;;; Arbitrary other things are appropriate for naming things which are +;;; not the FDEFINITION of NAME. E.g. +;;; NAME = (:FLET FOO BAR) +;;; for the FLET function in +;;; (DEFUN BAR (X) +;;; (FLET ((FOO (Y) (+ X Y))) +;;; FOO)) +;;; or +;;; NAME = (:METHOD PRINT-OBJECT :AROUND (STARSHIP T)) +;;; for the function used to implement +;;; (DEFMETHOD PRINT-OBJECT :AROUND ((SS STARSHIP) STREAM) ...). (defun name-lambdalike (thing) (case (car thing) ((named-lambda) @@ -557,67 +609,65 @@ Return VALUE without evaluating it." (compiler-error "Not a valid lambda expression:~% ~S" thing)))) -(defun fun-name-leaf (thing) +(defun enclose (start next funs) + (let ((enclose (make-enclose :funs funs))) + (link-node-to-previous-ctran enclose start) + (use-ctran enclose next) + (dolist (fun funs) + (setf (functional-enclose fun) enclose)))) + +;;; Get the leaf corresponding to THING, allocating and converting it +;;; if it's a lambda expression or otherwise finding the lexically +;;; apparent function associated to it. +(defun find-or-convert-fun-leaf (thing start) (cond - ((typep thing - '(cons (member lambda named-lambda lambda-with-lexenv))) - (values (ir1-convert-lambdalike - thing :debug-name (name-lambdalike thing)) - t)) + ((typep thing '(cons (member lambda named-lambda lambda-with-lexenv))) + (let ((ctran (make-ctran)) + (leaf (ir1-convert-lambdalike thing + :debug-name (name-lambdalike thing)))) + (enclose start ctran (list leaf)) + (values leaf ctran))) ((legal-fun-name-p thing) - (values (find-lexically-apparent-fun - thing "as the argument to FUNCTION") - nil)) + (values (find-lexically-apparent-fun thing "as the argument to FUNCTION") + start)) (t (compiler-error "~S is not a legal function name." thing)))) -(def-ir1-translator %fun-name-leaf ((thing) start next result) - (fun-name-leaf thing) +;;; Convert a lambda without referencing it, side-effecting the +;;; compile-time environment. This is useful for converting named +;;; lambdas not meant to have entry points during block compilation, +;;; since references will create entry points. +(def-ir1-translator %refless-defun ((thing) start next result) + (ir1-convert-lambdalike thing :debug-name (name-lambdalike thing)) (ir1-convert start next result nil)) -(def-ir1-translator %%allocate-closures ((&rest leaves) start next result) - (aver (eq result 'nil)) - (let ((lambdas leaves)) - ;; Opaquely quoting this list avoids recursing in find-constant - ;; to check for dumpability of sub-parts as it would otherwise do. - (ir1-convert start next result `(%allocate-closures ,(opaquely-quote lambdas))) - (let ((allocator (node-dest (ctran-next start)))) - (dolist (lambda lambdas) - (setf (functional-allocator lambda) allocator))))) - -(defmacro with-fun-name-leaf ((leaf thing start &key global-function) &body body) - `(multiple-value-bind (,leaf allocate-p) - (if ,global-function - (find-global-fun ,thing t) - (fun-name-leaf ,thing)) - (if allocate-p - (let ((.new-start. (make-ctran))) - (ir1-convert ,start .new-start. nil `(%%allocate-closures ,leaf)) - (let ((,start .new-start.)) - ,@body)) - (locally - ,@body)))) - (def-ir1-translator function ((thing) start next result) "FUNCTION name Return the lexically apparent definition of the function NAME. NAME may also be a lambda expression." - (with-fun-name-leaf (leaf thing start) + (multiple-value-bind (leaf start) + (find-or-convert-fun-leaf thing start) (reference-leaf start next result leaf))) ;;; Like FUNCTION, but ignores local definitions and inline ;;; expansions, and doesn't nag about undefined functions. ;;; Used for optimizing things like (FUNCALL 'FOO). (def-ir1-translator global-function ((thing) start next result) - (with-fun-name-leaf (leaf thing start :global-function t) - (reference-leaf start next result leaf))) - -(defun constant-global-fun-name (thing) - (let ((constantp (sb-xc:constantp thing))) + (reference-leaf start next result (find-global-fun thing t))) + +;;; Return T if THING is a constant value and either a symbol (if EXTENDEDP is NIL) +;;; or an extended-function-name (if EXTENDEDP is T). +;;; Note however that whether THING actually names something is irrelevant. +;;; This test is only if it _could_ name something. Return NIL if THING is a function +;;; or a constant form evaluating to a function, or not a legal designator at all. +(defun constant-global-fun-name (thing lexenv extendedp) + (let ((constantp (constantp thing lexenv))) (when constantp - (let ((name (constant-form-value thing))) - (when (legal-fun-name-p name) + (let ((name (constant-form-value thing lexenv))) + (when (if extendedp + (legal-fun-name-p name) + (symbolp name)) name))))) (defun lvar-constant-global-fun-name (lvar) @@ -626,14 +676,15 @@ be a lambda expression." (when (legal-fun-name-p name) name)))) -(defun ensure-source-fun-form (source &key (coercer '%coerce-callable-for-call) give-up) +(defun ensure-source-fun-form (source lexenv &key (coercer '%coerce-callable-for-call) + (extendedp t) give-up) (let ((op (when (consp source) (car source)))) (cond ((memq op '(%coerce-callable-to-fun %coerce-callable-for-call)) - (ensure-source-fun-form (second source) :coercer coercer)) + (ensure-source-fun-form (second source) lexenv :coercer coercer)) ((member op '(function global-function lambda named-lambda)) (values source nil)) (t - (let ((cname (constant-global-fun-name source))) + (let ((cname (constant-global-fun-name source lexenv extendedp))) (if cname (values `(global-function ,cname) nil) (values `(,coercer ,source) give-up))))))) @@ -675,10 +726,14 @@ be a lambda expression." (let ((function (handler-case (%macroexpand function *lexenv*) (error () function)))) (if (typep function '(cons (member function global-function) (cons t null))) - (with-fun-name-leaf (leaf (cadr function) start - :global-function (eq (car function) - 'global-function)) - (ir1-convert start next result `(,leaf ,@args))) + ;; We manually frob the function to get the leaf like this so + ;; we let setf functions have their source transforms fire. + (destructuring-bind (operator definition) function + (multiple-value-bind (leaf start) + (ecase operator + (function (find-or-convert-fun-leaf definition start)) + (global-function (values (find-global-fun definition t) start))) + (ir1-convert start next result `(,leaf ,@args)))) (let ((ctran (make-ctran)) (fun-lvar (make-lvar))) (ir1-convert start ctran fun-lvar `(the function ,function)) @@ -687,12 +742,24 @@ be a lambda expression." (def-ir1-translator %funcall-lvar ((function &rest args) start next result) (ir1-convert-combination-args function start next result args)) +(def-ir1-translator %funcall-no-nargs ((function &rest args) start next result) + (let ((ctran (make-ctran)) + (fun-lvar (make-lvar))) + (ir1-convert start ctran fun-lvar `(the function ,function)) + (ir1-convert-combination-args fun-lvar ctran next result args :pass-nargs nil))) + ;;; This source transform exists to reduce the amount of work for the ;;; compiler. If the called function is a FUNCTION form, then convert ;;; directly to %FUNCALL, instead of waiting around for type ;;; inference. -(define-source-transform funcall (function &rest args) - `(%funcall ,(ensure-source-fun-form function :coercer '%coerce-callable-for-call) ,@args)) +(define-source-transform funcall (function &rest args &environment env) + ;; This transform should not allow violating the type constraint on FUNCALL + ;; by sneaking in a use of #'name via %FUNCALL in cases where the name is + ;; an extended-function-designator instead of just function-designator. + `(%funcall ,(ensure-source-fun-form function env + :coercer '%coerce-callable-for-call + :extendedp nil) + ,@args)) (deftransform %coerce-callable-to-fun ((thing) * * :node node) "optimize away possible call to FDEFINITION at runtime" @@ -703,8 +770,8 @@ be a lambda expression." "optimize away possible call to FDEFINITION at runtime" (ensure-lvar-fun-form thing 'thing :give-up t :coercer '%coerce-callable-for-call)) -(define-source-transform %coerce-callable-to-fun (thing) - (ensure-source-fun-form thing :give-up t)) +(define-source-transform %coerce-callable-to-fun (thing &environment env) + (ensure-source-fun-form thing env :give-up t)) ;;;; LET and LET* @@ -741,7 +808,7 @@ be a lambda expression." name :context context :allow-symbol-macro nil) (unless (eq context 'let*) (funcall names name)) - (vars (varify-lambda-arg name)) + (vars (varify-lambda-arg name spec)) (vals value))))) (values (vars) (vals)))) @@ -783,7 +850,8 @@ have been evaluated." :debug-name (debug-name 'let bindings)))) (reference-leaf start ctran fun-lvar fun)) (values next result)))) - (ir1-convert-combination-args fun-lvar ctran next result values))))) + (ir1-convert-combination-args fun-lvar ctran next result values + :arg-source-forms bindings))))) (def-ir1-translator let* ((bindings &body body) start next result) @@ -794,7 +862,8 @@ form to reference any of the previous VARS." (multiple-value-bind (vars values forms decls) (parse-letish bindings body 'let*) (processing-decls (decls vars nil next result post-binding-lexenv) (ir1-convert-aux-bindings - start next result forms vars values post-binding-lexenv)))) + start next result forms vars values post-binding-lexenv + :value-source-forms bindings)))) ;;; logic shared between IR1 translators for LOCALLY, MACROLET, ;;; and SYMBOL-MACROLET @@ -847,7 +916,11 @@ also processed as top level forms." ,@decls (block ,(fun-name-block-name name) . ,forms))))))) - (values (names) (defs)))) + (let ((names (names))) + (unless (= (length names) + (length (remove-duplicates names :test #'equal))) + (compiler-warn "Duplicate definitions in ~S" definitions)) + (values names (defs))))) (defun parse-fletish (definitions body context) (multiple-value-bind (forms declarations) (parse-body body nil) @@ -857,28 +930,28 @@ also processed as top level forms." (multiple-value-call #'values (extract-fletish-vars definitions context) forms declarations)))) +;;; This is similar to IR1-CONVERT-PROGN-BODY except that code to +;;; potentially make a closure for each FUN in FUNS is emitted, and +;;; then the body is converted as usual. +;;; +;;; When one of these FUNS is declared dynamic extent, we make a +;;; cleanup with the ENCLOSE as the MESS-UP node and introduce it into +;;; the lexical environment to convert the body in. We force NEXT to +;;; start a block outside of this cleanup, causing cleanup code to be +;;; emitted when the scope is exited. (defun ir1-convert-fbindings (start next result funs body) - (let ((ctran (make-ctran)) - (dx-p (find-if #'leaf-dynamic-extent funs))) - (when dx-p - (ctran-starts-block ctran) - (ctran-starts-block next)) - (ir1-convert start ctran nil `(%%allocate-closures ,@funs)) - (cond (dx-p - (let* ((dummy (make-ctran)) - (entry (make-entry)) - (cleanup (make-cleanup :kind :dynamic-extent - :mess-up entry - :info (list (node-dest - (ctran-next start)))))) - (push entry (lambda-entries (lexenv-lambda *lexenv*))) - (setf (entry-cleanup entry) cleanup) - (link-node-to-previous-ctran entry ctran) - (use-ctran entry dummy) - + (let ((enclose-ctran (make-ctran))) + (enclose start enclose-ctran funs) + (cond ((some #'leaf-dynamic-extent funs) + (ctran-starts-block next) + (let ((cleanup (make-cleanup :kind :dynamic-extent + :mess-up (ctran-use enclose-ctran))) + (cleanup-ctran (make-ctran))) (let ((*lexenv* (make-lexenv :cleanup cleanup))) - (ir1-convert-progn-body dummy next result body)))) - (t (ir1-convert-progn-body ctran next result body))))) + (ir1-convert enclose-ctran cleanup-ctran nil '(%cleanup-point)) + (ir1-convert-progn-body cleanup-ctran next result body)))) + (t + (ir1-convert-progn-body enclose-ctran next result body))))) (def-ir1-translator flet ((definitions &body body) start next result) @@ -974,7 +1047,7 @@ other." (values-subtypep (make-single-value-type (leaf-type value)) type)) (and (not (fun-designator-type-p type)) - (sb-xc:constantp value) + (constantp value) (or (not (values-type-p type)) (values-type-may-be-single-value-p type)) (ctypep (constant-form-value value) @@ -1033,7 +1106,8 @@ care." derive-type-only truly source-form - use-annotations) + use-annotations + restart) form) start next result) (let ((value-type (if (ctype-p value-type) @@ -1041,7 +1115,12 @@ care." (values-specifier-type value-type))) (*current-path* (if source-form (ensure-source-path source-form) - *current-path*))) + *current-path*)) + (context (cond (restart + ;; For now, these share the same place in the debug info + (aver (not context)) + :restart) + (context)))) (cond (derive-type-only ;; For something where we really know the type and need no mismatch checking, ;; e.g. structure accessors @@ -1155,13 +1234,14 @@ care." (let* ((name (first things)) (value-form (second things)) (leaf (or (lexenv-find name vars) (find-free-var name)))) + (maybe-note-undefined-variable-reference leaf name) (etypecase leaf (leaf (when (constant-p leaf) (compiler-error "~S is a constant and thus can't be set." name)) (when (lambda-var-p leaf) (let ((home-lambda (ctran-home-lambda-or-null start))) - (when home-lambda + (when (and home-lambda (neq (lambda-var-home leaf) home-lambda)) (sset-adjoin leaf (lambda-calls-or-closes home-lambda)))) (when (lambda-var-ignorep leaf) ;; ANSI's definition of "Declaration IGNORE, IGNORABLE" @@ -1198,7 +1278,11 @@ care." ,value)) (let ((res (make-set :var var :value dest-lvar))) (setf (lvar-dest dest-lvar) res) - (setf (leaf-ever-used var) t) + (cond (result ; SETQ with a result counts as a REF also + (setf (leaf-ever-used var) t)) + ((not (leaf-ever-used var)) ; doesn't count as a REF + ;; (EVER-USED might already be T, leave it alone if so) + (setf (leaf-ever-used var) 'set))) (push res (basic-var-sets var)) (link-node-to-previous-ctran res dest-ctran) (use-continuation res next result)))) @@ -1254,7 +1338,7 @@ to TAG." :debug-name (debug-name 'escape-fun tag)))) (ctran (make-ctran))) (setf (functional-kind fun) :escape) - (ir1-convert start ctran nil `(%%allocate-closures ,fun)) + (enclose start ctran (list fun)) (reference-leaf ctran next result fun))) ;;; Yet another special special form. This one looks up a local @@ -1278,16 +1362,13 @@ the thrown values will be returned." ;; We represent the possibility of the control transfer by making an ;; "escape function" that does a lexical exit, and instantiate the ;; cleanup using %WITHIN-CLEANUP. - (let* ((tag-ctran (make-ctran)) - (tag-lvar (make-lvar))) - (ir1-convert start tag-ctran tag-lvar tag) - (ir1-convert - tag-ctran next result - (with-unique-names (exit-block) - `(block ,exit-block - (%within-cleanup - :catch (%catch (%escape-fun ,exit-block) ,tag-lvar) - ,@body)))))) + (ir1-convert + start next result + (with-unique-names (exit-block) + `(block ,exit-block + (%within-cleanup + :catch (%catch (%escape-fun ,exit-block) ,tag) + ,@body))))) ;;; Since NSP is restored on unwind we only need to protect against ;;; local transfers of control, basically the same as special @@ -1440,7 +1521,10 @@ values from the first VALUES-FORM making up the first argument, etc." ;; important for simplifying compilation of ;; MV-COMBINATIONS. (make-combination fun-lvar)))) - (ir1-convert start ctran fun-lvar (ensure-source-fun-form fun :coercer '%coerce-callable-for-call)) + (ir1-convert start ctran fun-lvar + (ensure-source-fun-form fun *lexenv* + :coercer '%coerce-callable-for-call + :extendedp nil)) (setf (lvar-dest fun-lvar) node) (collect ((arg-lvars)) (let ((this-start ctran)) @@ -1454,6 +1538,15 @@ values from the first VALUES-FORM making up the first argument, etc." (use-continuation node next result) (setf (basic-combination-args node) (arg-lvars)))))) +;;; MULTIPLE-VALUE-PROG1 is represented in IR1 by having the +;;; VALUES-FORM code use a VALUE lvar that gets handed off to +;;; RESULT. In other words, as the result continuation isn't +;;; IMMEDIATELY-USED-P by the nodes that compute the result, we have +;;; to interpose a DELAY node using RESULT immediately so that the +;;; result continuation can assume that it is immediately used. This +;;; is important here because MULTIPLE-VALUE-PROG1 is the only special +;;; form which receives unknown values with multiple uses, some (in +;;; this case one) of which are not immediate. (def-ir1-translator multiple-value-prog1 ((values-form &rest forms) start next result) "MULTIPLE-VALUE-PROG1 values-form form* @@ -1463,17 +1556,13 @@ VALUES-FORM." (let* ((value-ctran (make-ctran)) (forms-ctran (make-ctran)) (value-lvar (make-lvar)) - ;; This is to avoid writing in the RESULT LVAR before the - ;; body is executed, because the body may overwrite it. - ;; See MAY-DELETE-VESTIGIAL-EXIT. - (cast (make-vestigial-exit-cast - :value value-lvar))) + (delay (make-delay :value value-lvar))) (ctran-starts-block value-ctran) (ir1-convert start value-ctran value-lvar values-form) (ir1-convert-progn-body value-ctran forms-ctran nil forms) - (link-node-to-previous-ctran cast forms-ctran) - (setf (lvar-dest value-lvar) cast) - (use-continuation cast next result))) + (link-node-to-previous-ctran delay forms-ctran) + (setf (lvar-dest value-lvar) delay) + (use-continuation delay next result))) ;;;; interface to defining macros diff --git a/src/compiler/ir1final.lisp b/src/compiler/ir1final.lisp index 4fc08e018d..1723ce05ca 100644 --- a/src/compiler/ir1final.lisp +++ b/src/compiler/ir1final.lisp @@ -57,45 +57,48 @@ ;;; possibility that new references might be converted to it. (defun finalize-xep-definition (fun) (let* ((leaf (functional-entry-fun fun)) + (source-name (and (leaf-has-source-name-p leaf) + (leaf-source-name leaf))) (ns *ir1-namespace*) (defined-ftype (definition-type leaf))) (setf (leaf-type leaf) defined-ftype) - (when (and (leaf-has-source-name-p leaf) - (eq (leaf-source-name leaf) (functional-debug-name leaf)) - (functional-top-level-defun-p leaf)) - (let ((source-name (leaf-source-name leaf))) - (let* ((where (info :function :where-from source-name)) - (*compiler-error-context* (lambda-bind (main-entry leaf))) - (global-def (gethash source-name (free-funs ns))) - (global-p (defined-fun-p global-def))) - (note-name-defined source-name :function) - (when global-p - (remhash source-name (free-funs ns))) - (ecase where - (:assumed - (let ((approx-type (info :function :assumed-type source-name))) - (when (and approx-type (fun-type-p defined-ftype)) - (valid-approximate-type approx-type defined-ftype)) - ;; globaldb can't enforce invariants such as :assumed-type and - ;; :type being mutually exclusive. For that reason it would have - ;; made sense to use a single info-type holding either a true - ;; function type or an approximate-fun-type. Regardless, it is - ;; slightly preferable to clear the old before setting the new. - (clear-info :function :assumed-type source-name) - (setf (info :function :type source-name) defined-ftype)) - (setf (info :function :where-from source-name) :defined)) - ((:declared :defined-method) - (let ((declared-ftype (global-ftype source-name))) - (unless (defined-ftype-matches-declared-ftype-p + (when (and source-name + (eq source-name (functional-debug-name leaf)) + ;; FIXME (?): We don't know how to set the globaldb + ;; info for these kinds of names. + (not (pcl-methodfn-name-p source-name))) + (let* ((where (info :function :where-from source-name)) + (*compiler-error-context* (lambda-bind (main-entry leaf))) + (global-def (gethash source-name (free-funs ns))) + (global-p (defined-fun-p global-def))) + (note-name-defined source-name :function) + (when global-p + (remhash source-name (free-funs ns))) + (ecase where + (:assumed + (let ((approx-type (info :function :assumed-type source-name))) + (when (and approx-type (fun-type-p defined-ftype)) + (valid-approximate-type approx-type defined-ftype)) + ;; globaldb can't enforce invariants such as :assumed-type and + ;; :type being mutually exclusive. For that reason it would have + ;; made sense to use a single info-type holding either a true + ;; function type or an approximate-fun-type. Regardless, it is + ;; slightly preferable to clear the old before setting the new. + (clear-info :function :assumed-type source-name) + (setf (info :function :type source-name) defined-ftype)) + (setf (info :function :where-from source-name) :defined)) + ((:declared :defined-method) + (let ((declared-ftype (global-ftype source-name))) + (unless (defined-ftype-matches-declared-ftype-p defined-ftype declared-ftype) - (compiler-style-warn - "~@<The previously declared FTYPE~ + (compiler-style-warn + "~@<The previously declared FTYPE~ ~2I ~_~/sb-impl:print-type/~I ~_~ conflicts with the definition type ~ ~2I~_~/sb-impl:print-type/~:>" - declared-ftype defined-ftype)))) - (:defined - (setf (info :function :type source-name) defined-ftype))))))) + declared-ftype defined-ftype)))) + (:defined + (setf (info :function :type source-name) defined-ftype)))))) (values)) ;;; Find all calls in COMPONENT to assumed functions and update the @@ -123,8 +126,7 @@ (do-nodes-backwards (node lvar block :restart-p t) (let ((dest (when lvar (lvar-dest lvar)))) (cond ((and (cast-p dest) - (not (cast-type-check dest)) - (almost-immediately-used-p lvar node)) + (not (cast-type-check dest))) (let ((dtype (node-derived-type node)) (atype (node-derived-type dest))) (when (values-types-equal-or-intersect @@ -144,7 +146,10 @@ (delete-filter node lvar (cast-value node)))))))) (defglobal *two-arg-functions* - `((* two-arg-*) + `((* two-arg-* + ,@(sb-c::unless-vop-existsp (:translate sb-c::fixnum*) + `((,(specifier-type 'fixnum) ,(specifier-type 'fixnum)) + multiply-fixnums))) (+ two-arg-+) (- two-arg--) (/ two-arg-/ (,(specifier-type 'integer) ,(specifier-type 'integer)) sb-kernel::integer-/-integer) @@ -194,6 +199,28 @@ (def-two-arg-funs (number number) >= <= /=) +;;; A list of function which always call their functional argument correctly, +;;; meaning that no arg-count-error can occur in the callee +;;; and therefore the callee can skip the check. +(dolist (fun '(sb-thread::call-with-mutex + sb-thread::call-with-recursive-lock + sb-thread::call-with-system-mutex + sb-thread::call-with-system-mutex/allow-with-interrupts + sb-thread::call-with-system-mutex/without-gcing + sb-thread::call-with-recursive-system-lock + ;; wish we had a little more commonality to these names + sb-impl::%with-standard-io-syntax + sb-impl::%with-rebound-io-syntax + sb-debug::funcall-with-debug-io-syntax + sb-impl::call-with-sane-io-syntax + ;; there are others, maybe %with-compilation-unit + sb-impl::%print-unreadable-object + )) + (let ((info (info :function :info fun))) + (when info + (setf (ir1-attributep (fun-info-attributes info) callee-omit-arg-count-check) + t)))) + ;;; Convert function designators to functions in calls to known functions ;;; Also convert to TWO-ARG- variants (defun ir1-optimize-functional-arguments (component) @@ -201,44 +228,70 @@ (do-nodes (node nil block) (when (and (combination-p node) (eq (combination-kind node) :known) + ;; REDUCE can call with zero arguments. (neq (lvar-fun-name (combination-fun node) t) 'reduce)) (map-callable-arguments - (lambda (lvar args results &key no-function-conversion &allow-other-keys) - (declare (ignore results)) - (unless no-function-conversion - (let ((ref (lvar-uses lvar)) - (arg-count (length args))) - (labels ((translate-two-args (name) - (and (eql arg-count 2) - (not (fun-lexically-notinline-p name (node-lexenv node))) - (cadr (assoc name *two-arg-functions*)))) - (translate (ref) - (let* ((leaf (ref-leaf ref)) - (fun-name (and (constant-p leaf) - (constant-value leaf))) - (replacement - (cond ((and fun-name (symbolp fun-name)) - (translate-two-args fun-name)) - ((and (global-var-p leaf) - (eq (global-var-kind leaf) :global-function)) - (translate-two-args (global-var-%source-name leaf))))) - (*compiler-error-context* node)) - (and replacement - (find-free-fun replacement "ir1-finalize"))))) - (cond ((ref-p ref) - (let ((replacement (translate ref))) - (when replacement - (change-ref-leaf ref replacement)))) - ((cast-p ref) - (let* ((cast ref) - (ref (lvar-uses (cast-value cast)))) - (when (ref-p ref) - (let ((replacement (translate ref))) - (when replacement - (change-ref-leaf ref replacement :recklessly t) - (setf (node-derived-type cast) - (lvar-derived-type (cast-value cast))))))))))))) - node))))) + (lambda (lvar args results &key no-function-conversion &allow-other-keys) + (declare (ignore results)) + ;; Process annotations while the original values are still there. + (process-annotations lvar) + (unless no-function-conversion + (let ((ref (lvar-uses lvar)) + (arg-count (length args))) + (labels ((translate-two-args (name) + (and (eql arg-count 2) + (not (fun-lexically-notinline-p name (node-lexenv node))) + (cadr (assoc name *two-arg-functions*)))) + (translate (ref) + (let* ((leaf (ref-leaf ref)) + (fun-name (and (constant-p leaf) + (constant-value leaf))) + (replacement + (cond ((and fun-name (symbolp fun-name)) + (or (translate-two-args fun-name) + (and (not (memq (info :function :kind fun-name) + '(:macro :special-form))) + fun-name))) + ((and (global-var-p leaf) + (eq (global-var-kind leaf) :global-function)) + (translate-two-args (global-var-%source-name leaf))))) + (*compiler-error-context* node)) + (and replacement + (find-global-fun replacement t))))) + (cond ((ref-p ref) + (let ((replacement (translate ref))) + (when replacement + (change-ref-leaf ref replacement)))) + ((cast-p ref) + (let* ((cast ref) + (ref (lvar-uses (cast-value cast)))) + (when (ref-p ref) + (let ((replacement (translate ref))) + (when replacement + (change-ref-leaf ref replacement :recklessly t) + (setf (node-derived-type cast) + (lvar-derived-type (cast-value cast))))))))))))) + node) + ;; One more thing: builtin higher-order functions utilized by builtin macros + ;; can impart a policy change to the callee, but it can't (easily) be done + ;; strictly lexically, because the policy would leak downward. + ;; e.g. (WITH-SOME-STUFF () ..) -> + ;; -> (DX-FLET ((THUNK () <user-code>)) (CALL-WITH-STUFF #'THUNK)) + ;; should not inject (OPTIMIZE (VERIFY-ARG-COUNT 0)) at the top of <user-code> + ;; because every lambda therein would omit the arg-count check. + (when (ir1-attributep (fun-info-attributes (combination-fun-info node)) + callee-omit-arg-count-check) + (let* ((args (combination-args node)) + (arg (if (eq (lvar-fun-name (combination-fun node) t) + 'sb-impl::%print-unreadable-object) + (fourth args) + (first args))) + (ref (and arg (lvar-uses arg)))) + (when (and (ref-p ref) (lambda-p (ref-leaf ref))) + ;; It seems impolite (un-debuggable too) to alter the lexenv-policy + ;; of functional-lexenv, so annotate this differently. + (setf (getf (functional-plist (ref-leaf ref)) 'verify-arg-count) + nil)))))))) (defun rewrite-full-call (combination) (let ((combination-name (lvar-fun-name (combination-fun combination) t)) @@ -257,6 +310,8 @@ for type in types always (csubtypep (lvar-type arg) type))) (setf two-arg typed-two-arg)) + (setf (combination-fun-info combination) + (fun-info-or-lose two-arg)) (change-ref-leaf ref (find-free-fun two-arg "rewrite-full-call"))))))) diff --git a/src/compiler/ir1opt.lisp b/src/compiler/ir1opt.lisp index d559eec07a..1a980182cf 100644 --- a/src/compiler/ir1opt.lisp +++ b/src/compiler/ir1opt.lisp @@ -20,60 +20,77 @@ ;;; Return true for an LVAR whose sole use is a reference to a ;;; constant leaf. -(defun constant-lvar-p (thing) - (declare (type (or lvar null) thing)) - (and (lvar-p thing) - (let* ((type (lvar-type thing)) - (principal-lvar (principal-lvar thing)) - (principal-use (lvar-uses principal-lvar)) - leaf) - (or (and (ref-p principal-use) - (constant-p (setf leaf (ref-leaf principal-use))) - ;; LEAF may be a CONSTANT behind a cast that will - ;; later turn out to be of the wrong type. - ;; And ir1-transforms suffer from this because - ;; they expect LVAR-VALUE to be of a restricted type. - (or (not (lvar-reoptimize principal-lvar)) - (ctypep (constant-value leaf) type))) - ;; check for EQL types and singleton numeric types - (values (type-singleton-p type)))))) +(defun constant-lvar-p (lvar) + (declare (type lvar lvar)) + (let* ((type (lvar-type lvar)) + (principal-lvar (principal-lvar lvar)) + (principal-use (lvar-uses principal-lvar)) + leaf) + (or (and (ref-p principal-use) + (constant-p (setf leaf (ref-leaf principal-use))) + ;; LEAF may be a CONSTANT behind a cast that will + ;; later turn out to be of the wrong type. + ;; And ir1-transforms suffer from this because + ;; they expect LVAR-VALUE to be of a restricted type. + (or (not (lvar-reoptimize principal-lvar)) + (ctypep (constant-value leaf) type))) + ;; check for EQL types and singleton numeric types + (values (type-singleton-p type))))) + +(defun constant-lvar-ignore-types-p (lvar &optional (singleton-types t)) + (declare (type lvar lvar)) + (let ((use (principal-lvar-use lvar))) + (or (and (ref-p use) + (constant-p (ref-leaf use))) + ;; check for EQL types and singleton numeric types + (and singleton-types + (values (type-singleton-p (lvar-type lvar))))))) ;;; Are all the uses constant? -(defun constant-lvar-uses-p (thing) - (declare (type (or lvar null) thing)) - (and (lvar-p thing) - (let* ((type (lvar-type thing)) - (principal-lvar (principal-lvar thing)) - (uses (lvar-uses principal-lvar)) - leaf) - (when (consp uses) - (loop for use in uses - always - (and (ref-p use) - (constant-p (setf leaf (ref-leaf use))) - ;; LEAF may be a CONSTANT behind a cast that will - ;; later turn out to be of the wrong type. - ;; And ir1-transforms suffer from this because - ;; they expect LVAR-VALUE to be of a restricted type. - (or (not (lvar-reoptimize principal-lvar)) - (ctypep (constant-value leaf) type)))))))) +(defun constant-lvar-uses-p (lvar) + (declare (type lvar lvar)) + (let* ((type (lvar-type lvar)) + (principal-lvar (principal-lvar lvar)) + (uses (lvar-uses principal-lvar)) + leaf) + (when (consp uses) + (loop for use in uses + always + (and (ref-p use) + (constant-p (setf leaf (ref-leaf use))) + ;; LEAF may be a CONSTANT behind a cast that will + ;; later turn out to be of the wrong type. + ;; And ir1-transforms suffer from this because + ;; they expect LVAR-VALUE to be of a restricted type. + (or (not (lvar-reoptimize principal-lvar)) + (ctypep (constant-value leaf) type))))))) ;;; Return the constant value for an LVAR whose only use is a constant ;;; node. -(declaim (ftype (function (lvar) t) lvar-value)) (defun lvar-value (lvar) + (declare (type lvar lvar)) (let ((use (principal-lvar-use lvar)) (type (lvar-type lvar)) leaf) (if (and (ref-p use) (constant-p (setf leaf (ref-leaf use)))) - (constant-value leaf) + (values (constant-value leaf) leaf) (multiple-value-bind (constantp value) (type-singleton-p type) (unless constantp (error "~S used on non-constant LVAR ~S" 'lvar-value lvar)) - value)))) + (values value (find-constant value)))))) + +(defun lvar-value-is-nil (lvar) + (and (constant-lvar-p lvar) (null (lvar-value lvar)))) + +;;; Return true if ARG is NIL, or is a constant-lvar whose +;;; value is NIL, false otherwise. +(defun unsupplied-or-nil (arg) + (declare (type (or lvar null) arg)) + (or (not arg) (lvar-value-is-nil arg))) (defun lvar-uses-values (lvar) + (declare (type lvar lvar)) (let ((uses (principal-lvar-use lvar))) (loop for use in uses for leaf = (ref-leaf use) @@ -289,6 +306,9 @@ (let* ((block (node-block node)) (component (block-component block))) (setf (node-reoptimize node) t) + (when (cast-p node) + (do-uses (node (cast-value node)) + (reoptimize-node node))) (reoptimize-component component t) (setf (block-reoptimize block) t))) @@ -370,7 +390,6 @@ ;;;; IR1-OPTIMIZE -#-sb-devel (declaim (start-block ir1-optimize ir1-optimize-last-effort)) ;;; Do one forward pass over COMPONENT, deleting unreachable blocks @@ -462,7 +481,11 @@ (setf (node-reoptimize node) nil) (typecase node (combination - (ir1-optimize-combination-fast node)))))) + (ir1-optimize-combination-fast node)) + (cif + ;; Don't want comparisons of constants against constants + ;; from reaching the VOPs. + (ir1-optimize-if node t)))))) ;;; Only handle constant folding, some VOPs do not work ;;; on constants. @@ -478,7 +501,11 @@ (= (length args) 2) (constant-lvar-p (first args)) (not (constant-lvar-p (second args)))) - (setf (basic-combination-args node) (nreverse args)))))))) + (setf (basic-combination-args node) (nreverse args))))) + (:full + ;; Probably, this can only come from CUT-TO-WIDTH + ;; otherwise normal ir1-convert would've called recognize-known-call. + (recognize-known-call node nil nil nil))))) ;;; Loop over the nodes in BLOCK, acting on (and clearing) REOPTIMIZE ;;; flags. @@ -519,7 +546,9 @@ ;; type. (let ((value (exit-value node))) (when value - (derive-node-type node (lvar-derived-type value))))) + (derive-node-type node (if (lvar-single-value-p (node-lvar node)) + (lvar-type value) + (lvar-derived-type value)))))) (cset ;; PROPAGATE-FROM-SETS can do a better job if NODE-REOPTIMIZE ;; is accurate till the node actually has been reoptimized. @@ -547,8 +576,9 @@ (delete-lvar-use other-node))) (typecase node (ref - (delete-ref node) - (unlink-node node)) + (when (flushable-reference-p node) + (delete-ref node) + (unlink-node node))) (combination (when (and (not (node-tail-p node)) (flushable-combination-p node)) @@ -669,7 +699,6 @@ ;;;; IF optimization -#-sb-devel (declaim (start-block ir1-optimize-if)) ;;; Check whether the predicate is known to be true or false, @@ -679,39 +708,40 @@ ;;; of them. ;;; Also, if the test has multiple uses, replicate the node when possible... ;;; in fact, splice in direct jumps to the right branch if possible. -(defun ir1-optimize-if (node) +(defun ir1-optimize-if (node &optional fast) (declare (type cif node)) - (let ((test (if-test node)) - (block (node-block node))) - (let* ((type (lvar-type test)) - (consequent (if-consequent node)) - (alternative (if-alternative node)) - (victim - (cond ((constant-lvar-p test) - (if (lvar-value test) alternative consequent)) - ((not (types-equal-or-intersect type (specifier-type 'null))) - alternative) - ((type= type (specifier-type 'null)) - consequent) - ((or (eq consequent alternative) + (let* ((test (if-test node)) + (block (node-block node))(type (lvar-type test)) + (consequent (if-consequent node)) + (alternative (if-alternative node)) + (victim + (cond ((constant-lvar-p test) + (if (lvar-value test) alternative consequent)) + ((not (types-equal-or-intersect type (specifier-type 'null))) + alternative) + ((type= type (specifier-type 'null)) + consequent) + ((eq consequent alternative) + alternative) + ((and (not fast) + (or (blocks-equivalent-p alternative consequent) - (if-test-redundant-p test consequent alternative)) - ;; Even if the references are the same they can have - ;; different derived types based on the TEST - ;; Don't lose the second type when killing it. - (let ((consequent-ref (block-start-node consequent))) - (derive-node-type consequent-ref - (values-type-union - (node-derived-type consequent-ref) - (node-derived-type (block-start-node alternative))) - :from-scratch t)) - alternative)))) - (when victim - (kill-if-branch-1 node test block victim) - (return-from ir1-optimize-if (values)))) - (tension-if-if-1 node test block) - (duplicate-if-if-1 node test block) - (values))) + (if-test-redundant-p test consequent alternative))) + ;; Even if the references are the same they can have + ;; different derived types based on the TEST + ;; Don't lose the second type when killing it. + (let ((consequent-ref (block-start-node consequent))) + (derive-node-type consequent-ref + (values-type-union + (node-derived-type consequent-ref) + (node-derived-type (block-start-node alternative))) + :from-scratch t)) + alternative)))) + (cond (victim + (kill-if-branch-1 node test block victim)) + ((not fast) + (tension-if-if-1 node test block) + (duplicate-if-if-1 node test block))))) ;; When we know that we only have a single successor, kill the victim ;; ... unless the victim and the remaining successor are the same. @@ -785,13 +815,13 @@ (when (and lvar (listp (lvar-uses lvar))) (do-uses (use lvar) - (let ((block (node-block use))) - (when (and (immediately-used-p lvar use) - (type= (single-value-type (node-derived-type use)) - (specifier-type 'null)) - (eq (block-last block) use) - (or good-lambda-shape - (setf good-lambda-shape (split-let var lambda)))) + (when (and (immediately-used-p lvar use) + (type= (single-value-type (node-derived-type use)) + (specifier-type 'null)) + (eq (block-last (node-block use)) use) + (or good-lambda-shape + (setf good-lambda-shape (split-let var lambda)))) + (let ((block (node-block use))) (change-block-successor block (car (block-succ block)) (if-alternative node)) @@ -803,13 +833,17 @@ (call (and ref (node-lvar ref) (lvar-dest (node-lvar ref)))) - (vars (lambda-vars original-lambda))) + (all-vars (lambda-vars original-lambda))) (when (and call - (eq var (car (last vars))) - (notany #'lambda-var-specvar vars)) + (eq var (car (last all-vars))) + (notany #'lambda-var-specvar all-vars)) (or (= (count-if #'identity (combination-args call)) 1) (with-ir1-environment-from-node call - (let* ((penultimate (lvar-uses (car (last (combination-args call) 2)))) + (let* ((all-args (combination-args call)) + (penultimate-arg (find-if #'identity all-args + :from-end t + :end (1- (length all-args)))) + (penultimate (lvar-uses penultimate-arg)) (penultimate (if (consp penultimate) (car penultimate) penultimate)) @@ -820,7 +854,7 @@ :pred (block-pred next-block) :succ (list next-block))) (bind (make-bind)) - (vars (butlast vars)) + (vars (butlast all-vars)) (lambda (make-lambda :vars vars :kind :let :bind bind @@ -828,11 +862,11 @@ :%source-name 'split :%debug-name `(split ,(lambda-%debug-name original-lambda)))) (ref (make-ref lambda)) - (args (butlast (combination-args call)))) + (args (butlast all-args))) (push lambda (lambda-lets (lambda-home original-lambda))) (push ref (lambda-refs lambda)) - (setf (combination-args call) (last (combination-args call))) - (setf (lambda-vars original-lambda) (last (lambda-vars original-lambda)) + (setf (combination-args call) (last all-args)) + (setf (lambda-vars original-lambda) (last all-vars) (lambda-tail-set lambda) (make-tail-set :funs (list lambda))) (setf (bind-lambda bind) lambda) (loop for var in vars @@ -851,13 +885,13 @@ (node-reoptimize ref) nil) (use-lvar ref lambda-lvar) (setf (lvar-dest lambda-lvar) call) - (insert-node-before-no-split bind call) + (insert-node-before bind call) (setf (combination-kind call) :local (combination-args call) args) (loop for arg in args when arg do (setf (lvar-dest arg) call)) - (insert-node-before-no-split call ref)) + (insert-node-before call ref)) t)))))) ;; Finally, duplicate EQ-nil tests @@ -947,21 +981,32 @@ (when (and entry (eq (node-home-lambda node) (node-home-lambda entry))) (setf (entry-exits entry) (delq1 node (entry-exits entry))) - (if value - (delete-filter node (node-lvar node) value) - (unlink-node node))))) + (cond (value + ;; The number of consumed values is now known, reoptimize the users. + ;; The VALUES transform in particular benefits from this. + (do-uses (use value) + (reoptimize-node use)) + (delete-filter node (node-lvar node) value)) + (t + (unlink-node node)))))) ;;;; combination IR1 optimization -#-sb-devel (declaim (start-block ir1-optimize-combination maybe-terminate-block - validate-call-type)) + validate-call-type recognize-known-call)) (defun check-important-result (node info) (when (and (null (node-lvar node)) (ir1-attributep (fun-info-attributes info) important-result) (neq (combination-info node) :important-result-discarded)) + (when (lvar-fun-is (combination-fun node) '(adjust-array)) + (let ((type (lvar-type (car (combination-args node))))) + ;; - if the array is simple, then result is important + ;; - if non-simple, then result is not important + ;; - if not enough information, then don't warn + (when (or (not (array-type-p type)) (array-type-complexp type)) ; T or :MAYBE + (return-from check-important-result)))) (let ((*compiler-error-context* node)) (setf (combination-info node) :important-result-discarded) (compiler-style-warn @@ -1044,7 +1089,7 @@ (let ((original-lambda-list (second original-lambda))) ;; KISS - the closure that you're passing can have 0 or more ;; mandatory args and nothing else. - (unless (intersection original-lambda-list sb-xc:lambda-list-keywords) + (unless (intersection original-lambda-list lambda-list-keywords) (push `(,tempname ,original-lambda-list (%funcall ,(nth arg-spec received-args) ,@original-lambda-list)) @@ -1066,16 +1111,30 @@ ;;; the code - it does; but compiler doesn't appear to respect the DX-FLET. (defglobal *dxify-args-transform* (make-transform :type (specifier-type 'function) - :function (lambda (node) + :%fun (lambda (node) + "auto-DX" (or (let ((name (combination-fun-source-name node))) (dxify-downward-funargs node (fun-name-dx-args name) name)) - (give-up-ir1-transform))) - :note "auto-DX")) + (give-up-ir1-transform))))) + +(defun check-proper-sequences (combination info) + (when (fun-info-annotation info) + (map-combination-args-and-types + (lambda (lvar type lvars annotations) + (declare (ignore type lvars)) + (when (constant-lvar-p lvar) + (loop with value = (lvar-value lvar) + for annotation in annotations + when (improper-sequence-p annotation value) + do + (setf (combination-kind combination) :error) + (return-from check-proper-sequences)))) + combination info))) ;;; Do IR1 optimizations on a COMBINATION node. -(declaim (ftype (function (combination) (values)) ir1-optimize-combination)) -(defun ir1-optimize-combination (node) +(defun ir1-optimize-combination (node &aux (show *show-transforms-p*)) + (declare (type combination node)) (when (lvar-reoptimize (basic-combination-fun node)) (propagate-fun-change node) (when (node-deleted node) @@ -1090,10 +1149,13 @@ (setf (lvar-reoptimize arg) nil)))) (process-info () (check-important-result node info) + (check-proper-sequences node info) (let ((fun (fun-info-derive-type info))) (when fun (let ((res (funcall fun node))) (when res + (when (eq show :derive-type) + (show-type-derivation node res)) (derive-node-type node (coerce-to-values res)) (maybe-terminate-block node nil))))))) (ecase kind @@ -1143,6 +1205,8 @@ (when (constant-fold-call-p node) (constant-fold-call node) (return-from ir1-optimize-combination)) + (when (fold-call-derived-to-constant node) + (return-from ir1-optimize-combination)) (when (and (ir1-attributep attr commutative) (= (length args) 2) (constant-lvar-p (first args)) @@ -1172,14 +1236,14 @@ ;; Are type checks getting in the way? (or (try-equality-constraint node) (dolist (x (fun-info-transforms info)) - (when (eq *show-transforms-p* :all) + (when (eq show :all) (let* ((lvar (basic-combination-fun node)) (fname (lvar-fun-name lvar t))) (format *trace-output* "~&trying transform ~s for ~s" (transform-type x) fname))) - (unless (ir1-transform node x) - (when (eq *show-transforms-p* :all) + (unless (ir1-transform node x show) + (when (eq show :all) (format *trace-output* "~&quitting because IR1-TRANSFORM result was NIL")) (return)))))))))))))) @@ -1217,11 +1281,18 @@ (succ (first (block-succ block)))) (declare (ignore lvar)) (unless (or (and (eq node (block-last block)) (eq succ tail)) - (block-delete-p block)) - ;; Even if the combination will never return, don't terminate if this - ;; is the tail call of a XEP: doing that would inhibit TCO. - (when (and (eq (node-derived-type node) *empty-type*) - (not (xep-tail-combination-p node))) + (block-delete-p block) + ;; Even if the combination will never return, don't + ;; terminate if this is the tail call of a XEP: doing + ;; that would inhibit TCO. + (xep-tail-combination-p node) + ;; Do not consider the block for termination if this + ;; is a LET-like combination, since the successor of + ;; this node is the body of the LET. + (and (combination-p node) + (eq (combination-kind node) :local) + (functional-somewhat-letlike-p (combination-lambda node)))) + (when (eq (node-derived-type node) *empty-type*) (cond (ir1-converting-not-optimizing-p (cond ((block-last block) @@ -1266,7 +1337,7 @@ ;;; We return the leaf referenced (NIL if not a leaf) and the ;;; FUN-INFO assigned. (defun recognize-known-call (call ir1-converting-not-optimizing-p - &optional unknown-keys) + &optional unknown-keys (inline t)) (declare (type combination call)) (let* ((ref (lvar-uses (basic-combination-fun call))) (leaf (when (ref-p ref) (ref-leaf ref))) @@ -1274,6 +1345,8 @@ (defined-fun-inlinep leaf) 'no-chance))) (cond + ((eq (basic-combination-kind call) :error) + (values nil nil)) (unknown-keys (setf (basic-combination-kind call) :unknown-keys) (values leaf nil)) @@ -1285,7 +1358,8 @@ ((not (and (global-var-p leaf) (eq (global-var-kind leaf) :global-function))) (values leaf nil)) - ((and (ecase inlinep + ((and inline + (ecase inlinep (inline t) (no-chance nil) ((nil maybe-inline) (policy call (zerop space)))) @@ -1299,43 +1373,43 @@ ;; For INLINE case local call analysis will copy the expansion later, ;; but for MAYBE-INLINE and NIL cases we only get one copy of the ;; expansion per component. - ;; - ;; FIXME: We also convert in INLINE & FUNCTIONAL-KIND case below. What - ;; is it for? (with-ir1-environment-from-node call (let ((fun (defined-fun-functional leaf))) - (if (or (not fun) - (and (eq inlinep 'inline) (functional-kind fun)) - ;; Referencing it again will break the invariant - ;; for assignment functions. - (eq (functional-kind fun) :assignment)) - ;; Convert. - (let* ((name (leaf-source-name leaf)) - (*inline-expansions* - (register-inline-expansion leaf call)) - (res (ir1-convert-inline-expansion - name - (defined-fun-inline-expansion leaf) - leaf - inlinep - (info :function :info name)))) - ;; Allow backward references to this function from following - ;; forms. (Reused only if policy matches.) - (push res (defined-fun-functionals leaf)) - (change-ref-leaf ref res) - (unless ir1-converting-not-optimizing-p - (locall-analyze-component *current-component*))) - ;; If we've already converted, change ref to the converted - ;; functional. - (change-ref-leaf ref fun)))) + (cond ((or (not fun) + ;; It has already been processed by locall, + ;; inline again. + (functional-kind fun)) + (when (eq (car *current-path*) 'original-source-start) + (setf (ctran-source-path (node-prev call)) *current-path*)) + ;; Convert. + (let* ((name (leaf-source-name leaf)) + (*inline-expansions* + (register-inline-expansion leaf call)) + (res (ir1-convert-inline-expansion + name + (defined-fun-inline-expansion leaf) + leaf + inlinep + (info :function :info name)))) + + ;; Allow backward references to this function from following + ;; forms. (Reused only if policy matches.) + (push res (defined-fun-functionals leaf)) + (change-ref-leaf ref res) + (unless ir1-converting-not-optimizing-p + (locall-analyze-component *current-component*)))) + (t + ;; If we've already converted, change ref to the converted + ;; functional. + (maybe-reanalyze-functional fun) + (change-ref-leaf ref fun))))) (values (ref-leaf ref) nil)) (t (let ((info (info :function :info (leaf-source-name leaf)))) (if info (values leaf - (progn - (setf (basic-combination-kind call) :known) - (setf (basic-combination-fun-info call) info))) + (setf (basic-combination-kind call) :known + (basic-combination-fun-info call) info)) (values leaf nil))))))) ;;; Check whether CALL satisfies TYPE. If so, apply the type to the @@ -1382,8 +1456,11 @@ (cond (valid (assert-call-type call type) (maybe-terminate-block call ir1-converting-not-optimizing-p) - (setf (combination-kind call) :full) - (recognize-known-call call ir1-converting-not-optimizing-p unknown-keys)) + (cond ((eq (combination-kind call) :error) + (values nil nil)) + (t + (setf (combination-kind call) :full) + (recognize-known-call call ir1-converting-not-optimizing-p unknown-keys)))) (t (setf (combination-kind call) :error) (values nil nil)))))))) @@ -1403,7 +1480,8 @@ (case (combination-kind call) (:local (let ((fun (combination-lambda call))) - (maybe-let-convert fun) + (or (maybe-let-convert fun) + (maybe-convert-to-assignment fun)) (unless (member (functional-kind fun) '(:let :assignment :deleted)) (derive-node-type call (tail-set-type (lambda-tail-set fun)))))) (:full @@ -1460,11 +1538,11 @@ ;;; finalize to pick up. We return true if the transform failed, and ;;; thus further transformation should be attempted. We return false ;;; if either the transform succeeded or was aborted. -(defun ir1-transform (node transform) +(defun ir1-transform (node transform show) (declare (type combination node) (type transform transform)) (declare (notinline warn)) ; See COMPILER-WARN for rationale (let* ((type (transform-type transform)) - (fun (transform-function transform)) + (fun (transform-%fun transform)) (constrained (fun-type-p type)) (table (component-failed-optimizations *component-being-compiled*)) (flame (case (transform-important transform) @@ -1478,14 +1556,13 @@ (valid-fun-use node type)) (multiple-value-bind (severity args) (catch 'give-up-ir1-transform - (transform-call node - (let ((new-form (funcall fun node))) - (when *show-transforms-p* - (show-transform "ir" - (combination-fun-source-name node) - new-form)) - new-form) - (combination-fun-source-name node)) + (let ((new-form (if (listp fun) ; the deftransform had :INFO + (funcall (car fun) node (cdr fun)) + (funcall fun node))) + (fun-name (combination-fun-source-name node))) + (when (show-transform-p show fun-name) + (show-transform "ir" fun-name new-form node)) + (transform-call node new-form fun-name)) (values :none nil)) (ecase severity (:none @@ -1549,6 +1626,9 @@ (throw 'give-up-ir1-transform (values :failure args))) (defun abort-ir1-transform (&rest args) (throw 'give-up-ir1-transform (values :aborted args))) + +(defvar *delayed-ir1-transforms*) + (defun delay-ir1-transform (node &rest reasons) (let ((assoc (assoc node *delayed-ir1-transforms*))) (cond ((not assoc) @@ -1631,12 +1711,16 @@ (with-ir1-environment-from-node call (with-component-last-block (*current-component* (block-next (node-block call))) - (let ((new-fun (ir1-convert-inline-lambda - res - :debug-name (debug-name 'lambda-inlined source-name) - :system-lambda t)) - (type (node-derived-type call)) - (ref (lvar-use (combination-fun call)))) + (unless (or (memq 'transformed *current-path*) + (memq 'inlined *current-path*)) + (setf (ctran-source-path (node-prev call)) *current-path*)) + (let* ((*transforming* (1+ *transforming*)) + (new-fun (ir1-convert-inline-lambda + res + :debug-name (debug-name 'lambda-inlined source-name) + :system-lambda t)) + (type (node-derived-type call)) + (ref (lvar-use (combination-fun call)))) (change-ref-leaf ref new-fun) (setf (combination-kind call) :full) ;; Don't lose the original derived type @@ -1682,11 +1766,11 @@ (declare (ignore type lvars)) (unless (if (eql (car annotation) 'function-designator) (let ((fun (or (lvar-fun-name arg t) - (and (constant-lvar-p arg) + (and (constant-lvar-ignore-types-p arg) (lvar-value arg))))) (and fun (constant-fold-arg-p fun))) - (constant-lvar-p arg)) + (constant-lvar-ignore-types-p arg)) (return-from constant-fold-call-p))) combination info @@ -1694,7 +1778,7 @@ (return-from constant-fold-call-p))) t) (t - (every #'constant-lvar-p args))))) + (every #'constant-lvar-ignore-types-p args))))) ;;; Replace a call to a foldable function of constant arguments with ;;; the result of evaluating the form. If there is an error during the @@ -1718,53 +1802,11 @@ (resolve-key-args args type) args))) (args (mapcar #'value lvar-args))) - (multiple-value-bind (values win) - (careful-call fun-name - args - call - ;; Note: CMU CL had COMPILER-WARN here, and that - ;; seems more natural, but it's probably not. - ;; - ;; It's especially not while bug 173 exists: - ;; Expressions like - ;; (COND (END - ;; (UNLESS (OR UNSAFE? (<= END SIZE))) - ;; ...)) - ;; can cause constant-folding TYPE-ERRORs (in - ;; #'<=) when END can be proved to be NIL, even - ;; though the code is perfectly legal and safe - ;; because a NIL value of END means that the - ;; #'<= will never be executed. - ;; - ;; Moreover, even without bug 173, - ;; quite-possibly-valid code like - ;; (COND ((NONINLINED-PREDICATE END) - ;; (UNLESS (<= END SIZE)) - ;; ...)) - ;; (where NONINLINED-PREDICATE is something the - ;; compiler can't do at compile time, but which - ;; turns out to make the #'<= expression - ;; unreachable when END=NIL) could cause errors - ;; when the compiler tries to constant-fold (<= - ;; END SIZE). - ;; - ;; So, with or without bug 173, it'd be - ;; unnecessarily evil to do a full - ;; COMPILER-WARNING (and thus return FAILURE-P=T - ;; from COMPILE-FILE) for legal code, so we we - ;; use a wimpier COMPILE-STYLE-WARNING instead. - #-sb-xc-host #'compiler-style-warn - ;; On the other hand, for code we control, we - ;; should be able to work around any bug - ;; 173-related problems, and in particular we - ;; want to be alerted to calls to our own - ;; functions which aren't being folded away; a - ;; COMPILER-WARNING is butch enough to stop the - ;; SBCL build itself in its tracks. - #+sb-xc-host #'compiler-warn - "constant folding") + (multiple-value-bind (values win) (careful-call fun-name args) (cond ((not win) - (setf (combination-kind call) :error)) + (setf (combination-kind call) :error + (combination-info call) + (list #'compiler-style-warn "Lisp error during constant folding:~%~A" values))) ((and (proper-list-of-length-p values 1)) (replace-combination-with-constant (first values) call)) (t (let ((dummies (make-gensym-list (length args)))) @@ -1783,10 +1825,18 @@ values))) fun-name))))))) (values)) + +(defun fold-call-derived-to-constant (call) + (when (flushable-combination-p call) + (let ((type (node-derived-type call))) + (when (type-single-value-p type) + (multiple-value-bind (single-p value) (type-singleton-p (single-value-type type)) + (when single-p + (replace-combination-with-constant value call) + t)))))) ;;;; local call optimization -#-sb-devel (declaim (start-block ir1-optimize-set constant-reference-p delete-let propagate-let-args propagate-local-call-args propagate-to-refs propagate-from-sets @@ -1854,85 +1904,123 @@ high (max this-high (or high this-high)))))) type)) -;;; Iteration variable: exactly one SETQ of the form: +;;; Iteration variable: only SETQs of the form: ;;; ;;; (let ((var initial)) ;;; ... -;;; (setq var (+ var step)) +;;; (setq var (+/- var step_1)) +;;; ... +;;; (setq var (+/- var step_k)) ;;; ...) +;;; +;;; such that the modifications either all increment or all decrement +;;; VAR. +(declaim (inline %inc-or-dec-p)) +(defun %inc-or-dec-p (node) + (and (combination-p node) + (eq (combination-kind node) :known) + (fun-info-p (combination-fun-info node)) + (not (node-to-be-deleted-p node)) + (let ((source-name (combination-fun-source-name node))) + (when (memq source-name '(- +)) + source-name)))) + +(defun %analyze-set-uses (sets var initial-type) + (let ((some-plusp nil) + (some-minusp nil) + (set-types '()) + (every-set-type-suitable-p t)) + (dolist (set sets) + (let* ((set-use (principal-lvar-use (set-value set))) + (function (%inc-or-dec-p set-use))) + (unless function ; every use must be + or - + (return-from %analyze-set-uses nil)) + (let ((args (basic-combination-args set-use))) + ;; Every use must be of the form ({+,-} VAR STEP). + (unless (and (proper-list-of-length-p args 2 2) + (let ((first (principal-lvar-use (first args)))) + (and (ref-p first) + (eq (ref-leaf first) var)))) + (return-from %analyze-set-uses nil)) + (let ((step-type (lvar-type (second args))) + (set-type (lvar-type (set-value set)))) + ;; In ({+,-} VAR STEP), the type of STEP must be a numeric + ;; type matching INITIAL-TYPE. + (unless (and (numeric-type-p step-type) + (or (numeric-type-equal initial-type step-type) + ;; Detect cases like (LOOP FOR 1.0 to 5.0 + ;; ...), where the initial and the step + ;; are of different types, and the step + ;; is less contagious. + (let ((contagion-type (numeric-contagion initial-type + step-type))) + (and (numeric-type-p contagion-type) + (numeric-type-equal initial-type contagion-type))))) + (return-from %analyze-set-uses nil)) + ;; Track the directions of the increments/decrements. + (let ((non-negative-p (csubtypep step-type (specifier-type '(real 0 *)))) + (non-positive-p (csubtypep step-type (specifier-type '(real * 0))))) + (cond ((or (and (eq function '+) non-negative-p) + (and (eq function '-) non-positive-p)) + (setf some-plusp t)) + ((or (and (eq function '-) non-negative-p) + (and (eq function '+) non-positive-p)) + (setf some-minusp t)) + (t ; Can't tell direction + (setf some-plusp t some-minusp t)))) + ;; Ultimately, the derived types of the sets must match + ;; INITIAL-TYPE if we are going to derive new bounds. + (unless (and (numeric-type-p set-type) + (numeric-type-equal set-type initial-type)) + (setf every-set-type-suitable-p nil)) + (push set-type set-types))))) + (values (cond ((and some-plusp (not some-minusp)) '+) + ((and some-minusp (not some-plusp)) '-) + (t '*)) + set-types every-set-type-suitable-p))) + (defun maybe-infer-iteration-var-type (var initial-type) (binding* ((sets (lambda-var-sets var) :exit-if-null) - (set (first sets)) - (() (null (rest sets)) :exit-if-null) - (set-use (principal-lvar-use (set-value set))) - (() (and (combination-p set-use) - (eq (combination-kind set-use) :known) - (fun-info-p (combination-fun-info set-use)) - (not (node-to-be-deleted-p set-use)) - (or (eq (combination-fun-source-name set-use) '+) - (eq (combination-fun-source-name set-use) '-))) - :exit-if-null) - (minusp (eq (combination-fun-source-name set-use) '-)) - (+-args (basic-combination-args set-use)) - (() (and (proper-list-of-length-p +-args 2 2) - (let ((first (principal-lvar-use - (first +-args)))) - (and (ref-p first) - (eq (ref-leaf first) var)))) - :exit-if-null) - (step-type (lvar-type (second +-args))) - (set-type (lvar-type (set-value set))) - (initial-type (weaken-numeric-union-type initial-type))) - (when (and (numeric-type-p initial-type) - (numeric-type-p step-type) - (or (numeric-type-equal initial-type step-type) - ;; Detect cases like (LOOP FOR 1.0 to 5.0 ...), where - ;; the initial and the step are of different types, - ;; and the step is less contagious. - (numeric-type-equal initial-type - (numeric-contagion initial-type - step-type)))) - (labels ((leftmost (x y cmp cmp=) - (cond ((eq x nil) nil) - ((eq y nil) nil) - ((listp x) - (let ((x1 (first x))) - (cond ((listp y) - (let ((y1 (first y))) - (if (funcall cmp x1 y1) x y))) - (t - (if (funcall cmp x1 y) x y))))) - ((listp y) - (let ((y1 (first y))) - (if (funcall cmp= x y1) x y))) - (t (if (funcall cmp x y) x y)))) - (max* (x y) (leftmost x y #'> #'>=)) - (min* (x y) (leftmost x y #'< #'<=))) - (multiple-value-bind (low high) - (let ((step-type-non-negative (csubtypep step-type (specifier-type - '(real 0 *)))) - (step-type-non-positive (csubtypep step-type (specifier-type - '(real * 0))))) - (cond ((or (and step-type-non-negative (not minusp)) - (and step-type-non-positive minusp)) - (values (numeric-type-low initial-type) - (when (and (numeric-type-p set-type) - (numeric-type-equal set-type initial-type)) - (max* (numeric-type-high initial-type) - (numeric-type-high set-type))))) - ((or (and step-type-non-positive (not minusp)) - (and step-type-non-negative minusp)) - (values (when (and (numeric-type-p set-type) - (numeric-type-equal set-type initial-type)) - (min* (numeric-type-low initial-type) - (numeric-type-low set-type))) - (numeric-type-high initial-type))) - (t - (values nil nil)))) - (modified-numeric-type initial-type - :low low - :high high - :enumerable nil)))))) + (initial-type (weaken-numeric-union-type initial-type)) + ((direction set-types every-set-type-suitable-p) + (when (numeric-type-p initial-type) + (%analyze-set-uses sets var initial-type)) + :exit-if-null)) + (labels ((leftmost (x y cmp cmp=) + (cond ((eq x nil) nil) + ((eq y nil) nil) + ((listp x) + (let ((x1 (first x))) + (cond ((listp y) + (let ((y1 (first y))) + (if (funcall cmp x1 y1) x y))) + (t + (if (funcall cmp x1 y) x y))))) + ((listp y) + (let ((y1 (first y))) + (if (funcall cmp= x y1) x y))) + (t (if (funcall cmp x y) x y))))) + (multiple-value-bind (low high) + (ecase direction + (+ + (values (numeric-type-low initial-type) + (when every-set-type-suitable-p + (reduce (lambda (x y) (leftmost x y #'> #'>=)) set-types + :initial-value (numeric-type-high initial-type) + :key #'numeric-type-high))) + ) + (- + (values (when every-set-type-suitable-p + (reduce (lambda (x y) (leftmost x y #'< #'<=)) set-types + :initial-value (numeric-type-low initial-type) + :key #'numeric-type-low)) + (numeric-type-high initial-type))) + (* + (values nil nil))) + (modified-numeric-type initial-type :low low + :high high + :enumerable nil))))) + (deftransform + ((x y) * * :result result) "check for iteration variable reoptimization" (let ((dest (principal-lvar-end result)) @@ -1946,7 +2034,7 @@ ;;; Figure out the type of a LET variable that has sets. We compute ;;; the union of the INITIAL-TYPE and the types of all the set -;;; values and to a PROPAGATE-TO-REFS with this type. +;;; values and do a PROPAGATE-TO-REFS with this type. (defun propagate-from-sets (var initial-type) (let ((types nil)) (dolist (set (lambda-var-sets var)) @@ -2034,10 +2122,12 @@ ;; we should not change lifetime of unknown values lvars (cast (and (type-single-value-p (lvar-derived-type arg)) - (multiple-value-bind (pdest pprev) - (principal-lvar-end lvar) - (declare (ignore pdest)) - (lvar-single-value-p pprev)) + (or + (let-var-immediately-used-p ref var arg) + (multiple-value-bind (pdest pprev) + (principal-lvar-end lvar) + (declare (ignore pdest)) + (lvar-single-value-p pprev))) ;; CASTs can disappear, don't substitute if ;; DEST-LVAR has other uses (block nil @@ -2072,7 +2162,11 @@ (eq (node-home-lambda ref) (lambda-home (lambda-var-home var)))) (let ((ref-type (single-value-type (node-derived-type ref)))) - (cond ((csubtypep (single-value-type (lvar-type arg)) ref-type) + (cond ((or (csubtypep (single-value-type (lvar-type arg)) ref-type) + ;; Can't impart the same type to multiple uses, as + ;; they are coming from different branches with + ;; different derived values. + (consp (lvar-uses lvar))) (substitute-lvar-uses lvar arg ;; Really it is (EQ (LVAR-USES LVAR) REF): t) @@ -2080,9 +2174,8 @@ (t (let* ((value (make-lvar)) (cast (insert-cast-before ref value ref-type - ;; KLUDGE: it should be (TYPE-CHECK 0) - *policy*))) - (setf (cast-type-to-check cast) *wild-type*) + **zero-typecheck-policy**))) + (setf (cast-%type-check cast) nil) (substitute-lvar-uses value arg ;; FIXME t) @@ -2106,10 +2199,14 @@ (declare (type clambda clambda)) (aver (functional-letlike-p clambda)) (note-unreferenced-fun-vars clambda) - (let ((call (let-combination clambda))) + (let ((call (let-combination clambda)) + (bind (lambda-bind clambda))) (flush-dest (basic-combination-fun call)) + (when (eq (car (node-source-path bind)) 'original-source-start) + (setf (ctran-source-path (node-prev (car (leaf-refs clambda)))) + (node-source-path bind))) (unlink-node call) - (unlink-node (lambda-bind clambda)) + (unlink-node bind) (setf (lambda-bind clambda) nil)) (setf (functional-kind clambda) :zombie) (let ((home (lambda-home clambda))) @@ -2263,7 +2360,8 @@ (let ((lambda (combination-lambda node))) (when (lvar-reoptimize fun) (setf (lvar-reoptimize fun) nil) - (maybe-let-convert lambda)) + (or (maybe-let-convert lambda) + (maybe-convert-to-assignment lambda))) (cond ((neq (functional-kind lambda) :mv-let) (loop for arg in (basic-combination-args node) do @@ -2286,7 +2384,8 @@ (when (and (ref-p use) (functional-p (ref-leaf use))) (convert-call-if-possible use node) (when (eq (basic-combination-kind node) :local) - (maybe-let-convert (ref-leaf use)))))) + (or (maybe-let-convert (ref-leaf use)) + (maybe-convert-to-assignment (ref-leaf use))))))) (unless (or (eq (basic-combination-kind node) :local) (eq (lvar-fun-name fun) '%throw)) (ir1-optimize-mv-call node)))) @@ -2500,14 +2599,14 @@ (let ((arg (pop args)) (new-lvar (pop lvars)) (type (pop types))) - (if (and type - (not (type-asserted-p arg type))) - ;; Propagate derived types from the VALUES call to its args: - ;; transforms can leave the VALUES call with a better type - ;; than its args have, so make sure not to throw that away. - (use-lvar (insert-cast-before use arg type **zero-typecheck-policy**) - new-lvar) - (substitute-lvar-uses new-lvar arg nil)))) + (when (and type + (not (type-asserted-p arg type))) + ;; Propagate derived types from the VALUES call to its args: + ;; transforms can leave the VALUES call with a better type + ;; than its args have, so make sure not to throw that away. + (do-uses (node arg) + (derive-node-type node type))) + (substitute-lvar-uses new-lvar arg nil))) ;; Discard unused arguments (loop for arg in args do (flush-dest arg)) @@ -2547,14 +2646,18 @@ (when (combination-p use) (let ((name (lvar-fun-name (combination-fun use))) (args (combination-args use))) + ;; Recognizing LIST* seems completely ad-hoc, however, once upon a time + ;; (LIST x) was translated to (CONS x NIL), so in order for this optimizer to + ;; pick off (VALUES-LIST (LIST x)), it had to instead look for (CONS x NIL). + ;; Realistically nobody should hand-write (VALUES-LIST ({CONS | LIST*} x NIL)) + ;; so it seems very questionable in utility to preserve both spellings. (when (or (eq name 'list) - (and (eq name 'cons) - (let ((cdr (second args))) - (and (constant-lvar-p cdr) - (null (lvar-value cdr)) + (and (eq name 'list*) + (let ((cdr (car (last args)))) + (and (lvar-value-is-nil cdr) (progn (flush-dest cdr) - (setf (cdr args) nil) + (setf args (butlast args)) t))))) ;; FIXME: VALUES might not satisfy an assertion on NODE-LVAR. @@ -2597,6 +2700,13 @@ (not (node-deleted (bound-cast-check cast)))) (flush-combination (bound-cast-check cast)) (setf (bound-cast-check cast) nil)) + (unless (array-index-cast-p cast) + ;; Normally the types are the same, as the cast gets its derived + ;; type from the lvar, but it may get a different type when an + ;; inlined function with a derived type is let-converted. + (let ((type (node-derived-type cast))) + (do-uses (node value) + (derive-node-type node type)))) (delete-filter cast lvar value) (when lvar (reoptimize-lvar lvar) @@ -2621,12 +2731,23 @@ (defun may-delete-cast (cast) (typecase cast - (vestigial-exit-cast - nil) + (delay nil) (bound-cast (may-delete-bound-cast cast)) (t t))) +(defun cast-mismatch-from-inlined-p (cast node) + (let* ((path (node-source-path node)) + (transformed (memq 'transformed path)) + (inlined)) + (cond ((and transformed + (not (eq (memq 'transformed (node-source-path cast)) + transformed)))) + ((setf inlined + (memq 'inlined path)) + (not (eq (memq 'inlined (node-source-path cast)) + inlined)))))) + ;;; Delete or move around casts when possible (defun maybe-delete-cast (cast) (let ((lvar (cast-lvar cast)) @@ -2637,6 +2758,17 @@ (cast-asserted-type cast)) (delete-cast cast) t) + ((and (fun-type-p (cast-asserted-type cast)) + (let ((uses (lvar-uses value))) + (when (ref-p uses) + (let ((fun (ref-leaf uses))) + (when (and (functional-p fun) + (functional-entry-fun fun)) + ;; FIXME: is it important to compute this once? + (csubtypep (definition-type (functional-entry-fun fun)) + (cast-asserted-type cast))))))) + (delete-cast cast) + t) ((listp (lvar-uses value)) ;; Turn (the vector (if x y #())) into ;; (if x (the vector y) #()) @@ -2661,7 +2793,10 @@ (link-blocks (node-block use) next-block) ;; At least one use is good, downgrade any possible ;; type conflicts to style warnings. - (setf (cast-silent-conflict cast) :style-warning) + (setf (cast-silent-conflict cast) + (if (cast-mismatch-from-inlined-p cast use) + t + :style-warning)) (when (and (return-p dest) (basic-combination-p use) (eq (basic-combination-kind use) :local)) @@ -2693,46 +2828,49 @@ ;; Combinations have nil-fun-returned-error (setf (cast-%type-check cast) nil)) (t - (let ((context (node-source-form cast)) - (detail (lvar-all-sources (cast-value cast)))) - (unless (cast-silent-conflict cast) + (let* ((source-form (node-source-form cast)) + (detail (lvar-all-sources (cast-value cast))) + (context (cast-context cast)) + (context (if (local-call-context-p context) + (local-call-context-var context) + context))) + (when (or (not (cast-silent-conflict cast)) + (and (eq (cast-silent-conflict cast) :style-warning) + (not (cast-single-value-p cast)) + (setf context :multiple-values))) (filter-lvar value (if (cast-single-value-p cast) - `(list 'dummy) - `(multiple-value-call #'list 'dummy)))) + (lambda (dummy) `(list ,dummy)) + (lambda (dummy) `(multiple-value-call #'list ,dummy))))) (filter-lvar (cast-value cast) ;; FIXME: Derived type. (if (cast-silent-conflict cast) - (let ((dummy-sym (gensym))) - `(let ((,dummy-sym 'dummy)) - ,@(and (eq (cast-silent-conflict cast) :style-warning) - `((%compile-time-type-style-warn ,dummy-sym - ',(type-specifier atype) - ',(type-specifier value-type) - ',detail - ',(compile-time-type-error-context context) - ',(cast-context cast)))) - ,(internal-type-error-call dummy-sym atype - (cast-context cast)) - ,dummy-sym)) - `(%compile-time-type-error 'dummy - ',(type-specifier atype) - ',(type-specifier value-type) - ',detail - ',(compile-time-type-error-context context) - ',(cast-context cast))))) - ;; KLUDGE: FILTER-LVAR does not work for non-returning - ;; functions, so we declare the return type of - ;; %COMPILE-TIME-TYPE-ERROR to be * and derive the real type - ;; here. - (setq value (cast-value cast)) - (derive-node-type (lvar-uses value) *empty-type*) - (maybe-terminate-block (lvar-uses value) nil) - ;; FIXME: Is it necessary? - (aver (null (block-pred (node-block cast)))) - (delete-block-lazily (node-block cast)) + (lambda (dummy) + (let ((dummy-sym (gensym))) + `(let ((,dummy-sym ,dummy)) + ,@(and (eq (cast-silent-conflict cast) :style-warning) + `((%compile-time-type-style-warn ,dummy-sym + ',(type-specifier atype) + ',(type-specifier value-type) + ',detail + ',(compile-time-type-error-context source-form) + ',context))) + ,(internal-type-error-call dummy-sym atype context) + ,dummy-sym))) + (lambda (dummy) + `(%compile-time-type-error ,dummy + ',(type-specifier atype) + ',(type-specifier value-type) + ',detail + ',(compile-time-type-error-context source-form) + ',context)))) + ;; maybe-terminate-block during ir1-convert (in filter-lvar) doesn't + ;; properly terminate blocks for NIL returning functions, do it manually here. + (setq value (cast-value cast)) + (derive-node-type (lvar-uses value) *empty-type*) + (maybe-terminate-block (lvar-uses value) nil)) (return-from ir1-optimize-cast))) (when (eq (node-derived-type cast) *empty-type*) (maybe-terminate-block cast nil)) diff --git a/src/compiler/ir1report.lisp b/src/compiler/ir1report.lisp index 0e1794b9f0..432cbd6aa6 100644 --- a/src/compiler/ir1report.lisp +++ b/src/compiler/ir1report.lisp @@ -80,25 +80,39 @@ (args (compiler-error-context-format-args context))) (collect ((full nil cons) (short nil cons)) - (let ((forms (source-path-forms path)) - (n 0)) - (dolist (src (if (member (first forms) args) - (rest forms) - forms)) - (if (>= n *enclosing-source-cutoff*) - (short (stringify-form (if (consp src) - (car src) - src) - nil)) - (full (stringify-form src))) - (incf n)) - (setf (compiler-error-context-%enclosing-source context) (short) - (compiler-error-context-%source context) (full))))))) + (flet ((no-transforms (x) + (let ((pos (position 'transformed x :from-end t))) + (if pos + (subseq x (1+ pos)) + x))) + (hide-inlines (x) + (loop for elt = (pop x) + while x + if (eq elt 'inlined) + do (pop x) + else + collect elt))) + (let* ((forms (source-path-forms path)) + (n 0) + (forms (if (member (first forms) args) + (rest forms) + forms)) + (forms (hide-inlines (no-transforms forms)))) + (dolist (src forms) + (if (>= n *enclosing-source-cutoff*) + (short (stringify-form (if (consp src) + (car src) + src) + nil)) + (full (stringify-form src))) + (incf n)) + (setf (compiler-error-context-%enclosing-source context) (short) + (compiler-error-context-%source context) (full)))))))) ;;; If true, this is the node which is used as context in compiler warning ;;; messages. -(declaim (type (or null compiler-error-context node - lvar-annotation) *compiler-error-context*)) +(declaim (type (or list compiler-error-context node + lvar-annotation ctran) *compiler-error-context*)) (defvar *compiler-error-context* nil) ;;; a plist mapping macro names to source context parsers. Each parser @@ -234,7 +248,7 @@ ;;; If OLD-CONTEXTS is passed in, and includes a context with the ;;; same original source path as the new context would have, the old ;;; context is reused instead, and a secondary value of T is returned. -(defun find-error-context (args &optional old-contexts) +(defun find-error-context (args &optional old-contexts (old-contexts-key #'identity)) (let ((context *compiler-error-context*)) (if (compiler-error-context-p context) (values context t) @@ -242,13 +256,19 @@ (node-source-path context)) ((lvar-annotation-p context) (lvar-annotation-source-path context)) + ((ctran-p context) + (ctran-source-path context)) + ((consp context) context) ((boundp '*current-path*) *current-path*))) (old (find (when path (source-path-original-source path)) - (remove-if #'null old-contexts) + old-contexts :test #'equal - :key #'compiler-error-context-original-source-path))) + :key (lambda (x) + (and x + (compiler-error-context-original-source-path + (funcall old-contexts-key x))))))) (if old (values old t) (when (and *source-info* path) @@ -260,7 +280,10 @@ :original-form form :format-args args :context src-context - :file-name (file-info-name file-info) + :file-name (if (symbolp (file-info-truename file-info)) ; :LISP or :STREAM + ;; (pathname will be NIL in those two cases) + (file-info-truename file-info) + (file-info-pathname file-info)) :file-position (nth-value 1 (find-source-root tlf *source-info*)) :path path @@ -429,6 +452,7 @@ a STYLE-WARNING (or any more serious condition).")) (:documentation "A condition type signalled when the compiler deletes code that the user has written, having proved that it is unreachable.")) +(define-condition unknown-typep-note (simple-compiler-note) ()) (define-condition compiler-macro-application-missed-warning (style-warning) @@ -453,45 +477,6 @@ has written, having proved that it is unreachable.")) (compiler-macro-application-missed-warning-count condition) (compiler-macro-application-missed-warning-function condition))))) -(macrolet ((with-condition ((condition datum args) &body body) - (with-unique-names (block) - `(block ,block - (let ((,condition - (apply #'coerce-to-condition ,datum - 'simple-compiler-note 'with-condition - ,args))) - (restart-case - (signal ,condition) - (muffle-warning () - (return-from ,block (values)))) - ,@body - (values)))))) - - (defun compiler-notify (datum &rest args) - (unless (if *compiler-error-context* - (policy *compiler-error-context* (= inhibit-warnings 3)) - (policy *lexenv* (= inhibit-warnings 3))) - (with-condition (condition datum args) - (incf *compiler-note-count*) - (print-compiler-message - *error-output* - (format nil "note: ~~A") - (list (princ-to-string condition))))) - (values)) - - ;; Issue a note when we might or might not be in the compiler. - (defun maybe-compiler-notify (datum &rest args) - (if (boundp '*lexenv*) ; if we're in the compiler - (apply #'compiler-notify datum args) - (with-condition (condition datum args) - (let ((stream *error-output*)) - (pprint-logical-block (stream nil :per-line-prefix ";") - (format stream " note: ~3I~_") - (pprint-logical-block (stream nil) - (format stream "~A" condition))) - ;; (outside logical block, no per-line-prefix) - (fresh-line stream)))))) - ;;; The politically correct way to print out progress messages and ;;; such like. We clear the current error context so that we know that ;;; it needs to be reprinted, and we also FORCE-OUTPUT so that the @@ -531,6 +516,8 @@ has written, having proved that it is unreachable.")) (defvar *compiler-style-warning-count*) (defvar *compiler-note-count*) +(defvar *methods-in-compilation-unit*) + ;;; Keep track of whether any surrounding COMPILE or COMPILE-FILE call ;;; should return WARNINGS-P or FAILURE-P. (defvar *failure-p*) @@ -559,6 +546,49 @@ has written, having proved that it is unreachable.")) (setf *warnings-p* t) (print-compiler-condition condition) (muffle-warning condition)) + +(macrolet ((with-condition ((condition datum args) &body body) + (with-unique-names (block) + `(block ,block + (let ((,condition + (apply #'coerce-to-condition ,datum + 'simple-compiler-note 'with-condition + ,args))) + (restart-case + (signal ,condition) + (muffle-warning () + (return-from ,block (values)))) + ,@body + (values)))))) + + (defun compiler-notify (datum &rest args) + (unless (if *compiler-error-context* + (policy (if (ctran-p *compiler-error-context*) + (ctran-next *compiler-error-context*) + *compiler-error-context*) + (= inhibit-warnings 3)) + (policy *lexenv* (= inhibit-warnings 3))) + (with-condition (condition datum args) + (incf *compiler-note-count*) + (print-compiler-message + *error-output* + (format nil "note: ~~A") + (list (princ-to-string condition))))) + (values)) + + ;; Issue a note when we might or might not be in the compiler. + (defun maybe-compiler-notify (datum &rest args) + (if (boundp '*lexenv*) ; if we're in the compiler + (apply #'compiler-notify datum args) + (with-condition (condition datum args) + (let ((stream *error-output*)) + (pprint-logical-block (stream nil :per-line-prefix ";") + (format stream " note: ~3I~_") + (pprint-logical-block (stream nil) + (format stream "~A" condition))) + ;; (outside logical block, no per-line-prefix) + (fresh-line stream)))))) + ;;;; undefined warnings @@ -578,10 +608,10 @@ has written, having proved that it is unreachable.")) ;;; the compiler, hence the BOUNDP check. (defun note-undefined-reference (name kind) #+sb-xc-host - ;; Whitelist functions are looked up prior to UNCROSS, + ;; Allowlist functions are looked up prior to UNCROSS, ;; so that we can distinguish CL:SOMEFUN from SB-XC:SOMEFUN. (when (and (eq kind :function) - (gethash name sb-cold:*undefined-fun-whitelist*)) + (gethash name sb-cold:*undefined-fun-allowlist*)) (return-from note-undefined-reference (values))) (setq name (uncross name)) (unless (and @@ -622,6 +652,47 @@ has written, having proved that it is unreachable.")) (incf (undefined-warning-count res)))))) (values)) +(defun maybe-note-undefined-variable-reference (var name) + (when (and (global-var-p var) + (eq (global-var-kind var) :unknown) + (not (deprecated-thing-p 'variable name))) + (note-undefined-reference name :variable))) + +(defun note-key-arg-mismatch (name keys) + (let* ((found (find name + *argument-mismatch-warnings* + :key #'argument-mismatch-warning-name)) + (res (or found + (make-argument-mismatch-warning :name name)))) + (unless found + (push res *argument-mismatch-warnings*)) + (multiple-value-bind (context old) + (find-error-context (list name) (argument-mismatch-warning-warnings res) #'cdr) + (unless old + (push (cons keys context) (argument-mismatch-warning-warnings res)))))) + +(defun report-key-arg-mismatches () + #-sb-xc-host + (loop for warning in *argument-mismatch-warnings* + for name = (argument-mismatch-warning-name warning) + for type = (sb-pcl::compute-gf-ftype name) + when (and (fun-type-p type) + (not (fun-type-allowp type))) + do + (loop for (keys . context) in (argument-mismatch-warning-warnings warning) + for bad = (loop for key in keys + when (not (member key (fun-type-keywords type) + :key #'key-info-name)) + collect key) + do (let ((*compiler-error-context* context)) + (cond ((cdr bad) + (compiler-style-warn "~@<~{~S~^, ~} and ~S are not a known argument keywords.~:@>" + (butlast bad) + (car (last bad)))) + (bad + (compiler-style-warn "~S is not a known argument keyword." + (car bad)))))))) + ;; The compiler tracks full calls that were emitted so that it is possible ;; to detect a definition of a compiler-macro occuring after the first ;; compile-time observed use of (vs. actual call of) that function name. @@ -640,7 +711,7 @@ has written, having proved that it is unreachable.")) ;; The current approach is reliable, at a cost of ~3 words per function. ;; (defun warn-if-compiler-macro-dependency-problem (name) - (unless (sb-xc:compiler-macro-function name) + (unless (compiler-macro-function name) (let ((status (car (info :function :emitted-full-calls name)))) ; TODO use emitted-full-call-count? (when (and (integerp status) (oddp status)) ;; Show the total number of calls, because otherwise the warning @@ -660,7 +731,7 @@ has written, having proved that it is unreachable.")) ;; (defun warn-if-inline-failed/proclaim (name new-inlinep) (when (eq new-inlinep 'inline) - (let ((warning-count (emitted-full-call-count name))) + (let ((warning-count (sb-impl::emitted-full-call-count name))) (when (and warning-count ;; Warn only if the the compiler did not have the expansion. (not (fun-name-inline-expansion name)) diff --git a/src/compiler/ir1tran-lambda.lisp b/src/compiler/ir1tran-lambda.lisp index 3636c75dd2..f434118580 100644 --- a/src/compiler/ir1tran-lambda.lisp +++ b/src/compiler/ir1tran-lambda.lisp @@ -15,20 +15,17 @@ ;;;; LAMBDA hackery -;;;; FIXME: where is that file? -;;;; Answer: As usual, with CMUCL. ;;;; Note: Take a look at the compiler-overview.tex section on "Hairy ;;;; function representation" before you seriously mess with this ;;;; stuff. -#-sb-devel (declaim (start-block ir1-convert-lambda ir1-convert-lambda-body ir1-convert-aux-bindings varify-lambda-arg ir1-convert-lambdalike)) ;;; Return a VAR structure for NAME, filling in info if it is globally ;;; special. If it is losing, we punt with a COMPILER-ERROR. -(declaim (ftype (sfunction (symbol) lambda-var) varify-lambda-arg)) -(defun varify-lambda-arg (name) +(declaim (ftype (sfunction (symbol &optional t) lambda-var) varify-lambda-arg)) +(defun varify-lambda-arg (name &optional source-form) (case (info :variable :kind name) (:special (let ((variable (find-free-var name))) @@ -37,7 +34,8 @@ :where-from (leaf-where-from variable) :specvar variable))) (t - (make-lambda-var :%source-name name)))) + (make-lambda-var :%source-name name + :source-form source-form)))) ;;; Parse a lambda list into a list of VAR structures, stripping off ;;; any &AUX bindings. Each arg name is checked for legality, and @@ -67,7 +65,8 @@ (add-info (var kind &key (default nil defaultp) suppliedp-var key) (let ((info (make-arg-info :kind kind))) (when defaultp - (setf (arg-info-default info) default)) + (setf (arg-info-default info) default + (arg-info-default-p info) t)) (when suppliedp-var (setf (arg-info-supplied-p info) (varify-lambda-arg suppliedp-var))) @@ -117,7 +116,7 @@ ;;; SOURCE-NAME and DEBUG-NAME. But I (WHN) don't use &AUX bindings, ;;; so I'm not motivated. Patches will be accepted... (defun ir1-convert-aux-bindings (start next result body aux-vars aux-vals - post-binding-lexenv) + post-binding-lexenv &key value-source-forms) (declare (type ctran start next) (type (or lvar null) result) (list body aux-vars aux-vals)) (if (null aux-vars) @@ -132,10 +131,12 @@ :post-binding-lexenv post-binding-lexenv :debug-name (debug-name '&aux-bindings - aux-vars)))) + aux-vars) + :value-source-forms (rest value-source-forms)))) (reference-leaf start ctran fun-lvar fun) (ir1-convert-combination-args fun-lvar ctran next result - (list (first aux-vals))))) + (list (first aux-vals)) + :arg-source-forms (list (first value-source-forms))))) (values)) ;;; This is similar to IR1-CONVERT-PROGN-BODY except that code to bind @@ -150,13 +151,15 @@ ;;; to start a block outside of this cleanup, causing cleanup code to ;;; be emitted when the scope is exited. (defun ir1-convert-special-bindings - (start next result body aux-vars aux-vals svars post-binding-lexenv) + (start next result body aux-vars aux-vals svars post-binding-lexenv + &key value-source-forms) (declare (type ctran start next) (type (or lvar null) result) (list body aux-vars aux-vals svars)) (cond ((null svars) (ir1-convert-aux-bindings start next result body aux-vars aux-vals - post-binding-lexenv)) + post-binding-lexenv + :value-source-forms value-source-forms)) (t (ctran-starts-block next) (let ((cleanup (make-cleanup :kind :special-bind)) @@ -164,14 +167,15 @@ (bind-ctran (make-ctran)) (cleanup-ctran (make-ctran))) (ir1-convert start bind-ctran nil - `(%special-bind ',(leaf-source-name (lambda-var-specvar var)) ,var)) + `(%special-bind ',(lambda-var-specvar var) ,var)) (setf (cleanup-mess-up cleanup) (ctran-use bind-ctran)) (let ((*lexenv* (make-lexenv :cleanup cleanup))) (ir1-convert bind-ctran cleanup-ctran nil '(%cleanup-point)) (ir1-convert-special-bindings cleanup-ctran next result body aux-vars aux-vals (rest svars) - post-binding-lexenv))))) + post-binding-lexenv + :value-source-forms value-source-forms))))) (values)) ;;; Create a lambda node out of some code, returning the result. The @@ -200,7 +204,9 @@ debug-name (note-lexical-bindings t) post-binding-lexenv - system-lambda) + system-lambda + local-policy + value-source-forms) (declare (list body vars aux-vars aux-vals)) ;; We're about to try to put new blocks into *CURRENT-COMPONENT*. @@ -208,10 +214,13 @@ (let* ((bind (make-bind)) (lambda (make-lambda :vars vars - :bind bind - :%source-name source-name - :%debug-name debug-name - :system-lambda-p system-lambda)) + :bind bind + :%source-name source-name + :%debug-name debug-name + :system-lambda-p system-lambda + :lexenv (if local-policy + (make-lexenv :policy local-policy) + *lexenv*))) (result-ctran (make-ctran)) (result-lvar (make-lvar))) ;; just to check: This function should fail internal assertions if @@ -266,7 +275,8 @@ (ir1-convert-special-bindings postbind-ctran result-ctran result-lvar body aux-vars aux-vals (svars) - post-binding-lexenv))))) + post-binding-lexenv + :value-source-forms value-source-forms))))) (link-blocks (component-head *current-component*) (node-block bind)) (push lambda (component-new-functionals *current-component*)) @@ -304,9 +314,9 @@ (fun (collect ((default-bindings) (default-vals)) (dolist (default defaults) - (if (sb-xc:constantp default) + (if (constantp default) (default-vals default) - (let ((var (sb-xc:gensym))) + (let ((var (gensym))) (default-bindings `(,var ,default)) (default-vals var)))) (let ((bindings (default-bindings)) @@ -358,7 +368,7 @@ (default (arg-info-default info)) (supplied-p (arg-info-supplied-p info)) (force (or force - (not (sb-xc:constantp (arg-info-default info))))) + (not (constantp (arg-info-default info))))) (ep (if supplied-p (ir1-convert-hairy-args res @@ -446,10 +456,10 @@ :type (leaf-type var) :where-from (leaf-where-from var)))) - (let* ((n-context (sb-xc:gensym "N-CONTEXT-")) + (let* ((n-context (gensym "N-CONTEXT-")) (context-temp (make-lambda-var :%source-name n-context :arg-info (make-arg-info :kind :more-context))) - (n-count (sb-xc:gensym "N-COUNT-")) + (n-count (gensym "N-COUNT-")) (count-temp (make-lambda-var :%source-name n-count :type (specifier-type 'index) :arg-info (make-arg-info :kind :more-count)))) @@ -469,17 +479,19 @@ ;; and take advantage of the base+index+displacement addressing ;; mode on x86oids.) (when (optional-dispatch-keyp res) - (let ((n-index (sb-xc:gensym "N-INDEX-")) - (n-key (sb-xc:gensym "N-KEY-")) - (n-value-temp (sb-xc:gensym "N-VALUE-TEMP-")) - (n-allowp (sb-xc:gensym "N-ALLOWP-")) - (n-lose (sb-xc:gensym "N-LOSE-")) + (let ((n-index (gensym "N-INDEX-")) + (n-key (gensym "N-KEY-")) + (n-value-temp (gensym "N-VALUE-TEMP-")) + (n-allowp (gensym "N-ALLOWP-")) + (n-lose (gensym "N-LOSE-")) (allowp (or (optional-dispatch-allowp res) (policy *lexenv* (zerop safety)))) (found-allow-p nil)) (temps #-stack-grows-downward-not-upward - `(,n-index (1- ,n-count)) + `(,n-index (+ ,n-count ,(if (vop-existsp :translate %more-keyword-pair) + 0 + -1))) #+stack-grows-downward-not-upward `(,n-index (- (1- ,n-count))) #-stack-grows-downward-not-upward n-value-temp @@ -495,9 +507,9 @@ (keyword (arg-info-key info)) (supplied-p (arg-info-supplied-p info)) (supplied-used-p (arg-info-supplied-used-p info)) - (n-value (sb-xc:gensym "N-VALUE-")) + (n-value (gensym "N-VALUE-")) (clause (cond (supplied-p - (let ((n-supplied (sb-xc:gensym "N-SUPPLIED-"))) + (let ((n-supplied (gensym "N-SUPPLIED-"))) (temps (list n-supplied (if supplied-used-p nil @@ -535,7 +547,9 @@ (setq ,n-lose ,n-key)))) (body - `(when (oddp ,n-count) + `(when (oddp ,(if (vop-existsp :translate %more-keyword-pair) + n-index + n-count)) (%odd-key-args-error))) (body @@ -543,12 +557,19 @@ `(locally (declare (optimize (safety 0))) (loop - (when (minusp ,n-index) (return)) - (setf ,n-value-temp (%more-arg ,n-context ,n-index)) - (decf ,n-index) - (setq ,n-key (%more-arg ,n-context ,n-index)) - (decf ,n-index) - (case ,n-key ,@(tests)))) + ,@(cond ((vop-existsp :translate %more-keyword-pair) + `((when (zerop ,n-index) (return)) + (decf ,n-index 2) + (multiple-value-bind (key value) + (%more-keyword-pair ,n-context ,n-index) + (setf ,n-value-temp value ,n-key key)))) + (t + `((when (minusp ,n-index) (return)) + (setf ,n-value-temp (%more-arg ,n-context ,n-index)) + (decf ,n-index) + (setq ,n-key (%more-arg ,n-context ,n-index)) + (decf ,n-index)))) + (case ,n-key ,@(tests)))) #+stack-grows-downward-not-upward `(locally (declare (optimize (safety 0))) (loop @@ -560,7 +581,7 @@ (case ,n-key ,@(tests)))))) (unless allowp - (let ((location (opaquely-quote (make-restart-location)))) + (let ((location (make-restart-location))) (body `(if (and (not (unbound-marker-p ,n-lose)) (not ,n-allowp)) (%unknown-key-arg-error ,n-lose ,location) @@ -615,10 +636,10 @@ ;; Make up two extra variables, and squirrel them away in ;; ARG-INFO-DEFAULT for transforming (VALUES-LIST REST) into ;; (%MORE-ARG-VALUES CONTEXT 0 COUNT) when possible. - (let* ((context-name (sb-xc:gensym "REST-CONTEXT-")) + (let* ((context-name (gensym "REST-CONTEXT-")) (context (make-lambda-var :%source-name context-name :arg-info (make-arg-info :kind :more-context))) - (count-name (sb-xc:gensym "REST-COUNT-")) + (count-name (gensym "REST-COUNT-")) (count (make-lambda-var :%source-name count-name :arg-info (make-arg-info :kind :more-count) :type (specifier-type 'index)))) @@ -636,7 +657,7 @@ (dolist (key keys) (let* ((info (lambda-var-arg-info key)) (default (arg-info-default info)) - (hairy-default (not (sb-xc:constantp default))) + (hairy-default (not (constantp default))) (supplied-p (arg-info-supplied-p info)) ;; was: (format nil "~A-DEFAULTING-TEMP" (leaf-source-name key)) (n-val (make-symbol ".DEFAULTING-TEMP.")) @@ -646,7 +667,7 @@ (main-vars val-temp) (bind-vars key) (cond ((or hairy-default supplied-p) - (let* ((n-supplied (sb-xc:gensym "N-SUPPLIED-")) + (let* ((n-supplied (gensym "N-SUPPLIED-")) (supplied-temp (make-lambda-var :%source-name n-supplied))) (unless supplied-p @@ -857,10 +878,21 @@ res)) +(defvar *lambda-conversions*) + +(defun add-types-for-fixed-args (fun vars) + (let ((fun-info (info :function :info fun))) + (when (and fun-info + (ir1-attributep (fun-info-attributes fun-info) fixed-args)) + (loop for type in (fun-type-required (info :function :type fun)) + for var in vars + do (setf (lambda-var-type var) type)))) + vars) + ;;; Convert a LAMBDA form into a LAMBDA leaf or an OPTIONAL-DISPATCH leaf. (defun ir1-convert-lambda (form &key (source-name '.anonymous.) - debug-name maybe-add-debug-catch - system-lambda) + debug-name maybe-add-debug-catch + system-lambda) (unless (consp form) (compiler-error "A ~S was found when expecting a lambda expression:~% ~S" (type-of form) @@ -878,56 +910,62 @@ (bug "Both SYSTEM-LAMBDA and MAYBE-ADD-DEBUG-CATCH specified")) (unless (or debug-name (neq '.anonymous. source-name)) (setf debug-name (name-lambdalike form))) - (multiple-value-bind (forms decls doc) (parse-body (cddr form) t) - (let ((*lexenv* (process-muffle-decls decls *lexenv*))) - (multiple-value-bind (vars keyp allow-other-keys aux-vars aux-vals) - (make-lambda-vars (cadr form)) - (binding* (((*lexenv* result-type post-binding-lexenv - lambda-list explicit-check source-form) - (process-decls decls (append aux-vars vars) nil - :binding-form-p t :allow-lambda-list t)) - (debug-catch-p (and maybe-add-debug-catch - *allow-instrumenting* - (policy *lexenv* - (>= insert-debug-catch 2)))) - (forms (if debug-catch-p - (wrap-forms-in-debug-catch forms) - forms)) - (forms (if (eq result-type *wild-type*) - forms - `((the ,(type-specifier result-type) (progn ,@forms))))) - (*allow-instrumenting* (and (not system-lambda) *allow-instrumenting*)) - (res (cond ((or (find-if #'lambda-var-arg-info vars) keyp) - (ir1-convert-hairy-lambda forms vars keyp - allow-other-keys - aux-vars aux-vals - :post-binding-lexenv post-binding-lexenv - :source-name source-name - :debug-name debug-name - :system-lambda system-lambda)) - (t - (ir1-convert-lambda-body forms vars - :aux-vars aux-vars - :aux-vals aux-vals - :post-binding-lexenv post-binding-lexenv - :source-name source-name - :debug-name debug-name - :system-lambda system-lambda))))) - (when explicit-check - (setf (getf (functional-plist res) 'explicit-check) explicit-check)) - (setf (functional-inline-expansion res) (or source-form form)) - (setf (functional-arg-documentation res) - (if (eq lambda-list :unspecified) - (strip-lambda-list (cadr form) :arglist) - lambda-list)) - (setf (functional-documentation res) doc) - (when (boundp '*lambda-conversions*) - ;; KLUDGE: Not counting TL-XEPs is a lie, of course, but - ;; keeps things less confusing to users of TIME, where this - ;; count gets used. - (unless (and (consp debug-name) (eq 'tl-xep (car debug-name))) - (incf *lambda-conversions*))) - res))))) + (binding* (((forms decls doc) (parse-body (cddr form) t)) + ((*lexenv* source-form) (process-muffle-decls decls *lexenv*)) + (*current-path* (or (and source-form + (get-source-path source-form)) + *current-path*)) + ((vars keyp allow-other-keys aux-vars aux-vals) + (make-lambda-vars (cadr form))) + ((*lexenv* result-type post-binding-lexenv + lambda-list explicit-check source-form + local-policy) + (process-decls decls (append aux-vars vars) nil + :binding-form-p t :allow-lambda-list t)) + (debug-catch-p (and maybe-add-debug-catch + *allow-instrumenting* + (policy *lexenv* + (>= insert-debug-catch 2)))) + (forms (if debug-catch-p + (wrap-forms-in-debug-catch forms) + forms)) + (forms (if (eq result-type *wild-type*) + forms + `((the ,(type-specifier result-type) (progn ,@forms))))) + (*allow-instrumenting* (and (not system-lambda) *allow-instrumenting*)) + (res (cond ((or (find-if #'lambda-var-arg-info vars) keyp) + (ir1-convert-hairy-lambda forms vars keyp + allow-other-keys + aux-vars aux-vals + :post-binding-lexenv post-binding-lexenv + :source-name source-name + :debug-name debug-name + :system-lambda system-lambda)) + (t + (ir1-convert-lambda-body forms + (add-types-for-fixed-args source-name vars) + :aux-vars aux-vars + :aux-vals aux-vals + :post-binding-lexenv post-binding-lexenv + :source-name source-name + :debug-name debug-name + :system-lambda system-lambda + :local-policy local-policy))))) + (when explicit-check + (setf (getf (functional-plist res) 'explicit-check) explicit-check)) + (setf (functional-inline-expansion res) (or source-form form)) + (setf (functional-arg-documentation res) + (if (eq lambda-list :unspecified) + (strip-lambda-list (cadr form) :arglist) + lambda-list)) + (setf (functional-documentation res) doc) + (when (boundp '*lambda-conversions*) + ;; KLUDGE: Not counting TL-XEPs is a lie, of course, but + ;; keeps things less confusing to users of TIME, where this + ;; count gets used. + (unless (and (consp debug-name) (eq 'tl-xep (car debug-name))) + (incf *lambda-conversions*))) + res)) (defun wrap-forms-in-debug-catch (forms) #+unwind-to-frame-and-call-vop @@ -960,14 +998,6 @@ (progn ,@forms)))))))) -;; FIXME: really should be an aspect of the lexical environment, -;; but LEXENVs don't know whether they are toplevel or not. -(defun has-toplevelness-decl (lambda-expr) - (dolist (expr (cddr lambda-expr)) ; Skip over (LAMBDA (ARGS)) - (cond ((equal expr '(declare (top-level-form))) (return t)) - ((typep expr '(or (cons (eql declare)) string))) ; DECL | DOCSTRING - (t (return nil))))) - ;;; helper for LAMBDA-like things, to massage them into a form ;;; suitable for IR1-CONVERT-LAMBDA. (defun ir1-convert-lambdalike (thing @@ -985,7 +1015,16 @@ ((named-lambda) (let* ((name (cadr thing)) (lambda-expression `(lambda ,@(cddr thing))) - (*inline-expansions* (list name 1 *inline-expansions*))) + (*inline-expansions* (list name 1 *inline-expansions*)) + (simple-lexenv-p (simple-lexical-environment-p *lexenv*))) + ;; Discard any forward references to this function unless we + ;; are block compiling and the lexical environment doesn't + ;; contain any hair. If the lexical environment is too hairy, then we only + ;; install the definition during the processing of this NAMED-LAMBDA, + ;; ensuring that the function cannot be called outside of the correct + ;; environment. + (unless (and (block-compile *compilation*) simple-lexenv-p) + (remhash name (free-funs *ir1-namespace*))) (if (and name (legal-fun-name-p name)) (let ((defined-fun-res (get-defined-fun name (second lambda-expression))) (res (ir1-convert-lambda lambda-expression @@ -993,13 +1032,17 @@ :source-name name)) (info (info :function :info name))) (setf (functional-inlinep res) (info :function :inlinep name) - (defined-fun-named-lambda-p defined-fun-res) t) - (when (has-toplevelness-decl lambda-expression) - (setf (functional-top-level-defun-p res) t)) + (defined-fun-same-block-p defined-fun-res) t) ;; FIXME: Should non-entry block compiled defuns have ;; this propagate? - (assert-global-function-definition-type name res) - (push res (defined-fun-functionals defined-fun-res)) + (unless (and info + (ir1-attributep (fun-info-attributes info) fixed-args)) + (assert-global-function-definition-type name res)) + ;; If in a simple environment, then we can allow + ;; backward references to this function from following + ;; top-level forms. + (when simple-lexenv-p + (push res (defined-fun-functionals defined-fun-res))) (unless (or (eq (defined-fun-inlinep defined-fun-res) 'notinline) ;; Don't treat recursive stubs like CAR as self-calls @@ -1031,8 +1074,8 @@ (declaim (end-block)) - ;;;; defining global functions + ;;; Given a lambda-list, return a FUN-TYPE object representing the signature: ;;; return type is *, and each individual arguments type is T -- but we get ;;; the argument counts and keywords. @@ -1054,7 +1097,66 @@ (allow (when (ll-kwds-allowp llks) '(&allow-other-keys)))) (careful-specifier-type `(function (,@reqs ,@opts ,@rest ,@keys ,@allow) *)))))) -#-sb-devel +;;; Return a lambda form that has been "closed" with respect to +;;; LEXENV, returning a LAMBDA-WITH-LEXENV if there are interesting +;;; declarations. To handle local macros, rather than closing over +;;; definitions in the environment, expand all macros in the body of +;;; LAMBDA, so that nothing in the syntactic environment is needed in +;;; the expansion. If there is something too complex in the lexical +;;; environment (like a lexical variable), then we return NIL. +(defun inline-syntactic-closure-lambda (lambda lexenv) + (declare (type list lambda) (type lexenv-designator lexenv)) + (aver (eql (first lambda) 'lambda)) + (typecase lexenv + (lexenv + (let ((vars (lexenv-vars lexenv)) + (funs (lexenv-funs lexenv)) + (decls ())) + (cond ((or (lexenv-blocks lexenv) (lexenv-tags lexenv)) nil) + ((and (null vars) (null funs)) lambda) + ((dolist (x vars nil) + (let ((name (car x)) + (what (cdr x))) + (when (eq x (assoc name vars :test #'eq)) + (typecase what + (cons + (aver (eq (car what) 'macro))) + (global-var + (aver (eq (global-var-kind what) :special)) + (push `(special ,name) decls)) + (t (return t)))))) + nil) + ((dolist (x funs nil) + (let ((name (car x)) + (what (cdr x))) + (when (eq x (assoc name funs :test #'equal)) + (typecase what + (cons) + ;; FIXME: Is there a good reason for this not to be + ;; DEFINED-FUN (which :INCLUDEs GLOBAL-VAR, in case + ;; you're wondering how this ever worked :-)? Maybe + ;; in conjunction with an AVERrance that it's not an + ;; (AND GLOBAL-VAR (NOT GLOBAL-FUN))? -- CSR, + ;; 2002-07-08 + (global-var + (when (defined-fun-p what) + (push `(,(car (defined-fun-inlinep what)) + ,name) + decls))) + (t (return t)))))) + nil) + (t + (let ((expansion (sb-walker:macroexpand-all lambda lexenv))) + (if decls + `(lambda-with-lexenv (:declare ,decls) ,@(cdr expansion)) + expansion)))))) + #+(and sb-fasteval (not sb-xc-host)) + (sb-interpreter:basic-env + (awhen (sb-interpreter::reconstruct-syntactic-closure-env lexenv) + `(lambda-with-lexenv ,it ,@(cdr lambda)))) + #+sb-fasteval + (null lambda))) ; trivial case. Never occurs in the compiler. + (declaim (start-block ir1-convert-inline-lambda)) ;;; Convert the forms produced by RECONSTRUCT-LEXENV to LEXENV @@ -1123,6 +1225,7 @@ (lexenv-flushable *lexenv*) lexenv-lambda *lexenv*))) + (*inlining* (1+ *inlining*)) (clambda (ir1-convert-lambda body :source-name source-name :debug-name debug-name @@ -1137,39 +1240,38 @@ ;;; previous references. (defun get-defined-fun (name &optional (lambda-list nil lp)) (proclaim-as-fun-name name) - (when #+sb-xc-host (not *compile-time-eval*) - #-sb-xc-host (boundp '*ir1-namespace*) - (let ((found (find-free-fun name "shouldn't happen! (defined-fun)")) - (free-funs (free-funs *ir1-namespace*))) - (note-name-defined name :function) - (cond ((not (defined-fun-p found)) - ;; This assertion is wrong in block compilation mode, for - ;; instance - ;; - ;; (defun foo (x) (bar x)) - ;; (declaim (inline bar)) - ;; (defun bar (x) x) - (aver (or (block-compile *compilation*) - (not (info :function :inlinep name)))) - (let* ((where-from (leaf-where-from found)) - (res (make-defined-fun - :%source-name name - :where-from (if (eq where-from :declared) - :declared - :defined-here) - :type (if (eq :declared where-from) - (leaf-type found) - (or (and lp - (ftype-from-lambda-list lambda-list)) - (specifier-type 'function)))))) - (substitute-leaf res found) - (setf (gethash name free-funs) res))) - ;; If FREE-FUNS has a previously converted definition - ;; for this name, then blow it away and try again. - ((defined-fun-functionals found) - (remhash name free-funs) - (get-defined-fun name lambda-list)) - (t found))))) + (let ((found (find-free-fun name "shouldn't happen! (defined-fun)")) + (free-funs (free-funs *ir1-namespace*))) + (note-name-defined name :function) + (cond ((not (defined-fun-p found)) + ;; This assertion is wrong in block compilation mode, for + ;; instance + ;; + ;; (defun foo (x) (bar x)) + ;; (declaim (inline bar)) + ;; (defun bar (x) x) + (aver (or (block-compile *compilation*) + (not (info :function :inlinep name)))) + (let* ((where-from (leaf-where-from found)) + (res (make-defined-fun + :%source-name name + :where-from (if (eq where-from :declared) + :declared + :defined-here) + :type (if (eq :declared where-from) + (leaf-type found) + (or (and lp + (ignore-errors + (ftype-from-lambda-list lambda-list))) + (specifier-type 'function)))))) + (substitute-leaf res found) + (setf (gethash name free-funs) res))) + ;; If FREE-FUNS has a previously converted definition + ;; for this name, then blow it away and try again. + ((defined-fun-functionals found) + (remhash name free-funs) + (get-defined-fun name lambda-list)) + (t found)))) ;;; Check a new global function definition for consistency with ;;; previous declaration or definition, and assert argument/result @@ -1204,6 +1306,18 @@ "previous declaration" "previous definition")))) +;;; The lexical environment is hairy if it has stuff like lexical +;;; variables, blocks, or tags that are not load-time constants. Local +;;; functions and macros are OK, since we are worried about outside +;;; calls. Macros get expanded, and local functions are load-time +;;; constants. +(defun simple-lexical-environment-p (lexenv) + (and (null (lexenv-blocks lexenv)) + (null (lexenv-tags lexenv)) + (every (lambda (entry) + (consp (cdr entry))) + (lexenv-vars lexenv)))) + ;;; Used for global inline expansion. Earlier something like this was ;;; used by %DEFUN too. FIXME: And now it's probably worth rethinking ;;; whether this function is a good idea at all. @@ -1243,16 +1357,17 @@ (note-inlining (optional-dispatch-more-entry fun)) (mapc #'note-inlining (optional-dispatch-entry-points fun)))) ;; substitute for any old references - (unless (or (eq (defined-fun-inlinep var) :notinline) + (unless (or (eq (defined-fun-inlinep var) 'notinline) (not (block-compile *compilation*)) (and info (or (fun-info-transforms info) (fun-info-templates info) (fun-info-ir2-convert info)))) (substitute-leaf fun var) - ;; If in a simple environment, then we can allow backward references - ;; to this function from following top-level forms. - (when expansion + ;; If in a simple environment, then we can allow backward + ;; references to this function from following top-level + ;; forms. + (when (simple-lexical-environment-p *lexenv*) (push fun (defined-fun-functionals var)))) fun)) @@ -1373,27 +1488,3 @@ is potentially harmful to any already-compiled callers using (SAFETY 0)." (specifier-type 'function)))) (values)) - -;; Similar to above, detect duplicate definitions within a file, -;; but the package lock check is unnecessary - it's handled elsewhere. -;; -;; Additionally, this is a STYLE-WARNING, not a WARNING, because there is -;; meaningful behavior that can be ascribed to some redefinitions, e.g. -;; (defmacro foo () first-definition) -;; (defun f () (use-it (foo ))) -;; (defmacro foo () other-definition) -;; will use the first definition when compiling F, but make the second available -;; in the loaded fasl. In this usage it would have made sense to wrap the -;; respective definitions with EVAL-WHEN for different situations, -;; but as long as the compile-time behavior is deterministic, it's just bad style -;; and not flat-out wrong, though there is indeed some waste in the fasl. -;; -;; KIND is the globaldb KIND of this NAME -(defun %compiler-defmacro (kind name) - (let ((name-key `(,kind ,name))) - (when (boundp '*lexenv*) - (aver (producing-fasl-file)) - ;; a slight OAOO issue here wrt %COMPILER-DEFUN - (if (member name-key (fun-names-in-this-file *compilation*) :test #'equal) - (compiler-style-warn 'same-file-redefinition-warning :name name) - (push name-key (fun-names-in-this-file *compilation*)))))) diff --git a/src/compiler/ir1tran.lisp b/src/compiler/ir1tran.lisp index b1a7aaf9d9..c3b76af939 100644 --- a/src/compiler/ir1tran.lisp +++ b/src/compiler/ir1tran.lisp @@ -14,6 +14,10 @@ (declaim (special *compiler-error-bailout*)) +;;; the lexical environment we are currently converting in +(defvar *lexenv*) +(declaim (type lexenv *lexenv*)) + ;;; *CURRENT-FORM-NUMBER* is used in FIND-SOURCE-PATHS to compute the ;;; form number to associate with a source path. This should be bound ;;; to an initial value of 0 before the processing of each truly @@ -23,7 +27,8 @@ ;;; Report as we try each transform? (either source or IR) ;;; Bind to T to see the ones that didn't abort, -;;; or :ALL if you want to see each attempted transform. +;;; :ALL if you want to see each attempted transform. +;;; :DERIVE-TYPE for newly derived types of combinations. (defvar *show-transforms-p* nil) (declaim (inline source-form-has-path-p)) @@ -34,10 +39,29 @@ (when (source-form-has-path-p form) (gethash form *source-paths*))) +(defvar *transforming* 0) +(defvar *inlining* 0) + (defun ensure-source-path (form) - (or (get-source-path form) - (cons (simplify-source-path-form form) - *current-path*))) + (flet ((level> (value kind) + (let ((x (memq kind *current-path*))) + (> value + (if x + (cadr x) + 0))))) + (or (get-source-path form) + (cond ((level> *transforming* 'transformed) + ;; Don't hide all the transformed paths, since we might want + ;; to look at the final form for error reporting. + (list* (simplify-source-path-form form) + 'transformed *transforming* *current-path*)) + ;; Avoids notes about inlined code leaking out + ((level> *inlining* 'inlined) + (list* (simplify-source-path-form form) + 'inlined *inlining* *current-path*)) + (t + (cons (simplify-source-path-form form) + *current-path*)))))) (defun simplify-source-path-form (form) (if (consp form) @@ -56,6 +80,11 @@ (setf (gethash form *source-paths*) (apply #'list* 'original-source-start *current-form-number* arguments)))) +(defun proper-list (form) + (if (proper-list-p form) + form + (compiler-error "~@<~S is not a proper list.~@:>" form))) + ;;; *CURRENT-COMPONENT* is the COMPONENT structure which we link ;;; blocks into as we generate them. This just serves to glue the ;;; emitted blocks together until local call analysis and flow graph @@ -76,22 +105,50 @@ (defvar *current-path*) (defun call-with-current-source-form (thunk &rest forms) - (let ((*current-path* (when (and (some #'identity forms) - (boundp '*source-paths*)) - (or (some #'get-source-path forms) - (when (boundp '*current-path*) - *current-path*))))) + (let ((*current-path* (or (and (some #'identity forms) + (boundp '*source-paths*) + (some #'get-source-path forms)) + (and (boundp '*current-path*) + *current-path*)))) (funcall thunk))) -(defvar *derive-function-types* nil - "Should the compiler assume that function types will never change, - so that it can use type information inferred from current definitions - to optimize code which uses those definitions? Setting this true - gives non-ANSI, early-CMU-CL behavior. It can be useful for improving - the efficiency of stable code.") +(defvar *derive-function-types* :same-file + "If true, argument and result type information derived from + compilation of DEFUNs is used when compiling calls to that + function. If :SAME-FILE (the default, as allowed by ANSI 3.2.2.3), + the information is derived only from DEFUNs in the same file. If + false, only information from FTYPE proclamations will be used.") ;;;; namespace management utilities +;;; Unpack (INFO :FUNCTION :INLINING-DATA FUN-NAME). If an explicit expansion +;;; is not stored but FUN-NAME is a structure constructor, reconstitute the +;;; expansion from the defstruct description. Secondary value is T if the expansion +;;; was explicit. See SAVE-INLINE-EXPANSION-P for why we care. +;;; (Essentially, once stored then always stored, lest inconsistency result) +;;; If we have just a DXABLE-ARGS, or nothing at all, return NIL and NIL. +;;; If called on a string or anything that is not a function designator, +;;; return NIL and NIL. +(declaim (ftype (sfunction (t) (values list boolean)) + fun-name-inline-expansion)) +(defun fun-name-inline-expansion (fun-name) + (multiple-value-bind (answer winp) (info :function :inlining-data fun-name) + (typecase answer + ;; an INLINING-DATA is a DXABLE-ARGS, so test it first + (inlining-data (setq answer (inlining-data-expansion answer))) + (dxable-args (setq answer nil winp nil))) + (when (and (not winp) (symbolp fun-name)) + (let ((info (info :function :source-transform fun-name))) + (when (typep info '(cons defstruct-description (eql :constructor))) + (let* ((dd (car info)) (spec (assq fun-name (dd-constructors dd)))) + (aver spec) + (setq answer `(lambda ,@(structure-ctor-lambda-parts dd (cdr spec)))))))) + (values answer winp))) +(defun fun-name-dx-args (fun-name) + (let ((answer (info :function :inlining-data fun-name))) + (when (typep answer 'dxable-args) + (dxable-args-list answer)))) + ;; As with LEXENV-FIND, we assume use of *LEXENV*, but macroexpanders ;; receive an explicit environment and should pass it. ;; A declaration will trump a proclamation. @@ -111,9 +168,9 @@ ;; If ANSWER is NIL, go for the global value (eq (or answer (info :function :inlinep name)) 'notinline))) -#-sb-devel + (declaim (start-block find-free-fun find-lexically-apparent-fun - ;; needed by with-fun-name-leaf + ;; needed by ir1-translators find-global-fun)) (defun maybe-defined-here (name where) @@ -126,88 +183,47 @@ ;;; Return a GLOBAL-VAR structure usable for referencing the global ;;; function NAME. (defun find-global-fun (name latep) - (unless (info :function :kind name) - (setf (info :function :kind name) :function) - (setf (info :function :where-from name) :assumed)) - (let ((where (info :function :where-from name))) - (when (and (eq where :assumed) - ;; Slot accessors are defined just-in-time, if not already. - (not (typep name '(cons (eql sb-pcl::slot-accessor)))) - ;; In the ordinary target Lisp, it's silly to report - ;; undefinedness when the function is defined in the - ;; running Lisp. But at cross-compile time, the current - ;; definedness of a function is irrelevant to the - ;; definedness at runtime, which is what matters. - #-sb-xc-host (not (fboundp name)) - ;; LATEP is true when the user has indicated that - ;; late-late binding is desired by using eg. a quoted - ;; symbol -- in which case it makes little sense to - ;; complain about undefined functions. - (not latep)) - (note-undefined-reference name :function)) - (let ((ftype (global-ftype name)) - (notinline (fun-lexically-notinline-p name))) - (make-global-var - :kind :global-function - :%source-name name - :type (if (or (eq where :declared) - (and (not latep) - (not notinline) - *derive-function-types*)) - ftype - (specifier-type 'function)) - :defined-type (if (and (not latep) (not notinline)) - ftype - (specifier-type 'function)) - :where-from (if notinline - where - (maybe-defined-here name where)))))) - -;;; Have some DEFINED-FUN-FUNCTIONALS of a FREE-FUNS entry become invalid? -;;; Drop 'em. -;;; -;;; This was added to fix bug 138 in SBCL. It is possible for a FREE-FUNS -;;; entry to contain a DEFINED-FUN whose DEFINED-FUN-FUNCTIONAL object -;;; contained IR1 stuff (NODEs, BLOCKs...) referring to an already compiled -;;; (aka "dead") component. When this IR1 stuff was reused in a new component, -;;; under further obscure circumstances it could be used by -;;; WITH-IR1-ENVIRONMENT-FROM-NODE to generate a binding for -;;; *CURRENT-COMPONENT*. At that point things got all confused, since IR1 -;;; conversion was sending code to a component which had already been compiled -;;; and would never be compiled again. -;;; -;;; Note: as of 1.0.24.41 this seems to happen only in XC, and the original -;;; BUGS entry also makes it seem like this might not be an issue at all on -;;; target. -(defun clear-invalid-functionals (free-fun) - ;; There might be other reasons that FREE-FUN entries could - ;; become invalid, but the only one we've been bitten by so far - ;; (sbcl-0.pre7.118) is this one: - (when (defined-fun-p free-fun) - (setf (defined-fun-functionals free-fun) - (delete-if (lambda (functional) - (or (eq (functional-kind functional) :deleted) - (when (lambda-p functional) - (or - ;; (The main reason for this first test is to bail - ;; out early in cases where the LAMBDA-COMPONENT - ;; call in the second test would fail because links - ;; it needs are uninitialized or invalid.) - ;; - ;; If the BIND node for this LAMBDA is null, then - ;; according to the slot comments, the LAMBDA has - ;; been deleted or its call has been deleted. In - ;; that case, it seems rather questionable to reuse - ;; it, and certainly it shouldn't be necessary to - ;; reuse it, so we cheerfully declare it invalid. - (not (lambda-bind functional)) - ;; If this IR1 stuff belongs to a dead component, - ;; then we can't reuse it without getting into - ;; bizarre confusion. - (eq (component-info (lambda-component functional)) - :dead))))) - (defined-fun-functionals free-fun))) - nil)) + (let ((kind (info :function :kind name))) + (unless kind + (setf (info :function :kind name) :function) + (setf (info :function :where-from name) :assumed)) + (let ((where (info :function :where-from name))) + (when (and (eq where :assumed) + ;; Slot accessors are defined just-in-time, if not already. + (not (typep name '(cons (eql sb-pcl::slot-accessor)))) + ;; In the ordinary target Lisp, it's silly to report + ;; undefinedness when the function is defined in the + ;; running Lisp. But at cross-compile time, the current + ;; definedness of a function is irrelevant to the + ;; definedness at runtime, which is what matters. + #-sb-xc-host (not (fboundp name)) + ;; LATEP is true when the user has indicated that + ;; late-late binding is desired by using eg. a quoted + ;; symbol -- in which case it makes little sense to + ;; complain about undefined functions. + (not latep)) + (note-undefined-reference name :function)) + (case kind + ((:macro :special-form) + (compiler-warn "~(~a~) ~s where a function is expected" kind name))) + (let ((ftype (global-ftype name)) + (notinline (fun-lexically-notinline-p name))) + (make-global-var + :kind :global-function + :%source-name name + :type (if (or (eq where :declared) + (and (not latep) + (not notinline) + (eq *derive-function-types* t))) + ftype + (specifier-type 'function)) + :defined-type (if (and (not latep) (not notinline) + *derive-function-types*) + ftype + (specifier-type 'function)) + :where-from (if notinline + where + (maybe-defined-here name where))))))) ;;; If NAME already has a valid entry in (FREE-FUNS *IR1-NAMESPACE*), then return ;;; the value. Otherwise, make a new GLOBAL-VAR using information from @@ -217,10 +233,7 @@ ;;; demanded a function. (declaim (ftype (sfunction (t string) global-var) find-free-fun)) (defun find-free-fun (name context &aux (free-funs (free-funs *ir1-namespace*))) - (or (let ((old-free-fun (gethash name free-funs))) - (when old-free-fun - (clear-invalid-functionals old-free-fun) - old-free-fun)) + (or (gethash name free-funs) (let ((kind (info :function :kind name))) (ecase kind ((:macro :special-form) @@ -261,16 +274,11 @@ (declaim (end-block)) -(defun maybe-find-free-var (name) - (let ((found (gethash name (free-vars *ir1-namespace*)))) - (unless (eq found :deprecated) - found))) - ;;; Return the LEAF node for a global variable reference to NAME. If ;;; NAME is already entered in (FREE-VARS *IR1-NAMESPACE*), then we just return the ;;; corresponding value. Otherwise, we make a new leaf using ;;; information from the global environment and enter it in -;;; FREE-VARS. If the variable is unknown, then we emit a warning. +;;; FREE-VARS. (declaim (ftype (sfunction (t) (or leaf cons heap-alien-info)) find-free-var)) (defun find-free-var (name &aux (free-vars (free-vars *ir1-namespace*)) (existing (gethash name free-vars))) @@ -282,8 +290,6 @@ (type (info :variable :type name)) (where-from (info :variable :where-from name)) (deprecation-state (deprecated-thing-p 'variable name))) - (when (and (eq kind :unknown) (not deprecation-state)) - (note-undefined-reference name :variable)) ;; For deprecated vars, warn about LET and LAMBDA bindings, SETQ, and ref. ;; Don't warn again if the name was already seen by the transform ;; of SYMBOL[-GLOBAL]-VALUE. @@ -305,11 +311,6 @@ (type (type-specifier (info :variable :type name)))) `(macro . (the ,type ,expansion)))) (:constant - #+sb-xc-host ; check that we never reference host constants - (unless (member name '(nil t)) ; other than these 2 - (when (eq (find-symbol (string name) "XC-STRICT-CL") - name) - (error "Using a constant from the host ~s" name))) (find-constant (symbol-value name) name)) (t (make-global-var :kind kind @@ -317,71 +318,98 @@ :type type :where-from where-from))))))) +;;; Return T if and only if OBJ's nature as an externalizable thing renders +;;; it a leaf for dumping purposes. Symbols are leaflike despite havings slots +;;; containing pointers; similarly (COMPLEX RATIONAL) and RATIO. +(defun dumpable-leaflike-p (obj) + (or (sb-xc:typep obj '(or symbol number character + ;; (ARRAY NIL) is not included in UNBOXED-ARRAY + (or unboxed-array (array nil)) + system-area-pointer + #+sb-simd-pack simd-pack + #+sb-simd-pack-256 simd-pack-256)) + (cl:typep obj 'debug-name-marker) + ;; STANDARD-OBJECT layouts use MAKE-LOAD-FORM, but all other layouts + ;; have the same status as symbols - composite objects but leaflike. + (and (typep obj 'wrapper) (not (layout-for-pcl-obj-p obj))) + ;; PACKAGEs are also leaflike. + (cl:typep obj 'package) + ;; The cross-compiler wants to dump CTYPE instances as leaves, + ;; but CLASSOIDs are excluded since they have a MAKE-LOAD-FORM method. + #+sb-xc-host (cl:typep obj '(and ctype (not classoid))))) + ;;; Grovel over CONSTANT checking for any sub-parts that need to be ;;; processed with MAKE-LOAD-FORM. We have to be careful, because ;;; CONSTANT might be circular. We also check that the constant (and ;;; any subparts) are dumpable at all. -(defun maybe-emit-make-load-forms (constant &optional (name nil namep)) - (let ((xset (alloc-xset))) - (labels ((grovel (value) - ;; Unless VALUE is an object which which obviously - ;; can't contain other objects - (unless (dumpable-leaflike-p value) - (if (xset-member-p value xset) - (return-from grovel nil) - (add-to-xset value xset)) - (typecase value - (cons - (grovel (car value)) - (grovel (cdr value))) - (simple-vector - (dotimes (i (length value)) - (grovel (svref value i)))) - ((vector t) - (dotimes (i (length value)) - (grovel (aref value i)))) - ((simple-array t) - ;; Even though the (ARRAY T) branch does the exact - ;; same thing as this branch we do this separately - ;; so that the compiler can use faster versions of - ;; array-total-size and row-major-aref. - (dotimes (i (array-total-size value)) - (grovel (row-major-aref value i)))) - ((array t) - (dotimes (i (array-total-size value)) - (grovel (row-major-aref value i)))) - (instance - ;; In the target SBCL, we can dump any instance, but - ;; in the cross-compilation host, %INSTANCE-FOO - ;; functions don't work on general instances, only on - ;; STRUCTURE!OBJECTs. - ;; - ;; Behold the wonderfully clear sense of this- - ;; WHEN (EMIT-MAKE-LOAD-FORM VALUE) - ;; meaning "when you're _NOT_ using a custom load-form" - ;; - ;; FIXME: What about funcallable instances with - ;; user-defined MAKE-LOAD-FORM methods? - (when (emit-make-load-form value) - #+sb-xc-host - (aver (eql (layout-bitmap (%instance-layout value)) - sb-kernel:+layout-all-tagged+)) - (do-instance-tagged-slot (i value) - (grovel (%instance-ref value i))))) - (t - (compiler-error - "Objects of type ~/sb-impl:print-type-specifier/ ~ - can't be dumped into fasl files." - (type-of value))))))) - ;; Dump all non-trivial named constants using the name. - (if (and namep (not (sb-xc:typep constant '(or symbol character fixnum - #+64-bit single-float)))) - (emit-make-load-form constant name) - (grovel constant)))) +(defun maybe-emit-make-load-forms (constant) + (declare #-sb-xc-host (inline alloc-xset)) + (dx-let ((things-processed (alloc-xset))) + (named-let grovel ((value constant)) + (unless (or (dumpable-leaflike-p value) + (xset-member-p value things-processed) + #-sb-xc-host + (unbound-marker-p value)) + (add-to-xset value things-processed) + ;; FIXME: shouldn't this be something like SB-XC:TYPECASE ? + (typecase value + (cons + (grovel (car value)) + (grovel (cdr value))) + (simple-vector + (dotimes (i (length value)) + (grovel (svref value i)))) + ((vector t) + (dotimes (i (length value)) + (grovel (aref value i)))) + ((simple-array t) + ;; Even though the (ARRAY T) branch does the exact + ;; same thing as this branch we do this separately + ;; so that the compiler can use faster versions of + ;; array-total-size and row-major-aref. + (dotimes (i (array-total-size value)) + (grovel (row-major-aref value i)))) + ((array t) + (dotimes (i (array-total-size value)) + (grovel (row-major-aref value i)))) + (instance + ;; Behold the wonderfully clear sense of this- + ;; WHEN (EMIT-MAKE-LOAD-FORM VALUE) + ;; meaning "when you're _NOT_ using a custom load-form" + ;; + ;; FIXME: What about funcallable instances with + ;; user-defined MAKE-LOAD-FORM methods? + (when (emit-make-load-form value) + #+sb-xc-host + (aver (eql (wrapper-bitmap (%instance-wrapper value)) + sb-kernel:+layout-all-tagged+)) + (do-instance-tagged-slot (i value) + (grovel (%instance-ref value i))))) + (t + (compiler-error + "Objects of type ~/sb-impl:print-type-specifier/ can't be dumped into fasl files." + (type-of value))))))) (values)) ;;;; some flow-graph hacking utilities +;; Bind *COMPILER-ERROR-BAILOUT* to a function that throws out of the +;; body and converts a condition signalling form instead. The source +;; form is converted to a string since it may contain arbitrary +;; non-externalizable objects. +(defmacro ir1-error-bailout ((start next result form) &body body) + (with-unique-names (skip condition) + `(block ,skip + (let ((,condition (catch 'ir1-error-abort + (let ((*compiler-error-bailout* + (lambda (&optional e) + (throw 'ir1-error-abort e)))) + ,@body + (return-from ,skip nil))))) + (ir1-convert ,start ,next ,result + (make-compiler-error-form ,condition + ,form)))))) + ;;; This function sets up the back link between the node and the ;;; ctran which continues at it. (defun link-node-to-previous-ctran (node ctran) @@ -394,7 +422,7 @@ ;;; determine what is evaluated next. If the ctran has no block, then ;;; we make it be in the block that the node is in. If the ctran heads ;;; its block, we end our block and link it to that block. -#-sb-fluid (declaim (inline use-ctran)) +(declaim (inline use-ctran)) (defun use-ctran (node ctran) (declare (type node node) (type ctran ctran)) (if (eq (ctran-kind ctran) :unused) @@ -421,21 +449,12 @@ ;;; Insert NEW before OLD in the flow-graph. (defun insert-node-before (old new) - (let ((prev (node-prev old)) - (temp (make-ctran))) - (ensure-block-start prev) - (setf (ctran-next prev) nil) - (link-node-to-previous-ctran new prev) - (use-ctran new temp) - (link-node-to-previous-ctran old temp)) - (values)) - -(defun insert-node-before-no-split (old new) (let ((prev (node-prev old)) (temp (make-ctran))) (setf (ctran-next prev) nil) (link-node-to-previous-ctran new prev) (use-ctran new temp) + (setf (ctran-source-path temp) (ctran-source-path prev)) (link-node-to-previous-ctran old temp)) (values)) @@ -456,7 +475,7 @@ (setf (lvar-uses lvar) (list node (lvar-uses lvar))))) (reoptimize-lvar lvar))) -#-sb-fluid(declaim (inline use-continuation)) +(declaim (inline use-continuation)) (defun use-continuation (node ctran lvar) (use-ctran node ctran) (use-lvar node lvar)) @@ -550,75 +569,59 @@ (frob) (frob) (setq trail (cdr trail))))))) + ;;;; IR1-CONVERT, macroexpansion and special form dispatching -#-sb-devel (declaim (start-block ir1-convert ir1-convert-progn-body ir1-convert-combination-args reference-leaf reference-constant expand-compiler-macro - instrument-coverage)) - -(declaim (ftype (sfunction (ctran ctran (or lvar null) t) - (values)) - ir1-convert)) -(macrolet (;; Bind *COMPILER-ERROR-BAILOUT* to a function that throws - ;; out of the body and converts a condition signalling form - ;; instead. The source form is converted to a string since it - ;; may contain arbitrary non-externalizable objects. - (ir1-error-bailout ((start next result form) &body body) - (with-unique-names (skip condition) - `(block ,skip - (let ((,condition (catch 'ir1-error-abort - (let ((*compiler-error-bailout* - (lambda (&optional e) - (throw 'ir1-error-abort e)))) - ,@body - (return-from ,skip nil))))) - (ir1-convert ,start ,next ,result - (make-compiler-error-form ,condition - ,form))))))) - - ;; Translate FORM into IR1. The code is inserted as the NEXT of the - ;; CTRAN START. RESULT is the LVAR which receives the value of the - ;; FORM to be translated. The translators call this function - ;; recursively to translate their subnodes. - ;; - ;; As a special hack to make life easier in the compiler, a LEAF - ;; IR1-converts into a reference to that LEAF structure. This allows - ;; the creation using backquote of forms that contain leaf - ;; references, without having to introduce dummy names into the - ;; namespace. - (defun ir1-convert (start next result form) - (let* ((*current-path* (ensure-source-path form)) - (start (instrument-coverage start nil form))) - (ir1-error-bailout (start next result form) - (cond ((atom form) - (cond ((and (symbolp form) (not (keywordp form))) - (ir1-convert-var start next result form)) - ((leaf-p form) - (reference-leaf start next result form)) - (t - (reference-constant start next result form)))) - ((not (proper-list-p form)) - (compiler-error "~@<~S is not a proper list.~@:>" form)) - (t - (ir1-convert-functoid start next result form))))) - (values)) - - ;; Generate a reference to a manifest constant, creating a new leaf - ;; if necessary. - (defun reference-constant (start next result value) - (declare (type ctran start next) - (type (or lvar null) result)) - (ir1-error-bailout (start next result value) - (let* ((leaf (find-constant value)) - (res (make-ref leaf))) - (push res (leaf-refs leaf)) - (link-node-to-previous-ctran res start) - (use-continuation res next result))) - (values))) + maybe-reanalyze-functional)) + +;;; Translate FORM into IR1. The code is inserted as the NEXT of the +;;; CTRAN START. RESULT is the LVAR which receives the value of the +;;; FORM to be translated. The translators call this function +;;; recursively to translate their subnodes. +;;; +;;; As a special hack to make life easier in the compiler, a LEAF +;;; IR1-converts into a reference to that LEAF structure. This allows +;;; the creation using backquote of forms that contain leaf +;;; references, without having to introduce dummy names into the +;;; namespace. +(defun ir1-convert (start next result form) + (declare (type ctran start next) + (type (or lvar null) result)) + (let* ((*current-path* (ensure-source-path form)) + (start (instrument-coverage start nil form))) + (ir1-error-bailout (start next result form) + (cond ((atom form) + (cond ((and (symbolp form) (not (keywordp form))) + (ir1-convert-var start next result form)) + ((leaf-p form) + (reference-leaf start next result form)) + (t + (reference-constant start next result form)))) + (t + (ir1-convert-functoid start next result form))))) + (values)) + +;;; Generate a reference to a manifest constant, creating a new leaf +;;; if necessary. If we are producing a fasl file, make sure that +;;; MAKE-LOAD-FORM gets used on any parts of the constant that it +;;; needs to be. +(defun reference-constant (start next result value) + (declare (type ctran start next) + (type (or lvar null) result)) + (ir1-error-bailout (start next result value) + (when (producing-fasl-file) + (maybe-emit-make-load-forms value)) + (let* ((leaf (find-constant value)) + (res (make-ref leaf))) + (push res (leaf-refs leaf)) + (link-node-to-previous-ctran res start) + (use-continuation res next result))) + (values)) ;;; Add FUNCTIONAL to the COMPONENT-REANALYZE-FUNCTIONALS, unless it's ;;; some trivial type for which reanalysis is a trivial no-op. @@ -636,18 +639,15 @@ ;;; Generate a REF node for LEAF, frobbing the LEAF structure as ;;; needed. If LEAF represents a defined function which has already -;;; been converted, and is not NOTINLINE, then reference the -;;; functional instead. +;;; been converted in the same compilation block, and is not +;;; NOTINLINE, then reference the functional instead. (defun reference-leaf (start next result leaf &optional (name '.anonymous.)) (declare (type ctran start next) (type (or lvar null) result) (type leaf leaf)) (assure-leaf-live-p leaf) (let* ((type (lexenv-find leaf type-restrictions)) (leaf (or (and (defined-fun-p leaf) (neq (defined-fun-inlinep leaf) 'notinline) - ;; Only reference defined functionals from named-lambda, - ;; everything else should do this through recognize-known-call, - ;; avoiding copying references to global functions - (defined-fun-named-lambda-p leaf) + (defined-fun-same-block-p leaf) (let ((functional (defined-fun-functional leaf))) (when (and functional (not (functional-kind functional))) (maybe-reanalyze-functional functional)))) @@ -657,6 +657,11 @@ (maybe-reanalyze-functional leaf)) leaf)) (ref (make-ref leaf name))) + (when (and result + (lambda-var-p leaf) + (lambda-var-constant leaf)) + (push (make-lvar-lambda-var-annotation :lambda-var leaf) + (lvar-annotations result))) (push ref (leaf-refs leaf)) (when (and (functional-p leaf) (functional-ignore leaf)) @@ -683,45 +688,36 @@ (defun ir1-convert-var (start next result name) (declare (type ctran start next) (type (or lvar null) result) (symbol name)) (let ((var (or (lexenv-find name vars) (find-free-var name)))) - (if (and (global-var-p var) (not (always-boundp name))) - ;; KLUDGE: If the variable may be unbound, convert using SYMEVAL - ;; which is not flushable, so that unbound dead variables signal an - ;; error (bug 412, lp#722734): checking for null RESULT is not enough, - ;; since variables can become dead due to later optimizations. - (ir1-convert start next result - (if (eq (global-var-kind var) :global) - `(sym-global-val ',name) - `(symeval ',name))) - (etypecase var - (leaf - (cond - ((lambda-var-p var) - (let ((home (ctran-home-lambda-or-null start))) - (when home - (sset-adjoin var (lambda-calls-or-closes home)))) - (when (lambda-var-ignorep var) - ;; (ANSI's specification for the IGNORE declaration requires - ;; that this be a STYLE-WARNING, not a full WARNING.) - #-sb-xc-host - (compiler-style-warn "reading an ignored variable: ~S" name) - ;; there's no need for us to accept ANSI's lameness when - ;; processing our own code, though. - #+sb-xc-host - (warn "reading an ignored variable: ~S" name)))) - (reference-leaf start next result var name)) - ((cons (eql macro)) ; symbol-macro - ;; FIXME: the following comment is probably wrong now. - ;; If we warn here on :early and :late deprecation - ;; then we get an extra warning somehow. - ;; This case signals {EARLY,LATE,FINAL}-DEPRECATION-WARNING - ;; for symbol-macros. Includes variables, constants, - ;; etc. in :FINAL deprecation. - (when (eq (deprecated-thing-p 'variable name) :final) - (check-deprecated-thing 'variable name)) - ;; FIXME: [Free] type declarations. -- APD, 2002-01-26 - (ir1-convert start next result (cdr var))) - (heap-alien-info - (ir1-convert start next result `(%heap-alien ',var)))))) + (etypecase var + (leaf + (when (lambda-var-p var) + (let ((home (ctran-home-lambda-or-null start))) + (when (and home (neq (lambda-var-home var) home)) + (sset-adjoin var (lambda-calls-or-closes home)))) + (when (lambda-var-ignorep var) + ;; (ANSI's specification for the IGNORE declaration requires + ;; that this be a STYLE-WARNING, not a full WARNING.) + #-sb-xc-host + (compiler-style-warn "reading an ignored variable: ~S" name) + ;; there's no need for us to accept ANSI's lameness when + ;; processing our own code, though. + #+sb-xc-host + (warn "reading an ignored variable: ~S" name))) + (maybe-note-undefined-variable-reference var name) + (reference-leaf start next result var name)) + ((cons (eql macro)) ; symbol-macro + ;; FIXME: the following comment is probably wrong now. + ;; If we warn here on :early and :late deprecation + ;; then we get an extra warning somehow. + ;; This case signals {EARLY,LATE,FINAL}-DEPRECATION-WARNING + ;; for symbol-macros. Includes variables, constants, + ;; etc. in :FINAL deprecation. + (when (eq (deprecated-thing-p 'variable name) :final) + (check-deprecated-thing 'variable name)) + ;; FIXME: [Free] type declarations. -- APD, 2002-01-26 + (ir1-convert start next result (cdr var))) + (heap-alien-info + (ir1-convert start next result `(%heap-alien ',var))))) (values)) ;;; Find a compiler-macro for a form, taking FUNCALL into account. @@ -729,17 +725,17 @@ (flet ((legal-cm-name-p (name) (and (legal-fun-name-p name) (or (not (symbolp name)) - (not (sb-xc:macro-function name *lexenv*)))))) + (not (macro-function name *lexenv*)))))) (if (eq opname 'funcall) (let ((fun-form (cadr form))) (cond ((and (consp fun-form) (eq 'function (car fun-form)) (not (cddr fun-form))) (let ((real-fun (cadr fun-form))) (if (legal-cm-name-p real-fun) - (values (sb-xc:compiler-macro-function real-fun *lexenv*) + (values (compiler-macro-function real-fun *lexenv*) real-fun) (values nil nil)))) - ((sb-xc:constantp fun-form *lexenv*) + ((constantp fun-form *lexenv*) (let ((fun (constant-form-value fun-form *lexenv*))) (if (legal-cm-name-p fun) ;; CLHS tells us that local functions must shadow @@ -751,12 +747,12 @@ ;; a list (function name)", that means that ;; (funcall 'name) that gets here doesn't fit the ;; definition. - (values (sb-xc:compiler-macro-function fun nil) fun) + (values (compiler-macro-function fun nil) fun) (values nil nil)))) (t (values nil nil)))) (if (legal-fun-name-p opname) - (values (sb-xc:compiler-macro-function opname *lexenv*) opname) + (values (compiler-macro-function opname *lexenv*) opname) (values nil nil))))) ;;; If FORM has a usable compiler macro, use it; otherwise return FORM itself. @@ -786,7 +782,7 @@ (let* ((op (car form)) (translator (and (symbolp op) (info :function :ir1-convert op)))) (if translator - (funcall translator start next result form) + (funcall translator start next result (proper-list form)) (multiple-value-bind (res cmacro-fun-name) (expand-compiler-macro form) (cond ((eq res form) @@ -901,9 +897,10 @@ ;;; Convert a bunch of forms, discarding all the values except the ;;; last. If there aren't any forms, then translate a NIL. -(declaim (ftype (sfunction (ctran ctran (or lvar null) list) (values)) - ir1-convert-progn-body)) (defun ir1-convert-progn-body (start next result body) + (declare (type ctran start next) + (type (or lvar null) result) + (type list body)) (if (endp body) (reference-constant start next result nil) (let ((this-start start) @@ -922,89 +919,19 @@ (values)) -;;;; code coverage - -;;; Check the policy for whether we should generate code coverage -;;; instrumentation. If not, just return the original START -;;; ctran. Otherwise insert code coverage instrumentation after -;;; START, and return the new ctran. -(defun instrument-coverage (start mode form - &aux (metadata (coverage-metadata *compilation*))) - ;; We don't actually use FORM for anything, it's just convenient to - ;; have around when debugging the instrumentation. - (declare (ignore form)) - (if (and metadata - (policy *lexenv* (> store-coverage-data 0)) - *allow-instrumenting*) - (let ((path (source-path-original-source *current-path*))) - (when mode - (push mode path)) - (if (member (ctran-block start) - (gethash path (code-coverage-blocks metadata))) - ;; If this source path has already been instrumented in - ;; this block, don't instrument it again. - start - (let ((store - ;; Get an interned record cons for the path. A cons - ;; with the same object identity must be used for - ;; each instrument for the same block. - (ensure-gethash path (code-coverage-records metadata) - (cons path +code-coverage-unmarked+))) - (next (make-ctran)) - (*allow-instrumenting* nil)) - #+(or x86-64 x86) (declare (ignore store)) ; eval'd for side-effect only - (push (ctran-block start) - (gethash path (code-coverage-blocks metadata))) - (ir1-convert start next nil - #+(or x86-64 x86) - `(%primitive mark-covered ',path) - #-(or x86-64 x86) - `(locally - (declare (optimize speed - (safety 0) - (debug 0) - (check-constant-modification 0))) - ;; We're being naughty here, and - ;; modifying constant data. That's ok, - ;; we know what we're doing. - (%rplacd ',store t))) - next))) - start)) - -;;; In contexts where we don't have a source location for FORM -;;; e.g. due to it not being a cons, but where we have a source -;;; location for the enclosing cons, use the latter source location if -;;; available. This works pretty well in practice, since many PROGNish -;;; macroexpansions will just directly splice a block of forms into -;;; some enclosing form with `(progn ,@body), thus retaining the -;;; EQness of the conses. -(defun maybe-instrument-progn-like (start forms form) - (or (when (and *allow-instrumenting* - (not (get-source-path form))) - (let ((*current-path* (get-source-path forms))) - (when *current-path* - (instrument-coverage start nil form)))) - start)) - ;;;; converting combinations ;;; Does this form look like something that we should add single-stepping ;;; instrumentation for? (defun step-form-p (form) (flet ((step-symbol-p (symbol) - ;; Consistent treatment of *FOO* vs (SYMBOL-VALUE '*FOO*): - ;; we insert calls to SYMEVAL for most non-lexical - ;; variable references in order to avoid them being elided - ;; if the value is unused. - (if (member symbol '(symeval sym-global-val)) - (not (constantp (second form))) - (not (member (sb-xc:symbol-package symbol) - (load-time-value - ;; KLUDGE: packages we're not interested in - ;; stepping. - (mapcar #'find-package '(sb-c sb-int sb-impl - sb-kernel sb-pcl)) - t)))))) + (not (member (sb-xc:symbol-package symbol) + (load-time-value + ;; KLUDGE: packages we're not interested in + ;; stepping. + (mapcar #'find-package '(sb-c sb-int sb-impl + sb-kernel sb-pcl)) + t))))) (and *allow-instrumenting* (policy *lexenv* (= insert-step-conditions 3)) (listp form) @@ -1014,15 +941,18 @@ ;;; Convert a function call where the function FUN is a LEAF. FORM is ;;; the source for the call. We return the COMBINATION node so that ;;; the caller can poke at it if it wants to. -(declaim (ftype (sfunction (ctran ctran (or lvar null) list leaf) combination) - ir1-convert-combination)) (defun ir1-convert-combination (start next result form fun) + (declare (type ctran start next) + (type (or lvar null) result) + (type list form) + (type leaf fun) + #-sb-xc-host (values combination)) (let ((ctran (make-ctran)) (fun-lvar (make-lvar))) (ir1-convert start ctran fun-lvar `(the (or function symbol) ,fun)) (let ((combination (ir1-convert-combination-args fun-lvar ctran next result - (cdr form)))) + (cdr (proper-list form))))) (when (step-form-p form) ;; Store a string representation of the form in the ;; combination node. This will let the IR2 translator know @@ -1039,12 +969,16 @@ ;;; node. FUN-LVAR yields the function to call. ARGS is the list of ;;; arguments for the call, which defaults to the cdr of source. We ;;; return the COMBINATION node. -(defun ir1-convert-combination-args (fun-lvar start next result args) +(defun ir1-convert-combination-args (fun-lvar start next result args + &key (pass-nargs t) + arg-source-forms) (declare (type ctran start next) (type lvar fun-lvar) (type (or lvar null) result) - (list args)) + (type list args)) (let ((node (make-combination fun-lvar))) + (unless pass-nargs + (setf (combination-pass-nargs node) nil)) (setf (lvar-dest fun-lvar) node) (collect ((arg-lvars)) (let ((this-start start) @@ -1058,7 +992,9 @@ (setf this-start (maybe-instrument-progn-like this-start forms arg)) (let ((this-ctran (make-ctran)) - (this-lvar (make-lvar node))) + (this-lvar (make-lvar node)) + (*current-path* (or (get-source-path (pop arg-source-forms)) + *current-path*))) (ir1-convert this-start this-ctran this-lvar arg) (setq this-start this-ctran) (arg-lvars this-lvar)))) @@ -1068,10 +1004,6 @@ (setf (combination-args node) (arg-lvars)))) node)) -(defun show-transform (kind name new-form) - (let ((*print-right-margin* 100)) - (format *trace-output* "~&xform (~a) ~S~% -> ~S~%" - kind name new-form))) ;;; Convert a call to a global function. If not NOTINLINE, then we do ;;; source transforms and try out any inline expansion. If there is no ;;; expansion, but is INLINE, then give an efficiency note (unless a @@ -1093,14 +1025,22 @@ (struct-fun-transform transform form name)) ;; Note that "pass" means fail. Gotta love it. (cond (pass - (ir1-convert-maybe-predicate start next result form var)) + (ir1-convert-maybe-predicate start next result + (proper-list form) + var)) (t (unless (policy *lexenv* (zerop store-xref-data)) (record-call name (ctran-block start) *current-path*)) - (when *show-transforms-p* + (when (show-transform-p *show-transforms-p* name) (show-transform "src" name transformed)) - (ir1-convert start next result transformed)))) - (ir1-convert-maybe-predicate start next result form var)))))) + (let ((*transforming* (1+ *transforming*))) + (when (eq (car *current-path*) 'original-source-start) + (setf (ctran-source-path start) *current-path*)) + (ir1-convert start next result transformed))))) + (ir1-convert-maybe-predicate start next result + (proper-list form) + var)))))) + ;;; KLUDGE: If we insert a synthetic IF for a function with the PREDICATE ;;; attribute, don't generate any branch coverage instrumentation for it. @@ -1117,13 +1057,15 @@ (type (or lvar null) result) (list form) (type global-var var)) - (let ((info (info :function :info (leaf-source-name var)))) - (if (and info - (ir1-attributep (fun-info-attributes info) predicate) - (not (if-p (and result (lvar-dest result))))) - (let ((*instrument-if-for-code-coverage* nil)) - (ir1-convert start next result `(if ,form t nil))) - (ir1-convert-combination-checking-type start next result form var)))) + (if (vop-existsp :named sb-vm::move-conditional-result) + (ir1-convert-combination-checking-type start next result form var) + (let ((info (info :function :info (leaf-source-name var)))) + (if (and info + (ir1-attributep (fun-info-attributes info) predicate) + (not (if-p (and result (lvar-dest result))))) + (let ((*instrument-if-for-code-coverage* nil)) + (ir1-convert start next result `(if ,form t nil))) + (ir1-convert-combination-checking-type start next result form var))))) ;;; Actually really convert a global function call that we are allowed ;;; to early-bind. @@ -1165,7 +1107,6 @@ ;;;; PROCESS-DECLS -#-sb-devel (declaim (start-block process-decls make-new-inlinep find-in-bindings process-muffle-decls @@ -1175,9 +1116,9 @@ ;;; LAMBDA-VAR for that name, or NIL if it isn't found. We return the ;;; *last* variable with that name, since LET* bindings may be ;;; duplicated, and declarations always apply to the last. -(declaim (ftype (sfunction (list symbol) (or lambda-var list)) - find-in-bindings)) (defun find-in-bindings (vars name) + (declare (list vars) (symbol name) + #-sb-xc-host (values (or lambda-var list))) (let ((found nil)) (dolist (var vars) (cond ((leaf-p var) @@ -1217,6 +1158,7 @@ (var (or bound-var (lexenv-find var-name vars) (find-free-var var-name)))) + (maybe-note-undefined-variable-reference var var-name) (etypecase var (leaf (flet @@ -1323,6 +1265,10 @@ ;; to be bound... yet nowhere does it say that the special declaration ;; removes the constantness. Call it a spec bug and prohibit it. Same ;; for GLOBAL variables. + (unless (symbolp name) + (compiler-error + "~S is not a symbol and thus can't be declared special." + name)) (let ((kind (info :variable :kind name))) (unless (member kind '(:special :unknown)) (compiler-error @@ -1367,6 +1313,15 @@ (t (setf (lambda-var-no-constraints var) t)))))) +(defun process-constant-decl (spec vars) + (dolist (name (rest spec)) + (let ((var (find-in-bindings vars name))) + (cond + ((not var) + (warn "No ~s variable" name)) + (t + (setf (lambda-var-constant var) t)))))) + ;;; Return a DEFINED-FUN which copies a GLOBAL-VAR but for its INLINEP ;;; (and TYPE if notinline), plus type-restrictions from the lexenv. (defun make-new-inlinep (var inlinep local-type) @@ -1386,7 +1341,9 @@ (setf (defined-fun-inline-expansion res) (defined-fun-inline-expansion var)) (setf (defined-fun-functionals res) - (defined-fun-functionals var))) + (defined-fun-functionals var)) + (setf (defined-fun-same-block-p res) + (defined-fun-same-block-p var))) ;; FIXME: Is this really right? Needs we not set the FUNCTIONAL ;; to the original global-var? res)) @@ -1495,6 +1452,13 @@ (setf (lambda-var-ignorep var) t))))) (values)) +(defvar *stack-allocate-dynamic-extent* t + "If true (the default), the compiler respects DYNAMIC-EXTENT declarations +and stack allocates otherwise inaccessible parts of the object whenever +possible. Potentially long (over one page in size) vectors are, however, not +stack allocated except in zero SAFETY code, as such a vector could overflow +the stack without triggering overflow protection.") + (defun process-extent-decl (names vars fvars kind) (let ((extent (ecase kind @@ -1510,22 +1474,21 @@ (let* ((bound-var (find-in-bindings vars name)) (var (or bound-var (lexenv-find name vars) - (maybe-find-free-var name)))) + (find-free-var name)))) + (maybe-note-undefined-variable-reference var name) (etypecase var (leaf - (if bound-var - (if (and (leaf-extent var) (neq extent (leaf-extent var))) - (warn "Multiple incompatible extent declarations for ~S?" name) - (setf (leaf-extent var) extent)) - (compiler-notify - "Ignoring free ~S declaration: ~S" kind name))) + (cond + ((and (typep var 'global-var) (eq (global-var-kind var) :unknown))) + (bound-var + (if (and (leaf-extent var) (neq extent (leaf-extent var))) + (warn "Multiple incompatible extent declarations for ~S?" name) + (setf (leaf-extent var) extent))) + (t (compiler-notify "Ignoring free ~S declaration: ~S" kind name)))) (cons (compiler-error "~S on symbol-macro: ~S" kind name)) (heap-alien-info - (compiler-error "~S on alien-variable: ~S" kind name)) - (null - (compiler-style-warn - "Unbound variable declared ~S: ~S" kind name))))) + (compiler-error "~S on alien-variable: ~S" kind name))))) ((and (consp name) (eq (car name) 'function) (null (cddr name)) @@ -1541,12 +1504,7 @@ (etypecase fun (leaf (if bound-fun - #+stack-allocatable-closures (setf (leaf-extent bound-fun) extent) - #-stack-allocatable-closures - (compiler-notify - "Ignoring DYNAMIC-EXTENT declaration on function ~S ~ - (not supported on this platform)." fname) (compiler-notify "Ignoring free DYNAMIC-EXTENT declaration: ~S" name))) (cons @@ -1622,9 +1580,24 @@ (make-lexenv :default res :flushable (cdr spec))) + (current-defmethod + (destructuring-bind (name qualifiers specializers lambda-list) + (cdr spec) + (let* ((gfs (or *methods-in-compilation-unit* + (setf *methods-in-compilation-unit* + (make-hash-table :test #'equal)))) + (methods (or (gethash name gfs) + (setf (gethash name gfs) + (make-hash-table :test #'equal))))) + (setf (gethash (cons qualifiers specializers) methods) + lambda-list))) + res) (no-constraints (process-no-constraints-decl spec vars) res) + (constant-value + (process-constant-decl spec vars) + res) ;; We may want to detect LAMBDA-LIST and VALUES decls here, ;; and report them as "Misplaced" rather than "Unrecognized". (t @@ -1637,15 +1610,18 @@ optimize-qualities))) (defun process-muffle-decls (decls lexenv) - (flet ((process-it (spec) - (cond ((atom spec)) - ((member (car spec) '(muffle-conditions unmuffle-conditions)) - (setq lexenv - (process-1-decl spec lexenv nil nil nil nil)))))) - (dolist (decl decls) - (dolist (spec (rest decl)) - (process-it spec)))) - lexenv) + (let (source-form) + (flet ((process-it (spec) + (cond ((atom spec)) + ((member (car spec) '(muffle-conditions unmuffle-conditions)) + (setq lexenv + (process-1-decl spec lexenv nil nil nil nil))) + ((eq (car spec) 'source-form) + (setf source-form (cadr spec)))))) + (dolist (decl decls) + (dolist (spec (rest decl)) + (process-it spec)))) + (values lexenv source-form))) ;;; Use a list of DECLARE forms to annotate the lists of LAMBDA-VAR ;;; and FUNCTIONAL structures which are being bound. In addition to @@ -1668,6 +1644,7 @@ (allow-explicit-check allow-lambda-list) (lambda-list (if allow-lambda-list :unspecified nil)) (optimize-qualities) + (local-optimize) source-form (post-binding-lexenv (if binding-form-p (list nil)))) ; dummy cell (flet ((process-it (spec decl) @@ -1707,9 +1684,13 @@ it)) (setq explicit-check (or (cdr spec) t) allow-explicit-check nil)) ; at most one of this decl - ((equal spec '(top-level-form))) ; ignore ((typep spec '(cons (eql source-form))) (setf source-form (cadr spec))) + ;; Used only for the current function. + ;; E.g. suppressing argument checking without doing + ;; so in all the subforms. + ((typep spec '(cons (eql local-optimize))) + (setf local-optimize spec)) (t (multiple-value-bind (new-env new-qualities) (process-1-decl spec lexenv vars fvars @@ -1725,8 +1706,11 @@ ;; Kludge: EVAL calls this function to deal with LOCALLY. (process-it spec decl))))) (warn-repeated-optimize-qualities (lexenv-policy lexenv) optimize-qualities) + (values lexenv result-type (cdr post-binding-lexenv) - lambda-list explicit-check source-form))) + lambda-list explicit-check source-form + (when local-optimize + (process-optimize-decl local-optimize (lexenv-policy lexenv)))))) (defun %processing-decls (decls vars fvars ctran lvar binding-form-p fun) (multiple-value-bind (*lexenv* result-type post-binding-lexenv) @@ -1749,7 +1733,7 @@ &body forms) (declare (symbol ctran lvar)) (let ((post-binding-lexenv-p (not (null post-binding-lexenv))) - (post-binding-lexenv (or post-binding-lexenv (sb-xc:gensym "LEXENV")))) + (post-binding-lexenv (or post-binding-lexenv (gensym "LEXENV")))) `(%processing-decls ,decls ,vars ,fvars ,ctran ,lvar ,post-binding-lexenv-p (lambda (,ctran ,lvar ,post-binding-lexenv) @@ -1778,3 +1762,140 @@ :where-from :declared)))) (declaim (end-block)) + + +;;;; Proclamations: +;;; +;;; PROCLAIM changes the global environment, so we must handle its +;;; compile time side effects if we are to keep the information in the +;;; (FREE-xxx *IR1-NAMESPACE*) tables up to date. When there is a var +;;; structure we disown it by replacing it with an updated copy. Uses +;;; of the variable which were translated before the PROCLAIM will get +;;; the old version, while subsequent references will get the updated +;;; information. + +;;; If a special block compilation delimiter, then start or end the +;;; block as appropriate. If :BLOCK-COMPILE is T or NIL, then we +;;; ignore any start/end block declarations. +(defun process-block-compile-proclamation (kind entry-points) + (if (eq *block-compile-argument* :specified) + (ecase kind + (start-block + (finish-block-compilation) + (let ((compilation *compilation*)) + (setf (block-compile compilation) t) + (setf (entry-points compilation) entry-points))) + (end-block + (finish-block-compilation))) + (compiler-notify "ignoring ~S declaration since ~ + :BLOCK-COMPILE is not :SPECIFIED" + kind))) + +;;; Update function type info cached in (FREE-FUNS *IR1-NAMESPACE*). +;;; If: +;;; -- there is a GLOBAL-VAR, then just update the type and remove the +;;; name from the list of undefined functions. Someday we should +;;; check for incompatible redeclaration. +;;; -- there is a FUNCTIONAL, then apply the type assertion to that +;;; function. This will only happen during block compilation. +(defun process-1-ftype-proclamation (name type) + (proclaim-as-fun-name name) + (let* ((free-funs (free-funs *ir1-namespace*)) + (var (gethash name free-funs))) + (etypecase var + (null) + (global-var + (setf (gethash name free-funs) + (let ((kind (global-var-kind var))) + (if (defined-fun-p var) + (make-defined-fun + :%source-name name :type type :where-from :declared :kind kind + :inlinep (defined-fun-inlinep var) + :inline-expansion (defined-fun-inline-expansion var) + :same-block-p (defined-fun-same-block-p var) + :functionals (defined-fun-functionals var)) + (make-global-var :%source-name name :type type + :where-from :declared :kind kind)))) + (when (defined-fun-p var) + (let ((fun (defined-fun-functional var))) + (when fun + (assert-definition-type fun type + :unwinnage-fun #'compiler-notify + :where "this declaration")))))))) + +(defun process-ftype-proclamation (spec names) + (declare (list names)) + (let ((type (specifier-type spec))) + (unless (csubtypep type (specifier-type 'function)) + (error "Not a function type: ~/sb-impl:print-type/" spec)) + (dolist (name names) + (process-1-ftype-proclamation name type)))) + +;;; Replace each old var entry with one having the new type. +(defun process-type-proclamation (spec names) + (declare (list names)) + (let ((free-vars (free-vars *ir1-namespace*)) + (type (specifier-type spec))) + (dolist (name names) + (let ((var (gethash name free-vars))) + (etypecase var + (null) + ;; Constants cannot be redefined, and we already give the + ;; constant object the tightest type possible. We will error + ;; if the type is incompatible. + (constant) + (global-var + (setf (gethash name free-vars) + (make-global-var :%source-name name + :type type :where-from :declared + :kind (global-var-kind var))))))))) + +;;; Similar in effect to FTYPE, but change the :INLINEP. Copying the +;;; global-var ensures that when we substitute a functional for a +;;; global var (i.e. for DEFUN) that we won't clobber any uses +;;; declared :NOTINLINE. +(defun process-inline-proclamation (kind funs) + (declare (type (and inlinep (not null)) kind)) + (dolist (name funs) + (proclaim-as-fun-name name) + (let* ((free-funs (free-funs *ir1-namespace*)) + (var (gethash name free-funs))) + (etypecase var + (null) + (global-var + (setf (gethash name free-funs) + ;; Use the universal type as the local type restriction, + ;; since we are processing the proclamation at the top + ;; level and hence in a null lexical environment. + (make-new-inlinep var kind *universal-type*))))))) + +;;; Handle the compile-time side effects of PROCLAIM that don't happen +;;; at load time. These mostly side-effect the global state of the +;;; compiler, rather than the global environment. +(defun %compiler-proclaim (kind args) + (case kind + ((special global) + (dolist (name args) + (let* ((free-vars (free-vars *ir1-namespace*)) + (old (gethash name free-vars))) + (when old + (ecase (global-var-kind old) + ((:special :global)) + (:unknown + (setf (gethash name free-vars) + (make-global-var :%source-name name :type (leaf-type old) + :where-from (leaf-where-from old) + :kind (ecase kind + (special :special) + (global :global)))))))))) + ((start-block end-block) + #-(and sb-devel sb-xc-host) + (process-block-compile-proclamation kind args)) + (ftype + (destructuring-bind (spec &rest args) args + (process-ftype-proclamation spec args))) + (type + (destructuring-bind (spec &rest args) args + (process-type-proclamation spec args))) + ((inline notinline maybe-inline) + (process-inline-proclamation kind args)))) diff --git a/src/compiler/ir1util.lisp b/src/compiler/ir1util.lisp index 965c4d76a9..9836079cb9 100644 --- a/src/compiler/ir1util.lisp +++ b/src/compiler/ir1util.lisp @@ -14,10 +14,18 @@ ;;;; cleanup hackery +(defun delete-lexenv-enclosing-cleanup (lexenv) + (declare (type lexenv lexenv)) + (do ((lexenv2 lexenv + (lambda-call-lexenv (lexenv-lambda lexenv2)))) + ((null lexenv2) nil) + (when (lexenv-cleanup lexenv2) + (setf (lexenv-cleanup lexenv2) nil)))) + (defun lexenv-enclosing-cleanup (lexenv) (declare (type lexenv lexenv)) (do ((lexenv2 lexenv - (lambda-call-lexenv (lexenv-lambda lexenv2)))) + (lambda-call-lexenv (lexenv-lambda lexenv2)))) ((null lexenv2) nil) (awhen (lexenv-cleanup lexenv2) (return it)))) @@ -224,8 +232,7 @@ ;;; uninteresting nodes intervening. ;;; ;;; Uninteresting nodes are nodes in the same block which are either -;;; REFs, external CASTs to the same destination, or known combinations -;;; that never unwind. +;;; REFs, ENCLOSEs, or external CASTs to the same destination. (defun almost-immediately-used-p (lvar node) (declare (type lvar lvar) (type node node)) @@ -248,13 +255,8 @@ (when (and (memq (cast-type-check node) '(:external nil)) (eq dest (node-dest node))) (go :next))) - (combination - ;; KLUDGE: Unfortunately we don't have an attribute for - ;; "never unwinds", so we just special case - ;; %ALLOCATE-CLOSURES: it is easy to run into with eg. - ;; FORMAT and a non-constant first argument. - (when (eq '%allocate-closures (combination-fun-source-name node nil)) - (go :next)))))) + (enclose + (go :next))))) (t ;; Loops shouldn't cause a problem, either it will ;; encounter a not "uninteresting" node, or the destination @@ -368,23 +370,21 @@ (%delete-lvar-use node) (add-lvar-use node new)) (reoptimize-lvar new) - (propagate-lvar-dx new old propagate-dx)) + (when propagate-dx + (propagate-lvar-dx new old))) (t (update-lvar-dependencies new old) (flush-dest old))) (values)) -(defun propagate-lvar-dx (new old propagate-dx) - (awhen (and propagate-dx (lvar-dynamic-extent old)) - (setf (lvar-dynamic-extent old) nil) - (unless (lvar-dynamic-extent new) - (setf (lvar-dynamic-extent new) it) - (setf (cleanup-info it) (subst new old (cleanup-info it))))) - (when (lvar-dynamic-extent new) - (do-uses (node new) - (unless (node-to-be-deleted-p node) - (node-ends-block node))))) +(defun propagate-lvar-dx (new old) + (let ((cleanup (lvar-dynamic-extent old))) + (when cleanup + (setf (lvar-dynamic-extent old) nil) + (unless (lvar-dynamic-extent new) + (setf (lvar-dynamic-extent new) cleanup) + (setf (cleanup-nlx-info cleanup) (subst new old (cleanup-nlx-info cleanup))))))) (defun lexenv-contains-lambda (lambda parent-lexenv) (loop for lexenv = (lambda-lexenv lambda) @@ -408,11 +408,54 @@ (lambda-var-p new-lambda-var) ;; Make sure the let is inside the dx let (lexenv-contains-lambda (lambda-var-home new-lambda-var) - (cleanup-lexenv dx))) + (node-lexenv (cleanup-mess-up dx)))) (let ((new-lvar (lambda-var-ref-lvar new-ref))) (when new-lvar - (propagate-lvar-dx new-lvar old-lvar t) + (propagate-lvar-dx new-lvar old-lvar) t))))) + +(defun node-dominates-p (node1 node2) + (let ((block1 (node-block node1)) + (block2 (node-block node2))) + (if (eq block1 block2) + (do-nodes (node nil block1) + (cond ((eq node node1) + (setf node1 0)) + ((eq node node2) + (return (eq node1 0))))) + (let ((component (block-component block1))) + (unless (component-dominators-computed component) + (find-dominators component)) + (dominates-p block1 block2))))) + +(defun set-slot-old-p (node) + (let ((args (combination-args node))) + (multiple-value-bind (object-lvar value-lvar) + (if (lvar-fun-is (combination-fun node) '(%%primitive)) + (values (car (last args 2)) + (car (last args))) + (values (first args) (second args))) + (let ((allocator (principal-lvar-ref-use object-lvar)) + (value-ref (principal-lvar-ref value-lvar)) + (uses (lvar-uses value-lvar))) + (when (and (combination-p allocator) + (lvar-fun-is (combination-fun allocator) '(list* list + %make-instance + %make-funcallable-instance))) + + (when value-ref + (let ((var (ref-leaf value-ref))) + (when (and (lambda-var-p (ref-leaf value-ref)) + (not (lambda-var-sets (ref-leaf value-ref)))) + (when (member (functional-kind (lambda-var-home var)) + '(:external :optional)) + (return-from set-slot-old-p t)) + (setf uses (principal-lvar-ref-use value-lvar))))) + (when uses + (if (consp uses) + (loop for use in uses + always (node-dominates-p use allocator)) + (node-dominates-p uses allocator)))))))) ;;;; block starting/creation @@ -459,84 +502,48 @@ (node-ends-block (ctran-use ctran))))) (values)) -;;; CTRAN must be the last ctran in an incomplete block; finish the -;;; block and start a new one if necessary. -(defun start-block (ctran) - (declare (type ctran ctran)) - (aver (not (ctran-next ctran))) - (ecase (ctran-kind ctran) - (:inside-block - (let ((block (ctran-block ctran)) - (node (ctran-use ctran))) - (aver (not (block-last block))) - (aver node) - (setf (block-last block) node) - (setf (node-next node) nil) - (setf (ctran-use ctran) nil) - (setf (ctran-kind ctran) :unused) - (setf (ctran-block ctran) nil) - (link-blocks block (ctran-starts-block ctran)))) - (:block-start))) ;;;; -;;; Filter values of LVAR through FORM, which must be an ordinary/mv -;;; call. Exactly one argument must be 'DUMMY, which will be replaced -;;; with LVAR. In case of an ordinary call the function should not -;;; have return type NIL. We create a new "filtered" lvar. -;;; -;;; TODO: remove preconditions. -(defun filter-lvar (lvar form) - (declare (type lvar lvar) (type list form)) +;;; Filter values of LVAR through the form produced by +;;; FUNCTION. FUNCTION takes one argument and returns a form with the +;;; argument spliced into the form exactly once. This argument is a +;;; placeholder which will be replaced with LVAR once the form is +;;; IR1 converted and the resulting code is spliced in before LVAR's +;;; DEST. The new lvar which represents the value of the form is +;;; called the "filtered" lvar. +(defun filter-lvar (lvar function) + (declare (type lvar lvar) + (type function function)) (let* ((dest (lvar-dest lvar)) - (ctran (node-prev dest))) + (ctran (node-prev dest)) + ;; We pick an arbitrary unique leaf so that IR1-convert will + ;; reference it. + (placeholder (make-constant 0)) + (form (funcall function placeholder))) (with-ir1-environment-from-node dest - (ensure-block-start ctran) (let* ((old-block (ctran-block ctran)) (new-start (make-ctran)) (filtered-lvar (make-lvar)) (new-block (ctran-starts-block new-start))) - ;; Splice in the new block before DEST, giving the new block ;; all of DEST's predecessors. (dolist (block (block-pred old-block)) (change-block-successor block old-block new-block)) - (ir1-convert new-start ctran filtered-lvar form) - ;; KLUDGE: Comments at the head of this function in CMU CL - ;; said that somewhere in here we - ;; Set the new block's start and end cleanups to the *start* - ;; cleanup of PREV's block. This overrides the incorrect - ;; default from WITH-IR1-ENVIRONMENT-FROM-NODE. - ;; Unfortunately I can't find any code which corresponds to this. - ;; Perhaps it was a stale comment? Or perhaps I just don't - ;; understand.. -- WHN 19990521 - - ;; Replace 'DUMMY with the LVAR. (We can find 'DUMMY because - ;; no LET conversion has been done yet.) The [mv-]combination - ;; code from the call in the form will be the use of the new - ;; check lvar. We substitute exactly one argument. - (let* ((node (lvar-use filtered-lvar)) - victim) - (dolist (arg (basic-combination-args node) (aver victim)) - (let* ((arg (principal-lvar arg)) - (use (lvar-use arg)) - leaf) - (when (and (ref-p use) - (constant-p (setf leaf (ref-leaf use))) - (eql (constant-value leaf) 'dummy)) - (aver (not victim)) - (setf victim arg)))) - (aver (eq (constant-value (ref-leaf (lvar-use victim))) - 'dummy)) - + ;; Replace PLACEHOLDER with the LVAR. + (let* ((refs (leaf-refs placeholder)) + (node (first refs)) + (victim (node-lvar node))) + (aver (null (rest refs))) ; PLACEHOLDER must be referenced exactly once. (substitute-lvar filtered-lvar lvar) (substitute-lvar lvar victim) (flush-dest victim)) - ;; Invoking local call analysis converts this call to a LET. + ;; The form may have introduced new local calls, for example, + ;; from LET bindings, so invoke local call analysis. (locall-analyze-component *current-component*)))) (values)) @@ -552,7 +559,7 @@ (eq (basic-combination-kind use) :local)) (merges use)))) (substitute-lvar-uses lvar value - (and lvar (eq (lvar-uses lvar) node))) + (eq (lvar-uses lvar) node)) (%delete-lvar-use node) (prog1 (unlink-node node) @@ -570,31 +577,19 @@ (defun %insert-cast-before (next cast) (declare (type node next) (type cast cast)) - (let* ((ctran (node-prev next)) - (lvar (cast-value cast)) - (internal-ctran (make-ctran))) - (setf (ctran-next ctran) cast - (node-prev cast) ctran) - (use-ctran cast internal-ctran) - (link-node-to-previous-ctran next internal-ctran) + (let ((lvar (cast-value cast))) + (insert-node-before next cast) (setf (lvar-dest lvar) cast) (reoptimize-lvar lvar) - (when (return-p next) - (node-ends-block cast)) cast)) (defun insert-ref-before (leaf node) - (let* ((ref (make-ref leaf)) - (lvar (make-lvar node)) - (ctran (make-ctran)) - (node-ctran (node-prev node))) + (let ((ref (make-ref leaf)) + (lvar (make-lvar node))) + (insert-node-before node ref) (push ref (leaf-refs leaf)) (setf (leaf-ever-used leaf) t) - (setf (ctran-next node-ctran) ref - (node-prev ref) node-ctran) - (use-ctran ref ctran) (use-lvar ref lvar) - (link-node-to-previous-ctran node ctran) lvar)) ;;;; miscellaneous shorthand functions @@ -603,6 +598,7 @@ ;;; the LEXENV-LAMBDA may be deleted, we must chain up the ;;; LAMBDA-CALL-LEXENV thread until we find a CLAMBDA that isn't ;;; deleted, and then return its home. +(declaim (maybe-inline node-home-lambda)) (defun node-home-lambda (node) (declare (type node node)) (do ((fun (lexenv-lambda (node-lexenv node)) @@ -615,18 +611,29 @@ (defun lambda-parent (lambda) (lexenv-lambda (lambda-lexenv lambda))) -(declaim (ftype (sfunction (node) component) node-component)) (defun node-component (node) - (block-component (node-block node))) -(declaim (ftype (sfunction (node) physenv) node-physenv)) -(defun node-physenv (node) - (lambda-physenv (node-home-lambda node))) + (declare (type node node)) + (the component (block-component (node-block node)))) + +(declaim (maybe-inline node-environment)) +(defun node-environment (node) + (declare (type node node) #-sb-xc-host (inline node-home-lambda)) + (the environment (lambda-environment (node-home-lambda node)))) -#-sb-fluid (declaim (inline node-stack-allocate-p)) +(declaim (inline node-stack-allocate-p)) (defun node-stack-allocate-p (node) (awhen (node-lvar node) (lvar-dynamic-extent it))) +;; If there's a possibility the variable might be unbound, then its +;; references are unflushable. +(defun flushable-reference-p (node) + (let ((leaf (ref-leaf node))) + (not (and (global-var-p leaf) + (member (global-var-kind leaf) + '(:special :global :unknown)) + (not (always-boundp (leaf-source-name leaf))))))) + (defun flushable-callable-arg-p (name arg-count) (typecase name (null @@ -702,6 +709,7 @@ ;;; actually correspond to code which will be written anywhere. (declaim (ftype (sfunction (cblock) (or clambda null)) block-home-lambda-or-null)) (defun block-home-lambda-or-null (block) + #-sb-xc-host (declare (inline node-home-lambda)) (if (node-p (block-last block)) ;; This is the old CMU CL way of doing it. (node-home-lambda (block-last block)) @@ -731,14 +739,14 @@ nil)))) ;;; Return the non-LET LAMBDA that holds BLOCK's code. -(declaim (ftype (sfunction (cblock) clambda) block-home-lambda)) (defun block-home-lambda (block) - (block-home-lambda-or-null block)) + (declare (type cblock block)) + (the clambda (block-home-lambda-or-null block))) -;;; Return the IR1 physical environment for BLOCK. -(declaim (ftype (sfunction (cblock) physenv) block-physenv)) -(defun block-physenv (block) - (lambda-physenv (block-home-lambda block))) +;;; Return the IR1 environment for BLOCK. +(defun block-environment (block) + (declare (type cblock block)) + (lambda-environment (block-home-lambda block))) ;;;; DYNAMIC-EXTENT related @@ -755,48 +763,45 @@ (leaf-debug-name leaf)))) (defun note-no-stack-allocation (lvar &key flush) - ;; If the target being compiled does not have all 4 of these features, - ;; then never warn about failure to stack-allocate. It's only useful to - ;; see when a _particular_ allocation can't go on the stack. - ;; It's just a distraction otherwise. - (declare (ignorable lvar flush)) - - #+(and sb-xc-host - (not (and stack-allocatable-closures - stack-allocatable-vectors - stack-allocatable-lists - stack-allocatable-fixed-objects))) - (return-from note-no-stack-allocation) - (do-uses (use (principal-lvar lvar)) (dolist (use (ensure-list (if (cast-p use) (principal-lvar-use (cast-value use)) use))) (unless (or - ;; Don't complain about not being able to stack allocate constants. - (and (ref-p use) (constant-p (ref-leaf use))) ;; If we're flushing, don't complain if we can flush the combination. (and flush (or (node-to-be-deleted-p use) (and (combination-p use) (flushable-combination-p use)))) - ;; Don't report those with homes in :OPTIONAL -- we'd get doubled - ;; reports that way. - ;; Also don't report if the home is :EXTERNAL. This allows declaring - ;; funargs as dynamic-extent which can inform compilation of callers - ;; to this lambda that they can DXify the arg. - (and (ref-p use) (lambda-var-p (ref-leaf use)) - (member (lambda-kind (lambda-var-home (ref-leaf use))) - '(:optional :external))) - ;; Don't complain if the referent is #'SOMEFUN, avoiding a note for - ;; (DEFUN FOO (X &KEY (TEST #'IDENTITY)) ...) - ;; where TEST is declared DX, and one possible use of this LVAR is - ;; to the supplied arg, and other is essentially constant-like. (and (ref-p use) - (let ((var (ref-leaf use))) - (and (global-var-p var) - (eq (global-var-kind var) :global-function))))) + (let ((leaf (ref-leaf use)) ) + (or + ;; Don't complain about not being able to stack allocate constants. + (constant-p leaf) + ;; Don't report those with homes in :OPTIONAL -- we'd get doubled + ;; reports that way. + ;; Also don't report if the home is :EXTERNAL. This allows declaring + ;; funargs as dynamic-extent which can inform compilation of callers + ;; to this lambda that they can DXify the arg. + (and (lambda-var-p leaf) + (member (lambda-kind (lambda-var-home (ref-leaf use))) + '(:optional :external))) + (or + ;; Don't complain if the referent is #'SOMEFUN, avoiding a note for + ;; (DEFUN FOO (X &KEY (TEST #'IDENTITY)) ...) + ;; where TEST is declared DX, and one possible use of this LVAR is + ;; to the supplied arg, and other is essentially constant-like. + (and (global-var-p leaf) + (eq (global-var-kind leaf) :global-function)) + ;; Ignore top level closures + (and (functional-p leaf) + (functional-enclose leaf) + (eq (functional-kind (node-home-lambda (functional-enclose leaf))) + :toplevel)))))) + ;; It's supposed to be slow, so who cares it can't + ;; stack allocate something. + (policy use (= speed 0))) ;; FIXME: For the first leg (lambda-bind (lambda-var-home ...)) ;; would be a far better description, but since we use ;; *COMPILER-ERROR-CONTEXT* for muffling we can't -- as that node @@ -809,35 +814,28 @@ (compiler-notify "~@<could~2:I not stack allocate: ~S~:@>" (find-original-source (node-source-path use))))))))) -(defun use-good-for-dx-p (use dx &optional component) - ;; FIXME: Can casts point to LVARs in other components? - ;; RECHECK-DYNAMIC-EXTENT-LVARS assumes that they can't -- that is, that the - ;; PRINCIPAL-LVAR is always in the same component as the original one. It - ;; would be either good to have an explanation of why casts don't point - ;; across components, or an explanation of when they do it. ...in the - ;; meanwhile AVER that our assumption holds true. - (aver (or (not component) (eq component (node-component use)))) +(defun use-good-for-dx-p (use dx) (and (not (node-to-be-deleted-p use)) (or (dx-combination-p use dx) (and (cast-p use) (not (cast-type-check use)) - (lvar-good-for-dx-p (cast-value use) dx component)) + (lvar-good-for-dx-p (cast-value use) dx)) (and (trivial-lambda-var-ref-p use) (let ((uses (lvar-uses (trivial-lambda-var-ref-lvar use)))) (or (eq use uses) - (lvar-good-for-dx-p (trivial-lambda-var-ref-lvar use) dx component))))))) + (lvar-good-for-dx-p (trivial-lambda-var-ref-lvar use) dx))))))) -(defun lvar-good-for-dx-p (lvar dx &optional component) +(defun lvar-good-for-dx-p (lvar dx) (let ((uses (lvar-uses lvar))) (cond ((null uses) nil) ((consp uses) (every (lambda (use) - (use-good-for-dx-p use dx component)) + (use-good-for-dx-p use dx)) uses)) (t - (use-good-for-dx-p uses dx component))))) + (use-good-for-dx-p uses dx))))) (defun known-dx-combination-p (use dx) (and (eq (combination-kind use) :known) @@ -905,12 +903,18 @@ (let* ((lvar (ref-lvar ref)) (dest (when lvar (lvar-dest lvar)))) (and (combination-p dest) - (eq :known (combination-kind dest)) - (awhen (combination-fun-info dest) - (or (ir1-attributep (fun-info-attributes it) dx-safe) - (and (not (combination-lvar dest)) - (awhen (fun-info-result-arg it) - (eql lvar (nth it (combination-args dest)))))))))) + (case (combination-kind dest) + (:known + (awhen (combination-fun-info dest) + (or (ir1-attributep (fun-info-attributes it) dx-safe) + (and (not (combination-lvar dest)) + (awhen (fun-info-result-arg it) + (eql lvar (nth it (combination-args dest)))))))) + (:local + (every #'trivial-lambda-var-ref-p + (lambda-var-refs (lvar-lambda-var lvar)))))))) + +(defvar *dx-lexenv*) (defun trivial-lambda-var-ref-p (use) (and (ref-p use) @@ -920,12 +924,14 @@ (neq (lambda-var-extent var) 'indefinite-extent)) (let ((home (lambda-var-home var)) (refs (lambda-var-refs var))) - ;; bound by a non-XEP system lambda, no other REFS that aren't + ;; bound by a non-XEP lambda, no other REFS that aren't ;; DX-SAFE, or are result-args when the result is discarded. - (when (and (lambda-system-lambda-p home) - (neq :external (lambda-kind home)) + (when (and (neq :external (lambda-kind home)) + (or (lambda-system-lambda-p home) + (lexenv-contains-lambda home *dx-lexenv*)) (dolist (ref refs t) - (unless (or (eq use ref) (ref-good-for-dx-p ref)) + (unless (or (eq use ref) + (ref-good-for-dx-p ref)) (return nil)))) ;; the LAMBDA this var is bound by has only a single REF, going ;; to a combination @@ -971,7 +977,7 @@ return arg)))))) ;;; This needs to play nice with LVAR-GOOD-FOR-DX-P and friends. -(defun handle-nested-dynamic-extent-lvars (dx lvar &optional recheck-component) +(defun handle-nested-dynamic-extent-lvars (dx lvar) (let ((uses (lvar-uses lvar))) ;; DX value generators must end their blocks: see UPDATE-UVL-LIVE-SETS. ;; Uses of mupltiple-use LVARs already end their blocks, so we just need @@ -986,25 +992,25 @@ (etypecase use (cast (handle-nested-dynamic-extent-lvars - dx (cast-value use) recheck-component)) + dx (cast-value use))) (combination (loop for arg in (combination-args use) ;; deleted args show up as NIL here when (and arg - (lvar-good-for-dx-p arg dx recheck-component)) + (lvar-good-for-dx-p arg dx)) append (handle-nested-dynamic-extent-lvars - dx arg recheck-component))) + dx arg))) (ref (let* ((other (trivial-lambda-var-ref-lvar use))) (unless (eq other lvar) (handle-nested-dynamic-extent-lvars - dx other recheck-component))))))) + dx other))))))) (cons (cons dx lvar) (if (listp uses) (loop for use in uses - when (use-good-for-dx-p use dx recheck-component) + when (use-good-for-dx-p use dx) nconc (recurse use)) - (when (use-good-for-dx-p uses dx recheck-component) + (when (use-good-for-dx-p uses dx) (recurse uses))))))) ;;; Return the Top Level Form number of PATH, i.e. the ordinal number @@ -1034,26 +1040,11 @@ (defun source-path-forms (path) (subseq path 0 (position 'original-source-start path))) -(defun tree-some (predicate tree) - (let ((seen (make-hash-table))) - (labels ((walk (tree) - (cond ((funcall predicate tree)) - ((and (consp tree) - (not (gethash tree seen))) - (setf (gethash tree seen) t) - (or (walk (car tree)) - (walk (cdr tree))))))) - (walk tree)))) - ;;; Return the innermost source form for NODE. (defun node-source-form (node) (declare (type node node)) (let* ((path (node-source-path node)) - (forms (remove-if (lambda (x) - (tree-some #'leaf-p x)) - (source-path-forms path)))) - ;; another option: if first form includes a leaf, return - ;; find-original-source instead. + (forms (source-path-forms path))) (if forms (first forms) (values (find-original-source path))))) @@ -1119,13 +1110,15 @@ (defun cast-single-value-p (cast) (not (values-type-p (cast-asserted-type cast)))) -#-sb-fluid (declaim (inline lvar-single-value-p)) +(declaim (inline lvar-single-value-p)) (defun lvar-single-value-p (lvar) (or (not lvar) (%lvar-single-value-p lvar))) (defun %lvar-single-value-p (lvar) (let ((dest (lvar-dest lvar))) (typecase dest - ((or creturn exit) + (exit + (lvar-single-value-p (node-lvar dest))) + (creturn nil) (mv-combination (eq (basic-combination-fun dest) lvar)) @@ -1144,11 +1137,12 @@ (defun principal-lvar-single-valuify (lvar) (loop for prev = lvar then (node-lvar dest) for dest = (and prev (lvar-dest prev)) - while (cast-p dest) + while (or (cast-p dest) + (exit-p dest)) do (setf (node-derived-type dest) (make-short-values-type (list (single-value-type (node-derived-type dest))))) - (reoptimize-lvar prev))) + (reoptimize-lvar prev))) ;;; Return a new LEXENV just like DEFAULT except for the specified ;;; slot values. Values for the alist slots are APPENDed to the @@ -1163,7 +1157,7 @@ (lexenv-disabled-package-locks default)) (policy (lexenv-policy default)) (user-data (lexenv-user-data default)) - (flushable (lexenv-flushable default)) + flushable (parent default)) (macrolet ((frob (var slot) `(let ((old (,slot default))) @@ -1295,9 +1289,8 @@ ;;; otherwise false. (defun join-successor-if-possible (block) (declare (type cblock block)) - (let* ((next (first (block-succ block))) - (start (block-start next))) - (when start ; NEXT is not an END-OF-COMPONENT marker + (let ((next (first (block-succ block)))) + (when (block-start next) ; NEXT is not an END-OF-COMPONENT marker (cond ( ;; We cannot combine with a successor block if: (or ;; the successor has more than one predecessor; @@ -1313,28 +1306,8 @@ ;; thus the control transfer is a non-local exit. (not (eq (block-home-lambda block) (block-home-lambda next))) - ;; Stack analysis phase wants ENTRY to start a block... - (entry-p (block-start-node next)) - (let ((last (block-last block))) - (and (valued-node-p last) - (awhen (node-lvar last) - (or - ;; ... and a DX-allocator to end a block. - (lvar-dynamic-extent it) - ;; ... and for there to be no chance of there - ;; being two successive USEs of the same - ;; multi-valued LVAR in the same block (since - ;; we can only insert cleanup code at block - ;; boundaries, but need to discard - ;; multi-valued LVAR contents before they are - ;; overwritten). - (and (consp (lvar-uses it)) - (not (lvar-single-value-p it))))))) (neq (block-type-check block) - (block-type-check next)) - ;; This ctran is a destination of an EXIT, - ;; a later inlined function may want to use it. - (ctran-entries start)) + (block-type-check next))) nil) (t (join-blocks block next) @@ -1441,7 +1414,10 @@ (unless (eq type1 type2) (derive-node-type ref1 (values-type-union type1 type2) - :from-scratch t))) + :from-scratch t)) + (setf (ref-constraints ref1) + (intersection (ref-constraints ref1) + (ref-constraints ref2)))) (loop for pred in (block-pred block2) do (change-block-successor pred block2 block1)) @@ -1472,31 +1448,6 @@ (setf (block-prev next) block)) (values)) -;;; List all NLX-INFOs which BLOCK can exit to. -;;; -;;; We hope that no cleanup actions are performed in the middle of -;;; BLOCK, so it is enough to look only at cleanups in the block -;;; end. The tricky thing is a special cleanup block; all its nodes -;;; have the same cleanup info, corresponding to the start, so the -;;; same approach returns safe result. -(defun map-block-nlxes (fun block &optional dx-cleanup-fun) - (do-nested-cleanups (cleanup (block-end-lexenv block)) - (let ((mess-up (cleanup-mess-up cleanup))) - (case (cleanup-kind cleanup) - ((:block :tagbody) - (aver (entry-p mess-up)) - (loop for exit in (entry-exits mess-up) - for nlx-info = (exit-nlx-info exit) - do (funcall fun nlx-info))) - ((:catch :unwind-protect) - (aver (combination-p mess-up)) - (let* ((arg-lvar (first (basic-combination-args mess-up))) - (nlx-info (constant-value (ref-leaf (lvar-use arg-lvar))))) - (funcall fun nlx-info))) - ((:dynamic-extent) - (when dx-cleanup-fun - (funcall dx-cleanup-fun cleanup))))))) - ;;; Set the FLAG for all the blocks in COMPONENT to NIL, except for ;;; the head and tail which are set to T. (declaim (ftype (sfunction (component) (values)) clear-flags)) @@ -1582,7 +1533,6 @@ ;;;; deleting stuff -#-sb-devel (declaim (start-block delete-ref delete-functional flush-node flush-dest delete-lvar delete-block delete-block-lazily delete-lambda mark-for-deletion)) @@ -1835,14 +1785,6 @@ (setf (lvar-uses lvar) nil)) (values)) -(defun delete-dest (lvar) - (when lvar - (let* ((dest (lvar-dest lvar)) - (prev (node-prev dest))) - (let ((block (ctran-block prev))) - (unless (block-delete-p block) - (mark-for-deletion block)))))) - ;;; Queue the block for deletion (defun delete-block-lazily (block) (declare (type cblock block)) @@ -1945,7 +1887,7 @@ (delete node (basic-var-sets var))))) (cast (flush-dest (cast-value node))) - (no-op))) + (enclose))) (remove-from-dfo block) (values)) @@ -1955,33 +1897,36 @@ ;;; Do stuff to indicate that the return node NODE is being deleted. (defun delete-return (node) (declare (type creturn node)) - (let ((fun (return-lambda node))) - (when fun ;; could become replaced by MOVE-RETURN-STUFF - (let ((tail-set (lambda-tail-set fun))) - (aver (lambda-return fun)) - (setf (lambda-return fun) nil) - (when (and tail-set (not (find-if #'lambda-return - (tail-set-funs tail-set)))) - (setf (tail-set-type tail-set) *empty-type*))))) + (let* ((fun (return-lambda node)) + (tail-set (lambda-tail-set fun))) + (aver (lambda-return fun)) + (setf (lambda-return fun) nil) + (when (and tail-set (not (find-if #'lambda-return + (tail-set-funs tail-set)))) + (setf (tail-set-type tail-set) *empty-type*))) (values)) ;;; If any of the VARS in FUN was never referenced and was not ;;; declared IGNORE, then complain. (defun note-unreferenced-vars (vars policy) (dolist (var vars) - (unless (or (leaf-ever-used var) - (lambda-var-ignorep var)) - (unless (policy policy (= inhibit-warnings 3)) - ;; ANSI section "3.2.5 Exceptional Situations in the Compiler" - ;; requires this to be no more than a STYLE-WARNING. - #-sb-xc-host - (compiler-style-warn "The variable ~S is defined but never used." - (leaf-debug-name var)) - ;; There's no reason to accept this kind of equivocation - ;; when compiling our own code, though. - #+sb-xc-host - (warn "The variable ~S is defined but never used." - (leaf-debug-name var))) + (unless (or (eq (leaf-ever-used var) t) (lambda-var-ignorep var)) + (let ((*lexenv* (if (node-p *compiler-error-context*) + (node-lexenv *compiler-error-context*) + *lexenv*)) + (*compiler-error-context* + (or (get-source-path (lambda-var-source-form var)) + *compiler-error-context*))) + (unless (policy policy (= inhibit-warnings 3)) + ;; ANSI section "3.2.5 Exceptional Situations in the Compiler" + ;; requires this to be no more than a STYLE-WARNING. + ;; There's no reason to accept this kind of equivocation + ;; when compiling our own code, though. + (#-sb-xc-host compiler-style-warn #+sb-xc-host warn + (if (eq (leaf-ever-used var) 'set) + "The variable ~S is assigned but never read." + "The variable ~S is defined but never used.") + (leaf-debug-name var)))) (setf (leaf-ever-used var) t)))) ; to avoid repeated warnings? -- WHN (defun note-unreferenced-fun-vars (fun) @@ -2055,39 +2000,94 @@ (unless (eq (functional-kind home) :deleted) (do-nodes (node nil block) (let* ((path (node-source-path node)) - (first (first path))) - (when (and (not (return-p node)) - ;; CASTs are just value filters and do not - ;; represent code and they can be moved around - ;; making CASTs from the original source code - ;; appear in code inserted by the compiler, generating - ;; false deletion notes. - ;; And if a block with the original source gets - ;; deleted the node that produces the value for - ;; the CAST will get a note, no need to note - ;; twice. - (not (cast-p node)) - ;; Nothing interesting in BIND nodes - (not (bind-p node)) + (ctran-path (ctran-source-path (node-prev node)))) + (flet ((visible-p (path) + (let ((first (first path))) (or (eq first 'original-source-start) (and (atom first) (or (not (symbolp first)) (let ((pkg (cl:symbol-package first))) (and pkg (neq pkg *keyword-package*)))) (not (member first '(t nil))) - (not (cl:typep first '(or fixnum character))) + (not (cl:typep first '(or fixnum character + #+64-bit single-float))) (every (lambda (x) (present-in-form first x 0)) (source-path-forms path)) (present-in-form first (find-original-source path) - 0)))) - (let ((*compiler-error-context* node)) - (compiler-notify 'code-deletion-note - :format-control "deleting unreachable code" - :format-arguments nil)) - (return)))))) + 0)))))) + (cond ((and ctran-path + (visible-p ctran-path)) + (push (cons ctran-path (node-lexenv node)) + (deleted-source-paths *compilation*)) + (return)) + ((and (not (return-p node)) + ;; CASTs are just value filters and do not + ;; represent code and they can be moved around + ;; making CASTs from the original source code + ;; appear in code inserted by the compiler, generating + ;; false deletion notes. + ;; And if a block with the original source gets + ;; deleted the node that produces the value for + ;; the CAST will get a note, no need to note + ;; twice. + (not (cast-p node)) + ;; Nothing interesting in BIND nodes + (not (bind-p node)) + ;; Try to get the outer deleted node. + (not (and (valued-node-p node) + (let ((dest (node-dest node))) + (and dest + (node-to-be-deleted-p dest) + (node-source-inside-p node dest))))) + (visible-p path)) + (push (cons path (node-lexenv node)) + (deleted-source-paths *compilation*)) + (return)))))))) (values)) +(defun node-source-inside-p (inner-node outer-node) + (tailp (source-path-original-source (node-source-path outer-node)) + (source-path-original-source (node-source-path inner-node)))) + +(defun report-code-deletion () + (let ((forms (make-hash-table :test #'equal)) + (reversed-path)) + ;; Report only the outermost form + (loop for pair in (shiftf (deleted-source-paths *compilation*) nil) + for (path) = pair + do + (when (eq (car path) 'original-source-start) + (setf (gethash (source-path-original-source path) forms) path)) + (push pair reversed-path)) + (loop for (path . lexenv) in reversed-path + for original = (source-path-original-source path) + when (loop for outer on (if (eq (car path) 'original-source-start) + (cdr original) + original) + never (gethash outer forms)) + do + (let ((*current-path* path) + (*lexenv* lexenv)) + (compiler-notify 'code-deletion-note + :format-control "deleting unreachable code" + :format-arguments nil))))) + +(defun maybe-reoptimize-previous-node (ctran block) + (flet ((maybe-reoptimize (node) + (when (basic-combination-p node) + (let ((fun-info (basic-combination-fun-info node))) + (when (and fun-info + (ir1-attributep (fun-info-attributes fun-info) + reoptimize-when-unlinking)) + (reoptimize-node node)))))) + (case (ctran-kind ctran) + (:inside-block + (maybe-reoptimize (ctran-use ctran))) + (:block-start + (dolist (pred (block-pred block)) + (maybe-reoptimize (block-last pred))))))) + ;;; Delete a node from a block, deleting the block if there are no ;;; nodes left. We remove the node from the uses of its LVAR. ;;; @@ -2102,13 +2102,13 @@ (declare (type node node)) (when (valued-node-p node) (delete-lvar-use node)) - (let* ((ctran (node-next node)) (next (and ctran (ctran-next ctran))) (prev (node-prev node)) (block (ctran-block prev)) (prev-kind (ctran-kind prev)) (last (block-last block))) + (maybe-reoptimize-previous-node prev block) (cond ((or (eq prev-kind :inside-block) (and (eq prev-kind :block-start) (not (eq node last)))) @@ -2118,7 +2118,9 @@ (t (setf (ctran-next prev) next) (setf (node-prev next) prev) - (when (if-p next) ; AOP wanted + (unless (ctran-source-path prev) + (setf (ctran-source-path prev) (ctran-source-path ctran))) + (when (if-p next) (reoptimize-lvar (if-test next))))) (setf (node-prev node) nil) nil) @@ -2126,15 +2128,8 @@ (aver (eq prev-kind :block-start)) (aver (eq node last)) (let* ((succ (block-succ block)) - (next (first succ)) - (next-ctran (block-start next))) + (next (first succ))) (aver (singleton-p succ)) - ;; Update the ctran used by EXITs from BLOCKs. - (when next-ctran - (loop for entry in (ctran-entries prev) - do (setf (second entry) next-ctran)) - (setf (ctran-entries next-ctran) - (ctran-entries prev))) (cond ((eq block (first succ)) (with-ir1-environment-from-node node @@ -2363,179 +2358,96 @@ is :ANY, the function name is not checked." (change-ref-leaf ref new-leaf))) (values)) -;;; Do almost the same thing that EQUAL does, but consider strings -;;; to be dissimilar if their element types differ. -;;; When cross-compiling, any STRING= strings are similar -;;; because there is logically only a BASE-STRING type. -;;; ISTM that the language botched this up by not defining a standard -;;; predicate which returns T if and only if objects are similar. -(defun similarp (x y) - #+sb-xc-host (equal x y) - #-sb-xc-host - (named-let recurse ((x x) (y y)) - (cond ((%eql x y) t) - ((consp x) - (and (consp y) - (recurse (car x) (car y)) - (recurse (cdr x) (cdr y)))) - ((stringp x) - (and (stringp y) - ;; (= (widetag-of ...)) would be too strict, because a simple string - ;; can be be similar to a non-simple string. - (eq (array-element-type x) - (array-element-type y)) - (string= x y))) - (t ; PATHNAME and BIT-vector can fall back upon EQUAL - ;; This could be slightly wrong, but so it always was, because we use - ;; (and have used) EQUAL for PATHNAME in SB-C::FIND-CONSTANT, but: - ;; "Two pathnames S and C are similar if all corresponding pathname components are similar." - ;; and we readily admit that similarity of strings requires equal element types. - ;; So this is slightly dubious: - ;; (EQUAL (MAKE-PATHNAME :NAME (COERCE "A" 'SB-KERNEL:SIMPLE-CHARACTER-STRING)) - ;; (MAKE-PATHNAME :NAME (COERCE "A" 'BASE-STRING))) => T - ;; On the other hand, nothing says that the pathname constructors such as - ;; MAKE-PATHNAME and MERGE-PATHNAMES don't convert to a canonical representation - ;; which renders them EQUAL when all strings are STRING=. - ;; This area of the language spec seems to have been a clusterfsck. - (equal x y))))) - -;;; FIXME: FIND-CONSTANT is rife with problems. -;;; -;;; - We sometimes fail to use `(SYMBOL-VALUE ,a-defconstant) when we should, -;;; which can break some EQ tests in user code. [This is not a conformance issue, -;;; but goes against what we try so very hard to do: reference non-EQL-comparable -;;; constants only through the global symbol at load time] -;;; -;;; - We can't detect similar arrays other than BIT-VECTOR and STRING. -;;; -;;; - There is no general notion of similarity for INSTANCE, yet CORE-COALESCE-P used to -;;; return T of instances ever since git rev 45bc305be4 "refactor handling of constants". -;;; What was it trying to achieve? Maybe capture PATHNAME , HASH-TABLE and RANDOM-STATE, -;;; which are implemented as INSTANCE types, except EQUAL does not descend into -;;; any of them but PATHNAME. -;;; -;;; - What was it trying to achieve with SYMBOLS beyond the EQ test? I guess it's ok -;;; to collapse uninterned symbols by STRING=, but EQUAL won't do that. -;;; -;;; - Overall the CORE-COALESCE-P is just massively confusing. The only constants that can -;; legally be collapsed when compiling to memory are numbers. Characters would be EQ -;;; if they were EQL. Symbol and instances, as I expressed already - WTF is up with that? - -;;; I think the only way forward is twofold: -;;; - design a hash-table that correctly implements SIMILAR, -;;; - always prefer a named constant over an anonymous constant when they are similar. -;;; We'll have to do this by never coalescing a named constant with an unnamed, -;;; then postprocess the constants to remove any unnamed that are similar to -;;; a named constant that got inserted later. Minimal problem example: -#| -(defconstant +foo+ (if (boundp '+foo+) +foo+ (cons nil nil))) -;;; A-MACRO by pure coincidence expands to contain a constant that -;;; is similar to +FOO+ but not EQ to it. -(defmacro a-macro () ''(nil)) -;;; Because A-MACRO is opaque, you don't know that it injects a constant -;;; EQUAL to +FOO+. The compiler assumes that the "second" use of the same -;;; constant might as well use the value from the first occurrence, -;;; not realizing that you actually relied on the EQ-ness condition. -(defun getfoo () (values (a-macro) +foo+)) -;;; Counterintuitively, compiled (ISFOO (NTH-VALUE 1 (GETFOO))) returns NIL. -(defun isfoo (x) (eq x +foo+)) -;;; -* (load "try.lisp") -* (ISFOO (NTH-VALUE 1 (GETFOO))) => T -* (load (compile-file "try.lisp")) -* (ISFOO (NTH-VALUE 1 (GETFOO))) => NIL -|# - -;;; Return a LEAF which represents the specified constant object. If -;;; the object is not in (CONSTANTS *IR1-NAMESPACE*), then we create a new -;;; constant LEAF and enter it. If we are producing a fasl file, make sure that -;;; MAKE-LOAD-FORM gets used on any parts of the constant that it -;;; needs to be. +;;; FIXME: This logic is incomplete, lacking PACKAGE, RANDOM-STATE, +;;; SIMPLE-VECTOR, HASH-TABLE, and PATHNAME, and all arrays of rank +;;; other than 1. SIMPLE-VECTOR, PATHNAME, and possibly RANDOM-STATE, +;;; could be worthwhile to handle. +(defun coalescible-object-p (object) + (labels ((cons-coalesce-p (x) + (when (coalesce-tree-p x) + (labels ((descend (x) + (do ((y x (cdr y))) + ((atom y) (atom-colesce-p y)) + ;; Don't just call file-coalesce-p, because + ;; it'll invoke COALESCE-TREE-P repeatedly + (let ((car (car y))) + (unless (if (consp car) + (descend car) + (atom-colesce-p car)) + (return nil)))))) + (descend x)))) + (atom-colesce-p (x) + (sb-xc:typep x '(or (unboxed-array (*)) number symbol instance character)))) + (if (consp object) + (cons-coalesce-p object) + ;; Coalescing of SYMBOL, INSTANCE, CHARACTER is not useful - + ;; if OBJECT is one of those, it would only be findable in the + ;; EQL table. However, a coalescible objects with subparts + ;; may contain those. + (sb-xc:typep object '(or (unboxed-array (*)) number))))) + +;;; Return a LEAF which represents the specified constant object. ;;; ;;; We are allowed to coalesce things like EQUAL strings and bit-vectors ;;; when file-compiling, but not when using COMPILE. -(defun find-constant (object &optional (name nil namep)) - ;; Pick off some objects that aren't actually constants in user code. - ;; These things appear as literals in forms such as `(%POP-VALUES ,x) - ;; acting as a magic mechanism for passing data along. - (when (opaque-box-p object) ; quote an object without examining it - (return-from find-constant - (make-constant (opaque-box-value object) *universal-type*))) - ;; Note that we haven't picked off LAYOUT yet for two reasons: - ;; 1. layouts go in the hash-table so that a code component references - ;; any given layout at most once - ;; 2. STANDARD-OBJECT layouts use MAKE-LOAD-FORM - (let ((faslp (producing-fasl-file)) - (ns (if (boundp '*ir1-namespace*) *ir1-namespace*))) - (labels ((core-coalesce-p (x) - (sb-xc:typep x '(or symbol number character instance))) - (cons-coalesce-p (x) - (if (eq +code-coverage-unmarked+ (cdr x)) - ;; These are already coalesced, and the CAR should - ;; always be OK, so no need to check. - t - (when (coalesce-tree-p x) - (labels ((descend (x) - (do ((y x (cdr y))) - ((atom y) (atom-colesce-p y)) - ;; Don't just call file-coalesce-p, because it'll - ;; invoke COALESCE-TREE-P repeatedly - (let ((car (car y))) - (unless (if (consp car) - (descend car) - (atom-colesce-p car)) - (return nil)))))) - (descend x))))) - (atom-colesce-p (x) - (or (core-coalesce-p x) - (typep x '(or bit-vector string)))) - (file-coalesce-p (x) - ;; CLHS 3.2.4.2.2: We are also allowed to coalesce various - ;; other things when file-compiling. - (if (consp x) - (cons-coalesce-p x) - (atom-colesce-p x)))) - ;; When compiling to core we don't coalesce strings, because - ;; "The functions eval and compile are required to ensure that literal objects - ;; referenced within the resulting interpreted or compiled code objects are - ;; the _same_ as the corresponding objects in the source code." - ;; but in a dumped image, if gc_coalesce_string_literals is 1 then GC will - ;; coalesce similar immutable strings to save memory, - ;; even if not technically permitted. According to CLHS 3.7.1 - ;; "The consequences are undefined if literal objects are destructively modified - ;; For this purpose, the following operations are considered destructive: - ;; array - Storing a new value into some element of the array ..." - ;; so a string, once used as a literal in source, becomes logically immutable. - #-sb-xc-host - (when (and (not faslp) (simple-string-p object)) - (logically-readonlyize object nil)) - ;; Has this identical object been seen before? Bail out early if so. - (awhen (and ns (gethash object (eq-constants ns))) - (return-from find-constant it)) - (let* ((coalescep (and ns - (if faslp - (file-coalesce-p object) - (core-coalesce-p object)))) - (effectively-coalescible - (and coalescep - ;; No instance subtype except a pathname can be coalesced - ;; by the similarity table (as currently implemented) - (or (not (sb-xc:typep object 'instance)) - (sb-xc:typep object 'pathname))))) - (when effectively-coalescible - (dolist (candidate (gethash object (similar-constants ns))) - (when (similarp (constant-value candidate) object) - (return-from find-constant candidate)))) - (when (and faslp (not (sb-fasl:dumpable-layout-p object))) - (if namep - (maybe-emit-make-load-forms object name) - (maybe-emit-make-load-forms object))) - (let ((new (make-constant object))) - (when ns - (setf (gethash object (eq-constants ns)) new) - (when effectively-coalescible - (push new (gethash object (similar-constants ns))))) - new))))) +;;; FIXME: +;;; - EQUAL (the comparator in the similarity hash-table) is both too strict +;;; and not strict enough. Too strict because it won't compare simple-vector; +;;; not strict enough because base-string and character-string can't coalesce. +;;; We deal with this fine, but a real SIMILAR kind of hash-table would be nice. +;;; - arrays other than the handled kinds can be similar. +(defun find-constant (object &optional name + &aux (namespace (if (boundp '*ir1-namespace*) *ir1-namespace*))) + (cond + ((not (producing-fasl-file)) + ;; "The consequences are undefined if literal objects are destructively modified + ;; For this purpose, the following operations are considered destructive: + ;; array - Storing a new value into some element of the array ..." + ;; so a string, once used as a literal in source, becomes logically immutable. + #-sb-xc-host + (when (sb-xc:typep object '(simple-array * (*))) + (logically-readonlyize object nil)) + ;; "The functions eval and compile are required to ensure that literal objects + ;; referenced within the resulting interpreted or compiled code objects are + ;; the _same_ as the corresponding objects in the source code. + ;; ... + ;; The constraints on literal objects described in this section apply only to + ;; compile-file; eval and compile do not copy or coalesce constants." + ;; (http://www.lispworks.com/documentation/HyperSpec/Body/03_bd.htm) + ;; The preceding notwithstanding, numbers are always freely copyable and coalescible. + (if namespace + (values (ensure-gethash object (eql-constants namespace) (make-constant object))) + (make-constant object))) + ((if name + ;; Git rev eded4f76 added an assertion that a named non-fixnum is referenced + ;; via its name at (defconstant +share-me-4+ (* 2 most-positive-fixnum)) + ;; I'm not sure that test makes any sense, but whatever... + (sb-xc:typep object '(or fixnum character symbol)) + (sb-xc:typep object '(or number character symbol))) + (values (ensure-gethash object (eql-constants namespace) (make-constant object)))) + (t + ;; CLHS 3.2.4.2.2: We are allowed to coalesce by similarity when + ;; file-compiling. + (let ((coalescep (coalescible-object-p object))) + ;; When COALESCEP is true, the similarity table is "useful" for + ;; this object. + (if name + ;; If the constant is named, always look in the named-constants table first. + ;; This ensure that there is no chance of referring to the constant at load-time + ;; through an access path other than `(SYMBOL-GLOBAL-VALUE ,name). + (ensure-gethash name + (named-constants namespace) + (make-constant object (ctype-of object) name)) + ;; If the constant is anonymous, just make a new constant + ;; unless it is EQL or similar to an existing leaf. + (or (gethash object (eql-constants namespace)) + (and coalescep + (get-similar object (similar-constants namespace))) + (let ((new (make-constant object))) + (setf (gethash object (eql-constants namespace)) new) + (when coalescep + (setf (get-similar object (similar-constants namespace)) new)) + new))))))) ;;; Return true if X and Y are lvars whose only use is a ;;; reference to the same leaf, and the value of the leaf cannot @@ -2588,8 +2500,8 @@ is :ANY, the function name is not checked." (declare (type exit exit)) (let* ((entry (exit-entry exit)) (cleanup (entry-cleanup entry)) - (block (first (block-succ (node-block exit))))) - (dolist (nlx (physenv-nlx-info (node-physenv entry)) nil) + (block (first (block-succ (node-block exit))))) + (dolist (nlx (environment-nlx-info (node-environment entry)) nil) (when (and (eq (nlx-info-block nlx) block) (eq (nlx-info-cleanup nlx) cleanup)) (return nlx))))) @@ -2788,38 +2700,29 @@ is :ANY, the function name is not checked." (let ((info (basic-combination-fun-info call))) (and (not (fun-info-ir2-convert info)) + (not (fun-info-ltn-annotate info)) (dolist (template (fun-info-templates info) t) (when (eq (template-ltn-policy template) :fast-safe) (multiple-value-bind (val win) - (valid-fun-use call (template-type template)) + (valid-fun-use call (template-type template)) (when (or val (not win)) (return nil))))))))))) ;;;; careful call ;;; Apply a function to some arguments, returning a list of the values ;;; resulting of the evaluation. If an error is signalled during the -;;; application, then we produce a warning message using WARN-FUN and -;;; return NIL as our second value to indicate this. NODE is used as -;;; the error context for any error message, and CONTEXT is a string -;;; that is spliced into the warning. -(declaim (ftype (sfunction ((or symbol function) list node function string) - (values list boolean)) +;;; application, then return the condition and NIL as the +;;; second value. +(declaim (ftype (sfunction ((or symbol function) list) + (values t boolean)) careful-call)) -(defun careful-call (function args node warn-fun context) - (declare (ignorable node warn-fun context)) - ;; When cross-compiling, being "careful" is the wrong thing - our code should - ;; not allowed malformed or out-of-order definitions to proceed as if all is well. - #+sb-xc-host - (values (multiple-value-list (apply function args)) t) - #-sb-xc-host - (values - (multiple-value-list - (handler-case (apply function args) - (error (condition) - (let ((*compiler-error-context* node)) - (funcall warn-fun "Lisp error during ~A:~%~A" context condition) - (return-from careful-call (values nil nil)))))) - t)) +(defun careful-call (function args) + (handler-case (values (multiple-value-list (apply function args)) t) + ;; When cross-compiling, being "careful" is the wrong thing - our code should + ;; not allowed malformed or out-of-order definitions to proceed as if all is well. + #-sb-xc-host + (error (condition) + (values condition nil)))) ;;; Variations of SPECIFIER-TYPE for parsing possibly wrong ;;; specifiers. @@ -3000,6 +2903,7 @@ is :ANY, the function name is not checked." ;;; from system lambdas. (defun preserve-single-use-debug-var-p (call var) (and (policy call (eql preserve-single-use-debug-variables 3)) + (not (lambda-var-specvar var)) (or (not (lambda-var-p var)) (not (lambda-system-lambda-p (lambda-var-home var)))))) @@ -3137,7 +3041,7 @@ is :ANY, the function name is not checked." (defun propagate-lvar-annotations (new old &optional (propagate-dependencies t)) (when propagate-dependencies (loop for dep in (lvar-dependent-annotations old) - do (nsubst new old (lvar-function-designator-annotation-deps dep)) + do (nsubst new old (lvar-dependent-annotation-deps dep)) when (lvar-p new) do (pushnew dep (lvar-dependent-annotations new) :test #'eq)) @@ -3207,6 +3111,15 @@ is :ANY, the function name is not checked." (values :calls constants))))))))) (defun process-lvar-modified-annotation (lvar annotation) + (loop for annot in (lvar-annotations lvar) + when (lvar-lambda-var-annotation-p annot) + do (let ((lambda-var (lvar-lambda-var-annotation-lambda-var annot))) + (when (and (lambda-var-constant lambda-var) + (not (lambda-var-sets lambda-var))) + (warn 'sb-kernel::macro-arg-modified + :fun-name (lvar-modified-annotation-caller annotation) + :variable (lambda-var-original-name lambda-var)) + (return-from process-lvar-modified-annotation)))) (multiple-value-bind (type values) (lvar-constants lvar) (labels ((modifiable-p (value) (or (consp value) @@ -3228,23 +3141,26 @@ is :ANY, the function name is not checked." (report values))) t))))) +(defun improper-sequence-p (annotation value) + (case annotation + (proper-list + (and (listp value) + (not (proper-list-p value)))) + (proper-sequence + (and (typep value 'sequence) + (not (proper-sequence-p value)))) + (proper-or-circular-list + (and (listp value) + (not (proper-or-circular-list-p value)))) + (proper-or-dotted-list + (and (listp value) + (not (proper-or-dotted-list-p value)))))) + (defun process-lvar-proper-sequence-annotation (lvar annotation) (multiple-value-bind (type values) (lvar-constants lvar) (let ((kind (lvar-proper-sequence-annotation-kind annotation))) (labels ((bad-p (value) - (case kind - (proper-list - (and (listp value) - (not (proper-list-p value)))) - (proper-sequence - (and (typep value 'sequence) - (not (proper-sequence-p value)))) - (proper-or-circular-list - (and (listp value) - (not (proper-or-circular-list-p value)))) - (proper-or-dotted-list - (and (listp value) - (not (proper-or-dotted-list-p value)))))) + (improper-sequence-p kind value)) (report (values) (when (every #'bad-p values) (if (singleton-p values) @@ -3289,29 +3205,42 @@ is :ANY, the function name is not checked." 'slot-initform-type-style-warning (return-from process-lvar-type-annotation))) (t - 'sb-int:type-warning))) - (type (lvar-type-annotation-type annotation))) + 'type-warning))) + (type (lvar-type-annotation-type annotation)) + (dest (lvar-dest lvar))) (cond ((not (types-equal-or-intersect (lvar-type lvar) type)) (%compile-time-type-error-warn annotation (type-specifier type) (type-specifier (lvar-type lvar)) - (lvar-all-sources lvar) + (let ((path (lvar-annotation-source-path annotation))) + (list + (if (eq (car path) 'original-source-start) + (find-original-source path) + (car path)))) :condition condition)) ((consp uses) - (loop for use in uses - for dtype = (node-derived-type use) - unless (values-types-equal-or-intersect dtype type) - do (%compile-time-type-error-warn annotation - (type-specifier type) - (type-specifier dtype) - (list (node-source-form use)) - :condition condition)))))) + (let ((condition (case condition + (type-warning 'type-style-warning) + (t condition)))) + (loop for use in uses + for dtype = (node-derived-type use) + unless (or (cast-mismatch-from-inlined-p dest use) + (values-types-equal-or-intersect dtype type)) + do (%compile-time-type-error-warn use + (type-specifier type) + (type-specifier dtype) + (list (node-source-form use)) + :condition condition))))))) + +(defun process-lvar-sequence-bounds-annotation (lvar annotation) + (destructuring-bind (start end) (lvar-dependent-annotation-deps annotation) + (check-sequence-ranges lvar start end annotation))) (defun process-annotations (lvar) (unless (and (combination-p (lvar-dest lvar)) (lvar-fun-is (combination-fun (lvar-dest lvar)) ;; KLUDGE: after some type derivation and merging with other types - ;; a path can be emerge which is erronous and has a bad constant, + ;; a path can emerge which is erronous and has a bad constant, ;; but another value can still be good. ;; see compiler.pure/generate-type-checks-on-dead-blocks '(%type-check-error %type-check-error/c))) @@ -3331,13 +3260,19 @@ is :ANY, the function name is not checked." (lvar-function-annotation (check-function-lvar lvar annot)) (lvar-type-annotation - (process-lvar-type-annotation lvar annot))) + (process-lvar-type-annotation lvar annot)) + (lvar-sequence-bounds-annotation + (process-lvar-sequence-bounds-annotation lvar annot))) (setf (lvar-annotation-fired annot) t)))))) (defun add-annotation (lvar annotation) (unless (eq (lvar-annotations lvar) (pushnew annotation (lvar-annotations lvar) :key #'type-of)) + (when (typep annotation 'lvar-dependent-annotation) + (loop for lvar in (lvar-dependent-annotation-deps annotation) + when (lvar-p lvar) + do (push annotation (lvar-dependent-annotations lvar)))) (unless (lvar-annotation-source-path annotation) (setf (lvar-annotation-source-path annotation) (if (boundp '*current-path*) diff --git a/src/compiler/ir2opt.lisp b/src/compiler/ir2opt.lisp index 3a5030f2a0..d508ceb0c0 100644 --- a/src/compiler/ir2opt.lisp +++ b/src/compiler/ir2opt.lisp @@ -19,8 +19,8 @@ ;;; For blocks it's a cons with (pred . succ) ;;; For labels it maps to the label block (defvar *2block-info*) -(defmacro vop-predecessors (vop) `(car (gethash ,vop *2block-info*))) -(defmacro vop-successors (vop) `(cdr (gethash ,vop *2block-info*))) +(defmacro ir2block-predecessors (x) `(car (gethash (the ir2-block ,x) *2block-info*))) +(defmacro ir2block-successors (x) `(cdr (gethash (the ir2-block ,x) *2block-info*))) (defun initialize-ir2-blocks-flow-info (component) (labels ((block-last-2block (block) @@ -67,7 +67,7 @@ (remove 2block (car info))))) (setf (cdr info) succ) (dolist (new succ) - (pushnew 2block (vop-predecessors new)))))) + (pushnew 2block (ir2block-predecessors new)))))) ;;;; Conditional move insertion support code (defun move-value-target (2block) @@ -91,24 +91,51 @@ (defun cmovp (label a b) (declare (type label label) (type cblock a b)) - (cond ((eq label (ir2-block-%label (block-info a)))) - ((eq label (ir2-block-%label (block-info b))) - (rotatef a b)) - (t (return-from cmovp))) - (let ((succ-a (block-succ a)) - (succ-b (block-succ b))) - (when (and (singleton-p succ-a) - (singleton-p succ-b) - (eq (car succ-a) (car succ-b)) - (singleton-p (block-pred a)) - (singleton-p (block-pred b))) - (multiple-value-bind (value-a target) - (move-value-target (block-info a)) - (multiple-value-bind (value-b targetp) - (move-value-target (block-info b)) - (and value-a value-b (eq target targetp) - (values (block-label (car succ-a)) - target value-a value-b))))))) + (let ((a2 (block-info a)) + (b2 (block-info b))) + (cond ((eq label (ir2-block-%label a2))) + ((eq label (ir2-block-%label b2)) + (rotatef a b) + (rotatef a2 b2)) + (t (return-from cmovp))) + (let ((succ-a (block-succ a)) + (succ-b (block-succ b))) + (cond ((and (singleton-p succ-a) + (singleton-p succ-b) + (eq (car succ-a) (car succ-b)) + (singleton-p (block-pred a)) + (singleton-p (block-pred b))) + (multiple-value-bind (value-a target) + (move-value-target a2) + (multiple-value-bind (value-b targetp) + (move-value-target b2) + (and value-a value-b (eq target targetp) + (values (block-label (car succ-a)) + target value-a value-b))))) + ;; A branch jumping over a move. + ((and (singleton-p succ-a) + (singleton-p (block-pred a)) + (equal (car succ-a) + b)) + (multiple-value-bind (value target) + (move-value-target a2) + (when value + (values (block-label b) + target value target)))) + ((and (singleton-p succ-b) + (singleton-p (block-pred b)) + (equal (car succ-b) + a)) + (multiple-value-bind (value target) + (move-value-target b2) + (when value + (values (block-label a) + target target value)))))))) + +#-x86-64 +(defun sb-vm::computable-from-flags-p (res x y flags) + (declare (ignorable res x y flags)) + nil) ;; To convert a branch to a conditional move: ;; 1. Convert both possible values to the chosen common representation @@ -122,13 +149,28 @@ target res flags info label - vop node 2block) - (let ((prev (vop-prev vop))) - (delete-vop vop) - (flet ((reuse-if-eq-arg (value-if vop) + vop node 2block + &aux (prev (vop-prev vop))) + (delete-vop vop) + (let ((last (ir2-block-last-vop 2block))) + (when (and last + (eq (vop-name last) 'branch)) + (delete-vop last))) + (cond + ((and (constant-tn-p arg-if) + (constant-tn-p arg-else) + (sb-vm::computable-from-flags-p + res (tn-value arg-if) (tn-value arg-else) flags)) + (emit-template node 2block (template-or-lose 'sb-vm::compute-from-flags) + (reference-tn-list (list arg-if arg-else) nil) + (reference-tn res t) + (list* flags info))) + (t + (flet ((reuse-if-eq-arg (value-if vop) ;; Most of the time this means: ;; if X is already NIL, don't load it again. - (when (and (eq (vop-name vop) 'if-eq) + (when (and vop + (eq (vop-name vop) 'if-eq) (constant-tn-p value-if)) (let* ((args (vop-args vop)) (x-tn (tn-ref-tn args)) @@ -139,84 +181,74 @@ (eq (tn-primitive-type x-tn) (tn-primitive-type res))) x-tn)))) - (load-and-coerce (dst src) + (load-and-coerce (dst src) (when (and dst (neq dst src)) (emit-and-insert-vop node 2block (template-or-lose 'move) (reference-tn src nil) (reference-tn dst t) (ir2-block-last-vop 2block))))) - (let ((reuse (reuse-if-eq-arg value-if prev))) - (if reuse - (setf arg-if reuse) - (load-and-coerce arg-if value-if))) - (load-and-coerce arg-else value-else)) - (emit-template node 2block (template-or-lose cmove-vop) - (reference-tn-list (remove nil (list arg-if arg-else)) - nil) - (reference-tn res t) - (list* flags info)) + (let ((reuse (reuse-if-eq-arg value-if prev))) + (if reuse + (setf arg-if reuse) + (load-and-coerce arg-if value-if))) + (load-and-coerce arg-else value-else)) + (emit-template node 2block (template-or-lose cmove-vop) + (reference-tn-list (remove nil (list arg-if arg-else)) + nil) + (reference-tn res t) + (list* flags info)))) (emit-move node 2block res target) (vop branch node 2block label) - (update-block-succ 2block (list label)))) - -;; Since conditional branches are always at the end of blocks, -;; it suffices to look at the last VOP in each block. -(defun maybe-convert-one-cmov (2block) - (let ((vop (or (ir2-block-last-vop 2block) - (return-from maybe-convert-one-cmov)))) - (unless (eq (vop-name vop) 'branch-if) - (return-from maybe-convert-one-cmov)) - ;; The test and branch-if may be split between two IR1 blocks - ;; due to cleanups, can't use bloc-succ of the ir2-block-block - (let* ((node (vop-node vop)) - (succ (block-succ (node-block node))) - (a (first succ)) - (b (second succ))) - - (destructuring-bind (jump-target not-p flags) (vop-codegen-info vop) - (multiple-value-bind (label target value-a value-b) - (cmovp jump-target a b) - (unless label + (update-block-succ 2block (list label))) + +(defun maybe-convert-one-cmov (vop) + ;; The test and branch-if may be split between two IR1 blocks + ;; due to cleanups, can't use bloc-succ of the ir2-block-block + (let* ((node (vop-node vop)) + (succ (block-succ (node-block node))) + (a (first succ)) + (b (second succ))) + + (destructuring-bind (jump-target not-p flags) (vop-codegen-info vop) + (multiple-value-bind (label target value-a value-b) + (cmovp jump-target a b) + (unless label + (return-from maybe-convert-one-cmov)) + (multiple-value-bind (cmove-vop arg-a arg-b res info) + (convert-conditional-move-p node target value-a value-b) + (unless cmove-vop (return-from maybe-convert-one-cmov)) - (multiple-value-bind (cmove-vop arg-a arg-b res info) - (convert-conditional-move-p node target value-a value-b) - (unless cmove-vop - (return-from maybe-convert-one-cmov)) - (when not-p - (rotatef value-a value-b) - (rotatef arg-a arg-b)) - (flet ((safe-coercion-p (from to) - (let ((from (tn-primitive-type from)) - (to (tn-primitive-type to))) - ;; These moves will be repositioned before the test VOP, - ;; which may be restricting their type. - ;; Avoid the moves that may touch memory and - ;; thus fail on immediate values. - (not (and (eq from *backend-t-primitive-type*) - (memq (primitive-type-name to) - '(#+64-bit sb-vm::unsigned-byte-64 - #+64-bit sb-vm::unsigned-byte-63 - #+64-bit sb-vm::signed-byte-64 - #-64-bit sb-vm::unsigned-byte-32 - #-64-bit sb-vm::unsigned-byte-31 - #-64-bit sb-vm::signed-byte-32 - #-64-bit single-float - double-float - complex-single-float - complex-double-float - system-area-pointer))))))) - (if (and (safe-coercion-p value-a arg-a) + (when not-p + (rotatef value-a value-b) + (rotatef arg-a arg-b)) + (flet ((safe-coercion-p (from to) + (let ((from (tn-primitive-type from)) + (to (tn-primitive-type to))) + ;; These moves will be repositioned before the test VOP, + ;; which may be restricting their type. + ;; Avoid the moves that may touch memory and + ;; thus fail on immediate values. + (not (and (eq from *backend-t-primitive-type*) + (memq (primitive-type-name to) + '(#+64-bit sb-vm::unsigned-byte-64 + #+64-bit sb-vm::unsigned-byte-63 + #+64-bit sb-vm::signed-byte-64 + #-64-bit sb-vm::unsigned-byte-32 + #-64-bit sb-vm::unsigned-byte-31 + #-64-bit sb-vm::signed-byte-32 + #-64-bit single-float + double-float + complex-single-float + complex-double-float + system-area-pointer))))))) + (when (and (safe-coercion-p value-a arg-a) (safe-coercion-p value-b arg-b)) - (convert-one-cmov cmove-vop value-a arg-a - value-b arg-b - target res - flags info - label vop node 2block))))))))) - -(defun convert-cmovs (component) - (do-ir2-blocks (2block component (values)) - (maybe-convert-one-cmov 2block))) + (convert-one-cmov cmove-vop value-a arg-a + value-b arg-b + target res + flags info + label vop node (vop-block vop))))))))) (defun delete-unused-ir2-blocks (component) (declare (type component component)) @@ -283,76 +315,87 @@ (let ((x (tn-ref-tn args)) (y (tn-ref-tn results))) (when (location= x y) - (delete-vop vop))))))))) + (delete-vop vop) + ;; Deleting the copy may make it look like that register + ;; is not used anywhere else and some optimizations, + ;; like combine-instructions, may incorrectly trigger. + ;; FIXME: these tn-refs never go away, so things like + ;; combine-instructions should use a different mechanism + ;; for checking writes/reads. + (let ((x-reads (tn-reads x)) + (x-writes (tn-writes x))) + (when (tn-reads y) + (reference-tn x nil)) + (when (tn-writes y) + (reference-tn x t)) + (when x-reads + (reference-tn y nil)) + (when x-writes + (reference-tn y t))))))))))) ;;; Unchain BRANCHes that jump to a BRANCH. ;;; Remove BRANCHes that are jumped over by BRANCH-IF ;;; Should be run after DELETE-NO-OP-VOPS, otherwise the empty moves ;;; will interfere. - -;;; FIXME: there is one more minor glitch caused by multiway branch, -;;; but it is not a correctness bug. Consider: -;;; (defun f (&optional (a (missing-arg)) (b (missing-arg)) -;;; (c (missing-arg)) (d (missing-arg))) -;;; (list a b c d )) -;;; -;;; Granted that this is a slightly weird idiom, but it is used frequently -;;; in system internals as well as by FORMATTER's macroexpansion. -;;; The main entry point dispatches on the argument count. -;;; After elimination of redundant moves, we end up with: -;;; ; DF2: 42FF2498 JMP QWORD PTR [RAX+R11*4] -;;; ; DF6: E981000000 JMP L3 -;;; ; DFB: E999000000 JMP L4 -;;; ; E00: E9B1000000 JMP L5 -;;; ; E05: E9C9000000 JMP L6 -;;; where every one of the jumps to a label is unreachable. -;;; This is because each of the original IF's would have branched -;;; to two MOVEs that are eliminated as the arg/results get packed -;;; in the same physical location, and then the branch is performed, -;;; but it is in a dead IR2 block. (defun ir2-optimize-jumps (component) - (flet ((start-vop (block) - (do ((block block (ir2-block-next block))) - ((null block) nil) - (let ((vop (ir2-block-start-vop block))) - (when vop - (if (eq (vop-name vop) 'sb-c:note-environment-start) - (let ((next (vop-next vop))) - (when next - (return next))) - (return vop)))))) - (next-label (block) - (do ((block (ir2-block-next block) - (ir2-block-next block))) - ((null block) nil) - (let ((label (or (ir2-block-%trampoline-label block) - (ir2-block-%label block)))) - (cond (label - (return label)) - ((ir2-block-start-vop block) - (return nil))))))) - ;; This is the same information as in *2block-info*. "Too Many Cooks" - ;; (Well, the *2block-info* is gone at this point) - (let ((label-block-map (make-hash-table :test #'eq))) - (do-ir2-blocks (block component) - (setf (gethash (ir2-block-%trampoline-label block) label-block-map) - block) - (setf (gethash (ir2-block-%label block) label-block-map) - block)) + (let ((*2block-info* (make-hash-table :test #'eq))) + (initialize-ir2-blocks-flow-info component) + (flet ((start-vop (block) + (do ((block block (ir2-block-next block))) + ((or + (null block) + (not (singleton-p (ir2block-predecessors block)))) nil) + (let ((vop (ir2-block-start-vop block))) + (when vop + (if (eq (vop-name vop) 'sb-c:note-environment-start) + (let ((next (vop-next vop))) + (when next + (return next))) + (return vop)))))) + (delete-chain (block) + (do ((block block (ir2-block-next block))) + ((null block) nil) + ;; Just pop any block, *2block-info* is only used here + ;; and it just needs to know the number of predecessors, + ;; not their identity. + (pop (ir2block-predecessors block)) + (if (ir2block-predecessors block) + (return) + (let ((vop (ir2-block-start-vop block))) + (when vop + (when (eq (vop-name vop) 'sb-c:note-environment-start) + (setf vop (vop-next vop))) + (when vop + (aver (eq (vop-name vop) 'branch)) + (delete-vop vop) + (return t))))))) + (next-label (block) + (do ((block (ir2-block-next block) + (ir2-block-next block))) + ((null block) nil) + (let ((label (or (ir2-block-%trampoline-label block) + (ir2-block-%label block)))) + (cond (label + (return label)) + ((ir2-block-start-vop block) + (return nil))))))) (labels ((unchain-jumps (vop) ;; Handle any branching vop except a multiway branch (setf (first (vop-codegen-info vop)) (follow-jumps (first (vop-codegen-info vop))))) - (follow-jumps (target-label) + (follow-jumps (target-label &optional (delete t)) (declare (type label target-label)) - (let* ((target-block (gethash target-label label-block-map)) + (let* ((target-block (gethash target-label *2block-info*)) (target-vop (start-vop target-block))) - (if (and target-vop - (eq (vop-name target-vop) 'branch) - (neq (first (vop-codegen-info target-vop)) - target-label)) - (follow-jumps (first (vop-codegen-info target-vop))) - target-label))) + (cond ((and target-vop + (eq (vop-name target-vop) 'branch) + (neq (first (vop-codegen-info target-vop)) + target-label)) + (when delete + (setf delete (delete-chain target-block))) + (follow-jumps (first (vop-codegen-info target-vop)) delete)) + (t + target-label)))) (remove-jump-overs (branch-if branch) ;; Turn BRANCH-IF #<L1>, BRANCH #<L2>, L1: ;; into BRANCH-IF[NOT] L2 @@ -374,27 +417,34 @@ ;; should take the label of the latter. (do-ir2-blocks (block component) (let ((last (ir2-block-last-vop block))) - (case (and last (vop-name last)) - (branch - (unchain-jumps last) - ;; A block may end up having BRANCH-IF + BRANCH after converting an IF. - ;; Multiway can't coexist with any other branch preceding or following - ;; in the block, so we don't have to check for that, just a BRANCH-IF. - (let ((prev (vop-prev last))) - (when (and prev - (or (eq (vop-name prev) 'branch-if) - (conditional-p prev))) - (unchain-jumps prev)))) - (branch-if - (unchain-jumps last)) - (multiway-branch-if-eq - ;; codegen-info = (labels else-label key-type keys original-comparator) - (let ((info (vop-codegen-info last))) - (setf (car info) (mapcar #'follow-jumps (car info)) - (cadr info) (follow-jumps (cadr info))))) - (t - (when (and last (conditional-p last)) - (unchain-jumps last)))))) + (when last + (case (vop-name last) + (branch + (unchain-jumps last) + ;; A block may end up having BRANCH-IF + BRANCH after converting an IF. + ;; Multiway can't coexist with any other branch preceding or following + ;; in the block, so we don't have to check for that, just a BRANCH-IF. + (let ((prev (vop-prev last))) + (when (and prev + (or (eq (vop-name prev) 'branch-if) + (conditional-p prev))) + (unchain-jumps prev)))) + (branch-if + (unchain-jumps last)) + (multiway-branch-if-eq + ;; codegen-info = (labels else-label key-type keys original-comparator) + (let ((info (vop-codegen-info last))) + ;; Don't delete the branches when they reach zero + ;; predecessors as multiway-branch-if-eq inserts + ;; extra jumps which are not in the original ir2 + ;; and do not correspond to any predecessors. + (setf (car info) (mapcar (lambda (x) + (follow-jumps x nil)) + (car info)) + (cadr info) (follow-jumps (cadr info) nil)))) + (t + (when (conditional-p last) + (unchain-jumps last))))))) ;; Pass 2 ;; Need to unchain the jumps before handling jump-overs, ;; otherwise the BRANCH over which BRANCH-IF jumps may be a @@ -421,16 +471,34 @@ (defun next-vop (vop) (or (vop-next vop) - (let ((next-block (ir2-block-next (vop-block vop)))) - (and (not (or (ir2-block-%trampoline-label next-block) - (ir2-block-%label next-block))) - (ir2-block-start-vop next-block))))) + (do ((2block (ir2-block-next (vop-block vop)) + (ir2-block-next 2block))) + ((null 2block) nil) + (cond ((or (ir2-block-%trampoline-label 2block) + (ir2-block-%label 2block)) + (return)) + ((ir2-block-start-vop 2block) + (return (ir2-block-start-vop 2block))))))) + +(defun prev-vop (vop) + (or (vop-prev vop) + (do* ((2block (vop-block vop) prev) + (prev (ir2-block-prev 2block) + (ir2-block-prev 2block))) + ((null prev) nil) + (cond ((or (ir2-block-%trampoline-label 2block) + (ir2-block-%label 2block)) + (return)) + ((ir2-block-last-vop prev) + (return (ir2-block-last-vop prev))))))) (defun immediate-templates (fun &optional (constants t)) (let ((primitive-types (list (primitive-type-or-lose 'character) (primitive-type-or-lose 'fixnum) (primitive-type-or-lose 'sb-vm::positive-fixnum) + #-x86 ;; i387 is weird (primitive-type-or-lose 'double-float) + #-x86 (primitive-type-or-lose 'single-float) . #+(or 64-bit 64-bit-registers) @@ -482,43 +550,124 @@ args1) args2))) -;;; Turn CMP X,Y BRANCH-IF M CMP X,Y BRANCH-IF N -;;; into CMP X,Y BRANCH-IF M BRANCH-IF N -;; while it's portable the VOPs are not validated for -;; compatibility on other backends yet. -#+(or arm arm64 x86 x86-64) (defoptimizer (vop-optimize branch-if) (branch-if) - (let ((prev (vop-prev branch-if))) - (when (and prev - (memq (vop-name prev) *comparison-vops*)) - (let ((next (next-vop branch-if)) - transpose) - (when (and next - (memq (vop-name next) *comparison-vops*) - (or (vop-args-equal prev next) - (and (or (setf transpose - (memq (vop-name prev) *commutative-comparison-vops*)) - (memq (vop-name next) *commutative-comparison-vops*)) - (vop-args-equal prev next t)))) - (when transpose - ;; Could flip the flags for non-commutative operations - (loop for tn-ref = (vop-args prev) then (tn-ref-across tn-ref) - for arg in (nreverse (vop-arg-list prev)) - do (change-tn-ref-tn tn-ref arg))) - (delete-vop next)))))) + (cond ((boundp '*2block-info*) + (maybe-convert-one-cmov branch-if)) + #+(or arm arm64 x86 x86-64) + (t + ;; Turn CMP X,Y BRANCH-IF M CMP X,Y BRANCH-IF N + ;; into CMP X,Y BRANCH-IF M BRANCH-IF N + ;; Run it after CMOVs are converted. + ;; While it's portable the VOPs are not validated for + ;; compatibility on other backends yet. + (let ((prev (vop-prev branch-if))) + (when (and prev + (memq (vop-name prev) *comparison-vops*)) + (let ((next (next-vop branch-if)) + transpose) + (when (and next + (memq (vop-name next) *comparison-vops*) + (or (vop-args-equal prev next) + (and (or (setf transpose + (memq (vop-name prev) *commutative-comparison-vops*)) + (memq (vop-name next) *commutative-comparison-vops*)) + (vop-args-equal prev next t)))) + (when transpose + ;; Could flip the flags for non-commutative operations + (loop for tn-ref = (vop-args prev) then (tn-ref-across tn-ref) + for arg in (nreverse (vop-arg-list prev)) + do (change-tn-ref-tn tn-ref arg))) + (setf (sb-assem::label-comment (car (vop-codegen-info branch-if))) + :merged-ifs) + (delete-vop next)))))))) (defun next-start-vop (block) - (loop for 2block = block then (ir2-block-next 2block) - while (and 2block - (= (length (vop-predecessors 2block)) 1)) - when (ir2-block-start-vop 2block) return it)) + (loop thereis (ir2-block-start-vop block) + while (and (= (length (ir2block-predecessors block)) 1) + (setf block (ir2-block-next block))))) (defun branch-destination (branch &optional (true t)) - (destructuring-bind (label not-p flags) (vop-codegen-info branch) - (declare (ignore flags)) + (unless (vop-codegen-info branch) + (let ((next (vop-next branch))) + (if (and next + (eq (vop-name next) 'branch-if)) + (setf branch next) + (return-from branch-destination)))) + (destructuring-bind (label not-p &rest rest) (vop-codegen-info branch) + (declare (ignore rest)) (if (eq not-p true) - (next-start-vop (ir2-block-next (vop-block branch))) - (next-start-vop (gethash label *2block-info*))))) + (if (eq branch (ir2-block-last-vop (vop-block branch))) + (next-start-vop (ir2-block-next (vop-block branch))) + (let ((next (next-vop branch))) + (and (eq (vop-name next) 'branch) + (next-start-vop (gethash (car (vop-codegen-info next)) *2block-info*))))) + (let ((dest (gethash label *2block-info*))) + (when dest + (next-start-vop dest)))))) + +;;; Replace (BOUNDP X) + (BRANCH-IF) + {(SYMBOL-VALUE X) | anything} +;;; by (FAST-SYMBOL-VALUE X) + (UNBOUND-MARKER-P) + BRANCH-IF +;;; and delete SYMBOL-VALUE, with the result of FAST-SYMBOL-VALUE flowing +;;; into the same TN as symbol-value's result. +;;; This is a valid substitution on any of the architectures, but +;;; it requires that UNBOUND-MARKER-P return its result in a flag, +;;; so presently is enabled only for x86-64. +#+x86-64 +(defoptimizer (vop-optimize boundp) (vop) + (let ((sym (tn-ref-tn (vop-args vop))) + (next (vop-next vop))) + (unless (and (boundp '*2block-info*) + next (eq (vop-name next) 'branch-if)) + (return-from vop-optimize-boundp-optimizer nil)) + ;; Only replace if the BOUNDP=T consequent starts with SYMBOL-VALUE so that + ;; a bad example such as (IF (BOUNDP '*FOO*) (PRINT 'HI) *FOO*) + ;; - which has SYMBOL-VALUE as the wrong consequent of the IF - is unaffected. + (let* ((successors (ir2block-successors (vop-block next))) + (info (vop-codegen-info next)) + (label-block (gethash (car info) *2block-info*)) + (symbol-value-vop + (ir2-block-start-vop + (cond ((eq (second info) nil) label-block) ; not negated test. + ;; When negated, the BOUNDP case goes to the "other" successor + ;; block, i.e. whichever is not started by the #<label>. + ((eq label-block (first successors)) (second successors)) + (t (first successors)))))) + (when (and symbol-value-vop + (or (eq (vop-name symbol-value-vop) 'symbol-value) + ;; Expect SYMBOL-GLOBAL-VALUE only for variables of kind :GLOBAL. + (and (eq (vop-name symbol-value-vop) 'symbol-global-value) + (constant-tn-p sym) + (eq (info :variable :kind (tn-value sym)) :global))) + (eq sym (tn-ref-tn (vop-args symbol-value-vop))) + ;; If the symbol is either a compile-time known symbol, + ;; or can only be the same thing for both vops, + ;; then we're fine to combine. + (or (constant-tn-p sym) + (not (tn-writes sym)) + (not (tn-ref-next (tn-writes sym)))) + ;; Elide the SYMBOL-VALUE only if there is exactly one way to get there. + ;; Technically we could split the IR2 block and peel off the SYMBOL-VALUE, + ;; and if coming from the BRANCH-IF, jump to the block that contained + ;; everything else except the SYMBOL-VALUE vop. + (not (cdr (ir2block-predecessors (vop-block symbol-value-vop))))) + (let ((replacement (if (eq (vop-name symbol-value-vop) 'symbol-global-value) + 'fast-symbol-global-value + 'fast-symbol-value)) + (result-tn (tn-ref-tn (vop-results symbol-value-vop)))) + (emit-and-insert-vop (vop-node vop) (vop-block vop) + (template-or-lose replacement) + (reference-tn sym nil) (reference-tn result-tn t) next) + (emit-and-insert-vop (vop-node vop) (vop-block vop) + (template-or-lose 'unbound-marker-p) + (reference-tn result-tn nil) nil next) + ;; We need to invert the test since BOUNDP and UNBOUND-MARKER-P have + ;; the opposite meaning in the language. But by chance, they specify + ;; opposite flags in the vop, which means that the sense of the + ;; BRANCH-IF test is automagically correct after substitution. + ;; Of course, this is machine-dependent. + (delete-vop vop) + (delete-vop symbol-value-vop) + next))))) ;;; Optimize (if x ... nil) to reuse the NIL coming from X. (defoptimizer (vop-optimize if-eq) (if-eq) @@ -529,16 +678,21 @@ (let* ((args (vop-args if-eq)) (x (tn-ref-tn args)) (y (tn-ref-tn (tn-ref-across args)))) - (when (constant-tn-p y) - (let ((move (branch-destination branch-if))) - (when (and move - (eq (vop-name move) 'move)) - (let* ((args (vop-args move)) - (from (tn-ref-tn args))) - (when (and (constant-tn-p from) - (eq (tn-leaf y) - (tn-leaf from))) - (change-tn-ref-tn args x)))))) + (flet ((constant-p (x) + (or (constant-tn-p x) + (type= (tn-type x) + (specifier-type 'null))))) + (when (constant-p y) + (let ((move (branch-destination branch-if))) + (when (and move + (eq (vop-name move) 'move) + (singleton-p (ir2block-predecessors (vop-block move)))) + (let* ((args (vop-args move)) + (from (tn-ref-tn args))) + (when (and (constant-p from) + (eq (tn-leaf y) + (tn-leaf from))) + (change-tn-ref-tn args x))))))) nil))))) ;;; If 2BLOCK ends in an IF-EQ (or similar) + BRANCH-IF where the second operand @@ -647,7 +801,7 @@ (tn-value (tn-ref-tn (tn-ref-across (vop-args conditional)))) ;; "-eq-/C" vops take a codegen arg (car (vop-codegen-info conditional)))) - (else-block-predecessors (vop-predecessors else-block)) + (else-block-predecessors (ir2block-predecessors else-block)) (else-vop (ir2-block-start-vop else-block))) (push (cons val then-block) chain) ;; If ELSE block has more than one predecessor, that's OK, @@ -697,7 +851,7 @@ (let ((values (mapcar #'car choices))) (cond ((every #'fixnump values)) ; ok ((every #'characterp values) - (setq values (mapcar #'sb-xc:char-code values))) + (setq values (mapcar #'char-code values))) (t (return-from should-use-jump-table-p nil))) (let* ((min (reduce #'min values)) @@ -738,7 +892,7 @@ (destructuring-bind (clauses else-block test-vop-name) culled-chain (let* ((key-type (if (characterp (caar clauses)) 'character 'fixnum)) (clause-keyfn (if (eq key-type 'character) - (lambda (x) (sb-xc:char-code (car x))) + (lambda (x) (char-code (car x))) #'car)) ;; Sort and unzip the alist (ordered (sort (copy-list clauses) #'< :key clause-keyfn)) @@ -825,20 +979,327 @@ (vop-codegen-info vop)) (delete-vop vop))))) +#+(or arm64 x86-64) +(defoptimizer (vop-optimize #+arm64 + (sb-vm::data-vector-ref/simple-bit-vector-c + sb-vm::data-vector-ref/simple-bit-vector) + #+x86-64 + (sb-vm::data-vector-ref-with-offset/simple-bit-vector-c + sb-vm::data-vector-ref-with-offset/simple-bit-vector)) + (vop) + (let* ((next (next-vop vop)) + (branch (and next + (next-vop next))) + plusp) + (when (and branch + (or + (eq (vop-name next) #+x86-64 'sb-vm::fast-if-eq-fixnum/c + #+arm64 'sb-vm::fast-if-eq-integer/c) + (and (eq (vop-name next) + #-arm64 'sb-vm::fast-if->-c/fixnum + #+arm64 'sb-vm::fast-if->-integer/c) + (eql (car (vop-codegen-info next)) 0) + (setf plusp t))) + (eq (vop-name branch) + 'branch-if)) + (let* ((result (tn-ref-tn (vop-results vop))) + (value (if plusp + 1 + (car (vop-codegen-info next))))) + (when (and (not (tn-ref-next (tn-reads result))) + (eq result (tn-ref-tn (vop-args next)))) + (check-type value bit) + (let ((template (template-or-lose #+arm64 + (if (eq (vop-name vop) 'sb-vm::data-vector-ref/simple-bit-vector) + 'sb-vm::data-vector-ref/simple-bit-vector-eq + 'sb-vm::data-vector-ref/simple-bit-vector-c-eq) + #+x86-64 + (if (eq (vop-name vop) 'sb-vm::data-vector-ref-with-offset/simple-bit-vector) + 'sb-vm::data-vector-ref-with-offset/simple-bit-vector-eq + 'sb-vm::data-vector-ref-with-offset/simple-bit-vector-c-eq)))) + (prog1 + (emit-and-insert-vop (vop-node vop) + (vop-block vop) + template + (reference-tn-refs (vop-args vop) nil) + nil + vop + (vop-codegen-info vop)) + ;; copy the condition flag + (setf (third (vop-codegen-info branch)) + (cdr (template-result-types template))) + (when (eq value 1) + (setf (second (vop-codegen-info branch)) + (not (second (vop-codegen-info branch))))) + (delete-vop vop) + (delete-vop next)))))))) + +(when-vop-existsp (:named sb-vm::<-integer-fixnum) + ;; The <-integer-fixnum VOPs already perform dispatch for fixnum/bignum, + ;; and load the header byte. + ;; Replace the preceding INTEGERP VOP with an appropriate + ;; <-integer-fixnum, which checks for INTEGER. + (defoptimizer (vop-optimize integerp) (vop) + (when (boundp '*2block-info*) + (destructuring-bind (target not-p) (vop-codegen-info vop) + (let ((target-block (gethash target *2block-info*))) + (when target-block + (let* ((next (if (eq vop (ir2-block-last-vop (vop-block vop))) + (ir2-block-next (vop-block vop)) + (let ((next (next-vop vop))) + (and (eq (vop-name next) 'branch) + (gethash (car (vop-codegen-info next)) *2block-info*))))) + (not-target-block (if not-p + target-block + next)) + (target-block (if not-p + next + target-block)) + (cmp (ir2-block-start-vop target-block))) + (when (and cmp + (singleton-p (ir2block-predecessors target-block))) + (let ((integer (tn-ref-tn (vop-args vop))) + (args (vop-args cmp)) + tns) + (when (case (vop-name cmp) + ((sb-vm::>-integer-fixnum sb-vm::<-integer-fixnum) + (when (eq (tn-ref-tn args) integer) + (setf tns (list integer (tn-ref-tn (tn-ref-across args)))))) + ((sb-vm::>-fixnum-integer sb-vm::<-fixnum-integer) + (when (eq (tn-ref-tn (tn-ref-across args)) integer) + (setf tns (list (tn-ref-tn args) integer))))) + (destructuring-bind (cmp-target cmp-not-p) (vop-codegen-info cmp) + (let* ((cmp-next-block (ir2-block-next (vop-block cmp))) + (cmp-target-block (gethash cmp-target *2block-info*))) + (flet ((invert () + (template-or-lose + (case (vop-name cmp) + (sb-vm::>-integer-fixnum 'sb-vm::<=-integer-fixnum) + (sb-vm::<-integer-fixnum 'sb-vm::>=-integer-fixnum) + (sb-vm::>-fixnum-integer 'sb-vm::<=-fixnum-integer) + (sb-vm::<-fixnum-integer 'sb-vm::>=-fixnum-integer))))) + (multiple-value-bind (new-vop new-target new-not-p) + (cond ((and not-p + (eq not-target-block cmp-next-block)) + (if cmp-not-p + (values (invert) cmp-target nil) + (values (vop-info cmp) cmp-target nil))) + ((and not-p + (eq not-target-block cmp-target-block)) + (if cmp-not-p + (values (vop-info cmp) cmp-target t) + (values (invert) cmp-target t))) + ((and (not not-p) + (eq not-target-block cmp-target-block)) + (if cmp-not-p + (values (vop-info cmp) (ir2-block-%label target-block) nil) + (values (invert) (ir2-block-%label target-block) nil))) + ((and (not not-p) + (eq not-target-block cmp-next-block)) + (if cmp-not-p + (values (invert) cmp-target nil) + (values (vop-info cmp) cmp-target nil))) + (t + (return-from vop-optimize-integerp-optimizer))) + (prog1 + (emit-and-insert-vop (vop-node vop) (vop-block vop) + new-vop + (reference-tn-list tns nil) + nil vop + (list new-target new-not-p)) + (delete-vop vop) + (delete-vop cmp)))))))))))) + nil)))) + +;;; No need to reset the stack pointer just before returning. +(defoptimizer (vop-optimize reset-stack-pointer) (vop) + (loop for next = (next-vop vop) then (next-vop next) + do (cond ((not next) + (return)) + ((eq (vop-name next) 'move)) + ((memq (vop-name next) '(return-single return known-return + tail-call tail-call-named + static-tail-call-named)) + (delete-vop vop) + ;; Delete the VOP that saves the stack pointer too. + (let ((tn (tn-ref-tn (vop-args vop)))) + (unless (tn-reads tn) + (aver (eq (vop-name (tn-ref-vop (tn-writes tn))) + 'current-stack-pointer)) + (delete-vop (tn-ref-vop (tn-writes tn))))) + (return)) + (t + (return))))) + +;;; stack-analyze may have avoided creating a cleanup +;;; leaving this unused +(defoptimizer (vop-optimize current-stack-pointer) (vop) + (let ((tn (tn-ref-tn (vop-results vop)))) + (when (not (tn-reads tn)) + (delete-vop vop)))) + +;;; Load the WIDETAG once for a series of type tests. +(when-vop-existsp (:named sb-vm::load-other-pointer-widetag) + (defoptimizer (vop-optimize %other-pointer-subtype-p) (vop) + (when (boundp '*2block-info*) + (let (vops + stop + null + (value (tn-ref-tn (vop-args vop)))) + (labels ((good-vop-p (vop) + (and (singleton-p (ir2block-predecessors (vop-block vop))) + (or (getf sb-vm::*other-pointer-type-vops* (vop-name vop)) + (eq (vop-name vop) '%other-pointer-subtype-p)) + (eq (tn-ref-tn (vop-args vop)) value))) + (chain (vop &optional (collect t)) + (let ((next (branch-destination vop nil))) + (cond ((and next + (or (neq (vop-name vop) 'symbolp) + (and (not null) + (setf null (branch-destination vop))))) + (when collect + (push vop vops)) + (cond ((good-vop-p next) + (chain next)) + ((not stop) + (setf stop (vop-block next))))) + ((not stop) + (setf stop (vop-block vop))))) + (let ((true (branch-destination vop))) + (when (and true + (good-vop-p true)) + (push true vops) + (chain true nil)))) + (ir2-block-label (block) + (or (ir2-block-%label block) + (setf (ir2-block-%label block) (gen-label))))) + (chain vop) + (when (> (length vops) 1) + (let ((widetag (make-normal-tn (primitive-type-or-lose 'sb-vm::unsigned-byte-64))) + (block (vop-block vop))) + (setf (tn-type value) + (tn-ref-type (vop-args vop))) + (emit-and-insert-vop (vop-node vop) + block + (template-or-lose 'sb-vm::load-other-pointer-widetag) + (reference-tn value nil) + (reference-tn widetag t) + vop + (list (ir2-block-label stop) + (and null + (ir2-block-label (vop-block null))))) + (update-block-succ block + (cons stop + (ir2block-successors block))) + + (let ((test-vop (template-or-lose 'sb-vm::test-widetag))) + (loop for vop in vops + for info = (vop-codegen-info vop) + for tags = (if (eq (vop-name vop) '%other-pointer-subtype-p) + (third info) + (getf sb-vm::*other-pointer-type-vops* (vop-name vop))) + do + (let ((next (vop-next vop))) + (when (and next + (eq (vop-name next) 'branch-if)) + (setf info (vop-codegen-info next)) + (delete-vop next)) + (emit-and-insert-vop (vop-node vop) + (vop-block vop) + test-vop + (reference-tn widetag nil) + nil + vop + (list (first info) (second info) tags))) + (delete-vop vop)))))))) + nil) + + (loop for (vop) on sb-vm::*other-pointer-type-vops* by #'cddr + do + (set-vop-optimizer (template-or-lose vop) + #'vop-optimize-%other-pointer-subtype-p-optimizer))) + +(when-vop-existsp (:named sb-vm::load-instance-layout) + (defoptimizer (vop-optimize structure-typep) (vop) + (when (boundp '*2block-info*) + (let (vops + stop + (value (tn-ref-tn (vop-args vop)))) + (labels ((good-vop-p (vop) + (and (singleton-p (ir2block-predecessors (vop-block vop))) + (eq (vop-name vop) 'structure-typep) + (eq (tn-ref-tn (vop-args vop)) value))) + (chain (vop &optional (collect t)) + (let ((next (branch-destination vop nil))) + (cond (next + (when collect + (push vop vops)) + (cond ((good-vop-p next) + (chain next)) + ((not stop) + (setf stop (vop-block next))))) + ((not stop) + (setf stop (vop-block vop))))) + (let ((true (branch-destination vop))) + (when (and true + (good-vop-p true)) + (push true vops) + (chain true nil)))) + (ir2-block-label (block) + (or (ir2-block-%label block) + (setf (ir2-block-%label block) (gen-label))))) + (chain vop) + (when (> (length vops) 1) + (let ((layout (make-normal-tn *backend-t-primitive-type*)) + (block (vop-block vop))) + (setf (tn-type value) + (tn-ref-type (vop-args vop))) + (emit-and-insert-vop (vop-node vop) + block + (template-or-lose 'sb-vm::load-instance-layout) + (reference-tn value nil) + (reference-tn layout t) + vop + (list (ir2-block-label stop))) + (update-block-succ block + (cons stop + (ir2block-successors block))) + (let ((test-vop (template-or-lose 'sb-vm::structure-typep*))) + (loop for vop in vops + for info = (vop-codegen-info vop) + do + (emit-and-insert-vop (vop-node vop) + (vop-block vop) + test-vop + (reference-tn layout nil) + nil + vop + info) + (delete-vop vop)))))))) + nil)) + (defun very-temporary-p (tn) (let ((writes (tn-writes tn)) (reads (tn-reads tn))) (and writes reads (not (tn-ref-next writes)) (not (tn-ref-next reads))))) -(defun next-vop-is (vop name) - (let ((next (vop-next vop))) - (and next (eq (vop-name next) name)))) +(defun next-vop-is (vop names) + (let ((next (next-vop vop))) + (and next + (let ((name (vop-name next))) + (if (atom names) (eq name names) (memq name names))) + next))) + +(defun previous-vop-is (vop names) + (let ((prev (vop-prev vop))) + (and prev + (let ((name (vop-name prev))) + (if (atom names) (eq name names) (memq name names))) + prev))) ;;; Possibly replace HOWMANY vops starting at FIRST with a vop named REPLACEMENT. ;;; Each deleted vop must have exactly one argument and one result. ;;; - There must be no way to begin execution in the middle of the pattern. -;;; For now we'll require that the vops have the same IR2 block, -;;; which is a more restrictive condition. ;;; - The argument to each successive vop must be the result of its predecessor. ;;; - There must be no other refs to TNs which are to be deleted. ;;; @@ -848,16 +1309,15 @@ ;;; is in a register (so we get the load as part of the instruction). (defun replace-vops (howmany first replacement) (flet ((can-replace (vop &aux (result (tn-ref-tn (vop-results vop))) - (next (vop-next vop))) - (and (eq (vop-block vop) (vop-block next)) - (very-temporary-p result) + (next (next-vop vop))) + (and (very-temporary-p result) (eq (tn-ref-tn (vop-args next)) result)))) (let ((last (ecase howmany (2 (when (can-replace first) - (vop-next first))) + (next-vop first))) (3 (when (and (can-replace first) - (can-replace (vop-next first))) - (vop-next (vop-next first))))))) + (can-replace (next-vop first))) + (next-vop (next-vop first))))))) (when last (let ((new (emit-and-insert-vop (vop-node first) (vop-block first) @@ -866,7 +1326,7 @@ (reference-tn (tn-ref-tn (vop-results last)) t) first))) ; insert before this (dotimes (i (1- howmany)) ; if 3, replace 2 "NEXT"'s and then first, etc - (delete-vop (vop-next first))) + (delete-vop (next-vop first))) (delete-vop first) new))))) ; return suitable value for RUN-VOP-OPTIMIZERS @@ -881,6 +1341,52 @@ (funcall it vop)) (vop-next vop))))))) +(defun merge-instance-set-vops (vop) + (let ((instance (tn-ref-tn (vop-args vop))) + (this vop) + (pairs)) + (loop + (let ((index (tn-ref-tn (tn-ref-across (vop-args this))))) + (unless (constant-tn-p index) (return)) + (push (cons (tn-value index) (tn-ref-tn (sb-vm::vop-nth-arg 2 this))) + pairs)) + (let ((next (vop-next this))) + (unless (and next + (eq (vop-name next) 'sb-vm::instance-index-set) + (eq (tn-ref-tn (vop-args next)) instance)) + (return)) + (setq this next))) + (unless (cdr pairs) ; if at least 2 + (return-from merge-instance-set-vops nil)) + (setq pairs (nreverse pairs)) + (let ((new (emit-and-insert-vop + (vop-node vop) (vop-block vop) + (template-or-lose 'sb-vm::instance-set-multiple) + (reference-tn-list (cons instance (mapcar #'cdr pairs)) nil) + nil vop (list (mapcar #'car pairs))))) + (loop (let ((next (vop-next vop))) + (delete-vop vop) + (pop pairs) + (setq vop next)) + (unless pairs (return))) + new))) + +(defun ir2-optimize-stores (component) + ;; This runs after representation selection. It's the same as RUN-VOP-OPTIMIZERS, + ;; but with hardcoded vop names and function to call. + ;; It seems like this should also supplant the #+arm64 hack in GENERATE-CODE. + (do-ir2-blocks (block component) + (let ((vop (ir2-block-start-vop block))) + (loop (unless vop (return)) + (let ((optimizer + (case (vop-name vop) + (sb-vm::instance-index-set + (when (gethash 'sb-vm::instance-set-multiple + *backend-parsed-vops*) + 'merge-instance-set-vops))))) + (setq vop (or (awhen optimizer (funcall it vop)) + (vop-next vop)))))))) + (defun ir2-optimize (component) (let ((*2block-info* (make-hash-table :test #'eq))) (initialize-ir2-blocks-flow-info component) @@ -894,8 +1400,22 @@ ;; Look for if/else chains before cmovs, because a cmov ;; affects whether the last if/else is recognizable. #+(or ppc ppc64 x86 x86-64) (convert-if-else-chains component) - (convert-cmovs component) (run-vop-optimizers component) (delete-unused-ir2-blocks component)) (values)) + +(defun delete-unnecessary-move (vop) + (when (and (vop-next vop) + (eq (vop-name (vop-next vop)) 'move) + ;; the source of the move is the result of this + (eq (tn-ref-tn (vop-args (vop-next vop))) + (tn-ref-tn (vop-results vop))) + ;; the destination of the move is the same as the input of this + (eq (tn-ref-tn (vop-results (vop-next vop))) + (tn-ref-tn (vop-args vop))) + ;; there is exactly one write and one read of the intermediate TN + (very-temporary-p (tn-ref-tn (vop-results vop)))) + ;; Change my result ref to the same TN as the input and delete the MOVE + (change-tn-ref-tn (vop-results vop) (tn-ref-tn (vop-args vop))) + (delete-vop (vop-next vop)))) diff --git a/src/compiler/ir2tran.lisp b/src/compiler/ir2tran.lisp index 02617e5c87..fb827cae8c 100644 --- a/src/compiler/ir2tran.lisp +++ b/src/compiler/ir2tran.lisp @@ -40,43 +40,31 @@ ;;;; leaf reference ;;; Return the TN that holds the value of THING in the environment ENV. -(declaim (ftype (sfunction ((or nlx-info lambda-var clambda) physenv) tn) - find-in-physenv)) -(defun find-in-physenv (thing physenv) - (or (cdr (assoc thing (ir2-physenv-closure (physenv-info physenv)))) +(defun find-in-environment (thing env) + (declare (type (or nlx-info lambda-var clambda) thing) (type environment env) + #-sb-xc-host (values tn)) + (or (cdr (assoc thing (ir2-environment-closure (environment-info env)))) (etypecase thing (lambda-var - ;; I think that a failure of this assertion means that we're - ;; trying to access a variable which was improperly closed - ;; over. The PHYSENV describes a physical environment. Every - ;; variable that a form refers to should either be in its - ;; physical environment directly, or grabbed from a - ;; surrounding physical environment when it was closed over. - ;; The ASSOC expression above finds closed-over variables, so - ;; if we fell through the ASSOC expression, it wasn't closed - ;; over. Therefore, it must be in our physical environment - ;; directly. If instead it is in some other physical - ;; environment, then it's bogus for us to reference it here - ;; without it being closed over. -- WHN 2001-09-29 - (aver (eq physenv (lambda-physenv (lambda-var-home thing)))) + (aver (eq env (lambda-environment (lambda-var-home thing)))) (leaf-info thing)) (nlx-info - (aver (eq physenv (block-physenv (nlx-info-target thing)))) + (aver (eq env (block-environment (nlx-info-target thing)))) (ir2-nlx-info-home (nlx-info-info thing))) (clambda (aver (xep-p thing)) (entry-info-closure-tn (lambda-info thing)))) - (bug "~@<~2I~_~S ~_not found in ~_~S~:>" thing physenv))) + (bug "~@<~2I~_~S ~_not found in ~_~S~:>" thing env))) ;;; Return a TN that represents the value of LEAF, or NIL if LEAF ;;; isn't directly represented by a TN. ENV is the environment that ;;; the reference is done in. (defun leaf-tn (leaf env) - (declare (type leaf leaf) (type physenv env)) + (declare (type leaf leaf) (type environment env)) (typecase leaf (lambda-var (unless (lambda-var-indirect leaf) - (find-in-physenv leaf env))) + (find-in-environment leaf env))) (constant (make-constant-tn leaf)) (t nil))) @@ -91,19 +79,19 @@ (declare (type ref node) (type ir2-block block)) (let* ((lvar (node-lvar node)) (leaf (ref-leaf node)) - (locs (lvar-result-tns lvar (list (leaf-type leaf)))) + (locs (lvar-result-tns lvar (list (single-value-type (node-derived-type node))))) (res (first locs))) (etypecase leaf (lambda-var - (let ((tn (find-in-physenv leaf (node-physenv node))) + (let ((tn (find-in-environment leaf (node-environment node))) (indirect (lambda-var-indirect leaf)) (explicit (lambda-var-explicit-value-cell leaf))) (cond ((and indirect explicit) (vop value-cell-ref node block tn res)) ((and indirect - (not (eq (node-physenv node) - (lambda-physenv (lambda-var-home leaf))))) + (not (eq (node-environment node) + (lambda-environment (lambda-var-home leaf))))) (let ((reffer (third (primitive-type-indirect-cell-type (primitive-type (leaf-type leaf)))))) (if reffer @@ -137,46 +125,55 @@ (vop fast-symbol-global-value node block name-tn res) (vop symbol-global-value node block name-tn res)))) (:global-function + ;; A :GLOBAL-FUNCTION refers to #'NAME for some purpose _other_ _than_ + ;; NAME being a symbol at the CAR of a form (and referenced in FUN-LVAR-TN). ;; In cross-compilation, testing (INFO :function :definition) is not ;; sensible (or possible) but we can assume that things with fun-info ;; will eventually be defined. If that's untrue, e.g. if we referred ;; to #'DESCRIBE during cold-load, we'd just fix it locally by declaring ;; DESCRIBE notinline. - ;; But in the target, more caution is warranted because users might - ;; DEFKNOWN a function but fail to define it. And they shouldn't be - ;; expected to understand the failure mode and the remedy. - (cond ((and #-sb-xc-host (info :function :definition name) + ;; But don't do this for non-internal packages, because users + ;; might DEFKNOWN a function but fail to define it, or they + ;; might try to redefine it and get the old definition. And + ;; they shouldn't be expected to understand the failure mode + ;; and the remedy. + (cond ((and (labels ((internal-name-p (what) + (typecase what + (list + (every #'internal-name-p what)) + (symbol + (let ((pkg (sb-xc:symbol-package what))) + (or (and pkg (system-package-p pkg)) + (eq pkg *cl-package*)))) + (t t)))) + (internal-name-p name)) (info :function :info name) + ;; Known functions can be dumped without going through fdefns. + ;; But if NOTINLINEd, don't early-bind to the functional value + ;; because that disallows redefinition, including but not limited + ;; to encapsulations, which in turn makes TRACE not work, which + ;; leads to extreme frustration when debugging. (let ((*lexenv* (node-lexenv node))) - (not (fun-lexically-notinline-p name)))) - ;; Known functions can be dumped without going through fdefns. - ;; But if NOTINLINEd, don't early-bind to the functional value - ;; because that disallows redefinition, including but not limited - ;; to encapsulations, which in turn makes TRACE not work, which - ;; leads to extreme frustration when debugging. + (not (fun-lexically-notinline-p name))) + ;; If NOT compiling to a file, then the function had better exist now. + ;; If to a file, then it better exist at some point, but its existence + ;; in the compilation lisp doesn't really imply that it will. + #-sb-xc-host (if (producing-fasl-file) t (fboundp name))) (emit-move node block (make-load-time-constant-tn :known-fun name) res)) (t - #+untagged-fdefns - (let ((fdefn-tn (make-load-time-constant-tn :named-call name))) + (let ((fdefn-tn (make-load-time-constant-tn :fdefinition name))) + #+untagged-fdefns (if unsafe (vop sb-vm::untagged-fdefn-fun node block fdefn-tn res) - (vop sb-vm::safe-untagged-fdefn-fun node block fdefn-tn res))) - #-untagged-fdefns - (let ((fdefn-tn (make-load-time-constant-tn :fdefinition name))) + (vop sb-vm::safe-untagged-fdefn-fun node block fdefn-tn res)) + #-untagged-fdefns (if unsafe (vop fdefn-fun node block fdefn-tn res) (vop safe-fdefn-fun node block fdefn-tn res))))))))) ;;; some sanity checks for a CLAMBDA passed to IR2-CONVERT-CLOSURE (defun assertions-on-ir2-converted-clambda (clambda) - ;; This assertion was sort of an experiment. It would be nice and - ;; sane and easier to understand things if it were *always* true, - ;; but experimentally I observe that it's only *almost* always - ;; true. -- WHN 2001-01-02 - #+nil - (aver (eql (lambda-component clambda) - (block-component (ir2-block-block ir2-block)))) ;; Check for some weirdness which came up in bug ;; 138, 2002-01-02. ;; @@ -203,9 +200,7 @@ (values)) ;;; Emit code to load a function object implementing FUNCTIONAL into -;;; RES. This gets interesting when the referenced function is a -;;; closure: we must make the closure and move the closed-over values -;;; into it. +;;; RES. ;;; ;;; FUNCTIONAL is either a :TOPLEVEL-XEP functional or the XEP lambda ;;; for the called function, since local call analysis converts all @@ -231,15 +226,15 @@ (let ((closure (etypecase functional (clambda (assertions-on-ir2-converted-clambda functional) - (physenv-closure (get-lambda-physenv functional))) + (environment-closure (get-lambda-environment functional))) (functional (aver (eq (functional-kind functional) :toplevel-xep)) nil))) global-var) (cond (closure (prepare) - (let* ((physenv (node-physenv ref)) - (tn (find-in-physenv functional physenv))) + (let* ((this-env (node-environment ref)) + (tn (find-in-environment functional this-env))) (emit-move ref ir2-block tn res))) ;; we're about to emit a reference to a "closure" that's actually ;; an inlinable global function. @@ -259,7 +254,7 @@ (defun closure-initial-value (what this-env current-fp) (declare (type (or nlx-info lambda-var clambda) what) - (type physenv this-env) + (type environment this-env) (type (or tn null) current-fp)) ;; If we have an indirect LAMBDA-VAR that does not require an ;; EXPLICIT-VALUE-CELL, and is from this environment (not from being @@ -267,68 +262,59 @@ (if (and (lambda-var-p what) (lambda-var-indirect what) (not (lambda-var-explicit-value-cell what)) - (eq (lambda-physenv (lambda-var-home what)) + (eq (lambda-environment (lambda-var-home what)) this-env)) current-fp - (find-in-physenv what this-env))) - -(defoptimizer (%allocate-closures ltn-annotate) ((leaves) node ltn-policy) - (declare (ignore ltn-policy)) - (when (lvar-dynamic-extent leaves) - (let ((info (make-ir2-lvar *backend-t-primitive-type*))) - (setf (ir2-lvar-kind info) :delayed) - (setf (lvar-info leaves) info) - (setf (ir2-lvar-stack-pointer info) - (make-stack-pointer-tn))))) - -(defoptimizer (%allocate-closures ir2-convert) ((leaves) call 2block) - (let ((dx-p (lvar-dynamic-extent leaves))) + (find-in-environment what this-env))) + +;;; Emit code to create function objects implementing the FUNCTIONALs +;;; of the enclose node. This gets interesting when the functions are +;;; mutually referential closures as in LABELS constructs: we must +;;; make the closures first and move the closed-over values into them +;;; in such a way that any closed over closures are initialized before +;;; they are moved into environments. A simple solution: we postpone +;;; the initialization of the closures until after they have all been +;;; created, though this may require more registers. TODO: it may be +;;; possible to improve on this somehow. +(defun ir2-convert-enclose (node ir2-block) + (declare (type enclose node) + (type ir2-block ir2-block)) + (let ((funs (enclose-funs node)) + (lvar (node-lvar node))) ; non-null when DX + (when lvar + (vop current-stack-pointer node ir2-block (ir2-lvar-stack-pointer (lvar-info lvar)))) (collect ((delayed)) - (when dx-p - (vop current-stack-pointer call 2block - (ir2-lvar-stack-pointer (lvar-info leaves)))) - (dolist (leaf (lvar-value leaves)) - (binding* ((xep (awhen (functional-entry-fun leaf) - ;; if the xep's been deleted then we can skip it - (if (eq (functional-kind it) :deleted) - nil it)) - :exit-if-null) - (nil (aver (xep-p xep))) - (entry-info (lambda-info xep) :exit-if-null) - (tn (entry-info-closure-tn entry-info) :exit-if-null) - (closure (physenv-closure (get-lambda-physenv xep))) - #-x86-64 - (entry (make-load-time-constant-tn :entry xep))) - (let ((this-env (node-physenv call)) - (leaf-dx-p (and dx-p (leaf-dynamic-extent leaf)))) - (aver (entry-info-offset entry-info)) - (vop make-closure call 2block #-x86-64 entry - (entry-info-offset entry-info) (length closure) - leaf-dx-p tn) - (loop for what in closure and n from 0 do - (unless (and (lambda-var-p what) - (null (leaf-refs what))) - ;; In LABELS a closure may refer to another closure - ;; in the same group, so we must be sure that we - ;; store a closure only after its creation. - ;; - ;; TODO: Here is a simple solution: we postpone - ;; putting of all closures after all creations - ;; (though it may require more registers). - (if (lambda-p what) - (delayed (list tn (find-in-physenv what this-env) n)) - (let ((initial-value (closure-initial-value - what this-env nil))) - (if initial-value - (vop closure-init call 2block - tn initial-value n) - ;; An initial-value of NIL means to stash - ;; the frame pointer... which requires a - ;; different VOP. - (vop closure-init-from-fp call 2block tn n))))))))) + (dolist (fun funs) + (let ((xep (functional-entry-fun fun))) + ;; If there is no XEP then no closure needs to be created. + (when (and xep (not (eq (functional-kind xep) :deleted))) + (aver (xep-p xep)) + (let ((closure (environment-closure (get-lambda-environment xep)))) + (when closure + (let* ((entry-info (lambda-info xep)) + (tn (entry-info-closure-tn entry-info)) + #-(or x86-64 arm64) + (entry (make-load-time-constant-tn :entry xep)) + (env (node-environment node)) + (leaf-dx-p (and lvar (leaf-dynamic-extent fun)))) + (aver (entry-info-offset entry-info)) + (vop make-closure node ir2-block #-(or x86-64 arm64) entry + (entry-info-offset entry-info) (length closure) + leaf-dx-p tn) + (loop for what in closure and n from 0 do + (unless (and (lambda-var-p what) + (null (leaf-refs what))) + (if (lambda-p what) + (delayed (list tn (find-in-environment what env) n)) + (let ((initial-value (closure-initial-value what env nil))) + (if initial-value + (vop closure-init node ir2-block tn initial-value n) + ;; An initial-value of NIL means to stash + ;; the frame pointer... which requires a + ;; different VOP. + (vop closure-init-from-fp node ir2-block tn n)))))))))))) (loop for (tn what n) in (delayed) - do (vop closure-init call 2block - tn what n)))) + do (vop closure-init node ir2-block tn what n)))) (values)) ;;; Convert a SET node. If the NODE's LVAR is annotated, then we also @@ -346,15 +332,15 @@ (etypecase leaf (lambda-var (when (leaf-refs leaf) - (let ((tn (find-in-physenv leaf (node-physenv node))) + (let ((tn (find-in-environment leaf (node-environment node))) (indirect (lambda-var-indirect leaf)) (explicit (lambda-var-explicit-value-cell leaf))) (cond ((and indirect explicit) (vop value-cell-set node block tn val)) ((and indirect - (not (eq (node-physenv node) - (lambda-physenv (lambda-var-home leaf))))) + (not (eq (node-environment node) + (lambda-environment (lambda-var-home leaf))))) (let ((setter (fourth (primitive-type-indirect-cell-type (primitive-type (leaf-type leaf)))))) (if setter @@ -394,7 +380,7 @@ (ecase (ir2-lvar-kind 2lvar) (:delayed (let ((ref (lvar-uses lvar))) - (leaf-tn (ref-leaf ref) (node-physenv ref)))) + (leaf-tn (ref-leaf ref) (node-environment ref)))) (:fixed (aver (= (length (ir2-lvar-locs 2lvar)) 1)) (first (ir2-lvar-locs 2lvar))))) @@ -449,7 +435,8 @@ ;;; IR2-LVAR-LOCS. Otherwise we make a new list padded as necessary by ;;; discarded TNs. We always return a TN of the specified type, using ;;; the lvar locs only when they are of the correct type. -(defun lvar-result-tns (lvar types &optional primitive-types) +(defun lvar-result-tns (lvar types &optional primitive-types + call) (declare (type (or lvar null) lvar) (type list primitive-types types)) (let ((primitive-types (or primitive-types @@ -466,13 +453,23 @@ for prim-type in primitive-types always (eq (tn-primitive-type loc) prim-type))) locs - (loop for prim-type in primitive-types + (loop with optional = (and call + (vop-info-p (combination-info call)) + (vop-info-optional-results (combination-info call))) + for prim-type in primitive-types for type in types + for i from 0 for loc = (pop locs) - collect (if (and loc - (eq (tn-primitive-type loc) prim-type)) - loc - (make-normal-tn prim-type type)))))) + collect (cond ((and loc + (if (eq (tn-kind loc) :unused) + (member i optional) + (eq (tn-primitive-type loc) prim-type))) + loc) + ((and (not loc) + (member i optional)) + (make-unused-tn)) + (t + (make-normal-tn prim-type type))))))) (:unknown (mapcar #'make-normal-tn primitive-types types)))) (mapcar #'make-normal-tn primitive-types types)))) @@ -513,6 +510,7 @@ (ndest (length dest))) (mapc (lambda (from to) (unless (or (eq from to) + (eq (tn-kind from) :unused) (eq (tn-kind to) :unused)) (emit-move node block from to))) (if (> ndest nsrc) @@ -546,22 +544,10 @@ (unless (eq locs results) (move-results-coerced node block results locs)))) (:unknown - (let ((locs (loop for tn in results - collect (cond #+(or x86 x86-64) - ((eq (tn-kind tn) :constant) - tn) - ((and - #-(or x86 x86-64) - (neq (tn-kind tn) :constant) - (eq (tn-primitive-type tn) *backend-t-primitive-type*)) - tn) - ((let ((new (make-normal-tn *backend-t-primitive-type*))) - (emit-move node block tn new) - new)))))) - (vop* push-values node block - ((reference-tn-list locs nil)) - ((reference-tn-list (ir2-lvar-locs 2lvar) t)) - (length results)))))))) + (vop* push-values node block + ((reference-tn-list results nil)) + ((reference-tn-list (ir2-lvar-locs 2lvar) t)) + (length results))))))) (values)) ;;; CAST @@ -572,7 +558,7 @@ (2lvar (lvar-info lvar)) (value (cast-value node)) (2value (lvar-info value))) - (when 2lvar ;; the cast can be unused but not deleted to due vestigial exits + (when 2lvar ;; the cast can be unused but not deleted due to DELAY (ecase (ir2-lvar-kind 2lvar) (:unused) ((:unknown :fixed) @@ -581,8 +567,7 @@ (ir2-lvar-locs 2value) (ir2-lvar-locs 2lvar))))))) -(defoptimizer (%check-bound ir2-hook) ((array bound index) node block) - (declare (ignore block)) +(defoptimizer (%check-bound ir2-hook) ((array bound index) node) (let* ((bound-type (lvar-type bound)) (bound-type (specifier-type `(integer 0 @@ -590,7 +575,7 @@ (lvar-value bound)) ((and (integer-type-p bound-type) (nth-value 1 (integer-type-numeric-bounds bound-type)))) - (sb-xc:array-dimension-limit)))))) + (array-dimension-limit)))))) (index-type (lvar-type index))) (when (eq (type-intersection bound-type index-type) *empty-type*) @@ -657,12 +642,53 @@ (register-drop-thru alternative) (vop branch node block (block-label alternative)))) (t + (when (equal flags '(:after-sc-selection)) + ;; To be fixed up by VOP-INFO-AFTER-SC-SELECTION + (setf flags (list :after-sc-selection)) + (setf info-args (append info-args flags))) (emit-template node block template args nil info-args) (vop branch-if if block (block-label consequent) not-p flags) (if (drop-thru-p if alternative) (register-drop-thru alternative) (vop branch if block (block-label alternative))))))) +(when-vop-existsp (:named sb-vm::move-conditional-result) + ;; Use a dedicated VOP instead of wrapping a conditional that needs + ;; to return T/NIL in (if x t nil) + ;; Produces slightly better code, not emitted when not needed. + (defun ir2-convert-conditional-result (node block template args info-args lvar) + (declare (type node node) (type ir2-block block) + (type template template) (type (or tn-ref null) args) + (list info-args)) + (let* ((res (lvar-result-tns lvar + (list *universal-type*) + (list *backend-t-primitive-type*))) + (res-refs (reference-tn-list res t)) + (flags (and (consp (template-result-types template)) + (rest (template-result-types template))))) + (aver (= (template-info-arg-count template) + (+ (length info-args) + (if flags 0 2)))) + (cond ((not flags) + (let ((true (gen-label))) + (emit-template node block template args nil + (list* true nil info-args)) + (emit-template node block (template-or-lose 'sb-vm::move-conditional-result) nil res-refs + (list true)))) + (t + (when (equal flags '(:after-sc-selection)) + ;; To be fixed up by VOP-INFO-AFTER-SC-SELECTION + (setf flags (list :after-sc-selection)) + (setf info-args (append info-args flags))) + (emit-template node block template args nil info-args) + (emit-template node block (template-or-lose 'sb-vm::move-if/descriptor) + (reference-tn-list + (list (emit-constant t) + (emit-constant nil)) + nil) + res-refs (list flags)))) + (move-lvar-result node block res lvar)))) + ;;; Convert an IF that isn't the DEST of a conditional template. (defun ir2-convert-if (node block) (declare (type ir2-block block) (type cif node)) @@ -713,7 +739,9 @@ (return nil)))) locs (lvar-result-tns lvar - (find-template-result-types call rtypes))))) + (find-template-result-types call rtypes) + nil + call)))) ;;; Get the operands into TNs, make TN-REFs for them, and then call ;;; the template emit function. @@ -726,8 +754,15 @@ (reference-args call block (combination-args call) template) (aver (not (template-more-results-type template))) (if (template-conditional-p template) - (ir2-convert-conditional call block template args info-args - (lvar-dest lvar) nil) + (let ((dest (lvar-dest lvar))) + (cond ((when-vop-existsp (:named sb-vm::move-conditional-result) + (unless (and (if-p dest) + (immediately-used-p (if-test dest) call)) + (ir2-convert-conditional-result call block template args info-args lvar) + t))) + (t + (ir2-convert-conditional call block template args info-args + dest nil)))) (let* ((results (make-template-result-tns call lvar rtypes)) (r-refs (reference-tn-list results t))) (aver (= (length info-args) @@ -748,8 +783,7 @@ ;;; case of IR2-CONVERT-TEMPLATE is that there can be codegen-info ;;; arguments. (defoptimizer (%%primitive ir2-convert) ((template info &rest args) call block) - (declare (ignore args)) - (let* ((template (gethash (lvar-value template) *backend-template-names*)) + (let* ((template (lvar-value template)) (info (lvar-value info)) (lvar (node-lvar call)) (rtypes (template-result-types template)) @@ -769,11 +803,14 @@ (values)) (defoptimizer (%%primitive derive-type) ((template info &rest args)) - (declare (ignore info args)) - (let ((type (template-type (gethash (lvar-value template) *backend-template-names*)))) - (if (fun-type-p type) - (fun-type-returns type) - *wild-type*))) + (let* ((template (lvar-value template)) + (type (template-type template))) + (cond ((zerop (vop-info-num-results template)) + (values-specifier-type '(values &optional))) + ((fun-type-p type) + (fun-type-returns type)) + (t + *wild-type*)))) ;;;; local call @@ -842,10 +879,10 @@ (locs loc)))) (when old-fp - (let ((this-1env (node-physenv node)) - (called-env (physenv-info (lambda-physenv fun))) + (let ((this-1env (node-environment node)) + (called-env (environment-info (lambda-environment fun))) passed) - (dolist (thing (ir2-physenv-closure called-env)) + (dolist (thing (ir2-environment-closure called-env)) (let ((value (closure-initial-value (car thing) this-1env closure-fp)) (loc (cdr thing))) ;; Don't pass the FP for indirect variables multiple times @@ -853,8 +890,10 @@ (push loc passed) (temps value) (locs loc)))) - (temps old-fp) - (locs (ir2-physenv-old-fp called-env)))) + #-arm64 + (progn + (temps old-fp) + (locs (ir2-environment-old-fp called-env))))) (values (temps) (locs))))) @@ -864,26 +903,26 @@ ;;; function's passing location. (defun ir2-convert-tail-local-call (node block fun) (declare (type combination node) (type ir2-block block) (type clambda fun)) - (let ((this-env (physenv-info (node-physenv node))) + (let ((this-env (environment-info (node-environment node))) (current-fp (make-stack-pointer-tn))) (multiple-value-bind (temps locs) (emit-psetq-moves node block fun - (ir2-physenv-old-fp this-env) current-fp) + (ir2-environment-old-fp this-env) current-fp) ;; If we're about to emit a move from CURRENT-FP then we need to ;; initialize it. - (when (find current-fp temps) + (when (memq current-fp temps) (vop current-fp node block current-fp)) (mapc (lambda (temp loc) (emit-move node block temp loc)) temps locs)) - + #-fp-and-pc-standard-save (emit-move node block - (ir2-physenv-return-pc this-env) - (ir2-physenv-return-pc-pass - (physenv-info - (lambda-physenv fun))))) + (ir2-environment-return-pc this-env) + (ir2-environment-return-pc-pass + (environment-info + (lambda-environment fun))))) (values)) @@ -916,9 +955,10 @@ (old-fp (make-stack-pointer-tn))) (multiple-value-bind (temps locs) (emit-psetq-moves node block fun old-fp) - (vop current-fp node block old-fp) + (when (memq old-fp temps) + (vop current-fp node block old-fp)) (vop allocate-frame node block - (physenv-info (lambda-physenv fun)) + (environment-info (lambda-environment fun)) fp nfp) (values fp nfp temps (mapcar #'make-alias-tn locs))))) @@ -934,7 +974,7 @@ (vop* known-call-local node block (fp nfp (reference-tn-list temps nil)) ((reference-tn-list locs t)) - arg-locs (physenv-info (lambda-physenv fun)) start) + arg-locs (environment-info (lambda-environment fun)) start) (move-lvar-result node block locs lvar))) (values)) @@ -954,7 +994,7 @@ (multiple-value-bind (fp nfp temps arg-locs) (ir2-convert-local-call-args node block fun) (let ((2lvar (and lvar (lvar-info lvar))) - (env (physenv-info (lambda-physenv fun))) + (env (environment-info (lambda-environment fun))) (temp-refs (reference-tn-list temps nil))) (if (and 2lvar (eq (ir2-lvar-kind 2lvar) :unknown)) (vop* multiple-call-local node block (fp nfp temp-refs) @@ -1021,11 +1061,11 @@ ;; and CL:GENSYM, in case a piece of code mentions both. (let ((name (uncross (lvar-fun-name lvar t)))) ;; Static fdefns never need a code header constant. + ;; Calls to immobile space fdefns won't use the constant, + ;; but it needs to exist for GC's pointer tracing. (values (if (sb-vm::static-fdefn-offset name) name - ;; Calls to immobile space fdefns won't use this constant, - ;; but it needs to exist for GC's pointer tracing. - (make-load-time-constant-tn :named-call name)) + (make-load-time-constant-tn :fdefinition name)) name))) (t (values (lvar-tn node block lvar) nil))))) @@ -1037,15 +1077,20 @@ (let ((args (basic-combination-args node)) (last nil) (first nil)) - (dotimes (num (length args)) - (let ((loc (standard-arg-location num))) - (emit-move node block (lvar-tn node block (elt args num)) loc) - (let ((ref (reference-tn loc nil))) - (if last - (setf (tn-ref-across last) ref) - (setf first ref)) - (setq last ref)))) - first)) + (multiple-value-bind (fixed-args-state fixed-args-types) + (fixed-args-state node) + (dotimes (num (length args)) + (let ((loc (cond (fixed-args-state + (sb-vm::fixed-call-arg-location (pop fixed-args-types) fixed-args-state)) + (t + (standard-arg-location num))))) + (emit-move node block (lvar-tn node block (elt args num)) loc) + (let ((ref (reference-tn loc nil))) + (if last + (setf (tn-ref-across last) ref) + (setf first ref)) + (setq last ref)))) + (values first fixed-args-state)))) #+call-symbol (defun fun-tn-type (lvar tn) @@ -1057,66 +1102,102 @@ (t :symbol))) +(defun pass-nargs-p (combination) + (let ((fun-info (combination-fun-info combination))) + (and #+(or arm64 x86-64) + (combination-pass-nargs combination) + (not (and (eq (combination-kind combination) :known) + fun-info + (ir1-attributep (fun-info-attributes fun-info) no-verify-arg-count) + (let ((type (info :function :type (combination-fun-source-name combination)))) + (and (not (fun-type-keyp type)) + (not (fun-type-rest type)) + (not (fun-type-optional type))))))))) + ;;; Move the arguments into the passing locations and do a (possibly ;;; named) tail call. (defun ir2-convert-tail-full-call (node block) (declare (type combination node) (type ir2-block block)) - (let* ((env (physenv-info (node-physenv node))) + (let* ((env (environment-info (node-environment node))) (args (basic-combination-args node)) (nargs (length args)) - (pass-refs (move-tail-full-call-args node block)) - (old-fp (ir2-physenv-old-fp env)) - (return-pc (ir2-physenv-return-pc env)) - (fun-lvar (basic-combination-fun node))) - (multiple-value-bind (fun-tn named) - (fun-lvar-tn node block fun-lvar) - (cond ((not named) - (vop* tail-call node block - (fun-tn old-fp return-pc pass-refs) - (nil) - nargs (emit-step-p node) - #+call-symbol - (fun-tn-type fun-lvar fun-tn))) - #-immobile-code - ((eq fun-tn named) - (vop* static-tail-call-named node block - (old-fp return-pc pass-refs) ; args - (nil) ; results - nargs named (emit-step-p node))) - (t - (vop* tail-call-named node block - (#-immobile-code fun-tn old-fp return-pc pass-refs) ; args - (nil) ; results - nargs #+immobile-code named (emit-step-p node)))))) ; info + (old-fp (ir2-environment-old-fp env)) + (return-pc (ir2-environment-return-pc env)) + (fun-lvar (basic-combination-fun node)) + (nargs (if (pass-nargs-p node) + nargs + (list nargs)))) + (multiple-value-bind (pass-refs fixed-args-p) + (move-tail-full-call-args node block) + (multiple-value-bind (fun-tn named) + (fun-lvar-tn node block fun-lvar) + (cond ((not named) + (vop* tail-call node block + (fun-tn old-fp return-pc pass-refs) + (nil) + nargs (emit-step-p node) + #+call-symbol + (fun-tn-type fun-lvar fun-tn))) + #-immobile-code + ((eq fun-tn named) + (vop* static-tail-call-named node block + (old-fp return-pc pass-refs) ; args + (nil) ; results + nargs named (emit-step-p node))) + (fixed-args-p + (when-vop-existsp (:named sb-vm::fixed-tail-call-named) + (vop* sb-vm::fixed-tail-call-named node block + (#-immobile-code fun-tn old-fp return-pc pass-refs) ; args + (nil) ; results + nargs #+immobile-code named (emit-step-p node)))) + (t + (vop* tail-call-named node block + (#-immobile-code fun-tn old-fp return-pc pass-refs) ; args + (nil) ; results + nargs #+immobile-code named (emit-step-p node))))))) ; info (values)) +(defun fixed-args-state (node) + (let ((info (combination-fun-info node))) + (when (and info + (ir1-attributep (fun-info-attributes info) fixed-args)) + (values (sb-vm::make-fixed-call-args-state) + (fun-type-required (info :function :type (combination-fun-source-name node))))))) + ;;; like IR2-CONVERT-LOCAL-CALL-ARGS, only different (defun ir2-convert-full-call-args (node block) (declare (type combination node) (type ir2-block block)) (let* ((args (basic-combination-args node)) (nargs (length args)) (fp (make-stack-pointer-tn nargs))) - (vop allocate-full-call-frame node block nargs fp) - (collect ((locs)) - (let ((last nil) - (first nil)) - (dotimes (num nargs) - (locs (sb-vm::standard-call-arg-location num)) - (let ((ref (reference-tn (lvar-tn node block (elt args num)) - nil))) - (if last - (setf (tn-ref-across last) ref) - (setf first ref)) - (setq last ref))) - - (values fp first (locs) nargs))))) + (multiple-value-bind (fixed-args-state fixed-args-types) + (fixed-args-state node) + (vop allocate-full-call-frame node block nargs fp) + (collect ((locs)) + (let ((last nil) + (first nil)) + (dotimes (num nargs) + (let* ((arg (elt args num)) + (ref (reference-tn (lvar-tn node block arg) + nil))) + (locs + (cond (fixed-args-state + (sb-vm::fixed-call-arg-location (pop fixed-args-types) fixed-args-state)) + (t + (sb-vm::standard-call-arg-location num)))) + + (if last + (setf (tn-ref-across last) ref) + (setf first ref)) + (setq last ref))) + (values fp first (locs) nargs fixed-args-state)))))) ;;; Do full call when a fixed number of values are desired. We make ;;; STANDARD-RESULT-TNS for our lvar, then deliver the result using ;;; MOVE-LVAR-RESULT. We do named or normal call, as appropriate. (defun ir2-convert-fixed-full-call (node block) (declare (type combination node) (type ir2-block block)) - (multiple-value-bind (fp args arg-locs nargs) + (multiple-value-bind (fp args arg-locs nargs fixed-args-p) (ir2-convert-full-call-args node block) (let* ((lvar (node-lvar node)) (locs (and lvar @@ -1131,7 +1212,10 @@ (standard-arg-location i)))))) (loc-refs (reference-tn-list locs t)) (nvals (length locs)) - (fun-lvar (basic-combination-fun node))) + (fun-lvar (basic-combination-fun node)) + (nargs (if (pass-nargs-p node) + nargs + (list nargs)))) (multiple-value-bind (fun-tn named) (fun-lvar-tn node block fun-lvar) (cond ((not named) @@ -1146,10 +1230,17 @@ (loc-refs) arg-locs nargs named nvals (emit-step-p node))) + (fixed-args-p + (when-vop-existsp (:named sb-vm::fixed-call-named) + (vop* sb-vm::fixed-call-named node block + (fp #-immobile-code fun-tn args) ; args + (loc-refs) ; results + arg-locs nargs #+immobile-code named nvals ; info + (emit-step-p node)))) (t (vop* call-named node block (fp #-immobile-code fun-tn args) ; args - (loc-refs) ; results + (loc-refs) ; results arg-locs nargs #+immobile-code named nvals ; info (emit-step-p node)))) (move-lvar-result node block locs lvar)))) @@ -1245,8 +1336,8 @@ (warn-if-inline-failed/call fname (node-lexenv node) cell)) (case *track-full-called-fnames* (:detailed - (when (boundp 'sb-xc:*compile-file-pathname*) - (pushnew sb-xc:*compile-file-pathname* (cdr cell) + (when (boundp '*compile-file-pathname*) + (pushnew *compile-file-pathname* (cdr cell) :test #'equal))) (:very-detailed (pushnew (component-name *component-being-compiled*) @@ -1275,8 +1366,8 @@ ;; check to see if we know anything about the function (let ((info (info :function :info fname))) ;; if we know something, check to see if the full call was valid - (when (and info (ir1-attributep (fun-info-attributes info) - always-translatable)) + (when (and info + (ir1-attributep (fun-info-attributes info) always-translatable)) (/show (policy node speed) (policy node safety)) (/show (policy node compilation-speed)) (bug "full call to ~S" fname)))) @@ -1303,7 +1394,9 @@ ;;;; entering functions (defun xep-verify-arg-count (node block fun arg-count-location) - (when (policy fun (plusp verify-arg-count)) + (when (and (policy fun (plusp verify-arg-count)) + ;; this property will be absent in most cases + (getf (functional-plist fun) 'verify-arg-count t)) (let* ((ef (functional-entry-fun fun)) (optional (optional-dispatch-p ef)) (min (and optional @@ -1312,8 +1405,11 @@ (1- (length (lambda-vars fun)))) ((and optional (not (optional-dispatch-more-entry ef))) - (optional-dispatch-max-args ef))))) - (unless (and (eql min 0) (not max)) + (optional-dispatch-max-args ef)))) + (fun-info (info :function :info (functional-%source-name ef)))) + (unless (or (and (eql min 0) (not max)) + (and fun-info + (ir1-attributep (fun-info-attributes fun-info) no-verify-arg-count))) (vop verify-arg-count node block arg-count-location min @@ -1329,7 +1425,7 @@ (defun init-xep-environment (node block fun) (declare (type bind node) (type ir2-block block) (type clambda fun)) (let ((start-label (entry-info-offset (leaf-info fun))) - (env (physenv-info (node-physenv node))) + (env (environment-info (node-environment node))) arg-count-tn) (let ((ef (functional-entry-fun fun))) (vop xep-allocate-frame node block start-label) @@ -1350,13 +1446,13 @@ ;; not all backends have been updated yet. On backends ;; that have not been updated, we still need to use ;; XEP-SETUP-SP here. - #+(or alpha hppa mips sparc) + #+(or mips sparc) (vop xep-setup-sp node block) (vop copy-more-arg node block (optional-dispatch-max-args ef) #+x86-64 verified)) (t (vop xep-setup-sp node block)))) - (when (ir2-physenv-closure env) + (when (ir2-environment-closure env) (let ((closure (make-normal-tn *backend-t-primitive-type*))) (when (policy fun (> store-closure-debug-pointer 1)) ;; Save the closure pointer on the stack. @@ -1365,29 +1461,40 @@ sb-vm:control-stack-sc-number))) (vop setup-closure-environment node block start-label closure-save) - (setf (ir2-physenv-closure-save-tn env) closure-save) + (setf (ir2-environment-closure-save-tn env) closure-save) (component-live-tn closure-save))) (vop setup-closure-environment node block start-label closure) (let ((n -1)) - (dolist (loc (ir2-physenv-closure env)) - (vop closure-ref node block closure (incf n) (cdr loc))))))) - (unless (eq (functional-kind fun) :toplevel) - (let ((vars (lambda-vars fun)) - (n 0)) - (when (leaf-refs (first vars)) - (emit-move node block arg-count-tn (leaf-info (first vars)))) - (dolist (arg (rest vars)) - (when (leaf-refs arg) - (let ((pass (standard-arg-location n)) - (home (leaf-info arg))) - (if (and (lambda-var-indirect arg) - (lambda-var-explicit-value-cell arg)) - (emit-make-value-cell node block pass home) - (emit-move node block pass home)))) - (incf n)))) - + (dolist (loc (ir2-environment-closure env)) + (vop closure-ref node block closure (incf n) (cdr loc)))))) + (unless (eq (functional-kind fun) :toplevel) + (let* ((vars (lambda-vars fun)) + (n 0) + (name (functional-%source-name ef)) + (fun-info (info :function :info name)) + (fixed-args + (and fun-info + (ir1-attributep (fun-info-attributes fun-info) fixed-args))) + (arg-types (and fixed-args + (fun-type-required (info :function :type name)))) + (fixed-arg-state (and fixed-args + (sb-vm::make-fixed-call-args-state)))) + (when (leaf-refs (first vars)) + (emit-move node block arg-count-tn (leaf-info (first vars)))) + (dolist (arg (rest vars)) + (when (leaf-refs arg) + (let ((pass (if fixed-args + (sb-vm::fixed-call-arg-location (pop arg-types) fixed-arg-state) + (standard-arg-location n))) + (home (leaf-info arg))) + (if (and (lambda-var-indirect arg) + (lambda-var-explicit-value-cell arg)) + (emit-make-value-cell node block pass home) + (emit-move node block pass home)))) + (incf n))))) + #-fp-and-pc-standard-save (emit-move node block (make-old-fp-passing-location) - (ir2-physenv-old-fp env))) + (ir2-environment-old-fp env))) (values)) @@ -1413,18 +1520,16 @@ ;; ;; It could be saved from the XEP, but some functions have both ;; external and internal entry points, so it will be saved twice. - (let ((temp (make-normal-tn *backend-t-primitive-type*)) - (bsp-save-tn (make-representation-tn *backend-t-primitive-type* + (let ((bsp-save-tn (make-representation-tn *backend-t-primitive-type* sb-vm:control-stack-sc-number))) - (vop current-binding-pointer node block temp) - (emit-move node block temp bsp-save-tn) - (setf (ir2-physenv-bsp-save-tn env) bsp-save-tn) + (vop current-binding-pointer node block bsp-save-tn) + (setf (ir2-environment-bsp-save-tn env) bsp-save-tn) (component-live-tn bsp-save-tn))) (defun ir2-convert-bind (node block) (declare (type bind node) (type ir2-block block)) (let* ((fun (bind-lambda node)) - (env (physenv-info (lambda-physenv fun)))) + (env (environment-info (lambda-environment fun)))) (aver (member (functional-kind fun) '(nil :external :optional :toplevel :cleanup))) @@ -1440,10 +1545,10 @@ ;; handles closures inside closures correctly). [remark by JES] (let* ((entry-fun (lambda-entry-fun fun))) (when entry-fun - (let ((2env (physenv-info (lambda-physenv fun))) - (entry-2env (physenv-info (lambda-physenv entry-fun)))) - (setf (ir2-physenv-closure-save-tn 2env) - (ir2-physenv-closure-save-tn entry-2env))))))) + (let ((2env (environment-info (lambda-environment fun))) + (entry-2env (environment-info (lambda-environment entry-fun)))) + (setf (ir2-environment-closure-save-tn 2env) + (ir2-environment-closure-save-tn entry-2env))))))) #-fp-and-pc-standard-save (let ((lab (gen-label))) ;; KLUDGE: Technically, we should be doing this before VOP @@ -1451,16 +1556,17 @@ ;; expected to work anyway, so there's no real window to worry ;; about. (vop emit-label node block lab) - (setf (ir2-physenv-cfp-saved-pc env) lab)) + (setf (ir2-environment-cfp-saved-pc env) lab)) + #-fp-and-pc-standard-save (emit-move node block - (ir2-physenv-return-pc-pass env) - (ir2-physenv-return-pc env)) + (ir2-environment-return-pc-pass env) + (ir2-environment-return-pc env)) #-fp-and-pc-standard-save (let ((lab (gen-label))) (vop emit-label node block lab) - (setf (ir2-physenv-lra-saved-pc env) lab)) + (setf (ir2-environment-lra-saved-pc env) lab)) #+unwind-to-frame-and-call-vop (when (and (lambda-allow-instrumenting fun) @@ -1469,10 +1575,10 @@ (save-bsp node block env)) (let ((lab (gen-label))) - (setf (ir2-physenv-environment-start env) lab) + (setf (ir2-environment-environment-start env) lab) (vop note-environment-start node block lab) #+sb-safepoint - (unless (policy fun (>= inhibit-safepoints 2)) + (when (policy fun (/= insert-safepoints 0)) (vop sb-vm::insert-safepoint node block)))) (values)) @@ -1492,9 +1598,9 @@ (2lvar (lvar-info lvar)) (lvar-kind (ir2-lvar-kind 2lvar)) (fun (return-lambda node)) - (env (physenv-info (lambda-physenv fun))) - (old-fp (ir2-physenv-old-fp env)) - (return-pc (ir2-physenv-return-pc env)) + (env (environment-info (lambda-environment fun))) + (old-fp (ir2-environment-old-fp env)) + (return-pc (ir2-environment-return-pc env)) (returns (tail-set-info (lambda-tail-set fun)))) (cond ((and (eq (return-info-kind returns) :fixed) @@ -1536,15 +1642,15 @@ ;;;; function as multiple values. (defoptimizer (%caller-frame ir2-convert) (() node block) - (let ((ir2-physenv (physenv-info (node-physenv node)))) + (let ((ir2-environment (environment-info (node-environment node)))) (move-lvar-result node block - (list (ir2-physenv-old-fp ir2-physenv)) + (list (ir2-environment-old-fp ir2-environment)) (node-lvar node)))) (defoptimizer (%caller-pc ir2-convert) (() node block) - (let ((ir2-physenv (physenv-info (node-physenv node)))) + (let ((ir2-environment (environment-info (node-environment node)))) (move-lvar-result node block - (list (ir2-physenv-return-pc ir2-physenv)) + (list (ir2-environment-return-pc ir2-environment)) (node-lvar node)))) ;;;; multiple values @@ -1605,10 +1711,10 @@ (eq (ir2-lvar-kind start-lvar) :unknown))) (cond (tails - (let ((env (physenv-info (node-physenv node)))) + (let ((env (environment-info (node-environment node)))) (vop tail-call-variable node block start fun - (ir2-physenv-old-fp env) - (ir2-physenv-return-pc env) + (ir2-environment-old-fp env) + (ir2-environment-return-pc env) #+call-symbol (fun-tn-type fun-lvar fun)))) ((and 2lvar @@ -1726,6 +1832,9 @@ not stack-allocated LVAR ~S." source-lvar))))) (ir2-convert-full-call node block))))) (defoptimizer (%more-arg-values ir2-convert) ((context start count) node block) + ;; Slime is still using that argument + (aver (and (constant-lvar-p start) + (eql (lvar-value start) 0))) (binding* ((lvar (node-lvar node) :exit-if-null) (2lvar (lvar-info lvar))) (ecase (ir2-lvar-kind 2lvar) @@ -1733,22 +1842,15 @@ not stack-allocated LVAR ~S." source-lvar))))) (loop for loc in (ir2-lvar-locs 2lvar) for idx upfrom 0 unless (eq (tn-kind loc) :unused) - do #+(vop-named sb-vm::more-arg-or-nil) - (vop sb-vm::more-arg-or-nil node block + do (vop sb-vm::more-arg-or-nil node block (lvar-tn node block context) (lvar-tn node block count) idx - loc) - #-(vop-named sb-vm::more-arg-or-nil) - (vop sb-vm::more-arg node block - (lvar-tn node block context) - (emit-constant idx) loc))) (:unknown (let ((locs (ir2-lvar-locs 2lvar))) (vop* %more-arg-values node block ((lvar-tn node block context) - (lvar-tn node block start) (lvar-tn node block count) nil) ((reference-tn-list locs t)))))))) @@ -1763,7 +1865,7 @@ not stack-allocated LVAR ~S." source-lvar))))) ;;; This is trivial, given our assumption of a shallow-binding ;;; implementation. (defoptimizer (%special-bind ir2-convert) ((var value) node block) - (let ((name (lvar-value var))) + (let ((name (leaf-source-name (lvar-value var)))) ;; Emit either BIND or DYNBIND, preferring BIND if both exist. ;; If only one exists, it's DYNBIND. ;; Even if the backend supports load-time TLS index assignment, @@ -1786,10 +1888,9 @@ not stack-allocated LVAR ~S." source-lvar))))) (emit-constant name)))))) (defoptimizer (%special-unbind ir2-convert) ((&rest symbols) node block) - (declare (ignorable symbols)) - #-(vop-named sb-c:unbind-n) (vop unbind node block) - #+(vop-named sb-c:unbind-n) (vop unbind-n node block - (mapcar #'lvar-value symbols))) + (if-vop-existsp (:named sb-c:unbind-n) + (vop unbind-n node block (mapcar #'lvar-value symbols)) + (vop unbind node block))) ;;; ### It's not clear that this really belongs in this file, or ;;; should really be done this way, but this is the least violation of @@ -1845,7 +1946,7 @@ not stack-allocated LVAR ~S." source-lvar))))) (defun ir2-convert-exit (node block) (declare (type exit node) (type ir2-block block)) (let* ((nlx (exit-nlx-info node)) - (loc (find-in-physenv nlx (node-physenv node))) + (loc (find-in-environment nlx (node-environment node))) (temp (make-stack-pointer-tn)) (value (exit-value node))) (if (nlx-info-safe-p nlx) @@ -1853,7 +1954,10 @@ not stack-allocated LVAR ~S." source-lvar))))) (emit-move node block loc temp)) (if value (let ((locs (ir2-lvar-locs (lvar-info value)))) - (vop unwind node block temp (first locs) (second locs))) + (vop unwind node block temp (first locs) + (or (second locs) + ;; FIXME: avoid writing this TN + (emit-constant 0)))) (let ((0-tn (emit-constant 0))) (vop unwind node block temp 0-tn 0-tn)))) @@ -1861,7 +1965,7 @@ not stack-allocated LVAR ~S." source-lvar))))) ;;; %CLEANUP-POINT doesn't do anything except prevent the body from ;;; being entirely deleted. -(defoptimizer (%cleanup-point ir2-convert) ((&rest args) node block) args node block) +(defoptimizer (%cleanup-point ir2-convert) ((&rest args))) ;;; This function invalidates a lexical exit on exiting from the ;;; dynamic extent. This is done by storing 0 into the indirect value @@ -1870,7 +1974,7 @@ not stack-allocated LVAR ~S." source-lvar))))) (let ((nlx (lvar-value info))) (when (nlx-info-safe-p nlx) (vop value-cell-set node block - (find-in-physenv nlx (node-physenv node)) + (find-in-environment nlx (node-environment node)) (emit-constant 0))))) ;;; We have to do a spurious move of no values to the result lvar so @@ -1947,7 +2051,6 @@ not stack-allocated LVAR ~S." source-lvar))))) (check-catch-tag-type tag) (emit-nlx-start node block (lvar-value info-lvar) tag)) (defoptimizer (%unwind-protect ir2-convert) ((info-lvar cleanup) node block) - (declare (ignore cleanup)) (emit-nlx-start node block (lvar-value info-lvar) nil)) ;;; Emit the entry code for a non-local exit. We receive values and @@ -1973,9 +2076,10 @@ not stack-allocated LVAR ~S." source-lvar))))) (let* ((info (lvar-value info-lvar)) (lvar (node-lvar node)) (2info (nlx-info-info info)) - (target (ir2-nlx-info-target 2info))) + (target (ir2-nlx-info-target 2info)) + (kind (cleanup-kind (nlx-info-cleanup info)))) - (ecase (cleanup-kind (nlx-info-cleanup info)) + (ecase kind ((:catch :block :tagbody) (let ((top-loc (ir2-nlx-info-save-sp 2info)) (start-loc (make-nlx-entry-arg-start-location)) @@ -1987,11 +2091,19 @@ not stack-allocated LVAR ~S." source-lvar))))) ((reference-tn-list (ir2-lvar-locs 2lvar) t)) target) (let ((locs (standard-result-tns lvar))) - (vop* nlx-entry node block - (top-loc start-loc count-loc nil) - ((reference-tn-list locs t)) - target - (length locs)) + (if (and (= (length locs) 1) + (memq kind '(:block :tagbody)) + lvar + (lvar-single-value-p lvar)) + (vop* nlx-entry-single node block + (top-loc start-loc nil) + ((reference-tn-list locs t)) + target) + (vop* nlx-entry node block + (top-loc start-loc count-loc nil) + ((reference-tn-list locs t)) + target + (length locs))) (move-lvar-result node block locs lvar))))) #-no-continue-unwind ((:unwind-protect) @@ -2034,53 +2146,39 @@ not stack-allocated LVAR ~S." source-lvar))))) ;;;; n-argument functions -(macrolet ((def (name) - `(defoptimizer (,name ir2-convert) ((&rest args) node block) - (cond #+gencgc - ((>= (length args) - (/ sb-vm:large-object-size - (* sb-vm:n-word-bytes 2))) - ;; The VOPs will try to allocate all space at once - ;; And it'll end up in large objects, and no conses - ;; are welcome there. - (ir2-convert-full-call node block)) - (t - (let* ((scs - (operand-parse-scs - (vop-parse-more-args - (gethash 'list *backend-parsed-vops*)))) - (allow-const - ;; Make sure the backend allows both of IMMEDIATE - ;; and CONSTANT since MAKE-CONSTANT-TN could produce either. - (and (member 'sb-vm::constant scs) - (member 'sb-vm::immediate scs) - ;; FIXME: this is terribly wrong that in high debug - ;; settings we can't allow constants at the IR2 level. - ;; But two UNWIND-TO-FRAME-AND-CALL tests fail when - ;; constants are allowed. Somehow we're affecting - ;; semantics. It's baffling. - (policy node (< debug 3)))) - (refs (reference-tn-list - (loop for arg in args - for tn = (make-normal-tn *backend-t-primitive-type*) - do - (cond ((and allow-const (constant-lvar-p arg)) - (setq tn (emit-constant (lvar-value arg)))) - (t - (emit-move node block (lvar-tn node block arg) tn))) - collect tn) - nil)) - (lvar (node-lvar node)) - (res (lvar-result-tns - lvar (list (specifier-type 'list))))) - (when (and lvar (lvar-dynamic-extent lvar)) - (vop current-stack-pointer node block - (ir2-lvar-stack-pointer (lvar-info lvar)))) - (vop* ,name node block (refs) ((first res) nil) - (length args)) - (move-lvar-result node block res lvar))))))) - (def list) - (def list*)) +(defoptimizer (list ir2-convert) ((&rest args) node block) + (let* ((fun (lvar-fun-name (combination-fun node))) + (star (ecase fun (list* t) (list nil))) + (num-conses (- (length args) (if star 1 0)))) + ;; LIST needs at least 1 arg, LIST* demands at least 2 args + (aver (if star (cdr args) args)) + (when (> num-conses sb-vm::max-conses-per-page) + (return-from list-ir2-convert-optimizer (ir2-convert-full-call node block))) + (let* ((refs (reference-tn-list (mapcar (lambda (arg) (lvar-tn node block arg)) + args) + nil)) + (lvar (node-lvar node)) + (res (lvar-result-tns lvar (list (specifier-type 'list))))) + (when (and lvar (lvar-dynamic-extent lvar)) + (vop current-stack-pointer node block (ir2-lvar-stack-pointer (lvar-info lvar)))) + ;;; This COND-like expression is unfortunate, but the VOP* macro chokes if the name + ;;; doesn't exist. This was the best workaround I found, short of using #+. + (or (when-vop-existsp (:named cons) + (when (= num-conses 1) + (unless star + (setf (tn-ref-across refs) (reference-tn (emit-constant nil) nil))) + (vop* cons node block (refs) ((first res) nil)) + t)) + (when-vop-existsp (:named sb-vm::cons-2) + (when (= num-conses 2) + (unless star + (setf (tn-ref-across (tn-ref-across refs)) + (reference-tn (emit-constant nil) nil))) + (vop* sb-vm::cons-2 node block (refs) ((first res) nil)) + t)) + (vop* list node block (refs) ((first res) nil) star num-conses)) + (move-lvar-result node block res lvar)))) +(setf (fun-info-ir2-convert (fun-info-or-lose 'list*)) #'list-ir2-convert-optimizer) (defoptimizer (mask-signed-field ir2-convert) ((width x) node block) @@ -2131,9 +2229,32 @@ not stack-allocated LVAR ~S." source-lvar))))) (emit-move node block (lvar-tn node block x) (first results)) (move-lvar-result node block results lvar))) +(defoptimizer (%compile-time-type-error ir2-convert) + ((objects atype dtype detail code-context cast-context) node block) + ;; Remove %COMPILE-TIME-TYPE-ERROR bits + (setf (node-source-path node) + (cdr (node-source-path node))) + (%compile-time-type-error-warn node + (lvar-value atype) + (lvar-value dtype) + (lvar-value detail) + :cast-context (lvar-value cast-context)) + (ir2-convert-full-call node block)) + +(defoptimizer (%compile-time-type-style-warn ir2-convert) + ((objects atype dtype detail code-context cast-context) node) + ;; Remove %COMPILE-TIME-TYPE-ERROR bits + (setf (node-source-path node) + (cddr (node-source-path node))) + (%compile-time-type-error-warn node + (lvar-value atype) + (lvar-value dtype) + (lvar-value detail) + :cast-context (lvar-value cast-context) + :condition 'type-style-warning)) + #-sb-xc-host ;; package-lock-violation-p is not present yet -(defoptimizer (set ir2-hook) ((symbol value) node block) - (declare (ignore value block)) +(defoptimizer (set ir2-hook) ((symbol value) node) (when (constant-lvar-p symbol) (let* ((symbol (lvar-value symbol)) (kind (info :variable :kind symbol))) @@ -2203,10 +2324,11 @@ not stack-allocated LVAR ~S." source-lvar))))) (member (loop-kind (block-loop block)) '(:natural :strange)) (eq block (loop-head (block-loop block))) - (policy first-node (< inhibit-safepoints 2))) + (policy first-node (/= insert-safepoints 0))) (vop sb-vm::insert-safepoint first-node 2block)))) (ir2-convert-block block) - (incf num)))))) + (incf num)))) + (setf (component-max-block-number component) num))) (values)) ;;; If necessary, emit a terminal unconditional branch to go to the @@ -2263,11 +2385,17 @@ not stack-allocated LVAR ~S." source-lvar))))) (do-nodes (node lvar block) (etypecase node (ref - (when lvar - (let ((2lvar (lvar-info lvar))) - ;; function REF in a local call is not annotated - (when (and 2lvar (not (eq (ir2-lvar-kind 2lvar) :delayed))) - (ir2-convert-ref node 2block))))) + (if lvar + (let ((2lvar (lvar-info lvar))) + ;; function REF in a local call is not annotated + (when (and 2lvar (not (eq (ir2-lvar-kind 2lvar) :delayed))) + (ir2-convert-ref node 2block))) + (when (not (flushable-reference-p node)) + (aver (global-var-p (ref-leaf node))) + ;; convert for effect only + (ir2-convert-global-var node 2block (ref-leaf node) + (make-normal-tn + *backend-t-primitive-type*))))) (combination (let ((kind (basic-combination-kind node))) (ecase kind @@ -2313,7 +2441,9 @@ not stack-allocated LVAR ~S." source-lvar))))) (when (exit-entry node) (ir2-convert-exit node 2block))) (entry - (ir2-convert-entry node 2block))))) + (ir2-convert-entry node 2block)) + (enclose + (ir2-convert-enclose node 2block))))) (finish-ir2-block block) diff --git a/src/compiler/knownfun.lisp b/src/compiler/knownfun.lisp index a87cd33d46..43abbe6ede 100644 --- a/src/compiler/knownfun.lisp +++ b/src/compiler/knownfun.lisp @@ -30,9 +30,9 @@ (type (missing-arg) :type ctype) ;; the transformation function. Takes the COMBINATION node and ;; returns a lambda expression, or throws out. - (function (missing-arg) :type function) - ;; string used in efficiency notes - (note (missing-arg) :type string) + ;; If a cons, then the CAR is the function to call, and the CDR is an argument + ;; to pass to that function in addition to the NODE being considered. + (%fun (missing-arg) :type (or function (cons function))) ;; T if we should emit a failure note even if SPEED=INHIBIT-WARNINGS. (important nil :type (member nil :slightly t)) ;; A function with NODE as an argument that checks wheteher the @@ -41,29 +41,36 @@ ;; notes about failed transformation due to types even though it ;; wouldn't have been applied with the right types anyway, ;; or if another transform could be applied with the right policy. - (policy nil :type (or null function)) - (extra-type nil)) + (policy nil :type (or null function))) +(defun transform-function (transform) + (let ((fun (transform-%fun transform))) (if (listp fun) (car fun) fun))) +(defun transform-note (transform) + (or #+sb-xc-host (documentation (transform-function transform) 'function) + #-sb-xc-host (and (fboundp 'sb-pcl::fun-doc) + (funcall 'sb-pcl::fun-doc (transform-function transform))) + "optimize")) -(defprinter (transform) type note important) +(defmethod print-object ((x transform) stream) + (print-unreadable-object (x stream :type t :identity t) + (princ (type-specifier (transform-type x)) stream))) ;;; Grab the FUN-INFO and enter the function, replacing any old ;;; one with the same type and note. -(defun %deftransform (name type fun &optional note important policy) +;;; Argument order is: policy constraint, ftype constraint, consequent. +;;; (think "qualifiers + specializers -> method") +(defun %deftransform (name policy type fun &optional (important :slightly)) (let* ((ctype (specifier-type type)) - (note (or note "optimize")) (info (fun-info-or-lose name)) (old (find ctype (fun-info-transforms info) :test #'type= :key #'transform-type))) (cond (old - (style-warn 'redefinition-with-deftransform - :transform old) - (setf (transform-function old) fun - (transform-note old) note + (style-warn 'redefinition-with-deftransform :transform old) + (setf (transform-%fun old) fun (transform-important old) important (transform-policy old) policy)) (t - (push (make-transform :type ctype :function fun :note note + (push (make-transform :type ctype :%fun fun :important important :policy policy) (fun-info-transforms info)))) @@ -82,35 +89,53 @@ (type-specifier ctype) ctype))) (dolist (name names) - (unless overwrite-fndb-silently - (let ((old-fun-info (info :function :info name))) - (when old-fun-info - ;; This is handled as an error because it's generally a bad - ;; thing to blow away all the old optimization stuff. It's - ;; also a potential source of sneaky bugs: - ;; DEFKNOWN FOO - ;; DEFTRANSFORM FOO - ;; DEFKNOWN FOO ; possibly hidden inside some macroexpansion - ;; ; Now the DEFTRANSFORM doesn't exist in the target Lisp. - ;; However, it's continuable because it might be useful to do - ;; it when testing new optimization stuff interactively. - (cerror "Go ahead, overwrite it." - "~@<overwriting old FUN-INFO ~2I~_~S ~I~_for ~S~:>" - old-fun-info name)))) - (setf (info :function :type name) type-to-store) - (setf (info :function :where-from name) :declared) - (setf (info :function :kind name) :function) - (setf (info :function :info name) - (make-fun-info :attributes attributes - :derive-type derive-type - :optimizer optimizer - :result-arg result-arg - :call-type-deriver call-type-deriver - :annotation annotation)) - (if location - (setf (getf (info :source-location :declaration name) 'defknown) - location) - (remf (info :source-location :declaration name) 'defknown)))) + (let ((old-fun-info (info :function :info name)) + inherit) + (block ignore + (unless overwrite-fndb-silently + (when old-fun-info + ;; This is handled as an error because it's generally a bad + ;; thing to blow away all the old optimization stuff. It's + ;; also a potential source of sneaky bugs: + ;; DEFKNOWN FOO + ;; DEFTRANSFORM FOO + ;; DEFKNOWN FOO ; possibly hidden inside some macroexpansion + ;; ; Now the DEFTRANSFORM doesn't exist in the target Lisp. + ;; However, it's continuable because it might be useful to do + ;; it when testing new optimization stuff interactively. + (restart-case + (cerror "Go ahead, overwrite it." + "~@<overwriting old FUN-INFO ~2I~_~S ~I~_for ~S~:>" + old-fun-info name) + (continue () + :report "Inherit templates and optimizers" + (setf inherit t)) + (ignore () + (return-from ignore))))) + (setf (info :function :type name) type-to-store) + (setf (info :function :where-from name) :declared) + (setf (info :function :kind name) :function) + (cond (inherit + (when optimizer + (setf (fun-info-optimizer old-fun-info) optimizer)) + (when derive-type + (setf (fun-info-derive-type old-fun-info) derive-type)) + (setf (fun-info-attributes old-fun-info) attributes + (fun-info-result-arg old-fun-info) result-arg + (fun-info-annotation old-fun-info) annotation + (fun-info-call-type-deriver old-fun-info) call-type-deriver)) + (t + (setf (info :function :info name) + (make-fun-info :attributes attributes + :derive-type derive-type + :optimizer optimizer + :result-arg result-arg + :call-type-deriver call-type-deriver + :annotation annotation)))) + (if location + (setf (getf (info :source-location :declaration name) 'defknown) + location) + (remf (info :source-location :declaration name) 'defknown)))))) names) @@ -146,6 +171,13 @@ (setq attributes (union '(unwind) attributes))) (when (member 'flushable attributes) (pushnew 'unsafely-flushable attributes)) + #-(or arm64 x86-64) ;; Needs to be supported by the call VOPs + (setf attributes (remove 'no-verify-arg-count attributes)) + #-(or arm64 x86-64) ;; Needs to be supported by the call VOPs, sb-vm::fixed-call-arg-location + (setf attributes (remove 'fixed-args attributes)) + (when (memq 'fixed-args attributes) + (pushnew 'no-verify-arg-count attributes)) + (multiple-value-bind (type annotation) (split-type-info arg-types result-type) `(%defknown ',(if (and (consp name) @@ -247,10 +279,15 @@ ;;;; generic type inference methods -(defun symeval-derive-type (node &aux (args (basic-combination-args node)) +(defun maybe-find-free-var (name) + (let ((found (gethash name (free-vars *ir1-namespace*)))) + (unless (eq found :deprecated) + found))) + +(defun symbol-value-derive-type (node &aux (args (basic-combination-args node)) (lvar (pop args))) (unless (and lvar (endp args)) - (return-from symeval-derive-type)) + (return-from symbol-value-derive-type)) (if (constant-lvar-p lvar) (let* ((sym (lvar-value lvar)) (var (maybe-find-free-var sym)) @@ -278,15 +315,6 @@ (let ((lvar (nth n (combination-args call)))) (when lvar (lvar-type lvar))))) -;;; Derive the result type according to the float contagion rules, but -;;; always return a float. This is used for irrational functions that -;;; preserve realness of their arguments. -(defun result-type-float-contagion (call) - (declare (type combination call)) - (reduce #'numeric-contagion (combination-args call) - :key #'lvar-type - :initial-value (specifier-type 'single-float))) - (defun simplify-list-type (type &key preserve-dimensions) ;; Preserve all the list types without dragging ;; (cons (eql 10)) stuff in. @@ -309,7 +337,7 @@ preserve-vector-type) (lambda (call) (declare (type combination call)) - (let ((lvar (nth (1- n) (combination-args call)))) + (let ((lvar (nth n (combination-args call)))) (when lvar (let ((type (lvar-type lvar))) (cond ((simplify-list-type type @@ -331,7 +359,7 @@ (defun result-type-specifier-nth-arg (n) (lambda (call) (declare (type combination call)) - (let ((lvar (nth (1- n) (combination-args call)))) + (let ((lvar (nth n (combination-args call)))) (when (and lvar (constant-lvar-p lvar)) (careful-specifier-type (lvar-value lvar)))))) @@ -349,7 +377,7 @@ (defun creation-result-type-specifier-nth-arg (n) (lambda (call) (declare (type combination call)) - (let ((lvar (nth (1- n) (combination-args call)))) + (let ((lvar (nth n (combination-args call)))) (when (and lvar (constant-lvar-p lvar)) (let* ((specifier (lvar-value lvar)) (lspecifier (if (atom specifier) (list specifier) specifier))) @@ -413,7 +441,7 @@ (and (proper-sequence-p value) (let ((length (length value))) (values length length)))) - (let ((max 0) (min sb-xc:array-total-size-limit)) + (let ((max 0) (min array-total-size-limit)) (block nil (labels ((max-dim (type) ;; This can deal with just enough hair to handle type STRING, @@ -427,12 +455,11 @@ (process-dim (array-type-dimensions type)))) (t (return '*)))) (process-dim (dim) - (let ((length (car dim))) - (if (and (singleton-p dim) - (integerp length)) + (if (typep dim '(cons integer null)) + (let ((length (car dim))) (setf max (max max length) - min (min min length)) - (return '*))))) + min (min min length))) + (return '*)))) ;; If type derivation were able to notice that non-simple arrays can ;; be mutated (changing the type), we could safely use LVAR-TYPE on ;; any vector type. But it doesn't notice. @@ -442,16 +469,6 @@ (max-dim (lvar-type lvar)) (values max min)))))) -(defun position-derive-type (call) - (let ((dim (sequence-lvar-dimensions (second (combination-args call))))) - (when (integerp dim) - (specifier-type `(or (integer 0 (,dim)) null))))) - -(defun count-derive-type (call) - (let ((dim (sequence-lvar-dimensions (second (combination-args call))))) - (when (integerp dim) - (specifier-type `(integer 0 ,dim))))) - ;;; This used to be done in DEFOPTIMIZER DERIVE-TYPE, but ;;; ASSERT-CALL-TYPE already asserts the ARRAY type, so it gets an extra ;;; assertion that may not get eliminated and requires extra work. @@ -479,7 +496,16 @@ (pop required) (type-intersection (pop required) - (specifier-type `(array * ,(length args))))) + (let ((rank (length args))) + (when (>= rank array-rank-limit) + (setf (combination-kind call) :error) + (compiler-warn "More subscripts for ~a (~a) than ~a (~a)" + (combination-fun-debug-name call) + rank + 'array-rank-limit + array-rank-limit) + (return-from array-call-type-deriver)) + (specifier-type `(array * ,rank))))) set) (loop for type in required do diff --git a/src/compiler/late-proclaim.lisp b/src/compiler/late-proclaim.lisp deleted file mode 100644 index 1befb99009..0000000000 --- a/src/compiler/late-proclaim.lisp +++ /dev/null @@ -1,27 +0,0 @@ -;;;; late happenning functionality for PROCLAIM. We run through -;;;; queued-up type and ftype proclaims that were made before the type -;;;; system was initialized, and (since it is now initalized) -;;;; reproclaim them. - -;;;; This software is part of the SBCL system. See the README file for -;;;; more information. -;;;; -;;;; This software is derived from the CMU CL system, which was -;;;; written at Carnegie Mellon University and released into the -;;;; public domain. The software is in the public domain and is -;;;; provided with absolutely no warranty. See the COPYING and CREDITS -;;;; files for more information. - -(in-package "SB-C") - -(!begin-collecting-cold-init-forms) - -(!cold-init-forms (aver *type-system-initialized*)) -(!cold-init-forms (mapcar #'sb-xc:proclaim *queued-proclaims*)) -;;; We only need this once, then it's set up for good. We keep it -;;; around in the cross-compiler mostly so that we can inspect its -;;; value. -#-sb-xc-host -(!cold-init-forms (makunbound '*queued-proclaims*)) - -(!defun-from-collected-cold-init-forms !late-proclaim-cold-init) diff --git a/src/compiler/lexenv.lisp b/src/compiler/lexenv.lisp deleted file mode 100644 index 2c5c5e04cf..0000000000 --- a/src/compiler/lexenv.lisp +++ /dev/null @@ -1,133 +0,0 @@ -;;;; the representation of a lexical environment - -;;;; This software is part of the SBCL system. See the README file for -;;;; more information. -;;;; -;;;; This software is derived from the CMU CL system, which was -;;;; written at Carnegie Mellon University and released into the -;;;; public domain. The software is in the public domain and is -;;;; provided with absolutely no warranty. See the COPYING and CREDITS -;;;; files for more information. - -(in-package "SB-C") - -;;; support for the idiom (in MACROEXPAND and elsewhere) that NIL is -;;; to be taken as a null lexical environment. -;;; Of course this is a mostly pointless "idiom" because NIL *is* -;;; an environment, as far as most environment inquiry functions care. -(defun coerce-to-lexenv (x) - (etypecase x - (null (make-null-lexenv)) - (lexenv x) - #+(and sb-fasteval (not sb-xc-host)) - (sb-interpreter:basic-env (sb-interpreter:lexenv-from-env x)))) - -;;; Take the lexenv surrounding an inlined function and extract things -;;; needed for the inline expansion suitable for dumping into fasls. -;;; Right now it's MACROLET, SYMBOL-MACROLET, SPECIAL and -;;; INLINE/NOTINLINE declarations. Upon encountering something else return NIL. -;;; This is later used by PROCESS-INLINE-LEXENV to reproduce the lexenv. -;;; -;;; Previously it just used the functions and vars of the innermost -;;; lexenv, but the body of macrolet can refer to other macrolets -;;; defined earlier, so it needs to process all the parent lexenvs to -;;; recover the proper order. -(defun reconstruct-lexenv (lexenv) - (let (shadowed-funs - shadowed-vars - result) - (loop for env = lexenv then parent - for parent = (lexenv-parent env) - for vars = (lexenv-vars env) - for funs = (lexenv-funs env) - for declarations = nil - for symbol-macros = nil - for macros = nil - do - (loop for binding in vars - for (name . what) = binding - unless (and parent - (find binding (lexenv-vars parent))) - do (typecase what - (cons - (aver (eq (car what) 'macro)) - (push name shadowed-vars) - (push (list name (cdr what)) symbol-macros)) - (global-var - (aver (eq (global-var-kind what) :special)) - (push `(special ,name) declarations)) - (t - (unless (memq name shadowed-vars) - (return-from reconstruct-lexenv))))) - (loop for binding in funs - for (name . what) = binding - unless (and parent - (find binding (lexenv-funs parent))) - do - (typecase what - (cons - (push name shadowed-funs) - (let ((expression (function-lambda-expression (cdr what)))) - (aver expression) - (push (cons name expression) macros))) - ;; FIXME: Is there a good reason for this not to be - ;; DEFINED-FUN (which :INCLUDEs GLOBAL-VAR, in case - ;; you're wondering how this ever worked :-)? Maybe - ;; in conjunction with an AVERrance that it's not an - ;; (AND GLOBAL-VAR (NOT GLOBAL-FUN))? -- CSR, - ;; 2002-07-08 - (global-var - (unless (defined-fun-p what) - (return-from reconstruct-lexenv)) - (push `(,(car (defined-fun-inlinep what)) - ,name) - declarations)) - (t - (unless (memq name shadowed-funs) - (return-from reconstruct-lexenv))))) - (when declarations - (setf result (list* :declare declarations (and result (list result))))) - (when symbol-macros - (setf result (list* :symbol-macro symbol-macros (and result (list result))))) - (when macros - (setf result (list* :macro macros (and result (list result))))) - while (and parent - (not (null-lexenv-p parent)))) - result)) - -;;; Return a sexpr for LAMBDA in LEXENV such that loading it from fasl -;;; preserves the original lexical environment for inlining. -;;; Return NIL if the lexical environment is too complicated. -(defun maybe-inline-syntactic-closure (lambda lexenv) - (declare (type list lambda) (type lexenv-designator lexenv)) - (aver (eql (first lambda) 'lambda)) - ;; We used to have a trivial implementation, verifying that lexenv - ;; was effectively null. However, this fails to take account of the - ;; idiom - ;; - ;; (declaim (inline foo)) - ;; (macrolet ((def (x) `(defun ,x () ...))) - ;; (def foo)) - ;; - ;; which, while too complicated for the cross-compiler to handle in - ;; unfriendly foreign lisp environments, would be good to support in - ;; the target compiler. -- CSR, 2002-05-13 and 2002-11-02 - (typecase lexenv - (lexenv - (let ((vars (lexenv-vars lexenv)) - (funs (lexenv-funs lexenv))) - (acond ((or (lexenv-blocks lexenv) (lexenv-tags lexenv)) nil) - ((and (null vars) (null funs)) lambda) - ;; If the lexenv is too hairy for cross-compilation, - ;; you'll find out later, when trying to perform inlining. - ;; This is fine, because if the inline expansion is only - ;; for the target, it's totally OK to cross-compile this - ;; defining form. The syntactic env is correctly captured. - ((reconstruct-lexenv lexenv) - `(lambda-with-lexenv ,it ,@(cdr lambda)))))) - #+(and sb-fasteval (not sb-xc-host)) - (sb-interpreter:basic-env - (awhen (sb-interpreter::reconstruct-syntactic-closure-env lexenv) - `(lambda-with-lexenv ,it ,@(cdr lambda)))) - #+sb-fasteval - (null lambda))) ; trivial case. Never occurs in the compiler. diff --git a/src/compiler/life.lisp b/src/compiler/life.lisp index efe1e98c57..6766a26ec4 100644 --- a/src/compiler/life.lisp +++ b/src/compiler/life.lisp @@ -41,16 +41,9 @@ ;;; Do the actual insertion of the conflict NEW into BLOCK's global ;;; conflicts. (defun insert-block-global-conflict (new block) - (let ((global-num (tn-number (global-conflicts-tn new)))) - (do ((prev nil conf) - (conf (ir2-block-global-tns block) - (global-conflicts-next-blockwise conf))) - ((or (null conf) - (> (tn-number (global-conflicts-tn conf)) global-num)) - (if prev - (setf (global-conflicts-next-blockwise prev) new) - (setf (ir2-block-global-tns block) new)) - (setf (global-conflicts-next-blockwise new) conf)))) + ;; This used to keep the TNs sorted by TN-NUMBER, but appears to be + ;; unnecessary. + (shiftf (global-conflicts-next-blockwise new) (ir2-block-global-tns block) new) (values)) ;;; Reset the CURRENT-CONFLICT slot in all packed TNs to point to the @@ -59,19 +52,19 @@ (do-packed-tns (tn component) (setf (tn-current-conflict tn) (tn-global-conflicts tn)))) -;;; Cache the results of BLOCK-PHYSENV during lifetime analysis. +;;; Cache the results of BLOCK-ENVIRONMENT during lifetime analysis. ;;; -;;; Fetching the home-lambda of a block (needed in block-physenv) can +;;; Fetching the home-lambda of a block (needed in block-environment) can ;;; be an expensive operation under some circumstances, and it needs ;;; to be done a lot during lifetime analysis when compiling with high ;;; DEBUG (e.g. 30% of the total compilation time for CL-PPCRE with ;;; DEBUG 3 just for that). -(defun cached-block-physenv (block) - (let ((physenv (block-physenv-cache block))) - (if (eq physenv :none) - (setf (block-physenv-cache block) - (block-physenv block)) - physenv))) +(defun cached-block-environment (block) + (let ((env (block-environment-cache block))) + (if (eq env :none) + (setf (block-environment-cache block) + (block-environment block)) + env))) ;;;; pre-pass @@ -312,20 +305,11 @@ ((null op)) (let ((tn (tn-ref-tn op))) (unless (member (tn-kind tn) '(:unused :constant)) - (assert - (flet ((frob (refs) - (do ((ref refs (tn-ref-next ref))) - ((null ref) t) - (when (and (eq (vop-block (tn-ref-vop ref)) block) - (not (eq ref op))) - (return nil))))) - (and (frob (tn-reads tn)) (frob (tn-writes tn)))) - () "More operand ~S used more than once in its VOP." op) - (aver (not (find-in #'global-conflicts-next-blockwise tn - (ir2-block-global-tns block) - :key #'global-conflicts-tn))) - - (add-global-conflict :read-only tn block num) + ;; A TN could be used more than once in :more. + (unless (find-in #'global-conflicts-next-blockwise tn + (ir2-block-global-tns block) + :key #'global-conflicts-tn) + (add-global-conflict :read-only tn block num)) (setf (tn-local tn) block) (setf (tn-local-number tn) num))))) (values)) @@ -370,27 +354,27 @@ (clear-lifetime-info 2block) (cond - ((vop-next lose) - (aver (not (eq last-lose lose))) - (let ((new (split-ir2-blocks 2block lose (incf counter)))) - (aver (not (find-local-references new))) - (init-global-conflict-kind new))) - (t - (aver (not (eq lose coalesced))) - (setq coalesced lose) - (event coalesce-more-ltn-numbers (vop-node lose)) - (let ((info (vop-info lose)) - (new (if (vop-prev lose) - (split-ir2-blocks 2block (vop-prev lose) - (incf counter)) - 2block))) - (coalesce-more-ltn-numbers new (vop-args lose) - (vop-info-arg-types info)) - (coalesce-more-ltn-numbers new (vop-results lose) - (vop-info-result-types info)) - (let ((lose (find-local-references new))) - (aver (not lose))) - (init-global-conflict-kind new)))))))) + ((vop-next lose) + (aver (not (eq last-lose lose))) + (let ((new (split-ir2-blocks 2block lose (incf counter)))) + (aver (not (find-local-references new))) + (init-global-conflict-kind new))) + (t + (aver (not (eq lose coalesced))) + (setq coalesced lose) + (event coalesce-more-ltn-numbers (vop-node lose)) + (let ((info (vop-info lose)) + (new (if (vop-prev lose) + (split-ir2-blocks 2block (vop-prev lose) + (incf counter)) + 2block))) + (coalesce-more-ltn-numbers new (vop-args lose) + (vop-info-arg-types info)) + (coalesce-more-ltn-numbers new (vop-results lose) + (vop-info-result-types info)) + (let ((lose (find-local-references new))) + (aver (not lose))) + (init-global-conflict-kind new)))))))) (values)) @@ -441,14 +425,14 @@ ;;; TN. We make the TN global if it isn't already. The TN must have at ;;; least one reference. (defun setup-environment-tn-conflicts (component tn env debug-p) - (declare (type component component) (type tn tn) (type physenv env)) + (declare (type component component) (type tn tn) (type environment env)) (when (and debug-p (not (tn-global-conflicts tn)) (tn-local tn)) (convert-to-global tn)) (setf (tn-current-conflict tn) (tn-global-conflicts tn)) (do-blocks-backwards (block component) - (when (eq (cached-block-physenv block) env) + (when (eq (cached-block-environment block) env) (let* ((2block (block-info block)) (last (do ((b (ir2-block-next 2block) (ir2-block-next b)) (prev 2block b)) @@ -462,14 +446,14 @@ ;;; Implicit value cells are allocated on the stack and local ;;; functions can access closed over values of the parent function ;;; that way, but when the parent function tail calls a local function -;;; its physenv ceases to exist, yet the indirect TNs should still be -;;; accessible within the tail-called function. -;;; Find all the users of the TN, returning their physenvs, in wich -;;; the TN should be marked as live. +;;; its environment ceases to exist, yet the indirect TNs should still +;;; be accessible within the tail-called function. Find all the users +;;; of the TN, returning their environments, in which the TN should be +;;; marked as live. (defun find-implicit-value-cell-users (home-env tn) (let (result) (labels ((recur (lambda) - (let ((env (lambda-physenv lambda))) + (let ((env (lambda-environment lambda))) (unless (or (eq env home-env) (memq env result)) (push env result) @@ -486,39 +470,39 @@ (defun setup-environment-live-conflicts (component) (declare (type component component)) (dolist (fun (component-lambdas component)) - (let* ((env (lambda-physenv fun)) - (2env (physenv-info env))) - (dolist (tn (ir2-physenv-live-tns 2env)) + (let* ((env (lambda-environment fun)) + (2env (environment-info env))) + (dolist (tn (ir2-environment-live-tns 2env)) (setup-environment-tn-conflicts component tn env nil) (when (implicit-value-cell-tn-p tn) (loop for env in (find-implicit-value-cell-users env tn) ;; See the comment above FIND-IMPLICIT-VALUE-CELL-USERS - when (memq (physenv-lambda env) + when (memq (environment-lambda env) (tail-set-funs (lambda-tail-set fun))) do (setup-environment-tn-conflicts component tn env nil)))) - (dolist (tn (ir2-physenv-debug-live-tns 2env)) + (dolist (tn (ir2-environment-debug-live-tns 2env)) (setup-environment-tn-conflicts component tn env t)))) (values)) ;;; Convert a :NORMAL or :DEBUG-ENVIRONMENT TN to an :ENVIRONMENT TN. -;;; This requires adding :LIVE conflicts to all blocks in TN-PHYSENV. -(defun convert-to-environment-tn (tn tn-physenv) - (declare (type tn tn) (type physenv tn-physenv)) +;;; This requires adding :LIVE conflicts to all blocks in TN-ENV. +(defun convert-to-environment-tn (tn tn-env) + (declare (type tn tn) (type environment tn-env)) (aver (member (tn-kind tn) '(:normal :debug-environment))) (ecase (tn-kind tn) (:debug-environment - (setq tn-physenv (tn-physenv tn)) - (let* ((2env (physenv-info tn-physenv))) - (setf (ir2-physenv-debug-live-tns 2env) - (delete tn (ir2-physenv-debug-live-tns 2env))))) + (setq tn-env (tn-environment tn)) + (let* ((2env (environment-info tn-env))) + (setf (ir2-environment-debug-live-tns 2env) + (delete tn (ir2-environment-debug-live-tns 2env))))) (:normal (setf (tn-local tn) nil) (setf (tn-local-number tn) nil))) - (setup-environment-tn-conflicts *component-being-compiled* tn tn-physenv nil) + (setup-environment-tn-conflicts *component-being-compiled* tn tn-env nil) (setf (tn-kind tn) :environment) - (setf (tn-physenv tn) tn-physenv) - (push tn (ir2-physenv-live-tns (physenv-info tn-physenv))) + (setf (tn-environment tn) tn-env) + (push tn (ir2-environment-live-tns (environment-info tn-env))) (values)) ;;;; flow analysis @@ -706,7 +690,7 @@ (num (global-conflicts-number conf))) (when (and num (zerop (sbit live-bits num)) (eq (tn-kind tn) :debug-environment) - (eq (tn-physenv tn) (cached-block-physenv 1block)) + (eq (tn-environment tn) (cached-block-environment 1block)) (saved-after-read tn block)) (note-conflicts live-bits live-list tn num) (setf (sbit live-bits num) 1) @@ -778,7 +762,7 @@ (unless (eq (tn-kind tn) :environment) (convert-to-environment-tn tn - (cached-block-physenv (ir2-block-block block)))))))) + (cached-block-environment (ir2-block-block block)))))))) (values)) ;;; This is used in SCAN-VOP-REFS to simultaneously do something to @@ -1024,16 +1008,16 @@ (values)) ;;; On high debug levels, for all variables that a lambda closes over -;;; convert the TNs to :ENVIRONMENT TNs (in the physical environment -;;; of that lambda). This way the debugger can display the variables. +;;; convert the TNs to :ENVIRONMENT TNs (in the environment of that +;;; lambda). This way the debugger can display the variables. (defun maybe-environmentalize-closure-tns (component) (dolist (lambda (component-lambdas component)) (when (policy lambda (>= debug 2)) - (let ((physenv (lambda-physenv lambda))) - (dolist (closure-var (physenv-closure physenv)) - (let ((tn (find-in-physenv closure-var physenv))) + (let ((env (lambda-environment lambda))) + (dolist (closure-var (environment-closure env)) + (let ((tn (find-in-environment closure-var env))) (when (member (tn-kind tn) '(:normal :debug-environment)) - (convert-to-environment-tn tn physenv)))))))) + (convert-to-environment-tn tn env)))))))) (defun lifetime-analyze (component) diff --git a/src/compiler/locall.lisp b/src/compiler/locall.lisp index 69625e5b2b..9e4bc273c9 100644 --- a/src/compiler/locall.lisp +++ b/src/compiler/locall.lisp @@ -21,6 +21,13 @@ (in-package "SB-C") +(defstruct (local-call-context + (:constructor make-local-call-context (fun var)) + (:copier nil)) + (fun nil :read-only t) + (var nil :read-only t)) +(!set-load-form-method local-call-context (:xc :target) :ignore-it) + ;;; This function propagates information from the variables in the ;;; function FUN to the actual arguments in CALL. This is also called ;;; by the VALUES IR1 optimizer when it sleazily converts MV-BINDs to @@ -36,42 +43,54 @@ (declare (type combination call) (type clambda fun)) (loop with policy = (lexenv-policy (node-lexenv call)) for args on (basic-combination-args call) - and var in (lambda-vars fun) + for var in (lambda-vars fun) + for name = (lambda-var-%source-name var) do (assert-lvar-type (car args) (leaf-type var) policy - (lambda-var-%source-name var)) - do (unless (leaf-refs var) + (if (eq (functional-kind fun) :optional) + (make-local-call-context fun name) + name)) + (unless (leaf-refs var) (flush-dest (car args)) (setf (car args) nil))) (values)) +;;; Given a local call CALL to FUN, find the associated argument LVARs +;;; of CALL corresponding to declared dynamic extent LAMBDA-VARs and +;;; note them as dynamic extent LVARs. This operation is transitive, +;;; because dynamic extent is contagious. In particular, the arguments +;;; of any COMBINATIONs returning a stack-allocatable object in a +;;; dynamic extent LVAR are dynamic extent as well if the argument +;;; LVARs contain otherwise-inaccessible stack-allocatable subobjects +;;; themselves. (defun recognize-dynamic-extent-lvars (call fun) (declare (type combination call) (type clambda fun)) - (loop for arg in (basic-combination-args call) - for var in (lambda-vars fun) - for dx = (leaf-dynamic-extent var) - when (and dx arg (not (lvar-dynamic-extent arg))) - append (handle-nested-dynamic-extent-lvars dx arg) into dx-lvars - ;; The block may end up being deleted due to cast optimization - ;; caused by USE-GOOD-FOR-DX-P - when (node-to-be-deleted-p call) return nil - finally (when dx-lvars - ;; Stack analysis requires that the CALL ends the block, so - ;; that MAP-BLOCK-NLXES sees the cleanup we insert here. - (node-ends-block call) - (let* ((entry (with-ir1-environment-from-node call - (make-entry))) - (cleanup (make-cleanup :kind :dynamic-extent - :mess-up entry - :info dx-lvars - :lexenv (lambda-lexenv fun)))) - (setf (entry-cleanup entry) cleanup) - (insert-node-before call entry) - (setf (node-lexenv call) - (make-lexenv :default (node-lexenv call) - :cleanup cleanup)) - (push entry (lambda-entries (node-home-lambda entry))) - (dolist (cell dx-lvars) - (setf (lvar-dynamic-extent (cdr cell)) cleanup))))) + ;; The block may end up being deleted due to cast optimization + ;; caused by USE-GOOD-FOR-DX-P + (unless (node-to-be-deleted-p call) + (let* ((*dx-lexenv* (node-lexenv call)) + (dx-lvars + (loop for arg in (basic-combination-args call) + for var in (lambda-vars fun) + for dx = (leaf-dynamic-extent var) + when (and dx arg (not (lvar-dynamic-extent arg))) + append (handle-nested-dynamic-extent-lvars dx arg)))) + (when dx-lvars + (let* ((entry (with-ir1-environment-from-node call + (make-entry))) + (cleanup (make-cleanup :kind :dynamic-extent + :mess-up entry + :nlx-info dx-lvars))) + (setf (entry-cleanup entry) cleanup) + (insert-node-before call entry) + (setf (node-lexenv call) + (make-lexenv :default (node-lexenv call) + :cleanup cleanup)) + ;; Make CALL end its block, so that we have a place to + ;; insert cleanup code. + (node-ends-block call) + (push entry (lambda-entries (node-home-lambda entry))) + (dolist (cell dx-lvars) + (setf (lvar-dynamic-extent (cdr cell)) cleanup)))))) (values)) ;;; This function handles merging the tail sets if CALL is potentially @@ -159,13 +178,21 @@ (clambda (let* ((n-supplied (gensym)) (nargs (length (lambda-vars fun))) - (temps (make-gensym-list nargs))) + (temps (make-gensym-list nargs)) + (info (info :function :info (functional-%source-name fun))) + (types (and info + (ir1-attributep (fun-info-attributes info) fixed-args) + (loop for var in (lambda-vars fun) + for temp in temps + collect `(type ,(type-specifier (lambda-var-type var)) ,temp))))) + `(lambda (,n-supplied ,@temps) (declare (type index ,n-supplied) - (ignore ,n-supplied)) + (ignore ,n-supplied) + ,@types) (%funcall ,fun ,@temps)))) (optional-dispatch - ;; Force convertion of all entries + ;; Force conversion of all entries (optional-dispatch-entry-point-fun fun 0) (let* ((min (optional-dispatch-min-args fun)) (max (optional-dispatch-max-args fun)) @@ -263,10 +290,14 @@ (declare (type functional fun)) (aver (null (functional-entry-fun fun))) (with-ir1-environment-from-node (lambda-bind (main-entry fun)) - (let ((xep (ir1-convert-lambda (make-xep-lambda-expression fun) - :debug-name (debug-name - 'xep (leaf-debug-name fun)) - :system-lambda t))) + (let* ((*lexenv* (if (neq (lexenv-policy (functional-lexenv fun)) + (lexenv-policy *lexenv*)) + (make-lexenv :policy (lexenv-policy (functional-lexenv fun))) + *lexenv*)) + (xep (ir1-convert-lambda (make-xep-lambda-expression fun) + :debug-name (debug-name + 'xep (leaf-debug-name fun)) + :system-lambda t))) (setf (functional-kind xep) :external (leaf-ever-used xep) t (functional-entry-fun xep) fun @@ -379,7 +410,8 @@ (push fun (component-lambdas component))) (locall-analyze-fun-1 fun) (when (lambda-p fun) - (maybe-let-convert fun component))))))) + (or (maybe-let-convert fun component) + (maybe-convert-to-assignment fun)))))))) (values)) (defun locall-analyze-clambdas-until-done (clambdas) @@ -416,9 +448,9 @@ (multiple-value-bind (losing-local-object converted-lambda) (catch 'locall-already-let-converted (with-ir1-environment-from-node call - (let ((*inline-expansions* - (register-inline-expansion original-functional call)) - (*lexenv* (functional-lexenv original-functional))) + (let* ((*inline-expansions* + (register-inline-expansion original-functional call)) + (*lexenv* (functional-lexenv original-functional))) (values nil (ir1-convert-lambda (functional-inline-expansion original-functional) @@ -498,7 +530,7 @@ (setq fun (maybe-expand-local-inline fun ref call))) (aver (member (functional-kind fun) - '(nil :escape :cleanup :optional))) + '(nil :escape :cleanup :optional :assignment))) (cond ((mv-combination-p call) (convert-mv-call ref call fun)) ((lambda-p fun) @@ -928,10 +960,10 @@ ;; information. (setf (tail-set-info (lambda-tail-set clambda)) nil)) -;;; Handle the PHYSENV semantics of LET conversion. We add CLAMBDA and -;;; its LETs to LETs for the CALL's home function. We merge the calls -;;; for CLAMBDA with the calls for the home function, removing CLAMBDA -;;; in the process. We also merge the ENTRIES. +;;; Handle the environment semantics of LET conversion. We add CLAMBDA +;;; and its LETs to LETs for the CALL's home function. We merge the +;;; calls for CLAMBDA with the calls for the home function, removing +;;; CLAMBDA in the process. We also merge the ENTRIES. ;;; ;;; We also unlink the function head from the component head and set ;;; COMPONENT-REANALYZE to true to indicate that the DFO should be @@ -950,28 +982,28 @@ (depart-from-tail-set clambda) (let* ((home (node-home-lambda call)) - (home-physenv (lambda-physenv home)) - (physenv (lambda-physenv clambda))) + (home-env (lambda-environment home)) + (env (lambda-environment clambda))) (aver (not (eq home clambda))) ;; CLAMBDA belongs to HOME now. (push clambda (lambda-lets home)) (setf (lambda-home clambda) home) - (setf (lambda-physenv clambda) home-physenv) + (setf (lambda-environment clambda) home-env) - (when physenv - (unless home-physenv - (setf home-physenv (get-lambda-physenv home))) - (setf (physenv-nlx-info home-physenv) - (nconc (physenv-nlx-info physenv) - (physenv-nlx-info home-physenv)))) + (when env + (unless home-env + (setf home-env (get-lambda-environment home))) + (setf (environment-nlx-info home-env) + (nconc (environment-nlx-info env) + (environment-nlx-info home-env)))) ;; All of CLAMBDA's LETs belong to HOME now. (let ((lets (lambda-lets clambda))) (dolist (let lets) (setf (lambda-home let) home) - (setf (lambda-physenv let) home-physenv)) + (setf (lambda-environment let) home-env)) (setf (lambda-lets home) (nconc lets (lambda-lets home)))) ;; CLAMBDA no longer has an independent existence as an entity ;; which has LETs. @@ -1024,10 +1056,13 @@ (return-result (lambda-return (node-home-lambda call))) (node-lvar call))) (call-type (node-derived-type call))) - (unless (eq call-type *wild-type*) - ;; FIXME: Replace the call with unsafe CAST. -- APD, 2003-01-26 - (do-uses (use result) - (derive-node-type use call-type))) + ;; FIXME: Replace the call with unsafe CAST. -- APD, 2003-01-26 + (do-uses (use result) + ;; CRETURN is an unknown value destination, now the + ;; destination might be consuming just one value. + ;; Reoptimize to help the VALUES transform, for example. + (reoptimize-node use) + (derive-node-type use call-type)) (substitute-lvar-uses lvar result (and lvar (eq (lvar-uses lvar) call))))) @@ -1040,32 +1075,42 @@ ;;; the RETURN-RESULT, because the return might have been deleted (if ;;; all calls were TR.) (defun unconvert-tail-calls (fun call next-block) - (do-sset-elements (called (lambda-calls-or-closes fun)) - (when (lambda-p called) - (dolist (ref (leaf-refs called)) - (let ((this-call (node-dest ref))) - (when (and this-call - (node-tail-p this-call) - (not (node-to-be-deleted-p this-call)) - (eq (node-home-lambda this-call) fun)) - (setf (node-tail-p this-call) nil) - (ecase (functional-kind called) - ((nil :cleanup :optional) - (let ((block (node-block this-call)) - (lvar (node-lvar call))) - (unlink-blocks block (first (block-succ block))) - (link-blocks block next-block) - (if (eq (node-derived-type this-call) *empty-type*) - (maybe-terminate-block this-call nil) - (add-lvar-use this-call lvar)))) - (:deleted) - ;; The called function might be an assignment in the - ;; case where we are currently converting that function. - ;; In steady-state, assignments never appear as a called - ;; function. - (:assignment - (aver (eq called fun))))))))) - (values)) + (let (maybe-terminate) + (do-sset-elements (called (lambda-calls-or-closes fun)) + (when (lambda-p called) + (dolist (ref (leaf-refs called)) + (let ((this-call (node-dest ref))) + (when (and this-call + (node-tail-p this-call) + (not (node-to-be-deleted-p this-call)) + (eq (node-home-lambda this-call) fun)) + (setf (node-tail-p this-call) nil) + (ecase (functional-kind called) + ((nil :cleanup :optional) + (let ((block (node-block this-call)) + (lvar (node-lvar call))) + (unlink-blocks block (first (block-succ block))) + (link-blocks block next-block) + (if (eq (node-derived-type this-call) *empty-type*) + ;; Delay terminating the block, because there may be more calls + ;; to be processed here and this may prematurely delete NEXT-BLOCK + ;; before we attach more preceding blocks to it. + ;; Although probably if one call to a function + ;; is derived to be NIL all other calls would + ;; be NIL too, but that may not be available at the same time. + ;; (Or something is smart in the future to + ;; derive different results from different + ;; calls.) + (push this-call maybe-terminate) + (add-lvar-use this-call lvar)))) + (:deleted) + ;; The called function might be an assignment in the + ;; case where we are currently converting that function. + ;; In steady-state, assignments never appear as a called + ;; function. + (:assignment + (aver (eq called fun))))))))) + maybe-terminate)) ;;; Deal with returning from a LET or assignment that we are ;;; converting. FUN is the function we are calling, CALL is a call to @@ -1093,22 +1138,17 @@ (defun move-return-stuff (fun call next-block) (declare (type clambda fun) (type basic-combination call) (type (or cblock null) next-block)) - (when next-block - (unconvert-tail-calls fun call next-block)) - (let* ((return (lambda-return fun)) + (let* ((maybe-terminate-calls (when next-block + (unconvert-tail-calls fun call next-block))) + (return (lambda-return fun)) (call-fun (node-home-lambda call)) (call-return (lambda-return call-fun))) (when (and call-return (block-delete-p (node-block call-return))) (flush-dest (return-result call-return)) (delete-return call-return) - ;; A new return will be put into that lambda, don't want - ;; DELETE-RETURN called by DELETE-BLOCK to delete the new return - ;; from the lambda. - ;; (Previously, UNLINK-NODE was called on the return, but it - ;; doesn't work well on deleted blocks) - (setf (return-lambda call-return) nil - call-return nil)) + (unlink-node call-return) + (setq call-return nil)) (cond ((not return)) ((or next-block call-return) (unless (block-delete-p (node-block return)) @@ -1120,8 +1160,11 @@ (aver (node-tail-p call)) (setf (lambda-return call-fun) return) (setf (return-lambda return) call-fun) - (setf (lambda-return fun) nil)))) - (delete-lvar-use call) ; LET call does not have value semantics + (setf (lambda-return fun) nil))) + ;; Delayed because otherwise next-block could become deleted + (dolist (call maybe-terminate-calls) + (maybe-terminate-block call nil))) + (delete-lvar-use call) ; LET call does not have value semantics (values)) ;;; Actually do LET conversion. We call subfunctions to do most of the @@ -1137,11 +1180,7 @@ next-block))) (move-return-stuff fun call next-block) (merge-lets fun call) - (setf (node-tail-p call) nil) - ;; If CALL has a derive type NIL, it means that "its return" is - ;; unreachable, but the next BIND is still reachable; in order to - ;; not confuse MAYBE-TERMINATE-BLOCK... - (setf (node-derived-type call) *wild-type*))) + (setf (node-tail-p call) nil))) ;;; Reoptimize all of CALL's args and its result. (defun reoptimize-call (call) @@ -1169,11 +1208,10 @@ (not (functional-inline-expanded clambda))) ;; ANSI requires that explicit NOTINLINE be respected. (or (eq (lambda-inlinep clambda) 'notinline) - ;; If (= LET-CONVERSION 0) we can guess that inlining - ;; generally won't be appreciated, but if the user - ;; specifically requests inlining, that takes precedence over - ;; our general guess. - (and (policy clambda (= let-conversion 0)) + ;; If (= LET-CONVERSION 0) or (= DEBUG 3) we can guess that inlining + ;; generally won't be appreciated, but if the user specifically requests + ;; inlining, that takes precedence over our general guess. + (and (or (policy clambda (or (= let-conversion 0) (= debug 3)))) (not (eq (lambda-inlinep clambda) 'inline)))))) ;;; We also don't convert calls to named functions which appear in the @@ -1346,53 +1384,123 @@ (values t (maybe-convert-to-assignment fun)))))) ;;; This is called when we believe it might make sense to convert -;;; CLAMBDA to an assignment. All this function really does is +;;; FUN to an assignment. All this function really does is ;;; determine when a function with more than one call can still be ;;; combined with the calling function's environment. We can convert ;;; when: ;;; -- The function is a normal, non-entry function, and -;;; -- Except for one call, all calls must be tail recursive calls -;;; in the called function (i.e. are self-recursive tail calls) +;;; -- All calls must return to the same place, so some +;;; may be tail recursive calls in the called function (i.e. are +;;; self-recursive tail calls) ;;; -- OK-INITIAL-CONVERT-P is true. ;;; -;;; There may be one outside call, and it need not be tail-recursive. -;;; Since all tail local calls have already been converted to direct -;;; transfers, the only control semantics needed are to splice in the -;;; body at the non-tail call. If there is no non-tail call, then we -;;; need only merge the environments. Both cases are handled by -;;; LET-CONVERT. +;;; There may be any number of outside calls, and they need not be +;;; tail-recursive. The only constraint is that they return to the +;;; same place (taking into account cleanup actions). Note that in +;;; particular, this is also satisfied when the calls to FUN are +;;; derived to not return at all. Since all tail local calls have +;;; already been converted to direct transfers, the only control +;;; semantics needed are to splice in the body at some non-tail +;;; call. If there is no non-tail call, then we need only merge the +;;; environments. Both cases are handled by LET-CONVERT. ;;; ;;; ### It would actually be possible to allow any number of outside ;;; calls as long as they all return to the same place (i.e. have the -;;; same conceptual continuation.) A special case of this would be -;;; when all of the outside calls are tail recursive. -(defun maybe-convert-to-assignment (clambda) - (declare (type clambda clambda)) - (when (and (not (functional-kind clambda)) - (not (functional-entry-fun clambda)) - (not (functional-has-external-references-p clambda))) - (let ((outside-non-tail-call nil) - (outside-call nil)) - (when (and (dolist (ref (leaf-refs clambda) t) +;;; same conceptual continuation.) Some currently unhandled cases of +;;; this are outside tail calls from multiple functions which +;;; themselves return to the same place transitively. The paper +;;; "Contification using dominators" by Fluet and Weeks describes a +;;; maximal algorithm for detecting all such calls returning to the +;;; same place. +(defun maybe-convert-to-assignment (fun) + (declare (type clambda fun)) + (when (and (not (functional-kind fun)) + (not (functional-entry-fun fun)) + (not (functional-has-external-references-p fun)) + ;; If a functional is explicitly inlined, we don't want + ;; to assignment convert it, as more call-site + ;; specialization can be done with inlining. + (not (functional-inlinep fun)) + (not (block-delete-p (lambda-block fun)))) + (let ((outside-calls nil) + (outside-calls-ctran nil) + (outside-calls-env nil) + (outside-calls-cleanup nil)) + (when (and (dolist (ref (leaf-refs fun) t) (let ((dest (node-dest ref))) (when (or (not dest) (node-to-be-deleted-p ref) (node-to-be-deleted-p dest)) (return nil)) (let ((home (node-home-lambda ref))) - (unless (eq home clambda) - (when outside-call - (return nil)) - (setq outside-call dest)) - (unless (node-tail-p dest) - (when (or outside-non-tail-call (eq home clambda)) - (return nil)) - (setq outside-non-tail-call dest))))) - (ok-initial-convert-p clambda)) - (cond (outside-call (setf (functional-kind clambda) :assignment) - (let-convert clambda outside-call) - (when outside-non-tail-call - (reoptimize-call outside-non-tail-call)) - t) - (t (delete-lambda clambda) - nil)))))) + (if (eq home fun) + (unless (node-tail-p dest) + (return nil)) + (let ((dest-ctran + (or (node-next dest) + (block-start (first (block-succ (node-block dest)))))) + (dest-env + (node-home-lambda dest)) + (dest-cleanup + (node-enclosing-cleanup dest))) + (aver dest-env) + (cond (outside-calls-env + ;; We can only convert multiple + ;; outside calls when they are all + ;; in the same environment, so we + ;; don't muck up tail sets. This + ;; is not a conceptual restriction + ;; though; it may be possible to + ;; lift this if things are + ;; reworked. The cleanup checking + ;; here is also overly + ;; conservative. A better approach + ;; would be to check for harmful + ;; cleanups with respect to the + ;; messiest common ancestor. + (unless (and (or (eq (node-derived-type dest) *empty-type*) + (and (eq outside-calls-ctran dest-ctran))) + (eq outside-calls-env dest-env) + (eq outside-calls-cleanup dest-cleanup)) + (return nil))) + (t + (setq outside-calls-env dest-env) + (setq outside-calls-ctran dest-ctran) + (setq outside-calls-cleanup dest-cleanup))) + (push dest outside-calls)))))) + (ok-initial-convert-p fun)) + (cond (outside-calls + (setf (functional-kind fun) :assignment) + ;; The only time OUTSIDE-CALLS contains a mix of both + ;; tail and non-tail calls is when calls to FUN are + ;; derived to not return, in which case it doesn't + ;; matter whether a given call is tail, so there is no + ;; harm in the arbitrary choice here. + (let ((first-outside-call (first outside-calls))) + (let ((original-tail-p (node-tail-p first-outside-call))) + (let-convert fun first-outside-call) + (unless original-tail-p + (reoptimize-call first-outside-call))) + (dolist (outside-call outside-calls) + ;; Splice in the other calls, without the rest of + ;; the let converting return semantics machinery, + ;; since we've already let converted the function. + (unless (eq outside-call first-outside-call) + (insert-let-body fun outside-call)) + (delete-lvar-use outside-call) + ;; Make sure these calls are local converted as + ;; soon as possible, to avoid having a window of + ;; time where there are :ASSIGNMENT lambdas + ;; floating around which are still called by :FULL + ;; combinations, as this confuses stuff like + ;; MAYBE-TERMINATE-BLOCK. + (convert-call-if-possible (lvar-use (combination-fun outside-call)) + outside-call) + (unless (or (eq outside-call first-outside-call) + (node-tail-p outside-call)) + (reoptimize-call first-outside-call)) + (setf (node-tail-p outside-call) nil))) + t) + (t + (delete-lambda fun) + nil)))))) diff --git a/src/compiler/loop.lisp b/src/compiler/loop.lisp index 02a1fa42a9..83c9bd0453 100644 --- a/src/compiler/loop.lisp +++ b/src/compiler/loop.lisp @@ -41,11 +41,13 @@ (setq dom (copy-sset pdom) changed t))))) (setf (block-dominators block) dom) (when dom (sset-adjoin block dom)))) - (unless changed (return))))) + (unless changed (return))) + (setf (component-dominators-computed component) t))) (defun clear-dominators (component) (do-blocks (block component) - (setf (block-dominators block) nil))) + (setf (block-dominators block) nil)) + (setf (component-dominators-computed component) nil)) ;;; DOMINATES-P -- Internal ;;; diff --git a/src/compiler/ltn.lisp b/src/compiler/ltn.lisp index ea6c6d05b8..8d33059cbe 100644 --- a/src/compiler/ltn.lisp +++ b/src/compiler/ltn.lisp @@ -95,7 +95,7 @@ (link-blocks node-block next-block))) ;;; an annotated lvar's primitive-type -#-sb-fluid (declaim (inline lvar-ptype)) +(declaim (inline lvar-ptype)) (defun lvar-ptype (lvar) (declare (type lvar lvar)) (ir2-lvar-primitive-type (lvar-info lvar))) @@ -162,16 +162,16 @@ (values)) #+call-symbol -(defoptimizer (%coerce-callable-for-call ltn-annotate) ((fun) node ltn-policy) - (declare (ignore ltn-policy)) - (let ((dest (node-dest node))) +(defoptimizer (%coerce-callable-for-call ltn-annotate) ((fun) node) + (multiple-value-bind (dest dest-lvar) + (and (node-lvar node) + (principal-lvar-dest-and-lvar (node-lvar node))) (cond ((and (basic-combination-p dest) (eq (basic-combination-kind dest) :full) - (eq (lvar-uses (basic-combination-fun dest)) node) + (eq (basic-combination-fun dest) dest-lvar) ;; Everything else can't handle NIL, just don't ;; bother optimizing it. - (not (and (constant-lvar-p fun) - (null (lvar-value fun))))) + (not (lvar-value-is-nil fun))) (setf (basic-combination-fun dest) fun (basic-combination-args node) '(nil) (node-lvar node) nil @@ -198,6 +198,11 @@ (setf (node-tail-p call) nil)))) (values)) +(defun signal-delayed-combination-condition (call) + (let ((*compiler-error-context* call) + (delayed (combination-info call))) + (apply #'funcall delayed))) + ;;; We set the kind to :FULL or :FUNNY, depending on whether there is ;;; an IR2-CONVERT method. If a funny function, then we inhibit tail ;;; recursion normally, since the IR2 convert method is going to want @@ -225,6 +230,8 @@ (setf (node-tail-p call) nil)) (t (when (eq kind :error) + (when (basic-combination-info call) + (signal-delayed-combination-condition call)) (setf (basic-combination-kind call) :full)) (setf (basic-combination-info call) :full) (rewrite-full-call call)))) @@ -369,13 +376,13 @@ (primitive-types)) (let ((n-values (nth-value 1 (values-types (lvar-derived-type arg))))) - (loop for (prim-type . lvar-type) = (pop types) - repeat n-values + (loop repeat n-values do - (primitive-types (or prim-type - *backend-t-primitive-type*)) - (lvar-types (or lvar-type - *universal-type*))) + (destructuring-bind (&optional prim-type . lvar-type) (pop types) + (primitive-types (or prim-type + *backend-t-primitive-type*)) + (lvar-types (or lvar-type + *universal-type*)))) (annotate-fixed-values-lvar arg (primitive-types) (lvar-types)))))))) @@ -456,6 +463,7 @@ (let* ((test (if-test node)) (use (lvar-uses test))) (unless (and (combination-p use) + (immediately-used-p test use) (let ((info (basic-combination-info use))) (and (template-p info) (template-conditional-p info)))) @@ -469,9 +477,21 @@ (setf (node-tail-p node) nil) (let ((value (exit-value node))) (when value - (annotate-unknown-values-lvar value))) + (if (lvar-single-value-p (node-lvar node)) + (annotate-fixed-values-lvar value (list *backend-t-primitive-type*)) + (annotate-unknown-values-lvar value)))) (values)) +(defun ltn-analyze-enclose (node) + (declare (type enclose node)) + (let ((lvar (node-lvar node))) + (when lvar ; only DX encloses use lvars. + (let ((info (make-ir2-lvar *backend-t-primitive-type*))) + (setf (lvar-info lvar) info) + (setf (ir2-lvar-kind info) :delayed) + (setf (ir2-lvar-stack-pointer info) + (make-stack-pointer-tn)))))) + ;;; We need a special method for %UNWIND-PROTECT that ignores the ;;; cleanup function. We don't annotate either arg, since we don't ;;; need them at run-time. @@ -479,24 +499,17 @@ ;;; (The default is o.k. for %CATCH, since environment analysis ;;; converted the reference to the escape function into a constant ;;; reference to the NLX-INFO.) -(defoptimizer (%unwind-protect ltn-annotate) ((escape cleanup) - node - ltn-policy) - (declare (ignore escape cleanup ltn-policy)) +(defoptimizer (%unwind-protect ltn-annotate) ((escape cleanup) node) (setf (basic-combination-info node) :funny) (setf (node-tail-p node) nil)) ;;; Make sure that arguments of magic functions are not annotated. ;;; (Otherwise the compiler may dump its internal structures as ;;; constants :-() -(defoptimizer (%pop-values ltn-annotate) ((%lvar) node ltn-policy) - (declare (ignore %lvar node ltn-policy))) -(defoptimizer (%dummy-dx-alloc ltn-annotate) ((target source) node ltn-policy) - (declare (ignore target source node ltn-policy))) - -(defoptimizer (%nip-values ltn-annotate) ((&rest lvars) - node ltn-policy) - (declare (ignore node ltn-policy)) +(defoptimizer (%pop-values ltn-annotate) ((%lvar))) +(defoptimizer (%dummy-dx-alloc ltn-annotate) ((target source))) + +(defoptimizer (%nip-values ltn-annotate) ((&rest lvars)) ;; Undo the optimization performed by LTN-ANALYZE-MV-CALL, ;; which only uses the CSP of the first argument. (loop for lvar-lvar in lvars @@ -535,7 +548,13 @@ (funcall (second type) value) (sb-xc:typep value type)))) (cond (lvar - (and (constant-lvar-p lvar) + (and (if (policy (let ((uses (lvar-uses lvar))) + (if (consp uses) + (car uses) + uses)) + (= preserve-constants 3)) + (constant-lvar-ignore-types-p lvar nil) + (constant-lvar-p lvar)) (type-p (lvar-value lvar) (cdr restr)))) (tn (and (eq (tn-kind tn) :constant) @@ -567,6 +586,26 @@ (unless (operand-restriction-ok type (lvar-ptype arg) :lvar arg) (return nil)))))) +(defun diagnose-template-args (template call) + ;; Scan all except the MORE args. If you've managed to create not-ok MORE args, + ;; you're probably smart enough to figure it out on your own. + (let ((args (basic-combination-args call)) + (types (template-arg-types template))) + (unless (= (length args) (length types)) + (return-from diagnose-template-args "bad length")) + (do ((args args (cdr args)) + (i 0 (1+ i)) + (any-fail nil) + (types types (cdr types))) + ((null types) any-fail) + (let* ((arg (car args)) + (type (car types)) + (ok (operand-restriction-ok type (lvar-ptype arg) :lvar arg))) + (let ((*print-pretty* nil)) + (format t "arg~d: is ~s need ~s, ~a~%" i + (primitive-type-name (lvar-ptype arg)) + type (if ok "OK" "FAIL"))) + (unless ok (setq any-fail :fail)))))) ;;; Check that TEMPLATE can be used with the specifed RESULT-TYPE. ;;; Result type checking is pretty different from argument type @@ -622,7 +661,7 @@ (let* ((guard (template-guard template)) (lvar (node-lvar call)) (dtype (node-derived-type call))) - (cond ((and guard (not (funcall guard))) + (cond ((and guard (not (funcall guard call))) (values nil :guard)) ((not (template-args-ok template call safe-p)) (values nil @@ -630,11 +669,12 @@ :arg-check :arg-types))) ((template-conditional-p template) - (let ((dest (lvar-dest lvar))) - (if (and (if-p dest) - (immediately-used-p (if-test dest) call)) - (values t nil) - (values nil :conditional)))) + (or (vop-existsp :named sb-vm::move-conditional-result) + (let ((dest (lvar-dest lvar))) + (if (and (if-p dest) + (immediately-used-p (if-test dest) call)) + (values t nil) + (values nil :conditional))))) ((template-results-ok template dtype) (values t nil)) (t @@ -787,9 +827,9 @@ (template-or-lose 'call-named))) *efficiency-note-cost-threshold*))) (dolist (try (fun-info-templates (basic-combination-fun-info call))) - (when (> (template-cost try) max-cost) (return)) ; FIXME: UNLESS'd be cleaner. + (when (> (template-cost try) max-cost) (return)) (let ((guard (template-guard try))) - (when (and (or (not guard) (funcall guard)) + (when (and (or (not guard) (funcall guard call)) (or (not safe-p) (ltn-policy-safe-p (template-ltn-policy try))) (not (and (eq ltn-policy :safe) @@ -877,7 +917,7 @@ ;; transforms or VOPs or whatever. (unless template (ltn-default-call call) - (when (let ((funleaf (physenv-lambda (node-physenv call))) + (when (let ((funleaf (environment-lambda (node-environment call))) (name (lvar-fun-name (combination-fun call)))) (and (leaf-has-source-name-p funleaf) (eq name (leaf-source-name funleaf)) @@ -977,6 +1017,7 @@ (exit (ltn-analyze-exit node)) (cset (ltn-analyze-set node)) (cast (ltn-analyze-cast node)) + (enclose (ltn-analyze-enclose node)) (mv-combination (ecase (basic-combination-kind node) (:local diff --git a/src/compiler/ltv.lisp b/src/compiler/ltv.lisp index 64f4f4be91..d48d309853 100644 --- a/src/compiler/ltv.lisp +++ b/src/compiler/ltv.lisp @@ -13,38 +13,6 @@ (defknown %load-time-value (t) t (flushable movable)) -;;; Compile FORM and arrange for it to be called at load-time. Return -;;; the dumper handle and our best guess at the type of the object. -;;; It would be nice if L-T-V forms were generally eligible -;;; for fopcompilation, as it could eliminate special cases below. -(defun compile-load-time-value (form &optional no-skip) - (acond ((typecase form - ;; This case is important for dumping packages as constants - ;; in cold-init, but works fine in the normal target too. - ((cons (eql find-package) (cons string null)) 'package) - ;; Another similar case - this allows the printer to work - ;; immediately in cold-init. (See SETUP-PRINTER-STATE.) - ((cons (eql function) - (cons (satisfies legal-fun-name-p) null)) - 'function) - ;; We want to construct cold classoid cells, but in general - ;; FIND-CLASSOID-CELL could be called with :CREATE NIL - ;; which can not be handled in cold-load. - #+sb-xc-host - ((cons (eql find-classoid-cell) (cons (cons (eql quote)))) - (aver (eq (getf (cddr form) :create) t)) - 'sb-kernel::classoid-cell)) - (fopcompile form nil t) - (values (sb-fasl::dump-pop *compile-object*) (specifier-type it))) - (t - (let ((lambda (compile-load-time-stuff form t))) - (values (fasl-dump-load-time-value-lambda lambda *compile-object* - no-skip) - (let ((type (leaf-type lambda))) - (if (fun-type-p type) - (single-value-type (fun-type-returns type)) - *wild-type*))))))) - (def-ir1-translator load-time-value ((form &optional read-only-p) start next result) "Arrange for FORM to be evaluated at load-time and use the value produced as @@ -89,6 +57,10 @@ guaranteed to never be modified, so it can be put in read-only storage." ;; KLUDGE: purify on cheneygc moves everything in code ;; constants into read-only space, value-cell breaks the ;; chain. + ;; Technically, if FORM returns an INSTANCE which does not have + ;; ":PURE T" in its defstruct, then it will not be put in readonly + ;; space, so we _could_ avoid the indirection cell. But it's not + ;; worth trying to optimize that out for benefit of a crappy GC. (cond #-gencgc ((not read-only-p) `(make-value-cell ,form)) @@ -114,7 +86,10 @@ guaranteed to never be modified, so it can be put in read-only storage." ;; (LET ((X 3)) (MACROLET ((M () (HAIR))) (LOAD-TIME-VALUE (THING))) ;; can make use of M. We choose to say that it can't. (let ((value (let ((thunk ; Pass T for the EPHEMERAL flag. - (compile-in-lexenv `(lambda () ,form) (make-null-lexenv) + (compile-in-lexenv `(lambda () + (declare (local-optimize (verify-arg-count 0))) + ,form) + (make-null-lexenv) nil nil nil t nil))) (handler-case (funcall thunk) (error (condition) diff --git a/src/compiler/macros.lisp b/src/compiler/macros.lisp index 2b3577dfd2..24ba69cfe3 100644 --- a/src/compiler/macros.lisp +++ b/src/compiler/macros.lisp @@ -11,6 +11,24 @@ (in-package "SB-C") +;;;; DEFTYPEs + +;;; An INLINEP value describes how a function is called. The values +;;; have these meanings: +;;; NIL No declaration seen: do whatever you feel like, but don't +;;; dump an inline expansion. +;;; NOTINLINE NOTINLINE declaration seen: always do full function call. +;;; INLINE INLINE declaration seen: save expansion, expanding to it +;;; if policy favors. +;;; MAYBE-INLINE +;;; Retain expansion, but only use it opportunistically. +;;; MAYBE-INLINE is quite different from INLINE. As explained +;;; by APD on #lisp 2005-11-26: "MAYBE-INLINE lambda is +;;; instantiated once per component, INLINE - for all +;;; references (even under #'without FUNCALL)." +(deftype inlinep () '(member inline maybe-inline notinline nil)) + + ;;;; source-hacking defining forms ;;; Parse a DEFMACRO-style lambda-list, setting things up so that a @@ -266,6 +284,8 @@ ;;; - Don't actually instantiate a transform, instead just DEFUN ;;; Name with the specified transform definition function. This ;;; may be later instantiated with %DEFTRANSFORM. +;;; :INFO - an extra piece of information the transform receives, +;;; typically for use with :DEFUN-ONLY ;;; :IMPORTANT ;;; - If the transform fails and :IMPORTANT is ;;; NIL, then never print an efficiency note. @@ -275,24 +295,30 @@ (defmacro deftransform (name (lambda-list &optional (arg-types '*) (result-type '*) &key result policy node defun-only + (info nil info-p) (important :slightly)) &body body-decls-doc) (declare (type (member nil :slightly t) important)) + (cond (defun-only + (aver (eq important :slightly)) ; can't be specified + (aver (not policy))) ; has no effect on the defun + (t + (aver (not info)))) (multiple-value-bind (body decls doc) (parse-body body-decls-doc t) - (let ((n-node (or node (make-symbol "NODE"))) - (n-decls (sb-xc:gensym)) - (n-lambda (sb-xc:gensym))) + (let ((n-node (or node '#:node)) + (n-decls '#:decls) + (n-lambda '#:lambda)) (multiple-value-bind (bindings vars) (parse-deftransform lambda-list n-node '(give-up-ir1-transform)) (let ((stuff - `((,n-node &aux ,@bindings + `((,n-node ,@(if info-p (list info)) &aux ,@bindings ,@(when result `((,result (node-lvar ,n-node))))) (declare (ignorable ,@(mapcar #'car bindings))) (declare (lambda-list (node))) ,@decls - ,@(and defun-only doc `(,doc)) + ,@(if doc `(,doc)) ;; What purpose does it serve to allow the transform's body ;; to return decls as a second value? They would go in the ;; right place if simply returned as part of the expression. @@ -307,15 +333,11 @@ ,,n-lambda))))))) (if defun-only `(defun ,name ,@stuff) - `(%deftransform - ',name - '(function ,arg-types ,result-type) - (named-lambda (deftransform ,name) ,@stuff) - ,doc - ,important - ,(and policy - `(lambda (,n-node) - (policy ,n-node ,policy)))))))))) + `(%deftransform ',name + ,(and policy `(lambda (,n-node) (policy ,n-node ,policy))) + '(function ,arg-types ,result-type) + (named-lambda (deftransform ,name) ,@stuff) + ,important))))))) (defmacro deftransforms (names (lambda-list &optional (arg-types '*) (result-type '*) @@ -323,24 +345,18 @@ &body body-decls-doc) (let ((transform-name (symbolicate (car names) '-transform)) - (type (list 'function arg-types result-type)) - (doc (nth-value 2 (parse-body body-decls-doc t)))) + (type (list 'function arg-types result-type))) `(progn (deftransform ,transform-name (,lambda-list ,arg-types ,result-type :defun-only t :result ,result :policy ,policy :node ,node) ,@body-decls-doc) - ,@(loop for name in names - collect - `(let ((policy ,(and policy - (let ((node-sym (gensym "NODE"))) - `(lambda (,node-sym) - (policy ,node-sym ,policy)))))) - (%deftransform ',name ',type #',transform-name - ,doc - ,important - policy)))))) + (flet ,(if policy `((policy-test (node) (policy node ,policy)))) + ,@(mapcar (lambda (name) + `(%deftransform ',name ,(if policy '#'policy-test) ',type + #',transform-name ,important)) + names))))) ;;; Create a function which parses combination args according to WHAT ;;; and LAMBDA-LIST, where WHAT is either a function name or a list @@ -364,7 +380,7 @@ ;;; methods are passed an additional POLICY argument, and IR2-CONVERT ;;; methods are passed an additional IR2-BLOCK argument. (defmacro defoptimizer (what (lambda-list - &optional (node (sb-xc:gensym) node-p) + &optional (node (gensym)) &rest vars) &body body) (let ((name (flet ((function-name (name) @@ -386,38 +402,52 @@ ,@body) ,@(loop for vop-name in (ensure-list (second what)) collect - `(setf (vop-info-optimizer (template-or-lose ',vop-name)) - #',name))) + `(set-vop-optimizer (template-or-lose ',vop-name) #',name))) (binding* (((forms decls) (parse-body body nil)) ((var-decls more-decls) (extract-var-decls decls vars)) - ;; In case the BODY declares IGNORE of the formal NODE var, - ;; we rebind it from N-NODE and never reference it from BINDS. - (n-node (make-symbol "NODE")) - ((binds lambda-vars gensyms) - (parse-deftransform lambda-list n-node + ((binds lambda-vars) + (parse-deftransform lambda-list node `(return-from ,name ,(if (and (consp what) (eq (second what) 'equality-constraint)) :give-up - nil))))) + nil)))) + (args (gensym))) (declare (ignore lambda-vars)) `(progn ;; We can't stuff the BINDS as &AUX vars into the lambda list ;; because there can be a RETURN-FROM in there. - (defun ,name (,n-node ,@vars) + (defun ,name (,node ,@vars &rest ,args) + (declare (ignorable ,node ,@(butlast vars)) + (ignore ,args)) ,@(if var-decls (list var-decls)) - (let* (,@binds ,@(if node-p `((,node ,n-node)))) - ;; Syntax requires naming NODE even if undesired if VARS - ;; are present, so in that case make NODE ignorable. - (declare (ignorable ,@(if (and vars node-p) `(,node)) - ,@gensyms)) + (let* (,@binds) + (declare (ignorable ,@(mapcar #'car binds))) ,@more-decls ,@forms)) ,@(when (consp what) `((setf (,(let ((*package* (sb-xc:symbol-package 'fun-info))) (symbolicate "FUN-INFO-" (second what))) (fun-info-or-lose ',(first what))) #',name)))))))) + +(defmacro defoptimizers (kind names (lambda-list + &optional (node (gensym)) + &rest vars) + &body body) + (let ((optimizer-name (symbolicate (car names) + "-" + kind + "-OPTIMIZER"))) + `(progn + (defoptimizer ,optimizer-name + (,lambda-list ,node ,@vars) + ,@body) + ,@(loop for name in names + collect `(setf (,(let ((*package* (sb-xc:symbol-package 'fun-info))) + (symbolicate "FUN-INFO-" kind)) + (fun-info-or-lose ',name)) + #',optimizer-name))))) ;;;; IR groveling macros @@ -584,21 +614,18 @@ ;;; this table, as 42 is EQ to 42 no matter where in the source it ;;; appears. GET-SOURCE-PATH and NOTE-SOURCE-PATH functions should be ;;; always used to access this table. -(declaim (hash-table *source-paths*)) +(declaim (type hash-table *source-paths*)) (defvar *source-paths*) (defmacro with-source-paths (&body forms) - (with-unique-names (source-paths) - `(let* ((,source-paths (make-hash-table :test 'eq)) - (*source-paths* ,source-paths)) - (unwind-protect - (progn ,@forms) - (clrhash ,source-paths))))) + `(let ((*source-paths* (make-hash-table :test 'eq))) + ,@forms)) ;;; Bind the hashtables used for keeping track of global variables, ;;; functions, etc. (defmacro with-ir1-namespace (&body forms) - `(let ((*ir1-namespace* (make-ir1-namespace))) ,@forms)) + `(let ((*ir1-namespace* (make-ir1-namespace))) + ,@forms)) ;;; Look up NAME in the lexical environment namespace designated by ;;; SLOT, returning the <value, T>, or <NIL, NIL> if no entry. The @@ -625,6 +652,100 @@ (setf (component-last-block ,component) ,old-last-block)))))) + +;;;; boolean attribute utilities +;;;; +;;;; We need to maintain various sets of boolean attributes for known +;;;; functions and VOPs. To save space and allow for quick set +;;;; operations, we represent the attributes as bits in a fixnum. + +(deftype attributes () 'fixnum) + +;;; Given a list of attribute names and an alist that translates them +;;; to masks, return the OR of the masks. +(defun encode-attribute-mask (names universe) + (loop for name in names + for pos = (position name universe) + sum (if pos (ash 1 pos) (error "unknown attribute name: ~S" name)))) + +(defun decode-attribute-mask (bits universe) + (loop for name across universe + for mask = 1 then (ash mask 1) + when (logtest mask bits) collect name)) + +;;; Define a new class of boolean attributes, with the attributes +;;; having the specified ATTRIBUTE-NAMES. NAME is the name of the +;;; class, which is used to generate some macros to manipulate sets of +;;; the attributes: +;;; +;;; NAME-attributep attributes attribute-name* +;;; Return true if one of the named attributes is present, false +;;; otherwise. When set with SETF, updates the place Attributes +;;; setting or clearing the specified attributes. +;;; +;;; NAME-attributes attribute-name* +;;; Return a set of the named attributes. +(defmacro !def-boolean-attribute (name &body attribute-names) + (let ((vector (coerce attribute-names 'vector)) + (constructor (symbolicate name "-ATTRIBUTES")) + (test-name (symbolicate name "-ATTRIBUTEP"))) + `(progn + (defmacro ,constructor (&rest attribute-names) + "Automagically generated boolean attribute creation function. + See !DEF-BOOLEAN-ATTRIBUTE." + (encode-attribute-mask attribute-names ,vector)) + (defun ,(symbolicate "DECODE-" name "-ATTRIBUTES") (attributes) + (decode-attribute-mask attributes ,vector)) + (defmacro ,test-name (attributes &rest attribute-names) + "Automagically generated boolean attribute test function. + See !DEF-BOOLEAN-ATTRIBUTE." + `(logtest (the attributes ,attributes) + (,',constructor ,@attribute-names))) + (define-setf-expander ,test-name (place &rest attributes + &environment env) + "Automagically generated boolean attribute setter. See + !DEF-BOOLEAN-ATTRIBUTE." + (multiple-value-bind (temps values stores setter getter) + (#+sb-xc-host cl:get-setf-expansion + #-sb-xc-host get-setf-expansion place env) + (when (cdr stores) + (error "multiple store variables for ~S" place)) + (let ((newval (gensym)) + (n-place (gensym)) + (mask (encode-attribute-mask attributes ,vector))) + (values `(,@temps ,n-place) + `(,@values ,getter) + `(,newval) + `(let ((,(first stores) + (if ,newval + (logior ,n-place ,mask) + (logandc2 ,n-place ,mask)))) + ,setter + ,newval) + `(,',test-name ,n-place ,@attributes)))))))) + +;;; And now for some gratuitous pseudo-abstraction... +;;; +;;; ATTRIBUTES-UNION +;;; Return the union of all the sets of boolean attributes which are its +;;; arguments. +;;; ATTRIBUTES-INTERSECTION +;;; Return the intersection of all the sets of boolean attributes which +;;; are its arguments. +;;; ATTRIBUTES= +;;; True if the attributes present in ATTR1 are identical to +;;; those in ATTR2. +(defmacro attributes-union (&rest attributes) + `(the attributes + (logior ,@(mapcar (lambda (x) `(the attributes ,x)) attributes)))) +(defmacro attributes-intersection (&rest attributes) + `(the attributes + (logand ,@(mapcar (lambda (x) `(the attributes ,x)) attributes)))) +(declaim (ftype (function (attributes attributes) boolean) attributes=)) +(declaim (inline attributes=)) +(defun attributes= (attr1 attr2) + (eql attr1 attr2)) + ;;;; the EVENT statistics/trace utility @@ -747,7 +868,7 @@ ;;;; functions on directly-linked lists (linked through specialized ;;;; NEXT operations) -#-sb-fluid (declaim (inline find-in position-in)) +(declaim (inline find-in position-in)) ;;; Find ELEMENT in a null-terminated LIST linked by the accessor ;;; function NEXT. KEY and TEST are the same as for generic sequence functions. @@ -783,7 +904,7 @@ (defmacro deletef-in (next place item &environment env) (multiple-value-bind (temps vals stores store access) - (#+sb-xc sb-xc:get-setf-expansion #-sb-xc get-setf-expansion place env) + (#-sb-xc-host get-setf-expansion #+sb-xc-host cl:get-setf-expansion place env) (when (cdr stores) (error "multiple store variables for ~S" place)) (let ((n-item (gensym)) @@ -809,7 +930,7 @@ ;;; (defmacro push-in (next item place &environment env) (multiple-value-bind (temps vals stores store access) - (#+sb-xc sb-xc:get-setf-expansion #-sb-xc get-setf-expansion place env) + (#-sb-xc-host get-setf-expansion #+sb-xc-host cl:get-setf-expansion place env) (when (cdr stores) (error "multiple store variables for ~S" place)) `(let (,@(mapcar #'list temps vals) @@ -846,3 +967,64 @@ specify bindings for printer control variables.") (nreverse (mapcar #'car *compiler-print-variable-alist*)) (nreverse (mapcar #'cdr *compiler-print-variable-alist*)) ,@forms))) + +#| +In trying to figure out whether we can rectify the totally unobvious behavior +that FUN-INFO-TRANSFORMS are tried in the reverse order of their definitions, +it is helpful to understand when multiple transforms exist where more than +one could be selected. +In the absence of type overlap, it wouldn't matter what order they were attempted. +Unfortunately there are plenty of cases where the _least_ _specific_ fun-type +should be attempted first, which at least superfically makes no sense at all. + +(in-package sb-c) +;; As a special case, delete any functions where there are 2 transforms +;; and they can't possibly both apply. Just check the first arg. +(defun domains-possibly-overlap (xforms) + (when (/= (length xforms) 2) ; lazy, just say yes + (return-from domains-possibly-overlap t)) + (let ((t1 (transform-type (car xforms))) + (t2 (transform-type (cadr xforms)))) + (unless (and (fun-type-p t1) (fun-type-p t2)) + (return-from domains-possibly-overlap t)) + (let ((req1 (car (fun-type-required t1))) + (req2 (car (fun-type-required t2)))) + (unless (and req1 req2) + (return-from domains-possibly-overlap t)) + (when (or (and (type= req1 (specifier-type 'single-float)) + (type= req2 (specifier-type 'double-float))) + (and (type= req1 (specifier-type 'double-float)) + (type= req2 (specifier-type 'single-float)))) + (return-from domains-possibly-overlap nil)))) + ;; The conservative answer is always T. + t) +(let (list) + (do-all-symbols (s) + (dolist (name (list s `(setf ,s) `(cas ,s))) + (let* ((info (sb-int:info :function :info name)) + (xforms (and info (sb-c::fun-info-transforms info)))) + (when (and info + (> (length xforms) 1) + (not (assoc name list))) + (if (domains-possibly-overlap xforms) + (push (cons name xforms) list) + (format t "~&Nonoverlapping xforms on ~s~%" name)))))) + (let ((*print-pretty* nil)) + (dolist (x (sort (copy-list list) #'> :key (lambda (x) (length (cdr x)))) + (format t "~s functions~%" (length list))) + (format t "~a~%" (car x)) + (let ((i 0)) + (dolist (xform (cdr x)) + (incf i) + (format t " ~2d. ~s~%" i (sb-kernel:type-specifier + (sb-c::transform-type xform))) + (let* ((fun (sb-c::transform-function xform)) + (code (sb-kernel:fun-code-header fun)) + (info (sb-kernel:%code-debug-info code)) + (source (sb-c::compiled-debug-info-source info)) + (tlf (sb-c::compiled-debug-info-tlf-number info)) + (offs (sb-c::compiled-debug-info-char-offset info)) + (ns (sb-c::debug-source-namestring source)) + (doc (documentation (sb-c::transform-function xform) 'function))) + (format t " ; ~a ~a ~d ~d~%" doc ns tlf offs))))))) +|# diff --git a/src/compiler/main.lisp b/src/compiler/main.lisp index 3ba0ddae34..5af0c01d59 100644 --- a/src/compiler/main.lisp +++ b/src/compiler/main.lisp @@ -1,6 +1,4 @@ -;;;; the top level interfaces to the compiler, plus some other -;;;; compiler-related stuff (e.g. CL:CALL-ARGUMENTS-LIMIT) which -;;;; doesn't obviously belong anywhere else +;;;; the top level interfaces to the compiler ;;;; This software is part of the SBCL system. See the README file for ;;;; more information. @@ -16,6 +14,12 @@ (defvar *block-compile-default* nil "The default value for the :Block-Compile argument to COMPILE-FILE.") +;;; *BLOCK-COMPILE-ARGUMENT* holds the original value of the :BLOCK-COMPILE +;;; argument, which overrides any internal declarations. +(defvar *block-compile-argument*) +(declaim (type (member nil t :specified) + *block-compile-default* *block-compile-argument*)) + (defvar *entry-points-argument*) (declaim (type list *entry-points-argument*)) @@ -24,30 +28,25 @@ ;;; Set to NIL to disable loop analysis for register allocation. (defvar *loop-analyze* t) -;;; The current non-macroexpanded toplevel form as printed when -;;; *compile-print* is true. -;;; FIXME: should probably have no value outside the compiler. -(defvar *top-level-form-noted* nil) - -(defvar sb-xc:*compile-verbose* t +(defvar *compile-verbose* t "The default for the :VERBOSE argument to COMPILE-FILE.") -(defvar sb-xc:*compile-print* t +(defvar *compile-print* nil "The default for the :PRINT argument to COMPILE-FILE.") (defvar *compile-progress* nil "When this is true, the compiler prints to *STANDARD-OUTPUT* progress information about the phases of compilation of each function. (This is useful mainly in large block compilations.)") -(defvar sb-xc:*compile-file-pathname* nil +(defvar *compile-file-pathname* nil "The defaulted pathname of the file currently being compiled, or NIL if not compiling.") -(defvar sb-xc:*compile-file-truename* nil +(defvar *compile-file-truename* nil "The TRUENAME of the file currently being compiled, or NIL if not compiling.") (declaim (type (or pathname null) - sb-xc:*compile-file-pathname* - sb-xc:*compile-file-truename*)) + *compile-file-pathname* + *compile-file-truename*)) ;;; the SOURCE-INFO structure for the current compilation. This is ;;; null globally to indicate that we aren't currently in any @@ -65,18 +64,16 @@ ;;; Mumble conditional on *COMPILE-PROGRESS*. (defun maybe-mumble (&rest foo) (when *compile-progress* - (compiler-mumble "~&") - (pprint-logical-block (*standard-output* nil :per-line-prefix "; ") - (apply #'compiler-mumble foo)))) + (apply #'compiler-mumble foo))) (deftype object () '(or fasl-output core-object null)) + +(defvar *compile-object* nil) (declaim (type object *compile-object*)) (defvar *emit-cfasl* nil) -(defvar *fopcompile-label-counter*) - (declaim (inline code-coverage-records code-coverage-blocks)) ;; Used during compilation to map code paths to the matching ;; instrumentation conses. @@ -87,7 +84,7 @@ ;;;; WITH-COMPILATION-UNIT and WITH-COMPILATION-VALUES -(defmacro sb-xc:with-compilation-unit (options &body body) +(defmacro with-compilation-unit (options &body body) "Affects compilations that take place within its dynamic extent. It is intended to be eg. wrapped around the compilation of all files in the same system. @@ -190,6 +187,8 @@ Examples: (*compiler-style-warning-count* 0) (*compiler-note-count* 0) (*undefined-warnings* nil) + *argument-mismatch-warnings* + *methods-in-compilation-unit* (*in-compilation-unit* t)) (handler-bind ((parse-unknown-type (lambda (c) @@ -242,6 +241,7 @@ Examples: (*last-error-context* nil)) (handler-bind ((style-warning #'compiler-style-warning-handler) (warning #'compiler-warning-handler)) + (report-key-arg-mismatches) (dolist (kind '(:variable :function :type)) (let ((names (mapcar #'undefined-warning-name (remove kind undefs :test #'neq @@ -360,7 +360,7 @@ Examples: (file-compiling-p (file-info-p file-info))) (flet ((match-p (entry) (destructuring-bind (entry-thing entry-fmt &rest entry-args) entry - ;; THING is compared by EQ, FMT by STRING=. + ;; THING is compared by EQ, FMT mostly by STRING=. (and (eq entry-thing thing) (cond ((typep entry-fmt 'condition) (and (typep fmt-or-condition 'condition) @@ -368,6 +368,12 @@ Examples: (princ-to-string fmt-or-condition)))) ((typep fmt-or-condition 'condition) nil) + ;; If at least one is a FMT-CONTROL-PROXY + ;; the two should be either EQ or a + ;; mismatch. + ((not (stringp entry-fmt)) + (and (not (stringp fmt-or-condition)) + (eq entry-fmt fmt-or-condition))) ((string= entry-fmt fmt-or-condition))) ;; We don't want to walk into default values, ;; e.g. (&optional (b #<insane-struct)) @@ -405,37 +411,37 @@ necessary, since type inference may take arbitrarily long to converge.") (cleared-reanalyze nil) (fastp nil)) (loop - (when (component-reanalyze component) - (setf count 0 - fastp nil - cleared-reanalyze t - (component-reanalyze component) nil)) - (setf (component-reoptimize component) nil) - (ir1-optimize component fastp) - (cond ((component-reoptimize component) - (incf count) - (when (and (>= count *max-optimize-iterations*) - (not (component-reanalyze component)) - (eq (component-reoptimize component) :maybe)) - (maybe-mumble "*") - (cond ((retry-delayed-ir1-transforms :optimize) - (maybe-mumble "+") - (setq count 0)) - (t - (event ir1-optimize-maxed-out) - (ir1-optimize-last-effort component) - (return))))) - ((retry-delayed-ir1-transforms :optimize) - (setf count 0) - (maybe-mumble "+")) - (t - (maybe-mumble " ") - (return))) - (when (setq fastp (>= count *max-optimize-iterations*)) - (ir1-optimize-last-effort component)) - (maybe-mumble (if fastp "-" "."))) + (when (component-reanalyze component) + (setf count 0 + fastp nil + cleared-reanalyze t + (component-reanalyze component) nil)) + (setf (component-reoptimize component) nil) + (ir1-optimize component fastp) + (cond ((component-reoptimize component) + (incf count) + (when (and (>= count *max-optimize-iterations*) + (not (component-reanalyze component)) + (eq (component-reoptimize component) :maybe)) + (maybe-mumble "*") + (cond ((retry-delayed-ir1-transforms :optimize) + (maybe-mumble "+") + (setq count 0)) + (t + (event ir1-optimize-maxed-out) + (ir1-optimize-last-effort component) + (return))))) + ((retry-delayed-ir1-transforms :optimize) + (setf count 0) + (maybe-mumble "+")) + (t + (return))) + (when (setq fastp (>= count *max-optimize-iterations*)) + (ir1-optimize-last-effort component)) + (maybe-mumble (if fastp "-" "."))) (when cleared-reanalyze - (setf (component-reanalyze component) t))) + (setf (component-reanalyze component) t)) + (maybe-mumble " ")) (values)) (defparameter *constraint-propagate* t) @@ -459,31 +465,43 @@ necessary, since type inference may take arbitrarily long to converge.") (defparameter *reoptimize-limit* 10) (defun ir1-optimize-phase-1 (component) - (let ((loop-count 0)) - (loop - (ir1-optimize-until-done component) - (when (or (component-new-functionals component) - (component-reanalyze-functionals component)) - (maybe-mumble "Locall ") - (locall-analyze-component component)) - (eliminate-dead-code component) - (dfo-as-needed component) - (when *constraint-propagate* - (maybe-mumble "Constraint ") - (constraint-propagate component)) - (when (retry-delayed-ir1-transforms :constraint) - (setf loop-count 0) ;; otherwise nothing may get retried - (maybe-mumble "Rtran ")) - (unless (or (component-reoptimize component) - (component-reanalyze component) - (component-new-functionals component) - (component-reanalyze-functionals component)) - (return)) - (when (> loop-count *reoptimize-limit*) - (maybe-mumble "[Reoptimize Limit]") - (event reoptimize-maxed-out) - (return)) - (incf loop-count)))) + (let ((loop-count 0) + (*constraint-propagate* *constraint-propagate*)) + (tagbody + again + (loop + (ir1-optimize-until-done component) + (when (or (component-new-functionals component) + (component-reanalyze-functionals component)) + (maybe-mumble "Locall ") + (locall-analyze-component component)) + (eliminate-dead-code component) + (dfo-as-needed component) + (when *constraint-propagate* + (maybe-mumble "Constraint ") + (constraint-propagate component) + (when (retry-delayed-ir1-transforms :constraint) + (setf loop-count 0) ;; otherwise nothing may get retried + (maybe-mumble "Rtran "))) + (unless (or (component-reoptimize component) + (component-reanalyze component) + (component-new-functionals component) + (component-reanalyze-functionals component)) + (return)) + (when (> loop-count *reoptimize-limit*) + (maybe-mumble "[Reoptimize Limit]") + (event reoptimize-maxed-out) + (return)) + (incf loop-count)) + ;; Do it once more for the transforms that will produce code + ;; that loses some information for further optimizations and + ;; it's better to insert it at the last moment. + ;; Such code shouldn't need constraint propagation, the slowest + ;; part, so avoid it. + (when (retry-delayed-ir1-transforms :ir1-phases) + (setf loop-count 0 + *constraint-propagate* nil) + (go again))))) ;;; Do all the IR1 phases for a non-top-level component. (defun ir1-phases (component) @@ -534,6 +552,7 @@ necessary, since type inference may take arbitrarily long to converge.") (if (fasl-output-p *compile-object*) (and (eq *compile-file-to-memory-space* :immobile) (neq (component-kind component) :toplevel) + (policy *lexenv* (/= sb-c:store-coverage-data 3)) :immobile) (if (core-object-ephemeral *compile-object*) :dynamic @@ -548,117 +567,125 @@ necessary, since type inference may take arbitrarily long to converge.") (eq (component-mem-space component) :immobile)))) (defun %compile-component (component) - (let ((*adjustable-vectors* nil)) ; Needed both by codegen and fasl writer - (maybe-mumble "GTN ") - (gtn-analyze component) - (maybe-mumble "LTN ") - (ltn-analyze component) - (dfo-as-needed component) + (maybe-mumble "GTN ") + (gtn-analyze component) + (maybe-mumble "LTN ") + (ltn-analyze component) + (dfo-as-needed component) - (maybe-mumble "Control ") - (control-analyze component) - - (when (or (ir2-component-values-receivers (component-info component)) - (component-dx-lvars component)) - (maybe-mumble "Stack ") - ;; STACK only uses dominance information for DX LVAR back - ;; propagation (see BACK-PROPAGATE-ONE-DX-LVAR). - (when (component-dx-lvars component) - (clear-dominators component) - (find-dominators component)) - (stack-analyze component) - ;; Assign BLOCK-NUMBER for any cleanup blocks introduced by - ;; stack analysis. There shouldn't be any unreachable code after - ;; control, so this won't delete anything. - (dfo-as-needed component)) + (maybe-mumble "Control ") + (control-analyze component) - (unwind-protect - (progn - (maybe-mumble "IR2Tran ") - (entry-analyze component) - (ir2-convert component) - - (when (policy *lexenv* (>= speed compilation-speed)) - (maybe-mumble "Copy ") - (copy-propagate component)) - - (when *compiler-trace-output* - (format *compiler-trace-output* - "~|~%;;;; component: ~S~2%" (component-name component))) - (ir2-optimize component) - - (select-representations component) - - (when *check-consistency* - (maybe-mumble "Check2 ") - (check-ir2-consistency component)) - - (delete-unreferenced-tns component) - - (maybe-mumble "Life ") - (lifetime-analyze component) - - (when *compile-progress* - (compiler-mumble "") ; Sync before doing more output. - (pre-pack-tn-stats component *standard-output*)) - - (when *check-consistency* - (maybe-mumble "CheckL ") - (check-life-consistency component)) - - (maybe-mumble "Pack ") - (sb-regalloc:pack component) - - (when *check-consistency* - (maybe-mumble "CheckP ") - (check-pack-consistency component)) - - (delete-no-op-vops component) - (ir2-optimize-jumps component) - (optimize-constant-loads component) - (when *compiler-trace-output* - (when (memq :ir1 *compile-trace-targets*) - (let ((*standard-output* *compiler-trace-output*)) - (print-all-blocks component))) - (when (memq :ir2 *compile-trace-targets*) - (describe-ir2-component component *compiler-trace-output*))) - - (maybe-mumble "Code ") - (multiple-value-bind (segment text-length fun-table - elsewhere-label fixup-notes) - (let ((*compiler-trace-output* - (and (memq :vop *compile-trace-targets*) - *compiler-trace-output*))) - (generate-code component)) - (declare (ignorable text-length fun-table)) - - (let ((bytes (sb-assem:segment-contents-as-vector segment)) - (object *compile-object*) - (*elsewhere-label* elsewhere-label)) ; KLUDGE + (report-code-deletion) - #-sb-xc-host - (when (and *compiler-trace-output* - (memq :disassemble *compile-trace-targets*)) - (let ((ranges - (maplist (lambda (list) - (cons (+ (car list) - (ash sb-vm:simple-fun-insts-offset - sb-vm:word-shift)) - (or (cadr list) text-length))) - fun-table))) - (format *compiler-trace-output* - "~|~%Disassembly of code for ~S~2%" component) - (sb-disassem:disassemble-assem-segment - bytes ranges *compiler-trace-output*))) - - (funcall (etypecase object - (fasl-output (maybe-mumble "FASL") #'fasl-dump-component) - #-sb-xc-host ; no compiling to core - (core-object (maybe-mumble "Core") #'make-core-component) - (null (lambda (&rest dummies) - (declare (ignore dummies))))) - component segment (length bytes) fixup-notes - object)))))) + (when (or (ir2-component-values-receivers (component-info component)) + (component-dx-lvars component)) + (maybe-mumble "Stack ") + ;; STACK only uses dominance information for DX LVAR back + ;; propagation (see BACK-PROPAGATE-ONE-DX-LVAR). + (when (component-dx-lvars component) + (clear-dominators component) + (find-dominators component)) + (stack-analyze component) + ;; Assign BLOCK-NUMBER for any cleanup blocks introduced by + ;; stack analysis. There shouldn't be any unreachable code after + ;; control, so this won't delete anything. + (dfo-as-needed component)) + + (maybe-mumble "IR2Tran ") + (entry-analyze component) + + ;; For on-demand recalculation of dominators, the previously + ;; computed results may be stale. + + (clear-dominators component) + + (ir2-convert component) + + (when (policy *lexenv* (>= speed compilation-speed)) + (maybe-mumble "Copy ") + (copy-propagate component)) + + (ir2-optimize component) + + (select-representations component) + ;; Try to combine consecutive uses of %INSTANCE-SET. + ;; This can't be done prior to selecting representations + ;; because SELECT-REPRESENTATIONS might insert some + ;; things like MOVE-FROM-DOUBLE which makes the + ;; "consecutive" vops no longer consecutive. + + (ir2-optimize-stores component) + + (when *check-consistency* + (maybe-mumble "Check2 ") + (check-ir2-consistency component)) + + (delete-unreferenced-tns component) + + (maybe-mumble "Life ") + (lifetime-analyze component) + + (when *compile-progress* + (compiler-mumble "") ; Sync before doing more output. + (pre-pack-tn-stats component *standard-output*)) + + (when *check-consistency* + (maybe-mumble "CheckL ") + (check-life-consistency component)) + + (maybe-mumble "Pack ") + (sb-regalloc:pack component) + + (when *check-consistency* + (maybe-mumble "CheckP ") + (check-pack-consistency component)) + + (delete-no-op-vops component) + (ir2-optimize-jumps component) + (optimize-constant-loads component) + (when *compiler-trace-output* + (when (memq :ir1 *compile-trace-targets*) + (describe-component component *compiler-trace-output*)) + (when (memq :ir2 *compile-trace-targets*) + (describe-ir2-component component *compiler-trace-output*))) + + (maybe-mumble "Code ") + (multiple-value-bind (segment text-length fun-table + elsewhere-label fixup-notes alloc-points) + (let ((*compiler-trace-output* + (and (memq :vop *compile-trace-targets*) + *compiler-trace-output*))) + (generate-code component)) + (declare (ignorable text-length fun-table)) + + (let ((bytes (sb-assem:segment-contents-as-vector segment)) + (object *compile-object*) + (*elsewhere-label* elsewhere-label)) ; KLUDGE + #-sb-xc-host + (when (and *compiler-trace-output* + (memq :disassemble *compile-trace-targets*)) + (let ((ranges + (maplist (lambda (list) + (cons (+ (car list) + (ash sb-vm:simple-fun-insts-offset + sb-vm:word-shift)) + (or (cadr list) text-length))) + fun-table))) + (format *compiler-trace-output* + "~|~%Disassembly of code for ~S~2%" component) + (sb-disassem:disassemble-assem-segment + bytes ranges *compiler-trace-output*))) + + (funcall (etypecase object + (fasl-output (maybe-mumble "FASL") #'fasl-dump-component) + #-sb-xc-host ; no compiling to core + (core-object (maybe-mumble "Core") #'make-core-component) + (null (lambda (&rest dummies) + (declare (ignore dummies))))) + component segment (length bytes) + fixup-notes alloc-points + object))) ;; We're done, so don't bother keeping anything around. (setf (component-info component) :dead) @@ -701,9 +728,11 @@ necessary, since type inference may take arbitrarily long to converge.") (aver (eql (node-component (lambda-bind lambda)) component))) (let* ((*component-being-compiled* component)) - (when (and sb-xc:*compile-print* (block-compile *compilation*)) - (with-compiler-io-syntax - (compiler-mumble "~&; compiling ~A" (component-name component)))) + + (when *compile-progress* + (compiler-mumble "~&") + (pprint-logical-block (*standard-output* nil :per-line-prefix "; ") + (compiler-mumble "Compiling ~A: " (component-name component)))) ;; Record xref information before optimization. This way the ;; stored xref data reflects the real source as closely as @@ -712,9 +741,9 @@ necessary, since type inference may take arbitrarily long to converge.") (ir1-phases component) - ;; This should happen at some point before PHYSENV-ANALYZE, and - ;; after RECORD-COMPONENT-XREFS. Beyond that, I haven't really - ;; thought things through. -- AJB, 2014-Jun-08 + ;; This should happen at some point before ENVIRONMENT-ANALYZE, + ;; and after RECORD-COMPONENT-XREFS. Beyond that, I haven't + ;; really thought things through. -- AJB, 2014-Jun-08 (eliminate-dead-code component) (when *loop-analyze* @@ -739,14 +768,15 @@ necessary, since type inference may take arbitrarily long to converge.") |# (maybe-mumble "Env ") - (physenv-analyze component) + (environment-analyze component) (dfo-as-needed component) (delete-if-no-entries component) - (unless (eq (block-next (component-head component)) - (component-tail component)) - (%compile-component component)) + (if (eq (block-next (component-head component)) + (component-tail component)) + (report-code-deletion) + (%compile-component component)) (when *compile-component-hook* (funcall *compile-component-hook* component))) @@ -769,7 +799,7 @@ necessary, since type inference may take arbitrarily long to converge.") (maphash (lambda (k v) (declare (ignore k)) (setf (leaf-info v) nil)) - (eq-constants ns)) + (eql-constants ns)) (maphash (lambda (k v) (declare (ignore k)) (when (constant-p v) @@ -795,14 +825,21 @@ necessary, since type inference may take arbitrarily long to converge.") (eq (node-component x) component))) (blast (free-vars ns)) (blast (free-funs ns)) - ;; There can be more constants to blast when considering them by EQ rather + ;; There can be more constants to blast when considering them by EQL rather ;; than similarity. But it's totally OK to visit a #<CONSTANT> twice. ;; Its refs will be scanned redundantly, which is harmless. - (blast (eq-constants ns))) + (blast (eql-constants ns))) (values)) ;;;; trace output +;;; Print out some useful info about COMPONENT to STREAM. +(defun describe-component (component *standard-output*) + (declare (type component component)) + (format t "~|~%;;;; component: ~S~2%" (component-name component)) + (print-all-blocks component) + (values)) + (defun describe-ir2-component (component *standard-output*) (format t "~%~|~%;;;; IR2 component: ~S~2%" (component-name component)) (format t "entries:~%") @@ -818,22 +855,39 @@ necessary, since type inference may take arbitrarily long to converge.") (terpri) (values)) +;;; Leave this as NIL if you want modern, rational, correct, behavior, +;;; or switch it to T for legacy (CLHS-specified) bullshit a la +;;; "During a call to compile-file, *compile-file-pathname* is bound to the pathname +;;; denoted by the first argument to compile-file, merged against the defaults" +;;; The normal build sets it to T in make-target-2, despite that I think most people would +;;; prefer the nonstandard behavior. The standard behavior makes stored pathnames all wrong +;;; when files are physically moved. (Same problem as SBCL_HOME embedded into C pretty much) +(defglobal *merge-pathnames* nil) + ;;; Given a pathname, return a SOURCE-INFO structure. (defun make-file-source-info (file external-format &optional form-tracking-p) (make-source-info - :file-info (make-file-info :name (truename file) ; becomes *C-F-TRUENAME* - :untruename #+sb-xc-host file ; becomes *C-F-PATHNAME* - #-sb-xc-host (merge-pathnames file) - :external-format external-format - :subforms - (if form-tracking-p - (make-array 100 :fill-pointer 0 :adjustable t)) - :write-date (file-write-date file)))) + :file-info (make-file-info + ;; becomes *COMPILE-FILE-PATHNAME* + :pathname (if *merge-pathnames* (merge-pathnames file) file) + :external-format external-format + :subforms (if form-tracking-p (make-array 100 :fill-pointer 0 :adjustable t)) + :write-date (file-write-date file)))) + +;; LOAD-AS-SOURCE uses this. +(defun make-file-stream-source-info (file-stream) + (make-source-info + :file-info (make-file-info :truename (truename file-stream) ; FIXME: WHY USE TRUENAME??? + ;; This T-L-P has been around since at least 2011. + ;; It's unclear why an LPN isn't good enough. + :pathname (translate-logical-pathname file-stream) + :external-format (stream-external-format file-stream) + :write-date (file-write-date file-stream)))) ;;; Return a SOURCE-INFO to describe the incremental compilation of FORM. (defun make-lisp-source-info (form &key parent) (make-source-info - :file-info (make-file-info :name :lisp + :file-info (make-file-info :truename :lisp :forms (vector form) :positions '#(0)) :parent parent)) @@ -847,7 +901,7 @@ necessary, since type inference may take arbitrarily long to converge.") (finfo (source-info-file-info sinfo) (source-info-file-info sinfo))) ((or (not (source-info-p (source-info-parent sinfo))) - (pathnamep (file-info-name finfo))) + (pathnamep (file-info-truename finfo))) finfo)))) ;;; If STREAM is present, return it, otherwise open a stream to the @@ -867,28 +921,34 @@ necessary, since type inference may take arbitrarily long to converge.") (declare (type source-info info)) (or (source-info-stream info) (let* ((file-info (source-info-file-info info)) - (name (file-info-name file-info)) + (pathname (file-info-pathname file-info)) (external-format (file-info-external-format file-info))) - (setf sb-xc:*compile-file-truename* name - sb-xc:*compile-file-pathname* (file-info-untruename file-info) - (source-info-stream info) - (let ((stream - (open name - :direction :input - :external-format external-format - ;; SBCL stream classes aren't available in the host - #-sb-xc-host :class - #-sb-xc-host 'form-tracking-stream))) - #+(and sb-xc-host sb-show) - (setq stream (make-concatenated-stream - stream - (make-string-input-stream - (format nil "(write-string \"Completed TLFs: ~A~%\")" - (file-info-untruename file-info))))) - (when (file-info-subforms file-info) - (setf (form-tracking-stream-observer stream) - (make-form-tracking-stream-observer file-info))) - stream))))) + (let ((stream + (open pathname + :direction :input + :external-format external-format + ;; SBCL stream classes aren't available in the host + #-sb-xc-host :class + #-sb-xc-host 'form-tracking-stream))) + ;; If you don't want merged pathnames embedded in your build artifacts, + ;; then you surely don't want them in *COMPILE-FILE-PATHNAME* either. + ;; [And can't we just bind this to PATHNAME is all cases? If anything, + ;; it seems to me that asking the stream for its name is expressly backwards] + (setf *compile-file-pathname* (if *merge-pathnames* (pathname stream) pathname) + *compile-file-truename* (truename stream) + (file-info-truename file-info) *compile-file-truename*) + (when (file-info-subforms file-info) + (setf (form-tracking-stream-observer stream) + (make-form-tracking-stream-observer file-info))) + (setf (source-info-stream info) stream) + ;; This used to happen before opening the file, which + ;; inhibited lazy computation of the truename, and was a + ;; minor time-of-check-vs-time-of-use mistake. It doesn't + ;; seem worthwhile to pass the verbose bit down from C-F, + ;; however. + (when *compile-verbose* + (print-compile-start-note info)) + stream)))) ;;; Close the stream in INFO if it is open. (defun close-source-info (info) @@ -966,11 +1026,9 @@ necessary, since type inference may take arbitrarily long to converge.") &optional (on-error ''input-error-in-load)) &body body) (aver (symbolp form)) - (once-only ((info info)) - `(let ((*source-info* ,info)) - (%do-forms-from-info (lambda (,form &key ,@keys &allow-other-keys) - ,@body) - ,info ,on-error)))) + `(%do-forms-from-info (lambda (,form &key ,@keys &allow-other-keys) + ,@body) + ,info ,on-error)) ;;; Return the INDEX'th source form read from INFO and the position ;;; where it was read. @@ -986,32 +1044,26 @@ necessary, since type inference may take arbitrarily long to converge.") ;;; actually compile something. If (BLOCK-COMPILE *COMPILATION*) is T, ;;; then we still convert the form, but delay compilation, pushing the result ;;; on (TOPLEVEL-LAMBDAS *COMPILATION*) instead. -(defun convert-and-maybe-compile (form path &optional (expand t)) +;;; +;;; The policy at this time becomes the default policy for compiling +;;; the form. Any enclosed PROCLAIMs will affect only subsequent +;;; forms. +(defun convert-and-maybe-compile (form path) (declare (list path)) #+sb-xc-host (when sb-cold::*compile-for-effect-only* (return-from convert-and-maybe-compile)) - (let ((*top-level-form-noted* (note-top-level-form form t))) - ;; Don't bother to compile simple objects that just sit there. - (when (and form (or (symbolp form) (consp form))) - (if (and #-sb-xc-host - (policy *policy* - ;; FOP-compiled code is harder to debug. - (or (< debug 2) - (> space debug))) - (not (eq (block-compile *compilation*) t)) - (fopcompilable-p form expand)) - (let ((*fopcompile-label-counter* 0)) - (fopcompile form path nil expand)) - (let ((*lexenv* (make-lexenv - :policy *policy* - :handled-conditions *handled-conditions* - :disabled-package-locks *disabled-package-locks*)) - (tll (ir1-toplevel form path nil))) - (if (eq (block-compile *compilation*) t) - (push tll (toplevel-lambdas *compilation*)) - (compile-toplevel (list tll) nil)) - nil))))) + ;; Don't bother to compile simple objects that just sit there. + (when (and form (or (symbolp form) (consp form))) + (let* ((*lexenv* (make-lexenv + :policy *policy* + :handled-conditions *handled-conditions* + :disabled-package-locks *disabled-package-locks*)) + (tll (ir1-toplevel form path nil))) + (if (eq (block-compile *compilation*) t) + (push tll (toplevel-lambdas *compilation*)) + (compile-toplevel (list tll) nil)) + nil))) ;;; Macroexpand FORM in the current environment with an error handler. ;;; We only expand one level, so that we retain all the intervening @@ -1231,26 +1283,14 @@ necessary, since type inference may take arbitrarily long to converge.") (mapc #'clear-ir1-info components-from-dfo) result)))))) -(defun note-top-level-form (form &optional finalp) - (when sb-xc:*compile-print* - (cond ((not *top-level-form-noted*) - (let ((*print-length* 2) - (*print-level* 2) - (*print-pretty* nil)) - (with-compiler-io-syntax - (compiler-mumble "~&; processing ~S" form))) - form) - ((and finalp - (eq :top-level-forms sb-xc:*compile-print*) - (neq form *top-level-form-noted*)) - (let ((*print-length* 1) - (*print-level* 1) - (*print-pretty* nil)) - (with-compiler-io-syntax - (compiler-mumble "~&; ... top level ~S" form))) - form) - (t - *top-level-form-noted*)))) +;;; Print some noise about FORM if *COMPILE-PRINT* is true. +(defun note-top-level-form (form) + (when *compile-print* + (let ((*print-length* 2) + (*print-level* 2) + (*print-pretty* nil)) + (with-compiler-io-syntax + (compiler-mumble "~&; processing ~S" form))))) ;;; Handle the evaluation the a :COMPILE-TOPLEVEL body during ;;; compilation. Normally just evaluate in the appropriate @@ -1353,8 +1393,7 @@ necessary, since type inference may take arbitrarily long to converge.") ((progn) (process-toplevel-progn (rest form) path compile-time-too)) (t - (let ((*top-level-form-noted* (note-top-level-form form)) - (expanded (preprocessor-macroexpand-1 form))) + (let ((expanded (preprocessor-macroexpand-1 form))) (cond ((neq expanded form) ; macro -> take it from the top (process-toplevel-form expanded path compile-time-too)) (t @@ -1383,47 +1422,32 @@ necessary, since type inference may take arbitrarily long to converge.") (defun producing-fasl-file () (fasl-output-p *compile-object*)) +;;; Compile FORM and arrange for it to be called at load-time. Return +;;; the dumper handle and our best guess at the type of the object. +;;; TODO: We could use a bytecode compiler here to produce smaller +;;; code. Same goes for top level code. +(defun compile-load-time-value (form) + (let ((lambda (compile-load-time-stuff form t))) + (values (fasl-dump-load-time-value-lambda lambda *compile-object*) + (let ((type (leaf-type lambda))) + (if (fun-type-p type) + (single-value-type (fun-type-returns type)) + *wild-type*))))) + ;;; Compile the FORMS and arrange for them to be called (for effect, ;;; not value) at load time. -(defun compile-make-load-form-init-forms (forms fasl) - ;; If FORMS has exactly one PROGN containing a call of SB-PCL::SET-SLOTS, - ;; then fopcompile it, otherwise use the main compiler. - (when (singleton-p forms) - (let ((call (car forms))) - (when (typep call '(cons (eql sb-pcl::set-slots) (cons instance))) - (pop call) - (let ((instance (pop call)) - (slot-names (pop call)) - (value-forms call) - (values)) - (when (and (every #'symbolp slot-names) - (every (lambda (x) - ;; +SLOT-UNBOUND+ is not a constant, - ;; but is trivially dumpable. - (or (eql x 'sb-pcl:+slot-unbound+) - (sb-xc:constantp x))) - value-forms)) - (dolist (form value-forms) - (unless (eq form 'sb-pcl:+slot-unbound+) - (let ((val (constant-form-value form))) - ;; invoke recursive MAKE-LOAD-FORM stuff as necessary - (find-constant val) - (push val values)))) - (setq values (nreverse values)) - (dolist (form value-forms) - (if (eq form 'sb-pcl:+slot-unbound+) - (dump-fop 'sb-fasl::fop-misc-trap fasl) - (dump-object (pop values) fasl))) - (dump-object slot-names fasl) - (dump-object instance fasl) - (dump-fop 'sb-fasl::fop-set-slot-values fasl (length slot-names)) - (return-from compile-make-load-form-init-forms)))))) +(defun compile-make-load-form-init-forms (forms) (let ((lambda (compile-load-time-stuff `(progn ,@forms) nil))) (fasl-dump-toplevel-lambda-call lambda *compile-object*))) ;;; Do the actual work of COMPILE-LOAD-TIME-VALUE or ;;; COMPILE-MAKE-LOAD-FORM-INIT-FORMS. (defun compile-load-time-stuff (form for-value) + ;; We want to force top level lambdas before any recursive IR1 + ;; namespacing happens. Therefore, we need to force here as well as + ;; in EMIT-MAKE-LOAD-FORMS, since we could enter recursive IR1 + ;; namespacing through either function. + (compile-toplevel-lambdas () t) (with-ir1-namespace (let* ((*lexenv* (make-null-lexenv)) (lambda (ir1-toplevel form *current-path* for-value nil))) @@ -1443,9 +1467,151 @@ necessary, since type inference may take arbitrarily long to converge.") (setf (component-name component) (leaf-debug-name lambda)) (compile-component component) (clear-ir1-info component)))) + + +;;; The entry point for MAKE-LOAD-FORM support. When IR1 conversion +;;; finds a constant structure, it invokes this to arrange for proper +;;; dumping. If it turns out that the constant has already been +;;; dumped, then we don't need to do anything. +;;; +;;; If the constant hasn't been dumped, then we check to see whether +;;; we are in the process of creating it. We detect this by +;;; maintaining the special *CONSTANTS-BEING-CREATED* as a list of all +;;; the constants we are in the process of creating. Actually, each +;;; entry is a list of the constant and any init forms that need to be +;;; processed on behalf of that constant. +;;; +;;; It's not necessarily an error for this to happen. If we are +;;; processing the init form for some object that showed up *after* +;;; the original reference to this constant, then we just need to +;;; defer the processing of that init form. To detect this, we +;;; maintain *CONSTANTS-CREATED-SINCE-LAST-INIT* as a list of the +;;; constants created since the last time we started processing an +;;; init form. If the constant passed to emit-make-load-form shows up +;;; in this list, then there is a circular chain through creation +;;; forms, which is an error. +;;; +;;; If there is some intervening init form, then we blow out of +;;; processing it by throwing to the tag PENDING-INIT. The value we +;;; throw is the entry from *CONSTANTS-BEING-CREATED*. This is so the +;;; offending init form can be tacked onto the init forms for the +;;; circular object. +;;; +;;; If the constant doesn't show up in *CONSTANTS-BEING-CREATED*, then +;;; we have to create it. We call MAKE-LOAD-FORM and check if the +;;; result comes from MAKE-LOAD-FORM-SAVING-SLOTS, and if so we don't +;;; do anything. The dumper will eventually get its hands on the +;;; object and use the normal structure dumping noise on it. +;;; +;;; Otherwise, we bind *CONSTANTS-BEING-CREATED* and +;;; *CONSTANTS-CREATED-SINCE- LAST-INIT* and compile the creation form +;;; much the way LOAD-TIME-VALUE does. When this finishes, we tell the +;;; dumper to use that result instead whenever it sees this constant. +;;; +;;; Now we try to compile the init form. We bind +;;; *CONSTANTS-CREATED-SINCE-LAST-INIT* to NIL and compile the init +;;; form (and any init forms that were added because of circularity +;;; detection). If this works, great. If not, we add the init forms to +;;; the init forms for the object that caused the problems and let it +;;; deal with it. +(defvar *constants-being-created*) +(defvar *constants-created-since-last-init*) +(defun emit-make-load-form (constant &aux (constants-being-created + (if (boundp '*constants-being-created*) + *constants-being-created*)) + (constants-created-since-last-init + (if (boundp '*constants-created-since-last-init*) + *constants-created-since-last-init*)) + (fasl *compile-object*)) + (aver (fasl-output-p fasl)) + (unless (fasl-constant-already-dumped-p constant fasl) + (let ((circular-ref (assoc constant constants-being-created :test #'eq))) + (when circular-ref + (when (find constant constants-created-since-last-init :test #'eq) + (throw constant t)) + (throw 'pending-init circular-ref))) + (multiple-value-bind (creation-form init-form) + (handler-case (make-load-form constant (make-null-lexenv)) + (error (condition) (sb-c:compiler-error condition))) + (cond + ;; Used mainly as an optimization to avoid dumping internal + ;; compiler data structures (see :IGNORE-IT), and to avoid + ;; unnecessary top level lambda forcing. + ((and (null creation-form) (null init-form)) + (sb-fasl::dump-fop 'sb-fasl::fop-empty-list fasl) + (fasl-note-handle-for-constant constant (sb-fasl::dump-pop fasl) fasl) + nil) + ((and + ;; MAKE-LOAD-FORM-SAVING-SLOTS on the cross-compiler needs + ;; the type to be defined for the target. + #+sb-xc-host + (find-classoid (type-of constant) nil) + (multiple-value-bind (ss-creation-form ss-init-form) + (make-load-form-saving-slots constant) + (cond + ((and (typep constant 'structure-object) + (equal creation-form ss-creation-form) + (equal init-form ss-init-form)) + (fasl-validate-structure constant fasl) + t) + ((and (not (typep constant 'structure-object)) + (equal creation-form ss-creation-form) + (subsetp (rest init-form) (rest ss-init-form) :test #'equal)) + (collect ((slot-names)) + (dolist (init (rest init-form)) + (when (eq (first init) 'setf) + (destructuring-bind (slot-value object 'slot-name) + (second init) + (declare (ignore slot-value object quote)) + (slot-names slot-name)))) + (fasl-note-instance-saves-slots constant (slot-names) fasl)) + t))))) + (t + (compile-toplevel-lambdas () t) + (when (fasl-constant-already-dumped-p constant fasl) + (return-from emit-make-load-form nil)) + ;; Allow dumping objects that can't be printed + ;; Non-invocation of PRINT-OBJECT is tested by 'mlf.impure-cload.lisp'. + (let* ((name #+sb-xc-host 'blobby ; the name means nothing + #-sb-xc-host + (format nil "the-~A-formerly-known-as-~X" + (type-of constant) + (get-lisp-obj-address constant))) + (info (if init-form + (list constant name init-form) + (list constant)))) + (let ((*constants-being-created* (cons info constants-being-created)) + (*constants-created-since-last-init* + (cons constant constants-created-since-last-init))) + (when + (catch constant + (fasl-note-handle-for-constant + constant + (compile-load-time-value creation-form) + fasl) + nil) + (compiler-error "circular references in creation form for ~S" + constant))) + (when (cdr info) + (let* ((*constants-created-since-last-init* nil) + (circular-ref + (catch 'pending-init + (loop for (nil form) on (cdr info) by #'cddr + collect form into forms + finally (compile-make-load-form-init-forms forms)) + nil))) + (when circular-ref + (setf (cdr circular-ref) + (append (cdr circular-ref) (cdr info))))))) + nil))))) + ;;;; COMPILE-FILE +;;; The maximum number of top-level lambdas we put in a single top-level +;;; component. +(defparameter top-level-lambda-max 20) + (defun object-call-toplevel-lambda (tll) (declare (type functional tll)) (let ((object *compile-object*)) @@ -1454,21 +1620,33 @@ necessary, since type inference may take arbitrarily long to converge.") (core-object (core-call-toplevel-lambda tll object)) (null)))) -;;; Smash LAMBDAS into a single component, compile it, and arrange for -;;; the resulting function to be called. -(defun sub-compile-toplevel-lambdas (lambdas) +;;; Add LAMBDAS to the pending lambdas. If this leaves more than +;;; TOP-LEVEL-LAMBDA-MAX lambdas in the list, or if FORCE-P is true, +;;; then smash the lambdas into a single component, compile it, and +;;; arrange for the resulting function to be called. +(defun sub-compile-toplevel-lambdas (lambdas force-p) (declare (list lambdas)) - (when lambdas - (multiple-value-bind (component tll) (merge-toplevel-lambdas lambdas) - (compile-component component) - (clear-ir1-info component) - (object-call-toplevel-lambda tll))) + (let ((compilation *compilation*)) + (setf (pending-toplevel-lambdas compilation) + (append (pending-toplevel-lambdas compilation) lambdas)) + (let ((pending (pending-toplevel-lambdas compilation))) + (when (and pending + (or (> (length pending) top-level-lambda-max) + force-p + (package-environment-changed compilation))) + (multiple-value-bind (component tll) + (merge-toplevel-lambdas pending) + (setf (pending-toplevel-lambdas compilation) ()) + (compile-component component) + (clear-ir1-info component) + (object-call-toplevel-lambda tll)) + (setf (package-environment-changed compilation) nil)))) (values)) ;;; Compile top level code and call the top level lambdas. We pick off ;;; top level lambdas in non-top-level components here, calling ;;; SUB-c-t-l-l on each subsequence of normal top level lambdas. -(defun compile-toplevel-lambdas (lambdas) +(defun compile-toplevel-lambdas (lambdas force-p) (declare (list lambdas)) (let ((len (length lambdas))) (flet ((loser (start) @@ -1485,17 +1663,19 @@ necessary, since type inference may take arbitrarily long to converge.") len))) (do* ((start 0 (1+ loser)) (loser (loser start) (loser start))) - ((>= start len)) - (sub-compile-toplevel-lambdas (subseq lambdas start loser)) + ((>= start len) + (when force-p + (sub-compile-toplevel-lambdas nil t))) + (sub-compile-toplevel-lambdas (subseq lambdas start loser) + (or force-p (/= loser len))) (unless (= loser len) (object-call-toplevel-lambda (elt lambdas loser)))))) (values)) ;;; Compile LAMBDAS (a list of CLAMBDAs for top level forms) into the -;;; object file. -;;; -;;; LOAD-TIME-VALUE-P seems to control whether it's MAKE-LOAD-FORM and -;;; COMPILE-LOAD-TIME-VALUE stuff. -- WHN 20000201 +;;; object file. We loop doing local call analysis until it converges, +;;; since a single pass might miss something due to components being +;;; joined by let conversion. (defun compile-toplevel (lambdas load-time-value-p) (declare (list lambdas)) @@ -1509,17 +1689,19 @@ necessary, since type inference may take arbitrarily long to converge.") (maybe-mumble "[Check]~%") (check-ir1-consistency (append components top-components))) - (dolist (component components) - (compile-component component) - (replace-toplevel-xeps component)) + (let ((top-level-closure nil)) + (dolist (component components) + (compile-component component) + (when (replace-toplevel-xeps component) + (setq top-level-closure t))) - (when *check-consistency* - (maybe-mumble "[Check]~%") - (check-ir1-consistency (append components top-components))) + (when *check-consistency* + (maybe-mumble "[Check]~%") + (check-ir1-consistency (append components top-components))) - (if load-time-value-p - (compile-load-time-value-lambda lambdas) - (compile-toplevel-lambdas lambdas)) + (if load-time-value-p + (compile-load-time-value-lambda lambdas) + (compile-toplevel-lambdas lambdas top-level-closure))) (mapc #'clear-ir1-info components)) (values)) @@ -1530,14 +1712,9 @@ necessary, since type inference may take arbitrarily long to converge.") (let ((compilation *compilation*)) (when (block-compile compilation) (when (toplevel-lambdas compilation) - ;; FIXME: Use the source information from the initial - ;; conversion. CMUCL does this right. - (with-source-paths - (compile-toplevel (nreverse (toplevel-lambdas compilation)) nil)) + (compile-toplevel (nreverse (toplevel-lambdas compilation)) nil) (setf (toplevel-lambdas compilation) nil)) - ;; CMUCL always reverts this to :SPECIFIED. But we probably want - ;; to restore it to the user default. - (setf (block-compile compilation) *block-compile-argument*) + (setf (block-compile compilation) :specified) (setf (entry-points compilation) nil)))) (declaim (ftype function handle-condition-p)) @@ -1553,7 +1730,7 @@ necessary, since type inference may take arbitrarily long to converge.") (compiler-error-context-handled-conditions ctxt)) ;; Is this right? I would think that if lexenv is null ;; we should look at *HANDLED-CONDITIONS*. - (null (lexenv-handled-conditions *lexenv*)))) + ((or ctran list) (lexenv-handled-conditions *lexenv*)))) *handled-conditions*)) (handle-p (condition type) #+sb-xc-host (cl:typep condition type) ; TYPE is a sexpr @@ -1595,10 +1772,11 @@ necessary, since type inference may take arbitrarily long to converge.") (declare (type source-info info)) (let ((*package* (sane-package)) (*readtable* *readtable*) - (sb-xc:*compile-file-pathname* nil) ; set by GET-SOURCE-STREAM - (sb-xc:*compile-file-truename* nil) ; " + (*compile-file-pathname* nil) ; set by GET-SOURCE-STREAM + (*compile-file-truename* nil) ; " (*policy* *policy*) (*macro-policy* *macro-policy*) + (*source-info* info) (*compilation* (make-compilation @@ -1623,43 +1801,42 @@ necessary, since type inference may take arbitrarily long to converge.") (declare (ignore error)) (return-from sub-compile-file (values t t t)))) (*current-path* nil) - (sb-xc:*gensym-counter* 0) (sb-impl::*eval-source-info* nil) (sb-impl::*eval-tlf-index* nil) (sb-impl::*eval-source-context* nil)) (handler-case (handler-bind (((satisfies handle-condition-p) #'handle-condition-handler)) (with-compilation-values - (sb-xc:with-compilation-unit () - (with-world-lock () - (setf (sb-fasl::fasl-output-source-info *compile-object*) - (debug-source-for-info info)) - (with-ir1-namespace + (with-compilation-unit () + (fasl-dump-partial-source-info info *compile-object*) + (with-ir1-namespace + (with-source-paths (do-forms-from-info ((form current-index) info 'input-error-in-compile-file) - (with-source-paths - (find-source-paths form current-index) - (let ((sb-xc:*gensym-counter* 0)) - (process-toplevel-form - form `(original-source-start 0 ,current-index) nil)))) - (let ((*source-info* info)) - (finish-block-compilation))) - (let ((code-coverage-records - (code-coverage-records (coverage-metadata *compilation*)))) + (clrhash *source-paths*) + (find-source-paths form current-index) + (note-top-level-form form) + (let ((*gensym-counter* 0)) + (process-toplevel-form + form `(original-source-start 0 ,current-index) nil))) + (finish-block-compilation) + (compile-toplevel-lambdas () t) + (let ((object *compile-object*)) + (etypecase object + (fasl-output (fasl-dump-source-info info object)) + #-sb-xc-host + (core-object (fix-core-source-info info object)) + (null))))) + (let ((code-coverage-records + (code-coverage-records (coverage-metadata *compilation*)))) (unless (zerop (hash-table-count code-coverage-records)) - ;; Dump the code coverage records into the fasl. - (with-source-paths - (fopcompile `(record-code-coverage - ',(namestring sb-xc:*compile-file-pathname*) - ',(let (list) - (maphash (lambda (k v) - (declare (ignore k)) - (push v list)) - code-coverage-records) - list)) - nil - nil)))) - nil)))) + ;; Dump the code coverage records into the fasl. + (sb-fasl::dump-code-coverage-records + (namestring *compile-file-pathname*) + (loop for k being each hash-key of code-coverage-records + collect (cons k +code-coverage-unmarked+)) + *compile-object*))) + nil))) ;; Some errors are sufficiently bewildering that we just fail ;; immediately, without trying to recover and compile more of ;; the input file. @@ -1692,8 +1869,8 @@ necessary, since type inference may take arbitrarily long to converge.") (defun elapsed-time-to-string (internal-time-delta) (multiple-value-bind (tsec remainder) - (truncate internal-time-delta sb-xc:internal-time-units-per-second) - (let ((ms (truncate remainder (/ sb-xc:internal-time-units-per-second 1000)))) + (truncate internal-time-delta internal-time-units-per-second) + (let ((ms (truncate remainder (/ internal-time-units-per-second 1000)))) (multiple-value-bind (tmin sec) (truncate tsec 60) (multiple-value-bind (thr min) (truncate tmin 60) (format nil "~D:~2,'0D:~2,'0D.~3,'0D" thr min sec ms)))))) @@ -1705,10 +1882,10 @@ necessary, since type inference may take arbitrarily long to converge.") #+sb-xc-host (compiler-mumble "~&; ~Aing file ~S:~%" (if sb-cold::*compile-for-effect-only* "load" "x-compil") - (namestring (file-info-name file-info))) + (namestring (file-info-pathname file-info))) #-sb-xc-host (compiler-mumble "~&; compiling file ~S (written ~A):~%" - (namestring (file-info-name file-info)) + (namestring (file-info-pathname file-info)) (format-universal-time nil (file-info-write-date file-info) :style :government @@ -1725,24 +1902,54 @@ necessary, since type inference may take arbitrarily long to converge.") (source-info-start-real-time source-info)))) (values)) +(defglobal *compile-elapsed-time* 0) ; nanoseconds +(defglobal *compile-file-elapsed-time* 0) ; nanoseconds +(defun get-thread-virtual-time () + #+(and linux (not sb-xc-host)) + (multiple-value-bind (sec nsec) + (sb-unix::clock-gettime sb-unix:clock-thread-cputime-id) + (cons sec nsec)) + #-(and linux (not sb-xc-host)) + '(0 . 0)) + +(defun accumulate-compiler-time (symbol start) + (declare (ignorable symbol start)) + #+(and linux (not sb-xc-host)) + (destructuring-bind (sec-after . nsec-after) (get-thread-virtual-time) + (destructuring-bind (sec-before . nsec-before) start + (let* ((sec-diff (- sec-after sec-before)) + (nsec-diff (- nsec-after nsec-before)) + (total-nsec-diff (+ (* sec-diff (* 1000 1000 1000)) + nsec-diff)) + (old (symbol-global-value symbol))) + (loop + ;; FIXME: should we define #'(CAS SYMBOL-GLOBAL-VALUE) ? + ;; Probably want to get it working everywhere first. + (let ((new (+ old total-nsec-diff))) + (when (eq old (setq old + #-x86-64 + (cas (symbol-value symbol) old new) + #+x86-64 + (%cas-symbol-global-value symbol old new))) + (return)))))))) + ;;; Open some files and call SUB-COMPILE-FILE. If something unwinds ;;; out of the compile, then abort the writing of the output file, so ;;; that we don't overwrite it with known garbage. -(defun sb-xc:compile-file +(defun compile-file (input-file &key ;; ANSI options - (output-file (cfp-output-file-default input-file)) - ;; FIXME: ANSI doesn't seem to say anything about - ;; *COMPILE-VERBOSE* and *COMPILE-PRINT* being rebound by this - ;; function.. - ((:verbose sb-xc:*compile-verbose*) sb-xc:*compile-verbose*) - ((:print sb-xc:*compile-print*) sb-xc:*compile-print*) - ((:progress *compile-progress*) *compile-progress*) + (output-file "" output-file-p) + ;; We rebind the specials despite such behavior not being mentioned + ;; in CLHS. Several other lisp implementations do this as well. + ((:verbose *compile-verbose*) *compile-verbose*) + ((:print *compile-print*) *compile-print*) (external-format :default) ;; extensions + ((:progress *compile-progress*) *compile-progress*) (trace-file nil) ((:block-compile *block-compile-argument*) *block-compile-default*) @@ -1751,19 +1958,22 @@ necessary, since type inference may take arbitrarily long to converge.") "Compile INPUT-FILE, producing a corresponding fasl file and returning its filename. - :PRINT - If true, a message per non-macroexpanded top level form is printed - to *STANDARD-OUTPUT*. Top level forms that whose subforms are - processed as top level forms (eg. EVAL-WHEN, MACROLET, PROGN) receive - no such message, but their subforms do. + :OUTPUT-FILE + The name of the FASL to output, NIL for none, T for the default. + (Note the difference between the treatment of NIL :OUTPUT-FILE + here and in COMPILE-FILE-PATHNAME.) The returned pathname of the + output file may differ from the pathname of the :OUTPUT-FILE + parameter, e.g. when the latter is a designator for a directory. + + :VERBOSE + If true, information indicating what file is being compiled is printed + to *STANDARD-OUTPUT*. - As an extension to ANSI, if :PRINT is :top-level-forms, a message - per top level form after macroexpansion is printed to *STANDARD-OUTPUT*. - For example, compiling an IN-PACKAGE form will result in a message about - a top level SETQ in addition to the message about the IN-PACKAGE form' - itself. + :PRINT + If true, each top level form in the file is printed to *STANDARD-OUTPUT*. - Both forms of reporting obey the SB-EXT:*COMPILER-PRINT-VARIABLE-ALIST*. + :EXTERNAL-FORMAT + The external format to use when opening the source file. :BLOCK-COMPILE {NIL | :SPECIFIED | T} Determines whether multiple functions are compiled together as a unit, @@ -1791,13 +2001,14 @@ returning its filename. :EMIT-CFASL (Experimental). If true, outputs the toplevel compile-time effects of this file into a separate .cfasl file." - (let* ((fasl-output nil) + (let* ((output-file-pathname nil) + (fasl-output nil) + (cfasl-pathname nil) (cfasl-output nil) - (output-file-name nil) - (coutput-file-name nil) (abort-p t) (warnings-p nil) (failure-p t) ; T in case error keeps this from being set later + (clock-start (get-thread-virtual-time)) (input-pathname (verify-source-file input-file)) (source-info (make-file-source-info input-pathname external-format @@ -1808,20 +2019,15 @@ returning its filename. (unwind-protect (progn - (when output-file - (setq output-file-name - (sb-xc:compile-file-pathname input-file - :output-file output-file)) - (setq fasl-output - (open-fasl-output output-file-name - (namestring input-pathname)))) + ;; To avoid passing "" as OUTPUT-FILE when unsupplied, we exploit the fact + ;; that COMPILE-FILE-PATHNAME allows random &KEY args. + (setq output-file-pathname + (compile-file-pathname input-file (when output-file-p :output-file) output-file) + fasl-output (open-fasl-output output-file-pathname + (namestring input-pathname))) (when emit-cfasl - (setq coutput-file-name - (make-pathname :type "cfasl" - :defaults output-file-name)) - (setq cfasl-output - (open-fasl-output coutput-file-name - (namestring input-pathname)))) + (setq cfasl-pathname (make-pathname :type "cfasl" :defaults output-file-pathname)) + (setq cfasl-output (open-fasl-output cfasl-pathname (namestring input-pathname)))) (when trace-file (setf *compiler-trace-output* (if (streamp trace-file) @@ -1832,9 +2038,6 @@ returning its filename. (fasl-output-stream fasl-output))) :if-exists :supersede :direction :output)))) - (when sb-xc:*compile-verbose* - (print-compile-start-note source-info)) - (let ((*compile-object* fasl-output)) (setf (values abort-p warnings-p failure-p) (sub-compile-file source-info cfasl-output)))) @@ -1843,47 +2046,50 @@ returning its filename. (when fasl-output (close-fasl-output fasl-output abort-p) - (setq output-file-name - (pathname (fasl-output-stream fasl-output))) - (when (and (not abort-p) sb-xc:*compile-verbose*) - (compiler-mumble "~2&; wrote ~A~%" (namestring output-file-name)))) + ;; There was an assignment here + ;; (setq fasl-pathname (pathname (fasl-output-stream fasl-output))) + ;; which seems pretty bogus, because we've computed the fasl-pathname, + ;; and should return exactly what was computed so that it 100% agrees + ;; with what COMPILE-FILE-PATHNAME said we would write into. + ;; A distorted variation of the name coming from the stream is just wrong, + ;; because do not support versioned pathnames. + (when (and (not abort-p) *compile-verbose*) + (compiler-mumble "~2&; wrote ~A~%" (namestring output-file-pathname)))) (when cfasl-output (close-fasl-output cfasl-output abort-p) - (when (and (not abort-p) sb-xc:*compile-verbose*) - (compiler-mumble "; wrote ~A~%" (namestring coutput-file-name)))) + (when (and (not abort-p) *compile-verbose*) + (compiler-mumble "; wrote ~A~%" (namestring cfasl-pathname)))) - (when sb-xc:*compile-verbose* + (when *compile-verbose* (print-compile-end-note source-info (not abort-p))) ;; Don't nuke stdout if you use :trace-file *standard-output* (when (and trace-file (not (streamp trace-file))) (close *compiler-trace-output*))) + (accumulate-compiler-time '*compile-file-elapsed-time* clock-start) + ;; CLHS says that the first value is NIL if the "file could not ;; be created". We interpret this to mean "a valid fasl could not ;; be created" -- which can happen if the compilation is aborted ;; before the whole file has been processed, due to eg. a reader ;; error. (values (when (and (not abort-p) output-file) - ;; Hack around filesystem race condition... - (or (probe-file output-file-name) output-file-name)) + ;; Again, more bogosity. Why do PROBE-FILE here + ;; when it achieves nothing other than to potentially disagree + ;; with what COMPILE-FILE-PATHNAME returned. + ;; I would guess that the intent of the spec was to not return + ;; pathnames with a wild version component, but it never anticipated + ;; that content-addressable storage would be a thing. + ;; Unfortunately there's no way to give lossless information here + ;; while remaining ANSI-compliant. So let's repurpose the secret + ;; *MERGE-PATHNAMES* option to return pathnames that don't suck. + (or (and *merge-pathnames* (probe-file output-file-pathname)) + output-file-pathname)) warnings-p failure-p))) -;;; a helper function for COMPILE-FILE-PATHNAME: the default for -;;; the OUTPUT-FILE argument -;;; -;;; ANSI: The defaults for the OUTPUT-FILE are taken from the pathname -;;; that results from merging the INPUT-FILE with the value of -;;; *DEFAULT-PATHNAME-DEFAULTS*, except that the type component should -;;; default to the appropriate implementation-defined default type for -;;; compiled files. -(defun cfp-output-file-default (input-file) - (let* ((defaults (merge-pathnames input-file *default-pathname-defaults*)) - (retyped (make-pathname :type *fasl-file-type* :defaults defaults))) - retyped)) - ;;; KLUDGE: Part of the ANSI spec for this seems contradictory: ;;; If INPUT-FILE is a logical pathname and OUTPUT-FILE is unsupplied, ;;; the result is a logical pathname. If INPUT-FILE is a logical @@ -1893,133 +2099,99 @@ returning its filename. ;;; at the level of e.g. whether it returns logical pathname or a ;;; physical pathname. Patches to make it more correct are welcome. ;;; -- WHN 2000-12-09 -(defun sb-xc:compile-file-pathname (input-file - &key - (output-file nil output-file-p) - &allow-other-keys) - "Return a pathname describing what file COMPILE-FILE would write to given - these arguments." - (if output-file-p - (merge-pathnames output-file (cfp-output-file-default input-file)) - (cfp-output-file-default input-file))) - -;;;; MAKE-LOAD-FORM stuff - -;;; The entry point for MAKE-LOAD-FORM support. When IR1 conversion -;;; finds a constant structure, it invokes this to arrange for proper -;;; dumping. If it turns out that the constant has already been -;;; dumped, then we don't need to do anything. ;;; -;;; If the constant hasn't been dumped, then we check to see whether -;;; we are in the process of creating it. We detect this by -;;; maintaining the special *CONSTANTS-BEING-CREATED* as a list of all -;;; the constants we are in the process of creating. Actually, each -;;; entry is a list of the constant and any init forms that need to be -;;; processed on behalf of that constant. +;;; Issues of logical-pathname handling aside, I checked some other lisps +;;; to see what they do with the following two examples: +;;; (COMPILE-FILE "a/b/file.lisp :output-file "x/y/z/") +;;; (COMPILE-FILE "a/b/file.lisp :output-file "x/y/out") +;;; and it turns out that they don't implement the spirit of the law, +;;; forget about the letter of the law. The spirit (intent) is that regardless +;;; of how pathnames are handled, COMPILE-FILE-PATHNAME should tell you exactly +;;; what pathname the compiler would write into given the input and output to +;;; COMPILE-FILE. But they can't even do that much correctly. +;;; So forget about how merging "should" work - it's a crap shoot at best. + +;;; Clozure 1.10-r16196 +;;; ------------------- +;;; ? (COMPILE-FILE-PATHNAME "a/b/file.lisp" :output-file #p"x/y/z/") +;;; => #P"a/b/x/y/z/file.lx64fsl" ; ok, so it thinks it merges input and output dirs +;;; let's confirm by actually compiling: +;;; ? (COMPILE-FILE "a/b/file.lisp" :output-file #p"x/y/z/") +;;; #P"/tmp/sbcl/x/y/z/file.lx64fsl" ; no, it didn't actually. it's what I want though ;;; -;;; It's not necessarily an error for this to happen. If we are -;;; processing the init form for some object that showed up *after* -;;; the original reference to this constant, then we just need to -;;; defer the processing of that init form. To detect this, we -;;; maintain *CONSTANTS-CREATED-SINCE-LAST-INIT* as a list of the -;;; constants created since the last time we started processing an -;;; init form. If the constant passed to emit-make-load-form shows up -;;; in this list, then there is a circular chain through creation -;;; forms, which is an error. -;;; -;;; If there is some intervening init form, then we blow out of -;;; processing it by throwing to the tag PENDING-INIT. The value we -;;; throw is the entry from *CONSTANTS-BEING-CREATED*. This is so the -;;; offending init form can be tacked onto the init forms for the -;;; circular object. +;;; ECL 16.1.3 +;;; ---------- +;;; (compile-file-pathname "a/b/file.lisp" :output-file #p"x/y/z/") +;;; #P"x/y/z/" ; ok, maybe it will do additional defaulting to get the name and type? +;;; (compile-file "a/b/file.lisp" :output-file #p"x/y/z/") +;;; Internal error: +;;; ** Pathname without a physical namestring: +;;; Nope, it won't default them. However: +;;; (compile-file "a/b/file.lisp" :output-file #p"x/y/z/out") +;;; => #P"/tmp/sbcl/x/y/z/out" +;;; so it worked, but it failed to default the file type to '.fas' +;;; which it would have if nothing were specified. ;;; -;;; If the constant doesn't show up in *CONSTANTS-BEING-CREATED*, then -;;; we have to create it. We call %MAKE-LOAD-FORM and check -;;; if the result is 'FOP-STRUCT, and if so we don't do anything. -;;; The dumper will eventually get its hands on the object and use the -;;; normal structure dumping noise on it. +;;; ABCL 1.7.1 +;;; ---------- +;;; (compile-file-pathname "a/b/file.lisp" :output-file #p"x/y/z/") +;;; #P"/tmp/sbcl/a/b/x/y/z/file.lisp" ; OK, so it says it merged input + output dirs +;;; but it didn't stick on a pathname-type. However +;;; (compile-file "a/b/file.lisp" :output-file #p"x/y/z/") +;;; ; Compiling /tmp/sbcl/a/b/file.lisp ... +;;; #<THREAD "interpreter" {E2B80EB}>: Debugger invoked on condition of type SIMPLE-ERROR +;;; Pathname has no namestring: +;;; And now: +;;; (compile-file "a/b/file.lisp" :output-file #p"x/y/z/out.abcl") +;;; => #P"/tmp/sbcl/x/y/z/out.abcl" ; so it *didn't* actually merge dirs, which is fine ;;; -;;; Otherwise, we bind *CONSTANTS-BEING-CREATED* and -;;; *CONSTANTS-CREATED-SINCE- LAST-INIT* and compile the creation form -;;; much the way LOAD-TIME-VALUE does. When this finishes, we tell the -;;; dumper to use that result instead whenever it sees this constant. +;;; But we try our best to give somewhat understandable semantics: +;;; * strongly prefer that all fasls have a pathname-type +;;; whether or not the output was specified. However, if you are sadistic +;;; (and/or enjoy being confusing to others), then :OUTPUT-FILE is permitted +;;; to have :UNSPECIFIC as the type, and it will lack the '.fasl' suffix. +;;; * we can accept just a directory for the output (a namestring ending in "/" +;;; on Unix) and will take the pathname-name from the input +;;; * we will never merge directories from the input to output ;;; -;;; Now we try to compile the init form. We bind -;;; *CONSTANTS-CREATED-SINCE-LAST-INIT* to NIL and compile the init -;;; form (and any init forms that were added because of circularity -;;; detection). If this works, great. If not, we add the init forms to -;;; the init forms for the object that caused the problems and let it -;;; deal with it. -(defvar *constants-being-created* nil) -(defvar *constants-created-since-last-init* nil) -;;; FIXME: Shouldn't these^ variables be unbound outside LET forms? -(defun emit-make-load-form (constant &optional (name nil namep) - &aux (fasl *compile-object*)) - (aver (fasl-output-p fasl)) - (unless (fasl-constant-already-dumped-p constant fasl) - (let ((circular-ref (assoc constant *constants-being-created* :test #'eq))) - (when circular-ref - (when (find constant *constants-created-since-last-init* :test #'eq) - (throw constant t)) - (throw 'pending-init circular-ref))) - ;; If this is a global constant reference, we can call SYMBOL-GLOBAL-VALUE - ;; during LOAD as a fasl op, and not compile a lambda. - ;; However: the cross-compiler can not always emit fop-funcall for this, - ;; because the order of load-time actions is not strictly preserved as it - ;; would be for normal compilation. If the symbol's value needs computation, - ;; then it is unbound during genesis. - ;; So check if assignment was deferred, and if so, also defer the use. - (when (and namep #+sb-xc-host (not (member name *!const-value-deferred*))) - (fopcompile `(symbol-global-value ',name) nil t nil) - (fasl-note-handle-for-constant constant (sb-fasl::dump-pop fasl) fasl) - (return-from emit-make-load-form nil)) - (multiple-value-bind (creation-form init-form) - (cond (namep (values `(symbol-global-value ',name) nil)) - (t (%make-load-form constant))) - (cond - ((eq init-form 'sb-fasl::fop-struct) - (fasl-note-dumpable-instance constant fasl) - t) - (t - (let* ((name (write-to-string constant :level 1 :length 2)) - (info (if init-form - (list constant name init-form) - (list constant)))) - (let ((*constants-being-created* - (cons info *constants-being-created*)) - (*constants-created-since-last-init* - (cons constant *constants-created-since-last-init*))) - (when - (catch constant - (fasl-note-handle-for-constant - constant - (cond ((typep creation-form - '(cons (eql sb-kernel::new-instance) - (cons symbol null))) - (dump-object (cadr creation-form) fasl) - (dump-fop 'sb-fasl::fop-allocate-instance fasl) - (let ((index (sb-fasl::fasl-output-table-free fasl))) - (setf (sb-fasl::fasl-output-table-free fasl) (1+ index)) - index)) - (t - (compile-load-time-value creation-form t))) - fasl) - nil) - (compiler-error "circular references in creation form for ~S" - constant))) - (when (cdr info) - (let* ((*constants-created-since-last-init* nil) - (circular-ref - (catch 'pending-init - (loop for (nil form) on (cdr info) by #'cddr - collect form into forms - finally (compile-make-load-form-init-forms forms fasl)) - nil))) - (when circular-ref - (setf (cdr circular-ref) - (append (cdr circular-ref) (cdr info))))))) - nil))))) +;;; It is unclear what should happen with +;;; (compile-file "sys:contrib;foo.lisp" :output-file "obj") +;;; Is "obj" on the logical host or the physical host? +(defun compile-file-pathname (input-file &key (output-file nil output-file-p) + &allow-other-keys) + "Return a pathname describing what file COMPILE-FILE would write to given + these arguments." + ;; ANSI: The defaults for the OUTPUT-FILE are taken from the pathname + ;; that results from merging the INPUT-FILE with the value of + ;; *DEFAULT-PATHNAME-DEFAULTS*, except that the type component should + ;; default to the appropriate implementation-defined default type for + ;; compiled files. + (let* ((input (pathname input-file)) + (output (if output-file-p (pathname output-file))) + (host/dev/dir + (if (or (not output) (memq (pathname-directory output) '(nil :unspecific))) + input output))) + ;; Merging *D-P-D* here is ridiculous, because every pathname is eventually + ;; merged against it. + ;; Users can set it to #P"" around calling this to obtain a lossless answer. + (merge-pathnames + (flet ((pick (slot default &aux (specified (if output (funcall slot output)))) + ;; :unspecific is left alone, "as if the field were 'filled'" + ;; (http://www.lispworks.com/documentation/HyperSpec/Body/19_bbbca.htm) + ;; which makes little to zero sense at all for the PATHNAME-NAME + ;; of a fasl file, but is allowable for its PATHNAME-TYPE. + (cond ((or (not specified) + (and (eq specified :unspecific) (eq slot 'pathname-name))) + default) + (t + specified)))) + (make-pathname :host (pathname-host host/dev/dir) + :device (pathname-device host/dev/dir) + :directory (pathname-directory host/dev/dir) + :name (pick 'pathname-name (pathname-name input)) + :type (pick 'pathname-type *fasl-file-type*)))))) + ;;; FIXME: find a better place for this. (defun always-boundp (name) (case (info :variable :always-bound name) diff --git a/src/compiler/meta-vmdef.lisp b/src/compiler/meta-vmdef.lisp index b8540f2637..56d3b87eab 100644 --- a/src/compiler/meta-vmdef.lisp +++ b/src/compiler/meta-vmdef.lisp @@ -276,7 +276,8 @@ ;; this operand is allowed into. If NIL, there is no restriction. (scs nil :type (or symbol list) :read-only t) ;; If non-null, we are a temp wired to this offset in SC. - (offset nil :type (or unsigned-byte null) :read-only t)) + (offset nil :type (or unsigned-byte null) :read-only t) + (unused-if nil)) (declaim (freeze-type operand-parse)) (defun operand-parse-sc (parse) ; Enforce a single symbol @@ -302,6 +303,8 @@ (more-results nil :type (or operand-parse null)) ;; a list of all the above together (operands nil :type list) + ;; Which results can accept :unused TNs + (optional-results nil :type list) ;; names of variables that should be declared IGNORE (ignores () :type list) ;; true if this is a :CONDITIONAL VOP. T if a branchful VOP, @@ -339,7 +342,7 @@ (save-p nil :type (member t nil :compute-only :force-to-stack)) ;; info about how to emit MOVE-ARG VOPs for the &MORE operand in ;; call/return VOPs - (move-args nil :type (member nil :local-call :full-call :known-return)) + (move-args nil :type (member nil :local-call :full-call :known-return :fixed)) (args-var '.args. :type symbol) (results-var '.results. :type symbol) (before-load :unspecified :type (or (member :unspecified) list))) @@ -371,7 +374,7 @@ ;;; Order here is insignificant; it happens to be alphabetical. (defglobal vop-parse-slot-names '(arg-types args args-var before-load body conditional-p cost guard ignores info-args inherits - ltn-policy more-args more-results move-args name node-var note result-types + ltn-policy more-args more-results move-args name node-var note optional-results result-types results results-var save-p source-location temps translate variant variant-vars vop-var)) ;; A sanity-check. Of course if this fails, the likelihood is that you can't even ;; get this far in cross-compilaion. So it's probably not worth much. @@ -607,7 +610,7 @@ :num-results ,num-results :ref-ordering ,ordering ,@(when (targets) - `(:targets ,(sb-xc:coerce (targets) `(vector ,te-type))))))))) + `(:targets ,(coerce (targets) `(vector ,te-type))))))))) (defun make-emit-function-and-friends (parse) `(:temps ,(compute-temporaries-description parse) @@ -780,9 +783,67 @@ `(,dummy))) (ignorable ,n-args ,n-results)) ,@(loads) - (assemble () - ,@(vop-parse-body parse)) + ;; RETURN-FROM can exit the ASSEMBLE while continuing on with saves. + (block ,(vop-parse-name parse) + (assemble () + ,@(vop-parse-body parse))) ,@(saves)))))) + +(defun make-after-sc-function (parse) + (let ((unused-temps + (remove-if-not #'operand-parse-unused-if + (vop-parse-temps parse))) + (conditional (typep (vop-parse-conditional-p parse) '(cons (eql :after-sc-selection))))) + (when (or unused-temps + conditional) + (let* ((n-vop (vop-parse-vop-var parse)) + (n-args (vop-parse-args-var parse)) + (n-results (vop-parse-results-var parse)) + (n-info (gensym)) + (n-variant (gensym)) + (bindings + `((,n-args (vop-args ,n-vop)) + (,n-results (vop-results ,n-vop)) + ,@(access-operands (vop-parse-args parse) + (vop-parse-more-args parse) + n-args) + ,@(access-operands (vop-parse-results parse) + (vop-parse-more-results parse) + n-results) + ,@(and unused-temps + (access-operands (vop-parse-temps parse) nil + `(vop-temps ,n-vop))) + ,@(when (vop-parse-info-args parse) + `((,n-info (vop-codegen-info ,n-vop)) + ,@(mapcar (lambda (x) `(,x (pop ,n-info))) + (vop-parse-info-args parse)))) + ,@(when (vop-parse-variant-vars parse) + `((,n-variant (vop-info-variant (vop-info ,n-vop))) + ,@(mapcar (lambda (x) `(,x (pop ,n-variant))) + (vop-parse-variant-vars parse)))) + ,@(loop for op in (vop-parse-operands parse) + when + (ecase (operand-parse-kind op) + ((:argument :result) + `(,(operand-parse-name op) + (tn-ref-tn ,(operand-parse-temp op)))) + (:temporary + (and (operand-parse-unused-if op) + `(,(operand-parse-name op) + (tn-ref-tn ,(operand-parse-temp op))))) + ((:more-argument :more-result))) + collect it)))) + `(lambda (,n-vop) + (let* ,bindings + (declare (ignorable ,@(mapcar #'car bindings))) + ,@(when conditional + `((setf (car (last (vop-codegen-info ,n-vop))) + (progn ,@(cdr (vop-parse-conditional-p parse)))) + (setf (vop-codegen-info ,n-vop) + (butlast (vop-codegen-info ,n-vop))))) + ,@(loop for op in unused-temps + collect `(when ,(operand-parse-unused-if op) + (setf (tn-kind ,(operand-parse-name op)) :unused))))))))) (defvar *parse-vop-operand-count*) (defun make-operand-parse-temp () @@ -811,31 +872,35 @@ (when more (error "The MORE operand isn't the last operand: ~S" specs)) (incf *parse-vop-operand-count*) + (incf num) (let* ((name (first spec)) (old (if (vop-parse-inherits parse) (find-operand name (vop-parse-or-lose (vop-parse-inherits parse)) - (list kind) + (list* kind + (if (eq kind :argument) + '(:more-argument) + '(:more-result))) nil) nil)) (res - (nconc (list :kind kind) - (if old - (list - :target (operand-parse-target old) - :born (operand-parse-born old) - :dies (operand-parse-dies old) - :scs (operand-parse-scs old) - :load-tn (operand-parse-load-tn old) - :load (operand-parse-load old)) - (ecase kind - (:argument - (list :born (parse-time-spec :load) - :dies (parse-time-spec `(:argument ,(incf num))))) - (:result - (list :born (parse-time-spec `(:result ,(incf num))) - :dies (parse-time-spec :save)))))))) + (nconc (list :kind kind) + (if old + (list + :target (operand-parse-target old) + :born (operand-parse-born old) + :dies (operand-parse-dies old) + :scs (operand-parse-scs old) + :load-tn (operand-parse-load-tn old) + :load (operand-parse-load old)) + (ecase kind + (:argument + (list :born (parse-time-spec :load) + :dies (parse-time-spec `(:argument ,num)))) + (:result + (list :born (parse-time-spec `(:result ,num)) + :dies (parse-time-spec :save)))))))) (do ((tail (rest spec) (cddr tail))) ((null tail)) (let ((key (first tail)) @@ -896,6 +961,11 @@ (dolist (name (cddr spec)) (unless (symbolp name) (error "bad temporary name: ~S" name)) + ;; It's almost always a mistake to have overlaps in the operand names. + ;; But I guess that some users think it's fine? + #+sb-xc-host + (when (member name (vop-parse-temps parse) :key #'operand-parse-name) + (warn "temp ~s already exists in ~s" name (vop-parse-name parse))) (incf *parse-vop-operand-count*) (let ((res (list :born (parse-time-spec :load) :dies (parse-time-spec :save)))) @@ -920,6 +990,7 @@ (unless (= (length scs) 1) (error "must specify exactly one SC for a temporary")) (setf value (first scs)))) + (:unused-if) (t (error "unknown temporary option: ~S" opt))) (setf (getf res key) value))) @@ -1010,7 +1081,7 @@ (:move-args (setf (vop-parse-move-args parse) (vop-spec-arg spec '(member nil :local-call :full-call - :known-return)))) + :known-return :fixed)))) (:node-var (setf (vop-parse-node-var parse) (vop-spec-arg spec 'symbol))) (:note @@ -1037,6 +1108,10 @@ (setf (vop-parse-save-p parse) (vop-spec-arg spec '(member t nil :compute-only :force-to-stack)))) + (:optional-results + (setf (vop-parse-optional-results parse) + (append (vop-parse-optional-results parse) + (rest spec)))) (t (error "unknown option specifier: ~S" (first spec))))) (values))) @@ -1094,11 +1169,11 @@ (values costs load-scs))) (defconstant-eqx +no-costs+ - (make-array sb-vm:sc-number-limit :initial-element 0) + (make-array sb-vm:sc-number-limit :initial-element 0) #'equalp) (defconstant-eqx +no-loads+ - (make-array sb-vm:sc-number-limit :initial-element t) + (make-array sb-vm:sc-number-limit :initial-element t) #'equalp) ;;; Pick off the case of operands with no restrictions. @@ -1123,23 +1198,26 @@ (compute-costs-and-restrictions-list (vop-parse-args parse) t) (multiple-value-bind (result-costs result-scs) (compute-costs-and-restrictions-list (vop-parse-results parse) nil) - `( - :cost ,(vop-parse-cost parse) - - :arg-costs ',arg-costs - :arg-load-scs ',arg-scs - :result-costs ',result-costs - :result-load-scs ',result-scs - - :more-arg-costs - ',(if (vop-parse-more-args parse) - (compute-loading-costs-if-any (vop-parse-more-args parse) t) - nil) - - :more-result-costs - ',(if (vop-parse-more-results parse) - (compute-loading-costs-if-any (vop-parse-more-results parse) nil) - nil))))) + (multiple-value-bind (more-arg-costs more-arg-scs) + (and (vop-parse-more-args parse) + (compute-loading-costs-if-any (vop-parse-more-args parse) t)) + `(:cost ,(vop-parse-cost parse) + + :arg-costs ',arg-costs + :arg-load-scs ',arg-scs + :result-costs ',result-costs + :result-load-scs ',result-scs + + :more-arg-costs ',more-arg-costs + :more-arg-load-scs ',(unless (eq more-arg-costs +no-loads+) + (substitute-if nil #'listp more-arg-scs)) + + :more-result-costs + ',(if (vop-parse-more-results parse) + (compute-loading-costs-if-any (vop-parse-more-results parse) nil) + nil) + :optional-results ',(loop for name in (vop-parse-optional-results parse) + collect (position name (vop-parse-results parse) :key #'operand-parse-name))))))) ;;;; operand checking and stuff @@ -1222,7 +1300,9 @@ (when (sc-allowed-by-primitive-type (sc-or-lose sc) (primitive-type-or-lose ptype)) - (return t)))) + (return t))) + #+arm64 + (eq sc 'sb-vm::zero)) (warn "~:[Result~;Argument~] ~A to VOP ~S~@ has SC restriction ~S which is ~ not allowed by the operand type:~% ~S" @@ -1339,6 +1419,8 @@ :more-args-type ,(when more-args (make-operand-type more-arg)) :result-types ,(cond ((eq conditional t) :conditional) + ((eql (car conditional) :after-sc-selection) + ''(:conditional :after-sc-selection)) (conditional `'(:conditional . ,conditional)) (t @@ -1385,8 +1467,10 @@ `(make-vop-info :name ',(vop-parse-name parse) ,@(make-vop-info-types parse) - :guard ,(when (vop-parse-guard parse) - `(lambda () ,(vop-parse-guard parse))) + :guard ,(awhen (vop-parse-guard parse) + (if (typep it '(cons (eql lambda))) + it + `(lambda (node) (declare (ignore node)) ,it))) :note ',(vop-parse-note parse) :info-arg-count ,(length (vop-parse-info-args parse)) :ltn-policy ',(vop-parse-ltn-policy parse) @@ -1399,7 +1483,10 @@ (equal (vop-parse-body parse) (vop-parse-body iparse))) (unless (eq (vop-parse-body parse) :unspecified) (make-generator-function parse))) - :variant (list ,@variant)))) + :variant (list ,@variant) + :after-sc-selection + ;; TODO: inherit it? + ,(make-after-sc-function parse)))) ;;; Define the symbol NAME to be a Virtual OPeration in the compiler. ;;; If specified, INHERITS is the name of a VOP that we default @@ -1546,6 +1633,8 @@ ;;; Specifies a Form that is evaluated in the global environment. ;;; If form returns NIL, then emission of this VOP is prohibited ;;; even when all other restrictions are met. +;;; As an additional possibility, if Form is a lambda expression, +;;; then it is funcalled with the node under consideration. ;;; ;;; :VOP-VAR Name ;;; :NODE-VAR Name @@ -1559,6 +1648,9 @@ ;;; Indicates if and how the more args should be moved into a ;;; different frame. (defmacro define-vop ((&optional name inherits) &body specs) + (%define-vop name inherits specs t)) + +(defun %define-vop (name inherits specs set) (declare (type symbol name)) ;; Parse the syntax into a VOP-PARSE structure, and then expand into ;; code that creates the appropriate VOP-INFO structure at load time. @@ -1574,8 +1666,9 @@ (let ((clause (assoc :translate specs))) (when (singleton-p (cdr clause)) (setf name (cadr clause))))) - (aver (typep name '(and symbol (not null)))) - (setf (vop-parse-name parse) name) + (when set + (aver (typep name '(and symbol (not null)))) + (setf (vop-parse-name parse) name)) (setf (vop-parse-inherits parse) inherits) (parse-define-vop parse specs) @@ -1590,79 +1683,144 @@ (vop-parse-more-results parse) (vop-parse-result-types parse) nil) - `(progn - (eval-when (:compile-toplevel) - (setf (gethash ',name *backend-parsed-vops*) ',parse)) - (register-vop-parse - ,@(macrolet - ((quotify-slots () - (collect ((forms)) - (dolist (x vop-parse-slot-names (cons 'list (forms))) - (let ((reader (package-symbolicate (sb-xc:symbol-package 'vop-parse) - "VOP-PARSE-" x))) - (forms - (case x - (source-location ''(source-location)) - ((temps args results) `(quotify-list (,reader parse))) - ((more-args more-results) `(quotify (,reader parse))) - (t `(list 'quote (,reader parse)))))))))) - (labels ((quotify (operand-or-nil) - (when operand-or-nil - (list 'quote (quotify-1 operand-or-nil)))) - (quotify-list (operands) - (list 'quote (mapcar #'quotify-1 operands))) - (quotify-1 (x) ; Return everything except the KIND, quoted - `(,(operand-parse-name x) - ,(operand-parse-target x) ,(operand-parse-temp x) - ,(operand-parse-born x) ,(operand-parse-dies x) - ,(operand-parse-load-tn x) ,(operand-parse-load x) - ,(operand-parse-scs x) ,(operand-parse-offset x)))) - (quotify-slots)))) - ,@(unless (eq (vop-parse-body parse) :unspecified) - `((let ((,n-res ,(set-up-vop-info inherited-parse parse))) - (store-vop-info ,n-res) - ,@(set-up-fun-translation parse n-res)))) - ',name))) + (if set + `(progn + (eval-when (:compile-toplevel) + (setf (gethash ',name *backend-parsed-vops*) ',parse)) + (register-vop-parse + ,@(macrolet + ((quotify-slots () + (collect ((forms)) + (dolist (x vop-parse-slot-names (cons 'list (forms))) + (let ((reader (package-symbolicate (sb-xc:symbol-package 'vop-parse) + "VOP-PARSE-" x))) + (forms + (case x + (source-location ''(source-location)) + ((temps args results) `(quotify-list (,reader parse))) + ((more-args more-results) `(quotify (,reader parse))) + (t `(list 'quote (,reader parse)))))))))) + (labels ((quotify (operand-or-nil) + (when operand-or-nil + (list 'quote (quotify-1 operand-or-nil)))) + (quotify-list (operands) + (list 'quote (mapcar #'quotify-1 operands))) + (quotify-1 (x) ; Return everything except the KIND, quoted + `(,(operand-parse-name x) + ,(operand-parse-target x) ,(operand-parse-temp x) + ,(operand-parse-born x) ,(operand-parse-dies x) + ,(operand-parse-load-tn x) ,(operand-parse-load x) + ,(operand-parse-scs x) ,(operand-parse-offset x)))) + (quotify-slots)))) + ,@(unless (eq (vop-parse-body parse) :unspecified) + `((let ((,n-res ,(set-up-vop-info inherited-parse parse))) + (store-vop-info ,n-res) + ,@(set-up-fun-translation parse n-res)))) + ',name) + `(let ((info ,(set-up-vop-info inherited-parse parse))) + (setf (vop-info-type info) + (specifier-type (template-type-specifier info))) + info)))) + +;;; (inline-vop +;;; (((param unsigned-reg unsigned-num :to :save) arg) +;;; ((temp unsigned-reg unsigned-num)) +;;; ((temp2))) ;; will reuse the previous specifications +;;; ((result unsigned-reg unsigned-num)) +;;; (inst x result temp param)) +(defmacro inline-vop (vars results &body body) + (collect ((input) + (args) + (arg-types) + (infos) + (temps) + (results) + (result-types)) + (loop for (var arg) in vars + for (name this-sc) = var + for (nil sc type . rest) = (if this-sc + var + prev) + for prev = (if this-sc + var + prev) + do (cond ((eq name :info) + (infos this-sc) + (input arg)) + (arg + (input arg) + (args (list* name :scs (list sc) rest)) + (arg-types (or type '*))) + (t + (temps `(:temporary (:sc ,sc ,@rest) + ,name))))) + (loop for result in results + for (name this-sc) = result + for (nil sc type . rest) = (if this-sc + result + prev) + for prev = (if this-sc + result + prev) + do (results (list* name :scs (list sc) rest)) + (result-types (or type '*))) + `(inline-%primitive + ,(eval (%define-vop nil nil + (delete nil + (list* (and (args) + (list* :args (args))) + (and (arg-types) + (list* :arg-types (arg-types))) + (and (results) + (list* :results (results))) + (and (result-types) + (list* :result-types (result-types))) + (and (infos) + (list* :info (infos))) + (list* :generator 0 body) + (temps))) + nil)) + ,@(input)))) (macrolet - ((def () - `(defun register-vop-parse ,vop-parse-slot-names - ;; Try to share each OPERAND-PARSE structure with a similar existing one. - (labels ((share-list (operand-specs accessor kind) - (let ((new (mapcar (lambda (x) (share x kind)) operand-specs))) - (dohash ((key parse) *backend-parsed-vops* :result new) - (declare (ignore key)) - (when (equal (funcall accessor parse) new) - (return (funcall accessor parse)))))) - (share (operand-spec kind) - ;; OPERAND-PARSE structures are immutable. Scan all vops for one - ;; with an operand matching OPERAND-SPEC, and use that if found. - (destructuring-bind (name targ temp born dies load-tn load scs offs) - operand-spec - (let ((op (make-operand-parse - :name name :kind kind :target targ :temp temp - :born born :dies dies :load-tn load-tn :load load - :scs scs :offset offs))) - (dohash ((key parse) *backend-parsed-vops* :result op) - (declare (ignore key)) - (awhen (find op (vop-parse-operands parse) :test #'operand=) - (return it)))))) - (operand= (a b) - ;; EQUALP is too weak a comparator for arbitrary sexprs, - ;; since (EQUALP "foo" #(#\F #\O #\O)) is T, not that - ;; we expect such weirdness in the LOAD-IF expression. - (and (equal (operand-parse-load a) (operand-parse-load b)) - (equalp a b)))) - (setq temps (share-list temps #'vop-parse-temps :temporary) - args (share-list args #'vop-parse-args :argument) - results (share-list results #'vop-parse-results :result)) - (when more-args (setq more-args (share more-args :more-argument))) - (when more-results (setq more-results (share more-results :more-result)))) - (let ((parse - (make-vop-parse ,@(mapcan (lambda (x) (list (keywordicate x) x)) - vop-parse-slot-names)))) - (set-vop-parse-operands parse) - (setf (gethash name *backend-parsed-vops*) parse))))) + ((def () + `(defun register-vop-parse ,vop-parse-slot-names + ;; Try to share each OPERAND-PARSE structure with a similar existing one. + (labels ((share-list (operand-specs accessor kind) + (let ((new (mapcar (lambda (x) (share x kind)) operand-specs))) + (dohash ((key parse) *backend-parsed-vops* :result new) + (declare (ignore key)) + (when (equal (funcall accessor parse) new) + (return (funcall accessor parse)))))) + (share (operand-spec kind) + ;; OPERAND-PARSE structures are immutable. Scan all vops for one + ;; with an operand matching OPERAND-SPEC, and use that if found. + (destructuring-bind (name targ temp born dies load-tn load scs offs) + operand-spec + (let ((op (make-operand-parse + :name name :kind kind :target targ :temp temp + :born born :dies dies :load-tn load-tn :load load + :scs scs :offset offs))) + (dohash ((key parse) *backend-parsed-vops* :result op) + (declare (ignore key)) + (awhen (find op (vop-parse-operands parse) :test #'operand=) + (return it)))))) + (operand= (a b) + ;; EQUALP is too weak a comparator for arbitrary sexprs, + ;; since (EQUALP "foo" #(#\F #\O #\O)) is T, not that + ;; we expect such weirdness in the LOAD-IF expression. + (and (equal (operand-parse-load a) (operand-parse-load b)) + (equalp a b)))) + (setq temps (share-list temps #'vop-parse-temps :temporary) + args (share-list args #'vop-parse-args :argument) + results (share-list results #'vop-parse-results :result)) + (when more-args (setq more-args (share more-args :more-argument))) + (when more-results (setq more-results (share more-results :more-result)))) + (let ((parse + (make-vop-parse ,@(mapcan (lambda (x) (list (keywordicate x) x)) + vop-parse-slot-names)))) + (set-vop-parse-operands parse) + (setf (gethash name *backend-parsed-vops*) parse))))) (def)) (defun store-vop-info (vop-info) @@ -1718,8 +1876,27 @@ (try-coalescing vop-info-temps) (try-coalescing vop-info-ref-ordering) (try-coalescing vop-info-targets))) + ;; vop rdefinition should be allowed, but a dup in the cross-compiler + ;; is probably a mistake. REGISTER-VOP-PARSE is the wrong place + ;; to check this, because parsing has both compile-time and load-time + ;; effects, since inheritance is computed at compile-time. + ;; And there are false positives with any DEFINE-VOP in an assembler file + ;; because those are processed twice. I don't know what to do. + #+nil (when (gethash (vop-info-name vop-info) *backend-template-names*) + (warn "Duplicate vop name: ~s" vop-info)) (setf (gethash (vop-info-name vop-info) *backend-template-names*) vop-info)) + +(defun undefine-vop (name) + (let ((parse (gethash name *backend-parsed-vops*))) + (dolist (translate (vop-parse-translate parse)) + (let ((info (info :function :info translate))) + (setf (fun-info-templates info) + (delete name (fun-info-templates info) + :key #'vop-info-name)) + (format t "~&~s has ~d templates~%" translate (length (fun-info-templates info))))) + (remhash name *backend-parsed-vops*) + (remhash name *backend-template-names*))) ;;;; emission macros @@ -1957,17 +2134,18 @@ (when (and ,tn-var (not (eq ,tn-var :more))) (,bod ,tn-var))))))))))) -;;; Iterate over all the IR2 blocks in PHYSENV, in emit order. -(defmacro do-physenv-ir2-blocks ((block-var physenv &optional result) - &body body) - (once-only ((n-physenv physenv)) - (once-only ((n-first `(lambda-block (physenv-lambda ,n-physenv)))) +;;; Iterate over all the IR2 blocks in the environment ENV, in emit +;;; order. +(defmacro do-environment-ir2-blocks ((block-var env &optional result) + &body body) + (once-only ((n-env env)) + (once-only ((n-first `(lambda-block (environment-lambda ,n-env)))) (once-only ((n-tail `(block-info (component-tail (block-component ,n-first))))) `(do ((,block-var (block-info ,n-first) (ir2-block-next ,block-var))) ((or (eq ,block-var ,n-tail) - (not (eq (ir2-block-physenv ,block-var) ,n-physenv))) + (not (eq (ir2-block-environment ,block-var) ,n-env))) ,result) ,@body))))) diff --git a/src/compiler/mips/alloc.lisp b/src/compiler/mips/alloc.lisp index 06e5dd4283..930e8210bc 100644 --- a/src/compiler/mips/alloc.lisp +++ b/src/compiler/mips/alloc.lisp @@ -10,28 +10,39 @@ ;;;; files for more information. (in-package "SB-VM") + +(defun allocation (type size result lowtag temps &key stackp) + (cond (stackp + (align-csp (car temps) (cadr temps)) + (inst or result csp-tn lowtag) + (inst add csp-tn size)) + (t + (let ((end-addr (car temps)) + (new-freeptr (cadr temps)) + (region (if (eq type 'list) cons-region mixed-region))) + (without-scheduling () + (inst lw result null-tn (- region nil-value)) + (inst lw end-addr null-tn (+ 4 (- region nil-value))) + (inst add new-freeptr result size) + (inst tltu end-addr new-freeptr + (logior (if (eq type 'list) #x100 0) (reg-tn-encoding result))) + (inst sw new-freeptr null-tn (- region nil-value)) + (unless (= lowtag 0) + (inst or result lowtag))))))) ;;;; LIST and LIST* -(define-vop (list-or-list*) - (:args (things :more t)) +(define-vop (list) + (:args (things :more t :scs (any-reg descriptor-reg zero null control-stack))) (:temporary (:scs (descriptor-reg)) ptr) (:temporary (:scs (descriptor-reg)) temp) (:temporary (:scs (descriptor-reg) :to (:result 0) :target result) res) (:temporary (:sc non-descriptor-reg :offset nl4-offset) pa-flag) - (:info num) + (:info star cons-cells) (:results (result :scs (descriptor-reg))) - (:variant-vars star) - (:policy :safe) (:node-var node) (:generator 0 - (cond ((zerop num) - (move result null-tn)) - ((and star (= num 1)) - (move result (tn-ref-tn things))) - (t - (macrolet - ((store-car (tn list &optional (slot cons-car-slot)) + (macrolet ((store-car (tn list &optional (slot cons-car-slot)) `(let ((reg (sc-case ,tn ((any-reg descriptor-reg zero null) @@ -40,17 +51,11 @@ (load-stack-tn temp ,tn) temp)))) (storew reg ,list ,slot list-pointer-lowtag)))) - (let* ((dx-p (node-stack-allocate-p node)) - (cons-cells (if star (1- num) num)) - (alloc (* (pad-data-block cons-size) cons-cells))) - (pseudo-atomic (pa-flag :extra (if dx-p 0 alloc)) - (when dx-p - (align-csp res)) - (inst srl res (if dx-p csp-tn alloc-tn) n-lowtag-bits) - (inst sll res n-lowtag-bits) - (inst or res list-pointer-lowtag) - (when dx-p - (inst addu csp-tn alloc)) + (let ((dx-p (node-stack-allocate-p node)) + (alloc (* (pad-data-block cons-size) cons-cells))) + (pseudo-atomic (pa-flag :elide-if dx-p) + (allocation 'list alloc res list-pointer-lowtag + `(,pa-flag ,temp) :stackp dx-p) (move ptr res) (dotimes (i (1- cons-cells)) (store-car (tn-ref-tn things) ptr) @@ -67,13 +72,7 @@ (storew null-tn ptr cons-cdr-slot list-pointer-lowtag))) (aver (null (tn-ref-across things))) - (move result res)))))))) - -(define-vop (list list-or-list*) - (:variant nil)) - -(define-vop (list* list-or-list*) - (:variant t)) + (move result res)))))) ;;;; Special purpose inline allocators. @@ -87,6 +86,7 @@ positive-fixnum) (:temporary (:sc non-descriptor-reg) bytes) (:temporary (:sc non-descriptor-reg :offset nl4-offset) pa-flag) + (:temporary (:sc non-descriptor-reg) temp) (:results (result :scs (descriptor-reg) :from :load)) (:policy :fast-safe) (:generator 100 @@ -95,8 +95,7 @@ (inst srl bytes n-lowtag-bits) (inst sll bytes n-lowtag-bits) (pseudo-atomic (pa-flag) - (inst or result alloc-tn other-pointer-lowtag) - (inst addu alloc-tn bytes) + (allocation type bytes result other-pointer-lowtag `(,pa-flag ,temp)) (storew type result 0 other-pointer-lowtag) (storew length result vector-length-slot other-pointer-lowtag)))) @@ -118,8 +117,8 @@ (inst srl bytes n-lowtag-bits) (inst sll bytes n-lowtag-bits) ;; FIXME: It would be good to check for stack overflow here. - (pseudo-atomic (pa-flag) - (align-csp temp) + (pseudo-atomic (pa-flag) ; FIXME: why pseudo-atomic on stack? + (align-csp temp pa-flag) (inst or result csp-tn other-pointer-lowtag) (inst addu temp csp-tn (* vector-data-offset n-word-bytes)) (inst addu csp-tn bytes) @@ -130,7 +129,7 @@ (storew zero-tn temp 0) (inst bne temp csp-tn loop) (inst addu temp n-word-bytes)) - (align-csp temp)))) + (align-csp temp pa-flag)))) ; why do it again??? (define-vop (make-fdefn) (:policy :fast-safe) @@ -156,15 +155,9 @@ (:generator 10 (let* ((size (+ length closure-info-offset)) (alloc-size (pad-data-block size))) - (pseudo-atomic (pa-flag :extra (if stack-allocate-p 0 alloc-size)) - (cond (stack-allocate-p - (align-csp result) - (inst srl result csp-tn n-lowtag-bits) - (inst addu csp-tn alloc-size)) - (t - (inst srl result alloc-tn n-lowtag-bits))) - (inst sll result n-lowtag-bits) - (inst or result fun-pointer-lowtag) + (pseudo-atomic (pa-flag :elide-if stack-allocate-p) + (allocation closure-widetag alloc-size result fun-pointer-lowtag + `(,pa-flag ,temp) :stackp stack-allocate-p) (inst li temp (logior (ash (1- size) n-widetag-bits) closure-widetag)) (storew temp result 0 fun-pointer-lowtag) @@ -204,23 +197,15 @@ (:temporary (:scs (non-descriptor-reg)) temp) (:temporary (:sc non-descriptor-reg :offset nl4-offset) pa-flag) (:generator 4 - (pseudo-atomic (pa-flag :extra (if stack-allocate-p - 0 - (pad-data-block words))) + (pseudo-atomic (pa-flag) (cond (stack-allocate-p - (align-csp result) + (align-csp result pa-flag) (inst or result csp-tn lowtag) (inst addu csp-tn (pad-data-block words))) (t - ;; The pseudo-atomic bit in alloc-tn is set. If the - ;; lowtag also has a 1 bit in the same position, we're all - ;; set. Otherwise, we need to subtract the pseudo-atomic - ;; bit. - (inst or result alloc-tn (if (logbitp 0 lowtag) lowtag - (1- lowtag))))) - (when type - (inst li temp (logior (ash (1- words) (length-field-shift type)) type)) - (storew temp result 0 lowtag))))) + (allocation type (pad-data-block words) result lowtag `(,pa-flag ,temp)))) + (inst li temp (compute-object-header words type)) + (storew temp result 0 lowtag)))) (define-vop (var-alloc) (:args (extra :scs (any-reg))) @@ -229,7 +214,7 @@ (:ignore name stack-allocate-p) (:results (result :scs (descriptor-reg))) (:temporary (:scs (any-reg)) bytes) - (:temporary (:scs (non-descriptor-reg)) header) + (:temporary (:scs (non-descriptor-reg)) header temp) (:temporary (:sc non-descriptor-reg :offset nl4-offset) pa-flag) (:generator 6 (inst addu bytes extra (* (1+ words) n-word-bytes)) @@ -243,7 +228,5 @@ (inst srl bytes bytes n-lowtag-bits) (inst sll bytes bytes n-lowtag-bits))) (pseudo-atomic (pa-flag) - (inst or result alloc-tn lowtag) - (storew header result 0 lowtag) - (inst addu alloc-tn alloc-tn bytes)))) - + (allocation type bytes result lowtag `(,pa-flag ,temp)) + (storew header result 0 lowtag)))) diff --git a/src/compiler/mips/arith.lisp b/src/compiler/mips/arith.lisp index c248436afd..8b8b0badd3 100644 --- a/src/compiler/mips/arith.lisp +++ b/src/compiler/mips/arith.lisp @@ -191,7 +191,7 @@ (:generator 3 (inst bgez amount positive) (inst subu ndesc zero-tn amount) - (inst slt temp ndesc 32) + (inst slt temp ndesc 32) ; FIXME: should be sltu here ? (inst bne temp done) (inst srl result number ndesc) (inst b done) @@ -217,7 +217,7 @@ (:generator 3 (inst bgez amount positive) (inst subu ndesc zero-tn amount) - (inst slt temp ndesc 31) + (inst sltu temp ndesc 31) (inst bne temp done) (inst sra result number ndesc) (inst b done) @@ -581,33 +581,19 @@ ;;;; 32-bit logical operations -(define-vop (shift-towards-someplace) - (:policy :fast-safe) - (:args (num :scs (unsigned-reg)) - (amount :scs (signed-reg))) - (:arg-types unsigned-num tagged-num) - (:results (r :scs (unsigned-reg))) - (:result-types unsigned-num)) - -(define-vop (shift-towards-start shift-towards-someplace) - (:translate shift-towards-start) - (:note "SHIFT-TOWARDS-START") - (:generator 1 - (ecase *backend-byte-order* - (:big-endian - (inst sll r num amount)) - (:little-endian - (inst srl r num amount))))) - -(define-vop (shift-towards-end shift-towards-someplace) - (:translate shift-towards-end) - (:note "SHIFT-TOWARDS-END") - (:generator 1 - (ecase *backend-byte-order* - (:big-endian - (inst srl r num amount)) - (:little-endian - (inst sll r num amount))))) +(macrolet ((define (translate operation) + `(define-vop () + (:translate ,translate) + (:note ,(string translate)) + (:policy :fast-safe) + (:args (num :scs (unsigned-reg)) + (amount :scs (signed-reg))) + (:arg-types unsigned-num tagged-num) + (:results (r :scs (unsigned-reg))) + (:result-types unsigned-num) + (:generator 1 (inst ,operation r num amount))))) + (define shift-towards-start #+big-endian sll #+little-endian srl) + (define shift-towards-end #+big-endian srl #+little-endian sll)) ;;;; Modular arithmetic (define-modular-fun +-mod32 (x y) + :untagged nil 32) @@ -629,7 +615,7 @@ fast-ash-left/unsigned=>unsigned)) (deftransform ash-left-mod32 ((integer count) ((unsigned-byte 32) (unsigned-byte 5))) - (when (sb-c::constant-lvar-p count) + (when (sb-c:constant-lvar-p count) (sb-c::give-up-ir1-transform)) '(%primitive fast-ash-left-mod32/unsigned=>unsigned integer count)) diff --git a/src/compiler/mips/array.lisp b/src/compiler/mips/array.lisp index 75e84f77a9..505a93cb7b 100644 --- a/src/compiler/mips/array.lisp +++ b/src/compiler/mips/array.lisp @@ -18,7 +18,7 @@ (:args (type :scs (any-reg)) (rank :scs (any-reg))) (:arg-types positive-fixnum positive-fixnum) - (:temporary (:scs (non-descriptor-reg)) bytes header) + (:temporary (:scs (non-descriptor-reg)) bytes header temp) (:temporary (:sc non-descriptor-reg :offset nl4-offset) pa-flag) (:results (result :scs (descriptor-reg))) (:generator 13 @@ -26,16 +26,17 @@ lowtag-mask)) (inst srl bytes n-lowtag-bits) (inst sll bytes n-lowtag-bits) - (inst addu header rank (fixnumize (1- array-dimensions-offset))) - (inst sll header n-widetag-bits) + ;; Compute the encoded rank. See ENCODE-ARRAY-RANK. + (inst addu header rank (fixnumize -1)) + (inst and header header (fixnumize array-rank-mask)) + (inst sll header header array-rank-position) (inst or header type) ;; Remove the extraneous fixnum tag bits because TYPE and RANK ;; were fixnums (inst srl header n-fixnum-tag-bits) (pseudo-atomic (pa-flag) - (inst or result alloc-tn other-pointer-lowtag) - (storew header result 0 other-pointer-lowtag) - (inst addu alloc-tn bytes)))) + (allocation type bytes result other-pointer-lowtag `(,pa-flag ,temp)) + (storew header result 0 other-pointer-lowtag)))) ;;;; Additional accessors and setters for the array header. (define-full-reffer %array-dimension * @@ -46,17 +47,20 @@ array-dimensions-offset other-pointer-lowtag (any-reg) positive-fixnum %set-array-dimension) -(define-vop (array-rank-vop) +(define-vop () (:translate %array-rank) (:policy :fast-safe) (:args (x :scs (descriptor-reg))) - (:temporary (:scs (non-descriptor-reg)) temp) - (:results (res :scs (any-reg descriptor-reg))) + (:results (res :scs (unsigned-reg))) + (:result-types positive-fixnum) (:generator 6 - (loadw temp x 0 other-pointer-lowtag) - (inst sra temp n-widetag-bits) - (inst subu temp (1- array-dimensions-offset)) - (inst sll res temp n-fixnum-tag-bits))) + ;; convert ARRAY-RANK-POSITION to byte index and compensate for endianness + ;; ASSUMPTION: n-widetag-bits = 8 and rank is adjacent to widetag + (inst lbu res x #+little-endian (- 1 other-pointer-lowtag) + #+big-endian (- 2 other-pointer-lowtag)) + (inst nop) + (inst addu res 1) + (inst and res array-rank-mask))) ;;;; Bounds checking routine. (define-vop (check-bound) @@ -82,27 +86,58 @@ ;;; elements are represented in integer registers and are built out of ;;; 8, 16, or 32 bit elements. (macrolet ((def-full-data-vector-frobs (type element-type &rest scs) - `(progn - (define-full-reffer ,(symbolicate "DATA-VECTOR-REF/" type) ,type - vector-data-offset other-pointer-lowtag - ,(remove-if #'(lambda (x) (member x '(null zero))) scs) - ,element-type - data-vector-ref) - (define-full-setter ,(symbolicate "DATA-VECTOR-SET/" type) ,type - vector-data-offset other-pointer-lowtag ,scs ,element-type - data-vector-set))) - + `(progn (define-full-reffer ,(symbolicate "DATA-VECTOR-REF/" type) ,type + vector-data-offset other-pointer-lowtag + ,(remove-if #'(lambda (x) (member x '(null zero))) scs) + ,element-type + data-vector-ref) + (define-full-setter ,(symbolicate "DATA-VECTOR-SET/" type) ,type + vector-data-offset other-pointer-lowtag ,scs ,element-type + data-vector-set))) (def-partial-data-vector-frobs (type element-type size signed &rest scs) - `(progn - (define-partial-reffer ,(symbolicate "DATA-VECTOR-REF/" type) ,type - ,size ,signed vector-data-offset other-pointer-lowtag ,scs - ,element-type data-vector-ref) - (define-partial-setter ,(symbolicate "DATA-VECTOR-SET/" type) ,type - ,size vector-data-offset other-pointer-lowtag ,scs - ,element-type data-vector-set)))) + `(progn + (define-partial-reffer ,(symbolicate "DATA-VECTOR-REF/" type) ,type + ,size ,signed vector-data-offset other-pointer-lowtag ,scs + ,element-type data-vector-ref) + (define-partial-setter ,(symbolicate "DATA-VECTOR-SET/" type) ,type + ,size vector-data-offset other-pointer-lowtag ,scs + ,element-type data-vector-set)))) - (def-full-data-vector-frobs simple-vector * - descriptor-reg any-reg null zero) + ;; SIMPLE-VECTOR + (define-full-reffer data-vector-ref/simple-vector simple-vector + vector-data-offset other-pointer-lowtag (descriptor-reg any-reg) * data-vector-ref) + (define-vop (data-vector-set/simple-vector) + (:translate data-vector-set) + (:policy :fast-safe) + (:args (object :scs (descriptor-reg)) (index :scs (any-reg)) + (value :scs (descriptor-reg any-reg null zero))) + (:arg-types simple-vector tagged-num *) + (:temporary (:scs (non-descriptor-reg)) ea temp) + (:vop-var vop) + (:generator 6 + ;; We could potentially eliminate the ADDIU by ensuring that a simple-vector + ;; never starts 2 words before the end of a card. + ;; However, that's tricky to reason about and I don't care to do it. + ;; (and also it's maybe not correct for card-spanning vectors) + (inst addu ea object index) + (inst addu ea ea (- (ash vector-data-offset word-shift) other-pointer-lowtag)) + (without-scheduling () + (emit-gc-store-barrier object ea temp (vop-nth-arg 2 vop) value) + (storew value ea 0 0)))) + (define-vop (data-vector-set/simple-vector-c) + (:translate data-vector-set) + (:policy :fast-safe) + (:args (object :scs (descriptor-reg)) (value :scs (descriptor-reg any-reg null zero))) + (:temporary (:scs (non-descriptor-reg)) ea temp) + (:info index) + ;; not sure if the load/store-index is off by something now + (:arg-types simple-vector (:constant (load/store-index 4 7 2)) *) + (:vop-var vop) + (:generator 5 + (inst addu ea object (- (ash (+ vector-data-offset index) word-shift) other-pointer-lowtag)) + (without-scheduling () + (emit-gc-store-barrier object ea temp (vop-nth-arg 1 vop) value) + (storew value object (+ vector-data-offset index) other-pointer-lowtag)))) (def-partial-data-vector-frobs simple-base-string character :byte nil character-reg) @@ -201,10 +236,8 @@ (:policy :fast-safe) (:args (object :scs (descriptor-reg)) (index :scs (unsigned-reg) :target shift) - (value :scs (unsigned-reg zero immediate) :target result)) + (value :scs (unsigned-reg zero immediate))) (:arg-types ,type positive-fixnum positive-fixnum) - (:results (result :scs (unsigned-reg))) - (:result-types positive-fixnum) (:temporary (:scs (interior-reg)) lip) (:temporary (:scs (non-descriptor-reg)) temp old) (:temporary (:scs (non-descriptor-reg) :from (:argument 1)) shift) @@ -236,19 +269,12 @@ (inst or old temp)) (inst sw old lip (- (* vector-data-offset n-word-bytes) - other-pointer-lowtag)) - (sc-case value - (immediate - (inst li result (tn-value value))) - (zero - (move result zero-tn)) - (unsigned-reg - (move result value))))) + other-pointer-lowtag)))) (define-vop (,(symbolicate "DATA-VECTOR-SET-C/" type)) (:translate data-vector-set) (:policy :fast-safe) (:args (object :scs (descriptor-reg)) - (value :scs (unsigned-reg zero immediate) :target result)) + (value :scs (unsigned-reg zero immediate))) (:arg-types ,type (:constant (integer 0 @@ -259,8 +285,6 @@ elements-per-word)))) positive-fixnum) (:info index) - (:results (result :scs (unsigned-reg))) - (:result-types positive-fixnum) (:temporary (:scs (non-descriptor-reg)) temp old) (:generator 20 (multiple-value-bind (word extra) (floor index ,elements-per-word) @@ -293,14 +317,7 @@ (inst or old temp))) (inst sw old object (- (* (+ word vector-data-offset) n-word-bytes) - other-pointer-lowtag)) - (sc-case value - (immediate - (inst li result (tn-value value))) - (zero - (move result zero-tn)) - (unsigned-reg - (move result value)))))))))) + other-pointer-lowtag))))))))) (def-small-data-vector-frobs simple-bit-vector 1) (def-small-data-vector-frobs simple-array-unsigned-byte-2 2) (def-small-data-vector-frobs simple-array-unsigned-byte-4 4)) @@ -329,18 +346,14 @@ (:policy :fast-safe) (:args (object :scs (descriptor-reg)) (index :scs (any-reg)) - (value :scs (single-reg) :target result)) + (value :scs (single-reg))) (:arg-types simple-array-single-float positive-fixnum single-float) - (:results (result :scs (single-reg))) - (:result-types single-float) (:temporary (:scs (interior-reg)) lip) (:generator 20 (inst addu lip object index) (inst swc1 value lip (- (* vector-data-offset n-word-bytes) - other-pointer-lowtag)) - (unless (location= result value) - (inst fmove :single result value)))) + other-pointer-lowtag)))) (define-vop (data-vector-ref/simple-array-double-float) (:note "inline array access") @@ -380,10 +393,8 @@ (:policy :fast-safe) (:args (object :scs (descriptor-reg)) (index :scs (any-reg)) - (value :scs (double-reg) :target result)) + (value :scs (double-reg))) (:arg-types simple-array-double-float positive-fixnum double-float) - (:results (result :scs (double-reg))) - (:result-types double-float) (:temporary (:scs (interior-reg)) lip) (:generator 20 (inst addu lip object index) @@ -404,9 +415,7 @@ (inst swc1-odd value lip (+ (- (* vector-data-offset n-word-bytes) other-pointer-lowtag) - n-word-bytes)))) - (unless (location= result value) - (inst fmove :double result value)))) + n-word-bytes)))))) ;;; Complex float arrays. (define-vop (data-vector-ref/simple-array-complex-single-float) @@ -436,27 +445,19 @@ (:policy :fast-safe) (:args (object :scs (descriptor-reg)) (index :scs (any-reg)) - (value :scs (complex-single-reg) :target result)) + (value :scs (complex-single-reg))) (:arg-types simple-array-complex-single-float positive-fixnum complex-single-float) - (:results (result :scs (complex-single-reg))) - (:result-types complex-single-float) (:temporary (:scs (interior-reg)) lip) (:generator 5 (inst addu lip object index) (inst addu lip index) - (let ((value-real (complex-single-reg-real-tn value)) - (result-real (complex-single-reg-real-tn result))) + (let ((value-real (complex-single-reg-real-tn value))) (inst swc1 value-real lip (- (* vector-data-offset n-word-bytes) - other-pointer-lowtag)) - (unless (location= result-real value-real) - (inst fmove :single result-real value-real))) - (let ((value-imag (complex-single-reg-imag-tn value)) - (result-imag (complex-single-reg-imag-tn result))) + other-pointer-lowtag))) + (let ((value-imag (complex-single-reg-imag-tn value))) (inst swc1 value-imag lip (- (* (1+ vector-data-offset) n-word-bytes) - other-pointer-lowtag)) - (unless (location= result-imag value-imag) - (inst fmove :single result-imag value-imag))))) + other-pointer-lowtag))))) (define-vop (data-vector-ref/simple-array-complex-double-float) (:note "inline array access") @@ -486,28 +487,20 @@ (:policy :fast-safe) (:args (object :scs (descriptor-reg)) (index :scs (any-reg) :target shift) - (value :scs (complex-double-reg) :target result)) + (value :scs (complex-double-reg))) (:arg-types simple-array-complex-double-float positive-fixnum complex-double-float) - (:results (result :scs (complex-double-reg))) - (:result-types complex-double-float) (:temporary (:scs (interior-reg)) lip) (:temporary (:scs (any-reg) :from (:argument 1)) shift) (:generator 6 (inst sll shift index n-fixnum-tag-bits) (inst addu lip object shift) - (let ((value-real (complex-double-reg-real-tn value)) - (result-real (complex-double-reg-real-tn result))) + (let ((value-real (complex-double-reg-real-tn value))) (str-double value-real lip (- (* vector-data-offset n-word-bytes) - other-pointer-lowtag)) - (unless (location= result-real value-real) - (inst fmove :double result-real value-real))) - (let ((value-imag (complex-double-reg-imag-tn value)) - (result-imag (complex-double-reg-imag-tn result))) + other-pointer-lowtag))) + (let ((value-imag (complex-double-reg-imag-tn value))) (str-double value-imag lip (- (* (+ vector-data-offset 2) n-word-bytes) - other-pointer-lowtag)) - (unless (location= result-imag value-imag) - (inst fmove :double result-imag value-imag))))) + other-pointer-lowtag))))) ;;; These vops are useful for accessing the bits of a vector irrespective of diff --git a/src/compiler/mips/c-call.lisp b/src/compiler/mips/c-call.lisp index e001a7b62c..011d939667 100644 --- a/src/compiler/mips/c-call.lisp +++ b/src/compiler/mips/c-call.lisp @@ -131,8 +131,8 @@ (make-result-state)))))) (deftransform %alien-funcall ((function type &rest args)) - (aver (sb-c::constant-lvar-p type)) - (let* ((type (sb-c::lvar-value type)) + (aver (sb-c:constant-lvar-p type)) + (let* ((type (sb-c:lvar-value type)) (env (make-null-lexenv)) (arg-types (alien-fun-type-arg-types type)) (result-type (alien-fun-type-result-type type))) @@ -231,10 +231,9 @@ (:info foreign-symbol) (:results (res :scs (sap-reg))) (:result-types system-area-pointer) - (:temporary (:scs (non-descriptor-reg)) addr) (:generator 2 - (inst li addr (make-fixup foreign-symbol :foreign-dataref)) - (loadw res addr))) + (inst li res (make-fixup foreign-symbol :foreign-dataref)) + (loadw res res))) (define-vop (call-out) (:args (function :scs (sap-reg) :target cfunc) @@ -251,8 +250,8 @@ (let ((cur-nfp (current-nfp-tn vop))) (when cur-nfp (store-stack-tn nfp-save cur-nfp)) - ;; (linkage-table-entry-address 0) is "call-into-c" in mips-assem.S - (inst lw tramp null-tn (- (linkage-table-entry-address 0) nil-value)) + ;; (alien-linkage-table-entry-address 0) is "call-into-c" in mips-assem.S + (inst lw tramp null-tn (- (alien-linkage-table-entry-address 0) nil-value)) (inst nop) (inst jal tramp) (inst move cfunc function) @@ -362,8 +361,9 @@ and a pointer to the arguments." (incf words-processed) (incf offset n-word-bytes)) (when gprs - (loop repeat words + (loop for gpr = (pop gprs) + repeat words when gpr do (inst sw gpr nsp-tn offset) do diff --git a/src/compiler/mips/call.lisp b/src/compiler/mips/call.lisp index 17bed97698..dec230d2b8 100644 --- a/src/compiler/mips/call.lisp +++ b/src/compiler/mips/call.lisp @@ -39,7 +39,7 @@ ;;; them at a known location. (defun make-old-fp-save-location (env) (specify-save-tn - (physenv-debug-live-tn (make-normal-tn *fixnum-primitive-type*) env) + (environment-debug-live-tn (make-normal-tn *fixnum-primitive-type*) env) (make-wired-tn *fixnum-primitive-type* control-stack-arg-scn ocfp-save-offset))) @@ -47,7 +47,7 @@ (defun make-return-pc-save-location (env) (let ((ptype *backend-t-primitive-type*)) (specify-save-tn - (physenv-debug-live-tn (make-normal-tn ptype) env) + (environment-debug-live-tn (make-normal-tn ptype) env) (make-wired-tn ptype control-stack-arg-scn lra-save-offset)))) ;;; Make a TN for the standard argument count passing location. We only @@ -148,7 +148,7 @@ (move res csp-tn) (inst addu csp-tn csp-tn (* n-word-bytes (sb-allocated-size 'control-stack))) - (when (ir2-physenv-number-stack-p callee) + (when (ir2-environment-number-stack-p callee) (inst addu nsp-tn nsp-tn (- (bytes-needed-for-non-descriptor-stack-frame))) (move nfp nsp-tn)))) @@ -374,8 +374,7 @@ default-value-8 values-start) (:temporary (:sc any-reg :offset nargs-offset :from :eval :to (:result 1)) - nvals) - (:temporary (:scs (non-descriptor-reg)) temp)) + nvals)) ;;; This hook in the codegen pass lets us insert code before fall-thru entry @@ -1127,6 +1126,23 @@ default-value-8 (:generator 4 (loadw value context index))) +(define-vop (more-arg-or-nil) + (:policy :fast-safe) + (:args (object :scs (descriptor-reg) :to (:result 1)) + (count :scs (any-reg) :to (:result 1))) + (:temporary (:scs (any-reg)) temp) + (:info index) + (:results (value :scs (descriptor-reg any-reg))) + (:result-types *) + (:generator 3 + (cond ((zerop index) + (inst beq count done)) + (t + (inst subu temp (fixnumize index) count) + (inst bgez temp done))) + (move value null-tn) + (loadw value object index) + done)) ;;; Turn more arg (context, count) into a list. (define-vop () @@ -1136,7 +1152,7 @@ default-value-8 (:temporary (:scs (any-reg) :from (:argument 0)) context) (:temporary (:scs (any-reg) :from (:argument 1)) count) (:temporary (:scs (descriptor-reg) :from :eval) temp dst) - (:temporary (:sc non-descriptor-reg :offset nl4-offset) pa-flag) + (:temporary (:sc non-descriptor-reg) pa-flag) (:results (result :scs (descriptor-reg))) (:translate %listify-rest-args) (:policy :safe) @@ -1145,8 +1161,8 @@ default-value-8 (let* ((enter (gen-label)) (loop (gen-label)) (done (gen-label)) - (dx-p (node-stack-allocate-p node)) - (alloc-area-tn (if dx-p csp-tn alloc-tn))) + (leave-pa (gen-label)) + (dx-p (node-stack-allocate-p node))) (move context context-arg) (move count count-arg) ;; Check to see if there are any arguments. @@ -1154,17 +1170,39 @@ default-value-8 (inst move result null-tn) ;; We need to do this atomically. - (pseudo-atomic (pa-flag) - (when dx-p - (align-csp temp)) - ;; Allocate a cons (2 words) for each item. - (inst srl result alloc-area-tn n-lowtag-bits) - (inst sll result n-lowtag-bits) - (inst or result list-pointer-lowtag) + (pseudo-atomic (pa-flag :elide-if dx-p) + (inst sll count 1) + (cond (dx-p + (allocation 'list count result list-pointer-lowtag `(,pa-flag ,temp) + :stackp t)) + (t + (let ((end-addr pa-flag) + (new-freeptr temp) + (continue (gen-label))) + (without-scheduling () + (inst lw result null-tn (- cons-region nil-value)) + (inst lw end-addr null-tn (+ 4 (- cons-region nil-value))) + (inst add new-freeptr result count) + ;; Use a different 'code' field for listify. Technically there are enough + ;; bits in the code field to indicate how many bytes to skip to branch out + ;; of the entire loop, which the C handler could use to adjust the RA. + ;; But the assembler doesn't provide a way to compute that distance. + (inst tltu end-addr new-freeptr (logior #x300 (reg-tn-encoding result))) + ;; Jump to the freeptr writeback + (inst beq zero-tn continue) + ;; Encode CONTEXT into a dummy instruction + (inst addu zero-tn context context) ; ADDU never signals overflow + ;; If we return here, then skip the loop + (inst beq zero-tn leave-pa) + (inst nop) + (emit-label continue) + (inst sw new-freeptr null-tn (- cons-region nil-value)) + (inst or result list-pointer-lowtag))))) + (move dst result) - (inst sll temp count 1) + (inst b enter) - (inst addu alloc-area-tn temp) + (inst srl count 1) ;; Store the current cons in the cdr of the previous cons. (emit-label loop) @@ -1184,7 +1222,8 @@ default-value-8 (storew temp dst 0 list-pointer-lowtag) ;; NIL out the last cons. - (storew null-tn dst 1 list-pointer-lowtag)) + (storew null-tn dst 1 list-pointer-lowtag) + (emit-label leave-pa)) (emit-label done)))) ;;; Return the location and size of the more arg glob created by Copy-More-Arg. @@ -1220,30 +1259,36 @@ default-value-8 (:vop-var vop) (:save-p :compute-only) (:generator 3 - (let ((err-lab - (generate-error-code vop 'invalid-arg-count-error nargs))) - (cond ((not min) - (cond ((zerop max) - (inst bne nargs err-lab)) - (t - (inst li temp (fixnumize max)) - (inst bne nargs temp err-lab))) - (inst nop)) - (max - (when (plusp min) - (inst li temp (fixnumize min)) - (inst sltu temp nargs temp) - (inst bne temp err-lab) - (inst nop)) - (inst li temp (fixnumize max)) - (inst sltu temp temp nargs) - (inst bne temp err-lab) - (inst nop)) - ((plusp min) - (inst li temp (fixnumize min)) - (inst sltu temp nargs temp) - (inst bne temp err-lab) - (inst nop)))))) + (cond + ((not min) ; fixed args + (unless (zerop max) (inst li temp (fixnumize max))) + (note-this-location vop :internal-error) + (inst tne nargs (if (zerop max) zero-tn temp) invalid-arg-count-trap)) + (t + (let ((err-lab + (generate-error-code vop 'invalid-arg-count-error nargs))) + (cond ((not min) + (cond ((zerop max) + (inst bne nargs err-lab)) + (t + (inst li temp (fixnumize max)) + (inst bne nargs temp err-lab))) + (inst nop)) + (max + (when (plusp min) + (inst li temp (fixnumize min)) + (inst sltu temp nargs temp) + (inst bne temp err-lab) + (inst nop)) + (inst li temp (fixnumize max)) + (inst sltu temp temp nargs) + (inst bne temp err-lab) + (inst nop)) + ((plusp min) + (inst li temp (fixnumize min)) + (inst sltu temp nargs temp) + (inst bne temp err-lab) + (inst nop)))))))) ;;; Single-stepping diff --git a/src/compiler/mips/cell.lisp b/src/compiler/mips/cell.lisp index c54e5812b6..16b8feb4a6 100644 --- a/src/compiler/mips/cell.lisp +++ b/src/compiler/mips/cell.lisp @@ -27,13 +27,12 @@ (value :scs (descriptor-reg any-reg null zero))) (:info name offset lowtag) (:ignore name) - (:results) + (:temporary (:sc non-descriptor-reg) temp) + (:vop-var vop) (:generator 1 - (storew value object offset lowtag))) - -(define-vop (init-slot set-slot) - (:info name dx-p offset lowtag) - (:ignore name dx-p)) + (without-scheduling () + (emit-gc-store-barrier object nil temp (vop-nth-arg 1 vop) value) + (storew value object offset lowtag)))) ;;;; Symbol hacking VOPs: @@ -53,11 +52,10 @@ (:temporary (:scs (non-descriptor-reg)) temp) (:temporary (:scs (descriptor-reg) :from (:argument 0)) obj-temp)) -;;; With Symbol-Value, we check that the value isn't the trap object. So -;;; Symbol-Value of NIL is NIL. +;;; With Symbol-Value, we check that the value isn't the trap object. ;;; (define-vop (symbol-value checked-cell-ref) - (:translate symeval) + (:translate symbol-value) (:generator 9 (move obj-temp object) (loadw value obj-temp symbol-value-slot other-pointer-lowtag) @@ -67,19 +65,17 @@ (inst nop)))) ;;; Like CHECKED-CELL-REF, only we are a predicate to see if the cell is bound. -(define-vop (boundp-frob) +(define-vop (boundp) (:args (object :scs (descriptor-reg))) (:conditional) (:info target not-p) (:policy :fast-safe) - (:temporary (:scs (descriptor-reg)) value) - (:temporary (:scs (non-descriptor-reg)) temp)) - -(define-vop (boundp boundp-frob) + (:temporary (:scs (non-descriptor-reg)) temp) (:translate boundp) (:generator 9 - (loadw value object symbol-value-slot other-pointer-lowtag) - (inst xor temp value unbound-marker-widetag) + (inst lb temp object (+ (- (ash symbol-value-slot word-shift) other-pointer-lowtag) + #+big-endian 3)) + (inst xor temp temp unbound-marker-widetag) (if not-p (inst beq temp target) (inst bne temp target)) @@ -88,7 +84,7 @@ (define-vop (fast-symbol-value cell-ref) (:variant symbol-value-slot other-pointer-lowtag) (:policy :fast) - (:translate symeval)) + (:translate symbol-value)) (define-vop (symbol-hash) (:policy :fast-safe) @@ -109,9 +105,9 @@ ;;; On unithreaded builds these are just copies of the non-global versions. (define-vop (%set-symbol-global-value set)) (define-vop (symbol-global-value symbol-value) - (:translate sym-global-val)) + (:translate symbol-global-value)) (define-vop (fast-symbol-global-value fast-symbol-value) - (:translate sym-global-val)) + (:translate symbol-global-value)) ;;;; Fdefinition (fdefn) objects. @@ -142,8 +138,9 @@ (:temporary (:scs (non-descriptor-reg)) type) (:results (result :scs (descriptor-reg))) (:generator 38 + (without-scheduling () + (emit-gc-store-barrier fdefn nil type)) ; type = temp (load-type type function (- fun-pointer-lowtag)) - (inst nop) (inst xor type simple-fun-widetag) (inst beq type normal-fn) (inst addu lip function @@ -167,15 +164,12 @@ (define-vop (fdefn-makunbound) (:policy :fast-safe) (:translate fdefn-makunbound) - (:args (fdefn :scs (descriptor-reg) :target result)) + (:args (fdefn :scs (descriptor-reg))) (:temporary (:scs (non-descriptor-reg)) temp) - (:results (result :scs (descriptor-reg))) (:generator 38 (storew null-tn fdefn fdefn-fun-slot other-pointer-lowtag) (inst li temp (make-fixup 'undefined-tramp :assembly-routine)) - (storew temp fdefn fdefn-raw-addr-slot other-pointer-lowtag) - (move result fdefn))) - + (storew temp fdefn fdefn-raw-addr-slot other-pointer-lowtag))) ;;;; Binding and Unbinding. @@ -189,20 +183,25 @@ (:args (val :scs (any-reg descriptor-reg)) (symbol :scs (descriptor-reg))) (:temporary (:scs (descriptor-reg)) temp) + (:temporary (:scs (non-descriptor-reg)) temp2) (:generator 5 (loadw temp symbol symbol-value-slot other-pointer-lowtag) (inst addu bsp-tn bsp-tn (* 2 n-word-bytes)) (storew temp bsp-tn (- binding-value-slot binding-size)) (storew symbol bsp-tn (- binding-symbol-slot binding-size)) - (storew val symbol symbol-value-slot other-pointer-lowtag))) - + (without-scheduling () + (emit-gc-store-barrier symbol nil temp2) + (storew val symbol symbol-value-slot other-pointer-lowtag)))) (define-vop (unbind) (:temporary (:scs (descriptor-reg)) symbol value) + (:temporary (:scs (non-descriptor-reg)) temp) (:generator 0 (loadw symbol bsp-tn (- binding-symbol-slot binding-size)) (loadw value bsp-tn (- binding-value-slot binding-size)) - (storew value symbol symbol-value-slot other-pointer-lowtag) + (without-scheduling () + (emit-gc-store-barrier symbol nil temp) + (storew value symbol symbol-value-slot other-pointer-lowtag)) (storew zero-tn bsp-tn (- binding-symbol-slot binding-size)) (storew zero-tn bsp-tn (- binding-value-slot binding-size)) (inst addu bsp-tn bsp-tn (* -2 n-word-bytes)))) @@ -212,6 +211,7 @@ (:args (arg :scs (descriptor-reg any-reg) :target where)) (:temporary (:scs (any-reg) :from (:argument 0)) where) (:temporary (:scs (descriptor-reg)) symbol value) + (:temporary (:scs (non-descriptor-reg)) temp) (:generator 0 (let ((loop (gen-label)) (skip (gen-label)) @@ -224,7 +224,9 @@ (loadw symbol bsp-tn (- binding-symbol-slot binding-size)) (inst beq symbol skip) (loadw value bsp-tn (- binding-value-slot binding-size)) - (storew value symbol symbol-value-slot other-pointer-lowtag) + (without-scheduling () + (emit-gc-store-barrier symbol nil temp) + (storew value symbol symbol-value-slot other-pointer-lowtag)) (storew zero-tn bsp-tn (- binding-symbol-slot binding-size)) (emit-label skip) @@ -243,9 +245,9 @@ closure-info-offset fun-pointer-lowtag (descriptor-reg any-reg) * %closure-index-ref) -(define-full-setter set-funcallable-instance-info * - funcallable-instance-info-offset fun-pointer-lowtag - (descriptor-reg any-reg null zero) * %set-funcallable-instance-info) +(define-full-setter %closure-index-set * + closure-info-offset fun-pointer-lowtag + (descriptor-reg any-reg null zero) * %closure-index-set) (define-full-reffer funcallable-instance-info * funcallable-instance-info-offset fun-pointer-lowtag @@ -262,8 +264,11 @@ (:args (object :scs (descriptor-reg)) (value :scs (descriptor-reg any-reg))) (:info offset) + (:temporary (:scs (non-descriptor-reg)) temp) (:generator 4 - (storew value object (+ closure-info-offset offset) fun-pointer-lowtag))) + (without-scheduling () + (emit-gc-store-barrier object nil temp) + (storew value object (+ closure-info-offset offset) fun-pointer-lowtag)))) (define-vop (closure-init-from-fp) (:args (object :scs (descriptor-reg))) @@ -306,16 +311,46 @@ (define-full-reffer code-header-ref * 0 other-pointer-lowtag (descriptor-reg any-reg) * code-header-ref) -(define-full-setter code-header-set * 0 other-pointer-lowtag - (descriptor-reg any-reg null zero) * code-header-set) - - +(define-vop (code-header-set) + (:translate code-header-set) + (:policy :fast-safe) + (:args (object :scs (descriptor-reg)) + (index :scs (any-reg)) + (value :scs (any-reg descriptor-reg))) + (:arg-types * tagged-num *) + (:temporary (:scs (non-descriptor-reg)) temp card) + (:temporary (:sc non-descriptor-reg) pa-flag) + (:generator 10 + (inst li temp (make-fixup "gc_card_table_mask" :foreign-dataref)) + (loadw temp temp) ; address of gc_card_table_mask + (inst lw temp temp 0) ; value of gc_card_table_mask (4-byte int) + (pseudo-atomic (pa-flag) + ;; Compute card mark index + (inst srl card object gencgc-card-shift) + (inst and card card temp) + ;; Load mark table base + (inst li temp (make-fixup "gc_card_mark" :foreign-dataref)) ; address of linkage entry + (loadw temp temp) ; address of gc_card_mark + (loadw temp temp) ; value of gc_card_mark (pointer) + ;; Touch the card mark byte. + (inst add temp temp card) + (inst sb null-tn temp 0) + ;; set 'written' flag in the code header + ;; If two threads get here at the same time, they'll write the same byte. + (let ((byte (- #+little-endian 3 other-pointer-lowtag))) + (inst lbu temp object byte) + (inst or temp temp #x40) + (inst sb temp object byte)) + ;; No need for LIP register because this is pseudo-atomic + (inst sll temp index (- word-shift n-fixnum-tag-bits)) + (inst add temp object temp) + (inst sw value temp (- other-pointer-lowtag))))) ;;;; raw instance slot accessors (macrolet ((def (suffix sc primtype) `(progn - (define-vop (,(symbolicate "RAW-INSTANCE-REF/" suffix)) + (define-vop () (:translate ,(symbolicate "%RAW-INSTANCE-REF/" suffix)) (:policy :fast-safe) (:args (object :scs (descriptor-reg)) @@ -328,24 +363,21 @@ (inst addu lip object index) (loadw value lip instance-slots-offset instance-pointer-lowtag))) - (define-vop (,(symbolicate "RAW-INSTANCE-SET/" suffix)) + (define-vop () (:translate ,(symbolicate "%RAW-INSTANCE-SET/" suffix)) (:policy :fast-safe) (:args (object :scs (descriptor-reg)) (index :scs (any-reg)) - (value :scs (,sc) :target result)) + (value :scs (,sc))) (:arg-types * positive-fixnum ,primtype) - (:results (result :scs (,sc))) (:temporary (:scs (interior-reg)) lip) - (:result-types ,primtype) (:generator 5 (inst addu lip object index) - (storew value lip instance-slots-offset instance-pointer-lowtag) - (move result value)))))) + (storew value lip instance-slots-offset instance-pointer-lowtag)))))) (def word unsigned-reg unsigned-num) (def signed-word signed-reg signed-num)) -(define-vop (raw-instance-ref/single) +(define-vop () (:translate %raw-instance-ref/single) (:policy :fast-safe) (:args (object :scs (descriptor-reg)) @@ -359,24 +391,20 @@ (inst lwc1 value lip (- (* instance-slots-offset n-word-bytes) instance-pointer-lowtag)))) -(define-vop (raw-instance-set/single) +(define-vop () (:translate %raw-instance-set/single) (:policy :fast-safe) (:args (object :scs (descriptor-reg)) (index :scs (any-reg)) - (value :scs (single-reg) :target result)) + (value :scs (single-reg))) (:arg-types * positive-fixnum single-float) - (:results (result :scs (single-reg))) (:temporary (:scs (interior-reg)) lip) - (:result-types single-float) (:generator 5 (inst addu lip object index) (inst swc1 value lip (- (* instance-slots-offset n-word-bytes) - instance-pointer-lowtag)) - (unless (location= result value) - (inst fmove :single result value)))) + instance-pointer-lowtag)))) -(define-vop (raw-instance-ref/double) +(define-vop () (:translate %raw-instance-ref/double) (:policy :fast-safe) (:args (object :scs (descriptor-reg)) @@ -398,16 +426,14 @@ (:big-endian (inst lwc1 value lip immediate-offset)) (:little-endian (inst lwc1-odd value lip immediate-offset)))))) -(define-vop (raw-instance-set/double) +(define-vop () (:translate %raw-instance-set/double) (:policy :fast-safe) (:args (object :scs (descriptor-reg)) (index :scs (any-reg)) - (value :scs (double-reg) :target result)) + (value :scs (double-reg))) (:arg-types * positive-fixnum double-float) - (:results (result :scs (double-reg))) (:temporary (:scs (interior-reg)) lip) - (:result-types double-float) (:generator 5 (inst addu lip object index) (let ((immediate-offset (- (* instance-slots-offset n-word-bytes) @@ -419,11 +445,9 @@ instance-pointer-lowtag))) (ecase *backend-byte-order* (:big-endian (inst swc1 value lip immediate-offset)) - (:little-endian (inst swc1-odd value lip immediate-offset)))) - (unless (location= result value) - (inst fmove :double result value)))) + (:little-endian (inst swc1-odd value lip immediate-offset)))))) -(define-vop (raw-instance-ref/complex-single) +(define-vop () (:translate %raw-instance-ref/complex-single) (:policy :fast-safe) (:args (object :scs (descriptor-reg)) @@ -445,36 +469,23 @@ (- (* (1+ instance-slots-offset) n-word-bytes) instance-pointer-lowtag)))) -(define-vop (raw-instance-set/complex-single) +(define-vop () (:translate %raw-instance-set/complex-single) (:policy :fast-safe) (:args (object :scs (descriptor-reg)) (index :scs (any-reg)) - (value :scs (complex-single-reg) :target result)) + (value :scs (complex-single-reg))) (:arg-types * positive-fixnum complex-single-float) - (:results (result :scs (complex-single-reg))) (:temporary (:scs (interior-reg)) lip) - (:result-types complex-single-float) (:generator 5 (inst addu lip object index) - (let ((value-real (complex-single-reg-real-tn value)) - (result-real (complex-single-reg-real-tn result))) - (inst swc1 - value-real - lip - (- (* instance-slots-offset n-word-bytes) - instance-pointer-lowtag)) - (unless (location= result-real value-real) - (inst fmove :single result-real value-real))) - (let ((value-imag (complex-single-reg-imag-tn value)) - (result-imag (complex-single-reg-imag-tn result))) - (inst swc1 - value-imag - lip - (- (* (1+ instance-slots-offset) n-word-bytes) - instance-pointer-lowtag)) - (unless (location= result-imag value-imag) - (inst fmove :single result-imag value-imag))))) + (inst swc1 (complex-single-reg-real-tn value) + lip (- (* instance-slots-offset n-word-bytes) + instance-pointer-lowtag)) + (inst swc1 + (complex-single-reg-imag-tn value) + lip (- (* (1+ instance-slots-offset) n-word-bytes) + instance-pointer-lowtag)))) (define-vop (raw-instance-ref/complex-double) (:translate %raw-instance-ref/complex-double) @@ -532,20 +543,17 @@ lip immediate-offset)))))) -(define-vop (raw-instance-set/complex-double) +(define-vop () (:translate %raw-instance-set/complex-double) (:policy :fast-safe) (:args (object :scs (descriptor-reg)) (index :scs (any-reg)) - (value :scs (complex-double-reg) :target result)) + (value :scs (complex-double-reg))) (:arg-types * positive-fixnum complex-double-float) - (:results (result :scs (complex-double-reg))) (:temporary (:scs (interior-reg)) lip) - (:result-types complex-double-float) (:generator 5 (inst addu lip object index) - (let ((value-real (complex-double-reg-real-tn value)) - (result-real (complex-double-reg-real-tn result))) + (let ((value-real (complex-double-reg-real-tn value))) (let ((immediate-offset (- (* instance-slots-offset n-word-bytes) instance-pointer-lowtag))) (ecase *backend-byte-order* @@ -567,11 +575,8 @@ (:little-endian (inst swc1-odd value-real lip - immediate-offset)))) - (unless (location= result-real value-real) - (inst fmove :double result-real value-real))) - (let ((value-imag (complex-double-reg-imag-tn value)) - (result-imag (complex-double-reg-imag-tn result))) + immediate-offset))))) + (let ((value-imag (complex-double-reg-imag-tn value))) (let ((immediate-offset (- (* (+ instance-slots-offset 2) n-word-bytes) instance-pointer-lowtag))) (ecase *backend-byte-order* @@ -593,6 +598,4 @@ (:little-endian (inst swc1-odd value-imag lip - immediate-offset)))) - (unless (location= result-imag value-imag) - (inst fmove :double result-imag value-imag))))) + immediate-offset))))))) diff --git a/src/compiler/mips/debug.lisp b/src/compiler/mips/debug.lisp index b73dbc640c..88e3542525 100644 --- a/src/compiler/mips/debug.lisp +++ b/src/compiler/mips/debug.lisp @@ -12,16 +12,16 @@ (in-package "SB-VM") -(define-vop (debug-cur-sp) - (:translate sb-di::current-sp) +(define-vop () + (:translate current-sp) (:policy :fast-safe) (:results (res :scs (sap-reg))) (:result-types system-area-pointer) (:generator 1 (move res csp-tn))) -(define-vop (debug-cur-fp) - (:translate sb-di::current-fp) +(define-vop (current-fp-sap) + (:translate current-fp) (:policy :fast-safe) (:results (res :scs (sap-reg))) (:result-types system-area-pointer) @@ -47,15 +47,12 @@ (:policy :fast-safe) (:args (object :scs (sap-reg) :target sap) (offset :scs (any-reg)) - (value :scs (descriptor-reg) :target result)) + (value :scs (descriptor-reg))) (:arg-types system-area-pointer positive-fixnum *) - (:results (result :scs (descriptor-reg))) - (:result-types *) (:temporary (:scs (sap-reg) :from (:argument 1)) sap) (:generator 2 (inst addu sap object offset) - (inst sw value sap 0) - (move result value))) + (inst sw value sap 0))) (define-vop (code-from-mumble) (:policy :fast-safe) diff --git a/src/compiler/mips/insts.lisp b/src/compiler/mips/insts.lisp index ff33948975..fc2a659978 100644 --- a/src/compiler/mips/insts.lisp +++ b/src/compiler/mips/insts.lisp @@ -19,6 +19,8 @@ sb-vm::immediate-constant sb-vm::registers sb-vm::float-registers sb-vm::zero + sb-vm::null-offset + sb-vm::zero-offset sb-vm::lip-tn sb-vm::zero-tn))) ;;;; Constants, types, conversion functions, some disassembler stuff. @@ -26,8 +28,8 @@ (defun reg-tn-encoding (tn) (declare (type tn tn)) (sc-case tn - (zero sb-vm::zero-offset) - (null sb-vm::null-offset) + (zero zero-offset) + (null null-offset) (t (if (eq (sb-name (sc-sb (tn-sc tn))) 'registers) (tn-offset tn) @@ -95,9 +97,9 @@ (note-code-constant offset dstate)))))) (defparameter *float-reg-symbols* - (coerce - (loop for n from 0 to 31 collect (make-symbol (format nil "$F~d" n))) - 'vector)) + #.(coerce + (loop for n from 0 to 31 collect (make-symbol (format nil "$F~d" n))) + 'vector)) (define-arg-type fp-reg :printer #'(lambda (value stream dstate) @@ -144,7 +146,7 @@ '(:f :un :eq :ueq :olt :ult :ole :ule :sf :ngle :seq :ngl :lt :nge :le :ngt) #'equalp) -(defconstant-eqx compare-kinds-vec #.(apply #'vector compare-kinds) +(defconstant-eqx compare-kinds-vec (apply #'vector compare-kinds) #'equalp) (deftype compare-kind () @@ -223,19 +225,9 @@ (load-store-annotation :fields (list (byte 5 21) (byte 16 0)) :type 'load-store-annotation)) -(eval-when (:compile-toplevel :load-toplevel :execute) - (defparameter jump-printer - #'(lambda (value stream dstate) - (let ((addr (ash value 2))) - (cond (stream - (maybe-note-assembler-routine addr t dstate) - (write addr :base 16 :radix t :stream stream)) - (t - (operand addr dstate))))))) - (define-instruction-format (jump 32 :default-printer '(:name :tab target)) (op :field (byte 6 26)) - (target :field (byte 26 0) :printer jump-printer)) + (target :field (byte 26 0) :printer #'jump-printer)) (defconstant-eqx reg-printer '(:name :tab rd (:unless (:same-as rd) ", " rs) ", " rt) @@ -257,6 +249,14 @@ (subcode :field (byte 10 6) :reader break-subcode) (funct :field (byte 6 0) :value #b001101)) +(define-instruction-format (trap 32 :default-printer + '(:name :tab rs ", " rt ", " code)) + (op :field (byte 6 26)) + (rs :field (byte 5 21) :type 'reg) + (rt :field (byte 5 16) :type 'reg) + (code :field (byte 10 6)) + (funct :field (byte 6 0))) + (define-instruction-format (coproc-branch 32 :default-printer '(:name :tab offset)) (op :field (byte 6 26)) @@ -532,13 +532,18 @@ (define-instruction sll (segment dst src1 &optional src2) (:declare (type tn dst) - (type (or tn (unsigned-byte 5) null) src1 src2)) + (type (or tn (unsigned-byte 5) null) src1) + ;; use-case for fixup is GC card index calculation (WIP) + (type (or tn (unsigned-byte 5) null fixup) src2)) (:printer register ((op special-op) (rs 0) (shamt nil) (funct #b000000)) shift-printer) (:printer register ((op special-op) (funct #b000100)) shift-printer) (:dependencies (reads src1) (if src2 (reads src2) (reads dst)) (writes dst)) (:delay 0) (:emitter + (when (and (fixup-p src2) (eq (fixup-flavor src2) :gc-barrier)) + (note-fixup segment :sll-sa src2) ; shift amount + (setq src2 0)) (emit-shift-inst segment #b00 dst src1 src2))) (define-instruction sra (segment dst src1 &optional src2) @@ -771,8 +776,7 @@ (define-instruction bgez (segment reg target) (:declare (type label target) (type tn reg)) - (:printer - immediate ((op bcond-op) (rt 1) (immediate nil :type 'relative-label)) + (:printer immediate ((op bcond-op) (rt 1) (immediate nil :type 'relative-label)) cond-branch-printer) (:attributes branch) (:dependencies (reads reg)) @@ -782,8 +786,7 @@ (define-instruction bltzal (segment reg target) (:declare (type label target) (type tn reg)) - (:printer - immediate ((op bcond-op) (rt #b01000) (immediate nil :type 'relative-label)) + (:printer immediate ((op bcond-op) (rt #b10000) (immediate nil :type 'relative-label)) cond-branch-printer) (:attributes branch) (:dependencies (reads reg) (writes lip-tn)) @@ -793,8 +796,7 @@ (define-instruction bgezal (segment reg target) (:declare (type label target) (type tn reg)) - (:printer - immediate ((op bcond-op) (rt #b01001) (immediate nil :type 'relative-label)) + (:printer immediate ((op bcond-op) (rt #b10001) (immediate nil :type 'relative-label)) cond-branch-printer) (:attributes branch) (:delay 1) @@ -1035,41 +1037,6 @@ ;;;; Random system hackery and other noise -(define-instruction-macro entry-point () - nil) - -(defmacro break-cases (breaknum &body cases) - (let ((bn-temp (gensym))) - (collect ((clauses)) - (dolist (case cases) - (clauses `((= ,bn-temp ,(car case)) ,@(cdr case)))) - `(let ((,bn-temp ,breaknum)) - (cond ,@(clauses)))))) - -(defun break-control (chunk inst stream dstate) - (declare (ignore inst)) - (flet ((nt (x) (if stream (note x dstate)))) - (let ((trap (break-subcode chunk dstate))) - (case trap - (#.halt-trap - (nt "Halt trap")) - (#.pending-interrupt-trap - (nt "Pending interrupt trap")) - (#.breakpoint-trap - (nt "Breakpoint trap")) - (#.fun-end-breakpoint-trap - (nt "Function end breakpoint trap")) - (#.after-breakpoint-trap - (nt "After breakpoint trap")) - (#.single-step-around-trap - (nt "Single step around trap")) - (#.single-step-before-trap - (nt "Single step before trap")) - (t - (when (or (and (= trap cerror-trap) (progn (nt "cerror trap") t)) - (>= trap error-trap)) - (handle-break-args #'snarf-error-junk trap stream dstate))))))) - (define-instruction break (segment code &optional (subcode 0)) (:declare (type (unsigned-byte 10) code subcode)) (:printer break ((op special-op) (funct #b001101)) @@ -1081,6 +1048,38 @@ (:emitter (emit-break-inst segment special-op code subcode #b001101))) +(macrolet ((deftrap (name bits) + `(define-instruction ,name (segment rs rt &optional (code 0)) + (:declare (type (unsigned-byte 10) code)) + (:printer trap ((op special-op) (funct ,bits))) + :pinned + (:cost 0) + (:delay 0) + (:emitter + (emit-break-inst segment special-op + (logior (ash (reg-tn-encoding rs) 5) (reg-tn-encoding rt)) + code ,bits)))) + (deftrapi (name bits) + `(define-instruction ,name (segment rs imm) + (:printer immediate ((op #b000001) (rt ,bits))) + :pinned + (:cost 0) + (:delay 0) + (:emitter (emit-immediate-inst segment #b000001 (reg-tn-encoding rs) ,bits imm))))) + (deftrap teq #b110100) + (deftrap tge #b110000) + (deftrap tgeu #b110001) + (deftrap tlt #b110010) + (deftrap tltu #b110011) + (deftrap tne #b110110) + + (deftrapi teqi #b01100) + (deftrapi tgei #b01000) + (deftrapi tgeiu #b01001) + (deftrapi tlti #b01010) + (deftrapi tltiu #b01011) + (deftrapi tnei #b01110)) + (define-instruction syscall (segment) (:printer register ((op special-op) (rd 0) (rt 0) (rs 0) (funct #b001110)) '(:name)) @@ -1247,12 +1246,21 @@ (define-instruction lw (segment reg base &optional (index 0)) (:declare (type tn reg base) - (type (or (signed-byte 16) fixup) index)) + (type (or (signed-byte 16) fixup label) index)) (:printer load-store ((op #b100011))) (:dependencies (reads base) (reads :memory) (writes reg)) (:delay 1) (:emitter - (emit-load/store-inst segment #b100011 base reg index))) + (if (and (label-p index) (eq base sb-vm::code-tn)) + (emit-back-patch segment 4 + (lambda (segment posn) + (declare (ignore posn)) + (emit-load/store-inst segment #b100011 + base reg + (+ (component-header-length) + (label-position index) + (- sb-vm:other-pointer-lowtag))))) + (emit-load/store-inst segment #b100011 base reg index)))) ;; next is just for ease of coding double-in-int c-call convention (define-instruction lw-odd (segment reg base &optional (index 0)) @@ -1377,3 +1385,107 @@ (:emitter (emit-fp-load/store-inst segment #b111001 reg 1 base index))) +;;; This mechanism is more complicated than minimally necessary for it to do its job. +;;; Consequently each backend has its own completely screwy way of canonicalizing +;;; because each one is better than the other. +;;; CONSTANT is just the &REST list passed to REGISTER-INLINE-CONSTANT which acts as +;;; a key in an EQUAL table for collapsing multiple references to the same data +;;; so that we only emit it once (or possibly not even once, if we fuse bytes from +;;; adjacent constants as suggested by comments in codegen. e.g. an 8-byte constant +;;; may contain a naturally-aligned 4-byte constant whose bytes match). +;;; The question is - why doesn't the vop just pass the proper key in the first place? +(defun canonicalize-inline-constant (constant) + constant) + +;;; Again this is too complex in the simplest case- you return an assembler label, +;;; and a cookie to hand to the consumer of the constant, which is {often,always} +;;; redundant, because the consumer knows what shape the value is - float, octaword, etc. +;;; The label alone conveys enough data to access the bits stored, however +;;; in some cases the sorting logic might need a way to determine the storage size. +(defun inline-constant-value (constant) + (declare (ignore constant)) + (let ((label (gen-label))) + (values label label))) + +;;; Trivial "sort" +(defun sort-inline-constants (constants) constants) + +;;; This is called once per unboxed constant, to emit its bytes. +;;; In general the bytes may be literal octets, or a fixup (as here) +;;; which is in turn emitted with a pseudo-instruction. +(defun emit-inline-constant (section constant label) + (aver (typep constant '(cons (eql :layout-id) (cons t null)))) + (emit section + `(.align 2) ; 2 bits of alignment (just to be pedantic I suppose) + label + `(.layout-id ,(cadr constant)))) + +(sb-assem::%def-inst-encoder + '.layout-id + (lambda (segment layout) + (sb-c:note-fixup segment :absolute (sb-c:make-fixup layout :layout-id)) + (sb-assem::%emit-skip segment 4))) + +(defun sb-vm:fixup-code-object (code offset value kind flavor) + (declare (type index offset)) + (declare (ignore flavor)) + (unless (zerop (rem offset sb-assem:+inst-alignment-bytes+)) + (error "Unaligned instruction? offset=#x~X." offset)) + (let ((sap (code-instructions code))) + (ecase kind + (:absolute + (setf (sap-ref-32 sap offset) value)) + (:sll-sa + ;; VALUE is the number of bits we'd like to mask the card table index to. + ;; But instead of using an AND instruction, we use left-shift + right-shift. + ;; So it's the same as right-shift + AND but weird. + (let* ((inst (sap-ref-32 sap offset)) + (next (sap-ref-32 sap (+ offset 4))) + (rd (ldb (byte 5 11) inst)) + (left-shamt (- 32 (+ sb-vm::gencgc-card-shift value))) + (right-shamt (+ left-shamt sb-vm::gencgc-card-shift))) + ;; the next instruction has to be SRL rd, d, # + (aver (and (= (ldb (byte 11 21) next) #b00000000000) + (= (ldb (byte 10 11) next) (logior (ash rd 5) rd)) + (= (ldb (byte 6 0) next) #b000010))) + (setf (sap-ref-32 sap offset) (dpb left-shamt (byte 5 6) inst)) + (setf (sap-ref-32 sap (+ offset 4)) (dpb right-shamt (byte 5 6) next)))) + (:jump + (aver (zerop (ash value -28))) + (setf (ldb (byte 26 0) (sap-ref-32 sap offset)) + (ash value -2))) + (:lui + (setf (ldb (byte 16 0) (sap-ref-32 sap offset)) + (ash (1+ (ash value -15)) -1))) + (:addi + (setf (ldb (byte 16 0) (sap-ref-32 sap offset)) + (ldb (byte 16 0) value))))) + nil) + +(defun sb-c::pack-retained-fixups (fixup-notes) + (let (result) + (dolist (note fixup-notes (sb-c:pack-code-fixup-locs nil nil result)) + (let ((fixup (fixup-note-fixup note))) + (when (eq (fixup-flavor fixup) :gc-barrier) + (push (fixup-note-position note) result)))))) + +(define-instruction store-coverage-mark (segment mark-index) + ;; Don't need to annotate the dependence on code-tn, I think? + (:dependencies (writes :memory)) + (:delay 0) + (:emitter + ;; No backpatch is needed to compute the offset into the code header + ;; because COMPONENT-HEADER-LENGTH is known at this point. + ;; + ;; If someone wants to be clever and allow larger offsets from code-tn, + ;; feel free to try to improve this, but given that ASSEM-SCHEDULER-P is T + ;; for MIPS, I very much suspect that something would go wrong + ;; by emitting more than 1 CPU instruction from within an emitter. + (let ((offset (+ (component-header-length) + ;; skip over jump table word and entries + (* (1+ (component-n-jump-table-entries)) + n-word-bytes) + mark-index + (- other-pointer-lowtag)))) + (inst* segment 'sb sb-vm::null-tn sb-vm::code-tn + (the (unsigned-byte 15) offset))))) diff --git a/src/compiler/mips/macros.lisp b/src/compiler/mips/macros.lisp index 9672637b0c..0523e17759 100644 --- a/src/compiler/mips/macros.lisp +++ b/src/compiler/mips/macros.lisp @@ -39,26 +39,21 @@ (defmacro zeroize (reg) `(inst move ,reg zero-tn)) -(defmacro def-mem-op (op inst shift load) - `(defmacro ,op (object base &optional (offset 0) (lowtag 0)) - `(progn - (inst ,',inst ,object ,base (- (ash ,offset ,,shift) ,lowtag)) - ,,@(when load '('(inst nop)))))) -;;; -(def-mem-op loadw lw word-shift t) -(def-mem-op storew sw word-shift nil) +(macrolet ((def-mem-op (op inst shift) + `(defmacro ,op (object base &optional (offset 0) (lowtag 0)) + `(inst ,',inst ,object ,base (- (ash ,offset ,,shift) ,lowtag))))) + (def-mem-op loadw lw word-shift) + (def-mem-op storew sw word-shift)) (defmacro load-symbol (reg symbol) (once-only ((reg reg) (symbol symbol)) `(inst addu ,reg null-tn (static-symbol-offset ,symbol)))) (defmacro load-symbol-value (reg symbol) - `(progn - (inst lw ,reg null-tn - (+ (static-symbol-offset ',symbol) - (ash symbol-value-slot word-shift) - (- other-pointer-lowtag))) - (inst nop))) + `(inst lw ,reg null-tn + (+ (static-symbol-offset ',symbol) + (ash symbol-value-slot word-shift) + (- other-pointer-lowtag)))) (defmacro store-symbol-value (reg symbol) `(inst sw ,reg null-tn @@ -159,33 +154,24 @@ placed inside the PSEUDO-ATOMIC, and presumably initializes the object." (dynamic-extent-p dynamic-extent-p) (lowtag lowtag)) `(if ,dynamic-extent-p - (pseudo-atomic (,flag-tn) - (align-csp ,temp-tn) + (pseudo-atomic (,flag-tn) ; why P-A ??? + (align-csp ,temp-tn ,flag-tn) (inst or ,result-tn csp-tn ,lowtag) (inst li ,temp-tn (compute-object-header ,size ,type-code)) (inst addu csp-tn (pad-data-block ,size)) (storew ,temp-tn ,result-tn 0 ,lowtag) ,@body) - (pseudo-atomic (,flag-tn :extra (pad-data-block ,size)) - ;; The pseudo-atomic bit in alloc-tn is set. If the lowtag also - ;; has a 1 bit in the same position, we're all set. Otherwise, - ;; we need to subtract the pseudo-atomic bit. - (inst or ,result-tn alloc-tn ,lowtag) - (unless (logbitp 0 ,lowtag) (inst subu ,result-tn 1)) + (pseudo-atomic (,flag-tn) + (allocation ,type-code (pad-data-block ,size) ,result-tn ,lowtag + (list ,flag-tn ,temp-tn) :stackp ,dynamic-extent-p) (inst li ,temp-tn (compute-object-header ,size ,type-code)) (storew ,temp-tn ,result-tn 0 ,lowtag) ,@body)))) -(defun align-csp (temp) - ;; is used for stack allocation of dynamic-extent objects - (let ((aligned (gen-label))) - (inst and temp csp-tn lowtag-mask) - (inst beq temp aligned) - (inst nop) - (inst addu csp-tn n-word-bytes) - (storew zero-tn csp-tn -1) - (emit-label aligned))) - +(defun align-csp (temp1 temp2) + (inst li temp1 (lognot lowtag-mask)) + (inst addu temp2 csp-tn lowtag-mask) + (inst and csp-tn temp2 temp1)) ;;;; Three Way Comparison (defun three-way-comparison (x y condition flavor not-p target temp) @@ -238,21 +224,18 @@ placed inside the PSEUDO-ATOMIC, and presumably initializes the object." ;;;; PSEUDO-ATOMIC -;;; handy macro for making sequences look atomic -(defmacro pseudo-atomic ((flag-tn &key (extra 0)) &rest forms) +(defmacro pseudo-atomic ((flag-tn &key elide-if (extra nil)) &rest forms) + (aver (not extra)) `(progn - (aver (= (tn-offset ,flag-tn) nl4-offset)) - (aver (not (minusp ,extra))) - (without-scheduling () - (inst li ,flag-tn ,extra) - (inst addu alloc-tn 1)) + (unless ,elide-if + (without-scheduling () + (store-symbol-value csp-tn *pseudo-atomic-atomic*))) ,@forms - (without-scheduling () - (let ((label (gen-label))) - (inst bgez ,flag-tn label) - (inst addu alloc-tn (1- ,extra)) - (inst break 0 pending-interrupt-trap) - (emit-label label))))) + (unless ,elide-if + (without-scheduling () + (store-symbol-value null-tn *pseudo-atomic-atomic*) + (load-symbol-value ,flag-tn *pseudo-atomic-interrupted*) + (inst tne zero-tn ,flag-tn))))) ;;;; memory accessor vop generators @@ -298,39 +281,44 @@ placed inside the PSEUDO-ATOMIC, and presumably initializes the object." (defmacro define-full-setter (name type offset lowtag scs el-type &optional translate) + (aver translate) `(progn (define-vop (,name) - ,@(when translate - `((:translate ,translate))) + (:translate ,translate) (:policy :fast-safe) (:args (object :scs (descriptor-reg)) (index :scs (any-reg)) - (value :scs ,scs :target result)) + (value :scs ,scs)) (:arg-types ,type tagged-num ,el-type) - (:temporary (:scs (interior-reg)) lip) - (:results (result :scs ,scs)) - (:result-types ,el-type) + (:temporary (:scs (non-descriptor-reg)) temp) + (:vop-var vop) (:generator 2 - (inst addu lip object index) - (storew value lip ,offset ,lowtag) - (move result value))) + ,@(if (member name '(instance-index-set %closure-index-set)) + `((without-scheduling () + (emit-gc-store-barrier object nil temp (vop-nth-arg 2 vop) value) + (inst addu temp object index) + (storew value temp ,offset ,lowtag))) + `((inst addu temp object index) + (storew value temp ,offset ,lowtag))))) (define-vop (,(symbolicate name "-C")) - ,@(when translate - `((:translate ,translate))) + (:translate ,translate) (:policy :fast-safe) (:args (object :scs (descriptor-reg)) (value :scs ,scs)) (:info index) + ,@(when (member name '(instance-index-set %closure-index-set)) + '((:temporary (:scs (non-descriptor-reg)) temp))) (:arg-types ,type (:constant (load/store-index ,n-word-bytes ,(eval lowtag) ,(eval offset))) ,el-type) - (:results (result :scs ,scs)) - (:result-types ,el-type) + (:vop-var vop) (:generator 1 - (storew value object (+ ,offset index) ,lowtag) - (move result value))))) - + ,@(if (member name '(instance-index-set %closure-index-set)) + `((without-scheduling () + (emit-gc-store-barrier object nil temp (vop-nth-arg 1 vop) value) + (storew value object (+ ,offset index) ,lowtag))) + `((storew value object (+ ,offset index) ,lowtag))))))) (defmacro define-partial-reffer (name type size signed offset lowtag scs el-type &optional translate) @@ -385,34 +373,28 @@ placed inside the PSEUDO-ATOMIC, and presumably initializes the object." (:policy :fast-safe) (:args (object :scs (descriptor-reg)) (index :scs (unsigned-reg)) - (value :scs ,scs :target result)) + (value :scs ,scs)) (:arg-types ,type positive-fixnum ,el-type) (:temporary (:scs (interior-reg)) lip) - (:results (result :scs ,scs)) - (:result-types ,el-type) (:generator 5 (inst addu lip object index) ,@(when (eq size :short) '((inst addu lip index))) (inst ,(ecase size (:byte 'sb) (:short 'sh)) - value lip (- (* ,offset n-word-bytes) ,lowtag)) - (move result value))) + value lip (- (* ,offset n-word-bytes) ,lowtag)))) (define-vop (,(symbolicate name "-C")) ,@(when translate `((:translate ,translate))) (:policy :fast-safe) (:args (object :scs (descriptor-reg)) - (value :scs ,scs :target result)) + (value :scs ,scs)) (:info index) (:arg-types ,type (:constant (load/store-index ,scale ,(eval lowtag) ,(eval offset))) ,el-type) - (:results (result :scs ,scs)) - (:result-types ,el-type) (:generator 4 (inst ,(ecase size (:byte 'sb) (:short 'sh)) value object - (- (+ (* ,offset n-word-bytes) (* index ,scale)) ,lowtag)) - (move result value)))))) + (- (+ (* ,offset n-word-bytes) (* index ,scale)) ,lowtag))))))) diff --git a/src/compiler/mips/memory.lisp b/src/compiler/mips/memory.lisp index 63166ff476..40d584ac64 100644 --- a/src/compiler/mips/memory.lisp +++ b/src/compiler/mips/memory.lisp @@ -1,5 +1,13 @@ (in-package "SB-VM") +;;; You should generally put WITHOUT-SCHEDULING around this because the fixup patcher +;;; wants to see the two shifts as consecutive instructions. +(defun emit-gc-store-barrier (object cell-address temp &optional value-tn-ref value-tn) + (when (require-gc-store-barrier-p object value-tn-ref value-tn) + (inst sll temp (or cell-address object) (make-fixup nil :gc-barrier)) + (inst srl temp temp 0) + (inst addu temp temp cardbase-tn) + (inst sb zero-tn temp 0))) ;;; Cell-Ref and Cell-Set are used to define VOPs like CAR, where the offset to ;;; be read or written is a property of the VOP used. @@ -17,5 +25,9 @@ (value :scs (descriptor-reg any-reg null zero))) (:variant-vars offset lowtag) (:policy :fast-safe) + (:temporary (:sc non-descriptor-reg) temp) + (:vop-var vop) (:generator 4 - (storew value object offset lowtag))) + (without-scheduling () + (emit-gc-store-barrier object nil temp (vop-nth-arg 1 vop) value) + (storew value object offset lowtag)))) diff --git a/src/compiler/mips/move.lisp b/src/compiler/mips/move.lisp index 6d5f6a2ce3..cd8d4c6ebc 100644 --- a/src/compiler/mips/move.lisp +++ b/src/compiler/mips/move.lisp @@ -185,6 +185,7 @@ (with-fixed-allocation (y pa-flag temp bignum-widetag (1+ bignum-digits-offset) nil) + ;; FIXME: could this store be moved forward into the branch delay slot? (storew x y bignum-digits-offset other-pointer-lowtag)) (inst b done) (inst nop) @@ -208,7 +209,7 @@ (inst beq temp done) (inst sll y x n-fixnum-tag-bits) - (load-constant vop (emit-constant (1+ sb-xc:most-positive-fixnum)) + (load-constant vop (emit-constant (1+ most-positive-fixnum)) y) (inst b done) (inst nop) @@ -225,7 +226,7 @@ (inst beq temp done) (inst sll y x n-fixnum-tag-bits) - (load-constant vop (emit-constant (1- sb-xc:most-negative-fixnum)) + (load-constant vop (emit-constant (1- most-negative-fixnum)) y) (inst b done) (inst nop) @@ -249,9 +250,9 @@ (inst beq temp done) (inst sll y x n-fixnum-tag-bits) - (pseudo-atomic - (pa-flag :extra (pad-data-block (+ bignum-digits-offset 2))) - (inst or y alloc-tn other-pointer-lowtag) + (pseudo-atomic (pa-flag) + (allocation bignum-widetag (pad-data-block (+ bignum-digits-offset 2)) y + other-pointer-lowtag `(,pa-flag ,temp)) (inst slt temp x zero-tn) (inst sll temp n-widetag-bits) (inst addu temp (logior (ash 1 n-widetag-bits) bignum-widetag)) diff --git a/src/compiler/mips/nlx.lisp b/src/compiler/mips/nlx.lisp index 323ff5d9f1..16e583705b 100644 --- a/src/compiler/mips/nlx.lisp +++ b/src/compiler/mips/nlx.lisp @@ -196,6 +196,18 @@ (inst nop)))))) (load-stack-tn csp-tn sp))) +(define-vop (nlx-entry-single) + (:args (sp) + (value)) + (:results (res :from :load)) + (:info label) + (:save-p :force-to-stack) + (:vop-var vop) + (:generator 30 + (emit-return-pc label) + (note-this-location vop :non-local-entry) + (move res value) + (load-stack-tn csp-tn sp))) (define-vop (nlx-entry-multiple) (:args (top :target dst) (start :target src) (count :target num)) diff --git a/src/compiler/mips/parms.lisp b/src/compiler/mips/parms.lisp index 7bfa61c982..4818f16438 100644 --- a/src/compiler/mips/parms.lisp +++ b/src/compiler/mips/parms.lisp @@ -18,6 +18,10 @@ ;; The o32 ABI specifies 4k-64k as page size. We have to pick the ;; maximum since mprotect() works only with page granularity. (defconstant +backend-page-bytes+ 65536) +(defconstant gencgc-page-bytes 8192) +(defconstant cards-per-page 8) +(defconstant gencgc-alloc-granularity 0) +(defconstant gencgc-release-granularity +backend-page-bytes+) ;;;; Machine Architecture parameters: (eval-when (:compile-toplevel :load-toplevel :execute) @@ -29,28 +33,6 @@ ;;; address space) (defconstant n-machine-word-bits 32) -(defconstant float-sign-shift 31) - -(defconstant single-float-bias 126) -(defconstant-eqx single-float-exponent-byte (byte 8 23) #'equalp) -(defconstant-eqx single-float-significand-byte (byte 23 0) #'equalp) -(defconstant single-float-normal-exponent-min 1) -(defconstant single-float-normal-exponent-max 254) -(defconstant single-float-hidden-bit (ash 1 23)) - -(defconstant double-float-bias 1022) -(defconstant-eqx double-float-exponent-byte (byte 11 20) #'equalp) -(defconstant-eqx double-float-significand-byte (byte 20 0) #'equalp) -(defconstant double-float-normal-exponent-min 1) -(defconstant double-float-normal-exponent-max #x7FE) -(defconstant double-float-hidden-bit (ash 1 20)) - -(defconstant single-float-digits - (+ (byte-size single-float-significand-byte) 1)) - -(defconstant double-float-digits - (+ (byte-size double-float-significand-byte) n-word-bits 1)) - (defconstant float-inexact-trap-bit (ash 1 0)) (defconstant float-underflow-trap-bit (ash 1 1)) (defconstant float-overflow-trap-bit (ash 1 2)) @@ -74,24 +56,10 @@ #+linux (progn - ;; Where to put the address spaces on Linux. - ;; - ;; C runtime executable segment starts at 0x00400000 - (defconstant read-only-space-start #x01000000) - (defconstant read-only-space-end #x07ff0000) ; 112 MiB - - (defconstant linkage-table-space-start #x08000000) - ;; 64K of linkage space = 16K linkage entries - (defconstant linkage-table-space-end (+ linkage-table-space-start 65536)) - (defconstant static-space-start linkage-table-space-end) - (defconstant static-space-end #x0fff0000) - ;; C runtime read/write segment starts at 0x10000000, heap and DSOs - ;; start at 0x2a000000 - (defparameter dynamic-0-space-start #x30000000) - (defparameter dynamic-0-space-end #x4fff0000) - - (defconstant linkage-table-entry-size 4) - (defconstant linkage-table-growth-direction :down) + (!gencgc-space-setup #x04000000 :dynamic-space-start #x4f000000) + + (defconstant alien-linkage-table-entry-size 4) + (defconstant alien-linkage-table-growth-direction :down) (setq *linkage-space-predefined-entries* '(("call_into_c" nil))) ;; C stack grows downward from 0x80000000 @@ -102,14 +70,12 @@ ;;;; Other non-type constants. -(defenum () - atomic-flag - interrupted-flag) - (defenum (:start 8) halt-trap pending-interrupt-trap cerror-trap + invalid-arg-count-trap + allocation-trap breakpoint-trap fun-end-breakpoint-trap after-breakpoint-trap @@ -127,7 +93,9 @@ ;;; space directly after the static symbols. That way, the raw-addr ;;; can be loaded directly out of them by indirecting relative to NIL. (defconstant-eqx +static-symbols+ - `#(,@+common-static-symbols+) + `#(,@+common-static-symbols+ + *pseudo-atomic-atomic* + *pseudo-atomic-interrupted*) #'equalp) (defconstant-eqx +static-fdefns+ diff --git a/src/compiler/mips/sap.lisp b/src/compiler/mips/sap.lisp index 77481f1dc4..e2fd57d277 100644 --- a/src/compiler/mips/sap.lisp +++ b/src/compiler/mips/sap.lisp @@ -145,9 +145,7 @@ ;;;; mumble-SYSTEM-REF and mumble-SYSTEM-SET (macrolet ((def-system-ref-and-set - (ref-name set-name sc type size &optional signed) - (let ((ref-name-c (symbolicate ref-name "-C")) - (set-name-c (symbolicate set-name "-C"))) + (ref-name set-name sc type size &optional signed) `(progn (define-vop (,ref-name) (:translate ,ref-name) @@ -182,7 +180,7 @@ '((inst lwc1 result sap 0) (inst lwc1-odd result sap n-word-bytes)))))) (inst nop))) - (define-vop (,ref-name-c) + (define-vop (,(symbolicate ref-name "-C")) (:translate ,ref-name) (:policy :fast-safe) (:args (object :scs (sap-reg))) @@ -221,83 +219,60 @@ (define-vop (,set-name) (:translate ,set-name) (:policy :fast-safe) - (:args (object :scs (sap-reg) :target sap) - (offset :scs (signed-reg)) - (value :scs (,sc) :target result)) - (:arg-types system-area-pointer signed-num ,type) - (:results (result :scs (,sc))) - (:result-types ,type) - (:temporary (:scs (sap-reg) :from (:argument 0)) sap) + (:args (value :scs (,sc) :to :eval) ; VALUE has to conflict with SAP + (object :scs (sap-reg) :target sap) + (offset :scs (signed-reg))) + (:arg-types ,type system-area-pointer signed-num) + (:temporary (:scs (sap-reg) :from (:argument 1)) sap) (:generator 5 (inst addu sap object offset) ,@(ecase size (:byte - '((inst sb value sap 0) - (move result value))) + '((inst sb value sap 0))) (:short - '((inst sh value sap 0) - (move result value))) + '((inst sh value sap 0))) (:long - '((inst sw value sap 0) - (move result value))) + '((inst sw value sap 0))) (:single - '((inst swc1 value sap 0) - (unless (location= result value) - (inst fmove :single result value)))) + '((inst swc1 value sap 0))) (:double (ecase *backend-byte-order* (:big-endian '((inst swc1 value sap n-word-bytes) - (inst swc1-odd value sap 0) - (unless (location= result value) - (inst fmove :double result value)))) + (inst swc1-odd value sap 0))) (:little-endian '((inst swc1 value sap 0) - (inst swc1-odd value sap n-word-bytes) - (unless (location= result value) - (inst fmove :double result value))))))))) - (define-vop (,set-name-c) + (inst swc1-odd value sap n-word-bytes)))))))) + (define-vop (,(symbolicate set-name "-C")) (:translate ,set-name) (:policy :fast-safe) - (:args (object :scs (sap-reg)) - (value :scs (,sc) :target result)) - (:arg-types system-area-pointer + (:args (value :scs (,sc)) + (object :scs (sap-reg))) + (:arg-types ,type system-area-pointer (:constant ,(if (eq size :double) ;; We need to be able to add 4. `(integer ,(- (ash 1 16)) ,(- (ash 1 16) 5)) - '(signed-byte 16))) - ,type) + '(signed-byte 16)))) (:info offset) - (:results (result :scs (,sc))) - (:result-types ,type) (:generator 4 ,@(ecase size (:byte - '((inst sb value object offset) - (move result value))) + '((inst sb value object offset))) (:short - '((inst sh value object offset) - (move result value))) + '((inst sh value object offset))) (:long - '((inst sw value object offset) - (move result value))) + '((inst sw value object offset))) (:single - '((inst swc1 value object offset) - (unless (location= result value) - (inst fmove :single result value)))) + '((inst swc1 value object offset))) (:double (ecase *backend-byte-order* (:big-endian '((inst swc1 value object (+ offset n-word-bytes)) - (inst swc1-odd value object offset) - (unless (location= result value) - (inst fmove :double result value)))) + (inst swc1-odd value object offset))) (:little-endian '((inst swc1 value object offset) - (inst swc1-odd value object (+ offset n-word-bytes)) - (unless (location= result value) - (inst fmove :double result value))))))))))))) + (inst swc1-odd value object (+ offset n-word-bytes)))))))))))) (def-system-ref-and-set sap-ref-8 %set-sap-ref-8 unsigned-reg positive-fixnum :byte nil) (def-system-ref-and-set signed-sap-ref-8 %set-signed-sap-ref-8 diff --git a/src/compiler/mips/show.lisp b/src/compiler/mips/show.lisp index 292ccf83a6..da103c0687 100644 --- a/src/compiler/mips/show.lisp +++ b/src/compiler/mips/show.lisp @@ -26,8 +26,8 @@ (when cur-nfp (store-stack-tn nfp-save cur-nfp)) (move nl0 object) - ;; (linkage-table-entry-address 0) is "call-into-c" in mips-assem.S - (inst lw tramp null-tn (- (linkage-table-entry-address 0) nil-value)) + ;; (alien-linkage-table-entry-address 0) is "call-into-c" in mips-assem.S + (inst lw tramp null-tn (- (alien-linkage-table-entry-address 0) nil-value)) (inst li cfunc (make-fixup "debug_print" :foreign)) (inst jal tramp) (inst subu nsp-tn 16) diff --git a/src/compiler/mips/system.lisp b/src/compiler/mips/system.lisp index 37a8d44676..2dccf84e6f 100644 --- a/src/compiler/mips/system.lisp +++ b/src/compiler/mips/system.lisp @@ -53,10 +53,29 @@ OTHER-PTR (load-type result object (- other-pointer-lowtag)) - (inst nop) DONE)) +(define-vop () + (:translate sb-c::%structure-is-a) + (:args (x :scs (descriptor-reg))) + (:arg-types * (:constant t)) + (:policy :fast-safe) + (:conditional) + ;; "extra" info in conditional vops follows the 2 super-magical info args + (:info target not-p test-layout) + (:temporary (:sc unsigned-reg) this-id test-id) + (:generator 4 + (let ((label (register-inline-constant :layout-id test-layout)) + (offset (+ (id-bits-offset) + (ash (- (wrapper-depthoid test-layout) 2) 2) + (- instance-pointer-lowtag)))) + (inst lw test-id sb-vm::code-tn label) + (inst lw this-id x offset) + (inst nop) + (inst* (if not-p 'bne 'beq) this-id test-id target) + (inst nop)))) + (define-vop (%other-pointer-widetag) (:translate %other-pointer-widetag) (:policy :fast-safe) @@ -66,15 +85,14 @@ (:generator 6 (load-type result object (- other-pointer-lowtag)))) -(define-vop (fun-subtype) - (:translate fun-subtype) +(define-vop () + (:translate %fun-pointer-widetag) (:policy :fast-safe) (:args (function :scs (descriptor-reg))) (:results (result :scs (unsigned-reg))) (:result-types positive-fixnum) (:generator 6 - (load-type result function (- fun-pointer-lowtag)) - (inst nop))) + (load-type result function (- fun-pointer-lowtag)))) (define-vop (get-header-data) (:translate get-header-data) @@ -89,10 +107,9 @@ (define-vop (set-header-data) (:translate set-header-data) (:policy :fast-safe) - (:args (x :scs (descriptor-reg) :target res) + (:args (x :scs (descriptor-reg)) (data :scs (any-reg immediate zero))) (:arg-types * positive-fixnum) - (:results (res :scs (descriptor-reg))) (:temporary (:scs (non-descriptor-reg)) t1 t2) (:generator 6 (loadw t1 x 0 other-pointer-lowtag) @@ -109,8 +126,7 @@ (inst li t2 val) (inst or t1 t2))))) (zero)) - (storew t1 x 0 other-pointer-lowtag) - (move res x))) + (storew t1 x 0 other-pointer-lowtag))) (define-vop (pointer-hash) (:translate pointer-hash) @@ -125,14 +141,6 @@ ;;;; Allocation -(define-vop (dynamic-space-free-pointer) - (:results (int :scs (sap-reg))) - (:result-types system-area-pointer) - (:translate dynamic-space-free-pointer) - (:policy :fast-safe) - (:generator 1 - (move int alloc-tn))) - (define-vop (binding-stack-pointer-sap) (:results (int :scs (sap-reg))) (:result-types system-area-pointer) @@ -240,3 +248,10 @@ (:translate spin-loop-hint) (:policy :fast-safe) (:generator 0)) + +(define-vop (sb-c::mark-covered) + (:info index) + (:generator 4 + ;; Can't convert index to a code-relative index until the boxed header length + ;; has been determined. + (inst store-coverage-mark index))) diff --git a/src/compiler/mips/target-insts.lisp b/src/compiler/mips/target-insts.lisp index db2de12a6c..3478ff3335 100644 --- a/src/compiler/mips/target-insts.lisp +++ b/src/compiler/mips/target-insts.lisp @@ -11,5 +11,36 @@ ;;;; provided with absolutely no warranty. See the COPYING and CREDITS ;;;; files for more information. -(in-package "SB-VM") +(in-package "SB-MIPS-ASM") +(defun jump-printer (value stream dstate) + (let ((addr (ash value 2))) + (cond (stream + (maybe-note-assembler-routine addr t dstate) + (write addr :base 16 :radix t :stream stream)) + (t + (operand addr dstate))))) + +(defun break-control (chunk inst stream dstate) + (declare (ignore inst)) + (flet ((nt (x) (if stream (note x dstate)))) + (let ((trap (break-subcode chunk dstate))) + (case trap + (#.halt-trap + (nt "Halt trap")) + (#.pending-interrupt-trap + (nt "Pending interrupt trap")) + (#.breakpoint-trap + (nt "Breakpoint trap")) + (#.fun-end-breakpoint-trap + (nt "Function end breakpoint trap")) + (#.after-breakpoint-trap + (nt "After breakpoint trap")) + (#.single-step-around-trap + (nt "Single step around trap")) + (#.single-step-before-trap + (nt "Single step before trap")) + (t + (when (or (and (= trap cerror-trap) (progn (nt "cerror trap") t)) + (>= trap error-trap)) + (handle-break-args #'snarf-error-junk trap stream dstate))))))) diff --git a/src/compiler/mips/type-vops.lisp b/src/compiler/mips/type-vops.lisp index 992243d70d..5e1740e946 100644 --- a/src/compiler/mips/type-vops.lisp +++ b/src/compiler/mips/type-vops.lisp @@ -61,7 +61,6 @@ (assemble () (%test-lowtag value temp when-false t lowtag) (load-type temp value (- lowtag)) - (inst nop) (let ((delta 0)) (do ((remaining headers (cdr remaining))) ((null remaining)) @@ -121,7 +120,7 @@ (define-vop (signed-byte-32-p type-predicate) (:translate signed-byte-32-p) - (:generator 45 + (:generator 10 (signed-byte-32-test value temp not-p target not-target) NOT-TARGET)) @@ -174,7 +173,7 @@ (define-vop (unsigned-byte-32-p type-predicate) (:translate unsigned-byte-32-p) - (:generator 45 + (:generator 10 (unsigned-byte-32-test value temp not-p target not-target) NOT-TARGET)) diff --git a/src/compiler/mips/values.lisp b/src/compiler/mips/values.lisp index 832c86c14b..1ba56ecd1e 100644 --- a/src/compiler/mips/values.lisp +++ b/src/compiler/mips/values.lisp @@ -63,7 +63,7 @@ ;;; (define-vop (push-values) (:args - (vals :more t)) + (vals :more t :scs (descriptor-reg any-reg control-stack))) (:results (start :scs (any-reg)) (count :scs (any-reg))) @@ -81,7 +81,7 @@ ((null val)) (let ((tn (tn-ref-tn val))) (sc-case tn - (descriptor-reg + ((descriptor-reg any-reg) (storew tn start-temp i)) (control-stack (load-stack-tn temp tn) @@ -125,22 +125,15 @@ ;;; as function arguments. (define-vop (%more-arg-values) (:args (context :scs (descriptor-reg any-reg) :target src) - (skip :scs (any-reg zero immediate)) (num :scs (any-reg) :target count)) - (:arg-types * positive-fixnum positive-fixnum) + (:arg-types * positive-fixnum) (:temporary (:sc any-reg :from (:argument 0)) src) (:temporary (:sc any-reg :from (:argument 2)) dst) (:temporary (:sc descriptor-reg :from (:argument 1)) temp) (:results (start :scs (any-reg)) (count :scs (any-reg))) (:generator 20 - (sc-case skip - (zero - (move src context)) - (immediate - (inst addu src context (* (tn-value skip) n-word-bytes))) - (any-reg - (inst addu src context skip))) + (move src context) (move count num) (inst beq num done) (emit-nop-or-move start csp-tn) diff --git a/src/compiler/mips/vm.lisp b/src/compiler/mips/vm.lisp index f7de334b29..09920a1607 100644 --- a/src/compiler/mips/vm.lisp +++ b/src/compiler/mips/vm.lisp @@ -11,6 +11,8 @@ (in-package "SB-VM") +(defconstant-eqx +fixup-kinds+ #(:absolute :jmp :lui :addi :sll-sa) #'equalp) + ;;;; Registers @@ -59,8 +61,8 @@ (defreg csp 23) ; control stack pointer ;; More C unsaved temporaries. (defreg l1 24) ; tagged temporary 1 - (defreg alloc 25) ; ALLOC pointer - ;; 26 and 27 are used by the system kernel. + (defreg cardbase 25) + ;; 26 and 27 are used by the syste kernel. (defreg k0 26) (defreg k1 27) ;; 28 is the global pointer of our C runtime @@ -273,7 +275,7 @@ (defregtn bsp any-reg) (defregtn cfp any-reg) (defregtn csp any-reg) - (defregtn alloc any-reg) + (defregtn cardbase any-reg) (defregtn nsp any-reg) (defregtn code descriptor-reg) @@ -291,8 +293,7 @@ (if (static-symbol-p value) immediate-sc-number nil)) - ((or (integer #.sb-xc:most-negative-fixnum #.sb-xc:most-positive-fixnum) - character) + ((signed-byte 30) immediate-sc-number) #-sb-xc-host ; There is no such object type in the host (system-area-pointer diff --git a/src/compiler/modarith.lisp b/src/compiler/modarith.lisp index 709c858950..cfc9c3b70b 100644 --- a/src/compiler/modarith.lisp +++ b/src/compiler/modarith.lisp @@ -16,12 +16,12 @@ (defstruct (modular-class (:copier nil)) ;; hash: name -> { :GOOD | optimizer | ({modular-fun-info}*)} - (funs (make-hash-table :test 'eq)) + (funs (make-hash-table)) ; keys are symbols ;; hash: modular-variant -> (prototype width) ;; ;; FIXME: Reimplement with generic function names of kind ;; (MODULAR-VERSION prototype width) - (versions (make-hash-table :test 'eq)) + (versions (make-hash-table)) ;; list of increasing widths + signedps (widths nil)) (define-load-time-global *untagged-unsigned-modular-class* (make-modular-class)) @@ -96,10 +96,23 @@ (check-type kind (member :untagged :tagged)) (when lambda-list-p (dolist (arg lambda-list) - (when (member arg sb-xc:lambda-list-keywords) + (when (member arg lambda-list-keywords) (error "Lambda list keyword ~S is not supported for modular ~ function lambda lists." arg)))))) +(defun make-modular-fun-type-deriver (prototype width signedp) + (let ((info (fun-info-or-lose prototype)) + (mask-type (specifier-type + (if signedp + `(signed-byte ,width) + `(unsigned-byte ,width))))) + (lambda (call) + (let ((res (funcall (fun-info-derive-type info) call))) + (when res + (if (csubtypep res mask-type) + res + mask-type)))))) + (defmacro define-modular-fun (name lambda-list prototype kind signedp width) (%check-modular-fun-macro-arguments name kind lambda-list) (check-type prototype symbol) @@ -107,13 +120,12 @@ `(progn (%define-modular-fun ',name ',lambda-list ',prototype ',kind ',signedp ,width) (defknown ,name ,(mapcar (constantly 'integer) lambda-list) - (,(ecase signedp - ((nil) 'unsigned-byte) - ((t) 'signed-byte)) - ,width) - (foldable flushable movable) - :derive-type (make-modular-fun-type-deriver - ',prototype ',kind ,width ',signedp)))) + (,(ecase signedp + ((nil) 'unsigned-byte) + ((t) 'signed-byte)) + ,width) + (foldable flushable movable always-translatable) + :derive-type (make-modular-fun-type-deriver ',prototype ,width ',signedp)))) (defun %define-good-modular-fun (name kind signedp) (setf (gethash name (modular-class-funs (find-modular-class kind signedp))) :good) @@ -200,8 +212,10 @@ (return-from insert-lvar-cut))))) (filter-lvar lvar (if signedp - `(mask-signed-field ,width 'dummy) - `(logand 'dummy ,(ldb (byte width 0) -1)))) + (lambda (dummy) + `(mask-signed-field ,width ,dummy)) + (lambda (dummy) + `(logand ,dummy ,(ldb (byte width 0) -1))))) (do-uses (node lvar) (setf (block-reoptimize (node-block node)) t) (reoptimize-component (node-component node) :maybe)) @@ -228,7 +242,7 @@ (cond ((= constant-value new-value) (values t nil)) ; we knew what to do and did nothing (t - (change-ref-leaf node (make-constant new-value) + (change-ref-leaf node (find-constant new-value) :recklessly t) (let ((lvar (node-lvar node))) (setf (lvar-%derived-type lvar) @@ -381,7 +395,6 @@ ))))))) (defoptimizer (mask-signed-field optimizer) ((width x) node) - (declare (ignore width)) (let ((result-type (single-value-type (node-derived-type node)))) (multiple-value-bind (low high) (integer-type-numeric-bounds result-type) @@ -439,32 +452,59 @@ ,(1- (ash 1 (+ width (lvar-value amount)))))) `(lambda (value amount1 amount2) (ash value (+ amount1 amount2))))))))) - (macrolet - ((def (name kind width signedp) + ((def (left-name name kind width signedp) + (declare (ignorable name)) (let ((type (ecase signedp ((nil) 'unsigned-byte) ((t) 'signed-byte)))) `(progn - (defknown ,name (integer (integer 0)) (,type ,width) - (foldable flushable movable)) + (defknown ,left-name (integer (integer 0)) (,type ,width) + (foldable flushable movable) + :derive-type (make-modular-fun-type-deriver 'ash ',width ',signedp)) (define-modular-fun-optimizer ash ((integer count) ,kind ,signedp :width width) - (when (and (<= width ,width) - (or (and (constant-lvar-p count) + (let ((integer-type (lvar-type integer)) + (count-type (lvar-type count))) + (declare (ignorable integer-type)) + (when (<= width ,width) + (cond ((or (and (constant-lvar-p count) (plusp (lvar-value count))) - (csubtypep (lvar-type count) - (specifier-type '(and unsigned-byte fixnum))))) - (cut-to-width integer ,kind width ,signedp) - ',name)) - (setf (gethash ',name (modular-class-versions (find-modular-class ',kind ',signedp))) - `(ash ,',width)))))) - ;; This should really be dependent on SB-VM:N-WORD-BITS, but since we - ;; don't have a true Alpha64 port yet, we'll have to stick to - ;; SB-VM:N-MACHINE-WORD-BITS for the time being. --njf, 2004-08-14 - #.`(progn - #+(or x86 x86-64 arm arm64) - (def sb-vm::ash-left-modfx - :tagged ,(- sb-vm:n-word-bits sb-vm:n-fixnum-tag-bits) t) - (def ,(intern (format nil "ASH-LEFT-MOD~D" sb-vm:n-machine-word-bits) - "SB-VM") - :untagged ,sb-vm:n-machine-word-bits nil))) + (csubtypep count-type + (specifier-type '(and unsigned-byte fixnum)))) + (cut-to-width integer ,kind width ,signedp) + ',left-name) + #+(or arm64 x86-64) + ((and (not (constant-lvar-p count)) + (csubtypep count-type (specifier-type 'fixnum)) + ;; Unknown sign + (not (csubtypep count-type (specifier-type '(integer * 0)))) + (not (csubtypep count-type (specifier-type '(integer 0 *)))) + (or (csubtypep integer-type (specifier-type `(unsigned-byte ,sb-vm:n-word-bits))) + (csubtypep integer-type (specifier-type `(signed-byte ,sb-vm:n-word-bits))))) + ',name))))) + (setf (gethash ',left-name (modular-class-versions (find-modular-class ',kind ',signedp))) + `(ash ,',width)) + (deftransform ,left-name ((integer count) (t (constant-arg (eql 0)))) + 'integer) + #+(or arm64 x86-64) + (progn + (defknown ,name (integer integer) (,type ,width) + (foldable flushable movable) + :derive-type (make-modular-fun-type-deriver 'ash ',width ',signedp)) + (setf (gethash ',name (modular-class-versions (find-modular-class ',kind ',signedp))) + `(ash ,',width)) + ;; Go back to ASH if the sign becomes known + (flet ((cut (x) + (if ,signedp + `(mask-signed-field ,',width ,x) + `(logand ,x (ldb (byte ,',width 0) -1))))) + (deftransform ,name ((integer count) (t (integer * 0)) * :important nil) + `,(cut '(ash integer count))) + (deftransform ,name ((integer count) (t (integer 0 *)) * :important nil) + `(,',left-name ,(cut 'integer) count)))))))) + #+(or x86 x86-64 arm arm64) + (def sb-vm::ash-left-modfx sb-vm::ash-modfx :tagged #.sb-vm:n-fixnum-bits t) + (def #.(intern (format nil "ASH-LEFT-MOD~D" sb-vm:n-machine-word-bits) "SB-VM") + #.(intern (format nil "ASH-MOD~D" sb-vm:n-machine-word-bits) "SB-VM") + :untagged #.sb-vm:n-machine-word-bits nil)) + diff --git a/src/compiler/node.lisp b/src/compiler/node.lisp index 03433f4ecd..60c28e7089 100644 --- a/src/compiler/node.lisp +++ b/src/compiler/node.lisp @@ -12,13 +12,130 @@ (in-package "SB-C") -;;; The front-end data structure (IR1) is composed of nodes, -;;; representing actual evaluations. Linear sequences of nodes in -;;; control-flow order are combined into blocks (but see -;;; JOIN-SUCCESSOR-IF-POSSIBLE for precise conditions); control -;;; transfers inside a block are represented with CTRANs and between -;;; blocks -- with BLOCK-SUCC/BLOCK-PRED lists; data transfers are -;;; represented with LVARs. +(declaim (special *lexenv*)) + +;;; The LEXENV represents the lexical environment used for IR1 conversion. +;;; (This is also what shows up as an ENVIRONMENT value in macroexpansion.) +(declaim (inline internal-make-lexenv)) +(defstruct (lexenv + (:include abstract-lexenv) + (:print-function + (lambda (lexenv stream depth) + (if (null-lexenv-p lexenv) + (print-unreadable-object (lexenv stream) + (write-string "NULL-LEXENV" stream)) + (default-structure-print lexenv stream depth)))) + (:copier nil) + (:constructor make-null-lexenv ()) + (:constructor make-almost-null-lexenv + (%policy handled-conditions flushable lambda parent + &optional user-data)) + (:constructor make-package-lock-lexenv + (disabled-package-locks %policy + &aux (handled-conditions nil))) + (:constructor internal-make-lexenv + (funs vars blocks tags + type-restrictions + flushable + lambda cleanup handled-conditions + disabled-package-locks %policy user-data + parent))) + ;; an alist of (NAME . WHAT), where WHAT is either a FUNCTIONAL (a + ;; local function), a DEFINED-FUN, representing an + ;; INLINE/NOTINLINE declaration, or a list (MACRO . <function>) (a + ;; local macro, with the specifier expander). Note that NAME may be + ;; a (SETF <name>) list, not necessarily a single symbol. + (funs nil :type list) + ;; an alist translating variable names to LEAF structures. A special + ;; binding is indicated by a :SPECIAL GLOBAL-VAR leaf. Each special + ;; binding within the code gets a distinct leaf structure, as does + ;; the current "global" value on entry to the code compiled. + ;; (locally (special ...)) is handled by adding the most recent + ;; special binding to the front of the list. + ;; + ;; If the CDR is (MACRO . <exp>), then <exp> is the expansion of a + ;; symbol macro. + (vars nil :type list) + ;; BLOCKS and TAGS are alists from block and go-tag names to 2-lists + ;; of the form (<entry> <continuation>), where <continuation> is the + ;; continuation to exit to, and <entry> is the corresponding ENTRY + ;; node. + (blocks nil :type list) + (tags nil :type list) + ;; an alist (THING . CTYPE) which is used to keep track of + ;; "pervasive" type declarations. When THING is a leaf, this is for + ;; type declarations that pertain to the type in a syntactic extent + ;; which does not correspond to a binding of the affected name. + (type-restrictions nil :type list) + ;; the lexically enclosing lambda, if any + (lambda nil :type (or clambda null)) + ;; the lexically enclosing cleanup, or NIL if none enclosing within LAMBDA + (cleanup nil :type (or cleanup null)) + ;; condition types we handle with a handler around the compiler + (handled-conditions *handled-conditions*) + ;; lexically disabled package locks (list of symbols) + (disabled-package-locks *disabled-package-locks*) + ;; the current OPTIMIZE policy. this is null in the null environment, + ;; and the global policy is stored in *POLICY*. (Because we want to + ;; be able to affect it from :WITH-COMPILATION-UNIT.) NIL here also + ;; works as a convenient null-lexenv identifier. + (%policy nil :type (or null policy)) + ;; A list associating extra user info to symbols. The entries + ;; are of the form (:declare name . value), + ;; (:variable name key . value), or (:function name key . value) + (user-data nil :type list) + (parent nil) + ;; Cache of all visible variables, including the ones coming from + ;; (call-lexenv lambda) + ;; Used for LEAF-VISIBLE-TO-DEBUGGER-P + (var-cache nil :type (or null hash-table)) + ;; A list of functions that can be removed when unused. + ;; Similar to the FLUSHABLE attribute in DEFKNOWN, but can applied + ;; locally to things that are generally not flushable but can be + ;; flushed in some circumstances. + (flushable nil :type list)) + +(defun lexenv-policy (lexenv) + (or (lexenv-%policy lexenv) *policy*)) + +(defun null-lexenv-p (lexenv) + (not (lexenv-%policy lexenv))) + +;;; an object suitable for input to standard functions that accept +;;; "environment objects" (of the ANSI glossary) +(def!type lexenv-designator () '(or abstract-lexenv null)) + +;;; support for the idiom (in MACROEXPAND and elsewhere) that NIL is +;;; to be taken as a null lexical environment. +;;; Of course this is a mostly pointless "idiom" because NIL *is* +;;; an environment, as far as most environment inquiry functions care. +(defun coerce-to-lexenv (x) + (etypecase x + (null (make-null-lexenv)) + (lexenv x) + #+(and sb-fasteval (not sb-xc-host)) + (sb-interpreter:basic-env (sb-interpreter:lexenv-from-env x)))) + +;;; The front-end data structure (IR1) is composed of nodes and +;;; continuations. The general idea is that continuations contain +;;; top-down information and nodes contain bottom-up, derived +;;; information. A continuation represents a place in the code, while +;;; a node represents code that does something. +;;; +;;; This representation is more of a flow-graph than an augmented +;;; syntax tree. The evaluation order is explicitly represented in the +;;; linkage by continuations, rather than being implicit in the nodes +;;; which receive the the results of evaluation. This allows us to +;;; decouple the flow of results from the flow of control. A +;;; continuation represents both, but the continuation can represent +;;; the case of a discarded result by having no DEST. + +;;; Note: Continuations have been split into CTRANs and LVARs. Control +;;; transfers inside a block are represented with CTRANs; data +;;; transfers are represented with LVARs. However, many of the +;;; comments and names have not been updated to reflect this, and it +;;; is easy to find references to the old way of doing things with +;;; continuations throughout the compiler. ;;; "Lead-in" Control TRANsfer [to some node] (defstruct (ctran (:constructor make-ctran) (:copier nil)) @@ -48,8 +165,9 @@ ;; the basic block this continuation is in. This is null only in ;; :UNUSED continuations. (block nil :type (or cblock null)) - ;; Entries created by the BLOCK special operator - (entries nil :type list)) + ;; Use for reporting notes for the following node, + ;; which can be transformed and lose its original source code. + (source-path nil :type list)) (defmethod print-object ((x ctran) stream) (print-unreadable-object (x stream :type t :identity t) @@ -81,6 +199,7 @@ (dependent-nodes nil) (annotations nil) (dependent-annotations nil)) +(!set-load-form-method lvar (:xc :target) :ignore-it) ;;; These are used for annotating a LVAR with information that can't ;;; be expressed using types or if the CAST semantics are undesirable @@ -128,6 +247,10 @@ (result-specs nil :type list) type) +(defstruct (lvar-sequence-bounds-annotation + (:include lvar-dependent-annotation) + (:copier nil))) + (defstruct (lvar-type-annotation (:include lvar-annotation) (:copier nil)) @@ -138,21 +261,26 @@ (:include lvar-type-annotation) (:copier nil))) +(defstruct (lvar-lambda-var-annotation + (:include lvar-annotation) + (:copier nil)) + lambda-var) + (defmethod print-object ((x lvar) stream) (print-unreadable-object (x stream :type t :identity t) (when (boundp '*compilation*) (format stream "~D" (cont-num x))))) -#-sb-fluid (declaim (inline lvar-has-single-use-p)) +(declaim (inline lvar-has-single-use-p)) (defun lvar-has-single-use-p (lvar) (typep (lvar-uses lvar) '(not list))) ;;; Return the unique node, delivering a value to LVAR. -#-sb-fluid (declaim (inline lvar-use)) +(declaim (inline lvar-use)) (defun lvar-use (lvar) (the (not list) (lvar-uses lvar))) -#-sb-fluid (declaim (inline lvar-derived-type)) +(declaim (inline lvar-derived-type)) (defun lvar-derived-type (lvar) (declare (type lvar lvar)) (or (lvar-%derived-type lvar) @@ -202,16 +330,16 @@ ;; top level form containing the original source. (source-path *current-path* :type list) ;; If this node is in a tail-recursive position, then this is set to - ;; T. At the end of IR1 (in physical environment analysis) this is - ;; computed for all nodes (after cleanup code has been emitted). - ;; Before then, a non-null value indicates that IR1 optimization has + ;; T. At the end of IR1 (in environment analysis) this is computed + ;; for all nodes (after cleanup code has been emitted). Before + ;; then, a non-null value indicates that IR1 optimization has ;; converted a tail local call to a direct transfer. ;; ;; If the back-end breaks tail-recursion for some reason, then it ;; can null out this slot. (tail-p nil :type boolean)) -#-sb-fluid (declaim (inline node-block)) +(declaim (inline node-block)) (defun node-block (node) (ctran-block (node-prev node))) @@ -234,7 +362,7 @@ ;; the value is unused. (lvar nil :type (or lvar null))) -#-sb-fluid (declaim (inline node-dest)) +(declaim (inline node-dest)) (defun node-dest (node) (awhen (node-lvar node) (lvar-dest it))) @@ -323,13 +451,13 @@ (:copier nil) (:conc-name block-) (:predicate block-p)) - ;; a list of all the blocks that are predecessors/successors of this - ;; block. In well-formed IR1, most blocks will have one successor. - ;; The only exceptions are: - ;; 1. component head blocks (any number) - ;; 2. blocks ending in an IF (1 or 2) - ;; 3. blocks with DELETE-P set (zero) - (pred nil :type list) + ;; a list of all the blocks that are predecessors/successors of this + ;; block. In well-formed IR1, most blocks will have one successor. + ;; The only exceptions are: + ;; 1. component head blocks (any number) + ;; 2. blocks ending in an IF (1 or 2) + ;; 3. blocks with DELETE-P set (zero) + (pred nil :type list) (succ nil :type list) ;; the ctran which heads this block (a :BLOCK-START), or NIL when we ;; haven't made the start ctran yet (and in the dummy component head @@ -375,9 +503,9 @@ ;; what macroexpansions and source transforms happened "in" this block, used ;; for xref (xrefs nil :type list) - ;; Cache the physenv of a block during lifetime analysis. :NONE if - ;; no cached value has been stored yet. - (physenv-cache :none :type (or null physenv (member :none)))) + ;; Cache the environment of a block during lifetime analysis. :NONE + ;; if no cached value has been stored yet. + (environment-cache :none :type (or null environment (member :none)))) (defmethod print-object ((cblock cblock) stream) (if (boundp '*compilation*) (print-unreadable-object (cblock stream :type t :identity t) @@ -456,9 +584,9 @@ ;; Entry/exit points have these blocks as their ;; predecessors/successors. The start and return from each ;; non-deleted function is linked to the component head and - ;; tail. Until physical environment analysis links NLX entry stubs - ;; to the component head, every successor of the head is a function - ;; start (i.e. begins with a BIND node.) + ;; tail. Until environment analysis links NLX entry stubs to the + ;; component head, every successor of the head is a function start + ;; (i.e. begins with a BIND node.) (head (missing-arg) :type cblock) (tail (missing-arg) :type cblock) ;; New blocks are inserted before this. @@ -509,13 +637,13 @@ ;; from COMPONENT-LAMBDAS. (reanalyze-functionals nil :type list) (delete-blocks nil :type list) - (nlx-info-generated-p nil :type boolean) - ;; this is filled by physical environment analysis + ;; this is filled by environment analysis (dx-lvars nil :type list) ;; The default LOOP in the component. (outer-loop (missing-arg) :type cloop) - ;; The current sset index - (sset-number 0 :type fixnum)) + (max-block-number 0 :type fixnum) + (dominators-computed nil)) + (defprinter (component :identity t) name (reanalyze :test reanalyze)) @@ -562,62 +690,37 @@ (mess-up nil :type (or node null)) ;; For all kinds, except :DYNAMIC-EXTENT: a list of all the NLX-INFO ;; structures whose NLX-INFO-CLEANUP is this cleanup. This is filled - ;; in by physical environment analysis. + ;; in by environment analysis. ;; ;; For :DYNAMIC-EXTENT: a list of all DX LVARs, preserved by this ;; cleanup. This is filled when the cleanup is created (now by - ;; locall call analysis) and is rechecked by physical environment - ;; analysis. (For closures this is a list of the allocating node - - ;; during IR1, and a list of the argument LVAR of the allocator - - ;; after physical environment analysis.) - (info nil :type list) - ;; Used by propagate-ref-dx to check that the new ref is inside the - ;; original let - (lexenv nil :type (or null lexenv))) + ;; locall call analysis) and is rechecked by environment + ;; analysis. (For closures this is a list of the LVAR of the enclose + ;; after environment analysis.) + (nlx-info nil :type list)) (defprinter (cleanup :identity t) kind mess-up - (info :test info)) + (nlx-info :test nlx-info)) -;;; A PHYSENV represents the result of physical environment analysis. -;;; -;;; As far as I can tell from reverse engineering, this IR1 structure -;;; represents the physical environment (which is probably not the -;;; standard Lispy term for this concept, but I dunno what is the -;;; standard term): those things in the lexical environment which a -;;; LAMBDA actually interacts with. Thus in -;;; (DEFUN FROB-THINGS (THINGS) -;;; (DOLIST (THING THINGS) -;;; (BLOCK FROBBING-ONE-THING -;;; (MAPCAR (LAMBDA (PATTERN) -;;; (WHEN (FITS-P THING PATTERN) -;;; (RETURN-FROM FROB-THINGS (LIST :FIT THING PATTERN)))) -;;; *PATTERNS*)))) -;;; the variables THINGS, THING, and PATTERN and the block names -;;; FROB-THINGS and FROBBING-ONE-THING are all in the inner LAMBDA's -;;; lexical environment, but of those only THING, PATTERN, and -;;; FROB-THINGS are in its physical environment. In IR1, we largely -;;; just collect the names of these things; in IR2 an IR2-PHYSENV -;;; structure is attached to INFO and used to keep track of -;;; associations between these names and less-abstract things (like -;;; TNs, or eventually stack slots and registers). -- WHN 2001-09-29 -(defstruct (physenv (:copier nil)) - ;; the function that allocates this physical environment +;;; The ENVIRONMENT structure represents the result of environment analysis. +(defstruct (environment (:copier nil)) + ;; the function that allocates this environment (lambda (missing-arg) :type clambda :read-only t) ;; This ultimately converges to a list of all the LAMBDA-VARs and ;; NLX-INFOs needed from enclosing environments by code in this - ;; physical environment. In the meantime, it may be + ;; environment. In the meantime, it may be ;; * NIL at object creation time ;; * a superset of the correct result, generated somewhat later ;; * smaller and smaller sets converging to the correct result as ;; we notice and delete unused elements in the superset (closure nil :type list) ;; a list of NLX-INFO structures describing all the non-local exits - ;; into this physical environment + ;; into this environment (nlx-info nil :type list) ;; some kind of info used by the back end (info nil)) -(defprinter (physenv :identity t) +(defprinter (environment :identity t) lambda (closure :test closure) (nlx-info :test nlx-info)) @@ -652,11 +755,10 @@ ;;; An NLX-INFO structure is used to collect various information about ;;; non-local exits. This is effectively an annotation on the ;;; continuation, although it is accessed by searching in the -;;; PHYSENV-NLX-INFO. +;;; ENVIRONMENT-NLX-INFO. (defstruct (nlx-info (:copier nil) - (:constructor make-nlx-info - (cleanup exit &aux (block (first (block-succ (node-block exit))))))) + (:constructor make-nlx-info (cleanup block))) ;; the cleanup associated with this exit. In a catch or ;; unwind-protect, this is the :CATCH or :UNWIND-PROTECT cleanup, ;; and not the cleanup for the escape block. The CLEANUP-KIND of @@ -665,7 +767,7 @@ (cleanup (missing-arg) :type cleanup) ;; the ``continuation'' exited to (the block, succeeding the EXIT ;; nodes). If this exit is from an escape function (CATCH or - ;; UNWIND-PROTECT), then physical environment analysis deletes the + ;; UNWIND-PROTECT), then environment analysis deletes the ;; escape function and instead has the %NLX-ENTRY use this ;; continuation. ;; @@ -674,9 +776,9 @@ ;; ENTRY must also be used to disambiguate, since exits to different ;; places may deliver their result to the same continuation. (block (missing-arg) :type cblock) - ;; the entry stub inserted by physical environment analysis. This is - ;; a block containing a call to the %NLX-ENTRY funny function that - ;; has the original exit destination as its successor. Null only + ;; the entry stub inserted by environment analysis. This is a block + ;; containing a call to the %NLX-ENTRY funny function that has the + ;; original exit destination as its successor. Null only ;; temporarily. (target nil :type (or cblock null)) ;; for a lexical exit it determines whether tag existence check is @@ -688,6 +790,8 @@ block target info) +(!set-load-form-method nlx-info (:xc :target) :ignore-it) + ;;;; LEAF structures @@ -740,13 +844,17 @@ (where-from :assumed :type (member :declared :assumed :defined-here :defined :defined-method)) ;; list of the REF nodes for this leaf (refs () :type list) - ;; true if there was ever a REF or SET node for this leaf. This may - ;; be true when REFS and SETS are null, since code can be deleted. - (ever-used nil :type boolean) + ;; For tracking whether to warn about unused variables: + ;; NIL if there was never a REF or SET. + ;; SET if there was a set but no REF. + ;; T if there was a REF. + ;; This may be non-nil when REFS and SETS are null, since code can be deleted. + (ever-used nil :type (member nil set t)) ;; is it declared dynamic-extent, or truly-dynamic-extent? (extent nil :type (member nil truly-dynamic-extent dynamic-extent indefinite-extent)) ;; some kind of info used by the back end (info nil)) +(!set-load-form-method leaf (:xc :target) :ignore-it) (defun leaf-dynamic-extent (leaf) (let ((extent (leaf-extent leaf))) @@ -762,20 +870,21 @@ (leaf-%source-name leaf)) ;;; The CONSTANT structure is used to represent known constant values. -;;; Since the same constant leaf may be shared between named and anonymous -;;; constants, %SOURCE-NAME is never used. +;;; If NAME is not null, then it is the name of the named constant +;;; which this leaf corresponds to, otherwise this is an anonymous +;;; constant. (defstruct (constant (:constructor make-constant (value &optional (type (ctype-of value)) - &aux (%source-name '.anonymous.) + &aux (where-from :defined))) (:copier nil) (:include leaf)) ;; the value of the constant (value (missing-arg) :type t)) (defprinter (constant :identity t) - value) + value (%source-name :test (neq %source-name '.anonymous.))) ;;; The BASIC-VAR structure represents information common to all ;;; variables which don't correspond to known local functions. @@ -831,16 +940,20 @@ ;; global environment. (inlinep nil :type inlinep) (inline-expansion nil :type (or cons null)) - ;; List of functionals corresponding to this DEFINED-FUN: either from the - ;; conversion of a NAMED-LAMBDA, or from inline-expansion (see - ;; RECOGNIZE-KNOWN-CALL) - we need separate functionals for each policy in - ;; which the function is used. - (functionals nil :type list) - (named-lambda-p nil)) + ;; Was the function defined in this compilation block? + (same-block-p nil :type boolean) + ;; The block-local definition of this function (either because it + ;; was semi-inline, or because it was defined in this block). If + ;; this function is not an entry point, then this may be deleted or + ;; LET-converted. NULL if we haven't converted the expansion yet. + ;; Note: We need separate functionals for each policy in which + ;; the function is used. + (functionals nil :type list)) (defprinter (defined-fun :identity t :pretty-ir-printer (pretty-print-global-var structure stream)) %source-name inlinep + same-block-p (functionals :test functionals)) ;;;; function stuff @@ -906,8 +1019,8 @@ ;; ;; :ASSIGNMENT ;; similar to a LET (as per FUNCTIONAL-SOMEWHAT-LETLIKE-P), but - ;; can have other than one call as long as there is at most - ;; one non-tail call. + ;; can have more than one call as long as the calls all return to + ;; the same place. ;; ;; :OPTIONAL ;; a lambda that is an entry point for an OPTIONAL-DISPATCH. @@ -981,15 +1094,15 @@ ;; INLINEP will always be NIL as well.) (inline-expansion nil :type list) ;; the lexical environment that the INLINE-EXPANSION should be converted in - (lexenv *lexenv* :type lexenv :read-only t) + (lexenv *lexenv* :type lexenv) ;; the original function or macro lambda list, or :UNSPECIFIED if ;; this is a compiler created function (arg-documentation nil :type (or list (member :unspecified))) ;; the documentation string for the lambda (documentation nil :type (or null string)) - ;; Node, allocating closure for this lambda. May be NIL when we are - ;; sure that no closure is needed. - (allocator nil :type (or null combination)) + ;; the enclose node allocating the closure for this lambda. May be + ;; NIL when we are sure that no closure is needed. + (enclose nil :type (or null enclose)) ;; various rare miscellaneous info that drives code generation & stuff (plist () :type list) ;; xref information for this functional (only used for functions with an @@ -998,8 +1111,6 @@ ;; True if this functional was created from an inline expansion. This ;; is either T, or the GLOBAL-VAR for which it is an expansion. (inline-expanded nil) - ;; Is it coming from a top-level NAMED-LAMBDA? - (top-level-defun-p nil) (ignore nil)) (defun pretty-print-functional (functional stream) @@ -1114,9 +1225,9 @@ (tail-set nil :type (or tail-set null)) ;; the structure which represents the phsical environment that this ;; function's variables are allocated in. This is filled in by - ;; physical environment analysis. In a LET, this is EQ to our home's - ;; physical environment. - (physenv nil :type (or physenv null)) + ;; environment analysis. In a LET, this is EQ to our home's + ;; environment. + (environment nil :type (or environment null)) ;; In a LET, this is the NODE-LEXENV of the combination node. We ;; retain it so that if the LET is deleted (due to a lack of vars), ;; we will still have caller's lexenv to figure out which cleanup is @@ -1249,6 +1360,7 @@ ;; For &REST arguments this may contain information about more context ;; the rest list comes from. (default nil :type t) + (default-p nil :type boolean) ;; the actual key for a &KEY argument. Note that in ANSI CL this is ;; not necessarily a keyword: (DEFUN FOO (&KEY ((BAR BAR))) ...). (key nil :type symbol)) @@ -1264,29 +1376,31 @@ ;;; lambda arguments which may ultimately turn out not to be simple ;;; and lexical. ;;; -;;; LAMBDA-VARs with no REFs are considered to be deleted; physical -;;; environment analysis isn't done on these variables, so the back -;;; end must check for and ignore unreferenced variables. Note that a -;;; deleted LAMBDA-VAR may have sets; in this case the back end is -;;; still responsible for propagating the SET-VALUE to the set's CONT. +;;; LAMBDA-VARs with no REFs are considered to be deleted; environment +;;; analysis isn't done on these variables, so the back end must check +;;; for and ignore unreferenced variables. Note that a deleted +;;; LAMBDA-VAR may have sets; in this case the back end is still +;;; responsible for propagating the SET-VALUE to the set's CONT. (!def-boolean-attribute lambda-var ;; true if this variable has been declared IGNORE ignore - ;; This is set by physical environment analysis if it chooses an - ;; indirect (value cell) representation for this variable because it - ;; is both set and closed over. + ;; This is set by environment analysis if it chooses an indirect + ;; (value cell) representation for this variable because it is both + ;; set and closed over. indirect ;; true if the last reference has been deleted (and new references ;; should not be made) deleted - ;; This is set by physical environment analysis if, should it be an - ;; indirect lambda-var, an actual value cell object must be - ;; allocated for this variable because one or more of the closures - ;; that refer to it are not dynamic-extent. Note that both - ;; attributes must be set for the value-cell object to be created. + ;; This is set by environment analysis if, should it be an indirect + ;; lambda-var, an actual value cell object must be allocated for + ;; this variable because one or more of the closures that refer to + ;; it are not dynamic-extent. Note that both attributes must be set + ;; for the value-cell object to be created. explicit-value-cell ;; Do not propagate constraints for this var - no-constraints) + no-constraints + ;; Does it hold a constant that should't be destructively modified + constant) (defstruct (lambda-var (:include basic-var) (:copier nil)) (flags (lambda-var-attributes) @@ -1318,9 +1432,6 @@ (private-constraints nil :type (or null (array t 1))) (equality-constraints nil :type (or null (array t 1))) - ;; The FOP handle of the lexical variable represented by LAMBDA-VAR - ;; in the fopcompiler. - (fop-value nil) source-form) (defprinter (lambda-var :identity t) %source-name @@ -1341,6 +1452,9 @@ `(lambda-var-attributep (lambda-var-flags ,var) explicit-value-cell)) (defmacro lambda-var-no-constraints (var) `(lambda-var-attributep (lambda-var-flags ,var) no-constraints)) +(defmacro lambda-var-constant (var) + `(lambda-var-attributep (lambda-var-flags ,var) constant)) + ;;;; basic node types @@ -1416,8 +1530,8 @@ (defstruct (basic-combination (:include valued-node) (:constructor nil) (:copier nil)) - ;; LVAR for the function - (fun (missing-arg) :type lvar) + ;; LVAR for the function + (fun (missing-arg) :type lvar) ;; list of LVARs for the args. In a local call, an argument lvar may ;; be replaced with NIL to indicate that the corresponding variable ;; is unreferenced, and thus no argument value need be passed. @@ -1438,7 +1552,7 @@ ;; Untrusted type we have asserted for this combination. (type-validated-for-leaf nil) ;; some kind of information attached to this node by the back end - ;; or by CHECK-IMPORTANT-RESULT + ;; or by CHECK-IMPORTANT-RESULT, or by anything else that may need to. (info nil) (step-info nil) ;; A plist of inline expansions @@ -1449,7 +1563,8 @@ ;;; an MV-COMBINATION isn't COMBINATION-P. (defstruct (combination (:include basic-combination) (:constructor make-combination (fun)) - (:copier nil))) + (:copier nil)) + (pass-nargs t :type boolean)) (defprinter (combination :identity t) (fun :prin1 (lvar-uses fun)) (args :prin1 (mapcar (lambda (x) @@ -1533,12 +1648,16 @@ asserted-type type-to-check) -;;; A filter to help order the value semantics of MULTIPLE-VALUE-PROG1 -(defstruct (vestigial-exit-cast (:include cast - (%type-check nil) - (asserted-type *wild-type*) - (type-to-check *wild-type*)) - (:copier nil))) +;;; The DELAY node is interposed between a VALUE's USE and its DEST in +;;; order to allow the value to be immediately used. This is necessary +;;; for implementing multiple-use unknown values LVARs, as otherwise, +;;; a non-moveable dynamic extent object may be allocated between the +;;; DEST and one of the LVAR's uses but not the others. +(defstruct (delay (:include cast + (%type-check nil) + (asserted-type *wild-type*) + (type-to-check *wild-type*)) + (:copier nil))) ;;; A cast that always follows %check-bound and they are deleted together. ;;; Created via BOUND-CAST ir1-translator by chaining it together with %check-bound. @@ -1580,8 +1699,8 @@ ;;; continuation and the exit continuation's DEST. Instead of using ;;; the returned value being delivered directly to the exit ;;; continuation, it is delivered to our VALUE lvar. The original exit -;;; lvar is the exit node's LVAR; physenv analysis also makes it the -;;; lvar of %NLX-ENTRY call. +;;; lvar is the exit node's LVAR; environment analysis also makes it +;;; the lvar of %NLX-ENTRY call. (defstruct (exit (:include valued-node) (:copier nil)) ;; the ENTRY node that this is an exit for. If null, this is a @@ -1597,8 +1716,45 @@ (entry :test entry) (value :test value)) -(defstruct (no-op (:include node) - (:copier nil))) +;;; The ENCLOSE node marks the place at which closure allocation code +;;; would be emitted, if necessary. +(defstruct (enclose (:include valued-node) ; this node uses a dummy lvar for dx analysis + (:copier nil)) + ;; the list of functionals that this ENCLOSE node allocates. + (funs nil :type list)) +(defprinter (enclose :identity t) + funs) + + +;;;; miscellaneous IR1 structures + +(defstruct (undefined-warning + (:print-object (lambda (x s) + (print-unreadable-object (x s :type t) + (prin1 (undefined-warning-name x) s)))) + (:copier nil)) + ;; the name of the unknown thing + (name nil :type (or symbol list)) + ;; the kind of reference to NAME + (kind (missing-arg) :type (member :function :type :variable)) + ;; the number of times this thing was used + (count 0 :type unsigned-byte) + ;; a list of COMPILER-ERROR-CONTEXT structures describing places + ;; where this thing was used. Note that we only record the first + ;; *UNDEFINED-WARNING-LIMIT* calls. + (warnings () :type list)) + +(declaim (freeze-type undefined-warning)) + +(defstruct (argument-mismatch-warning + (:print-object (lambda (x s) + (print-unreadable-object (x s :type t) + (prin1 (argument-mismatch-warning-name x) s)))) + (:copier nil)) + (name nil :type (or symbol list)) + ;; a list of (KEYS . COMPILER-ERROR-CONTEXT) + (warnings () :type list)) + ;;; a helper for the POLICY macro, defined late here so that the ;;; various type tests can be inlined @@ -1627,6 +1783,5 @@ ;;;; Freeze some structure types to speed type testing. -#-sb-fluid (declaim (freeze-type node lexenv ctran lvar cblock component cleanup - physenv tail-set nlx-info leaf)) + environment tail-set nlx-info leaf)) diff --git a/src/compiler/pack-iterative.lisp b/src/compiler/pack-iterative.lisp index a8f22c9a1c..dc56773861 100644 --- a/src/compiler/pack-iterative.lisp +++ b/src/compiler/pack-iterative.lisp @@ -65,7 +65,7 @@ ;; vertex, taking into account reserve locations and preallocated ;; TNs. (initial-domain 0 :type sc-locations) - (initial-domain-size 0 :type #.`(integer 0 ,sb-vm:finite-sc-offset-limit)) + (initial-domain-size 0 :type (integer 0 #.sb-vm:finite-sc-offset-limit)) ;; TN this is a vertex for. (tn nil :type tn :read-only t) (element-size nil :type (integer 1 8) :read-only t) diff --git a/src/compiler/pack.lisp b/src/compiler/pack.lisp index d19ad9b527..fece7c8fb0 100644 --- a/src/compiler/pack.lisp +++ b/src/compiler/pack.lisp @@ -17,8 +17,6 @@ ;;; attempt (defvar *pack-assign-costs* t) (defvar *pack-optimize-saves* t) -;;; FIXME: Perhaps SB-FLUID should be renamed to SB-TWEAK and these -;;; should be made conditional on SB-TWEAK. (declaim (ftype (function (component) index) ir2-block-count)) @@ -323,7 +321,7 @@ (let* ((vop (tn-ref-vop op)) (args (vop-args vop)) (results (vop-results vop)) - (name (with-simple-output-to-string (stream) + (name (%with-output-to-string (stream) (print-tn-guts tn stream))) (2comp (component-info *component-being-compiled*)) temp) @@ -340,9 +338,7 @@ ((setq temp (position-in #'tn-ref-across tn (vop-temps vop) :key #'tn-ref-tn)) `("~2D: ~A (temporary ~A)" ,loc ,name - ,(operand-parse-name (elt (vop-parse-temps - (vop-parse-or-lose - (vop-info-name (vop-info vop)))) + ,(operand-parse-name (elt (vop-parse-temps (vop-parse-or-lose (vop-name vop))) temp)))) ((eq (tn-kind tn) :component) `("~2D: ~A (component live)" ,loc ,name)) @@ -391,7 +387,7 @@ time. Recompile.~%Compilation order may be incorrect.~]" (mapcar #'sc-name scs) n arg-p - (vop-info-name (vop-info (tn-ref-vop op))) + (vop-name (tn-ref-vop op)) (unused) (used) incon)))) @@ -420,7 +416,6 @@ ;;;; register saving -#-sb-devel (declaim (start-block optimized-emit-saves emit-saves assign-tn-costs pack-save-tn)) @@ -471,7 +466,7 @@ (aver (eq (ir2-block-block block) (ir2-block-block (vop-block vop)))) (do ((current last (vop-prev current))) ((null current)) - (when (eq (vop-info-name (vop-info current)) name) + (when (eq (vop-name current) name) (return-from reverse-find-vop current))))) ;;; For TNs that have other than one writer, we save the TN before @@ -490,11 +485,14 @@ (when (eq (tn-kind save) :specified-save) (setf (tn-kind save) :save)) (aver (eq (tn-kind save) :save)) - (emit-operand-load node block tn save - (if (eq (vop-info-move-args (vop-info vop)) - :local-call) - (reverse-find-vop 'allocate-frame vop) - vop)) + (multiple-value-bind (before block) + (if (eq (vop-info-move-args (vop-info vop)) :local-call) + (let ((before (reverse-find-vop 'allocate-frame vop))) + ;; Because of SPLIT-IR2-BLOCKS the ALLOCATE-FRAME VOP + ;; may be in a different block. + (values before (vop-block before))) + (values vop block)) + (emit-operand-load node block tn save before)) (emit-operand-load node block save tn next))) ;;; Return a VOP after which is an OK place to save the value of TN. @@ -522,8 +520,7 @@ (return nil)))) (tn-ref-vop res))) - (unless (eq (vop-info-name (vop-info (tn-ref-vop write))) - 'move-operand) + (unless (eq (vop-name (tn-ref-vop write)) 'move-operand) (when res (return nil)) (setq res write)))) @@ -554,14 +551,26 @@ ;;; appropriate. This is also called by SPILL-AND-PACK-LOAD-TN. (defun basic-save-tn (tn vop) (declare (type tn tn) (type vop vop)) - (let ((save (tn-save-tn tn))) - (cond ((and save (eq (tn-kind save) :save-once)) - (restore-single-writer-tn tn vop)) - ((save-single-writer-tn tn) - (restore-single-writer-tn tn vop)) - (t - (save-complex-writer-tn tn vop)))) - (values)) + (let* ((save (tn-save-tn tn)) + (node (vop-node vop))) + (flet ((restore () + (not + (and (sb-c::combination-p node) + ;; Don't restore if the function doesn't return. + (let ((type (sb-c::lvar-fun-type (sb-c::combination-fun node)))) + (and (fun-type-p type) + (eq (sb-kernel:fun-type-returns type) *empty-type*))) + (or + (sb-c::combination-fun-info node) + (policy node (zerop safety))))))) + (cond ((and save (eq (tn-kind save) :save-once)) + (when (restore) + (restore-single-writer-tn tn vop))) + ((save-single-writer-tn tn) + (when (restore) + (restore-single-writer-tn tn vop))) + (t + (save-complex-writer-tn tn vop)))))) ;;; Scan over the VOPs in BLOCK, emiting saving code for TNs noted in ;;; the codegen info that are packed into saved SCs. @@ -662,7 +671,7 @@ (do ((vop (ir2-block-last-vop block) (vop-prev vop))) ((null vop)) (let ((info (vop-info vop))) - (case (vop-info-name info) + (case (vop-name vop) (allocate-frame (aver skipping) (setq skipping nil)) @@ -833,18 +842,17 @@ (declaim (end-block)) ;; Misc. utilities -(declaim (inline unbounded-sc-p)) +(declaim (maybe-inline unbounded-sc-p)) (defun unbounded-sc-p (sc) (eq (sb-kind (sc-sb sc)) :unbounded)) (defun unbounded-tn-p (tn) + #-sb-xc-host (declare (inline unbounded-sc-p)) (unbounded-sc-p (tn-sc tn))) -(declaim (notinline unbounded-sc-p)) ;;;; load TN packing -#-sb-devel (declaim (start-block pack-load-tns load-tn-conflicts-in-sc)) ;;; These variables indicate the last location at which we computed @@ -1093,7 +1101,7 @@ (do ((ref refs (tn-ref-next ref))) ((null ref)) (let ((vop (tn-ref-vop ref))) - (if (eq (vop-info-name (vop-info vop)) 'move-operand) + (if (eq (vop-name vop) 'move-operand) (delete-vop vop) (pushnew (vop-block vop) *repack-blocks*)))))) (zot (tn-reads tn)) @@ -1203,7 +1211,7 @@ ;;; the restriction, we pack a Load-TN and load the operand into it. ;;; If a load-tn has already been allocated, we can assume that the ;;; restriction is satisfied. -#-sb-fluid (declaim (inline check-operand-restrictions)) +(declaim (inline check-operand-restrictions)) (defun check-operand-restrictions (scs ops) (declare (list scs) (type (or tn-ref null) ops)) @@ -1214,7 +1222,8 @@ (let ((target (tn-ref-target op)) (tn (tn-ref-tn op))) (when (and target - (not (eq (tn-kind tn) :unused))) + (not (eq (tn-kind tn) :unused)) + (tn-primitive-type tn)) (let* ((load-tn (tn-ref-load-tn op)) (load-scs (svref (car scs) (sc-number @@ -1231,7 +1240,8 @@ (let ((target (tn-ref-target op)) (tn (tn-ref-tn op))) (unless (or target - (eq (tn-kind tn) :unused)) + (eq (tn-kind tn) :unused) + (not (tn-primitive-type tn))) (let* ((load-tn (tn-ref-load-tn op)) (load-scs (svref (car scs) (sc-number @@ -1262,7 +1272,6 @@ ;;;; targeting -#-sb-devel (declaim (start-block pack pack-tn target-if-desirable ;; needed for pack-iterative pack-wired-tn)) @@ -1345,7 +1354,7 @@ &rest keys &key limit reads writes) &body body) (declare (ignore limit reads writes)) - (let ((callback (sb-xc:gensym "CALLBACK"))) + (let ((callback (gensym "CALLBACK"))) `(flet ((,callback (,target-variable) ,@body)) (declare (dynamic-extent #',callback)) @@ -1482,43 +1491,29 @@ ;; For non-x86 ports the presence of a save-tn associated with a ;; tn is used to identify the old-fp and return-pc tns. It depends ;; on the old-fp and return-pc being passed in registers. - #-fp-and-pc-standard-save - (when (and (not (eq (tn-kind tn) :specified-save)) + (when (and #-fp-and-pc-standard-save + (not (eq (tn-kind tn) :specified-save)) (conflicts-in-sc original sc offset)) - (error "~S is wired to a location that it conflicts with." tn)) + (error "~S is wired to location ~D in SC ~A of kind ~S that it conflicts with." + tn offset sc (tn-kind tn))) ;; Use the above check, but only print a verbose warning. This can ;; be helpful for debugging the x86 port. #+nil (when (and (not (eq (tn-kind tn) :specified-save)) (conflicts-in-sc original sc offset)) - (format t "~&* Pack-wired-tn possible conflict:~% ~ + (format t "~&* Pack-wired-tn possible conflict:~% ~ tn: ~S; tn-kind: ~S~% ~ sc: ~S~% ~ sb: ~S; sb-name: ~S; sb-kind: ~S~% ~ offset: ~S; end: ~S~% ~ original ~S~% ~ tn-save-tn: ~S; tn-kind of tn-save-tn: ~S~%" - tn (tn-kind tn) sc - sb (sb-name sb) (sb-kind sb) - offset end - original - (tn-save-tn tn) (tn-kind (tn-save-tn tn)))) - - ;; On the x86 ports the old-fp and return-pc are often passed on - ;; the stack so the above hack for the other ports does not always - ;; work. Here the old-fp and return-pc tns are identified by being - ;; on the stack in their standard save locations. - #+fp-and-pc-standard-save - (when (and (not (and - (= (sc-number sc) #.(sc+offset-scn old-fp-passing-offset)) - (= offset #.(sc+offset-offset old-fp-passing-offset)))) - (not (and - (= (sc-number sc) #.(sc+offset-scn return-pc-passing-offset)) - (= offset #.(sc+offset-offset return-pc-passing-offset)))) - (conflicts-in-sc original sc offset)) - (error "~S is wired to location ~D in SC ~A of kind ~S that it conflicts with." - tn offset sc (tn-kind tn))) + tn (tn-kind tn) sc + sb (sb-name sb) (sb-kind sb) + offset end + original + (tn-save-tn tn) (tn-kind (tn-save-tn tn)))) (unless (eq (sb-kind sb) :unbounded) (setf (ldb (byte 1 (truly-the sb-vm:finite-sc-offset offset)) @@ -1585,7 +1580,7 @@ (walk-tn-refs (tn-reads tn)) (walk-tn-refs (tn-writes tn)) (if (eql path t) - sb-xc:most-positive-fixnum + most-positive-fixnum (length path))))) (declaim (type (member :iterative :greedy :adaptive) diff --git a/src/compiler/parse-lambda-list.lisp b/src/compiler/parse-lambda-list.lisp index 47ab8fb7f4..3553c9c1ce 100644 --- a/src/compiler/parse-lambda-list.lisp +++ b/src/compiler/parse-lambda-list.lisp @@ -9,6 +9,8 @@ (in-package "SB-C") +(declaim (special *lexenv*)) + (eval-when (:compile-toplevel :load-toplevel :execute) (defconstant-eqx lambda-list-parser-states #(:required &optional &rest &more &key &aux &environment &whole @@ -17,7 +19,7 @@ ;; Return a bitmask representing the LIST of lambda list keywords. (defmacro lambda-list-keyword-mask (list) - (if (constantp list) + (if (cl:constantp list) ;; When invoked with a quoted constant, some flexibility ;; is allowed, in that the input may be a single symbol. (let ((val (#+sb-xc constant-form-value #-sb-xc eval list))) @@ -112,21 +114,26 @@ (probably-ll-keyword-p (arg) ;; Compiler doesn't see that the check is manually done. :-( #-sb-xc-host - (declare (optimize (sb-c::insert-array-bounds-checks 0))) + (declare (optimize (sb-c:insert-array-bounds-checks 0))) (and (symbolp arg) (let ((name (symbol-name arg))) (and (plusp (length name)) (char= (char name 0) #\&))))) (check-suspicious (kind form) (and (probably-ll-keyword-p form) - (member form sb-xc:lambda-list-keywords) + (member form lambda-list-keywords) (report-suspicious kind form))) (report-suspicious (kind what) - (style-warn-once list "suspicious ~A ~S in lambda list: ~S." + (style-warn-once list (sb-format:tokens + "suspicious ~A ~S in lambda list: ~ + ~/sb-impl:print-lambda-list/.") kind what list) nil) ; Avoid "return convention is not fixed" optimizer note (need-arg (state) - (croak "expecting variable after ~A in: ~S" state list)) + (croak (sb-format:tokens + "expecting variable after ~A in: ~ + ~/sb-impl:print-lambda-list/") + state list)) (need-symbol (x why) (unless (symbolp x) (croak "~A is not a symbol: ~S" why x))) @@ -179,7 +186,10 @@ (symbolp input)) (setf rest (list input))) (t - (croak "illegal dotted lambda list: ~S" list))) + (croak (sb-format:tokens + "illegal dotted lambda list: ~ + ~/sb-impl:print-lambda-list/") + list))) (return)) (shiftf last-arg arg (pop input)) @@ -220,7 +230,10 @@ (destructuring-bind "a destructuring lambda list") (defmethod "a specialized lambda list") (t context)))) - (croak "~A is not allowed in ~A: ~S" arg where list))) + (croak (sb-format:tokens + "~A is not allowed in ~A: ~ + ~/sb-impl:print-lambda-list/") + arg where list))) ;; &ENVIRONMENT can't intercede between &KEY,&ALLOW-OTHER-KEYS. ;; For all other cases it's as if &ENVIRONMENT were never there. @@ -235,9 +248,14 @@ ;; a better thing can be said, e.g. &WHOLE must go to the front. (cond ((logbitp to-state seen) ; Oops! Been here before. (if (= rest-bits 3) - (croak "~S and ~S are mutually exclusive: ~S" + (croak (sb-format:tokens + "~S and ~S are mutually exclusive: ~ + ~/sb-impl:print-lambda-list/") '&body '&rest list) - (croak "repeated ~S in lambda list: ~S" arg list))) + (croak (sb-format:tokens + "repeated ~S in lambda list: ~ + ~/sb-impl:print-lambda-list/") + arg list))) ((logbitp state from-states) ; valid transition (setq state to-state seen (logior seen (ash 1 state)) @@ -245,10 +263,11 @@ ((logbitp state (bits &whole &rest &more &environment)) (need-arg last-arg)) ; Variable expected. (t - (croak (if (state= to-state &whole) - "~A must appear first in a lambda list: ~S" - "misplaced ~A in lambda list: ~S") - arg list))) + (croak (sb-format:tokens + "~:[misplaced ~A in lambda list~;~ + ~A must appear first in a lambda list~]: + ~/sb-impl:print-lambda-list/") + (state= to-state &whole) arg list))) (go LOOP))) ;; Fell through, so warn if desired, and fall through some more. (unless silent (report-suspicious "variable" arg))) @@ -256,7 +275,10 @@ ;; Handle a lambda variable (when (logbitp state (bits &allow-other-keys ; Not a collecting state. :post-env :post-rest :post-more)) - (croak "expected lambda list keyword at ~S in: ~S" arg list)) + (croak (sb-format:tokens + "expected lambda list keyword at ~S in: ~ + ~/sb-impl:print-lambda-list/") + arg list)) (let ((item (list arg))) (setq tail (if tail (setf (cdr tail) item) (begin-list item)))) (when (logbitp state (bits &rest &more &whole &environment)) @@ -278,7 +300,9 @@ (style-warn-once list (make-condition '&optional-and-&key-in-lambda-list - :format-control "&OPTIONAL and &KEY found in the same lambda list: ~S" + :format-control (sb-format:tokens + "&OPTIONAL and &KEY found in the same lambda list: ~ + ~/sb-impl:print-lambda-list/") :format-arguments (list list)))) ;; For CONTEXT other than :VALUES-TYPE/:FUNCTION-TYPE we reject @@ -308,10 +332,13 @@ ;; (This is not a regression) (destructuring-bind (var &optional default sup-p) arg (if (and (consp var) (eq what-kind '&key)) - (destructuring-bind (keyword-name var) var - (unless (symbolp keyword-name) - (croak "keyword-name in ~S is not a symbol" arg)) - (need-bindable var description)) + (cond ((singleton-p (cdr var)) + (destructuring-bind (keyword-name var) var + (unless (symbolp keyword-name) + (croak "keyword-name in ~S is not a symbol" arg)) + (need-bindable var description))) + (t + (croak "invalid &KEY syntax: ~S" var))) (need-bindable var description)) ;; Inform the user about a possibly malformed ;; destructuring list (&OPTIONAL (A &OPTIONAL B)). @@ -413,7 +440,7 @@ (when (and (not silent) (vectorp parse)) ; is destructuring (let ((default (and (cdr arg-specifier) ; have an explicit default (cadr arg-specifier)))) - (when (and (constantp default) + (when (and (cl:constantp default) (not (ds-lambda-list-match-p (#+sb-xc constant-form-value #-sb-xc eval default) @@ -528,7 +555,9 @@ (if (ll-kwds-keyp llks) (cons '&key keys)) ; KEYS can be nil (if (ll-kwds-allowp llks) '(&allow-other-keys)) ;; Should &AUX be inserted even if empty? Probably not. - (if aux (cons '&aux aux))))))) + (if aux (cons '&aux aux)) + ;; fresh lambda list spine everywhere + nil))))) ;;; Produce a destructuring lambda list from its internalized representation, ;;; excluding any parts that don't constrain the shape of the expected input. @@ -778,7 +807,7 @@ (if sup-p-var `(values ,def nil) def)))) (cond ((not sup-p-var) (bind-pat var vals)) ((not (symbolp var)) - (let ((var-temp (sb-xc:gensym)) + (let ((var-temp (gensym)) (sup-p-temp (copy-symbol suppliedp))) (bind `((,var-temp ,sup-p-temp) ,vals)) (descend var var-temp) @@ -801,7 +830,7 @@ ;; in theory, (MULTIPLE-VALUE-BIND () (EXPR) ...) ;; but in practice it becomes a binding of an ignored gensym. (let* ((bindings-p (or whole required opt rest keys)) - (temp (and bindings-p (sb-xc:gensym)))) + (temp (and bindings-p (gensym)))) (bind `(,temp ,(cond ((or emit-pre-test (ll-kwds-keyp llks)) (emit-ds-bind-check parsed-lambda-list input @@ -851,7 +880,7 @@ (dolist (elt keys) (multiple-value-bind (keyword var def sup-p-var) (parse-key-arg-spec elt default-default) - (let ((temp (sb-xc:gensym))) + (let ((temp (gensym))) (bind `(,temp (ds-getf ,input ',keyword))) (bind-if :not `(eql ,temp 0) `(car (truly-the cons ,temp)) var sup-p-var def)))) @@ -1056,7 +1085,7 @@ (pop plist) (unless (or (keywordp key) (and (symbolp key) - (constantp key) + (cl:constantp key) (eq key (symbol-value key)))) (signal 'compiler-macro-keyword-problem :argument key)))) @@ -1130,10 +1159,15 @@ ;; Drop &WHOLE and &ENVIRONMENT (new-ll (make-lambda-list llks nil req opt rest keys aux)) #-sb-xc-host - (*lexenv* (process-muffle-decls decls - (if (boundp '*lexenv*) - *lexenv* - (make-null-lexenv)))) + ((*lexenv* source-form) (process-muffle-decls decls + (if (boundp '*lexenv*) + *lexenv* + (make-null-lexenv)))) + #-sb-xc-host + (*current-path* (or (and source-form + (get-source-path source-form)) + (and (boundp '*current-path*) + *current-path*))) (parse (parse-ds-lambda-list new-ll)) ((declared-lambda-list decls) (let ((ll @@ -1151,7 +1185,8 @@ (loop for (declare . declarations) in decls collect (list* declare (remove 'lambda-list declarations :key #'car))) - decls))))) + decls)))) + (variables (ds-lambda-list-variables parse nil))) ;; Signal a style warning for duplicate names, but disregard &AUX variables ;; because most folks agree that (LET* ((X (F)) (X (G X))) ..) makes sense ;; - some would even say that it is idiomatic - and &AUX bindings are just @@ -1163,7 +1198,7 @@ (when (memq (car tail) (cdr tail)) (style-warn-once lambda-list "variable ~S occurs more than once" (car tail)))) - (append whole env (ds-lambda-list-variables parse nil))) + (append whole env variables)) ;; Maybe kill docstring, but only under the cross-compiler. #+(and (not sb-doc) sb-xc-host) (setq docstring nil) ;; Note that we *NEVER* declare macro lambdas as a toplevel named lambda. @@ -1178,6 +1213,9 @@ (,ll-whole ,@ll-env ,@(and ll-aux (cons '&aux ll-aux))) ,@(when (and docstring (eq doc-string-allowed :internal)) (prog1 (list docstring) (setq docstring nil))) + #-sb-xc-host + ,@(and source-form + `((declare (source-form ,source-form)))) ;; MACROLET doesn't produce an object capable of reflection, ;; so don't bother inserting a different lambda-list. ,@(unless (eq kind 'macrolet) @@ -1190,7 +1228,9 @@ `(:special-form . ,name) `(:macro ,name . ,kind))) '(destructuring-bind)) - ,new-ll (,accessor ,ll-whole) + ,new-ll (,accessor ,ll-whole) + #-sb-xc-host + (declare (constant-value ,@variables)) ,@decls ,@(if wrap-block `((block ,(fun-name-block-name name) ,@forms)) @@ -1273,3 +1313,18 @@ (unless allow-special (lose "special variable")))) (values name kind)))) + +;; This is a variant of destructuring-bind that provides the name +;; of the containing construct in generated error messages. +(macrolet (#+sb-xc-host ; Bootstrap NAMED-DS-BIND + (named-ds-bind (name lambda-list expression &body body) + (declare (ignore name)) + `(cl:destructuring-bind ,lambda-list ,expression ,@body))) + (defmacro named-ds-bind (name lambda-list expression &body body + &environment env) + (declare (ignore env)) ; could be policy-sensitive (but isn't) + `(binding* ,(sb-c::expand-ds-bind lambda-list expression t nil name + (and (eq (car name) :macro) + (eq (cddr name) 'deftype) + ''*)) + ,@body))) diff --git a/src/compiler/policies.lisp b/src/compiler/policies.lisp index a4446e9cfe..54945bf089 100644 --- a/src/compiler/policies.lisp +++ b/src/compiler/policies.lisp @@ -123,9 +123,17 @@ optimizations. When enabled, the variable is preserved and can be seen in the debugger.") +(define-optimization-quality preserve-constants + 0 + ("no" "no" "no" "yes")) + (define-optimization-quality insert-array-bounds-checks (if (= safety 0) 0 3) ("no" "yes" "yes" "yes")) +(define-optimization-quality aref-trapping + #-ubsan (if (= safety 3) 3 0) ; equiv. to safety unless expressed otherwise + #+ubsan 2 ; default to yes + ("no" "yes" "yes" "yes")) (define-optimization-quality store-xref-data (if (= space 3) @@ -142,10 +150,10 @@ debugger.") ("no" "no" "yes" "yes")) #+sb-safepoint -(define-optimization-quality inhibit-safepoints - 0 - ("no" "no" "yes" "yes") - "When disabled, the compiler will insert safepoints at strategic +(define-optimization-quality insert-safepoints + 1 + ("no" "yes" "yes" "yes") + "When enabled, the compiler will insert safepoints at strategic points (loop edges, function prologues) to ensure that potentially long-running code can be interrupted. diff --git a/src/compiler/policy.lisp b/src/compiler/policy.lisp index 841d761896..689ac7597c 100644 --- a/src/compiler/policy.lisp +++ b/src/compiler/policy.lisp @@ -14,16 +14,71 @@ ;;; a value for an optimization declaration (deftype policy-quality () '(integer 0 3)) -(defvar *macro-policy* nil) -;;; global policy restrictions as a POLICY object or nil -(defvar *policy-min* nil) -(defvar *policy-max* nil) +(defconstant-eqx +policy-primary-qualities+ + #(;; ANSI standard qualities + compilation-speed + debug + safety + space + speed + ;; SBCL extensions + ;; + ;; FIXME: INHIBIT-WARNINGS is a misleading name for this. + ;; Perhaps BREVITY would be better. But the ideal name would + ;; have connotations of suppressing not warnings but only + ;; optimization-related notes, which is already mostly the + ;; behavior, and should probably become the exact behavior. + ;; Perhaps INHIBIT-NOTES? + inhibit-warnings) + #'equalp) + +(eval-when (:compile-toplevel :load-toplevel :execute) + (defconstant n-policy-primary-qualities (length +policy-primary-qualities+)) + ;; 1 bit per quality is stored to indicate whether it was explicitly given + ;; a value in a lexical policy. In addition to the 5 ANSI-standard qualities, + ;; SBCL defines one more "primary" quality and 16 dependent qualities. + ;; Both kinds take up 1 bit in the mask of specified qualities. + (defconstant max-policy-qualities 32)) + +;; Each primary and dependent quality policy is assigned a small integer index. +;; The POLICY struct represents a set of policies in an order-insensitive way +;; that facilitates quicker lookup than scanning an alist. +(defstruct (policy (:constructor make-policy + (primary-qualities &optional + presence-bits dependent-qualities))) + ;; Mask with a 1 for each quality that has an explicit value in this policy. + ;; Primary qualities fill the mask from left-to-right and dependent qualities + ;; from right-to-left. + ;; xc has trouble folding this MASK-FIELD, but it works when host-evaluated. + (presence-bits #.(mask-field + (byte n-policy-primary-qualities + (- max-policy-qualities n-policy-primary-qualities)) + -1) + :type (unsigned-byte #.max-policy-qualities)) + ;; For efficiency, primary qualities are segregated because there are few + ;; enough of them to fit in a fixnum. + (primary-qualities 0 :type (unsigned-byte #.(* 2 n-policy-primary-qualities))) + ;; 2 bits per dependent quality is a fixnum on 64-bit build, not on 32-bit. + ;; It would certainly be possible to constrain this to storing exactly + ;; the 16 currently defined dependent qualities, + ;; but that would be overly limiting. + (dependent-qualities 0 + :type (unsigned-byte #.(* (- max-policy-qualities n-policy-primary-qualities) + 2)))) +(declaim (freeze-type policy)) + ;;; *POLICY* holds the current global compiler policy information, as ;;; a POLICY object mapping from the compiler-assigned index (unique per ;;; quality name) to quality value. ;;; This used to be an alist, but tail-sharing was never really possible ;;; because for deterministic comparison the list was always freshly ;;; consed so that destructive sorting could be done for canonicalization. +(defvar *policy*) +(defvar *macro-policy* nil) +;;; global policy restrictions as a POLICY object or nil +(defvar *policy-min* nil) +(defvar *policy-max* nil) + (declaim (type policy *policy*) (type (or policy null) *policy-min* *policy-max*)) @@ -142,20 +197,6 @@ See also :POLICY option in WITH-COMPILATION-UNIT." (policy-presence-bits policy)) (if presentp 1 0)) policy) -;;; Is it deprecated? -(declaim (ftype function deprecation-warn)) -(defun policy-quality-deprecation-warning (quality) - (case quality - ((stack-allocate-dynamic-extent stack-allocate-vector stack-allocate-value-cells) - (deprecation-warn :late "SBCL" "1.0.19.7" 'policy quality '*stack-allocate-dynamic-extent* - :runtime-error nil) - t) - ((merge-tail-calls) - (deprecation-warn :early "SBCL" "1.0.53.74" 'policy quality nil :runtime-error nil) - t) - (otherwise - nil))) - ;; ANSI-specified default of 1 for each quality. (defglobal **baseline-policy** nil) ;; Baseline policy altered with (TYPE-CHECK 0) @@ -168,15 +209,16 @@ See also :POLICY option in WITH-COMPILATION-UNIT." ;;; OPTIMIZE forms have messed with it. #-sb-xc-host (defun !policy-cold-init-or-resanify () - (macrolet ((init (policy-symbol) ; Act like MAKE-LOAD-FORM essentially - (let ((policy (symbol-value policy-symbol))) - `(setq ,policy-symbol + (macrolet ((reflect-host-value (target-policy &optional (host-policy target-policy)) + ;; Act like MAKE-LOAD-FORM essentially + (let ((policy (symbol-value host-policy))) + `(setq ,target-policy (make-policy ,(policy-primary-qualities policy) ,(policy-presence-bits policy) ,(policy-dependent-qualities policy)))))) - (init **baseline-policy**) - (init **zero-typecheck-policy**) - (setq *policy* (copy-policy **baseline-policy**)))) + (reflect-host-value **baseline-policy**) + (reflect-host-value **zero-typecheck-policy**) + (reflect-host-value *policy* **baseline-policy**))) #+sb-xc-host (defun init-xc-policy (&optional baseline-qualities) @@ -187,11 +229,11 @@ See also :POLICY option in WITH-COMPILATION-UNIT." sum (ash #b01 (* i 2)))) *policy* (copy-policy **baseline-policy**)) (when baseline-qualities - (sb-xc:proclaim `(optimize ,@baseline-qualities)) + (proclaim `(optimize ,@baseline-qualities)) ;; Copy altered policy back as the baseline policy (setq **baseline-policy** (copy-policy *policy*))) (let ((*policy* *policy*)) - (sb-xc:proclaim '(optimize (type-check 0))) + (proclaim '(optimize (type-check 0))) (setq **zero-typecheck-policy** *policy*))) ;;; Look up a named optimization quality in POLICY. This is only @@ -244,6 +286,13 @@ See also :POLICY option in WITH-COMPILATION-UNIT." ;; can create a POLICY that indicates absence of primary qualities. ;; This does not affect RESTRICT-COMPILER-POLICY because a lower bound of 0 ;; can be assumed for everything. SET-MACRO-POLICY might care though. + ;; + ;; FIXME: it is wrong IMHO that the min/max are applied lazily, every time + ;; they are fetched from a policy. This makes it impossible to create + ;; a policy that represents _exactly_ what you want in the internals of the + ;; CLOS implementation. Applying the min/max when a policy is created would + ;; provide an escape mechanism. Alternatively we could indicate in the policy + ;; whether each quality should be treated as absolute. (define-getter %policy-quality (let ((min *policy-min*) (max *policy-max*)) @@ -346,10 +395,9 @@ See also :POLICY option in WITH-COMPILATION-UNIT." (values quality raw-value))) (let ((index (policy-quality-name-p quality))) (cond ((not index) - (or (policy-quality-deprecation-warning quality) - (compiler-warn - "~@<Ignoring unknown optimization quality ~S in:~_ ~S~:>" - quality spec))) + (compiler-warn + "~@<Ignoring unknown optimization quality ~S in:~_ ~S~:>" + quality spec)) ((not (typep raw-value 'policy-quality)) (compiler-warn "~@<Ignoring bad optimization value ~S in:~_ ~S~:>" diff --git a/src/compiler/ppc/alloc.lisp b/src/compiler/ppc/alloc.lisp index e888410b91..da0288b20f 100644 --- a/src/compiler/ppc/alloc.lisp +++ b/src/compiler/ppc/alloc.lisp @@ -10,29 +10,98 @@ ;;;; files for more information. (in-package "SB-VM") + +;;;; Storage allocation: + +;;; This is the main mechanism for allocating memory in the lisp heap. +;;; +;;; The allocated space is stored in RESULT-TN with the lowtag LOWTAG +;;; applied. The amount of space to be allocated is SIZE bytes (which +;;; must be a multiple of the lisp object size). +;;; +;;; On other platforms (Non-PPC), if STACK-P is given, then allocation +;;; occurs on the control stack (for dynamic-extent). In this case, +;;; you MUST also specify NODE, so that the appropriate compiler +;;; policy can be used, and TEMP-TN, which is needed for work-space. +;;; TEMP-TN MUST be a non-descriptor reg. FIXME: This is not yet +;;; implemented on PPC. We should implement this and replace the +;;; inline stack-based allocation that presently occurs in the +;;; VOPs. The stack-p argument is ignored on PPC. +(defun allocation (type size lowtag result-tn &key stack-p node temp-tn flag-tn) + (declare (ignore stack-p node)) + (binding* ((cons-region-p (or #+use-cons-region (eq type 'list))) + ((region-base-tn field-offset) + #-sb-thread + (values null-tn (- (if cons-region-p cons-region mixed-region) nil-value)) + #+sb-thread + (values thread-base-tn + (ash (if cons-region-p thread-cons-tlab-slot thread-mixed-tlab-slot) + word-shift))) + (imm-size (typep size '(unsigned-byte 15)))) + + (unless imm-size ; Make temp-tn be the size + (if (numberp size) + (inst lr temp-tn size) + (move temp-tn size))) + + (inst lwz result-tn region-base-tn field-offset) + (inst lwz flag-tn region-base-tn (+ field-offset n-word-bytes)) ; region->end_addr + + ;; CAUTION: The C code depends on the exact order of + ;; instructions here. In particular, immediately before the + ;; TW instruction must be an ADD or ADDI instruction, so it + ;; can figure out the size of the desired allocation, and + ;; storing the new base pointer back to the allocation region + ;; must take one instruction. + (without-scheduling () + ;; Make result-tn point at the end of the object, to + ;; figure out if we overflowed the current region. + (if imm-size + (inst addi result-tn result-tn size) + (inst add result-tn result-tn temp-tn)) + + ;; result-tn points to the new end of the region. Did we go past + ;; the actual end of the region? If so, we need a full alloc. + ;; The C code depends on this exact form of instruction. If + ;; either changes, you have to change the other appropriately! + ;; These two trap instructions are behaviorally the same, + ;; but the encoding of the TO field informs the runtime + ;; whether the allocation is a list or general object. + (if (eq type 'list) + (inst tw :llt flag-tn result-tn) ; trap if region.end < new_freeptr + (inst tw :lgt result-tn flag-tn)) ; trap if new_freeptr > region.end + (inst stw result-tn region-base-tn field-offset)) + + ;; Execution resumes here if the trap fires. + ;; At this point, result-tn points at the end of the object. + ;; Adjust to point to the beginning. + (cond (imm-size + (inst addi result-tn result-tn (+ (- size) lowtag))) + (t + (inst sub result-tn result-tn temp-tn) + ;; Set the lowtag appropriately + (inst ori result-tn result-tn lowtag))))) + +(defun align-csp (temp) + ;; is used for stack allocation of dynamic-extent objects + (storew null-tn csp-tn 0 0) ; store a known-good value (don't want wild pointers below CSP) + (inst addi temp csp-tn lowtag-mask) + (inst clrrwi csp-tn temp n-lowtag-bits)) ;;;; LIST and LIST* -(define-vop (list-or-list*) - (:args (things :more t)) +(define-vop (list) + (:args (things :more t :scs (any-reg descriptor-reg zero null control-stack))) (:temporary (:scs (descriptor-reg)) ptr) (:temporary (:scs (descriptor-reg)) temp) (:temporary (:scs (descriptor-reg) :to (:result 0) :target result) res) (:temporary (:sc non-descriptor-reg :offset nl3-offset) pa-flag) (:temporary (:scs (non-descriptor-reg)) alloc-temp) - (:info num) + (:info star cons-cells) (:results (result :scs (descriptor-reg))) - (:variant-vars star) - (:policy :safe) (:node-var node) (:generator 0 - (cond ((zerop num) - (move result null-tn)) - ((and star (= num 1)) - (move result (tn-ref-tn things))) - (t - (macrolet - ((maybe-load (tn) + (macrolet ((maybe-load (tn) (once-only ((tn tn)) `(sc-case ,tn ((any-reg descriptor-reg zero null) @@ -40,15 +109,13 @@ (control-stack (load-stack-tn temp ,tn) temp))))) - (let* ((dx-p (node-stack-allocate-p node)) - (cons-cells (if star (1- num) num)) - (alloc (* (pad-data-block cons-size) cons-cells))) - (pseudo-atomic (pa-flag :sync nil) + (let ((dx-p (node-stack-allocate-p node)) + (alloc (* (pad-data-block cons-size) cons-cells))) + (pseudo-atomic (pa-flag :sync nil :elide-if dx-p) (if dx-p (progn (align-csp res) - (inst clrrwi res csp-tn n-lowtag-bits) - (inst ori res res list-pointer-lowtag) + (inst ori res csp-tn list-pointer-lowtag) (inst addi csp-tn csp-tn alloc)) (allocation 'list alloc list-pointer-lowtag res :temp-tn alloc-temp @@ -68,14 +135,7 @@ (maybe-load (tn-ref-tn (tn-ref-across things))) null-tn) ptr cons-cdr-slot list-pointer-lowtag)) - (move result res))))))) - -(define-vop (list list-or-list*) - (:variant nil)) - -(define-vop (list* list-or-list*) - (:variant t)) - + (move result res))))) ;;;; Special purpose inline allocators. @@ -103,13 +163,12 @@ (:generator 10 (let* ((size (+ length closure-info-offset)) (alloc-size (pad-data-block size))) - (pseudo-atomic (pa-flag) + (pseudo-atomic (pa-flag :elide-if stack-allocate-p) (if stack-allocate-p (progn (align-csp result) - (inst clrrwi. result csp-tn n-lowtag-bits) + (inst ori result csp-tn fun-pointer-lowtag) (inst addi csp-tn csp-tn alloc-size) - (inst ori result result fun-pointer-lowtag) (inst lr temp (logior (ash (1- size) n-widetag-bits) closure-widetag))) (progn (allocation nil (pad-data-block size) fun-pointer-lowtag result @@ -180,6 +239,9 @@ (t (inst addi header header (+ (ash -2 (length-field-shift type)) type)) (inst clrrwi bytes bytes n-lowtag-bits))) + #+bignum-assertions + (when (= type bignum-widetag) + (inst slwi bytes bytes 1)) ; use 2x the space (pseudo-atomic (pa-flag) (allocation nil bytes lowtag result :temp-tn temp :flag-tn pa-flag) (storew header result 0 lowtag)))) diff --git a/src/compiler/ppc/arith.lisp b/src/compiler/ppc/arith.lisp index 9ed0af56b5..cc8719ef69 100644 --- a/src/compiler/ppc/arith.lisp +++ b/src/compiler/ppc/arith.lisp @@ -502,7 +502,7 @@ (inst cmpwi amount 0) (inst neg ndesc amount) (inst bge positive) - (inst cmpwi ndesc 31) + (inst cmplwi ndesc 31) (inst srw result number ndesc) (inst ble done) (move result zero-tn) @@ -549,7 +549,7 @@ (inst cmpwi amount 0) (inst neg ndesc amount) (inst bge positive) - (inst cmpwi ndesc 31) + (inst cmplwi ndesc 31) (inst sraw result number ndesc) (inst ble done) (inst srawi result number 31) @@ -706,7 +706,7 @@ fast-ash-left/unsigned=>unsigned)) (deftransform ash-left-mod32 ((integer count) ((unsigned-byte 32) (unsigned-byte 5))) - (when (sb-c::constant-lvar-p count) + (when (sb-c:constant-lvar-p count) (sb-c::give-up-ir1-transform)) '(%primitive fast-ash-left-mod32/unsigned=>unsigned integer count)) @@ -948,7 +948,7 @@ ;;; (define-vop (fast-eql/fixnum fast-conditional) - (:args (x :scs (any-reg descriptor-reg zero)) + (:args (x :scs (any-reg zero)) (y :scs (any-reg zero))) (:arg-types tagged-num tagged-num) (:note "inline fixnum comparison") @@ -958,11 +958,13 @@ (inst b? (if not-p :ne :eq) target))) ;;; (define-vop (generic-eql/fixnum fast-eql/fixnum) + (:args (x :scs (any-reg descriptor-reg)) + (y :scs (any-reg))) (:arg-types * tagged-num) (:variant-cost 7)) (define-vop (fast-eql-c/fixnum fast-conditional/fixnum) - (:args (x :scs (any-reg descriptor-reg zero))) + (:args (x :scs (any-reg zero))) (:arg-types tagged-num (:constant (signed-byte 14))) (:info target not-p y) (:translate eql) @@ -971,33 +973,28 @@ (inst b? (if not-p :ne :eq) target))) ;;; (define-vop (generic-eql-c/fixnum fast-eql-c/fixnum) + (:args (x :scs (any-reg descriptor-reg))) (:arg-types * (:constant (signed-byte 11))) (:variant-cost 6)) ;;;; 32-bit logical operations -(define-vop (shift-towards-someplace) - (:policy :fast-safe) - (:args (num :scs (unsigned-reg)) - (amount :scs (signed-reg))) - (:arg-types unsigned-num tagged-num) - (:results (r :scs (unsigned-reg))) - (:result-types unsigned-num)) - -(define-vop (shift-towards-start shift-towards-someplace) - (:translate shift-towards-start) - (:note "shift-towards-start") - (:generator 1 - (inst rlwinm amount amount 0 27 31) - (inst slw r num amount))) - -(define-vop (shift-towards-end shift-towards-someplace) - (:translate shift-towards-end) - (:note "shift-towards-end") - (:generator 1 - (inst rlwinm amount amount 0 27 31) - (inst srw r num amount))) +(macrolet ((define (translate operation) + `(define-vop () + (:translate ,translate) + (:note ,(string translate)) + (:policy :fast-safe) + (:args (num :scs (unsigned-reg)) + (amount :scs (signed-reg))) + (:arg-types unsigned-num tagged-num) + (:results (r :scs (unsigned-reg))) + (:result-types unsigned-num) + (:generator 1 + (inst rlwinm amount amount 0 27 31) + (inst ,operation r num amount))))) + (define shift-towards-start slw) + (define shift-towards-end srw)) ;;;; Bignum stuff. @@ -1009,6 +1006,7 @@ (:translate sb-bignum:%bignum-set-length) (:policy :fast-safe)) +#-bignum-assertions (define-vop (bignum-ref word-index-ref) (:variant bignum-digits-offset other-pointer-lowtag) (:translate sb-bignum:%bignum-ref) @@ -1017,13 +1015,12 @@ (define-vop (bignum-set word-index-set) (:variant bignum-digits-offset other-pointer-lowtag) - (:translate sb-bignum:%bignum-set) + (:translate #+bignum-assertions sb-bignum:%%bignum-set + #-bignum-assertions sb-bignum:%bignum-set) (:args (object :scs (descriptor-reg)) (index :scs (any-reg immediate zero)) (value :scs (unsigned-reg))) - (:arg-types t positive-fixnum unsigned-num) - (:results (result :scs (unsigned-reg))) - (:result-types unsigned-num)) + (:arg-types t positive-fixnum unsigned-num)) (define-vop (digit-0-or-plus) (:translate sb-bignum:%digit-0-or-plusp) diff --git a/src/compiler/ppc/array.lisp b/src/compiler/ppc/array.lisp index 6a6cc6f748..ae0262fbca 100644 --- a/src/compiler/ppc/array.lisp +++ b/src/compiler/ppc/array.lisp @@ -33,8 +33,12 @@ (allocation nil ndescr other-pointer-lowtag header :temp-tn gc-temp :flag-tn pa-flag) - (inst addi ndescr rank (fixnumize (1- array-dimensions-offset))) - (inst slwi ndescr ndescr n-widetag-bits) + ;; Compute the encoded rank. See ENCODE-ARRAY-RANK. + (inst subi ndescr rank (fixnumize 1)) + ;; Exercise for the reader: these next 4 instructions can be + ;; replaced by just 2: one RLWINM and one RLWIMI + (inst andi. ndescr ndescr (fixnumize array-rank-mask)) + (inst slwi ndescr ndescr array-rank-position) (inst or ndescr ndescr type) (inst srwi ndescr ndescr n-fixnum-tag-bits) (storew ndescr header 0 other-pointer-lowtag)) @@ -52,17 +56,18 @@ (:policy :fast-safe) (:variant array-dimensions-offset other-pointer-lowtag)) -(define-vop (array-rank-vop) +(define-vop () (:translate %array-rank) (:policy :fast-safe) (:args (x :scs (descriptor-reg))) - (:temporary (:scs (non-descriptor-reg)) temp) - (:results (res :scs (any-reg descriptor-reg))) + (:results (res :scs (unsigned-reg))) + (:result-types positive-fixnum) (:generator 6 - (loadw temp x 0 other-pointer-lowtag) - (inst srawi temp temp n-widetag-bits) - (inst subi temp temp (1- array-dimensions-offset)) - (inst slwi res temp n-fixnum-tag-bits))) + ;; convert ARRAY-RANK-POSITION to byte index and compensate for endianness + ;; ASSUMPTION: n-widetag-bits = 8 and rank is adjacent to widetag + (inst lbz res x (- 2 other-pointer-lowtag)) ; big-endian only + (inst addi res res 1) + (inst andi. res res array-rank-mask))) ;;;; Bounds checking routine. @@ -108,9 +113,7 @@ (:arg-types ,type positive-fixnum ,element-type) (:args (object :scs (descriptor-reg)) (index :scs (any-reg zero immediate)) - (value :scs ,scs)) - (:results (result :scs ,scs)) - (:result-types ,element-type))))) + (value :scs ,scs)))))) (def-data-vector-frobs simple-base-string byte-index character character-reg) #+sb-unicode @@ -207,10 +210,8 @@ (:policy :fast-safe) (:args (object :scs (descriptor-reg)) (index :scs (unsigned-reg) :target shift) - (value :scs (unsigned-reg zero immediate) :target result)) + (value :scs (unsigned-reg zero immediate))) (:arg-types ,type positive-fixnum positive-fixnum) - (:results (result :scs (unsigned-reg))) - (:result-types positive-fixnum) (:temporary (:scs (non-descriptor-reg)) temp old offset) (:temporary (:scs (non-descriptor-reg) :from (:argument 1)) shift) (:generator 25 @@ -236,23 +237,16 @@ (inst andi. temp value ,(1- (ash 1 bits))))) (inst slw temp temp shift) (inst or old old temp)) - (inst stwx old object offset) - (sc-case value - (immediate - (inst lr result (tn-value value))) - (t - (move result value))))) + (inst stwx old object offset))) (define-vop (,(symbolicate 'data-vector-set-c/ type)) (:translate data-vector-set) (:policy :fast-safe) (:args (object :scs (descriptor-reg)) - (value :scs (unsigned-reg zero immediate) :target result)) + (value :scs (unsigned-reg zero immediate))) (:arg-types ,type (:constant index) positive-fixnum) (:info index) - (:results (result :scs (unsigned-reg))) - (:result-types positive-fixnum) (:temporary (:scs (non-descriptor-reg)) offset-reg temp old) (:generator 20 (multiple-value-bind (word extra) (floor index ,elements-per-word) @@ -293,12 +287,7 @@ (inst or old old temp))) (if (typep offset '(signed-byte 16)) (inst stw old object offset) - (inst stwx old object offset-reg))) - (sc-case value - (immediate - (inst lr result (tn-value value))) - (t - (move result value)))))))))) + (inst stwx old object offset-reg)))))))))) (def-small-data-vector-frobs simple-bit-vector 1) (def-small-data-vector-frobs simple-array-unsigned-byte-2 2) (def-small-data-vector-frobs simple-array-unsigned-byte-4 4)) @@ -329,18 +318,14 @@ (:policy :fast-safe) (:args (object :scs (descriptor-reg)) (index :scs (any-reg)) - (value :scs (single-reg) :target result)) + (value :scs (single-reg))) (:arg-types simple-array-single-float positive-fixnum single-float) - (:results (result :scs (single-reg))) - (:result-types single-float) (:temporary (:scs (non-descriptor-reg)) offset) (:generator 5 (inst addi offset index (- (* vector-data-offset n-word-bytes) other-pointer-lowtag)) - (inst stfsx value object offset) - (unless (location= result value) - (inst frsp result value)))) + (inst stfsx value object offset))) (define-vop (data-vector-ref/simple-array-double-float) (:note "inline array access") @@ -364,18 +349,14 @@ (:policy :fast-safe) (:args (object :scs (descriptor-reg)) (index :scs (any-reg)) - (value :scs (double-reg) :target result)) + (value :scs (double-reg))) (:arg-types simple-array-double-float positive-fixnum double-float) - (:results (result :scs (double-reg))) - (:result-types double-float) (:temporary (:scs (non-descriptor-reg)) offset) (:generator 20 (inst slwi offset index 1) (inst addi offset offset (- (* vector-data-offset n-word-bytes) other-pointer-lowtag)) - (inst stfdx value object offset) - (unless (location= result value) - (inst fmr result value)))) + (inst stfdx value object offset))) ;;; Complex float arrays. @@ -406,27 +387,19 @@ (:policy :fast-safe) (:args (object :scs (descriptor-reg)) (index :scs (any-reg)) - (value :scs (complex-single-reg) :target result)) + (value :scs (complex-single-reg))) (:arg-types simple-array-complex-single-float positive-fixnum complex-single-float) - (:results (result :scs (complex-single-reg))) - (:result-types complex-single-float) (:temporary (:scs (non-descriptor-reg) :from (:argument 1)) offset) (:generator 5 - (let ((value-real (complex-single-reg-real-tn value)) - (result-real (complex-single-reg-real-tn result))) + (let ((value-real (complex-single-reg-real-tn value))) (inst slwi offset index 1) (inst addi offset offset (- (* vector-data-offset n-word-bytes) other-pointer-lowtag)) - (inst stfsx value-real object offset) - (unless (location= result-real value-real) - (inst frsp result-real value-real))) - (let ((value-imag (complex-single-reg-imag-tn value)) - (result-imag (complex-single-reg-imag-tn result))) + (inst stfsx value-real object offset)) + (let ((value-imag (complex-single-reg-imag-tn value))) (inst addi offset offset n-word-bytes) - (inst stfsx value-imag object offset) - (unless (location= result-imag value-imag) - (inst frsp result-imag value-imag))))) + (inst stfsx value-imag object offset)))) (define-vop (data-vector-ref/simple-array-complex-double-float) @@ -453,29 +426,21 @@ (:note "inline array store") (:translate data-vector-set) (:policy :fast-safe) - (:args (object :scs (descriptor-reg) :to :result) + (:args (object :scs (descriptor-reg)) (index :scs (any-reg)) - (value :scs (complex-double-reg) :target result)) + (value :scs (complex-double-reg))) (:arg-types simple-array-complex-double-float positive-fixnum complex-double-float) - (:results (result :scs (complex-double-reg))) - (:result-types complex-double-float) (:temporary (:scs (non-descriptor-reg) :from (:argument 1)) offset) (:generator 20 - (let ((value-real (complex-double-reg-real-tn value)) - (result-real (complex-double-reg-real-tn result))) + (let ((value-real (complex-double-reg-real-tn value))) (inst slwi offset index 2) (inst addi offset offset (- (* vector-data-offset n-word-bytes) other-pointer-lowtag)) - (inst stfdx value-real object offset) - (unless (location= result-real value-real) - (inst fmr result-real value-real))) - (let ((value-imag (complex-double-reg-imag-tn value)) - (result-imag (complex-double-reg-imag-tn result))) + (inst stfdx value-real object offset)) + (let ((value-imag (complex-double-reg-imag-tn value))) (inst addi offset offset (* 2 n-word-bytes)) - (inst stfdx value-imag object offset) - (unless (location= result-imag value-imag) - (inst fmr result-imag value-imag))))) + (inst stfdx value-imag object offset)))) ;;; These vops are useful for accessing the bits of a vector irrespective of @@ -496,8 +461,6 @@ (index :scs (any-reg zero immediate)) (value :scs (unsigned-reg))) (:arg-types * positive-fixnum unsigned-num) - (:results (result :scs (unsigned-reg))) - (:result-types unsigned-num) (:variant vector-data-offset other-pointer-lowtag)) ;;; @@ -517,9 +480,7 @@ (:arg-types simple-array-signed-byte-8 positive-fixnum tagged-num) (:args (object :scs (descriptor-reg)) (index :scs (any-reg zero immediate)) - (value :scs (signed-reg))) - (:results (result :scs (signed-reg))) - (:result-types tagged-num)) + (value :scs (signed-reg)))) (define-vop (data-vector-ref/simple-array-signed-byte-16 signed-halfword-index-ref) @@ -537,9 +498,7 @@ (:arg-types simple-array-signed-byte-16 positive-fixnum tagged-num) (:args (object :scs (descriptor-reg)) (index :scs (any-reg zero immediate)) - (value :scs (signed-reg))) - (:results (result :scs (signed-reg))) - (:result-types tagged-num)) + (value :scs (signed-reg)))) ;;;; ATOMIC-INCF for arrays diff --git a/src/compiler/ppc/c-call.lisp b/src/compiler/ppc/c-call.lisp index 00ba088ffa..464ce441e0 100644 --- a/src/compiler/ppc/c-call.lisp +++ b/src/compiler/ppc/c-call.lisp @@ -19,19 +19,14 @@ (defconstant +stack-alignment-bytes+ ;; Duh. PPC Linux (and VxWorks) adhere to the EABI. - #-darwin 7 - ;; But Darwin doesn't - #+darwin 15) + 7) (defstruct arg-state (gpr-args 0) (fpr-args 0) ;; SVR4 [a]abi wants two words on stack (callee saved lr, ;; backpointer). - #-darwin (stack-frame-size 2) - ;; PowerOpen ABI wants 8 words on the stack corresponding to GPR3-10 - ;; in addition to the 6 words of link area (see number-stack-displacement) - #+darwin (stack-frame-size (+ 8 6))) + (stack-frame-size 2)) (defun int-arg (state prim-type reg-sc stack-sc) (let ((reg-args (arg-state-gpr-args state))) @@ -62,7 +57,6 @@ ;;; Excess floats stored on the stack are stored as floats. ;;; ;;; We follow gcc. -#-darwin (define-alien-type-method (single-float :arg-tn) (type state) (declare (ignore type)) (let* ((fprs (arg-state-fpr-args state))) @@ -75,31 +69,6 @@ (setf (arg-state-stack-frame-size state) (+ stack-offset 1)) (make-wired-tn* 'single-float single-stack-sc-number stack-offset)))))) -;;; If a single-float arg has to go on the stack, it's promoted to -;;; double. That way, C programs can get subtle rounding errors when -;;; unrelated arguments are introduced. -#+darwin -(define-alien-type-method (single-float :arg-tn) (type state) - (declare (ignore type)) - (let* ((fprs (arg-state-fpr-args state)) - (gprs (arg-state-gpr-args state))) - (cond ((< gprs 8) ; and by implication also (< fprs 13) - (incf (arg-state-fpr-args state)) - ;; Assign outgoing FPRs starting at FP1 - (list (make-wired-tn* 'single-float single-reg-sc-number (1+ fprs)) - (int-arg state 'signed-byte-32 signed-reg-sc-number signed-stack-sc-number))) - ((< fprs 13) - ;; See comments below for double-float. - (incf (arg-state-fpr-args state)) - (incf (arg-state-stack-frame-size state)) - (make-wired-tn* 'single-float single-reg-sc-number (1+ fprs))) - (t - ;; Pass on stack only - (let ((stack-offset (arg-state-stack-frame-size state))) - (incf (arg-state-stack-frame-size state)) - (make-wired-tn* 'single-float single-stack-sc-number stack-offset)))))) - -#-darwin (define-alien-type-method (double-float :arg-tn) (type state) (declare (ignore type)) (let* ((fprs (arg-state-fpr-args state))) @@ -114,35 +83,6 @@ (setf (arg-state-stack-frame-size state) (+ stack-offset 2)) (make-wired-tn* 'double-float double-stack-sc-number stack-offset)))))) -#+darwin -(define-alien-type-method (double-float :arg-tn) (type state) - (declare (ignore type)) - (let ((fprs (arg-state-fpr-args state)) - (gprs (arg-state-gpr-args state))) - (cond ((< gprs 8) ; and by implication also (< fprs 13) - (incf (arg-state-fpr-args state)) - ;; Assign outgoing FPRs starting at FP1 - ;; - ;; The PowerOpen ABI says float values are stored in float - ;; regs. But if we're calling a varargs function, we also - ;; need to put the float into some gprs. We indicate this - ;; to %alien-funcall ir2-convert by making a list of the - ;; TNs for the float reg and for the int regs. - ;; - (list (make-wired-tn* 'double-float double-reg-sc-number (1+ fprs)) - (int-arg state 'signed-byte-32 signed-reg-sc-number signed-stack-sc-number) - (int-arg state 'unsigned-byte-32 unsigned-reg-sc-number unsigned-stack-sc-number))) - ((< fprs 13) - (incf (arg-state-fpr-args state)) - (list (make-wired-tn* 'double-float double-reg-sc-number (1+ fprs)) - (int-arg state 'signed-byte-32 signed-reg-sc-number signed-stack-sc-number) - (int-arg state 'unsigned-byte-32 unsigned-reg-sc-number unsigned-stack-sc-number))) - (t - ;; Pass on stack only - (let ((stack-offset (arg-state-stack-frame-size state))) - (incf (arg-state-stack-frame-size state) 2) - (make-wired-tn* 'double-float double-stack-sc-number stack-offset)))))) - ;;; Result state handling (defstruct result-state @@ -153,11 +93,6 @@ (0 nl0-offset) (1 nl1-offset))) -;;; FIXME: These #-DARWIN methods should be adjusted to take a state -;;; argument, firstly because that's our "official" API (see -;;; src/code/host-alieneval) and secondly because that way we can -;;; probably have less duplication of code. -- CSR, 2003-07-29 - (define-alien-type-method (system-area-pointer :result-tn) (type state) (declare (ignore type)) (let ((num-results (result-state-num-results state))) @@ -208,10 +143,9 @@ ;;; Sort out long longs, by splitting them up. However, need to take ;;; care about register/stack alignment and whether they will fully ;;; fit into registers or must go on the stack. -#-darwin (deftransform %alien-funcall ((function type &rest args)) - (aver (sb-c::constant-lvar-p type)) - (let* ((type (sb-c::lvar-value type)) + (aver (sb-c:constant-lvar-p type)) + (let* ((type (sb-c:lvar-value type)) (arg-types (alien-fun-type-arg-types type)) (result-type (alien-fun-type-result-type type)) (gprs 0) @@ -304,67 +238,6 @@ ,@(new-args)))))) (sb-c::give-up-ir1-transform)))) -#+darwin -(deftransform %alien-funcall ((function type &rest args)) - (aver (sb-c::constant-lvar-p type)) - (let* ((type (sb-c::lvar-value type)) - (arg-types (alien-fun-type-arg-types type)) - (result-type (alien-fun-type-result-type type))) - (aver (= (length arg-types) (length args))) - ;; We need to do something special for 64-bit integer arguments - ;; and results. - (if (or (some #'(lambda (type) - (and (alien-integer-type-p type) - (> (sb-alien::alien-integer-type-bits type) 32))) - arg-types) - (and (alien-integer-type-p result-type) - (> (sb-alien::alien-integer-type-bits result-type) 32))) - (collect ((new-args) (lambda-vars) (new-arg-types)) - (dolist (type arg-types) - (let ((arg (gensym))) - (lambda-vars arg) - (cond ((and (alien-integer-type-p type) - (> (sb-alien::alien-integer-type-bits type) 32)) - ;; 64-bit long long types are stored in - ;; consecutive locations, most significant word - ;; first (big-endian). - (new-args `(ash ,arg -32)) - (new-args `(logand ,arg #xffffffff)) - (if (alien-integer-type-signed type) - (new-arg-types (parse-alien-type '(signed 32) nil)) - (new-arg-types (parse-alien-type '(unsigned 32) nil))) - (new-arg-types (parse-alien-type '(unsigned 32) nil))) - (t - (new-args arg) - (new-arg-types type))))) - (cond ((and (alien-integer-type-p result-type) - (> (sb-alien::alien-integer-type-bits result-type) 32)) - (let ((new-result-type - (let ((sb-alien::*values-type-okay* t)) - (parse-alien-type - (if (alien-integer-type-signed result-type) - '(values (signed 32) (unsigned 32)) - '(values (unsigned 32) (unsigned 32))) - nil)))) - `(lambda (function type ,@(lambda-vars)) - (declare (ignore type)) - (multiple-value-bind (high low) - (%alien-funcall function - ',(make-alien-fun-type - :arg-types (new-arg-types) - :result-type new-result-type) - ,@(new-args)) - (logior low (ash high 32)))))) - (t - `(lambda (function type ,@(lambda-vars)) - (declare (ignore type)) - (%alien-funcall function - ',(make-alien-fun-type - :arg-types (new-arg-types) - :result-type result-type) - ,@(new-args)))))) - (sb-c::give-up-ir1-transform)))) - (define-vop (foreign-symbol-sap) (:translate foreign-symbol-sap) (:policy :fast-safe) @@ -384,10 +257,9 @@ (:info foreign-symbol) (:results (res :scs (sap-reg))) (:result-types system-area-pointer) - (:temporary (:scs (non-descriptor-reg)) addr) (:generator 2 - (inst lr addr (make-fixup foreign-symbol :foreign-dataref)) - (loadw res addr))) + (inst lr res (make-fixup foreign-symbol :foreign-dataref)) + (loadw res res))) (define-vop (call-out) (:args (function :scs (sap-reg) :target cfunc) @@ -469,20 +341,12 @@ (t `(deref (sap-alien (sap+ ,sap ,offset) (* ,type))))))) - ;;; The "Mach-O Runtime Conventions" document for OS X almost - ;;; specifies the calling convention (it neglects to mention that - ;;; the linkage area is 24 bytes). - #+darwin - (defconstant n-foreign-linkage-area-bytes 24) - ;;; On linux only use 8 bytes for LR and Back chain. JRXR ;;; 2006/11/10. - #-darwin (defconstant n-foreign-linkage-area-bytes 8) ;;; Returns a vector in static space containing machine code for the ;;; callback wrapper. Linux version. JRXR. 2006/11/13 - #-darwin (defun alien-callback-assembler-wrapper (index result-type argument-types) (flet ((make-gpr (n) (make-random-tn :kind :normal :sc (sc-or-lose 'any-reg) :offset n)) @@ -643,8 +507,7 @@ ;; Setup everything. Now save sp, setup the frame. (inst mflr r0) - (inst stw r0 stack-pointer (* 2 n-word-bytes)) ; FIXME: magic - ; constant, copied from Darwin. + (inst stw r0 stack-pointer n-word-bytes) (inst stwu stack-pointer stack-pointer (- frame-size)) ;; And make the call. @@ -659,7 +522,7 @@ ;; We're back! Restore sp and lr, load the ;; return value from just under sp, and return. (inst lwz stack-pointer stack-pointer 0) - (inst lwz r0 stack-pointer (* 2 n-word-bytes)) + (inst lwz r0 stack-pointer n-word-bytes) (inst mtlr r0) (cond ((sb-alien::alien-single-float-type-p result-type) @@ -673,10 +536,10 @@ ) (t (loop with gprs = (mapcar #'make-gpr '(3 4)) - repeat n-return-area-words for gpr = (pop gprs) for offset from (- return-area-pos) by n-word-bytes + repeat n-return-area-words do (unless gpr (bug "Out of return registers in alien-callback trampoline.")) @@ -698,145 +561,4 @@ unsigned-long)) sap (length buffer)) vector)))) - - ;;; Returns a vector in static space containing machine code for the - ;;; callback wrapper - #+darwin - (defun alien-callback-assembler-wrapper (index result-type argument-types) - (flet ((make-gpr (n) - (make-random-tn :kind :normal :sc (sc-or-lose 'any-reg) :offset n)) - (make-fpr (n) - (make-random-tn :kind :normal :sc (sc-or-lose 'double-reg) :offset n))) - (let* ((segment (make-segment))) - (assemble (segment) - ;; To save our arguments, we follow the algorithm sketched in the - ;; "PowerPC Calling Conventions" section of that document. - ;; - ;; CLH: There are a couple problems here. First, we bail if - ;; we run out of registers. AIUI, we can just ignore the extra - ;; args here and we will be ok... - (let ((words-processed 0) - (gprs (mapcar #'make-gpr '(3 4 5 6 7 8 9 10))) - (fprs (mapcar #'make-fpr '(1 2 3 4 5 6 7 8 9 10 11 12 13))) - (stack-pointer (make-gpr 1))) - (labels ((save-arg (type words) - (let ((integerp (not (alien-float-type-p type))) - (offset (+ (* words-processed n-word-bytes) - n-foreign-linkage-area-bytes))) - (cond (integerp - (dotimes (k words) - (let ((gpr (pop gprs))) - (when gpr - (inst stw gpr stack-pointer offset)) - (incf words-processed) - (incf offset n-word-bytes)))) - ;; The handling of floats is a little ugly - ;; because we hard-code the number of words - ;; for single- and double-floats. - ((alien-single-float-type-p type) - (pop gprs) - (let ((fpr (pop fprs))) - (when fpr - (inst stfs fpr stack-pointer offset))) - (incf words-processed)) - ((alien-double-float-type-p type) - (setf gprs (cddr gprs)) - (let ((fpr (pop fprs))) - (when fpr - (inst stfd fpr stack-pointer offset))) - (incf words-processed 2)) - (t - (bug "Unknown alien floating point type: ~S" type)))))) - (mapc #'save-arg - argument-types - (mapcar (lambda (arg) - (ceiling (alien-type-bits arg) n-word-bits)) - argument-types)))) - ;; Set aside room for the return area just below sp, then - ;; actually call funcall3: funcall3 (call-alien-function, - ;; index, args, return-area) - ;; - ;; INDEX is fixnumized, ARGS and RETURN-AREA don't need to be - ;; because they're word-aligned. Kinda gross, but hey ... - (let* ((n-return-area-words - (ceiling (or (alien-type-bits result-type) 0) n-word-bits)) - (n-return-area-bytes (* n-return-area-words n-word-bytes)) - ;; FIXME: magic constant, and probably n-args-bytes - (args-size (* 3 n-word-bytes)) - ;; FIXME: n-frame-bytes? - (frame-size (logandc2 (+ n-foreign-linkage-area-bytes - n-return-area-bytes - args-size - +stack-alignment-bytes+) - +stack-alignment-bytes+))) - (destructuring-bind (sp r0 arg1 arg2 arg3 arg4) - (mapcar #'make-gpr '(1 0 3 4 5 6)) - ;; FIXME: This is essentially the same code as LR in - ;; insts.lisp, but attempting to use (INST LR ...) instead - ;; of this function results in callbacks not working. Why? - ;; --njf, 2006-01-04 - (flet ((load-address-into (reg addr) - (let ((high (ldb (byte 16 16) addr)) - (low (ldb (byte 16 0) addr))) - (inst lis reg high) - (inst ori reg reg low)))) - ;; Setup the args - (load-address-into arg1 (static-fdefn-fun-addr 'enter-alien-callback)) - (loadw arg1 arg1) - (inst li arg2 (fixnumize index)) - (inst addi arg3 sp n-foreign-linkage-area-bytes) - ;; FIXME: This was (- (* RETURN-AREA-SIZE N-WORD-BYTES)), while - ;; RETURN-AREA-SIZE was (* N-RETURN-AREA-WORDS N-WORD-BYTES): - ;; I assume the intention was (- N-RETURN-AREA-BYTES), but who knows? - ;; --NS 2005-06-11 - (inst addi arg4 sp (- n-return-area-bytes)) - ;; FIXME! FIXME FIXME: What does this FIXME refer to? - ;; Save sp, setup the frame - (inst mflr r0) - (inst stw r0 sp (* 2 n-word-bytes)) ; FIXME: magic constant - (inst stwu sp sp (- frame-size)) - ;; Make the call - (load-address-into r0 (foreign-symbol-address "funcall3")) - (inst mtlr r0) - (inst blrl)) - ;; We're back! Restore sp and lr, load the return value from just - ;; under sp, and return. - (inst lwz sp sp 0) - (inst lwz r0 sp (* 2 n-word-bytes)) - (inst mtlr r0) - (cond - ((sb-alien::alien-single-float-type-p result-type) - (let ((f1 (make-fpr 1))) - (inst lfs f1 sp (- (* n-return-area-words n-word-bytes))))) - ((sb-alien::alien-double-float-type-p result-type) - (let ((f1 (make-fpr 1))) - (inst lfd f1 sp (- (* n-return-area-words n-word-bytes))))) - ((sb-alien::alien-void-type-p result-type) - ;; Nothing to do - ) - (t - (loop with gprs = (mapcar #'make-gpr '(3 4)) - repeat n-return-area-words - for gpr = (pop gprs) - for offset from (- (* n-return-area-words n-word-bytes)) - by n-word-bytes - do - (unless gpr - (bug "Out of return registers in alien-callback trampoline.")) - (inst lwz gpr sp offset)))) - (inst blr)))) - (finalize-segment segment) - ;; Now that the segment is done, convert it to a static - ;; vector we can point foreign code to. - (let* ((buffer (sb-assem:segment-buffer segment)) - (vector (make-static-vector (length buffer) - :element-type '(unsigned-byte 8) - :initial-contents buffer)) - (sap (vector-sap vector))) - (alien-funcall - (extern-alien "ppc_flush_icache" - (function void - system-area-pointer - unsigned-long)) - sap (length buffer)) - vector))))) +) diff --git a/src/compiler/ppc/call.lisp b/src/compiler/ppc/call.lisp index 18ecd1f754..a5458d16ff 100644 --- a/src/compiler/ppc/call.lisp +++ b/src/compiler/ppc/call.lisp @@ -39,13 +39,13 @@ ;;; them at a known location. (defun make-old-fp-save-location (env) (specify-save-tn - (physenv-debug-live-tn (make-normal-tn *fixnum-primitive-type*) env) + (environment-debug-live-tn (make-normal-tn *fixnum-primitive-type*) env) (make-wired-tn *fixnum-primitive-type* control-stack-arg-scn ocfp-save-offset))) (defun make-return-pc-save-location (env) (specify-save-tn - (physenv-debug-live-tn (make-normal-tn *backend-t-primitive-type*) env) + (environment-debug-live-tn (make-normal-tn *backend-t-primitive-type*) env) (make-wired-tn *backend-t-primitive-type* control-stack-arg-scn lra-save-offset))) @@ -142,7 +142,7 @@ (move res csp-tn) (inst addi csp-tn csp-tn (* n-word-bytes (sb-allocated-size 'control-stack))) - (when (ir2-physenv-number-stack-p callee) + (when (ir2-environment-number-stack-p callee) (let* ((nbytes (bytes-needed-for-non-descriptor-stack-frame))) (when (> nbytes number-stack-displacement) (inst stwu nsp-tn nsp-tn (- (bytes-needed-for-non-descriptor-stack-frame))) @@ -354,8 +354,7 @@ default-value-8 values-start) (:temporary (:sc any-reg :offset nargs-offset :from :eval :to (:result 1)) - nvals) - (:temporary (:scs (non-descriptor-reg)) temp)) + nvals)) ;;; This hook in the codegen pass lets us insert code before fall-thru entry @@ -1130,7 +1129,7 @@ default-value-8 (inst cmpwi count (fixnumize index)) (move value null-tn) (inst ble done) - (inst lwz value object (ash index word-shift)) + (loadw value object index) done)) ;;; Turn more arg (context, count) into a list. @@ -1159,14 +1158,12 @@ default-value-8 (move result null-tn) (inst beq done) - ;; We need to do this atomically. - (pseudo-atomic (pa-flag :sync nil) + (pseudo-atomic (pa-flag :sync nil :elide-if dx-p) ;; Allocate a cons (2 words) for each item. (if dx-p (progn (align-csp temp) - (inst clrrwi result csp-tn n-lowtag-bits) - (inst ori result result list-pointer-lowtag) + (inst ori result csp-tn list-pointer-lowtag) (move dst result) (inst slwi temp count 1) (inst add csp-tn csp-tn temp)) diff --git a/src/compiler/ppc/cell.lisp b/src/compiler/ppc/cell.lisp index b0404c6279..92555ecbb2 100644 --- a/src/compiler/ppc/cell.lisp +++ b/src/compiler/ppc/cell.lisp @@ -31,10 +31,6 @@ (:generator 1 (storew value object offset lowtag))) -(define-vop (init-slot set-slot) - (:info name dx-p offset lowtag) - (:ignore name dx-p)) - (define-vop (compare-and-swap-slot) (:args (object :scs (descriptor-reg)) (old :scs (descriptor-reg any-reg)) @@ -79,7 +75,7 @@ (inst stwx new thread-base-tn temp) DONT-STORE-TLS - (inst cmpwi result no-tls-value-marker-widetag) + (inst cmpwi result no-tls-value-marker) (inst bne CHECK-UNBOUND)) (inst li temp (- (* symbol-value-slot n-word-bytes) @@ -110,9 +106,8 @@ (:temporary (:scs (descriptor-reg) :from (:argument 0)) obj-temp)) ;;; With SYMBOL-VALUE, we check that the value isn't the trap object. -;;; So SYMBOL-VALUE of NIL is NIL. (define-vop (symbol-global-value checked-cell-ref) - (:translate sym-global-val) + (:translate symbol-global-value) (:generator 9 (move obj-temp object) (loadw value obj-temp symbol-value-slot other-pointer-lowtag) @@ -123,7 +118,7 @@ (define-vop (fast-symbol-global-value cell-ref) (:variant symbol-value-slot other-pointer-lowtag) (:policy :fast) - (:translate sym-global-val)) + (:translate symbol-global-value)) #+sb-thread (progn @@ -134,7 +129,7 @@ (:generator 4 (loadw tls-slot symbol symbol-tls-index-slot other-pointer-lowtag) (inst lwzx temp thread-base-tn tls-slot) - (inst cmpwi temp no-tls-value-marker-widetag) + (inst cmpwi temp no-tls-value-marker) (inst beq GLOBAL-VALUE) (inst stwx value thread-base-tn tls-slot) (inst b DONE) @@ -142,10 +137,9 @@ (storew value symbol symbol-value-slot other-pointer-lowtag) DONE)) - ;; With Symbol-Value, we check that the value isn't the trap object. So - ;; Symbol-Value of NIL is NIL. + ;; With Symbol-Value, we check that the value isn't the trap object. (define-vop (symbol-value) - (:translate symeval) + (:translate symbol-value) (:policy :fast-safe) (:args (object :scs (descriptor-reg) :to (:result 1))) (:results (value :scs (descriptor-reg any-reg))) @@ -154,7 +148,7 @@ (:generator 9 (loadw value object symbol-tls-index-slot other-pointer-lowtag) (inst lwzx value thread-base-tn value) - (inst cmpwi value no-tls-value-marker-widetag) + (inst cmpwi value no-tls-value-marker) (inst bne CHECK-UNBOUND) (loadw value object symbol-value-slot other-pointer-lowtag) CHECK-UNBOUND @@ -168,11 +162,11 @@ ;; unbound", which is used in the implementation of COPY-SYMBOL. -- ;; CSR, 2003-04-22 (:policy :fast) - (:translate symeval) + (:translate symbol-value) (:generator 8 (loadw value object symbol-tls-index-slot other-pointer-lowtag) (inst lwzx value thread-base-tn value) - (inst cmpwi value no-tls-value-marker-widetag) + (inst cmpwi value no-tls-value-marker) (inst bne DONE) (loadw value object symbol-value-slot other-pointer-lowtag) DONE))) @@ -181,36 +175,31 @@ #-sb-thread (progn (define-vop (symbol-value symbol-global-value) - (:translate symeval)) + (:translate symbol-value)) (define-vop (fast-symbol-value fast-symbol-global-value) - (:translate symeval)) + (:translate symbol-value)) (define-vop (set %set-symbol-global-value))) ;;; Like CHECKED-CELL-REF, only we are a predicate to see if the cell ;;; is bound. -(define-vop (boundp-frob) +(define-vop (boundp) (:args (object :scs (descriptor-reg))) (:conditional) (:info target not-p) (:policy :fast-safe) - (:temporary (:scs (descriptor-reg)) value)) - -#+sb-thread -(define-vop (boundp boundp-frob) + (:temporary (:scs (descriptor-reg)) value) (:translate boundp) + #+sb-thread (:generator 9 (loadw value object symbol-tls-index-slot other-pointer-lowtag) (inst lwzx value thread-base-tn value) - (inst cmpwi value no-tls-value-marker-widetag) + (inst cmpwi value no-tls-value-marker) (inst bne CHECK-UNBOUND) (loadw value object symbol-value-slot other-pointer-lowtag) CHECK-UNBOUND (inst cmpwi value unbound-marker-widetag) - (inst b? (if not-p :eq :ne) target))) - -#-sb-thread -(define-vop (boundp boundp-frob) - (:translate boundp) + (inst b? (if not-p :eq :ne) target)) + #-sb-thread (:generator 9 (loadw value object symbol-value-slot other-pointer-lowtag) (inst cmpwi value unbound-marker-widetag) @@ -222,13 +211,15 @@ (:args (symbol :scs (descriptor-reg))) (:results (res :scs (any-reg))) (:result-types positive-fixnum) + (:args-var args) (:generator 2 ;; The symbol-hash slot of NIL holds NIL because it is also the ;; car slot, so we have to strip off the two low bits to make sure ;; it is a fixnum. The lowtag selection magic that is required to ;; ensure this is explained in the comment in objdef.lisp (loadw res symbol symbol-hash-slot other-pointer-lowtag) - (inst clrrwi res res n-fixnum-tag-bits))) + (unless (not-nil-tn-ref-p args) + (inst clrrwi res res n-fixnum-tag-bits)))) ;;;; Fdefinition (fdefn) objects. @@ -275,16 +266,12 @@ (define-vop (fdefn-makunbound) (:policy :fast-safe) (:translate fdefn-makunbound) - (:args (fdefn :scs (descriptor-reg) :target result)) + (:args (fdefn :scs (descriptor-reg))) (:temporary (:scs (non-descriptor-reg)) temp) - (:results (result :scs (descriptor-reg))) (:generator 38 (storew null-tn fdefn fdefn-fun-slot other-pointer-lowtag) (load-asm-rtn-addr temp 'undefined-tramp) - (storew temp fdefn fdefn-raw-addr-slot other-pointer-lowtag) - (move result fdefn))) - - + (storew temp fdefn fdefn-raw-addr-slot other-pointer-lowtag))) ;;;; Binding and Unbinding. @@ -380,14 +367,14 @@ (:variant closure-info-offset fun-pointer-lowtag) (:translate %closure-index-ref)) +(define-vop (%closure-index-set word-index-set) + (:variant closure-info-offset fun-pointer-lowtag) + (:translate %closure-index-set)) + (define-vop (funcallable-instance-info word-index-ref) (:variant funcallable-instance-info-offset fun-pointer-lowtag) (:translate %funcallable-instance-info)) -(define-vop (set-funcallable-instance-info word-index-set) - (:variant funcallable-instance-info-offset fun-pointer-lowtag) - (:translate %set-funcallable-instance-info)) - (define-vop (closure-ref) (:args (object :scs (descriptor-reg))) (:results (value :scs (descriptor-reg any-reg))) @@ -447,6 +434,15 @@ (:translate %instance-cas) (:variant instance-slots-offset instance-pointer-lowtag) (:arg-types instance tagged-num * *)) +(define-vop (%raw-instance-cas/word %instance-cas) + (:args (object) + (index) + (old-value :scs (unsigned-reg)) + (new-value :scs (unsigned-reg))) + (:arg-types * tagged-num unsigned-num unsigned-num) + (:results (result :scs (unsigned-reg) :from :load)) + (:result-types unsigned-num) + (:translate %raw-instance-cas/word)) ;;;; Code object frobbing. @@ -456,12 +452,44 @@ (:policy :fast-safe) (:variant 0 other-pointer-lowtag)) -(define-vop (code-header-set word-index-set) +(define-vop (code-header-set) (:translate code-header-set) (:policy :fast-safe) - (:variant 0 other-pointer-lowtag)) - - + (:args (object :scs (descriptor-reg)) + (index :scs (any-reg)) + (value :scs (any-reg descriptor-reg))) + (:arg-types * tagged-num *) + (:temporary (:scs (non-descriptor-reg)) temp #+gencgc card) + #+gencgc (:temporary (:sc non-descriptor-reg :offset nl3-offset) pa-flag) + (:generator 10 + #+cheneygc + (progn (inst addi temp index (- other-pointer-lowtag)) + (inst stwx value object temp)) + #+gencgc + (progn + ;; Load the card mask + (inst lr temp (make-fixup "gc_card_table_mask" :foreign-dataref)) ; address of linkage entry + (loadw temp temp) ; address of gc_card_table_mask + (inst lwz temp temp 0) ; value of gc_card_table_mask + (pseudo-atomic (pa-flag) + ;; Compute card mark index + ;; Maybe these 2 steps should be one RLWINM, but I'm not that clever. + (inst srawi card object gencgc-card-shift) + (inst and card card temp) + ;; Load mark table base + (inst lr temp (make-fixup "gc_card_mark" :foreign-dataref)) ; address of linkage entry + (loadw temp temp) ; address of gc_card_mark + (loadw temp temp) ; value of gc_card_mark + ;; Touch the card mark byte. + (inst stbx null-tn temp card) + ;; set 'written' flag in the code header + ;; If two threads get here at the same time, they'll write the same byte. + (let ((byte #+big-endian (- other-pointer-lowtag) #+little-endian (bug "Wat"))) + (inst lbz temp object byte) + (inst ori temp temp #x40) + (inst stb temp object byte)) + (inst addi temp index (- other-pointer-lowtag)) + (inst stwx value object temp))))) ;;;; raw instance slot accessors @@ -471,27 +499,19 @@ (macrolet ((def (suffix sc primtype) `(progn - (define-vop (,(symbolicate "RAW-INSTANCE-INIT/" suffix)) - (:args (object :scs (descriptor-reg)) - (value :scs (,sc))) - (:arg-types * ,primtype) - (:info index) - (:generator 4 (inst stw value object (offset-for-raw-slot index)))) - (define-vop (,(symbolicate "RAW-INSTANCE-REF/" suffix) word-index-ref) + (define-vop (,(symbolicate "%RAW-INSTANCE-REF/" suffix) word-index-ref) (:policy :fast-safe) (:translate ,(symbolicate "%RAW-INSTANCE-REF/" suffix)) (:variant instance-slots-offset instance-pointer-lowtag) (:arg-types instance positive-fixnum) (:results (value :scs (,sc))) (:result-types ,primtype)) - (define-vop (,(symbolicate "RAW-INSTANCE-SET/" suffix) word-index-set) + (define-vop (,(symbolicate "%RAW-INSTANCE-SET/" suffix) word-index-set) (:policy :fast-safe) (:translate ,(symbolicate "%RAW-INSTANCE-SET/" suffix)) (:variant instance-slots-offset instance-pointer-lowtag) (:arg-types instance positive-fixnum ,primtype) - (:args (object) (index) (value :scs (,sc))) - (:results (result :scs (,sc))) - (:result-types ,primtype))))) + (:args (object) (index) (value :scs (,sc))))))) (def word unsigned-reg unsigned-num) (def signed-word signed-reg signed-num)) @@ -520,15 +540,7 @@ (inst bne LOOP) (inst isync))) -(define-vop (raw-instance-init/single) - (:args (object :scs (descriptor-reg)) - (value :scs (single-reg))) - (:arg-types * single-float) - (:info index) - (:generator 4 - (inst stfs value object (offset-for-raw-slot index)))) - -(define-vop (raw-instance-ref/single) +(define-vop () (:translate %raw-instance-ref/single) (:policy :fast-safe) (:args (object :scs (descriptor-reg)) @@ -542,32 +554,20 @@ instance-pointer-lowtag)) (inst lfsx value object offset))) -(define-vop (raw-instance-set/single) +(define-vop () (:translate %raw-instance-set/single) (:policy :fast-safe) (:args (object :scs (descriptor-reg)) (index :scs (any-reg)) - (value :scs (single-reg) :target result)) + (value :scs (single-reg))) (:arg-types * positive-fixnum single-float) - (:results (result :scs (single-reg))) - (:result-types single-float) (:temporary (:scs (non-descriptor-reg)) offset) (:generator 5 (inst addi offset index (- (ash instance-slots-offset word-shift) instance-pointer-lowtag)) - (inst stfsx value object offset) - (unless (location= result value) - (inst frsp result value)))) - -(define-vop (raw-instance-init/double) - (:args (object :scs (descriptor-reg)) - (value :scs (double-reg))) - (:arg-types * double-float) - (:info index) - (:generator 4 - (inst stfd value object (offset-for-raw-slot index)))) + (inst stfsx value object offset))) -(define-vop (raw-instance-ref/double) +(define-vop () (:translate %raw-instance-ref/double) (:policy :fast-safe) (:args (object :scs (descriptor-reg)) @@ -581,35 +581,20 @@ instance-pointer-lowtag)) (inst lfdx value object offset))) -(define-vop (raw-instance-set/double) +(define-vop () (:translate %raw-instance-set/double) (:policy :fast-safe) (:args (object :scs (descriptor-reg)) (index :scs (any-reg)) - (value :scs (double-reg) :target result)) + (value :scs (double-reg))) (:arg-types * positive-fixnum double-float) - (:results (result :scs (double-reg))) - (:result-types double-float) (:temporary (:scs (non-descriptor-reg)) offset) (:generator 5 (inst addi offset index (- (ash instance-slots-offset word-shift) instance-pointer-lowtag)) - (inst stfdx value object offset) - (unless (location= result value) - (inst fmr result value)))) + (inst stfdx value object offset))) -(define-vop (raw-instance-init/complex-single) - (:args (object :scs (descriptor-reg)) - (value :scs (complex-single-reg))) - (:arg-types * complex-single-float) - (:info index) - (:generator 4 - (inst stfs (complex-single-reg-real-tn value) - object (offset-for-raw-slot index)) - (inst stfs (complex-single-reg-imag-tn value) - object (offset-for-raw-slot index 1)))) - -(define-vop (raw-instance-ref/complex-single) +(define-vop () (:translate %raw-instance-ref/complex-single) (:policy :fast-safe) (:args (object :scs (descriptor-reg)) @@ -625,43 +610,22 @@ (inst addi offset offset n-word-bytes) (inst lfsx (complex-single-reg-imag-tn value) object offset))) -(define-vop (raw-instance-set/complex-single) +(define-vop () (:translate %raw-instance-set/complex-single) (:policy :fast-safe) (:args (object :scs (descriptor-reg)) (index :scs (any-reg)) - (value :scs (complex-single-reg) :target result)) + (value :scs (complex-single-reg))) (:arg-types * positive-fixnum complex-single-float) - (:results (result :scs (complex-single-reg))) - (:result-types complex-single-float) (:temporary (:scs (non-descriptor-reg)) offset) (:generator 5 (inst addi offset index (- (ash instance-slots-offset word-shift) instance-pointer-lowtag)) - (let ((value-real (complex-single-reg-real-tn value)) - (result-real (complex-single-reg-real-tn result))) - (inst stfsx value-real object offset) - (unless (location= result-real value-real) - (inst frsp result-real value-real))) + (inst stfsx (complex-single-reg-real-tn value) object offset) (inst addi offset offset n-word-bytes) - (let ((value-imag (complex-single-reg-imag-tn value)) - (result-imag (complex-single-reg-imag-tn result))) - (inst stfsx value-imag object offset) - (unless (location= result-imag value-imag) - (inst frsp result-imag value-imag))))) + (inst stfsx (complex-single-reg-imag-tn value) object offset))) -(define-vop (raw-instance-init/complex-double) - (:args (object :scs (descriptor-reg)) - (value :scs (complex-double-reg))) - (:arg-types * complex-double-float) - (:info index) - (:generator 4 - (inst stfd (complex-single-reg-real-tn value) - object (offset-for-raw-slot index)) - (inst stfd (complex-double-reg-imag-tn value) - object (offset-for-raw-slot index 2)))) - -(define-vop (raw-instance-ref/complex-double) +(define-vop () (:translate %raw-instance-ref/complex-double) (:policy :fast-safe) (:args (object :scs (descriptor-reg)) @@ -677,27 +641,17 @@ (inst addi offset offset (* 2 n-word-bytes)) (inst lfdx (complex-double-reg-imag-tn value) object offset))) -(define-vop (raw-instance-set/complex-double) +(define-vop () (:translate %raw-instance-set/complex-double) (:policy :fast-safe) (:args (object :scs (descriptor-reg)) (index :scs (any-reg)) - (value :scs (complex-double-reg) :target result)) + (value :scs (complex-double-reg))) (:arg-types * positive-fixnum complex-double-float) - (:results (result :scs (complex-double-reg))) - (:result-types complex-double-float) (:temporary (:scs (non-descriptor-reg)) offset) (:generator 5 (inst addi offset index (- (ash instance-slots-offset word-shift) instance-pointer-lowtag)) - (let ((value-real (complex-double-reg-real-tn value)) - (result-real (complex-double-reg-real-tn result))) - (inst stfdx value-real object offset) - (unless (location= result-real value-real) - (inst fmr result-real value-real))) + (inst stfdx (complex-double-reg-real-tn value) object offset) (inst addi offset offset (* 2 n-word-bytes)) - (let ((value-imag (complex-double-reg-imag-tn value)) - (result-imag (complex-double-reg-imag-tn result))) - (inst stfdx value-imag object offset) - (unless (location= result-imag value-imag) - (inst fmr result-imag value-imag))))) + (inst stfdx (complex-double-reg-imag-tn value) object offset))) diff --git a/src/compiler/ppc/char.lisp b/src/compiler/ppc/char.lisp index 935ce0b6ed..bc63239bcf 100644 --- a/src/compiler/ppc/char.lisp +++ b/src/compiler/ppc/char.lisp @@ -126,7 +126,7 @@ (:note "inline comparison") (:variant-vars condition not-condition) (:generator 2 - (inst cmplwi x (sb-xc:char-code y)) + (inst cmplwi x (char-code y)) (inst b? (if not-p not-condition condition) target))) (define-vop (fast-char=/character/c character-compare/c) diff --git a/src/compiler/ppc/debug.lisp b/src/compiler/ppc/debug.lisp index d4dc62f5f9..fc679459ed 100644 --- a/src/compiler/ppc/debug.lisp +++ b/src/compiler/ppc/debug.lisp @@ -12,15 +12,15 @@ (in-package "SB-VM") (define-vop () - (:translate sb-di::current-sp) + (:translate current-sp) (:policy :fast-safe) (:results (res :scs (sap-reg))) (:result-types system-area-pointer) (:generator 1 (move res csp-tn))) -(define-vop () - (:translate sb-di::current-fp) +(define-vop (current-fp-sap) + (:translate current-fp) (:policy :fast-safe) (:results (res :scs (sap-reg))) (:result-types system-area-pointer) @@ -43,13 +43,10 @@ (:policy :fast-safe) (:args (sap :scs (sap-reg)) (offset :scs (any-reg)) - (value :scs (descriptor-reg) :target result)) + (value :scs (descriptor-reg))) (:arg-types system-area-pointer positive-fixnum *) - (:results (result :scs (descriptor-reg))) - (:result-types *) (:generator 5 - (inst stwx value sap offset) - (move result value))) + (inst stwx value sap offset))) (define-vop (code-from-mumble) (:policy :fast-safe) diff --git a/src/compiler/ppc/float.lisp b/src/compiler/ppc/float.lisp index 91ddfab72f..28a6d2e90e 100644 --- a/src/compiler/ppc/float.lisp +++ b/src/compiler/ppc/float.lisp @@ -849,68 +849,3 @@ (:translate imagpart) (:note "complex double float imagpart") (:variant :imag)) - -;; This vop and the next are intended to be used only for moving a -;; float to an integer arg location (register or stack) for C callout. -;; See %alien-funcall ir2convert in aliencomp.lisp. - -#+darwin -(define-vop (move-double-to-int-arg) - (:args (float :scs (double-reg))) - (:results (hi-bits :scs (signed-reg signed-stack)) - (lo-bits :scs (unsigned-reg unsigned-stack))) - (:temporary (:scs (double-stack)) stack-temp) - (:temporary (:scs (signed-reg)) temp) - (:arg-types double-float) - (:result-types signed-num unsigned-num) - (:policy :fast-safe) - (:vop-var vop) - (:generator 5 - (sc-case float - (double-reg - (inst stfd float (current-nfp-tn vop) - (tn-byte-offset stack-temp)) - (sc-case hi-bits - (signed-reg - (inst lwz hi-bits (current-nfp-tn vop) - (tn-byte-offset stack-temp))) - (signed-stack - (inst lwz temp (current-nfp-tn vop) - (tn-byte-offset stack-temp)) - (inst stw temp nsp-tn - (tn-byte-offset hi-bits)))) - (sc-case lo-bits - (unsigned-reg - (inst lwz lo-bits (current-nfp-tn vop) - (* (1+ (tn-offset stack-temp)) n-word-bytes))) - (unsigned-stack - (inst lwz temp (current-nfp-tn vop) - (* (1+ (tn-offset stack-temp)) n-word-bytes)) - (inst stw temp nsp-tn - (tn-byte-offset lo-bits)))))))) - -#+darwin -(define-vop (move-single-to-int-arg) - (:args (float :scs (single-reg))) - (:results (bits :scs (signed-reg signed-stack))) - (:temporary (:scs (double-stack)) stack-temp) - (:temporary (:scs (signed-reg)) temp) - (:arg-types single-float) - (:result-types signed-num) - (:policy :fast-safe) - (:vop-var vop) - (:generator 5 - (sc-case float - (single-reg - (inst stfs float (current-nfp-tn vop) - (tn-byte-offset stack-temp)) - (sc-case bits - (signed-reg - (inst lwz bits (current-nfp-tn vop) - (tn-byte-offset stack-temp))) - (signed-stack - (inst lwz temp (current-nfp-tn vop) - (tn-byte-offset stack-temp)) - (inst stw temp nsp-tn - (tn-byte-offset bits)))))))) - diff --git a/src/compiler/ppc/macros.lisp b/src/compiler/ppc/macros.lisp index 2f9548c3a5..51fbd534a1 100644 --- a/src/compiler/ppc/macros.lisp +++ b/src/compiler/ppc/macros.lisp @@ -22,7 +22,7 @@ (defmacro load-asm-rtn-addr (reg name) ;; Gencgc has asm code in static space and we can reference it relative to NIL. - #+gencgc `(inst addi ,reg null-tn (make-fixup ,name :asm-routine-nil-offset)) + #+gencgc `(inst addi ,reg null-tn (make-fixup ,name :assembly-routine*)) ;; Cheneygc has asm code in read-only space which is not within ;; a sufficiently small displacement. #+cheneygc `(inst lr ,reg (make-fixup ,name :assembly-routine))) @@ -143,105 +143,6 @@ ((control-stack) (loadw ,n-reg cfp-tn (tn-offset ,n-stack)))))))) - -;;;; Storage allocation: - -;;; This is the main mechanism for allocating memory in the lisp heap. -;;; -;;; The allocated space is stored in RESULT-TN with the lowtag LOWTAG -;;; applied. The amount of space to be allocated is SIZE bytes (which -;;; must be a multiple of the lisp object size). -;;; -;;; On other platforms (Non-PPC), if STACK-P is given, then allocation -;;; occurs on the control stack (for dynamic-extent). In this case, -;;; you MUST also specify NODE, so that the appropriate compiler -;;; policy can be used, and TEMP-TN, which is needed for work-space. -;;; TEMP-TN MUST be a non-descriptor reg. FIXME: This is not yet -;;; implemented on PPC. We should implement this and replace the -;;; inline stack-based allocation that presently occurs in the -;;; VOPs. The stack-p argument is ignored on PPC. -;;; -;;; If generational GC is enabled, you MUST supply a value for TEMP-TN -;;; because a temp register is needed to do inline allocation. -;;; TEMP-TN, in this case, can be any register, since it holds a -;;; double-word aligned address (essentially a fixnum). -(defun allocation (type size lowtag result-tn &key stack-p node temp-tn flag-tn) - ;; We assume we're in a pseudo-atomic so the pseudo-atomic bit is - ;; set. If the lowtag also has a 1 bit in the same position, we're all - ;; set. Otherwise, we need to zap out the lowtag from alloc-tn, and - ;; then or in the lowtag. - ;; Normal allocation to the heap. - (declare (ignore stack-p node) - (ignorable type temp-tn flag-tn)) - #-gencgc - (progn - (if (logbitp (1- n-lowtag-bits) lowtag) - (progn - (inst ori result-tn alloc-tn lowtag)) - (progn - (inst clrrwi result-tn alloc-tn n-lowtag-bits) - (inst ori result-tn result-tn lowtag))) - (if (numberp size) - (inst addi alloc-tn alloc-tn size) - (inst add alloc-tn alloc-tn size))) - #+gencgc - (binding* ((imm-size (typep size '(unsigned-byte 15))) - ((region-base-tn field-offset) - #-sb-thread (values null-tn - (- (+ static-space-start - ;; skip over the array header - (* 2 n-word-bytes)) - nil-value)) - #+sb-thread (values thread-base-tn - (* thread-alloc-region-slot n-word-bytes)))) - - (unless imm-size ; Make temp-tn be the size - (if (numberp size) - (inst lr temp-tn size) - (move temp-tn size))) - - (inst lwz result-tn region-base-tn field-offset) - (inst lwz flag-tn region-base-tn (+ field-offset n-word-bytes)) ; region->end_addr - - (without-scheduling () - ;; CAUTION: The C code depends on the exact order of - ;; instructions here. In particular, immediately before the - ;; TW instruction must be an ADD or ADDI instruction, so it - ;; can figure out the size of the desired allocation and - ;; storing the new base pointer back to the allocation region - ;; must take two instructions (one on threaded targets). - - ;; Now make result-tn point at the end of the object, to - ;; figure out if we overflowed the current region. - (if imm-size - (inst addi result-tn result-tn size) - (inst add result-tn result-tn temp-tn)) - - ;; result-tn points to the new end of the region. Did we go past - ;; the actual end of the region? If so, we need a full alloc. - ;; The C code depends on this exact form of instruction. If - ;; either changes, you have to change the other appropriately! - ;; See the ppc64 file for more explanation about this. - ;; (Or better yet, merge the two codebases) - (inst tw (if (eq type 'list) :lgt :lge) result-tn flag-tn) - - ;; The C code depends on this instruction sequence taking up - ;; one machine instruction. - (inst stw result-tn region-base-tn field-offset)) - - ;; Should the allocation trap above have fired, the runtime - ;; arranges for execution to resume here, just after where we - ;; would have updated the free pointer in the alloc region. - - ;; At this point, result-tn points at the end of the object. - ;; Adjust to point to the beginning. - (cond (imm-size - (inst addi result-tn result-tn (+ (- size) lowtag))) - (t - (inst sub result-tn result-tn temp-tn) - ;; Set the lowtag appropriately - (inst ori result-tn result-tn lowtag))))) - (defmacro with-fixed-allocation ((result-tn flag-tn temp-tn type-code size &key (lowtag other-pointer-lowtag) stack-allocate-p) @@ -259,23 +160,15 @@ (align-csp ,temp-tn) (inst ori ,result-tn csp-tn ,lowtag) (inst addi csp-tn csp-tn (pad-data-block ,size))) - (allocation nil (pad-data-block ,size) ,lowtag ,result-tn + (allocation nil + (* (pad-data-block ,size) + #+bignum-assertions (if (eql ,type-code bignum-widetag) 2 1)) + ,lowtag ,result-tn :temp-tn ,temp-tn :flag-tn ,flag-tn)) - (when ,type-code - (inst lr ,temp-tn (compute-object-header ,size ,type-code)) - (storew ,temp-tn ,result-tn 0 ,lowtag)) + (inst lr ,temp-tn (compute-object-header ,size ,type-code)) + (storew ,temp-tn ,result-tn 0 ,lowtag) ,@body))) - -(defun align-csp (temp) - ;; is used for stack allocation of dynamic-extent objects - (let ((aligned (gen-label))) - (inst andi. temp csp-tn lowtag-mask) - (inst beq aligned) - (inst addi csp-tn csp-tn n-word-bytes) - (storew zero-tn csp-tn -1) - (emit-label aligned))) - ;;;; Error Code (defun emit-error-break (vop kind code values) @@ -298,43 +191,18 @@ ;;;; PSEUDO-ATOMIC -;;; handy macro for making sequences look atomic -;;; -;;; FLAG-TN must be wired to NL3. If a deferred interrupt happens -;;; while we have the low bits of ALLOC-TN set, we add a "large" -;;; constant to FLAG-TN. On exit, we add FLAG-TN to ALLOC-TN which (a) -;;; aligns ALLOC-TN again and (b) makes ALLOC-TN go negative. We then -;;; trap if ALLOC-TN's negative (handling the deferred interrupt) and -;;; using FLAG-TN - minus the large constant - to correct ALLOC-TN. -(defmacro pseudo-atomic ((flag-tn &key (sync t)) &body forms) - (declare (ignorable sync)) - #+sb-safepoint-strictly - `(progn ,flag-tn ,@forms (emit-safepoint)) - #-sb-safepoint-strictly +;;; handy macro for making sequences look atomic with respect to GC +(defmacro pseudo-atomic ((flag-tn &key elide-if (sync #+sb-thread t)) &body forms) `(progn - (without-scheduling () - ;; Extra debugging stuff: - #+debug - (progn - (inst andi. ,flag-tn alloc-tn lowtag-mask) - (inst twi :ne ,flag-tn 0)) - (inst ori alloc-tn alloc-tn pseudo-atomic-flag)) + (unless ,elide-if + (without-scheduling () + (inst stb null-tn thread-base-tn (* n-word-bytes thread-pseudo-atomic-bits-slot)))) ,@forms - #+sb-thread - (when ,sync - (inst sync)) - (without-scheduling () - (inst subi alloc-tn alloc-tn pseudo-atomic-flag) - ;; Now test to see if the pseudo-atomic interrupted bit is set. - (inst andi. ,flag-tn alloc-tn pseudo-atomic-interrupted-flag) - (inst twi :ne ,flag-tn 0)) - #+debug - (progn - (inst andi. ,flag-tn alloc-tn lowtag-mask) - (inst twi :ne ,flag-tn 0)) - #+sb-safepoint - (emit-safepoint))) - -#+sb-safepoint -(defun emit-safepoint () - (inst lwz zero-tn null-tn (- (+ gc-safepoint-trap-offset n-word-bytes other-pointer-lowtag)))) + (unless ,elide-if + (when ,sync ; why??? + (inst sync)) + (without-scheduling () + (inst stb thread-base-tn thread-base-tn (* n-word-bytes thread-pseudo-atomic-bits-slot)) + ;; Now test to see if the pseudo-atomic interrupted bit is set. + (inst lhz ,flag-tn thread-base-tn (+ 2 (* n-word-bytes thread-pseudo-atomic-bits-slot))) + (inst twi :ne ,flag-tn 0))))) diff --git a/src/compiler/ppc/memory.lisp b/src/compiler/ppc/memory.lisp index 94c8e77da5..ce051daa60 100644 --- a/src/compiler/ppc/memory.lisp +++ b/src/compiler/ppc/memory.lisp @@ -34,17 +34,16 @@ ;;;; Indexed references: ;;; Define some VOPs for indexed memory reference. -(defmacro define-indexer (name write-p ri-op rr-op shift &optional sign-extend-byte) +(defmacro define-indexer (name write-p ri-op rr-op shift &key sign-extend-byte) `(define-vop (,name) (:args (object :scs (descriptor-reg)) (index :scs (any-reg zero immediate)) - ,@(when write-p - '((value :scs (any-reg descriptor-reg) :target result)))) + ,@(when write-p '((value :scs (any-reg descriptor-reg))))) (:arg-types * tagged-num ,@(when write-p '(*))) (:temporary (:scs (non-descriptor-reg)) temp) - (:results (,(if write-p 'result 'value) - :scs (any-reg descriptor-reg))) - (:result-types *) + ,@(unless write-p + `((:results (value :scs (any-reg descriptor-reg))) + (:result-types *))) (:variant-vars offset lowtag) (:policy :fast-safe) (:generator 5 @@ -69,18 +68,17 @@ (- (ash offset word-shift) lowtag)) (inst ,rr-op value object temp))) ,@(when sign-extend-byte - `((inst extsb value value))) - ,@(when write-p - '((move result value)))))) + `((inst extsb value value)))))) -(define-indexer word-index-ref nil lwz lwzx 0) -(define-indexer word-index-set t stw stwx 0) -(define-indexer halfword-index-ref nil lhz lhzx 1) +(define-indexer word-index-ref nil lwz lwzx 0) +(define-indexer halfword-index-ref nil lhz lhzx 1) (define-indexer signed-halfword-index-ref nil lha lhax 1) -(define-indexer halfword-index-set t sth sthx 1) -(define-indexer byte-index-ref nil lbz lbzx 2) -(define-indexer signed-byte-index-ref nil lbz lbzx 2 t) -(define-indexer byte-index-set t stb stbx 2) +(define-indexer byte-index-ref nil lbz lbzx 2) +(define-indexer signed-byte-index-ref nil lbz lbzx 2 :sign-extend-byte t) + +(define-indexer word-index-set t stw stwx 0) +(define-indexer halfword-index-set t sth sthx 1) +(define-indexer byte-index-set t stb stbx 2) (define-vop (word-index-cas) (:args (object :scs (descriptor-reg)) diff --git a/src/compiler/ppc/move.lisp b/src/compiler/ppc/move.lisp index c85270e0cf..a98493a9bd 100644 --- a/src/compiler/ppc/move.lisp +++ b/src/compiler/ppc/move.lisp @@ -203,7 +203,7 @@ (inst addo. temp temp temp) ; set CR0 SO if any top three bits differ (inst slwi y x n-fixnum-tag-bits) ; assume fixnum (tagged ok, maybe lost some high bits) (inst bns done) - (load-constant vop (emit-constant (1+ sb-xc:most-positive-fixnum)) + (load-constant vop (emit-constant (1+ most-positive-fixnum)) y) DONE)) @@ -215,7 +215,7 @@ (inst addo. temp temp temp) ; set CR0 SO if any top three bits differ (inst slwi y x n-fixnum-tag-bits) ; assume fixnum (tagged ok, maybe lost some high bits) (inst bns done) - (load-constant vop (emit-constant (1- sb-xc:most-negative-fixnum)) + (load-constant vop (emit-constant (1- most-negative-fixnum)) y) DONE)) diff --git a/src/compiler/ppc/nlx.lisp b/src/compiler/ppc/nlx.lisp index e1e48c533d..92790352e7 100644 --- a/src/compiler/ppc/nlx.lisp +++ b/src/compiler/ppc/nlx.lisp @@ -214,6 +214,18 @@ (inst b defaulting-done)))))) (load-stack-tn csp-tn sp))) +(define-vop (nlx-entry-single) + (:args (sp) + (value)) + (:results (res :from :load)) + (:info label) + (:save-p :force-to-stack) + (:vop-var vop) + (:generator 30 + (emit-return-pc label) + (note-this-location vop :non-local-entry) + (move res value) + (load-stack-tn csp-tn sp))) (define-vop (nlx-entry-multiple) (:args (top :target result) (src) (count)) diff --git a/src/compiler/ppc/parms.lisp b/src/compiler/ppc/parms.lisp index e362ecf2fe..9e288af7e4 100644 --- a/src/compiler/ppc/parms.lisp +++ b/src/compiler/ppc/parms.lisp @@ -34,7 +34,7 @@ ;;; The size in bytes of GENCGC cards, i.e. the granularity at which ;;; writes to old generations are logged. With mprotect-based write ;;; barriers, this must be a multiple of the OS page size. -(defconstant gencgc-card-bytes +backend-page-bytes+) +(defconstant gencgc-page-bytes +backend-page-bytes+) ;;; The minimum size of new allocation regions. While it doesn't ;;; currently make a lot of sense to have a card size lower than ;;; the alloc granularity, it will, once we are smarter about finding @@ -51,33 +51,6 @@ ;;; address space) (defconstant n-machine-word-bits 32) -;;; flags for the generational garbage collector -(defconstant pseudo-atomic-interrupted-flag 1) -(defconstant pseudo-atomic-flag 4) - -(defconstant float-sign-shift 31) - -(defconstant single-float-bias 126) -(defconstant-eqx single-float-exponent-byte (byte 8 23) #'equalp) -(defconstant-eqx single-float-significand-byte (byte 23 0) #'equalp) -(defconstant single-float-normal-exponent-min 1) -(defconstant single-float-normal-exponent-max 254) -(defconstant single-float-hidden-bit (ash 1 23)) - -(defconstant double-float-bias 1022) -(defconstant-eqx double-float-exponent-byte (byte 11 20) #'equalp) -(defconstant-eqx double-float-significand-byte (byte 20 0) #'equalp) -(defconstant double-float-normal-exponent-min 1) -(defconstant double-float-normal-exponent-max #x7FE) -(defconstant double-float-hidden-bit (ash 1 20)) - -(defconstant single-float-digits - (+ (byte-size single-float-significand-byte) 1)) - -(defconstant double-float-digits - (+ (byte-size double-float-significand-byte) n-word-bits 1)) - - (defconstant float-inexact-trap-bit (ash 1 0)) (defconstant float-divide-by-zero-trap-bit (ash 1 1)) (defconstant float-underflow-trap-bit (ash 1 2)) @@ -112,64 +85,16 @@ ;;;; Where to put the different spaces. -;;; On non-gencgc we need large dynamic and static spaces for PURIFY -#-gencgc -(progn - (defconstant read-only-space-start #x04000000) - (defconstant read-only-space-end #x07ff8000) - (defconstant static-space-start #x08000000) - (defconstant static-space-end #x097fff00) - - (defconstant linkage-table-space-start #x0a000000) - (defconstant linkage-table-space-end #x0b000000)) - -;;; While on gencgc we don't. -#+gencgc (!gencgc-space-setup #x04000000 :read-only-space-size 0 :dynamic-space-start #+linux #x4f000000 #+netbsd #x4f000000 - #+openbsd #x4f000000 - #+darwin #x10000000) - -(defconstant linkage-table-growth-direction :up) -(defconstant linkage-table-entry-size 16) - -#+linux -(progn - #-gencgc - (progn - (defparameter dynamic-0-space-start #x4f000000) - (defparameter dynamic-0-space-end #x66fff000))) - -#+netbsd -(progn - #-gencgc - (progn - (defparameter dynamic-0-space-start #x4f000000) - (defparameter dynamic-0-space-end #x66fff000))) - -;;; Text and data segments start at #x01800000. Range for randomized -;;; malloc() starts #x20000000 (MAXDSIZ) after end of data seg and -;;; extends 256 MB. Use 512 - 64 MB for dynamic space so we can run -;;; under default resource limits. -;;; FIXME: MAXDSIZ is a kernel parameter, and can vary as high as 1GB. -;;; These parameters should probably be tested under such a configuration, -;;; as rare as it might or might not be. -#+openbsd -(progn - #-gencgc - (progn - (defparameter dynamic-0-space-start #x4f000000) - (defparameter dynamic-0-space-end #x5cfff000))) - -#+darwin -(progn - #-gencgc - (progn - (defparameter dynamic-0-space-start #x10000000) - (defparameter dynamic-0-space-end #x3ffff000))) + #+openbsd #x4f000000) + +(defconstant alien-linkage-table-growth-direction :up) +(defconstant alien-linkage-table-entry-size 16) + (defenum (:start 8) halt-trap diff --git a/src/compiler/ppc/sap.lisp b/src/compiler/ppc/sap.lisp index d91d3160ec..14384c8260 100644 --- a/src/compiler/ppc/sap.lisp +++ b/src/compiler/ppc/sap.lisp @@ -136,11 +136,9 @@ ;;;; mumble-SYSTEM-REF and mumble-SYSTEM-SET (macrolet ((def-system-ref-and-set (ref-name set-name sc type size &optional signed) - (let ((ref-name-c (symbolicate ref-name "-C")) - (set-name-c (symbolicate set-name "-C"))) - `(progn + `(progn (define-vop (,ref-name) - (:translate ,ref-name) + (:translate ,ref-name) (:policy :fast-safe) (:args (sap :scs (sap-reg)) (offset :scs (signed-reg))) @@ -157,8 +155,8 @@ result sap offset) ,@(when (and (eq size :byte) signed) '((inst extsb result result))))) - (define-vop (,ref-name-c) - (:translate ,ref-name) + (define-vop (,(symbolicate ref-name "-C")) + (:translate ,ref-name) (:policy :fast-safe) (:args (sap :scs (sap-reg))) (:arg-types system-area-pointer (:constant (signed-byte 16))) @@ -176,14 +174,12 @@ ,@(when (and (eq size :byte) signed) '((inst extsb result result))))) (define-vop (,set-name) - (:translate ,set-name) + (:translate ,set-name) (:policy :fast-safe) - (:args (sap :scs (sap-reg)) - (offset :scs (signed-reg)) - (value :scs (,sc) :target result)) - (:arg-types system-area-pointer signed-num ,type) - (:results (result :scs (,sc))) - (:result-types ,type) + (:args (value :scs (,sc)) + (sap :scs (sap-reg)) + (offset :scs (signed-reg))) + (:arg-types ,type system-area-pointer signed-num) (:generator 5 (inst ,(ecase size (:byte 'stbx) @@ -191,24 +187,14 @@ (:long 'stwx) (:single 'stfsx) (:double 'stfdx)) - value sap offset) - (unless (location= result value) - ,@(case size - (:single - '((inst frsp result value))) - (:double - '((inst fmr result value))) - (t - '((inst mr result value))))))) - (define-vop (,set-name-c) - (:translate ,set-name) + value sap offset))) + (define-vop (,(symbolicate set-name "-C")) + (:translate ,set-name) (:policy :fast-safe) - (:args (sap :scs (sap-reg)) - (value :scs (,sc) :target result)) - (:arg-types system-area-pointer (:constant (signed-byte 16)) ,type) + (:args (value :scs (,sc)) + (sap :scs (sap-reg))) + (:arg-types ,type system-area-pointer (:constant (signed-byte 16))) (:info offset) - (:results (result :scs (,sc))) - (:result-types ,type) (:generator 4 (inst ,(ecase size (:byte 'stb) @@ -216,15 +202,7 @@ (:long 'stw) (:single 'stfs) (:double 'stfd)) - value sap offset) - (unless (location= result value) - ,@(case size - (:single - '((inst frsp result value))) - (:double - '((inst fmr result value))) - (t - '((inst mr result value))))))))))) + value sap offset)))))) (def-system-ref-and-set sap-ref-8 %set-sap-ref-8 unsigned-reg positive-fixnum :byte nil) (def-system-ref-and-set signed-sap-ref-8 %set-signed-sap-ref-8 diff --git a/src/compiler/ppc/system.lisp b/src/compiler/ppc/system.lisp index b2f8c63860..89e54a408b 100644 --- a/src/compiler/ppc/system.lisp +++ b/src/compiler/ppc/system.lisp @@ -48,6 +48,33 @@ DONE)) +(define-vop () + (:translate sb-c::%structure-is-a) + (:args (x :scs (descriptor-reg))) + (:arg-types * (:constant t)) + (:policy :fast-safe) + (:conditional) + ;; "extra" info in conditional vops follows the 2 super-magical info args + (:info target not-p test-layout) + (:temporary (:scs (non-descriptor-reg)) this-id that-id) + (:generator 4 + (let ((test-id (layout-id test-layout)) + (offset (+ (id-bits-offset) + (ash (- (wrapper-depthoid test-layout) 2) 2) + (- instance-pointer-lowtag)))) + (inst lwz this-id x offset) + ;; Always prefer 'cmpwi' if compiling to memory. + ;; 8-bit IDs are permanently assigned, so no fixup ever needed for those. + (cond ((or (typep test-id '(and (signed-byte 8) (not (eql 0)))) + (and (not (sb-c::producing-fasl-file)) + (typep test-id '(signed-byte 16)))) + (inst cmpwi this-id test-id)) + (t + (inst lwz that-id code-tn + (register-inline-constant `(:layout-id . ,test-layout) :word)) + (inst cmpw this-id that-id)))) + (inst b? (if not-p :ne :eq) target))) + (define-vop (%other-pointer-widetag) (:translate %other-pointer-widetag) (:policy :fast-safe) @@ -57,8 +84,8 @@ (:generator 6 (load-type result object (- other-pointer-lowtag)))) -(define-vop (fun-subtype) - (:translate fun-subtype) +(define-vop () + (:translate %fun-pointer-widetag) (:policy :fast-safe) (:args (function :scs (descriptor-reg))) (:results (result :scs (unsigned-reg))) @@ -79,10 +106,9 @@ (define-vop (set-header-data) (:translate set-header-data) (:policy :fast-safe) - (:args (x :scs (descriptor-reg) :target res) + (:args (x :scs (descriptor-reg)) (data :scs (any-reg immediate zero))) (:arg-types * positive-fixnum) - (:results (res :scs (descriptor-reg))) (:temporary (:scs (non-descriptor-reg)) t1 t2) (:generator 6 (loadw t1 x 0 other-pointer-lowtag) @@ -99,8 +125,7 @@ (inst lr t2 val) (inst or t1 t1 t2))))) (zero)) - (storew t1 x 0 other-pointer-lowtag) - (move res x))) + (storew t1 x 0 other-pointer-lowtag))) (define-vop (pointer-hash) @@ -114,14 +139,6 @@ ;;;; Allocation -(define-vop (dynamic-space-free-pointer) - (:results (int :scs (sap-reg))) - (:result-types system-area-pointer) - (:translate dynamic-space-free-pointer) - (:policy :fast-safe) - (:generator 1 - (move int alloc-tn))) - (define-vop (binding-stack-pointer-sap) (:results (int :scs (sap-reg))) (:result-types system-area-pointer) @@ -259,3 +276,11 @@ (:translate spin-loop-hint) (:policy :fast-safe) (:generator 0)) + +(define-vop (sb-c::mark-covered) + (:info index) + (:temporary (:sc unsigned-reg) tmp) + (:generator 4 + ;; Can't convert index to a code-relative index until the boxed header length + ;; has been determined. + (inst store-coverage-mark index tmp))) diff --git a/src/compiler/ppc/type-vops.lisp b/src/compiler/ppc/type-vops.lisp index c69085f689..164c9d735c 100644 --- a/src/compiler/ppc/type-vops.lisp +++ b/src/compiler/ppc/type-vops.lisp @@ -109,7 +109,7 @@ (define-vop (signed-byte-32-p type-predicate) (:translate signed-byte-32-p) - (:generator 45 + (:generator 10 (let ((not-target (gen-label))) (multiple-value-bind (yep nope) @@ -131,7 +131,7 @@ (define-vop (unsigned-byte-32-p type-predicate) (:translate unsigned-byte-32-p) - (:generator 45 + (:generator 10 (let ((not-target (gen-label)) (single-word (gen-label)) (fixnum (gen-label))) diff --git a/src/compiler/ppc/values.lisp b/src/compiler/ppc/values.lisp index 205d322866..aefed663af 100644 --- a/src/compiler/ppc/values.lisp +++ b/src/compiler/ppc/values.lisp @@ -56,11 +56,12 @@ ;;; operand, but this seems unworthwhile. ;;; (define-vop (push-values) - (:args (vals :more t)) + (:args (vals :more t :scs (descriptor-reg any-reg control-stack))) (:results (start :scs (any-reg) :from :load) (count :scs (any-reg))) (:info nvals) (:temporary (:scs (descriptor-reg)) temp) + (:vop-var vop) (:generator 20 (inst mr start csp-tn) (inst addi csp-tn csp-tn (* nvals n-word-bytes)) @@ -69,10 +70,13 @@ ((null val)) (let ((tn (tn-ref-tn val))) (sc-case tn - (descriptor-reg + ((descriptor-reg any-reg) (storew tn start i)) (control-stack (load-stack-tn temp tn) + (storew temp start i)) + (constant + (load-constant vop tn temp) (storew temp start i))))) (inst lr count (fixnumize nvals)))) @@ -116,9 +120,8 @@ ;;; (define-vop (%more-arg-values) (:args (context :scs (descriptor-reg any-reg) :target src) - (skip :scs (any-reg zero immediate)) (num :scs (any-reg) :target count)) - (:arg-types * positive-fixnum positive-fixnum) + (:arg-types * positive-fixnum) (:temporary (:sc any-reg :from (:argument 0)) src) (:temporary (:sc any-reg :from (:argument 2)) dst) (:temporary (:sc descriptor-reg :from (:argument 1)) temp) @@ -126,13 +129,7 @@ (:results (start :scs (any-reg)) (count :scs (any-reg))) (:generator 20 - (sc-case skip - (zero - (inst mr src context)) - (immediate - (inst addi src context (* (tn-value skip) n-word-bytes))) - (any-reg - (inst add src context skip))) + (move src context) (inst mr. count num) (inst mr start csp-tn) (inst beq done) diff --git a/src/compiler/ppc/vm.lisp b/src/compiler/ppc/vm.lisp index 4bccc28ca2..966c6df227 100644 --- a/src/compiler/ppc/vm.lisp +++ b/src/compiler/ppc/vm.lisp @@ -11,6 +11,8 @@ (in-package "SB-VM") +(defconstant-eqx +fixup-kinds+ #(:absolute :layout-id :b :ba :ha :l) #'equalp) + ;;; NUMBER-STACK-DISPLACEMENT ;;; ;;; The number of bytes reserved above the number stack pointer. These @@ -18,8 +20,7 @@ ;;; work. This must be a power of 2 - see BYTES-REQUIRED-FOR-NUMBER-STACK. ;;; (defconstant number-stack-displacement - (* #-darwin 2 - #+darwin 8 + (* 2 n-word-bytes)) ;;;; Define the registers @@ -51,17 +52,12 @@ (defreg nl6 9) (defreg fdefn 10) (defreg nargs 11) - ;; FIXME: some kind of comment here would be nice. - ;; - ;; FIXME II: this also reveals the need to autogenerate lispregs.h - #+darwin (defreg cfunc 12) - #-darwin (defreg nfp 12) - #+darwin (defreg nfp 13) - #-darwin (defreg cfunc 13) + (defreg nfp 12) + (defreg cfunc 13) (defreg bsp 14) (defreg cfp 15) (defreg csp 16) - (defreg alloc 17) + (defreg thread 17) (defreg null 18) (defreg code 19) (defreg cname 20) @@ -74,19 +70,19 @@ (defreg a3 27) (defreg l0 28) (defreg l1 29) - (defreg #-sb-thread l2 #+sb-thread thread 30) + (defreg l2 30) (defreg lip 31) (defregset non-descriptor-regs nl0 nl1 nl2 nl3 nl4 nl5 nl6 cfunc nargs nfp) (defregset descriptor-regs - fdefn a0 a1 a2 a3 ocfp lra cname lexenv l0 l1 #-sb-thread l2 ) + fdefn a0 a1 a2 a3 ocfp lra cname lexenv l0 l1 l2) (defregset boxed-regs fdefn code cname lexenv ocfp lra a0 a1 a2 a3 - l0 l1 #-sb-thread l2 #+sb-thread thread) + l0 l1 l2) (defregset *register-arg-offsets* a0 a1 a2 a3) @@ -244,7 +240,6 @@ (defregtn lip interior-reg) (defregtn null descriptor-reg) (defregtn code descriptor-reg) - (defregtn alloc any-reg) (defregtn lra descriptor-reg) (defregtn lexenv descriptor-reg) @@ -263,7 +258,7 @@ zero-sc-number) (null null-sc-number) - ((or (integer #.sb-xc:most-negative-fixnum #.sb-xc:most-positive-fixnum) + ((or (integer #.most-negative-fixnum #.most-positive-fixnum) character) immediate-sc-number) (symbol @@ -307,7 +302,6 @@ :offset n)) *register-arg-offsets*)) -#+sb-thread (defparameter thread-base-tn (make-random-tn :kind :normal :sc (sc-or-lose 'unsigned-reg) :offset thread-offset)) @@ -364,8 +358,8 @@ (destructuring-bind (size posn integer) (sb-c::basic-combination-args node) (declare (ignore integer)) - (<= (+ (sb-c::lvar-value size) - (sb-c::lvar-value posn)) + (<= (+ (sb-c:lvar-value size) + (sb-c:lvar-value posn)) width))))) (if (or (validp 'fixnum 29) (validp '(signed-byte 32) 32) diff --git a/src/compiler/ppc64/alloc.lisp b/src/compiler/ppc64/alloc.lisp index 9e4f4a6c94..6c49b49ada 100644 --- a/src/compiler/ppc64/alloc.lisp +++ b/src/compiler/ppc64/alloc.lisp @@ -10,30 +10,111 @@ ;;;; files for more information. (in-package "SB-VM") + +;;;; Storage allocation: + +;;; This is the main mechanism for allocating memory in the lisp heap. +;;; +;;; The allocated space is stored in RESULT-TN with the lowtag LOWTAG +;;; applied. The amount of space to be allocated is SIZE bytes (which +;;; must be a multiple of the lisp object size). +;;; +;;; On other platforms (Non-PPC), if STACK-P is given, then allocation +;;; occurs on the control stack (for dynamic-extent). In this case, +;;; you MUST also specify NODE, so that the appropriate compiler +;;; policy can be used, and TEMP-TN, which is needed for work-space. +;;; TEMP-TN MUST be a non-descriptor reg. FIXME: This is not yet +;;; implemented on PPC. We should implement this and replace the +;;; inline stack-based allocation that presently occurs in the +;;; VOPs. The stack-p argument is ignored on PPC. +;;; +;;; Using trap instructions for not-very-exceptional situations, such as +;;; allocating, is clever but not very convenient when using gdb to debug. +;;; Set the :sigill-traps feature to use SIGILL instead of SIGTRAP. +;;; +(defun allocation (type size lowtag result-tn &key stack-p node temp-tn flag-tn) + (declare (ignore stack-p node)) + (binding* ((imm-size (typep size '(unsigned-byte 15))) + ((region-base-tn field-offset) + (values thread-base-tn + (if (or #+use-cons-region (eq type 'list)) + (ash thread-cons-tlab-slot word-shift) + (ash thread-mixed-tlab-slot word-shift))))) + + (unless imm-size ; Make temp-tn be the size + (if (numberp size) + (inst lr temp-tn size) + (move temp-tn size))) + + (inst ld result-tn region-base-tn field-offset) + (inst ld flag-tn region-base-tn (+ field-offset n-word-bytes)) ; region->end_addr + + ;; CAUTION: The C code depends on the exact order of + ;; instructions here. In particular, immediately before the + ;; TW instruction must be an ADD or ADDI instruction, so it + ;; can figure out the size of the desired allocation and + ;; storing the new base pointer back to the allocation region + ;; must take one instruction. + (without-scheduling () + ;; Now make result-tn point at the end of the object, to + ;; figure out if we overflowed the current region. + (if imm-size + (inst addi result-tn result-tn size) + (inst add result-tn result-tn temp-tn)) + + ;; result-tn points to the new end of the region. Did we go past + ;; the actual end of the region? If so, we need a full alloc. + ;; The C code depends on this exact form of instruction. If + ;; either changes, you have to change the other appropriately! + (let ((ok (gen-label))) + (declare (ignorable ok)) + #+sigill-traps + (progn (inst cmpld result-tn flag-tn) + (inst ble ok) + (inst mfmq temp-reg-tn) ; an illegal instructions + ;; KLUDGE: emit another ADD so that the sigtrap handler + ;; can behave just as if the trap happened at the TD. + (if imm-size + (inst addi result-tn result-tn size) + (inst add result-tn result-tn temp-tn))) + (if (eq type 'list) + (inst td :llt flag-tn result-tn) ; trap if region.end < new_freeptr + (inst td :lgt result-tn flag-tn)) ; trap if new_freeptr > region.end + #+sigill-traps (emit-label ok)) + ;; The C code depends on exactly 1 instruction here. + (inst std result-tn region-base-tn field-offset)) + + ;; Execution resumes here if the trap fires. + ;; At this point, result-tn points at the end of the object. + ;; Adjust to point to the beginning. + (cond (imm-size + (inst addi result-tn result-tn (+ (- size) lowtag))) + (t + (inst sub result-tn result-tn temp-tn) + ;; Set the lowtag appropriately + (inst ori result-tn result-tn lowtag))))) + +(defun align-csp (temp) + ;; is used for stack allocation of dynamic-extent objects + (storew null-tn csp-tn 0 0) ; store a known-good value (don't want wild pointers below CSP) + (inst addi temp csp-tn lowtag-mask) + (inst clrrdi csp-tn temp n-lowtag-bits)) ;;;; LIST and LIST* -(define-vop (list-or-list*) - (:args (things :more t)) +(define-vop (list) + (:args (things :more t :scs (any-reg descriptor-reg null control-stack))) (:temporary (:scs (descriptor-reg)) ptr) (:temporary (:scs (descriptor-reg)) temp) (:temporary (:scs (descriptor-reg) :to (:result 0) :target result) res) (:temporary (:sc non-descriptor-reg :offset nl3-offset) pa-flag) (:temporary (:scs (non-descriptor-reg)) alloc-temp) - (:info num) + (:info star cons-cells) (:results (result :scs (descriptor-reg))) - (:variant-vars star) - (:policy :safe) (:node-var node) #-gencgc (:ignore alloc-temp) (:generator 0 - (cond ((zerop num) - (move result null-tn)) - ((and star (= num 1)) - (move result (tn-ref-tn things))) - (t - (macrolet - ((maybe-load (tn) + (macrolet ((maybe-load (tn) (once-only ((tn tn)) `(sc-case ,tn ((any-reg descriptor-reg null) @@ -41,15 +122,13 @@ (control-stack (load-stack-tn temp ,tn) temp))))) - (let* ((dx-p (node-stack-allocate-p node)) - (cons-cells (if star (1- num) num)) - (alloc (* (pad-data-block cons-size) cons-cells))) - (pseudo-atomic (pa-flag :sync nil) + (let ((dx-p (node-stack-allocate-p node)) + (alloc (* (pad-data-block cons-size) cons-cells))) + (pseudo-atomic (pa-flag :sync nil :elide-if dx-p) (if dx-p (progn (align-csp res) - (inst clrrdi res csp-tn n-lowtag-bits) - (inst ori res res list-pointer-lowtag) + (inst ori res csp-tn list-pointer-lowtag) (inst addi csp-tn csp-tn alloc)) (allocation 'list alloc list-pointer-lowtag res :temp-tn alloc-temp @@ -69,14 +148,7 @@ (maybe-load (tn-ref-tn (tn-ref-across things))) null-tn) ptr cons-cdr-slot list-pointer-lowtag)) - (move result res))))))) - -(define-vop (list list-or-list*) - (:variant nil)) - -(define-vop (list* list-or-list*) - (:variant t)) - + (move result res))))) ;;;; Special purpose inline allocators. @@ -89,7 +161,7 @@ (:translate make-fdefn) (:generator 37 (with-fixed-allocation (result pa-flag temp fdefn-widetag fdefn-size) - (inst addi temp null-tn (make-fixup 'undefined-tramp :asm-routine-nil-offset)) + (inst addi temp null-tn (make-fixup 'undefined-tramp :assembly-routine*)) (storew name result fdefn-name-slot other-pointer-lowtag) (storew null-tn result fdefn-fun-slot other-pointer-lowtag) (storew temp result fdefn-raw-addr-slot other-pointer-lowtag)))) @@ -104,13 +176,12 @@ (:generator 10 (let* ((size (+ length closure-info-offset)) (alloc-size (pad-data-block size))) - (pseudo-atomic (pa-flag) + (pseudo-atomic (pa-flag :elide-if stack-allocate-p) (if stack-allocate-p (progn (align-csp result) - (inst clrrdi result csp-tn n-lowtag-bits) + (inst ori result csp-tn fun-pointer-lowtag) (inst addi csp-tn csp-tn alloc-size) - (inst ori result result fun-pointer-lowtag) (inst lr temp (logior (ash (1- size) n-widetag-bits) closure-widetag))) (progn (allocation nil (pad-data-block size) fun-pointer-lowtag result @@ -146,7 +217,7 @@ (:args) (:results (result :scs (any-reg))) (:generator 1 - (inst addi result null-tn (make-fixup 'funcallable-instance-tramp :asm-routine-nil-offset)))) + (inst addi result null-tn (make-fixup 'funcallable-instance-tramp :assembly-routine*)))) (define-vop (fixed-alloc) (:args) diff --git a/src/compiler/ppc64/arith.lisp b/src/compiler/ppc64/arith.lisp index ed1e7224ed..4bdd487bfb 100644 --- a/src/compiler/ppc64/arith.lisp +++ b/src/compiler/ppc64/arith.lisp @@ -190,13 +190,26 @@ `(progn (define-vop (,(symbolicate 'fast- translate '-c/fixnum=>fixnum) fast-fixnum-binop-c) (:translate ,translate) - (:generator 1 (generate-fast-+-c r x (fixnumize (,translate y))))) + (:generator 1 + (cond ((and (eq ',translate '-) + (= y most-negative-fixnum)) + (inst lr temp-reg-tn (fixnumize y)) + (inst sub r x temp-reg-tn)) + (t + (generate-fast-+-c r x (fixnumize (,translate y))))))) (define-vop (,(symbolicate 'fast- translate '-c/signed=>signed) fast-signed-binop-c) (:translate ,translate) - (:generator ,untagged-penalty (generate-fast-+-c r x (,translate y)))) + (:generator ,untagged-penalty + (cond ((and (eq ',translate '-) + (= y (- (expt 2 (1- n-word-bits))))) + (inst lr temp-reg-tn y) + (inst sub r x temp-reg-tn)) + (t + (generate-fast-+-c r x (,translate y)))))) (define-vop (,(symbolicate 'fast- translate '-c/unsigned=>unsigned) fast-unsigned-binop-c) (:translate ,translate) - (:generator ,untagged-penalty (generate-fast-+-c r x (,translate y))))))) + (:generator ,untagged-penalty + (generate-fast-+-c r x (,translate y))))))) (define-const-binop + 4) (define-const-binop - 4)) @@ -204,13 +217,13 @@ `(flet ((emit (r x y) (cond ((typep y '(unsigned-byte 16)) (inst ,op r x y)) - ((and (typep (ash y -16) '(unsigned-byte 16)) + ((and (typep (ash y -16) '(unsigned-byte 16)) ; effectively (unsigned-byte 32) ;; logical AND can't be split into two instructions ,@(if (eq translate 'logand) '((zerop (ldb (byte 16 0) y))))) (inst ,shifted-op r x (ash y -16)) (when (ldb-test (byte 16 0) y) - (inst ,op r x (ldb (byte 16 0) y)))) ; not sign-extended - (t + (inst ,op r r (ldb (byte 16 0) y)))) ; not sign-extended + (t ; everything else: just load the constant from memory (inst lr temp-reg-tn y) (inst ,general-op r x temp-reg-tn))))) (define-vop (,(symbolicate 'fast- translate '-c/fixnum=>fixnum) fast-fixnum-logop-c) @@ -300,7 +313,7 @@ (inst cmpdi amount 0) (inst neg ndesc amount) (inst bge positive) - (inst cmpdi ndesc 63) + (inst cmpldi ndesc 63) (inst srd result number ndesc) (inst ble done) (inst li result 0) @@ -347,7 +360,7 @@ (inst cmpdi amount 0) (inst neg ndesc amount) (inst bge positive) - (inst cmpdi ndesc 63) + (inst cmpldi ndesc 63) (inst srad result number ndesc) (inst ble done) ;; smear the sign bit into all bits @@ -497,7 +510,7 @@ fast-ash-left/unsigned=>unsigned)) (deftransform ash-left-mod64 ((integer count) ((unsigned-byte 64) (unsigned-byte 6))) - (when (sb-c::constant-lvar-p count) + (when (sb-c:constant-lvar-p count) (sb-c::give-up-ir1-transform)) '(%primitive fast-ash-left-mod64/unsigned=>unsigned integer count)) @@ -805,7 +818,7 @@ ;;; (define-vop (fast-eql/fixnum fast-conditional) - (:args (x :scs (any-reg descriptor-reg)) + (:args (x :scs (any-reg)) (y :scs (any-reg))) (:arg-types tagged-num tagged-num) (:note "inline fixnum comparison") @@ -815,11 +828,13 @@ (inst b? (if not-p :ne :eq) target))) ;;; (define-vop (generic-eql/fixnum fast-eql/fixnum) + (:args (x :scs (any-reg descriptor-reg)) + (y :scs (any-reg))) (:arg-types * tagged-num) (:variant-cost 7)) (define-vop (fast-eql-c/fixnum fast-conditional/fixnum) - (:args (x :scs (any-reg descriptor-reg))) + (:args (x :scs (any-reg))) (:arg-types tagged-num (:constant (signed-byte #.(- 16 n-fixnum-tag-bits)))) (:info target not-p y) (:translate eql) @@ -834,32 +849,22 @@ ;;;; 64-bit logical operations -(define-vop (shift-towards-someplace) - (:policy :fast-safe) - (:args (num :scs (unsigned-reg)) - (amount :scs (signed-reg))) - (:arg-types unsigned-num tagged-num) - (:temporary (:sc unsigned-reg) temp) - (:results (r :scs (unsigned-reg))) - (:result-types unsigned-num)) - -(define-vop (shift-towards-start shift-towards-someplace) - (:translate shift-towards-start) - (:note "shift-towards-start") - (:generator 1 - (inst andi. temp amount #b111111) - (ecase *backend-byte-order* - (:big-endian (inst sld r num temp)) - (:little-endian (inst srd r num temp))))) - -(define-vop (shift-towards-end shift-towards-someplace) - (:translate shift-towards-end) - (:note "shift-towards-end") - (:generator 1 - (inst andi. temp amount #b111111) - (ecase *backend-byte-order* - (:big-endian (inst srd r num temp)) - (:little-endian (inst sld r num temp))))) +(macrolet ((define (translate operation) + `(define-vop () + (:translate ,translate) + (:note ,(string translate)) + (:policy :fast-safe) + (:args (num :scs (unsigned-reg)) + (amount :scs (signed-reg))) + (:arg-types unsigned-num tagged-num) + (:temporary (:sc unsigned-reg) temp) + (:results (r :scs (unsigned-reg))) + (:result-types unsigned-num) + (:generator 1 + (inst andi. temp amount #b111111) + (inst ,operation r num temp))))) + (define shift-towards-start #+big-endian sld #+little-endian srd) + (define shift-towards-end #+big-endian srd #+little-endian sld)) ;;;; Bignum stuff. @@ -883,9 +888,7 @@ (:args (object :scs (descriptor-reg)) (index :scs (any-reg immediate)) (value :scs (unsigned-reg))) - (:arg-types t positive-fixnum unsigned-num) - (:results (result :scs (unsigned-reg))) - (:result-types unsigned-num)) + (:arg-types t positive-fixnum unsigned-num)) (define-vop (digit-0-or-plus) (:translate sb-bignum:%digit-0-or-plusp) diff --git a/src/compiler/ppc64/array.lisp b/src/compiler/ppc64/array.lisp index 8374f083b3..a012c3cfb2 100644 --- a/src/compiler/ppc64/array.lisp +++ b/src/compiler/ppc64/array.lisp @@ -35,8 +35,12 @@ (allocation nil ndescr other-pointer-lowtag header :temp-tn gc-temp :flag-tn pa-flag) - (inst addi ndescr rank (fixnumize (1- array-dimensions-offset))) - (inst slwi ndescr ndescr n-widetag-bits) + ;; Compute the encoded rank. See ENCODE-ARRAY-RANK. + (inst subi ndescr rank (fixnumize 1)) + ;; Exercise for the reader: these next 4 instructions can be + ;; replaced by just 2: one RLWINM and one RLWIMI + (inst andi. ndescr ndescr (fixnumize array-rank-mask)) + (inst slwi ndescr ndescr array-rank-position) (inst or ndescr ndescr type) (inst srwi ndescr ndescr n-fixnum-tag-bits) (storew ndescr header 0 other-pointer-lowtag)) @@ -54,17 +58,19 @@ (:policy :fast-safe) (:variant array-dimensions-offset other-pointer-lowtag)) -(define-vop (array-rank-vop) +(define-vop () (:translate %array-rank) (:policy :fast-safe) (:args (x :scs (descriptor-reg))) - (:temporary (:scs (non-descriptor-reg)) temp) - (:results (res :scs (any-reg descriptor-reg))) + (:results (res :scs (unsigned-reg))) + (:result-types positive-fixnum) (:generator 6 - (loadw temp x 0 other-pointer-lowtag) - (inst srawi temp temp n-widetag-bits) - (inst subi temp temp (1- array-dimensions-offset)) - (inst slwi res temp n-fixnum-tag-bits))) + ;; convert ARRAY-RANK-POSITION to byte index and compensate for endianness + ;; ASSUMPTION: n-widetag-bits = 8 and rank is adjacent to widetag + (inst lbz res x #+little-endian (- 1 other-pointer-lowtag) + #+big-endian (- 6 other-pointer-lowtag)) + (inst addi res res 1) + (inst andi. res res array-rank-mask))) ;;;; Bounds checking routine. @@ -102,7 +108,40 @@ (:arg-types ,type positive-fixnum) (:results (value :scs ,scs)) (:result-types ,element-type)) - (define-vop (,(symbolicate "DATA-VECTOR-SET/" (string type)) + ,(if (eq type 'simple-vector) + `(define-vop (,(symbolicate "DATA-VECTOR-SET/" (string type))) + (:note "inline array store") + (:translate data-vector-set) + (:arg-types ,type positive-fixnum ,element-type) + (:args (object :scs (descriptor-reg)) + (index :scs (any-reg immediate)) + (value :scs ,scs)) + (:arg-types simple-vector positive-fixnum *) + (:policy :fast-safe) + (:temporary (:scs (non-descriptor-reg)) ea t1) + (:vop-var vop) + (:generator 5 + ;; To ensure the right card gets marked, the exact element address must + ;; be computed. Alternatively, we could allow some leeway in which card(s) + ;; we look at in GC to decide whether a vector page was touched. + ;; i.e there are games that could be played to make the boundaries fuzzy + ;; which might obviate the need to perform two ADDs here, + ;; at the expense of some precision in which cards to re-protect. + ;; Probably better to just compute effective address precisely. + (cond ((sc-is index immediate) + (let ((disp (- (ash (+ vector-data-offset (tn-value index)) word-shift) + other-pointer-lowtag))) + (cond ((typep disp '(signed-byte 16)) + (inst addi ea object disp)) + (t ; doesn't fit in ADDI + (inst lr ea disp) + (inst add ea object ea))))) + (t + (inst addi ea index (- (ash vector-data-offset word-shift) other-pointer-lowtag)) + (inst add ea object ea))) + (emit-gc-store-barrier object ea (list t1) (vop-nth-arg 2 vop) value) + (inst std value ea 0))) + `(define-vop (,(symbolicate "DATA-VECTOR-SET/" (string type)) ,(symbolicate (string variant) "-SET")) (:note "inline array store") (:variant vector-data-offset other-pointer-lowtag) @@ -110,9 +149,7 @@ (:arg-types ,type positive-fixnum ,element-type) (:args (object :scs (descriptor-reg)) (index :scs (any-reg immediate)) - (value :scs ,scs)) - (:results (result :scs ,scs)) - (:result-types ,element-type))))) + (value :scs ,scs))))))) (def-data-vector-frobs simple-base-string byte-index character character-reg) #+sb-unicode @@ -226,10 +263,8 @@ (:policy :fast-safe) (:args (object :scs (descriptor-reg)) (index :scs (unsigned-reg) :target shift) - (value :scs (unsigned-reg immediate) :target result)) + (value :scs (unsigned-reg immediate))) (:arg-types ,type positive-fixnum positive-fixnum) - (:results (result :scs (unsigned-reg))) - (:result-types positive-fixnum) (:temporary (:scs (non-descriptor-reg)) temp old offset) (:temporary (:scs (non-descriptor-reg) :from (:argument 1)) shift) (:generator 25 @@ -256,23 +291,16 @@ (inst andi. temp value ,(1- (ash 1 bits))))) (inst slw temp temp shift) (inst or old old temp)) - (inst stwx old object offset) - (sc-case value - (immediate - (inst lr result (tn-value value))) - (t - (move result value))))) + (inst stwx old object offset))) (define-vop (,(symbolicate 'data-vector-set-c/ type)) (:translate data-vector-set) (:policy :fast-safe) (:args (object :scs (descriptor-reg)) - (value :scs (unsigned-reg immediate) :target result)) + (value :scs (unsigned-reg immediate))) (:arg-types ,type (:constant index) positive-fixnum) (:info index) - (:results (result :scs (unsigned-reg))) - (:result-types positive-fixnum) (:temporary (:scs (non-descriptor-reg)) offset-reg temp old) (:generator 20 (multiple-value-bind (word extra) (floor index ,elements-per-word) @@ -314,12 +342,7 @@ (inst or old old temp))) (if (typep offset '(signed-byte 16)) (inst stw old object offset) - (inst stwx old object offset-reg))) - (sc-case value - (immediate - (inst lr result (tn-value value))) - (t - (move result value)))))))))) + (inst stwx old object offset-reg)))))))))) (def-small-data-vector-frobs simple-bit-vector 1) (def-small-data-vector-frobs simple-array-unsigned-byte-2 2) (def-small-data-vector-frobs simple-array-unsigned-byte-4 4)) @@ -371,16 +394,12 @@ (:policy :fast-safe) (:args (object :scs (descriptor-reg)) (index :scs (any-reg)) - (value :scs (single-reg) :target result)) + (value :scs (single-reg))) (:arg-types simple-array-single-float positive-fixnum single-float) - (:results (result :scs (single-reg))) - (:result-types single-float) (:temporary (:scs (non-descriptor-reg)) offset) (:generator 5 (compute-sfloat-offset) - (inst stfsx value object offset) - (unless (location= result value) - (inst frsp result value)))) + (inst stfsx value object offset))) (define-vop (data-vector-ref/simple-array-double-float) (:note "inline array access") @@ -402,16 +421,12 @@ (:policy :fast-safe) (:args (object :scs (descriptor-reg)) (index :scs (any-reg)) - (value :scs (double-reg) :target result)) + (value :scs (double-reg))) (:arg-types simple-array-double-float positive-fixnum double-float) - (:results (result :scs (double-reg))) - (:result-types double-float) (:temporary (:scs (non-descriptor-reg)) offset) (:generator 20 (compute-lispword-offset) - (inst stfdx value object offset) - (unless (location= result value) - (inst fmr result value)))) + (inst stfdx value object offset))) ;;; Complex float arrays. @@ -438,25 +453,15 @@ (:policy :fast-safe) (:args (object :scs (descriptor-reg)) (index :scs (any-reg)) - (value :scs (complex-single-reg) :target result)) + (value :scs (complex-single-reg))) (:arg-types simple-array-complex-single-float positive-fixnum complex-single-float) - (:results (result :scs (complex-single-reg))) - (:result-types complex-single-float) (:temporary (:scs (non-descriptor-reg) :from (:argument 1)) offset) (:generator 5 (compute-lispword-offset) - (let ((value-real (complex-single-reg-real-tn value)) - (result-real (complex-single-reg-real-tn result))) - (inst stfsx value-real object offset) - (unless (location= result-real value-real) - (inst frsp result-real value-real))) - (let ((value-imag (complex-single-reg-imag-tn value)) - (result-imag (complex-single-reg-imag-tn result))) - (inst addi offset offset 4) - (inst stfsx value-imag object offset) - (unless (location= result-imag value-imag) - (inst frsp result-imag value-imag))))) + (inst stfsx (complex-single-reg-real-tn value) object offset) + (inst addi offset offset 4) + (inst stfsx (complex-single-reg-imag-tn value) object offset))) (define-vop (data-vector-ref/simple-array-complex-double-float) (:note "inline array access") @@ -478,27 +483,17 @@ (:note "inline array store") (:translate data-vector-set) (:policy :fast-safe) - (:args (object :scs (descriptor-reg) :to :result) + (:args (object :scs (descriptor-reg)) (index :scs (any-reg)) - (value :scs (complex-double-reg) :target result)) + (value :scs (complex-double-reg))) (:arg-types simple-array-complex-double-float positive-fixnum complex-double-float) - (:results (result :scs (complex-double-reg))) - (:result-types complex-double-float) (:temporary (:scs (non-descriptor-reg) :from (:argument 1)) offset) (:generator 20 (compute-cplx-dfloat-offset) - (let ((value-real (complex-double-reg-real-tn value)) - (result-real (complex-double-reg-real-tn result))) - (inst stfdx value-real object offset) - (unless (location= result-real value-real) - (inst fmr result-real value-real))) - (let ((value-imag (complex-double-reg-imag-tn value)) - (result-imag (complex-double-reg-imag-tn result))) - (inst addi offset offset 8) - (inst stfdx value-imag object offset) - (unless (location= result-imag value-imag) - (inst fmr result-imag value-imag)))))) + (inst stfdx (complex-double-reg-real-tn value) object offset) + (inst addi offset offset 8) + (inst stfdx (complex-double-reg-imag-tn value) object offset)))) ;;; These vops are useful for accessing the bits of a vector irrespective of @@ -519,8 +514,6 @@ (index :scs (any-reg immediate)) (value :scs (unsigned-reg))) (:arg-types * positive-fixnum unsigned-num) - (:results (result :scs (unsigned-reg))) - (:result-types unsigned-num) (:variant vector-data-offset other-pointer-lowtag)) ;;; @@ -540,9 +533,7 @@ (:arg-types simple-array-signed-byte-8 positive-fixnum tagged-num) (:args (object :scs (descriptor-reg)) (index :scs (any-reg immediate)) - (value :scs (signed-reg))) - (:results (result :scs (signed-reg))) - (:result-types tagged-num)) + (value :scs (signed-reg)))) (define-vop (data-vector-ref/simple-array-signed-byte-16 signed-16-bits-index-ref) @@ -560,9 +551,7 @@ (:arg-types simple-array-signed-byte-16 positive-fixnum tagged-num) (:args (object :scs (descriptor-reg)) (index :scs (any-reg immediate)) - (value :scs (signed-reg))) - (:results (result :scs (signed-reg))) - (:result-types tagged-num)) + (value :scs (signed-reg)))) (define-vop (data-vector-ref/simple-array-signed-byte-32 signed-32-bits-index-ref) @@ -580,9 +569,7 @@ (:arg-types simple-array-signed-byte-32 positive-fixnum tagged-num) (:args (object :scs (descriptor-reg)) (index :scs (any-reg immediate)) - (value :scs (signed-reg))) - (:results (result :scs (signed-reg))) - (:result-types tagged-num)) + (value :scs (signed-reg)))) ;;;; ATOMIC-INCF for arrays diff --git a/src/compiler/ppc64/c-call.lisp b/src/compiler/ppc64/c-call.lisp index a41c7ff85b..a16143a823 100644 --- a/src/compiler/ppc64/c-call.lisp +++ b/src/compiler/ppc64/c-call.lisp @@ -25,12 +25,12 @@ ;;;; "The stack pointer (stored in r1) shall maintain quadword alignment." ;;;; (quadword = 16 bytes) (defconstant +stack-alignment-mask+ 15) +(defconstant +stack-frame-size+ #+little-endian 12 #+big-endian 14) (defstruct arg-state (gpr-args 0) (fpr-args 0) - (stack-frame-size #+little-endian 12 - #+big-endian 14)) + (stack-frame-size +stack-frame-size+)) (defun int-arg (state prim-type reg-sc stack-sc) (let ((reg-args (arg-state-gpr-args state))) @@ -140,7 +140,7 @@ (values (make-wired-tn* 'positive-fixnum any-reg-sc-number nsp-offset) (let ((size (arg-state-stack-frame-size arg-state))) (cond #+little-endian - ((= size 12) + ((= size +stack-frame-size+) ;; no stack args 0) (t @@ -172,10 +172,9 @@ (:info foreign-symbol) (:results (res :scs (sap-reg))) (:result-types system-area-pointer) - (:temporary (:scs (non-descriptor-reg)) addr) (:generator 2 - (inst lr addr (make-fixup foreign-symbol :foreign-dataref)) - (loadw res addr))) + (inst lr res (make-fixup foreign-symbol :foreign-dataref)) + (loadw res res))) (define-vop (call-out) (:args (function :scs (sap-reg) :target cfunc) @@ -262,7 +261,9 @@ (make-random-tn :kind :normal :sc (sc-or-lose 'double-reg) :offset n))) - (let* ((segment (make-segment))) + (let* ((segment (make-segment)) + #+big-endian + (function-descriptor-size 24)) (assemble (segment 'nil) ;; Copy args from registers or stack to new position ;; on stack. @@ -311,8 +312,7 @@ (save-arg (type words) (let ((integerp (not (alien-float-type-p type))) (in-offset (+ (* in-words-processed n-word-bytes) - (* 12 n-word-bytes - #+big-endian 2))) + (* +stack-frame-size+ n-word-bytes))) (out-offset (- (* out-words-processed n-word-bytes) arg-store-pos))) (cond (integerp @@ -386,6 +386,11 @@ (incf out-words-processed)) (t (bug "Unknown alien floating point type: ~S" type)))))) + ;; Leave a gap for a PPC64ELF ABIv1 function descriptor, + ;; to be filled in later relative to the SAP. + #+big-endian + (dotimes (k (/ function-descriptor-size 4)) ; nop is 4 bytes + (inst nop)) (mapc #'save-arg argument-types (mapcar (lambda (arg) @@ -411,11 +416,17 @@ (inst stdu stack-pointer stack-pointer (- frame-size)) ;; And make the call. + #+little-endian (load-address-into r0 - (foreign-symbol-address - #-sb-thread "funcall3" - #+sb-thread "callback_wrapper_trampoline")) + (foreign-symbol-address "callback_wrapper_trampoline")) + #+big-endian + (destructuring-bind (r2 r12) (mapcar #'make-gpr '(2 12)) + (load-address-into + r12 + (foreign-symbol-address "callback_wrapper_trampoline")) + (inst ld r0 r12 0) + (inst ld r2 r12 8)) (inst mtlr r0) (inst blrl) @@ -436,10 +447,10 @@ ) (t (loop with gprs = (mapcar #'make-gpr '(3 4)) - repeat n-return-area-words for gpr = (pop gprs) for offset from (- return-area-pos) by n-word-bytes + repeat n-return-area-words do (unless gpr (bug "Out of return registers in alien-callback trampoline.")) @@ -454,6 +465,13 @@ :element-type '(unsigned-byte 8) :initial-contents buffer)) (sap (vector-sap vector))) + ;; Fill in the PPC64ELF ABIv1 function descriptor that + ;; points just past the end of itself, to the first + ;; instruction of the wrapper. This assembler wrapper only + ;; cares about the address, so leave the other descriptor + ;; fields filled with no-op instructions. + #+big-endian + (setf (sap-ref-64 sap 0) (+ (sap-int sap) function-descriptor-size)) (alien-funcall (extern-alien "ppc_flush_icache" (function void @@ -461,3 +479,18 @@ unsigned-long)) sap (length buffer)) vector))))) + +;;; For (CAS SAP-REF-{8,16,32}) +(defknown sign-extend ((signed-byte 64) t) fixnum + (foldable flushable movable)) + +(define-vop (sign-extend) + (:translate sign-extend) + (:policy :fast-safe) + (:args (val :scs (signed-reg))) + (:arg-types signed-num (:constant fixnum)) + (:info size) + (:results (res :scs (signed-reg))) + (:result-types fixnum) + (:generator 1 + (inst* (ecase size (8 'extsb) (16 'extsh) (32 'extsw)) res val))) diff --git a/src/compiler/ppc64/call.lisp b/src/compiler/ppc64/call.lisp index 0c69f4f8af..c8d400dcbb 100644 --- a/src/compiler/ppc64/call.lisp +++ b/src/compiler/ppc64/call.lisp @@ -39,13 +39,13 @@ ;;; them at a known location. (defun make-old-fp-save-location (env) (specify-save-tn - (physenv-debug-live-tn (make-normal-tn *fixnum-primitive-type*) env) + (environment-debug-live-tn (make-normal-tn *fixnum-primitive-type*) env) (make-wired-tn *fixnum-primitive-type* control-stack-arg-scn ocfp-save-offset))) (defun make-return-pc-save-location (env) (specify-save-tn - (physenv-debug-live-tn (make-normal-tn *backend-t-primitive-type*) env) + (environment-debug-live-tn (make-normal-tn *backend-t-primitive-type*) env) (make-wired-tn *backend-t-primitive-type* control-stack-arg-scn lra-save-offset))) @@ -142,7 +142,7 @@ (move res csp-tn) (inst addi csp-tn csp-tn (* n-word-bytes (sb-allocated-size 'control-stack))) - (when (ir2-physenv-number-stack-p callee) + (when (ir2-environment-number-stack-p callee) (let* ((nbytes (bytes-needed-for-non-descriptor-stack-frame))) (when (> nbytes number-stack-displacement) (inst stdu nsp-tn nsp-tn (- (bytes-needed-for-non-descriptor-stack-frame))) @@ -354,8 +354,7 @@ default-value-8 values-start) (:temporary (:sc any-reg :offset nargs-offset :from :eval :to (:result 1)) - nvals) - (:temporary (:scs (non-descriptor-reg)) temp)) + nvals)) ;;; This hook in the codegen pass lets us insert code before fall-thru entry @@ -742,9 +741,6 @@ default-value-8 ;; Conditionally insert a conditional trap: (when step-instrumenting ;; Get the symbol-value of SB-IMPL::*STEPPING* - #-sb-thread - (load-symbol-value stepping sb-impl::*stepping*) - #+sb-thread (loadw stepping thread-base-tn thread-stepping-slot) (inst cmpwi stepping 0) ;; If it's not null, trap. @@ -877,7 +873,7 @@ default-value-8 (inst addi nsp-tn cur-nfp (- (bytes-needed-for-non-descriptor-stack-frame) number-stack-displacement)))) - (inst addi temp null-tn (make-fixup 'tail-call-variable :asm-routine-nil-offset)) + (inst addi temp null-tn (make-fixup 'tail-call-variable :assembly-routine*)) (inst mtlr temp) (inst blr))) @@ -1005,7 +1001,7 @@ default-value-8 (move old-fp old-fp-arg) (move vals vals-arg) (move nvals nvals-arg) - (inst addi temp null-tn (make-fixup 'return-multiple :asm-routine-nil-offset)) + (inst addi temp null-tn (make-fixup 'return-multiple :assembly-routine*)) (inst mtlr temp) (inst blr)))) @@ -1134,6 +1130,20 @@ default-value-8 (:variant 0 0) (:translate %more-arg)) +(define-vop (more-arg-or-nil) + (:policy :fast-safe) + (:args (object :scs (descriptor-reg) :to (:result 1)) + (count :scs (any-reg))) + (:info index) + (:results (value :scs (descriptor-reg any-reg))) + (:result-types *) + (:generator 3 + (inst cmpwi count (fixnumize index)) + (move value null-tn) + (inst ble done) + (loadw value object index) + done)) + ;;; Turn more arg (context, count) into a list. (define-vop () (:translate %listify-rest-args) @@ -1160,14 +1170,12 @@ default-value-8 (move result null-tn) (inst beq done) - ;; We need to do this atomically. - (pseudo-atomic (pa-flag :sync nil) + (pseudo-atomic (pa-flag :sync nil :elide-if dx-p) ;; Allocate a cons (2 words) for each item. (if dx-p (progn (align-csp temp) - (inst clrrdi result csp-tn n-lowtag-bits) - (inst ori result result list-pointer-lowtag) + (inst ori result csp-tn list-pointer-lowtag) (move dst result) (inst sldi temp count (1+ (- word-shift n-fixnum-tag-bits))) (inst add csp-tn csp-tn temp)) @@ -1252,9 +1260,6 @@ default-value-8 (:vop-var vop) (:generator 3 ;; Get the symbol-value of SB-IMPL::*STEPPING* - #-sb-thread - (load-symbol-value stepping sb-impl::*stepping*) - #+sb-thread (loadw stepping thread-base-tn thread-stepping-slot) (inst cmpwi stepping 0) ;; If it's not zero, trap. diff --git a/src/compiler/ppc64/cell.lisp b/src/compiler/ppc64/cell.lisp index 51e4d1823a..6f84c24d63 100644 --- a/src/compiler/ppc64/cell.lisp +++ b/src/compiler/ppc64/cell.lisp @@ -16,41 +16,73 @@ ;;; PPC64 can't use the NIL-as-CONS + NIL-as-symbol trick *and* avoid using ;;; temp-reg-tn to access symbol slots. -;;; Since the NIL-as-CONS is necessary, and efficient accessor to lists and +;;; Since the NIL-as-CONS is necessary, and efficient access to lists and ;;; instances is desirable, we lose a little on symbol access by being forced -;;; to pre-check for NIL. There is trick that can get back some performance -;;; on SYMBOL-VALUE which I plan to implement after this much works right. +;;; to pre-check for NIL. + +(defun read-symbol-slot (slot symbol result) + (let ((null-label (gen-label)) + (done-label (gen-label))) + (inst cmpld symbol null-tn) + (inst beq null-label) + (loadw result symbol slot other-pointer-lowtag) + (inst b done-label) + (emit-label null-label) + ;; This is a very un-memorable bit of fudge factor magic + ;; that I have to re-figure-out every time I need it. + ;; Some sort of abstraction might be nice. Or not. + (loadw result symbol (1- slot) list-pointer-lowtag) + (emit-label done-label))) + (define-vop (slot) (:args (object :scs (descriptor-reg))) (:info name offset lowtag) (:results (result :scs (descriptor-reg any-reg))) (:generator 1 - (cond ((member name '(symbol-name symbol-info sb-xc:symbol-package)) - (let ((null-label (gen-label)) - (done-label (gen-label))) - (inst cmpld object null-tn) - (inst beq null-label) - (loadw result object offset lowtag) - (inst b done-label) - (emit-label null-label) - (loadw result object (1- offset) list-pointer-lowtag) - (emit-label done-label))) + (cond ((member name '(symbol-%info %symbol-fdefn)) + (read-symbol-slot offset object result)) (t (loadw result object offset lowtag))))) +(define-vop () + (:args (symbol :scs (descriptor-reg))) + (:results (result :scs (unsigned-reg))) + (:result-types positive-fixnum) + (:translate sb-impl::symbol-package-id) + (:policy :fast-safe) + (:generator 5 + (inst cmpld symbol null-tn) + ;; This loads "random" bits if SYMBOL is NIL, but since RESULT is non-descriptor + ;; there is no harm. We check for NULL and move a constant to the result if so. + ;; ASSUMPTION: symbol-package-bits = 16 + (inst lhz result symbol (+ (ash symbol-name-slot word-shift) + (- other-pointer-lowtag) + #+little-endian 6)) + (inst bne done) + (inst lr result 1) ; SB-IMPL::+PACKAGE-ID-LISP+ + DONE)) +(define-vop () + (:args (symbol :scs (descriptor-reg))) + (:results (result :scs (descriptor-reg))) + (:translate symbol-name) + (:policy :fast-safe) + (:temporary (:sc non-descriptor-reg :offset nl3-offset) pa-flag) + (:generator 2 + (pseudo-atomic (pa-flag :sync nil) + (read-symbol-slot symbol-name-slot symbol result) + (inst rldicl result result 0 sb-impl::package-id-bits)))) + (define-vop (set-slot) (:args (object :scs (descriptor-reg)) (value :scs (descriptor-reg any-reg))) (:info name offset lowtag) + (:temporary (:scs (non-descriptor-reg)) t1) + (:vop-var vop) (:ignore name) - (:results) (:generator 1 + (emit-gc-store-barrier object nil (list t1) (vop-nth-arg 1 vop) value) (storew value object offset lowtag))) -(define-vop (init-slot set-slot) - (:info name dx-p offset lowtag) - (:ignore name dx-p)) - (define-vop (compare-and-swap-slot) (:args (object :scs (descriptor-reg)) (old :scs (descriptor-reg any-reg)) @@ -59,7 +91,9 @@ (:info name offset lowtag) (:ignore name) (:results (result :scs (descriptor-reg) :from :load)) + (:vop-var vop) (:generator 5 + (emit-gc-store-barrier object nil (list temp) (vop-nth-arg 2 vop) new) (inst sync) (inst li temp (- (* offset n-word-bytes) lowtag)) LOOP @@ -84,19 +118,17 @@ (:policy :fast-safe) (:vop-var vop) (:generator 15 + (emit-gc-store-barrier symbol nil (list temp) (vop-nth-arg 2 vop) new) (inst sync) - #+sb-thread - (assemble () - (load-tls-index temp symbol) - ;; Thread-local area, no synchronization needed. - (inst ldx result thread-base-tn temp) - (inst cmpd result old) - (inst bne DONT-STORE-TLS) - (inst stdx new thread-base-tn temp) - DONT-STORE-TLS - - (inst cmpdi result no-tls-value-marker-widetag) - (inst bne CHECK-UNBOUND)) + (load-tls-index temp symbol) + ;; Thread-local area, no synchronization needed. + (inst ldx result thread-base-tn temp) + (inst cmpd result old) + (inst bne DONT-STORE-TLS) + (inst stdx new thread-base-tn temp) + DONT-STORE-TLS + (inst cmpdi result no-tls-value-marker) + (inst bne CHECK-UNBOUND) (inst li temp (- (* symbol-value-slot n-word-bytes) other-pointer-lowtag)) @@ -126,9 +158,8 @@ (:temporary (:scs (descriptor-reg) :from (:argument 0)) obj-temp)) ;;; With SYMBOL-VALUE, we check that the value isn't the trap object. -;;; So SYMBOL-VALUE of NIL is NIL. (define-vop (symbol-global-value checked-cell-ref) - (:translate sym-global-val) + (:translate symbol-global-value) (:generator 9 ;; TODO: can this be made branchless somehow? (inst cmpld object null-tn) @@ -146,7 +177,7 @@ (define-vop (fast-symbol-global-value cell-ref) (:variant symbol-value-slot other-pointer-lowtag) (:policy :fast) - (:translate sym-global-val) + (:translate symbol-global-value) (:ignore offset lowtag) (:generator 7 (inst cmpld object null-tn) @@ -157,96 +188,84 @@ (move value object) DONE)) -#+sb-thread -(progn - (define-vop (set) - (:args (symbol :scs (descriptor-reg)) - (value :scs (descriptor-reg any-reg))) - (:temporary (:sc any-reg) tls-slot temp) - (:generator 4 - (load-tls-index tls-slot symbol) - (inst ldx temp thread-base-tn tls-slot) - (inst cmpdi temp no-tls-value-marker-widetag) - (inst beq GLOBAL-VALUE) - (inst stdx value thread-base-tn tls-slot) - (inst b DONE) - GLOBAL-VALUE - (storew value symbol symbol-value-slot other-pointer-lowtag) - DONE)) +(define-vop (set) + (:args (symbol :scs (descriptor-reg)) + (value :scs (descriptor-reg any-reg))) + (:temporary (:sc non-descriptor-reg) tls-slot) + (:temporary (:sc any-reg) temp) + (:vop-var vop) + (:generator 4 + (load-tls-index tls-slot symbol) + (inst ldx temp thread-base-tn tls-slot) + (inst cmpdi temp no-tls-value-marker) + (inst beq GLOBAL-VALUE) + (inst stdx value thread-base-tn tls-slot) + (inst b DONE) + GLOBAL-VALUE + (emit-gc-store-barrier symbol nil (list tls-slot) (vop-nth-arg 1 vop) value) + (storew value symbol symbol-value-slot other-pointer-lowtag) + DONE)) - ;; With Symbol-Value, we check that the value isn't the trap object. So - ;; Symbol-Value of NIL is NIL. - (define-vop (symbol-value) - (:translate symeval) - (:policy :fast-safe) - (:args (object :scs (descriptor-reg) :to (:result 1))) - (:results (value :scs (descriptor-reg any-reg))) - (:vop-var vop) - (:save-p :compute-only) - (:generator 9 - (inst cmpld object null-tn) - (inst beq NULL) - (load-tls-index value object) - (inst ldx value thread-base-tn value) - (inst cmpdi value no-tls-value-marker-widetag) - (inst bne CHECK-UNBOUND) - (loadw value object symbol-value-slot other-pointer-lowtag) - CHECK-UNBOUND - (inst cmpdi value unbound-marker-widetag) - (inst beq (generate-error-code vop 'unbound-symbol-error object)) - (inst b DONE) - NULL - (move value object) - DONE)) +;; With Symbol-Value, we check that the value isn't the trap object. +(define-vop (symbol-value) + (:translate symbol-value) + (:policy :fast-safe) + (:args (object :scs (descriptor-reg) :to (:result 1))) + (:results (value :scs (descriptor-reg any-reg))) + (:vop-var vop) + (:save-p :compute-only) + (:generator 9 + (inst cmpld object null-tn) + (inst beq NULL) + (load-tls-index value object) + (inst ldx value thread-base-tn value) + (inst cmpdi value no-tls-value-marker) + (inst bne CHECK-UNBOUND) + (loadw value object symbol-value-slot other-pointer-lowtag) + CHECK-UNBOUND + (inst cmpdi value unbound-marker-widetag) + (inst beq (generate-error-code vop 'unbound-symbol-error object)) + (inst b DONE) + NULL + (move value object) + DONE)) - (define-vop (fast-symbol-value symbol-value) - ;; KLUDGE: not really fast, in fact, because we're going to have to - ;; do a full lookup of the thread-local area anyway. But half of - ;; the meaning of FAST-SYMBOL-VALUE is "do not signal an error if - ;; unbound", which is used in the implementation of COPY-SYMBOL. -- - ;; CSR, 2003-04-22 - (:policy :fast) - (:translate symeval) - (:generator 8 - (inst cmpld object null-tn) - (inst beq NULL) - (load-tls-index value object) - (inst ldx value thread-base-tn value) - (inst cmpdi value no-tls-value-marker-widetag) - (inst bne DONE) - (loadw value object symbol-value-slot other-pointer-lowtag) - (inst b DONE) - NULL - (move value object) - DONE))) - -;;; On unithreaded builds these are just copies of the global versions. -#-sb-thread -(progn - (define-vop (symbol-value symbol-global-value) - (:translate symeval)) - (define-vop (fast-symbol-value fast-symbol-global-value) - (:translate symeval)) - (define-vop (set %set-symbol-global-value))) +(define-vop (fast-symbol-value symbol-value) + ;; KLUDGE: not really fast, in fact, because we're going to have to + ;; do a full lookup of the thread-local area anyway. But half of + ;; the meaning of FAST-SYMBOL-VALUE is "do not signal an error if + ;; unbound", which is used in the implementation of COPY-SYMBOL. -- + ;; CSR, 2003-04-22 + (:policy :fast) + (:translate symbol-value) + (:generator 8 + (inst cmpld object null-tn) + (inst beq NULL) + (load-tls-index value object) + (inst ldx value thread-base-tn value) + (inst cmpdi value no-tls-value-marker) + (inst bne DONE) + (loadw value object symbol-value-slot other-pointer-lowtag) + (inst b DONE) + NULL + (move value object) + DONE)) ;;; Like CHECKED-CELL-REF, only we are a predicate to see if the cell ;;; is bound. -(define-vop (boundp-frob) +(define-vop (boundp) (:args (object :scs (descriptor-reg))) (:conditional) (:info target not-p) (:policy :fast-safe) - (:temporary (:scs (descriptor-reg)) value)) - -#+sb-thread -(define-vop (boundp boundp-frob) + (:temporary (:scs (descriptor-reg)) value) (:translate boundp) (:generator 9 (inst cmpld object null-tn) (inst beq (if not-p out target)) (load-tls-index value object) (inst ldx value thread-base-tn value) - (inst cmpdi value no-tls-value-marker-widetag) + (inst cmpdi value no-tls-value-marker) (inst bne CHECK-UNBOUND) (loadw value object symbol-value-slot other-pointer-lowtag) CHECK-UNBOUND @@ -254,21 +273,17 @@ (inst b? (if not-p :eq :ne) target) OUT)) -#-sb-thread -(define-vop (boundp boundp-frob) - (:translate boundp) - (:generator 9 - (loadw value object symbol-value-slot other-pointer-lowtag) - (inst cmpwi value unbound-marker-widetag) - (inst b? (if not-p :eq :ne) target))) - (define-vop (symbol-hash) (:policy :fast-safe) (:translate symbol-hash) (:args (symbol :scs (descriptor-reg))) (:results (res :scs (any-reg))) (:result-types positive-fixnum) + (:args-var args) (:generator 4 + (when (not-nil-tn-ref-p args) + (loadw res symbol symbol-hash-slot other-pointer-lowtag) + (return-from symbol-hash)) (inst cmpld symbol null-tn) (inst beq NULL) (loadw res symbol symbol-hash-slot other-pointer-lowtag) @@ -276,27 +291,6 @@ NULL (inst addi res null-tn (- (logand sb-vm:nil-value sb-vm:fixnum-tag-mask))) DONE)) -(define-vop (symbol-plist) - (:policy :fast-safe) - (:translate symbol-plist) - (:args (symbol :scs (descriptor-reg))) - (:results (res :scs (descriptor-reg))) - (:temporary (:scs (unsigned-reg)) temp) - (:generator 6 - (inst cmpld symbol null-tn) - (inst beq NULL) - (loadw res symbol symbol-info-slot other-pointer-lowtag) - (inst andi. temp res lowtag-mask) - (inst cmpwi temp list-pointer-lowtag) - (inst beq take-car) - (move res null-tn) ; if INFO is a non-list, then the PLIST is NIL - (inst b DONE) - NULL - (loadw res symbol (1- symbol-info-slot) list-pointer-lowtag) - ;; fallthru. NULL's info slot always holds a cons - TAKE-CAR - (loadw res res cons-car-slot list-pointer-lowtag) - DONE)) ;;;; Fdefinition (fdefn) objects. @@ -354,6 +348,7 @@ (:temporary (:scs (non-descriptor-reg)) type) (:results (result :scs (descriptor-reg))) (:generator 38 + (emit-gc-store-barrier fdefn nil (list type)) (let ((normal-fn (gen-label))) (load-type type function (- fun-pointer-lowtag)) (inst cmpdi type simple-fun-widetag) @@ -361,7 +356,7 @@ (inst addi lip function (- (ash simple-fun-insts-offset word-shift) fun-pointer-lowtag)) (inst beq normal-fn) - (inst addi lip null-tn (make-fixup 'closure-tramp :asm-routine-nil-offset)) + (inst addi lip null-tn (make-fixup 'closure-tramp :assembly-routine*)) (emit-label normal-fn) (storew lip fdefn fdefn-raw-addr-slot other-pointer-lowtag) (storew function fdefn fdefn-fun-slot other-pointer-lowtag) @@ -370,16 +365,12 @@ (define-vop (fdefn-makunbound) (:policy :fast-safe) (:translate fdefn-makunbound) - (:args (fdefn :scs (descriptor-reg) :target result)) + (:args (fdefn :scs (descriptor-reg))) (:temporary (:scs (non-descriptor-reg)) temp) - (:results (result :scs (descriptor-reg))) (:generator 38 (storew null-tn fdefn fdefn-fun-slot other-pointer-lowtag) - (inst addi temp null-tn (make-fixup 'undefined-tramp :asm-routine-nil-offset)) - (storew temp fdefn fdefn-raw-addr-slot other-pointer-lowtag) - (move result fdefn))) - - + (inst addi temp null-tn (make-fixup 'undefined-tramp :assembly-routine*)) + (storew temp fdefn fdefn-raw-addr-slot other-pointer-lowtag))) ;;;; Binding and Unbinding. @@ -387,7 +378,6 @@ ;;; the symbol on the binding stack and stuff the new value into the ;;; symbol. ;;; See the "Chapter 9: Specials" of the SBCL Internals Manual. -#+sb-thread (define-vop (dynbind) (:args (val :scs (any-reg descriptor-reg)) (symbol :scs (descriptor-reg))) @@ -402,19 +392,6 @@ (storew tls-index bsp-tn (- binding-symbol-slot binding-size)) (inst stdx val thread-base-tn tls-index)))) -#-sb-thread -(define-vop (dynbind) - (:args (val :scs (any-reg descriptor-reg)) - (symbol :scs (descriptor-reg))) - (:temporary (:scs (descriptor-reg)) temp) - (:generator 5 - (loadw temp symbol symbol-value-slot other-pointer-lowtag) - (inst addi bsp-tn bsp-tn (* binding-size n-word-bytes)) - (storew temp bsp-tn (- binding-value-slot binding-size)) - (storew symbol bsp-tn (- binding-symbol-slot binding-size)) - (storew val symbol symbol-value-slot other-pointer-lowtag))) - -#+sb-thread (define-vop (unbind) (:temporary (:scs (descriptor-reg)) tls-index value) (:temporary (:scs (any-reg)) zero) @@ -427,20 +404,6 @@ (storew zero bsp-tn (- binding-value-slot binding-size)) (inst subi bsp-tn bsp-tn (* binding-size n-word-bytes)))) -#-sb-thread -(define-vop (unbind) - (:temporary (:scs (descriptor-reg)) symbol value) - (:temporary (:scs (any-reg)) zero) - (:generator 0 - (loadw symbol bsp-tn (- binding-symbol-slot binding-size)) - (loadw value bsp-tn (- binding-value-slot binding-size)) - (storew value symbol symbol-value-slot other-pointer-lowtag) - (inst li zero 0) - (storew zero bsp-tn (- binding-symbol-slot binding-size)) - (storew zero bsp-tn (- binding-value-slot binding-size)) - (inst subi bsp-tn bsp-tn (* binding-size n-word-bytes)))) - - (define-vop (unbind-to-here) (:args (arg :scs (descriptor-reg any-reg) :target where)) (:temporary (:scs (any-reg) :from (:argument 0)) where zero) @@ -456,10 +419,7 @@ (inst cmpdi symbol 0) (inst beq skip) (loadw value bsp-tn (- binding-value-slot binding-size)) - #+sb-thread (inst stdx value thread-base-tn symbol) - #-sb-thread - (storew value symbol symbol-value-slot other-pointer-lowtag) (storew zero bsp-tn (- binding-symbol-slot binding-size)) SKIP @@ -478,14 +438,14 @@ (:variant closure-info-offset fun-pointer-lowtag) (:translate %closure-index-ref)) +(define-vop (%closure-index-set descriptor-word-index-set) + (:variant closure-info-offset fun-pointer-lowtag) + (:translate %closure-index-set)) + (define-vop (funcallable-instance-info word-index-ref) (:variant funcallable-instance-info-offset fun-pointer-lowtag) (:translate %funcallable-instance-info)) -(define-vop (set-funcallable-instance-info word-index-set) - (:variant funcallable-instance-info-offset fun-pointer-lowtag) - (:translate %set-funcallable-instance-info)) - (define-vop (closure-ref) (:args (object :scs (descriptor-reg))) (:results (value :scs (descriptor-reg any-reg))) @@ -497,7 +457,9 @@ (:args (object :scs (descriptor-reg)) (value :scs (descriptor-reg any-reg))) (:info offset) + (:temporary (:scs (non-descriptor-reg)) temp) (:generator 4 + (emit-gc-store-barrier object nil (list temp)) (storew value object (+ closure-info-offset offset) fun-pointer-lowtag))) (define-vop (closure-init-from-fp) @@ -534,7 +496,7 @@ (:variant instance-slots-offset instance-pointer-lowtag) (:arg-types instance positive-fixnum)) -(define-vop (instance-index-set word-index-set) +(define-vop (instance-index-set descriptor-word-index-set) (:policy :fast-safe) (:translate %instance-set) (:variant instance-slots-offset instance-pointer-lowtag) @@ -545,52 +507,70 @@ (:translate %instance-cas) (:variant instance-slots-offset instance-pointer-lowtag) (:arg-types instance tagged-num * *)) +(define-vop (%raw-instance-cas/word %instance-cas) + (:args (object) + (index) + (old-value :scs (unsigned-reg)) + (new-value :scs (unsigned-reg))) + (:arg-types * tagged-num unsigned-num unsigned-num) + (:results (result :scs (unsigned-reg) :from :load)) + (:result-types unsigned-num) + (:translate %raw-instance-cas/word)) ;;;; Code object frobbing. -(define-vop (code-header-ref-any) +(define-vop (code-header-ref+tag) (:args (object :scs (descriptor-reg)) (index :scs (any-reg))) (:arg-types * tagged-num) + (:info implied-lowtag) + ;; conservative_root_p() in gencgc treats untagged pointers to fdefns + ;; as implicitly pinned. It has to be in a boxed register. (:results (value :scs (descriptor-reg))) (:policy :fast-safe) (:temporary (:scs (non-descriptor-reg)) temp) (:generator 2 ;; ASSUMPTION: N-FIXNUM-TAG-BITS = 3 (inst addi temp index (- other-pointer-lowtag)) - (inst ldx value object temp))) - -(define-vop (code-header-ref-fdefn) - (:args (object :scs (descriptor-reg)) - (index :scs (any-reg))) - (:arg-types * tagged-num) - (:results (value :scs (descriptor-reg))) - (:policy :fast-safe) - (:temporary (:scs (non-descriptor-reg)) temp) - (:generator 3 - ;; ASSUMPTION: N-FIXNUM-TAG-BITS = 3 - (inst addi temp index (- other-pointer-lowtag)) - ;; Loaded value is automatically pinned. (inst ldx value object temp) - (inst ori value value other-pointer-lowtag))) + (unless (zerop implied-lowtag) + (inst ori value value implied-lowtag)))) #-sb-xc-host (defun code-header-ref (code index) (declare (index index)) - (let ((fdefns-start (sb-impl::code-fdefns-start-index code)) - (count (code-n-named-calls code))) - (declare ((unsigned-byte 16) fdefns-start count)) - (if (and (>= index fdefns-start) (< index (+ fdefns-start count))) - (%primitive code-header-ref-fdefn code index) - (%primitive code-header-ref-any code index)))) - -(define-vop (code-header-set word-index-set) + (binding* (((start count) (sb-vm::code-header-fdefn-range code)) + (end (+ start count))) + (values (if (and (>= index start) (< index end)) + (%primitive code-header-ref+tag code index other-pointer-lowtag) + (%primitive code-header-ref+tag code index 0))))) + +(define-vop (code-header-set) (:translate code-header-set) (:policy :fast-safe) - (:variant 0 other-pointer-lowtag)) - - + (:args (object :scs (descriptor-reg)) + (index :scs (any-reg)) + (value :scs (any-reg descriptor-reg))) + (:arg-types * tagged-num *) + (:temporary (:scs (non-descriptor-reg)) temp card) + (:temporary (:sc non-descriptor-reg :offset nl3-offset) pa-flag) + (:generator 10 + ;; Load mark table base + (inst ld temp thread-base-tn (ash thread-card-table-slot word-shift)) + (pseudo-atomic (pa-flag) + ;; Compute card mark index + (inst rldicl card object (- 64 gencgc-card-shift) (make-fixup nil :gc-barrier)) + ;; Touch the card mark byte. + (inst stbx thread-base-tn temp card) ; THREAD-TN's low byte is 0 + ;; set 'written' flag in the code header + ;; If two threads get here at the same time, they'll write the same byte. + (let ((byte (- #+big-endian 4 #+little-endian 3 other-pointer-lowtag))) + (inst lbz temp object byte) + (inst ori temp temp #x40) + (inst stb temp object byte)) + (inst addi temp index (- other-pointer-lowtag)) + (inst stdx value object temp)))) ;;;; raw instance slot accessors @@ -601,30 +581,19 @@ (macrolet ((def (suffix sc primtype) `(progn - (define-vop (,(symbolicate "RAW-INSTANCE-INIT/" suffix)) - (:args (object :scs (descriptor-reg)) - (value :scs (,sc))) - (:arg-types * ,primtype) - (:info index) - (:temporary (:scs (non-descriptor-reg)) temp) - (:generator 4 - (inst lr temp (offset-for-raw-slot index)) - (inst stdx value object temp))) - (define-vop (,(symbolicate "RAW-INSTANCE-REF/" suffix) word-index-ref) + (define-vop (,(symbolicate "%RAW-INSTANCE-REF/" suffix) word-index-ref) (:policy :fast-safe) (:translate ,(symbolicate "%RAW-INSTANCE-REF/" suffix)) (:variant instance-slots-offset instance-pointer-lowtag) (:arg-types instance positive-fixnum) (:results (value :scs (,sc))) (:result-types ,primtype)) - (define-vop (,(symbolicate "RAW-INSTANCE-SET/" suffix) word-index-set) + (define-vop (,(symbolicate "%RAW-INSTANCE-SET/" suffix) word-index-set) (:policy :fast-safe) (:translate ,(symbolicate "%RAW-INSTANCE-SET/" suffix)) (:variant instance-slots-offset instance-pointer-lowtag) (:arg-types instance positive-fixnum ,primtype) - (:args (object) (index) (value :scs (,sc))) - (:results (result :scs (,sc))) - (:result-types ,primtype))))) + (:args (object) (index) (value :scs (,sc))))))) (def word unsigned-reg unsigned-num) (def signed-word signed-reg signed-num)) @@ -654,32 +623,7 @@ (inst bne LOOP) (inst isync))) -(define-vop (raw-instance-ref/word word-index-ref) - (:policy :fast-safe) - (:translate %raw-instance-ref/word) - (:variant instance-slots-offset instance-pointer-lowtag) - (:arg-types instance positive-fixnum) - (:results (value :scs (unsigned-reg))) - (:result-types unsigned-num)) - -(define-vop (raw-instance-set/word word-index-set) - (:policy :fast-safe) - (:translate %raw-instance-set/word) - (:variant instance-slots-offset instance-pointer-lowtag) - (:arg-types instance positive-fixnum unsigned-num) - (:args (object) (index) (value :scs (unsigned-reg))) - (:results (result :scs (unsigned-reg))) - (:result-types unsigned-num)) - -(define-vop (raw-instance-init/single) - (:args (object :scs (descriptor-reg)) - (value :scs (single-reg))) - (:arg-types * single-float) - (:info index) - (:generator 4 - (inst stfs value object (offset-for-raw-slot index)))) - -(define-vop (raw-instance-ref/single) +(define-vop () (:translate %raw-instance-ref/single) (:policy :fast-safe) (:args (object :scs (descriptor-reg)) @@ -694,33 +638,21 @@ instance-pointer-lowtag)) (inst lfsx value object offset))) -(define-vop (raw-instance-set/single) +(define-vop () (:translate %raw-instance-set/single) (:policy :fast-safe) (:args (object :scs (descriptor-reg)) (index :scs (any-reg)) - (value :scs (single-reg) :target result)) + (value :scs (single-reg))) (:arg-types * positive-fixnum single-float) - (:results (result :scs (single-reg))) - (:result-types single-float) (:temporary (:scs (non-descriptor-reg)) offset) (:generator 5 (inst sldi offset index (- word-shift n-fixnum-tag-bits)) (inst addi offset offset (- (ash instance-slots-offset word-shift) instance-pointer-lowtag)) - (inst stfsx value object offset) - (unless (location= result value) - (inst frsp result value)))) + (inst stfsx value object offset))) -(define-vop (raw-instance-init/double) - (:args (object :scs (descriptor-reg)) - (value :scs (double-reg))) - (:arg-types * double-float) - (:info index) - (:generator 4 - (inst stfd value object (offset-for-raw-slot index)))) - -(define-vop (raw-instance-ref/double) +(define-vop () (:translate %raw-instance-ref/double) (:policy :fast-safe) (:args (object :scs (descriptor-reg)) @@ -735,36 +667,21 @@ instance-pointer-lowtag)) (inst lfdx value object offset))) -(define-vop (raw-instance-set/double) +(define-vop () (:translate %raw-instance-set/double) (:policy :fast-safe) (:args (object :scs (descriptor-reg)) (index :scs (any-reg)) - (value :scs (double-reg) :target result)) + (value :scs (double-reg))) (:arg-types * positive-fixnum double-float) - (:results (result :scs (double-reg))) - (:result-types double-float) (:temporary (:scs (non-descriptor-reg)) offset) (:generator 5 (inst sldi offset index (- word-shift n-fixnum-tag-bits)) (inst addi offset offset (- (ash instance-slots-offset word-shift) instance-pointer-lowtag)) - (inst stfdx value object offset) - (unless (location= result value) - (inst fmr result value)))) + (inst stfdx value object offset))) -(define-vop (raw-instance-init/complex-single) - (:args (object :scs (descriptor-reg)) - (value :scs (complex-single-reg))) - (:arg-types * complex-single-float) - (:info index) - (:generator 4 - (inst stfs (complex-single-reg-real-tn value) - object (offset-for-raw-slot index)) - (inst stfs (complex-single-reg-imag-tn value) - object (offset-for-raw-slot index (/ n-word-bytes 2))))) - -(define-vop (raw-instance-ref/complex-single) +(define-vop () (:translate %raw-instance-ref/complex-single) (:policy :fast-safe) (:args (object :scs (descriptor-reg)) @@ -781,44 +698,23 @@ (inst addi offset offset (/ n-word-bytes 2)) (inst lfsx (complex-single-reg-imag-tn value) object offset))) -(define-vop (raw-instance-set/complex-single) +(define-vop () (:translate %raw-instance-set/complex-single) (:policy :fast-safe) (:args (object :scs (descriptor-reg)) (index :scs (any-reg)) - (value :scs (complex-single-reg) :target result)) + (value :scs (complex-single-reg))) (:arg-types * positive-fixnum complex-single-float) - (:results (result :scs (complex-single-reg))) - (:result-types complex-single-float) (:temporary (:scs (non-descriptor-reg)) offset) (:generator 5 (inst sldi offset index (- word-shift n-fixnum-tag-bits)) (inst addi offset offset (- (ash instance-slots-offset word-shift) instance-pointer-lowtag)) - (let ((value-real (complex-single-reg-real-tn value)) - (result-real (complex-single-reg-real-tn result))) - (inst stfsx value-real object offset) - (unless (location= result-real value-real) - (inst frsp result-real value-real))) + (inst stfsx (complex-single-reg-real-tn value) object offset) (inst addi offset offset (/ n-word-bytes 2)) - (let ((value-imag (complex-single-reg-imag-tn value)) - (result-imag (complex-single-reg-imag-tn result))) - (inst stfsx value-imag object offset) - (unless (location= result-imag value-imag) - (inst frsp result-imag value-imag))))) - -(define-vop (raw-instance-init/complex-double) - (:args (object :scs (descriptor-reg)) - (value :scs (complex-double-reg))) - (:arg-types * complex-double-float) - (:info index) - (:generator 4 - (inst stfd (complex-single-reg-real-tn value) - object (offset-for-raw-slot index)) - (inst stfd (complex-double-reg-imag-tn value) - object (offset-for-raw-slot index n-word-bytes)))) + (inst stfsx (complex-single-reg-imag-tn value) object offset))) -(define-vop (raw-instance-ref/complex-double) +(define-vop () (:translate %raw-instance-ref/complex-double) (:policy :fast-safe) (:args (object :scs (descriptor-reg)) @@ -835,28 +731,18 @@ (inst addi offset offset n-word-bytes) (inst lfdx (complex-double-reg-imag-tn value) object offset))) -(define-vop (raw-instance-set/complex-double) +(define-vop () (:translate %raw-instance-set/complex-double) (:policy :fast-safe) (:args (object :scs (descriptor-reg)) (index :scs (any-reg)) - (value :scs (complex-double-reg) :target result)) + (value :scs (complex-double-reg))) (:arg-types * positive-fixnum complex-double-float) - (:results (result :scs (complex-double-reg))) - (:result-types complex-double-float) (:temporary (:scs (non-descriptor-reg)) offset) (:generator 5 (inst sldi offset index (- word-shift n-fixnum-tag-bits)) (inst addi offset offset (- (ash instance-slots-offset word-shift) instance-pointer-lowtag)) - (let ((value-real (complex-double-reg-real-tn value)) - (result-real (complex-double-reg-real-tn result))) - (inst stfdx value-real object offset) - (unless (location= result-real value-real) - (inst fmr result-real value-real))) + (inst stfdx (complex-double-reg-real-tn value) object offset) (inst addi offset offset n-word-bytes) - (let ((value-imag (complex-double-reg-imag-tn value)) - (result-imag (complex-double-reg-imag-tn result))) - (inst stfdx value-imag object offset) - (unless (location= result-imag value-imag) - (inst fmr result-imag value-imag))))) + (inst stfdx (complex-double-reg-imag-tn value) object offset))) diff --git a/src/compiler/ppc64/char.lisp b/src/compiler/ppc64/char.lisp index 935ce0b6ed..bc63239bcf 100644 --- a/src/compiler/ppc64/char.lisp +++ b/src/compiler/ppc64/char.lisp @@ -126,7 +126,7 @@ (:note "inline comparison") (:variant-vars condition not-condition) (:generator 2 - (inst cmplwi x (sb-xc:char-code y)) + (inst cmplwi x (char-code y)) (inst b? (if not-p not-condition condition) target))) (define-vop (fast-char=/character/c character-compare/c) diff --git a/src/compiler/ppc64/debug.lisp b/src/compiler/ppc64/debug.lisp index 9ef08501ca..d1b1e9b68a 100644 --- a/src/compiler/ppc64/debug.lisp +++ b/src/compiler/ppc64/debug.lisp @@ -12,15 +12,15 @@ (in-package "SB-VM") (define-vop () - (:translate sb-di::current-sp) + (:translate current-sp) (:policy :fast-safe) (:results (res :scs (sap-reg))) (:result-types system-area-pointer) (:generator 1 (move res csp-tn))) -(define-vop () - (:translate sb-di::current-fp) +(define-vop (current-fp-sap) + (:translate current-fp) (:policy :fast-safe) (:results (res :scs (sap-reg))) (:result-types system-area-pointer) @@ -45,15 +45,12 @@ (:policy :fast-safe) (:args (sap :scs (sap-reg)) (offset :scs (any-reg)) - (value :scs (descriptor-reg) :target result)) + (value :scs (descriptor-reg))) (:arg-types system-area-pointer positive-fixnum *) - (:results (result :scs (descriptor-reg))) (:temporary (:scs (unsigned-reg)) temp) - (:result-types *) (:generator 5 (inst sldi temp offset (- word-shift n-fixnum-tag-bits)) - (inst stdx value sap temp) - (move result value))) + (inst stdx value sap temp))) (define-vop (code-from-mumble) (:policy :fast-safe) diff --git a/src/compiler/ppc64/insts.lisp b/src/compiler/ppc64/insts.lisp index 2d9f808638..4494f2d5cc 100644 --- a/src/compiler/ppc64/insts.lisp +++ b/src/compiler/ppc64/insts.lisp @@ -457,13 +457,10 @@ (def-ppc-iformat (x-4 '(:name :tab rt)) rt (xo xo21-30)) -(def-ppc-iformat (x-5 '(:name :tab ra "," rs "," rb)) +(def-ppc-iformat (x-5 '(:name :tab rs "," ra "," rb)) rs ra rb (xo xo21-30) rc) -(def-ppc-iformat (x-7 '(:name :tab ra "," rs "," rb)) - rs ra rb (xo xo21-30)) - -(def-ppc-iformat (x-8 '(:name :tab ra "," rs "," nb)) +(def-ppc-iformat (x-8 '(:name :tab rs "," ra "," nb)) rs ra nb (xo xo21-30)) (def-ppc-iformat (x-9 '(:name :tab ra "," rs "," sh)) @@ -493,7 +490,7 @@ (def-ppc-iformat (x-22 '(:name :tab frt)) frt (xo xo21-30) rc) -(def-ppc-iformat (x-23 '(:name :tab ra "," frs "," rb)) +(def-ppc-iformat (x-23 '(:name :tab frs "," ra "," rb)) frs ra rb (xo xo21-30)) (def-ppc-iformat (x-24 '(:name :tab bt)) @@ -625,7 +622,8 @@ (emit-d-form-inst segment opcode rt ra (+ (component-header-length) (segment-header-skew segment) - (label-position si)))))) + (label-position si) + (- sb-vm::code-tn-lowtag)))))) (t (when (typep si 'fixup) (note-fixup segment :l si) @@ -1472,9 +1470,12 @@ (macrolet ((def (mnemonic op Rc) `(define-instruction ,mnemonic (segment ra rs sh m) - (:declare (type (integer 0 63) sh m)) + (:declare (type (integer 0 63) sh) (type (or (integer 0 63) fixup) m)) (:printer md-form ((op 30) (subop ,op) (rc ,rc))) (:emitter + (when (and (fixup-p m) (eq (fixup-flavor m) :gc-barrier)) + (note-fixup segment :rldic-m m) + (setq m 0)) (emit-md-form-inst segment 30 (reg-tn-encoding rs) (reg-tn-encoding ra) (ldb (byte 5 0) sh) @@ -2231,6 +2232,7 @@ (:delay 0) (:emitter (etypecase word + #-64-bit (fixup (note-fixup segment :absolute word) (emit-word segment 0)) @@ -2242,6 +2244,7 @@ (:delay 0) (:emitter (etypecase dword + #+64-bit (fixup (note-fixup segment :absolute dword) (emit-dword segment 0)) @@ -2369,16 +2372,90 @@ (defun sort-inline-constants (constants) (stable-sort constants #'> :key (lambda (x) (align-of (car x))))) +(sb-assem::%def-inst-encoder + '.layout-id + (lambda (segment layout) + (sb-c:note-fixup segment :layout-id (sb-c:make-fixup layout :layout-id)) + (sb-assem::%emit-skip segment 4))) + (defun emit-inline-constant (section constant label) (let ((size (align-of constant))) (emit section `(.align ,(integer-length (1- size))) label - (if (eq (car constant) :jump-table) - `(.lispword ,@(coerce (cdr constant) 'list)) - (let* ((val (cdr constant)) - (bytes (loop repeat size - collect (prog1 (ldb (byte 8 0) val) - (setf val (ash val -8)))))) - #+big-endian (setq bytes (nreverse bytes)) - `(.byte ,@bytes)))))) + (cond ((eq (car constant) :jump-table) + `(.lispword ,@(coerce (cdr constant) 'list))) + ((typep (cdr constant) '(cons (eql :layout-id))) + `(.layout-id ,(cddr constant))) + (t + (let* ((val (cdr constant)) + (bytes (loop repeat size + collect (prog1 (ldb (byte 8 0) val) + (setf val (ash val -8)))))) + #+big-endian (setq bytes (nreverse bytes)) + `(.byte ,@bytes))))))) + +(defun sb-vm:fixup-code-object (code offset value kind flavor) + (declare (type index offset) (ignore flavor)) + (unless (zerop (rem offset sb-assem:+inst-alignment-bytes+)) + (error "Unaligned instruction? offset=#x~X." offset)) + (let ((sap (code-instructions code))) + (ecase kind + (:absolute + ;; There is an implicit addend currently stored in the fixup location. + (incf (sap-ref-word sap offset) value)) + (:layout-id + (aver (zerop (sap-ref-32 sap offset))) + (setf (signed-sap-ref-32 sap offset) (the layout-id value))) + (:rldic-m ; This is the M (mask) immediate operand to RLDIC{L,R} which + ;; appears in (byte 6 5) of the instruction. See EMIT-MD-FORM-INST. + (setf (ldb (byte 6 5) (sap-ref-32 sap offset)) (encode-mask6 (- 64 value)))) + (:b + (error "Can't deal with CALL fixups, yet.")) + (:ba + (setf (ldb (byte 24 2) (sap-ref-32 sap offset)) (ash value -2))) + (:ha + (let* ((h (ldb (byte 16 16) value)) + (l (ldb (byte 16 0) value))) + ; Compensate for possible sign-extension when the low half + ; is added to the high. We could avoid this by ORI-ing + ; the low half in 32-bit absolute loads, but it'd be + ; nice to be able to do: + ; lis rX,foo@ha + ; lwz rY,foo@l(rX) + ; and lwz/stw and friends all use a signed 16-bit offset. + (setf (ldb (byte 16 0) (sap-ref-32 sap offset)) + (if (logbitp 15 l) (ldb (byte 16 0) (1+ h)) h)))) + (:l + (setf (ldb (byte 16 0) (sap-ref-32 sap offset)) + (ldb (byte 16 0) value))))) + nil) + +(defun sb-c::pack-retained-fixups (fixup-notes) + (let (result) + (dolist (note fixup-notes (sb-c:pack-code-fixup-locs nil nil result)) + (let ((fixup (fixup-note-fixup note))) + (when (eq (fixup-flavor fixup) :gc-barrier) + (push (fixup-note-position note) result)))))) + +(define-instruction store-coverage-mark (segment mark-index temp) + (:emitter + ;; No backpatch is needed to compute the offset into the code header + ;; because COMPONENT-HEADER-LENGTH is known at this point. + (let ((offset (+ (component-header-length) + ;; skip over jump table word and entries + (* (1+ (component-n-jump-table-entries)) + n-word-bytes) + mark-index + (- code-tn-lowtag)))) + (inst* segment 'stb sb-vm::null-tn sb-vm::code-tn + (etypecase offset + ((unsigned-byte 15) offset) + ((unsigned-byte 31) + ;; This is redundant with the logic in %LR, but unfortunately + ;; %LR does not take a SEGMENT argument. + ;; We could probably do this whole sequence in just 2 instructions- + ;; an "ADDIS LIP, CODE, something" and a STB using LIP as the base. + (inst* segment 'lis temp (ldb (byte 15 16) offset)) + (inst* segment 'ori temp (ldb (byte 16 16) offset)) + temp)))))) diff --git a/src/compiler/ppc64/macros.lisp b/src/compiler/ppc64/macros.lisp index 17f5fec8b4..a0b20360df 100644 --- a/src/compiler/ppc64/macros.lisp +++ b/src/compiler/ppc64/macros.lisp @@ -35,12 +35,10 @@ (defmacro load-symbol (reg symbol) `(inst addi ,reg null-tn (static-symbol-offset ,symbol))) -#+sb-thread -(progn - (defun load-tls-index (reg symbol) - (inst lwz reg symbol (- #+little-endian 4 other-pointer-lowtag))) - (defun store-tls-index (reg symbol) - (inst stw reg symbol (- #+little-endian 4 other-pointer-lowtag)))) +(defun load-tls-index (reg symbol) + (inst lwz reg symbol (- #+little-endian 4 other-pointer-lowtag))) +(defun store-tls-index (reg symbol) + (inst stw reg symbol (- #+little-endian 4 other-pointer-lowtag))) (defmacro load-symbol-value (reg symbol) ;; Work around the usual lowtag subtraction problem. @@ -61,8 +59,6 @@ ;; cross-compile time so we can just use a fixed offset within the ;; TLS block instead of mucking about with the extra memory access ;; (and temp register, for stores)? -#+sb-thread -(progn (defmacro load-tl-symbol-value (reg symbol) `(progn (inst lwz ,reg null-tn (+ (static-symbol-offset ',symbol) @@ -72,14 +68,7 @@ `(progn (inst lwz ,temp null-tn (+ (static-symbol-offset ',symbol) (- #+little-endian 4 other-pointer-lowtag))) - (inst stdx ,reg thread-base-tn ,temp)))) -#-sb-thread -(progn -(defmacro load-tl-symbol-value (reg symbol) - `(load-symbol-value ,reg ,symbol)) -(defmacro store-tl-symbol-value (reg symbol temp) - (declare (ignore temp)) - `(store-symbol-value ,reg ,symbol))) + (inst stdx ,reg thread-base-tn ,temp))) (defmacro load-type (target source &optional (offset 0)) "Loads the type bits of a pointer into target independent of @@ -153,117 +142,6 @@ (loadw ,n-reg cfp-tn (tn-offset ,n-stack)))))))) -;;;; Storage allocation: - -;;; This is the main mechanism for allocating memory in the lisp heap. -;;; -;;; The allocated space is stored in RESULT-TN with the lowtag LOWTAG -;;; applied. The amount of space to be allocated is SIZE bytes (which -;;; must be a multiple of the lisp object size). -;;; -;;; On other platforms (Non-PPC), if STACK-P is given, then allocation -;;; occurs on the control stack (for dynamic-extent). In this case, -;;; you MUST also specify NODE, so that the appropriate compiler -;;; policy can be used, and TEMP-TN, which is needed for work-space. -;;; TEMP-TN MUST be a non-descriptor reg. FIXME: This is not yet -;;; implemented on PPC. We should implement this and replace the -;;; inline stack-based allocation that presently occurs in the -;;; VOPs. The stack-p argument is ignored on PPC. -;;; -;;; If generational GC is enabled, you MUST supply a value for TEMP-TN -;;; because a temp register is needed to do inline allocation. -;;; TEMP-TN, in this case, can be any register, since it holds a -;;; double-word aligned address (essentially a fixnum). -;;; -;;; Using trap instructions for not-very-exceptional situations, such as -;;; allocating, is clever but not very convenient when using gdb to debug. -;;; Set the :sigill-traps feature to use SIGILL instead of SIGTRAP. -;;; -(defun allocation (type size lowtag result-tn &key stack-p node temp-tn flag-tn) - ;; We assume we're in a pseudo-atomic so the pseudo-atomic bit is - ;; set. If the lowtag also has a 1 bit in the same position, we're all - ;; set. Otherwise, we need to zap out the lowtag from alloc-tn, and - ;; then or in the lowtag. - ;; Normal allocation to the heap. - (declare (ignore stack-p node)) - (binding* ((imm-size (typep size '(unsigned-byte 15))) - ((region-base-tn field-offset) - #-sb-thread (values thread-base-tn ; will be STATIC-SPACE-START - ;; skip over the array header - (* 2 n-word-bytes)) - #+sb-thread (values thread-base-tn - (* thread-alloc-region-slot n-word-bytes)))) - - ;; use a spare register because of the usual problem that lw & sw only allow - ;; displacements that are a multiple of 4. Otherwise NULL-TN would do. - ;; STATIC-SPACE-START can be put into the register using exactly 1 instruction - ;; without referencing a code constant, whereas computing the actual base - ;; address of the struct would use an LIS + ORI. - #-sb-thread (inst lr thread-base-tn static-space-start) - - (unless imm-size ; Make temp-tn be the size - (if (numberp size) - (inst lr temp-tn size) - (move temp-tn size))) - - (inst ld result-tn region-base-tn field-offset) - (inst ld flag-tn region-base-tn (+ field-offset n-word-bytes)) ; region->end_addr - - (without-scheduling () - ;; CAUTION: The C code depends on the exact order of - ;; instructions here. In particular, immediately before the - ;; TW instruction must be an ADD or ADDI instruction, so it - ;; can figure out the size of the desired allocation and - ;; storing the new base pointer back to the allocation region - ;; must take two instructions (one on threaded targets). - - ;; Now make result-tn point at the end of the object, to - ;; figure out if we overflowed the current region. - (if imm-size - (inst addi result-tn result-tn size) - (inst add result-tn result-tn temp-tn)) - - ;; result-tn points to the new end of the region. Did we go past - ;; the actual end of the region? If so, we need a full alloc. - ;; The C code depends on this exact form of instruction. If - ;; either changes, you have to change the other appropriately! - ;; - ;; We use the EQ bit of the 5-bit TO field to indicate whether this - ;; allocation can go on large-object pages. The trap condition - ;; is :LGE in that case which "spuriously fails" in the edge case - ;; when it could have actually used the current open region, - ;; exactly touching the end pointer. But that's fine, the trap - ;; handler doesn't bother to see whether the failure was spurious, - ;; because lisp_alloc() just works. - (let ((ok (gen-label))) - (declare (ignorable ok)) - #+sigill-traps - (progn (inst cmpld result-tn flag-tn) - (inst ble ok) - (inst mfmq temp-reg-tn) ; an illegal instructions - ;; KLUDGE: emit another ADD so that the sigtrap handler - ;; can behave just as if the trap happened at the TD. - (if imm-size - (inst addi result-tn result-tn size) - (inst add result-tn result-tn temp-tn))) - (inst td (if (eq type 'list) :lgt :lge) result-tn flag-tn) - #+sigill-traps (emit-label ok)) - ;; The C code depends on exactly 1 instruction here. - (inst std result-tn region-base-tn field-offset)) - - ;; Should the allocation trap above have fired, the runtime - ;; arranges for execution to resume here, just after where we - ;; would have updated the free pointer in the alloc region. - - ;; At this point, result-tn points at the end of the object. - ;; Adjust to point to the beginning. - (cond (imm-size - (inst addi result-tn result-tn (+ (- size) lowtag))) - (t - (inst sub result-tn result-tn temp-tn) - ;; Set the lowtag appropriately - (inst ori result-tn result-tn lowtag))))) - (defmacro with-fixed-allocation ((result-tn flag-tn temp-tn type-code size &key (lowtag other-pointer-lowtag) stack-allocate-p) @@ -284,21 +162,10 @@ (allocation nil (pad-data-block ,size) ,lowtag ,result-tn :temp-tn ,temp-tn :flag-tn ,flag-tn)) - (when ,type-code - (inst lr ,temp-tn (compute-object-header ,size ,type-code)) - (storew ,temp-tn ,result-tn 0 ,lowtag)) + (inst lr ,temp-tn (compute-object-header ,size ,type-code)) + (storew ,temp-tn ,result-tn 0 ,lowtag) ,@body))) -(defun align-csp (temp) - ;; is used for stack allocation of dynamic-extent objects - (let ((aligned (gen-label))) - (inst andi. temp csp-tn lowtag-mask) - (inst beq aligned) - (inst addi csp-tn csp-tn n-word-bytes) - (inst li temp 0) - (storew temp csp-tn -1) - (emit-label aligned))) - ;;;; Error Code (defun emit-error-break (vop kind code values) @@ -321,40 +188,24 @@ ;;;; PSEUDO-ATOMIC -;;; handy macro for making sequences look atomic -;;; -;;; FLAG-TN must be wired to NL3. If a deferred interrupt happens -;;; while we have the low bits of ALLOC-TN set, we add a "large" -;;; constant to FLAG-TN. On exit, we add FLAG-TN to ALLOC-TN which (a) -;;; aligns ALLOC-TN again and (b) makes ALLOC-TN go negative. We then -;;; trap if ALLOC-TN's negative (handling the deferred interrupt) and -;;; using FLAG-TN - minus the large constant - to correct ALLOC-TN. -(defmacro pseudo-atomic ((flag-tn &key (sync t)) &body forms) - (declare (ignorable sync)) - #+sb-safepoint-strictly - `(progn ,flag-tn ,@forms (emit-safepoint)) - #-sb-safepoint-strictly +;;; handy macro for making sequences look atomic with respect to GC +(defmacro pseudo-atomic ((flag-tn &key elide-if (sync t)) &body forms) `(progn - (inst ori alloc-tn alloc-tn pseudo-atomic-flag) + (unless ,elide-if + (inst stb null-tn thread-base-tn (* n-word-bytes thread-pseudo-atomic-bits-slot))) ,@forms - #+sb-thread - (when ,sync - (inst sync)) - (without-scheduling () - (inst subi alloc-tn alloc-tn pseudo-atomic-flag) - ;; Now test to see if the pseudo-atomic interrupted bit is set. - (inst andi. ,flag-tn alloc-tn pseudo-atomic-interrupted-flag) - #+sigill-traps - (let ((continue (gen-label))) - (inst beq continue) - (inst mfmq (make-random-tn :kind :normal :sc (sc-or-lose 'unsigned-reg) :offset 1)) - (emit-label continue)) - #-sigill-traps - (inst twi :ne ,flag-tn 0)) - #+sb-safepoint - (emit-safepoint))) - -#+sb-safepoint -(defun emit-safepoint () - (inst lwz temp-reg-tn null-tn - (- (+ gc-safepoint-trap-offset n-word-bytes other-pointer-lowtag)))) + (unless ,elide-if + (when ,sync + (inst sync)) + (without-scheduling () + ;; Clear PA. The low byte of THREAD-BASE-TN contains 0 as the value to store + (inst stb thread-base-tn thread-base-tn (* n-word-bytes thread-pseudo-atomic-bits-slot)) + ;; Now test to see if the pseudo-atomic interrupted bit is set. + (inst lhz ,flag-tn thread-base-tn (+ 2 (* n-word-bytes thread-pseudo-atomic-bits-slot))) + #+sigill-traps + (let ((continue (gen-label))) + (inst beq continue) + (inst mfmq (make-random-tn :kind :normal :sc (sc-or-lose 'unsigned-reg) :offset 1)) + (emit-label continue)) + #-sigill-traps + (inst twi :ne ,flag-tn 0))))) diff --git a/src/compiler/ppc64/memory.lisp b/src/compiler/ppc64/memory.lisp index 5610c0dfbe..ce9d0bec37 100644 --- a/src/compiler/ppc64/memory.lisp +++ b/src/compiler/ppc64/memory.lisp @@ -11,6 +11,17 @@ ;;;; files for more information. (in-package "SB-VM") + +(defun emit-gc-store-barrier (object cell-address temps &optional value-tn-ref value-tn) + (aver (neq (car temps) cell-address)) ; LD would clobber the cell-address + (when (require-gc-store-barrier-p object value-tn-ref value-tn) + ;; (inst ld (car temps) thread-base-tn (ash thread-card-table-slot word-shift)) + ;; RLIDCL dest, source, (64-rightshift), (64-indexbits) + (inst rldicl (car temps) (or cell-address object) (- 64 gencgc-card-shift) + (make-fixup nil :gc-barrier)) + ;; THREAD-TN's low byte is 0. + (inst stbx thread-base-tn card-table-base-tn (car temps)))) + ;;; Cell-Ref and Cell-Set are used to define VOPs like CAR, where the offset to ;;; be read or written is a property of the VOP used. @@ -28,13 +39,39 @@ (value :scs (descriptor-reg any-reg))) (:variant-vars offset lowtag) (:policy :fast-safe) + (:vop-var vop) + (:temporary (:sc non-descriptor-reg) t1) (:generator 4 + (emit-gc-store-barrier object nil (list t1) (vop-nth-arg 1 vop) value) (storew value object offset lowtag))) ;;;; Indexed references: ;;; Define some VOPs for indexed memory reference. +(define-vop (descriptor-word-index-set) + (:args (object :scs (descriptor-reg)) + (index :scs (any-reg immediate)) + (value :scs (any-reg descriptor-reg))) + (:arg-types * tagged-num *) + (:temporary (:scs (non-descriptor-reg)) temp) + (:variant-vars offset lowtag) + (:policy :fast-safe) + (:vop-var vop) + (:generator 5 + (emit-gc-store-barrier object nil (list temp) (vop-nth-arg 2 vop) value) + (sc-case index + ((immediate) + (let ((offset (- (ash (+ (tn-value index) offset) word-shift) lowtag))) + (cond ((and (typep offset '(signed-byte 16)) (not (logtest offset #b11))) + (inst std value object offset)) + (t + (inst lr temp offset) + (inst stdx value object temp))))) + (t + (inst addi temp index (- (ash offset word-shift) lowtag)) + (inst stdx value object temp))))) + ;;; Due to the encoding restrictione that doubleword accesses can not displace ;;; from the base register by an arbitrarily aligned value, but only an even ;;; multiple of 4. By using a certain arrangement of lowtags we can get two of @@ -60,13 +97,12 @@ `(define-vop (,name) (:args (object :scs (descriptor-reg)) (index :scs (any-reg immediate)) - ,@(when write-p - '((value :scs (any-reg descriptor-reg) :target result)))) + ,@(when write-p '((value :scs (any-reg descriptor-reg))))) (:arg-types * tagged-num ,@(when write-p '(*))) (:temporary (:scs (non-descriptor-reg)) temp) - (:results (,(if write-p 'result 'value) - :scs (any-reg descriptor-reg))) - (:result-types *) + ,@(unless write-p + `((:results (value :scs (any-reg descriptor-reg))) + (:result-types *))) (:variant-vars offset lowtag) (:policy :fast-safe) (:generator 5 @@ -92,20 +128,19 @@ (- (ash offset word-shift) lowtag)) (inst ,rr-op value object temp))) ,@(when sign-extend-byte - `((inst extsb value value))) - ,@(when write-p - '((move result value)))))) + `((inst extsb value value)))))) (define-indexer word-index-ref 3 nil ld ldx) ;; Word means Lisp Word -(define-indexer word-index-set 3 t std stdx) (define-indexer 32-bits-index-ref 2 nil lwz lwzx) (define-indexer signed-32-bits-index-ref 2 nil lwa lwax :multiple-of-four t) -(define-indexer 32-bits-index-set 2 t stw stwx) (define-indexer 16-bits-index-ref 1 nil lhz lhzx) (define-indexer signed-16-bits-index-ref 1 nil lha lhax) -(define-indexer 16-bits-index-set 1 t sth sthx) (define-indexer byte-index-ref 0 nil lbz lbzx) (define-indexer signed-byte-index-ref 0 nil lbz lbzx :sign-extend-byte t) + +(define-indexer word-index-set 3 t std stdx) +(define-indexer 32-bits-index-set 2 t stw stwx) +(define-indexer 16-bits-index-set 1 t sth sthx) (define-indexer byte-index-set 0 t stb stbx) (define-vop (word-index-cas) @@ -119,12 +154,23 @@ (:result-types *) (:variant-vars offset lowtag) (:policy :fast-safe) + (:vop-var vop) (:generator 5 + (let ((ea + (ecase lowtag + (#.instance-pointer-lowtag nil) + (#.other-pointer-lowtag ; has to be (SETF SVREF) + (cond ((sc-is index immediate) + (let ((offset (- (ash (+ (tn-value index) offset) word-shift) lowtag))) + (inst lr temp offset))) + (t + (inst addi temp index (- (ash offset word-shift) lowtag)))) + (inst add temp object temp) + temp)))) + (emit-gc-store-barrier object ea (list result temp) (vop-nth-arg 3 vop) new-value)) (sc-case index ((immediate) - (let ((offset (- (+ (ash (tn-value index) word-shift) - (ash offset word-shift)) - lowtag))) + (let ((offset (- (ash (+ (tn-value index) offset) word-shift) lowtag))) (inst lr temp offset))) (t (inst sldi temp index (- word-shift n-fixnum-tag-bits)) diff --git a/src/compiler/ppc64/move.lisp b/src/compiler/ppc64/move.lisp index 60df566ae5..347d961425 100644 --- a/src/compiler/ppc64/move.lisp +++ b/src/compiler/ppc64/move.lisp @@ -208,7 +208,7 @@ (2 '((inst addo x arg arg) (inst addo. y x x))) (3 '((inst addo x arg arg) (inst addo x x x) (inst addo. y x x)))) (inst bns done) ; branch if no summary overflow - (load-constant vop (emit-constant (1+ sb-xc:most-positive-fixnum)) y) + (load-constant vop (emit-constant (1+ most-positive-fixnum)) y) DONE)))) (define-move-from-fixnum+1)) @@ -221,7 +221,7 @@ (2 '((inst addo x arg arg) (inst addo. y x x))) (3 '((inst addo x arg arg) (inst addo x x x) (inst addo. y x x)))) (inst bns done) ; branch if no summary overflow - (load-constant vop (emit-constant (1- sb-xc:most-negative-fixnum)) y) + (load-constant vop (emit-constant (1- most-negative-fixnum)) y) DONE)))) (define-move-from-fixnum-1)) diff --git a/src/compiler/ppc64/nlx.lisp b/src/compiler/ppc64/nlx.lisp index 4e63a62a9e..22b76ffdea 100644 --- a/src/compiler/ppc64/nlx.lisp +++ b/src/compiler/ppc64/nlx.lisp @@ -42,7 +42,7 @@ (:args (catch :scs (descriptor-reg)) (nfp :scs (descriptor-reg)) (nsp :scs (descriptor-reg))) - #+sb-thread (:temporary (:scs (any-reg)) temp) + (:temporary (:scs (any-reg)) temp) (:vop-var vop) (:generator 10 (store-tl-symbol-value catch *current-catch-block* temp) @@ -126,7 +126,7 @@ ;;; (define-vop (set-unwind-protect) (:args (uwp :scs (any-reg))) - #+sb-thread (:temporary (:scs (any-reg)) temp) + (:temporary (:scs (any-reg)) temp) (:generator 7 (store-tl-symbol-value uwp *current-unwind-protect-block* temp))) @@ -135,7 +135,7 @@ (:args (current-block)) (:ignore current-block) (:temporary (:scs (any-reg)) block) - #+sb-thread (:temporary (:scs (any-reg)) temp) + (:temporary (:scs (any-reg)) temp) (:policy :fast-safe) (:generator 17 (load-tl-symbol-value block *current-catch-block*) @@ -146,7 +146,7 @@ (:args (current-block)) (:ignore current-block) (:temporary (:scs (any-reg)) block) - #+sb-thread (:temporary (:scs (any-reg)) temp) + (:temporary (:scs (any-reg)) temp) (:policy :fast-safe) (:generator 17 (load-tl-symbol-value block *current-unwind-protect-block*) @@ -214,6 +214,18 @@ (inst b defaulting-done)))))) (load-stack-tn csp-tn sp))) +(define-vop (nlx-entry-single) + (:args (sp) + (value)) + (:results (res :from :load)) + (:info label) + (:save-p :force-to-stack) + (:vop-var vop) + (:generator 30 + (emit-return-pc label) + (note-this-location vop :non-local-entry) + (move res value) + (load-stack-tn csp-tn sp))) (define-vop (nlx-entry-multiple) (:args (top :target result) (src) (count :target limit)) diff --git a/src/compiler/ppc64/parms.lisp b/src/compiler/ppc64/parms.lisp index af69f6a492..2a80fbfe07 100644 --- a/src/compiler/ppc64/parms.lisp +++ b/src/compiler/ppc64/parms.lisp @@ -19,17 +19,14 @@ (defconstant sb-assem:+inst-alignment-bytes+ 4) (defconstant +backend-fasl-file-implementation+ :ppc) - ;; On Linux, the ABI specifies the page size to be 4k-64k, use the - ;; maximum of that range. FIXME: it'd be great if somebody would - ;; find out whether using exact multiples of the page size actually - ;; matters in the few places where that's done, or whether we could - ;; just use 4k everywhere. -(defconstant +backend-page-bytes+ #+linux 65536 #-linux 4096) - -;;; The size in bytes of GENCGC cards, i.e. the granularity at which -;;; writes to old generations are logged. With mprotect-based write -;;; barriers, this must be a multiple of the OS page size. -(defconstant gencgc-card-bytes +backend-page-bytes+) +;; Granularity at which memory is mapped +(defconstant +backend-page-bytes+ 65536) + +;;; The size in bytes of GENCGC pages, i.e. the granularity at which +;;; threads claim memory from the global heap. +(defconstant gencgc-page-bytes +backend-page-bytes+) +;;; Granularity at which writes to old generations are logged. +(defconstant cards-per-page 32) ;;; The minimum size of new allocation regions. While it doesn't ;;; currently make a lot of sense to have a card size lower than ;;; the alloc granularity, it will, once we are smarter about finding @@ -46,33 +43,6 @@ ;;; address space) (defconstant n-machine-word-bits 64) -;;; flags for the generational garbage collector -(defconstant pseudo-atomic-interrupted-flag 1) -(defconstant pseudo-atomic-flag 4) - -(defconstant float-sign-shift 31) - -(defconstant single-float-bias 126) -(defconstant-eqx single-float-exponent-byte (byte 8 23) #'equalp) -(defconstant-eqx single-float-significand-byte (byte 23 0) #'equalp) -(defconstant single-float-normal-exponent-min 1) -(defconstant single-float-normal-exponent-max 254) -(defconstant single-float-hidden-bit (ash 1 23)) - -(defconstant double-float-bias 1022) -(defconstant-eqx double-float-exponent-byte (byte 11 20) #'equalp) -(defconstant-eqx double-float-significand-byte (byte 20 0) #'equalp) -(defconstant double-float-normal-exponent-min 1) -(defconstant double-float-normal-exponent-max #x7FE) -(defconstant double-float-hidden-bit (ash 1 20)) - -(defconstant single-float-digits - (+ (byte-size single-float-significand-byte) 1)) - -(defconstant double-float-digits - (+ (byte-size double-float-significand-byte) 32 1)) - - (defconstant float-inexact-trap-bit (ash 1 0)) (defconstant float-divide-by-zero-trap-bit (ash 1 1)) (defconstant float-underflow-trap-bit (ash 1 2)) @@ -108,59 +78,13 @@ ;;;; Where to put the different spaces. -;;; On non-gencgc we need large dynamic and static spaces for PURIFY -#-gencgc -(progn - (defconstant read-only-space-start #x04000000) - (defconstant read-only-space-end #x07ff8000) - (defconstant static-space-start #x08000000) - (defconstant static-space-end #x097fff00) - - (defconstant linkage-table-space-start #x0a000000) - (defconstant linkage-table-space-end #x0b000000)) - -;;; While on gencgc we don't. -#+gencgc (!gencgc-space-setup #x04000000 +(!gencgc-space-setup #x04000000 :read-only-space-size 0 :dynamic-space-start #x1000000000) -(defconstant linkage-table-growth-direction :up) -(defconstant linkage-table-entry-size #+little-endian 28 #+big-endian 24) - -#+linux -(progn - #-gencgc - (progn - (defparameter dynamic-0-space-start #x4f000000) - (defparameter dynamic-0-space-end #x66fff000))) - -#+netbsd -(progn - #-gencgc - (progn - (defparameter dynamic-0-space-start #x4f000000) - (defparameter dynamic-0-space-end #x66fff000))) - -;;; Text and data segments start at #x01800000. Range for randomized -;;; malloc() starts #x20000000 (MAXDSIZ) after end of data seg and -;;; extends 256 MB. Use 512 - 64 MB for dynamic space so we can run -;;; under default resource limits. -;;; FIXME: MAXDSIZ is a kernel parameter, and can vary as high as 1GB. -;;; These parameters should probably be tested under such a configuration, -;;; as rare as it might or might not be. -#+openbsd -(progn - #-gencgc - (progn - (defparameter dynamic-0-space-start #x4f000000) - (defparameter dynamic-0-space-end #x5cfff000))) - -#+darwin -(progn - #-gencgc - (progn - (defparameter dynamic-0-space-start #x10000000) - (defparameter dynamic-0-space-end #x3ffff000))) +(defconstant alien-linkage-table-growth-direction :up) +(defconstant alien-linkage-table-entry-size #+little-endian 28 #+big-endian 24) + (defenum (:start 8) halt-trap diff --git a/src/compiler/ppc64/sap.lisp b/src/compiler/ppc64/sap.lisp index e94f28f87c..d5b9762937 100644 --- a/src/compiler/ppc64/sap.lisp +++ b/src/compiler/ppc64/sap.lisp @@ -136,13 +136,53 @@ ;;;; mumble-SYSTEM-REF and mumble-SYSTEM-SET (macrolet ((def-system-ref-and-set (ref-name set-name sc type size &optional signed) - (let () - `(progn - (define-vop (,ref-name) - (:translate ,ref-name) + `(progn + ;; smaller-than-word atomics are not necessarily implemented in hardware. + ;; I found something about it regarding C compiler intrinsics: + ;; "__lqarx, __lharx, and __lbarx is valid only when -qarch is set to target POWER8 processors." + ;; https://www.ibm.com/docs/en/xl-c-aix/13.1.0?topic=functions-lqarx-ldarx-lwarx-lharx-lbarx + ;; and in fact they're not present on gcc110.fsffrance.org + ;; You're supposed to use lwarx, stwcx. in those cases, + ;; which I don't feel like doing. + ,@(when (member ref-name '(sap-ref-8 sap-ref-16 + sap-ref-32 sap-ref-64 signed-sap-ref-64 + sap-ref-lispobj sap-ref-sap)) + (multiple-value-bind (load store) + (ecase size + (:byte (values 'lbarx 'stbcx.)) + (:short (values 'lharx 'sthcx.)) + (:word (values 'lwarx 'stwcx.)) + (:long (values 'ldarx 'stdcx.))) + `((define-vop (,(symbolicate "CAS-" ref-name)) + (:translate (cas ,ref-name)) + (:policy :fast-safe) + (:args (oldval :scs (,sc)) + (newval :scs (,sc)) + (sap :scs (sap-reg)) + (offset :scs (signed-reg))) + (:arg-types ,type ,type system-area-pointer signed-num) + (:results (result :scs (,sc) :from :load)) + (:result-types ,type) + (:generator 5 + ;; sap-registers = non-descriptor-registers which does not include reg 0, + ;; but make sure, because 0 as RA means the immediate value 0. + (aver (/= (tn-offset sap) 0)) + (inst sync) + LOOP + (inst ,load result sap offset) + ;; The load-and-reserve forms shorter than 'Doubleword' clear + ;; all the remaining bits of the destination register, + ;; so it's always OK to use a doubleword comparison. + (inst cmpd result oldval) + (inst bne EXIT) + (inst ,store newval sap offset) + (inst bne LOOP) + EXIT + (inst isync)))))) + (define-vop (,ref-name) + (:translate ,ref-name) (:policy :fast-safe) - (:args (sap :scs (sap-reg)) - (offset :scs (signed-reg))) + (:args (sap :scs (sap-reg)) (offset :scs (signed-reg))) (:arg-types system-area-pointer signed-num) (:results (result :scs (,sc))) (:result-types ,type) @@ -159,8 +199,8 @@ '((inst extsb result result))))) ;;; FIXME: need to add a constraint on the offset alignment for doubleword #+nil - (define-vop (,(symbolicate ref-name "-C")) - (:translate ,ref-name) + (define-vop (,(symbolicate ref-name "-C")) + (:translate ,ref-name) (:policy :fast-safe) (:args (sap :scs (sap-reg))) (:arg-types system-area-pointer (:constant (signed-byte 16))) @@ -177,15 +217,13 @@ result sap offset) ,@(when (and (eq size :byte) signed) '((inst extsb result result))))) - (define-vop (,set-name) - (:translate ,set-name) + (define-vop (,set-name) + (:translate ,set-name) (:policy :fast-safe) - (:args (sap :scs (sap-reg)) - (offset :scs (signed-reg)) - (value :scs (,sc) :target result)) - (:arg-types system-area-pointer signed-num ,type) - (:results (result :scs (,sc))) - (:result-types ,type) + (:args (value :scs (,sc)) + (sap :scs (sap-reg)) + (offset :scs (signed-reg))) + (:arg-types ,type system-area-pointer signed-num) (:generator 5 (inst ,(ecase size (:byte 'stbx) @@ -194,25 +232,15 @@ (:long 'stdx) (:single 'stfsx) (:double 'stfdx)) - value sap offset) - (unless (location= result value) - ,@(case size - (:single - '((inst frsp result value))) - (:double - '((inst fmr result value))) - (t - '((inst mr result value))))))) + value sap offset))) #+nil - (define-vop (,(symbolicate set-name "-C")) - (:translate ,set-name) + (define-vop (,(symbolicate set-name "-C")) + (:translate ,set-name) (:policy :fast-safe) - (:args (sap :scs (sap-reg)) - (value :scs (,sc) :target result)) - (:arg-types system-area-pointer (:constant (signed-byte 16)) ,type) + (:args (value :scs (,sc)) + (sap :scs (sap-reg))) + (:arg-types ,type system-area-pointer (:constant (signed-byte 16))) (:info offset) - (:results (result :scs (,sc))) - (:result-types ,type) (:generator 4 (inst ,(ecase size (:byte 'stb) @@ -220,15 +248,7 @@ (:long 'stw) (:single 'stfs) (:double 'stfd)) - value sap offset) - (unless (location= result value) - ,@(case size - (:single - '((inst frsp result value))) - (:double - '((inst fmr result value))) - (t - '((inst mr result value))))))))))) + value sap offset)))))) (def-system-ref-and-set sap-ref-8 %set-sap-ref-8 unsigned-reg positive-fixnum :byte nil) (def-system-ref-and-set signed-sap-ref-8 %set-signed-sap-ref-8 diff --git a/src/compiler/ppc64/system.lisp b/src/compiler/ppc64/system.lisp index 13c144de99..2908291b06 100644 --- a/src/compiler/ppc64/system.lisp +++ b/src/compiler/ppc64/system.lisp @@ -63,6 +63,33 @@ instance-pointer-lowtag)) (inst lwax res object temp))) +(define-vop () + (:translate sb-c::%structure-is-a) + (:args (x :scs (descriptor-reg))) + (:arg-types * (:constant t)) + (:policy :fast-safe) + (:conditional) + ;; "extra" info in conditional vops follows the 2 super-magical info args + (:info target not-p test-layout) + (:temporary (:scs (non-descriptor-reg)) this-id) + (:generator 4 + (let ((test-id (layout-id test-layout)) + (offset (+ (id-bits-offset) + (ash (- (wrapper-depthoid test-layout) 2) 2) + (- instance-pointer-lowtag)))) + (inst lwa this-id x offset) + ;; Always prefer 'cmpwi' if compiling to memory. + ;; 8-bit IDs are permanently assigned, so no fixup ever needed for those. + (cond ((or (typep test-id '(and (signed-byte 8) (not (eql 0)))) + (and (not (sb-c::producing-fasl-file)) + (typep test-id '(signed-byte 16)))) + (inst cmpwi this-id test-id)) + (t + (inst lwa temp-reg-tn code-tn + (register-inline-constant `(:layout-id . ,test-layout) :word)) + (inst cmpw this-id temp-reg-tn)))) + (inst b? (if not-p :ne :eq) target))) + (define-vop (%other-pointer-widetag) (:translate %other-pointer-widetag) (:policy :fast-safe) @@ -72,8 +99,8 @@ (:generator 6 (load-type result object (- other-pointer-lowtag)))) -(define-vop (fun-subtype) - (:translate fun-subtype) +(define-vop () + (:translate %fun-pointer-widetag) (:policy :fast-safe) (:args (function :scs (descriptor-reg))) (:results (result :scs (unsigned-reg))) @@ -94,17 +121,15 @@ (define-vop (set-header-data) (:translate set-header-data) (:policy :fast-safe) - (:args (x :scs (descriptor-reg) :target res) + (:args (x :scs (descriptor-reg)) (data :scs (any-reg))) (:arg-types * positive-fixnum) - (:results (res :scs (descriptor-reg))) (:temporary (:scs (non-descriptor-reg)) t1 t2) (:generator 6 (load-type t1 x (- other-pointer-lowtag)) (inst sldi t2 data (- n-widetag-bits n-fixnum-tag-bits)) (inst or t1 t1 t2) - (storew t1 x 0 other-pointer-lowtag) - (move res x))) + (storew t1 x 0 other-pointer-lowtag))) (define-vop (pointer-hash) (:translate pointer-hash) @@ -117,14 +142,6 @@ ;;;; Allocation -(define-vop (dynamic-space-free-pointer) - (:results (int :scs (sap-reg))) - (:result-types system-area-pointer) - (:translate dynamic-space-free-pointer) - (:policy :fast-safe) - (:generator 1 - (move int alloc-tn))) - (define-vop (binding-stack-pointer-sap) (:results (int :scs (sap-reg))) (:result-types system-area-pointer) @@ -184,7 +201,6 @@ (:generator 1 (inst unimp pending-interrupt-trap))) -#+sb-thread (define-vop (current-thread-offset-sap) (:results (sap :scs (sap-reg))) (:result-types system-area-pointer) @@ -249,3 +265,11 @@ (:translate spin-loop-hint) (:policy :fast-safe) (:generator 0)) + +(define-vop (sb-c::mark-covered) + (:info index) + (:temporary (:sc unsigned-reg) tmp) + (:generator 4 + ;; Can't convert index to a code-relative index until the boxed header length + ;; has been determined. + (inst store-coverage-mark index tmp))) diff --git a/src/compiler/ppc64/type-vops.lisp b/src/compiler/ppc64/type-vops.lisp index a4e0c4414e..e3dee70da1 100644 --- a/src/compiler/ppc64/type-vops.lisp +++ b/src/compiler/ppc64/type-vops.lisp @@ -126,7 +126,7 @@ (define-vop (signed-byte-64-p type-predicate) (:translate signed-byte-64-p) - (:generator 45 + (:generator 10 (multiple-value-bind (yep nope) (if not-p (values not-target target) @@ -144,7 +144,7 @@ ;;; exactly two digits and the second digit all zeros. (define-vop (unsigned-byte-64-p type-predicate) (:translate unsigned-byte-64-p) - (:generator 45 + (:generator 10 (let ((not-target (gen-label)) (single-word (gen-label)) (fixnum (gen-label))) diff --git a/src/compiler/ppc64/values.lisp b/src/compiler/ppc64/values.lisp index 5f4ffb0ddd..f2a4103695 100644 --- a/src/compiler/ppc64/values.lisp +++ b/src/compiler/ppc64/values.lisp @@ -56,11 +56,12 @@ ;;; operand, but this seems unworthwhile. ;;; (define-vop (push-values) - (:args (vals :more t)) + (:args (vals :more t :scs (descriptor-reg any-reg control-stack))) (:results (start :scs (any-reg) :from :load) (count :scs (any-reg))) (:info nvals) (:temporary (:scs (descriptor-reg)) temp) + (:vop-var vop) (:generator 20 (inst mr start csp-tn) (inst addi csp-tn csp-tn (* nvals n-word-bytes)) @@ -69,10 +70,13 @@ ((null val)) (let ((tn (tn-ref-tn val))) (sc-case tn - (descriptor-reg + ((descriptor-reg any-reg) (storew tn start i)) (control-stack (load-stack-tn temp tn) + (storew temp start i)) + (constant + (load-constant vop tn temp) (storew temp start i))))) (inst lr count (fixnumize nvals)))) @@ -113,9 +117,8 @@ ;;; (define-vop (%more-arg-values) (:args (context :scs (descriptor-reg any-reg) :target src) - (skip :scs (any-reg immediate)) (num :scs (any-reg) :target count)) - (:arg-types * positive-fixnum positive-fixnum) + (:arg-types * positive-fixnum) (:temporary (:sc any-reg :from (:argument 0)) src) (:temporary (:sc any-reg :from (:argument 2)) dst) (:temporary (:sc descriptor-reg :from (:argument 1)) temp) @@ -123,15 +126,7 @@ (:results (start :scs (any-reg)) (count :scs (any-reg))) (:generator 20 - (sc-case skip - (immediate - (inst addi src context (* (tn-value skip) n-word-bytes))) - (any-reg - (let ((delta (cond ((= n-fixnum-tag-bits word-shift) skip) - (t (inst slwi temp-reg-tn skip - (- word-shift n-fixnum-tag-bits)) - temp-reg-tn)))) - (inst add src context delta)))) + (move src context) (inst mr. count num) (inst mr start csp-tn) (inst beq done) diff --git a/src/compiler/ppc64/vm.lisp b/src/compiler/ppc64/vm.lisp index 8fd7f5e8f2..812b020087 100644 --- a/src/compiler/ppc64/vm.lisp +++ b/src/compiler/ppc64/vm.lisp @@ -11,6 +11,9 @@ (in-package "SB-VM") +(defconstant-eqx +fixup-kinds+ #(:absolute :layout-id :b :ba :ha :l :rldic-m) + #'equalp) + ;;; NUMBER-STACK-DISPLACEMENT ;;; ;;; The number of bytes reserved above the number stack pointer. These @@ -53,7 +56,7 @@ (defreg bsp 14) (defreg cfp 15) (defreg csp 16) - (defreg alloc 17) + (defreg gc-card-table 17) (defreg null 18) ;; Use of a tagged pointer in reg_CODE on PPC64 is expensive, adding an extra ;; instruction to each load of a boxed constant. We should allow this register @@ -223,6 +226,13 @@ ;;;; Make some random tns for important registers. +(defparameter thread-base-tn + (make-random-tn :kind :normal :sc (sc-or-lose 'unsigned-reg) + :offset thread-offset)) +(defparameter card-table-base-tn + (make-random-tn :kind :normal :sc (sc-or-lose 'unsigned-reg) + :offset gc-card-table-offset)) + (macrolet ((defregtn (name sc) (let ((offset-sym (symbolicate name "-OFFSET")) (tn-sym (symbolicate name "-TN"))) @@ -234,7 +244,6 @@ (defregtn lip interior-reg) (defregtn null descriptor-reg) (defregtn code descriptor-reg) - (defregtn alloc any-reg) (defregtn lra descriptor-reg) (defregtn lexenv descriptor-reg) @@ -251,7 +260,7 @@ (typecase value (null null-sc-number) - ((or (integer #.sb-xc:most-negative-fixnum #.sb-xc:most-positive-fixnum) + ((or (integer #.most-negative-fixnum #.most-positive-fixnum) character) immediate-sc-number) (symbol @@ -294,10 +303,6 @@ :offset n)) *register-arg-offsets*)) -(defparameter thread-base-tn - (make-random-tn :kind :normal :sc (sc-or-lose 'unsigned-reg) - :offset thread-offset)) - (export 'single-value-return-byte-offset) ;;; This is used by the debugger. @@ -356,8 +361,8 @@ (destructuring-bind (size posn integer) (sb-c::basic-combination-args node) (declare (ignore integer)) - (<= (+ (sb-c::lvar-value size) - (sb-c::lvar-value posn)) + (<= (+ (sb-c:lvar-value size) + (sb-c:lvar-value posn)) width))))) (if (or (validp 'fixnum 29) (validp '(signed-byte 32) 32) diff --git a/src/compiler/proclaim.lisp b/src/compiler/proclaim.lisp index 1614a6fbf4..cb9b772c0b 100644 --- a/src/compiler/proclaim.lisp +++ b/src/compiler/proclaim.lisp @@ -17,7 +17,199 @@ ;;; A list of UNDEFINED-WARNING structures representing references to unknown ;;; stuff which came up in a compilation unit. (defvar *undefined-warnings*) -(declaim (list *undefined-warnings*)) +(defvar *argument-mismatch-warnings*) +(declaim (list *undefined-warnings* *argument-mismatch-warnings*)) + +;;; Delete any undefined warnings for NAME and KIND. This is for the +;;; benefit of the compiler, but it's sometimes called from stuff like +;;; type-defining code which isn't logically part of the compiler. +(declaim (ftype (function ((or symbol cons) keyword) (values)) + note-name-defined)) +(defun note-name-defined (name kind) + #-sb-xc-host (atomic-incf sb-kernel::*type-cache-nonce*) + ;; We do this BOUNDP check because this function can be called when + ;; not in a compilation unit (as when loading top level forms). + (when (boundp '*undefined-warnings*) + (let ((name (uncross name))) + (setq *undefined-warnings* + (delete-if (lambda (x) + (and (equal (undefined-warning-name x) name) + (eq (undefined-warning-kind x) kind))) + *undefined-warnings*)))) + (values)) + +(defun check-variable-name (name &key + (context "local variable") + (signal-via #'compiler-error)) + (unless (legal-variable-name-p name) + (funcall signal-via "~@<~S~[~; is a keyword and~; is not a symbol and~ + ~] cannot be used as a ~A.~@:>" + name + (typecase name + (null 0) + (keyword 1) + (t 2)) + context)) + name) + +;;; Check that NAME is a valid function name, returning the name if +;;; OK, and signalling an error if not. In addition to checking for +;;; basic well-formedness, we also check that symbol names are not NIL +;;; or the name of a special form. +(defun check-fun-name (name) + (typecase name + (list + (unless (legal-fun-name-p name) + (compiler-error "~@<Illegal function name: ~S.~@:>" name))) + (symbol + (when (eq (info :function :kind name) :special-form) + (compiler-error "~@<Special form is an illegal function name: ~S.~@:>" + name))) + (t + (compiler-error "~@<Illegal function name: ~S.~@:>" name))) + name) + +;;; Check that NAME is a valid class name, returning the name if OK, +;;; and signalling an error if not. +(declaim (inline sb-pcl::check-class-name)) +(defun sb-pcl::check-class-name (name &optional (allow-nil t)) + ;; Apparently, FIND-CLASS and (SETF FIND-CLASS) accept any symbol, + ;; but DEFCLASS only accepts non-NIL symbols. + (if (or (not (legal-class-name-p name)) + (and (null name) (not allow-nil))) + (error 'sb-kernel::illegal-class-name-error :name name) + name)) + +;;; Check that NAME is a valid designator for the defining macro +;;; MACRO. This is used mostly to give a consistent message for all +;;; defining forms, except for DEFCLASS, which uses CHECK-CLASS-NAME. +(defun check-designator (name macro &optional (predicate #'symbolp) + (what "symbol") + (arg-reference "NAME")) + ;; If we decide that the correct behavior is to actually macroexpand + ;; and then fail later, well, I suppose we could express all macros + ;; such that they perform their LEGAL-FUN-NAME-P/SYMBOLP check as + ;; part of the ordinary code, as in: (DEFPARAMETER "foo" 3) -> + ;; (%defparameter (the symbol '"foo") ...) which seems at least + ;; slightly preferable to failing in the internal function that + ;; would store the globaldb info. + (unless (funcall predicate name) + (error (format nil "The ~A argument to ~A, ~~S, is not a ~A." + arg-reference macro what) + name))) + +;;; This is called to do something about SETF functions that overlap +;;; with SETF macros. Perhaps we should interact with the user to see +;;; whether the macro should be blown away, but for now just give a +;;; warning. Due to the weak semantics of the (SETF FUNCTION) name, we +;;; can't assume that they aren't just naming a function (SETF FOO) +;;; for the heck of it. NAME is already known to be well-formed. +(defun warn-if-setf-macro (name) + ;; Never warn about this situation when running the cross-compiler. + ;; SBCL provides expanders/inverses *and* functions for most SETFable things + ;; even when CLHS does not specifically state that #'(SETF x) exists. + #+sb-xc-host (declare (ignore name)) + #-sb-xc-host + (let ((stem (second name))) + (when (info :setf :expander stem) + (compiler-style-warn + "defining function ~S when ~S already has a SETF macro" + name stem))) + (values)) + +;;; Record a new function definition, and check its legality. +(defun proclaim-as-fun-name (name) + + ;; legal name? + (check-fun-name name) + + ;; KLUDGE: This can happen when eg. compiling a NAMED-LAMBDA, and isn't + ;; guarded against elsewhere -- so we want to assert package locks here. The + ;; reason we do it only when stomping on existing stuff is because we want + ;; to keep + ;; (WITHOUT-PACKAGE-LOCKS (DEFUN LOCKED:FOO ...)) + ;; viable, which requires no compile-time violations in the harmless cases. + (with-single-package-locked-error () + (flet ((assert-it () + (assert-symbol-home-package-unlocked name "proclaiming ~S as a function"))) + + (let ((kind (info :function :kind name))) + ;; scrubbing old data: possible collision with a macro + ;; There's a silly little problem with fun names that are not ANSI-legal names, + ;; e.g. (CAS mumble). We can't ask the host whether that is FBOUNDP, + ;; because it would rightly complain. So, just assume that it is not FBOUNDP. + (when (and #+sb-xc-host (symbolp name) + (fboundp name) + (eq :macro kind)) + (assert-it) + (compiler-style-warn "~S was previously defined as a macro." name) + (setf (info :function :where-from name) :assumed) + (clear-info :function :macro-function name)) + + (unless (eq :function kind) + (assert-it) + ;; There's no reason to store (:FUNCTION :KIND) for names which + ;; could only be of kind :FUNCTION if anything. + (unless (pcl-methodfn-name-p name) + (setf (info :function :kind name) :function)))))) + + (values)) + +;;; Make NAME no longer be a function name: clear everything back to +;;; the default. +(defun undefine-fun-name (name) + (when name + (macrolet ((frob (&rest types) + `(clear-info-values + name ',(mapcar (lambda (x) + (meta-info-number (meta-info :function x))) + types)))) + ;; Note that this does not clear the :DEFINITION. + ;; That's correct, because if we lose the association between a + ;; symbol and its #<fdefn> object, it could lead to creation of + ;; a non-unique #<fdefn> for a name. + (frob :info + :type ; Hmm. What if it was proclaimed- shouldn't it stay? + :where-from ; Ditto. + :inlinep + :kind + :macro-function + :inlining-data + :source-transform + :assumed-type))) + (values)) + +;;; part of what happens with DEFUN, also with some PCL stuff: Make +;;; NAME known to be a function definition. +(defun become-defined-fun-name (name) + (proclaim-as-fun-name name) + (when (eq (info :function :where-from name) :assumed) + (setf (info :function :where-from name) :defined) + (if (info :function :assumed-type name) + (clear-info :function :assumed-type name)))) + +;;; to be called when a variable is lexically bound +(declaim (ftype (function (symbol) (values)) note-lexical-binding)) +(defun note-lexical-binding (symbol) + ;; This check is intended to protect us from getting silently + ;; burned when we define + ;; foo.lisp: + ;; (DEFVAR *FOO* -3) + ;; (DEFUN FOO (X) (+ X *FOO*)) + ;; bar.lisp: + ;; (DEFUN BAR (X) + ;; (LET ((*FOO* X)) + ;; (FOO 14))) + ;; and then we happen to compile bar.lisp before foo.lisp. + (when (looks-like-name-of-special-var-p symbol) + ;; FIXME: should be COMPILER-STYLE-WARNING? + (style-warn 'asterisks-around-lexical-variable-name + :format-control + "using the lexical binding of the symbol ~ + ~/sb-ext:print-symbol-with-prefix/, not the~@ + dynamic binding" + :format-arguments (list symbol))) + (values)) ;;; In the target compiler, a lexenv can hold an alist of condition ;;; types (CTYPE . ACTION) such that when signaling condition CTYPE, @@ -101,11 +293,7 @@ (enable-package-locks (set-difference old names :test #'equal))))) -;;; This variable really wants to be a DEFVAR, but the "if (boundp)" expression -;;; is too tricky for genesis. Let's ensure proper behavior by not clobbering -;;; it in the host, but doing the only thing that genesis can do in the target. -(#+sb-xc-host defvar #-sb-xc-host defparameter - *queued-proclaims* nil) ; should this be !*QUEUED-PROCLAIMS* ? +(defvar *queued-proclaims* nil) (defun process-variable-declaration (name kind info-value) (unless (symbolp name) @@ -120,14 +308,8 @@ (multiple-value-bind (allowed test) (ecase kind (special - ;; KLUDGE: There is probably a better place to do this. - (when (boundp '*ir1-namespace*) - (remhash name (free-vars *ir1-namespace*))) (values '(:special :unknown) #'eq)) (global - ;; KLUDGE: Ditto. - (when (boundp '*ir1-namespace*) - (remhash name (free-vars *ir1-namespace*))) (values '(:global :unknown) #'eq)) (always-bound (values '(:constant) #'neq))) (let ((old (info :variable :kind name))) @@ -201,37 +383,18 @@ (setf (info :function :type name) type-oid (info :function :where-from name) where-from))) -(defun seal-class (class) - (declare (type classoid class)) - (setf (classoid-state class) :sealed) - (let ((subclasses (classoid-subclasses class))) - (when subclasses - (dohash ((subclass layout) subclasses :locked t) - (declare (ignore layout)) - (setf (classoid-state subclass) :sealed))))) +(defun seal-class (classoid) + (declare (type classoid classoid)) + (setf (classoid-state classoid) :sealed) + (sb-kernel::do-subclassoids ((subclassoid wrapper) classoid) + (declare (ignore wrapper)) + (setf (classoid-state subclassoid) :sealed))) (defun process-freeze-type-declaration (type-specifier) (let ((class (specifier-type type-specifier))) (when (typep class 'classoid) (seal-class class)))) -(defun process-inline-declaration (name kind) - (declare (type (and inlinep (not null)) kind)) - ;; since implicitly it is a function, also scrubs (FREE-FUNS *IR1-NAMESPACE*) - (proclaim-as-fun-name name) - (warn-if-inline-failed/proclaim name kind) - (setf (info :function :inlinep name) kind)) - -(defun process-block-compile-declaration (entries kind) - (ecase kind - (start-block - (finish-block-compilation) - (let ((compilation *compilation*)) - (setf (block-compile compilation) t) - (setf (entry-points compilation) entries))) - (end-block - (finish-block-compilation)))) - (defun check-deprecation-declaration (state since form) (unless (typep state 'deprecation-state) (error 'simple-type-error @@ -306,6 +469,19 @@ (defun %proclaim (raw-form location) (destructuring-bind (&whole form &optional kind &rest args) (canonized-decl-spec raw-form) + ;; It seems strange to test whether we are currently in + ;; compile-time mode this way, but the reason we don't just call + ;; %COMPILER-PROCLAIM in a :COMPILE-TOPLEVEL-only situation in the + ;; macro-expansion of DECLAIM is that unlike the DEFmumble macros, + ;; DECLAIM and PROCLAIM both exist, and it is unclear whether the + ;; intent of the ANSI specification is that + ;; (EVAL-WHEN (:COMPILE-TOPLEVEL ...) + ;; (LET () + ;; (PROCLAIM ...))) + ;; should have the exact same compile time effects as (DECLAIM ...). + ;; We make the assumption that yes, they should have the same semantics. + (when (boundp '*compilation*) + (%compiler-proclaim kind args)) (labels ((store-location (name &key (key kind)) (if location (setf (getf (info :source-location :declaration name) key) @@ -338,16 +514,14 @@ (type #'proclaim-type) (ftype #'proclaim-ftype)) ctype type :declared))) - (push raw-form *queued-proclaims*))) + #-sb-xc-host + (push raw-form *queued-proclaims*) + #+sb-xc-host + (error "Type system not yet initialized."))) (freeze-type (map-args #'process-freeze-type-declaration)) - ((start-block end-block) - (when (and *compile-time-eval* (boundp '*compilation*)) - (if (eq *block-compile-argument* :specified) - (process-block-compile-declaration args kind) - (compiler-notify "ignoring ~S declaration since ~ - :BLOCK-COMPILE is not :SPECIFIED" - kind)))) + ;; This only has compile-time effects. + ((start-block end-block)) (optimize (multiple-value-bind (new-policy specified-qualities) (process-optimize-decl form *policy*) @@ -372,7 +546,10 @@ (setq *disabled-package-locks* (process-package-lock-decl form *disabled-package-locks*))) ((inline notinline maybe-inline) - (map-args #'process-inline-declaration kind)) + (dolist (name args) + (warn-if-inline-failed/proclaim name kind) + (setf (info :function :inlinep name) + (the (and inlinep (not null)) kind)))) (deprecated (destructuring-bind (state since &rest things) args (multiple-value-bind (state software version) @@ -390,11 +567,19 @@ (unless (info :declaration :known kind) (compiler-warn "unrecognized declaration ~S" raw-form))))))) -(defun sb-xc:proclaim (raw-form) +(defun proclaim (raw-form) (/noshow "PROCLAIM" raw-form) (%proclaim raw-form nil) (values)) +;;; Note that the type NAME has been (re)defined, updating the +;;; undefined warnings and VALUES-SPECIFIER-TYPE cache. +(defun %note-type-defined (name) + (declare (symbol name)) + (note-name-defined name :type) + (values-specifier-type-cache-clear) + (values)) + ;; Issue a style warning if there are any repeated OPTIMIZE declarations ;; given the SPECIFIED-QUALITIES, unless there is no ambiguity. (defun warn-repeated-optimize-qualities (new-policy specified-qualities) diff --git a/src/compiler/pseudo-vops.lisp b/src/compiler/pseudo-vops.lisp index 51c6253f46..fa13642130 100644 --- a/src/compiler/pseudo-vops.lisp +++ b/src/compiler/pseudo-vops.lisp @@ -39,7 +39,26 @@ (:generator 0 (emit-label the-label))) -(define-vop (mark-covered) - (:info path) - (:generator 0 - (sb-assem:inst* 'sb-assem:.coverage-mark path))) +#-x86-64 (define-vop (fixed-alloc-to-stack fixed-alloc)) + +;;; SPLAT is always a no-op for architectures other than x86-64 +;;; because: +;;; - the heap is zero-filled, and only value that can be +;;; splatted is zero which would be redundant. +;;; - stack-allocation vops for precise GC have to zero-fill at the +;;; time of allocation, while inside the pseudo-atomic, +;;; so zero-filling would be redundant. +;;; Those architectures which require the initializing inside the +;;; pseudo-atomic would benefit from a way to advise the allocator +;;; to fill with a non-default value. +#-x86-64 +(define-vop () + (:policy :fast-safe) + (:translate sb-vm::splat) + (:args (vector :scs (sb-vm::descriptor-reg)) + (words :scs (sb-vm::unsigned-reg sb-vm::immediate))) + (:info value) + (:arg-types * sb-vm::positive-fixnum (:constant t)) + (:results (result :scs (sb-vm::descriptor-reg))) + (:ignore words value) + (:generator 1 (move result vector))) diff --git a/src/compiler/represent.lisp b/src/compiler/represent.lisp index 5b6194e220..a6fcca31da 100644 --- a/src/compiler/represent.lisp +++ b/src/compiler/represent.lisp @@ -217,7 +217,6 @@ (defconstant-eqx ignore-cost-vops '(set type-check-error) #'equal) (defconstant-eqx suppress-note-vops '(type-check-error) #'equal) -#-sb-devel (declaim (start-block select-tn-representation)) ;;; We special-case the move VOP, since using this costs for the @@ -295,7 +294,7 @@ t) - (let ((min sb-xc:most-positive-fixnum) + (let ((min most-positive-fixnum) (min-scn nil) (unique nil)) (dolist (scn scs) @@ -324,9 +323,9 @@ (vop-block (tn-ref-vop ref))))) (tails (lambda-tail-set lambda))) (flet ((frob (fun) - (setf (ir2-physenv-number-stack-p - (physenv-info - (lambda-physenv fun))) + (setf (ir2-environment-number-stack-p + (environment-info + (lambda-environment fun))) t))) (frob lambda) (when tails @@ -444,7 +443,7 @@ ;;; ;;; If the TN is an unused result TN, then we don't actually emit the ;;; move; we just change to the right kind of TN. -(defun emit-coerce-vop (op dest-tn scs before) +(defun emit-coerce-vop (op dest-tn scs before &optional load-scs) (declare (type tn-ref op) (type sc-vector scs) (type (or vop null) before) (type (or tn null) dest-tn)) (let* ((op-tn (tn-ref-tn op)) @@ -468,7 +467,7 @@ (cond ((not write-p) (or - (coerce-from-constant op temp) + (coerce-from-constant op temp load-scs) (emit-move (or (maybe-move-from-fixnum+-1 op-tn temp op) res) @@ -500,26 +499,38 @@ ;;; specified VOP. Dest-TN is the destination TN if we are doing a ;;; move or move-arg, and is NIL otherwise. This is only used for ;;; efficiency notes. -(defun coerce-some-operands (ops dest-tn load-scs before) +(defun coerce-some-operands (ops dest-tn load-scs before + &optional more-load-scs) (declare (type (or tn-ref null) ops) (list load-scs) (type (or tn null) dest-tn) (type (or vop null) before)) (do ((op ops (tn-ref-across op)) (scs load-scs (cdr scs))) - ((null scs)) - (let ((tn (tn-ref-tn op))) + ((null op)) + + (let* (more + (scs (cond (scs + (car scs)) + (more-load-scs + (setf more t) + more-load-scs) + (t + (return)))) + (tn (tn-ref-tn op))) (unless (or (eq (tn-kind tn) :unused) - (svref (car scs) + (svref scs (sc-number (tn-sc tn)))) - (emit-coerce-vop op dest-tn (car scs) before)))) + (emit-coerce-vop op dest-tn scs before (and more + more-load-scs))))) (values)) ;;; Emit coerce VOPs for the args and results, as needed. (defun coerce-vop-operands (vop) (declare (type vop vop)) (let ((info (vop-info vop))) - (coerce-some-operands (vop-args vop) nil (vop-info-arg-load-scs info) vop) + (coerce-some-operands (vop-args vop) nil (vop-info-arg-load-scs info) vop + (vop-info-more-arg-load-scs info)) (coerce-some-operands (vop-results vop) nil (vop-info-result-load-scs info) - (vop-next vop))) + (vop-next vop) nil)) (values)) ;;; Iterate over the more operands to a call VOP, emitting move-arg @@ -558,27 +569,27 @@ (change-tn-ref-tn val pass-tn) (let* ((this-fp - (cond ((not (sc-number-stack-p pass-sc)) fp-tn) - (nfp-tn) - (t - (aver (eq how :known-return)) - (setq nfp-tn (make-number-stack-pointer-tn)) - (setf (tn-sc nfp-tn) - (svref *backend-sc-numbers* - (first (primitive-type-scs - (tn-primitive-type nfp-tn))))) - (emit-context-template - node block - (template-or-lose 'compute-old-nfp) - nfp-tn vop) - (aver (not (sc-number-stack-p (tn-sc nfp-tn)))) - nfp-tn))) + (cond ((or (eq how :fixed) + (not (sc-number-stack-p pass-sc))) fp-tn) + (nfp-tn) + (t + (aver (eq how :known-return)) + (setq nfp-tn (make-number-stack-pointer-tn)) + (setf (tn-sc nfp-tn) + (svref *backend-sc-numbers* + (first (primitive-type-scs + (tn-primitive-type nfp-tn))))) + (emit-context-template + node block + (template-or-lose 'compute-old-nfp) + nfp-tn vop) + (aver (not (sc-number-stack-p (tn-sc nfp-tn)))) + nfp-tn))) (new (emit-move-arg-template node block res val-tn this-fp pass-tn vop)) (after (cond ((eq how :local-call) - (aver (eq (vop-info-name (vop-info prev)) - 'allocate-frame)) + (aver (eq (vop-name prev) 'allocate-frame)) prev) (prev (vop-next prev)) (t @@ -594,23 +605,32 @@ (let ((type (tn-ref-type x-tn-ref))) (cond ((not type) nil) + ((csubtypep type (specifier-type 'fixnum)) + (template-or-lose 'sb-vm::move-from-word/fixnum)) ((csubtypep type - (specifier-type `(integer ,sb-xc:most-negative-fixnum - ,(1+ sb-xc:most-positive-fixnum)))) + (specifier-type `(integer ,most-negative-fixnum + ,(1+ most-positive-fixnum)))) (template-or-lose 'sb-vm::move-from-fixnum+1)) ((csubtypep type - (specifier-type `(integer ,(1- sb-xc:most-negative-fixnum) - ,sb-xc:most-positive-fixnum))) + (specifier-type `(integer ,(1- most-negative-fixnum) + ,most-positive-fixnum))) (template-or-lose 'sb-vm::move-from-fixnum-1)))))) -(defun coerce-from-constant (x-tn-ref y) +(defun coerce-from-constant (x-tn-ref y &optional load-scs) (when (and (sc-is y sb-vm::descriptor-reg sb-vm::control-stack) (tn-ref-type x-tn-ref)) (multiple-value-bind (constantp value) (type-singleton-p (tn-ref-type x-tn-ref)) (when constantp - (change-tn-ref-tn x-tn-ref - (make-constant-tn (find-constant value) t)) - t)))) + (let* ((constant (find-constant value)) + (sc (constant-sc constant))) + (when (or (not load-scs) + ;; This is a more-arg-load-scs + ;; Because more args do not have a generic load + ;; sequence it can't handle aribtrary constants or + ;; immediates. + (svref load-scs (sc-number sc))) + (change-tn-ref-tn x-tn-ref (make-constant-tn constant t)) + t)))))) (defun split-ir2-block (vop) (cond ((vop-next vop) @@ -619,9 +639,11 @@ (succ (ir2-block-block 2block)) (start (make-ctran)) (block (ctran-starts-block start)) - (no-op-node (make-no-op)) + (no-op-node (make-exit)) (new-2block (make-ir2-block block)) (vop-next (vop-next vop))) + (setf (block-number block) + (incf (component-max-block-number (block-component block)))) (link-node-to-previous-ctran no-op-node start) (setf (block-info block) new-2block) (add-to-emit-order new-2block (ir2-block-prev 2block)) @@ -673,7 +695,9 @@ (eq (car (vop-codegen-info last)) (ir2-block-%label dest-block)) (setf branch last))))) (let ((dest (tn-ref-tn (vop-results dest-vop)))) - (when (and (eq (tn-sc x) (tn-sc dest)) + (when (and (or (eq (tn-sc x) (tn-sc dest)) + (and (eq (sc-number (tn-sc x)) sb-vm:constant-sc-number) + (eq (sc-number (tn-sc dest)) sb-vm:descriptor-reg-sc-number))) (eq (find-move-vop x nil (tn-sc dest) (tn-primitive-type dest) #'sc-move-vops) (vop-info vop))) (let ((new-block (split-ir2-block dest-vop)) @@ -733,12 +757,14 @@ ((vop-info-move-args info) (emit-arg-moves vop)) (t - (coerce-vop-operands vop)))))) + (coerce-vop-operands vop))) + (when (vop-info-after-sc-selection info) + (funcall (vop-info-after-sc-selection info) vop))))) ;;; If TN is in a number stack SC, make all the right annotations. ;;; Note that this should be called after TN has been referenced, ;;; since it must iterate over the referencing environments. -#-sb-fluid (declaim (inline note-if-number-stack)) +(declaim (inline note-if-number-stack)) (defun note-if-number-stack (tn 2comp restricted) (declare (type tn tn) (type ir2-component 2comp)) (when (if restricted @@ -753,12 +779,11 @@ ;;; Arrange boxed constants so that all :NAMED-CALL constants are first, ;;; then constant leaves, and finally LOAD-TIME-VALUE constants. ;;; There exist a few reasons for placing all the FDEFNs first: -;;; * FDEFNs which are referenced for lisp call - as opposed to referenced -;;; in #'FUN syntax - could be stored as untagged pointers which would -;;; benefit the PPC64 architecture by removing a few instructions from each -;;; use of such fdefn by not having to subtract its lowtag prior to loading -;;; from both the fun and raw-fun slots. GC would need to be aware of the -;;; untagged pointer convention. +;;; * FDEFNs which are referenced for call (versus for value as in #'FUN) +;;; may be stored in the code header as untagged pointers. This benefits PPC64 +;;; because lowtag subtraction can't be had "for free" due to the architectural +;;; requirement that lispword-aligned loads need a displacement that is +;;; a multiple of 4, which OTHER-POINTER-LOWTAG does not satisfy. ;;; * In the current approach for so-called "static" linking of immobile code, ;;; we change code instruction bytes so that they call into a simple-fun ;;; directly rather than through an fdefn, but the approach is subject to a @@ -785,11 +810,11 @@ (dovector (constant unsorted) (incf old-offset) (when (eql pass (cond ((constant-p constant) 2) - ((eq (car constant) :named-call) 1) + ((eq (car constant) :fdefinition) 1) (t 3))) (let ((new-offset (vector-push-extend constant sorted))) (push (cons old-offset new-offset) renumbering)))))) - (scan 1) ; first all the called fdefinitions + (scan 1) ; first all the fdefinitions use for call or global function ref (as in #'FUN) (scan 2) ; then IR1 constants (scan 3)) ; then various flavors of load-time magic ;; Update the TN-OFFSET slot. @@ -803,6 +828,53 @@ (cdr (the (not null) (assoc old-offset renumbering))))))) sorted)) +#+arm64 +(defun choose-zero-tn (tn) + (let (zero-tn) + (flet ((zero-tn () + (or zero-tn + (setf zero-tn + (component-live-tn + (make-wired-tn nil + sb-vm:any-reg-sc-number + sb-vm::zr-offset)))))) + (do ((tn tn (tn-next tn))) + ((null tn)) + (when (and (constant-tn-p tn) + (eql (tn-value tn) 0)) + (loop with next + for read = (tn-reads tn) then next + while read + do + (setf next (tn-ref-next read)) + (do* ((vop (tn-ref-vop read)) + (info (vop-info vop)) + (cost (vop-info-arg-costs info) (cdr cost)) + (op (vop-args vop) (tn-ref-across op))) + ((null cost)) + (when (eq op read) + (when (eql (svref (car cost) sb-vm:zero-sc-number) 0) + (change-tn-ref-tn read (zero-tn))) + (return))))))))) + +;;; The call VOPs allocate a temporary register wired to +;;; nfp-save-offset, but don't use it if there's no nfp-tn in the +;;; current frame, but the stack space is still allocated. +#-c-stack-is-control-stack +(defun unwire-nfp-save-tn (2comp) + (unless (ir2-component-nfp 2comp) + (do ((prev) + (tn (ir2-component-wired-tns 2comp) (tn-next tn))) + ((null tn)) + (cond ((and (sc-is tn sb-vm::control-stack) + (eql (tn-offset tn) sb-vm:nfp-save-offset)) + (setf (tn-kind tn) :unused) + (if prev + (setf (tn-next prev) (tn-next tn)) + (setf (ir2-component-wired-tns 2comp) (tn-next tn)))) + (t + (setf prev tn)))))) + ;;; This is the entry to representation selection. First we select the ;;; representation for all normal TNs, setting the TN-SC. After ;;; selecting the TN representations, we set the SC for all :ALIAS TNs @@ -862,6 +934,10 @@ (do-ir2-blocks (block component) (emit-moves-and-coercions block)) + + #+arm64 + (choose-zero-tn (ir2-component-constant-tns 2comp)) + ;; Give the optimizers a second opportunity to alter newly inserted vops ;; by looking for patterns that have a shorter expression as a single vop. (run-vop-optimizers component) @@ -872,5 +948,7 @@ (note-if-number-stack tn 2comp ,restricted)))) (frob ir2-component-normal-tns nil) (frob ir2-component-wired-tns t) - (frob ir2-component-restricted-tns t))) + (frob ir2-component-restricted-tns t) + #-c-stack-is-control-stack + (unwire-nfp-save-tn 2comp))) (values)) diff --git a/src/compiler/riscv/alloc.lisp b/src/compiler/riscv/alloc.lisp index 4afbe23759..8ab305c0d8 100644 --- a/src/compiler/riscv/alloc.lisp +++ b/src/compiler/riscv/alloc.lisp @@ -12,58 +12,47 @@ (in-package "SB-VM") -(define-vop (list-or-list*) - (:args (things :more t)) +(define-vop (list) + (:args (things :more t :scs (any-reg descriptor-reg zero control-stack))) (:temporary (:scs (descriptor-reg)) ptr) (:temporary (:scs (descriptor-reg) :to (:result 0) :target result) res) (:temporary (:scs (any-reg)) temp) (:temporary (:sc non-descriptor-reg) pa-flag) - (:info num) + (:info star cons-cells) (:results (result :scs (descriptor-reg))) - (:policy :fast-safe) - (:variant-vars star) (:node-var node) (:generator 0 - (cond ((zerop num) - (move result null-tn)) - ((and star (= num 1)) - (move result (tn-ref-tn things))) - (t (flet ((maybe-load (tn) - (sc-case tn - ((any-reg descriptor-reg) - tn) - (control-stack - (load-stack-tn temp tn) - temp)))) - (let* ((cons-cells (if star (1- num) num)) - (alloc (* (pad-data-block cons-size) cons-cells))) - (pseudo-atomic (pa-flag) - (allocation 'list alloc list-pointer-lowtag res - :flag-tn pa-flag - :stack-allocate-p (node-stack-allocate-p node) - :temp-tn temp) - (move ptr res) - (dotimes (i (1- cons-cells)) - (storew (maybe-load (tn-ref-tn things)) ptr - cons-car-slot list-pointer-lowtag) - (setf things (tn-ref-across things)) - (inst addi ptr ptr (pad-data-block cons-size)) - (storew ptr ptr (- cons-cdr-slot cons-size) - list-pointer-lowtag)) - (storew (maybe-load (tn-ref-tn things)) ptr - cons-car-slot list-pointer-lowtag) - (storew (if star - (maybe-load (tn-ref-tn (tn-ref-across things))) - null-tn) - ptr cons-cdr-slot list-pointer-lowtag)) - (move result res))))))) - -(define-vop (list list-or-list*) - (:variant nil)) -(define-vop (list* list-or-list*) - (:variant t)) - + (flet ((maybe-load (tn) + (sc-case tn + ((any-reg descriptor-reg zero) tn) + (control-stack + (load-stack-tn temp tn) + temp)))) + (let ((alloc (* (pad-data-block cons-size) cons-cells))) + (pseudo-atomic (pa-flag) + (allocation 'list alloc list-pointer-lowtag res + :flag-tn pa-flag + :stack-allocate-p (node-stack-allocate-p node) + :temp-tn temp) + (let ((ptr (if (= cons-cells 1) + res + ptr))) + (move ptr res) + (dotimes (i (1- cons-cells)) + (storew (maybe-load (tn-ref-tn things)) ptr + cons-car-slot list-pointer-lowtag) + (setf things (tn-ref-across things)) + (inst addi ptr ptr (pad-data-block cons-size)) + (storew ptr ptr (- cons-cdr-slot cons-size) + list-pointer-lowtag)) + (storew (maybe-load (tn-ref-tn things)) ptr + cons-car-slot list-pointer-lowtag) + (storew (if star + (maybe-load (tn-ref-tn (tn-ref-across things))) + null-tn) + ptr cons-cdr-slot list-pointer-lowtag))) + (move result res))))) ;;;; Special purpose inline allocators. @@ -158,7 +147,7 @@ ;;; The compiler likes to be able to directly make value cells. (define-vop (make-value-cell) - (:args (value :to :save :scs (descriptor-reg any-reg))) + (:args (value :to :save :scs (descriptor-reg any-reg zero))) (:temporary (:sc non-descriptor-reg) pa-flag) (:results (result :scs (descriptor-reg))) (:info stack-allocate-p) @@ -197,7 +186,7 @@ (:info name words type lowtag stack-allocate-p) (:ignore name stack-allocate-p) (:temporary (:scs (any-reg)) bytes) - (:temporary (:sc non-descriptor-reg) pa-flag) + (:temporary (:sc non-descriptor-reg :from (:argument 0) :to (:eval 0)) pa-flag) (:temporary (:sc non-descriptor-reg) header) (:results (result :scs (descriptor-reg))) (:generator 6 diff --git a/src/compiler/riscv/arith.lisp b/src/compiler/riscv/arith.lisp index 6869ed6996..264f8b7a36 100644 --- a/src/compiler/riscv/arith.lisp +++ b/src/compiler/riscv/arith.lisp @@ -53,31 +53,31 @@ ;;; Assume that any constant operand is the second arg... (define-vop (fast-fixnum-binop fast-safe-arith-op) - (:args (x :target r :scs (any-reg)) - (y :target r :scs (any-reg))) + (:args (x :target r :scs (any-reg zero)) + (y :target r :scs (any-reg zero))) (:arg-types tagged-num tagged-num) (:results (r :scs (any-reg))) (:result-types tagged-num) (:note "inline fixnum arithmetic")) (define-vop (fast-unsigned-binop fast-safe-arith-op) - (:args (x :target r :scs (unsigned-reg)) - (y :target r :scs (unsigned-reg))) + (:args (x :target r :scs (unsigned-reg zero)) + (y :target r :scs (unsigned-reg zero))) (:arg-types unsigned-num unsigned-num) (:results (r :scs (unsigned-reg))) (:result-types unsigned-num) (:note #.(format nil "inline (unsigned-byte ~a) arithmetic" n-machine-word-bits))) (define-vop (fast-signed-binop fast-safe-arith-op) - (:args (x :target r :scs (signed-reg)) - (y :target r :scs (signed-reg))) + (:args (x :target r :scs (signed-reg zero)) + (y :target r :scs (signed-reg zero))) (:arg-types signed-num signed-num) (:results (r :scs (signed-reg))) (:result-types signed-num) (:note #.(format nil "inline (signed-byte ~a) arithmetic" n-machine-word-bits))) (define-vop (fast-fixnum-binop-c fast-safe-arith-op) - (:args (x :target r :scs (any-reg))) + (:args (x :target r :scs (any-reg zero))) (:info y) (:arg-types tagged-num (:constant short-immediate-fixnum)) (:results (r :scs (any-reg))) @@ -85,7 +85,7 @@ (:note "inline arithmetic")) (define-vop (fast-unsigned-binop-c fast-safe-arith-op) - (:args (x :target r :scs (unsigned-reg))) + (:args (x :target r :scs (unsigned-reg zero))) (:info y) (:arg-types unsigned-num (:constant short-immediate)) (:results (r :scs (unsigned-reg))) @@ -93,7 +93,7 @@ (:note "inline unsigned unboxed arithmetic")) (define-vop (fast-signed-binop-c fast-safe-arith-op) - (:args (x :target r :scs (signed-reg))) + (:args (x :target r :scs (signed-reg zero))) (:info y) (:arg-types signed-num (:constant short-immediate)) (:results (r :scs (signed-reg))) @@ -375,9 +375,8 @@ ;; optimize this. (loop for masker in maskers for shift = 1 then (ash shift 1) do - (inst li mask masker) ; NL1 + (inst li mask masker) (let ((input (if (= shift 1) arg num))) - ; TEMP = NL2 ARG = NL3 NUM = NL0 (inst srli temp input shift) (inst and num input mask)) (inst and temp temp mask) @@ -464,24 +463,24 @@ (:policy :fast-safe)) (define-vop (fast-conditional/fixnum fast-conditional) - (:args (x :scs (any-reg)) - (y :scs (any-reg))) + (:args (x :scs (any-reg zero)) + (y :scs (any-reg zero))) (:arg-types tagged-num tagged-num) (:note "inline fixnum comparison") (:generator 1 (three-way-comparison x y condition :signed not-p target))) (define-vop (fast-conditional/signed fast-conditional) - (:args (x :scs (signed-reg)) - (y :scs (signed-reg))) + (:args (x :scs (signed-reg zero)) + (y :scs (signed-reg zero))) (:arg-types signed-num signed-num) (:note #.(format nil "inline (signed-byte ~a) comparison" n-word-bits)) (:generator 1 (three-way-comparison x y condition :signed not-p target))) (define-vop (fast-conditional/unsigned fast-conditional) - (:args (x :scs (unsigned-reg)) - (y :scs (unsigned-reg))) + (:args (x :scs (unsigned-reg zero)) + (y :scs (unsigned-reg zero))) (:arg-types unsigned-num unsigned-num) (:note #.(format nil "inline (unsigned-byte ~a) comparison" n-word-bits)) (:generator 1 @@ -514,8 +513,8 @@ ;;; doing this is to prevent fixnum specific operations from being ;;; used on word integers, spuriously consing the argument. (define-vop (fast-eql/fixnum fast-conditional) - (:args (x :scs (any-reg)) - (y :scs (any-reg))) + (:args (x :scs (any-reg zero)) + (y :scs (any-reg zero))) (:arg-types tagged-num tagged-num) (:note "inline fixnum comparison") (:translate eql) @@ -532,26 +531,19 @@ ;;;; Logical operations -(define-vop (shift-towards-someplace) - (:policy :fast-safe) - (:args (num :scs (unsigned-reg)) - (amount :scs (signed-reg))) - (:arg-types unsigned-num tagged-num) - (:results (r :scs (unsigned-reg))) - (:result-types unsigned-num)) - -(define-vop (shift-towards-start shift-towards-someplace) - (:translate shift-towards-start) - (:note "SHIFT-TOWARDS-START") - (:generator 1 - (inst srl r num amount))) - -(define-vop (shift-towards-end shift-towards-someplace) - (:translate shift-towards-end) - (:note "SHIFT-TOWARDS-END") - (:generator 1 - (inst sll r num amount))) - +(macrolet ((define (translate operation) + `(define-vop () + (:translate ,translate) + (:note ,(string translate)) + (:policy :fast-safe) + (:args (num :scs (unsigned-reg)) + (amount :scs (signed-reg))) + (:arg-types unsigned-num tagged-num) + (:results (r :scs (unsigned-reg))) + (:result-types unsigned-num) + (:generator 1 (inst ,operation r num amount))))) + (define shift-towards-start srl) + (define shift-towards-end sll)) ;;;; Modular arithmetic (defmacro define-mod-binop ((name prototype) function) @@ -609,7 +601,7 @@ (deftransform ash-left-mod32 ((integer count) ((unsigned-byte 32) (unsigned-byte 5))) - (when (sb-c::constant-lvar-p count) + (when (sb-c:constant-lvar-p count) (sb-c::give-up-ir1-transform)) '(%primitive fast-ash-left-mod32/unsigned=>unsigned integer count))) @@ -624,7 +616,7 @@ (deftransform ash-left-mod64 ((integer count) ((unsigned-byte 64) (unsigned-byte 6))) - (when (sb-c::constant-lvar-p count) + (when (sb-c:constant-lvar-p count) (sb-c::give-up-ir1-transform)) '(%primitive fast-ash-left-mod64/unsigned=>unsigned integer count))) diff --git a/src/compiler/riscv/array.lisp b/src/compiler/riscv/array.lisp index acfb3ebec0..9e7c8d2555 100644 --- a/src/compiler/riscv/array.lisp +++ b/src/compiler/riscv/array.lisp @@ -31,34 +31,15 @@ (allocation nil ndescr other-pointer-lowtag header :flag-tn pa-flag) ;; Now that we have the space allocated, compute the header ;; value. - (inst slli ndescr rank (- n-widetag-bits n-fixnum-tag-bits)) - (inst addi ndescr ndescr (ash (1- array-dimensions-offset) n-widetag-bits)) - (inst srli pa-flag type n-fixnum-tag-bits) - (inst or ndescr ndescr pa-flag) + ;; Compute the encoded rank. See ENCODE-ARRAY-RANK. + (inst subi ndescr rank (fixnumize 1)) + (inst andi ndescr ndescr (fixnumize array-rank-mask)) + (inst slli ndescr ndescr array-rank-position) + (inst or ndescr ndescr type) + (inst srli ndescr ndescr n-fixnum-tag-bits) ;; And store the header value. (storew ndescr header 0 other-pointer-lowtag)) (move result header))) - -(define-vop (make-array-header/c) - (:translate make-array-header) - (:policy :fast-safe) - (:arg-types (:constant t) (:constant t)) - (:info type rank) - (:temporary (:scs (descriptor-reg) :to (:result 0) :target result) header) - (:temporary (:sc non-descriptor-reg) pa-flag) - (:results (result :scs (descriptor-reg))) - (:generator 4 - (let* ((header-size (+ rank (1- array-dimensions-offset))) - (bytes (logandc2 (+ (* (1+ header-size) n-word-bytes) - lowtag-mask) - lowtag-mask)) - (header-bits (logior (ash header-size n-widetag-bits) type))) - (pseudo-atomic (pa-flag) - (allocation nil bytes other-pointer-lowtag header :flag-tn pa-flag) - (inst li pa-flag header-bits) - (storew pa-flag header 0 other-pointer-lowtag))) - (move result header))) - ;;;; Additional accessors and setters for the array header. (define-full-reffer %array-dimension * @@ -69,18 +50,17 @@ array-dimensions-offset other-pointer-lowtag (any-reg) positive-fixnum sb-kernel:%set-array-dimension) -(define-vop (array-rank-vop) - (:translate sb-kernel:%array-rank) +(define-vop () + (:translate %array-rank) (:policy :fast-safe) (:args (x :scs (descriptor-reg))) - (:temporary (:scs (non-descriptor-reg)) temp) - (:results (res :scs (any-reg descriptor-reg))) + (:results (res :scs (unsigned-reg))) + (:result-types positive-fixnum) (:generator 6 - (loadw temp x 0 other-pointer-lowtag) - (inst srai temp temp n-widetag-bits) - (inst subi temp temp (1- array-dimensions-offset)) - (inst slli res temp n-fixnum-tag-bits))) - + (inst lbu res x (- (/ array-rank-position n-byte-bits) other-pointer-lowtag)) + (inst addi res res 1) + (inst andi res res array-rank-mask))) + ;;;; Bounds checking routine. (define-vop (check-bound) (:translate %check-bound) @@ -130,7 +110,9 @@ (setname (symbolicate "DATA-VECTOR-SET/" type))) `(progn (define-full-reffer ,refname ,type - vector-data-offset other-pointer-lowtag ,scs ,element-type data-vector-ref) + vector-data-offset other-pointer-lowtag + ,(remove-if (lambda (x) (member x '(zero))) scs) + ,element-type data-vector-ref) (define-full-setter ,setname ,type vector-data-offset other-pointer-lowtag ,scs ,element-type data-vector-set)))) (def-partial-data-vector-frobs (type element-type size signed &rest scs) @@ -159,7 +141,7 @@ ,setname ,type ,size ,format vector-data-offset other-pointer-lowtag ,scs ,element-type t "inline array store" data-vector-set))))) - (def-full-data-vector-frobs simple-vector * descriptor-reg any-reg) + (def-full-data-vector-frobs simple-vector * descriptor-reg any-reg zero) (def-partial-data-vector-frobs simple-base-string character 1 nil character-reg) #+(and sb-unicode (not 64-bit)) @@ -260,10 +242,8 @@ (:policy :fast-safe) (:args (object :scs (descriptor-reg)) (index :scs (unsigned-reg) :target shift) - (value :scs (unsigned-reg immediate) :target result)) + (value :scs (unsigned-reg zero immediate))) (:arg-types ,type positive-fixnum positive-fixnum) - (:results (result :scs (unsigned-reg))) - (:result-types positive-fixnum) (:temporary (:scs (interior-reg)) lip) (:temporary (:scs (non-descriptor-reg)) temp old) (:temporary (:scs (non-descriptor-reg) :from (:argument 1)) shift) @@ -285,26 +265,22 @@ (inst sll temp temp shift) (inst xori temp temp -1) (inst and old old temp)) - ;; LOGIOR in the new value (shifted appropriatly). - (sc-case value - (immediate - (inst li temp (logand (tn-value value) ,(1- (ash 1 bits))))) - (unsigned-reg - (inst andi temp value ,(1- (ash 1 bits))))) - (inst sll temp temp shift) - (inst or old old temp) + ;; LOGIOR in the new value (shifted appropriately). + (unless (sc-is value zero) + (sc-case value + (immediate + (inst li temp (logand (tn-value value) ,(1- (ash 1 bits))))) + (unsigned-reg + (inst andi temp value ,(1- (ash 1 bits))))) + (inst sll temp temp shift) + (inst or old old temp)) ;; Write the altered word back to the array. - (storew old lip vector-data-offset other-pointer-lowtag) - (sc-case value - (immediate - (inst li result (tn-value value))) - (unsigned-reg - (move result value))))) + (storew old lip vector-data-offset other-pointer-lowtag))) (define-vop (,(symbolicate "DATA-VECTOR-SET-C/" type)) (:translate data-vector-set) (:policy :fast-safe) (:args (object :scs (descriptor-reg)) - (value :scs (unsigned-reg immediate) :target result)) + (value :scs (unsigned-reg zero immediate))) (:arg-types ,type (:constant (integer 0 @@ -315,8 +291,6 @@ elements-per-word)))) positive-fixnum) (:info index) - (:results (result :scs (unsigned-reg))) - (:result-types positive-fixnum) (:temporary (:scs (non-descriptor-reg)) temp old) (:generator 20 (multiple-value-bind (word extra) (floor index ,elements-per-word) @@ -331,6 +305,7 @@ (lognot (ash ,(1- (ash 1 bits)) (* extra ,bits)))) (inst and old old temp)))) (sc-case value + (zero) (immediate (let ((value (ash (logand (tn-value value) ,(1- (ash 1 bits))) (* extra ,bits)))) @@ -343,12 +318,7 @@ (unsigned-reg (inst slli temp value (* extra ,bits)) (inst or old old temp))) - (storew old object (+ word vector-data-offset) other-pointer-lowtag) - (sc-case value - (immediate - (inst li result (tn-value value))) - (unsigned-reg - (move result value)))))))))) + (storew old object (+ word vector-data-offset) other-pointer-lowtag)))))))) (def-small-data-vector-frobs simple-bit-vector 1) (def-small-data-vector-frobs simple-array-unsigned-byte-2 2) (def-small-data-vector-frobs simple-array-unsigned-byte-4 4)) diff --git a/src/compiler/riscv/c-call.lisp b/src/compiler/riscv/c-call.lisp index e22f83e607..0e23dc3d10 100644 --- a/src/compiler/riscv/c-call.lisp +++ b/src/compiler/riscv/c-call.lisp @@ -13,25 +13,23 @@ (defconstant-eqx c-saved-registers - (list* lip-offset - 8 9 (loop for i from 18 to 27 collect i)) + `(1 8 9 ,@(loop for i from 18 to 27 collect i)) #'equal) (defconstant-eqx c-unsaved-registers - (append (list lip-offset) - (loop for i from 5 to 7 collect i) - (loop for i from 10 to 17 collect i) - (loop for i from 28 to 31 collect i)) + `(1 ,@(loop for i from 5 to 7 collect i) + ,@(loop for i from 10 to 17 collect i) + ,@(loop for i from 28 to 31 collect i)) #'equal) (defconstant-eqx c-saved-float-registers - (list* 8 9 (loop for i from 18 to 27 collect i)) + `(8 9 ,@(loop for i from 18 to 27 collect i)) #'equal) (defconstant-eqx c-unsaved-float-registers - (append (loop for i from 0 to 7 collect i) - (loop for i from 10 to 17 collect i) - (loop for i from 28 to 31 collect i)) + `(,@(loop for i from 0 to 7 collect i) + ,@(loop for i from 10 to 17 collect i) + ,@(loop for i from 28 to 31 collect i)) #'equal) (defun make-reg-tn (offset &optional (sc 'any-reg)) @@ -171,13 +169,12 @@ (:info foreign-symbol) (:results (res :scs (sap-reg))) (:result-types system-area-pointer) - (:temporary (:scs (non-descriptor-reg)) addr) (:generator 2 ;; This probably has to be 3 instructions unless we can put some linkage entries ;; near enough to NULL-TN. Would only make a difference when compiling to memory ;; since compiling to file has to assume worst case. - (inst li addr (make-fixup foreign-symbol :foreign-dataref)) - (loadw res addr))) + (inst li res (make-fixup foreign-symbol :foreign-dataref)) + (loadw res res))) (define-vop (call-out) (:args (function :scs (sap-reg) :target cfunc) @@ -194,7 +191,7 @@ (when cur-nfp (store-stack-tn nfp-save cur-nfp)) (move cfunc function) - (invoke-asm-routine 'call-into-c) + (inst jal ra-tn (make-fixup 'call-into-c :assembly-routine)) (when cur-nfp (load-stack-tn cur-nfp nfp-save))))) diff --git a/src/compiler/riscv/call.lisp b/src/compiler/riscv/call.lisp index 0d407c6aee..50173369f2 100644 --- a/src/compiler/riscv/call.lisp +++ b/src/compiler/riscv/call.lisp @@ -17,10 +17,8 @@ ;;; Make a passing location TN for a local call return PC. (defun make-return-pc-passing-location (standard) - ;; Should we have a non standard convention? RISCV gives a hardware bonus to using x1 and x5 - (if standard - (make-wired-tn *backend-t-primitive-type* descriptor-reg-sc-number lra-offset) - (make-restricted-tn *backend-t-primitive-type* descriptor-reg-sc-number))) + (declare (ignore standard)) + (make-wired-tn *fixnum-primitive-type* immediate-arg-scn ra-offset)) ;;; This is similar to MAKE-RETURN-PC-PASSING-LOCATION, but makes a ;;; location to pass OLD-FP in. This is (obviously) wired in the @@ -38,13 +36,14 @@ ;;; them at a known location. (defun make-old-fp-save-location (env) (specify-save-tn - (physenv-debug-live-tn (make-normal-tn *fixnum-primitive-type*) env) + (environment-debug-live-tn (make-normal-tn *fixnum-primitive-type*) env) (make-wired-tn *fixnum-primitive-type* control-stack-arg-scn ocfp-save-offset))) (defun make-return-pc-save-location (env) - (specify-save-tn - (physenv-debug-live-tn (make-normal-tn *backend-t-primitive-type*) env) - (make-wired-tn *backend-t-primitive-type* control-stack-arg-scn lra-save-offset))) + (let ((ptype *fixnum-primitive-type*)) + (specify-save-tn + (environment-debug-live-tn (make-normal-tn ptype) env) + (make-wired-tn ptype control-stack-arg-scn ra-save-offset)))) ;;; Make a TN for the standard argument count passing location. We ;;; only need to make the standard location, since a count is never @@ -99,6 +98,7 @@ (define-vop (xep-allocate-frame) (:info start-lab) (:temporary (:scs (interior-reg)) lip) + (:temporary (:scs (descriptor-reg) :offset l0-offset) fn) (:generator 1 ;; Make sure the function is aligned, and drop a label pointing to this ;; function header. @@ -107,7 +107,7 @@ ;; Allocate function header. (inst simple-fun-header-word) (inst .skip (* (1- simple-fun-insts-offset) n-word-bytes)) - (inst compute-code code-tn lip start-lab))) + (inst compute-code-from-fn code-tn fn lip start-lab))) (define-vop (xep-setup-sp) (:vop-var vop) @@ -125,7 +125,7 @@ (:generator 2 (move res csp-tn) (inst addi csp-tn csp-tn (* n-word-bytes (sb-allocated-size 'control-stack))) - (when (ir2-physenv-number-stack-p callee) + (when (ir2-environment-number-stack-p callee) (inst addi nsp-tn nsp-tn (- (bytes-needed-for-non-descriptor-stack-frame))) (move nfp nsp-tn)))) @@ -175,7 +175,7 @@ (note-this-location vop (if (<= nvals 1) :single-value-return :unknown-return)) - (inst compute-code code-tn lip lra-label) + (inst compute-code-from-ra code-tn ra-tn lip lra-label) ;; Pick off the single-value case first. (sb-assem:without-scheduling () @@ -267,10 +267,10 @@ ;;; Args and Nargs are TNs wired to the named locations. We must ;;; explicitly allocate these TNs, since their lifetimes overlap with the ;;; results Start and Count (also, it's nice to be able to target them). -(defun receive-unknown-values (args nargs start count lra-label lip) +(defun receive-unknown-values (args nargs start count label lip) (declare (type tn args nargs start count)) (assemble () - (inst compute-code code-tn lip lra-label) + (inst compute-code-from-ra code-tn ra-tn lip label) (inst bge nargs-tn zero-tn MULTIPLE) (move start csp-tn) (inst addi csp-tn csp-tn n-word-bytes) @@ -350,10 +350,9 @@ (when callee-nfp (maybe-load-stack-tn callee-nfp nfp))) (maybe-load-stack-tn cfp-tn fp) - (inst compute-lra (callee-return-pc-tn callee) lip label code-tn) (note-this-location vop :call-site) - (inst j target) - (emit-return-pc label) + (inst jal ra-tn target) + (emit-label label) (default-unknown-values vop values nvals move-temp lip label) (when cur-nfp (load-stack-tn cur-nfp nfp-save))))) @@ -386,10 +385,9 @@ (when callee-nfp (maybe-load-stack-tn callee-nfp nfp))) (maybe-load-stack-tn cfp-tn fp) - (inst compute-lra (callee-return-pc-tn callee) lip label code-tn) (note-this-location vop :call-site) - (inst j target) - (emit-return-pc label) + (inst jal ra-tn target) + (emit-label label) (note-this-location vop :unknown-return) (receive-unknown-values values-start nvals start count label lip) (when cur-nfp @@ -415,20 +413,16 @@ (:move-args :local-call) (:vop-var vop) (:temporary (:sc control-stack :offset nfp-save-offset) nfp-save) - (:temporary (:scs (interior-reg)) lip) (:generator 5 - (let ((label (gen-label)) - (cur-nfp (current-nfp-tn vop))) + (let ((cur-nfp (current-nfp-tn vop))) (when cur-nfp (store-stack-tn nfp-save cur-nfp)) (let ((callee-nfp (callee-nfp-tn callee))) (when callee-nfp (maybe-load-stack-tn callee-nfp nfp))) (maybe-load-stack-tn cfp-tn fp) - (inst compute-lra (callee-return-pc-tn callee) lip label code-tn) (note-this-location vop :call-site) - (inst j target) - (emit-return-pc label) + (inst jal ra-tn target) (note-this-location vop :known-return) (when cur-nfp (load-stack-tn cur-nfp nfp-save))))) @@ -441,11 +435,11 @@ ;;; since all registers may be tied up by the more operand. Instead, ;;; we use MAYBE-LOAD-STACK-TN. (define-vop (known-return) - (:args (old-fp :scs (any-reg)) - (return-pc :scs (descriptor-reg)) + (:args (old-fp :target old-fp-temp) + (return-pc :target return-pc-temp) (values :more t)) (:temporary (:sc any-reg :from (:argument 0)) old-fp-temp) - (:temporary (:sc descriptor-reg :from (:argument 1)) return-pc-temp) + (:temporary (:sc any-reg :from (:argument 1) :offset ra-offset) return-pc-temp) (:info val-locs) (:ignore val-locs values) (:move-args :known-return) @@ -456,7 +450,7 @@ (move csp-tn cfp-tn) (clear-number-stack vop) (move cfp-tn old-fp-temp) - (lisp-return return-pc-temp :known))) + (inst jalr zero-tn return-pc-temp 0))) ;;;; Full call: @@ -529,7 +523,8 @@ ,@(when (eq named :direct) '(fun)) ,@(when (eq return :fixed) '(nvals)) step-instrumenting) - (:ignore ,@(unless (or variable (eq return :tail)) '(arg-locs)) + (:ignore ,@(unless (eq return :tail) '(return-pc-pass)) + ,@(unless (or variable (eq return :tail)) '(arg-locs)) ,@(unless variable '(args))) (:temporary (:sc descriptor-reg @@ -539,8 +534,8 @@ '(:to :eval))) old-fp-pass) - (:temporary (:sc descriptor-reg - :offset lra-offset + (:temporary (:sc any-reg + :offset ra-offset :from (:argument ,(if (eq return :tail) 2 1)) :to :eval) return-pc-pass) @@ -550,7 +545,8 @@ :from (:argument ,(if (eq return :tail) 0 1)) :to :eval) ,(if named 'name-pass 'lexenv)))) - (:temporary (:scs (descriptor-reg) :to :eval) + (:temporary (:scs (descriptor-reg) :offset l0-offset + :to :eval) function) (:temporary (:sc any-reg :offset nargs-offset :to ,(if (eq return :fixed) @@ -581,7 +577,7 @@ (if (eq return :unknown) 25 0)) (let* ((cur-nfp (current-nfp-tn vop)) ,@(unless (eq return :tail) - '((lra-label (gen-label)))) + '((label (gen-label)))) (step-done-label (gen-label)) (filler (remove nil @@ -594,8 +590,7 @@ :load-return-pc) (when cur-nfp :frob-nfp)) - '(:comp-lra - (when cur-nfp + '((when cur-nfp :frob-nfp) :save-fp :load-fp)))))) @@ -621,16 +616,14 @@ (load-stack-tn old-fp-pass old-fp)))) (:load-return-pc (sc-case return-pc - (descriptor-reg + (any-reg (move return-pc-pass return-pc)) (control-stack (load-stack-tn return-pc-pass return-pc)))) (:frob-nfp (inst addi nsp-tn cur-nfp (bytes-needed-for-non-descriptor-stack-frame)))) - `((:comp-lra - (inst compute-lra return-pc-pass lip lra-label code-tn)) - (:frob-nfp + `((:frob-nfp (store-stack-tn nfp-save cur-nfp)) (:save-fp (move old-fp-pass cfp-tn)) @@ -699,19 +692,24 @@ (return))) (note-this-location vop :call-site) - (lisp-jump function)) + (inst jalr ,(if (eq return :tail) + 'zero-tn + 'ra-tn) + function + (- (ash simple-fun-insts-offset word-shift) + fun-pointer-lowtag))) ,@(ecase return (:fixed - '((emit-return-pc lra-label) - (default-unknown-values vop values nvals move-temp lip lra-label) + '((emit-label label) + (default-unknown-values vop values nvals move-temp lip label) (when cur-nfp (load-stack-tn cur-nfp nfp-save)))) (:unknown - '((emit-return-pc lra-label) + '((emit-label label) (note-this-location vop :unknown-return) (receive-unknown-values values-start nvals start count - lra-label lip) + label lip) (when cur-nfp (load-stack-tn cur-nfp nfp-save)))) (:tail))))))) @@ -735,22 +733,22 @@ (args-arg :scs (any-reg) :target args) (function-arg :scs (descriptor-reg) :target lexenv) (old-fp-arg :scs (any-reg) :target old-fp) - (lra-arg :scs (descriptor-reg) :target lra)) + (ra-arg :scs (any-reg) :target ra)) (:temporary (:sc any-reg :offset nl0-offset :from (:argument 0)) args) (:temporary (:sc any-reg :offset lexenv-offset :from (:argument 1)) lexenv) (:temporary (:sc any-reg :offset ocfp-offset :from (:argument 2)) old-fp) - (:temporary (:sc any-reg :offset lra-offset :from (:argument 3)) lra) + (:temporary (:sc any-reg :offset ra-offset :from (:argument 3)) ra) (:vop-var vop) (:generator 75 ;; Move these into the passing locations if they are not already there. (move args args-arg) (move lexenv function-arg) (move old-fp old-fp-arg) - (move lra lra-arg) + (move ra ra-arg) ;; Clear the number stack if anything is there. (clear-number-stack vop) ;; And jump to the assembly routine. - (invoke-asm-routine 'tail-call-variable))) + (inst jal zero-tn (make-fixup 'tail-call-variable :assembly-routine)))) ;;;; Unknown values return: @@ -763,8 +761,9 @@ ;;; Return a single value using the unknown-values convention. (define-vop (return-single) (:args (old-fp :scs (any-reg)) - (return-pc :scs (descriptor-reg)) + (return-pc :scs (any-reg) :target ra) (value)) + (:temporary (:sc any-reg :offset ra-offset :from (:argument 1)) ra) (:ignore value) (:vop-var vop) (:generator 6 @@ -774,7 +773,9 @@ (move csp-tn cfp-tn) (move cfp-tn old-fp) ;; Out of here. - (lisp-return return-pc :single-value))) + (inst li nargs-tn -1) ; mark single value return + (move ra return-pc) + (inst jalr zero-tn ra 0))) ;;; Do unknown-values return of a fixed number of values. The Values ;;; are required to be set up in the standard passing locations. @@ -791,7 +792,7 @@ collect (gensym)))) `(define-vop (return) (:args (old-fp :scs (any-reg)) - (return-pc :scs (descriptor-reg) :to (:eval 1)) + (return-pc :scs (any-reg) :to (:eval 1) :target ra) (values :more t)) (:ignore values) ,@(loop for an-offset in *register-arg-offsets* @@ -802,6 +803,7 @@ ,an)) (:temporary (:sc any-reg :offset nargs-offset) nargs) (:temporary (:sc any-reg :offset ocfp-offset) val-ptr) + (:temporary (:sc any-reg :offset ra-offset :from (:eval 1)) ra) (:info nvals) (:vop-var vop) (:generator 6 @@ -822,7 +824,8 @@ (dolist (reg (subseq (list ,@a) nvals)) (move reg null-tn))) ;; And away we go. - (lisp-return return-pc :multiple-values)))))) + (move ra return-pc) + (inst jalr zero-tn ra 0)))))) (frob)) ;;; Do unknown-values return of an arbitrary number of values (passed @@ -832,11 +835,11 @@ ;;; assembly-routine. (define-vop (return-multiple) (:args (old-fp-arg :scs (any-reg) :target old-fp) - (lra-arg :scs (descriptor-reg) :target lra) + (return-pc :scs (any-reg) :target ra) (vals-arg :scs (any-reg) :target vals) (nvals-arg :scs (any-reg) :target nvals)) (:temporary (:sc any-reg :offset nl1-offset :from (:argument 0)) old-fp) - (:temporary (:sc descriptor-reg :offset lra-offset :from (:argument 1)) lra) + (:temporary (:sc any-reg :offset ra-offset :from (:argument 1)) ra) (:temporary (:sc any-reg :offset nl0-offset :from (:argument 2)) vals) (:temporary (:sc any-reg :offset nargs-offset :from (:argument 3)) nvals) (:temporary (:scs (descriptor-reg) :offset a0-offset) a0) @@ -854,15 +857,17 @@ ;; Return with one value. (move csp-tn cfp-tn) (move cfp-tn old-fp-arg) - (lisp-return lra-arg :single-value) + (inst li nargs-tn -1) ; mark single value return + (move ra return-pc) + (inst jalr zero-tn ra 0) NOT-SINGLE (move old-fp old-fp-arg) - (move lra lra-arg) + (move ra return-pc) (move vals vals-arg) (move nvals nvals-arg) - (invoke-asm-routine 'return-multiple))) + (inst jal zero-tn (make-fixup 'return-multiple :assembly-routine)))) ;;;; XEP hackery: @@ -972,7 +977,7 @@ (when (< fixed register-arg-count) ;; Now we have to deposit any more args that showed up in registers. (when (zerop fixed) - (inst subi count nargs-tn (fixnumize fixed))) + (move count nargs-tn)) (do ((i fixed (1+ i))) ((>= i register-arg-count)) ;; Don't deposit any more than there are. @@ -1002,7 +1007,7 @@ (:generator 3 (move value null-tn) (cond ((zerop index) - (inst bge zero-tn count done)) + (inst beq count zero-tn done)) (t (inst li index-temp (fixnumize index)) (inst bge index-temp count done))) diff --git a/src/compiler/riscv/cell.lisp b/src/compiler/riscv/cell.lisp index 07a225fa12..baf935395a 100644 --- a/src/compiler/riscv/cell.lisp +++ b/src/compiler/riscv/cell.lisp @@ -23,17 +23,13 @@ (define-vop (set-slot) (:args (object :scs (descriptor-reg)) - (value :scs (descriptor-reg any-reg))) + (value :scs (descriptor-reg any-reg zero))) (:info name offset lowtag) (:ignore name) (:results) (:generator 1 (storew value object offset lowtag))) -(define-vop (init-slot set-slot) - (:info name dx-p offset lowtag) - (:ignore name dx-p)) - (define-vop (compare-and-swap-slot) (:args (object :scs (descriptor-reg)) (old :scs (descriptor-reg any-reg)) @@ -51,7 +47,7 @@ (inst sc temp new lip :aq :rl) (inst bne temp zero-tn LOOP) EXIT)) - + ;;;; Symbol hacking VOPs: (define-vop (%compare-and-swap-symbol-value) (:translate %compare-and-swap-symbol-value) @@ -74,7 +70,7 @@ (inst bne result old DONT-STORE-TLS) (storew new lip) DONT-STORE-TLS - (inst xori temp result no-tls-value-marker-widetag) + (inst xori temp result no-tls-value-marker) (inst bne temp zero-tn CHECK-UNBOUND)) (inst addi lip symbol (- (* symbol-value-slot n-word-bytes) @@ -101,7 +97,7 @@ (load-tls-index tls-slot symbol) (inst add lip thread-base-tn tls-slot) (loadw temp lip) - (inst xori temp temp no-tls-value-marker-widetag) + (inst xori temp temp no-tls-value-marker) (inst bne temp zero-tn TLS-VALUE) (storew value symbol symbol-value-slot other-pointer-lowtag) (inst j DONE) @@ -123,10 +119,9 @@ (:temporary (:scs (non-descriptor-reg)) temp)) ;;; With Symbol-Value, we check that the value isn't the trap object. -;;; So Symbol-Value of NIL is NIL. #+sb-thread (define-vop (symbol-value checked-cell-ref) - (:translate symeval) + (:translate symbol-value) (:temporary (:scs (interior-reg)) lip) (:variant-vars check-boundp) (:variant t) @@ -134,7 +129,7 @@ (load-tls-index value object) (inst add lip thread-base-tn value) (loadw value lip) - (inst xori temp value no-tls-value-marker-widetag) + (inst xori temp value no-tls-value-marker) (inst bne temp zero-tn CHECK-UNBOUND) (loadw value object symbol-value-slot other-pointer-lowtag) CHECK-UNBOUND @@ -145,7 +140,7 @@ #-sb-thread (define-vop (symbol-value checked-cell-ref) - (:translate symeval) + (:translate symbol-value) (:generator 9 (loadw value object symbol-value-slot other-pointer-lowtag) (let ((err-lab (generate-error-code vop 'unbound-symbol-error object))) @@ -153,34 +148,29 @@ (inst beq temp zero-tn err-lab)))) ;;; Like CHECKED-CELL-REF, only we are a predicate to see if the cell is bound. -(define-vop (boundp-frob) +(define-vop (boundp) (:args (object :scs (descriptor-reg))) (:conditional) (:info target not-p) (:policy :fast-safe) (:temporary (:scs (descriptor-reg)) value) - (:temporary (:scs (non-descriptor-reg)) temp)) - -#+sb-thread -(define-vop (boundp boundp-frob) - (:temporary (:scs (interior-reg)) lip) + #+sb-thread (:temporary (:scs (interior-reg)) lip) + (:temporary (:scs (non-descriptor-reg)) temp) (:translate boundp) + #+sb-thread (:generator 9 (load-tls-index value object) (inst add lip thread-base-tn value) (loadw value lip) - (inst xori temp value no-tls-value-marker-widetag) + (inst xori temp value no-tls-value-marker) (inst bne temp zero-tn CHECK-UNBOUND) (loadw value object symbol-value-slot other-pointer-lowtag) CHECK-UNBOUND (inst xori temp value unbound-marker-widetag) (if not-p (inst beq temp zero-tn target) - (inst bne temp zero-tn target)))) - -#-sb-thread -(define-vop (boundp boundp-frob) - (:translate boundp) + (inst bne temp zero-tn target))) + #-sb-thread (:generator 9 (loadw value object symbol-value-slot other-pointer-lowtag) (inst xori temp value unbound-marker-widetag) @@ -198,14 +188,14 @@ (define-vop (fast-symbol-value cell-ref) (:variant symbol-value-slot other-pointer-lowtag) (:policy :fast) - (:translate symeval)) + (:translate symbol-value)) ;;; On unithreaded builds these are just copies of the non-global versions. (define-vop (%set-symbol-global-value set)) (define-vop (symbol-global-value symbol-value) - (:translate sym-global-val)) + (:translate symbol-global-value)) (define-vop (fast-symbol-global-value fast-symbol-value) - (:translate sym-global-val)) + (:translate symbol-global-value)) (define-vop (symbol-hash) (:policy :fast-safe) @@ -223,6 +213,30 @@ (loadw temp symbol symbol-hash-slot other-pointer-lowtag) (inst andi res temp (lognot fixnum-tag-mask)))) +#+64-bit +(define-vop () + (:args (symbol :scs (descriptor-reg))) + (:results (result :scs (unsigned-reg))) + (:result-types positive-fixnum) + (:translate sb-impl::symbol-package-id) + (:policy :fast-safe) + (:generator 1 ; ASSUMPTION: symbol-package-bits = 16 + (inst lhu result symbol (+ (ash symbol-name-slot word-shift) + (- other-pointer-lowtag) + 6)))) ; little-endian +#+64-bit +(define-vop () + (:policy :fast-safe) + (:translate symbol-name) + (:args (symbol :scs (descriptor-reg))) + (:results (result :scs (descriptor-reg))) + (:temporary (:sc non-descriptor-reg) pa-flag) + (:generator 5 + (pseudo-atomic (pa-flag) + (loadw result symbol symbol-name-slot other-pointer-lowtag) + (inst slli result result sb-impl::package-id-bits) + (inst srli result result sb-impl::package-id-bits)))) + ;;;; Fdefinition (fdefn) objects. (define-vop (fdefn-fun cell-ref) (:variant fdefn-fun-slot other-pointer-lowtag)) @@ -261,14 +275,12 @@ (define-vop (fdefn-makunbound) (:policy :fast-safe) (:translate fdefn-makunbound) - (:args (fdefn :scs (descriptor-reg) :target result)) + (:args (fdefn :scs (descriptor-reg))) (:temporary (:scs (non-descriptor-reg)) temp) - (:results (result :scs (descriptor-reg))) (:generator 38 (storew null-tn fdefn fdefn-fun-slot other-pointer-lowtag) (inst li temp (make-fixup 'undefined-tramp :assembly-routine)) - (storew temp fdefn fdefn-raw-addr-slot other-pointer-lowtag) - (move result fdefn))) + (storew temp fdefn fdefn-raw-addr-slot other-pointer-lowtag))) ;;;; Binding and Unbinding. @@ -277,7 +289,7 @@ ;;; symbol. #+sb-thread (define-vop (dynbind) - (:args (value :scs (any-reg descriptor-reg)) + (:args (value :scs (any-reg descriptor-reg zero)) (symbol :scs (descriptor-reg) :target alloc-tls-symbol)) ;; These have a dual personality in the assembly routine. We are ;; trying to pack as tightly as possible. @@ -290,7 +302,7 @@ (load-tls-index tls-index symbol) (inst bne tls-index zero-tn TLS-VALID) (move alloc-tls-symbol symbol) - (invoke-asm-routine 'alloc-tls-index) + (inst jal lip (make-fixup 'alloc-tls-index :assembly-routine)) TLS-VALID (inst add lip thread-base-tn tls-index) (loadw value-temp lip) @@ -303,7 +315,7 @@ #-sb-thread (define-vop (dynbind) - (:args (value :scs (any-reg descriptor-reg)) + (:args (value :scs (any-reg descriptor-reg zero)) (symbol :scs (descriptor-reg))) (:temporary (:scs (descriptor-reg)) temp) (:temporary (:scs (any-reg)) bsp-temp) @@ -384,9 +396,9 @@ closure-info-offset fun-pointer-lowtag (descriptor-reg any-reg) * %closure-index-ref) -(define-full-setter set-funcallable-instance-info * - funcallable-instance-info-offset fun-pointer-lowtag - (descriptor-reg any-reg) * %set-funcallable-instance-info) +(define-full-setter %closure-index-set * + closure-info-offset fun-pointer-lowtag + (descriptor-reg any-reg zero) * %closure-index-set) (define-full-reffer funcallable-instance-info * funcallable-instance-info-offset fun-pointer-lowtag @@ -435,7 +447,7 @@ instance-pointer-lowtag (descriptor-reg any-reg) * %instance-ref) (define-full-setter instance-index-set * instance-slots-offset - instance-pointer-lowtag (descriptor-reg any-reg) * %instance-set) + instance-pointer-lowtag (descriptor-reg any-reg zero) * %instance-set) (define-full-casser instance-index-cas * instance-slots-offset instance-pointer-lowtag (descriptor-reg any-reg) * %instance-cas) @@ -446,17 +458,49 @@ (define-full-reffer code-header-ref * 0 other-pointer-lowtag (descriptor-reg any-reg) * code-header-ref) -(define-full-setter code-header-set * 0 other-pointer-lowtag - (descriptor-reg any-reg) * code-header-set) +(define-vop (code-header-set) + (:translate code-header-set) + (:policy :fast-safe) + (:args (object :scs (descriptor-reg)) + (index :scs (any-reg)) + (value :scs (any-reg descriptor-reg zero))) + (:arg-types * tagged-num *) + (:temporary (:scs (non-descriptor-reg)) temp card) + (:temporary (:sc non-descriptor-reg) pa-flag) + (:generator 10 + (inst li temp (make-fixup "gc_card_table_mask" :foreign-dataref)) + (loadw temp temp) ; address of gc_card_table_mask + (inst #+64-bit lwu #-64-bit lw temp temp 0) ; value of gc_card_table_mask (4-byte int) + (pseudo-atomic (pa-flag) + ;; Compute card mark index + (inst srli card object gencgc-card-shift) + (inst and card card temp) + ;; Load mark table base + (inst li temp (make-fixup "gc_card_mark" :foreign-dataref)) ; address of linkage entry + (loadw temp temp) ; address of gc_card_mark + (loadw temp temp) ; value of gc_card_mark (pointer) + ;; Touch the card mark byte. + (inst add temp temp card) + (inst sb null-tn temp 0) + ;; set 'written' flag in the code header + ;; If two threads get here at the same time, they'll write the same byte. + (let ((byte (- 3 other-pointer-lowtag))) + (inst lbu temp object byte) + (inst ori temp temp #x40) + (inst sb temp object byte)) + ;; No need for LIP register because this is pseudo-atomic + (inst slli temp index (- word-shift n-fixnum-tag-bits)) + (inst add temp object temp) + (inst #+64-bit sd #-64-bit sw value temp (- other-pointer-lowtag))))) ;;;; raw instance slot accessors (macrolet ((define-raw-slot-word-vops (name value-sc value-primtype) `(progn - (define-full-reffer ,(symbolicate "RAW-INSTANCE-REF/" name) * instance-slots-offset + (define-full-reffer ,(symbolicate "%RAW-INSTANCE-REF/" name) * instance-slots-offset instance-pointer-lowtag (,value-sc) ,value-primtype ,(symbolicate "%RAW-INSTANCE-REF/" name)) - (define-full-setter ,(symbolicate "RAW-INSTANCE-SET/" name) * instance-slots-offset + (define-full-setter ,(symbolicate "%RAW-INSTANCE-SET/" name) * instance-slots-offset instance-pointer-lowtag (,value-sc) ,value-primtype ,(symbolicate "%RAW-INSTANCE-SET/" name)) (define-full-casser ,(symbolicate "RAW-INSTANCE-CAS/" name) instance instance-slots-offset @@ -466,21 +510,21 @@ (define-raw-slot-word-vops signed-word signed-reg signed-num)) (macrolet ((define-raw-slot-float-vops (name value-primtype value-sc size format &optional complexp) - (let ((ref-vop (symbolicate "RAW-INSTANCE-REF/" name)) - (set-vop (symbolicate "RAW-INSTANCE-SET/" name))) + (let ((ref-vop (symbolicate "%RAW-INSTANCE-REF/" name)) + (set-vop (symbolicate "%RAW-INSTANCE-SET/" name))) `(progn (,(if complexp 'define-complex-float-reffer 'define-float-reffer) ,ref-vop * ,size ,format instance-slots-offset instance-pointer-lowtag (,value-sc) ,value-primtype nil "raw instance access" - ,(symbolicate "%" ref-vop)) + ,ref-vop) (,(if complexp 'define-complex-float-setter 'define-float-setter) ,set-vop * ,size ,format instance-slots-offset instance-pointer-lowtag (,value-sc) ,value-primtype nil "raw instance store" - ,(symbolicate "%" set-vop)))))) + ,set-vop))))) (define-raw-slot-float-vops single single-float single-reg 4 :single) (define-raw-slot-float-vops double double-float double-reg 8 :double) (define-raw-slot-float-vops complex-single complex-single-float complex-single-reg 4 :single t) diff --git a/src/compiler/riscv/debug.lisp b/src/compiler/riscv/debug.lisp index b43838b7d8..74e6c0dfa5 100644 --- a/src/compiler/riscv/debug.lisp +++ b/src/compiler/riscv/debug.lisp @@ -19,7 +19,7 @@ (:generator 1 (move res csp-tn))) -(define-vop () +(define-vop (current-fp-sap) (:translate current-fp) (:policy :fast-safe) (:results (res :scs (sap-reg))) @@ -48,18 +48,15 @@ (:policy :fast-safe) (:args (object :scs (sap-reg) :target sap) (offset :scs (any-reg)) - (value :scs (descriptor-reg) :target result)) + (value :scs (descriptor-reg))) (:arg-types system-area-pointer positive-fixnum *) - (:results (result :scs (descriptor-reg))) - (:result-types *) (:temporary (:scs (sap-reg) :from (:argument 1)) sap) #+#.(cl:if sb-vm::fixnum-as-word-index-needs-temp '(and) '(or)) (:temporary (:sc non-descriptor-reg) temp) (:generator 2 (with-fixnum-as-word-index (offset temp) (inst add sap object offset)) - (storew value sap 0) - (move result value))) + (storew value sap 0))) (define-vop (code-from-mumble) (:policy :fast-safe) @@ -83,10 +80,6 @@ (move code null-tn) (inst j done))))) -(define-vop (code-from-lra code-from-mumble) - (:translate sb-di::lra-code-header) - (:variant other-pointer-lowtag)) - (define-vop (code-from-fun code-from-mumble) (:translate sb-di::fun-code-header) (:variant fun-pointer-lowtag)) diff --git a/src/compiler/riscv/float.lisp b/src/compiler/riscv/float.lisp index fa6d2d650e..7dc3e27410 100644 --- a/src/compiler/riscv/float.lisp +++ b/src/compiler/riscv/float.lisp @@ -787,14 +787,12 @@ (unless (location= value-tn r) (inst fmove :single r value-tn))) #+64-bit - (ecase slot - (:real - (unless (location= r x) - (inst fmove :single r x))) - (:imag - (inst fmvx<- :double temp x) - (inst srli temp temp 32) - (inst fmvx-> :single r temp)))) + (progn + (inst fmvx<- :double temp x) + (ecase slot + (:real) + (:imag (inst srli temp temp 32))) + (inst fmvx-> :single r temp))) (complex-single-stack (inst fload :single r (current-nfp-tn vop) (+ (ecase slot diff --git a/src/compiler/riscv/insts.lisp b/src/compiler/riscv/insts.lisp index 0036d72223..b547a70d3e 100644 --- a/src/compiler/riscv/insts.lisp +++ b/src/compiler/riscv/insts.lisp @@ -14,13 +14,28 @@ (eval-when (:compile-toplevel :load-toplevel :execute) ;; Imports from SB-VM into this package - (import '(sb-vm::u-and-i-inst-immediate - sb-vm::lip-tn - sb-vm::zero-tn - sb-vm::null-tn + (import '(;; SBs, SCs, and TNs + sb-vm::immediate-constant + sb-vm::registers sb-vm::float-registers + sb-vm::zero + sb-vm::zero-offset + sb-vm::lip-tn sb-vm::zero-tn + ;; Types + sb-vm::u-and-i-inst-immediate sb-vm::short-immediate sb-vm::short-immediate-fixnum sb-vm::u+i-immediate))) + +;;;; Constants, types, conversion functions, some disassembler stuff. + +(defun reg-tn-encoding (tn) + (declare (type tn tn)) + (sc-case tn + (zero zero-offset) + (t + (case (sb-name (sc-sb (tn-sc tn))) + ((registers float-registers) (tn-offset tn)) + (t (error "~S isn't a register." tn)))))) ;;;; disassembler field definitions @@ -68,11 +83,11 @@ (integer (emit-machine-word segment word))))) -(defconstant-eqx reg-printer +(defconstant-eqx r-printer '(:name :tab rd ", " rs1 ", " rs2) - #'equalp) + #'equal) -(define-instruction-format (r 32 :default-printer reg-printer) +(define-instruction-format (r 32 :default-printer r-printer) (funct7 :field (byte 7 25)) (rs2 :field (byte 5 20) :type 'reg) (rs1 :field (byte 5 15) :type 'reg) @@ -83,11 +98,11 @@ (define-bitfield-emitter %emit-r-inst 32 (byte 7 25) (byte 5 20) (byte 5 15) (byte 3 12) (byte 5 7) (byte 7 0)) (defun emit-r-inst (segment funct7 rs2 rs1 funct3 rd opcode) - (%emit-r-inst segment funct7 (tn-offset rs2) (tn-offset rs1) funct3 (tn-offset rd) opcode)) + (%emit-r-inst segment funct7 (reg-tn-encoding rs2) (reg-tn-encoding rs1) funct3 (reg-tn-encoding rd) opcode)) (defconstant-eqx i-printer '(:name :tab rd ", " rs1 ", " imm) - #'equalp) + #'equal) (define-instruction-format (i 32 :default-printer i-printer) (i-annotation :fields (list (byte 5 15) (byte 12 20))) @@ -104,14 +119,14 @@ (defun emit-i-inst (segment imm rs1 funct3 rd opcode) (etypecase imm (short-immediate - (%emit-i-inst segment imm (tn-offset rs1) funct3 (tn-offset rd) opcode)) + (%emit-i-inst segment imm (reg-tn-encoding rs1) funct3 (reg-tn-encoding rd) opcode)) (fixup (note-fixup segment :i-type imm) - (%emit-i-inst segment 0 (tn-offset rs1) funct3 (tn-offset rd) opcode)))) + (%emit-i-inst segment 0 (reg-tn-encoding rs1) funct3 (reg-tn-encoding rd) opcode)))) (defconstant-eqx s-printer '(:name :tab rs2 ", " "(" imm ")" rs1) - #'equalp) + #'equal) (define-instruction-format (s 32 :default-printer s-printer) (store-annotation :fields (list (byte 5 15) (byte 7 25) (byte 5 7)) :type 'store-annotation) @@ -126,14 +141,20 @@ (defun emit-s-inst (segment imm rs2 rs1 funct3 opcode) (etypecase imm (short-immediate - (%emit-s-inst segment (ldb (byte 7 5) imm) (tn-offset rs2) (tn-offset rs1) funct3 (ldb (byte 5 0) imm) opcode)) + (%emit-s-inst segment (ldb (byte 7 5) imm) + (reg-tn-encoding rs2) (reg-tn-encoding rs1) + funct3 (ldb (byte 5 0) imm) + opcode)) (fixup (note-fixup segment :s-type imm) - (%emit-s-inst segment 0 (tn-offset rs2) (tn-offset rs1) funct3 0 opcode)))) + (%emit-s-inst segment 0 + (reg-tn-encoding rs2) (reg-tn-encoding rs1) + funct3 0 + opcode)))) (defconstant-eqx cond-branch-printer '(:name :tab rs1 ", " rs2 ", " imm) - #'equalp) + #'equal) (define-instruction-format (b 32 :default-printer cond-branch-printer) (imm :fields (list (byte 1 31) (byte 1 7) (byte 6 25) (byte 4 8)) :type 'relative-b-label) @@ -147,12 +168,13 @@ (defun emit-b-inst (segment imm rs2 rs1 funct3 opcode) (aver (not (logbitp 0 imm))) (%emit-b-inst segment (ldb (byte 1 12) imm) (ldb (byte 6 5) imm) - (tn-offset rs2) (tn-offset rs1) funct3 (ldb (byte 4 1) imm) + (reg-tn-encoding rs2) (reg-tn-encoding rs1) + funct3 (ldb (byte 4 1) imm) (ldb (byte 1 11) imm) opcode)) (defconstant-eqx u-printer '(:name :tab rd ", " imm) - #'equalp) + #'equal) (define-instruction-format (u 32 :default-printer u-printer) (imm :field (byte 20 12) :printer "#x~5,'0X") @@ -164,14 +186,14 @@ (defun emit-u-inst (segment imm rd opcode) (etypecase imm (integer - (%emit-u-inst segment imm (tn-offset rd) opcode)) + (%emit-u-inst segment imm (reg-tn-encoding rd) opcode)) (fixup (note-fixup segment :u-type imm) - (%emit-u-inst segment 0 (tn-offset rd) opcode)))) + (%emit-u-inst segment 0 (reg-tn-encoding rd) opcode)))) (defconstant-eqx j-printer '(:name :tab rd ", " imm) - #'equalp) + #'equal) (define-instruction-format (j 32 :default-printer j-printer) (imm :fields (list (byte 1 31) (byte 8 12) (byte 1 20) (byte 10 21)) :type 'relative-j-label) @@ -184,7 +206,7 @@ (aver (not (logbitp 0 imm))) (%emit-j-inst segment (ldb (byte 1 20) imm) (ldb (byte 10 1) imm) (ldb (byte 1 11) imm) (ldb (byte 8 12) imm) - (tn-offset rd) opcode)) + (reg-tn-encoding rd) opcode)) (define-instruction lui (segment rd ui) (:printer u ((opcode #b0110111))) @@ -292,38 +314,36 @@ (define-branch-instruction bltu #b110) (define-branch-instruction bgeu #b111)) -(macrolet ((define-load-instruction (name funct3 &optional wordp) +(macrolet ((define-load-instruction (name funct3) `(define-instruction ,name (segment rd rs offset) (:printer i ((funct3 ,funct3) (opcode #b0000011) (i-annotation nil :type 'load-annotation)) - '(:name :tab rd ", (" imm ")" rs1 - ,(when wordp 'i-annotation))) + '(:name :tab rd ", (" imm ")" rs1 i-annotation)) (:emitter (emit-i-inst segment offset rs ,funct3 rd #b0000011))))) (define-load-instruction lb #b000) (define-load-instruction lh #b001) - (define-load-instruction lw #b010 #-64-bit t) + (define-load-instruction lw #b010) #+64-bit (progn - (define-load-instruction ld #b011 t) + (define-load-instruction ld #b011) (define-load-instruction lwu #b110)) (define-load-instruction lbu #b100) (define-load-instruction lhu #b101)) -(macrolet ((define-store-instruction (name funct3 &optional wordp) +(macrolet ((define-store-instruction (name funct3) `(define-instruction ,name (segment rs2 rs1 offset) (:printer s ((funct3 ,funct3) (opcode #b0100011)) - '(:name :tab rs2 ", " "(" imm ")" rs1 - ,(when wordp 'store-annotation))) + '(:name :tab rs2 ", " "(" imm ")" rs1 store-annotation)) (:emitter (emit-s-inst segment offset rs2 rs1 ,funct3 #b0100011))))) (define-store-instruction sb #b000) (define-store-instruction sh #b001) - (define-store-instruction sw #b010 #-64-bit t) + (define-store-instruction sw #b010) #+64-bit - (define-store-instruction sd #b011 t)) + (define-store-instruction sd #b011)) (macrolet ((define-immediate-arith-instruction (name funct3 &optional word-name) `(progn @@ -331,7 +351,12 @@ (:printer i ((funct3 ,funct3) (opcode #b0010011))) (:emitter - (emit-i-inst segment imm rs ,funct3 rd #b0010011))) + ,(if (eq name 'xori) + ;; Use something like PLAUSIBLE-SIGNED-IMM32-OPERAND-P in the amd64 assembler. + ;; This is totally ad-hoc and just enough to emit a logical NOT instruction. + `(flet ((cast-to-imm (x) (if (= x most-positive-word) -1 x))) + (emit-i-inst segment (cast-to-imm imm) rs ,funct3 rd #b0010011)) + `(emit-i-inst segment imm rs ,funct3 rd #b0010011)))) ,(when word-name #+64-bit `(define-instruction ,word-name (segment rd rs imm) @@ -564,10 +589,16 @@ (:fcsr #x003))) (defun emit-csr-inst (segment csr funct3 rs rd) - (%emit-i-inst segment (csr-encoding csr) (tn-offset rs) funct3 (tn-offset rd) #b1110011)) + (%emit-i-inst segment + (csr-encoding csr) (reg-tn-encoding rs) + funct3 (reg-tn-encoding rd) + #b1110011)) (defun emit-csr-i-inst (segment csr funct3 zimm rd) - (%emit-i-inst segment (csr-encoding csr) zimm funct3 (tn-offset rd) #b1110011)) + (%emit-i-inst segment + (csr-encoding csr) zimm + funct3 (reg-tn-encoding rd) + #b1110011)) (macrolet ((define-csr-instruction (name funct3) `(define-instruction ,name (segment rd csr rs) @@ -698,23 +729,23 @@ (rd :field (byte 5 7) :type 'fp-reg) (opcode :field (byte 7 0))) -(defun ensure-tn-offset (imm/tn) +(defun ensure-reg-tn-encoding (imm/tn) (etypecase imm/tn ((integer 0 31) imm/tn) - (tn (tn-offset imm/tn)))) + (tn (reg-tn-encoding imm/tn)))) (defun emit-r-float-inst (segment rs3/funct5 fmt rs2 rs1 rm rd opcode) (%emit-r-inst segment - (dpb (ensure-tn-offset rs3/funct5) + (dpb (ensure-reg-tn-encoding rs3/funct5) (byte 5 2) (ecase fmt (:single #b00) (:double #b01) (:quad #b10))) - (ensure-tn-offset rs2) - (tn-offset rs1) + (ensure-reg-tn-encoding rs2) + (reg-tn-encoding rs1) rm - (tn-offset rd) + (reg-tn-encoding rd) opcode)) (defun rm-encoding (rm) @@ -830,11 +861,11 @@ (:emitter (emit-s-inst segment offset rs1 rs2 (fmt-funct3 fmt) #b0100111)))) -;;;; Boxed-object computation instructions (for LRA and CODE) +;;;; Boxed-object computation instructions (for RA and CODE) ;;; Try to compute DEST from SRC if possible. Otherwise, fall back to ;;; using a PC relative calculation as the worst case. -(defun emit-compute (segment vop dest lip pc-relative-delta src-relative-delta &optional src) +(defun emit-compute (segment vop dest src lip pc-relative-delta src-relative-delta) (labels ((pc-relative-emitter (segment position) (multiple-value-bind (u i) (u-and-i-inst-immediate (funcall pc-relative-delta position)) @@ -843,11 +874,11 @@ (inst addi dest lip i)))) (src-relative-emitter (segment position) (assemble (segment vop) - (inst addi dest src (funcall src-relative-delta position)))) - (maybe-shrink (segment chooser position magic-value) + (inst addi dest src (funcall src-relative-delta position 0)))) + (maybe-shrink (segment chooser position delta-if-after) (declare (ignore chooser)) (when (and src - (typep (funcall src-relative-delta position magic-value) + (typep (funcall src-relative-delta position delta-if-after) 'short-immediate)) (emit-back-patch segment 4 #'src-relative-emitter) t))) @@ -856,44 +887,48 @@ #'maybe-shrink #'pc-relative-emitter))) -;;; FIXME: Could potentially optimize away an instruction in -;;; XEP-ALLOCATE-FRAME in some cases when the code can be computed off -;;; of the register used to call the function, like MIPS. Probably -;;; requires always using LR as a lip tn though. Also, if the return -;;; register is fixed, could compute code in one instruction in values -;;; receiving routines. -(define-instruction compute-code (segment code lip label &optional src) +(define-instruction compute-code-from-fn (segment dest src lip label) (:vop-var vop) (:emitter - (emit-compute segment vop code lip - (lambda (position &optional magic-value) - (declare (ignore magic-value)) + (emit-compute segment vop dest src lip + (lambda (position) (- other-pointer-lowtag position (component-header-length))) - ;; code = lra - other-pointer-tag - header - label-offset + other-pointer-tagged - ;; = lra - (header + label-offset) - (lambda (position &optional (magic-value 0)) - (- (+ (label-position label position magic-value) - (component-header-length)))) - src))) - -(define-instruction compute-lra (segment dest lip lra-label &optional src) + ;; code = fn - fn-ptr-type - header - label-offset + other-pointer-tag + (lambda (position delta-if-after) + (- other-pointer-lowtag + (+ fun-pointer-lowtag + (label-position label position delta-if-after) + (component-header-length))))))) + +(define-instruction compute-code-from-ra (segment dest src lip label) (:vop-var vop) (:emitter - (emit-compute segment vop dest lip - (lambda (position &optional magic-value) - (- (+ (label-position lra-label - (when magic-value position) - magic-value) - other-pointer-lowtag) - position)) - ;; lra = code + other-pointer-tag + header + label-offset - other-pointer-tag - ;; = code + header + label-offset - (lambda (position &optional (magic-value 0)) - (+ (label-position lra-label position magic-value) + (emit-compute segment vop dest src lip + (lambda (position) + (- other-pointer-lowtag + position (component-header-length))) - src))) + ;; code = ra - header - label-offset + other-pointer-tag + ;; = ra + other-pointer-tag - (header + label-offset) + (lambda (position delta-if-after) + (- other-pointer-lowtag + (+ (label-position label position delta-if-after) + (component-header-length))))))) + +(define-instruction compute-ra-from-code (segment dest src lip label) + (:vop-var vop) + (:emitter + (emit-compute segment vop dest src lip + (lambda (position) + (- (label-position label) position)) + ;; ra = code - other-pointer-tag + header + label-offset + ;; = code + header + label-offset - other-pointer-tag + (lambda (position delta-if-after) + (- (+ (label-position label position delta-if-after) + (component-header-length)) + other-pointer-lowtag))))) (defun emit-header-data (segment type) (emit-back-patch @@ -908,6 +943,490 @@ (:emitter (emit-header-data segment simple-fun-widetag))) -(define-instruction lra-header-word (segment) +(define-instruction-macro load-layout-id (reg layout) + `(progn (inst .layout-id-fixup ,layout) + (inst lui ,reg #xfffff) + (inst addi ,reg ,reg -1))) + +(define-instruction .layout-id-fixup (segment layout) + (:emitter (sb-c:note-fixup segment :u+i-type (sb-c:make-fixup layout :layout-id)))) + +(defun sb-vm:fixup-code-object (code offset value kind flavor) + (declare (type index offset)) + (unless (zerop (rem offset sb-assem:+inst-alignment-bytes+)) + (error "Unaligned instruction? offset=#x~X." offset)) + #+64-bit + (unless (typep value 'u+i-immediate) + (error "Tried to fixup with ~a." value)) + (let ((sap (code-instructions code))) + (multiple-value-bind (u i) (u-and-i-inst-immediate value) + (ecase kind + (:absolute + (setf (sap-ref-32 sap offset) value)) + (:u-type + (setf (ldb (byte 20 12) (sap-ref-32 sap offset)) u)) + (:i-type + (setf (ldb (byte 12 20) (sap-ref-32 sap offset)) i)) + (:u+i-type + (sb-vm:fixup-code-object code offset u :u-type flavor) + (sb-vm:fixup-code-object code (+ offset 4) i :i-type flavor)) + (:s-type + (setf (ldb (byte 5 7) (sap-ref-32 sap offset)) + (ldb (byte 5 0) i)) + (setf (ldb (byte 7 25) (sap-ref-32 sap offset)) + (ldb (byte 7 5) i)))))) + nil) + +(define-instruction store-coverage-mark (segment mark-index) + (:emitter + ;; No backpatch is needed to compute the offset into the code header + ;; because COMPONENT-HEADER-LENGTH is known at this point. + (let ((offset (+ (component-header-length) + ;; skip over jump table word and entries + (* (1+ (component-n-jump-table-entries)) + n-word-bytes) + mark-index + (- other-pointer-lowtag)))) + (assemble (segment) + (inst sb sb-vm::null-tn sb-vm::code-tn + (the (unsigned-byte 11) offset)))))) + + +;;;; The RISC-V C extension. + +(define-arg-type rvc-reg :printer #'print-rvc-reg) +(define-arg-type ci-imm :printer #'print-ci-imm) +(define-arg-type ci-load-32-imm :printer #'print-ci-load-32-imm) +(define-arg-type ci-load-64-imm :printer #'print-ci-load-64-imm) +(define-arg-type css-32-imm :printer #'print-css-32-imm) +(define-arg-type css-64-imm :printer #'print-css-64-imm) +(define-arg-type ciw-imm :printer #'print-ciw-imm) +(define-arg-type cl/cs-32-imm :printer #'print-cl/cs-32-imm) +(define-arg-type cl/cs-64-imm :printer #'print-cl/cs-64-imm) +(define-arg-type cb-arith-imm :printer #'print-cb-arith-imm) +(define-arg-type relative-cb-label :use-label #'use-cb-label) +(define-arg-type relative-cj-label :use-label #'use-cj-label) + +(defun rvc-reg-tn-encoding (tn) + (declare (type tn tn)) + (let ((offset (reg-tn-encoding tn))) + (aver (<= 8 offset 15)) + (- offset 8))) + +(defconstant-eqx cr-printer + '(:name :tab rd/rs1 ", " rs2) + #'equal) + +(define-instruction-format (cr 16 :default-printer cr-printer) + (funct4 :field (byte 4 12)) + (rd/rs1 :field (byte 5 7) :type 'reg) + (rs2 :field (byte 5 2) :type 'reg) + (opcode :field (byte 2 0))) + +(define-bitfield-emitter %emit-cr-inst 16 + (byte 4 12) (byte 5 7) (byte 5 2) (byte 2 0)) +(defun emit-cr-inst (segment funct4 rd/rs1 rs2 opcode) + (%emit-cr-inst segment funct4 (reg-tn-encoding rd/rs1) (reg-tn-encoding rs2) opcode)) + +(defconstant-eqx ci-printer + '(:name :tab rd/rs1 ", " imm) + #'equal) + +(define-instruction-format (ci 16 :default-printer ci-printer) + (funct3 :field (byte 3 13)) + (rd/rs1 :field (byte 5 7) :type 'reg) + (imm :fields (list (byte 1 12) (byte 5 2)) :type 'ci-imm) + (opcode :field (byte 2 0))) + +(define-bitfield-emitter %emit-ci-inst 16 + (byte 3 13) (byte 1 12) (byte 5 7) (byte 5 2) (byte 2 0)) +(defun emit-ci-inst (segment funct3 rd/rs1 imm opcode) + (%emit-ci-inst segment funct3 (ldb (byte 1 5) imm) + (reg-tn-encoding rd/rs1) (ldb (byte 5 0) imm) opcode)) + +(defconstant-eqx ci-load-printer + '(:name :tab rd ", " imm) + #'equal) + +(define-instruction-format (ci-load-32 16 :default-printer ci-load-printer) + (funct3 :field (byte 3 13)) + (rd :field (byte 5 7) :type 'reg) + (imm :fields (list (byte 1 12) (byte 5 2)) :type 'ci-load-32-imm) + (opcode :field (byte 2 0))) + +(define-bitfield-emitter %emit-ci-load-32-inst 16 + (byte 3 13) (byte 1 12) (byte 5 7) (byte 3 4) (byte 2 2) (byte 2 0)) + +(defun emit-ci-load-32-inst (segment funct3 rd imm opcode) + (aver (zerop (rem imm 4))) + (%emit-ci-load-32-inst segment funct3 (ldb (byte 1 5) imm) + (reg-tn-encoding rd) (ldb (byte 3 2) imm) + (ldb (byte 2 6) imm) opcode)) + +(define-instruction-format (ci-load-64 16 :default-printer ci-load-printer) + (funct3 :field (byte 3 13)) + (rd :field (byte 5 7) :type 'reg) + (imm :fields (list (byte 1 12) (byte 5 2)) :type 'ci-load-64-imm) + (opcode :field (byte 2 0))) + +(define-bitfield-emitter %emit-ci-load-64-inst 16 + (byte 3 13) (byte 1 12) (byte 5 7) (byte 2 5) (byte 3 2) (byte 2 0)) + +(defun emit-ci-load-64-inst (segment funct3 rd imm opcode) + (aver (zerop (rem imm 8))) + (%emit-ci-load-32-inst segment funct3 (ldb (byte 1 5) imm) + (reg-tn-encoding rd) (ldb (byte 2 3) imm) + (ldb (byte 3 6) imm) opcode)) + +(defconstant-eqx css-printer + '(:name :tab rs2 ", " imm) + #'equal) + +(define-instruction-format (css-32 16 :default-printer css-printer) + ;; TODO: store annotation + (funct3 :field (byte 3 13)) + (imm :fields (list (byte 2 7) (byte 4 9)) :type 'css-32-imm) + (rs2 :field (byte 5 2) :type 'reg) + (opcode :field (byte 2 0))) + +(define-bitfield-emitter %emit-css-32-inst 16 + (byte 3 13) (byte 4 9) (byte 2 7) (byte 5 2) (byte 2 0)) +(defun emit-css-32-inst (segment funct3 imm rs2 opcode) + (aver (zerop (rem imm 4))) + (%emit-css-32-inst segment (ldb (byte 4 2) imm) + funct3 (ldb (byte 2 6) imm) + (rvc-reg-tn-encoding rs2) opcode)) + +(define-instruction-format (css-64 16 :default-printer css-printer) + ;; TODO: store annotation + (funct3 :field (byte 3 13)) + (imm :fields (list (byte 3 7) (byte 3 10)) :type 'css-64-imm) + (rs2 :field (byte 5 2) :type 'reg) + (opcode :field (byte 2 0))) + +(define-bitfield-emitter %emit-css-64-inst 16 + (byte 3 13) (byte 3 10) (byte 3 7) (byte 5 2) (byte 2 0)) +(defun emit-css-64-inst (segment funct3 imm rs2 opcode) + (aver (zerop (rem imm 4))) + (%emit-css-64-inst segment (ldb (byte 4 2) imm) + funct3 (ldb (byte 2 6) imm) + (rvc-reg-tn-encoding rs2) opcode)) + +(defconstant-eqx ciw-printer + '(:name :tab rd* ", " imm) + #'equal) + +(define-instruction-format (ciw 16 :default-printer ciw-printer) + (funct3 :field (byte 3 13)) + (imm :fields (list (byte 4 7) (byte 2 11) (byte 1 5) (byte 1 6)) :type 'ciw-imm) + (rd* :field (byte 3 2) :type 'rvc-reg) + (opcode :field (byte 2 0))) + +(define-bitfield-emitter %emit-ciw-inst 16 + (byte 3 13) (byte 2 11) (byte 4 7) (byte 1 6) (byte 1 5) (byte 3 2) (byte 2 0)) +(defun emit-ciw-inst (segment funct3 imm rd* opcode) + (%emit-ciw-inst segment funct3 (ldb (byte 2 4) imm) + (ldb (byte 4 6) imm) (ldb (byte 1 2) imm) + (ldb (byte 1 3) imm) (rvc-reg-tn-encoding rd*) + opcode)) + +(defconstant-eqx cl/cs-printer + '(:name :tab rd*/rs2* ", " "(" imm ")" rs1*) + #'equal) + +(define-instruction-format (cl/cs-32 16 :default-printer cl/cs-printer) + (funct3 :field (byte 3 13)) + (imm :fields (list (byte 1 6) (byte 3 10) (byte 1 5)) :type 'cl/cs-32-imm) + (rs1* :field (byte 3 7) :type 'rvc-reg) + (rd*/rs2* :field (byte 3 2) :type 'rvc-reg) + (opcode :field (byte 2 0))) + +(define-bitfield-emitter %emit-cl/cs-32-inst 16 + (byte 3 13) (byte 3 10) (byte 3 7) (byte 1 6) (byte 1 5) (byte 3 2) (byte 2 0)) + +(defun emit-cl/cs-32-inst (segment funct3 rs1* imm rd*/rs2* opcode) + (aver (zerop (rem imm 4))) + (%emit-cl/cs-32-inst segment funct3 (ldb (byte 3 3) imm) + (rvc-reg-tn-encoding rs1*) (ldb (byte 1 2) imm) + (ldb (byte 1 6) imm) (rvc-reg-tn-encoding rd*/rs2*) + opcode)) + +(define-instruction-format (cl/cs-64 16 :default-printer cl/cs-printer) + (funct3 :field (byte 3 13)) + (imm :fields (list (byte 2 5) (byte 3 10)) :type 'cl/cs-64-imm) + (rs1* :field (byte 3 7) :type 'rvc-reg) + (rd*/rs2* :field (byte 3 2) :type 'rvc-reg) + (opcode :field (byte 2 0))) + +(define-bitfield-emitter %emit-cl/cs-64-inst 16 + (byte 3 13) (byte 3 10) (byte 3 7) (byte 2 5) (byte 3 2) (byte 2 0)) + +(defun emit-cl/cs-64-inst (segment funct3 rs1* imm rd*/rs2* opcode) + (aver (zerop (rem imm 8))) + (%emit-cl/cs-64-inst segment funct3 (ldb (byte 3 3) imm) + (rvc-reg-tn-encoding rs1*) (ldb (byte 2 6) imm) + (rvc-reg-tn-encoding rd*/rs2*) opcode)) + +(defconstant-eqx ca-printer + '(:name :tab rd*/rs1* ", " rs2*) + #'equal) + +(define-instruction-format (ca 16 :default-printer ca-printer) + (funct6 :field (byte 6 10)) + (rd*/rs1* :field (byte 3 7) :type 'rvc-reg) + (funct2 :field (byte 2 5)) + (rs2* :field (byte 3 2) :type 'rvc-reg) + (opcode :field (byte 2 0))) + +(define-bitfield-emitter %emit-ca-inst 16 + (byte 6 10) (byte 3 7) (byte 2 5) (byte 3 2) (byte 2 0)) + +(defconstant-eqx cb-arith-printer + '(:name :tab rd*/rs1* ", " imm) + #'equal) + +(define-instruction-format (cb-arith 16 :default-printer cb-arith-printer) + (funct3 :field (byte 3 13)) + (imm :fields (list (byte 1 12) (byte 5 2)) :type 'cb-arith-imm) + (funct2 :field (byte 2 10)) + (rd*/rs1* :field (byte 3 7) :type 'rvc-reg) + (opcode :field (byte 2 0))) + +(define-bitfield-emitter %emit-cb-arith-inst 16 + (byte 3 13) (byte 1 12) (byte 2 10) (byte 3 7) (byte 5 2) (byte 2 0)) + +(defun emit-cb-arith-inst (segment funct3 funct2 rd*/rs1* imm opcode) + (%emit-cb-arith-inst segment funct3 (ldb (byte 1 5) imm) + funct2 (rvc-reg-tn-encoding rd*/rs1*) + (ldb (byte 5 0) imm) opcode)) + +(defconstant-eqx cb-branch-printer + '(:name :tab rs1* ", " offset) + #'equal) + +(define-instruction-format (cb-branch 16 :default-printer cb-branch-printer) + (funct3 :field (byte 3 13)) + (offset :fields (list (byte 1 12) (byte 2 5) (byte 1 2) (byte 2 10) (byte 2 3)) + :type 'relative-cb-label) + (rs1* :field (byte 3 7) :type 'rvc-reg) + (opcode :field (byte 2 0))) + +(define-bitfield-emitter %emit-cb-branch-inst 16 + (byte 3 13) (byte 1 12) (byte 2 10) (byte 3 7) + (byte 2 5) (byte 2 3) (byte 1 2) (byte 2 0)) + +(defun emit-cb-branch-inst (segment funct3 imm rs1* opcode) + (aver (not (logbitp 0 imm))) + (%emit-cb-branch-inst segment funct3 + (ldb (byte 1 8) imm) + (ldb (byte 2 3) imm) + (rvc-reg-tn-encoding rs1*) + (ldb (byte 2 6) imm) + (ldb (byte 2 1) imm) + (ldb (byte 1 5) imm) + opcode)) + +(defconstant-eqx cj-printer + '(:name :tab imm) + #'equal) + +(define-instruction-format (cj 16 :default-printer cj-printer) + (funct3 :field (byte 3 13)) + (imm :fields (list (byte 1 12) (byte 1 8) (byte 2 9) (byte 1 6) + (byte 1 7) (byte 1 2) (byte 1 8) (byte 3 3)) + :type 'relative-cj-label) + (opcode :field (byte 2 0))) + +(define-bitfield-emitter %emit-cj-inst 16 + (byte 3 13) (byte 1 12) (byte 1 11) (byte 2 9) (byte 1 8) + (byte 1 7) (byte 1 6) (byte 3 3) (byte 1 2) (byte 2 0)) + +(defun emit-cj-inst (segment funct3 imm opcode) + (aver (not (logbitp 0 imm))) + (%emit-cj-inst segment funct3 + (ldb (byte 1 11) imm) (ldb (byte 1 4) imm) + (ldb (byte 2 8) imm) (ldb (byte 1 10) imm) + (ldb (byte 1 6) imm) (ldb (byte 1 7) imm) + (ldb (byte 3 1) imm) (ldb (byte 1 5) imm) + opcode)) + +(macrolet ((define-rvc-sp-load-instruction (name funct3 emitter) + `(define-instruction ,name (segment rd offset) + (:printer ci + ((funct3 ,funct3) + (opcode #b10))) + (:emitter + (,emitter segment ,funct3 rd offset #b10))))) + (define-rvc-sp-load-instruction c.lwsp #b010 emit-ci-load-32-inst) + #+64-bit + (define-rvc-sp-load-instruction c.ldsp #b011 emit-ci-load-64-inst) + #+(and (not 64-bit) soft-doubles) + (define-rvc-sp-load-instruction c.flwsp #b011 emit-ci-load-32-inst) + (define-rvc-sp-load-instruction c.fldsp #b001 emit-ci-load-64-inst)) + +(macrolet ((define-rvc-sp-store-instruction (name funct3 size) + (multiple-value-bind (emitter type) + (ecase size + (32 (values 'emit-css-32-inst 'css-32)) + (64 (values 'emit-css-64-inst 'css-64))) + `(define-instruction ,name (segment rs2 offset) + (:printer ,type + ((funct3 ,funct3) + (opcode #b10))) + (:emitter + (,emitter segment ,funct3 rs2 offset #b10)))))) + + (define-rvc-sp-store-instruction c.swsp #b110 32) + #+64-bit + (define-rvc-sp-store-instruction c.sdsp #b111 64) + #+(and (not 64-bit) soft-doubles) + (define-rvc-sp-store-instruction c.fswsp #b111 32) + (define-rvc-sp-store-instruction c.fsdsp #b101 64)) + +(macrolet ((define-rvc-load/store-instruction (name funct3 size arg) + (multiple-value-bind (emitter type) + (ecase size + (32 (values 'emit-cl/cs-32-inst 'cl/cs-32)) + (64 (values 'emit-cl/cs-64-inst 'cl/cs-64))) + `(define-instruction ,name (segment ,arg rs1* offset) + (:printer ,type + ((funct3 ,funct3) + (opcode #b00))) + (:emitter + (,emitter segment ,funct3 ,arg offset rs1* #b00)))))) + (define-rvc-load/store-instruction c.lw #b010 32 rd*) + #+64-bit + (define-rvc-load/store-instruction c.ld #b011 64 rd*) + #+(and (not 64-bit) soft-doubles) + (define-rvc-load/store-instruction c.flw #b011 32 rd*) + (define-rvc-load/store-instruction c.fld #b001 64 rd*) + (define-rvc-load/store-instruction c.sw #b110 32 rs2*) + #+64-bit + (define-rvc-load/store-instruction c.sd #b111 64 rs2*) + #+(and (not 64-bit) soft-doubles) + (define-rvc-load/store-instruction c.fsw #b111 32 rs2*) + (define-rvc-load/store-instruction c.fsd #b101 64 rs2*)) + +(macrolet ((define-rvc-cj-jump-instruction (name funct3) + `(define-instruction ,name (segment offset) + (:printer cj + ((funct3 ,funct3) + (opcode #b01))) + (:emitter + (emit-cj-inst segment ,funct3 offset #b01))))) + (define-rvc-cj-jump-instruction c.j #b101) + #-64-bit + (define-rvc-cj-jump-instruction c.jal #b001)) + +(macrolet ((define-rvc-cr-jump-instruction (name funct4) + `(define-instruction ,name (segment rs1) + (:printer cr + ((funct4 ,funct4) + (opcode #b10) + (rs2 0))) + (:emitter + (%emit-cr-inst segment ,funct4 (reg-tn-encoding rs1) 0 #b10))))) + (define-rvc-cr-jump-instruction c.jr #b1000) + #-64-bit + (define-rvc-cr-jump-instruction c.jalr #b1001)) + +(macrolet ((define-rvc-branch-instruction (name funct3) + `(define-instruction ,name (segment rs1* offset) + (:printer cb-branch + ((funct3 ,funct3) + (opcode #b01))) + (:emitter + (emit-cb-branch-inst segment ,funct3 rs1* offset #b01))))) + (define-rvc-branch-instruction c.beqz #b110) + (define-rvc-branch-instruction c.bnez #b111)) + +(macrolet ((define-rvc-constant-gen-instruction (name funct3) + `(define-instruction ,name (segment rd imm) + (:printer ci + ((funct3 ,funct3) + (opcode #b01))) + (:emitter + (emit-ci-inst segment ,funct3 rd imm #b01))))) + (define-rvc-constant-gen-instruction c.li #b010) + (define-rvc-constant-gen-instruction c.lui #b011)) + +(macrolet ((define-rvc-ci-arith-instruction (name funct3 opcode) + `(define-instruction ,name (segment rd/rs1 imm) + (:printer ci + ((funct3 ,funct3) + (opcode ,opcode))) + (:emitter + (emit-ci-inst segment ,funct3 rd/rs1 imm ,opcode))))) + (define-rvc-ci-arith-instruction c.addi #b000 #b01) + #+64-bit + (define-rvc-ci-arith-instruction c.addiw #b001 #b01) + (define-rvc-ci-arith-instruction c.slli #b000 #b10)) + +(define-instruction c.addisp16 (segment imm) + (:emitter + segment imm + (error "What a funky instruction."))) + +(define-instruction c.addi4spn (segment rd* imm) + (:printer ciw + ((funct3 #b00) + (opcode #b00))) + (:emitter + (emit-ciw-inst segment #b00 imm rd* #b00))) + +(macrolet ((define-rvc-cb-arith-instruction (name funct3 funct2) + `(define-instruction ,name (segment rd*/rs1* imm) + (:printer cb-arith + ((funct3 ,funct3) + (funct2 ,funct2) + (opcode #b01))) + (:emitter + (emit-cb-arith-inst segment ,funct3 ,funct2 rd*/rs1* imm #b01))))) + (define-rvc-cb-arith-instruction c.srli #b100 #b00) + (define-rvc-cb-arith-instruction c.srai #b100 #b01) + (define-rvc-cb-arith-instruction c.andi #b100 #b10)) + +(macrolet ((define-rvc-cr-arith-instruction (name funct4) + `(define-instruction ,name (segment rd/rs1 rs2) + (:printer cr + ((funct4 ,funct4) + (opcode #b10))) + (:emitter + (%emit-cr-inst segment ,funct4 rd/rs1 rs2 #b10))))) + (define-rvc-cr-arith-instruction c.mv #b1000) + (define-rvc-cr-arith-instruction c.add #b1001)) + +(macrolet ((define-rvc-ca-arith-instruction (name funct6 funct2) + `(define-instruction ,name (segment rd*/rs1* rs2*) + (:printer ca + ((funct6 ,funct6) + (funct2 ,funct2) + (opcode #b01))) + (:emitter + (%emit-ca-inst segment ,funct6 rd*/rs1* ,funct2 rs2* #b01))))) + (define-rvc-ca-arith-instruction c.and #b100011 #b11) + (define-rvc-ca-arith-instruction c.or #b100011 #b10) + (define-rvc-ca-arith-instruction c.xor #b100011 #b01) + (define-rvc-ca-arith-instruction c.sub #b100011 #b00) + #+64-bit + (define-rvc-ca-arith-instruction c.addw #b100111 #b01) + #+64-bit + (define-rvc-ca-arith-instruction c.subw #b100111 #b00)) + +(define-instruction c.nop (segment) + (:printer ci + ((funct3 #b000) + (rd/rs1 0) + (imm '(0 0)) + (opcode #b01))) + (:emitter + (%emit-ci-inst segment #b000 0 0 0 #b01))) + +(define-instruction c.ebreak (segment) + (:printer cr + ((funct4 #b1001) + (rd/rs1 0) + (rs2 0) + (opcode #b10))) (:emitter - (emit-header-data segment return-pc-widetag))) + (%emit-cr-inst segment #b1001 0 0 #b10))) diff --git a/src/compiler/riscv/macros.lisp b/src/compiler/riscv/macros.lisp index bb83714fa5..b411453494 100644 --- a/src/compiler/riscv/macros.lisp +++ b/src/compiler/riscv/macros.lisp @@ -93,7 +93,7 @@ (define-tls-accessors load-stepping store-stepping thread-stepping-slot sb-impl::*stepping*)) -;;; TODO: these two macros would benefit from linkage-table space being +;;; TODO: these two macros would benefit from alien-linkage-table space being ;;; located below static space with linkage entries allocated downward ;;; from the end. Then the sequence would reduce to 2 instructions: ;;; lw temp (k)$NULL @@ -119,26 +119,6 @@ byte-ordering issues." `(inst lbu ,target ,source ,offset)) -(defun lisp-jump (function) - "Jump to the lisp function FUNCTION." - (inst jalr zero-tn function (- (ash simple-fun-insts-offset word-shift) - fun-pointer-lowtag))) - -(defun lisp-return (return-pc return-style) - "Return to RETURN-PC." - (ecase return-style - (:single-value (inst li nargs-tn -1)) - (:multiple-values) - (:known)) - ;; Avoid the LRA header word. - (inst jalr zero-tn return-pc (- n-word-bytes other-pointer-lowtag))) - -(defun emit-return-pc (label) - "Emit a return-pc header word. LABEL is the label to use for this return-pc." - (emit-alignment n-lowtag-bits) - (emit-label label) - (inst lra-header-word)) - ;;;; Three Way Comparison (defun three-way-comparison (x y condition flavor not-p target) @@ -271,33 +251,27 @@ and (:policy :fast-safe) (:args (object :scs (descriptor-reg)) (index :scs (any-reg)) - (value :scs ,scs :target result)) + (value :scs ,scs)) (:arg-types ,type tagged-num ,eltype) (:temporary (:scs (interior-reg)) lip) ,@(when fixnum-as-word-index-needs-temp `((:temporary (:sc non-descriptor-reg) temp))) - (:results (result :scs ,scs)) - (:result-types ,eltype) (:generator 3 (with-fixnum-as-word-index (index temp) (inst add lip object index)) - (storew value lip ,offset ,lowtag) - (move result value))) + (storew value lip ,offset ,lowtag))) (define-vop (,(symbolicate name "-C")) ,@(when translate `((:translate ,translate))) (:policy :fast-safe) (:args (object :scs (descriptor-reg)) - (value :scs ,scs :target result)) + (value :scs ,scs)) (:info index) (:arg-types ,type (:constant (load/store-index #.n-word-bytes ,(eval lowtag) ,(eval offset))) ,eltype) - (:results (result :scs ,scs)) - (:result-types ,eltype) (:generator 1 - (storew value object (+ ,offset index) ,lowtag) - (move result value))))) + (storew value object (+ ,offset index) ,lowtag))))) (defmacro define-partial-reffer (name type size signed offset lowtag scs eltype &optional translate) (let ((shift (- (integer-length size) n-fixnum-tag-bits 1))) @@ -353,11 +327,9 @@ and (index :scs (any-reg)) (value :scs ,scs)) (:arg-types ,type positive-fixnum ,eltype) - (:results (result :scs ,scs)) (:temporary (:scs (interior-reg)) lip) ,@(unless (zerop shift) `((:temporary (:sc non-descriptor-reg) temp))) - (:result-types ,eltype) (:generator 5 ,@(cond ((zerop shift) '((inst add lip object index))) @@ -367,25 +339,21 @@ and `(inst slli temp index ,shift)) (inst add lip object temp)))) (inst ,(ecase size (1 'sb) (2 'sh) (4 'sw)) - value lip (- (* ,offset n-word-bytes) ,lowtag)) - (move result value))) + value lip (- (* ,offset n-word-bytes) ,lowtag)))) (define-vop (,(symbolicate name "-C")) ,@(when translate `((:translate ,translate))) (:policy :fast-safe) (:args (object :scs (descriptor-reg)) - (value :scs ,scs :target result)) + (value :scs ,scs)) (:info index) (:arg-types ,type (:constant (load/store-index ,(eval size) ,(eval lowtag) ,(eval offset))) ,eltype) - (:results (result :scs ,scs)) - (:result-types ,eltype) (:generator 4 (inst ,(ecase size (1 'sb) (2 'sh) (4 'sw)) value object - (- (+ (* ,offset n-word-bytes) (* index ,size)) ,lowtag)) - (move result value)))))) + (- (+ (* ,offset n-word-bytes) (* index ,size)) ,lowtag))))))) (defmacro define-float-reffer (name type size format offset lowtag scs eltype &optional arrayp note translate) (let ((shift (if arrayp @@ -427,7 +395,8 @@ and (defmacro define-float-setter (name type size format offset lowtag scs eltype &optional arrayp note translate) (let ((shift (if arrayp (- (integer-length size) n-fixnum-tag-bits 1) - (- word-shift n-fixnum-tag-bits)))) + (- word-shift n-fixnum-tag-bits))) + (resultp nil)) `(progn (define-vop (,name) (:note ,note) @@ -435,13 +404,12 @@ and (:policy :fast-safe) (:args (object :scs (descriptor-reg)) (index :scs (any-reg)) - (value :scs ,scs :target result)) + (value :scs ,scs ,@(when resultp '(:target result)))) (:arg-types ,type tagged-num ,eltype) (:temporary (:scs (interior-reg)) lip) ,@(unless (zerop shift) `((:temporary (:sc non-descriptor-reg) temp))) - (:results (result :scs ,scs)) - (:result-types ,eltype) + ,@(when resultp `((:results (result :scs ,scs)) (:result-types ,eltype))) (:generator 5 ,@(cond ((zerop shift) `((inst add lip object index))) @@ -449,24 +417,23 @@ and `((inst slli temp index ,shift) (inst add lip object temp)))) (inst fstore ,format value lip (- (* ,offset n-word-bytes) ,lowtag)) - (unless (location= result value) - (inst fmove ,format result value)))) + ,@(when resultp + `((unless (location= result value) (inst fmove ,format result value)))))) (define-vop (,(symbolicate name "-C")) (:note ,note) ,@(when translate `((:translate ,translate))) (:policy :fast-safe) (:args (object :scs (descriptor-reg)) - (value :scs ,scs :target result)) + (value :scs ,scs ,@(when resultp '(:target result)))) (:info index) (:arg-types ,type (:constant (load/store-index ,(if arrayp size n-word-bytes) ,(eval lowtag) ,(eval offset))) ,eltype) - (:results (result :scs ,scs)) - (:result-types ,eltype) + ,@(when resultp `((:results (result :scs ,scs)) (:result-types ,eltype))) (:generator 4 (inst fstore ,format value object (- (+ (* ,offset n-word-bytes) (* index ,(if arrayp size n-word-bytes))) ,lowtag)) - (unless (location= result value) - (inst fmove ,format result value))))))) + ,@(when resultp + `((unless (location= result value) (inst fmove ,format result value))))))))) ;; FIXME: constant arg VOPs missing. (defmacro define-complex-float-reffer (name type size format offset lowtag scs eltype &optional arrayp note translate) @@ -505,20 +472,20 @@ and (defmacro define-complex-float-setter (name type size format offset lowtag scs eltype &optional arrayp note translate) (let ((shift (if arrayp (- (integer-length size) n-fixnum-tag-bits) - (- word-shift n-fixnum-tag-bits)))) + (- word-shift n-fixnum-tag-bits))) + (resultp nil)) `(define-vop (,name) (:note ,note) ,@(when translate `((:translate ,translate))) (:policy :fast-safe) (:args (object :scs (descriptor-reg)) (index :scs (any-reg)) - (value :scs ,scs :target result)) + (value :scs ,scs ,@(when resultp '(:target result)))) (:arg-types ,type tagged-num ,eltype) (:temporary (:scs (interior-reg)) lip) ,@(unless (zerop shift) `((:temporary (:sc non-descriptor-reg) temp))) - (:results (result :scs ,scs)) - (:result-types ,eltype) + ,@(when resultp `((:results (result :scs ,scs)) (:result-types ,eltype))) (:generator 6 ,@(cond ((zerop shift) `((inst add lip object index))) @@ -535,7 +502,7 @@ and (inst fstore ,format real-tn lip (- (* ,offset n-word-bytes) ,lowtag))) (let ((imag-tn (complex-reg-imag-tn ,format value))) (inst fstore ,format imag-tn lip (- (+ (* ,offset n-word-bytes) ,size) ,lowtag)))))) - (move-complex ,format result value))))) + ,@(when resultp `((move-complex ,format result value))))))) (defmacro define-full-casser (name type offset lowtag scs eltype &optional translate) `(define-vop (,name) @@ -639,21 +606,21 @@ and (defun load-alloc-free-pointer (reg) #-sb-thread - (loadw reg null-tn 0 (- boxed-region)) + (loadw reg null-tn 0 (- nil-value mixed-region)) #+sb-thread - (loadw reg thread-base-tn thread-alloc-region-slot)) + (loadw reg thread-base-tn thread-mixed-tlab-slot)) (defun load-alloc-end-addr (reg) #-sb-thread - (loadw reg null-tn 1 (- boxed-region)) + (loadw reg null-tn 1 (- nil-value mixed-region)) #+sb-thread - (loadw reg thread-base-tn (+ thread-alloc-region-slot 1))) + (loadw reg thread-base-tn (+ thread-mixed-tlab-slot 1))) (defun store-alloc-free-pointer (reg) #-sb-thread - (storew reg null-tn 0 (- boxed-region)) + (storew reg null-tn 0 (- nil-value mixed-region)) #+sb-thread - (storew reg thread-base-tn thread-alloc-region-slot)) + (storew reg thread-base-tn thread-mixed-tlab-slot)) ;;; This is the main mechanism for allocating memory in the lisp heap. ;;; @@ -672,7 +639,6 @@ and stack-allocate-p temp-tn) (declare (ignorable type)) - #-gencgc (declare (ignore temp-tn)) (cond (stack-allocate-p ;; Stack allocation ;; @@ -692,20 +658,6 @@ and (tn (inst add csp-tn csp-tn size)))) ;; Normal allocation to the heap. - #-gencgc - (t - (load-symbol-value flag-tn *allocation-pointer*) - (inst ori result-tn flag-tn lowtag) - (etypecase size - (short-immediate - (inst addi flag-tn flag-tn size)) - (u+i-immediate - (inst li flag-tn (- size lowtag)) - (inst add flag-tn flag-tn result-tn)) - (tn - (inst add flag-tn flag-tn size))) - (store-symbol-value flag-tn *allocation-pointer*)) - #+gencgc (t (let ((alloc (gen-label)) (back-from-alloc (gen-label))) @@ -734,7 +686,7 @@ and (inst ori result-tn result-tn lowtag))) (assemble (:elsewhere) (emit-label alloc) - (invoke-asm-routine (alloc-tramp-stub-name (tn-offset result-tn) type)) + (inst jal lip-tn (make-fixup (alloc-tramp-stub-name (tn-offset result-tn) type) :assembly-routine)) (inst j back-from-alloc)))))) (defmacro with-fixed-allocation ((result-tn flag-tn type-code size @@ -756,7 +708,6 @@ and :flag-tn ,flag-tn :stack-allocate-p ,stack-allocate-p ,@(when temp-tn `(:temp-tn ,temp-tn))) - (when ,type-code - (inst li ,flag-tn (compute-object-header ,size ,type-code)) - (storew ,flag-tn ,result-tn 0 ,lowtag)) + (inst li ,flag-tn (compute-object-header ,size ,type-code)) + (storew ,flag-tn ,result-tn 0 ,lowtag) ,@body))) diff --git a/src/compiler/riscv/memory.lisp b/src/compiler/riscv/memory.lisp index 3a35625a33..7f308bb693 100644 --- a/src/compiler/riscv/memory.lisp +++ b/src/compiler/riscv/memory.lisp @@ -24,14 +24,14 @@ (define-vop (cell-set) (:args (object :scs (descriptor-reg)) - (value :scs (descriptor-reg any-reg))) + (value :scs (descriptor-reg any-reg zero))) (:variant-vars offset lowtag) (:generator 4 (storew value object offset lowtag))) (define-vop (set-instance-hashed) (:args (object :scs (descriptor-reg))) - (:temporary (:sc non-descriptor-reg) baseptr bit) + (:temporary (:sc non-descriptor-reg) baseptr bit temp) (:generator 5 (inst addi baseptr object (- instance-pointer-lowtag)) (inst li bit (ash 1 stable-hash-required-flag)) diff --git a/src/compiler/riscv/move.lisp b/src/compiler/riscv/move.lisp index 42ff08b813..a54bc5cd89 100644 --- a/src/compiler/riscv/move.lisp +++ b/src/compiler/riscv/move.lisp @@ -12,7 +12,7 @@ (in-package "SB-VM") (define-move-fun (load-immediate 1) (vop x y) - ((immediate) + ((zero immediate) (any-reg descriptor-reg)) (let ((val (tn-value x))) (etypecase val @@ -27,7 +27,7 @@ character-widetag)))))) (define-move-fun (load-number 1) (vop x y) - ((immediate) + ((zero immediate) (signed-reg unsigned-reg)) (inst li y (tn-value x))) @@ -65,7 +65,7 @@ (loadw y (current-nfp-tn vop) (tn-offset x))) (define-move-fun (store-stack 5) (vop x y) - ((any-reg descriptor-reg) (control-stack)) + ((any-reg descriptor-reg zero) (control-stack)) (store-stack-tn y x)) (define-move-fun (store-number-stack 5) (vop x y) @@ -74,31 +74,26 @@ (signed-reg) (signed-stack) (unsigned-reg) (unsigned-stack)) (storew x (current-nfp-tn vop) (tn-offset y))) - + ;;;; The Move VOP: ;;; (define-vop (move) (:args (x :target y - :scs (any-reg descriptor-reg) - :load-if (not (or (location= x y) - (and (sc-is x immediate) - (eql (tn-value x) 0)))))) + :scs (any-reg zero descriptor-reg) + :load-if (not (location= x y)))) (:results (y :scs (any-reg descriptor-reg control-stack) :load-if (not (location= x y)))) (:generator 0 - (let ((x (if (and (sc-is x immediate) - (eql (tn-value x) 0)) - zero-tn - x))) - (cond ((location= x y)) - ((sc-is y control-stack) - (store-stack-tn y x)) - (t - (move y x)))))) + (unless (location= x y) + (sc-case y + ((any-reg descriptor-reg) + (move y x)) + (control-stack + (store-stack-tn y x)))))) (define-move-vop move :move - (any-reg descriptor-reg) + (any-reg descriptor-reg zero) (any-reg descriptor-reg)) @@ -107,7 +102,7 @@ ;;; (define-vop (move-arg) (:args (x :target y - :scs (any-reg descriptor-reg)) + :scs (any-reg descriptor-reg zero)) (fp :scs (any-reg) :load-if (not (sc-is y any-reg descriptor-reg)))) (:results (y)) @@ -119,7 +114,7 @@ (storew x fp (tn-offset y)))))) ;;; (define-move-vop move-arg :move-arg - (any-reg descriptor-reg) + (any-reg descriptor-reg zero) (any-reg descriptor-reg)) ;;;; Moves and coercions: @@ -232,10 +227,10 @@ DONE)) (define-vop (move-from-fixnum+1 move-from-fixnum+/-1) - (:variant (1+ sb-xc:most-positive-fixnum))) + (:variant (1+ most-positive-fixnum))) (define-vop (move-from-fixnum-1 move-from-fixnum+/-1) - (:variant (1- sb-xc:most-negative-fixnum))) + (:variant (1- most-negative-fixnum))) ;;; Check for fixnum, and possibly allocate one or two word bignum ;;; result. Use a worst-case cost to make sure people know they may diff --git a/src/compiler/riscv/nlx.lisp b/src/compiler/riscv/nlx.lisp index bdb54ae918..87bf6f5c15 100644 --- a/src/compiler/riscv/nlx.lisp +++ b/src/compiler/riscv/nlx.lisp @@ -86,7 +86,7 @@ (storew temp block unwind-block-uwp-slot) (storew cfp-tn block unwind-block-cfp-slot) (storew code-tn block unwind-block-code-slot) - (inst compute-lra temp lip entry-label code-tn) + (inst compute-ra-from-code temp code-tn lip entry-label) (storew temp block catch-block-entry-pc-slot))) ;;; Like Make-Unwind-Block, except that we also store in the specified tag, and @@ -105,7 +105,7 @@ (storew temp result catch-block-uwp-slot) (storew cfp-tn result catch-block-cfp-slot) (storew code-tn result catch-block-code-slot) - (inst compute-lra temp lip entry-label code-tn) + (inst compute-ra-from-code temp code-tn lip entry-label) (storew temp result catch-block-entry-pc-slot) (storew tag result catch-block-tag-slot) @@ -155,7 +155,7 @@ (:save-p :force-to-stack) (:vop-var vop) (:generator 30 - (emit-return-pc label) + (emit-label label) (note-this-location vop :non-local-entry) (cond ((zerop nvals)) ((= nvals 1) @@ -186,6 +186,19 @@ (store-stack-tn tn move-temp)))))))) (load-stack-tn csp-tn sp))) +(define-vop (nlx-entry-single) + (:args (sp) + (value)) + (:results (res :from :load)) + (:info label) + (:save-p :force-to-stack) + (:vop-var vop) + (:generator 30 + (emit-label label) + (note-this-location vop :non-local-entry) + (move res value) + (load-stack-tn csp-tn sp))) + (define-vop (nlx-entry-multiple) (:args (top :target result) (src) @@ -203,7 +216,7 @@ (:save-p :force-to-stack) (:vop-var vop) (:generator 30 - (emit-return-pc label) + (emit-label label) (note-this-location vop :non-local-entry) (let ((loop (gen-label)) @@ -237,5 +250,5 @@ (:ignore block start count) (:vop-var vop) (:generator 0 - (emit-return-pc label) + (emit-label label) (note-this-location vop :non-local-entry))) diff --git a/src/compiler/riscv/parms.lisp b/src/compiler/riscv/parms.lisp index dd1f3a7da5..1f20b28c7a 100644 --- a/src/compiler/riscv/parms.lisp +++ b/src/compiler/riscv/parms.lisp @@ -23,7 +23,7 @@ ;;; The size in bytes of GENCGC cards, i.e. the granularity at which ;;; writes to old generations are logged. With mprotect-based write ;;; barriers, this must be a multiple of the OS page size. -(defconstant gencgc-card-bytes +backend-page-bytes+) +(defconstant gencgc-page-bytes +backend-page-bytes+) ;;; The minimum size of new allocation regions. While it doesn't ;;; currently make a lot of sense to have a card size lower than ;;; the alloc granularity, it will, once we are smarter about finding @@ -40,34 +40,6 @@ ;;; address space) (defconstant n-machine-word-bits #-64-bit 32 #+64-bit 64) -;;; Floating-point related constants, both format descriptions and FPU -;;; control register descriptions. These don't exactly match up with -;;; what the machine manuals say because the Common Lisp standard -;;; defines floating-point values somewhat differently than the IEEE -;;; standard does. - -(defconstant float-sign-shift 31) - -(defconstant single-float-bias 126) -(defconstant-eqx single-float-exponent-byte (byte 8 23) #'equalp) -(defconstant-eqx single-float-significand-byte (byte 23 0) #'equalp) -(defconstant single-float-normal-exponent-min 1) -(defconstant single-float-normal-exponent-max 254) -(defconstant single-float-hidden-bit (ash 1 23)) - -(defconstant double-float-bias 1022) -(defconstant-eqx double-float-exponent-byte (byte 11 20) #'equalp) -(defconstant-eqx double-float-significand-byte (byte 20 0) #'equalp) -(defconstant double-float-normal-exponent-min 1) -(defconstant double-float-normal-exponent-max #x7FE) -(defconstant double-float-hidden-bit (ash 1 20)) - -(defconstant single-float-digits - (+ (byte-size single-float-significand-byte) 1)) - -(defconstant double-float-digits - (+ (byte-size double-float-significand-byte) 32 1)) - (defconstant float-inexact-trap-bit (ash 1 0)) (defconstant float-underflow-trap-bit (ash 1 1)) (defconstant float-overflow-trap-bit (ash 1 2)) @@ -89,32 +61,13 @@ ;;;; Where to put the different spaces. -;;; On non-gencgc we need large dynamic and static spaces for PURIFY -#-gencgc -(progn - (defconstant read-only-space-start #x04000000) - (defconstant read-only-space-end #x07ff8000) - (defconstant static-space-start #x08000000) - (defconstant static-space-end #x097fff00) - - (defconstant linkage-table-space-start #x0a000000) - (defconstant linkage-table-space-end #x0b000000)) - -;;; While on gencgc we don't. -#+gencgc (!gencgc-space-setup #x04000000 :dynamic-space-start #x4f000000) -(defconstant linkage-table-entry-size #-64-bit 4 #+64-bit 8) ; N-WORD-BYTES (not defined yet) -(defconstant linkage-table-growth-direction :down) -(setq *linkage-space-predefined-entries* '(#+gencgc("alloc" nil) - #+gencgc("alloc_list" nil))) - -#+(or linux netbsd) -(progn - #-gencgc - (progn - (defparameter dynamic-0-space-start #x4f000000) - (defparameter dynamic-0-space-end #x66fff000))) +(defconstant alien-linkage-table-entry-size #-64-bit 8 #+64-bit 24) +(defconstant alien-linkage-table-growth-direction :down) +(setq *linkage-space-predefined-entries* '(("alloc" nil) + ("alloc_list" nil))) + ;;;; other miscellaneous constants @@ -145,7 +98,6 @@ ;;; (defconstant-eqx +static-symbols+ `#(,@+common-static-symbols+ - *allocation-pointer* #-sb-thread ,@'(*binding-stack-pointer* ;; interrupt handling diff --git a/src/compiler/riscv/pred.lisp b/src/compiler/riscv/pred.lisp index 1471675901..bb26478367 100644 --- a/src/compiler/riscv/pred.lisp +++ b/src/compiler/riscv/pred.lisp @@ -39,8 +39,8 @@ ;;;; Conditional VOPs: (define-vop (if-eq) - (:args (x :scs (any-reg descriptor-reg)) - (y :scs (any-reg descriptor-reg))) + (:args (x :scs (any-reg descriptor-reg zero)) + (y :scs (any-reg descriptor-reg zero))) (:conditional) (:info target not-p) (:policy :fast-safe) diff --git a/src/compiler/riscv/sap.lisp b/src/compiler/riscv/sap.lisp index 5a580dff7f..c1af03a5fd 100644 --- a/src/compiler/riscv/sap.lisp +++ b/src/compiler/riscv/sap.lisp @@ -159,33 +159,25 @@ (:double (inst fload :double result sap offset)))) -(defun sap-set (result value sap offset size) +(defun sap-set (value sap offset size) (ecase size (:byte - (inst sb value sap offset) - (move result value)) + (inst sb value sap offset)) (:short - (inst sh value sap offset) - (move result value)) + (inst sh value sap offset)) (:word - (inst sw value sap offset) - (move result value)) + (inst sw value sap offset)) #+64-bit (:dword - (inst sd value sap offset) - (move result value)) + (inst sd value sap offset)) (:single - (inst fstore :single result sap offset) - (inst fmove :single result value)) + (inst fstore :single value sap offset)) (:double - (inst fstore :double result sap offset) - (inst fmove :double result value)))) + (inst fstore :double value sap offset)))) (macrolet ((def-system-ref-and-set (ref-name set-name sc type size &key signed) - (let ((ref-name-c (symbolicate ref-name "-C")) - (set-name-c (symbolicate set-name "-C"))) - `(progn + `(progn (define-vop (,ref-name) (:translate ,ref-name) (:policy :fast-safe) @@ -198,7 +190,7 @@ (:generator 5 (inst add sap object offset) (sap-ref result sap 0 ,signed ,size))) - (define-vop (,ref-name-c) + (define-vop (,(symbolicate ref-name "-C")) (:translate ,ref-name) (:policy :fast-safe) (:args (sap :scs (sap-reg))) @@ -212,29 +204,24 @@ (define-vop (,set-name) (:translate ,set-name) (:policy :fast-safe) - (:args (object :scs (sap-reg) :target sap) - (offset :scs (signed-reg)) - (value :scs (,sc) :target result)) - (:arg-types system-area-pointer signed-num ,type) - (:results (result :scs (,sc))) - (:result-types ,type) - (:temporary (:scs (sap-reg) :from (:argument 0)) sap) + ;; this is untested, but it matches the MIPS vop + (:args (value :scs (,sc) :to :eval) ; VALUE has to conflict with SAP + (object :scs (sap-reg) :target sap) + (offset :scs (signed-reg))) + (:arg-types ,type system-area-pointer signed-num) + (:temporary (:scs (sap-reg) :from (:argument 1)) sap) (:generator 5 (inst add sap object offset) - (sap-set result value sap 0 ,size))) - (define-vop (,set-name-c) + (sap-set value sap 0 ,size))) + (define-vop (,(symbolicate set-name "-C")) (:translate ,set-name) (:policy :fast-safe) - (:args (sap :scs (sap-reg)) - (value :scs (,sc) :target result)) - (:arg-types system-area-pointer - (:constant short-immediate) - ,type) + (:args (value :scs (,sc)) + (sap :scs (sap-reg))) + (:arg-types ,type system-area-pointer (:constant short-immediate)) (:info offset) - (:results (result :scs (,sc))) - (:result-types ,type) (:generator 4 - (sap-set result value sap offset ,size))))))) + (sap-set value sap offset ,size)))))) (def-system-ref-and-set sap-ref-8 %set-sap-ref-8 unsigned-reg positive-fixnum :byte :signed nil) (def-system-ref-and-set signed-sap-ref-8 %set-signed-sap-ref-8 diff --git a/src/compiler/riscv/show.lisp b/src/compiler/riscv/show.lisp index f6b26436b0..0f84cc7539 100644 --- a/src/compiler/riscv/show.lisp +++ b/src/compiler/riscv/show.lisp @@ -26,7 +26,7 @@ (store-stack-tn nfp-save cur-nfp)) (move ca0 object) (inst li cfunc (make-fixup "debug_print" :foreign)) - (invoke-asm-routine 'call-into-c) + (inst jal ra-tn (make-fixup 'call-into-c :assembly-routine)) (when cur-nfp (load-stack-tn cur-nfp nfp-save)) (move result ca0)))) diff --git a/src/compiler/riscv/system.lisp b/src/compiler/riscv/system.lisp index e4df180659..9bb7abf607 100644 --- a/src/compiler/riscv/system.lisp +++ b/src/compiler/riscv/system.lisp @@ -53,6 +53,26 @@ (load-type result lip) DONE)) +(define-vop () + (:translate sb-c::%structure-is-a) + (:args (x :scs (descriptor-reg))) + (:arg-types * (:constant t)) + (:policy :fast-safe) + (:conditional) + ;; "extra" info in conditional vops follows the 2 super-magical info args + (:info target not-p test-layout) + (:temporary (:sc unsigned-reg) this-id temp) + (:generator 4 + (let ((offset (+ (id-bits-offset) + (ash (- (wrapper-depthoid test-layout) 2) 2) + (- instance-pointer-lowtag)))) + (inst lw this-id x offset) + (if (or (typep (layout-id test-layout) '(and (signed-byte 8) (not (eql 0)))) + (not (sb-c::producing-fasl-file))) + (inst li temp (layout-id test-layout)) + (inst load-layout-id temp test-layout)) + (inst* (if not-p 'bne 'beq) this-id temp target)))) + #+64-bit (define-vop (layout-depthoid) (:translate layout-depthoid) @@ -77,8 +97,8 @@ (:generator 6 (load-type result object (- other-pointer-lowtag)))) -(define-vop (fun-subtype) - (:translate fun-subtype) +(define-vop () + (:translate %fun-pointer-widetag) (:policy :fast-safe) (:args (function :scs (descriptor-reg))) (:results (result :scs (unsigned-reg))) @@ -99,10 +119,9 @@ (define-vop (set-header-data) (:translate set-header-data) (:policy :fast-safe) - (:args (x :scs (descriptor-reg) :target res) - (data :scs (any-reg immediate))) + (:args (x :scs (descriptor-reg)) + (data :scs (any-reg immediate zero))) (:arg-types * positive-fixnum) - (:results (res :scs (descriptor-reg))) (:temporary (:scs (non-descriptor-reg)) t1 t2) (:generator 6 (load-type t1 x (- other-pointer-lowtag)) @@ -116,9 +135,9 @@ (inst ori t1 t1 val)) (t (inst li t2 val) - (inst or t1 t1 t2)))))) - (storew t1 x 0 other-pointer-lowtag) - (move res x))) + (inst or t1 t1 t2))))) + (zero)) + (storew t1 x 0 other-pointer-lowtag))) (define-vop (pointer-hash) (:translate pointer-hash) @@ -131,14 +150,6 @@ ;;;; Allocation -(define-vop (dynamic-space-free-pointer) - (:results (int :scs (sap-reg))) - (:result-types system-area-pointer) - (:translate dynamic-space-free-pointer) - (:policy :fast-safe) - (:generator 1 - (load-symbol-value int *allocation-pointer*))) - (define-vop (binding-stack-pointer-sap) (:results (int :scs (sap-reg))) (:result-types system-area-pointer) @@ -214,38 +225,6 @@ (inst add ndescr ndescr offset) (inst subi ndescr ndescr (- other-pointer-lowtag fun-pointer-lowtag)) (inst add func code ndescr))) -;;; -(define-vop (symbol-info-vector) - (:policy :fast-safe) - (:translate symbol-info-vector) - (:args (x :scs (descriptor-reg))) - (:results (res :scs (descriptor-reg))) - (:temporary (:sc unsigned-reg) temp) - (:generator 1 - (loadw res x symbol-info-slot other-pointer-lowtag) - ;; If RES has list-pointer-lowtag, take its CDR. If not, use it as-is. - (inst andi temp res lowtag-mask) - (inst xori temp temp list-pointer-lowtag) - (inst bne temp zero-tn not-equal) - (loadw res res cons-cdr-slot list-pointer-lowtag) - NOT-EQUAL)) - -(define-vop (symbol-plist) - (:policy :fast-safe) - (:translate symbol-plist) - (:args (x :scs (descriptor-reg))) - (:results (res :scs (descriptor-reg))) - (:temporary (:sc non-descriptor-reg) temp) - (:generator 1 - (loadw res x symbol-info-slot other-pointer-lowtag) - ;; Instruction pun: (CAR x) is the same as (VECTOR-LENGTH x) - ;; so if the info slot holds a vector, this gets a fixnum- it's not a plist. - (loadw res res cons-car-slot list-pointer-lowtag) - (inst andi temp res fixnum-tag-mask) - (inst bne temp zero-tn not-equal) - (move res null-tn) - NOT-EQUAL)) - ;;;; Other random VOPs. @@ -321,3 +300,10 @@ (:policy :fast-safe) (:translate %data-dependency-barrier) (:generator 3)) + +(define-vop (sb-c::mark-covered) + (:info index) + (:generator 4 + ;; Can't convert index to a code-relative index until the boxed header length + ;; has been determined. + (inst store-coverage-mark index))) diff --git a/src/compiler/riscv/target-insts.lisp b/src/compiler/riscv/target-insts.lisp index 71b0b92cad..59a453b395 100644 --- a/src/compiler/riscv/target-insts.lisp +++ b/src/compiler/riscv/target-insts.lisp @@ -40,9 +40,8 @@ function addresses and register values.") #'equalp) (defconstant-eqx riscv-reg-symbols - (coerce - (loop for n from 0 to 31 collect (make-symbol (format nil "x~d" n))) - 'vector) + (coerce (loop for n from 0 to 31 collect (make-symbol (format nil "x~d" n))) + 'vector) #'equalp) (defun print-reg (value stream dstate) @@ -75,9 +74,8 @@ function addresses and register values.") (coerce-signed u-imm 12)))) (defconstant-eqx float-reg-symbols - (coerce - (loop for n from 0 to 31 collect (make-symbol (format nil "ft~d" n))) - 'vector) + (coerce (loop for n from 0 to 31 collect (make-symbol (format nil "ft~d" n))) + 'vector) #'equalp) (defun print-fp-reg (value stream dstate) @@ -176,9 +174,8 @@ function addresses and register values.") (#.sb-vm::thread-offset (let* ((thread-slots (load-time-value - (primitive-object-slots - (find 'sb-vm::thread *primitive-objects* - :key #'primitive-object-name)) t)) + (primitive-object-slots (sb-vm::primitive-object 'sb-vm::thread)) + t)) (slot (find (ash offset (- word-shift)) thread-slots :key #'slot-offset))) (when slot @@ -208,6 +205,34 @@ function addresses and register values.") (destructuring-bind (rs i-imm) value (maybe-note-assembler-routine (maybe-augment rs i-imm) t dstate))) +;;;; printers for RISC-V C extension + +(defun print-rvc-reg (value stream dstate) + (declare (stream stream) (fixnum value)) + (print-reg (+ value 8) stream dstate)) + +(macrolet ((define-rvc-imm-printer (name) + `(defun ,name (value stream dstate) + (declare (stream stream) (ignore value stream dstate)) + (error "Not written yet")))) + (define-rvc-imm-printer print-ci-imm) + (define-rvc-imm-printer print-ci-load-32-imm) + (define-rvc-imm-printer print-ci-load-64-imm) + (define-rvc-imm-printer print-css-32-imm) + (define-rvc-imm-printer print-css-64-imm) + (define-rvc-imm-printer print-ciw-imm) + (define-rvc-imm-printer print-cl/cs-32-imm) + (define-rvc-imm-printer print-cl/cs-64-imm) + (define-rvc-imm-printer print-cb-arith-imm)) + +(defun use-cb-label (value dstate) + (declare (type disassem-state dstate) (ignore value dstate)) + (error "Not written yet")) + +(defun use-cj-label (value dstate) + (declare (type disassem-state dstate) (ignore value dstate)) + (error "Not written yet")) + ;;;; interrupt instructions (defun break-control (chunk inst stream dstate) diff --git a/src/compiler/riscv/type-vops.lisp b/src/compiler/riscv/type-vops.lisp index 2dd37d813e..58b85481c5 100644 --- a/src/compiler/riscv/type-vops.lisp +++ b/src/compiler/riscv/type-vops.lisp @@ -134,7 +134,7 @@ (define-vop (#-64-bit signed-byte-32-p #+64-bit signed-byte-64-p type-predicate) (:translate #-64-bit signed-byte-32-p #+64-bit signed-byte-64-p) - (:generator 45 + (:generator 10 (let ((not-target (gen-label))) (signed-byte-n-word-bits-test value temp not-p target not-target) (emit-label not-target)))) @@ -145,7 +145,7 @@ (define-vop (#-64-bit unsigned-byte-32-p #+64-bit unsigned-byte-64-p type-predicate) (:translate #-64-bit unsigned-byte-32-p #+64-bit unsigned-byte-64-p) (:temporary (:scs (non-descriptor-reg)) temp1) - (:generator 45 + (:generator 10 (let ((not-target (gen-label))) (multiple-value-bind (yep nope) (if not-p diff --git a/src/compiler/riscv/values.lisp b/src/compiler/riscv/values.lisp index 659cb8dbdc..eb6132f460 100644 --- a/src/compiler/riscv/values.lisp +++ b/src/compiler/riscv/values.lisp @@ -57,7 +57,7 @@ ;;; operand, but this seems unworthwhile. ;;; (define-vop (push-values) - (:args (vals :more t)) + (:args (vals :more t :scs (descriptor-reg any-reg control-stack))) (:results (start :scs (any-reg) :from :load) (count :scs (any-reg))) (:info nvals) @@ -71,7 +71,7 @@ ((null val)) (let ((tn (tn-ref-tn val))) (sc-case tn - (descriptor-reg + ((descriptor-reg any-reg) (storew tn start i)) (control-stack (load-stack-tn temp tn) @@ -113,21 +113,15 @@ ;;; as function arguments. (define-vop (%more-arg-values) (:args (context :scs (descriptor-reg any-reg) :target src) - (skip :scs (any-reg immediate)) (num :scs (any-reg) :target count)) - (:arg-types * positive-fixnum positive-fixnum) + (:arg-types * positive-fixnum) (:temporary (:sc any-reg :from (:argument 0)) src) (:temporary (:sc any-reg :from (:argument 2)) dst) (:temporary (:sc descriptor-reg) temp) (:results (start :scs (any-reg)) (count :scs (any-reg))) (:generator 20 - (sc-case skip - (immediate - (inst addi src context (* (tn-value skip) n-word-bytes))) - (any-reg - (with-fixnum-as-word-index (skip temp) - (inst add src context skip)))) + (move src context) (move count num) (move start csp-tn) (inst beq count zero-tn done) diff --git a/src/compiler/riscv/vm.lisp b/src/compiler/riscv/vm.lisp index b29cbf4972..aa8f9e15a9 100644 --- a/src/compiler/riscv/vm.lisp +++ b/src/compiler/riscv/vm.lisp @@ -10,7 +10,22 @@ ;;;; files for more information. (in-package "SB-VM") - + +(defconstant-eqx +fixup-kinds+ #(:absolute :i-type :s-type :u-type :u+i-type) #'equalp) + +(defun u-and-i-inst-immediate (value) + (let ((hi (ash (+ value (expt 2 11)) -12))) + (values hi (- value (ash hi 12))))) + +(def!type short-immediate () `(signed-byte 12)) +(def!type short-immediate-fixnum () `(signed-byte ,(- 12 n-fixnum-tag-bits))) + +(deftype u+i-immediate () + #-64-bit `(or (signed-byte 32) (unsigned-byte 32)) + #+64-bit `(or (integer #x-80000800 #x7ffff7ff) + (integer ,(+ (ash 1 64) #x-80000800) + ,(1- (ash 1 64))))) + (eval-when (:compile-toplevel :load-toplevel :execute) (defvar *register-names* (make-array 32 :initial-element nil))) @@ -30,11 +45,11 @@ (defconstant register-arg-count ,(length args))))) ; ABI register mnemonic (defreg zero 0) ; zero - (defreg lip 1) ; ra + (defreg ra 1) ; ra (defreg nsp 2) ; sp (defreg global 3) ; gp (defreg tp 4) ; tp - (defreg lra 5) ; t0, alternate link register + (defreg lip 5) ; t0, alternate link register (defreg cfp 6) ; t1 (defreg ocfp 7) ; t2 (defreg nfp 8) ; s0, callee-saved @@ -64,19 +79,19 @@ (defreg code 30) ; t5 (defreg nargs 31) ; t6 - (defregset non-descriptor-regs nl0 nl1 nl2 nl3 nl4 nl5 nl6 nl7 nargs nfp cfunc) - (defregset descriptor-regs a0 a1 a2 a3 a4 a5 l0 l1 #-sb-thread l2 ocfp lra lexenv) + (defregset non-descriptor-regs nl0 nl1 nl2 ra nl3 nl4 nl5 nl6 nl7 nargs nfp cfunc) + (defregset descriptor-regs a0 a1 a2 a3 a4 a5 l0 l1 #-sb-thread l2 ocfp lexenv) (defregset reserve-descriptor-regs lexenv) (defregset reserve-non-descriptor-regs cfunc) (defregset boxed-regs a0 a1 a2 a3 a4 a5 l0 l1 #-sb-thread l2 #+sb-thread thread - ocfp lra lexenv code) + ocfp lexenv code) (define-argument-register-set a0 a1 a2 a3 a4 a5)) (!define-storage-bases (define-storage-base registers :finite :size 32) - (define-storage-base control-stack :unbounded :size 8) + (define-storage-base control-stack :unbounded :size 0) (define-storage-base non-descriptor-stack :unbounded :size 0) (define-storage-base float-registers :finite :size 32) @@ -86,7 +101,12 @@ ) (!define-storage-classes + + ;; Non-immediate constants in the constant pool (constant constant) + + ;; Immediate constant. + (zero immediate-constant) (immediate immediate-constant) (control-stack control-stack) @@ -95,7 +115,7 @@ :reserve-locations #.(append reserve-non-descriptor-regs reserve-descriptor-regs) :alternate-scs (control-stack) - :constant-scs (immediate constant) + :constant-scs (immediate zero constant) :save-p t) ;; Pointer descriptor objects. Must be seen by GC. @@ -134,7 +154,7 @@ :locations #.non-descriptor-regs :reserve-locations #.reserve-non-descriptor-regs :alternate-scs (signed-stack) - :constant-scs (immediate) + :constant-scs (zero immediate) :save-p t) (unsigned-stack non-descriptor-stack) (unsigned-reg registers @@ -185,37 +205,53 @@ :sc (sc-or-lose ',sc) :offset ,offset-sym))))) (defregtn zero any-reg) - (defregtn nargs any-reg) - - (defregtn nfp any-reg) - (defregtn ocfp any-reg) - + (defregtn lip interior-reg) + (defregtn code descriptor-reg) (defregtn null descriptor-reg) + + (defregtn nargs any-reg) (defregtn lexenv descriptor-reg) - (defregtn cfp any-reg) (defregtn csp any-reg) + (defregtn cfp any-reg) + (defregtn nsp any-reg) + (defregtn ocfp any-reg) + (defregtn nfp any-reg) - (defregtn code descriptor-reg) - (defregtn lip interior-reg)) + (defregtn ra any-reg)) ;;; If VALUE can be represented as an immediate constant, then return the ;;; appropriate SC number, otherwise return NIL. (defun immediate-constant-sc (value) (typecase value + ((integer 0 0) + zero-sc-number) (null (values descriptor-reg-sc-number null-offset)) - ((or (integer #.sb-xc:most-negative-fixnum #.sb-xc:most-positive-fixnum) - character) - immediate-sc-number) (symbol (if (static-symbol-p value) immediate-sc-number - nil)))) + nil)) + ((integer #.most-negative-fixnum #.most-positive-fixnum) + ;; KLUDGE: This is a subset on 64-bit because we currently + ;; produce untagged intermediates in %LI. + (typecase (fixnumize value) + #-64-bit + ((signed-byte 32) + immediate-sc-number) + #+64-bit + ((integer #x-80000800 #x7ffff7ff) + immediate-sc-number))) + #-sb-xc-host ; There is no such object type in the host + (system-area-pointer + immediate-sc-number) + (character + immediate-sc-number))) (defun boxed-immediate-sc-p (sc) - (eql sc immediate-sc-number)) + (or (eql sc zero-sc-number) + (eql sc immediate-sc-number))) ;;;; Function Call Parameters @@ -226,7 +262,7 @@ ;;; Offsets of special stack frame locations (defconstant ocfp-save-offset 0) -(defconstant lra-save-offset 1) +(defconstant ra-save-offset 1) (defconstant nfp-save-offset 2) (defparameter *register-arg-tns* @@ -244,15 +280,17 @@ ;;; addresses. (defconstant single-value-return-byte-offset 0) +;;; This function is called by debug output routines that want a pretty name +;;; for a TN's location. It returns a thing that can be printed with PRINC. (defun location-print-name (tn) (declare (type tn tn)) (let ((sb (sb-name (sc-sb (tn-sc tn)))) (offset (tn-offset tn))) (ecase sb (registers (or (svref *register-names* offset) - (format nil "x~D" offset))) + (format nil "R~D" offset))) + (float-registers (format nil "F~D" offset)) (control-stack (format nil "CS~D" offset)) - (float-registers (format nil "f~D" offset)) (non-descriptor-stack (format nil "NS~D" offset)) (constant (format nil "Const~D" offset)) (immediate-constant "Immed")))) @@ -269,6 +307,3 @@ (progn (defconstant pseudo-atomic-flag (ash list-pointer-lowtag 0)) (defconstant pseudo-atomic-interrupted-flag (ash list-pointer-lowtag 16))) - -#-sb-thread -(defconstant boxed-region (- (+ static-space-start (* 2 n-word-bytes)) nil-value)) diff --git a/src/compiler/saptran.lisp b/src/compiler/saptran.lisp index 0eae26af43..b070587f5a 100644 --- a/src/compiler/saptran.lisp +++ b/src/compiler/saptran.lisp @@ -13,7 +13,6 @@ ;;;; DEFKNOWNs -#+linkage-table (deftransform foreign-symbol-address ((symbol &optional datap) ((constant-arg simple-string) &optional (constant-arg boolean))) @@ -23,12 +22,7 @@ (deftransform foreign-symbol-sap ((symbol &optional datap) (simple-string &optional boolean)) - #-linkage-table - (if (null datap) - (give-up-ir1-transform) - `(foreign-symbol-sap symbol)) - #+linkage-table - (if (and (constant-lvar-p symbol) (constant-lvar-p datap)) + (if (and (constant-lvar-p symbol) (and datap (constant-lvar-p datap))) (if (lvar-value datap) `(foreign-symbol-dataref-sap symbol) `(foreign-symbol-sap symbol)) @@ -49,38 +43,63 @@ (defknown int-sap ((unsigned-byte #.sb-vm:n-machine-word-bits)) system-area-pointer (movable)) -;;; FIXME: presumably the x86-64 backend could benefit from the -WITH-OFFSET -;;; transforms. Perhaps measure to find out whether the transform ever fires. -(macrolet ((defsapref (fun value-type) - (let (#+x86 - (with-offset-fun (intern (format nil "~A-WITH-OFFSET" fun))) - (set-fun (intern (format nil "%SET-~A" fun))) - #+x86 - (set-with-offset-fun (intern (format nil "%SET-~A-WITH-OFFSET" fun)))) - `(progn - (defknown ,fun (system-area-pointer fixnum) ,value-type - (flushable)) - #+x86 - (defknown ,with-offset-fun (system-area-pointer fixnum fixnum) ,value-type +(macrolet ((defsapref (fun value-type + &aux (setter (symbolicate "%SET-" fun)) + (setter-translatable + (unless (member fun #-64-bit '(sap-ref-64 signed-sap-ref-64) + #+64-bit nil) + '(always-translatable)))) + `(progn + ;; Callable definitions of these are are defined in src/code/stubs + (defknown ,fun (system-area-pointer fixnum) ,value-type (flushable always-translatable)) - (defknown ,set-fun (system-area-pointer fixnum ,value-type) ,value-type - ()) - #+x86 - (defknown ,set-with-offset-fun (system-area-pointer fixnum fixnum ,value-type) ,value-type - (always-translatable)))))) - (defsapref sap-ref-8 (unsigned-byte 8)) - (defsapref sap-ref-16 (unsigned-byte 16)) - (defsapref sap-ref-32 (unsigned-byte 32)) - (defsapref sap-ref-64 (unsigned-byte 64)) - (defsapref signed-sap-ref-8 (signed-byte 8)) - (defsapref signed-sap-ref-16 (signed-byte 16)) - (defsapref signed-sap-ref-32 (signed-byte 32)) - (defsapref signed-sap-ref-64 (signed-byte 64)) - (defsapref sap-ref-sap system-area-pointer) - (defsapref sap-ref-lispobj t) - (defsapref sap-ref-single single-float) - (defsapref sap-ref-double double-float) - (defsapref sap-ref-long long-float) + (defknown (setf ,fun) (,value-type system-area-pointer fixnum) + ,value-type ()) + (defknown ,setter (,value-type system-area-pointer fixnum) (values) + (,@setter-translatable)) + ;; word-sized integers can be treated as signed or unsigned for CAS, + ;; but sub-word will require an explicit sign-extension step, + ;; either in the vop or in Lisp. + ,@(when (member fun '(sap-ref-8 sap-ref-16 + sap-ref-32 #-64-bit signed-sap-ref-32 + #+64-bit sap-ref-64 + #+64-bit signed-sap-ref-64 + sap-ref-sap sap-ref-lispobj)) + `((defknown (cas ,fun) (,value-type ,value-type system-area-pointer fixnum) + ,value-type (always-translatable)))) + ,@(when setter-translatable + ;; Unlike macros, source-transforms work on (funcall #'(setf name) ...) + ;; If this is a 64-bit sizes on a 32-bit machines, + ;; then the source-transform is defined at the end of this file. + `((define-source-transform (setf ,fun) (value sap offset) + `(let ((result ,value)) + (,',setter result ,sap ,offset) ; vop-translated + result)))) + ;; FIXME: I think these transform are the opposite of good. + ;; They can take arithmetic which is perfectly well-defined in the + ;; pointer domain (modular addition on unsigned words), + ;; and potentially turn it into a call to GENERIC+. + (deftransform ,fun ((sap offset)) + (splice-fun-args sap 'sap+ 2) + `(lambda (sap offset1 offset2) + (,',fun sap (+ offset1 offset2)))) + (deftransform ,setter ((value sap offset)) + (splice-fun-args sap 'sap+ 2) + `(lambda (value sap offset1 offset2) + (,',setter value sap (+ offset1 offset2))))))) + (defsapref sap-ref-8 (unsigned-byte 8)) + (defsapref signed-sap-ref-8 (signed-byte 8)) + (defsapref sap-ref-16 (unsigned-byte 16)) + (defsapref signed-sap-ref-16 (signed-byte 16)) + (defsapref sap-ref-32 (unsigned-byte 32)) + (defsapref signed-sap-ref-32 (signed-byte 32)) + (defsapref sap-ref-64 (unsigned-byte 64)) + (defsapref signed-sap-ref-64 (signed-byte 64)) + (defsapref sap-ref-sap system-area-pointer) + (defsapref sap-ref-lispobj t) + (defsapref sap-ref-single single-float) + (defsapref sap-ref-double double-float) + (defsapref sap-ref-long long-float) ; actually DOUBLE-FLOAT ) ; MACROLET @@ -106,80 +125,23 @@ '(lambda (sap offset1 offset2) (sap+ sap (+ offset1 offset2)))))) -(macrolet ((def (fun &optional setp value-type) - (declare (ignorable value-type)) - `(progn - (deftransform ,fun ((sap offset ,@(when setp `(new-value))) * *) - (splice-fun-args sap 'sap+ 2) - `(lambda (sap offset1 offset2 ,@',(when setp `(new-value))) - (,',fun sap (+ offset1 offset2) ,@',(when setp `(new-value))))) - ;; Avoid defining WITH-OFFSET transforms for accessors whose - ;; sizes are larger than the word size; they'd probably be - ;; pointless to optimize anyway and tricky to boot. - ,(unless (and (listp value-type) - (or (eq (first value-type) 'unsigned-byte) - (eq (first value-type) 'signed-byte)) - (> (second value-type) sb-vm:n-word-bits)) - #+x86 - (let ((with-offset-fun (intern (format nil "~A-WITH-OFFSET" fun)))) - `(progn - ,(cond - (setp - `(deftransform ,fun ((sap offset new-value) - (system-area-pointer fixnum ,value-type) *) - `(,',with-offset-fun sap (truly-the fixnum offset) 0 new-value))) - (t - `(deftransform ,fun ((sap offset) (system-area-pointer fixnum) *) - `(,',with-offset-fun sap (truly-the fixnum offset) 0)))) - (deftransform ,with-offset-fun ((sap offset disp - ,@(when setp `(new-value))) * *) - (fold-index-addressing ',with-offset-fun - 8 ; all sap-offsets are in bytes - 0 ; lowtag - 0 ; data offset - offset disp ,setp)))))))) - (def sap-ref-8) - (def %set-sap-ref-8 t (unsigned-byte 8)) - (def signed-sap-ref-8) - (def %set-signed-sap-ref-8 t (signed-byte 8)) - (def sap-ref-16) - (def %set-sap-ref-16 t (unsigned-byte 16)) - (def signed-sap-ref-16) - (def %set-signed-sap-ref-16 t (signed-byte 16)) - (def sap-ref-32) - (def %set-sap-ref-32 t (unsigned-byte 32)) - (def signed-sap-ref-32) - (def %set-signed-sap-ref-32 t (signed-byte 32)) - (def sap-ref-64) - (def %set-sap-ref-64 t (unsigned-byte 64)) - (def signed-sap-ref-64) - (def %set-signed-sap-ref-64 t (signed-byte 64)) - (def sap-ref-sap) - (def %set-sap-ref-sap t system-area-pointer) - (def sap-ref-lispobj) - (def %set-sap-ref-lispobj t t) - (def sap-ref-single) - (def %set-sap-ref-single t single-float) - (def sap-ref-double) - (def %set-sap-ref-double t double-float) - #+long-float (def sap-ref-long) - #+long-float (def %set-sap-ref-long t long-float)) ;;; [%SET-][SIGNED-]SAP-REF-WORD gets a defknown but no IR transforms, ;;; just source transforms. -(macrolet ((def (alias args value-type) +(macrolet ((def (alias value-type) (let* ((str (string alias)) (prefix (subseq str 0 (- (length str) 4))) ; remove -WORD - (fun (symbolicate prefix (write-to-string sb-vm:n-word-bits))) - (setp (string= prefix "%SET-" :end1 5))) + (fun (symbolicate prefix (write-to-string sb-vm:n-word-bits)))) `(progn - (defknown ,alias (system-area-pointer fixnum ,@(if setp (list value-type))) - ,value-type (flushable)) - (define-source-transform ,alias ,args `(,',fun ,,@args)))))) - (def sap-ref-word (sap offset) word) - (def signed-sap-ref-word (sap offset) sb-vm:signed-word) - (def %set-sap-ref-word (sap offset value) word) - (def %set-signed-sap-ref-word (sap offset value) sb-vm:signed-word)) + (defknown ,alias (system-area-pointer fixnum) ,value-type (flushable)) + (defknown (setf ,alias) (,value-type system-area-pointer fixnum) + (,value-type) ()) + (define-source-transform ,alias (sap offset) + `(,',fun ,sap ,offset)) + (define-source-transform (setf ,alias) (value sap offset) + `(funcall #'(setf ,',fun) ,value ,sap ,offset)))))) + (def sap-ref-word word) + (def signed-sap-ref-word sb-vm:signed-word)) ;;; Transforms for 64-bit SAP accessors on 32-bit platforms. @@ -187,41 +149,49 @@ (progn #+little-endian (progn - (deftransform sap-ref-64 ((sap offset) (* *)) - '(logior (sap-ref-32 sap offset) - (ash (sap-ref-32 sap (+ offset 4)) 32))) - - (deftransform signed-sap-ref-64 ((sap offset) (* *)) - '(logior (sap-ref-32 sap offset) - (ash (signed-sap-ref-32 sap (+ offset 4)) 32))) - - (deftransform %set-sap-ref-64 ((sap offset value) (* * *)) - '(progn - (%set-sap-ref-32 sap offset (logand value #xffffffff)) - (%set-sap-ref-32 sap (+ offset 4) (ash value -32)))) - - (deftransform %set-signed-sap-ref-64 ((sap offset value) (* * *)) - '(progn - (%set-sap-ref-32 sap offset (logand value #xffffffff)) - (%set-signed-sap-ref-32 sap (+ offset 4) (ash value -32))))) + (define-source-transform sap-ref-64 (sap offset) + `(let ((sap ,sap) (offset ,offset)) + (logior (sap-ref-32 sap offset) + (ash (sap-ref-32 sap (+ offset 4)) 32)))) + + (define-source-transform signed-sap-ref-64 (sap offset) + `(let ((sap ,sap) (offset ,offset)) + (logior (sap-ref-32 sap offset) + (ash (signed-sap-ref-32 sap (+ offset 4)) 32)))) + + (define-source-transform (setf sap-ref-64) (value sap offset) + `(let ((value ,value) (sap ,sap) (offset ,offset)) + (%set-sap-ref-32 (logand value #xffffffff) sap offset) + (%set-sap-ref-32 (ash value -32) sap (+ offset 4)) + value)) + + (define-source-transform (setf signed-sap-ref-64) (value sap offset) + `(let ((value ,value) (sap ,sap) (offset ,offset)) + (%set-sap-ref-32 (logand value #xffffffff) sap offset) + (%set-signed-sap-ref-32 (ash value -32) sap (+ offset 4)) + value))) #+big-endian (progn - (deftransform sap-ref-64 ((sap offset) (* *)) - '(logior (ash (sap-ref-32 sap offset) 32) - (sap-ref-32 sap (+ offset 4)))) - - (deftransform signed-sap-ref-64 ((sap offset) (* *)) - '(logior (ash (signed-sap-ref-32 sap offset) 32) - (sap-ref-32 sap (+ 4 offset)))) - - (deftransform %set-sap-ref-64 ((sap offset value) (* * *)) - '(progn - (%set-sap-ref-32 sap offset (ash value -32)) - (%set-sap-ref-32 sap (+ offset 4) (logand value #xffffffff)))) - - (deftransform %set-signed-sap-ref-64 ((sap offset value) (* * *)) - '(progn - (%set-signed-sap-ref-32 sap offset (ash value -32)) - (%set-sap-ref-32 sap (+ 4 offset) (logand value #xffffffff))))) + (define-source-transform sap-ref-64 (sap offset) + `(let ((sap ,sap) (offset ,offset)) + (logior (ash (sap-ref-32 sap offset) 32) + (sap-ref-32 sap (+ offset 4))))) + + (define-source-transform signed-sap-ref-64 (sap offset) + `(let ((sap ,sap) (offset ,offset)) + (logior (ash (signed-sap-ref-32 sap offset) 32) + (sap-ref-32 sap (+ 4 offset))))) + + (define-source-transform (setf sap-ref-64) (value sap offset) + `(let ((value ,value) (sap ,sap) (offset ,offset)) + (%set-sap-ref-32 (ash value -32) sap offset) + (%set-sap-ref-32 (logand value #xffffffff) sap (+ offset 4)) + value)) + + (define-source-transform (setf signed-sap-ref-64) (value sap offset) + `(let ((value ,value) (sap ,sap) (offset ,offset)) + (%set-signed-sap-ref-32 (ash value -32) sap offset) + (%set-sap-ref-32 (logand value #xffffffff) sap (+ 4 offset)) + value))) ) ; (= 32 SB-VM:N-MACHINE-WORD-BITS) diff --git a/src/compiler/seqtran.lisp b/src/compiler/seqtran.lisp index 56c0c3ed51..719704b961 100644 --- a/src/compiler/seqtran.lisp +++ b/src/compiler/seqtran.lisp @@ -61,7 +61,8 @@ arglists `(,n-first ,@(rest arglists)))) (let ((v (gensym))) - (do-clauses `(,v ,a (cdr ,v))) + (do-clauses `(,v (the* (list :use-annotations t :source-form ,a) ,a) + (cdr ,v))) (tests `(endp ,v)) (args-to-fn (if take-car `(car ,v) v)))) @@ -288,9 +289,14 @@ (let* ((all-seqs (cons seq seqs)) (seq-args (make-gensym-list (length all-seqs)))) `(lambda (result-type fun ,@seq-args) - (map-into (make-sequence result-type - (min ,@(loop for arg in seq-args - collect `(length ,arg)))) + (map-into (locally + #-sb-xc-host + (declare (muffle-conditions array-initial-element-mismatch)) + (make-sequence result-type + ,(if (cdr seq-args) + `(min ,@(loop for arg in seq-args + collect `(length ,arg))) + `(length ,(car seq-args))))) fun ,@seq-args)))) (t (let* ((all-seqs (cons seq seqs)) @@ -329,7 +335,7 @@ `(%fun-name (svref sb-impl::%%vector-map-into-funs%% ,typecode))) (deftransform map-into ((result fun &rest seqs) - (vector * &rest *) + (vector t &rest t) * :node node) "open code" (let* ((seqs-names (make-gensym-list (length seqs))) @@ -381,20 +387,20 @@ ;;; FIXME: once the confusion over doing transforms with known-complex ;;; arrays is over, we should also transform the calls to (AND (ARRAY ;;; * (*)) (NOT (SIMPLE-ARRAY * (*)))) objects. -(deftransform elt ((s i) ((simple-array * (*)) *) *) +(deftransform elt ((s i) ((simple-array * (*)) t) *) '(aref s i)) -(deftransform elt ((s i) (list *) * :policy (< safety 3)) +(deftransform elt ((s i) (list t) * :policy (< safety 3)) '(nth i s)) -(deftransform %setelt ((s i v) ((simple-array * (*)) * *) *) +(deftransform %setelt ((s i v) ((simple-array * (*)) t t) *) '(setf (aref s i) v)) -(deftransform %setelt ((s i v) (list * *) * :policy (< safety 3)) +(deftransform %setelt ((s i v) (list t t) * :policy (< safety 3)) '(setf (car (nthcdr i s)) v)) (deftransform %check-vector-sequence-bounds ((vector start end) - (vector * *) * + (vector t t) * :node node) (if (policy node (= 0 insert-array-bounds-checks)) '(or end (length vector)) @@ -411,7 +417,7 @@ (csubtypep type (specifier-type 'eq-comparable-type))) (defun specialized-list-seek-function-name (function-name key-functions &optional variant) - (or (find-symbol (with-simple-output-to-string (s) + (or (find-symbol (%with-output-to-string (s) ;; Write "%NAME-FUN1-FUN2-FUN3", etc. Not only is ;; this ever so slightly faster then FORMAT, this ;; way we are also proof against *PRINT-CASE* @@ -677,7 +683,7 @@ (t (aver (integer-type-p element-ctype)) :bits)))) - (if (constant-lvar-p item) + (if (and item (constant-lvar-p item)) (let* ((basher-name (format nil "UB~D-BASH-FILL" n-bits)) (basher (or (find-symbol basher-name #.(find-package "SB-KERNEL")) (abort-ir1-transform @@ -760,10 +766,22 @@ '(char-code item) 'item))))))) +(deftransform quickfill ((seq item) (vector t) * :node node) + ;; The QUICKFILL function has no START,END lexical vars, but if + ;; the transform hits the bashable non-simple or non-bashable case, + ;; it will invoke WITH-ARRAY-DATA using these variables. + `(let ((start 0) (end nil)) + (declare (ignorable start end)) + ,(fill-transform 'quickfill node seq item nil nil))) (deftransform fill ((seq item &key (start 0) (end nil)) (vector t &key (:start t) (:end t)) * :node node) + (fill-transform 'fill node seq item start end)) +(defun fill-transform (fun-name node seq item start end) + (add-annotation seq + (make-lvar-sequence-bounds-annotation :deps (list start end) + :source-path (node-source-path node))) (let* ((type (lvar-type seq)) (element-ctype (array-type-upgraded-element-type type)) (element-type (type-specifier element-ctype)) @@ -772,23 +790,54 @@ (cond ((eq *wild-type* element-ctype) (delay-ir1-transform node :constraint) `(vector-fill* seq item start end)) + ((and (array-type-p type) + (not (array-type-complexp type)) + (or (not start) + (and (constant-lvar-p start) + (eql (lvar-value start) 0))) + (not end) + (typep (array-type-dimensions type) '(cons number null)) + (<= (car (array-type-dimensions type)) + (cond #+soft-card-marks + ((eq element-ctype *universal-type*) + ;; Each write will have a store barrier, + ;; marking it pretty large. + 2) + (t + 10)))) + `(progn + ,@(loop for i below (car (array-type-dimensions type)) + collect `(setf (aref seq ,i) item)) + seq)) #+x86-64 ((and (type= element-ctype *universal-type*) (csubtypep (lvar-type seq) (specifier-type '(simple-array * (*)))) + ;; FIXME: why can't this work with arbitrary START and END? + ;; VECTOR-FILL/T certainly seems to take them. (or (not start) (and (constant-lvar-p start) (eql (lvar-value start) 0))) - (not end)) - '(vector-fill/t seq item 0 (length seq))) + (or (not end) + ;; QUICKFILL always fills the whole vector, but I anticipate + ;; supplying END to avoid a call to VECTOR-LENGTH + (eq fun-name 'quickfill))) + ;; VECTOR-LENGTH entails one fewer transform than LENGTH + ;; and it too can derive a constant length if known. + '(vector-fill/t seq item 0 (vector-length seq))) ((and saetp (sb-vm:valid-bit-bash-saetp-p saetp)) (multiple-value-bind (basher bash-value) (find-basher saetp item node) (values ;; KLUDGE: WITH-ARRAY data in its full glory is going to mess up ;; dynamic-extent for MAKE-ARRAY :INITIAL-ELEMENT initialization. - (if (csubtypep (lvar-type seq) (specifier-type '(simple-array * (*)))) + (cond + ((eq fun-name 'quickfill) + ;; array is simple, and out-of-bounds can't happen + `(,basher ,bash-value seq 0 (vector-length seq))) + ;; FIXME: isn't this (NOT (CONSERVATIVE-ARRAY-TYPE-COMPLEXP (lvar-type seq))) ? + ((csubtypep (lvar-type seq) (specifier-type '(simple-array * (*)))) `(block nil (tagbody - (let* ((len (length seq)) + (let* ((len (vector-length seq)) (end (cond (end (when (> end len) (go bad-index)) @@ -804,7 +853,8 @@ start)) (- end start)))) bad-index - (sequence-bounding-indices-bad-error seq start end))) + (sequence-bounding-indices-bad-error seq start end)))) + (t `(with-array-data ((data seq) (start start) (end end) @@ -813,8 +863,9 @@ (declare (type index start end)) (declare (optimize (safety 0) (speed 3))) (,basher ,bash-value data start (- end start)) - seq)) + seq))) `((declare (type ,element-type item)))))) + ;; OK, it's not a "bashable" array type. ((policy node (> speed space)) (values `(with-array-data ((data seq) @@ -887,7 +938,7 @@ `(deftransform ,name ((string1 string2 start1 end1 start2 end2) (simple-string simple-string t t t t) *) `(multiple-value-bind (index diff) - (%sp-string-compare string1 start1 end1 string2 start2 end2) + (%sp-string-compare string1 string2 start1 end1 start2 end2) (if ,',test ,,(if index ''index 'nil) ,,(if index 'nil ''index)))))) @@ -928,17 +979,43 @@ (t (give-up-ir1-transform)))) -(macrolet ((def (name test index) - `(deftransform ,name ((string1 string2 start1 end1 start2 end2) - (simple-string simple-string t t t t) *) - `(multiple-value-bind (index diff) - (%sp-string-compare string1 start1 end1 string2 start2 end2) - (declare (ignorable index)) - (if (,',test diff 0) - ,,(if index ''index t) - nil))))) - (def string=* = nil) ; FIXME: this xform looks counterproductive. - (def string/=* /= t)) +(deftransform string=* + ((string1 string2 start1 end1 start2 end2) (simple-base-string simple-base-string t t t t) *) + `(simple-base-string= string1 string2 start1 end1 start2 end2)) + +#+sb-unicode +(deftransform string=* + ((string1 string2 start1 end1 start2 end2) (simple-character-string simple-character-string t t t t) *) + `(simple-character-string= string1 string2 start1 end1 start2 end2)) + +(deftransform string/=* + ((string1 string2 start1 end1 start2 end2) (simple-string simple-string t t t t) *) + `(multiple-value-bind (index diff) + (%sp-string-compare string1 string2 start1 end1 start2 end2) + (declare (ignorable index)) + (if (,'/= diff 0) + ,'index + nil))) + +(deftransforms (string=* simple-base-string= + simple-character-string=) + ((string1 string2 start1 end1 start2 end2) + (t t (constant-arg t) (constant-arg t) (constant-arg t) (constant-arg t))) + (let* ((start1 (lvar-value start1)) + (length1 (vector-type-length (lvar-type string1))) + (end1 (or (lvar-value end1) + length1)) + (start2 (lvar-value start2)) + (length2 (vector-type-length (lvar-type string2))) + (end2 (or (lvar-value end2) + length2))) + (if (and length1 length2 + (<= start1 end1 length1) + (<= start2 end2 length2) + (/= (- end1 start1) + (- end2 start2))) + nil + (give-up-ir1-transform)))) (deftransform string/=* ((str1 str2 start1 end1 start2 end2) * * :node node :important nil) @@ -949,6 +1026,162 @@ `(if (string=* str1 str2 start1 end1 start2 end2) nil 0) (give-up-ir1-transform))) +(defun check-sequence-ranges (string start end node &optional (suffix "") sequence-name) + (let* ((type (lvar-type string)) + (length (vector-type-length type)) + (annotation (find-if #'lvar-sequence-bounds-annotation-p (lvar-annotations string)))) + (when annotation + (when (shiftf (lvar-annotation-fired annotation) t) + (return-from check-sequence-ranges))) + (flet ((arg-type (x) + (typecase x + (constant (ctype-of (constant-value x))) + (lvar (lvar-type x)) + (t (leaf-type x))))) + (when length + (flet ((check (index name length-type) + (when index + (let ((index-type (arg-type index))) + (unless (types-equal-or-intersect index-type + (specifier-type length-type)) + (let ((*compiler-error-context* node)) + (compiler-warn "Bad :~a~a ~a for~a ~a" + name suffix + (type-specifier index-type) + (if sequence-name + (format nil " for ~a of type" sequence-name) + suffix) + (type-specifier type)))))))) + (check start "start" `(integer 0 ,length)) + (check end "end" `(or null (integer 0 ,length))))) + (when (and start end) + (let* ((start-type (arg-type start)) + (start-interval (type-approximate-interval start-type)) + (end-type (arg-type end)) + (end-interval (type-approximate-interval end-type))) + (when (and (interval-p start-interval) + (interval-p end-interval) + (interval-< end-interval start-interval)) + (let ((*compiler-error-context* node)) + (compiler-warn ":start~a ~a is greater than :end~a ~a" + suffix + (type-specifier start-type) + suffix + (type-specifier end-type))))))))) +(defoptimizers ir2-hook + (string=* string<* string>* string<=* string>=* + %sp-string-compare simple-base-string= + #+sb-unicode simple-character-string=) + ((string1 string2 start1 end1 start2 end2) node) + (check-sequence-ranges string1 start1 end1 node 1 'string1) + (check-sequence-ranges string2 start2 end2 node 2 'string2)) + +(defoptimizers ir2-hook + (string-equal string-not-equal string-greaterp string-lessp) + ((string1 string2 &key start1 end1 start2 end2) node) + (check-sequence-ranges string1 start1 end1 node 1 'string1) + (check-sequence-ranges string2 start2 end2 node 2 'string2)) + +(defoptimizers ir2-hook + (string-downcase string-upcase + nstring-downcase nstring-upcase + string-capitalize nstring-capitalize) + ((string &key start end) node) + (check-sequence-ranges string start end node)) + +(defoptimizers ir2-hook + (find find-if find-if-not position position-if position-if-not + remove remove-if remove-if-not delete delete-if delete-if-not + count count-if count-if-not reduce + remove-duplicates delete-duplicates) + ((x sequence &key start end &allow-other-keys) node) + (check-sequence-ranges sequence start end node)) + +(defoptimizers ir2-hook + (remove-duplicates delete-duplicates) + ((sequence &key start end &allow-other-keys) node) + (check-sequence-ranges sequence start end node)) + +(defoptimizer (%find-position ir2-hook) ((item sequence from-end start end key test) node) + (check-sequence-ranges sequence start end node)) + +(defoptimizers ir2-hook + (%find-position-if %find-position-if-not) + ((predicate sequence from-end start end key) node) + (check-sequence-ranges sequence start end node)) + +(defoptimizer (fill ir2-hook) ((sequence item &key start end) node) + (check-sequence-ranges sequence start end node)) + +(defoptimizer (search ir2-hook) ((sub-sequence1 main-sequence2 &key start1 end1 start2 end2 &allow-other-keys) node) + (check-sequence-ranges sub-sequence1 start1 end1 node 1 'sub-sequence1) + (check-sequence-ranges main-sequence2 start2 end2 node 2 'main-sequence2)) + +(defoptimizer (mismatch ir2-hook) ((sequence1 sequence2 &key start1 end1 start2 end2 &allow-other-keys) node) + (check-sequence-ranges sequence1 start1 end1 node 1 'sequence1) + (check-sequence-ranges sequence2 start2 end2 node 2 'sequence2)) + +(defun string-cmp-deriver (string1 string2 start1 end1 start2 end2 &optional equality) + (flet ((dims (string start end) + (let* ((type (lvar-type string)) + (length (vector-type-length type)) + (start (cond ((not start) + 0) + ((constant-lvar-p start) + (lvar-value start)))) + (end (cond ((not end) + length) + ((constant-lvar-p end) + (or (lvar-value end) + length))))) + (values + start + end + (and start end + (- end start)))))) + (multiple-value-bind (start1 end1 length1) + (dims string1 start1 end1) + (let (low + high + (length2 (nth-value 2 (dims string2 start2 end2)))) + (when start1 + (setf low start1)) + (when end1 + (setf high end1)) + (when (and length2 start1) + (let ((high2 (+ start1 length2))) + (when (or (not high) + (> high high2)) + (setf high high2)))) + (when (or low high) + (let ((type (make-numeric-type :class 'integer :high high :low low))) + (if (and equality length1 length2 + (/= length1 length2)) + (if (eq equality '%sp-string-compare) + (make-values-type :required + (list type + (specifier-type '(and integer (not (eql 0)))))) + type) + (type-union type + (specifier-type 'null))))))))) + +(macrolet ((def (name &optional equality) + `(defoptimizer (,name derive-type) ((string1 string2 start1 end1 start2 end2)) + (string-cmp-deriver string1 string2 start1 end1 start2 end2 ,equality)))) + (def string<*) + (def string>*) + (def string<=*) + (def string>=*) + (def string/=* t) + (def %sp-string-compare '%sp-string-compare)) + +(macrolet ((def (name &optional equality) + `(defoptimizer (,name derive-type) ((string1 string2 &key start1 end1 start2 end2)) + (string-cmp-deriver string1 string2 start1 end1 start2 end2 ,equality)))) + (def string-greaterp) + (def string-lessp) + (def string-not-equal t)) + (deftransform string ((x) (symbol)) '(symbol-name x)) (deftransform string ((x) (string)) '(progn x)) @@ -991,67 +1224,205 @@ ;;; you tweak it, make sure that you compare the disassembly, if not the ;;; performance of, the functions implementing string streams ;;; (e.g. SB-IMPL::BASE-STRING-SOUT). -(eval-when (#-sb-xc :compile-toplevel :load-toplevel :execute) - (defun !make-replace-transform (saetp sequence-type1 sequence-type2) - `(deftransform replace ((seq1 seq2 &key (start1 0) (start2 0) end1 end2) - (,sequence-type1 ,sequence-type2 &rest t) - ,sequence-type1 - :node node) - `(let* ((len1 (length seq1)) - (len2 (length seq2)) - (end1 (or end1 len1)) - (end2 (or end2 len2)) - (replace-len (min (- end1 start1) (- end2 start2)))) - ,(unless (policy node (= insert-array-bounds-checks 0)) - `(progn - (unless (<= 0 start1 end1 len1) - (sequence-bounding-indices-bad-error seq1 start1 end1)) - (unless (<= 0 start2 end2 len2) - (sequence-bounding-indices-bad-error seq2 start2 end2)))) - ,',(cond - ((and saetp (sb-vm:valid-bit-bash-saetp-p saetp)) - (let* ((n-element-bits (sb-vm:saetp-n-bits saetp)) - (bash-function (intern (format nil "UB~D-BASH-COPY" - n-element-bits) - (find-package "SB-KERNEL")))) - `(funcall (function ,bash-function) seq2 start2 - seq1 start1 replace-len))) - (t - `(if (and - ;; If the sequence types are different, SEQ1 and - ;; SEQ2 must be distinct arrays. - ,(eql sequence-type1 sequence-type2) - (eq seq1 seq2) (> start1 start2)) - (do ((i (truly-the (or (eql -1) index) (+ start1 replace-len -1)) - (1- i)) - (j (truly-the (or (eql -1) index) (+ start2 replace-len -1)) - (1- j))) - ((< i start1)) - (declare (optimize (insert-array-bounds-checks 0))) - (setf (aref seq1 i) (aref seq2 j))) - (do ((i start1 (1+ i)) - (j start2 (1+ j)) - (end (+ start1 replace-len))) - ((>= i end)) - (declare (optimize (insert-array-bounds-checks 0))) - (setf (aref seq1 i) (aref seq2 j)))))) - seq1)))) - -(macrolet - ((define-replace-transforms () - (loop for saetp across sb-vm:*specialized-array-element-type-properties* - for sequence-type = `(simple-array ,(sb-vm:saetp-specifier saetp) (*)) - unless (= (sb-vm:saetp-typecode saetp) sb-vm:simple-array-nil-widetag) - collect (!make-replace-transform saetp sequence-type sequence-type) - into forms - finally (return `(progn ,@forms)))) - (define-one-transform (sequence-type1 sequence-type2) - (!make-replace-transform nil sequence-type1 sequence-type2))) - (define-replace-transforms) - #+sb-unicode - (progn - (define-one-transform (simple-array base-char (*)) (simple-array character (*))) - (define-one-transform (simple-array character (*)) (simple-array base-char (*))))) +(defun transform-replace-bashable (bash-function node) + ;; This is a little circuitous - we transform REPLACE into BASH-COPY + ;; and then possibly transform BASH-COPY into an unrolled loop. + ;; There ought to be a way to see if the BASH-COPY transform applies. + `(let* ((len1 (length seq1)) + (len2 (length seq2)) + (end1 (or end1 len1)) + (end2 (or end2 len2)) + (replace-len (min (- end1 start1) (- end2 start2)))) + ,@(when (policy node (/= insert-array-bounds-checks 0)) + '((unless (<= 0 start1 end1 len1) + (sequence-bounding-indices-bad-error seq1 start1 end1)) + (unless (<= 0 start2 end2 len2) + (sequence-bounding-indices-bad-error seq2 start2 end2)))) + (,bash-function seq2 start2 seq1 start1 replace-len) + seq1)) +(defun transform-replace (same-types-p node) + `(let* ((len1 (length seq1)) + (len2 (length seq2)) + (end1 (or end1 len1)) + (end2 (or end2 len2)) + (replace-len (min (- end1 start1) (- end2 start2)))) + ,@(when (policy node (/= insert-array-bounds-checks 0)) + '((unless (<= 0 start1 end1 len1) + (sequence-bounding-indices-bad-error seq1 start1 end1)) + (unless (<= 0 start2 end2 len2) + (sequence-bounding-indices-bad-error seq2 start2 end2)))) + ,(flet ((down () + '(do ((i (truly-the (or (eql -1) index) (+ start1 replace-len -1)) (1- i)) + (j (truly-the (or (eql -1) index) (+ start2 replace-len -1)) (1- j))) + ((< j start2)) + (declare (optimize (insert-array-bounds-checks 0))) + (setf (aref seq1 i) (data-vector-ref seq2 j)))) + (up () + '(do ((i start1 (1+ i)) + (j start2 (1+ j)) + (end (+ start1 replace-len))) + ((>= i end)) + (declare (optimize (insert-array-bounds-checks 0))) + (setf (aref seq1 i) (data-vector-ref seq2 j))))) + ;; "If sequence-1 and sequence-2 are the same object and the region being modified + ;; overlaps the region being copied from, then it is as if the entire source region + ;; were copied to another place and only then copied back into the target region. + ;; However, if sequence-1 and sequence-2 are not the same, but the region being modified + ;; overlaps the region being copied from (perhaps because of shared list structure or + ;; displaced arrays), then after the replace operation the subsequence of sequence-1 + ;; being modified will have unpredictable contents." + (if same-types-p ; source and destination sequences could be EQ + `(if (and (eq seq1 seq2) (> start1 start2)) ,(down) ,(up)) + (up))) + seq1)) + +(deftransform replace ((seq1 seq2 &key (start1 0) (start2 0) end1 end2) + ((simple-array * (*)) (simple-array * (*)) &rest t) (simple-array * (*)) + :node node) + (let ((et (and (array-type-p (lvar-type seq1)) + (array-type-p (lvar-type seq2)) + (array-type-specialized-element-type (lvar-type seq1))))) + (if (and et + (neq et *empty-type*) + (neq et *wild-type*) + (eq (array-type-specialized-element-type (lvar-type seq2)) et)) + (let ((saetp (find-saetp-by-ctype et))) + (if (sb-vm:valid-bit-bash-saetp-p saetp) + (transform-replace-bashable + (intern (format nil "UB~D-BASH-COPY" (sb-vm:saetp-n-bits saetp)) + #.(find-package "SB-KERNEL")) + node) + (transform-replace t node))) + (give-up-ir1-transform)))) +#+sb-unicode +(progn +(deftransform replace ((seq1 seq2 &key (start1 0) (start2 0) end1 end2) + (simple-base-string simple-character-string &rest t) simple-base-string + :node node) + (transform-replace nil node)) +(deftransform replace ((seq1 seq2 &key (start1 0) (start2 0) end1 end2) + (simple-character-string simple-base-string &rest t) simple-character-string + :node node) + (transform-replace nil node))) + +(defoptimizer (replace ir2-hook) ((seq1 seq2 &key start1 end1 start2 end2) node) + (flet ((element-type (lvar) + (type-array-element-type (lvar-type lvar)))) + (let ((type1 (element-type seq1)) + (type2 (element-type seq2))) + (check-sequence-ranges seq1 start1 end1 node 1 'target-sequence1) + (check-sequence-ranges seq2 start2 end2 node 2 'source-sequence2) + (cond ((eq type1 *wild-type*)) + ((eq type2 *wild-type*) + (when (constant-lvar-p seq2) + (map nil (lambda (x) + (unless (ctypep x type1) + (let ((*compiler-error-context* node)) + (compiler-warn "The source sequence has an element ~s incompatible with the target array element type ~a." + x + (type-specifier type1))) + (return-from replace-ir2-hook-optimizer)) + x) + (lvar-value seq2)))) + ((not (types-equal-or-intersect type1 type2)) + (let ((*compiler-error-context* node)) + (compiler-warn "Incompatible array element types: ~a and ~a" + (type-specifier type1) + (type-specifier type2)))))))) + +(defoptimizer (%make-array ir2-hook) ((dimensions widetag n-bits &key initial-contents &allow-other-keys) node) + (when (and (constant-lvar-p widetag) + initial-contents) + (let* ((saetp (find (lvar-value widetag) sb-vm:*specialized-array-element-type-properties* + :key #'sb-vm:saetp-typecode)) + (element-type (sb-vm:saetp-ctype saetp)) + (initial-contents-type (lvar-type initial-contents)) + (initial-contents-element-type (type-array-element-type initial-contents-type))) + (cond ((not (or (eq initial-contents-element-type *wild-type*) + (types-equal-or-intersect element-type initial-contents-element-type))) + (let ((*compiler-error-context* node)) + (compiler-warn "Incompatible :initial-contents ~s for :element-type ~a." + (type-specifier initial-contents-type) + (sb-vm:saetp-specifier saetp)))) + ((constant-lvar-p initial-contents) + (map nil (lambda (x) + (unless (ctypep x element-type) + (let ((*compiler-error-context* node)) + (compiler-warn ":initial-contents has an element ~s incompatible with :element-type ~a." + x + (type-specifier element-type))) + (return-from %make-array-ir2-hook-optimizer)) + x) + (lvar-value initial-contents))))))) + +(defun check-sequence-item (item seq node format-string) + (let ((seq-type (lvar-type seq)) + (item-type (lvar-type item))) + (when (neq item-type *wild-type*) + (let ((element-type (type-array-element-type seq-type))) + (unless (or (eq element-type *wild-type*) + (types-equal-or-intersect item-type element-type)) + (let ((*compiler-error-context* node)) + (compiler-warn format-string + (type-specifier item-type) + (type-specifier seq-type)))))))) + +(defoptimizers ir2-hook + (substitute substitute-if substitute-if-not + nsubstitute nsubstitute-if nsubstitute-if-not) + ((new x seq &key start end &allow-other-keys) node) + (check-sequence-ranges seq start end node) + (check-sequence-item new seq node "Can't substitute ~a into ~a")) + +(defoptimizer (vector-fill* ir2-hook) ((seq item start end) node) + (check-sequence-ranges seq start end node) + (check-sequence-item item seq node "Can't fill ~a into ~a")) + +(defoptimizer (vector-push ir2-hook) ((item vector) node) + (check-sequence-item item vector node "Can't push ~a into ~a")) + +(defoptimizer (vector-push-extend ir2-hook) ((item vector &optional min-extension) node) + (check-sequence-item item vector node "Can't push ~a into ~a")) + +(defun check-concatenate (type sequences node &optional (description "concatenate")) + (let ((result-element-type (if (ctype-p type) + type + (type-array-element-type (specifier-type type))))) + (unless (or (eq result-element-type *wild-type*) + (eq result-element-type *universal-type*)) + (loop for i from 0 + for sequence in sequences + for sequence-type = (lvar-type sequence) + for element-type = (type-array-element-type sequence-type) + do (unless (or (eq element-type *wild-type*) + (types-equal-or-intersect element-type result-element-type)) + (let ((*compiler-error-context* node)) + (compiler-warn "Can't ~a ~s into ~s" + description + (type-specifier sequence-type) + (if (ctype-p type) + (type-specifier (make-array-type '(*) + :specialized-element-type type + :element-type type)) + type)))))))) + +(defoptimizer (%concatenate-to-string ir2-hook) ((&rest args) node) + (check-concatenate 'string args node)) + +(defoptimizer (%concatenate-to-base-string ir2-hook) ((&rest args) node) + (check-concatenate 'base-string args node)) + +(defoptimizer (%concatenate-to-vector ir2-hook) ((widetag &rest args) node) + (when (constant-lvar-p widetag) + (check-concatenate (sb-vm:saetp-ctype + (find (lvar-value widetag) + sb-vm:*specialized-array-element-type-properties* + :key #'sb-vm:saetp-typecode)) + args node))) + +(defoptimizer (merge ir2-hook) ((type sequence1 sequence2 predicate &key &allow-other-keys) node) + (when (constant-lvar-p type) + (check-concatenate (lvar-value type) (list sequence1 sequence2) node "merge"))) ;;; Expand simple cases of UB<SIZE>-BASH-COPY inline. "simple" is ;;; defined as those cases where we are doing word-aligned copies from @@ -1063,72 +1434,50 @@ ;;; restrictive, but they do catch common cases, like allocating a (* 2 ;;; N)-size buffer and blitting in the old N-size buffer in. -(defun frob-bash-transform (src src-offset - dst dst-offset - length n-elems-per-word) +(deftransform transform-bash-copy ((src src-offset dst dst-offset length) + * * + :defun-only t :info n-bits-per-elem) (declare (ignore src dst length)) - (let ((n-bits-per-elem (truncate sb-vm:n-word-bits n-elems-per-word))) - (multiple-value-bind (src-word src-elt) - (truncate (lvar-value src-offset) n-elems-per-word) - (multiple-value-bind (dst-word dst-elt) - (truncate (lvar-value dst-offset) n-elems-per-word) - ;; Avoid non-word aligned copies. - (unless (and (zerop src-elt) (zerop dst-elt)) - (give-up-ir1-transform)) - ;; Avoid copies where we would have to insert code for - ;; determining the direction of copying. - (unless (= src-word dst-word) - (give-up-ir1-transform)) - `(let ((end (+ ,src-word (truncate (the index length) ,n-elems-per-word)))) - (declare (type index end)) - ;; Handle any bits at the end. - (when (logtest length (1- ,n-elems-per-word)) - (let* ((extra (mod length ,n-elems-per-word)) - ;; FIXME: The shift amount on this ASH is - ;; *always* negative, but the backend doesn't - ;; have a NEGATIVE-FIXNUM primitive type, so we - ;; wind up with a pile of code that tests the - ;; sign of the shift count prior to shifting when - ;; all we need is a simple negate and shift - ;; right. Yuck. - (mask (ash most-positive-word - (* (- extra ,n-elems-per-word) - ,n-bits-per-elem)))) - (setf (%vector-raw-bits dst end) - (logior - (logandc2 (%vector-raw-bits dst end) - (ash mask - ,(ecase *backend-byte-order* - (:little-endian 0) - (:big-endian `(* (- ,n-elems-per-word extra) - ,n-bits-per-elem))))) - (logand (%vector-raw-bits src end) - (ash mask - ,(ecase *backend-byte-order* - (:little-endian 0) - (:big-endian `(* (- ,n-elems-per-word extra) - ,n-bits-per-elem))))))))) - ;; Copy from the end to save a register. - (do ((i end (1- i))) - ((<= i ,src-word)) - (setf (%vector-raw-bits dst (1- i)) - (%vector-raw-bits src (1- i)))) - (values)))))) - -#. -(let ((arglist '((src src-offset dst dst-offset length) - ((simple-unboxed-array (*)) (constant-arg index) - (simple-unboxed-array (*)) (constant-arg index) - index) - *))) - (loop for i = 1 then (* i 2) - for name = (intern (format nil "UB~D-BASH-COPY" i) "SB-KERNEL") - collect `(deftransform ,name ,arglist - (frob-bash-transform src src-offset - dst dst-offset length - ,(truncate sb-vm:n-word-bits i))) into forms - until (= i sb-vm:n-word-bits) - finally (return `(progn ,@forms)))) + (binding* ((n-elems-per-word (truncate sb-vm:n-word-bits n-bits-per-elem)) + ((src-word src-elt) (truncate (lvar-value src-offset) n-elems-per-word)) + ((dst-word dst-elt) (truncate (lvar-value dst-offset) n-elems-per-word))) + ;; Avoid non-word aligned copies. + (unless (and (zerop src-elt) (zerop dst-elt)) + (give-up-ir1-transform)) + ;; Avoid copies where we would have to insert code for + ;; determining the direction of copying. + (unless (= src-word dst-word) + (give-up-ir1-transform)) + `(let ((end (+ ,src-word (truncate (the index length) ,n-elems-per-word))) + (extra (mod length ,n-elems-per-word))) + (declare (type index end)) + ;; Handle any bits at the end. + (unless (zerop extra) + ;; MASK selects just the bits that we want from the ending word of + ;; the source array. The number of bits to shift out is + ;; (- n-word-bits (* extra n-bits-per-elem)) + ;; which is equal mod n-word-bits to the expression below. + (let ((mask (shift-towards-start + most-positive-word (* extra ,(- n-bits-per-elem))))) + (%set-vector-raw-bits + dst end (logior (logand (%vector-raw-bits src end) mask) + (logandc2 (%vector-raw-bits dst end) mask))))) + ;; Copy from the end to save a register. + (do ((i (1- end) (1- i))) + ((< i ,src-word)) + (%set-vector-raw-bits dst i (%vector-raw-bits src i))) + (values)))) + +;;; Detect misuse with sb-devel. "Misuse" means mismatched array element types +#-sb-devel +(loop for i = 1 then (* i 2) + do (%deftransform (intern (format nil "UB~D-BASH-COPY" i) "SB-KERNEL") + nil + '(function ((simple-unboxed-array (*)) (constant-arg index) + (simple-unboxed-array (*)) (constant-arg index) + index) *) + (cons #'transform-bash-copy i)) + until (= i sb-vm:n-word-bits)) ;;; We expand copy loops inline in SUBSEQ and COPY-SEQ if we're copying ;;; arrays with elements of size >= the word size. We do this because @@ -1183,7 +1532,7 @@ (j (+ ,dst-offset ,length) (1- j))) ((<= i ,src-offset)) (declare (optimize (insert-array-bounds-checks 0)) - (type (integer 0 #.sb-xc:array-dimension-limit) j i)) + (type (integer 0 #.array-dimension-limit) j i)) (setf (aref ,dst (1- j)) (aref ,src (1- i)))))) ;;; MAKE-SEQUENCE, SUBSEQ, COPY-SEQ @@ -1252,8 +1601,9 @@ ;; As with MAKE-ARRAY, this is merely undefined ;; behavior, not an error. (compiler-style-warn - "The default initial element ~S is not a ~S." - default-initial-element elt-type)))) + 'initial-element-mismatch-style-warning + :format-control "The default initial element ~S is not a ~S." + :format-arguments (list default-initial-element elt-type))))) ;; In would be possible in some cases, ;; like :INITIAL-ELEMENT (IF X #\x #\y) in a call ;; to MAKE-SEQUENCE '(VECTOR (MEMBER #\A #\B)) @@ -1263,10 +1613,10 @@ (not (ctypep (lvar-value initial-element) elt-ctype))) ;; MAKE-ARRAY considers this a warning, not an error. - (compiler-warn "~S ~S is not a ~S" - :initial-element - (lvar-value initial-element) - elt-type))))) + (compiler-warn 'array-initial-element-mismatch + :format-control "~S ~S is not a ~S" + :format-arguments + (list :initial-element (lvar-value initial-element) elt-type)))))) (give-up-ir1-transform))))))) (deftransform subseq ((seq start &optional end) @@ -1280,10 +1630,9 @@ (let ((element-type (type-specifier (array-type-specialized-element-type type)))) `(let* ((length (length seq)) (end (or end length))) - ,(unless (policy node (zerop insert-array-bounds-checks)) - '(progn - (unless (<= 0 start end length) - (sequence-bounding-indices-bad-error seq start end)))) + ,@(when (policy node (/= insert-array-bounds-checks 0)) + '((unless (<= 0 start end length) + (sequence-bounding-indices-bad-error seq start end)))) (let* ((size (- end start)) (result (make-array size :element-type ',element-type))) ,(maybe-expand-copy-loop-inline 'seq (if (constant-lvar-p start) @@ -1321,22 +1670,23 @@ (deftransform search ((pattern text &key start1 start2 end1 end2 test test-not key from-end) - ((constant-arg sequence) * &rest *)) + ((constant-arg sequence) t &rest t)) (if key (give-up-ir1-transform) (let* ((pattern (lvar-value pattern)) (pattern-start (cond ((not (proper-sequence-p pattern)) (give-up-ir1-transform)) - ((constant-lvar-p start1) - (lvar-value start1)) ((not start1) 0) + ((constant-lvar-p start1) + (lvar-value start1)) (t (give-up-ir1-transform)))) - (pattern-end (cond ((constant-lvar-p end1) - (lvar-value end1)) - ((not end1) + (pattern-end (cond ((not end1) (length pattern)) + ((constant-lvar-p end1) + (or (lvar-value end1) + (length pattern))) (t (give-up-ir1-transform)))) (pattern (if (and (= (- pattern-end pattern-start) 1) @@ -1445,19 +1795,21 @@ &key start1 end1 start2 end2 from-end &allow-other-keys)) - (let* ((constant-start1 (and (constant-lvar-p start1) + (let* ((constant-start1 (and start1 + (constant-lvar-p start1) (lvar-value start1))) - (constant-end1 (and (constant-lvar-p end1) + (constant-end1 (and end1 + (constant-lvar-p end1) (lvar-value end1))) - (constant-start2 (and (constant-lvar-p start2) + (constant-start2 (and start2 + (constant-lvar-p start2) (lvar-value start2))) - (constant-end2 (and (constant-lvar-p end2) + (constant-end2 (and end2 + (constant-lvar-p end2) (lvar-value end2))) - (not-from-end (or (not from-end) - (and (constant-lvar-p from-end) - (not (lvar-value from-end))))) + (not-from-end (unsupplied-or-nil from-end)) (min-result (or constant-start2 0)) - (max-result (or constant-end2 (1- sb-xc:array-dimension-limit))) + (max-result (or constant-end2 (1- array-dimension-limit))) (max2 (sequence-lvar-dimensions sequence2)) (max-result (if (integerp max2) (min max-result max2) @@ -1488,12 +1840,14 @@ null)))) (defun index-into-sequence-derive-type (sequence start end &key (inclusive t)) - (let* ((constant-start (and (constant-lvar-p start) + (let* ((constant-start (and start + (constant-lvar-p start) (lvar-value start))) - (constant-end (and (constant-lvar-p end) + (constant-end (and end + (constant-lvar-p end) (lvar-value end))) (min-result (or constant-start 0)) - (max-result (or constant-end (1- sb-xc:array-dimension-limit))) + (max-result (or constant-end (1- array-dimension-limit))) (max (sequence-lvar-dimensions sequence)) (max-result (if (integerp max) (min max-result max) @@ -1510,10 +1864,7 @@ (multiple-value-bind (min max) (index-into-sequence-derive-type sequence1 start1 end1) (specifier-type `(or (integer ,min ,max) null)))) -(defoptimizer (position derive-type) ((item sequence - &key start end - key test test-not - &allow-other-keys)) +(defun position-derive-type (item sequence start end key test test-not) (multiple-value-bind (min max) (index-into-sequence-derive-type sequence start end :inclusive nil) (let ((integer-range `(integer ,min ,max)) @@ -1524,7 +1875,8 @@ ;; (1+ (position (the (member :x :y) item) #(:foo :bar :x :y))). ;; In that example, a more exact bound could be determined too. (cond ((or (not (constant-lvar-p sequence)) - start end key test test-not)) + start end key test test-not + (not item))) (t (let ((const-seq (lvar-value sequence)) (item-type (lvar-type item))) @@ -1542,6 +1894,55 @@ integer-range `(or ,integer-range null)))))) +(defun find-derive-type (item sequence key test start end from-end) + (declare (ignore start end from-end)) + (let ((type *universal-type*) + (key-identity-p (or (not key) + (lvar-value-is-nil key) + (lvar-fun-is key '(identity))))) + (flet ((fun-accepts-type (fun-lvar argument) + (when fun-lvar + (let ((fun-type (lvar-fun-type fun-lvar))) + (when (fun-type-p fun-type) + (let ((arg (nth argument (fun-type-n-arg-types (1+ argument) fun-type)))) + (when arg + (setf type + (type-intersection type arg))))))))) + (when (and item + key-identity-p + (or (not test) + (lvar-fun-is test '(eq eql char= char-equal)) + (lvar-value-is-nil test))) + ;; Maybe FIND returns ITEM itself (or an EQL number). + (setf type (lvar-type item))) + ;; Should return something the functions can accept + (if key-identity-p + (fun-accepts-type test (if item 1 0)) ;; the -if variants. + (fun-accepts-type key 0))) + (let ((upgraded-type (type-array-element-type (lvar-type sequence)))) + (unless (eq upgraded-type *wild-type*) + (setf type + (type-intersection type upgraded-type)))) + (unless (eq type *empty-type*) + (type-union type + (specifier-type 'null))))) + +(defoptimizer (find derive-type) ((item sequence &key key test + start end from-end)) + (find-derive-type item sequence key test start end from-end)) + +(defoptimizer (find-if derive-type) ((predicate sequence &key key start end from-end)) + (find-derive-type nil sequence key predicate start end from-end)) + +(defoptimizer (find-if-not derive-type) ((predicate sequence &key key start end from-end)) + (find-derive-type nil sequence key predicate start end from-end)) + +(defoptimizer (position derive-type) ((item sequence + &key start end + key test test-not + &allow-other-keys)) + (position-derive-type item sequence start end key test test-not)) + (defoptimizer (position-if derive-type) ((function sequence &key start end &allow-other-keys)) @@ -1558,6 +1959,30 @@ (index-into-sequence-derive-type sequence start end :inclusive nil) (specifier-type `(or (integer ,min ,max) null)))) +(defoptimizer (%find-position derive-type) ((item sequence from-end start end key test)) + (let ((find (find-derive-type item sequence key test start end from-end)) + (position (position-derive-type item sequence start end key test nil))) + (when (or find position) + (make-values-type :required + (list (or find *universal-type*) + (or position *universal-type*)))))) + +(defoptimizer (%find-position-if derive-type) ((predicate sequence from-end start end key)) + (let ((find (find-derive-type nil sequence key predicate start end from-end)) + (position (position-derive-type nil sequence start end key predicate nil))) + (when (or find position) + (make-values-type :required + (list (or find *universal-type*) + (or position *universal-type*)))))) + +(defoptimizer (%find-position-if-not derive-type) ((predicate sequence from-end start end key)) + (let ((find (find-derive-type nil sequence key predicate start end from-end)) + (position (position-derive-type nil sequence start end key predicate nil))) + (when (or find position) + (make-values-type :required + (list (or find *universal-type*) + (or position *universal-type*)))))) + (defoptimizer (count derive-type) ((item sequence &key start end &allow-other-keys)) @@ -1586,7 +2011,8 @@ (let* ((sequence-type (lvar-type sequence)) (constant-start (and (constant-lvar-p start) (lvar-value start))) - (constant-end (and (constant-lvar-p end) + (constant-end (and end + (constant-lvar-p end) (lvar-value end))) (index-length (and constant-start constant-end (- constant-end constant-start))) @@ -1849,36 +2275,6 @@ ;;;; FIND, POSITION, and their -IF and -IF-NOT variants -(defoptimizer (find derive-type) ((item sequence &key key test - start end from-end)) - (declare (ignore sequence start end from-end)) - (let ((key-fun (or (and key (lvar-fun-name* key)) 'identity))) - ;; If :KEY is a known function, then regardless of the :TEST, - ;; FIND returns an object of the type that KEY accepts, or nil. - ;; If LVAR-FUN-NAME can't be determined, it returns NIL. - ;; :KEY NIL is valid, and means #'IDENTITY. - ;; So either way, we get IDENTITY which skips this code. - (unless (eq key-fun 'identity) - (acond ((info :function :info key-fun) - (let ((type (info :function :type key-fun))) - (return-from find-derive-type-optimizer - (awhen (and (fun-type-p type) - (fun-type-required type)) - (type-union (first it) (specifier-type 'null)))))) - ((structure-instance-accessor-p key-fun) - (return-from find-derive-type-optimizer - (specifier-type `(or ,(dd-name (car it)) null))))))) - ;; Otherwise maybe FIND returns ITEM itself (or an EQL number). - ;; :TEST is allowed only if EQ or EQL (where NIL means EQL). - ;; :KEY is allowed only if IDENTITY or NIL. - (when (and (or (not test) - (lvar-fun-is test '(eq eql)) - (and (constant-lvar-p test) (null (lvar-value test)))) - (or (not key) - (lvar-fun-is key '(identity)) - (and (constant-lvar-p key) (null (lvar-value key))))) - (type-union (lvar-type item) (specifier-type 'null)))) - ;;; We want to make sure that %FIND-POSITION is inline-expanded into ;;; %FIND-POSITION-IF only when %FIND-POSITION-IF has an inline ;;; expansion, so we factor out the condition into this function. @@ -1914,8 +2310,7 @@ (not (and (lvar-single-value-p (node-lvar node)) (constant-lvar-p start) (eql (lvar-value start) 0) - (constant-lvar-p end) - (null (lvar-value end)))))) + (lvar-value-is-nil end))))) `(let ((find nil) (position nil)) (flet ((bounds-error () @@ -2139,8 +2534,7 @@ (if (eq '* (upgraded-element-type-specifier sequence)) (let ((form `(sb-impl::string-dispatch ((simple-array character (*)) - (simple-array base-char (*)) - (simple-array nil (*))) + (simple-array base-char (*))) sequence (%find-position item sequence from-end start end key test)))) (if (csubtypep (lvar-type sequence) (specifier-type 'simple-string)) @@ -2182,12 +2576,14 @@ (%coerce-callable-to-fun ,key) #'identity))) -(macrolet ((define-find-position (fun-name values-index &optional preamble) +(macrolet ((define-find-position (fun-name values-index) `(deftransform ,fun-name ((item sequence &key from-end (start 0) end key test test-not) (t (or list vector) &rest t)) (when (and (constant-lvar-p sequence) + (or (proper-sequence-p (lvar-value sequence)) + (give-up-ir1-transform)) (zerop (length (lvar-value sequence)))) (if (and test test-not) ;; even though one kwd arg could legit be NIL, it's not interesting. @@ -2195,12 +2591,101 @@ (return-from ,fun-name '(lambda (&rest args) (declare (ignore args)) nil)))) (let ((effective-test - (unless test-not - (if test (lvar-fun-name* test) 'eql))) + (unless test-not + (if test (lvar-fun-name* test) 'eql))) (test-form '(effective-find-position-test test test-not)) (const-seq (when (constant-lvar-p sequence) (lvar-value sequence)))) - ,@preamble + ;; Destructive modification of constants is illegal. + ;; Therefore if this sequence would have been output as a code header + ;; constant, its contents can't change. We don't need to reference + ;; the sequence itself to compare elements. + ;; There are two transforms to try in this situation: + ;; 1) Use CASE if the sequence contains only perfectly-hashed symbols. + ;; There is no upper limit on the sequence length- as it increases, + ;; so does the bias against using a series of IFs. In fact, CASE + ;; might even consider the constant-returning mode to allow + ;; some hash colllisions, which it doesn't currently. + ;; 2) Otherwise, use COND, not to exceed some length limit. + (when (and const-seq + (member effective-test '(eql eq char= char-equal)) + (not start) (not end) (not key) + (or (not from-end) (constant-lvar-p from-end))) + (let ((items (coerce const-seq 'list)) + ;; It seems silly to use :from-end and a constant list + ;; in a way where it actually matters (with repeated elements), + ;; but we either have to do it right or not do it. + (reversedp (and from-end (lvar-value from-end)))) + (when (and (every #'symbolp items) + (memq effective-test '(eql eq)) + ;; PICK-BEST will stupidly hash dups and call that a collision. + (= (pick-best-sxhash-bits (remove-duplicates items) 'sxhash) 1)) + ;; Construct a map from symbol to position so that correct results + ;; are obtained for :from-end, and/or with duplicates present. + ;; Precomputing it is easier than trying to roll the logic into the + ;; production of the result form. :TEST can be ignored. + (let ((map (loop for x in items for i from 0 + collect (cons x + (ecase ',fun-name + (position i) + (find `',x))))) + (clauses) + (seen)) + (dolist (x (if reversedp (reverse map) map)) + (let ((sym (car x))) + (unless (member sym seen) + ;; NIL, T, OTHERWISE need wrapping in () since they should not signify + ;; an empty list of keys or the "otherwise" case respectively. + (push (list (if (memq sym '(nil t otherwise)) + (list sym) + sym) + (cdr x)) + clauses) + (push sym seen)))) + ;; CASE could decide not to use hash-based lookup, as there is a + ;; minimum item count cutoff, but that's ok, the code is good either way. + (return-from ,fun-name + `(lambda (item sequence &rest rest) + (declare (ignore sequence rest)) + (case item + ,@(nreverse clauses) + ;; This CASE looks like it could return NIL, which is potentially + ;; in conflict with the derived type of POSITION when we have already + ;; determined that the item is in the list. So the fallthrough + ;; value has to be numeric. It's actually unreachable. + ,@(when (and (eq ',fun-name 'position) + (csubtypep (lvar-type item) (specifier-type `(member ,@seen)))) + `(((t 0))))))))) + (unless (nthcdr 10 items) + (let ((clauses (loop for x in items for i from 0 + ;; Later transforms will change EQL to EQ if appropriate. + collect `((,effective-test item ',x) + ,(ecase ',fun-name + (position i) + (find + (cond + ((memq effective-test '(eq char=)) + 'item) + ((and (eq effective-test 'eql) + (sb-xc:typep x 'eq-comparable-type)) + 'item) + ((and (eq effective-test 'char-equal) + (not (both-case-p x))) + 'item) + (t + `',x)))))))) + ;; FIXME: dups cause more than one test on the same key because IR1 + ;; doesn't propagate information about which IFs can't possibly match. + ;; FIXME: suffers from same type derivation issue as above. + ;; e.g. (- (position (the (member 10 20) x) #(1 2 5 10 15 20 30))) + ;; -> "Constant NIL conflicts with its asserted type NUMBER." + ;; But a fix for the general case (with any :TEST) has to figure out + ;; whether the returned value must definitely be non-NIL before doing + ;; the same thing as above which we claim is unreachable. + (return-from ,fun-name + `(lambda (item sequence &rest rest) + (declare (ignore sequence rest)) + (cond ,@(if reversedp (nreverse clauses) clauses)))))))) ;; For both FIND and POSITION, try to optimize EQL into EQ. (when (and (eq effective-test 'eql) const-seq @@ -2226,78 +2711,7 @@ (effective-find-position-key key) ,test-form)))))) (define-find-position find 0) - (define-find-position position 1 - ;; Destructive modification of constants is illegal. - ;; Therefore if this sequence would have been output as a code header - ;; constant, its contents can't change. We don't need to reference - ;; the sequence itself to compare elements. - ;; There are two transforms to try in this situation: - ;; 1) Use CASE if the sequence contains only perfectly-hashed symbols. - ;; There is no upper limit on the sequence length- as it increases, - ;; so does the bias against using a series of IFs. In fact, CASE - ;; might even consider the constant-returning mode to allow - ;; some hash colllisions, which it doesn't currently. - ;; 2) Otherwise, use COND, not to exceed some length limit. - ((when (and const-seq - (member effective-test '(eql eq)) - (not start) (not end) (not key) - (or (not from-end) (constant-lvar-p from-end))) - (let ((items (coerce const-seq 'list)) - ;; It seems silly to use :from-end and a constant list - ;; in a way where it actually matters (with repeated elements), - ;; but we either have to do it right or not do it. - (reversedp (and from-end (lvar-value from-end)))) - (when (every #'symbolp items) - ;; PICK-BEST will stupidly hash dups and call that a collision. - (when (= (pick-best-sxhash-bits (remove-duplicates items) 'sxhash) 1) - ;; Construct a map from symbol to position so that correct results - ;; are obtained for :from-end, and/or with duplicates present. - ;; Precomputing it is easier than trying to roll the logic into the - ;; production of the result form. :TEST can be ignored. - (let ((map (loop for x in items for i from 0 - collect (cons x i))) - (clauses) - (seen)) - (dolist (x (if reversedp (reverse map) map)) - (let ((sym (car x))) - (unless (member sym seen) - ;; NIL, T, OTHERWISE need wrapping in () since they should not signify - ;; an empty list of keys or the "otherwise" case respectively. - (push (list (if (memq sym '(nil t otherwise)) - (list sym) - sym) - (cdr x)) - clauses) - (push sym seen)))) - ;; CASE could decide not to use hash-based lookup, as there is a - ;; minimum item count cutoff, but that's ok, the code is good either way. - (return-from position - `(lambda (item sequence &rest rest) - (declare (ignore sequence rest)) - (case item - ,@(nreverse clauses) - ;; This CASE looks like it could return NIL, which is potentially - ;; in conflict with the derived type of POSITION when we have already - ;; determined that the item is in the list. So the fallthrough - ;; value has to be numeric. It's actually unreachable. - ,@(when (csubtypep (lvar-type item) (specifier-type `(member ,@seen))) - `(((t 0)))))))))) - (unless (nthcdr 10 items) - (let ((clauses (loop for x in items for i from 0 - ;; Later transforms will change EQL to EQ if appropriate. - collect `((,effective-test item ',x) ,i)))) - ;; FIXME: dups cause more than one test on the same key because IR1 - ;; doesn't propagate information about which IFs can't possibly match. - ;; FIXME: suffers from same type derivation issue as above. - ;; e.g. (- (position (the (member 10 20) x) #(1 2 5 10 15 20 30))) - ;; -> "Constant NIL conflicts with its asserted type NUMBER." - ;; But a fix for the general case (with any :TEST) has to figure out - ;; whether the returned value must definitely be non-NIL before doing - ;; the same thing as above which we claim is unreachable. - (return-from position - `(lambda (item sequence &rest rest) - (declare (ignore sequence rest)) - (cond ,@(if reversedp (nreverse clauses) clauses))))))))))) + (define-find-position position 1)) (macrolet ((define-find-position-if (fun-name values-index) `(deftransform ,fun-name ((predicate sequence &key @@ -2387,19 +2801,25 @@ (define-trimmer-transform string-trim t t)) -;;; (partially) constant-fold backq-* functions, or convert to their -;;; plain CL equivalent (now that they're not needed for pprinting). -;; Pop constant values from the end, list/list* them if any, and link -;; the remainder with list* at runtime. +;;; Pop anonymous constant values from the end, list/list* them if +;;; any, and link the remainder with list* at runtime. We don't try to +;;; fold named constant references, because while theoretically +;;; possible, in addition to needing to make a load form for a +;;; structure recording the constant name which wraps the constant +;;; value, the dumper would have to learn how to patch constant values +;;; into list structure, to deal with the load form potentially being +;;; evaluated for value earlier than the constant definition is +;;; loaded. (defun transform-backq-list-or-list* (function values) (let ((gensyms (make-gensym-list (length values))) (reverse (reverse values)) (constants '())) (loop while (and reverse - (constant-lvar-p (car reverse))) - do (push (lvar-value (pop reverse)) - constants)) + (constant-lvar-p (car reverse)) + (not (leaf-has-source-name-p + (nth-value 1 (lvar-value (car reverse)))))) + do (push (lvar-value (pop reverse)) constants)) (if (null constants) `(lambda ,gensyms (,function ,@gensyms)) @@ -2420,6 +2840,30 @@ (deftransform sb-impl::|List*| ((&rest elts)) (transform-backq-list-or-list* 'list* elts)) +(deftransform sb-impl::|Vector| ((&rest elts)) + (let ((gensyms (make-gensym-list (length elts))) + constants) + ;; There's not much that can be done with semi-constant vectors- + ;; either we're going to call VECTOR at compile-time or runtime. + ;; There's little point to building up intermediate lists in the partially + ;; constant case. There are ways to expand using MULTIPLE-VALUE-CALL that + ;; might avoid consing intermediate lists if ,@ is involved + ;; though I doubt it would provide benefit to many real-world scenarios. + (dolist (elt elts) + (cond ((and (constant-lvar-p elt) + (not (leaf-has-source-name-p + (nth-value 1 (lvar-value elt))))) + (push (lvar-value elt) constants)) + (t + (setq constants :fail) + (return)))) + `(lambda ,gensyms + ,@(cond ((listp constants) + `((declare (ignore ,@gensyms)) + ,(apply 'vector (nreverse constants)))) + (t + `((vector ,@gensyms))))))) + ;; Merge adjacent constant values (deftransform sb-impl::|Append| ((&rest elts)) (let ((gensyms (make-gensym-list (length elts))) @@ -2492,7 +2936,6 @@ (give-up-ir1-transform))))) (defoptimizer (union derive-type) ((list1 list2 &rest args)) - (declare (ignore args)) (let ((cons-type (specifier-type 'cons))) (if (or (csubtypep (lvar-type list1) cons-type) (csubtypep (lvar-type list2) cons-type)) @@ -2500,7 +2943,6 @@ (specifier-type 'list)))) (defoptimizer (nunion derive-type) ((list1 list2 &rest args)) - (declare (ignore args)) (let ((cons-type (specifier-type 'cons))) (if (or (csubtypep (lvar-type list1) cons-type) (csubtypep (lvar-type list2) cons-type)) @@ -2563,3 +3005,109 @@ `(sb-impl::tree-equal-eql list1 list2)) (t (give-up-ir1-transform)))) + +(defun vector-type-length (type) + (catch 'give-up-ir1-transform + (return-from + vector-type-length + (let* ((dim (array-type-dimensions-or-give-up type))) + (when (and (typep dim '(cons integer null)) + (not (conservative-array-type-complexp type))) + (first dim))))) + nil) + +(defoptimizer (reduce derive-type) ((fun sequence + &key + initial-value + key + start + end + &allow-other-keys)) + (multiple-value-bind (fun-type name) (lvar-fun-type fun) + (when (fun-type-p fun-type) + (let* ((initial-value-type (and initial-value + (lvar-type initial-value))) + (sequence-type (lvar-type sequence)) + (element-type + (cond ((and key + (multiple-value-bind (key-type name) (lvar-fun-type key) + (cond ((eq name 'identity) + nil) + ((fun-type-p key-type) + (single-value-type (fun-type-returns key-type))) + (t + *universal-type*))))) + ((csubtypep sequence-type (specifier-type 'array)) + (let ((upgraded-type + (array-type-upgraded-element-type sequence-type))) + (if (eq upgraded-type *wild-type*) + *universal-type* + upgraded-type))))) + (end (if end + (and (constant-lvar-p end) + (or (lvar-value end) + (vector-type-length sequence-type))) + (vector-type-length sequence-type))) + (start (if start + (and (constant-lvar-p start) + (lvar-value start)) + 0)) + (length (and start end + (- end start)))) + ;; Calling the type deriver would be more universal, but + ;; type derivers expect a combination, but even then there's + ;; not a lot of standard functions which are usually used + ;; with REDUCE and which benefit from improved type + ;; derivation. + (or + (when (and (eq name '+) + element-type + (neq element-type *wild-type*) + (neq element-type *universal-type*)) + (let* ((non-empty (typep length '(integer 1))) + (identity-p (and (not initial-value) + (not non-empty)))) + (labels ((try (type) + (let ((type (specifier-type type))) + (when (csubtypep element-type type) + (cond (identity-p + (type-union type + (specifier-type '(eql 0)))) + (initial-value + (let ((contagion (numeric-contagion type initial-value-type + :rational nil + :unsigned t))) + (if non-empty + contagion + (type-union contagion initial-value-type)))) + (t + type)))))) + (some #'try '(double-float single-float float unsigned-byte integer rational real))))) + (let ((fun-result (single-value-type (fun-type-returns fun-type)))) + (cond (initial-value-type + (type-union initial-value-type fun-result)) + ((typep length '(integer 2)) + fun-result) + (element-type + (type-union fun-result element-type))))))))) + +(defoptimizer (nth derive-type) ((n list)) + (when (constant-lvar-p list) + (let* ((list (lvar-value list)) + (rest list) + type + (seen (list list))) + (loop for element = (pop rest) + do (setf type + (if type + (type-union (ctype-of element) type) + (ctype-of element))) + until (or (memq rest seen) + (atom rest)) + do (push rest seen) + finally (unless (or rest + (let ((n-int (type-approximate-interval (lvar-type n)))) + (and n-int + (interval<n n-int (length list))))) + (setf type (type-union (specifier-type 'null) type)))) + type))) diff --git a/src/compiler/sparc/alloc.lisp b/src/compiler/sparc/alloc.lisp index d31dd93442..8188806f79 100644 --- a/src/compiler/sparc/alloc.lisp +++ b/src/compiler/sparc/alloc.lisp @@ -12,26 +12,18 @@ (in-package "SB-VM") ;;;; LIST and LIST* -(define-vop (list-or-list*) - (:args (things :more t)) +(define-vop (list) + (:args (things :more t :scs (any-reg descriptor-reg zero null control-stack))) (:temporary (:scs (descriptor-reg)) ptr) (:temporary (:scs (descriptor-reg)) temp) (:temporary (:scs (descriptor-reg) :to (:result 0) :target result) res) (:temporary (:scs (non-descriptor-reg)) alloc-temp) - (:info num) + (:info star cons-cells) (:results (result :scs (descriptor-reg))) - (:variant-vars star) - (:policy :safe) (:node-var node) (:generator 0 - (cond ((zerop num) - (move result null-tn)) - ((and star (= num 1)) - (move result (tn-ref-tn things))) - (t - (macrolet - ((maybe-load (tn) + (macrolet ((maybe-load (tn) (once-only ((tn tn)) `(sc-case ,tn ((any-reg descriptor-reg zero null) @@ -39,10 +31,9 @@ (control-stack (load-stack-tn temp ,tn) temp))))) - (let* ((dx-p (node-stack-allocate-p node)) - (cons-cells (if star (1- num) num)) - (alloc (* (pad-data-block cons-size) cons-cells))) - (pseudo-atomic () + (let ((dx-p (node-stack-allocate-p node)) + (alloc (* (pad-data-block cons-size) cons-cells))) + (pseudo-atomic (temp) (allocation 'list alloc list-pointer-lowtag res :stack-p dx-p :temp-tn alloc-temp) @@ -61,14 +52,7 @@ (maybe-load (tn-ref-tn (tn-ref-across things))) null-tn) ptr cons-cdr-slot list-pointer-lowtag)) - (move result res))))))) - -(define-vop (list list-or-list*) - (:variant nil)) - -(define-vop (list* list-or-list*) - (:variant t)) - + (move result res))))) ;;;; Special purpose inline allocators. @@ -95,7 +79,7 @@ (:generator 10 (let* ((size (+ length closure-info-offset)) (alloc-size (pad-data-block size))) - (pseudo-atomic () + (pseudo-atomic (temp) (allocation nil alloc-size fun-pointer-lowtag result :stack-p stack-allocate-p :temp-tn temp) @@ -132,15 +116,15 @@ (define-vop (fixed-alloc) (:args) (:info name words type lowtag stack-allocate-p) - (:ignore name stack-allocate-p) + (:ignore name) (:results (result :scs (descriptor-reg))) (:temporary (:scs (non-descriptor-reg)) temp) (:generator 4 - (pseudo-atomic () - (allocation nil (pad-data-block words) lowtag result :temp-tn temp) - (when type - (inst li temp (logior (ash (1- words) (length-field-shift type)) type)) - (storew temp result 0 lowtag))))) + (pseudo-atomic (temp) + (allocation nil (pad-data-block words) lowtag result :temp-tn temp + :stack-p stack-allocate-p) + (inst li temp (compute-object-header words type)) + (storew temp result 0 lowtag)))) (define-vop (var-alloc) (:args (extra :scs (any-reg))) @@ -161,6 +145,6 @@ (t (inst add header header (+ (ash -2 (length-field-shift type)) type)) (inst and bytes (lognot lowtag-mask)))) - (pseudo-atomic () + (pseudo-atomic (temp) (allocation nil bytes lowtag result :temp-tn temp) (storew header result 0 lowtag)))) diff --git a/src/compiler/sparc/arith.lisp b/src/compiler/sparc/arith.lisp index 485cfb2291..5bb6c12e4d 100644 --- a/src/compiler/sparc/arith.lisp +++ b/src/compiler/sparc/arith.lisp @@ -650,7 +650,7 @@ fast-ash-left/unsigned=>unsigned)) (deftransform ash-left-mod32 ((integer count) ((unsigned-byte 32) (unsigned-byte 5))) - (when (sb-c::constant-lvar-p count) + (when (sb-c:constant-lvar-p count) (sb-c::give-up-ir1-transform)) '(%primitive fast-ash-left-mod32/unsigned=>unsigned integer count)) @@ -769,25 +769,19 @@ ;;;; 32-bit logical operations -(define-vop (shift-towards-someplace) - (:policy :fast-safe) - (:args (num :scs (unsigned-reg)) - (amount :scs (signed-reg))) - (:arg-types unsigned-num tagged-num) - (:results (r :scs (unsigned-reg))) - (:result-types unsigned-num)) - -(define-vop (shift-towards-start shift-towards-someplace) - (:translate shift-towards-start) - (:note "shift-towards-start") - (:generator 1 - (inst sll r num amount))) - -(define-vop (shift-towards-end shift-towards-someplace) - (:translate shift-towards-end) - (:note "shift-towards-end") - (:generator 1 - (inst srl r num amount))) +(macrolet ((define (translate operation) + `(define-vop () + (:translate ,translate) + (:note ,(string translate)) + (:policy :fast-safe) + (:args (num :scs (unsigned-reg)) + (amount :scs (signed-reg))) + (:arg-types unsigned-num tagged-num) + (:results (r :scs (unsigned-reg))) + (:result-types unsigned-num) + (:generator 1 (inst ,operation r num amount))))) + (define shift-towards-start sll) + (define shift-towards-end srl)) ;;;; Bignum stuff. (define-vop (bignum-length get-header-data) @@ -810,9 +804,7 @@ (:args (object :scs (descriptor-reg)) (index :scs (any-reg immediate zero)) (value :scs (unsigned-reg))) - (:arg-types t positive-fixnum unsigned-num) - (:results (result :scs (unsigned-reg))) - (:result-types unsigned-num)) + (:arg-types t positive-fixnum unsigned-num)) (define-vop (digit-0-or-plus) (:translate sb-bignum:%digit-0-or-plusp) diff --git a/src/compiler/sparc/array.lisp b/src/compiler/sparc/array.lisp index 306fb55861..018cfc4d06 100644 --- a/src/compiler/sparc/array.lisp +++ b/src/compiler/sparc/array.lisp @@ -23,13 +23,15 @@ (:temporary (:scs (non-descriptor-reg)) gencgc-temp) (:results (result :scs (descriptor-reg))) (:generator 0 - (pseudo-atomic () + (pseudo-atomic (gencgc-temp) (inst add ndescr rank (+ (* array-dimensions-offset n-word-bytes) lowtag-mask)) (inst andn ndescr lowtag-mask) (allocation nil ndescr other-pointer-lowtag header :temp-tn gencgc-temp) - (inst add ndescr rank (fixnumize (1- array-dimensions-offset))) - (inst sll ndescr ndescr n-widetag-bits) + ;; Compute the encoded rank. See ENCODE-ARRAY-RANK. + (inst sub ndescr rank (fixnumize 1)) + (inst and ndescr ndescr (fixnumize array-rank-mask)) + (inst sll ndescr ndescr array-rank-position) (inst or ndescr ndescr type) ;; Remove the extraneous fixnum tag bits because TYPE and RANK ;; were fixnums @@ -48,17 +50,17 @@ (:policy :fast-safe) (:variant array-dimensions-offset other-pointer-lowtag)) -(define-vop (array-rank-vop) +(define-vop () (:translate %array-rank) (:policy :fast-safe) (:args (x :scs (descriptor-reg))) - (:temporary (:scs (non-descriptor-reg)) temp) - (:results (res :scs (any-reg descriptor-reg))) + (:results (res :scs (unsigned-reg))) + (:result-types positive-fixnum) (:generator 6 - (loadw temp x 0 other-pointer-lowtag) - (inst sra temp n-widetag-bits) - (inst sub temp (1- array-dimensions-offset)) - (inst sll res temp n-fixnum-tag-bits))) + ;; 2 = ARRAY-RANK-POSITION adjusted for endianness + (inst ldub res x (- 2 other-pointer-lowtag)) ; big-endian only + (inst add res res 1) + (inst and res res array-rank-mask))) ;;;; Bounds checking routine. (define-vop (check-bound) @@ -100,9 +102,7 @@ (:arg-types ,type positive-fixnum ,element-type) (:args (object :scs (descriptor-reg)) (index :scs (any-reg zero immediate)) - (value :scs ,scs)) - (:results (result :scs ,scs)) - (:result-types ,element-type))))) + (value :scs ,scs)))))) (def-data-vector-frobs simple-base-string byte-index character character-reg) @@ -191,10 +191,8 @@ (:policy :fast-safe) (:args (object :scs (descriptor-reg)) (index :scs (unsigned-reg) :target shift) - (value :scs (unsigned-reg zero immediate) :target result)) + (value :scs (unsigned-reg zero immediate))) (:arg-types ,type positive-fixnum positive-fixnum) - (:results (result :scs (unsigned-reg))) - (:result-types positive-fixnum) (:temporary (:scs (non-descriptor-reg)) temp old offset) (:temporary (:scs (non-descriptor-reg) :from (:argument 1)) shift) (:generator 25 @@ -221,23 +219,16 @@ (inst and temp value ,(1- (ash 1 bits))))) (inst sll temp shift) (inst or old temp)) - (inst st old object offset) - (sc-case value - (immediate - (inst li result (tn-value value))) - (t - (move result value))))) + (inst st old object offset))) (define-vop (,(symbolicate "DATA-VECTOR-SET-C/" type)) (:translate data-vector-set) (:policy :fast-safe) (:args (object :scs (descriptor-reg)) - (value :scs (unsigned-reg zero immediate) :target result)) + (value :scs (unsigned-reg zero immediate))) (:arg-types ,type (:constant index) positive-fixnum) (:info index) - (:results (result :scs (unsigned-reg))) - (:result-types positive-fixnum) (:temporary (:scs (non-descriptor-reg)) offset-reg temp old) (:generator 20 (multiple-value-bind (word extra) (floor index ,elements-per-word) @@ -279,12 +270,7 @@ (inst or old temp))) (if (typep offset '(signed-byte 13)) (inst st old object offset) - (inst st old object offset-reg))) - (sc-case value - (immediate - (inst li result (tn-value value))) - (t - (move result value)))))))))) + (inst st old object offset-reg)))))))))) (def-small-data-vector-frobs simple-bit-vector 1) (def-small-data-vector-frobs simple-array-unsigned-byte-2 2) @@ -313,18 +299,14 @@ (:policy :fast-safe) (:args (object :scs (descriptor-reg)) (index :scs (any-reg)) - (value :scs (single-reg) :target result)) + (value :scs (single-reg))) (:arg-types simple-array-single-float positive-fixnum single-float) - (:results (result :scs (single-reg))) - (:result-types single-float) (:temporary (:scs (non-descriptor-reg)) offset) (:generator 5 (inst add offset index (- (* vector-data-offset n-word-bytes) other-pointer-lowtag)) - (inst stf value object offset) - (unless (location= result value) - (inst fmovs result value)))) + (inst stf value object offset))) (define-vop (data-vector-ref/simple-array-double-float) (:note "inline array access") @@ -348,18 +330,14 @@ (:policy :fast-safe) (:args (object :scs (descriptor-reg)) (index :scs (any-reg)) - (value :scs (double-reg) :target result)) + (value :scs (double-reg))) (:arg-types simple-array-double-float positive-fixnum double-float) - (:results (result :scs (double-reg))) - (:result-types double-float) (:temporary (:scs (non-descriptor-reg)) offset) (:generator 20 (inst sll offset index 1) (inst add offset (- (* vector-data-offset n-word-bytes) other-pointer-lowtag)) - (inst stdf value object offset) - (unless (location= result value) - (move-double-reg result value)))) + (inst stdf value object offset))) #+long-float (define-vop (data-vector-ref/simple-array-long-float) @@ -415,9 +393,7 @@ (:arg-types simple-array-signed-byte-8 positive-fixnum tagged-num) (:args (object :scs (descriptor-reg)) (index :scs (any-reg zero immediate)) - (value :scs (signed-reg))) - (:results (result :scs (signed-reg))) - (:result-types tagged-num)) + (value :scs (signed-reg)))) (define-vop (data-vector-ref/simple-array-signed-byte-16 @@ -436,9 +412,7 @@ (:arg-types simple-array-signed-byte-16 positive-fixnum tagged-num) (:args (object :scs (descriptor-reg)) (index :scs (any-reg zero immediate)) - (value :scs (signed-reg))) - (:results (result :scs (signed-reg))) - (:result-types tagged-num)) + (value :scs (signed-reg)))) ;;; Complex float arrays. @@ -467,29 +441,21 @@ (:note "inline array store") (:translate data-vector-set) (:policy :fast-safe) - (:args (object :scs (descriptor-reg) :to :result) + (:args (object :scs (descriptor-reg)) (index :scs (any-reg)) - (value :scs (complex-single-reg) :target result)) + (value :scs (complex-single-reg))) (:arg-types simple-array-complex-single-float positive-fixnum complex-single-float) - (:results (result :scs (complex-single-reg))) - (:result-types complex-single-float) (:temporary (:scs (non-descriptor-reg) :from (:argument 1)) offset) (:generator 5 - (let ((value-real (complex-single-reg-real-tn value)) - (result-real (complex-single-reg-real-tn result))) + (let ((value-real (complex-single-reg-real-tn value))) (inst sll offset index 1) (inst add offset (- (* vector-data-offset n-word-bytes) other-pointer-lowtag)) - (inst stf value-real object offset) - (unless (location= result-real value-real) - (inst fmovs result-real value-real))) - (let ((value-imag (complex-single-reg-imag-tn value)) - (result-imag (complex-single-reg-imag-tn result))) + (inst stf value-real object offset)) + (let ((value-imag (complex-single-reg-imag-tn value))) (inst add offset n-word-bytes) - (inst stf value-imag object offset) - (unless (location= result-imag value-imag) - (inst fmovs result-imag value-imag))))) + (inst stf value-imag object offset)))) (define-vop (data-vector-ref/simple-array-complex-double-float) (:note "inline array access") @@ -515,29 +481,21 @@ (:note "inline array store") (:translate data-vector-set) (:policy :fast-safe) - (:args (object :scs (descriptor-reg) :to :result) + (:args (object :scs (descriptor-reg)) (index :scs (any-reg)) - (value :scs (complex-double-reg) :target result)) + (value :scs (complex-double-reg))) (:arg-types simple-array-complex-double-float positive-fixnum complex-double-float) - (:results (result :scs (complex-double-reg))) - (:result-types complex-double-float) (:temporary (:scs (non-descriptor-reg) :from (:argument 1)) offset) (:generator 20 - (let ((value-real (complex-double-reg-real-tn value)) - (result-real (complex-double-reg-real-tn result))) + (let ((value-real (complex-double-reg-real-tn value))) (inst sll offset index 2) (inst add offset (- (* vector-data-offset n-word-bytes) other-pointer-lowtag)) - (inst stdf value-real object offset) - (unless (location= result-real value-real) - (move-double-reg result-real value-real))) - (let ((value-imag (complex-double-reg-imag-tn value)) - (result-imag (complex-double-reg-imag-tn result))) + (inst stdf value-real object offset)) + (let ((value-imag (complex-double-reg-imag-tn value))) (inst add offset (* 2 n-word-bytes)) - (inst stdf value-imag object offset) - (unless (location= result-imag value-imag) - (move-double-reg result-imag value-imag))))) + (inst stdf value-imag object offset)))) #+long-float (define-vop (data-vector-ref/simple-array-complex-long-float) @@ -606,6 +564,4 @@ (index :scs (any-reg zero immediate)) (value :scs (unsigned-reg))) (:arg-types * tagged-num unsigned-num) - (:results (result :scs (unsigned-reg))) - (:result-types unsigned-num) (:variant vector-data-offset other-pointer-lowtag)) diff --git a/src/compiler/sparc/c-call.lisp b/src/compiler/sparc/c-call.lisp index 1a941a6015..b437a5f9cb 100644 --- a/src/compiler/sparc/c-call.lisp +++ b/src/compiler/sparc/c-call.lisp @@ -97,8 +97,8 @@ (make-result-state)))))) (deftransform %alien-funcall ((function type &rest args)) - (aver (sb-c::constant-lvar-p type)) - (let* ((type (sb-c::lvar-value type)) + (aver (sb-c:constant-lvar-p type)) + (let* ((type (sb-c:lvar-value type)) (arg-types (alien-fun-type-arg-types type)) (result-type (alien-fun-type-result-type type))) (aver (= (length arg-types) (length args))) @@ -197,10 +197,9 @@ (:info foreign-symbol) (:results (res :scs (sap-reg))) (:result-types system-area-pointer) - (:temporary (:scs (non-descriptor-reg)) addr) (:generator 2 - (inst li addr (make-fixup foreign-symbol :foreign-dataref)) - (loadw res addr))) + (inst li res (make-fixup foreign-symbol :foreign-dataref)) + (loadw res res))) (define-vop (call-out) (:args (function :scs (sap-reg) :target cfunc) diff --git a/src/compiler/sparc/call.lisp b/src/compiler/sparc/call.lisp index 5a7301fcb7..23c8eb9eac 100644 --- a/src/compiler/sparc/call.lisp +++ b/src/compiler/sparc/call.lisp @@ -41,14 +41,14 @@ ;;; them at a known location. (defun make-old-fp-save-location (env) (specify-save-tn - (physenv-debug-live-tn (make-normal-tn *fixnum-primitive-type*) env) + (environment-debug-live-tn (make-normal-tn *fixnum-primitive-type*) env) (make-wired-tn *fixnum-primitive-type* control-stack-arg-scn ocfp-save-offset))) (defun make-return-pc-save-location (env) (specify-save-tn - (physenv-debug-live-tn (make-normal-tn *backend-t-primitive-type*) env) + (environment-debug-live-tn (make-normal-tn *backend-t-primitive-type*) env) (make-wired-tn *backend-t-primitive-type* control-stack-arg-scn lra-save-offset))) @@ -141,7 +141,7 @@ (move res csp-tn) (inst add csp-tn csp-tn (* n-word-bytes (sb-allocated-size 'control-stack))) - (when (ir2-physenv-number-stack-p callee) + (when (ir2-environment-number-stack-p callee) (inst sub nsp-tn (bytes-needed-for-non-descriptor-stack-frame)) (inst add nfp nsp-tn number-stack-displacement)))) @@ -352,8 +352,7 @@ default-value-8 values-start) (:temporary (:sc any-reg :offset nargs-offset :from :eval :to (:result 1)) - nvals) - (:temporary (:scs (non-descriptor-reg)) temp)) + nvals)) ;;; This hook in the codegen pass lets us insert code before fall-thru entry @@ -436,6 +435,7 @@ default-value-8 (:ignore args save) (:vop-var vop) (:temporary (:sc control-stack :offset nfp-save-offset) nfp-save) + (:temporary (:scs (non-descriptor-reg)) temp) (:generator 20 (let ((label (gen-label)) (cur-nfp (current-nfp-tn vop))) @@ -1061,6 +1061,20 @@ default-value-8 (:variant 0 0) (:translate %more-arg)) +(define-vop (more-arg-or-nil) + (:policy :fast-safe) + (:args (object :scs (descriptor-reg) :to (:result 1)) + (count :scs (any-reg))) + (:info index) + (:results (value :scs (descriptor-reg any-reg))) + (:result-types *) + (:generator 3 + (inst cmp count (fixnumize index)) + (inst b :le done) + (move value null-tn) + (loadw value object index) + done)) + ;;; Turn more arg (context, count) into a list. (define-vop () (:args (context-arg :target context :scs (descriptor-reg)) @@ -1087,7 +1101,7 @@ default-value-8 (move result null-tn) ;; We need to do this atomically. - (pseudo-atomic () + (pseudo-atomic (temp) ;; Allocate a cons (2 words) for each item. (inst sll temp count 1) (allocation 'list temp list-pointer-lowtag result diff --git a/src/compiler/sparc/cell.lisp b/src/compiler/sparc/cell.lisp index 4dc3495118..4b712916da 100644 --- a/src/compiler/sparc/cell.lisp +++ b/src/compiler/sparc/cell.lisp @@ -29,10 +29,6 @@ (:results) (:generator 1 (storew value object offset lowtag))) - -(define-vop (init-slot set-slot) - (:info name dx-p offset lowtag) - (:ignore name dx-p)) ;;;; Symbol hacking VOPs: @@ -50,9 +46,8 @@ (:temporary (:scs (descriptor-reg) :from (:argument 0)) obj-temp)) ;;; With Symbol-Value, we check that the value isn't the trap object. -;;; So Symbol-Value of NIL is NIL. (define-vop (symbol-value checked-cell-ref) - (:translate symeval) + (:translate symbol-value) (:generator 9 (move obj-temp object) (loadw value obj-temp symbol-value-slot other-pointer-lowtag) @@ -63,14 +58,12 @@ ;;; Like CHECKED-CELL-REF, only we are a predicate to see if the cell ;;; is bound. -(define-vop (boundp-frob) +(define-vop (boundp) (:args (object :scs (descriptor-reg))) (:conditional) (:info target not-p) (:policy :fast-safe) - (:temporary (:scs (descriptor-reg)) value)) - -(define-vop (boundp boundp-frob) + (:temporary (:scs (descriptor-reg)) value) (:translate boundp) (:generator 9 (loadw value object symbol-value-slot other-pointer-lowtag) @@ -81,7 +74,7 @@ (define-vop (fast-symbol-value cell-ref) (:variant symbol-value-slot other-pointer-lowtag) (:policy :fast) - (:translate symeval)) + (:translate symbol-value)) (define-vop (symbol-hash) (:policy :fast-safe) @@ -89,20 +82,22 @@ (:args (symbol :scs (descriptor-reg))) (:results (res :scs (any-reg))) (:result-types positive-fixnum) + (:args-var args) (:generator 2 ;; The symbol-hash slot of NIL holds NIL because it is also the ;; cdr slot, so we have to strip off the two low bits to make sure ;; it is a fixnum. The lowtag selection magic that is required to ;; ensure this is explained in the comment in objdef.lisp (loadw res symbol symbol-hash-slot other-pointer-lowtag) - (inst andn res res fixnum-tag-mask))) + (unless (not-nil-tn-ref-p args) + (inst andn res res fixnum-tag-mask)))) ;;; On unithreaded builds these are just copies of the non-global versions. (define-vop (%set-symbol-global-value set)) (define-vop (symbol-global-value symbol-value) - (:translate sym-global-val)) + (:translate symbol-global-value)) (define-vop (fast-symbol-global-value fast-symbol-value) - (:translate sym-global-val)) + (:translate symbol-global-value)) ;;;; FDEFINITION (fdefn) objects. (define-vop (fdefn-fun cell-ref) @@ -147,15 +142,12 @@ (define-vop (fdefn-makunbound) (:policy :fast-safe) (:translate fdefn-makunbound) - (:args (fdefn :scs (descriptor-reg) :target result)) + (:args (fdefn :scs (descriptor-reg))) (:temporary (:scs (non-descriptor-reg)) temp) - (:results (result :scs (descriptor-reg))) (:generator 38 (storew null-tn fdefn fdefn-fun-slot other-pointer-lowtag) (inst li temp (make-fixup 'undefined-tramp :assembly-routine)) - (storew temp fdefn fdefn-raw-addr-slot other-pointer-lowtag) - (move result fdefn))) - + (storew temp fdefn fdefn-raw-addr-slot other-pointer-lowtag))) ;;;; Binding and Unbinding. @@ -223,14 +215,14 @@ (:variant closure-info-offset fun-pointer-lowtag) (:translate %closure-index-ref)) +(define-vop (%closure-index-set word-index-set) + (:variant closure-info-offset fun-pointer-lowtag) + (:translate %closure-index-set)) + (define-vop (funcallable-instance-info word-index-ref) (:variant funcallable-instance-info-offset fun-pointer-lowtag) (:translate %funcallable-instance-info)) -(define-vop (set-funcallable-instance-info word-index-set) - (:variant funcallable-instance-info-offset fun-pointer-lowtag) - (:translate %set-funcallable-instance-info)) - (define-vop (closure-ref) (:args (object :scs (descriptor-reg))) (:results (value :scs (descriptor-reg any-reg))) @@ -290,12 +282,37 @@ (:policy :fast-safe) (:variant 0 other-pointer-lowtag)) -(define-vop (code-header-set word-index-set) +(define-vop (code-header-set) (:translate code-header-set) (:policy :fast-safe) - (:variant 0 other-pointer-lowtag)) - - + (:args (object :scs (descriptor-reg)) + (index :scs (any-reg)) + (value :scs (any-reg descriptor-reg))) + (:arg-types * tagged-num *) + (:temporary (:scs (non-descriptor-reg)) temp card) + (:generator 10 + ;; Load the card mask + (inst li temp (make-fixup "gc_card_table_mask" :foreign-dataref)) ; linkage entry + (inst ld temp temp) ; address of gc_card_table_mask + (inst ld temp temp) ; value of gc_card_table_mask + (pseudo-atomic (temp) + ;; Compute card mark index + (inst srl card object gencgc-card-shift) + (inst and card card temp) + ;; Load mark table base + (inst li temp (make-fixup "gc_card_mark" :foreign-dataref)) ; linkage entry + (inst ld temp temp) ; address of gc_card_mark + (inst ld temp temp) ; value of gc_card_mark + ;; Touch the card mark byte. + (inst stb null-tn temp card) + ;; set 'written' flag in the code header + ;; If two threads get here at the same time, they'll write the same byte. + (let ((byte #+big-endian (- other-pointer-lowtag) #+little-endian (bug "Wat"))) + (inst ldub temp object byte) + (inst or temp temp #x40) + (inst stb temp object byte)) + (inst add temp index (- other-pointer-lowtag)) + (inst st value object temp)))) ;;;; raw instance slot accessors @@ -322,18 +339,15 @@ (index :scs (any-reg)) (value :scs (,sc))) (:arg-types * positive-fixnum ,result-type) - (:results (result :scs (,sc))) (:temporary (:scs (non-descriptor-reg)) offset) - (:result-types ,result-type) (:generator 5 (inst add offset index (- (ash instance-slots-offset word-shift) instance-pointer-lowtag)) - (inst st value object offset) - (move result value)))))) + (inst st value object offset)))))) (def "" unsigned-reg unsigned-num) (def "SIGNED-" signed-reg signed-num)) -(define-vop (raw-instance-ref/single) +(define-vop () (:translate %raw-instance-ref/single) (:policy :fast-safe) (:args (object :scs (descriptor-reg)) @@ -347,24 +361,20 @@ instance-pointer-lowtag)) (inst ldf value object offset))) -(define-vop (raw-instance-set/single) +(define-vop () (:translate %raw-instance-set/single) (:policy :fast-safe) (:args (object :scs (descriptor-reg)) (index :scs (any-reg)) - (value :scs (single-reg) :target result)) + (value :scs (single-reg))) (:arg-types * positive-fixnum single-float) - (:results (result :scs (single-reg))) - (:result-types single-float) (:temporary (:scs (non-descriptor-reg)) offset) (:generator 5 (inst add offset index (- (ash instance-slots-offset word-shift) instance-pointer-lowtag)) - (inst stf value object offset) - (unless (location= result value) - (inst fmovs result value)))) + (inst stf value object offset))) -(define-vop (raw-instance-ref/double) +(define-vop () (:translate %raw-instance-ref/double) (:policy :fast-safe) (:args (object :scs (descriptor-reg)) @@ -378,24 +388,20 @@ instance-pointer-lowtag)) (inst lddf value object offset))) -(define-vop (raw-instance-set/double) +(define-vop () (:translate %raw-instance-set/double) (:policy :fast-safe) (:args (object :scs (descriptor-reg)) (index :scs (any-reg)) - (value :scs (double-reg) :target result)) + (value :scs (double-reg))) (:arg-types * positive-fixnum double-float) - (:results (result :scs (double-reg))) - (:result-types double-float) (:temporary (:scs (non-descriptor-reg)) offset) (:generator 5 (inst add offset index (- (ash instance-slots-offset word-shift) instance-pointer-lowtag)) - (inst stdf value object offset) - (unless (location= result value) - (move-double-reg result value)))) + (inst stdf value object offset))) -(define-vop (raw-instance-ref/complex-single) +(define-vop () (:translate %raw-instance-ref/complex-single) (:policy :fast-safe) (:args (object :scs (descriptor-reg)) @@ -411,32 +417,22 @@ (inst add offset offset n-word-bytes) (inst ldf (complex-single-reg-imag-tn value) object offset))) -(define-vop (raw-instance-set/complex-single) +(define-vop () (:translate %raw-instance-set/complex-single) (:policy :fast-safe) (:args (object :scs (descriptor-reg)) (index :scs (any-reg)) - (value :scs (complex-single-reg) :target result)) + (value :scs (complex-single-reg))) (:arg-types * positive-fixnum complex-single-float) - (:results (result :scs (complex-single-reg))) - (:result-types complex-single-float) (:temporary (:scs (non-descriptor-reg)) offset) (:generator 5 (inst add offset index (- (ash instance-slots-offset word-shift) instance-pointer-lowtag)) - (let ((value-real (complex-single-reg-real-tn value)) - (result-real (complex-single-reg-real-tn result))) - (inst stf value-real object offset) - (unless (location= result-real value-real) - (inst fmovs result-real value-real))) + (inst stf (complex-single-reg-real-tn value) object offset) (inst add offset offset n-word-bytes) - (let ((value-imag (complex-single-reg-imag-tn value)) - (result-imag (complex-single-reg-imag-tn result))) - (inst stf value-imag object offset) - (unless (location= result-imag value-imag) - (inst fmovs result-imag value-imag))))) + (inst stf (complex-single-reg-imag-tn value) object offset))) -(define-vop (raw-instance-ref/complex-double) +(define-vop () (:translate %raw-instance-ref/complex-double) (:policy :fast-safe) (:args (object :scs (descriptor-reg)) @@ -452,27 +448,17 @@ (inst add offset offset (* 2 n-word-bytes)) (inst lddf (complex-double-reg-imag-tn value) object offset))) -(define-vop (raw-instance-set/complex-double) +(define-vop () (:translate %raw-instance-set/complex-double) (:policy :fast-safe) (:args (object :scs (descriptor-reg)) (index :scs (any-reg)) - (value :scs (complex-double-reg) :target result)) + (value :scs (complex-double-reg))) (:arg-types * positive-fixnum complex-double-float) - (:results (result :scs (complex-double-reg))) - (:result-types complex-double-float) (:temporary (:scs (non-descriptor-reg)) offset) (:generator 5 (inst add offset index (- (ash instance-slots-offset word-shift) instance-pointer-lowtag)) - (let ((value-real (complex-double-reg-real-tn value)) - (result-real (complex-double-reg-real-tn result))) - (inst stdf value-real object offset) - (unless (location= result-real value-real) - (move-double-reg result-real value-real))) + (inst stdf (complex-double-reg-real-tn value) object offset) (inst add offset offset (* 2 n-word-bytes)) - (let ((value-imag (complex-double-reg-imag-tn value)) - (result-imag (complex-double-reg-imag-tn result))) - (inst stdf value-imag object offset) - (unless (location= result-imag value-imag) - (move-double-reg result-imag value-imag))))) + (inst stdf (complex-double-reg-imag-tn value) object offset))) diff --git a/src/compiler/sparc/char.lisp b/src/compiler/sparc/char.lisp index c23cbd8471..b8a49b89cd 100644 --- a/src/compiler/sparc/char.lisp +++ b/src/compiler/sparc/char.lisp @@ -139,7 +139,7 @@ (:note "inline constant comparison") (:variant-vars condition not-condition) (:generator 2 - (inst cmp x (sb-xc:char-code y)) + (inst cmp x (char-code y)) (inst b (if not-p not-condition condition) target) (inst nop))) diff --git a/src/compiler/sparc/debug.lisp b/src/compiler/sparc/debug.lisp index 1fe3a059f8..92022dc1df 100644 --- a/src/compiler/sparc/debug.lisp +++ b/src/compiler/sparc/debug.lisp @@ -19,7 +19,7 @@ (:generator 1 (move res csp-tn))) -(define-vop () +(define-vop (current-fp-sap) (:translate current-fp) (:policy :fast-safe) (:results (res :scs (sap-reg))) @@ -43,13 +43,10 @@ (:policy :fast-safe) (:args (sap :scs (sap-reg)) (offset :scs (any-reg)) - (value :scs (descriptor-reg) :target result)) + (value :scs (descriptor-reg))) (:arg-types system-area-pointer positive-fixnum *) - (:results (result :scs (descriptor-reg))) - (:result-types *) (:generator 5 - (inst st value sap offset) - (move result value))) + (inst st value sap offset))) (define-vop (code-from-mumble) (:policy :fast-safe) diff --git a/src/compiler/sparc/float.lisp b/src/compiler/sparc/float.lisp index 770c48e0e6..dd968cd1f7 100644 --- a/src/compiler/sparc/float.lisp +++ b/src/compiler/sparc/float.lisp @@ -1305,7 +1305,7 @@ (:generator 3 (let ((nfp (current-nfp-tn vop)) (offset (* n-word-bytes (tn-offset temp)))) - (pseudo-atomic () + (pseudo-atomic (my-fsr) ;; Get the current FSR, so we can get the new %fcc's (inst stxfsr nfp offset) (inst ldx my-fsr nfp offset) diff --git a/src/compiler/sparc/insts.lisp b/src/compiler/sparc/insts.lisp index 0de9bd5693..dfdf8113b2 100644 --- a/src/compiler/sparc/insts.lisp +++ b/src/compiler/sparc/insts.lisp @@ -135,9 +135,9 @@ about function addresses and register values.") (operand regname dstate)))))) (defparameter float-reg-symbols - #.(coerce - (loop for n from 0 to 63 collect (make-symbol (format nil "%F~d" n))) - 'vector)) + (coerce + (loop for n from 0 to 63 collect (make-symbol (format nil "%F~d" n))) + 'vector)) (define-arg-type fp-reg :printer (lambda (value stream dstate) @@ -200,8 +200,6 @@ about function addresses and register values.") (define-arg-type branch-fp-condition :printer (coerce branch-fp-conditions 'vector)) -(define-arg-type call-fixup :use-label t) - (deftype fp-branch-condition () `(member ,@branch-fp-conditions)) @@ -370,6 +368,8 @@ about function addresses and register values.") (data :field (byte 22 0) :reader format-2-unimp-data)) (defconstant-eqx f3-printer + ;; FIXME: args are inverted if eliding display of source1, + ;; and I think totally backwards in any case. '(:name :tab (:unless (:same-as rd) rs1 ", ") (:choose rs2 immed) ", " @@ -561,14 +561,8 @@ about function addresses and register values.") '(:reserved :z :lez :lz :reserved :nz :gz :gez) #'equalp) -;;; Why "#.(coerce)" instead of just coerce: as a consequence of revision -;;; c7791afe76, cross-compiled DEFCONSTANT-EQX requires that the assigned -;;; value be "constant per se" - only an expression for which CONSTANTP -;;; returns T. Uses of the constant symbol in cold-load will read its value -;;; from the cold symbol, therefore a literal value must be dumped for it. -;;; A lambda computing the value is no good - it would be target machine code. (defconstant-eqx cond-move-integer-condition-vec - #.(coerce cond-move-integer-conditions 'vector) + (coerce cond-move-integer-conditions 'vector) #'equalp) (deftype cond-move-integer-condition () @@ -758,11 +752,11 @@ about function addresses and register values.") ,printer)) (defconstant-eqx load-printer - '#.(with-ref-format `(:NAME :TAB ,ref-format ", " rd)) + (with-ref-format `(:NAME :TAB ,ref-format ", " rd)) #'equalp) (defconstant-eqx store-printer - '#.(with-ref-format `(:NAME :TAB rd ", " ,ref-format)) + (with-ref-format `(:NAME :TAB rd ", " ,ref-format)) #'equalp) (macrolet ((define-f3-inst (name op op3 &key fixup load-store (dest-kind 'reg) @@ -1938,3 +1932,51 @@ about function addresses and register values.") (define-cond-fp-move-integer fmovrs #b0101) (define-cond-fp-move-integer fmovrd #b0110 :extended t) (define-cond-fp-move-integer fmovrq #b0111 :extended t)) + +(define-instruction-macro load-layout-id (reg layout) + `(without-scheduling () + (inst .layout-id-fixup ,layout) + (inst sethi ,reg 0) + (inst add ,reg #x3ff))) + +;;; The architectures which use the scheduler get angry if DEFINE-INSTRUCTION +;;; lacks the read/write dependency specifications. +;;; But this isn't a real instruction, it's just marks where to fixup. +(sb-assem::%def-inst-encoder + '.layout-id-fixup + (lambda (segment layout) + (sb-c:note-fixup segment :sethi+add (sb-c:make-fixup layout :layout-id)))) + +(defun sb-vm:fixup-code-object (code offset value kind flavor) + (declare (type index offset)) + (unless (zerop (rem offset sb-assem:+inst-alignment-bytes+)) + (error "Unaligned instruction? offset=#x~X." offset)) + (let ((sap (code-instructions code))) + (ecase kind + (:call + (error "Can't deal with CALL fixups, yet.")) + (:sethi + (setf (ldb (byte 22 0) (sap-ref-32 sap offset)) + (ldb (byte 22 10) value))) + (:add + (setf (ldb (byte 10 0) (sap-ref-32 sap offset)) + (ldb (byte 10 0) value))) + (:sethi+add + (sb-vm:fixup-code-object code offset value :sethi flavor) + (sb-vm:fixup-code-object code (+ offset 4) value :add flavor)) + (:absolute + (setf (sap-ref-32 sap offset) value)))) + nil) + +(define-instruction store-coverage-mark (segment mark-index) + (:delay 0) + (:emitter + ;; This just barely works- INDEX has to fit in (SIGNED-BYTE 13). + ;; Honestly I don't care about SPARC, and neither should you. + (let ((offset (+ (component-header-length) + ;; skip over jump table word and entries + (* (1+ (component-n-jump-table-entries)) + n-word-bytes) + mark-index + (- other-pointer-lowtag)))) + (inst* segment 'stb sb-vm::null-tn sb-vm::code-tn offset)))) diff --git a/src/compiler/sparc/macros.lisp b/src/compiler/sparc/macros.lisp index c6c7f7ef5b..8722d5fa2f 100644 --- a/src/compiler/sparc/macros.lisp +++ b/src/compiler/sparc/macros.lisp @@ -132,13 +132,6 @@ ;;;; Storage allocation: -;;; Define the offset from NULL-TN to the first field in 'struct alloc_region' -;;; located in static space. The structure begin at two words past the start -;;; of the space, because there is a vector header at the exact start. -;;; This displacement is negative because its address is below NIL. -(defconstant boxed-region (- (+ static-space-start (* 2 n-word-bytes)) - nil-value)) - ;;;; Allocation macro ;;;; ;;;; This macro does the appropriate stuff to allocate space. @@ -148,7 +141,6 @@ ;;;; must be a multiple of the lisp object size). (defun allocation (type size lowtag result-tn &key stack-p temp-tn) (declare (ignorable type)) - #+gencgc ;; A temp register is needed to do inline allocation. TEMP-TN, in ;; this case, can be any register, since it holds a double-word ;; aligned address (essentially a fixnum). @@ -170,13 +162,8 @@ ;; temp-tn is csp-tn rounded up to a multiple of 8 (lispobj size) (align-csp temp-tn) - ;; For the benefit of future historians, this is how CMUCL does the - ;; align-csp (I think their version is branch free only because - ;; they simply don't worry about zeroing the pad word): - #+nil (inst add ,temp-tn csp-tn sb-vm:lowtag-mask) - #+nil (inst andn ,temp-tn sb-vm:lowtag-mask) - ;; Set the result to temp-tn, with appropriate lowtag + ;; Set the result to csp-tn, with appropriate lowtag (inst or result-tn csp-tn lowtag) ;; Allocate the desired space on the stack. @@ -185,34 +172,10 @@ ;; Need to rearrange this code. (inst add csp-tn size)) - #-gencgc - ;; Normal allocation to the heap -- cheneygc version. - ;; - ;; On cheneygc, the alloc-tn currently has the pseudo-atomic bit. - ;; If the lowtag also has a 1 bit in the same position, we're all set. - ;; - ;; See comment in PSEUDO-ATOMIC-FLAG. - ((logbitp (1- n-lowtag-bits) lowtag) - (inst or result-tn alloc-tn lowtag) - (inst add alloc-tn size)) - ;; - ;; Otherwise, we need to zap out the lowtag from alloc-tn, and then - ;; or in the lowtag. - #-gencgc - (t - (inst andn result-tn alloc-tn lowtag-mask) - (inst or result-tn lowtag) - (inst add alloc-tn size)) - ;; Normal allocation to the heap -- gencgc version. - ;; - ;; No need to worry about lowtag bits matching up here, since - ;; alloc-tn is just a "pseudo-atomic-bit-tn" now and we don't read - ;; it. - #+gencgc (t - (loadw result-tn null-tn 0 (- boxed-region)) ; free_pointer - (loadw temp-tn null-tn 1 (- boxed-region)) ; end_addr + (loadw result-tn null-tn 0 (- nil-value mixed-region)) ; free_pointer + (loadw temp-tn null-tn 1 (- nil-value mixed-region)) ; end_addr (without-scheduling () (let ((done (gen-label)) @@ -227,6 +190,10 @@ ;; past the actual end of the region? If so, we need a ;; full alloc. (inst cmp result-tn temp-tn) + ;; Why not just use trap on greater-than ??? This seems kooky. + ;; But I think it's because we have to encode size/result/page-type + ;; into another word. The PPC instruction is able to encode + ;; some registers into the trap instruction itself. (if (member :sparc-v9 *backend-subfeatures*) (inst b :gtu full-alloc :pn) (inst b :gtu full-alloc)) @@ -234,9 +201,7 @@ ;; the branch delay slot to write back the free-pointer ;; (on overflow restore it the trap handler to a good value), ;; and fold the lowtag addition into the size subtraction. - ;; (Possibly not ok for the sprof_alloc_region, - ;; but sb-sprof didn't work on sparc prior to this change) - (storew result-tn null-tn 0 (- boxed-region)) + (storew result-tn null-tn 0 (- nil-value mixed-region)) ;; Compute the base pointer and add lowtag. (cond ((integerp size) (inst sub result-tn (- size lowtag))) @@ -269,7 +234,7 @@ (bug "empty &body in WITH-FIXED-ALLOCATION")) (once-only ((result-tn result-tn) (temp-tn temp-tn) (type-code type-code) (size size)) - `(pseudo-atomic () + `(pseudo-atomic (,temp-tn) (allocation nil (pad-data-block ,size) other-pointer-lowtag ,result-tn :temp-tn ,temp-tn) (inst li ,temp-tn (compute-object-header ,size ,type-code)) @@ -277,15 +242,9 @@ ,@body))) (defun align-csp (temp) - (let ((aligned (gen-label))) - ;; FIXME: why use a TEMP? Why not just ZERO-TN? - (inst andcc temp csp-tn lowtag-mask) - (if (member :sparc-v9 *backend-subfeatures*) - (inst b :eq aligned :pt) - (inst b :eq aligned)) - (storew zero-tn csp-tn 0) ; sneaky use of delay slot - (inst add csp-tn csp-tn n-word-bytes) - (emit-label aligned))) + (storew null-tn csp-tn 0 0) ; store a known-good value (don't want wild pointers below CSP) + (inst add temp csp-tn lowtag-mask) + (inst and csp-tn temp (lognot lowtag-mask))) ;;;; Error Code (defun emit-error-break (vop kind code values) @@ -307,18 +266,21 @@ start-lab))) ;;; a handy macro for making sequences look atomic -(defmacro pseudo-atomic ((&optional) &rest forms) - (let () - `(progn +(defmacro pseudo-atomic ((temp &optional) &rest forms) + `(progn + (without-scheduling () ;; Set the pseudo-atomic flag. - (without-scheduling () - (inst or alloc-tn 4)) - ,@forms + (inst stb null-tn thread-tn (ash thread-pseudo-atomic-bits-slot + word-shift))) + ,@forms + (without-scheduling () ;; Reset the pseudo-atomic flag. - (without-scheduling () - ;; Remove the pseudo-atomic flag. - (inst andn alloc-tn 4) - ;; Check to see if pseudo-atomic interrupted flag is set (bit 0 = 1). - (inst andcc zero-tn alloc-tn 3) - ;; The C code needs to process this correctly and fixup alloc-tn. - (inst t :ne pseudo-atomic-trap))))) + ;; I wonder if it's worth trying to reduce this to one 'ldstub' + ;; instruction by packing both the PA-Atomic and PA-Interrupted flag + ;; into one byte. + (inst stb zero-tn thread-tn (ash thread-pseudo-atomic-bits-slot + word-shift))) + (inst ldub ,temp thread-tn (+ 2 (ash thread-pseudo-atomic-bits-slot + word-shift))) + (inst andcc zero-tn ,temp ,temp) + (inst t :ne pseudo-atomic-trap))) diff --git a/src/compiler/sparc/memory.lisp b/src/compiler/sparc/memory.lisp index 47ca5bf040..df659232fb 100644 --- a/src/compiler/sparc/memory.lisp +++ b/src/compiler/sparc/memory.lisp @@ -35,16 +35,15 @@ ;;; Define some VOPs for indexed memory reference. (macrolet ((define-indexer (name write-p op shift) - `(define-vop (,name) + `(define-vop (,name) (:args (object :scs (descriptor-reg)) - (index :scs (any-reg zero immediate)) - ,@(when write-p - '((value :scs (any-reg descriptor-reg) :target result)))) + (index :scs (any-reg zero immediate)) + ,@(when write-p '((value :scs (any-reg descriptor-reg))))) (:arg-types * tagged-num ,@(when write-p '(*))) (:temporary (:scs (non-descriptor-reg)) temp) - (:results (,(if write-p 'result 'value) - :scs (any-reg descriptor-reg))) - (:result-types *) + ,@(unless write-p + `((:results (value :scs (any-reg descriptor-reg))) + (:result-types *))) (:variant-vars offset lowtag) (:policy :fast-safe) (:generator 5 @@ -67,9 +66,7 @@ `((inst srl temp index ,shift))) (inst add temp ,(if (zerop shift) 'index 'temp) (- (ash offset word-shift) lowtag)) - (inst ,op value object temp))) - ,@(when write-p - '((move result value))))))) + (inst ,op value object temp))))))) (define-indexer word-index-ref nil ld 0) (define-indexer word-index-set t st 0) (define-indexer halfword-index-ref nil lduh 1) @@ -78,4 +75,3 @@ (define-indexer byte-index-ref nil ldub 2) (define-indexer signed-byte-index-ref nil ldsb 2) (define-indexer byte-index-set t stb 2)) - diff --git a/src/compiler/sparc/move.lisp b/src/compiler/sparc/move.lisp index 381343d005..b07185a7ca 100644 --- a/src/compiler/sparc/move.lisp +++ b/src/compiler/sparc/move.lisp @@ -241,7 +241,7 @@ (inst b :eq done) (inst sll y x n-fixnum-tag-bits) - (load-constant vop (emit-constant (1+ sb-xc:most-positive-fixnum)) + (load-constant vop (emit-constant (1+ most-positive-fixnum)) y) (inst b done) (inst nop) @@ -259,7 +259,7 @@ (inst b :eq done) (inst sll y x n-fixnum-tag-bits) - (load-constant vop (emit-constant (1- sb-xc:most-negative-fixnum)) + (load-constant vop (emit-constant (1- most-negative-fixnum)) y) (inst b done) (inst nop) diff --git a/src/compiler/sparc/nlx.lisp b/src/compiler/sparc/nlx.lisp index 5c12742c58..f5f6ffadd7 100644 --- a/src/compiler/sparc/nlx.lisp +++ b/src/compiler/sparc/nlx.lisp @@ -207,6 +207,18 @@ (inst nop)))))) (load-stack-tn csp-tn sp))) +(define-vop (nlx-entry-single) + (:args (sp) + (value)) + (:results (res :from :load)) + (:info label) + (:save-p :force-to-stack) + (:vop-var vop) + (:generator 30 + (emit-return-pc label) + (note-this-location vop :non-local-entry) + (move res value) + (load-stack-tn csp-tn sp))) (define-vop (nlx-entry-multiple) (:args (top :target result) (src) (count)) diff --git a/src/compiler/sparc/parms.lisp b/src/compiler/sparc/parms.lisp index caa6dce37a..dae8e6a3e1 100644 --- a/src/compiler/sparc/parms.lisp +++ b/src/compiler/sparc/parms.lisp @@ -19,7 +19,7 @@ ;;; The size in bytes of GENCGC cards, i.e. the granularity at which ;;; writes to old generations are logged. With mprotect-based write ;;; barriers, this must be a multiple of the OS page size. -(defconstant gencgc-card-bytes +backend-page-bytes+) +(defconstant gencgc-page-bytes +backend-page-bytes+) ;;; The minimum size of new allocation regions. While it doesn't ;;; currently make a lot of sense to have a card size lower than ;;; the alloc granularity, it will, once we are smarter about finding @@ -39,28 +39,6 @@ ;;; address space) (defconstant n-machine-word-bits 32) -;;; flags for the generational garbage collector -(defconstant pseudo-atomic-interrupted-flag 1) -(defconstant pseudo-atomic-flag - ;; Must be (ash 1 (1- sb-vm:n-lowtag-bits)) for cheneygc ALLOCATION. - 4) - -(defconstant float-sign-shift 31) - -(defconstant single-float-bias 126) -(defconstant-eqx single-float-exponent-byte (byte 8 23) #'equalp) -(defconstant-eqx single-float-significand-byte (byte 23 0) #'equalp) -(defconstant single-float-normal-exponent-min 1) -(defconstant single-float-normal-exponent-max 254) -(defconstant single-float-hidden-bit (ash 1 23)) - -(defconstant double-float-bias 1022) -(defconstant-eqx double-float-exponent-byte (byte 11 20) #'equalp) -(defconstant-eqx double-float-significand-byte (byte 20 0) #'equalp) -(defconstant double-float-normal-exponent-min 1) -(defconstant double-float-normal-exponent-max #x7FE) -(defconstant double-float-hidden-bit (ash 1 20)) - ;;; CMUCL COMMENT: ;;; X These values are for the x86 80 bit format and are no doubt ;;; incorrect for the sparc. @@ -72,12 +50,6 @@ (defconstant long-float-normal-exponent-max #x7FFE) (defconstant long-float-hidden-bit (ash 1 31)) -(defconstant single-float-digits - (+ (byte-size single-float-significand-byte) 1)) - -(defconstant double-float-digits - (+ (byte-size double-float-significand-byte) n-word-bits 1)) - ;;; This looks wrong - CSR (defconstant long-float-digits (+ (byte-size long-float-significand-byte) n-word-bits 1)) @@ -109,56 +81,12 @@ ;;;; Description of the target address space. -#+gencgc ; sensibly small read-only and static spaces (!gencgc-space-setup #x0f800000 :dynamic-space-start #x30000000) -;;; Where to put the different spaces. Must match the C code! -#+(and linux cheneygc) -(progn - (defconstant linkage-table-space-start #x0f800000) - (defconstant linkage-table-space-end #x10000000) - - (defconstant read-only-space-start #x11000000) - (defconstant read-only-space-end #x15000000) - - (defconstant static-space-start #x28000000) - (defconstant static-space-end #x2c000000) - - (defparameter dynamic-0-space-start #x30000000) - (defparameter dynamic-0-space-end #x38000000)) - -#+(and sunos cheneygc) ; might as well start by trying the same numbers -(progn - (defconstant linkage-table-space-start #x0f800000) - (defconstant linkage-table-space-end #x10000000) - - (defconstant read-only-space-start #x11000000) - (defconstant read-only-space-end #x15000000) - - (defconstant static-space-start #x28000000) - (defconstant static-space-end #x2c000000) - - (defparameter dynamic-0-space-start #x30000000) - (defparameter dynamic-0-space-end #x38000000)) - -#+(and netbsd cheneygc) ; Need a gap at 0x4000000 for shared libraries -(progn - (defconstant linkage-table-space-start #x0f800000) - (defconstant linkage-table-space-end #x10000000) - - (defconstant read-only-space-start #x11000000) - (defconstant read-only-space-end #x15000000) - - (defconstant static-space-start #x18000000) - (defconstant static-space-end #x1c000000) - - (defparameter dynamic-0-space-start #x48000000) - (defparameter dynamic-0-space-end #x5ffff000)) - -;; Size of one linkage-table entry in bytes. See comment in +;; Size of one alien-linkage-table entry in bytes. See comment in ;; src/runtime/sparc-arch.c -(defconstant linkage-table-entry-size 16) -(defconstant linkage-table-growth-direction :up) +(defconstant alien-linkage-table-entry-size 16) +(defconstant alien-linkage-table-growth-direction :up) (defenum (:start 8) @@ -170,7 +98,7 @@ after-breakpoint-trap single-step-around-trap single-step-before-trap - #+gencgc allocation-trap + allocation-trap error-trap) ;;;; static symbols. diff --git a/src/compiler/sparc/sap.lisp b/src/compiler/sparc/sap.lisp index 6ac3e2567f..183c2fa0fb 100644 --- a/src/compiler/sparc/sap.lisp +++ b/src/compiler/sparc/sap.lisp @@ -138,14 +138,12 @@ ;;;; mumble-SYSTEM-REF and mumble-SYSTEM-SET (macrolet ((def-system-ref-and-set (ref-name set-name sc type size &optional signed) - (let ((ref-name-c (symbolicate ref-name "-C")) - (set-name-c (symbolicate set-name "-C"))) - `(progn + `(progn (define-vop (,ref-name) - (:translate ,ref-name) + (:translate ,ref-name) (:policy :fast-safe) (:args (sap :scs (sap-reg)) - (offset :scs (signed-reg))) + (offset :scs (signed-reg))) (:arg-types system-area-pointer signed-num) (:results (result :scs (,sc))) (:result-types ,type) @@ -159,8 +157,8 @@ (:single 'ldf) (:double 'lddf)) result sap offset))))) - (define-vop (,ref-name-c) - (:translate ,ref-name) + (define-vop (,(symbolicate ref-name "-C")) + (:translate ,ref-name) (:policy :fast-safe) (:args (sap :scs (sap-reg))) (:arg-types system-area-pointer (:constant (signed-byte 13))) @@ -178,14 +176,12 @@ (:double 'lddf)) result sap offset))))) (define-vop (,set-name) - (:translate ,set-name) + (:translate ,set-name) (:policy :fast-safe) - (:args (sap :scs (sap-reg)) - (offset :scs (signed-reg)) - (value :scs (,sc) :target result)) - (:arg-types system-area-pointer signed-num ,type) - (:results (result :scs (,sc))) - (:result-types ,type) + (:args (value :scs (,sc)) + (sap :scs (sap-reg)) + (offset :scs (signed-reg))) + (:arg-types ,type system-area-pointer signed-num) (:generator 5 ,@(if (eql size :long-float) '((store-long-reg value sap offset t)) @@ -195,26 +191,14 @@ (:long 'st) (:single 'stf) (:double 'stdf)) - value sap offset))) - (unless (location= result value) - ,@(case size - (:single - '((inst fmovs result value))) - (:double - '((move-double-reg result value))) - (:long-float - '((move-long-reg result value))) - (t - '((inst move result value))))))) - (define-vop (,set-name-c) - (:translate ,set-name) + value sap offset))))) + (define-vop (,(symbolicate set-name "-C")) + (:translate ,set-name) (:policy :fast-safe) - (:args (sap :scs (sap-reg)) - (value :scs (,sc) :target result)) - (:arg-types system-area-pointer (:constant (signed-byte 13)) ,type) + (:args (value :scs (,sc)) + (sap :scs (sap-reg))) + (:arg-types ,type system-area-pointer (:constant (signed-byte 13))) (:info offset) - (:results (result :scs (,sc))) - (:result-types ,type) (:generator 4 ,@(if (eql size :long-float) '((store-long-reg value sap offset t)) @@ -224,17 +208,7 @@ (:long 'st) (:single 'stf) (:double 'stdf)) - value sap offset))) - (unless (location= result value) - ,@(case size - (:single - '((inst fmovs result value))) - (:double - '((move-double-reg result value))) - (:long-float - '((move-long-reg result value))) - (t - '((inst move result value))))))))))) + value sap offset)))))))) (def-system-ref-and-set sap-ref-8 %set-sap-ref-8 unsigned-reg positive-fixnum :byte nil) diff --git a/src/compiler/sparc/system.lisp b/src/compiler/sparc/system.lisp index 6e676d4f44..2906b4c4d2 100644 --- a/src/compiler/sparc/system.lisp +++ b/src/compiler/sparc/system.lisp @@ -49,6 +49,28 @@ DONE)) +(define-vop () + (:translate sb-c::%structure-is-a) + (:args (x :scs (descriptor-reg))) + (:arg-types * (:constant t)) + (:policy :fast-safe) + (:conditional) + ;; "extra" info in conditional vops follows the 2 super-magical info args + (:info target not-p test-layout) + (:temporary (:sc unsigned-reg) this-id temp) + (:generator 4 + (let ((offset (+ (id-bits-offset) + (ash (- (wrapper-depthoid test-layout) 2) 2) + (- instance-pointer-lowtag)))) + (inst ld this-id x offset) + (if (or (typep (layout-id test-layout) '(and (signed-byte 8) (not (eql 0)))) + (not (sb-c::producing-fasl-file))) + (inst li temp (layout-id test-layout)) + (inst load-layout-id temp test-layout)) + (inst cmp this-id temp) + (inst b (if not-p :ne :eq) target) + (inst nop)))) + (define-vop (%other-pointer-widetag) (:translate %other-pointer-widetag) (:policy :fast-safe) @@ -58,8 +80,8 @@ (:generator 6 (load-type result object (- other-pointer-lowtag)))) -(define-vop (fun-subtype) - (:translate fun-subtype) +(define-vop () + (:translate %fun-pointer-widetag) (:policy :fast-safe) (:args (function :scs (descriptor-reg))) (:results (result :scs (unsigned-reg))) @@ -80,10 +102,9 @@ (define-vop (set-header-data) (:translate set-header-data) (:policy :fast-safe) - (:args (x :scs (descriptor-reg) :target res) + (:args (x :scs (descriptor-reg)) (data :scs (any-reg immediate zero))) (:arg-types * positive-fixnum) - (:results (res :scs (descriptor-reg))) (:temporary (:scs (non-descriptor-reg)) t1 t2) (:generator 6 (loadw t1 x 0 other-pointer-lowtag) @@ -100,8 +121,7 @@ (inst li t2 val) (inst or t1 t2))))) (zero)) - (storew t1 x 0 other-pointer-lowtag) - (move res x))) + (storew t1 x 0 other-pointer-lowtag))) (define-vop (pointer-hash) @@ -118,14 +138,6 @@ ;;;; allocation -(define-vop (dynamic-space-free-pointer) - (:results (int :scs (sap-reg))) - (:result-types system-area-pointer) - (:translate dynamic-space-free-pointer) - (:policy :fast-safe) - (:generator 1 - (move int alloc-tn))) - (define-vop (binding-stack-pointer-sap) (:results (int :scs (sap-reg))) (:result-types system-area-pointer) @@ -210,3 +222,10 @@ (:translate spin-loop-hint) (:policy :fast-safe) (:generator 0)) + +(define-vop (sb-c::mark-covered) + (:info index) + (:generator 4 + ;; Can't convert index to a code-relative index until the boxed header length + ;; has been determined. + (inst store-coverage-mark index))) diff --git a/src/compiler/sparc/target-insts.lisp b/src/compiler/sparc/target-insts.lisp index aea624e6bf..958b234e8b 100644 --- a/src/compiler/sparc/target-insts.lisp +++ b/src/compiler/sparc/target-insts.lisp @@ -89,20 +89,6 @@ ;; We have an ADD %NULL, <n>, RD instruction. This is a ;; reference to a static symbol. (maybe-note-nil-indexed-object immed-val dstate)) - ((= rs1 alloc-offset) - ;; ADD %ALLOC, n. This must be some allocation or - ;; pseudo-atomic stuff - (cond ((and (= immed-val 4) (= rd alloc-offset) - (not *pseudo-atomic-set*)) - ;; "ADD 4, %ALLOC" sets the flag - (note "Set pseudo-atomic flag" dstate) - (setf *pseudo-atomic-set* t)) - ((= rd alloc-offset) - ;; "ADD n, %ALLOC" is reseting the flag, with extra - ;; allocation. - (note (format nil "Reset pseudo-atomic, allocated ~D bytes" - (+ immed-val 4)) dstate) - (setf *pseudo-atomic-set* nil)))) #+nil ((and (= rs1 zero-offset) *pseudo-atomic-set*) ;; "ADD %ZERO, num, RD" inside a pseudo-atomic is very ;; likely loading up a header word. Make a note to that @@ -146,8 +132,9 @@ (setf *note-sethi-inst* (delete sethi *note-sethi-inst*)))))))) (defun handle-andcc-inst (rs1 immed-val rd dstate) + (declare (ignorable rs1 immed-val rd dstate)) ;; ANDCC %ALLOC, 3, %ZERO instruction - (when (and (= rs1 alloc-offset) (= rd zero-offset) (= immed-val 3)) + (when nil (note "pseudo-atomic interrupted?" dstate))) (defun unimp-control (chunk inst stream dstate) diff --git a/src/compiler/sparc/type-vops.lisp b/src/compiler/sparc/type-vops.lisp index 288ac15906..0d01c11874 100644 --- a/src/compiler/sparc/type-vops.lisp +++ b/src/compiler/sparc/type-vops.lisp @@ -132,22 +132,22 @@ (define-vop (signed-byte-32-p type-predicate) (:translate signed-byte-32-p) - (:generator 45 - (let ((not-target (gen-label))) - (multiple-value-bind - (yep nope) - (if not-p - (values not-target target) - (values target not-target)) - (inst andcc zero-tn value fixnum-tag-mask) - (inst b :eq yep) - (test-type value temp nope t (other-pointer-lowtag)) - (loadw temp value 0 other-pointer-lowtag) - (inst cmp temp (+ (ash 1 n-widetag-bits) - bignum-widetag)) - (inst b (if not-p :ne :eq) target) - (inst nop) - (emit-label not-target))))) + (:generator 10 + (let ((not-target (gen-label))) + (multiple-value-bind + (yep nope) + (if not-p + (values not-target target) + (values target not-target)) + (inst andcc zero-tn value fixnum-tag-mask) + (inst b :eq yep) + (test-type value temp nope t (other-pointer-lowtag)) + (loadw temp value 0 other-pointer-lowtag) + (inst cmp temp (+ (ash 1 n-widetag-bits) + bignum-widetag)) + (inst b (if not-p :ne :eq) target) + (inst nop) + (emit-label not-target))))) @@ -159,52 +159,52 @@ (define-vop (unsigned-byte-32-p type-predicate) (:translate unsigned-byte-32-p) - (:generator 45 - (let ((not-target (gen-label)) - (single-word (gen-label)) - (fixnum (gen-label))) - (multiple-value-bind - (yep nope) - (if not-p - (values not-target target) - (values target not-target)) - ;; Is it a fixnum? - (inst andcc temp value fixnum-tag-mask) - (inst b :eq fixnum) - (inst cmp value) - - ;; If not, is it an other pointer? - (test-type value temp nope t (other-pointer-lowtag)) - ;; Get the header. - (loadw temp value 0 other-pointer-lowtag) - ;; Is it one? - (inst cmp temp (+ (ash 1 n-widetag-bits) bignum-widetag)) - (inst b :eq single-word) - ;; If it's other than two, we can't be an - ;; (unsigned-byte 32) - (inst cmp temp (+ (ash 2 n-widetag-bits) bignum-widetag)) - (inst b :ne nope) - ;; Get the second digit. - (loadw temp value (1+ bignum-digits-offset) other-pointer-lowtag) - ;; All zeros, its an (unsigned-byte 32). - (inst cmp temp) - (inst b :eq yep) - (inst nop) - ;; Otherwise, it isn't. - (inst b nope) - (inst nop) - - (emit-label single-word) - ;; Get the single digit. - (loadw temp value bignum-digits-offset other-pointer-lowtag) - (inst cmp temp) - - ;; positive implies (unsigned-byte 32). - (emit-label fixnum) - (inst b (if not-p :lt :ge) target) - (inst nop) - - (emit-label not-target))))) + (:generator 10 + (let ((not-target (gen-label)) + (single-word (gen-label)) + (fixnum (gen-label))) + (multiple-value-bind + (yep nope) + (if not-p + (values not-target target) + (values target not-target)) + ;; Is it a fixnum? + (inst andcc temp value fixnum-tag-mask) + (inst b :eq fixnum) + (inst cmp value) + + ;; If not, is it an other pointer? + (test-type value temp nope t (other-pointer-lowtag)) + ;; Get the header. + (loadw temp value 0 other-pointer-lowtag) + ;; Is it one? + (inst cmp temp (+ (ash 1 n-widetag-bits) bignum-widetag)) + (inst b :eq single-word) + ;; If it's other than two, we can't be an + ;; (unsigned-byte 32) + (inst cmp temp (+ (ash 2 n-widetag-bits) bignum-widetag)) + (inst b :ne nope) + ;; Get the second digit. + (loadw temp value (1+ bignum-digits-offset) other-pointer-lowtag) + ;; All zeros, its an (unsigned-byte 32). + (inst cmp temp) + (inst b :eq yep) + (inst nop) + ;; Otherwise, it isn't. + (inst b nope) + (inst nop) + + (emit-label single-word) + ;; Get the single digit. + (loadw temp value bignum-digits-offset other-pointer-lowtag) + (inst cmp temp) + + ;; positive implies (unsigned-byte 32). + (emit-label fixnum) + (inst b (if not-p :lt :ge) target) + (inst nop) + + (emit-label not-target))))) ;;;; List/symbol types: diff --git a/src/compiler/sparc/values.lisp b/src/compiler/sparc/values.lisp index 40ac59685b..e742e5597e 100644 --- a/src/compiler/sparc/values.lisp +++ b/src/compiler/sparc/values.lisp @@ -62,7 +62,7 @@ ;;; memory-to-memory moves for each operand, but this seems ;;; unworthwhile. (define-vop (push-values) - (:args (vals :more t)) + (:args (vals :more t :scs (descriptor-reg any-reg control-stack))) (:results (start :scs (any-reg) :from :load) (count :scs (any-reg))) (:info nvals) @@ -75,7 +75,7 @@ ((null val)) (let ((tn (tn-ref-tn val))) (sc-case tn - (descriptor-reg + ((descriptor-reg any-reg) (storew tn start i)) (control-stack (load-stack-tn temp tn) @@ -121,9 +121,8 @@ ;;; as function arguments. (define-vop (%more-arg-values) (:args (context :scs (descriptor-reg any-reg) :target src) - (skip :scs (any-reg zero immediate)) (num :scs (any-reg) :target count)) - (:arg-types * positive-fixnum positive-fixnum) + (:arg-types * positive-fixnum) (:temporary (:sc any-reg :from (:argument 0)) src) (:temporary (:sc any-reg :from (:argument 2)) dst) (:temporary (:sc descriptor-reg :from (:argument 1)) temp) @@ -131,13 +130,7 @@ (:results (start :scs (any-reg)) (count :scs (any-reg))) (:generator 20 - (sc-case skip - (zero - (move src context)) - (immediate - (inst add src context (* (tn-value skip) n-word-bytes))) - (any-reg - (inst add src context skip))) + (move src context) (inst orcc count zero-tn num) (inst b :eq done) (inst move start csp-tn) diff --git a/src/compiler/sparc/vm.lisp b/src/compiler/sparc/vm.lisp index 41559c6ceb..cd2f4a779a 100644 --- a/src/compiler/sparc/vm.lisp +++ b/src/compiler/sparc/vm.lisp @@ -11,6 +11,8 @@ (in-package "SB-VM") +(defconstant-eqx +fixup-kinds+ #(:call :sethi :add :absolute :sethi+add) #'equalp) + ;;;; Additional constants ;;; NUMBER-STACK-DISPLACEMENT @@ -44,7 +46,7 @@ ;; Globals. These are difficult to extract from a sigcontext. (defreg zero 0) ; %g0 - (defreg alloc 1) ; %g1 + (defreg thread 1) ; %g1 (defreg null 2) ; %g2 (defreg csp 3) ; %g3 (defreg cfp 4) ; %g4 @@ -277,7 +279,7 @@ (defregtn null descriptor-reg) (defregtn code descriptor-reg) (defregtn lip descriptor-reg) - (defregtn alloc any-reg) + (defregtn thread any-reg) (defregtn nargs any-reg) (defregtn bsp any-reg) @@ -294,7 +296,7 @@ zero-sc-number) (null null-sc-number) - ((or (integer #.sb-xc:most-negative-fixnum #.sb-xc:most-positive-fixnum) + ((or (integer #.most-negative-fixnum #.most-positive-fixnum) character) immediate-sc-number) (symbol diff --git a/src/compiler/srctran.lisp b/src/compiler/srctran.lisp index 946d0ecd9f..a3f7796ac2 100644 --- a/src/compiler/srctran.lisp +++ b/src/compiler/srctran.lisp @@ -20,17 +20,21 @@ (define-source-transform values (x) `(prog1 ,x)) (deftransform constantly ((value) * * :node node) - (let ((lvar (node-lvar node))) - (map-all-lvar-dests - lvar - (lambda (lvar node) - (unless (lvar-called-by-node-p lvar node) - (give-up-ir1-transform)))) - `#'(lambda (&rest rest) - (declare (ignore rest)) - value))) - -;;; CONSTANTLY is pretty much never worth transforming, but it's good to get the type. + (if (constant-lvar-p value) + `#'(lambda (&rest rest) + (declare (ignore rest)) + ',(lvar-value value)) + (let ((lvar (node-lvar node))) + ;; Is it destined to a funcall? Then don't create a closure + (map-all-lvar-dests + lvar + (lambda (lvar node) + (unless (lvar-called-by-node-p lvar node) + (give-up-ir1-transform)))) + `#'(lambda (&rest rest) + (declare (ignore rest)) + value)))) + (defoptimizer (constantly derive-type) ((value)) (specifier-type `(function (&rest t) (values ,(type-specifier (lvar-type value)) &optional)))) @@ -126,25 +130,20 @@ (define-source-transform ninth (x) `(nth 8 ,x)) (define-source-transform tenth (x) `(nth 9 ,x)) -;;; LIST with one arg is an extremely common operation (at least inside -;;; SBCL itself); translate it to CONS to take advantage of common -;;; allocation routines. +;;; Pick off special cases of LIST and LIST*. (define-source-transform list (&rest args) - (case (length args) - (1 `(cons ,(first args) nil)) - (t (values nil t)))) + (if args (values nil t) (values nil nil))) +(define-source-transform list* (arg &rest others) + (if others (values nil t) (values arg nil))) +;;; Use LIST* in lieu of CONS so that there are only 2 low-level allocators +;;; instead of 3. Strictly speaking, LIST is redundant as well. +(define-source-transform cons (x y) `(list* ,x ,y)) (defoptimizer (list derive-type) ((&rest args)) (if args (specifier-type 'cons) (specifier-type 'null))) -;;; And similarly for LIST*. -(define-source-transform list* (arg &rest others) - (cond ((not others) arg) - ((not (cdr others)) `(cons ,arg ,(car others))) - (t (values nil t)))) - (defoptimizer (list* derive-type) ((arg &rest args)) (if args (specifier-type 'cons) @@ -155,11 +154,7 @@ ;; Use of &KEY in source xforms doesn't have all the usual semantics. ;; It's better to hand-roll it - cf. transforms for WRITE[-TO-STRING]. (typep rest '(cons (eql :initial-element) (cons t null)))) - ;; Something fishy here- If THE is removed, OPERAND-RESTRICTION-OK - ;; returns NIL because type inference on MAKE-LIST never happens. - ;; But the fndb entry for %MAKE-LIST is right, so I'm slightly bewildered. - `(%make-list (the (integer 0 (,(1- sb-xc:array-dimension-limit))) ,length) - ,(second rest)) + `(%make-list ,length ,(second rest)) (values nil t))) ; give up (deftransform %make-list ((length item) ((constant-arg (eql 0)) t)) nil) @@ -240,7 +235,7 @@ ,n-x))) (deftransform last ((list &optional n) (t &optional t)) - (let ((c (constant-lvar-p n))) + (let ((c (and n (constant-lvar-p n)))) (cond ((or (not n) (and c (eql 1 (lvar-value n)))) '(%last1 list)) @@ -314,9 +309,6 @@ (define-source-transform oddp (x) `(logtest ,x 1)) (define-source-transform evenp (x) `(not (logtest ,x 1))) -;;; Note that all the integer division functions are available for -;;; inline expansion. - (macrolet ((deffrob (fun) `(define-source-transform ,fun (x &optional (y nil y-p)) (declare (ignore y)) @@ -340,16 +332,17 @@ (let ((type (two-arg-derive-type x y #'logand-derive-type-aux #'logand))) - (multiple-value-bind (typep definitely) - (ctypep 0 type) - (cond ((and (not typep) definitely) - t) - ((type= type (specifier-type '(eql 0))) - nil) - ((neq :default (combination-implementation-style node)) - (give-up-ir1-transform)) - (t - `(not (zerop (logand x y)))))))) + (when type + (multiple-value-bind (typep definitely) + (ctypep 0 type) + (cond ((and (not typep) definitely) + t) + ((type= type (specifier-type '(eql 0))) + nil) + ((neq :default (combination-implementation-style node)) + (give-up-ir1-transform)) + (t + `(not (zerop (logand x y))))))))) (deftransform logbitp ((index integer)) (let ((integer-type (lvar-type integer)) @@ -409,22 +402,6 @@ ;;;; have to create these new interval structures even though ;;;; numeric-type has everything we want to know. Reason 2 wins for ;;;; now. - -;;; Support operations that mimic real arithmetic comparison -;;; operators, but imposing a total order on the floating points such -;;; that negative zeros are strictly less than positive zeros. -(macrolet ((def (name op) - `(defun ,name (x y) - (declare (type real x y)) - (if (and (floatp x) (floatp y) (zerop x) (zerop y)) - (,op (float-sign x) (float-sign y)) - (,op x y))))) - (def signed-zero->= sb-xc:>=) - (def signed-zero-> sb-xc:>) - (def signed-zero-= sb-xc:=) - (def signed-zero-< sb-xc:<) - (def signed-zero-<= sb-xc:<=)) - (defun make-interval (&key low high) (labels ((normalize-bound (val) (cond ((and (floatp val) @@ -460,9 +437,18 @@ ;; With these traps masked, we might get things like infinity ;; or negative infinity returned. Check for this and return ;; NIL to indicate unbounded. + #+sb-xc-host + (when (and (eql f #'log) + (zerop x)) + (return-from bound-func)) (let ((y (funcall f (type-bound-number x)))) - (if (and (floatp y) - (float-infinity-p y)) + (if (or (and (floatp y) + (float-infinity-p y)) + (and (typep y 'complex) + (or (and (floatp (imagpart y)) + (float-infinity-p (imagpart y))) + (and (floatp (realpart y)) + (float-infinity-p (realpart y)))))) nil (set-bound y (and strict (consp x)))))) ;; Some numerical operations will signal an ERROR, e.g. in @@ -472,7 +458,7 @@ (defun safe-double-coercion-p (x) (or (typep x 'double-float) - (sb-xc:<= sb-xc:most-negative-double-float x sb-xc:most-positive-double-float))) + (sb-xc:<= most-negative-double-float x most-positive-double-float))) (defun safe-single-coercion-p (x) (or (typep x 'single-float) @@ -506,7 +492,7 @@ #+x86 (not (typep x `(or (integer * (,most-negative-exactly-single-float-fixnum)) (integer (,most-positive-exactly-single-float-fixnum) *)))) - (sb-xc:<= sb-xc:most-negative-single-float x sb-xc:most-positive-single-float)))) + (sb-xc:<= most-negative-single-float x most-positive-single-float)))) ;;; Apply a binary operator OP to two bounds X and Y. The result is ;;; NIL if either is NIL. Otherwise bound is computed and the result @@ -586,12 +572,12 @@ (if (coercion-loses-precision-p (car val) type) xbound (list xbound)))) - ((sb-xc:subtypep type 'double-float) - (if (sb-xc:<= sb-xc:most-negative-double-float val sb-xc:most-positive-double-float) + ((subtypep type 'double-float) + (if (sb-xc:<= most-negative-double-float val most-positive-double-float) (coerce val type))) - ((or (sb-xc:subtypep type 'single-float) (sb-xc:subtypep type 'float)) + ((or (subtypep type 'single-float) (subtypep type 'float)) ;; coerce to float returns a single-float - (if (sb-xc:<= sb-xc:most-negative-single-float val sb-xc:most-positive-single-float) + (if (sb-xc:<= most-negative-single-float val most-positive-single-float) (coerce val type))) (t (coerce val type)))) @@ -603,17 +589,17 @@ xbound (list xbound))) (cond - ((sb-xc:subtypep type 'double-float) - (if (sb-xc:<= sb-xc:most-negative-double-float val sb-xc:most-positive-double-float) + ((subtypep type 'double-float) + (if (sb-xc:<= most-negative-double-float val most-positive-double-float) (coerce val type) - (if (sb-xc:< val sb-xc:most-negative-double-float) - sb-xc:most-negative-double-float sb-xc:most-positive-double-float))) - ((or (sb-xc:subtypep type 'single-float) (sb-xc:subtypep type 'float)) + (if (sb-xc:< val most-negative-double-float) + most-negative-double-float most-positive-double-float))) + ((or (subtypep type 'single-float) (subtypep type 'float)) ;; coerce to float returns a single-float - (if (sb-xc:<= sb-xc:most-negative-single-float val sb-xc:most-positive-single-float) + (if (sb-xc:<= most-negative-single-float val most-positive-single-float) (coerce val type) - (if (sb-xc:< val sb-xc:most-negative-single-float) - sb-xc:most-negative-single-float sb-xc:most-positive-single-float))) + (if (sb-xc:< val most-negative-single-float) + most-negative-single-float most-positive-single-float))) (t (coerce val type)))))) ;;; Convert a numeric-type object to an interval object. @@ -682,9 +668,9 @@ (declare (type interval x)) (let ((lo (interval-low x)) (hi (interval-high x))) - (cond ((and lo (signed-zero->= (type-bound-number lo) point)) + (cond ((and lo (sb-xc:>= (type-bound-number lo) point)) '+) - ((and hi (signed-zero->= point (type-bound-number hi))) + ((and hi (sb-xc:>= point (type-bound-number hi))) '-) (t nil)))) @@ -693,9 +679,9 @@ (declare (type interval x)) (let ((lo (interval-low x)) (hi (interval-high x))) - (cond ((and lo (signed-zero->= (type-bound-number lo) point)) + (cond ((and lo (sb-xc:>= (type-bound-number lo) point)) '+) - ((and hi (signed-zero-> point (type-bound-number hi))) + ((and hi (sb-xc:> point (type-bound-number hi))) '-)))) ;;; Test to see whether the interval X is bounded. HOW determines the @@ -721,26 +707,26 @@ (hi (interval-high x))) (cond ((and lo hi) ;; The interval is bounded - (if (and (signed-zero-<= (type-bound-number lo) p) - (signed-zero-<= p (type-bound-number hi))) + (if (and (sb-xc:<= (type-bound-number lo) p) + (sb-xc:<= p (type-bound-number hi))) ;; P is definitely in the closure of the interval. ;; We just need to check the end points now. - (cond ((signed-zero-= p (type-bound-number lo)) + (cond ((sb-xc:= p (type-bound-number lo)) (numberp lo)) - ((signed-zero-= p (type-bound-number hi)) + ((sb-xc:= p (type-bound-number hi)) (numberp hi)) (t t)) nil)) (hi ;; Interval with upper bound - (if (signed-zero-< p (type-bound-number hi)) + (if (sb-xc:< p (type-bound-number hi)) t - (and (numberp hi) (signed-zero-= p hi)))) + (and (numberp hi) (sb-xc:= p hi)))) (lo ;; Interval with lower bound - (if (signed-zero-> p (type-bound-number lo)) + (if (sb-xc:> p (type-bound-number lo)) t - (and (numberp lo) (signed-zero-= p lo)))) + (and (numberp lo) (sb-xc:= p lo)))) (t ;; Interval with no bounds t)))) @@ -1117,6 +1103,13 @@ (defun interval-sqr (x) (declare (type interval x)) (interval-func (lambda (x) (sb-xc:* x x)) (interval-abs x))) + +(defun interval<n (interval n) + (let ((high (interval-high interval))) + (and high + (if (consp high) + (<= (car high) n) + (< high n))))) ;;;; numeric DERIVE-TYPE methods @@ -1447,6 +1440,22 @@ (defoptimizer (* derive-type) ((x y)) (two-arg-derive-type x y #'*-derive-type-aux #'sb-xc:*)) +(defoptimizer (%signed-multiply-high derive-type) ((x y)) + (two-arg-derive-type x y + (lambda (x y same-arg) + (let* ((type (*-derive-type-aux x y same-arg)) + (low (numeric-type-low type)) + (high (numeric-type-high type))) + (when (and low high) + (make-numeric-type :class 'integer + :low + (ash low (- sb-vm:n-word-bits)) + :high (ash high (- sb-vm:n-word-bits)))))) + #'sb-xc:*)) + +(defoptimizer (%multiply-high derive-type) ((x y) node) + (%signed-multiply-high-derive-type-optimizer node)) + (defun /-derive-type-aux (x y same-arg) (if (and (numeric-type-real-p x) (numeric-type-real-p y)) @@ -1483,14 +1492,14 @@ (flet ((ash-outer (n s) (when (and (fixnump s) (<= s 64) - (> s sb-xc:most-negative-fixnum)) + (> s most-negative-fixnum)) (ash n s))) ;; KLUDGE: The bare 64's here should be related to ;; symbolic machine word size values somehow. (ash-inner (n s) (if (and (fixnump s) - (> s sb-xc:most-negative-fixnum)) + (> s most-negative-fixnum)) (ash n (min s 64)) (if (minusp n) -1 0)))) (or (and (csubtypep n-type (specifier-type 'integer)) @@ -1525,7 +1534,7 @@ (numeric-type-format type)))))) (defoptimizer (lognot derive-type) ((int)) - (lognot-derive-type-aux (lvar-type int))) + (one-arg-derive-type int #'lognot-derive-type-aux #'lognot)) (defoptimizer (%negate derive-type) ((num)) (flet ((negate-bound (b) @@ -1605,6 +1614,8 @@ ;; are REAL so the result is a REAL. 'real))) +(defvar *conservative-quotient-bound* t) + (defun truncate-derive-type-quot (number-type divisor-type) (let* ((rem-type (rem-result-type number-type divisor-type)) (number-interval (numeric-type->interval number-type)) @@ -1621,20 +1632,28 @@ (interval-high divisor-interval)))) (specifier-type (if (listp res) res 'integer)))) (t - (let ((quot (truncate-quotient-bound - (interval-div number-interval - divisor-interval)))) - (specifier-type `(integer ,(or (interval-low quot) '*) - ,(or (interval-high quot) '*)))))))) + (multiple-value-bind (quot conservative) + (if (and (eql (interval-high divisor-interval) 1) + (eql (interval-low divisor-interval) 1)) + (values number-interval nil) + (values (interval-div number-interval + divisor-interval))) + (let* ((*conservative-quotient-bound* conservative) + (quot (truncate-quotient-bound quot))) + (specifier-type `(integer ,(or (interval-low quot) '*) + ,(or (interval-high quot) '*))))))))) (defun truncate-derive-type-rem (number-type divisor-type) (let* ((rem-type (rem-result-type number-type divisor-type)) (number-interval (numeric-type->interval number-type)) (divisor-interval (numeric-type->interval divisor-type)) (rem (truncate-rem-bound number-interval divisor-interval))) - ;;(declare (type (member '(integer rational float)) rem-type)) - ;; We have real numbers now. - (cond ((eq rem-type 'integer) + (cond ((and (numberp (interval-low divisor-interval)) + (numberp (interval-high divisor-interval)) + (zerop (interval-low divisor-interval)) + (zerop (interval-high divisor-interval))) + nil) + ((eq rem-type 'integer) ;; Since the remainder type is INTEGER, both args are ;; INTEGERs. (specifier-type `(,rem-type ,(or (interval-low rem) '*) @@ -1688,33 +1707,6 @@ (when (and quot rem) (make-values-type :required (list quot rem))))) -(defun ftruncate-derive-type-quot (number-type divisor-type) - ;; The bounds are the same as for truncate. However, the first - ;; result is a float of some type. We need to determine what that - ;; type is. Basically it's the more contagious of the two types. - (let ((q-type (truncate-derive-type-quot number-type divisor-type)) - (format (numeric-type-format - (numeric-contagion number-type divisor-type)))) - (make-numeric-type :class 'float - :format format - :low (coerce-for-bound (numeric-type-low q-type) format) - :high (coerce-for-bound (numeric-type-high q-type) format)))) - -(defun ftruncate-derive-type-quot-aux (n d same-arg) - (declare (ignore same-arg)) - (when (and (numeric-type-real-p n) - (numeric-type-real-p d)) - (ftruncate-derive-type-quot n d))) - -(defoptimizer (ftruncate derive-type) ((number divisor)) - (let ((quot - (two-arg-derive-type number divisor - #'ftruncate-derive-type-quot-aux #'ftruncate)) - (rem (two-arg-derive-type number divisor - #'truncate-derive-type-rem-aux #'rem))) - (when (and quot rem) - (make-values-type :required (list quot rem))))) - (defun %unary-truncate-derive-type-aux (number) (truncate-derive-type-quot number (specifier-type '(integer 1 1)))) @@ -1733,12 +1725,84 @@ #'%unary-truncate-derive-type-aux #'%unary-truncate)) -(defoptimizer (%unary-ftruncate derive-type) ((number)) - (let ((divisor (specifier-type '(integer 1 1)))) - (one-arg-derive-type number - #'(lambda (n) - (ftruncate-derive-type-quot-aux n divisor nil)) - #'%unary-ftruncate))) +(defoptimizer (unary-truncate derive-type) ((number)) + (let* ((one (specifier-type '(integer 1 1))) + (quot (one-arg-derive-type number + (lambda (x) + (truncate-derive-type-quot-aux x one nil)) + #'truncate)) + (rem (one-arg-derive-type number + (lambda (x) (truncate-derive-type-rem-aux x one nil)) + #'rem))) + (when (and quot rem) + (make-values-type :required (list quot rem))))) + +(deftransform unary-truncate ((number) (integer)) + '(values number 0)) + +#-round-float +(progn + (defun ftruncate-derive-type-quot (number-type divisor-type) + ;; The bounds are the same as for truncate. However, the first + ;; result is a float of some type. We need to determine what that + ;; type is. Basically it's the more contagious of the two types. + (let ((q-type (truncate-derive-type-quot number-type divisor-type)) + (format (numeric-type-format + (numeric-contagion number-type divisor-type)))) + (make-numeric-type :class 'float + :format format + :low (coerce-for-bound (numeric-type-low q-type) format) + :high (coerce-for-bound (numeric-type-high q-type) format)))) + + (defun ftruncate-derive-type-quot-aux (n d same-arg) + (declare (ignore same-arg)) + (when (and (numeric-type-real-p n) + (numeric-type-real-p d)) + (ftruncate-derive-type-quot n d))) + + + (defoptimizer (ftruncate derive-type) ((number divisor)) + (let ((quot + (two-arg-derive-type number divisor + #'ftruncate-derive-type-quot-aux #'ftruncate)) + (rem (two-arg-derive-type number divisor + #'truncate-derive-type-rem-aux #'rem))) + (when (and quot rem) + (make-values-type :required (list quot rem))))) + + + (defoptimizer (%unary-ftruncate derive-type) ((number)) + (let ((divisor (specifier-type '(integer 1 1)))) + (one-arg-derive-type number + #'(lambda (n) + (ftruncate-derive-type-quot-aux n divisor nil)) + #'%unary-ftruncate)))) + +#+round-float +(macrolet ((derive (type) + `(case (lvar-value mode) + ,@(loop for mode in '(:round :floor :ceiling :truncate) + for fun in '(fround ffloor fceiling ftruncate) + collect + `(,mode + (one-arg-derive-type number + (lambda (type) + (when (numeric-type-p type) + (let ((lo (numeric-type-low type)) + (hi (numeric-type-high type))) + (specifier-type (list ',type + (if lo + (,fun (type-bound-number lo)) + '*) + (if hi + (,fun (type-bound-number hi)) + '*)))))) + (lambda (x) + (values (,fun x))))))))) + (defoptimizer (round-single derive-type) ((number mode)) + (derive single-float)) + (defoptimizer (round-double derive-type) ((number mode)) + (derive double-float))) (defoptimizer (%unary-round derive-type) ((number)) (one-arg-derive-type number @@ -1835,62 +1899,14 @@ (def floor floor-quotient-bound floor-rem-bound) (def ceiling ceiling-quotient-bound ceiling-rem-bound)) -;;; Define optimizers for FFLOOR and FCEILING -(macrolet ((def (name q-name r-name) - (let ((q-aux (symbolicate "F" q-name "-AUX")) - (r-aux (symbolicate r-name "-AUX"))) - `(progn - ;; Compute type of quotient (first) result. - (defun ,q-aux (number-type divisor-type) - (let* ((number-interval - (numeric-type->interval number-type)) - (divisor-interval - (numeric-type->interval divisor-type)) - (quot (,q-name (interval-div number-interval - divisor-interval))) - (res-type (numeric-contagion number-type - divisor-type)) - (format (numeric-type-format res-type))) - (make-numeric-type - :class (numeric-type-class res-type) - :format format - :low (coerce-for-bound (interval-low quot) format) - :high (coerce-for-bound (interval-high quot) format)))) - - (defoptimizer (,name derive-type) ((number divisor)) - (flet ((derive-q (n d same-arg) - (declare (ignore same-arg)) - (when (and (numeric-type-real-p n) - (numeric-type-real-p d)) - (,q-aux n d))) - (derive-r (num div same-arg) - (declare (ignore same-arg)) - (cond ((not (and (numeric-type-real-p num) - (numeric-type-real-p div))) - nil) - ;; Floats introduce rounding errors - ((and (memq (numeric-type-class num) '(integer rational)) - (memq (numeric-type-class div) '(integer rational))) - (,r-aux num div)) - (t - (numeric-contagion num div))))) - (let ((quot (two-arg-derive-type - number divisor #'derive-q #',name)) - (rem (two-arg-derive-type - number divisor #'derive-r #'mod))) - (when (and quot rem) - (make-values-type :required (list quot rem)))))))))) - - (def ffloor floor-quotient-bound floor-rem-bound) - (def fceiling ceiling-quotient-bound ceiling-rem-bound)) - ;;; The quotient for floats depends on the divisor, ;;; make the result conservative, without letting it cross 0 (defmacro conservative-quotient-bound (result direction bound) (let ((result-sym (gensym))) `(let ((,result-sym ,result)) (,direction ,result-sym - (if (and (floatp ,bound) + (if (and *conservative-quotient-bound* + (floatp ,bound) (/= ,result-sym 0)) 1 0))))) @@ -2228,7 +2244,6 @@ (t `(,high)))))) (defoptimizer (random derive-type) ((bound &optional state)) - (declare (ignore state)) (one-arg-derive-type bound #'random-derive-type-aux nil)) ;;;; miscellaneous derive-type methods @@ -2300,7 +2315,7 @@ `(mod ,base-char-code-limit))) (t (specifier-type - `(mod ,sb-xc:char-code-limit)))))) + `(mod ,char-code-limit)))))) (defoptimizer (code-char derive-type) ((code)) (let ((type (lvar-type code))) @@ -2423,7 +2438,6 @@ (xform spec env int '%deposit-field newbyte))) (defoptimizer (%ldb derive-type) ((size posn num)) - (declare (ignore posn num)) (let ((size (lvar-type size))) (if (and (numeric-type-p size) (csubtypep size (specifier-type 'integer))) @@ -2434,7 +2448,6 @@ *universal-type*))) (defoptimizer (%mask-field derive-type) ((size posn num)) - (declare (ignore num)) (let ((size (lvar-type size)) (posn (lvar-type posn))) (if (and (numeric-type-p size) @@ -2481,11 +2494,9 @@ `(unsigned-byte* ,raw-bit-count))))))))) (defoptimizer (%dpb derive-type) ((newbyte size posn int)) - (declare (ignore newbyte)) (%deposit-field-derive-type-aux size posn int)) (defoptimizer (%deposit-field derive-type) ((newbyte size posn int)) - (declare (ignore newbyte)) (%deposit-field-derive-type-aux size posn int)) (deftransform %ldb ((size posn int) (fixnum fixnum integer) word) @@ -2535,7 +2546,6 @@ (logand int (lognot mask))))) (defoptimizer (mask-signed-field derive-type) ((size x)) - (declare (ignore x)) (let ((size (lvar-type size))) (if (numeric-type-p size) (let ((size-high (numeric-type-high size))) @@ -2546,12 +2556,7 @@ ;;; Rightward ASH -;;; Assert correctness of build order. (Need not be exhaustive) -#-(vop-translates sb-kernel:%ash/right) -(eval-when (:compile-toplevel) #+x86-64 (error "Expected %ASH/RIGHT vop")) - -#+(vop-translates sb-kernel:%ash/right) -(progn +(when-vop-existsp (:translate sb-kernel:%ash/right) (defun %ash/right (integer amount) (ash integer (- amount))) @@ -2690,22 +2695,22 @@ (give-up-ir1-transform "BOOLE code is not a constant.")) (let ((control (lvar-value op))) (case control - (#.sb-xc:boole-clr 0) - (#.sb-xc:boole-set -1) - (#.sb-xc:boole-1 'x) - (#.sb-xc:boole-2 'y) - (#.sb-xc:boole-c1 '(lognot x)) - (#.sb-xc:boole-c2 '(lognot y)) - (#.sb-xc:boole-and '(logand x y)) - (#.sb-xc:boole-ior '(logior x y)) - (#.sb-xc:boole-xor '(logxor x y)) - (#.sb-xc:boole-eqv '(logeqv x y)) - (#.sb-xc:boole-nand '(lognand x y)) - (#.sb-xc:boole-nor '(lognor x y)) - (#.sb-xc:boole-andc1 '(logandc1 x y)) - (#.sb-xc:boole-andc2 '(logandc2 x y)) - (#.sb-xc:boole-orc1 '(logorc1 x y)) - (#.sb-xc:boole-orc2 '(logorc2 x y)) + (#.boole-clr 0) + (#.boole-set -1) + (#.boole-1 'x) + (#.boole-2 'y) + (#.boole-c1 '(lognot x)) + (#.boole-c2 '(lognot y)) + (#.boole-and '(logand x y)) + (#.boole-ior '(logior x y)) + (#.boole-xor '(logxor x y)) + (#.boole-eqv '(logeqv x y)) + (#.boole-nand '(lognand x y)) + (#.boole-nor '(lognor x y)) + (#.boole-andc1 '(logandc1 x y)) + (#.boole-andc2 '(logandc2 x y)) + (#.boole-orc1 '(logorc1 x y)) + (#.boole-orc2 '(logorc2 x y)) (t (abort-ir1-transform "~S is an illegal control arg to BOOLE." control))))) @@ -2713,18 +2718,97 @@ ;;;; converting special case multiply/divide to shifts ;;; If arg is a constant power of two, turn * into a shift. -(deftransform * ((x y) (integer integer) *) +(deftransform * ((x y) (integer (constant-arg unsigned-byte)) * :node node) "convert x*2^k to shift" - (unless (constant-lvar-p y) - (give-up-ir1-transform)) - (let* ((y (lvar-value y)) - (y-abs (abs y)) - (len (1- (integer-length y-abs)))) - (unless (and (> y-abs 0) (= y-abs (ash 1 len))) + ;; Delay to make sure the surrounding casts are apparent. + (delay-ir1-transform node :optimize) + (let* ((type (single-value-type (node-asserted-type node))) + (y (lvar-value y)) + (len (1- (integer-length y)))) + (unless (or (not (csubtypep (lvar-type x) (specifier-type '(or word sb-vm:signed-word)))) + (csubtypep type (specifier-type 'word)) + (csubtypep type (specifier-type 'sb-vm:signed-word)) + (>= len sb-vm:n-word-bits)) + (give-up-ir1-transform)) + (unless (= y (ash 1 len)) (give-up-ir1-transform)) - (if (minusp y) - `(- (ash x ,len)) - `(ash x ,len)))) + `(ash x ,len))) + +;;; * deals better with ASH that overflows +(deftransform ash ((integer amount) ((or word sb-vm:signed-word) + (constant-arg (integer 1 *))) * + :important nil + :node node) + ;; Give modular arithmetic optimizers a chance + (delay-ir1-transform node :optimize) + (let ((type (single-value-type (node-asserted-type node))) + (shift (lvar-value amount))) + (when (or (csubtypep type (specifier-type 'word)) + (csubtypep type (specifier-type 'sb-vm:signed-word)) + (>= shift sb-vm:n-word-bits)) + (give-up-ir1-transform)) + `(* integer ,(ash 1 shift)))) + +(macrolet ((def (name fun type &optional (types `(,type ,type))) + `(when-vop-existsp (:translate ,name) + (defun ,name (x y type) + (declare (,type x y)) + (let ((r (,fun x y))) + (unless (typep r type) + (error 'type-error :expected-type type :datum r)) + r)) + + (deftransform ,fun ((x y) ,types * :node node :important nil) + (delay-ir1-transform node :optimize) + (let ((dest (node-dest node)) + (target-type (specifier-type ',type)) + (type (single-value-type (node-derived-type node))) + type-to-check) + (if (and (cast-p dest) + (cast-type-check dest) + (types-equal-or-intersect target-type type) + (not (csubtypep type target-type)) + (not (csubtypep type (specifier-type 'word))) + (not (csubtypep type (specifier-type 'sb-vm:signed-word))) + (csubtypep (setf type-to-check (single-value-type (cast-type-to-check dest))) target-type)) + `(,',name x y ',(type-specifier type-to-check)) + (give-up-ir1-transform)))) + + (deftransform ,name ((x y type-to-check) * * :node node) + (let (type + (type-to-check (lvar-value type-to-check)) + (sword (specifier-type ',type))) + (cond ((or (csubtypep (setf type (two-arg-derive-type x y + #',(symbolicate fun '-derive-type-aux) + #',fun)) + sword) + (not (types-equal-or-intersect sword type))) + `(the ,type-to-check (,',fun x y))) + (t + (give-up-ir1-transform)))))))) + + + (def unsigned+signed + word (word sb-vm:signed-word)) + (def unsigned-signed - word (word sb-vm:signed-word)) + + (def signed* * sb-vm:signed-word) + (def signed+ + sb-vm:signed-word) + (def signed- - sb-vm:signed-word) + + (def unsigned* * word) + (def unsigned+ + word) + (def unsigned- - word) + + (def fixnum* * fixnum)) + +(when-vop-existsp (:translate unsigned+signed) + (deftransform unsigned+signed + ((x y type-to-check) (word word t) * :node node :important nil) + `(the ,(lvar-value type-to-check) (+ x y))) + + (deftransform unsigned-signed + ((x y type-to-check) (word word t) * :node node :important nil) + `(the ,(lvar-value type-to-check) (- x y)))) ;;; These must come before the ones below, so that they are tried ;;; first. @@ -2844,7 +2928,6 @@ (defoptimizer (truncate constraint-propagate) ((x y) node gen) - (declare (ignore node x)) (when (csubtypep (lvar-type y) (specifier-type 'rational)) (let ((var (ok-lvar-lambda-var y gen))) (when var @@ -2852,7 +2935,6 @@ (defoptimizer (/ constraint-propagate) ((x y) node gen) - (declare (ignore node x)) (when (csubtypep (lvar-type y) (specifier-type 'rational)) (let ((var (ok-lvar-lambda-var y gen))) (when var @@ -2938,13 +3020,96 @@ `(ash (%multiply-high (logandc2 x ,(1- (ash 1 shift1))) ,m) ,(- (+ shift1 shift2))))))))) -#-(vop-translates sb-kernel:%multiply-high) -(progn -;;; Assert correctness of build order. (Need not be exhaustive) -(eval-when (:compile-toplevel) #+x86-64 (error "Expected %MULTIPLY-HIGH vop")) -(define-source-transform %multiply-high (x y) - `(values (sb-bignum:%multiply ,x ,y))) -) +(when-vop-existsp (:translate %signed-multiply-high) + (defun %signed-multiply-high (x y) + (%signed-multiply-high x y)) + + (defun gen-signed-truncate-by-constant-expr (y precision) + (declare (type sb-vm:signed-word y) + (type fixnum precision)) + (aver (not (zerop (logand y (1- y))))) + (labels ((ld (x) + ;; the floor of the binary logarithm of (positive) X + (integer-length (1- x))) + (choose-multiplier (y precision) + (do* ((l (ld y)) + (shift l (1- shift)) + (expt-2-n+l (expt 2 (+ sb-vm:n-word-bits l))) + (m-low (truncate expt-2-n+l y) (ash m-low -1)) + (m-high (truncate (+ expt-2-n+l + (ash expt-2-n+l (- precision))) + y) + (ash m-high -1))) + ((not (and (< (ash m-low -1) (ash m-high -1)) + (> shift 0))) + (values m-high shift))))) + (let ((n (expt 2 sb-vm:n-word-bits)) + (n-1 (expt 2 (1- sb-vm:n-word-bits)))) + (multiple-value-bind (m shift) (choose-multiplier (abs y) precision) + (let ((code + (cond ((< m n-1) + `(ash (%signed-multiply-high x ,m) + ,(- shift))) + (t + `(ash (truly-the sb-vm:signed-word + (+ x (%signed-multiply-high x ,(- m n)))) + ,(- shift)))))) + (if (minusp y) + `(- (ash x (- 1 sb-vm:n-word-bits)) ,code) + `(- ,code (ash x (- 1 sb-vm:n-word-bits))))))))) + + (deftransform truncate ((x y) (sb-vm:signed-word + (constant-arg sb-vm:signed-word)) + * + :policy (and (> speed compilation-speed) + (> speed space))) + "convert integer division to multiplication" + (let* ((y (lvar-value y)) + (abs-y (abs y)) + (x-type (lvar-type x))) + (multiple-value-bind (precision max-x) + (if (and (numeric-type-p x-type) + (numeric-type-high x-type) + (numeric-type-low x-type)) + (values (max (integer-length (numeric-type-high x-type)) + (integer-length (numeric-type-low x-type))) + (max (numeric-type-high x-type) + (abs (numeric-type-low x-type)))) + (values (1- sb-vm:n-word-bits) + (expt 2 (1- sb-vm:n-word-bits)))) + ;; Division by zero, one or powers of two is handled elsewhere. + (when (or (zerop (logand y (1- y))) + ;; Leave it for the unsigned transform + (and (plusp y) + (not (types-equal-or-intersect x-type + (specifier-type + '(and sb-vm:signed-word + (not unsigned-byte))))))) + (give-up-ir1-transform)) + `(let* ((quot (truly-the + (integer ,(- (truncate max-x abs-y)) ,(truncate max-x abs-y)) + ,(gen-signed-truncate-by-constant-expr y precision))) + (rem (truly-the (integer ,(- 1 abs-y) ,(1- abs-y)) + (- x (truly-the sb-vm:signed-word (* quot ,y)))))) + (values quot rem)))))) + +;;; The paper also has this, +;;; but it seems to overflow when adding to X +;; (defun gen-signed-floor-by-constant-expr (y max-x) +;; (declare (type sb-vm:signed-word y) +;; (type word max-x)) +;; (let ((trunc (gen-signed-truncate-by-constant-expr y +;; max-x))) +;; (let ((y-sign (xsign y))) +;; `(let* ((x-sign (xsign (logior x (+ x ,y-sign)))) +;; (x (+ ,y-sign (- x-sign) x))) +;; (truly-the sb-vm:signed-word +;; (+ ,trunc +;; (logxor x-sign ,y-sign))))))) + +(unless-vop-existsp (:translate %multiply-high) + (define-source-transform %multiply-high (x y) + `(values (sb-bignum:%multiply ,x ,y)))) ;;; If the divisor is constant and both args are positive and fit in a ;;; machine word, replace the division by a multiplication and possibly @@ -2968,17 +3133,19 @@ ;; Division by zero, one or powers of two is handled elsewhere. (when (zerop (logand y (1- y))) (give-up-ir1-transform)) - `(let* ((quot ,(gen-unsigned-div-by-constant-expr y max-x)) - (rem (ldb (byte #.sb-vm:n-word-bits 0) - (- x (* quot ,y))))) + `(let* ((quot (truly-the (integer 0 ,(truncate max-x y)) + ,(gen-unsigned-div-by-constant-expr y max-x))) + (rem (truly-the (mod ,y) + (- x (* quot ,y))))) (values quot rem)))) + ;;;; arithmetic and logical identity operation elimination ;;; Flush calls to various arith functions that convert to the ;;; identity function or a constant. (macrolet ((def (name identity result) - `(deftransform ,name ((x y) (* (constant-arg (member ,identity))) *) + `(deftransform ,name ((x y) (t (constant-arg (member ,identity))) *) "fold identity operations" ',result))) (def ash 0 x) @@ -2993,7 +3160,7 @@ (and (/= x -1) (1- (integer-length (logxor x (1+ x)))))) -(deftransform logand ((x y) (* (constant-arg integer)) *) +(deftransform logand ((x y) (t (constant-arg integer)) *) "fold identity operation" (let* ((y (lvar-value y)) (width (or (least-zero-bit y) '*))) @@ -3003,7 +3170,7 @@ (give-up-ir1-transform)) 'x)) -(deftransform mask-signed-field ((size x) ((constant-arg t) *) *) +(deftransform mask-signed-field ((size x) ((constant-arg t) t) *) "fold identity operation" (let ((size (lvar-value size))) (cond ((= size 0) 0) @@ -3012,7 +3179,7 @@ (t (give-up-ir1-transform))))) -(deftransform logior ((x y) (* (constant-arg integer)) *) +(deftransform logior ((x y) (t (constant-arg integer)) *) "fold identity operation" (let* ((y (lvar-value y)) (width (or (least-zero-bit (lognot y)) @@ -3057,7 +3224,7 @@ (def + :type rational :folded (+ -)) (def * :type rational :folded (* /))) -(deftransform mask-signed-field ((width x) ((constant-arg unsigned-byte) *)) +(deftransform mask-signed-field ((width x) ((constant-arg unsigned-byte) t)) "Fold mask-signed-field/mask-signed-field of constant width" (binding* ((node (if (lvar-has-single-use-p x) (lvar-use x) @@ -3251,7 +3418,7 @@ (,op ,a ,reverse))) `(,op ,a ,char)))) -(deftransform two-arg-char-equal ((a b) (* (constant-arg character)) * +(deftransform two-arg-char-equal ((a b) (t (constant-arg character)) * :node node) (transform-constant-char-equal 'a b)) @@ -3293,12 +3460,12 @@ ((same-leaf-ref-p x y) t) ((not (types-equal-or-intersect (lvar-type x) (lvar-type y))) nil) - #+(vop-translates sb-kernel:%instance-ref-eq) ;; Reduce (eq (%instance-ref x i) Y) to 1 instruction ;; if possible, but do not defer the memory load unless doing ;; so can have no effect, i.e. Y is a constant or provably not ;; effectful. For now, just handle constant Y. - ((and (constant-lvar-p y) + ((and (vop-existsp :translate %instance-ref-eq) + (constant-lvar-p y) (combination-p use) (almost-immediately-used-p x use) (eql '%instance-ref (lvar-fun-name (combination-fun use))) @@ -3350,6 +3517,19 @@ (t (give-up-ir1-transform))))) +#+integer-eql-vop +(deftransform %eql/integer ((x y) * * :node node) + (let* ((x-type (lvar-type x)) + (y-type (lvar-type y))) + (cond + ((same-leaf-ref-p x y) t) + ((not (types-equal-or-intersect x-type y-type)) + nil) + ((or (eq-comparable-type-p x-type) (eq-comparable-type-p y-type)) + '(eq y x)) + (t + (give-up-ir1-transform))))) + (defun array-type-dimensions-mismatch (x-type y-type) (let ((array-type (specifier-type 'array)) (simple-array-type (specifier-type 'simple-array))) @@ -3510,26 +3690,24 @@ '(= x y)) ((both-csubtypep 'hash-table) '(hash-table-equalp x y)) + ;; TODO: two instances of the same type should dispatch + ;; directly to the EQUALP-IMPL function in the layout. ((and (both-csubtypep 'array) ;; At least one array has to be longer than 0 ;; and not adjustable, because #() and "" are equal. (or (array-type-non-empty-p x-type) (array-type-non-empty-p y-type)) - (flet ((upgraded-et (type) - (multiple-value-bind (specialized supetype) - (array-type-upgraded-element-type type) - (or supetype specialized)))) - (let ((number-ctype (specifier-type 'number)) - (x-et (upgraded-et x-type)) - (y-et (upgraded-et y-type))) - (and (neq x-et *wild-type*) - (neq y-et *wild-type*) - (cond ((types-equal-or-intersect x-et y-et) - nil) - ((csubtypep x-et number-ctype) - (not (types-equal-or-intersect y-et number-ctype))) - ((types-equal-or-intersect y-et number-ctype) - (not (types-equal-or-intersect x-et number-ctype)))))))) + (let ((number-ctype (specifier-type 'number)) + (x-et (type-array-element-type x-type)) + (y-et (type-array-element-type y-type))) + (and (neq x-et *wild-type*) + (neq y-et *wild-type*) + (cond ((types-equal-or-intersect x-et y-et) + nil) + ((csubtypep x-et number-ctype) + (not (types-equal-or-intersect y-et number-ctype))) + ((types-equal-or-intersect y-et number-ctype) + (not (types-equal-or-intersect x-et number-ctype))))))) nil) ((types-equal-or-intersect x-type y-type) (if (and (types-equal-or-intersect x-type combination-type) @@ -3608,11 +3786,11 @@ (csubtypep y-type (specifier-type 'float))) (and (csubtypep x-type (specifier-type '(complex float))) (csubtypep y-type (specifier-type '(complex float)))) - #+(vop-named sb-vm::=/complex-single-float) - (and (csubtypep x-type (specifier-type '(or single-float (complex single-float)))) + (and (vop-existsp :named sb-vm::=/complex-single-float) + (csubtypep x-type (specifier-type '(or single-float (complex single-float)))) (csubtypep y-type (specifier-type '(or single-float (complex single-float))))) - #+(vop-named sb-vm::=/complex-double-float) - (and (csubtypep x-type (specifier-type '(or double-float (complex double-float)))) + (and (vop-existsp :named sb-vm::=/complex-double-float) + (csubtypep x-type (specifier-type '(or double-float (complex double-float)))) (csubtypep y-type (specifier-type '(or double-float (complex double-float)))))) ;; They are both floats. Leave as = so that -0.0 is ;; handled correctly. @@ -3973,7 +4151,7 @@ (source-transform-transitive 'logxor args 0 'integer)) (define-source-transform logand (&rest args) (source-transform-transitive 'logand args -1 'integer)) -#-(or arm arm64 hppa mips x86 x86-64 riscv) ; defined in compiler/target/arith.lisp +#-(or arm arm64 mips x86 x86-64 riscv) ; defined in compiler/{arch}/arith.lisp (define-source-transform logeqv (&rest args) (source-transform-transitive 'logeqv args -1 'integer)) (define-source-transform gcd (&rest args) @@ -4009,7 +4187,7 @@ ((and (typep (abs low) `(integer 0 ,(min (expt 2 32) - sb-xc:most-positive-fixnum))) + most-positive-fixnum))) ;; Get some extra points (positive-primep (abs low))) (pushnew (abs low) primes))) @@ -4089,7 +4267,7 @@ (case (let ((name (lvar-fun-name (combination-fun thing)))) (or (modular-version-info name :untagged nil) name)) ((+ -) - (let ((min sb-xc:most-positive-fixnum) + (let ((min most-positive-fixnum) (itype (specifier-type 'integer))) (dolist (arg (combination-args thing) min) (if (csubtypep (lvar-type arg) itype) @@ -4116,7 +4294,7 @@ 0))) (integer (if (zerop thing) - sb-xc:most-positive-fixnum + most-positive-fixnum (do ((result 0 (1+ result)) (num thing (ash num -1))) ((logbitp 0 num) result)))) @@ -4324,7 +4502,8 @@ (deftransform %rest-ref ((n list context count &optional length-checked-p)) (cond ((not (rest-var-more-context-ok list)) `(nth n list)) - ((and (constant-lvar-p length-checked-p) + ((and length-checked-p + (constant-lvar-p length-checked-p) (lvar-value length-checked-p)) `(%more-arg context n)) (t @@ -4374,16 +4553,15 @@ (lvar-use control) (find-constant (cond ((not symbols) new-string) - ((fasl-output-p *compile-object*) + ((producing-fasl-file) (acond ((assoc string (constant-cache *compilation*) :test 'equal) (cdr it)) (t - (let ((new (if symbols - (sb-format::make-fmt-control-proxy - new-string symbols) - new-string))) - (push (cons string new) (constant-cache *compilation*)) - new)))) + (let ((proxy (sb-format::make-fmt-control-proxy + new-string symbols))) + (maybe-emit-make-load-forms proxy) + (push (cons string proxy) (constant-cache *compilation*)) + proxy)))) #-sb-xc-host ; no such object as a FMT-CONTROL (t (sb-format::make-fmt-control new-string symbols))))))))) @@ -4474,9 +4652,7 @@ (lambda (node) (check-format-args node fun arg-n nil))))) (defoptimizer (format derive-type) ((dest control &rest args)) - (declare (ignore control args)) - (when (and (constant-lvar-p dest) - (null (lvar-value dest))) + (when (lvar-value-is-nil dest) (specifier-type 'simple-string))) ;;; We disable this transform in the cross-compiler to save memory in @@ -4529,7 +4705,7 @@ (let ((arg-names (make-gensym-list (length args)))) `(lambda (stream control ,@arg-names) (declare (ignore stream)) - (with-simple-output-to-string (stream) + (%with-output-to-string (stream) (funcall control stream ,@arg-names))))) (defun concatenate-format-p (control args) @@ -4624,7 +4800,7 @@ (and car-good cdr-good (values (cons car cdr) t))))))))) -(defoptimizer (coerce derive-type) ((value type) node) +(defoptimizer (coerce derive-type) ((value type)) (multiple-value-bind (type constant) (if (constant-lvar-p type) (values (lvar-value type) t) @@ -4671,17 +4847,10 @@ (type-union result-typeoid (type-intersection (lvar-type value) (specifier-type 'rational)))))) - ;; At zero safety the deftransform for COERCE can elide dimension - ;; checks for the things like (COERCE X '(SIMPLE-VECTOR 5)) -- so we - ;; need to simplify the type to drop the dimension information. - ((and (policy node (zerop safety)) - (csubtypep result-typeoid (specifier-type '(array * (*)))) - (simplify-vector-type result-typeoid))) (t result-typeoid)))))) (defoptimizer (compile derive-type) ((nameoid function)) - (declare (ignore function)) (when (csubtypep (lvar-type nameoid) (specifier-type 'null)) (values-specifier-type '(values function boolean boolean)))) @@ -4790,7 +4959,7 @@ (start-1 (1- ,',start)) (current-heap-size (- ,',end ,',start)) (keyfun ,keyfun)) - (declare (type (integer -1 #.(1- sb-xc:most-positive-fixnum)) + (declare (type (integer -1 #.(1- most-positive-fixnum)) start-1)) (declare (type index current-heap-size)) (declare (type function keyfun)) @@ -4820,13 +4989,13 @@ (%sort-vector (or ,key #'identity)))))) (deftransform sort ((list predicate &key key) - (list * &rest t) *) + (list t &rest t) *) `(sb-impl::stable-sort-list list (%coerce-callable-to-fun predicate) (if key (%coerce-callable-to-fun key) #'identity))) (deftransform stable-sort ((sequence predicate &key key) - ((or vector list) *)) + ((or vector list) t)) (let ((sequence-type (lvar-type sequence))) (cond ((csubtypep sequence-type (specifier-type 'list)) `(sb-impl::stable-sort-list sequence @@ -4873,8 +5042,7 @@ ;;; Can fold only when time-zone is supplied. (defoptimizer (encode-universal-time optimizer) - (#1=(second minute hour date month year time-zone) node) - (declare (ignore . #1#)) + ((second minute hour date month year time-zone) node) (when (every #'constant-lvar-p (basic-combination-args node)) (constant-fold-call node) t)) @@ -4920,7 +5088,7 @@ (base-char `(sb-impl::%make-base-string-ostream)) (t (give-up-ir1-transform)))) -(flet ((xform (symbol match-kind fallback) +(flet ((xform (symbol match-kind) (when (constant-lvar-p symbol) (let* ((symbol (lvar-value symbol)) (kind (info :variable :kind symbol)) @@ -4947,14 +5115,15 @@ (boundp symbol) (typep (symbol-value symbol) '(or character symbol fixnum #+64-bit single-float)))) - (return-from xform symbol)))) - fallback)) + symbol))))) (deftransform symbol-global-value ((symbol)) - (xform symbol :global `(sym-global-val symbol))) + (or (xform symbol :global) + (give-up-ir1-transform))) (deftransform symbol-value ((symbol)) - (xform symbol :special `(symeval symbol)))) + (or (xform symbol :special) + (give-up-ir1-transform)))) -(deftransform symeval ((symbol) ((constant-arg symbol))) +(deftransform symbol-value ((symbol) ((constant-arg symbol))) (let* ((symbol (lvar-value symbol)) (kind (info :variable :kind symbol))) (if (and (eq kind :constant) @@ -4975,9 +5144,9 @@ (if (or (eq kind match-kind) (memq kind '(:constant :global))) ; as above `(setq ,symbol value) (give-up-ir1-transform))))) - (deftransform set-symbol-global-value ((symbol value) ((constant-arg symbol) *)) + (deftransform set-symbol-global-value ((symbol value) ((constant-arg symbol) t)) (xform symbol :global)) - (deftransform set ((symbol value) ((constant-arg symbol) *)) + (deftransform set ((symbol value) ((constant-arg symbol) t)) (xform symbol :special))) (deftransforms (prin1-to-string princ-to-string) ((object) (number) * :important nil) @@ -4987,32 +5156,20 @@ `(write-string object stream)) #+sb-thread -(defoptimizer (sb-thread::call-with-recursive-lock derive-type) ((function mutex waitp timeout)) - (declare (ignore mutex)) +(progn +(defoptimizer (sb-thread::call-with-mutex derive-type) ((function mutex waitp timeout)) (let ((type (lvar-fun-type function))) (when (fun-type-p type) (let ((null-p (not (and (constant-lvar-p waitp) (lvar-value waitp) - (constant-lvar-p timeout) - (null (lvar-value timeout)))))) + (lvar-value-is-nil timeout))))) (if null-p (values-type-union (fun-type-returns type) (values-specifier-type '(values null &optional))) (fun-type-returns type)))))) -#+sb-thread -(defoptimizer (sb-thread::call-with-mutex derive-type) ((function mutex value waitp timeout)) - (declare (ignore mutex value)) - (let ((type (lvar-fun-type function))) - (when (fun-type-p type) - (let ((null-p (not (and (constant-lvar-p waitp) - (lvar-value waitp) - (constant-lvar-p timeout) - (null (lvar-value timeout)))))) - (if null-p - (values-type-union (fun-type-returns type) - (values-specifier-type '(values null &optional))) - (fun-type-returns type)))))) +(setf (fun-info-derive-type (fun-info-or-lose 'sb-thread::call-with-recursive-lock)) + (fun-info-derive-type (fun-info-or-lose 'sb-thread::call-with-mutex)))) (deftransform pointerp ((object)) (let ((type (lvar-type object))) @@ -5022,3 +5179,38 @@ 't) (t (give-up-ir1-transform))))) + +;;; Add transforms in reverse of the order you want them tried +;;; (because of stupid semantics) +(deftransform fboundp ((symbol) (symbol)) + `(let ((fdefn (sb-vm::%symbol-fdefn symbol))) + (and (not (eq fdefn 0)) + (fdefn-fun (truly-the fdefn fdefn))))) +;;; Normally we don't create fdefns by side-effect of calling FBOUNDP, +;;; but this transform is neutral in terms of the sum of code and data size. +;;; So for the cost of an FDEFN that might never store a function, the code +;;; is smaller by about the size of an fdefn; and it's faster, so do it. +(deftransform fboundp ((name) ((constant-arg symbol))) + `(fdefn-fun (load-time-value (find-or-create-fdefn ',(lvar-value name)) t))) + +;;; Remove special bindings with empty bodies +(deftransform %cleanup-point (() * * :node node) + (let ((prev (ctran-use (node-prev (ctran-use (node-prev node)))))) + (cond ((and (combination-p prev) + (eq (combination-fun-source-name prev nil) '%special-bind) + (not (node-next node)) + (let ((succ (car (block-succ (node-block node))))) + (and succ + (block-start succ) + (let ((start-cleanup (block-start-cleanup succ))) + (and (neq (node-enclosing-cleanup node) start-cleanup) + (do-nested-cleanups (cleanup (node-lexenv node) t) + (when (eq cleanup start-cleanup) + (return t)) + (when (eq (cleanup-kind cleanup) :dynamic-extent) + (return)))))))) + (setf (lexenv-cleanup (node-lexenv node)) nil) + (flush-combination prev) + nil) + (t + (give-up-ir1-transform))))) diff --git a/src/compiler/sset.lisp b/src/compiler/sset.lisp index e9a6261552..92a35bc247 100644 --- a/src/compiler/sset.lisp +++ b/src/compiler/sset.lisp @@ -75,7 +75,7 @@ (set-result (+ result (ash result -9))) (set-result (logxor result (ash result -5))) (set-result (+ result (ash result -2))) - (logand sb-xc:most-positive-fixnum result)))) + (logand most-positive-fixnum result)))) ;;; Secondary hash (for double hash probing). Needs to return an odd ;;; number. diff --git a/src/compiler/stack.lisp b/src/compiler/stack.lisp index 43216c39e3..7234dc6ddd 100644 --- a/src/compiler/stack.lisp +++ b/src/compiler/stack.lisp @@ -108,9 +108,12 @@ use-blocks :key (lambda (block) (let ((2block (block-info block))) + ;; same as logic in UPDATE-UVL-LIVE-SETS (merge-uvl-live-sets - (ir2-block-end-stack 2block) - (ir2-block-pushed 2block)))))) + (set-difference + (ir2-block-start-stack 2block) + (ir2-block-popped 2block)) + (member dx-lvar (reverse (ir2-block-pushed 2block)))))))) (start-block (find-lowest-common-dominator (list* block use-blocks)))) (aver start-block) @@ -119,12 +122,13 @@ (when (eq (block-flag succ) cycle) (mark succ))) (when (eq (block-out block) nlx) - (map-block-nlxes - (lambda (nlx) - (let ((target (nlx-info-target nlx))) - (when (eq (block-flag target) cycle) - (mark target)))) - block))) + (do-nested-cleanups (cleanup (block-end-lexenv block)) + (case (cleanup-kind cleanup) + ((:block :tagbody :catch :unwind-protect) + (dolist (nlx-info (cleanup-nlx-info cleanup)) + (let ((target (nlx-info-target nlx-info))) + (when (eq (block-flag target) cycle) + (mark target))))))))) (mark (block) (let ((2block (block-info block))) (unless (eq (block-flag block) flag) @@ -148,7 +152,8 @@ t) ((eq (block-flag current-block) flag) t) - ((eq (block-flag current-block) cycle)) + ((eq (block-flag current-block) cycle) + nil) ;; Don't go back past START-BLOCK. ((not (eq current-block start-block)) (setf (block-flag current-block) cycle) @@ -196,57 +201,61 @@ ;; they're handled specially. (remove-if #'lvar-dynamic-extent (ir2-block-start-stack (block-info succ)))))) - (map-block-nlxes (lambda (nlx-info) - (let* ((nle (nlx-info-target nlx-info)) - (nle-start-stack (ir2-block-start-stack - (block-info nle))) - (exit-lvar (nlx-info-lvar nlx-info)) - (next-stack (if exit-lvar - (remove exit-lvar nle-start-stack) - nle-start-stack))) - (setq new-end (merge-uvl-live-sets - new-end next-stack)))) - block - (lambda (dx-cleanup) - (dolist (lvar (cleanup-info dx-cleanup)) - (do-uses (generator lvar) - (let* ((block (node-block generator)) - (2block (block-info block))) - ;; DX objects, living in the LVAR, are alive in - ;; the environment, protected by the CLEANUP. We - ;; also cannot move them (because, in general, we - ;; cannot track all references to them). - ;; Therefore, everything, allocated deeper than a - ;; DX object -- that is, before the DX object -- - ;; should be kept alive until the object is - ;; deallocated. - ;; - ;; Since DX generators end their blocks, we can - ;; find out UVLs allocated before them by looking - ;; at the stack at the end of the block. - (setq new-end (merge-uvl-live-sets - new-end (ir2-block-end-stack 2block))) - (setq new-end (merge-uvl-live-sets - new-end (ir2-block-pushed 2block)))))))) + (do-nested-cleanups (cleanup (block-end-lexenv block)) + (case (cleanup-kind cleanup) + ((:block :tagbody :catch :unwind-protect) + (dolist (nlx-info (cleanup-nlx-info cleanup)) + (let* ((nle (nlx-info-target nlx-info)) + (nle-start-stack (ir2-block-start-stack + (block-info nle))) + (exit-lvar (nlx-info-lvar nlx-info)) + (next-stack (if exit-lvar + (remove exit-lvar nle-start-stack) + nle-start-stack))) + (setq new-end (merge-uvl-live-sets + new-end next-stack))))) + (:dynamic-extent + (dolist (lvar (cleanup-nlx-info cleanup)) + (do-uses (generator lvar) + (let* ((block (node-block generator)) + (2block (block-info block))) + ;; DX objects, living in the LVAR, are alive in + ;; the environment, protected by the CLEANUP. We + ;; also cannot move them (because, in general, we + ;; cannot track all references to them). + ;; Therefore, everything, allocated deeper than a + ;; DX object -- that is, before the DX object -- + ;; should be kept alive until the object is + ;; deallocated. + (setq new-end (merge-uvl-live-sets + new-end + (set-difference + (ir2-block-start-stack 2block) + (ir2-block-popped 2block)))) + (setq new-end (merge-uvl-live-sets + ;; union in the lvars + ;; pushed before LVAR in + ;; this block. + new-end (member lvar (reverse (ir2-block-pushed 2block))))))))))) (setf (ir2-block-end-stack 2block) new-end) - ;; If a block starts with an "entry DX" node (the start of a DX + ;; If a block has a "entry DX" node (the start of a DX ;; environment) then we need to back-propagate the DX LVARs to ;; their allocation sites. We need to be clever about this ;; because some code paths may not allocate all of the DX LVARs. - (let ((first-node (ctran-next (block-start block)))) - (when (typep first-node 'entry) - (let ((cleanup (entry-cleanup first-node))) + (do-nodes (node nil block) + (when (typep node 'entry) + (let ((cleanup (entry-cleanup node))) (when (eq (cleanup-kind cleanup) :dynamic-extent) - (back-propagate-dx-lvars block (cleanup-info cleanup)))))) + (back-propagate-dx-lvars block (cleanup-nlx-info cleanup)))))) (let ((start new-end)) (setq start (set-difference start (ir2-block-pushed 2block))) (setq start (merge-uvl-live-sets start (ir2-block-popped 2block))) ;; We cannot delete unused UVLs during NLX, so all UVLs live at - ;; ENTRY will be actually live at NLE. + ;; ENTRY which are not popped will be actually live at NLE. ;; ;; BUT, UNWIND-PROTECTor is called in the environment, which has ;; nothing in common with the environment of its entry. So we @@ -261,7 +270,9 @@ (cleanup (nlx-info-cleanup nlx-info))) (unless (eq (cleanup-kind cleanup) :unwind-protect) (let* ((entry-block (node-block (cleanup-mess-up cleanup))) - (entry-stack (ir2-block-start-stack (block-info entry-block)))) + (entry-stack (set-difference + (ir2-block-start-stack (block-info entry-block)) + (ir2-block-popped (block-info entry-block))))) (setq start (merge-uvl-live-sets start entry-stack)))))) (when *check-consistency* @@ -413,23 +424,25 @@ ((eq (car before-stack) (car after-stack)) (binding* ((moved-count (mismatch before-stack after-stack) :exit-if-null) - (moved + ((moved qmoved) (loop for moved-lvar in before-stack repeat moved-count - collect moved-lvar)) + collect moved-lvar into moved + collect `',moved-lvar into qmoved + finally (return (values moved qmoved)))) + (q-last-moved (car (last qmoved))) ((nil last-nipped rest) (find-popped (nthcdr moved-count before-stack) (nthcdr moved-count after-stack)))) (cleanup-code - `(%nip-values ,(opaquely-quote last-nipped) - ,(opaquely-quote (car (last moved))) - ,@(mapcar #'opaquely-quote moved))) + `(%nip-values ',last-nipped ,q-last-moved + ,@qmoved)) (discard (nconc moved rest) after-stack))) (t (multiple-value-bind (popped last-popped rest) (find-popped before-stack after-stack) (declare (ignore popped)) - (cleanup-code `(%pop-values ,(opaquely-quote last-popped))) + (cleanup-code `(%pop-values ',last-popped)) (discard rest after-stack))))) (dummy-allocations (before-stack after-stack) (loop @@ -508,6 +521,10 @@ (when (and (block-start succ) (not (eq (ir2-block-start-stack (block-info succ)) top))) - (insert-stack-cleanups block succ))))) + ;; Return resets the stack, so no need to clean anything. + (let ((start (block-last succ))) + (unless (and (return-p start) + (eq (block-start succ) (node-prev start))) + (insert-stack-cleanups block succ))))))) (values)) diff --git a/src/compiler/sxhash.lisp b/src/compiler/sxhash.lisp index ea760e1ac4..2ec694e5b3 100644 --- a/src/compiler/sxhash.lisp +++ b/src/compiler/sxhash.lisp @@ -12,13 +12,29 @@ (in-package "SB-C") -;;; Because we unobviously run transforms in the reverse order of definition, -;;; these must be the first transforms defined so that they become the last -;;; transforms attempted, with INTEGER taking precedence over NUMBER. +;;; CAUTION: transforms are selected in the *reverse* order of definition, +;;; so define the most general first, followed by more specific. ;;; I once tried to fix that glitch by using APPEND instead of PUSH into ;;; FUN-INFO-TRANSFORMS, and of course it broke things because we depend on such -;;; stupidity. It would be easily remedied by reversing all definitions whenever +;;; stupidity. It would be remedied by reversing all definitions whenever ;;; it matters but I didn't feel like figuring out all places where it does. + +(deftransform sxhash ((x) (t)) + (let ((type (lvar-type x))) + ;; It is common for structure slots to have a :TYPE resembling (OR STRING NULL), + ;; and also common to create custom hash calculations on structures with such slots. + ;; So it makes sense for the compiler to try to pick off cases where the slot type + ;; has a specialized hash computation via sxhash after picking off NIL. + (or (dolist (case '((simple-string . %sxhash-simple-string) + (string . %sxhash-string) + (simple-bit-vector . %sxhash-simple-bit-vector) + (bit-vector . %sxhash-bit-vector))) + (cond ((csubtypep type (specifier-type (car case))) + (return `(,(cdr case) x))) + ((csubtypep type (specifier-type `(or null ,(car case)))) + (return `(if x (,(cdr case) x) ,(sb-xc:sxhash nil)))))) + (give-up-ir1-transform)))) + (deftransform sxhash ((x) (number)) `(sb-impl::number-sxhash x)) (deftransform sxhash ((x) (integer)) `(sb-impl::integer-sxhash x)) @@ -111,7 +127,7 @@ `(let ((bits (logand (single-float-bits x) ,(1- (ash 1 32))))) (logxor 66194023 (sxhash (the sb-xc:fixnum - (logand sb-xc:most-positive-fixnum + (logand most-positive-fixnum (logxor bits (ash bits -7)))))))) (deftransform sxhash ((x) (single-float)) '#.+sxhash-single-float-expr+) @@ -122,65 +138,34 @@ (hilo (logxor hi lo))) (logxor 475038542 (sxhash (the fixnum - (logand sb-xc:most-positive-fixnum + (logand most-positive-fixnum (logxor hilo (ash hilo -7)))))))) ;;; SXHASH of FIXNUM values is defined as a DEFTRANSFORM because it's so ;;; simple. (defglobal +sxhash-fixnum-expr+ - (let ((c (logand 1193941380939624010 sb-xc:most-positive-fixnum))) + (let ((c (logand 1193941380939624010 most-positive-fixnum))) ;; shift by -1 to get sign bit into hash - `(logand (logxor (ash x 4) (ash x -1) ,c) sb-xc:most-positive-fixnum))) + `(logand (logxor (ash x 4) (ash x -1) ,c) most-positive-fixnum))) (deftransform sxhash ((x) (fixnum)) '#.+sxhash-fixnum-expr+) ;;; Treat double-float essentially the same as a fixnum if words are 64 bits. #+64-bit (defglobal +sxhash-double-float-expr+ - ;; logical negation of magic constant ensures that 0.0d0 hashes to something - ;; other than what the fixnum 0 hashes to (as tested in hash.impure.lisp) - (let ((c (logandc1 1193941380939624010 sb-xc:most-positive-fixnum))) - `(let ((x (double-float-bits x))) - ;; ensure we mix the sign bit into the hash - (logand (logxor (ash x 4) - (ash x (- (1+ sb-vm:n-fixnum-tag-bits))) - ,c) - sb-xc:most-positive-fixnum)))) + `(let ((x (double-float-bits x))) + ;; ensure we mix the sign bit into the hash + (logand (logxor (ash x 4) + (ash x (- (1+ sb-vm:n-fixnum-tag-bits))) + ;; logical negation of magic constant ensures + ;; that 0.0d0 hashes to something other than what + ;; the fixnum 0 hashes to (as tested in + ;; hash.impure.lisp) + #.(logandc1 1193941380939624010 most-positive-fixnum)) + most-positive-fixnum))) (deftransform sxhash ((x) (double-float)) '#.+sxhash-double-float-expr+) -;;; SXHASH of SIMPLE-BIT-VECTOR values is defined as a DEFTRANSFORM -;;; because it is endian-dependent. -;;; ("because it is endian-dependent" is not a reason to define -;;; a transform. This is probably better off as an asm routine) -(deftransform sxhash ((x) (simple-bit-vector)) - `(let* ((length (length x)) - (result (word-mix 410823708 length))) - (declare (type unsigned-byte result)) - (multiple-value-bind (n-full-words n-bits-remaining) - (floor length sb-vm:n-word-bits) - (dotimes (i n-full-words) - (setq result (word-mix (%vector-raw-bits x i) result))) - (when (plusp n-bits-remaining) - ;; FIXME: Do we really have to mask off bits of the final word? - ;; I don't think so, given that remaining bits are invariantly zero. - (setq result - (word-mix (logand (ash (1- (ash 1 n-bits-remaining)) - ,(ecase sb-c:*backend-byte-order* - (:little-endian 0) - (:big-endian - '(- sb-vm:n-word-bits n-bits-remaining)))) - (%vector-raw-bits x n-full-words)) - result))) - (logand result sb-xc:most-positive-fixnum)))) - -;;; Some other common SXHASH cases are defined as DEFTRANSFORMs in -;;; order to avoid having to do TYPECASE at runtime. -(deftransform sxhash ((x) (string)) - (cond ((csubtypep (lvar-type x) (specifier-type 'simple-string)) - '(%sxhash-simple-string x)) - (t - '(%sxhash-string x)))) (deftransform sxhash ((x) (symbol)) (cond ((csubtypep (lvar-type x) (specifier-type 'keyword)) ;; All interned symbols have a precomputed hash. @@ -212,26 +197,29 @@ * :important nil) `(symbol-hash* object 'non-null-symbol-p)) ; etc -;;; To define SB-XC:SXHASH compatibly without repeating the logic in the transforms +;;; To define SXHASH compatibly without repeating the logic in the transforms ;;; that define the numeric cases, we do some monkey business involving #. to paste ;;; in the expressions that the transforms would return. #+sb-xc-host (progn (defvar *sxhash-crosscheck* nil) + (defun symbol-name-hash (x) + (cond ((string= x "NIL") ; :NIL must hash the same as NIL + (ash sb-vm:nil-value (- sb-vm:n-fixnum-tag-bits))) + (t + ;; (STRING X) could be a non-simple string, it's OK. + (let ((hash (logxor (sb-impl::%sxhash-simple-string (string x)) + most-positive-fixnum))) + (aver (ldb-test (byte (- 32 sb-vm:n-fixnum-tag-bits) 0) hash)) + hash)))) (defun sxhash (x) (let ((answer (etypecase x ; croak on anything but these - (symbol - (cond ((string= x "NIL") ; :NIL must hash the same as NIL - (ash sb-vm:nil-value (- sb-vm:n-fixnum-tag-bits))) - (t - ;; (STRING X) could be a non-simple string, it's OK. - (let ((hash (logxor (sb-impl::%sxhash-simple-string (string x)) - sb-xc:most-positive-fixnum))) - (aver (ldb-test (byte (- 32 sb-vm:n-fixnum-tag-bits) 0) hash)) - hash)))) + (symbol (symbol-name-hash x)) (sb-xc:fixnum #.+sxhash-fixnum-expr+) (single-float #.+sxhash-single-float-expr+) (double-float #.+sxhash-double-float-expr+)))) - (push (cons x answer) *sxhash-crosscheck*) + ;; Symbol hashes are cross-checked during cold-init + (unless (symbolp x) + (push (cons x answer) *sxhash-crosscheck*)) answer))) diff --git a/src/compiler/target-disassem.lisp b/src/compiler/target-disassem.lisp index fb3e1ab6ac..d0e9d7fe2a 100644 --- a/src/compiler/target-disassem.lisp +++ b/src/compiler/target-disassem.lisp @@ -45,13 +45,6 @@ (print-unreadable-object (inst stream :type t :identity t) (format stream "~A(~A)" (inst-name inst) (inst-format-name inst)))) -(declaim (ftype function read-suffix)) -(defun read-signed-suffix (length dstate) - (declare (type (member 8 16 32 64) length) - (type disassem-state dstate) - (optimize (speed 3) (safety 0))) - (sign-extend (read-suffix length dstate) length)) - ;;;; combining instructions where one specializes another ;;; Return non-NIL if the instruction SPECIAL is a more specific @@ -106,7 +99,7 @@ ;;;; choosing an instruction -#-sb-fluid (declaim (inline inst-matches-p choose-inst-specialization)) +(declaim (inline inst-matches-p choose-inst-specialization)) ;;; Return non-NIL if all constant-bits in INST match CHUNK. (defun inst-matches-p (inst chunk) @@ -150,25 +143,37 @@ ;;;; searching for an instruction in instruction space +#-x86-64 +(defun pre-decode (chunk dstate) + (declare (ignore dstate)) + (values chunk 0)) + ;;; Return the instruction object within INST-SPACE corresponding to the ;;; bit-pattern CHUNK, or NIL if there isn't one. -(defun find-inst (chunk inst-space) +(defun find-inst (chunk inst-space &optional dstate) (declare (type dchunk chunk) (type (or null inst-space instruction) inst-space)) - (etypecase inst-space - (null nil) - (instruction - (if (inst-matches-p inst-space chunk) - (choose-inst-specialization inst-space chunk) - nil)) - (inst-space - (let* ((mask (ispace-valid-mask inst-space)) - (id (dchunk-and mask chunk))) - (declare (type dchunk id mask)) - (dolist (choice (ispace-choices inst-space)) - (declare (type inst-space-choice choice)) - (when (dchunk= id (ischoice-common-id choice)) - (return (find-inst chunk (ischoice-subspace choice))))))))) + (binding* (((new-chunk length-adjustment) + (if dstate (pre-decode chunk dstate) (values chunk 0))) + (inst + (named-let recurse ((chunk new-chunk) (inst-space inst-space)) + (etypecase inst-space + (null nil) + (instruction + (if (inst-matches-p inst-space chunk) + (choose-inst-specialization inst-space chunk) + nil)) + (inst-space + (let* ((mask (ispace-valid-mask inst-space)) + (id (dchunk-and mask chunk))) + (declare (type dchunk id mask)) + (dolist (choice (ispace-choices inst-space)) + (declare (type inst-space-choice choice)) + (when (dchunk= id (ischoice-common-id choice)) + (return (recurse chunk (ischoice-subspace choice))))))))))) + (if inst + (values inst (+ (inst-length inst) length-adjustment) new-chunk) + (values nil 0 chunk)))) ;;;; building the instruction space @@ -288,7 +293,7 @@ ;;; LRA layout (dual word aligned): ;;; header-word -#-sb-fluid (declaim (inline words-to-bytes)) +(declaim (inline words-to-bytes)) (eval-when (:compile-toplevel :load-toplevel :execute) ;;; Convert a word-offset NUM to a byte-offset. @@ -313,16 +318,6 @@ (seg-virtual-location seg) (seg-code seg))))) -;;;; function ops - -;;; the offset of FUNCTION from the start of its code-component's -;;; instruction area -(defun fun-insts-offset (simple-fun) ; FUNCTION *must* be pinned - (declare (type simple-fun simple-fun)) - (- (get-lisp-obj-address simple-fun) - sb-vm:fun-pointer-lowtag - (sap-int (code-instructions (fun-code-header simple-fun))))) - ;;;; operations on code-components (which hold the instructions for ;;;; one or more functions) @@ -360,7 +355,7 @@ (type alignment size)) (zerop (logand (1- size) address))) -#-(or x86 x86-64) +#-(or x86 x86-64 arm64 riscv) (progn (defconstant lra-size (words-to-bytes 1)) (defun lra-hook (chunk stream dstate) @@ -378,33 +373,25 @@ (+ (dstate-cur-offs dstate) (1- lra-size)))) sb-vm:return-pc-widetag)) - (unless (null stream) + (when stream (note "possible LRA header" dstate))) nil)) ;;; Print the fun-header (entry-point) pseudo-instruction at the -;;; current location in DSTATE to STREAM. +;;; current location in DSTATE to STREAM and skip 2 words. (defun fun-header-hook (fun-index stream dstate) (declare (type (or null stream) stream) (type disassem-state dstate)) - (unless (null stream) - (let* ((seg (dstate-segment dstate)) - (code (seg-code seg)) - (woffs (+ sb-vm:code-constants-offset (* fun-index sb-vm:code-slots-per-simple-fun))) - (name (code-header-ref code (+ woffs sb-vm:simple-fun-name-slot))) - (args (code-header-ref code (+ woffs sb-vm:simple-fun-arglist-slot))) - (info (code-header-ref code (+ woffs sb-vm:simple-fun-info-slot))) - (type (typecase info - ((cons t simple-vector) (car info)) - ((not simple-vector) info)))) + (when stream + (let* ((fun (%code-entry-point (seg-code (dstate-segment dstate)) fun-index)) + (name (%simple-fun-name fun)) + (args (%simple-fun-arglist fun))) ;; if the function's name conveys its args, don't show ARGS too - (format stream ".~A ~S~:[~:A~;~]" 'entry name + (format stream ".~A ~S~:[~:A~;~]" + 'entry name (and (typep name '(cons (eql lambda) (cons list))) (equal args (second name))) - args) - (note (lambda (stream) - (format stream "~:S" type)) ; use format to print NIL as () - dstate))) + args))) (incf (dstate-next-offs dstate) (words-to-bytes sb-vm:simple-fun-insts-offset))) @@ -437,6 +424,7 @@ (type segment segment)) (setf (dstate-segment dstate) segment) (setf (dstate-inst-properties dstate) 0) + (setf (dstate-known-register-contents dstate) nil) (setf (dstate-cur-offs-hooks dstate) (stable-sort (nreverse (copy-list (seg-hooks segment))) (lambda (oh1 oh2) @@ -492,7 +480,7 @@ (defun handle-bogus-instruction (stream dstate prefix-len) (let ((alignment (dstate-alignment dstate))) - (unless (null stream) + (when stream (multiple-value-bind (words bytes) (truncate alignment sb-vm:n-word-bytes) (when (> words 0) @@ -562,12 +550,13 @@ (setf (dstate-filtered-arg-pool-in-use dstate) nil) (loop ;; There is no point to using GET-DCHUNK. How many bytes remain is unknown. - (let* ((chunk (logand (sap-ref-word (dstate-segment-sap dstate) - (dstate-cur-offs dstate)) - dchunk-one)) - (inst (find-inst chunk *disassem-inst-space*))) + (multiple-value-bind (inst len chunk) + (find-inst (logand (sap-ref-word (dstate-segment-sap dstate) + (dstate-cur-offs dstate)) + dchunk-one) + *disassem-inst-space* dstate) (aver inst) - (let ((offs (+ (dstate-cur-offs dstate) (inst-length inst)))) + (let ((offs (+ (dstate-cur-offs dstate) len))) (setf (dstate-next-offs dstate) offs) (funcall (inst-prefilter inst) dstate chunk) ;; Grab the revised NEXT-OFFS @@ -610,24 +599,11 @@ (prefix-len 0) ; sum of lengths of any prefix instruction(s) (prefix-print-names nil)) ; reverse list of prefixes seen - ;; To minimize the extent of disabled GC, the obligatory disabling for - ;; cheneygc occurs inside the per-instruction loop rather than around it. - ;; Otherwise, operating on huge memory regions could exhaust the heap. - ;; gencgc can do better though: pin SEG-OBJECT once only outside the loop. - (macrolet ((with-pinned-segment (&body body) - #-gencgc `(without-gcing - (setf (dstate-segment-sap dstate) - (funcall (seg-sap-maker segment))) - ,@body) - #+gencgc `(progn ,@body))) - (rewind-current-segment dstate segment) - ;; Do not pin anything yet if using cheneygc, as that would inhibit GC - ;; with a larger scope than intended. - (with-pinned-objects (#+gencgc (seg-object (dstate-segment dstate)) - #+gencgc dstate) ; for SAP access to SCRATCH-BUF - #+gencgc (setf (dstate-segment-sap dstate) (funcall (seg-sap-maker segment))) + (with-pinned-objects ((seg-object (dstate-segment dstate)) + dstate) ; for SAP access to SCRATCH-BUF + (setf (dstate-segment-sap dstate) (funcall (seg-sap-maker segment))) ;; Now commence disssembly of instructions (loop @@ -648,15 +624,14 @@ (call-offs-hooks nil stream dstate) (unless (> (dstate-next-offs dstate) (dstate-cur-offs dstate)) - (with-pinned-segment (let* ((bytes-remaining (- (seg-length (dstate-segment dstate)) (dstate-cur-offs dstate))) - (chunk (get-dchunk dstate)) - (fun-prefix-p (call-fun-hooks chunk stream dstate))) + (raw-chunk (get-dchunk dstate)) + (fun-prefix-p (call-fun-hooks raw-chunk stream dstate))) (declare (index bytes-remaining)) (if (> (dstate-next-offs dstate) (dstate-cur-offs dstate)) (setf prefix-p fun-prefix-p) - (let ((inst (find-inst chunk ispace))) + (multiple-value-bind (inst len chunk) (find-inst raw-chunk ispace dstate) (cond ((null inst) (handle-bogus-instruction stream dstate prefix-len) (setf prefix-p nil)) @@ -664,19 +639,17 @@ ;; decode as "ADD [RAX], AL" if there are 2 bytes, ;; but if there's only 1 byte, it should show "BYTE 0". ;; There's really nothing we can do about the former. - ((> (inst-length inst) bytes-remaining) + ((> len bytes-remaining) (when stream (print-inst bytes-remaining stream dstate) (print-bytes bytes-remaining stream dstate) (terpri stream)) (return)) (t - (setf (dstate-inst dstate) inst) - (setf (dstate-next-offs dstate) - (+ (dstate-cur-offs dstate) (inst-length inst))) + (setf (dstate-inst dstate) inst + (dstate-next-offs dstate) (+ (dstate-cur-offs dstate) len)) (when stream - (print-inst (inst-length inst) stream dstate - :trailing-space nil)) + (print-inst len stream dstate :trailing-space nil)) (let ((orig-next (dstate-next-offs dstate))) (funcall (inst-prefilter inst) dstate chunk) (setf prefix-p (null (inst-printer inst))) @@ -688,12 +661,11 @@ orig-next))) (when (plusp suffix-len) (print-inst suffix-len stream dstate - :offset (inst-length inst) + :offset len :trailing-space nil)) ;; Keep track of the number of bytes ;; printed so far. - (incf prefix-len (+ (inst-length inst) - suffix-len))) + (incf prefix-len (+ len suffix-len))) (if prefix-p (awhen (inst-print-name inst) (push it prefix-print-names)) @@ -708,7 +680,7 @@ (funcall function chunk inst) (awhen (inst-control inst) - (funcall it chunk inst stream dstate)))))))))) + (funcall it chunk inst stream dstate))))))))) (setf (dstate-cur-offs dstate) (dstate-next-offs dstate)) @@ -723,7 +695,7 @@ (nconc (dstate-filtered-arg-pool-free dstate) (dstate-filtered-arg-pool-in-use dstate))) (setf (dstate-filtered-arg-pool-in-use dstate) nil) - (setf (dstate-inst-properties dstate) 0))))))) + (setf (dstate-inst-properties dstate) 0)))))) (defun collect-labelish-operands (args cache) @@ -757,29 +729,18 @@ ;; add labels at the beginning with a label-number of nil; we'll notice ;; later and fill them in (and sort them) (declare (type disassem-state dstate)) - ;; Holy cow, is this flaky. The problem is that labels are computed as absolute - ;; addresses, yet GC is (in theory) able to relocate the code while disassembling. - ;; The labels wouldn't make sense if that happens. - ;; I'm disinclined to revise all of the backends to compute labels relative to - ;; code-instructions. Probably we shouldn't try to support code movement while - ;; disassembling, it's just not worth the headache. - ;; However, a potential fix might be to pin the code while scanning it for - ;; labels, then relativize all labels to the segment base. - ;; When disassembling arbitrary memory, relativization would be skipped. (let ((labels (dstate-labels dstate))) (map-segment-instructions (lambda (chunk inst) (declare (type dchunk chunk) (type instruction inst)) - (declare (optimize (sb-c::insert-array-bounds-checks 0))) - (loop with list = (inst-labeller inst) - while list - ;; item = #(FUNCTION PREFILTERED-VALUE-INDEX) - ;; | #(FUNCTION SIGN-EXTEND-P BYTE-SPEC ...) - for item = (if (listp list) (pop list) (prog1 list (setq list nil))) - then (pop list) - do (let* ((item-length (length item)) - (index/signedp (svref item 1)) - (adjusted-value + (declare (optimize (sb-c:insert-array-bounds-checks 0))) + (loop + ;; item = #(FUNCTION PREFILTERED-VALUE-INDEX) + ;; | #(FUNCTION SIGN-EXTEND-P BYTE-SPEC ...) + for item in (ensure-list (inst-labeller inst)) + do (let* ((item-length (length item)) + (index/signedp (svref item 1)) + (adjusted-value (funcall (svref item 0) (flet ((extract-byte (spec-index) @@ -791,33 +752,30 @@ (case item-length (2 (svref (dstate-filtered-values dstate) index/signedp)) (3 (extract-byte 2)) ; extract exactly one byte - (t ; extract >1 byte. + (t ; extract >1 byte. ;; FIXME: this is strictly redundant. ;; You should combine fields in the prefilter ;; so that the labeller receives a single byte. - ;; AARCH64 and HPPA make use of this though. + ;; AARCH64 makes use of this though. (loop for i from 2 below item-length collect (extract-byte i))))) dstate))) - ;; If non-integer, the value is not a label. - (when (and (integerp adjusted-value) - (not (assoc adjusted-value labels))) - (push (cons adjusted-value nil) labels))))) + ;; If non-integer, the value is not a label. + (when (and (integerp adjusted-value) + (not (assoc adjusted-value labels))) + (push (cons adjusted-value nil) labels))))) segment dstate) ;; erase any notes that got there by accident (setf (dstate-notes dstate) nil) - ;; add labels from code header jump tables. As noted above, - ;; this is buggy if code moves, but no worse than anything else. + ;; add labels from code header jump tables. ;; CODE-JUMP-TABLE-WORDS = 0 if the architecture doesn't have jump tables. (binding* ((code (seg-code segment) :exit-if-null)) (with-pinned-objects (code) (loop with insts = (code-instructions code) for i from 1 below (code-jump-table-words code) do (pushnew (cons (sap-ref-word insts (ash i sb-vm:word-shift)) nil) - labels :key #'car - ;; FIXME: compiler uses EQ instead of EQL unless forced - :test #'=)))) + labels :key #'car :test #'=)))) ;; Return the new list (setf (dstate-labels dstate) labels))) @@ -1409,7 +1367,7 @@ (format stream "#X~2,'0x" (sap-ref-8 sap (+ offs start-offs)))))) (defvar *default-dstate-hooks* - (list* #-(or x86 x86-64) #'lra-hook nil)) + (list* #-(or x86 x86-64 arm64 riscv) #'lra-hook nil)) ;;; Make a disassembler-state object. (defun make-dstate (&optional (fun-hooks *default-dstate-hooks*)) @@ -1442,7 +1400,8 @@ (dotimes (i (code-n-entries (seg-code segment))) (let* ((fun (%code-entry-point (seg-code segment) i)) (length (seg-length segment)) - (offset (code-offs-to-segment-offs (%fun-code-offset fun) segment))) + (code-offs (%fun-code-offset fun)) + (offset (code-offs-to-segment-offs code-offs segment))) (when (<= 0 offset length) ;; Up to 2 words (less a byte) of padding might be present to align the ;; next simple-fun. Limit on OFFSET is to avoid incorrect triggering @@ -1455,11 +1414,12 @@ (incf (dstate-next-offs dstate) offset)) :offset 0) ; at 0 bytes into this seg, skip OFFSET bytes (seg-hooks segment))) - (push (make-offs-hook - :offset offset - :fun (let ((i i)) ; capture the _current_ I, not the final value - (lambda (stream dstate) (fun-header-hook i stream dstate)))) - (seg-hooks segment)))))) + (unless (minusp offset) + (push (make-offs-hook + :offset offset + :fun (let ((i i)) ; capture the _current_ I, not the final value + (lambda (stream dstate) (fun-header-hook i stream dstate)))) + (seg-hooks segment))))))) ;;; A SAP-MAKER is a no-argument function that returns a SAP. @@ -1518,6 +1478,13 @@ ;;; objects). ;;; INITIAL-OFFSET is the displacement into the instruction bytes ;;; of CODE (if supplied) that the segment begins at. +;;; +;;; Technically we need to pin OBJECT around all of calls of MAKE-SEGMENT +;;; with that same object. Otherwise, the VIRTUAL-LOCATION slots could come +;;; out inconsistently across them. It's unlikely to happen, but if it did, +;;; that would tend to lead to buggy disassemblies due to subtlety of +;;; absolute addressing in MAP-SEGMENT-INSTRUCTIONS that supposedly hides +;;; the movability of the underlying object. (defun make-segment (object sap-maker length &key code (initial-offset 0) virtual-location @@ -1633,6 +1600,7 @@ ;;; Assuming that CODE-OBJ is pinned, return true if ADDR is anywhere ;;; between the tagged pointer and the first occuring simple-fun. (defun points-to-code-constant-p (addr code-obj) + (declare (type word addr) (type code-component code-obj)) (<= (get-lisp-obj-address code-obj) addr (get-lisp-obj-address (%code-entry-point code-obj 0)))) @@ -1727,7 +1695,8 @@ (offset (sb-c:sc+offset-offset sc+offset))) (when (>= offset length) (setf locations (adjust-array locations - (max (* 2 length) (1+ offset))) + (max (* 2 length) (1+ offset)) + :initial-element nil) (location-group-locations group) locations)) (let ((already-there (aref locations offset))) (cond ((null already-there) @@ -1829,6 +1798,8 @@ )))) (no-debug-blocks () nil))))) +;;; Disabled because it produces poor annotations, especially around +;;; macros. (defvar *disassemble-annotate* nil "Annotate DISASSEMBLE output with source code.") @@ -1847,62 +1818,39 @@ (let* ((function (%fun-fun function)) (code (fun-code-header function)) (fun-map (code-fun-map code)) - (fname (%simple-fun-name function)) (sfcache (make-source-form-cache)) - (first-block-seen-p nil) - (nil-block-seen-p nil) - (last-offset 0) - (last-debug-fun nil) - (segments nil)) - (flet ((add-seg (offs len df) - (when (> len 0) - (push (make-code-segment code offs len - :debug-fun df - :source-form-cache sfcache) - segments)))) - (loop for fmap-entry = fun-map then next - for offset = (sb-c::compiled-debug-fun-offset fmap-entry) - for next = (sb-c::compiled-debug-fun-next fmap-entry) - do - (when first-block-seen-p - (add-seg last-offset - (- offset last-offset) - last-debug-fun) - (setf last-debug-fun nil)) - (setf last-offset offset) - (let ((name (sb-c::compiled-debug-fun-name fmap-entry)) - (kind (sb-c::compiled-debug-fun-kind fmap-entry))) - #+nil - (format t ";;; SAW ~S ~S ~S,~S ~W,~W~%" - name kind first-block-seen-p nil-block-seen-p - last-offset - (sb-c::compiled-debug-fun-start-pc fmap-entry)) - (cond (#+nil (eq last-offset fun-offset) - (and (equal name fname) - (null kind) - (not first-block-seen-p)) - (setf first-block-seen-p t)) - ((eq kind :external) - (when first-block-seen-p - (return))) - ((eq kind nil) - (when nil-block-seen-p - (return)) - (when first-block-seen-p - (setf nil-block-seen-p t)))) - (setf last-debug-fun - (sb-di::make-compiled-debug-fun fmap-entry code))) - while next) - (let ((max-offset (%code-text-size code))) - (when (and first-block-seen-p last-debug-fun) - (add-seg last-offset - (- max-offset last-offset) - last-debug-fun)) - (if (null segments) ; FIXME: when does this happen? Comment PLEASE - (let ((offs (fun-insts-offset function))) - (list - (make-code-segment code offs (- max-offset offs)))) - (nreverse segments)))))) + (fun-start (sb-di::function-start-pc-offset function)) + (max-offset (%code-text-size code))) + (loop for cdf = fun-map then next + for offset = (sb-c::compiled-debug-fun-offset cdf) + for next = (sb-c::compiled-debug-fun-next cdf) + when (and (not (sb-c::compiled-debug-fun-kind cdf)) + (>= offset fun-start)) + do (let* ((len (- + (if next + (sb-c::compiled-debug-fun-offset next) + max-offset) + offset)) + (elsewhere (sb-c::compiled-debug-fun-elsewhere-pc cdf)) + (elsewhere-len (and next + (- (sb-c::compiled-debug-fun-elsewhere-pc next) + elsewhere)))) + (when (plusp len) + (let ((df (sb-di::make-compiled-debug-fun cdf code))) + (return (list* (make-code-segment code offset len + :debug-fun df + :source-form-cache sfcache) + (and next ;; otherwise the above segment will already contain elsewhere + (plusp elsewhere-len) + (list (make-code-segment code elsewhere elsewhere-len + :debug-fun df + :source-form-cache sfcache)))))))) + while next + finally + ;; FIXME: when does this happen? Comment PLEASE + (return + (list + (make-code-segment code fun-start (- max-offset fun-start))))))) ;;; Return a list of the segments of memory containing machine code ;;; instructions for the code-component CODE. If START-OFFSET and/or @@ -2144,7 +2092,7 @@ (segments (if (eq code-component sb-fasl:*assembler-routines*) (collect ((segs)) - (dohash ((name locs) (car (%code-debug-info code-component))) + (dohash ((name locs) (%code-debug-info code-component)) (destructuring-bind (start end . index) locs (declare (ignore index)) (let ((seg (make-code-segment @@ -2191,12 +2139,16 @@ ;; What could it do- disassemble the interpreter? (error "Can't disassemble a special operator")) (t (get-compiled-funs object)))) + (when (code-component-p object) + (let* ((base (- (get-lisp-obj-address object) sb-vm:other-pointer-lowtag)) + (insts (code-instructions object))) + (format stream "~&; Base: ~x Data: ~x~%" base (sap-int insts)))) (disassemble-code-component thing :stream stream))))) ;;;; code to disassemble assembler segments ;;; Disassemble the machine code instructions associated with -;;; BYTES (a vector of assembly-unit) betwen each of RANGES. +;;; BYTES (a vector of assembly-unit) between each of RANGES. (defun disassemble-assem-segment (bytes ranges stream) (declare (type stream stream)) (let* ((dstate (make-dstate)) @@ -2216,8 +2168,7 @@ (define-load-time-global *grokked-symbol-slots* (sort (copy-list `((,sb-vm:symbol-value-slot . symbol-value) (,sb-vm:symbol-info-slot . symbol-info) - (,sb-vm:symbol-name-slot . symbol-name) - (,sb-vm:symbol-package-slot . symbol-package))) + (,sb-vm:symbol-name-slot . symbol-name))) #'< :key #'car)) @@ -2264,15 +2215,16 @@ (setf (gethash (funcall addr-xform address) addr->name) name)) name->addr))) (let ((code sb-fasl:*assembler-routines*)) - (invert (car (%code-debug-info code)) - (lambda (x) (sap-int (sap+ (code-instructions code) (car x)))))) - #-linkage-table - (invert *static-foreign-symbols* #'identity)) - (loop for name across sb-vm::+all-static-fdefns+ - for address = - #+immobile-code (sb-vm::function-raw-address name) - #-immobile-code (+ sb-vm:nil-value (sb-vm:static-fun-offset name)) - do (setf (gethash address addr->name) name)) + (invert (%code-debug-info code) + (lambda (x) (sap-int (sap+ (code-instructions code) (car x))))))) + (dovector (name sb-vm::+all-static-fdefns+) + ;; ENTER-ALIEN-CALLBACK is not fboundp until src/code/alien-callback + ;; is compiled, so don't fail in function-raw-address. + (when (fboundp name) + (let ((address + #+immobile-code (sb-vm::function-raw-address name) + #-immobile-code (+ sb-vm:nil-value (sb-vm:static-fun-offset name)))) + (setf (gethash address addr->name) name)))) ;; Not really a routine, but it uses the similar logic for annotations #+sb-safepoint (setf (gethash (+ sb-vm:gc-safepoint-page-addr @@ -2284,7 +2236,7 @@ (values found 0)) (t (let* ((code sb-fasl:*assembler-routines*) - (hashtable (car (%code-debug-info code))) + (hashtable (%code-debug-info code)) (start (sap-int (code-instructions code))) (end (+ start (1- (%code-text-size code))))) (when (<= start address end) ; it has to be an asm routine @@ -2311,7 +2263,9 @@ (type (member :little-endian :big-endian) byte-order)) (if (or (eq length 1) (and (eq byte-order #+big-endian :big-endian #+little-endian :little-endian) - #-(or arm arm64 ppc ppc64 x86 x86-64) ; unaligned loads are ok for these + ;; unaligned loads are ok for these + #-(or (and arm (not openbsd)) ; openbsd enables alignment faults + arm64 ppc ppc64 x86 x86-64) (not (logtest (1- length) (sap-int (sap+ sap offset)))))) (locally (declare (optimize (safety 0))) ; disregard shadow memory for msan @@ -2342,6 +2296,13 @@ length (dstate-byte-order dstate)) (incf (dstate-next-offs dstate) length)))) + +(defun read-signed-suffix (length dstate) + (declare (type (member 8 16 32 64) length) + (type disassem-state dstate) + (optimize (speed 3) (safety 0))) + (sign-extend (read-suffix length dstate) length)) + ;;;; optional routines to make notes about code @@ -2386,10 +2347,10 @@ (ecase how (:relative ;; When CODE-TN has a lowtag (as it usually does), we add it in here. - ;; x86-64 does not have a code-tn, but it behaves like ppc64 + ;; x86-64 and arm64 do not have a code-tn, but they behave like ppc64 ;; in that the displacement is relative to the base of the code. (let ((addr (+ location - #-(or x86-64 ppc64) sb-vm:other-pointer-lowtag))) + #-(or x86-64 ppc64 arm64) sb-vm:other-pointer-lowtag))) (values addr (ash addr (- sb-vm:word-shift))))) (:absolute ;; Concerning object movement: @@ -2447,7 +2408,7 @@ (let ((base-obj (if (simple-fun-p thing) (fun-code-header thing) thing))) (+ (logandc2 (get-lisp-obj-address base-obj) sb-vm:lowtag-mask) - (sb-vm::primitive-object-size base-obj) + (primitive-object-size base-obj) -1))) (return thing))))))) @@ -2501,18 +2462,20 @@ (unless (typep address 'address) (return-from maybe-note-assembler-routine nil)) (multiple-value-bind (name offs) (find-assembler-routine address) - #+linkage-table (unless name (setq name (sap-foreign-symbol (int-sap address)))) (when name (when (eql offs 0) (setq offs nil)) - (note (cond (note-address-p - (format nil "#x~8,'0x: ~a~@[ +~d~]" address name offs)) - (offs - (format nil "~a +~d" name offs)) - (t - (string name))) + (note (lambda (stream) + (cond (note-address-p + (format stream "#x~8,'0x: ~a~@[ +~d~]" address name offs)) + (offs + (format stream "~a +~d" name offs)) + ((stringp name) + (princ name stream)) + (t + (prin1 name stream)))) dstate)) name)) @@ -2572,21 +2535,7 @@ (dovector (symbol sb-vm:+static-symbols+) (when (= (get-lisp-obj-address symbol) address) (return-from found symbol)))) - ;; Guess whether 'address' is an immobile-space symbol by looking at - ;; code header constants. If it matches any constant, assume that it - ;; is a use of the constant. This has false positives of course, - ;; as does MAYBE-NOTE-STATIC-SYMBOL in general - any random immediate - ;; used in an unboxed context, such as an ADD instruction, - ;; might be wrongly construed as an address. - #+immobile-space - (let ((code (seg-code (dstate-segment dstate)))) - (when code - (loop for i downfrom (1- (code-header-words code)) - to sb-vm:code-constants-offset - for const = (code-header-ref code i) - when (eql (get-lisp-obj-address const) address) - do (return-from found const)))) - (return-from maybe-note-static-symbol)))) + (return-from maybe-note-static-symbol)))) (note (lambda (s) (prin1 symbol s)) dstate))) (defun get-internal-error-name (errnum) @@ -2625,21 +2574,22 @@ (type (or null stream) stream) (type disassem-state dstate)) (multiple-value-bind (errnum adjust sc+offsets lengths error-byte) - (funcall error-parse-fun - (dstate-segment-sap dstate) - (dstate-next-offs dstate) - trap-number - (null stream)) + (funcall error-parse-fun + (dstate-segment-sap dstate) + (dstate-next-offs dstate) + trap-number + (null stream)) (when stream (setf (dstate-cur-offs dstate) (dstate-next-offs dstate)) (flet ((emit-err-arg () (let ((num (pop lengths))) - (print-notes-and-newline stream dstate) - (print-current-address stream dstate) - (print-inst num stream dstate) - (print-bytes num stream dstate) - (incf (dstate-cur-offs dstate) num))) + (unless (zerop num) + (print-notes-and-newline stream dstate) + (print-current-address stream dstate) + (print-inst num stream dstate) + (print-bytes num stream dstate) + (incf (dstate-cur-offs dstate) num)))) (emit-note (note) (when note (note (string note) dstate)))) @@ -2657,11 +2607,10 @@ ;;; so can't easily share this code. ;;; But probably we should just add the conditionalization in here. #-arm64 -(defun snarf-error-junk (sap offset trap-number &optional length-only (compact-error-trap t)) +(defun snarf-error-junk (sap offset trap-number &optional length-only) (let* ((index offset) (error-byte t) - (error-number (cond ((and compact-error-trap - (>= trap-number sb-vm:error-trap)) + (error-number (cond ((>= trap-number sb-vm:error-trap) (setf error-byte nil) (- trap-number sb-vm:error-trap)) (t @@ -2756,8 +2705,8 @@ ;; nontrivial, the code-generating code is not so useful after the ;; initial instruction space is built, so it can all be removed. ;; But if you need all these macros to exist for some reason, - ;; then define one of the two following features to keep them: - #-(or sb-fluid sb-retain-assembler-macros) + ;; then define the following feature to keep them: + #-sb-retain-assembler-macros (do-symbols (symbol sb-assem::*backend-instruction-set-package*) (remf (symbol-plist symbol) 'arg-type) (remf (symbol-plist symbol) 'inst-format))) diff --git a/src/compiler/target-dstate.lisp b/src/compiler/target-dstate.lisp index e4236c6c5d..0ea11eb3fd 100644 --- a/src/compiler/target-dstate.lisp +++ b/src/compiler/target-dstate.lisp @@ -98,6 +98,7 @@ :type (member :beginning :block-boundary nil)) + (known-register-contents) ;; alist of (address . label-number) (labels nil :type list) diff --git a/src/compiler/target-main.lisp b/src/compiler/target-main.lisp index 3d07362740..def81ed46f 100644 --- a/src/compiler/target-main.lisp +++ b/src/compiler/target-main.lisp @@ -26,7 +26,7 @@ (defun compile-in-lexenv (form *lexenv* name source-info tlf ephemeral errorp) (let ((source-paths (when source-info *source-paths*))) (with-compilation-values - (sb-xc:with-compilation-unit () + (with-compilation-unit () ;; FIXME: These bindings were copied from SUB-COMPILE-FILE with ;; few changes. Once things are stable, the shared bindings ;; probably be merged back together into some shared utility @@ -47,7 +47,7 @@ (make-compilation :msan-unpoison (and (member :msan *features*) - (find-dynamic-foreign-symbol-address "__msan_unpoison")) + (find-foreign-symbol-address "__msan_unpoison")) :block-compile nil)) (*current-path* nil) (*last-message-count* (list* 0 nil nil)) @@ -74,6 +74,13 @@ ;; controlled by function arguments and lexical variables. (*compile-verbose* nil) (*compile-print* nil) + ;; in some circumstances, we can trigger execution + ;; of user code during optimization, which can + ;; re-enter the compiler through explicit calls to + ;; EVAL or COMPILE. Those inner evaluations + ;; shouldn't attempt to report any compiler problems + ;; using the outer compiler error context. + (*compiler-error-context* nil) (oops nil)) (handler-bind (((satisfies handle-condition-p) #'handle-condition-handler)) (unless source-paths @@ -129,7 +136,9 @@ WARNING occur during the compilation, and NIL otherwise. Tertiary value is true if any conditions of type ERROR, or WARNING that are not STYLE-WARNINGs occur during compilation, and NIL otherwise. " - (multiple-value-bind (compiled-definition warnings-p failure-p) + (binding* + ((clock-start (get-thread-virtual-time)) + ((compiled-definition warnings-p failure-p) ;; TODO: generic functions with any interpreted methods ;; should compile the methods and reinstall them. (if (compiled-function-p definition) @@ -139,7 +148,8 @@ not STYLE-WARNINGs occur during compilation, and NIL otherwise. (values (the cons definition) (make-null-lexenv)) #+(or sb-eval sb-fasteval) (prepare-for-compile definition)) - (compile-in-lexenv sexpr lexenv name nil nil nil nil))) + (compile-in-lexenv sexpr lexenv name nil nil nil nil))))) + (accumulate-compiler-time '*compile-elapsed-time* clock-start) (values (cond (name (if (and (symbolp name) (macro-function name)) (setf (macro-function name) compiled-definition) @@ -272,7 +282,7 @@ not STYLE-WARNINGs occur during compilation, and NIL otherwise. ;; answers. (Modulo any bugs due to near-total lack of testing) (defun compile-file-position-helper (file-info path-to-find) - (let (found-form start-char) + (let (start-char) (labels ((recurse (subpath upper-bound queue) (let ((index -1)) @@ -288,8 +298,7 @@ not STYLE-WARNINGs occur during compilation, and NIL otherwise. ;; This does not eagerly declare victory, because we want ;; to find the rightmost match. In "#1=(FOO)" there are two ;; different annotations pointing to (FOO). - (setq found-form (cdr item) - start-char (caar item))) + (setq start-char (caar item))) (unless queue (return)) (let* ((next (car queue)) (next-end (cdar next))) @@ -320,9 +329,6 @@ not STYLE-WARNINGs occur during compilation, and NIL otherwise. ;;;; Coverage helpers -(defun record-code-coverage (namestring cc) - (setf (gethash namestring (car *code-coverage-info*)) cc)) - (defun clear-code-coverage () (clrhash (car *code-coverage-info*)) (setf (cdr *code-coverage-info*) nil)) diff --git a/src/compiler/tn.lisp b/src/compiler/tn.lisp index 74db0a95ff..3dbd8dc540 100644 --- a/src/compiler/tn.lisp +++ b/src/compiler/tn.lisp @@ -32,11 +32,11 @@ ,inner (progn ,@body) (if (setq ,tn (tn-next ,tn)) (go ,inner) (go ,outer))))) -(defun set-ir2-physenv-live-tns (value instance) - (setf (ir2-physenv-live-tns instance) value)) +(defun set-ir2-environment-live-tns (value instance) + (setf (ir2-environment-live-tns instance) value)) -(defun set-ir2-physenv-debug-live-tns (value instance) - (setf (ir2-physenv-debug-live-tns instance) value)) +(defun set-ir2-environment-debug-live-tns (value instance) + (setf (ir2-environment-debug-live-tns instance) value)) (defun set-ir2-component-alias-tns (value instance) (setf (ir2-component-alias-tns instance) value)) @@ -70,9 +70,10 @@ (t (delete-1 tn prev setter)))))) (used-p (tn) - (or (tn-reads tn) (tn-writes tn) - (member (tn-kind tn) '(:component :environment)) - (not (zerop (sbit aliases (tn-number tn)))))) + (and (neq (tn-kind tn) :unused) + (or (tn-reads tn) (tn-writes tn) + (member (tn-kind tn) '(:component :environment)) + (not (zerop (sbit aliases (tn-number tn))))))) (delete-1 (tn prev setter) (if prev (setf (tn-next prev) (tn-next tn)) @@ -81,14 +82,14 @@ (case (tn-kind tn) (:environment (clear-live tn - #'ir2-physenv-live-tns - #'set-ir2-physenv-live-tns)) + #'ir2-environment-live-tns + #'set-ir2-environment-live-tns)) (:debug-environment (clear-live tn - #'ir2-physenv-debug-live-tns - #'set-ir2-physenv-debug-live-tns)))) + #'ir2-environment-debug-live-tns + #'set-ir2-environment-debug-live-tns)))) (clear-live (tn getter setter) - (let ((env (physenv-info (tn-physenv tn)))) + (let ((env (environment-info (tn-environment tn)))) (funcall setter (delete tn (funcall getter env)) env)))) (declare (inline used-p delete-some delete-1 clear-live)) (delete-some #'ir2-component-alias-tns @@ -170,24 +171,24 @@ (make-tn (incf (ir2-component-global-tn-counter (component-info *component-being-compiled*))) :unused nil nil)) -;;; Make TN be live throughout PHYSENV. Return TN. In the DEBUG case, -;;; the TN is treated normally in blocks in the environment which +;;; Make TN be live throughout ENV. Return TN. In the DEBUG case, the +;;; TN is treated normally in blocks in the environment which ;;; reference the TN, allowing targeting to/from the TN. This results ;;; in move efficient code, but may result in the TN sometimes not ;;; being live when you want it. -(defun physenv-live-tn (tn physenv) - (declare (type tn tn) (type physenv physenv)) +(defun environment-live-tn (tn env) + (declare (type tn tn) (type environment env)) (aver (eq (tn-kind tn) :normal)) (setf (tn-kind tn) :environment) - (setf (tn-physenv tn) physenv) - (push tn (ir2-physenv-live-tns (physenv-info physenv))) + (setf (tn-environment tn) env) + (push tn (ir2-environment-live-tns (environment-info env))) tn) -(defun physenv-debug-live-tn (tn physenv) - (declare (type tn tn) (type physenv physenv)) +(defun environment-debug-live-tn (tn env) + (declare (type tn tn) (type environment env)) (aver (eq (tn-kind tn) :normal)) (setf (tn-kind tn) :debug-environment) - (setf (tn-physenv tn) physenv) - (push tn (ir2-physenv-debug-live-tns (physenv-info physenv))) + (setf (tn-environment tn) env) + (push tn (ir2-environment-debug-live-tns (environment-info env))) tn) ;;; Make TN be live throughout the current component. Return TN. @@ -226,11 +227,13 @@ (immediate-constant-sc (constant-value constant)) ;; currently NULL-OFFSET is used only on ARM64 (if null-offset - (setf (leaf-info constant) - (component-live-tn - (make-wired-tn (primitive-type (leaf-type constant)) - immed - null-offset))) + (let ((tn (component-live-tn + (make-wired-tn (primitive-type (leaf-type constant)) + immed + null-offset + (specifier-type 'null))))) + (setf (tn-leaf tn) constant + (leaf-info constant) tn)) (let* ((boxed (or (not immed) (boxed-immediate-sc-p immed))) (component (component-info *component-being-compiled*)) @@ -252,7 +255,7 @@ #+immobile-space (let ((val (constant-value constant))) (or (and (symbolp val) (not (sb-vm:static-symbol-p val))) - (typep val 'layout))))) + (typep val 'wrapper))))) (let ((constants (ir2-component-constants component))) (setf (tn-offset res) (vector-push-extend constant constants)))) @@ -263,6 +266,23 @@ (setf (tn-leaf res) constant) res))))) +;;; Extracted from above +(defun constant-sc (constant) + (if (leaf-info constant) + (tn-sc (leaf-info constant)) + (multiple-value-bind (immed null-offset) + (immediate-constant-sc (constant-value constant)) + (if null-offset + immed + (let ((boxed (or (not immed) + (boxed-immediate-sc-p immed)))) + (cond (boxed + (if immed + (svref *backend-sc-numbers* immed) + (sc-or-lose 'constant))) + (t + (sc-or-lose 'constant)))))))) + (defun make-load-time-value-tn (handle type) (let* ((component (component-info *component-being-compiled*)) (sc (svref *backend-sc-numbers* @@ -337,6 +357,18 @@ (push-in tn-ref-next res (tn-reads tn)))) res)) +(defun reference-tn-refs (refs write-p) + (when refs + (let* ((first (reference-tn (tn-ref-tn refs) write-p)) + (prev first)) + (loop for tn-ref = (tn-ref-across refs) then (tn-ref-across tn-ref) + while tn-ref + do + (let ((ref (reference-tn (tn-ref-tn tn-ref) write-p))) + (setf (tn-ref-across prev) ref) + (setq prev ref))) + first))) + ;;; Make TN-REFS to reference each TN in TNs, linked together by ;;; TN-REF-ACROSS. WRITE-P is the WRITE-P value for the refs. MORE is ;;; stuck in the TN-REF-ACROSS of the ref for the last TN, or returned diff --git a/src/compiler/generic/early-type-vops.lisp b/src/compiler/type-vop-macros.lisp similarity index 64% rename from src/compiler/generic/early-type-vops.lisp rename to src/compiler/type-vop-macros.lisp index fcc4cb6b16..86ad410c10 100644 --- a/src/compiler/generic/early-type-vops.lisp +++ b/src/compiler/type-vop-macros.lisp @@ -1,4 +1,4 @@ -;;;; generic type testing and checking apparatus +;;;; generic type testing and checking VOPs ;;;; This software is part of the SBCL system. See the README file for ;;;; more information. @@ -9,11 +9,54 @@ ;;;; provided with absolutely no warranty. See the COPYING and CREDITS ;;;; files for more information. (in-package "SB-VM") - + (defconstant-eqx +immediate-types+ `(,unbound-marker-widetag ,character-widetag #+64-bit ,single-float-widetag) #'equal) +(defconstant-eqx +simple-rank-1-array-widetags+ + (map 'list #'saetp-typecode *specialized-array-element-type-properties*) + #'equal) + +(defconstant-eqx +vector-widetags+ + `(,complex-vector-widetag + #-sb-unicode ,unused-simple-char-string ; because of the contiguity assertion + #-sb-unicode ,unused-complex-char-string + ,@(append + (map 'list #'saetp-typecode *specialized-array-element-type-properties*) + (mapcan (lambda (saetp) + (when (saetp-complex-typecode saetp) + (list (saetp-complex-typecode saetp)))) + (coerce *specialized-array-element-type-properties* 'list)))) + #'equal) + +(defconstant-eqx +simple-array-widetags+ + `(,simple-array-widetag ,@+simple-rank-1-array-widetags+) + #'equal) + +(defconstant-eqx +array-widetags+ + `(,simple-array-widetag ,complex-array-widetag ,@+vector-widetags+) + #'equal) + +(defconstant-eqx +string-widetags+ + `(#+sb-unicode ,simple-character-string-widetag + #+sb-unicode ,complex-character-string-widetag + ,simple-base-string-widetag ,complex-base-string-widetag) + #'equal) + +#+sb-xc-host +(flet ((check (list) + ;; Assert that LIST is a contiguous range of widetags + (let* ((sorted (sort (copy-list list) #'<)) + (min (first sorted)) + (max (car (last sorted)))) + (assert (equal sorted (loop for w from min to max by 4 collect w)))))) + (check +simple-rank-1-array-widetags+) + (check +vector-widetags+) + (check +simple-array-widetags+) + (check +array-widetags+) + #+sb-unicode (check +string-widetags+)) ; they're discontiguous if #-sb-unicode + ;; Given a list of widetags in HEADERS, compress into a minimal list of ranges ;; and/or singletons that should be tested. ;; FIXME: At present the "is it effectively a one-sided test" is re-implemented @@ -77,12 +120,17 @@ &key &allow-other-keys) ;; Determine what interesting combinations we need to test for. (let* ((type-codes (mapcar #'eval type-codes)) - (fixnump (and (every (lambda (lowtag) - (member lowtag type-codes)) - '#.(mapcar #'symbol-value fixnum-lowtags)) - t)) - (lowtags (remove lowtag-limit type-codes :test #'<)) - (extended (remove lowtag-limit type-codes :test #'>)) + ;; FIXNUMP is true if every one of the fixnum lowtags is present + ;; in your specified list of type-codes (NOT the other way 'round) + (fixnump (subsetp fixnum-lowtags type-codes)) + ;; On 64-bit, UNBOUND-MARKER-WIDETAG may be smaller than LOWTAG-LIMIT + ;; but it is not a lowtag. + (lowtags (remove unbound-marker-widetag + (remove lowtag-limit type-codes :test #'<))) + (extended (remove-if (lambda (x) + (and (< x lowtag-limit) + (/= x unbound-marker-widetag))) + type-codes)) (immediates (intersection extended +immediate-types+ :test #'eql)) ;; To collapse the range of widetags comprising real numbers on 64-bit ;; machines, consider SHORT-FLOAT-WIDETAG both a header and immediate. @@ -112,9 +160,7 @@ (remf other-args :value-tn-ref)) (cond (fixnump - (when (remove-if (lambda (x) - (member x '#.(mapcar #'symbol-value fixnum-lowtags))) - lowtags) + (when (set-difference lowtags fixnum-lowtags) (error "can't mix fixnum testing with other lowtags")) (when function-p (error "can't mix fixnum testing with function subtype testing")) @@ -166,3 +212,45 @@ ,@other-args)) (t (error "nothing to test?"))))) + +#+(or x86 x86-64) +(progn +(define-vop (type-predicate) + (:args (value :scs (any-reg descriptor-reg))) + ;; x86 code has to avoid 'esi' and 'edi' for the temp + ;; since they can't be accessed as an 8-bit byte. + ;; x86-64 being more regular, any reg can serve as the temp. + ;; In all likelihood, it'll get rax anyway just because. + (:temporary (:sc unsigned-reg #+x86 :offset #+x86 eax-offset) temp) + (:conditional) + (:info target not-p) + (:args-var args) + (:policy :fast-safe)) +;; A vop that accepts a computed set of widetags. +(define-vop (%other-pointer-subtype-p type-predicate) + (:translate %other-pointer-subtype-p) + (:info target not-p widetags) + (:arg-types * (:constant t)) ; voodoo - 'target' and 'not-p' are absent + (:generator 15 ; arbitrary + (multiple-value-bind (headers except) (canonicalize-widetags+exceptions widetags) + (%test-headers value temp target not-p nil headers :except except + :value-tn-ref args))))) + +#-(or x86 x86-64) +(progn +(define-vop (type-predicate) + (:args (value :scs (any-reg descriptor-reg))) + (:temporary (:sc non-descriptor-reg) temp) + (:conditional) + (:info target not-p) + (:args-var args) + (:policy :fast-safe)) +;; A vop that accepts a computed set of widetags. +(define-vop (%other-pointer-subtype-p type-predicate) + (:translate %other-pointer-subtype-p) + (:info target not-p widetags) + (:arg-types * (:constant t)) ; voodoo - 'target' and 'not-p' are absent + (:args-var args) + (:generator 15 ; arbitrary + (%test-headers value temp target not-p nil (canonicalize-widetags widetags) + :value-tn-ref args)))) diff --git a/src/compiler/typetran.lisp b/src/compiler/typetran.lisp index baa69a8dc4..4f1bf08df4 100644 --- a/src/compiler/typetran.lisp +++ b/src/compiler/typetran.lisp @@ -46,8 +46,7 @@ (cons (cons type name) (remove name *backend-type-predicates* :key #'cdr))) - (%deftransform name '(function (t) *) #'fold-type-predicate) - name)) + (%deftransform name nil '(function (t) *) #'fold-type-predicate))) ;;;; IR1 transforms @@ -60,8 +59,7 @@ (deftransform typep ((object type &optional env) * * :node node) (unless (constant-lvar-p type) (give-up-ir1-transform "can't open-code test of non-constant type")) - (unless (or (null env) - (and (constant-lvar-p env) (null (lvar-value env)))) + (unless (unsupplied-or-nil env) (give-up-ir1-transform "environment argument present and not null")) (multiple-value-bind (expansion fail-p) (source-transform-typep 'object (lvar-value type)) @@ -75,8 +73,31 @@ (defun ir1-transform-type-predicate (object type node) (declare (type lvar object) (type ctype type)) (let ((otype (lvar-type object))) - (flet ((tricky () - (cond ((typep type 'alien-type-type) + (cond ((not (types-equal-or-intersect otype type)) + (return-from ir1-transform-type-predicate nil)) + ((csubtypep otype type) + (return-from ir1-transform-type-predicate t)) + ((eq type *empty-type*) + (return-from ir1-transform-type-predicate nil))) + (let ((intersect (type-intersection2 type otype))) + ;; I guess the theory here is that an intersection type + ;; is never a singleton, because if we could see that it was + ;; a singleton, it wouldn't be an intersection. + (when (and intersect (not (intersection-type-p intersect))) + (multiple-value-bind (constantp value) (type-singleton-p intersect) + (when constantp + (return-from ir1-transform-type-predicate `(eql object ',value))))) + ;; If the object type is known to be (OR NULL <type>), + ;; it is almost always cheaper to test for not EQ to NIL. + ;; There is one exception: + ;; - FIXNUMP is possibly cheapear than comparison to NIL, or definitely + ;; not worse. For x86, NIL is a 4-byte immediate operand, + ;; for lack of a null-tn register. FIXNUM-TAG-MASK is only 1 byte. + (when (type= otype (type-union (specifier-type 'null) type)) + (let ((difference (type-difference type (specifier-type 'null)))) + (unless (type= difference (specifier-type 'fixnum)) + (return-from ir1-transform-type-predicate `(not (null object)))))) + (cond ((typep type 'alien-type-type) ;; We don't transform alien type tests until here, because ;; once we do that the rest of the type system can no longer ;; reason about them properly -- so we'd miss out on type @@ -86,48 +107,8 @@ ;; If it's a lisp-rep-type, the CTYPE should be one already. (aver (not (compute-lisp-rep-type alien-type))) `(sb-alien::alien-value-typep object ',alien-type))) - #+(vop-translates sb-int:fixnump-instance-ref) - ((and (type= type (specifier-type 'fixnum)) - (let ((use (lvar-uses object))) - (and (combination-p use) - (almost-immediately-used-p object use) - (or (and (eq (lvar-fun-name (combination-fun use)) - '%instance-ref) - (constant-lvar-p - (second (combination-args use)))) - (member (lvar-fun-name (combination-fun use)) - '(car cdr)))))) - ;; This is a disturbing trend, but it's the best way to - ;; combine instructions in the compiler as it is - ;; (as opposed to the compiler as we wish it would be). - (case (lvar-fun-name (combination-fun (lvar-uses object))) - (%instance-ref - (splice-fun-args object '%instance-ref 2) - `(lambda (obj i) (fixnump-instance-ref obj i))) - (car - (splice-fun-args object 'car 1) - `(lambda (obj) (fixnump-car obj))) - (cdr - (splice-fun-args object 'cdr 1) - `(lambda (obj) (fixnump-cdr obj))))) - (t - (give-up-ir1-transform))))) - (cond ((not (types-equal-or-intersect otype type)) - nil) - ((csubtypep otype type) - t) - ((eq type *empty-type*) - nil) - (t - (let ((intersect (type-intersection2 type otype))) - (when (or (not intersect) - (intersection-type-p intersect)) - (tricky)) - (multiple-value-bind (constantp value) - (type-singleton-p intersect) - (if constantp - `(eql object ',value) - (tricky))))))))) + (t + (give-up-ir1-transform)))))) ;;; Flush %TYPEP tests whose result is known at compile time. (deftransform %typep ((object type) * * :node node) @@ -159,8 +140,7 @@ (error "Class not yet defined: ~S" name)))) (defoptimizer (%typep-wrapper constraint-propagate-if) - ((test-value variable type) node gen) - (declare (ignore test-value gen)) + ((test-value variable type) node) (aver (constant-lvar-p type)) (let ((type (lvar-value type))) (values variable (if (ctype-p type) @@ -193,7 +173,6 @@ nil) (defoptimizer (%type-constraint constraint-propagate) ((x type) node gen) - (declare (ignore node)) (let ((var (ok-lvar-lambda-var x gen))) (when var (let ((type (lvar-value type))) @@ -327,18 +306,31 @@ type))) (rational 'rational) (float (or (numeric-type-format type) 'float)) - ((nil) 'real)))) + ((nil) 'real))) + (low (numeric-type-low type)) + (high (numeric-type-high type))) (ecase (numeric-type-complexp type) (:real - (cond #+(or x86 x86-64 arm arm64) ;; Not implemented elsewhere yet - ((and - (eql (numeric-type-class type) 'integer) - (or (eql (numeric-type-low type) 0) - (eql (numeric-type-low type) 1)) - (fixnump (numeric-type-high type))) + (cond ((and (eql (numeric-type-class type) 'integer) + (and (fixnump low) + (fixnump high) + #+(or x86 x86-64 arm arm64) + (/= low 0) + (< (- high low) 2))) + ;; The fixnum-mod-p case is worse than just EQ testing with + ;; only 2 values in the range. (INTEGER 1 2) would have become + ;; (and (not (eq x 0)) (fixnump x) (not (> x 2))). + ;; If exactly 1 value, it should have been picked off by TYPE-SINGLETON-P + ;; in %SOURCE-TRANSFORM-TYPEP, but even if it wasn't, + ;; the OR will drop out due to constraint propagation. + `(or (eq ,object ,low) (eq ,object ,high))) + #+(or x86 x86-64 arm arm64) ;; Not implemented elsewhere yet + ((and (eql (numeric-type-class type) 'integer) + (or (eql low 0) (eql low 1)) + (fixnump (numeric-type-high type))) (let ((mod-p `(fixnum-mod-p ,object ,(numeric-type-high type)))) - (if (eql (numeric-type-low type) 1) + (if (eql low 1) `(and (not (eq ,object 0)) ,mod-p) mod-p))) @@ -364,14 +356,29 @@ (defun source-transform-hairy-typep (object type) (declare (type hairy-type type)) (let ((spec (hairy-type-specifier type))) - (cond ((unknown-type-p type) - #+sb-xc-host + (cond ((and (unknown-type-p type) + (symbolp spec) + (eq (info :type :kind spec) :forthcoming-defclass-type)) + ;; Knowing that it was DEFCLASSed is enough to emit a CLASSOID-CELL-TYPEP test. + ;; Combinators involving this - e.g. (OR A-NEW-CLASS OTHER-CLASS) - + ;; are handled correctly, because we don't punt on everything in the expression + ;; as soon as any unknown is present. + `(classoid-cell-typep ,(find-classoid-cell spec :create t) ,object)) + ((unknown-type-p type) + #+(and sb-xc-host (not sb-devel)) (warn "can't open-code test of unknown type ~S" (type-specifier type)) - #-sb-xc-host - (when (policy *lexenv* (> speed inhibit-warnings)) - (compiler-notify "can't open-code test of unknown type ~S" - (type-specifier type))) + ;; This is not a policy-based decision to notify here, + ;; because it is _ALWAYS_ questionable style imho to refer to unknown types. + ;; Unfortunately, people love to suppress COMPILER-NOTE because SBCL produces + ;; far too many of those for low-level things like untagged-SAP-to-tagged-SAP. + ;; So we could opt to STYLE-WARN, which is, in this case, perhaps more severe + ;; than we'd like? + ;; I guess we're just going to have to say that if you've muffled too may + ;; kinds of NOTEs, that's on you. + #-sb-xc-host (compiler-notify 'unknown-typep-note + :format-control "can't open-code test of unknown type ~S" + :format-arguments (list (type-specifier type))) `(let ((object ,object) (cache (load-time-value (cons #'sb-kernel::cached-typep ',spec) t))) @@ -531,13 +538,21 @@ (t (multiple-value-bind (widetags more-types) (sb-kernel::widetags-from-union-type types) - (if widetags - `(or (%other-pointer-subtype-p ,object ',widetags) - (typep ,object '(or ,@(mapcar #'type-specifier more-types)))) - `(or - ,@(mapcar (lambda (x) - `(typep ,object ',(type-specifier x))) - more-types)))))))) + (multiple-value-bind (predicate more-union-types) + (split-union-type-tests type) + (cond ((and predicate + (< (length more-union-types) + (length more-types))) + `(or (,predicate ,object) + (typep ,object '(or ,@(mapcar #'type-specifier more-union-types))))) + (widetags + `(or (%other-pointer-subtype-p ,object ',widetags) + (typep ,object '(or ,@(mapcar #'type-specifier more-types))))) + (t + `(or + ,@(mapcar (lambda (x) + `(typep ,object ',(type-specifier x))) + more-types)))))))))) ;;; Do source transformation for TYPEP of a known intersection type. (defun source-transform-intersection-typep (object type) @@ -546,52 +561,60 @@ (intersection-type-types type)))) ;;; If necessary recurse to check the cons type. -(defun source-transform-cons-typep (object type) - (let* ((car-type (cons-type-car-type type)) - (cdr-type (cons-type-cdr-type type)) - (car-test-p (not (type= car-type *universal-type*))) - (cdr-test-p (not (type= cdr-type *universal-type*)))) - (if (and (not car-test-p) (not cdr-test-p)) - `(consp ,object) - ;; CONSP can be safely weakened to LISTP if either of the CAR - ;; or CDR test (or both) can distinguish LIST from CONS - ;; by never returning T when given an input of NIL. - (labels ((safely-weakened (ctype) - (typecase ctype - (member-type - (not (member nil (member-type-members ctype)))) - (classoid - ;; can't weaken if the specifier is (CONS SYMBOL) - (not (ctypep nil ctype))) - ;; these are disjoint from NIL - ((or cons-type numeric-type array-type character-set-type) - t) - (intersection-type - ;; at least one of them must not spuriously return T - (some #'safely-weakened (compound-type-types ctype))) - (union-type - ;; require that none spuriously return T - (every #'safely-weakened (compound-type-types ctype))) - (hairy-type - ;; hack - (CONS KEYWORD) is weakenable - ;; because NIL is not a keyword. - (equal (hairy-type-specifier ctype) - '(satisfies keywordp)))))) - (let ((car-test - (and car-test-p - `((typep (car ,object) ',(type-specifier car-type))))) - (cdr-test - (and cdr-test-p - `((typep (cdr ,object) ',(type-specifier cdr-type)))))) - ;; Being paranoid, perform the safely weakenable test first - ;; so that the other part doesn't execute on an object that - ;; it would not have gotten, were the CONSP test not weakened. - (cond ((and car-test-p (safely-weakened car-type)) - `(and (listp ,object) ,@car-test ,@cdr-test)) - ((and cdr-test-p (safely-weakened cdr-type)) - `(and (listp ,object) ,@cdr-test ,@car-test)) - (t - `(and (consp ,object) ,@car-test ,@cdr-test)))))))) +(defun source-transform-cons-typep + (object type &aux (car-type (cons-type-car-type type)) + (cdr-type (cons-type-cdr-type type)) + (car-test-p (not (type= car-type *universal-type*))) + (cdr-test-p (not (type= cdr-type *universal-type*)))) + ;; CONSP can be safely weakened to LISTP if either of the CAR + ;; or CDR test (or both) can distinguish LIST from CONS + ;; by never returning T when given an input of NIL. + (labels ((safely-weakened (ctype) + (typecase ctype + (member-type + (not (member nil (member-type-members ctype)))) + (classoid + ;; can't weaken if the specifier is (CONS SYMBOL) + (not (ctypep nil ctype))) + ;; these are disjoint from NIL + ((or cons-type numeric-type array-type character-set-type) + t) + (intersection-type + ;; at least one of them must not spuriously return T + (some #'safely-weakened (compound-type-types ctype))) + (union-type + ;; require that none spuriously return T + (every #'safely-weakened (compound-type-types ctype))) + (hairy-type + ;; hack - (CONS KEYWORD) is weakenable + ;; because NIL is not a keyword. + (equal (hairy-type-specifier ctype) + '(satisfies keywordp)))))) + (cond + ((and (not car-test-p) (not cdr-test-p)) + `(consp ,object)) + ((and (not cdr-test-p) + (member-type-p car-type) + (vop-existsp :translate car-eq-if-listp) + (type-singleton-p car-type) + (typep (first (member-type-members car-type)) '(and symbol (not null)))) + `(car-eq-if-listp ,object ',(first (member-type-members car-type)))) + (t + (let ((car-test + (and car-test-p + `((typep (car ,object) ',(type-specifier car-type))))) + (cdr-test + (and cdr-test-p + `((typep (cdr ,object) ',(type-specifier cdr-type)))))) + ;; Being paranoid, perform the safely weakenable test first + ;; so that the other part doesn't execute on an object that + ;; it would not have gotten, were the CONSP test not weakened. + (cond ((and car-test-p (safely-weakened car-type)) + `(and (listp ,object) ,@car-test ,@cdr-test)) + ((and cdr-test-p (safely-weakened cdr-type)) + `(and (listp ,object) ,@cdr-test ,@car-test)) + (t + `(and (consp ,object) ,@car-test ,@cdr-test)))))))) (defun source-transform-character-set-typep (object type) (let ((pairs (character-set-type-pairs type))) @@ -601,11 +624,11 @@ #+(and sb-unicode (or x86-64 arm64)) ((= (cdar pairs) (1- base-char-code-limit)) `(base-char-p ,object)) - ((= (cdar pairs) (1- sb-xc:char-code-limit)) + ((= (cdar pairs) (1- char-code-limit)) `(characterp ,object)))) (let ((n-code (gensym "CODE"))) `(and (characterp ,object) - (let ((,n-code (sb-xc:char-code ,object))) + (let ((,n-code (char-code ,object))) (or ,@(loop for pair in pairs collect @@ -620,9 +643,10 @@ (simd-pack-p ,object) (let ((,n-tag (%simd-pack-tag ,object))) (or ,@(loop - for type in (simd-pack-type-element-type type) - for index = (position type *simd-pack-element-types*) - collect `(eql ,n-tag ,index)))))))) + for bit across (simd-pack-type-element-type type) + for i from 0 + if (= bit 1) + collect `(eql ,n-tag ,i)))))))) #+sb-simd-pack-256 (defun source-transform-simd-pack-256-typep (object type) @@ -633,9 +657,10 @@ (simd-pack-256-p ,object) (let ((,n-tag (%simd-pack-256-tag ,object))) (or ,@(loop - for type in (simd-pack-256-type-element-type type) - for index = (position type *simd-pack-element-types*) - collect `(eql ,n-tag ,index)))))))) + for bit across (simd-pack-256-type-element-type type) + for i from 0 + if (= bit 1) + collect `(eql ,n-tag ,i)))))))) ;;; Return the predicate and type from the most specific entry in ;;; *TYPE-PREDICATES* that is a supertype of TYPE. @@ -658,23 +683,26 @@ ;;; ;;; Secondary return value is true if passing the generated tests implies that ;;; the array has a header. -(defun test-array-dimensions (obj type stype +(defun test-array-dimensions (original-obj type stype simple-array-header-p) (declare (type array-type type stype)) - (let ((obj `(truly-the ,(type-specifier stype) ,obj)) + (let ((obj `(truly-the ,(type-specifier stype) ,original-obj)) (dims (array-type-dimensions type)) (header-test (if simple-array-header-p - `(simple-array-header-p ,obj) - `(array-header-p ,obj)))) + `(simple-array-header-p ,original-obj) + `(array-header-p ,original-obj)))) (unless (or (eq dims '*) (equal dims (array-type-dimensions stype))) (cond ((cdr dims) - (values `(,header-test - ,@(when (eq (array-type-dimensions stype) '*) - #+x86-64 - `((%array-rank= ,obj ,(length dims))) - #-x86-64 - `((= (%array-rank ,obj) ,(length dims)))) + (values `(,@(if (and simple-array-header-p + (vop-existsp :translate simple-array-header-of-rank-p) + (eq (array-type-dimensions stype) '*)) + `((simple-array-header-of-rank-p ,original-obj ,(length dims))) + `(,header-test + ,@(when (eq (array-type-dimensions stype) '*) + (if (vop-existsp :translate %array-rank=) + `((%array-rank= ,obj ,(length dims))) + `((= (%array-rank ,obj) ,(length dims))))))) ,@(loop for d in dims for i from 0 unless (eq '* d) @@ -759,7 +787,9 @@ (simple-array-header-p (and (null (array-type-complexp stype)) (listp dims) - (cdr dims)))) + (cdr dims))) + (complexp (and (eql (array-type-complexp stype) :maybe) + (eql (array-type-complexp type) t)))) (if complex-tag `(and (%other-pointer-p ,object) (eq (%other-pointer-widetag ,object) ,complex-tag) @@ -768,20 +798,31 @@ (multiple-value-bind (tests headerp) (test-array-dimensions object type stype simple-array-header-p) - `(and ,@(unless (or (and headerp (eql pred 'arrayp)) - simple-array-header-p) - ;; ARRAY-HEADER-P from TESTS will test for that - `((,pred ,object))) - ,@(when (and (eql (array-type-complexp stype) :maybe) - (eql (array-type-complexp type) t)) - ;; KLUDGE: this is a bit lame; if we get here, - ;; we already know that OBJECT is an array, but - ;; (NOT SIMPLE-ARRAY) doesn't know that. On the - ;; other hand, this should get compiled down to - ;; two widetag tests, so it's only a bit lame. - `((typep ,object '(not simple-array)))) - ,@tests - ,@(test-array-element-type object type stype headerp))))) + `(and + ,@(cond ((and (eql pred 'vectorp) + complexp) + `((%other-pointer-subtype-p ,object + ',(list sb-vm:complex-base-string-widetag + #+sb-unicode sb-vm:complex-character-string-widetag + sb-vm:complex-bit-vector-widetag + sb-vm:complex-vector-widetag)))) + ((and (eql pred 'arrayp) + complexp) + `((%other-pointer-subtype-p ,object + ',(list sb-vm:complex-base-string-widetag + #+sb-unicode sb-vm:complex-character-string-widetag + sb-vm:complex-bit-vector-widetag + sb-vm:complex-vector-widetag + sb-vm:complex-array-widetag)))) + (t + `(,@(unless (or (and headerp (eql pred 'arrayp)) + simple-array-header-p) + ;; ARRAY-HEADER-P from TESTS will test for that + `((,pred ,object))) + ,@(when complexp + `((typep ,object '(not simple-array))))))) + ,@tests + ,@(test-array-element-type object type stype headerp))))) `(%typep ,object ',(type-specifier type))))))) ;;; Transform a type test against some instance type. The type test is @@ -790,7 +831,7 @@ ;;; layout-EQ. If a structure then test for layout-EQ and then a ;;; general test based on layout-inherits. Otherwise, look up the indirect ;;; class-cell and call CLASS-CELL-TYPEP at runtime. -(deftransform %instance-typep ((object spec) (* *) * :node node) +(deftransform %instance-typep ((object spec) * * :node node) (aver (constant-lvar-p spec)) (let* ((spec (lvar-value spec)) (class (specifier-type spec)) @@ -832,156 +873,138 @@ ;;; object's layout can ever be EQ to that of the ancestor. ;;; e.g. a fixnum as representative of class REAL. ;;; So in actual practice, you can't make something that is a pure STREAM, etc. + +;;; TODOs: +;;; 1. There is an additional tweak that can potentially return false in one fewer +;;; conditional branch if the layout being tested has depthoid 8 (or 9 if #+64-bit). +;;; In that scenario, if the ID word of the candidate structure's layout does not +;;; exist, then it's the 0th bitmap word and safe to read always. Therefore +;;; STRUCTURE-IS-A and depthoid can be tested in that order. If there is no ID match, +;;; there's no depthoid test. If there is an ID match, it's the same as before. +;;; 2. Since all backends implement STRUCTURE-IS-A, is there any reason that the +;;; depthoid test is in the transform's expansion and not baked into that vop? +;;; Putting it in the vop could be better for some backends, +;;; and would eliminate the ad-hoc LAYOUT-DEPTHOID-GE vop. + +#-(or x86 x86-64) ; vop-translated for these 2 +(defmacro layout-depthoid-ge (layout depthoid) + `(>= (wrapper-depthoid ,layout) ,depthoid)) +(symbol-macrolet ((get-hash #+metaspace 'layout-clos-hash #-metaspace 'wrapper-clos-hash) + (get-flags #+metaspace 'layout-flags #-metaspace 'wrapper-flags)) (defun transform-instance-typep (classoid) (binding* ((name (classoid-name classoid)) - (layout (let ((res (info :type :compiler-layout name))) - (when (and res (not (layout-invalid res))) res))) - ((primtype-predicate slot-reader) + (wrapper (let ((res (info :type :compiler-layout name))) + (when (and res (not (wrapper-invalid res))) res))) + (layout (and wrapper (wrapper-friend wrapper))) + ((lowtag lowtag-test slot-reader) (cond ((csubtypep classoid (specifier-type 'funcallable-instance)) - (values '(function-with-layout-p object) - '(%fun-layout object))) - ((or (csubtypep classoid (specifier-type 'instance)) - ;; CONDITION can't be a funcallable-instance - (csubtypep classoid (specifier-type 'condition))) - (values '(%instancep object) - '(%instance-layout object))))) - (get-layout-or-return-false - (if primtype-predicate - ;; Test just one of %INSTANCEP or %FUNCALLABLE-INSTANCE-P - `(if ,primtype-predicate ,slot-reader (return-from typep nil)) - ;; But if we don't know which is will be, try both. - ;; This is less general than LAYOUT-OF,and therefore - ;; a little quicker to fail, because objects with - ;; {LIST|OTHER}-POINTER-LOWTAG can't possibly pass. - ;; It's a bit disappointing that STREAM uses this slower path, - ;; but some people think it should be possible to create - ;; funcallable streams. As a countermeasure, it would be possible to emit - ;; slightly better code in a vop. - `(cond ((%instancep object) (%instance-layout object)) - ((function-with-layout-p object) (%fun-layout object)) - (t (return-from typep nil))))) - (depthoid (if layout (layout-depthoid layout) -1)) - (n-layout (gensym)) - ;; In order to efficiently perform the DEEPER-P test without this hack of using - ;; a vop (when available for non-risc machines), we'd have to do two things: - ;; - have instcombine combine the read and compare as one instruction - ;; - implement half-width structure slots - ;; Since both of those are not happening any time soon, ... - (deeper-p - #+(vop-translates sb-c::layout-depthoid-gt) `(layout-depthoid-gt ,n-layout ,depthoid) - #-(vop-translates sb-c::layout-depthoid-gt) `(> (layout-depthoid ,n-layout) ,depthoid)) - (nth-ancestor ; This is possibly unused (if no compile-time layout, or depthoid -1) - ;; Use DATA-VECTOR-REF directly, since that's what SVREF in SAFETY 0 will become. - `(locally (declare (optimize (safety 0))) - (data-vector-ref (layout-inherits ,n-layout) ,depthoid))) - (ancestor-layout-eq - ;; Layouts are immediate constants in immobile space. Again, this is something that - ;; an instcombine pass might be able to recognize as having a single instruction. - #+(and immobile-space x86-64) `(sb-vm::layout-inherits-ref-eq - (layout-inherits ,n-layout) ,depthoid ,layout) - #-(and immobile-space x86-64) `(eq ,nth-ancestor ,layout)) - ;; For shallow depthoid we can avoid checking the depthoid or reading the 'inherits' - ;; slot, because the layout has some number of ancestor layouts directly in it. - (ancestor-slot (layout-nth-ancestor-slot depthoid))) + (values sb-vm:fun-pointer-lowtag + '(function-with-layout-p object) '(%fun-layout object))) + ((csubtypep classoid (specifier-type 'instance)) + (values sb-vm:instance-pointer-lowtag + '(%instancep object) '(%instance-layout object))))) + (depthoid (if wrapper (wrapper-depthoid wrapper) -1)) + (type (make-symbol "TYPE"))) + (declare (ignorable layout)) ;; Easiest case first: single bit test. (cond ((member name '(condition pathname structure-object)) - `(and (%instancep object) - (logtest (layout-flags (%instance-layout object)) - ,(case name - (condition +condition-layout-flag+) - (pathname +pathname-layout-flag+) - (t +structure-layout-flag+))))) + (let ((flag (case name + (condition +condition-layout-flag+) + (pathname +pathname-layout-flag+) + (t +structure-layout-flag+)))) + (if (vop-existsp :translate structure-typep) + `(structure-typep object ,flag) + `(and (%instancep object) + (logtest (,get-flags (%instance-layout object)) ,flag))))) + + ;; TODO: remove after April 2021 release. + ((eq name 'sb-kernel::random-class) + (style-warn "~S should not appear in a TYPEP test" name) + nil) - ;; Next easiest: Sealed and at most one subclass. - ((and (eq (classoid-state classoid) :sealed) layout - (or (not (classoid-subclasses classoid)) - (eql (hash-table-count (classoid-subclasses classoid)) - 1))) - ;; It's possible to seal a STANDARD-CLASS, not just a STRUCTURE-CLASS, - ;; though probably extremely weird. Also the PRED should be set in - ;; that event, but it isn't. - ;; The crummy dual expressions for the same result are because - ;; (BLOCK (RETURN ...)) seems to emit a forward branch in the - ;; passing case, but AND emits a forward branch in the failing - ;; case which I believe is the better choice. - (let ((other-layout (and (classoid-subclasses classoid) - (dohash ((classoid layout) - (classoid-subclasses classoid) - :locked t) - (declare (ignore classoid)) - (return layout))))) - (flet ((check-layout (layout-getter) - (cond (other-layout - ;; It's faster to compare two layouts than - ;; doing whatever is done below - `(let ((object-layout ,layout-getter)) - (or (eq object-layout ',layout) - (eq object-layout ',other-layout)))) - #+(vop-named sb-vm::layout-eq) - ((equal layout-getter '(%instance-layout object)) - `(sb-vm::layout-eq object ',layout)) - (t - `(eq ,layout-getter ',layout))))) - (if primtype-predicate - `(and ,primtype-predicate ,(check-layout slot-reader)) - `(block typep ,(check-layout get-layout-or-return-false)))))) + ;; Next easiest: Sealed and no subtypes. Typically for DEFSTRUCT only. + ;; Even if you don't seal a DEFCLASS, we're allowed to assume that things + ;; won't change, as per CLHS 3.2.2.3 on Semantic Constraints: + ;; "Classes defined by defclass in the compilation environment must be defined + ;; at run time to have the same superclasses and same metaclass." + ;; I think that means we should know the lowtag always. Nonetheless, this isn't + ;; an important scenario, and only if you _do_ seal a class could this case be + ;; reached; users rarely seal their classes since the standard doesn't say how. + ((and wrapper + (eq (classoid-state classoid) :sealed) + (not (classoid-subclasses classoid))) + (cond ((and (eq lowtag sb-vm:instance-pointer-lowtag) + (vop-existsp :translate structure-typep)) + `(structure-typep object ,wrapper)) + (lowtag-test + `(and ,lowtag-test + ,(if (vop-existsp :translate layout-eq) + `(layout-eq object ,wrapper ,lowtag) + `(eq ,slot-reader ,layout)))) + (t + ;; `(eq ,layout + ;; (if-vop-existsp (:translate %instanceoid-layout) + ;; (%instanceoid-layout object) + ;; ;; Slightly quicker than LAYOUT-OF. See also %PCL-INSTANCE-P + ;; (cond ((%instancep object) (%instance-layout object)) + ;; ((funcallable-instance-p object) (%fun-layout object)) + ;; (t ,(find-layout 't))))) + (bug "Unexpected metatype for ~S" wrapper)))) ;; All other structure types - ((and (typep classoid 'structure-classoid) layout) + ((and (typep classoid 'structure-classoid) wrapper) ;; structure type tests; hierarchical layout depths - (aver (equal primtype-predicate '(%instancep object))) + (aver (eql lowtag sb-vm:instance-pointer-lowtag)) ;; we used to check for invalid layouts here, but in fact that's both unnecessary and ;; wrong; it's unnecessary because structure classes can't be redefined, and it's wrong ;; because it is quite legitimate to pass an object with an invalid layout ;; to a structure type test. - `(and (%instancep object) - ;; If we allowed structure classes to be mixed in to standard-object, - ;; this might have to change to consider object invalidation. Probably would - ;; want to track structure classoids that would render this code inadmissible. - (let ((,n-layout (%instance-layout object))) - ,(cond ((<= 2 depthoid layout-inherits-max-optimized-depth) - `(or (eq (,ancestor-slot ,n-layout) ,layout) - (eq ,n-layout ,layout))) - ((dd-constructors (layout-info layout)) - `(cond ((eq ,n-layout ,layout) t) - (,deeper-p ,ancestor-layout-eq))) - (t ; abstract base type deeper than optimized max. - ;; Assume that no layout is EQ to the base layout, - ;; and unconditionally fetch and dereference layout-inherits. - `(eq (if ,deeper-p ,nth-ancestor ,n-layout) ,layout)))))) + (if (vop-existsp :translate structure-typep) + ;; A single VOP is easier to optimize later in ir2opt. + `(structure-typep object ,wrapper) + `(and (%instancep object) + ,(if (<= depthoid sb-kernel::layout-id-vector-fixed-capacity) + `(%structure-is-a (%instance-layout object) ,wrapper) + `(let ((,type (%instance-layout object))) + (and (layout-depthoid-ge ,type ,depthoid) + (%structure-is-a ,type ,wrapper))))))) - ((> depthoid 0) ; fixed-depth ancestors of non-structure types: STREAM, FILE-STREAM, - ;; SEQUENCE, CONDITION; all are abstract base types. + ((> depthoid 0) + ;; fixed-depth ancestors of non-structure types: + ;; STREAM, FILE-STREAM, STRING-STREAM, and SEQUENCE. #+sb-xc-host (when (typep classoid 'static-classoid) ;; should have use :SEALED code above - (bug "Non-frozen static classoids?")) - ;; quasi-hierarchical layout for other things: STREAM, FILE-STREAM, - ;; SEQUENCE, CONDITION; all are abstract base types. - (let ((guts `(,@(unless (eq name 'condition) - `((when (zerop (layout-clos-hash ,n-layout)) - (setq ,n-layout - (truly-the layout - (update-object-layout-or-invalid - object ',layout)))))) - ;; the Nth ancestor for N=1 is not directly stored in the layout. - ;; But we don't have to check the layout-inherits length because - ;; it has as least two physical data elements even if it has T - ;; as the sole ancestor. - (or ,(if (eql depthoid 1) - ancestor-layout-eq - `(eq (,ancestor-slot ,n-layout) ,layout)) - ;; So that (TYPEP (MAKE-CONDITION 'CONDITION) 'CONDITION) => T - ,@(when (eq name 'condition) `((eq ,n-layout ,layout))))))) - (if primtype-predicate - `(and ,primtype-predicate (let ((,n-layout ,slot-reader)) ,@guts)) - `(block typep - (let ((,n-layout ,get-layout-or-return-false)) ,@guts))))) + (bug "Non-frozen static classoids ~S" name)) + (let ((guts `((when (zerop (,get-hash ,type)) + (setq ,type (update-object-layout object))) + ,(ecase name + (stream + `(logtest (,get-flags ,type) ,+stream-layout-flag+)) + (file-stream + `(logtest (,get-flags ,type) ,+file-stream-layout-flag+)) + (string-stream + `(logtest (,get-flags ,type) ,+string-stream-layout-flag+)) + ;; Testing the type EXTENDED-SEQUENCE tests for #<LAYOUT of SEQUENCE>. + ;; It can only arise from a direct invocation of TRANSFORM-INSTANCE-TYPEP, + ;; because the lisp type is not a classoid. It's done this way to define + ;; the logic once only, instead of both here and src/code/pred.lisp. + (sequence + `(logtest (,get-flags ,type) ,+sequence-layout-flag+)))))) + (if lowtag-test + `(and ,lowtag-test (let ((,type ,slot-reader)) ,@guts)) + (if-vop-existsp (:translate %instanceoid-layout) + `(let ((,type (%instanceoid-layout object))) ,@guts) + `(block typep + (let ((,type (cond ((%instancep object) (%instance-layout object)) + ((funcallable-instance-p object) (%fun-layout object)) + (t (return-from typep nil))))) + ,@guts)))))) (t `(classoid-cell-typep ',(find-classoid-cell name :create t) - object))))) + object)))))) ;;; If the specifier argument is a quoted constant, then we consider ;;; converting into a simple predicate or other stuff. If the type is @@ -1000,6 +1023,10 @@ (let ((ctype (careful-specifier-type type))) (if ctype (or + ;; It's purely a waste of compiler resources to wait for IR1 to + ;; see these 2 edge cases that can be decided right now. + (cond ((eq ctype *universal-type*) t) + ((eq ctype *empty-type*) nil)) (and (not (intersection-type-p ctype)) (multiple-value-bind (constantp value) (type-singleton-p ctype) (and constantp @@ -1027,8 +1054,6 @@ (args-type (compiler-warn "illegal type specifier for TYPEP: ~S" type) (return-from %source-transform-typep (values nil t))) - (t nil)) - (typecase ctype (numeric-type (source-transform-numeric-typep object ctype)) (classoid @@ -1060,6 +1085,44 @@ (values `(let ((,name ,object)) (%typep-wrapper ,transform ,name ',type))))))) +;;; These things will be removed by the tree shaker, so no #+ needed. +(defvar *interesting-types* nil) +(defun involves-alien-p (ctype) + (sb-kernel::map-type + (lambda (type) + (when (alien-type-type-p type) (return-from involves-alien-p t))) + ctype)) +(defun dump/restore-interesting-types (op) + (declare (ignorable op)) + #+collect-typep-regression-dataset + (ecase op + (write + (when *interesting-types* + (let ((list (sort (loop for k being each hash-key of *interesting-types* collect k) + #'string< :key #'write-to-string))) + (with-open-file (f "interesting-types.lisp-expr" :direction :output + :if-exists :supersede :if-does-not-exist :create) + (let ((*package* #+sb-xc-host (find-package "XC-STRICT-CL") + #-sb-xc-host #.(find-package "SB-KERNEL")) + (*print-pretty* nil) + (*print-length* nil) + (*print-level* nil) + (*print-readably* t)) + (dolist (item list) + (write (uncross item) :stream f) + (terpri f))))))) + (read + (unless (hash-table-p *interesting-types*) + (setq *interesting-types* (make-hash-table :test 'equal :synchronized t))) + (with-open-file (f "interesting-types.lisp-expr" :if-does-not-exist nil) + (when f + (let ((*package* (find-package "SB-KERNEL"))) + (loop (let ((expr (read f nil f))) + (when (eq expr f) (return)) + (format t "Read ~a~%" expr) + (setf (gethash expr *interesting-types*) t)))))) + *interesting-types*))) + (define-source-transform typep (object spec &optional env) ;; KLUDGE: It looks bad to only do this on explicitly quoted forms, ;; since that would overlook other kinds of constants. But it turns @@ -1076,8 +1139,24 @@ ;; during block compilation, we give ourselves a better chance ;; at open-coding the type test. (let ((type (cadr spec))) + ;; + #+collect-typep-regression-dataset + (let ((parse (specifier-type type))) + ;; alien types aren't externalizable as trees of symbols, + ;; and some classoid types aren't defined at the start of warm build, + ;; making it impossible to re-parse a dump produced late in the build. + ;; Luckily there are no cases involving compund types and classoids. + (unless (or (involves-alien-p parse) + (or (classoid-p parse) + (and (cons-type-p parse) + (classoid-p (cons-type-car-type parse))))) + (let ((table *interesting-types*)) + (unless (hash-table-p table) + (setq table (dump/restore-interesting-types 'read))) + (setf (gethash type table) t)))) + ;; (if (and (block-compile *compilation*) - (unknown-type-p (specifier-type type))) + (contains-unknown-type-p (careful-specifier-type type))) (values nil t) (source-transform-typep object type)))) (values nil t))) @@ -1155,6 +1234,35 @@ (error "~a is not a subtype of VECTOR." type))))) (simplify type))) +(defun strip-array-dimensions-and-complexity (type) + (labels ((process-compound-type (types) + (let (array-types) + (dolist (type types) + (unless (or (hairy-type-p type) + (sb-kernel::negation-type-p type)) + (push (strip type) array-types))) + (apply #'type-union array-types))) + (strip (type) + (cond ((array-type-p type) + (let ((dim (array-type-dimensions type))) + (make-array-type + (if (eq dim '*) + dim + (make-list (length dim) + :initial-element '*)) + :complexp :maybe + :element-type (array-type-element-type type) + :specialized-element-type (array-type-specialized-element-type type)))) + ((union-type-p type) + (process-compound-type (union-type-types type))) + ((intersection-type-p type) + (process-compound-type (intersection-type-types type))) + ((member-type-p type) + (process-compound-type + (mapcar #'ctype-of (member-type-members type)))) + (t + (error "~a is not a subtype of ARRAY." type))))) + (strip type))) (defun check-coerce (value-type to-type type-specifier node) (flet ((fail () @@ -1189,7 +1297,7 @@ (t (fail))))) -(deftransform coerce ((x type) (* *) * :node node) +(deftransform coerce ((x type) * * :node node) (unless (constant-lvar-p type) (give-up-ir1-transform)) (let* ((tval (lvar-value type)) @@ -1210,7 +1318,9 @@ (if (types-equal-or-intersect value-type (specifier-type 'float)) `(the ,tval (if (floatp x) x - (%single-float x))) + (let ((r (the* (real :silent-conflict t) x))) + (declare (muffle-conditions code-deletion-note)) + (sb-kernel:%single-float r)))) `(the ,tval (%single-float x)))) ((csubtypep tspec (specifier-type 'complex)) (multiple-value-bind (part-type result-type) @@ -1239,49 +1349,57 @@ `(the ,result-type (complex (coerce (realpart x) ',part-type) (coerce (imagpart x) ',part-type))))))))) - ;; Special case STRING and SIMPLE-STRING as they are union types - ;; in SBCL. - ((member tval '(string simple-string)) - `(the ,tval - (if (typep x ',tval) - x - (replace (make-array (length x) :element-type 'character) x)))) ((eq tval 'character) `(character x)) - ;; Special case VECTOR - ((eq tval 'vector) - `(the ,tval - (if (vectorp x) - x - (replace (make-array (length x)) x)))) ;; Handle specialized element types for 1D arrays. - ((csubtypep tspec (specifier-type '(array * (*)))) - ;; Can we avoid checking for dimension issues like (COERCE FOO - ;; '(SIMPLE-VECTOR 5)) returning a vector of length 6? - ;; - ;; CLHS actually allows this for all code with SAFETY < 3, - ;; but we're a conservative bunch. - (if (or (policy node (zerop safety)) ; no need in unsafe code - (and (array-type-p tspec) ; no need when no dimensions - (equal (array-type-dimensions tspec) '(*)))) - ;; We can! - (multiple-value-bind (vtype etype upgraded) (simplify-vector-type tspec) - (unless upgraded - (give-up-ir1-transform)) - (let ((vtype (type-specifier vtype))) - `(the ,vtype - (if (typep x ',vtype) - x - (replace - (make-array (length x) - ,@(and (not (eq etype *universal-type*)) - (not (eq etype *wild-type*)) - `(:element-type ',(type-specifier etype)))) - x))))) - ;; No, duh. Dimension checking required. - (give-up-ir1-transform - "~@<~S specifies dimensions other than (*) in safe code.~:@>" - tval))) + ((multiple-value-bind (result already-type-p dimension specialization) + (cond ((or (and (array-type-p tspec) + (neq (array-type-complexp tspec) t) ; :MAYBE and NIL are good + (not (contains-unknown-type-p (array-type-element-type tspec))) + ;; just for requesting (array nil (*)), you lose + (neq (array-type-specialized-element-type tspec) *empty-type*) + (consp (array-type-dimensions tspec)))) + (values tspec + (source-transform-array-typep 'x tspec) + (car (array-type-dimensions tspec)) + (let ((et (array-type-specialized-element-type tspec))) + (unless (or (eq et *universal-type*) ; don't need + ;; * is illegal as :element-type; in this context + ;; it means to produce a SIMPLE-VECTOR + (eq et *wild-type*)) + `(:element-type ',(type-specifier et)))))) + ;; Check for string types. This loses on (STRING 1) and such. + #+sb-unicode + ((type= tspec (specifier-type 'simple-string)) + (values 'simple-string '(simple-string-p x) '* '(:element-type 'character))) + #+sb-unicode + ((type= tspec (specifier-type 'string)) + (values 'string '(stringp x) '* '(:element-type 'character)))) + (when result + ;; If the dimension is in the type, we check the input length if safety > 0, + ;; though technically CLHS would allow not checking in safety < 3. + ;; And if mismatch occurs in unsafe code, the results accords with the + ;; specifier, NOT the dimension of the input. This is a rational choice + ;; because one could not argue that incorrect code should have taken the + ;; bad input's length when COERCE was asked for an exact type of output. + `(truly-the ,result + (if ,already-type-p + x + ,(cond ((eq dimension '*) + #+ubsan + ;; Passing :INITIAL-CONTENTS avoids allocating ubsan shadow bits, + ;; but redundantly checks the length of the input in MAKE-ARRAY's + ;; transform because we don't or can't infer that LENGTH gives the + ;; same answer each time it is called on X. There may be a way to + ;; extract more efficiency - at least eliminate the unreachable + ;; error-signaling code on mismatch - but I don't care to try. + `(make-array (length x) ,@specialization :initial-contents x) + #-ubsan ; better: do not generate a redundant LENGTH check + `(replace (make-array (length x) ,@specialization) x)) + ((policy node (= safety 0)) ; Disregard the input length + `(replace (make-array ,dimension ,@specialization) x)) + (t + `(make-array ,dimension ,@specialization :initial-contents x)))))))) ((type= tspec (specifier-type 'list)) `(coerce-to-list x)) ((csubtypep tspec (specifier-type 'function)) @@ -1298,7 +1416,7 @@ tval))))) (deftransform #+64-bit unsigned-byte-64-p #-64-bit unsigned-byte-32-p - ((value) (fixnum) * :important nil) + ((value) (sb-vm:signed-word) * :important nil) `(>= value 0)) (deftransform %other-pointer-p ((object)) @@ -1313,3 +1431,6 @@ ((csubtypep (lvar-type object) this-type) nil) ((give-up-ir1-transform))))) + +;;; BIGNUMP is simpler than INTEGERP, so if we can rule out FIXNUM then ... +(deftransform integerp ((x) ((not fixnum)) * :important nil) '(bignump x)) diff --git a/src/compiler/vmdef.lisp b/src/compiler/vmdef.lisp index 27979596a3..382f2a503b 100644 --- a/src/compiler/vmdef.lisp +++ b/src/compiler/vmdef.lisp @@ -111,8 +111,8 @@ (last-result (1- num-operands)) (temps (vop-info-temps template)) ;; Can't have more temps than registers in the CPU. - ;; 32 is totally reasonable - (refs (make-array (+ (* 2 (the (mod 32) (length temps))) + ;; 64 is totally reasonable + (refs (make-array (+ (* 2 (the (mod 64) (length temps))) num-operands))) (ref-ordering (vop-info-ref-ordering template))) (declare (dynamic-extent refs)) @@ -196,7 +196,7 @@ ;;; Return a function type specifier describing TEMPLATE's type computed ;;; from the operand type restrictions. -#-sb-fluid (declaim (inline template-conditional-p)) +(declaim (inline template-conditional-p)) (defun template-conditional-p (template) (declare (type template template)) (let ((rtypes (template-result-types template))) @@ -222,13 +222,11 @@ (results (if (template-conditional-p template) '(boolean) (convert result-restr - (cond ((template-more-results-type template)) - ((/= (length result-restr) 1) '*) - (t nil)))))) + (template-more-results-type template))))) `(function ,args - ,(if (= (length results) 1) - (first results) - `(values ,@results)))))) + (values ,@results + ,@(unless (template-more-results-type template) + '(&optional))))))) (defun template-translates-arg-p (function argument type) (let ((primitive-type (primitive-type (specifier-type type)))) diff --git a/src/compiler/vop-existsp.lisp b/src/compiler/vop-existsp.lisp new file mode 100644 index 0000000000..3e43a01c82 --- /dev/null +++ b/src/compiler/vop-existsp.lisp @@ -0,0 +1,71 @@ +;;;; This software is part of the SBCL system. See the README file for +;;;; more information. +;;;; +;;;; This software is derived from the CMU CL system, which was +;;;; written at Carnegie Mellon University and released into the +;;;; public domain. The software is in the public domain and is +;;;; provided with absolutely no warranty. See the COPYING and CREDITS +;;;; files for more information. + +(in-package "SB-C") + +;;; translation from template names to template structures +(defglobal *backend-template-names* (make-hash-table)) ; keys are symbols +(declaim (type hash-table *backend-template-names*)) + +;;; When compiling the cross-compiler, a %VOP-EXISTS-P result could depend on +;;; the build order. Usually it will not, because the decision to use a vop is +;;; typically made in a transform, so the query occurs only when a transform runs. +;;; However, sometimes the existsp check is performed to decide whether or not +;;; to define a function or other transform. In that case the existsp check is +;;; sensitive to the order of vop definitions. Such uses will often occur inside +;;; a "#." so that the defining form remains toplevel. +;;; If called with OPTIMISTIC = T then we're trying to return NIL or T +;;; from the VOP-EXISTSP macroexpander, and if NIL then we decide later. +#-(and sb-xc (not sb-devel)) +(progn + (defvar *vop-not-existsp* nil) + ;;; This function is invoked after compiling the cross-compiler + ;;; before quitting the image, and when loading it from compiled fasls + ;;; (because toplevel forms might use %VOP-EXISTSP at any time). + (defun %vop-existsp (name query &optional optimistic) + (declare (notinline info fun-info-templates)) + (let ((answer + (not (null (ecase query + (:named + (gethash name *backend-template-names*)) + (:translate + (awhen (info :function :info name) + (fun-info-templates it)))))))) + ;; Negatives won't be stored in the journal in optimistic mode. + (when (and (not answer) (not optimistic)) + (pushnew (cons name query) *vop-not-existsp* :test 'equal)) + answer)) + (defun check-vop-existence-correctness () + (dolist (entry *vop-not-existsp*) + (assert (not (%vop-existsp (car entry) (cdr entry))))))) + +(defmacro vop-existsp (query name) + #+sb-xc-host + (cond ((%vop-existsp name query t) + ;;(format t "~&VOP-EXISTSP ~s ~s: Yes~%" name query) + t) + (t + ;;(format t "~&VOP-EXISTSP ~s ~s: DEFER~%" name query) + `(%vop-existsp ',name ,query))) + ;; When running the cross-compiler, all the inquiries to VOP-EXISTSP have + ;; definitive answers, so this never defers. + ;; We use the version of %VOP-EXISTSP that was built in to the host. + #-sb-xc-host + (funcall '%vop-existsp name query)) + +;;; For situations where you want to write (IF (VOP-EXISTSP ...) (THEN) (ELSE)) +;;; but at least one of (THEN) or (ELSE) contains code that can't be macroexpanded +;;; or compiled, as may occur with (VOP* ...), use a different macro that never +;;; defers. Correctness of the result requires that the vop be defined in time. +(defmacro if-vop-existsp ((query name) then &optional else) + (if (funcall '%vop-existsp name query) then else)) +(defmacro when-vop-existsp ((query name) &body body) + (if (funcall '%vop-existsp name query) `(progn ,@body))) +(defmacro unless-vop-existsp ((query name) &body body) + (if (not (funcall '%vop-existsp name query)) `(progn ,@body))) diff --git a/src/compiler/vop.lisp b/src/compiler/vop.lisp index 8e643ada81..99b4d9372d 100644 --- a/src/compiler/vop.lisp +++ b/src/compiler/vop.lisp @@ -134,8 +134,8 @@ ;;; environment pointer should be saved after the binding is ;;; instantiated. ;;; -;;; PHYSENV-INFO -;;; Holds the IR2-PHYSENV structure. +;;; ENVIRONMENT-INFO +;;; Holds the IR2-ENVIRONMENT structure. ;;; ;;; TAIL-SET-INFO ;;; Holds the RETURN-INFO structure. @@ -231,7 +231,9 @@ (dropped-thru-to nil) ;; list of LOCATION-INFO structures describing all the interesting ;; (to the debugger) locations in this block - (locations nil :type list)) + (locations nil :type list) + ;; reference to list of source paths for coverage + (covered-paths-ref (list nil) :type list)) (defprinter (ir2-block :identity t) (pushed :test pushed) @@ -354,9 +356,6 @@ (constants (make-array 10 :fill-pointer 1 :adjustable t :initial-element :ignore) :type vector :read-only t) - ;; some kind of info about the component's run-time representation. - ;; This is filled in by the VM supplied SELECT-COMPONENT-FORMAT function. - format ;; a list of the ENTRY-INFO structures describing all of the entries ;; into this component. Filled in by entry analysis. (entries nil :type list) @@ -375,8 +374,12 @@ ;; collect dynamic statistics.) #+sb-dyncount (dyncount-info nil :type (or null dyncount-info)) - #+avx2 - (avx2-used-p nil)) + ;; the number of jump table entries in this component + (n-jump-table-entries 0 :type index) + ;; an array of references to lists of original source paths covered + ;; for coverage instrumentation. + (coverage-map (make-array 0 :fill-pointer 0 :adjustable t) + :type vector :read-only t)) ;;; An ENTRY-INFO condenses all the information that the dumper needs ;;; to create each XEP's function entry data structure. ENTRY-INFO @@ -396,7 +399,7 @@ ;; some string that is intended to be informative. (name "<not computed>" :type (or simple-string list symbol)) ;; the argument list that the function was defined with. - (arguments nil :type list) + (arguments :unknown :type (or list (eql :unknown))) ;; source form and/or docstring (form/doc nil :type (or list string (cons t string))) ;; a function type specifier representing the arguments and results @@ -408,16 +411,16 @@ (xref (entry-info-xref entry))) (if (and type xref) (cons type xref) (or type xref)))) -;;; An IR2-PHYSENV is used to annotate non-LET LAMBDAs with their -;;; passing locations. It is stored in the PHYSENV-INFO. -(defstruct (ir2-physenv (:copier nil)) +;;; An IR2-ENVIRONMENT is used to annotate non-LET LAMBDAs with their +;;; passing locations. It is stored in the ENVIRONMENT-INFO. +(defstruct (ir2-environment (:copier nil)) ;; TN info for closed-over things within the function: an alist ;; mapping from NLX-INFOs and LAMBDA-VARs to TNs holding the ;; corresponding thing within this function ;; ;; Elements of this list have a one-to-one correspondence with - ;; elements of the PHYSENV-CLOSURE list of the PHYSENV object that - ;; links to us. + ;; elements of the ENVIRONMENT-CLOSURE list of the ENVIRONMENT + ;; object that links to us. (closure (missing-arg) :type list :read-only t) ;; the TNs that hold the OLD-FP and RETURN-PC within the function. ;; We always save these so that the debugger can do a backtrace, @@ -459,7 +462,7 @@ #+unwind-to-frame-and-call-vop (bsp-save-tn nil :type (or tn null))) -(defprinter (ir2-physenv) +(defprinter (ir2-environment) closure old-fp return-pc @@ -576,6 +579,10 @@ (target nil :type (or null tn-ref)) ;; the load TN allocated for this operand, if any (load-tn nil :type (or tn null)) + ;; on CISC microprocessors, a representation of the memory load + ;; (or store) based on this TN-REF (for which its TN is the base register) + ;; and not directly an operand from/into which the TN-REF flows. + (memory-access) ;; The type of the LVAR the TN of this TN-REF is used for. (type nil :type (or ctype null))) @@ -688,7 +695,7 @@ ;; ;; :KNOWN-RETURN ;; If needed, the old NFP is computed using COMPUTE-OLD-NFP. - (move-args nil :type (member nil :full-call :local-call :known-return)) + (move-args nil :type (member nil :full-call :local-call :known-return :fixed)) ;; a list of sc-vectors representing the loading costs of each fixed ;; argument and result (arg-costs nil :type list) @@ -705,6 +712,7 @@ ;; operand SC restriction. (arg-load-scs nil :type list) (result-load-scs nil :type list) + (more-arg-load-scs nil :type (or null sc-vector)) ;; a function that emits assembly code for a use of this VOP when it ;; is called with the VOP structure. This is null if this VOP has no ;; specified generator (i.e. if it exists only to be inherited by @@ -731,7 +739,21 @@ ;; MAX-VOP-TN-REFS) and the dest ref index. (targets nil :type (or null (simple-array (unsigned-byte 16) 1))) (optimizer nil :type (or null function)) - move-vop-p) + (optional-results nil :type list) + move-vop-p + (after-sc-selection nil :type (or null function) :read-only t)) +(!set-load-form-method vop-info (:xc :target) :ignore-it) + +(declaim (inline vop-name)) +(defun vop-name (vop) + (declare (type vop vop)) + (vop-info-name (vop-info vop))) + +(defun set-vop-optimizer (info fun) + (when (vop-info-optimizer info) + ;; Warn about trying to make two optimizers, because it doesn't work + (warn "Redefining vop-info-optimizer for ~S" (vop-info-name info))) + (setf (vop-info-optimizer info) fun)) ;; These printers follow the definition of VOP-INFO because they ;; want to inline VOP-INFO-NAME, and it's less code to move them here @@ -744,12 +766,8 @@ (defprinter (tn-ref) tn write-p - (vop :test vop :prin1 (vop-info-name (vop-info vop)))) + (vop :test vop :prin1 (vop-name vop))) -(declaim (inline vop-name)) -(defun vop-name (vop) - (declare (type vop vop)) - (vop-info-name (vop-info vop))) ;;;; SBs and SCs @@ -850,7 +868,8 @@ ;;; The compiler will never look at the toplevel value though. (defvar *finite-sbs* #-sb-xc-host - (make-array #.(count :non-packed *backend-sbs* :key #'sb-kind :test #'neq))) + (make-array #.(count :non-packed *backend-sbs* :key #'sb-kind :test #'neq) + :initial-element (make-unbound-marker))) #-sb-xc-host (progn (declaim (type (simple-vector #.(length *finite-sbs*)) *finite-sbs*) @@ -1084,8 +1103,8 @@ ;; some kind of info about how important this TN is (cost 0 :type fixnum) ;; If a :ENVIRONMENT or :DEBUG-ENVIRONMENT TN, this is the - ;; physical environment that the TN is live throughout. - (physenv nil :type (or physenv null)) + ;; environment that the TN is live throughout. + (environment nil :type (or environment null)) ;; Used by pack-iterative (vertex nil)) @@ -1110,8 +1129,7 @@ (:copier nil)) ;; the IR2-BLOCK that this structure represents the conflicts for (block (missing-arg) :type ir2-block) - ;; thread running through all the GLOBAL-CONFLICTSs for BLOCK. This - ;; thread is sorted by TN number + ;; thread running through all the GLOBAL-CONFLICTSs for BLOCK. (next-blockwise nil :type (or global-conflicts null)) ;; the way that TN is used by BLOCK ;; diff --git a/src/compiler/x86-64/alloc.lisp b/src/compiler/x86-64/alloc.lisp index 9282182b76..152252c74a 100644 --- a/src/compiler/x86-64/alloc.lisp +++ b/src/compiler/x86-64/alloc.lisp @@ -22,7 +22,7 @@ (inst mov result base) (inst lea result (ea lowtag base)))) -(defun stack-allocation (alloc-tn size lowtag) +(defun stack-allocation (size lowtag alloc-tn &optional known-alignedp) (aver (not (location= alloc-tn rsp-tn))) (inst sub rsp-tn size) ;; see comment in x86/macros.lisp implementation of this @@ -32,106 +32,143 @@ ;; - It's not the job of FIXED-ALLOC to realign anything. ;; - The real issue is that it's not obvious that the stack is ;; 16-byte-aligned at *all* times. Maybe it is, maybe it isn't. - (inst and rsp-tn #.(lognot lowtag-mask)) + (unless known-alignedp ; can skip this AND if we're all good + (inst and rsp-tn #.(lognot lowtag-mask))) (tagify alloc-tn rsp-tn lowtag) (values)) -;;; For assemfile -#+(and avx2 sb-xc-host) -(defvar *avx-registers-used-p* nil) - -#+avx2 -(defun avx-registers-used-p () - (or #+sb-xc-host *avx-registers-used-p* - (when (and #+sb-xc-host (boundp '*component-being-compiled*)) - (let ((comp (component-info *component-being-compiled*))) - (or (sb-c::ir2-component-avx2-used-p comp) - (flet ((used-p (tn) - (do ((tn tn (sb-c::tn-next tn))) - ((null tn)) - (when (sc-is tn avx2-reg - int-avx2-reg - double-avx2-reg single-avx2-reg) - (return-from avx-registers-used-p - (setf (sb-c::ir2-component-avx2-used-p comp) t)))))) - (used-p (sb-c::ir2-component-normal-tns comp)) - (used-p (sb-c::ir2-component-wired-tns comp)))))))) - -;;; Call an allocator trampoline and get the result in the proper register. -;;; There are 2x2x2 choices of trampoline: -;;; - invoke alloc() or alloc_list() in C -;;; - place result into R11, or leave it on the stack -;;; - preserve YMM registers around the call, or don't -;;; Rather than have 8 different DEFINE-ASSEMBLY-ROUTINEs, there are only 4, -;;; and each has 2 entry points. The earlier entry adds 1 more instruction -;;; to set the non-cons bit (the first of the binary choices mentioned above). -;;; Most of the time, the inline allocation sequence wants to use the trampoline -;;; that returns a result in TEMP-REG-TN (R11) which saves one move and -;;; clears the size argument from the stack in the RET instruction. -;;; If the result is returned on the stack, then we pop it below. -(defun %alloc-tramp (type node result-tn size lowtag) - (let ((consp (eq type 'list)) - (to-r11 (location= result-tn r11-tn))) - (when (typep size 'integer) - (aver (= (align-up size (* 2 n-word-bytes)) size)) - (when (neq type 'list) - (incf size) ; the low bit means we're allocating a non-cons object - ;; Jump into the cons entry point which saves one instruction because why not. - (setq consp t))) - (cond ((typep size '(and integer (not (signed-byte 32)))) - ;; MOV accepts large immediate operands, PUSH does not - (inst mov result-tn size) - (inst push result-tn)) - (t - (inst push size))) - (invoke-asm-routine - 'call - (cond #+avx2 - ((avx-registers-used-p) - (if to-r11 - (if consp 'cons->r11.avx2 'alloc->r11.avx2) - (if consp 'cons->rnn.avx2 'alloc->rnn.avx2))) - (t - (if to-r11 - (if consp 'cons->r11 'alloc->r11) - (if consp 'cons->rnn 'alloc->rnn)))) - node) - (unless to-r11 - (inst pop result-tn))) - (unless (eql lowtag 0) - (inst or :byte result-tn lowtag))) +(defun alloc-unboxed-p (type) + (case type + ((unboxed-array + #.bignum-widetag + #.sap-widetag + #.double-float-widetag + #.complex-single-float-widetag + #.complex-double-float-widetag) + t))) ;;; Insert allocation profiler instrumentation -(defun instrument-alloc (size node) +(eval-when (:compile-toplevel) + (aver (= thread-tot-bytes-alloc-unboxed-slot + (1+ thread-tot-bytes-alloc-boxed-slot)))) + +;;; the #+allocator metrics histogram contains an exact count +;;; for all sizes up to (* cons-size n-word-bytes histogram-small-bins). +;;; Larger allocations are grouped by the binary log of the size. +;;; It seems that 99.5% of all allocations are less than the small bucket limit, +;;; making the histogram fairly exact except for the tail. +(defparameter *consing-histo* nil) +(defconstant non-small-bucket-offset + (+ histogram-small-bins + (- (integer-length (* sb-vm::histogram-small-bins + sb-vm:cons-size sb-vm:n-word-bytes))))) + +;;; Emit counter increments for SB-APROF. SCRATCH-REGISTERS is either a TN +;;; or list of TNs that can be used to store into the profiling data. +;;; We pick one of the available TNs to use for addressing the data buffer. +;;; The TN that we pick can't be R12 because encoding it into an instruction +;;; always requires a SIB byte, which doesn't fit in the reserved bytes +;;; of the instruction stream where hot patching occurs. +(defun instrument-alloc (type size node scratch-registers + &optional thread-temp + &aux (temp + (if (listp scratch-registers) + (dolist (reg scratch-registers + (first scratch-registers)) + (unless (location= reg r12-tn) (return reg))) + scratch-registers))) + (declare (ignorable type thread-temp)) + (aver (not (location= temp r12-tn))) + ;; Each allocation sequence has to call INSTRUMENT-ALLOC, + ;; so we may as well take advantage of this fact to load the temp reg + ;; here, if provided, rather than spewing more #+gs-seg tests around. + #+gs-seg (when thread-temp (inst rdgsbase thread-temp)) + #+allocator-metrics + (let ((use-size-temp (not (typep size '(or (signed-byte 32) tn)))) + (tally (gen-label)) + (inexact (gen-label))) + (cond ((tn-p type) ; from ALLOCATE-VECTOR-ON-HEAP + ;; Constant huge size + unknown type can't occur. + (aver (not use-size-temp)) + (inst cmp :byte type simple-vector-widetag) + (inst set :ne temp) + (inst and :dword temp 1) + (inst add :qword + (ea thread-segment-reg + (ash thread-tot-bytes-alloc-boxed-slot word-shift) + thread-tn temp 8) + size)) + (t + (inst add :qword + (thread-slot-ea (if (alloc-unboxed-p type) + thread-tot-bytes-alloc-unboxed-slot + thread-tot-bytes-alloc-boxed-slot)) + (cond (use-size-temp (inst mov temp size) temp) + (t size))))) + (cond ((tn-p size) + (inst cmp size (* histogram-small-bins 16)) + (inst jmp :g inexact) + (inst mov :dword temp size) + (inst shr :dword temp (1+ word-shift)) + (inst dec :dword temp) + (inst jmp tally) + (emit-label inexact) + (inst bsr temp size) + ;; bsr returns 1 less than INTEGER-LENGTH + (inst add :dword temp (1+ non-small-bucket-offset)) + (emit-label tally) + (inst inc :qword (ea thread-segment-reg + (ash thread-obj-size-histo-slot word-shift) + thread-tn temp 8))) + (t + (let* ((n-conses (/ size (* sb-vm:cons-size sb-vm:n-word-bytes))) + (bucket (if (<= n-conses histogram-small-bins) + (1- n-conses) + (+ (integer-length size) + non-small-bucket-offset)))) + (inst inc :qword + (thread-slot-ea (+ thread-obj-size-histo-slot bucket))))))) (when (policy node (> sb-c::instrument-consing 1)) - (let ((skip-instrumentation (gen-label))) - (inst mov temp-reg-tn (thread-slot-ea thread-profile-data-slot)) - (inst test temp-reg-tn temp-reg-tn) + (when (tn-p size) + (aver (not (location= size temp)))) + (let ((data temp) + (patch-loc (gen-label)) + (skip-instrumentation (gen-label))) + (inst mov data (thread-slot-ea thread-profile-data-slot thread-temp)) + (inst test data data) ;; This instruction is modified to "JMP :z" when profiling is ;; partially enabled. After the buffer is assigned, it becomes ;; fully enabled. The unconditional jmp gives minimal performance ;; loss if the profiler is statically disabled. (one memory ;; read and a test whose result is never used, which the CPU ;; is good at ignoring as far as instruction prefetch goes) + (emit-label patch-loc) + (push patch-loc (sb-assem::asmstream-alloc-points sb-assem:*asmstream*)) (inst jmp skip-instrumentation) (emit-alignment 3 :long-nop) - (let ((helper (if (integerp size) - 'enable-alloc-counter - 'enable-sized-alloc-counter))) - (cond ((or (not node) ; assembly routine - (sb-c::code-immobile-p node)) - (inst call (make-fixup helper :assembly-routine)) ; 5 bytes - (emit-alignment 3 :long-nop)) - (t - (inst call (ea (make-fixup helper :assembly-routine*))) ; 7 bytes - (inst nop))) ; align - (unless (integerp size) - ;; This TEST instruction is never executed- it informs the profiler - ;; which register holds SIZE. - (inst test size size) ; 3 bytes - (emit-alignment 3 :long-nop))) + (let ((helper + (if (integerp size) 'enable-alloc-counter 'enable-sized-alloc-counter))) + ;; This jump is always encoded as 5 bytes + (inst call (if (or (not node) ; assembly routine + (sb-c::code-immobile-p node)) + (make-fixup helper :assembly-routine) + (uniquify-fixup helper)))) + (inst nop) + ;; Emit "TEST AL, imm" where the immediate value + ;; encodes the the data buffer base reg and size reg numbers. + (inst byte #xA8) ; "TEST AL,imm" + (cond ((integerp size) + (inst byte (tn-offset data))) + (t + (inst byte (logior (tn-offset data) (ash (tn-offset size) 4))) + (inst .skip 8 :long-nop))) (emit-label skip-instrumentation)))) +;;; An arbitrary marker for the cons primitive-type, not to be confused +;;; with the CONS-TYPE in our type-algebraic sense. Mostly just informs +;;; the allocator to use cons_tlab. +(defconstant +cons-primtype+ list-pointer-lowtag) + ;;; Emit code to allocate an object with a size in bytes given by ;;; SIZE into ALLOC-TN. The size may be an integer of a TN. ;;; NODE may be used to make policy-based decisions. @@ -142,182 +179,288 @@ ;;; ;;; A mnemonic device for the argument pattern here: ;;; 1. what to allocate: type, size, lowtag describe the object -;;; 2. how to allocate it: policy and how to invoke the trampoline -;;; 3. where to put the result -(defun allocation (type size lowtag node dynamic-extent alloc-tn) - (when dynamic-extent - (stack-allocation alloc-tn size lowtag) - (return-from allocation (values))) - (aver (and (not (location= alloc-tn temp-reg-tn)) - (or (integerp size) (not (location= size temp-reg-tn))))) - - (aver (not (sb-assem::assembling-to-elsewhere-p))) - ;; Otherwise do the normal inline allocation thing - (let ((NOT-INLINE (gen-label)) - (DONE (gen-label)) - ;; thread->alloc_region.free_pointer - (free-pointer - #+sb-thread (thread-slot-ea thread-alloc-region-slot) - #-sb-thread (ea (+ static-space-start - (ash vector-data-offset word-shift)))) - ;; thread->alloc_region.end_addr - (end-addr - #+sb-thread (thread-slot-ea (1+ thread-alloc-region-slot)) - #-sb-thread (ea (+ static-space-start - (ash (1+ vector-data-offset) word-shift))))) - - (cond ((typep size `(integer , large-object-size)) - ;; large objects will never be made in a per-thread region - (%alloc-tramp type node alloc-tn size lowtag)) - ((eql lowtag 0) - (cond ((and (tn-p size) (location= size alloc-tn)) - (inst mov temp-reg-tn free-pointer) - ;; alloc-tn <- old free ptr and temp <- new free ptr - (inst xadd temp-reg-tn alloc-tn)) - (t - (inst mov alloc-tn free-pointer) - (inst lea temp-reg-tn (ea size alloc-tn)))) - (inst cmp temp-reg-tn end-addr) - (inst jmp :a NOT-INLINE) - (inst mov free-pointer temp-reg-tn) - (emit-label DONE) - (assemble (:elsewhere) - (emit-label NOT-INLINE) - (let ((size (cond ((and (tn-p size) (location= size alloc-tn)) - (inst sub temp-reg-tn alloc-tn) - temp-reg-tn) - (t - size)))) - (%alloc-tramp type node alloc-tn size 0)) - (inst jmp DONE))) - (t - (inst mov temp-reg-tn free-pointer) - (cond ((integerp size) - (inst lea alloc-tn (ea size temp-reg-tn))) - ((location= alloc-tn size) - (inst add alloc-tn temp-reg-tn)) +;;; 2. where to put the result +;;; 3. node (for determining immobile-space-p) and a scratch register or two +(defvar *use-system-tlab* nil) +(defun system-tlab-p (node) + #-system-tlabs (declare (ignore node)) + #+system-tlabs + (or *use-system-tlab* + (and node + (named-let search-env ((env (sb-c::node-lexenv node))) + (dolist (data (sb-c::lexenv-user-data env) + (and (sb-c::lexenv-parent env) + (search-env (sb-c::lexenv-parent env)))) + (when (and (eq (first data) :declare) + (eq (second data) 'sb-c::tlab)) + (return (eq (third data) :system)))))))) + +(defun allocation (type size lowtag alloc-tn node temp thread-temp + &key overflow + &aux (systemp (system-tlab-p node))) + (declare (ignorable thread-temp)) + (flet ((fallback (size) + ;; Call an allocator trampoline and get the result in the proper register. + ;; There are 2 choices of trampoline to invoke alloc() or alloc_list() + ;; in C. This is chosen by the name of the asm routine. + (cond ((typep size '(and integer (not (signed-byte 32)))) + ;; MOV accepts large immediate operands, PUSH does not + (inst mov alloc-tn size) + (inst push alloc-tn)) (t - (inst lea alloc-tn (ea temp-reg-tn size)))) - (inst cmp alloc-tn end-addr) - (inst jmp :a NOT-INLINE) - (inst mov free-pointer alloc-tn) - (emit-label DONE) - (tagify alloc-tn temp-reg-tn lowtag) - (assemble (:elsewhere) - (emit-label NOT-INLINE) - (cond ((and (tn-p size) (location= size alloc-tn)) ; recover SIZE - (inst sub alloc-tn temp-reg-tn) - (%alloc-tramp type node temp-reg-tn alloc-tn 0)) - (t ; SIZE is intact - (%alloc-tramp type node temp-reg-tn size 0))) - (inst jmp DONE)))) - (values))) - -;;; Allocate an other-pointer object of fixed SIZE with a single word + (inst push size))) + (invoke-asm-routine + 'call + (if systemp + (if (eql type +cons-primtype+) 'sys-list-alloc-tramp 'sys-alloc-tramp) + (if (eql type +cons-primtype+) 'list-alloc-tramp 'alloc-tramp)) + node) + (inst pop alloc-tn))) + (let* ((NOT-INLINE (gen-label)) + (DONE (gen-label)) + (free-pointer #+sb-thread + (let ((slot (if systemp + (if (eql type +cons-primtype+) + thread-sys-cons-tlab-slot + thread-sys-mixed-tlab-slot) + (if (eql type +cons-primtype+) + thread-cons-tlab-slot + thread-mixed-tlab-slot)))) + (thread-slot-ea slot #+gs-seg thread-temp)) + #-sb-thread (ea (if (eql type +cons-primtype+) + cons-region mixed-region))) + (end-addr (ea (sb-x86-64-asm::ea-segment free-pointer) + (+ n-word-bytes (ea-disp free-pointer)) + (ea-base free-pointer)))) + (cond ((typep size `(integer ,large-object-size)) + ;; large objects will never be made in a per-thread region + (cond (overflow (funcall overflow)) + (t (fallback size) + (when (/= lowtag 0) (inst or :byte alloc-tn lowtag))))) + ((and (tn-p size) (location= size alloc-tn)) + (aver (and temp (not (location= temp size)))) + (inst mov temp free-pointer) + ;; alloc-tn <- old free ptr and temp <- new free ptr + (inst xadd temp alloc-tn) + (inst cmp temp end-addr) + (inst jmp :a NOT-INLINE) + (inst mov free-pointer temp) + (emit-label DONE) + (when (/= lowtag 0) (inst or :byte alloc-tn lowtag)) + (assemble (:elsewhere) + (emit-label NOT-INLINE) + (inst sub temp alloc-tn) ; new-free-ptr - old-free-ptr = size + (cond (overflow (funcall overflow)) + (t (fallback temp) + (inst jmp DONE))))) + (t + ;; fixed-size allocation whose size fits in an imm32 can be done + ;; with only one register, the ALLOC-TN. If it doesn't fit in imm32, + ;; it would get the first branch of the COND, for large objects. + (inst mov alloc-tn free-pointer) + (cond (temp + (when (tn-p size) (aver (not (location= size temp)))) + (inst lea temp (ea size alloc-tn)) + (inst cmp temp end-addr) + (inst jmp :a NOT-INLINE) + (inst mov free-pointer temp) + (emit-label DONE) + (when (/= lowtag 0) (inst or :byte alloc-tn lowtag))) + (t + (inst add alloc-tn size) + (inst cmp alloc-tn end-addr) + (inst jmp :a NOT-INLINE) + (inst mov free-pointer alloc-tn) + (cond ((tn-p size) + (inst sub alloc-tn size) + (emit-label DONE) + (when (/= lowtag 0) (inst or :byte alloc-tn lowtag))) + (t + ;; SUB can compute the result and tagify it. + ;; The fallback also has to tagify. + (let ((bias (+ (- size) lowtag))) + (if (= bias -1) (inst dec alloc-tn) (inst add alloc-tn bias))) + (emit-label DONE))))) + (assemble (:elsewhere) + (emit-label NOT-INLINE) + (cond (overflow (funcall overflow)) + (t + (fallback size) + (when (and (/= lowtag 0) (not temp) (not (tn-p size))) + (inst or :byte alloc-tn lowtag)) + (inst jmp DONE)))))))) + t) + +;;; Allocate an other-pointer object of fixed NWORDS with a single-word ;;; header having the specified WIDETAG value. The result is placed in -;;; RESULT-TN. -(defun alloc-other (result-tn widetag size node &optional stack-allocate-p - &aux (bytes (pad-data-block size))) - (let ((header (compute-object-header size widetag))) - (cond (stack-allocate-p - (allocation nil bytes other-pointer-lowtag node t result-tn) - (storew header result-tn 0 other-pointer-lowtag)) +;;; RESULT-TN. NWORDS counts the header word. +(defun alloc-other (widetag nwords result-tn node alloc-temp thread-temp + &aux (bytes (pad-data-block nwords))) + (declare (ignorable thread-temp)) + (let ((header (compute-object-header nwords widetag))) + #+bignum-assertions + (when (= widetag bignum-widetag) (setq bytes (* bytes 2))) ; use 2x the space + (cond ((and (not alloc-temp) (location= result-tn r12-tn)) + ;; this is the problematic case for INSTRUMENT-ALLOC. + ;; Therefore, allocate into RAX but save it in RESULT-TN + ;; and then switch them back. + (inst mov result-tn rax-tn) + (instrument-alloc widetag bytes node rax-tn thread-temp) + (pseudo-atomic (:thread-tn thread-temp) + (allocation nil bytes other-pointer-lowtag rax-tn node nil thread-temp) + (storew* header rax-tn 0 other-pointer-lowtag t)) + (inst xchg rax-tn result-tn)) (t - (instrument-alloc bytes node) + (instrument-alloc widetag bytes node result-tn thread-temp) (pseudo-atomic () - (allocation nil bytes 0 node nil result-tn) - (storew* header result-tn 0 0 t) - (inst or :byte result-tn other-pointer-lowtag)))))) + (cond (alloc-temp + (allocation nil bytes 0 result-tn node alloc-temp thread-temp) + (storew* header result-tn 0 0 t) + (inst or :byte result-tn other-pointer-lowtag)) + (t + (allocation nil bytes other-pointer-lowtag result-tn node nil thread-temp) + (storew* header result-tn 0 other-pointer-lowtag t)))))))) + +;;;; CONS, ACONS, LIST and LIST* +(macrolet ((store-slot (tn list &optional (slot cons-car-slot) + (lowtag list-pointer-lowtag)) + ;; TODO: gencgc does not need EMIT-GC-STORE-BARRIER here, + ;; but other other GC strategies might. + `(let ((reg + ;; FIXME: single-float gets placed in the boxed header + ;; rather than just doing an immediate store. + (sc-case ,tn + ((control-stack constant) + (move temp ,tn) + temp) + (t + (encode-value-if-immediate ,tn))))) + (storew reg ,list ,slot ,lowtag temp)))) + +(define-vop (cons) + (:args (car :scs (any-reg descriptor-reg constant immediate)) + (cdr :scs (any-reg descriptor-reg constant immediate))) + (:temporary (:sc unsigned-reg :to (:result 0) :target result) alloc) + (:temporary (:sc unsigned-reg :to (:result 0)) temp) + (:results (result :scs (descriptor-reg))) + #+gs-seg (:temporary (:sc unsigned-reg :offset 15) thread-tn) + (:node-var node) + (:generator 10 + (let ((stack-allocate-p (node-stack-allocate-p node)) + (nbytes (* cons-size n-word-bytes))) + (unless stack-allocate-p + (instrument-alloc +cons-primtype+ nbytes node (list temp alloc) thread-tn)) + (pseudo-atomic (:elide-if stack-allocate-p :thread-tn thread-tn) + (if stack-allocate-p + (stack-allocation nbytes 0 alloc) + (allocation +cons-primtype+ nbytes 0 alloc node temp thread-tn)) + (store-slot car alloc cons-car-slot 0) + (store-slot cdr alloc cons-cdr-slot 0) + (if (location= alloc result) + (inst or :byte alloc list-pointer-lowtag) + (inst lea result (ea list-pointer-lowtag alloc))))))) -;;;; CONS, LIST and LIST* -(define-vop (list-or-list*) - (:args (things :more t :scs (descriptor-reg constant immediate))) +(define-vop (acons) + (:args (key :scs (any-reg descriptor-reg constant immediate)) + (val :scs (any-reg descriptor-reg constant immediate)) + (tail :scs (any-reg descriptor-reg constant immediate))) + (:temporary (:sc unsigned-reg :to (:result 0)) alloc) + (:temporary (:sc unsigned-reg :to (:result 0) :target result) temp) + (:results (result :scs (descriptor-reg))) + #+gs-seg (:temporary (:sc unsigned-reg :offset 15) thread-tn) + (:node-var node) + (:translate acons) + (:policy :fast-safe) + (:generator 10 + (let ((nbytes (* cons-size 2 n-word-bytes))) + (instrument-alloc +cons-primtype+ nbytes node (list temp alloc) thread-tn) + (pseudo-atomic (:thread-tn thread-tn) + (allocation +cons-primtype+ nbytes 0 alloc node temp thread-tn) + (store-slot tail alloc cons-cdr-slot 0) + (inst lea temp (ea (+ 16 list-pointer-lowtag) alloc)) + (store-slot temp alloc cons-car-slot 0) + (let ((pair temp) (temp alloc)) ; give STORE-SLOT the ALLOC as its TEMP + (store-slot key pair) + (store-slot val pair cons-cdr-slot)) + ;; ALLOC could have been clobbered by using it as a temp for + ;; loading a constant. + (if (location= temp result) + (inst sub result 16) ; TEMP is ALLOC+16+lowtag, so just subtract 16 + (inst lea result (ea (- 16) temp))))))) + +;;; CONS-2 is similar to ACONS, except that instead of producing +;;; ((X . Y) . Z) it produces (X Y . Z) +(define-vop (cons-2) + (:args (car :scs (any-reg descriptor-reg constant immediate)) + (cadr :scs (any-reg descriptor-reg constant immediate)) + (cddr :scs (any-reg descriptor-reg constant immediate))) + (:temporary (:sc unsigned-reg :to (:result 0) :target result) alloc) + (:temporary (:sc unsigned-reg :to (:result 0)) temp) + (:results (result :scs (descriptor-reg))) + #+gs-seg (:temporary (:sc unsigned-reg :offset 15) thread-tn) + (:node-var node) + (:generator 10 + (let ((stack-allocate-p (node-stack-allocate-p node)) + (nbytes (* cons-size 2 n-word-bytes))) + (unless stack-allocate-p + (instrument-alloc +cons-primtype+ nbytes node (list temp alloc) thread-tn)) + (pseudo-atomic (:elide-if stack-allocate-p :thread-tn thread-tn) + (if stack-allocate-p + (stack-allocation nbytes 0 alloc) + (allocation +cons-primtype+ nbytes 0 alloc node temp thread-tn)) + (store-slot car alloc cons-car-slot 0) + (store-slot cadr alloc (+ 2 cons-car-slot) 0) + (store-slot cddr alloc (+ 2 cons-cdr-slot) 0) + (inst lea temp (ea (+ 16 list-pointer-lowtag) alloc)) + (store-slot temp alloc cons-cdr-slot 0) + (if (location= alloc result) + (inst or :byte alloc list-pointer-lowtag) + (inst lea result (ea list-pointer-lowtag alloc))))))) + +(define-vop (list) + (:args (things :more t :scs (descriptor-reg any-reg constant immediate))) (:temporary (:sc unsigned-reg) ptr temp) (:temporary (:sc unsigned-reg :to (:result 0) :target result) res) - (:info num) + #+gs-seg (:temporary (:sc unsigned-reg :offset 15) thread-tn) + (:info star cons-cells) (:results (result :scs (descriptor-reg))) - (:variant-vars star) - (:policy :safe) (:node-var node) (:generator 0 - (cond ((zerop num) - ;; (move result nil-value) - (inst mov result nil-value)) - ((and star (= num 1)) - (move result (tn-ref-tn things))) - (t - (macrolet - ((store-slot (tn list &optional (slot cons-car-slot) - (lowtag list-pointer-lowtag)) - `(let ((reg - ;; FIXME: single-float gets placed in the boxed header - ;; rather than just doing an immediate store. - (sc-case ,tn - ((control-stack constant) - (move temp ,tn) - temp) - (t - (encode-value-if-immediate ,tn))))) - (storew* reg ,list ,slot ,lowtag (not stack-allocate-p))))) - (let* ((cons-cells (if star (1- num) num)) - (stack-allocate-p (node-stack-allocate-p node)) - (size (* (pad-data-block cons-size) cons-cells))) - (unless stack-allocate-p - (instrument-alloc size node)) - (pseudo-atomic (:elide-if stack-allocate-p) - (allocation 'list size (if (= cons-cells 2) 0 list-pointer-lowtag) - node stack-allocate-p res) - (multiple-value-bind (last-base-reg lowtag car cdr) - (cond - ((= cons-cells 2) - ;; Note that this does not use the 'ptr' register at all. - ;; It would require a different vop to free that register up. - (store-slot (tn-ref-tn things) res cons-car-slot 0) - (setf things (tn-ref-across things)) - (inst lea temp (ea (+ (* cons-size n-word-bytes) list-pointer-lowtag) res)) - (store-slot temp res cons-cdr-slot 0) - (values res 0 (+ cons-size cons-car-slot) (+ cons-size cons-cdr-slot))) - ;; 1 cons IR1-transforms to CONS which IR2-converts as FIXED-ALLOC. - ((= cons-cells 1) (bug "Why?")) ; shoulda been CONS - (t - (move ptr res) - (dotimes (i (1- cons-cells)) - (store-slot (tn-ref-tn things) ptr) - (setf things (tn-ref-across things)) - (inst add ptr (pad-data-block cons-size)) - (storew ptr ptr (- cons-cdr-slot cons-size) - list-pointer-lowtag)) - (values ptr list-pointer-lowtag cons-car-slot cons-cdr-slot))) - (store-slot (tn-ref-tn things) last-base-reg car lowtag) - (cond (star - (setf things (tn-ref-across things)) - (store-slot (tn-ref-tn things) last-base-reg cdr lowtag)) - (t - (storew* nil-value last-base-reg cdr lowtag - (not stack-allocate-p)))) - (cond ((= cons-cells 2) - (if (location= result res) - (inst or :byte result list-pointer-lowtag) - (inst lea result (ea list-pointer-lowtag res)))) - (t - (move result res))))))) - (aver (null (tn-ref-across things))))))) - -(define-vop (list list-or-list*) - (:variant nil)) - -(define-vop (list* list-or-list*) - (:variant t)) + (aver (>= cons-cells 3)) ; prevent regressions in ir2tran's vop selection + (let ((stack-allocate-p (node-stack-allocate-p node)) + (size (* (pad-data-block cons-size) cons-cells))) + (unless stack-allocate-p + (instrument-alloc +cons-primtype+ size node (list ptr temp) thread-tn)) + (pseudo-atomic (:elide-if stack-allocate-p :thread-tn thread-tn) + (if stack-allocate-p + (stack-allocation size list-pointer-lowtag res) + (allocation +cons-primtype+ size list-pointer-lowtag res node temp thread-tn)) + (move ptr res) + (dotimes (i (1- cons-cells)) + (store-slot (tn-ref-tn things) ptr) + (setf things (tn-ref-across things)) + (inst add ptr (pad-data-block cons-size)) + (storew ptr ptr (- cons-cdr-slot cons-size) list-pointer-lowtag)) + (store-slot (tn-ref-tn things) ptr cons-car-slot list-pointer-lowtag) + (cond (star + (setf things (tn-ref-across things)) + (store-slot (tn-ref-tn things) ptr cons-cdr-slot list-pointer-lowtag)) + (t + (storew nil-value ptr cons-cdr-slot list-pointer-lowtag))) + (aver (null (tn-ref-across things))) + (move result res))))) +) ;;;; special-purpose inline allocators ;;; Special variant of 'storew' which might have a shorter encoding ;;; when storing to the heap (which starts out zero-filled). ;;; This will always write 8 bytes if WORD is a negative number. -(defun storew* (word object slot lowtag zeroed) +(defun storew* (word object slot lowtag zeroed &optional temp) (cond - ((or (not zeroed) (not (typep word '(unsigned-byte 31)))) - (storew word object slot lowtag)) ; Possibly use temp-reg-tn + ((or (not zeroed) (not (typep word '(unsigned-byte 31)))) + ;; Will use temp reg if WORD can't be encoded as an imm32 + (storew word object slot lowtag temp)) ((/= word 0) (let ((size (cond ((typep word '(unsigned-byte 8)) @@ -341,122 +484,244 @@ (inst mov size (ea (- (* slot n-word-bytes) lowtag) object) word))))) ;;; ALLOCATE-VECTOR -(macrolet ((calc-size-in-bytes (n-words result-tn) +(defun store-string-trailing-null (vector type length words) + ;; BASE-STRING needs to have a null terminator. The byte is inaccessible + ;; to lisp, so clear it now. + (cond ((and (sc-is type immediate) + (/= (tn-value type) sb-vm:simple-base-string-widetag))) ; do nothing + ((and (sc-is type immediate) + (= (tn-value type) sb-vm:simple-base-string-widetag) + (sc-is length immediate)) + (inst mov :byte (ea (- (+ (ash vector-data-offset word-shift) + (tn-value length)) + other-pointer-lowtag) + vector) + 0)) + ;; Zeroizing the entire final word is easier than using LENGTH now. + ((sc-is words immediate) + ;; I am not convinced that this case is reachable - + ;; we won't DXify a vector of unknown type. + (inst mov :qword + ;; Given N data words, write to word N-1 + (ea (- (ash (+ (tn-value words) vector-data-offset -1) + word-shift) + other-pointer-lowtag) + vector) + 0)) + (t + ;; This final case is ok with 0 data words - it might clobber the LENGTH + ;; slot, but subsequently we rewrite that slot. + ;; But strings always have at least 1 word, so no worries either way. + (inst mov :qword + (ea (- (ash (1- vector-data-offset) word-shift) + other-pointer-lowtag) + vector + words (ash 1 (- word-shift n-fixnum-tag-bits))) + 0)))) + +(macrolet ((calc-size-in-bytes (n-words size-tn) `(cond ((sc-is ,n-words immediate) (pad-data-block (+ (tn-value ,n-words) vector-data-offset))) (t - (inst lea ,result-tn + (inst lea ,size-tn (ea (+ lowtag-mask (* vector-data-offset n-word-bytes)) nil ,n-words (ash 1 (- word-shift n-fixnum-tag-bits)))) - (inst and ,result-tn (lognot lowtag-mask)) - ,result-tn))) - (put-header (vector-tn lowtag type length zeroed) - `(progn (storew* (if (sc-is ,type immediate) (tn-value ,type) ,type) - ,vector-tn 0 ,lowtag ,zeroed) - (storew* (if (sc-is ,length immediate) - (fixnumize (tn-value ,length)) - ,length) - ,vector-tn vector-length-slot ,lowtag ,zeroed)))) + (inst and ,size-tn (lognot lowtag-mask)) + ,size-tn))) + (put-header (vector-tn lowtag type len zeroed temp) + `(let ((len (if (sc-is ,len immediate) (fixnumize (tn-value ,len)) ,len)) + (type (if (sc-is ,type immediate) (tn-value ,type) ,type))) + (storew* type ,vector-tn 0 ,lowtag ,zeroed ,temp) + #+ubsan (inst mov :dword (vector-len-ea ,vector-tn ,lowtag) len) + #-ubsan (storew* len ,vector-tn vector-length-slot + ,lowtag ,zeroed ,temp))) + (want-shadow-bits () + `(and poisoned + (if (sc-is type immediate) + (/= (tn-value type) simple-vector-widetag) + :maybe))) + (calc-shadow-bits-size (reg) + `(cond ((sc-is length immediate) + ;; Calculate number of dualwords (as 128 bits per dualword) + ;; and multiply by 16 to get number of bytes. Also add the 2 header words. + (* 16 (+ 2 (ceiling (tn-value length) 128)))) + (t + ;; Compute (CEILING length 128) by adding 127, then truncating divide + ;; by 128, and untag as part of the divide step. + ;; Account for the two fixed words by adding in 128 more bits initially. + (inst lea :dword ,reg (ea (fixnumize (+ 128 127)) length)) + (inst shr :dword ,reg 8) ; divide by 128 and untag as one operation + (inst shl :dword ,reg 4) ; multiply by 16 bytes per dualword + ,reg))) + (store-originating-pc (vector) + ;; Put the current program-counter into the length slot of the shadow bits + ;; so that we can ascribe blame to the array's creator. + `(let ((here (gen-label))) + (emit-label here) + (inst lea temp (rip-relative-ea here)) + (inst shl temp 4) + (inst mov (ea (- 8 other-pointer-lowtag) ,vector) temp)))) (define-vop (allocate-vector-on-heap) + #+ubsan (:info poisoned) (:args (type :scs (unsigned-reg immediate)) (length :scs (any-reg immediate)) (words :scs (any-reg immediate))) ;; Result is live from the beginning, like a temp, because we use it as such ;; in 'calc-size-in-bytes' (:results (result :scs (descriptor-reg) :from :load)) - (:arg-types positive-fixnum positive-fixnum positive-fixnum) + (:arg-types #+ubsan (:constant t) + positive-fixnum positive-fixnum positive-fixnum) + (:temporary (:sc unsigned-reg) temp) + #+gs-seg (:temporary (:sc unsigned-reg :offset 15) thread-tn) (:policy :fast-safe) (:node-var node) (:generator 100 + #+ubsan + (when (want-shadow-bits) + ;; allocate a vector of "written" bits unless the vector is simple-vector-T, + ;; which can use unbound-marker as a poison value on reads. + (when (sc-is type unsigned-reg) + (inst cmp :byte type simple-vector-widetag) + (inst push 0) + (inst jmp :e NO-SHADOW-BITS)) + ;; It would be possible to do this and the array proper + ;; in a single pseudo-atomic section, but I don't care to do that. + (let ((nbytes (calc-shadow-bits-size result))) + (pseudo-atomic () + ;; Allocate the bits into RESULT + (allocation nil nbytes 0 result node temp nil) + (inst mov :byte (ea result) simple-bit-vector-widetag) + (inst mov :dword (vector-len-ea result 0) + (if (sc-is length immediate) (fixnumize (tn-value length)) length)) + (inst or :byte result other-pointer-lowtag))) + (store-originating-pc result) + (inst push result)) ; save the pointer to the shadow bits + NO-SHADOW-BITS ;; The LET generates instructions that needn't be pseudoatomic ;; so don't move it inside. - (let ((size (calc-size-in-bytes words result))) - (instrument-alloc size node) - (pseudo-atomic () - (allocation nil size 0 node nil result) - (put-header result 0 type length t) - (inst or :byte result other-pointer-lowtag))))) + ;; There are 3 possibilities for correctness of INSTRUMENT-ALLOC: + ;; * If WORDS is not immediate, and ALLOC-TEMP is R12, then compute size + ;; into ALLOC-TEMP, use RESULT as the instrumentation temp. + ;; ALLOCATION receives: input = ALLOC-TEMP, output = RESULT, and no other temp + ;; * If WORDS is not immediate and ALLOC-TEMP is not R12, then compute size + ;; into RESULT, use ALLOC-TEMP as the instrumentation temp. + ;; ALLOCATION receives: input = RESULT, output = RESULT, temp = ALLOC-TEMP. + (multiple-value-bind (size-tn instrumentation-temp alloc-temp) + (cond ((sc-is words immediate) + ;; If WORDS is immediate, then let INSTRUMENT-ALLOC choose its temp + (values (calc-size-in-bytes words nil) (list result temp) temp)) + ((location= temp r12-tn) + ;; Compute the size into TEMP, use RESULT for instrumentation. + ;; Don't give another temp to ALLOCATION, because its SIZE and temp + ;; can not be in the same register (which it AVERs). + (values (calc-size-in-bytes words temp) result nil)) + (t + ;; Compute the size into RESULT, use TEMP for instrumentation. + ;; ALLOCATION needs the temp register in this case, + ;; because input and output are in the same register. + (values (calc-size-in-bytes words result) temp temp))) + (instrument-alloc (if (sc-is type immediate) + (case (tn-value type) + (#.simple-vector-widetag 'simple-vector) + (t 'unboxed-array)) + type) + size-tn node instrumentation-temp thread-tn) + (pseudo-atomic (:thread-tn thread-tn) + (allocation nil size-tn 0 result node alloc-temp thread-tn) + (put-header result 0 type length t alloc-temp) + (inst or :byte result other-pointer-lowtag))) + #+ubsan + (cond ((want-shadow-bits) + (inst pop temp-reg-tn) ; restore shadow bits + (inst mov (object-slot-ea result 1 other-pointer-lowtag) temp-reg-tn)) + (poisoned ; uninitialized SIMPLE-VECTOR + (store-originating-pc result))))) (define-vop (allocate-vector-on-stack) + #+ubsan (:info poisoned) (:args (type :scs (unsigned-reg immediate)) (length :scs (any-reg immediate)) (words :scs (any-reg immediate))) (:results (result :scs (descriptor-reg) :from :load)) - (:temporary (:sc any-reg :offset ecx-offset :from :eval) rcx) - (:temporary (:sc any-reg :offset eax-offset :from :eval) rax) - (:temporary (:sc any-reg :offset edi-offset :from :eval) rdi) - (:temporary (:sc complex-double-reg) zero) - (:arg-types positive-fixnum positive-fixnum positive-fixnum) - (:translate allocate-vector) + (:vop-var vop) + (:arg-types #+ubsan (:constant t) + positive-fixnum positive-fixnum positive-fixnum) + #+ubsan (:temporary (:sc any-reg :offset rax-offset) rax) + #+ubsan (:temporary (:sc any-reg :offset rcx-offset) rcx) + #+ubsan (:temporary (:sc any-reg :offset rdi-offset) rdi) (:policy :fast-safe) - (:node-var node) - (:generator 100 - (let ((size (calc-size-in-bytes words result)) - (rax-zeroed)) + (:generator 10 + #+ubsan + (when (want-shadow-bits) + ;; allocate a vector of "written" bits unless the vector is simple-vector-T, + ;; which can use unbound-marker as a poison value on reads. + (when (sc-is type unsigned-reg) (bug "vector-on-stack: unknown type")) + (zeroize rax) + (let ((nbytes (calc-shadow-bits-size rcx))) + (stack-allocation nbytes 0 rdi) + (when (sc-is length immediate) (inst mov rcx nbytes))) + (inst rep) + (inst stos :byte) ; RAX was zeroed + (inst lea rax (ea other-pointer-lowtag rsp-tn)) + (inst mov :dword (ea (- other-pointer-lowtag) rax) simple-bit-vector-widetag) + (inst mov :dword (vector-len-ea rax) + (if (sc-is length immediate) (fixnumize (tn-value length)) length)) + (store-originating-pc rax)) + (let ((size (calc-size-in-bytes words result))) ;; Compute tagged pointer sooner than later since access off RSP ;; requires an extra byte in the encoding anyway. - (stack-allocation result size other-pointer-lowtag) - (put-header result other-pointer-lowtag type length nil) + (stack-allocation size other-pointer-lowtag result + ;; If already aligned RSP, don't need to do it again. + #+ubsan (want-shadow-bits)) + ;; NB: store the trailing null BEFORE storing the header, + ;; in case the length in words is 0, which stores into the LENGTH slot + ;; as if it were element -1 of data (which probably can't happen). + (store-string-trailing-null result type length words) ;; FIXME: It would be good to check for stack overflow here. - ;; It would also be good to skip zero-fill of specialized vectors - ;; perhaps in a policy-dependent way. At worst you'd see random - ;; bits, and CLHS says consequences are undefined. - (when (sb-c:msan-unpoison sb-c:*compilation*) - ;; Unpoison all DX vectors regardless of widetag. - ;; Mark the header and length as valid, not just the payload. - #+linux ; unimplemented for others - (let ((words-savep - ;; 'words' might be co-located with any of the temps - (or (location= words rdi) (location= words rcx) (location= words rax)))) - (setq rax-zeroed (not (location= words rax))) - (when words-savep ; use 'result' to save 'words' - (inst mov result words)) - (cond ((sc-is words immediate) - (inst mov rcx (+ (tn-value words) vector-data-offset))) - (t - (inst lea rcx - (ea (ash vector-data-offset n-fixnum-tag-bits) words)) - (inst shr rcx n-fixnum-tag-bits))) - (inst mov rdi msan-mem-to-shadow-xor-const) - (inst xor rdi rsp-tn) ; compute shadow address - (zeroize rax) - (inst rep) - (inst stos rax) - (when words-savep - (inst mov words result) ; restore 'words' - (inst lea result ; recompute the tagged pointer - (ea other-pointer-lowtag rsp-tn))))) - (unless (sb-c::vector-initialized-p node) - (let ((data-addr - (ea (- (* vector-data-offset n-word-bytes) other-pointer-lowtag) - result))) - (block zero-fill - (cond ((sc-is words immediate) - (let ((n (tn-value words))) - (cond ((> n 8) - (inst mov rcx (tn-value words))) - ((= n 1) - (inst mov :qword data-addr 0) - (return-from zero-fill)) - (t - (multiple-value-bind (double single) (truncate n 2) - (inst xorpd zero zero) - (dotimes (i double) - (inst movapd data-addr zero) - (setf data-addr - (ea (+ (ea-disp data-addr) (* n-word-bytes 2)) - (ea-base data-addr)))) - (unless (zerop single) - (inst movaps data-addr zero)) - (return-from zero-fill)))))) - (t - (move rcx words) - (inst shr rcx n-fixnum-tag-bits))) - (inst lea rdi data-addr) - (unless rax-zeroed (zeroize rax)) - (inst rep) - (inst stos rax)))))))) + (put-header result other-pointer-lowtag type length nil nil) + ) + #+ubsan + (cond ((want-shadow-bits) + (inst mov (ea (- (ash vector-length-slot word-shift) other-pointer-lowtag) + result) + rax)) + (poisoned ; uninitialized SIMPLE-VECTOR + (store-originating-pc result))))) + + #+linux ; unimplemented for others + (define-vop (allocate-vector-on-stack+msan-unpoison) + #+ubsan (:info poisoned) + #+ubsan (:ignore poisoned) + (:args (type :scs (unsigned-reg immediate)) + (length :scs (any-reg immediate)) + (words :scs (any-reg immediate))) + (:results (result :scs (descriptor-reg) :from :load)) + (:arg-types #+ubsan (:constant t) + positive-fixnum positive-fixnum positive-fixnum) + ;; This is a separate vop because it needs more temps. + (:temporary (:sc any-reg :offset rcx-offset) rcx) + (:temporary (:sc any-reg :offset rax-offset) rax) + (:temporary (:sc any-reg :offset rdi-offset) rdi) + (:policy :fast-safe) + (:generator 10 + (let ((size (calc-size-in-bytes words result))) + ;; Compute tagged pointer sooner than later since access off RSP + ;; requires an extra byte in the encoding anyway. + (stack-allocation size other-pointer-lowtag result) + (store-string-trailing-null result type length words) + ;; FIXME: It would be good to check for stack overflow here. + (put-header result other-pointer-lowtag type length nil nil) + (cond ((sc-is words immediate) + (inst mov rcx (+ (tn-value words) vector-data-offset))) + (t + (inst lea rcx (ea (ash vector-data-offset n-fixnum-tag-bits) words)) + (inst shr rcx n-fixnum-tag-bits))) + (inst mov rdi msan-mem-to-shadow-xor-const) + (inst xor rdi rsp-tn) ; compute shadow address + (zeroize rax) + (inst rep) + (inst stos :qword))))) ;;; ALLOCATE-LIST (macrolet ((calc-size-in-bytes (length answer) @@ -472,8 +737,7 @@ (ash 1 (1+ (- word-shift n-fixnum-tag-bits))))) ,answer))) (compute-end () - `(let ((size (cond ((or (not (fixnump size)) - (plausible-signed-imm32-operand-p size)) + `(let ((size (cond ((typep size '(or (signed-byte 32) tn)) size) (t (inst mov limit size) @@ -492,7 +756,7 @@ (:generator 20 (let ((size (calc-size-in-bytes length next)) (loop (gen-label))) - (stack-allocation result size list-pointer-lowtag) + (stack-allocation size list-pointer-lowtag result) (compute-end) (inst mov next result) (emit-label LOOP) @@ -508,23 +772,32 @@ (define-vop (allocate-list-on-heap) (:args (length :scs (any-reg immediate)) - (element :scs (any-reg descriptor-reg) - :load-if (not (and (sc-is element immediate) - (eql (tn-value element) 0))))) + ;; Too bad we don't have an SC that implies actually a CPU immediate + ;; i.e. fits in an imm32 operand + (element :scs (any-reg descriptor-reg))) (:results (result :scs (descriptor-reg) :from :load)) (:arg-types positive-fixnum *) (:policy :fast-safe) (:node-var node) (:temporary (:sc descriptor-reg) tail next limit) + #+gs-seg (:temporary (:sc unsigned-reg :offset 15) thread-tn) (:generator 20 - (let ((size (calc-size-in-bytes length next)) + (let ((size (calc-size-in-bytes length tail)) (entry (gen-label)) (loop (gen-label)) - (no-init - (and (sc-is element immediate) (eql (tn-value element) 0)))) - (instrument-alloc size node) - (pseudo-atomic () - (allocation 'list size list-pointer-lowtag node nil result) + (leave-pa (gen-label))) + (instrument-alloc +cons-primtype+ size node (list next limit) thread-tn) + (pseudo-atomic (:thread-tn thread-tn) + (allocation +cons-primtype+ size list-pointer-lowtag result node limit thread-tn + :overflow + (lambda () + ;; Push C call args right-to-left + (inst push (if (integerp size) (constantize size) size)) + (inst push (if (sc-is element immediate) (tn-value element) element)) + (invoke-asm-routine + 'call (if (system-tlab-p node) 'sys-make-list 'make-list) node) + (inst pop result) + (inst jmp leave-pa))) (compute-end) (inst mov next result) (inst jmp entry) @@ -533,12 +806,13 @@ (emit-label ENTRY) (inst mov tail next) (inst add next (* 2 n-word-bytes)) - (unless no-init ; don't bother writing zeros in the CARs - (storew element tail cons-car-slot list-pointer-lowtag)) + (storew element tail cons-car-slot list-pointer-lowtag) (inst cmp next limit) - (inst jmp :ne loop)) - (storew nil-value tail cons-cdr-slot list-pointer-lowtag)) - done))) + (inst jmp :ne loop) + ;; still pseudo-atomic + (storew nil-value tail cons-cdr-slot list-pointer-lowtag) + (emit-label leave-pa))) + done))) ; label needed by calc-size-in-bytes #-immobile-space (define-vop (make-fdefn) @@ -546,59 +820,73 @@ (:translate make-fdefn) (:args (name :scs (descriptor-reg) :to :eval)) (:results (result :scs (descriptor-reg) :from :argument)) + #+gs-seg (:temporary (:sc unsigned-reg :offset 15) thread-tn) (:node-var node) (:generator 37 - (alloc-other result fdefn-widetag fdefn-size node) + (alloc-other fdefn-widetag fdefn-size result node nil thread-tn) (storew name result fdefn-name-slot other-pointer-lowtag) (storew nil-value result fdefn-fun-slot other-pointer-lowtag) (storew (make-fixup 'undefined-tramp :assembly-routine) result fdefn-raw-addr-slot other-pointer-lowtag))) (define-vop (make-closure) - ; (:args (function :to :save :scs (descriptor-reg))) (:info label length stack-allocate-p) (:temporary (:sc any-reg) temp) + #+gs-seg (:temporary (:sc unsigned-reg :offset 15) thread-tn) (:results (result :scs (descriptor-reg))) (:node-var node) (:generator 10 - (let* ((words (+ length closure-info-offset)) ; including header - (bytes (pad-data-block words)) - (header (logior (ash (1- words) n-widetag-bits) closure-widetag))) - (unless stack-allocate-p - (instrument-alloc bytes node)) - (pseudo-atomic (:elide-if stack-allocate-p) - (allocation nil bytes fun-pointer-lowtag node stack-allocate-p result) - (storew* #-immobile-space header ; write the widetag and size - #+immobile-space ; ... plus the layout pointer - (progn (inst mov temp header) - (inst or temp #-sb-thread (static-symbol-value-ea 'function-layout) - #+sb-thread - (thread-slot-ea thread-function-layout-slot)) - temp) - result 0 fun-pointer-lowtag (not stack-allocate-p))) - ;; Done with pseudo-atomic - (when label - (inst lea temp (rip-relative-ea label (ash simple-fun-insts-offset word-shift))) - (storew temp result closure-fun-slot fun-pointer-lowtag))))) + (let* ((words (+ length closure-info-offset)) ; including header + (bytes (pad-data-block words)) + (header (logior (ash (1- words) n-widetag-bits) closure-widetag))) + (unless stack-allocate-p + (instrument-alloc closure-widetag bytes node (list result temp) thread-tn)) + (pseudo-atomic (:elide-if stack-allocate-p :thread-tn thread-tn) + (if stack-allocate-p + (stack-allocation bytes fun-pointer-lowtag result) + (allocation nil bytes fun-pointer-lowtag result node temp thread-tn)) + (storew* #-immobile-space header ; write the widetag and size + #+immobile-space ; ... plus the layout pointer + (let ((layout #-sb-thread (static-symbol-value-ea 'function-layout) + #+sb-thread (thread-slot-ea thread-function-layout-slot))) + (cond ((typep header '(unsigned-byte 16)) + (inst mov temp layout) + ;; emit a 2-byte constant, the low 4 of TEMP were zeroed + (inst mov :word temp header)) + (t + (inst mov temp header) + (inst or temp layout))) + temp) + result 0 fun-pointer-lowtag (not stack-allocate-p))) + ;; Finished with the pseudo-atomic instructions + ;; TODO: gencgc does not need EMIT-GC-STORE-BARRIER here, but other other GC strategies might. + (inst lea temp (rip-relative-ea label (ash simple-fun-insts-offset word-shift))) + (storew temp result closure-fun-slot fun-pointer-lowtag) + #+metaspace + (let ((origin (sb-assem::asmstream-data-origin-label sb-assem:*asmstream*))) + (inst lea temp (rip-relative-ea origin :code)) + (storew temp result closure-code-slot fun-pointer-lowtag))))) ;;; The compiler likes to be able to directly make value cells. (define-vop (make-value-cell) (:args (value :scs (descriptor-reg any-reg) :to :result)) (:results (result :scs (descriptor-reg) :from :eval)) + #+gs-seg (:temporary (:sc unsigned-reg :offset 15) thread-tn) (:info stack-allocate-p) (:node-var node) (:generator 10 - (alloc-other result value-cell-widetag value-cell-size node stack-allocate-p) + (cond (stack-allocate-p + (stack-allocation (pad-data-block value-cell-size) other-pointer-lowtag result) + (let ((header (compute-object-header value-cell-size value-cell-widetag))) + (storew header result 0 other-pointer-lowtag))) + (t + (alloc-other value-cell-widetag value-cell-size result node nil thread-tn))) + ;; TODO: gencgc does not need EMIT-GC-STORE-BARRIER here, but other other GC strategies might. (storew value result value-cell-value-slot other-pointer-lowtag))) ;;;; automatic allocators for primitive objects -(define-vop (make-unbound-marker) - (:args) - (:results (result :scs (descriptor-reg any-reg))) - (:generator 1 - (inst mov result unbound-marker-widetag))) - +;;; FIXME: figure out how not to need this? (define-vop (make-funcallable-instance-tramp) (:args) (:results (result :scs (any-reg))) @@ -609,49 +897,65 @@ (inst lea result (ea tramp rip-tn)) (inst mov result tramp))))) -(define-vop (fixed-alloc) - (:args) - (:info name words type lowtag stack-allocate-p) - (:results (result :scs (descriptor-reg))) - (:node-var node) - (:generator 50 - (let* ((instancep (typep type 'layout)) ; is this any instance? - (layoutp #+immobile-space - (eq type #.(find-layout 'layout))) ; " a new LAYOUT instance? - (bytes (pad-data-block words))) +(flet + ((alloc (name words type lowtag stack-allocate-p result + &optional alloc-temp node vop + &aux (bytes (pad-data-block words))) + (declare (ignorable vop)) + #+bignum-assertions + (when (eq type bignum-widetag) (setq bytes (* bytes 2))) ; use 2x the space (progn name) ; possibly not used - (unless (or stack-allocate-p layoutp) - (instrument-alloc bytes node)) - (pseudo-atomic (:elide-if stack-allocate-p) - (cond (layoutp - (invoke-asm-routine 'call 'alloc-layout node) - (inst mov result r11-tn)) - (t - ;; If storing a header word, defer ORing in the lowtag until after - ;; the header is written so that displacement can be 0. - (allocation nil bytes (if type 0 lowtag) node stack-allocate-p result) - (when type - (let* ((widetag (if instancep instance-widetag type)) - (header (logior (ash (1- words) (length-field-shift widetag)) widetag))) - (if (or #+compact-instance-header - (and (eq name '%make-structure-instance) stack-allocate-p)) - ;; Write a :DWORD, not a :QWORD, because the high half will be - ;; filled in when the layout is stored. Can't use STOREW* though, - ;; because it tries to store as few bytes as possible, - ;; where this instruction must write exactly 4 bytes. - (inst mov :dword (ea 0 result) header) - (storew* header result 0 0 (not stack-allocate-p))) - (inst or :byte result lowtag)))))) - (when instancep ; store its layout - (inst mov :dword (ea (+ 4 (- lowtag)) result) - (make-fixup type :layout)))))) + (unless stack-allocate-p + (instrument-alloc type bytes node (list result alloc-temp) thread-tn)) + (pseudo-atomic (:elide-if stack-allocate-p :thread-tn thread-tn) + ;; If storing a header word, defer ORing in the lowtag until after + ;; the header is written so that displacement can be 0. + (cond (stack-allocate-p + (stack-allocation bytes (if type 0 lowtag) result)) + #+immobile-space + ((eql type funcallable-instance-widetag) + (inst push bytes) + (invoke-asm-routine 'call 'alloc-funinstance vop) + (inst pop result)) + (t + (allocation nil bytes (if type 0 lowtag) result node alloc-temp thread-tn))) + (let ((header (compute-object-header words type))) + (cond #+compact-instance-header + ((and (eq name '%make-structure-instance) stack-allocate-p) + ;; Write a :DWORD, not a :QWORD, because the high half will be + ;; filled in when the layout is stored. Can't use STOREW* though, + ;; because it tries to store as few bytes as possible, + ;; where this instruction must write exactly 4 bytes. + (inst mov :dword (ea 0 result) header)) + (t + (storew* header result 0 0 (not stack-allocate-p))))) + ;; GC can make the best choice about placement if it has a layout. + ;; Of course with conservative GC the object will be pinned anyway, + ;; but still, always having a layout is a good thing. + (when (typep type 'wrapper) ; store its layout, while still in pseudo-atomic + (inst mov :dword (ea 4 result) (make-fixup type :layout))) + (inst or :byte result lowtag)))) + ;; DX is strictly redundant in these 2 vops, but they're written this way + ;; so that backends can choose to use a single vop for both. + (define-vop (fixed-alloc) + (:info name words type lowtag dx) + (:results (result :scs (descriptor-reg))) + (:temporary (:sc unsigned-reg) alloc-temp) + #+gs-seg (:temporary (:sc unsigned-reg :offset 15) thread-tn) + (:vop-var vop) + (:node-var node) + (:generator 50 (alloc name words type lowtag dx result alloc-temp node vop))) + (define-vop (sb-c::fixed-alloc-to-stack) + (:info name words type lowtag dx) + (:results (result :scs (descriptor-reg))) + (:generator 50 (alloc name words type lowtag dx result)))) ;;; Allocate a non-vector variable-length object. ;;; Exactly 4 allocators are rendered via this vop: ;;; BIGNUM (%ALLOCATE-BIGNUM) ;;; FUNCALLABLE-INSTANCE (%MAKE-FUNCALLABLE-INSTANCE) ;;; CLOSURE (%ALLOC-CLOSURE) -;;; INSTANCE (%MAKE-INSTANCE) +;;; INSTANCE (%MAKE-INSTANCE,%MAKE-INSTANCE/MIXED) ;;; WORDS accounts for the mandatory slots *including* the header. ;;; EXTRA is the variable payload, also measured in words. (define-vop (var-alloc) @@ -662,6 +966,9 @@ (:results (result :scs (descriptor-reg) :from (:eval 1))) (:temporary (:sc unsigned-reg :from :eval :to (:eval 1)) bytes) (:temporary (:sc unsigned-reg :from :eval :to :result) header) + ;; KLUDGE: wire to RAX so that it doesn't get R12 + (:temporary (:sc unsigned-reg :offset 0) alloc-temp) + #+gs-seg (:temporary (:sc unsigned-reg :offset 15) thread-tn) (:node-var node) (:generator 50 ;; With the exception of bignums, these objects have effectively @@ -675,53 +982,113 @@ (inst lea operand-size header ; (w-1 << 8) | type (ea (+ (ash -2 (length-field-shift type)) type) header)) (inst and operand-size bytes (lognot lowtag-mask))) - (cond (stack-allocate-p - (stack-allocation result bytes lowtag) + #+bignum-assertions + (when (= type bignum-widetag) (inst shl :dword bytes 1)) ; use 2x the space + (cond (stack-allocate-p + (stack-allocation bytes lowtag result) (storew header result 0 lowtag)) - (t - (instrument-alloc bytes node) - (pseudo-atomic () - (allocation nil bytes lowtag node nil result) + (t + ;; can't pass RESULT as a possible choice of scratch register + ;; because it might be in the same physical reg as BYTES. + ;; Yup, the lifetime specs in this vop are pretty confusing. + (instrument-alloc type bytes node alloc-temp thread-tn) + (pseudo-atomic (:thread-tn thread-tn) + (allocation nil bytes lowtag result node alloc-temp thread-tn) (storew header result 0 lowtag)))))) +#+immobile-space (macrolet ((c-call (name) `(let ((c-fun (make-fixup ,name :foreign))) (inst call (cond ((sb-c::code-immobile-p node) c-fun) - (t (progn (inst mov temp-reg-tn c-fun) - temp-reg-tn))))))) -#+immobile-space -(define-vop (alloc-immobile-fixedobj) - (:info lowtag size header) - (:temporary (:sc unsigned-reg :to :eval :offset rdi-offset) c-arg1) - (:temporary (:sc unsigned-reg :to :eval :offset rsi-offset) c-arg2) - (:temporary (:sc unsigned-reg :from :eval :to (:result 0) :offset rax-offset) - c-result) + (t (progn (inst mov rax c-fun) rax))))))) +(define-vop (!alloc-immobile-fixedobj) + (:args (size-class :scs (any-reg) :target c-arg1) + (nwords :scs (any-reg) :target c-arg2) + (header :scs (any-reg) :target c-arg3)) + (:temporary (:sc unsigned-reg :from (:argument 0) :to :eval :offset rdi-offset) c-arg1) + (:temporary (:sc unsigned-reg :from (:argument 1) :to :eval :offset rsi-offset) c-arg2) + (:temporary (:sc unsigned-reg :from (:argument 2) :to :eval :offset rdx-offset) c-arg3) + (:temporary (:sc unsigned-reg :from :eval :to (:result 0) :offset rax-offset) rax) (:results (result :scs (descriptor-reg))) (:node-var node) (:generator 50 - (inst mov c-arg1 size) - (inst mov c-arg2 header) + (inst mov c-arg1 size-class) + (inst mov c-arg2 nwords) + (inst mov c-arg3 header) ;; RSP needn't be restored because the allocators all return immediately ;; which has that effect (inst and rsp-tn -16) (pseudo-atomic () - (c-call "alloc_fixedobj") - (inst lea result (ea lowtag c-result))))) + (c-call "alloc_immobile_fixedobj") + (move result rax)))) -(define-vop (alloc-dynamic-space-code) - (:args (total-words :scs (signed-reg) :target c-arg1)) - (:temporary (:sc unsigned-reg :from (:argument 0) :to :eval :offset rdi-offset) c-arg1) - (:temporary (:sc unsigned-reg :from :eval :to (:result 0) :offset rax-offset) - c-result) +;;; Timing test: +;;; Dynamic-space allocation: +;;; * (defun f (n) (dotimes (i n) (make-symbol "b"))) +;;; * (time (f 500000)) +;;; Evaluation took: 0.004 seconds of real time +;;; Immobile-space: +;;; * (defun f (n) (dotimes (i n) (sb-vm::make-immobile-symbol "b"))) +;;; Evaluation took: 0.043 seconds of real time +;;; With vop: 0.028 seconds of real time + +(eval-when (:compile-toplevel) + (aver (evenp symbol-size))) ; assumptions in the code below + +(define-vop (!fast-alloc-immobile-symbol) (:results (result :scs (descriptor-reg))) - (:node-var node) - (:generator 50 - (inst mov c-arg1 total-words) - ;; RSP needn't be restored because the allocators all return immediately - ;; which has that effect - (inst and rsp-tn -16) - (pseudo-atomic () (c-call "alloc_code_object")) - ;; C-RESULT is a tagged ptr. MOV doesn't need to be inside the PSEUDO-ATOMIC. - (inst mov result c-result))) + (:temporary (:sc unsigned-reg :offset rax-offset) rax) + (:temporary (:sc unsigned-reg :offset rbx-offset) rbx) + (:temporary (:sc unsigned-reg :offset rcx-offset) rcx) + (:temporary (:sc unsigned-reg) header) + (:generator 1 + ;; fixedobj_pages linkage entry: 1 PTE per page, 12-byte struct + (inst mov rbx (rip-relative-ea (make-fixup "fixedobj_pages" :foreign-dataref))) + ;; fixedobj_page_hint: 1 hint per sizeclass. C type = uint32_t + (inst mov rax (rip-relative-ea (make-fixup "fixedobj_page_hint" :foreign-dataref))) + (inst mov rbx (ea rbx)) ; get the base of the fixedobj_pages array + ;; This has to be pseudoatomic as soon as the page hint is loaded. + ;; Consider the situation where there is exactly one symbol on a page that + ;; is almost all free, and the symbol page hint points to that page. + ;; If GC occurs, it might dispose that symbol, resetting the page attributes + ;; and page hint. It would be an error to allocate to that page + ;; because it is no longer a page of symbols but rather a free page. + ;; There is no way to inform GC that we are currently looking at a page + ;; in anticipation of allocating to it. + (pseudo-atomic () + (assemble () + (inst mov :dword rax (ea 4 rax)) ; rax := fixedobj_page_hint[1] (sizeclass=SYMBOL) + (inst test :dword rax rax) + (inst jmp :z FAIL) ; fail if hint page is 0 + (inst lea rbx (ea rbx rax 8)) ; rbx := &fixedobj_pages[hint].free_index + ;; compute fixedobj_page_address(hint) into RAX + (inst mov rcx (rip-relative-ea (make-fixup "FIXEDOBJ_SPACE_START" :foreign-dataref))) + (inst shl rax (integer-length (1- immobile-card-bytes))) + (inst add rax (ea rcx)) + ;; load the page's free pointer + (inst mov :dword rcx (ea rbx)) ; rcx := fixedobj_pages[hint].free_index + ;; fail if allocation would overrun the page + (inst cmp :dword rcx (- immobile-card-bytes (* symbol-size n-word-bytes))) + (inst jmp :a FAIL) + ;; compute address of the allegedly free memory block into RESULT + (inst lea result (ea rcx rax)) ; free_index + page_base + ;; read the potential symbol header + (inst mov rax (ea result)) + (inst test :dword rax 1) + (inst jmp :nz FAIL) ; not a fixnum implies already taken + ;; try to claim this word of memory + (inst mov header (logior (ash (1- symbol-size) n-widetag-bits) symbol-widetag)) + (inst cmpxchg :lock (ea result) header) + (inst jmp :ne FAIL) ; already taken + ;; compute new free_index = spacing + old header + free_index + (inst lea :dword rax (ea (* symbol-size n-word-bytes) rax rcx)) + (inst mov :dword (ea rbx) rax) ; store new free_index + ;; set the low bit of the 'gens' field + (inst or :lock :byte (ea 7 rbx) 1) ; 7+rbx = &fixedobj_pages[i].attr.parts.gens_ + (inst or :byte result other-pointer-lowtag) ; make_lispobj() + (inst jmp OUT) + FAIL + (inst mov result nil-value) + OUT)))) ) ; end MACROLET diff --git a/src/compiler/x86-64/arith.lisp b/src/compiler/x86-64/arith.lisp index 35a0b04e57..20079319c5 100644 --- a/src/compiler/x86-64/arith.lisp +++ b/src/compiler/x86-64/arith.lisp @@ -27,6 +27,7 @@ (define-vop (fixnum-unop fast-safe-arith-op) (:args (x :scs (any-reg control-stack) :target res :load-if nil)) (:results (res :scs (any-reg control-stack) :load-if nil)) + (:temporary (:sc unsigned-reg) temp) (:note "inline fixnum arithmetic") (:arg-types tagged-num) (:result-types tagged-num)) @@ -34,22 +35,23 @@ (define-vop (signed-unop fast-safe-arith-op) (:args (x :scs (signed-reg signed-stack) :target res :load-if nil)) (:results (res :scs (signed-reg signed-stack) :load-if nil)) + (:temporary (:sc unsigned-reg) temp) (:note "inline (signed-byte 64) arithmetic") (:arg-types signed-num) (:result-types signed-num)) ;;; logical or arithmetic negation -(defun emit-inline-neg (op arg result vop &optional fixnump) +(defun emit-inline-neg (op arg result temp vop &optional fixnump) (declare (ignore vop)) ;; If ARG and RESULT are the same location, then the initial and final MOVEs ;; are both no-ops. If different locations and not both memory, ;; then the initial move is a physical move and the final is a no-op. - ;; If both are stack locations, then compute the answer in temp-reg-tn. + ;; If both are stack locations, then compute the answer in temp. ;; (REG might be a stack location, not necessarily a GPR in this emitter. ;; It's just a naming convention that is consistent with other emitters) (let ((reg (if (or (alias-p arg result) (gpr-tn-p arg) (gpr-tn-p result)) result - temp-reg-tn))) + temp))) (move reg arg) (case op (not (if fixnump (inst xor reg (fixnumize -1)) (inst not reg))) @@ -59,36 +61,36 @@ (define-vop (fast-negate/fixnum fixnum-unop) (:translate %negate) (:vop-var vop) - (:generator 1 (emit-inline-neg 'neg x res vop))) + (:generator 1 (emit-inline-neg 'neg x res temp vop))) (define-vop (fast-negate/signed signed-unop) (:translate %negate) (:vop-var vop) - (:generator 2 (emit-inline-neg 'neg x res vop))) + (:generator 2 (emit-inline-neg 'neg x res temp vop))) (define-vop (fast-negate/unsigned signed-unop) (:args (x :scs (unsigned-reg unsigned-stack) :target res :load-if nil)) (:arg-types unsigned-num) (:translate %negate) (:vop-var vop) - (:generator 3 (emit-inline-neg 'neg x res vop))) + (:generator 3 (emit-inline-neg 'neg x res temp vop))) (define-vop (fast-negate/signed-unsigned signed-unop) (:results (res :scs (unsigned-reg unsigned-stack) :load-if nil)) (:result-types unsigned-num) (:translate %negate) (:vop-var vop) - (:generator 3 (emit-inline-neg 'neg x res vop))) + (:generator 3 (emit-inline-neg 'neg x res temp vop))) (define-vop (fast-lognot/fixnum fixnum-unop) (:translate lognot) (:vop-var vop) - (:generator 1 (emit-inline-neg 'not x res vop t))) + (:generator 1 (emit-inline-neg 'not x res temp vop t))) (define-vop (fast-lognot/signed signed-unop) (:translate lognot) (:vop-var vop) - (:generator 2 (emit-inline-neg 'not x res vop nil))) + (:generator 2 (emit-inline-neg 'not x res temp vop nil))) ;;;; binary fixnum operations @@ -281,15 +283,14 @@ (move r x) (inst or r y))) -(defun prepare-alu-operands (op x y vop const-tn-xform commutative) - (declare (ignore op)) - (let ((arg (sb-c::vop-args vop))) +(defun prepare-alu-operands (x y vop const-tn-xform commutative) + (let ((arg (vop-args vop))) (when (tn-ref-load-tn arg) (bug "Shouldn't have a load TN for arg0")) (let ((arg (tn-ref-across arg))) (when (and arg (tn-ref-load-tn arg)) (bug "Shouldn't have a load TN for arg1")))) - (let ((res (sb-c::vop-results vop))) + (let ((res (vop-results vop))) (when (tn-ref-load-tn res) (bug "Shouldn't have a load TN for result"))) ;; Immediates won't be loaded since the :LOAD-IF expression is NIL. ;; Such value should always be placed into Y if the operation is +. @@ -303,14 +304,14 @@ (rotatef x y)) ; weird! why did IR1 not flip the args? (values x y)) -(defun emit-inline-smul (op x y result vop dummy taggedp) ; signed multiply +(defun emit-inline-smul (op x y result temp vop dummy taggedp) ; signed multiply (declare (ignore op dummy)) - (multiple-value-setq (x y) (prepare-alu-operands 'mul x y vop 'identity t)) + (multiple-value-setq (x y) (prepare-alu-operands x y vop 'identity t)) (aver (not (integerp x))) (let ((constant-y (integerp y))) ; don't need to unscale Y if true (when (and constant-y (not (typep y '(signed-byte 32)))) (setq y (register-inline-constant :qword y))) - (let ((reg (if (gpr-tn-p result) result temp-reg-tn))) + (let ((reg (if (gpr-tn-p result) result temp))) (cond ((integerp y) (inst imul reg x y)) ((alias-p reg y) @@ -336,11 +337,11 @@ ;;; is going. ;;; Non-commutative operations (notably SUB) need a little extra care. ;;; MUL is also a bit different due to asymmetry of the instruction. -(defun emit-inline-add-sub (op x y result vop const-tn-xform) +(defun emit-inline-add-sub (op x y result temp vop const-tn-xform) (declare (type (member add sub) op)) - (multiple-value-setq (x y) - (prepare-alu-operands op x y vop const-tn-xform (eq op 'add))) + (multiple-value-setq (x y) (prepare-alu-operands x y vop const-tn-xform (eq op 'add))) + ;; FIXME: What is (ash -1 63) for ? this comment within doesn't match the test. (when (and (eq op 'sub) (and (integerp y) (not (eql y (ash -1 63))))) ;; If Y is -2147483648 then the negation is not (signed-byte 32). ;; How likely is someone to subtract that? @@ -353,14 +354,16 @@ (let* ((y-is-reg-or-imm32 (or (gpr-tn-p y) (typep y '(signed-byte 32)))) (commutative (eq op 'add))) (when (alias-p result x) + ;; the first two clauses are correct because if the instruction was SUB with + ;; an immediate then it got turned into ADD with the negation of the immediate. (cond ((eql y -1) (inst dec x)) ((eql y +1) (inst inc x)) ((or (gpr-tn-p x) y-is-reg-or-imm32) ;; At most one memory operand. Result could be memory or register. (inst* op x y)) (t ; two memory operands: X is not a GPR, Y is neither GPR nor immm - (inst mov temp-reg-tn y) - (inst* op x temp-reg-tn))) + (inst mov temp y) + (inst* op x temp))) (return-from emit-inline-add-sub)) (when (and (alias-p result y) commutative) ;; Result in the same location as Y can happen because we no longer specify @@ -368,24 +371,26 @@ (cond ((or (gpr-tn-p x) (gpr-tn-p y)) (inst* op y x)) (t - (inst mov temp-reg-tn x) - (inst* op y temp-reg-tn))) + (inst mov temp x) + (inst* op y temp))) (return-from emit-inline-add-sub)) (let ((reg (if (and (gpr-tn-p result) ;; If Y aliases RESULT in SUB, then an initial (move reg x) ;; could clobber Y. (or commutative (not (alias-p result y)))) result - temp-reg-tn))) + temp))) (cond ((and (eq op 'add) ; LEA can't do subtraction (gpr-tn-p x) y-is-reg-or-imm32) ; register + (register | imm32) (inst lea reg (if (fixnump y) (ea y x) (ea x y)))) (t ;; If commutative, then neither X nor Y is an alias of RESULT. ;; If non-commutative, then RESULT could be Y, in which case REG is - ;; TEMP-REG-TN so that we don't trash Y by moving X into it. + ;; TEMP so that we don't trash Y by moving X into it. (inst mov reg x) - (inst* op reg y))) + (cond ((and (eq op 'add) (eql y 1)) (inst inc reg)) + ((and (eq op 'add) (eql y -1)) (inst dec reg)) + (t (inst* op reg y))))) (move result reg)))) ;;; FIXME: we shouldn't need 12 variants, plus the modular variants, for what should @@ -409,10 +414,11 @@ (:arg-types ,primtype ,primtype) (:results (r :scs ,scs :load-if nil)) (:result-types ,primtype) + (:temporary (:sc unsigned-reg) temp) (:vop-var vop) ;; (:node-var node) (:note ,note) (:generator ,(1+ cost) - (,emit ',op x y r vop ',val-xform ,@extra))) + (,emit ',op x y r temp vop ',val-xform ,@extra))) (define-vop (,name/c fast-safe-arith-op) (:translate ,fun-name) (:args (x :scs ,scs :target r :load-if nil)) @@ -420,10 +426,11 @@ (:arg-types ,primtype (:constant ,type)) (:results (r :scs ,scs :load-if nil)) (:result-types ,primtype) + (:temporary (:sc unsigned-reg) temp) (:vop-var vop) ;; (:node-var node) (:note ,note) (:generator ,cost - (,emit ',op x (,val-xform y) r vop ',val-xform ,@extra)))))) + (,emit ',op x (,val-xform y) r temp vop ',val-xform ,@extra)))))) (def + fast-+/fixnum=>fixnum fast-+-c/fixnum=>fixnum (any-reg control-stack) tagged-num fixnum 1 fixnumize) (def + fast-+/signed=>signed fast-+-c/signed=>signed @@ -445,6 +452,19 @@ ;; unsigned is different because MUL always uses RAX:RDX as 1st operand. ) +(define-vop (fast--/unsigned=>signed fast-safe-arith-op) + (:translate -) + (:args (x :scs (unsigned-reg unsigned-stack immediate) :target r :load-if nil) + (y :scs (unsigned-reg unsigned-stack immediate) :load-if nil)) + (:arg-types unsigned-num unsigned-num) + (:results (r :scs (signed-reg signed-stack) :load-if nil)) + (:result-types signed-num) + (:temporary (:sc unsigned-reg) temp) + (:vop-var vop) + (:note "inline (unsigned-byte 64) arithmetic") + (:generator 4 + (emit-inline-add-sub 'sub x y r temp vop 'identity))) + ;;;; Special logand cases: (logand signed unsigned) => unsigned (define-vop (fast-logand/signed-unsigned=>unsigned @@ -482,9 +502,9 @@ (:args (x :scs (unsigned-reg) :target eax) (y :scs (unsigned-reg unsigned-stack))) (:arg-types unsigned-num unsigned-num) - (:temporary (:sc unsigned-reg :offset eax-offset :target r + (:temporary (:sc unsigned-reg :offset rax-offset :target r :from (:argument 0) :to :result) eax) - (:temporary (:sc unsigned-reg :offset edx-offset + (:temporary (:sc unsigned-reg :offset rdx-offset :from :eval :to :result) edx) (:ignore edx) (:results (r :scs (unsigned-reg))) @@ -502,9 +522,9 @@ (:args (x :scs (unsigned-reg) :target eax)) (:info y) (:arg-types unsigned-num (:constant (unsigned-byte 64))) - (:temporary (:sc unsigned-reg :offset eax-offset :target r + (:temporary (:sc unsigned-reg :offset rax-offset :target r :from (:argument 0) :to :result) eax) - (:temporary (:sc unsigned-reg :offset edx-offset + (:temporary (:sc unsigned-reg :offset rdx-offset :from :eval :to :result) edx) (:ignore edx) (:results (r :scs (unsigned-reg))) @@ -517,6 +537,290 @@ (inst mul eax (register-inline-constant :qword y)) (move r eax))) +(define-vop () + (:translate sb-c::fixnum*) + (:args (x :scs (any-reg)) + (y :scs (signed-reg))) + (:arg-types tagged-num tagged-num (:constant t)) + (:info type) + (:results (r :scs (any-reg) :from :load)) + (:result-types tagged-num) + (:policy :fast-safe) + (:vop-var vop) + (:generator 5 + (let* ((*location-context* (unless (eq type 'fixnum) + type)) + (error (generate-error-code vop 'sb-kernel::mul-overflow-error x y))) + (move r x) + (inst imul r y) + (inst jmp :o error)))) + +(define-vop (fixnum*/c) + (:translate sb-c::fixnum*) + (:args (x :scs (any-reg))) + (:arg-types tagged-num (:constant (satisfies plausible-signed-imm32-operand-p)) (:constant t)) + (:info y type) + (:results (r :scs (any-reg) :from :load)) + (:result-types tagged-num) + (:policy :fast-safe) + (:vop-var vop) + (:generator 2 + (let* ((*location-context* (unless (eq type 'fixnum) + type)) + (y (plausible-signed-imm32-operand-p y)) + (error (generate-error-code+ (lambda () + (inst mov r (fixnumize y))) + vop + 'sb-kernel::mul-overflow-error x + r))) + (inst imul r x y) + (inst jmp :o error)))) + +(define-vop (*/signed=>integer) + (:translate *) + (:args (x :scs (signed-reg) :target rax) + (y :scs (signed-reg) :target header)) + (:arg-types signed-num signed-num) + (:temporary (:sc signed-reg :offset rax-offset :from (:argument 0)) + rax) + (:temporary (:sc signed-reg :offset rdx-offset :from (:argument 1)) + rdx) + (:temporary (:sc signed-reg :from (:argument 2)) header alloc-temp) + (:results (r :scs (descriptor-reg))) + (:policy :fast-safe) + (:vop-var vop) + (:node-var node) + (:generator 10 + (move rax x) + (inst imul y) + (inst mov header (bignum-header-for-length 2)) + (inst jmp :o allocate) + (move r rax) + (inst shl r 1) + (inst jmp :no DONE) + (inst mov header (bignum-header-for-length 1)) + #+bignum-assertions + (zeroize rdx) + allocate + (pseudo-atomic () + (allocation nil (pad-data-block (+ 2 bignum-digits-offset)) 0 + r node alloc-temp thread-tn) + (storew header r) + (storew rax r 1) + (storew rdx r 2) + (inst or r other-pointer-lowtag)) + DONE)) + +(define-vop (+/signed=>integer) + (:translate +) + (:args (x :scs (signed-reg)) + (y :scs (signed-reg))) + (:arg-types signed-num signed-num) + (:temporary (:sc signed-reg) high low) + (:temporary (:sc signed-reg :from (:argument 2)) header alloc-temp) + (:results (r :scs (descriptor-reg))) + (:policy :fast-safe) + (:vop-var vop) + (:node-var node) + (:generator 7 + (inst mov low x) + (inst add low y) + (inst set :c high) + (inst mov header (bignum-header-for-length 2)) + (inst jmp :o allocate) + (move r low) + (inst shl r 1) + (inst jmp :no DONE) + (inst mov header (bignum-header-for-length 1)) + allocate + (inst movzx '(:byte :dword) high high) + (inst neg high) + (pseudo-atomic () + (allocation nil (pad-data-block (+ 2 bignum-digits-offset)) 0 + r node alloc-temp thread-tn) + (storew header r) + (storew low r 1) + (storew high r 2) + (inst or r other-pointer-lowtag)) + DONE)) + +(define-vop (-/signed=>integer) + (:translate -) + (:args (x :scs (signed-reg)) + (y :scs (signed-reg))) + (:arg-types signed-num signed-num) + (:temporary (:sc signed-reg) high low) + (:temporary (:sc signed-reg :from (:argument 2)) header alloc-temp) + (:results (r :scs (descriptor-reg))) + (:policy :fast-safe) + (:vop-var vop) + (:node-var node) + (:generator 7 + (inst mov low x) + (inst sub low y) + (inst set :nc high) + (inst mov header (bignum-header-for-length 2)) + (inst jmp :o allocate) + (move r low) + (inst shl r 1) + (inst jmp :no DONE) + (inst mov header (bignum-header-for-length 1)) + allocate + (inst movzx '(:byte :dword) high high) + (inst neg high) + (pseudo-atomic () + (allocation nil (pad-data-block (+ 2 bignum-digits-offset)) 0 + r node alloc-temp thread-tn) + (storew header r) + (storew low r 1) + (storew high r 2) + (inst or r other-pointer-lowtag)) + DONE)) + +(define-vop (+/unsigned=>integer) + (:translate +) + (:args (x :scs (unsigned-reg)) + (y :scs (unsigned-reg))) + (:arg-types unsigned-num unsigned-num) + (:temporary (:sc unsigned-reg) high low) + (:temporary (:sc unsigned-reg :from (:argument 2)) header alloc-temp) + (:results (r :scs (descriptor-reg))) + (:policy :fast-safe) + (:vop-var vop) + (:node-var node) + (:generator 8 + (inst mov low x) + (inst add low y) + (inst set :c high) + (inst mov header (bignum-header-for-length 2)) + (inst jmp :c allocate) + (inst jmp :s allocate) + (move r low) + (inst shl r 1) + (inst jmp :no DONE) + (inst mov header (bignum-header-for-length 1)) + allocate + (inst movzx '(:byte :dword) high high) + (pseudo-atomic () + (allocation nil (pad-data-block (+ 2 bignum-digits-offset)) 0 + r node alloc-temp thread-tn) + (storew header r) + (storew low r 1) + (storew high r 2) + (inst or r other-pointer-lowtag)) + DONE)) + +(define-vop (-/unsigned=>integer) + (:translate -) + (:args (x :scs (unsigned-reg)) + (y :scs (unsigned-reg))) + (:arg-types unsigned-num unsigned-num) + (:temporary (:sc unsigned-reg) high low) + (:temporary (:sc unsigned-reg :from (:argument 2)) header alloc-temp) + (:results (r :scs (descriptor-reg))) + (:policy :fast-safe) + (:vop-var vop) + (:node-var node) + (:generator 8 + (inst mov low x) + (inst sub low y) + (inst set :c high) + (inst mov header (bignum-header-for-length 2)) + + (inst jmp :c negative) + (inst jmp :s allocate) + (inst jmp positive) + negative + (inst jmp :ns allocate) + positive + + (move r low) + (inst shl r 1) + (inst jmp :no DONE) + (inst mov header (bignum-header-for-length 1)) + allocate + (inst movzx '(:byte :dword) high high) + (inst neg high) + (pseudo-atomic () + (allocation nil (pad-data-block (+ 2 bignum-digits-offset)) 0 + r node alloc-temp thread-tn) + (storew header r) + (storew low r 1) + (storew high r 2) + (inst or r other-pointer-lowtag)) + DONE)) + +(define-vop () + (:translate sb-c::unsigned+) + (:args (x :scs (unsigned-reg)) + (y :scs (unsigned-reg))) + (:arg-types unsigned-num unsigned-num (:constant t)) + (:info type) + (:results (r :scs (unsigned-reg) :from (:argument 0))) + (:result-types unsigned-num) + (:policy :fast-safe) + (:vop-var vop) + (:generator 2 + (move r x) + (inst add r y) + (let* ((*location-context* (unless (eq type 'fixnum) + type)) + (error (generate-error-code vop 'sb-kernel::add-sub-overflow-error r))) + (inst jmp :c error)))) + +(define-vop () + (:translate sb-c::unsigned-) + (:args (x :scs (unsigned-reg)) + (y :scs (unsigned-reg))) + (:arg-types unsigned-num unsigned-num (:constant t)) + (:info type) + (:results (r :scs (unsigned-reg) :from (:argument 0))) + (:result-types unsigned-num) + (:policy :fast-safe) + (:vop-var vop) + (:generator 2 + (move r x) + (inst sub r y) + (let* ((*location-context* (unless (eq type 'fixnum) + type)) + (error (generate-error-code vop 'sb-kernel::sub-overflow-error r))) + (inst jmp :c error)))) + +(define-vop () + (:translate sb-c::signed+) + (:args (x :scs (signed-reg)) + (y :scs (signed-reg))) + (:arg-types signed-num signed-num (:constant t)) + (:info type) + (:results (r :scs (signed-reg) :from (:argument 0))) + (:result-types signed-num) + (:policy :fast-safe) + (:vop-var vop) + (:generator 2 + (move r x) + (inst add r y) + (let* ((*location-context* (unless (eq type 'fixnum) + type)) + (error (generate-error-code vop 'sb-kernel::add-sub-overflow-error r))) + (inst jmp :o error)))) + +(define-vop () + (:translate sb-c::signed-) + (:args (x :scs (signed-reg)) + (y :scs (signed-reg))) + (:arg-types signed-num signed-num (:constant t)) + (:info type) + (:results (r :scs (signed-reg) :from (:argument 0))) + (:result-types signed-num) + (:policy :fast-safe) + (:vop-var vop) + (:generator 2 + (move r x) + (inst sub r y) + (let* ((*location-context* (unless (eq type 'fixnum) + type)) + (error (generate-error-code vop 'sb-kernel::sub-overflow-error r))) + (inst jmp :o error)))) (define-vop (fast-truncate/fixnum=>fixnum fast-safe-arith-op) (:translate truncate) @@ -524,10 +828,10 @@ (y :scs (any-reg control-stack))) (:args-var args) (:arg-types tagged-num tagged-num) - (:temporary (:sc signed-reg :offset eax-offset :target quo - :from (:argument 0) :to (:result 0)) eax) - (:temporary (:sc unsigned-reg :offset edx-offset :target rem - :from (:argument 0) :to (:result 1)) edx) + (:temporary (:sc signed-reg :offset rax-offset :target quo + :from (:argument 0) :to (:result 0)) eax) + (:temporary (:sc unsigned-reg :offset rdx-offset :target rem + :from (:argument 0) :to (:result 1)) edx) (:results (quo :scs (any-reg)) (rem :scs (any-reg))) (:result-types tagged-num tagged-num) @@ -556,9 +860,9 @@ (:args (x :scs (any-reg) :target eax)) (:info y) (:arg-types tagged-num (:constant fixnum)) - (:temporary (:sc signed-reg :offset eax-offset :target quo + (:temporary (:sc signed-reg :offset rax-offset :target quo :from :argument :to (:result 0)) eax) - (:temporary (:sc any-reg :offset edx-offset :target rem + (:temporary (:sc any-reg :offset rdx-offset :target rem :from :eval :to (:result 1)) edx) (:temporary (:sc any-reg :from :eval :to :result) y-arg) (:results (quo :scs (any-reg)) @@ -585,9 +889,9 @@ (y :scs (unsigned-reg signed-stack))) (:arg-types unsigned-num unsigned-num) (:args-var args) - (:temporary (:sc unsigned-reg :offset eax-offset :target quo + (:temporary (:sc unsigned-reg :offset rax-offset :target quo :from (:argument 0) :to (:result 0)) eax) - (:temporary (:sc unsigned-reg :offset edx-offset :target rem + (:temporary (:sc unsigned-reg :offset rdx-offset :target rem :from (:argument 0) :to (:result 1)) edx) (:results (quo :scs (unsigned-reg)) (rem :scs (unsigned-reg))) @@ -603,7 +907,7 @@ (inst cmp y 0)) (inst jmp :eq (generate-error-code vop 'division-by-zero-error x y))) (move eax x) - (inst xor edx edx) + (zeroize edx) (inst div eax y) (move quo eax) (move rem edx))) @@ -613,9 +917,9 @@ (:args (x :scs (unsigned-reg) :target eax)) (:info y) (:arg-types unsigned-num (:constant (unsigned-byte 64))) - (:temporary (:sc unsigned-reg :offset eax-offset :target quo + (:temporary (:sc unsigned-reg :offset rax-offset :target quo :from :argument :to (:result 0)) eax) - (:temporary (:sc unsigned-reg :offset edx-offset :target rem + (:temporary (:sc unsigned-reg :offset rdx-offset :target rem :from :eval :to (:result 1)) edx) (:temporary (:sc unsigned-reg :from :eval :to :result) y-arg) (:results (quo :scs (unsigned-reg)) @@ -626,7 +930,7 @@ (:save-p :compute-only) (:generator 32 (move eax x) - (inst xor edx edx) + (zeroize edx) (inst mov y-arg y) (inst div eax y-arg) (move quo eax) @@ -638,9 +942,9 @@ (y :scs (signed-reg signed-stack))) (:args-var args) (:arg-types signed-num signed-num) - (:temporary (:sc signed-reg :offset eax-offset :target quo + (:temporary (:sc signed-reg :offset rax-offset :target quo :from (:argument 0) :to (:result 0)) eax) - (:temporary (:sc signed-reg :offset edx-offset :target rem + (:temporary (:sc signed-reg :offset rdx-offset :target rem :from (:argument 0) :to (:result 1)) edx) (:results (quo :scs (signed-reg)) (rem :scs (signed-reg))) @@ -666,9 +970,9 @@ (:args (x :scs (signed-reg) :target eax)) (:info y) (:arg-types signed-num (:constant (signed-byte 64))) - (:temporary (:sc signed-reg :offset eax-offset :target quo + (:temporary (:sc signed-reg :offset rax-offset :target quo :from :argument :to (:result 0)) eax) - (:temporary (:sc signed-reg :offset edx-offset :target rem + (:temporary (:sc signed-reg :offset rdx-offset :target rem :from :eval :to (:result 1)) edx) (:temporary (:sc signed-reg :from :eval :to :result) y-arg) (:results (quo :scs (signed-reg)) @@ -688,229 +992,232 @@ ;;;; Shifting +(macrolet ((encodable-as-lea () + `(and (gpr-tn-p number) (gpr-tn-p result) + (not (location= number result)) + (member amount '(1 2 3)))) + (generate-lea () + `(case amount + (1 (inst lea result (ea number number))) + (2 (inst lea result (ea nil number 4))) + (3 (inst lea result (ea nil number 8))))) + (with-shift-operands (&body body) + ;; If the initial "MOVE result number" is a legal instruction, + ;; then we're OK; otherwise use the temp reg to do the shift. + `(multiple-value-bind (save result) + (if (or (location= number result) (gpr-tn-p number) (gpr-tn-p result)) + (values nil result) + (values result temp)) + (move result number) + (assemble () + ,@body) + (when save (inst mov save result))))) + (define-vop (fast-ash-c/fixnum=>fixnum) (:translate ash) (:policy :fast-safe) - (:args (number :scs (any-reg) :target result - :load-if (not (and (sc-is number any-reg control-stack) - (sc-is result any-reg control-stack) - (location= number result))))) + (:args (number :scs (any-reg control-stack) :target result)) (:info amount) (:arg-types tagged-num (:constant integer)) - (:results (result :scs (any-reg) - :load-if (not (and (sc-is number control-stack) - (sc-is result control-stack) - (location= number result))))) + (:results (result :scs (any-reg control-stack))) (:result-types tagged-num) (:note "inline ASH") (:variant nil) (:variant-vars modularp) + (:temporary (:sc unsigned-reg) temp) (:generator 2 - (cond ((and (= amount 1) (not (location= number result))) - (inst lea result (ea number number))) - ((and (= amount 2) (not (location= number result))) - (inst lea result (ea nil number 4))) - ((and (= amount 3) (not (location= number result))) - (inst lea result (ea nil number 8))) + (cond ((= amount 0) (bug "shifting by 0")) + ((>= amount 64) ; shifting left (zero fill) + (unless modularp + (bug "Impossible: fixnum ASH left exceeds word length")) + (zeroize result)) + ((encodable-as-lea) (generate-lea)) (t - (move result number) - (cond ((< -64 amount 64) - ;; this code is used both in ASH and ASH-MODFX, so - ;; be careful - (if (plusp amount) - (inst shl result amount) - (progn - (inst sar result (- amount)) - (inst and result (lognot fixnum-tag-mask))))) - ;; shifting left (zero fill) - ((plusp amount) - (unless modularp - (aver (not "Impossible: fixnum ASH should not be called with -constant shift greater than word length"))) - (if (sc-is result any-reg) - (zeroize result) - (inst mov result 0))) - ;; shifting right (sign fill) - (t (inst sar result 63) - (inst and result (lognot fixnum-tag-mask)))))))) + (with-shift-operands + (cond ((< -64 amount 64) + ;; this code is used both in ASH and ASH-MODFX, so + ;; be careful + (if (plusp amount) + (inst shl result amount) + (progn + (inst sar result (- amount)) + (inst and result (lognot fixnum-tag-mask))))) + ;; shifting right (sign fill) + (t (move result number) + (inst sar result 63) + (inst and result (lognot fixnum-tag-mask))))))))) (define-vop (fast-ash-left/fixnum=>fixnum) (:translate ash) - (:args (number :scs (any-reg) :target result - :load-if (not (and (sc-is number control-stack) - (sc-is result control-stack) - (location= number result)))) + (:args (number :scs (any-reg control-stack) :target result) (amount :scs (unsigned-reg) :target ecx)) (:arg-types tagged-num positive-fixnum) - (:temporary (:sc unsigned-reg :offset ecx-offset :from (:argument 1)) ecx) - (:results (result :scs (any-reg) :from (:argument 0) - :load-if (not (and (sc-is number control-stack) - (sc-is result control-stack) - (location= number result))))) + (:temporary (:sc unsigned-reg :offset rcx-offset :from (:argument 1)) ecx) + (:results (result :scs (any-reg control-stack) :from (:argument 0))) (:result-types tagged-num) (:policy :fast-safe) (:note "inline ASH") + (:temporary (:sc unsigned-reg) temp) (:generator 3 - (move result number) - (move ecx amount) - ;; The result-type ensures us that this shift will not overflow. - (inst shl result :cl))) - -(define-vop (fast-ash-left/fixnum-unbounded=>fixnum - fast-ash-left/fixnum=>fixnum) - (:translate) - (:generator 3 - (move result number) - (move ecx amount) - (inst cmp amount 63) - (inst jmp :be OKAY) - (zeroize result) - OKAY - (inst shl result :cl))) + (with-shift-operands + (move ecx amount) + ;; The result-type ensures us that this shift will not overflow. + (inst shl result :cl)))) (define-vop (fast-ash-c/signed=>signed) (:translate ash) (:policy :fast-safe) - (:args (number :scs (signed-reg) :target result - :load-if (not (and (sc-is number signed-stack) - (sc-is result signed-stack) - (location= number result))))) + (:args (number :scs (signed-reg signed-stack) :target result)) (:info amount) (:arg-types signed-num (:constant integer)) - (:results (result :scs (signed-reg) - :load-if (not (and (sc-is number signed-stack) - (sc-is result signed-stack) - (location= number result))))) + (:results (result :scs (signed-reg signed-stack))) (:result-types signed-num) (:note "inline ASH") + (:temporary (:sc unsigned-reg) temp) (:generator 3 - (cond ((and (= amount 1) (not (location= number result))) - (inst lea result (ea number number))) - ((and (= amount 2) (not (location= number result))) - (inst lea result (ea nil number 4))) - ((and (= amount 3) (not (location= number result))) - (inst lea result (ea nil number 8))) + (cond ((encodable-as-lea) (generate-lea)) (t - (move result number) - (cond ((plusp amount) (inst shl result amount)) - (t (inst sar result (min 63 (- amount))))))))) + (with-shift-operands + (cond ((plusp amount) (inst shl result amount)) + (t (inst sar result (min 63 (- amount)))))))))) (define-vop (fast-ash-c/unsigned=>unsigned) (:translate ash) (:policy :fast-safe) - (:args (number :scs (unsigned-reg) :target result - :load-if (not (and (sc-is number unsigned-stack) - (sc-is result unsigned-stack) - (location= number result))))) + (:args (number :scs (unsigned-reg unsigned-stack) :target result)) (:info amount) (:arg-types unsigned-num (:constant integer)) - (:results (result :scs (unsigned-reg) - :load-if (not (and (sc-is number unsigned-stack) - (sc-is result unsigned-stack) - (location= number result))))) + (:results (result :scs (unsigned-reg unsigned-stack))) (:result-types unsigned-num) (:note "inline ASH") + (:temporary (:sc unsigned-reg) temp) (:generator 3 - (cond ((and (= amount 1) (not (location= number result))) - (inst lea result (ea number number))) - ((and (= amount 2) (not (location= number result))) - (inst lea result (ea nil number 4))) - ((and (= amount 3) (not (location= number result))) - (inst lea result (ea nil number 8))) + (cond ((= amount 0) (bug "shifting by 0")) + ((not (< -64 amount 64)) (zeroize result)) + ((encodable-as-lea) (generate-lea)) (t - (move result number) - (cond ((< -64 amount 64) ;; XXXX - ;; this code is used both in ASH and ASH-MOD64, so - ;; be careful - (if (plusp amount) - (inst shl result amount) - (inst shr result (- amount)))) - (t (if (sc-is result unsigned-reg) - (zeroize result) - (inst mov result 0)))))))) + (with-shift-operands + (if (plusp amount) + (inst shl result amount) + (inst shr result (- amount)))))))) (define-vop (fast-ash-left/signed=>signed) (:translate ash) - (:args (number :scs (signed-reg) :target result - :load-if (not (and (sc-is number signed-stack) - (sc-is result signed-stack) - (location= number result)))) + (:args (number :scs (signed-reg signed-stack) :target result) (amount :scs (unsigned-reg) :target ecx)) (:arg-types signed-num positive-fixnum) - (:temporary (:sc unsigned-reg :offset ecx-offset :from (:argument 1)) ecx) - (:results (result :scs (signed-reg) :from (:argument 0) - :load-if (not (and (sc-is number signed-stack) - (sc-is result signed-stack) - (location= number result))))) + (:temporary (:sc unsigned-reg :offset rcx-offset :from (:argument 1)) ecx) + (:results (result :scs (signed-reg signed-stack) :from (:argument 0))) (:result-types signed-num) (:policy :fast-safe) (:note "inline ASH") + (:temporary (:sc unsigned-reg) temp) (:generator 4 - (move result number) - (move ecx amount) - (inst shl result :cl))) + (with-shift-operands + (move ecx amount) + (inst shl result :cl)))) (define-vop (fast-ash-left/unsigned=>unsigned) (:translate ash) - (:args (number :scs (unsigned-reg) :target result - :load-if (not (and (sc-is number unsigned-stack) - (sc-is result unsigned-stack) - (location= number result)))) + (:args (number :scs (unsigned-reg unsigned-stack) :target result) (amount :scs (unsigned-reg) :target ecx)) (:arg-types unsigned-num positive-fixnum) - (:temporary (:sc unsigned-reg :offset ecx-offset :from (:argument 1)) ecx) - (:results (result :scs (unsigned-reg) :from (:argument 0) - :load-if (not (and (sc-is number unsigned-stack) - (sc-is result unsigned-stack) - (location= number result))))) + (:temporary (:sc unsigned-reg :offset rcx-offset :from (:argument 1)) ecx) + (:results (result :scs (unsigned-reg unsigned-stack) :from (:argument 0))) (:result-types unsigned-num) (:policy :fast-safe) (:note "inline ASH") + (:temporary (:sc unsigned-reg) temp) (:generator 4 - (move result number) - (move ecx amount) - (inst shl result :cl))) + (with-shift-operands + (move ecx amount) + (inst shl result :cl)))) -(define-vop (fast-ash-left/unsigned-unbounded=>unsigned +(define-vop (fast-ash-left/fixnum-modfx=>fixnum + fast-ash-left/fixnum=>fixnum) + (:translate ash-left-modfx) + (:args-var args) + (:generator 3 + (with-shift-operands + (move ecx amount) + (unless (csubtypep (tn-ref-type (tn-ref-across args)) ;; amount + (specifier-type '(mod 63))) + (inst cmp amount 63) + (inst jmp :be OKAY) + (zeroize result)) + OKAY + (inst shl result :cl)))) + +(define-vop (fast-ash-left-mod64-c/unsigned=>unsigned + fast-ash-c/unsigned=>unsigned) + (:translate ash-left-mod64)) + +(define-vop (fast-ash-left-modfx-c/fixnum=>fixnum + fast-ash-c/fixnum=>fixnum) + (:variant :modular) + (:translate ash-left-modfx)) + +(define-vop (fast-ash-left/unsigned-mod64=>unsigned fast-ash-left/unsigned=>unsigned) - (:translate) + (:translate ash-left-mod64) + (:args-var args) (:generator 3 - (move result number) - (move ecx amount) - (inst cmp amount 63) - (inst jmp :be OKAY) - (zeroize result) - OKAY - (inst shl result :cl))) + (with-shift-operands + (move ecx amount) + (unless (csubtypep (tn-ref-type (tn-ref-across args)) ;; amount + (specifier-type '(mod 63))) + (inst cmp amount 63) + (inst jmp :be OKAY) + (zeroize result)) + OKAY + (inst shl result :cl)))) -(define-vop (fast-ash/signed=>signed) - (:translate ash) +(define-vop (fast-%ash/right/unsigned) + (:translate %ash/right) (:policy :fast-safe) - (:args (number :scs (signed-reg) :target result) - (amount :scs (signed-reg) :target ecx)) - (:arg-types signed-num signed-num) - (:results (result :scs (signed-reg) :from (:argument 0))) - (:result-types signed-num) - (:temporary (:sc signed-reg :offset ecx-offset :from (:argument 1)) ecx) - (:note "inline ASH") - (:generator 5 - (move result number) - (move ecx amount) - (inst test ecx ecx) - (inst jmp :ns POSITIVE) - (inst neg ecx) - (inst cmp ecx 63) - (inst jmp :be OKAY) - (inst mov ecx 63) - OKAY - (inst sar result :cl) - (inst jmp DONE) + (:args (number :scs (unsigned-reg unsigned-stack) :target result) + (amount :scs (unsigned-reg) :target rcx)) + (:arg-types unsigned-num unsigned-num) + (:results (result :scs (unsigned-reg unsigned-stack) :from (:argument 0))) + (:result-types unsigned-num) + (:temporary (:sc signed-reg :offset rcx-offset :from (:argument 1)) rcx) + (:temporary (:sc unsigned-reg) temp) + (:generator 4 + (with-shift-operands + (move rcx amount) + (inst shr result :cl)))) - POSITIVE - ;; The result-type ensures us that this shift will not overflow. - (inst shl result :cl) +(define-vop (fast-%ash/right/signed) + (:translate %ash/right) + (:policy :fast-safe) + (:args (number :scs (signed-reg signed-stack) :target result) + (amount :scs (unsigned-reg) :target rcx)) + (:arg-types signed-num unsigned-num) + (:results (result :scs (signed-reg signed-stack) :from (:argument 0))) + (:result-types signed-num) + (:temporary (:sc signed-reg :offset rcx-offset :from (:argument 1)) rcx) + (:temporary (:sc unsigned-reg) temp) + (:generator 4 + (with-shift-operands + (move rcx amount) + (inst sar result :cl)))) - DONE)) +(define-vop (fast-%ash/right/fixnum) + (:translate %ash/right) + (:policy :fast-safe) + (:args (number :scs (any-reg control-stack) :target result) + (amount :scs (unsigned-reg) :target rcx)) + (:arg-types tagged-num unsigned-num) + (:results (result :scs (any-reg control-stack) :from (:argument 0))) + (:result-types tagged-num) + (:temporary (:sc signed-reg :offset rcx-offset :from (:argument 1)) rcx) + (:temporary (:sc unsigned-reg) temp) + (:generator 3 + (with-shift-operands + (move rcx amount) + (inst sar result :cl) + (inst and result (lognot fixnum-tag-mask))))) +) ; end MACROLET (define-vop (fast-ash/unsigned=>unsigned) (:translate ash) @@ -920,7 +1227,9 @@ constant shift greater than word length"))) (:arg-types unsigned-num signed-num) (:results (result :scs (unsigned-reg) :from (:argument 0))) (:result-types unsigned-num) - (:temporary (:sc signed-reg :offset ecx-offset :from (:argument 1)) ecx) + (:temporary (:sc signed-reg :offset rcx-offset :from (:argument 1)) ecx) + (:args-var args) + (:variant-vars check-amount signed) (:note "inline ASH") (:generator 5 (move result number) @@ -928,62 +1237,102 @@ constant shift greater than word length"))) (inst test ecx ecx) (inst jmp :ns POSITIVE) (inst neg ecx) - (inst cmp ecx 63) - (inst jmp :be OKAY) - (zeroize result) - (inst jmp DONE) + (unless (csubtypep (tn-ref-type (tn-ref-across args)) + (specifier-type `(integer -63 *))) + (inst cmp ecx 63) + (inst jmp :be OKAY) + (cond (signed + (inst or ecx 63)) + (t + (zeroize result)))) OKAY - (inst shr result :cl) + (if signed + (inst sar result :cl) + (inst shr result :cl)) (inst jmp DONE) POSITIVE - ;; The result-type ensures us that this shift will not overflow. + (unless (or (not check-amount) ;; The result-type ensures us that this shift will not overflow. + (csubtypep (tn-ref-type (tn-ref-across args)) + (specifier-type `(integer * 63)))) + (inst cmp ecx 63) + (inst jmp :be STILL-OKAY) + (zeroize result)) + STILL-OKAY (inst shl result :cl) DONE)) -(define-vop (fast-%ash/right/unsigned) - (:translate %ash/right) - (:policy :fast-safe) - (:args (number :scs (unsigned-reg) :target result) - (amount :scs (unsigned-reg) :target rcx)) - (:arg-types unsigned-num unsigned-num) - (:results (result :scs (unsigned-reg) :from (:argument 0))) - (:result-types unsigned-num) - (:temporary (:sc signed-reg :offset rcx-offset :from (:argument 1)) rcx) - (:generator 4 - (move result number) - (move rcx amount) - (inst shr result :cl))) - -(define-vop (fast-%ash/right/signed) - (:translate %ash/right) - (:policy :fast-safe) +(define-vop (fast-ash/signed=>signed + fast-ash/unsigned=>unsigned) (:args (number :scs (signed-reg) :target result) - (amount :scs (unsigned-reg) :target rcx)) - (:arg-types signed-num unsigned-num) + (amount :scs (signed-reg) :target ecx)) + (:arg-types signed-num signed-num) (:results (result :scs (signed-reg) :from (:argument 0))) (:result-types signed-num) - (:temporary (:sc signed-reg :offset rcx-offset :from (:argument 1)) rcx) - (:generator 4 - (move result number) - (move rcx amount) - (inst sar result :cl))) + (:variant nil t)) -(define-vop (fast-%ash/right/fixnum) - (:translate %ash/right) +(define-vop (fast-ash-modfx/signed/unsigned=>fixnum) + (:translate ash-modfx) (:policy :fast-safe) - (:args (number :scs (any-reg) :target result) - (amount :scs (unsigned-reg) :target rcx)) - (:arg-types tagged-num unsigned-num) + (:args (number :scs (signed-reg unsigned-reg) :to :save) + (amount :scs (signed-reg) :target ecx)) + (:arg-types (:or signed-num unsigned-num) signed-num) (:results (result :scs (any-reg) :from (:argument 0))) + (:args-var args) (:result-types tagged-num) - (:temporary (:sc signed-reg :offset rcx-offset :from (:argument 1)) rcx) + (:temporary (:sc signed-reg :offset rcx-offset :from (:argument 1)) ecx) + (:note "inline ASH") (:generator 3 (move result number) - (move rcx amount) - (inst sar result :cl) - (inst and result (lognot fixnum-tag-mask)))) + (move ecx amount) + (inst test ecx ecx) + (inst jmp :ns POSITIVE) + (inst neg ecx) + (unless (csubtypep (tn-ref-type (tn-ref-across args)) + (specifier-type `(integer -63 *))) + (inst cmp ecx 63) + (inst jmp :be OKAY) + (sc-case number + (signed-reg + (inst or ecx 63)) + (unsigned-reg + (zeroize result)))) + OKAY + (sc-case number + (signed-reg + (inst sar result :cl)) + (unsigned-reg + (inst shr result :cl))) + (inst jmp DONE) + + POSITIVE + (unless (csubtypep (tn-ref-type (tn-ref-across args)) + (specifier-type `(integer * 63))) + (inst cmp ecx 63) + (inst jmp :be STILL-OKAY) + (zeroize result)) + STILL-OKAY + (inst shl result :cl) + DONE + (inst shl result n-fixnum-tag-bits))) + +(define-vop (fast-ash-modfx/signed=>signed + fast-ash/signed=>signed) + (:variant t t) + (:translate ash-modfx)) + +(define-vop (fast-ash-mod64/unsigned=>unsigned + fast-ash/unsigned=>unsigned) + (:variant t nil) + (:translate ash-mod64)) + +(define-vop (fast-ash-mod64/signed=>unsigned + fast-ash/signed=>signed) + (:results (result :scs (unsigned-reg))) + (:result-types unsigned-num) + (:variant t t) + (:translate ash-mod64)) (in-package "SB-C") @@ -1051,7 +1400,7 @@ constant shift greater than word length"))) (:arg-types unsigned-num signed-num) (:results (result :scs (unsigned-reg) :from (:argument 0))) (:result-types unsigned-num) - (:temporary (:sc signed-reg :offset ecx-offset :from (:argument 1)) ecx) + (:temporary (:sc signed-reg :offset rcx-offset :from (:argument 1)) ecx) (:temporary (:sc any-reg :from (:eval 0) :to (:eval 1)) zero) (:note "inline ASH") (:guard (member :cmov *backend-subfeatures*)) @@ -1177,51 +1526,46 @@ constant shift greater than word length"))) (define-vop (fast-conditional) (:conditional :e) (:info) + (:temporary (:sc unsigned-reg) temp) (:policy :fast-safe)) (define-vop (fast-conditional/fixnum fast-conditional) - (:args (x :scs (any-reg) - :load-if (not (and (sc-is x control-stack) - (sc-is y any-reg)))) + (:args (x :scs (any-reg control-stack)) (y :scs (any-reg control-stack))) (:arg-types tagged-num tagged-num) (:note "inline fixnum comparison")) (define-vop (fast-conditional-c/fixnum fast-conditional/fixnum) - (:args (x :scs (any-reg) :load-if t)) + (:args (x :scs (any-reg control-stack))) (:arg-types tagged-num (:constant fixnum)) (:info y)) (define-vop (fast-conditional/signed fast-conditional) - (:args (x :scs (signed-reg) - :load-if (not (and (sc-is x signed-stack) - (sc-is y signed-reg)))) + (:args (x :scs (signed-reg signed-stack)) (y :scs (signed-reg signed-stack))) (:arg-types signed-num signed-num) (:note "inline (signed-byte 64) comparison")) (define-vop (fast-conditional-c/signed fast-conditional/signed) - (:args (x :scs (signed-reg) :load-if t)) + (:args (x :scs (signed-reg signed-stack))) (:arg-types signed-num (:constant (signed-byte 64))) (:info y)) (define-vop (fast-conditional/unsigned fast-conditional) - (:args (x :scs (unsigned-reg) - :load-if (not (and (sc-is x unsigned-stack) - (sc-is y unsigned-reg)))) + (:args (x :scs (unsigned-reg unsigned-stack)) (y :scs (unsigned-reg unsigned-stack))) (:arg-types unsigned-num unsigned-num) (:note "inline (unsigned-byte 64) comparison")) (define-vop (fast-conditional-c/unsigned fast-conditional/unsigned) - (:args (x :scs (unsigned-reg) :load-if t)) + (:args (x :scs (unsigned-reg unsigned-stack))) (:arg-types unsigned-num (:constant (unsigned-byte 64))) (:info y)) -(defun ensure-not-mem+mem (x y) +(defun ensure-not-mem+mem (x y temp) (cond ((sc-is x immediate) - (inst mov temp-reg-tn (tn-value x)) - (ensure-not-mem+mem temp-reg-tn y)) + (inst mov temp (tn-value x)) + (ensure-not-mem+mem temp y nil)) (t (when (and (tn-p y) (sc-is y immediate)) @@ -1231,14 +1575,14 @@ constant shift greater than word length"))) (return-from ensure-not-mem+mem (values x it))) ((typep y '(unsigned-byte 32)) ;; Rather than a RIP-relative constant, load a dword (w/o sign-extend) - (inst mov :dword temp-reg-tn y) - (return-from ensure-not-mem+mem (values x temp-reg-tn)))) + (inst mov :dword temp y) + (return-from ensure-not-mem+mem (values x temp)))) (setq y (register-inline-constant :qword y))) (cond ((or (gpr-tn-p x) (gpr-tn-p y)) (values x y)) (t - (inst mov temp-reg-tn x) - (values temp-reg-tn y)))))) + (inst mov temp x) + (values temp y)))))) (defun immediate-operand-smallest-nbits (x) (declare (type word x)) @@ -1265,7 +1609,7 @@ constant shift greater than word length"))) ;;; if doing so could affect whether the sign flag comes out the same. ;;; e.g. if EDX is #xff, "TEST EDX, #x80" indicates a non-negative result ;;; whereas "TEST DL, #x80" indicates a negative result. -(defun emit-optimized-test-inst (x y sign-bit-matters) +(defun emit-optimized-test-inst (x y temp sign-bit-matters) (let* ((bits (if (or (not (integerp y)) (minusp y)) 64 (immediate-operand-smallest-nbits y))) @@ -1281,8 +1625,8 @@ constant shift greater than word length"))) (and (eq size :word) (not (logtest #xFF y))))) (cond ((not size) ;; Ensure that both operands are acceptable - ;; by possibly loading one into TEMP-REG-TN - (multiple-value-setq (x y) (ensure-not-mem+mem x y)) + ;; by possibly loading one into TEMP + (multiple-value-setq (x y) (ensure-not-mem+mem x y temp)) (inst test :qword x y)) ((sc-is x control-stack unsigned-stack signed-stack) ;; Otherwise, when using an immediate operand smaller @@ -1298,44 +1642,110 @@ constant shift greater than word length"))) (inst test :byte `(,x . :high-byte) (ash y -8)) (inst test size x y)))))) -;; Stolen liberally from the x86 32-bit implementation. (macrolet ((define-logtest-vops () `(progn ,@(loop for suffix in '(/fixnum -c/fixnum /signed -c/signed /unsigned -c/unsigned) - ;; FIXME: remove, after changing the ancestor vops - ;; to not pessimize their allowable SCs - for scs = (case (let ((s (string suffix))) - (intern (subseq s (1+ (position #\/ s))))) - (fixnum '(any-reg control-stack)) - (signed '(signed-reg signed-stack)) - (unsigned '(unsigned-reg unsigned-stack))) - ;; for cost in '(4 3 6 5 6 5) collect `(define-vop (,(symbolicate "FAST-LOGTEST" suffix) ,(symbolicate "FAST-CONDITIONAL" suffix)) (:translate logtest) - ;; Simplify the lambda made by MAKE-GENERATOR-FUNCTION: - ;; LOAD-IF can be NIL because the only alternate SCs to - ;; register SCs are stack SCs. And since we're pretending - ;; that the CPU can directly receive two stack operands, - ;; loading would just check that each argument individually - ;; is either in a register or on the stack - which it is - - ;; and do nothing. - (:args (x :scs ,scs :load-if nil) - ,@(unless (search "-C/" (string suffix)) `((y :scs ,scs :load-if nil)))) - ;; This temp spec is just being cautious. TEMP-REG-TN is reserved - (:temporary (:sc unsigned-reg :offset #.(tn-offset temp-reg-tn)) scratch) - (:ignore scratch) (:conditional :ne) (:generator ,cost (emit-optimized-test-inst x ,(if (eq suffix '-c/fixnum) `(fixnumize y) 'y) - nil))))))) + temp nil))))))) (define-logtest-vops)) +;;; This works for tagged or untagged values, but the vop optimizer +;;; has to pre-adjust Y if tagged. +(define-vop (logtest-memref fast-conditional) + (:args (x :scs (descriptor-reg))) + (:arg-types * (:constant integer)) + (:info y) + (:args-var arg-ref) + (:conditional :ne) + (:generator 1 + (let ((disp (cdr (tn-ref-memory-access arg-ref)))) + ;; Try as :BYTE, :WORD, :DWORD + (macrolet ((try (size bits) + `(let ((disp disp) (y y) (mask ,(ldb (byte bits 0) -1))) + (dotimes (i ,(/ 64 bits)) + (when (zerop (logandc2 y mask)) + (inst test ,size (ea disp x) (ash y (* i ,(- bits)))) + (return-from logtest-memref)) + (setq mask (ash mask ,bits)) + (incf disp ,(/ bits 8)))))) + (try :byte 8) + (try :word 16) + (try :dword 32)) + (let ((val (ea disp x)) + (y (constantize y))) + (cond ((integerp y) + (inst test :qword val y)) + (t + (inst mov temp val) + (inst test :qword temp y))))))) + +;;; Try to absorb a memory load into LOGTEST. +;;; This removes one instruction and possibly shortens the TEST by eliding +;;; a REX prefix. +(defoptimizer (sb-c::vop-optimize fast-logtest-c/fixnum) (vop) + (unless (tn-ref-memory-access (vop-args vop)) + (let ((prev (sb-c::previous-vop-is + ;; TODO: missing data-vector-ref/simple-vector-c + vop '(%raw-instance-ref/signed-word + %raw-instance-ref/word + instance-index-ref-c + ;; This would only happen in unsafe code most likely, + ;; because CAR,CDR, etc would need to cast/assert the loaded + ;; value to fixnum. However, in practive it doesn't work anyway + ;; because there seems to be a spurious MOVE vop in between + ;; the SLOT and the FAST-LOGTEST-C/FIXNUM. + ;; But ironically enough we _did_ seem to want to optimize + ;; an expression in GENERATE-CODE along the lines of: + ;; (if (oddp (length (ir2-component-constants ir2-component))) ...) + ;; which, if #+ubsan, would not be admissible + ;; because VECTOR-LENGTH is not in a slot. + ;; Obviously a GENERATE-CODE bug is the mother of all bugs. + #-ubsan slot)))) + (aver (not (vop-results vop))) ; is a :CONDITIONAL vop + (when (and prev (eq (vop-block prev) (vop-block vop))) + ;; If the memory ref produces a fixnum, the constant should be a fixnum + ;; so that we don't see cases such as in lp#1939897. + ;; In the absence of vop combining, MOVE-TO-WORD would be inserted + ;; between INSTANCE-INDEX-REF and LOGTEST, but it did not happen yet. + (let* ((arg (vop-args vop)) + (info-arg (car (vop-codegen-info vop))) + (constant (if (member (vop-name prev) '(instance-index-ref-c slot)) + (ash info-arg n-fixnum-tag-bits) + info-arg))) + (when (and (eq (tn-ref-tn (vop-results prev)) (tn-ref-tn arg)) + (sb-c::very-temporary-p (tn-ref-tn arg)) + (typep constant '(or word signed-word))) + (binding* ((disp (valid-memref-byte-disp prev) :exit-if-null) + (arg-ref (sb-c:reference-tn (tn-ref-tn (vop-args prev)) nil)) + (new (sb-c::emit-and-insert-vop + (sb-c::vop-node vop) (vop-block vop) + (template-or-lose 'logtest-memref) + arg-ref nil prev (list constant)))) + (setf (tn-ref-memory-access arg-ref) `(:read . ,disp)) + (sb-c::delete-vop prev) + (sb-c::delete-vop vop) + new))))))) +(setf (sb-c::vop-info-optimizer (template-or-lose 'fast-logtest-c/signed)) + #'vop-optimize-fast-logtest-c/fixnum-optimizer) +(setf (sb-c::vop-info-optimizer (template-or-lose 'fast-logtest-c/unsigned)) + #'vop-optimize-fast-logtest-c/fixnum-optimizer) + +;;; TODO: The TEST instruction preceding this JEQ is entirely superfluous +;;; and can be removed with a vop optimizer: +;;; E1: 25FE0F0000 AND EAX, 4094 +;;; E6: 4885C0 TEST RAX, RAX +;;; E9: 74C9 JEQ L2 + ;;; %LOGBITP has the same argument order as ordinary LOGBITP which is * backwards * ;;; relative to every other architecture. ;;; I suspect the others have a predilection for placing codegen info args last. @@ -1365,17 +1775,29 @@ constant shift greater than word length"))) (int :scs (constant signed-reg signed-stack unsigned-reg unsigned-stack) :load-if nil)) (:arg-types untagged-num untagged-num) + (:temporary (:sc unsigned-reg) temp) (:generator 4 (when (sc-is int constant immediate) (setq int (tn-value int))) ;; Force INT to be a RIP-relative operand if it is a constant. (let ((word (if (integerp int) (register-inline-constant :qword int) int)) (bit (cond ((sc-is bit signed-reg unsigned-reg) bit) - (t (inst mov :dword temp-reg-tn bit) + (t (inst mov :dword temp bit) (when (sc-is bit any-reg control-stack) - (inst shr :dword temp-reg-tn n-fixnum-tag-bits)) - temp-reg-tn)))) + (inst shr :dword temp n-fixnum-tag-bits)) + temp)))) (inst bt word bit)))) +(defun change-tested-flag (vop from-flag to-flag) + (ecase (vop-name vop) + (branch-if + (let ((info (vop-codegen-info vop))) + (aver (equal (third info) (list from-flag))) + (setf (vop-codegen-info vop) (list (car info) (cadr info) (list to-flag))))) + (compute-from-flags + (let ((info (vop-codegen-info vop))) + (aver (equal (first info) (list from-flag))) + (setf (vop-codegen-info vop) (list (list to-flag))))))) + (define-vop (%logbitp/c fast-safe-arith-op) (:translate %logbitp) (:conditional :c) @@ -1383,140 +1805,248 @@ constant shift greater than word length"))) (:args (int :scs (signed-reg signed-stack unsigned-reg unsigned-stack any-reg control-stack) :load-if nil)) (:arg-types (:constant (mod 64)) untagged-num) + (:vop-var vop) (:generator 1 (when (sc-is int any-reg control-stack) - ;; Adjust the index up by something. + ;; Acount for fixnum tag bit. ;; Reading beyond the sign bit is the same as reading the sign bit. (setf bit (min (1- n-word-bits) (+ bit n-fixnum-tag-bits)))) + (let ((next (vop-next vop))) + (when (member (vop-name next) '(branch-if compute-from-flags)) + (cond ((not (gpr-tn-p int)) ; is in memory, issue it as a TEST + ;; To test bit index 8: add 1 to the disp, and use immediate val 0x01 + ;; index 9: add 1 to the disp, and use immediate val 0x02 + ;; etc + ;; I'm not crazy about this approach, because we lose the connection + ;; to which TN we're reading. There needs to be a way to emit the instruction + ;; as byte-within-stack-tn so that it is understood by other optimizations. + (binding* ((frame-disp (frame-byte-offset (tn-offset int))) + ((extra-disp bit-shift) (floor bit 8))) + (inst test :byte (ea (+ frame-disp extra-disp) rbp-tn) (ash 1 bit-shift))) + (change-tested-flag next :c :ne) + (return-from %logbitp/c)) + ((= bit 31) ; test the sign bit of the 32-bit register + (inst test :dword int int) + (change-tested-flag next :c :s) + (return-from %logbitp/c)) + ((< bit 32) + (inst test (if (< bit 8) :byte :dword) int (ash 1 bit)) + (change-tested-flag next :c :ne) + (return-from %logbitp/c))))) (inst bt (if (<= bit 31) :dword :qword) int bit))) -(defun emit-optimized-cmp (x y) - (if (and (gpr-tn-p x) (eql y 0)) +(define-vop (%logbitp-memref fast-conditional) + (:args (x :scs (descriptor-reg))) + (:arg-types (:constant (mod 64)) *) + (:info bit) + (:args-var arg-ref) + (:vop-var vop) + (:conditional :ne) + (:ignore temp) + (:generator 1 + ;; This resembles the above case for TN being not in a GPR + (binding* ((slot-disp (cdr (tn-ref-memory-access arg-ref))) + ((extra-disp bit-shift) (floor bit 8))) + (inst test :byte (ea (+ slot-disp extra-disp) x) (ash 1 bit-shift))))) + +(defoptimizer (sb-c::vop-optimize %logbitp/c) (vop) + (unless (tn-ref-memory-access (vop-args vop)) + (let ((prev (sb-c::previous-vop-is + ;; TODO: missing data-vector-ref/simple-vector-c and SLOT + vop '(%raw-instance-ref/signed-word + %raw-instance-ref/word + instance-index-ref-c)))) + (aver (not (vop-results vop))) ; is a :CONDITIONAL vop + (when (and prev (eq (vop-block prev) (vop-block vop))) + (let ((arg (vop-args vop))) + (when (and (eq (tn-ref-tn (vop-results prev)) (tn-ref-tn arg)) + (sb-c::very-temporary-p (tn-ref-tn arg)) + (vop-next vop) + ;; Ensure we can change the tested flag from CF to ZF + (member (vop-name (vop-next vop)) + '(branch-if compute-from-flags))) + (binding* ((disp (valid-memref-byte-disp prev) :exit-if-null) + (arg-ref + (sb-c:reference-tn (tn-ref-tn (vop-args prev)) nil)) + (bit (car (vop-codegen-info vop))) + (info + (if (sb-c::previous-vop-is vop 'instance-index-ref-c) ; tagged slot + ;; Reading beyond the sign bit is the same as reading the sign bit. + (min (+ bit n-fixnum-tag-bits) (1- n-word-bits)) + bit)) + (new (sb-c::emit-and-insert-vop + (sb-c::vop-node vop) (vop-block vop) + (template-or-lose '%logbitp-memref) + arg-ref nil prev (list info)))) + (setf (tn-ref-memory-access arg-ref) `(:read . ,disp)) + (change-tested-flag (vop-next vop) :c :ne) + (sb-c::delete-vop prev) + (sb-c::delete-vop vop) + new))))))) + +;;; We can delete some MOVEs that seem often to get inserted with iteration constructs +;;; such as (setq i (1+ i)) where the result of 1+ creates a new TN which is moved +;;; to the same TN that is the input to 1+, but PACK chooses different physical registers +;;; for the arg and result of FAST-+-C/FIXNUM=>FIXNUM. So we "cleverly" can use the LEA +;;; instruction as a 3-operand ADD, only to move the destination of LEA back to the +;;; same register that was one of the input operands. Yet the TN which was the result +;;; had otherwise no use. Why does this happen? I don't know. +;;; +;;; So let's try to prevent it by removing the MOVE, which reduces to just the ADD +;;; instruction instead of LEA + MOV. If a vop can only take one physical representation +;;; (such as tagged fixnum) for input, and can only produce that same representation, +;;; and the TN flows back to that vop, then the move is not needed. But if a vop can take +;;; several physical representations, such as accepting either tagged or untagged, +;;; and the SC has not been chosen yet (which happens), then we can't remove. +;;; +;;; For some reason, it seems to come up a trememdous amount with FAST-+-C/FIXNUM=>FIXNUM. +;;; Maybe it comes up with others, I don't know. No harm in trying, I suppose. +;;; To do this for other vops, you have to be certain that the move isn't a coercion. +;;; +;;; [And it would be nice if every backend named their vops consistently +;;; so that this optimizer could be made architecture-independent] +;;; The SB-C::DELETE- function isn't defined yet in the build order, so wrap it in a lambda. +(flet ((optimizer (vop) (sb-c::delete-unnecessary-move vop))) + (dolist (name '(sb-vm::fast-+-c/fixnum=>fixnum + sb-vm::fast-+-c/signed=>signed + sb-vm::fast-+-c/unsigned=>unsigned + sb-vm::fast---c/fixnum=>fixnum + sb-vm::fast---c/signed=>signed + sb-vm::fast---c/unsigned=>unsigned + sb-vm::fast-*-c/fixnum=>fixnum + sb-vm::fast-*-c/signed=>signed + sb-vm::fast-*-c/unsigned=>unsigned)) + (sb-c::set-vop-optimizer (template-or-lose name) #'optimizer))) + +(defun emit-optimized-cmp (x y temp &optional x-ctype) + ;; Shorten the encoding by eliding a REX prefix where the upper bits + ;; can not possibly matter. + ;; Be sure to account for N-FIXNUM-TAG-BITS in determining how many bits + ;; of precision are in the representation of X. + ;; Little-endian addressing makes this valid for stack TNs as well as registers. + (let ((operand-size (if (and (numeric-type-p x-ctype) + (typep y '(signed-byte 32)) + (csubtypep x-ctype + (if (sc-is x any-reg descriptor-reg control-stack) + (specifier-type '(signed-byte 31)) + (specifier-type '(signed-byte 32))))) + :dword + :qword))) + (if (and (gpr-tn-p x) (eql y 0)) ;; Amazingly (to me), use of TEST in lieu of CMP produces all the correct ;; flag bits for inequality comparison as well as EQL comparison. ;; You'd think that the Jxx instruction should examine _only_ the S flag, ;; but in fact the other flags are right too. Nonetheless this is ;; quite confusing, and I would prefer that we alter the branch test ;; when emitting TEST in place of CMP. - (inst test x x) ; smaller instruction - (progn (multiple-value-setq (x y) (ensure-not-mem+mem x y)) - (inst cmp x y)))) + (inst test operand-size x x) ; smaller instruction + (progn (multiple-value-setq (x y) (ensure-not-mem+mem x y temp)) + (inst cmp operand-size x y))))) (macrolet ((define-conditional-vop (tran cond unsigned not-cond not-unsigned) (declare (ignore not-cond not-unsigned)) `(progn ,@(mapcar (lambda (suffix cost signed) - (let ((scs (case (let ((s (string suffix))) - (intern (subseq s (1+ (position #\/ s))))) - (fixnum '(any-reg control-stack)) - (signed '(signed-reg signed-stack)) - (unsigned '(unsigned-reg unsigned-stack))))) `(define-vop (,(symbolicate "FAST-IF-" tran suffix) ,(symbolicate "FAST-CONDITIONAL" suffix)) - (:args (x :scs ,scs :load-if nil) - ,@(unless (search "-C/" (string suffix)) - `((y :scs ,scs :load-if nil)))) (:translate ,tran) (:conditional ,(if signed cond unsigned)) + (:args-var x-tn-ref) (:generator ,cost (emit-optimized-cmp - x ,(if (eq suffix '-c/fixnum) `(fixnumize y) 'y)))))) + x ,(if (eq suffix '-c/fixnum) `(fixnumize y) 'y) + temp (tn-ref-type x-tn-ref))))) '(/fixnum -c/fixnum /signed -c/signed /unsigned -c/unsigned) -; '(/fixnum /signed /unsigned) '(4 3 6 5 6 5) '(t t t t nil nil))))) (define-conditional-vop < :l :b :ge :ae) (define-conditional-vop > :g :a :le :be)) -(define-vop (fast-if->-zero) - (:args (x :scs (descriptor-reg))) - (:arg-types integer (:constant (integer 0 0))) - (:info target not-p y) - (:ignore y) - (:temporary (:sc unsigned-reg) temp) - (:translate >) - (:conditional) - (:variant nil) - (:variant-vars bignum-only) +(define-vop (<-unsigned-signed) + (:translate <) + (:args (unsigned :scs (unsigned-reg)) + (signed :scs (signed-reg))) + (:arg-types unsigned-num signed-num) + (:temporary (:sc signed-reg) temp) + (:conditional :b) (:policy :fast-safe) - (:generator 8 - (move temp x) - (unless bignum-only - (generate-fixnum-test temp) - (inst jmp :nz BIGNUM) - (inst test temp temp) - (inst jmp (if not-p :le :g) target) - (inst jmp DONE)) - BIGNUM - (loadw temp x 0 other-pointer-lowtag) - (inst shr temp n-widetag-bits) - (inst cmp :qword - (ea (- (+ (* bignum-digits-offset n-word-bytes)) - other-pointer-lowtag - n-word-bytes) - x - temp - (ash 1 word-shift)) - 0) - (inst jmp (if not-p :l :ge) target) - DONE)) + (:generator 7 + (zeroize temp) + (inst test signed signed) + (inst cmov :ge temp signed) + (inst cmp unsigned temp))) -(define-vop (fast-if->-zero-bignum fast-if->-zero) - (:arg-types bignum (:constant (integer 0 0))) - (:variant t)) - -(define-vop (fast-if-<-zero fast-if->-zero) - (:info y) +(define-vop (>-unsigned-signed) + (:translate >) + (:args (unsigned :scs (unsigned-reg)) + (signed :scs (signed-reg))) + (:arg-types unsigned-num signed-num) + (:policy :fast-safe) + (:conditional :a) + (:generator 7 + (inst test signed signed) + (inst jmp :l done) + (inst cmp unsigned signed) + done)) + +(define-vop (<-signed-unsigned) (:translate <) - (:conditional :l) - (:variant nil) - (:generator 9 - (unless bignum-only - (move temp x) - (generate-fixnum-test temp) - (inst jmp :z TEST)) - (loadw temp x 0 other-pointer-lowtag) - (inst shr temp n-widetag-bits) - (inst mov temp (ea (- (* bignum-digits-offset n-word-bytes) - other-pointer-lowtag - n-word-bytes) - x - temp - (ash 1 word-shift))) - TEST - (inst test temp temp))) - -(define-vop (fast-if-<-zero-bignum fast-if-<-zero) - (:arg-types bignum (:constant (integer 0 0))) - (:variant t)) + (:args (signed :scs (signed-reg)) + (unsigned :scs (unsigned-reg))) + (:arg-types signed-num unsigned-num) + (:conditional :a) + (:policy :fast-safe) + (:generator 7 + (inst test signed signed) + (inst jmp :l done) + (inst cmp unsigned signed) + done)) + +(define-vop (>-signed-unsigned <-signed-unsigned) + (:translate >) + (:temporary (:sc signed-reg) temp) + (:conditional :a) + (:generator 7 + (zeroize temp) + (inst test signed signed) + (inst cmov :ge temp signed) + (inst cmp temp unsigned))) + +(define-vop (eql-unsigned-signed) + (:translate eql %eql/integer) + (:args (unsigned :scs (unsigned-reg)) + (signed :scs (signed-reg))) + (:arg-types unsigned-num signed-num) + (:conditional :eq) + (:policy :fast-safe) + (:generator 7 + (inst test signed signed) + (inst jmp :l done) + (inst cmp unsigned signed) + done)) + +(define-vop (eql-signed-unsigned eql-unsigned-signed) + (:args (signed :scs (signed-reg)) + (unsigned :scs (unsigned-reg))) + (:arg-types signed-num unsigned-num)) (define-vop (fast-if-eql/signed fast-conditional/signed) (:translate eql %eql/integer) - (:generator 6 - (inst cmp x y))) + (:generator 6 (emit-optimized-cmp x y temp))) (define-vop (fast-if-eql-c/signed fast-conditional-c/signed) (:translate eql %eql/integer) - (:generator 5 - (cond ((and (sc-is x signed-reg) (zerop y)) - (inst test x x)) ; smaller instruction - (t - (inst cmp x (constantize y)))))) + (:generator 5 (emit-optimized-cmp x y temp))) (define-vop (fast-if-eql/unsigned fast-conditional/unsigned) (:translate eql %eql/integer) - (:generator 6 - (inst cmp x y))) + (:generator 6 (emit-optimized-cmp x y temp))) (define-vop (fast-if-eql-c/unsigned fast-conditional-c/unsigned) (:translate eql %eql/integer) - (:generator 5 - (cond ((and (sc-is x unsigned-reg) (zerop y)) - (inst test x x)) ; smaller instruction - (t - (inst cmp x (constantize y)))))) + (:generator 5 (emit-optimized-cmp x y temp))) ;;; EQL/FIXNUM is funny because the first arg can be of any type, not just a ;;; known fixnum. @@ -1528,75 +2058,81 @@ constant shift greater than word length"))) ;;; consing the argument. (define-vop (fast-eql/fixnum fast-conditional) - (:args (x :scs (any-reg) - :load-if (not (and (sc-is x control-stack) - (sc-is y any-reg)))) + (:args (x :scs (any-reg control-stack)) (y :scs (any-reg control-stack))) (:arg-types tagged-num tagged-num) (:note "inline fixnum comparison") (:translate eql %eql/integer) - (:generator 4 - (inst cmp x y))) + (:generator 4 (emit-optimized-cmp x y temp))) (define-vop (generic-eql/fixnum fast-eql/fixnum) - (:args (x :scs (any-reg descriptor-reg) - :load-if (not (and (sc-is x control-stack) - (sc-is y any-reg)))) + (:args (x :scs (any-reg descriptor-reg control-stack)) (y :scs (any-reg control-stack))) (:arg-types * tagged-num) (:variant-cost 7)) (define-vop (fast-eql-c/fixnum fast-conditional-c/fixnum) - (:args (x :scs (any-reg) :load-if t)) + (:args (x :scs (any-reg control-stack))) (:arg-types tagged-num (:constant fixnum)) (:info y) (:conditional :e) (:policy :fast-safe) (:translate eql %eql/integer) - (:generator 2 - (cond ((and (sc-is x any-reg descriptor-reg) (zerop y)) - (inst test x x)) ; smaller instruction - (t - (inst cmp x (constantize (fixnumize y))))))) + (:args-var x-tn-ref) + (:generator 2 (emit-optimized-cmp x (fixnumize y) temp (tn-ref-type x-tn-ref)))) +;;; FIXME: this seems never to be invoked any more. What did we either break or improve? (define-vop (generic-eql-c/fixnum fast-eql-c/fixnum) - (:args (x :scs (any-reg descriptor-reg) :load-if t)) + (:args (x :scs (any-reg descriptor-reg control-stack))) (:arg-types * (:constant fixnum)) (:variant-cost 6)) ;;;; 64-bit logical operations ;;; Only the lower 6 bits of the shift amount are significant. -(define-vop (shift-towards-someplace) - (:policy :fast-safe) - (:args (num :scs (unsigned-reg) :target r) - (amount :scs (signed-reg) :target ecx)) - (:arg-types unsigned-num tagged-num) - (:temporary (:sc signed-reg :offset ecx-offset :from (:argument 1)) ecx) - (:results (r :scs (unsigned-reg) :from (:argument 0))) - (:result-types unsigned-num)) - -(define-vop (shift-towards-start shift-towards-someplace) - (:translate shift-towards-start) - (:note "SHIFT-TOWARDS-START") - (:generator 1 - (move r num) - (move ecx amount) - (inst shr r :cl))) - -(define-vop (shift-towards-end shift-towards-someplace) - (:translate shift-towards-end) - (:note "SHIFT-TOWARDS-END") - (:generator 1 - (move r num) - (move ecx amount) - (inst shl r :cl))) +(macrolet ((define (translate operation) + `(define-vop () + (:translate ,translate) + (:note ,(string translate)) + (:policy :fast-safe) + (:args (num :scs (unsigned-reg) :target r) + (amount :scs (signed-reg) :target rcx)) + (:arg-types unsigned-num tagged-num) + (:temporary (:sc signed-reg :offset rcx-offset :from (:argument 1)) rcx) + (:results (r :scs (unsigned-reg) :from (:argument 0))) + (:result-types unsigned-num) + (:generator 1 + (move r num) + (move rcx amount :dword) + (inst ,operation r :cl))))) + (define shift-towards-start shr) + (define shift-towards-end shl)) ;;;; Modular functions (defmacro define-mod-binop ((name prototype) function) - (unless (search "FAST-*" (string prototype)) ; fast-* doesn't accept stack locations yet - (return-from define-mod-binop + (if (search "FAST-*" (string prototype)) ; fast-* doesn't accept stack locations yet + `(define-vop (,name ,prototype) + (:args (x :target r :scs (unsigned-reg signed-reg) + :load-if (not (and (or (sc-is x unsigned-stack) + (sc-is x signed-stack)) + (or (sc-is y unsigned-reg) + (sc-is y signed-reg)) + (or (sc-is r unsigned-stack) + (sc-is r signed-stack)) + (location= x r)))) + (y :scs (unsigned-reg signed-reg unsigned-stack signed-stack))) + (:arg-types untagged-num untagged-num) + (:results (r :scs (unsigned-reg signed-reg) :from (:argument 0) + :load-if (not (and (or (sc-is x unsigned-stack) + (sc-is x signed-stack)) + (or (sc-is y unsigned-reg) + (sc-is y unsigned-reg)) + (or (sc-is r unsigned-stack) + (sc-is r unsigned-stack)) + (location= x r))))) + (:result-types unsigned-num) + (:translate ,function)) `(define-vop (,name ,prototype) (:args (x :scs (unsigned-reg signed-reg unsigned-stack signed-stack immediate) :load-if nil :target r) @@ -1607,30 +2143,16 @@ constant shift greater than word length"))) :load-if nil)) (:result-types unsigned-num) (:translate ,function)))) - `(define-vop (,name ,prototype) - (:args (x :target r :scs (unsigned-reg signed-reg) - :load-if (not (and (or (sc-is x unsigned-stack) - (sc-is x signed-stack)) - (or (sc-is y unsigned-reg) - (sc-is y signed-reg)) - (or (sc-is r unsigned-stack) - (sc-is r signed-stack)) - (location= x r)))) - (y :scs (unsigned-reg signed-reg unsigned-stack signed-stack))) - (:arg-types untagged-num untagged-num) - (:results (r :scs (unsigned-reg signed-reg) :from (:argument 0) - :load-if (not (and (or (sc-is x unsigned-stack) - (sc-is x signed-stack)) - (or (sc-is y unsigned-reg) - (sc-is y unsigned-reg)) - (or (sc-is r unsigned-stack) - (sc-is r unsigned-stack)) - (location= x r))))) - (:result-types unsigned-num) - (:translate ,function))) + (defmacro define-mod-binop-c ((name prototype) function) - (unless (search "FAST-*" (string prototype)) ; fast-* doesn't accept stack locations yet - (return-from define-mod-binop-c + (if (search "FAST-*" (string prototype)) ; fast-* doesn't accept stack locations yet + `(define-vop (,name ,prototype) + (:args (x :target r :scs (unsigned-reg signed-reg) :load-if t)) + (:info y) + (:arg-types untagged-num (:constant (or (unsigned-byte 64) (signed-byte 64)))) + (:results (r :scs (unsigned-reg signed-reg) :from (:argument 0) :load-if t)) + (:result-types unsigned-num) + (:translate ,function)) `(define-vop (,name ,prototype) (:args (x :target r :scs (unsigned-reg signed-reg unsigned-stack signed-stack) :load-if nil)) (:info y) @@ -1638,23 +2160,14 @@ constant shift greater than word length"))) (:results (r :scs (unsigned-reg signed-reg unsigned-stack signed-stack) :load-if nil)) (:result-types unsigned-num) (:translate ,function)))) - `(define-vop (,name ,prototype) - (:args (x :target r :scs (unsigned-reg signed-reg) - :load-if t)) - (:info y) - (:arg-types untagged-num (:constant (or (unsigned-byte 64) (signed-byte 64)))) - (:results (r :scs (unsigned-reg signed-reg) :from (:argument 0) - :load-if t)) - (:result-types unsigned-num) - (:translate ,function))) - -(macrolet ((def (name -c-p &aux (inherit name)) + +(macrolet ((def (name) (let ((fun64 (symbolicate name "-MOD64")) (funfx (symbolicate name "-MODFX")) - (vopu (symbolicate "FAST-" inherit "/UNSIGNED=>UNSIGNED")) - (vopcu (symbolicate "FAST-" inherit "-C/UNSIGNED=>UNSIGNED")) - (vopf (symbolicate "FAST-" inherit "/FIXNUM=>FIXNUM")) - (vopcf (symbolicate "FAST-" inherit "-C/FIXNUM=>FIXNUM")) + (vopu (symbolicate "FAST-" name "/UNSIGNED=>UNSIGNED")) + (vopcu (symbolicate "FAST-" name "-C/UNSIGNED=>UNSIGNED")) + (vopf (symbolicate "FAST-" name "/FIXNUM=>FIXNUM")) + (vopcf (symbolicate "FAST-" name "-C/FIXNUM=>FIXNUM")) (vop64u (symbolicate "FAST-" name "-MOD64/WORD=>UNSIGNED")) (vop64f (symbolicate "FAST-" name "-MOD64/FIXNUM=>FIXNUM")) (vop64cu (symbolicate "FAST-" name "-MOD64-C/WORD=>UNSIGNED")) @@ -1664,20 +2177,18 @@ constant shift greater than word length"))) (declare (ignore vop64cf)) ; maybe someone will want it some day `(progn (define-modular-fun ,fun64 (x y) ,name :untagged nil 64) - (define-modular-fun ,funfx (x y) ,name :tagged t - #.(- n-word-bits n-fixnum-tag-bits)) + (define-modular-fun ,funfx (x y) ,name :tagged t #.n-fixnum-bits) (define-mod-binop (,vop64u ,vopu) ,fun64) ;; This seems a bit lame. Could we not just have one vop ;; which which takes any combination of signed/unsigned reg ;; and which translates the normal function and the modular function? (define-vop (,vop64f ,vopf) (:translate ,fun64)) (define-vop (,vopfxf ,vopf) (:translate ,funfx)) - ,@(when -c-p - `((define-mod-binop-c (,vop64cu ,vopcu) ,fun64) - (define-vop (,vopfxcf ,vopcf) (:translate ,funfx)))))))) - (def + t) - (def - t) - (def * t)) + (define-mod-binop-c (,vop64cu ,vopcu) ,fun64) + (define-vop (,vopfxcf ,vopcf) (:translate ,funfx)))))) + (def +) + (def -) + (def *)) (define-modular-fun %negate-mod64 (x) %negate :untagged nil 64) (define-vop (%negate-mod64) @@ -1691,40 +2202,9 @@ constant shift greater than word length"))) (move r x) (inst neg r))) -(define-modular-fun %negate-modfx (x) %negate :tagged t #.(- n-word-bits - n-fixnum-tag-bits)) +(define-modular-fun %negate-modfx (x) %negate :tagged t #.n-fixnum-bits) (define-vop (%negate-modfx fast-negate/fixnum) (:translate %negate-modfx)) - -(define-vop (fast-ash-left-mod64-c/unsigned=>unsigned - fast-ash-c/unsigned=>unsigned) - (:translate ash-left-mod64)) -(define-vop (fast-ash-left-mod64/unsigned=>unsigned - fast-ash-left/unsigned=>unsigned)) -(define-vop (fast-ash-left-mod64/unsigned-unbounded=>unsigned - fast-ash-left/unsigned-unbounded=>unsigned) - (:translate ash-left-mod64)) -(deftransform ash-left-mod64 ((integer count) - ((unsigned-byte 64) (unsigned-byte 6))) - (when (sb-c::constant-lvar-p count) - (sb-c::give-up-ir1-transform)) - '(%primitive fast-ash-left-mod64/unsigned=>unsigned integer count)) - -(define-vop (fast-ash-left-modfx-c/fixnum=>fixnum - fast-ash-c/fixnum=>fixnum) - (:variant :modular) - (:translate ash-left-modfx)) -(define-vop (fast-ash-left-modfx/fixnum-unbounded=>fixnum - fast-ash-left/fixnum-unbounded=>fixnum) - (:translate ash-left-modfx)) -(define-vop (fast-ash-left-modfx/fixnum=>fixnum - fast-ash-left/fixnum=>fixnum)) -(deftransform ash-left-modfx ((integer count) - (fixnum (unsigned-byte 6))) - (when (sb-c::constant-lvar-p count) - (sb-c::give-up-ir1-transform)) - '(%primitive fast-ash-left-modfx/fixnum=>fixnum integer count)) - (in-package "SB-C") (defknown sb-vm::%lea-mod64 (integer integer (member 1 2 4 8) (signed-byte 64)) @@ -1742,7 +2222,7 @@ constant shift greater than word length"))) (cut-to-width index :untagged width nil) 'sb-vm::%lea-mod64)) (define-modular-fun-optimizer %lea ((base index scale disp) :tagged t :width width) - (when (and (<= width (- sb-vm:n-word-bits sb-vm:n-fixnum-tag-bits)) + (when (and (<= width sb-vm:n-fixnum-bits) (constant-lvar-p scale) (constant-lvar-p disp)) (cut-to-width base :tagged width t) @@ -1754,7 +2234,7 @@ constant shift greater than word length"))) (defun sb-vm::%lea-mod64 (base index scale disp) (ldb (byte 64 0) (%lea base index scale disp))) (defun sb-vm::%lea-modfx (base index scale disp) - (mask-signed-field (- sb-vm:n-word-bits sb-vm:n-fixnum-tag-bits) + (mask-signed-field sb-vm:n-fixnum-bits (%lea base index scale disp)))) #-sb-xc-host (progn @@ -1765,7 +2245,7 @@ constant shift greater than word length"))) ;; constant SCALE and DISP. (ldb (byte 64 0) (+ base (* index scale) disp)))) (defun sb-vm::%lea-modfx (base index scale disp) - (let* ((fixnum-width (- sb-vm:n-word-bits sb-vm:n-fixnum-tag-bits)) + (let* ((fixnum-width sb-vm:n-fixnum-bits) (base (mask-signed-field fixnum-width base)) (index (mask-signed-field fixnum-width index))) ;; can't use modular version of %LEA, as we only have VOPs for @@ -1827,13 +2307,17 @@ constant shift greater than word length"))) (:translate sb-bignum:%bignum-set-length) (:policy :fast-safe)) +#-bignum-assertions ; %BIGNUM-ref is an inline function if compiling with assertions (define-full-reffer bignum-ref * bignum-digits-offset other-pointer-lowtag (unsigned-reg) unsigned-num sb-bignum:%bignum-ref) -(define-full-reffer+offset bignum-ref-with-offset * bignum-digits-offset +#-bignum-assertions ; does not get called if compiling with assertions +(define-full-reffer+addend bignum-ref-with-offset * bignum-digits-offset other-pointer-lowtag (unsigned-reg) unsigned-num sb-bignum:%bignum-ref-with-offset) (define-full-setter bignum-set * bignum-digits-offset other-pointer-lowtag - (unsigned-reg) unsigned-num sb-bignum:%bignum-set) + (unsigned-reg) unsigned-num + #+bignum-assertions sb-bignum:%%bignum-set + #-bignum-assertions sb-bignum:%bignum-set) (define-vop (digit-0-or-plus) (:translate sb-bignum:%digit-0-or-plusp) @@ -1858,14 +2342,16 @@ constant shift greater than word length"))) (:temporary (:sc any-reg :from (:argument 2) :to :eval) temp) (:results (result :scs (unsigned-reg) :from (:argument 0)) (carry :scs (unsigned-reg))) + (:optional-results carry) (:result-types unsigned-num positive-fixnum) (:generator 4 (move result a) (move temp c) (inst neg temp) ; Set the carry flag to 0 if c=0 else to 1 (inst adc result b) - (inst set carry :c) - (inst and :dword carry 1))) + (unless (eq (tn-kind carry) :unused) + (inst set :c carry) + (inst and :dword carry 1)))) ;;; Note: the borrow is 1 for no borrow and 0 for a borrow, the opposite ;;; of the x86-64 convention. @@ -1878,14 +2364,15 @@ constant shift greater than word length"))) (:arg-types unsigned-num unsigned-num positive-fixnum) (:results (result :scs (unsigned-reg) :from :eval) (borrow :scs (unsigned-reg))) + (:optional-results borrow) (:result-types unsigned-num positive-fixnum) (:generator 5 (inst cmp c 1) ; Set the carry flag to 1 if c=0 else to 0 (move result a) (inst sbb result b) - (inst mov borrow 1) - (inst sbb :dword borrow 0))) - + (unless (eq (tn-kind borrow) :unused) + (inst mov borrow 1) + (inst sbb :dword borrow 0)))) (define-vop (bignum-mult-and-add-3-arg) (:translate sb-bignum:%multiply-and-add) @@ -1894,9 +2381,9 @@ constant shift greater than word length"))) (y :scs (unsigned-reg unsigned-stack)) (carry-in :scs (unsigned-reg unsigned-stack))) (:arg-types unsigned-num unsigned-num unsigned-num) - (:temporary (:sc unsigned-reg :offset eax-offset :from (:argument 0) + (:temporary (:sc unsigned-reg :offset rax-offset :from (:argument 0) :to (:result 1) :target lo) eax) - (:temporary (:sc unsigned-reg :offset edx-offset :from (:argument 1) + (:temporary (:sc unsigned-reg :offset rdx-offset :from (:argument 1) :to (:result 0) :target hi) edx) (:results (hi :scs (unsigned-reg)) (lo :scs (unsigned-reg))) @@ -1917,9 +2404,9 @@ constant shift greater than word length"))) (prev :scs (unsigned-reg unsigned-stack)) (carry-in :scs (unsigned-reg unsigned-stack))) (:arg-types unsigned-num unsigned-num unsigned-num unsigned-num) - (:temporary (:sc unsigned-reg :offset eax-offset :from (:argument 0) + (:temporary (:sc unsigned-reg :offset rax-offset :from (:argument 0) :to (:result 1) :target lo) eax) - (:temporary (:sc unsigned-reg :offset edx-offset :from (:argument 1) + (:temporary (:sc unsigned-reg :offset rdx-offset :from (:argument 1) :to (:result 0) :target hi) edx) (:results (hi :scs (unsigned-reg)) (lo :scs (unsigned-reg))) @@ -1941,9 +2428,9 @@ constant shift greater than word length"))) (:args (x :scs (unsigned-reg) :target eax) (y :scs (unsigned-reg unsigned-stack))) (:arg-types unsigned-num unsigned-num) - (:temporary (:sc unsigned-reg :offset eax-offset :from (:argument 0) + (:temporary (:sc unsigned-reg :offset rax-offset :from (:argument 0) :to (:result 1) :target lo) eax) - (:temporary (:sc unsigned-reg :offset edx-offset :from (:argument 1) + (:temporary (:sc unsigned-reg :offset rdx-offset :from (:argument 1) :to (:result 0) :target hi) edx) (:results (hi :scs (unsigned-reg)) (lo :scs (unsigned-reg))) @@ -1960,9 +2447,9 @@ constant shift greater than word length"))) (:args (x :scs (unsigned-reg) :target eax) (y :scs (unsigned-reg unsigned-stack))) (:arg-types unsigned-num unsigned-num) - (:temporary (:sc unsigned-reg :offset eax-offset :from (:argument 0)) + (:temporary (:sc unsigned-reg :offset rax-offset :from (:argument 0)) eax) - (:temporary (:sc unsigned-reg :offset edx-offset :from (:argument 1) + (:temporary (:sc unsigned-reg :offset rdx-offset :from (:argument 1) :to (:result 0) :target hi) edx) (:results (hi :scs (unsigned-reg))) (:result-types unsigned-num) @@ -1977,8 +2464,8 @@ constant shift greater than word length"))) (:args (x :scs (any-reg) :target eax) (y :scs (unsigned-reg unsigned-stack))) (:arg-types positive-fixnum unsigned-num) - (:temporary (:sc any-reg :offset eax-offset :from (:argument 0)) eax) - (:temporary (:sc any-reg :offset edx-offset :from (:argument 1) + (:temporary (:sc any-reg :offset rax-offset :from (:argument 0)) eax) + (:temporary (:sc any-reg :offset rdx-offset :from (:argument 1) :to (:result 0) :target hi) edx) (:results (hi :scs (any-reg))) (:result-types positive-fixnum) @@ -1988,6 +2475,23 @@ constant shift greater than word length"))) (move hi edx) (inst and hi (lognot fixnum-tag-mask)))) +(define-vop () + (:translate %signed-multiply-high) + (:policy :fast-safe) + (:args (x :scs (signed-reg) :target eax) + (y :scs (signed-reg signed-stack))) + (:arg-types signed-num signed-num) + (:temporary (:sc signed-reg :offset rax-offset :from (:argument 0)) + eax) + (:temporary (:sc signed-reg :offset rdx-offset :from (:argument 1) + :to (:result 0) :target hi) edx) + (:results (hi :scs (signed-reg))) + (:result-types signed-num) + (:generator 20 + (move eax x) + (inst imul y) + (move hi edx))) + (define-vop (bignum-lognot lognot-mod64/unsigned=>unsigned) (:translate sb-bignum:%lognot)) @@ -2012,9 +2516,9 @@ constant shift greater than word length"))) (div-low :scs (unsigned-reg) :target eax) (divisor :scs (unsigned-reg unsigned-stack))) (:arg-types unsigned-num unsigned-num unsigned-num) - (:temporary (:sc unsigned-reg :offset eax-offset :from (:argument 1) + (:temporary (:sc unsigned-reg :offset rax-offset :from (:argument 1) :to (:result 0) :target quo) eax) - (:temporary (:sc unsigned-reg :offset edx-offset :from (:argument 0) + (:temporary (:sc unsigned-reg :offset rdx-offset :from (:argument 0) :to (:result 1) :target rem) edx) (:results (quo :scs (unsigned-reg)) (rem :scs (unsigned-reg))) @@ -2047,7 +2551,7 @@ constant shift greater than word length"))) (:args (digit :scs (unsigned-reg unsigned-stack) :target result) (count :scs (unsigned-reg) :target ecx)) (:arg-types unsigned-num positive-fixnum) - (:temporary (:sc unsigned-reg :offset ecx-offset :from (:argument 1)) ecx) + (:temporary (:sc unsigned-reg :offset rcx-offset :from (:argument 1)) ecx) (:results (result :scs (unsigned-reg) :from (:argument 0) :load-if (not (and (sc-is result unsigned-stack) (location= digit result))))) diff --git a/src/compiler/x86-64/array.lisp b/src/compiler/x86-64/array.lisp index f85eb21164..768beb9807 100644 --- a/src/compiler/x86-64/array.lisp +++ b/src/compiler/x86-64/array.lisp @@ -16,6 +16,49 @@ ;; field of an EA can't contain 64 bit values. (sb-xc:deftype low-index () '(signed-byte 29)) +(defun unpoison-element (array index &optional (addend 0)) + #-ubsan (declare (ignore array index addend)) + #+ubsan + (let ((no-bits (gen-label))) + (aver (= addend 0)) + (inst mov temp-reg-tn (object-slot-ea array 1 other-pointer-lowtag)) + ;; See if the ancillary slot holds a bit-vector and not a list. + ;; A list will denote the stack trace at the creation site + ;; rather than shadow bits. + (inst test :byte temp-reg-tn #b1000) + (inst jmp :z no-bits) + (flet ((constant-index (index) + (multiple-value-bind (dword-index bit) (floor index 32) dword-index bit + (inst bts :lock :dword (ea (bit-base dword-index) temp-reg-tn) bit)))) + (if (integerp index) + (constant-index index) + (sc-case index + (immediate (constant-index (tn-value index))) + ((signed-reg unsigned-reg) + (inst bts :lock (ea (bit-base 0) temp-reg-tn) index)) + (t + (aver (sc-is index any-reg)) + (inst shr :dword index 1) ; untag it + (inst bts :lock (ea (bit-base 0) temp-reg-tn) index) + (inst shl :dword index 1))))) + (emit-label no-bits))) + +(defun test-poisoned (vop temp array index &optional (addend 0)) + (declare (ignore vop temp array index addend)) + #+nil + (unless (sb-c::policy (sb-c::vop-node vop) (= safety 0)) + (let ((ok (gen-label))) + (when (integerp index) (setq index (emit-constant index))) + (inst mov temp (object-slot-ea object 1 other-pointer-lowtag)) ; shadow bits + (inst test :byte temp temp) + (inst jmp :z ok) ; no shadow bits + (if (and (eql addend 0) (eql (tn-sc index unsigned-reg))) + (inst bt (ea (bit-base 0) temp) index) + (error "Unhandled SCs in test-poisoned")) + (inst jmp :nc (generate-error-code vop 'uninitialized-element-error + object index addend)) + (emit-label ok)))) + ;;;; allocator for the array header (define-vop (make-array-header) @@ -26,6 +69,8 @@ (:arg-types positive-fixnum positive-fixnum) (:temporary (:sc any-reg :to :eval) bytes) (:temporary (:sc any-reg :to :result) header) + (:temporary (:sc unsigned-reg) temp) + #+gs-seg (:temporary (:sc unsigned-reg :offset 15) thread-tn) (:results (result :scs (descriptor-reg) :from :eval)) (:node-var node) (:generator 13 @@ -33,36 +78,17 @@ (ea (+ (* array-dimensions-offset n-word-bytes) lowtag-mask) nil rank (ash 1 (- word-shift n-fixnum-tag-bits)))) (inst and :dword bytes (lognot lowtag-mask)) - (inst lea :dword header (ea (fixnumize (1- array-dimensions-offset)) rank)) - (inst shl :dword header n-widetag-bits) + ;; rank 1 is stored as 0, 2 is stored as 1, ... + (inst lea :dword header (ea (fixnumize -1) rank)) + (inst and :dword header (fixnumize array-rank-mask)) + (inst shl :dword header array-rank-position) (inst or :dword header type) (inst shr :dword header n-fixnum-tag-bits) - (instrument-alloc bytes node) - (pseudo-atomic () - (allocation nil bytes 0 node nil result) + (instrument-alloc nil bytes node temp thread-tn) + (pseudo-atomic (:thread-tn thread-tn) + (allocation nil bytes 0 result node temp thread-tn) (storew header result 0 0) (inst or :byte result other-pointer-lowtag)))) - -(define-vop (make-array-header/c) - (:translate make-array-header) - (:policy :fast-safe) - (:arg-types (:constant t) (:constant t)) - (:info type rank) - (:results (result :scs (descriptor-reg) :from :eval)) - (:node-var node) - (:generator 12 - (let* ((header-size (+ rank - (1- array-dimensions-offset))) - (bytes (* (align-up (1+ header-size) 2) n-word-bytes)) - (header (logior (ash header-size - n-widetag-bits) - type))) - (instrument-alloc bytes node) - (pseudo-atomic () - (allocation nil bytes 0 node nil result) - (storew* header result 0 0 t) - (inst or :byte result other-pointer-lowtag))))) - ;;;; additional accessors and setters for the array header (define-full-reffer %array-dimension * @@ -73,31 +99,17 @@ array-dimensions-offset other-pointer-lowtag (any-reg) positive-fixnum %set-array-dimension) -(define-vop (array-rank-vop) +(symbol-macrolet ((rank-disp + (- (/ array-rank-position n-byte-bits) other-pointer-lowtag))) +(define-vop () (:translate %array-rank) (:policy :fast-safe) (:args (x :scs (descriptor-reg))) (:results (res :scs (unsigned-reg))) (:result-types positive-fixnum) (:generator 3 - ;; An unaligned dword read not spanning a 16-byte boundary is as fast as - ;; and shorter by 5 bytes than a qword read and right-shift by 8. - (inst mov :dword res (ea (1+ (- other-pointer-lowtag)) x)) - (inst sub :dword res (1- array-dimensions-offset)))) - -(define-vop (array-rank-vop=>fixnum) - (:translate %array-rank) - (:policy :fast-safe) - (:args (x :scs (descriptor-reg))) - (:results (res :scs (any-reg))) - (:result-types positive-fixnum) - (:generator 2 - (inst mov :dword res (ea (1+ (- other-pointer-lowtag)) x)) - (inst lea :dword res - (let ((scale (ash 1 n-fixnum-tag-bits))) - ;; Compute [res*N-disp]. for N=2 use [res+res-disp] - (ea (- (* scale (1- array-dimensions-offset))) - (if (= scale 2) res nil) res (if (= scale 2) 1 scale)))))) + (inst movzx '(:byte :dword) res (ea rank-disp x)) + (inst inc :byte res))) (define-vop () (:translate %array-rank=) @@ -107,12 +119,92 @@ (:arg-types * (:constant t)) (:conditional :e) (:generator 2 - (inst cmp :dword - (ea (1+ (- other-pointer-lowtag)) array) - (+ rank - (1- array-dimensions-offset))))) + (inst cmp :byte (ea rank-disp array) (encode-array-rank rank)))) + +(define-vop (array-vectorp simple-type-predicate) + ;; SIMPLE-TYPE-PREDICATE says that it takes stack locations, but that's no good. + (:args (array :scs (any-reg descriptor-reg))) + (:translate vectorp) + (:conditional :z) + (:info) + (:guard (lambda (node) + (let ((arg (car (sb-c::combination-args node)))) + (csubtypep (sb-c::lvar-type arg) (specifier-type 'array))))) + (:generator 1 + (inst cmp :byte (ea rank-disp array) (encode-array-rank 1))))) + +(define-vop (simple-array-header-of-rank-p type-predicate) + (:translate sb-c::simple-array-header-of-rank-p) + (:info rank) + (:conditional :e) + (:arg-types * (:constant t)) + (:generator 2 + (let ((c (dpb (encode-array-rank rank) (byte 8 array-rank-position) + simple-array-widetag))) + (cond ((other-pointer-tn-ref-p args) + (inst cmp :word (ea (- other-pointer-lowtag) value) c)) + (t + (%lea-for-lowtag-test temp value other-pointer-lowtag :qword) + (inst test :byte temp lowtag-mask) + (inst jmp :ne OUT) + (inst cmp :word (ea temp) c)))) + OUT)) ;;;; bounds checking routine +(defun emit-bounds-check (vop %test-fixnum array index limit) + (let* ((use-length-p (null limit)) + (error + (if use-length-p + (generate-error-code vop 'sb-kernel::invalid-vector-index-error + array index) + (generate-error-code vop 'invalid-array-index-error array limit + index))) + (bound (if (and (tn-p limit) (sc-is limit immediate)) + (let ((value (tn-value limit))) + (cond ((and %test-fixnum + (power-of-two-limit-p (1- value))) + (lognot (fixnumize (1- value)))) + ((sc-is index any-reg descriptor-reg) + (fixnumize value)) + (t + value))) + limit)) + (index (if (sc-is index immediate) + (let ((value (tn-value index))) + (if (or (null bound) ; from array header + (sc-is bound any-reg descriptor-reg)) + (fixnumize value) + value)) + index))) + (cond ((typep bound '(integer * -1)) + ;; Power of two bound, can be checked for fixnumness at + ;; the same time as it always occupies a consecutive bit + ;; range, everything else, including the tag, has to be + ;; zero. + (inst test index (if (eql bound -1) + index ;; zero? + bound)) + (inst jmp :ne error)) + (t + (when (and %test-fixnum (not (integerp index))) + (%test-fixnum index nil error t)) + (cond (use-length-p + (let ((len (vector-len-ea array))) + (cond ((integerp index) + (inst cmp vector-len-op-size len index) + (inst jmp :be error)) + (t + (inst cmp vector-len-op-size index len) + (inst jmp :nb error))))) + ((integerp bound) + (inst cmp index bound) + (inst jmp :nb error)) + (t + (if (eql index 0) + (inst test bound bound) + (inst cmp bound index)) + (inst jmp :be error))))))) + (define-vop (check-bound) (:translate %check-bound) (:policy :fast-safe) @@ -130,45 +222,8 @@ (:variant t) (:vop-var vop) (:save-p :compute-only) - (:generator 6 - (let ((error (generate-error-code vop 'invalid-array-index-error - array bound index)) - (bound (if (sc-is bound immediate) - (let ((value (tn-value bound))) - (cond ((and %test-fixnum - (power-of-two-limit-p (1- value))) - (lognot (fixnumize (1- value)))) - ((sc-is index any-reg descriptor-reg) - (fixnumize value)) - (t - value))) - bound)) - (index (if (sc-is index immediate) - (let ((value (tn-value index))) - (if (sc-is bound any-reg descriptor-reg) - (fixnumize value) - value)) - index))) - (cond ((typep bound '(integer * -1)) - ;; Power of two bound, can be checked for fixnumness at - ;; the same time as it always occupies a consecutive bit - ;; range, everything else, including the tag, has to be - ;; zero. - (inst test index (if (eql bound -1) - index ;; zero? - bound)) - (inst jmp :ne error)) - (t - (when (and %test-fixnum (not (integerp index))) - (%test-fixnum index nil error t)) - (cond ((integerp bound) - (inst cmp index bound) - (inst jmp :nb error)) - (t - (if (eql index 0) - (inst test bound bound) - (inst cmp bound index)) - (inst jmp :be error)))))))) + (:generator 6 (emit-bounds-check vop %test-fixnum array index bound))) + (define-vop (check-bound/fast check-bound) (:policy :fast) (:variant nil) @@ -190,23 +245,131 @@ (:or unsigned-num signed-num)) (:variant nil) (:variant-cost 5)) + +(define-vop (check-vector-bound) + (:args (array :scs (descriptor-reg)) ; no constant sc allowed + (index :scs (any-reg descriptor-reg) + :load-if (not (and (sc-is index immediate) + (typep (tn-value index) + 'sc-offset))))) + (:variant-vars %test-fixnum) + (:variant t) + (:vop-var vop) + (:save-p :compute-only) + (:generator 5 (emit-bounds-check vop %test-fixnum array index nil))) + +(define-vop (check-vector-bound/fast check-vector-bound) + (:policy :fast) + (:variant nil) + (:variant-cost 3)) + +(define-vop (check-vector-bound/fixnum check-vector-bound) + (:args (array) + (index :scs (any-reg))) + (:arg-types * tagged-num) + (:variant nil) + (:variant-cost 3)) + +(flet ((try-absorb-load (vop replacement) + (let ((prev (sb-c::vop-prev vop))) + ;; If the 2nd arg is the result of VECTOR-LENGTH of the 1st arg, then + ;; don't load the length; instead absorb it into a CMP instruction. + (when (and prev + (eq (vop-name prev) 'slot) + (eq (car (vop-codegen-info prev)) 'sb-c::vector-length) + (eq (tn-ref-tn (vop-args prev)) + (tn-ref-tn (vop-args vop)))) + (let* ((args (vop-args vop)) + (array (tn-ref-tn args)) + (limit (tn-ref-tn (tn-ref-across args))) + (index (tn-ref-tn (tn-ref-across (tn-ref-across args))))) + ;; Don't eliminate VECTOR-LENGTH if it has more than one read ref + (unless (tn-ref-next (sb-c::tn-reads limit)) + (let ((new (sb-c::emit-and-insert-vop + (sb-c::vop-node vop) (vop-block vop) + (template-or-lose replacement) + (sb-c:reference-tn-list (list array index) nil) + nil vop))) + (sb-c::delete-vop prev) + (sb-c::delete-vop vop) + new))))))) + (setf (sb-c::vop-info-optimizer (template-or-lose 'check-bound)) + (lambda (vop) (try-absorb-load vop 'check-vector-bound)) + (sb-c::vop-info-optimizer (template-or-lose 'check-bound/fast)) + (lambda (vop) (try-absorb-load vop 'check-vector-bound/fast)) + (sb-c::vop-info-optimizer (template-or-lose 'check-bound/fixnum)) + (lambda (vop) (try-absorb-load vop 'check-vector-bound/fixnum)))) ;;;; accessors/setters -;;; variants built on top of WORD-INDEX-REF, etc. I.e., those vectors -;;; whose elements are represented in integer registers and are built -;;; out of 8, 16, or 32 bit elements. -(macrolet ((def-full-data-vector-frobs (type element-type &rest scs) - `(progn - (define-full-reffer+offset - ,(symbolicate "DATA-VECTOR-REF-WITH-OFFSET/" type) - ,type vector-data-offset other-pointer-lowtag ,scs - ,element-type data-vector-ref-with-offset) - (define-full-setter+offset - ,(symbolicate "DATA-VECTOR-SET-WITH-OFFSET/" type) - ,type vector-data-offset other-pointer-lowtag ,scs - ,element-type data-vector-set-with-offset)))) - (def-full-data-vector-frobs simple-vector * descriptor-reg any-reg immediate) +;;; Ancestors +(define-vop (dvref) + ;; I don't think we should print these notes even if we could, which we can't. + ;; We do, however, seem to print + ;; "The first argument is a (SIMPLE-ARRAY * (1)), not a SIMPLE-STRING." + ;; for pretty much any general type-unknown AREF. + ;; (:note "inline array access") + (:translate data-vector-ref-with-offset) + (:policy :fast-safe)) +(define-vop (dvset) + ;; (:note "inline array store") + (:translate data-vector-set-with-offset) + (:policy :fast-safe)) + +;;; variants which affect an entire lispword-sized value. +;;; Toplevel macro for ease of viewing the expansion. +(defmacro define-full-setter+addend (name type offset lowtag scs el-type) + `(progn + (define-vop (,name dvset) + (:args (object :scs (descriptor-reg)) + (index :scs (any-reg signed-reg unsigned-reg)) + (value :scs ,scs)) + (:info addend) + (:arg-types ,type tagged-num + (:constant (constant-displacement other-pointer-lowtag + n-word-bytes + vector-data-offset)) + ,el-type) + (:temporary (:sc unsigned-reg) val-temp) + (:vop-var vop) + (:generator 4 + ;; XXX: Is this good - we unpoison first, and then store? It seems wrong. + ,@(unless (eq type 'simple-vector) '((unpoison-element object index addend))) + (let ((ea (ea (- (* (+ ,offset addend) n-word-bytes) ,lowtag) + object index (index-scale n-word-bytes index)))) + ,@(when (eq type 'simple-vector) + '((emit-gc-store-barrier object ea val-temp (vop-nth-arg 2 vop) value))) + (gen-cell-set ea value val-temp)))) + (define-vop (,(symbolicate name "-C") dvset) + (:args (object :scs (descriptor-reg)) + (value :scs ,scs)) + (:info index addend) + (:arg-types ,type + (:constant (load/store-index ,n-word-bytes ,(eval lowtag) + ,(eval offset))) + (:constant (constant-displacement other-pointer-lowtag + n-word-bytes + vector-data-offset)) + ,el-type) + (:temporary (:sc unsigned-reg) val-temp) + (:vop-var vop) + (:generator 3 + ;; XXX: Is this good - we unpoison first, and then store? It seems wrong. + ,@(unless (eq type 'simple-vector) '((unpoison-element object (+ index addend)))) + (let ((ea (ea (- (* (+ ,offset index addend) n-word-bytes) ,lowtag) object))) + ,@(when (eq type 'simple-vector) + '((emit-gc-store-barrier object ea val-temp (vop-nth-arg 1 vop) value))) + (gen-cell-set ea value val-temp)))))) +(defmacro def-full-data-vector-frobs (type element-type &rest scs) + `(progn + (define-full-reffer+addend ,(symbolicate "DATA-VECTOR-REF-WITH-OFFSET/" type) + ,type vector-data-offset other-pointer-lowtag ,scs + ,element-type data-vector-ref-with-offset) + (define-full-setter+addend ,(symbolicate "DATA-VECTOR-SET-WITH-OFFSET/" type) + ,type vector-data-offset other-pointer-lowtag ,scs + ,element-type))) +(progn + (def-full-data-vector-frobs simple-vector * descriptor-reg any-reg immediate constant) (def-full-data-vector-frobs simple-array-unsigned-byte-64 unsigned-num unsigned-reg) (def-full-data-vector-frobs simple-array-fixnum tagged-num any-reg) @@ -217,250 +380,382 @@ (def-full-data-vector-frobs simple-array-unsigned-byte-63 unsigned-num unsigned-reg)) +;;; Try to combine DATA-VECTOR-REF/SIMPLE-VECTOR + IF-EQ. +;;; But never do it under ubsan. +#-ubsan +(defoptimizer (sb-c::vop-optimize data-vector-ref-with-offset/simple-vector) (vop) + (let ((next (vop-next vop))) + (when (and next + (eq (vop-name next) 'if-eq) + ;; Prevent this optimization in safe code + (sb-c::policy (sb-c::vop-node vop) (< safety 3))) + (let* ((result-tn (tn-ref-tn (vop-results vop))) + (next-args (vop-args next)) + (left (tn-ref-tn next-args)) + (right (tn-ref-tn (tn-ref-across next-args))) + (comparand (if (eq result-tn left) right left))) + ;; Since we're only looking at the :Z flag it does not matter + ;; if the array ref is the left or right operand of CMP. + (when (and (sb-c::very-temporary-p result-tn) + (or (eq result-tn left) (eq result-tn right)) + (or (not (constant-tn-p comparand)) + (and (tn-sc comparand) + (plausible-signed-imm32-operand-p + (encode-value-if-immediate comparand))))) + (let* ((new-args (sb-c:reference-tn-list + (list (tn-ref-tn (vop-args vop)) + (tn-ref-tn (tn-ref-across (vop-args vop))) + comparand) + nil)) + (new (sb-c::emit-and-insert-vop + (sb-c::vop-node vop) (vop-block vop) + (template-or-lose 'svref-with-addend+if-eq) + new-args nil vop (vop-codegen-info vop)))) + (sb-c::delete-vop vop) + (sb-c::delete-vop next) + new)))))) + +(define-vop (svref-with-addend+if-eq) + (:args (object :scs (descriptor-reg)) + (index :scs (any-reg signed-reg unsigned-reg)) + (comparand :scs (any-reg descriptor-reg immediate))) + (:info addend) + (:arg-types simple-vector tagged-num * (:constant integer)) + (:conditional :z) + (:generator 1 + (inst cmp :qword + (ea (- (* (+ vector-data-offset addend) n-word-bytes) other-pointer-lowtag) + object index + (index-scale n-word-bytes index)) + (encode-value-if-immediate comparand)))) + (define-vop (data-vector-ref-with-offset/constant-simple-vector) (:policy :fast-safe) (:args (object :scs (constant)) (index :scs (any-reg))) (:temporary (:sc unsigned-reg) array) - (:info offset) + (:info addend) (:arg-types simple-vector tagged-num (:constant fixnum)) (:results (value :scs (descriptor-reg any-reg immediate))) (:result-types *) (:generator 3 (inst lea array object) - (inst mov value (ea (* offset n-word-bytes) array + (inst mov value (ea (* addend n-word-bytes) array index (ash 1 (- word-shift n-fixnum-tag-bits)))))) +;;; TODO: check for uninitialized element if safety = 3 (define-full-compare-and-swap %compare-and-swap-svref simple-vector vector-data-offset other-pointer-lowtag (descriptor-reg any-reg) * %compare-and-swap-svref) -;;;; integer vectors whose elements are smaller than a byte, i.e., -;;;; bit, 2-bit, and 4-bit vectors +;;; SIMPLE-BIT-VECTOR +(defun bit-base (dword-index) + (+ (* dword-index 4) + (- (* vector-data-offset n-word-bytes) other-pointer-lowtag))) -(define-vop (data-vector-ref-with-offset/simple-bit-vector-c) - (:translate data-vector-ref-with-offset) +(defun emit-sbit-op (inst bv index &optional word temp) + (cond ((integerp index) + (multiple-value-bind (dword-index bit) (floor index 32) + (let ((disp (bit-base dword-index))) + (cond ((typep disp '(signed-byte 32)) + (inst* inst :dword (ea disp bv) bit)) + (t ; excessive index, really? + (aver temp) + (inst mov temp index) + (inst* inst (ea (bit-base 0) bv) temp)))))) + (t + ;; mem/reg BT[SR] are really slow. + (inst mov word index) + (inst shr word (integer-length (1- n-word-bits))) + (inst mov temp (ea (bit-base 0) bv word n-word-bytes)) + (if (functionp inst) + (funcall inst) + (inst* inst temp index)) + (inst mov (ea (bit-base 0) bv word n-word-bytes) temp)))) + +(define-vop (data-vector-set-with-offset/simple-bit-vector) + (:translate data-vector-set-with-offset) (:policy :fast-safe) + ;; Arg order is (VECTOR INDEX ADDEND VALUE) + (:arg-types simple-bit-vector positive-fixnum (:constant (eql 0)) positive-fixnum) + (:args (bv :scs (descriptor-reg)) + (index :scs (unsigned-reg)) + (value :scs (immediate any-reg signed-reg unsigned-reg control-stack + signed-stack unsigned-stack))) + (:temporary (:sc unsigned-reg) word temp) + (:info addend) + (:ignore addend) + (:generator 6 + (unpoison-element bv index) + (if (sc-is value immediate) + (ecase (tn-value value) + (1 (emit-sbit-op 'bts bv index word temp)) + (0 (emit-sbit-op 'btr bv index word temp))) + (emit-sbit-op (lambda () + (assemble () + (inst test :byte value + (if (sc-is value control-stack signed-stack unsigned-stack) #xff value)) + (inst jmp :z ZERO) + (inst bts temp index) + (inst jmp OUT) + ZERO + (inst btr temp index) + OUT)) + bv index word temp)))) + +(define-vop (data-vector-set-with-offset/simple-bit-vector/c-index) + (:translate data-vector-set-with-offset) + (:policy :fast-safe) + ;; Arg order is (VECTOR INDEX ADDEND VALUE) + (:arg-types simple-bit-vector (:constant fixnum) (:constant (eql 0)) positive-fixnum) + (:args (bv :scs (descriptor-reg)) + (value :scs (immediate any-reg signed-reg unsigned-reg control-stack + signed-stack unsigned-stack))) + (:info index addend) + (:ignore addend) + (:generator 5 + (unpoison-element bv index) + (when (sc-is value immediate) + (ecase (tn-value value) + (1 (emit-sbit-op 'bts bv index)) + (0 (emit-sbit-op 'btr bv index))) + (return-from data-vector-set-with-offset/simple-bit-vector/c-index)) + (inst test :byte value + (if (sc-is value control-stack signed-stack unsigned-stack) #xff value)) + (inst jmp :z ZERO) + (emit-sbit-op 'bts bv index) + (inst jmp OUT) + ZERO + (emit-sbit-op 'btr bv index) + OUT)) + +(define-vop (data-vector-ref-with-offset/simple-bit-vector-c dvref) (:args (object :scs (descriptor-reg))) (:arg-types simple-bit-vector ;; this constant is possibly off by something ;; but (sbit n <huge-constant>) is unlikely to appear in code (:constant (integer 0 #x3ffffffff)) (:constant (integer 0 0))) - (:info index offset) - (:ignore offset) + (:info index addend) + (:ignore addend) (:results (result :scs (any-reg))) (:result-types positive-fixnum) (:generator 3 ;; using 32-bit operand size might elide the REX prefix on mov + shift (multiple-value-bind (dword-index bit) (floor index 32) - (inst mov :dword result - (ea (+ (* dword-index 4) - (- (* vector-data-offset n-word-bytes) other-pointer-lowtag)) - object)) + (inst mov :dword result (ea (bit-base dword-index) object)) (let ((right-shift (- bit n-fixnum-tag-bits))) (cond ((plusp right-shift) (inst shr :dword result right-shift)) - ((minusp right-shift) ; = left shift + ((minusp right-shift) ; = left shift (inst shl :dword result (- right-shift)))))) (inst and :dword result (fixnumize 1)))) -(define-vop (data-vector-ref-with-offset/simple-bit-vector) - (:translate data-vector-ref-with-offset) - (:policy :fast-safe) +(define-vop (data-vector-ref-with-offset/simple-bit-vector dvref) (:args (object :scs (descriptor-reg)) (index :scs (unsigned-reg))) - (:info offset) - (:ignore offset) + (:info addend) + (:ignore addend) (:arg-types simple-bit-vector positive-fixnum (:constant (integer 0 0))) + (:temporary (:sc unsigned-reg) temp) (:results (result :scs (any-reg))) (:result-types positive-fixnum) + (:vop-var vop) (:generator 4 - (inst bt (ea (- (* vector-data-offset n-word-bytes) other-pointer-lowtag) - object) index) + ;; mem/reg BT is really slow. + (inst mov temp index) + (inst shr temp (integer-length (1- n-word-bits))) + (inst mov temp (ea (bit-base 0) object temp n-word-bytes)) + (inst bt temp index) (inst sbb :dword result result) (inst and :dword result (fixnumize 1)))) +(define-vop (data-vector-ref-with-offset/simple-bit-vector-c-eq) + (:policy :fast-safe) + (:args (object :scs (descriptor-reg))) + (:arg-types simple-bit-vector + (:constant (integer 0 #x3ffffffff)) (:constant (integer 0 0))) + (:info index addend) + (:ignore addend) + (:conditional :eq) + (:generator 3 + (multiple-value-bind (byte-index bit) (floor index 8) + (inst test :byte (ea (+ byte-index + (- (* vector-data-offset n-word-bytes) other-pointer-lowtag)) + object) + (ash 1 bit))))) + +(define-vop (data-vector-ref-with-offset/simple-bit-vector-eq) + (:policy :fast-safe) + (:args (object :scs (descriptor-reg)) + (index :scs (unsigned-reg))) + (:info addend) + (:ignore addend) + (:arg-types simple-bit-vector positive-fixnum (:constant (integer 0 0))) + (:temporary (:sc unsigned-reg) word) + (:conditional :nc) + (:vop-var vop) + (:generator 4 + ;; mem/reg BT is really slow. + (inst mov word index) + (inst shr word (integer-length (1- n-word-bits))) + (inst mov word (ea (bit-base 0) object word n-word-bytes)) + (inst bt word index))) + +;;;; vectors whose elements are 2 or 4 bits each (macrolet ((def-small-data-vector-frobs (type bits) (let* ((elements-per-word (floor n-word-bits bits)) (bit-shift (1- (integer-length elements-per-word)))) - `(progn - ,@(unless (= bits 1) - `((define-vop (,(symbolicate 'data-vector-ref-with-offset/ type)) - (:note "inline array access") - (:translate data-vector-ref-with-offset) - (:policy :fast-safe) - (:args (object :scs (descriptor-reg)) - (index :scs (unsigned-reg))) - (:info offset) - (:arg-types ,type positive-fixnum (:constant (integer 0 0))) - (:results (result :scs (unsigned-reg) :from (:argument 0))) - (:result-types positive-fixnum) - (:temporary (:sc unsigned-reg :offset ecx-offset) ecx) - (:generator 20 - (aver (zerop offset)) - (move ecx index) - (inst shr ecx ,bit-shift) - (inst mov result - (ea (- (* vector-data-offset n-word-bytes) other-pointer-lowtag) - object ecx n-word-bytes)) - (move ecx index) - ;; We used to mask ECX for all values of BITS, but since - ;; Intel's documentation says that the chip will mask shift - ;; and rotate counts by 63 automatically, we can safely move - ;; the masking operation under the protection of this UNLESS - ;; in the bit-vector case. --njf, 2006-07-14 - ,@(unless (= bits 1) - `((inst and ecx ,(1- elements-per-word)) - (inst shl ecx ,(1- (integer-length bits))))) - (inst shr result :cl) - (inst and result ,(1- (ash 1 bits))))) - (define-vop (,(symbolicate 'data-vector-ref-with-offset/ type "-C")) - (:translate data-vector-ref-with-offset) - (:policy :fast-safe) - (:args (object :scs (descriptor-reg))) - (:arg-types ,type (:constant low-index) (:constant (integer 0 0))) - (:info index offset) - (:results (result :scs (unsigned-reg))) - (:result-types positive-fixnum) - (:generator 15 - (aver (zerop offset)) - (multiple-value-bind (word extra) (floor index ,elements-per-word) - (loadw result object (+ word vector-data-offset) - other-pointer-lowtag) - (unless (zerop extra) - (inst shr result (* extra ,bits))) - (unless (= extra ,(1- elements-per-word)) - (inst and result ,(1- (ash 1 bits))))))))) - (define-vop (,(symbolicate 'data-vector-set-with-offset/ type)) - (:note "inline array store") - (:translate data-vector-set-with-offset) - (:policy :fast-safe) - (:args (object :scs (descriptor-reg)) - (index :scs (unsigned-reg) :target ecx) - (value :scs (unsigned-reg immediate) :target result)) - (:info offset) - (:arg-types ,type positive-fixnum (:constant (integer 0 0)) - positive-fixnum) - (:results (result :scs (unsigned-reg))) - (:result-types positive-fixnum) - (:temporary (:sc unsigned-reg) word-index) - (:temporary (:sc unsigned-reg) old) - (:temporary (:sc unsigned-reg :offset ecx-offset) ecx) - (:generator 25 - (aver (zerop offset)) - (move word-index index) - (inst shr word-index ,bit-shift) - (inst mov old - (ea (- (* vector-data-offset n-word-bytes) other-pointer-lowtag) - object word-index n-word-bytes)) - (move ecx index) - ;; We used to mask ECX for all values of BITS, but since - ;; Intel's documentation says that the chip will mask shift - ;; and rotate counts by 63 automatically, we can safely move - ;; the masking operation under the protection of this UNLESS - ;; in the bit-vector case. --njf, 2006-07-14 - ,@(unless (= bits 1) - `((inst and ecx ,(1- elements-per-word)) - (inst shl ecx ,(1- (integer-length bits))))) - (inst ror old :cl) - (unless (and (sc-is value immediate) - (= (tn-value value) ,(1- (ash 1 bits)))) - (inst and old ,(lognot (1- (ash 1 bits))))) - (sc-case value - (immediate - (unless (zerop (tn-value value)) - (inst or old (logand (tn-value value) ,(1- (ash 1 bits)))))) - (unsigned-reg - (inst or old value))) - (inst rol old :cl) - (inst mov (ea (- (* vector-data-offset n-word-bytes) other-pointer-lowtag) - object word-index n-word-bytes) - old) - (sc-case value - (immediate - (inst mov result (tn-value value))) - (unsigned-reg - (move result value))))) - (define-vop (,(symbolicate 'data-vector-set-with-offset/ type "-C")) - (:translate data-vector-set-with-offset) - (:policy :fast-safe) - (:args (object :scs (descriptor-reg)) - (value :scs (unsigned-reg immediate) :target result)) - (:arg-types ,type (:constant low-index) - (:constant (integer 0 0)) positive-fixnum) - (:temporary (:sc unsigned-reg) mask-tn) - (:info index offset) - (:results (result :scs (unsigned-reg))) - (:result-types positive-fixnum) - (:temporary (:sc unsigned-reg :to (:result 0)) old) - (:generator 20 - (aver (zerop offset)) - (multiple-value-bind (word extra) (floor index ,elements-per-word) - (inst mov old - (ea (- (* (+ word vector-data-offset) n-word-bytes) - other-pointer-lowtag) - object)) - (sc-case value - (immediate - (let* ((value (tn-value value)) - (mask ,(1- (ash 1 bits))) - (shift (* extra ,bits))) - (unless (= value mask) - (inst mov mask-tn (ldb (byte 64 0) - (lognot (ash mask shift)))) - (inst and old mask-tn)) - (unless (zerop value) - (inst mov mask-tn (ash value shift)) - (inst or old mask-tn)))) - (unsigned-reg - (let ((shift (* extra ,bits))) - (unless (zerop shift) - (inst ror old shift)) - (inst mov mask-tn (lognot ,(1- (ash 1 bits)))) - (inst and old mask-tn) - (inst or old value) - (unless (zerop shift) - (inst rol old shift))))) - (inst mov (ea (- (* (+ word vector-data-offset) n-word-bytes) - other-pointer-lowtag) - object) - old) - (sc-case value - (immediate - (inst mov result (tn-value value))) - (unsigned-reg - (move result value)))))))))) - (def-small-data-vector-frobs simple-bit-vector 1) + `(progn + (define-vop (,(symbolicate 'data-vector-ref-with-offset/ type) dvref) + (:args (object :scs (descriptor-reg)) + (index :scs (unsigned-reg))) + (:info addend) + (:ignore addend) + (:arg-types ,type positive-fixnum (:constant (integer 0 0))) + (:results (result :scs (unsigned-reg) :from (:argument 0))) + (:result-types positive-fixnum) + (:temporary (:sc unsigned-reg :offset rcx-offset) ecx) + (:generator 20 + (move ecx index) + (inst shr ecx ,bit-shift) + (inst mov result + (ea (- (* vector-data-offset n-word-bytes) other-pointer-lowtag) + object ecx n-word-bytes)) + (move ecx index) + ;; We used to mask ECX for all values of BITS, but since + ;; Intel's documentation says that the chip will mask shift + ;; and rotate counts by 63 automatically, we can safely move + ;; the masking operation under the protection of this UNLESS + ;; in the bit-vector case. --njf, 2006-07-14 + ,@(unless (= bits 1) + `((inst and ecx ,(1- elements-per-word)) + (inst shl ecx ,(1- (integer-length bits))))) + (inst shr result :cl) + (inst and result ,(1- (ash 1 bits))))) + (define-vop (,(symbolicate 'data-vector-ref-with-offset/ type "-C") dvref) + (:args (object :scs (descriptor-reg))) + (:arg-types ,type (:constant low-index) (:constant (integer 0 0))) + (:info index addend) + (:ignore addend) + (:results (result :scs (unsigned-reg))) + (:result-types positive-fixnum) + (:generator 15 + (multiple-value-bind (word extra) (floor index ,elements-per-word) + (loadw result object (+ word vector-data-offset) + other-pointer-lowtag) + (unless (zerop extra) + (inst shr result (* extra ,bits))) + (unless (= extra ,(1- elements-per-word)) + (inst and result ,(1- (ash 1 bits))))))) + (define-vop (,(symbolicate 'data-vector-set-with-offset/ type) dvset) + (:args (object :scs (descriptor-reg)) + (index :scs (unsigned-reg) :target ecx) + (value :scs (unsigned-reg immediate))) + (:info addend) + (:ignore addend) + (:arg-types ,type positive-fixnum (:constant (integer 0 0)) + positive-fixnum) + (:temporary (:sc unsigned-reg) word-index) + (:temporary (:sc unsigned-reg) old) + (:temporary (:sc unsigned-reg :offset rcx-offset) ecx) + (:generator 25 + (unpoison-element object index) + (move word-index index) + (inst shr word-index ,bit-shift) + (inst mov old + (ea (- (* vector-data-offset n-word-bytes) other-pointer-lowtag) + object word-index n-word-bytes)) + (move ecx index) + ;; We used to mask ECX for all values of BITS, but since + ;; Intel's documentation says that the chip will mask shift + ;; and rotate counts by 63 automatically, we can safely move + ;; the masking operation under the protection of this UNLESS + ;; in the bit-vector case. --njf, 2006-07-14 + ,@(unless (= bits 1) + `((inst and ecx ,(1- elements-per-word)) + (inst shl ecx ,(1- (integer-length bits))))) + (inst ror old :cl) + (unless (and (sc-is value immediate) + (= (tn-value value) ,(1- (ash 1 bits)))) + (inst and old ,(lognot (1- (ash 1 bits))))) + (sc-case value + (immediate + (unless (zerop (tn-value value)) + (inst or old (logand (tn-value value) ,(1- (ash 1 bits)))))) + (unsigned-reg + (inst or old value))) + (inst rol old :cl) + (inst mov (ea (- (* vector-data-offset n-word-bytes) other-pointer-lowtag) + object word-index n-word-bytes) + old))) + (define-vop (,(symbolicate 'data-vector-set-with-offset/ type "-C") dvset) + (:args (object :scs (descriptor-reg)) + (value :scs (unsigned-reg immediate))) + (:arg-types ,type (:constant low-index) + (:constant (integer 0 0)) positive-fixnum) + (:temporary (:sc unsigned-reg) mask-tn) + (:info index addend) + (:ignore addend) + (:temporary (:sc unsigned-reg :to (:result 0)) old) + (:generator 20 + (unpoison-element object index) + (multiple-value-bind (word extra) (floor index ,elements-per-word) + (inst mov old + (ea (- (* (+ word vector-data-offset) n-word-bytes) + other-pointer-lowtag) + object)) + (sc-case value + (immediate + (let* ((value (tn-value value)) + (mask ,(1- (ash 1 bits))) + (shift (* extra ,bits))) + (unless (= value mask) + (inst mov mask-tn (ldb (byte 64 0) + (lognot (ash mask shift)))) + (inst and old mask-tn)) + (unless (zerop value) + (inst mov mask-tn (ash value shift)) + (inst or old mask-tn)))) + (unsigned-reg + (let ((shift (* extra ,bits))) + (unless (zerop shift) + (inst ror old shift)) + (inst mov mask-tn (lognot ,(1- (ash 1 bits)))) + (inst and old mask-tn) + (inst or old value) + (unless (zerop shift) + (inst rol old shift))))) + (inst mov (ea (- (* (+ word vector-data-offset) n-word-bytes) + other-pointer-lowtag) + object) + old)))))))) (def-small-data-vector-frobs simple-array-unsigned-byte-2 2) (def-small-data-vector-frobs simple-array-unsigned-byte-4 4)) ;;; And the float variants. -(defun float-ref-ea (object index offset element-size +(defun float-ref-ea (object index addend element-size &key (scale 1) (complex-offset 0)) (etypecase index (integer (ea (- (+ (* vector-data-offset n-word-bytes) - (* (+ index offset) element-size) + (* (+ index addend) element-size) complex-offset) other-pointer-lowtag) object)) (tn (ea (- (+ (* vector-data-offset n-word-bytes) - (* offset element-size) + (* addend element-size) complex-offset) other-pointer-lowtag) object index scale)))) #. (let ((use-temp (<= word-shift n-fixnum-tag-bits))) - `(define-vop (data-vector-ref-with-offset/simple-array-single-float) - (:note "inline array access") - (:translate data-vector-ref-with-offset) - (:policy :fast-safe) + `(define-vop (data-vector-ref-with-offset/simple-array-single-float dvref) (:args (object :scs (descriptor-reg)) (index :scs (any-reg))) - (:info offset) + (:info addend) (:arg-types simple-array-single-float tagged-num (:constant (constant-displacement other-pointer-lowtag 4 vector-data-offset))) @@ -471,270 +766,207 @@ ,@(if use-temp '((move dword-index index) (inst shr dword-index (1+ (- n-fixnum-tag-bits word-shift))) - (inst movss value (float-ref-ea object dword-index offset 4))) - '((inst movss value (float-ref-ea object index offset 4 + (inst movss value (float-ref-ea object dword-index addend 4))) + '((inst movss value (float-ref-ea object index addend 4 :scale (ash 4 (- n-fixnum-tag-bits))))))))) -(define-vop (data-vector-ref-with-offset/simple-array-single-float-c) - (:note "inline array access") - (:translate data-vector-ref-with-offset) - (:policy :fast-safe) +(define-vop (data-vector-ref-with-offset/simple-array-single-float-c dvref) (:args (object :scs (descriptor-reg))) - (:info index offset) + (:info index addend) (:arg-types simple-array-single-float (:constant low-index) (:constant (constant-displacement other-pointer-lowtag 4 vector-data-offset))) (:results (value :scs (single-reg))) (:result-types single-float) (:generator 4 - (inst movss value (float-ref-ea object index offset 4)))) + (inst movss value (float-ref-ea object index addend 4)))) #. (let ((use-temp (<= word-shift n-fixnum-tag-bits))) - `(define-vop (data-vector-set-with-offset/simple-array-single-float) - (:note "inline array store") - (:translate data-vector-set-with-offset) - (:policy :fast-safe) + `(define-vop (data-vector-set-with-offset/simple-array-single-float dvset) (:args (object :scs (descriptor-reg)) (index :scs (any-reg)) - (value :scs (single-reg) :target result)) - (:info offset) + (value :scs (single-reg))) + (:info addend) (:arg-types simple-array-single-float tagged-num (:constant (constant-displacement other-pointer-lowtag 4 vector-data-offset)) single-float) ,@(when use-temp '((:temporary (:sc unsigned-reg) dword-index))) - (:results (result :scs (single-reg))) - (:result-types single-float) (:generator 5 + (unpoison-element object index addend) + ;; NOTE: this can not possibly work with n-fixnum-tag-bits = 3 + ;; because (ash 4 -3) is 0 ,@(if use-temp '((move dword-index index) (inst shr dword-index (1+ (- n-fixnum-tag-bits word-shift))) - (inst movss (float-ref-ea object dword-index offset 4) value)) - '((inst movss (float-ref-ea object index offset 4 - :scale (ash 4 (- n-fixnum-tag-bits))) value))) - (move result value)))) + (inst movss (float-ref-ea object dword-index addend 4) value)) + '((inst movss (float-ref-ea object index addend 4 + :scale (ash 4 (- n-fixnum-tag-bits))) value)))))) -(define-vop (data-vector-set-with-offset/simple-array-single-float-c) - (:note "inline array store") - (:translate data-vector-set-with-offset) - (:policy :fast-safe) +(define-vop (data-vector-set-with-offset/simple-array-single-float-c dvset) (:args (object :scs (descriptor-reg)) - (value :scs (single-reg) :target result)) - (:info index offset) + (value :scs (single-reg))) + (:info index addend) (:arg-types simple-array-single-float (:constant low-index) (:constant (constant-displacement other-pointer-lowtag 4 vector-data-offset)) single-float) - (:results (result :scs (single-reg))) - (:result-types single-float) (:generator 4 - (inst movss (float-ref-ea object index offset 4) value) - (move result value))) + (unpoison-element object (+ index addend)) + (inst movss (float-ref-ea object index addend 4) value))) -(define-vop (data-vector-ref-with-offset/simple-array-double-float) - (:note "inline array access") - (:translate data-vector-ref-with-offset) - (:policy :fast-safe) +(define-vop (data-vector-ref-with-offset/simple-array-double-float dvref) (:args (object :scs (descriptor-reg)) - (index :scs (any-reg))) - (:info offset) + (index :scs (any-reg signed-reg unsigned-reg))) + (:info addend) (:arg-types simple-array-double-float tagged-num (:constant (constant-displacement other-pointer-lowtag 8 vector-data-offset))) (:results (value :scs (double-reg))) (:result-types double-float) (:generator 7 - (inst movsd value (float-ref-ea object index offset 8 - :scale (ash 1 (- word-shift n-fixnum-tag-bits)))))) + (inst movsd value (float-ref-ea object index addend 8 :scale (index-scale 8 index))))) -(define-vop (data-vector-ref-c/simple-array-double-float) - (:note "inline array access") - (:translate data-vector-ref-with-offset) - (:policy :fast-safe) +(define-vop (data-vector-ref-c/simple-array-double-float dvref) (:args (object :scs (descriptor-reg))) - (:info index offset) + (:info index addend) (:arg-types simple-array-double-float (:constant low-index) (:constant (constant-displacement other-pointer-lowtag 8 vector-data-offset))) (:results (value :scs (double-reg))) (:result-types double-float) (:generator 6 - (inst movsd value (float-ref-ea object index offset 8)))) + (inst movsd value (float-ref-ea object index addend 8)))) -(define-vop (data-vector-set-with-offset/simple-array-double-float) - (:note "inline array store") - (:translate data-vector-set-with-offset) - (:policy :fast-safe) +(define-vop (data-vector-set-with-offset/simple-array-double-float dvset) (:args (object :scs (descriptor-reg)) - (index :scs (any-reg)) - (value :scs (double-reg) :target result)) - (:info offset) + (index :scs (any-reg signed-reg unsigned-reg)) + (value :scs (double-reg))) + (:info addend) (:arg-types simple-array-double-float tagged-num (:constant (constant-displacement other-pointer-lowtag 8 vector-data-offset)) double-float) - (:results (result :scs (double-reg))) - (:result-types double-float) (:generator 20 - (inst movsd (float-ref-ea object index offset 8 - :scale (ash 1 (- word-shift n-fixnum-tag-bits))) - value) - (move result value))) + (unpoison-element object index addend) + (inst movsd (float-ref-ea object index addend 8 :scale (index-scale 8 index)) value))) -(define-vop (data-vector-set-with-offset/simple-array-double-float-c) - (:note "inline array store") - (:translate data-vector-set-with-offset) - (:policy :fast-safe) +(define-vop (data-vector-set-with-offset/simple-array-double-float-c dvset) (:args (object :scs (descriptor-reg)) - (value :scs (double-reg) :target result)) - (:info index offset) + (value :scs (double-reg))) + (:info index addend) (:arg-types simple-array-double-float (:constant low-index) (:constant (constant-displacement other-pointer-lowtag 8 vector-data-offset)) double-float) - (:results (result :scs (double-reg))) - (:result-types double-float) (:generator 19 - (inst movsd (float-ref-ea object index offset 8) value) - (move result value))) - + (unpoison-element object (+ index addend)) + (inst movsd (float-ref-ea object index addend 8) value))) ;;; complex float variants -(define-vop (data-vector-ref-with-offset/simple-array-complex-single-float) - (:note "inline array access") - (:translate data-vector-ref-with-offset) - (:policy :fast-safe) +(define-vop (data-vector-ref-with-offset/simple-array-complex-single-float dvref) (:args (object :scs (descriptor-reg)) (index :scs (any-reg))) - (:info offset) + (:info addend) (:arg-types simple-array-complex-single-float tagged-num (:constant (constant-displacement other-pointer-lowtag 8 vector-data-offset))) (:results (value :scs (complex-single-reg))) (:result-types complex-single-float) (:generator 5 - (inst movq value (float-ref-ea object index offset 8 + (inst movq value (float-ref-ea object index addend 8 :scale (ash 1 (- word-shift n-fixnum-tag-bits)))))) -(define-vop (data-vector-ref-with-offset/simple-array-complex-single-float-c) - (:note "inline array access") - (:translate data-vector-ref-with-offset) - (:policy :fast-safe) +(define-vop (data-vector-ref-with-offset/simple-array-complex-single-float-c dvref) (:args (object :scs (descriptor-reg))) - (:info index offset) + (:info index addend) (:arg-types simple-array-complex-single-float (:constant low-index) (:constant (constant-displacement other-pointer-lowtag 8 vector-data-offset))) (:results (value :scs (complex-single-reg))) (:result-types complex-single-float) (:generator 4 - (inst movq value (float-ref-ea object index offset 8)))) + (inst movq value (float-ref-ea object index addend 8)))) -(define-vop (data-vector-set-with-offset/simple-array-complex-single-float) - (:note "inline array store") - (:translate data-vector-set-with-offset) - (:policy :fast-safe) +(define-vop (data-vector-set-with-offset/simple-array-complex-single-float dvset) (:args (object :scs (descriptor-reg)) (index :scs (any-reg)) - (value :scs (complex-single-reg) :target result)) - (:info offset) + (value :scs (complex-single-reg))) + (:info addend) (:arg-types simple-array-complex-single-float tagged-num (:constant (constant-displacement other-pointer-lowtag 8 vector-data-offset)) complex-single-float) - (:results (result :scs (complex-single-reg))) - (:result-types complex-single-float) (:generator 5 - (move result value) - (inst movq (float-ref-ea object index offset 8 + (unpoison-element object index addend) + (inst movq (float-ref-ea object index addend 8 :scale (ash 1 (- word-shift n-fixnum-tag-bits))) value))) -(define-vop (data-vector-set-with-offset/simple-array-complex-single-float-c) - (:note "inline array store") - (:translate data-vector-set-with-offset) - (:policy :fast-safe) +(define-vop (data-vector-set-with-offset/simple-array-complex-single-float-c dvset) (:args (object :scs (descriptor-reg)) - (value :scs (complex-single-reg) :target result)) - (:info index offset) + (value :scs (complex-single-reg))) + (:info index addend) (:arg-types simple-array-complex-single-float (:constant low-index) (:constant (constant-displacement other-pointer-lowtag 8 vector-data-offset)) complex-single-float) - (:results (result :scs (complex-single-reg))) - (:result-types complex-single-float) (:generator 4 - (move result value) - (inst movq (float-ref-ea object index offset 8) value))) + (unpoison-element object (+ index addend)) + (inst movq (float-ref-ea object index addend 8) value))) -(define-vop (data-vector-ref-with-offset/simple-array-complex-double-float) - (:note "inline array access") - (:translate data-vector-ref-with-offset) - (:policy :fast-safe) +(define-vop (data-vector-ref-with-offset/simple-array-complex-double-float dvref) (:args (object :scs (descriptor-reg)) (index :scs (any-reg))) - (:info offset) + (:info addend) (:arg-types simple-array-complex-double-float tagged-num (:constant (constant-displacement other-pointer-lowtag 16 vector-data-offset))) (:results (value :scs (complex-double-reg))) (:result-types complex-double-float) (:generator 7 - (inst movapd value (float-ref-ea object index offset 16 + (inst movapd value (float-ref-ea object index addend 16 :scale (ash 2 (- word-shift n-fixnum-tag-bits)))))) -(define-vop (data-vector-ref-with-offset/simple-array-complex-double-float-c) - (:note "inline array access") - (:translate data-vector-ref-with-offset) - (:policy :fast-safe) +(define-vop (data-vector-ref-with-offset/simple-array-complex-double-float-c dvref) (:args (object :scs (descriptor-reg))) - (:info index offset) + (:info index addend) (:arg-types simple-array-complex-double-float (:constant low-index) (:constant (constant-displacement other-pointer-lowtag 16 vector-data-offset))) (:results (value :scs (complex-double-reg))) (:result-types complex-double-float) (:generator 6 - (inst movapd value (float-ref-ea object index offset 16)))) + (inst movapd value (float-ref-ea object index addend 16)))) -(define-vop (data-vector-set-with-offset/simple-array-complex-double-float) - (:note "inline array store") - (:translate data-vector-set-with-offset) - (:policy :fast-safe) +(define-vop (data-vector-set-with-offset/simple-array-complex-double-float dvset) (:args (object :scs (descriptor-reg)) (index :scs (any-reg)) - (value :scs (complex-double-reg) :target result)) - (:info offset) + (value :scs (complex-double-reg))) + (:info addend) (:arg-types simple-array-complex-double-float tagged-num (:constant (constant-displacement other-pointer-lowtag 16 vector-data-offset)) complex-double-float) - (:results (result :scs (complex-double-reg))) - (:result-types complex-double-float) (:generator 20 - (inst movapd (float-ref-ea object index offset 16 + (unpoison-element object index addend) + (inst movapd (float-ref-ea object index addend 16 :scale (ash 2 (- word-shift n-fixnum-tag-bits))) - value) - (move result value))) + value))) -(define-vop (data-vector-set-with-offset/simple-array-complex-double-float-c) - (:note "inline array store") - (:translate data-vector-set-with-offset) - (:policy :fast-safe) +(define-vop (data-vector-set-with-offset/simple-array-complex-double-float-c dvset) (:args (object :scs (descriptor-reg)) - (value :scs (complex-double-reg) :target result)) - (:info index offset) + (value :scs (complex-double-reg))) + (:info index addend) (:arg-types simple-array-complex-double-float (:constant low-index) (:constant (constant-displacement other-pointer-lowtag 16 vector-data-offset)) complex-double-float) - (:results (result :scs (complex-double-reg))) - (:result-types complex-double-float) (:generator 19 - (inst movapd (float-ref-ea object index offset 16) value) - (move result value))) + (unpoison-element object (+ index addend)) + (inst movapd (float-ref-ea object index addend 16) value))) @@ -743,75 +975,64 @@ type &rest scs) (binding* ((opcode-modifier (if (eq mov-inst 'mov) operand-size - `(,operand-size :qword))) + `(,operand-size ,(if (eq mov-inst 'movzx) :dword :qword)))) (n-bytes (the (member 1 2 4) (size-nbyte operand-size))) - ((index-sc scale) + ((index-scs scale) (if (>= n-bytes (ash 1 n-fixnum-tag-bits)) - (values 'any-reg (ash n-bytes (- n-fixnum-tag-bits))) - (values 'signed-reg n-bytes))) + (values '(any-reg signed-reg unsigned-reg) `(index-scale ,n-bytes index)) + (values '(signed-reg unsigned-reg) n-bytes))) (ea-expr `(ea (+ (* vector-data-offset n-word-bytes) - (* offset ,n-bytes) + (* addend ,n-bytes) (- other-pointer-lowtag)) object index ,scale)) (ea-expr-const `(ea (+ (* vector-data-offset n-word-bytes) - (* ,n-bytes (+ index offset)) + (* ,n-bytes (+ index addend)) (- other-pointer-lowtag)) object))) `(progn - (define-vop (,(symbolicate "DATA-VECTOR-REF-WITH-OFFSET/" ptype)) - (:translate data-vector-ref-with-offset) - (:policy :fast-safe) + (define-vop (,(symbolicate "DATA-VECTOR-REF-WITH-OFFSET/" ptype) dvref) (:args (object :scs (descriptor-reg)) - (index :scs (,index-sc))) - (:info offset) + (index :scs ,index-scs)) + (:info addend) (:arg-types ,ptype tagged-num (:constant (constant-displacement other-pointer-lowtag ,n-bytes vector-data-offset))) (:results (value :scs ,scs)) (:result-types ,type) (:generator 5 (inst ,mov-inst ',opcode-modifier value ,ea-expr))) - (define-vop (,(symbolicate "DATA-VECTOR-REF-WITH-OFFSET/" ptype "-C")) - (:translate data-vector-ref-with-offset) - (:policy :fast-safe) + (define-vop (,(symbolicate "DATA-VECTOR-REF-WITH-OFFSET/" ptype "-C") dvref) (:args (object :scs (descriptor-reg))) - (:info index offset) + (:info index addend) (:arg-types ,ptype (:constant low-index) (:constant (constant-displacement other-pointer-lowtag ,n-bytes vector-data-offset))) (:results (value :scs ,scs)) (:result-types ,type) (:generator 4 (inst ,mov-inst ',opcode-modifier value ,ea-expr-const))) - (define-vop (,(symbolicate "DATA-VECTOR-SET-WITH-OFFSET/" ptype)) - (:translate data-vector-set-with-offset) - (:policy :fast-safe) + ;; FIXME: these all need to accept immediate SC for the value + (define-vop (,(symbolicate "DATA-VECTOR-SET-WITH-OFFSET/" ptype) dvset) (:args (object :scs (descriptor-reg) :to (:eval 0)) - (index :scs (,index-sc) :to (:eval 0)) - (value :scs ,scs :target result)) - (:info offset) + (index :scs ,index-scs :to (:eval 0)) + (value :scs ,scs)) + (:info addend) (:arg-types ,ptype tagged-num (:constant (constant-displacement other-pointer-lowtag ,n-bytes vector-data-offset)) ,type) - (:results (result :scs ,scs)) - (:result-types ,type) (:generator 5 - (inst mov ,operand-size ,ea-expr value) - (move result value))) - (define-vop (,(symbolicate "DATA-VECTOR-SET-WITH-OFFSET/" ptype "-C")) - (:translate data-vector-set-with-offset) - (:policy :fast-safe) + (unpoison-element object index addend) + (inst mov ,operand-size ,ea-expr value))) + (define-vop (,(symbolicate "DATA-VECTOR-SET-WITH-OFFSET/" ptype "-C") dvset) (:args (object :scs (descriptor-reg) :to (:eval 0)) - (value :scs ,scs :target result)) - (:info index offset) + (value :scs ,scs)) + (:info index addend) (:arg-types ,ptype (:constant low-index) (:constant (constant-displacement other-pointer-lowtag ,n-bytes vector-data-offset)) ,type) - (:results (result :scs ,scs)) - (:result-types ,type) (:generator 4 - (inst mov ,operand-size ,ea-expr-const value) - (move result value))))))) + (unpoison-element object (+ index addend)) + (inst mov ,operand-size ,ea-expr-const value))))))) (define-data-vector-frobs simple-array-unsigned-byte-7 movzx :byte positive-fixnum unsigned-reg signed-reg) (define-data-vector-frobs simple-array-unsigned-byte-8 movzx :byte @@ -826,14 +1047,14 @@ positive-fixnum unsigned-reg signed-reg) (define-data-vector-frobs simple-array-signed-byte-16 movsx :word tagged-num signed-reg) - (define-data-vector-frobs simple-array-unsigned-byte-32 movzx :dword + (define-data-vector-frobs simple-array-unsigned-byte-32 mov :dword positive-fixnum unsigned-reg signed-reg) - (define-data-vector-frobs simple-array-unsigned-byte-31 movzx :dword + (define-data-vector-frobs simple-array-unsigned-byte-31 mov :dword positive-fixnum unsigned-reg signed-reg) (define-data-vector-frobs simple-array-signed-byte-32 movsx :dword tagged-num signed-reg) #+sb-unicode - (define-data-vector-frobs simple-character-string movzx :dword + (define-data-vector-frobs simple-character-string mov :dword character character-reg)) @@ -856,7 +1077,8 @@ (:results (result :scs (unsigned-reg))) (:result-types unsigned-num) (:generator 4 - (inst xadd (ea (- (* vector-data-offset n-word-bytes) other-pointer-lowtag) - array index (ash 1 (- word-shift n-fixnum-tag-bits))) - diff :lock) + (inst xadd :lock + (ea (- (* vector-data-offset n-word-bytes) other-pointer-lowtag) + array index (ash 1 (- word-shift n-fixnum-tag-bits))) + diff) (move result diff))) diff --git a/src/compiler/x86-64/avx2-insts.lisp b/src/compiler/x86-64/avx2-insts.lisp index 0a050acb32..c60762bd0f 100644 --- a/src/compiler/x86-64/avx2-insts.lisp +++ b/src/compiler/x86-64/avx2-insts.lisp @@ -1,16 +1,5 @@ (in-package "SB-X86-64-ASM") -(defun get-avx2 (number) - (svref (load-time-value - (coerce (loop for i from 0 below 16 - collect (!make-reg (!make-avx2-id i))) - 'vector) - t) - number)) - -(defun is-avx2-id-p (reg-id) - (= (ldb (byte 3 0) reg-id) 3)) - (define-arg-type ymmreg :prefilter #'prefilter-reg-r :printer #'print-ymmreg) @@ -228,12 +217,12 @@ 0 1)) (xmm-size (r) - (cond ((is-avx2-id-p (reg-id r)) + (cond ((is-ymm-id-p (reg-id r)) 1) ((xmm-register-p r) 0)))) (let ((l (cond (l) - (reg + ((xmm-register-p reg) (xmm-size reg)) ((xmm-register-p thing) (xmm-size thing)) @@ -581,6 +570,31 @@ (def vpmovzxwq #x66 #x34 #x0f38) (def vpmovzxdq #x66 #x35 #x0f38)) +(macrolet ((def (name prefix) + `(define-instruction ,name (segment dst src pattern) + ,@(avx2-inst-printer-list + 'ymm-ymm/mem-imm prefix #x70 + :printer '(:name :tab reg ", " reg/mem ", " imm)) + (:emitter + (emit-avx2-inst segment dst src ,prefix #x70 + :remaining-bytes 1) + (emit-byte segment pattern))))) + (def vpshufd #x66) + (def vpshufhw #xf3) + (def vpshuflw #xf2)) + +(macrolet ((def (name prefix) + `(define-instruction ,name (segment dst src src2 pattern) + ,@(avx2-inst-printer-list + 'ymm-ymm/mem-imm prefix #xc6) + (:emitter + (emit-avx2-inst segment src2 dst ,prefix #xc6 + :vvvv src + :remaining-bytes 1) + (emit-byte segment pattern))))) + (def vshufpd #x66) + (def vshufps nil)) + (macrolet ((def (name prefix opcode) `(define-instruction ,name (segment dst src src2 imm) @@ -739,14 +753,12 @@ (:emitter (cond ((and (xmm-register-p dst) (ea-p src)) - (emit-avx2-inst segment dst src ,prefix #x10 :l 0)) + (emit-avx2-inst segment src dst ,prefix #x10 :l 0)) ((xmm-register-p dst) - (emit-avx2-inst segment dst src2 ,prefix #x10 :vvvv src - :l 0)) + (emit-avx2-inst segment src2 dst ,prefix #x10 :vvvv src :l 0)) (t (aver (xmm-register-p src)) - (emit-avx2-inst segment src dst ,prefix #x11 - :l 0))))))) + (emit-avx2-inst segment dst src ,prefix #x11 :l 0))))))) (def vmovsd #xf2) (def vmovss #xf3)) @@ -895,13 +907,13 @@ (define-instruction vzeroupper (segment) (:printer vex2-op ((op #x77) (l 0) (r 1) (pp 0))) (:emitter - (emit-two-byte-vex segment 0 #b1111 0 nil) + (emit-two-byte-vex segment 0 0 0 nil) (emit-byte segment #x77))) (define-instruction vzeroall (segment) (:printer vex2-op ((op #x77) (l 1) (r 1) (pp 0))) (:emitter - (emit-two-byte-vex segment 0 #b1111 1 nil) + (emit-two-byte-vex segment 0 0 1 nil) (emit-byte segment #x77))) (macrolet ((def (name opcode &optional l (mem-size :qword)) @@ -983,18 +995,21 @@ :remaining-bytes 1) (emit-byte segment imm))))) (def vpermpd #x66 #x01) - (def vpermpq #x66 #x00)) + (def vpermq #x66 #x00)) -(define-instruction vpermps (segment dst src src2) - (:emitter - (emit-avx2-inst segment src2 dst #x66 #x16 - :opcode-prefix #x0f38 - :vvvv src - :w 0 :l 1)) - . #.(avx2-inst-printer-list 'ymm-ymm/mem #x66 #x16 - :w 0 :l 1 - :nds t - :opcode-prefix #x0f38)) +(macrolet ((def (name op) + `(define-instruction ,name (segment dst src src2) + ,@(avx2-inst-printer-list 'ymm-ymm/mem #x66 op + :w 0 :l 1 + :nds t + :opcode-prefix #x0f38) + (:emitter + (emit-avx2-inst segment src2 dst #x66 ,op + :opcode-prefix #x0f38 + :vvvv src + :w 0 :l 1))))) + (def vpermps #x16) + (def vpermd #x36)) (macrolet ((def (name op op-imm) `(define-instruction ,name (segment dst src src2/imm) @@ -1096,11 +1111,11 @@ :w ,w :l ,(ecase sizing ((xmm/ymm-vmx/y xmm/ymm-vmx) - `(if (is-avx2-id-p (reg-id dst)) + `(if (is-ymm-id-p (reg-id dst)) 1 0)) (xmm-vmx/y - `(if (eq (sc-name (tn-sc (ea-index vm))) 'avx2-reg) + `(if (eq (sc-name (tn-sc (ea-index vm))) 'ymm-reg) 1 0))) :vm t))))) @@ -1204,3 +1219,21 @@ :w 0 :opcode-prefix #x0f3a :printer '(:name :tab reg/mem ", " reg ", " imm))) + +(define-instruction xsave (segment dst) + (:printer ext-reg/mem-no-width ((op '(#xae 4)))) + (:emitter + (aver (not (register-p dst))) + (emit-prefixes segment dst nil :do-not-set) + (emit-byte segment #x0F) + (emit-byte segment #xAE) + (emit-ea segment dst 4))) + +(define-instruction xrstor (segment dst) + (:printer ext-reg/mem-no-width ((op '(#xae 5)))) + (:emitter + (aver (not (register-p dst))) + (emit-prefixes segment dst nil :do-not-set) + (emit-byte segment #x0F) + (emit-byte segment #xAE) + (emit-ea segment dst 5))) diff --git a/src/compiler/x86-64/c-call.lisp b/src/compiler/x86-64/c-call.lisp index 2c73d50800..18f17dd69f 100644 --- a/src/compiler/x86-64/c-call.lisp +++ b/src/compiler/x86-64/c-call.lisp @@ -73,8 +73,8 @@ (defun result-reg-offset (slot) (ecase slot - (0 eax-offset) - (1 edx-offset))) + (0 rax-offset) + (1 rdx-offset))) (define-alien-type-method (integer :result-tn) (type state) (let ((num-results (result-state-num-results state))) @@ -124,7 +124,7 @@ (collect ((arg-tns)) (dolist (arg-type (alien-fun-type-arg-types type)) (arg-tns (invoke-alien-type-method :arg-tn arg-type arg-state))) - (values (make-wired-tn* 'positive-fixnum any-reg-sc-number esp-offset) + (values (make-wired-tn* 'positive-fixnum any-reg-sc-number rsp-offset) (* (arg-state-stack-frame-size arg-state) n-word-bytes) (arg-tns) (invoke-alien-type-method :result-tn @@ -133,8 +133,8 @@ (deftransform %alien-funcall ((function type &rest args) * * :node node) - (aver (sb-c::constant-lvar-p type)) - (let* ((type (sb-c::lvar-value type)) + (aver (sb-c:constant-lvar-p type)) + (let* ((type (sb-c:lvar-value type)) (env (sb-c::node-lexenv node)) (arg-types (alien-fun-type-arg-types type)) (result-type (alien-fun-type-result-type type))) @@ -200,6 +200,10 @@ (defknown sign-extend ((signed-byte 64) t) fixnum (foldable flushable movable)) +(defoptimizer (sign-extend derive-type) ((x size)) + (when (sb-c:constant-lvar-p size) + (specifier-type `(signed-byte ,(sb-c:lvar-value size))))) + (define-vop (sign-extend) (:translate sign-extend) (:policy :fast-safe) @@ -219,6 +223,9 @@ (16 (sign-extend x size)) (32 (sign-extend x size)))) +;;; Note that if jumping _to_ the linkage entry, the jump is to the JMP instruction +;;; at entry + 0, but if jumping _via_ the linkage index, we can jump to [entry+8] +;;; which holds the ultimate address to jump to. (define-vop (foreign-symbol-sap) (:translate foreign-symbol-sap) (:policy :fast-safe) @@ -227,8 +234,16 @@ (:info foreign-symbol) (:results (res :scs (sap-reg))) (:result-types system-area-pointer) + (:vop-var vop) (:generator 2 - (inst mov res (make-fixup foreign-symbol :foreign)))) + #-immobile-space ; non-relocatable alien linkage table + (inst mov res (make-fixup foreign-symbol :foreign)) + #+immobile-space ; relocatable alien linkage table + (cond ((sb-c::code-immobile-p vop) + (inst lea res (rip-relative-ea (make-fixup foreign-symbol :foreign)))) + (t + (inst mov res (thread-slot-ea thread-alien-linkage-table-base-slot)) + (inst lea res (ea (make-fixup foreign-symbol :alien-code-linkage-index) res)))))) (define-vop (foreign-symbol-dataref-sap) (:translate foreign-symbol-dataref-sap) @@ -238,14 +253,28 @@ (:info foreign-symbol) (:results (res :scs (sap-reg))) (:result-types system-area-pointer) + (:vop-var vop) (:generator 2 - (inst mov res (ea (make-fixup foreign-symbol :foreign-dataref))))) + #-immobile-space ; non-relocatable alien linkage table + (inst mov res (ea (make-fixup foreign-symbol :foreign-dataref))) + #+immobile-space ; relocatable alien linkage table + (cond ((sb-c::code-immobile-p vop) + (inst mov res (rip-relative-ea (make-fixup foreign-symbol :foreign-dataref)))) + (t + (inst mov res (thread-slot-ea thread-alien-linkage-table-base-slot)) + (inst mov res (ea (make-fixup foreign-symbol :alien-data-linkage-index) res)))))) #+sb-safepoint -(defconstant thread-saved-csp-offset -1) +(defconstant thread-saved-csp-offset (- (1+ sb-vm::thread-header-slots))) (eval-when (#-sb-xc :compile-toplevel :load-toplevel :execute) (defun destroyed-c-registers () + ;; Safepoints do not save interrupt contexts to be scanned during + ;; GCing, it only looks at the stack, so if a register isn't + ;; spilled it won't be visible to the GC. + #+sb-safepoint + '((:save-p t)) + #-sb-safepoint (let ((gprs (list rcx-offset rdx-offset #-win32 rsi-offset #-win32 rdi-offset r8-offset r9-offset r10-offset r11-offset)) @@ -270,13 +299,17 @@ (:temporary (:sc unsigned-reg :offset rax-offset :to :result) rax) #+sb-safepoint (:temporary (:sc unsigned-stack :from :eval :to :result) pc-save) + #+win32 + (:temporary (:sc unsigned-reg :offset r15-offset :from :eval :to :result) r15) (:ignore results) (:vop-var vop) (:generator 0 (move rbx function) (emit-c-call vop rax rbx args sb-alien::*alien-fun-type-varargs-default* - #+sb-safepoint pc-save)) + #+sb-safepoint pc-save + #+win32 rbx)) + #+win32 (:ignore r15) . #.(destroyed-c-registers)) ;;; Calls to C can generally be made without loading a register @@ -288,18 +321,36 @@ (:temporary (:sc unsigned-reg :offset rax-offset :to :result) rax) #+sb-safepoint (:temporary (:sc unsigned-stack :from :eval :to :result) pc-save) + #+win32 + (:temporary (:sc unsigned-reg :offset r15-offset :from :eval :to :result) r15) + #+win32 + (:ignore r15) + #+win32 + (:temporary (:sc unsigned-reg :offset rbx-offset :from :eval :to :result) rbx) (:ignore results) (:vop-var vop) (:generator 0 - (emit-c-call vop rax c-symbol args varargsp #+sb-safepoint pc-save)) + (emit-c-call vop rax c-symbol args varargsp + #+sb-safepoint pc-save + #+win32 rbx)) . #.(destroyed-c-registers)) -(defun emit-c-call (vop rax fun args varargsp #+sb-safepoint pc-save) +#+win32 +(defconstant win64-seh-direct-thunk-addr win64-seh-data-addr) +#+win32 +(defconstant win64-seh-indirect-thunk-addr (+ win64-seh-data-addr 8)) + +(defun emit-c-call (vop rax fun args varargsp #+sb-safepoint pc-save #+win32 rbx) (declare (ignorable varargsp)) ;; Current PC - don't rely on function to keep it in a form that ;; GC understands #+sb-safepoint (let ((label (gen-label))) + ;; This looks unnecessary. GC can look at the stack word physically below + ;; the CSP-around-foreign-call, which must be a PC pointing into the lisp caller. + ;; A more interesting question would arise if we had callee-saved registers + ;; within lisp code, which we don't at the moment. If we did, those + ;; wouldn't be anywhere on the stack unless C code decides to save them. (inst lea rax (rip-relative-ea label)) (emit-label label) (move pc-save rax)) @@ -316,30 +367,61 @@ ;; for vararg calls. (when varargsp (move-immediate rax - (loop for tn-ref = args then (tn-ref-across tn-ref) - while tn-ref - count (eq (sb-name (sc-sb (tn-sc (tn-ref-tn tn-ref)))) - 'float-registers)))) + (loop for tn-ref = args then (tn-ref-across tn-ref) + while tn-ref + count (eq (sb-name (sc-sb (tn-sc (tn-ref-tn tn-ref)))) + 'float-registers)))) + + ;; Store SP in thread struct, unless the enclosing block says not to #+sb-safepoint - ;; Store SP in thread struct - (storew rsp-tn thread-base-tn thread-saved-csp-offset) + (when (policy (sb-c::vop-node vop) (/= sb-c:insert-safepoints 0)) + (inst mov (thread-slot-ea thread-saved-csp-offset) rsp-tn)) + #+win32 (inst sub rsp-tn #x20) ;MS_ABI: shadow zone + ;; From immobile space we use the "CALL rel32" format to the linkage ;; table jump, and from dynamic space we use "CALL [ea]" format ;; where ea is the address of the linkage table entry's operand. ;; So while the former is a jump to a jump, we can optimize out - ;; one jump in a statically linked executable. + ;; one jump in an ELF executable. + ;; N.B.: if you change how the call is emitted, you will also have to adjust + ;; the UNDEFINED-ALIEN-TRAMP lisp asm routine to recognize the various shapes + ;; this instruction sequence can take. + #-win32 + (inst call (if (tn-p fun) + fun + #-immobile-space (ea (make-fixup fun :foreign 8)) + #+immobile-space + (cond ((sb-c::code-immobile-p vop) (make-fixup fun :foreign)) + (t + ;; Pick r10 as the lowest unused clobberable register. + ;; RAX has a designated purpose, and RBX is nonvolatile (not always + ;; spilled by Lisp because a C function has to save it if used) + (inst mov r10-tn (thread-slot-ea thread-alien-linkage-table-base-slot)) + (ea (make-fixup fun :alien-code-linkage-index 8) r10-tn))))) + + ;; On win64, we don't support immobile space (yet) and calls go through one of + ;; the thunks defined in set_up_win64_seh_data(). If the linkage table is + ;; involved, RBX either points to a linkage table trampoline or to the linkage + ;; table operand; this simplifies UNDEFINED-ALIEN-TRAMP's job. + #+win32 + (cond ((tn-p fun) + (move rbx fun) + (inst mov rax win64-seh-direct-thunk-addr) + (inst call rax)) + (t + (inst mov rbx (make-fixup fun :foreign 8)) + (inst mov rax win64-seh-indirect-thunk-addr) + (inst call rax))) - (inst call (cond ((tn-p fun) fun) - ((sb-c::code-immobile-p vop) (make-fixup fun :foreign)) - (t (ea (make-fixup fun :foreign 8))))) ;; For the undefined alien error (note-this-location vop :internal-error) #+win32 (inst add rsp-tn #x20) ;MS_ABI: remove shadow space + + ;; Zero the saved CSP, unless this code shouldn't ever stop for GC #+sb-safepoint - ;; Zero the saved CSP - (inst xor (object-slot-ea thread-base-tn thread-saved-csp-offset 0) - rsp-tn)) + (when (policy (sb-c::vop-node vop) (/= sb-c:insert-safepoints 0)) + (inst xor (thread-slot-ea thread-saved-csp-offset) rsp-tn))) (define-vop (alloc-number-stack-space) (:info amount) @@ -368,17 +450,6 @@ (inst sub :qword (alien-stack-ptr) delta))) (inst mov result (alien-stack-ptr))))) -;;; not strictly part of the c-call convention, but needed for the -;;; WITH-PINNED-OBJECTS macro used for "locking down" lisp objects so -;;; that GC won't move them while foreign functions go to work. -(define-vop (touch-object) - (:translate touch-object) - (:args (object)) - (:ignore object) - (:policy :fast-safe) - (:arg-types t) - (:generator 0)) - ;;; Callbacks #-sb-xc-host @@ -435,7 +506,7 @@ ;; stack location to a temporary register. (unless gpr (incf stack-argument-count) - (setf gpr temp-reg-tn) + (setf gpr rax) (inst mov gpr stack-arg-tn)) ;; Copy from either argument register or temporary ;; register to target. @@ -452,8 +523,8 @@ ;; temporary (general purpose) register, and ;; from there to the target location. (incf stack-argument-count) - (inst mov temp-reg-tn stack-arg-tn) - (inst mov target-tn temp-reg-tn))))) + (inst mov rax stack-arg-tn) + (inst mov target-tn rax))))) (t (bug "Unknown alien floating point type: ~S" type))))) @@ -500,8 +571,11 @@ #+win32 (inst sub rsp #x20) #+win32 (inst and rsp #x-20) ;; Call - (inst mov rax (foreign-symbol-address "callback_wrapper_trampoline")) - (inst call rax) + #+immobile-space (inst call (static-symbol-value-ea 'callback-wrapper-trampoline)) + ;; do this without MAKE-FIXUP because fixup'ing does not happen when + ;; assembling callbacks (probably could, but ...) + #-immobile-space + (inst call (ea (+ (foreign-symbol-address "callback_wrapper_trampoline") 8))) ;; Back! Restore frame (inst mov rsp rbp) (inst pop rbp)) diff --git a/src/compiler/x86-64/call.lisp b/src/compiler/x86-64/call.lisp index 892294ece3..48498d4078 100644 --- a/src/compiler/x86-64/call.lisp +++ b/src/compiler/x86-64/call.lisp @@ -14,29 +14,9 @@ (defconstant arg-count-sc (make-sc+offset any-reg-sc-number rcx-offset)) (defconstant closure-sc (make-sc+offset any-reg-sc-number rax-offset)) -;;; Make a passing location TN for a local call return PC. -;;; -;;; Always wire the return PC location to the stack in its standard -;;; location. -(defun make-return-pc-passing-location (standard) - (declare (ignore standard)) - (make-wired-tn (primitive-type-or-lose 'system-area-pointer) - sap-stack-sc-number return-pc-save-offset)) - (defconstant return-pc-passing-offset (make-sc+offset sap-stack-sc-number return-pc-save-offset)) -;;; This is similar to MAKE-RETURN-PC-PASSING-LOCATION, but makes a -;;; location to pass OLD-FP in. -;;; -;;; This is wired in both the standard and the local-call conventions, -;;; because we want to be able to assume it's always there. Besides, -;;; the x86 doesn't have enough registers to really make it profitable -;;; to pass it in a register. -(defun make-old-fp-passing-location () - (make-wired-tn *fixnum-primitive-type* control-stack-sc-number - ocfp-save-offset)) - (defconstant old-fp-passing-offset (make-sc+offset control-stack-sc-number ocfp-save-offset)) @@ -46,16 +26,17 @@ ;;; ;;; Without using a save-tn - which does not make much sense if it is ;;; wired to the stack? -(defun make-old-fp-save-location (physenv) - (physenv-debug-live-tn (make-wired-tn *fixnum-primitive-type* - control-stack-sc-number - ocfp-save-offset) - physenv)) -(defun make-return-pc-save-location (physenv) - (physenv-debug-live-tn - (make-wired-tn (primitive-type-or-lose 'system-area-pointer) - sap-stack-sc-number return-pc-save-offset) - physenv)) +(defun make-old-fp-save-location () + (let ((tn (make-wired-tn *fixnum-primitive-type* + control-stack-sc-number + ocfp-save-offset))) + (setf (tn-kind tn) :environment) + tn)) +(defun make-return-pc-save-location () + (let ((tn (make-wired-tn (primitive-type-or-lose 'system-area-pointer) + sap-stack-sc-number return-pc-save-offset))) + (setf (tn-kind tn) :environment) + tn)) ;;; Make a TN for the standard argument count passing location. We only ;;; need to make the standard location, since a count is never passed when we @@ -258,7 +239,7 @@ ;;; there are stack values. ;;; -- Reset SP. This must be done whenever other than 1 value is ;;; returned, regardless of the number of values desired. -(defun default-unknown-values (vop values nvals node) +(defun default-unknown-values (vop values nvals node rbx move-temp) (declare (type (or tn-ref null) values) (type unsigned-byte nvals)) (let ((type (sb-c::basic-combination-derived-type node))) @@ -267,17 +248,11 @@ (note-this-location vop :single-value-return) (cond ((<= (sb-kernel:values-type-max-value-count type) - register-arg-count) - (when (and (named-type-p type) - (eq nil (named-type-name type))) - ;; The function never returns, it may happen that the code - ;; ends right here leavig the :SINGLE-VALUE-RETURN note - ;; dangling. Let's emit a NOP. - (inst nop))) + register-arg-count)) ((not (sb-kernel:values-type-may-be-single-value-p type)) - (inst mov rsp-tn rbx-tn)) + (inst mov rsp-tn rbx)) (t - (inst cmov :c rsp-tn rbx-tn)))) + (inst cmov :c rsp-tn rbx)))) ((<= nvals register-arg-count) (note-this-location vop :unknown-return) (when (sb-kernel:values-type-may-be-single-value-p type) @@ -298,11 +273,11 @@ do (inst mov :dword (tn-ref-tn tn-ref) (if 2nd-tn-live 2nd-tn nil-value))))) - (inst mov rbx-tn rsp-tn) + (inst mov rbx rsp-tn) (emit-label regs-defaulted))) (when (< register-arg-count (sb-kernel:values-type-max-value-count type)) - (inst mov rsp-tn rbx-tn))) + (inst mov rsp-tn rbx))) (t (collect ((defaults)) (let ((default-stack-slots (gen-label)) @@ -327,7 +302,7 @@ (loop for null = nil-value then (car used-registers) for reg in used-registers do (inst mov :dword reg null)) - (move rbx-tn rsp-tn) + (move rbx rsp-tn) (inst jmp defaulting-done))) REGS-DEFAULTED (do ((i register-arg-count (1+ i)) @@ -343,12 +318,12 @@ (inst jmp :be default-lab) (sc-case tn (control-stack - (loadw r11-tn rbx-tn (frame-word-offset (+ sp->fp-offset i))) - (inst mov tn r11-tn)) + (loadw move-temp rbx (frame-word-offset (+ sp->fp-offset i))) + (inst mov tn move-temp)) (t - (loadw tn rbx-tn (frame-word-offset (+ sp->fp-offset i))))))))) + (loadw tn rbx (frame-word-offset (+ sp->fp-offset i))))))))) DEFAULTING-DONE - (move rsp-tn rbx-tn) + (move rsp-tn rbx) (let ((defaults (defaults))) (when defaults (assemble (:elsewhere) @@ -356,7 +331,7 @@ (loop for null = nil-value then (car used-registers) for reg in used-registers do (inst mov :dword reg null)) - (move rbx-tn rsp-tn) + (move rbx rsp-tn) (dolist (default defaults) (emit-label (car default)) (inst mov (cdr default) nil-value)) @@ -473,7 +448,7 @@ (emit-label trampoline-label) (popw rbp-tn (frame-word-offset return-pc-save-offset))) (when alignp - (emit-alignment n-lowtag-bits :long-nop)) + (emit-alignment n-lowtag-bits alignp)) (emit-label start-label)) ;;; Non-TR local call for a fixed number of values passed according to @@ -506,11 +481,12 @@ (:vop-var vop) (:ignore nfp arg-locs args callee) (:node-var node) + (:temporary (:sc any-reg) move-temp) (:generator 5 (move rbp-tn fp) (note-this-location vop :call-site) (inst call target) - (default-unknown-values vop values nvals node))) + (default-unknown-values vop values nvals node rbx-tn move-temp))) ;;; Non-TR local call for a variable number of return values passed according ;;; to the unknown values convention. The results are the start of the values @@ -613,7 +589,7 @@ ;;; In tail call with fixed arguments, the passing locations are ;;; passed as a more arg, but there is no new-FP, since the arguments ;;; have been set up in the current frame. -(macrolet ((define-full-call (vop-name named return variable) +(macrolet ((define-full-call (vop-name named return variable &optional args) (aver (not (and variable (eq return :tail)))) #+immobile-code (when named (setq named :direct)) `(define-vop (,vop-name ,@(when (eq return :unknown) @@ -634,7 +610,9 @@ '((old-fp) (return-pc))) - ,@(unless variable '((args :more t :scs (descriptor-reg))))) + ,@(unless variable + `((args :more t ,@(unless (eq args :fixed) + '(:scs (descriptor-reg))))))) ,@(when (eq return :fixed) '((:results (values :more t)))) @@ -642,7 +620,9 @@ (:save-p ,(if (eq return :tail) :compute-only t)) ,@(unless (or (eq return :tail) variable) - '((:move-args :full-call))) + `((:move-args ,(if (eq args :fixed) + :fixed + :full-call)))) (:vop-var vop) (:node-var node) @@ -660,8 +640,7 @@ (:ignore ,@(unless (or variable (eq return :tail)) '(arg-locs)) - ,@(unless variable '(args)) - ,@(and (eq return :fixed) '(rbx))) + ,@(unless variable '(args))) ;; We pass either the fdefn object (for named call) or ;; the actual function object (for unnamed call) in @@ -682,7 +661,8 @@ ,@(when (eq return :fixed) ;; Save it for DEFAULT-UNKNOWN-VALUES to work `((:temporary (:sc unsigned-reg :offset rbx-offset - :from :result) rbx))) + :from :result) rbx) + (:temporary (:sc any-reg) move-temp))) ;; With variable call, we have to load the ;; register-args out of the (new) stack frame before @@ -738,9 +718,11 @@ for index downfrom -1 do (noise `(loadw ,name new-fp ,index))) (noise)) - '((if (zerop nargs) - (zeroize rcx) - (inst mov rcx (fixnumize nargs))))) + '((cond ((listp nargs)) ;; no-verify-arg-count + ((zerop nargs) + (zeroize rcx)) + (t + (inst mov rcx (fixnumize nargs)))))) ,@(cond ((eq return :tail) '(;; Python has figured out what frame we should ;; return to so might as well use that clue. @@ -817,41 +799,21 @@ DONE (note-this-location vop :call-site) ,(cond ((eq named :direct) - #+immobile-code - `(let* ((fixup (make-fixup - fun - (if (static-fdefn-offset fun) - :static-call - :named-call))) - (target - (if (and (sb-c::code-immobile-p node) - (not step-instrumenting)) - fixup - (progn - ;; RAX-TN was not declared as a temp var, - ;; however it's sole purpose at this point is - ;; for function call, so even if it was used - ;; to compute a stack argument, it's free now. - ;; If the call hits the undefined fun trap, - ;; RAX will get loaded regardless. - (inst mov rax-tn fixup) - rax-tn)))) - (inst ,(if (eq return :tail) 'jmp 'call) target)) - #-immobile-code - `(inst ,(if (eq return :tail) 'jmp 'call) - (ea (+ nil-value (static-fun-offset fun))))) + #+immobile-code `(emit-direct-call fun ',(if (eq return :tail) 'jmp 'call) + node step-instrumenting) + #-immobile-code `(inst ,(if (eq return :tail) 'jmp 'call) + (ea (+ nil-value (static-fun-offset fun))))) #-immobile-code (named `(inst ,(if (eq return :tail) 'jmp 'call) - (ea (- (* fdefn-raw-addr-slot n-word-bytes) - other-pointer-lowtag) rax))) + (object-slot-ea rax fdefn-raw-addr-slot other-pointer-lowtag))) ((eq return :tail) `(tail-call-unnamed rax fun-type vop)) (t `(call-unnamed rax fun-type vop))) ,@(ecase return (:fixed - '((default-unknown-values vop values nvals node))) + '((default-unknown-values vop values nvals node rbx move-temp))) (:unknown '((note-this-location vop :unknown-return) (receive-unknown-values values-start nvals start count @@ -872,7 +834,32 @@ (define-full-call static-tail-call-named :direct :tail nil) (define-full-call call-variable nil :fixed t) - (define-full-call multiple-call-variable nil :unknown t)) + (define-full-call multiple-call-variable nil :unknown t) + (define-full-call fixed-call-named t :fixed nil :fixed) + (define-full-call fixed-tail-call-named t :tail nil :fixed)) + +;;; Call NAME "directly" meaning in a single JMP or CALL instruction, +;;; if possible (without loading RAX) +(defun emit-direct-call (name instruction node step-instrumenting) + ;; a :STATIC-CALL fixup is the address of the entry point of + ;; the function itself, and a :FDEFN-CALL fixup is the address + ;; of the JMP instruction embedded in the header for the named FDEFN. + (let* ((fixup (make-fixup name + (if (static-fdefn-offset name) :static-call :fdefn-call))) + (target + (if (and (sb-c::code-immobile-p node) + (not step-instrumenting)) + fixup + (progn + ;; RAX-TN was not declared as a temp var, + ;; however it's sole purpose at this point is + ;; for function call, so even if it was used + ;; to compute a stack argument, it's free now. + ;; If the call hits the undefined fun trap, + ;; RAX will get loaded regardless. + (inst mov rax-tn fixup) + rax-tn)))) + (inst* instruction target))) ;;; Invoke the function-designator FUN. (defun tail-call-unnamed (fun type vop) @@ -1272,54 +1259,85 @@ done)) ;;; Turn more arg (context, count) into a list. +;;; Cons cells will be filled in right-to-left. +;;; This has a slight advantage in code size, and eliminates an initial +;;; forward jump into the loop. it also admits an interesting possibility +;;; to reduce the scope of the pseudo-atomic section so as not to +;;; encompass construction of the list. To do that, we will need to invent +;;; a new widetag for "contiguous CONS block" which has a header conveying +;;; the total payload length. Initially we would store that into the CAR of the +;;; first cons cell. Upon seeing such header, GC shall treat that entire object +;;; as a boxed payload of specified length. It will be implicitly pinned +;;; (if conservative) or transported as a whole (if precise). Then when the CAR +;;; of the first cons is overwritten, the object changes to a linked list. (define-vop () (:translate %listify-rest-args) (:policy :safe) - (:args (context :scs (descriptor-reg) :target src) + ;; CONTEXT is used throughout the copying loop + (:args (context :scs (descriptor-reg) :to :save) (count :scs (any-reg) :target rcx)) (:arg-types * tagged-num) - (:temporary (:sc unsigned-reg :offset rsi-offset :from (:argument 0)) src) + ;; The only advantage to specifying RCX here is that JRCXZ can be used + ;; in one place, and then only in the unlikely scenario that CONTEXT is not + ;; in RCX. If it was, SHL sets/clears the Z flag, but LEA doesn't. + ;; Not much of an advantage, but why not. (:temporary (:sc unsigned-reg :offset rcx-offset :from (:argument 1)) rcx) - (:temporary (:sc unsigned-reg :offset rax-offset) rax) - (:temporary (:sc unsigned-reg) dst) + ;; Note that DST conflicts with RESULT because we use both as temps + (:temporary (:sc unsigned-reg) value dst) + #+gs-seg (:temporary (:sc unsigned-reg :offset 15) thread-tn) (:results (result :scs (descriptor-reg))) (:node-var node) (:generator 20 - (let ((enter (gen-label)) - (loop (gen-label)) + (let ((loop (gen-label)) (done (gen-label)) + (leave-pa (gen-label)) (stack-allocate-p (node-stack-allocate-p node))) - (move src context) - (move rcx count) - ;; Check to see whether there are no args, and just return NIL if so. + ;; Compute the number of bytes to allocate + (let ((shift (- (1+ word-shift) n-fixnum-tag-bits))) + (if (location= count rcx) + (inst shl :dword rcx shift) + (inst lea :dword rcx (ea nil count (ash 1 shift))))) + ;; Setup for the CDR of the last cons (or the entire result) being NIL. (inst mov result nil-value) - (inst test rcx rcx) - (inst jmp :z done) - (inst lea dst (ea nil rcx (ash 2 (- word-shift n-fixnum-tag-bits)))) + (inst jrcxz DONE) (unless stack-allocate-p - (instrument-alloc dst node)) - (pseudo-atomic (:elide-if stack-allocate-p) - (allocation 'list dst list-pointer-lowtag node stack-allocate-p dst) - ;; Set up the result. - (move result dst) - ;; Jump into the middle of the loop, 'cause that's where we want - ;; to start. - (inst jmp enter) - (emit-label loop) - ;; Compute a pointer to the next cons. - (inst add dst (* cons-size n-word-bytes)) - ;; Store a pointer to this cons in the CDR of the previous cons. - (storew dst dst -1 list-pointer-lowtag) - (emit-label enter) - ;; Grab one value and stash it in the car of this cons. - (inst mov rax (ea src)) - (inst sub src n-word-bytes) - (storew rax dst 0 list-pointer-lowtag) - ;; Go back for more. - (inst sub rcx (fixnumize 1)) + (instrument-alloc +cons-primtype+ rcx node (list value dst) thread-tn)) + (pseudo-atomic (:elide-if stack-allocate-p :thread-tn thread-tn) + ;; Produce an untagged pointer into DST + (if stack-allocate-p + (stack-allocation rcx 0 dst) + (allocation +cons-primtype+ rcx 0 dst node value thread-tn + :overflow + (lambda () + (inst push rcx) + (inst push context) + (invoke-asm-routine + 'call (if (system-tlab-p node) 'sys-listify-&rest 'listify-&rest) + node) + (inst pop result) + (inst jmp leave-pa)))) + ;; Recalculate DST as a tagged pointer to the last cons + (inst lea dst (ea (- list-pointer-lowtag (* cons-size n-word-bytes)) dst rcx)) + (inst shr :dword rcx (1+ word-shift)) ; convert bytes to number of cells + ;; The rightmost arguments are at lower addresses. + ;; Start by indexing the last argument + (inst neg rcx) ; :QWORD because it's a signed number + (emit-label LOOP) + ;; Grab one value and store into this cons. Use RCX as an index into the + ;; vector of values in CONTEXT, but add 8 because CONTEXT points exactly at + ;; the 0th value, which means that the index is 1 word too low. + ;; (It's -1 if there is exactly 1 value, instead of 0, and so on) + (inst mov value (ea 8 context rcx 8)) + ;; RESULT began as NIL which gives the correct value for the CDR in the final cons. + ;; Subsequently it points to each cons just populated, which is correct all the way + ;; up to and including the final result. + (storew result dst cons-cdr-slot list-pointer-lowtag) + (storew value dst cons-car-slot list-pointer-lowtag) + (inst mov result dst) ; preserve the value to put in the CDR of the preceding cons + (inst sub dst (* cons-size n-word-bytes)) ; get the preceding cons + (inst inc rcx) ; :QWORD because it's a signed number (inst jmp :nz loop) - ;; NIL out the last cons. - (storew nil-value dst 1 list-pointer-lowtag)) + (emit-label leave-pa)) (emit-label done)))) ;;; Return the location and size of the &MORE arg glob created by @@ -1356,6 +1374,7 @@ (:policy :fast-safe) (:args (nargs :scs (any-reg))) (:arg-types positive-fixnum (:constant t) (:constant t)) + (:temporary (:sc unsigned-reg :offset rbx-offset) temp) (:info min max) (:vop-var vop) (:save-p :compute-only) @@ -1363,24 +1382,24 @@ ;; NOTE: copy-more-arg expects this to issue a CMP for min > 1 (let ((err-lab (generate-error-code vop 'invalid-arg-count-error nargs))) - (flet ((check-min () - (cond ((= min 1) - (inst test nargs nargs) - (inst jmp :e err-lab)) - ((plusp min) - (inst cmp nargs (fixnumize min)) - (inst jmp :b err-lab))))) - (cond ((not min) - (if (zerop max) - (inst test nargs nargs) - (inst cmp nargs (fixnumize max))) - (inst jmp :ne err-lab)) - (max - (check-min) - (inst cmp nargs (fixnumize max)) - (inst jmp :a err-lab)) - (t - (check-min))))))) + (cond ((not min) + (if (zerop max) + (inst test nargs nargs) + (inst cmp nargs (fixnumize max))) + (inst jmp :ne err-lab)) + (max + (if (zerop min) + (setf temp nargs) + (inst lea temp (ea (fixnumize (- min)) nargs))) + (inst cmp temp (fixnumize (- max min))) + (inst jmp :a err-lab)) + (t + (cond ((= min 1) + (inst test nargs nargs) + (inst jmp :e err-lab)) + ((plusp min) + (inst cmp nargs (fixnumize min)) + (inst jmp :b err-lab)))))))) ;; Signal an error about an untagged number. ;; These are pretty much boilerplate and could be generic except: diff --git a/src/compiler/x86-64/cell.lisp b/src/compiler/x86-64/cell.lisp index 19369c7e8b..ddb143eee6 100644 --- a/src/compiler/x86-64/cell.lisp +++ b/src/compiler/x86-64/cell.lisp @@ -13,13 +13,22 @@ ;;;; data object ref/set stuff +(defconstant vector-len-op-size #+ubsan :dword #-ubsan :qword) +(defmacro vector-len-ea (v &optional (lowtag sb-vm:other-pointer-lowtag)) + #+ubsan `(ea (- 4 ,lowtag) ,v) ; high 4 bytes of header + #-ubsan `(ea (- (ash vector-length-slot word-shift) ,lowtag) ,v)) + (define-vop (slot) (:args (object :scs (descriptor-reg))) (:info name offset lowtag) - (:ignore name) + #-ubsan (:ignore name) (:results (result :scs (descriptor-reg any-reg))) (:generator 1 - (loadw result object offset lowtag))) + (cond #+ubsan + ((member name '(sb-c::vector-length %array-fill-pointer)) ; half-sized slot + (inst mov :dword result (vector-len-ea object))) + (t + (loadw result object offset lowtag))))) ;; This vop is selected by name from vm-ir2tran for converting any ;; setter or setf'er that is defined by 'objdef' @@ -29,89 +38,154 @@ (:info name offset lowtag) (:results) (:vop-var vop) + (:node-var node) + (:args-var args) + (:temporary (:sc unsigned-reg) val-temp) (:generator 1 - (cond ((emit-code-page-write-barrier-p name) - ;; Don't assume that the immediate is acceptable to 'push' - ;; (only MOV can take a 64-bit immediate) - (inst mov temp-reg-tn (encode-value-if-immediate value)) - (inst push temp-reg-tn) - ;; Push the slot index into code, then code itself - (cond ((= lowtag fun-pointer-lowtag) - ;; compute code address similarly to CODE-FROM-FUNCTION vop - (inst mov :dword temp-reg-tn (ea (- fun-pointer-lowtag) object)) - (inst shr :dword temp-reg-tn n-widetag-bits) - ;; now temp-reg-tn holds the difference in words from code to fun. - (inst push temp-reg-tn) - (inst add :qword (ea 0 rsp-tn) offset) ; for particular slot - ;; finish computing the code address - (inst neg temp-reg-tn) - (inst lea temp-reg-tn - (ea (- other-pointer-lowtag fun-pointer-lowtag) - object temp-reg-tn n-word-bytes)) - (inst push temp-reg-tn)) - (t ; is code already - (inst push offset) - (inst push object))) - (invoke-asm-routine 'call 'code-header-set vop)) - ((equal name '(setf %funcallable-instance-fun)) - (gen-cell-set (object-slot-ea object offset lowtag) value nil vop t)) - (t - (gen-cell-set (object-slot-ea object offset lowtag) value nil))))) - -;; INIT-SLOT has to know about the :COMPACT-INSTANCE-HEADER feature. -(define-vop (init-slot set-slot) - (:info name dx-p offset lowtag) - (:generator 1 - (progn name dx-p) - (cond #+compact-instance-header - ((and (eq name '%make-structure-instance) (eql offset :layout)) - ;; The layout is in the upper half of the header word. - (inst mov :dword (ea (- 4 instance-pointer-lowtag) object) - (if (sc-is value immediate) - (make-fixup (tn-value value) :layout) - value))) - ((sc-is value immediate) - (move-immediate (ea (- (* offset n-word-bytes) lowtag) object) - (encode-value-if-immediate value) - temp-reg-tn (not dx-p))) + (cond #+ubsan + ((and (eql offset sb-vm:array-fill-pointer-slot) ; half-sized slot + (or (eq name 'make-array) + (equal name '(setf %array-fill-pointer)))) + (when (eq name 'make-array) ; nullify the creating PC location + (inst mov :qword (object-slot-ea object 1 lowtag) nil-value)) + (inst mov :dword (vector-len-ea object) + (or (encode-value-if-immediate value) value))) (t - (storew value object offset lowtag))))) ; Else, value not immediate. + (let* ((value-tn (tn-ref-tn (tn-ref-across args))) + (prim-type (sb-c::tn-primitive-type value-tn)) + (scs (and prim-type + (sb-c::primitive-type-scs prim-type)))) + (unless (and + ;; Can this TN be boxed after the allocator? + (or (singleton-p scs) + (not (member descriptor-reg-sc-number scs))) + (or + ;; gencgc does not need to emit the barrier for constructors + (eq name :allocator) + (sb-c::set-slot-old-p node))) + (emit-gc-store-barrier object nil val-temp (vop-nth-arg 1 vop) value))) + (gen-cell-set (object-slot-ea object offset lowtag) value val-temp))))) (define-vop (compare-and-swap-slot) (:args (object :scs (descriptor-reg) :to :eval) - (old :scs (descriptor-reg any-reg) :target rax) + (old :scs (descriptor-reg any-reg) #|:target rax|#) (new :scs (descriptor-reg any-reg))) + ;; if OLD were LOCATION= to RAX then we'd clobber OLD + ;; while computing the EA for the barrier. (:temporary (:sc descriptor-reg :offset rax-offset - :from (:argument 1) :to :result :target result) + #|:from (:argument 1)|# :to :result :target result) rax) (:info name offset lowtag) (:ignore name) (:results (result :scs (descriptor-reg any-reg))) + (:vop-var vop) (:generator 5 + (emit-gc-store-barrier object nil rax (vop-nth-arg 2 vop) new) (move rax old) - (inst cmpxchg (ea (- (* offset n-word-bytes) lowtag) object) - new :lock) + (inst cmpxchg :lock (ea (- (* offset n-word-bytes) lowtag) object) new) (move result rax))) ;;;; symbol hacking VOPs +(define-vop (make-unbound-marker) + (:args) + (:results (result :scs (descriptor-reg any-reg))) + (:generator 1 + (inst mov result (unbound-marker-bits)))) + +(defmacro emit-symbol-write-barrier (sym &rest rest) + ;; IMMEDIATE sc means that the symbol is static or immobile. + ;; Static symbols are roots, and immobile symbols use page fault handling. + `(unless (sc-is ,sym immediate) (emit-gc-store-barrier ,sym ,@rest))) + (define-vop (%set-symbol-global-value) - (:args (object :scs (descriptor-reg immediate)) + (:args (symbol :scs (descriptor-reg immediate)) (value :scs (descriptor-reg any-reg immediate))) (:policy :fast-safe) + (:temporary (:sc unsigned-reg) val-temp) + (:vop-var vop) (:generator 4 - (gen-cell-set (cond ((sc-is object immediate) - (symbol-slot-ea (tn-value object) symbol-value-slot)) - (t - (object-slot-ea object symbol-value-slot - other-pointer-lowtag))) - value nil))) + (emit-symbol-write-barrier symbol nil val-temp (vop-nth-arg 1 vop) value) + (gen-cell-set (if (sc-is symbol immediate) + (symbol-slot-ea (tn-value symbol) symbol-value-slot) + (object-slot-ea symbol symbol-value-slot other-pointer-lowtag)) + value val-temp))) + +;;; This does not resolve the TLS-INDEX at load-time, because we don't want to +;;; waste TLS indices for symbols that may never get thread-locally bound. +;;; So instead we make a fixup to the address of the 4-byte TLS field in the symbol. +(defun symbol-tls-index-ea (symbol) + (ea (make-fixup (tn-value symbol) :immobile-symbol (- 4 other-pointer-lowtag)))) + +(defun get-symbol-value-slot-ea (ea-tn symbol) + (if (sc-is symbol immediate) + (inst mov ea-tn (make-fixup (tn-value symbol) :immobile-symbol + (- (ash symbol-value-slot word-shift) other-pointer-lowtag))) + (inst lea ea-tn (object-slot-ea symbol symbol-value-slot other-pointer-lowtag)))) + +;;; As implemented for x86-64, SET performs at most one conditional branch and no +;;; unconditional jump, contrasting with the other common approach of branching around +;;; a store to either the TLS or the global value, followed by an unconditional jump +;;; out, and in the middle doing the opposite of whichever store was jumped over. +;;; (see the arm64, ppc64, and riscv implementations) +;;; I would surmise that one unconditional branch is preferable. +;;; Slightly in favor of that claim is that if you run this through a C compiler: +;;; void f1(long val, int test, long *a, long *b) { +;;; if (test) *a = val; else *b = val; +;;; } +;;; it generates the same code as if you had written "*(test?a:b) = val;" +;;; So while that's not 100% analagous to this situation here, it does imply +;;; slight favoritism for branch-free code. It might be possible to use CMOV +;;; if we don't need to emit the GC barrier such as when storing a fixnum. +;;; On the other hand, Torvalds has ranted against writing branchless code +;;; for its own sake (https://yarchive.net/comp/linux/cmov.html) +;;; +;;; FIXME: quite likely this vop should exist in several variants, for a known +;;; symbol, variable symbol, etc. As it stands, we can see that a symbol is +;;; always-thread-local only if immobile-space is in use, wherein the symbol's SC +;;; is immediate. +#+sb-thread +(define-vop (set) + (:args (symbol :scs (descriptor-reg immediate)) + (value :scs (descriptor-reg any-reg immediate))) + (:temporary (:sc unsigned-reg) val-temp cell) + #+gs-seg (:temporary (:sc unsigned-reg) thread-temp) + (:vop-var vop) + (:generator 4 + (if (and (sc-is symbol immediate) + (eq (info :variable :wired-tls (tn-value symbol)) :always-thread-local)) + ;; We never need the GC barrier for TLS. I think it would be preferable + ;; to resolve this in IR1, maybe turning it into SET-TLS-VALUE. + (gen-cell-set (ea (make-fixup (tn-value symbol) :symbol-tls-index) thread-tn) + value val-temp) + (let ((store (gen-label))) + (cond ((and (sc-is symbol immediate) + (info :variable :wired-tls (tn-value symbol))) + ;; The TLS index is arbitrary but known to be nonzero, + ;; so we can resolve the displacement of the thread-local value + ;; at load-time, saving one instruction over the general case. + (inst lea cell (ea (make-fixup (tn-value symbol) :symbol-tls-index) + thread-tn))) + (t + ;; These MOVs look the same, but when the symbol is immediate, this is + ;; a load from an absolute address. Needless to say, the names of these + ;; accessor macros are arbitrary - the difference is not very apparent. + (inst mov :dword cell (if (sc-is symbol immediate) + (symbol-tls-index-ea symbol) + (tls-index-of symbol))) + (inst add cell thread-tn))) + (inst cmp :qword (ea cell) no-tls-value-marker) + (inst jmp :ne STORE) + (emit-symbol-write-barrier symbol nil val-temp (vop-nth-arg 1 vop) value) + (get-symbol-value-slot-ea cell symbol) + (emit-label STORE) + (gen-cell-set (ea cell) value val-temp))))) (define-vop (fast-symbol-global-value) (:args (object :scs (descriptor-reg immediate))) (:results (value :scs (descriptor-reg any-reg))) (:policy :fast) - (:translate sym-global-val) + (:translate symbol-global-value) (:generator 4 (cond ((sc-is object immediate) (inst mov value (symbol-slot-ea (tn-value object) symbol-value-slot))) @@ -120,7 +194,7 @@ (define-vop (symbol-global-value) (:policy :fast-safe) - (:translate sym-global-val) + (:translate symbol-global-value) (:args (object :scs (descriptor-reg) :to (:result 1))) (:results (value :scs (descriptor-reg any-reg))) (:vop-var vop) @@ -128,10 +202,10 @@ (:generator 9 (let ((err-lab (generate-error-code vop 'unbound-symbol-error object))) (loadw value object symbol-value-slot other-pointer-lowtag) - (inst cmp :dword value unbound-marker-widetag) + (inst cmp :byte value unbound-marker-widetag) (inst jmp :e err-lab)))) -;; Return the DISP field to use in an EA relative to thread-base-tn +;; Return the DISP field to use in an EA relative to thread-base (defun load-time-tls-offset (symbol) (let ((where (info :variable :wired-tls symbol))) (cond ((integerp where) where) @@ -139,43 +213,53 @@ (deftransform %compare-and-swap-symbol-value ((symbol old new) ((constant-arg symbol) t t)) - (if (eq (info :variable :kind (sb-c::lvar-value symbol)) :global) + (if (eq (info :variable :kind (sb-c:lvar-value symbol)) :global) `(%cas-symbol-global-value symbol old new) (sb-c::give-up-ir1-transform))) -(macrolet (;; Logic common to thread-aware SET and CAS. CELL is assigned - ;; to the location that should be accessed to modify SYMBOL's - ;; value either in the TLS or the symbol's value slot as follows: - ;; (1) make it look as if the TLS cell were a symbol by biasing - ;; upward by other-pointer-lowtag less 1 word. - ;; (2) conditionally make CELL point to the symbol itself - (compute-virtual-symbol () - `(progn - (inst mov :dword cell (tls-index-of symbol)) - (inst lea cell - (ea (- other-pointer-lowtag (ash symbol-value-slot word-shift)) - thread-base-tn cell)) - (inst cmp :dword (symbol-value-slot-ea cell) ; TLS reference - no-tls-value-marker-widetag) - (inst cmov :e cell symbol))) ; now possibly get the symbol - (access-wired-tls-val (sym) ; SYM is a symbol +(macrolet ((access-wired-tls-val (sym) ; SYM is a symbol `(thread-tls-ea (load-time-tls-offset ,sym))) (symbol-value-slot-ea (sym) ; SYM is a TN `(ea (- (* symbol-value-slot n-word-bytes) other-pointer-lowtag) - ,sym))) + ,sym)) + (load-oldval () + `(if (sc-is old immediate) + (inst mov rax (encode-value-if-immediate old)) + (move rax old)))) - (define-vop (%compare-and-swap-symbol-value) +(define-vop (%cas-symbol-global-value) + (:translate %cas-symbol-global-value) + (:args (symbol :scs (descriptor-reg immediate) :to (:result 0)) + (old :scs (descriptor-reg any-reg constant immediate)) + (new :scs (descriptor-reg any-reg))) + ;; RAX is the temp for computing the card mark, so it has to conflict + ;; with OLD and therefore the default lifetime spec is fine + (:temporary (:sc descriptor-reg :offset rax-offset :to (:result 0)) rax) + (:results (result :scs (descriptor-reg any-reg))) + (:policy :fast-safe) + (:vop-var vop) + (:generator 10 + (emit-symbol-write-barrier symbol nil rax (vop-nth-arg 2 vop) new) + (load-oldval) + (inst cmpxchg :lock (if (sc-is symbol immediate) + (symbol-slot-ea (tn-value symbol) symbol-value-slot) + (symbol-value-slot-ea symbol)) + new) + (move result rax))) + +(define-vop (%compare-and-swap-symbol-value) (:translate %compare-and-swap-symbol-value) - (:args (symbol :scs (descriptor-reg) :to (:result 0)) - (old :scs (descriptor-reg any-reg) :target rax) + (:args (symbol :scs (descriptor-reg immediate) :to (:result 0)) + (old :scs (descriptor-reg any-reg constant immediate) :target rax) (new :scs (descriptor-reg any-reg))) (:temporary (:sc descriptor-reg :offset rax-offset :from (:argument 1) :to (:result 0)) rax) - #+sb-thread (:temporary (:sc descriptor-reg :to (:result 0)) cell) + #+gs-seg (:temporary (:sc unsigned-reg) thread-temp) (:results (result :scs (descriptor-reg any-reg))) (:policy :fast-safe) (:vop-var vop) + (:node-var node) (:generator 15 ;; This code has two pathological cases: NO-TLS-VALUE-MARKER ;; or UNBOUND-MARKER as NEW: in either case we would end up @@ -183,49 +267,31 @@ ;; Even worse: don't supply old=NO-TLS-VALUE with a symbol whose ;; tls-index=0, because that would succeed, assigning NEW to each ;; symbol in existence having otherwise no thread-local value. - (let ((unbound (generate-error-code vop 'unbound-symbol-error symbol))) - #+sb-thread (progn (compute-virtual-symbol) - (move rax old) - (inst cmpxchg (symbol-value-slot-ea cell) new :lock)) - #-sb-thread (progn (move rax old) - ;; is the :LOCK is necessary? - (inst cmpxchg (symbol-value-slot-ea symbol) new :lock)) - (inst cmp :dword rax unbound-marker-widetag) - (inst jmp :e unbound) - (move result rax)))) - - (define-vop (%cas-symbol-global-value) - (:translate %cas-symbol-global-value) - (:args (symbol :scs (descriptor-reg immediate) :to (:result 0)) - (old :scs (descriptor-reg any-reg) :target rax) - (new :scs (descriptor-reg any-reg))) - (:temporary (:sc descriptor-reg :offset rax-offset - :from (:argument 1) :to (:result 0)) rax) - (:results (result :scs (descriptor-reg any-reg))) - (:policy :fast-safe) - (:generator 10 - (move rax old) - (inst cmpxchg - (if (sc-is symbol immediate) - (symbol-slot-ea (tn-value symbol) symbol-value-slot) - (symbol-value-slot-ea symbol)) - new :lock) + #+sb-thread (progn + (inst mov :dword cell (if (sc-is symbol immediate) + (symbol-tls-index-ea symbol) + (tls-index-of symbol))) + (inst add cell thread-tn) + (inst cmp :qword (ea cell) no-tls-value-marker) + (inst jmp :ne CAS)) + ;; GLOBAL. All logic that follows is for both + and - sb-thread + (emit-symbol-write-barrier symbol nil cell (vop-nth-arg 2 vop) new) + (get-symbol-value-slot-ea cell symbol) + CAS + (load-oldval) + (inst cmpxchg :lock (ea cell) new) + ;; FIXME: if :ALWAYS-BOUND then elide the BOUNDP check. + ;; But we don't accept a constant or immediate, so how to know + ;; what symbol is being CASed? I kind of feel like whether to perform + ;; the check ought to be supplied as codegen info so that we don't + ;; conflate storage-class of an arg with whether we could elide the check. + (unless (policy node (= safety 0)) + (inst cmp :byte rax unbound-marker-widetag) + (inst jmp :e (generate-error-code vop 'unbound-symbol-error symbol))) (move result rax))) #+sb-thread (progn - ;; TODO: SET could be shorter for any known wired-tls symbol. - (define-vop (set) - (:args (symbol :scs (descriptor-reg)) - (value :scs (descriptor-reg any-reg immediate))) - (:temporary (:sc descriptor-reg) cell) - (:generator 4 - ;; Compute the address into which to store. CMOV can only move into - ;; a register, so we can't conditionally move into the TLS and - ;; conditionally move in the opposite flag sense to the symbol. - (compute-virtual-symbol) - (gen-cell-set (symbol-value-slot-ea cell) value nil))) - ;; This code is tested by 'codegen.impure.lisp' (defun emit-symeval (value symbol symbol-reg check-boundp vop) (let* ((known-symbol-p (sc-is symbol constant immediate)) @@ -267,7 +333,7 @@ (setq symbol-reg symbol))) ;; Load the global value if the TLS value didn't exist - (inst cmp :dword value no-tls-value-marker-widetag) + (inst cmp :qword value no-tls-value-marker) (inst cmov :e value (if (and known-symbol-p (sc-is symbol immediate)) (symbol-slot-ea known-symbol symbol-value-slot) ; MOV Rxx, imm32 @@ -275,7 +341,7 @@ (when check-boundp (assemble () - (inst cmp :dword value unbound-marker-widetag) + (inst cmp :byte value unbound-marker-widetag) (let* ((immediatep (sc-is symbol immediate)) (staticp (and immediatep (static-symbol-p known-symbol))) (*location-context* (make-restart-location RETRY value))) @@ -294,10 +360,9 @@ symbol-reg)))) RETRY)))) - ;; With Symbol-Value, we check that the value isn't the trap object. So - ;; Symbol-Value of NIL is NIL. + ;; With Symbol-Value, we check that the value isn't the trap object. (define-vop (symbol-value) - (:translate symeval) + (:translate symbol-value) (:policy :fast-safe) (:args (symbol :scs (descriptor-reg constant immediate) :to (:result 1))) ;; TODO: use no temp if the symbol is known to be thread-local @@ -320,6 +385,11 @@ (:variant nil) (:variant-cost 5)) + ;; TODO: this vop doesn't see that when (INFO :VARIABLE :KIND) = :GLOBAL + ;; there is no need to check the TLS. Probably this is better handled in IR1 + ;; rather than IR2. It would need a new GLOBAL-BOUNDP function. + ;; On the other hand, how many users know that you can declaim + ;; a variable GLOBAL without using DEFGLOBAL ? (define-vop (boundp) (:translate boundp) (:policy :fast-safe) @@ -328,19 +398,19 @@ (:temporary (:sc unsigned-reg) temp) (:generator 9 (inst mov :dword temp (tls-index-of object)) - (inst mov :dword temp (thread-tls-ea temp)) - (inst cmp :dword temp no-tls-value-marker-widetag) + (inst mov :qword temp (thread-tls-ea temp)) + (inst cmp :qword temp no-tls-value-marker) (inst cmov :dword :e temp (symbol-value-slot-ea object)) - (inst cmp :dword temp unbound-marker-widetag)))) + (inst cmp :byte temp unbound-marker-widetag)))) ) ; END OF MACROLET #-sb-thread (progn (define-vop (symbol-value symbol-global-value) - (:translate symeval)) + (:translate symbol-value)) (define-vop (fast-symbol-value fast-symbol-global-value) - (:translate symeval)) + (:translate symbol-value)) (define-vop (set %set-symbol-global-value)) (define-vop (boundp) (:translate boundp) @@ -348,7 +418,7 @@ (:args (symbol :scs (descriptor-reg))) (:conditional :ne) (:generator 9 - (inst cmp :dword (object-slot-ea + (inst cmp :byte (object-slot-ea symbol symbol-value-slot other-pointer-lowtag) unbound-marker-widetag)))) @@ -358,28 +428,30 @@ (:args (symbol :scs (descriptor-reg))) (:results (res :scs (any-reg))) (:result-types positive-fixnum) + (:args-var args) (:generator 2 + (loadw res symbol symbol-hash-slot other-pointer-lowtag) ;; The symbol-hash slot of NIL holds NIL because it is also the ;; car slot, so we have to zero the fixnum tag bit(s) to make sure ;; it is a fixnum. The lowtag selection magic that is required to ;; ensure this is explained in the comment in objdef.lisp - (loadw res symbol symbol-hash-slot other-pointer-lowtag) - (inst and res (lognot fixnum-tag-mask)))) + (unless (not-nil-tn-ref-p args) + (inst and res (lognot fixnum-tag-mask))))) ;;; Combine SYMBOL-HASH and the lisp fallback code into one vop. (define-vop () (:policy :fast-safe) (:translate ensure-symbol-hash) (:args (symbol :scs (descriptor-reg))) - (:results (res :scs (any-reg))) + (:results (res :from :load :scs (any-reg))) ; force it to conflict with arg 0 (:result-types positive-fixnum) (:vop-var vop) (:generator 5 - (when (location= res symbol) (move temp-reg-tn symbol)) ; save a backup + (aver (not (location= res symbol))) (loadw res symbol symbol-hash-slot other-pointer-lowtag) (inst test :dword res res) (inst jmp :ne good) - (inst push (if (location= res symbol) temp-reg-tn symbol)) + (inst push symbol) (invoke-asm-routine 'call 'ensure-symbol-hash vop) (inst pop res) GOOD @@ -419,9 +491,29 @@ (inst and base-ptr (lognot lowtag-mask)) (inst mov res (ea n-word-bytes base-ptr)) ; 1 word beyond the header (inst and res (lognot fixnum-tag-mask)))) + +(define-vop () + (:args (symbol :scs (descriptor-reg))) + (:results (result :scs (unsigned-reg))) + (:result-types positive-fixnum) + (:translate sb-impl::symbol-package-id) + (:policy :fast-safe) + (:generator 2 ; ASSUMPTION: symbol-package-bits = 16 + (inst mov :word result (object-slot-ea symbol symbol-name-slot (- other-pointer-lowtag 6))) + (inst movzx '(:word :dword) result result))) +(define-vop () + (:args (symbol :scs (descriptor-reg))) + (:results (result :scs (descriptor-reg) :from :load)) + (:translate symbol-name) + (:policy :fast-safe) + (:generator 2 + (inst mov result (1- (ash 1 sb-impl::symbol-name-bits))) + (inst and result (object-slot-ea symbol symbol-name-slot other-pointer-lowtag)))) ;;;; fdefinition (FDEFN) objects +;;; IR2-CONVERT-GLOBAL-VAR makes direct use of this vop by name, +;;; so even though it has a :ref-trans in objdef, we also need the vop. (define-vop (fdefn-fun cell-ref) ; /pfw - alpha (:variant fdefn-fun-slot other-pointer-lowtag)) @@ -441,15 +533,15 @@ (inst jmp :e err-lab)) RETRY)) -#-immobile-code (define-vop (set-fdefn-fun) (:policy :fast-safe) - (:translate (setf fdefn-fun)) + #-immobile-code (:translate (setf fdefn-fun)) (:args (function :scs (descriptor-reg) :target result) (fdefn :scs (descriptor-reg))) (:temporary (:sc unsigned-reg) raw) (:results (result :scs (descriptor-reg))) (:generator 38 + (emit-gc-store-barrier fdefn nil raw) (inst mov raw (make-fixup 'closure-tramp :assembly-routine)) (inst cmp :byte (ea (- fun-pointer-lowtag) function) simple-fun-widetag) @@ -460,39 +552,35 @@ (move result function))) #+immobile-code (progn -(define-vop (set-fdefn-fun) +(define-vop (set-direct-callable-fdefn-fun) (:args (fdefn :scs (descriptor-reg)) (function :scs (descriptor-reg)) (raw-word :scs (unsigned-reg))) (:vop-var vop) (:generator 38 + ;; N.B. concerning the use of pseudo-atomic here, + ;; refer to doc/internals-notes/fdefn-gc-safety + ;; No barrier here, because fdefns in immobile space rely on the SIGSEGV signal + ;; to manage the card marks. (pseudo-atomic () - (inst push fdefn) - (invoke-asm-routine 'call 'touch-gc-card vop) - (inst mov (ea (- (ash fdefn-fun-slot word-shift) other-pointer-lowtag) fdefn) - function) - (inst mov (ea (- (ash fdefn-raw-addr-slot word-shift) other-pointer-lowtag) fdefn) - raw-word) + (storew function fdefn fdefn-fun-slot other-pointer-lowtag) + (storew raw-word fdefn fdefn-raw-addr-slot other-pointer-lowtag) ;; Ensure that the header contains a JMP instruction, not INT3. ;; This store is aligned (inst mov :word (ea (- 2 other-pointer-lowtag) fdefn) #x25FF)))) (define-vop (set-undefined-fdefn-fun) ;; Do not set the raw-addr slot and do not change the header + ;; This vop is specifically for SB-C::INSTALL-GUARD-FUNCTION (:args (fdefn :scs (descriptor-reg)) (function :scs (descriptor-reg))) (:vop-var vop) - (:generator 38 - (pseudo-atomic () - (inst push fdefn) - (invoke-asm-routine 'call 'touch-gc-card vop) - (inst mov (ea (- (ash fdefn-fun-slot word-shift) other-pointer-lowtag) fdefn) - function))))) + (:generator 1 (storew function fdefn fdefn-fun-slot other-pointer-lowtag)))) (define-vop (fdefn-makunbound) (:policy :fast-safe) (:translate fdefn-makunbound) - (:args (fdefn :scs (descriptor-reg) :target result)) - (:results (result :scs (descriptor-reg))) + (:args (fdefn :scs (descriptor-reg))) + (:temporary (:sc unsigned-reg) temp) (:vop-var vop) (:generator 38 ;; Change the JMP instruction to INT3 so that a trap occurs in the fdefn @@ -508,9 +596,9 @@ ;; and resume at undefined-tramp. However, CALL-SYMBOL jumps via raw-addr if ;; its callable object was not a function. In that case RAX holds a symbol, ;; so we're OK because we can identify the undefined function. - (storew (make-fixup 'undefined-tramp :assembly-routine) - fdefn fdefn-raw-addr-slot other-pointer-lowtag) - (move result fdefn))) + ;; Technically this could be computed using "LEA temp, [RIP-disp]" + (inst mov temp (ea (make-fixup 'undefined-tramp :assembly-routine*))) + (storew temp fdefn fdefn-raw-addr-slot other-pointer-lowtag))) ;;;; binding and unbinding @@ -576,6 +664,7 @@ (store-binding-stack-pointer bsp) (storew temp bsp (- binding-value-slot binding-size)) (storew symbol bsp (- binding-symbol-slot binding-size)) + (emit-gc-store-barrier symbol nil temp) (storew val symbol symbol-value-slot other-pointer-lowtag))) #+sb-thread @@ -605,6 +694,7 @@ (:generator 0 (load-binding-stack-pointer bsp) (loadw symbol bsp (- binding-symbol-slot binding-size)) + (emit-gc-store-barrier symbol nil value) ; VALUE is the card-mark temp (loadw value bsp (- binding-value-slot binding-size)) (storew value symbol symbol-value-slot other-pointer-lowtag) (storew 0 bsp (- binding-symbol-slot binding-size)) @@ -632,12 +722,11 @@ (loadw symbol bsp binding-symbol-slot) (inst test symbol symbol)) (inst jmp :z SKIP) - (loadw value bsp binding-value-slot) - #-sb-thread - (storew value symbol symbol-value-slot other-pointer-lowtag) - #+sb-thread - (inst mov (thread-tls-ea symbol) value) - + #-sb-thread (progn (emit-gc-store-barrier symbol nil value) ; VALUE is the card-mark temp + (loadw value bsp binding-value-slot) + (storew value symbol symbol-value-slot other-pointer-lowtag)) + #+sb-thread (progn (loadw value bsp binding-value-slot) + (inst mov (thread-tls-ea symbol) value)) SKIP (inst movapd (ea bsp) zero) @@ -660,9 +749,8 @@ closure-info-offset fun-pointer-lowtag (any-reg descriptor-reg) * %closure-index-ref) -(define-full-setter set-funcallable-instance-info * - funcallable-instance-info-offset fun-pointer-lowtag - (any-reg descriptor-reg) * %set-funcallable-instance-info) +(define-full-setter %closure-index-set * closure-info-offset fun-pointer-lowtag + (any-reg descriptor-reg) * %closure-index-set) (define-full-reffer funcallable-instance-info * funcallable-instance-info-offset fun-pointer-lowtag @@ -679,13 +767,23 @@ (:args (object :scs (descriptor-reg)) (value :scs (descriptor-reg any-reg))) (:info offset) + (:vop-var vop) + ;; temp is wasted if we don't need a barrier, which we almost never do + (:temporary (:sc unsigned-reg) temp) (:generator 4 + (let* ((value-tn (tn-ref-tn (tn-ref-across (vop-args vop)))) + (prim-type (sb-c::tn-primitive-type value-tn)) + (scs (and prim-type (sb-c::primitive-type-scs prim-type)))) + (when (and (not (singleton-p scs)) + (member descriptor-reg-sc-number scs)) + (emit-gc-store-barrier object nil temp (vop-nth-arg 1 vop) value))) (storew value object (+ closure-info-offset offset) fun-pointer-lowtag))) (define-vop (closure-init-from-fp) (:args (object :scs (descriptor-reg))) (:info offset) (:generator 4 + ;; RBP-TN looks like a fixnum (non-pointer) so no barrier (storew rbp-tn object (+ closure-info-offset offset) fun-pointer-lowtag))) ;;;; value cell hackery @@ -698,57 +796,104 @@ ;;;; structure hackery +(defun load-instance-length (result instance taggedp) + (inst mov :dword result (ea (- instance-pointer-lowtag) instance)) + ;; Returning fixnum/any-reg elides some REX prefixes due to the shifts + ;; being small. Maybe the asm optimizer could figure it out now? + (cond (taggedp + (inst shr :dword result (- instance-length-shift n-fixnum-tag-bits)) + (inst and :dword result (fixnumize instance-length-mask))) + (t + (inst shr :dword result instance-length-shift) + (inst and :dword result instance-length-mask)))) + (define-vop () (:policy :fast-safe) (:translate %instance-length) (:args (struct :scs (descriptor-reg))) (:results (res :scs (any-reg))) (:result-types positive-fixnum) - (:generator 4 - (inst mov :dword res (ea (- instance-pointer-lowtag) struct)) - ;; Returning fixnum/any-reg elides some REX prefixes due to the shifts - ;; being small. Maybe the asm optimizer could figure it out now? - (inst shr :dword res (- instance-length-shift n-fixnum-tag-bits)) - (inst and :dword res (fixnumize instance-length-mask)))) - -#+compact-instance-header -(progn - (define-vop (%instance-layout) - (:translate %instance-layout) - (:policy :fast-safe) - (:args (object :scs (descriptor-reg))) - (:results (res :scs (descriptor-reg))) - (:variant-vars lowtag) - (:variant instance-pointer-lowtag) - (:generator 1 - (inst mov :dword res (ea (- 4 lowtag) object)))) - (define-vop (%set-instance-layout) - (:translate %set-instance-layout) - (:policy :fast-safe) - (:args (object :scs (descriptor-reg)) - (value :scs (any-reg descriptor-reg) :target res)) - (:results (res :scs (any-reg descriptor-reg))) - (:vop-var vop) - (:generator 1 - (inst mov :dword (ea (- 4 instance-pointer-lowtag) object) value) - (move res value))) - (define-vop (%fun-layout %instance-layout) - (:translate %fun-layout) - (:variant fun-pointer-lowtag)) - (define-vop (%set-funcallable-instance-layout %set-instance-layout) - (:translate %set-funcallable-instance-layout) - (:generator 50 - (pseudo-atomic () - (inst push object) - (invoke-asm-routine 'call 'touch-gc-card vop) - (inst mov :dword (ea (- 4 fun-pointer-lowtag) object) value)) - (move res value)))) + (:generator 4 (load-instance-length res struct t))) (define-full-reffer instance-index-ref * instance-slots-offset instance-pointer-lowtag (any-reg descriptor-reg) * %instance-ref) (define-full-setter instance-index-set * instance-slots-offset - instance-pointer-lowtag (any-reg descriptor-reg immediate) * %instance-set) + instance-pointer-lowtag (any-reg descriptor-reg immediate constant) * %instance-set) + +;;; Try to group consecutive %INSTANCE-SET vops on the same instance +;;; so that: +;;; 1) we can potentially utilize multi-word stores, +;;; 2) a GC store barrier need occur once only (depending on the kind of barrier) +;;; +;;; in the absence of barriers, we would like to be allowed to rearrange +;;; stores; in particular, storing the constant 0 to clear out a structure +;;; should not require that you remember the slot order. +;;; all the more so if we are permitted to optimize the slot order of the defstruct +;;; by putting all tagged slots together, then all raw slots together. +;;; +(define-vop (instance-set-multiple) + (:args (instance :scs (descriptor-reg)) + (values :more t :scs (descriptor-reg constant immediate))) + (:temporary (:sc unsigned-reg) val-temp) + ;; Would like to try to store adjacent 0s (and/or NILs) using 16 byte stores. + (:temporary (:sc int-sse-reg) xmm-temp) + (:info indices) + (:generator 1 + (let* ((max-index (reduce #'max indices)) + ;;(min-index (reduce #'min indices)) + ;;(count (length indices)) + (zerop-mask 0) ; slots which become a zero + (constantp-mask 0) ; slots which become any constant + (const-vals (make-array (1+ max-index) :initial-element nil)) + (use-xmm-p)) + (do ((tn-ref values (tn-ref-across tn-ref)) + (indices indices (cdr indices))) + ((null tn-ref)) + (let ((tn (tn-ref-tn tn-ref))) + (when (constant-tn-p tn) + (let ((slot (car indices)) + (val (tn-value tn))) + (setf constantp-mask (logior constantp-mask (ash 1 slot)) + zerop-mask (logior zerop-mask (if (eql val 0) (ash 1 slot) 0)) + (aref const-vals slot) val))))) + ;; If there are at least 3 zeros stored or any pair of adjacent 0s + ;; then load the xmm-temp with 0. + (setq use-xmm-p (or (>= (logcount zerop-mask) 3) + (loop for slot below max-index + thereis (= (ldb (byte 2 slot) zerop-mask) #b11)))) + (emit-gc-store-barrier instance nil val-temp values) + (when use-xmm-p + (inst xorpd xmm-temp xmm-temp)) + (loop + (let* ((slot (pop indices)) + (val (tn-ref-tn values)) + (ea (ea (- (ash (+ instance-slots-offset slot) word-shift) + instance-pointer-lowtag) + instance))) + (aver (tn-p instance)) + (setq values (tn-ref-across values)) + ;; If the xmm temp was loaded with 0 and this value is 0, + ;; and possibly the next, then store through the temp + (cond + ((and use-xmm-p (constant-tn-p val) (eql (tn-value val) 0)) + (let* ((next-slot (car indices)) + (next-val (if next-slot (tn-ref-tn values)))) + (cond ((and (eql (1+ slot) next-slot) + (constant-tn-p next-val) + (eql (tn-value next-val) 0)) + (inst movupd ea xmm-temp) + (pop indices) + (setq values (tn-ref-across values))) + (t + (inst movsd ea xmm-temp))))) + ((stack-tn-p val) + (inst mov val-temp val) + (inst mov ea val-temp)) + (t + (gen-cell-set ea val val-temp))) + (unless indices (return))))) + (aver (not values)))) (define-full-compare-and-swap %instance-cas instance instance-slots-offset instance-pointer-lowtag @@ -756,99 +901,97 @@ (define-full-compare-and-swap %raw-instance-cas/word instance instance-slots-offset instance-pointer-lowtag (unsigned-reg) unsigned-num %raw-instance-cas/word) +(define-full-compare-and-swap %raw-instance-cas/signed-word instance + instance-slots-offset instance-pointer-lowtag + (signed-reg) signed-num %raw-instance-cas/signed-word) + +(define-vop () + (:translate %raw-instance-xchg/word) + (:policy :fast-safe) + (:args (instance :scs (descriptor-reg)) + (newval :scs (unsigned-reg immediate constant) :target result)) + (:info index) + (:arg-types * (:constant integer) unsigned-num) + (:results (result :scs (unsigned-reg))) + (:result-types unsigned-num) + (:temporary (:sc unsigned-reg) temp) + (:generator 3 + ;; Use RESULT as the source of the exchange, unless doing so + ;; would clobber NEWVAL + (let ((source (if (location= result instance) temp result))) + (if (sc-is newval immediate) + (inst mov source (constantize (tn-value newval))) + (move source newval)) + (inst xchg (ea (- (ash (+ instance-slots-offset index) word-shift) + instance-pointer-lowtag) instance) + source) + (unless (eq source result) + (move result temp))))) ;;;; code object frobbing (define-full-reffer code-header-ref * 0 other-pointer-lowtag (any-reg descriptor-reg) * code-header-ref) -;; CODE-HEADER-SET of a constant index is never used, so we specifically -;; ask not to get it defined. (It's not impossible to use, it's just not -;; helpful to have - either you want to access CODE-FIXUPS or CODE-DEBUG-INFO, -;; which do things their own way, or you want a variable index.) -(define-full-setter (code-header-set :no-constant-variant) - * 0 other-pointer-lowtag - (any-reg descriptor-reg) * code-header-set) +(define-vop () + (:translate code-header-set) + (:policy :fast-safe) + (:args (object :scs (descriptor-reg)) + (index :scs (unsigned-reg)) + (value :scs (any-reg descriptor-reg))) + (:arg-types * unsigned-num *) + (:vop-var vop) + (:temporary (:sc unsigned-reg :offset rax-offset) rax) ; for the asm routine + (:temporary (:sc unsigned-reg :offset rdx-offset) rdx) + (:temporary (:sc unsigned-reg :offset rdi-offset) rdi) + (:ignore rax rdx rdi) + (:generator 10 + (inst push value) + (inst push index) + (inst push object) + (invoke-asm-routine 'call 'code-header-set vop))) ;;;; raw instance slot accessors (flet ((instance-slot-ea (object index) - (etypecase index - (integer - (ea (+ (* (+ instance-slots-offset index) n-word-bytes) - (- instance-pointer-lowtag)) - object)) - (tn - (ea (+ (* instance-slots-offset n-word-bytes) - (- instance-pointer-lowtag)) - object index (ash 1 (- word-shift n-fixnum-tag-bits))))))) + (let ((constant-index + (if (integerp index) index + (if (sc-is index immediate) (tn-value index))))) + (if constant-index + (ea (+ (* (+ instance-slots-offset constant-index) n-word-bytes) + (- instance-pointer-lowtag)) + object) + (ea (+ (* instance-slots-offset n-word-bytes) + (- instance-pointer-lowtag)) + object index (ash 1 (- word-shift n-fixnum-tag-bits))))))) (macrolet - ((def (suffix result-sc result-type inst &optional (inst/c (list 'quote inst))) + ((def (suffix result-sc result-type inst) `(progn - (define-vop (,(symbolicate "RAW-INSTANCE-REF/" suffix)) + (define-vop () (:translate ,(symbolicate "%RAW-INSTANCE-REF/" suffix)) (:policy :fast-safe) - (:args (object :scs (descriptor-reg)) (index :scs (any-reg))) + (:args (object :scs (descriptor-reg)) (index :scs (any-reg immediate))) (:arg-types * tagged-num) (:results (value :scs (,result-sc))) (:result-types ,result-type) - (:generator 5 - (inst ,inst value (instance-slot-ea object index)))) - (define-vop (,(symbolicate "RAW-INSTANCE-REF-C/" suffix)) - (:translate ,(symbolicate "%RAW-INSTANCE-REF/" suffix)) - (:policy :fast-safe) - (:args (object :scs (descriptor-reg))) - ;; Why are we pedantic about the index constraint here - ;; if we're not equally so in the init vop? - (:arg-types * (:constant (load/store-index #.n-word-bytes - #.instance-pointer-lowtag - #.instance-slots-offset))) - (:info index) - (:results (value :scs (,result-sc))) - (:result-types ,result-type) - (:generator 4 - (inst* ,inst/c value (instance-slot-ea object index)))) - (define-vop (,(symbolicate "RAW-INSTANCE-SET/" suffix)) - (:translate ,(symbolicate "%RAW-INSTANCE-SET/" suffix)) - (:policy :fast-safe) - (:args (object :scs (descriptor-reg)) - (index :scs (any-reg)) - (value :scs (,result-sc) :target result)) - (:arg-types * tagged-num ,result-type) - (:results (result :scs (,result-sc))) - (:result-types ,result-type) - (:generator 5 - (inst ,inst (instance-slot-ea object index) value) - (move result value))) - (define-vop (,(symbolicate "RAW-INSTANCE-SET-C/" suffix)) + (:generator 1 (inst ,inst value (instance-slot-ea object index)))) + (define-vop () (:translate ,(symbolicate "%RAW-INSTANCE-SET/" suffix)) (:policy :fast-safe) (:args (object :scs (descriptor-reg)) - (value :scs (,result-sc) :target result)) - (:arg-types * (:constant (load/store-index #.n-word-bytes - #.instance-pointer-lowtag - #.instance-slots-offset)) - ,result-type) - (:info index) - (:results (result :scs (,result-sc))) - (:result-types ,result-type) - (:generator 4 - (inst* ,inst/c (instance-slot-ea object index) value) - (move result value))) - (define-vop (,(symbolicate "RAW-INSTANCE-INIT/" suffix)) - (:args (object :scs (descriptor-reg)) + (index :scs (any-reg immediate)) (value :scs (,result-sc))) - (:arg-types * ,result-type) - (:info index) - (:generator 4 - (inst* ,inst/c (instance-slot-ea object index) value)))))) + (:arg-types * tagged-num ,result-type) + (:generator 1 (inst ,inst (instance-slot-ea object index) value)))))) (def word unsigned-reg unsigned-num mov) (def signed-word signed-reg signed-num mov) (def single single-reg single-float movss) (def double double-reg double-float movsd) (def complex-single complex-single-reg complex-single-float movq) (def complex-double complex-double-reg complex-double-float - movupd (if (oddp index) 'movapd 'movupd))) + ;; Todo: put back the choice of using APD or UPD. + ;; But was it even right for either +/- compact-instance-header? + movupd #| (if (oddp index) 'movapd 'movupd) |#)) (define-vop (raw-instance-atomic-incf/word) (:translate %raw-instance-atomic-incf/word) @@ -860,7 +1003,7 @@ (:results (result :scs (unsigned-reg))) (:result-types unsigned-num) (:generator 5 - (inst xadd (instance-slot-ea object index) diff :lock) + (inst xadd :lock (instance-slot-ea object index) diff) (move result diff))) (define-vop (raw-instance-atomic-incf-c/word) @@ -876,7 +1019,7 @@ (:results (result :scs (unsigned-reg))) (:result-types unsigned-num) (:generator 4 - (inst xadd (instance-slot-ea object index) diff :lock) + (inst xadd :lock (instance-slot-ea object index) diff) (move result diff)))) ;;;; @@ -892,7 +1035,7 @@ (move rdx old-hi) (move rbx new-lo) (move rcx new-hi) - (inst cmpxchg16b memory-operand :lock) + (inst cmpxchg16b :lock memory-operand) ;; RDX:RAX hold the actual old contents of memory. ;; Manually analyze result lifetimes to avoid clobbering. (cond ((and (location= result-lo rdx) (location= result-hi rax)) @@ -904,48 +1047,59 @@ (move result-lo rax) ; move low part first (move result-hi rdx)))) +;;; TODO: these GC-STORE-BARRIERs are inadequate if the GC strategy +;;; requires that 2 old pointees and 2 new pointees all be greyed. (macrolet - ((define-cmpxchg-vop (name memory-operand more-stuff &optional index-arg) - `(define-vop (,name) + ((define-dblcas (translate indexedp &rest rest) + `(define-vop () (:policy :fast-safe) - ,@more-stuff + (:translate ,translate) (:args (object :scs (descriptor-reg) :to :eval) - ,@index-arg + ,@(when indexedp '((index :scs (any-reg) :to :eval))) (expected-old-lo :scs (descriptor-reg any-reg) :target eax) (expected-old-hi :scs (descriptor-reg any-reg) :target edx) (new-lo :scs (descriptor-reg any-reg) :target ebx) (new-hi :scs (descriptor-reg any-reg) :target ecx)) + ,@(when indexedp '((:arg-types * positive-fixnum * * * *))) + ,@rest (:results (result-lo :scs (descriptor-reg any-reg)) (result-hi :scs (descriptor-reg any-reg))) - (:temporary (:sc unsigned-reg :offset eax-offset + ;; this is sufficiently confusing that I don't want to try reusing + ;; one of the other declared temps as the EA for the store barrier. + (:temporary (:sc unsigned-reg) temp) + (:temporary (:sc unsigned-reg :offset rax-offset :from (:argument 2) :to (:result 0)) eax) - (:temporary (:sc unsigned-reg :offset edx-offset + (:temporary (:sc unsigned-reg :offset rdx-offset :from (:argument 3) :to (:result 0)) edx) - (:temporary (:sc unsigned-reg :offset ebx-offset + (:temporary (:sc unsigned-reg :offset rbx-offset :from (:argument 4) :to (:result 0)) ebx) - (:temporary (:sc unsigned-reg :offset ecx-offset - :from (:argument 5) :to (:result 0)) ecx) - (:generator 7 - (generate-dblcas ,memory-operand - expected-old-lo expected-old-hi new-lo new-hi - eax ebx ecx edx result-lo result-hi))))) - (define-cmpxchg-vop compare-and-exchange-pair - (ea (- list-pointer-lowtag) object) - ((:translate %cons-cas-pair))) - (define-cmpxchg-vop compare-and-exchange-pair-indexed - (ea offset object index (ash n-word-bytes (- n-fixnum-tag-bits))) - ((:variant-vars offset)) - ((index :scs (descriptor-reg any-reg) :to :eval)))) - -;; The CPU requires 16-byte alignment for the memory operand. -;; A vector's data portion starts on a 16-byte boundary, -;; so any even numbered index is OK. -(define-vop (%vector-cas-pair compare-and-exchange-pair-indexed) - (:translate %vector-cas-pair) - (:variant (- (* n-word-bytes vector-data-offset) other-pointer-lowtag))) - -;; Here you specify an odd numbered slot, otherwise get a bus error. -;; An instance's first user-visible slot at index 1 is 16-byte-aligned. -(define-vop (%instance-cas-pair compare-and-exchange-pair-indexed) - (:translate %instance-cas-pair) - (:variant (- (* n-word-bytes instance-slots-offset) instance-pointer-lowtag))) + (:temporary (:sc unsigned-reg :offset rcx-offset + :from (:argument 5) :to (:result 0)) ecx)))) + + (define-dblcas %cons-cas-pair nil + (:generator 2 + (emit-gc-store-barrier object nil temp) + (generate-dblcas (ea (- list-pointer-lowtag) object) + expected-old-lo expected-old-hi new-lo new-hi + eax ebx ecx edx result-lo result-hi))) + + ;; The CPU requires 16-byte alignment for the memory operand. + ;; A vector's data portion starts on a 16-byte boundary, so any even numbered index is OK. + (define-dblcas %vector-cas-pair t + (:generator 2 + (let ((ea (ea (- (* n-word-bytes vector-data-offset) other-pointer-lowtag) + object index (ash n-word-bytes (- n-fixnum-tag-bits))))) + (emit-gc-store-barrier object ea temp) + (generate-dblcas ea expected-old-lo expected-old-hi new-lo new-hi + eax ebx ecx edx result-lo result-hi)))) + + ;; Here you have to specify an odd numbered slot. + ;; An instance's first user-visible slot at index 1 is 16-byte-aligned. + ;; (Hmm, does the constraint differ by +/- compact-instance-header?) + (define-dblcas %instance-cas-pair t + (:generator 2 + (emit-gc-store-barrier object nil temp) + (let ((ea (ea (- (* n-word-bytes instance-slots-offset) instance-pointer-lowtag) + object index (ash n-word-bytes (- n-fixnum-tag-bits))))) + (generate-dblcas ea expected-old-lo expected-old-hi new-lo new-hi + eax ebx ecx edx result-lo result-hi))))) diff --git a/src/compiler/x86-64/char.lisp b/src/compiler/x86-64/char.lisp index adf5415e05..96da3c2e90 100644 --- a/src/compiler/x86-64/char.lisp +++ b/src/compiler/x86-64/char.lisp @@ -31,19 +31,20 @@ ;;; create an arbitrary EA given a stack TN. So, instead do: ;;; * mem-to-reg: dword load, shift ;;; * mem-to-mem: dword load to temp, shift temp, store as a qword -(defun untagify-char (dst src shift) +(defun untagify-char (dst src shift temp) (if (and (location= src dst) (stack-tn-p dst)) ; shift right in memory (inst shr :dword dst shift) - (let ((reg (if (stack-tn-p dst) temp-reg-tn dst))) - (32bit-move reg src) + (let ((reg (if (stack-tn-p dst) temp dst))) + (move reg src :dword) (inst shr :dword reg shift) (when (stack-tn-p dst) ; store as qword to ensure upper bytes are 0 - (inst mov dst temp-reg-tn))))) + (inst mov dst temp))))) (define-vop (move-to-character) (:args (x :scs (any-reg descriptor-reg control-stack) :target y :load-if nil)) (:results (y :scs (character-reg character-stack) :load-if nil)) + (:temporary (:sc unsigned-reg) temp) (:note "character untagging") - (:generator 1 (untagify-char y x n-widetag-bits))) + (:generator 1 (untagify-char y x n-widetag-bits temp))) (define-move-vop move-to-character :move (any-reg) (character-reg)) @@ -56,10 +57,11 @@ (assert (not (logbitp 7 character-widetag)))) (define-vop (tagged-char-code) ; valid only if N-FIXNUM-TAG-BITS = 1 (:args (x :scs (any-reg descriptor-reg control-stack) :target y :load-if nil)) - (:results (y :scs (any-reg control-stack) :load-if nil)) + (:results (y :scs (any-reg descriptor-reg control-stack) :load-if nil)) + (:temporary (:sc unsigned-reg) temp) (:note "character untagging") (:generator 1 - (untagify-char y x (- n-widetag-bits n-fixnum-tag-bits)) + (untagify-char y x (- n-widetag-bits n-fixnum-tag-bits) temp) (when (> n-fixnum-tag-bits 1) (inst and :dword y fixnum-tag-mask)))) ;;; Move an untagged char to a tagged representation. @@ -68,8 +70,7 @@ (:results (y :scs (any-reg descriptor-reg))) (:note "character tagging") (:generator 1 - (unless (location= x y) - (inst mov :dword y x)) + (move y x :dword) (inst shl :dword y n-widetag-bits) (inst or :dword y character-widetag))) (define-move-vop move-from-character :move @@ -77,21 +78,20 @@ (any-reg descriptor-reg)) ;;; Move untagged character values. -(defun move-raw-char-code (dst src) ; move SRC to DST +(defun move-raw-char-code (dst src temp) ; move SRC to DST (unless (location= src dst) ;; Aways store as :qword to stack (storing the upper 32 zero bits) so that ;; loading as either :dword or :qword is ok. ;; We can see immediate constants here which become untagged integers. (inst mov (if (stack-tn-p dst) :qword :dword) dst - (cond ((stack-tn-p src) - (inst mov :qword temp-reg-tn src) - temp-reg-tn) + (cond ((stack-tn-p src) (inst mov :qword temp src) temp) ((encode-value-if-immediate src nil)))))) (define-vop (character-move) (:args (x :target y :scs (character-reg character-stack) :load-if nil)) (:results (y :scs (character-reg character-stack) :load-if nil)) + (:temporary (:sc unsigned-reg) temp) (:note "character move") - (:generator 0 (move-raw-char-code y x))) + (:generator 0 (move-raw-char-code y x temp))) (define-move-vop character-move :move (character-reg) (character-reg character-stack)) @@ -108,7 +108,7 @@ (character-reg (move y x)) (character-stack - (if (= (tn-offset fp) esp-offset) + (if (= (tn-offset fp) rsp-offset) (storew x fp (tn-offset y)) ; c-call (storew x fp (frame-word-offset (tn-offset y)))))))) (define-move-vop move-character-arg :move-arg @@ -128,7 +128,8 @@ (:arg-types character) (:results (res :scs (unsigned-reg unsigned-stack) :load-if nil)) (:result-types positive-fixnum) - (:generator 1 (move-raw-char-code res ch))) + (:temporary (:sc unsigned-reg) temp) + (:generator 1 (move-raw-char-code res ch temp))) (define-vop (code-char) (:translate code-char) @@ -137,7 +138,8 @@ (:arg-types positive-fixnum) (:results (res :scs (character-reg character-stack) :load-if nil)) (:result-types character) - (:generator 1 (move-raw-char-code res code))) + (:temporary (:sc unsigned-reg) temp) + (:generator 1 (move-raw-char-code res code temp))) ;;; comparison of CHARACTERs (define-vop (character-compare) @@ -150,7 +152,7 @@ (:policy :fast-safe) (:note "inline comparison") (:generator 3 - (inst cmp x y))) + (inst cmp :dword x y))) (define-vop (fast-char=/character character-compare) (:translate char=) @@ -171,7 +173,7 @@ (:policy :fast-safe) (:note "inline constant comparison") (:generator 2 - (inst cmp x (sb-xc:char-code y)))) + (inst cmp :dword x (char-code y)))) (define-vop (fast-char=/character/c character-compare/c) (:translate char=) @@ -224,5 +226,5 @@ ;;; with just the TAGGED-CHAR-CODE vop. (defoptimizer (sb-c::vop-optimize move-to-character) (vop) (when (and (sb-c:next-vop-is vop 'char-code) - (sb-c:next-vop-is (sb-c:vop-next vop) 'move-from-word/fixnum)) + (sb-c:next-vop-is (sb-c::next-vop vop) 'move-from-word/fixnum)) (sb-c:replace-vops 3 vop 'tagged-char-code))) diff --git a/src/compiler/x86-64/debug.lisp b/src/compiler/x86-64/debug.lisp index 97afe11020..8740fd46ed 100644 --- a/src/compiler/x86-64/debug.lisp +++ b/src/compiler/x86-64/debug.lisp @@ -19,7 +19,7 @@ (:generator 1 (move res rsp-tn))) -(define-vop () +(define-vop (current-fp-sap) (:translate current-fp) (:policy :fast-safe) (:results (res :scs (sap-reg sap-stack))) @@ -51,19 +51,16 @@ (:policy :fast-safe) (:args (sap :scs (sap-reg) :to :eval) (offset :scs (any-reg) :target temp) - (value :scs (descriptor-reg) :to :result :target result)) + (value :scs (descriptor-reg))) (:arg-types system-area-pointer positive-fixnum *) - (:temporary (:sc unsigned-reg :from (:argument 1) :to :result) temp) - (:results (result :scs (descriptor-reg))) - (:result-types *) + (:temporary (:sc unsigned-reg :from (:argument 1)) temp) (:generator 9 (move temp offset) (inst neg temp) (inst mov (ea (frame-byte-offset 0) sap temp (ash 1 (- word-shift n-fixnum-tag-bits))) - value) - (move result value))) + value))) (define-vop () (:translate fun-code-header) diff --git a/src/compiler/x86-64/float.lisp b/src/compiler/x86-64/float.lisp index 6ef604eb6c..d36873d2c2 100644 --- a/src/compiler/x86-64/float.lisp +++ b/src/compiler/x86-64/float.lisp @@ -112,7 +112,7 @@ (inst movsd (ea-for-df-stack y) x)) (eval-when (:compile-toplevel :execute) - (setf *read-default-float-format* 'cl:single-float)) + (setf cl:*read-default-float-format* 'cl:single-float)) ;;;; complex float move functions @@ -173,8 +173,9 @@ (:results (y :scs (descriptor-reg))) (:node-var node) (:note "float to pointer coercion") + #+gs-seg (:temporary (:sc unsigned-reg :offset 15) thread-tn) (:generator 13 - (alloc-other y double-float-widetag double-float-size node) + (alloc-other double-float-widetag double-float-size y node nil thread-tn) (inst movsd (ea-for-df-desc y) x))) (define-move-vop move-from-double :move (double-reg) (descriptor-reg)) @@ -225,10 +226,11 @@ (define-vop (move-from-complex-single) (:args (x :scs (complex-single-reg) :to :save)) (:results (y :scs (descriptor-reg))) + #+gs-seg (:temporary (:sc unsigned-reg :offset 15) thread-tn) (:node-var node) (:note "complex float to pointer coercion") (:generator 13 - (alloc-other y complex-single-float-widetag complex-single-float-size node) + (alloc-other complex-single-float-widetag complex-single-float-size y node nil thread-tn) (inst movlps (ea-for-csf-data-desc y) x))) (define-move-vop move-from-complex-single :move (complex-single-reg) (descriptor-reg)) @@ -236,10 +238,11 @@ (define-vop (move-from-complex-double) (:args (x :scs (complex-double-reg) :to :save)) (:results (y :scs (descriptor-reg))) + #+gs-seg (:temporary (:sc unsigned-reg :offset 15) thread-tn) (:node-var node) (:note "complex float to pointer coercion") (:generator 13 - (alloc-other y complex-double-float-widetag complex-double-float-size node) + (alloc-other complex-double-float-widetag complex-double-float-size y node nil thread-tn) (inst movapd (ea-for-cdf-data-desc y) x))) (define-move-vop move-from-complex-double :move (complex-double-reg) (descriptor-reg)) @@ -284,7 +287,7 @@ (,sc (move y x)) (,stack-sc - (if (= (tn-offset fp) esp-offset) + (if (= (tn-offset fp) rsp-offset) (let* ((offset (tn-byte-offset y)) (ea (ea offset fp))) ,@(ecase format @@ -1070,7 +1073,7 @@ complex-double-reg fp-complex-double-immediate complex-double-float movsd movapd cmppd movmskpd #b11)) -(macrolet ((define-</> (op single-name double-name &rest flags) +(macrolet ((define (op single-name double-name &rest flags) `(progn (define-vop (,double-name double-float-compare) (:translate ,op) @@ -1101,10 +1104,14 @@ (setf y (register-inline-constant (tn-value y)))) (t)) (inst comiss x y)))))) - (define-</> < <single-float <double-float not :p :nc) - (define-</> > >single-float >double-float not :p :na) - (define-</> <= <=single-float <=double-float not :p :a) - (define-</> >= >=single-float >=double-float not :p :b)) + ;; UNORDERED: ZF,PF,CF <- 111; + ;; GREATER_THAN: ZF,PF,CF <- 000; + ;; LESS_THAN: ZF,PF,CF <- 001; + ;; EQUAL: ZF,PF,CF <- 100; + (define < <single-float <double-float not :p :nc) + (define > >single-float >double-float not :p :na) + (define <= <=single-float <=double-float not :p :a) + (define >= >=single-float >=double-float not :p :b)) ;;;; conversion @@ -1572,3 +1579,43 @@ (:generator 2 (move r x) (inst shufpd r r #b01))) + +#+round-float +(progn + (define-vop () + (:translate round-double) + (:policy :fast-safe) + (:args (x :scs (double-reg) :target r)) + (:arg-types double-float (:constant symbol)) + (:info mode) + (:results (r :scs (double-reg))) + (:result-types double-float) + (:generator 2 + (unless (location= r x) + (inst xorpd r r)) + (inst roundsd r x + (logior #b1000 + (ecase mode + (:round 0) + (:floor 1) + (:ceiling 2) + (:truncate 3)))))) + + (define-vop () + (:translate round-single) + (:policy :fast-safe) + (:args (x :scs (single-reg) :target r)) + (:arg-types single-float (:constant symbol)) + (:info mode) + (:results (r :scs (single-reg))) + (:result-types single-float) + (:generator 2 + (unless (location= r x) + (inst xorps r r)) + (inst roundss r x + (logior #b1000 + (ecase mode + (:round 0) + (:floor 1) + (:ceiling 2) + (:truncate 3))))))) diff --git a/src/compiler/x86-64/insts.lisp b/src/compiler/x86-64/insts.lisp index 7e38b88fd9..bfb8aaa086 100644 --- a/src/compiler/x86-64/insts.lisp +++ b/src/compiler/x86-64/insts.lisp @@ -14,19 +14,55 @@ (eval-when (:compile-toplevel :load-toplevel :execute) ;; Imports from this package into SB-VM - (import '(conditional-opcode + (import '(conditional-opcode negate-condition plausible-signed-imm32-operand-p ea-p ea-base ea-index size-nbyte alias-p - ea make-ea ea-disp rip-relative-ea) "SB-VM") + ea ea-disp rip-relative-ea) "SB-VM") + (import 'sb-assem::&prefix) ;; Imports from SB-VM into this package #+sb-simd-pack-256 (import '(sb-vm::int-avx2-reg sb-vm::double-avx2-reg sb-vm::single-avx2-reg)) (import '(sb-vm::tn-byte-offset sb-vm::tn-reg sb-vm::reg-name sb-vm::frame-byte-offset sb-vm::rip-tn sb-vm::rbp-tn sb-vm::gpr-tn-p sb-vm::stack-tn-p sb-c::tn-reads sb-c::tn-writes - #+avx2 sb-vm::avx2-reg + sb-vm::ymm-reg sb-vm::registers sb-vm::float-registers sb-vm::stack))) ; SB names +(defconstant +lock-prefix-present+ #x80) +;;; v---- size prefix presence bit +(defconstant +byte-size-prefix+ #b100) +(defconstant +word-size-prefix+ #b101) +(defconstant +dword-size-prefix+ #b110) +(defconstant +qword-size-prefix+ #b111) +(defun lockp (prefix) (if (logtest +lock-prefix-present+ prefix) :lock)) +(defmacro opsize-prefix-present (byte) `(logtest ,byte #b100)) +(defmacro opsize-prefix-keyword (byte) + `(svref #(:byte :word :dword :qword) (logand ,byte #b11))) +(defun pick-operand-size (prefix operand1 &optional operand2) + (acond ((logtest prefix #b100) (opsize-prefix-keyword prefix)) + (operand2 (matching-operand-size operand1 operand2)) + (t (operand-size operand1)))) +(defun encode-size-prefix (prefix) + (case prefix + (:byte +byte-size-prefix+) + (:word +word-size-prefix+) + (:dword +dword-size-prefix+) + (:qword +qword-size-prefix+))) +;;; Prefix is a mandatory operand to the encoder, so if none were +;;; written then this correctly prepends a 0. +(defun sb-assem::extract-prefix-keywords (args &aux (lockp 0) (size 0)) + (loop (acond ((eq (car args) :lock) (setq lockp +lock-prefix-present+)) + ((encode-size-prefix (car args)) (setq size it)) + (t (return (cons (logior lockp size) args)))) + (pop args))) +(defun sb-assem::decode-prefix (args) ; for trace file only + (let ((b (car args))) + (if (zerop b) + (cdr args) + (cons (append (if (logtest +lock-prefix-present+ b) '(:lock)) + (if (opsize-prefix-present b) (list (opsize-prefix-keyword b)))) + (cdr args))))) + ;;; a REG object discards all information about a TN except its storage base ;;; (a/k/a register class), size class (for GPRs), and encoding. ;;; The disassembler also uses this structure. @@ -60,12 +96,13 @@ ;;; REX-R A REX prefix with the "register" bit set was found ;;; REX-X A REX prefix with the "index" bit set was found ;;; REX-B A REX prefix with the "base" bit set was found -(defconstant +allow-qword-imm+ #b1000000000) -(defconstant +imm-size-8+ #b0100000000) -(defconstant +operand-size-8+ #b0010000000) -(defconstant +operand-size-16+ #b0001000000) -(defconstant +fs-segment+ #b0000100000) -(defconstant +rex+ #b0000010000) +(defconstant +allow-qword-imm+ #b10000000000) +(defconstant +imm-size-8+ #b01000000000) +(defconstant +operand-size-8+ #b00100000000) +(defconstant +operand-size-16+ #b00010000000) +(defconstant +fs-segment+ #b00001000000) +(defconstant +gs-segment+ #b00000100000) +(defconstant +rex+ #b00000010000) ;;; The next 4 exactly correspond to the bits in the REX prefix itself, ;;; to avoid unpacking and stuffing into inst-properties one at a time. (defconstant +rex-w+ #b1000) @@ -82,8 +119,6 @@ (:oword 16) (:hword 32))) -(defun is-size-p (arg) (member arg '(:byte :word :dword :qword))) - ;;; If chopping IMM to 32 bits and sign-extending is equal to the original value, ;;; return the signed result, which the CPU will always extend to 64 bits. ;;; Notably this allows MOST-POSITIVE-WORD to be an immediate constant. @@ -155,8 +190,11 @@ value)) :printer (lambda (value stream dstate) (cond (stream + ;; This use of MAYBE-NOTE-STATIC-LISPOBJ gets us the + ;; code blob called using canonical 'CALL rel32' form. (or #+immobile-space - (and (integerp value) (maybe-note-lisp-callee value dstate)) + (and (integerp value) + (maybe-note-static-lispobj value dstate)) (maybe-note-assembler-routine value nil dstate)) (print-label value stream dstate)) (t @@ -213,14 +251,10 @@ ;; if it is in a location corresponding to an absolute code fixup. (if (and (memq size '(:dword :qword)) (memq opcode '(mov cmp push)) - (maybe-note-static-symbol value dstate)) + (maybe-note-static-lispobj value dstate t)) (princ16 value stream) (princ value stream)))))) -(define-arg-type signed-imm-data/asm-routine - :type 'signed-imm-data - :printer #'print-imm/asm-routine) - ;;; Used by those instructions that have a default operand size of ;;; :qword. Nevertheless the immediate is at most of size :dword. ;;; The only instruction of this kind having a variant with an immediate @@ -303,11 +337,11 @@ (:le . 14) (:ng . 14) (:nle . 15) (:g . 15)) #'equal) -(defconstant-eqx sb-vm::+condition-name-vec+ - #.(let ((vec (make-array 16 :initial-element nil))) - (dolist (cond +conditions+ vec) - (when (null (aref vec (cdr cond))) - (setf (aref vec (cdr cond)) (car cond))))) +(defconstant-eqx +condition-name-vec+ + (let ((vec (make-array 16 :initial-element nil))) + (dolist (cond +conditions+ vec) + (when (null (aref vec (cdr cond))) + (setf (aref vec (cdr cond)) (car cond))))) #'equalp) ;;; SSE shuffle patterns. The names end in the number of bits of the @@ -325,10 +359,12 @@ (define-sse-shuffle-arg-type sse-shuffle-pattern-2-2 "#b~2,'0B") (define-sse-shuffle-arg-type sse-shuffle-pattern-8-4 "#4r~4,4,'0R")) -(define-arg-type condition-code :printer sb-vm::+condition-name-vec+) +(define-arg-type condition-code :printer +condition-name-vec+) (defun conditional-opcode (condition) (cdr (assoc condition +conditions+ :test #'eq))) +(defun negate-condition (name) + (aref +condition-name-vec+ (logxor 1 (conditional-opcode name)))) ;;;; disassembler instruction formats @@ -442,7 +478,7 @@ (width :field (byte 1 0) :type 'width) (reg/mem :fields (list (byte 2 14) (byte 3 8)) :type 'reg/mem :reader regrm-inst-r/m) - (reg :field (byte 3 11) :type 'reg) + (reg :field (byte 3 11) :type 'reg :reader regrm-inst-reg) ;; optional fields (imm)) @@ -481,13 +517,6 @@ (reg/mem :type 'sized-reg/mem) (imm :type 'signed-imm-data)) -(define-instruction-format (reg/mem-imm/asm-routine 16 - :include reg/mem-imm - :default-printer - '(:name :tab reg/mem ", " imm)) - (reg/mem :type 'sized-reg/mem) - (imm :type 'signed-imm-data/asm-routine)) - ;;; Same as reg/mem, but with using the accumulator in the default printer (define-instruction-format (accum-reg/mem 16 @@ -533,22 +562,6 @@ (op :field (byte 5 11)) (reg :field (byte 3 8) :type 'reg-b)) -;;; Same as reg/mem, but with a prefix of #x0F -(define-instruction-format (ext-reg/mem 24 - :default-printer '(:name :tab reg/mem)) - (prefix :field (byte 8 0) :value #x0F) - (op :fields (list (byte 7 9) (byte 3 19))) - (width :field (byte 1 8) :type 'width) - (reg/mem :fields (list (byte 2 22) (byte 3 16)) - :type 'sized-reg/mem) - ;; optional fields - (imm)) - -(define-instruction-format (ext-reg/mem-imm 24 - :include ext-reg/mem - :default-printer - '(:name :tab reg/mem ", " imm)) - (imm :type 'signed-imm-data)) (define-instruction-format (ext-reg/mem-no-width+imm8 24 :include ext-reg/mem-no-width @@ -569,6 +582,7 @@ (define-instruction-format (xmm-xmm/mem 24 :default-printer '(:name :tab reg ", " reg/mem)) + (rex) ; optional (x0f :field (byte 8 0) :value #x0f) (op :field (byte 8 8)) (reg/mem :fields (list (byte 2 22) (byte 3 16)) @@ -581,6 +595,7 @@ :default-printer '(:name :tab reg ", " reg/mem)) (prefix :field (byte 8 0)) + (rex) ; optional (x0f :field (byte 8 8) :value #x0f) (op :field (byte 8 16)) (reg/mem :fields (list (byte 2 30) (byte 3 24)) @@ -588,23 +603,11 @@ (reg :field (byte 3 27) :type 'xmmreg) (imm)) -(define-instruction-format (ext-rex-xmm-xmm/mem 40 - :default-printer - '(:name :tab reg ", " reg/mem)) - (prefix :field (byte 8 0)) - (rex :field (byte 4 12) :value #b0100) - (wrxb :field (byte 4 8) :type 'wrxb) - (x0f :field (byte 8 16) :value #x0f) - (op :field (byte 8 24)) - (reg/mem :fields (list (byte 2 38) (byte 3 32)) - :type 'xmmreg/mem) - (reg :field (byte 3 35) :type 'xmmreg) - (imm)) - (define-instruction-format (ext-2byte-xmm-xmm/mem 40 :default-printer '(:name :tab reg ", " reg/mem)) (prefix :field (byte 8 0)) + (rex) ; optional (x0f :field (byte 8 8) :value #x0f) (op1 :field (byte 8 16)) ; #x38 or #x3a (op2 :field (byte 8 24)) @@ -612,19 +615,6 @@ :type 'xmmreg/mem) (reg :field (byte 3 35) :type 'xmmreg)) -(define-instruction-format (ext-rex-2byte-xmm-xmm/mem 48 - :default-printer - '(:name :tab reg ", " reg/mem)) - (prefix :field (byte 8 0)) - (rex :field (byte 4 12) :value #b0100) - (wrxb :field (byte 4 8) :type 'wrxb) - (x0f :field (byte 8 16) :value #x0f) - (op1 :field (byte 8 24)) ; #x38 or #x3a - (op2 :field (byte 8 32)) - (reg/mem :fields (list (byte 2 46) (byte 3 40)) - :type 'xmmreg/mem) - (reg :field (byte 3 43) :type 'xmmreg)) - ;;; Same as xmm-xmm/mem etc., but with direction bit. (define-instruction-format (ext-xmm-xmm/mem-dir 32 @@ -636,15 +626,6 @@ (op :field (byte 7 17)) (dir :field (byte 1 16))) -(define-instruction-format (ext-rex-xmm-xmm/mem-dir 40 - :include ext-rex-xmm-xmm/mem - :default-printer - `(:name - :tab - ,(swap-if 'dir 'reg ", " 'reg/mem))) - (op :field (byte 7 25)) - (dir :field (byte 1 24))) - ;;; Instructions having an XMM register as one operand ;;; and a constant (unsigned) byte as the other. @@ -652,6 +633,7 @@ :default-printer '(:name :tab reg/mem ", " imm)) (prefix :field (byte 8 0)) + (rex) ; optional (x0f :field (byte 8 8) :value #x0f) (op :field (byte 8 16)) (/i :field (byte 3 27)) @@ -660,26 +642,13 @@ :type 'xmmreg-b) (imm :type 'imm-byte)) -(define-instruction-format (ext-rex-xmm-imm 40 - :default-printer - '(:name :tab reg/mem ", " imm)) - (prefix :field (byte 8 0)) - (rex :field (byte 4 12) :value #b0100) - (wrxb :field (byte 4 8) :type 'wrxb) - (x0f :field (byte 8 16) :value #x0f) - (op :field (byte 8 24)) - (/i :field (byte 3 35)) - (b11 :field (byte 2 38) :value #b11) - (reg/mem :field (byte 3 32) - :type 'xmmreg-b) - (imm :type 'imm-byte)) - ;;; Instructions having an XMM register as one operand and a general- ;;; -purpose register or a memory location as the other operand. (define-instruction-format (xmm-reg/mem 24 :default-printer '(:name :tab reg ", " reg/mem)) + (rex) ; optional (x0f :field (byte 8 0) :value #x0f) (op :field (byte 8 8)) (reg/mem :fields (list (byte 2 22) (byte 3 16)) @@ -698,23 +667,11 @@ (reg :field (byte 3 27) :type 'xmmreg) (imm)) -(define-instruction-format (ext-rex-xmm-reg/mem 40 - :default-printer - '(:name :tab reg ", " reg/mem)) - (prefix :field (byte 8 0)) - (rex :field (byte 4 12) :value #b0100) - (wrxb :field (byte 4 8) :type 'wrxb) - (x0f :field (byte 8 16) :value #x0f) - (op :field (byte 8 24)) - (reg/mem :fields (list (byte 2 38) (byte 3 32)) - :type 'sized-reg/mem) - (reg :field (byte 3 35) :type 'xmmreg) - (imm)) - (define-instruction-format (ext-2byte-xmm-reg/mem 40 :default-printer '(:name :tab reg ", " reg/mem)) (prefix :field (byte 8 0)) + (rex) ; optional (x0f :field (byte 8 8) :value #x0f) (op1 :field (byte 8 16)) (op2 :field (byte 8 24)) @@ -728,6 +685,7 @@ (define-instruction-format (reg-xmm/mem 24 :default-printer '(:name :tab reg ", " reg/mem)) + (rex) ; optional (x0f :field (byte 8 0) :value #x0f) (op :field (byte 8 8)) (reg/mem :fields (list (byte 2 22) (byte 3 16)) @@ -738,24 +696,13 @@ :default-printer '(:name :tab reg ", " reg/mem)) (prefix :field (byte 8 0)) + (rex) ; optional (x0f :field (byte 8 8) :value #x0f) (op :field (byte 8 16)) (reg/mem :fields (list (byte 2 30) (byte 3 24)) :type 'xmmreg/mem) (reg :field (byte 3 27) :type 'reg)) -(define-instruction-format (ext-rex-reg-xmm/mem 40 - :default-printer - '(:name :tab reg ", " reg/mem)) - (prefix :field (byte 8 0)) - (rex :field (byte 4 12) :value #b0100) - (wrxb :field (byte 4 8) :type 'wrxb) - (x0f :field (byte 8 16) :value #x0f) - (op :field (byte 8 24)) - (reg/mem :fields (list (byte 2 38) (byte 3 32)) - :type 'xmmreg/mem) - (reg :field (byte 3 35) :type 'reg)) - ;;; Instructions having a general-purpose register or a memory location ;;; as one operand and an a XMM register as the other operand. @@ -763,6 +710,7 @@ :default-printer '(:name :tab reg/mem ", " reg)) (prefix :field (byte 8 0)) + (rex) ; optional (x0f :field (byte 8 8) :value #x0f) (op :field (byte 8 16)) (reg/mem :fields (list (byte 2 30) (byte 3 24)) @@ -770,23 +718,11 @@ (reg :field (byte 3 27) :type 'xmmreg) (imm)) -(define-instruction-format (ext-rex-reg/mem-xmm 40 - :default-printer - '(:name :tab reg/mem ", " reg)) - (prefix :field (byte 8 0)) - (rex :field (byte 4 12) :value #b0100) - (wrxb :field (byte 4 8) :type 'wrxb) - (x0f :field (byte 8 16) :value #x0f) - (op :field (byte 8 24)) - (reg/mem :fields (list (byte 2 38) (byte 3 32)) - :type 'reg/mem) - (reg :field (byte 3 35) :type 'xmmreg) - (imm)) - (define-instruction-format (ext-2byte-reg/mem-xmm 40 :default-printer '(:name :tab reg/mem ", " reg)) (prefix :field (byte 8 0)) + (rex) ; optional (x0f :field (byte 8 8) :value #x0f) (op1 :field (byte 8 16)) (op2 :field (byte 8 24)) @@ -794,49 +730,15 @@ (reg :field (byte 3 35) :type 'xmmreg) (imm)) -(define-instruction-format (ext-rex-2byte-reg/mem-xmm 48 - :default-printer - '(:name :tab reg/mem ", " reg)) - (prefix :field (byte 8 0)) - (rex :field (byte 4 12) :value #b0100) - (wrxb :field (byte 4 8) :type 'wrxb) - (x0f :field (byte 8 16) :value #x0f) - (op1 :field (byte 8 24)) - (op2 :field (byte 8 32)) - (reg/mem :fields (list (byte 2 46) (byte 3 40)) :type 'reg/mem) - (reg :field (byte 3 43) :type 'xmmreg) - (imm)) - ;;; Instructions having a general-purpose register as one operand and an a ;;; general-purpose register or a memory location as the other operand, ;;; and using a prefix byte. -(define-instruction-format (ext-prefix-reg-reg/mem 32 - :default-printer - '(:name :tab reg ", " reg/mem)) - (prefix :field (byte 8 0)) - (x0f :field (byte 8 8) :value #x0f) - (op :field (byte 8 16)) - (reg/mem :fields (list (byte 2 30) (byte 3 24)) - :type 'sized-reg/mem) - (reg :field (byte 3 27) :type 'reg)) - -(define-instruction-format (ext-rex-prefix-reg-reg/mem 40 - :default-printer - '(:name :tab reg ", " reg/mem)) - (prefix :field (byte 8 0)) - (rex :field (byte 4 12) :value #b0100) - (wrxb :field (byte 4 8) :type 'wrxb) - (x0f :field (byte 8 16) :value #x0f) - (op :field (byte 8 24)) - (reg/mem :fields (list (byte 2 38) (byte 3 32)) - :type 'sized-reg/mem) - (reg :field (byte 3 35) :type 'reg)) - (define-instruction-format (ext-2byte-prefix-reg-reg/mem 40 :default-printer '(:name :tab reg ", " reg/mem)) (prefix :field (byte 8 0)) + (rex) ; optional (x0f :field (byte 8 8) :value #x0f) (op1 :field (byte 8 16)) ; #x38 or #x3a (op2 :field (byte 8 24)) @@ -844,19 +746,6 @@ :type 'sized-reg/mem) (reg :field (byte 3 35) :type 'reg)) -(define-instruction-format (ext-rex-2byte-prefix-reg-reg/mem 48 - :default-printer - '(:name :tab reg ", " reg/mem)) - (prefix :field (byte 8 0)) - (rex :field (byte 4 12) :value #b0100) - (wrxb :field (byte 4 8) :type 'wrxb) - (x0f :field (byte 8 16) :value #x0f) - (op1 :field (byte 8 24)) ; #x38 or #x3a - (op2 :field (byte 8 32)) - (reg/mem :fields (list (byte 2 46) (byte 3 40)) - :type 'sized-reg/mem) - (reg :field (byte 3 43) :type 'reg)) - ;; XMM comparison instruction (defconstant-eqx +sse-conditions+ @@ -929,49 +818,15 @@ (op :field (byte 16 0)) (code :field (byte 8 16) :reader word-imm-code)) -;;; F3 escape map - Needs a ton more work. - -(define-instruction-format (F3-escape 24) - (prefix1 :field (byte 8 0) :value #xF3) - (prefix2 :field (byte 8 8) :value #x0F) - (op :field (byte 8 16))) - -(define-instruction-format (rex-F3-escape 32) - ;; F3 is a legacy prefix which was generalized to select an alternate opcode - ;; map. Legacy prefixes are encoded in the instruction before a REX prefix. - (prefix1 :field (byte 8 0) :value #xF3) - (rex :field (byte 4 12) :value 4) ; "prefix2" - (wrxb :field (byte 4 8) :type 'wrxb) - (prefix3 :field (byte 8 16) :value #x0F) - (op :field (byte 8 24))) - -(define-instruction-format (F3-escape-reg-reg/mem 32 - :include F3-escape - :default-printer - '(:name :tab reg ", " reg/mem)) - (reg/mem :fields (list (byte 2 30) (byte 3 24)) :type 'sized-reg/mem) - (reg :field (byte 3 27) :type 'reg)) - -(define-instruction-format (rex-F3-escape-reg-reg/mem 40 - :include rex-F3-escape - :default-printer - '(:name :tab reg ", " reg/mem)) - (reg/mem :fields (list (byte 2 38) (byte 3 32)) :type 'sized-reg/mem) - (reg :field (byte 3 35) :type 'reg)) - ;;;; primitive emitters (define-bitfield-emitter emit-word 16 (byte 16 0)) -;; FIXME: a nice enhancement would be to save all sexprs of small functions -;; within the same file, and drop them at the end. -;; Expressly declaimed inline definitions would be saved as usual though. -(declaim (inline emit-dword)) +(declaim (maybe-inline emit-dword)) (define-bitfield-emitter emit-dword 32 (byte 32 0)) -(declaim (notinline emit-dword)) (define-bitfield-emitter emit-qword 64 (byte 64 0)) @@ -984,7 +839,7 @@ (defun emit-signed-dword (segment value) (declare (type sb-assem:segment segment) (type (signed-byte 32) value)) - (declare (inline emit-dword)) + #-sb-xc-host (declare (inline emit-dword)) (emit-dword segment value)) (define-bitfield-emitter emit-mod-reg-r/m-byte 8 @@ -997,14 +852,14 @@ ;;;; fixup emitters (defun emit-absolute-fixup (segment fixup &optional quad-p) - (note-fixup segment (if quad-p :absolute64 :absolute) fixup) + (note-fixup segment (if quad-p :absolute :abs32) fixup) (let ((offset (fixup-offset fixup))) (if quad-p (emit-qword segment offset) (emit-signed-dword segment offset)))) (defun emit-relative-fixup (segment fixup) - (note-fixup segment :relative fixup) + (note-fixup segment :rel32 fixup) (emit-signed-dword segment (fixup-offset fixup))) @@ -1018,19 +873,17 @@ (:predicate nil) (:copier nil)) (label nil :type label) - (addend 0 :type (signed-byte 32))) + ;; The addend of :CODE computes the tagged code object. + ;; It could be represented by just a label, except that the assembler can't + ;; directly reference labels in the boxed header. A label would need a negative + ;; POSN to represent such a location. + (addend 0 :type (or (signed-byte 32) (eql :code)))) (declaim (freeze-type label+addend)) ;;;; the effective-address (ea) structure -(defstruct (ea (:constructor %ea (disp base index scale)) - (:constructor %make-ea-dont-use (size disp base index scale)) +(defstruct (ea (:constructor %ea (segment disp base index scale)) (:copier nil)) - ;; FIXME: SIZE is unnecessary, but is here for backward-compatibility - ;; temporarily anyway. Our code only creates EAs with :unspecific, - ;; but 3rd-party uses of the assembler might expect the size to do something. - ;; All such code will have to be fixed before removing this slot. - (size :unspecific :type (member :byte :word :dword :qword :unspecific) - :read-only t) + (segment nil :type (member :cs :gs) :read-only t) (base nil :type (or tn null) :read-only t) (index nil :type (or tn null) :read-only t) (scale 1 :type (member 1 2 4 8) :read-only t) @@ -1071,8 +924,8 @@ ;;; (EA displacement &OPTIONAL base-register index-register scale) ;;; (EA base-register &OPTIONAL index-register scale) ;;; -;;; mnemonic device: the syntax is like AT&T "disp(%rbase,%rindex,scale)" -;;; where the leading "disp" is optional. +;;; mnemonic device: the syntax is like AT&T "%seg:disp(%rbase,%rindex,scale)" +;;; where the leading "seg" and "disp" are optional. ;;; ;;; Most instructions can determine an EA size based on the size of a register ;;; operand. The few that can't are mem+immediate mode instructions, and @@ -1083,17 +936,32 @@ ;;; Intel : test byte ptr [rax], 40 ;;; SBCL : (TEST :BYTE (EA RAX-TN) #x40) ;;; -(defun ea (displacement &optional base (index nil indexp) (scale 1 scalep)) - (when (or (null displacement) (tn-p displacement)) - (aver (not scalep)) - (setq scale (if indexp index 1) - index base - base displacement - displacement 0)) - (%ea displacement base index scale)) +(defun ea (&rest args) ; seg displacement base index scale + (declare (dynamic-extent args)) + (let ((seg :cs) disp) + (let ((first (car args))) + (case first + (:gs (setq seg first) (pop args)) + (:cs (pop args)))) + (let ((first (car args))) + ;; Rather than checking explicitly for all the things that are legal to be + ;; a displacement (i.e. LABEL, FIXUP, INTEGER), look for (NOT (OR TN NULL).) + ;; That is, NIL must be a placeholder for absence of base register, + ;; and not a displacement. + (unless (typep first '(or tn null)) + (setq disp first) + (pop args))) + ;; The minimal EA is either an absolute address or an unindexed base register. + ;; So gotta have at least one of disp or base. Enforce by doing either of two + ;; destructuring-binds depending on whether DISP was present. + (if disp + (destructuring-bind (&optional base index (scale 1)) args + (%ea seg disp base index scale)) + (destructuring-bind (base &optional index (scale 1)) args + (%ea seg 0 base index scale))))) (defun rip-relative-ea (label &optional addend) - (%ea (if addend (make-label+addend label addend) label) rip-tn nil 1)) + (%ea :cs (if addend (make-label+addend label addend) label) rip-tn nil 1)) (defun emit-byte-displacement-backpatch (segment target) (emit-back-patch segment 1 @@ -1121,19 +989,19 @@ ;;; set defined by the AMD64 architecture, and indices 20, 21, 22, 23 are ;;; for the legacy high byte registers AH,CH,DH,BH respectively. ;;; (indices 16 through 19 are unused) -(defun !make-gpr-id (size index) +(defun make-gpr-id (size index) (logior (ash (if (eq size :byte) (the (mod 24) index) (the (mod 16) index)) 3) (ash (or (position size #(:qword :dword :word :byte)) (error "Bad register size ~s" size)) 1))) -(defun !make-fpr-id (index) +(defun make-fpr-id (index size) (declare (type (mod 16) index)) - (logior (ash index 3) 1)) ; low bit = FPR, not GPR - -(defun !make-avx2-id (index) - (declare (type (mod 16) index)) - (logior (ash index 3) 3)) + (ecase size + (:xmm (logior (ash index 3) 1)) ; low bit = FPR, not GPR + (:ymm (logior (ash index 3) 3)))) +(defun is-ymm-id-p (reg-id) + (= (ldb (byte 3 0) reg-id) 3)) (declaim (inline is-gpr-id-p gpr-id-size-class reg-id-num)) (defun is-gpr-id-p (reg-id) @@ -1172,8 +1040,7 @@ sb-vm::+byte-register-names+) t) (gpr-id-size-class id))) - #+avx2 - ((is-avx2-id-p id) + ((is-ymm-id-p id) #.(coerce (loop for i below 16 collect (format nil "YMM~D" i)) 'vector)) (t @@ -1201,22 +1068,15 @@ (defun emit-byte+reg (seg byte reg) (emit-byte seg (+ byte (reg-encoding reg seg)))) -(defmethod print-object ((reg reg) stream) - (if *print-readably* - ;; cross-compiled DEFMETHOD can't use call-next-method - #+sb-xc (default-structure-print reg stream *current-level-in-print*) - #-sb-xc (call-next-method) - (write-string (reg-name reg) stream))) - ;;; The GPR for any size and register number is a unique atom. Return it. (defun get-gpr (size number) (svref (load-time-value (coerce (append - (loop for i from 0 below 16 collect (!make-reg (!make-gpr-id :qword i))) - (loop for i from 0 below 16 collect (!make-reg (!make-gpr-id :dword i))) - (loop for i from 0 below 16 collect (!make-reg (!make-gpr-id :word i))) + (loop for i from 0 below 16 collect (!make-reg (make-gpr-id :qword i))) + (loop for i from 0 below 16 collect (!make-reg (make-gpr-id :dword i))) + (loop for i from 0 below 16 collect (!make-reg (make-gpr-id :word i))) ;; byte reg vector is #(AL CL ... R15B AH CH DH BH) - (loop for i from 0 below 20 collect (!make-reg (!make-gpr-id :byte i)))) + (loop for i from 0 below 20 collect (!make-reg (make-gpr-id :byte i)))) 'vector) t) (+ (if (eq size :byte) (the (mod 20) number) (the (mod 16) number)) @@ -1226,13 +1086,22 @@ (:word 32) (:byte 48))))) -(defun get-fpr (number) - (svref (load-time-value - (coerce (loop for i from 0 below 16 - collect (!make-reg (!make-fpr-id i))) - 'vector) - t) - number)) +(defun get-fpr (regset number) + (ecase regset + (:xmm + (svref (load-time-value + (coerce (loop for i from 0 below 16 + collect (!make-reg (make-fpr-id i :xmm))) + 'vector) + t) + number)) + (:ymm + (svref (load-time-value + (coerce (loop for i from 0 below 16 + collect (!make-reg (make-fpr-id i :ymm))) + 'vector) + t) + number)))) ;;; Given a TN which maps to a GPR, return the corresponding REG. ;;; This is called during operand lowering, and also for emitting an EA @@ -1257,15 +1126,14 @@ operand) ((eq (sb-name (sc-sb (tn-sc operand))) 'registers) (tn-reg operand)) - #+avx2 ((memq (sc-name (tn-sc operand)) - '(avx2-reg + '(ymm-reg int-avx2-reg double-avx2-reg single-avx2-reg)) - (get-avx2 (tn-offset operand))) + (get-fpr :ymm (tn-offset operand))) ((eq (sb-name (sc-sb (tn-sc operand))) 'float-registers) - (get-fpr (tn-offset operand))) + (get-fpr :xmm (tn-offset operand))) (t ; a stack SC or constant operand))) operands)) @@ -1300,6 +1168,8 @@ (if (typep disp 'label+addend) (values (label+addend-label disp) (label+addend-addend disp)) (values disp 0)) + (when (eq addend :code) + (setq addend (- sb-vm:other-pointer-lowtag (component-header-length)))) ;; To point at ADDEND bytes beyond the label, pretend that the PC ;; at which the EA occurs is _smaller_ by that amount. (emit-dword-displacement-backpatch @@ -1330,7 +1200,7 @@ (if (location= index sb-vm::rsp-tn) (error "can't index off of RSP") (reg-encoding (if xmm-index - (get-fpr (tn-offset index)) + (get-fpr :xmm (tn-offset index)) (tn-reg index)) segment)))) (base (if (null base) #b101 base-encoding))) @@ -1398,8 +1268,10 @@ (declare (type (or tn reg ea fixup null) thing) (type (or tn reg integer null) reg) (type (member :byte :word :dword :qword :do-not-set) operand-size)) - ;; Legacy prefixes are order-insensitive, but let's match the + ;; Legacy prefixes are order-insensitive, but let's approximately match the ;; output of the system assembler for consistency's sake. + (when (and (ea-p thing) (eq (ea-segment thing) :gs)) + (emit-byte segment #x65)) (when (eq operand-size :word) (emit-byte segment #x66)) (ecase lock @@ -1428,9 +1300,6 @@ (let ((id (reg-id thing))) (when (is-gpr-id-p id) (aref #(:qword :dword :word :byte) (gpr-id-size-class id))))) - (ea ; FIXME: remove this case, let EA fall through to returning NIL - (unless (eq (ea-size thing) :unspecific) - (ea-size thing))) (fixup ;; GNA. Guess who spelt "flavor" correctly first time round? ;; There's a strong argument in my mind to change all uses of @@ -1441,6 +1310,8 @@ (t nil))) +;;; FIXME: I'm fairly certain that this can be removed, as there should be +;;; no way for operand sizes to differ. (defun matching-operand-size (dst src) (let ((dst-size (operand-size dst)) (src-size (operand-size src))) @@ -1480,6 +1351,11 @@ (declare (ignore value)) (dstate-setprop dstate +fs-segment+)))) nil :print-name nil)) +(define-instruction gs (segment) + (:printer byte ((op #x65 :prefilter (lambda (dstate value) + (declare (ignore value)) + (dstate-setprop dstate +gs-segment+)))) + nil :print-name nil)) (define-instruction lock (segment) (:printer byte ((op #xF0)) nil)) @@ -1506,26 +1382,24 @@ ;;; This function SHOULD NOT BE USED. It is only for compatibility. (defun sb-vm::reg-in-size (tn size) + ;; We don't put internal functions through a deprecation cycle. + ;; This should annoy maintainers enough to remove their misuses of this. + (warn "Don't use REG-IN-SIZE") (sized-thing (tn-reg tn) size)) -(define-instruction mov (segment maybe-size dst &optional src) +(define-instruction mov (segment &prefix prefix dst src) ;; immediate to register (:printer reg ((op #b1011 :prefilter (lambda (dstate value) (dstate-setprop dstate +allow-qword-imm+) value)) - (imm nil :type 'signed-imm-data/asm-routine)) + (imm nil :type 'signed-imm-data)) '(:name :tab reg ", " imm)) ;; register to/from register/memory (:printer reg-reg/mem-dir ((op #b100010))) ;; immediate to register/memory - (:printer reg/mem-imm/asm-routine ((op '(#b1100011 #b000)))) + (:printer reg/mem-imm ((op '(#b1100011 #b000)))) (:emitter - (let ((size (cond (src - (aver (is-size-p maybe-size)) - maybe-size) - (t - (setq src dst dst maybe-size) - (matching-operand-size dst src))))) + (let ((size (pick-operand-size prefix dst src))) (emit-mov segment size (sized-thing dst size) (sized-thing src size))))) (defun emit-mov (segment size dst src) @@ -1640,15 +1514,6 @@ (let ((dst-size (cadr sizes)) ; DST-SIZE size governs the OPERAND-SIZE (src-size (car sizes))) ; SRC-SIZE is controlled by the opcode (aver (> (size-nbyte dst-size) (size-nbyte src-size))) - ;; Zero-extending into a 64-bit register is the same as zero-extending - ;; into the 32-bit register. - (when (and (not signed-p) (eq dst-size :qword)) - ;; It's slightly strange for the assembler to output a different instruction - ;; from the one you said to. I'm not sure how to feel about this. - ;; There might be reasons you wanted to emit a certain thing. - (when (eq src-size :dword) ; this is a straight MOV - (return-from emit* (emit-mov segment :dword dst src))) - (setf dst-size :dword)) (emit-prefixes segment (sized-thing src src-size) dst dst-size) (if (eq src-size :dword) ;; AMD calls this MOVSXD. If emitted without REX.W, it writes @@ -1670,7 +1535,8 @@ (define-instruction movzx (segment sizes dst src) (:printer move-with-extension ((op #b1011011))) - (:emitter (emit* segment sizes dst src nil)))) + (:emitter (aver (not (equal sizes '(:dword :qword)))) ; should use MOV instead + (emit* segment sizes dst src nil)))) (flet ((emit* (segment thing gpr-opcode mem-opcode subcode) (let ((size (or (operand-size thing) :qword))) @@ -1738,7 +1604,7 @@ ;;; The disassembler additionally correctly matches encoding variants ;;; that the assembler doesn't generate, for example 4E90 prints as NOP ;;; and 4F90 as XCHG RAX, R8 (both because REX.R and REX.X are ignored). -(define-instruction xchg (segment operand1 operand2) +(define-instruction xchg (segment &prefix prefix operand1 operand2) ;; This printer matches all patterns that encode exchanging RAX with ;; R8, EAX with R8D, or AX with R8W. These consist of the opcode #x90 ;; with a REX prefix with REX.B = 1, and possibly the #x66 prefix. @@ -1751,7 +1617,11 @@ ;; Register/Memory with Register. (:printer reg-reg/mem ((op #b1000011))) (:emitter - (let ((size (matching-operand-size operand1 operand2))) + ;; Not parsing a :LOCK prefix is ok, because: + ;; "If a memory operand is referenced, the processor's locking protocol is automatically + ;; implemented for the duration of the exchange operation, regardless of the presence + ;; or absence of the LOCK prefix or of the value of the IOPL." + (let ((size (pick-operand-size prefix operand1 operand2))) (labels ((xchg-acc-with-something (acc something) (if (and (not (eq size :byte)) (gpr-p something) @@ -1777,41 +1647,33 @@ (t (error "bogus args to XCHG: ~S ~S" operand1 operand2))))))) -(define-instruction lea (segment maybe-size dst &optional src) +(define-instruction lea (segment &prefix prefix dst src) (:printer reg-reg/mem ((op #b1000110) (width 1) (reg/mem nil :use-label #'lea-compute-label :printer #'lea-print-ea))) (:emitter - (let ((size (cond (src - (aver (is-size-p maybe-size)) - maybe-size) - (t - (setq src dst dst maybe-size) - (operand-size dst))))) + (let ((size (pick-operand-size prefix dst))) (aver (member size '(:dword :qword))) (emit-prefixes segment src dst size) (emit-byte segment #x8D) (emit-ea segment src dst)))) -(define-instruction cmpxchg (segment maybe-size dst &optional src prefix) +(define-instruction cmpxchg (segment &prefix prefix dst src) ;; Register/Memory with Register. (:printer ext-reg-reg/mem ((op #b1011000)) '(:name :tab reg/mem ", " reg)) (:emitter - (let ((size (cond ((is-size-p maybe-size) maybe-size) - (t - (shiftf prefix src dst maybe-size) - (matching-operand-size src dst))))) + (let ((size (pick-operand-size prefix dst src))) (aver (gpr-p src)) - (emit-prefixes segment dst (sized-thing src size) size :lock prefix) + (emit-prefixes segment dst (sized-thing src size) size :lock (lockp prefix)) (emit-bytes segment #x0F (opcode+size-bit #xB0 size)) (emit-ea segment dst src)))) -(define-instruction cmpxchg16b (segment mem &optional prefix) +(define-instruction cmpxchg16b (segment &prefix prefix mem) (:printer ext-reg/mem-no-width ((op '(#xC7 1)))) (:emitter (aver (not (gpr-p mem))) - (emit-prefixes segment mem nil :qword :lock prefix) + (emit-prefixes segment mem nil :qword :lock (lockp prefix)) (emit-bytes segment #x0F #xC7) (emit-ea segment mem 1))) @@ -1847,23 +1709,21 @@ ;;;; arithmetic -(flet ((emit* (name segment maybe-size dst src lockp opcode) - (let ((size (cond ((is-size-p maybe-size) maybe-size) - (t - (shiftf lockp src dst maybe-size) - (matching-operand-size dst src))))) +(flet ((emit* (name segment prefix dst src opcode) + (let ((size (pick-operand-size prefix dst src))) (setq src (sized-thing src size) dst (sized-thing dst size)) (acond ((and (neq size :byte) (plausible-signed-imm8-operand-p src size)) - (emit-prefixes segment dst nil size :lock lockp) + (emit-prefixes segment dst nil size :lock (lockp prefix)) (emit-byte segment #x83) - (emit-ea segment dst opcode) + (emit-ea segment dst opcode :remaining-bytes 1) (emit-byte segment it)) ((or (integerp src) (and (fixup-p src) - (memq (fixup-flavor src) '(:layout :immobile-symbol)))) - (emit-prefixes segment dst nil size :lock lockp) + (memq (fixup-flavor src) '(:layout-id :layout :immobile-symbol + :gc-barrier)))) + (emit-prefixes segment dst nil size :lock (lockp prefix)) (cond ((accumulator-p dst) (emit-byte segment (opcode+size-bit (dpb opcode (byte 3 3) #b00000100) @@ -1882,12 +1742,12 @@ (cond ((gpr-p src) (values dst src #b00)) ((gpr-p dst) (values src dst #b10)) (t (error "bogus operands to ~A" name))) - (emit-prefixes segment reg/mem reg size :lock lockp) + (emit-prefixes segment reg/mem reg size :lock (lockp prefix)) (emit-byte segment (opcode+size-bit (dpb opcode (byte 3 3) dir-bit) size)) (emit-ea segment reg/mem reg))))))) (macrolet ((define (name subop) - `(define-instruction ,name (segment maybe-size dst &optional src prefix) + `(define-instruction ,name (segment &prefix prefix dst src) (:printer accum-imm ((op ,(dpb subop (byte 3 2) #b0000010)))) (:printer reg/mem-imm ((op '(#b1000000 ,subop)))) ;; The redundant encoding #x82 is invalid in 64-bit mode, @@ -1895,7 +1755,7 @@ (:printer reg/mem-imm ((op '(#b1000001 ,subop)) (width 1) (imm nil :type 'signed-imm-byte))) (:printer reg-reg/mem-dir ((op ,(dpb subop (byte 3 1) #b000000)))) - (:emitter (emit* ,(string name) segment maybe-size dst src prefix ,subop))))) + (:emitter (emit* ,(string name) segment prefix dst src ,subop))))) (define add #b000) (define adc #b010) (define sub #b101) @@ -1905,28 +1765,25 @@ (define or #b001) (define xor #b110))) -(flet ((emit* (segment maybe-size dst lockp opcode subcode) - (let ((size (cond ((is-size-p maybe-size) maybe-size) - (t - (shiftf lockp dst maybe-size) - (operand-size dst))))) - (emit-prefixes segment (sized-thing dst size) nil size :lock lockp) +(flet ((emit* (segment prefix dst opcode subcode) + (let ((size (pick-operand-size prefix dst))) + (emit-prefixes segment (sized-thing dst size) nil size :lock (lockp prefix)) (emit-byte segment (opcode+size-bit (ash opcode 1) size)) (emit-ea segment dst subcode)))) - (define-instruction not (segment maybe-size &optional dst prefix) + (define-instruction not (segment &prefix prefix dst) (:printer reg/mem ((op '(#b1111011 #b010)))) - (:emitter (emit* segment maybe-size dst prefix #b1111011 #b010))) - (define-instruction neg (segment maybe-size &optional dst prefix) + (:emitter (emit* segment prefix dst #b1111011 #b010))) + (define-instruction neg (segment &prefix prefix dst) (:printer reg/mem ((op '(#b1111011 #b011)))) - (:emitter (emit* segment maybe-size dst prefix #b1111011 #b011))) + (:emitter (emit* segment prefix dst #b1111011 #b011))) ;; The one-byte encodings for INC and DEC are used as REX prefixes ;; in 64-bit mode so we always use the two-byte form. - (define-instruction inc (segment maybe-size &optional dst prefix) + (define-instruction inc (segment &prefix prefix dst) (:printer reg/mem ((op '(#b1111111 #b000)))) - (:emitter (emit* segment maybe-size dst prefix #b1111111 #b000))) - (define-instruction dec (segment maybe-size &optional dst prefix) + (:emitter (emit* segment prefix dst #b1111111 #b000))) + (define-instruction dec (segment &prefix prefix dst) (:printer reg/mem ((op '(#b1111111 #b001)))) - (:emitter (emit* segment maybe-size dst prefix #b1111111 #b001)))) + (:emitter (emit* segment prefix dst #b1111111 #b001)))) (define-instruction mul (segment dst src) (:printer accum-reg/mem ((op '(#b1111011 #b100)))) @@ -1975,7 +1832,7 @@ (if imm (emit-byte segment (if (eq imm-size :byte) #x6B #x69)) (emit-bytes segment #x0F #xAF)) - (emit-ea segment src dst) + (emit-ea segment src dst :remaining-bytes (if imm (size-nbyte imm-size) 0)) (if imm (emit-imm-operand segment imm imm-size)))))))) @@ -1992,13 +1849,10 @@ (:printer accum-reg/mem ((op '(#b1111011 #b111)))) (:emitter (emit* segment dst src #b111)))) -(define-instruction bswap (segment maybe-size &optional (reg nil regp)) +(define-instruction bswap (segment &prefix prefix dst) (:printer ext-reg-no-width ((op #b11001))) (:emitter - (multiple-value-bind (size dst) - (if regp - (values maybe-size reg) - (let ((reg maybe-size)) (values (operand-size reg) reg))) + (let ((size (pick-operand-size prefix dst))) (aver (member size '(:dword :qword))) (emit-prefixes segment dst nil size) (emit-byte segment #x0f) @@ -2042,13 +1896,13 @@ (emit-prefixes segment nil nil :qword) (emit-byte segment #x99))) -(define-instruction xadd (segment dst src &optional prefix) +(define-instruction xadd (segment &prefix prefix dst src) ;; Register/Memory with Register. (:printer ext-reg-reg/mem ((op #b1100000)) '(:name :tab reg/mem ", " reg)) (:emitter (aver (gpr-p src)) - (let ((size (matching-operand-size src dst))) - (emit-prefixes segment dst src size :lock prefix) + (let ((size (pick-operand-size prefix dst src))) + (emit-prefixes segment dst src size :lock (lockp prefix)) (emit-bytes segment #x0F (opcode+size-bit #xC0 size)) (emit-ea segment dst src)))) @@ -2061,13 +1915,8 @@ (op :fields (list (byte 6 2) (byte 3 11))) (variablep :field (byte 1 1))) -(flet ((emit* (segment maybe-size dst amount subcode) - (let ((size (cond (amount - (aver (is-size-p maybe-size)) - maybe-size) - (t - (setq amount dst dst maybe-size) - (operand-size dst))))) +(flet ((emit* (segment prefix dst amount subcode) + (let ((size (pick-operand-size prefix dst))) (multiple-value-bind (opcode immed) (case amount (:cl (values #b11010010 nil)) @@ -2075,15 +1924,15 @@ (t (values #b11000000 t))) (emit-prefixes segment (sized-thing dst size) nil size) (emit-byte segment (opcode+size-bit opcode size)) - (emit-ea segment dst subcode) + (emit-ea segment dst subcode :remaining-bytes (if immed 1 0)) (when immed (emit-byte segment amount)))))) (macrolet ((define (name subop) - `(define-instruction ,name (segment maybe-size dst &optional amount) + `(define-instruction ,name (segment &prefix prefix dst amount) (:printer shift-inst ((op '(#b110100 ,subop)))) ; shift by CL or 1 (:printer reg/mem-imm ((op '(#b1100000 ,subop)) (imm nil :type 'imm-byte))) - (:emitter (emit* segment maybe-size dst amount ,subop))))) + (:emitter (emit* segment prefix dst amount ,subop))))) (define rol #b000) (define ror #b001) (define rcl #b010) @@ -2092,40 +1941,34 @@ (define shr #b101) (define sar #b111))) -(flet ((emit* (segment opcode dst src amt) - (declare (type (or (member :cl) (mod 64)) amt)) - (let ((size (matching-operand-size dst src))) +(flet ((emit* (segment opcode prefix dst src amt) + (let ((size (pick-operand-size prefix dst src))) (when (eq size :byte) (error "Double shift requires word or larger operand")) (emit-prefixes segment dst src size) (emit-bytes segment #x0F ;; SHLD = A4 or A5; SHRD = AC or AD (dpb opcode (byte 1 3) (if (eq amt :cl) #xA5 #xA4))) - (emit-ea segment dst src) + (emit-ea segment dst src :remaining-bytes (if (eq amt :cl) 0 1)) (unless (eq amt :cl) - (emit-byte segment amt))))) + (emit-byte segment (the (mod 64) amt)))))) (macrolet ((define (name direction-bit op) - `(define-instruction ,name (segment dst src amt) + `(define-instruction ,name (segment &prefix prefix dst src amt) (:printer ext-reg-reg/mem-no-width ((op ,(logior op #b100)) (imm nil :type 'imm-byte)) '(:name :tab reg/mem ", " reg ", " imm)) (:printer ext-reg-reg/mem-no-width ((op ,(logior op #b101))) '(:name :tab reg/mem ", " reg ", " 'cl)) - (:emitter (emit* segment ,direction-bit dst src amt))))) + (:emitter (emit* segment ,direction-bit prefix dst src amt))))) (define shld 0 #b10100000) (define shrd 1 #b10101000))) -(define-instruction test (segment maybe-size this &optional that) +(define-instruction test (segment &prefix prefix this that) (:printer accum-imm ((op #b1010100))) (:printer reg/mem-imm ((op '(#b1111011 #b000)))) (:printer reg-reg/mem ((op #b1000010))) (:emitter - (let ((size (cond (that - (aver (is-size-p maybe-size)) - maybe-size) - (t - (setq that this this maybe-size) - (matching-operand-size this that))))) + (let ((size (pick-operand-size prefix this that))) (setq this (sized-thing this size) that (sized-thing that size)) (when (and (gpr-p this) (mem-ref-p that)) @@ -2144,7 +1987,7 @@ (emit-byte segment (opcode+size-bit #xA8 size))) (t (emit-byte segment (opcode+size-bit #xF6 size)) - (emit-ea segment this #b000))) + (emit-ea segment this #b000 :remaining-bytes 1))) (emit-imm-operand segment that size)) (t (emit-byte segment (opcode+size-bit #x84 size)) @@ -2163,30 +2006,25 @@ (:printer string-op ((op #b1010011))) (:emitter (emit* segment #b1010011 size))) - (define-instruction lods (segment acc) + (define-instruction lods (segment size) (:printer string-op ((op #b1010110))) - (:emitter (aver (accumulator-p acc)) - (emit* segment #b1010110 (operand-size acc)))) + (:emitter (emit* segment #b1010110 size))) - (define-instruction scas (segment acc) + (define-instruction scas (segment size) (:printer string-op ((op #b1010111))) - (:emitter (aver (accumulator-p acc)) - (emit* segment #b1010111 (operand-size acc)))) + (:emitter (emit* segment #b1010111 size))) - (define-instruction stos (segment acc) + (define-instruction stos (segment size) (:printer string-op ((op #b1010101))) - (:emitter (aver (accumulator-p acc)) - (emit* segment #b1010101 (operand-size acc)))) + (:emitter (emit* segment #b1010101 size))) - (define-instruction ins (segment acc) + (define-instruction ins (segment size) (:printer string-op ((op #b0110110))) - (:emitter (aver (accumulator-p acc)) - (emit* segment #b0110110 (operand-size acc)))) + (:emitter (emit* segment #b0110110 size))) - (define-instruction outs (segment acc) + (define-instruction outs (segment size) (:printer string-op ((op #b0110111))) - (:emitter (aver (accumulator-p acc)) - (emit* segment #b0110111 (operand-size acc))))) + (:emitter (emit* segment #b0110111 size)))) (define-instruction xlat (segment) (:printer byte ((op #b11010111))) @@ -2212,24 +2050,21 @@ (:printer ext-reg-reg/mem-no-width ((op #xBD))) (:emitter (emit* segment #xBD dst src)))) -(flet ((emit* (segment maybe-size src index lockp opcode) - (let ((size (cond ((is-size-p maybe-size) maybe-size) - (t - (shiftf lockp index src maybe-size) - (matching-operand-size src index))))) +(flet ((emit* (segment prefix src index opcode) + (let ((size (pick-operand-size prefix src index))) (when (eq size :byte) (error "can't test byte: ~S" src)) - (emit-prefixes segment src index size :lock lockp) + (emit-prefixes segment src index size :lock (lockp prefix)) (cond ((integerp index) (emit-bytes segment #x0F #xBA) - (emit-ea segment src opcode) + (emit-ea segment src opcode :remaining-bytes 1) (emit-byte segment index)) (t (emit-bytes segment #x0F (dpb opcode (byte 3 3) #b10000011)) (emit-ea segment src index)))))) (macrolet ((define (inst opcode-extension) - `(define-instruction ,inst (segment maybe-size src &optional index prefix) + `(define-instruction ,inst (segment &prefix prefix src index) (:printer ext-reg/mem-no-width+imm8 ((op '(#xBA ,opcode-extension)) (reg/mem nil :type 'sized-reg/mem))) @@ -2237,8 +2072,7 @@ ((op ,(dpb opcode-extension (byte 3 3) #b10000011)) (reg/mem nil :type 'sized-reg/mem)) '(:name :tab reg/mem ", " reg)) - (:emitter (emit* segment maybe-size src index prefix - ,opcode-extension))))) + (:emitter (emit* segment prefix src index ,opcode-extension))))) (define bt 4) (define bts 5) (define btr 6) @@ -2373,15 +2207,10 @@ (emit-byte-displacement-backpatch segment target))) ;;;; conditional move -(define-instruction cmov (segment maybe-size cond dst &optional src) +(define-instruction cmov (segment &prefix prefix cond dst src) (:printer cond-move ()) (:emitter - (let ((size (cond (src - (aver (is-size-p maybe-size)) - maybe-size) - (t - (setq src dst dst cond cond maybe-size) - (matching-operand-size dst src))))) + (let ((size (pick-operand-size prefix dst src))) (aver (gpr-p dst)) (aver (neq size :byte)) (emit-prefixes segment src dst size)) @@ -2391,7 +2220,7 @@ ;;;; conditional byte set -(define-instruction set (segment dst cond) +(define-instruction set (segment cond dst) ; argument order is like JMPcc (:printer cond-set ()) (:emitter (emit-prefixes segment (sized-thing dst :byte) nil :byte) @@ -2469,17 +2298,17 @@ (declare (type sb-assem:segment segment) (type index amount)) ;; Pack all instructions into one byte vector to save space. - (let* ((bytes #.(sb-xc:coerce - #(#x90 - #x66 #x90 - #x0f #x1f #x00 - #x0f #x1f #x40 #x00 - #x0f #x1f #x44 #x00 #x00 - #x66 #x0f #x1f #x44 #x00 #x00 - #x0f #x1f #x80 #x00 #x00 #x00 #x00 - #x0f #x1f #x84 #x00 #x00 #x00 #x00 #x00 - #x66 #x0f #x1f #x84 #x00 #x00 #x00 #x00 #x00) - '(vector (unsigned-byte 8)))) + (let* ((bytes #.(coerce + #(#x90 + #x66 #x90 + #x0f #x1f #x00 + #x0f #x1f #x40 #x00 + #x0f #x1f #x44 #x00 #x00 + #x66 #x0f #x1f #x44 #x00 #x00 + #x0f #x1f #x80 #x00 #x00 #x00 #x00 + #x0f #x1f #x84 #x00 #x00 #x00 #x00 #x00 + #x66 #x0f #x1f #x84 #x00 #x00 #x00 #x00 #x00) + '(vector (unsigned-byte 8)))) (max-length (isqrt (* 2 (length bytes))))) (loop (let* ((count (min amount max-length)) @@ -2520,38 +2349,21 @@ ;;;; Instructions required to do floating point operations using SSE -;; Return a one- or two-element list of printers for SSE instructions. -;; The one-element list is used in the cases where the REX prefix is -;; really a prefix and thus automatically supported, the two-element -;; list is used when the REX prefix is used in an infix position. +;;; Return a :PRINTER expression for SSE instructions. (eval-when (#-sb-xc :compile-toplevel :load-toplevel :execute) - (defun sse-inst-printer-list (inst-format-stem prefix opcode - &key more-fields printer) - (let ((fields `(,@(when prefix - `((prefix ,prefix))) + (defun sse-inst-printer (inst-format-stem prefix opcode &key more-fields printer) + (let ((fields `(,@(when prefix `((prefix ,prefix))) (op ,opcode) - ,@more-fields)) - (inst-formats (if prefix - (list (symbolicate "EXT-" inst-format-stem) - (symbolicate "EXT-REX-" inst-format-stem)) - (list inst-format-stem)))) - (mapcar (lambda (inst-format) - `(:printer ,inst-format ,fields ,@(if printer `(',printer)))) - inst-formats))) - (defun 2byte-sse-inst-printer-list (inst-format-stem prefix op1 op2 - &key more-fields printer) - (let ((fields `(,@(when prefix - `((prefix, prefix))) + ,@more-fields))) + `((:printer ,(if prefix (symbolicate "EXT-" inst-format-stem) inst-format-stem) + ,fields ,@(if printer `(',printer)))))) + (defun 2byte-sse-inst-printer (inst-format-stem prefix op1 op2 &key more-fields printer) + (let ((fields `(,@(when prefix `((prefix, prefix))) (op1 ,op1) (op2 ,op2) - ,@more-fields)) - (inst-formats (if prefix - (list (symbolicate "EXT-" inst-format-stem) - (symbolicate "EXT-REX-" inst-format-stem)) - (list inst-format-stem)))) - (mapcar (lambda (inst-format) - `(:printer ,inst-format ,fields ,@(if printer `(',printer)))) - inst-formats)))) + ,@more-fields))) + `((:printer ,(if prefix (symbolicate "EXT-" inst-format-stem) inst-format-stem) + ,fields ,@(if printer `(',printer))))))) (defun emit-sse-inst (segment dst src prefix opcode &key operand-size (remaining-bytes 0)) @@ -2591,12 +2403,13 @@ (macrolet ((define-imm-sse-instruction (name opcode /i) `(define-instruction ,name (segment dst/src imm) - ,@(sse-inst-printer-list 'xmm-imm #x66 opcode - :more-fields `((/i ,/i))) + ,@(sse-inst-printer 'xmm-imm #x66 opcode :more-fields `((/i ,/i))) (:emitter (emit-sse-inst-with-imm segment dst/src imm #x66 ,opcode ,/i :operand-size :do-not-set))))) + ;; FIXME: why did someone decide to invent new mnemonics for the immediate forms? + ;; Can we put them back to normal? (define-imm-sse-instruction pslldq #x73 7) (define-imm-sse-instruction psllw-imm #x71 6) (define-imm-sse-instruction pslld-imm #x72 6) @@ -2633,7 +2446,7 @@ (macrolet ((define-regular-sse-inst (name prefix opcode) `(define-instruction ,name (segment dst src) - ,@(sse-inst-printer-list 'xmm-xmm/mem prefix opcode) + ,@(sse-inst-printer 'xmm-xmm/mem prefix opcode) (:emitter (emit-regular-sse-inst segment dst src ,prefix ,opcode))))) ;; moves @@ -2776,7 +2589,7 @@ (intern (format nil "SSE-SHUFFLE-PATTERN-~D-~D" n-bits radix)))) `(define-instruction ,name (segment dst src pattern) - ,@(sse-inst-printer-list + ,@(sse-inst-printer 'xmm-xmm/mem prefix opcode :more-fields `((imm nil :type ',shuffle-pattern)) :printer '(:name :tab reg ", " reg/mem ", " imm)) @@ -2798,12 +2611,12 @@ (aver (xmm-register-p src)) (aver (xmm-register-p mask)) (emit-regular-sse-inst segment src mask #x66 #xf7)) - . #.(sse-inst-printer-list 'xmm-xmm/mem #x66 #xf7)) + . #.(sse-inst-printer 'xmm-xmm/mem #x66 #xf7)) (macrolet ((define-comparison-sse-inst (name prefix opcode name-prefix name-suffix) `(define-instruction ,name (segment op x y) - ,@(sse-inst-printer-list + ,@(sse-inst-printer 'xmm-xmm/mem prefix opcode :more-fields '((imm nil :type 'sse-condition-code)) :printer `(,name-prefix imm ,name-suffix @@ -2822,7 +2635,7 @@ ;;; MOVSD, MOVSS (macrolet ((define-movsd/ss-sse-inst (name prefix) `(define-instruction ,name (segment dst src) - ,@(sse-inst-printer-list 'xmm-xmm/mem-dir prefix #b0001000) + ,@(sse-inst-printer 'xmm-xmm/mem-dir prefix #b0001000) (:emitter (cond ((xmm-register-p dst) (emit-sse-inst segment dst src ,prefix #x10 @@ -2847,8 +2660,8 @@ ,prefix ,opcode-from)))) (define-instruction ,name (segment dst src) ,@(when opcode-from - (sse-inst-printer-list 'xmm-xmm/mem prefix opcode-from)) - ,@(sse-inst-printer-list + (sse-inst-printer 'xmm-xmm/mem prefix opcode-from)) + ,@(sse-inst-printer 'xmm-xmm/mem prefix opcode-to :printer '(:name :tab reg/mem ", " reg)) (:emitter @@ -2889,7 +2702,7 @@ (aver (and (xmm-register-p dst) (not (xmm-register-p src)))) (emit-regular-2byte-sse-inst segment dst src #x66 #x38 #x2a)) - . #.(2byte-sse-inst-printer-list '2byte-xmm-xmm/mem #x66 #x38 #x2a)) + . #.(2byte-sse-inst-printer '2byte-xmm-xmm/mem #x66 #x38 #x2a)) ;;; Move a 32-bit value (MOVD) or 64-bit value (MOVQ) ;;; MOVD has encodings for xmm <-> r/m32. @@ -2930,8 +2743,7 @@ ;;; This is simply saying that we can faithfully round-trip our own asm. ;;; (3) On top of that, we'll _require_ that MOVD only operate on 32 bits, ;;; and MOVQ on 64 bits. This is stricter than other assemblers. -;;; The rationale is after removing REG-IN-SIZE, the correct behavior -;;; is obtained with no further "opcode modifier" such as +;;; Furthermore MOVD does not accept a size prefix such as ;;; (INST MOVD :QWORD X Y) ; <- What is this, I can't even. ;;; ;;; For further reading: @@ -2950,15 +2762,19 @@ (setq dst (sized-thing dst size) src (sized-thing src size)) (cond ((xmm-register-p dst) - (emit-sse-inst segment dst src #x66 #x6e)) + (emit-sse-inst segment dst src #x66 #x6e + :operand-size (and (ea-p src) + :do-not-set))) (t (aver (xmm-register-p src)) - (emit-sse-inst segment src dst #x66 #x7e))))) + (emit-sse-inst segment src dst #x66 #x7e + :operand-size (and (ea-p dst) + :do-not-set)))))) (define-instruction movd (segment dst src) (:emitter (move-xmm<->gpr segment dst src :dword)) - . #.(append (sse-inst-printer-list 'xmm-reg/mem #x66 #x6e + . #.(append (sse-inst-printer 'xmm-reg/mem #x66 #x6e :printer '(#'print-mov[dq]-opcode :tab reg ", " reg/mem)) - (sse-inst-printer-list 'xmm-reg/mem #x66 #x7e + (sse-inst-printer 'xmm-reg/mem #x66 #x7e :printer '(#'print-mov[dq]-opcode :tab reg/mem ", " reg)))) (define-instruction movq (segment dst src) @@ -2973,10 +2789,18 @@ (aver (xmm-register-p src)) (emit-sse-inst segment src dst #x66 #xd6 :operand-size :do-not-set)))))) - . #.(append (sse-inst-printer-list 'xmm-xmm/mem #xf3 #x7e) - (sse-inst-printer-list 'xmm-xmm/mem #x66 #xd6 + . #.(append (sse-inst-printer 'xmm-xmm/mem #xf3 #x7e) + (sse-inst-printer 'xmm-xmm/mem #x66 #xd6 :printer '(:name :tab reg/mem ", " reg))))) +(define-instruction rdfsbase (segment dst) + (:printer ext-xmm-reg/mem ((prefix #xF3) (op #xAE) + (reg nil :prefilter nil :printer #("RDFSBASE" "RDGSBASE"))) + '(reg :tab reg/mem)) + (:emitter (emit-sse-inst segment 0 dst #xf3 #xae))) +(define-instruction rdgsbase (segment dst) + (:emitter (emit-sse-inst segment 1 dst #xf3 #xae))) + ;;; Instructions having an XMM register as the destination operand ;;; and a general-purpose register or a memory location as the source ;;; operand. The operand size is calculated from the source operand. @@ -2984,30 +2808,35 @@ (macrolet ((define-extract-sse-instruction (name prefix op1 op2 &key explicit-qword) `(define-instruction ,name (segment dst src imm) - (:printer - ,(if op2 (if explicit-qword - 'ext-rex-2byte-reg/mem-xmm - 'ext-2byte-reg/mem-xmm) - 'ext-reg/mem-xmm) - ((prefix '(,prefix)) - ,@(if op2 - `((op1 '(,op1)) (op2 '(,op2))) - `((op '(,op1)))) - (imm nil :type 'imm-byte)) - '(:name :tab reg/mem ", " reg ", " imm)) + ;; The printer for PEXTRD changes the opcode name to PEXTRQ + ;; depending on the REX.W bit. + ,@(case name + (pextrq nil) + (pextrd + `((:printer ext-2byte-reg/mem-xmm + ((prefix '(,prefix)) + (rex nil :prefilter (lambda (dstate) + (if (dstate-getprop dstate +rex-w+) 1 0)) + :printer #("PEXTRD" "PEXTRQ")) + (op1 '(,op1)) + (op2 '(,op2)) + (imm nil :type 'imm-byte)) + '(rex :tab reg/mem ", " reg ", " imm)))) + + (t + `((:printer ext-2byte-reg/mem-xmm + ((prefix '(,prefix)) + (op1 '(,op1)) + (op2 '(,op2)) + (imm nil :type 'imm-byte)) + '(:name :tab reg/mem ", " reg ", " imm))))) (:emitter (aver (and (xmm-register-p src) (not (xmm-register-p dst)))) - ,(if op2 - `(emit-sse-inst-2byte segment dst src ,prefix ,op1 ,op2 - :operand-size ,(if explicit-qword - :qword - :do-not-set) - :remaining-bytes 1) - `(emit-sse-inst segment dst src ,prefix ,op1 + (emit-sse-inst-2byte segment src dst ,prefix ,op1 ,op2 :operand-size ,(if explicit-qword :qword :do-not-set) - :remaining-bytes 1)) + :remaining-bytes 1) (emit-byte segment imm)))) (define-insert-sse-instruction (name prefix op1 op2) @@ -3054,16 +2883,16 @@ :operand-size :do-not-set :remaining-bytes 1)) (emit-byte segment imm)) . #.(append - (2byte-sse-inst-printer-list '2byte-reg/mem-xmm #x66 #x3a #x15 + (2byte-sse-inst-printer '2byte-reg/mem-xmm #x66 #x3a #x15 :more-fields '((imm nil :type 'imm-byte)) :printer '(:name :tab reg/mem ", " reg ", " imm)) - (sse-inst-printer-list 'reg/mem-xmm #x66 #xc5 + (sse-inst-printer 'reg/mem-xmm #x66 #xc5 :more-fields '((imm nil :type 'imm-byte)) :printer '(:name :tab reg/mem ", " reg ", " imm)))) (macrolet ((define-integer-source-sse-inst (name prefix opcode &key mem-only) `(define-instruction ,name (segment dst src) - ,@(sse-inst-printer-list 'xmm-reg/mem prefix opcode) + ,@(sse-inst-printer 'xmm-reg/mem prefix opcode) (:emitter (aver (xmm-register-p dst)) ,(when mem-only @@ -3086,7 +2915,7 @@ &key (size '(operand-size dst)) reg-only) `(define-instruction ,name (segment dst src) - ,@(sse-inst-printer-list 'reg-xmm/mem prefix opcode) + ,@(sse-inst-printer 'reg-xmm/mem prefix opcode) (:emitter (aver (gpr-p dst)) ,(when reg-only @@ -3119,14 +2948,14 @@ (macrolet ((regular-2byte-sse-inst (name prefix op1 op2) `(define-instruction ,name (segment dst src) - ,@(2byte-sse-inst-printer-list '2byte-xmm-xmm/mem prefix + ,@(2byte-sse-inst-printer '2byte-xmm-xmm/mem prefix op1 op2) (:emitter (emit-regular-2byte-sse-inst segment dst src ,prefix ,op1 ,op2)))) (regular-2byte-sse-inst-imm (name prefix op1 op2) `(define-instruction ,name (segment dst src imm) - ,@(2byte-sse-inst-printer-list + ,@(2byte-sse-inst-printer '2byte-xmm-xmm/mem prefix op1 op2 :more-fields '((imm nil :type 'imm-byte)) :printer `(:name :tab reg ", " reg/mem ", " imm)) @@ -3218,12 +3047,13 @@ ;; Instructions implicitly using XMM0 as a mask (macrolet ((define-sse-inst-implicit-mask (name prefix op1 op2) `(define-instruction ,name (segment dst src mask) - ,@(2byte-sse-inst-printer-list + ,@(2byte-sse-inst-printer '2byte-xmm-xmm/mem prefix op1 op2 :printer '(:name :tab reg ", " reg/mem ", XMM0")) (:emitter (aver (xmm-register-p dst)) - (aver (and (xmm-register-p mask) (= (tn-offset mask) 0))) + (aver (and (xmm-register-p mask) + (= (reg-id-num (reg-id mask)) 0))) (emit-regular-2byte-sse-inst segment dst src ,prefix ,op1 ,op2))))) @@ -3242,7 +3072,6 @@ (flet ((emit* (segment opcode subcode src) (aver (not (register-p src))) - (aver (eq (operand-size src) :byte)) (aver subcode) (emit-prefixes segment src nil :byte) (emit-byte segment #x0f) @@ -3291,14 +3120,15 @@ (:printer ext-reg/mem-no-width ((op '(#xae 3)))) (:emitter (emit* segment dst 3)))) -(define-instruction popcnt (segment dst src) - (:printer f3-escape-reg-reg/mem ((op #xB8))) - (:printer rex-f3-escape-reg-reg/mem ((op #xB8))) +(define-instruction popcnt (segment &prefix prefix dst src) + (:printer ext-xmm-reg/mem ((prefix #xF3) (op #xB8) (reg nil :type 'reg))) (:emitter - (aver (gpr-p dst)) - (aver (and (gpr-p dst) (not (eq (operand-size dst) :byte)))) - (aver (not (eq (operand-size src) :byte))) - (emit-sse-inst segment dst src #xf3 #xb8))) + (let ((size (pick-operand-size prefix dst src))) + (aver (neq size :byte)) + ;; FIXME: this disagrees with the prefix order that other assemblers emit + ;; for "popcnt %ax,%r10w" which is 66 f3 44 0f b8 d0. + ;; We disassemble it wrongly, but I think ours is a valid encoding. + (emit-sse-inst segment dst src #xf3 #xb8 :operand-size size)))) (define-instruction crc32 (segment src-size dst src) ;; The low bit of the final opcode byte sets the source size. @@ -3308,11 +3138,6 @@ (op2 #b1111000 :field (byte 7 25)) ; #xF0 ignoring the low bit (src-width nil :field (byte 1 24) :prefilter #'prefilter-width) (reg nil :printer #'print-d/q-word-reg))) - (:printer ext-rex-2byte-prefix-reg-reg/mem - ((prefix #xf2) (op1 #x38) - (op2 #b1111000 :field (byte 7 33)) ; ditto - (src-width nil :field (byte 1 32) :prefilter #'prefilter-width) - (reg nil :printer #'print-d/q-word-reg))) (:emitter (let ((dst-size (operand-size dst))) ;; The following operand size combinations are possible: @@ -3460,7 +3285,12 @@ (defun sort-inline-constants (constants) ;; Each constant is ((size . bits) . label) - (stable-sort constants #'> :key (lambda (x) (align-of (car x))))) + ;; Jump tables must precede everything else. + (let ((jump-tables (remove :jump-table constants :test #'neq :key #'caar)) + (rest (remove :jump-table constants :key #'caar))) + (concatenate 'vector + jump-tables + (stable-sort rest #'> :key (lambda (x) (align-of (car x))))))) (defun emit-inline-constant (section constant label) ;; See comment at CANONICALIZE-INLINE-CONSTANT about how we are @@ -3479,6 +3309,79 @@ collect (prog1 (ldb (byte 8 0) val) (setf val (ash val -8)))))))))) +;;; This gets called by LOAD to resolve newly positioned objects +;;; with things (like code instructions) that have to refer to them. +;;; Return KIND if the fixup needs to be recorded in %CODE-FIXUPS. +;;; The code object we're fixing up is pinned whenever this is called. +(defun fixup-code-object (code offset value kind flavor) + (declare (type index offset)) + (let ((sap (code-instructions code))) + (case flavor + (:gc-barrier ; the VALUE is nbits, so convert it to an AND mask + (setf (sap-ref-32 sap offset) (1- (ash 1 value)))) + (:layout-id ; layout IDs are signed quantities on x86-64 + (setf (signed-sap-ref-32 sap offset) value)) + (:alien-data-linkage-index + (setf (sap-ref-32 sap offset) (* value alien-linkage-table-entry-size))) + (:alien-code-linkage-index + (let ((addend (sap-ref-32 sap offset))) + (setf (sap-ref-32 sap offset) (+ (* value alien-linkage-table-entry-size) addend)))) + (t + ;; All x86-64 fixup locations contain an implicit addend at the location + ;; to be fixed up. The addend is always zero for certain <KIND,FLAVOR> pairs, + ;; but we don't need to assert that. + (incf value (if (eq kind :absolute) + (signed-sap-ref-64 sap offset) + (signed-sap-ref-32 sap offset))) + (ecase kind + (:abs32 ; 32 unsigned bits + (setf (sap-ref-32 sap offset) value)) + (:rel32 + ;; Replace word with the difference between VALUE and current pc. + ;; JMP/CALL are relative to the next instruction, + ;; so add 4 bytes for the size of the displacement itself. + ;; Relative fixups don't exist with movable code, + ;; so in the #-immobile-code case, there's nothing to assert. + #+(and immobile-code (not sb-xc-host)) + (unless (immobile-space-obj-p code) + (error "Can't compute fixup relative to movable object ~S" code)) + (setf (signed-sap-ref-32 sap offset) (- value (+ (sap-int sap) offset 4)))) + (:absolute + ;; These are used for jump tables and are not recorded in %code-fixups. + ;; GC knows to adjust the values if code is moved. + (setf (sap-ref-64 sap offset) value)))))) + nil) + +(defun sb-c::pack-retained-fixups (fixup-notes &aux abs32-fixups imm-fixups) + ;; An absolute fixup is stored in the code header's %FIXUPS slot if it + ;; references an immobile-space (but not static-space) object. + ;; Note that: + ;; (1) Call fixups occur in both :REL32 and :ABS32 kinds. We can ignore the :REL32 kind. + ;; (2) :STATIC-CALL fixups point to immobile text space, not static space. + (dolist (note fixup-notes (sb-c:pack-code-fixup-locs abs32-fixups nil imm-fixups)) + (let* ((fixup (fixup-note-fixup note)) + (offset (fixup-note-position note)) + (flavor (fixup-flavor fixup))) + (cond ((eq flavor :gc-barrier) (push offset imm-fixups)) + #+immobile-space + ((and (eq (fixup-note-kind note) :abs32) + (memq flavor + '(:fdefn-call :layout :immobile-symbol :symbol-value ; -> fixedobj space + :static-call))) ; -> text space + (push offset abs32-fixups)))))) + +;;; Coverage support + +(define-instruction store-coverage-mark (segment mark-index) + (:emitter + (assemble (segment) + (inst mov :byte (rip-relative-ea (segment-origin segment) + ;; skip over jump table word and entries + (+ (* (1+ (component-n-jump-table-entries)) + n-word-bytes) + mark-index)) + 1)))) + (defun sb-assem::%mark-used-labels (operand) (when (typep operand 'ea) (let ((disp (ea-disp operand))) @@ -3488,48 +3391,18 @@ (label+addend (setf (label-usedp (label+addend-label disp)) t)))))) -(defun sb-c::branch-opcode-p (mnemonic) - (case mnemonic - ((call ret jmp jrcxz break int iret - loop loopz loopnz syscall - byte word dword) ; unexplained phenomena - t))) - -;;; Replace the STATEMENT with an instruction to store a coverage mark -;;; in the OFFSETth byte beyond LABEL. -(defun sb-c::replace-coverage-instruction (statement label offset) - (setf (stmt-mnemonic statement) 'mov - (stmt-operands statement) `(:byte ,(rip-relative-ea label offset) 1))) - - -;;; This constructor is for broken 3rd-party library code. It's fine that we have -;;; some degree of backward-compatibility, but it's another entirely to say that -;;; we allowed code that SHOULD NOT have been allowed to work. -;;; -;;; The problem: MAKE-EA gets called with registers that were resized -;;; using REG-IN-SIZE. The BASE and INDEX parts of an EA are *always* -;;; qwords, and we should have enforced that. Well, it's too late now -;;; to start enforcing. -(defun make-ea (size &key base index (scale 1) (disp 0)) - (flet ((fix (reg) - (if (register-p reg) - (make-random-tn :kind :normal - :sc (sc-or-lose 'sb-vm::unsigned-reg) - :offset (reg-id-num (reg-id reg))) - reg))) - (%make-ea-dont-use size disp (fix base) (fix index) scale))) +;;; Assembly optimizer support (defun parse-2-operands (stmt) (let* ((operands (stmt-operands stmt)) - (size (let* ((first (car operands)) - (second (cadr operands))) - (cond ((is-size-p first) (pop operands) first) - ;; This next case is noise to support obsolete REG-IN-SIZE - ((or (register-p first) (register-p second)) - (matching-operand-size first second)) ; FIXME: remove - (t :qword))))) - ;; Recompute first + second because potentially popped one. - (values size (first operands) (second operands)))) + (first (pop operands)) + (second (pop operands))) + (if (atom (gethash (stmt-mnemonic stmt) sb-assem::*inst-encoder*)) ; no prefixes + (values :qword first second) + (let ((prefix first) + (first second) + (second (pop operands))) + (values (pick-operand-size prefix first second) first second))))) (defun smaller-of (size1 size2) (if (or (eq size1 :dword) (eq size2 :dword)) :dword :qword)) @@ -3553,7 +3426,7 @@ (location= dst2 dst1) (eq size1 :qword) (eq size2 :dword)) - (setf (stmt-operands stmt) `(:dword ,dst1 ,src1)) + (setf (stmt-operands stmt) `(,+dword-size-prefix+ ,dst1 ,src1)) next))) ;;; "AND r, imm1" + "AND r, imm2" -> "AND r, (imm1 & imm2)" @@ -3567,11 +3440,40 @@ (member size2 '(:dword :qword)) (typep src2 '(signed-byte 32))) (setf (stmt-operands next) - `(,(smaller-of size1 size2) ,dst2 ,(logand src1 src2))) + `(,(encode-size-prefix (smaller-of size1 size2)) ,dst2 ,(logand src1 src2))) (add-stmt-labels next (stmt-labels stmt)) (delete-stmt stmt) next))) +;;; In "{AND,OR,...} reg, src ; TEST reg, reg ; {JMP,SET} {:z,:nz,:s,:ns}" +;;; the TEST is unnecessary since ALU operations set the Z and S flags. +;;; Per the processor manual, TEST clears OF and CF, so presumably +;;; there is not a branch-if on either of those flags. +;;; It shouldn't be a problem that removal of TEST leaves more flags affected. +(defpattern "ALU + test" ((add adc sub sbb and or xor neg sar shl shr) (test)) (stmt next) + (binding* (((size1 dst1 src1) (parse-2-operands stmt)) + ((size2 dst2 src2) (parse-2-operands next)) + (next-next (stmt-next next))) + (declare (ignore src1)) + (when (and (not (stmt-labels next)) + (gpr-tn-p dst2) + (location= dst1 dst2) ; they can have different SCs + (eq dst2 src2) + next-next + ;; Zero shifts do not affect the flags + (not (and (memq (stmt-mnemonic stmt) '(sar shl shr)) + (memq (car (last (stmt-operands stmt))) + '(:cl 0)))) + (memq (stmt-mnemonic next-next) '(jmp set)) + ;; TODO: figure out when it would be correct to omit TEST for the carry flag + (case (car (stmt-operands next-next)) + ((:s :ns) + (eq size2 size1)) + ((:ne :e :nz :z) + (or (eq size2 size1) (and (eq size1 :dword) (eq size2 :qword)))))) + (delete-stmt next) + next-next))) + ;;; "fixnumize" + "SHR reg, N" where N > n-tag-bits skips the fixnumize. ;;; (could generalize: masking out N bits with AND, following by shifting ;;; out N low bits can eliminate the AND) @@ -3614,7 +3516,7 @@ ;; so I'm constraining this to 31 bits, not 32. (when (<= max-dst1-bit-index 30) (setf (stmt-mnemonic stmt) 'shr - (stmt-operands stmt) `(:dword ,dst1 ,src1)) + (stmt-operands stmt) `(,+dword-size-prefix+ ,dst1 ,src1)) next))))) (defun reg= (a b) ; Return T if A and B are the same register diff --git a/src/compiler/x86-64/macros.lisp b/src/compiler/x86-64/macros.lisp index c6ed9502bc..e2281af7f0 100644 --- a/src/compiler/x86-64/macros.lisp +++ b/src/compiler/x86-64/macros.lisp @@ -17,25 +17,8 @@ ;;; the support for SC-dependent move instructions needed here makes ;;; that expand into so large an expression that the resulting code ;;; bloat is not justifiable. -(defun move (dst src) +(defun move (dst src &optional size) "Move SRC into DST unless they are location=." - ;; The first case is for backward-compatibility. It's not necessary - ;; for any of our code, but it is for code that performs - ;; (MOVE (REG-IN-SIZE blah :dword) (REG-IN-SIZE from :dword)) - ;; Most of this garbage will go away because eventually I'd like to preserve - ;; all seemingly redundant moves, and then eliminate them before emission. - ;; This way we can track movement of TNs into the same physical reg in a - ;; different SC which will give useful information to a peephole optimizer. - (when (and (sb-x86-64-asm::register-p dst) - (sb-x86-64-asm::register-p src)) - (let ((dst (sb-x86-64-asm::reg-id dst)) - (src (sb-x86-64-asm::reg-id src))) - (aver (sb-x86-64-asm::is-gpr-id-p dst)) - (aver (sb-x86-64-asm::is-gpr-id-p src)) - (unless (= (sb-x86-64-asm::reg-id-num dst) - (sb-x86-64-asm::reg-id-num src)) - (inst mov dst src))) - (return-from move)) (unless (location= dst src) (sc-case dst ((single-reg complex-single-reg) @@ -53,7 +36,7 @@ (aver (xmm-tn-p src)) (inst movaps dst src)) #+sb-simd-pack-256 - ((int-avx2-reg avx2-reg) + ((ymm-reg int-avx2-reg) (aver (xmm-tn-p src)) (inst vmovdqa dst src)) #+sb-simd-pack-256 @@ -61,11 +44,9 @@ (aver (xmm-tn-p src)) (inst vmovaps dst src)) (t - (inst mov dst src))))) - -(defun 32bit-move (dst src) - (unless (location= dst src) - (inst mov :dword dst src))) + (if size + (inst mov size dst src) + (inst mov dst src)))))) (defmacro object-slot-ea (ptr slot lowtag) `(ea (- (* ,slot n-word-bytes) ,lowtag) ,ptr)) @@ -75,7 +56,7 @@ (defmacro loadw (value ptr &optional (slot 0) (lowtag 0)) `(inst mov ,value (object-slot-ea ,ptr ,slot ,lowtag))) -(defun storew (value ptr &optional (slot 0) (lowtag 0)) +(defun storew (value ptr &optional (slot 0) (lowtag 0) temp) (let* ((size (if (tn-p value) (sc-operand-size (tn-sc value)) :qword)) @@ -83,8 +64,11 @@ (aver (eq size :qword)) (cond ((and (integerp value) (not (typep value '(signed-byte 32)))) - (inst mov temp-reg-tn value) - (inst mov ea temp-reg-tn)) + (cond (temp + (inst mov temp value) + (inst mov ea temp)) + (t + (bug "need temp reg for STOREW of oversized immediate operand")))) (t (inst mov :qword ea value))))) @@ -109,23 +93,33 @@ (- other-pointer-lowtag)))) (defun thread-tls-ea (index) + #+gs-seg (ea :gs index) ; INDEX is either a DISP or a BASE of the EA ;; Whether index is an an integer or a register, the EA constructor ;; call is the same. - ;; Due to an encoding peculiarity, using thread-base-tn as the index register + ;; Due to an encoding peculiarity, using thread-base-reg as the index register ;; is better when index is non-constant. ;; Base of r13 is reg=5 in ModRegRM, so if mod were 0, it would imply ;; RIP-relative addressing. (And attempting to encode an index is illegal) ;; So the 'mod' bits must be nonzero, which mandates encoding of an ;; explicit displacement of 0. Using INDEX as base avoids the extra byte. - (ea index thread-base-tn)) + #-gs-seg (ea index thread-tn)) ;;; assert that alloc-region->free_pointer and ->end_addr can be accessed -;;; using a single byte displacement from thread-base-tn +;;; using a single byte displacement from thread-tn (eval-when (:compile-toplevel) - (aver (<= (1+ thread-alloc-region-slot) 15))) - -(defun thread-slot-ea (slot-index) - (ea (ash slot-index word-shift) thread-base-tn)) + (aver (<= (1+ thread-boxed-tlab-slot) 15)) + (aver (<= (1+ thread-mixed-tlab-slot) 15)) + (aver (<= (1+ thread-cons-tlab-slot) 15))) + +;;; Access a thread slot at a fixed index. If GPR-TN is provided, +;;; then it points to 'struct thread', which is relevant only if +;;; #+gs-seg. +(defun thread-slot-ea (slot-index &optional gpr-tn) + (if gpr-tn + (ea (ash slot-index word-shift) gpr-tn) + ;; Otherwise do something depending on #[-+]gs-seg + (let (#+gs-seg (thread-tn nil)) + (ea thread-segment-reg (ash slot-index word-shift) thread-tn)))) #+sb-thread (progn @@ -203,37 +197,55 @@ #+sb-safepoint (defun emit-safepoint () - (inst test :byte rax-tn (ea (- nil-value n-word-bytes other-pointer-lowtag - gc-safepoint-trap-offset)))) - -(defmacro pseudo-atomic ((&key elide-if) &rest forms) - #+sb-safepoint-strictly + ;; FIXME: need to get the node and policy to decide not to emit this safepoint. + ;; Also, it would be good to emit only the last of consecutive safepoints in + ;; straight-line code, e.g. (LIST (LIST X Y) (LIST Z W)) should emit 1 safepoint + ;; not 3, even if we consider it 3 separate pointer bumps. + ;; (Ideally we'd only do 1 pointer bump, but that's a separate issue) + (inst test :byte rax-tn (ea (- static-space-start gc-safepoint-trap-offset)))) + +;;; This macro is purposely unhygienic with respect to THREAD-TN, +;;; which is either a global symbol macro, or a LET-bound variable, +;;; depending on #+gs-seg. +(defmacro pseudo-atomic ((&key ((:thread-tn thread)) elide-if) &body forms) + (declare (ignorable thread)) + #+sb-safepoint `(progn ,@forms (unless ,elide-if (emit-safepoint))) - #-sb-safepoint-strictly + #-sb-safepoint (with-unique-names (label pa-bits-ea) + (let ((true + ;; TRUE is anything nonzero. Moving a register to memory is + ;; allegedly faster than reading an imm8 operand. I don't know, + ;; but I'm not going to debate it. However THREAD-TN is a better + ;; choice than RBP-TN since it's never written to. + #+(and sb-thread (not gs-seg)) 'thread-tn + #-(and sb-thread (not gs-seg)) 'rbp-tn)) `(let ((,label (gen-label)) (,pa-bits-ea - #+sb-thread (thread-slot-ea thread-pseudo-atomic-bits-slot) + #+sb-thread (thread-slot-ea + thread-pseudo-atomic-bits-slot + #+gs-seg ,@(if thread (list thread))) #-sb-thread (static-symbol-value-ea '*pseudo-atomic-bits*))) (unless ,elide-if - (inst mov ,pa-bits-ea rbp-tn)) + (inst mov ,pa-bits-ea ,true)) ,@forms (unless ,elide-if - (inst xor ,pa-bits-ea rbp-tn) + (inst xor ,pa-bits-ea ,true) (inst jmp :z ,label) ;; if PAI was set, interrupts were disabled at the same time ;; using the process signal mask. - (inst break pending-interrupt-trap) - (emit-label ,label) - #+sb-safepoint - ;; In this case, when allocation thinks a GC should be done, it - ;; does not mark PA as interrupted, but schedules a safepoint - ;; trap instead. Let's take the opportunity to trigger that - ;; safepoint right now. - (emit-safepoint))))) + #+int1-breakpoints (inst icebp) + #-int1-breakpoints (inst break pending-interrupt-trap) + (emit-label ,label)))))) ;;;; indexed references +(defun index-scale (element-size index-tn) + (if (sc-is index-tn immediate) + 1 + (ash element-size + (if (sc-is index-tn any-reg) (- n-fixnum-tag-bits) 0)))) + (sb-xc:deftype load/store-index (scale lowtag min-offset &optional (max-offset min-offset)) `(integer ,(- (truncate (+ (ash 1 16) @@ -248,48 +260,76 @@ (name type offset lowtag scs el-type &optional translate) `(progn (define-vop (,name) - ,@(when translate `((:translate ,translate))) + (:translate ,translate) (:policy :fast-safe) (:args (object :scs (descriptor-reg) :to :eval) (index :scs (,@(when (member translate '(%instance-cas %raw-instance-cas/word)) '(immediate)) - any-reg) :to :eval) - (old-value :scs ,scs :target rax) + any-reg signed-reg unsigned-reg) :to :eval) + (old-value :scs ,scs #|:target rax|#) (new-value :scs ,scs)) + (:vop-var vop) (:arg-types ,type tagged-num ,el-type ,el-type) + ;; if OLD-VALUE were LOCATION= to RAX then we'd clobber it + ;; while computing the EA for the barrier, or else we could use + ;; a separate temp. (:temporary (:sc descriptor-reg :offset rax-offset - :from (:argument 2) :to :result :target value) rax) + #|:from (:argument 2)|# :to :result :target value) rax) (:results (value :scs ,scs)) (:result-types ,el-type) (:generator 5 - (move rax old-value) - (inst cmpxchg - (ea (- (* (+ (if (sc-is index immediate) (tn-value index) 0) ,offset) + (let ((ea (ea (- (* (+ (if (sc-is index immediate) (tn-value index) 0) ,offset) n-word-bytes) ,lowtag) object (unless (sc-is index immediate) index) - (ash 1 (- word-shift n-fixnum-tag-bits))) - new-value :lock) - (move value rax))))) + (index-scale n-word-bytes index)))) + ,@(ecase name + (%compare-and-swap-svref + ;; store barrier needs the EA of the affected element + '((emit-gc-store-barrier object ea rax (vop-nth-arg 3 vop) new-value))) + (%instance-cas + ;; store barrier affects only the object's base address + '((emit-gc-store-barrier object nil rax (vop-nth-arg 3 vop) new-value))) + ((%raw-instance-cas/word %raw-instance-cas/signed-word))) + (move rax old-value) + (inst cmpxchg :lock ea new-value) + (move value rax)))))) + +(defun bignum-index-check (bignum index addend vop) + (declare (ignore bignum index addend vop)) + ;; Conditionally compile this in to sanity-check the bignum logic + #+nil + (let ((ok (gen-label))) + (cond ((and (tn-p index) (not (constant-tn-p index))) + (aver (sc-is index any-reg)) + (inst lea :dword temp-reg-tn (ea (fixnumize addend) index)) + (inst shr :dword temp-reg-tn n-fixnum-tag-bits)) + (t + (inst mov temp-reg-tn (+ (if (tn-p index) (tn-value index) index) addend)))) + (inst cmp :dword temp-reg-tn (ea (- 1 other-pointer-lowtag) bignum)) + (inst jmp :b ok) + (inst break halt-trap) + (emit-label ok))) (defmacro define-full-reffer (name type offset lowtag scs el-type &optional translate) `(progn (define-vop (,name) - ,@(when translate - `((:translate ,translate))) + (:translate ,translate) (:policy :fast-safe) (:args (object :scs (descriptor-reg)) - (index :scs (any-reg))) + (index :scs (any-reg signed-reg unsigned-reg))) (:arg-types ,type tagged-num) (:results (value :scs ,scs)) (:result-types ,el-type) + (:vop-var vop) (:generator 3 ; pw was 5 + ,@(when (eq translate 'sb-bignum:%bignum-ref) + '((bignum-index-check object index 0 vop))) (inst mov value (ea (- (* ,offset n-word-bytes) ,lowtag) - object index (ash 1 (- word-shift n-fixnum-tag-bits)))))) + object index (index-scale n-word-bytes index))))) (define-vop (,(symbolicate name "-C")) - ,@(when translate - `((:translate ,translate))) + (:translate ,translate) (:policy :fast-safe) (:args (object :scs (descriptor-reg))) (:info index) @@ -298,33 +338,57 @@ ,(eval offset)))) (:results (value :scs ,scs)) (:result-types ,el-type) + (:vop-var vop) (:generator 2 ; pw was 5 + ,@(when (eq translate 'sb-bignum:%bignum-ref) + '((bignum-index-check object index 0 vop))) (inst mov value (ea (- (* (+ ,offset index) n-word-bytes) ,lowtag) object)))))) -(defmacro define-full-reffer+offset (name type offset lowtag scs el-type &optional translate) +(defmacro define-full-reffer+addend (name type offset lowtag scs el-type &optional translate) + (flet ((trap (index-to-encode) + (declare (ignorable index-to-encode)) + #+ubsan + ;; It's OK that the cell is read twice when testing for a trap value. + ;; The value should only change from trapping to non-trapping, so if we loaded + ;; a trap, and then one instruction later the data is valid (due to being + ;; stored in another thread), then it's a false positive that is indicative + ;; of a race. A false negative (failure to signal on a trap value) can not + ;; occur unless unsafely using REPLACE into this vector. + (when (memq name '(data-vector-ref-with-offset/simple-vector + data-vector-ref-with-offset/simple-vector-c)) + `((when (sb-c::policy (sb-c::vop-node vop) (> sb-c::aref-trapping 0)) + (inst cmp :byte ea unwritten-vector-element-marker) + (inst jmp :e (generate-error-code + vop 'uninitialized-element-error object + ,index-to-encode))))))) `(progn (define-vop (,name) - ,@(when translate - `((:translate ,translate))) + (:translate ,translate) (:policy :fast-safe) (:args (object :scs (descriptor-reg)) - (index :scs (any-reg))) - (:info offset) + (index :scs (any-reg signed-reg unsigned-reg))) + (:info addend) (:arg-types ,type tagged-num (:constant (constant-displacement other-pointer-lowtag n-word-bytes vector-data-offset))) (:results (value :scs ,scs)) (:result-types ,el-type) - (:generator 3 ; pw was 5 - (inst mov value (ea (- (* (+ ,offset offset) n-word-bytes) ,lowtag) - object index (ash 1 (- word-shift n-fixnum-tag-bits)))))) + (:vop-var vop) + (:generator 3 + ,@(when (eq translate 'sb-bignum:%bignum-ref-with-offset) + '((bignum-index-check object index addend vop))) + (let ((ea (ea (- (* (+ ,offset addend) n-word-bytes) ,lowtag) + object index (index-scale n-word-bytes index)))) + ,@(trap 'index) + (inst mov value ea)))) + ;; This vop is really not ideal to have. Couldn't we recombine two constants + ;; and use a vop that only takes the object and just ONE index? (define-vop (,(symbolicate name "-C")) - ,@(when translate - `((:translate ,translate))) + (:translate ,translate) (:policy :fast-safe) (:args (object :scs (descriptor-reg))) - (:info index offset) + (:info index addend) (:arg-types ,type (:constant (load/store-index ,n-word-bytes ,(eval lowtag) ,(eval offset))) @@ -332,108 +396,34 @@ n-word-bytes vector-data-offset))) (:results (value :scs ,scs)) (:result-types ,el-type) - (:generator 2 ; pw was 5 - (inst mov value (ea (- (* (+ ,offset index offset) n-word-bytes) ,lowtag) - object)))))) - -(defmacro define-full-setter (name type offset lowtag scs el-type &optional translate) - (let ((want-both-variants - (cond ((symbolp name) t) - (t - (aver (typep name '(cons symbol (cons (eql :no-constant-variant) null)))) - (setq name (car name)) - nil)))) - `(progn - (define-vop (,name) - ,@(when translate - `((:translate ,translate))) + (:vop-var vop) + (:generator 2 + ,@(when (eq translate 'sb-bignum:%bignum-ref-with-offset) + '((bignum-index-check object index addend vop))) + (let ((ea (ea (- (* (+ ,offset index addend) n-word-bytes) ,lowtag) object))) + ,@(trap '(emit-constant (+ index addend))) + (inst mov value ea))))))) + +;;; used for: INSTANCE-INDEX-SET %CLOSURE-INDEX-SET +;;; SB-BIGNUM:%BIGNUM-SET %SET-ARRAY-DIMENSION %SET-VECTOR-RAW-BITS +(defmacro define-full-setter (name type offset lowtag scs el-type translate) + `(define-vop (,name) + (:translate ,translate) (:policy :fast-safe) (:args (object :scs (descriptor-reg)) - (index :scs (any-reg)) - (value :scs ,scs :target result)) + (index :scs (any-reg immediate signed-reg unsigned-reg)) + (value :scs ,scs)) (:arg-types ,type tagged-num ,el-type) - (:results (result :scs ,scs)) - (:result-types ,el-type) (:vop-var vop) - (:generator 4 ; was 5 - ,@(if (eq name 'code-header-set) - '((inst push value) - ;; the asm routine wants a natural machine integer as the index, - ;; but this macro declares the index arg as 'any-reg', so it has a tag bit, - ;; so we'll push the arg and then shift right as the next instruction. - (inst push index) - (inst shr :qword (ea rsp-tn) n-fixnum-tag-bits) - (inst push object) - (invoke-asm-routine 'call 'code-header-set vop) - (move result value)) - `((gen-cell-set - (ea (- (* ,offset n-word-bytes) ,lowtag) - object index (ash 1 (- word-shift n-fixnum-tag-bits))) - value result vop - ,(eq name 'set-funcallable-instance-info)))))) - ,@(when want-both-variants - `((define-vop (,(symbolicate name "-C")) - ,@(when translate - `((:translate ,translate))) - (:policy :fast-safe) - (:args (object :scs (descriptor-reg)) - (value :scs ,scs :target result)) - (:info index) - (:arg-types ,type - (:constant (load/store-index ,n-word-bytes ,(eval lowtag) - ,(eval offset))) - ,el-type) - (:results (result :scs ,scs)) - (:result-types ,el-type) - (:vop-var vop) - (:generator 3 ; was 5 - (gen-cell-set - (ea (- (* (+ ,offset index) n-word-bytes) ,lowtag) - object) - value result vop - ,(eq name 'set-funcallable-instance-info))))))))) - -(defmacro define-full-setter+offset (name type offset lowtag scs el-type &optional translate) - `(progn - (define-vop (,name) - ,@(when translate - `((:translate ,translate))) - (:policy :fast-safe) - (:args (object :scs (descriptor-reg)) - (index :scs (any-reg)) - (value :scs ,scs :target result)) - (:info offset) - (:arg-types ,type tagged-num - (:constant (constant-displacement other-pointer-lowtag - n-word-bytes - vector-data-offset)) - ,el-type) - (:results (result :scs ,scs)) - (:result-types ,el-type) - (:generator 4 ; was 5 - (gen-cell-set - (ea (- (* (+ ,offset offset) n-word-bytes) ,lowtag) - object index (ash 1 (- word-shift n-fixnum-tag-bits))) - value result))) - (define-vop (,(symbolicate name "-C")) - ,@(when translate - `((:translate ,translate))) - (:policy :fast-safe) - (:args (object :scs (descriptor-reg)) - (value :scs ,scs :target result)) - (:info index offset) - (:arg-types ,type - (:constant (load/store-index ,n-word-bytes ,(eval lowtag) - ,(eval offset))) - (:constant (constant-displacement other-pointer-lowtag - n-word-bytes - vector-data-offset)) - ,el-type) - (:results (result :scs ,scs)) - (:result-types ,el-type) - (:generator 3 ; was 5 - (gen-cell-set - (ea (- (* (+ ,offset index offset) n-word-bytes) ,lowtag) - object) - value result))))) - + (:temporary (:sc unsigned-reg) val-temp) + (:generator 4 + ,@(when (eq translate 'sb-bignum:%bignum-set) + '((bignum-index-check object index 0 vop))) + (let ((ea (if (sc-is index immediate) + (ea (- (* (+ ,offset (tn-value index)) n-word-bytes) ,lowtag) + object) + (ea (- (* ,offset n-word-bytes) ,lowtag) + object index (index-scale n-word-bytes index))))) + ,@(when (member name '(instance-index-set %closure-index-set)) + '((emit-gc-store-barrier object nil val-temp (vop-nth-arg 2 vop) value))) + (gen-cell-set ea value val-temp))))) diff --git a/src/compiler/x86-64/memory.lisp b/src/compiler/x86-64/memory.lisp index 3ac8742262..ca1e830e92 100644 --- a/src/compiler/x86-64/memory.lisp +++ b/src/compiler/x86-64/memory.lisp @@ -18,49 +18,60 @@ (+ nil-value (static-symbol-offset symbol) offset) (make-fixup symbol :immobile-symbol offset))))) -(defun gen-cell-set (ea value result &optional vop pseudo-atomic) - (when pseudo-atomic - ;; (SETF %FUNCALLABLE-INSTANCE-FUN) and (SETF %FUNCALLABLE-INSTANCE-INFO) - ;; pass in pseudo-atomic = T. - (pseudo-atomic () - (inst push (ea-base ea)) - (invoke-asm-routine 'call 'touch-gc-card vop) - (gen-cell-set ea value result)) - (return-from gen-cell-set)) - (when (sc-is value immediate) - (let ((bits (encode-value-if-immediate value))) - (cond ((not result) - ;; Try to move imm-to-mem if BITS fits - (acond ((or (and (fixup-p bits) - ;; immobile-object fixups must fit in 32 bits - (eq (fixup-flavor bits) :immobile-symbol) - bits) - (plausible-signed-imm32-operand-p bits)) - (inst mov :qword ea it)) - (t - (inst mov temp-reg-tn bits) - (inst mov ea temp-reg-tn))) - (return-from gen-cell-set)) - ;; Move the immediate value into RESULT provided that doing so - ;; doesn't clobber EA. If it would, use TEMP-REG-TN instead. - ;; TODO: if RESULT is unused, and the immediate fits in an - ;; imm32 operand, then perform imm-to-mem move, but as the comment - ;; observes, there's no easy way to spot an unused TN. - ((or (location= (ea-base ea) result) - (awhen (ea-index ea) (location= it result))) - (inst mov temp-reg-tn bits) - (setq value temp-reg-tn)) - (t - ;; Can move into RESULT, then into EA - (inst mov result bits) - (inst mov ea result) - (return-from gen-cell-set))))) - (inst mov :qword ea value) ; specify the size for when VALUE is an integer - (when result - ;; Ideally we would skip this move if RESULT is unused hereafter, - ;; but unfortunately (NOT (TN-READS RESULT)) isn't equivalent - ;; to there being no reads from the TN at all. - (move result value))) +;;; TODOs: +;;; 1. Sometimes people write constructors like +;;; (defun make-foo (&key a b c) +;;; (let ((new-foo (really-make-foo))) +;;; (when should-set-a (setf (foo-a new-foo) a)) +;;; (when should-set-b (setf (foo-b new-foo) b)) +;;; ... +;;; In this case, the asssignments are constructor-like. Even though +;;; they look mutating, the store barrier can be omitted. +;;; I think the general idea is that if a slot of a newly +;;; constructed thing receives the value of an incoming +;;; argument, the object in that argument can't possibly +;;; be younger than the newly constructed thing. +;;; 2. hash-table k/v pair should mark once only. +;;; (the vector elements are certainly on the same card) +(defun emit-gc-store-barrier (object cell-address scratch-reg &optional value-tn-ref value-tn) + (when (sc-is object constant immediate) + (aver (symbolp (tn-value object)))) + (when (require-gc-store-barrier-p object value-tn-ref value-tn) + (if cell-address ; for SIMPLE-VECTOR, the page holding the specific element index gets marked + (inst lea scratch-reg cell-address) + ;; OBJECT could be a symbol in immobile space + (inst mov scratch-reg (encode-value-if-immediate object))) + (inst shr scratch-reg gencgc-card-shift) + ;; gc_allocate_ptes() asserts mask to be < 32 bits, which is hugely generous. + (inst and :dword scratch-reg card-index-mask) + ;; I wanted to use thread-tn as the source of the store, but it isn't 256-byte-aligned + ;; due to presence of negatively indexed thread header slots. + ;; Probably word-alignment is enough, because we can just check the lowest bit, + ;; borrowing upon the idea from PSEUDO-ATOMIC which uses RBP-TN as the source. + ;; I'd like to measure to see if using a register is actually better. + ;; If all threads store 0, it might be easier on the CPU's store buffer. + ;; Otherwise, it has to remember who "wins". 0 makes it indifferent. + (inst mov :byte (ea gc-card-table-reg-tn scratch-reg) 0))) + +(defun gen-cell-set (ea value val-temp) + (sc-case value + (immediate + (let ((bits (encode-value-if-immediate value))) + ;; Try to move imm-to-mem if BITS fits + (acond ((or (and (fixup-p bits) + ;; immobile-object fixups must fit in 32 bits + (eq (fixup-flavor bits) :immobile-symbol) + bits) + (plausible-signed-imm32-operand-p bits)) + (inst mov :qword ea it)) + (t + (inst mov val-temp bits) + (inst mov ea val-temp))))) + (constant + (inst mov val-temp value) + (inst mov :qword ea val-temp)) + (t + (inst mov :qword ea value)))) ;;; CELL-REF and CELL-SET are used to define VOPs like CAR, where the ;;; offset to be read or written is a property of the VOP used. @@ -78,8 +89,12 @@ (value :scs (descriptor-reg any-reg immediate))) (:variant-vars offset lowtag) (:policy :fast-safe) + (:temporary (:sc unsigned-reg) val-temp) + (:vop-var vop) (:generator 4 - (gen-cell-set (object-slot-ea object offset lowtag) value nil))) + (emit-gc-store-barrier object nil val-temp (vop-nth-arg 1 vop) value) + (let ((ea (object-slot-ea object offset lowtag))) + (gen-cell-set ea value val-temp)))) ;;; X86 special (define-vop (cell-xadd) @@ -91,7 +106,7 @@ (:policy :fast-safe) (:generator 4 (move result value) - (inst xadd (object-slot-ea object offset lowtag) result :lock))) + (inst xadd :lock (object-slot-ea object offset lowtag) result))) (define-vop (cell-xsub cell-xadd) (:args (object) @@ -103,11 +118,11 @@ (sc-case value (immediate (let ((k (tn-value value))) - (inst mov result (fixnumize (if (= k sb-xc:most-negative-fixnum) k (- k)))))) + (inst mov result (fixnumize (if (= k most-negative-fixnum) k (- k)))))) (t (move result value) (inst neg result))) - (inst xadd (object-slot-ea object offset lowtag) result :lock))) + (inst xadd :lock (object-slot-ea object offset lowtag) result))) (define-vop (atomic-inc-symbol-global-value cell-xadd) (:translate %atomic-inc-symbol-global-value) @@ -149,7 +164,7 @@ (const (if (sc-is delta immediate) (fixnumize ,(if (eq inherit 'cell-xsub) `(let ((x (tn-value delta))) - (if (= x sb-xc:most-negative-fixnum) + (if (= x most-negative-fixnum) x (- x))) `(tn-value delta))))) (retry (gen-label))) @@ -167,9 +182,9 @@ `(progn (move newval rax) (inst sub newval delta)) `(inst lea newval (ea rax delta)))) - (inst cmpxchg + (inst cmpxchg :lock (object-slot-ea cell ,slot list-pointer-lowtag) - newval :lock) + newval) (inst jmp :ne retry) (inst mov result rax))))))) (def-atomic %atomic-inc-car cell-xadd cons-car-slot) @@ -181,8 +196,92 @@ (define-vop (set-instance-hashed) (:args (x :scs (descriptor-reg))) (:generator 1 - (inst or :byte (ea (- 1 instance-pointer-lowtag) x) + (inst or :lock :byte (ea (- 1 instance-pointer-lowtag) x) ;; Bit index is 0-based. Subtract 8 since we're using the EA ;; to select byte 1 of the header word. - (ash 1 (- stable-hash-required-flag 8)) - :lock))) + (ash 1 (- stable-hash-required-flag 8))))) + +(defmacro compute-splat-bits (value) + ;; :SAFE-DEFAULT means any unspecific value that is safely a default. + ;; Heap allocation uses 0 since that costs nothing. + ;; If the user wanted a specific value, it could have been explicitly given. + `(if (typep ,value 'sb-vm:word) + ,value + (case ,value + (:unbound (unbound-marker-bits)) + ((nil) (bug "Should not see SPLAT NIL")) + (t #+ubsan unwritten-vector-element-marker + #-ubsan 0)))) + +;;; This logic was formerly in ALLOCATE-VECTOR-ON-STACK. +;;; Choosing amongst 3 vops gets potentially better register allocation +;;; by not wasting registers in the cases that don't use them. +(define-vop (splat-word) + (:policy :fast-safe) + (:translate splat) + (:args (vector :scs (descriptor-reg))) + (:info words value) + (:arg-types * (:constant (eql 1)) (:constant t)) + (:results (result :scs (descriptor-reg))) + (:generator 1 + (progn words) ; don't put it in :ignore, which gets inherited + (inst mov :qword + (ea (- (* vector-data-offset n-word-bytes) other-pointer-lowtag) vector) + (compute-splat-bits value)) + (move result vector))) + +(define-vop (splat-small splat-word) + (:arg-types * (:constant (integer 2 10)) (:constant t)) + (:temporary (:sc complex-double-reg) zero) + (:generator 5 + (let ((bits (compute-splat-bits value))) + (if (= bits 0) + (inst xorpd zero zero) + (inst movdqa zero + (register-inline-constant :oword (logior (ash bits 64) bits))))) + (let ((data-addr (ea (- (* vector-data-offset n-word-bytes) other-pointer-lowtag) + vector))) + (multiple-value-bind (double single) (truncate words 2) + (dotimes (i double) + (inst movapd data-addr zero) + (setf data-addr (ea (+ (ea-disp data-addr) (* n-word-bytes 2)) + (ea-base data-addr)))) + (unless (zerop single) + (inst movaps data-addr zero)))) + (move result vector))) + +(define-vop (splat-any splat-word) + ;; vector has to conflict with everything so that a tagged pointer + ;; corresponding to RDI always exists + (:args (vector :scs (descriptor-reg) :to (:result 0)) + (words :scs (unsigned-reg immediate) :target rcx)) + (:info value) + (:arg-types * positive-fixnum (:constant t)) + (:temporary (:sc any-reg :offset rdi-offset :from (:argument 0) + :to (:result 0)) rdi) + (:temporary (:sc any-reg :offset rcx-offset :from (:argument 1) + :to (:result 0)) rcx) + (:temporary (:sc any-reg :offset rax-offset :from :eval + :to (:result 0)) rax) + (:results (result :scs (descriptor-reg))) + (:generator 10 + (inst lea rdi (ea (- (* vector-data-offset n-word-bytes) other-pointer-lowtag) + vector)) + (let ((bits (compute-splat-bits value))) + (cond ((and (= bits 0) + (constant-tn-p words) + (typep (tn-value words) '(unsigned-byte 7))) + (zeroize rax) + (inst lea :dword rcx (ea (tn-value words) rax))) ; smaller encoding + (t + ;; words could be in RAX, so read it first, then zeroize + (inst mov rcx (or (and (constant-tn-p words) (tn-value words)) words)) + (if (= bits 0) (zeroize rax) (inst mov rax bits))))) + (inst rep) + (inst stos :qword) + (move result vector))) + +(dolist (name '(splat-word splat-small splat-any)) + ;; It wants a function, not a symbol + (setf (sb-c::vop-info-optimizer (template-or-lose name)) + (lambda (vop) (sb-c::elide-zero-fill vop)))) diff --git a/src/compiler/x86-64/move.lisp b/src/compiler/x86-64/move.lisp index 78a34a1684..f10ec02b25 100644 --- a/src/compiler/x86-64/move.lisp +++ b/src/compiler/x86-64/move.lisp @@ -12,7 +12,9 @@ (in-package "SB-VM") (defun zeroize (tn) - (inst xor :dword tn tn)) + (if (stack-tn-p tn) + (inst mov tn 0) + (inst xor :dword tn tn))) (define-move-fun (load-immediate 1) (vop x y) ((immediate) @@ -63,10 +65,11 @@ (not (or (location= x y) (and (sc-is x any-reg descriptor-reg immediate) (sc-is y control-stack)))))) + (:temporary (:sc any-reg :from (:argument 0) :to (:result 0)) temp) (:generator 0 (if (and (sc-is x immediate) (sc-is y any-reg descriptor-reg control-stack)) - (move-immediate y (encode-value-if-immediate x) temp-reg-tn) + (move-immediate y (encode-value-if-immediate x) temp) (move y x)))) (define-move-vop move :move @@ -122,20 +125,20 @@ (fp :scs (any-reg) :load-if (not (sc-is y any-reg descriptor-reg)))) (:results (y)) + (:temporary (:sc unsigned-reg) val-temp) ; for oversized immediate operand (:generator 0 + (let ((val (encode-value-if-immediate x))) (sc-case y ((any-reg descriptor-reg) (if (sc-is x immediate) - (let ((val (encode-value-if-immediate x))) - (if (eql val 0) (zeroize y) (inst mov y val))) + (if (eql val 0) (zeroize y) (inst mov y val)) (move y x))) ((control-stack) - (if (= (tn-offset fp) esp-offset) + (if (= (tn-offset fp) rsp-offset) ;; C-call - (storew (encode-value-if-immediate x) fp (tn-offset y)) + (storew val fp (tn-offset y) 0 val-temp) ;; Lisp stack - (storew (encode-value-if-immediate x) fp - (frame-word-offset (tn-offset y)))))))) + (storew val fp (frame-word-offset (tn-offset y)) 0 val-temp))))))) (define-move-vop move-arg :move-arg (any-reg descriptor-reg) @@ -204,19 +207,23 @@ (define-vop (move-to-word/integer) (:args (x :scs (descriptor-reg) :target y)) (:results (y :scs (signed-reg unsigned-reg))) + (:results-var results) (:note "integer to untagged word coercion") (:temporary (:sc unsigned-reg) backup) (:generator 4 - (move y x) - (if (location= x y) - ;; It would be great if a principled way existed to advise GC of - ;; algebraic transforms such as 2*R being a conservative root. - ;; Until that is possible, emit straightforward code that uses - ;; a copy of the potential reference. - (move backup x) - (setf backup x)) - (inst sar y 1) ; optimistically assume it's a fixnum - (inst jmp :nc DONE) ; no carry implies tag was 0 + (cond ((types-equal-or-intersect (tn-ref-type results) (specifier-type 'fixnum)) + (move y x) + (if (location= x y) + ;; It would be great if a principled way existed to advise GC of + ;; algebraic transforms such as 2*R being a conservative root. + ;; Until that is possible, emit straightforward code that uses + ;; a copy of the potential reference. + (move backup x) + (setf backup x)) + (inst sar y 1) ; optimistically assume it's a fixnum + (inst jmp :nc DONE)) ; no carry implies tag was 0 + (t + (setf backup x))) (loadw y backup bignum-digits-offset other-pointer-lowtag) DONE)) @@ -246,22 +253,17 @@ (signed-reg unsigned-reg) (any-reg descriptor-reg)) (eval-when (:compile-toplevel :execute) - ;; Don't use a macro for this, because define-vop is weird. + ;; This is like a macro, but not a macro, because define-vop is weird. (defun bignum-from-reg (tn signedp) - (flet ((make-vector (suffix) + (flet ((make-vector () (map 'vector (lambda (x) ;; At present R11 can not occur here, ;; but let's be future-proof and allow for it. (unless (member x '(rsp rbp) :test 'string=) - (symbolicate "ALLOC-" signedp "-BIGNUM-IN-" x suffix))) + (symbolicate "ALLOC-" signedp "-BIGNUM-IN-" x))) +qword-register-names+))) - `(aref (cond #+avx2 - ((avx-registers-used-p) - ',(make-vector "-AVX2")) - (t - ',(make-vector ""))) - (tn-offset ,tn))))) + `(aref ,(make-vector) (tn-offset ,tn))))) ;;; Convert an untagged signed word to a lispobj -- fixnum or bignum ;;; as the case may be. Fixnum case inline, bignum case in an assembly @@ -295,32 +297,30 @@ (define-vop (move-from-fixnum+1) (:args (x :scs (signed-reg unsigned-reg))) (:results (y :scs (any-reg descriptor-reg))) + (:args-var arg-ref) + (:vop-var vop) (:generator 4 - (cond ((= n-fixnum-tag-bits 1) - (move y x) - (inst shl y 1) - (inst cmov :o y (emit-constant (1+ sb-xc:most-positive-fixnum)))) - (t - ;; not worth optimizing into SHL. The processor doesn't set OF for - ;; for shift count > 1 so we'd have to detect overflow differently. - (inst imul y x (ash 1 n-fixnum-tag-bits)) - (inst jmp :no DONE) - (move y (emit-constant (1+ sb-xc:most-positive-fixnum))))) + (let ((const (case (vop-name vop) + (move-from-fixnum-1 (1- most-negative-fixnum)) + (t (1+ most-positive-fixnum))))) + (cond ((= n-fixnum-tag-bits 1) + (cond ((csubtypep (tn-ref-type arg-ref) (specifier-type 'fixnum)) + ;; I think MAYBE-MOVE-FROM-FIXNUM+-1 could select MOVE-FROM-WORD/FIXNUM + ;; if Y is known to fit in a fixnum, but this works, albeit redundant. + (if (location= x y) (inst shl y 1) (inst lea y (ea x x)))) + (t + (move y x) + (inst shl y 1) + (inst cmov :o y (emit-constant const))))) + (t + ;; not worth optimizing into SHL. The processor doesn't set OF for + ;; for shift count > 1 so we'd have to detect overflow differently. + (inst imul y x (ash 1 n-fixnum-tag-bits)) + (inst jmp :no DONE) + (move y (emit-constant const))))) DONE)) -(define-vop (move-from-fixnum-1 move-from-fixnum+1) - (:generator 4 - (cond ((= n-fixnum-tag-bits 1) - (move y x) - (inst shl y 1) - (inst cmov :o y (emit-constant (1- sb-xc:most-negative-fixnum)))) - (t - ;; not worth optimizing into SHL. The processor doesn't set OF for - ;; for shift count > 1 so we'd have to detect overflow differently. - (inst imul y x (ash 1 n-fixnum-tag-bits)) - (inst jmp :no DONE) - (move y (emit-constant (1- sb-xc:most-negative-fixnum))))) - DONE)) +(define-vop (move-from-fixnum-1 move-from-fixnum+1)) ;;; Convert an untagged unsigned word to a lispobj -- fixnum or bignum ;;; as the case may be. Fixnum case inline, bignum case in an assembly @@ -378,7 +378,7 @@ ((signed-reg unsigned-reg) (move y x)) ((signed-stack unsigned-stack) - (if (= (tn-offset fp) esp-offset) + (if (= (tn-offset fp) rsp-offset) (storew x fp (tn-offset y)) ; c-call (storew x fp (frame-word-offset (tn-offset y)))))))) (define-move-vop move-word-arg :move-arg diff --git a/src/compiler/x86-64/nlx.lisp b/src/compiler/x86-64/nlx.lisp index f040c4862c..6a4b7e8427 100644 --- a/src/compiler/x86-64/nlx.lisp +++ b/src/compiler/x86-64/nlx.lisp @@ -38,6 +38,15 @@ ;;; Compute the address of the catch block from its TN, then store into the ;;; block the current Fp, Env, Unwind-Protect, and the entry PC. +#+sb-thread +(progn + ;; MOVAPD instruction faults if not properly aligned + (assert (evenp (/ (info :variable :wired-tls '*binding-stack-pointer*) n-word-bytes))) + (assert (= (- (info :variable :wired-tls '*current-catch-block*) + (info :variable :wired-tls '*binding-stack-pointer*)) + n-word-bytes)) + (assert (= (- unwind-block-current-catch-slot unwind-block-bsp-slot) 1))) + (define-vop (make-unwind-block) (:args (tn)) (:info entry-label) @@ -53,9 +62,7 @@ (inst lea temp (rip-relative-ea entry-label)) (storew temp block unwind-block-entry-pc-slot) #+sb-thread - (let ((bsp #1=(info :variable :wired-tls '*binding-stack-pointer*))) - #.(assert (and (= (- (info :variable :wired-tls '*current-catch-block*) #1#) n-word-bytes) - (= (- unwind-block-current-catch-slot unwind-block-bsp-slot) 1))) + (let ((bsp (info :variable :wired-tls '*binding-stack-pointer*))) (inst movapd xmm-temp (thread-tls-ea bsp)) (inst movupd (ea (* unwind-block-bsp-slot n-word-bytes) block) xmm-temp)) #-sb-thread @@ -179,6 +186,19 @@ (inst jmp defaulting-done)))))) (inst mov rsp-tn sp))) +(define-vop (nlx-entry-single) + (:args (sp) + (start)) + (:results (res :from :load)) + (:info label) + (:save-p :force-to-stack) + (:vop-var vop) + (:generator 30 + (emit-label label) + (note-this-location vop :non-local-entry) + (inst mov res start) + (inst mov rsp-tn sp))) + (define-vop (nlx-entry-multiple) (:args (top :target result :scs (any-reg)) @@ -251,6 +271,7 @@ (:temporary (:sc sap-reg) temp) (:temporary (:sc descriptor-reg :offset rbx-offset) saved-function) (:temporary (:sc unsigned-reg :offset rax-offset) block) + (:temporary (:sc unsigned-reg :offset r11-offset) extra-temp-reg) (:vop-var vop) (:generator 22 ;; Store the function into a non-stack location, since we'll be @@ -268,8 +289,8 @@ (loadw temp ofp sap-pointer-slot other-pointer-lowtag) (storew temp block unwind-block-cfp-slot) - (inst lea temp-reg-tn (rip-relative-ea entry-label)) - (storew temp-reg-tn block unwind-block-entry-pc-slot) + (inst lea extra-temp-reg (rip-relative-ea entry-label)) + (storew extra-temp-reg block unwind-block-entry-pc-slot) (storew bsp block unwind-block-bsp-slot) (storew catch-block block unwind-block-current-catch-slot) diff --git a/src/compiler/x86-64/parms.lisp b/src/compiler/x86-64/parms.lisp index aaa9012d4c..3641be229e 100644 --- a/src/compiler/x86-64/parms.lisp +++ b/src/compiler/x86-64/parms.lisp @@ -17,24 +17,20 @@ (defconstant sb-assem:+inst-alignment-bytes+ 1) (defconstant +backend-fasl-file-implementation+ :x86-64) -(defconstant-eqx +fixup-kinds+ #(:absolute :relative :absolute64) - #'equalp) +(defconstant-eqx +fixup-kinds+ #(:abs32 :rel32 :absolute) #'equalp) -;;; KLUDGE: It would seem natural to set this by asking our C runtime -;;; code for it, but mostly we need it for GENESIS, which doesn't in -;;; general have our C runtime code running to ask, so instead we set -;;; it by hand. -- WHN 2001-04-15 -;;; -;;; Actually any information that we can retrieve C-side would be -;;; useless in SBCL, since it's possible for otherwise binary -;;; compatible systems to return different values for getpagesize(). -;;; -- JES, 2007-01-06 +;;; This size is supposed to indicate something about the actual granularity +;;; at which you can map memory. We just hardwire it, but that may or may not +;;; be necessary any more. (defconstant +backend-page-bytes+ #+win32 65536 #-win32 32768) -;;; The size in bytes of GENCGC cards, i.e. the granularity at which -;;; writes to old generations are logged. With mprotect-based write -;;; barriers, this must be a multiple of the OS page size. -(defconstant gencgc-card-bytes +backend-page-bytes+) +;;; The size in bytes of GENCGC pages. A page is the smallest amount of memory +;;; that a thread can claim for a thread-local region, and also determines +;;; the granularity at which we can find the start of a sequence of objects. +(defconstant gencgc-page-bytes 32768) +;;; The divisor relative to page-bytes which computes the granularity +;;; at which writes to old generations are logged. +(defconstant cards-per-page 32) ;;; The minimum size of new allocation regions. While it doesn't ;;; currently make a lot of sense to have a card size lower than ;;; the alloc granularity, it will, once we are smarter about finding @@ -64,35 +60,6 @@ ;;; address space) (defconstant n-machine-word-bits 64) -(defconstant float-sign-shift 31) - -;;; comment from CMU CL: -;;; These values were taken from the alpha code. The values for -;;; bias and exponent min/max are not the same as shown in the 486 book. -;;; They may be correct for how Python uses them. -(defconstant single-float-bias 126) ; Intel says 127. -(defconstant-eqx single-float-exponent-byte (byte 8 23) #'equalp) -(defconstant-eqx single-float-significand-byte (byte 23 0) #'equalp) -;;; comment from CMU CL: -;;; The 486 book shows the exponent range -126 to +127. The Lisp -;;; code that uses these values seems to want already biased numbers. -(defconstant single-float-normal-exponent-min 1) -(defconstant single-float-normal-exponent-max 254) -(defconstant single-float-hidden-bit (ash 1 23)) - -(defconstant double-float-bias 1022) -(defconstant-eqx double-float-exponent-byte (byte 11 20) #'equalp) -(defconstant-eqx double-float-significand-byte (byte 20 0) #'equalp) -(defconstant double-float-normal-exponent-min 1) -(defconstant double-float-normal-exponent-max #x7FE) -(defconstant double-float-hidden-bit (ash 1 20)) - -(defconstant single-float-digits - (+ (byte-size single-float-significand-byte) 1)) - -(defconstant double-float-digits - (+ (byte-size double-float-significand-byte) 32 1)) - ;;; from AMD64 Architecture manual (defconstant float-invalid-trap-bit (ash 1 0)) (defconstant float-denormal-trap-bit (ash 1 1)) @@ -124,24 +91,25 @@ ;;; would be possible, but probably not worth the time and code bloat ;;; it would cause. -- JES, 2005-12-11 -#+linux +#+(or linux darwin) (!gencgc-space-setup #x50000000 - :read-only-space-size 0 - :fixedobj-space-size #.(* 30 1024 1024) - :varyobj-space-size #.(* 130 1024 1024) + :read-only-space-size #+metaspace #.(* 2 1024 1024) + #-metaspace 0 + :fixedobj-space-size #.(* 40 1024 1024) + :text-space-size #.(* 130 1024 1024) :dynamic-space-start #x1000000000) ;;; The default dynamic space size is lower on OpenBSD to allow SBCL to ;;; run under the default 512M data size limit. -#-linux +#-(or linux darwin) (!gencgc-space-setup #x20000000 - #-win32 :read-only-space-size #-win32 0 + :read-only-space-size 0 :dynamic-space-start #x1000000000 #+openbsd :dynamic-space-size #+openbsd #x1bcf0000) -(defconstant linkage-table-growth-direction :up) -(defconstant linkage-table-entry-size 16) +(defconstant alien-linkage-table-growth-direction :up) +(defconstant alien-linkage-table-entry-size 16) (defenum (:start 8) @@ -177,6 +145,10 @@ ;;; Note these spaces grow from low to high addresses. (defvar *binding-stack-pointer*) +;;; Bit indices into *CPU-FEATURE-BITS* +(defconstant cpu-has-ymm-registers 0) +(defconstant cpu-has-popcnt 1) + (defconstant-eqx +static-symbols+ `#(,@+common-static-symbols+ #+(and immobile-space (not sb-thread)) function-layout @@ -184,7 +156,14 @@ ;; interrupt handling #-sb-thread *pseudo-atomic-bits* ; ditto #-sb-thread *binding-stack-pointer* ; ditto - *cpuid-fn1-ecx*) + ;; Since the text space and alien linkage table might both get relocated on startup + ;; under #+immobile-space, an alien callback wrapper can't wire in the address + ;; of a word that holds the C function pointer to callback_wrapper_trampoline. + ;; (There is no register that points to a known address when entering the callback) + ;; A static symbol works well for this, and is sensible considering that + ;; the assembled wrappers also reside in static space. + #+(and sb-thread immobile-space) callback-wrapper-trampoline + *cpu-feature-bits*) #'equalp) (defconstant-eqx +static-fdefns+ @@ -204,12 +183,23 @@ two-arg-gcd two-arg-lcm ensure-symbol-hash - update-object-layout-or-invalid + sb-impl::install-hash-table-lock + update-object-layout %coerce-callable-to-fun) #'equalp) #+sb-simd-pack -(defglobal *simd-pack-element-types* '(integer single-float double-float)) +(defglobal *simd-pack-element-types* + '(single-float + double-float + (unsigned-byte 8) + (unsigned-byte 16) + (unsigned-byte 32) + (unsigned-byte 64) + (signed-byte 8) + (signed-byte 16) + (signed-byte 32) + (signed-byte 64))) (defconstant undefined-fdefn-header ;; This constant is constructed as follows: Take the INT opcode diff --git a/src/compiler/x86-64/pred.lisp b/src/compiler/x86-64/pred.lisp index 73bcd14ef6..6c3707e88b 100644 --- a/src/compiler/x86-64/pred.lisp +++ b/src/compiler/x86-64/pred.lisp @@ -36,29 +36,45 @@ (define-vop (branch-if) (:info dest not-p flags) + (:vop-var vop) (:generator 0 + (when (cdr flags) + ;; Specifying multiple flags is an extremely confusing convention that supports + ;; floating-point inequality tests utilizing the flag register in an unusual way, + ;; as documented in the COMISS and COMISD instructions: + ;; "the ZF, PF, and CF flags in the EFLAGS register according + ;; to the result (unordered, greater than, less than, or equal)" + ;; I think it would have been better if, instead of allowing more than one flag, + ;; we passed in a pseudo-condition code such as ':sf<=' and deferred to this vop + ;; to interpret the abstract condition in terms of how to CPU sets the bits + ;; in those particular instructions. + ;; Note that other architectures allow only 1 flag in branch-if, if it works at all. + ;; Enable this assertion if you need to sanity-check the preceding claim. + ;; There's really no "dynamic" reason for it to fail. + #+nil + (aver (memq (vop-name (sb-c::vop-prev vop)) + '(<single-float <double-float <=single-float <=double-float + >single-float >double-float >=single-float >=double-float + =/single-float =/double-float)))) (when (eq (car flags) 'not) (pop flags) (setf not-p (not not-p))) - (flet ((negate-condition (name) - (let ((code (logxor 1 (conditional-opcode name)))) - (aref +condition-name-vec+ code)))) - (cond ((null (rest flags)) + (cond ((null (rest flags)) (inst jmp (if not-p (negate-condition (first flags)) (first flags)) dest)) - (not-p + (not-p (let ((not-lab (gen-label)) (last (car (last flags)))) (dolist (flag (butlast flags)) (inst jmp flag not-lab)) (inst jmp (negate-condition last) dest) (emit-label not-lab))) - (t + (t (dolist (flag flags) - (inst jmp flag dest))))))) + (inst jmp flag dest)))))) (define-vop (multiway-branch-if-eq) ;; TODO: also accept signed-reg, unsigned-reg, character-reg @@ -66,6 +82,7 @@ (:args (x :scs (any-reg descriptor-reg))) (:info labels otherwise key-type keys test-vop-name) (:temporary (:sc unsigned-reg) table) + (:temporary (:sc unsigned-reg) temp) (:args-var x-tn-ref) (:generator 10 (let* ((key-derived-type (tn-ref-type x-tn-ref)) @@ -93,12 +110,12 @@ ;; First exclude out-of-bounds values because there's no harm ;; in doing that up front regardless of the argument's lisp type. (typecase -min - ;; TODO: if min is 0, use X directly, don't move into temp-reg-tn - ((eql 0) (move temp-reg-tn x)) - ((signed-byte 32) (inst lea temp-reg-tn (ea -min x))) - (t (inst mov temp-reg-tn x) - (inst add :qword temp-reg-tn (constantize -min)))) - (inst cmp temp-reg-tn (constantize (fixnumize (- max min)))) + ;; TODO: if min is 0, use X directly, don't move into temp + ((eql 0) (move temp x)) + ((signed-byte 32) (inst lea temp (ea -min x))) + (t (inst mov temp x) + (inst add :qword temp (constantize -min)))) + (inst cmp temp (constantize (fixnumize (- max min)))) (inst jmp :a otherwise) ;; We have to check the type here because a chain of EQ tests ;; does not impose a type constraint. @@ -106,7 +123,7 @@ (unless (eq test-vop-name 'sb-vm::fast-if-eq-fixnum/c) (inst test :byte x fixnum-tag-mask) (inst jmp :ne otherwise)) - (setq ea (ea table temp-reg-tn 4)))) + (setq ea (ea table temp 4)))) (inst lea table (register-inline-constant :jump-table vector)) (inst jmp ea)) (character @@ -115,14 +132,14 @@ fast-if-eq-character/c)) (inst cmp :byte x character-widetag) (inst jmp :ne otherwise)) - (inst mov :dword temp-reg-tn x) - (inst shr :dword temp-reg-tn n-widetag-bits) + (inst mov :dword temp x) + (inst shr :dword temp n-widetag-bits) (unless (= min 0) - (inst sub :dword temp-reg-tn min)) - (inst cmp temp-reg-tn (- max min)) + (inst sub :dword temp min)) + (inst cmp temp (- max min)) (inst jmp :a otherwise) (inst lea table (register-inline-constant :jump-table vector)) - (inst jmp (ea table temp-reg-tn 8))))))) + (inst jmp (ea table temp 8))))))) (define-load-time-global *cmov-ptype-representation-vop* (mapcan (lambda (entry) @@ -184,13 +201,11 @@ (:args (then) (else)) (:results (res)) (:info flags) + (:temporary (:sc unsigned-reg) temp) (:generator 0 (let ((not-p (eq (first flags) 'not))) (when not-p (pop flags)) - (flet ((negate-condition (name) - (let ((code (logxor 1 (conditional-opcode name)))) - (aref +condition-name-vec+ code))) - (load-immediate (dst constant-tn + (flet ((load-immediate (dst constant-tn &optional (sc (sc-name (tn-sc dst)))) ;; Can't use ZEROIZE, since XOR will affect the flags. (inst mov dst @@ -201,8 +216,8 @@ (load-immediate res else) (move res else)) (when (sc-is then immediate) - (load-immediate temp-reg-tn then (sc-name (tn-sc res))) - (setf then temp-reg-tn)) + (load-immediate temp then (sc-name (tn-sc res))) + (setf then temp)) (inst cmov (if not-p (negate-condition (first flags)) (first flags)) @@ -211,8 +226,8 @@ (not-p (cond ((sc-is then immediate) (when (location= else res) - (inst mov temp-reg-tn else) - (setf else temp-reg-tn)) + (inst mov temp else) + (setf else temp)) (load-immediate res then)) ((location= else res) (inst xchg else then) @@ -220,8 +235,8 @@ (t (move res then))) (when (sc-is else immediate) - (load-immediate temp-reg-tn else (sc-name (tn-sc res))) - (setf else temp-reg-tn)) + (load-immediate temp else (sc-name (tn-sc res))) + (setf else temp)) (dolist (flag flags) (inst cmov flag res else))) (t @@ -229,8 +244,8 @@ (load-immediate res else) (move res else)) (when (sc-is then immediate) - (load-immediate temp-reg-tn then (sc-name (tn-sc res))) - (setf then temp-reg-tn)) + (load-immediate temp then (sc-name (tn-sc res))) + (setf then temp)) (dolist (flag flags) (inst cmov flag res then)))))))) @@ -254,24 +269,119 @@ #+sb-unicode (def-move-if move-if/char character character-reg character-stack) (def-move-if move-if/sap system-area-pointer sap-reg sap-stack)) + +;;; Return a hint about how to calculate the answer from X,Y and flags. +;;; Return NIL to give up. +(defun computable-from-flags-p (res x y flags) + ;; TODO: handle unsigned-reg + (unless (and (singleton-p flags) + (sc-is res sb-vm::any-reg sb-vm::descriptor-reg)) + (return-from computable-from-flags-p nil)) + ;; There are plenty more algebraic transforms possible, + ;; but this picks off some very common cases. + (flet ((try-shift (x y) + (and (eql x 0) + (typep y '(and fixnum unsigned-byte)) + (= (logcount y) 1) + 'shl)) + (try-add (x y) ; commutative + ;; (signed-byte 32) is gonna work for sure. + ;; Other things might too, but "perfect is the enemy of good". + ;; The constant in LEA is pre-fixnumized. + ;; Post-fixnumizing instead would open up a few more possibilities. + (and (fixnump x) + (fixnump y) + (typep (fixnumize x) '(signed-byte 32)) + (typep (fixnumize y) '(signed-byte 32)) + (member (abs (fixnumize (- x y))) '(2 4 8)) + 'add))) + (or #+sb-thread (or (and (eq x t) (eq y nil) 'boolean) + (and (eq x nil) (eq y t) 'boolean)) + (try-shift x y) + (try-shift y x) + (try-add x y)))) + +(define-vop (compute-from-flags) + (:args (x-tn :scs (immediate constant)) + (y-tn :scs (immediate constant))) + (:results (res :scs (any-reg descriptor-reg))) + (:info flags) + (:generator 3 + (let* ((x (tn-value x-tn)) + (y (tn-value y-tn)) + #+gs-seg (thread-tn nil) + (hint (computable-from-flags-p res x y flags)) + (flag (car flags))) + (ecase hint + (boolean + ;; FIXNUMP -> {T,NIL} could be special-cased, reducing the instruction count by + ;; 1 or 2 depending on whether the argument and result are in the same register. + ;; Best case would be "AND :dword res, arg, 1 ; MOV res, [ea]". + (when (eql x t) + ;; T is at the lower address, so to pick it out we need index=0 + ;; which makes the condition in (IF BIT T NIL) often flipped. + (setq flag (negate-condition flag))) + (inst set flag res) + (inst movzx '(:byte :dword) res res) + (inst mov :dword res + (ea thread-segment-reg (ash thread-t-nil-constants-slot word-shift) + thread-tn res 4))) + (shl + (when (eql x 0) + (setq flag (negate-condition flag))) + (let ((bit (1- (integer-length (fixnumize (logior x y)))))) + (inst set flag res) + (inst movzx '(:byte :dword) res res) + (inst shl (if (> bit 31) :qword :dword) res bit))) + (add + (let* ((x (fixnumize x)) + (y (fixnumize y)) + (min (min x y)) + (delta (abs (- x y))) + ;; [RES+RES+n] encodes more compactly than [RES*2+n] + (ea (if (= delta 2) (ea min res res) (ea min nil res delta)))) + (when (eql x min) + (setq flag (negate-condition flag))) + (inst set flag res) + (inst movzx '(:byte :dword) res res) + ;; Retain bit 63... if either is negative + (inst lea (if (or (minusp x) (minusp y)) :qword :dword) res ea))))))) ;;;; conditional VOPs ;;; Note: a constant-tn is allowed in CMP; it uses an EA displacement, ;;; not immediate data. (define-vop (if-eq) - (:args (x :scs (any-reg descriptor-reg control-stack)) - (y :scs (any-reg descriptor-reg immediate) - :load-if (and (sc-is x control-stack) - (not (sc-is y any-reg descriptor-reg immediate))))) + (:args (x :scs (any-reg descriptor-reg control-stack immediate)) + (y :scs (any-reg descriptor-reg control-stack immediate constant))) (:conditional :e) (:policy :fast-safe) (:translate eq) + (:args-var x-tn-ref) + (:temporary (:sc unsigned-reg) temp) (:generator 6 (cond + ((sc-is y constant) + (inst cmp x (cond ((sc-is x descriptor-reg any-reg) y) + (t (inst mov temp y) temp)))) ((sc-is y immediate) (let* ((value (encode-value-if-immediate y)) (immediate (plausible-signed-imm32-operand-p value))) + (when (and (null (tn-value y)) (tn-ref-type x-tn-ref)) + ;; if the complement of X's type with respect to type NULL can't + ;; be a cons, then we don't need a 4-byte comparison against NIL. + ;; It suffices to test the low byte. Similar logic could pertain to many + ;; other type tests, e.g. STRINGP on known (OR INSTANCE STRING) + ;; could skip the widetag test. + ;; I'm starting to wonder if it would be better to expose the lowtag/widetag + ;; tests in IR1 as an AND expression so that type inference can remove what's + ;; possible to deduce. The we just need a way to efficiently recombine + ;; the AND back to one vop where we can. "selection DAG, anyone?" + (when (not (types-equal-or-intersect + (type-difference (tn-ref-type x-tn-ref) (specifier-type 'null)) + (specifier-type 'cons))) + (inst cmp :byte x (logand nil-value #xff)) + (return-from if-eq))) (cond ((fixup-p value) ; immobile object (inst cmp x value)) ((and (zerop value) (sc-is x any-reg descriptor-reg)) @@ -281,8 +391,11 @@ ((not (sc-is x control-stack)) (inst cmp x (constantize value))) (t - (inst mov temp-reg-tn value) - (inst cmp x temp-reg-tn))))) + (inst mov temp value) + (inst cmp x temp))))) + ((and (sc-is x control-stack) (sc-is y control-stack)) + (inst mov temp x) + (inst cmp temp y)) (t (inst cmp x y))))) @@ -326,32 +439,6 @@ instance) (encode-value-if-immediate x)))) -(define-vop (fixnump-instance-ref) - (:args (instance :scs (descriptor-reg))) - (:arg-types * (:constant (unsigned-byte 16))) - (:info slot) - (:translate fixnump-instance-ref) - (:conditional :e) - (:policy :fast-safe) - (:generator 1 - (inst test :byte - (ea (+ (- instance-pointer-lowtag) - (ash (+ slot instance-slots-offset) word-shift)) - instance) - fixnum-tag-mask))) -(macrolet ((def-fixnump-cxr (name index) - `(define-vop (,name) - (:args (x :scs (descriptor-reg))) - (:translate ,name) - (:conditional :e) - (:policy :fast-safe) - (:generator 1 - (inst test :byte - (ea (- (ash ,index word-shift) list-pointer-lowtag) x) - fixnum-tag-mask))))) - (def-fixnump-cxr fixnump-car cons-car-slot) - (def-fixnump-cxr fixnump-cdr cons-cdr-slot)) - ;;; See comment below about ASSUMPTIONS (eval-when (:compile-toplevel) (assert (eql other-pointer-lowtag #b1111)) @@ -376,7 +463,9 @@ (:temporary (:sc unsigned-reg :offset rdi-offset :from (:argument 0)) rdi) (:temporary (:sc unsigned-reg :offset rsi-offset :from (:argument 1)) rsi) (:temporary (:sc unsigned-reg :offset rax-offset) rax) + (:temporary (:sc unsigned-reg :offset r11-offset) asm-temp) (:vop-var vop) + (:ignore asm-temp) (:generator 15 (inst cmp x y) (inst jmp :e done) ; affirmative diff --git a/src/compiler/x86-64/sap.lisp b/src/compiler/x86-64/sap.lisp index d3af5c401c..c762b080de 100644 --- a/src/compiler/x86-64/sap.lisp +++ b/src/compiler/x86-64/sap.lisp @@ -27,10 +27,11 @@ (define-vop (move-from-sap) (:args (sap :scs (sap-reg) :to :result)) (:results (res :scs (descriptor-reg) :from :argument)) + #+gs-seg (:temporary (:sc unsigned-reg :offset 15) thread-tn) (:note "SAP to pointer coercion") (:node-var node) (:generator 20 - (alloc-other res sap-widetag sap-size node) + (alloc-other sap-widetag sap-size res node nil thread-tn) (storew sap res sap-pointer-slot other-pointer-lowtag))) (define-move-vop move-from-sap :move (sap-reg) (descriptor-reg)) @@ -61,7 +62,7 @@ (sap-reg (move y x)) (sap-stack - (if (= (tn-offset fp) esp-offset) + (if (= (tn-offset fp) rsp-offset) (storew x fp (tn-offset y)) ; c-call (storew x fp (frame-word-offset (tn-offset y)))))))) (define-move-vop move-sap-arg :move-arg @@ -103,40 +104,16 @@ (define-vop () (:translate sap+) - (:args (ptr :scs (sap-reg) :target res - :load-if (not (location= ptr res))) - (offset :scs (signed-reg immediate))) + (:args (ptr :scs (sap-reg sap-stack) :target res :load-if nil) + (offset :scs (signed-reg signed-stack immediate))) (:arg-types system-area-pointer signed-num) - (:results (res :scs (sap-reg) :from (:argument 0) - :load-if (not (location= ptr res)))) + (:results (res :scs (sap-reg sap-stack) :load-if nil)) + (:vop-var vop) (:result-types system-area-pointer) - (:temporary (:sc signed-reg) temp) + (:temporary (:sc signed-reg) temp) ; TODO: add an :unused-if on this (:policy :fast-safe) (:generator 1 - (cond ((and (sc-is ptr sap-reg) (sc-is res sap-reg) - (not (location= ptr res))) - (sc-case offset - (signed-reg - (inst lea res (ea ptr offset))) - (immediate - (let ((value (tn-value offset))) - (cond ((typep value '(signed-byte 32)) - (inst lea res (ea value ptr))) - (t - (inst mov temp value) - (inst lea res (ea ptr temp)))))))) - (t - (move res ptr) - (sc-case offset - (signed-reg - (inst add res offset)) - (immediate - (let ((value (tn-value offset))) - (cond ((typep value '(signed-byte 32)) - (inst add res (tn-value offset))) - (t - (inst mov temp value) - (inst add res temp)))))))))) + (emit-inline-add-sub 'add ptr offset res temp vop 'identity))) (define-vop () (:translate sap-) @@ -163,16 +140,16 @@ https://llvm.org/doxygen/MemorySanitizer_8cpp.html /// and we store the shadow _before_ the app store." |# -(defun emit-sap-ref (size insn modifier result ea node vop) - (declare (ignorable node size vop)) +(defun emit-sap-ref (size insn modifier result ea node vop temp) + (declare (ignorable node size vop temp)) (cond #+linux ((and (sb-c:msan-unpoison sb-c:*compilation*) (policy node (> safety 0))) - ;; Must not clobber TEMP-REG-TN with the load. - (aver (not (location= temp-reg-tn result))) - (inst lea temp-reg-tn ea) - (sb-assem:inst* insn modifier result (ea temp-reg-tn)) - (inst xor temp-reg-tn (thread-slot-ea thread-msan-xor-constant-slot)) + ;; Must not clobber TEMP with the load. + (aver (not (location= temp result))) + (inst lea temp ea) + (sb-assem:inst* insn modifier result (ea temp)) + (inst xor temp (thread-slot-ea thread-msan-xor-constant-slot)) ;; Per the documentation, shadow is tested _after_ (let ((mask (sb-c::masked-memory-load-p vop)) (good (gen-label)) @@ -181,17 +158,17 @@ https://llvm.org/doxygen/MemorySanitizer_8cpp.html ;; If the load is going to be masked, then we must only check the ;; shadow bits under the mask. (cond ((not mask) - (inst cmp size (ea temp-reg-tn) 0)) + (inst cmp size (ea temp) 0)) ((or (neq size :qword) (plausible-signed-imm32-operand-p mask)) - (inst test size (ea temp-reg-tn) + (inst test size (ea temp) (ldb (byte (* 8 nbytes) 0) mask))) (t ;; Test two 32-bit chunks of the shadow memory since we don't ;; have an available register to load a 64-bit constant. - (inst test :dword (ea temp-reg-tn) (ldb (byte 32 0) mask)) + (inst test :dword (ea temp) (ldb (byte 32 0) mask)) (setq bad (gen-label)) (inst jmp :ne bad) - (inst test :dword (ea 4 temp-reg-tn) (ldb (byte 32 32) mask)))) + (inst test :dword (ea 4 temp) (ldb (byte 32 32) mask)))) (inst jmp :e good) (when bad (emit-label bad)) (inst break sb-vm:uninitialized-load-trap) @@ -203,25 +180,76 @@ https://llvm.org/doxygen/MemorySanitizer_8cpp.html (t (sb-assem:inst* insn modifier result ea)))) -(defun emit-sap-set (size ea value result) +(defun emit-sap-set (size ea value temp) #+linux (when (sb-c:msan-unpoison sb-c:*compilation*) - (inst lea temp-reg-tn ea) - (inst xor temp-reg-tn (thread-slot-ea thread-msan-xor-constant-slot)) - (inst mov size (ea temp-reg-tn) 0)) - (inst mov size ea value) - (move result value)) + (inst lea temp ea) + (inst xor temp (thread-slot-ea thread-msan-xor-constant-slot)) + (inst mov size (ea temp) 0)) + (when (sc-is value constant immediate) + (cond ((plausible-signed-imm32-operand-p (tn-value value)) + (setq value (tn-value value))) + (t + (inst mov temp (tn-value value)) + (setq value temp)))) + (inst mov size ea value)) +(defun emit-cas-sap-ref (size sap offset oldval newval result rax temp) + (multiple-value-bind (disp index) + (cond ((sc-is offset signed-reg) + (values 0 offset)) + ((typep (tn-value offset) '(signed-byte 32)) + (values (tn-value offset) nil)) + (t + (inst mov temp (tn-value offset)) + (values 0 temp))) + (cond ((sc-is oldval immediate constant) + (inst mov rax (tn-value oldval))) + ((not (location= oldval rax)) + (inst mov (if (eq size :qword) :qword :dword) rax oldval))) + (inst cmpxchg size :lock (ea disp sap index) newval) + (unless (location= result rax) + (inst mov (if (eq size :qword) :qword :dword) result rax)))) + +;;; TODO: these should be refactored so that there is only one vop for any given +;;; result storage class. In particular, sap-ref-{8,16,32} can all produce tagged-num. +;;; The vop can examine the node to see which function it translates +;;; and select the appropriate modifier to movzx or movsx. (macrolet ((def-system-ref-and-set (ref-name set-name ref-insn sc type size) - (let ((ref-name-c (symbolicate ref-name "-C")) - (set-name-c (symbolicate set-name "-C")) - (modifier (if (eq ref-insn 'mov) size `(,size :qword)))) + (let ((value-scs (cond ((member ref-name '(sap-ref-64 signed-sap-ref-64)) + `(,sc constant immediate)) + ((not (member ref-name '(sap-ref-single sap-ref-sap + sap-ref-lispobj))) + `(,sc immediate)) + (t + `(,sc)))) + (modifier (if (eq ref-insn 'mov) + size + `(,size ,(if (eq ref-insn 'movzx) :dword :qword))))) `(progn + ,@(when (member ref-name '(sap-ref-8 sap-ref-16 sap-ref-32 sap-ref-64 + signed-sap-ref-64 + sap-ref-lispobj sap-ref-sap)) + `((define-vop (,(symbolicate "CAS-" ref-name)) + (:translate (cas ,ref-name)) + (:policy :fast-safe) + (:args (oldval :scs ,value-scs :target rax) + (newval :scs ,(remove 'immediate value-scs)) + (sap :scs (sap-reg)) + (offset :scs (signed-reg immediate))) + (:arg-types ,type ,type system-area-pointer signed-num) + (:results (result :scs (,sc))) + (:result-types ,type) + (:temporary (:sc unsigned-reg :offset rax-offset + :from (:argument 0) :to :result) rax) + (:temporary (:sc unsigned-reg) temp) + (:generator 3 + (emit-cas-sap-ref ',size sap offset oldval newval result rax temp))))) (define-vop (,ref-name) (:translate ,ref-name) (:policy :fast-safe) @@ -232,9 +260,14 @@ https://llvm.org/doxygen/MemorySanitizer_8cpp.html (:result-types ,type) (:node-var node) (:vop-var vop) + ;; this temp has to be wired because the uninitialized-load-trap handler + ;; looks in RAX to get the poisoned address. + ;; We should have a different variant of this reffer for msan or no msan + ;; to avoid wasting a register that is not needed. + (:temporary (:sc unsigned-reg :offset rax-offset) temp) (:generator 3 (emit-sap-ref ,size ',ref-insn - ',modifier result (ea sap offset) node vop))) - (define-vop (,ref-name-c) + ',modifier result (ea sap offset) node vop temp))) + (define-vop (,(symbolicate ref-name "-C")) (:translate ,ref-name) (:policy :fast-safe) (:args (sap :scs (sap-reg))) @@ -244,28 +277,29 @@ https://llvm.org/doxygen/MemorySanitizer_8cpp.html (:result-types ,type) (:node-var node) (:vop-var vop) + (:temporary (:sc unsigned-reg :offset rax-offset) temp) (:generator 2 (emit-sap-ref ,size ',ref-insn - ',modifier result (ea offset sap) node vop))) + ',modifier result (ea offset sap) node vop temp))) (define-vop (,set-name) (:translate ,set-name) (:policy :fast-safe) - (:args (sap :scs (sap-reg) :to (:eval 0)) - (offset :scs (signed-reg) :to (:eval 0)) - (value :scs (,sc) :target result)) - (:arg-types system-area-pointer signed-num ,type) - (:results (result :scs (,sc))) - (:result-types ,type) - (:generator 5 (emit-sap-set ,size (ea sap offset) value result))) - (define-vop (,set-name-c) + (:args (value :scs ,value-scs) + (sap :scs (sap-reg)) + (offset :scs (signed-reg))) + (:arg-types ,type system-area-pointer signed-num) + (:temporary (:sc unsigned-reg) temp) + (:generator 5 + (emit-sap-set ,size (ea sap offset) value temp))) + (define-vop (,(symbolicate set-name "-C")) (:translate ,set-name) (:policy :fast-safe) - (:args (sap :scs (sap-reg) :to (:eval 0)) - (value :scs (,sc) :target result)) - (:arg-types system-area-pointer (:constant (signed-byte 32)) ,type) + (:args (value :scs ,value-scs) + (sap :scs (sap-reg))) + (:arg-types ,type system-area-pointer (:constant (signed-byte 32))) (:info offset) - (:results (result :scs (,sc))) - (:result-types ,type) - (:generator 4 (emit-sap-set ,size (ea offset sap) value result))))))) + (:temporary (:sc unsigned-reg) temp) + (:generator 4 + (emit-sap-set ,size (ea offset sap) value temp))))))) (def-system-ref-and-set sap-ref-8 %set-sap-ref-8 movzx unsigned-reg positive-fixnum :byte) @@ -275,7 +309,7 @@ https://llvm.org/doxygen/MemorySanitizer_8cpp.html unsigned-reg positive-fixnum :word) (def-system-ref-and-set signed-sap-ref-16 %set-signed-sap-ref-16 movsx signed-reg tagged-num :word) - (def-system-ref-and-set sap-ref-32 %set-sap-ref-32 movzx + (def-system-ref-and-set sap-ref-32 %set-sap-ref-32 mov unsigned-reg unsigned-num :dword) (def-system-ref-and-set signed-sap-ref-32 %set-signed-sap-ref-32 movsx signed-reg signed-num :dword) @@ -314,23 +348,19 @@ https://llvm.org/doxygen/MemorySanitizer_8cpp.html (define-vop (,set-fun) (:translate ,set-fun) (:policy :fast-safe) - (:args (sap :scs (sap-reg) :to (:eval 0)) - (offset :scs (signed-reg) :to (:eval 0)) - (value :scs (,res-sc))) - (:arg-types system-area-pointer signed-num ,res-type) - (:results (result :scs (,res-sc))) - (:result-types ,res-type) - (:generator 5 (inst ,insn (ea sap offset) value) (move result value))) + (:args (value :scs (,res-sc immediate)) + (sap :scs (sap-reg)) + (offset :scs (signed-reg))) + (:arg-types ,res-type system-area-pointer signed-num) + (:generator 5 (inst ,insn (ea sap offset) value))) (define-vop (,(symbolicate set-fun "-C")) (:translate ,set-fun) (:policy :fast-safe) - (:args (sap :scs (sap-reg) :to (:eval 0)) - (value :scs (,res-sc))) - (:arg-types system-area-pointer (:constant (signed-byte 32)) ,res-type) + (:args (value :scs (,res-sc)) + (sap :scs (sap-reg))) + (:arg-types ,res-type system-area-pointer (:constant (signed-byte 32))) (:info offset) - (:results (result :scs (,res-sc))) - (:result-types ,res-type) - (:generator 4 (inst ,insn (ea offset sap) value) (move result value)))))) + (:generator 4 (inst ,insn (ea offset sap) value)))))) (def-system-ref-and-set sap-ref-single single-reg single-float movss) (def-system-ref-and-set sap-ref-double double-reg double-float movsd)) @@ -344,24 +374,9 @@ https://llvm.org/doxygen/MemorySanitizer_8cpp.html (:result-types system-area-pointer) (:generator 2 (let ((disp (- (* vector-data-offset n-word-bytes) other-pointer-lowtag))) - (if (location= sap vector) - (inst add sap disp) - (inst lea sap (ea disp vector)))))) - -;;; Compare and swap -(define-vop (signed-sap-cas-32) - (:policy :fast-safe) - (:args (sap :scs (sap-reg) :to (:eval 0)) - (offset :scs (signed-reg) :to (:eval 0)) - (oldval :scs (signed-reg) :target eax) - (newval :scs (signed-reg) :to (:eval 0))) - (:temporary (:sc unsigned-reg :offset eax-offset - :from (:argument 2) :to (:result 0)) eax) - (:arg-types system-area-pointer signed-num signed-num signed-num) - (:results (result :scs (signed-reg))) - (:result-types signed-num) - (:generator 5 - (inst mov :dword eax oldval) - (inst cmpxchg :dword (ea sap offset) newval :lock) - (inst movsx '(:dword :qword) result eax))) - + (flet ((2-operand-add (dst src) + (cond ((eql src 1) (inst inc dst)) + (t (inst add dst src))))) + (if (location= sap vector) + (2-operand-add sap disp) + (inst lea sap (ea disp vector))))))) diff --git a/src/compiler/x86-64/show.lisp b/src/compiler/x86-64/show.lisp index df25fc2bcd..df8dd7761c 100644 --- a/src/compiler/x86-64/show.lisp +++ b/src/compiler/x86-64/show.lisp @@ -14,27 +14,27 @@ (define-vop (print) (:args (object :scs (descriptor-reg any-reg) - :target rdi)) + :target c-arg)) (:temporary (:sc unsigned-reg - :offset rdi-offset + :offset #+win32 rcx-offset #-win32 rdi-offset :from :eval) - rdi) + c-arg) (:temporary (:sc unsigned-reg :offset rax-offset :target result :from :eval :to (:result 0)) rax) - (:temporary (:sc unsigned-reg) call-target) + (:temporary (:sc unsigned-reg) rsp-save) (:results (result :scs (descriptor-reg))) (:save-p t) (:generator 100 - (move rdi object) - (inst mov call-target rsp-tn) ; save RSP temporarily elsewhere + (move c-arg object) + (inst mov rsp-save rsp-tn) ; save RSP temporarily elsewhere (inst and rsp-tn -16) ; align as required for ABI - (inst push call-target) ; push twice to preserve alignment - (inst push call-target) - (inst mov call-target (make-fixup "debug_print" :foreign)) - (inst call call-target) + (inst push rsp-save) ; push twice to preserve alignment + (inst push rsp-save) + #+immobile-space (inst call (make-fixup "debug_print" :foreign)) + #-immobile-space (inst call (ea (make-fixup "debug_print" :foreign 8))) (inst pop rsp-tn) ; restore the original RSP (move result rax))) diff --git a/src/compiler/x86-64/simd-pack-256.lisp b/src/compiler/x86-64/simd-pack-256.lisp index 26e56a3f93..b9233c6c66 100644 --- a/src/compiler/x86-64/simd-pack-256.lisp +++ b/src/compiler/x86-64/simd-pack-256.lisp @@ -11,6 +11,9 @@ (in-package "SB-VM") +(defun ea-for-avx-stack (tn &optional (base rbp-tn)) + (ea (frame-byte-offset (+ (tn-offset tn) 3)) base)) + (defun float-avx2-p (tn) (sc-is tn single-avx2-reg single-avx2-stack single-avx2-immediate double-avx2-reg double-avx2-stack double-avx2-immediate)) @@ -32,10 +35,10 @@ (p2 (%simd-pack-256-2 x)) (p3 (%simd-pack-256-3 x))) (cond ((= p0 p1 p2 p3 0) - (inst pxor y y)) + (inst vpxor y y y)) ((= p0 p1 p2 p3 (ldb (byte 64 0) -1)) ;; don't think this is recognized as dependency breaking... - (inst vpcmpeqd y y)) + (inst vpcmpeqd y y y)) (t (inst vmovdqu y (register-inline-constant x)))))) @@ -56,19 +59,19 @@ (define-move-fun (load-int-avx2 2) (vop x y) ((int-avx2-stack) (int-avx2-reg)) - (inst vmovdqu y (ea-for-sse-stack x))) + (inst vmovdqu y (ea-for-avx-stack x))) (define-move-fun (load-float-avx2 2) (vop x y) ((single-avx2-stack double-avx2-stack) (single-avx2-reg double-avx2-reg)) - (inst vmovups y (ea-for-sse-stack x))) + (inst vmovups y (ea-for-avx-stack x))) (define-move-fun (store-int-avx2 2) (vop x y) ((int-avx2-reg) (int-avx2-stack)) - (inst vmovdqu (ea-for-sse-stack y) x)) + (inst vmovdqu (ea-for-avx-stack y) x)) (define-move-fun (store-float-avx2 2) (vop x y) ((double-avx2-reg single-avx2-reg) (double-avx2-stack single-avx2-stack)) - (inst vmovups (ea-for-sse-stack y) x)) + (inst vmovups (ea-for-avx-stack y) x)) (define-vop (avx2-move) (:args (x :scs (single-avx2-reg double-avx2-reg int-avx2-reg) @@ -83,28 +86,38 @@ (int-avx2-reg single-avx2-reg double-avx2-reg) (int-avx2-reg single-avx2-reg double-avx2-reg)) -(define-vop (move-from-avx2) - (:args (x :scs (single-avx2-reg double-avx2-reg int-avx2-reg))) - (:results (y :scs (descriptor-reg))) - (:node-var node) - (:note "AVX2 to pointer coercion") - (:generator 13 - (alloc-other y simd-pack-256-widetag simd-pack-256-size node) - ;; see *simd-pack-element-types* - (storew (fixnumize - (sc-case x - (single-avx2-reg 1) - (double-avx2-reg 2) - (int-avx2-reg 0) - (t 0))) - y simd-pack-256-tag-slot other-pointer-lowtag) - (let ((ea (object-slot-ea - y simd-pack-256-p0-slot other-pointer-lowtag))) - (if (float-avx2-p x) - (inst vmovups ea x) - (inst vmovdqu ea x))))) -(define-move-vop move-from-avx2 :move - (int-avx2-reg single-avx2-reg double-avx2-reg) (descriptor-reg)) +(macrolet ((define-move-from-avx2 (type tag &rest scs) + (let ((name (symbolicate "MOVE-FROM-AVX2/" type))) + `(progn + (define-vop (,name) + (:args (x :scs ,scs)) + (:results (y :scs (descriptor-reg))) + #+gs-seg (:temporary (:sc unsigned-reg :offset 15) thread-tn) + (:node-var node) + (:arg-types ,type) + (:note "AVX2 to pointer coercion") + (:generator 13 + (alloc-other simd-pack-256-widetag simd-pack-256-size y node nil thread-tn) + (storew (fixnumize ,tag) + y simd-pack-256-tag-slot other-pointer-lowtag) + (let ((ea (object-slot-ea + y simd-pack-256-p0-slot other-pointer-lowtag))) + (if (float-avx2-p x) + (inst vmovups ea x) + (inst vmovdqu ea x))))) + (define-move-vop ,name :move + ,scs (descriptor-reg)))))) + ;; see *simd-pack-element-types* + (define-move-from-avx2 simd-pack-256-single 0 single-avx2-reg) + (define-move-from-avx2 simd-pack-256-double 1 double-avx2-reg) + (define-move-from-avx2 simd-pack-256-ub8 2 int-avx2-reg) + (define-move-from-avx2 simd-pack-256-ub16 3 int-avx2-reg) + (define-move-from-avx2 simd-pack-256-ub32 4 int-avx2-reg) + (define-move-from-avx2 simd-pack-256-ub64 5 int-avx2-reg) + (define-move-from-avx2 simd-pack-256-sb8 6 int-avx2-reg) + (define-move-from-avx2 simd-pack-256-sb16 7 int-avx2-reg) + (define-move-from-avx2 simd-pack-256-sb32 8 int-avx2-reg) + (define-move-from-avx2 simd-pack-256-sb64 9 int-avx2-reg)) (define-vop (move-to-avx2) (:args (x :scs (descriptor-reg))) @@ -136,8 +149,8 @@ (inst vmovdqu y x)))) ((int-avx2-stack double-avx2-stack single-avx2-stack) (if (float-avx2-p x) - (inst vmovups (ea-for-sse-stack y fp) x) - (inst vmovdqu (ea-for-sse-stack y fp) x)))))) + (inst vmovups (ea-for-avx-stack y fp) x) + (inst vmovdqu (ea-for-avx-stack y fp) x)))))) (define-move-vop move-avx2-arg :move-arg (int-avx2-reg double-avx2-reg single-avx2-reg descriptor-reg) (int-avx2-reg double-avx2-reg single-avx2-reg)) @@ -149,47 +162,28 @@ (define-vop (%simd-pack-256-0) (:translate %simd-pack-256-0) - (:args (x :scs (int-avx2-reg double-avx2-reg single-avx2-reg))) + (:args (x :scs (descriptor-reg))) (:arg-types simd-pack-256) (:results (dst :scs (unsigned-reg))) (:result-types unsigned-num) (:policy :fast-safe) (:generator 3 - (inst vmovq dst x))) + (loadw dst x simd-pack-256-p0-slot other-pointer-lowtag))) -(define-vop (%simd-pack-256-1) +(define-vop (%simd-pack-256-1 %simd-pack-256-0) (:translate %simd-pack-256-1) - (:args (x :scs (int-avx2-reg double-avx2-reg single-avx2-reg))) - (:arg-types simd-pack-256) - (:results (dst :scs (unsigned-reg))) - (:result-types unsigned-num) - (:policy :fast-safe) (:generator 3 - (inst vpextrq dst x 1))) + (loadw dst x simd-pack-256-p1-slot other-pointer-lowtag))) -(define-vop (%simd-pack-256-2) +(define-vop (%simd-pack-256-2 %simd-pack-256-0) (:translate %simd-pack-256-2) - (:args (x :scs (int-avx2-reg double-avx2-reg single-avx2-reg))) - (:arg-types simd-pack-256) - (:temporary (:sc avx2-reg :from (:argument 1)) tmp) - (:results (dst :scs (unsigned-reg))) - (:result-types unsigned-num) - (:policy :fast-safe) (:generator 3 - (inst vextracti128 tmp x 1) - (inst vmovq dst tmp))) + (loadw dst x simd-pack-256-p2-slot other-pointer-lowtag))) -(define-vop (%simd-pack-256-3) +(define-vop (%simd-pack-256-3 %simd-pack-256-0) (:translate %simd-pack-256-3) - (:args (x :scs (int-avx2-reg double-avx2-reg single-avx2-reg))) - (:arg-types simd-pack-256) - (:temporary (:sc avx2-reg :from (:argument 1)) tmp) - (:results (dst :scs (unsigned-reg))) - (:result-types unsigned-num) - (:policy :fast-safe) (:generator 3 - (inst vextracti128 tmp x 1) - (inst vpextrq dst tmp 1))) + (loadw dst x simd-pack-256-p3-slot other-pointer-lowtag))) (define-vop (%make-simd-pack-256) (:translate %make-simd-pack-256) @@ -202,9 +196,10 @@ (:arg-types tagged-num unsigned-num unsigned-num unsigned-num unsigned-num) (:results (dst :scs (descriptor-reg) :from :load)) (:result-types t) + #+gs-seg (:temporary (:sc unsigned-reg :offset 15) thread-tn) (:node-var node) (:generator 13 - (alloc-other dst simd-pack-256-widetag simd-pack-256-size node) + (alloc-other simd-pack-256-widetag simd-pack-256-size dst node nil thread-tn) ;; see *simd-pack-element-types* (storew tag dst simd-pack-256-tag-slot other-pointer-lowtag) (storew p0 dst simd-pack-256-p0-slot other-pointer-lowtag) @@ -222,7 +217,7 @@ (:arg-types unsigned-num unsigned-num unsigned-num unsigned-num) (:temporary (:sc int-avx2-reg) tmp) (:results (dst :scs (int-avx2-reg))) - (:result-types simd-pack-256-int) + (:result-types simd-pack-256-ub64) (:generator 5 (inst vmovq dst p0) (inst vpinsrq dst dst p1 1) @@ -230,34 +225,103 @@ (inst vpinsrq tmp tmp p3 1) (inst vinserti128 dst dst tmp 1))) +(defmacro simd-pack-256-dispatch (pack &body body) + (check-type pack symbol) + `(let ((,pack ,pack)) + (etypecase ,pack + ,@(mapcar (lambda (eltype) + `((simd-pack-256 ,eltype) ,@body)) + *simd-pack-element-types*)))) + #-sb-xc-host -(progn - (declaim (inline %make-simd-pack-256-ub32)) - (defun %make-simd-pack-256-ub32 (p0 p1 p2 p3 p4 p5 p6 p7) - (declare (type (unsigned-byte 32) p0 p1 p2 p3 p4 p5 p6 p7)) - (%make-simd-pack-256-ub64 (logior p0 (ash p1 32)) - (logior p2 (ash p3 32)) - (logior p4 (ash p5 32)) - (logior p6 (ash p7 32)))) +(macrolet ((unpack-unsigned (pack bits) + `(simd-pack-256-dispatch ,pack + (let ((a (%simd-pack-256-0 ,pack)) + (b (%simd-pack-256-1 ,pack)) + (c (%simd-pack-256-2 ,pack)) + (d (%simd-pack-256-3 ,pack))) + (values + ,@(loop for pos by bits below 64 collect + `(unpack-unsigned-1 ,bits ,pos a)) + ,@(loop for pos by bits below 64 collect + `(unpack-unsigned-1 ,bits ,pos b)) + ,@(loop for pos by bits below 64 collect + `(unpack-unsigned-1 ,bits ,pos c)) + ,@(loop for pos by bits below 64 collect + `(unpack-unsigned-1 ,bits ,pos d)))))) + (unpack-unsigned-1 (bits position ub64) + `(ldb (byte ,bits ,position) ,ub64))) + (declaim (inline %simd-pack-256-ub8s)) + (defun %simd-pack-256-ub8s (pack) + (declare (type simd-pack-256 pack)) + (unpack-unsigned pack 8)) + + (declaim (inline %simd-pack-256-ub16s)) + (defun %simd-pack-256-ub16s (pack) + (declare (type simd-pack-256 pack)) + (unpack-unsigned pack 16)) - (declaim (inline %simd-pack-256-ub32s %simd-pack-256-ub64s)) + (declaim (inline %simd-pack-256-ub32s)) (defun %simd-pack-256-ub32s (pack) (declare (type simd-pack-256 pack)) - (let ((p0 (%simd-pack-256-0 pack)) - (p1 (%simd-pack-256-1 pack)) - (p2 (%simd-pack-256-2 pack)) - (p3 (%simd-pack-256-3 pack))) - (values (ldb (byte 32 0) p0) (ash p0 -32) - (ldb (byte 32 0) p1) (ash p1 -32) - (ldb (byte 32 0) p2) (ash p2 -32) - (ldb (byte 32 0) p3) (ash p3 -32)))) + (unpack-unsigned pack 32)) + (declaim (inline %simd-pack-256-ub64s)) (defun %simd-pack-256-ub64s (pack) (declare (type simd-pack-256 pack)) - (values (%simd-pack-256-0 pack) - (%simd-pack-256-1 pack) - (%simd-pack-256-2 pack) - (%simd-pack-256-3 pack)))) + (unpack-unsigned pack 64))) + +#-sb-xc-host +(macrolet ((unpack-signed (pack bits) + `(simd-pack-256-dispatch ,pack + (let ((a (%simd-pack-256-0 ,pack)) + (b (%simd-pack-256-1 ,pack)) + (c (%simd-pack-256-2 ,pack)) + (d (%simd-pack-256-3 ,pack))) + (values + ,@(loop for pos by bits below 64 collect + `(unpack-signed-1 ,bits ,pos a)) + ,@(loop for pos by bits below 64 collect + `(unpack-signed-1 ,bits ,pos b)) + ,@(loop for pos by bits below 64 collect + `(unpack-signed-1 ,bits ,pos c)) + ,@(loop for pos by bits below 64 collect + `(unpack-signed-1 ,bits ,pos d)))))) + (unpack-signed-1 (bits position ub64) + `(- (mod (+ (ldb (byte ,bits ,position) ,ub64) + ,(expt 2 (1- bits))) + ,(expt 2 bits)) + ,(expt 2 (1- bits))))) + (declaim (inline %simd-pack-256-sb8s)) + (defun %simd-pack-256-sb8s (pack) + (declare (type simd-pack-256 pack)) + (unpack-signed pack 8)) + + (declaim (inline %simd-pack-256-sb16s)) + (defun %simd-pack-256-sb16s (pack) + (declare (type simd-pack-256 pack)) + (unpack-signed pack 16)) + + (declaim (inline %simd-pack-256-sb32s)) + (defun %simd-pack-256-sb32s (pack) + (declare (type simd-pack-256 pack)) + (unpack-signed pack 32)) + + (declaim (inline %simd-pack-256-sb64s)) + (defun %simd-pack-256-sb64s (pack) + (declare (type simd-pack-256 pack)) + (unpack-signed pack 64))) + +#-sb-xc-host +(progn + (defun %make-simd-pack-256-ub32 (p0 p1 p2 p3 p4 p5 p6 p7) + (declare (type (unsigned-byte 32) p0 p1 p2 p3 p4 p5 p6 p7)) + (%make-simd-pack-256 + #.(position '(unsigned-byte 32) *simd-pack-element-types* :test #'equal) + (logior p0 (ash p1 32)) + (logior p2 (ash p3 32)) + (logior p4 (ash p5 32)) + (logior p6 (ash p7 32))))) (define-vop (%make-simd-pack-256-double) (:translate %make-simd-pack-256-double) @@ -329,14 +393,15 @@ (declaim (inline %simd-pack-256-singles)) (defun %simd-pack-256-singles (pack) (declare (type simd-pack-256 pack)) - (values (%simd-pack-256-single-item pack 0) - (%simd-pack-256-single-item pack 1) - (%simd-pack-256-single-item pack 2) - (%simd-pack-256-single-item pack 3) - (%simd-pack-256-single-item pack 4) - (%simd-pack-256-single-item pack 5) - (%simd-pack-256-single-item pack 6) - (%simd-pack-256-single-item pack 7)))) + (simd-pack-256-dispatch pack + (values (%simd-pack-256-single-item pack 0) + (%simd-pack-256-single-item pack 1) + (%simd-pack-256-single-item pack 2) + (%simd-pack-256-single-item pack 3) + (%simd-pack-256-single-item pack 4) + (%simd-pack-256-single-item pack 5) + (%simd-pack-256-single-item pack 6) + (%simd-pack-256-single-item pack 7))))) (defknown %simd-pack-256-double-item (simd-pack-256 (integer 0 3)) double-float (flushable)) @@ -367,10 +432,11 @@ (declaim (inline %simd-pack-256-doubles)) (defun %simd-pack-256-doubles (pack) (declare (type simd-pack-256 pack)) - (values (%simd-pack-256-double-item pack 0) - (%simd-pack-256-double-item pack 1) - (%simd-pack-256-double-item pack 2) - (%simd-pack-256-double-item pack 3))) + (simd-pack-256-dispatch pack + (values (%simd-pack-256-double-item pack 0) + (%simd-pack-256-double-item pack 1) + (%simd-pack-256-double-item pack 2) + (%simd-pack-256-double-item pack 3)))) (defun %simd-pack-256-inline-constant (pack) (list :avx2 (logior (%simd-pack-256-0 pack) diff --git a/src/compiler/x86-64/simd-pack.lisp b/src/compiler/x86-64/simd-pack.lisp index c1dc353a24..2046d524ed 100644 --- a/src/compiler/x86-64/simd-pack.lisp +++ b/src/compiler/x86-64/simd-pack.lisp @@ -80,27 +80,37 @@ (int-sse-reg single-sse-reg double-sse-reg) (int-sse-reg single-sse-reg double-sse-reg)) -(define-vop (move-from-sse) - (:args (x :scs (single-sse-reg double-sse-reg int-sse-reg))) - (:results (y :scs (descriptor-reg))) - (:node-var node) - (:note "SSE to pointer coercion") - (:generator 13 - (alloc-other y simd-pack-widetag simd-pack-size node) - ;; see *simd-pack-element-types* - (storew (fixnumize - (sc-case x - (single-sse-reg 1) - (double-sse-reg 2) - (int-sse-reg 0) - (t 0))) - y simd-pack-tag-slot other-pointer-lowtag) - (let ((ea (object-slot-ea y simd-pack-lo-value-slot other-pointer-lowtag))) - (if (float-sse-p x) - (inst movaps ea x) - (inst movdqa ea x))))) -(define-move-vop move-from-sse :move - (int-sse-reg single-sse-reg double-sse-reg) (descriptor-reg)) +(macrolet ((define-move-from-sse (type tag &rest scs) + (let ((name (symbolicate "MOVE-FROM-SSE/" type))) + `(progn + (define-vop (,name) + (:args (x :scs ,scs)) + (:results (y :scs (descriptor-reg))) + #+gs-seg (:temporary (:sc unsigned-reg :offset 15) thread-tn) + (:node-var node) + (:arg-types ,type) + (:note "AVX2 to pointer coercion") + (:generator 13 + (alloc-other simd-pack-widetag simd-pack-size y node nil thread-tn) + (storew (fixnumize ,tag) + y simd-pack-tag-slot other-pointer-lowtag) + (let ((ea (object-slot-ea y simd-pack-lo-value-slot other-pointer-lowtag))) + (if (float-sse-p x) + (inst movaps ea x) + (inst movdqa ea x))))) + (define-move-vop ,name :move + ,scs (descriptor-reg)))))) + ;; see *simd-pack-element-types* + (define-move-from-sse simd-pack-single 0 single-sse-reg) + (define-move-from-sse simd-pack-double 1 double-sse-reg) + (define-move-from-sse simd-pack-ub8 2 int-sse-reg) + (define-move-from-sse simd-pack-ub16 3 int-sse-reg) + (define-move-from-sse simd-pack-ub32 4 int-sse-reg) + (define-move-from-sse simd-pack-ub64 5 int-sse-reg) + (define-move-from-sse simd-pack-sb8 6 int-sse-reg) + (define-move-from-sse simd-pack-sb16 7 int-sse-reg) + (define-move-from-sse simd-pack-sb32 8 int-sse-reg) + (define-move-from-sse simd-pack-sb64 9 int-sse-reg)) (define-vop (move-to-sse) (:args (x :scs (descriptor-reg))) @@ -185,9 +195,10 @@ (:arg-types tagged-num unsigned-num unsigned-num) (:results (dst :scs (descriptor-reg) :from :load)) (:result-types t) + #+gs-seg (:temporary (:sc unsigned-reg :offset 15) thread-tn) (:node-var node) (:generator 13 - (alloc-other dst simd-pack-widetag simd-pack-size node) + (alloc-other simd-pack-widetag simd-pack-size dst node nil thread-tn) ;; see *simd-pack-element-types* (storew tag dst simd-pack-tag-slot other-pointer-lowtag) (storew lo dst simd-pack-lo-value-slot other-pointer-lowtag) @@ -201,34 +212,96 @@ (:arg-types unsigned-num unsigned-num) (:temporary (:sc int-sse-reg) tmp) (:results (dst :scs (int-sse-reg))) - (:result-types simd-pack-int) + (:result-types simd-pack-ub64) (:generator 5 (inst movq dst lo) (inst movq tmp hi) (inst punpcklqdq dst tmp))) +(defmacro simd-pack-dispatch (pack &body body) + (check-type pack symbol) + `(let ((,pack ,pack)) + (etypecase ,pack + ,@(mapcar (lambda (eltype) + `((simd-pack ,eltype) ,@body)) + *simd-pack-element-types*)))) + #-sb-xc-host -(progn - (declaim (inline %make-simd-pack-ub32)) - (defun %make-simd-pack-ub32 (w x y z) - (declare (type (unsigned-byte 32) w x y z)) - (%make-simd-pack-ub64 (logior w (ash x 32)) - (logior y (ash z 32)))) +(macrolet ((unpack-unsigned (pack bits) + `(simd-pack-dispatch ,pack + (let ((lo (%simd-pack-low ,pack)) + (hi (%simd-pack-high ,pack))) + (values + ,@(loop for pos by bits below 64 collect + `(unpack-unsigned-1 ,bits ,pos lo)) + ,@(loop for pos by bits below 64 collect + `(unpack-unsigned-1 ,bits ,pos hi)))))) + (unpack-unsigned-1 (bits position ub64) + `(ldb (byte ,bits ,position) ,ub64))) + (declaim (inline %simd-pack-ub8s)) + (defun %simd-pack-ub8s (pack) + (declare (type simd-pack pack)) + (unpack-unsigned pack 8)) + + (declaim (inline %simd-pack-ub16s)) + (defun %simd-pack-ub16s (pack) + (declare (type simd-pack pack)) + (unpack-unsigned pack 16)) - (declaim (inline %simd-pack-ub32s %simd-pack-ub64s)) + (declaim (inline %simd-pack-ub32s)) (defun %simd-pack-ub32s (pack) (declare (type simd-pack pack)) - (let ((lo (%simd-pack-low pack)) - (hi (%simd-pack-high pack))) - (values (ldb (byte 32 0) lo) - (ash lo -32) - (ldb (byte 32 0) hi) - (ash hi -32)))) + (unpack-unsigned pack 32)) + (declaim (inline %simd-pack-ub64s)) (defun %simd-pack-ub64s (pack) (declare (type simd-pack pack)) - (values (%simd-pack-low pack) - (%simd-pack-high pack)))) + (unpack-unsigned pack 64))) + +#-sb-xc-host +(macrolet ((unpack-signed (pack bits) + `(simd-pack-dispatch ,pack + (let ((lo (%simd-pack-low ,pack)) + (hi (%simd-pack-high ,pack))) + (values + ,@(loop for pos by bits below 64 collect + `(unpack-signed-1 ,bits ,pos lo)) + ,@(loop for pos by bits below 64 collect + `(unpack-signed-1 ,bits ,pos hi)))))) + (unpack-signed-1 (bits position ub64) + `(- (mod (+ (ldb (byte ,bits ,position) ,ub64) + ,(expt 2 (1- bits))) + ,(expt 2 bits)) + ,(expt 2 (1- bits))))) + (declaim (inline %simd-pack-sb8s)) + (defun %simd-pack-sb8s (pack) + (declare (type simd-pack pack)) + (unpack-signed pack 8)) + + (declaim (inline %simd-pack-sb16s)) + (defun %simd-pack-sb16s (pack) + (declare (type simd-pack pack)) + (unpack-signed pack 16)) + + (declaim (inline %simd-pack-sb32s)) + (defun %simd-pack-sb32s (pack) + (declare (type simd-pack pack)) + (unpack-signed pack 32)) + + (declaim (inline %simd-pack-sb64s)) + (defun %simd-pack-sb64s (pack) + (declare (type simd-pack pack)) + (unpack-signed pack 64))) + +#-sb-xc-host +(progn + (declaim (inline %make-simd-pack-ub32)) + (defun %make-simd-pack-ub32 (w x y z) + (declare (type (unsigned-byte 32) w x y z)) + (%make-simd-pack + #.(position '(unsigned-byte 32) *simd-pack-element-types* :test #'equal) + (logior w (ash x 32)) + (logior y (ash z 32))))) (define-vop (%make-simd-pack-double) (:translate %make-simd-pack-double) @@ -292,10 +365,11 @@ (declaim (inline %simd-pack-singles)) (defun %simd-pack-singles (pack) (declare (type simd-pack pack)) - (values (%simd-pack-single-item pack 0) - (%simd-pack-single-item pack 1) - (%simd-pack-single-item pack 2) - (%simd-pack-single-item pack 3)))) + (simd-pack-dispatch pack + (values (%simd-pack-single-item pack 0) + (%simd-pack-single-item pack 1) + (%simd-pack-single-item pack 2) + (%simd-pack-single-item pack 3))))) (defknown %simd-pack-double-item (simd-pack (integer 0 1)) double-float (flushable)) @@ -327,5 +401,6 @@ (declaim (inline %simd-pack-doubles)) (defun %simd-pack-doubles (pack) (declare (type simd-pack pack)) - (values (%simd-pack-double-item pack 0) - (%simd-pack-double-item pack 1)))) + (simd-pack-dispatch pack + (values (%simd-pack-double-item pack 0) + (%simd-pack-double-item pack 1))))) diff --git a/src/compiler/x86-64/system.lisp b/src/compiler/x86-64/system.lisp index 0fb6eea622..da7aea8249 100644 --- a/src/compiler/x86-64/system.lisp +++ b/src/compiler/x86-64/system.lisp @@ -46,35 +46,13 @@ (inst movzx '(:byte :dword) result object) DONE)) -(macrolet ((read-depthoid () - `(ea (- (+ 4 (ash (+ instance-slots-offset - (get-dsd-index layout sb-kernel::flags)) - word-shift)) - instance-pointer-lowtag) - layout))) - (define-vop (layout-depthoid) - (:translate layout-depthoid) - (:policy :fast-safe) - (:args (layout :scs (descriptor-reg))) - (:results (res :scs (any-reg))) - (:result-types fixnum) - (:generator 1 (inst movsx '(:dword :qword) res (read-depthoid)))) - (define-vop (sb-c::layout-depthoid-gt) - (:translate sb-c::layout-depthoid-gt) - (:policy :fast-safe) - (:args (layout :scs (descriptor-reg))) - (:info k) - (:arg-types * (:constant (unsigned-byte 16))) - (:conditional :g) - (:generator 1 (inst cmp :dword (read-depthoid) (fixnumize k))))) - #+compact-instance-header -;; ~20 instructions vs. 35 -(define-vop (layout-of) ; no translation +(progn +;; ~17 instructions vs. 35 +(define-vop () (:policy :fast-safe) - (:translate layout-of) - (:args (object :scs (descriptor-reg)) - #+nil (layouts :scs (constant))) + (:translate wrapper-of) + (:args (object :scs (descriptor-reg))) (:temporary (:sc unsigned-reg :offset rax-offset) rax) (:results (result :scs (descriptor-reg))) (:generator 6 @@ -102,23 +80,30 @@ (inst jmp :eq NULL) (inst movzx '(:byte :dword) rax object) LOAD-FROM-VECTOR - #+nil ;; old way - (progn - (inst mov result layouts) - (inst mov :dword result - (ea (+ (ash vector-data-offset word-shift) (- other-pointer-lowtag)) - result rax 8))) - ;; new way (inst mov :dword result - (ea (make-fixup '**primitive-object-layouts** - :symbol-value + (ea (make-fixup '**primitive-object-layouts** :symbol-value (- (ash vector-data-offset word-shift) other-pointer-lowtag)) nil rax 8)) ; no base register (inst jmp done) NULL (inst mov result (make-fixup 'null :layout)) - DONE)) + DONE + #+metaspace (inst mov result (ea +5 result)))) ; layout->wrapper +(define-vop () + (:policy :fast-safe) + (:translate %instanceoid-layout) + (:args (object :scs (descriptor-reg) :to :save)) + (:temporary (:sc unsigned-reg) temp) + (:results (result :scs (descriptor-reg))) + (:generator 6 + (inst lea temp (ea -3 object)) + (inst and temp (lognot #b1000)) + (inst mov :dword result (make-fixup 't :layout)) + (inst test :byte temp 15) + (inst jmp :ne DONE) + (inst mov :dword result (ea 4 temp)) + DONE))) (macrolet ((load-type (target source lowtag) `(inst movzx '(:byte :dword) ,target (ea (- ,lowtag) ,source)))) @@ -129,8 +114,8 @@ (:results (result :scs (unsigned-reg))) (:result-types positive-fixnum) (:generator 1 (load-type result object other-pointer-lowtag))) -(define-vop (fun-subtype) - (:translate fun-subtype) +(define-vop () + (:translate %fun-pointer-widetag) (:policy :fast-safe) (:args (function :scs (descriptor-reg))) (:results (result :scs (unsigned-reg))) @@ -149,45 +134,72 @@ ;;; This operation is racy with GC and therefore slightly dangerous, especially ;;; on objects in immobile space which reserve byte 3 of the header for GC. -(define-vop (set-header-data) +(define-vop () (:translate set-header-data) (:policy :fast-safe) - (:args (x :scs (descriptor-reg) :target res :to (:result 0)) + (:args (x :scs (descriptor-reg) :to :eval) (data :scs (any-reg) :target temp)) (:arg-types * positive-fixnum) - (:results (res :scs (descriptor-reg))) - (:temporary (:sc unsigned-reg :from (:argument 1) :to (:result 0)) temp) + (:temporary (:sc unsigned-reg :from (:argument 1)) temp) (:generator 6 (move temp data) (inst shl temp (- n-widetag-bits n-fixnum-tag-bits)) ;; merge in the widetag. We should really preserve bit 63 as well ;; which could be a GC mark bit, but it's not concurrent at the moment. (inst mov :byte temp (ea (- other-pointer-lowtag) x)) - (storew temp x 0 other-pointer-lowtag) + (storew temp x 0 other-pointer-lowtag))) +(define-vop (logior-header-bits) + (:translate logior-header-bits) + (:policy :fast-safe) + (:args (x :scs (descriptor-reg)) + (bits :scs (unsigned-reg immediate))) + (:arg-types * positive-fixnum) + (:results (res :scs (descriptor-reg))) + (:generator 1 + (if (sc-is bits immediate) + (let ((bits (tn-value bits))) + (cond ((typep bits '(unsigned-byte 8)) + (inst or :byte (ea (- 1 other-pointer-lowtag) x) bits)) + ((not (logtest bits #xff)) + (inst or :byte (ea (- 2 other-pointer-lowtag) x) (ash bits -8))) + (t + (inst or :word (ea (- 1 other-pointer-lowtag) x) bits)))) + (inst or :word (ea (- 1 other-pointer-lowtag) x) bits)) (move res x))) - -;;; These next 2 vops are for manipulating the flag bits of a vector header. -(define-vop (set-header-bits) - (:translate set-header-bits) +(define-vop () + (:translate assign-vector-flags) (:policy :fast-safe) (:args (x :scs (descriptor-reg))) - (:arg-types t (:constant t)) (:info bits) + (:arg-types t (:constant (unsigned-byte 8))) (:generator 1 - (if (typep bits '(unsigned-byte 8)) - (inst or :byte (ea (- 1 other-pointer-lowtag) x) bits) - (inst or :dword (ea (- other-pointer-lowtag) x) (ash bits n-widetag-bits))))) -(define-vop (unset-header-bits) - (:translate unset-header-bits) + (inst mov :byte (ea (- (/ array-flags-position n-word-bytes) other-pointer-lowtag) x) + bits))) +(define-vop () + (:translate reset-header-bits) (:policy :fast-safe) (:args (x :scs (descriptor-reg))) - (:arg-types t (:constant t)) + (:arg-types t (:constant (unsigned-byte 16))) (:info bits) (:generator 1 - (if (typep bits '(unsigned-byte 8)) - (inst and :byte (ea (- 1 other-pointer-lowtag) x) (lognot bits)) - (inst and :dword (ea (- other-pointer-lowtag) x) - (lognot (ash bits n-widetag-bits)))))) + (let ((byte 1)) + (when (> bits #xff) + (setf bits (ash bits -8)) + (setf byte 2)) + (inst and :byte (ea (- byte other-pointer-lowtag) x) (logandc1 bits #xff))))) +(define-vop (test-header-data-bit) + (:translate test-header-data-bit) + (:policy :fast-safe) + (:args (array :scs (descriptor-reg))) + (:info mask) + (:arg-types t (:constant t)) + (:conditional :ne) + (:generator 1 + (let ((byte 1)) + (when (> mask #xff) + (setf mask (ash mask -8)) + (setf byte 2)) + (inst test :byte (ea (- byte other-pointer-lowtag) array) mask)))) (define-vop (pointer-hash) (:translate pointer-hash) @@ -276,39 +288,27 @@ result)))) ;;;; symbol frobbing -(defun load-symbol-info-vector (result symbol) +(defun load-symbol-dbinfo (result symbol) (loadw result symbol symbol-info-slot other-pointer-lowtag) ;; If RES has list-pointer-lowtag, take its CDR. If not, use it as-is. ;; This CMOV safely reads from memory when it does not move, because if - ;; there is an info-vector in the slot, it has at least one element. + ;; there is a PACKED-INFO in the slot, it has at least 4 data words in total + ;; - the header, at least one info descriptor, and at least one datum. + ;; And since 3 is odd, that would be aligned up to 4. + ;; Use bit index 2 of the lowtag to distinguish list from instance. + ;; An instance will have a 0 in that bit. ;; This would compile to almost the same code without a VOP, ;; but using a jmp around a mov instead. - (aver (= (logior list-pointer-lowtag #b1000) other-pointer-lowtag)) - (inst test :byte result #b1000) - (inst cmov :e result - (object-slot-ea result cons-cdr-slot list-pointer-lowtag))) + (aver (= (logior instance-pointer-lowtag #b0100) list-pointer-lowtag)) + (inst test :byte result #b0100) + (inst cmov :nz result (object-slot-ea result cons-cdr-slot list-pointer-lowtag))) -(define-vop (symbol-info-vector) +(define-vop (symbol-dbinfo) (:policy :fast-safe) - (:translate symbol-info-vector) + (:translate symbol-dbinfo) (:args (x :scs (descriptor-reg))) (:results (res :scs (descriptor-reg))) - (:generator 1 (load-symbol-info-vector res x))) - -(define-vop (symbol-plist) - (:policy :fast-safe) - (:translate symbol-plist) - (:args (x :scs (descriptor-reg))) - (:results (res :scs (descriptor-reg))) - (:temporary (:sc unsigned-reg) temp) - (:generator 1 - (loadw res x symbol-info-slot other-pointer-lowtag) - ;; Instruction pun: (CAR x) is the same as (VECTOR-LENGTH x) - ;; so if the info slot holds a vector, this gets a fixnum- it's not a plist. - (loadw res res cons-car-slot list-pointer-lowtag) - (inst mov temp nil-value) - (inst test :byte res fixnum-tag-mask) - (inst cmov :e res temp))) + (:generator 1 (load-symbol-dbinfo res x))) ;;;; other miscellaneous VOPs @@ -329,18 +329,20 @@ (:arg-types (:constant signed-byte)) (:policy :fast-safe) (:generator 1 - (inst mov sap (thread-slot-ea n)))) + #-gs-seg (inst mov sap (if (= n thread-this-slot) thread-tn (thread-slot-ea n))) + #+gs-seg (inst mov sap (thread-slot-ea n)))) (define-vop (current-thread-offset-sap) (:results (sap :scs (sap-reg))) (:result-types system-area-pointer) (:translate current-thread-offset-sap) - (:args (n :scs (any-reg) :target sap)) + (:args (index :scs (any-reg) :target sap)) (:arg-types tagged-num) (:policy :fast-safe) (:generator 2 - (inst mov sap - (ea thread-base-tn - n (ash 1 (- word-shift n-fixnum-tag-bits))))))) + (let (#+gs-seg (thread-tn nil)) + (inst mov sap + (ea thread-segment-reg thread-tn + index (ash 1 (- word-shift n-fixnum-tag-bits)))))))) (define-vop (halt) (:generator 1 @@ -382,10 +384,10 @@ (define-vop (%read-cycle-counter) (:policy :fast-safe) (:translate %read-cycle-counter) - (:temporary (:sc unsigned-reg :offset eax-offset :target lo) eax) - (:temporary (:sc unsigned-reg :offset edx-offset :target hi) edx) - (:temporary (:sc unsigned-reg :offset ebx-offset) ebx) - (:temporary (:sc unsigned-reg :offset ecx-offset) ecx) + (:temporary (:sc unsigned-reg :offset rax-offset :target lo) eax) + (:temporary (:sc unsigned-reg :offset rdx-offset :target hi) edx) + (:temporary (:sc unsigned-reg :offset rbx-offset) ebx) + (:temporary (:sc unsigned-reg :offset rcx-offset) ecx) (:ignore ebx ecx) (:results (hi :scs (unsigned-reg)) (lo :scs (unsigned-reg))) @@ -483,13 +485,13 @@ number of CPU cycles elapsed as secondary value. EXPERIMENTAL." (d :scs (unsigned-reg))) (:result-types unsigned-num unsigned-num unsigned-num unsigned-num) (:temporary (:sc unsigned-reg :from (:argument 0) :to (:result 0) - :offset eax-offset) eax) + :offset rax-offset) eax) (:temporary (:sc unsigned-reg :from (:argument 1) :to (:result 2) - :offset ecx-offset) ecx) + :offset rcx-offset) ecx) (:temporary (:sc unsigned-reg :from :eval :to (:result 3) - :offset edx-offset) edx) + :offset rdx-offset) edx) (:temporary (:sc unsigned-reg :from :eval :to (:result 1) - :offset ebx-offset) ebx) + :offset rbx-offset) ebx) (:generator 5 (move eax function) (move ecx subfunction) @@ -503,25 +505,16 @@ number of CPU cycles elapsed as secondary value. EXPERIMENTAL." (:args (fdefn :scs (descriptor-reg))) (:generator 1 ;; atomic because the immobile gen# is in the same byte - (inst or :byte (ea (- 1 other-pointer-lowtag) fdefn) #x80 :lock))) + (inst or :lock :byte (ea (- 1 other-pointer-lowtag) fdefn) #x80))) (define-vop (unset-fdefn-has-static-callers) (:args (fdefn :scs (descriptor-reg))) (:generator 1 ;; atomic because the immobile gen# is in the same byte - (inst and :byte (ea (- 1 other-pointer-lowtag) fdefn) #x7f :lock))) - -(define-vop () - (:translate update-object-layout-or-invalid) - (:args (obj :scs (descriptor-reg))) - (:info layout) - (:arg-types * (:constant t)) - (:results (res :scs (descriptor-reg))) - (:policy :fast-safe) - (:vop-var vop) - (:generator 1 - (inst push (if (immediate-constant-sc layout) - (make-fixup layout :layout) - (make-constant-tn (sb-c::find-constant layout)))) - (inst push obj) - (invoke-asm-routine 'call 'invalid-layout-trap vop) - (inst pop res))) + (inst and :lock :byte (ea (- 1 other-pointer-lowtag) fdefn) #x7f))) + +(define-vop (sb-c::mark-covered) + (:info index) + (:generator 1 + ;; Can't convert index to a code-relative index until the boxed header length + ;; has been determined. + (inst store-coverage-mark index))) diff --git a/src/compiler/x86-64/target-avx2-insts.lisp b/src/compiler/x86-64/target-avx2-insts.lisp index 4e57d45242..43e65b95d9 100644 --- a/src/compiler/x86-64/target-avx2-insts.lisp +++ b/src/compiler/x86-64/target-avx2-insts.lisp @@ -15,9 +15,7 @@ (let* ((offset (etypecase value ((unsigned-byte 4) value) (reg (reg-num value)))) - (reg (if (dstate-getprop dstate +vex-l+) - (get-avx2 offset) - (get-fpr offset))) + (reg (get-fpr (if (dstate-getprop dstate +vex-l+) :ymm :xmm) offset)) (name (reg-name reg))) (if stream (write-string name stream) diff --git a/src/compiler/x86-64/target-insts.lisp b/src/compiler/x86-64/target-insts.lisp index e4fc6666d6..662c850473 100644 --- a/src/compiler/x86-64/target-insts.lisp +++ b/src/compiler/x86-64/target-insts.lisp @@ -15,6 +15,31 @@ (in-package "SB-X86-64-ASM") +(defun sb-disassem::pre-decode (chunk dstate) + (let ((byte (ldb (byte 8 0) chunk))) + (case byte + ((#x64 ; FS: + #x65 ; GS: + #x66 ; operand size modifier + #x67 ; address size modifier + #xf0 ; LOCK + #xf2 ; REPNE or SSE inst + #xf3) ; REP or SSE inst + ;; If the next byte is a REX prefix, then strip it out, recording the 'wrxb' + ;; bits in the dstate, and return the chunk as if the REX byte were absent. + (let ((next (ldb (byte 8 8) chunk))) + (when (= (logand next #xf0) #x40) + (dstate-setprop dstate (logior +rex+ (logand next #b1111))) + (let ((new (logior byte (ash (ldb (byte 48 16) chunk) 8)))) + (return-from sb-disassem::pre-decode (values new 1)))))))) + (values chunk 0)) + +(defmethod print-object ((reg reg) stream) + (if *print-readably* + ;; cross-compiled DEFMETHOD can't use call-next-method + (default-structure-print reg stream *current-level-in-print*) + (write-string (reg-name reg) stream))) + ;;; Return the operand size depending on the prefixes and width bit as ;;; stored in DSTATE. (defun inst-operand-size (dstate) @@ -58,6 +83,9 @@ (defun reg-imm-data (dchunk dstate) dchunk (aref (sb-disassem::dstate-filtered-values dstate) 4)) +;;; This structure is logically immutable, except for one problem: +;;; the disassembler recycles instances of it (re-uses the same +;;; one for each successive instruction). See DECODE-MOD-R/M. (defstruct (machine-ea (:copier nil) (:constructor %make-machine-ea)) ;; possible TODO: base,index,scale could be packed thusly in 13 bits: @@ -149,7 +177,18 @@ value (inst-operand-size-default-qword dstate) t stream dstate)) (defun print-jmp-ea (value stream dstate) - (print-sized-reg/mem-default-qword value stream dstate)) + (cond ((typep value 'machine-ea) + (print-mem-ref :ref value :qword stream dstate) + #+immobile-space + (when (and (null (machine-ea-base value)) + (null (machine-ea-index value)) + (let* ((v sb-fasl::*asm-routine-vector*) + (a (logandc2 (get-lisp-obj-address v) sb-vm:lowtag-mask))) + (<= a (machine-ea-disp value) (1- (+ a (primitive-object-size v)))))) + (let ((target (sap-ref-word (int-sap (machine-ea-disp value)) 0))) + (maybe-note-assembler-routine target t dstate)))) + ((null stream) (operand value dstate)) + (t (write value :stream stream)))) (defun print-sized-byte-reg/mem (value stream dstate) (print-reg/mem-with-width value :byte t stream dstate)) @@ -165,7 +204,7 @@ (princ16 value stream)) (defun print-xmmreg (value stream dstate) - (let* ((reg (get-fpr + (let* ((reg (get-fpr :xmm ;; FIXME: why are we seeing a value from the GPR ;; prefilter instead of XMM prefilter here sometimes? (etypecase value @@ -181,25 +220,74 @@ (print-mem-ref :ref value nil stream dstate) (print-xmmreg value stream dstate))) -;;; Find the Lisp object, if any, called by a "CALL rel32offs" -;;; instruction format and add it as an end-of-line comment. -;;; Alternatively, the value might be an immediate operand to MOV, -;;; which in general decodes as a signed integer. So ignore it -;;; unless it looks like an address. -#+immobile-space -(defun maybe-note-lisp-callee (value dstate) +;;; Guess whether VALUE is an immobile-space symbol or code blob by looking +;;; at all code header constants. If it matches any constant, assume that it +;;; is a use of the constant. This has false positives of course, +;;; as does MAYBE-NOTE-STATIC-SYMBOL and friends. Any random immediate value +;;; used in an unboxed context, such as an ADD instruction, +;;; can be wrongly construed as an address. +;;; Note that for symbols we can match either the tagged pointer to it +;;; OR the untagged address of the SYMBOL-VALUE slot. +;;; +;;; "static" in this usage implies "at a fixed address" - it could be +;;; in static space or immobile space. +;;; +;;; TODO: probably should take an &OPTIONAL for ALLOW-INTERIOR-PTR to +;;; reject false positives from instructions that don't access an object +;;; except through a tagged pointer. +(defun maybe-note-static-lispobj (value dstate &optional quote) + (when (maybe-note-static-symbol value dstate) + ;; Returning T prints VALUE using base 16 + ;; (see the SIGNED-IMM-DATA printer, PRINT-IMM/ASM-ROUTINE) + ;; This should probably pass through the QUOTE option but it's not critical. + (return-from maybe-note-static-lispobj t)) + (let ((code (seg-code (dstate-segment dstate))) + (adjusted-val (logior (- value (ash sb-vm:symbol-value-slot sb-vm:word-shift)) + sb-vm:other-pointer-lowtag)) + (found-const) + (slot)) + (when code + (loop for i downfrom (1- (code-header-words code)) to sb-vm:code-constants-offset + for const = (code-header-ref code i) + do (when (symbolp const) + (let ((addr (get-lisp-obj-address const))) + (cond ((eql addr value) + (return (setq found-const const))) + ((eql addr adjusted-val) + (return (setq found-const const + slot sb-vm:symbol-value-slot))))))) + (unless found-const ; try static symbol's value slots + (dovector (symbol sb-vm:+static-symbols+) + (when (= (get-lisp-obj-address symbol) adjusted-val) + (return (setq found-const symbol + slot sb-vm:symbol-value-slot))))) + (when found-const + (note (cond (slot + (lambda (s) (format s "(SYMBOL-VALUE '~S)" found-const))) + ((and (symbolp found-const) quote) + (lambda (s) (write-char #\' s) (prin1 found-const s))) + (t + (lambda (s) (prin1 found-const s)))) + dstate) + ;; Returning T prints in base 16 (see PRINT-IMM/ASM-ROUTINE) + (return-from maybe-note-static-lispobj t)))) + #| This mysterious code seems to have no regression tests. + Comenting it out until I can figure out why it was in target-disassem + ;; Kludge: layout of STREAM, FILE-STREAM, and STRING-STREAM can be used + ;; as immediate operands without a corresponding boxed header constant. + ;; I think we always elide the boxed constant for builtin layouts, + ;; but these three have some slightly unusual codegen that causes a PUSH + ;; instruction to need some help to show its operand as a lisp object. + (dolist (thing (load-time-value (list (find-layout 'stream) + (find-layout 'file-stream) + (find-layout 'string-stream)) + t)) + (when (eql (get-lisp-obj-address thing) address) + (return-from found thing))))) |# (awhen (and (typep value 'word) (sb-disassem::find-code-constant-from-interior-pointer value dstate)) (note (lambda (stream) (princ it stream)) dstate))) -(defun print-imm/asm-routine (value stream dstate) - (cond ((not stream) (operand value dstate)) - ((or #+immobile-space (maybe-note-lisp-callee value dstate) - (maybe-note-assembler-routine value nil dstate) - (maybe-note-static-symbol value dstate)) - (princ16 value stream)) - (t (princ value stream)))) - ;;; Return an instance of REG or MACHINE-EA. ;;; MOD and R/M are the extracted bits from the instruction's ModRM byte. ;;; Depending on MOD and R/M, a SIB byte and/or displacement may be read. @@ -227,7 +315,7 @@ (cond ((= mod #b11) ; register direct mode (case regclass (gpr (get-gpr :qword full-reg)) ; size is not really known here - (fpr (get-fpr full-reg)))) + (fpr (get-fpr :xmm full-reg)))) ((= r/m #b100) ; SIB byte - rex.b is "don't care" (let* ((sib (the (unsigned-byte 8) (read-suffix 8 dstate))) (index-reg (extend +rex-x+ (ldb (byte 3 3) sib))) @@ -258,9 +346,9 @@ (sap-ref-word (int-sap addr) 0))) (define-load-time-global thread-slot-names - (let* ((slots (primitive-object-slots - (find 'sb-vm::thread *primitive-objects* - :key #'primitive-object-name))) + (let* ((slots (coerce (primitive-object-slots + (sb-vm::primitive-object 'sb-vm::thread)) + 'list)) (a (make-array (1+ (slot-offset (car (last slots)))) :initial-element nil))) (dolist (slot slots a) @@ -288,9 +376,12 @@ (type (member nil :byte :word :dword :qword) width) (type (or null stream) stream) (type disassem-state dstate)) + ;; If disassembling into the dstate, print nothing; just stash the operand. (when (null stream) (return-from print-mem-ref (operand (cons value width) dstate))) + + ;; Unpack and print the pieces of the machine EA. (let ((base-reg (machine-ea-base value)) (disp (machine-ea-disp value)) (index-reg (machine-ea-index value)) @@ -300,6 +391,8 @@ (princ '| PTR | stream)) (when (dstate-getprop dstate +fs-segment+) (princ "FS:" stream)) + (when (dstate-getprop dstate +gs-segment+) + (princ "GS:" stream)) (write-char #\[ stream) (when base-reg (if (eql :rip base-reg) @@ -321,18 +414,20 @@ (princ disp stream)) (firstp (princ16 disp stream) - ;; Avoid the MAYBE-NOTE- calls if we can. A negative offset is never an + ;; Avoid the MAYBE-NOTE call if we can. A negative offset is never an ;; absolute address as would be used for asm routines and static symbols. - (or (minusp disp) - (maybe-note-assembler-routine disp nil dstate) - ;; Static symbols coming from CELL-REF - (maybe-note-static-symbol (+ disp (- other-pointer-lowtag n-word-bytes)) - dstate))) + ;; FIRSTP implies lack of a base and index register. + (unless (minusp disp) + (maybe-note-assembler-routine disp nil dstate))) (t (princ disp stream)))) (write-char #\] stream) + + ;; Always try to add an end-of-line comment about the EA. + ;; Assembler routines were already handled above (not really sure why) + ;; so now we have to figure out everything else. + (when (and (eq (machine-ea-base value) :rip) (neq mode :compute)) - ;; Always try to print the EA as a note (block nil (binding* ((seg (dstate-segment dstate)) (code (seg-code seg) :exit-if-null) @@ -347,7 +442,13 @@ ;; compilation to memory says it is all associated with ;; the symbol "lisp_jit_code" which is not useful. (when (plusp addr) - (or (unless (sb-kernel:immobile-space-addr-p addr) + (or (when (<= sb-vm:alien-linkage-table-space-start addr + (+ sb-vm:alien-linkage-table-space-start + (1- sb-vm:alien-linkage-table-space-size))) + (let* ((index (sb-vm::alien-linkage-table-index-from-address addr)) + (name (sb-impl::alien-linkage-index-to-name index))) + (note (lambda (s) (format s "&~A" name)) dstate))) + (unless (sb-kernel:immobile-space-addr-p addr) (maybe-note-assembler-routine addr nil dstate)) ;; Show the absolute address and maybe the contents. (note (format nil "[#x~x]~@[ = #x~x~]" @@ -355,7 +456,21 @@ (case width (:qword (unboxed-constant-ref dstate addr disp)))) dstate)))))) - #+sb-thread + + ;; Recognize "[Rbase+disp]" as an alien linkage table reference if Rbase was + ;; just loaded with the base address in the prior instruction. + (when (and (eql (machine-ea-base value) + (car (sb-disassem::dstate-known-register-contents dstate))) + (eq (cdr (sb-disassem::dstate-known-register-contents dstate)) + 'alien-linkage) + (not (machine-ea-index value)) + (integerp (machine-ea-disp value))) + (let* ((index (sb-vm::alien-linkage-table-index-from-address + (+ sb-vm:alien-linkage-table-space-start (machine-ea-disp value)))) + (name (sb-impl::alien-linkage-index-to-name index))) + (note (lambda (s) (format s "&~A" name)) dstate))) + (setf (sb-disassem::dstate-known-register-contents dstate) nil) + (flet ((guess-symbol (predicate) (binding* ((code-header (seg-code (dstate-segment dstate)) :exit-if-null) (header-n-words (code-header-words code-header))) @@ -363,7 +478,15 @@ for obj = (code-header-ref code-header word-num) when (and (symbolp obj) (funcall predicate obj)) do (return obj))))) + (when (and (not base-reg) (not index-reg) disp) + (let ((addr (+ disp ; guess that DISP points to a symbol-value slot + (- (ash sb-vm:symbol-value-slot sb-vm:word-shift)) + sb-vm:other-pointer-lowtag))) + (awhen (guess-symbol (lambda (s) (= (get-lisp-obj-address s) addr))) + (note (lambda (stream) (prin1 it stream)) dstate) + (return-from print-mem-ref)))) ;; Try to reverse-engineer which thread-local binding this is + #+sb-thread (cond ((and disp ; Test whether disp looks aligned to an object header (not (logtest (- disp 4) sb-vm:lowtag-mask)) (not base-reg) (not index-reg)) @@ -371,26 +494,33 @@ (symbol (guess-symbol (lambda (s) (= (get-lisp-obj-address s) addr))))) (when symbol - ;; Q: what's the difference between "tls_index:" and "tls:" (below)? + ;; "tls_index:" is access to the half-sized slot within the + ;; symbol header that provides an offset into TLS. (note (lambda (stream) (format stream "tls_index: ~S" symbol)) dstate)))) - ((and (not base-reg) (not index-reg) disp) - (let ((addr (+ disp ; guess that DISP points to a symbol-value slot - (- (ash sb-vm:symbol-value-slot sb-vm:word-shift)) - sb-vm:other-pointer-lowtag))) - (awhen (guess-symbol (lambda (s) (= (get-lisp-obj-address s) addr))) - (note (lambda (stream) (format stream "~A" it)) dstate)))) - ((and (eql base-reg #.(tn-offset sb-vm::thread-base-tn)) - (not (dstate-getprop dstate +fs-segment+)) ; not system TLS + ;; thread slots + ((and (eql base-reg sb-vm::thread-reg) + #+gs-seg (dstate-getprop dstate +gs-segment+) + #-gs-seg (not (dstate-getprop dstate +fs-segment+)) ; not system TLS (not index-reg) ; no index - (typep disp '(integer 0 *)) ; positive displacement + (typep disp '(integer -128 *)) ; valid displacement (zerop (logand disp 7))) ; lispword-aligned - (let ((index (ash disp -3))) - (when (< index (length thread-slot-names)) - (awhen (aref thread-slot-names index) - (return-from print-mem-ref - (note (lambda (stream) (format stream "thread.~(~A~)" it)) - dstate))))) + (let* ((index (ash disp -3)) + (symbol (cond ((minusp index) + (let ((index (1- (- index)))) + (when (array-in-bounds-p sb-vm::+thread-header-slot-names+ index) + (aref sb-vm::+thread-header-slot-names+ index)))) + ((< index (length thread-slot-names)) + (aref thread-slot-names index))))) + (when symbol + (when (and (eq symbol 'sb-vm::alien-linkage-table-base) + (eql (logandc2 (sb-disassem::dstate-inst-properties dstate) +rex-r+) + (logior +rex+ +rex-w+ +rex-b+))) + (setf (sb-disassem::dstate-known-register-contents dstate) + `(,(reg-num (regrm-inst-reg dchunk-zero dstate)) . alien-linkage))) + (return-from print-mem-ref + (note (lambda (stream) (format stream "thread.~(~A~)" symbol)) + dstate)))) (let ((symbol (or (guess-symbol (lambda (s) (= (symbol-tls-index s) disp))) ;; static symbols aren't in the code header @@ -398,8 +528,10 @@ :key #'symbol-tls-index)))) (when symbol (return-from print-mem-ref + ;; "tls:" refers to the current value of the symbol in TLS (note (lambda (stream) (format stream "tls: ~S" symbol)) - dstate))))))))) + dstate))))) + )))) (defun lea-compute-label (value dstate) ;; If VALUE should be regarded as a label, return the address. @@ -489,23 +621,6 @@ (snarf-error-junk sap offset trap-number length-only))) trap stream dstate))))))) -;;; Note: this really has nothing to do with the code fixups, and we're -;;; merely utilizing PACK-CODE-FIXUP-LOCS to perform data compression. -(defun sb-c::convert-alloc-point-fixups (code locs) - ;; Find the instruction which jumps over the profiling code, - ;; and record the offset, and not the instruction that makes the call - ;; to enable the counter. The instructions preceding the call comprise - ;; a test, jmp, and long nop. Luckily a long nop encoding never - ;; has the byte #xEB in it, so just scan backwards looking for that. - (pack-code-fixup-locs - (mapcar (lambda (loc) - (loop (cond ((zerop (decf loc)) - (bug "Failed to find allocation point")) - ((eql (sap-ref-8 (code-instructions code) loc) #xEB) - (return loc))))) - locs) - nil)) - ;;; Disassemble memory of CODE from START-ADDRESS for LENGTH bytes ;;; calling FUNCTION on each instruction that has a PC-relative operand. ;;; If supplied, PREDICATE is used to filter out some function invocations. @@ -519,6 +634,7 @@ (jmp-inst (find-inst #xE9 inst-space)) (cond-jmp-inst (find-inst #x800f inst-space)) (lea-inst (find-inst #x8D inst-space)) + (mov-inst (find-inst #x8B inst-space)) (address (get-lisp-obj-address code)) (text-start (sap-int (code-instructions code))) (text-end (+ text-start (%code-text-size code))) @@ -527,7 +643,7 @@ (seg-length segment) length (seg-sap-maker segment) (lambda () sap)) (map-segment-instructions - (lambda (dchunk inst) + (lambda (dchunk inst &aux (opcode (sap-ref-8 sap (dstate-cur-offs dstate)))) (flet ((includep (target) ;; Self-relative (to the code object) operands are ignored. (and (or (< target address) (>= target text-end)) @@ -546,10 +662,11 @@ (when (includep operand) (funcall function (+ (dstate-cur-offs dstate) 2) operand inst)))) - ((eq inst lea-inst) + ((or (eq inst lea-inst) + (and (eq inst mov-inst) (eql opcode #x8B))) ;; Computing the address of UNDEFINED-FDEFN and ;; FUNCALLABLE-INSTANCE-TRAMP is done with LEA. - (aver (eql (sap-ref-8 sap (dstate-cur-offs dstate)) #x8D)) + ;; Load from the alien linkage table can be done with MOV Rnn,[RIP-k]. (let ((modrm (sap-ref-8 sap (1+ (dstate-cur-offs dstate))))) (when (= (logand modrm #b11000111) #b00000101) ; RIP-relative mode (let ((operand (+ (signed-sap-ref-32 diff --git a/src/compiler/x86-64/type-vops.lisp b/src/compiler/x86-64/type-vops.lisp index 7ca6319d0a..b19eb1a786 100644 --- a/src/compiler/x86-64/type-vops.lisp +++ b/src/compiler/x86-64/type-vops.lisp @@ -16,8 +16,7 @@ (defun generate-fixnum-test (value) "Set the Z flag if VALUE is fixnum" (inst test :byte - (cond ;; This is hooey. None of the type-vops presently allow - ;; control-stack as a storage class. + (cond ((ea-p value) value) ; merged a memory load + fixnump vop ((sc-is value control-stack) (ea (frame-byte-offset (tn-offset value)) rbp-tn)) (t @@ -88,12 +87,8 @@ (defun %test-immediate (value temp target not-p immediate &optional (drop-through (gen-label))) - ;; Code a single instruction byte test if possible. - (cond ((sc-is value any-reg descriptor-reg) - (inst cmp :byte value immediate)) - (t - (move temp value) ; FIXME - why load? - (inst cmp :byte temp immediate))) + (declare (ignore temp)) + (inst cmp :byte value immediate) (inst jmp (if not-p :ne :e) target) (emit-label drop-through)) @@ -120,7 +115,8 @@ (defun %test-headers (value temp target not-p function-p headers &key except (drop-through (gen-label)) - (compute-temp t) + (load-widetag t) + (compute-temp load-widetag) value-tn-ref) (let* ((lowtag (if function-p fun-pointer-lowtag other-pointer-lowtag)) ;; It is preferable (smaller and faster code) to directly @@ -128,13 +124,16 @@ ;; a register first. Find out if this is possible and set ;; WIDETAG-TN accordingly. If impossible, generate the ;; register load. - (widetag-tn (if (and (null (cdr headers)) + (widetag-tn (if (and load-widetag + (null (cdr headers)) (not except) (or (atom (car headers)) (= (caar headers) bignum-widetag) (= (cdar headers) complex-array-widetag))) (ea (- lowtag) value) temp)) + (first (car headers)) + (second (cadr headers)) (untagged)) (multiple-value-bind (equal less-or-equal greater-or-equal when-true @@ -147,7 +146,8 @@ (values :ne :a :b drop-through target) (values :e :na :nb target drop-through)) - (cond ((and value-tn-ref + (cond ((not load-widetag)) + ((and value-tn-ref (eq lowtag other-pointer-lowtag) (other-pointer-tn-ref-p value-tn-ref))) ; best case: lowtag is right ((and value-tn-ref @@ -174,61 +174,78 @@ (inst test :byte temp lowtag-mask) (inst jmp :nz when-false))) - (when (eq widetag-tn temp) + (when (and load-widetag + (eq widetag-tn temp)) (inst mov :dword temp (or untagged (ea (- lowtag) value)))) (dolist (widetag except) (inst cmp :byte temp widetag) (inst jmp :e when-false)) - ;; FIXME: this backend seems to be missing the special logic for - ;; testing exactly two widetags differing only in a single bit, - ;; which through evolution is almost totally unworkable anyway... + (cond + ((and (fixnump first) + (fixnump second) + (not (cddr headers)) + (= (logcount (logxor first second)) 1)) + ;; Two widetags differing at one bit. Use one cmp and branch. + ;; Start by ORing in the bit that they differ on. + (let ((diff-bit (logxor first second))) + (aver (not (ea-p widetag-tn))) ; can't clobber a header + (inst or :byte widetag-tn diff-bit) + (inst cmp :byte widetag-tn (logior first diff-bit)) + (if not-p (inst jmp :ne target) (inst jmp :eq target)))) + (t ;; Compared to x86 we additionally optimize the cases of a ;; range starting with BIGNUM-WIDETAG (= min widetag) ;; or ending with COMPLEX-ARRAY-WIDETAG (= max widetag) - (do ((remaining headers (cdr remaining))) - ((null remaining)) - (let ((header (car remaining)) - (last (null (cdr remaining)))) - (cond - ((atom header) - (inst cmp :byte widetag-tn header) - (if last - (inst jmp equal target) - (inst jmp :e when-true))) - (t - (let ((start (car header)) - (end (cdr header))) - (cond - ((= start bignum-widetag) - (inst cmp :byte widetag-tn end) - (if last - (inst jmp less-or-equal target) - (inst jmp :be when-true))) - ((= end complex-array-widetag) - (inst cmp :byte widetag-tn start) - (if last - (inst jmp greater-or-equal target) - (inst jmp :b when-false))) - ((not last) - (inst cmp :byte temp start) - (inst jmp :b when-false) - (inst cmp :byte temp end) - (inst jmp :be when-true)) - (t - (inst sub :byte temp start) - (inst cmp :byte temp (- end start)) - (inst jmp less-or-equal target)))))))) + (do ((remaining headers (cdr remaining))) + ((null remaining)) + (let ((header (car remaining)) + (last (null (cdr remaining)))) + (cond + ((atom header) + (inst cmp :byte widetag-tn header) + (if last + (inst jmp equal target) + (inst jmp :e when-true))) + (t + (let ((start (car header)) + (end (cdr header))) + (cond + ((= start bignum-widetag) + (inst cmp :byte widetag-tn end) + (if last + (inst jmp less-or-equal target) + (inst jmp :be when-true))) + ((= end complex-array-widetag) + (inst cmp :byte widetag-tn start) + (if last + (inst jmp greater-or-equal target) + (inst jmp :b when-false))) + ((not last) + (inst cmp :byte temp start) + (inst jmp :b when-false) + (inst cmp :byte temp end) + (inst jmp :be when-true)) + (t + (inst sub :byte temp start) + (inst cmp :byte temp (- end start)) + (inst jmp less-or-equal target)))))))))) + (emit-label drop-through)))) ;;;; other integer ranges +(define-vop (simple-type-predicate) + (:args (value :scs (any-reg descriptor-reg control-stack))) + (:conditional) + (:args-var args) + (:policy :fast-safe)) + (define-vop (fixnump/unsigned-byte-64 simple-type-predicate) (:args (value :scs (unsigned-reg))) (:arg-types unsigned-num) (:translate fixnump) (:temporary (:sc unsigned-reg :from (:argument 0)) tmp) - (:info) (:conditional :z) (:generator 3 (move tmp value) @@ -237,7 +254,6 @@ #-#.(cl:if (cl:= sb-vm:n-fixnum-tag-bits 1) '(:and) '(:or)) (define-vop (fixnump/signed-byte-64 simple-type-predicate) (:args (value :scs (signed-reg))) - (:info) (:conditional :z) (:temporary (:sc unsigned-reg) temp) (:arg-types signed-num) @@ -247,14 +263,13 @@ ;; a <= x <= a + 2^n - 1 ;; is equivalent to unsigned ;; ((x-a) >> n) = 0 - (inst mov temp #.(- sb-xc:most-negative-fixnum)) + (inst mov temp #.(- most-negative-fixnum)) (inst add temp value) (inst shr temp n-fixnum-bits))) #+#.(cl:if (cl:= sb-vm:n-fixnum-tag-bits 1) '(:and) '(:or)) (define-vop (fixnump/signed-byte-64 simple-type-predicate) (:args (value :scs (signed-reg) :target temp)) - (:info) (:conditional :no) (:temporary (:sc unsigned-reg :from (:argument 0)) temp) (:arg-types signed-num) @@ -267,61 +282,125 @@ ;;; A (SIGNED-BYTE 64) can be represented with either fixnum or a bignum with ;;; exactly one digit. -(define-vop (signed-byte-64-p type-predicate) +(define-vop (pointerp) + (:args (value :scs (any-reg descriptor-reg))) + (:temporary (:sc unsigned-reg :from (:argument 0)) temp) + (:conditional :z) + (:policy :fast-safe) + (:translate pointerp) + (:generator 3 + (if (location= temp value) (inst sub :dword value 3) (inst lea :dword temp (ea -3 value))) + (inst test :byte temp #b11))) + +;; A fixnum or single-digit bignum satisfies signed-byte-64-p +(define-vop (signed-byte-64-p pointerp) (:translate signed-byte-64-p) - (:generator 45 - (multiple-value-bind (yep nope) - (if not-p - (values not-target target) - (values target not-target)) - (case n-fixnum-tag-bits - (1 (%lea-for-lowtag-test temp value other-pointer-lowtag) - (inst test :byte temp fixnum-tag-mask) ; 0th bit = 1 => fixnum - (inst jmp :nz yep) - (inst test :byte temp lowtag-mask)) - (t ;; we'll only examine 1 byte, but moving a :dword is preferable - ;; as it doesn't require the CPU to retain the other 7 bytes. - (inst mov :dword temp value) - (inst test :byte temp fixnum-tag-mask) - (inst jmp :e yep) - (inst and :byte temp lowtag-mask) - (inst cmp :byte temp other-pointer-lowtag))) - (inst jmp :ne nope) - (inst cmp :qword (ea (- other-pointer-lowtag) value) - (+ (ash 1 n-widetag-bits) bignum-widetag)) - (inst jmp (if not-p :ne :e) target)) - NOT-TARGET)) + (:conditional :z) + (:args-var arg-ref) + (:generator 6 + (when (types-equal-or-intersect (tn-ref-type arg-ref) (specifier-type 'fixnum)) + (inst test :byte value fixnum-tag-mask) + (inst jmp :z out)) ; good + (let ((ea (cond ((fixnum-or-other-pointer-tn-ref-p arg-ref) + (ea (- other-pointer-lowtag) value)) + (t + (%lea-for-lowtag-test temp value other-pointer-lowtag :qword) + (inst test :byte temp lowtag-mask) + (inst jmp :nz out) + (ea temp))))) + (inst cmp :qword ea (bignum-header-for-length 1))) + OUT)) + +(define-vop (signed-byte-64-p/unsigned) + (:args (value :scs (unsigned-reg))) + (:arg-types unsigned-num) + (:conditional :ns) + (:policy :fast-safe) + (:translate signed-byte-64-p) + (:generator 5 + (inst test value value))) + +(macrolet ((define (name src-size) + `(progn + (define-vop (,name) + (:translate ,name) + (:args (value :scs (any-reg descriptor-reg))) + (:conditional :z) + (:args-var arg-ref) + (:policy :fast-safe) + (:temporary (:sc unsigned-reg) temp temp2) + (:generator 6 + ;; Optimistically assume that the argument is a fixnum. + ;; If it is, then we're shifting out the tag bit, otherwise + ;; putting random bits in the low byte, which is harmless. + (move temp value) + (inst sar temp n-fixnum-tag-bits) + (inst movsx '(,src-size :qword) temp2 temp) + (inst cmp temp2 temp) + ;; If the input wasn't known to be a fixnum, and it passed + ;; the sign-extension test, then check FIXNUMP now. + (unless (csubtypep (tn-ref-type arg-ref) (specifier-type 'fixnum)) + (inst jmp :nz OUT) ; did NOT pass the sign-extension test + (inst test :byte value fixnum-tag-mask)) + OUT)) + (define-vop (,(symbolicate name "/SIGNED")) + (:translate ,name) + (:args (value :scs (signed-reg))) + (:arg-types signed-num) + (:conditional :z) + (:policy :fast-safe) + (:temporary (:sc unsigned-reg) temp) + (:generator 2 + (inst movsx '(,src-size :qword) temp value) + (inst cmp temp value)))))) + (define signed-byte-8-p :byte) + (define signed-byte-16-p :word) + (define signed-byte-32-p :dword)) + +;;; Sign bit and fixnum tag bit. +(defconstant non-negative-fixnum-mask-constant + #x8000000000000001) +(defconstant non-negative-fixnum-mask-constant-wired-address + (+ static-space-start (* 12 n-word-bytes))) +;; the preceding constant is embedded in an array, +;; the header of which must not overlap the static alloc regions +#-sb-thread +(aver (>= (- non-negative-fixnum-mask-constant-wired-address (* 2 n-word-bytes)) + (+ (max boxed-region cons-region mixed-region) (* 3 n-word-bytes)))) ;;; An (unsigned-byte 64) can be represented with either a positive ;;; fixnum, a bignum with exactly one positive digit, or a bignum with ;;; exactly two digits and the second digit all zeros. (define-vop (unsigned-byte-64-p type-predicate) (:translate unsigned-byte-64-p) - (:generator 45 + (:generator 10 (let ((not-target (gen-label)) (single-word (gen-label)) - (fixnum (gen-label))) + (fixnum-p (types-equal-or-intersect (tn-ref-type args) (specifier-type 'fixnum)))) (multiple-value-bind (yep nope) (if not-p (values not-target target) (values target not-target)) - ;; Is it a fixnum? - (inst mov temp value) - (inst test :byte temp fixnum-tag-mask) - (inst jmp :e fixnum) - - ;; If not, is it an other pointer? - (inst and :byte temp lowtag-mask) - (inst cmp :byte temp other-pointer-lowtag) - (inst jmp :ne nope) + (when fixnum-p + ;; Is it a fixnum with the sign bit clear? + (inst test (ea non-negative-fixnum-mask-constant-wired-address) value) + (inst jmp :z yep)) + (cond ((fixnum-or-other-pointer-tn-ref-p args) + (when fixnum-p + (inst test :byte value fixnum-tag-mask) + (inst jmp :z nope))) + (t + (%lea-for-lowtag-test temp value other-pointer-lowtag) + (inst test :byte temp lowtag-mask) + (inst jmp :ne nope))) ;; Get the header. (loadw temp value 0 other-pointer-lowtag) ;; Is it one? - (inst cmp temp (+ (ash 1 n-widetag-bits) bignum-widetag)) + (inst cmp temp (bignum-header-for-length 1)) (inst jmp :e single-word) ;; If it's other than two, we can't be an (unsigned-byte 64) ;: Leave TEMP holding 0 in the affirmative case. - (inst sub temp (+ (ash 2 n-widetag-bits) bignum-widetag)) + (inst sub temp (bignum-header-for-length 2)) (inst jmp :ne nope) ;; Compare the second digit to zero (in TEMP). (inst cmp (object-slot-ea value (1+ bignum-digits-offset) other-pointer-lowtag) @@ -332,9 +411,7 @@ (emit-label single-word) ;; Get the single digit. (loadw temp value bignum-digits-offset other-pointer-lowtag) - ;; positive implies (unsigned-byte 64). - (emit-label fixnum) (inst test temp temp) (inst jmp (if not-p :s :ns) target) @@ -356,8 +433,13 @@ (:generator 4 (let* ((fixnum-hi (if (sc-is value unsigned-reg signed-reg) hi - (fixnumize hi)))) - (inst test value (constantize (lognot fixnum-hi)))))) + (fixnumize hi))) + (mask (lognot fixnum-hi)) + (constant + (if (= (ldb (byte 64 0) mask) non-negative-fixnum-mask-constant) + (ea non-negative-fixnum-mask-constant-wired-address) + (constantize mask)))) + (inst test value constant)))) (define-vop (test-fixnum-mod-tagged-unsigned) (:args (value :scs (any-reg unsigned-reg signed-reg))) @@ -389,31 +471,191 @@ (inst jmp (if not-p :a :be) target) (emit-label skip)))) -(define-vop (pointerp) - (:args (value :scs (any-reg descriptor-reg) :target temp)) - (:temporary (:sc unsigned-reg :from (:argument 0)) temp) - (:conditional) - (:info target not-p) - (:policy :fast-safe) - (:translate pointerp) - (:generator 3 - (inst lea :dword temp (ea -3 value)) - (inst test :byte temp #b11) - (inst jmp (if not-p :nz :z) target))) +;;; SINGLE-FLOAT-P, CHARACTERP, UNBOUND-MARKER-P produce a flag result +;;; and never need a temporary. +(macrolet ((define (name widetag) + `(define-vop (,name simple-type-predicate) + (:translate ,name) + (:conditional :z) + (:generator 1 (inst cmp :byte value ,widetag))))) + (define single-float-p single-float-widetag) + (define characterp character-widetag) + (define unbound-marker-p unbound-marker-widetag)) + +;;; FUNCTIONP, LISTP, %INSTANCEP, %OTHER-POINTER-P produce a flag result +(macrolet ((define (name lowtag) + `(define-vop (,name pointerp) + (:translate ,name) + (:generator 2 + (if (location= temp value) + (inst sub :dword value ,lowtag) + (inst lea :dword temp (ea (- ,lowtag) value))) + (inst test :byte temp lowtag-mask))))) + (define functionp fun-pointer-lowtag) + (define listp list-pointer-lowtag) + (define %instancep instance-pointer-lowtag) + (define %other-pointer-p other-pointer-lowtag)) + +;;; Function subtypes produce a flag result +(macrolet ((define (name widetag) + `(define-vop (,name type-predicate) + (:translate ,name) + (:info) ; nullify the info + (:conditional :z) + (:generator 4 + (inst lea temp (ea (- fun-pointer-lowtag) value)) + (inst test :byte temp lowtag-mask) + (inst jmp :ne out) + (inst cmp :byte (ea temp) ,widetag) + out)))) + (define closurep closure-widetag) + (define simple-fun-p simple-fun-widetag) + (define funcallable-instance-p funcallable-instance-widetag)) +;;; Various OTHER-POINTER objects produce a flag result. +;;; The parens around widetag are from copy&paste of generic/type-vops +(macrolet ((define (name (widetag)) + `(define-vop (,name type-predicate) + (:translate ,name) + (:info) ; nullify the info + (:conditional :z) + (:generator 4 + (test-other-ptr value args ,widetag temp out) + out)))) + (define bignump (bignum-widetag)) + (define ratiop (ratio-widetag)) + (define complex-rational-p (complex-widetag)) + (define complex-single-float-p (complex-single-float-widetag)) + (define complex-double-float-p (complex-double-float-widetag)) + (define double-float-p (double-float-widetag)) + (define system-area-pointer-p (sap-widetag)) + (define weak-pointer-p (weak-pointer-widetag)) + (define code-component-p (code-header-widetag)) + (define fdefn-p (fdefn-widetag)) + (define simple-array-header-p (simple-array-widetag)) + (define complex-vector-p (complex-vector-widetag))) + +(macrolet ((fail-if-not-otherptr () + `(cond ((other-pointer-tn-ref-p value-tn-ref) + (inst mov :byte temp (ea (- other-pointer-lowtag) value))) + (t + (inst lea temp (ea (- other-pointer-lowtag) value)) + (inst test :byte temp lowtag-mask) + ;; TEST clears the Carry, so if this jump occurs, + ;; it returns the correct answer for the vops that return + ;; their result in Z or C. + (inst jmp :nz out) + (inst mov :byte temp (ea temp)))))) + #+sb-unicode + (macrolet ((define (name (simple nonsimple)) + (aver (= (logior 8 (symbol-value simple)) (symbol-value nonsimple))) + `(define-vop (,name type-predicate) + (:translate ,name) + (:info) ; nullify the info + (:conditional :z) + (:args-var value-tn-ref) + (:generator 4 + (fail-if-not-otherptr) + (inst or :byte temp 8) + (inst cmp :byte temp ,nonsimple) + out)))) + (define base-string-p (simple-base-string-widetag complex-base-string-widetag)) + (define character-string-p + (simple-character-string-widetag complex-character-string-widetag))) + (macrolet ((define (name widetags) + (let* ((widetags (symbol-value widetags)) + (min (reduce #'min widetags)) + (max (reduce #'max widetags))) + `(define-vop (,name type-predicate) + (:translate ,name) + (:info) + (:conditional :c) ; Carry flag = "below" (unsigned) + (:args-var value-tn-ref) + (:generator 4 + (fail-if-not-otherptr) + (inst sub :byte temp ,min) + (inst cmp :byte temp ,(1+ (- max min))) + OUT))))) + (define simple-rank-1-array-*-p +simple-rank-1-array-widetags+) + (define vectorp +vector-widetags+) + (define simple-array-p +simple-array-widetags+) + #+sb-unicode (define stringp +string-widetags+))) ;;;; list/symbol types ;;; ;;; symbolp (or symbol (eq nil)) ;;; consp (and list (not (eq nil))) +;;; Test whether ARG is an other-pointer to WIDETAG, setting the Z flag if so +(defun test-other-ptr (arg arg-ref widetag temp label) + (inst cmp :byte + (cond ((other-pointer-tn-ref-p arg-ref) + (ea (- other-pointer-lowtag) arg)) + (t + (%lea-for-lowtag-test temp arg other-pointer-lowtag :qword) + (inst test :byte temp lowtag-mask) + (inst jmp :ne label) + (ea temp))) + widetag)) + (define-vop (symbolp type-predicate) (:translate symbolp) - (:generator 12 - (let ((is-symbol-label (if not-p DROP-THRU target))) - (inst cmp value nil-value) - (inst jmp :e is-symbol-label) - (test-type value temp target not-p (symbol-widetag))) - DROP-THRU)) + (:info) + (:conditional :z) + (:generator 5 + ;; If the VALUE were known to be an OTHER-POINTER, the the IR1 lvar type + ;; can't intersect NULL. So the IR1 should have been transformed to NON-NULL-SYMBOL-P. + ;; Hence this must *not* be known to be an OTHER-POINTER. + (aver (not (other-pointer-tn-ref-p args))) + (%lea-for-lowtag-test temp value other-pointer-lowtag :qword) + (inst test :byte temp lowtag-mask) + (inst jmp :e compare-widetag) + (inst cmp value nil-value) + (inst jmp out) + compare-widetag + (inst cmp :byte (ea temp) symbol-widetag) + out)) + +(define-vop (non-null-symbol-p symbolp) + (:translate non-null-symbol-p) + (:generator 3 (test-other-ptr value args symbol-widetag temp out) out)) + +;;; It would be far better if we could recognize the IR1 for +;;; (AND (CONSP X) (EQ (CAR X) 'FOO)) +;;; rather than treating (TYPEP X '(CONS (EQL FOO))) as a special case, +;;; but hey at least this provides the IR2 support for it. +(define-vop (car-eq-if-listp) + (:args (value :scs (descriptor-reg)) + (obj :scs (immediate any-reg descriptor-reg))) + (:temporary (:sc unsigned-reg) temp) + (:conditional :z) + (:policy :fast-safe) + (:translate car-eq-if-listp) + (:generator 3 + (inst lea temp (ea (- list-pointer-lowtag) value)) + (inst test :byte temp lowtag-mask) + (inst jmp :nz out) + (inst cmp :qword (ea temp) (encode-value-if-immediate obj)) + out)) + +(eval-when (:compile-toplevel) (aver (= sb-impl::package-id-bits 16))) +(define-vop (keywordp symbolp) + (:translate keywordp) + (:args-var args-ref) + (:generator 3 + (cond ((csubtypep (tn-ref-type args-ref) (specifier-type 'symbol)) + (inst cmp :word (ea (+ (ash symbol-name-slot word-shift) 6 + (- other-pointer-lowtag)) + value) + sb-impl::+package-id-keyword+)) + (t + (inst lea temp (ea (- other-pointer-lowtag) value)) + (inst test :byte temp lowtag-mask) + (inst jmp :ne out) + (inst cmp :byte (ea temp) symbol-widetag) + (inst jmp :ne out) + (inst cmp :word (ea (+ (ash symbol-name-slot word-shift) 6) temp) + sb-impl::+package-id-keyword+))) + out)) (define-vop (consp type-predicate) (:translate consp) @@ -435,41 +677,395 @@ (:generator 2 (inst cmp :byte (ea (- other-pointer-lowtag) x) widetag))) -;;; TRANSFORM-INSTANCE-TYPEP checks for this vop by name and will try to use it, -;;; so don't define it if inapplicable. #+compact-instance-header (progn -(defknown layout-eq (instance t) boolean (flushable)) -(define-vop (layout-eq) - (:translate layout-eq) + (define-vop () + (:translate %instance-layout) + (:policy :fast-safe) + (:args (object :scs (descriptor-reg))) + (:results (res :scs (descriptor-reg))) + (:variant-vars lowtag) + (:variant instance-pointer-lowtag) + (:generator 1 + (inst mov :dword res (ea (- 4 lowtag) object)))) + (define-vop () + (:translate %set-instance-layout) + (:policy :fast-safe) + (:args (object :scs (descriptor-reg)) + (value :scs (any-reg descriptor-reg))) + (:vop-var vop) + (:temporary (:sc unsigned-reg) temp) + (:node-var node) + (:generator 1 + (unless (sb-c::set-slot-old-p node) + (emit-gc-store-barrier object nil temp (vop-nth-arg 1 vop) value)) + (inst mov :dword (ea (- 4 instance-pointer-lowtag) object) value))) + (define-vop (%fun-layout %instance-layout) + (:translate %fun-layout) + (:variant fun-pointer-lowtag)) + (define-vop (%set-fun-layout %set-instance-layout) + (:translate %set-fun-layout) + (:generator 1 + (unless (sb-c::set-slot-old-p node) + (emit-gc-store-barrier object nil temp (vop-nth-arg 1 vop) value)) + (inst mov :dword (ea (- 4 fun-pointer-lowtag) object) value))) + (define-vop () + (:translate sb-c::layout-eq) (:policy :fast-safe) (:conditional :e) - (:args (instance :scs (descriptor-reg)) - (layout :scs (descriptor-reg immediate))) + (:args (object :scs (descriptor-reg)) + (layout :scs (descriptor-reg immediate #+metaspace constant))) + (:arg-types * * (:constant t)) + (:info lowtag) (:generator 1 - (inst cmp :dword - (ea (- 4 instance-pointer-lowtag) instance) - (if (sc-is layout immediate) + ;; With metaspace, the layout argument is actually a #<WRAPPER> + ;; which does not have IMMEDIATE sc, but rather CONSTANT sc. + ;; But we use a layout fixup which stuffs in the pointer to the layout. + (inst cmp :dword (ea (- 4 lowtag) object) + (if (sc-is layout immediate constant) (make-fixup (tn-value layout) :layout) layout))))) -(defknown layout-inherits-ref-eq (simple-vector index t) boolean (flushable)) -(define-vop (layout-inherits-ref-eq) - (:translate layout-inherits-ref-eq) +;;; Return the DISP part of an EA based on MEM-OP, +;;; which is a memory access vop such as INSTANCE-REF. +;;; Return NIL if the access can't be absorbed into a following instruction. +(defun valid-memref-byte-disp (mem-op &aux (info (vop-codegen-info mem-op))) + (ecase (vop-name mem-op) + (instance-index-ref-c + ;; for historical reasons, this has a "-C" variant which takes an info arg + (destructuring-bind (index) info + (- (ash (+ index instance-slots-offset) word-shift) + instance-pointer-lowtag))) + ((%raw-instance-ref/word %raw-instance-ref/signed-word) + ;; raw slot vops accept an immediate TN, not a codegen arg + (let ((index (tn-ref-tn (tn-ref-across (vop-args mem-op))))) + (when (sc-is index immediate) + (- (ash (+ (tn-value index) instance-slots-offset) word-shift) + instance-pointer-lowtag)))) + (slot + (destructuring-bind (name index lowtag) info + (declare (ignore name)) + (- (ash index word-shift) lowtag))) + (data-vector-ref-with-offset/simple-vector-c + (destructuring-bind (index offset) info + (let ((disp (- (ash (+ vector-data-offset index offset) word-shift) + other-pointer-lowtag))) + (if (typep disp '(signed-byte 32)) disp)))))) + +(define-vop (fixnump simple-type-predicate) + (:translate fixnump) + (:args-var arg-ref) + (:args (value :scs (any-reg descriptor-reg) :load-if (tn-ref-memory-access arg-ref))) + (:conditional :z) + ;; the compiler is very sensitive to this cost here as regards boxing. DON'T TOUCH !!! + (:generator 3 + (awhen (tn-ref-memory-access arg-ref) + (setq value (ea (cdr it) value))) + (generate-fixnum-test value))) + +(macrolet + ((define-simple-array-type-vops () + `(progn + ,@(map 'list + (lambda (saetp &aux (primtype (saetp-primitive-type-name saetp)) + (name (symbolicate primtype "-P"))) + `(define-vop (,name symbolp) + (:translate ,name) + (:generator 4 + (test-other-ptr value args ,(saetp-typecode saetp) temp out) + out))) + *specialized-array-element-type-properties*)))) + (define-simple-array-type-vops)) + +;;; Try to absorb a memory load into FIXNUMP. +(defoptimizer (sb-c::vop-optimize fixnump) (vop) + ;; Ensure that the fixnump vop does not try to absorb more than one memref. + ;; That is, if the initial IR2 matches (fixnump (memref (memref))) which is simplified + ;; to (memref+fixnump (memref x)), it would seem to allow matching of the pattern + ;; again if this optimizer is reapplied, because the "new" fixnump vop is superficially + ;; the same, except for the attachment of extra data to its input. + (unless (tn-ref-memory-access (vop-args vop)) + (let ((prev (sb-c::previous-vop-is + vop + '(instance-index-ref-c slot + ;; FIXME: could we also handle the non "-C" vop? + ;; The problem is that because FIXNUMP only takes one arg, + ;; an additional TN would have to be grafted into the data flow + ;; to convey the INDEX arg. So it's not the same fixnump vop + ;; any more - it's like a two-arg variant of fixnump. + data-vector-ref-with-offset/simple-vector-c)))) + ;; Inhibit the optimization on simple-vector if we need to trap uninitialized reads. + ;; #+ubsan always inhibits, otherwise it's policy-based + (when (and prev + (eq (vop-name prev) 'data-vector-ref-with-offset/simple-vector-c) + #-ubsan (sb-c::policy (sb-c::vop-node vop) (= safety 3))) + (return-from vop-optimize-fixnump-optimizer nil)) + (aver (not (vop-results vop))) ; is a :CONDITIONAL vop + (when (and prev (eq (vop-block prev) (vop-block vop))) + (let ((arg (vop-args vop))) + (when (and (eq (tn-ref-tn (vop-results prev)) (tn-ref-tn arg)) + (sb-c::very-temporary-p (tn-ref-tn arg))) + (binding* ((disp (valid-memref-byte-disp prev) :exit-if-null) + (arg-ref + (sb-c:reference-tn (tn-ref-tn (vop-args prev)) nil)) + (new (sb-c::emit-and-insert-vop + (sb-c::vop-node vop) (vop-block vop) (sb-c::vop-info vop) + arg-ref nil prev (vop-codegen-info vop)))) + (setf (tn-ref-memory-access arg-ref) `(:read . ,disp)) + (sb-c::delete-vop prev) + (sb-c::delete-vop vop) + new))))))) + +(define-vop (>-integer-fixnum) + (:translate >) + (:args (integer :scs (descriptor-reg)) + (fixnum :scs (immediate any-reg))) + (:arg-types (:or integer bignum) tagged-num) + (:temporary (:sc unsigned-reg) temp) + (:conditional) + (:info target not-p) + (:args-var args) + (:policy :fast-safe) + (:variant-vars comparison) + (:variant :g) + (:generator 8 + (unless (sc-is (tn-ref-tn args) descriptor-reg control-stack) + (setf args (tn-ref-across args))) + (let* ((integer-p (csubtypep (tn-ref-type args) (specifier-type 'integer))) + (fixnum (if (sc-is fixnum immediate) + (let* ((value (fixnumize (tn-value fixnum)))) + (cond ((plausible-signed-imm32-operand-p value) + value) + (t + (inst mov temp value) + temp))) + fixnum))) + (multiple-value-bind (yep nope) + (if not-p + (values not-target target) + (values target not-target)) + (assemble () + (when (types-equal-or-intersect (tn-ref-type args) (specifier-type 'fixnum)) + (generate-fixnum-test integer) + (inst jmp :nz BIGNUM) + (if (eql fixnum 0) + (inst test integer integer) + (inst cmp integer fixnum)) + (inst jmp comparison yep) + (inst jmp nope)) + bignum + (unless (fixnum-or-other-pointer-tn-ref-p args) + (test-type integer temp nope t (other-pointer-lowtag))) + (loadw temp integer 0 other-pointer-lowtag) + (unless integer-p + (inst cmp :byte temp bignum-widetag) + (inst jmp :ne nope)) + #.(assert (= (integer-length bignum-widetag) 5)) + (inst shr temp 5) + (inst cmp :qword (ea (- other-pointer-lowtag) integer temp) 0) + (inst jmp (case comparison + ((:l :le) (if not-p :ge :l)) + (t (if not-p :l :ge))) + target)))) + not-target)) + +(define-vop (<-integer-fixnum >-integer-fixnum) + (:translate <) + (:variant :l)) + +(define-vop (>-fixnum-integer >-integer-fixnum) + (:translate >) + (:args (fixnum :scs (immediate any-reg)) + (integer :scs (descriptor-reg))) + (:arg-types tagged-num (:or integer bignum)) + (:variant :l)) + +(define-vop (<-fixnum-integer >-fixnum-integer) + (:translate <) + (:variant :g)) + +;;; For integerp+cmp +(define-vop (<=-integer-fixnum >-integer-fixnum) + (:translate) + (:variant :le)) +(define-vop (>=-integer-fixnum <-integer-fixnum) + (:translate) + (:variant :ge)) +(define-vop (<=-fixnum-integer >-fixnum-integer) + (:translate) + (:variant :ge)) +(define-vop (>=-fixnum-integer <-fixnum-integer) + (:translate) + (:variant :le)) + +(define-vop (load-other-pointer-widetag) + (:args (value :scs (any-reg descriptor-reg))) + (:args-var args) + (:info not-other-pointer-label null-label) + (:results (r :scs (unsigned-reg))) + (:result-types unsigned-num) + (:generator 1 + (cond ((other-pointer-tn-ref-p args) + (inst mov :byte r (ea (- other-pointer-lowtag) value))) + (t + (when null-label + (inst cmp value nil-value) + (inst jmp :e null-label)) + (%lea-for-lowtag-test r value other-pointer-lowtag :qword) + (inst test :byte r lowtag-mask) + (inst jmp :nz not-other-pointer-label) + (inst mov :byte r (ea r)))))) + +(define-vop (test-widetag) + (:args (value :scs (unsigned-reg) :target temp)) + (:temporary (:sc unsigned-reg :from (:argument 1)) temp) + (:info target not-p type-codes) + (:generator 1 + (move temp value :dword) + (%test-headers nil temp target not-p nil type-codes + :load-widetag nil))) + +(macrolet ((read-depthoid () + `(ea (- (+ 4 (ash (+ instance-slots-offset + (get-dsd-index layout sb-kernel::flags)) + word-shift)) + instance-pointer-lowtag) + layout))) + (define-vop () + (:translate layout-depthoid) + (:policy :fast-safe) + (:args (layout :scs (descriptor-reg))) + (:results (res :scs (any-reg))) + (:result-types fixnum) + (:generator 1 + (inst movsx '(:dword :qword) res (read-depthoid)))) + (define-vop () + (:translate sb-c::layout-depthoid-ge) + (:policy :fast-safe) + (:args (layout :scs (descriptor-reg))) + (:info k) + (:arg-types * (:constant (unsigned-byte 16))) + (:conditional :ge) + (:generator 1 + (inst cmp :dword (read-depthoid) (fixnumize k)))) + + (defun structure-is-a (layout test-layout &optional target not-p done) + (cond ((integerp test-layout) + (inst test + (if (typep test-layout '(unsigned-byte 8)) + :byte + :dword) + (ea (- (ash (+ instance-slots-offset + (get-dsd-index layout sb-kernel::flags)) + word-shift) + instance-pointer-lowtag) + layout) + test-layout)) + ((let ((classoid (wrapper-classoid test-layout))) + (and (eq (classoid-state classoid) :sealed) + (not (classoid-subclasses classoid)))) + (emit-constant test-layout) + #+compact-instance-header + (inst cmp :dword + layout (make-fixup test-layout :layout)) + #-compact-instance-header + (inst cmp (emit-constant test-layout) layout)) + + (t + (let* ((depthoid (wrapper-depthoid test-layout)) + (offset (+ (id-bits-offset) + (ash (- depthoid 2) 2) + (- instance-pointer-lowtag)))) + (when (and target + (> depthoid sb-kernel::layout-id-vector-fixed-capacity)) + (inst cmp :dword (read-depthoid) (fixnumize depthoid)) + (inst jmp :l (if not-p target done))) + (inst cmp :dword + (ea offset layout) + ;; Small layout-ids can only occur for layouts made in genesis. + ;; Therefore if the compile-time value of the ID is small, + ;; it is permanently assigned to that type. + ;; Otherwise, we allow for the possibility that the compile-time ID + ;; is not the same as the load-time ID. + ;; I don't think layout-id 0 can get here, but be sure to exclude it. + (cond ((or (typep (layout-id test-layout) '(and (signed-byte 8) (not (eql 0)))) + (not (sb-c::producing-fasl-file))) + (layout-id test-layout)) + (t + (make-fixup test-layout :layout-id))))))))) + +(define-vop () + (:translate sb-c::%structure-is-a) + (:args (x :scs (descriptor-reg))) + (:arg-types * (:constant t)) + (:info test) (:policy :fast-safe) (:conditional :e) - (:args (vector :scs (descriptor-reg)) - (index :scs (any-reg descriptor-reg immediate)) - (thing :scs (descriptor-reg immediate))) (:generator 1 - (inst cmp :dword - (if (sc-is index immediate) - (ea (+ (- other-pointer-lowtag) - (ash (+ vector-data-offset (tn-value index)) word-shift)) - vector) - (ea (+ (- other-pointer-lowtag) - (ash vector-data-offset word-shift)) - vector index (ash 1 (- word-shift n-fixnum-tag-bits)))) - (if (sc-is thing immediate) - (make-fixup (tn-value thing) :layout) - thing)))) + (structure-is-a x test))) + +(define-vop () + (:translate sb-c::structure-typep) + (:args (object :scs (descriptor-reg))) + (:arg-types * (:constant t)) + (:args-var args) + (:policy :fast-safe) + (:conditional) + (:info target not-p test-layout) + (:temporary (:sc descriptor-reg) layout) + (:generator 4 + (unless (instance-tn-ref-p args) + (%test-lowtag object layout (if not-p target done) t instance-pointer-lowtag)) + + (cond ((and (not (integerp test-layout)) + (let ((classoid (wrapper-classoid test-layout))) + (and (eq (classoid-state classoid) :sealed) + (not (classoid-subclasses classoid))))) + (emit-constant test-layout) + #+compact-instance-header + (inst cmp :dword (ea (- 4 instance-pointer-lowtag) object) + (make-fixup test-layout :layout)) + #-compact-instance-header + (progn + (inst mov layout (emit-constant test-layout)) + (inst cmp (object-slot-ea object instance-slots-offset instance-pointer-lowtag) + layout))) + (t + #+compact-instance-header + (inst mov :dword layout (ea (- 4 instance-pointer-lowtag) object)) + #-compact-instance-header + (loadw layout object instance-slots-offset instance-pointer-lowtag) + (structure-is-a layout test-layout target not-p done))) + (inst jmp (if (if (integerp test-layout) + (not not-p) + not-p) + :ne :e) target) + done)) + +(define-vop (structure-typep*) + (:args (layout :scs (descriptor-reg))) + (:arg-types * (:constant t)) + (:policy :fast-safe) + (:conditional) + (:info target not-p test-layout) + (:generator 4 + (structure-is-a layout test-layout target not-p done) + (inst jmp (if (if (integerp test-layout) + (not not-p) + not-p) + :ne :e) target) + done)) + +(define-vop (load-instance-layout) + (:args (object :scs (any-reg descriptor-reg))) + (:args-var args) + (:info not-instance) + (:temporary (:sc unsigned-reg) temp) + (:results (r :scs (descriptor-reg))) + (:generator 1 + (unless (instance-tn-ref-p args) + (%test-lowtag object temp not-instance t instance-pointer-lowtag)) + #+compact-instance-header + (inst mov :dword r (ea (- 4 instance-pointer-lowtag) object)) + #-compact-instance-header + (loadw r object instance-slots-offset instance-pointer-lowtag))) diff --git a/src/compiler/x86-64/values.lisp b/src/compiler/x86-64/values.lisp index c6744756f1..9a317baa1a 100644 --- a/src/compiler/x86-64/values.lisp +++ b/src/compiler/x86-64/values.lisp @@ -12,7 +12,7 @@ (in-package "SB-VM") (define-vop (reset-stack-pointer) - (:args (ptr :scs (any-reg))) + (:args (ptr :scs (any-reg control-stack))) (:generator 1 (move rsp-tn ptr))) @@ -56,19 +56,26 @@ ;;; bogus SC that reflects the costs of the memory-to-memory moves for each ;;; operand, but this seems unworthwhile. (define-vop (push-values) - (:args (vals :more t - :scs (descriptor-reg))) + (:args (vals :more t :scs (descriptor-reg any-reg immediate constant))) (:results (start :from :load) (count)) (:info nvals) + (:temporary (:scs (descriptor-reg)) temp) + (:vop-var vop) (:generator 20 (unless (eq (tn-kind start) :unused) (move start rsp-tn)) - (do ((val vals (tn-ref-across val))) - ((null val)) - (inst push (let ((value (encode-value-if-immediate (tn-ref-tn val)))) - (if (integerp value) - (constantize value) - value)))) + (do ((tn-ref vals (tn-ref-across tn-ref))) + ((null tn-ref)) + (let ((tn (tn-ref-tn tn-ref))) + (inst push (sc-case tn + (constant + (load-constant vop tn temp) + temp) + (t + (let ((value (encode-value-if-immediate tn))) + (if (integerp value) + (constantize value) + value))))))) (unless (eq (tn-kind count) :unused) (inst mov count (fixnumize nvals))))) @@ -115,33 +122,15 @@ ;;; defining a new stack frame. (define-vop (%more-arg-values) (:args (context :scs (descriptor-reg any-reg) :target src) - (skip :scs (any-reg immediate)) (num :scs (any-reg) :target loop-index)) - (:arg-types * positive-fixnum positive-fixnum) + (:arg-types * positive-fixnum) (:temporary (:sc any-reg :offset rsi-offset :from (:argument 0)) src) (:temporary (:sc descriptor-reg :offset rax-offset) temp) (:temporary (:sc unsigned-reg :offset rcx-offset :from (:argument 2)) loop-index) (:results (start :scs (any-reg)) (count :scs (any-reg))) (:generator 20 - (sc-case skip - (immediate - (if (zerop (tn-value skip)) - (move src context) - (inst lea src (ea (- (* (tn-value skip) n-word-bytes)) context)))) - (any-reg - (cond ((= word-shift n-fixnum-tag-bits) - (move src context) - (inst sub src skip)) - (t - ;; TODO: Reducing CALL-ARGUMENTS-LIMIT to something reasonable to - ;; allow DWORD ops without it looking like a bug would make sense. - ;; With a stack size of about 2MB, the limit is absurd anyway. - (inst neg skip) - (inst lea src - (ea context skip (ash 1 (- word-shift n-fixnum-tag-bits)))) - (inst neg skip))))) - + (move src context) (unless (eq (tn-kind count) :unused) (move count num)) (if (location= loop-index num) diff --git a/src/compiler/x86-64/vm.lisp b/src/compiler/x86-64/vm.lisp index f85d03de27..b78eb9b1a1 100644 --- a/src/compiler/x86-64/vm.lisp +++ b/src/compiler/x86-64/vm.lisp @@ -13,6 +13,80 @@ ;;;; register specs +;;; Observe that [R12 + displacement] needs an extra byte of encoding in +;;; certain addressing modes, as does [R13 + index] +;;; 49895B08 MOV [R11+8], RBX +;;; 49895C2408 MOV [R12+8], RBX +;;; 49895D08 MOV [R13+8], RBX +;;; 49891C03 MOV [R11+RAX], RBX +;;; 49891C04 MOV [R12+RAX], RBX +;;; 49895C0500 MOV [R13+RAX], RBX +;;; This is because 12 and 13 are equal-mod-8 to 4 and 5, the indices of RSP +;;; and RBP respectively, which have different behaviors in the ModRegR/M byte. +;;; So due to lack of perfectly orthogonal encodings, it would be slightly +;;; beneficial to hint to the register allocator that it should pick registers +;;; 12 and 13 only when all other registers are unavailable. +;;; And you might think that it should "work" simply to list the usable offsets +;;; in the SC in the order in which they should be chosen when the register +;;; allocator needs to pick the next available register, but unfortunately +;;; it does not work to do that, because it uses bitmaps from which to pick, +;;; and not an ordered list. + +;;; A register that's never used by the code generator, and can therefore +;;; be used as an assembly temporary in cases where a VOP :TEMPORARY can't +;;; be used. +;;; This is only enabled for certain build configurations that need +;;; a scratch register in various random places. +#-ubsan (eval-when (:compile-toplevel :load-toplevel :execute) + (defconstant global-temp-reg nil)) +#+ubsan (progn (define-symbol-macro temp-reg-tn r11-tn) + (defconstant global-temp-reg 11)) + +#+gs-seg +(progn + ;; There is no permanent THREAD-TN. There are a few problems in trying + ;; cleverly to make PSEUDO-ATOMIC agnostic of whether you're using a global + ;; THREAD-TN or a local one (a global symbol macro vs. a let binding) + ;; 1) ECL seems to think that it is an error to LET bind a global symbol macro. + ;; > (define-symbol-macro thread-tn 'wat) + ;; > (defun f (&optional (thread-tn thread-tn)) (format t "Hi: ~a~%" thread-tn)) + ;; > (compile'f) + ;; ;;; Error: + ;; ;;; * The constant THREAD-TN is being bound. + ;; 2) It actually doesn't completely work completely anyway, + ;; because pseudo-atomic needs to know not to use a segment override, + ;; and TNs don't indicate a memory segment. + ;; While the second problem could be solved, the first can't, + ;; and it's not clear to me whether ECL is wrong to say it's an error, + ;; or SBCL is remiss in choosing not to style-warn (which would annoy me + ;; for that reason). + ;; So we wire the thread structure to r15 within some vops when convenient. + ;; Wiring to r15 is not strictly necessary, but I want to see if sb-aprof + ;; can be made to work slightly easier regardless of #+gs-seg. + ;; And with 15 being the highest register number, it is the least likely + ;; to be picked by the register allocator for anything else. + ;; Additionally I'd like to have an optimization pass that avoids reloading + ;; r15 when consecutive allocation sequences occur in straight-line code. + (define-symbol-macro thread-segment-reg :gs) + (define-symbol-macro thread-reg nil)) +#-gs-seg +(progn + (define-symbol-macro thread-segment-reg :cs) + ;; r13 is preferable to r12 because 12 is an alias of 4 in ModRegRM, which + ;; implies use of a SIB byte with no index register for fixed displacement. + (define-symbol-macro thread-reg 13) + (define-symbol-macro thread-tn r13-tn)) + +;;; Kludge needed for decoding internal error args - we assume that the +;;; shadow memory is pointed to by this register (RAX). +(defconstant msan-temp-reg-number 0) + +;;; The encoding anomaly for r12 makes it a perfect choice for the card table base. +;;; It will never be used with a constant displacement. +(define-symbol-macro card-table-reg 12) +(define-symbol-macro gc-card-table-reg-tn r12-tn) +(define-symbol-macro card-index-mask (make-fixup nil :gc-barrier)) + (macrolet ((defreg (name offset size) (declare (ignore size)) `(eval-when (:compile-toplevel :load-toplevel :execute) @@ -45,8 +119,9 @@ array)))) (defglobal ,offsets-list (remove-if (lambda (x) - (member x `(,r11-offset ; temp reg - ,r13-offset ; thread base + (member x `(,global-temp-reg ; if there is one + ,thread-reg ; if using a GPR + ,card-table-reg ,rsp-offset ,rbp-offset))) (loop for i below 16 collect i)))))) @@ -54,7 +129,7 @@ (define-gprs t *qword-regs* +qword-register-names+ #("RAX" "RCX" "RDX" "RBX" "RSP" "RBP" "RSI" "RDI" "R8" "R9" "R10" "R11" "R12" "R13" "R14" "R15")) - (define-gprs t *dword-regs* +dword-register-names+ + (define-gprs nil *dword-regs* +dword-register-names+ #("EAX" "ECX" "EDX" "EBX" "ESP" "EBP" "ESI" "EDI" "R8D" "R9D" "R10D" "R11D" "R12D" "R13D" "R14D" "R15D")) (define-gprs nil *word-regs* +word-register-names+ @@ -99,7 +174,8 @@ #-win32 (defregset *c-call-register-arg-offsets* rdi rsi rdx rcx r8 r9) #+win32 - (defregset *c-call-register-arg-offsets* rcx rdx r8 r9)) + (defregset *c-call-register-arg-offsets* rcx rdx r8 r9) + (defregset *descriptor-args* rdx rdi rsi rbx rcx r8 r9 r10 r14 r15)) ;;;; SB definitions @@ -274,9 +350,9 @@ :constant-scs (single-sse-immediate) :save-p t :alternate-scs (single-sse-stack)) - #+avx2 - (avx2-reg float-registers - :locations #.*float-regs*) + (ymm-reg float-registers :locations #.*float-regs*) + ;; These next 3 should probably be named to YMM-{INT,SINGLE,DOUBLE}-REG + ;; but I think there are 3rd-party libraries that expect these names. #+sb-simd-pack-256 (int-avx2-reg float-registers :locations #.*float-regs* @@ -315,7 +391,7 @@ (defparameter *oword-sc-names* '(sse-reg int-sse-reg single-sse-reg double-sse-reg int-sse-stack single-sse-stack double-sse-stack)) #+sb-simd-pack-256 -(defparameter *hword-sc-names* '(avx2-reg int-avx2-reg single-avx2-reg double-avx2-reg +(defparameter *hword-sc-names* '(ymm-reg int-avx2-reg single-avx2-reg double-avx2-reg int-avx2-stack single-avx2-stack double-avx2-stack)) ) ; EVAL-WHEN (!define-storage-classes @@ -377,11 +453,6 @@ (and (tn-p thing) (eq (sb-name (sc-sb (tn-sc thing))) 'stack))) -;; A register that's never used by the code generator, and can therefore -;; be used as an assembly temporary in cases where a VOP :TEMPORARY can't -;; be used. -(define-symbol-macro temp-reg-tn r11-tn) - ;;; TNs for registers used to pass arguments ;;; This can't be a DEFCONSTANT-EQX, for a similar reason to above, but worse. ;;; Among the problems, RECEIVE-UNKNOWN-VALUES uses (FIRST *REGISTER-ARG-TNS*) @@ -393,15 +464,11 @@ (symbol-value (symbolicate register-arg-name "-TN"))) *register-arg-names*)) -;; r13 is preferable to r12 because 12 is an alias of 4 in ModRegRM, which -;; implies use of a SIB byte with no index register for fixed displacement. -(define-symbol-macro thread-base-tn r13-tn) - ;;; If value can be represented as an immediate constant, then return ;;; the appropriate SC number, otherwise return NIL. (defun immediate-constant-sc (value) (typecase value - ((or (integer #.sb-xc:most-negative-fixnum #.sb-xc:most-positive-fixnum) + ((or (integer #.most-negative-fixnum #.most-positive-fixnum) character) immediate-sc-number) (symbol ; Symbols in static and immobile space are immediate @@ -419,14 +486,14 @@ ;; is used to determine whether it's immediate. #+(and (not sb-xc-host) immobile-space (not immobile-symbols)) (or (logbitp +initial-core-symbol-bit+ (get-header-data value)) - (and (sb-c::core-object-p sb-c::*compile-object*) - (immobile-space-obj-p value))) + (locally (declare (notinline sb-c::producing-fasl-file)) + (and (not (sb-c::producing-fasl-file)) + (immobile-space-obj-p value)))) (static-symbol-p value)) immediate-sc-number)) - #+immobile-space - (layout - immediate-sc-number) + #+metaspace (sb-vm:layout (bug "Can't reference layout as a constant")) + #+(and immobile-space (not metaspace)) (wrapper immediate-sc-number) (single-float (if (eql value $0f0) fp-single-zero-sc-number fp-single-immediate-sc-number)) (double-float @@ -463,8 +530,8 @@ (symbol (if (static-symbol-p val) (+ nil-value (static-symbol-offset val)) (make-fixup val :immobile-symbol))) - #+immobile-space - (layout + #+(and immobile-space (not metaspace)) + (wrapper (make-fixup val :layout)) (character (if tag (logior (ash (char-code val) n-widetag-bits) @@ -506,7 +573,16 @@ (sb (sb-name (sc-sb sc))) (offset (tn-offset tn))) (ecase sb - (registers (reg-name (tn-reg tn))) + (registers + (concatenate 'string + (reg-name (tn-reg tn)) + (case (sc-name (tn-sc tn)) + (descriptor-reg "(d)") + (any-reg "(a)") + (unsigned-reg "(u)") + (signed-reg "(s)") + (sap-reg "(p)") + (t "(?)")))) (float-registers (format nil "FLOAT~D" offset)) (stack (format nil "S~D" offset)) (constant (format nil "Const~D" offset)) @@ -542,4 +618,15 @@ (t (values :default nil))))) -(defparameter *register-names* +qword-register-names+) +(defvar *register-names* +qword-register-names+) + +(defmacro unbound-marker-bits () + (logior (+ sb-vm:static-space-start #x100) unbound-marker-widetag)) + +;;; See WRITE-FUNINSTANCE-PROLOGUE in x86-64-vm. +;;; There are 4 bytes available in the imm32 operand of a dummy MOV instruction. +;;; (It's a valid instruction on the theory that illegal opcodes might cause +;;; the decode stage in the CPU to behave suboptimally) +(defmacro compact-fsc-instance-hash (fin) + `(sap-ref-32 (int-sap (get-lisp-obj-address ,fin)) + (+ (ash 3 word-shift) 4 (- fun-pointer-lowtag)))) diff --git a/src/compiler/x86/alloc.lisp b/src/compiler/x86/alloc.lisp index fa1c5cadac..54b417855c 100644 --- a/src/compiler/x86/alloc.lisp +++ b/src/compiler/x86/alloc.lisp @@ -75,23 +75,21 @@ #+(and sb-thread win32) (scratch-tn (pop scratch-tns)) #+(and sb-thread win32) (swap-tn (pop scratch-tns)) (free-pointer - ;; thread->alloc_region.free_pointer + ;; thread->mixed_tlab.free_pointer (make-ea :dword :base (or #+(and sb-thread win32) scratch-tn) :disp - #+sb-thread (* n-word-bytes thread-alloc-region-slot) - #-sb-thread (+ static-space-start - (ash vector-data-offset word-shift)))) + #+sb-thread (* n-word-bytes thread-mixed-tlab-slot) + #-sb-thread mixed-region)) (end-addr - ;; thread->alloc_region.end_addr + ;; thread->mixed_tlab.end_addr (make-ea :dword :base (or #+(and sb-thread win32) scratch-tn) :disp - #+sb-thread (* n-word-bytes (1+ thread-alloc-region-slot)) - #-sb-thread (+ static-space-start - (ash (1+ vector-data-offset) word-shift))))) + #+sb-thread (* n-word-bytes (1+ thread-mixed-tlab-slot)) + #-sb-thread (+ mixed-region n-word-bytes)))) (unless (and (tn-p size) (location= alloc-tn size)) (inst mov alloc-tn size)) #+(and sb-thread win32) @@ -170,7 +168,7 @@ (allocation-inline type alloc-tn size)) (t (allocation-notinline type alloc-tn size))) - (when (and lowtag (not dynamic-extent)) + (when (and lowtag (/= lowtag 0) (not dynamic-extent)) ;; This is dumb, it should be an ADD or an OR, but a better solution ;; would be to pass lowtag into the allocation-inline function so that ;; for a fixed size we don't emit code such as "SUB r, 8 ; ADD r, 3". @@ -182,30 +180,23 @@ ;;; RESULT-TN. (defun alloc-other (result-tn widetag size node &optional stack-allocate-p) (pseudo-atomic (:elide-if stack-allocate-p) - (allocation nil (pad-data-block size) other-pointer-lowtag + (allocation nil (* (pad-data-block size) + #+bignum-assertions (if (eql widetag bignum-widetag) 2 1)) + other-pointer-lowtag node stack-allocate-p result-tn) (storew (compute-object-header size widetag) result-tn 0 other-pointer-lowtag))) ;;;; CONS, LIST and LIST* -(define-vop (list-or-list*) - (:args (things :more t)) +(define-vop (list) + (:args (things :more t :scs (descriptor-reg any-reg control-stack))) (:temporary (:sc unsigned-reg) ptr temp) (:temporary (:sc unsigned-reg :to (:result 0) :target result) res) - (:info num) + (:info star cons-cells) (:results (result :scs (descriptor-reg))) - (:variant-vars star) - (:policy :safe) (:node-var node) (:generator 0 - (cond ((zerop num) - ;; (move result nil-value) - (inst mov result nil-value)) - ((and star (= num 1)) - (move result (tn-ref-tn things))) - (t - (macrolet - ((store-car (tn list &optional (slot cons-car-slot)) + (macrolet ((store-car (tn list &optional (slot cons-car-slot)) `(let ((reg (sc-case ,tn ((any-reg descriptor-reg) ,tn) @@ -213,9 +204,8 @@ (move temp ,tn) temp)))) (storew reg ,list ,slot list-pointer-lowtag)))) - (let ((cons-cells (if star (1- num) num)) - (stack-allocate-p (node-stack-allocate-p node))) - (pseudo-atomic (:elide-if stack-allocate-p) + (let ((stack-allocate-p (node-stack-allocate-p node))) + (pseudo-atomic (:elide-if stack-allocate-p) (allocation 'list (* (pad-data-block cons-size) cons-cells) list-pointer-lowtag node stack-allocate-p res) (move ptr res) @@ -233,13 +223,7 @@ (storew nil-value ptr cons-cdr-slot list-pointer-lowtag))) (aver (null (tn-ref-across things))))) - (move result res)))))) - -(define-vop (list list-or-list*) - (:variant nil)) - -(define-vop (list* list-or-list*) - (:variant t)) + (move result res)))) ;;;; special-purpose inline allocators @@ -249,12 +233,18 @@ (length :scs (any-reg immediate)) (words :scs (any-reg immediate))) (:results (result :scs (descriptor-reg) :from :load)) - (:arg-types positive-fixnum - positive-fixnum - positive-fixnum) + (:arg-types positive-fixnum positive-fixnum positive-fixnum) (:policy :fast-safe) (:node-var node) (:generator 100 + (flet ((store-widetag (value ptr slot lowtag) + (inst mov (object-slot-ea + ptr slot lowtag + (typecase value + ((unsigned-byte 8) :byte) + ((unsigned-byte 16) :word) + (t :dword))) + value))) (let ((size (sc-case words (immediate (logandc2 (+ (fixnumize (tn-value words)) @@ -272,7 +262,6 @@ (allocation nil size other-pointer-lowtag node nil result) (sc-case type (immediate - (aver (typep (tn-value type) '(unsigned-byte 9))) (store-widetag (tn-value type) result 0 other-pointer-lowtag)) (t (storew type result 0 other-pointer-lowtag))) @@ -287,7 +276,7 @@ (storew fixnum-length result vector-length-slot other-pointer-lowtag))))) (t - (storew length result vector-length-slot other-pointer-lowtag))))))) + (storew length result vector-length-slot other-pointer-lowtag)))))))) (define-vop (allocate-vector-on-stack) (:args (type :scs (unsigned-reg immediate) :to :save) @@ -300,7 +289,6 @@ (:arg-types positive-fixnum positive-fixnum positive-fixnum) - (:translate allocate-vector) (:policy :fast-safe) (:generator 100 (inst lea result (make-ea :byte :base words :disp @@ -318,7 +306,7 @@ (sc-case type (immediate (aver (typep (tn-value type) '(unsigned-byte 8))) - (store-widetag (tn-value type) result 0 other-pointer-lowtag)) + (storew (tn-value type) result 0 other-pointer-lowtag)) (t (storew type result 0 other-pointer-lowtag))) (storew length result vector-length-slot other-pointer-lowtag) @@ -384,39 +372,16 @@ (inst mov result (make-fixup 'funcallable-instance-tramp :assembly-routine)))) (define-vop (fixed-alloc) - (:args) (:info name words type lowtag stack-allocate-p) (:ignore name) (:results (result :scs (descriptor-reg))) (:node-var node) (:generator 50 - ;; We special case the allocation of conses, because they're - ;; extremely common and because the pseudo-atomic sequence on x86 - ;; is relatively heavyweight. However, if the user asks for top - ;; speed, we accomodate him. The primary reason that we don't - ;; also check for (< SPEED SPACE) is because we want the space - ;; savings that these out-of-line allocation routines bring whilst - ;; compiling SBCL itself. --njf, 2006-07-08 - (if (and (not stack-allocate-p) - (= lowtag list-pointer-lowtag) (policy node (< speed 3))) - (let ((dst - ;; FIXME: out-of-line dx-allocation - #.(loop for offset in *dword-regs* - collect `(,offset - ',(intern (format nil "ALLOCATE-CONS-TO-~A" - (svref +dword-register-names+ - offset)))) into cases - finally (return `(case (tn-offset result) - ,@cases))))) - (aver (null type)) - (inst call (make-fixup dst :assembly-routine))) - (pseudo-atomic (:elide-if stack-allocate-p) - (allocation nil (pad-data-block words) lowtag node stack-allocate-p result) - (when type - (storew (logior (ash (1- words) (length-field-shift type)) type) - result - 0 - lowtag)))))) + (pseudo-atomic (:elide-if stack-allocate-p) + (let ((nbytes (* (pad-data-block words) + #+bignum-assertions (if (eql type bignum-widetag) 2 1)))) + (allocation nil nbytes lowtag node stack-allocate-p result)) + (storew (compute-object-header words type) result 0 lowtag)))) (define-vop (var-alloc) (:args (extra :scs (any-reg))) @@ -436,6 +401,7 @@ (make-ea :dword :base header :disp (+ (ash -2 (length-field-shift type)) type))) (inst and bytes (lognot lowtag-mask)) + #+bignum-assertions (when (eql type bignum-widetag) (inst shl bytes 1)) ; use 2x space (pseudo-atomic (:elide-if stack-allocate-p) (allocation nil bytes lowtag node stack-allocate-p result) (storew header result 0 lowtag)))) diff --git a/src/compiler/x86/arith.lisp b/src/compiler/x86/arith.lisp index a0f2758351..0437e32228 100644 --- a/src/compiler/x86/arith.lisp +++ b/src/compiler/x86/arith.lisp @@ -1351,30 +1351,23 @@ constant shift greater than word length"))) ;;;; 32-bit logical operations ;;; Only the lower 5 bits of the shift amount are significant. -(define-vop (shift-towards-someplace) - (:policy :fast-safe) - (:args (num :scs (unsigned-reg) :target r) - (amount :scs (signed-reg) :target ecx)) - (:arg-types unsigned-num tagged-num) - (:temporary (:sc signed-reg :offset ecx-offset :from (:argument 1)) ecx) - (:results (r :scs (unsigned-reg) :from (:argument 0))) - (:result-types unsigned-num)) - -(define-vop (shift-towards-start shift-towards-someplace) - (:translate shift-towards-start) - (:note "SHIFT-TOWARDS-START") - (:generator 1 - (move r num) - (move ecx amount) - (inst shr r :cl))) - -(define-vop (shift-towards-end shift-towards-someplace) - (:translate shift-towards-end) - (:note "SHIFT-TOWARDS-END") - (:generator 1 - (move r num) - (move ecx amount) - (inst shl r :cl))) +(macrolet ((define (translate operation) + `(define-vop () + (:translate ,translate) + (:note ,(string translate)) + (:policy :fast-safe) + (:args (num :scs (unsigned-reg) :target r) + (amount :scs (signed-reg) :target ecx)) + (:arg-types unsigned-num tagged-num) + (:temporary (:sc signed-reg :offset ecx-offset :from (:argument 1)) ecx) + (:results (r :scs (unsigned-reg) :from (:argument 0))) + (:result-types unsigned-num) + (:generator 1 + (move r num) + (move ecx amount) + (inst ,operation r :cl))))) + (define shift-towards-start shr) + (define shift-towards-end shl)) ;;;; Modular functions (defmacro define-mod-binop ((name prototype) function) @@ -1472,7 +1465,7 @@ constant shift greater than word length"))) fast-ash-left/unsigned=>unsigned)) (deftransform ash-left-mod32 ((integer count) ((unsigned-byte 32) (unsigned-byte 5))) - (when (sb-c::constant-lvar-p count) + (when (sb-c:constant-lvar-p count) (sb-c::give-up-ir1-transform)) '(%primitive fast-ash-left-mod32/unsigned=>unsigned integer count)) @@ -1485,7 +1478,7 @@ constant shift greater than word length"))) fast-ash-left/fixnum=>fixnum)) (deftransform ash-left-modfx ((integer count) (fixnum (unsigned-byte 5))) - (when (sb-c::constant-lvar-p count) + (when (sb-c:constant-lvar-p count) (sb-c::give-up-ir1-transform)) '(%primitive fast-ash-left-modfx/fixnum=>fixnum integer count)) @@ -1595,13 +1588,17 @@ constant shift greater than word length"))) (:translate sb-bignum:%bignum-set-length) (:policy :fast-safe)) +#-bignum-assertions ; %BIGNUM-ref is an inline function if compiling with assertions (define-full-reffer bignum-ref * bignum-digits-offset other-pointer-lowtag (unsigned-reg) unsigned-num sb-bignum:%bignum-ref) -(define-full-reffer+offset bignum-ref-with-offset * +#-bignum-assertions ; does not get called if compiling with assertions +(define-full-reffer+addend bignum-ref-with-offset * bignum-digits-offset other-pointer-lowtag (unsigned-reg) unsigned-num sb-bignum:%bignum-ref-with-offset) (define-full-setter bignum-set * bignum-digits-offset other-pointer-lowtag - (unsigned-reg) unsigned-num sb-bignum:%bignum-set) + (unsigned-reg) unsigned-num + #+bignum-assertions sb-bignum:%%bignum-set + #-bignum-assertions sb-bignum:%bignum-set) (define-vop (digit-0-or-plus) (:translate sb-bignum:%digit-0-or-plusp) @@ -1633,7 +1630,7 @@ constant shift greater than word length"))) (move temp c) (inst neg temp) ; Set the carry flag to 0 if c=0 else to 1 (inst adc result b) - (inst set carry-temp :c) + (inst set :c carry-temp) (inst and carry-temp 1) (move carry carry-temp))) diff --git a/src/compiler/x86/array.lisp b/src/compiler/x86/array.lisp index 7e996f8fac..26b532ac5f 100644 --- a/src/compiler/x86/array.lisp +++ b/src/compiler/x86/array.lisp @@ -29,34 +29,15 @@ :disp (+ (* array-dimensions-offset n-word-bytes) lowtag-mask))) (inst and bytes (lognot lowtag-mask)) - (inst lea header (make-ea :dword :base rank - :disp (fixnumize (1- array-dimensions-offset)))) - (inst shl header n-widetag-bits) + ;; rank 1 is stored as 0, 2 is stored as 1, ... + (inst lea header (make-ea :dword :disp (fixnumize -1) :base rank)) + (inst and header (fixnumize array-rank-mask)) + (inst shl header array-rank-position) (inst or header type) - (inst shr header 2) + (inst shr header n-fixnum-tag-bits) (pseudo-atomic () (allocation nil bytes other-pointer-lowtag node nil result) (storew header result 0 other-pointer-lowtag)))) - -(define-vop (make-array-header/c) - (:translate make-array-header) - (:policy :fast-safe) - (:arg-types (:constant t) (:constant t)) - (:info type rank) - (:results (result :scs (descriptor-reg))) - (:node-var node) - (:generator 12 - (let* ((header-size (+ rank - (1- array-dimensions-offset))) - (bytes (logandc2 (+ (* (1+ header-size) n-word-bytes) - lowtag-mask) - lowtag-mask)) - (header (logior (ash header-size - n-widetag-bits) - type))) - (pseudo-atomic () - (allocation nil bytes other-pointer-lowtag node nil result) - (storew header result 0 other-pointer-lowtag))))) ;;;; additional accessors and setters for the array header (define-full-reffer %array-dimension * @@ -67,16 +48,42 @@ array-dimensions-offset other-pointer-lowtag (any-reg) positive-fixnum %set-array-dimension) -(define-vop (array-rank-vop) +(symbol-macrolet ((rank-disp + (- (/ array-rank-position n-byte-bits) other-pointer-lowtag))) +(define-vop () (:translate %array-rank) (:policy :fast-safe) (:args (x :scs (descriptor-reg))) (:results (res :scs (unsigned-reg))) (:result-types positive-fixnum) (:generator 6 - (loadw res x 0 other-pointer-lowtag) - (inst shr res n-widetag-bits) - (inst sub res (1- array-dimensions-offset)))) + (inst movzx res (make-ea :byte :disp rank-disp :base x)) + ;; not all registers have an addressable low byte, so the simple trick + ;; used on x86-64 of adding 1 to the 8-bit register won't work. + (inst inc res) + (inst and res array-rank-mask))) + +(define-vop () + (:translate %array-rank=) + (:policy :fast-safe) + (:args (array :scs (descriptor-reg))) + (:info rank) + (:arg-types * (:constant t)) + (:conditional :e) + (:generator 2 + (inst cmp (make-ea :byte :disp rank-disp :base array) (encode-array-rank rank)))) + +(define-vop (array-vectorp simple-type-predicate) + ;; SIMPLE-TYPE-PREDICATE says that it takes stack locations, but that's no good. + (:args (array :scs (any-reg descriptor-reg))) + (:translate vectorp) + (:conditional :z) + (:info) + (:guard (lambda (node) + (let ((arg (car (sb-c::combination-args node)))) + (csubtypep (sb-c::lvar-type arg) (specifier-type 'array))))) + (:generator 1 + (inst cmp (make-ea :byte :disp rank-disp :base array) (encode-array-rank 1))))) ;;;; bounds checking routine (define-vop (check-bound) @@ -158,17 +165,46 @@ ;;;; accessors/setters -;;; variants built on top of WORD-INDEX-REF, etc. I.e., those vectors -;;; whose elements are represented in integer registers and are built -;;; out of 8, 16, or 32 bit elements. +;;; Ancestors +(define-vop (dvref) + (:translate data-vector-ref-with-offset) + (:policy :fast-safe)) +(define-vop (dvset) + (:translate data-vector-set-with-offset) + (:policy :fast-safe)) + +;;; variants which affect an entire lispword-sized value. +(defmacro define-full-setter+addend (name type offset lowtag scs el-type) + `(progn + (define-vop (,name dvset) + (:policy :fast-safe) + (:args (object :scs (descriptor-reg)) + (index :scs (any-reg immediate)) + (value :scs ,scs)) + (:info addend) + (:arg-types ,type tagged-num + (:constant (constant-displacement ,lowtag n-word-bytes ,offset)) ,el-type) + (:generator 4 + (sc-case index + (immediate + (inst mov (make-ea :dword :base object + :disp (- (* (+ ,offset (tn-value index) addend) + n-word-bytes) + ,lowtag)) + value)) + (t + (inst mov (make-ea :dword :base object :index index + :disp (- (* (+ ,offset addend) + n-word-bytes) ,lowtag)) + value))))))) (macrolet ((def-full-data-vector-frobs (type element-type &rest scs) `(progn - (define-full-reffer+offset ,(symbolicate "DATA-VECTOR-REF-WITH-OFFSET/" type) + (define-full-reffer+addend ,(symbolicate "DATA-VECTOR-REF-WITH-OFFSET/" type) ,type vector-data-offset other-pointer-lowtag ,scs ,element-type data-vector-ref-with-offset) - (define-full-setter+offset ,(symbolicate "DATA-VECTOR-SET-WITH-OFFSET/" type) + (define-full-setter+addend ,(symbolicate "DATA-VECTOR-SET-WITH-OFFSET/" type) ,type vector-data-offset other-pointer-lowtag ,scs - ,element-type data-vector-set-with-offset)))) + ,element-type)))) (def-full-data-vector-frobs simple-vector * descriptor-reg any-reg) (def-full-data-vector-frobs simple-array-unsigned-byte-32 unsigned-num unsigned-reg) @@ -189,14 +225,12 @@ ;;;; integer vectors whose elements are smaller than a byte, i.e., ;;;; bit, 2-bit, and 4-bit vectors -(define-vop (data-vector-ref-with-offset/simple-bit-vector-c) - (:translate data-vector-ref-with-offset) - (:policy :fast-safe) +(define-vop (data-vector-ref-with-offset/simple-bit-vector-c dvref) (:args (object :scs (descriptor-reg))) (:arg-types simple-bit-vector (:constant (integer 0 #x7fffffff)) (:constant (integer 0 0))) - (:info index offset) - (:ignore offset) + (:info index addend) + (:ignore addend) (:results (result :scs (any-reg))) (:result-types positive-fixnum) (:generator 3 @@ -213,13 +247,11 @@ (inst shl result (- right-shift)))))) (inst and result (fixnumize 1)))) -(define-vop (data-vector-ref-with-offset/simple-bit-vector) - (:translate data-vector-ref-with-offset) - (:policy :fast-safe) +(define-vop (data-vector-ref-with-offset/simple-bit-vector dvref) (:args (object :scs (descriptor-reg)) (index :scs (unsigned-reg))) - (:info offset) - (:ignore offset) + (:info addend) + (:ignore addend) (:arg-types simple-bit-vector positive-fixnum (:constant (integer 0 0))) (:results (result :scs (any-reg))) (:result-types positive-fixnum) @@ -236,19 +268,16 @@ (bit-shift (1- (integer-length elements-per-word)))) `(progn ,@(unless (= bits 1) - `((define-vop (,(symbolicate 'data-vector-ref-with-offset/ type)) - (:note "inline array access") - (:translate data-vector-ref-with-offset) - (:policy :fast-safe) + `((define-vop (,(symbolicate 'data-vector-ref-with-offset/ type) dvref) (:args (object :scs (descriptor-reg)) (index :scs (unsigned-reg))) - (:info offset) + (:info addend) + (:ignore addend) (:arg-types ,type positive-fixnum (:constant (integer 0 0))) (:results (result :scs (unsigned-reg) :from (:argument 0))) (:result-types positive-fixnum) (:temporary (:sc unsigned-reg :offset ecx-offset) ecx) (:generator 20 - (aver (zerop offset)) (move ecx index) (inst shr ecx ,bit-shift) (inst mov result (make-ea-for-vector-data object :index ecx)) @@ -263,16 +292,14 @@ (inst shl ecx ,(1- (integer-length bits))))) (inst shr result :cl) (inst and result ,(1- (ash 1 bits))))) - (define-vop (,(symbolicate 'data-vector-ref-with-offset/ type "-C")) - (:translate data-vector-ref-with-offset) - (:policy :fast-safe) + (define-vop (,(symbolicate 'data-vector-ref-with-offset/ type "-C") dvref) (:args (object :scs (descriptor-reg))) (:arg-types ,type (:constant index) (:constant (integer 0 0))) - (:info index offset) + (:info index addend) + (:ignore addend) (:results (result :scs (unsigned-reg))) (:result-types positive-fixnum) (:generator 15 - (aver (zerop offset)) (multiple-value-bind (word extra) (floor index ,elements-per-word) (loadw result object (+ word vector-data-offset) other-pointer-lowtag) @@ -280,23 +307,18 @@ (inst shr result (* extra ,bits))) (unless (= extra ,(1- elements-per-word)) (inst and result ,(1- (ash 1 bits))))))))) - (define-vop (,(symbolicate 'data-vector-set-with-offset/ type)) - (:note "inline array store") - (:translate data-vector-set-with-offset) - (:policy :fast-safe) + (define-vop (,(symbolicate 'data-vector-set-with-offset/ type) dvset) (:args (object :scs (descriptor-reg) :to (:argument 2)) (index :scs (unsigned-reg) :target ecx) - (value :scs (unsigned-reg immediate) :target result)) - (:info offset) + (value :scs (unsigned-reg immediate))) + (:info addend) + (:ignore addend) (:arg-types ,type positive-fixnum (:constant (integer 0 0)) positive-fixnum) - (:results (result :scs (unsigned-reg))) - (:result-types positive-fixnum) (:temporary (:sc unsigned-reg) word-index) (:temporary (:sc unsigned-reg) old) (:temporary (:sc unsigned-reg :offset ecx-offset :from (:argument 1)) ecx) (:generator 25 - (aver (zerop offset)) (move word-index index) (inst shr word-index ,bit-shift) (inst mov old (make-ea-for-vector-data object :index word-index)) @@ -321,25 +343,16 @@ (inst or old value))) (inst rol old :cl) (inst mov (make-ea-for-vector-data object :index word-index) - old) - (sc-case value - (immediate - (inst mov result (tn-value value))) - (unsigned-reg - (move result value))))) - (define-vop (,(symbolicate 'data-vector-set-with-offset/ type "-C")) - (:translate data-vector-set-with-offset) - (:policy :fast-safe) + old))) + (define-vop (,(symbolicate 'data-vector-set-with-offset/ type "-C") dvset) (:args (object :scs (descriptor-reg)) - (value :scs (unsigned-reg immediate) :target result)) + (value :scs (unsigned-reg immediate))) (:arg-types ,type (:constant index) (:constant (integer 0 0)) positive-fixnum) - (:info index offset) - (:results (result :scs (unsigned-reg))) - (:result-types positive-fixnum) + (:info index addend) + (:ignore addend) (:temporary (:sc unsigned-reg :to (:result 0)) old) (:generator 20 - (aver (zerop offset)) (multiple-value-bind (word extra) (floor index ,elements-per-word) (loadw old object (+ word vector-data-offset) other-pointer-lowtag) (sc-case value @@ -360,12 +373,7 @@ (inst or old value) (unless (zerop shift) (inst rol old shift))))) - (storew old object (+ word vector-data-offset) other-pointer-lowtag) - (sc-case value - (immediate - (inst mov result (tn-value value))) - (unsigned-reg - (move result value)))))))))) + (storew old object (+ word vector-data-offset) other-pointer-lowtag)))))))) (def-small-data-vector-frobs simple-bit-vector 1) (def-small-data-vector-frobs simple-array-unsigned-byte-2 2) (def-small-data-vector-frobs simple-array-unsigned-byte-4 4)) @@ -388,13 +396,10 @@ complex-offset) other-pointer-lowtag))))) -(define-vop (data-vector-ref-with-offset/simple-array-single-float) - (:note "inline array access") - (:translate data-vector-ref-with-offset) - (:policy :fast-safe) +(define-vop (data-vector-ref-with-offset/simple-array-single-float dvref) (:args (object :scs (descriptor-reg)) (index :scs (any-reg immediate))) - (:info offset) + (:info addend) (:arg-types simple-array-single-float tagged-num (:constant (constant-displacement other-pointer-lowtag 4 vector-data-offset))) @@ -402,49 +407,31 @@ (:result-types single-float) (:generator 5 (with-empty-tn@fp-top(value) - (inst fld (float-ref-ea object index offset 4))))) + (inst fld (float-ref-ea object index addend 4))))) -(define-vop (data-vector-set-with-offset/simple-array-single-float) - (:note "inline array store") - (:translate data-vector-set-with-offset) - (:policy :fast-safe) +(define-vop (data-vector-set-with-offset/simple-array-single-float dvset) (:args (object :scs (descriptor-reg)) (index :scs (any-reg immediate)) - (value :scs (single-reg) :target result)) - (:info offset) + (value :scs (single-reg))) + (:info addend) (:arg-types simple-array-single-float tagged-num (:constant (constant-displacement other-pointer-lowtag 4 vector-data-offset)) single-float) - (:results (result :scs (single-reg))) - (:result-types single-float) (:generator 5 (cond ((zerop (tn-offset value)) ;; Value is in ST0. - (inst fst (float-ref-ea object index offset 4)) - (unless (zerop (tn-offset result)) - ;; Value is in ST0 but not result. - (inst fst result))) + (inst fst (float-ref-ea object index addend 4))) (t ;; Value is not in ST0. (inst fxch value) - (inst fst (float-ref-ea object index offset 4)) - (cond ((zerop (tn-offset result)) - ;; The result is in ST0. - (inst fst value)) - (t - ;; Neither value or result are in ST0 - (unless (location= value result) - (inst fst result)) - (inst fxch value))))))) - -(define-vop (data-vector-ref-with-offset/simple-array-double-float) - (:note "inline array access") - (:translate data-vector-ref-with-offset) - (:policy :fast-safe) + (inst fst (float-ref-ea object index addend 4)) + (inst fxch value))))) + +(define-vop (data-vector-ref-with-offset/simple-array-double-float dvref) (:args (object :scs (descriptor-reg)) (index :scs (any-reg immediate))) - (:info offset) + (:info addend) (:arg-types simple-array-double-float tagged-num (:constant (constant-displacement other-pointer-lowtag @@ -453,51 +440,33 @@ (:result-types double-float) (:generator 7 (with-empty-tn@fp-top(value) - (inst fldd (float-ref-ea object index offset 8 :scale 2))))) + (inst fldd (float-ref-ea object index addend 8 :scale 2))))) -(define-vop (data-vector-set-with-offset/simple-array-double-float) - (:note "inline array store") - (:translate data-vector-set-with-offset) - (:policy :fast-safe) +(define-vop (data-vector-set-with-offset/simple-array-double-float dvset) (:args (object :scs (descriptor-reg)) (index :scs (any-reg immediate)) - (value :scs (double-reg) :target result)) - (:info offset) + (value :scs (double-reg))) + (:info addend) (:arg-types simple-array-double-float tagged-num (:constant (constant-displacement other-pointer-lowtag 8 vector-data-offset)) double-float) - (:results (result :scs (double-reg))) - (:result-types double-float) (:generator 20 (cond ((zerop (tn-offset value)) ;; Value is in ST0. - (inst fstd (float-ref-ea object index offset 8 :scale 2)) - (unless (zerop (tn-offset result)) - ;; Value is in ST0 but not result. - (inst fstd result))) + (inst fstd (float-ref-ea object index addend 8 :scale 2))) (t ;; Value is not in ST0. (inst fxch value) - (inst fstd (float-ref-ea object index offset 8 :scale 2)) - (cond ((zerop (tn-offset result)) - ;; The result is in ST0. - (inst fstd value)) - (t - ;; Neither value or result are in ST0 - (unless (location= value result) - (inst fstd result)) - (inst fxch value))))))) + (inst fstd (float-ref-ea object index addend 8 :scale 2)) + (inst fxch value))))) ;;; complex float variants -(define-vop (data-vector-ref-with-offset/simple-array-complex-single-float) - (:note "inline array access") - (:translate data-vector-ref-with-offset) - (:policy :fast-safe) +(define-vop (data-vector-ref-with-offset/simple-array-complex-single-float dvref) (:args (object :scs (descriptor-reg)) (index :scs (any-reg immediate))) - (:info offset) + (:info addend) (:arg-types simple-array-complex-single-float tagged-num (:constant (constant-displacement other-pointer-lowtag 8 vector-data-offset))) @@ -506,64 +475,42 @@ (:generator 5 (let ((real-tn (complex-single-reg-real-tn value))) (with-empty-tn@fp-top (real-tn) - (inst fld (float-ref-ea object index offset 8 :scale 2)))) + (inst fld (float-ref-ea object index addend 8 :scale 2)))) (let ((imag-tn (complex-single-reg-imag-tn value))) (with-empty-tn@fp-top (imag-tn) ;; FIXME - (inst fld (float-ref-ea object index offset 8 + (inst fld (float-ref-ea object index addend 8 :scale 2 :complex-offset 4)))))) -(define-vop (data-vector-set-with-offset/simple-array-complex-single-float) - (:note "inline array store") - (:translate data-vector-set-with-offset) - (:policy :fast-safe) +(define-vop (data-vector-set-with-offset/simple-array-complex-single-float dvset) (:args (object :scs (descriptor-reg)) (index :scs (any-reg immediate)) - (value :scs (complex-single-reg) :target result)) - (:info offset) + (value :scs (complex-single-reg))) + (:info addend) (:arg-types simple-array-complex-single-float tagged-num (:constant (constant-displacement other-pointer-lowtag 8 vector-data-offset)) complex-single-float) - (:results (result :scs (complex-single-reg))) - (:result-types complex-single-float) (:generator 5 - (let ((value-real (complex-single-reg-real-tn value)) - (result-real (complex-single-reg-real-tn result))) + (let ((value-real (complex-single-reg-real-tn value))) (cond ((zerop (tn-offset value-real)) ;; Value is in ST0. - (inst fst (float-ref-ea object index offset 8 :scale 2)) - (unless (zerop (tn-offset result-real)) - ;; Value is in ST0 but not result. - (inst fst result-real))) + (inst fst (float-ref-ea object index addend 8 :scale 2))) (t ;; Value is not in ST0. (inst fxch value-real) - (inst fst (float-ref-ea object index offset 8 :scale 2)) - (cond ((zerop (tn-offset result-real)) - ;; The result is in ST0. - (inst fst value-real)) - (t - ;; Neither value or result are in ST0 - (unless (location= value-real result-real) - (inst fst result-real)) - (inst fxch value-real)))))) - (let ((value-imag (complex-single-reg-imag-tn value)) - (result-imag (complex-single-reg-imag-tn result))) + (inst fst (float-ref-ea object index addend 8 :scale 2)) + (inst fxch value-real)))) + (let ((value-imag (complex-single-reg-imag-tn value))) (inst fxch value-imag) - (inst fst (float-ref-ea object index offset 8 + (inst fst (float-ref-ea object index addend 8 :scale 2 :complex-offset 4)) - (unless (location= value-imag result-imag) - (inst fst result-imag)) (inst fxch value-imag)))) -(define-vop (data-vector-ref-with-offset/simple-array-complex-double-float) - (:note "inline array access") - (:translate data-vector-ref-with-offset) - (:policy :fast-safe) +(define-vop (data-vector-ref-with-offset/simple-array-complex-double-float dvref) (:args (object :scs (descriptor-reg)) (index :scs (any-reg immediate))) - (:info offset) + (:info addend) (:arg-types simple-array-complex-double-float tagged-num (:constant (constant-displacement other-pointer-lowtag 16 vector-data-offset))) @@ -572,56 +519,37 @@ (:generator 7 (let ((real-tn (complex-double-reg-real-tn value))) (with-empty-tn@fp-top (real-tn) - (inst fldd (float-ref-ea object index offset 16 :scale 4))) + (inst fldd (float-ref-ea object index addend 16 :scale 4))) (let ((imag-tn (complex-double-reg-imag-tn value))) (with-empty-tn@fp-top (imag-tn) - (inst fldd (float-ref-ea object index offset 16 + (inst fldd (float-ref-ea object index addend 16 :scale 4 :complex-offset 8))))))) -(define-vop (data-vector-set-with-offset/simple-array-complex-double-float) - (:note "inline array store") - (:translate data-vector-set-with-offset) - (:policy :fast-safe) +(define-vop (data-vector-set-with-offset/simple-array-complex-double-float dvset) (:args (object :scs (descriptor-reg)) (index :scs (any-reg immediate)) - (value :scs (complex-double-reg) :target result)) - (:info offset) + (value :scs (complex-double-reg))) + (:info addend) (:arg-types simple-array-complex-double-float tagged-num (:constant (constant-displacement other-pointer-lowtag 16 vector-data-offset)) complex-double-float) - (:results (result :scs (complex-double-reg))) - (:result-types complex-double-float) (:generator 20 - (let ((value-real (complex-double-reg-real-tn value)) - (result-real (complex-double-reg-real-tn result))) + (let ((value-real (complex-double-reg-real-tn value))) (cond ((zerop (tn-offset value-real)) ;; Value is in ST0. - (inst fstd (float-ref-ea object index offset 16 - :scale 4)) - (unless (zerop (tn-offset result-real)) - ;; Value is in ST0 but not result. - (inst fstd result-real))) + (inst fstd (float-ref-ea object index addend 16 + :scale 4))) (t ;; Value is not in ST0. (inst fxch value-real) - (inst fstd (float-ref-ea object index offset 16 + (inst fstd (float-ref-ea object index addend 16 :scale 4)) - (cond ((zerop (tn-offset result-real)) - ;; The result is in ST0. - (inst fstd value-real)) - (t - ;; Neither value or result are in ST0 - (unless (location= value-real result-real) - (inst fstd result-real)) - (inst fxch value-real)))))) - (let ((value-imag (complex-double-reg-imag-tn value)) - (result-imag (complex-double-reg-imag-tn result))) + (inst fxch value-real)))) + (let ((value-imag (complex-double-reg-imag-tn value))) (inst fxch value-imag) - (inst fstd (float-ref-ea object index offset 16 + (inst fstd (float-ref-ea object index addend 16 :scale 4 :complex-offset 8)) - (unless (location= value-imag result-imag) - (inst fstd result-imag)) (inst fxch value-imag)))) @@ -630,12 +558,10 @@ (macrolet ((define-data-vector-frobs (ptype element-type ref-inst 8-bit-tns-p &rest scs) `(progn - (define-vop (,(symbolicate "DATA-VECTOR-REF-WITH-OFFSET/" ptype)) - (:translate data-vector-ref-with-offset) - (:policy :fast-safe) + (define-vop (,(symbolicate "DATA-VECTOR-REF-WITH-OFFSET/" ptype) dvref) (:args (object :scs (descriptor-reg)) (index :scs (signed-reg immediate))) - (:info offset) + (:info addend) (:arg-types ,ptype tagged-num (:constant (constant-displacement other-pointer-lowtag 1 vector-data-offset))) @@ -646,48 +572,41 @@ (immediate (inst ,ref-inst value (make-ea-for-vector-data object :size :byte - :offset (+ (tn-value index) offset)))) + :offset (+ (tn-value index) addend)))) (t (inst ,ref-inst value (make-ea-for-vector-data object :size :byte - :index index :offset offset)))))) - (define-vop (,(symbolicate "DATA-VECTOR-SET-WITH-OFFSET/" ptype)) - (:translate data-vector-set-with-offset) - (:policy :fast-safe) + :index index :offset addend)))))) + (define-vop (,(symbolicate "DATA-VECTOR-SET-WITH-OFFSET/" ptype) dvset) (:args (object :scs (descriptor-reg) :to (:eval 0)) (index :scs (signed-reg immediate) :to (:eval 0)) (value :scs ,scs ,@(unless 8-bit-tns-p '(:target eax)))) - (:info offset) + (:info addend) (:arg-types ,ptype tagged-num (:constant (constant-displacement other-pointer-lowtag 1 vector-data-offset)) ,element-type) ,@(unless 8-bit-tns-p - '((:temporary (:sc unsigned-reg :offset eax-offset :target result + '((:temporary (:sc unsigned-reg :offset eax-offset :from (:argument 2) :to (:result 0)) eax))) - (:results (result :scs ,scs)) - (:result-types ,element-type) (:generator 5 ,@(unless 8-bit-tns-p '((move eax value))) (sc-case index (immediate (inst mov (make-ea-for-vector-data - object :size :byte :offset (+ (tn-value index) offset)) + object :size :byte :offset (+ (tn-value index) addend)) ,(if 8-bit-tns-p 'value 'al-tn))) (t (inst mov (make-ea-for-vector-data object :size :byte - :index index :offset offset) + :index index :offset addend) ,(if 8-bit-tns-p 'value - 'al-tn)))) - (move result ,(if 8-bit-tns-p - 'value - 'eax))))))) + 'al-tn))))))))) (define-data-vector-frobs simple-array-unsigned-byte-7 positive-fixnum movzx nil unsigned-reg signed-reg) (define-data-vector-frobs simple-array-unsigned-byte-8 positive-fixnum @@ -701,12 +620,10 @@ ;;; {un,}signed-byte-16 (macrolet ((define-data-vector-frobs (ptype element-type ref-inst &rest scs) `(progn - (define-vop (,(symbolicate "DATA-VECTOR-REF-WITH-OFFSET/" ptype)) - (:translate data-vector-ref-with-offset) - (:policy :fast-safe) + (define-vop (,(symbolicate "DATA-VECTOR-REF-WITH-OFFSET/" ptype) dvref) (:args (object :scs (descriptor-reg)) (index :scs (signed-reg immediate))) - (:info offset) + (:info addend) (:arg-types ,ptype tagged-num (:constant (constant-displacement other-pointer-lowtag 2 vector-data-offset))) @@ -717,39 +634,34 @@ (immediate (inst ,ref-inst value (make-ea-for-vector-data object :size :word - :offset (+ (tn-value index) offset)))) + :offset (+ (tn-value index) addend)))) (t (inst ,ref-inst value (make-ea-for-vector-data object :size :word - :index index :offset offset)))))) - (define-vop (,(symbolicate "DATA-VECTOR-SET-WITH-OFFSET/" ptype)) - (:translate data-vector-set-with-offset) - (:policy :fast-safe) + :index index :offset addend)))))) + (define-vop (,(symbolicate "DATA-VECTOR-SET-WITH-OFFSET/" ptype) dvset) (:args (object :scs (descriptor-reg) :to (:eval 0)) (index :scs (signed-reg immediate) :to (:eval 0)) - (value :scs ,scs :target eax)) - (:info offset) + (value :scs ,scs)) + (:info addend) (:arg-types ,ptype tagged-num (:constant (constant-displacement other-pointer-lowtag 2 vector-data-offset)) ,element-type) - (:temporary (:sc unsigned-reg :offset eax-offset :target result + (:temporary (:sc unsigned-reg :offset eax-offset :from (:argument 2) :to (:result 0)) eax) - (:results (result :scs ,scs)) - (:result-types ,element-type) (:generator 5 (move eax value) (sc-case index (immediate (inst mov (make-ea-for-vector-data - object :size :word :offset (+ (tn-value index) offset)) + object :size :word :offset (+ (tn-value index) addend)) ax-tn)) (t (inst mov (make-ea-for-vector-data object :size :word - :index index :offset offset) - ax-tn))) - (move result eax)))))) + :index index :offset addend) + ax-tn)))))))) (define-data-vector-frobs simple-array-unsigned-byte-15 positive-fixnum movzx unsigned-reg signed-reg) (define-data-vector-frobs simple-array-unsigned-byte-16 positive-fixnum diff --git a/src/compiler/x86/c-call.lisp b/src/compiler/x86/c-call.lisp index fb4648bc27..4b8cca1b1c 100644 --- a/src/compiler/x86/c-call.lisp +++ b/src/compiler/x86/c-call.lisp @@ -130,8 +130,8 @@ (deftransform %alien-funcall ((function type &rest args) * * :node node) - (aver (sb-c::constant-lvar-p type)) - (let* ((type (sb-c::lvar-value type)) + (aver (sb-c:constant-lvar-p type)) + (let* ((type (sb-c:lvar-value type)) (env (sb-c::node-lexenv node)) (arg-types (alien-fun-type-arg-types type)) (result-type (alien-fun-type-result-type type))) @@ -379,17 +379,6 @@ delta))) (load-symbol-value result *alien-stack-pointer*))) -;;; not strictly part of the c-call convention, but needed for the -;;; WITH-PINNED-OBJECTS macro used for "locking down" lisp objects so -;;; that GC won't move them while foreign functions go to work. -(define-vop (touch-object) - (:translate touch-object) - (:args (object)) - (:ignore object) - (:policy :fast-safe) - (:arg-types t) - (:generator 0)) - #-sb-xc-host (defun alien-callback-accessor-form (type sp offset) `(deref (sap-alien (sap+ ,sp ,offset) (* ,type)))) diff --git a/src/compiler/x86/call.lisp b/src/compiler/x86/call.lisp index f4a46f5c73..c1c83a7dee 100644 --- a/src/compiler/x86/call.lisp +++ b/src/compiler/x86/call.lisp @@ -14,29 +14,9 @@ (defconstant arg-count-sc (make-sc+offset any-reg-sc-number ecx-offset)) (defconstant closure-sc (make-sc+offset descriptor-reg-sc-number eax-offset)) -;;; Make a passing location TN for a local call return PC. -;;; -;;; Always wire the return PC location to the stack in its standard -;;; location. -(defun make-return-pc-passing-location (standard) - (declare (ignore standard)) - (make-wired-tn (primitive-type-or-lose 'system-area-pointer) - sap-stack-sc-number return-pc-save-offset)) - (defconstant return-pc-passing-offset (make-sc+offset sap-stack-sc-number return-pc-save-offset)) -;;; This is similar to MAKE-RETURN-PC-PASSING-LOCATION, but makes a -;;; location to pass OLD-FP in. -;;; -;;; This is wired in both the standard and the local-call conventions, -;;; because we want to be able to assume it's always there. Besides, -;;; the x86 doesn't have enough registers to really make it profitable -;;; to pass it in a register. -(defun make-old-fp-passing-location () - (make-wired-tn *fixnum-primitive-type* control-stack-sc-number - ocfp-save-offset)) - (defconstant old-fp-passing-offset (make-sc+offset control-stack-sc-number ocfp-save-offset)) @@ -46,16 +26,17 @@ ;;; ;;; Without using a save-tn - which does not make much sense if it is ;;; wired to the stack? -(defun make-old-fp-save-location (physenv) - (physenv-debug-live-tn (make-wired-tn *fixnum-primitive-type* - control-stack-sc-number - ocfp-save-offset) - physenv)) -(defun make-return-pc-save-location (physenv) - (physenv-debug-live-tn - (make-wired-tn (primitive-type-or-lose 'system-area-pointer) - sap-stack-sc-number return-pc-save-offset) - physenv)) +(defun make-old-fp-save-location () + (let ((tn (make-wired-tn *fixnum-primitive-type* + control-stack-sc-number + ocfp-save-offset))) + (setf (tn-kind tn) :environment) + tn)) +(defun make-return-pc-save-location () + (let ((tn (make-wired-tn (primitive-type-or-lose 'system-area-pointer) + sap-stack-sc-number return-pc-save-offset))) + (setf (tn-kind tn) :environment) + tn)) ;;; Make a TN for the standard argument count passing location. We only ;;; need to make the standard location, since a count is never passed when we @@ -1337,49 +1318,56 @@ (define-vop () (:translate %listify-rest-args) (:policy :safe) - (:args (context :scs (descriptor-reg) :target src) + ;; CONTEXT is used throughout the copying loop + (:args (context :scs (descriptor-reg) :to :save) (count :scs (any-reg) :target ecx)) (:arg-types * tagged-num) - (:temporary (:sc unsigned-reg :offset esi-offset :from (:argument 0)) src) + ;; The only advantage to specifying ECX here is that JECXZ can be used + ;; in one place, and then only in the unlikely scenario that CONTEXT is not + ;; in ECX. If it was, SHL sets/clears the Z flag, but LEA doesn't. + ;; Not much of an advantage, but why not. (:temporary (:sc unsigned-reg :offset ecx-offset :from (:argument 1)) ecx) - (:temporary (:sc unsigned-reg :offset eax-offset) eax) - (:temporary (:sc unsigned-reg) dst) + ;; Note that DST conflicts with RESULT because we use both as temps + (:temporary (:sc unsigned-reg ) value dst) (:results (result :scs (descriptor-reg))) (:node-var node) (:generator 20 - (let ((enter (gen-label)) - (loop (gen-label)) + (let ((loop (gen-label)) (done (gen-label)) (stack-allocate-p (node-stack-allocate-p node))) - (move src context) - (move ecx count) - ;; Check to see whether there are no args, and just return NIL if so. + ;; Compute the number of bytes to allocate + (let ((shift (- (1+ word-shift) n-fixnum-tag-bits))) + (if (location= count ecx) + (inst shl ecx shift) + (inst lea ecx (make-ea :dword :index count :scale (ash 1 shift))))) + ;; Setup for the CDR of the last cons (or the entire result) being NIL. (inst mov result nil-value) - (inst test ecx ecx) - (inst jmp :z done) - (inst lea dst (make-ea :dword :base ecx :index ecx)) + (inst jecxz DONE) (pseudo-atomic (:elide-if stack-allocate-p) - (allocation 'list dst list-pointer-lowtag node stack-allocate-p dst) - ;; Set up the result. - (move result dst) - ;; Jump into the middle of the loop, 'cause that's where we want - ;; to start. - (inst jmp enter) - (emit-label loop) - ;; Compute a pointer to the next cons. - (inst add dst (* cons-size n-word-bytes)) - ;; Store a pointer to this cons in the CDR of the previous cons. - (storew dst dst -1 list-pointer-lowtag) - (emit-label enter) - ;; Grab one value and stash it in the car of this cons. - (inst mov eax (make-ea :dword :base src)) - (inst sub src n-word-bytes) - (storew eax dst 0 list-pointer-lowtag) - ;; Go back for more. - (inst sub ecx n-word-bytes) - (inst jmp :nz loop) - ;; NIL out the last cons. - (storew nil-value dst 1 list-pointer-lowtag)) + ;; Produce an untagged pointer into DST + (allocation 'list ecx 0 node stack-allocate-p dst) + ;; Recalculate DST as a tagged pointer to the last cons + (inst lea dst (make-ea :dword :disp (- list-pointer-lowtag (* cons-size n-word-bytes)) + :base dst :index ecx)) + (inst shr ecx (1+ word-shift)) ; convert bytes to number of cells + ;; The rightmost arguments are at lower addresses. + ;; Start by indexing the last argument + (inst neg ecx) + (emit-label LOOP) + ;; Grab one value and store into this cons. Use ECX as an index into the + ;; vector of values in CONTEXT, but add 4 because CONTEXT points exactly at + ;; the 0th value, which means that the index is 1 word too low. + ;; (It's -1 if there is exactly 1 value, instead of 0, and so on) + (inst mov value (make-ea :dword :disp 4 :base context :index ecx :scale 4)) + ;; RESULT began as NIL which gives the correct value for the CDR in the final cons. + ;; Subsequently it points to each cons just populated, which is correct all the way + ;; up to and including the final result. + (storew result dst cons-cdr-slot list-pointer-lowtag) + (storew value dst cons-car-slot list-pointer-lowtag) + (inst mov result dst) ; preserve the value to put in the CDR of the preceding cons + (inst sub dst (* cons-size n-word-bytes)) ; get the preceding cons + (inst inc ecx) + (inst jmp :nz loop)) (emit-label done)))) ;;; Return the location and size of the &MORE arg glob created by diff --git a/src/compiler/x86/cell.lisp b/src/compiler/x86/cell.lisp index 86a56dd5ca..64c348f9ac 100644 --- a/src/compiler/x86/cell.lisp +++ b/src/compiler/x86/cell.lisp @@ -21,37 +21,16 @@ (:generator 1 (loadw result object offset lowtag))) +;;; This vop is magical in (at least) 2 ways: +;;; 1. it is always selected by name (in ir2-convert-setter or -setfer) +;;; 2. the ir2 converter makes it return a value despite absence of :results (define-vop (set-slot) (:args (object :scs (descriptor-reg)) (value :scs (descriptor-reg any-reg immediate))) (:info name offset lowtag) - (:results) - (:generator 1 - (cond ((emit-code-page-write-barrier-p name) - (inst push (encode-value-if-immediate value)) - (inst push offset) - (inst push object) - (when (= lowtag fun-pointer-lowtag) - (inst push eax-tn) ; spill eax to use as a temp - (loadw eax-tn object 0 fun-pointer-lowtag) - (inst shr eax-tn n-widetag-bits) - ;; increment index by number of boxed words - (inst add (make-ea :dword :base esp-tn :disp 8) eax-tn) - ;; and compute the code pointer from the fun pointer - (inst lea eax-tn - (make-ea :dword :index eax-tn :scale n-word-bytes - :disp (- fun-pointer-lowtag other-pointer-lowtag))) - (inst sub (make-ea :dword :base esp-tn :disp 4) eax-tn) - (inst pop eax-tn)) ; restore - (inst call (make-fixup 'code-header-set :assembly-routine))) - (t - (storew (encode-value-if-immediate value) object offset lowtag))))) - -(define-vop (init-slot set-slot) - (:info name dx-p offset lowtag) + (:ignore name) (:generator 1 - (storew (encode-value-if-immediate value) object offset lowtag)) - (:ignore name dx-p)) + (storew (encode-value-if-immediate value) object offset lowtag))) (define-vop (compare-and-swap-slot) (:args (object :scs (descriptor-reg) :to :eval) @@ -96,7 +75,7 @@ ;; Thread-local area, no LOCK needed. (with-tls-ea (EA :base tls :base-already-live-p t) (inst cmpxchg EA new :maybe-fs)) - (inst cmp eax no-tls-value-marker-widetag) + (inst cmp eax no-tls-value-marker) (inst jmp :ne check) (move eax old)) (inst cmpxchg (make-ea :dword :base symbol @@ -114,11 +93,11 @@ (define-vop (fast-symbol-global-value cell-ref) (:variant symbol-value-slot other-pointer-lowtag) (:policy :fast) - (:translate sym-global-val)) + (:translate symbol-global-value)) (define-vop (symbol-global-value) (:policy :fast-safe) - (:translate sym-global-val) + (:translate symbol-global-value) (:args (object :scs (descriptor-reg) :to (:result 1))) (:results (value :scs (descriptor-reg any-reg))) (:vop-var vop) @@ -140,7 +119,7 @@ (done (gen-label))) (loadw tls symbol symbol-tls-index-slot other-pointer-lowtag) (with-tls-ea (EA :base tls :base-already-live-p t) - (inst cmp EA no-tls-value-marker-widetag :maybe-fs) + (inst cmp EA no-tls-value-marker :maybe-fs) (inst jmp :z global-val) (inst mov EA value :maybe-fs)) (inst jmp done) @@ -148,10 +127,9 @@ (storew value symbol symbol-value-slot other-pointer-lowtag) (emit-label done)))) - ;; With Symbol-Value, we check that the value isn't the trap object. So - ;; Symbol-Value of NIL is NIL. + ;; With Symbol-Value, we check that the value isn't the trap object. (define-vop (symbol-value) - (:translate symeval) + (:translate symbol-value) (:policy :fast-safe) (:args (object :scs (descriptor-reg) :to (:result 1))) (:results (value :scs (descriptor-reg any-reg))) @@ -164,7 +142,7 @@ (loadw value object symbol-tls-index-slot other-pointer-lowtag) (with-tls-ea (EA :base value :base-already-live-p t) (inst mov value EA :maybe-fs)) - (inst cmp value no-tls-value-marker-widetag) + (inst cmp value no-tls-value-marker) (inst jmp :ne check-unbound-label) (loadw value object symbol-value-slot other-pointer-lowtag) (emit-label check-unbound-label) @@ -179,13 +157,13 @@ ;; unbound", which is used in the implementation of COPY-SYMBOL. -- ;; CSR, 2003-04-22 (:policy :fast) - (:translate symeval) + (:translate symbol-value) (:generator 8 (let ((ret-lab (gen-label))) (loadw value object symbol-tls-index-slot other-pointer-lowtag) (with-tls-ea (EA :base value :base-already-live-p t) (inst mov value EA :maybe-fs)) - (inst cmp value no-tls-value-marker-widetag) + (inst cmp value no-tls-value-marker) (inst jmp :ne ret-lab) (loadw value object symbol-value-slot other-pointer-lowtag) (emit-label ret-lab))))) @@ -193,9 +171,9 @@ #-sb-thread (progn (define-vop (symbol-value symbol-global-value) - (:translate symeval)) + (:translate symbol-value)) (define-vop (fast-symbol-value fast-symbol-global-value) - (:translate symeval)) + (:translate symbol-value)) (define-vop (set %set-symbol-global-value))) #+sb-thread @@ -210,7 +188,7 @@ (loadw value object symbol-tls-index-slot other-pointer-lowtag) (with-tls-ea (EA :base value :base-already-live-p t) (inst mov value EA :maybe-fs)) - (inst cmp value no-tls-value-marker-widetag) + (inst cmp value no-tls-value-marker) (inst jmp :ne check-unbound-label) (loadw value object symbol-value-slot other-pointer-lowtag) (emit-label check-unbound-label) @@ -234,13 +212,15 @@ (:args (symbol :scs (descriptor-reg))) (:results (res :scs (any-reg))) (:result-types positive-fixnum) + (:args-var args) (:generator 2 ;; The symbol-hash slot of NIL holds NIL because it is also the ;; car slot, so we have to strip off the two low bits to make sure ;; it is a fixnum. The lowtag selection magic that is required to ;; ensure this is explained in the comment in objdef.lisp (loadw res symbol symbol-hash-slot other-pointer-lowtag) - (inst and res (lognot #b11)))) + (unless (not-nil-tn-ref-p args) + (inst and res (lognot #b11))))) ;;;; fdefinition (FDEFN) objects @@ -281,13 +261,11 @@ (define-vop (fdefn-makunbound) (:policy :fast-safe) (:translate fdefn-makunbound) - (:args (fdefn :scs (descriptor-reg) :target result)) - (:results (result :scs (descriptor-reg))) + (:args (fdefn :scs (descriptor-reg))) (:generator 38 (storew nil-value fdefn fdefn-fun-slot other-pointer-lowtag) (storew (make-fixup 'undefined-tramp :assembly-routine) - fdefn fdefn-raw-addr-slot other-pointer-lowtag) - (move result fdefn))) + fdefn fdefn-raw-addr-slot other-pointer-lowtag))) ;;;; binding and unbinding @@ -412,9 +390,8 @@ closure-info-offset fun-pointer-lowtag (any-reg descriptor-reg) * %closure-index-ref) -(define-full-setter set-funcallable-instance-info * - funcallable-instance-info-offset fun-pointer-lowtag - (any-reg descriptor-reg) * %set-funcallable-instance-info) +(define-full-setter %closure-index-set * closure-info-offset fun-pointer-lowtag + (any-reg descriptor-reg) * %closure-index-set) (define-full-reffer funcallable-instance-info * funcallable-instance-info-offset fun-pointer-lowtag @@ -477,6 +454,11 @@ (define-full-compare-and-swap %raw-instance-cas/word instance instance-slots-offset instance-pointer-lowtag (unsigned-reg) unsigned-num %raw-instance-cas/word) + +(define-full-compare-and-swap %raw-instance-cas/signed-word instance + instance-slots-offset instance-pointer-lowtag + (signed-reg) signed-num %raw-instance-cas/signed-word) + ;;;; code object frobbing @@ -487,17 +469,32 @@ (:translate code-header-set) (:policy :fast-safe) (:args (object :scs (descriptor-reg)) - (index :scs (unsigned-reg)) - (value :scs (any-reg descriptor-reg) :target result)) - (:arg-types * unsigned-num *) - (:results (result :scs (any-reg descriptor-reg))) - (:result-types *) + (index :scs (any-reg)) + (value :scs (any-reg descriptor-reg))) + (:arg-types * tagged-num *) + (:temporary (:sc unsigned-reg) table card) (:generator 10 - (inst push value) - (inst push index) - (inst push object) - (inst call (make-fixup 'code-header-set :assembly-routine)) - (move result value))) + ;; Find card mark table base. If the linkage entry contained the + ;; *value* of gc_card_mark pointer, we could eliminate one deref. + ;; Putting it in a statc symbol would also work, but this vop is + ;; not performance-critical by any stretch of the imagination. + (inst mov table (make-ea :dword :disp (make-fixup "gc_card_mark" :foreign-dataref))) + (inst mov table (make-ea :dword :base table)) + (pseudo-atomic () + ;; Compute card mark index and touch the mark byte + (inst mov card object) + (inst shr card gencgc-card-shift) + (inst and card (make-fixup nil :gc-barrier)) + (inst mov (make-ea :byte :base table :index card) 1) ; CARD_MARKED + ;; set 'written' flag in the code header + ;; this doesn't need to use :LOCK because the only other writer + ;; would be a GCing thread, but we're pseudo-atomic here. + ;; If two threads actually did write the byte, then they would write + ;; the same value, and that works fine. + (inst or (make-ea :byte :base object :disp (- 3 other-pointer-lowtag)) #x40) + ;; store + (inst mov (make-ea :dword :base object :index index :disp (- other-pointer-lowtag)) + value)))) ;;;; raw instance slot accessors @@ -511,7 +508,7 @@ :disp (- (ash (+ (or imm-index 0) displacement instance-slots-offset) word-shift) instance-pointer-lowtag)))) -(define-vop (raw-instance-ref/word) +(define-vop () (:translate %raw-instance-ref/word) (:policy :fast-safe) (:args (object :scs (descriptor-reg)) (index :scs (any-reg immediate))) @@ -521,28 +518,16 @@ (:generator 5 (inst mov value (instance-slot-ea object index)))) -(define-vop (raw-instance-set/word) +(define-vop () (:translate %raw-instance-set/word) (:policy :fast-safe) (:args (object :scs (descriptor-reg)) (index :scs (any-reg immediate)) - (value :scs (unsigned-reg) :target result)) - (:arg-types * tagged-num unsigned-num) - (:results (result :scs (unsigned-reg))) - (:result-types unsigned-num) - (:generator 5 - (inst mov (instance-slot-ea object index) value) - (move result value))) - -(define-vop (raw-instance-init/word) - (:args (object :scs (descriptor-reg)) (value :scs (unsigned-reg))) - (:arg-types * unsigned-num) - (:info index) - (:generator 5 - (inst mov (instance-slot-ea object index) value))) + (:arg-types * tagged-num unsigned-num) + (:generator 5 (inst mov (instance-slot-ea object index) value))) -(define-vop (raw-instance-ref/signed-word) +(define-vop () (:translate %raw-instance-ref/signed-word) (:policy :fast-safe) (:args (object :scs (descriptor-reg)) (index :scs (any-reg immediate))) @@ -552,26 +537,14 @@ (:generator 5 (inst mov value (instance-slot-ea object index)))) -(define-vop (raw-instance-set/signed-word) +(define-vop () (:translate %raw-instance-set/signed-word) (:policy :fast-safe) (:args (object :scs (descriptor-reg)) (index :scs (any-reg immediate)) - (value :scs (signed-reg) :target result)) - (:arg-types * tagged-num signed-num) - (:results (result :scs (signed-reg))) - (:result-types signed-num) - (:generator 5 - (inst mov (instance-slot-ea object index) value) - (move result value))) - -(define-vop (raw-instance-init/signed-word) - (:args (object :scs (descriptor-reg)) (value :scs (signed-reg))) - (:arg-types * signed-num) - (:info index) - (:generator 5 - (inst mov (instance-slot-ea object index) value))) + (:arg-types * tagged-num signed-num) + (:generator 5 (inst mov (instance-slot-ea object index) value))) (define-vop (raw-instance-atomic-incf/word) (:translate %raw-instance-atomic-incf/word) @@ -586,7 +559,7 @@ (inst xadd (instance-slot-ea object index) diff :lock) (move result diff))) -(define-vop (raw-instance-ref/single) +(define-vop () (:translate %raw-instance-ref/single) (:policy :fast-safe) (:args (object :scs (descriptor-reg)) (index :scs (any-reg immediate))) @@ -597,40 +570,17 @@ (with-empty-tn@fp-top(value) (inst fld (instance-slot-ea object index))))) -(define-vop (raw-instance-set/single) +(define-vop () (:translate %raw-instance-set/single) (:policy :fast-safe) (:args (object :scs (descriptor-reg)) (index :scs (any-reg immediate)) - (value :scs (single-reg) :target result)) - (:arg-types * tagged-num single-float) - (:results (result :scs (single-reg))) - (:result-types single-float) - (:generator 5 - (unless (zerop (tn-offset value)) - (inst fxch value)) - (inst fst (instance-slot-ea object index)) - (cond - ((zerop (tn-offset value)) - (unless (zerop (tn-offset result)) - (inst fst result))) - ((zerop (tn-offset result)) - (inst fst value)) - (t - (unless (location= value result) - (inst fst result)) - (inst fxch value))))) - -(define-vop (raw-instance-init/single) - (:args (object :scs (descriptor-reg)) (value :scs (single-reg))) - (:arg-types * single-float) - (:info index) + (:arg-types * tagged-num single-float) (:generator 5 - (with-tn@fp-top (value) - (inst fst (instance-slot-ea object index))))) + (with-tn@fp-top (value) (inst fst (instance-slot-ea object index))))) -(define-vop (raw-instance-ref/double) +(define-vop () (:translate %raw-instance-ref/double) (:policy :fast-safe) (:args (object :scs (descriptor-reg)) (index :scs (any-reg immediate))) @@ -641,40 +591,17 @@ (with-empty-tn@fp-top(value) (inst fldd (instance-slot-ea object index))))) -(define-vop (raw-instance-set/double) +(define-vop () (:translate %raw-instance-set/double) (:policy :fast-safe) (:args (object :scs (descriptor-reg)) (index :scs (any-reg immediate)) - (value :scs (double-reg) :target result)) - (:arg-types * tagged-num double-float) - (:results (result :scs (double-reg))) - (:result-types double-float) - (:generator 5 - (unless (zerop (tn-offset value)) - (inst fxch value)) - (inst fstd (instance-slot-ea object index)) - (cond - ((zerop (tn-offset value)) - (unless (zerop (tn-offset result)) - (inst fstd result))) - ((zerop (tn-offset result)) - (inst fstd value)) - (t - (unless (location= value result) - (inst fstd result)) - (inst fxch value))))) - -(define-vop (raw-instance-init/double) - (:args (object :scs (descriptor-reg)) (value :scs (double-reg))) - (:arg-types * double-float) - (:info index) + (:arg-types * tagged-num double-float) (:generator 5 - (with-tn@fp-top (value) - (inst fstd (instance-slot-ea object index))))) + (with-tn@fp-top (value) (inst fstd (instance-slot-ea object index))))) -(define-vop (raw-instance-ref/complex-single) +(define-vop () (:translate %raw-instance-ref/complex-single) (:policy :fast-safe) (:args (object :scs (descriptor-reg)) @@ -690,58 +617,23 @@ (with-empty-tn@fp-top (imag-tn) (inst fld (instance-slot-ea object index 1)))))) -(define-vop (raw-instance-set/complex-single) +(define-vop () (:translate %raw-instance-set/complex-single) (:policy :fast-safe) (:args (object :scs (descriptor-reg)) (index :scs (any-reg immediate)) - (value :scs (complex-single-reg) :target result)) - (:arg-types * positive-fixnum complex-single-float) - (:results (result :scs (complex-single-reg))) - (:result-types complex-single-float) - (:generator 5 - (let ((value-real (complex-single-reg-real-tn value)) - (result-real (complex-single-reg-real-tn result))) - (cond ((zerop (tn-offset value-real)) - ;; Value is in ST0. - (inst fst (instance-slot-ea object index)) - (unless (zerop (tn-offset result-real)) - ;; Value is in ST0 but not result. - (inst fst result-real))) - (t - ;; Value is not in ST0. - (inst fxch value-real) - (inst fst (instance-slot-ea object index)) - (cond ((zerop (tn-offset result-real)) - ;; The result is in ST0. - (inst fst value-real)) - (t - ;; Neither value or result are in ST0 - (unless (location= value-real result-real) - (inst fst result-real)) - (inst fxch value-real)))))) - (let ((value-imag (complex-single-reg-imag-tn value)) - (result-imag (complex-single-reg-imag-tn result))) - (inst fxch value-imag) - (inst fst (instance-slot-ea object index 1)) - (unless (location= value-imag result-imag) - (inst fst result-imag)) - (inst fxch value-imag)))) - -(define-vop (raw-instance-init/complex-single) - (:args (object :scs (descriptor-reg)) (value :scs (complex-single-reg))) - (:arg-types * complex-single-float) - (:info index) + (:arg-types * positive-fixnum complex-single-float) (:generator 5 (let ((value-real (complex-single-reg-real-tn value))) (with-tn@fp-top (value-real) (inst fst (instance-slot-ea object index)))) (let ((value-imag (complex-single-reg-imag-tn value))) - (with-tn@fp-top (value-imag) - (inst fst (instance-slot-ea object index 1)))))) + (inst fxch value-imag) + (inst fst (instance-slot-ea object index 1)) + (inst fxch value-imag)))) -(define-vop (raw-instance-ref/complex-double) +(define-vop () (:translate %raw-instance-ref/complex-double) (:policy :fast-safe) (:args (object :scs (descriptor-reg)) @@ -757,56 +649,21 @@ (with-empty-tn@fp-top (imag-tn) (inst fldd (instance-slot-ea object index 2)))))) -(define-vop (raw-instance-set/complex-double) +(define-vop () (:translate %raw-instance-set/complex-double) (:policy :fast-safe) (:args (object :scs (descriptor-reg)) (index :scs (any-reg immediate)) - (value :scs (complex-double-reg) :target result)) - (:arg-types * positive-fixnum complex-double-float) - (:results (result :scs (complex-double-reg))) - (:result-types complex-double-float) - (:generator 20 - (let ((value-real (complex-double-reg-real-tn value)) - (result-real (complex-double-reg-real-tn result))) - (cond ((zerop (tn-offset value-real)) - ;; Value is in ST0. - (inst fstd (instance-slot-ea object index)) - (unless (zerop (tn-offset result-real)) - ;; Value is in ST0 but not result. - (inst fstd result-real))) - (t - ;; Value is not in ST0. - (inst fxch value-real) - (inst fstd (instance-slot-ea object index)) - (cond ((zerop (tn-offset result-real)) - ;; The result is in ST0. - (inst fstd value-real)) - (t - ;; Neither value or result are in ST0 - (unless (location= value-real result-real) - (inst fstd result-real)) - (inst fxch value-real)))))) - (let ((value-imag (complex-double-reg-imag-tn value)) - (result-imag (complex-double-reg-imag-tn result))) - (inst fxch value-imag) - (inst fstd (instance-slot-ea object index 2)) - (unless (location= value-imag result-imag) - (inst fstd result-imag)) - (inst fxch value-imag)))) - -(define-vop (raw-instance-init/complex-double) - (:args (object :scs (descriptor-reg)) (value :scs (complex-double-reg))) - (:arg-types * complex-double-float) - (:info index) + (:arg-types * positive-fixnum complex-double-float) (:generator 20 (let ((value-real (complex-double-reg-real-tn value))) (with-tn@fp-top (value-real) (inst fstd (instance-slot-ea object index)))) (let ((value-imag (complex-double-reg-imag-tn value))) - (with-tn@fp-top (value-imag) - (inst fstd (instance-slot-ea object index 2)))))) + (inst fxch value-imag) + (inst fstd (instance-slot-ea object index 2)) + (inst fxch value-imag)))) ;;;; diff --git a/src/compiler/x86/char.lisp b/src/compiler/x86/char.lisp index c04da3e737..5dfdaef453 100644 --- a/src/compiler/x86/char.lisp +++ b/src/compiler/x86/char.lisp @@ -185,7 +185,7 @@ (:policy :fast-safe) (:note "inline constant comparison") (:generator 2 - (inst cmp x (sb-xc:char-code y)))) + (inst cmp x (char-code y)))) (define-vop (fast-char=/character/c character-compare/c) (:translate char=) diff --git a/src/compiler/x86/debug.lisp b/src/compiler/x86/debug.lisp index 6d4b2576da..b2060df540 100644 --- a/src/compiler/x86/debug.lisp +++ b/src/compiler/x86/debug.lisp @@ -19,7 +19,7 @@ (:generator 1 (move res esp-tn))) -(define-vop () +(define-vop (current-fp-sap) (:translate current-fp) (:policy :fast-safe) (:results (res :scs (sap-reg sap-stack))) @@ -50,18 +50,15 @@ (:policy :fast-safe) (:args (sap :scs (sap-reg) :to :eval) (offset :scs (any-reg) :target temp) - (value :scs (descriptor-reg) :to :result :target result)) + (value :scs (descriptor-reg))) (:arg-types system-area-pointer positive-fixnum *) - (:temporary (:sc unsigned-reg :from (:argument 1) :to :result) temp) - (:results (result :scs (descriptor-reg))) - (:result-types *) + (:temporary (:sc unsigned-reg :from (:argument 1)) temp) (:generator 9 (move temp offset) (inst neg temp) (inst mov (make-ea :dword :base sap :disp (frame-byte-offset 0) :index temp) - value) - (move result value))) + value))) (define-vop () (:translate fun-code-header) diff --git a/src/compiler/x86/insts.lisp b/src/compiler/x86/insts.lisp index 908f5d3b09..d60865c635 100644 --- a/src/compiler/x86/insts.lisp +++ b/src/compiler/x86/insts.lisp @@ -14,7 +14,7 @@ (eval-when (:compile-toplevel :load-toplevel :execute) ;; Imports from this package into SB-VM - (import '(conditional-opcode + (import '(conditional-opcode negate-condition register-p ; FIXME: rename to GPR-P make-ea ea-disp width-bits) "SB-VM") ;; Imports from SB-VM into this package @@ -167,17 +167,19 @@ (:le . 14) (:ng . 14) (:nle . 15) (:g . 15)) #'equal) -(defconstant-eqx sb-vm::+condition-name-vec+ - #.(let ((vec (make-array 16 :initial-element nil))) - (dolist (cond +conditions+ vec) - (when (null (aref vec (cdr cond))) - (setf (aref vec (cdr cond)) (car cond))))) +(defconstant-eqx +condition-name-vec+ + (let ((vec (make-array 16 :initial-element nil))) + (dolist (cond +conditions+ vec) + (when (null (aref vec (cdr cond))) + (setf (aref vec (cdr cond)) (car cond))))) #'equalp) -(define-arg-type condition-code :printer sb-vm::+condition-name-vec+) +(define-arg-type condition-code :printer +condition-name-vec+) (defun conditional-opcode (condition) (cdr (assoc condition +conditions+ :test #'eq))) +(defun negate-condition (name) + (aref +condition-name-vec+ (logxor 1 (conditional-opcode name)))) ;;;; disassembler instruction formats @@ -244,11 +246,6 @@ (imm) ) -;;; Same as reg, but with direction bit -(define-instruction-format (reg-dir 8 :include reg) - (op :field (byte 3 5)) - (dir :field (byte 1 4))) - (define-instruction-format (reg-reg/mem 16 :default-printer `(:name :tab reg ", " reg/mem)) @@ -334,23 +331,6 @@ (op :field (byte 5 11)) (reg :field (byte 3 8) :type 'reg)) -;;; Same as reg/mem, but with a prefix of #b00001111 -(define-instruction-format (ext-reg/mem 24 - :default-printer '(:name :tab reg/mem)) - (prefix :field (byte 8 0) :value #b00001111) - (op :fields (list (byte 7 9) (byte 3 19))) - (width :field (byte 1 8) :type 'width) - (reg/mem :fields (list (byte 2 22) (byte 3 16)) - :type 'sized-reg/mem) - ;; optional fields - (imm)) - -(define-instruction-format (ext-reg/mem-imm 24 - :include ext-reg/mem - :default-printer - '(:name :tab reg/mem ", " imm)) - (imm :type 'imm-data)) - (define-instruction-format (ext-reg/mem-no-width+imm8 24 :include ext-reg/mem-no-width :default-printer @@ -375,17 +355,6 @@ (op :fields (list (byte 3 0) (byte 3 11))) (fp-reg :field (byte 3 8) :type 'fp-reg)) -;;; fp insn to/from fp reg, with the reversed source/destination flag. -(define-instruction-format (floating-point-fp-d 16 - :default-printer - `(:name :tab ,(swap-if 'd "ST0" ", " 'fp-reg))) - (prefix :field (byte 5 3) :value #b11011) - (suffix :field (byte 2 14) :value #b11) - (op :fields (list (byte 2 0) (byte 3 11))) - (d :field (byte 1 2)) - (fp-reg :field (byte 3 8) :type 'fp-reg)) - - ;;; (added by (?) pfw) ;;; fp no operand isns (define-instruction-format (floating-point-no 16 :default-printer '(:name)) @@ -862,11 +831,6 @@ (emit-byte segment #b11111111) (emit-ea segment src #b110)))))))) -(define-instruction pusha (segment) - (:printer byte ((op #b01100000))) - (:emitter - (emit-byte segment #b01100000))) - (define-instruction pop (segment dst) (:printer reg-no-width ((op #b01011))) (:printer reg/mem ((op '(#b1000111 #b000)) (width 1))) @@ -880,11 +844,6 @@ (emit-byte segment #b10001111) (emit-ea segment dst #b000)))))) -(define-instruction popa (segment) - (:printer byte ((op #b01100001))) - (:emitter - (emit-byte segment #b01100001))) - (define-instruction xchg (segment operand1 operand2) ;; Register with accumulator. (:printer reg-no-width ((op #b10010)) '(:name :tab accum ", " reg)) @@ -957,71 +916,35 @@ ;;;; flag control instructions -;;; CLC -- Clear Carry Flag. -(define-instruction clc (segment) - (:printer byte ((op #b11111000))) - (:emitter - (emit-byte segment #b11111000))) - -;;; CLD -- Clear Direction Flag. -(define-instruction cld (segment) - (:printer byte ((op #b11111100))) - (:emitter - (emit-byte segment #b11111100))) - -;;; CLI -- Clear Iterrupt Enable Flag. -(define-instruction cli (segment) - (:printer byte ((op #b11111010))) - (:emitter - (emit-byte segment #b11111010))) - -;;; CMC -- Complement Carry Flag. -(define-instruction cmc (segment) - (:printer byte ((op #b11110101))) - (:emitter - (emit-byte segment #b11110101))) - -;;; LAHF -- Load AH into flags. -(define-instruction lahf (segment) - (:printer byte ((op #b10011111))) - (:emitter - (emit-byte segment #b10011111))) - -;;; POPF -- Pop flags. -(define-instruction popf (segment) - (:printer byte ((op #b10011101))) - (:emitter - (emit-byte segment #b10011101))) - -;;; PUSHF -- push flags. -(define-instruction pushf (segment) - (:printer byte ((op #b10011100))) - (:emitter - (emit-byte segment #b10011100))) - -;;; SAHF -- Store AH into flags. -(define-instruction sahf (segment) - (:printer byte ((op #b10011110))) - (:emitter - (emit-byte segment #b10011110))) - -;;; STC -- Set Carry Flag. -(define-instruction stc (segment) - (:printer byte ((op #b11111001))) - (:emitter - (emit-byte segment #b11111001))) - -;;; STD -- Set Direction Flag. -(define-instruction std (segment) - (:printer byte ((op #b11111101))) - (:emitter - (emit-byte segment #b11111101))) - -;;; STI -- Set Interrupt Enable Flag. -(define-instruction sti (segment) - (:printer byte ((op #b11111011))) - (:emitter - (emit-byte segment #b11111011))) +(macrolet ((def (mnemonic opcode) + `(define-instruction ,mnemonic (segment) + (:printer byte ((op ,opcode))) + (:emitter (emit-byte segment ,opcode))))) + (def daa #x27) ; Decimal Adjust After Addition + (def das #x2F) ; Decimal Adjust after Subtraction + (def aaa #x37) ; ASCII Adjust After Addition + (def aas #x3F) ; ASCII Adjust After Subtraction + (def pusha #x60) ; push all regs + (def popa #x61) ; pop all regs + (def wait #x9B) ; Wait + (def pushf #x9C) ; Push flags + (def popf #x9D) ; Pop flags + (def sahf #x9E) ; Store AH into flags + (def lahf #x9F) ; Load AH from flags + (def leave #xC9) + (def into #xCE) ; Interrupt if Overflow + (def iret #xCF) ; Interrupt Return + (def xlat #xD7) ; Translate Byte + (def icebp #xF1) ; ICE breakpoint + (def hlt #xF4) ; Halt + (def cmc #xF5) ; Complement Carry Flag + (def clc #xF8) ; Clear Carry Flag + (def stc #xF9) ; Set Carry Flag + (def cli #xFA) ; Clear Iterrupt Enable Flag + (def sti #xFB) ; Set Interrupt Enable Flag + (def cld #xFC) ; Clear Direction Flag + (def std #xFD) ; Set Direction Flag +) ;;;; arithmetic @@ -1029,23 +952,26 @@ (let ((size (matching-operand-size dst src))) (maybe-emit-operand-size-prefix segment size) (cond - ((integerp src) - (cond ((and (not (eq size :byte)) (<= -128 src 127)) + ((or (integerp src) + (and (fixup-p src) (memq (fixup-flavor src) '(:gc-barrier :layout-id)))) + (cond ((and (neq size :byte) (typep src '(signed-byte 8))) (emit-byte segment #b10000011) (emit-ea segment dst opcode) (emit-byte segment src)) - ((accumulator-p dst) - (emit-byte segment - (dpb opcode - (byte 3 3) - (if (eq size :byte) - #b00000100 - #b00000101))) - (emit-imm-operand segment src size)) (t - (emit-byte segment (if (eq size :byte) #b10000000 #b10000001)) - (emit-ea segment dst opcode) - (emit-imm-operand segment src size)))) + (cond ((accumulator-p dst) + (emit-byte segment + (dpb opcode + (byte 3 3) + (if (eq size :byte) + #b00000100 + #b00000101)))) + (t + (emit-byte segment (if (eq size :byte) #b10000000 #b10000001)) + (emit-ea segment dst opcode))) + (if (fixup-p src) + (emit-absolute-fixup segment src) + (emit-imm-operand segment src size))))) ((register-p src) (emit-byte segment (dpb opcode @@ -1116,26 +1042,6 @@ (emit-byte segment (if (eq size :byte) #b11110110 #b11110111)) (emit-ea segment dst #b011)))) -(define-instruction aaa (segment) - (:printer byte ((op #b00110111))) - (:emitter - (emit-byte segment #b00110111))) - -(define-instruction aas (segment) - (:printer byte ((op #b00111111))) - (:emitter - (emit-byte segment #b00111111))) - -(define-instruction daa (segment) - (:printer byte ((op #b00100111))) - (:emitter - (emit-byte segment #b00100111))) - -(define-instruction das (segment) - (:printer byte ((op #b00101111))) - (:emitter - (emit-byte segment #b00101111))) - (define-instruction mul (segment dst src) (:printer accum-reg/mem ((op '(#b1111011 #b100)))) (:emitter @@ -1416,12 +1322,6 @@ (aver (accumulator-p acc)) (maybe-emit-operand-size-prefix segment size) (emit-byte segment (if (eq size :byte) #b10101010 #b10101011))))) - -(define-instruction xlat (segment) - (:printer byte ((op #b11010111))) - (:emitter - (emit-byte segment #b11010111))) - ;;;; bit manipulation @@ -1631,15 +1531,13 @@ ;;;; conditional byte set -(define-instruction set (segment dst cond) +(define-instruction set (segment cond dst) (:printer cond-set ()) (:emitter (emit-byte segment #b00001111) (emit-byte segment (dpb (conditional-opcode cond) (byte 4 0) #b10010000)) (emit-ea segment dst #b000))) -;;;; enter/leave - (define-instruction enter (segment disp &optional (level 0)) (:declare (type (unsigned-byte 16) disp) (type (unsigned-byte 8) level)) @@ -1648,11 +1546,6 @@ (emit-byte segment #b11001000) (emit-word segment disp) (emit-byte segment level))) - -(define-instruction leave (segment) - (:printer byte ((op #b11001001))) - (:emitter - (emit-byte segment #b11001001))) ;;;; prefetch (define-instruction prefetchnta (segment ea) @@ -1712,11 +1605,6 @@ (emit-byte segment #b11001101) (emit-byte segment number))))) -(define-instruction into (segment) - (:printer byte ((op #b11001110))) - (:emitter - (emit-byte segment #b11001110))) - (define-instruction bound (segment reg bounds) (:emitter (let ((size (matching-operand-size reg bounds))) @@ -1726,28 +1614,15 @@ (emit-byte segment #b01100010) (emit-ea segment bounds (reg-tn-encoding reg))))) -(define-instruction iret (segment) - (:printer byte ((op #b11001111))) - (:emitter - (emit-byte segment #b11001111))) ;;;; processor control -(define-instruction hlt (segment) - (:printer byte ((op #b11110100))) - (:emitter - (emit-byte segment #b11110100))) - (define-instruction nop (segment) (:printer byte ((op #b10010000))) (:printer ext-reg/mem-no-width ((op '(#x1F 0)))) (:emitter (emit-byte segment #b10010000))) -(define-instruction wait (segment) - (:printer byte ((op #b10011011))) - (:emitter - (emit-byte segment #b10011011))) ;;;; miscellaneous hackery @@ -2529,14 +2404,86 @@ collect (prog1 (ldb (byte 8 0) val) (setf val (ash val -8)))))))))) +;;; This gets called by LOAD to resolve newly positioned objects +;;; with things (like code instructions) that have to refer to them. +(defun fixup-code-object (code offset value kind flavor) + (declare (type index offset)) + (let ((sap (code-instructions code))) + (ecase kind + (:absolute + (case flavor + (:layout-id + (setf (signed-sap-ref-32 sap offset) value)) + (:gc-barrier + ;; the VALUE is nbits, so convert it to an AND mask + (setf (sap-ref-32 sap offset) (1- (ash 1 value)))) + (t + ;; 32-bit quantity at SAP + offset contains an + ;; addend to be replaced by adding it to VALUE. + (setf (sap-ref-32 sap offset) (+ value (sap-ref-32 sap offset)))))) + (:relative + ;; VALUE is the actual address wanted. + ;; Replace word with displacement to get there. + (let* ((loc-sap (+ (sap-int sap) offset)) + ;; Use modular arithmetic so that if the offset + ;; doesn't fit into signed-byte-32 it'll wrap around + ;; when added to EIP. + ;; "-4" is for the number of remaining bytes in the current instruction. + ;; The CPU calculates based off the next instruction. + (rel-val (ldb (byte 32 0) (- value loc-sap 4)))) + (declare (type (unsigned-byte 32) loc-sap rel-val)) + (setf (sap-ref-32 sap offset) rel-val))))) + nil) + +(defun sb-c::pack-retained-fixups (fixup-notes) + (let (abs-fixups rel-fixups imm-fixups) + (dolist (note fixup-notes) + (let* ((fixup (fixup-note-fixup note)) + (offset (fixup-note-position note)) + (kind (fixup-note-kind note)) + (flavor (fixup-flavor fixup))) + (cond ((and (eq kind :absolute) (eq flavor :code-object)) + ;; If there are N jump table entries, then any code-object fixups occurring + ;; at offsets 4, 8, 12, ..., 4*N are to patch in the jump vectors, and + ;; do need need to be explicitly retained. GC knows how to fix them again. + ;; (Offset 0 is the jump table count word) + ;; We care where the patch occurs, and NOT where the patch points to. + (unless (<= offset (* sb-vm:n-word-bytes (sb-c::component-n-jump-table-entries))) + (push offset abs-fixups))) + ((and (eq kind :relative) (member flavor '(:assembly-routine :foreign))) + (push offset rel-fixups)) + ((eq flavor :gc-barrier) + (push offset imm-fixups)) + ((or (and (eq kind :absolute) + (member flavor '(:assembly-routine :foreign :foreign-dataref))) + (member flavor '(:layout-id :symbol-tls-index)))) ; discard + (t + (bug "Unexpected fixup"))))) + (sb-c:pack-code-fixup-locs abs-fixups rel-fixups imm-fixups))) + +;;; Coverage support + +(define-instruction store-coverage-mark (segment mark-index) + (:emitter + (let ((offset (+ (component-header-length) + ;; skip over jump table word and entries + (* (1+ (component-n-jump-table-entries)) + n-word-bytes) + mark-index + (- other-pointer-lowtag)))) + (assemble (segment) + (inst mov (make-ea :byte :disp (make-fixup nil :code-object offset)) 1))))) + ;;; Perform exhaustive analysis here because of the extreme degree ;;; of confusion I have about what is allowed to reach the instruction ;;; emitter as a raw fixup, a fixup wrapped in an EA, a label wrapped ;;; in a fixup wrapped in an EA etc. +;;; (The x86-64 assembler is more understandable - we need to kill this one) (defun sb-assem::%mark-used-labels (operand) (named-let recurse ((operand operand)) (etypecase operand ((or integer tn keyword null)) + #+sb-xc-host ((cons (eql sb-assem::entry))) (ea (let ((disp (ea-disp operand))) (etypecase disp @@ -2549,16 +2496,3 @@ (setf (label-usedp offset) t)) ((consp offset) (setf (label-usedp (car offset)) t)))))))) - -(defun sb-c::branch-opcode-p (mnemonic) - (case mnemonic - ((call ret jmp jecxz break int iret - loop loopz loopnz syscall - byte word dword) ; unexplained phenomena - t))) - -;;; Replace the STATEMENT with an instruction to store a coverage mark -;;; in the OFFSETth byte beyond LABEL. -(defun sb-c::replace-coverage-instruction (statement label offset) - (setf (stmt-mnemonic statement) 'mov - (stmt-operands statement) `(,(make-ea :byte :disp `(+ ,label ,offset)) 1))) diff --git a/src/compiler/x86/macros.lisp b/src/compiler/x86/macros.lisp index 1e952dda2b..390a79ed9f 100644 --- a/src/compiler/x86/macros.lisp +++ b/src/compiler/x86/macros.lisp @@ -59,13 +59,6 @@ (once-only ((value value)) `(inst mov (object-slot-ea ,ptr ,slot ,lowtag) ,value))) -;;; A handy utility for storing widetags. -(defun store-widetag (value ptr &optional (slot 0) (lowtag 0)) - (inst mov (object-slot-ea - ptr slot lowtag - (if (typep value '(and integer (not (unsigned-byte 8)))) :word :byte)) - value)) - (defmacro pushw (ptr &optional (slot 0) (lowtag 0)) `(inst push (object-slot-ea ,ptr ,slot ,lowtag))) @@ -201,13 +194,12 @@ #+sb-safepoint (defun emit-safepoint () (inst test eax-tn (make-ea :dword :disp - (- nil-value n-word-bytes other-pointer-lowtag - gc-safepoint-trap-offset)))) + (- static-space-start gc-safepoint-trap-offset)))) (defmacro pseudo-atomic ((&key elide-if) &rest forms) - #+sb-safepoint-strictly + #+sb-safepoint `(progn ,@forms (unless ,elide-if (emit-safepoint))) - #-sb-safepoint-strictly + #-sb-safepoint (with-unique-names (label pa-bits-ea) `(let ((,label (gen-label)) (,pa-bits-ea @@ -224,13 +216,7 @@ ;; if PAI was set, interrupts were disabled at the same time ;; using the process signal mask. (inst break pending-interrupt-trap) - (emit-label ,label) - #+sb-safepoint - ;; In this case, when allocation thinks a GC should be done, it - ;; does not mark PA as interrupted, but schedules a safepoint - ;; trap instead. Let's take the opportunity to trigger that - ;; safepoint right now. - (emit-safepoint))))) + (emit-label ,label))))) ;;;; indexed references @@ -295,7 +281,7 @@ :disp (- (* ,offset n-word-bytes) ,lowtag))))))))) -(defmacro define-full-reffer+offset (name type offset lowtag scs el-type &optional translate) +(defmacro define-full-reffer+addend (name type offset lowtag scs el-type &optional translate) `(progn (define-vop (,name) ,@(when translate @@ -305,7 +291,7 @@ (index :scs (any-reg immediate unsigned-reg))) (:arg-types ,type tagged-num (:constant (constant-displacement ,lowtag n-word-bytes ,offset))) - (:info offset) + (:info addend) (:results (value :scs ,scs)) (:result-types ,el-type) (:generator 3 ; pw was 5 @@ -314,32 +300,29 @@ (inst mov value (make-ea :dword :base object :disp (- (* (+ ,offset (tn-value index) - offset) + addend) n-word-bytes) ,lowtag)))) (unsigned-reg (inst mov value (make-ea :dword :base object :index index :scale 4 - :disp (- (* (+ ,offset offset) + :disp (- (* (+ ,offset addend) n-word-bytes) ,lowtag)))) (t (inst mov value (make-ea :dword :base object :index index - :disp (- (* (+ ,offset offset) + :disp (- (* (+ ,offset addend) n-word-bytes) ,lowtag))))))))) (defmacro define-full-setter (name type offset lowtag scs el-type &optional translate) - `(progn - (define-vop (,name) + `(define-vop (,name) ,@(when translate `((:translate ,translate))) (:policy :fast-safe) (:args (object :scs (descriptor-reg)) (index :scs (any-reg immediate)) - (value :scs ,scs :target result)) + (value :scs ,scs)) (:arg-types ,type tagged-num ,el-type) - (:results (result :scs ,scs)) - (:result-types ,el-type) (:generator 4 ; was 5 (sc-case index (immediate @@ -351,37 +334,7 @@ (t (inst mov (make-ea :dword :base object :index index :disp (- (* ,offset n-word-bytes) ,lowtag)) - value))) - (move result value))))) - -(defmacro define-full-setter+offset (name type offset lowtag scs el-type &optional translate) - `(progn - (define-vop (,name) - ,@(when translate - `((:translate ,translate))) - (:policy :fast-safe) - (:args (object :scs (descriptor-reg)) - (index :scs (any-reg immediate)) - (value :scs ,scs :target result)) - (:info offset) - (:arg-types ,type tagged-num - (:constant (constant-displacement ,lowtag n-word-bytes ,offset)) ,el-type) - (:results (result :scs ,scs)) - (:result-types ,el-type) - (:generator 4 ; was 5 - (sc-case index - (immediate - (inst mov (make-ea :dword :base object - :disp (- (* (+ ,offset (tn-value index) offset) - n-word-bytes) - ,lowtag)) - value)) - (t - (inst mov (make-ea :dword :base object :index index - :disp (- (* (+ ,offset offset) - n-word-bytes) ,lowtag)) - value))) - (move result value))))) + value)))))) ;;; Helper to hide the fact that thread access on Windows needs one more ;;; instruction, needs the FS prefix in that instruction _instead_ of diff --git a/src/compiler/x86/move.lisp b/src/compiler/x86/move.lisp index d36bb2e1a7..fbfa17d12c 100644 --- a/src/compiler/x86/move.lisp +++ b/src/compiler/x86/move.lisp @@ -222,14 +222,14 @@ (:generator 4 (inst imul y x (ash 1 n-fixnum-tag-bits)) (inst jmp :no done) - (inst mov y (emit-constant (1+ sb-xc:most-positive-fixnum))) + (inst mov y (emit-constant (1+ most-positive-fixnum))) done)) (define-vop (move-from-fixnum-1 move-from-fixnum+1) (:generator 4 (inst imul y x (ash 1 n-fixnum-tag-bits)) (inst jmp :no done) - (inst mov y (emit-constant (1- sb-xc:most-negative-fixnum))) + (inst mov y (emit-constant (1- most-negative-fixnum))) done)) ;;; Convert an untagged unsigned word to a lispobj -- fixnum or bignum diff --git a/src/compiler/x86/nlx.lisp b/src/compiler/x86/nlx.lisp index d860b4fa9a..3c5c55ab49 100644 --- a/src/compiler/x86/nlx.lisp +++ b/src/compiler/x86/nlx.lisp @@ -203,6 +203,19 @@ (inst jmp defaulting-done)))))) (inst mov esp-tn sp))) +(define-vop (nlx-entry-single) + (:args (sp) + (start)) + (:results (res :from :load)) + (:info label) + (:save-p :force-to-stack) + (:vop-var vop) + (:generator 30 + (emit-label label) + (note-this-location vop :non-local-entry) + (inst mov res start) + (inst mov esp-tn sp))) + (define-vop (nlx-entry-multiple) (:args (top) (source) diff --git a/src/compiler/x86/parms.lisp b/src/compiler/x86/parms.lisp index 70a268ff39..b0a248bc9d 100644 --- a/src/compiler/x86/parms.lisp +++ b/src/compiler/x86/parms.lisp @@ -33,7 +33,7 @@ ;;; The size in bytes of GENCGC cards, i.e. the granularity at which ;;; writes to old generations are logged. With mprotect-based write ;;; barriers, this must be a multiple of the OS page size. -(defconstant gencgc-card-bytes +backend-page-bytes+) +(defconstant gencgc-page-bytes +backend-page-bytes+) ;;; The minimum size of new allocation regions. While it doesn't ;;; currently make a lot of sense to have a card size lower than ;;; the alloc granularity, it will, once we are smarter about finding @@ -61,29 +61,6 @@ ;;; address space) (defconstant n-machine-word-bits 32) -(defconstant float-sign-shift 31) - -;;; comment from CMU CL: -;;; These values were taken from the alpha code. The values for -;;; bias and exponent min/max are not the same as shown in the 486 book. -;;; They may be correct for how Python uses them. -(defconstant single-float-bias 126) ; Intel says 127. -(defconstant-eqx single-float-exponent-byte (byte 8 23) #'equalp) -(defconstant-eqx single-float-significand-byte (byte 23 0) #'equalp) -;;; comment from CMU CL: -;;; The 486 book shows the exponent range -126 to +127. The Lisp -;;; code that uses these values seems to want already biased numbers. -(defconstant single-float-normal-exponent-min 1) -(defconstant single-float-normal-exponent-max 254) -(defconstant single-float-hidden-bit (ash 1 23)) - -(defconstant double-float-bias 1022) -(defconstant-eqx double-float-exponent-byte (byte 11 20) #'equalp) -(defconstant-eqx double-float-significand-byte (byte 20 0) #'equalp) -(defconstant double-float-normal-exponent-min 1) -(defconstant double-float-normal-exponent-max #x7FE) -(defconstant double-float-hidden-bit (ash 1 20)) - (defconstant long-float-bias 16382) (defconstant-eqx long-float-exponent-byte (byte 15 0) #'equalp) (defconstant-eqx long-float-significand-byte (byte 31 0) #'equalp) @@ -91,12 +68,6 @@ (defconstant long-float-normal-exponent-max #x7FFE) (defconstant long-float-hidden-bit (ash 1 31)) ; actually not hidden -(defconstant single-float-digits - (+ (byte-size single-float-significand-byte) 1)) - -(defconstant double-float-digits - (+ (byte-size double-float-significand-byte) n-word-bits 1)) - (defconstant long-float-digits (+ (byte-size long-float-significand-byte) n-word-bits 1)) @@ -128,7 +99,7 @@ ;;; where to put the different spaces ;;; -;;; Note: Mostly these values are black magic, inherited from CMU CL +;;; Note: Mostly these values are magic, inherited from CMU CL ;;; without any documentation. However, there were a few explanatory ;;; comments in the CMU CL sources: ;;; * On Linux, @@ -192,7 +163,7 @@ ;;; table: "In CMUCL: 0xB0000000->0xB1000000" (defmacro space-setup (arg &rest more) - `(!gencgc-space-setup ,arg #-win32 :read-only-space-size #-win32 0 ,@more)) + `(!gencgc-space-setup ,arg ,@more)) #+win32 (space-setup #x22000000) #+linux (space-setup #x01000000 :dynamic-space-start #x09000000) @@ -203,9 +174,9 @@ #+netbsd (space-setup #x20000000 :dynamic-space-start #x60000000) #+darwin (space-setup #x04000000 :dynamic-space-start #x10000000) -;;; Size of one linkage-table entry in bytes. -(defconstant linkage-table-entry-size 8) -(defconstant linkage-table-growth-direction :up) +;;; Size of one alien-linkage-table entry in bytes. +(defconstant alien-linkage-table-entry-size 8) +(defconstant alien-linkage-table-growth-direction :up) (defenum (:start 8) diff --git a/src/compiler/x86/pred.lisp b/src/compiler/x86/pred.lisp index d408641a59..46f5322649 100644 --- a/src/compiler/x86/pred.lisp +++ b/src/compiler/x86/pred.lisp @@ -37,15 +37,12 @@ (define-vop (branch-if) (:info dest not-p flags) (:generator 0 - (flet ((negate-condition (name) - (let ((code (logxor 1 (conditional-opcode name)))) - (aref +condition-name-vec+ code)))) (aver (null (rest flags))) (inst jmp (if not-p (negate-condition (first flags)) (first flags)) - dest)))) + dest))) (define-vop (multiway-branch-if-eq) ;; TODO: also accept signed-reg, unsigned-reg, character-reg diff --git a/src/compiler/x86/sap.lisp b/src/compiler/x86/sap.lisp index 082ca5687a..1632640864 100644 --- a/src/compiler/x86/sap.lisp +++ b/src/compiler/x86/sap.lisp @@ -155,9 +155,7 @@ (:policy :fast-safe) (:args (sap :scs (sap-reg)) (offset :scs (signed-reg immediate))) - (:info disp) - (:arg-types system-area-pointer signed-num - (:constant (constant-displacement 0 1 0))) + (:arg-types system-area-pointer signed-num) (:results (result :scs (,sc))) (:result-types ,type) (:generator 5 @@ -169,293 +167,118 @@ (immediate (inst ,mov-inst result (make-ea ,size :base sap - :disp (+ (tn-value offset) disp)))) + :disp (tn-value offset)))) (t (inst ,mov-inst result (make-ea ,size :base sap - :index offset - :disp disp))))))) + :index offset))))))) (define-vop (,set-name) (:translate ,set-name) (:policy :fast-safe) - (:args (sap :scs (sap-reg) :to (:eval 0)) - (offset :scs (signed-reg immediate) :to (:eval 0)) - (value :scs (,sc) - :target ,(if (eq size :dword) - 'result - 'temp))) - (:info disp) - (:arg-types system-area-pointer signed-num - (:constant (constant-displacement 0 1 0)) - ,type) + (:args (value :scs (,sc)) + (sap :scs (sap-reg)) + (offset :scs (signed-reg immediate))) + (:arg-types ,type system-area-pointer signed-num) ,@(unless (eq size :dword) - `((:temporary (:sc ,temp-sc :offset eax-offset - :from (:argument 2) :to (:result 0) - :target result) - temp))) - (:results (result :scs (,sc))) - (:result-types ,type) + `((:temporary (:sc ,temp-sc :offset eax-offset) temp))) (:generator 5 - ,@(unless (eq size :dword) - `((move eax-tn value))) + ,@(unless (eq size :dword) `((move eax-tn value))) (inst mov (sc-case offset (immediate (make-ea ,size :base sap - :disp (+ (tn-value offset) - disp))) + :disp (tn-value offset))) (t (make-ea ,size :base sap - :index offset - :disp disp))) - ,(if (eq size :dword) 'value 'temp)) - (move result - ,(if (eq size :dword) 'value 'eax-tn)))))))) - - (def-system-ref-and-set sb-c::sap-ref-8-with-offset sb-c::%set-sap-ref-8-with-offset + :index offset))) + ,(if (eq size :dword) 'value 'temp)))))))) + (def-system-ref-and-set sap-ref-8 %set-sap-ref-8 unsigned-reg positive-fixnum :byte nil) - (def-system-ref-and-set sb-c::signed-sap-ref-8-with-offset sb-c::%set-signed-sap-ref-8-with-offset + (def-system-ref-and-set signed-sap-ref-8 %set-signed-sap-ref-8 signed-reg tagged-num :byte t) - (def-system-ref-and-set sb-c::sap-ref-16-with-offset sb-c::%set-sap-ref-16-with-offset + (def-system-ref-and-set sap-ref-16 %set-sap-ref-16 unsigned-reg positive-fixnum :word nil) - (def-system-ref-and-set sb-c::signed-sap-ref-16-with-offset sb-c::%set-signed-sap-ref-16-with-offset + (def-system-ref-and-set signed-sap-ref-16 %set-signed-sap-ref-16 signed-reg tagged-num :word t) - (def-system-ref-and-set sb-c::sap-ref-32-with-offset sb-c::%set-sap-ref-32-with-offset + (def-system-ref-and-set sap-ref-32 %set-sap-ref-32 unsigned-reg unsigned-num :dword nil) - (def-system-ref-and-set sb-c::signed-sap-ref-32-with-offset sb-c::%set-signed-sap-ref-32-with-offset + (def-system-ref-and-set signed-sap-ref-32 %set-signed-sap-ref-32 signed-reg signed-num :dword t) - (def-system-ref-and-set sb-c::sap-ref-sap-with-offset sb-c::%set-sap-ref-sap-with-offset + (def-system-ref-and-set sap-ref-sap %set-sap-ref-sap sap-reg system-area-pointer :dword) - (def-system-ref-and-set sb-c::sap-ref-lispobj-with-offset sb-c::%set-sap-ref-lispobj-with-offset + (def-system-ref-and-set sap-ref-lispobj %set-sap-ref-lispobj descriptor-reg * :dword)) ;;;; SAP-REF-DOUBLE -(define-vop (sap-ref-double-with-offset) - (:translate sb-c::sap-ref-double-with-offset) +(define-vop () + (:translate sap-ref-double) (:policy :fast-safe) (:args (sap :scs (sap-reg)) (offset :scs (signed-reg immediate))) - (:info disp) - (:arg-types system-area-pointer signed-num - (:constant (constant-displacement 0 1 0))) + (:arg-types system-area-pointer signed-num) (:results (result :scs (double-reg))) (:result-types double-float) (:generator 5 (sc-case offset (immediate - (aver (zerop disp)) (with-empty-tn@fp-top(result) (inst fldd (make-ea :dword :base sap :disp (tn-value offset))))) (t (with-empty-tn@fp-top(result) - (inst fldd (make-ea :dword :base sap :index offset - :disp disp))))))) + (inst fldd (make-ea :dword :base sap :index offset))))))) -(define-vop (%set-sap-ref-double-with-offset) - (:translate sb-c::%set-sap-ref-double-with-offset) +(define-vop () + (:translate %set-sap-ref-double) (:policy :fast-safe) - (:args (sap :scs (sap-reg) :to (:eval 0)) - (offset :scs (signed-reg) :to (:eval 0)) - (value :scs (double-reg))) - (:info disp) - (:arg-types system-area-pointer signed-num - (:constant (constant-displacement 0 1 0)) - double-float) - (:results (result :scs (double-reg))) - (:result-types double-float) + (:args (value :scs (double-reg)) + (sap :scs (sap-reg)) + (offset :scs (signed-reg))) + (:arg-types double-float system-area-pointer signed-num) (:generator 5 - (cond ((zerop (tn-offset value)) - ;; Value is in ST0. - (inst fstd (make-ea :dword :base sap :index offset :disp disp)) - (unless (zerop (tn-offset result)) - ;; Value is in ST0 but not result. - (inst fstd result))) - (t - ;; Value is not in ST0. - (inst fxch value) - (inst fstd (make-ea :dword :base sap :index offset :disp disp)) - (cond ((zerop (tn-offset result)) - ;; The result is in ST0. - (inst fstd value)) - (t - ;; Neither value or result are in ST0. - (unless (location= value result) - (inst fstd result)) - (inst fxch value))))))) + (with-tn@fp-top (value) + (inst fstd (make-ea :dword :base sap :index offset))))) -(define-vop (%set-sap-ref-double-with-offset-c) - (:translate sb-c::%set-sap-ref-double-with-offset) - (:policy :fast-safe) - (:args (sap :scs (sap-reg) :to (:eval 0)) - (value :scs (double-reg))) - (:arg-types system-area-pointer (:constant (signed-byte 32)) - (:constant (constant-displacement 0 1 0)) - double-float) - (:info offset disp) - (:results (result :scs (double-reg))) - (:result-types double-float) - (:generator 4 - (aver (zerop disp)) - (cond ((zerop (tn-offset value)) - ;; Value is in ST0. - (inst fstd (make-ea :dword :base sap :disp offset)) - (unless (zerop (tn-offset result)) - ;; Value is in ST0 but not result. - (inst fstd result))) - (t - ;; Value is not in ST0. - (inst fxch value) - (inst fstd (make-ea :dword :base sap :disp offset)) - (cond ((zerop (tn-offset result)) - ;; The result is in ST0. - (inst fstd value)) - (t - ;; Neither value or result are in ST0. - (unless (location= value result) - (inst fstd result)) - (inst fxch value))))))) - ;;;; SAP-REF-SINGLE -(define-vop (sap-ref-single-with-offset) - (:translate sb-c::sap-ref-single-with-offset) +(define-vop () + (:translate sap-ref-single) (:policy :fast-safe) (:args (sap :scs (sap-reg)) (offset :scs (signed-reg immediate))) - (:info disp) - (:arg-types system-area-pointer signed-num - (:constant (constant-displacement 0 1 0))) + (:arg-types system-area-pointer signed-num) (:results (result :scs (single-reg))) (:result-types single-float) (:generator 5 (sc-case offset (immediate - (aver (zerop disp)) (with-empty-tn@fp-top(result) (inst fld (make-ea :dword :base sap :disp (tn-value offset))))) (t (with-empty-tn@fp-top(result) - (inst fld (make-ea :dword :base sap :index offset :disp disp))))))) + (inst fld (make-ea :dword :base sap :index offset))))))) -(define-vop (%set-sap-ref-single-with-offset) - (:translate sb-c::%set-sap-ref-single-with-offset) +(define-vop () + (:translate %set-sap-ref-single) (:policy :fast-safe) - (:args (sap :scs (sap-reg) :to (:eval 0)) - (offset :scs (signed-reg) :to (:eval 0)) - (value :scs (single-reg))) - (:info disp) - (:arg-types system-area-pointer signed-num - (:constant (constant-displacement 0 1 0)) - single-float) - (:results (result :scs (single-reg))) - (:result-types single-float) + (:args (value :scs (single-reg)) + (sap :scs (sap-reg)) + (offset :scs (signed-reg))) + (:arg-types single-float system-area-pointer signed-num) (:generator 5 - (cond ((zerop (tn-offset value)) - ;; Value is in ST0 - (inst fst (make-ea :dword :base sap :index offset :disp disp)) - (unless (zerop (tn-offset result)) - ;; Value is in ST0 but not result. - (inst fst result))) - (t - ;; Value is not in ST0. - (inst fxch value) - (inst fst (make-ea :dword :base sap :index offset :disp disp)) - (cond ((zerop (tn-offset result)) - ;; The result is in ST0. - (inst fst value)) - (t - ;; Neither value or result are in ST0 - (unless (location= value result) - (inst fst result)) - (inst fxch value))))))) + (with-tn@fp-top (value) + (inst fst (make-ea :dword :base sap :index offset))))) -(define-vop (%set-sap-ref-single-with-offset-c) - (:translate sb-c::%set-sap-ref-single-with-offset) - (:policy :fast-safe) - (:args (sap :scs (sap-reg) :to (:eval 0)) - (value :scs (single-reg))) - (:arg-types system-area-pointer (:constant (signed-byte 32)) - (:constant (constant-displacement 0 1 0)) - single-float) - (:info offset disp) - (:results (result :scs (single-reg))) - (:result-types single-float) - (:generator 4 - (aver (zerop disp)) - (cond ((zerop (tn-offset value)) - ;; Value is in ST0 - (inst fst (make-ea :dword :base sap :disp offset)) - (unless (zerop (tn-offset result)) - ;; Value is in ST0 but not result. - (inst fst result))) - (t - ;; Value is not in ST0. - (inst fxch value) - (inst fst (make-ea :dword :base sap :disp offset)) - (cond ((zerop (tn-offset result)) - ;; The result is in ST0. - (inst fst value)) - (t - ;; Neither value or result are in ST0 - (unless (location= value result) - (inst fst result)) - (inst fxch value))))))) - -;;;; SAP-REF-LONG - -(define-vop (sap-ref-long) +(define-vop () (:translate sap-ref-long) (:policy :fast-safe) (:args (sap :scs (sap-reg)) (offset :scs (signed-reg))) (:arg-types system-area-pointer signed-num) - (:results (result :scs (#+long-float long-reg #-long-float double-reg))) - (:result-types #+long-float long-float #-long-float double-float) + (:results (result :scs (double-reg))) + (:result-types double-float) (:generator 5 (with-empty-tn@fp-top(result) - (inst fldl (make-ea :dword :base sap :index offset))))) + (inst fldl (make-ea :dword :base sap :index offset))))) -(define-vop (sap-ref-long-c) - (:translate sap-ref-long) - (:policy :fast-safe) - (:args (sap :scs (sap-reg))) - (:arg-types system-area-pointer (:constant (signed-byte 32))) - (:info offset) - (:results (result :scs (#+long-float long-reg #-long-float double-reg))) - (:result-types #+long-float long-float #-long-float double-float) - (:generator 4 - (with-empty-tn@fp-top(result) - (inst fldl (make-ea :dword :base sap :disp offset))))) - -#+long-float -(define-vop (%set-sap-ref-long) - (:translate %set-sap-ref-long) - (:policy :fast-safe) - (:args (sap :scs (sap-reg) :to (:eval 0)) - (offset :scs (signed-reg) :to (:eval 0)) - (value :scs (long-reg))) - (:arg-types system-area-pointer signed-num long-float) - (:results (result :scs (long-reg))) - (:result-types long-float) - (:generator 5 - (cond ((zerop (tn-offset value)) - ;; Value is in ST0 - (store-long-float (make-ea :dword :base sap :index offset)) - (unless (zerop (tn-offset result)) - ;; Value is in ST0 but not result. - (inst fstd result))) - (t - ;; Value is not in ST0. - (inst fxch value) - (store-long-float (make-ea :dword :base sap :index offset)) - (cond ((zerop (tn-offset result)) - ;; The result is in ST0. - (inst fstd value)) - (t - ;; Neither value or result are in ST0 - (unless (location= value result) - (inst fstd result)) - (inst fxch value))))))) - ;;; noise to convert normal lisp data objects into SAPs (define-vop (vector-sap) diff --git a/src/compiler/x86/system.lisp b/src/compiler/x86/system.lisp index 898523f06d..534de8282b 100644 --- a/src/compiler/x86/system.lisp +++ b/src/compiler/x86/system.lisp @@ -48,15 +48,34 @@ word-shift) instance-pointer-lowtag) :base layout))) - (define-vop (sb-c::layout-depthoid-gt) - (:translate sb-c::layout-depthoid-gt) + (define-vop () + (:translate sb-c::layout-depthoid-ge) (:policy :fast-safe) (:args (layout :scs (descriptor-reg))) (:info k) (:arg-types * (:constant (unsigned-byte 16))) - (:conditional :g) + (:conditional :ge) (:generator 1 (inst cmp (read-depthoid) (fixnumize k))))) +(define-vop () + (:translate sb-c::%structure-is-a) + (:args (x :scs (descriptor-reg))) + (:arg-types * (:constant t)) + (:info test) + (:policy :fast-safe) + (:conditional :e) + (:generator 1 + (inst cmp + (make-ea :dword + :disp (+ (id-bits-offset) + (ash (- (wrapper-depthoid test) 2) 2) + (- instance-pointer-lowtag)) + :base x) + (if (or (typep (layout-id test) '(and (signed-byte 8) (not (eql 0)))) + (not (sb-c::producing-fasl-file))) + (layout-id test) + (make-fixup test :layout-id))))) + (define-vop (%other-pointer-widetag) (:translate %other-pointer-widetag) (:policy :fast-safe) @@ -68,8 +87,8 @@ :disp (- other-pointer-lowtag))))) -(define-vop (fun-subtype) - (:translate fun-subtype) +(define-vop () + (:translate %fun-pointer-widetag) (:policy :fast-safe) (:args (function :scs (descriptor-reg))) (:results (result :scs (unsigned-reg))) @@ -91,18 +110,33 @@ (define-vop (set-header-data) (:translate set-header-data) (:policy :fast-safe) - (:args (x :scs (descriptor-reg) :target res :to (:result 0)) + (:args (x :scs (descriptor-reg) :to :eval) (data :scs (any-reg) :target eax)) (:arg-types * positive-fixnum) - (:results (res :scs (descriptor-reg))) - (:temporary (:sc unsigned-reg :offset eax-offset - :from (:argument 1) :to (:result 0)) eax) + (:temporary (:sc unsigned-reg :offset eax-offset :from (:argument 1)) eax) (:generator 6 (move eax data) - (inst shl eax (- n-widetag-bits 2)) + (inst shl eax (- n-widetag-bits n-fixnum-tag-bits)) (load-type al-tn x (- other-pointer-lowtag)) - (storew eax x 0 other-pointer-lowtag) - (move res x))) + (storew eax x 0 other-pointer-lowtag))) + +(define-vop (test-header-data-bit) + (:translate test-header-data-bit) + (:policy :fast-safe) + (:args (array :scs (descriptor-reg))) + (:arg-types t (:constant t)) + (:info mask) + (:conditional :ne) + (:generator 1 + ;; Assert that the mask is in header-data byte index 0 + ;; which is byte index 1 of the whole header word. + (cond ((typep mask '(unsigned-byte 8)) + (inst test (make-ea :byte :disp (- 1 other-pointer-lowtag) :base array) mask)) + ((and (typep mask '(unsigned-byte 16)) (not (logtest mask #xFF))) + (inst test (make-ea :byte :disp (- 2 other-pointer-lowtag) :base array) + (ash mask -8))) + (t + (bug "Unimplemented"))))) (define-vop (pointer-hash) (:translate pointer-hash) @@ -204,39 +238,6 @@ :disp (- fun-pointer-lowtag (* simple-fun-insts-offset n-word-bytes)))))) -;;;; symbol frobbing - -(define-vop (symbol-info-vector) - (:policy :fast-safe) - (:translate symbol-info-vector) - (:args (x :scs (descriptor-reg))) - (:results (res :scs (descriptor-reg))) - (:temporary (:sc unsigned-reg :offset eax-offset) eax) - (:generator 1 - (loadw res x symbol-info-slot other-pointer-lowtag) - ;; If RES has list-pointer-lowtag, take its CDR. If not, use it as-is. - ;; This CMOV safely reads from memory when it does not move, because if - ;; there is an info-vector in the slot, it has at least one element. - ;; This would compile to almost the same code without a VOP, - ;; but using a jmp around a mov instead. - (inst lea eax (make-ea :dword :base res :disp (- list-pointer-lowtag))) - (emit-optimized-test-inst eax lowtag-mask) - (inst cmov :e res - (object-slot-ea res cons-cdr-slot list-pointer-lowtag)))) -(define-vop (symbol-plist) - (:policy :fast-safe) - (:translate symbol-plist) - (:args (x :scs (descriptor-reg))) - (:results (res :scs (descriptor-reg))) - (:temporary (:sc unsigned-reg) temp) - (:generator 1 - (loadw res x symbol-info-slot other-pointer-lowtag) - ;; Instruction pun: (CAR x) is the same as (VECTOR-LENGTH x) - ;; so if the info slot holds a vector, this gets a fixnum- it's not a plist. - (loadw res res cons-car-slot list-pointer-lowtag) - (inst mov temp nil-value) - (emit-optimized-test-inst res fixnum-tag-mask) - (inst cmov :e res temp))) ;;;; other miscellaneous VOPs @@ -429,3 +430,10 @@ number of CPU cycles elapsed as secondary value. EXPERIMENTAL." (move b ebx) (move c ecx) (move d edx))) + +(define-vop (sb-c::mark-covered) + (:info index) + (:generator 1 + ;; Can't convert index to a code-relative index until the boxed header length + ;; has been determined. + (inst store-coverage-mark index))) diff --git a/src/compiler/x86/type-vops.lisp b/src/compiler/x86/type-vops.lisp index 01dcdcf9b4..6e6b10d375 100644 --- a/src/compiler/x86/type-vops.lisp +++ b/src/compiler/x86/type-vops.lisp @@ -169,6 +169,10 @@ ;;;; other integer ranges +(define-vop (fixnump simple-type-predicate) + (:translate fixnump) + (:generator 4 (%test-fixnum value nil target not-p))) + (define-vop (fixnump/unsigned-byte-32 simple-type-predicate) (:args (value :scs (unsigned-reg))) (:info) @@ -179,7 +183,7 @@ ;; We could encode this with :Z and SHR, analogously to the signed-byte-32 ;; case below -- as we do on x86-64 -- but that costs us an extra ;; register. Compromises... - (inst cmp value #.sb-xc:most-positive-fixnum))) + (inst cmp value #.most-positive-fixnum))) (define-vop (fixnump/signed-byte-32 type-predicate) (:args (value :scs (signed-reg))) @@ -194,9 +198,9 @@ ;; is equivalent to unsigned ;; ((x-a) >> n) = 0 (inst mov eax-tn value) - (inst sub eax-tn #.sb-xc:most-negative-fixnum) - (inst shr eax-tn #.(integer-length (- sb-xc:most-positive-fixnum - sb-xc:most-negative-fixnum))))) + (inst sub eax-tn #.most-negative-fixnum) + (inst shr eax-tn #.(integer-length (- most-positive-fixnum + most-negative-fixnum))))) ;;; A (SIGNED-BYTE 32) can be represented with either fixnum or a bignum with ;;; exactly one digit. @@ -204,7 +208,7 @@ (define-vop (signed-byte-32-p type-predicate) (:translate signed-byte-32-p) (:ignore temp) - (:generator 45 + (:generator 10 (multiple-value-bind (yep nope) (if not-p (values not-target target) @@ -226,7 +230,7 @@ (define-vop (unsigned-byte-32-p type-predicate) (:translate unsigned-byte-32-p) (:ignore temp) - (:generator 45 + (:generator 10 (let ((not-target (gen-label)) (single-word (gen-label)) (fixnum (gen-label))) diff --git a/src/compiler/x86/values.lisp b/src/compiler/x86/values.lisp index 1d98e57f8a..c87727ff52 100644 --- a/src/compiler/x86/values.lisp +++ b/src/compiler/x86/values.lisp @@ -12,7 +12,7 @@ (in-package "SB-VM") (define-vop (reset-stack-pointer) - (:args (ptr :scs (any-reg))) + (:args (ptr :scs (any-reg control-stack))) (:generator 1 (move esp-tn ptr))) @@ -56,15 +56,22 @@ ;;; bogus SC that reflects the costs of the memory-to-memory moves for each ;;; operand, but this seems unworthwhile. (define-vop (push-values) - (:args (vals :more t - :scs (descriptor-reg))) + (:args (vals :more t :scs (descriptor-reg any-reg immediate constant))) (:results (start :from :load) (count)) (:info nvals) + (:temporary (:scs (descriptor-reg)) temp) + (:vop-var vop) (:generator 20 (move start esp-tn) ; WARN pointing 1 below - (do ((val vals (tn-ref-across val))) - ((null val)) - (inst push (encode-value-if-immediate (tn-ref-tn val)))) + (do ((tn-ref vals (tn-ref-across tn-ref))) + ((null tn-ref)) + (let ((tn (tn-ref-tn tn-ref))) + (inst push (sc-case tn + (constant + (load-constant vop tn temp) + temp) + (t + (encode-value-if-immediate tn)))))) (inst mov count (fixnumize nvals)))) ;;; Push a list of values on the stack, returning Start and Count as used in @@ -110,25 +117,15 @@ ;;; defining a new stack frame. (define-vop (%more-arg-values) (:args (context :scs (descriptor-reg any-reg) :target src) - (skip :scs (any-reg immediate)) (num :scs (any-reg) :target count)) - (:arg-types * positive-fixnum positive-fixnum) + (:arg-types * positive-fixnum) (:temporary (:sc any-reg :offset esi-offset :from (:argument 0)) src) (:temporary (:sc descriptor-reg :offset eax-offset) temp) (:temporary (:sc unsigned-reg :offset ecx-offset) loop-index) (:results (start :scs (any-reg)) (count :scs (any-reg))) (:generator 20 - (sc-case skip - (immediate - (if (zerop (tn-value skip)) - (move src context) - (inst lea src (make-ea :dword :base context - :disp (- (* (tn-value skip) - n-word-bytes)))))) - (any-reg - (move src context) - (inst sub src skip))) + (move src context) (move count num) (move loop-index count) diff --git a/src/compiler/x86/vm.lisp b/src/compiler/x86/vm.lisp index 25bf339a5b..c9615f4d5d 100644 --- a/src/compiler/x86/vm.lisp +++ b/src/compiler/x86/vm.lisp @@ -347,7 +347,7 @@ ;;; the appropriate SC number, otherwise return NIL. (defun immediate-constant-sc (value) (typecase value - ((or (integer #.sb-xc:most-negative-fixnum #.sb-xc:most-positive-fixnum) + ((or (integer #.most-negative-fixnum #.most-positive-fixnum) character) immediate-sc-number) (symbol @@ -467,7 +467,7 @@ (logbitp (cond ((and (valid-funtype '((integer 0 29) fixnum) '*) - (sb-c::constant-lvar-p (first (sb-c::basic-combination-args node)))) + (sb-c:constant-lvar-p (first (sb-c::basic-combination-args node)))) (values :transform '(lambda (index integer) (%logbitp integer index)))) ((valid-funtype '((integer 0 31) (signed-byte 32)) '*) diff --git a/src/compiler/xref.lisp b/src/compiler/xref.lisp index 6f0f0b9ee5..ec814f3537 100644 --- a/src/compiler/xref.lisp +++ b/src/compiler/xref.lisp @@ -79,12 +79,12 @@ (defun record-node-xrefs (node context) (declare (type node node)) (etypecase node - ((or creturn cif entry mv-combination cast exit)) + ((or creturn cif entry mv-combination cast exit enclose)) (combination ;; Record references to globals made using SYMBOL-VALUE. (let ((fun (principal-lvar-use (combination-fun node))) (arg (car (combination-args node)))) - (when (and (ref-p fun) (eq 'symeval (leaf-%source-name (ref-leaf fun))) + (when (and (ref-p fun) (eq 'symbol-value (leaf-%source-name (ref-leaf fun))) (constant-lvar-p arg) (symbolp (lvar-value arg))) (record-xref :references (lvar-value arg) context node nil)))) (ref @@ -252,7 +252,8 @@ ;;; space-efficient form, and return that packed form. (defun pack-xref-data (xref-data) (unless xref-data (return-from pack-xref-data)) - (let* ((result (make-array 1 :adjustable t :fill-pointer 1)) + (let* ((result (make-array 1 :adjustable t :fill-pointer 1 + :initial-element 0)) (ensure-index (name->index result)) (entries '()) (max-index 0) @@ -287,7 +288,7 @@ (number-bits (integer-length max-number)) (encoder (index-and-number-encoder name-bits number-bits)) (vector (make-array 0 :element-type '(unsigned-byte 8) - :adjustable t :fill-pointer 0))) + :adjustable t :fill-pointer 0 :initial-element 0))) (write-var-integer name-bits vector) (write-var-integer number-bits vector) (loop for (kind-number . kind-entries) in entries @@ -299,7 +300,7 @@ do (dolist (number numbers) (write-var-integer (funcall encoder index number) vector)))) (setf (aref result 0) - (sb-xc:coerce vector '(simple-array (unsigned-byte 8) 1)))) + (coerce vector '(simple-array (unsigned-byte 8) 1)))) ;; RESULT is adjustable. Make it simple. (coerce result 'simple-vector))) diff --git a/src/interpreter/basic-env.lisp b/src/interpreter/basic-env.lisp index 688a34f4b5..5dd6e11b68 100644 --- a/src/interpreter/basic-env.lisp +++ b/src/interpreter/basic-env.lisp @@ -77,3 +77,61 @@ ;; as heck, since ENV-LEXENV could be reasonably construed as the function ;; that returns a compiler LEXENV corresponding to this BASIC-ENV. (contour nil :type decl-scope :read-only t)) + +;;; Some of these structures could be defined in warm load, but then they +;;; couldn't benefit from the assignment of a single-byte layout ID. +;;; (After self-build is complete, layout-ids are always 4 bytes.) + +;; Binding frame specification for LET and LET* +;; This is a prototype stack-frame rather than a runtime stack frame in that +;; one exists per syntactic form, not per dynamic invocation of same. +(defstruct (frame (:include decl-scope) + (:copier nil) (:predicate nil) + (:constructor make-let-frame + (declarations %policy + symbols special-b values sexpr specials))) + ;; If more symbols exist than values, the remainder are free specials. + (symbols nil :read-only t :type simple-vector) + ;; Bitmask over symbols. 1 in bit N means bind the Nth symbol as special. + (special-b nil :read-only t :type integer) + ;; A let frame can't have zero values. (It would be converted to LOCALLY) + (values nil :read-only t :type simple-vector) + (sexpr nil :read-only t) ; code to execute + ;; To avoid reconstituting the first PROGV operand from the special-b mask + ;; and vector of all bound symbols, store the bound specials as follows: + ;; for LET - a list of all bound specials + ;; for LET* - a list of singleton lists of bound specials + ;; for LAMBDA - possibly both of the preceding: a list for mandatory args + ;; and lists of singleton lists for &optional/&rest/&key. + (specials nil :read-only t)) + +;;; LET and LET* share the same frame structure +(defstruct (let*-frame + (:include frame) (:predicate nil) (:copier nil) + (:constructor make-let*-frame + (declarations %policy symbols special-b + values sexpr specials)))) + +;; Fancy binding frame specification +(defstruct (lambda-frame (:include let*-frame) (:predicate nil) (:copier nil)) + ;; Unlike for a LET* frame the count of bound values can not be determined + ;; from the length of the VALUES vector, which contains various extra markers + ;; dictating how the arguments are to be parsed. + (n-bound-vars 0 :read-only t :type fixnum) + ;; Number of mandatory and optional arguments. + (min-args 0 :read-only t :type fixnum) + (n-optional 0 :read-only t :type fixnum) + ;; Packed flags indicating presence of &REST/&KEY/&ALLOW-OTHER-KEYS. + (keyword-bits 0 :read-only t :type fixnum) + ;; A BLOCK name in which to wrap the lambda's evaluable forms. + ;; This behaves exactly the same as using a block-env around the forms, + ;; however a lambda-env consumes only 8 words plus 2 for the freshly consed + ;; catch tag; whereas a var-env + block-env would consume 6 + 6 + 2, which + ;; entails 40% more overhead to enter the most trivial interpreted function. + (block-name 0 :read-only t :type (or (eql 0) symbol)) + ;; SHARE-BLOCK-P is T if BLOCK-NAME can be created concurrently + ;; with variable bindings. If NIL when a block-name is present, + ;; then another environment is allocated to enclose the block, + ;; which is not as big a win as combining the block-env and var-env, + ;; but still beneficial as it avoids separately calling the block handler. + (share-block-p nil :read-only t :type boolean)) diff --git a/src/interpreter/env.lisp b/src/interpreter/env.lisp index fe25fbc410..178d9d3ff8 100644 --- a/src/interpreter/env.lisp +++ b/src/interpreter/env.lisp @@ -163,42 +163,12 @@ ;;; "scope" and "frame" are basically synonymous here. ;;; The existence of both terms is a minor accident. -;; Binding frame specification for LET and LET* -;; This is a prototype stack-frame rather than a runtime stack frame in that -;; one exists per syntactic form, not per dynamic invocation of same. -(defstruct (frame (:include decl-scope) - (:copier nil) (:predicate nil) - (:constructor make-let-frame - (declarations %policy - symbols special-b values sexpr specials))) - ;; If more symbols exist than values, the remainder are free specials. - (symbols nil :read-only t :type simple-vector) - ;; Bitmask over symbols. 1 in bit N means bind the Nth symbol as special. - (special-b nil :read-only t :type integer) - ;; A let frame can't have zero values. (It would be converted to LOCALLY) - (values nil :read-only t :type simple-vector) - (sexpr nil :read-only t) ; code to execute - ;; To avoid reconstituting the first PROGV operand from the special-b mask - ;; and vector of all bound symbols, store the bound specials as follows: - ;; for LET - a list of all bound specials - ;; for LET* - a list of singleton lists of bound specials - ;; for LAMBDA - possibly both of the preceding: a list for mandatory args - ;; and lists of singleton lists for &optional/&rest/&key. - (specials nil :read-only t)) - (defmethod print-object ((self frame) stream) (print-unreadable-object (self stream :type t :identity t))) (declaim (inline frame-size)) (defun frame-size (frame) (length (frame-values frame))) -;;; A LET* frame is just like a LET frame. -(defstruct (let*-frame - (:include frame) (:predicate nil) (:copier nil) - (:constructor make-let*-frame - (declarations %policy symbols special-b - values sexpr specials)))) - ;;; BASIC-ENV stores a policy for its body, but if evaluation has not reached ;;; the body forms of a LET*, then the old policy is in effect. This is due to ;;; the need for presenting a consistent view of the policy, but a frozen ENV @@ -215,30 +185,6 @@ (env-policy (env-parent env)) policy))))) -;; Fancy binding frame specification -(defstruct (lambda-frame (:include let*-frame) (:predicate nil) (:copier nil)) - ;; Unlike for a LET* frame the count of bound values can not be determined - ;; from the length of the VALUES vector, which contains various extra markers - ;; dictating how the arguments are to be parsed. - (n-bound-vars 0 :read-only t :type fixnum) - ;; Number of mandatory and optional arguments. - (min-args 0 :read-only t :type fixnum) - (n-optional 0 :read-only t :type fixnum) - ;; Packed flags indicating presence of &REST/&KEY/&ALLOW-OTHER-KEYS. - (keyword-bits 0 :read-only t :type fixnum) - ;; A BLOCK name in which to wrap the lambda's evaluable forms. - ;; This behaves exactly the same as using a block-env around the forms, - ;; however a lambda-env consumes only 8 words plus 2 for the freshly consed - ;; catch tag; whereas a var-env + block-env would consume 6 + 6 + 2, which - ;; entails 40% more overhead to enter the most trivial interpreted function. - (block-name 0 :read-only t :type (or (eql 0) symbol)) - ;; SHARE-BLOCK-P is T if BLOCK-NAME can be created concurrently - ;; with variable bindings. If NIL when a block-name is present, - ;; then another environment is allocated to enclose the block, - ;; which is not as big a win as combining the block-env and var-env, - ;; but still beneficial as it avoids separately calling the block handler. - (share-block-p nil :read-only t :type boolean)) - (defconstant +restp-bit+ #b100) (defconstant +keyp-bit+ #b010) (defconstant +allowp-bit+ #b001) @@ -346,7 +292,8 @@ (defmacro with-environment-vars ((symbols end) env &body body) `(awhen (env-symbols ,env) (let ((,symbols (truly-the simple-vector (if (listp it) (cdr it) it))) - (,end (locally (declare (optimize (safety 0))) (car it)))) + (,end #+ubsan (if (listp it) (car it) (sb-c::vector-length it)) + #-ubsan (locally (declare (optimize (safety 0))) (car it)))) (declare (index-or-minus-1 ,end)) ,@body))) (eval-when (:compile-toplevel) @@ -547,7 +494,7 @@ (values (proto-fn-%frame proto-fn) (proto-fn-cookie proto-fn)) (digest-lambda env proto-fn))) -(defun %fun-type (fun) +(defun %fun-ftype (fun) (let ((proto-fn (fun-proto-fn fun))) (or (proto-fn-type proto-fn) (setf (proto-fn-type proto-fn) @@ -893,7 +840,7 @@ ;; then insert assertions for all variables bound by this scope. (when (and (policy env (>= safety 1)) (find-if #'cdr symbols :end n-var-bindings)) - (let ((checks (make-array n-var-bindings))) + (let ((checks (make-array n-var-bindings :initial-element 0))) (dotimes (i n-var-bindings (setf (binding-typechecks decl-scope) checks)) (awhen (cdr (svref symbols i)) (setf (svref checks i) (type-checker it)))))) @@ -1143,7 +1090,9 @@ (specialize binding)) ((eq reason 'compile) ;; access interpreter's lexical vars - (macroize sym `(svref ,payload ,i))) + ;; Prevent SETF on the variable from getting + ;; "Destructive function (SETF SVREF) called on constant data" + (macroize sym `(svref (load-time-value ,payload) ,i))) (t (let ((leaf (make-lambda-var :%source-name sym diff --git a/src/interpreter/eval.lisp b/src/interpreter/eval.lisp index 5fd450f0b6..abb3bb8fab 100644 --- a/src/interpreter/eval.lisp +++ b/src/interpreter/eval.lisp @@ -66,6 +66,22 @@ (defparameter *eval-level* -1) (defparameter *eval-verbose* nil) +(defun special-form-handler (fname) + ;; Returns a cons of the deferred processor and immediate processor. + ;; The CDR can be NIL if there is no immediate handler. + (binding* ((info (symbol-dbinfo fname) :exit-if-null) + ;; This is safe: PACKED-INFO invariant requires that it have length >= 1. + (word (the fixnum (%info-ref info 0)))) + ;; Test that the first info-number is +fdefn-info-num+ and its n-infos + ;; field is nonzero. These conditions can be tested simultaneously + ;; using a SIMD-in-a-register idea. The low 6 bits must be nonzero + ;; and the next 6 must be exactly #b111111, so considered together + ;; as a 12-bit unsigned integer it must be >= #b111111000001 + (when (>= (ldb (byte (* info-number-bits 2) 0) word) + (1+ (ash +fdefn-info-num+ info-number-bits))) + (%info-ref info (1- (truly-the (integer 1 *) + (sb-impl::packed-info-len info))))))) + (defun %eval (exp env) (labels ((%%eval (&aux fname) @@ -97,15 +113,13 @@ ;; CLHS 3.1.2.1.2.1 Special Forms ;; Pick off special forms first for speed. Special operators ;; can't be shadowed by local defs. - ((logtest (get-header-data fname) +special-op-symbol+) - (cond ((or (logtest (get-header-data fname) +simple-special-op+) + ((test-header-data-bit fname +special-op-symbol+) + (cond ((or (test-header-data-bit fname +simple-special-op+) (eq sb-ext:*evaluator-mode* :interpret)) - (cond ((and (symbol-extra-slot-p fname) - (functionp (symbol-extra fname))) - (funcall (truly-the function (symbol-extra fname)) - (cdr exp) env)) - (t - (dispatch (%sexpr exp) env)))) + (let ((handler (cdr (special-form-handler fname)))) ; immediate handler + (if (functionp handler) + (funcall handler (cdr exp) env) + (dispatch (%sexpr exp) env)))) (t (compile-it)))) (t ; Everything else: macros and functions. @@ -168,7 +182,7 @@ (%program-error "Invalid function name: ~S" fname))) ;; CLHS 3.1.2.1.2.1 Special Forms. (when (logtest (get-header-data fname) +special-op-symbol+) - (let ((processor (info :function :interpreter fname))) + (let ((processor (car (special-form-handler fname)))) ; deferred handler (when (functionp processor) (return-from digest-form (let ((digested-form (funcall processor (cdr form) env))) @@ -237,6 +251,18 @@ ;; affect the policy in an interpreter environment. (%eval form interpreter-env)))) +;;; Return a handler that returns a constant. +;;; The %SEXPR constructor elides a handler for constants, +;;; but there are cases where NIL sneaks through and demands a callable handler. +;;; We avoid generating N copies of such handler. Same goes for 0 and T. +;;; Moved here as LOAD-TIME-VALUE has to happen after the file +;;; containing %HANDLER has been loaded. +(defun return-constant (object) + (cond ((null object) (load-time-value (handler #'%const nil))) + ((eq object t) (load-time-value (handler #'%const t))) + ((eql object 0) (load-time-value (handler #'%const 0))) + (t (handler #'%const object)))) + (push (let ((this-pkg (find-package "SB-INTERPRETER"))) `("SB-INTERPRETER" diff --git a/src/interpreter/macros.lisp b/src/interpreter/macros.lisp index 615efe4ca6..b54a0ad95c 100644 --- a/src/interpreter/macros.lisp +++ b/src/interpreter/macros.lisp @@ -79,14 +79,11 @@ (with-subforms ,macro-lambda-list ,form-var ,@body))))))) `((lambda (name simple immediate deferred) - (setf (info :function :interpreter name) deferred) - (when immediate - (aver (symbol-extra-slot-p name)) - (setf (symbol-extra name) immediate)) - (set-header-data + (aver (not (info :function :definition name))) + (setf (info :function :definition name) (cons deferred immediate)) + (logior-header-bits name (logior +special-op-symbol+ - (if simple +simple-special-op+ 0) - (get-header-data name)))) + (if simple +simple-special-op+ 0)))) ',name ',simple-p ,(when immediate-code diff --git a/src/interpreter/sexpr.lisp b/src/interpreter/sexpr.lisp index 6946841f38..27764c75d8 100644 --- a/src/interpreter/sexpr.lisp +++ b/src/interpreter/sexpr.lisp @@ -132,22 +132,12 @@ (declare (ignore env sexpr) #.+handler-optimize+) x) -;;; Return a handler that returns a constant. -;;; The %SEXPR constructor elides a handler for constants, -;;; but there are cases where NIL sneaks through and demands a callable handler. -;;; We avoid generating N copies of such handler. Same goes for 0 and T. -(defun return-constant (object) - (cond ((null object) (load-time-value (handler #'%const nil))) - ((eq object t) (load-time-value (handler #'%const t))) - ((eql object 0) (load-time-value (handler #'%const 0))) - (t (handler #'%const object)))) - (defun return-constant-values (values env sexpr) (declare (ignore env sexpr) #.+handler-optimize+) (values-list values)) ;; Forward defs -(declaim (ftype function digest-form %eval eval-setq)) +(declaim (ftype function digest-form %eval eval-setq reutrn-constant)) ;;; Return a SEXPR object that will, when dispatched, evaluate FORM. ;;; Unlike optimizations on SEXPRS whereby they install the most-specific @@ -916,7 +906,7 @@ Test case. (defun tracing-macroexpand-1 (form env &optional (predicate #'fluid-def-p) &aux (original-hook (valid-macroexpand-hook)) expanders) - (unless (allow-macro-redefinition env) + (unless (allow-macro-redef-p env) (return-from tracing-macroexpand-1 (values (macroexpand-1 form env) nil))) (flet ((macroexpand-hook (function form env) @@ -946,7 +936,7 @@ Test case. ;;; Return T if the evaluator should always consider that macros ;;; might be redefined. If NIL then cached expansions are permanent. -(defun allow-macro-redefinition (env) +(defun allow-macro-redef-p (env) (if (policy env (and (= speed 3) (= debug 0) (= safety 0))) nil t)) @@ -1050,56 +1040,60 @@ Test case. (pop tail))))))))) ;;; Apply what is probably a function - it was when the form was digested. -;;; This carefully mimics the compiler's behavior of referencing the -;;; function only after evaluation of its args. In particular, supposing that -;;; BAZ is not defined, this works in compiled code: -;;; (DEFUN FOO () (BAZ (SETF (SYMBOL-FUNCTION 'BAZ) (LAMBDA (X) `(HI ,X))))) +;;; This _might_ or might not mimic the compiler's behavior of referencing the +;;; function only after evaluation of its args. Consider an example: +;;; * (fmakunbound 'g) +;;; * (defun define-g () (setf (symbol-function 'g) #'print) *terminal-io*) +;;; * (defun f (x) (g (- x) (define-g))) +;;; * (f 3) +;;; +;;; sb-eval couldn't eval F because #'G is undefined when attempting to eval the +;;; head of the body form in F. But compiled code works fine, as the CAR of a +;;; combination node is accessed last. (Portable code shouldn't rely on that) ;;; -;;; Interpreted code needs an explicit check for NIL in an fdefn-fun. -;;; Compiled code doesn't because the 'raw-addr' slot is always -;;; something valid to jump to. -(defun apply-probably-fun (fdefinition args env &aux (n-args 0)) +;;; sb-fasteval similarly accepts it the backend has CALL-SYMBOL, but it works +;;; accidentally rather than on purpose now. #'G is looked up to see whether +;;; it is macro and then called normally if not. But if #'G is undefined, then G +;;; is invoked by name so that backtrace shows it. However, if CALL-SYMBOL isn't +;;; a thing, then F will fail at (%COERCE-CALLABLE-FOR-CALL 'G) +;;; It was surprising to me that %COERCE-CALLABLE-FOR-CALL is performed eagerly +;;; where CALL-SYMBOL doesn't exist. I would have figured it would be performed +;;; as late as possible, as if by CALL-SYMBOL. +(defun apply-probably-fun (name args env &aux (n-args 0)) + (declare (symbol name)) (multiple-value-setq (args n-args) (arglist-to-sexprs args)) (macrolet - ((funcall-n (n) - (let* ((arg-names (subseq '(a b c d e) 0 n)) - (bindings - (loop for arg in arg-names for i from 1 repeat n - collect `(,arg - (dispatch - ,(if (= n 1) '(cdr data) `(svref data ,i)) - env))))) - `(hlambda (GLOBAL-CALL ,n) (data) (env sexpr) - (symbol-macrolet ((fdefn ,(case n - (0 'data) - (1 '(car data)) - (t '(svref data 0))))) - (if (re-expand-p) - (digest-form (sexpr-form sexpr) env sexpr) - (let ,bindings - (funcall (sb-c:safe-fdefn-fun fdefn) ,@arg-names))))))) + ((funcall-n (n &aux (s (case n (0 'data) (1 '(car data)) (t '(svref data 0))))) + `(hlambda (GLOBAL-CALL ,n) (data) (env sexpr) + (let* ((symbol (truly-the symbol ,s)) + (function (or (%symbol-function symbol) symbol))) + (if (re-expand-p) + (digest-form (sexpr-form sexpr) env sexpr) + (funcall function + ,@(loop for i from 1 repeat n + collect `(dispatch ,(if (= n 1) '(cdr data) `(svref data ,i)) + env))))))) (generate-switch () `(case n-args - (0 (let ((data fdefinition)) (funcall-n 0))) - (1 (let ((data (cons fdefinition (first args)))) (funcall-n 1))) + (0 (let ((data name)) (funcall-n 0))) + (1 (let ((data (cons name (first args)))) (funcall-n 1))) (t - (let ((data (coerce (cons fdefinition args) 'vector))) + (let ((data (coerce (cons name args) 'vector))) (cases n-args (2 5 funcall-n) (t (hlambda GLOBAL-CALL (data) (env sexpr) (declare (simple-vector data)) - (symbol-macrolet ((fdefn (svref data 0))) + (let* ((symbol (truly-the symbol (svref data 0))) + (function (or (%symbol-function symbol) symbol))) (if (re-expand-p) (digest-form (sexpr-form sexpr) env sexpr) (let* ((arglist (make-list (1- (length data)))) (tail arglist)) - (dotimes (i (1- (length data)) - (apply (sb-c:safe-fdefn-fun fdefn) arglist)) + (dotimes (i (1- (length data)) (apply function arglist)) (rplaca tail (dispatch (svref data (1+ i)) env)) (pop tail))))))))))))) - (if (allow-macro-redefinition env) + (if (allow-macro-redef-p env) (macrolet ((re-expand-p () - '(let ((f (fdefn-fun fdefn))) - (and f (sb-impl::macro/special-guard-fun-p f))))) + '(and (functionp function) (sb-impl::macro/special-guard-fun-p function)))) (generate-switch)) (macrolet ((re-expand-p () nil)) (generate-switch))))) @@ -1180,17 +1174,18 @@ Test case. (setf (debug-source-namestring source) (sb-kernel::function-file-namestring f) (debug-source-created source) nil) ; = unknown - ;; Clobber the TLF-NUM + OFFSET. We should do better that that, - ;; but interpreted functions do not track their file offset, - ;; so the conservative thing is to plug in NILs, not bogus values - ;; from whatever file (if any) is currently being loaded. - (setf (sb-c::compiled-debug-info-tlf-num+offset cdi) 0) - (setf (symbol-function fname) compiled-fun))))) + ;; Skirt a package lock by avoiding (SETF SYMBOL-FUNCTION) + ;; *technically* this should be a compare-and-swap to ensure that the + ;; original lambda expression is as expected. To do that, we need + ;; to get to the point where fdefns do not store "both" representations + ;; of one function pointer, because we can't assume that multi-word CAS + ;; is a thing. Or use a mutex (horrible). + (setf (%symbol-function fname) compiled-fun))))) (when (fluid-def-p fname) ;; Return a handler that calls FNAME very carefully (return-from digest-global-call - (apply-probably-fun (find-or-create-fdefn fname) args env)))) + (apply-probably-fun fname args env)))) ;; Try to recognize (FUNCALL constant-fun ...) ;; This syntax is required when using SETF functions, and it should diff --git a/src/interpreter/special-forms.lisp b/src/interpreter/special-forms.lisp index d0fb9153a7..02be6f013f 100644 --- a/src/interpreter/special-forms.lisp +++ b/src/interpreter/special-forms.lisp @@ -9,9 +9,6 @@ (in-package "SB-INTERPRETER") -(eval-when (:compile-toplevel :load-toplevel :execute) - (shadow "SYMEVAL")) - ;;; Return a THE form that wraps EXPRESSION, but if CTYPE is NIL, ;;; just return EXPRESSION. (defun cast-to (ctype expression) @@ -308,7 +305,7 @@ (if (policy env (> speed safety)) (%eval form env) (let ((type (parse-type type-specifier))) - (multiple-value-call (if (sb-kernel::%values-type-p type) + (multiple-value-call (if (sb-kernel::values-type-p type) #'enforce-values-types #'enforce-single-type) type (%eval form env)))) @@ -319,7 +316,7 @@ (if (eq type *universal-type*) ; don't type-check if T (handler #'digest-form form) (let ((form (%sexpr form))) - (if (sb-kernel::%values-type-p type) + (if (sb-kernel::values-type-p type) (hlambda THE/MULTI (type form) (env) (multiple-value-call #'enforce-values-types type (dispatch form env))) @@ -806,7 +803,7 @@ ,@(when (eq operator 'let*) `((when (singleton-p bindings) (return-from let* - (funcall (info :function :interpreter 'let) + (funcall (car (special-form-handler 'let)) `(,bindings ,@body) env))))) ;; FIXME: aren't MAKE-LET*-FRAME and MAKE-LET-FRAME essentially ;; the same now? @@ -1151,22 +1148,23 @@ (make-proto-fn name)) (multiple-value-bind (kind definition frame-ptr) (find-lexical-fun env name) - (if definition - (if (eq kind :macro) - (not-a-function name) - (hlambda FUNCTION (frame-ptr) (env) - (local-fdefinition frame-ptr env))) + (cond (definition ; lexical function + (if (eq kind :macro) + (not-a-function name) + (hlambda FUNCTION (frame-ptr) (env) + (local-fdefinition frame-ptr env)))) ;; Consider (DEFUN GET-THING () #'THING) - it shouldn't return ;; THING's error trampoline if THING is redefined after ;; GET-THING was called once. - (let ((fdefn (find-or-create-fdefn name))) - (if (symbolp name) ; could be a macro - (hlambda FUNCTION (fdefn) (env) - (declare (ignore env)) - (let ((fun (sb-c:safe-fdefn-fun fdefn))) - (if (sb-impl::macro/special-guard-fun-p fun) - (not-a-function (fdefn-name fdefn)) - fun))) + ((symbolp name) ; could be a macro + (hlambda FUNCTION (name) (env) + (declare (ignore env)) + (let ((fun (%symbol-function name))) + (if (or (not fun) (sb-impl::macro/special-guard-fun-p fun)) + (not-a-function name) + fun)))) + (t + (let ((fdefn (find-or-create-fdefn name))) (hlambda FUNCTION (fdefn) (env) ; could not be a macro (declare (ignore env)) (sb-c:safe-fdefn-fun fdefn))))))))) @@ -1206,7 +1204,7 @@ ;; hand-generated lists of useful functions (setq *unary-functions* (sb-impl::%stuff-hash-table - (make-hash-table :test #'eq) + (make-hash-table) ; keys are symbols (macrolet ((def-wrapper (&rest input) (cons 'list @@ -1286,7 +1284,7 @@ (setq *binary-functions* (sb-impl::%stuff-hash-table - (make-hash-table :test #'eq) + (make-hash-table) ; keys are symbols (macrolet ((def-wrapper (&rest input) (cons 'list diff --git a/src/pcl/boot.lisp b/src/pcl/boot.lisp index 040d2e9625..15cdc53f56 100644 --- a/src/pcl/boot.lisp +++ b/src/pcl/boot.lisp @@ -250,7 +250,7 @@ bootstrapping. (defmacro defgeneric (fun-name lambda-list &body options) (declare (type list lambda-list)) - (check-designator fun-name defgeneric) + (check-designator fun-name 'defgeneric #'legal-fun-name-p "function name") (with-current-source-form (lambda-list) (check-gf-lambda-list lambda-list)) (let ((initargs ()) @@ -355,7 +355,9 @@ bootstrapping. ;; except that it doesn't clear an :ASSUMED-TYPE. Should it? (setf (info :function :where-from fun-name) :defined) (setf (info :function :type fun-name) - (specifier-type 'function)))) + (if (eq **boot-state** 'complete) + :generic-function + (specifier-type 'function))))) (defun load-defgeneric (fun-name lambda-list source-location &rest initargs) (when (fboundp fun-name) @@ -401,7 +403,9 @@ bootstrapping. ;; incorrect use of defaults. (labels ((lose (kind arg) (generic-function-lambda-list-error - "~@<Invalid ~A argument specifier ~S ~_in ~A ~:S~:>" + (sb-format:tokens + "~@<Invalid ~A argument specifier ~S ~_in ~A ~ + ~/sb-impl:print-lambda-list/~:>") kind arg context lambda-list)) (verify-optional (spec) (when (nth-value 3 (parse-optional-arg-spec spec)) @@ -429,7 +433,7 @@ bootstrapping. ;;; which means that checking of callers' arglists can only occur after called ;;; methods are actually loaded. (defmacro defmethod (name &rest args) - (check-designator name defmethod) + (check-designator name 'defmethod #'legal-fun-name-p "function name") (multiple-value-bind (qualifiers lambda-list body) (parse-defmethod args) `(progn @@ -530,7 +534,9 @@ bootstrapping. (method-lambda `(lambda ,unspecialized-lambda-list (declare (sb-c::source-form (lambda ,unspecialized-lambda-list - ,@body))) + ,@body)) + (sb-c::current-defmethod ,name ,qualifiers ,specializers + ,unspecialized-lambda-list)) ,@body)) ((method-function-lambda initargs new-lambda-list) (make-method-lambda-using-specializers @@ -756,7 +762,7 @@ bootstrapping. ;; perhaps because of the way that STRUCTURE-OBJECT inherits ;; both from SLOT-OBJECT and from SB-KERNEL:INSTANCE. In an ;; effort to sweep such problems under the rug, we exclude these - ;; problem cases by blacklisting them here. -- WHN 2001-01-19 + ;; problem cases here. -- WHN 2001-01-19 ((eq specializer 'slot-object) (declare-type nil)) @@ -1335,7 +1341,7 @@ bootstrapping. (defstruct (constant-method-call (:copier nil) (:include method-call)) value) -#-sb-fluid (declaim (sb-ext:freeze-type method-call)) +(declaim (sb-ext:freeze-type method-call)) (defmacro invoke-method-call1 (function args cm-args) `(let ((.function. ,function) @@ -1352,16 +1358,11 @@ bootstrapping. `(list ,@required-args+rest-arg)) (method-call-call-method-args ,method-call))) -(defstruct (fast-method-call (:copier nil)) - (function #'identity :type function) - pv - next-method-call - arg-info) (defstruct (constant-fast-method-call (:copier nil) (:include fast-method-call)) value) -#-sb-fluid (declaim (sb-ext:freeze-type fast-method-call)) +(declaim (sb-ext:freeze-type fast-method-call)) ;; The two variants of INVOKE-FAST-METHOD-CALL differ in how REST-ARGs ;; are handled. The first one will get REST-ARG as a single list (as @@ -1391,9 +1392,13 @@ bootstrapping. ;; a factor of 2 with very little effect on the other ;; cases. Though it'd be nice to have the generic case be equally ;; fast. + ;; This is enough hardwired cases to handle the 0, 1, or 2 optional + ;; arguments to STREAM-WRITE-STRING. If you change anything about this, + ;; make sure to benchmark it. `(case ,more-count (0 ,(generate-call 0)) (1 ,(generate-call 1)) + (2 ,(generate-call 2)) (t (multiple-value-call (fast-method-call-function ,method-call) (values (fast-method-call-pv ,method-call)) (values (fast-method-call-next-method-call ,method-call)) @@ -1403,7 +1408,7 @@ bootstrapping. (defstruct (fast-instance-boundp (:copier nil)) (index 0 :type fixnum)) -#-sb-fluid (declaim (sb-ext:freeze-type fast-instance-boundp)) +(declaim (sb-ext:freeze-type fast-instance-boundp)) (eval-when (:compile-toplevel :load-toplevel :execute) (defvar *allow-emf-call-tracing-p* nil) @@ -1570,14 +1575,14 @@ bootstrapping. (fixnum (cond ((null args) (%program-error "invalid number of arguments: 0")) - ((null (cdr args)) + ((and (not (minusp emf)) (null (cdr args))) (let* ((slots (get-slots (car args))) (value (clos-slots-ref slots emf))) (if (unbound-marker-p value) (slot-unbound-internal (car args) emf) value))) - ((null (cddr args)) - (setf (clos-slots-ref (get-slots (cadr args)) emf) + ((and (minusp emf) (not (null (cdr args))) (null (cddr args))) + (setf (clos-slots-ref (get-slots (cadr args)) (lognot emf)) (car args))) (t (%program-error "invalid number of arguments")))) (fast-instance-boundp @@ -1649,48 +1654,6 @@ bootstrapping. (let ,rebindings ,@body))))) -;;; CMUCL comment (Gerd Moellmann): -;;; -;;; The standard says it's an error if CALL-NEXT-METHOD is called with -;;; arguments, and the set of methods applicable to those arguments is -;;; different from the set of methods applicable to the original -;;; method arguments. (According to Barry Margolin, this rule was -;;; probably added to ensure that before and around methods are always -;;; run before primary methods.) -;;; -;;; This could be optimized for the case that the generic function -;;; doesn't have hairy methods, does have standard method combination, -;;; is a standard generic function, there are no methods defined on it -;;; for COMPUTE-APPLICABLE-METHODS and probably a lot more of such -;;; preconditions. That looks hairy and is probably not worth it, -;;; because this check will never be fast. -(defun %check-cnm-args (cnm-args orig-args method-cell) - ;; 1. Check for no arguments. - (when cnm-args - (let* ((gf (method-generic-function (car method-cell))) - (nreq (generic-function-nreq gf))) - (declare (fixnum nreq)) - ;; 2. Requirement arguments pairwise: if all are EQL, the applicable - ;; methods must be the same. This takes care of the relatively common - ;; case of twiddling with &KEY arguments without being horribly - ;; expensive. - (unless (do ((orig orig-args (cdr orig)) - (args cnm-args (cdr args)) - (n nreq (1- nreq))) - ((zerop n) t) - (unless (and orig args (eql (car orig) (car args))) - (return nil))) - ;; 3. Only then do the full check. - (let ((omethods (compute-applicable-methods gf orig-args)) - (nmethods (compute-applicable-methods gf cnm-args))) - (unless (equal omethods nmethods) - (error "~@<The set of methods ~S applicable to argument~P ~ - ~{~S~^, ~} to call-next-method is different from ~ - the set of methods ~S applicable to the original ~ - method argument~P ~{~S~^, ~}.~@:>" - nmethods (length cnm-args) cnm-args omethods - (length orig-args) orig-args))))))) - ;; FIXME: replacing this entire mess with DESTRUCTURING-BIND would correct ;; problems similar to those already solved by a correct implementation ;; of DESTRUCTURING-BIND, such as incorrect binding order: @@ -1788,6 +1751,21 @@ bootstrapping. ;; modified in the method body. (parameters-setqd nil)) (flet ((walk-function (form context env) + (when (eq context :set) + (let ((var form)) + ;; PCL uses "poor man's constraint propagation" - it starts by assuming + ;; that each specialized parameter has a known type. If any SETQ on it + ;; occurs in a method body, the assumption is dropped for the entire body. + ;; Needless to say, it's horrible and could do much better by initially + ;; binding all specialized parameters thusly: + ;; (let ((arg1 (truly-the specialization1 arg1)) + ;; (arg2 (truly-the specialization2 arg2)) ... + ;; and then having ordinary transforms kick in. + (when (var-declaration '%parameter var env) + ;; If a parameter is shadowed by another binding it won't have a + ;; %PARAMETER declaration. + (pushnew var parameters-setqd :test #'eq))) + (return-from walk-function form)) (unless (and (eq context :eval) (consp form)) (return-from walk-function form)) (case (car form) @@ -1796,27 +1774,6 @@ bootstrapping. (unless (eq call-next-method-p t) (setq call-next-method-p (if (cdr form) t :simple))) form) - ((setq multiple-value-setq) - ;; The walker will split (SETQ A 1 B 2) to - ;; separate (SETQ A 1) and (SETQ B 2) forms, so we - ;; only need to handle the simple case of SETQ - ;; here. - (let ((vars (if (eq (car form) 'setq) - (list (second form)) - (second form)))) - (dolist (var vars) - ;; Note that we don't need to check for - ;; %VARIABLE-REBINDING declarations like is - ;; done in CAN-OPTIMIZE-ACCESS1, since the - ;; bindings that will have that declation will - ;; never be SETQd. - (when (var-declaration '%parameter var env) - ;; If a parameter binding is shadowed by - ;; another binding it won't have a - ;; %PARAMETER declaration anymore, and this - ;; won't get executed. - (pushnew var parameters-setqd :test #'eq)))) - form) (function (when (equal (cdr form) '(call-next-method)) (setq call-next-method-p t)) @@ -1827,11 +1784,9 @@ bootstrapping. (slot-value #'optimize-slot-value) (set-slot-value #'optimize-set-slot-value) (slot-boundp #'optimize-slot-boundp)))) - `(sb-c::with-source-form ,form - ,(funcall fun form slots required-parameters env))) + (funcall fun form slots required-parameters env)) form)) (t form)))) - (let* ((sb-walker::*walk-form-preserve-source* t) (walked-lambda (walk-form method-lambda env #'walk-function))) ;;; FIXME: the walker's rewriting of the source code causes @@ -1878,18 +1833,29 @@ bootstrapping. (defun load-defmethod-internal (method-class gf-spec qualifiers specializers lambda-list initargs source-location) - (when (and (eq **boot-state** 'complete) - (fboundp gf-spec)) - (let* ((gf (fdefinition gf-spec)) - (method (and (generic-function-p gf) - (generic-function-methods gf) - (find-method gf qualifiers specializers nil)))) - (when method - (warn 'sb-kernel:redefinition-with-defmethod - :name gf-spec - :new-location source-location - :old-method method - :qualifiers qualifiers :specializers specializers)))) + (block nil + (when (and (eq **boot-state** 'complete) + (fboundp gf-spec)) + (restart-bind + ((continue (lambda () + (fmakunbound gf-spec) + (return)) + :report-function + (lambda (stream) + (format stream "Unbind the generic function")) + :test-function + (lambda (c) + (typep c 'find-method-length-mismatch)))) + (let* ((gf (fdefinition gf-spec)) + (method (and (generic-function-p gf) + (generic-function-methods gf) + (find-method gf qualifiers specializers nil)))) + (when method + (warn 'sb-kernel:redefinition-with-defmethod + :name gf-spec + :new-location source-location + :old-method method + :qualifiers qualifiers :specializers specializers)))))) (let ((method (apply #'add-named-method gf-spec qualifiers specializers lambda-list 'source source-location @@ -2013,12 +1979,6 @@ bootstrapping. macro.~@:>") :format-arguments (list fun-name))) -(define-load-time-global *sgf-wrapper* - (!boot-make-wrapper (!early-class-size 'standard-generic-function) - 'standard-generic-function - nil - #+immobile-code +machine-code-embedding-fsc-instance-bitmap+)) - (define-load-time-global *sgf-slots-init* (mapcar (lambda (canonical-slot) (if (memq (getf canonical-slot :name) '(arg-info source)) @@ -2074,9 +2034,11 @@ bootstrapping. gf-info-static-c-a-m-emf (gf-info-c-a-m-emf-std-p t) - gf-info-fast-mf-p) + gf-info-fast-mf-p -#-sb-fluid (declaim (sb-ext:freeze-type arg-info)) + gf-info-cnm-checker) + +(declaim (sb-ext:freeze-type arg-info)) (defun arg-info-valid-p (arg-info) (not (null (arg-info-number-optional arg-info)))) @@ -2129,9 +2091,10 @@ bootstrapping. (= nopt gf-nopt) (eq (ll-keyp-or-restp llks) gf-key/rest-p)) (restart-case - (error "New lambda-list ~S is incompatible with ~ - existing methods of ~S.~%~ - Old lambda-list ~s" + (error (sb-format:tokens + "New lambda-list ~/sb-impl:print-lambda-list/ is ~ + incompatible with existing methods of ~S.~%~ + Old lambda-list ~/sb-impl:print-lambda-list/") lambda-list gf (arg-info-lambda-list arg-info)) (continue () :report "Remove all methods." @@ -2212,16 +2175,6 @@ bootstrapping. (!bootstrap-slot-index 'global-writer-method s) (!bootstrap-slot-index 'global-boundp-method s)))) -(defconstant-eqx +standard-method-class-names+ - '(standard-method standard-reader-method - standard-writer-method standard-boundp-method - global-reader-method global-writer-method - global-boundp-method) - #'equal) - -(declaim (list **standard-method-classes**)) -(defglobal **standard-method-classes** nil) - (defun safe-method-specializers (method) (if (member (class-of method) **standard-method-classes** :test #'eq) (clos-slots-ref (std-instance-slots method) +sm-specializers-index+) @@ -2295,11 +2248,12 @@ bootstrapping. ((and (consp name) (member (car name) *internal-pcl-generalized-fun-name-symbols*)) - nil) + nil) (t (let* ((symbol (fun-name-block-name name)) - (package (symbol-package symbol))) - (and (or (eq package *pcl-package*) - (memq package (package-use-list *pcl-package*))) + (package (symbol-package symbol)) + (pcl-package #.(find-package "SB-PCL"))) + (and (or (eq package pcl-package) + (memq package (package-use-list pcl-package))) (not (eq package *cl-package*)) ;; FIXME: this test will eventually be ;; superseded by the *internal-pcl...* test, @@ -2365,7 +2319,7 @@ bootstrapping. (let ((fin (allocate-standard-funcallable-instance *sgf-wrapper* name))) (replace (fsc-instance-slots fin) *sgf-slots-init*) (when function - (set-funcallable-instance-function fin function)) + (setf (%funcallable-instance-fun fin) function)) (setf (gdefinition name) fin) (!bootstrap-set-slot 'standard-generic-function fin 'name name) (!bootstrap-set-slot 'standard-generic-function fin @@ -2404,8 +2358,7 @@ bootstrapping. (cond ((eq **boot-state** 'complete) ;; Check that we are under the lock. - #+sb-thread - (aver (eq sb-thread:*current-thread* (sb-thread:mutex-owner (gf-lock gf)))) + #+sb-thread (aver (sb-thread:holding-mutex-p (gf-lock gf))) (setf (safe-gf-dfun-state gf) new-state)) (t (setf (clos-slots-ref (get-slots gf) +sgf-dfun-state-index+) @@ -2626,18 +2579,22 @@ bootstrapping. (result (list :early-method + ;; SECOND (getf initargs :function) + ;; THIRD (let ((mf (getf initargs :function))) (aver mf) (and (typep mf '%method-function) (%method-function-fast-function mf))) + ;; FOURTH ;; the parsed specializers. This is used by ;; EARLY-METHOD-SPECIALIZERS to cache the parse. ;; Note that this only comes into play when there is ;; more than one early method on an early gf. parsed + ;; FIFTH ;; A list to which REAL-MAKE-A-METHOD can be applied ;; to make a real method corresponding to this early ;; one. @@ -2647,7 +2604,10 @@ bootstrapping. (when slot-name (list :slot-name slot-name :object-class object-class :method-class-function method-class-function)) - (list 'source source))))) + (list 'source source)) + + ;; SIXTH + (cons nil nil)))) (initialize-method-function initargs result) result)) @@ -2860,10 +2820,11 @@ bootstrapping. (function-header (sb-kernel:fun-code-header function-object)) (debug-info (sb-kernel:%code-debug-info function-header)) (debug-source (sb-c::debug-info-source debug-info)) - (debug-fun (debug-info-debug-function function debug-info))) + (debug-fun (debug-info-debug-function function debug-info)) + (tlf (and debug-fun (sb-c::compiled-debug-fun-tlf-number debug-fun)))) (sb-c::%make-definition-source-location (sb-c::debug-source-namestring debug-source) - (sb-c::compiled-debug-info-tlf-number debug-info) + tlf (sb-c::compiled-debug-fun-form-number debug-fun)))) (debug-info-debug-function (function debug-info) @@ -2900,19 +2861,6 @@ bootstrapping. (/show "leaving !FIX-EARLY-GENERIC-FUNCTIONS")) -;;; PARSE-DEFMETHOD is used by DEFMETHOD to parse the &REST argument -;;; into the 'real' arguments. This is where the syntax of DEFMETHOD -;;; is really implemented. -(defun parse-defmethod (cdr-of-form) - (declare (list cdr-of-form)) - (let ((qualifiers ()) - (spec-ll ())) - (loop (if (and (car cdr-of-form) (atom (car cdr-of-form))) - (push (pop cdr-of-form) qualifiers) - (return (setq qualifiers (nreverse qualifiers))))) - (setq spec-ll (pop cdr-of-form)) - (values qualifiers spec-ll cdr-of-form))) - (defun parse-specializers (generic-function specializers) (declare (list specializers)) (flet ((parse (spec) @@ -2933,46 +2881,6 @@ bootstrapping. (def 1 extract-lambda-list) (def 2 extract-specializer-names)) -(define-condition specialized-lambda-list-error - (reference-condition simple-program-error) - () - (:default-initargs :references '((:ansi-cl :section (3 4 3))))) - -(defun specialized-lambda-list-error (format-control &rest format-arguments) - (error 'specialized-lambda-list-error - :format-control format-control - :format-arguments format-arguments)) - -;; Return 3 values: -;; - the bound variables, without defaults, supplied-p vars, or &AUX vars. -;; - the lambda list without specializers. -;; - just the specializers -(defun parse-specialized-lambda-list (arglist) - (binding* (((llks specialized optional rest key aux) - (parse-lambda-list - arglist - :context 'defmethod - :accept (lambda-list-keyword-mask - '(&optional &rest &key &allow-other-keys &aux)) - :silent t ; never signal &OPTIONAL + &KEY style-warning - :condition-class 'specialized-lambda-list-error)) - (required (mapcar (lambda (x) (if (listp x) (car x) x)) specialized)) - (specializers (mapcar (lambda (x) (if (listp x) (cadr x) t)) specialized))) - (check-lambda-list-names - llks required optional rest key aux nil nil - :context "a method lambda list" :signal-via #'specialized-lambda-list-error) - (values (append required - (mapcar #'parse-optional-arg-spec optional) - rest - ;; Preserve keyword-names when given as (:KEYWORD var) - (mapcar (lambda (x) - (if (typep x '(cons cons)) - (car x) - (parse-key-arg-spec x))) - key)) - (make-lambda-list llks nil required optional rest key aux) - specializers))) - (setq **boot-state** 'early) ;;; FIXME: In here there was a #-CMU definition of SYMBOL-MACROLET diff --git a/src/pcl/braid.lisp b/src/pcl/braid.lisp index 964b9c3ba2..16bec02fdb 100644 --- a/src/pcl/braid.lisp +++ b/src/pcl/braid.lisp @@ -30,414 +30,6 @@ ;;;; specification. (in-package "SB-PCL") - -(defun allocate-standard-instance (wrapper) - (let* ((instance (%make-instance (1+ sb-vm:instance-data-start))) - (slots (make-array (layout-length wrapper) :initial-element +slot-unbound+))) - (setf (%instance-layout instance) wrapper) - (setf (std-instance-slots instance) slots) - instance)) - -(define-condition unset-funcallable-instance-function - (reference-condition simple-error) - () - (:default-initargs - :references '((:amop :generic-function allocate-instance) - (:amop :function set-funcallable-instance-function)))) - -(defun allocate-standard-funcallable-instance (wrapper name) - (declare (layout wrapper)) - (let* ((hash (if name - (mix (sxhash name) (sxhash :generic-function)) ; arb. constant - (sb-impl::quasi-random-address-based-hash - (load-time-value (make-array 1 :element-type '(and fixnum unsigned-byte))) - most-positive-fixnum))) - (slots (make-array (layout-length wrapper) :initial-element +slot-unbound+)) - (fin (cond #+(and immobile-code) - ((/= (layout-bitmap wrapper) +layout-all-tagged+) - (let ((f (truly-the funcallable-instance - (sb-vm::make-immobile-funinstance wrapper slots)))) - ;; set the upper 4 bytes of wordindex 5 - (sb-sys:with-pinned-objects (f) - (setf (sb-impl::fsc-instance-trailer-hash f) (ldb (byte 32 0) hash))) - f)) - (t - (let ((f (truly-the funcallable-instance - (%make-standard-funcallable-instance slots hash)))) - (setf (%fun-layout f) wrapper) - f))))) - (set-funcallable-instance-function - fin - #'(lambda (&rest args) - (declare (ignore args)) - (error 'unset-funcallable-instance-function - :format-control "~@<The function of funcallable instance ~ - ~S has not been set.~@:>" - :format-arguments (list fin)))) - fin)) - -(defun classify-slotds (slotds) - (let (instance-slots class-slots custom-slots bootp) - (dolist (slotd slotds) - (let ((alloc (cond ((consp slotd) ; bootstrap - (setf bootp t) - :instance) - (t - (slot-definition-allocation slotd))))) - (case alloc - (:instance - (push slotd instance-slots)) - (:class - (push slotd class-slots)) - (t - (push slotd custom-slots))))) - (values (if bootp - (nreverse instance-slots) - (when slotds - (sort instance-slots #'< :key #'slot-definition-location))) - class-slots - custom-slots))) - -;;;; BOOTSTRAP-META-BRAID -;;;; -;;;; This function builds the base metabraid from the early class definitions. - -(defmacro !initial-classes-and-wrappers (&rest classes) - `(progn - ,@(mapcar (lambda (class) - (let ((wr (format-symbol *pcl-package* "~A-WRAPPER" class))) - `(setf ,wr ,(if (eq class 'standard-generic-function) - '*sgf-wrapper* - `(!boot-make-wrapper - (!early-class-size ',class) - ',class)) - ,class (allocate-standard-instance - ,(if (eq class 'standard-generic-function) - 'funcallable-standard-class-wrapper - 'standard-class-wrapper)) - (wrapper-class ,wr) ,class - (find-class ',class) ,class))) - classes))) - -(defun !wrapper-p (x) (and (sb-kernel::layout-p x) (layout-for-pcl-obj-p x))) - -(defun !bootstrap-meta-braid () - (let* ((*create-classes-from-internal-structure-definitions-p* nil) - standard-class-wrapper standard-class - funcallable-standard-class-wrapper funcallable-standard-class - slot-class-wrapper slot-class - system-class-wrapper system-class - built-in-class-wrapper built-in-class - structure-class-wrapper structure-class - condition-class-wrapper condition-class - standard-direct-slot-definition-wrapper - standard-direct-slot-definition - standard-effective-slot-definition-wrapper - standard-effective-slot-definition - class-eq-specializer-wrapper class-eq-specializer - standard-generic-function-wrapper standard-generic-function) - (!initial-classes-and-wrappers - standard-class funcallable-standard-class - slot-class system-class built-in-class structure-class condition-class - standard-direct-slot-definition standard-effective-slot-definition - class-eq-specializer standard-generic-function) - ;; First, make a class metaobject for each of the early classes. For - ;; each metaobject we also set its wrapper. Except for the class T, - ;; the wrapper is always that of STANDARD-CLASS. - (dolist (definition *!early-class-definitions*) - (let* ((name (ecd-class-name definition)) - (meta (ecd-metaclass definition)) - (wrapper (ecase meta - (slot-class slot-class-wrapper) - (standard-class standard-class-wrapper) - (funcallable-standard-class - funcallable-standard-class-wrapper) - (built-in-class built-in-class-wrapper) - (system-class system-class-wrapper) - (structure-class structure-class-wrapper) - (condition-class condition-class-wrapper))) - (class (or (find-class name nil) - (allocate-standard-instance wrapper)))) - (setf (find-class name) class))) - (dolist (definition *!early-class-definitions*) - (let ((name (ecd-class-name definition)) - (meta (ecd-metaclass definition)) - (source (ecd-source-location definition)) - (direct-supers (ecd-superclass-names definition)) - (direct-slots (ecd-canonical-slots definition)) - (other-initargs (ecd-other-initargs definition))) - (let ((direct-default-initargs - (getf other-initargs :direct-default-initargs))) - (multiple-value-bind (slots cpl default-initargs direct-subclasses) - (!early-collect-inheritance name) - (let* ((class (find-class name)) - (wrapper (cond ((eq class slot-class) - slot-class-wrapper) - ((eq class standard-class) - standard-class-wrapper) - ((eq class funcallable-standard-class) - funcallable-standard-class-wrapper) - ((eq class standard-direct-slot-definition) - standard-direct-slot-definition-wrapper) - ((eq class - standard-effective-slot-definition) - standard-effective-slot-definition-wrapper) - ((eq class system-class) system-class-wrapper) - ((eq class built-in-class) - built-in-class-wrapper) - ((eq class structure-class) - structure-class-wrapper) - ((eq class condition-class) - condition-class-wrapper) - ((eq class class-eq-specializer) - class-eq-specializer-wrapper) - ((eq class standard-generic-function) - standard-generic-function-wrapper) - (t - (!boot-make-wrapper (length slots) name)))) - (proto nil)) - (let ((symbol (make-class-symbol name))) - (when (eq (info :variable :kind symbol) :global) - (set symbol class))) - (dolist (slot slots) - (unless (eq (getf slot :allocation :instance) :instance) - (error "Slot allocation ~S is not supported in bootstrap." - (getf slot :allocation)))) - - (when (!wrapper-p wrapper) - (setf (layout-slot-list wrapper) slots)) - - (setq proto (if (eq meta 'funcallable-standard-class) - (allocate-standard-funcallable-instance wrapper name) - (allocate-standard-instance wrapper))) - - (setq direct-slots - (!bootstrap-make-slot-definitions - name class direct-slots - standard-direct-slot-definition-wrapper nil)) - (setq slots - (!bootstrap-make-slot-definitions - name class slots - standard-effective-slot-definition-wrapper t)) - - (setf (layout-slot-table wrapper) (make-slot-table class slots t)) - (when (!wrapper-p wrapper) - (setf (layout-slot-list wrapper) slots)) - - (case meta - ((standard-class funcallable-standard-class) - (!bootstrap-initialize-class - meta - class name class-eq-specializer-wrapper source - direct-supers direct-subclasses cpl wrapper proto - direct-slots slots direct-default-initargs default-initargs)) - (built-in-class ; *the-class-t* - (!bootstrap-initialize-class - meta - class name class-eq-specializer-wrapper source - direct-supers direct-subclasses cpl wrapper proto)) - (system-class - (!bootstrap-initialize-class - meta - class name class-eq-specializer-wrapper source - direct-supers direct-subclasses cpl wrapper proto)) - (slot-class ; *the-class-slot-object* - (!bootstrap-initialize-class - meta - class name class-eq-specializer-wrapper source - direct-supers direct-subclasses cpl wrapper proto)) - (structure-class ; *the-class-structure-object* - (!bootstrap-initialize-class - meta - class name class-eq-specializer-wrapper source - direct-supers direct-subclasses cpl wrapper)) - (condition-class - (!bootstrap-initialize-class - meta - class name class-eq-specializer-wrapper source - direct-supers direct-subclasses cpl wrapper)))))))) - - (setq **standard-method-classes** - (mapcar (lambda (name) - (symbol-value (make-class-symbol name))) - +standard-method-class-names+)) - - (flet ((make-method-combination (class-name) - (let* ((class (find-class class-name)) - (wrapper (!bootstrap-get-slot - 'standard-class class 'wrapper)) - (instance (allocate-standard-instance wrapper))) - (flet ((set-slot (name value) - (!bootstrap-set-slot class-name instance name value))) - (values instance #'set-slot))))) - ;; Create the STANDARD method combination object. - (multiple-value-bind (method-combination set-slot) - (make-method-combination 'standard-method-combination) - (funcall set-slot 'source nil) - (funcall set-slot 'type-name 'standard) - (funcall set-slot 'options '()) - (funcall set-slot '%generic-functions (make-gf-hash-table)) - (funcall set-slot '%documentation "The standard method combination.") - (setq *standard-method-combination* method-combination)) - ;; Create an OR method combination object. - (multiple-value-bind (method-combination set-slot) - (make-method-combination 'short-method-combination) - (funcall set-slot 'source 'nil) - (funcall set-slot 'type-name 'or) - (funcall set-slot 'operator 'or) - (funcall set-slot 'identity-with-one-argument t) - (funcall set-slot '%generic-functions (make-gf-hash-table)) - (funcall set-slot '%documentation nil) - (funcall set-slot 'options '(:most-specific-first)) - (setq *or-method-combination* method-combination))))) - -;;; I have no idea why we care so much about being able to create an instance -;;; of STRUCTURE-OBJECT, when (almost) no other structure class in the system -;;; begins life such that MAKE-INSTANCE works on it. -;;; And ALLOCATE-INSTANCE seems to work fine anyway. e.g. you can call -;;; (ALLOCATE-INSTANCE (FIND-CLASS 'HASH-TABLE)). -;;; Anyway, see below in !BOOTSTRAP-INITIALIZE-CLASS where we refer to -;;; the name of this seemingly useless constructor function. -(defun |STRUCTURE-OBJECT class constructor| () - (sb-kernel:%make-structure-instance - #.(sb-kernel:find-defstruct-description 'structure-object) - nil)) - -;;; Initialize a class metaobject. -(defun !bootstrap-initialize-class - (metaclass-name class name - class-eq-wrapper source direct-supers direct-subclasses cpl wrapper - &optional - (proto nil proto-p) - direct-slots slots direct-default-initargs default-initargs) - (flet ((classes (names) (mapcar #'find-class names)) - (set-slot (slot-name value) - (!bootstrap-set-slot metaclass-name class slot-name value))) - (set-slot 'name name) - (set-slot 'finalized-p t) - (set-slot 'source source) - (set-slot 'safe-p nil) - (set-slot '%type (if (eq class (find-class t)) - t - ;; FIXME: Could this just be CLASS instead - ;; of `(CLASS ,CLASS)? If not, why not? - ;; (See also similar expression in - ;; SHARED-INITIALIZE :BEFORE (CLASS).) - `(class ,class))) - (set-slot 'class-eq-specializer - (let ((spec (allocate-standard-instance class-eq-wrapper))) - (!bootstrap-set-slot 'class-eq-specializer spec '%type - `(class-eq ,class)) - (!bootstrap-set-slot 'class-eq-specializer spec 'object - class) - spec)) - (set-slot '%class-precedence-list (classes cpl)) - (set-slot 'cpl-available-p t) - (set-slot 'can-precede-list (classes (cdr cpl))) - (set-slot 'incompatible-superclass-list nil) - (set-slot 'direct-superclasses (classes direct-supers)) - (set-slot 'direct-subclasses (classes direct-subclasses)) - (set-slot 'direct-methods (cons nil nil)) - (set-slot 'wrapper wrapper) - (set-slot '%documentation nil) - (set-slot 'plist - `(,@(and direct-default-initargs - `(direct-default-initargs ,direct-default-initargs)) - ,@(and default-initargs - `(default-initargs ,default-initargs)))) - (when (memq metaclass-name '(standard-class funcallable-standard-class - structure-class condition-class - slot-class)) - (set-slot 'direct-slots direct-slots) - (set-slot 'slots slots) - (setf (layout-slot-table wrapper) - (make-slot-table class slots - (member metaclass-name - '(standard-class funcallable-standard-class)))) - (when (!wrapper-p wrapper) - (setf (layout-slot-list wrapper) slots))) - - ;; For all direct superclasses SUPER of CLASS, make sure CLASS is - ;; a direct subclass of SUPER. Note that METACLASS-NAME doesn't - ;; matter here for the slot DIRECT-SUBCLASSES, since every class - ;; inherits the slot from class CLASS. - (dolist (super direct-supers) - (let* ((super (find-class super)) - (subclasses (!bootstrap-get-slot metaclass-name super - 'direct-subclasses))) - (cond ((unbound-marker-p subclasses) - (!bootstrap-set-slot metaclass-name super 'direct-subclasses - (list class))) - ((not (memq class subclasses)) - (!bootstrap-set-slot metaclass-name super 'direct-subclasses - (cons class subclasses)))))) - - (case metaclass-name - (structure-class - (let ((constructor-sym '|STRUCTURE-OBJECT class constructor|)) - (set-slot 'defstruct-form - `(defstruct (structure-object (:constructor - ,constructor-sym) - (:copier nil)))) - (set-slot 'defstruct-constructor constructor-sym) - (set-slot 'from-defclass-p t) - (set-slot 'plist nil) - (set-slot 'prototype (funcall constructor-sym)))) - (condition-class - (set-slot 'prototype (make-condition name))) - (t - (set-slot 'prototype - (if proto-p proto (allocate-standard-instance wrapper))))) - class)) - -(defun !bootstrap-make-slot-definitions (name class slots wrapper effective-p) - (let ((index -1)) - (mapcar (lambda (slot) - (incf index) - (!bootstrap-make-slot-definition - name class slot wrapper effective-p index)) - slots))) - -(defun !bootstrap-make-slot-definition - (name class slot wrapper effective-p index) - (let* ((slotd-class-name (if effective-p - 'standard-effective-slot-definition - 'standard-direct-slot-definition)) - (slotd (allocate-standard-instance wrapper)) - (slot-name (getf slot :name))) - (flet ((get-val (name) (getf slot name)) - (set-val (name val) - (!bootstrap-set-slot slotd-class-name slotd name val))) - (set-val 'name slot-name) - (set-val 'initform (get-val :initform)) - (set-val 'initfunction (get-val :initfunction)) - (set-val 'initargs (get-val :initargs)) - (unless effective-p - (set-val 'readers (get-val :readers)) - (set-val 'writers (get-val :writers))) - (set-val 'allocation :instance) - (set-val '%type (or (get-val :type) t)) - (set-val '%documentation (or (get-val :documentation) "")) - (set-val '%class class) - (when effective-p - (set-val 'location index) - (set-val 'accessor-flags 7) - (set-val - 'info - (make-slot-info - :reader - (make-optimized-std-reader-method-function nil nil slot-name index) - :writer - (make-optimized-std-writer-method-function nil nil slot-name index) - :boundp - (make-optimized-std-boundp-method-function nil nil slot-name index)))) - (when (and (eq name 'standard-class) - (eq slot-name 'slots) effective-p) - (setq *the-eslotd-standard-class-slots* slotd)) - (when (and (eq name 'funcallable-standard-class) - (eq slot-name 'slots) effective-p) - (setq *the-eslotd-funcallable-standard-class-slots* slotd)) - slotd))) (defun !bootstrap-accessor-definitions (early-p) (let ((*early-p* early-p)) @@ -523,70 +115,71 @@ (dolist (writer writers) (do-writer-definition writer)) (dolist (boundp boundps) (do-boundp-definition boundp)))) -(defun !bootstrap-built-in-classes () - - ;; First make sure that all the supers listed in - ;; *BUILT-IN-CLASS-LATTICE* are themselves defined by - ;; *BUILT-IN-CLASS-LATTICE*. This is just to check for typos and - ;; other sorts of brainos. (The exceptions, T and SEQUENCE, are - ;; those classes which are SYSTEM-CLASSes which nevertheless have - ;; BUILT-IN-CLASS subclasses.) - (dolist (e *built-in-classes*) - (dolist (super (cadr e)) - (unless (or (eq super t) - (eq super 'sequence) - (assq super *built-in-classes*)) - (error "in *BUILT-IN-CLASSES*: ~S has ~S as a super,~%~ - but ~S is not itself a class in *BUILT-IN-CLASSES*." - (car e) super super)))) - - ;; In the first pass, we create a skeletal object to be bound to the - ;; class name. - (let* ((built-in-class (find-class 'built-in-class)) - (built-in-class-wrapper (class-wrapper built-in-class))) - (dolist (e *built-in-classes*) - (let ((class (allocate-standard-instance built-in-class-wrapper))) - (setf (find-class (car e)) class)))) - - ;; In the second pass, we initialize the class objects. - (let ((class-eq-wrapper (class-wrapper (find-class 'class-eq-specializer)))) - (dolist (e *built-in-classes*) - (destructuring-bind (name supers subs cpl prototype) e - (let* ((class (find-class name)) - (lclass (find-classoid name)) - (wrapper (classoid-layout lclass))) - (setf (classoid-pcl-class lclass) class) - - (!bootstrap-initialize-class 'built-in-class class - name class-eq-wrapper nil - supers subs - (cons name cpl) - wrapper prototype)))))) (defun class-of (x) (declare (explicit-check)) - (wrapper-class* (layout-of x))) + (wrapper-class (wrapper-of x))) (defun eval-form (form) (lambda () (eval form))) -(defun ensure-non-standard-class (name classoid &optional existing-class) - (flet +(defun ensure-non-standard-class (name classoid &optional existing-class extra-data) + (labels ((ensure (metaclass slots) (let ((supers (mapcar #'classoid-name (classoid-direct-superclasses classoid)))) (ensure-class-using-class existing-class name :metaclass metaclass :name name :direct-superclasses supers :direct-slots slots))) - (slot-initargs-from-structure-slotd (slotd) - (let ((accessor (structure-slotd-accessor-symbol slotd))) - `(:name ,(structure-slotd-name slotd) - :defstruct-accessor-symbol ,accessor - :internal-reader-function ,(structure-slotd-reader-function slotd) - :internal-writer-function ,(structure-slotd-writer-function name slotd) - :type ,(or (structure-slotd-type slotd) t) - :initform ,(structure-slotd-init-form slotd) - :initfunction ,(eval-form (structure-slotd-init-form slotd))))) + (slot-initargs-from-structure-slotd (slotd writer-fn reader-fn) + (flet ((name->fun (f) (if (functionp f) f (fdefinition f)))) + `(:name ,(dsd-name slotd) + :defstruct-accessor-symbol ,(dsd-accessor-name slotd) + :internal-reader-function ,(name->fun reader-fn) + :internal-writer-function ,(name->fun writer-fn) + :type ,(dsd-type slotd) + :initform ,(dsd-default slotd) + ;; This is nuts! any DEFAULT might need its lexical environment, + ;; yet we EVAL in the null environment. + :initfunction ,(eval-form (dsd-default slotd))))) + (accessor-closures (dsd) + (multiple-value-bind (reader-fn writer-fn) (sb-kernel::dsd-reader dsd nil) + ;; This is for a structure class that exists only in its compile-time representation. + ;; I don't see how these would get called, since you can't make an instance + ;; of the structure. + (list (lambda (newval object) (funcall writer-fn newval object) newval) + (lambda (object) (funcall reader-fn object))))) + (structure-type-slot-description-list (type) + (let* ((dd (find-defstruct-description type)) + (include (dd-include dd)) + (all-slots (dd-slots dd))) + (unless extra-data + (acond ((assoc (dd-name dd) sb-kernel::*struct-accesss-fragments-delayed*) + (let ((fragments (cdr it))) + (dolist (dsd (dd-slots dd)) + (push (list dsd (pop fragments) (pop fragments)) extra-data))) + (setq sb-kernel::*struct-accesss-fragments-delayed* + (delete it sb-kernel::*struct-accesss-fragments-delayed*))) + (t + (dolist (dsd (dd-slots dd)) + (push (cons dsd (accessor-closures dsd)) extra-data))))) + (multiple-value-bind (super slot-overrides) + (if (consp include) + (values (car include) (mapcar #'car (cdr include))) + (values include nil)) + (let ((included-slots + (when super + (dd-slots (find-defstruct-description super))))) + ;; This seems like a very unclear way to do what it's doing, which is + ;; collect slots of TYPE that are not in its direct ancestor, *or* + ;; which have an altered definition relative to the inherited one. + (loop for slot = (pop all-slots) + for included-slot = (pop included-slots) + while slot + when (or (not included-slot) + (member (dsd-name included-slot) slot-overrides :test #'eq)) + collect (apply #'slot-initargs-from-structure-slotd + (assoc slot extra-data))))))) (slot-initargs-from-condition-slot (slot) `(:name ,(condition-slot-name slot) :initargs ,(condition-slot-initargs slot) @@ -599,9 +192,7 @@ :allocation ,(condition-slot-allocation slot) :documentation ,(condition-slot-documentation slot)))) (cond ((structure-type-p name) - (ensure 'structure-class - (mapcar #'slot-initargs-from-structure-slotd - (structure-type-slot-description-list name)))) + (ensure 'structure-class (structure-type-slot-description-list name))) ((condition-type-p name) (ensure 'condition-class (mapcar #'slot-initargs-from-condition-slot @@ -609,14 +200,30 @@ (t (error "~@<~S is not the name of a class.~@:>" name))))) -(defun ensure-deffoo-class (classoid) +(defun ensure-deffoo-class (classoid &optional accessors) (let ((class (classoid-pcl-class classoid))) (cond (class - (ensure-non-standard-class (class-name class) classoid class)) + (ensure-non-standard-class (class-name class) classoid class accessors)) ((eq 'complete **boot-state**) - (ensure-non-standard-class (classoid-name classoid) classoid))))) - -(pushnew 'ensure-deffoo-class sb-kernel::*defstruct-hooks*) + (ensure-non-standard-class (classoid-name classoid) classoid nil accessors))))) + +(defun ensure-defstruct-class (classoid) + ;; Create an association from the DSD to the reader and writer functions. + (let* ((name (classoid-name classoid)) + (dd (find-defstruct-description name)) + (fragments sb-kernel::*struct-accesss-fragments*)) + (collect ((accessors)) + (dolist (dsd (dd-slots dd)) + (accessors (list dsd (pop fragments) (pop fragments)))) + (ensure-deffoo-class classoid (accessors))))) + +;;; Prior to the normal (steady-state) defstruct hook getting installed, +;;; we just accumulate an alist of slot accessor functions keyed by +;;; the type name. After switching it over, we start calling +;;; ENSURE-CLASS-USING-CLASS. But that means if PCL isn't ready to +;;; actually create classes, we can't switch over. So we refrain +;;; from installing the DEFSTRUCT-HOOK until there are no more +;;; defstruct forms to execute within PCL itself. (pushnew 'ensure-deffoo-class sb-kernel::*define-condition-hooks*) (defun !make-class-predicate (class name source-location) @@ -650,17 +257,49 @@ (add-method gf class-method))) gf)) +(define-load-time-global *simple-stream-root-classoid* :unknown) + +(defun set-bitmap-and-flags (wrapper &aux (inherits (wrapper-inherits wrapper)) + (flags (wrapper-flags wrapper)) + (layout (wrapper-friend wrapper))) + (when (eq (wrapper-classoid wrapper) *simple-stream-root-classoid*) + (setq flags (logior flags +simple-stream-layout-flag+))) + ;; We decide only at class finalization time whether it is funcallable. + ;; Picking the right bitmap could probably be done sooner given the metaclass, + ;; but this approach avoids changing how PCL uses MAKE-LAYOUT. + ;; FIXME: we should assert that this is not a STRUCTURE-OBJECT, + ;; because there must not be additional ID words preceding the bitmap. + ;; STANDARD-OBJECT can't generally use a fixed number of ID slots + ;; because of arbitrary changes to inheritance being permissible. + ;; On the other hand, we do create a new layout for each change + ;; to superclasses, so maybe it's possible. + (dovector (ancestor inherits) + (when (eq ancestor #.(find-layout 'function)) + (%raw-instance-set/signed-word + layout (sb-kernel::type-dd-length sb-vm:layout) + sb-kernel::standard-gf-primitive-obj-layout-bitmap)) + (setq flags (logior (logand (logior +sequence-layout-flag+ + +stream-layout-flag+ + +simple-stream-layout-flag+ + +file-stream-layout-flag+ + +string-stream-layout-flag+) + (wrapper-flags ancestor)) + flags))) + (setf (layout-flags (wrapper-friend wrapper)) flags)) + ;;; Set the inherits from CPL, and register the layout. This actually ;;; installs the class in the Lisp type system. -(defun %update-lisp-class-layout (class layout) - ;; Protected by *world-lock* in callers. - (let ((classoid (layout-classoid layout))) - (unless (eq (classoid-layout classoid) layout) - (set-layout-inherits layout +(defun %update-lisp-class-layout (class wrapper) + ;; Protected by **world-lock** in callers. + (let ((classoid (wrapper-classoid wrapper))) + (unless (eq (classoid-wrapper classoid) wrapper) + (set-layout-inherits wrapper (order-layout-inherits (map 'simple-vector #'class-wrapper - (reverse (rest (class-precedence-list class)))))) - (register-layout layout :invalidate t) + (reverse (rest (class-precedence-list class))))) + nil 0) + (set-bitmap-and-flags wrapper) + (register-layout wrapper :invalidate t) ;; FIXME: I don't think this should be necessary, but without it ;; we are unable to compile (TYPEP foo '<class-name>) in the @@ -672,10 +311,8 @@ (when (and name (symbolp name) (eq name (classoid-name classoid))) (setf (find-classoid name) classoid)))))) -(!bootstrap-meta-braid) (!bootstrap-accessor-definitions t) (!bootstrap-accessor-definitions nil) -(!bootstrap-built-in-classes) (loop for (name . x) in (let (classoid-cells) @@ -687,7 +324,7 @@ (when (classoid-cell-pcl-class x) (let* ((class (find-class-from-cell name x)) (layout (class-wrapper class)) - (lclass (layout-classoid layout)) + (lclass (wrapper-classoid layout)) (lclass-pcl-class (classoid-pcl-class lclass)) (olclass (find-classoid name nil))) (if lclass-pcl-class @@ -699,9 +336,7 @@ (cond (olclass (aver (eq lclass olclass))) (t - (setf (find-classoid name) lclass))) - - ))) + (setf (find-classoid name) lclass)))))) (setq **boot-state** 'braid) diff --git a/src/pcl/cache.lisp b/src/pcl/cache.lisp index dbb7beba1f..b05826b86e 100644 --- a/src/pcl/cache.lisp +++ b/src/pcl/cache.lisp @@ -64,6 +64,7 @@ ;;;; Subsequences of the cache vector are called cache lines. ;;;; +(declaim (inline %copy-cache)) (defstruct (cache (:constructor %make-cache) (:copier %copy-cache)) ;; Number of keys the cache uses. @@ -90,6 +91,15 @@ (depth 0 :type index) ;; Maximum allowed probe-depth before the cache needs to expand. (limit 0 :type index)) +;;; There is no syntax to freeze a type before the copier function +;;; is defined. That's sad, because it means that the global defun +;;; for %COPY-CACHE does *not* inline its allocator, for two different reasons: +;;; 1. the DEFSTRUCT-DESCRIPTION doesn't exist yet +;;; 2. the classoid isn't in sealed state when the DEFUN occurs +;;; (i.e. those are generally true of any defstruct form) +;;; However, all other uses of %COPY-CACHE aside from the global one +;;; _are_ inlined. So we're ok- we get the desired result, unless +;;; somebody funcalls #'%copy-cache, which nobody does. (declaim (freeze-type cache)) (defun compute-cache-mask (vector-length line-size) @@ -124,7 +134,7 @@ ;;; Return VALUE if it is not the unbound marker, otherwise executes ELSE: (defmacro non-empty-or (value else) - (with-unique-names (n-value) + (let ((n-value '#:val)) `(let ((,n-value ,value)) (if (unbound-marker-p ,n-value) ,else @@ -157,9 +167,10 @@ ;;; Perhaps we can dynamically optimize the mixing by picking bits that work ;;; best for the set of keys in the cache. (declaim (inline compute-cache-index)) +(export 'compute-cache-index) ; for a test (defun compute-cache-index (cache layouts) (macrolet ((fetch-hash (x) - `(let ((hash (layout-clos-hash ,x))) + `(let ((hash (wrapper-clos-hash ,x))) (when (zerop hash) (return-from compute-cache-index nil)) hash))) (let ((index (fetch-hash (car layouts)))) @@ -196,12 +207,19 @@ ;;; In other words, produces inlined code for COMPUTE-CACHE-INDEX when ;;; number of keys and presence of values in the cache is known ;;; beforehand. +(defglobal *hash-vars* + (make-array 6 :initial-contents + (loop for i from 0 below 6 collect (make-symbol (format nil "H~D" i))))) (defun emit-cache-lookup (cache-var layout-vars miss-tag value-var) (declare (muffle-conditions code-deletion-note)) - (with-unique-names (probe n-vector n-depth n-mask + (multiple-value-bind (probe n-vector n-depth n-mask MATCH-WRAPPERS EXIT-WITH-HIT) + (values '#:probe '#:vect '#:depth '#:mask '#:try '#:hit) (let* ((num-keys (length layout-vars)) - (hash-vars (make-gensym-list num-keys)) + (hash-vars (loop for i from 0 below num-keys + collect (if (< i #.(length *hash-vars*)) + (aref *hash-vars* i) + (make-symbol (format nil "H~D" i))))) (pointer ;; We don't need POINTER if the cache has 1 key and no value, ;; or if FOLD-INDEX-ADDRESSING is supported, in which case adding @@ -210,7 +228,7 @@ (when (or (> num-keys 1) value-var) (make-symbol "PTR"))) (line-size (power-of-two-ceiling (+ num-keys (if value-var 1 0))))) ;; Why not use PROG* ? are we expressly trying to avoid a new block? - `(let* (,@(mapcar (lambda (x y) `(,x (layout-clos-hash ,y))) hash-vars layout-vars) + `(let* (,@(mapcar (lambda (x y) `(,x (wrapper-clos-hash ,y))) hash-vars layout-vars) (,n-mask (cache-mask ,cache-var)) (,probe (if (zerop ,(cache-mixer-expression 'logand hash-vars t)) (go ,miss-tag) @@ -277,7 +295,7 @@ (case key-count (1 (let* ((layout (if (%instancep key) key (car key))) - (hash (layout-clos-hash layout)) + (hash (wrapper-clos-hash layout)) (index (logand hash mask))) (unless (= hash 0) (probe-loop (eq (svref vector (truly-the index index)) layout))))) @@ -419,14 +437,14 @@ ;; Check if the line is in use, and check validity of the keys. (let ((key1 (svref vector index))) (when (cache-key-p key1) - (if (zerop (layout-clos-hash key1)) + (if (zerop (wrapper-clos-hash key1)) ;; First key invalid. (return-from cache-has-invalid-entries-p t) ;; Line is in use and the first key is valid: check the rest. (loop for offset from 1 below key-count do (let ((thing (svref vector (+ index offset)))) (when (or (not (cache-key-p thing)) - (zerop (layout-clos-hash thing))) + (zerop (wrapper-clos-hash thing))) ;; Incomplete line or invalid layout. (return-from cache-has-invalid-entries-p t))))))) ;; Line empty of valid, onwards. @@ -487,7 +505,7 @@ cache) ;;; Copying a cache without expanding it is very much like mapping it: -;;; we need to be carefull because there may be updates while we are +;;; we need to be careful because there may be updates while we are ;;; copying it, and we don't want to copy incomplete entries or invalid ;;; ones. (defun copy-cache (cache) @@ -569,7 +587,7 @@ (total-lines (/ size line-size)) (total-n-keys 0) ; a "key" is a tuple of layouts (n-dirty 0) ; lines that have an unbound marker but are not wholly empty - (n-obsolete 0) ; lines that need to be evicted due to 0 in a layout-clos-hash + (n-obsolete 0) ; lines that need to be evicted due to 0 in a wrapper-clos-hash (histogram (when compute-histogram (make-array (1+ (cache-limit cache)) :initial-element 0)))) @@ -582,7 +600,7 @@ (n-misses 0)) (cond ((find-if-not #'cache-key-p layouts) (incf n-dirty)) - ((find 0 layouts :key #'layout-clos-hash) + ((find 0 layouts :key #'wrapper-clos-hash) (incf n-obsolete)) (t (incf total-n-keys) diff --git a/src/pcl/call-next-method.lisp b/src/pcl/call-next-method.lisp new file mode 100644 index 0000000000..466422964d --- /dev/null +++ b/src/pcl/call-next-method.lisp @@ -0,0 +1,200 @@ +;;;; This software is part of the SBCL system. See the README file for +;;;; more information. + +;;;; This software is derived from software originally released by Xerox +;;;; Corporation. Copyright and release statements follow. Later modifications +;;;; to the software are in the public domain and are provided with +;;;; absolutely no warranty. See the COPYING and CREDITS files for more +;;;; information. + +;;;; copyright information from original PCL sources: +;;;; +;;;; Copyright (c) 1985, 1986, 1987, 1988, 1989, 1990 Xerox Corporation. +;;;; All rights reserved. +;;;; +;;;; Use and copying of this software and preparation of derivative works based +;;;; upon this software are permitted. Any distribution of this software or +;;;; derivative works must comply with all applicable United States export +;;;; control laws. +;;;; +;;;; This software is made available AS IS, and Xerox Corporation makes no +;;;; warranty about the software, its performance or its conformity to any +;;;; specification. + +(in-package "SB-PCL") + +;;; CMUCL comment (Gerd Moellmann): +;;; +;;; The standard says it's an error if CALL-NEXT-METHOD is called with +;;; arguments, and the set of methods applicable to those arguments is +;;; different from the set of methods applicable to the original +;;; method arguments. (According to Barry Margolin, this rule was +;;; probably added to ensure that before and around methods are always +;;; run before primary methods.) +;;; +;;; This could be optimized for the case that the generic function +;;; doesn't have hairy methods, does have standard method combination, +;;; is a standard generic function, there are no methods defined on it +;;; for COMPUTE-APPLICABLE-METHODS and probably a lot more of such +;;; preconditions. That looks hairy and is probably not worth it, +;;; because this check will never be fast. + +;;; Or maybe it will (Jan Moringen): +;;; +;;; The "CALL-NEXT-METHOD argument checker" is a generic function +;;; which has twice as many required parameters as the original +;;; generic function. Consider, for example +;;; +;;; (defgeneric foo (bar baz &key fez)) +;;; +;;; The cnm args checker for this generic function is a generic +;;; function roughly equivalent to +;;; +;;; (defgeneric cnm-args-checker-for-foo (old-bar old-baz new-bar new-baz) +;;; (:generic-function-class cnm-args-checker)) +;;; +;;; The cnm args checker is applied to the concatenation of the +;;; original arguments and the arguments supplied to +;;; CALL-NEXT-METHOD: +;;; +;;; ;; In the expansion of (call-next-method new-bar new-bar ...): +;;; (when (funcall CNM-ARGS-CHECKER-FOR-FOO +;;; old-bar old-baz new-bar new-baz) +;;; (error "This list of applicable methods ... differs.")) +;;; +;;; A cnm args checker initially does not have any methods. When it is +;;; called with a particular sequence of arguments and does not have +;;; an applicable method for these arguments, it computes the +;;; applicable methods /of the original generic function/ for the old +;;; arguments and for the new arguments and adds a method that +;;; immediately returns the computed result when the same (in terms of +;;; CLOS dispatch) combination appears again. +;;; +;;; The cnm args checker must be invalidated when the results cached +;;; in its defined methods become invalid. + +(defun %check-cnm-args (cnm-args orig-args method-cell) + (declare (optimize (speed 3) (safety 0) (debug 0)) + (type list cnm-args orig-args)) + ;; 1. Check for no arguments. + (when cnm-args + (let* ((gf (method-generic-function (car method-cell))) + (nreq (generic-function-nreq gf))) + (declare (type (integer 0 #.call-arguments-limit) nreq)) + ;; 2. Consider required arguments pairwise: if the old and new + ;; arguments in all pairs are EQL, the applicable methods must + ;; be the same. This takes care of the relatively common case of + ;; twiddling with &KEY arguments. + (unless (do ((orig orig-args (cdr orig)) + (args cnm-args (cdr args)) + (n nreq (1- n))) + ((zerop n) t) + (declare (type (integer 0 #.call-arguments-limit) n)) + (unless (eql (car orig) (car args)) + (return nil))) + ;; 3. Only then make a cnm args checker and do the full check. + ;; Disabled until problems with EQL specializers and method + ;; "shadowing" are worked out. + #+(or) (let ((result (%use-cnm-checker gf nreq cnm-args orig-args))) + (when result + (destructuring-bind (cnm-methods . orig-methods) result + (error "~@<The set of methods ~S applicable to argument~P ~ + ~{~S~^, ~} to call-next-method is different from ~ + the set of methods ~S applicable to the original ~ + method argument~P ~{~S~^, ~}.~@:>" + cnm-methods (length cnm-args) cnm-args + orig-methods (length orig-args) orig-args)))) + (let ((orig-methods (compute-applicable-methods gf orig-args)) + (cnm-methods (compute-applicable-methods gf cnm-args))) + (unless (equal orig-methods cnm-methods) + (error "~@<The set of methods ~S applicable to argument~P ~ + ~{~S~^, ~} to call-next-method is different from ~ + the set of methods ~S applicable to the original ~ + method argument~P ~{~S~^, ~}.~@:>" + cnm-methods (length cnm-args) cnm-args + orig-methods (length orig-args) orig-args))))))) + +;;; CALL-NEXT-METHOD argument checker application + +(defun %use-cnm-checker (generic-function nreq cnm-args orig-args) + (declare (type (integer 1 #.call-arguments-limit) nreq)) + (let* ((info (gf-arg-info generic-function)) + ;; Setting GF-INFO-CNM-CHECKER is racy but should be OK. + (checker (or (gf-info-cnm-checker info) + (setf (gf-info-cnm-checker info) + (%make-cnm-checker generic-function)))) + (args (make-list (* 2 nreq)))) + (declare (dynamic-extent args)) + ;; Construct the concatenation of the required arguments in + ;; ORIG-ARGS and CNM-ARGS in ARGS. + (loop for rest1 on args + for arg in orig-args + repeat nreq + do (setf (car rest1) arg) + finally (loop for rest2 on (rest rest1) + for arg in cnm-args + do (setf (car rest2) arg))) + (apply checker args))) + +(defun %cnm-checker-lambda-list (nreq) + (append (map-into (make-list (* 2 nreq)) #'gensym) '(&rest rest))) + +;;; CALL-NEXT-METHOD argument checker implementation + +;;; The eval-when is due to a deficiency in compile-time handling of DEFCLASS which +;;; doesn't make the new class accessible to the optimizer for MAKE-INSTANCE with a +;;; quoted symbol as the argument. But we explicitly call pass ERROR = T in +;;; (SB-PCL::FIND-CLASS-FROM-CELL STREAM-FUNCTION NIL T) dynamically within a +;;; CLASS-NOT-FOUND handler. What the fsck? How about don't pass ERRORP = T ? +(eval-when (:compile-toplevel :load-toplevel :execute) +(defclass cnm-args-checker (standard-generic-function) + ((%generic-function :initarg :generic-function + :reader cnm-args-checker-generic-function)) + (:metaclass funcallable-standard-class))) + +(defun %make-cnm-checker (generic-function) + (let ((nreq (generic-function-nreq generic-function))) + (make-instance 'cnm-args-checker + :name nil + :lambda-list (%cnm-checker-lambda-list nreq) + :generic-function generic-function))) + +(defmethod no-applicable-method ((generic-function cnm-args-checker) + &rest args) + ;; Construct a method for GENERIC-FUNCTION that, when applied to + ;; ARGS, returns NIL (which indicates "fno error") if the + ;; CALL-NEXT-METHOD call is fine for the generic function + ;; (cnm-args-checker-generic-function generic-function) and a cons + ;; (ORIG-METHODS . CNM-METHODS) otherwise. + (let* ((original-generic-function (cnm-args-checker-generic-function + generic-function)) + (nreq (generic-function-nreq original-generic-function)) + (orig-args (subseq args 0 nreq)) + (orig-methods (compute-applicable-methods + original-generic-function orig-args)) + (cnm-args (subseq args nreq)) + (cnm-methods (compute-applicable-methods + original-generic-function cnm-args)) + (result (if (equal orig-methods cnm-methods) + nil + (cons orig-methods cnm-methods))) + (lambda-list (%cnm-checker-lambda-list nreq)) + (lambda (make-method-lambda + generic-function + (class-prototype (generic-function-method-class + generic-function)) + `(lambda ,lambda-list + (declare (ignore ,@(remove '&rest lambda-list)) + (optimize (speed 3) (debug 0) (safety 0))) + ',result) + nil)) + (function (pcl-compile lambda :safe)) + (specializers (append (method-specializers (first orig-methods)) + (method-specializers (first cnm-methods)))) + (method (make-instance 'standard-method + :qualifiers '() + :lambda-list lambda-list + :specializers specializers + :function function))) + (add-method generic-function method) + (apply generic-function args))) diff --git a/src/pcl/class-init.lisp b/src/pcl/class-init.lisp new file mode 100644 index 0000000000..5fd0e376e4 --- /dev/null +++ b/src/pcl/class-init.lisp @@ -0,0 +1,780 @@ +;;;; This file was split out from braid.lisp so that we could do some +;;;; of the work of building the meta-braid at cold initialization +;;;; time. + +;;;; This software is part of the SBCL system. See the README file for +;;;; more information. + +;;;; This software is derived from software originally released by Xerox +;;;; Corporation. Copyright and release statements follow. Later modifications +;;;; to the software are in the public domain and are provided with +;;;; absolutely no warranty. See the COPYING and CREDITS files for more +;;;; information. + +;;;; copyright information from original PCL sources: +;;;; +;;;; Copyright (c) 1985, 1986, 1987, 1988, 1989, 1990 Xerox Corporation. +;;;; All rights reserved. +;;;; +;;;; Use and copying of this software and preparation of derivative works based +;;;; upon this software are permitted. Any distribution of this software or +;;;; derivative works must comply with all applicable United States export +;;;; control laws. +;;;; +;;;; This software is made available AS IS, and Xerox Corporation makes no +;;;; warranty about the software, its performance or its conformity to any +;;;; specification. + +(in-package "SB-PCL") + +(declaim (list **standard-method-classes**)) +(defglobal **standard-method-classes** nil) + +(defconstant-eqx +standard-method-class-names+ + '(standard-method standard-reader-method + standard-writer-method standard-boundp-method + global-reader-method global-writer-method + global-boundp-method) + #'equal) + +(define-load-time-global *sgf-wrapper* + (!boot-make-wrapper (!early-class-size 'standard-generic-function) + 'standard-generic-function + sb-kernel::standard-gf-primitive-obj-layout-bitmap)) + + +(defun allocate-standard-instance (wrapper) + (let* ((instance (%new-instance wrapper (1+ sb-vm:instance-data-start))) + (slots (make-array (wrapper-length wrapper) :initial-element +slot-unbound+))) + (%instance-set instance sb-vm:instance-data-start slots) + instance)) + +(define-condition unset-funcallable-instance-function + (reference-condition simple-error) + () + (:default-initargs + :references '((:amop :generic-function allocate-instance) + (:amop :function set-funcallable-instance-function)))) + +(defmacro error-no-implementation-function (fin) + `(error 'unset-funcallable-instance-function + :format-control "~@<The function of funcallable instance ~ + ~S has not been set.~@:>" + :format-arguments (list ,fin))) + +(defun allocate-standard-funcallable-instance (wrapper name) + (declare (wrapper wrapper)) + (let* ((hash (if name + ;; Named functions have a predictable hash + (mix (sxhash name) (sxhash :generic-function)) ; arb. constant + (sb-impl::quasi-random-address-based-hash + (load-time-value (make-array 1 :element-type '(and fixnum unsigned-byte))) + most-positive-fixnum))) + (slots (make-array (wrapper-length wrapper) :initial-element +slot-unbound+)) + (fin (truly-the funcallable-instance + (%make-standard-funcallable-instance + slots #-compact-instance-header hash)))) + (setf (%fun-wrapper fin) wrapper) + #+compact-instance-header + (let ((32-bit-hash + ;; don't know how good our hash is, so use all N-FIXNUM-BITS of it + ;; as input to murmur-hash, which should definitely affect all bits, + ;; and then take 32 bits of that result. + (ldb (byte 32 0) (sb-impl:murmur-fmix-word hash)))) + (sb-sys:with-pinned-objects (fin) + (setf (sb-vm::compact-fsc-instance-hash fin) 32-bit-hash))) + (setf (%funcallable-instance-fun fin) + (lambda (&rest args) + (declare (ignore args)) + (error-no-implementation-function fin))) + fin)) + +(defun classify-slotds (slotds) + (let (instance-slots class-slots custom-slots bootp) + (dolist (slotd slotds) + (let ((alloc (cond ((consp slotd) ; bootstrap + (setf bootp t) + :instance) + (t + (slot-definition-allocation slotd))))) + (case alloc + (:instance + (push slotd instance-slots)) + (:class + (push slotd class-slots)) + (t + (push slotd custom-slots))))) + (values (if bootp + (nreverse instance-slots) + (when slotds + (sort instance-slots #'< :key #'slot-definition-location))) + class-slots + custom-slots))) + + +;;;; BOOTSTRAP-META-BRAID +;;;; +;;;; This function builds the base metabraid from the early class definitions. + +(declaim (inline wrapper-slot-list)) +(defun wrapper-slot-list (wrapper) + (let ((info (sb-kernel::wrapper-%info wrapper))) + (if (listp info) info))) +(defun (setf wrapper-slot-list) (newval wrapper) + ;; The current value must be a list, otherwise we'd clobber + ;; a defstruct-description. + (aver (listp (sb-kernel::wrapper-%info wrapper))) + (setf (sb-kernel::wrapper-%info wrapper) newval)) + +(macrolet + ((with-initial-classes-and-wrappers ((&rest classes) &body body) + `(let* ((*create-classes-from-internal-structure-definitions-p* nil) + ,@(mapcar (lambda (class) + `(,(symbolicate class "-WRAPPER") + ,(if (eq class 'standard-generic-function) + '*sgf-wrapper* + `(!boot-make-wrapper (!early-class-size ',class) + ',class)))) + classes) + ,@(mapcar (lambda (class) + `(,class (allocate-standard-instance + ,(if (eq class 'standard-generic-function) + 'funcallable-standard-class-wrapper + 'standard-class-wrapper)))) + classes)) + ,@(mapcan (lambda (class &aux (wr (symbolicate class "-WRAPPER"))) + `((setf (wrapper-class ,wr) ,class + (find-class ',class) ,class))) + classes) + ,@body))) +(defun !bootstrap-meta-braid () + (with-initial-classes-and-wrappers + (standard-class funcallable-standard-class + slot-class system-class built-in-class structure-class condition-class + standard-direct-slot-definition standard-effective-slot-definition + class-eq-specializer standard-generic-function) + ;; First, make a class metaobject for each of the early classes. For + ;; each metaobject we also set its wrapper. Except for the class T, + ;; the wrapper is always that of STANDARD-CLASS. + (dolist (definition *!early-class-definitions*) + (let* ((name (ecd-class-name definition)) + (meta (ecd-metaclass definition)) + (wrapper (ecase meta + (slot-class slot-class-wrapper) + (standard-class standard-class-wrapper) + (funcallable-standard-class + funcallable-standard-class-wrapper) + (built-in-class built-in-class-wrapper) + (system-class system-class-wrapper) + (structure-class structure-class-wrapper) + (condition-class condition-class-wrapper))) + (class (or (find-class name nil) + (allocate-standard-instance wrapper)))) + (setf (find-class name) class))) + (dolist (definition *!early-class-definitions*) + (let ((name (ecd-class-name definition)) + (meta (ecd-metaclass definition)) + (source (ecd-source-location definition)) + (direct-supers (ecd-superclass-names definition)) + (direct-slots (ecd-canonical-slots definition)) + (other-initargs (ecd-other-initargs definition))) + (let ((direct-default-initargs + (getf other-initargs :direct-default-initargs))) + (multiple-value-bind (slots cpl default-initargs direct-subclasses) + (!early-collect-inheritance name) + (let* ((class (find-class name)) + ;; All funcallable objects get the bitmap of standard-GF. + ;; This is checked in verify_range() of gencgc. + (bitmap (if (memq name '(standard-generic-function + funcallable-standard-object + generic-function)) + sb-kernel::standard-gf-primitive-obj-layout-bitmap + +layout-all-tagged+)) + (wrapper (cond ((eq class slot-class) + slot-class-wrapper) + ((eq class standard-class) + standard-class-wrapper) + ((eq class funcallable-standard-class) + funcallable-standard-class-wrapper) + ((eq class standard-direct-slot-definition) + standard-direct-slot-definition-wrapper) + ((eq class + standard-effective-slot-definition) + standard-effective-slot-definition-wrapper) + ((eq class system-class) system-class-wrapper) + ((eq class built-in-class) + built-in-class-wrapper) + ((eq class structure-class) + structure-class-wrapper) + ((eq class condition-class) + condition-class-wrapper) + ((eq class class-eq-specializer) + class-eq-specializer-wrapper) + ((eq class standard-generic-function) + standard-generic-function-wrapper) + (t + (!boot-make-wrapper (length slots) name bitmap)))) + (proto nil)) + (let ((symbol (make-class-symbol name))) + (when (eq (info :variable :kind symbol) :global) + (set symbol class))) + (dolist (slot slots) + (unless (eq (getf slot :allocation :instance) :instance) + (error "Slot allocation ~S is not supported in bootstrap." + (getf slot :allocation)))) + + (when (layout-for-pcl-obj-p wrapper) + (setf (wrapper-slot-list wrapper) slots)) + + (setq proto + (cond ((eq name t) nil) + ((eq meta 'funcallable-standard-class) + (allocate-standard-funcallable-instance wrapper name)) + (t + (allocate-standard-instance wrapper)))) + + (setq direct-slots + (!bootstrap-make-slot-definitions + name class direct-slots + standard-direct-slot-definition-wrapper nil)) + (setq slots + (!bootstrap-make-slot-definitions + name class slots + standard-effective-slot-definition-wrapper t)) + + (setf (wrapper-slot-table wrapper) (make-slot-table class slots t)) + (when (layout-for-pcl-obj-p wrapper) + (setf (wrapper-slot-list wrapper) slots)) + + (ecase meta + ((standard-class funcallable-standard-class) + (!bootstrap-initialize-class + meta + class name class-eq-specializer-wrapper source + direct-supers direct-subclasses cpl wrapper proto + direct-slots slots direct-default-initargs default-initargs)) + (built-in-class ; *the-class-t* + (!bootstrap-initialize-class + meta + class name class-eq-specializer-wrapper source + direct-supers direct-subclasses cpl wrapper proto)) + (system-class + (!bootstrap-initialize-class + meta + class name class-eq-specializer-wrapper source + direct-supers direct-subclasses cpl wrapper proto)) + (slot-class ; *the-class-slot-object* + (!bootstrap-initialize-class + meta + class name class-eq-specializer-wrapper source + direct-supers direct-subclasses cpl wrapper proto)) + (structure-class ; *the-class-structure-object* + (!bootstrap-initialize-class + meta + class name class-eq-specializer-wrapper source + direct-supers direct-subclasses cpl wrapper)) + (condition-class + (!bootstrap-initialize-class + meta + class name class-eq-specializer-wrapper source + direct-supers direct-subclasses cpl wrapper)))))))) + + (setq **standard-method-classes** + (mapcar (lambda (name) + (symbol-value (make-class-symbol name))) + +standard-method-class-names+)) + + (flet ((make-method-combination (class-name) + (let* ((class (find-class class-name)) + (wrapper (!bootstrap-get-slot + 'standard-class class 'wrapper)) + (instance (allocate-standard-instance wrapper))) + (flet ((set-slot (name value) + (!bootstrap-set-slot class-name instance name value))) + (values instance #'set-slot))))) + ;; Create the STANDARD method combination object. + (multiple-value-bind (method-combination set-slot) + (make-method-combination 'standard-method-combination) + (funcall set-slot 'source nil) + (funcall set-slot 'type-name 'standard) + (funcall set-slot 'options '()) + (funcall set-slot '%generic-functions (make-gf-hash-table)) + (funcall set-slot '%documentation "The standard method combination.") + (setq *standard-method-combination* method-combination)) + ;; Create an OR method combination object. + (multiple-value-bind (method-combination set-slot) + (make-method-combination 'short-method-combination) + (funcall set-slot 'source 'nil) + (funcall set-slot 'type-name 'or) + (funcall set-slot 'operator 'or) + (funcall set-slot 'identity-with-one-argument t) + (funcall set-slot '%generic-functions (make-gf-hash-table)) + (funcall set-slot '%documentation nil) + (funcall set-slot 'options '(:most-specific-first)) + (setq *or-method-combination* method-combination)))))) + +(defun !bootstrap-built-in-classes () + + ;; First make sure that all the supers listed in + ;; *BUILT-IN-CLASS-LATTICE* are themselves defined by + ;; *BUILT-IN-CLASS-LATTICE*. This is just to check for typos and + ;; other sorts of brainos. (The exceptions, T and SEQUENCE, are + ;; those classes which are SYSTEM-CLASSes which nevertheless have + ;; BUILT-IN-CLASS subclasses.) + (dolist (e *built-in-classes*) + (dolist (super (cadr e)) + (unless (or (eq super t) + (eq super 'sequence) + (assq super *built-in-classes*)) + (error "in *BUILT-IN-CLASSES*: ~S has ~S as a super,~%~ + but ~S is not itself a class in *BUILT-IN-CLASSES*." + (car e) super super)))) + + ;; In the first pass, we create a skeletal object to be bound to the + ;; class name. + (let* ((built-in-class (find-class 'built-in-class)) + (built-in-class-wrapper (!bootstrap-get-slot 'standard-class built-in-class 'wrapper))) + (dolist (e *built-in-classes*) + (let ((class (allocate-standard-instance built-in-class-wrapper))) + (setf (find-class (car e)) class)))) + + ;; In the second pass, we initialize the class objects. + (let ((class-eq-wrapper (!bootstrap-get-slot 'standard-class (find-class 'class-eq-specializer) 'wrapper))) + (dolist (e *built-in-classes*) + (destructuring-bind (name supers subs cpl prototype) e + (let* ((class (find-class name)) + (lclass (find-classoid name)) + (wrapper (classoid-wrapper lclass))) + (setf (classoid-pcl-class lclass) class) + + (!bootstrap-initialize-class 'built-in-class class + name class-eq-wrapper nil + supers subs + (cons name cpl) + wrapper prototype)))))) + +;;; I have no idea why we care so much about being able to create an instance +;;; of STRUCTURE-OBJECT, when (almost) no other structure class in the system +;;; begins life such that MAKE-INSTANCE works on it. +;;; And ALLOCATE-INSTANCE seems to work fine anyway. e.g. you can call +;;; (ALLOCATE-INSTANCE (FIND-CLASS 'HASH-TABLE)). +;;; Anyway, see below in !BOOTSTRAP-INITIALIZE-CLASS where we refer to +;;; the name of this seemingly useless constructor function. +(defun |STRUCTURE-OBJECT class constructor| () + (sb-kernel:%make-structure-instance + #.(sb-kernel:find-defstruct-description 'structure-object) + nil)) + +;;; Initialize a class metaobject. +(defun !bootstrap-initialize-class + (metaclass-name class name + class-eq-wrapper source direct-supers direct-subclasses cpl wrapper + &optional + (proto nil proto-p) + direct-slots slots direct-default-initargs default-initargs) + (flet ((classes (names) (mapcar #'find-class names)) + (set-slot (slot-name value) + (!bootstrap-set-slot metaclass-name class slot-name value))) + (set-slot 'name name) + (set-slot 'finalized-p t) + (set-slot 'source source) + (set-slot 'safe-p nil) + (set-slot '%type (if (eq class (find-class t)) + t + ;; FIXME: Could this just be CLASS instead + ;; of `(CLASS ,CLASS)? If not, why not? + ;; (See also similar expression in + ;; SHARED-INITIALIZE :BEFORE (CLASS).) + `(class ,class))) + (set-slot 'class-eq-specializer + (let ((spec (allocate-standard-instance class-eq-wrapper))) + (!bootstrap-set-slot 'class-eq-specializer spec '%type + `(class-eq ,class)) + (!bootstrap-set-slot 'class-eq-specializer spec 'object + class) + spec)) + (set-slot '%class-precedence-list (classes cpl)) + (set-slot 'cpl-available-p t) + (set-slot 'can-precede-list (classes (cdr cpl))) + (set-slot 'incompatible-superclass-list nil) + (set-slot 'direct-superclasses (classes direct-supers)) + (set-slot 'direct-subclasses (classes direct-subclasses)) + (set-slot 'direct-methods (cons nil nil)) + (set-slot 'wrapper wrapper) + (set-slot '%documentation nil) + (set-slot 'plist + `(,@(and direct-default-initargs + `(direct-default-initargs ,direct-default-initargs)) + ,@(and default-initargs + `(default-initargs ,default-initargs)))) + (when (memq metaclass-name '(standard-class funcallable-standard-class + structure-class condition-class + slot-class)) + (set-slot 'direct-slots direct-slots) + (set-slot 'slots slots) + (setf (wrapper-slot-table wrapper) + (make-slot-table class slots + (member metaclass-name + '(standard-class funcallable-standard-class)))) + (when (layout-for-pcl-obj-p wrapper) + (setf (wrapper-slot-list wrapper) slots))) + + ;; For all direct superclasses SUPER of CLASS, make sure CLASS is + ;; a direct subclass of SUPER. Note that METACLASS-NAME doesn't + ;; matter here for the slot DIRECT-SUBCLASSES, since every class + ;; inherits the slot from class CLASS. + (dolist (super direct-supers) + (let* ((super (find-class super)) + (subclasses (!bootstrap-get-slot metaclass-name super + 'direct-subclasses))) + (cond ((unbound-marker-p subclasses) + (!bootstrap-set-slot metaclass-name super 'direct-subclasses + (list class))) + ((not (memq class subclasses)) + (!bootstrap-set-slot metaclass-name super 'direct-subclasses + (cons class subclasses)))))) + + (case metaclass-name + (structure-class + (aver (not proto-p)) + (let ((constructor-sym '|STRUCTURE-OBJECT class constructor|)) + (set-slot 'defstruct-form + `(defstruct (structure-object (:constructor + ,constructor-sym) + (:copier nil)))) + (set-slot 'defstruct-constructor constructor-sym) + (set-slot 'from-defclass-p t) + (set-slot 'plist nil) + (set-slot 'prototype (funcall constructor-sym)))) + (condition-class + (aver (not proto-p)) + (set-slot 'prototype (make-condition name))) + (t + (aver proto-p) + (unless (eq name 't) (set-slot 'prototype proto)))) + class)) + +(defun !bootstrap-make-slot-definitions (name class slots wrapper effective-p) + (let ((index -1)) + (mapcar (lambda (slot) + (incf index) + (!bootstrap-make-slot-definition + name class slot wrapper effective-p index)) + slots))) + +(defun !bootstrap-make-slot-definition + (name class slot wrapper effective-p index) + (let* ((slotd-class-name (if effective-p + 'standard-effective-slot-definition + 'standard-direct-slot-definition)) + (slotd (allocate-standard-instance wrapper)) + (slot-name (getf slot :name))) + (flet ((get-val (name) (getf slot name)) + (set-val (name val) + (!bootstrap-set-slot slotd-class-name slotd name val))) + (set-val 'name slot-name) + (set-val 'initform (get-val :initform)) + (set-val 'initfunction (get-val :initfunction)) + (set-val 'initargs (get-val :initargs)) + (unless effective-p + (set-val 'readers (get-val :readers)) + (set-val 'writers (get-val :writers))) + (set-val 'allocation :instance) + (set-val '%type (or (get-val :type) t)) + (set-val '%documentation (or (get-val :documentation) "")) + (set-val '%class class) + (when effective-p + (set-val 'location index) + (set-val 'accessor-flags 7) + (set-val + 'info + (make-slot-info + :reader + (make-optimized-std-reader-method-function nil nil slot-name index) + :writer + (make-optimized-std-writer-method-function nil nil slot-name index) + :boundp + (make-optimized-std-boundp-method-function nil nil slot-name index)))) + (when (and (eq name 'standard-class) + (eq slot-name 'slots) effective-p) + (setq *the-eslotd-standard-class-slots* slotd)) + (when (and (eq name 'funcallable-standard-class) + (eq slot-name 'slots) effective-p) + (setq *the-eslotd-funcallable-standard-class-slots* slotd)) + slotd))) + +;;;; from slots-boot.lisp + +(defun make-optimized-std-reader-method-function + (fsc-p slotd slot-name location) + (set-fun-name + (etypecase location + (fixnum + (if fsc-p + (lambda (instance) + (check-obsolete-instance instance) + (let ((value (clos-slots-ref (fsc-instance-slots instance) + location))) + (if (unbound-marker-p value) + (values + (slot-unbound (class-of instance) instance slot-name)) + value))) + (lambda (instance) + (check-obsolete-instance instance) + (let ((value (clos-slots-ref (std-instance-slots instance) + location))) + (if (unbound-marker-p value) + (values + (slot-unbound (class-of instance) instance slot-name)) + value))))) + (cons + (lambda (instance) + (check-obsolete-instance instance) + (let ((value (cdr location))) + (if (unbound-marker-p value) + (values (slot-unbound (class-of instance) instance slot-name)) + value)))) + (null + (lambda (instance) + (declare (ignore instance)) + (instance-structure-protocol-error slotd 'slot-value-using-class)))) + `(reader ,slot-name))) + +(defun make-optimized-std-writer-method-function (fsc-p slotd slot-name location) + ;; The (WHEN SLOTD ...) gunk is for building early slot definitions. + (let* ((class (when slotd (slot-definition-class slotd))) + (safe-p (when slotd (safe-p class))) + (orig-wrapper (when safe-p (class-wrapper class))) + (info (when safe-p (slot-definition-info slotd))) + (writer-fun (etypecase location + ;; In SAFE-P case the typechecking already validated the instance. + (fixnum + (if fsc-p + (if safe-p + (lambda (nv instance) + (setf (clos-slots-ref (fsc-instance-slots instance) + location) + nv)) + (lambda (nv instance) + (check-obsolete-instance instance) + (setf (clos-slots-ref (fsc-instance-slots instance) + location) + nv))) + (if safe-p + (lambda (nv instance) + (setf (clos-slots-ref (std-instance-slots instance) + location) + nv)) + (lambda (nv instance) + (check-obsolete-instance instance) + (setf (clos-slots-ref (std-instance-slots instance) + location) + nv))))) + (cons + (if safe-p + (lambda (nv instance) + (declare (ignore instance)) + (setf (cdr location) nv)) + (lambda (nv instance) + (check-obsolete-instance instance) + (setf (cdr location) nv)))) + (null + (lambda (nv instance) + (declare (ignore nv instance)) + (instance-structure-protocol-error + slotd + '(setf slot-value-using-class)))))) + (checking-fun (when safe-p + (lambda (new-value instance) + ;; If we have a TYPE-CHECK-FUNCTION, call it. + (let* (;; Note that the class of INSTANCE here is not + ;; neccessarily the SLOT-DEFINITION-CLASS of + ;; the SLOTD passed to M-O-S-W-M-F, since it's + ;; e.g. possible for a subclass to define a + ;; slot of the same name but with no + ;; accessors. So we may need to fetch the + ;; right SLOT-INFO from the wrapper instead of + ;; just closing over it. + (wrapper (valid-wrapper-of instance)) + (typecheck + (slot-info-typecheck + (if (eq wrapper orig-wrapper) + info + (cdr (find-slot-cell wrapper slot-name)))))) + (when typecheck + (setf new-value (funcall typecheck new-value)))) + ;; Then call the real writer. + (funcall writer-fun new-value instance))))) + (set-fun-name (if safe-p + checking-fun + writer-fun) + `(writer ,slot-name)))) + +(defun make-optimized-std-boundp-method-function + (fsc-p slotd slot-name location) + (set-fun-name + (etypecase location + (fixnum (if fsc-p + (lambda (instance) + (check-obsolete-instance instance) + (not (unbound-marker-p (clos-slots-ref (fsc-instance-slots instance) + location)))) + (lambda (instance) + (check-obsolete-instance instance) + (not (unbound-marker-p (clos-slots-ref (std-instance-slots instance) + location)))))) + (cons (lambda (instance) + (check-obsolete-instance instance) + (not (unbound-marker-p (cdr location))))) + (null + (lambda (instance) + (declare (ignore instance)) + (instance-structure-protocol-error slotd 'slot-boundp-using-class)))) + `(boundp ,slot-name))) + +;;;; FINDING SLOT DEFINITIONS +;;; +;;; Historical PCL found slot definitions by iterating over +;;; CLASS-SLOTS, which is O(N) for number of slots, and moreover +;;; requires a GF call (for SLOT-DEFINITION-NAME) for each slot in +;;; list up to the desired one. +;;; +;;; Current SBCL hashes the effective slot definitions, and some +;;; information pulled out from them into a simple-vector, with bucket +;;; chains made out of plists keyed by the slot names. This fixes +;;; gives O(1) performance, and avoid the GF calls. +;;; +;;; MAKE-SLOT-TABLE constructs the hashed vector out of a list of +;;; effective slot definitions and the class they pertain to, and +;;; FIND-SLOT-DEFINITION knows how to look up slots in that vector. +;;; +;;; The only bit of cleverness in the implementation is to make the +;;; vectors fairly tight, but always longer then 0 elements: +;;; +;;; -- We don't want to waste huge amounts of space no these vectors, +;;; which are mostly required by things like SLOT-VALUE with a +;;; variable slot name, so a constant extension over the minimum +;;; size seems like a good choise. +;;; +;;; -- As long as the vector always has a length > 0 +;;; FIND-SLOT-DEFINITION doesn't need to handle the rare case of an +;;; empty vector separately: it just returns a NIL. +;;; +;;; In addition to the slot-definition we also store the slot-location +;;; and type-check function for instances of standard metaclasses, so +;;; that SLOT-VALUE &co using variable slot names can get at them +;;; without additional GF calls. +;;; +;;; Notes: +;;; It would also be nice to have STANDARD-INSTANCE-STRUCTURE-P +;;; generic instead of checking versus STANDARD-CLASS and +;;; FUNCALLABLE-STANDARD-CLASS. +;;; +;;; Uh, the comments above talking about how FIND-SLOT-DEFINITION +;;; does something with slot vectors has no basis in reality. +;;; Probably the comments need fixing, rather than the code. + +(defun find-slot-definition (class slot-name &optional errorp) + (unless (class-finalized-p class) + (or (try-finalize-inheritance class) + (if errorp + (error "Cannot look up slot-definition for ~S in ~S (too early to finalize.)" + slot-name class) + (return-from find-slot-definition (values nil nil))))) + (dolist (slotd (class-slots class) + (if errorp + (error "No slot called ~S in ~S." slot-name class) + (values nil t))) + (when (eq slot-name (slot-definition-name slotd)) + (return (values slotd t))))) + +(defun find-slot-cell (wrapper slot-name) + (declare (symbol slot-name)) + (declare (optimize (sb-c:insert-array-bounds-checks 0))) + (let* ((vector (wrapper-slot-table wrapper)) + (modulus (truly-the index (svref vector 0))) + ;; Can elide the 'else' branch of (OR symbol-hash ensure-symbol-hash) + ;; because every symbol in the slot-table already got a nonzero hash. + (index (rem (symbol-hash slot-name) modulus)) + (probe (svref vector (1+ index)))) + (declare (simple-vector vector) (index index)) + (cond ((fixnump probe) + (do* ((count (svref vector (1- (truly-the index probe)))) + (end (truly-the index (+ probe count))) + (j probe (1+ j))) + ((>= j end)) + (declare (index count j)) + (when (eq (svref vector j) slot-name) + (return (svref vector (truly-the index (+ j count))))))) + ((eq (car (truly-the list probe)) slot-name) + (cdr probe))))) + +(defun make-slot-table (class slots &optional bootstrap) + (unless slots + ;; *** If changing this empty table value to something else, + ;; be sure to make a similar change to MAKE-COLD-LAYOUT in + ;; compiler/generic/genesis as well as in DEFSTRUCT LAYOUT. + ;; A DEFCONSTANT for this would only transfer the problem + ;; to cold-init in a different sort of way. :-( + (return-from make-slot-table #(1 nil))) + (let* ((n (+ (logior (length slots) 1) 2)) ; an odd divisor is preferred + (vector (make-array n :initial-element nil))) + (flet ((add-to-vector (name slot) + (declare (symbol name) + (optimize (sb-c:insert-array-bounds-checks 0))) + (let ((index (rem (ensure-symbol-hash name) n))) + (setf (svref vector index) + (acons name + (cons (when (or bootstrap + (and (standard-class-p class) + (slot-accessor-std-p slot 'all))) + (if bootstrap + (early-slot-definition-location slot) + (slot-definition-location slot))) + (the slot-info + (if bootstrap + (early-slot-definition-info slot) + (slot-definition-info slot)))) + (svref vector index)))))) + (if (eq 'complete **boot-state**) + (dolist (slot slots) + (add-to-vector (slot-definition-name slot) slot)) + (dolist (slot slots) + (add-to-vector (early-slot-definition-name slot) slot)))) + ;; The VECTOR as computed above implements a hash table with chaining. + ;; Rather than store chains using cons cells, chains can be stored in the + ;; vector itself at the end, with the table entry pointing to another + ;; index in the vector. The chain length is stored first, then all keys, + ;; then all values. The resulting structure takes less memory than + ;; linked lists, and can be scanned faster. As an exception, for lists + ;; of length 1, the table cell holds a (key . value) pair directly. + (let* ((final-n + (+ 1 n + ;; number of additional cells needed to represent linked lists + ;; as length-prefixed subsequences in the final vector. + (loop for cell across vector + for count = (length cell) + sum (if (<= count 1) 0 (1+ (* count 2)))))) + (final-vector (make-array final-n)) + (data-index (1+ n))) ; after the hashtable portion of the vector + (setf (aref final-vector 0) n) ; the modulus + (dotimes (i n final-vector) + (let ((alist (aref vector i))) + (if (not (cdr alist)) ; store it in the final vector as-is + (setf (aref final-vector (1+ i)) (car alist)) + (let ((count (length alist))) + ;; Probed cell holds the index of the first symbol. + ;; The symbol count precedes the first symbol cell. + (setf (aref final-vector (1+ i)) (1+ data-index) + (aref final-vector data-index) count) + (dolist (cell alist) + (setf (aref final-vector (incf data-index)) (car cell))) + (dolist (cell alist) + (setf (aref final-vector (incf data-index)) (cdr cell))) + (incf data-index)))))))) + + +;;;; initialize the initial class hierarchy + +(!bootstrap-meta-braid) +(!bootstrap-built-in-classes) diff --git a/src/pcl/combin.lisp b/src/pcl/combin.lisp index 6e990a125c..08f1940b88 100644 --- a/src/pcl/combin.lisp +++ b/src/pcl/combin.lisp @@ -146,13 +146,25 @@ `(combined-method ,(generic-function-name gf)))) (defun maybe-trace-method (gf method fun fmf-p) - (let ((info (gethash gf sb-debug::*traced-funs*))) - (if (and info (sb-debug::trace-info-methods info)) - (let ((minfo (copy-structure info))) - (setf (sb-debug::trace-info-what minfo) (method-trace-name gf method)) + (let ((m-name (when (plusp (hash-table-count sb-debug::*traced-funs*)) + ;; KLUDGE: testing if *TRACE-FUNS* has anything anything to + ;; avoid calling METHOD-TRACE-NAME during PCL bootstrapping + ;; when the generic-function type is not yet defined.) + (method-trace-name gf method)))) + (when m-name + (sb-debug::retrace-local-funs m-name)) + (let ((info (when m-name + (or (gethash m-name sb-debug::*traced-funs*) + (let ((gf-info (gethash (or (generic-function-name gf) gf) + sb-debug::*traced-funs*))) + (when (and gf-info (sb-debug::trace-info-methods gf-info)) + (let ((copy (copy-structure gf-info))) + (setf (sb-debug::trace-info-what copy) m-name) + copy))))))) + (if info (lambda (&rest args) - (apply #'sb-debug::trace-method-call minfo fun fmf-p args))) - fun))) + (apply #'sb-debug::trace-method-call info fun fmf-p args)) + fun)))) (defun make-emf-from-method (gf method cm-args fmf-p &optional method-alist wrappers) @@ -195,7 +207,7 @@ (let* ((fmf (fast-method-call-function emf)) (fun (method-function-from-fast-method-call emf)) (mf (%make-method-function fmf))) - (set-funcallable-instance-function mf fun) + (setf (%funcallable-instance-fun mf) fun) (make-instance 'standard-method :specializers nil ; XXX :qualifiers nil @@ -244,9 +256,8 @@ (defun get-effective-method-gensym () (or (pop *rebound-effective-method-gensyms*) - (let ((new (format-symbol *pcl-package* - "EFFECTIVE-METHOD-GENSYM-~D" - (length *global-effective-method-gensyms*)))) + (let ((new (pcl-format-symbol "EFFECTIVE-METHOD-GENSYM-~D" + (length *global-effective-method-gensyms*)))) (setq *global-effective-method-gensyms* (append *global-effective-method-gensyms* (list new))) new))) @@ -397,16 +408,16 @@ (effective-method-lambda (expand-effective-method-function generic-function effective-method))) (multiple-value-bind (cfunction constants) - (get-fun1 effective-method-lambda - (lambda (form) - (memf-test-converter form generic-function - method-alist-p wrappers-p)) - (lambda (form) - (memf-code-converter form generic-function - metatypes applyp - method-alist-p wrappers-p)) - (lambda (form) - (memf-constant-converter form generic-function))) + (get-fun effective-method-lambda + (lambda (form) + (memf-test-converter form generic-function + method-alist-p wrappers-p)) + (lambda (form) + (memf-code-converter form generic-function + metatypes applyp + method-alist-p wrappers-p)) + (lambda (form) + (memf-constant-converter form generic-function))) (lambda (method-alist wrappers) (flet ((compute-constant (constant) (if (consp constant) diff --git a/src/pcl/compiler-support.lisp b/src/pcl/compiler-support.lisp index cd4070a716..a7f8703664 100644 --- a/src/pcl/compiler-support.lisp +++ b/src/pcl/compiler-support.lisp @@ -35,6 +35,10 @@ ;;;; STANDARD-CLASS (deftransform sb-pcl::pcl-instance-p ((object)) + ;; We declare SPECIFIER-TYPE notinline here because otherwise the + ;; literal classoid reflection/dumping machinery will instantiate + ;; the type at Genesis time, confusing PCL bootstrapping. + (declare (notinline specifier-type)) (let* ((otype (lvar-type object)) (standard-object (specifier-type 'standard-object))) ;; Flush tests whose result is known at compile time. @@ -42,20 +46,6 @@ ((not (types-equal-or-intersect otype standard-object)) nil) (t `(%pcl-instance-p object))))) -(defun sb-pcl::safe-code-p (&optional env) - (policy (or env (make-null-lexenv)) (eql safety 3))) - -(declaim (ftype function sb-pcl::parse-specialized-lambda-list)) -(define-source-context defmethod (name &rest stuff) - (let ((arg-pos (position-if #'listp stuff))) - (if arg-pos - `(defmethod ,name ,@(subseq stuff 0 arg-pos) - ,(handler-case - (nth-value 2 (sb-pcl::parse-specialized-lambda-list - (elt stuff arg-pos))) - (error () "<illegal syntax>"))) - `(defmethod ,name "<illegal syntax>")))) - (define-load-time-global sb-pcl::*internal-pcl-generalized-fun-name-symbols* nil) (defmacro define-internal-pcl-function-name-syntax (name (var) &body body) diff --git a/src/pcl/ctor.lisp b/src/pcl/ctor.lisp index 3f5df0dd83..d7de5a4d1b 100644 --- a/src/pcl/ctor.lisp +++ b/src/pcl/ctor.lisp @@ -143,20 +143,59 @@ ;;; Reset CTOR to use a default function that will compute an ;;; optimized constructor function when called. +;;; +;;; Note that lp#1951341 saw a very rare failure which suggested +;;; a memory ordering issue. Indeed, here is what happened: +;;; - thread A allocates a CTOR +;;; CTOR -> +-------------------------------+ +;;; | word 0: funinstance header | +;;; | word 1: trampline | +;;; | word 2: layout-of-CTOR | +;;; | word 3: funinstance function | +;;; | ... more slots ... | +;;; +-------------------------------+ +;;; +;;; - thread A creates a lambda that captures CTOR +;;; CLOSURE -> +------------------------------+ +;;; | word 0: closure header | +;;; | word 1: underlying function | +;;; | word 2: CTOR | +;;; +------------------------------+ +;;; +;;; - thread A stores CLOSURE into word 3 of CTOR +;;; by way of (SETF (%FUNCALLABLE-INSTANCE-FUN CTOR) ...) +;;; +;;; - thread B gets ahold of CTOR - how? I'm not clear +;;; on the protocol, but I guess it was already installed +;;; as the class's constructor +;;; +;;; - thread B reads word 3 out of the CTOR and calls +;;; the CLOSURE (successfully entering into its instructions) +;;; +;;; - CLOSURE's code loads CTOR from itself and calls +;;; INSTALL-OPTIMIZED-CONSTRUCTOR with an argument of 0 +;;; because B did not observe a store into word 2 +;;; of CLOSURE +;;; +;;; The fix is to use properly paired barriers. (defun install-initial-constructor (ctor &optional force-p) (when (or force-p (ctor-class ctor)) (setf (ctor-class ctor) nil (ctor-state ctor) 'initial) - (setf (%funcallable-instance-fun ctor) - (ecase (ctor-type ctor) - (ctor - (lambda (&rest args) - (install-optimized-constructor ctor) - (apply ctor args))) - (allocator - (lambda () - (install-optimized-allocator ctor) - (funcall ctor))))))) + (let ((closure + (ecase (ctor-type ctor) + (ctor + (lambda (&rest args) + (sb-thread:barrier (:read)) + (install-optimized-constructor ctor) + (apply ctor args))) + (allocator + (lambda () + (sb-thread:barrier (:read)) + (install-optimized-allocator ctor) + (funcall ctor)))))) + (sb-thread:barrier (:write)) + (setf (%funcallable-instance-fun ctor) closure)))) (defun make-ctor-function-name (class-name initargs safe-code-p) (labels ((arg-name (x) @@ -242,6 +281,7 @@ (t (bug "Something strange where symbol or class expected.")))) +(export '(+ctor-list-max-size+ +ctor-table-max-size+)) ; for a test ;;; Max number of CTORs kept in an inline list cache. Once this is ;;; exceeded we switch to a table. (defconstant +ctor-list-max-size+ 12) @@ -466,7 +506,7 @@ (flet (;; Return the name of parameter number I of a constructor ;; function. (parameter-name (i) - (format-symbol *pcl-package* ".P~D." i)) + (pcl-format-symbol ".P~D." i)) ;; Check if CLASS-ARG is a constant symbol. Give up if ;; not. (constant-class-p () @@ -543,7 +583,7 @@ ;; ...), because part of the deal is that those only happen from ;; FORCE-CACHE-FLUSHES, which create a new valid wrapper for the ;; class. An invalid layout of T needs to be flushed, however. - (when (eq (layout-invalid (class-wrapper class)) t) + (when (eq (wrapper-invalid (class-wrapper class)) t) (%force-cache-flushes class)) (setf (ctor-class ctor) class) (pushnew (make-weak-pointer ctor) (plist-value class 'ctors) @@ -551,12 +591,9 @@ (multiple-value-bind (form locations names optimizedp) (constructor-function-form ctor) (setf (%funcallable-instance-fun ctor) - (apply - (let ((*compiling-optimized-constructor* t)) - (handler-bind ((compiler-note #'muffle-warning)) - (compile nil `(lambda ,names (declare #.*optimize-speed*) - ,form)))) - locations) + (apply (let ((*compiling-optimized-constructor* t)) + (pcl-compile `(lambda ,names ,form) :unsafe)) + locations) (ctor-state ctor) (if optimizedp 'optimized 'fallback)))))) (defun install-optimized-allocator (ctor) @@ -571,7 +608,7 @@ ;; ...), because part of the deal is that those only happen from ;; FORCE-CACHE-FLUSHES, which create a new valid wrapper for the ;; class. An invalid layout of T needs to be flushed, however. - (when (eq (layout-invalid (class-wrapper class)) t) + (when (eq (wrapper-invalid (class-wrapper class)) t) (%force-cache-flushes class)) (setf (ctor-class ctor) class) (pushnew (make-weak-pointer ctor) (plist-value class 'ctors) @@ -580,8 +617,7 @@ (allocator-function-form ctor) (setf (%funcallable-instance-fun ctor) (let ((*compiling-optimized-constructor* t)) - (handler-bind ((compiler-note #'muffle-warning)) - (compile nil form))) + (pcl-compile form :unsafe)) (ctor-state ctor) (if optimizedp 'optimized 'fallback)))))) (defun allocator-function-form (ctor) @@ -753,7 +789,7 @@ `(lambda ,(make-ctor-parameter-list ctor) (declare #.*optimize-speed*) (block nil - (when (layout-invalid ,wrapper) + (when (wrapper-invalid ,wrapper) (install-initial-constructor ,ctor t) (return (funcall ,ctor ,@(make-ctor-parameter-list ctor)))) ,(wrap-in-allocate-forms ctor body early-unbound-markers-p))) @@ -766,7 +802,7 @@ `(lambda () (declare #.*optimize-speed*) (block nil - (when (layout-invalid ,wrapper) + (when (wrapper-invalid ,wrapper) (install-initial-constructor ,ctor t) (return (funcall ,ctor))) ,(wrap-in-allocate-forms ctor nil t))))) @@ -779,15 +815,19 @@ (defun wrap-in-allocate-forms (ctor body early-unbound-markers-p) (let* ((class (ctor-class ctor)) (wrapper (class-wrapper class))) + ;; Prefer to allocate slots first so that potentially we can make this construct + ;; the primitive instance and assign its layout and slots while pseudo-atomic. + ;; Even if we can't do that, this order of operations can avoid a GC store barrier + ;; - it doesn't currently, but it should - because the pointer store is young->old. + ;; Best-case we'd allocate two things in one allocation request, + ;; but there aren't allocation vops that do that. (etypecase class (standard-class - `(let ((.instance. (%make-instance (1+ sb-vm:instance-data-start))) - (.slots. (make-array - ,(layout-length wrapper) - ,@(when early-unbound-markers-p - '(:initial-element +slot-unbound+))))) - (setf (%instance-layout .instance.) ,wrapper) - (setf (std-instance-slots .instance.) .slots.) + `(let ((.slots. (make-array ,(wrapper-length wrapper) + ,@(when early-unbound-markers-p + '(:initial-element +slot-unbound+)))) + (.instance. (%new-instance ,wrapper (1+ sb-vm:instance-data-start)))) + (%instance-set .instance. sb-vm:instance-data-start .slots.) ,body .instance.)) (funcallable-standard-class @@ -913,7 +953,7 @@ (safe-p (ctor-safe-p ctor)) (wrapper (class-wrapper class)) (slot-vector - (make-array (layout-length wrapper) :initial-element nil)) + (make-array (wrapper-length wrapper) :initial-element nil)) (class-inits ()) (default-inits ()) (defaulting-initargs ()) @@ -939,10 +979,8 @@ (unless (initializedp location) (setf (aref slot-vector location) (list kind val type slotd)))) - (default-init-var-name (i) - (format-symbol *pcl-package* ".D~D." i)) - (location-var-name (i) - (format-symbol *pcl-package* ".L~D." i))) + (default-init-var-name (i) (pcl-format-symbol ".D~D." i)) + (location-var-name (i) (pcl-format-symbol ".L~D." i))) ;; Loop over supplied initargs and values and record which ;; instance and class slots they initialize. (loop for (key value) on initargs by #'cddr diff --git a/src/pcl/defclass.lisp b/src/pcl/defclass.lisp index d870a46ee0..433ab4da34 100644 --- a/src/pcl/defclass.lisp +++ b/src/pcl/defclass.lisp @@ -21,44 +21,87 @@ ;;;; warranty about the software, its performance or its conformity to any ;;;; specification. +(in-package "SB-KERNEL") + +(defun call-with-defining-class (kind name thunk) + (declare (ignorable kind name)) + (with-single-package-locked-error + (:symbol name "defining ~S as a ~(~A~)" kind) + (funcall thunk))) + +(defun preinform-compiler-about-class-type (name forthcoming-info) + ;; Unless the type system already has an actual type attached to + ;; NAME (in which case (1) writing a placeholder value over that + ;; actual type as a compile-time side-effect would probably be a bad + ;; idea and (2) anyway we don't need to modify it in order to make + ;; NAME be recognized as a valid type name) + (when (and forthcoming-info (not (info :type :kind name))) + ;; Tell the compiler to expect a class with the given NAME, by + ;; writing a kind of minimal placeholder type information. This + ;; placeholder will be overwritten later when the class is + ;; defined. + (setf (info :type :kind name) :forthcoming-defclass-type))) + +(symbol-macrolet + ((reader-function-type (specifier-type '(function (t) t))) + (writer-function-type (specifier-type '(function (t t) t)))) + (flet ((proclaim-ftype-for-name (kind name type) + (ecase kind + (condition + (proclaim `(ftype ,(type-specifier type) ,name))) + (class + (when (eq (info :function :where-from name) :assumed) + (sb-c:proclaim-ftype name type nil :defined)))))) + + (defun preinform-compiler-about-accessors (kind readers writers) + (flet ((inform (names type) + (mapc (lambda (name) (proclaim-ftype-for-name kind name type)) + names))) + (inform readers reader-function-type) + (inform writers writer-function-type))) + + (defun preinform-compiler-about-slot-functions (kind slots) + (flet ((inform (slots key type) + (mapc (lambda (slot) + (let ((name (funcall key slot))) + (proclaim-ftype-for-name kind name type))) + slots))) + (inform slots #'sb-pcl::slot-reader-name reader-function-type) + (inform slots #'sb-pcl::slot-boundp-name reader-function-type) + (inform slots #'sb-pcl::slot-writer-name writer-function-type))))) + +(defun %%compiler-defclass (name readers writers slots) + ;; ANSI says (Macro DEFCLASS, section 7.7) that DEFCLASS, if it + ;; "appears as a top level form, the compiler must make the class + ;; name be recognized as a valid type name in subsequent + ;; declarations (as for deftype) and be recognized as a valid class + ;; name for defmethod parameter specializers and for use as the + ;; :metaclass option of a subsequent defclass." + (preinform-compiler-about-class-type name t) + (preinform-compiler-about-accessors 'class readers writers) + (preinform-compiler-about-slot-functions 'class slots)) + +(defun %compiler-defclass (name readers writers slots) + (call-with-defining-class + 'class name + (lambda () + (%%compiler-defclass name readers writers slots)))) + (in-package "SB-PCL") ;;;; DEFCLASS macro and close personal friends -(declaim (global *the-class-t* - *the-class-slot-object* - *the-class-structure-object* - *the-class-standard-object* - *the-class-function* - *the-class-funcallable-standard-object* - *the-class-system-class* - *the-class-slot-class* - *the-class-condition-class* - *the-class-structure-class* - *the-class-standard-class* - *the-class-funcallable-standard-class* - *the-class-forward-referenced-class* - *the-class-method* - *the-class-standard-method* - *the-class-standard-reader-method* - *the-class-standard-writer-method* - *the-class-standard-boundp-method* - *the-class-global-reader-method* - *the-class-global-writer-method* - *the-class-global-boundp-method* - *the-class-standard-generic-function* - *the-class-standard-direct-slot-definition* - *the-class-standard-effective-slot-definition* - - *the-eslotd-standard-class-slots* - *the-eslotd-funcallable-standard-class-slots*)) - ;;; state for the current DEFCLASS expansion (defvar *initfunctions-for-this-defclass*) (defvar *readers-for-this-defclass*) (defvar *writers-for-this-defclass*) (defvar *slot-names-for-this-defclass*) +;; forward declarations so the host doesn't warn these to be undefined functions. +(declaim (ftype (function (t t) (values t t &optional)) *subtypep)) +(declaim (ftype (function (t) (values t &optional)) class-direct-slots)) +(declaim (ftype (function (t t t) (values cons t t t &optional)) make-structure-class-defstruct-form)) + ;;; Like the DEFMETHOD macro, the expansion of the DEFCLASS macro is ;;; fixed. DEFCLASS always expands into a call to LOAD-DEFCLASS. Until ;;; the meta-braid is set up, LOAD-DEFCLASS has a special definition @@ -68,7 +111,7 @@ ;;; After the metabraid has been setup, and the protocol for defining ;;; classes has been defined, the real definition of LOAD-DEFCLASS is ;;; installed by the file std-class.lisp -(defmacro defclass (&environment env name direct-superclasses direct-slots &rest options) +(sb-xc:defmacro defclass (&environment env name direct-superclasses direct-slots &rest options) (check-class-name name nil) (let (*initfunctions-for-this-defclass* *readers-for-this-defclass* ;Truly a crock, but we got @@ -161,7 +204,6 @@ options) (let (metaclass default-initargs - documentation canonized-options) (dolist (option options) (unless (listp option) @@ -191,7 +233,6 @@ (:documentation (unless (stringp (second option)) (error "~S is not a legal :documentation value" (second option))) - (setf documentation t) (push `(:documentation ,(second option)) canonized-options)) (otherwise (push `(',(car option) ',(cdr option)) canonized-options)))) @@ -245,9 +286,9 @@ (setf initform val)) (:type (when (eq metaclass 'standard-class) - (sb-kernel::check-slot-type-specifier - val name (cons 'defclass class-name)) - (setf type val)))) + (when (sb-kernel::check-slot-type-specifier + val name (cons 'defclass class-name)) + (setf type val))))) (when (get-properties others (list key)) (%program-error "Duplicate slot option ~S for slot ~ ~S in DEFCLASS ~S." @@ -293,188 +334,33 @@ source-form) (cond ((and (or (eq initform t) (equal initform ''t)) - (neq type t)) + (eq type t)) '(function constantly-t)) ((and (or (eq initform nil) (equal initform ''nil)) - (neq type t)) + (eq type t)) '(function constantly-nil)) ((and (or (eql initform 0) (equal initform ''0)) - (neq type t)) + (eq type t)) '(function constantly-0)) (t - (let* ((initform (if (eq type t) - initform - `(sb-c::with-source-form ,source-form - (the* (,type :source-form ,initform - ;; Don't want to insert a cast, - ;; as a subclass may change the type, - ;; just report this at compile-time. - :use-annotations t) - ,initform)))) + (let* ((initform `(sb-c::with-source-form ,source-form + (the* (,type :source-form ,initform + ;; Don't want to insert a cast, + ;; as a subclass may change the type, + ;; just report this at compile-time. + :use-annotations t) + ,initform))) (entry (assoc initform *initfunctions-for-this-defclass* :test #'equal))) (unless entry (setq entry (list initform (gensym) - `(function (lambda () - (declare (optimize - (sb-c:store-coverage-data 0))) + `(function + (lambda () + (declare (optimize (sb-c:store-coverage-data 0) + (sb-c:verify-arg-count 0))) ,initform)))) (push entry *initfunctions-for-this-defclass*)) (cadr entry))))) - - -;;; This is the early definition of LOAD-DEFCLASS. It just collects up -;;; all the class definitions in a list. Later, in braid1.lisp, these -;;; are actually defined. - -;;; Each entry in *EARLY-CLASS-DEFINITIONS* is an EARLY-CLASS-DEFINITION. -(defparameter *!early-class-definitions* ()) - -(defun !early-class-definition (class-name) - (or (find class-name *!early-class-definitions* :key #'ecd-class-name) - (error "~S is not a class in *early-class-definitions*." class-name))) - -(defun !make-early-class-definition - (name source-location metaclass - superclass-names canonical-slots other-initargs) - (list 'early-class-definition - name source-location metaclass - superclass-names canonical-slots other-initargs)) - -(defun ecd-class-name (ecd) (nth 1 ecd)) -(defun ecd-source-location (ecd) (nth 2 ecd)) -(defun ecd-metaclass (ecd) (nth 3 ecd)) -(defun ecd-superclass-names (ecd) (nth 4 ecd)) -(defun ecd-canonical-slots (ecd) (nth 5 ecd)) -(defun ecd-other-initargs (ecd) (nth 6 ecd)) - -(defvar *!early-class-slots* nil) - -(defun canonical-slot-name (canonical-slot) - (getf canonical-slot :name)) - -(defun !early-class-slots (class-name) - (cdr (or (assoc class-name *!early-class-slots*) - (let ((a (cons class-name - (mapcar #'canonical-slot-name - (!early-collect-inheritance class-name))))) - (push a *!early-class-slots*) - a)))) - -(defun !early-class-size (class-name) - (length (!early-class-slots class-name))) - -(defun !early-collect-inheritance (class-name) - ;;(declare (values slots cpl default-initargs direct-subclasses)) - (let ((cpl (!early-collect-cpl class-name))) - (values (!early-collect-slots cpl) - cpl - (!early-collect-default-initargs cpl) - (let (collect) - (dolist (definition *!early-class-definitions*) - (when (memq class-name (ecd-superclass-names definition)) - (push (ecd-class-name definition) collect))) - (nreverse collect))))) - -(defun !early-collect-slots (cpl) - (let* ((definitions (mapcar #'!early-class-definition cpl)) - (super-slots (mapcar #'ecd-canonical-slots definitions)) - (slots (apply #'append (reverse super-slots)))) - (dolist (s1 slots) - (let ((name1 (canonical-slot-name s1))) - (dolist (s2 (cdr (memq s1 slots))) - (when (eq name1 (canonical-slot-name s2)) - (error "More than one early class defines a slot with the~%~ - name ~S. This can't work because the bootstrap~%~ - object system doesn't know how to compute effective~%~ - slots." - name1))))) - slots)) - -(defun !early-collect-cpl (class-name) - (labels ((walk (c) - (let* ((definition (!early-class-definition c)) - (supers (ecd-superclass-names definition))) - (cons c - (apply #'append (mapcar #'!early-collect-cpl supers)))))) - (remove-duplicates (walk class-name) :from-end nil :test #'eq))) - -(defun !early-collect-default-initargs (cpl) - (let ((default-initargs ())) - (dolist (class-name cpl) - (let* ((definition (!early-class-definition class-name)) - (others (ecd-other-initargs definition))) - (loop (when (null others) (return nil)) - (let ((initarg (pop others))) - (unless (eq initarg :direct-default-initargs) - (error "~@<The defclass option ~S is not supported by ~ - the bootstrap object system.~:@>" - initarg))) - (setq default-initargs - (nconc default-initargs (reverse (pop others))))))) - (reverse default-initargs))) - -(defun !bootstrap-slot-index (class-name slot-name) - (or (position slot-name (!early-class-slots class-name)) - (error "~S not found" slot-name))) - -;;; !BOOTSTRAP-GET-SLOT and !BOOTSTRAP-SET-SLOT are used to access and -;;; change the values of slots during bootstrapping. During -;;; bootstrapping, there are only two kinds of objects whose slots we -;;; need to access, CLASSes and SLOT-DEFINITIONs. The first argument -;;; to these functions tells whether the object is a CLASS or a -;;; SLOT-DEFINITION. -;;; -;;; Note that the way this works it stores the slot in the same place -;;; in memory that the full object system will expect to find it -;;; later. This is critical to the bootstrapping process, the whole -;;; changeover to the full object system is predicated on this. -;;; -;;; One important point is that the layout of standard classes and -;;; standard slots must be computed the same way in this file as it is -;;; by the full object system later. -(defmacro !bootstrap-get-slot (type object slot-name) - `(clos-slots-ref (get-slots ,object) - (!bootstrap-slot-index ,type ,slot-name))) -(defun !bootstrap-set-slot (type object slot-name new-value) - (setf (!bootstrap-get-slot type object slot-name) new-value)) - -(defun early-class-precedence-list (class) - (!bootstrap-get-slot 'pcl-class class '%class-precedence-list)) - -(defun early-class-slotds (class) - (!bootstrap-get-slot 'slot-class class 'slots)) - -(defun early-slot-definition-name (slotd) - (!bootstrap-get-slot 'standard-effective-slot-definition slotd 'name)) - -(defun early-slot-definition-location (slotd) - (!bootstrap-get-slot 'standard-effective-slot-definition slotd 'location)) - -(defun early-slot-definition-info (slotd) - (!bootstrap-get-slot 'standard-effective-slot-definition slotd 'info)) - -(defun early-class-direct-subclasses (class) - (!bootstrap-get-slot 'class class 'direct-subclasses)) - -(declaim (notinline load-defclass)) -(defun load-defclass (name metaclass supers canonical-slots canonical-options - readers writers slot-names source-location &optional safe-p) - ;; SAFE-P is used by REAL-LOAD-DEFCLASS, but can be ignored here, since - ;; during the bootstrap we won't have (SAFETY 3). - (declare (ignore safe-p)) - (sb-kernel::%%compiler-defclass name readers writers slot-names) - (let ((ecd (!make-early-class-definition name - source-location - metaclass - (copy-tree supers) - (copy-tree canonical-slots) - (copy-tree canonical-options))) - (existing - (find name *!early-class-definitions* :key #'ecd-class-name))) - (setq *!early-class-definitions* - (cons ecd (remove existing *!early-class-definitions*))) - ecd)) diff --git a/src/pcl/defcombin.lisp b/src/pcl/defcombin.lisp index 9bee9b9344..4c2ea314c7 100644 --- a/src/pcl/defcombin.lisp +++ b/src/pcl/defcombin.lisp @@ -29,7 +29,7 @@ ;;; (defmacro define-method-combination (&whole form name . args) (declare (ignore args)) - (check-designator name define-method-combination) + (check-designator name 'define-method-combination) `(progn (with-single-package-locked-error (:symbol ',name "defining ~A as a method combination")) @@ -39,6 +39,7 @@ (expand-short-defcombin form)))) (defstruct method-combination-info + (lambda-list nil :type list) (constructor (error "missing arg") :type function) (cache nil :type list) (source-location nil :type (or null sb-c:definition-source-location))) @@ -101,8 +102,20 @@ documentation) (sb-c:source-location)))) +(defun random-documentation (name type) + (cdr (assoc type (info :random-documentation :stuff name)))) + +(defun (setf random-documentation) (new-value name type) + (let ((pair (assoc type (info :random-documentation :stuff name)))) + (if pair + (setf (cdr pair) new-value) + (push (cons type new-value) + (info :random-documentation :stuff name)))) + new-value) + (defun load-short-defcombin (type-name operator ioa doc source-location) (let ((info (make-method-combination-info + :lambda-list '(&optional (order :most-specific-first)) :source-location source-location :constructor (lambda (options) (short-combine-methods type-name options operator ioa source-location doc)))) @@ -182,12 +195,13 @@ type-name lambda-list method-group-specifiers args-option gf-var body) `(load-long-defcombin ',type-name ',documentation #',function - ',args-option (sb-c:source-location))))) + ',lambda-list ',args-option (sb-c:source-location))))) (define-load-time-global *long-method-combination-functions* (make-hash-table :test 'eq)) -(defun load-long-defcombin (type-name doc function args-lambda-list source-location) +(defun load-long-defcombin (type-name doc function lambda-list args-lambda-list source-location) (let ((info (make-method-combination-info + :lambda-list lambda-list :constructor (lambda (options) (make-instance 'long-method-combination :type-name type-name @@ -314,7 +328,8 @@ (setq ,name (nreverse ,name))) (:most-specific-last)))) order-cleanups)))) - `(let (,@(nreverse names) ,@(nreverse specializer-caches)) + `(let (,@(nreverse names) ,@specializer-caches) + (declare (ignorable ,@specializer-caches)) ,@declarations (dolist (.method. .applicable-methods.) (let ((.qualifiers. (method-qualifiers .method.)) diff --git a/src/pcl/defs.lisp b/src/pcl/defs.lisp index aec10d5e16..e6f5680044 100644 --- a/src/pcl/defs.lisp +++ b/src/pcl/defs.lisp @@ -38,7 +38,7 @@ has already been partially loaded. This may not work, you may~%~ need to get a fresh lisp (reboot) and then load PCL.")) -#-sb-fluid (declaim (inline gdefinition)) +(declaim (inline gdefinition)) (defun gdefinition (spec) ;; This is null layer right now, but once FDEFINITION stops bypasssing ;; fwrappers/encapsulations we can do that here. @@ -122,7 +122,7 @@ ((not and or) `(,(car type) ,@(mapcar #'convert-to-system-type (cdr type)))) ((class class-eq) ; class-eq is impossible to do right - (layout-classoid (class-wrapper (cadr type)))) + (wrapper-classoid (class-wrapper (cadr type)))) (eql type) (t (if (null (cdr type)) (car type) @@ -159,8 +159,7 @@ (convert-to-system-type type2)))))))) (defun make-class-symbol (class-name) - (format-symbol #.(find-package "SB-PCL") - "*THE-CLASS-~A*" (symbol-name class-name))) + (pcl-format-symbol "*THE-CLASS-~A*" (symbol-name class-name))) (defvar *standard-method-combination*) (defvar *or-method-combination*) @@ -177,50 +176,52 @@ ;;;; built-in classes -;;; Grovel over SB-KERNEL::+!BUILT-IN-CLASSES+ in order to set +;;; Grovel over SB-KERNEL::*BUILTIN-CLASSOIDS* in order to set ;;; SB-PCL:*BUILT-IN-CLASSES*. (/show "about to set up SB-PCL::*BUILT-IN-CLASSES*") (define-load-time-global *built-in-classes* - (labels ((direct-supers (class) - (/noshow "entering DIRECT-SUPERS" (classoid-name class)) - (if (typep class 'built-in-classoid) - (built-in-classoid-direct-superclasses class) - (let ((inherits (layout-inherits - (classoid-layout class)))) - (/noshow inherits) - (list (svref inherits (1- (length inherits))))))) - (direct-subs (class) - (/noshow "entering DIRECT-SUBS" (classoid-name class)) - (collect ((res)) - (let ((subs (classoid-subclasses class))) - (/noshow subs) - (when subs - (dohash ((sub v) subs) - (declare (ignore v)) - (/noshow sub) - (when (member class (direct-supers sub) :test #'eq) - (res sub))))) - (res)))) - (mapcar (lambda (kernel-bic-entry) - (/noshow "setting up" kernel-bic-entry) - (let* ((name (car kernel-bic-entry)) - (class (find-classoid name))) - (/noshow name class) - `(,name - ,(mapcar #'classoid-name (direct-supers class)) - ,(mapcar #'classoid-name (direct-subs class)) - ,(map 'list - (lambda (x) (classoid-name (layout-classoid x))) - (reverse (layout-inherits (classoid-layout class)))) - ,(eval (getf (cdr kernel-bic-entry) :prototype-form))))) - (remove-if (lambda (kernel-bic-entry) - (member (first kernel-bic-entry) - ;; remove special classes (T and our - ;; SYSTEM-CLASSes) from the - ;; BUILT-IN-CLASS list - '(t function stream sequence - file-stream string-stream))) - sb-kernel::+!built-in-classes+)))) + (macrolet + ((frob () + (labels ((direct-supers (class) + (/noshow "entering DIRECT-SUPERS" (classoid-name class)) + (if (typep class 'built-in-classoid) + (built-in-classoid-direct-superclasses class) + (let ((inherits (wrapper-inherits (classoid-wrapper class)))) + (/noshow inherits) + (list (svref inherits (1- (length inherits))))))) + (direct-subs (class) + (/noshow "entering DIRECT-SUBS" (classoid-name class)) + (collect ((res)) + (let ((subs (classoid-subclasses class))) + (/noshow subs) + (when subs + (sb-kernel::do-subclassoids ((sub wrapper) class) + (declare (ignore wrapper)) + (/noshow sub) + (when (member class (direct-supers sub) :test #'eq) + (res sub))))) + (sort (res) #'string< :key #'classoid-name)))) + `(list ,@(mapcar (lambda (kernel-bic-entry) + (/noshow "setting up" kernel-bic-entry) + (let* ((name (car kernel-bic-entry)) + (class (find-classoid name))) + (/noshow name class) + `(list ',name + ',(mapcar #'classoid-name (direct-supers class)) + ',(mapcar #'classoid-name (direct-subs class)) + ',(map 'list #'wrapper-classoid-name + (reverse (wrapper-inherits (classoid-wrapper class)))) + ,(getf (cdr kernel-bic-entry) :prototype-form)))) + (remove-if (lambda (kernel-bic-entry) + (member (first kernel-bic-entry) + ;; remove special classes (T and our + ;; SYSTEM-CLASSes) from the + ;; BUILT-IN-CLASS list + '(t function stream sequence + file-stream string-stream + slot-object))) + sb-kernel::*builtin-classoids*)))))) + (frob))) (/noshow "done setting up SB-PCL::*BUILT-IN-CLASSES*") ;;;; the classes that define the kernel of the metabraid @@ -330,6 +331,7 @@ (lambda-list :initform () :initarg :lambda-list :reader method-lambda-list) (%function :initform nil :initarg :function :reader method-function) (%documentation :initform nil :initarg :documentation) + (%cache :initform nil :accessor method-em-cache) ;; True IFF method is known to have no CALL-NEXT-METHOD in it, or ;; just a plain (CALL-NEXT-METHOD). (simple-next-method-call @@ -458,6 +460,11 @@ (info :accessor slot-definition-info))) +(defun uninitialized-accessor-function (type slotd) + (lambda (&rest args) + (declare (ignore args)) + (error "~:(~A~) function~@[ for ~S ~] not yet initialized." + type slotd))) ;;; We use a structure here, because fast slot-accesses to this information ;;; are critical to making SLOT-VALUE-USING-CLASS &co fast: places that need ;;; these functions can access the SLOT-INFO directly, avoiding the overhead @@ -568,14 +575,12 @@ ;; gethash on a live key should get the identical specializer, but since ;; nothing referenced the old specializer, consing a new one is fine. (defglobal *eql-specializer-table* - (make-hash-table :test 'eql :weakness :value)) + (sb-impl::make-system-hash-table :test 'eql :weakness :value :synchronized nil)) (defun intern-eql-specializer (object) ;; Avoid style-warning about compiler-macro being unavailable. (declare (notinline make-instance)) - ;; Need to lock, so that two threads don't get non-EQ specializers - ;; for an EQL object. - (with-locked-system-table (*eql-specializer-table*) + (with-system-mutex ((hash-table-lock *eql-specializer-table*)) (ensure-gethash object *eql-specializer-table* (make-instance 'eql-specializer :object object)))) diff --git a/src/pcl/dfun.lisp b/src/pcl/dfun.lisp index 410f7334aa..d159f4e0a5 100644 --- a/src/pcl/dfun.lisp +++ b/src/pcl/dfun.lisp @@ -373,7 +373,7 @@ Except see also BREAK-VICIOUS-METACIRCLE. -- CSR, 2003-05-28 (lambda (new arg) (accessor-miss gf new arg dfun-info))))) -#-sb-fluid (declaim (sb-ext:freeze-type dfun-info)) +(declaim (sb-ext:freeze-type dfun-info)) (defun make-one-class-accessor-dfun (gf type wrapper index) (let ((emit (ecase type @@ -667,7 +667,7 @@ Except see also BREAK-VICIOUS-METACIRCLE. -- CSR, 2003-05-28 (declaim (inline make-callable)) (defun make-callable (generator method-alist wrappers) - (function-funcall generator method-alist wrappers)) + (funcall (the function generator) method-alist wrappers)) (defun make-dispatch-dfun (gf) (values (get-dispatch-function gf) nil (dispatch-dfun-info))) @@ -715,16 +715,20 @@ Except see also BREAK-VICIOUS-METACIRCLE. -- CSR, 2003-05-28 (when (and ,applicable (not (memq ,gf *dfun-miss-gfs-on-stack*))) (let ((*dfun-miss-gfs-on-stack* (cons ,gf *dfun-miss-gfs-on-stack*))) ,@body)) - ;; Create a FAST-INSTANCE-BOUNDP structure instance for a cached - ;; SLOT-BOUNDP so that INVOKE-EMF does the right thing, that is, - ;; does not signal a SLOT-UNBOUND error for a boundp test. - ,@(if type - ;; FIXME: could the NEMF not be a CONS (for :CLASS-allocated - ;; slots?) - `((if (and (eq ,type 'boundp) (integerp ,nemf)) - (invoke-emf (make-fast-instance-boundp :index ,nemf) ,args) - (invoke-emf ,nemf ,args))) - `((invoke-emf ,nemf ,args))))) + ,(if type + ;; Munge the EMF so that INVOKE-EMF can do the right thing: + ;; BOUNDP gets a structure, WRITER the logical not of the + ;; index, so that READER can use the raw index. + ;; + ;; FIXME: could the NEMF not be a CONS (for :CLASS-allocated + ;; slots?) + `(if (integerp ,nemf) + (case ,type + (boundp (invoke-emf (make-fast-instance-boundp :index ,nemf) ,args)) + (reader (invoke-emf ,nemf ,args)) + (writer (invoke-emf (lognot ,nemf) ,args))) + (invoke-emf ,nemf ,args)) + `(invoke-emf ,nemf ,args)))) ;;; The dynamically adaptive method lookup algorithm is implemented is ;;; implemented as a kind of state machine. The kinds of @@ -885,8 +889,6 @@ Except see also BREAK-VICIOUS-METACIRCLE. -- CSR, 2003-05-28 (t (make-final-caching-dfun gf classes-list new-class))))) -(define-load-time-global *pcl-misc-random-state* (make-random-state)) - (defun accessor-miss (gf new object dfun-info) (let* ((ostate (type-of dfun-info)) (otype (dfun-info-accessor-type dfun-info)) @@ -900,7 +902,7 @@ Except see also BREAK-VICIOUS-METACIRCLE. -- CSR, 2003-05-28 ;; which are the parameters of the new state, and get other ;; information from the lexical variables bound above. (flet ((two-class (index w0 w1) - (when (zerop (random 2 *pcl-misc-random-state*)) + (when (zerop (random 2 (load-time-value *pcl-misc-random-state*))) (psetf w0 w1 w1 w0)) (dfun-update gf #'make-two-class-accessor-dfun @@ -1601,21 +1603,13 @@ Except see also BREAK-VICIOUS-METACIRCLE. -- CSR, 2003-05-28 root))) nil)) -;;; Not synchronized, as all the uses we have for it are multiple ones -;;; and need WITH-LOCKED-SYSTEM-TABLE in any case. -;;; -;;; FIXME: Is it really more efficient to store this stuff in a global -;;; table instead of having a slot in each method? -;;; -;;; FIXME: This table also seems to contain early methods, which should -;;; presumably be dropped during the bootstrap. -(define-load-time-global *effective-method-cache* (make-hash-table :test 'eq)) - (defun flush-effective-method-cache (generic-function) - (let ((cache *effective-method-cache*)) - (with-locked-system-table (cache) - (dolist (method (generic-function-methods generic-function)) - (remhash method cache))))) + (dolist (method (generic-function-methods generic-function)) + (let ((cache + (if (listp method) (sixth method) (method-em-cache method)))) + (when cache + (rplaca cache nil) + (rplacd cache nil))))) (defun get-secondary-dispatch-function (gf methods types &optional method-alist wrappers) @@ -1637,24 +1631,26 @@ Except see also BREAK-VICIOUS-METACIRCLE. -- CSR, 2003-05-28 (lambda (&rest args) (call-no-applicable-method gf args))) (let* ((key (car methods)) - (ht *effective-method-cache*) - (ht-value (with-locked-system-table (ht) - (ensure-gethash key ht (cons nil nil))))) + (cache + (if (listp key) ; early method + (sixth key) ; See !EARLY-MAKE-A-METHOD + (or (method-em-cache key) + (setf (method-em-cache key) (cons nil nil)))))) (if (and (null (cdr methods)) all-applicable-p ; the most common case (null method-alist-p) wrappers-p (not function-p)) - (or (car ht-value) - (setf (car ht-value) + (or (car cache) + (setf (car cache) (get-secondary-dispatch-function2 gf methods types method-alist-p wrappers-p all-applicable-p all-sorted-p function-p))) (let ((akey (list methods (if all-applicable-p 'all-applicable types) method-alist-p wrappers-p function-p))) - (or (cdr (assoc akey (cdr ht-value) :test #'equal)) + (or (cdr (assoc akey (cdr cache) :test #'equal)) (let ((value (get-secondary-dispatch-function2 gf methods types method-alist-p wrappers-p all-applicable-p all-sorted-p function-p))) - (push (cons akey value) (cdr ht-value)) + (push (cons akey value) (cdr cache)) value))))))) (defun get-secondary-dispatch-function2 (gf methods types method-alist-p @@ -1703,6 +1699,15 @@ Except see also BREAK-VICIOUS-METACIRCLE. -- CSR, 2003-05-28 (defun update-dfun (generic-function &optional dfun cache info) (let ((early-p (early-gf-p generic-function))) (flet ((update () + ;; If GENERIC-FUNCTION has a CALL-NEXT-METHOD argument + ;; checker, the methods of the checker (the checker is a + ;; generic function, each method caches a computation for + ;; a combination of original and C-N-M argument classes) + ;; must be re-computed. + (when (eq **boot-state** 'complete) + (let ((checker (gf-info-cnm-checker (gf-arg-info generic-function)))) + (when checker + (remove-methods checker)))) ;; Save DFUN-STATE, so that COMPUTE-DISCRIMINATING-FUNCTION can ;; access it, and so that it's there for eg. future cache updates. (set-dfun generic-function dfun cache info) diff --git a/src/pcl/dlisp.lisp b/src/pcl/dlisp.lisp index da13d62c24..936b79cd71 100644 --- a/src/pcl/dlisp.lisp +++ b/src/pcl/dlisp.lisp @@ -34,14 +34,14 @@ (defun dfun-arg-symbol (arg-number) (or (nth arg-number *dfun-arg-symbols*) - (format-symbol *pcl-package* ".ARG~A." arg-number))) + (pcl-format-symbol ".ARG~A." arg-number))) (declaim (list *slot-vector-symbols*)) (define-load-time-global *slot-vector-symbols* '(.SLOTS0. .SLOTS1. .SLOTS2. .SLOTS3.)) (defun slot-vector-symbol (arg-number) (or (nth arg-number *slot-vector-symbols*) - (format-symbol *pcl-package* ".SLOTS~A." arg-number))) + (pcl-format-symbol ".SLOTS~A." arg-number))) (declaim (inline make-dfun-required-args)) (defun make-dfun-required-args (count) @@ -182,12 +182,12 @@ (declare (optimize (sb-c:store-source-form 0))) (declare (optimize (sb-c::store-closure-debug-pointer 3))) #'(lambda ,args - (let () + (let () ; What is this LET doing? (declare #.*optimize-speed*) ,form))))) (values (if *precompiling-lap* `#',lambda - (compile nil lambda)) + (pcl-compile lambda :safe)) nil))) ;;; note on implementation for CMU 17 and later (including SBCL): @@ -219,15 +219,15 @@ ,@(unless class-slot-p `((setq slots (std-instance-slots ,instance)))) - (%instance-layout ,instance)) + (%instance-wrapper ,instance)) ((fsc-instance-p ,instance) ,@(unless class-slot-p `((setq slots (fsc-instance-slots ,instance)))) - (%fun-layout ,instance))))) + (%fun-wrapper ,instance))))) (block access (when (and wrapper - (not (zerop (layout-clos-hash wrapper))) + (not (zerop (wrapper-clos-hash wrapper))) ,@(if (eql 1 1-or-2-class) `((eq wrapper wrapper-0)) `((or (eq wrapper wrapper-0) @@ -350,9 +350,7 @@ (wrapper-bindings (mapcan (lambda (arg mt) (unless (eq mt t) (incf index) - `((,(format-symbol *pcl-package* - "WRAPPER-~D" - index) + `((,(pcl-format-symbol "WRAPPER-~D" index) ,(emit-fetch-wrapper mt arg miss-tag (pop slot-vars)))))) args metatypes)) @@ -385,18 +383,18 @@ (with-unique-names (wrapper) `(cond ((std-instance-p ,argument) ,(if slots-var - `(let ((,wrapper (%instance-layout ,argument))) + `(let ((,wrapper (%instance-wrapper ,argument))) (when (layout-for-pcl-obj-p ,wrapper) (setq ,slots-var (std-instance-slots ,argument))) ,wrapper) - `(%instance-layout ,argument))) + `(%instance-wrapper ,argument))) ((fsc-instance-p ,argument) ,(if slots-var - `(let ((,wrapper (%fun-layout ,argument))) + `(let ((,wrapper (%fun-wrapper ,argument))) (when (layout-for-pcl-obj-p ,wrapper) (setq ,slots-var (fsc-instance-slots ,argument))) ,wrapper) - `(%fun-layout ,argument))) + `(%fun-wrapper ,argument))) (t (go ,miss-tag))))) ;; Sep92 PCL used to distinguish between some of these cases (and ;; spuriously exclude others). Since in SBCL @@ -407,7 +405,7 @@ (when slots-var (bug "SLOT requested for metatype ~S, but it isn't going to happen." metatype)) - `(layout-of ,argument)) + `(wrapper-of ,argument)) ;; a metatype of NIL should never be seen here, as NIL is only in ;; the metatypes before a generic function is fully initialized. ;; T should never be seen because we never need to get a wrapper diff --git a/src/pcl/documentation.lisp b/src/pcl/documentation.lisp index cb66eb2fc5..3b6f670df3 100644 --- a/src/pcl/documentation.lisp +++ b/src/pcl/documentation.lisp @@ -46,6 +46,49 @@ (setf (%simple-fun-doc function) new-value))) new-value) +(defun real-function-name (name) + ;; Resolve the actual name of the function named by NAME + ;; e.g. (setf (name-function 'x) #'car) + ;; (real-function-name 'x) => CAR + (cond ((not (fboundp name)) + nil) + ((and (symbolp name) + (macro-function name)) + (let ((name (%fun-name (macro-function name)))) + (and (consp name) + (eq (car name) 'macro-function) + (cadr name)))) + (t + (%fun-name (fdefinition name))))) + +;;; It would be nice not to need this at all, but there's too much spaghetti +;;; and macrology for me to figure out where relying on a method just works. +(defun %doc-info (x doc-type) + (case doc-type + (function + ;; Unused + (error "FUNCTION doc-type is not supported.")) + (structure + (typecase x + (symbol (cond + ((eq (info :type :kind x) :instance) + (values (info :type :documentation x))) + ((info :typed-structure :info x) + (values (info :typed-structure :documentation x))))))) + (type + (typecase x + (structure-class (values (info :type :documentation (class-name x)))) + (t (and (typep x 'symbol) (values (info :type :documentation x)))))) + ((t) + (typecase x + (function (fun-doc x)) + (structure-class (values (info :type :documentation (class-name x)))) + ((or symbol cons) + (random-documentation x doc-type)))) + (t + (when (typep x '(or symbol cons)) + (random-documentation x doc-type))))) + ;;; (SETF %DOC-INFO) is a thin wrapper on INFO that set or clears ;;; a :DOCUMENTATION info value depending on whether STRING is NIL. ;;; It, and the corresponding reader, are not for use outside this file. @@ -61,12 +104,11 @@ (info-number :type :documentation)) ((info :typed-structure :info name) (info-number :typed-structure :documentation)))) - (type (info-number :type :documentation)) - (setf (info-number :setf :documentation)))))) + (type (info-number :type :documentation)))))) (cond (info-number (if string (set-info-value name info-number string) - (clear-info-values name (list info-number)))) + (clear-info-values name (list info-number)))) ((eq doc-type 'function) ;; FIXME: this silently loses ;; * (setf (documentation '(a bad name) 'function) "x") => "x" @@ -84,46 +126,18 @@ ;; " Documentation is attached as a documentation string to ;; /name/ (as kind function) and to the /function object/." (cond ((not (legal-fun-name-p name))) - ((not (equal (sb-c::real-function-name name) name)) + ((not (equal (real-function-name name) name)) (setf (random-documentation name 'function) string)) (t (setf (fun-doc (fdefinition name)) string)))) ((typep name '(or symbol cons)) (setf (random-documentation name doc-type) string))))) -;;; It would be nice not to need this at all, but there's too much spaghetti -;;; and macrology for me to figure out where relying on a method just works. -(defun %doc-info (x doc-type) - (case doc-type - (function - ;; Unused - (error "FUNCTION doc-type is not supported.")) - (structure - (typecase x - (symbol (cond - ((eq (info :type :kind x) :instance) - (values (info :type :documentation x))) - ((info :typed-structure :info x) - (values (info :typed-structure :documentation x))))))) - (type - (typecase x - (structure-class (values (info :type :documentation (class-name x)))) - (t (and (typep x 'symbol) (values (info :type :documentation x)))))) - ((t) - (typecase x - (function (fun-doc x)) - (structure-class (values (info :type :documentation (class-name x)))) - ((or symbol cons) - (random-documentation x doc-type)))) - (t - (when (typep x '(or symbol cons)) - (random-documentation x doc-type))))) - (defun set-function-name-documentation (name documentation) (aver name) (cond ((not (legal-fun-name-p name)) nil) - ((not (equal (sb-c::real-function-name name) name)) + ((not (equal (real-function-name name) name)) (setf (random-documentation name 'function) documentation)) (t (setf (fun-doc (or (and (symbolp name) @@ -168,7 +182,7 @@ (binding* (((state since replacements) (deprecated-thing-p namespace name)) (note (when state - (with-simple-output-to-string (stream) + (%with-output-to-string (stream) (sb-impl::print-deprecation-message namespace name (first since) (second since) replacements stream))))) @@ -233,10 +247,7 @@ (defmethod documentation ((x symbol) (doc-type (eql 'compiler-macro))) (awhen (compiler-macro-function x) - (documentation it t))) - - (defmethod documentation ((x symbol) (doc-type (eql 'setf))) - (values (info :setf :documentation x)))) + (documentation it t)))) (defmethod (setf documentation) (new-value (x function) (doc-type (eql 't))) (setf (fun-doc x) new-value)) @@ -258,8 +269,21 @@ (awhen (compiler-macro-function x) (setf (documentation it t) new-value))) +;;; SETF documentation is attached to the function that performs expansion, +;;; except for short form DEFSETF which is in the globaldb value directly. (defmethod (setf documentation) (new-value (x symbol) (doc-type (eql 'setf))) - (setf (%doc-info x 'setf) new-value)) + (let ((expander (info :setf :expander x))) + (typecase expander + ((cons symbol) (setf (second expander) new-value)) + (cons (setf (documentation (cdr expander) 'function) new-value)) + (function (setf (documentation expander 'function) new-value))))) + +(defmethod documentation ((x symbol) (doc-type (eql 'setf))) + (let ((expander (info :setf :expander x))) + (typecase expander + ((cons symbol) (second expander)) + (cons (documentation (cdr expander) 'function)) + (function (documentation expander 'function))))) ;;; method combinations (defmethod documentation ((x method-combination) (doc-type (eql 't))) @@ -402,8 +426,8 @@ Value of +SLOT-UNBOUND+ is unspecified, and should not be relied to be of any particular type, but it is guaranteed to be suitable for EQ comparison.") -#.(prog1 `(progn ,@*!documentation-methods*) - (setq *!documentation-methods* nil)) +(!install-cross-compiled-methods 'documentation) +(!install-cross-compiled-methods '(setf documentation)) (dolist (args (prog1 *!docstrings* (makunbound '*!docstrings*))) (apply #'(setf documentation) args)) diff --git a/src/pcl/ecd.lisp b/src/pcl/ecd.lisp new file mode 100644 index 0000000000..54deecc078 --- /dev/null +++ b/src/pcl/ecd.lisp @@ -0,0 +1,178 @@ +;;;; This software is part of the SBCL system. See the README file for +;;;; more information. + +;;;; This software is derived from software originally released by Xerox +;;;; Corporation. Copyright and release statements follow. Later modifications +;;;; to the software are in the public domain and are provided with +;;;; absolutely no warranty. See the COPYING and CREDITS files for more +;;;; information. + +;;;; copyright information from original PCL sources: +;;;; +;;;; Copyright (c) 1985, 1986, 1987, 1988, 1989, 1990 Xerox Corporation. +;;;; All rights reserved. +;;;; +;;;; Use and copying of this software and preparation of derivative works based +;;;; upon this software are permitted. Any distribution of this software or +;;;; derivative works must comply with all applicable United States export +;;;; control laws. +;;;; +;;;; This software is made available AS IS, and Xerox Corporation makes no +;;;; warranty about the software, its performance or its conformity to any +;;;; specification. + +(in-package "SB-PCL") + + +;;; This is the early definition of LOAD-DEFCLASS. It just collects up +;;; all the class definitions in a list. Later, in braid1.lisp, these +;;; are actually defined. + +;;; Each entry in *EARLY-CLASS-DEFINITIONS* is an EARLY-CLASS-DEFINITION. +(defparameter *!early-class-definitions* ()) + +(defun !early-class-definition (class-name) + (or (find class-name *!early-class-definitions* :key #'ecd-class-name) + (error "~S is not a class in *early-class-definitions*." class-name))) + +(defun !make-early-class-definition + (name source-location metaclass + superclass-names canonical-slots other-initargs) + (list 'early-class-definition + name source-location metaclass + superclass-names canonical-slots other-initargs)) + +(defun ecd-class-name (ecd) (nth 1 ecd)) +(defun ecd-source-location (ecd) (nth 2 ecd)) +(defun ecd-metaclass (ecd) (nth 3 ecd)) +(defun ecd-superclass-names (ecd) (nth 4 ecd)) +(defun ecd-canonical-slots (ecd) (nth 5 ecd)) +(defun ecd-other-initargs (ecd) (nth 6 ecd)) + +(defvar *!early-class-slots* nil) + +(defun canonical-slot-name (canonical-slot) + (getf canonical-slot :name)) + +(defun !early-class-slots (class-name) + (cdr (or (assoc class-name *!early-class-slots*) + (let ((a (cons class-name + (mapcar #'canonical-slot-name + (!early-collect-inheritance class-name))))) + (push a *!early-class-slots*) + a)))) + +(defun !early-class-size (class-name) + (length (!early-class-slots class-name))) + +(defun !early-collect-inheritance (class-name) + ;;(declare (values slots cpl default-initargs direct-subclasses)) + (let ((cpl (!early-collect-cpl class-name))) + (values (!early-collect-slots cpl) + cpl + (!early-collect-default-initargs cpl) + (let (collect) + (dolist (definition *!early-class-definitions*) + (when (memq class-name (ecd-superclass-names definition)) + (push (ecd-class-name definition) collect))) + (nreverse collect))))) + +(defun !early-collect-slots (cpl) + (let* ((definitions (mapcar #'!early-class-definition cpl)) + (super-slots (mapcar #'ecd-canonical-slots definitions)) + (slots (apply #'append (reverse super-slots)))) + (dolist (s1 slots) + (let ((name1 (canonical-slot-name s1))) + (dolist (s2 (cdr (memq s1 slots))) + (when (eq name1 (canonical-slot-name s2)) + (error "More than one early class defines a slot with the~%~ + name ~S. This can't work because the bootstrap~%~ + object system doesn't know how to compute effective~%~ + slots." + name1))))) + slots)) + +(defun !early-collect-cpl (class-name) + (labels ((walk (c) + (let* ((definition (!early-class-definition c)) + (supers (ecd-superclass-names definition))) + (cons c + (apply #'append (mapcar #'!early-collect-cpl supers)))))) + (remove-duplicates (walk class-name) :from-end nil :test #'eq))) + +(defun !early-collect-default-initargs (cpl) + (let ((default-initargs ())) + (dolist (class-name cpl) + (let* ((definition (!early-class-definition class-name)) + (others (ecd-other-initargs definition))) + (loop (when (null others) (return nil)) + (let ((initarg (pop others))) + (unless (eq initarg :direct-default-initargs) + (error "~@<The defclass option ~S is not supported by ~ + the bootstrap object system.~:@>" + initarg))) + (setq default-initargs + (nconc default-initargs (reverse (pop others))))))) + (reverse default-initargs))) + +(defun !bootstrap-slot-index (class-name slot-name) + (or (position slot-name (!early-class-slots class-name)) + (error "~S not found" slot-name))) + +;;; !BOOTSTRAP-GET-SLOT and !BOOTSTRAP-SET-SLOT are used to access and +;;; change the values of slots during bootstrapping. During +;;; bootstrapping, there are only two kinds of objects whose slots we +;;; need to access, CLASSes and SLOT-DEFINITIONs. The first argument +;;; to these functions tells whether the object is a CLASS or a +;;; SLOT-DEFINITION. +;;; +;;; Note that the way this works it stores the slot in the same place +;;; in memory that the full object system will expect to find it +;;; later. This is critical to the bootstrapping process, the whole +;;; changeover to the full object system is predicated on this. +;;; +;;; One important point is that the layout of standard classes and +;;; standard slots must be computed the same way in this file as it is +;;; by the full object system later. +(defmacro !bootstrap-get-slot (type object slot-name) + `(clos-slots-ref (get-slots ,object) + (!bootstrap-slot-index ,type ,slot-name))) +(defun !bootstrap-set-slot (type object slot-name new-value) + (setf (!bootstrap-get-slot type object slot-name) new-value)) + +(defun early-class-precedence-list (class) + (!bootstrap-get-slot 'pcl-class class '%class-precedence-list)) + +(defun early-class-slotds (class) + (!bootstrap-get-slot 'slot-class class 'slots)) + +(defun early-slot-definition-name (slotd) + (!bootstrap-get-slot 'standard-effective-slot-definition slotd 'name)) + +(defun early-slot-definition-location (slotd) + (!bootstrap-get-slot 'standard-effective-slot-definition slotd 'location)) + +(defun early-slot-definition-info (slotd) + (!bootstrap-get-slot 'standard-effective-slot-definition slotd 'info)) + +(defun early-class-direct-subclasses (class) + (!bootstrap-get-slot 'class class 'direct-subclasses)) + +(declaim (notinline load-defclass)) +(defun load-defclass (name metaclass supers canonical-slots canonical-options + readers writers slot-names source-location &optional safe-p) + ;; SAFE-P is used by REAL-LOAD-DEFCLASS, but can be ignored here, since + ;; during the bootstrap we won't have (SAFETY 3). + (declare (ignore safe-p)) + (sb-kernel::%%compiler-defclass name readers writers slot-names) + (let ((ecd (!make-early-class-definition name + source-location + metaclass + (copy-tree supers) + (copy-tree canonical-slots) + (copy-tree canonical-options))) + (existing + (find name *!early-class-definitions* :key #'ecd-class-name))) + (setq *!early-class-definitions* + (cons ecd (remove existing *!early-class-definitions*))) + ecd)) diff --git a/src/pcl/env.lisp b/src/pcl/env.lisp index 34caa07e61..1bab5beed8 100644 --- a/src/pcl/env.lisp +++ b/src/pcl/env.lisp @@ -25,132 +25,6 @@ (in-package "SB-PCL") -;;; FIXME: This stuff isn't part of the ANSI spec, and isn't even -;;; exported from PCL, but it looks as though it might be useful, -;;; so I don't want to just delete it. Perhaps it should go in -;;; a "contrib" directory eventually? - -#| -(defun parse-method-or-spec (spec &optional (errorp t)) - (let (gf method name temp) - (if (method-p spec) - (setq method spec - gf (method-generic-function method) - temp (and gf (generic-function-name gf)) - name (if temp - (make-method-spec temp - (method-qualifiers method) - (unparse-specializers - (method-specializers method))) - (make-symbol (format nil "~S" method)))) - (let ((gf-spec (car spec))) - (multiple-value-bind (quals specls) - (parse-defmethod (cdr spec)) - (and (setq gf (and (or errorp (fboundp gf-spec)) - (gdefinition gf-spec))) - (let ((nreq (compute-discriminating-function-arglist-info gf))) - (setq specls (append (parse-specializers specls) - (make-list (- nreq (length specls)) - :initial-element - *the-class-t*))) - (and - (setq method (get-method gf quals specls errorp)) - (setq name - (make-method-spec - gf-spec quals (unparse-specializers specls))))))))) - (values gf method name))) - -;;; TRACE-METHOD and UNTRACE-METHOD accept method specs as arguments. A -;;; method-spec should be a list like: -;;; (<generic-function-spec> qualifiers* (specializers*)) -;;; where <generic-function-spec> should be either a symbol or a list -;;; of (SETF <symbol>). -;;; -;;; For example, to trace the method defined by: -;;; -;;; (defmethod foo ((x spaceship)) 'ss) -;;; -;;; You should say: -;;; -;;; (trace-method '(foo (spaceship))) -;;; -;;; You can also provide a method object in the place of the method -;;; spec, in which case that method object will be traced. -;;; -;;; For UNTRACE-METHOD, if an argument is given, that method is untraced. -;;; If no argument is given, all traced methods are untraced. -(defclass traced-method (method) - ((method :initarg :method) - (function :initarg :function - :reader method-function) - (generic-function :initform nil - :accessor method-generic-function))) - -(defmethod method-lambda-list ((m traced-method)) - (with-slots (method) m (method-lambda-list method))) - -(defmethod method-specializers ((m traced-method)) - (with-slots (method) m (method-specializers method))) - -(defmethod method-qualifiers ((m traced-method)) - (with-slots (method) m (method-qualifiers method))) - -(defmethod accessor-method-slot-name ((m traced-method)) - (with-slots (method) m (accessor-method-slot-name method))) - -(defvar *traced-methods* ()) - -(defun trace-method (spec &rest options) - (multiple-value-bind (gf omethod name) - (parse-method-or-spec spec) - (let* ((tfunction (trace-method-internal (method-function omethod) - name - options)) - (tmethod (make-instance 'traced-method - :method omethod - :function tfunction))) - (remove-method gf omethod) - (add-method gf tmethod) - (pushnew tmethod *traced-methods*) - tmethod))) - -(defun untrace-method (&optional spec) - (flet ((untrace-1 (m) - (let ((gf (method-generic-function m))) - (when gf - (remove-method gf m) - (add-method gf (slot-value m 'method)) - (setq *traced-methods* (remove m *traced-methods*)))))) - (if (not (null spec)) - (multiple-value-bind (gf method) - (parse-method-or-spec spec) - (declare (ignore gf)) - (if (memq method *traced-methods*) - (untrace-1 method) - (error "~S is not a traced method?" method))) - (dolist (m *traced-methods*) (untrace-1 m))))) - -(defun trace-method-internal (ofunction name options) - (eval `(untrace ,name)) - (setf (fdefinition name) ofunction) - (eval `(trace ,name ,@options)) - (fdefinition name)) -|# - -#| -;;;; Helper for slightly newer trace implementation, based on -;;;; breakpoint stuff. The above is potentially still useful, so it's -;;;; left in, commented. - -;;; (this turned out to be a roundabout way of doing things) -(defun list-all-maybe-method-names (gf) - (let (result) - (dolist (method (generic-function-methods gf) (nreverse result)) - (let ((spec (nth-value 2 (parse-method-or-spec method)))) - (push spec result) - (push (list* 'fast-method (cdr spec)) result))))) -|# - ;;;; MAKE-LOAD-FORM ;; Overwrite the old bootstrap non-generic MAKE-LOAD-FORM function with a @@ -158,39 +32,40 @@ (fmakunbound 'make-load-form) (defgeneric make-load-form (object &optional environment)) -(defun !incorporate-cross-compiled-methods (gf-name &key except) +(defun !install-cross-compiled-methods (gf-name &key except) (assert (generic-function-p (fdefinition gf-name))) - ;; Reversing installs less-specific methods first, - ;; so that if perchance we crash mid way through the loop, - ;; there is (hopefully) at least some installed method that works. - (dovector (method (nreverse (cdr (assoc gf-name *!trivial-methods*)))) - ;; METHOD is a vector: - ;; #(#<GUARD> QUALIFIER SPECIALIZER #<FMF> LAMBDA-LIST SOURCE-LOC) - (let ((qualifier (svref method 1)) - (specializer (svref method 2)) - (fmf (svref method 3)) - (lambda-list (svref method 4)) - (source-loc (svref method 5))) - (unless (member specializer except) - (multiple-value-bind (specializers arg-info) - (ecase gf-name - (print-object - (values (list (find-class specializer) (find-class t)) - '(:arg-info (2)))) - (make-load-form - (values (list (find-class specializer)) - '(:arg-info (1 . t))))) - (load-defmethod - 'standard-method gf-name - (if qualifier (list qualifier)) specializers lambda-list - `(:function - ,(let ((mf (%make-method-function fmf))) - (sb-mop:set-funcallable-instance-function - mf (method-function-from-fast-function fmf arg-info)) - mf) - plist ,arg-info simple-next-method-call t) - source-loc)))))) -(!incorporate-cross-compiled-methods 'make-load-form :except '(layout)) + (dolist (method (cdr (assoc gf-name *!deferred-methods* :test #'equal))) + (destructuring-bind (qualifiers specializers fmf lambda-list source-loc) + method + (unless (member (first specializers) except) + (let ((arg-info + (if (equal gf-name '(setf documentation)) + '(:arg-info (3)) + (case gf-name + (print-object + '(:arg-info (2))) + ((make-load-form close) + '(:arg-info (1 . t))) + ((documentation) + '(:arg-info (2))) + (t + '(:arg-info (1))))))) + (load-defmethod + 'standard-method gf-name + qualifiers (mapcar (lambda (x) + (if (typep x '(cons (eql eql) (cons t null))) + (intern-eql-specializer (constant-form-value (second x))) + (find-class x))) + specializers) + lambda-list + `(:function + ,(let ((mf (%make-method-function fmf))) + (setf (%funcallable-instance-fun mf) + (method-function-from-fast-function fmf arg-info)) + mf) + plist ,arg-info simple-next-method-call t) + source-loc)))))) +(!install-cross-compiled-methods 'make-load-form :except '(wrapper)) (defmethod make-load-form ((class class) &optional env) ;; FIXME: should we not instead pass ENV to FIND-CLASS? Probably @@ -202,13 +77,13 @@ (error "~@<Can't use anonymous or undefined class as constant: ~S~:@>" class)))) -(defmethod make-load-form ((object layout) &optional env) +(defmethod make-load-form ((object wrapper) &optional env) (declare (ignore env)) - (let ((pname (classoid-proper-name (layout-classoid object)))) + (let ((pname (classoid-proper-name (wrapper-classoid object)))) (unless pname (error "can't dump wrapper for anonymous class:~% ~S" - (layout-classoid object))) - `(classoid-layout (find-classoid ',pname)))) + (wrapper-classoid object))) + `(classoid-wrapper (find-classoid ',pname)))) ;; FIXME: this seems wrong. NO-APPLICABLE-METHOD should be signaled. (defun dont-know-how-to-dump (object) @@ -223,11 +98,6 @@ (define-default-make-load-form-method standard-object) (define-default-make-load-form-method condition)) -sb-impl:: -(defmethod make-load-form ((host (eql *physical-host*)) &optional env) - (declare (ignore env)) - '*physical-host*) - ;;; I guess if the user defines other kinds of EQL specializers, she would ;;; need to implement this? And how is she supposed to know that? (defmethod eql-specializer-to-ctype ((specializer eql-specializer)) diff --git a/src/pcl/fixup.lisp b/src/pcl/fixup.lisp index 41d510c10e..f4a6ac012d 100644 --- a/src/pcl/fixup.lisp +++ b/src/pcl/fixup.lisp @@ -28,29 +28,42 @@ (fmakunbound 'ensure-accessor) (defun ensure-accessor (fun-name) ; Make FUN-NAME exist as a GF if it doesn't (destructuring-bind (slot-name method) (cddr fun-name) - ;; FIXME: change SLOT-OBJECT here to T to get SLOT-MISSING - ;; behaviour for non-slot-objects too? (let ((reader-specializers (load-time-value (list (find-class 'slot-object)) t)) (writer-specializers (load-time-value (list (find-class 't) - (find-class 'slot-object)) t))) - (multiple-value-bind (lambda-list specializers method-class initargs doc) + (find-class 'slot-object)) t)) + (fallback-reader-specializers + (load-time-value (list (find-class 't)) t)) + (fallback-writer-specializers + (load-time-value (list (find-class 't) (find-class 't)) t))) + (multiple-value-bind (lambda-list specializers method-class initargs doc + fallback-initargs + fallback-specializers) (ecase method (reader (values '(object) reader-specializers 'global-reader-method (make-std-reader-method-function 'slot-object slot-name) - "automatically-generated reader method")) + "automatically-generated reader method" + (make-fallback-reader-method-function slot-name) + fallback-reader-specializers)) (writer (values '(new-value object) writer-specializers 'global-writer-method (make-std-writer-method-function 'slot-object slot-name) - "automatically-generated writer method")) + "automatically-generated writer method" + (make-fallback-writer-method-function slot-name) + fallback-writer-specializers)) (boundp (values '(object) reader-specializers 'global-boundp-method (make-std-boundp-method-function 'slot-object slot-name) - "automatically-generated boundp method"))) + "automatically-generated boundp method" + (make-fallback-boundp-method-function slot-name) + fallback-reader-specializers))) (let ((gf (ensure-generic-function fun-name :lambda-list lambda-list))) - (add-method gf (make-a-method method-class - () lambda-list specializers + (add-method gf (make-a-method method-class () + lambda-list fallback-specializers + fallback-initargs doc :slot-name slot-name)) + (add-method gf (make-a-method method-class () + lambda-list specializers initargs doc :slot-name slot-name))))))) (dolist (gf-name *!temporary-ensure-accessor-functions*) @@ -58,13 +71,74 @@ (fmakunbound gf-name) (ensure-accessor gf-name)) +(setq sb-kernel::*defstruct-hooks* '(ensure-defstruct-class)) (compute-standard-slot-locations) (dolist (s '(condition function structure-object)) - (dohash ((k v) (classoid-subclasses (find-classoid s))) + (sb-kernel::do-subclassoids ((k v) (find-classoid s)) (declare (ignore v)) (find-class (classoid-name k)))) (setq **boot-state** 'complete) ;;; CLASS-PROTOTYPE for FUNCTION should not use ALLOCATE-INSTANCE. +;;; +;;; FIXME: this causes an error +;;; "A function with declared result type NIL returned: +;;; (SLOT-ACCESSOR :GLOBAL PROTOTYPE WRITER)" +;;; if SB-EXT:*DERIVE-FUNCTION-TYPES* is T. +;;; (let ((class (find-class 'function))) (setf (slot-value class 'prototype) #'identity)) + +(dolist (symbol '(add-method allocate-instance class-name compute-applicable-methods + ensure-generic-function make-instance method-qualifiers + remove-method add-dependent add-direct-method add-direct-subclass + class-default-initargs class-direct-default-initargs + class-direct-slots class-direct-subclasses + class-direct-superclasses class-finalized-p class-precedence-list + class-prototype class-slots + compute-applicable-methods-using-classes + compute-class-precedence-list compute-default-initargs + compute-discriminating-function compute-effective-method + compute-effective-slot-definition compute-slots + direct-slot-definition direct-slot-definition-class + effective-slot-definition effective-slot-definition-class + ensure-class ensure-class-using-class + ensure-generic-function-using-class eql-specializer + eql-specializer-object extract-lambda-list + extract-specializer-names finalize-inheritance + find-method-combination forward-referenced-class + funcallable-standard-class funcallable-standard-instance-access + funcallable-standard-object + generic-function-argument-precedence-order + generic-function-declarations generic-function-lambda-list + generic-function-method-class generic-function-method-combination + generic-function-methods generic-function-name + intern-eql-specializer make-method-lambda map-dependents + method-function method-generic-function method-lambda-list + method-specializers accessor-method-slot-definition + reader-method-class remove-dependent remove-direct-method + remove-direct-subclass set-funcallable-instance-function + slot-boundp-using-class slot-definition slot-definition-allocation + slot-definition-initargs slot-definition-initform + slot-definition-initfunction slot-definition-location + slot-definition-name slot-definition-readers + slot-definition-writers slot-definition-type + slot-makunbound-using-class slot-value-using-class specializer + specializer-direct-generic-functions specializer-direct-methods + standard-accessor-method standard-direct-slot-definition + standard-effective-slot-definition standard-instance-access + standard-reader-method standard-slot-definition + standard-writer-method update-dependent validate-superclass + writer-method-class)) + (sb-impl::deprecate-export *package* symbol :late "2.0.7")) + +(in-package "SB-KERNEL") +(defun slot-object-p (x) (typep x '(or structure-object standard-object condition))) + +(flet ((set-predicate (classoid-name pred) + (let ((c (find-classoid classoid-name))) + (%instance-set c (get-dsd-index built-in-classoid predicate) + pred)))) + (set-predicate 't #'constantly-t) + (set-predicate 'random-class #'constantly-nil) + (set-predicate 'sb-pcl::slot-object #'slot-object-p)) diff --git a/src/pcl/fngen.lisp b/src/pcl/fngen.lisp index 51fbde87c1..a0a31901aa 100644 --- a/src/pcl/fngen.lisp +++ b/src/pcl/fngen.lisp @@ -22,6 +22,23 @@ ;;;; specification. (in-package "SB-PCL") + +(defun pcl-compile (expr safety) + (let* ((base-policy sb-c::*policy*) + (lexenv + (sb-c::make-almost-null-lexenv + (ecase safety + (:safe base-policy) + (:unsafe (sb-c::process-optimize-decl + '((space 1) (compilation-speed 1) + (speed 3) (safety 0) (sb-ext:inhibit-warnings 3) (debug 0)) + base-policy))) + ;; I suspect that INHIBIT-WARNINGS precludes them from happening + (list (cons (sb-kernel:find-classoid 'style-warning) 'muffle-warning) + (cons (sb-kernel:find-classoid 'compiler-note) 'muffle-warning)) + nil nil nil + '((:declare sb-c::tlab :system))))) + (sb-c:compile-in-lexenv expr lexenv nil nil nil nil nil))) ;;; GET-FUN is the main user interface to this code. It is like ;;; COMPILE, only more efficient. It achieves this efficiency by @@ -48,19 +65,13 @@ (test-converter #'default-test-converter) (code-converter #'default-code-converter) (constant-converter #'default-constant-converter)) - (function-apply (get-fun-generator lambda test-converter code-converter) - (compute-constants lambda constant-converter))) - -(defun get-fun1 (lambda &optional - (test-converter #'default-test-converter) - (code-converter #'default-code-converter) - (constant-converter #'default-constant-converter)) (values (the function (get-fun-generator lambda test-converter code-converter)) (compute-constants lambda constant-converter))) (defun default-constantp (form) - (constant-typep form '(not (or symbol fixnum cons layout)))) + (and (constantp form) + (not (typep (constant-form-value form) '(or symbol fixnum cons wrapper))))) (defun default-test-converter (form) (if (default-constantp form) @@ -87,26 +98,29 @@ ;;; *FGENS* stores all the function generators we have so far. Each ;;; element is a FGEN structure as implemented below. Don't ever touch this -;;; list by hand, use LOOKUP-FGEN, and ENSURE-FGEN. -(define-load-time-global *fgens* (make-hash-table :test #'equal :synchronized t)) +;;; table by hand, use GET-FUN-GENERATOR and ENSURE-FGEN. +;;; We use explicit locking for properly scoped R/M/W operation without +;;; recursion on the mutex. So the table is not specified as :SYNCHRONIZED. +(define-load-time-global *fgens* (make-hash-table :test #'equal)) (defun ensure-fgen (test gensyms generator generator-lambda system) - (with-locked-system-table (*fgens*) - (let ((old (lookup-fgen test))) - (cond (old - (setf (fgen-generator old) generator) - (unless (fgen-system old) - (setf (fgen-system old) system))) - (t - (setf (gethash test *fgens*) - (make-fgen gensyms generator generator-lambda system))))))) + (let ((table *fgens*)) + (with-system-mutex ((hash-table-lock table)) + (let ((old (gethash test table))) + (cond (old + (setf (fgen-generator old) generator) + (unless (fgen-system old) + (setf (fgen-system old) system))) + (t + (setf (gethash test table) + (make-fgen gensyms generator generator-lambda system)))))))) -(defun lookup-fgen (test) - (gethash test *fgens*)) (defun get-fun-generator (lambda test-converter code-converter) (let* ((test (compute-test lambda test-converter)) - (fgen (lookup-fgen test))) + (table *fgens*) + (fgen (with-system-mutex ((hash-table-lock table)) + (gethash test table)))) (if fgen (fgen-generator fgen) (get-new-fun-generator lambda test code-converter)))) @@ -114,10 +128,9 @@ (defun get-new-fun-generator (lambda test code-converter) (multiple-value-bind (code gensyms) (compute-code lambda code-converter) (let ((generator-lambda `(lambda ,gensyms - (declare (muffle-conditions compiler-note) - (optimize (sb-c:store-source-form 0))) + (declare (optimize (sb-c:store-source-form 0))) (function ,code)))) - (let ((generator (compile nil generator-lambda))) + (let ((generator (pcl-compile generator-lambda :safe))) (ensure-fgen test gensyms generator generator-lambda nil) generator)))) @@ -167,8 +180,8 @@ (defmacro precompile-function-generators (&optional system) (let (collect) - (with-locked-system-table (*fgens*) - (maphash (lambda (test fgen) + ;; In single threaded code, only at system build time, and not used after. + (maphash (lambda (test fgen) (when (or (null (fgen-system fgen)) (eq (fgen-system fgen) system)) (when system @@ -180,5 +193,5 @@ ',(fgen-generator-lambda fgen) ',system) collect))) - *fgens*)) + *fgens*) `(progn ,@collect))) diff --git a/src/pcl/generic-functions.lisp b/src/pcl/generic-functions.lisp index 1a2d8b9e6c..e85d8a0316 100644 --- a/src/pcl/generic-functions.lisp +++ b/src/pcl/generic-functions.lisp @@ -211,7 +211,7 @@ (defgeneric generic-function-lambda-list (generic-function)) -(defgeneric generic-function-pretty-arglist (generic-function)) +(defgeneric generic-function-pretty-arglist (generic-function &optional current-defmethod)) (defgeneric gf-fast-method-function-p (gf)) diff --git a/src/pcl/gray-streams.lisp b/src/pcl/gray-streams.lisp index 90c6066df3..4c8c3b7ddc 100644 --- a/src/pcl/gray-streams.lisp +++ b/src/pcl/gray-streams.lisp @@ -11,141 +11,75 @@ (in-package "SB-GRAY") -;;; BUG-OR-ERROR: because we have extensible streams, wherewith the -;;; user is responsible for some of the protocol implementation, it's -;;; not necessarily a bug in SBCL itself if we fall through to one of -;;; these default methods. -;;; -;;; FIXME: there's a lot of similarity in these Gray stream -;;; implementation generic functions. All of them could (maybe -;;; should?) have two default methods: one on STREAM calling -;;; BUG-OR-ERROR, and one on T signalling a TYPE-ERROR. -(declaim (ftype (function * nil) bug-or-error)) -(defun bug-or-error (stream fun) - (declare (optimize allow-non-returning-tail-call)) - (error - "~@<The stream ~S has no suitable method for ~S, ~ - and so has fallen through to this method. If you think that this is ~ - a bug, please report it to the applicable authority (bugs in SBCL itself ~ - should go to the mailing lists referenced from ~ - <http://www.sbcl.org/>).~@:>" - stream fun)) +;;; See minor rant in call-next-method about this EVAL-WHEN. +(eval-when (:compile-toplevel :load-toplevel :execute) +(defclass stream-function (standard-generic-function) () + (:metaclass sb-mop:funcallable-standard-class))) +(defmacro !def-stream-generic (name ll &rest rest) + `(progn (fmakunbound ',name) + (defgeneric ,name ,ll (:generic-function-class stream-function) ,@rest) + (sb-pcl::!install-cross-compiled-methods ',name))) +(defmethod no-applicable-method ((function stream-function) &rest args) + (let ((stream (car args))) + (if (streamp stream) + (call-next-method) + (error 'type-error :datum stream :expected-type 'stream)))) -(fmakunbound 'stream-element-type) - -(defgeneric stream-element-type (stream) +(!def-stream-generic stream-element-type (stream) (:documentation "Return a type specifier for the kind of object returned by the STREAM. The class FUNDAMENTAL-CHARACTER-STREAM provides a default method which returns CHARACTER.")) -(defmethod stream-element-type ((stream ansi-stream)) - (ansi-stream-element-type stream)) - (defmethod stream-element-type ((stream fundamental-character-stream)) 'character) - -(defmethod stream-element-type ((stream stream)) - (bug-or-error stream 'stream-element-type)) - -(defmethod stream-element-type ((non-stream t)) - (error 'type-error :datum non-stream :expected-type 'stream)) -(fmakunbound 'open-stream-p) - -(defgeneric open-stream-p (stream) +(!def-stream-generic open-stream-p (stream) (:documentation "Return true if STREAM is not closed. A default method is provided by class FUNDAMENTAL-STREAM which returns true if CLOSE has not been called on the stream.")) -(defmethod open-stream-p ((stream ansi-stream)) - (ansi-stream-open-stream-p stream)) - (defmethod open-stream-p ((stream fundamental-stream)) (stream-open-p stream)) - -(defmethod open-stream-p ((stream stream)) - (bug-or-error stream 'open-stream-p)) - -(defmethod open-stream-p ((non-stream t)) - (error 'type-error :datum non-stream :expected-type 'stream)) -(fmakunbound 'close) - -(defgeneric close (stream &key abort) +(!def-stream-generic close (stream &key abort) (:documentation "Close the given STREAM. No more I/O may be performed, but inquiries may still be made. If :ABORT is true, an attempt is made to clean up the side effects of having created the stream.")) -(defmethod close ((stream ansi-stream) &key abort) - (ansi-stream-close stream abort)) - (defmethod close ((stream fundamental-stream) &key abort) (declare (ignore abort)) (setf (stream-open-p stream) nil) t) -(let () - (fmakunbound 'input-stream-p) - - (defgeneric input-stream-p (stream) +(progn + (!def-stream-generic input-stream-p (stream) (:documentation "Can STREAM perform input operations?")) - (defmethod input-stream-p ((stream ansi-stream)) - (ansi-stream-input-stream-p stream)) - (defmethod input-stream-p ((stream fundamental-stream)) nil) (defmethod input-stream-p ((stream fundamental-input-stream)) - t) - - (defmethod input-stream-p ((stream stream)) - (bug-or-error stream 'input-stream-p)) - - (defmethod input-stream-p ((non-stream t)) - (error 'type-error :datum non-stream :expected-type 'stream))) + t)) -(let () - (fmakunbound 'interactive-stream-p) - - (defgeneric interactive-stream-p (stream) +(progn + (!def-stream-generic interactive-stream-p (stream) (:documentation "Is STREAM an interactive stream?")) - (defmethod interactive-stream-p ((stream ansi-stream)) - (funcall (ansi-stream-misc stream) stream :interactive-p)) - (defmethod interactive-stream-p ((stream fundamental-stream)) - nil) - - (defmethod interactive-stream-p ((stream stream)) - (bug-or-error stream 'interactive-stream-p)) - - (defmethod interactive-stream-p ((non-stream t)) - (error 'type-error :datum non-stream :expected-type 'stream))) + nil)) -(let () - (fmakunbound 'output-stream-p) - - (defgeneric output-stream-p (stream) +(progn + (!def-stream-generic output-stream-p (stream) (:documentation "Can STREAM perform output operations?")) - (defmethod output-stream-p ((stream ansi-stream)) - (ansi-stream-output-stream-p stream)) - (defmethod output-stream-p ((stream fundamental-stream)) nil) (defmethod output-stream-p ((stream fundamental-output-stream)) - t) - - (defmethod output-stream-p ((stream stream)) - (bug-or-error stream 'output-stream-p)) - - (defmethod output-stream-p ((non-stream t)) - (error 'type-error :datum non-stream :expected-type 'stream))) + t)) ;;; character input streams ;;; @@ -211,23 +145,19 @@ calls to STREAM-READ-CHAR.")) (defmethod stream-read-line ((stream fundamental-character-input-stream)) - (let ((res (make-string 80)) - (len 80) - (index 0)) - (loop - (let ((ch (stream-read-char stream))) - (cond ((eq ch :eof) - (return (values (%shrink-vector res index) t))) - (t - (when (char= ch #\newline) - (return (values (%shrink-vector res index) nil))) - (when (= index len) - (setq len (* len 2)) - (let ((new (make-string len))) - (replace new res) - (setq res new))) - (setf (schar res index) ch) - (incf index))))))) + (let (eof) + ;; This loop is simpler than the one in ansi-stream-read-line + ;; because here we always return a string for the primary value, + ;; and the caller tests for a 0-length string. + ;; Writing to a string-output-stream adds negligible overhead + ;; versus the method dispatch for each input character. + (values (with-output-to-string (s) + (loop (let ((ch (stream-read-char stream))) + (case ch + (#\newline (return)) + (:eof (return (setq eof t))) + (t (funcall (ansi-stream-out s) s ch)))))) + eof))) (defgeneric stream-clear-input (stream) (:documentation @@ -236,10 +166,6 @@ (defmethod stream-clear-input ((stream fundamental-character-input-stream)) nil) -(defmethod stream-clear-input ((stream stream)) - (bug-or-error stream 'stream-clear-input)) -(defmethod stream-clear-input ((non-stream t)) - (error 'type-error :datum non-stream :expected-type 'stream)) (defgeneric stream-read-sequence (stream seq &optional start end) (:documentation @@ -369,10 +295,6 @@ (defmethod stream-finish-output ((stream fundamental-output-stream)) nil) -(defmethod stream-finish-output ((stream stream)) - (bug-or-error stream 'stream-finish-output)) -(defmethod stream-finish-output ((non-stream t)) - (error 'type-error :datum non-stream :expected-type 'stream)) (defgeneric stream-force-output (stream) (:documentation @@ -381,10 +303,6 @@ (defmethod stream-force-output ((stream fundamental-output-stream)) nil) -(defmethod stream-force-output ((stream stream)) - (bug-or-error stream 'stream-force-output)) -(defmethod stream-force-output ((non-stream t)) - (error 'type-error :datum non-stream :expected-type 'stream)) (defgeneric stream-clear-output (stream) (:documentation @@ -393,10 +311,6 @@ (defmethod stream-clear-output ((stream fundamental-output-stream)) nil) -(defmethod stream-clear-output ((stream stream)) - (bug-or-error stream 'stream-clear-output)) -(defmethod stream-clear-output ((non-stream t)) - (error 'type-error :datum non-stream :expected-type 'stream)) (defgeneric stream-advance-to-column (stream column) (:documentation @@ -452,32 +366,19 @@ "Used by READ-BYTE; returns either an integer, or the symbol :EOF if the stream is at end-of-file.")) -(defmethod stream-read-byte ((stream stream)) - (bug-or-error stream 'stream-read-byte)) -(defmethod stream-read-byte ((non-stream t)) - (error 'type-error :datum non-stream :expected-type 'stream)) - (defgeneric stream-write-byte (stream integer) (:documentation "Implements WRITE-BYTE; writes the integer to the stream and returns the integer as the result.")) -(defmethod stream-write-byte ((stream stream) integer) - (bug-or-error stream 'stream-write-byte)) -(defmethod stream-write-byte ((non-stream t) integer) - (error 'type-error :datum non-stream :expected-type 'stream)) - (defgeneric stream-file-position (stream &optional position-spec) (:documentation "Used by FILE-POSITION. Returns or changes the current position within STREAM.")) +(sb-pcl::!install-cross-compiled-methods 'stream-file-position) -(defmethod stream-file-position ((stream ansi-stream) &optional position-spec) - (ansi-stream-file-position stream position-spec)) - -(defmethod stream-file-position ((stream t) &optional position-spec) +(defmethod stream-file-position ((stream fundamental-stream) &optional position-spec) (declare (ignore stream position-spec)) nil) - ;;; This is not in the Gray stream proposal, so it is left here ;;; as example code. @@ -555,3 +456,36 @@ (defmethod stream-clear-input ((stream character-input-stream)) (clear-input (character-input-stream-lisp-stream stream))) |# + +#| +A small change to INVOKE-FAST-METHOD-CALL/MORE was able to get an easy 10% speedup + in STREAM-WRITE-STRING as shown below. +---- +(defclass sink-stream (fundamental-character-output-stream) ()) + +(defvar *callcount* 0) +(defmethod sb-gray:stream-write-string ((stream sink-stream) string &optional start end) + (declare (ignore start end)) + (incf *callcount*)) + +(defun time-this (&optional (n-iter 30000000)) + (declare (fixnum n-iter)) + (let ((stream (make-instance 'sink-stream))) + (dotimes (i n-iter) + (write-string "zook" stream :start 0 :end 4))) + (format t "Calls: ~s~%" *callcount*)) +---- + +Taking the best out of 3 runs each for old and new: +perf stat ... --noinform --eval '(setq *evaluator-mode* :compile)' --load foo.lisp --eval '(time-this)' --quit +Old: + 1.272560994 seconds time elapsed +New: + 1.136901160 seconds time elapsed + +Of course a dumb thing about this particular GF is that you probably never +invoke it directly, but only through WRITE-STRING or WRITE-LINE +in which case it always receives 4 args. So the small patch in src/pcl/boot +handles that afficiently, even if it was a little bit ad-hoc. +I don't think it was too ad-hoc though, because it's valid for any GF. +|# diff --git a/src/pcl/init.lisp b/src/pcl/init.lisp index 9a944ae526..9c3eeaddb5 100644 --- a/src/pcl/init.lisp +++ b/src/pcl/init.lisp @@ -91,13 +91,13 @@ ;; The normal, good case: compile an efficient typecheck function. (let ((*typecheck-stack* (cons cookie *typecheck-stack*))) (handler-bind (((or style-warning compiler-note) #'muffle-warning)) - (let ((fun (compile - nil + (let ((fun (pcl-compile `(named-lambda (slot-typecheck ,type) (value) (declare (optimize (sb-c:store-coverage-data 0) (sb-c::type-check 3) (sb-c:verify-arg-count 0))) - (the ,type value))))) + (the* (,type :restart t) value)) + :safe))) (setf (gethash type **typecheck-cache**) fun (slot-info-typecheck info) fun)))))))) diff --git a/src/pcl/low.lisp b/src/pcl/low.lisp index de6df0cf89..32322a1bc7 100644 --- a/src/pcl/low.lisp +++ b/src/pcl/low.lisp @@ -37,16 +37,13 @@ (in-package "SB-PCL") -;;; The PCL package is internal and is used by code in potential -;;; bottlenecks. And since it's internal, no one should be -;;; doing things like deleting and recreating it in a running target Lisp. -(define-symbol-macro *pcl-package* #.(find-package "SB-PCL")) (declaim (inline defstruct-classoid-p)) (defun defstruct-classoid-p (classoid) ;; It is non-obvious to me why STRUCTURE-CLASSOID-P doesn't ;; work instead of this. -- NS 2008-03-14 - (typep (layout-info (classoid-layout classoid)) 'defstruct-description)) + (typep (sb-kernel::wrapper-%info (classoid-wrapper classoid)) + 'defstruct-description)) ;;; This excludes structure types created with the :TYPE option to ;;; DEFSTRUCT. It also doesn't try to deal with types created by @@ -63,11 +60,22 @@ (defstruct-classoid-p classoid))))) ;;; Symbol contruction utilities -(defun format-symbol (package format-string &rest format-arguments) +(defun pkg-format-symbol (package format-string &rest format-arguments) (without-package-locks (intern (possibly-base-stringize (apply #'format nil format-string format-arguments)) package))) +;; Like the preceding, but always use PCL package, and override the package lock +;; in a more elegant way than using WITHOUT-PACKAGE-LOCKS. +(defun pcl-format-symbol (format-string &rest format-arguments) + (let ((string (possibly-base-stringize + (let ((*package* *keyword-package*)) + (apply #'format nil format-string format-arguments))))) + ;; Is there any way this can actually NOT be of type base-char? + (sb-impl::%intern string (length string) #.(find-package "SB-PCL") + (if (simple-base-string-p string) 'base-char 'character) + t ; ignore lock + nil))) ; no inheritance. Does it matter? (defun condition-type-p (type) (and (symbolp type) @@ -78,9 +86,12 @@ (declare (fixnum ,var)) ,@body)) +(define-load-time-global *pcl-misc-random-state* (make-random-state)) + (declaim (inline random-fixnum)) (defun random-fixnum () - (random (1+ most-positive-fixnum))) + (random (1+ most-positive-fixnum) + (load-time-value *pcl-misc-random-state*))) ;;; Lambda which executes its body (or not) randomly. Used to drop ;;; random cache entries. @@ -100,17 +111,15 @@ (setf ,drops (random-fixnum) ,drop-pos sb-vm:n-positive-fixnum-bits)))))) -(import 'sb-kernel:funcallable-instance-p) ; why? - (defun set-funcallable-instance-function (fin new-value) - (declare (type function new-value) - ;; KLUDGE: it might be nice to restrict - ;; SB-MOP:SET-FUNCALLABLE-INSTANCE-FUNCTION to operate only - ;; on generalized instances of - ;; SB-MOP:FUNCALLABLE-STANDARD-OBJECT; at present, even - ;; PCL's internal use of SET-FUNCALLABLE-INSTANCE-FUNCTION - ;; doesn't obey this restriction. - (type funcallable-instance fin)) + (declare (type function new-value)) + ;; It's not worth bothering to teach the compiler to efficiently transform + ;; a type test involving FUNCALLABLE-STANDARD-OBJECT, not the least + ;; of the problems being that the type isn't known during make-host-2. + (unless (and (function-with-layout-p fin) + (logtest (layout-flags (%fun-layout fin)) + +pcl-object-layout-flag+)) + (error 'type-error :datum fin :expected-type 'funcallable-standard-object)) (setf (%funcallable-instance-fun fin) new-value)) ;;; FIXME: these macros should just go away. It's not clear whether @@ -187,27 +196,15 @@ (setf (fdefinition new-name) fun)) fun) -;;; FIXME: probably no longer needed after init -(defmacro precompile-random-code-segments (&optional system) - `(progn - (eval-when (:compile-toplevel) - (update-dispatch-dfuns)) - (precompile-function-generators ,system) - (precompile-dfun-constructors ,system) - (precompile-ctors))) - ;;; This definition is for interpreted code. ;;; FIXME: (1) is EXPLICIT-CHECK really doing anything here? ;;; (2) why isn't this named STANDARD-OBJECT-P? (defun pcl-instance-p (x) (declare (explicit-check)) (%pcl-instance-p x)) -(defmacro %std-instance-slots (x) - `(%instance-ref ,x ,sb-vm:instance-data-start)) (defmacro std-instance-slots (x) - `(truly-the simple-vector (%std-instance-slots ,x))) -;; %fsc-instance-slots is defined in src/pcl/pre-warm + `(truly-the simple-vector (%instance-ref ,x ,sb-vm:instance-data-start))) (defmacro fsc-instance-slots (x) - `(truly-the simple-vector (%fsc-instance-slots ,x))) + `(truly-the simple-vector (%funcallable-instance-info ,x 0))) ;;; FIXME: These functions are called every place we do a ;;; CALL-NEXT-METHOD, and probably other places too. It's likely worth @@ -230,92 +227,10 @@ ;; (once in the test of PCL-INSTANCE-P and once in GET-SLOTS). (cond ((std-instance-p instance) (std-instance-slots instance)) ((fsc-instance-p instance) (fsc-instance-slots instance)))) - -;;;; structure-instance stuff -;;;; -;;;; FIXME: Now that the code is SBCL-only, this extra layer of -;;;; abstraction around our native structure representation doesn't -;;;; seem to add anything useful, and could probably go away. - -;;; The definition of STRUCTURE-TYPE-P was moved to early-low.lisp. - -(defun structure-type-slot-description-list (type) - (let* ((dd (find-defstruct-description type)) - (include (dd-include dd)) - (all-slots (dd-slots dd))) - (multiple-value-bind (super slot-overrides) - (if (consp include) - (values (car include) (mapcar #'car (cdr include))) - (values include nil)) - (let ((included-slots - (when super - (dd-slots (find-defstruct-description super))))) - (loop for slot = (pop all-slots) - for included-slot = (pop included-slots) - while slot - when (or (not included-slot) - (member (dsd-name included-slot) slot-overrides :test #'eq)) - collect slot))))) - -(defun uninitialized-accessor-function (type slotd) - (lambda (&rest args) - (declare (ignore args)) - (error "~:(~A~) function~@[ for ~S ~] not yet initialized." - type slotd))) - -(defun structure-slotd-name (slotd) - (dsd-name slotd)) - -(defun structure-slotd-accessor-symbol (slotd) - (dsd-accessor-name slotd)) - -(defun structure-slotd-reader-function (slotd) - (let ((name (dsd-accessor-name slotd))) - (if (fboundp name) - (fdefinition name) - (uninitialized-accessor-function :reader slotd)))) - -;;; Return a function to write the slot identified by SLOTD. -;;; This is easy for read/write slots - we just return the accessor -;;; that was already set up - but it requires work for read-only slots. -;;; Basically we get the slotter-setter-lambda-form and compile it. -;;; Using (COERCE lambda-form 'FUNCTION) as used to be done might produce -;;; an interpreted function. I'm not sure whether that's right or wrong, -;;; because if the DEFSTRUCT itself were evaluated, then the ordinary -;;; accessors would indeed be interpreted. However if the DEFSTRUCT were -;;; compiled, and the fasl loaded in a Lisp with *EVALUATOR-MODE* = :INTERPRET, -;;; arguably this is against the expectation that all things got compiled. -;;; But can people really expect that manipulating read-only slots -;;; via (SETF SLOT-VALUE) should be fast? -;;; -;;; Damned-if-you-do / damned-if-you don't - the best thing would be to -;;; compile all accessors at "really" compile-time but not store the writer -;;; for a reaadonly slot under the #<fdefn> for #'(SETF slot-name). -;;; -(defun structure-slotd-writer-function (type slotd) - ;; TYPE is not used, because the DD is taken from runtime data. - (declare (ignore type)) - (if (dsd-read-only slotd) - ;; We'd like to compile the writer just-in-time and store it - ;; back into the STRUCTURE-DIRECT-SLOT-DEFINITION and also - ;; the LAYOUT for the class, but we don't have a handle on - ;; any of the containing objects. So this has to be a closure. - (let ((setter 0)) - (lambda (newval instance) - (if (eql setter 0) - (let* ((dd (layout-info (%instance-layout instance))) - (f (compile nil (slot-setter-lambda-form dd slotd)))) - (if (functionp f) - (funcall (setq setter f) newval instance) - (uninitialized-accessor-function :writer slotd))) - (funcall (truly-the function setter) newval instance)))) - (let ((name `(setf ,(dsd-accessor-name slotd)))) - (if (fboundp name) - (fdefinition name) - (uninitialized-accessor-function :writer slotd))))) - -(defun structure-slotd-type (slotd) - (dsd-type slotd)) -(defun structure-slotd-init-form (slotd) - (dsd-default slotd)) +;;; This is here, moved from src/pcl/boot so that it gets a 1-byte layout ID +(defstruct (fast-method-call (:copier nil)) + (function #'identity :type function) + pv + next-method-call + arg-info) diff --git a/src/pcl/macros.lisp b/src/pcl/macros.lisp index a335b7a5bf..de45926775 100644 --- a/src/pcl/macros.lisp +++ b/src/pcl/macros.lisp @@ -44,40 +44,11 @@ (dolist (form (cdr d)) (when (and (consp form) (eq (car form) name)) (return-from get-declaration (cdr form)))))) - -(defmacro dolist-carefully ((var list improper-list-handler) &body body) - `(let ((,var nil) - (.dolist-carefully. ,list)) - (loop (when (null .dolist-carefully.) (return nil)) - (if (consp .dolist-carefully.) - (progn - (setq ,var (pop .dolist-carefully.)) - ,@body) - (,improper-list-handler))))) ;;;; FIND-CLASS ;;;; ;;;; This is documented in the CLOS specification. -(define-condition illegal-class-name-error (error) - ((name :initarg :name :reader illegal-class-name-error-name)) - (:default-initargs :name (missing-arg)) - (:report (lambda (condition stream) - (format stream "~@<~S is not a legal class name.~@:>" - (illegal-class-name-error-name condition))))) - -(declaim (inline legal-class-name-p check-class-name)) -(defun legal-class-name-p (thing) - (symbolp thing)) - -(defun check-class-name (thing &optional (allow-nil t)) - ;; Apparently, FIND-CLASS and (SETF FIND-CLASS) accept any symbol, - ;; but DEFCLASS only accepts non-NIL symbols. - (if (or (not (legal-class-name-p thing)) - (and (null thing) (not allow-nil))) - (error 'illegal-class-name-error :name thing) - thing)) - (define-condition class-not-found-error (sb-kernel::cell-error) ((sb-kernel::name :type (satisfies legal-class-name-p))) (:report (lambda (condition stream) @@ -170,23 +141,7 @@ (bind `((,object-var ,object)))) (setf object object-var) bind))) - ;; What's going on by not assuming that #'(SETF x) returns NEW-VALUE? - ;; It seems wrong to return anything other than what the SETF fun - ;; yielded. By analogy, when the SETF macro changes (SETF (F x) v) - ;; into (funcall #'(setf F) ...), it does not insert any code to - ;; enforce V as the overall value. So we do we do that here??? - (form `(let ((.new-value. ,new-value)) - ,(call-gf 'slot-writer-name object slot-name env '(.new-value.)) - .new-value.))) + (form (call-gf 'slot-writer-name object slot-name env (list new-value)))) (if bind-object `(let ,bind-object ,form) form)))) - -(defmacro function-funcall (form &rest args) - `(funcall (the function ,form) ,@args)) - -(defmacro function-apply (form &rest args) - `(apply (the function ,form) ,@args)) - -(defun get-setf-fun-name (name) - `(setf ,name)) diff --git a/src/pcl/methods.lisp b/src/pcl/methods.lisp index e53fa0475e..3bc8730db9 100644 --- a/src/pcl/methods.lisp +++ b/src/pcl/methods.lisp @@ -95,6 +95,16 @@ (invalid-method-initarg method "~@<~S of ~S is not a ~S.~@:>" :function fun 'function))) +(macrolet ((dolist-carefully ((var list improper-list-handler) &body body) + `(let ((,var nil) + (.dolist-carefully. ,list)) + (loop (when (null .dolist-carefully.) (return nil)) + (if (consp .dolist-carefully.) + (progn + (setq ,var (pop .dolist-carefully.)) + ,@body) + (,improper-list-handler)))))) + (defun check-qualifiers (method qualifiers) (flet ((improper-list () (invalid-method-initarg method @@ -135,6 +145,7 @@ ~V[~;~1{~S~}~;~1{~S and ~S~}~:;~{~#[~;and ~]~S~^, ~}~] ~ as ~2:*~V[~;a specializer~:;specializers~].~@:>" (length frcs) frcs))))) +) ; end MACROLET (defmethod shared-initialize :before ((method standard-method) slot-names &key @@ -360,18 +371,6 @@ (or restp (and number-of-requireds (/= number-of-requireds requireds))) specialized-argument-positions))) - -(defun make-discriminating-function-arglist (number-required-arguments restp) - (nconc (let ((args nil)) - (dotimes (i number-required-arguments) - (push (format-symbol *package* ;; ! is this right? - "Discriminating Function Arg ~D" - i) - args)) - (nreverse args)) - (when restp - `(&rest ,(format-symbol *package* - "Discriminating Function &rest Arg"))))) (defmethod generic-function-argument-precedence-order ((gf standard-generic-function)) @@ -492,27 +491,36 @@ (setf (info :function :type name) :generic-function)))))) (defun compute-gf-ftype (name) - (let ((gf (and (fboundp name) (fdefinition name)))) - (if (generic-function-p gf) - (let* ((ll (generic-function-lambda-list gf)) - ;; If the GF has &REST without &KEY then we don't augment - ;; the FTYPE with keywords, so as not to complain about keywords - ;; which seem not to be accepted. - (type (sb-c::ftype-from-lambda-list - (if (and (member '&rest ll) (not (member '&key ll))) - ll - (generic-function-pretty-arglist gf))))) - ;; It would be nice if globaldb were transactional, - ;; so that either both updates or neither occur. - (setf (info :function :type name) type - (info :function :where-from name) :defined-method) - type) - ;; The defaulting expression for (:FUNCTION :TYPE) does not store - ;; the default. For :GENERIC-FUNCTION that is not FBOUNDP we also - ;; don't, however this branch should never be reached because the - ;; info only stores :GENERIC-FUNCTION when methods are loaded. - ;; Maybe AVER that it does not happen? - (sb-c::ftype-from-fdefn name)))) + (let ((gf (and (fboundp name) (fdefinition name))) + (methods-in-compilation-unit (and (boundp 'sb-c::*methods-in-compilation-unit*) + sb-c::*methods-in-compilation-unit* + (gethash name sb-c::*methods-in-compilation-unit*)))) + (cond ((generic-function-p gf) + (let* ((ll (generic-function-lambda-list gf)) + ;; If the GF has &REST without &KEY then we don't augment + ;; the FTYPE with keywords, so as not to complain about keywords + ;; which seem not to be accepted. + (type (sb-c::ftype-from-lambda-list + (if (and (member '&rest ll) (not (member '&key ll))) + ll + (generic-function-pretty-arglist gf methods-in-compilation-unit))))) + + ;; It would be nice if globaldb were transactional, + ;; so that either both updates or neither occur. + (setf (info :function :where-from name) :defined-method + (info :function :type name) type))) + (methods-in-compilation-unit + (setf (info :function :where-from name) :defined-method + (info :function :type name) + (sb-c::ftype-from-lambda-list + (gf-merge-arglists methods-in-compilation-unit)))) + (t + ;; The defaulting expression for (:FUNCTION :TYPE) does not store + ;; the default. For :GENERIC-FUNCTION that is not FBOUNDP we also + ;; don't, however this branch should never be reached because the + ;; info only stores :GENERIC-FUNCTION when methods are loaded. + ;; Maybe AVER that it does not happen? + (sb-c::ftype-from-definition name))))) (defun real-add-method (generic-function method &optional skip-dfun-update-p) (flet ((similar-lambda-lists-p (old-method new-lambda-list) @@ -911,9 +919,9 @@ 'get-accessor-method-function))) ,optimized-std-fun))) (wrappers - (let ((wrappers (list (layout-of class) + (let ((wrappers (list (wrapper-of class) (class-wrapper class) - (layout-of slotd)))) + (wrapper-of slotd)))) (if (eq type 'writer) (cons (class-wrapper *the-class-t*) wrappers) wrappers))) @@ -1083,8 +1091,6 @@ (defmacro class-test (arg class) (cond ((eq class *the-class-t*) t) - ((eq class *the-class-slot-object*) - `(not (typep (classoid-of ,arg) 'system-classoid))) ((eq class *the-class-standard-object*) `(or (std-instance-p ,arg) (fsc-instance-p ,arg))) ((eq class *the-class-funcallable-standard-object*) @@ -1101,9 +1107,6 @@ (defmacro class-eq-test (arg class) `(eq (class-of ,arg) ',class)) -(defmacro eql-test (arg object) - `(eql ,arg ',object)) - (defun dnet-methods-p (form) (and (consp form) (or (eq (car form) 'methods) @@ -1273,8 +1276,8 @@ (defun compute-secondary-dispatch-function (generic-function net &optional method-alist wrappers) - (function-funcall (compute-secondary-dispatch-function1 generic-function net) - method-alist wrappers)) + (funcall (the function (compute-secondary-dispatch-function1 generic-function net)) + method-alist wrappers)) (defvar *eq-case-table-limit* 15) (defvar *case-table-limit* 10) @@ -1424,17 +1427,17 @@ (multiple-value-bind (cfunction constants) ;; We don't want NAMED-LAMBDA for any expressions handed to FNGEN, ;; because name mismatches will render the hashing ineffective. - (get-fun1 `(lambda ,arglist + (get-fun `(lambda ,arglist (declare (optimize (sb-c::store-closure-debug-pointer 3))) ,@(unless function-p `((declare (ignore .pv. .next-method-call.)))) (locally (declare #.*optimize-speed*) - (let ((emf ,net)) - ,(make-emf-call nargs applyp 'emf)))) - #'net-test-converter - #'net-code-converter - (lambda (form) - (net-constant-converter form generic-function))) + (let ((emf ,net)) + ,(make-emf-call nargs applyp 'emf)))) + #'net-test-converter + #'net-code-converter + (lambda (form) + (net-constant-converter form generic-function))) (lambda (method-alist wrappers) (let* ((alist (list nil)) (alist-tail alist)) @@ -1577,13 +1580,12 @@ ;; COMPUTE-DISCRIMINATING-FUNCTION, then (at least for the ;; special cases implemented as of 2006-05-09) any information ;; in the cache is misplaced. - (aver (null dfun-state))) - (typecase dfun-state - (null - (when (eq gf (load-time-value #'compute-applicable-methods t)) - (update-all-c-a-m-gf-info gf)) - (cond - ((eq gf (load-time-value #'slot-value-using-class t)) + (aver (null dfun-state))) + (typecase dfun-state + (null + (when (eq gf (load-time-value #'compute-applicable-methods t)) + (update-all-c-a-m-gf-info gf)) + (cond ((eq gf (load-time-value #'slot-value-using-class t)) (update-slot-value-gf-info gf 'reader) #'slot-value-using-class-dfun) ((eq gf (load-time-value #'(setf slot-value-using-class) t)) @@ -1631,8 +1633,8 @@ (make-final-dfun gf)) (t (make-initial-dfun gf)))) - (function dfun-state) - (cons (car dfun-state)))))) + (function dfun-state) + (cons (car dfun-state)))))) ;;; in general we need to support SBCL's encapsulation for generic ;;; functions: the default implementation of encapsulation changes the @@ -1665,7 +1667,7 @@ gf (generic-function-encapsulations gf) (call-next-method))) (defmethod (setf class-name) (new-value class) - (let ((classoid (layout-classoid (class-wrapper class)))) + (let ((classoid (wrapper-classoid (class-wrapper class)))) (if (and new-value (symbolp new-value)) (setf (classoid-name classoid) new-value) (setf (classoid-name classoid) nil))) @@ -1693,10 +1695,16 @@ ;;; The compiler uses this for type-checking that callers pass acceptable ;;; keywords, so don't make this do anything fancy like looking at effective ;;; methods without also fixing the compiler. -(defmethod generic-function-pretty-arglist ((gf standard-generic-function)) +(defmethod generic-function-pretty-arglist ((gf standard-generic-function) &optional methods-in-compilation-unit) (let ((gf-lambda-list (generic-function-lambda-list gf)) (methods (generic-function-methods gf))) - (flet ((canonize (k) + (flet ((lambda-list (m) + (or (and methods-in-compilation-unit + (gethash (cons (method-qualifiers m) + (unparse-specializers gf (method-specializers m))) + methods-in-compilation-unit)) + (method-lambda-list m))) + (canonize (k) (multiple-value-bind (kw var) (parse-key-arg-spec k) (if (and (eql (symbol-package kw) *keyword-package*) @@ -1705,15 +1713,54 @@ (list (list kw var)))))) (multiple-value-bind (llks required optional rest keys) (parse-lambda-list gf-lambda-list :silent t) - (collect ((keys (mapcar #'canonize keys))) - ;; Possibly extend the keyword parameters of the gf by - ;; additional key parameters of its methods: - (dolist (m methods - (make-lambda-list llks nil required optional rest (keys))) - (binding* (((m.llks nil nil nil m.keys) - (parse-lambda-list (method-lambda-list m) :silent t))) - (setq llks (logior llks m.llks)) - (dolist (k m.keys) - (unless (member (parse-key-arg-spec k) (keys) - :key #'parse-key-arg-spec :test #'eq) - (keys (canonize k))))))))))) + (if (or (ll-kwds-keyp llks) + (ll-kwds-restp llks)) + (collect ((keys (mapcar #'canonize keys))) + ;; Possibly extend the keyword parameters of the gf by + ;; additional key parameters of its methods: + (flet ((process (lambda-list) + (binding* (((m.llks nil nil nil m.keys) + (parse-lambda-list lambda-list :silent t))) + (setq llks (logior llks m.llks)) + (dolist (k m.keys) + (unless (member (parse-key-arg-spec k) (keys) + :key #'parse-key-arg-spec :test #'eq) + (keys (canonize k))))))) + (dolist (m methods) + (process (lambda-list m)))) + (make-lambda-list llks nil required optional rest (keys))) + (make-lambda-list llks nil required optional)))))) + +(defun gf-merge-arglists (methods-in-compilation-unit) + (flet ((canonize (k) + (multiple-value-bind (kw var) + (parse-key-arg-spec k) + (if (and (eql (symbol-package kw) *keyword-package*) + (string= kw var)) + var + (list (list kw var)))))) + (with-hash-table-iterator (iterator methods-in-compilation-unit) + (multiple-value-bind (llks required optional rest keys) + (parse-lambda-list (nth-value 2 (iterator)) :silent t) + (if (or (ll-kwds-keyp llks) + (ll-kwds-restp llks)) + (collect ((keys (mapcar #'canonize keys))) + ;; Possibly extend the keyword parameters of the gf by + ;; additional key parameters of its methods: + (flet ((process (lambda-list) + (binding* (((m.llks nil nil nil m.keys) + (parse-lambda-list lambda-list :silent t))) + (setq llks (logior llks m.llks)) + (dolist (k m.keys) + (unless (member (parse-key-arg-spec k) (keys) + :key #'parse-key-arg-spec :test #'eq) + (keys (canonize k))))))) + + (loop + (multiple-value-bind (more key value) (iterator) + (declare (ignore key)) + (unless more + (return)) + (process value))) + (make-lambda-list llks nil required optional rest (keys)))) + (make-lambda-list llks nil required optional)))))) diff --git a/src/pcl/pre-warm.lisp b/src/pcl/pre-warm.lisp index 1a55bc871c..d1e167bc90 100644 --- a/src/pcl/pre-warm.lisp +++ b/src/pcl/pre-warm.lisp @@ -52,10 +52,6 @@ ;;; function creation there is no danger of having the system get ;;; confused. -;;; FIXME: these all go in dynamic space and then allocate a trampoline when -;;; assigned into an FDEFN. Figure out how to put them in immobile space, -;;; or can we allocate them _anywhere_ with embedded code now? I think so! -;;; And why do we assign these info FDEFNs? What calls them via their names? #-sb-xc-host ; host doesn't need (progn (!defstruct-with-alternate-metaclass %method-function @@ -65,12 +61,11 @@ :metaclass-name static-classoid :metaclass-constructor make-static-classoid :dd-type funcallable-structure) -;;; Note: for x8-64 with #+immobile-code there are 2 additional raw slots which -;;; hold machine instructions to load the funcallable-instance-fun and jump to -;;; it, so that funcallable-instances can act like simple-funs, in as much as -;;; there's an address you can jump to without loading a register. +;; for x86-64 with compact-instance-header, generic functions are 6 words: +;; header, entrypoint, raw (x2), implementation function, slot vector +;; and the hash goes in 4 unused bytes of the second raw slot. (sb-kernel:!defstruct-with-alternate-metaclass standard-funcallable-instance - :slot-names (clos-slots hash-code) + :slot-names (clos-slots #-compact-instance-header hash-code) :constructor %make-standard-funcallable-instance :superclass-name function :metaclass-name static-classoid @@ -78,13 +73,6 @@ :dd-type funcallable-structure) ) -;;; Needed to compile the #n# reader because apparently some people think it amusing -;;; to create readable funcallable instances involving circularity and/or sharing. -;;; No constraint on the result type so that the slot implementation strategy -;;; is wholly defined within the warm build. -(defmacro %fsc-instance-slots (fin) - `(%funcallable-instance-info ,fin ,sb-vm:instance-data-start)) - ;;; Set up fake standard-classes. ;;; This is enough to fool the compiler into optimizing TYPEP into ;;; %INSTANCE-TYPEP. @@ -119,11 +107,6 @@ (long-method-combination long-method-combination-p) (short-method-combination short-method-combination-p))) -(defmacro set-layout-valid (layout) - `(let ((layout ,layout)) - (setf (layout-invalid layout) niL) - layout)) - #+sb-xc-host (progn ;;; Create #<SB-KERNEL::CONDITION-CLASSOID CONDITION> @@ -135,14 +118,14 @@ (let* ((name 'condition) (classoid (sb-kernel::make-condition-classoid :name name)) (cell (sb-kernel::make-classoid-cell name classoid)) - (layout (set-layout-valid - (make-layout (hash-layout-name name) + (layout (make-layout (hash-layout-name name) classoid - :inherits (vector (find-layout 't)) :depthoid 1 + :inherits (vector (find-layout 't)) :length (+ sb-vm:instance-data-start 1) - :flags +condition-layout-flag+)))) - (setf (classoid-layout classoid) layout + :flags +condition-layout-flag+ + :invalid nil))) + (setf (classoid-wrapper classoid) layout (info :type :classoid-cell name) cell (info :type :kind name) :instance)) @@ -151,14 +134,14 @@ (let* ((classoid (make-standard-classoid :name name)) (cell (sb-kernel::make-classoid-cell name classoid)) (layout - (set-layout-valid (make-layout (hash-layout-name name) classoid + :depthoid -1 :inherits (map 'vector #'find-layout (cons t (if fun-p '(function)))) :length 0 ; don't care - :depthoid -1)))) - (setf (classoid-layout classoid) layout + :invalid nil))) + (setf (classoid-wrapper classoid) layout (info :type :classoid-cell name) cell (info :type :kind name) :instance)))) ;; Because we don't wire into %INSTANCE-TYPEP any assumptions about @@ -190,3 +173,6 @@ `(defun ,predicate (x) (typep x ',class-name)))) *!early-class-predicates*)))) (define-class-predicates)) + +(defun safe-code-p (&optional env) + (sb-c::policy (or env (sb-c::make-null-lexenv)) (eql safety 3))) diff --git a/src/pcl/precom2.lisp b/src/pcl/precom2.lisp index 19aa113b77..ab6a805b2f 100644 --- a/src/pcl/precom2.lisp +++ b/src/pcl/precom2.lisp @@ -23,17 +23,26 @@ (in-package "SB-PCL") -(precompile-random-code-segments pcl) +(macrolet ((precompile-random-code-segments (&optional system) + `(progn + (eval-when (:compile-toplevel) + (update-dispatch-dfuns)) + (precompile-function-generators ,system) + (precompile-dfun-constructors ,system) + (precompile-ctors)))) + (precompile-random-code-segments pcl)) -(push '("SB-PCL" *pcl-package* *built-in-classes*) *!removable-symbols*) +(push '("SB-PCL" *built-in-classes*) *!removable-symbols*) +(defun !system-class-p (x) (typep x 'sb-pcl::system-class)) + +(let ((c (find-class 't))) + (assert (not (slot-boundp c 'sb-pcl::prototype)))) (let ((class (find-class 'sequence))) ;; Give the prototype a concrete prototype. It's an extra step because ;; SEQUENCE was removed from *built-in-classes* (setf (slot-value class 'prototype) #())) -(dolist (c (sb-vm:list-allocated-objects - :all - :test (compile nil '(lambda (x) (typep x 'sb-pcl::system-class))))) +(dolist (c (sb-vm:list-allocated-objects :all :test #'!system-class-p)) (when (slot-boundp c 'sb-pcl::prototype) (let ((val (slot-value c 'sb-pcl::prototype))) (assert (typep val c))))) diff --git a/src/pcl/print-object.lisp b/src/pcl/print-object.lisp index d4ed770ecf..26d78ac1dc 100644 --- a/src/pcl/print-object.lisp +++ b/src/pcl/print-object.lisp @@ -39,7 +39,7 @@ (let ((*print-pretty* t)) ; use pretty printer dispatch table, not PRINT-OBJECT (fmakunbound 'print-object) (defgeneric print-object (object stream)) - (!incorporate-cross-compiled-methods 'print-object)) + (!install-cross-compiled-methods 'print-object)) (unless (sb-impl::!c-runtime-noinform-p) (write-string " done ")) diff --git a/src/pcl/slot-name.lisp b/src/pcl/slot-name.lisp index 24eb99b8b7..ae81e73463 100644 --- a/src/pcl/slot-name.lisp +++ b/src/pcl/slot-name.lisp @@ -41,6 +41,14 @@ (defun slot-boundp-name (slot-name) (list 'slot-accessor :global slot-name 'boundp)) +(define-function-name-syntax slot-accessor (list) + (when (= (length list) 4) + (destructuring-bind (class slot rwb) (cdr list) + (when (and (member rwb '(sb-pcl::reader sb-pcl::writer sb-pcl::boundp)) + (symbolp slot) + (symbolp class)) + (values t slot))))) + ;;; This is the object that we stick into a slot to tell us that it is ;;; unbound. It is the same as the marker for unbound symbols. ;;; There are two ways to check whether a slot is unbound: diff --git a/src/pcl/slots-boot.lisp b/src/pcl/slots-boot.lisp index e092586782..9b9e6bf9b2 100644 --- a/src/pcl/slots-boot.lisp +++ b/src/pcl/slots-boot.lisp @@ -108,133 +108,6 @@ (declare (type function function)) (values value (slot-definition-location slotd)))))) -(defun make-optimized-std-reader-method-function - (fsc-p slotd slot-name location) - (set-fun-name - (etypecase location - (fixnum - (if fsc-p - (lambda (instance) - (check-obsolete-instance instance) - (let ((value (clos-slots-ref (fsc-instance-slots instance) - location))) - (if (unbound-marker-p value) - (values - (slot-unbound (class-of instance) instance slot-name)) - value))) - (lambda (instance) - (check-obsolete-instance instance) - (let ((value (clos-slots-ref (std-instance-slots instance) - location))) - (if (unbound-marker-p value) - (values - (slot-unbound (class-of instance) instance slot-name)) - value))))) - (cons - (lambda (instance) - (check-obsolete-instance instance) - (let ((value (cdr location))) - (if (unbound-marker-p value) - (values (slot-unbound (class-of instance) instance slot-name)) - value)))) - (null - (lambda (instance) - (declare (ignore instance)) - (instance-structure-protocol-error slotd 'slot-value-using-class)))) - `(reader ,slot-name))) - -(defun make-optimized-std-writer-method-function (fsc-p slotd slot-name location) - ;; The (WHEN SLOTD ...) gunk is for building early slot definitions. - (let* ((class (when slotd (slot-definition-class slotd))) - (safe-p (when slotd (safe-p class))) - (orig-wrapper (when safe-p (class-wrapper class))) - (info (when safe-p (slot-definition-info slotd))) - (writer-fun (etypecase location - ;; In SAFE-P case the typechecking already validated the instance. - (fixnum - (if fsc-p - (if safe-p - (lambda (nv instance) - (setf (clos-slots-ref (fsc-instance-slots instance) - location) - nv)) - (lambda (nv instance) - (check-obsolete-instance instance) - (setf (clos-slots-ref (fsc-instance-slots instance) - location) - nv))) - (if safe-p - (lambda (nv instance) - (setf (clos-slots-ref (std-instance-slots instance) - location) - nv)) - (lambda (nv instance) - (check-obsolete-instance instance) - (setf (clos-slots-ref (std-instance-slots instance) - location) - nv))))) - (cons - (if safe-p - (lambda (nv instance) - (declare (ignore instance)) - (setf (cdr location) nv)) - (lambda (nv instance) - (check-obsolete-instance instance) - (setf (cdr location) nv)))) - (null - (lambda (nv instance) - (declare (ignore nv instance)) - (instance-structure-protocol-error - slotd - '(setf slot-value-using-class)))))) - (checking-fun (when safe-p - (lambda (new-value instance) - ;; If we have a TYPE-CHECK-FUNCTION, call it. - (let* (;; Note that the class of INSTANCE here is not - ;; neccessarily the SLOT-DEFINITION-CLASS of - ;; the SLOTD passed to M-O-S-W-M-F, since it's - ;; e.g. possible for a subclass to define a - ;; slot of the same name but with no - ;; accessors. So we may need to fetch the - ;; right SLOT-INFO from the wrapper instead of - ;; just closing over it. - (wrapper (valid-wrapper-of instance)) - (typecheck - (slot-info-typecheck - (if (eq wrapper orig-wrapper) - info - (cdr (find-slot-cell wrapper slot-name)))))) - (when typecheck - (funcall typecheck new-value))) - ;; Then call the real writer. - (funcall writer-fun new-value instance))))) - (set-fun-name (if safe-p - checking-fun - writer-fun) - `(writer ,slot-name)))) - -(defun make-optimized-std-boundp-method-function - (fsc-p slotd slot-name location) - (set-fun-name - (etypecase location - (fixnum (if fsc-p - (lambda (instance) - (check-obsolete-instance instance) - (not (unbound-marker-p (clos-slots-ref (fsc-instance-slots instance) - location)))) - (lambda (instance) - (check-obsolete-instance instance) - (not (unbound-marker-p (clos-slots-ref (std-instance-slots instance) - location)))))) - (cons (lambda (instance) - (check-obsolete-instance instance) - (not (unbound-marker-p (cdr location))))) - (null - (lambda (instance) - (declare (ignore instance)) - (instance-structure-protocol-error slotd 'slot-boundp-using-class)))) - `(boundp ,slot-name))) - (defun make-optimized-structure-slot-value-using-class-method-function (function) (declare (type function function)) @@ -349,7 +222,7 @@ ;; for CLOS typechecking when it's not in use. `(if typecheck (make-mf-lambda - (funcall (the function typecheck) nv) + (setf nv (funcall (the function typecheck) nv)) ,@body) (make-mf-lambda ,@body)))) @@ -488,145 +361,25 @@ (lambda (instance) (pv-binding1 ((bug "Please report this") (instance) nil) - (instance-boundp-custom .pv. 0 instance)))))))))) - -;;;; FINDING SLOT DEFINITIONS -;;; -;;; Historical PCL found slot definitions by iterating over -;;; CLASS-SLOTS, which is O(N) for number of slots, and moreover -;;; requires a GF call (for SLOT-DEFINITION-NAME) for each slot in -;;; list up to the desired one. -;;; -;;; Current SBCL hashes the effective slot definitions, and some -;;; information pulled out from them into a simple-vector, with bucket -;;; chains made out of plists keyed by the slot names. This fixes -;;; gives O(1) performance, and avoid the GF calls. -;;; -;;; MAKE-SLOT-TABLE constructs the hashed vector out of a list of -;;; effective slot definitions and the class they pertain to, and -;;; FIND-SLOT-DEFINITION knows how to look up slots in that vector. -;;; -;;; The only bit of cleverness in the implementation is to make the -;;; vectors fairly tight, but always longer then 0 elements: -;;; -;;; -- We don't want to waste huge amounts of space no these vectors, -;;; which are mostly required by things like SLOT-VALUE with a -;;; variable slot name, so a constant extension over the minimum -;;; size seems like a good choise. -;;; -;;; -- As long as the vector always has a length > 0 -;;; FIND-SLOT-DEFINITION doesn't need to handle the rare case of an -;;; empty vector separately: it just returns a NIL. -;;; -;;; In addition to the slot-definition we also store the slot-location -;;; and type-check function for instances of standard metaclasses, so -;;; that SLOT-VALUE &co using variable slot names can get at them -;;; without additional GF calls. -;;; -;;; Notes: -;;; It would also be nice to have STANDARD-INSTANCE-STRUCTURE-P -;;; generic instead of checking versus STANDARD-CLASS and -;;; FUNCALLABLE-STANDARD-CLASS. -;;; -;;; Uh, the comments above talking about how FIND-SLOT-DEFINITION -;;; does something with slot vectors has no basis in reality. -;;; Probably the comments need fixing, rather than the code. + (instance-boundp-custom .pv. 0 instance))))))))) -(defun find-slot-definition (class slot-name &optional errorp) - (unless (class-finalized-p class) - (or (try-finalize-inheritance class) - (if errorp - (error "Cannot look up slot-definition for ~S in ~S (too early to finalize.)" - slot-name class) - (return-from find-slot-definition (values nil nil))))) - (dolist (slotd (class-slots class) - (if errorp - (error "No slot called ~S in ~S." slot-name class) - (values nil t))) - (when (eq slot-name (slot-definition-name slotd)) - (return (values slotd t))))) + (defun make-fallback-reader-method-function (slot-name) + (make-initargs + slot-name :reader + (make-method-function + (lambda (instance) + (slot-value instance slot-name))))) -(defun find-slot-cell (wrapper slot-name) - (declare (symbol slot-name)) - (declare (optimize (sb-c::insert-array-bounds-checks 0))) - (let* ((vector (layout-slot-table wrapper)) - (modulus (truly-the index (svref vector 0))) - ;; Can elide the 'else' branch of (OR symbol-hash ensure-symbol-hash) - ;; because every symbol in the slot-table already got a nonzero hash. - (index (rem (symbol-hash slot-name) modulus)) - (probe (svref vector (1+ index)))) - (declare (simple-vector vector) (index index)) - (cond ((fixnump probe) - (do* ((count (svref vector (1- (truly-the index probe)))) - (end (truly-the index (+ probe count))) - (j probe (1+ j))) - ((>= j end)) - (declare (index count j)) - (when (eq (svref vector j) slot-name) - (return (svref vector (truly-the index (+ j count))))))) - ((eq (car (truly-the list probe)) slot-name) - (cdr probe))))) + (defun make-fallback-writer-method-function (slot-name) + (make-initargs + slot-name :writer + (make-method-function + (lambda (nv instance) + (setf (slot-value instance slot-name) nv))))) -(defun make-slot-table (class slots &optional bootstrap) - (unless slots - ;; *** If changing this empty table value to something else, - ;; be sure to make a similar change to MAKE-COLD-LAYOUT in - ;; compiler/generic/genesis as well as in DEFSTRUCT LAYOUT. - ;; A DEFCONSTANT for this would only transfer the problem - ;; to cold-init in a different sort of way. :-( - (return-from make-slot-table #(1 nil))) - (let* ((n (+ (logior (length slots) 1) 2)) ; an odd divisor is preferred - (vector (make-array n :initial-element nil))) - (flet ((add-to-vector (name slot) - (declare (symbol name) - (optimize (sb-c::insert-array-bounds-checks 0))) - (let ((index (rem (ensure-symbol-hash name) n))) - (setf (svref vector index) - (acons name - (cons (when (or bootstrap - (and (standard-class-p class) - (slot-accessor-std-p slot 'all))) - (if bootstrap - (early-slot-definition-location slot) - (slot-definition-location slot))) - (the slot-info - (if bootstrap - (early-slot-definition-info slot) - (slot-definition-info slot)))) - (svref vector index)))))) - (if (eq 'complete **boot-state**) - (dolist (slot slots) - (add-to-vector (slot-definition-name slot) slot)) - (dolist (slot slots) - (add-to-vector (early-slot-definition-name slot) slot)))) - ;; The VECTOR as computed above implements a hash table with chaining. - ;; Rather than store chains using cons cells, chains can be stored in the - ;; vector itself at the end, with the table entry pointing to another - ;; index in the vector. The chain length is stored first, then all keys, - ;; then all values. The resulting structure takes less memory than - ;; linked lists, and can be scanned faster. As an exception, for lists - ;; of length 1, the table cell holds a (key . value) pair directly. - (let* ((final-n - (+ 1 n - ;; number of additional cells needed to represent linked lists - ;; as length-prefixed subsequences in the final vector. - (loop for cell across vector - for count = (length cell) - sum (if (<= count 1) 0 (1+ (* count 2)))))) - (final-vector (make-array final-n)) - (data-index (1+ n))) ; after the hashtable portion of the vector - (setf (aref final-vector 0) n) ; the modulus - (dotimes (i n final-vector) - (let ((alist (aref vector i))) - (if (not (cdr alist)) ; store it in the final vector as-is - (setf (aref final-vector (1+ i)) (car alist)) - (let ((count (length alist))) - ;; Probed cell holds the index of the first symbol. - ;; The symbol count precedes the first symbol cell. - (setf (aref final-vector (1+ i)) (1+ data-index) - (aref final-vector data-index) count) - (dolist (cell alist) - (setf (aref final-vector (incf data-index)) (car cell))) - (dolist (cell alist) - (setf (aref final-vector (incf data-index)) (cdr cell))) - (incf data-index)))))))) + (defun make-fallback-boundp-method-function (slot-name) + (make-initargs + slot-name :boundp + (make-method-function + (lambda (instance) + (slot-boundp instance slot-name)))))) diff --git a/src/pcl/slots.lisp b/src/pcl/slots.lisp index 5e996206dc..67479e6cd3 100644 --- a/src/pcl/slots.lisp +++ b/src/pcl/slots.lisp @@ -42,6 +42,9 @@ (cell-error-name condition) (type-of (unbound-slot-instance condition)))))))) +(define-condition missing-slot (cell-error simple-type-error) + ()) + ;;; These three functions work on std-instances and fsc-instances. These are ;;; instances for which it is possible to change the wrapper and the slots. ;;; @@ -95,7 +98,7 @@ (return-from slot-value (if cell (funcall (slot-info-reader (cdr cell)) object) - (values (slot-missing (wrapper-class* wrapper) object + (values (slot-missing (wrapper-class wrapper) object slot-name 'slot-value))))) ;; this next test means CONSP, but the transform that weakens ;; CONSP to LISTP isn't working here for some reason. @@ -104,21 +107,21 @@ (t (bug "Bogus slot cell in SLOT-VALUE: ~S" cell))))) (if (unbound-marker-p value) - (slot-unbound (wrapper-class* wrapper) object slot-name) + (slot-unbound (wrapper-class wrapper) object slot-name) value))) (defun set-slot-value (object slot-name new-value) (let* ((wrapper (valid-wrapper-of object)) (cell (or (find-slot-cell wrapper slot-name) (return-from set-slot-value - (progn (slot-missing (wrapper-class* wrapper) + (progn (slot-missing (wrapper-class wrapper) object slot-name 'setf new-value) new-value)))) (location (car cell)) (info (cdr cell)) (typecheck (slot-info-typecheck info))) (when typecheck - (funcall typecheck new-value)) + (setf new-value (funcall typecheck new-value))) (cond ((fixnump location) (if (std-instance-p object) (setf (standard-instance-access object location) new-value) @@ -143,13 +146,13 @@ (let* ((wrapper (valid-wrapper-of object)) (cell (or (find-slot-cell wrapper slot-name) (return-from slot-value - (values (slot-missing (wrapper-class* wrapper) object slot-name + (values (slot-missing (wrapper-class wrapper) object slot-name 'cas (list old-value new-value)))))) (location (car cell)) (info (cdr cell)) (typecheck (slot-info-typecheck info))) (when typecheck - (funcall typecheck new-value)) + (setf new-value (funcall typecheck new-value))) (let ((old (cond ((fixnump location) (if (std-instance-p object) (cas (standard-instance-access object location) old-value new-value) @@ -163,7 +166,7 @@ (t (bug "Bogus slot-cell in (CAS SLOT-VALUE): ~S" cell))))) (if (and (unbound-marker-p old) (neq old old-value)) - (slot-unbound (wrapper-class* wrapper) object slot-name) + (slot-unbound (wrapper-class wrapper) object slot-name) old)))) (defun slot-boundp (object slot-name) @@ -179,7 +182,7 @@ (return-from slot-boundp (if cell (funcall (slot-info-boundp (cdr cell)) object) - (and (slot-missing (wrapper-class* wrapper) object + (and (slot-missing (wrapper-class wrapper) object slot-name 'slot-boundp) t)))) ((listp location) ; forcibly transform CONSP to LISTP @@ -199,10 +202,10 @@ +slot-unbound+))) ((not location) (if cell - (let ((class (wrapper-class* wrapper))) + (let ((class (wrapper-class wrapper))) (slot-makunbound-using-class class object (find-slot-definition class slot-name))) - (slot-missing (wrapper-class* wrapper) object slot-name + (slot-missing (wrapper-class wrapper) object slot-name 'slot-makunbound))) ((listp location) ; forcibly transform CONSP to LISTP (setf (cdr location) +slot-unbound+)) @@ -369,26 +372,30 @@ (defmethod slot-missing ((class t) instance slot-name operation &optional new-value) - (error "~@<When attempting to ~A, the slot ~S is missing from the ~ + (error 'missing-slot + :name slot-name + :format-control + "~@<When attempting to ~A, the slot ~S is missing from the ~ object ~S.~@[~%~a~]~@:>" - (ecase operation - (slot-value "read the slot's value (slot-value)") - (setf (format nil - "set the slot's value to ~S (SETF of SLOT-VALUE)" - new-value)) - (slot-boundp "test to see whether slot is bound (SLOT-BOUNDP)") - (slot-makunbound "make the slot unbound (SLOT-MAKUNBOUND)")) - slot-name - instance - (let ((slot (and (typep class 'slot-class) - (find slot-name (class-slots class) - :key #'slot-definition-name - :test #'string-equal)))) - (when slot - (format nil "It has a slot ~/sb-ext:print-symbol-with-prefix/, while ~ + :format-arguments + (list (ecase operation + (slot-value "read the slot's value (slot-value)") + (setf (format nil + "set the slot's value to ~S (SETF of SLOT-VALUE)" + new-value)) + (slot-boundp "test to see whether slot is bound (SLOT-BOUNDP)") + (slot-makunbound "make the slot unbound (SLOT-MAKUNBOUND)")) + slot-name + instance + (let ((slot (and (typep class 'slot-class) + (find slot-name (class-slots class) + :key #'slot-definition-name + :test #'string-equal)))) + (when slot + (format nil "It has a slot ~/sb-ext:print-symbol-with-prefix/, while ~ ~/sb-ext:print-symbol-with-prefix/ is requested." - (slot-definition-name slot) - slot-name))))) + (slot-definition-name slot) + slot-name)))))) (defmethod slot-unbound ((class t) instance slot-name) (restart-case @@ -413,7 +420,7 @@ ;; in list. The only exceptions are when there are non-local slots ;; before the one we want. (slot-definition-name - (find position (layout-slot-list (layout-of instance)) + (find position (wrapper-slot-list (wrapper-of instance)) :key #'slot-definition-location))) (cons (car position)))))) @@ -449,11 +456,3 @@ :format-control "~S called on ~S, which is not yet finalized." :format-arguments (list 'class-slots class) :references '((:amop :generic-function class-slots))))) - -(defun %set-slots (object names &rest values) - (mapc (lambda (name value) - (if (unbound-marker-p value) - ;; SLOT-MAKUNBOUND-USING-CLASS might do something nonstandard. - (slot-makunbound object name) - (setf (slot-value object name) value))) - names values)) diff --git a/src/pcl/std-class.lisp b/src/pcl/std-class.lisp index 92267a7453..2e252e39df 100644 --- a/src/pcl/std-class.lisp +++ b/src/pcl/std-class.lisp @@ -174,7 +174,13 @@ (defmethod add-direct-subclass ((class class) (subclass class)) (with-slots (direct-subclasses) class (with-world-lock () - (pushnew subclass direct-subclasses :test #'eq)) + (pushnew subclass direct-subclasses :test #'eq) + (let ((wrapper (class-wrapper subclass))) + (when wrapper + (let ((classoid (wrapper-classoid wrapper))) + (dovector (super-wrapper (wrapper-inherits wrapper)) + (sb-kernel::add-subclassoid (wrapper-classoid super-wrapper) + classoid wrapper)))))) subclass)) (defmethod remove-direct-subclass ((class class) (subclass class)) (with-slots (direct-subclasses) class @@ -182,11 +188,9 @@ (setq direct-subclasses (remove subclass direct-subclasses)) ;; Remove from classoid subclasses as well. (let ((classoid (class-classoid subclass))) - (dovector (super-layout (layout-inherits (classoid-layout classoid))) - (let* ((super (layout-classoid super-layout)) - (subclasses (classoid-subclasses super))) - (when subclasses - (remhash classoid subclasses)))))) + (dovector (super-wrapper (wrapper-inherits (classoid-wrapper classoid))) + (sb-kernel::remove-subclassoid classoid + (wrapper-classoid super-wrapper))))) subclass)) ;;; Maintaining the direct-methods and direct-generic-functions backpointers. @@ -300,7 +304,14 @@ (let ((table (specializer-method-table self)) (object (specializer-object self))) (if create - (ensure-gethash object table (cons nil nil) t) + (with-system-mutex ((hash-table-lock table)) + (ensure-gethash object table (cons nil nil))) + ;; FIXME: in the CREATE case we're locking, because we might be inserting, + ;; and must ensure mutual exclusion with other writers. Fine, + ;; but SBCL's hash-tables aren't *reader* *safe* with any writer, so + ;; how can we know that this branch is safe? Honestly I have no idea. + ;; I believe that the lock should scope be widened, + ;; surrounding either branch of the IF. (gethash object table)))) (defun map-specializers (function) @@ -535,14 +546,16 @@ ;; some class is forthcoming, because there are legitimate ;; questions one can ask of the type system, implemented in ;; terms of CLASSOIDs, involving forward-referenced classes. So. - (let ((layout (make-wrapper 0 class))) - (setf (slot-value class 'wrapper) layout) + (let ((wrapper (make-wrapper 0 class))) + (setf (slot-value class 'wrapper) wrapper) (let ((cpl (compute-preliminary-cpl class))) - (set-layout-inherits layout + (set-layout-inherits wrapper (order-layout-inherits (map 'simple-vector #'class-wrapper - (reverse (rest cpl)))))) - (register-layout layout :invalidate t)))) + (reverse (rest cpl)))) + nil 0)) + (set-bitmap-and-flags wrapper) + (register-layout wrapper :invalidate t)))) (mapc #'make-preliminary-layout (class-direct-subclasses class)))))) @@ -602,7 +615,7 @@ finalized-p t (classoid-pcl-class classoid) class direct-supers direct-superclasses - wrapper (classoid-layout classoid) + wrapper (classoid-wrapper classoid) %class-precedence-list (compute-class-precedence-list class) cpl-available-p t (getf plist 'direct-default-initargs) @@ -610,7 +623,7 @@ (add-direct-subclasses class direct-superclasses) (let ((slots (compute-slots class))) (setf (slot-value class 'slots) slots) - (setf (layout-slot-table wrapper) (make-slot-table class slots))))) + (setf (wrapper-slot-table wrapper) (make-slot-table class slots))))) ;; Comment from Gerd's PCL, 2003-05-15: ;; ;; We don't ADD-SLOT-ACCESSORS here because we don't want to @@ -675,8 +688,8 @@ (error "Structure slots must have :INSTANCE allocation."))) (defun make-structure-class-defstruct-form (name direct-slots include) - (let* ((conc-name (format-symbol *package* "~S structure class " name)) - (constructor (format-symbol *package* "~Aconstructor" conc-name)) + (let* ((conc-name (pkg-format-symbol *package* "~S structure class " name)) + (constructor (pkg-format-symbol *package* "~Aconstructor" conc-name)) (included-name (class-name include)) (included-slots (when include @@ -754,7 +767,7 @@ ;; (LAMBDA () (SB-PCL::FAST-MAKE-INSTANCE #<STRUCTURE-CLASS THING>)) ;; So maybe we can figure out how to bundle two lambdas together? (lambda () - (let* ((dd (layout-info (class-wrapper class))) + (let* ((dd (wrapper-dd (class-wrapper class))) (f (%make-structure-instance-allocator dd nil))) (if (functionp f) (funcall (setf (slot-value class 'defstruct-constructor) f)) @@ -791,7 +804,7 @@ (when defstruct-p (let* ((slot-name (getf pl :name)) (accessor - (format-symbol *package* + (pkg-format-symbol *package* "~S structure class ~A" name slot-name))) (setq pl (list* :defstruct-accessor-symbol @@ -830,10 +843,10 @@ (let ((slots (compute-slots class))) (setf (slot-value class 'slots) slots) (let* ((lclass (find-classoid (slot-value class 'name))) - (layout (classoid-layout lclass))) + (layout (classoid-wrapper lclass))) (setf (classoid-pcl-class lclass) class) (setf (slot-value class 'wrapper) layout) - (setf (layout-slot-table layout) (make-slot-table class slots)))) + (setf (wrapper-slot-table layout) (make-slot-table class slots)))) (setf (slot-value class 'finalized-p) t) (add-slot-accessors class direct-slots))) @@ -1030,30 +1043,34 @@ (return nil))))))) (defun style-warn-about-duplicate-slots (class) - (do* ((slots (slot-value class 'slots) (cdr slots)) - (dupes nil)) - ((null slots) - (when dupes - (style-warn - "~@<slot names with the same SYMBOL-NAME but ~ - different SYMBOL-PACKAGE (possible package problem) ~ - for class ~S:~4I~@:_~<~@{~/sb-ext:print-symbol-with-prefix/~^~:@_~}~:>~@:>" - class dupes))) - (let* ((slot-name (slot-definition-name (car slots))) - (oslots (and (not (eq (symbol-package slot-name) - *pcl-package*)) - (remove-if - (lambda (slot-name-2) - (or (eq (symbol-package slot-name-2) - *pcl-package*) - (string/= slot-name slot-name-2))) - (cdr slots) - :key #'slot-definition-name)))) - (when oslots - (pushnew (cons slot-name - (mapcar #'slot-definition-name oslots)) - dupes - :test #'string= :key #'car))))) + (flet ((symbol-exported-p (symbol) + (let ((packages (list-all-packages)) + (name (symbol-name symbol))) + (dolist (package packages nil) + (multiple-value-bind (s status) (find-symbol name package) + (when (and (eq s symbol) (eq status :external)) + (return t))))))) + (do* ((dslots (class-direct-slots class) (cdr dslots)) + (slots (slot-value class 'slots)) + (dupes nil)) + ((null dslots) + (when dupes + (style-warn + "~@<slot names with the same SYMBOL-NAME but ~ + different SYMBOL-PACKAGE (possible package problem) ~ + for class ~S:~4I~@:_~<~@{~/sb-ext:print-symbol-with-prefix/~^~:@_~}~:>~@:>" + class dupes))) + (let* ((slot-name (slot-definition-name (car dslots))) + (oslots (remove-if + (lambda (slot-name-2) + (or (eq slot-name slot-name-2) + (string/= slot-name slot-name-2) + (not (symbol-exported-p slot-name-2)))) + slots + :key #'slot-definition-name))) + (when oslots + (pushnew (cons slot-name (mapcar #'slot-definition-name oslots)) dupes + :test #'string= :key #'car)))))) (defun %update-slots (class eslotds) (multiple-value-bind (instance-slots class-slots custom-slots) @@ -1062,7 +1079,7 @@ (owrapper (class-wrapper class)) (nwrapper (cond ((and owrapper - (slot-layouts-compatible-p (layout-slot-list owrapper) + (slot-layouts-compatible-p (wrapper-slot-list owrapper) instance-slots class-slots custom-slots)) owrapper) ((or (not owrapper) @@ -1078,9 +1095,9 @@ (class-wrapper class))))) (%update-lisp-class-layout class nwrapper) (setf (slot-value class 'slots) eslotds - (layout-slot-list nwrapper) eslotds - (layout-slot-table nwrapper) (make-slot-table class eslotds) - (layout-length nwrapper) nslots + (wrapper-slot-list nwrapper) eslotds + (wrapper-slot-table nwrapper) (make-slot-table class eslotds) + (wrapper-length nwrapper) nslots (slot-value class 'wrapper) nwrapper) (style-warn-about-duplicate-slots class) (setf (slot-value class 'finalized-p) t) @@ -1398,21 +1415,21 @@ (eq (class-of class) *the-class-standard-class*)))) ;;; What this does depends on which of the four possible values of -;;; LAYOUT-INVALID the PCL wrapper has; the simplest case is when it +;;; WRAPPER-INVALID the PCL wrapper has; the simplest case is when it ;;; is (:FLUSH <wrapper>) or (:OBSOLETE <wrapper>), when there is ;;; nothing to do, as the new wrapper has already been created. If -;;; LAYOUT-INVALID returns NIL, then we invalidate it (setting it to +;;; WRAPPER-INVALID returns NIL, then we invalidate it (setting it to ;;; (:FLUSH <wrapper>); UPDATE-SLOTS later gets to choose whether or ;;; not to "upgrade" this to (:OBSOLETE <wrapper>). ;;; -;;; This leaves the case where LAYOUT-INVALID returns T, which happens +;;; This leaves the case where WRAPPER-INVALID returns T, which happens ;;; when REGISTER-LAYOUT has invalidated a superclass of CLASS (which ;;; invalidated all the subclasses in SB-KERNEL land). Again, here we ;;; must flush the caches and allow UPDATE-SLOTS to decide whether to ;;; obsolete the wrapper. ;;; ;;; FIXME: either here or in INVALID-WRAPPER-P looks like a good place -;;; for (AVER (NOT (EQ (LAYOUT-INVALID OWRAPPER) +;;; for (AVER (NOT (EQ (WRAPPER-INVALID OWRAPPER) ;;; :UNINITIALIZED))) ;;; ;;; Thanks to Gerd Moellmann for the explanation. -- CSR, 2002-10-29 @@ -1429,19 +1446,19 @@ ;; a violation of locality or what might be considered ;; good style. There has to be a better way! -- CSR, ;; 2002-10-29 - (eq (layout-invalid owrapper) t)) - (let ((nwrapper (make-wrapper (layout-length owrapper) + (eq (wrapper-invalid owrapper) t)) + (let ((nwrapper (make-wrapper (wrapper-length owrapper) class))) - (setf (layout-slot-list nwrapper) (layout-slot-list owrapper)) - (setf (layout-slot-table nwrapper) (layout-slot-table owrapper)) + (setf (wrapper-slot-list nwrapper) (wrapper-slot-list owrapper)) + (setf (wrapper-slot-table nwrapper) (wrapper-slot-table owrapper)) (%update-lisp-class-layout class nwrapper) (setf (slot-value class 'wrapper) nwrapper) ;; Use :OBSOLETE instead of :FLUSH if any superclass has ;; been obsoleted. (if (find-if (lambda (x) (and (consp x) (eq :obsolete (car x)))) - (layout-inherits owrapper) - :key #'layout-invalid) + (wrapper-inherits owrapper) + :key #'wrapper-invalid) (%invalidate-wrapper owrapper :obsolete nwrapper) (%invalidate-wrapper owrapper :flush nwrapper)))))) nil) @@ -1452,14 +1469,14 @@ (defmethod make-instances-obsolete ((class std-class)) (with-world-lock () (let* ((owrapper (class-wrapper class)) - (nwrapper (make-wrapper (layout-length owrapper) + (nwrapper (make-wrapper (wrapper-length owrapper) class))) (unless (class-finalized-p class) (if (class-has-a-forward-referenced-superclass-p class) (return-from make-instances-obsolete class) (%update-cpl class (compute-class-precedence-list class)))) - (setf (layout-slot-list nwrapper) (layout-slot-list owrapper)) - (setf (layout-slot-table nwrapper) (layout-slot-table owrapper)) + (setf (wrapper-slot-list nwrapper) (wrapper-slot-list owrapper)) + (setf (wrapper-slot-table nwrapper) (wrapper-slot-table owrapper)) (%update-lisp-class-layout class nwrapper) (setf (slot-value class 'wrapper) nwrapper) (%invalidate-wrapper owrapper :obsolete nwrapper) @@ -1544,29 +1561,31 @@ "~@<obsolete structure error for a structure of type ~2I~_~S~:>" (type-of (obsolete-structure-datum condition)))))) +(macrolet ((replace-wrapper-and-slots (thing layout slot-vector) + `(if (functionp ,thing) + (setf (%fun-wrapper ,thing) ,layout + (fsc-instance-slots ,thing) ,slot-vector) + ;; TODO: use a double-wide CAS here if CPU supports it + (progn + (setf (%instance-wrapper ,thing) ,layout) + (%instance-set ,thing sb-vm:instance-data-start ,slot-vector))))) + (defun %obsolete-instance-trap (owrapper nwrapper instance) (cond ((layout-for-pcl-obj-p owrapper) - (binding* ((class (wrapper-class* nwrapper)) + (binding* ((class (wrapper-class nwrapper)) (oslots (get-slots instance)) - ((nslots nwrapper) - ;; All we need is a new backing store, but I guess we have - ;; to go through ALLOCATE-INSTANCE - is that per AMOP ? - ;; Anyway, let's render the new instance unusable. - (let ((copy (allocate-instance class))) - (if (std-instance-p copy) - (values (shiftf (%std-instance-slots copy) 0) - (%instance-layout copy)) - (values (shiftf (%fsc-instance-slots copy) 0) - (%fun-layout copy))))) + (nwrapper (class-wrapper class)) + (nslots (make-array (wrapper-length nwrapper) + :initial-element +slot-unbound+)) (added ()) (discarded ()) (plist ()) (safe (safe-p class)) ((new-instance-slots nil new-custom-slots) - (classify-slotds (layout-slot-list nwrapper))) + (classify-slotds (wrapper-slot-list nwrapper))) ((old-instance-slots old-class-slots old-custom-slots) - (classify-slotds (layout-slot-list owrapper))) + (classify-slotds (wrapper-slot-list owrapper))) (layout (mapcar (lambda (slotd) ;; Get the names only once. (cons (slot-definition-name slotd) slotd)) @@ -1600,9 +1619,7 @@ ((fixnump location) (clos-slots-ref oslots location)) ((not location) - (let ((location (slot-info-location (cdr cell)))) - (aver (integerp location)) - (clos-slots-ref oslots (slot-info-location (cdr cell))))) + (clos-slots-ref oslots (slot-info-location (cdr cell)))) (t (bug "non-FIXNUM non-NULL location in cell: ~S" cell))))) (unless (unbound-marker-p value) (let ((new (assq name layout))) @@ -1635,14 +1652,20 @@ (dolist (cell layout) (push (car cell) added))) - (if (std-instance-p instance) - (setf (%instance-layout instance) nwrapper - (std-instance-slots instance) nslots) - (setf (%fun-layout instance) nwrapper - (%fsc-instance-slots instance) nslots)) - - (update-instance-for-redefined-class - instance added discarded plist) + (replace-wrapper-and-slots instance nwrapper nslots) + ;; The obsolete instance protocol does not specify what happens if + ;; an error is signaled in U-I-F-R-C and there is a nonlocal exit + ;; outside; it may result in a half-updated instance whose + ;; structure is updated but whose added slots are not initialized. + ;; (See CLHS 3.7.2.) + ;; The approach taken here is to abort the update process, as defined + ;; in CLHS 4.3.6, altogether, and restore the instance to its obsolete + ;; state; this way the programmer can try to fix the U-I-F-R-C code + ;; which signaled an error and try to access the instance again + ;; in order to try and update it again. + (sb-sys:nlx-protect (update-instance-for-redefined-class + instance added discarded plist) + (replace-wrapper-and-slots instance owrapper oslots)) nwrapper)) (*in-obsolete-instance-trap* #.(find-layout 'structure-object)) @@ -1650,21 +1673,16 @@ (let ((*in-obsolete-instance-trap* t)) (error 'obsolete-structure :datum instance))))) - -(defun %change-class (instance new-class initargs) - (declare (notinline allocate-instance)) - (binding* ((old-wrapper (layout-of instance)) - (old-class (wrapper-class* old-wrapper)) - (copy (allocate-instance new-class)) - (new-wrapper (let ((layout (layout-of copy))) - (aver (layout-for-pcl-obj-p layout)) - (aver (= (layout-bitmap old-wrapper) - (layout-bitmap layout))) - layout)) +(defun %change-class (copy instance new-class initargs) + (binding* ((new-wrapper (class-wrapper (ensure-class-finalized new-class))) + (new-slots (make-array (wrapper-length new-wrapper) + :initial-element +slot-unbound+)) + (old-wrapper (wrapper-of instance)) + (old-class (wrapper-class old-wrapper)) (old-slots (get-slots instance)) - (new-slots (get-slots copy)) (safe (safe-p new-class)) - (new-wrapper-slots (layout-slot-list new-wrapper))) + (new-wrapper-slots (wrapper-slot-list new-wrapper))) + (replace-wrapper-and-slots copy new-wrapper new-slots) (flet ((initarg-for-slot-p (slot) (when initargs (dolist (slot-initarg (slot-definition-initargs slot)) @@ -1703,23 +1721,24 @@ ;; All uses of %CHANGE-CLASS are under the world lock, but that doesn't ;; preclude user code operating on the old slots + new layout or v.v. ;; Users need to synchronize their own access when changing class. - (cond ((std-instance-p instance) - (rotatef (%instance-layout instance) (%instance-layout copy)) - (rotatef (%std-instance-slots instance) (%std-instance-slots copy))) - (t - (rotatef (%fun-layout instance) (%fun-layout copy)) - (rotatef (%fsc-instance-slots instance) (%fsc-instance-slots copy)))) - - (apply #'update-instance-for-different-class copy instance initargs) - ;; If the user subsequently operates on COPY, crash and burn. As per CLHS: - ;; "The first argument to update-instance-for-different-class, /previous/, - ;; is that copy; it holds the old slot values temporarily. This argument has - ;; dynamic extent within change-class; if it is referenced in any way once - ;; update-instance-for-different-class returns, the results are undefined." - (cond ((std-instance-p copy) (setf (%std-instance-slots copy) 0)) - ((fsc-instance-p copy) (setf (%fsc-instance-slots copy) 0))) + (replace-wrapper-and-slots copy old-wrapper old-slots) + (replace-wrapper-and-slots instance new-wrapper new-slots) + + ;; The CLHS does not specify what happens if an error is signaled in + ;; U-I-F-D-C and there is a nonlocal exit outside; it may result in a + ;; half-updated instance whose class is updated but whose added slots + ;; are not initialized. (See CLHS 3.7.2.) + ;; The approach taken here is to abort the change-class process, as + ;; defined in CLHS 4.3.6, altogether, and restore the instance to its + ;; previous state; this way the programmer can try to fix the U-I-F-D-C + ;; code which signaled an error and try to CHANGE-CLASS the instance + ;; again. + (sb-sys:nlx-protect (apply #'update-instance-for-different-class + copy instance initargs) + (replace-wrapper-and-slots instance old-wrapper old-slots)) instance)) +) ; end MACROLET (defun check-new-class-not-metaobject (new-class) (dolist (class (class-precedence-list @@ -1734,11 +1753,23 @@ (check-metaobject method) (check-metaobject slot-definition)))) +;;; "The first argument to update-instance-for-different-class, /previous/, +;;; is that copy; it holds the old slot values temporarily. This argument has +;;; dynamic extent within change-class; if it is referenced in any way once +;;; update-instance-for-different-class returns, the results are undefined." +;;; The full ALLOCATE-INSTANCE protocol can not possibly support dynamic-extent +;;; allocation (at least, for SBCL; maybe for others it can). +;;; Calling ALLOCATE-INSTANCE from CHANGE-CLASS doesn't seem to be mandatory. +;;; At least 4 other Lisp implementations I tested don't call it. +(macrolet ((with-temporary-instance ((var) &body body) + `(dx-let ((,var (%make-instance (1+ sb-vm:instance-data-start)))) + ,@body))) (defmethod change-class ((instance standard-object) (new-class standard-class) &rest initargs) (with-world-lock () (check-new-class-not-metaobject new-class) - (%change-class instance new-class initargs))) + (with-temporary-instance (temp) + (%change-class temp instance new-class initargs)))) (defmethod change-class ((instance forward-referenced-class) (new-class standard-class) &rest initargs) @@ -1751,7 +1782,8 @@ (:amop :initialization class)))) (when (eq class (find-class 'class)) (return nil))) - (%change-class instance new-class initargs))) + (with-temporary-instance (temp) + (%change-class temp instance new-class initargs))))) (defmethod change-class ((instance t) (new-class forward-referenced-class) &rest initargs) @@ -1761,12 +1793,21 @@ '((:amop :generic-function ensure-class-using-class) (:amop :initialization class)))) +(macrolet ((with-temporary-funinstance ((var) &body body) + `(dx-let ((,var (%make-funcallable-instance + (+ sb-vm:instance-data-start 2)))) + (dx-flet ((signal-error () + (declare (optimize (sb-c::verify-arg-count 0))) + (error-no-implementation-function ,var))) + (setf (%funcallable-instance-fun ,var) #'signal-error) + ,@body)))) (defmethod change-class ((instance funcallable-standard-object) (new-class funcallable-standard-class) &rest initargs) (with-world-lock () (check-new-class-not-metaobject new-class) - (%change-class instance new-class initargs))) + (with-temporary-funinstance (temp) + (%change-class temp instance new-class initargs))))) (defmethod change-class ((instance standard-object) (new-class funcallable-standard-class) diff --git a/src/pcl/time.lisp b/src/pcl/time.lisp deleted file mode 100644 index 98a6b898de..0000000000 --- a/src/pcl/time.lisp +++ /dev/null @@ -1,142 +0,0 @@ -;;;; FIXME: This should probably move to some separate tests or benchmarks -;;;; directory. - -(in-package "SB-PCL") - -(declaim (optimize (speed 3) (safety 0) (compilation-speed 0))) - -(defvar *tests*) -(setq *tests* nil) - -(defvar m (car (generic-function-methods #'shared-initialize))) -(defvar gf #'shared-initialize) -(defvar c (find-class 'standard-class)) - -(defclass str () - ((slot :initform nil :reader str-slot)) - (:metaclass structure-class)) - -(defvar str (make-instance 'str)) - -(push (cons "Time unoptimized slot-value. This is case (1) from notes.text. (standard)" - '(time-slot-value m 'plist 10000)) - *tests*) -(push (cons "Time unoptimized slot-value. This is case (1) from notes.text. (standard)" - '(time-slot-value m '%generic-function 10000)) - *tests*) -(push (cons "Time unoptimized slot-value. This is case (1) from notes.text. (structure)" - '(time-slot-value str 'slot 10000)) - *tests*) -(defun time-slot-value (object slot-name n) - (time (dotimes-fixnum (i n) (slot-value object slot-name)))) - -(push (cons "Time optimized slot-value outside of a defmethod. Case (2). (standard)" - '(time-slot-value-function m 10000)) - *tests*) -(defun time-slot-value-function (object n) - (time (dotimes-fixnum (i n) (slot-value object '%function)))) - -(push (cons "Time optimized slot-value outside of a defmethod. Case (2). (structure)" - '(time-slot-value-slot str 10000)) - *tests*) -(defun time-slot-value-slot (object n) - (time (dotimes-fixnum (i n) (slot-value object 'slot)))) - -(push (cons "Time one-class dfun." - '(time-generic-function-methods gf 10000)) - *tests*) -(defun time-generic-function-methods (object n) - (time (dotimes-fixnum (i n) (generic-function-methods object)))) - -(push (cons "Time one-index dfun." - '(time-class-precedence-list c 10000)) - *tests*) -(defun time-class-precedence-list (object n) - (time (dotimes-fixnum (i n) (class-precedence-list object)))) - -(push (cons "Time n-n dfun." - '(time-method-function m 10000)) - *tests*) -(defun time-method-function (object n) - (time (dotimes-fixnum (i n) (method-function object)))) - -(push (cons "Time caching dfun." - '(time-class-slots c 10000)) - *tests*) -(defun time-class-slots (object n) - (time (dotimes-fixnum (i n) (class-slots object)))) - -(push (cons "Time typep for classes." - '(time-typep-standard-object m 10000)) - *tests*) -(defun time-typep-standard-object (object n) - (time (dotimes-fixnum (i n) (typep object 'standard-object)))) - -(push (cons "Time default-initargs." - '(time-default-initargs (find-class 'plist-mixin) 1000)) - *tests*) -(defun time-default-initargs (n) - (time (dotimes-fixnum (i n) (default-initargs nil nil)))) - -(push (cons "Time make-instance." - '(time-make-instance (find-class 'plist-mixin) 1000)) - *tests*) -(defun time-make-instance (class n) - (time (dotimes-fixnum (i n) (make-instance class)))) - -(push (cons "Time constant-keys make-instance." - '(time-constant-keys-make-instance 1000)) - *tests*) - -(expanding-make-instance-toplevel -(defun constant-keys-make-instance (n) - (dotimes-fixnum (i n) (make-instance 'plist-mixin)))) - -(precompile-random-code-segments) - -(defun time-constant-keys-make-instance (n) - (time (constant-keys-make-instance n))) - -(defun expand-all-macros (form) - (walk-form form nil (lambda (form context env) - (if (eq context :eval) - (values (%macroexpand form env)) - form)))) - -(push (cons "Macroexpand meth-structure-slot-value" - '(pprint (multiple-value-bind (pgf pm) - (prototypes-for-make-method-lambda - 'meth-structure-slot-value) - (expand-defmethod - 'meth-structure-slot-value pgf pm - nil '((object str)) - '((lambda () (slot-value object 'slot))) - nil)))) - *tests*) - -(push (cons "Show code for slot-value inside a defmethod for a structure-class. Case (3)." - '(disassemble (meth-structure-slot-value str))) - *tests*) -(defmethod meth-structure-slot-value ((object str)) - (lambda () (slot-value object 'slot))) - -#|| ; interesting, but long. (produces 100 lines of output) -(push (cons "Macroexpand meth-standard-slot-value" - '(pprint (expand-all-macros - (expand-defmethod-internal 'meth-standard-slot-value - nil '((object standard-method)) - '((lambda () (slot-value object '%function))) - nil)))) - *tests*) -(push (cons "Show code for slot-value inside a defmethod for a standard-class. Case (4)." - '(disassemble (meth-standard-slot-value m))) - *tests*) -(defmethod meth-standard-slot-value ((object standard-method)) - (lambda () (slot-value object '%function))) -||# - -(defun run-tests () - (dolist (doc+form (reverse *tests*)) - (format t "~&~%~A~%" (car doc+form)) - (pprint (cdr doc+form)) - (eval (cdr doc+form)))) diff --git a/src/pcl/vector.lisp b/src/pcl/vector.lisp index 145aa326c5..003edef411 100644 --- a/src/pcl/vector.lisp +++ b/src/pcl/vector.lisp @@ -58,7 +58,7 @@ ;;; ...and one lock to rule them. Lock because for certain (rare) ;;; cases this lock might be grabbed in the course of method dispatch -;;; -- and mostly this is already under the *world-lock* +;;; -- and mostly this is already under the **world-lock** (define-load-time-global *pv-lock* (sb-thread:make-mutex :name "pv table index lock")) @@ -97,7 +97,7 @@ (when slot-names (let* ((wrapper (pop wrappers)) (std-p (layout-for-pcl-obj-p wrapper)) - (class (wrapper-class* wrapper))) + (class (wrapper-class wrapper))) (dolist (slot-name slot-names) (destructuring-bind (location . info) (or (find-slot-cell wrapper slot-name) @@ -312,8 +312,6 @@ (define-walker-template pv-offset) ; These forms get munged by mutate slots. (defmacro pv-offset (arg) arg) -(define-walker-template instance-accessor-parameter) -(defmacro instance-accessor-parameter (x) x) ;;; It is safe for these two functions to be wrong. They just try to ;;; guess what the most likely case will be. @@ -767,8 +765,8 @@ ,@inner-decls ,@body-sans-decls)))) (mf (%make-method-function fmf))) - (set-funcallable-instance-function - mf (method-function-from-fast-function fmf ',(getf initargs 'plist))) + (setf (%funcallable-instance-fun mf) + (method-function-from-fast-function fmf ',(getf initargs 'plist))) mf) ',initargs))))) diff --git a/src/pcl/walk.lisp b/src/pcl/walk.lisp index 2e5ae4d34e..330a5c1869 100644 --- a/src/pcl/walk.lisp +++ b/src/pcl/walk.lisp @@ -27,15 +27,6 @@ ;;;; warranty about the software, its performance or its conformity to any ;;;; specification. -(defpackage "SB-WALKER" - (:use "CL" "SB-INT" "SB-EXT") - (:documentation "internal: a code walker used by PCL") - (:export "DEFINE-WALKER-TEMPLATE" - "WALK-FORM" - "*WALK-FORM-EXPAND-MACROS-P*" - "VAR-LEXICAL-P" "VAR-SPECIAL-P" - "VAR-GLOBALLY-SPECIAL-P" - "VAR-DECLARATION")) (in-package "SB-WALKER") ;;;; forward references @@ -233,9 +224,10 @@ (defun convert-macro-to-lambda (llist body env &optional (name "dummy macro")) (declare (ignorable llist body env name)) - #+sb-xc-host (error "CONVERT-MACRO-TO-LAMBDA called") ; no EVAL-IN-LEXENV - #-sb-xc-host (let ((gensym (make-symbol name))) + #+sb-xc-host + (eval `(sb-xc:defmacro ,gensym ,llist ,@body)) + #-sb-xc-host (eval-in-lexenv `(defmacro ,gensym ,llist ,@body) (sb-c::make-restricted-lexenv env)) (macro-function gensym))) @@ -449,8 +441,6 @@ (define-walker-template macrolet walk-macrolet) (define-walker-template multiple-value-call (nil eval repeat (eval))) (define-walker-template multiple-value-prog1 (nil return repeat (eval))) -(define-walker-template multiple-value-setq walk-multiple-value-setq) -(define-walker-template multiple-value-bind walk-multiple-value-bind) (define-walker-template progn (nil repeat (eval))) (define-walker-template progv (nil eval eval repeat (eval))) (define-walker-template quote (nil quote)) @@ -461,6 +451,7 @@ (define-walker-template the (nil quote eval)) (define-walker-template throw (nil eval eval)) (define-walker-template unwind-protect (nil return repeat (eval))) +(define-walker-template defun walk-defun) ;;; SBCL-only special forms (define-walker-template truly-the (nil quote eval)) @@ -469,10 +460,115 @@ ;;; FIXME: maybe we don't need this one any more, given that ;;; NAMED-LAMBDA now expands into (FUNCTION (NAMED-LAMBDA ...))? (define-walker-template named-lambda walk-named-lambda) +#| +;;; To find templateized symbols that aren't special operators: +(do-all-symbols (s) + (let ((template + (sb-int:info :function :walker-template s))) + (when (and template (not (special-operator-p s))) + (format t "Why? ~S~%" s)))) +|# (defvar *walk-form-expand-macros-p* nil) (defvar *walk-form-preserve-source* nil) +(defun macroexpand-all (form &optional environment) + (let ((*walk-form-expand-macros-p* t)) + (sb-walker:walk-form + form environment + (lambda (subform context env) + (acond ((and (eq context :eval) + (listp subform) + (symbolp (car subform)) + (get (car subform) :partial-macroexpander)) + ;; The partial expander must return T as its second value + ;; if it wants to stop the walk. + (funcall it subform env)) + (t + subform)))))) + +;; Given EXPR, the argument to an invocation of Quasiquote macro, macroexpand +;; evaluable subforms of EXPR using ENV. A subform is evaluable if all +;; preceding occurrences of #\` have been "canceled" by a comma. +;; DEPTH counts the nesting and should not be supplied by external callers. +(defun %quasiquoted-macroexpand-all (expr env &optional (depth 0)) + (flet ((quasiquote-p (x) + (and (listp x) (eq (car x) 'quasiquote) (singleton-p (cdr x)))) + (recurse (x) + (%quasiquoted-macroexpand-all x env depth))) + (if (atom expr) + (cond ((simple-vector-p expr) (map 'vector #'recurse expr)) + ((comma-p expr) + (unquote (if (> depth 1) + (%quasiquoted-macroexpand-all + (comma-expr expr) env (1- depth)) + (macroexpand-all (comma-expr expr) env)) + (comma-kind expr))) + (t expr)) + (if (quasiquote-p expr) + (list 'quasiquote + (%quasiquoted-macroexpand-all (second expr) env (1+ depth))) + (let (result) + (loop + (push (recurse (pop expr)) result) + (when (or (atom expr) (quasiquote-p expr)) + (return (nreconc result (recurse expr)))))))))) + +(setf (get 'quasiquote :partial-macroexpander) + (lambda (form env) + (destructuring-bind (arg) (cdr form) ; sanity-check the shape + (declare (ignore arg)) + (values (%quasiquoted-macroexpand-all form env) t)))) + +#| + +;; Another example that some people might find useful. + +(defun macroexpand-decls+forms (body env) ; a bit of a kludge, but it works + (mapcar (lambda (x) + (if (and (listp x) (eq (car x) 'declare)) + x + (macroexpand-all x env))) + body)) + +(setf (get 'dotimes :partial-macroexpander) + (lambda (form env) + (destructuring-bind ((var count &optional (result nil result-p)) + &body body) (cdr form) + (values `(dotimes (,var ,(macroexpand-all count env) + ,@(if result-p + (list (macroexpand-all result env)))) + ,@(macroexpand-decls+forms body env)) + t)))) + +(macroexpand-all '(macrolet ((hair (x) `(car ,x))) + (dotimes (i (bar)) (foo i (hair baz)) l)))) +=> +(MACROLET ((HAIR (X) + `(CAR ,X))) + (DOTIMES (I (BAR)) (FOO I (CAR BAZ)) L)) + +instead of + +(MACROLET ((HAIR (X) + `(CAR ,X))) + (BLOCK NIL + (LET ((I 0) (#:COUNT699 (BAR))) + (DECLARE (TYPE UNSIGNED-BYTE I) + (TYPE INTEGER #:COUNT699)) + (TAGBODY + (GO #:G701) + #:G700 + (TAGBODY (FOO I (CAR BAZ)) L) + (LET* () + (MULTIPLE-VALUE-BIND (#:NEW702) (1+ I) (PROGN (SETQ I #:NEW702) NIL))) + #:G701 + (IF (>= I #:COUNT699) + NIL + (PROGN (GO #:G700))) + (RETURN-FROM NIL (PROGN NIL)))))) +|# + #+sb-fasteval (declaim (ftype (sfunction (sb-interpreter:basic-env &optional t) sb-kernel:lexenv) sb-interpreter:lexenv-from-env environment)) @@ -509,67 +605,83 @@ ;; by walk-function is T then we don't recurse... (catch form (with-current-source-form (form) - (multiple-value-bind (newform walk-no-more-p) - (funcall (env-walk-function env) form context env) - (catch newform - (cond - (walk-no-more-p newform) - ((not (eq form newform)) - (walk-form-internal newform context env)) - ((and (not (consp newform)) - (or (eql context :eval) - (eql context :set))) - (let ((symmac (and (symbolp newform) - (car (variable-symbol-macro-p newform env))))) - (if symmac - (let* ((newnewform (walk-form-internal (cddr symmac) - context - env)) - (resultform - (if (eq newnewform (cddr symmac)) - (if *walk-form-expand-macros-p* newnewform newform) - newnewform)) - (type (env-var-type newform env))) - (if (eq t type) - resultform - `(the ,type ,resultform))) - newform))) - ((eql context :set) newform) - (t - (let* ((fn (car newform)) - (template (get-walker-template fn newform))) - (if template - (if (symbolp template) - (funcall template newform context env) - (walk-template newform template context env)) - (multiple-value-bind (newnewform macrop) - (walker-environment-bind - (new-env env :walk-form newform) - (%macroexpand-1 newform new-env)) - (cond - (macrop - (let ((newnewnewform (walk-form-internal newnewform - context - env))) - (cond ((eq newnewnewform newnewform) - (if *walk-form-expand-macros-p* newnewform newform)) - (*walk-form-preserve-source* - `(sb-c::with-source-form ,newform - ,newnewnewform)) - (t newnewnewform)))) - ((and (symbolp fn) - (special-operator-p fn)) - ;; This shouldn't happen, since this walker is now - ;; maintained as part of SBCL, so it should know - ;; about all the special forms that SBCL knows - ;; about. - (bug "unexpected special form ~S" fn)) - (t - ;; Otherwise, walk the form as if it's just a - ;; standard function call using a template for - ;; standard function call. - (walk-template - newnewform '(call repeat (eval)) context env))))))))))))) + (let ((sb-c::*compiler-error-bailout* + (lambda (c) + (return-from walk-form-internal + (sb-c::make-compiler-error-form c form))))) + (multiple-value-bind (newform walk-no-more-p) + (funcall (env-walk-function env) form context env) + (catch newform + (cond + (walk-no-more-p newform) + ((not (eq form newform)) + (record-new-source-path form newform) + (walk-form-internal newform context env)) + ((and (not (consp newform)) + (or (eql context :eval) + (eql context :set))) + (let ((symmac (and (symbolp newform) + (car (variable-symbol-macro-p newform env))))) + (if symmac + (let* ((newnewform (walk-form-internal (cddr symmac) + context + env)) + (resultform + (if (eq newnewform (cddr symmac)) + (if *walk-form-expand-macros-p* newnewform newform) + newnewform)) + (type (env-var-type newform env))) + (if (eq t type) + resultform + `(the ,type ,resultform))) + newform))) + ((eql context :set) newform) + (t + (let* ((fn (car newform)) + (template (get-walker-template fn newform))) + (if template + (if (symbolp template) + (funcall template newform context env) + (walk-template newform template context env)) + (multiple-value-bind (newnewform macrop) + (walker-environment-bind + (new-env env :walk-form newform) + (%macroexpand-1 newform new-env)) + (cond + (macrop + (let ((newnewnewform (walk-form-internal newnewform + context + env))) + (cond ((eq newnewnewform newnewform) + (if *walk-form-expand-macros-p* newnewform newform)) + (t + (record-new-source-path newform newnewnewform ))))) + ((and (symbolp fn) + (special-operator-p fn)) + ;; This shouldn't happen, since this walker is now + ;; maintained as part of SBCL, so it should know + ;; about all the special forms that SBCL knows + ;; about. + (bug "unexpected special form ~S" fn)) + (t + ;; Otherwise, walk the form as if it's just a + ;; standard function call using a template for + ;; standard function call. + (walk-template + newnewform '(call repeat (eval)) context env)))))))))))))) + +(defun record-new-source-path (old-form new-form) + (when (and *walk-form-preserve-source* + (boundp 'sb-c::*source-paths*)) + (let ((path (gethash old-form sb-c::*source-paths*))) + (when path + (setf (gethash new-form sb-c::*source-paths*) path)))) + new-form) + +(defun recons (old-cons car cdr) + (if (and (eq car (car old-cons)) (eq cdr (cdr old-cons))) + old-cons + (record-new-source-path old-cons (cons car cdr)))) (defun walk-template (form template context env) (if (atom template) @@ -759,23 +871,15 @@ new-env))) (relist* form let walked-bindings walked-body)))) -(defun let*-binding-name (binding) - (if (symbolp binding) - binding - (car binding))) - -(defun let*-binding-init (binding) - (if (or (symbolp binding) - (null (cdr binding))) - 'no-init - (cadr binding))) - -(defun let*-bindings (bindings &aux names inits (seen (make-hash-table :test #'eq))) +(defun let*-bindings (bindings &aux names inits (seen (alloc-xset))) (dolist (binding (reverse bindings) (values names inits)) - (let ((name (let*-binding-name binding))) - (push (cons name (gethash name seen)) names) - (setf (gethash name seen) t) - (push (let*-binding-init binding) inits)))) + (multiple-value-bind (name init) + (cond ((atom binding) (values binding 'no-init)) + ((not (cdr binding)) (values (car binding) 'no-init)) + (t (values (car binding) (cdr binding)))) + (push (cons name (xset-member-p name seen)) names) + (add-to-xset name seen) + (push init inits)))) (defun walk-let* (form context env) (walker-environment-bind (new-env env) @@ -813,9 +917,11 @@ (prog1 (car bindings) (note-var-binding (car name) new-env)) (prog1 - (relist (car bindings) + (recons (car bindings) (caar bindings) - (walk-form-internal init context new-env)) + (recons init + (walk-form-internal (car init) context new-env) + (cdr init))) (note-var-binding (car name) new-env))) (unless (cdr name) (setf decls (mapcar (lambda (d) @@ -852,55 +958,24 @@ (relist* form locally walked-body)))) -(defun walk-multiple-value-setq (form context env) - (let ((vars (cadr form))) - (if (some (lambda (var) - (and (symbolp var) (variable-symbol-macro-p var env))) - vars) - (let* ((temps (mapcar (lambda (var) - (declare (ignore var)) - (gensym)) - vars)) - (sets (mapcar (lambda (var temp) `(setq ,var ,temp)) - vars - temps)) - (expanded `(multiple-value-bind ,temps ,(caddr form) - ,@sets)) - (walked (walk-form-internal expanded context env))) - (if (eq walked expanded) - form - walked)) - (walk-template form '(nil (repeat (set)) eval) context env)))) - -(defun walk-multiple-value-bind (form context old-env) - (walker-environment-bind (new-env old-env) - (let* ((mvb (car form)) - (bindings (cadr form)) - (mv-form (walk-template (caddr form) 'eval context old-env)) - (body (cdddr form)) - walked-bindings - (walked-body - (walk-declarations - body - (lambda (real-body real-env) - (setq walked-bindings - (walk-bindings-1 bindings old-env new-env context)) - (walk-repeat-eval real-body real-env)) - new-env))) - (relist* form mvb walked-bindings mv-form walked-body)))) - (defun walk-bindings-1 (bindings old-env new-env context) (and bindings (let ((binding (car bindings))) (recons bindings - (if (symbolp binding) + (typecase binding + (symbol (prog1 binding - (note-var-binding binding new-env)) - (prog1 (relist binding - (car binding) - (walk-form-internal - (cadr binding) context old-env)) + (note-var-binding binding new-env))) + ((cons symbol list) + (prog1 (relist* binding + (car binding) + (walk-form-internal + (cadr binding) context old-env) + ;; Preserve "trailing junk" + (cddr binding)) (note-var-binding (car binding) new-env))) + (t ; illegal syntax, (let (#(foo))) or (let (a . #*1)) etc + binding)) (walk-bindings-1 (cdr bindings) old-env new-env context))))) (defun walk-lambda (form context old-env) @@ -929,6 +1004,10 @@ walked-arglist walked-body)))) +;;; The DEFUN macro does some stuff with the environment, handle it here. +(defun walk-defun (form context env) + (recons form (car form) (walk-lambda (cdr form) context env))) + (defun walk-setq (form context env) (if (cdddr form) (let* ((expanded (let ((rforms nil) diff --git a/src/pcl/wrapper.lisp b/src/pcl/wrapper.lisp index 6ab0d6d6a0..c3175a67b0 100644 --- a/src/pcl/wrapper.lisp +++ b/src/pcl/wrapper.lisp @@ -1,4 +1,4 @@ -;;;; Bits and pieces of the wrapper machninery. This used to live in cache.lisp, +;;;; Bits and pieces of the wrapper machinery. This used to live in cache.lisp, ;;;; but doesn't really logically belong there. ;;;; This software is part of the SBCL system. See the README file for @@ -27,28 +27,25 @@ (in-package "SB-PCL") (defmacro wrapper-class (wrapper) - `(classoid-pcl-class (layout-classoid ,wrapper))) + `(classoid-pcl-class (wrapper-classoid ,wrapper))) ;;; This is called in BRAID when we are making wrappers for classes ;;; whose slots are not initialized yet, and which may be built-in -;;; classes. We pass in the class name in addition to the class. -(defun !boot-make-wrapper (length name &optional class (bitmap -1)) +;;; classes. +(defun !boot-make-wrapper (length name &optional (bitmap +layout-all-tagged+)) (let ((found (find-classoid name nil))) (cond (found - (unless (classoid-pcl-class found) - (setf (classoid-pcl-class found) class)) - (aver (eq (classoid-pcl-class found) class)) - (let ((layout (classoid-layout found))) + (let ((layout (classoid-wrapper found))) (aver layout) layout)) (t - (set-layout-valid (make-layout (hash-layout-name name) - (make-standard-classoid :name name :pcl-class class) + (make-standard-classoid :name name) :length length - :flags +pcl-object-layout-flag+ - :bitmap bitmap)))))) + :flags (logior +pcl-object-layout-flag+ +strictly-boxed-flag+) + :bitmap bitmap + :invalid nil))))) ;;; In SBCL, as in CMU CL, the layouts (a.k.a wrappers) for built-in ;;; and structure classes already exist when PCL is initialized, so we @@ -65,7 +62,7 @@ (classoid (let ((owrap (class-wrapper class))) (cond (owrap - (layout-classoid owrap)) + (wrapper-classoid owrap)) ((or (*subtypep (class-of class) *the-class-standard-class*) (*subtypep (class-of class) *the-class-funcallable-standard-class*) (typep class 'forward-referenced-class)) @@ -74,35 +71,19 @@ :name (and (symbolp name) name))) (t (bug "Got to T branch in ~S" 'make-wrapper)))))) - (set-layout-valid - (make-layout (hash-layout-name name) - classoid :length length :flags +pcl-object-layout-flag+)))) + (make-layout (hash-layout-name name) classoid + :bitmap +layout-all-tagged+ + :invalid nil :length length + :flags (logior +pcl-object-layout-flag+ +strictly-boxed-flag+)))) (t (let* ((found (find-classoid (slot-value class 'name))) - (layout (classoid-layout found))) + (layout (classoid-wrapper found))) (unless (classoid-pcl-class found) (setf (classoid-pcl-class found) class)) (aver (eq (classoid-pcl-class found) class)) (aver layout) layout)))) -(declaim (inline wrapper-class*)) -(defun wrapper-class* (wrapper) - (or (wrapper-class wrapper) - ;; FIXME: this branch seems unreachable. - ;; It would be nice to eliminate WRAPPER-CLASS* if we can show that it - ;; is only a holdover from an earlier way of bootstrapping that resulted - ;; in the temporary absence of a PCL-CLASS for some non-standard-class. - ;; Certainly no test gets here [changing it to (BUG "got here") worked]. - ;; Note however that - ;; (CLASSOID-PCL-CLASS (FIND-CLASSOID 'STANDARD-INSTANCE)) => NIL - ;; which can be resolved by just ensuring one time that it has a CLASS. - ;; And nothing else seems to be problematic. - (let ((classoid (layout-classoid wrapper))) - (ensure-non-standard-class - (classoid-name classoid) - classoid)))) - ;;; The wrapper cache machinery provides general mechanism for ;;; trapping on the next access to any instance of a given class. This ;;; mechanism is used to implement the updating of instances when the @@ -119,7 +100,7 @@ ;;; This "simple" function hides a horrible inconsistency: we don't have a single ;;; canonical atomically checkable validity indicator. We carry around invalid layouts ;;; with nonzero hashes. Why else would there be so may places that can do: -;;; (setf (layout-invalid layout) nil +;;; (setf (wrapper-invalid layout) nil ;;; whilst the layout in question already has a "valid" hash? ;;; It's hard to know what the right thing is, but since internal code uses ;;; this test to decide how to handle layouts that have been invalidated, @@ -127,11 +108,11 @@ ;;; even though logically that *should* be the canonical test. (declaim (inline invalid-wrapper-p)) (defun invalid-wrapper-p (wrapper) - (not (null (layout-invalid wrapper)))) + (not (null (wrapper-invalid wrapper)))) ;;; The portable code inherited from the ancient PCL sources used an extremely ;;; clever mechanism to store a mapping from new layouts ("wrappers") to old. -;;; Old layouts point to new in a straighforward way - via the INVALID slot - +;;; Old layouts point to new in a straightforward way - via the INVALID slot - ;;; but the invalidation logic wants backpointers from new to old as well. ;;; It arranges so that if the following state exists: ;;; layout_A -> (:flush layout_B) @@ -140,7 +121,7 @@ ;;; the state of layout_A should be changed to (:flush layout_C) ;;; at the same time that the state of layout_B is changed. ;;; -;;; In general, alterating layout_B might might have to perform more than one +;;; In general, altering layout_B might might have to perform more than one ;;; update to older versions of the layout, so it's a one-to-many relation. ;;; The same "transitivity" could have been implemented at the time of flushing ;;; layout_A by chasing an extra pointer (the B -> C pointer) and recording that @@ -148,12 +129,12 @@ ;;; improves anything, as it merely performs work eagerly that could have ;;; been performed lazily. (PCL generally prefers lazy updates.) ;;; -;;; Anyway the extreme cleverness (and premature optimization, imho), was almost, +;;; Anyway the extreme cleverness (and premature optimization, IMHO), was almost, ;;; but not quite, clever enough - it leaked three conses per redefinition, ;;; which it pretty much had to in order to remain portable. ;;; We can at least replicate it in a way that doesn't leak conses, ;;; or at least theoretically doesn't. A likely scenario is that old caches may -;;; never get adquately flushed to drop all references to obsolete layouts. +;;; never get adequately flushed to drop all references to obsolete layouts. ;;; If you call a GF once and not again, it won't flush; thus causing a retained ;;; old layout no matter what else is done. ;;; @@ -170,18 +151,17 @@ ;;; The bug is that it was possible for an observer to see (:FLUSH new-thing) ;;; in an older layout when it should actually have seen (:OBSOLETE newer-thing). ;;; On the other hand, it's still possible for an observer to see the -;;; wrong value in the INVALID slot itself. i.e. if it reads the slot +;;; wrong value in the INVALID slot itself. I.e. if it reads the slot ;;; before %invalidate-wrapper performs the transitivity operation, ;;; hence the possibility that this optimization is not only premature, ;;; but also pretty much not correct. (defun %invalidate-wrapper (owrapper state nwrapper) (aver (member state '(:flush :obsolete))) - #+sb-thread (aver (eq (sb-thread:mutex-owner sb-c::**world-lock**) - sb-thread:*current-thread*)) - (let ((classoid (layout-classoid nwrapper)) + #+sb-thread (aver (sb-thread:holding-mutex-p sb-kernel::**world-lock**)) + (let ((classoid (wrapper-classoid nwrapper)) (new-previous ()) (new-state (cons state nwrapper))) - (aver (eq (layout-classoid owrapper) classoid)) + (aver (eq (wrapper-classoid owrapper) classoid)) ;; First off, a previous call to INVALIDATE-WRAPPER may have ;; recorded OWRAPPER as an NWRAPPER to update to. Since OWRAPPER ;; is about to be invalid, it no longer makes sense to update to @@ -193,8 +173,8 @@ (dolist (weak-pointer (sb-kernel::standard-classoid-old-layouts classoid)) (let ((previous (weak-pointer-value weak-pointer))) (when previous - (setf (layout-invalid previous) - (cond ((and (eq (car (layout-invalid previous)) :obsolete) + (setf (wrapper-invalid previous) + (cond ((and (eq (car (wrapper-invalid previous)) :obsolete) (eq state :flush)) ;; :obsolete must stay :obsolete, ;; requiring the protocol for obsolete instances. @@ -208,11 +188,12 @@ ;; accessing the wrapper at the same time from outside the lock? ;; Inform readers of the reason for wrapper invalidity before marking ;; the wrapper as invalid. - (setf (layout-invalid owrapper) new-state) + (setf (wrapper-invalid owrapper) new-state) ;; Ensure that the INVALID slot conveying ancillary data describing the ;; invalidity reason is published before causing the invalid layout trap. (sb-thread:barrier (:write)) - (setf (layout-clos-hash owrapper) 0) + #+metaspace (setf (layout-clos-hash (wrapper-friend owrapper)) 0) + (setf (wrapper-clos-hash owrapper) 0) (push (make-weak-pointer owrapper) new-previous) ;; This function is called for effect; return value is arbitrary. (setf (sb-kernel::standard-classoid-old-layouts classoid) @@ -223,8 +204,8 @@ ;;; (or the names of our callees.) (defun check-wrapper-validity (instance) (with-world-lock () - (let* ((owrapper (layout-of instance)) - (state (layout-invalid owrapper))) + (let* ((owrapper (wrapper-of instance)) + (state (wrapper-invalid owrapper))) (aver (not (eq state :uninitialized))) (cond ((not state) owrapper) @@ -242,7 +223,7 @@ ;; previous call to REGISTER-LAYOUT for a superclass of ;; INSTANCE's class. See also the comment above ;; FORCE-CACHE-FLUSHES. Paul Dietz has test cases for this. - (let ((class (wrapper-class* owrapper))) + (let ((class (wrapper-class owrapper))) (%force-cache-flushes class) ;; KLUDGE: avoid an infinite recursion, it's still better to ;; bail out with an error for server softwares. see FIXME above. @@ -251,7 +232,7 @@ ;; Error message here is trying to figure out a bit more about the ;; situation, since we don't have anything approaching a test-case ;; for the bug. - (let ((new-state (layout-invalid (layout-of instance)))) + (let ((new-state (wrapper-invalid (wrapper-of instance)))) (when (eq new-state t) (cerror "Nevermind and recurse." 'bug :format-control "~@<~4IProblem forcing cache flushes. Please report ~ @@ -260,31 +241,31 @@ ~% Wrapper-of: ~S~ ~% Class-wrapper: ~S~%~:@>" :format-arguments (mapcar (lambda (x) - (cons x (layout-invalid x))) + (cons x (wrapper-invalid x))) (list owrapper - (layout-of instance) + (wrapper-of instance) (class-wrapper class))))))) (check-wrapper-validity instance)) ((consp state) - (ecase (car state) - (:flush - (let ((new (cdr state))) + (let ((new (the wrapper (cdr state)))) + (ecase (car state) + (:flush (cond ((std-instance-p instance) - (setf (%instance-layout instance) new)) + (setf (%instance-wrapper instance) new)) ((fsc-instance-p instance) - (setf (%fun-layout instance) new)) + (setf (%fun-wrapper instance) new)) (t - (bug "unrecognized instance type"))))) - (:obsolete - (%obsolete-instance-trap owrapper (cdr state) instance)))))))) + (bug "unrecognized instance type")))) + (:obsolete + (%obsolete-instance-trap owrapper new instance))))))))) (declaim (inline check-obsolete-instance)) (defun check-obsolete-instance (instance) - (when (invalid-wrapper-p (layout-of instance)) + (when (invalid-wrapper-p (wrapper-of instance)) (check-wrapper-validity instance))) (defun valid-wrapper-of (instance) - (let ((wrapper (layout-of instance))) + (let ((wrapper (wrapper-of instance))) (if (invalid-wrapper-p wrapper) (check-wrapper-validity instance) wrapper))) @@ -374,7 +355,7 @@ `((class *the-class-t*) (type t)))) (unless (eq mt t) - (setq wrapper (layout-of arg)) + (setq wrapper (wrapper-of arg)) (when (invalid-wrapper-p wrapper) (setq ,invalid-wrapper-p t) (setq wrapper (check-wrapper-validity arg))) @@ -388,7 +369,7 @@ (setf (cdr dfun-wrappers-tail) new-dfun-wrappers-tail) (setf dfun-wrappers-tail new-dfun-wrappers-tail)))) ,@(when wrappers - `((setq class (wrapper-class* wrapper)) + `((setq class (wrapper-class wrapper)) (setq type `(class-eq ,class))))) ,@(when wrappers `((push wrapper wrappers-rev) diff --git a/src/runtime/Config.alpha-linux b/src/runtime/Config.alpha-linux deleted file mode 100644 index ba1e2900de..0000000000 --- a/src/runtime/Config.alpha-linux +++ /dev/null @@ -1,30 +0,0 @@ -# -*- makefile -*- for the C-level run-time support for SBCL - -# This software is part of the SBCL system. See the README file for -# more information. -# -# This software is derived from the CMU CL system, which was -# written at Carnegie Mellon University and released into the -# public domain. The software is in the public domain and is -# provided with absolutely no warranty. See the COPYING and CREDITS -# files for more information. - -#LD = ld -taso ;; $LD is no longer used anywhere, should that be moved below? -LINKFLAGS += -dynamic -v -Wl,-T -Wl,ld-script.alpha-linux -rdynamic -NM = ./linux-nm - -ASSEM_SRC = alpha-assem.S ldso-stubs.S -ARCH_SRC = alpha-arch.c - -OS_SRC = linux-os.c linux-mman.c alpha-linux-os.c -OS_LIBS = -ldl - -ifdef LISP_FEATURE_SB_CORE_COMPRESSION - OS_LIBS += -lz -endif - -GC_SRC = cheneygc.c - -# Nothing to do for after-grovel-headers. -.PHONY: after-grovel-headers -after-grovel-headers: diff --git a/src/runtime/Config.arm-android b/src/runtime/Config.arm-android index 2854b65f42..c532cb1420 100644 --- a/src/runtime/Config.arm-android +++ b/src/runtime/Config.arm-android @@ -12,7 +12,6 @@ CC=${NDK_PATH}/toolchains/arm-linux-androideabi-4.8/prebuilt/linux-x86_64/arm-linux-androideabi/bin/gcc CFLAGS += -marm -march=armv5 --sysroot=${NDK_PATH}/platforms/android-15/arch-arm/ LINKFLAGS += --sysroot=${NDK_PATH}/platforms/android-15/arch-arm/ -NM = ${NDK_PATH}/toolchains/arm-linux-androideabi-4.8/prebuilt/linux-x86_64/arm-linux-androideabi/bin/nm ASSEM_SRC = arm-assem.S ARCH_SRC = arm-arch.c @@ -22,20 +21,14 @@ OS_LIBS = -ldl ifdef LISP_FEATURE_GENCGC GC_SRC = fullcgc.c gencgc.c traceroot.c -else - GC_SRC = cheneygc.c endif ifdef LISP_FEATURE_SB_THREAD OS_LIBS += -lpthread endif ifdef LISP_FEATURE_SB_CORE_COMPRESSION - OS_LIBS += -lz + OS_LIBS += -lzstd endif ifdef LISP_FEATURE_LARGEFILE CFLAGS += -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 endif - -# Nothing to do for after-grovel-headers. -.PHONY: after-grovel-headers -after-grovel-headers: diff --git a/src/runtime/Config.arm-bsd b/src/runtime/Config.arm-bsd index 10a09e8c11..34fdc6ecdb 100644 --- a/src/runtime/Config.arm-bsd +++ b/src/runtime/Config.arm-bsd @@ -16,13 +16,7 @@ OS_SRC = bsd-os.c arm-bsd-os.c ifdef LISP_FEATURE_GENCGC GC_SRC = fullcgc.c gencgc.c traceroot.c -else - GC_SRC = cheneygc.c endif ifdef LISP_FEATURE_SB_CORE_COMPRESSION - OS_LIBS += -lz + OS_LIBS += -lzstd endif - -# Nothing to do for after-grovel-headers. -.PHONY: after-grovel-headers -after-grovel-headers: diff --git a/src/runtime/Config.arm-linux b/src/runtime/Config.arm-linux index 2f72b244e6..16c7d76c2a 100644 --- a/src/runtime/Config.arm-linux +++ b/src/runtime/Config.arm-linux @@ -10,7 +10,6 @@ # files for more information. CFLAGS += -marm -march=armv5 -NM = ./linux-nm ASSEM_SRC = arm-assem.S ARCH_SRC = arm-arch.c @@ -20,21 +19,20 @@ OS_LIBS = -ldl -Wl,-no-as-needed ifdef LISP_FEATURE_GENCGC GC_SRC = fullcgc.c gencgc.c traceroot.c -else - GC_SRC = cheneygc.c endif ifdef LISP_FEATURE_SB_THREAD OS_LIBS += -lpthread endif ifdef LISP_FEATURE_SB_CORE_COMPRESSION - OS_LIBS += -lz + OS_LIBS += -lzstd endif ifdef LISP_FEATURE_LARGEFILE CFLAGS += -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 endif LINKFLAGS += -Wl,--export-dynamic -# Nothing to do for after-grovel-headers. -.PHONY: after-grovel-headers -after-grovel-headers: +ifdef LISP_FEATURE_SB_LINKABLE_RUNTIME + LIBSBCL = sbcl.o + USE_LIBSBCL = sbcl.o +endif diff --git a/src/runtime/Config.arm-openbsd b/src/runtime/Config.arm-openbsd new file mode 100644 index 0000000000..1c0c75bb5f --- /dev/null +++ b/src/runtime/Config.arm-openbsd @@ -0,0 +1,16 @@ +# -*- makefile -*- for the C-level run-time support for SBCL + +# This software is part of the SBCL system. See the README file for +# more information. +# +# This software is derived from the CMU CL system, which was +# written at Carnegie Mellon University and released into the +# public domain. The software is in the public domain and is +# provided with absolutely no warranty. See the COPYING and CREDITS +# files for more information. + +include Config.arm-bsd +include Config.generic-openbsd + +OS_LIBS += -larm +LINKFLAGS += -Wl,--export-dynamic diff --git a/src/runtime/Config.hppa-linux b/src/runtime/Config.arm64-bsd similarity index 62% rename from src/runtime/Config.hppa-linux rename to src/runtime/Config.arm64-bsd index 75cc31c8cb..6cbcd344bf 100644 --- a/src/runtime/Config.hppa-linux +++ b/src/runtime/Config.arm64-bsd @@ -9,20 +9,14 @@ # provided with absolutely no warranty. See the COPYING and CREDITS # files for more information. -LINKFLAGS += -v -NM = ./linux-nm +ASSEM_SRC = arm64-assem.S +ARCH_SRC = arm64-arch.c -ASSEM_SRC = hppa-assem.S ldso-stubs.S -ARCH_SRC = hppa-arch.c +OS_SRC = bsd-os.c arm64-bsd-os.c -OS_SRC = linux-os.c linux-mman.c hppa-linux-os.c -OS_LIBS = -ldl +ifdef LISP_FEATURE_GENCGC + GC_SRC = fullcgc.c gencgc.c traceroot.c +endif ifdef LISP_FEATURE_SB_CORE_COMPRESSION - OS_LIBS += -lz + OS_LIBS += -lzstd endif - -GC_SRC = cheneygc.c - -# Nothing to do for after-grovel-headers. -.PHONY: after-grovel-headers -after-grovel-headers: diff --git a/src/runtime/Config.ppc-darwin b/src/runtime/Config.arm64-darwin similarity index 54% rename from src/runtime/Config.ppc-darwin rename to src/runtime/Config.arm64-darwin index 622d6cc0f4..3e07234f89 100644 --- a/src/runtime/Config.ppc-darwin +++ b/src/runtime/Config.arm64-darwin @@ -9,35 +9,36 @@ # provided with absolutely no warranty. See the COPYING and CREDITS # files for more information. -CFLAGS = -g -Wall -O2 -fdollars-in-identifiers -mmacosx-version-min=10.4 -LINKFLAGS += -mmacosx-version-min=10.4 +CFLAGS += -g -Wall -fdollars-in-identifiers -OS_SRC = bsd-os.c darwin-os.c ppc-darwin-os.c +# ifdef LISP_FEATURE_INODE64 +# CFLAGS += -D_DARWIN_USE_64_BIT_INODE +# endif -OS_LIBS = -lSystem -lc -ifdef LISP_FEATURE_SB_CORE_COMPRESSION - OS_LIBS += -lz -endif - -CC = gcc - -ASSEM_SRC = ppc-assem.S -ARCH_SRC = ppc-arch.c +OS_SRC = bsd-os.c arm64-bsd-os.c darwin-os.c arm64-darwin-os.c -CPPFLAGS += -no-cpp-precomp - -ifdef LISP_FEATURE_GENCGC - GC_SRC = fullcgc.c gencgc.c traceroot.c -else - GC_SRC = cheneygc.c +OS_LIBS = -lSystem -lc -ldl +ifdef LISP_FEATURE_SB_THREAD + OS_LIBS += -lpthread +endif +ifdef LISP_FEATURE_SB_CORE_COMPRESSION + OS_LIBS += -lzstd endif - ifdef LISP_FEATURE_SB_LINKABLE_RUNTIME LIBSBCL = libsbcl.a USE_LIBSBCL = -Wl,-force_load libsbcl.a endif -.PHONY: after-grovel-headers +ASSEM_SRC = arm64-assem.S +ARCH_SRC = arm64-arch.c + +LINKFLAGS += -dynamic -twolevel_namespace -bind_at_load + +CFLAGS += -fno-omit-frame-pointer +DISABLE_PIE=no -# Nothing to do. -after-grovel-headers: +ifdef LISP_FEATURE_IMMOBILE_SPACE + GC_SRC = fullcgc.c gencgc.c traceroot.c immobile-space.c +else + GC_SRC = fullcgc.c gencgc.c traceroot.c +endif diff --git a/src/runtime/Config.arm64-freebsd b/src/runtime/Config.arm64-freebsd new file mode 100644 index 0000000000..7a2e04f407 --- /dev/null +++ b/src/runtime/Config.arm64-freebsd @@ -0,0 +1,24 @@ +# -*- makefile -*- for the C-level run-time support for SBCL + +# This software is part of the SBCL system. See the README file for +# more information. +# +# This software is derived from the CMU CL system, which was +# written at Carnegie Mellon University and released into the +# public domain. The software is in the public domain and is +# provided with absolutely no warranty. See the COPYING and CREDITS +# files for more information. + +include Config.arm64-bsd + +LINKFLAGS += -dynamic -Wl,--export-dynamic + +OS_LIBS += -lutil + +# use libthr (1:1 threading). libpthread (m:n threading) does not work. +ifdef LISP_FEATURE_SB_THREAD + #OS_LIBS += -lpthread + OS_LIBS += -lthr +endif + +CFLAGS += -fno-omit-frame-pointer diff --git a/src/runtime/Config.arm64-linux b/src/runtime/Config.arm64-linux index 4672459412..1281c78933 100644 --- a/src/runtime/Config.arm64-linux +++ b/src/runtime/Config.arm64-linux @@ -9,8 +9,6 @@ # provided with absolutely no warranty. See the COPYING and CREDITS # files for more information. -NM = ./linux-nm - ASSEM_SRC = arm64-assem.S ARCH_SRC = arm64-arch.c @@ -19,21 +17,21 @@ OS_LIBS = -ldl -Wl,-no-as-needed ifdef LISP_FEATURE_GENCGC GC_SRC = fullcgc.c gencgc.c traceroot.c -else - GC_SRC = cheneygc.c endif ifdef LISP_FEATURE_SB_THREAD OS_LIBS += -lpthread endif ifdef LISP_FEATURE_SB_CORE_COMPRESSION - OS_LIBS += -lz + OS_LIBS += -lzstd endif +CFLAGS += -std=gnu99 ifdef LISP_FEATURE_LARGEFILE CFLAGS += -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 endif LINKFLAGS += -Wl,--export-dynamic -# Nothing to do for after-grovel-headers. -.PHONY: after-grovel-headers -after-grovel-headers: +ifdef LISP_FEATURE_SB_LINKABLE_RUNTIME + LIBSBCL = sbcl.o + USE_LIBSBCL = sbcl.o +endif diff --git a/src/runtime/Config.arm64-netbsd b/src/runtime/Config.arm64-netbsd new file mode 100644 index 0000000000..93470e33fc --- /dev/null +++ b/src/runtime/Config.arm64-netbsd @@ -0,0 +1,21 @@ +# -*- makefile -*- for the C-level run-time support for SBCL + +# This software is part of the SBCL system. See the README file for +# more information. +# +# This software is derived from the CMU CL system, which was +# written at Carnegie Mellon University and released into the +# public domain. The software is in the public domain and is +# provided with absolutely no warranty. See the COPYING and CREDITS +# files for more information. + +include Config.arm64-bsd + +OS_LIBS = -lutil + +ifdef LISP_FEATURE_SB_THREAD + OS_LIBS += -lpthread -lrt +endif + +LINKFLAGS += -export-dynamic +LDFLAGS += -export-dynamic diff --git a/src/runtime/Config.arm64-openbsd b/src/runtime/Config.arm64-openbsd new file mode 100644 index 0000000000..929d8a627b --- /dev/null +++ b/src/runtime/Config.arm64-openbsd @@ -0,0 +1,15 @@ +# -*- makefile -*- for the C-level run-time support for SBCL + +# This software is part of the SBCL system. See the README file for +# more information. +# +# This software is derived from the CMU CL system, which was +# written at Carnegie Mellon University and released into the +# public domain. The software is in the public domain and is +# provided with absolutely no warranty. See the COPYING and CREDITS +# files for more information. + +include Config.arm64-bsd +include Config.generic-openbsd + +LINKFLAGS += -Wl,--export-dynamic diff --git a/src/runtime/Config.generic-openbsd b/src/runtime/Config.generic-openbsd index 4ffb6ea7a5..6936223e5d 100644 --- a/src/runtime/Config.generic-openbsd +++ b/src/runtime/Config.generic-openbsd @@ -13,7 +13,7 @@ LINKFLAGS += -Wl,-z,wxneeded OS_LIBS += -lutil ifdef LISP_FEATURE_SB_THREAD -CFLAGS += -pthread -DOS_THREAD_STACK +CFLAGS += -pthread OS_LIBS += -pthread endif diff --git a/src/runtime/Config.hppa-hpux b/src/runtime/Config.hppa-hpux deleted file mode 100644 index 5b597a7df1..0000000000 --- a/src/runtime/Config.hppa-hpux +++ /dev/null @@ -1,40 +0,0 @@ -# -*- makefile -*- for the C-level run-time support for SBCL - -# This software is part of the SBCL system. See the README file for -# more information. -# -# This software is derived from the CMU CL system, which was -# written at Carnegie Mellon University and released into the -# public domain. The software is in the public domain and is -# provided with absolutely no warranty. See the COPYING and CREDITS -# files for more information. - -LINKFLAGS += -v -# avoid native tools -NM = /usr/local/bin/nm -CC = /usr/local/bin/gcc - -ASSEM_SRC = hppa-assem.S ldso-stubs.S -ARCH_SRC = hppa-arch.c -OS_SRC = hpux-os.c hppa-hpux-os.c - -OS_LIBS = - -CFLAGS += -D_POSIX_SOURCE -D_HPUX_SOURCE - -ifdef LISP_FEATURE_LARGEFILE - CFLAGS += -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -endif - -ifdef LISP_FEATURE_SB_THREAD - OS_LIBS += -lpthread -endif -ifdef LISP_FEATURE_SB_CORE_COMPRESSION - OS_LIBS += -lz -endif - -GC_SRC = cheneygc.c - -# Nothing to do for after-grovel-headers. -.PHONY: after-grovel-headers -after-grovel-headers: diff --git a/src/runtime/Config.mips-linux b/src/runtime/Config.mips-linux index 7ec674f4b2..5eb04d0582 100644 --- a/src/runtime/Config.mips-linux +++ b/src/runtime/Config.mips-linux @@ -9,8 +9,7 @@ # provided with absolutely no warranty. See the COPYING and CREDITS # files for more information. -LINKFLAGS += -O2 -Wl,--export-dynamic -NM = ./linux-nm +LINKFLAGS += -Wl,--export-dynamic ASSEM_SRC = mips-assem.S ARCH_SRC = mips-arch.c @@ -26,11 +25,7 @@ ifdef LISP_FEATURE_SB_THREAD OS_LIBS += -lpthread endif ifdef LISP_FEATURE_SB_CORE_COMPRESSION - OS_LIBS += -lz + OS_LIBS += -lzstd endif -GC_SRC = cheneygc.c - -# Nothing to do for after-grovel-headers. -.PHONY: after-grovel-headers -after-grovel-headers: +GC_SRC = gencgc.c fullcgc.c traceroot.c diff --git a/src/runtime/Config.ppc-linux b/src/runtime/Config.ppc-linux index 2f3ce9f631..00b35dd572 100644 --- a/src/runtime/Config.ppc-linux +++ b/src/runtime/Config.ppc-linux @@ -9,9 +9,8 @@ # provided with absolutely no warranty. See the COPYING and CREDITS # files for more information. -CFLAGS += -m32 +CFLAGS += -m32 -std=gnu99 LINKFLAGS += -m32 -Wl,--export-dynamic -NM = ./linux-nm ASSEM_SRC = ppc-assem.S ARCH_SRC = ppc-arch.c @@ -19,19 +18,11 @@ ARCH_SRC = ppc-arch.c OS_SRC = linux-os.c linux-mman.c ppc-linux-os.c OS_LIBS = -ldl -Wl,-no-as-needed -ifdef LISP_FEATURE_GENCGC - GC_SRC = fullcgc.c gencgc.c traceroot.c -else - GC_SRC = cheneygc.c -endif +GC_SRC = fullcgc.c gencgc.c traceroot.c ifdef LISP_FEATURE_SB_THREAD OS_LIBS += -lpthread endif ifdef LISP_FEATURE_SB_CORE_COMPRESSION - OS_LIBS += -lz + OS_LIBS += -lzstd endif - -# Nothing to do for after-grovel-headers. -.PHONY: after-grovel-headers -after-grovel-headers: diff --git a/src/runtime/Config.ppc-netbsd b/src/runtime/Config.ppc-netbsd index 40a63c7ff8..524c7f2931 100644 --- a/src/runtime/Config.ppc-netbsd +++ b/src/runtime/Config.ppc-netbsd @@ -18,11 +18,7 @@ ARCH_SRC = ppc-arch.c OS_SRC = bsd-os.c ppc-bsd-os.c OS_LIBS = # -ldl ifdef LISP_FEATURE_SB_CORE_COMPRESSION - OS_LIBS += -lz + OS_LIBS += -lzstd endif GC_SRC = fullcgc.c gencgc.c traceroot.c - -# Nothing to do for after-grovel-headers. -.PHONY: after-grovel-headers -after-grovel-headers: diff --git a/src/runtime/Config.ppc-openbsd b/src/runtime/Config.ppc-openbsd index 13c74c71ff..7839badf6d 100644 --- a/src/runtime/Config.ppc-openbsd +++ b/src/runtime/Config.ppc-openbsd @@ -19,11 +19,7 @@ ARCH_SRC = ppc-arch.c OS_SRC = bsd-os.c ppc-bsd-os.c ifdef LISP_FEATURE_SB_CORE_COMPRESSION - OS_LIBS += -lz + OS_LIBS += -lzstd endif GC_SRC = fullcgc.c gencgc.c traceroot.c - -# Nothing to do for after-grovel-headers. -.PHONY: after-grovel-headers -after-grovel-headers: diff --git a/src/runtime/Config.ppc64-linux b/src/runtime/Config.ppc64-linux index e58cb5d5c5..8f68d26156 100644 --- a/src/runtime/Config.ppc64-linux +++ b/src/runtime/Config.ppc64-linux @@ -9,9 +9,8 @@ # provided with absolutely no warranty. See the COPYING and CREDITS # files for more information. -CFLAGS += -m64 +CFLAGS += -m64 -std=gnu99 LINKFLAGS += -m64 -Wl,--export-dynamic -NM = ./linux-nm ASSEM_SRC = ppc64-assem.S ARCH_SRC = ppc-arch.c @@ -21,17 +20,11 @@ OS_LIBS = -ldl -Wl,-no-as-needed ifdef LISP_FEATURE_GENCGC GC_SRC = fullcgc.c gencgc.c traceroot.c -else - GC_SRC = cheneygc.c endif ifdef LISP_FEATURE_SB_THREAD OS_LIBS += -lpthread endif ifdef LISP_FEATURE_SB_CORE_COMPRESSION - OS_LIBS += -lz + OS_LIBS += -lzstd endif - -# Nothing to do for after-grovel-headers. -.PHONY: after-grovel-headers -after-grovel-headers: diff --git a/src/runtime/Config.riscv-linux b/src/runtime/Config.riscv-linux index 5d585934ea..d8b33d1d18 100644 --- a/src/runtime/Config.riscv-linux +++ b/src/runtime/Config.riscv-linux @@ -9,8 +9,6 @@ # provided with absolutely no warranty. See the COPYING and CREDITS # files for more information. -NM = ./linux-nm - ARCH_SRC = riscv-arch.c OS_SRC = linux-os.c linux-mman.c riscv-linux-os.c @@ -19,7 +17,7 @@ ifdef LISP_FEATURE_SB_THREAD OS_LIBS += -lpthread endif ifdef LISP_FEATURE_SB_CORE_COMPRESSION - OS_LIBS += -lz + OS_LIBS += -lzstd endif LINKFLAGS += -Wl,--export-dynamic DISABLE_PIE=no @@ -28,12 +26,4 @@ ifdef LISP_FEATURE_LARGEFILE CFLAGS += -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 endif -ifdef LISP_FEATURE_GENCGC - GC_SRC = fullcgc.c gencgc.c traceroot.c -else - GC_SRC = cheneygc.c -endif - -# Nothing to do for after-grovel-headers. -.PHONY: after-grovel-headers -after-grovel-headers: +GC_SRC = fullcgc.c gencgc.c traceroot.c diff --git a/src/runtime/Config.sparc-linux b/src/runtime/Config.sparc-linux index 8b7ab0d447..132b29a70a 100644 --- a/src/runtime/Config.sparc-linux +++ b/src/runtime/Config.sparc-linux @@ -12,7 +12,6 @@ CFLAGS += -m32 -fno-PIC ASFLAGS = -m32 -fno-PIC -g -Wall -Wa,-xarch=v8plus LINKFLAGS += -rdynamic -m32 -NM = ./linux-nm ASSEM_SRC = sparc-assem.S ARCH_SRC = sparc-arch.c @@ -20,15 +19,7 @@ ARCH_SRC = sparc-arch.c OS_SRC = linux-os.c linux-mman.c sparc-linux-os.c OS_LIBS = -ldl ifdef LISP_FEATURE_SB_CORE_COMPRESSION - OS_LIBS += -lz + OS_LIBS += -lzstd endif -ifdef LISP_FEATURE_GENCGC - GC_SRC = fullcgc.c gencgc.c traceroot.c -else - GC_SRC = cheneygc.c -endif - -# Nothing to do for after-grovel-headers. -.PHONY: after-grovel-headers -after-grovel-headers: +GC_SRC = fullcgc.c gencgc.c traceroot.c diff --git a/src/runtime/Config.sparc-netbsd b/src/runtime/Config.sparc-netbsd index 840750ac4f..b0ae9ad56d 100644 --- a/src/runtime/Config.sparc-netbsd +++ b/src/runtime/Config.sparc-netbsd @@ -10,9 +10,8 @@ # files for more information. CC = gcc -CFLAGS += -g -Wall -O2 +CFLAGS += -g -Wall LINKFLAGS += -export-dynamic -NM = nm -t x -p ASSEM_SRC = sparc-assem.S ARCH_SRC = sparc-arch.c @@ -20,15 +19,7 @@ ARCH_SRC = sparc-arch.c OS_SRC = bsd-os.c sparc-bsd-os.c OS_LIBS = # -ldl ifdef LISP_FEATURE_SB_CORE_COMPRESSION - OS_LIBS += -lz + OS_LIBS += -lzstd endif -ifdef LISP_FEATURE_GENCGC - GC_SRC = fullcgc.c gencgc.c traceroot.c -else - GC_SRC = cheneygc.c -endif - -# Nothing to do for after-grovel-headers. -.PHONY: after-grovel-headers -after-grovel-headers: +GC_SRC = fullcgc.c gencgc.c traceroot.c diff --git a/src/runtime/Config.sparc-sunos b/src/runtime/Config.sparc-sunos index 911b088cd4..7e77198a28 100644 --- a/src/runtime/Config.sparc-sunos +++ b/src/runtime/Config.sparc-sunos @@ -10,10 +10,9 @@ # files for more information. CC = gcc -CFLAGS += -DSVR4 -D_REENTRANT +CFLAGS += -D__EXTENSIONS__ -DSVR4 -D_REENTRANT ASFLAGS = -g -DSVR4 -Wa,-xarch=v8plus #LINKFLAGS += -v -NM = nm -t x -p # This next line has nothing to do with disabling PIE. It has only to # do with the problem that "grep" on the build machine I'm using can't # parse "-e '[^f]nopie" and so gets an error in GNUmakefile. @@ -25,15 +24,7 @@ ARCH_SRC = sparc-arch.c OS_SRC = sunos-os.c sparc-sunos-os.c OS_LIBS = -ldl -lsocket -lnsl -lrt ifdef LISP_FEATURE_SB_CORE_COMPRESSION - OS_LIBS += -lz + OS_LIBS += -lzstd endif -ifdef LISP_FEATURE_GENCGC - GC_SRC = fullcgc.c gencgc.c traceroot.c -else - GC_SRC = cheneygc.c -endif - -# Nothing to do for after-grovel-headers. -.PHONY: after-grovel-headers -after-grovel-headers: +GC_SRC = fullcgc.c gencgc.c traceroot.c diff --git a/src/runtime/Config.x86-64-bsd b/src/runtime/Config.x86-64-bsd index 88f47b4ce2..c2d3b07c8e 100644 --- a/src/runtime/Config.x86-64-bsd +++ b/src/runtime/Config.x86-64-bsd @@ -16,7 +16,10 @@ ARCH_SRC = x86-64-arch.c OS_SRC = bsd-os.c x86-64-bsd-os.c OS_LIBS = # -ldl ifdef LISP_FEATURE_SB_CORE_COMPRESSION - OS_LIBS += -lz + OS_LIBS += -lzstd +endif +ifdef HAVE_LIBUNWIND + OS_LIBS += -lunwind endif CFLAGS += -fno-omit-frame-pointer @@ -27,7 +30,3 @@ ifdef LISP_FEATURE_IMMOBILE_SPACE else GC_SRC = fullcgc.c gencgc.c traceroot.c endif - -# Nothing to do for after-grovel-headers. -.PHONY: after-grovel-headers -after-grovel-headers: diff --git a/src/runtime/Config.x86-64-darwin b/src/runtime/Config.x86-64-darwin index 027d0dfb84..2d9e7a6692 100644 --- a/src/runtime/Config.x86-64-darwin +++ b/src/runtime/Config.x86-64-darwin @@ -9,7 +9,7 @@ # provided with absolutely no warranty. See the COPYING and CREDITS # files for more information. -CFLAGS += -g -Wall -O2 -fdollars-in-identifiers -DOS_THREAD_STACK +CFLAGS += -g -Wall -fdollars-in-identifiers ifdef SBCL_MACOSX_VERSION_MIN CFLAGS += -mmacosx-version-min=$(SBCL_MACOSX_VERSION_MIN) @@ -29,7 +29,7 @@ ifdef LISP_FEATURE_SB_THREAD OS_LIBS += -lpthread endif ifdef LISP_FEATURE_SB_CORE_COMPRESSION - OS_LIBS += -lz + OS_LIBS += -lzstd endif ifdef LISP_FEATURE_SB_LINKABLE_RUNTIME LIBSBCL = libsbcl.a @@ -49,7 +49,3 @@ ifdef LISP_FEATURE_IMMOBILE_SPACE else GC_SRC = fullcgc.c gencgc.c traceroot.c endif - -# Nothing to do for after-grovel-headers. -.PHONY: after-grovel-headers -after-grovel-headers: diff --git a/src/runtime/Config.x86-64-freebsd b/src/runtime/Config.x86-64-freebsd index c94591ae5b..0c059c1a65 100644 --- a/src/runtime/Config.x86-64-freebsd +++ b/src/runtime/Config.x86-64-freebsd @@ -15,7 +15,8 @@ include Config.x86-64-bsd # worked fine for most things, but LOAD-FOREIGN & friends require # dlopen() etc., which in turn depend on dynamic linking of the # runtime. -OS_LIBS += -lutil +OS_LIBS += -lutil -L/usr/local/lib +CPPFLAGS += -isystem/usr/local/include # use libthr (1:1 threading). libpthread (m:n threading) does not work. ifdef LISP_FEATURE_SB_THREAD diff --git a/src/runtime/Config.x86-64-haiku b/src/runtime/Config.x86-64-haiku index 643cbb872f..c050ed0c63 100644 --- a/src/runtime/Config.x86-64-haiku +++ b/src/runtime/Config.x86-64-haiku @@ -37,7 +37,3 @@ ifdef LISP_FEATURE_SB_LINKABLE_RUNTIME LIBSBCL = sbcl.o USE_LIBSBCL = sbcl.o endif - -# Nothing to do for after-grovel-headers. -.PHONY: after-grovel-headers -after-grovel-headers: diff --git a/src/runtime/Config.x86-64-linux b/src/runtime/Config.x86-64-linux index 904631c688..230c5ac798 100644 --- a/src/runtime/Config.x86-64-linux +++ b/src/runtime/Config.x86-64-linux @@ -9,8 +9,6 @@ # provided with absolutely no warranty. See the COPYING and CREDITS # files for more information. -NM = ./linux-nm - ASSEM_SRC = x86-64-assem.S ARCH_SRC = x86-64-arch.c OS_SRC = linux-os.c linux-mman.c x86-64-linux-os.c @@ -39,7 +37,11 @@ ifdef LISP_FEATURE_SB_THREAD endif ifdef LISP_FEATURE_SB_CORE_COMPRESSION - OS_LIBS += -lz + OS_LIBS += -lzstd +endif + +ifdef HAVE_LIBUNWIND + OS_LIBS += -lunwind endif CFLAGS += -Wunused-parameter -fno-omit-frame-pointer -momit-leaf-frame-pointer @@ -55,7 +57,3 @@ ifdef LISP_FEATURE_SB_LINKABLE_RUNTIME LIBSBCL = sbcl.o USE_LIBSBCL = sbcl.o endif - -# Nothing to do for after-grovel-headers. -.PHONY: after-grovel-headers -after-grovel-headers: diff --git a/src/runtime/Config.x86-64-sunos b/src/runtime/Config.x86-64-sunos index 17eef040fc..174a4a3fcc 100644 --- a/src/runtime/Config.x86-64-sunos +++ b/src/runtime/Config.x86-64-sunos @@ -1,12 +1,11 @@ CC=gcc -CFLAGS = -m64 -g -O2 -Wall -D__EXTENSIONS__ -D_POSIX_C_SOURCE=199506L -DSVR4 -D_REENTRANT -fno-omit-frame-pointer +CFLAGS = -m64 -g -Wall -std=gnu89 -D__EXTENSIONS__ -DSVR4 -D_REENTRANT -fno-omit-frame-pointer LINKFLAGS = -m64 -g ASFLAGS = -m64 -Wall -NM = nm -xgp GREP = ggrep #CC=/opt/SunStudioExpress/bin/cc -#CFLAGS = -xarch=generic64 -g -O2 -Wall -D__EXTENSIONS__ -D_POSIX_C_SOURCE=199506L -DSVR4 -D_REENTRANT -fno-omit-frame-pointer +#CFLAGS = -xarch=generic64 -g -O2 -Wall -D__EXTENSIONS__ -DSVR4 -D_REENTRANT -fno-omit-frame-pointer #ASFLAGS = -xarch=generic64 -Wall ASSEM_SRC = x86-64-assem.S @@ -15,11 +14,11 @@ ARCH_SRC = x86-64-arch.c OS_SRC = sunos-os.c x86-64-sunos-os.c OS_LIBS= -ldl -lsocket -lnsl -lrt ifdef LISP_FEATURE_SB_CORE_COMPRESSION - OS_LIBS += -lz + OS_LIBS += -lzstd endif -GC_SRC= fullcgc.c gencgc.c traceroot.c - -# Nothing to do for after-grovel-headers. -.PHONY: after-grovel-headers -after-grovel-headers: +ifdef LISP_FEATURE_IMMOBILE_SPACE + GC_SRC = fullcgc.c gencgc.c traceroot.c immobile-space.c elf.c +else + GC_SRC = fullcgc.c gencgc.c traceroot.c +endif diff --git a/src/runtime/Config.x86-64-win32 b/src/runtime/Config.x86-64-win32 index a189f366be..b758a14bde 100644 --- a/src/runtime/Config.x86-64-win32 +++ b/src/runtime/Config.x86-64-win32 @@ -14,10 +14,6 @@ ARCH_SRC = x86-64-arch.c OS_SRC = win32-os.c x86-64-win32-os.c -ifdef LISP_FEATURE_SB_THREAD - OS_SRC += pthreads_win32.c -endif - ifdef LISP_FEATURE_SB_LINKABLE_RUNTIME LIBSBCL = libsbcl.a USE_LIBSBCL = -Wl,--whole-archive libsbcl.a -Wl,--no-whole-archive @@ -42,7 +38,10 @@ __LDFLAGS__ = OS_LIBS = -l ws2_32 -ladvapi32 ifdef LISP_FEATURE_SB_CORE_COMPRESSION - OS_LIBS += -lz + OS_LIBS += -lzstd +endif +ifdef LISP_FEATURE_SB_FUTEX + OS_LIBS += -lSynchronization endif ifdef LISP_FEATURE_IMMOBILE_SPACE @@ -52,13 +51,13 @@ else endif CFLAGS = -g -W -Wall \ - -Wno-unused-function \ + -Wno-unused-function -Wno-unused-parameter -Wno-cast-function-type \ -fno-omit-frame-pointer \ -O5 -m64 -DWINVER=0x0501 \ -D__W32API_USE_DLLIMPORT__ CC = gcc -# Nothing to do for after-grovel-headers. -.PHONY: after-grovel-headers -after-grovel-headers: +ifeq ($(shell $(LD) --disable-dynamicbase 2>&1 | grep disable-dynamicbase),) +LINKFLAGS += -Wl,--disable-dynamicbase +endif diff --git a/src/runtime/Config.x86-bsd b/src/runtime/Config.x86-bsd index 900bef7ab2..8887943cb6 100644 --- a/src/runtime/Config.x86-bsd +++ b/src/runtime/Config.x86-bsd @@ -18,11 +18,7 @@ LINKFLAGS += -Wl,--export-dynamic OS_SRC = bsd-os.c x86-bsd-os.c OS_LIBS = # -ldl ifdef LISP_FEATURE_SB_CORE_COMPRESSION - OS_LIBS += -lz + OS_LIBS += -lzstd endif GC_SRC = fullcgc.c gencgc.c traceroot.c - -# Nothing to do for after-grovel-headers. -.PHONY: after-grovel-headers -after-grovel-headers: diff --git a/src/runtime/Config.x86-darwin b/src/runtime/Config.x86-darwin deleted file mode 100644 index 1fb6c53c45..0000000000 --- a/src/runtime/Config.x86-darwin +++ /dev/null @@ -1,52 +0,0 @@ -# -*- makefile -*- for the C-level run-time support for SBCL - -# This software is part of the SBCL system. See the README file for -# more information. -# -# This software is derived from the CMU CL system, which was -# written at Carnegie Mellon University and released into the -# public domain. The software is in the public domain and is -# provided with absolutely no warranty. See the COPYING and CREDITS -# files for more information. - -CFLAGS += -arch i386 -g -Wall -O2 -fdollars-in-identifiers -fno-omit-frame-pointer -DOS_THREAD_STACK - -LINKFLAGS += -arch i386 -ifdef SBCL_MACOSX_VERSION_MIN - CFLAGS += -mmacosx-version-min=$(SBCL_MACOSX_VERSION_MIN) - LINKFLAGS += -mmacosx-version-min=$(SBCL_MACOSX_VERSION_MIN) -else - ifdef LISP_FEATURE_DARWIN9_OR_BETTER - CFLAGS += -mmacosx-version-min=10.5 - LINKFLAGS += -mmacosx-version-min=10.5 - else - CFLAGS += -mmacosx-version-min=10.4 - LINKFLAGS += -mmacosx-version-min=10.4 - endif -endif - -OS_SRC = bsd-os.c x86-bsd-os.c darwin-os.c x86-darwin-os.c - -OS_LIBS = -lSystem -lc -ldl -ifdef LISP_FEATURE_SB_THREAD - OS_LIBS += -lpthread -endif -ifdef LISP_FEATURE_SB_CORE_COMPRESSION - OS_LIBS += -lz -endif -ifdef LISP_FEATURE_SB_LINKABLE_RUNTIME - LIBSBCL = libsbcl.a - USE_LIBSBCL = -Wl,-force_load libsbcl.a -endif - -ASSEM_SRC = x86-assem.S -ARCH_SRC = x86-arch.c - -CPPFLAGS += -no-cpp-precomp - -GC_SRC = fullcgc.c gencgc.c traceroot.c - -.PHONY: after-grovel-headers - -# Nothing to do. -after-grovel-headers: diff --git a/src/runtime/Config.x86-linux b/src/runtime/Config.x86-linux index 67a758eb6f..b5f1355c01 100644 --- a/src/runtime/Config.x86-linux +++ b/src/runtime/Config.x86-linux @@ -9,8 +9,6 @@ # provided with absolutely no warranty. See the COPYING and CREDITS # files for more information. -NM = ./linux-nm - ASSEM_SRC = x86-assem.S ARCH_SRC = x86-arch.c OS_SRC = linux-os.c linux-mman.c x86-linux-os.c @@ -41,7 +39,10 @@ ifdef LISP_FEATURE_SB_THREAD OS_LIBS += -lpthread endif ifdef LISP_FEATURE_SB_CORE_COMPRESSION - OS_LIBS += -lz + OS_LIBS += -lzstd +endif +ifdef HAVE_LIBUNWIND + OS_LIBS += -lunwind endif ifdef LISP_FEATURE_SB_LINKABLE_RUNTIME LIBSBCL = sbcl.o @@ -49,7 +50,3 @@ ifdef LISP_FEATURE_SB_LINKABLE_RUNTIME endif GC_SRC = fullcgc.c gencgc.c traceroot.c - -# Nothing to do for after-grovel-headers. -.PHONY: after-grovel-headers -after-grovel-headers: diff --git a/src/runtime/Config.x86-sunos b/src/runtime/Config.x86-sunos index c63fa6676d..33c963e76d 100644 --- a/src/runtime/Config.x86-sunos +++ b/src/runtime/Config.x86-sunos @@ -10,8 +10,7 @@ # files for more information. CC=gcc -CFLAGS = -g -O2 -Wall -D__EXTENSIONS__ -D_POSIX_C_SOURCE=199506L -DSVR4 -D_REENTRANT -fno-omit-frame-pointer -NM = nm -xgp +CFLAGS = -g -O2 -Wall -D__EXTENSIONS__ -DSVR4 -D_REENTRANT -fno-omit-frame-pointer GREP = ggrep ASSEM_SRC = x86-assem.S @@ -21,11 +20,7 @@ OS_SRC = sunos-os.c x86-sunos-os.c OS_LIBS= -ldl -lsocket -lnsl -lrt ifdef LISP_FEATURE_SB_CORE_COMPRESSION - OS_LIBS += -lz + OS_LIBS += -lzstd endif GC_SRC= fullcgc.c gencgc.c traceroot.c - -# Nothing to do for after-grovel-headers. -.PHONY: after-grovel-headers -after-grovel-headers: diff --git a/src/runtime/Config.x86-win32 b/src/runtime/Config.x86-win32 index b9a81d7953..806971313b 100644 --- a/src/runtime/Config.x86-win32 +++ b/src/runtime/Config.x86-win32 @@ -14,7 +14,7 @@ TARGET=sbcl.exe ASSEM_SRC = x86-assem.S ARCH_SRC = x86-arch.c -OS_SRC = win32-os.c x86-win32-os.c pthreads_win32.c +OS_SRC = win32-os.c x86-win32-os.c ifdef LISP_FEATURE_SB_LINKABLE_RUNTIME LIBSBCL = libsbcl.a @@ -40,13 +40,16 @@ __LDFLAGS__ = OS_LIBS = -l ws2_32 -ladvapi32 ifdef LISP_FEATURE_SB_CORE_COMPRESSION - OS_LIBS += -lz + OS_LIBS += -lzstd +endif +ifdef LISP_FEATURE_SB_FUTEX + OS_LIBS += -lSynchronization endif GC_SRC = fullcgc.c gencgc.c traceroot.c CFLAGS = -g -Wall -O3 \ - -fno-omit-frame-pointer -march=i686 -DWINVER=0x0501 \ + -fno-omit-frame-pointer -march=i686 -DWINVER=0x600 -D_WIN32_WINNT=0x600 \ -D__W32API_USE_DLLIMPORT__ \ -mpreferred-stack-boundary=2 # We assume Windows ABI 4-byte alignment, but GCC decided to change to @@ -54,6 +57,6 @@ CFLAGS = -g -Wall -O3 \ CC = gcc -# Nothing to do for after-grovel-headers. -.PHONY: after-grovel-headers -after-grovel-headers: +ifeq ($(shell $(LD) --disable-dynamicbase 2>&1 | grep disable-dynamicbase),) +LINKFLAGS += -Wl,--disable-dynamicbase,--disable-nxcompat +endif diff --git a/src/runtime/GNUmakefile b/src/runtime/GNUmakefile index 0ea096e1c1..dd9d5a304e 100644 --- a/src/runtime/GNUmakefile +++ b/src/runtime/GNUmakefile @@ -22,7 +22,6 @@ SBCL_PAXCTL ?= : # Config file. Most of them are same on most systems right now. # If you need to override one of these, do it in Config. LINKFLAGS += -g -NM = nm -gp DEPEND_FLAGS = -MM GREP = grep LD = ld @@ -36,7 +35,7 @@ include ../../output/prefix.def CFLAGS += -g -Wall -Wundef -Wsign-compare -Wpointer-arith -O3 ASFLAGS += $(CFLAGS) -CPPFLAGS += -I. +CPPFLAGS += -I. -I../../ # Give make access to the target Lisp features. include genesis/Makefile.features @@ -46,7 +45,7 @@ include genesis/Makefile.features # Config-foo file for setup foo, then arrange for Config to be a # symlink to Config-foo. # Commonly used variables in Config are: ARCH_SRC, ASSEM_SRC, GC_SRC, -# OS_SRC, OS_LIBS, OS_CLEAN_FILES +# OS_SRC, OS_LIBS DISABLE_PIE=yes include Config @@ -75,24 +74,41 @@ COMMON_SRC = alloc.c backtrace.c breakpoint.c coalesce.c coreparse.c \ dynbind.c funcall.c gc-common.c globals.c hopscotch.c \ interr.c interrupt.c largefile.c main.c \ monitor.c murmur_hash.c os-common.c parse.c print.c \ - purify.c pthread-futex.c regnames.c run-program.c runtime.c \ - safepoint.c save.c sc-offset.c search.c thread.c time.c \ + regnames.c runtime.c safepoint.c save.c \ + sc-offset.c search.c stringspace.c thread.c time.c \ validate.c var-io.c vars.c wrap.c +ifndef LISP_FEATURE_WIN32 +COMMON_SRC += run-program.c sprof.c +endif + +ifdef LISP_FEATURE_SB_PRELINK_LINKAGE_TABLE +COMMON_SRC += linkage-table-prelink-info.c +endif + C_SRC = $(COMMON_SRC) ${ARCH_SRC} ${OS_SRC} ${GC_SRC} SRCS = $(C_SRC) ${ASSEM_SRC} -OBJS = $(C_SRC:.c=.o) $(ASSEM_SRC:.S=.o) +OBJS = $(C_SRC:.c=.o) $(ASSEM_SRC:.S=.o) ../../tlsf-bsd/tlsf/tlsf.o -LIBS = ${OS_LIBS} -lm +# "Commas ... cannot appear in the text of an argument as written" +comma := , -ifdef LISP_FEATURE_SUNOS # don't bother running 'nm' (or 'gnm') -targets: $(TARGET) $(OBJTARGET) sbcl.mk +ifeq ($(or $(LISP_FEATURE_OS_PROVIDES_DLOPEN),$(LISP_FEATURE_OS_PROVIDES_DLADDR)),1) +LIBS = ${OS_LIBS} $(LDLIBS) -lm else -targets: $(TARGET) $(OBJTARGET) sbcl.nm sbcl.mk +LIBS = $(filter-out -ldl,$(filter-out -Wl$(comma)-no-as-needed,$(OS_LIBS))) $(LDLIBS) -lm endif +targets: $(TARGET) $(OBJTARGET) sbcl.mk + +LDB_OBJS = $(filter-out main.o runtime.o monitor.o save.o thread.o,$(OBJS)) +ldb: $(LIBSBCL) + $(CC) -g $(CPPFLAGS) $(CFLAGS) -DSTANDALONE_LDB -c -o standalone-monitor.o monitor.c + $(CC) -g $(CPPFLAGS) $(CFLAGS) -DSTANDALONE_LDB -c -o standalone-thread.o thread.c + $(CC) $(LINKFLAGS) -o ldb standalone-monitor.o standalone-thread.o $(LDB_OBJS) $(LIBS) + $(TARGET): $(LIBSBCL) $(CC) ${LINKFLAGS} -o $@ $(USE_LIBSBCL) $(LIBS) $(SBCL_PAXCTL) $@ @@ -104,9 +120,9 @@ heap-reloc-test: ../../tests/heap-reloc/fake-mman.c $(OBJS) # Enable compiling gencgc with even more assertions and/or # data collection, with COMPILING_TESTS. Not really used yet. -gc-unit-tests.o: CFLAGS=-DCOMPILING_TESTS +gc-unit-tests.o: CFLAGS=-g -DCOMPILING_TESTS unit-tests: gc-unit-tests.o libsbcl.a - cc -g -no-pie -o $@ $^ -ldl -lpthread -lm + $(CC) -g -no-pie -o $@ $^ -ldl -lpthread -lm # ld -r -o sbcl.o works on Linux, but not on other platforms. # On macOS, it fails to keep debug sections. @@ -114,19 +130,21 @@ unit-tests: gc-unit-tests.o libsbcl.a sbcl.o: $(OBJS) $(LD) $(__LDFLAGS__) -r -o $@ $^ +linkage-table-prelink-info.o: linkage-table-prelink-info.c + $(CC) $(CFLAGS) $(CPPFLAGS) -Wno-builtin-declaration-mismatch -c -o $@ $< + libsbcl.a: $(OBJS) rm -f $@ ; ar rcs $@ $^ PIC_OBJS = $(subst .o,.pic.o,$(OBJS)) libsbcl.so: $(PIC_OBJS) - cc -shared -o $@ $^ $(LIBS) + $(CC) -shared -o $@ $^ $(LIBS) # for this to work, you must have with-gcc-tls in your build features already. # can't define it here because then it conflicts if you have it in both places. %.pic.o: %.c - $(CC) -fPIC -c $(filter-out -fno-pie,$(CFLAGS)) $< -o $@ + $(CC) -fPIC -c $(CPPFLAGS) $(filter-out -fno-pie,$(CFLAGS)) $< -o $@ %.pic.o: %.S # (-fPIC doesn't affect hand-written assembly source) - $(CC) -c $(CFLAGS) $< -o $@ -testmain: testmain.c libsbcl.so -ldl + $(CC) -c $(CPPFLAGS) $(CFLAGS) $< -o $@ SHRINKWRAP_DEPS = ../../output/sbcl.core ../../tools-for-build/editcore.lisp shrinkwrap-sbcl.s shrinkwrap-sbcl-core.o: $(SHRINKWRAP_DEPS) @@ -135,10 +153,16 @@ shrinkwrap-sbcl.s shrinkwrap-sbcl-core.o: $(SHRINKWRAP_DEPS) pie-shrinkwrap-sbcl.s pie-shrinkwrap-sbcl-core.o: $(SHRINKWRAP_DEPS) ../../run-sbcl.sh --script ../../tools-for-build/editcore.lisp split --pie \ ../../output/sbcl.core pie-shrinkwrap-sbcl.s -comma := , # "Commas ... cannot appear in the text of an argument as written" +# "Commas ... cannot appear in the text of an argument as written" +# There can not be any space after the comma on the next line, +# or else it becomes part of the expansion of $(comma) +comma := , shrinkwrap-sbcl: shrinkwrap-sbcl.s shrinkwrap-sbcl-core.o $(LIBSBCL) $(CC) -no-pie $(filter-out -Wl$(comma)--export-dynamic, $(LINKFLAGS)) \ $(CFLAGS) -o $@ $^ $(LIBS) +static-shrinkwrap-sbcl: shrinkwrap-sbcl.s shrinkwrap-sbcl-core.o $(LIBSBCL) + $(CC) -no-pie -static $(filter-out -Wl$(comma)--export-dynamic, $(LINKFLAGS)) \ + $(CFLAGS) -o $@ $^ $(LIBS) pie-shrinkwrap-sbcl: pie-shrinkwrap-sbcl.s pie-shrinkwrap-sbcl-core.o $(PIC_OBJS) $(CC) -pie -o $@ $^ $(LIBS) semiwrap-sbcl: shrinkwrap-sbcl.s $(LIBSBCL) @@ -159,10 +183,6 @@ sbcl.mk: Config fi ; \ : ) > $@ -sbcl.nm: $(TARGET) - $(NM) $(TARGET) | $(GREP) -v " [FUw] " > ,$@ - mv -f ,$@ $@ - sbcl.h: $(wildcard genesis/*.h) echo '#include "genesis/config.h"' >sbcl.h echo '#include "genesis/constants.h"' >>sbcl.h @@ -170,11 +190,12 @@ sbcl.h: $(wildcard genesis/*.h) # || true because we don't want the build to break if etags isn't there. # ...but it's still nice to have it done by default. HEADERS=$(wildcard *.h genesis/*.h) -TAGS tags: $(SRCS) $(HEADERS) - @etags $(SRCS) $(HEADERS) || true +INC=$(wildcard *.inc) +TAGS tags: $(SRCS) $(HEADERS) $(INC) + @etags --language=c $(SRCS) $(HEADERS) $(INC) || true clean: - -rm -f *.[do] $(TARGET) sbcl.nm sbcl.h core *.tmp $(OS_CLEAN_FILES) libsbcl.a shrinkwrap-sbcl* sbcl.mk + -rm -f *.[do] $(TARGET) ldb unit-tests sbcl.h core *.tmp libsbcl.a shrinkwrap-sbcl* sbcl.mk %.d: %.c sbcl.h @$(CC) $(DEPEND_FLAGS) $(CPPFLAGS) $< > $@.tmp; \ diff --git a/src/runtime/absl_glue.cc b/src/runtime/absl_glue.cc new file mode 100644 index 0000000000..09813caa82 --- /dev/null +++ b/src/runtime/absl_glue.cc @@ -0,0 +1,32 @@ +#include "absl/container/flat_hash_map.h" +#include "murmur_hash.h" + +typedef unsigned long lispobj; + +struct Hash { + size_t operator() (lispobj k) const { FMIX64(k); return k; } +}; + +typedef absl::flat_hash_map<lispobj,unsigned,Hash> inverted_heap; + +extern "C" { +void* new_absl_hashmap(int size) { + inverted_heap* hashmap = new inverted_heap; + hashmap->reserve(size); + return hashmap; +} +void absl_hashmap_destroy(inverted_heap* hashmap) { + delete hashmap; +} +unsigned absl_hashmap_get(inverted_heap* hashmap, lispobj key) { + return (*hashmap)[key]; +} +unsigned* absl_hashmap_get_ref(inverted_heap* hashmap, lispobj key) { + return &(*hashmap)[key]; +} +int absl_hashmap_size(inverted_heap* hashmap, int* capacity) { + *capacity = (*hashmap).bucket_count(); + return (*hashmap).size(); +} + +} diff --git a/src/runtime/alloc.c b/src/runtime/alloc.c index 56591a3689..dcff2986c8 100644 --- a/src/runtime/alloc.c +++ b/src/runtime/alloc.c @@ -16,56 +16,37 @@ #include "sbcl.h" #include "alloc.h" #include "thread.h" -#include "getallocptr.h" +#include "pseudo-atomic.h" #include "genesis/code.h" +lispobj* atomic_bump_static_space_free_ptr(int nbytes) +{ + gc_assert((nbytes & LOWTAG_MASK) == 0); + lispobj* claimed_ptr = static_space_free_pointer; + do { + lispobj* new = (lispobj*)((char*)claimed_ptr + nbytes); + // Fail if space exhausted or bogusly wrapped around + if (new > (lispobj*)STATIC_SPACE_END || new < claimed_ptr) return 0; + lispobj* actual_old = __sync_val_compare_and_swap(&static_space_free_pointer, + claimed_ptr, new); + if (actual_old == claimed_ptr) return claimed_ptr; + claimed_ptr = actual_old; + } while (1); +} + // Work space for the deterministic allocation profiler. // Only supported on x86-64, but the variables are always referenced // to reduce preprocessor conditionalization. os_vm_address_t alloc_profile_buffer; // array of counters static size_t profile_buffer_size; lispobj alloc_profile_data; // SIMPLE-VECTOR of <code-component,PC> -boolean alloc_profiling; // enabled flag +int alloc_profiling; // enabled flag -#ifdef LISP_FEATURE_GENCGC -#ifdef LISP_FEATURE_SB_THREAD -/* This lock is used to protect non-thread-local allocation. */ -static pthread_mutex_t allocation_lock = PTHREAD_MUTEX_INITIALIZER; +#ifdef LISP_FEATURE_WIN32 +CRITICAL_SECTION alloc_profiler_lock; // threads are mandatory for win32 +#elif defined LISP_FEATURE_SB_THREAD pthread_mutex_t alloc_profiler_lock = PTHREAD_MUTEX_INITIALIZER; #endif -lispobj alloc_code_object (unsigned total_words) -{ - struct thread *th = arch_os_get_current_thread(); -#if defined(LISP_FEATURE_X86_64) && !defined(LISP_FEATURE_WIN32) -# define REQUIRE_GC_INHIBIT 0 -#else -# define REQUIRE_GC_INHIBIT 1 -#endif -#if REQUIRE_GC_INHIBIT - /* It used to be that even on gencgc builds the - * ALLOCATE-CODE-OBJECT VOP did all this initialization within - * pseudo atomic. Here, we rely on gc being inhibited. */ - if (read_TLS(GC_INHIBIT, th) == NIL) - lose("alloc_code_object called with GC enabled."); -#endif - - /* Allocations of code are all serialized. We might also acquire - * free_pages_lock depending on availability of space in the region */ - int result = thread_mutex_lock(&allocation_lock); - gc_assert(!result); - struct code *code = (struct code *) - lisp_alloc(&gc_alloc_region[CODE_PAGE_TYPE-1], total_words*N_WORD_BYTES, - CODE_PAGE_TYPE, th); - result = thread_mutex_unlock(&allocation_lock); - gc_assert(!result); - - code->header = ((uword_t)total_words << CODE_HEADER_SIZE_SHIFT) | CODE_HEADER_WIDETAG; - code->boxed_size = 0; - code->debug_info = 0; - ((lispobj*)code)[total_words-1] = 0; // zeroize the simple-fun table count - return make_lispobj(code, OTHER_POINTER_LOWTAG); -} -#endif #include <stdio.h> #include "genesis/vector.h" @@ -80,11 +61,10 @@ unsigned int max_alloc_point_counters; void allocation_profiler_start() { - int __attribute__((unused)) ret = thread_mutex_lock(&alloc_profiler_lock); - gc_assert(ret == 0); + int __attribute__((unused)) ret = mutex_acquire(&alloc_profiler_lock); + gc_assert(ret); if (!alloc_profiling && simple_vector_p(alloc_profile_data)) { - max_alloc_point_counters = - fixnum_value(VECTOR(alloc_profile_data)->length)/2; + max_alloc_point_counters = vector_len(VECTOR(alloc_profile_data))/2; size_t size = N_WORD_BYTES * max_alloc_point_counters; os_vm_address_t old_buffer = 0; if (size != profile_buffer_size) { @@ -114,15 +94,16 @@ void allocation_profiler_start() "allocation profiler already started\n" : "profile metadata not created\n"); } - ret = thread_mutex_unlock(&alloc_profiler_lock); - gc_assert(ret == 0); + ret = mutex_release(&alloc_profiler_lock); + gc_assert(ret); + fflush(stdout); } // This is not exactly threadsafe. Don't try anything fancy. void allocation_profiler_stop() { - int __attribute__((unused)) ret = thread_mutex_lock(&alloc_profiler_lock); - gc_assert(ret == 0); + int __attribute__((unused)) ret = mutex_acquire(&alloc_profiler_lock); + gc_assert(ret); if (alloc_profiling) { alloc_profiling = 0; struct thread* th; @@ -132,8 +113,8 @@ void allocation_profiler_stop() } else { fprintf(stderr, "allocation profiler not started\n"); } - ret = thread_mutex_unlock(&alloc_profiler_lock); - gc_assert(ret == 0); + ret = mutex_release(&alloc_profiler_lock); + gc_assert(ret); #if 0 if (warning_issued) { fprintf(stderr, "allocation profile needed %d counters\n", @@ -142,3 +123,25 @@ void allocation_profiler_stop() } #endif } + +#ifdef LISP_FEATURE_METASPACE +#include "gc-private.h" +lispobj valid_metaspace_ptr_p(void* addr) +{ + struct slab_header* slab = (void*)ALIGN_DOWN((lispobj)addr, METASPACE_SLAB_SIZE); + fprintf(stderr, "slab base %p chunk_size %d capacity %d\n", slab, slab->chunksize, slab->capacity); + if (!slab->capacity) return 0; + lispobj slab_end = (lispobj)slab + METASPACE_SLAB_SIZE; + int index = (slab_end - (lispobj)addr) / slab->chunksize; + // for(int i=0; i<slab->capacity; ++i) fprint(stderr, "goober @ %p\n", slab_end - (1+i)*chunksize); + // fprintf(stderr, "index=%d\n", index); + if (index < slab->capacity) { + lispobj* obj_base = (lispobj*)(slab_end - (index+1)*slab->chunksize); + if (widetag_of(obj_base) == INSTANCE_WIDETAG) { + fprintf(stderr, "word @ %p is good\n", obj_base); + return (lispobj)obj_base; + } + } + return 0; +} +#endif diff --git a/src/runtime/alloc.h b/src/runtime/alloc.h index 4cb5488094..267314591b 100644 --- a/src/runtime/alloc.h +++ b/src/runtime/alloc.h @@ -17,15 +17,15 @@ #include "gc-internal.h" #include "genesis/sap.h" -#ifdef LISP_FEATURE_GENCGC -extern lispobj *lisp_alloc(struct alloc_region *region, sword_t nbytes, - int page_type_flag, struct thread *thread); -extern lispobj alloc_code_object(unsigned total_words); +#ifdef LISP_FEATURE_RISCV +# define SAP_ALIGN 32 /* this seems to do the trick */ +#else +# define SAP_ALIGN N_WORD_BYTES * 2 #endif #define DX_ALLOC_SAP(var_name, ptr) \ lispobj var_name; \ -struct sap _dx_##var_name __attribute__ ((aligned (N_WORD_BYTES * 2))); \ +struct sap _dx_##var_name __attribute__ ((aligned (SAP_ALIGN))); \ do { \ _dx_##var_name.header = (1 << 8) | SAP_WIDETAG; \ _dx_##var_name.pointer = (char *)(ptr); \ diff --git a/src/runtime/allocptr-c-symbol.inc b/src/runtime/allocptr-c-symbol.inc deleted file mode 100644 index a1cec6b0d3..0000000000 --- a/src/runtime/allocptr-c-symbol.inc +++ /dev/null @@ -1,34 +0,0 @@ -#ifdef LISP_FEATURE_CHENEYGC -#define set_alloc_pointer(value) dynamic_space_free_pointer = (lispobj*)(value) -#define get_alloc_pointer() (dynamic_space_free_pointer) -#endif - -#ifdef LISP_FEATURE_GENCGC -#define set_alloc_pointer(value) \ - (dynamic_space_free_pointer = \ - ((lispobj *) \ - ((value) | (((uword_t)dynamic_space_free_pointer) & LOWTAG_MASK)))) - -#define get_alloc_pointer() \ - ((uword_t) dynamic_space_free_pointer & ~LOWTAG_MASK) -#ifdef LISP_FEATURE_SB_THREAD -#include "pseudo-atomic.h" -#else -#define get_pseudo_atomic_atomic(thread) \ - ((uword_t)dynamic_space_free_pointer & flag_PseudoAtomic) -#define set_pseudo_atomic_atomic(thread) \ - (dynamic_space_free_pointer \ - = (lispobj*) ((uword_t)dynamic_space_free_pointer | flag_PseudoAtomic)) -#define clear_pseudo_atomic_atomic(thread) \ - (dynamic_space_free_pointer \ - = (lispobj*) ((uword_t) dynamic_space_free_pointer & ~flag_PseudoAtomic)) -#define get_pseudo_atomic_interrupted(thread) \ - ((uword_t) dynamic_space_free_pointer & flag_PseudoAtomicInterrupted) -#define clear_pseudo_atomic_interrupted(thread) \ - (dynamic_space_free_pointer \ - = (lispobj*) ((uword_t) dynamic_space_free_pointer & ~flag_PseudoAtomicInterrupted)) -#define set_pseudo_atomic_interrupted(thread) \ - (dynamic_space_free_pointer \ - = (lispobj*) ((uword_t) dynamic_space_free_pointer | flag_PseudoAtomicInterrupted)) -#endif -#endif diff --git a/src/runtime/allocptr-lisp-symbol.inc b/src/runtime/allocptr-lisp-symbol.inc deleted file mode 100644 index d5909118ab..0000000000 --- a/src/runtime/allocptr-lisp-symbol.inc +++ /dev/null @@ -1,49 +0,0 @@ -// ARM, AARCH64, and RISCV use a static-space lisp symbol for ALLOCATION_POINTER -#define set_alloc_pointer(value) SetSymbolValue(ALLOCATION_POINTER, value, 0) -#define get_alloc_pointer() (lispobj*)SymbolValue(ALLOCATION_POINTER, 0) - -#ifdef LISP_FEATURE_SB_THREAD -#include "pseudo-atomic.h" -#else -// unithread ARM, AARCH64, and RISCV use a static symbol for PSEUDO_ATOMIC_foo -static inline int -get_pseudo_atomic_atomic(struct thread *thread) -{ - return SymbolValue(PSEUDO_ATOMIC_ATOMIC, thread) != NIL; -} - -static inline void -set_pseudo_atomic_atomic(struct thread *thread) -{ - SetSymbolValue(PSEUDO_ATOMIC_ATOMIC, PSEUDO_ATOMIC_ATOMIC, thread); -} - -static inline void -clear_pseudo_atomic_atomic(struct thread *thread) -{ - SetSymbolValue(PSEUDO_ATOMIC_ATOMIC, NIL, thread); -} - -static inline int -get_pseudo_atomic_interrupted(struct thread *thread) -{ - return SymbolValue(PSEUDO_ATOMIC_INTERRUPTED, thread) != 0; -} - -static inline void -set_pseudo_atomic_interrupted(struct thread *thread) -{ - #ifndef DO_PENDING_INTERRUPT - // RISCV defines do_pending_interrupt as a lisp asm routine the address of which - // is stored in a static lisp symbol and which in C is obtained via #define. - extern void do_pending_interrupt(); - #endif - SetSymbolValue(PSEUDO_ATOMIC_INTERRUPTED, (lispobj)do_pending_interrupt, thread); -} - -static inline void -clear_pseudo_atomic_interrupted(struct thread *thread) -{ - SetSymbolValue(PSEUDO_ATOMIC_INTERRUPTED, 0, 0); -} -#endif diff --git a/src/runtime/allocptr-x86.inc b/src/runtime/allocptr-x86.inc deleted file mode 100644 index d9dba60888..0000000000 --- a/src/runtime/allocptr-x86.inc +++ /dev/null @@ -1,59 +0,0 @@ -#define set_alloc_pointer(value) dynamic_space_free_pointer = (lispobj*)(value) -#define get_alloc_pointer() (dynamic_space_free_pointer) - -#include "interr.h" // for lose() -#if defined(LISP_FEATURE_X86) -#define LISPOBJ_ASM_SUFFIX "l" -#elif defined(LISP_FEATURE_X86_64) -#define LISPOBJ_ASM_SUFFIX "q" -#endif - -#ifdef LISP_FEATURE_SB_THREAD -# define pa_bits thread->pseudo_atomic_bits -#else -# define pa_bits SYMBOL(PSEUDO_ATOMIC_BITS)->value -#endif - -static inline int -get_pseudo_atomic_atomic(struct thread __attribute__((unused)) *thread) -{ - // mask out the 'interrupted' bit before testing - return (pa_bits & ~1) != 0; -} - -static inline void -set_pseudo_atomic_atomic(struct thread __attribute__((unused)) *thread) -{ - if (pa_bits) lose("set_pseudo_atomic_atomic: bits=%"OBJ_FMTX, pa_bits); - __asm__ volatile ("or" LISPOBJ_ASM_SUFFIX " $~1, %0" : "+m" (pa_bits)); -} - -static inline void -clear_pseudo_atomic_atomic(struct thread __attribute__((unused)) *thread) -{ - __asm__ volatile ("and" LISPOBJ_ASM_SUFFIX " $1, %0" : "+m" (pa_bits)); -} - -static inline int -get_pseudo_atomic_interrupted(struct thread __attribute__((unused)) *thread) -{ - return pa_bits & 1; -} - -static inline void -set_pseudo_atomic_interrupted(struct thread *thread) -{ - if (!get_pseudo_atomic_atomic(thread)) - lose("set_pseudo_atomic_interrupted not in pseudo atomic"); - __asm__ volatile ("or" LISPOBJ_ASM_SUFFIX " $1, %0" : "+m" (pa_bits)); -} - -static inline void -clear_pseudo_atomic_interrupted(struct thread *thread) -{ - if (get_pseudo_atomic_atomic(thread)) - lose("clear_pseudo_atomic_interrupted in pseudo atomic"); - __asm__ volatile ("and" LISPOBJ_ASM_SUFFIX " $~1, %0" : "+m" (pa_bits)); -} -#undef pa_bits -#undef LISPOBJ_ASM_SUFFIX diff --git a/src/runtime/alpha-arch.c b/src/runtime/alpha-arch.c deleted file mode 100644 index 7002d20f41..0000000000 --- a/src/runtime/alpha-arch.c +++ /dev/null @@ -1,369 +0,0 @@ -/* - * This software is part of the SBCL system. See the README file for - * more information. - * - * This software is derived from the CMU CL system, which was - * written at Carnegie Mellon University and released into the - * public domain. The software is in the public domain and is - * provided with absolutely no warranty. See the COPYING and CREDITS - * files for more information. - */ - -/* Note that although superficially it appears that we use - * os_context_t like we ought to, we actually just assume its a - * ucontext in places. Naughty */ - -#include <stdio.h> -#include <string.h> - -#include "sbcl.h" -#include "runtime.h" -#include "globals.h" -#include "validate.h" -#include "os.h" -#include "arch.h" -#include "lispregs.h" -#include "signal.h" -#include "alloc.h" -#include "interrupt.h" -#include "interr.h" -#include "breakpoint.h" - -extern char call_into_lisp_LRA[], call_into_lisp_end[]; - -#define BREAKPOINT_INST 0x80 - - -void -arch_init(void) -{ - /* This must be called _after_ os_init(), so that we know what the - * page size is. */ - - if (mmap((os_vm_address_t) call_into_lisp_LRA_page,os_vm_page_size, - OS_VM_PROT_ALL,MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED,-1,0) - == (os_vm_address_t) -1) - perror("mmap"); - - /* call_into_lisp_LRA is a collection of trampolines written in asm - - * see alpha-assem.S. We copy it to call_into_lisp_LRA_page where - * VOPs and things can find it. (I don't know why they can't find it - * where it was to start with.) */ - bcopy(call_into_lisp_LRA,(void *)call_into_lisp_LRA_page,os_vm_page_size); - - os_flush_icache((os_vm_address_t)call_into_lisp_LRA_page, - os_vm_page_size); - return; -} - -os_vm_address_t -arch_get_bad_addr (int sig, siginfo_t *code, os_context_t *context) -{ - unsigned int badinst; - - /* Instructions are 32 bit quantities. */ - unsigned int *pc ; - /* fprintf(stderr,"arch_get_bad_addr %d %p %p\n", - sig, code, context); */ - pc= (unsigned int *)(*os_context_pc_addr(context)); - - if (((unsigned long)pc) & 3) { - return NULL; /* In what case would pc be unaligned?? */ - } - - if ( (pc < READ_ONLY_SPACE_START || - pc >= READ_ONLY_SPACE_START+READ_ONLY_SPACE_SIZE) && - (pc < current_dynamic_space || - pc >= current_dynamic_space + dynamic_space_size)) - return NULL; - - return context->uc_mcontext.sc_traparg_a0; -} - -void -arch_skip_instruction(os_context_t *context) -{ - /* This may be complete rubbish, as (at least for traps) pc points - * _after_ the instruction that caused us to be here anyway. - */ - char **pcptr; - pcptr = (char **) os_context_pc_addr(context); - *pcptr += 4; -} - -unsigned char * -arch_internal_error_arguments(os_context_t *context) -{ - return (unsigned char *)(*os_context_pc_addr(context)+4); -} - -boolean -arch_pseudo_atomic_atomic(os_context_t *context) -{ - /* FIXME: this foreign_function_call_active test is dubious at - * best. If a foreign call is made in a pseudo atomic section - * (?) or more likely a pseudo atomic section is in a foreign - * call then an interrupt is executed immediately. Maybe it - * has to do with C code not maintaining pseudo atomic - * properly. MG - 2005-08-10 - * - * The foreign_function_call_active used to live at each call-site - * to arch_pseudo_atomic_atomic, but this seems clearer. - * --NS 2007-05-15 */ - return (!foreign_function_call_active) - && ((*os_context_register_addr(context,reg_ALLOC)) & 1); -} - -void arch_set_pseudo_atomic_interrupted(os_context_t *context) -{ - /* On coming out of an atomic section, we subtract 1 from - * reg_Alloc, then try to store something at that address. So, - * to signal that it was interrupted and a signal should be handled, - * we set bit 63 of reg_ALLOC here so that the end-of-atomic code - * will raise SIGSEGV (no ram mapped there). We catch the signal - * (see the appropriate *-os.c) and call interrupt_handle_pending() - * for the saved signal instead */ - - *os_context_register_addr(context,reg_ALLOC) |= (1L<<63); -} - -void arch_clear_pseudo_atomic_interrupted(os_context_t *context) -{ - *os_context_register_addr(context, reg_ALLOC) &= ~(1L<<63); -} - -unsigned int arch_install_breakpoint(void *pc) -{ - unsigned int *ptr = (unsigned int *)pc; - unsigned int result = *ptr; - *ptr = BREAKPOINT_INST; - - os_flush_icache((os_vm_address_t)ptr, sizeof(unsigned int)); - - return result; -} - -void arch_remove_breakpoint(void *pc, unsigned int orig_inst) -{ - unsigned int *ptr = (unsigned int *)pc; - *ptr = orig_inst; - os_flush_icache((os_vm_address_t)pc, sizeof(unsigned int)); -} - -static unsigned int *skipped_break_addr, displaced_after_inst, - after_breakpoint; - - -/* This returns a PC value. Lisp code is all in the 32-bit-addressable - * space, so we should be ok with an unsigned int. */ -unsigned int -emulate_branch(os_context_t *context, unsigned int orig_inst) -{ - int op = orig_inst >> 26; - int reg_a = (orig_inst >> 21) & 0x1f; - int reg_b = (orig_inst >> 16) & 0x1f; - int disp = - (orig_inst&(1<<20)) ? - orig_inst | (-1 << 21) : - orig_inst&0x1fffff; - int next_pc = *os_context_pc_addr(context); - int branch = 0; /* was NULL; */ - - switch(op) { - case 0x1a: /* jmp, jsr, jsr_coroutine, ret */ - *os_context_register_addr(context,reg_a) = - *os_context_pc_addr(context); - *os_context_pc_addr(context) = - *os_context_register_addr(context,reg_b)& ~3; - break; - case 0x30: /* br */ - *os_context_register_addr(context,reg_a)=*os_context_pc_addr(context); - branch = 1; - break; - case 0x31: /* fbeq */ - if (*(os_context_float_register_addr(context,reg_a))==0) branch = 1; - break; - case 0x32: /* fblt */ - if (*os_context_float_register_addr(context,reg_a)<0) branch = 1; - break; - case 0x33: /* fble */ - if (*os_context_float_register_addr(context,reg_a)<=0) branch = 1; - break; - case 0x34: /* bsr */ - *os_context_register_addr(context,reg_a)=*os_context_pc_addr(context); - branch = 1; - break; - case 0x35: /* fbne */ - if (*os_context_register_addr(context,reg_a)!=0) branch = 1; - break; - case 0x36: /* fbge */ - if (*os_context_float_register_addr(context,reg_a)>=0) branch = 1; - break; - case 0x37: /* fbgt */ - if (*os_context_float_register_addr(context,reg_a)>0) branch = 1; - break; - case 0x38: /* blbc */ - if ((*os_context_register_addr(context,reg_a)&1) == 0) branch = 1; - break; - case 0x39: /* beq */ - if (*os_context_register_addr(context,reg_a)==0) branch = 1; - break; - case 0x3a: /* blt */ - if (*os_context_register_addr(context,reg_a)<0) branch = 1; - break; - case 0x3b: /* ble */ - if (*os_context_register_addr(context,reg_a)<=0) branch = 1; - break; - case 0x3c: /* blbs */ - if ((*os_context_register_addr(context,reg_a)&1)!=0) branch = 1; - break; - case 0x3d: /* bne */ - if (*os_context_register_addr(context,reg_a)!=0) branch = 1; - break; - case 0x3e: /* bge */ - if (*os_context_register_addr(context,reg_a)>=0) branch = 1; - break; - case 0x3f: /* bgt */ - if (*os_context_register_addr(context,reg_a)>0) branch = 1; - break; - } - if (branch) - next_pc += disp*4; - return next_pc; -} - -static sigset_t orig_sigmask; - -/* Perform the instruction that we overwrote with a breakpoint. As we - * don't have a single-step facility, this means we have to: - * - put the instruction back - * - put a second breakpoint at the following instruction, - * set after_breakpoint and continue execution. - * - * When the second breakpoint is hit (very shortly thereafter, we hope) - * sigtrap_handler gets called again, but follows the AfterBreakpoint - * arm, which - * - puts a bpt back in the first breakpoint place (running across a - * breakpoint shouldn't cause it to be uninstalled) - * - replaces the second bpt with the instruction it was meant to be - * - carries on - * - * Clear? - */ - -void arch_do_displaced_inst(os_context_t *context,unsigned int orig_inst) -{ - /* Apparent off-by-one errors ahoy. If you consult the Alpha ARM, - * it will tell you that after a BPT, the saved PC is the address - * of the instruction _after_ the instruction that caused the trap. - * - * However, we decremented PC by 4 before calling the Lisp-level - * handler that calls this routine (see alpha-arch.c line 322 and - * friends) so when we get to this point PC is actually pointing - * at the BPT instruction itself. This is good, because this is - * where we want to restart execution when we do that */ - - unsigned int *pc=(unsigned int *)(*os_context_pc_addr(context)); - unsigned int *next_pc; - int op = orig_inst >> 26;; - - orig_sigmask = *os_context_sigmask_addr(context); - sigaddset_blockable(os_context_sigmask_addr(context)); - - /* Put the original instruction back. */ - *pc = orig_inst; - os_flush_icache((os_vm_address_t)pc, sizeof(unsigned int)); - skipped_break_addr = pc; - - /* Figure out where we will end up after running the displaced - * instruction */ - if (op == 0x1a || (op&0xf) == 0x30) /* a branch */ - /* The cast to long is just to shut gcc up. */ - next_pc = (unsigned int *)((long)emulate_branch(context,orig_inst)); - else - next_pc = pc+1; - - /* Set the after breakpoint. */ - displaced_after_inst = *next_pc; - *next_pc = BREAKPOINT_INST; - after_breakpoint=1; - os_flush_icache((os_vm_address_t)next_pc, sizeof(unsigned int)); -} - -void -arch_handle_breakpoint(os_context_t *context) -{ - *os_context_pc_addr(context) -=4; - handle_breakpoint(context); -} - -void -arch_handle_fun_end_breakpoint(os_context_t *context) -{ - *os_context_pc_addr(context) -=4; - *os_context_pc_addr(context) = - (int)handle_fun_end_breakpoint(context); -} - -void -arch_handle_single_step_trap(os_context_t *context, int trap) -{ - unsigned int code = *((u32 *) (*os_context_pc_addr(context))); - int register_offset = code >> 8 & 0x1f; - handle_single_step_trap(context, trap, register_offset); - arch_skip_instruction(context); -} - -static void -sigtrap_handler(int signal, siginfo_t *siginfo, os_context_t *context) -{ - unsigned int code; - - /* this is different from how CMUCL does it. CMUCL used "call_pal - * PAL_gentrap", which doesn't do anything on Linux (unless NL0 - * contains certain specific values). We use "bugchk" instead. - * It's (for our purposes) just the same as bpt but has a - * different opcode so we can test whether we're dealing with a - * breakpoint or a "system service" */ - - if ((*(unsigned int*)(*os_context_pc_addr(context)-4))==BREAKPOINT_INST) { - if (after_breakpoint) { - /* see comments above arch_do_displaced_inst. This is where - * we reinsert the breakpoint that we removed earlier */ - - *os_context_pc_addr(context) -=4; - *skipped_break_addr = BREAKPOINT_INST; - os_flush_icache((os_vm_address_t)skipped_break_addr, - sizeof(unsigned int)); - skipped_break_addr = NULL; - *(unsigned int *)*os_context_pc_addr(context) = - displaced_after_inst; - os_flush_icache((os_vm_address_t)*os_context_pc_addr(context), sizeof(unsigned int)); - *os_context_sigmask_addr(context)= orig_sigmask; - after_breakpoint=0; /* false */ - return; - } else - code = trap_Breakpoint; - } else - /* a "system service" */ - code=*((u32 *)(*os_context_pc_addr(context))); - handle_trap(context, code); -} - -unsigned long -arch_get_fp_control() -{ - return ieee_get_fp_control(); -} - -void -arch_set_fp_control(unsigned long fp) -{ - ieee_set_fp_control(fp); -} - - -void arch_install_interrupt_handlers() -{ - undoably_install_low_level_interrupt_handler(SIGTRAP, sigtrap_handler); -} diff --git a/src/runtime/alpha-arch.h b/src/runtime/alpha-arch.h deleted file mode 100644 index dc7d726e57..0000000000 --- a/src/runtime/alpha-arch.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef _ALPHA_ARCH_H -#define _ALPHA_ARCH_H - -#define ALIEN_STACK_GROWS_DOWNWARD - -#endif /* _ALPHA_ARCH_H */ diff --git a/src/runtime/alpha-assem.S b/src/runtime/alpha-assem.S deleted file mode 100644 index 79a82ad7ab..0000000000 --- a/src/runtime/alpha-assem.S +++ /dev/null @@ -1,300 +0,0 @@ -/* - * This software is part of the SBCL system. See the README file for - * more information. - * - * This software is derived from the CMU CL system, which was - * written at Carnegie Mellon University and released into the - * public domain. The software is in the public domain and is - * provided with absolutely no warranty. See the COPYING and CREDITS - * files for more information. - */ - -#ifdef __ELF__ -// Mark the object as not requiring an executable stack. -.section .note.GNU-stack,"",%progbits -#endif - -#include "validate.h" -#include <alpha/regdef.h> -#ifdef linux -#include <asm/pal.h> -#else -#include <alpha/pal.h> -#endif -#include "sbcl.h" -#include "lispregs.h" -#include "genesis/fdefn.h" -#include "genesis/closure.h" -#include "genesis/code.h" -#include "genesis/funcallable-instance.h" -#include "genesis/simple-fun.h" -#include "genesis/static-symbols.h" - -/* #include "globals.h" */ - -/* - * Function to transfer control into lisp. - */ - .text - .align 4 - .globl call_into_lisp - .ent call_into_lisp -call_into_lisp: -#define framesize 8*8 - ldgp gp, 0($27) - /* Save all the C regs. */ - lda sp,-framesize(sp) - stq ra, framesize-8*8(sp) - stq s0, framesize-8*7(sp) - stq s1, framesize-8*6(sp) - stq s2, framesize-8*5(sp) - stq s3, framesize-8*4(sp) - stq s4, framesize-8*3(sp) - stq s5, framesize-8*2(sp) - stq s6, framesize-8*1(sp) - .mask 0x0fc001fe, -framesize - .frame sp,framesize,ra - - /* Clear descriptor regs */ - ldil reg_CODE,0 - ldil reg_FDEFN,0 - mov a0,reg_LEXENV - sll a2,2,reg_NARGS - ldil reg_OCFP,0 - ldil reg_LRA,0 - ldil reg_L0,0 - ldil reg_L1,0 - - - /* Establish NIL. */ - ldil reg_NULL,NIL - - /* The CMUCL comment here is "Start pseudo-atomic.", but */ - /* there's no obvious code that would have that effect */ - - /* No longer in foreign call. */ - stl zero,foreign_function_call_active - - /* Load lisp state. */ - ldq reg_ALLOC,dynamic_space_free_pointer - ldq reg_BSP,current_binding_stack_pointer - ldq reg_CSP,current_control_stack_pointer - ldq reg_OCFP,current_control_frame_pointer - mov a1,reg_CFP - - .set noat - ldil reg_L2,0 - .set at - - /* End of pseudo-atomic. */ - - /* Establish lisp arguments. */ - ldl reg_A0,0(reg_CFP) - ldl reg_A1,4(reg_CFP) - ldl reg_A2,8(reg_CFP) - ldl reg_A3,12(reg_CFP) - ldl reg_A4,16(reg_CFP) - ldl reg_A5,20(reg_CFP) - - /* This call will 'return' into the LRA page below */ - lda reg_LRA,call_into_lisp_LRA_page+OTHER_POINTER_LOWTAG - - /* Indirect the closure */ - ldl reg_CODE, CLOSURE_FUN_OFFSET(reg_LEXENV) - addl reg_CODE, SIMPLE_FUN_INSTS_OFFSET, reg_LIP - - /* And into lisp we go. */ - jsr reg_ZERO,(reg_LIP) - - - /* a page of the following code (from call_into_lisp_LRA - onwards) is copied into the LRA page at arch_init() time. */ - - .set noreorder - .align 3 - .globl call_into_lisp_LRA -call_into_lisp_LRA: - - .long RETURN_PC_WIDETAG - - /* execution resumes here*/ - mov reg_OCFP,reg_CSP - nop - - /* return value already there */ - mov reg_A0,v0 - - /* Turn on pseudo-atomic. */ - - /* Save LISP registers */ - stq reg_ALLOC, dynamic_space_free_pointer - stq reg_BSP,current_binding_stack_pointer - stq reg_CSP,current_control_stack_pointer - stq reg_CFP,current_control_frame_pointer - - /* Back in C land. [CSP is just a handy non-zero value.] */ - stl reg_CSP,foreign_function_call_active - - /* Turn off pseudo-atomic and check for traps. */ - - /* Restore C regs */ - ldq ra, framesize-8*8(sp) - ldq s0, framesize-8*7(sp) - ldq s1, framesize-8*6(sp) - ldq s2, framesize-8*5(sp) - ldq s3, framesize-8*4(sp) - ldq s4, framesize-8*3(sp) - ldq s5, framesize-8*2(sp) - ldq s6, framesize-8*1(sp) - - /* Restore the C stack! */ - lda sp, framesize(sp) - - ret zero,(ra),1 - .globl call_into_lisp_end -call_into_lisp_end: - .end call_into_lisp - -/* - * Transfering control from Lisp into C. reg_CFUNC (t10, 24) contains - * the address of the C function to call - */ - .set noreorder - .text - .align 4 - .globl call_into_c - .ent call_into_c -call_into_c: - .mask 0x0fc001fe, -12 - .frame sp,12,ra - mov reg_CFP, reg_OCFP - mov reg_CSP, reg_CFP - addq reg_CFP, 32, reg_CSP - stl reg_OCFP, 0(reg_CFP) - subl reg_LIP, reg_CODE, reg_L1 - addl reg_L1, OTHER_POINTER_LOWTAG, reg_L1 - stl reg_L1, 4(reg_CFP) - stl reg_CODE, 8(reg_CFP) - stl reg_NULL, 12(reg_CFP) - - /* Set the pseudo-atomic flag. */ - addq reg_ALLOC,1,reg_ALLOC - - /* Get the top two register args and fix the NSP to point to arg 7 */ - ldq reg_NL4,0(reg_NSP) - ldq reg_NL5,8(reg_NSP) - addq reg_NSP,16,reg_NSP - - /* Save lisp state. */ - subq reg_ALLOC,1,reg_L1 - stq reg_L1, dynamic_space_free_pointer - - stq reg_BSP, current_binding_stack_pointer - stq reg_CSP, current_control_stack_pointer - stq reg_CFP, current_control_frame_pointer - - /* Mark us as in C land. */ - stl reg_CSP, foreign_function_call_active - - /* Were we interrupted? */ - subq reg_ALLOC,1,reg_ALLOC - stl reg_ZERO,0(reg_ALLOC) - - /* Into C land we go. */ - - mov reg_CFUNC, reg_L1 /* L1=pv: this is a hint to the cache */ - - jsr ra, (reg_CFUNC) - ldgp $29,0(ra) - - /* restore NSP */ - subq reg_NSP,16,reg_NSP - - /* Clear unsaved descriptor regs */ - mov reg_ZERO, reg_NARGS - mov reg_ZERO, reg_A0 - mov reg_ZERO, reg_A1 - mov reg_ZERO, reg_A2 - mov reg_ZERO, reg_A3 - mov reg_ZERO, reg_A4 - mov reg_ZERO, reg_A5 - mov reg_ZERO, reg_L0 - .set noat - mov reg_ZERO, reg_L2 - .set at - - /* Turn on pseudo-atomic. */ - lda reg_ALLOC,1(reg_ZERO) - - /* Mark us at in Lisp land. */ - stl reg_ZERO, foreign_function_call_active - - /* Restore ALLOC, preserving pseudo-atomic-atomic */ - ldq reg_NL0,dynamic_space_free_pointer - addq reg_ALLOC,reg_NL0,reg_ALLOC - - /* Check for interrupt */ - subq reg_ALLOC,1,reg_ALLOC - stl reg_ZERO,0(reg_ALLOC) - - ldl reg_NULL, 12(reg_CFP) - - /* Restore LRA & CODE (they may have been GC'ed) */ - /* can you see anything here which touches LRA? I can't ...*/ - ldl reg_CODE, 8(reg_CFP) - ldl reg_NL0, 4(reg_CFP) - subq reg_NL0, OTHER_POINTER_LOWTAG, reg_NL0 - addq reg_CODE, reg_NL0, reg_NL0 - - mov reg_CFP, reg_CSP - mov reg_OCFP, reg_CFP - - ret zero, (reg_NL0), 1 - - .end call_into_c - - .text - .globl start_of_tramps -start_of_tramps: - - .text - .globl end_of_tramps -end_of_tramps: - - -/* - * fun-end breakpoint magic. - */ - -/* - * For an explanation of the magic involved in function-end - * breakpoints, see the implementation in ppc-assem.S. - */ - - .text - .align 2 - .set noreorder - .globl fun_end_breakpoint_guts -fun_end_breakpoint_guts: - .long (((CODE_SIZE+1)&~1)<<N_WIDETAG_BITS)|RETURN_PC_WIDETAG - br zero, fun_end_breakpoint_trap - nop - mov reg_CSP, reg_OCFP - addl reg_CSP, 4, reg_CSP - addl zero, 4, reg_NARGS - mov reg_NULL, reg_A1 - mov reg_NULL, reg_A2 - mov reg_NULL, reg_A3 - mov reg_NULL, reg_A4 - mov reg_NULL, reg_A5 -1: - - .globl fun_end_breakpoint_trap -fun_end_breakpoint_trap: - call_pal PAL_bugchk - .long trap_FunEndBreakpoint - br zero, fun_end_breakpoint_trap - - .globl fun_end_breakpoint_end -fun_end_breakpoint_end: - diff --git a/src/runtime/alpha-linux-os.c b/src/runtime/alpha-linux-os.c deleted file mode 100644 index 84a1b4b176..0000000000 --- a/src/runtime/alpha-linux-os.c +++ /dev/null @@ -1,103 +0,0 @@ -/* - * This is the Compaq/Digital Alpha Linux incarnation of - * arch-dependent OS-dependent routines. See also "linux-os.c". */ - -/* - * This software is part of the SBCL system. See the README file for - * more information. - * - * This software is derived from the CMU CL system, which was - * written at Carnegie Mellon University and released into the - * public domain. The software is in the public domain and is - * provided with absolutely no warranty. See the COPYING and CREDITS - * files for more information. - */ - -/* These header files were lifted wholesale from linux-os.c, some may - * be redundant. -- Dan Barlow ca. 2001-05-01 */ -#include <stdio.h> -#include <sys/param.h> -#include <sys/file.h> -#include "sbcl.h" -#include "./signal.h" -#include "os.h" -#include "arch.h" -#include "globals.h" -#include "interrupt.h" -#include "interr.h" -#include "lispregs.h" -#include <sys/socket.h> -#include <sys/utsname.h> - -#include <sys/types.h> -#include <signal.h> -#include <sys/time.h> -#include <sys/stat.h> -#include <unistd.h> -#include <asm/fpu.h> - -#include "validate.h" - -#ifdef LISP_FEATURE_SB_THREAD -#error "Define threading support functions" -#else -int arch_os_thread_init(struct thread *thread) { - return 1; /* success */ -} -int arch_os_thread_cleanup(struct thread *thread) { - return 1; /* success */ -} -#endif - - -os_context_register_t * -os_context_register_addr(os_context_t *context, int offset) -{ - return &context->uc_mcontext.sc_regs[offset]; -} - -os_context_register_t * -os_context_float_register_addr(os_context_t *context, int offset) -{ - return &context->uc_mcontext.sc_fpregs[offset]; -} - -os_context_register_t * -os_context_pc_addr(os_context_t *context) -{ - return &((context->uc_mcontext).sc_pc); -} - -sigset_t * -os_context_sigmask_addr(os_context_t *context) -{ - return &context->uc_sigmask; -} - -unsigned long -os_context_fp_control(os_context_t *context) -{ - return ieee_fpcr_to_swcr((context->uc_mcontext).sc_fpcr); -} - -void -os_restore_fp_control(os_context_t *context) -{ - /* FIXME: 0x7E0000 is defined as something useful in constants.h, - but without the UL, which would probably lead to 32/64-bit - errors if we simply used it here. Ugh. CSR, 2003-09-15 */ - arch_set_fp_control(os_context_fp_control(context) & ~(0x7e0000UL) & - /* KLUDGE: for some reason that I don't - understand, by the time we get here the - "enable denormalized traps" bit in the fp - control word is set. Since we really don't - want to tra every time someone types - LEAST-POSITIVE-SINGLE-FLOAT into the repl, - mask that bit out. -- CSR, 2003-09-15 */ - ~(0x1UL<<6)); -} - -void os_flush_icache(os_vm_address_t address, os_vm_size_t length) -{ - asm volatile ("imb" : : : "memory" ); -} diff --git a/src/runtime/alpha-linux-os.h b/src/runtime/alpha-linux-os.h deleted file mode 100644 index 0045a78095..0000000000 --- a/src/runtime/alpha-linux-os.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef _ALPHA_LINUX_OS_H -#define _ALPHA_LINUX_OS_H - -typedef ucontext_t os_context_t; -typedef long os_context_register_t; - -#include "arch-os-generic.inc" - -unsigned long os_context_fp_control(os_context_t *context); - -#endif /* _ALPHA_LINUX_OS_H */ diff --git a/src/runtime/alpha-lispregs.h b/src/runtime/alpha-lispregs.h deleted file mode 100644 index 24df43c54d..0000000000 --- a/src/runtime/alpha-lispregs.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * This software is part of the SBCL system. See the README file for - * more information. - * - * This software is derived from the CMU CL system, which was - * written at Carnegie Mellon University and released into the - * public domain. The software is in the public domain and is - * provided with absolutely no warranty. See the COPYING and CREDITS - * files for more information. - */ - -#define NREGS (32) - -#ifdef __ASSEMBLER__ -#ifdef linux -#define REG(num) $##num -#else -#define REG(num) $/**/num -#endif /* linux */ -#else -#define REG(num) num -#endif - /* "traditional" register name and use */ - /* courtesy of <alpha/regdef.h> */ -#define reg_LIP REG(0) /* v0 */ -#define reg_A0 REG(1) /* t0 - temporary (caller-saved) */ -#define reg_A1 REG(2) /* t1 */ -#define reg_A2 REG(3) /* t2 */ -#define reg_A3 REG(4) /* t3 */ -#define reg_A4 REG(5) /* t4 */ -#define reg_A5 REG(6) /* t5 */ -#define reg_L0 REG(7) /* t6 */ -#define reg_NARGS REG(8) /* t7 */ -#define reg_CSP REG(9) /* s0 - saved (callee-saved) */ -#define reg_CFP REG(10) /* s1 */ -#define reg_OCFP REG(11) /* s2 */ -#define reg_BSP REG(12) /* s3 */ -#define reg_LEXENV REG(13) /* s4 */ -#define reg_CODE REG(14) /* s5 */ -#define reg_NULL REG(15) /* s6 = fp (frame pointer) */ -#define reg_NL0 REG(16) /* a0 - argument (caller-saved) */ -#define reg_NL1 REG(17) /* a1 */ -#define reg_NL2 REG(18) /* a2 */ -#define reg_NL3 REG(19) /* a3 */ -#define reg_NL4 REG(20) /* a4 */ -#define reg_NL5 REG(21) /* a5 */ -#define reg_ALLOC REG(22) /* t8 - more temps (caller-saved) */ -#define reg_FDEFN REG(23) /* t9 */ -#define reg_CFUNC REG(24) /* t10 */ -#define reg_NFP REG(25) /* t11 */ -#define reg_LRA REG(26) /* ra - return address */ -#define reg_L1 REG(27) /* t12, or pv - procedure variable */ -#define reg_L2 REG(28) /* at - assembler temporary */ -#define reg_GP REG(29) /* global pointer */ -#define reg_NSP REG(30) /* sp - stack pointer */ -#define reg_ZERO REG(31) /* reads as zero, writes are noops */ - -#define call_into_lisp_LRA_page 0x10000 diff --git a/src/runtime/arch-os-generic.inc b/src/runtime/arch-os-generic.inc index 4170eb3101..0522c432b0 100644 --- a/src/runtime/arch-os-generic.inc +++ b/src/runtime/arch-os-generic.inc @@ -1,3 +1,5 @@ +/* -*- Mode: C -*- */ + static inline os_context_t *arch_os_get_context(void **void_context) { return (os_context_t *) *void_context; diff --git a/src/runtime/arch.h b/src/runtime/arch.h index 26f7f2269d..847cbdf6bf 100644 --- a/src/runtime/arch.h +++ b/src/runtime/arch.h @@ -49,6 +49,7 @@ extern lispobj funcall2(lispobj function, lispobj arg0, lispobj arg1); extern lispobj funcall3(lispobj function, lispobj arg0, lispobj arg1, lispobj arg2); extern lispobj *component_ptr_from_pc(char *pc); +extern lispobj *dynamic_space_code_from_pc(char *pc); #if defined(LISP_FEATURE_X86)||defined(LISP_FEATURE_X86_64) extern unsigned int * single_stepping; @@ -65,5 +66,6 @@ extern void arch_handle_single_step_trap(os_context_t *context, int trap); #endif extern void arch_write_linkage_table_entry(int index, void *target_addr, int datap); +extern void *arch_read_linkage_table_entry(int index, int datap); #endif /* __ARCH_H__ */ diff --git a/src/runtime/arm-arch.c b/src/runtime/arm-arch.c index 9984bf5c90..4438eb7bac 100644 --- a/src/runtime/arm-arch.c +++ b/src/runtime/arm-arch.c @@ -33,17 +33,12 @@ void arch_skip_instruction(os_context_t *context) { /* KLUDGE: Other platforms check for trap codes and skip inlined * trap/error parameters. We should too. */ - - /* Note that we're doing integer arithmetic here, not pointer. So - * the value that the return value of os_context_pc_addr() points - * to will be incremented by 4, not 16. - */ - *os_context_pc_addr(context) += 4; + OS_CONTEXT_PC(context) += 4; } unsigned char *arch_internal_error_arguments(os_context_t *context) { - return (unsigned char *)(*os_context_pc_addr(context) + 5); + return (unsigned char *)(OS_CONTEXT_PC(context) + 5); } boolean arch_pseudo_atomic_atomic(os_context_t *context) @@ -103,14 +98,13 @@ arch_handle_breakpoint(os_context_t *context) void arch_handle_fun_end_breakpoint(os_context_t *context) { - *os_context_pc_addr(context) = (int) handle_fun_end_breakpoint(context); + OS_CONTEXT_PC(context) = (int) handle_fun_end_breakpoint(context); } void arch_handle_single_step_trap(os_context_t *context, int trap) { - unsigned char register_offset = - *((unsigned char *)(*os_context_pc_addr(context))+5); + unsigned char register_offset = *(unsigned char *)(OS_CONTEXT_PC(context)+5); handle_single_step_trap(context, trap, register_offset); /* KLUDGE: arch_skip_instruction() only skips one instruction, and * there is a following word to deal with as well, so skip @@ -132,7 +126,7 @@ void arch_write_linkage_table_entry(int index, void *target_addr, int datap) { // allocate successive entries downward char *reloc_addr = - (char*)LINKAGE_TABLE_SPACE_END - (index + 1) * LINKAGE_TABLE_ENTRY_SIZE; + (char*)ALIEN_LINKAGE_TABLE_SPACE_END - (index + 1) * ALIEN_LINKAGE_TABLE_ENTRY_SIZE; if (datap) { *(unsigned long *)reloc_addr = (unsigned long)target_addr; return; @@ -169,3 +163,15 @@ void arch_write_linkage_table_entry(int index, void *target_addr, int datap) os_flush_icache((os_vm_address_t) reloc_addr, (char*) inst_ptr - reloc_addr); } + +void +*arch_read_linkage_table_entry(int index, int datap) +{ + char *reloc_addr = + (char *)ALIEN_LINKAGE_TABLE_SPACE_END - (index + 1) * ALIEN_LINKAGE_TABLE_ENTRY_SIZE; + if (datap) { + return (unsigned long*) *(unsigned long *)reloc_addr; + } + + return *(void**)((int*)reloc_addr+3); +} diff --git a/src/runtime/arm-arch.h b/src/runtime/arm-arch.h index f4c01872e4..8f07238a46 100644 --- a/src/runtime/arm-arch.h +++ b/src/runtime/arm-arch.h @@ -1,7 +1,6 @@ #ifndef _ARM_ARCH_H #define _ARM_ARCH_H -#define ALIEN_STACK_GROWS_DOWNWARD #define ARCH_HAS_LINK_REGISTER #endif /* _ARM_ARCH_H */ diff --git a/src/runtime/arm-assem.S b/src/runtime/arm-assem.S index b0b3730761..e118eb6eab 100644 --- a/src/runtime/arm-assem.S +++ b/src/runtime/arm-assem.S @@ -28,7 +28,7 @@ call_into_lisp: @@ All registers other than R0-R3 and R12 are callee-saves. @@ Save R3 to get 8-byte alignemnt. stmfd sp!, {r3-r11, lr} - fstmfdd sp!, {d8-d15} + vstmdb sp!, {d8-d15} @@ Start by finding NIL. ldr reg_NULL, .known_nil @@ -128,7 +128,7 @@ call_into_lisp: blxne reg_OCFP @@ Restore saved registers. - fldmfdd sp!, {d8-d15} + vldmia sp!, {d8-d15} ldmfd sp!, {r3-r11, lr} bx lr .size call_into_lisp, .-call_into_lisp @@ -287,7 +287,7 @@ fun_end_breakpoint_trap: fun_end_breakpoint_end: @@ FIXME: writing this as a lisp assembly routine would eliminate all the -@@ preprocessor noise. There's no reasom it can't be done, but we lack +@@ preprocessor noise. There's no reason it can't be done, but we lack @@ instruction encoders for: stmfd, ldmfd, stmea, ldmea, fstmfdd, fldfdd. #define DEFINE_TRAMPOLINE(name, entry) \ @@ -315,12 +315,12 @@ name: \ stmea r4, {r0-reg_LEXENV, r8} ;\ \ ldr r0, [sp, #4*4] ;\ - fstmfdd sp!, {d0-d7} ;\ + vstmdb sp!, {d0-d7} ;\ \ mov lr, pc ;\ ldr pc,=entry ;\ \ - fldmfdd sp!, {d0-d7} ;\ + vldmia sp!, {d0-d7} ;\ str r0, [sp, #4*4] ;\ ldr r4, STATIC_SYMBOL_VALUE(CONTROL_STACK_POINTER) ;\ ldmea r4, {r0-reg_LEXENV, r8} ;\ @@ -345,7 +345,7 @@ DEFINE_TRAMPOLINE(list_alloc_tramp, alloc_list) do_pending_interrupt: #if defined(LISP_FEATURE_LINUX) .word 0xe7f001f0 -#elif defined(LISP_FEATURE_NETBSD) +#elif defined(LISP_FEATURE_NETBSD) || defined(LISP_FEATURE_OPENBSD) .word 0xe7ffdefe #endif .byte trap_PendingInterrupt diff --git a/src/runtime/arm-bsd-os.c b/src/runtime/arm-bsd-os.c index b91a9278bd..2c630b5b87 100644 --- a/src/runtime/arm-bsd-os.c +++ b/src/runtime/arm-bsd-os.c @@ -25,9 +25,6 @@ #include "interrupt.h" #include "interr.h" #include "lispregs.h" -#include <sys/socket.h> -#include <sys/utsname.h> -#include <machine/sysarch.h> #include <sys/types.h> #include <signal.h> @@ -60,6 +57,8 @@ int arch_os_thread_cleanup(struct thread *thread) { } #endif +#if defined(LISP_FEATURE_NETBSD) + os_context_register_t * os_context_register_addr(os_context_t *context, int offset) { @@ -71,24 +70,58 @@ os_context_register_addr(os_context_t *context, int offset) return &context->uc_mcontext.__gregs[offset]; } -os_context_register_t * -os_context_pc_addr(os_context_t *context) +#elif defined(LISP_FEATURE_OPENBSD) + +os_context_register_t * +os_context_register_addr(os_context_t *context, int offset) { - return os_context_register_addr(context, reg_PC); + switch (offset) { + case 0: return (os_context_register_t *)(&context->sc_r0); + case 1: return (os_context_register_t *)(&context->sc_r1); + case 2: return (os_context_register_t *)(&context->sc_r2); + case 3: return (os_context_register_t *)(&context->sc_r3); + case 4: return (os_context_register_t *)(&context->sc_r4); + case 5: return (os_context_register_t *)(&context->sc_r5); + case 6: return (os_context_register_t *)(&context->sc_r6); + case 7: return (os_context_register_t *)(&context->sc_r7); + case 8: return (os_context_register_t *)(&context->sc_r8); + case 9: return (os_context_register_t *)(&context->sc_r9); + case 10: return (os_context_register_t *)(&context->sc_r10); + case 11: return (os_context_register_t *)(&context->sc_r11); + case 12: return (os_context_register_t *)(&context->sc_r12); + case reg_NSP: return (os_context_register_t *)(&context->sc_usr_sp); + case reg_LR: return (os_context_register_t *)(&context->sc_usr_lr); + case reg_PC: return (os_context_register_t *)(&context->sc_pc); + } + lose("illegal register number: %d", offset); } +#endif + os_context_register_t * os_context_lr_addr(os_context_t *context) { return os_context_register_addr(context, reg_LR); } +#if defined(LISP_FEATURE_OPENBSD) + +void +os_restore_fp_control(os_context_t *context) +{ + asm ("fmxr fpscr,%0" : : "r" (context->sc_fpscr)); +} + +#else + void os_restore_fp_control(os_context_t *context) { /* FIXME: Implement. */ } +#endif + void os_flush_icache(os_vm_address_t address, os_vm_size_t length) { @@ -98,8 +131,8 @@ os_flush_icache(os_vm_address_t address, os_vm_size_t length) static void sigtrap_handler(int signal, siginfo_t *siginfo, os_context_t *context) { - unsigned int code = *((unsigned char *)(4+*os_context_pc_addr(context))); - u32 trap_instruction = *((u32 *)*os_context_pc_addr(context)); + unsigned int code = *((unsigned char *)(4+OS_CONTEXT_PC(context))); + uint32_t trap_instruction = *(uint32_t *)OS_CONTEXT_PC(context); if (trap_instruction != 0xe7ffdefe) { lose("Unrecognized trap instruction %08lx in sigtrap_handler()", @@ -115,5 +148,5 @@ sigtrap_handler(int signal, siginfo_t *siginfo, os_context_t *context) void arch_install_interrupt_handlers() { - undoably_install_low_level_interrupt_handler(SIGTRAP, sigtrap_handler); + ll_install_handler(SIGTRAP, sigtrap_handler); } diff --git a/src/runtime/arm-bsd-os.h b/src/runtime/arm-bsd-os.h index a9178dba0c..63e9e77735 100644 --- a/src/runtime/arm-bsd-os.h +++ b/src/runtime/arm-bsd-os.h @@ -9,4 +9,10 @@ unsigned long os_context_fp_control(os_context_t *context); #define RESTORE_FP_CONTROL_FROM_CONTEXT void os_restore_fp_control(os_context_t *context); +#ifdef LISP_FEATURE_NETBSD +# define OS_CONTEXT_PC(context) context->uc_mcontext.__gregs[reg_PC] +#elif defined LISP_FEATURE_OPENBSD +# define OS_CONTEXT_PC(context) context->sc_pc +#endif + #endif /* _ARM_BSD_OS_H */ diff --git a/src/runtime/arm-linux-os.c b/src/runtime/arm-linux-os.c index 1baffa5d48..3c814ae7bc 100644 --- a/src/runtime/arm-linux-os.c +++ b/src/runtime/arm-linux-os.c @@ -25,8 +25,6 @@ #include "interrupt.h" #include "interr.h" #include "lispregs.h" -#include <sys/socket.h> -#include <sys/utsname.h> #include <sys/types.h> #include <signal.h> @@ -70,12 +68,6 @@ os_context_register_addr(os_context_t *context, int offset) return (os_context_register_t*)&(&context->uc_mcontext.arm_r0)[offset]; } -os_context_register_t * -os_context_pc_addr(os_context_t *context) -{ - return os_context_register_addr(context, reg_PC); -} - os_context_register_t * os_context_lr_addr(os_context_t *context) { @@ -105,8 +97,8 @@ os_flush_icache(os_vm_address_t address, os_vm_size_t length) static void sigtrap_handler(int signal, siginfo_t *siginfo, os_context_t *context) { - unsigned int code = *((unsigned char *)(4+*os_context_pc_addr(context))); - u32 trap_instruction = *((u32 *)*os_context_pc_addr(context)); + unsigned int code = *((unsigned char *)(4+OS_CONTEXT_PC(context))); + uint32_t trap_instruction = *(uint32_t *)OS_CONTEXT_PC(context); if (trap_instruction != 0xe7f001f0) { lose("Unrecognized trap instruction %08lx in sigtrap_handler()", @@ -122,5 +114,5 @@ sigtrap_handler(int signal, siginfo_t *siginfo, os_context_t *context) void arch_install_interrupt_handlers() { - undoably_install_low_level_interrupt_handler(SIGTRAP, sigtrap_handler); + ll_install_handler(SIGTRAP, sigtrap_handler); } diff --git a/src/runtime/arm-linux-os.h b/src/runtime/arm-linux-os.h index 1fa29d0650..7712f249d9 100644 --- a/src/runtime/arm-linux-os.h +++ b/src/runtime/arm-linux-os.h @@ -10,4 +10,6 @@ unsigned long os_context_fp_control(os_context_t *context); #define RESTORE_FP_CONTROL_FROM_CONTEXT void os_restore_fp_control(os_context_t *context); +#define OS_CONTEXT_PC(context) context->uc_mcontext.arm_pc + #endif /* _ARM_LINUX_OS_H */ diff --git a/src/runtime/arm64-arch.c b/src/runtime/arm64-arch.c index c68b98ff0b..89f64e729e 100644 --- a/src/runtime/arm64-arch.c +++ b/src/runtime/arm64-arch.c @@ -23,7 +23,7 @@ #include "interr.h" #include "breakpoint.h" #include "monitor.h" -#include "getallocptr.h" +#include "pseudo-atomic.h" os_vm_address_t arch_get_bad_addr(int sig, siginfo_t *code, os_context_t *context) { @@ -32,9 +32,9 @@ os_vm_address_t arch_get_bad_addr(int sig, siginfo_t *code, os_context_t *contex void arch_skip_instruction(os_context_t *context) { - u32 trap_instruction = *((u32 *)*os_context_pc_addr(context)); + uint32_t trap_instruction = *(uint32_t *)OS_CONTEXT_PC(context); unsigned code = trap_instruction >> 5 & 0xFF; - *os_context_pc_addr(context) += 4; + OS_CONTEXT_PC(context) += 4; switch (code) { case trap_Error: @@ -47,7 +47,7 @@ void arch_skip_instruction(os_context_t *context) unsigned char *arch_internal_error_arguments(os_context_t *context) { - return (unsigned char *)*os_context_pc_addr(context); + return (unsigned char *)OS_CONTEXT_PC(context); } boolean arch_pseudo_atomic_atomic(os_context_t *context) @@ -63,7 +63,7 @@ boolean arch_pseudo_atomic_atomic(os_context_t *context) * to arch_pseudo_atomic_atomic, but this seems clearer. * --NS 2007-05-15 */ #ifdef LISP_FEATURE_GENCGC - return get_pseudo_atomic_atomic(arch_os_get_current_thread()); + return get_pseudo_atomic_atomic(get_sb_vm_thread()); #else return (!foreign_function_call_active) && (NIL != SymbolValue(PSEUDO_ATOMIC_ATOMIC,0)); @@ -72,12 +72,12 @@ boolean arch_pseudo_atomic_atomic(os_context_t *context) void arch_set_pseudo_atomic_interrupted(os_context_t *context) { - set_pseudo_atomic_interrupted(arch_os_get_current_thread()); + set_pseudo_atomic_interrupted(get_sb_vm_thread()); } void arch_clear_pseudo_atomic_interrupted(os_context_t *context) { - clear_pseudo_atomic_interrupted(arch_os_get_current_thread()); + clear_pseudo_atomic_interrupted(get_sb_vm_thread()); } unsigned int arch_install_breakpoint(void *pc) @@ -106,7 +106,7 @@ arch_handle_breakpoint(os_context_t *context) void arch_handle_fun_end_breakpoint(os_context_t *context) { - *os_context_pc_addr(context) = (int) handle_fun_end_breakpoint(context); + OS_CONTEXT_PC(context) = (uword_t) handle_fun_end_breakpoint(context); } void @@ -119,11 +119,11 @@ arch_handle_single_step_trap(os_context_t *context, int trap) static void sigtrap_handler(int signal, siginfo_t *siginfo, os_context_t *context) { - u32 trap_instruction = *((u32 *)*os_context_pc_addr(context)); + uint32_t trap_instruction = *(uint32_t *)OS_CONTEXT_PC(context); unsigned code = trap_instruction >> 5 & 0xFF; if ((trap_instruction >> 21) != 0x6A1) { - lose("Unrecognized trap instruction %08lx in sigtrap_handler() (PC: %p)", - trap_instruction, *os_context_pc_addr(context)); + lose("Unrecognized trap instruction %08x in sigtrap_handler() (PC: %p)", + trap_instruction, (void*)OS_CONTEXT_PC(context)); } handle_trap(context, code); @@ -131,13 +131,13 @@ sigtrap_handler(int signal, siginfo_t *siginfo, os_context_t *context) void sigill_handler(int signal, siginfo_t *siginfo, os_context_t *context) { fake_foreign_function_call(context); - lose("Unhandled SIGILL at %p.", *os_context_pc_addr(context)); + lose("Unhandled SIGILL at %p.", (void*)OS_CONTEXT_PC(context)); } void arch_install_interrupt_handlers() { - undoably_install_low_level_interrupt_handler(SIGTRAP, sigtrap_handler); - undoably_install_low_level_interrupt_handler(SIGILL, sigill_handler); + ll_install_handler(SIGTRAP, sigtrap_handler); + ll_install_handler(SIGILL, sigill_handler); } @@ -150,10 +150,12 @@ void arch_install_interrupt_handlers() void arch_write_linkage_table_entry(int index, void *target_addr, int datap) { - char *reloc_addr = (char*)LINKAGE_TABLE_SPACE_START + index * LINKAGE_TABLE_ENTRY_SIZE; + THREAD_JIT(0); + char *reloc_addr = (char*)ALIEN_LINKAGE_TABLE_SPACE_START + index * ALIEN_LINKAGE_TABLE_ENTRY_SIZE; + if (datap) { *(unsigned long *)reloc_addr = (unsigned long)target_addr; - return; + goto DONE; } /* ldr reg,=address @@ -177,4 +179,18 @@ void arch_write_linkage_table_entry(int index, void *target_addr, int datap) *(unsigned long *)inst_ptr++ = (unsigned long)target_addr; os_flush_icache((os_vm_address_t) reloc_addr, (char*) inst_ptr - reloc_addr); + + DONE: + THREAD_JIT(1); +} + +void +*arch_read_linkage_table_entry(int index, int datap) +{ + char *reloc_addr = (char*)ALIEN_LINKAGE_TABLE_SPACE_START + index * ALIEN_LINKAGE_TABLE_ENTRY_SIZE; + if (datap) { + return (unsigned long*) *(unsigned long *)reloc_addr; + } + + return *(void**)((int*)reloc_addr+2); } diff --git a/src/runtime/arm64-arch.h b/src/runtime/arm64-arch.h index 9e9546770a..731c402492 100644 --- a/src/runtime/arm64-arch.h +++ b/src/runtime/arm64-arch.h @@ -1,7 +1,6 @@ #ifndef _ARM64_ARCH_H #define _ARM64_ARCH_H -#define ALIEN_STACK_GROWS_DOWNWARD #define ARCH_HAS_LINK_REGISTER #endif /* _ARM64_ARCH_H */ diff --git a/src/runtime/arm64-assem.S b/src/runtime/arm64-assem.S index 07b4db3d03..863e341a5d 100644 --- a/src/runtime/arm64-assem.S +++ b/src/runtime/arm64-assem.S @@ -1,6 +1,7 @@ #include "globals.h" #include "lispregs.h" #include "sbcl.h" +#include "validate.h" #include "genesis/closure.h" #include "genesis/funcallable-instance.h" @@ -18,6 +19,33 @@ #endif +#ifdef LISP_FEATURE_DARWIN +#define GNAME(var) _##var +#else +#define GNAME(var) var +#endif + +#ifdef LISP_FEATURE_DARWIN +#define TYPE(name) +#define SIZE(name) +#else +#define TYPE(name) .type name,%function +#define SIZE(name) .size name,.-name +#endif + +#ifdef LISP_FEATURE_SB_THREAD +.macro ENTER_PA + str reg_wNULL,[reg_THREAD,THREAD_PSEUDO_ATOMIC_BITS_OFFSET] +.endm + +.macro LEAVE_PA + str wzr,[reg_THREAD,THREAD_PSEUDO_ATOMIC_BITS_OFFSET] + ldr reg_wTMP,[reg_THREAD,THREAD_PSEUDO_ATOMIC_BITS_OFFSET+4] + cbz reg_wTMP,1f + brk trap_PendingInterrupt +1: +.endm +#else #define LOAD_STATIC_SYMBOL_VALUE(value,sym) \ mov reg_TMP,((sym)-NIL+SYMBOL_VALUE_OFFSET) ;\ ldr value,[reg_NULL, reg_TMP] @@ -25,16 +53,6 @@ #define STORE_STATIC_SYMBOL_VALUE(value,sym) \ mov reg_TMP,((sym)-NIL+SYMBOL_VALUE_OFFSET) ;\ str value,[reg_NULL, reg_TMP] -#ifdef LISP_FEATURE_SB_THREAD - #define ENTER_PA \ - str reg_wNULL,[reg_THREAD,THREAD_PSEUDO_ATOMIC_BITS_OFFSET] -#define LEAVE_PA \ - str wzr,[reg_THREAD,THREAD_PSEUDO_ATOMIC_BITS_OFFSET] ;\ - ldr reg_wTMP,[reg_THREAD,THREAD_PSEUDO_ATOMIC_BITS_OFFSET+4] ;\ - cbz reg_wTMP,1f ;\ - brk trap_PendingInterrupt ;\ -1: -#else #define ENTER_PA \ STORE_STATIC_SYMBOL_VALUE(reg_CFP,PSEUDO_ATOMIC_ATOMIC) @@ -49,10 +67,40 @@ /* the CSP page sits right before the thread */ # define THREAD_SAVED_CSP_OFFSET (-N_WORD_BYTES) #endif - .align - .global call_into_lisp - .type call_into_lisp, %function -call_into_lisp: + + +#ifdef LISP_FEATURE_OS_THREAD_STACK + .align 2 + .global GNAME(funcall1_switching_stack) + TYPE(funcall1_switching_stack) +GNAME(funcall1_switching_stack): + /* The arguments are switched, funcall1_switching_stack(arg, function) + to avoid shuffling registers + */ + /* save FP and LR to old stack */ + stp x29, x30, [sp, #-16]! + mov x29, sp + /* switch to new stack */ + ldr x9, [x0, #THREAD_ALIEN_STACK_START_OFFSET] + add x9, x9, #ALIEN_STACK_SIZE >> 12, lsl #12 +#if ALIEN_STACK_SIZE % 0x1000 != 0 + add x9, x9, #ALIEN_STACK_SIZE & 0xfff +#endif + sub sp, x9, #16 + /* call function */ + blr x1 + /* restore old SP, FP, LR and return */ + add sp, x29, #16 + ldp x29, x30, [x29] + ret + SIZE(funcall1_switching_stack) +#endif + + + .align 2 + .global GNAME(call_into_lisp) + TYPE(call_into_lisp) +GNAME(call_into_lisp): // At this point, we have: // X0 - function // X1 - pointer to args @@ -88,12 +136,21 @@ call_into_lisp: #ifdef LISP_FEATURE_SB_THREAD #ifdef LISP_FEATURE_GCC_TLS +#ifdef LISP_FEATURE_DARWIN + + adrp x0, _current_thread@TLVPPAGE + ldr x0, [x0, _current_thread@TLVPPAGEOFF] + ldr x8, [x0] + blr x8 + ldr reg_THREAD, [x0] +#else adrp x0, :gottprel:current_thread ldr x0, [x0, #:gottprel_lo12:current_thread] mrs reg_THREAD, tpidr_el0 ldr reg_THREAD, [reg_THREAD,x0] +#endif #else - ldr x0, specials + ldr x0, current_thread bl pthread_getspecific mov reg_THREAD, x0 #endif @@ -111,16 +168,21 @@ call_into_lisp: mov reg_R6, #0 mov reg_R7, #0 mov reg_R8, #0 +#ifndef LISP_FEATURE_DARWIN + mov reg_R10,#0 +#ifndef LISP_FEATURE_SB_THREAD + mov reg_R11,#0 +#endif +#endif - mov reg_CODE, #0 // Find the lisp stack and frame pointers. We're allocating a // new lisp stack frame, so load the stack pointer into CFP. #ifdef LISP_FEATURE_SB_THREAD ldp reg_OCFP,reg_CFP, [reg_THREAD, THREAD_CONTROL_FRAME_POINTER_OFFSET] #else - ldr reg_OCFP, =current_control_frame_pointer - ldr reg_CFP, =current_control_stack_pointer + ldr reg_OCFP, =GNAME(current_control_frame_pointer) + ldr reg_CFP, =GNAME(current_control_stack_pointer) ldr reg_OCFP, [reg_OCFP] ldr reg_CFP, [reg_CFP] #endif @@ -128,9 +190,9 @@ call_into_lisp: // Clear FFCA, so the runtime knows that we're "in lisp". #ifdef LISP_FEATURE_SB_THREAD - str xzr,[reg_THREAD, THREAD_FOREIGN_FUNCTION_CALL_ACTIVE_OFFSET] + str xzr,[reg_THREAD, THREAD_CONTROL_STACK_POINTER_OFFSET] #else - ldr reg_NL3, =foreign_function_call_active + ldr reg_NL3, =GNAME(foreign_function_call_active) str xzr, [reg_NL3] #endif // We need to set up the lisp stack pointer and the basics of @@ -145,10 +207,6 @@ call_into_lisp: // Set up the "frame link" str reg_OCFP, [reg_CFP] - // Set up the return address - ldr reg_NL3, =.lra - str reg_NL3, [reg_CFP, #8] - LEAVE_PA // Load our function args. @@ -166,15 +224,8 @@ no_args: // Load the closure-fun (or simple-fun-self), in case we're // trying to call a closure. - ldr reg_CODE, [reg_LEXENV, #CLOSURE_FUN_OFFSET] - - // And, finally, call into Lisp! - add reg_LR, reg_CODE, #SIMPLE_FUN_INSTS_OFFSET - br reg_LR - - .align 4 - .equ .lra, .+OTHER_POINTER_LOWTAG - .dword RETURN_PC_WIDETAG + ldr reg_LR, [reg_LEXENV, #CLOSURE_FUN_OFFSET] + blr reg_LR // Correct stack pointer for return processing. csel reg_CSP, reg_OCFP, reg_CSP, eq @@ -187,15 +238,14 @@ no_args: // Save the lisp stack and frame pointers. #ifdef LISP_FEATURE_SB_THREAD stp reg_CFP,reg_CSP, [reg_THREAD, THREAD_CONTROL_FRAME_POINTER_OFFSET] - str reg_CSP, [reg_THREAD, THREAD_FOREIGN_FUNCTION_CALL_ACTIVE_OFFSET] #else - ldr reg_NFP, =current_control_frame_pointer + ldr reg_NFP, =GNAME(current_control_frame_pointer) str reg_CFP, [reg_NFP] - ldr reg_OCFP, =current_control_stack_pointer + ldr reg_OCFP, =GNAME(current_control_stack_pointer) str reg_CSP, [reg_OCFP] // Set FFCA, so the runtime knows that we're not "in lisp". - ldr reg_OCFP, =foreign_function_call_active + ldr reg_OCFP, =GNAME(foreign_function_call_active) str reg_OCFP, [reg_OCFP] #endif @@ -217,74 +267,51 @@ no_args: ldp x19,x20, [sp],#160 ret - .size call_into_lisp, .-call_into_lisp + SIZE(call_into_lisp) - - .align - .global call_into_c - .type call_into_c, %function -call_into_c: +#ifdef LISP_FEATURE_SB_THREAD + .align 2 + .global GNAME(call_into_c) + TYPE(call_into_c) +GNAME(call_into_c): // At this point, we have: - // R8 -- C function to call. + // R9 -- C function to call. // LR -- Return address within the code component. // X0-X7 arguments // All other C arguments are already stashed on the C stack. - // We need to convert our return address to a GC-safe format, - // build a stack frame to count for the "foreign" frame, - // switch to C mode, move the register arguments to the - // correct locations, call the C function, move the result to - // the correct location, switch back to Lisp mode, tear down - // our stack frame, restore the return address, and return to - // our caller. - - sub reg_NARGS, reg_LR, reg_CODE - add reg_NFP, reg_NARGS, #OTHER_POINTER_LOWTAG - - // Build a Lisp stack frame. We need to stash our frame link, - // the code component, and our return offset. Frame link goes - // in slot 0 (OCFP-SAVE-OFFSET), the offset (a FIXNUM) goes in - // slot 1 (LRA-SAVE-OFFSET), and reg_CODE goes in slot 2. The - // debugger knows about this layout (see COMPUTE-CALLING-FRAME - // in SYS:SRC;CODE;DEBUG-INT.LISP). - add reg_CSP, reg_CSP, #4*8 - stp reg_CFP, reg_NFP, [reg_CSP, #-4*8] - str reg_CODE, [reg_CSP, #-2*8] - - ENTER_PA + // Build a Lisp stack frame. + // Can store two values above the stack pointer, interrupts ignore them. + stp reg_CFP, reg_LR, [reg_CSP] + add reg_R8, reg_CSP, #2*8 + mov reg_LEXENV, reg_LR // Save the lisp stack and frame pointers. #ifdef LISP_FEATURE_SB_THREAD - sub reg_TMP, reg_CSP, #4*8 - stp reg_TMP,reg_CSP, [reg_THREAD, THREAD_CONTROL_FRAME_POINTER_OFFSET] - str reg_CSP, [reg_THREAD, THREAD_FOREIGN_FUNCTION_CALL_ACTIVE_OFFSET] + stp reg_CSP, reg_R8, [reg_THREAD, THREAD_CONTROL_FRAME_POINTER_OFFSET] #else - ldr reg_NFP, =current_control_stack_pointer + ENTER_PA + ldr reg_NFP, =GNAME(current_control_stack_pointer) str reg_CSP, [reg_NFP] - ldr reg_NFP, =current_control_frame_pointer - sub reg_TMP, reg_CSP, #4*8 - str reg_TMP, [reg_NFP] + ldr reg_NFP, =GNAME(current_control_frame_pointer) + str reg_R8, [reg_NFP] // Set FFCA, so the runtime knows that we're not "in lisp". - ldr reg_OCFP, =foreign_function_call_active + ldr reg_OCFP, =GNAME(foreign_function_call_active) str reg_OCFP, [reg_OCFP] + LEAVE_PA #endif - LEAVE_PA + #ifdef LISP_FEATURE_SB_SAFEPOINT /* OK to run GC without stopping this thread from this point on. */ -# ifdef LISP_FEATURE_SB_THREAD str reg_CSP, [reg_THREAD, THREAD_SAVED_CSP_OFFSET] -# else - ldr reg_NL9, =all_threads - str reg_CSP, [reg_NL9, THREAD_SAVED_CSP_OFFSET] -# endif #endif // And call the C function. // - // R8 is important for undefined_alien_function. - blr reg_R8 + // R9 is important for undefined_alien_function. + blr reg_R9 // We're back. Our main tasks are to move the C return value // to where Lisp expects it, and to re-establish the Lisp @@ -299,73 +326,50 @@ call_into_c: mov reg_R5, #0 mov reg_R6, #0 mov reg_R7, #0 - mov reg_R8, #0 - mov reg_R9, #0 +#ifndef LISP_FEATURE_DARWIN + mov reg_R10,#0 #ifndef LISP_FEATURE_SB_THREAD - mov reg_R10, #0 + mov reg_R11,#0 +#endif #endif - mov reg_LEXENV, #0 - mov reg_CODE, #0 # ifdef LISP_FEATURE_SB_SAFEPOINT /* No longer OK to run GC except at safepoints. */ -# ifdef LISP_FEATURE_SB_THREAD str xzr, [reg_THREAD, THREAD_SAVED_CSP_OFFSET] -# else - ldr reg_NL9, =all_threads - str xzr, [reg_NL9, THREAD_SAVED_CSP_OFFSET] -# endif # endif - ENTER_PA - // Restore the Lisp stack and frame pointers, but store the - // control frame pointer in reg_NFP (saving a register move - // later). + // Restore the Lisp stack and frame pointers #ifdef LISP_FEATURE_SB_THREAD - str xzr, [reg_THREAD, THREAD_FOREIGN_FUNCTION_CALL_ACTIVE_OFFSET] - - ldp reg_NFP,reg_CSP, [reg_THREAD, THREAD_CONTROL_FRAME_POINTER_OFFSET] + str xzr, [reg_THREAD, THREAD_CONTROL_STACK_POINTER_OFFSET] #else // Clear FFCA, so the runtime knows that we're "in lisp". str xzr, [reg_OCFP] - - ldr reg_NFP, =current_control_stack_pointer - ldr reg_CSP, [reg_NFP] - ldr reg_NFP, =current_control_frame_pointer - ldr reg_NFP, [reg_NFP] #endif - LEAVE_PA - - // Restore our caller state from our stack frame. - ldr reg_CODE, [reg_NFP, #16] - ldr reg_CFP, [reg_NFP] - mov reg_CSP, reg_NFP - - // Return - add reg_LR, reg_NARGS, reg_CODE // reg_NARGS has the offset from reg_CODE + mov reg_LR, reg_LEXENV ret - .size call_into_c, .-call_into_c + SIZE(call_into_c) +#endif // FIXME-ARM: The following is random garbage, to make // code/debug-int compile. To get the debugger working, this // needs to be implemented. - .align - .global fun_end_breakpoint_guts - .type fun_end_breakpoint_guts, %object -fun_end_breakpoint_guts: - .global fun_end_breakpoint_trap - .type fun_end_breakpoint_trap, %function -fun_end_breakpoint_trap: - b fun_end_breakpoint_trap - .global fun_end_breakpoint_end -fun_end_breakpoint_end: - - .align - .global do_pending_interrupt - .type do_pending_interrupt, %function -do_pending_interrupt: + .align 2 + .global GNAME(fun_end_breakpoint_guts) + TYPE(fun_end_breakpoint_guts) +GNAME(fun_end_breakpoint_guts): + .global GNAME(fun_end_breakpoint_trap) + TYPE(fun_end_breakpoint_trap) +GNAME(fun_end_breakpoint_trap): + b GNAME(fun_end_breakpoint_trap) + .global GNAME(fun_end_breakpoint_end) +GNAME(fun_end_breakpoint_end): + + .align 2 + .global GNAME(do_pending_interrupt) + TYPE(do_pending_interrupt) +GNAME(do_pending_interrupt): brk trap_PendingInterrupt ret diff --git a/src/runtime/arm64-bsd-os.c b/src/runtime/arm64-bsd-os.c new file mode 100644 index 0000000000..92ccfbec55 --- /dev/null +++ b/src/runtime/arm64-bsd-os.c @@ -0,0 +1,214 @@ +/* + * This is the ARM BSD incarnation of arch-dependent OS-dependent + * routines. See also "bsd-os.c". + */ + +/* + * This software is part of the SBCL system. See the README file for + * more information. + * + * This software is derived from the CMU CL system, which was + * written at Carnegie Mellon University and released into the + * public domain. The software is in the public domain and is + * provided with absolutely no warranty. See the COPYING and CREDITS + * files for more information. + */ + +#include <stdio.h> +#include <sys/param.h> +#include <sys/file.h> +#include "sbcl.h" +#include "./signal.h" +#include "os.h" +#include "arch.h" +#include "globals.h" +#include "interrupt.h" +#include "interr.h" +#include "lispregs.h" + +#ifndef LISP_FEATURE_DARWIN +#include <machine/sysarch.h> +#endif + +#include <sys/types.h> +#include <signal.h> +#include <sys/time.h> +#include <sys/stat.h> +#include <unistd.h> +#include <errno.h> + +#include "validate.h" + +int arch_os_thread_cleanup(struct thread *thread) { + return 1; /* success */ +} + +int arch_os_thread_init(struct thread *thread) { + stack_t sigstack; + /* Signal handlers are normally run on the main stack, but we've + * swapped stacks, require that the control stack contain only + * boxed data, and expands upwards while the C stack expands + * downwards. */ + sigstack.ss_sp = calc_altstack_base(thread); + sigstack.ss_flags = 0; + sigstack.ss_size = calc_altstack_size(thread); + if(sigaltstack(&sigstack,0)<0) + lose("Cannot sigaltstack: %s\n",strerror(errno)); + + return 1; /* success */ +} + + +#if defined(LISP_FEATURE_OPENBSD) + +os_context_register_t * +os_context_register_addr(os_context_t *context, int regno) +{ + switch (regno) { + case reg_LR: return (&context->sc_lr); + case reg_NSP: return (&context->sc_sp); + default: return (&context->sc_x[regno]); + } +} + +os_context_register_t * +os_context_float_register_addr(os_context_t *context, int offset) +{ + return NULL; +} + +void +os_restore_fp_control(os_context_t *context) +{ +} + +os_context_register_t * +os_context_lr_addr(os_context_t *context) +{ + return os_context_register_addr(context, reg_LR); +} + +void +os_flush_icache(os_vm_address_t address, os_vm_size_t length) +{ + os_vm_address_t end_address + = (os_vm_address_t)(((uintptr_t) address) + length); + __clear_cache(address, end_address); +} +os_context_register_t * +os_context_flags_addr(os_context_t *context) +{ + return (os_context_register_t*)(&context->sc_spsr); +} + +#elif defined(LISP_FEATURE_NETBSD) +os_context_register_t * +os_context_register_addr(os_context_t *context, int offset) +{ + return (os_context_register_t *)&(context->uc_mcontext.__gregs[offset]); +} + +os_context_register_t * +os_context_lr_addr(os_context_t *context) +{ + return os_context_register_addr(context, reg_LR); +} + +void +os_restore_fp_control(os_context_t *context) +{ + /* FIXME: Implement. */ +} + +os_context_register_t * +os_context_float_register_addr(os_context_t *context, int offset) +{ + return (os_context_register_t*) + &context->uc_mcontext.__fregs.__qregs[offset]; +} + +os_context_register_t * +os_context_flags_addr(os_context_t *context) +{ + return (os_context_register_t *)&(context->uc_mcontext.__gregs[_REG_SPSR]); +} + +void +os_flush_icache(os_vm_address_t address, os_vm_size_t length) +{ + __builtin___clear_cache(address, address + length); +} +#elif defined LISP_FEATURE_FREEBSD +os_context_register_t * +os_context_register_addr(os_context_t *context, int offset) +{ + switch (offset) { + case reg_LR: return (&context->uc_mcontext.mc_gpregs.gp_lr); + case reg_NSP: return (&context->uc_mcontext.mc_gpregs.gp_sp); + default: return (&context->uc_mcontext.mc_gpregs.gp_x[offset]); + } +} + +os_context_register_t * +os_context_lr_addr(os_context_t *context) +{ + return os_context_register_addr(context, reg_LR); +} + +void +os_restore_fp_control(os_context_t *context) +{ + /* FIXME: Implement. */ +} + +os_context_register_t * +os_context_float_register_addr(os_context_t *context, int offset) +{ + return (os_context_register_t*) &context->uc_mcontext.mc_fpregs.fp_q[offset]; +} + +os_context_register_t * +os_context_flags_addr(os_context_t *context) +{ + return (os_context_register_t*)(&context->uc_mcontext.mc_gpregs.gp_spsr); +} + +void +os_flush_icache(os_vm_address_t address, os_vm_size_t length) +{ + __builtin___clear_cache(address, address + length); +} +#elif defined (LISP_FEATURE_DARWIN) +os_context_register_t * +os_context_register_addr(os_context_t *context, int regno) +{ + switch (regno) { + case reg_LR: return (os_context_register_t*)(&context->uc_mcontext->__ss.__lr); + case reg_NSP: return (os_context_register_t*)(&context->uc_mcontext->__ss.__sp); + default: return (os_context_register_t*)(&context->uc_mcontext->__ss.__x[regno]); + } +} + +os_context_register_t * +os_context_float_register_addr(os_context_t *context, int offset) +{ + return (os_context_register_t*)(&context->uc_mcontext->__ns.__v[offset]); +} + +void +os_restore_fp_control(os_context_t *context) +{ +} + +os_context_register_t * +os_context_lr_addr(os_context_t *context) +{ + return os_context_register_addr(context, reg_LR); +} + +os_context_register_t * +os_context_flags_addr(os_context_t *context) +{ + return (os_context_register_t*)(&context->uc_mcontext->__ss.__cpsr); +} +#endif diff --git a/src/runtime/arm64-bsd-os.h b/src/runtime/arm64-bsd-os.h new file mode 100644 index 0000000000..f0c4fcb41f --- /dev/null +++ b/src/runtime/arm64-bsd-os.h @@ -0,0 +1,20 @@ +#ifndef _ARM64_BSD_OS_H +#define _ARM64_BSD_OS_H + +typedef long os_context_register_t; + +#include "arch-os-generic.inc" + +unsigned long os_context_fp_control(os_context_t *context); +#define RESTORE_FP_CONTROL_FROM_CONTEXT +void os_restore_fp_control(os_context_t *context); + +#ifdef LISP_FEATURE_OPENBSD +# define OS_CONTEXT_PC(context) context->sc_elr; +#elif defined LISP_FEATURE_NETBSD +# define OS_CONTEXT_PC(context) context->uc_mcontext.__gregs[32] +#elif defined LISP_FEATURE_FREEBSD +# define OS_CONTEXT_PC(context) context->uc_mcontext.mc_gpregs.gp_x[32] +#endif + +#endif /* _ARM64_BSD_OS_H */ diff --git a/src/runtime/arm64-darwin-os.c b/src/runtime/arm64-darwin-os.c new file mode 100644 index 0000000000..3473074bcf --- /dev/null +++ b/src/runtime/arm64-darwin-os.c @@ -0,0 +1,99 @@ +#include "thread.h" +#include "gc-internal.h" +#include "gc-private.h" +void set_thread_stack(void *address) { + /* KLUDGE: There is no interface to change the stack location of + the initial thread, and without that backtrace(3) returns zero + frames, which breaks some graphical applications on High Sierra + */ + pthread_t thread = pthread_self(); + void *stackaddr = pthread_get_stackaddr_np(thread); + size_t stacksize = pthread_get_stacksize_np(thread); + + if (__PTHREAD_SIZE__ >= 22*8 && + ((void **)thread->__opaque)[20] == stackaddr && + ((size_t *)thread->__opaque)[21] == stacksize) { + ((void **)thread->__opaque)[20] = address; + ((size_t *)thread->__opaque)[21] = thread_control_stack_size; + ((size_t *)thread->__opaque)[23] = (thread_control_stack_size + vm_page_size); + } +} + +void jit_patch(lispobj* address, lispobj value) { + THREAD_JIT(0); + *address = value; + THREAD_JIT(1); +} + +void jit_copy_code_insts(lispobj dst, lispobj* src) +{ + lispobj* aligned_src = (lispobj*)(src + ((uword_t)src & N_WORD_BYTES)); // align up + struct code* code = (struct code*)(dst-OTHER_POINTER_LOWTAG); + int nwords = code_total_nwords(code); + gc_assert(code_total_nwords((struct code*)aligned_src)); + THREAD_JIT(0); + // Leave the header word alone + memcpy(&code->boxed_size, aligned_src + 1, (nwords-1)<<WORD_SHIFT); + for_each_simple_fun(i, fun, code, 1, { fun->self = fun_self_from_baseptr(fun); }) + THREAD_JIT(1); + free(src); + // FINISH-FIXUPS didn't call SB-VM:SANCTIFY-FOR-EXECUTION + // because the copy of the code on which it operates was only temporary. + __clear_cache(code, (lispobj*)code + nwords); +} + +void jit_copy_code_constants(lispobj lispcode, lispobj constants) +{ + struct code* code = (void*)(lispcode - OTHER_POINTER_LOWTAG); + gc_assert(header_widetag(code->header) == CODE_HEADER_WIDETAG); + struct vector* v = VECTOR(constants); + gc_assert(header_widetag(v->header) == SIMPLE_VECTOR_WIDETAG); + gc_assert(find_page_index((void*)code) >= 0); + THREAD_JIT(0); + sigset_t mask; + sigemptyset(&mask); + sigaddset(&mask, SIG_STOP_FOR_GC); + thread_sigmask(SIG_BLOCK, &mask, 0); + SET_WRITTEN_FLAG((lispobj*)code); + memcpy(&code->constants, v->data, vector_len(v) * N_WORD_BYTES); + thread_sigmask(SIG_UNBLOCK, &mask, 0); + THREAD_JIT(1); +} + +void jit_memcpy(void* dst, void* src, size_t n) { + THREAD_JIT(0); + memcpy(dst, src, n); + THREAD_JIT(1); +} + +void jit_patch_code(lispobj code, lispobj value, unsigned long index) { + /* It is critical that we NOT touch the mark table if the object is off-heap. + * With soft protection, it's doesn't matter - it's merely suboptimal - but arm64 + * uses physical protection for now, and a page fault on a page that is erroneously + * marked (i.e. not write-protected, allegedly) would be an error. + * Disallow GC in between setting the WRITTEN flag and doing the assigmment */ + if (find_page_index((void*)code) >= 0) { + THREAD_JIT(0); + sigset_t mask; + sigemptyset(&mask); + sigaddset(&mask, SIG_STOP_FOR_GC); + thread_sigmask(SIG_BLOCK, &mask, 0); + gc_card_mark[addr_to_card_index(code)] = CARD_MARKED; + SET_WRITTEN_FLAG(native_pointer(code)); + native_pointer(code)[index] = value; + thread_sigmask(SIG_UNBLOCK, &mask, 0); + THREAD_JIT(1); + } else { // Off-heap code objects can't be executed (or GC'd) + SET_WRITTEN_FLAG(native_pointer(code)); + native_pointer(code)[index] = value; + } +} + + +void +os_flush_icache(os_vm_address_t address, os_vm_size_t length) +{ + os_vm_address_t end_address + = (os_vm_address_t)(((uintptr_t) address) + length); + __clear_cache(address, end_address); +} diff --git a/src/runtime/arm64-darwin-os.h b/src/runtime/arm64-darwin-os.h new file mode 100644 index 0000000000..18c3a269b4 --- /dev/null +++ b/src/runtime/arm64-darwin-os.h @@ -0,0 +1,29 @@ +#ifndef _ARM64_DARWIN_OS_H +#define _ARM64_DARWIN_OS_H + +#include "darwin-os.h" + +/* static inline unsigned int * */ +/* arch_os_context_mxcsr_addr(os_context_t *context) */ +/* { */ +/* return &context->uc_mcontext->__fs.__fpu_mxcsr; */ + +/* } */ + +typedef register_t os_context_register_t; + +#include "arch-os-generic.inc" + +/* #if __DARWIN_UNIX03 */ +/* #define CONTEXT_ADDR_FROM_STEM(stem) (os_context_register_t*)&context->uc_mcontext->__ss.__##stem */ +/* #else */ +/* #define CONTEXT_ADDR_FROM_STEM(stem) &context->uc_mcontext->ss.stem */ +/* #endif /\* __DARWIN_UNIX03 *\/ */ + +#define RESTORE_FP_CONTROL_FROM_CONTEXT +void os_restore_fp_control(os_context_t *context); +void set_thread_stack(void *); + +#define OS_CONTEXT_PC(context) context->uc_mcontext->__ss.__pc + +#endif /* _ARM64_DARWIN_OS_H */ diff --git a/src/runtime/arm64-linux-os.c b/src/runtime/arm64-linux-os.c index eb111a55ed..3629cd52e4 100644 --- a/src/runtime/arm64-linux-os.c +++ b/src/runtime/arm64-linux-os.c @@ -25,8 +25,6 @@ #include "interrupt.h" #include "interr.h" #include "lispregs.h" -#include <sys/socket.h> -#include <sys/utsname.h> #include <sys/types.h> #include <signal.h> @@ -39,13 +37,6 @@ int arch_os_thread_init(struct thread *thread) { stack_t sigstack; -#ifdef LISP_FEATURE_SB_THREAD -#ifdef LISP_FEATURE_GCC_TLS - current_thread = thread; -#else - pthread_setspecific(specials,thread); -#endif -#endif /* Signal handlers are normally run on the main stack, but we've * swapped stacks, require that the control stack contain only * boxed data, and expands upwards while the C stack expands @@ -68,12 +59,6 @@ os_context_register_addr(os_context_t *context, int offset) return (os_context_register_t *)&(context->uc_mcontext.regs[offset]); } -os_context_register_t * -os_context_pc_addr(os_context_t *context) -{ - return (os_context_register_t *)&(context->uc_mcontext.pc); -} - os_context_register_t * os_context_lr_addr(os_context_t *context) { @@ -86,6 +71,12 @@ os_context_sigmask_addr(os_context_t *context) return &(context->uc_sigmask); } +os_context_register_t * +os_context_flags_addr(os_context_t *context) +{ + return (os_context_register_t *)&(context->uc_mcontext.pstate); +} + void os_restore_fp_control(os_context_t *context) { diff --git a/src/runtime/arm64-linux-os.h b/src/runtime/arm64-linux-os.h index 1fa29d0650..17576af24c 100644 --- a/src/runtime/arm64-linux-os.h +++ b/src/runtime/arm64-linux-os.h @@ -10,4 +10,6 @@ unsigned long os_context_fp_control(os_context_t *context); #define RESTORE_FP_CONTROL_FROM_CONTEXT void os_restore_fp_control(os_context_t *context); +#define OS_CONTEXT_PC(context) context->uc_mcontext.pc + #endif /* _ARM_LINUX_OS_H */ diff --git a/src/runtime/arm64-lispregs.h b/src/runtime/arm64-lispregs.h index 4038b7f18d..6f84bbb7eb 100644 --- a/src/runtime/arm64-lispregs.h +++ b/src/runtime/arm64-lispregs.h @@ -37,25 +37,31 @@ #define reg_R5 REG(15) #define reg_R6 REG(16) #define reg_R7 REG(17) + +#ifdef LISP_FEATURE_DARWIN +#define reg_R8 REG(20) +#else #define reg_R8 REG(18) +#define reg_R10 REG(20) +#endif + #define reg_R9 REG(19) #ifdef LISP_FEATURE_SB_THREAD -#define reg_THREAD REG(20) +#define reg_THREAD REG(21) #else -#define reg_R10 REG(20) +#define reg_R11 REG(21) #endif -#define reg_LEXENV REG(21) - -#define reg_NARGS REG(22) -#define reg_NFP REG(23) -#define reg_OCFP REG(24) -#define reg_CFP REG(25) -#define reg_CSP REG(26) -#define reg_TMP REG(27) -#define reg_wTMP w27 -#define reg_NULL REG(28) -#define reg_wNULL w28 -#define reg_CODE REG(29) +#define reg_LEXENV REG(22) + +#define reg_NARGS REG(23) +#define reg_NFP REG(24) +#define reg_OCFP REG(25) +#define reg_CFP REG(26) +#define reg_CSP REG(27) +#define reg_TMP REG(28) +#define reg_wTMP w28 +#define reg_NULL REG(29) +#define reg_wNULL w29 #define reg_LR REG(30) #define reg_NSP REG(31) diff --git a/src/runtime/atomiclog.inc b/src/runtime/atomiclog.inc new file mode 100644 index 0000000000..d698edc3d4 --- /dev/null +++ b/src/runtime/atomiclog.inc @@ -0,0 +1,84 @@ +/* -*- Mode: C -*- */ + +#ifndef ATOMIC_LOGGING +#define event0(fmt) +#define event1(fmt,a) +#define event2(fmt,a,b) +#define event3(fmt,a,b,c) +#define event4(fmt,a,b,c,d) +#define event5(fmt,a,b,c,d,e) +#define event6(fmt,a,b,c,d,e,f) +#else + +#define EVENTBUFMAX 40000 +extern uword_t *eventdata; +extern int n_logevents; + +/// eventN = record event with N parameters + +/// NOTE 1: The buffer is oversized by enough to ensure that i_+7 does not +/// overrun the buffer. So we don't need to adjust the comparison of 'i_ <' +/// by the number of additional arguments. + +/// NOTE 2: Assume that pthread_self() can be cast to 'uword_t', which is +/// pretty much true everywhere, and that the low 3 bits are 0 +/// (which may not be true for 32-bit, but almost surely is for 64-bit). +/// So we can stuff the low 3 bits with something. + +#define event0(fmt) \ + { int i_ = __sync_fetch_and_add(&n_logevents, 2); if (i_ < EVENTBUFMAX) { \ + eventdata[i_ ] = (uword_t)pthread_self(); \ + eventdata[i_+1] = (uword_t)fmt; } } + +#define event1(fmt, arg1) \ + { int i_ = __sync_fetch_and_add(&n_logevents, 3); if (i_ < EVENTBUFMAX) { \ + eventdata[i_ ] = 1|(uword_t)pthread_self(); \ + eventdata[i_+1] = (uword_t)fmt; \ + eventdata[i_+2] = (uword_t)arg1; } } + +#define event2(fmt, arg1, arg2) \ + { int i_ = __sync_fetch_and_add(&n_logevents, 4); if (i_+3 < EVENTBUFMAX) { \ + eventdata[i_ ] = 2|(uword_t)pthread_self(); \ + eventdata[i_+1] = (uword_t)fmt; \ + eventdata[i_+2] = (uword_t)arg1; \ + eventdata[i_+3] = (uword_t)arg2; } } + +#define event3(fmt, arg1, arg2, arg3) \ + { int i_ = __sync_fetch_and_add(&n_logevents, 5); if (i_ < EVENTBUFMAX) { \ + eventdata[i_ ] = 3|(uword_t)pthread_self(); \ + eventdata[i_+1] = (uword_t)fmt; \ + eventdata[i_+2] = (uword_t)arg1; \ + eventdata[i_+3] = (uword_t)arg2; \ + eventdata[i_+4] = (uword_t)arg3; } } + +#define event4(fmt, arg1, arg2, arg3, arg4) \ + { int i_ = __sync_fetch_and_add(&n_logevents, 6); if (i_ < EVENTBUFMAX) { \ + eventdata[i_ ] = 4|(uword_t)pthread_self(); \ + eventdata[i_+1] = (uword_t)fmt; \ + eventdata[i_+2] = (uword_t)arg1; \ + eventdata[i_+3] = (uword_t)arg2; \ + eventdata[i_+4] = (uword_t)arg3; \ + eventdata[i_+5] = (uword_t)arg4; } } + +#define event5(fmt, arg1, arg2, arg3, arg4, arg5) \ + { int i_ = __sync_fetch_and_add(&n_logevents, 7); if (i_ < EVENTBUFMAX) { \ + eventdata[i_ ] = 5|(uword_t)pthread_self(); \ + eventdata[i_+1] = (uword_t)fmt; \ + eventdata[i_+2] = (uword_t)arg1; \ + eventdata[i_+3] = (uword_t)arg2; \ + eventdata[i_+4] = (uword_t)arg3; \ + eventdata[i_+5] = (uword_t)arg4; \ + eventdata[i_+6] = (uword_t)arg5; } } + +#define event6(fmt, arg1, arg2, arg3, arg4, arg5, arg6) \ + { int i_ = __sync_fetch_and_add(&n_logevents, 8); if (i_ < EVENTBUFMAX) { \ + eventdata[i_ ] = 6|(uword_t)pthread_self(); \ + eventdata[i_+1] = (uword_t)fmt; \ + eventdata[i_+2] = (uword_t)arg1; \ + eventdata[i_+3] = (uword_t)arg2; \ + eventdata[i_+4] = (uword_t)arg3; \ + eventdata[i_+5] = (uword_t)arg4; \ + eventdata[i_+6] = (uword_t)arg5; \ + eventdata[i_+7] = (uword_t)arg6; } } + +#endif diff --git a/src/runtime/backtrace.c b/src/runtime/backtrace.c index 677c46c541..d9b226e2d5 100644 --- a/src/runtime/backtrace.c +++ b/src/runtime/backtrace.c @@ -35,28 +35,18 @@ #include "gc.h" #include "code.h" #include "var-io.h" +#include "gc-internal.h" +#include "forwarding-ptr.h" +#include "lispstring.h" #ifdef LISP_FEATURE_OS_PROVIDES_DLADDR # include <dlfcn.h> #endif -static void -sbcl_putwc(wchar_t c, FILE *file) -{ -#ifdef LISP_FEATURE_OS_PROVIDES_PUTWC - putwc(c, file); -#else - if (c < 256) { - fputc(c, file); - } else { - fputc('?', file); - } -#endif -} - -static int decode_locs(lispobj packed_integer, int *offset, int *elsewhere) +int df_decode_locs(lispobj encoded, int *offset, int *elsewhere) { struct varint_unpacker unpacker; + lispobj packed_integer = listp(encoded) ? CONS(encoded)->cdr : encoded; varint_unpacker_init(&unpacker, packed_integer); return varint_unpack(&unpacker, offset) && varint_unpack(&unpacker, elsewhere); } @@ -64,26 +54,28 @@ static int decode_locs(lispobj packed_integer, int *offset, int *elsewhere) struct compiled_debug_fun * debug_function_from_pc (struct code* code, void *pc) { - sword_t offset = (char*)pc - code_text_start(code); struct compiled_debug_info *di; - if (!instancep(code->debug_info)) + if (instancep(code->debug_info)) + di = (void*)native_pointer(code->debug_info); + else if (listp(code->debug_info) && instancep(CONS(code->debug_info)->car)) + di = (void*)native_pointer(CONS(code->debug_info)->car); + else return NULL; - di = (struct compiled_debug_info *) native_pointer(code->debug_info); - if (!instancep(di->fun_map)) return NULL; struct compiled_debug_fun *df = (struct compiled_debug_fun*)native_pointer(di->fun_map); int begin, end, elsewhere_begin, elsewhere_end; - if (!decode_locs(df->encoded_locs, &begin, &elsewhere_begin)) + if (!df_decode_locs(df->encoded_locs, &begin, &elsewhere_begin)) return NULL; + sword_t offset = (char*)pc - code_text_start(code); while (df) { struct compiled_debug_fun *next; if (df->next != NIL) { next = (struct compiled_debug_fun*) native_pointer(df->next); - if (!decode_locs(next->encoded_locs, &end, &elsewhere_end)) + if (!df_decode_locs(next->encoded_locs, &end, &elsewhere_end)) return NULL; } else { next = 0; @@ -103,46 +95,57 @@ debug_function_from_pc (struct code* code, void *pc) static void print_string (struct vector *vector, FILE *f) { - int tag = widetag_of(&vector->header); - -#define doit(TYPE) \ - do { \ - int i; \ - int n = fixnum_value(vector->length); \ - TYPE *data = (TYPE *) vector->data; \ - for (i = 0; i < n; i++) { \ - wchar_t c = (wchar_t) data[i]; \ - if (c == '\\' || c == '"') \ - putc('\\', f); \ - sbcl_putwc(c, f); \ - } \ - } while (0) - - switch (tag) { - case SIMPLE_BASE_STRING_WIDETAG: - doit(unsigned char); - break; -#ifdef SIMPLE_CHARACTER_STRING_WIDETAG - case SIMPLE_CHARACTER_STRING_WIDETAG: - doit(unsigned int); - break; -#endif - default: - fprintf(f, "<??? type %d>", tag); - } -#undef doit + if (!string_widetag_p(widetag_of(&vector->header))) { + fprintf(f, "<??? type %d>", widetag_of(&vector->header)); + return; + } + int i; + int n = vector_len(vector); + for (i = 0; i < n; i++) { + unsigned int c = schar(vector, i); + if (c > 0xFFFF) fprintf(f,"\\U%08x", c); + // without knowing whether the terminal can accept + // character codes 128 through 255, it's conservative + // to just output unicode escapes. + else if (c > 0x7F) fprintf(f,"\\u%04x", c); + else { + if (c == '\\' || c == '"') putc('\\', f); + putc(c, f); + } + } } -static int string_equal (struct vector *vector, char *string) +lispobj debug_print(lispobj string) { - if (widetag_of(&vector->header) != SIMPLE_BASE_STRING_WIDETAG) - return 0; - return !strcmp((char *) vector->data, string); + print_string(VECTOR(string), stderr); + putc('\n', stderr); + fflush(stderr); + return 0; +} + +lispobj symbol_package(struct symbol* s) +{ + static int warned; + // If using ldb when debugging cold-init, this can be confusing to see all symbols + // as if they were uninterned, but package-IDs are always available in the symbol. + // End-users should never see this failure. + if (!lisp_package_vector) { + if (!warned) { + fprintf(stderr, "Warning: lisp package array is not initialized for C\n"); + warned = 1; + } + return NIL; + } + struct vector* v = VECTOR(lisp_package_vector); + int id = symbol_package_id(s); + if (id < vector_len(v)) return v->data[id]; + lose("can't decode package ID %d", id); } static void print_entry_name (lispobj name, FILE *f) { + name = follow_maybe_fp(name); if (listp(name)) { putc('(', f); while (name != NIL) { @@ -152,42 +155,42 @@ print_entry_name (lispobj name, FILE *f) return; } print_entry_name(CONS(name)->car, f); - name = CONS(name)->cdr; + name = follow_maybe_fp(CONS(name)->cdr); if (name != NIL) putc(' ', f); } putc(')', f); } else if (lowtag_of(name) == OTHER_POINTER_LOWTAG) { - lispobj *object = native_pointer(name); - if (widetag_of(object) == SYMBOL_WIDETAG) { - struct symbol *symbol = (struct symbol *) object; - if (symbol->package != NIL) { + struct symbol *symbol = SYMBOL(name); + char* prefix = 0; + int widetag = header_widetag(symbol->header); + switch (widetag) { + case SYMBOL_WIDETAG: + switch (symbol_package_id(symbol)) { + case PACKAGE_ID_NONE: prefix = "#:"; break; + case PACKAGE_ID_LISP: prefix = ""; break; + case PACKAGE_ID_USER: prefix = "CL-USER::"; break; + case PACKAGE_ID_KEYWORD: prefix = ":"; break; + } + if (prefix) fputs(prefix, f); else { struct package *pkg - = (struct package *) native_pointer(symbol->package); - struct vector *pkg_name = VECTOR(pkg->_name); - if (string_equal(pkg_name, "COMMON-LISP")) - ; - else if (string_equal(pkg_name, "COMMON-LISP-USER")) { - fputs("CL-USER::", f); - } - else if (string_equal(pkg_name, "KEYWORD")) { - putc(':', f); - } else { - print_string(pkg_name, f); - fputs("::", f); - } + = (struct package *)native_pointer(symbol_package(symbol)); + struct vector *pkg_name = VECTOR(follow_maybe_fp(pkg->_name)); + print_string(pkg_name, f); + fputs("::", f); } - print_string(VECTOR(symbol->name), f); - } else if (widetag_of(object) == SIMPLE_BASE_STRING_WIDETAG + print_string(symbol_name(symbol), f); + break; + case SIMPLE_BASE_STRING_WIDETAG: #ifdef SIMPLE_CHARACTER_STRING_WIDETAG - || widetag_of(object) == SIMPLE_CHARACTER_STRING_WIDETAG + case SIMPLE_CHARACTER_STRING_WIDETAG: #endif - ) { putc('"', f); - print_string((struct vector*)object, f); + print_string((struct vector*)symbol, f); putc('"', f); - } else { - fprintf(f, "<??? type %d>", widetag_of(object)); + break; + default: + fprintf(f, "<??? type %d>", widetag); } } else if (fixnump(name)) { fprintf(f, "%d", (int)fixnum_value(name)); @@ -196,7 +199,7 @@ print_entry_name (lispobj name, FILE *f) } } -static void +static void __attribute__((unused)) print_entry_points (struct code *code, FILE *f) { int n_funs = code_n_funs(code); @@ -216,38 +219,7 @@ print_entry_points (struct code *code, FILE *f) /* KLUDGE: Sigh ... I know what the call frame looks like and it had * better not change. */ -struct call_frame { -#ifndef LISP_FEATURE_ALPHA - struct call_frame *old_cont; -#else - u32 old_cont; -#endif - lispobj saved_lra; - lispobj code; - lispobj other_state[5]; -}; - -struct call_info { -#ifndef LISP_FEATURE_ALPHA - struct call_frame *frame; -#else - u32 frame; -#endif - int interrupted; -#ifndef LISP_FEATURE_ALPHA - struct code *code; -#else - u32 code; -#endif - lispobj lra; - int pc; /* Note: this is the trace file offset, not the actual pc. */ -}; - -// simple-fun headers have a pointer to layout-of-function in the -// upper bytes if words are 8 bytes, so mask off those bytes. -#define HEADER_LENGTH(header) (((header)>>8) & FUN_HEADER_NWORDS_MASK) - -static int previous_info(struct call_info *info); +#include "callframe.inc" static struct code * code_pointer(lispobj object) @@ -257,9 +229,11 @@ code_pointer(lispobj object) switch (widetag_of(headerp)) { case CODE_HEADER_WIDETAG: break; +#ifdef RETURN_PC_WIDETAG case RETURN_PC_WIDETAG: +#endif case SIMPLE_FUN_WIDETAG: - len = HEADER_LENGTH(*headerp); + len = (HeaderValue(*headerp) & FUN_HEADER_NWORDS_MASK); if (len == 0) headerp = NULL; else @@ -273,25 +247,12 @@ code_pointer(lispobj object) } static boolean -cs_valid_pointer_p(struct call_frame *pointer) +cs_valid_pointer_p(struct thread *thread, struct call_frame *pointer) { - struct thread *thread=arch_os_get_current_thread(); return (((char *) thread->control_stack_start <= (char *) pointer) && ((char *) pointer < (char *) access_control_stack_pointer(thread))); } -static void -call_info_from_lisp_state(struct call_info *info) -{ - info->frame = (struct call_frame *)access_control_frame_pointer(arch_os_get_current_thread()); - info->interrupted = 0; - info->code = NULL; - info->lra = 0; - info->pc = 0; - - previous_info(info); -} - static void call_info_from_context(struct call_info *info, os_context_t *context) { @@ -305,43 +266,44 @@ call_info_from_context(struct call_info *info, os_context_t *context) info->frame = (struct call_frame *)(uword_t) (*os_context_register_addr(context, reg_OCFP)); +#ifdef reg_LRA info->lra = (lispobj)(*os_context_register_addr(context, reg_LRA)); +#else + info->lra = (lispobj)(*os_context_register_addr(context, reg_RA)); +#endif info->code = code_pointer(info->lra); pc = (uword_t)native_pointer(info->lra); } else #endif { + pc = os_context_pc(context); info->frame = (struct call_frame *)(uword_t) (*os_context_register_addr(context, reg_CFP)); info->code = +#ifdef reg_CODE code_pointer(*os_context_register_addr(context, reg_CODE)); +#else + (struct code *)dynamic_space_code_from_pc((char *)pc); +#endif info->lra = NIL; - pc = *os_context_pc_addr(context); + } + if (info->code != NULL) - info->pc = pc - (uword_t) info->code - -#ifndef LISP_FEATURE_ALPHA - (HEADER_LENGTH(info->code->header) * sizeof(lispobj)); -#else - (HEADER_LENGTH(((struct code *)info->code)->header) * sizeof(lispobj)); -#endif + info->pc = (char*)pc - (char*)info->code; else info->pc = 0; } -static int -previous_info(struct call_info *info) +// Return 1 if we have a valid frame, 0 if not. +int lisp_frame_previous(struct thread *thread, struct call_info *info) { struct call_frame *this_frame; - struct thread *thread=arch_os_get_current_thread(); int free_ici; lispobj lra; - if (!cs_valid_pointer_p(info->frame)) { - printf("Bogus callee value (0x%lx).\n", (long)info->frame); - return 0; - } + if (!cs_valid_pointer_p(thread, info->frame)) return 0; this_frame = info->frame; info->lra = this_frame->saved_lra; @@ -364,15 +326,22 @@ previous_info(struct call_info *info) } } } else if (fixnump(lra)) { - info->code = (struct code*)native_pointer(this_frame->code); - // FIXME: is this right? fixnumish LRAs are based off the object base address - // and not the code text start? - info->pc = (uword_t)(info->code + lra); + info->code = +#ifdef reg_CODE + (struct code*)native_pointer(this_frame->code); +#else + (struct code *)dynamic_space_code_from_pc((char *)lra); +#endif +#ifdef reg_LRA + info->pc = lra; +#else + info->pc = (char*)native_pointer(lra) - (char*)info->code; +#endif info->lra = NIL; } else { info->code = code_pointer(lra); if (info->code != NULL) - info->pc = (char*)native_pointer(info->lra) - code_text_start(info->code); + info->pc = (char*)native_pointer(info->lra) - (char*)info->code; else info->pc = 0; } @@ -383,46 +352,91 @@ previous_info(struct call_info *info) void lisp_backtrace(int nframes) { + struct thread *thread = get_sb_vm_thread(); struct call_info info; - int i = 0; - call_info_from_lisp_state(&info); + info.frame = (struct call_frame *)access_control_frame_pointer(thread); + info.interrupted = 0; + info.code = NULL; + info.lra = 0; + info.pc = 0; + + int i = 0; + int footnotes = 0; do { + if (!lisp_frame_previous(thread, &info)) { + if (info.frame) // 0 is normal termination of the call chain + printf("Bad frame pointer %p [valid range=%p..%p]\n", info.frame, + thread->control_stack_start, thread->control_stack_end); + break; + } printf("%4d: ", i); + // Print spaces to keep the alignment nice + if (info.interrupted +#ifdef reg_LRA + || info.lra == NIL +#endif + ) { + putchar('['); + if (info.interrupted) { footnotes |= 1; putchar('I'); } +#ifdef reg_LRA + if (info.lra == NIL) { footnotes |= 2; putchar('*'); } +#endif + putchar(']'); + if (!(info.lra == NIL && info.interrupted)) putchar(' '); + } else { + printf(" "); + } + printf("%p ", info.frame); + void* absolute_pc = 0; + if (info.code) { + absolute_pc = (char*)info.code + info.pc; + printf("pc=%p {%p+%04x} ", absolute_pc, info.code, (int)info.pc); + } else { + absolute_pc = (char*)info.pc; + printf("pc=%p ", absolute_pc); + } + + // If LRA does not match the PC, print it. This should not happen. + if (info.lra != make_lispobj(absolute_pc, OTHER_POINTER_LOWTAG) + && info.lra != NIL) + printf("LRA=%p ", (void*)info.lra); + + int fpvalid = (lispobj*)info.frame >= thread->control_stack_start + && (lispobj*)info.frame < thread->control_stack_end; + + // If the FP is invalid, then quite likely we'd crash trying to find a + // compiled-debug-fun because info.code is a wild pointer + if (!fpvalid) { printf(" BAD FRAME\n"); break; } - if (info.code != (struct code *) 0) { - struct compiled_debug_fun *df ; - if (info.lra != NIL && - (df = debug_function_from_pc((struct code *)info.code, (void *)info.lra))) + if (info.code) { + struct compiled_debug_fun *df; + if (absolute_pc && + (df = debug_function_from_pc((struct code *)info.code, absolute_pc))) print_entry_name(df->name, stdout); else - print_entry_points((struct code *)info.code, stdout); - - printf(" %p", (void*)((uword_t) info.code | OTHER_POINTER_LOWTAG)); + // I can't imagine a scenario where we have info.code + // but do not have an absolute_pc, or debug-fun can't be found. + // Anyway, we can uniquely identify code by serial# now. + printf("{code_serialno=%x}", code_serialno(info.code)); } - else - printf("CODE = ???"); - printf("%s fp = %p", info.interrupted ? " [interrupted]" : "", - info.frame); - - if (info.lra != NIL) - printf(" LRA = %p", (void*)info.lra); - else - printf(" <no LRA>"); - if (info.pc) - printf(" pc_ofs = %p", (void*)(long)info.pc); putchar('\n'); - } while (i++ < nframes && previous_info(&info)); + } while (++i <= nframes); + if (footnotes) printf("Note: [I] = interrupted" +#ifdef reg_LRA + ", [*] = no LRA" +#endif + "\n"); } #else static int -altstack_pointer_p (void __attribute__((unused)) *p) { +altstack_pointer_p(__attribute__((unused)) struct thread* thread, + __attribute__((unused)) void *p) { #ifndef LISP_FEATURE_WIN32 - struct thread* thread = arch_os_get_current_thread(); // FIXME: shouldn't this be testing '>=' start and '<' end ? // i.e. Was it only right because the calculations themselves were wrong ? return (p > calc_altstack_base(thread) && p <= calc_altstack_end(thread)); @@ -433,19 +447,18 @@ altstack_pointer_p (void __attribute__((unused)) *p) { } static int -stack_pointer_p (void *p) +stack_pointer_p(struct thread* thread, void *p) { /* we are using sizeof(long) here, because that is the right value on both * x86 and x86-64. (But note that false positives would not cause much harm * given the heuristical nature of x86_call_context.) */ uword_t stack_alignment = sizeof(void*); void *stack_start; - struct thread *thread = arch_os_get_current_thread(); - if (altstack_pointer_p(p)) + if (altstack_pointer_p(thread, p)) return 1; - if (altstack_pointer_p(&p)) { + if (altstack_pointer_p(thread, &p)) { stack_start = (void *) thread->control_stack_start; } else { /* Use the current frame address, since there should be no @@ -458,30 +471,30 @@ stack_pointer_p (void *p) } static int -ra_pointer_p (void *ra) +ra_pointer_p (struct thread* th, void *ra) { /* the check against 4096 is still a mystery to everyone interviewed about * it, but recent changes to sb-sprof seem to suggest that such values * do occur sometimes. */ - return ((uword_t) ra) > 4096 && !stack_pointer_p (ra); + return ((uword_t) ra) > 4096 && !stack_pointer_p (th, ra); } static int NO_SANITIZE_MEMORY -x86_call_context (void *fp, void **ra, void **ocfp) +x86_call_context (struct thread* th, void *fp, void **ra, void **ocfp) { void *c_ocfp; void *c_ra; int c_valid_p; - if (!stack_pointer_p(fp)) + if (!stack_pointer_p(th, fp)) return 0; c_ocfp = *((void **) fp); c_ra = *((void **) fp + 1); c_valid_p = (c_ocfp > fp - && stack_pointer_p(c_ocfp) - && ra_pointer_p(c_ra)); + && stack_pointer_p(th, c_ocfp) + && ra_pointer_p(th, c_ra)); if (c_valid_p) *ra = c_ra, *ocfp = c_ocfp; @@ -494,51 +507,60 @@ x86_call_context (void *fp, void **ra, void **ocfp) void describe_thread_state(void) { - struct thread *thread = arch_os_get_current_thread(); - struct interrupt_data *data = thread->interrupt_data; + struct thread *thread = get_sb_vm_thread(); + struct interrupt_data *data = &thread_interrupt_data(thread); #ifndef LISP_FEATURE_WIN32 sigset_t mask; - get_current_sigmask(&mask); - printf("Signal mask:\n"); - printf(" SIGALRM = %d\n", sigismember(&mask, SIGALRM)); - printf(" SIGINT = %d\n", sigismember(&mask, SIGINT)); - printf(" SIGPROF = %d\n", sigismember(&mask, SIGPROF)); -#ifdef SIG_STOP_FOR_GC - printf(" SIG_STOP_FOR_GC = %d\n", sigismember(&mask, SIG_STOP_FOR_GC)); -#endif + char string[180]; + thread_sigmask(SIG_BLOCK, 0, &mask); + sigset_tostring(&mask, string, sizeof string); + if (string[0]) printf("Signal mask: %s\n", string); #endif printf("Specials:\n"); - printf(" *GC-INHIBIT* = %s\n", (read_TLS(GC_INHIBIT, thread) == T) ? "T" : "NIL"); - printf(" *GC-PENDING* = %s\n", (read_TLS(GC_PENDING, thread) == T) ? "T" : "NIL"); - printf(" *INTERRUPTS-ENABLED* = %s\n", (read_TLS(INTERRUPTS_ENABLED, thread) == T) ? "T" : "NIL"); + printf(" *GC-INHIBIT* = %s\n", read_TLS(GC_INHIBIT, thread) == LISP_T ? "T" : "NIL"); + printf(" *GC-PENDING* = %s\n", read_TLS(GC_PENDING, thread) == LISP_T ? "T" : "NIL"); + printf(" *INTERRUPTS-ENABLED* = %s\n", + read_TLS(INTERRUPTS_ENABLED, thread) == LISP_T ? "T" : "NIL"); #ifdef STOP_FOR_GC_PENDING - printf(" *STOP-FOR-GC-PENDING* = %s\n", (read_TLS(STOP_FOR_GC_PENDING, thread) == T) ? "T" : "NIL"); + printf(" *STOP-FOR-GC-PENDING* = %s\n", + read_TLS(STOP_FOR_GC_PENDING, thread) == LISP_T ? "T" : "NIL"); #endif printf("Pending handler = %p\n", data->pending_handler); } static void print_backtrace_frame(char *pc, void *fp, int i, FILE *f) { - lispobj *p; - fprintf(f, "%4d: ", i); - - p = component_ptr_from_pc(pc); - - if (p) { - struct code *cp = (struct code *) p; - struct compiled_debug_fun *df = debug_function_from_pc(cp, pc); + fprintf(f, "%4d: fp=%p pc=%p ", i, fp, pc); + struct code *code = (void*)component_ptr_from_pc(pc); + if (code) { + struct compiled_debug_fun *df = debug_function_from_pc(code, pc); if (df) print_entry_name(df->name, f); + else if (pc >= (char*)asm_routines_start && pc < (char*)asm_routines_end) + fprintf(f, "(assembly routine)"); else - print_entry_points(cp, f); - fprintf(f, ", pc = %p, fp = %p", pc, fp); + fprintf(f, "{code_serialno=%x}", code_serialno(code)); + } else if (gc_managed_heap_space_p((uword_t)pc)) { +#ifdef LISP_FEATURE_X86 + // can't actually have a PC inside a random object, it's got to be a frame + // that didn't set up the pointer chain, quite possibly a signal frame such as: + // 7: fp=0xd78c8460 pc=0xf7fb51b0 Foreign function __kernel_rt_sigreturn + // 8: fp=0xd78c8478 pc=0xd9c43159 (bad PC) + // 9: fp=0xd78c84ec pc=0xd849a17e (FLET SB-C::DO-1-USE :IN SB-C::TENSION-IF-IF-1) + // where, if you print the PC actually from the context, line 8 would be 0xd823ea78. + fprintf(f, "(bad PC)"); +#else + // It could be a generic-function with self-contained tramponline code, + // or the executable JMP instruction in an fdefn. + fprintf(f, "(unknown lisp object)"); +#endif } else { #ifdef LISP_FEATURE_OS_PROVIDES_DLADDR Dl_info info; if (dladdr(pc, &info)) { - fprintf(f, "Foreign function %s, pc = %p, fp = %p", info.dli_sname, pc, fp); + fprintf(f, "Foreign function %s", info.dli_sname); } else #endif - fprintf(f, "Foreign function, pc = %p, fp = %p", pc, fp); + fprintf(f, "Foreign function"); } putc('\n', f); @@ -549,7 +571,7 @@ static void print_backtrace_frame(char *pc, void *fp, int i, FILE *f) { * example when debugging threading deadlocks. */ void NO_SANITIZE_MEMORY -log_backtrace_from_fp(void *fp, int nframes, int start, FILE *f) +log_backtrace_from_fp(struct thread* th, void *fp, int nframes, int start, FILE *f) { int i = start; @@ -557,30 +579,26 @@ log_backtrace_from_fp(void *fp, int nframes, int start, FILE *f) void *ra; void *next_fp; - if (!x86_call_context(fp, &ra, &next_fp)) + if (!x86_call_context(th, fp, &ra, &next_fp)) break; print_backtrace_frame(ra, next_fp, i, f); fp = next_fp; } } void backtrace_from_fp(void *fp, int nframes, int start) { - log_backtrace_from_fp(fp, nframes, start, stdout); + log_backtrace_from_fp(get_sb_vm_thread(), fp, nframes, start, stdout); } void backtrace_from_context(os_context_t *context, int nframes) { -#ifdef LISP_FEATURE_X86 - void *fp = (void *)*os_context_register_addr(context,reg_EBP); -#elif defined (LISP_FEATURE_X86_64) - void *fp = (void *)*os_context_register_addr(context,reg_RBP); -#endif - print_backtrace_frame((void *)*os_context_pc_addr(context), fp, 0, stdout); + void *fp = (void *)os_context_frame_pointer(context); + print_backtrace_frame((void *)os_context_pc(context), fp, 0, stdout); backtrace_from_fp(fp, nframes - 1, 1); } void lisp_backtrace(int nframes) { - struct thread *thread=arch_os_get_current_thread(); + struct thread *thread = get_sb_vm_thread(); int free_ici = fixnum_value(read_TLS(FREE_INTERRUPT_CONTEXT_INDEX,thread)); if (free_ici) { @@ -598,3 +616,175 @@ lisp_backtrace(int nframes) } } #endif + +// Find the simple_fun that contains 'pc' in 'code' +int simple_fun_index_from_pc(struct code* code, char *pc) +{ + char *instruction_area = code_text_start(code); + unsigned int* offsets = code_fun_table(code) - 1; + int index; + for (index = code_n_funs(code) - 1; index >= 0; --index) { + char *base = instruction_area + offsets[-index]; + if (pc >= base) return index; + } + return -1; +} + +static boolean __attribute__((unused)) print_lisp_fun_name(char* pc) +{ + struct code* code; + if (gc_managed_heap_space_p((uword_t)pc) && + (code = (void*)component_ptr_from_pc(pc)) != 0) { + struct compiled_debug_fun* df = debug_function_from_pc(code, pc); + if (df) { + fprintf(stderr, " %p [", pc); + print_entry_name(df->name, stderr); + fprintf(stderr, "]\n"); + return 1; + } + } + return 0; +} + +#ifdef LISP_FEATURE_BACKTRACE_ON_SIGNAL +#define UNW_LOCAL_ONLY +#ifdef HAVE_LIBUNWIND +#include <libunwind.h> +#endif +#include "genesis/thread-instance.h" +#include "genesis/mutex.h" +static __attribute__((unused))int backtrace_completion_pipe[2] = {-1,-1}; +void libunwind_backtrace(struct thread *th, os_context_t *context) +{ + fprintf(stderr, "Lisp thread @ %p, tid %d", th, (int)th->os_kernel_tid); +#ifdef LISP_FEATURE_SB_THREAD + // the TLS area is not used if #-sb-thread. And if so, it must be "main thred" + struct thread_instance* lispthread = (void*)native_pointer(th->lisp_thread); + if (lispthread->name != NIL) { + fprintf(stderr, " (\""); + print_string(VECTOR(lispthread->name), stderr); + fprintf(stderr, "\")"); + } + putc('\n', stderr); + if (lispthread->waiting_for != NIL) { + fprintf(stderr, "waiting for %p", (void*)lispthread->waiting_for); + if (instancep(lispthread->waiting_for)) { + // THREAD-WAITING-FOR can be a mutex or a waitqueue (if not a cons). + // Accessing it as if it's a mutex works because both a waitqueue + // and a mutex have a name at the same slot offset (if #+sb-futex). + // So to reiterate the comment from linux-os.c - + // "Use this only if you know what you're doing" + struct mutex* lispmutex = (void*)native_pointer(lispthread->waiting_for); + if (lispmutex->name != NIL) { + fprintf(stderr, " (MUTEX:\""); + print_string(VECTOR(lispmutex->name), stderr); + fprintf(stderr, "\")"); + } + } + putc('\n', stderr); + } +#endif +#ifdef HAVE_LIBUNWIND + char procname[100]; + unw_cursor_t cursor; + // "unw_init_local() is thread-safe as well as safe to use from a signal handler." + // "unw_get_proc_name() is thread-safe. If cursor cp is in the local address-space, + // this routine is also safe to use from a signal handler." + if (context) { + unw_init_local(&cursor, context); + } else { + unw_context_t here; + unw_getcontext(&here); + unw_init_local(&cursor, &here); + } + do { + uword_t offset; + char *pc; + unw_get_reg(&cursor, UNW_TDEP_IP, (uword_t*)&pc); + if (print_lisp_fun_name(pc)) { + // printed + } else if (!unw_get_proc_name(&cursor, procname, sizeof procname, &offset)) { + fprintf(stderr, " %p [%s]\n", pc, procname); + } else { + fprintf(stderr, " %p ?\n", pc); + } + } while (unw_step(&cursor)); +#else + // If you don't have libunwind, this will almost surely not work, + // because we can't figure out how to get backwards past a signal frame. + log_backtrace_from_fp(th, (void*)*os_context_fp_addr(context), 100, 0, stderr); +#endif +} +void backtrace_lisp_threads(int __attribute__((unused)) signal, + siginfo_t __attribute__((unused)) *info, + os_context_t *context) +{ + struct thread* this_thread = get_sb_vm_thread(); +#ifdef LISP_FEATURE_SB_THREAD + if (backtrace_completion_pipe[1] >= 0) { + libunwind_backtrace(get_sb_vm_thread(), context); + write(backtrace_completion_pipe[1], context /* any random byte */, 1); + return; + } + struct thread *th; + int nthreads = 0; + for_each_thread(th) { ++nthreads; } + if (signal) + fprintf(stderr, "Caught backtrace-all signal in tid %d, %d threads\n", + (int)this_thread->os_kernel_tid, nthreads); + // Would be nice if we could forcibly stop all the other threads, + // but pthread_mutex_trylock is not safe to use in a signal handler. + if (nthreads > 1) { + pipe(backtrace_completion_pipe); + } + for_each_thread(th) { + if (th == this_thread) + libunwind_backtrace(th, context); + else { + char junk; + pthread_kill(th->os_thread, SIGXCPU); + read(backtrace_completion_pipe[0], &junk, 1); + } + } + if (nthreads > 1) { + close(backtrace_completion_pipe[1]); + close(backtrace_completion_pipe[0]); + backtrace_completion_pipe[0] = backtrace_completion_pipe[1] = -1; + } +#else + libunwind_backtrace(this_thread, context); +#endif +} +static int watchdog_pipe[2] = {-1,-1}; +static pthread_t watchdog_tid; +static void* watchdog_thread(void* arg) { + struct timeval timeout; + fd_set fds; + FD_ZERO(&fds); + FD_SET(watchdog_pipe[0], &fds); + timeout.tv_sec = (long)arg; + timeout.tv_usec = 0; + int nfds = select(watchdog_pipe[0]+1, &fds, 0, 0, &timeout); + if (nfds == 0) { + // Ensure this message comes out in one piece even if nothing following it does. + char msg[] = "Watchdog timer expired\n"; write(2, msg, sizeof msg-1); + backtrace_lisp_threads(0, 0, 0); + _exit(1); // cause the test suite to exit with failure + } + return 0; +} +void start_watchdog(int sec) { + if (pipe(watchdog_pipe)) lose("Can't make watchdog pipe"); + pthread_create(&watchdog_tid, 0, watchdog_thread, (void*)(long)sec); + char msg[] = "Started watchdog thread\n"; write(2, msg, sizeof msg-1); +} +void stop_watchdog() { + char c[1] = {0}; + write(watchdog_pipe[1], c, 1); + close(watchdog_pipe[1]); + void* result; + pthread_join(watchdog_tid, &result); + close(watchdog_pipe[0]); + watchdog_pipe[0] = watchdog_pipe[1] = -1; +} +#endif diff --git a/src/runtime/breakpoint.c b/src/runtime/breakpoint.c index eff215d016..a8dc83738e 100644 --- a/src/runtime/breakpoint.c +++ b/src/runtime/breakpoint.c @@ -82,7 +82,7 @@ lispobj find_code(os_context_t *context) return code - HeaderValue(header)*sizeof(lispobj); #else lispobj codeptr = - (lispobj)component_ptr_from_pc((char *)(*os_context_pc_addr(context))); + (lispobj)component_ptr_from_pc((char *)os_context_pc(context)); if (codeptr == 0) return NIL; @@ -94,11 +94,7 @@ lispobj find_code(os_context_t *context) static long compute_offset(os_context_t *context, lispobj code) { if (code != NIL) { -#ifdef LISP_FEATURE_HPPA - uword_t pc = *os_context_pc_addr(context) & ~3; -#else - uword_t pc = *os_context_pc_addr(context); -#endif + uword_t pc = os_context_pc(context); struct code *codeptr = (struct code *)native_pointer(code); uword_t code_start = (uword_t)code_text_start(codeptr); int offset; @@ -117,7 +113,7 @@ void handle_breakpoint(os_context_t *context) fake_foreign_function_call(context); #ifndef LISP_FEATURE_SB_SAFEPOINT - unblock_gc_signals(0, 0); + unblock_gc_signals(); #endif code = find_code(context); @@ -144,7 +140,7 @@ void *handle_fun_end_breakpoint(os_context_t *context) fake_foreign_function_call(context); #ifndef LISP_FEATURE_SB_SAFEPOINT - unblock_gc_signals(0, 0); + unblock_gc_signals(); #endif code = find_code(context); diff --git a/src/runtime/brothertree.h b/src/runtime/brothertree.h new file mode 100644 index 0000000000..f0cc366336 --- /dev/null +++ b/src/runtime/brothertree.h @@ -0,0 +1,20 @@ +#include "lispobj.h" +#include "genesis/config.h" + +struct binary_node { + lispobj header; +#ifndef LISP_FEATURE_COMPACT_INSTANCE_HEADER + lispobj layout; +#endif + uword_t key; + lispobj left, right; +}; +struct unary_node { + lispobj header; +#ifndef LISP_FEATURE_COMPACT_INSTANCE_HEADER + lispobj layout; +#endif + lispobj child; +}; + +extern uword_t brothertree_find_lesseql(uword_t key, lispobj tree); diff --git a/src/runtime/bsd-os.c b/src/runtime/bsd-os.c index a041f8e8af..8cc7f6212a 100644 --- a/src/runtime/bsd-os.c +++ b/src/runtime/bsd-os.c @@ -44,10 +44,6 @@ #include "validate.h" #include "gc-internal.h" -#if defined(LISP_FEATURE_SB_WTIMER) && !defined(LISP_FEATURE_DARWIN) -# include <sys/event.h> -#endif - #ifdef __NetBSD__ @@ -63,7 +59,7 @@ static os_vm_size_t max_allocation_size; #if defined LISP_FEATURE_FREEBSD #include <sys/sysctl.h> -#if defined(LISP_FEATURE_SB_THREAD) && !defined(LISP_FEATURE_SB_PTHREAD_FUTEX) +#ifdef LISP_FEATURE_SB_FUTEX #include <sys/umtx.h> #endif @@ -89,8 +85,7 @@ static void dragonfly_init(); static void openbsd_init(); #endif -void -os_init(char *argv[], char *envp[]) +void os_init() { #ifdef __NetBSD__ netbsd_init(); @@ -122,14 +117,49 @@ os_context_sigmask_addr(os_context_t *context) } os_vm_address_t -os_validate(int attributes, os_vm_address_t addr, os_vm_size_t len) +os_alloc_gc_space(int space_id, int attributes, os_vm_address_t addr, os_vm_size_t len) { - int protection = attributes & IS_GUARD_PAGE ? OS_VM_PROT_NONE : OS_VM_PROT_ALL; - attributes &= ~IS_GUARD_PAGE; + int __attribute((unused)) + executable = (space_id == READ_ONLY_CORE_SPACE_ID) || + (space_id == ALIEN_LINKAGE_TABLE_CORE_SPACE_ID) || + (space_id == STATIC_CODE_CORE_SPACE_ID), + jit = (space_id == STATIC_CODE_CORE_SPACE_ID) || (space_id == DYNAMIC_CORE_SPACE_ID) + ? 1 : (space_id == ALIEN_LINKAGE_TABLE_CORE_SPACE_ID) ? 2 : 0; + + int protection; int flags = 0; -#ifndef LISP_FEATURE_DARWIN // Do not use MAP_FIXED, because the OS is sane. +#if defined(LISP_FEATURE_OPENBSD) && defined(MAP_STACK) + /* OpenBSD requires MAP_STACK for pages used as stack. + * Note that FreeBSD has a MAP_STACK with different behavior. */ + if (space_id == THREAD_STRUCT_CORE_SPACE_ID) flags = MAP_STACK; +#endif + // FIXME: This probaby needs to use MAP_TRYFIXED + if (attributes & IS_GUARD_PAGE) + protection = OS_VM_PROT_NONE; + else +#ifndef LISP_FEATURE_DARWIN_JIT + protection = OS_VM_PROT_ALL; +#else + if (jit) { + if (jit == 2) + protection = OS_VM_PROT_ALL; + else + protection = OS_VM_PROT_READ | OS_VM_PROT_WRITE; + flags = MAP_JIT; + } + else if (executable) { + protection = OS_VM_PROT_READ | OS_VM_PROT_EXECUTE; + } + else { + protection = OS_VM_PROT_READ | OS_VM_PROT_WRITE; + } +#endif + + attributes &= ~IS_GUARD_PAGE; + +#ifndef LISP_FEATURE_DARWIN // Do not use MAP_FIXED, because the OS is sane. /* The *BSD family of OSes seem to ignore 'addr' when it is outside * of some range which I could not figure out. Sometimes it seems like the * condition is that any address below 4GB can't be requested without MAP_FIXED, @@ -157,16 +187,7 @@ os_validate(int attributes, os_vm_address_t addr, os_vm_size_t len) Except for MAP_FIXED mappings, the system will never replace existing mappings. */ // ALLOCATE_LOW seems never to get what we want - if (!(attributes & MOVABLE) || (attributes & ALLOCATE_LOW)) { - flags = MAP_FIXED; - } - if (attributes & IS_THREAD_STRUCT) { -#if defined(LISP_FEATURE_OPENBSD) && defined(MAP_STACK) - /* OpenBSD requires MAP_STACK for pages used as stack. - * Note that FreeBSD has a MAP_STACK with different behavior. */ - flags = MAP_STACK; -#endif - } + if (!(attributes & MOVABLE) || (attributes & ALLOCATE_LOW)) flags = MAP_FIXED; #endif #ifdef MAP_EXCL // not defined in OpenBSD, NetBSD, DragonFlyBSD @@ -201,7 +222,12 @@ os_validate(int attributes, os_vm_address_t addr, os_vm_size_t len) } else #endif { + os_vm_address_t requested = addr; addr = mmap(addr, len, protection, flags, -1, 0); + if (requested && requested != addr && !(attributes & MOVABLE)) { + return 0; + } + } if (addr == MAP_FAILED) { @@ -211,27 +237,12 @@ os_validate(int attributes, os_vm_address_t addr, os_vm_size_t len) " mounted with wxallowed?\n"); else #endif - perror("mmap"); + perror("mmap"); return NULL; } return addr; } - -void -os_invalidate(os_vm_address_t addr, os_vm_size_t len) -{ - if (munmap(addr, len) == -1) - perror("munmap"); -} - -void -os_protect(os_vm_address_t address, os_vm_size_t length, os_vm_prot_t prot) -{ - if (mprotect(address, length, prot) == -1) { - perror("mprotect"); - } -} /* * any OS-dependent special low-level handling for signals @@ -250,58 +261,37 @@ memory_fault_handler(int signal, siginfo_t *siginfo, os_context_t *context) void *fault_addr = arch_get_bad_addr(signal, siginfo, context); #if defined(LISP_FEATURE_RESTORE_TLS_SEGMENT_REGISTER_FROM_CONTEXT) - FSHOW_SIGNAL((stderr, "/ TLS: restoring fs: %p in memory_fault_handler\n", - *CONTEXT_ADDR_FROM_STEM(fs))); os_restore_tls_segment_register(context); #endif - FSHOW((stderr, "Memory fault at: %p, PC: %p\n", fault_addr, *os_context_pc_addr(context))); + FSHOW((stderr, "Memory fault at: %p, PC: %p\n", fault_addr, OS_CONTEXT_PC(context))); #ifdef LISP_FEATURE_SB_SAFEPOINT - if (!handle_safepoint_violation(context, fault_addr)) + if (handle_safepoint_violation(context, fault_addr)) return; #endif - if (!gencgc_handle_wp_violation(fault_addr)) - if(!handle_guard_page_triggered(context,fault_addr)) - lisp_memory_fault_error(context, fault_addr); -} + if (gencgc_handle_wp_violation(context, fault_addr)) return; -#if defined(LISP_FEATURE_MACH_EXCEPTION_HANDLER) -void -mach_error_memory_fault_handler(int signal, siginfo_t *siginfo, - os_context_t *context) { - lose("Unhandled memory fault. Exiting."); + if (!handle_guard_page_triggered(context,fault_addr)) + lisp_memory_fault_error(context, fault_addr); } -#endif void os_install_interrupt_handlers(void) { - SHOW("os_install_interrupt_handlers()/bsd-os/defined(GENCGC)"); if (INSTALL_SIG_MEMORY_FAULT_HANDLER) { -#if defined(LISP_FEATURE_MACH_EXCEPTION_HANDLER) - undoably_install_low_level_interrupt_handler(SIG_MEMORY_FAULT, - mach_error_memory_fault_handler); -#else - undoably_install_low_level_interrupt_handler(SIG_MEMORY_FAULT, + ll_install_handler(SIG_MEMORY_FAULT, #if defined(LISP_FEATURE_FREEBSD) && !defined(__GLIBC__) (__siginfohandler_t *) #endif memory_fault_handler); -#endif - } -#ifdef LISP_FEATURE_SB_THREAD -# ifdef LISP_FEATURE_SB_SAFEPOINT -# ifdef LISP_FEATURE_SB_THRUPTION - undoably_install_low_level_interrupt_handler(SIGPIPE, thruption_handler); -# endif -# else - undoably_install_low_level_interrupt_handler(SIG_STOP_FOR_GC, - sig_stop_for_gc_handler); -# endif +#ifdef LISP_FEATURE_DARWIN + /* Unmapped pages get this and not SIGBUS. */ + ll_install_handler(SIGSEGV, memory_fault_handler); #endif - SHOW("leaving os_install_interrupt_handlers()"); + + } } #else /* Currently PPC/Darwin/Cheney only */ @@ -312,17 +302,16 @@ sigsegv_handler(int signal, siginfo_t *info, os_context_t *context) os_vm_address_t addr; addr = arch_get_bad_addr(signal, info, context); - if (!cheneygc_handle_wp_violation(context, addr)) - if (!handle_guard_page_triggered(context, addr)) + if (cheneygc_handle_wp_violation(context, addr)) return; + + if (!handle_guard_page_triggered(context, addr)) interrupt_handle_now(signal, info, context); } void os_install_interrupt_handlers(void) { - SHOW("os_install_interrupt_handlers()/bsd-os/!defined(GENCGC)"); - undoably_install_low_level_interrupt_handler(SIG_MEMORY_FAULT, - sigsegv_handler); + ll_install_handler(SIG_MEMORY_FAULT, sigsegv_handler); } #endif /* defined GENCGC */ @@ -347,20 +336,6 @@ The system may fail to start.\n", } max_allocation_size = (os_vm_size_t)((rl.rlim_cur / 2) & ~(32 * 1024 * 1024)); - -#ifdef LISP_FEATURE_X86 - { - size_t len; - int sse; - - len = sizeof(sse); - if (sysctlbyname("machdep.sse", &sse, &len, - NULL, 0) == 0 && sse != 0) { - /* Use the SSE detector */ - fast_bzero_pointer = fast_bzero_detect; - } - } -#endif /* LISP_FEATURE_X86 */ } /* Various routines in NetBSD's C library are compatibility wrappers @@ -428,30 +403,9 @@ static void freebsd_init() else sig_memory_fault = SIGSEGV; #endif - - /* Quote from sbcl-devel (NIIMI Satoshi): "Some OSes, like FreeBSD - * 4.x with GENERIC kernel, does not enable SSE support even on - * SSE capable CPUs". Detect this situation and skip the - * fast_bzero sse/base selection logic that's normally done in - * x86-assem.S. - */ -#ifdef LISP_FEATURE_X86 - { - size_t len; - int instruction_sse; - - len = sizeof(instruction_sse); - if (sysctlbyname("hw.instruction_sse", &instruction_sse, &len, - NULL, 0) == 0 && instruction_sse != 0) { - /* Use the SSE detector */ - fast_bzero_pointer = fast_bzero_detect; - } - } -#endif /* LISP_FEATURE_X86 */ } -#if defined(LISP_FEATURE_SB_THREAD) && defined(LISP_FEATURE_SB_FUTEX) \ - && !defined(LISP_FEATURE_SB_PTHREAD_FUTEX) +#ifdef LISP_FEATURE_SB_FUTEX int futex_wait(int *lock_word, long oldval, long sec, unsigned long usec) { @@ -459,30 +413,24 @@ futex_wait(int *lock_word, long oldval, long sec, unsigned long usec) int ret; if (sec < 0) - ret = umtx_wait((void *)lock_word, oldval, NULL); + ret = _umtx_op((void *)lock_word, UMTX_OP_WAIT, oldval, 0, 0); else { timeout.tv_sec = sec; timeout.tv_nsec = usec * 1000; - ret = umtx_wait((void *)lock_word, oldval, &timeout); - } - - switch (ret) { - case 0: - return 0; - case ETIMEDOUT: - return 1; - case EINTR: - return 2; - default: - /* EWOULDBLOCK and others, need to check the lock */ - return -1; + ret = _umtx_op((void *)lock_word, UMTX_OP_WAIT, oldval, (void*)sizeof timeout, &timeout); } + if (ret == 0) return 0; + // technically we would not need to check any of the error codes if the lisp side + // could just avoid looping if there is no time remaining. + if (errno == ETIMEDOUT) return 1; + if (errno == EINTR) return 2; + return -1; } int futex_wake(int *lock_word, int n) { - return umtx_wake((void *)lock_word, n); + return _umtx_op((void *)lock_word, UMTX_OP_WAKE, n, 0, 0); } #endif #endif /* __FreeBSD__ */ @@ -490,22 +438,10 @@ futex_wake(int *lock_word, int n) #ifdef __DragonFly__ static void dragonfly_init() { -#ifdef LISP_FEATURE_X86 - size_t len; - int instruction_sse; - - len = sizeof(instruction_sse); - if (sysctlbyname("hw.instruction_sse", &instruction_sse, &len, - NULL, 0) == 0 && instruction_sse != 0) { - /* Use the SSE detector */ - fast_bzero_pointer = fast_bzero_detect; - } -#endif /* LISP_FEATURE_X86 */ } -#if defined(LISP_FEATURE_SB_THREAD) && defined(LISP_FEATURE_SB_FUTEX) \ - && !defined(LISP_FEATURE_SB_PTHREAD_FUTEX) +#ifdef LISP_FEATURE_SB_FUTEX int futex_wait(int *lock_word, long oldval, long sec, unsigned long usec) { @@ -617,9 +553,6 @@ openbsd_init() mib[1] = CPU_OSFXSR; size = sizeof (openbsd_use_fxsave); sysctl(mib, 2, &openbsd_use_fxsave, &size, NULL, 0); - if (openbsd_use_fxsave) - /* Use the SSE detector */ - fast_bzero_pointer = fast_bzero_detect; #endif /* OpenBSD, like NetBSD, counts mmap()ed space against the @@ -646,7 +579,7 @@ The system may fail to start.\n", */ getrlimit (RLIMIT_DATA, &rl); if (dynamic_space_size + READ_ONLY_SPACE_SIZE + STATIC_SPACE_SIZE + - LINKAGE_TABLE_SPACE_SIZE + wantfree > rl.rlim_cur) + ALIEN_LINKAGE_TABLE_SPACE_SIZE + wantfree > rl.rlim_cur) fprintf (stderr, "RUNTIME WARNING: data size resource limit may be too low,\n" " try decreasing the dynamic space size with --dynamic-space-size\n" @@ -669,60 +602,3 @@ os_dlsym(void *handle, const char *symbol) } #endif - -#if defined(LISP_FEATURE_SB_WTIMER) && !defined(LISP_FEATURE_DARWIN) -/* - * Waitable timer implementation for the safepoint-based (SIGALRM-free) - * timer facility using kqueue. - */ -int -os_create_wtimer() -{ - int kq = kqueue(); - if (kq == -1) - lose("os_create_wtimer: kqueue"); - return kq; -} - -int -os_wait_for_wtimer(int kq) -{ - struct kevent ev; - int n; - if ( (n = kevent(kq, 0, 0, &ev, 1, 0)) == -1) { - if (errno != EINTR) - lose("os_wtimer_listen failed"); - n = 0; - } - return n != 1; -} - -void -os_close_wtimer(int kq) -{ - if (close(kq) == -1) - lose("os_close_wtimer failed"); -} - -void -os_set_wtimer(int kq, int sec, int nsec) -{ - long long msec - = ((long long) sec) * 1000 + (long long) (nsec+999999) / 1000000; - if (msec > INT_MAX) msec = INT_MAX; - - struct kevent ev; - EV_SET(&ev, 1, EVFILT_TIMER, EV_ADD|EV_ENABLE|EV_ONESHOT, 0, (int)msec, 0); - if (kevent(kq, &ev, 1, 0, 0, 0) == -1) - perror("os_set_wtimer: kevent"); -} - -void -os_cancel_wtimer(int kq) -{ - struct kevent ev; - EV_SET(&ev, 1, EVFILT_TIMER, EV_DISABLE, 0, 0, 0); - if (kevent(kq, &ev, 1, 0, 0, 0) == -1 && errno != ENOENT) - perror("os_cancel_wtimer: kevent"); -} -#endif diff --git a/src/runtime/bsd-os.h b/src/runtime/bsd-os.h index 9ffda9509c..0c5526c2cd 100644 --- a/src/runtime/bsd-os.h +++ b/src/runtime/bsd-os.h @@ -22,7 +22,7 @@ #endif typedef caddr_t os_vm_address_t; -#if defined __NetBSD__ || defined __OpenBSD__ +#if defined __NetBSD__ || defined __OpenBSD__ || defined __DragonFly__ typedef size_t os_vm_size_t; #else typedef vm_size_t os_vm_size_t; diff --git a/src/runtime/callframe.inc b/src/runtime/callframe.inc new file mode 100644 index 0000000000..b7c9295b79 --- /dev/null +++ b/src/runtime/callframe.inc @@ -0,0 +1,20 @@ +/* -*- Mode: C -*- */ + +struct call_frame { + struct call_frame *old_cont; + lispobj saved_lra; + lispobj code; + lispobj other_state[5]; +}; + +struct call_info { + struct call_frame *frame; + int interrupted; + struct code *code; + lispobj lra; + // Byte offset from 'code' base address to program counter, + // unless 'code' is 0, then an absolute PC. + uword_t pc; +}; + +int lisp_frame_previous(struct thread*, struct call_info *info); diff --git a/src/runtime/cheneygc-internal.h b/src/runtime/cheneygc-internal.h index dc5f738a52..4998b8e7f4 100644 --- a/src/runtime/cheneygc-internal.h +++ b/src/runtime/cheneygc-internal.h @@ -62,4 +62,17 @@ new_space_p(lispobj object) #endif +#define mixed_region 0 +#define small_mixed_region 0 +#define boxed_region 0 +#define unboxed_region 0 +#define code_region 0 +#define cons_region 0 +#define PAGE_TYPE_MIXED 0 +#define PAGE_TYPE_SMALL_MIXED 0 +#define PAGE_TYPE_BOXED 0 +#define PAGE_TYPE_UNBOXED 0 +#define PAGE_TYPE_CODE 0 +#define PAGE_TYPE_CONS 0 + extern boolean cheneygc_handle_wp_violation(os_context_t*, void*); diff --git a/src/runtime/cheneygc.c b/src/runtime/cheneygc.c index 85af1b9377..af55e05795 100644 --- a/src/runtime/cheneygc.c +++ b/src/runtime/cheneygc.c @@ -17,6 +17,7 @@ #include <sys/time.h> #include <sys/resource.h> #include <signal.h> +#include <stdlib.h> #include "sbcl.h" #include "runtime.h" #include "os.h" @@ -34,7 +35,8 @@ #include "arch.h" #include "code.h" #include "private-cons.inc" -#include "getallocptr.h" +#include "pseudo-atomic.h" +#include "genesis/gc-tables.h" // for leaf_obj_widetag_p /* So you need to debug? */ #if 0 @@ -50,6 +52,8 @@ lispobj *from_space_free_pointer; lispobj *new_space; lispobj *new_space_free_pointer; +lispobj *current_dynamic_space; + /* This does nothing. It's only to satisfy a reference from gc-common. */ char gc_coalesce_string_literals = 0; @@ -70,31 +74,49 @@ tv_diff(struct timeval *x, struct timeval *y) #endif void * -gc_general_alloc(sword_t bytes, int page_type_flag) { +gc_general_alloc(__attribute__((unused)) void* ignore, + sword_t bytes, + __attribute__((unused)) int page_type) { lispobj *new=new_space_free_pointer; new_space_free_pointer+=(bytes/N_WORD_BYTES); return new; } lispobj copy_unboxed_object(lispobj object, sword_t nwords) { - return copy_object(object,nwords); + return gc_copy_object(object, nwords, 0, 0); } -lispobj copy_large_object(lispobj object, sword_t nwords, int page_type_flag) { - return copy_object(object,nwords); +lispobj copy_potential_large_object(lispobj object, sword_t nwords, + __attribute__((unused)) void* region, + __attribute__((unused)) int page_type) { + return gc_copy_object(object, nwords, 0, 0); } -/* - * This flag is needed for compatibility with gencgc. - * In theory, it says to splat a nonzero byte pattern over newly allocated - * memory before giving the block to Lisp, to verify that Lisp is able to deal - * with non-pre-zeroed memory. - * In practice, that's not how cheneygc works. - */ -char gc_allocate_dirty = 0; +#if 0 +static void verify_range(int purified, lispobj *base, lispobj *end); +void show_spaces() +{ + fprintf(stderr, " R/O = %10p:%10p\n", (void*)READ_ONLY_SPACE_START, read_only_space_free_pointer); + fprintf(stderr, " static = %10p:%10p\n", (void*)STATIC_SPACE_START, static_space_free_pointer); + fprintf(stderr, " dynamic = %10p:%10p\n", current_dynamic_space, dynamic_space_free_pointer); + struct thread* th = all_threads; + fprintf(stderr, " stack = %10p:%10p\n", + th->control_stack_start, + access_control_stack_pointer(th)); +} +void verify_heap(int purified) +{ + show_spaces(); + verify_range(purified, (lispobj*)READ_ONLY_SPACE_START, read_only_space_free_pointer); + verify_range(purified, (lispobj*)STATIC_SPACE_START, static_space_free_pointer); + if (!purified) + verify_range(0, current_dynamic_space, dynamic_space_free_pointer); +} +#endif /* Note: The generic GC interface we're implementing passes us a * last_generation argument. That's meaningless for us, since we're * not a generational GC. So we ignore it. */ +int n_gcs; void collect_garbage(generation_index_t ignore) { @@ -108,7 +130,7 @@ collect_garbage(generation_index_t ignore) unsigned long size_retained; lispobj *current_static_space_free_pointer; sigset_t old; - struct thread *th=arch_os_get_current_thread(); + struct thread *th=get_sb_vm_thread(); #ifdef PRINTNOISE printf("[Collecting garbage ... \n"); @@ -127,6 +149,7 @@ collect_garbage(generation_index_t ignore) /* Set up from space and new space pointers. */ + // ++n_gcs; fprintf(stderr, "[%d] pre-verify:\n", n_gcs); verify_heap(0); from_space = current_dynamic_space; from_space_free_pointer = get_alloc_pointer(); @@ -150,11 +173,9 @@ collect_garbage(generation_index_t ignore) scavenge_interrupt_contexts(th); #ifdef PRINTNOISE - printf("Scavenging interrupt handlers (%d bytes) ...\n", - (int)sizeof(interrupt_handlers)); + printf("Scavenging interrupt handlers ...\n"); #endif - scavenge((lispobj *) interrupt_handlers, - sizeof(interrupt_handlers) / sizeof(lispobj)); + scavenge(lisp_sig_handlers, NSIG); #ifdef PRINTNOISE printf("Scavenging the control stack ...\n"); @@ -165,15 +186,9 @@ collect_garbage(generation_index_t ignore) (lispobj*)get_binding_stack_pointer(th), 0); -#ifdef PRINTNOISE - printf("Scavenging static space %p - %p (%d words) ...\n", - (void*)STATIC_SPACE_START, - current_static_space_free_pointer, - (int)(current_static_space_free_pointer - - (lispobj *) STATIC_SPACE_START)); -#endif heap_scavenge(((lispobj *)STATIC_SPACE_START), current_static_space_free_pointer); + scavenge(&lisp_package_vector, 1); /* Scavenge newspace. */ #ifdef PRINTNOISE @@ -201,10 +216,6 @@ collect_garbage(generation_index_t ignore) /* Maybe FIXME: it's possible that we could significantly reduce * RSS by zeroing the from_space or madvise(MADV_DONTNEED) or * similar os-dependent tricks here */ -#ifdef LISP_FEATURE_HPUX - /* hpux cant handle unmapping areas that are not 100% mapped */ - clear_auto_gc_trigger(); -#endif os_zero((os_vm_address_t) from_space, (os_vm_size_t) dynamic_space_size); @@ -227,6 +238,7 @@ collect_garbage(generation_index_t ignore) thread_sigmask(SIG_SETMASK, &old, 0); gc_active_p = 0; + // fprintf(stderr, "post-verify:\n"); verify_heap(0); #ifdef PRINTNOISE gettimeofday(&stop_tv, (struct timezone *) 0); @@ -332,19 +344,6 @@ print_garbage(lispobj *from_space, lispobj *from_space_free_pointer) } printf("%d total words not copied.\n", total_words_not_copied); } - - -/* weak pointers */ - -sword_t -scav_weak_pointer(lispobj *where, lispobj object) -{ - /* Do not let GC scavenge the value slot of the weak pointer */ - /* (that is why it is a weak pointer). Note: we could use */ - /* the scav_unboxed method here. */ - - return WEAK_POINTER_NWORDS; -} lispobj * search_dynamic_space(void *pointer) @@ -362,7 +361,7 @@ search_dynamic_space(void *pointer) void gc_init(void) { - weakobj_init(); + gc_common_init(); } /* noise to manipulate the gc trigger stuff */ @@ -394,8 +393,8 @@ void set_auto_gc_trigger(os_vm_size_t dynamic_usage) uword_t end = (uword_t)addr + length - 1; if (((uword_t)addr >= DYNAMIC_0_SPACE_START && end < semispace_0_end) || ((uword_t)addr >= DYNAMIC_1_SPACE_START && end < semispace_1_end)) { -#if defined(SUNOS) || defined(SOLARIS) || defined(LISP_FEATURE_HPUX) - os_invalidate(addr, length); +#if defined(SUNOS) || defined(SOLARIS) + os_deallocate(addr, length); #else os_protect(addr, length, 0); #endif @@ -417,7 +416,7 @@ void clear_auto_gc_trigger(void) addr = (os_vm_address_t)current_auto_gc_trigger; length = dynamic_space_size + (os_vm_address_t)current_dynamic_space - addr; -#if defined(SUNOS) || defined(SOLARIS) || defined(LISP_FEATURE_HPUX) +#if defined(SUNOS) || defined(SOLARIS) /* don't want to force whole space into swapping mode... */ os_validate(NOT_MOVABLE, addr, length); #else @@ -442,7 +441,7 @@ boolean cheneygc_handle_wp_violation(os_context_t *context, void *addr) { if(!foreign_function_call_active && gc_trigger_hit(addr)){ - struct thread *thread=arch_os_get_current_thread(); + struct thread *thread=get_sb_vm_thread(); clear_auto_gc_trigger(); /* Don't flood the system with interrupts if the need to gc is * already noted. This can happen for example when SUB-GC @@ -473,7 +472,7 @@ void gc_show_pte(lispobj obj) printf("unimplemented\n"); } -sword_t scav_code_header(lispobj *where, lispobj header) +sword_t scav_code_blob(lispobj *where, lispobj header) { struct code *code = (struct code *) where; sword_t n_header_words = code_header_words(code); @@ -492,3 +491,104 @@ sword_t scav_code_header(lispobj *where, lispobj header) return code_total_nwords(code); } + +#if 0 +static boolean in_stack_range_p(lispobj ptr) +{ + struct thread* th = all_threads; + return (ptr >= (uword_t)th->control_stack_start && + ptr < (uword_t)access_control_stack_pointer(th)); +} + +static boolean valid_space_p(int purified, lispobj ptr) +{ + if ((ptr >= READ_ONLY_SPACE_START && ptr < (uword_t)read_only_space_free_pointer) || + (ptr >= STATIC_SPACE_START && ptr < (uword_t)static_space_free_pointer) || + (!purified && + ((ptr >= (uword_t)current_dynamic_space && ptr < (uword_t)dynamic_space_free_pointer) || + in_stack_range_p(ptr)))) + return 1; + return 0; +} + +void check_ptr(int purified, lispobj* where, lispobj ptr) +{ + if (!is_lisp_pointer(ptr)) return; + + if (!valid_space_p(purified, ptr)) { + fprintf(stderr, "Sus' pointer %p @ %p outside expected ranges\n", + (void*)ptr, where); + return; + } + + // must be properly tagged + if (lowtag_of(ptr) == LIST_POINTER_LOWTAG) { + gc_assert(is_cons_half(CONS(ptr)->car)); + gc_assert(is_cons_half(CONS(ptr)->cdr)); + } else { + int widetag = widetag_of(native_pointer(ptr)); + if (LOWTAG_FOR_WIDETAG(widetag) != lowtag_of(ptr) && !in_stack_range_p(ptr)) + lose("Widetag/lowtag mismatch on %p", (void*)ptr); + } +} + +#define CHECK_PTR(x,y) check_ptr(purified,x,y) + +static void +verify_range(int purified, lispobj *base, lispobj *end) +{ + lispobj* where = base; + int len, i; + lispobj layout; + for ( ; where < end ; where += object_size(where) ) { + if (is_cons_half(*where)) { + CHECK_PTR(where+0, where[0]); + CHECK_PTR(where+1, where[1]); + } else switch (widetag_of(where)) { + case INSTANCE_WIDETAG: + layout = instance_layout(where); + if (layout) { + gc_assert(layoutp(layout)); + len = instance_length(*where); + struct bitmap bitmap = get_layout_bitmap(LAYOUT(layout)); + for (i=0; i<len; ++i) + if (bitmap_logbitp(i, bitmap)) CHECK_PTR(where+i+1, where[1+i]); + } + break; + case CODE_HEADER_WIDETAG: + len = code_header_words((struct code*)where); + for(i=2; i<len; ++i) CHECK_PTR(where+i, where[i]); + break; + case FDEFN_WIDETAG: + CHECK_PTR(where+1, where[1]); + CHECK_PTR(where+2, where[2]); + CHECK_PTR(where+3, decode_fdefn_rawfun((struct fdefn*)where)); + break; + case CLOSURE_WIDETAG: + case FUNCALLABLE_INSTANCE_WIDETAG: + // Scan the closure's trampoline word. + CHECK_PTR(where+1, fun_taggedptr_from_self(where[1])); + len = SHORT_BOXED_NWORDS(*where); + for(i=2; i<=len; ++i) CHECK_PTR(where+i, where[i]); + break; + default: + if (!leaf_obj_widetag_p(widetag_of(where))) { + int size = sizetab[widetag_of(where)](where); + for(i=1; i<size; ++i) CHECK_PTR(where+i, where[i]); + } + } + } +} + +void dump_space_to_file(lispobj* where, lispobj* limit, char* pathname) +{ + FILE *f; + f = fopen(pathname, "w"); + while (where < limit) { + fprintf(f, "%p: %x\n", where, *where); + where += object_size(where); + } + fprintf(f, "--\n"); + fclose(f); +} +#endif diff --git a/src/runtime/coalesce.c b/src/runtime/coalesce.c index ffe6fbeb7f..e4ca8f9bac 100644 --- a/src/runtime/coalesce.c +++ b/src/runtime/coalesce.c @@ -26,7 +26,6 @@ #include "immobile-space.h" #include "hopscotch.h" #include "code.h" -#include "getallocptr.h" static boolean gcable_pointer_p(lispobj pointer) { @@ -73,7 +72,7 @@ static boolean eql_comparable_p(lispobj obj) static boolean vector_isevery(boolean (*pred)(lispobj), struct vector* v) { int i; - for (i = fixnum_value(v->length)-1; i >= 0; --i) + for (i = vector_len(v)-1; i >= 0; --i) if (!pred(v->data[i])) return 0; return 1; } @@ -83,12 +82,12 @@ static boolean vector_isevery(boolean (*pred)(lispobj), struct vector* v) * updating the need-to-rehash indicator, we might create keys that compare * the same under the table's comparator. It seems like doing that could * cause various kinds of weirdness in some applications. Nobody has reported - * misbehavior in the 10 months or so that coalescing has been the default, + * misbehavior in the 3 years or so that coalescing has been the default, * so it doesn't seem horribly bad, but does seem a bit broken */ static void coalesce_obj(lispobj* where, struct hopscotch_table* ht) { lispobj ptr = *where; - if (lowtag_of(ptr) != OTHER_POINTER_LOWTAG) + if (lowtag_of(ptr) != OTHER_POINTER_LOWTAG || !gc_managed_heap_space_p(ptr)) return; extern char gc_coalesce_string_literals; @@ -96,8 +95,8 @@ static void coalesce_obj(lispobj* where, struct hopscotch_table* ht) // If 1, then we share vectors tagged as +VECTOR-SHAREABLE+, // but if >1, those and also +VECTOR-SHAREABLE-NONSTD+. int mask = gc_coalesce_string_literals > 1 - ? (VECTOR_SHAREABLE|VECTOR_SHAREABLE_NONSTD)<<N_WIDETAG_BITS - : (VECTOR_SHAREABLE )<<N_WIDETAG_BITS; + ? (VECTOR_SHAREABLE|VECTOR_SHAREABLE_NONSTD)<<ARRAY_FLAGS_POSITION + : (VECTOR_SHAREABLE )<<ARRAY_FLAGS_POSITION; lispobj* obj = native_pointer(ptr); lispobj header = *obj; @@ -109,9 +108,9 @@ static void coalesce_obj(lispobj* where, struct hopscotch_table* ht) || specialized_vector_widetag_p(widetag))) || coalescible_number_p(obj)) { if (widetag == SIMPLE_VECTOR_WIDETAG) { - sword_t n_elts = fixnum_value(obj[1]), i; - for (i = 2 ; i < n_elts+2 ; ++i) - coalesce_obj(obj + i, ht); + struct vector* v = (void*)obj; + sword_t n_elts = vector_len(v), i; + for (i = 0 ; i < n_elts ; ++i) coalesce_obj(v->data+i, ht); } int index = hopscotch_get(ht, (uword_t)obj, 0); if (!index) // Not found @@ -131,12 +130,12 @@ static void coalesce_obj(lispobj* where, struct hopscotch_table* ht) /* FIXME: there are 10+ variants of the skeleton of an object traverser. * Pick one and try to make it customizable. I tried a callback-based approach, - * but it's too slow. Next best thing is a ".inc" file which defines the shape + * but it's way too slow. Next best thing is a ".inc" file which defines the shape * of the function, with pieces inserted by #define. * * (1) gc-common's table-based mechanism * (2) gencgc's verify_range() - * (3) immobile space {fixedobj,varyobj}_points_to_younger_p() + * (3) immobile space {fixedobj,text}_points_to_younger_p() * and fixup_space() for defrag. [and the table-based thing is used too] * (4) fullcgc's trace_object() * (5) coreparse's relocate_space() @@ -148,44 +147,49 @@ static void coalesce_obj(lispobj* where, struct hopscotch_table* ht) * (10) do-referenced-object which thank goodness is common to 2 uses * and if you want to count 'print.c' as another, there's that. * There's also cheneygc's print_garbage() which uses the dispatch tables. + * And now there's update_writeprotection() which is also ad-hoc. */ static uword_t coalesce_range(lispobj* where, lispobj* limit, uword_t arg) { struct hopscotch_table* ht = (struct hopscotch_table*)arg; - lispobj layout, bitmap, *next; sword_t nwords, i; - for ( ; where < limit ; where = next ) { - lispobj header = *where; - if (is_cons_half(header)) { - coalesce_obj(where+0, ht); - coalesce_obj(where+1, ht); - next = where + 2; - } else { - int widetag = header_widetag(header); + for ( ; where < limit ; where += nwords ) { + lispobj word = *where; + if (is_header(word)) { + int widetag = header_widetag(word); nwords = sizetab[widetag](where); - next = where + nwords; + if (leaf_obj_widetag_p(widetag)) continue; // Ignore this object. + sword_t coalesce_nwords = nwords; + if (instanceoid_widetag_p(widetag)) { + lispobj layout = layout_of(where); + struct bitmap bitmap = get_layout_bitmap(LAYOUT(layout)); + for (i=0; i<(nwords-1); ++i) + if (bitmap_logbitp(i, bitmap)) coalesce_obj(where+1+i, ht); + continue; + } switch (widetag) { - case INSTANCE_WIDETAG: // mixed boxed/unboxed objects -#ifdef LISP_FEATURE_COMPACT_INSTANCE_HEADER - case FUNCALLABLE_INSTANCE_WIDETAG: -#endif - layout = instance_layout(where); - bitmap = LAYOUT(layout)->bitmap; - for(i=1; i<nwords; ++i) - if (layout_bitmap_logbitp(i-1, bitmap)) - coalesce_obj(where+i, ht); +#ifdef LISP_FEATURE_COMPACT_SYMBOL + case SYMBOL_WIDETAG: + { + struct symbol* symbol = (void*)where; + lispobj name = decode_symbol_name(symbol->name); + coalesce_obj(&name, ht); + set_symbol_name(symbol, name); continue; + } +#endif case CODE_HEADER_WIDETAG: - nwords = code_header_words((struct code*)where); + coalesce_nwords = code_header_words((struct code*)where); break; - default: - if (leaf_obj_widetag_p(widetag)) - continue; // Ignore this object. } - for(i=1; i<nwords; ++i) + for(i=1; i<coalesce_nwords; ++i) coalesce_obj(where+i, ht); + } else { + nwords = 2; + coalesce_obj(where+0, ht); + coalesce_obj(where+1, ht); } } return 0; @@ -200,19 +204,14 @@ void coalesce_similar_objects() uword_t arg = (uword_t)&ht; hopscotch_create(&ht, HOPSCOTCH_VECTOR_HASH, 0, 1<<17, 0); -#ifndef LISP_FEATURE_WIN32 - // Apparently this triggers the "Unable to recommit" lossage message - // in handle_access_violation() in src/runtime/win32-os.c - coalesce_range((lispobj*)READ_ONLY_SPACE_START, - (lispobj*)READ_ONLY_SPACE_END, - arg); - coalesce_range((lispobj*)STATIC_SPACE_START, - (lispobj*)STATIC_SPACE_END, - arg); -#endif + coalesce_range((lispobj*)READ_ONLY_SPACE_START, read_only_space_free_pointer, arg); + lispobj* the_symbol_nil = (lispobj*)(NIL - LIST_POINTER_LOWTAG - N_WORD_BYTES); + coalesce_range(the_symbol_nil, ALIGN_UP(SYMBOL_SIZE,2) + the_symbol_nil, arg); + coalesce_range((lispobj*)STATIC_SPACE_OBJECTS_START, static_space_free_pointer, arg); + #ifdef LISP_FEATURE_IMMOBILE_SPACE coalesce_range((lispobj*)FIXEDOBJ_SPACE_START, fixedobj_free_pointer, arg); - coalesce_range((lispobj*)VARYOBJ_SPACE_START, varyobj_free_pointer, arg); + coalesce_range((lispobj*)TEXT_SPACE_START, text_space_highwatermark, arg); #endif #ifdef LISP_FEATURE_GENCGC walk_generation(coalesce_range, -1, arg); diff --git a/src/runtime/code.h b/src/runtime/code.h index e23dcd04f7..df11843489 100644 --- a/src/runtime/code.h +++ b/src/runtime/code.h @@ -56,16 +56,13 @@ static inline unsigned int* code_fun_table(struct code* code) { return (unsigned int*)((char*)code + N_WORD_BYTES*code_total_nwords(code) - 4); } static inline unsigned short code_trailer_len(struct code* code) { - // Do not attempt to read the trailer len from a code page filler object. - // Fillers are recognizable by boxed_size == 0. - return code->boxed_size ? - *(unsigned short*)((char*)code + N_WORD_BYTES*code_total_nwords(code) - 2) : 0; + return *(unsigned short*)((char*)code + N_WORD_BYTES*code_total_nwords(code) - 2); } static inline unsigned short code_n_funs(struct code* code) { // Do not attempt to read the fun table size from a code object with no trailer. // If there is a nonzero trailer length, assume it is at least enough to store // the length of the fun table. - return !code_trailer_len(code) ? 0 : *(unsigned short*)code_fun_table(code) >> 4; + return !code_trailer_len(code) ? 0 : *(unsigned short*)code_fun_table(code) >> 5; } static inline char* code_text_start(struct code* code) { @@ -86,9 +83,12 @@ static inline unsigned int jumptable_count(lispobj* table) { return table ? *table & 0x3FFF : 0; } static inline unsigned int code_serialno(struct code* code) { - // extract next 18 bits regardless of machine word size lispobj* table = code_jumptable_start(code); - return table ? *table >> 14 : 0; +#ifdef LISP_FEATURE_64_BIT + return table ? *table >> 32 : 0; // high 4 bits are the serialno +#else + return table ? *table >> 14 : 0; // else it only gets 18 (= 32 - 14) bits +#endif } static inline unsigned int code_n_named_calls(struct code* code) { @@ -99,9 +99,6 @@ static inline unsigned int code_n_named_calls(struct code* code) { #endif } -// How many elements in 'code->constants[]' are taken by each simple-fun -#define CODE_SLOTS_PER_SIMPLE_FUN 4 - // Iterate over the native pointers to each function in 'code_var' // offsets are stored as the number of bytes into the instructions // portion of the code object at which the simple-fun object resides. @@ -167,7 +164,7 @@ base_pointer(lispobj ptr) return embedded_obj_p(widetag) ? fun_code_header(obj) : obj; } -#if defined LISP_FEATURE_X86 || defined LISP_FEATURE_X86_64 +#if defined LISP_FEATURE_X86 || defined LISP_FEATURE_X86_64 || defined LISP_FEATURE_ARM64 # define fun_self_from_baseptr(simple_fun) (lispobj)simple_fun->insts # define fun_self_from_taggedptr(funptr) \ funptr - FUN_POINTER_LOWTAG + 2*N_WORD_BYTES diff --git a/src/runtime/core.h b/src/runtime/core.h index 6e06524183..9033723c35 100644 --- a/src/runtime/core.h +++ b/src/runtime/core.h @@ -15,11 +15,7 @@ #include "sbcl.h" #include "runtime.h" -#ifdef LISP_FEATURE_ALPHA -typedef u32 core_entry_elt_t; -#else typedef sword_t core_entry_elt_t; -#endif struct ndir_entry { core_entry_elt_t identifier; @@ -54,7 +50,7 @@ extern os_vm_offset_t search_for_embedded_core(char *filename, * against a runtime with patches which add new C code) */ extern unsigned char build_id[]; -char* get_asm_routine_by_name(const char* name); +char* get_asm_routine_by_name(const char* name, int*); // By setting this to 0, all objects begin life in the nursery, and nothing // is pseudo-static. As such, any bugs due to code movement are likely to diff --git a/src/runtime/coreparse.c b/src/runtime/coreparse.c index cdef9b3925..d711ce9faa 100644 --- a/src/runtime/coreparse.c +++ b/src/runtime/coreparse.c @@ -40,13 +40,12 @@ #include "validate.h" #include "gc-internal.h" #include "gc-private.h" -#include "getallocptr.h" #include "code.h" #include <errno.h> #ifdef LISP_FEATURE_SB_CORE_COMPRESSION -# include <zlib.h> +# include <zstd.h> #endif /* build_id must match between the C code and .core file because a core @@ -83,7 +82,7 @@ open_binary(char *filename, int mode) return open(filename, mode); } -#if defined(LISP_FEATURE_LINUX) && defined(LISP_FEATURE_IMMOBILE_CODE) +#if defined(LISP_FEATURE_ELF) && defined(LISP_FEATURE_IMMOBILE_CODE) #define ELFCORE 1 #elif !defined(ELFCORE) #define ELFCORE 0 @@ -93,7 +92,7 @@ open_binary(char *filename, int mode) int lisp_code_in_elf() { return 0; } #else extern __attribute__((weak)) lispobj - lisp_code_start, lisp_jit_code, lisp_code_end, lisp_linkage_values; + lisp_code_start, lisp_jit_code, lisp_code_end, alien_linkage_values; int lisp_code_in_elf() { return &lisp_code_start != 0; } #endif @@ -170,83 +169,61 @@ search_for_embedded_core(char *filename, struct memsize_options *memsize_options #ifndef LISP_FEATURE_SB_CORE_COMPRESSION # define inflate_core_bytes(fd,offset,addr,len) \ - lose("This runtime was not built with zlib-compressed core support... aborting") + lose("This runtime was not built with zstd-compressed core support... aborting") #else -# define ZLIB_BUFFER_SIZE (1u<<16) static void inflate_core_bytes(int fd, os_vm_offset_t offset, os_vm_address_t addr, int len) { - z_stream stream; - unsigned char* buf = successful_malloc(ZLIB_BUFFER_SIZE); - int ret; - # ifdef LISP_FEATURE_WIN32 - /* Ensure the memory is committed so zlib doesn't segfault trying to - inflate. */ - os_validate_recommit(addr, len); + /* Ensure the memory is committed so zstd doesn't segfault trying + to inflate. */ + os_commit_memory(addr, len); # endif - - if (-1 == lseek(fd, offset, SEEK_SET)) { + if (-1 == lseek(fd, offset, SEEK_SET)) lose("Unable to lseek() on corefile"); - } - - stream.zalloc = NULL; - stream.zfree = NULL; - stream.opaque = NULL; - stream.avail_in = 0; - stream.next_in = buf; - ret = inflateInit(&stream); - if (ret != Z_OK) - lose("zlib error %i", ret); - - stream.next_out = (void*)addr; - stream.avail_out = len; + int ret; + size_t buf_size = ZSTD_DStreamInSize(); + unsigned char* buf = successful_malloc(buf_size); + ZSTD_inBuffer input; + input.src = buf; + input.pos = 0; + + ZSTD_outBuffer output; + output.dst = (void*)addr; + output.size = len; + output.pos = 0; + + ZSTD_DStream *stream = ZSTD_createDStream(); + if (stream == NULL) + lose("unable to create zstd decompression context"); + ret = ZSTD_initDStream(stream); + if (ZSTD_isError(ret)) + lose("ZSTD_initDStream failed with error: %s", ZSTD_getErrorName(ret)); + + /* Read in exactly one frame. */ do { - ssize_t count = read(fd, buf, ZLIB_BUFFER_SIZE); + ssize_t count = read(fd, buf, buf_size); if (count < 0) lose("unable to read core file (errno = %i)", errno); - stream.next_in = buf; - stream.avail_in = count; - if (count == 0) break; - ret = inflate(&stream, Z_NO_FLUSH); - switch (ret) { - case Z_STREAM_END: - break; - case Z_OK: - if (stream.avail_out == 0) - lose("Runaway gzipped core directory... aborting"); - if (stream.avail_in > 0) - lose("zlib inflate returned without fully" - "using up input buffer... aborting"); - break; - default: - lose("zlib inflate error: %i", ret); - break; - } - } while (ret != Z_STREAM_END); - - if (stream.avail_out > 0) { - if (stream.avail_out >= os_vm_page_size) - fprintf(stderr, "Warning: gzipped core directory significantly" - "shorter than expected (%lu bytes)", (unsigned long)stream.avail_out); - /* Is this needed? */ - memset(stream.next_out, 0, stream.avail_out); - } - - inflateEnd(&stream); - free(buf); + input.size = count; + input.pos = 0; + ret = ZSTD_decompressStream(stream, &output, &input); + if (ZSTD_isError(ret)) + lose("ZSTD_decompressStream failed with error: %s", + ZSTD_getErrorName(ret)); + } while (ret != 0); + + ZSTD_freeDStream(stream); } -# undef ZLIB_BUFFER_SIZE #endif -#define DYNAMIC_SPACE_ADJ_INDEX 0 +#define MAX_SPACE_RELOCATION_RANGES 4 struct heap_adjust { - /* range[0] is dynamic space, ranges[1] and [2] are immobile spaces */ struct range { lispobj start, end; sword_t delta; - } range[3]; + } range[MAX_SPACE_RELOCATION_RANGES]; int n_ranges; int n_relocs_abs; // absolute int n_relocs_rel; // relative @@ -260,35 +237,46 @@ struct heap_adjust { static inline sword_t calc_adjustment(struct heap_adjust* adj, lispobj x) { - if (adj->range[0].start <= x && x < adj->range[0].end) - return adj->range[0].delta; -#ifdef LISP_FEATURE_IMMOBILE_SPACE - if (adj->range[1].start <= x && x < adj->range[1].end) - return adj->range[1].delta; - if (adj->range[2].start <= x && x < adj->range[2].end) - return adj->range[2].delta; -#endif + int j; + for (j = adj->n_ranges - 1 ; j >= 0 ; --j) + if (adj->range[j].start <= x && x < adj->range[j].end) return adj->range[j].delta; return 0; } -// Return the adjusted value of 'word' without testing whether it looks -// like a pointer. But do test whether it points to a relocatable space. -static inline lispobj adjust_word(struct heap_adjust* adj, lispobj word) { - return word + calc_adjustment(adj, word); -} - // Given a post-relocation object 'x', compute the address at which // it was originally expected to have been placed as per the core file. static inline lispobj inverse_adjust(struct heap_adjust* adj, lispobj x) { int j; - for (j=0; j<3; ++j) + for (j = adj->n_ranges - 1 ; j >= 0 ; --j) if (adj->range[j].start + adj->range[j].delta <= x && x < adj->range[j].end + adj->range[j].delta) return x - adj->range[j].delta; return x; } +// Return the adjusted value of 'word' without testing whether it looks +// like a pointer. But do test whether it points to a relocatable space. +static inline lispobj adjust_word(struct heap_adjust* adj, lispobj word) { + return word + calc_adjustment(adj, word); +} + +static void +set_adjustment(struct heap_adjust* adj, + uword_t actual_addr, + uword_t desired_addr, + uword_t len) +{ + sword_t delta = len ? actual_addr - desired_addr : 0; + if (!delta) return; + int j = adj->n_ranges; + gc_assert(j < MAX_SPACE_RELOCATION_RANGES); + adj->range[j].start = (lispobj)desired_addr; + adj->range[j].end = (lispobj)desired_addr + len; + adj->range[j].delta = delta; + adj->n_ranges = j+1; +} + #define SHOW_SPACE_RELOCATION 0 #if SHOW_SPACE_RELOCATION > 1 # define FIXUP(expr, addr) fprintf(stderr, "%p: (a) %lx", addr, *(long*)(addr)), \ @@ -383,32 +371,31 @@ static inline void fix_fun_header_layout(lispobj __attribute__((unused)) *fun, struct heap_adjust __attribute__((unused)) *adj) { #if defined(LISP_FEATURE_COMPACT_INSTANCE_HEADER) && defined(LISP_FEATURE_64_BIT) - lispobj ptr = function_layout(fun); + lispobj ptr = funinstance_layout(fun); lispobj adjusted = adjust_word(adj, ptr); - if (adjusted != ptr) - FIXUP(set_function_layout(fun, adjusted), fun); + if (adjusted != ptr) FIXUP(funinstance_layout(fun)=adjusted, fun); #endif } static void relocate_space(uword_t start, lispobj* end, struct heap_adjust* adj) { lispobj *where = (lispobj*)start; - lispobj header_word; int widetag; long nwords; - lispobj layout, adjusted_layout, bitmap; + lispobj layout, adjusted_layout; struct code* code; sword_t delta; + int i; adj->n_relocs_abs = adj->n_relocs_rel = 0; for ( ; where < end ; where += nwords ) { - header_word = *where; - if (is_cons_half(header_word)) { + lispobj word = *where; + if (!is_header(word)) { adjust_pointers(where, 2, adj); nwords = 2; continue; } - widetag = header_widetag(header_word); + widetag = header_widetag(word); nwords = sizetab[widetag](where); switch (widetag) { case FUNCALLABLE_INSTANCE_WIDETAG: @@ -418,33 +405,30 @@ static void relocate_space(uword_t start, lispobj* end, struct heap_adjust* adj) // - Otherwise, the word might point to a relocated range, // either the instance itself, or a trampoline in immobile space. adjust_word_at(where+1, adj); + /* FALLTHROUGH */ case INSTANCE_WIDETAG: - layout = (widetag == FUNCALLABLE_INSTANCE_WIDETAG) ? - funinstance_layout(where) : instance_layout(where); + layout = layout_of(where); adjusted_layout = adjust_word(adj, layout); - // Do not alter the layout as stored in the instance if non-compact - // header. instance_scan() will do it if necessary. -#ifdef LISP_FEATURE_COMPACT_INSTANCE_HEADER - if (adjusted_layout != layout) - instance_layout(where) = adjusted_layout; -#endif - bitmap = LAYOUT(adjusted_layout)->bitmap; - gc_assert(fixnump(bitmap) - || widetag_of(native_pointer(bitmap))==BIGNUM_WIDETAG); - // If the post-adjustment address of 'layout' is higher than 'where', - // then the layout's pointer slots need adjusting. - // This is true regardless of whether the core was mapped at a higher - // or lower address than desired. - if (is_lisp_pointer(bitmap) && adjusted_layout > (lispobj)where) { - // Do not write back the adjusted bitmap pointer. Each heap word - // must be touched at most once. When the layout itself gets scanned, - // the bitmap slot will be rewritten if needed. - bitmap = adjust_word(adj, bitmap); + // writeback the layout if it changed. The layout is not a tagged slot + // so it would not be fixed up otherwise. + if (adjusted_layout != layout) layout_of(where) = adjusted_layout; + struct bitmap bitmap = get_layout_bitmap(LAYOUT(adjusted_layout)); + lispobj* slots = where+1; + for (i=0; i<(nwords-1); ++i) + if (bitmap_logbitp(i, bitmap)) adjust_pointers(slots+i, 1, adj); + continue; +#ifdef LISP_FEATURE_COMPACT_SYMBOL + case SYMBOL_WIDETAG: + { // Copied from scav_symbol() in gc-common + struct symbol* s = (void*)where; + adjust_pointers(&s->value, 3, adj); // value, function, info + lispobj name = decode_symbol_name(s->name); + lispobj adjusted_name = adjust_word(adj, name); + // writeback the name if it changed + if (adjusted_name != name) FIXUP(set_symbol_name(s, adjusted_name), &s->name); } - - instance_scan((void(*)(lispobj*,sword_t,uword_t))adjust_pointers, - where+1, nwords-1, bitmap, (uintptr_t)adj); continue; +#endif case FDEFN_WIDETAG: adjust_pointers(where+1, 2, adj); // For most architectures, 'raw_addr' doesn't satisfy is_lisp_pointer() @@ -453,19 +437,22 @@ static void relocate_space(uword_t start, lispobj* end, struct heap_adjust* adj) adjust_word_at(where+3, adj); continue; case CODE_HEADER_WIDETAG: - if (filler_obj_p(where)) { - if (where[2]) adjust_word_at(where+2, adj); - continue; - } // Fixup the constant pool. The word at where+1 is a fixnum. code = (struct code*)where; adjust_pointers(where+2, code_header_words(code)-2, adj); +#ifdef LISP_FEATURE_UNTAGGED_FDEFNS + // Process each untagged fdefn pointer. + lispobj* fdefns_start = code->constants + code_n_funs(code) + * CODE_SLOTS_PER_SIMPLE_FUN; + int i; + for (i=code_n_named_calls(code)-1; i>=0; --i) + adjust_word_at(fdefns_start+i, adj); +#endif #if defined LISP_FEATURE_X86 || defined LISP_FEATURE_X86_64 || \ defined LISP_FEATURE_PPC || defined LISP_FEATURE_PPC64 // Fixup absolute jump table lispobj* jump_table = code_jumptable_start(code); int count = jumptable_count(jump_table); - int i; for (i = 1; i < count; ++i) adjust_word_at(jump_table+i, adj); #endif // Fixup all embedded simple-funs @@ -490,8 +477,8 @@ static void relocate_space(uword_t start, lispobj* end, struct heap_adjust* adj) continue; case CLOSURE_WIDETAG: fix_fun_header_layout(where, adj); -#if defined(LISP_FEATURE_X86) || defined(LISP_FEATURE_X86_64) - // For x86[-64], the closure fun appears to be a fixnum, +#if FUN_SELF_FIXNUM_TAGGED + // For x86[-64], arm64, the closure fun appears to be a fixnum, // and might need adjustment unless pointing to immobile code. // Then fall into the general case; where[1] won't get re-adjusted // because it doesn't satisfy is_lisp_pointer(). @@ -500,13 +487,13 @@ static void relocate_space(uword_t start, lispobj* end, struct heap_adjust* adj) break; // Vectors require extra care because of address-based hashing. case SIMPLE_VECTOR_WIDETAG: - if (is_vector_subtype(*where, VectorAddrHashing)) { + if (vector_flagp(*where, VectorAddrHashing)) { struct vector* v = (struct vector*)where; // If you could make a hash-table vector with space for exactly 1 k/v pair, // it would have length 5. - gc_assert(v->length >= make_fixnum(5)); + gc_assert(vector_len(v) >= 5); // KLUDGE: need a manifest constant for fixed overhead lispobj* data = (lispobj*)v->data; - adjust_pointers(&data[fixnum_value(v->length)-1], 1, adj); + adjust_pointers(&data[vector_len(v)-1], 1, adj); int hwm = KV_PAIRS_HIGH_WATER_MARK(data); boolean needs_rehash = 0; lispobj *where = &data[2], *end = &data[2*(hwm+1)]; @@ -535,12 +522,13 @@ static void relocate_space(uword_t start, lispobj* end, struct heap_adjust* adj) case COMPLEX_CHARACTER_STRING_WIDETAG: #endif case COMPLEX_BASE_STRING_WIDETAG: - case COMPLEX_VECTOR_NIL_WIDETAG: case COMPLEX_BIT_VECTOR_WIDETAG: case COMPLEX_VECTOR_WIDETAG: case COMPLEX_ARRAY_WIDETAG: // And the rest of the purely descriptor objects. +#ifndef LISP_FEATURE_COMPACT_SYMBOL case SYMBOL_WIDETAG: +#endif case VALUE_CELL_WIDETAG: case WEAK_POINTER_WIDETAG: case RATIO_WIDETAG: @@ -569,19 +557,20 @@ static void relocate_space(uword_t start, lispobj* end, struct heap_adjust* adj) #ifdef SIMD_PACK_256_WIDETAG case SIMD_PACK_256_WIDETAG: #endif + case FILLER_WIDETAG: // non-card-spanning object pages container fillers continue; default: if (other_immediate_lowtag_p(widetag) && specialized_vector_widetag_p(widetag)) continue; else - lose("Unrecognized heap object: @%p: %"OBJ_FMTX, where, header_word); + lose("Unrecognized heap object: @%p: %"OBJ_FMTX, where, *where); } adjust_pointers(where+1, nwords-1, adj); } #if SHOW_SPACE_RELOCATION - fprintf(stderr, "space @ %p: fixed %d absolute + %d relative pointers\n", - (lispobj*)start, adj->n_relocs_abs, adj->n_relocs_rel); + fprintf(stderr, "space @ %p..%p: fixed %d absolute + %d relative pointers\n", + (lispobj*)start, end, adj->n_relocs_abs, adj->n_relocs_rel); #endif } @@ -597,41 +586,18 @@ static void relocate_heap(struct heap_adjust* adj) (char*)adj->range[i].start + adj->range[i].delta, (char*)adj->range[i].end + adj->range[i].delta); } - relocate_space(STATIC_SPACE_START, static_space_free_pointer, adj); + relocate_space(NIL_SYMBOL_SLOTS_START, (lispobj*)NIL_SYMBOL_SLOTS_END, adj); + relocate_space(STATIC_SPACE_OBJECTS_START, static_space_free_pointer, adj); #ifdef LISP_FEATURE_IMMOBILE_SPACE relocate_space(FIXEDOBJ_SPACE_START, fixedobj_free_pointer, adj); #endif -#ifdef LISP_FEATURE_CHENEYGC - relocate_space(DYNAMIC_0_SPACE_START, (lispobj*)get_alloc_pointer(), adj); -#else - relocate_space(DYNAMIC_SPACE_START, (lispobj*)get_alloc_pointer(), adj); -#endif + relocate_space(DYNAMIC_SPACE_START, (lispobj*)dynamic_space_highwatermark(), + adj); #ifdef LISP_FEATURE_IMMOBILE_SPACE - // Pointers within varyobj space to varyobj space do not need adjustment - // so remove any delta before performing the relocation pass on this space. - // FIXME: this was probably for PIE mode, which doesn't work. - if (lisp_code_in_elf() && adj->range[2].delta != 0) { - lose("code-in-elf + PIE not supported yet\n"); - adj->range[2].delta = 0; // FIXME: isn't this this already the case? - } - relocate_space(VARYOBJ_SPACE_START, varyobj_free_pointer, adj); + relocate_space(TEXT_SPACE_START, text_space_highwatermark, adj); #endif } -static void -set_adjustment(struct heap_adjust* adj, - uword_t actual_addr, - uword_t desired_addr, - uword_t len) -{ - int j = adj->n_ranges; - gc_assert(j <= 2); - adj->range[j].start = (lispobj)desired_addr; - adj->range[j].end = (lispobj)desired_addr + len; - adj->range[j].delta = actual_addr - desired_addr; - adj->n_ranges = j+1; -} - #if defined(LISP_FEATURE_ELF) && defined(LISP_FEATURE_IMMOBILE_SPACE) extern int apply_pie_relocs(long,long,int); #else @@ -641,14 +607,20 @@ set_adjustment(struct heap_adjust* adj, /// Compute the bounds of the lisp assembly routine code object void calc_asm_routine_bounds() { -#ifdef LISP_FEATURE_IMMOBILE_SPACE - asm_routines_start = VARYOBJ_SPACE_START; +#ifdef LISP_FEATURE_METASPACE + if (widetag_of((lispobj*)READ_ONLY_SPACE_START) == CODE_HEADER_WIDETAG) + asm_routines_start = READ_ONLY_SPACE_START; + else + asm_routines_start = READ_ONLY_SPACE_START + (256+2)*N_WORD_BYTES; +#elif defined LISP_FEATURE_IMMOBILE_CODE + asm_routines_start = TEXT_SPACE_START; #else - if (widetag_of((lispobj*)READ_ONLY_SPACE_START) == CODE_HEADER_WIDETAG) { + if ((uword_t)read_only_space_free_pointer > READ_ONLY_SPACE_START && + widetag_of((lispobj*)READ_ONLY_SPACE_START) == CODE_HEADER_WIDETAG) { asm_routines_start = READ_ONLY_SPACE_START; } else { - lispobj *where = (lispobj*)STATIC_SPACE_START; - for (; where < static_space_free_pointer; where += OBJECT_SIZE(*where, where)) + lispobj *where = (lispobj*)STATIC_SPACE_OBJECTS_START; + for (; where < static_space_free_pointer; where += object_size(where)) if (widetag_of((lispobj*)where) == CODE_HEADER_WIDETAG) { asm_routines_start = (uword_t)where; break; @@ -665,7 +637,7 @@ void calc_immobile_space_bounds() { /* Suppose we have: * A B C D - * | varyobj space | .... other random stuff ... | fixedobj space | ... + * | text space | .... other random stuff ... | fixedobj space | ... * then the lower bound is A, the upper bound is D, * the max_offset is the distance from A to D, * and the excluded middle is the range spanned by B to C. @@ -676,7 +648,7 @@ void calc_immobile_space_bounds() struct range range1 = {FIXEDOBJ_SPACE_START, FIXEDOBJ_SPACE_START + FIXEDOBJ_SPACE_SIZE}; struct range range2 = - {VARYOBJ_SPACE_START, VARYOBJ_SPACE_START + varyobj_space_size}; + {TEXT_SPACE_START, TEXT_SPACE_START + text_space_size}; if (range2.start < range1.start) { // swap struct range temp = range1; range1 = range2; @@ -689,6 +661,38 @@ void calc_immobile_space_bounds() } #endif +__attribute__((unused)) static void check_dynamic_space_addr_ok(uword_t start, uword_t size) +{ +#ifdef LISP_FEATURE_64_BIT // don't want a -Woverflow warning on 32-bit + uword_t end_word_addr = start + size - N_WORD_BYTES; + // Word-aligned pointers can't address more than 48 significant bits for now. + // If you want to lift that restriction, look at how SYMBOL-PACKAGE and + // SYMBOL-NAME are combined into one lispword. + uword_t unaddressable_bits = 0xFFFF000000000000; + if ((start & unaddressable_bits) || (end_word_addr & unaddressable_bits)) + lose("Panic! This version of SBCL can not address memory\n" + "in the range %p:%p given by the OS.\nPlease report this as a bug.", + (void*)start, (void*)(start + size)); +#endif +} + +static os_vm_address_t reserve_space(int space_id, int attr, + os_vm_address_t addr, os_vm_size_t size) +{ +#ifdef LISP_FEATURE_IMMOBILE_SPACE + if (space_id == IMMOBILE_TEXT_CORE_SPACE_ID) { + // Carve out the text space from the earlier request that was made + // for the fixedobj space. + ALIEN_LINKAGE_TABLE_SPACE_START = FIXEDOBJ_SPACE_START + FIXEDOBJ_SPACE_SIZE; + return (os_vm_address_t)(ALIEN_LINKAGE_TABLE_SPACE_START + ALIEN_LINKAGE_TABLE_SPACE_SIZE); + } +#endif + if (size == 0) return addr; + addr = os_alloc_gc_space(space_id, attr, addr, size); + if (!addr) lose("Can't allocate %#"OBJ_FMTX" bytes for space %d", size, space_id); + return addr; +} + /* TODO: If static + readonly were mapped as desired without disabling ASLR * but one of the large spaces couldn't be mapped as desired, start over from * the top, disabling ASLR. This should help to avoid relocating the heap @@ -712,69 +716,46 @@ process_directory(int count, struct ndir_entry *entry, lispobj** pfree_pointer; // pointer to x_free_pointer } spaces[MAX_CORE_SPACE_ID+1] = { {0, 0, 0, 0}, // blank for space ID 0 -#ifdef LISP_FEATURE_GENCGC {dynamic_space_size, 0, DYNAMIC_SPACE_START, 0}, -#else - // Whatever address the core's dynamic space has - // becomes subspace 0. The other is subspace 1. - // It makes no difference which has the lower address. - {dynamic_space_size, 0, DYNAMIC_0_SPACE_START, 0}, -#endif // This order is determined by constants in compiler/generic/genesis {0, 0, STATIC_SPACE_START, &static_space_free_pointer}, + {0, 0, READ_ONLY_SPACE_START, &read_only_space_free_pointer}, + +#ifdef LISP_FEATURE_DARWIN_JIT + {0, 0, STATIC_CODE_SPACE_START, &static_code_space_free_pointer}, +#endif + #ifdef LISP_FEATURE_IMMOBILE_SPACE {FIXEDOBJ_SPACE_SIZE | 1, 0, FIXEDOBJ_SPACE_START, &fixedobj_free_pointer}, - {1, 0, VARYOBJ_SPACE_START, &varyobj_free_pointer} + {1, 0, TEXT_SPACE_START, &text_space_highwatermark} #endif }; #if ELFCORE if (&lisp_code_start) { - VARYOBJ_SPACE_START = (uword_t)&lisp_code_start; - varyobj_free_pointer = &lisp_jit_code; - varyobj_space_size = (uword_t)&lisp_code_end - VARYOBJ_SPACE_START; - spaces[IMMOBILE_VARYOBJ_CORE_SPACE_ID].len = varyobj_space_size; - if (varyobj_free_pointer < (lispobj*)VARYOBJ_SPACE_START + TEXT_SPACE_START = (uword_t)&lisp_code_start; + text_space_highwatermark = &lisp_jit_code; + text_space_size = (uword_t)&lisp_code_end - TEXT_SPACE_START; + spaces[IMMOBILE_TEXT_CORE_SPACE_ID].len = text_space_size; + if (text_space_highwatermark < (lispobj*)TEXT_SPACE_START || !PTR_IS_ALIGNED(&lisp_code_end, 4096)) lose("ELF core alignment bug. Check for proper padding in 'editcore'"); #ifdef DEBUG_COREPARSE printf("Lisp code present in executable @ %lx:%lx (freeptr=%p)\n", (uword_t)&lisp_code_start, (uword_t)&lisp_code_end, - varyobj_free_pointer); + text_space_highwatermark); #endif - // Prefill the Lisp linkage table so that shrinkwrapped executables which link in - // all their C library dependencies can avoid linking with -ldl. - // All data references are potentially needed because aliencomp doesn't emit - // SAP-REF-n in a way that admits elision of the linkage entry. e.g. - // MOV RAX, [#x20200AA0] ; some_c_symbol - // MOV RAX, [RAX] - // might be rendered as - // MOV RAX, some_c_symbol(%rip) - // but that's more of a change to the asm instructions than I'm comfortable making; - // whereas "CALL linkage_entry_for_f" -> "CALL f" is quite straightforward. - // (Rarely would a jmp indirection be used; maybe for newly compiled code?) - lispobj* ptr = &lisp_linkage_values; - gc_assert(ptr); - int entry_index = 0; - int count; - extern int lisp_linkage_table_n_prelinked; - count = lisp_linkage_table_n_prelinked = *ptr++; - for ( ; count-- ; entry_index++ ) { - boolean datap = *ptr == (lispobj)-1; // -1 can't be a function address - if (datap) - ++ptr; - arch_write_linkage_table_entry(entry_index, (void*)*ptr++, datap); - } - + os_link_from_pointer_table(&alien_linkage_values); // unprotect the pages - os_protect((void*)VARYOBJ_SPACE_START, varyobj_space_size, OS_VM_PROT_ALL); + os_protect((void*)TEXT_SPACE_START, text_space_size, OS_VM_PROT_ALL); } else #endif #ifdef LISP_FEATURE_IMMOBILE_SPACE { - spaces[IMMOBILE_FIXEDOBJ_CORE_SPACE_ID].desired_size += VARYOBJ_SPACE_SIZE; + spaces[IMMOBILE_FIXEDOBJ_CORE_SPACE_ID].desired_size += + TEXT_SPACE_SIZE + ALIEN_LINKAGE_TABLE_SPACE_SIZE; } #endif @@ -791,30 +772,20 @@ process_directory(int count, struct ndir_entry *entry, if (id < 1 || id > MAX_CORE_SPACE_ID) lose("unknown space ID %ld addr %p", id, (void*)addr); -#ifdef LISP_FEATURE_IMMOBILE_SPACE - // Enforce address of readonly, static, immobile varyobj - int enforce_address = id != DYNAMIC_CORE_SPACE_ID - && id != IMMOBILE_FIXEDOBJ_CORE_SPACE_ID - && id != IMMOBILE_VARYOBJ_CORE_SPACE_ID; +#ifdef LISP_FEATURE_DARWIN_JIT + int enforce_address = (id == STATIC_CORE_SPACE_ID) || (id == READ_ONLY_CORE_SPACE_ID); #else - // Enforce address of readonly and static spaces. - int enforce_address = id != DYNAMIC_CORE_SPACE_ID; + int enforce_address = id == STATIC_CORE_SPACE_ID; #endif // We'd like to enforce proper alignment of 'addr' but there's // a problem: dynamic space has a stricter requirement (usually 32K) // than code space (4K). So don't assert the alignment. - if (enforce_address) { - int fail; - if ((fail = (addr != spaces[id].base)) != 0) - fprintf(stderr, "in core: %p; in runtime: %p\n", - (void*)addr, (void*)spaces[id].base); - char *names[] = { - "DYNAMIC", "STATIC", "READ_ONLY", "IMMOBILE", "IMMOBILE" - }; - if (fail) - lose("core/runtime address mismatch: %s_SPACE_START", names[id-1]); - } + if (enforce_address && addr != spaces[id].base) + lose("core address mismatch: %s_SPACE_START=%p but runtime expects %p\n", + id==READ_ONLY_CORE_SPACE_ID?"READ_ONLY":"STATIC", + (void*)addr, (void*)spaces[id].base); + spaces[id].base = addr; uword_t len = os_vm_page_size * entry->page_count; if (id == DYNAMIC_CORE_SPACE_ID && len > dynamic_space_size) { @@ -822,82 +793,76 @@ process_directory(int count, struct ndir_entry *entry, (unsigned long)len >> 10, (unsigned long)dynamic_space_size >> 10); } +#ifndef LISP_FEATURE_DARWIN_JIT + if (id == READ_ONLY_CORE_SPACE_ID) { + if (len) // There is no "nominal" size of readonly space, so give it a size + spaces[id].desired_size = len; + else // Assign some address, so free_pointer does enclose [0 .. addr+0] + READ_ONLY_SPACE_START = READ_ONLY_SPACE_END = addr; + } +#endif if (len != 0) { spaces[id].len = len; // Try to map at address requested by the core file. size_t request = spaces[id].desired_size; int sub_2gb_flag = (request & 1); request &= ~(size_t)1; -#ifdef LISP_FEATURE_IMMOBILE_SPACE - if (id == IMMOBILE_VARYOBJ_CORE_SPACE_ID) - // Pretend an os_validate() happened based on the address that - // would be obtained by a constant offset from fixedobj space - addr = FIXEDOBJ_SPACE_START + FIXEDOBJ_SPACE_SIZE; - else -#endif - if (request) { - addr = (uword_t)os_validate(sub_2gb_flag ? MOVABLE_LOW : MOVABLE, - (os_vm_address_t)addr, request); - if (!addr) { - lose("Can't allocate %#"OBJ_FMTX" bytes for space %ld", - (lispobj)request, id); - } - } + addr = (uword_t)reserve_space(id, sub_2gb_flag ? MOVABLE_LOW : MOVABLE, + (os_vm_address_t)addr, request); switch (id) { +#ifndef LISP_FEATURE_DARWIN_JIT + case READ_ONLY_CORE_SPACE_ID: + READ_ONLY_SPACE_START = addr; + READ_ONLY_SPACE_END = addr + len; + break; +#endif #ifdef LISP_FEATURE_IMMOBILE_SPACE case IMMOBILE_FIXEDOBJ_CORE_SPACE_ID: - case IMMOBILE_VARYOBJ_CORE_SPACE_ID: + case IMMOBILE_TEXT_CORE_SPACE_ID: if (addr + request > 0x80000000) lose("Won't map immobile space above 2GB"); if (id == IMMOBILE_FIXEDOBJ_CORE_SPACE_ID) FIXEDOBJ_SPACE_START = addr; else - VARYOBJ_SPACE_START = addr; + TEXT_SPACE_START = addr; break; #endif case DYNAMIC_CORE_SPACE_ID: -#ifdef LISP_FEATURE_CHENEYGC { - uword_t semispace_0_start = ALIGN_UP(addr, BACKEND_PAGE_BYTES); - uword_t semispace_0_end = ALIGN_DOWN(addr + request, BACKEND_PAGE_BYTES); - // assign to 'addr' too, because that's where we load the core file - DYNAMIC_0_SPACE_START = addr = semispace_0_start; - current_dynamic_space = (lispobj*)addr; - // Request that much again now -#ifdef LISP_FEATURE_ALPHA /* meaning: is this a 32-on-64 SBCL implementation */ - uword_t addr1 = (uword_t)os_validate(MOVABLE_LOW, 0, request); - extern os_set_cheneygc_spaces(uword_t,uword_t); - os_set_cheneygc_spaces(addr, addr1); -#else - uword_t addr1 = (uword_t)os_allocate(request); -#endif - uword_t semispace_1_start = ALIGN_UP(addr1, BACKEND_PAGE_BYTES); - uword_t semispace_1_end = ALIGN_DOWN(addr1 + request, BACKEND_PAGE_BYTES); - - DYNAMIC_1_SPACE_START = semispace_1_start; - uword_t semispace_0_size = semispace_0_end - semispace_0_start; - uword_t semispace_1_size = semispace_1_end - semispace_1_start; - dynamic_space_size = - semispace_0_size < semispace_1_size ? semispace_0_size : semispace_1_size; - } -#else /* gencgc */ - { - uword_t aligned_start = ALIGN_UP(addr, GENCGC_CARD_BYTES); - /* Misalignment can happen only if card size exceeds OS page. - * Drop one card to avoid overrunning the allocated space */ + uword_t aligned_start = ALIGN_UP(addr, GENCGC_PAGE_BYTES); + /* Misalignment can happen only if GC page size exceeds OS page. + * Drop one GC page to avoid overrunning the allocated space */ if (aligned_start > addr) // not card-aligned - dynamic_space_size -= GENCGC_CARD_BYTES; + dynamic_space_size -= GENCGC_PAGE_BYTES; DYNAMIC_SPACE_START = addr = aligned_start; + check_dynamic_space_addr_ok(addr, dynamic_space_size); } -#endif break; } sword_t offset = os_vm_page_size * (1 + entry->data_page); - if (compressed) + if (compressed) { +#ifdef LISP_FEATURE_DARWIN_JIT + if (id == READ_ONLY_CORE_SPACE_ID) + os_protect((os_vm_address_t)addr, len, OS_VM_PROT_WRITE); +#endif inflate_core_bytes(fd, offset + file_offset, (os_vm_address_t)addr, len); + +#ifdef LISP_FEATURE_DARWIN_JIT + if (id == READ_ONLY_CORE_SPACE_ID) + os_protect((os_vm_address_t)addr, len, OS_VM_PROT_READ | OS_VM_PROT_EXECUTE); +#endif + + } else - load_core_bytes(fd, offset + file_offset, (os_vm_address_t)addr, len); +#ifdef LISP_FEATURE_DARWIN_JIT + if (id == DYNAMIC_CORE_SPACE_ID || id == STATIC_CODE_CORE_SPACE_ID) { + load_core_bytes_jit(fd, offset + file_offset, (os_vm_address_t)addr, len); + } else +#endif + { + load_core_bytes(fd, offset + file_offset, (os_vm_address_t)addr, len, id == READ_ONLY_CORE_SPACE_ID); + } } #ifdef MADV_MERGEABLE @@ -910,70 +875,63 @@ process_directory(int count, struct ndir_entry *entry, lispobj *free_pointer = (lispobj *) addr + entry->nwords; switch (id) { default: - // varyobj free ptr is already nonzero if Lisp code in executable + // text free ptr is already nonzero if Lisp code in executable if (!*spaces[id].pfree_pointer) *spaces[id].pfree_pointer = free_pointer; break; case DYNAMIC_CORE_SPACE_ID: -#ifdef LISP_FEATURE_CHENEYGC - /* 'addr' is the actual address if relocatable. - * For cheneygc, this will be whatever the GC was using - * at the time the core was saved. - * For gencgc this is #defined as DYNAMIC_SPACE_START */ - current_dynamic_space = (lispobj *)addr; -#endif - set_alloc_pointer((lispobj)free_pointer); - + next_free_page = ALIGN_UP(entry->nwords<<WORD_SHIFT, GENCGC_PAGE_BYTES) + / GENCGC_PAGE_BYTES; anon_dynamic_space_start = (os_vm_address_t)(addr + len); } } calc_asm_routine_bounds(); -# ifdef LISP_FEATURE_GENCGC +#ifndef LISP_FEATURE_DARWIN_JIT + set_adjustment(adj, READ_ONLY_SPACE_START, // actual + spaces[READ_ONLY_CORE_SPACE_ID].base, // expected + spaces[READ_ONLY_CORE_SPACE_ID].len); +#endif set_adjustment(adj, DYNAMIC_SPACE_START, // actual spaces[DYNAMIC_CORE_SPACE_ID].base, // expected spaces[DYNAMIC_CORE_SPACE_ID].len); -# ifdef LISP_FEATURE_IMMOBILE_SPACE +#ifdef LISP_FEATURE_IMMOBILE_SPACE + if (lisp_code_in_elf() && TEXT_SPACE_START != spaces[IMMOBILE_TEXT_CORE_SPACE_ID].base) { + lose("code-in-elf + PIE not supported"); + } set_adjustment(adj, FIXEDOBJ_SPACE_START, // actual spaces[IMMOBILE_FIXEDOBJ_CORE_SPACE_ID].base, // expected spaces[IMMOBILE_FIXEDOBJ_CORE_SPACE_ID].len); - if (!apply_pie_relocs(VARYOBJ_SPACE_START - - spaces[IMMOBILE_VARYOBJ_CORE_SPACE_ID].base, + if (!apply_pie_relocs(TEXT_SPACE_START + - spaces[IMMOBILE_TEXT_CORE_SPACE_ID].base, DYNAMIC_SPACE_START - spaces[DYNAMIC_CORE_SPACE_ID].base, fd)) - set_adjustment(adj, VARYOBJ_SPACE_START, // actual - spaces[IMMOBILE_VARYOBJ_CORE_SPACE_ID].base, // expected - spaces[IMMOBILE_VARYOBJ_CORE_SPACE_ID].len); -# endif -# else - set_adjustment(adj, DYNAMIC_0_SPACE_START, // actual - spaces[DYNAMIC_CORE_SPACE_ID].base, // expected - spaces[DYNAMIC_CORE_SPACE_ID].len); -# endif // LISP_FEATURE_GENCGC - if (adj->range[0].delta | adj->range[1].delta | adj->range[2].delta) { - relocate_heap(adj); - } + set_adjustment(adj, TEXT_SPACE_START, // actual + spaces[IMMOBILE_TEXT_CORE_SPACE_ID].base, // expected + spaces[IMMOBILE_TEXT_CORE_SPACE_ID].len); +#endif + if (adj->n_ranges) relocate_heap(adj); #ifdef LISP_FEATURE_IMMOBILE_SPACE - /* Now determine page characteristics (such as object spacing) - * after relocation, because we need to know which objects are layouts - * based on knowing layout-of-layout. The test for that is dependent - * on what it's address should be, not what it was in the file */ + /* Now determine page characteristics such as object spacing + * (tbh it would be better to output the immobile-space page tables to the core file). + * This used to depend critically on space relocation already having been performed. + * It doesn't any more, but this is an OK time to do it */ immobile_space_coreparse(spaces[IMMOBILE_FIXEDOBJ_CORE_SPACE_ID].len, - spaces[IMMOBILE_VARYOBJ_CORE_SPACE_ID].len); + spaces[IMMOBILE_TEXT_CORE_SPACE_ID].len); calc_immobile_space_bounds(); #endif #ifdef LISP_FEATURE_X86_64 tune_asm_routines_for_microarch(); // before WPing immobile space #endif +#ifdef LISP_FEATURE_DARWIN_JIT + if (!static_code_space_free_pointer) + static_code_space_free_pointer = (lispobj *)STATIC_CODE_SPACE_START; +#endif } -#ifdef LISP_FEATURE_GENCGC -extern void gc_load_corefile_ptes(core_entry_elt_t, core_entry_elt_t, - off_t offset, int fd); -#else -#define gc_load_corefile_ptes(dummy1,dummy2,dummy3,dummy4) -#endif +extern void gc_load_corefile_ptes(int, core_entry_elt_t, core_entry_elt_t, + os_vm_offset_t offset, int fd); static void sanity_check_loaded_core(lispobj); @@ -1035,8 +993,9 @@ load_core_file(char *file, os_vm_offset_t file_offset, int merge_core_pages) merge_core_pages, &adj); break; case PAGE_TABLE_CORE_ENTRY_TYPE_CODE: - gc_load_corefile_ptes(ptr[0], ptr[1], - file_offset + (ptr[2] + 1) * os_vm_page_size, fd); + // elements = gencgc-card-table-index-nbits, n-ptes, nbytes, data-page + gc_load_corefile_ptes(ptr[0], ptr[1], ptr[2], + file_offset + (ptr[3] + 1) * os_vm_page_size, fd); break; case INITIAL_FUN_CORE_ENTRY_TYPE_CODE: initial_function = adjust_word(&adj, (lispobj)*ptr); @@ -1050,14 +1009,13 @@ load_core_file(char *file, os_vm_offset_t file_offset, int merge_core_pages) // fprintf(stderr, "NOTE: TLS size increased to %x\n", dynamic_values_bytes); } #endif -#ifdef LISP_FEATURE_GENCGC + // simple-fun implies cold-init, not a warm core (it would be a closure then) if (widetag_of(native_pointer(initial_function)) == SIMPLE_FUN_WIDETAG && !lisp_startup_options.noinform) { fprintf(stderr, "Initial page table:\n"); extern void print_generation_stats(void); print_generation_stats(); } -#endif sanity_check_loaded_core(initial_function); return initial_function; case RUNTIME_OPTIONS_MAGIC: break; // already processed @@ -1070,7 +1028,7 @@ load_core_file(char *file, os_vm_offset_t file_offset, int merge_core_pages) #include "genesis/hash-table.h" #include "genesis/vector.h" #include "genesis/cons.h" -char* get_asm_routine_by_name(const char* name) +char* get_asm_routine_by_name(const char* name, int *index) { struct code* code = (struct code*)asm_routines_start; lispobj ht = CONS(code->debug_info)->car; @@ -1079,31 +1037,34 @@ char* get_asm_routine_by_name(const char* name) VECTOR(((struct hash_table*)native_pointer(ht))->pairs); lispobj sym; int i; - for (i=2 ; i < fixnum_value(table->length) ; i += 2) + // ASSUMPTION: hash-table representation is known (same as in gc-common of course) + for (i=2 ; i < vector_len(table) ; i += 2) if (lowtag_of(sym = table->data[i]) == OTHER_POINTER_LOWTAG && widetag_of(&SYMBOL(sym)->header) == SYMBOL_WIDETAG - && !strcmp(name, (char*)(VECTOR(SYMBOL(sym)->name)->data))) - return code_text_start(code) + fixnum_value(CONS(table->data[i+1])->car); + && !strcmp(name, (char*)(symbol_name(SYMBOL(sym))->data))) { + lispobj value = table->data[i+1]; + // value = (start-address . (end-address . index)) + if (index) + *index = fixnum_value(CONS(CONS(value)->cdr)->cdr); // take cddr + return code_text_start(code) + fixnum_value(CONS(value)->car); + } // Something is wrong if we have a hashtable but find nothing. fprintf(stderr, "WARNING: get_asm_routine_by_name(%s) failed\n", name); } + if (index) *index = 0; return NULL; } void asm_routine_poke(const char* routine, int offset, char byte) { - char *address = get_asm_routine_by_name(routine); + char *address = get_asm_routine_by_name(routine, 0); if (address) address[offset] = byte; } // Caution: use at your own risk -#undef DEBUG_CORE_LOADING -#ifdef DEBUG_CORE_LOADING -#ifdef LISP_FEATURE_CHENEYGC -# error "Can't define DEBUG_CORE_LOADING for cheneygc" -#endif +#if defined DEBUG_CORE_LOADING && DEBUG_CORE_LOADING #include "hopscotch.h" #include "genesis/cons.h" #include "genesis/layout.h" @@ -1121,6 +1082,7 @@ struct visitor { struct hopscotch_table *reached; }; +static void trace_sym(lispobj, struct symbol*, struct hopscotch_table*); #define RECURSE(x) if(is_lisp_pointer(x))graph_visit(ptr,x,seen) static void graph_visit(lispobj __attribute__((unused)) referer, lispobj ptr, @@ -1132,38 +1094,36 @@ static void graph_visit(lispobj __attribute__((unused)) referer, if (hopscotch_get(seen, ptr, 0)) return; hopscotch_insert(seen, ptr, 1); - lispobj layout, bitmap, *obj; + lispobj layout, *obj; int nwords, i; if (lowtag_of(ptr) == LIST_POINTER_LOWTAG) { RECURSE(CONS(ptr)->car); RECURSE(CONS(ptr)->cdr); } else switch (widetag_of(obj = native_pointer(ptr))) { case SIMPLE_VECTOR_WIDETAG: - nwords = fixnum_value(obj[1]); // vector length - for(i=0; i<nwords; ++i) RECURSE(obj[i+2]); + { + struct vector* v = (void*)obj; + sword_t len = vector_len(v); + for(i=0; i<len; ++i) RECURSE(v->data[i]); + } break; - // In all the following cases except for CODE, 'nwords' is the count - // of payload words (following the header), so we iterate up to and - // including that word index. For example, if there are 2 payload words, - // then we scan word indices 1 and 2 off the object base address. case INSTANCE_WIDETAG: - layout = instance_layout(obj); - graph_visit(ptr, layout, seen); - nwords = instance_length(*obj); - bitmap = LAYOUT(layout)->bitmap; - for(i=1; i<=nwords; ++i) - if (layout_bitmap_logbitp(i-1, bitmap)) RECURSE(obj[i]); - break; case FUNCALLABLE_INSTANCE_WIDETAG: - layout = funinstance_layout(obj); + layout = layout_of(obj); graph_visit(ptr, layout, seen); - bitmap = LAYOUT(layout)->bitmap; - nwords = SHORT_BOXED_NWORDS(*obj); - // We don't need to scan the word at index 1 (the trampoline pointer) - // because it either points to the FIN itself or to readonly space. - for(i=2; i<=nwords; ++i) - if (layout_bitmap_logbitp(i-1, bitmap)) RECURSE(obj[i]); + nwords = headerobj_size(obj); + struct bitmap bitmap = get_layout_bitmap(LAYOUT(layout)); + for (i=0; i<(nwords-1); ++i) + if (bitmap_logbitp(i, bitmap)) RECURSE(obj[1+i]); break; + case CODE_HEADER_WIDETAG: + nwords = code_header_words((struct code*)obj); + for(i=2; i<nwords; ++i) RECURSE(obj[i]); + break; + // In all the remaining cases, 'nwords' is the count of payload words + // (following the header), so we iterate up to and including that + // word index. For example, if there are 2 payload words, + // then we scan word indices 1 and 2 off the object base address. case CLOSURE_WIDETAG: // We must scan the closure's trampoline word. graph_visit(ptr, fun_taggedptr_from_self(obj[1]), seen); @@ -1175,6 +1135,8 @@ static void graph_visit(lispobj __attribute__((unused)) referer, for(i=2; i<=nwords; ++i) RECURSE(obj[i]); break; case SYMBOL_WIDETAG: + trace_sym(ptr, SYMBOL(ptr), seen); + break; case WEAK_POINTER_WIDETAG: nwords = TINY_BOXED_NWORDS(*obj); for(i=1; i<=nwords; ++i) RECURSE(obj[i]); @@ -1182,19 +1144,22 @@ static void graph_visit(lispobj __attribute__((unused)) referer, case FDEFN_WIDETAG: RECURSE(obj[1]); RECURSE(obj[2]); - RECURSE(fdefn_callee_lispobj((struct fdefn*)obj)); - break; - case CODE_HEADER_WIDETAG: - nwords = code_header_words((struct code*)obj); - for(i=2; i<nwords; ++i) RECURSE(obj[i]); + RECURSE(decode_fdefn_rawfun((struct fdefn*)obj)); break; default: if (!leaf_obj_widetag_p(widetag_of(obj))) { - nwords = BOXED_NWORDS(*obj); - for(i=1; i<=nwords; ++i) RECURSE(obj[i]); + int size = headerobj_size(obj); + for(i=1; i<size; ++i) RECURSE(obj[i]); } } } +static void trace_sym(lispobj ptr, struct symbol* sym, struct hopscotch_table* seen) +{ + RECURSE(decode_symbol_name(sym->name)); + RECURSE(sym->value); + RECURSE(sym->info); + RECURSE(sym->fdefn); +} static void tally(lispobj ptr, struct visitor* v) { @@ -1202,44 +1167,53 @@ static void tally(lispobj ptr, struct visitor* v) ++v->headers[0].count; else { lispobj* obj = native_pointer(ptr); - int widetag = widetag_of(obj); + lispobj header = *obj; + int words = object_size2(obj, header); + int widetag = header_widetag(header); int header_index = widetag>>2; - int words = OBJECT_SIZE(*obj, obj); ++v->headers[header_index].count; v->headers[header_index].words += words; if (widetag == SIMPLE_VECTOR_WIDETAG) { - int subtype = (*obj >> N_WIDETAG_BITS) & 7; - if (subtype == subtype_VectorWeak) - subtype = 1; - else if (subtype & subtype_VectorHashing) + int subtype = 0; + if (vector_flagp(header, VectorHashing)) subtype = 2; - else // The above test should account for everything - gc_assert(subtype == 0); + else if (vector_flagp(header, VectorWeak)) + subtype = 1; ++v->sv_subtypes[subtype].count; v->sv_subtypes[subtype].words += words; } } } +/* This printing in here is useful, but it's too much to output in make-target-2, + * because genesis dumps a ton of unreachable objects. + * The reason is this: cold-load has no way of knowing if a literal loaded + * from fasl and written to core is really supposed to be consumed by target. + * e.g. if it's a string naming a foreign fixup, who reads that string? + * Answer: The host, but it appears in the cold core as if the target will need it. + * The only way to rectify this defect is just not worth doing - each literal + * would have to be kept only as a host proxy until such time as we actually refer + * to it from another object that is definitely in the cold core, via FOP-LOAD-CODE + * and who know what else. Thus it remains a graph tracing problem in nature, + * which is best left to GC */ static uword_t visit(lispobj* where, lispobj* limit, uword_t arg) { struct visitor* v = (struct visitor*)arg; lispobj* obj = where; while (obj < limit) { + if (widetag_of(obj) == FILLER_WIDETAG) { + obj += object_size(obj); + continue; + } lispobj ptr = compute_lispobj(obj); tally(ptr, v); - // Weird stuff happens in genesis where this logic thinks that the - // cold core holds a ton of unreachable objects. I have no idea why. - if (!hopscotch_get(v->reached, ptr, 0)) - printf("object not reached: %p\n", (void*)ptr); - obj += OBJECT_SIZE(*obj, obj); + if (!hopscotch_get(v->reached, ptr, 0)) printf("unreachable: %p\n", (void*)ptr); + obj += object_size(obj); } return 0; } -#ifdef LISP_FEATURE_GENCGC -#define dynamic_space_pointer_p(ptr) (find_page_index((void*)ptr) >= 0) -#endif +#define count_this_pointer_p(ptr) (find_page_index((void*)ptr) >= 0) static void sanity_check_loaded_core(lispobj initial_function) { @@ -1252,13 +1226,12 @@ static void sanity_check_loaded_core(lispobj initial_function) 1<<18, /* initial size */ 0); { - lispobj* where = (lispobj*)STATIC_SPACE_START; + trace_sym(NIL, SYMBOL(NIL), &reached); + lispobj* where = (lispobj*)STATIC_SPACE_OBJECTS_START; lispobj* end = static_space_free_pointer; while (where<end) { - // This falsely treats NIL as 4 conses but it doesn't really matter. - // The garbage collectors do too. graph_visit(0, compute_lispobj(where), &reached); - where += OBJECT_SIZE(*where, where); + where += object_size(where); } } graph_visit(0, initial_function, &reached); // not otherwise reachable @@ -1266,11 +1239,11 @@ static void sanity_check_loaded_core(lispobj initial_function) int key_index; lispobj ptr; for_each_hopscotch_key(key_index, ptr, reached) - if (dynamic_space_pointer_p(ptr)) - tally(ptr, &v[0]); + if (count_this_pointer_p(ptr)) tally(ptr, &v[0]); // Pass 2: Count all heap objects v[1].reached = &reached; walk_generation(visit, -1, (uword_t)&v[1]); + // Pass 3: Compare // Start with the conses v[0].headers[0].words = v[0].headers[0].count * 2; @@ -1286,7 +1259,6 @@ static void sanity_check_loaded_core(lispobj initial_function) ((strncmp(widetag_names[i], "unk", 3) && (i != CHARACTER_WIDETAG>>2) && (i != SIMPLE_FUN_WIDETAG>>2) - && (i != NO_TLS_VALUE_MARKER_WIDETAG>>2) && (i != UNBOUND_MARKER_WIDETAG>>2)))) { int mismatch = v[0].headers[i].count != v[1].headers[i].count; printf("%8d %11d | %8d %11d | %s%s\n", diff --git a/src/runtime/darwin-os.c b/src/runtime/darwin-os.c index c0dce91e79..2fe1d07c3f 100644 --- a/src/runtime/darwin-os.c +++ b/src/runtime/darwin-os.c @@ -32,16 +32,6 @@ #include <time.h> #include <sys/syscall.h> -#ifdef LISP_FEATURE_MACH_EXCEPTION_HANDLER -#include <libkern/OSAtomic.h> -#endif - -#if defined(LISP_FEATURE_SB_WTIMER) -# include <sys/types.h> -# include <sys/event.h> -# include <sys/time.h> -#endif - char *os_get_runtime_executable_path() { char path[PATH_MAX + 1]; @@ -69,148 +59,21 @@ void init_mach_clock() { } } -#ifdef LISP_FEATURE_MACH_EXCEPTION_HANDLER - -/* exc_server handles mach exception messages from the kernel and - * calls catch exception raise. We use the system-provided - * mach_msg_server, which, I assume, calls exc_server in a loop. - * - */ -extern boolean_t exc_server(); - -void * -mach_exception_handler(void *port) -{ - mach_msg_server(exc_server, 2048, (mach_port_t) port, 0); - /* mach_msg_server should never return, but it should dispatch mach - * exceptions to our catch_exception_raise function - */ - lose("mach_msg_server returned"); -} - -/* Sets up the thread that will listen for mach exceptions. note that - the exception handlers will be run on this thread. This is - different from the BSD-style signal handling situation in which the - signal handlers run in the relevant thread directly. */ - -mach_port_t mach_exception_handler_port_set = MACH_PORT_NULL; - -pthread_t -setup_mach_exception_handling_thread() -{ - kern_return_t ret; - pthread_t mach_exception_handling_thread = NULL; - pthread_attr_t attr; - - /* allocate a mach_port for this process */ - ret = mach_port_allocate(mach_task_self(), - MACH_PORT_RIGHT_PORT_SET, - &mach_exception_handler_port_set); - - /* create the thread that will receive the mach exceptions */ - - FSHOW((stderr, "Creating mach_exception_handler thread!\n")); - - pthread_attr_init(&attr); - pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN); - pthread_create(&mach_exception_handling_thread, - &attr, - mach_exception_handler, - (void*)(long)mach_exception_handler_port_set); - pthread_attr_destroy(&attr); - - return mach_exception_handling_thread; -} - -/* tell the kernel that we want EXC_BAD_ACCESS exceptions sent to the - exception port (which is being listened to do by the mach - exception handling thread). */ -kern_return_t -mach_lisp_thread_init(struct thread * thread) -{ - kern_return_t ret; - mach_port_t current_mach_thread, thread_exception_port; - - if (mach_port_allocate(mach_task_self(), - MACH_PORT_RIGHT_RECEIVE, - &thread_exception_port) != KERN_SUCCESS) { - lose("Cannot allocate thread_exception_port"); - } - - if (mach_port_set_context(mach_task_self(), thread_exception_port, - (mach_vm_address_t)thread) - != KERN_SUCCESS) { - lose("Cannot set thread_exception_port context"); - } - thread->mach_port_name = thread_exception_port; - - /* establish the right for the thread_exception_port to send messages */ - ret = mach_port_insert_right(mach_task_self(), - thread_exception_port, - thread_exception_port, - MACH_MSG_TYPE_MAKE_SEND); - if (ret) { - lose("mach_port_insert_right failed with return_code %d", ret); - } - - current_mach_thread = mach_thread_self(); - ret = thread_set_exception_ports(current_mach_thread, - EXC_MASK_BAD_ACCESS | EXC_MASK_BAD_INSTRUCTION | EXC_MASK_BREAKPOINT, - thread_exception_port, - EXCEPTION_DEFAULT, - THREAD_STATE_NONE); - if (ret) { - lose("thread_set_exception_ports failed with return_code %d", ret); - } - - ret = mach_port_deallocate (mach_task_self(), current_mach_thread); - if (ret) { - lose("mach_port_deallocate failed with return_code %d", ret); - } - - ret = mach_port_move_member(mach_task_self(), - thread_exception_port, - mach_exception_handler_port_set); - if (ret) { - lose("mach_port_move_member failed with return_code %d", ret); - } - - return ret; -} - -void -mach_lisp_thread_destroy(struct thread *thread) { - mach_port_t port = thread->mach_port_name; - FSHOW((stderr, "Deallocating mach port %x\n", port)); - if (mach_port_move_member(mach_task_self(), port, MACH_PORT_NULL) - != KERN_SUCCESS) { - lose("Error destroying an exception port"); - } - if (mach_port_deallocate(mach_task_self(), port) != KERN_SUCCESS) { - lose("Error destroying an exception port"); - } - - if (mach_port_destroy(mach_task_self(), port) != KERN_SUCCESS) { - lose("Error destroying an exception port"); - } -} -#endif - void darwin_reinit() { init_mach_clock(); -#ifdef LISP_FEATURE_MACH_EXCEPTION_HANDLER - setup_mach_exception_handling_thread(); - mach_lisp_thread_init(all_threads); +#ifdef LISP_FEATURE_SB_THREAD + struct extra_thread_data *extra_data = thread_extra_data(get_sb_vm_thread()); + os_sem_init(&extra_data->state_sem, 1); + os_sem_init(&extra_data->state_not_running_sem, 0); + os_sem_init(&extra_data->state_not_stopped_sem, 0); + os_sem_init(&extra_data->sprof_sem, 0); #endif } void darwin_init(void) { init_mach_clock(); -#ifdef LISP_FEATURE_MACH_EXCEPTION_HANDLER - setup_mach_exception_handling_thread(); -#endif } @@ -243,74 +106,6 @@ os_sem_destroy(os_sem_t *sem) #endif -#if defined(LISP_FEATURE_SB_WTIMER) - -# error Completely untested. Go ahead! Remove this line, try your luck! - -/* - * Waitable timer implementation for the safepoint-based (SIGALRM-free) - * timer facility using kqueue. - * - * Unlike FreeBSD with its ms (!) timer resolution, Darwin supports ns - * timer resolution -- or at least it pretends to do so on the API - * level (?). To use it, we need the *64 versions of the functions and - * structures. - * - * Unfortunately, I don't run Darwin, and can't test this code, so it's - * just a hopeful translation from FreeBSD. - */ - -int -os_create_wtimer() -{ - int kq = kqueue(); - if (kq == -1) - lose("os_create_wtimer: kqueue"); - return kq; -} - -int -os_wait_for_wtimer(int kq) -{ - struct kevent64_s ev; - int n; - if ( (n = kevent64(kq, 0, 0, &ev, 1, 0, 0)) == -1) { - if (errno != EINTR) - lose("os_wtimer_listen failed"); - n = 0; - } - return n != 1; -} - -void -os_close_wtimer(int kq) -{ - if (close(kq) == -1) - lose("os_close_wtimer failed"); -} - -void -os_set_wtimer(int kq, int sec, int nsec) -{ - int64_t nsec = ((int64_t) sec) * 1000000000 + (int64_t) nsec; - - struct kevent64_s ev; - EV_SET64(&ev, 1, EVFILT_TIMER, EV_ADD|EV_ENABLE|EV_ONESHOT, NOTE_NSECONDS, - nsec, 0, 0, 0); - if (kevent64(kq, &ev, 1, 0, 0, 0, 0) == -1) - perror("os_set_wtimer: kevent"); -} - -void -os_cancel_wtimer(int kq) -{ - struct kevent64_s ev; - EV_SET64(&ev, 1, EVFILT_TIMER, EV_DISABLE, 0, 0, 0, 0, 0); - if (kevent64(kq, &ev, 1, 0, 0, 0, 0) == -1 && errno != ENOENT) - perror("os_cancel_wtimer: kevent"); -} -#endif - /* nanosleep() is not re-entrant on some versions of Darwin, * reimplement it using the underlying syscalls. */ int diff --git a/src/runtime/darwin-os.h b/src/runtime/darwin-os.h index ac7b9ac6db..f13669fb04 100644 --- a/src/runtime/darwin-os.h +++ b/src/runtime/darwin-os.h @@ -37,7 +37,7 @@ typedef ucontext_t os_context_t; void darwin_init(void); #ifdef LISP_FEATURE_SB_THREAD -#define CANNOT_USE_POSIX_SEM_T +#define USE_DARWIN_GCD_SEMAPHORES #include <dispatch/dispatch.h> typedef dispatch_semaphore_t os_sem_t; #endif diff --git a/src/runtime/forwarding-ptr.h b/src/runtime/forwarding-ptr.h index 81dc54cb05..8b0dcf84c7 100644 --- a/src/runtime/forwarding-ptr.h +++ b/src/runtime/forwarding-ptr.h @@ -8,26 +8,17 @@ in_gc_p(void) { } #endif +#define FORWARDING_HEADER 1 + inline static boolean forwarding_pointer_p(lispobj *pointer) { - lispobj first_word=*pointer; -#ifdef LISP_FEATURE_GENCGC - return (first_word == 0x01); +#if defined LISP_FEATURE_64_BIT && defined LISP_FEATURE_LITTLE_ENDIAN + /* Read exactly 1 byte. The upper bytes can store the original object size. + * With other architectures we will need to pick a byte distinct from any widetag + * and any pointer in the low N-LOWTAG-BITS */ + return *(char*)pointer == 1; #else - // FIXME: change 5c0d71f92c371769f911e6a2ac60b2dd9fbde349 added - // an extra test here, which theoretically slowed things down. - // This was in response to 044e22192c25578efceedba042554dc9a96124c6 - // which caused cheneygc to break. But now the latter revision has been - // reverted due to performance degradation in gencgc. - // The right fix is probably for gc_search_all_spaces() to use a - // special version of gc_search_space for ldb. That is unfortunately - // made difficult by the call chain: - // search_all_gc_spaces() -> search_{foo}_space() -> gc_search_space(). - // which requires informing gc_search_space() to be more careful, - // and similarly forwarding_pointer_p(). - return (is_lisp_pointer(first_word) - && in_gc_p() /* cheneygc new_space_p() is broken when not in gc */ - && new_space_p(first_word)); + return (*pointer == FORWARDING_HEADER); #endif } @@ -39,9 +30,8 @@ forwarding_pointer_value(lispobj *pointer) { return pointer[0]; #endif } -static inline lispobj -set_forwarding_pointer(lispobj *pointer, lispobj newspace_copy) { - // The object at 'pointer' might already have been forwarded, +static inline void set_forwarding_pointer(lispobj *addr, lispobj newspace_copy) { + // The object at 'addr' might already have been forwarded, // but that's ok. Such occurs primarily when dealing with // code components, because code can be forwarded by scavenging any // pointer to a function that resides within the code. @@ -50,13 +40,35 @@ set_forwarding_pointer(lispobj *pointer, lispobj newspace_copy) { // Unfortunately this also implies we can't assert // that we're operating on a not-yet-forwarded object here. #ifdef LISP_FEATURE_GENCGC - gc_dcheck(compacting_p()); - pointer[0]=0x01; - pointer[1]=newspace_copy; + //gc_dcheck(from_space_p(addr)); // inclusion order problem, too bad + addr[0] = FORWARDING_HEADER; + addr[1] = newspace_copy; #else - pointer[0]=newspace_copy; + addr[0] = newspace_copy; #endif - return newspace_copy; +} +static inline void set_forwarding_pointer_resized(lispobj *addr, lispobj newspace_copy, + __attribute__((unused)) int old_nwords) +{ +#if defined LISP_FEATURE_64_BIT && defined LISP_FEATURE_LITTLE_ENDIAN + addr[0] = FORWARDING_HEADER | (old_nwords<<N_WIDETAG_BITS); + addr[1] = newspace_copy; +#else + set_forwarding_pointer(addr, newspace_copy); +#endif +} + +/// Chase the pointer in 'word' if it points to a forwarded object. +static inline lispobj follow_maybe_fp(lispobj word) +{ + return (is_lisp_pointer(word) && forwarding_pointer_p(native_pointer(word))) + ? forwarding_pointer_value(native_pointer(word)) : word; +} +/// As above, but 'ptr' MUST be a pointer. +static inline lispobj follow_fp(lispobj ptr) +{ + return forwarding_pointer_p(native_pointer(ptr)) + ? forwarding_pointer_value(native_pointer(ptr)) : ptr; } #endif diff --git a/src/runtime/fullcgc.c b/src/runtime/fullcgc.c index 2f1ad42df7..b3b28baf1f 100644 --- a/src/runtime/fullcgc.c +++ b/src/runtime/fullcgc.c @@ -23,6 +23,7 @@ #include "code.h" #include "immobile-space.h" #include "queue.h" +#include "os.h" #include <stdio.h> #ifndef LISP_FEATURE_WIN32 @@ -52,8 +53,7 @@ #define BIGNUM_MARK_BIT MARK_BIT #endif -#define interesting_pointer_p(x) \ - (find_page_index((void*)x) >= 0 || immobile_space_p(x)) +extern lispobj lisp_init_function, gc_object_watcher; #ifdef DEBUG # define dprintf(arg) printf arg @@ -75,15 +75,20 @@ static page_index_t free_page; /* The whole-page allocator works backwards from the end of dynamic space. * If it collides with 'next_free_page', then you lose. - * TOOD: It would be reasonably simple to have this request more memory from + * TODO: It would be reasonably simple to have this request more memory from * the OS instead of failing on overflow */ -static void* get_free_page() { +static void* get_free_page(boolean prezero) { --free_page; if (free_page < next_free_page) lose("Needed more space to GC"); - page_table[free_page].type = UNBOXED_PAGE_FLAG; + page_table[free_page].type = PAGE_TYPE_UNBOXED; char* mem = page_address(free_page); - zero_dirty_pages(free_page, free_page, 0); +#ifdef LISP_FEATURE_DARWIN_JIT + prezero = 1; // Might need to alter MMU-based protection +#elif defined LISP_FEATURE_WIN32 + os_commit_memory(page_address(free_page), GENCGC_PAGE_BYTES); +#endif + if (prezero) zeroize_pages_if_needed(free_page, free_page, 0); return mem; } @@ -92,35 +97,26 @@ static void* get_free_page() { * then one GC page can hold 2K cons cells. * One byte marks 8 conses (1 bit per cons), 256 bytes mark 2048 conses. * 128 blocks of 256 bytes fit on a 32K GC page. */ -char *suballocator_free_ptr, *suballocator_end_ptr; - -static void* allocate_cons_mark_bits() { - int nbytes = GENCGC_CARD_BYTES / (2 * N_WORD_BYTES) / 8; - if (suballocator_free_ptr + nbytes > suballocator_end_ptr) { - suballocator_free_ptr = get_free_page(); - suballocator_end_ptr = suballocator_free_ptr + GENCGC_CARD_BYTES; - } - void* mem = suballocator_free_ptr; - suballocator_free_ptr += nbytes; - return mem; -} +static char *suballocator_free_ptr, *suballocator_end_ptr; static void gc_enqueue(lispobj object) { gc_dcheck(is_lisp_pointer(object)); + gc_dcheck(widetag_of(native_pointer(object)) != SIMPLE_FUN_WIDETAG); struct Qblock* block = scav_queue.tail_block; if (block->count == QBLOCK_CAPACITY) { struct Qblock* next; next = scav_queue.recycler; if (next) { scav_queue.recycler = next->next; - next->next = 0; dprintf(("Popped recycle list\n")); } else { - next = (struct Qblock*)get_free_page(); + next = (struct Qblock*)get_free_page(0); dprintf(("Alloc'd new block\n")); } block = block->next = next; + block->next = 0; + block->tail = block->count = 0; scav_queue.tail_block = block; } block->elements[block->tail] = object; @@ -148,80 +144,105 @@ static lispobj gc_dequeue() return object; } -/* The 'mark_bits' hashtable maps a page address to a block of mark bits - * for headerless objects (conses) */ -struct hopscotch_table mark_bits; - -static inline uword_t compute_page_key(lispobj cons) { - return ALIGN_DOWN(cons, GENCGC_CARD_BYTES); +static inline sword_t dword_index(uword_t ptr, uword_t base) { + return (ptr - base) >> (1+WORD_SHIFT); } -static inline int compute_dword_number(lispobj cons) { - return (cons & (GENCGC_CARD_BYTES - 1)) >> (1+WORD_SHIFT); + +static inline lispobj canonical_ptr(lispobj pointer) +{ +#ifdef RETURN_PC_WIDETAG + /* NO_TLS_VALUE is all 1s, and so it might look like it has OTHER_POINTER_LOWTAG + * depending on the architecture (the word size, etc), but there is no memory + * at 0xff...ff so definitely don't call widetag_of - that won't fly! */ + if (lowtag_of(pointer)==OTHER_POINTER_LOWTAG + && pointer != NO_TLS_VALUE_MARKER + && widetag_of(native_pointer(pointer)) == RETURN_PC_WIDETAG) + return fun_code_tagged(native_pointer(pointer)); +#endif + return pointer; } -static inline int cons_markedp(lispobj pointer) { - unsigned char* bits = (unsigned char*) - hopscotch_get(&mark_bits, compute_page_key(pointer), 0); - if (!bits) return 0; - int index = compute_dword_number(pointer); - return (bits[index / 8] >> (index % 8)) & 1; +sword_t fixedobj_index_bit_bias, text_index_bit_bias; +uword_t *fullcgcmarks; +static size_t markbits_size; +static inline sword_t ptr_to_bit_index(lispobj pointer) { + if (pointer == NIL) return -1; + page_index_t p = find_page_index((void*)pointer); + if (p >= 0) return dword_index(pointer, DYNAMIC_SPACE_START); +#ifdef LISP_FEATURE_IMMOBILE_SPACE + p = find_fixedobj_page_index((void*)pointer); + if (p >= 0) return dword_index(pointer, FIXEDOBJ_SPACE_START) + fixedobj_index_bit_bias; + p = find_text_page_index((void*)pointer); + if (p >= 0) return dword_index(pointer, TEXT_SPACE_START) + text_index_bit_bias; +#endif + return -1; } +#define interesting_pointer_p(x) ptr_to_bit_index(x)>=0 /* Return true if OBJ has already survived the current GC. */ static inline int pointer_survived_gc_yet(lispobj pointer) { - if (!interesting_pointer_p(pointer)) - return 1; - if (listp(pointer)) - return cons_markedp(pointer); - lispobj header = *native_pointer(pointer); - int widetag = header_widetag(header); - switch (widetag) { - case BIGNUM_WIDETAG: return (header & BIGNUM_MARK_BIT) != 0; - case FDEFN_WIDETAG : return (header & FDEFN_MARK_BIT) != 0; - } - if (embedded_obj_p(widetag)) - header = *fun_code_header(native_pointer(pointer)); - return (header & MARK_BIT) != 0; + sword_t mark_index = ptr_to_bit_index(canonical_ptr(pointer)); + if (mark_index < 0) return 1; // "uninteresting" objects always survive GC + return (fullcgcmarks[mark_index / N_WORD_BITS] >> (mark_index % N_WORD_BITS)) & 1; } -void __mark_obj(lispobj pointer) -{ - gc_dcheck(is_lisp_pointer(pointer)); - if (!interesting_pointer_p(pointer)) - return; - if (!listp(pointer)) { - lispobj* base = native_pointer(pointer); - lispobj header = *base; - int widetag = header_widetag(header); - if (widetag == BIGNUM_WIDETAG) { - *base |= BIGNUM_MARK_BIT; - return; // don't enqueue - no pointers - } else { - if (embedded_obj_p(widetag)) { - base = fun_code_header(base); - pointer = make_lispobj(base, OTHER_POINTER_LOWTAG); - header = *base; +void dump_marked_objects() { + fprintf(stderr, "Marked objects:\n"); + page_index_t first = 0; + int n = 0; + while (first < next_free_page) { + page_index_t last = contiguous_block_final_page(first); + lispobj* where = (lispobj*)page_address(first); + lispobj* limit = (lispobj*)page_address(last) + page_words_used(last); + while (where < limit) { + lispobj obj = compute_lispobj(where); + if (pointer_survived_gc_yet(obj)) { + ++n; + fprintf(stderr, " %"OBJ_FMTX"\n", obj); } - uword_t markbit = (widetag == FDEFN_WIDETAG) ? FDEFN_MARK_BIT : MARK_BIT; - if (header & markbit) return; // already marked - *base |= markbit; + where += object_size(where); } - if (leaf_obj_widetag_p(widetag)) return; - } else { - uword_t key = compute_page_key(pointer); - int index = compute_dword_number(pointer); - unsigned char* bits = (unsigned char*)hopscotch_get(&mark_bits, key, 0); - if (!bits) { - bits = allocate_cons_mark_bits(); - hopscotch_insert(&mark_bits, key, (sword_t)bits); - } else if (bits[index / 8] & (1 << (index % 8))) { - return; - } - // Mark the cons - bits[index / 8] |= 1 << (index % 8); + first = 1 + last; + } + fprintf(stderr, "Total: %d\n", n); +} + +static void __mark_obj(lispobj pointer) +{ + lispobj* base; + + pointer = canonical_ptr(pointer); + sword_t mark_index = ptr_to_bit_index(pointer); + if (mark_index < 0) return; // uninteresting pointer + uword_t wordindex = mark_index / N_WORD_BITS; + uword_t bit = (uword_t)1 << (mark_index % N_WORD_BITS); + if (fullcgcmarks[wordindex] & bit) return; // already marked + if (lowtag_of(pointer) == FUN_POINTER_LOWTAG + && embedded_obj_p(widetag_of(FUNCTION(pointer)))) { + lispobj* code = fun_code_header(FUNCTION(pointer)); + mark_index -= ((char*)FUNCTION(pointer) - (char*)code) >> (1+WORD_SHIFT); + pointer = make_lispobj(code, OTHER_POINTER_LOWTAG); + base = code; + wordindex = mark_index / N_WORD_BITS; + bit = (uword_t)1 << (mark_index % N_WORD_BITS); + if (fullcgcmarks[wordindex] & bit) return; // already marked + } else + base = native_pointer(pointer); + fullcgcmarks[wordindex] |= bit; + // FIXME: restore the code for #ifdef LISP_FEATURE_UBSAN + if (widetag_of(base) == CODE_HEADER_WIDETAG) { + struct code* code = (void*)base; + /* mark all simple-funs which speeds up pointer_survived_gc_yet. + * Just add the offset in dwords from base to each fun to compute + * the mark bit index (rather than calling ptr_to_bit_index) */ + for_each_simple_fun(i, fun, code, 0, { + unsigned int offset = ((char*)fun - (char*)base) >> (1+WORD_SHIFT); + uword_t funmark = mark_index + offset; + fullcgcmarks[funmark / N_WORD_BITS] |= (uword_t)1 << (funmark % N_WORD_BITS); + }) } - gc_enqueue(pointer); + if (listp(pointer) || !leaf_obj_widetag_p(widetag_of(base))) gc_enqueue(pointer); } inline void gc_mark_obj(lispobj thing) { @@ -244,56 +265,59 @@ void gc_mark_range(lispobj* where, long count) { #define HT_ENTRY_LIVENESS_FUN_ARRAY_NAME alivep_funs #include "weak-hash-pred.inc" +static void trace_using_layout(lispobj layout, lispobj* where, int nslots) +{ + // Apart from the allowance for untagged pointers in lockfree list nodes, + // this contains almost none of the special cases that gencgc does. + if (!layout) return; +#ifdef LISP_FEATURE_METASPACE + gc_mark_obj(LAYOUT(layout)->friend); +#else + gc_mark_obj(layout); +#endif + if (lockfree_list_node_layout_p(LAYOUT(layout))) { // allow untagged 'next' + struct instance* node = (struct instance*)where; + lispobj next = node->slots[INSTANCE_DATA_START]; + // ignore if 0 + if (fixnump(next) && next) __mark_obj(next|INSTANCE_POINTER_LOWTAG); + } + struct bitmap bitmap = get_layout_bitmap(LAYOUT(layout)); + int i; + lispobj* slots = where+1; + for (i=0; i<nslots; ++i) + if (bitmap_logbitp(i, bitmap) && is_lisp_pointer(slots[i])) + __mark_obj(slots[i]); +} + static void trace_object(lispobj* where) { lispobj header = *where; int widetag = header_widetag(header); + + if (instanceoid_widetag_p(widetag)) + return trace_using_layout(layout_of(where), where, + instanceoid_length(header)); sword_t scan_from = 1; sword_t scan_to = sizetab[widetag](where); sword_t i; struct weak_pointer *weakptr; - lispobj layout, bitmap; - - /* If the C compiler emits this switch as a jump table, order doesn't matter. - * But if as consecutive tests, instance and vector should be tested first - * as they are the most freequent */ switch (widetag) { - case INSTANCE_WIDETAG: -#ifdef LISP_FEATURE_COMPACT_INSTANCE_HEADER - /* No need to deal with FINs for non-compact header, because the layout - pointer isn't in the header word, the trampoline pointer can only point - to readonly space, and all slots are tagged. */ - case FUNCALLABLE_INSTANCE_WIDETAG: - layout = instance_layout(where); - gc_mark_obj(layout); -#else - layout = instance_layout(where); // will be marked as where[1] -#endif - if (!layout) break; // fall into general case - // mixed boxed/unboxed objects - bitmap = LAYOUT(layout)->bitmap; - // If no raw slots, just scan without use of the bitmap. - // A bitmap of -1 implies that not only are all slots tagged, - // there is no special GC method for any slot. - if (bitmap == make_fixnum(-1)) break; - // Otherwise, the first slot might merit special treatment. - if (lockfree_list_node_layout_p(LAYOUT(layout))) { - struct instance* node = (struct instance*)where; - lispobj next = node->slots[INSTANCE_DATA_START]; - if (fixnump(next) && next) // ignore initially 0 heap words - __mark_obj(next|INSTANCE_POINTER_LOWTAG); - } - for(i=1; i<scan_to; ++i) - if (layout_bitmap_logbitp(i-1, bitmap) && is_lisp_pointer(where[i])) - __mark_obj(where[i]); - return; // do not scan slots case SIMPLE_VECTOR_WIDETAG: +#ifdef LISP_FEATURE_UBSAN + if (is_lisp_pointer(where[1])) gc_mark_obj(where[1]); +#endif // non-weak hashtable kv vectors are trivial in fullcgc. Keys don't move // so the table will not need rehash as a result of gc. - if ((vector_subtype(header) & ~subtype_VectorAddrHashing) - == subtype_VectorHashing + subtype_VectorWeak) { // weak table + // Ergo, those may be treated just like ordinary simple vectors. + // However, weakness remains as a special case. + if (vector_flagp(header, VectorWeak)) { + if (!vector_flagp(header, VectorHashing)) { + add_to_weak_vector_list(where, header); + return; + } + // Ok, we're looking at a weak hash-table. struct vector* v = (struct vector*)where; - lispobj lhash_table = v->data[fixnum_value(v->length)-1]; + lispobj lhash_table = v->data[vector_len(v)-1]; gc_dcheck(instancep(lhash_table)); __mark_obj(lhash_table); struct hash_table* hash_table @@ -313,12 +337,8 @@ static void trace_object(lispobj* where) } return; } - if (is_vector_subtype(header, VectorWeak)) { - add_to_weak_vector_list(where, header); - return; - } break; -#if defined(LISP_FEATURE_X86) || defined(LISP_FEATURE_X86_64) +#if defined(LISP_FEATURE_X86) || defined(LISP_FEATURE_X86_64) || defined (LISP_FEATURE_ARM64) /* on x86[-64], closure->fun is a fixnum-qua-pointer. Convert it to a lisp * pointer to mark it, but not on platforms where it's already a descriptor */ case CLOSURE_WIDETAG: @@ -330,7 +350,8 @@ static void trace_object(lispobj* where) scan_to = code_header_words((struct code*)where); #ifdef LISP_FEATURE_UNTAGGED_FDEFNS struct code* code = (struct code*)where; - lispobj* fdefns_start = code->constants + code_n_funs(code) * 4; + lispobj* fdefns_start = code->constants + + code_n_funs(code) * CODE_SLOTS_PER_SIMPLE_FUN; lispobj* fdefns_end = fdefns_start + code_n_named_calls(code); lispobj* limit = where + scan_to; where = where + scan_from; @@ -343,8 +364,17 @@ static void trace_object(lispobj* where) return; #endif break; +#ifdef LISP_FEATURE_COMPACT_SYMBOL + case SYMBOL_WIDETAG: + { + struct symbol* s = (void*)where; + gc_mark_obj(decode_symbol_name(s->name)); + gc_mark_range(&s->value, 3); + } + return; +#endif case FDEFN_WIDETAG: - gc_mark_obj(fdefn_callee_lispobj((struct fdefn*)where)); + gc_mark_obj(decode_fdefn_rawfun((struct fdefn*)where)); scan_to = 3; break; case WEAK_POINTER_WIDETAG: @@ -361,24 +391,37 @@ static void trace_object(lispobj* where) void prepare_for_full_mark_phase() { - // FIXME: Estimate how large to create mark_bits based on dynamic space size. - // Guess 8 words per object, and X% of the objects are conses. - // The problem is guessing how localized the conses are: guess that N conses - // will reside on fraction*N different pages, which guides us as to how many - // hash table entries are needed. - hopscotch_create(&mark_bits, HOPSCOTCH_HASH_FUN_DEFAULT, - N_WORD_BYTES, /* table values are machine words */ - 65536, /* initial size */ - 0); - free_page = page_table_pages; suballocator_free_ptr = suballocator_end_ptr = 0; - struct Qblock* block = (struct Qblock*)get_free_page(); + struct Qblock* block = (struct Qblock*)get_free_page(0); dprintf(("Queue block holds %d objects\n", (int)QBLOCK_CAPACITY)); scav_queue.head_block = block; scav_queue.tail_block = block; scav_queue.recycler = 0; - gc_assert(!scav_queue.head_block->count); + block->next = 0; + block->tail = block->count = 0; + /* Consume as many bits as cover the entire dynamic space regardless + * of its current usage. Same for the other spaces. + * This previously tried to be clever about using only as many bits for + * dynamic space as correspond to the current high water mark, which was + * an ill-conceived idea, because cull_weak_hash_tables() can consume + * dynamic space when processing finalizers. So it marks an object live, + * but that object's mark bit could be past the reserved range of dynamic + * space mark bits, thus accidentally marking some _other_ thing live. + * And heaven forbid that other object isn't supposed to be live, + * you're in for a heap of trouble (pun intended) */ + sword_t nbits_dynamic = dynamic_space_size / (2*N_WORD_BYTES); +#ifdef LISP_FEATURE_IMMOBILE_SPACE + sword_t nbits_fixedobj = FIXEDOBJ_SPACE_SIZE / (2*N_WORD_BYTES); + sword_t nbits_text = TEXT_SPACE_SIZE / (2*N_WORD_BYTES); + fixedobj_index_bit_bias = nbits_dynamic; + text_index_bit_bias = fixedobj_index_bit_bias + nbits_fixedobj; + sword_t nbytes = (nbits_dynamic + nbits_fixedobj + nbits_text) / 8; +#else + sword_t nbytes = nbits_dynamic / 8; +#endif + markbits_size = ALIGN_UP(nbytes, GETPAGESIZE); + fullcgcmarks = (void*)os_allocate(markbits_size); } void execute_full_mark_phase() @@ -387,13 +430,27 @@ void execute_full_mark_phase() struct rusage before, after; getrusage(RUSAGE_SELF, &before); #endif - lispobj* where = (lispobj*)STATIC_SPACE_START; + trace_object((lispobj*)NIL_SYMBOL_SLOTS_START); + lispobj* where = (lispobj*)STATIC_SPACE_OBJECTS_START; lispobj* end = static_space_free_pointer; while (where < end) { lispobj obj = compute_lispobj(where); gc_enqueue(obj); - where += listp(obj) ? 2 : sizetab[widetag_of(where)](where); + where += listp(obj) ? 2 : headerobj_size(where); + } +#ifdef LISP_FEATURE_METASPACE + where = (lispobj*)METASPACE_START; + end = (lispobj*)READ_ONLY_SPACE_END; + while (where < end) { + lispobj obj = compute_lispobj(where); + gc_enqueue(obj); + where += listp(obj) ? 2 : headerobj_size(where); } +#endif + gc_mark_obj(lisp_package_vector); + gc_mark_obj(lisp_init_function); + gc_mark_obj(gc_object_watcher); + gc_mark_obj(alloc_profile_data); do { lispobj ptr = gc_dequeue(); gc_dcheck(ptr != 0); @@ -412,8 +469,8 @@ void execute_full_mark_phase() (a.field.tv_usec-b.field.tv_usec)) / 1000000.0 if (gencgc_verbose) fprintf(stderr, - "[Mark phase: %d pages used, HT-count=%d, ET=%f+%f sys+usr]\n", - (int)(page_table_pages - free_page), mark_bits.count, + "[Mark phase: %d pages used, ET=%f+%f sys+usr]\n", + (int)(page_table_pages - free_page), timediff(before, after, ru_stime), timediff(before, after, ru_utime)); #endif } @@ -423,8 +480,8 @@ static void local_smash_weak_pointers() struct weak_pointer *wp, *next_wp; for (wp = weak_pointer_chain; wp != WEAK_POINTER_CHAIN_END; wp = next_wp) { gc_assert(widetag_of(&wp->header) == WEAK_POINTER_WIDETAG); - next_wp = wp->next; - wp->next = NULL; + next_wp = get_weak_pointer_next(wp); + reset_weak_pointer_next(wp); lispobj pointee = wp->value; gc_assert(is_lisp_pointer(pointee)); if (!pointer_survived_gc_yet(pointee)) @@ -437,7 +494,7 @@ static void local_smash_weak_pointers() struct vector* vector = (struct vector*)vectors->car; vectors = (struct cons*)vectors->cdr; UNSET_WEAK_VECTOR_VISITED(vector); - sword_t len = fixnum_value(vector->length); + sword_t len = vector_len(vector); sword_t i; for (i = 0; i<len; ++i) { lispobj obj = vector->data[i]; @@ -462,22 +519,15 @@ __attribute__((unused)) static char *fillerp(lispobj* where) static FILE *sweeplog; static int sweep_mode = 1; -# define NOTE_GARBAGE(gen,addr,nwords,tally,erase) \ - { tally[gen] += nwords; \ - if (sweep_mode & 2) /* print before erasing */ \ - fprintf(sweeplog, "%5d %d #x%"OBJ_FMTX": %"OBJ_FMTX" %"OBJ_FMTX"\n", \ - (int)nwords, gen, compute_lispobj(addr), \ - addr[0], addr[1]); \ - if (sweep_mode & 1) { erase; } } - #ifndef LISP_FEATURE_IMMOBILE_SPACE #undef immobile_obj_gen_bits #define immobile_obj_gen_bits(x) (lose("No page index?"),0) #else -static void sweep_fixedobj_pages(long *zeroed) +static void sweep_fixedobj_pages() { low_page_index_t page; - + uword_t space_base = FIXEDOBJ_SPACE_START; + sword_t bitmap_index_bias = fixedobj_index_bit_bias; for (page = FIXEDOBJ_RESERVED_PAGES ; ; ++page) { lispobj *obj = fixedobj_page_address(page); if (obj >= fixedobj_free_pointer) @@ -485,70 +535,79 @@ static void sweep_fixedobj_pages(long *zeroed) int obj_spacing = fixedobj_page_obj_align(page); if (!obj_spacing) continue; - int nwords = fixedobj_page_obj_size(page); + int nwords = obj_spacing >> WORD_SHIFT; lispobj *limit = (lispobj*)((char*)obj + IMMOBILE_CARD_BYTES - obj_spacing); for ( ; obj <= limit ; obj = (lispobj*)((char*)obj + obj_spacing) ) { lispobj header = *obj; - uword_t markbit = (header_widetag(header) == FDEFN_WIDETAG) ? FDEFN_MARK_BIT : MARK_BIT; - if (fixnump(header)) { // is a hole - } else if (header & markbit) { // live object - *obj = header ^ markbit; - } else { - NOTE_GARBAGE(immobile_obj_gen_bits(obj), obj, nwords, zeroed, - memset(obj, 0, nwords * N_WORD_BYTES)); - } + if (fixnump(header)) continue; // is a hole + uword_t index = bitmap_index_bias + (((uword_t)obj - space_base) >> (1+WORD_SHIFT)); + uword_t livep = + fullcgcmarks[index / N_WORD_BITS] & ((uword_t)1 << (index % N_WORD_BITS)); + if (!livep) memset(obj, 0, nwords * N_WORD_BYTES); } } } #endif -static uword_t sweep(lispobj* where, lispobj* end, uword_t arg) +/* Overwrite exactly 1 object wit non-pointer words of some sort. + * This eliminates tenured garbage in pseudo-static-generation, + * and does NOT strive to to write as few words as possible, + * unlike deposit_filler() which tries to be efficient */ +static void clobber_headered_object(lispobj* addr, sword_t nwords) { - long *zeroed = (long*)arg; // one count per generation - sword_t nwords; + // FIXME: clobbering an object on single-object pages should free entire pages + page_index_t page = find_page_index(addr); + if (page < 0) { // code space +#ifdef LISP_FEATURE_IMMOBILE_SPACE + extern lispobj codeblob_freelist; + if (widetag_of(addr) == CODE_HEADER_WIDETAG) { + // OAOO violation - like sweep_immobile_text() + assign_widetag(addr, FILLER_WIDETAG); + ((char*)addr)[2] = 0; // clear the TRACED flag + ((char*)addr)[3] = 0; // clear the WRITTEN flag and the generation + // add to list only if it is above tlsf_mem_start + // (below it will never by utilized by the TLSF allocator) + if (addr >= tlsf_mem_start) { + addr[1] = codeblob_freelist; // push into to-be-freed list + codeblob_freelist = (lispobj)addr; + } + } +#endif + } else if ((SINGLE_OBJECT_FLAG|page_table[page].type) == (SINGLE_OBJECT_FLAG|PAGE_TYPE_CODE)) { + // Code pages don't want (0 . 0) fillers, otherwise heap checking + // gets an error: "object @ 0x..... is non-code on code page" + addr[0] = make_filler_header(nwords); + addr[1] = 0; + } else { + memset(addr, 0, nwords * N_WORD_BYTES); + } +} - // TODO: consecutive dead objects on same page should be merged. +static uword_t sweep(lispobj* where, lispobj* end, + __attribute__((unused)) uword_t arg) +{ + sword_t nwords; + uword_t space_base = DYNAMIC_SPACE_START; + sword_t bitmap_index_bias = 0; +#ifdef LISP_FEATURE_IMMOBILE_SPACE + if (find_page_index(where) < 0) { + gc_assert(find_text_page_index(where) >= 0); + space_base = TEXT_SPACE_START; + bitmap_index_bias = text_index_bit_bias; + } +#endif for ( ; where < end ; where += nwords ) { - lispobj header = *where; - if (is_cons_half(header)) { - nwords = 2; - if (!cons_markedp((lispobj)where)) { - if (where[0] | where[1]) { - cons: - gc_dcheck(!immobile_space_p((lispobj)where)); - NOTE_GARBAGE(page_table[find_page_index(where)].gen, - where, 2, zeroed, - where[0] = where[1] = 0); - } - } + lispobj word = *where; + uword_t index = bitmap_index_bias + (((uword_t)where - space_base) >> (1+WORD_SHIFT)); + uword_t livep = + fullcgcmarks[index / N_WORD_BITS] & ((uword_t)1 << (index % N_WORD_BITS)); + if (is_header(word)) { + nwords = headerobj_size2(where, word); + if (!livep && header_widetag(word) != FILLER_WIDETAG) + clobber_headered_object(where, nwords); } else { - nwords = sizetab[header_widetag(header)](where); - lispobj markbit = MARK_BIT; - switch (header_widetag(header)) { - case BIGNUM_WIDETAG: markbit = BIGNUM_MARK_BIT; break; - case FDEFN_WIDETAG : markbit = FDEFN_MARK_BIT; break; - } - if (header & markbit) - *where = header ^ markbit; - else { - // Turn the object into either a (0 . 0) cons - // or an unboxed filler depending on size. - if (nwords <= 2) // could be SAP, SIMPLE-ARRAY-NIL, 1-word bignum, etc - goto cons; - struct code* code = (struct code*)where; - // Keep in sync with the definition of filler_obj_p() - if (!filler_obj_p((lispobj*)code)) { - page_index_t page = find_page_index(where); - int gen = page >= 0 ? page_table[page].gen - : immobile_obj_gen_bits(where); - NOTE_GARBAGE(gen, where, nwords, zeroed, { - code->boxed_size = 0; - code->header = (nwords << CODE_HEADER_SIZE_SHIFT) - | CODE_HEADER_WIDETAG; - memset(where+2, 0, (nwords - 2) * N_WORD_BYTES); - }) - } - } + nwords = 2; + if (!livep) where[0] = where[1] = (uword_t)-1; } } return 0; @@ -583,10 +642,19 @@ void execute_full_sweep_phase() memset(words_zeroed, 0, sizeof words_zeroed); #ifdef LISP_FEATURE_IMMOBILE_SPACE if (sweeplog) fprintf(sweeplog, "-- fixedobj space --\n"); - sweep_fixedobj_pages(words_zeroed); - if (sweeplog) fprintf(sweeplog, "-- varyobj space --\n"); - sweep((lispobj*)VARYOBJ_SPACE_START, varyobj_free_pointer, + sweep_fixedobj_pages(); + if (sweeplog) fprintf(sweeplog, "-- text space --\n"); + sweep((lispobj*)TEXT_SPACE_START, text_space_highwatermark, (uword_t)words_zeroed); + // Recompute generation masks for text space + int npages = (ALIGN_UP((uword_t)text_space_highwatermark, IMMOBILE_CARD_BYTES) + - TEXT_SPACE_START) / IMMOBILE_CARD_BYTES; + memset(text_page_genmask, 0, npages); + lispobj* where = (lispobj*)TEXT_SPACE_START; + for ( ; where < text_space_highwatermark ; where += object_size(where) ) + if (widetag_of(where) == CODE_HEADER_WIDETAG) + text_page_genmask[find_text_page_index(where)] + |= (1 << immobile_obj_gen_bits(where)); #endif if (sweeplog) fprintf(sweeplog, "-- dynamic space --\n"); walk_generation(sweep, -1, (uword_t)words_zeroed); @@ -597,24 +665,19 @@ void execute_full_sweep_phase() fprintf(stderr, "%ld%s", words_zeroed[i], i?"+":""); fprintf(stderr, " words zeroed]\n"); } - hopscotch_destroy(&mark_bits); + // deallocate the mark bits + os_deallocate((void*)fullcgcmarks, markbits_size); + fullcgcmarks = 0; markbits_size = 0; + if (sweeplog) fflush(sweeplog); - page_index_t first_page, last_page; - for (first_page = 0; first_page < next_free_page; ++first_page) - if (page_table[first_page].write_protected - && protection_mode(first_page) == PHYSICAL) { - last_page = first_page; - while (page_table[last_page+1].write_protected - && protection_mode(last_page+1) == PHYSICAL) - ++last_page; - os_protect(page_address(first_page), - (last_page - first_page + 1) * GENCGC_CARD_BYTES, - OS_VM_PROT_READ | OS_VM_PROT_EXECUTE); - first_page = last_page; - } - while (free_page < page_table_pages) { - page_table[free_page++].type = FREE_PAGE_FLAG; - } + page_index_t page; + // Give back all private-use pages and indicate need-to-zero + for (page = free_page; page < page_table_pages; ++page) { + gc_assert((page_table[page].type & PAGE_TYPE_MASK) == PAGE_TYPE_UNBOXED); + gc_assert(!page_bytes_used(page)); + set_page_need_to_zero(page, 1); + page_table[page].type = FREE_PAGE_FLAG; + } } diff --git a/src/runtime/funcall.c b/src/runtime/funcall.c index f55756e571..f2d05aa7ca 100644 --- a/src/runtime/funcall.c +++ b/src/runtime/funcall.c @@ -18,17 +18,16 @@ #include "sbcl.h" #include "runtime.h" #include "globals.h" -#include "os.h" #include "interrupt.h" extern lispobj call_into_lisp(lispobj fun, lispobj *args, int nargs) - #ifdef LISP_FEATURE_X86_64 __attribute__((sysv_abi)) #endif ; -#ifdef LISP_FEATURE_C_STACK_IS_CONTROL_STACK +#if defined(LISP_FEATURE_C_STACK_IS_CONTROL_STACK) || defined(LISP_FEATURE_ARM64) \ + || defined(LISP_FEATURE_ARM) /* These functions are an interface to the Lisp call-in facility. * Since this is C we can know nothing about the calling environment. * The control stack might be the C stack if called from the monitor @@ -79,7 +78,7 @@ lispobj funcall0(lispobj function) { lispobj **stack_pointer - = &access_control_stack_pointer(arch_os_get_current_thread()); + = &access_control_stack_pointer(get_sb_vm_thread()); lispobj *args = *stack_pointer; return call_into_lisp(function, args, 0); @@ -89,7 +88,7 @@ lispobj funcall1(lispobj function, lispobj arg0) { lispobj **stack_pointer - = &access_control_stack_pointer(arch_os_get_current_thread()); + = &access_control_stack_pointer(get_sb_vm_thread()); lispobj *args = *stack_pointer; *stack_pointer += 1; @@ -102,7 +101,7 @@ lispobj funcall2(lispobj function, lispobj arg0, lispobj arg1) { lispobj **stack_pointer - = &access_control_stack_pointer(arch_os_get_current_thread()); + = &access_control_stack_pointer(get_sb_vm_thread()); lispobj *args = *stack_pointer; *stack_pointer += 2; @@ -116,7 +115,7 @@ lispobj funcall3(lispobj function, lispobj arg0, lispobj arg1, lispobj arg2) { lispobj **stack_pointer - = &access_control_stack_pointer(arch_os_get_current_thread()); + = &access_control_stack_pointer(get_sb_vm_thread()); lispobj *args = *stack_pointer; *stack_pointer += 3; diff --git a/src/runtime/gc-assert.h b/src/runtime/gc-assert.h index 7de32ffc24..90669f31b3 100644 --- a/src/runtime/gc-assert.h +++ b/src/runtime/gc-assert.h @@ -27,19 +27,11 @@ /// Disable all assertions if NDEBUG #ifdef NDEBUG # define gc_assert(ex) ((void)0) -# define gc_assert_verbose(ex, fmt, ...) ((void)0) #else # define gc_assert(ex) \ do { \ if (!(ex)) gc_abort(); \ } while (0) -# define gc_assert_verbose(ex, fmt, ...) \ -do { \ - if (!(ex)) { \ - fprintf(stderr, fmt, ## __VA_ARGS__); \ - gc_abort(); \ - } \ -} while (0) #endif #endif diff --git a/src/runtime/gc-common.c b/src/runtime/gc-common.c index 5aa00f2222..566393688c 100644 --- a/src/runtime/gc-common.c +++ b/src/runtime/gc-common.c @@ -62,6 +62,14 @@ os_vm_size_t dynamic_space_size = DEFAULT_DYNAMIC_SPACE_SIZE; os_vm_size_t thread_control_stack_size = DEFAULT_CONTROL_STACK_SIZE; sword_t (*const scavtab[256])(lispobj *where, lispobj object); +uword_t gc_copied_nwords, gc_in_situ_live_nwords; + +/* If sb_sprof_enabled was used and the data are not in the final form + * (in the *SAMPLES* instance) then all code remains live. + * This is a weaker constraint than 'pin_all_dynamic_space_code' + * because the latter implies that all code is not potential garbage and not + * movable, whereas this only implies not potential garbage */ +int sb_sprof_enabled; // "Transport" functions are responsible for deciding where to copy an object // and how many bytes to copy (usually the sizing function is inlined into the @@ -80,19 +88,6 @@ struct cons *weak_vectors; os_vm_size_t bytes_consed_between_gcs = 12*1024*1024; -/* - * copying objects - */ - -/* gc_general_copy_object is inline from gc-internal.h */ - -/* to copy a boxed object */ -lispobj -copy_object(lispobj object, sword_t nwords) -{ - return gc_general_copy_object(object, nwords, BOXED_PAGE_FLAG); -} - #ifdef LISP_FEATURE_PPC64 // unevenly spaced pointer lowtags static void (*scav_ptr[16])(lispobj *where, lispobj object); /* forward decl */ @@ -103,61 +98,62 @@ static void (*scav_ptr[4])(lispobj *where, lispobj object); /* forward decl */ #define PTR_SCAVTAB_INDEX(ptr) ((uint32_t)ptr>>(N_LOWTAG_BITS-2))&3 #endif -static inline void scav1(lispobj* object_ptr, lispobj object) -{ - // GENCGC only: - // * With 32-bit words, is_lisp_pointer(object) returns true if object_ptr - // points to a forwarding pointer, so we need a sanity check inside the - // branch for is_lisp_pointer(). For maximum efficiency, check that only - // after from_space_p() returns false, so that valid pointers into - // from_space incur no extra test. This could be improved further by - // skipping the FP check if 'object' points within dynamic space, i.e., - // when find_page_index() returns >= 0. That would entail injecting - // from_space_p() explicitly into the loop, so as to separate the - // "was a page found at all" condition from the page generation test. - - // * With 64-bit words, is_lisp_pointer(object) is false when object_ptr - // points to a forwarding pointer, and the fixnump() test also returns - // false, so we'll indirect through scavtab[]. This will safely invoke - // scav_lose(), detecting corruption without any extra cost. - // The major difference between that and the explicit test is that you - // won't see 'start' and 'n_words', but if you need those, chances are - // you'll want to run under an external debugger in the first place. - // [And btw it sure would be nice to assert statically - // that is_lisp_pointer(0x01) is indeed false] - -#define FIX_POINTER() { \ - lispobj *ptr = native_pointer(object); \ - if (forwarding_pointer_p(ptr)) \ - *object_ptr = LOW_WORD(forwarding_pointer_value(ptr)); \ - else /* Scavenge that pointer. */ \ - scav_ptr[PTR_SCAVTAB_INDEX(object)](object_ptr, object); \ +/* Fixup the pointer in 'object' which is stored at *addr. + * That is, rewrite *addr if (and only if) 'object' got moved. + * + * As a precondition of calling this, 'object' must satisfy is_lisp_pointer(). + * + * For GENCGC only: + * - With 32-bit words, is_lisp_pointer(object) returns true if addr + * contains FORWARDING_HEADER (0x01), so we need a guard condition + * as the last case, to make error detection possible. + * - With 64-bit words, is_lisp_pointer(object) is false when addr + * contains FORWARDING_HEADER, so this function won't get called. + */ +static inline void scav1(lispobj* addr, lispobj object) +{ +#ifdef LISP_FEATURE_CHENEYGC + if (from_space_p(object)) { + if (forwarding_pointer_p(native_pointer(object))) + *addr = forwarding_pointer_value(native_pointer(object)); + else + scav_ptr[PTR_SCAVTAB_INDEX(object)](addr, object); + } +#else + /* In theory we can test forwarding_pointer_p on anything, but it's probably + * better to avoid reading more memory than needed. Hence the pre-check + * for a from_space object. But, rather than call from_space_p() which always + * checks for object pinning, it's a performance boost to treat from_space_p() + * as a leaky abstraction - reading one word at *native_pointer(object) is easier + * than looking in a hashset, and 9 times out of 10 times we need to read it anyway. + * And if the object was already forwarded, we never need pinned_p. + * + * Based on some instrumentation added to this function, I determined + * that it makes sense to read the 'gen' even if find_page_index() returns -1, + * because approximately 25% of all calls to scav1() *do* find that the object + * is in from_space. The guard condition on page_index is not needed + * because it is legal to access page_table at index -1. + * Therefore, when the object is in from_space, we incur one fewer branch */ + + page_index_t page = find_page_index((void*)object); + if (page_table[page].gen == from_space) { + if (forwarding_pointer_p(native_pointer(object))) + *addr = forwarding_pointer_value(native_pointer(object)); + else if (!pinned_p(object, page)) + scav_ptr[PTR_SCAVTAB_INDEX(object)](addr, object); } #ifdef LISP_FEATURE_IMMOBILE_SPACE - page_index_t page; - // It would be fine, though suboptimal, to use from_space_p() here. - // If it returns false, we don't want to call immobile_space_p() - // unless the pointer is *not* into dynamic space. - if ((page = find_page_index((void*)object)) >= 0) { - if (page_table[page].gen == from_space && !pinned_p(object, page)) - FIX_POINTER(); - } else if (immobile_space_p(object)) { + // Test immobile_space_p() only if object was definitely not in dynamic space + else if (page < 0 && immobile_space_p(object)) { lispobj *ptr = base_pointer(object); if (immobile_obj_gen_bits(ptr) == from_space) enliven_immobile_obj(ptr, 1); } -#else - if (from_space_p(object)) { - FIX_POINTER(); - } else { +#endif #if (N_WORD_BITS == 32) && defined(LISP_FEATURE_GENCGC) - if (forwarding_pointer_p(object_ptr)) - lose("unexpected forwarding pointer in scavenge @ %p", - object_ptr); + else if (object == FORWARDING_HEADER) + lose("unexpected forwarding pointer in scavenge @ %p", addr); #endif - /* It points somewhere other than oldspace. Leave it - * alone. */ - } #endif } @@ -171,6 +167,25 @@ inline void gc_scav_pair(lispobj where[2]) scav1(where+1, object); } +static sword_t scav_lose(lispobj *where, lispobj object) +{ + lose("no scavenge function for object %p (widetag %#x)", + (void*)object, widetag_of(where)); + + return 0; /* bogus return value to satisfy static type checking */ +} + +FILE *gc_activitylog_file; +FILE *gc_activitylog() +{ + char *pathname = "gc-action.log"; + if (!gc_activitylog_file) { + gc_activitylog_file = fopen(pathname, "w"); + fprintf(stderr, "opened %s\n", pathname); + } + return gc_activitylog_file; +} + // Scavenge a block of memory from 'start' to 'end' // that may contain object headers. void heap_scavenge(lispobj *start, lispobj *end) @@ -179,18 +194,26 @@ void heap_scavenge(lispobj *start, lispobj *end) for (object_ptr = start; object_ptr < end;) { lispobj object = *object_ptr; - if (other_immediate_lowtag_p(object)) + if (GC_LOGGING) fprintf(gc_activitylog(), "o %p\n", object_ptr); + if (other_immediate_lowtag_p(object)) { +#ifdef GC_DEBUG + /* This check for scav_lose() isn't strictly necessary, + * but a failure here is often clearer than ending up in + * scav_lose without knowing the [start,end] */ + if (scavtab[header_widetag(object)] == scav_lose) lose("Losing @ %p", object_ptr); +#endif /* It's some sort of header object or another. */ object_ptr += (scavtab[header_widetag(object)])(object_ptr, object); - else { // it's a cons + } else { // it's a cons gc_scav_pair(object_ptr); object_ptr += 2; } } // This assertion is usually the one that fails when something // is subtly wrong with the heap, so definitely always do it. - gc_assert_verbose(object_ptr == end, "Final object pointer %p, start %p, end %p\n", - object_ptr, start, end); + if (object_ptr != end) + lose("heap_scavenge failure: Final object pointer %p, start %p, end %p", + object_ptr, start, end); } // Scavenge a block of memory from 'start' extending for 'n_words' @@ -207,6 +230,71 @@ sword_t scavenge(lispobj *start, sword_t n_words) return n_words; } +/* Fix pointers in a range of memory from 'start' to 'end' where no raw words + * are allowed. Object headers and immediates are ignored, except that: + * - compact instance headers fix the layout + * - filler_widetag causes skipping of its payload. + * Recompute 'dirty' and return the new value as the logical OR of its initial + * value (determined by whether the card is sticky-marked) and whether + * any old->young pointer is seen. + * + * In case of card-spanning objects, the 'start' and 'end' parameters might not + * exactly delimit objects boundaries. */ +int descriptors_scavenge(lispobj *start, lispobj* end, + generation_index_t gen, int dirty) +{ + lispobj *where; + for (where = start; where < end; where++) { + lispobj ptr = *where; + int pointee_gen = 8; + // Nothing in the root set is forwardable. When I forgot to handle fillers, + // this assertion failed often, because we'd try to process old garbage. + gc_dcheck(ptr != 1); + if (is_lisp_pointer(ptr)) { + // A mostly copy-and-paste from scav1() + page_index_t page = find_page_index((void*)ptr); + if (page >= 0) { // Avoid falling into immobile_space_p if 'ptr' is to dynamic space + pointee_gen = page_table[page].gen; + if (pointee_gen == from_space) { + pointee_gen = new_space; + if (forwarding_pointer_p(native_pointer(ptr))) { + *where = forwarding_pointer_value(native_pointer(ptr)); + } else if (!pinned_p(ptr, page)) { + scav_ptr[PTR_SCAVTAB_INDEX(ptr)](where, ptr); + } + } + } +#ifdef LISP_FEATURE_IMMOBILE_SPACE + // do this only if object is definitely not in dynamic space. + else if (immobile_space_p(ptr)) { + immobile_obj: ; + lispobj *base = base_pointer(ptr); + int genbits = immobile_obj_gen_bits(base); + // The VISITED bit is masked out. Don't re-enliven visited. + // (VISITED = black in the traditional tri-color marking scheme) + pointee_gen = genbits & 0xf; + if (pointee_gen == from_space) pointee_gen = new_space; + if (genbits == from_space) enliven_immobile_obj(base, 1); + } +#endif + } +#ifdef LISP_FEATURE_IMMOBILE_SPACE + else if (instanceoid_widetag_p(ptr & WIDETAG_MASK) && ((ptr >>= 32) != 0)) + goto immobile_obj; +#endif + else { + // Advancing by the filler payload count (= total - 1) causes 'where' to + // align exactly to the next object after the loop steps by 1 as usual. + if (header_widetag(ptr) == FILLER_WIDETAG) + where += filler_total_nwords(ptr)-1; + continue; + } + // Dear lord, I hate the numbering scheme with SCRATCH_GENERATION higher than everything + if (pointee_gen < gen || pointee_gen == (1+PSEUDO_STATIC_GENERATION)) dirty = 1; + } + return dirty; +} + /* If 'fun' is provided, then call it on each livened object, * otherwise use scav1() */ void scav_binding_stack(lispobj* where, lispobj* end, void (*fun)(lispobj)) @@ -260,38 +348,11 @@ void scan_binding_stack() #endif } -static lispobj trans_fun_header(lispobj object); /* forward decls */ -static lispobj trans_short_boxed(lispobj object); - -static sword_t -scav_fun_pointer(lispobj *where, lispobj object) -{ - gc_dcheck(functionp(object)); - - /* Object is a pointer into from_space - not a FP. */ - lispobj *first_pointer = native_pointer(object); - - /* must transport object -- object may point to either a function - * header, a funcallable instance header, or a closure header. */ - lispobj copy = widetag_of(first_pointer) == SIMPLE_FUN_WIDETAG - ? trans_fun_header(object) : trans_short_boxed(object); - - if (copy != object) { - /* Set forwarding pointer */ - set_forwarding_pointer(first_pointer,copy); - } - - CHECK_COPY_POSTCONDITIONS(copy, FUN_POINTER_LOWTAG); - - *where = copy; - - return 1; -} - - +extern int pin_all_dynamic_space_code; static struct code * trans_code(struct code *code) { + gc_dcheck(!pin_all_dynamic_space_code); /* if object has already been transported, just return pointer */ if (forwarding_pointer_p((lispobj *)code)) { return (struct code *)native_pointer(forwarding_pointer_value((lispobj*)code)); @@ -300,20 +361,29 @@ trans_code(struct code *code) gc_dcheck(widetag_of(&code->header) == CODE_HEADER_WIDETAG); /* prepare to transport the code vector */ - lispobj l_code = (lispobj) LOW_WORD(code) | OTHER_POINTER_LOWTAG; - lispobj l_new_code = copy_large_object(l_code, - code_total_nwords(code), - CODE_PAGE_TYPE); - -#ifdef LISP_FEATURE_GENCGC - if (l_new_code == l_code) - return code; + long nwords = code_total_nwords(code); +#ifndef LISP_FEATURE_64_BIT + /* 32-bit can allocate large code to ordinary (small object) pages + * because it uses code regions larger than LARGE_OBJECT_SIZE. + * This makes large code accidentally fit into the region. + * We can correct that problem here by closing the code region. + * This is simpler than (or more abstract than) calling gc_alloc_large() + * because whatever post-copying actions gc_copy_object() performs, + * we still want, such as the NOTE_TRANSPORTING macro invocation */ + long nbytes = nwords << WORD_SHIFT; + if (nbytes >= LARGE_OBJECT_SIZE && !page_single_obj_p(find_page_index(code))) + ensure_region_closed(code_region, PAGE_TYPE_CODE); #endif + lispobj l_code = make_lispobj(code, OTHER_POINTER_LOWTAG); + lispobj l_new_code + = copy_potential_large_object(l_code, nwords, code_region, PAGE_TYPE_CODE); + + if (l_new_code == l_code) return code; set_forwarding_pointer((lispobj *)code, l_new_code); struct code *new_code = (struct code *) native_pointer(l_new_code); - uword_t displacement = l_new_code - l_code; + sword_t displacement = l_new_code - l_code; #if defined LISP_FEATURE_PPC || defined LISP_FEATURE_PPC64 || \ defined LISP_FEATURE_X86 || defined LISP_FEATURE_X86_64 @@ -337,25 +407,79 @@ trans_code(struct code *code) } }) gencgc_apply_code_fixups(code, new_code); -#ifdef LISP_FEATURE_GENCGC - /* Cheneygc doesn't need this os_flush_icache, it flushes the whole - spaces once when all copying is done. */ os_flush_icache(code_text_start(new_code), code_text_size(new_code)); -#endif return new_code; } -sword_t scav_code_header(lispobj *object, lispobj header); +#ifdef LISP_FEATURE_64_BIT +# define layout_flags(x) x->sw_flags +#else +# define layout_flags(x) x->uw_flags +#endif -static lispobj -trans_code_header(lispobj object) +static sword_t +scav_fun_pointer(lispobj *where, lispobj object) { - struct code *ncode = trans_code((struct code *) native_pointer(object)); - return (lispobj) LOW_WORD(ncode) | OTHER_POINTER_LOWTAG; + gc_dcheck(functionp(object)); + + lispobj* fun = (void*)(object - FUN_POINTER_LOWTAG); + lispobj copy; + int widetag = widetag_of(fun); + // object may be a simple-fun header, a funcallable instance, or closure + if (widetag == SIMPLE_FUN_WIDETAG) { + uword_t offset = (HeaderValue(*fun) & FUN_HEADER_NWORDS_MASK) * N_WORD_BYTES; + /* Transport the whole code object */ + struct code *code = trans_code((struct code *) ((uword_t) fun - offset)); + copy = make_lispobj((char*)code + offset, FUN_POINTER_LOWTAG); + } else { + int page_type = PAGE_TYPE_SMALL_MIXED; + void* region = small_mixed_region; + if (widetag == FUNCALLABLE_INSTANCE_WIDETAG) { + /* funcallable-instance might have all descriptor slots + * except for the trampoline, which points to an asm routine. + * This is not true for self-contained trampoline GFs though. */ +#ifdef LISP_FEATURE_IMMOBILE_SPACE + page_type = PAGE_TYPE_CODE, region = code_region; +#else + struct layout* layout = (void*)native_pointer(funinstance_layout(FUNCTION(object))); + if (layout && (layout_flags(layout) & STRICTLY_BOXED_FLAG)) + page_type = PAGE_TYPE_BOXED, region = boxed_region; +#endif + } else { + /* Closures can always go on strictly boxed pages even though the + * underlying function is (possibly) an untagged pointer. + * When a closure is scavenged as a root, it can't need to fix the + * value in closure->fun because that function has to be _older_ than + * (or the same gen as) the closure. So if it's older, then it's not + * in from_space. But what if it's the same? It's still not in + * from_space, because the closure and its function have + * generation >= (1+from_space) to be generational roots */ + page_type = PAGE_TYPE_BOXED, region = boxed_region; + } + copy = gc_copy_object(object, 1+SHORT_BOXED_NWORDS(*fun), region, page_type); + gc_assert(copy != object); +#ifdef LISP_FEATURE_IMMOBILE_SPACE + if (widetag == FUNCALLABLE_INSTANCE_WIDETAG) { + struct funcallable_instance* old = (void*)native_pointer(object); + struct funcallable_instance* new = (void*)native_pointer(copy); + if (old->trampoline == (lispobj)&old->instword1) + new->trampoline = (lispobj)&new->instword1; + } +#endif + set_forwarding_pointer(fun, copy); + } + if (copy != object) *where = copy; + CHECK_COPY_POSTCONDITIONS(copy, FUN_POINTER_LOWTAG); + return 1; } -static sword_t -size_code_header(lispobj *where) +static lispobj trans_code_blob(lispobj object) +{ + return make_lispobj(trans_code((struct code *)native_pointer(object)), + OTHER_POINTER_LOWTAG); +} + +static sword_t size_code_blob(lispobj *where) { return code_total_nwords((struct code*)where); } @@ -376,14 +500,13 @@ trans_return_pc_header(lispobj object) uword_t offset = HeaderValue(return_pc->header) * N_WORD_BYTES; /* Transport the whole code object */ - struct code *code = (struct code *) ((uword_t) return_pc - offset); - struct code *ncode = trans_code(code); + struct code *code = trans_code((struct code *) ((uword_t) return_pc - offset)); - return ((lispobj) LOW_WORD(ncode) + offset) | OTHER_POINTER_LOWTAG; + return make_lispobj((char*)code + offset, OTHER_POINTER_LOWTAG); } #endif /* RETURN_PC_WIDETAG */ -#if defined(LISP_FEATURE_X86) || defined(LISP_FEATURE_X86_64) +#if defined(LISP_FEATURE_X86) || defined(LISP_FEATURE_X86_64) || defined(LISP_FEATURE_ARM64) /* Closures hold a pointer to the raw simple-fun entry address instead of the * tagged object so that CALL [RAX+const] can be used to invoke it. */ static sword_t @@ -399,45 +522,57 @@ scav_closure(lispobj *where, lispobj header) } int payload_words = SHORT_BOXED_NWORDS(header); // Payload includes 'fun' which was just looked at, so subtract it. - scavenge(closure->info, payload_words - 1); + scavenge(1 + &closure->fun, payload_words - 1); return 1 + payload_words; } #endif - -#if !(defined(LISP_FEATURE_X86) || defined(LISP_FEATURE_X86_64)) -static sword_t -scav_fun_header(lispobj *where, lispobj object) -{ - lose("attempted to scavenge a function header where=%p object=%"OBJ_FMTX, - where, object); - return 0; /* bogus return value to satisfy static type checking */ -} -#endif /* LISP_FEATURE_X86 */ - -static lispobj -trans_fun_header(lispobj object) -{ - struct simple_fun *fheader = (struct simple_fun *) native_pointer(object); - uword_t offset = - (HeaderValue(fheader->header) & FUN_HEADER_NWORDS_MASK) * N_WORD_BYTES; - - /* Transport the whole code object */ - struct code *code = (struct code *) ((uword_t) fheader - offset); - struct code *ncode = trans_code(code); - - return ((lispobj) LOW_WORD(ncode) + offset) | FUN_POINTER_LOWTAG; -} - /* * instances */ +int n_unboxed_instances; + +/* If there are no raw words then we want to use a BOXED page if the instance + * length is small. Or if there are only raw words and immediates, then use UNBOXED. + * A bitmap of 0 implies that this instance could never be subject to CHANGE-CLASS, + * so it will never gain tagged slots. If all slots are immediates, + * then both constraints are satisfied; prefer UNBOXED. + * + * If the page is unboxed, the layout has to be pseudostatic. + * As to the restriction on instance length: refer to the comment above + * scan_contiguous_boxed_cards in gencgc. + */ static inline lispobj copy_instance(lispobj object) { // Object is an un-forwarded object in from_space lispobj header = *(lispobj*)(object - INSTANCE_POINTER_LOWTAG); int original_length = instance_length(header); + + void* region = small_mixed_region; + int page_type = PAGE_TYPE_SMALL_MIXED; + + struct layout* layout = (void*)native_pointer(instance_layout(INSTANCE(object))); + struct bitmap bitmap; + const int words_per_card = GENCGC_CARD_BYTES>>WORD_SHIFT; + if (layout) { + generation_index_t layout_gen = 0; +# ifdef LISP_FEATURE_IMMOBILE_SPACE + if (find_fixedobj_page_index(layout)) + layout_gen = immobile_obj_generation((lispobj*)layout); +# else + page_index_t p = find_page_index(layout); + if (p >= 0) layout_gen = page_table[p].gen; +# endif + if (layout_gen == PSEUDO_STATIC_GENERATION + && (bitmap = get_layout_bitmap(layout)).bits[0] == 0 + && bitmap.nwords == 1) + page_type = PAGE_TYPE_UNBOXED, region = unboxed_region; + else if (original_length < words_per_card && + (layout_flags(layout) & STRICTLY_BOXED_FLAG)) + page_type = PAGE_TYPE_BOXED, region = boxed_region; + } + lispobj copy; // KLUDGE: reading both flags at once doesn't really work // unless either we know what the opaque values are: @@ -449,9 +584,10 @@ static inline lispobj copy_instance(lispobj object) /* If odd, add 1 (making even). Rounding that to odd and then * adding 1 for the header will effectively add 2 words. * Otherwise, don't add anything because a padding slot exists */ + int old_nwords = 1 + (original_length|1); int new_length = original_length + (original_length & 1); - copy = gc_copy_object_resizing(object, 1 + (new_length|1), BOXED_PAGE_FLAG, - 1 + (original_length|1)); + copy = gc_copy_object_resizing(object, 1 + (new_length|1), + region, page_type, old_nwords); lispobj *base = native_pointer(copy); /* store the old address as the hash value */ #ifdef LISP_FEATURE_64_BIT @@ -471,10 +607,12 @@ static inline lispobj copy_instance(lispobj object) (void*)object, original_length, (void*)copy, new_length, instance_length(*base)); #endif + set_forwarding_pointer_resized(native_pointer(object), copy, old_nwords); } else { - copy = copy_object(object, 1 + (original_length|1)); + int nwords = 1 + (original_length|1); + copy = gc_copy_object(object, nwords, region, page_type); + set_forwarding_pointer(native_pointer(object), copy); } - set_forwarding_pointer(native_pointer(object), copy); return copy; } @@ -485,7 +623,7 @@ scav_instance_pointer(lispobj *where, lispobj object) lispobj copy = copy_instance(object); *where = copy; - struct instance* node = (struct instance*)(copy - INSTANCE_POINTER_LOWTAG); + struct instance* node = INSTANCE(copy); lispobj layout = instance_layout((lispobj*)node); if (layout) { if (forwarding_pointer_p((lispobj*)LAYOUT(layout))) @@ -499,7 +637,7 @@ scav_instance_pointer(lispobj *where, lispobj object) && !forwarding_pointer_p(native_pointer(object))) { copy = copy_instance(object); node->slots[INSTANCE_DATA_START] = copy; - node = (struct instance*)(copy - INSTANCE_POINTER_LOWTAG); + node = INSTANCE(copy); // We don't have to stop upon seeing an instance with a different layout. // The only other object in the 'next' chain could be *TAIL-ATOM* if we reach // the end. It's possible that all of the tests in the 'while' loop are met @@ -527,7 +665,8 @@ trans_list(lispobj object) { /* Copy 'object'. */ struct cons *copy = (struct cons *) - gc_general_alloc(sizeof(struct cons), BOXED_PAGE_FLAG); + gc_general_alloc(cons_region, sizeof(struct cons), PAGE_TYPE_CONS); + NOTE_TRANSPORTING(object, copy, CONS_SIZE); lispobj new_list_pointer = make_lispobj(copy, LIST_POINTER_LOWTAG); copy->car = CONS(object)->car; /* Grab the cdr: set_forwarding_pointer will clobber it in GENCGC */ @@ -544,7 +683,8 @@ trans_list(lispobj object) } /* Copy 'cdr'. */ struct cons *cdr_copy = (struct cons*) - gc_general_alloc(sizeof(struct cons), BOXED_PAGE_FLAG); + gc_general_alloc(cons_region, sizeof(struct cons), PAGE_TYPE_CONS); + NOTE_TRANSPORTING(cdr, cdr_copy, CONS_SIZE); cdr_copy->car = ((struct cons*)native_cdr)->car; /* Grab the cdr before it is clobbered. */ lispobj next = ((struct cons*)native_cdr)->cdr; @@ -589,16 +729,11 @@ scav_other_pointer(lispobj *where, lispobj object) // If the object was large, then instead of transporting it, // gencgc might simply promote the pages and return the same pointer. - // That decision is made in general_copy_large_object(). + // That decision is made in copy_potential_large_object(). if (copy != object) { set_forwarding_pointer(first_pointer, copy); -#ifdef LISP_FEATURE_GENCGC *where = copy; -#endif } -#ifndef LISP_FEATURE_GENCGC - *where = copy; -#endif CHECK_COPY_POSTCONDITIONS(copy, OTHER_POINTER_LOWTAG); return 1; } @@ -607,6 +742,11 @@ scav_other_pointer(lispobj *where, lispobj object) * immediate, boxed, and unboxed objects */ +static sword_t size_filler(lispobj *where) { return filler_total_nwords(*where); } +static sword_t scav_filler(__attribute__((unused)) lispobj *where, lispobj object) { + return filler_total_nwords(object); +} + /* The immediate object scavenger basically wants to be "scav_cons", * and so returns 2. To see why it's right, observe that scavenge() will * not invoke a scavtab entry on any object except for one satisfying @@ -636,93 +776,119 @@ scav_immediate(lispobj *where, lispobj object) return 2; } -static sword_t -size_immediate(lispobj __attribute__((unused)) *where) +#ifdef LISP_FEATURE_PPC64 +/* Dead conses are clobbered to contain all 1s. The first word of such a cons + * does NOT look like a valid cons half due to unusual lowtag arrangement */ +static sword_t scav_consfiller(lispobj *where, lispobj object) { - return 1; + gc_assert(object == (uword_t)-1); + gc_assert(where[1] == (uword_t)-1); + return 2; } - -static inline boolean bignum_logbitp_inline(int index, struct bignum* bignum) +static sword_t size_consfiller(lispobj *where) { - int len = HeaderValue(bignum->header); - int word_index = index / N_WORD_BITS; - int bit_index = index % N_WORD_BITS; - return word_index < len ? (bignum->digits[word_index] >> bit_index) & 1 : 0; + gc_assert(where[0] == (uword_t)-1 && where[1] == (uword_t)-1); + return 2; } -boolean positive_bignum_logbitp(int index, struct bignum* bignum) -{ - /* If the bignum in the layout has another pointer to it (besides the layout) - acting as a root, and which is scavenged first, then transporting the - bignum causes the layout to see a FP, as would copying an instance whose - layout that is. This is a nearly impossible scenario to create organically - in Lisp, because mostly nothing ever looks again at that exact (EQ) bignum - except for a few things that would cause it to be pinned anyway, - such as it being kept in a local variable during structure manipulation. - See 'interleaved-raw.impure.lisp' for a way to trigger this */ - if (forwarding_pointer_p((lispobj*)bignum)) { - lispobj forwarded = forwarding_pointer_value((lispobj*)bignum); -#if 0 - fprintf(stderr, "GC bignum_logbitp(): fwd from %p to %p\n", - (void*)bignum, (void*)forwarded); #endif - bignum = (struct bignum*)native_pointer(forwarded); - } - return bignum_logbitp_inline(index, bignum); + +//// General boxed object scav/trans/size functions + +#define DEF_SCAV_BOXED(suffix, sizer) \ + static sword_t __attribute__((unused)) \ + scav_##suffix(lispobj *where, lispobj header) { \ + return 1 + scavenge(where+1, sizer(header)); \ + } \ + static sword_t size_##suffix(lispobj *where) { return 1 + sizer(*where); } + +DEF_SCAV_BOXED(boxed, BOXED_NWORDS) +DEF_SCAV_BOXED(short_boxed, SHORT_BOXED_NWORDS) +DEF_SCAV_BOXED(tiny_boxed, TINY_BOXED_NWORDS) + +static lispobj trans_boxed(lispobj object) { + return gc_copy_object(object, 1 + BOXED_NWORDS(*native_pointer(object)), + boxed_region, PAGE_TYPE_BOXED); +} +static lispobj trans_tiny_mixed(lispobj object) { + return gc_copy_object(object, 1 + TINY_BOXED_NWORDS(*native_pointer(object)), + small_mixed_region, PAGE_TYPE_SMALL_MIXED); } -// Helper function for stepping through the tagged slots of an instance in -// scav_instance and verify_space. -void -instance_scan(void (*proc)(lispobj*, sword_t, uword_t), - lispobj *instance_slots, - sword_t nslots, /* number of payload words */ - lispobj layout_bitmap, - uword_t arg) -{ - sword_t index; - - if (fixnump(layout_bitmap)) { - if (layout_bitmap == make_fixnum(-1)) - proc(instance_slots, nslots, arg); - else { - sword_t bitmap = fixnum_value(layout_bitmap); // signed integer! - for (index = 0; index < nslots ; index++, bitmap >>= 1) - if (bitmap & 1) - proc(instance_slots + index, 1, arg); - } - } else { /* huge bitmap */ - struct bignum * bitmap; - bitmap = (struct bignum*)native_pointer(layout_bitmap); - for (index = 0; index < nslots ; index++) - if (bignum_logbitp_inline(index, bitmap)) - proc(instance_slots + index, 1, arg); - } +static sword_t scav_symbol(lispobj *where, lispobj header) { +#ifdef LISP_FEATURE_COMPACT_SYMBOL + struct symbol* s = (void*)where; + scavenge(&s->value, 3); // value, function, info + lispobj name = decode_symbol_name(s->name); + lispobj new = name; + scavenge(&new, 1); + if (new != name) set_symbol_name(s, new); + int indicated_nwords = (header>>N_WIDETAG_BITS) & 0xFF; + return 1 + (indicated_nwords|1); // round to odd, then add 1 for the header +#else + return scav_tiny_boxed(where, header); +#endif +} + +static inline int array_header_nwords(lispobj header) { + unsigned char rank = (header >> ARRAY_RANK_POSITION); + ++rank; // wraparound from 255 to 0 + int nwords = sizeof (struct array)/N_WORD_BYTES + (rank-1); + return ALIGN_UP(nwords, 2); +} +static sword_t scav_array(lispobj *where, lispobj header) { + struct array* a = (void*)where; + scav1(&a->data, a->data); + // displaced_p sounds like it would be T or NIL, but it is overloaded + // to hold information for situations where array A is displaced to an + // expressly adjustable array B which gets adjusted to become too small + // to contain all the elements of A. + scav1(&a->displaced_p, a->displaced_p); + scav1(&a->displaced_from, a->displaced_from); + return array_header_nwords(header); +} +static lispobj trans_array(lispobj object) { + // VECTOR is a lie but I'm using it only to subtract the lowtag + return gc_copy_object(object, array_header_nwords(VECTOR(object)->header), + boxed_region, PAGE_TYPE_BOXED); } +static sword_t size_array(lispobj *where) { return array_header_nwords(*where); } static sword_t scav_instance(lispobj *where, lispobj header) { - int nslots = instance_length(header) | 1; - if (!instance_layout(where)) return 1 + nslots; + int nslots = instance_length(header); // un-padded length + int total_nwords = 1 + (nslots | 1); - lispobj *layout = native_pointer(instance_layout(where)); -#ifdef LISP_FEATURE_COMPACT_INSTANCE_HEADER - if (immobile_obj_gen_bits(layout) == from_space) - enliven_immobile_obj(layout, 1); + // First things first: fix or enliven the layout pointer as necessary, + // writing it back if and only if it changed. + lispobj layoutptr = instance_layout(where); + if (!layoutptr) return total_nwords; // instance can't point to any data yet +#ifdef LISP_FEATURE_METASPACE + struct layout *layout = LAYOUT(layoutptr); // layouts never move in metaspace + scav1(&layout->friend, layout->friend); #else - if (forwarding_pointer_p(layout)) - layout = native_pointer(forwarding_pointer_value(layout)); + lispobj old = layoutptr; + scav1(&layoutptr, layoutptr); + if (layoutptr != old) instance_layout(where) = layoutptr; + struct layout *layout = LAYOUT(layoutptr); #endif - lispobj lbitmap = ((struct layout*)layout)->bitmap; - if (lbitmap == make_fixnum(-1)) { - scavenge(where+1, nslots); - return 1 + nslots; + struct bitmap bitmap = get_layout_bitmap(layout); + sword_t mask = bitmap.bits[0]; // there's always at least 1 bitmap word + + if (bitmap.nwords == 1) { + if ((uword_t)mask == (uword_t)-1 << INSTANCE_DATA_START) { + // Easy case: all slots are tagged words + scavenge(where+1+INSTANCE_DATA_START, nslots-INSTANCE_DATA_START); + return total_nwords; + } + if (mask == 0) return total_nwords; // trivial case: no tagged words } + // Specially scavenge the 'next' slot of a lockfree list node. If the node is // pending deletion, 'next' will satisfy fixnump() but is in fact a pointer. // GC doesn't care too much about the deletion algorithm, but does have to // ensure liveness of the pointee, which may move unless pinned. - if (lockfree_list_node_layout_p((struct layout*)layout)) { + if (lockfree_list_node_layout_p(layout)) { struct instance* node = (struct instance*)where; lispobj next = node->slots[INSTANCE_DATA_START]; if (fixnump(next) && next) { // ignore initially 0 heap words @@ -733,92 +899,108 @@ scav_instance(lispobj *where, lispobj header) node->slots[INSTANCE_DATA_START] = descriptor & ~LOWTAG_MASK; } } - if (!fixnump(lbitmap)) { - /* It is conceivable that 'lbitmap' points to from_space, AND that it - * is stored in one of the slots of the instance about to be scanned. - * If so, then forwarding it will deposit new bits into its first - * one or two words, rendering it bogus for use as the instance's bitmap. - * So scavenge it up front to fix its address */ - scav1(&lbitmap, lbitmap); - instance_scan((void(*)(lispobj*,sword_t,uword_t))scavenge, - where+1, nslots, lbitmap, 0); - } else { - sword_t bitmap = fixnum_value(lbitmap); // signed integer! - int n = nslots; - lispobj obj; - for ( ; n-- ; bitmap >>= 1) { - ++where; - if ((bitmap & 1) && is_lisp_pointer(obj = *where)) - scav1(where, obj); - } + + ++where; // skip over the header + lispobj obj; + unsigned int end_word_index = bitmap.nwords - 1; + if (end_word_index) { // > 1 word + unsigned int bitmap_word_index = 0; + // 'mask' was preloaded with the bitmap.bits[0] + do { + // I suspect that mutating a structure layout with raw slots + // could cause this assertion to fail, but at least we'll catch + // that the user did something dangerous, exiting with an error + // rather than causing heap corruption. + if (nslots < N_WORD_BITS) lose("Mutated structure layout %p", (void*)layout); + nslots -= N_WORD_BITS; + lispobj* limit = where + N_WORD_BITS; + do { + if ((mask & 1) && is_lisp_pointer(obj = *where)) scav1(where, obj); + mask >>= 1; + } while (++where < limit); + mask = bitmap.bits[++bitmap_word_index]; + } while (bitmap_word_index != end_word_index); } - return 1 + nslots; + // Scan at most N_WORD_BITS more using the final word of the mask. + // But there may be 0 slots remaining, or more than N_WORD_BITS slots remaining. + int count = nslots <= N_WORD_BITS ? nslots : N_WORD_BITS; + lispobj* limit = where + count; + for ( ; where < limit ; mask >>= 1, ++where ) + if ((mask & 1) && is_lisp_pointer(obj = *where)) scav1(where, obj); + nslots -= count; + + // Finally, see if the mask has its top bit on and there are more slots + if (mask < 0 && nslots != 0) scavenge(where, nslots); + return total_nwords; } static sword_t size_instance(lispobj *where) { return 1 + (instance_length(*where) | 1); } -#ifdef LISP_FEATURE_COMPACT_INSTANCE_HEADER static sword_t scav_funinstance(lispobj *where, lispobj header) { - // Do a similar thing as scav_instance but do not split into 3 cases - // based on whether the bitmap is a fixnum or a bignum or the special - // case of all tagged; it's always a fixnum, with at least 1 raw slot. - int nslots = SHORT_BOXED_NWORDS(header); - if (!instance_layout(where)) return 1 + nslots; - - lispobj *layout = native_pointer(instance_layout(where)); - if (immobile_obj_gen_bits(layout) == from_space) - enliven_immobile_obj(layout, 1); - lispobj lbitmap = ((struct layout*)layout)->bitmap; - gc_assert(fixnump(lbitmap)); - sword_t bitmap = fixnum_value(lbitmap); - int n = nslots; - lispobj obj; - for ( ; n-- ; bitmap >>= 1) { - ++where; - if ((bitmap & 1) && is_lisp_pointer(obj = *where)) - scav1(where, obj); - } - return 1 + nslots; -} + int nslots = HeaderValue(header) & SHORT_HEADER_MAX_WORDS; + // First things first: fix or enliven the layout pointer as necessary, + // writing it back if and only if it changed. + lispobj layoutptr = funinstance_layout(where); + if (!layoutptr) return 1 + (nslots | 1); // skip, instance can't point to data +#ifdef LISP_FEATURE_METASPACE + struct layout * layout = LAYOUT(layoutptr); + scav1(&layout->friend, layout->friend); +#else + lispobj old = layoutptr; + scav1(&layoutptr, layoutptr); + if (layoutptr != old) funinstance_layout(where) = layoutptr; #endif + struct funcallable_instance* fin = (void*)where; +#ifdef LISP_FEATURE_IMMOBILE_SPACE + // payload: entry addr, 2 raw words, implementation function + scavenge(&fin->function, nslots-3); +#else + // payload: trampoline entry addr, layout, implementation function, ... + scavenge(&fin->function, nslots-2); +#endif + return 1 + (nslots | 1); +} -//// Boxed object scav/trans/size functions - -#define DEF_SCAV_BOXED(suffix, sizer) \ - static sword_t __attribute__((unused)) \ - scav_##suffix(lispobj *where, lispobj header) { \ - return 1 + scavenge(where+1, sizer(header)); \ - } \ - static lispobj trans_##suffix(lispobj object) { \ - return copy_object(object, 1 + sizer(*native_pointer(object))); \ - } \ - static sword_t size_##suffix(lispobj *where) { return 1 + sizer(*where); } - -DEF_SCAV_BOXED(boxed, BOXED_NWORDS) -DEF_SCAV_BOXED(short_boxed, SHORT_BOXED_NWORDS) -DEF_SCAV_BOXED(tiny_boxed, TINY_BOXED_NWORDS) - -/* Bignums use the high bit as the mark, and all remaining bits - * excluding the 8 widetag bits to convey the size. - * To size it, shift out the high bit, the shift right by an extra bit, - * round to odd, and add 1 for the header. */ +/* Bignums use the highest bit of the header word as the GC mark bit. + * + * If assertions are enabled, the number of words taken up is double + * what it would ordinarily be, which is a gross overstatement of the + * the number of words actually needed for sanity-check bits, + * i.e. ALIGN_UP(CEILING(nwords,N_WORD_BITS),2) + * but the allocator is simplified by just doubling the space, + * and it doesn't matter because this is only for testing */ +static inline size_t bignum_nwords(lispobj header) { +#ifdef LISP_FEATURE_BIGNUM_ASSERTIONS + // FIXME: how did I arrive at this constant? (being less than the other by some bits) + int ndigits = ((unsigned int)header >> 8) & 0x7fffff; + return 2 * ndigits + 2; +#else + // NOTE: a better name for this constant would be BIGNUM_LENGTH_MASK, + // because hypothetically we could want a max length of #x7FFFC + // which would have a mask of #x7FFFF to not lose the low bits. + size_t ndigits = (header >> N_WIDETAG_BITS) & MAXIMUM_BIGNUM_LENGTH; + return 1 + (ndigits | 1); // round-to-odd + account for the header +#endif +} static inline sword_t size_bignum(lispobj *where) { - return 1 + ((*where << 1 >> (1+N_WIDETAG_BITS)) | 1); + return bignum_nwords(*where); +} +static sword_t scav_bignum(lispobj __attribute__((unused)) *where, lispobj header) { + return bignum_nwords(header); } - static lispobj trans_bignum(lispobj object) { gc_dcheck(lowtag_of(object) == OTHER_POINTER_LOWTAG); - return copy_large_object(object, size_bignum(native_pointer(object)), - UNBOXED_PAGE_FLAG); + return copy_potential_large_object(object, bignum_nwords(*native_pointer(object)), + unboxed_region, PAGE_TYPE_UNBOXED); } #ifndef LISP_FEATURE_X86_64 -lispobj fdefn_callee_lispobj(struct fdefn* fdefn) { +lispobj decode_fdefn_rawfun(struct fdefn* fdefn) { lispobj raw_addr = (lispobj)fdefn->raw_addr; if (!raw_addr || points_to_asm_code_p(raw_addr)) // technically this should return the address of the code object @@ -833,15 +1015,16 @@ scav_fdefn(lispobj *where, lispobj __attribute__((unused)) object) { struct fdefn *fdefn = (struct fdefn *)where; scavenge(where + 1, 2); // 'name' and 'fun' - lispobj obj = fdefn_callee_lispobj(fdefn); + lispobj obj = decode_fdefn_rawfun(fdefn); lispobj new = obj; scavenge(&new, 1); - if (new != obj) fdefn->raw_addr += (new - obj); + if (new != obj) fdefn->raw_addr += (sword_t)(new - obj); // Payload length is not computed from the header return FDEFN_SIZE; } static lispobj trans_fdefn(lispobj object) { - return copy_object(object, FDEFN_SIZE); + return gc_copy_object(object, FDEFN_SIZE, + small_mixed_region, PAGE_TYPE_SMALL_MIXED); } static sword_t size_fdefn(lispobj __attribute__((unused)) *where) { return FDEFN_SIZE; @@ -881,28 +1064,36 @@ trans_ratio_or_complex(lispobj object) { return copy_unboxed_object(object, 4); } - return copy_object(object, 4); + return gc_copy_object(object, 4, boxed_region, PAGE_TYPE_BOXED); } /* vector-like objects */ static lispobj -trans_vector(lispobj object) +trans_vector_t(lispobj object) { gc_dcheck(lowtag_of(object) == OTHER_POINTER_LOWTAG); - sword_t length = fixnum_value(VECTOR(object)->length); - return copy_large_object(object, ALIGN_UP(length + 2, 2), BOXED_PAGE_FLAG); + struct vector*v = VECTOR(object); + sword_t length = vector_len(v); + unsigned int mask = (VECTOR_ALLOC_MIXED_REGION_BIT + | (flag_VectorWeak << ARRAY_FLAGS_POSITION)); + void* region = boxed_region; + int page_type = PAGE_TYPE_BOXED; + if (!length) + page_type = PAGE_TYPE_UNBOXED, region = unboxed_region; + else if (v->header & mask) + page_type = PAGE_TYPE_SMALL_MIXED, region = small_mixed_region; + return copy_potential_large_object(object, ALIGN_UP(length + 2, 2), region, page_type); } static sword_t -size_vector(lispobj *where) +size_vector_t(lispobj *where) { - sword_t length = fixnum_value(((struct vector*)where)->length); + sword_t length = vector_len(((struct vector*)where)); return ALIGN_UP(length + 2, 2); } -static inline uword_t -NWORDS(uword_t x, uword_t n_bits) +static inline uword_t NWORDS(uword_t x, uword_t n_bits) { /* A good compiler should be able to constant-fold this whole thing, even with the conditional. */ @@ -918,32 +1109,56 @@ NWORDS(uword_t x, uword_t n_bits) } } -#define DEF_SCAV_TRANS_SIZE_UB(nbits) \ - DEF_SPECIALIZED_VECTOR(vector_unsigned_byte_##nbits, NWORDS(length, nbits)) +#ifdef LISP_FEATURE_UBSAN +// If specialized vectors point to a vector of bits in their first +// word after the header, they can't be relocated to unboxed pages. +#define SPECIALIZED_VECTOR_ARGS small_mixed_region, PAGE_TYPE_SMALL_MIXED +#else +#define SPECIALIZED_VECTOR_ARGS unboxed_region, PAGE_TYPE_UNBOXED +#endif + +static inline void check_shadow_bits(__attribute((unused)) lispobj* v) { +#ifdef LISP_FEATURE_UBSAN + if (is_lisp_pointer(v[1])) { + scavenge(v + 1, 1); // shadow bits + if (vector_len((struct vector*)native_pointer(v[1])) < vector_len((struct vector*)v)) + lose("messed up shadow bits for %p\n", v); + } else if (v[1]) { + char *origin_pc = (char*)(v[1]>>4); + lispobj* code = component_ptr_from_pc(origin_pc); + if (code) scavenge((lispobj*)&code, 1); + /* else if (widetag_of(v)==SIMPLE_VECTOR_WIDETAG) + lose("can't find code containing %p (vector=%p)", origin_pc, v); */ + } +#endif +} + #define DEF_SPECIALIZED_VECTOR(name, nwords) \ static sword_t __attribute__((unused)) scav_##name(\ lispobj *where, lispobj __attribute__((unused)) header) { \ - sword_t length = fixnum_value(((struct vector*)where)->length); \ + check_shadow_bits(where); \ + sword_t length = vector_len(((struct vector*)where)); \ return ALIGN_UP(nwords + 2, 2); \ } \ static lispobj __attribute__((unused)) trans_##name(lispobj object) { \ gc_dcheck(lowtag_of(object) == OTHER_POINTER_LOWTAG); \ - sword_t length = fixnum_value(VECTOR(object)->length); \ - return copy_large_object(object, ALIGN_UP(nwords + 2, 2), UNBOXED_PAGE_FLAG); \ + sword_t length = vector_len(VECTOR(object)); \ + return copy_potential_large_object(object, ALIGN_UP(nwords + 2, 2), \ + SPECIALIZED_VECTOR_ARGS); \ } \ static sword_t __attribute__((unused)) size_##name(lispobj *where) { \ - sword_t length = fixnum_value(((struct vector*)where)->length); \ + sword_t length = vector_len(((struct vector*)where)); \ return ALIGN_UP(nwords + 2, 2); \ } DEF_SPECIALIZED_VECTOR(vector_nil, 0*length) DEF_SPECIALIZED_VECTOR(vector_bit, NWORDS(length,1)) -/* NOTE: strings contain one more element of data (a terminating '\0' +/* NOTE: base strings contain one more element of data (a terminating '\0' * to help interface with C functions) than indicated by the length slot. - * This is true even for UCS4 strings, despite that C APIs are unlikely - * to have a convention that expects 4 zero bytes. */ + * UCS4 strings do not get a terminator element */ DEF_SPECIALIZED_VECTOR(base_string, NWORDS((length+1), 8)) -DEF_SPECIALIZED_VECTOR(character_string, NWORDS((length+1), 32)) +#define DEF_SCAV_TRANS_SIZE_UB(nbits) \ + DEF_SPECIALIZED_VECTOR(vector_unsigned_byte_##nbits, NWORDS(length, nbits)) DEF_SCAV_TRANS_SIZE_UB(2) DEF_SCAV_TRANS_SIZE_UB(4) DEF_SCAV_TRANS_SIZE_UB(8) @@ -956,47 +1171,57 @@ DEF_SPECIALIZED_VECTOR(vector_long_float, length * LONG_FLOAT_SIZE) DEF_SPECIALIZED_VECTOR(vector_complex_long_float, length * (2 * LONG_FLOAT_SIZE)) #endif -static lispobj -trans_weak_pointer(lispobj object) -{ - lispobj copy; - gc_dcheck(lowtag_of(object) == OTHER_POINTER_LOWTAG); - - /* Need to remember where all the weak pointers are that have */ - /* been transported so they can be fixed up in a post-GC pass. */ - - copy = copy_object(object, WEAK_POINTER_NWORDS); -#ifndef LISP_FEATURE_GENCGC - struct weak_pointer *wp = (struct weak_pointer *) native_pointer(copy); - - gc_dcheck(widetag_of(&wp->header)==WEAK_POINTER_WIDETAG); - /* Push the weak pointer onto the list of weak pointers. */ - if (weak_pointer_breakable_p(wp)) - add_to_weak_pointer_chain(wp); +#ifdef LISP_FEATURE_LITTLE_ENDIAN +// read 4 bits from byte index 1 of the header +# define WEAKPTR_SIZE(wp) ALIGN_UP(1+(((char*)(wp))[1] & 0xf), 2) +#else +# define WEAKPTR_SIZE(wp) ALIGN_UP(1+(((char*)(wp))[N_WORD_BYTES-2] & 0xf), 2) #endif - return copy; -} - -/* Check whether 'pointee' was forwarded. If it has been, update the contents - * of 'cell' to point to it. Otherwise, set 'cell' to 'broken'. - * Note that this macro has no braces around the body because one of the uses - * of it needs to stick on another 'else' or two */ -#define TEST_WEAK_CELL(cell, pointee, broken) \ - lispobj *native = native_pointer(pointee); \ - if (from_space_p(pointee)) \ - cell = forwarding_pointer_p(native) ? \ - LOW_WORD(forwarding_pointer_value(native)) : broken; \ - else if (immobile_space_p(pointee)) { \ - if (immobile_obj_gen_bits(base_pointer(pointee)) == from_space) cell = broken; \ +/* We might wish to support two sizes of weak-pointer. The hypothetical variation + * on weak-pointer would implement an ephemeron (https://en.wikipedia.org/wiki/Ephemeron) + * that otherwise can only be simulated very inefficiently in SBCL as a weak hash-table + * containing a single key */ +static sword_t scav_weakptr(lispobj *where, lispobj __attribute__((unused)) object) +{ + struct weak_pointer * wp = (struct weak_pointer*)where; + /* If wp->next is non-NULL then it's already in the weak pointer chain. + * If it is, then even if wp->value is now known to be live, + * we can't fix (or don't need to fix) the slot, because removing + * from a singly-linked-list is an O(n) operation */ + if (!in_weak_pointer_list(wp)) { + lispobj pointee = wp->value; + // A broken weak-pointer's value slot has unbound-marker + // which does not satisfy is_lisp_pointer(). + int breakable = is_lisp_pointer(pointee) && (from_space_p(pointee) +#ifdef LISP_FEATURE_IMMOBILE_SPACE + || (immobile_space_p(pointee) && + immobile_obj_gen_bits(base_pointer(pointee)) == from_space) +#endif + ); + if (breakable) { // Pointee could potentially be garbage. + // But it might already have been deemed live and forwarded. + if (forwarding_pointer_p(native_pointer(pointee))) + wp->value = forwarding_pointer_value(native_pointer(pointee)); + else + add_to_weak_pointer_chain(wp); + } } + return WEAKPTR_SIZE(wp); +} +static lispobj trans_weakptr(lispobj object) { + return gc_copy_object(object, + WEAKPTR_SIZE((object-OTHER_POINTER_LOWTAG)), + small_mixed_region, PAGE_TYPE_SMALL_MIXED); +} +static sword_t size_weakptr(lispobj *where) { return WEAKPTR_SIZE(where); } void smash_weak_pointers(void) { struct weak_pointer *wp, *next_wp; for (wp = weak_pointer_chain; wp != WEAK_POINTER_CHAIN_END; wp = next_wp) { gc_assert(widetag_of(&wp->header) == WEAK_POINTER_WIDETAG); - next_wp = wp->next; - wp->next = NULL; + next_wp = get_weak_pointer_next(wp); + reset_weak_pointer_next(wp); lispobj val = wp->value; /* A weak pointer is placed onto the list only if it points to an object @@ -1009,11 +1234,9 @@ void smash_weak_pointers(void) * it has been, the weak pointer is still good and needs to be * updated. Otherwise, the weak pointer needs to be broken. */ TEST_WEAK_CELL(wp->value, val, UNBOUND_MARKER_WIDETAG) -#ifdef LISP_FEATURE_GENCGC // Large objects are "moved" by touching the page table gen field. // Do nothing if the target of this weak pointer had that happen. else if (new_space_p(val)) { } -#endif else lose("unbreakable pointer %p", wp); } @@ -1023,8 +1246,9 @@ void smash_weak_pointers(void) while (vectors) { struct vector* vector = (struct vector*)vectors->car; vectors = (struct cons*)vectors->cdr; + ensure_non_ptr_word_writable(&vector->header); UNSET_WEAK_VECTOR_VISITED(vector); - sword_t len = fixnum_value(vector->length); + sword_t len = vector_len(vector); sword_t i; for (i = 0; i<len; ++i) { lispobj val = vector->data[i]; @@ -1093,26 +1317,21 @@ static inline int pointer_survived_gc_yet(lispobj obj) /* Return the beginning of data in ARRAY (skipping the header and the * length) or NULL if it isn't an array of the specified widetag after * all. */ -static inline void * -get_array_data (lispobj array, int widetag, sword_t *length) +static inline void *get_array_data(lispobj array, int widetag) { - if (is_lisp_pointer(array) && widetag_of(native_pointer(array)) == widetag) { - if (length != NULL) - *length = fixnum_value(native_pointer(array)[1]); + if (is_lisp_pointer(array) && widetag_of(native_pointer(array)) == widetag) return &(VECTOR(array)->data[0]); - } else { - return NULL; - } + lose("bad type: %"OBJ_FMTX" should have widetag %x", array, widetag); } extern uword_t gc_private_cons(uword_t, uword_t); void add_to_weak_vector_list(lispobj* vector, lispobj header) { - if (!is_vector_subtype(header, VectorWeakVisited)) { + if (!(header & WEAK_VECTOR_VISITED_BIT)) { weak_vectors = (struct cons*)gc_private_cons((uword_t)vector, (uword_t)weak_vectors); - *vector |= subtype_VectorWeakVisited << N_WIDETAG_BITS; + NON_FAULTING_STORE(*vector |= WEAK_VECTOR_VISITED_BIT, vector); } } @@ -1218,21 +1437,86 @@ boolean test_weak_triggers(int (*predicate)(lispobj), void (*mark)(lispobj)) return weak_objects.count != old_count; } -void weakobj_init() +int finalizer_thread_runflag = 1; +#ifdef LISP_FEATURE_SB_THREAD +#ifdef LISP_FEATURE_WIN32 +CRITICAL_SECTION finalizer_mutex; +CONDITION_VARIABLE finalizer_condvar; +void finalizer_thread_wait () { + EnterCriticalSection(&finalizer_mutex); + if (finalizer_thread_runflag) + SleepConditionVariableCS(&finalizer_condvar, &finalizer_mutex, INFINITE); + LeaveCriticalSection(&finalizer_mutex); +} +void finalizer_thread_wake () { + WakeAllConditionVariable(&finalizer_condvar); +} +void finalizer_thread_stop () { + EnterCriticalSection(&finalizer_mutex); + finalizer_thread_runflag = 0; + WakeAllConditionVariable(&finalizer_condvar); + LeaveCriticalSection(&finalizer_mutex); +} +#else +pthread_mutex_t finalizer_mutex = PTHREAD_MUTEX_INITIALIZER; +pthread_cond_t finalizer_condvar = PTHREAD_COND_INITIALIZER; +void finalizer_thread_wait () { + ignore_value(mutex_acquire(&finalizer_mutex)); + if (finalizer_thread_runflag) + pthread_cond_wait(&finalizer_condvar, &finalizer_mutex); + ignore_value(mutex_release(&finalizer_mutex)); +} +void finalizer_thread_wake() { + pthread_cond_broadcast(&finalizer_condvar); +} +void finalizer_thread_stop() { + ignore_value(mutex_acquire(&finalizer_mutex)); + finalizer_thread_runflag = 0; + pthread_cond_broadcast(&finalizer_condvar); + ignore_value(mutex_release(&finalizer_mutex)); +} +#endif +#endif + +void gc_common_init() { +#ifdef LISP_FEATURE_WIN32 + InitializeCriticalSection(&finalizer_mutex); + InitializeConditionVariable(&finalizer_condvar); +#endif hopscotch_init(); hopscotch_create(&weak_objects, HOPSCOTCH_HASH_FUN_DEFAULT, N_WORD_BYTES, 32 /* logical bin count */, 0 /* default range */); } +static inline boolean stable_eql_hash_p(lispobj obj) +{ + return lowtag_of(obj) == OTHER_POINTER_LOWTAG + && widetag_of((lispobj*)(obj-OTHER_POINTER_LOWTAG)) <= SYMBOL_WIDETAG; +} + +/* EQUAL and EQUALP tables always have hash vectors, so GC always knows + * for any given key whether it was hashed by address. + * EQ never has a hash vector (except if there is a user-defined hash function) + * but always hashes by the pointer bits (which could be an address or immediate). + * EQL never has a hash vector (same exception), but can hash some objects + * by their contents, not their address. This macro determines for a key whether + * its pointer bits force a rehash. In the case where we would call + * stable_eql_hash_p(), skip the call if 'rehash' is already 1. + */ +#define SHOULD_REHASH(oldkey, newkey, hashvec, hv_index) \ + ((newkey != oldkey) && \ + (!hashvec ? rehash || !eql_hashing || !stable_eql_hash_p(newkey) : \ + hashvec[hv_index] == MAGIC_HASH_VECTOR_VALUE)) + + /* Scavenge the "real" entries in the hash-table kv vector. The vector element * at index 0 bounds the scan. The element at length-1 (the hash table itself) * was scavenged already. * * We can disregard any entry in which both key and value are immediates. * This effectively ignores empty pairs, as well as makes fixnum -> fixnum table - * more efficient. If the bitwise OR of two lispobjs satisfies is_lisp_pointer(), - * then at least one is a pointer. + * more efficient. */ #define SCAV_ENTRIES(entry_alivep, defer) \ boolean __attribute__((unused)) any_deferred = 0; \ @@ -1246,9 +1530,7 @@ void weakobj_init() /* Scavenge the key and value. */ \ scav_entry(&data[2*i]); \ /* mark the table for rehash if address-based key moves */ \ - if (data[2*i] != key && \ - (!hash_vector || hash_vector[i] == MAGIC_HASH_VECTOR_VALUE)) \ - rehash = 1; \ + if (SHOULD_REHASH(key, data[2*i], hashvals, i)) rehash = 1; \ }}} \ /* Though at least partly writable, vector element 1 could be on a write-protected page. */ \ if (rehash) \ @@ -1258,7 +1540,7 @@ static void scan_nonweak_kv_vector(struct vector *kv_vector, void (*scav_entry)( { lispobj* data = kv_vector->data; - if (!is_vector_subtype(kv_vector->header, VectorAddrHashing)) { + if (!vector_flagp(kv_vector->header, VectorAddrHashing)) { // All keys were hashed address-insensitively return (void)scavenge(data + 2, KV_PAIRS_HIGH_WATER_MARK(data) * 2); } @@ -1268,19 +1550,22 @@ static void scan_nonweak_kv_vector(struct vector *kv_vector, void (*scav_entry)( // rehashing, which occurs only when rehashing without growing. // When growing a weak table, the KV vector is not created as weak initially; // its last element points to the hash-vector as for any strong KV vector. - sword_t kv_length = fixnum_value(kv_vector->length); - lispobj table_or_hashes = data[kv_length-1]; - lispobj lhash_vector; - if (instancep(table_or_hashes)) - lhash_vector = ((struct hash_table*)native_pointer(table_or_hashes))->hash_vector; - else - lhash_vector = table_or_hashes; - sword_t hash_vector_length; - uint32_t *hash_vector = get_array_data(lhash_vector, - SIMPLE_ARRAY_UNSIGNED_BYTE_32_WIDETAG, - &hash_vector_length); - if (hash_vector != NULL) - gc_assert(hash_vector_length == kv_length>>1); + sword_t kv_length = vector_len(kv_vector); + lispobj kv_supplement = data[kv_length-1]; + boolean eql_hashing = 0; // whether this table is an EQL table + if (instancep(kv_supplement)) { + struct hash_table* ht = (struct hash_table*)native_pointer(kv_supplement); + eql_hashing = hashtable_kind(ht) == 1; + kv_supplement = ht->hash_vector; + } else if (kv_supplement == LISP_T) { // EQL hashing on a non-weak table + eql_hashing = 1; + kv_supplement = NIL; + } + uint32_t *hashvals = 0; + if (kv_supplement != NIL) { + hashvals = get_array_data(kv_supplement, SIMPLE_ARRAY_UNSIGNED_BYTE_32_WIDETAG); + gc_assert(2 * vector_len(VECTOR(kv_supplement)) + 1 == kv_length); + } SCAV_ENTRIES(1, ); } @@ -1288,75 +1573,67 @@ boolean scan_weak_hashtable(struct hash_table *hash_table, int (*predicate)(lispobj,lispobj), void (*scav_entry)(lispobj*)) { - sword_t kv_length; - sword_t length; - sword_t next_vector_length; - sword_t hash_vector_length; - - lispobj *data = get_array_data(hash_table->pairs, - SIMPLE_VECTOR_WIDETAG, &kv_length); + lispobj *data = get_array_data(hash_table->pairs, SIMPLE_VECTOR_WIDETAG); if (data == NULL) lose("invalid kv_vector %"OBJ_FMTX, hash_table->pairs); + sword_t kv_length = vector_len(VECTOR(hash_table->pairs)); + + uint32_t *hashvals = 0; + if (hash_table->hash_vector != NIL) { + hashvals = get_array_data(hash_table->hash_vector, + SIMPLE_ARRAY_UNSIGNED_BYTE_32_WIDETAG); + gc_assert(vector_len(VECTOR(hash_table->hash_vector)) == + vector_len(VECTOR(hash_table->next_vector))); + } - uint32_t *index_vector = get_array_data(hash_table->index_vector, - SIMPLE_ARRAY_UNSIGNED_BYTE_32_WIDETAG, - &length); - if (index_vector == NULL) - lose("invalid index_vector %"OBJ_FMTX, hash_table->index_vector); - - if (get_array_data(hash_table->next_vector, - SIMPLE_ARRAY_UNSIGNED_BYTE_32_WIDETAG, - &next_vector_length) == NULL) - lose("invalid next_vector %"OBJ_FMTX, hash_table->next_vector); - - uint32_t *hash_vector = get_array_data(hash_table->hash_vector, - SIMPLE_ARRAY_UNSIGNED_BYTE_32_WIDETAG, - &hash_vector_length); - if (hash_vector != NULL) - gc_assert(hash_vector_length == next_vector_length); - - /* These lengths could be different as the index_vector can be a - * different length from the others, a larger index_vector could - * help reduce collisions. */ - gc_assert(next_vector_length == kv_length >> 1); + /* next_vector and hash_vector have a 1:1 size relation. + * kv_vector is twice that plus the supplemental cell. + * The index vector length is arbitrary - it can be smaller or larger + * than the maximum number of table entries. */ + gc_assert(2 * vector_len(VECTOR(hash_table->next_vector)) + 1 == kv_length); int weakness = hashtable_weakness(hash_table); + boolean eql_hashing = hashtable_kind(hash_table) == 1; /* Work through the KV vector. */ SCAV_ENTRIES(predicate(key, value), add_kv_triggers(&data[2*i], weakness)); if (!any_deferred && debug_weak_ht) fprintf(stderr, "will skip rescan of weak ht: %d/%d items\n", - (int)KV_PAIRS_HIGH_WATER_MARK(data), - (int)(next_vector_length - 1)); + (int)KV_PAIRS_HIGH_WATER_MARK(data), (int)(kv_length/2)); return any_deferred; } sword_t -scav_vector (lispobj *where, lispobj header) -{ - sword_t length = fixnum_value(where[1]); - - /* SB-VM:VECTOR-HASHING-SUBTYPE is set for all hash tables in the - * Lisp HASH-TABLE code to indicate need for special GC support. */ - if (is_vector_subtype(header, VectorNormal)) { +scav_vector_t(lispobj *where, lispobj header) +{ + sword_t length = vector_len((struct vector*)where); + + check_shadow_bits(where); + /* SB-VM:VECTOR-HASHING-FLAG is set for all hash tables in the + * Lisp HASH-TABLE code to indicate need for special GC support. + * But note that if the vector is a hashing vector that is neither + * weak nor contains any key hashed by its address, then it is basically + * a regular vector, except that GC needs only to look at cells below + * the high-water-mark, plus the SUPPLEMENT slot at the end */ + if (vector_flags_zerop(header)) { // ordinary simple-vector normal: scavenge(where + 2, length); goto done; } - if (vector_subtype(header) == subtype_VectorWeak) { // specifically not weak + hashing + if (vector_is_weak_not_hashing_p(header)) { add_to_weak_vector_list(where, header); goto done; } lispobj* data = where + 2; - // Verify that the rehash epoch is a fixnum + // Verify that the rehash stamp is a fixnum gc_assert(fixnump(data[1])); /* Scavenge element (length-1), which may be a hash-table structure. */ scavenge(&data[length-1], 1); - if (!is_vector_subtype(header, VectorWeak)) { + if (!vector_flagp(header, VectorWeak)) { scan_nonweak_kv_vector((struct vector*)where, gc_scav_pair); goto done; } @@ -1425,8 +1702,26 @@ scav_vector (lispobj *where, lispobj header) } /* Walk through the chain whose first element is *FIRST and remove - * dead weak entries. */ -static inline void + * dead weak entries. + * Return the new value for 'should rehash'. + * + * This operation might have to touch a hash-table that is currently + * on a write-protected page, as follows: + * hash-table in gen5 (WRITE-PROTECTED) -> pair vector in gen5 (NOT WRITE-PROTECTED) + * -> younger k/v in gen1 that are deemed not-alive. + * That's all fine, but now we have to store into the table for two reasons: + * 1. to adjust the count + * 2. to store the list of reusable cells + * The former store is a non-pointer, but the latter may create an old->young pointer, + * because the list of cells for reuse is freshly consed (and therefore young). + * Moreover, when updating 'smashed_cells', that slot might not even be on the same + * hardware page as the table header (if a page-spanning object) so it might be + * unwritable even if words 0 through <something> are writable. + * Employing the NON_FAULTING_STORE macro might make sense for the non-pointer slot, + * except that it's potentially a lot more unprotects and reprotects. + * Better to just get it done once. + */ +static inline boolean cull_weak_hash_table_bucket(struct hash_table *hash_table, uint32_t bucket, uint32_t index, lispobj *kv_vector, @@ -1434,9 +1729,10 @@ cull_weak_hash_table_bucket(struct hash_table *hash_table, int (*alivep_test)(lispobj,lispobj), void (*fix_pointers)(lispobj[2]), boolean save_culled_values, - boolean *rehash) + boolean rehash) { const lispobj empty_symbol = UNBOUND_MARKER_WIDETAG; + int eql_hashing = hashtable_kind(hash_table) == 1; for ( ; index ; index = next_vector[index] ) { lispobj key = kv_vector[2 * index]; lispobj value = kv_vector[2 * index + 1]; @@ -1445,6 +1741,8 @@ cull_weak_hash_table_bucket(struct hash_table *hash_table, if (key == empty_symbol && value == empty_symbol) continue; // If the pair doesn't have both halves empty, // then it mustn't have either half empty. + // FIXME: this looks like a potential data race - do we definitely store + // the key and value before inserting into a chain? Probably. gc_assert(key != empty_symbol); gc_assert(value != empty_symbol); if (!alivep_test(key, value)) { @@ -1453,19 +1751,21 @@ cull_weak_hash_table_bucket(struct hash_table *hash_table, lispobj val = kv_vector[2 * index + 1]; gc_assert(!is_lisp_pointer(val)); struct cons *cons = (struct cons*) - gc_general_alloc(sizeof(struct cons), BOXED_PAGE_FLAG); + gc_general_alloc(cons_region, sizeof(struct cons), PAGE_TYPE_CONS); // Lisp code which manipulates the culled_values slot must use // compare-and-swap, but C code need not, because GC runs in one // thread and has stopped the Lisp world. cons->cdr = hash_table->culled_values; cons->car = val; lispobj list = make_lispobj(cons, LIST_POINTER_LOWTAG); + notice_pointer_store(&hash_table->culled_values); hash_table->culled_values = list; // ensure this cons doesn't get smashed into (0 . 0) by full gc if (!compacting_p()) gc_mark_obj(list); } kv_vector[2 * index] = empty_symbol; kv_vector[2 * index + 1] = empty_symbol; + ensure_non_ptr_word_writable(&hash_table->_count); hash_table->_count -= make_fixnum(1); // Push (index . bucket) onto the table's GC culled cell list. @@ -1476,19 +1776,20 @@ cull_weak_hash_table_bucket(struct hash_table *hash_table, struct cons *cons; if ((index & ~0x3FFF) | (bucket & ~0x3FFF)) { // large values cons = (struct cons*) - gc_general_alloc(2 * sizeof(struct cons), BOXED_PAGE_FLAG); + gc_general_alloc(cons_region, 2 * sizeof(struct cons), PAGE_TYPE_CONS); cons->car = make_lispobj(cons + 1, LIST_POINTER_LOWTAG); cons[1].car = make_fixnum(index); // which cell became free cons[1].cdr = make_fixnum(bucket); // which chain was it in if (!compacting_p()) gc_mark_obj(cons->car); } else { // small values cons = (struct cons*) - gc_general_alloc(sizeof(struct cons), BOXED_PAGE_FLAG); + gc_general_alloc(cons_region, sizeof(struct cons), PAGE_TYPE_CONS); cons->car = ((index << 14) | bucket) << N_FIXNUM_TAG_BITS; } cons->cdr = hash_table->smashed_cells; // Lisp code must atomically pop the list whereas this C code // always wins and does not need compare-and-swap. + notice_pointer_store(&hash_table->smashed_cells); hash_table->smashed_cells = make_lispobj(cons, LIST_POINTER_LOWTAG); // ensure this cons doesn't get smashed into (0 . 0) by full gc if (!compacting_p()) gc_mark_obj(hash_table->smashed_cells); @@ -1497,12 +1798,12 @@ cull_weak_hash_table_bucket(struct hash_table *hash_table, if (fix_pointers) { // Follow FPs as necessary lispobj key = kv_vector[2 * index]; fix_pointers(&kv_vector[2 * index]); - if (kv_vector[2 * index] != key && - (!hash_vector || hash_vector[index] == MAGIC_HASH_VECTOR_VALUE)) - *rehash = 1; + if (SHOULD_REHASH(key, kv_vector[2 * index], hash_vector, index)) + rehash = 1; } } } + return rehash; } static void @@ -1510,27 +1811,34 @@ cull_weak_hash_table (struct hash_table *hash_table, int (*alivep_test)(lispobj,lispobj), void (*fix_pointers)(lispobj[2])) { - sword_t length = 0; /* prevent warning */ sword_t i; - lispobj *kv_vector = get_array_data(hash_table->pairs, - SIMPLE_VECTOR_WIDETAG, NULL); + lispobj *kv_vector = get_array_data(hash_table->pairs, SIMPLE_VECTOR_WIDETAG); uint32_t *index_vector = get_array_data(hash_table->index_vector, - SIMPLE_ARRAY_UNSIGNED_BYTE_32_WIDETAG, - &length); + SIMPLE_ARRAY_UNSIGNED_BYTE_32_WIDETAG); + sword_t n_buckets = vector_len(VECTOR(hash_table->index_vector)); uint32_t *next_vector = get_array_data(hash_table->next_vector, - SIMPLE_ARRAY_UNSIGNED_BYTE_32_WIDETAG, - NULL); - uint32_t *hash_vector = get_array_data(hash_table->hash_vector, - SIMPLE_ARRAY_UNSIGNED_BYTE_32_WIDETAG, NULL); + SIMPLE_ARRAY_UNSIGNED_BYTE_32_WIDETAG); + uint32_t *hash_vector = 0; + if (hash_table->hash_vector != NIL) + hash_vector = get_array_data(hash_table->hash_vector, + SIMPLE_ARRAY_UNSIGNED_BYTE_32_WIDETAG); boolean rehash = 0; - boolean save_culled_values = (hash_table->flags & MAKE_FIXNUM(4)) != 0; - for (i = 0; i < length; i++) { - cull_weak_hash_table_bucket(hash_table, i, index_vector[i], - kv_vector, next_vector, hash_vector, - alivep_test, fix_pointers, - save_culled_values, &rehash); + boolean save_culled_values = (hash_table->flags & make_fixnum(4)) != 0; + // I'm slightly confused as to why we can't (or don't) compute the + // 'should rehash' flag while scavenging the weak k/v vector. + // I believe the explanation is this: for weak-key-AND-value tables, the vector + // is never scavenged. It just ends up here after all other scavenging is done. + // We then need to fix the still-live pointers, which entails possibly setting the + // 'rehash' flag. It would not make sense to treat the other 3 flavors of + // weakness any differently. + for (i = 0; i < n_buckets; i++) { + if (cull_weak_hash_table_bucket(hash_table, i, index_vector[i], + kv_vector, next_vector, hash_vector, + alivep_test, fix_pointers, + save_culled_values, rehash)) + rehash = 1; } /* If an EQ-based key has moved, mark the hash-table for rehash */ if (rehash) @@ -1542,17 +1850,28 @@ cull_weak_hash_table (struct hash_table *hash_table, static void pair_follow_fps(lispobj ht_entry[2]) { lispobj obj = ht_entry[0]; - if (is_lisp_pointer(obj) && from_space_p (obj) && - forwarding_pointer_p(native_pointer(obj))) + /* Define a macro to safely test forwarding_pointer_p(). + * This could, in general, use 'from_space_p', however, from_space_p is more + * strict than "can we determine that it's OK to call forwarding_pointer_p". + * For gencgc it's OK to call forwarded_pointer_p even if the object is + * not in from_space, and so the test need not involve pinned_p */ +#ifdef LISP_FEATURE_CHENEYGC +#define IS_FORWARDED(x) (is_lisp_pointer(x) && from_space_p(x) && \ + forwarding_pointer_p(native_pointer(x))) +#else +#define IS_FORWARDED(x) (is_lisp_pointer(x) && find_page_index((void*)x) >= 0 && \ + forwarding_pointer_p(native_pointer(x))) +#endif + if (IS_FORWARDED(obj)) ht_entry[0] = forwarding_pointer_value(native_pointer(obj)); obj = ht_entry[1]; - if (is_lisp_pointer(obj) && from_space_p (obj) && - forwarding_pointer_p(native_pointer(obj))) + if (IS_FORWARDED(obj)) ht_entry[1] = forwarding_pointer_value(native_pointer(obj)); +#undef IS_FORWARDED } /* Remove dead entries from weak hash tables. */ -void cull_weak_hash_tables(int (*alivep[5])(lispobj,lispobj)) +void cull_weak_hash_tables(int (*alivep[4])(lispobj,lispobj)) { struct hash_table *table, *next; @@ -1560,8 +1879,9 @@ void cull_weak_hash_tables(int (*alivep[5])(lispobj,lispobj)) next = (struct hash_table *)table->next_weak_hash_table; NON_FAULTING_STORE(table->next_weak_hash_table = NIL, &table->next_weak_hash_table); - cull_weak_hash_table(table, alivep[hashtable_weakness(table)], - compacting_p() ? pair_follow_fps : 0); + int weakness = hashtable_weakness(table); + gc_assert((weakness & ~3) == 0); + cull_weak_hash_table(table, alivep[weakness], compacting_p() ? pair_follow_fps : 0); } weak_hash_tables = NULL; /* Reset weak_objects only if the count is nonzero. @@ -1571,10 +1891,8 @@ void cull_weak_hash_tables(int (*alivep[5])(lispobj,lispobj)) * which is what an extra reset would do if it saw no inserts. */ if (weak_objects.count) hopscotch_reset(&weak_objects); -#ifdef LISP_FEATURE_GENCGC // Close the region used when pushing items to the finalizer queue - ensure_region_closed(&boxed_region, BOXED_PAGE_FLAG); -#endif + ensure_region_closed(cons_region, PAGE_TYPE_CONS); } @@ -1582,15 +1900,6 @@ void cull_weak_hash_tables(int (*alivep[5])(lispobj,lispobj)) * initialization */ -static sword_t -scav_lose(lispobj *where, lispobj object) -{ - lose("no scavenge function for object %p (widetag %#x)", - (void*)object, widetag_of(where)); - - return 0; /* bogus return value to satisfy static type checking */ -} - static lispobj trans_lose(lispobj object) { @@ -1606,16 +1915,12 @@ size_lose(lispobj *where) (void*)where, widetag_of(where)); return 1; /* bogus return value to satisfy static type checking */ } -boolean valid_widetag_p(unsigned char widetag) { - return sizetab[widetag] != size_lose; -} - /* * initialization */ -sword_t scav_weak_pointer(lispobj *where, lispobj object); +sword_t scav_code_blob(lispobj *object, lispobj header); #include "genesis/gc-tables.h" /* Find the code object for the given pc, or return NULL on @@ -1623,6 +1928,12 @@ sword_t scav_weak_pointer(lispobj *where, lispobj object); lispobj * component_ptr_from_pc(char *pc) { + /* This will safely look in one or both codeblob trees and/or the + * sorted array of immobile text pages. Failing those, it'll perform + * the usual linear scan of generation 1 and up pages. In any case + * it should be perfectly threadsafe because the trees are made of immutable + * nodes, and linear scan only operates on pages that can't be + * concurrently manipulated */ lispobj *object = search_all_gc_spaces(pc); if (object != NULL && widetag_of(object) == CODE_HEADER_WIDETAG) @@ -1631,34 +1942,67 @@ component_ptr_from_pc(char *pc) return NULL; } +/// Return the name of the simple-fun containing 'pc', +/// and if 'pfun' is non-null then store the base pointer +/// to the function in *pfun. This is an easier-to-use interface than +/// just returning the function, because accessing the name requires +/// knowing the function's index into the entry-point vector. +lispobj simple_fun_name_from_pc(char *pc, lispobj** pfun) +{ + struct code* code = (void*)component_ptr_from_pc(pc); + if (!code) return 0; // not in lisp heap + char *insts = code_text_start(code); + unsigned int* offsets = code_fun_table(code) - 1; + int i; + // Scanning backwards makes the stopping condition easy: + // the first function lower than 'pc' is the right answer. + for (i=code_n_funs(code)-1; i>=0; --i) { + struct simple_fun* fun = (void*)(insts + offsets[-i]); + if ((char*)fun < pc) { + if (pfun) *pfun = (lispobj*)fun; + return code->constants[i*CODE_SLOTS_PER_SIMPLE_FUN]; + } + } + return 0; // oops, how did this happen? +} + +#ifdef LISP_FEATURE_UBSAN +// ubsan tracks memory origin by a not-exactly-gc-safe way +// that kinda works, as long as gc_search_space() doesn't crash, +// which it shouldn't if carefully visiting objects. +#define SEARCH_SPACE_FOLLOWS_FORWARDING_POINTERS 1 +#else +#define SEARCH_SPACE_FOLLOWS_FORWARDING_POINTERS 0 +#endif /* Scan an area looking for an object which encloses the given pointer. * Return the object start on success, or NULL on failure. */ lispobj * -gc_search_space3(void *pointer, lispobj *start, void *limit) +gc_search_space3(void *pointer, lispobj * const start, void *limit) { if (pointer < (void*)start || pointer >= limit) return NULL; size_t count; -#if 0 + lispobj* where = start; + +#if SEARCH_SPACE_FOLLOWS_FORWARDING_POINTERS /* CAUTION: this code is _significantly_ slower than the production version - due to the extra checks for forwarding. Only use it if debugging */ - for ( ; (void*)start < limit ; start += count) { - lispobj *forwarded_start; - if (forwarding_pointer_p(start)) - forwarded_start = native_pointer(forwarding_pointer_value(start)); - else - forwarded_start = start; - lispobj thing = *forwarded_start; - count = OBJECT_SIZE(thing, forwarded_start); + due to the extra checks for forwarding. + Also it is BROKEN. DO NOT ENABLE THE #define UNLESS/UNTIL FIXED. */ + for ( ; (void*)where < limit ; where += count) { + lispobj *copy = where; + if (forwarding_pointer_p(where)) + copy = native_pointer(forwarding_pointer_value(where)); + // BUG: the size of a forwarded object may exceed the size of the original + // due to the addition of a stable hash slot. + count = object_size(copy); /* Check whether the pointer is within this object. */ - if (pointer < (void*)(start+count)) return start; + if (pointer < (void*)(where+count)) return where; } #else - for ( ; (void*)start < limit ; start += count) { - lispobj thing = *start; - count = OBJECT_SIZE(thing, start); + for ( ; (void*)where < limit ; where += count) { + count = object_size(where); /* Check whether the pointer is within this object. */ - if (pointer < (void*)(start+count)) return start; + if (pointer < (void*)(where+count)) return where; } #endif return NULL; @@ -1704,20 +2048,14 @@ properly_tagged_p_internal(lispobj pointer, lispobj *start_addr) { // If a headerless object, confirm that 'pointer' is a list pointer. // Given the precondition that the heap is in a valid state, - // it may be assumed that one check of is_cons_half() suffices; - // we don't need to check the other half. - lispobj header = *start_addr; - if (is_cons_half(header)) + // it may be assumed that is_cons_half() is satisfied by both the + // car and cdr. + lispobj word = *start_addr; + if (!is_header(word)) return make_lispobj(start_addr, LIST_POINTER_LOWTAG) == pointer; - // Because this heap object was not deemed to be a cons, - // it must be an object header. Don't need a check except when paranoid. - gc_dcheck(other_immediate_lowtag_p(header)); - - // The space of potential widetags has 64 elements, not 256, - // because of the constant low 2 bits. - int widetag = header_widetag(header); - int lowtag = lowtag_for_widetag[widetag>>2]; + int widetag = header_widetag(word); + int lowtag = LOWTAG_FOR_WIDETAG(widetag); if (lowtag && make_lispobj(start_addr, lowtag) == pointer) return 1; // instant win @@ -1750,15 +2088,6 @@ properly_tagged_p_internal(lispobj pointer, lispobj *start_addr) return 0; // no good } -/* META: Note the ambiguous word "validate" in the comment below. - * This means "Decide whether <x> is valid". - * But when you see os_validate() elsewhere, that doesn't mean to ask - * whether something is valid, it says to *make* it valid. - * I think it would be nice if we could avoid using the word in the - * sense in which os_validate() uses it, which would entail renaming - * a bunch of stuff, which is harder than just explaining why - * the comments can be deceptive */ - /* Used by the debugger to validate possibly bogus pointers before * calling MAKE-LISP-OBJ on them. * @@ -1774,17 +2103,63 @@ properly_tagged_p_internal(lispobj pointer, lispobj *start_addr) int valid_lisp_pointer_p(lispobj pointer) { + /* We don't have a general way to ask a specific GC implementation + * whether 'pointer' is definitely the tagged pointer to an object - + * all we have is "search for a containing object" and then a decision + * whether pointer is the tagged pointer to that. + * But searching is actually too complex an operation for some easy + * cases when we could answer the question more simply. + * So unfortunately this generic interface has to know something about + * which GC is in use. */ + page_index_t page = find_page_index((void*)pointer); + if (page >= 0 && + (page_table[page].type & PAGE_TYPE_MASK) == PAGE_TYPE_BOXED) { + int wordindex = (pointer & (GENCGC_PAGE_BYTES-1)) >> WORD_SHIFT; + return (wordindex < page_table[page].words_used_) + /* strictly boxed pages can only contain headers and immediates */ + && is_header(*native_pointer(pointer)) + && make_lispobj(native_pointer(pointer), + LOWTAG_FOR_WIDETAG(*native_pointer(pointer) & WIDETAG_MASK)) + == pointer; + } lispobj *start = search_all_gc_spaces((void*)pointer); if (start != NULL) return properly_tagged_descriptor_p((void*)pointer, start); return 0; } +static boolean can_invoke_post_gc(__attribute__((unused)) struct thread* th, + sigset_t *context_sigmask) +{ +#ifdef LISP_FEATURE_SB_THREAD + lispobj obj = th->lisp_thread; + /* Ok, I seriously doubt that this can happen now. Don't we create + * the 'struct thread' with a pointer to its SB-THREAD:THREAD right away? + * I thought so. But if I'm mistaken, give up. */ + if (!obj) return 0; + struct thread_instance* lispthread = (void*)(obj - INSTANCE_POINTER_LOWTAG); + + /* If the SB-THREAD:THREAD has a 0 for its 'struct thread', give up. + * This is the same as the THREAD-ALIVE-P test. Maybe a thread that is + * in the process of un-setting that slot performed this GC. */ + if (!lispthread->uw_primitive_thread) return 0; + + /* I don't know why we aren't in general willing to run post-GC with some or all + * deferrable signals blocked. "Obviously" the idea is to run post-GC code only in + * a thread that is in a nominally pristine state, as opposed to one that is doing + * any manner of monkey business. But was there some specific issue related to + * running post-GC with signals blocked? Nontrivial post-GC code is bad anyway, + * so how could trivial code be adversely affected? i.e. if your post-GC code + * can't run with some signals blocked, then it shouldn't be your post-GC code. */ +#endif + return !deferrables_blocked_p(context_sigmask); +} + boolean maybe_gc(os_context_t *context) { lispobj gc_happened; - __attribute__((unused)) struct thread *thread = arch_os_get_current_thread(); + __attribute__((unused)) struct thread *thread = get_sb_vm_thread(); boolean were_in_lisp = !foreign_function_call_active_p(thread); if (were_in_lisp) { @@ -1813,9 +2188,9 @@ maybe_gc(os_context_t *context) * A kludgy alternative is to propagate the sigmask change to the * outer context. */ -#if !(defined(LISP_FEATURE_WIN32) || defined(LISP_FEATURE_SB_SAFEPOINT)) +#ifndef LISP_FEATURE_SB_SAFEPOINT check_gc_signals_unblocked_or_lose(os_context_sigmask_addr(context)); - unblock_gc_signals(0, 0); + unblock_gc_signals(); #endif FSHOW((stderr, "/maybe_gc: calling SUB_GC\n")); /* FIXME: Nothing must go wrong during GC else we end up running @@ -1826,11 +2201,7 @@ maybe_gc(os_context_t *context) * we may even be in a WITHOUT-INTERRUPTS. */ gc_happened = funcall1(StaticSymbolFunction(SUB_GC), 0); FSHOW((stderr, "/maybe_gc: gc_happened=%s\n", - (gc_happened == NIL) - ? "NIL" - : ((gc_happened == T) - ? "T" - : "0"))); + gc_happened == NIL ? "NIL" : gc_happened == LISP_T ? "T" : "0")); /* gc_happened can take three values: T, NIL, 0. * * T means that the thread managed to trigger a GC, and post-gc @@ -1843,7 +2214,7 @@ maybe_gc(os_context_t *context) * triggered by this thread; success, but post-gc doesn't have * to be called. */ - if ((gc_happened == T) && + if ((gc_happened == LISP_T) && /* See if interrupts are enabled or it's possible to enable * them. POST-GC has a similar check, but we don't want to * unlock deferrables in that case and get a pending interrupt @@ -1852,7 +2223,11 @@ maybe_gc(os_context_t *context) (read_TLS(ALLOW_WITH_INTERRUPTS,thread) != NIL))) { #ifndef LISP_FEATURE_WIN32 sigset_t *context_sigmask = os_context_sigmask_addr(context); - if (!deferrables_blocked_p(context_sigmask)) { + if (can_invoke_post_gc(thread, context_sigmask)) { + /* The gist of this is that we make it appear that return-from-signal + * happened, and the calling code decided to take a detour through the + * post-GC code. Except that we do it while the interrupt context + * is still on the stack */ thread_sigmask(SIG_SETMASK, context_sigmask, 0); #ifndef LISP_FEATURE_SB_SAFEPOINT check_gc_signals_unblocked_or_lose(0); @@ -1915,7 +2290,7 @@ maybe_gc(os_context_t *context) void scrub_control_stack() { - scrub_thread_control_stack(arch_os_get_current_thread()); + scrub_thread_control_stack(get_sb_vm_thread()); } void @@ -1939,7 +2314,7 @@ scrub_thread_control_stack(struct thread *th) ((os_vm_address_t)sp >= hard_guard_page_address)) || (((os_vm_address_t)sp < (guard_page_address + os_vm_page_size)) && ((os_vm_address_t)sp >= guard_page_address) && - (th->control_stack_guard_page_protected != NIL))) + th->state_word.control_stack_guard_page_protected)) return; #ifdef LISP_FEATURE_STACK_GROWS_DOWNWARD_NOT_UPWARD do { @@ -1988,43 +2363,38 @@ scavenge_control_stack(struct thread *th) * the compiler isn't allowed to store unboxed objects on the * control stack. -- AB, 2011-Dec-02 */ - /* FIXME: I believe that this loop could be replaced by scavenge(), - * as it can not "... blow past the end" on header words, - * the way that heap_scavenge() might */ for (object_ptr = th->control_stack_start; object_ptr < access_control_stack_pointer(th); object_ptr++) { - - lispobj object = *object_ptr; -#ifdef LISP_FEATURE_GENCGC - if (forwarding_pointer_p(object_ptr)) + lispobj word = *object_ptr; + if (word == FORWARDING_HEADER) lose("unexpected forwarding pointer in scavenge_control_stack: %p, start=%p, end=%p", object_ptr, th->control_stack_start, access_control_stack_pointer(th)); + else if (is_lisp_pointer(word)) { scav1(object_ptr, word); } +#ifdef LISP_FEATURE_PPC64 + /* For ppc64, ~0 does not satisfy is_lisp_pointer() or is_lisp_immediate(), + * but it can be ignored. It nominally satisfies is_lisp_pointer() on other + * architectures, and gets ignored because it does not point to the heap. */ + else if (is_lisp_immediate(word) || word == ~(uword_t)0) { } // ignore +#else + else if (is_lisp_immediate(word)) { } // ignore #endif - if (is_lisp_pointer(object) && from_space_p(object)) { - /* It currently points to old space. Check for a - * forwarding pointer. */ - lispobj *ptr = native_pointer(object); - if (forwarding_pointer_p(ptr)) { - /* Yes, there's a forwarding pointer. */ - *object_ptr = LOW_WORD(forwarding_pointer_value(ptr)); - } else { - /* Scavenge that pointer. */ - long n_words_scavenged = - (scavtab[header_widetag(object)])(object_ptr, object); - gc_assert(n_words_scavenged == 1); - } - } else if (scavtab[header_widetag(object)] == scav_lose) { + else if (scavtab[header_widetag(word)] == scav_lose) { lose("unboxed object in scavenge_control_stack: %p->%"OBJ_FMTX", start=%p, end=%p", - object_ptr, object, th->control_stack_start, access_control_stack_pointer(th)); + object_ptr, word, th->control_stack_start, access_control_stack_pointer(th)); } } } +#ifdef reg_CODE /* Scavenging Interrupt Contexts */ static int boxed_registers[] = BOXED_REGISTERS; +// Nothing usees os_context_pc_addr any more, except ACCESS_INTERIOR_POINTER_pc. +// I didn't see a good way to remove that one. +extern os_context_register_t* os_context_pc_addr(os_context_t*); + /* The GC has a notion of an "interior pointer" register, an unboxed * register that typically contains a pointer to inside an object * referenced by another pointer. The most obvious of these is the @@ -2165,7 +2535,10 @@ scavenge_interrupt_context(os_context_t * context) * compile out for the registers that don't exist on a given * platform? */ +#ifdef reg_LRA INTERIOR_POINTER_VARS(pc); +#endif + #ifdef reg_LIP INTERIOR_POINTER_VARS(lip); #endif @@ -2179,13 +2552,24 @@ scavenge_interrupt_context(os_context_t * context) INTERIOR_POINTER_VARS(ctr); #endif + /* Platforms without LRA pin on-stack code. Furthermore, the PC + must not be paired, as even on platforms with $CODE, there is + nothing valid to pair PC with immediately upon function + return. */ +#ifdef reg_LRA PAIR_INTERIOR_POINTER(pc); +#endif + #ifdef reg_LIP PAIR_INTERIOR_POINTER(lip); #endif + #ifdef ARCH_HAS_LINK_REGISTER - PAIR_INTERIOR_POINTER(lr); + { + PAIR_INTERIOR_POINTER(lr); + } #endif + #ifdef ARCH_HAS_NPC_REGISTER PAIR_INTERIOR_POINTER(npc); #endif @@ -2222,12 +2606,18 @@ scavenge_interrupt_context(os_context_t * context) /* Now that the scavenging is done, repair the various interior * pointers. */ +#ifdef reg_LRA FIXUP_INTERIOR_POINTER(pc); +#endif + #ifdef reg_LIP FIXUP_INTERIOR_POINTER(lip); #endif #ifdef ARCH_HAS_LINK_REGISTER - FIXUP_INTERIOR_POINTER(lr); + + { + FIXUP_INTERIOR_POINTER(lr); + } #endif #ifdef ARCH_HAS_NPC_REGISTER FIXUP_INTERIOR_POINTER(npc); @@ -2254,56 +2644,9 @@ scavenge_interrupt_contexts(struct thread *th) scavenge_interrupt_context(context); } } +#endif /* !REG_CODE */ #endif /* x86oid targets */ -void varint_unpacker_init(struct varint_unpacker* unpacker, lispobj integer) -{ - if (fixnump(integer)) { - unpacker->word = fixnum_value(integer); - unpacker->limit = N_WORD_BYTES; - unpacker->data = (char*)&unpacker->word; - } else { - struct bignum* bignum = (struct bignum*)(integer - OTHER_POINTER_LOWTAG); - unpacker->word = 0; - unpacker->limit = HeaderValue(bignum->header) * N_WORD_BYTES; - unpacker->data = (char*)bignum->digits; - } - unpacker->index = 0; -} - -// Fetch the next varint from 'unpacker' into 'result'. -// Because there is no length prefix on the number of varints encoded, -// spurious trailing zeros might be observed. The data consumer can -// circumvent that by storing a count as the first value in the series. -// Return 1 for success, 0 for EOF. -int varint_unpack(struct varint_unpacker* unpacker, int* result) -{ - if (unpacker->index >= unpacker->limit) return 0; - int accumulator = 0; - int shift = 0; - while (1) { -#ifdef LISP_FEATURE_LITTLE_ENDIAN - int byte = unpacker->data[unpacker->index]; -#else - // bignums are little-endian in word order, - // but machine-native within each word. - // We could pack bytes MSB-to-LSB in the bigdigits, - // but that seems less intuitive on the Lisp side. - int word_index = unpacker->index / N_WORD_BYTES; - int byte_index = unpacker->index % N_WORD_BYTES; - int byte = (((unsigned int*)unpacker->data)[word_index] - >> (byte_index * 8)) & 0xFF; -#endif - ++unpacker->index; - accumulator |= (byte & 0x7F) << shift; - if (!(byte & 0x80)) break; - gc_assert(unpacker->index < unpacker->limit); - shift += 7; - } - *result = accumulator; - return 1; -} - /* Our own implementation of heapsort, because some C libraries have a qsort() * that calls malloc() apparently, which we MUST NOT do. */ @@ -2345,3 +2688,9 @@ void gc_heapsort_uwords(heap array, int length) sift_down(array, 0, end); } } + +/// External function for calling from Lisp. +uword_t primitive_object_size(lispobj ptr) { + lispobj* addr = native_pointer(ptr); + return object_size(addr) * N_WORD_BYTES; +} diff --git a/src/runtime/gc-internal.h b/src/runtime/gc-internal.h index 26a33cb930..109b0a75c4 100644 --- a/src/runtime/gc-internal.h +++ b/src/runtime/gc-internal.h @@ -40,6 +40,9 @@ extern struct weak_pointer *weak_pointer_chain; /* in gc-common.c */ #include "align.h" +// Distinguish penultimate GC (iteration 1) from ultimate GC (iteration 2) in save-lisp +extern int save_lisp_gc_iteration; + // Offset from an fdefn raw address to the underlying simple-fun, // if and only if it points to a simple-fun. // For those of us who are too memory-impaired to know how to use the value: @@ -51,55 +54,81 @@ extern struct weak_pointer *weak_pointer_chain; /* in gc-common.c */ #define FUN_RAW_ADDR_OFFSET (offsetof(struct simple_fun, insts) - FUN_POINTER_LOWTAG) #endif -// For x86[-64], a simple-fun or closure's "self" slot is a fixum +// For x86[-64], arm64, a simple-fun or closure's "self" slot is a fixum // On other backends, it is a lisp ointer. -#if defined(LISP_FEATURE_X86) || defined(LISP_FEATURE_X86_64) +#if defined(LISP_FEATURE_X86) || defined(LISP_FEATURE_X86_64) || defined(LISP_FEATURE_ARM64) #define FUN_SELF_FIXNUM_TAGGED 1 #else #define FUN_SELF_FIXNUM_TAGGED 0 #endif -// Return only the lisp-visible vector header flag bits bits, -// masking out subtype_VectorWeakVisited. -#define vector_subtype(header) (HeaderValue(header) & 7) -// Test for presence of a bit in vector's header. -// As a special case, if 'val' is 0, then test for all bits clear. -#define is_vector_subtype(header, val) \ - (subtype_##val ? (HeaderValue(header) & subtype_##val) : \ - !(HeaderValue(header) & 7)) +/* + * Predicates rather than bit extractors should be used to test the flags + * in a vector header, because: + * + * - while trying to place the flags into a different header byte, I found it + * unobvious whether to treat flags as part of the "Header data" (which is a + * 3-byte or 7-byte wide field starting at bit 8) versus the entire "Header word". + * So e.g. if the Lisp VECTOR-WEAK value were redefined to #x0100, which would + * place a 1 bit into byte index 3 (using SET-HEADER-DATA), it isn't clear that + * "vector_flags(vector) == vectorWeak" is the proper test, because vector_flags() + * could reasonably be defined to right-shift by 0, 8, or 16 bits. + * (i.e. leave the bits where they are, but mask out the widetag; or make them + * act like "Header data"; or right-align as if we had Lisp bitfield extractors) + * Looked at differently, the natural values for the first 3 flag bits should be + * 1, 2, and 4 but this would force you to write expressions such as: + * (SET-HEADER-DATA V (ASH SB-VM:VECTOR-HASHING-FLAG SB-VM:VECTOR-FLAG-BITS-SHIFT)) + * which looks to be terribly inconvenient for Lisp. + * Alternatively, the constants can be defined as their "natural" values for C + * which would have flag_VectorWeak = 0x010000, but then you need the inverse + * shift in Lisp which expects SET-HEADER-DATA to get #x0100 as the argument. + * Hypothetically, that is. + * + * - With smarter macros it ought to be possible to avoid 8-byte loads and shifts. + * They would need to be endian-aware, which I didn't want to do just yet. + */ +#define vector_flagp(header, val) ((int)header & (flag_##val << ARRAY_FLAGS_POSITION)) +#define vector_flags_zerop(header) ((int)(header) & 0x07 << ARRAY_FLAGS_POSITION) == 0 +// Return true if vector is a weak vector that is not a hash-table <k,v> vector. +static inline int vector_is_weak_not_hashing_p(unsigned int header) { + return (header & ((flag_VectorWeak|flag_VectorHashing) << ARRAY_FLAGS_POSITION)) == + flag_VectorWeak << ARRAY_FLAGS_POSITION; +} + +// This bit can be anything that doesn't conflict with the fullcgc mark bit or a bit +// seen by lisp. Byte index 0 is the widetag, byte indices 1 and 2 are for the array-rank +// and vector-flags, depending on how src/compiler/generic/early-objdef assigns them. +#define WEAK_VECTOR_VISITED_BIT (1<<30) -// Mask out the fullcgc mark bit when asserting header validity +// Assert that the 'v' is a weak (not hashing) simple-vector and was visited, +// and then clear the visited bit. #define UNSET_WEAK_VECTOR_VISITED(v) \ - gc_assert((v->header & 0xffff) == \ - (((subtype_VectorWeakVisited|subtype_VectorWeak) << N_WIDETAG_BITS) \ - | SIMPLE_VECTOR_WIDETAG)); \ - v->header ^= subtype_VectorWeakVisited << N_WIDETAG_BITS - -/* values for the *_alloc_* parameters, also see the commentary for - * struct page in gencgc-internal.h. These constants are used in gc-common, - * so they can't easily be made gencgc-only */ -#define FREE_PAGE_FLAG 0 -#define PAGE_TYPE_MASK 7 // mask out the 'single-object flag' -/* Note: MAP-ALLOCATED-OBJECTS expects this value to be 1 */ -#define BOXED_PAGE_FLAG 1 -#define UNBOXED_PAGE_FLAG 2 -/* CONS_PAGE_FLAG doesn't get stored in the page table, though I am considering - * doing that. If conses went on segregated pages, then testing for a valid - * conservative root on a cons page is as simple as seeing whether the address - * is correctly aligned and lowtagged. - * Also, we could reserve bytes at the end of each page to act as a mark bitmap - * which is useful since conses are headerless objects, and one GC strategy - * demands mark bitmaps which are currently placed in a side table. - * That would unfortunately complicate the task of allocating a huge list, - * because hitting the line of demarcation between conses and the mark bits would - * require chaining the final cons to another page of conses and so on. */ -#define CONS_PAGE_FLAG 4 -#define OPEN_REGION_PAGE_FLAG 8 -#define CODE_PAGE_TYPE (BOXED_PAGE_FLAG|UNBOXED_PAGE_FLAG) + gc_assert((v->header & (WEAK_VECTOR_VISITED_BIT | 0xff << ARRAY_FLAGS_POSITION | 0xff)) == \ + (WEAK_VECTOR_VISITED_BIT | flag_VectorWeak << ARRAY_FLAGS_POSITION | SIMPLE_VECTOR_WIDETAG)); \ + v->header ^= WEAK_VECTOR_VISITED_BIT extern sword_t (*sizetab[256])(lispobj *where); -#define OBJECT_SIZE(header,where) \ - (is_cons_half(header)?2:sizetab[header_widetag(header)](where)) +typedef sword_t (*sizerfn)(lispobj*); +static inline sword_t object_size(lispobj* where) { + sizerfn f = sizetab[widetag_of(where)]; + return f ? f(where) : CONS_SIZE; +} +// These three variants are potentially more efficient - +// (1) if the widetag was loaded, avoids one memory read +// (2) if you know the object isn't a cons, use headerobj_size +// (3) both of the above pertain. +// Cases 1 and 3 exist only because C doesn't have optional args. +// These might be premature optimizations, I really don't know. +static inline sword_t object_size2(lispobj* where, unsigned int header) { + sizerfn f = sizetab[header & WIDETAG_MASK]; + return f ? f(where) : CONS_SIZE; +} +static inline sword_t headerobj_size(lispobj* where) { + return sizetab[widetag_of(where)](where); +} +static inline sword_t headerobj_size2(lispobj* where, unsigned int header) { + return sizetab[header & WIDETAG_MASK](where); +} lispobj *gc_search_space3(void *pointer, lispobj *start, void *limit); static inline lispobj *gc_search_space(lispobj *start, void *pointer) { @@ -108,8 +137,6 @@ static inline lispobj *gc_search_space(lispobj *start, void *pointer) { (void*)(1+((lispobj)pointer | LOWTAG_MASK))); } -struct vector *symbol_name(lispobj*); - extern void scrub_control_stack(void); extern void scrub_thread_control_stack(struct thread *); @@ -134,37 +161,7 @@ instance_scan(void (*proc)(lispobj*, sword_t, uword_t), extern int simple_fun_index(struct code*, struct simple_fun*); -#ifdef LISP_FEATURE_COMPACT_INSTANCE_HEADER -static inline lispobj funinstance_layout(lispobj* funinstance_ptr) { // native ptr - return instance_layout(funinstance_ptr); -} -static inline lispobj function_layout(lispobj* fun_ptr) { // native ptr - return instance_layout(fun_ptr); -} -static inline void set_function_layout(lispobj* fun_ptr, lispobj layout) { - instance_layout(fun_ptr) = layout; -} -#else -static inline lispobj funinstance_layout(lispobj* instance_ptr) { // native ptr - // first 4 words are: header, trampoline, fin-fun, layout - return instance_ptr[3]; -} -// No layout in simple-fun or closure, because there are no free bits -static inline lispobj -function_layout(lispobj __attribute__((unused)) *fun_ptr) { // native ptr - return 0; -} -static inline void set_function_layout(lispobj __attribute__((unused)) *fun_ptr, - lispobj __attribute__((unused)) layout) { - lose("Can't assign layout"); -} -#endif - -#include "genesis/bignum.h" -extern boolean positive_bignum_logbitp(int,struct bignum*); - -extern lispobj fdefn_callee_lispobj(struct fdefn *fdefn); - -boolean valid_widetag_p(unsigned char widetag); - +extern lispobj decode_fdefn_rawfun(struct fdefn *fdefn); +extern void gc_close_thread_regions(struct thread*, int); +extern void gc_close_collector_regions(int); #endif /* _GC_INTERNAL_H_ */ diff --git a/src/runtime/gc-private.h b/src/runtime/gc-private.h index ea05411fad..c8b589da09 100644 --- a/src/runtime/gc-private.h +++ b/src/runtime/gc-private.h @@ -15,23 +15,31 @@ #ifndef _GC_PRIVATE_H_ #define _GC_PRIVATE_H_ +#include "genesis/instance.h" #include "genesis/weak-pointer.h" #include "immobile-space.h" #include "code.h" #ifdef LISP_FEATURE_GENCGC -#include "gencgc-alloc-region.h" -static inline void * -gc_general_alloc(sword_t nbytes, int page_type_flag) +void *collector_alloc_fallback(struct alloc_region*,sword_t,int); +static inline void* __attribute__((unused)) +gc_general_alloc(struct alloc_region* region, sword_t nbytes, int page_type) { - void *gc_alloc_with_region(struct alloc_region*,sword_t,int); - if (1 <= page_type_flag && page_type_flag <= 3) - return gc_alloc_with_region(&gc_alloc_region[page_type_flag-1], - nbytes, page_type_flag); - lose("bad page type flag: %d", page_type_flag); + void *new_obj = region->free_pointer; + void *new_free_pointer = (char*)new_obj + nbytes; + // Large objects will never fit in a region, so we automatically dtrt + if (new_free_pointer <= region->end_addr) { + region->free_pointer = new_free_pointer; + return new_obj; + } + return collector_alloc_fallback(region, nbytes, page_type); } +lispobj copy_potential_large_object(lispobj object, sword_t nwords, + struct alloc_region*, int page_type); #else -extern void *gc_general_alloc(sword_t nbytes,int page_type_flag); +void *gc_general_alloc(void*,sword_t,int); +lispobj copy_potential_large_object(lispobj object, sword_t nwords, + void*, int page_type); #endif #define CHECK_COPY_PRECONDITIONS(object, nwords) \ @@ -43,34 +51,47 @@ extern void *gc_general_alloc(sword_t nbytes,int page_type_flag); gc_dcheck(lowtag_of(copy) == lowtag); \ gc_dcheck(!from_space_p(copy)); -#define note_transported_object(old, new) /* do nothing */ +#define GC_LOGGING 0 + +/* For debugging purposes, you can make this macro as complicated as you like, + * such as checking various other aspects of the object in 'old' */ +#if GC_LOGGING +#define NOTE_TRANSPORTING(old, new, nwords) really_note_transporting(old,new,nwords) +void really_note_transporting(lispobj old,void*new,sword_t nwords); +#elif defined COLLECT_GC_STATS && COLLECT_GC_STATS +#define NOTE_TRANSPORTING(old, new, nwords) gc_copied_nwords += nwords +#else +#define NOTE_TRANSPORTING(old, new, nwords) /* do nothing */ +#endif +// In-situ live objects are those which get logically "moved" from oldspace to newspace +// by frobbing the generation byte in the page table, not copying. +extern uword_t gc_copied_nwords, gc_in_situ_live_nwords; static inline lispobj -gc_general_copy_object(lispobj object, long nwords, int page_type_flag) +gc_copy_object(lispobj object, size_t nwords, void* region, int page_type) { CHECK_COPY_PRECONDITIONS(object, nwords); /* Allocate space. */ - lispobj *new = gc_general_alloc(nwords*N_WORD_BYTES, page_type_flag); + lispobj *new = gc_general_alloc(region, nwords*N_WORD_BYTES, page_type); + NOTE_TRANSPORTING(object, new, nwords); /* Copy the object. */ memcpy(new,native_pointer(object),nwords*N_WORD_BYTES); - note_transported_object(object, new); - return make_lispobj(new, lowtag_of(object)); } // Like above but copy potentially fewer words than are allocated. // ('old_nwords' can be, but does not have to be, smaller than 'nwords') static inline lispobj -gc_copy_object_resizing(lispobj object, long nwords, int page_type_flag, +gc_copy_object_resizing(lispobj object, long nwords, void* region, int page_type, int old_nwords) { CHECK_COPY_PRECONDITIONS(object, nwords); - lispobj *new = gc_general_alloc(nwords*N_WORD_BYTES, page_type_flag); + lispobj *new = gc_general_alloc(region, nwords*N_WORD_BYTES, page_type); + NOTE_TRANSPORTING(object, new, old_nwords); memcpy(new, native_pointer(object), old_nwords*N_WORD_BYTES); - note_transported_object(object, new); return make_lispobj(new, lowtag_of(object)); } @@ -97,12 +118,10 @@ extern boolean scan_weak_hashtable(struct hash_table *hash_table, void (*)(lispobj*)); extern int (*weak_ht_alivep_funs[4])(lispobj,lispobj); extern void gc_scav_pair(lispobj where[2]); -extern void weakobj_init(); +extern void gc_common_init(); extern boolean test_weak_triggers(int (*)(lispobj), void (*)(lispobj)); lispobj copy_unboxed_object(lispobj object, sword_t nwords); -lispobj copy_object(lispobj object, sword_t nwords); -lispobj copy_large_object(lispobj object, sword_t nwords, int page_type_flag); lispobj *search_read_only_space(void *pointer); lispobj *search_static_space(void *pointer); @@ -133,11 +152,7 @@ static inline int header_rememberedp(lispobj header) { return (header & (OBJ_WRITTEN_FLAG << 24)) != 0; } -#ifndef LISP_FEATURE_IMMOBILE_SPACE - -static inline boolean filler_obj_p(lispobj __attribute__((unused)) *obj) { return 0; } - -#else +#ifdef LISP_FEATURE_IMMOBILE_SPACE extern void enliven_immobile_obj(lispobj*,int); @@ -202,158 +217,364 @@ static inline void assign_generation(lispobj* obj, generation_index_t gen) #error "Need to define immobile_obj_gen_bits() for big-endian" #endif /* little-endian */ -static inline boolean filler_obj_p(lispobj* obj) { - return widetag_of(obj) == CODE_HEADER_WIDETAG && obj[1] == 0; -} - #endif /* immobile space */ +#ifdef LISP_FEATURE_64_BIT +#define WEAK_POINTER_CHAIN_END (void*)(intptr_t)1 +#define in_weak_pointer_list(wp) ((wp->header>>16)!=0) +static inline struct weak_pointer *get_weak_pointer_next(struct weak_pointer *wp) { + // 6 bytes to encode 'next' is way more than enough + uword_t offset = wp->header >> 16; + if (offset <= 1) return (void*)offset; + return (void*)((lispobj*)DYNAMIC_SPACE_START + offset); +} +static inline void reset_weak_pointer_next(struct weak_pointer *wp) { + wp->header = wp->header & 0xffff; +} +static inline lispobj encode_weakptr_next(void* x) { + if ((uword_t)x <= 1) return (uword_t)x; + sword_t wordindex = (lispobj*)x - (lispobj*)DYNAMIC_SPACE_START; + gc_assert(wordindex != 0); // wp can't be the first object in dynamic space + return wordindex; +} +#else #define WEAK_POINTER_CHAIN_END (void*)(intptr_t)-1 -#define WEAK_POINTER_NWORDS ALIGN_UP(WEAK_POINTER_SIZE,2) - -static inline boolean weak_pointer_breakable_p(struct weak_pointer *wp) -{ - lispobj pointee = wp->value; - // A broken weak-pointer's value slot has unbound-marker - // which does not satisfy is_lisp_pointer(). - return is_lisp_pointer(pointee) && (from_space_p(pointee) -#ifdef LISP_FEATURE_IMMOBILE_SPACE - || (immobile_space_p(pointee) && - immobile_obj_gen_bits(base_pointer(pointee)) == from_space) +#define in_weak_pointer_list(wp) (wp->next) +#define get_weak_pointer_next(wp) wp->next +#define reset_weak_pointer_next(wp) wp->next = 0 #endif - ); -} static inline void add_to_weak_pointer_chain(struct weak_pointer *wp) { + // Better already be fixed in position or we're in trouble + gc_dcheck(!compacting_p() || !from_space_p(make_lispobj(wp,OTHER_POINTER_LOWTAG))); /* Link 'wp' into weak_pointer_chain using its 'next' field. * We ensure that 'next' is always NULL when the weak pointer isn't * in the chain, and not NULL otherwise. The end of the chain * is denoted by WEAK_POINTER_CHAIN_END which is distinct from NULL. * The test of whether the weak pointer has been placed in the chain - * is performed in 'scav_weak_pointer' for gencgc. - * In cheneygc, chaining is performed in 'trans_weak_pointer' - * which works just as well, since an object is transported - * at most once per GC cycle */ - wp->next = (struct weak_pointer *)LOW_WORD(weak_pointer_chain); + * is performed in 'scav_weak_pointer' */ +#ifdef LISP_FEATURE_64_BIT + wp->header = (encode_weakptr_next(weak_pointer_chain)<<16) | (wp->header & 0xffff); +#else + wp->next = weak_pointer_chain; +#endif weak_pointer_chain = wp; } -/// Same as Lisp LOGBITP, except no negative bignums allowed. -static inline boolean layout_bitmap_logbitp(int index, lispobj bitmap) +#include "genesis/layout.h" +struct bitmap { sword_t *bits; unsigned int nwords; }; +static inline struct bitmap get_layout_bitmap(struct layout* layout) { - if (fixnump(bitmap)) - return (index < (N_WORD_BITS - N_FIXNUM_TAG_BITS)) - ? (bitmap >> (index+N_FIXNUM_TAG_BITS)) & 1 - : (sword_t)bitmap < 0; - return positive_bignum_logbitp(index, (struct bignum*)native_pointer(bitmap)); + struct bitmap bitmap; + const int layout_id_vector_fixed_capacity = 7; +#ifdef LISP_FEATURE_64_BIT + sword_t depthoid = layout->sw_flags; + // Depthoid is stored in the upper 4 bytes of 'flags', as a fixnum. + depthoid >>= (32 + N_FIXNUM_TAG_BITS); + int extra_id_words = + (depthoid > layout_id_vector_fixed_capacity) ? + ALIGN_UP(depthoid - layout_id_vector_fixed_capacity, 2) / 2 : 0; +#else + sword_t depthoid = fixnum_value(layout->depthoid); + int extra_id_words = (depthoid > layout_id_vector_fixed_capacity) ? + depthoid - layout_id_vector_fixed_capacity : 0; +#endif + // The 2 bits for stable address-based hashing can't ever bet set. + const int baseline_payload_words = (sizeof (struct layout) / N_WORD_BYTES) - 1; + int payload_words = ((unsigned int)layout->header >> INSTANCE_LENGTH_SHIFT) & 0x3FFF; + bitmap.bits = (sword_t*)((char*)layout + sizeof (struct layout)) + extra_id_words; + bitmap.nwords = payload_words - baseline_payload_words - extra_id_words; + return bitmap; +} + +/* Return true if the INDEXth bit is set in BITMAP. + * Index 0 corresponds to the word just after the instance header. + * So index 0 may be the layout pointer if #-compact-instance-header, + * or a user data slot if #+compact-instance-header + */ +static inline boolean bitmap_logbitp(unsigned int index, struct bitmap bitmap) +{ + unsigned int word_index = index / N_WORD_BITS; + unsigned int bit_index = index % N_WORD_BITS; + if (word_index >= bitmap.nwords) return bitmap.bits[bitmap.nwords-1] < 0; + return (bitmap.bits[word_index] >> bit_index) & 1; } /* Keep in sync with 'target-hash-table.lisp' */ +#define hashtable_kind(ht) ((ht->flags >> (4+N_FIXNUM_TAG_BITS)) & 3) #define hashtable_weakp(ht) (ht->flags & (8<<N_FIXNUM_TAG_BITS)) -#define hashtable_weakness(ht) (ht->flags >> (4+N_FIXNUM_TAG_BITS)) +#define hashtable_weakness(ht) (ht->flags >> (6+N_FIXNUM_TAG_BITS)) #if defined(LISP_FEATURE_GENCGC) -/* Define a macro to avoid a detour through the write fault handler. - * - * It's usually more efficient to do these extra tests than to receive - * a signal. And it leaves the page protected, which is a bonus. - * The downside is that multiple operations on the same page ought to - * be batched, so that there is at most one unprotect/reprotect per page - * rather than per write operation per page. - * - * This also should fix -fsanitize=thread which makes handling of SIGSEGV - * during GC difficult. Not impossible, but definitely broken. - * It has to do with the way the sanitizer intercepts calls - * to sigaction() - it mucks with your sa_mask :-(. - * - * This macro take an aribtrary expression as the 'operation' rather than - * an address and value to assign, for two reasons: - * 1. there may be more than one store operation that has to be - * within the scope of the lifted write barrier, - * so a single lvalue and rvalue is maybe inadequate. - * 2. it might need to use a sync_fetch_and_<frob>() gcc intrinsic, - * so it's not necessarily just going to be an '=' operator - * - * KLUDGE: assume that faults do not occur in immobile space. - * for the most part. (This is pretty obviously not true, - * but seems only to be a problem in fullcgc) - */ +extern unsigned char* gc_card_mark; + +#ifdef LISP_FEATURE_DARWIN_JIT +#define OS_VM_PROT_JIT_READ OS_VM_PROT_READ +#define OS_VM_PROT_JIT_ALL OS_VM_PROT_READ | OS_VM_PROT_WRITE +#else +#define OS_VM_PROT_JIT_READ OS_VM_PROT_READ | OS_VM_PROT_EXECUTE +#define OS_VM_PROT_JIT_ALL OS_VM_PROT_ALL +#endif + +// "assign" as the operation name is a little clearer than "set" +// which tends to be synonymous with setting a bit to 1. +#define assign_page_card_marks(page, val) \ + memset(gc_card_mark+page_to_card_index(page), val, CARDS_PER_PAGE) +#ifdef LISP_FEATURE_SOFT_CARD_MARKS + +#define NON_FAULTING_STORE(operation, addr) { operation; } +// The low bit of 0 implies "marked". So CARD_MARKED and STICKY_MARK +// are both considered marked. All bits of UNMARKED are 1s, so that +// one word full of mark bytes reads as -1. See the autogenerated +// functions in "genesis/cardmarks.h" for the use-case. +#define CARD_MARKED 0 +#define STICKY_MARK 2 +#define CARD_UNMARKED 0xff +#define MARK_BYTE_MASK 0xff + +#else + +// With physical page protection, bit index 0 is the MARKED bit (inverted WP bit) +// and bit index 1 is the WP_CLEARED (write_protect_cleared) bit. +// The fault handler always sets both bits. +// The only other bit pair value would be illegal. +#define CARD_UNMARKED 0 /* write-protected = 1 */ +#define CARD_MARKED 1 /* write-protected = 0 */ +#define WP_CLEARED_AND_MARKED 3 /* write-protected = 0, wp-cleared = 1 */ +// CODE-HEADER-SET can store the low byte from NULL-TN into the mark array. +// This sets the two low bits on, but also spuriously sets other bits, +// which we can ignore when reading the byte. +#define MARK_BYTE_MASK 3 + +#define PAGE_WRITEPROTECTED_P(n) (~gc_card_mark[page_to_card_index(n)] & CARD_MARKED) +#define SET_PAGE_PROTECTED(n,val) gc_card_mark[page_to_card_index(n)] = \ + (val ? CARD_UNMARKED : CARD_MARKED) + +#define cardseq_any_marked(card_index) (gc_card_mark[card_index] & CARD_MARKED) +#define cardseq_all_marked_nonsticky(card_index) cardseq_any_marked(card_index) +#define page_cards_all_marked_nonsticky(page_index) \ + cardseq_all_marked_nonsticky(page_to_card_index(page_index)) + +/* NON_FAULTING_STORE is only for fixnums and GC metadata where we need + * the ability to write-through the store barrier. + * The uses are limited to updating the weak vector chain, weak hash-table + * chain, and vector rehash flags. Those don't affect a page's marked state */ +#define PAGE_BASE(addr) ((char*)ALIGN_DOWN((uword_t)(addr),GENCGC_PAGE_BYTES)) #define NON_FAULTING_STORE(operation, addr) { \ page_index_t page_index = find_page_index(addr); \ - if (page_index < 0 || !page_table[page_index].write_protected) { operation; } \ - else { unprotect_page_index(page_index); \ + if (page_index < 0 || !PAGE_WRITEPROTECTED_P(page_index)) { operation; } \ + else { os_protect(PAGE_BASE(addr), GENCGC_PAGE_BYTES, OS_VM_PROT_JIT_ALL); \ operation; \ - protect_page(page_address(page_index), page_index); }} + os_protect(PAGE_BASE(addr), GENCGC_PAGE_BYTES, OS_VM_PROT_JIT_READ); } } -/* This is used bu the fault handler, and potentially during GC */ -static inline void unprotect_page_index(page_index_t page_index) +/* This is used by the fault handler, and potentially during GC + * if we need to remember that a pointer store occurred. + * The fault handler should supply WP_CLEARED_AND_MARKED as the mark, + * but the collector should use CARD_MARKED */ +static inline void unprotect_page(void* addr, unsigned char mark) { - os_protect(page_address(page_index), GENCGC_CARD_BYTES, OS_VM_PROT_ALL); - unsigned char *pflagbits = (unsigned char*)&page_table[page_index].gen - 1; - __sync_fetch_and_or(pflagbits, WP_CLEARED_FLAG); - __sync_fetch_and_and(pflagbits, ~WRITE_PROTECTED_FLAG); + // No atomic op needed for a 1-byte store. + gc_card_mark[addr_to_card_index(addr)] = mark; + os_protect(PAGE_BASE(addr), GENCGC_PAGE_BYTES, OS_VM_PROT_JIT_ALL); } +#endif -static inline void protect_page(void* page_addr, page_index_t page_index) +// Two helpers to avoid invoking the memory fault signal handler. +// For clarity, distinguish between words which *actually* need to frob +// physical (MMU-based) protection versus those which don't, +// but are forced to call mprotect() because it's the only choice. +// Unlike with NON_FAULTING_STORE, in this case we actually do want to record that +// the ensuing store toggles the WP bit without invoking the fault handler. +static inline void notice_pointer_store(void* addr) { +#ifdef LISP_FEATURE_SOFT_CARD_MARKS + int card = addr_to_card_index(addr); + // STICKY is stronger than MARKED. Only change if UNMARKED. + if (gc_card_mark[card] == CARD_UNMARKED) gc_card_mark[card] = CARD_MARKED; +#else + page_index_t index = find_page_index(addr); + gc_assert(index >= 0); + if (PAGE_WRITEPROTECTED_P(index)) unprotect_page(addr, CARD_MARKED); +#endif +} +static inline void ensure_non_ptr_word_writable(__attribute__((unused)) void* addr) { - os_protect((void *)page_addr, - GENCGC_CARD_BYTES, - OS_VM_PROT_READ|OS_VM_PROT_EXECUTE); - - /* Note: we never touch the write_protected_cleared bit when protecting - * a page. Consider two random threads that reach their SIGSEGV handlers - * concurrently, each checking why it got a write fault. One thread wins - * the race to remove the memory protection, and marks our shadow bit. - * wp_cleared is set so that the other thread can conclude that the fault - * was reasonable. - * If GC unprotects and reprotects a page, it's probably OK to reset the - * cleared bit 0 if it was 0 before. (Because the fault handler blocks - * SIG_STOP_FOR_GC which is usually SIGUSR2, handling the wp fault is - * atomic with respect to invocation of GC) - * But nothing is really gained by resetting the cleared flag. - * It is explicitly zeroed on pages marked as free though. - */ - page_table[page_index].write_protected = 1; + // there's nothing to "ensure" if using software card marks +#ifndef LISP_FEATURE_SOFT_CARD_MARKS + notice_pointer_store(addr); +#endif } +// #+soft-card-mark: this expresion is true of both CARD_MARKED and STICKY_MARK +// #-soft-card-mark: this expresion is true of both CARD_MARKED and WP_CLEARED_AND_MARKED +#define card_dirtyp(index) (gc_card_mark[index] & MARK_BYTE_MASK) != CARD_UNMARKED + #else +/* cheneygc */ +#define notice_pointer_store(dummy) +#define ensure_non_ptr_word_writable(dummy) #define NON_FAULTING_STORE(operation, addr) operation #endif -#if defined(LISP_FEATURE_X86_64) || defined(LISP_FEATURE_X86) -# define CODE_PAGES_USE_SOFT_PROTECTION 1 -#else -# define CODE_PAGES_USE_SOFT_PROTECTION 0 -#endif - #define KV_PAIRS_HIGH_WATER_MARK(kvv) fixnum_value(kvv[0]) #define KV_PAIRS_REHASH(kvv) kvv[1] -#include "genesis/layout.h" -// Generalize over INSTANCEish things. (Not general like SB-KERNEL:LAYOUT-OF) -static inline lispobj layout_of(lispobj* instance) { // native ptr - // Smart C compilers eliminate the ternary operator if exprs are the same - return widetag_of(instance) == FUNCALLABLE_INSTANCE_WIDETAG - ? funinstance_layout(instance) : instance_layout(instance); +/* This is NOT the same value that lisp's %INSTANCE-LENGTH returns. + * Lisp always uses the logical length (as originally allocated), + * except when heap-walking which requires exact physical sizes */ +static inline int instance_length(lispobj header) +{ + // * Byte 3 of an instance header word holds the immobile gen# and visited bit, + // so those have to be masked off. + // * fullcgc uses bit index 31 as a mark bit, so that has to + // be cleared. Lisp does not have to clear bit 31 because fullcgc does not + // operate concurrently. + // * If the object is in hashed-and-moved state and the original instance payload + // length was odd (total object length was even), then add 1. + // This can be detected by ANDing some bits, bit 10 being the least-significant + // bit of the original size, and bit 9 being the 'hashed+moved' bit. + // * 64-bit machines do not need 'long' right-shifts, so truncate to int. + + int extra = ((unsigned int)header >> 10) & ((unsigned int)header >> 9) & 1; + return (((unsigned int)header >> INSTANCE_LENGTH_SHIFT) & 0x3FFF) + extra; +} + +// This is index of the bit that differentiates FUNCALLABLE_INSTANCE_WIDETAG +// from INSTANCE_WIDETAG. +#define FUNINSTANCE_SELECTOR_BIT_NUMBER 2 +static inline boolean instanceoid_widetag_p(unsigned char widetag) { + return (widetag | (1<<FUNINSTANCE_SELECTOR_BIT_NUMBER)) == FUNCALLABLE_INSTANCE_WIDETAG; +} +static inline int instanceoid_length(lispobj header) { + return (header & (1<<FUNINSTANCE_SELECTOR_BIT_NUMBER)) + ? (int)(HeaderValue(header) & SHORT_HEADER_MAX_WORDS) : instance_length(header); +} + +/// instance_layout() and layout_of() macros takes a lispobj* and are lvalues +#ifdef LISP_FEATURE_COMPACT_INSTANCE_HEADER + +# ifdef LISP_FEATURE_LITTLE_ENDIAN +# define instance_layout(native_ptr) ((uint32_t*)(native_ptr))[1] +# else +# error "No instance_layout() defined" +# endif +# define funinstance_layout(native_ptr) instance_layout(native_ptr) +// generalize over either metatype, but not as general as SB-KERNEL:LAYOUT-OF +# define layout_of(native_ptr) instance_layout(native_ptr) + +#else + +// first 2 words of ordinary instance are: header, layout +# define instance_layout(native_ptr) ((lispobj*)native_ptr)[1] +// first 4 words of funcallable instance are: header, trampoline, layout, fin-fun +# define funinstance_layout(native_ptr) ((lispobj*)native_ptr)[2] +# define layout_of(native_ptr) \ + ((lispobj*)native_ptr)[1+((widetag_of(native_ptr)>>FUNINSTANCE_SELECTOR_BIT_NUMBER)&1)] + +#endif + +static inline int layout_depth2_id(struct layout* layout) { + int32_t* vector = (int32_t*)&layout->uw_id_word0; + return vector[0]; } +// Keep in sync with hardwired IDs in CHOOSE-LAYOUT-ID +// in src/compiler/generic/layout-ids.lisp +#define WRAPPER_LAYOUT_ID 2 +#define LAYOUT_LAYOUT_ID 3 +#define LFLIST_NODE_LAYOUT_ID 4 +#define BROTHERTREE_UNARY_NODE_LAYOUT_ID 5 -extern lispobj layout_of_layout; /// Return true if 'thing' is a layout. +/// This predicate is careful, as is it used to verify heap invariants. static inline boolean layoutp(lispobj thing) { - lispobj base_ptr = thing - INSTANCE_POINTER_LOWTAG; lispobj layout; - if ((base_ptr & LOWTAG_MASK) || !(layout = layout_of((lispobj*)base_ptr))) - return 0; - return layout == layout_of_layout; + if (lowtag_of(thing) != INSTANCE_POINTER_LOWTAG) return 0; + if ((layout = instance_layout(INSTANCE(thing))) == 0) return 0; + return layout_depth2_id(LAYOUT(layout)) == LAYOUT_LAYOUT_ID; +} +#ifdef LISP_FEATURE_METASPACE +static inline boolean wrapperp(lispobj thing) +{ + lispobj layout; + if (lowtag_of(thing) != INSTANCE_POINTER_LOWTAG) return 0; + if ((layout = instance_layout(INSTANCE(thing))) == 0) return 0; + return layout_depth2_id(LAYOUT(layout)) == WRAPPER_LAYOUT_ID; +} +static inline int wrapper_id(lispobj wrapper) +{ + struct layout* layout = LAYOUT(WRAPPER(wrapper)->friend); + return layout_depth2_id(layout); +} +#endif +/// Return true if 'thing' is the layout of any subtype of sb-lockless::list-node. +static inline boolean lockfree_list_node_layout_p(struct layout* layout) { + return layout_depth2_id(layout) == LFLIST_NODE_LAYOUT_ID; } -static inline int lockfree_list_node_layout_p(struct layout* layout) { - return layout->flags & flag_LockfreeListNode; +#ifdef LISP_FEATURE_METASPACE +#define METASPACE_START (READ_ONLY_SPACE_START+32768) /* KLUDGE */ +// Keep in sync with the macro definitions in src/compiler/generic/early-vm.lisp +struct slab_header { + short sizeclass; + short capacity; + short chunksize; + short count; + void* freelist; + struct slab_header *next; + struct slab_header *prev; +}; +#endif + +/* Check whether 'pointee' was forwarded. If it has been, update the contents + * of 'cell' to point to it. Otherwise, set 'cell' to 'broken'. + * Note that this macro has no braces around the body because one of the uses + * of it needs to stick on another 'else' or two */ +#define TEST_WEAK_CELL(cell, pointee, broken) \ + lispobj *native = native_pointer(pointee); \ + if (from_space_p(pointee)) \ + cell = forwarding_pointer_p(native) ? forwarding_pointer_value(native) : broken; \ + else if (immobile_space_p(pointee)) { \ + if (immobile_obj_gen_bits(base_pointer(pointee)) == from_space) cell = broken; \ + } + +#ifdef MAX_CONSES_PER_PAGE +static const int CONS_PAGE_USABLE_BYTES = MAX_CONSES_PER_PAGE*CONS_SIZE*N_WORD_BYTES; +#endif + +#include "genesis/cons.h" +/* Return true if 'addr' has a lowtag and widetag that correspond, + * given that the words at 'addr' are within range for an allocated page. + * 'addr' could be a pointer to random data, and this check is merely + * a heuristic. False positives are possible. */ +static inline boolean plausible_tag_p(lispobj addr) +{ + if (listp(addr)) + return is_cons_half(CONS(addr)->car) + && is_cons_half(CONS(addr)->cdr) + // -1 can be left by the */signed=>integer vop + // and is also useful as filler on cons pages. + && CONS(addr)->car != (uword_t)-1; + unsigned char widetag = widetag_of(native_pointer(addr)); + return other_immediate_lowtag_p(widetag) + && lowtag_of(addr) == LOWTAG_FOR_WIDETAG(widetag); } +#ifdef LISP_FEATURE_64_BIT +# define make_filler_header(n) (((uword_t)(n)<<32)|FILLER_WIDETAG) +# define filler_total_nwords(header) ((header)>>32) +#else +# define make_filler_header(n) (((n)<<N_WIDETAG_BITS)|FILLER_WIDETAG) +# define filler_total_nwords(header) ((header)>>N_WIDETAG_BITS) +#endif + +#ifdef LISP_FEATURE_BIG_ENDIAN +# define assign_widetag(addr, byte) ((unsigned char*)addr)[N_WORD_BYTES-1] = byte +#else +# define assign_widetag(addr, byte) *(unsigned char*)addr = byte +#endif + #endif /* _GC_PRIVATE_H_ */ diff --git a/src/runtime/gc-unit-tests.c b/src/runtime/gc-unit-tests.c index 560cb54e8f..be38d17588 100644 --- a/src/runtime/gc-unit-tests.c +++ b/src/runtime/gc-unit-tests.c @@ -2,6 +2,52 @@ #define MAX_PAGES_FOR_TEST 20 +/* A newly opened region must not start on a page that has 0 bytes available. + * The effect of that was to cause start_addr to be the next page's address, + * where the OPEN_REGION_PAGE_FLAG was already set on each page in the region + * including the one that was completely full. This caused a failure when + * closing the region because find_page_index(start_addr) was not the *first* + * page on which the open flag should be removed. + * Strangely, the assertion that caught this was far removed from the + * point of failure, in conservative_root_p(). + * It got broken in rev 400b724a8daf and then fixed in rev 07dc4b4e0f + * but the test case itself became buggy some time thereafter + * due to the minimum legal code component size being larger + */ +void test_find_freeish() +{ + unsigned char card_table[256]; + gc_card_table_nbits = 8; + gc_card_table_mask = 0xff; + gc_card_mark = card_table; + memset(card_table, CARD_MARKED, 256); + + page_table_pages = MAX_PAGES_FOR_TEST; + page_table = calloc(1+page_table_pages, sizeof(struct page)); + DYNAMIC_SPACE_START = 0x8000000; + + struct alloc_region r; + long tot_bytes = 0; + gc_init_region(&r); + int i; + for(i=0; i<100;++i) { + int chunk = N_WORD_BYTES*40; + gc_alloc_new_region(chunk, PAGE_TYPE_BOXED, &r, 0); + tot_bytes += chunk; + r.free_pointer = (char*)r.free_pointer + chunk; + int count_open_region_pages = 0, j; + for (j = 0; j < MAX_PAGES_FOR_TEST; ++j) + if (page_table[j].type & OPEN_REGION_PAGE_FLAG) ++count_open_region_pages; + gc_assert(count_open_region_pages == 1); + ensure_region_closed(&r, PAGE_TYPE_BOXED); + gc_assert(bytes_allocated == tot_bytes); + } + free(page_table); + page_table = 0; + DYNAMIC_SPACE_START = 0; + printf("alloc_new_region: PASS\n"); +} + /* Testing approach for adjust_obj_ptes(): * - Allocate a large object that is a smidgen smaller or larger * than an integral number of pages (for varying values of "smidgen"). @@ -18,15 +64,20 @@ void test_adjust_obj_ptes() { - void shrink_obj_test(int ending_size, int created_type, - struct page *expected_result); + void shrink_obj_test(int ending_size, int created_type, + struct page *expected_result); + unsigned char card_table[256]; + gc_card_table_nbits = 8; + gc_card_table_mask = 0xff; + gc_card_mark = card_table; + memset(card_table, CARD_MARKED, 256); // Mock out the dynamic space. Always allocate one extra page in // the page table as a sentinel. struct page expected_result[1+MAX_PAGES_FOR_TEST]; page_table_pages = MAX_PAGES_FOR_TEST; - posix_memalign((void**)&DYNAMIC_SPACE_START, GENCGC_CARD_BYTES, - MAX_PAGES_FOR_TEST * GENCGC_CARD_BYTES); + posix_memalign((void**)&DYNAMIC_SPACE_START, GENCGC_PAGE_BYTES, + MAX_PAGES_FOR_TEST * GENCGC_PAGE_BYTES); struct alloc_region test_region; int npages, fuzz; @@ -35,13 +86,12 @@ void test_adjust_obj_ptes() // i.e. 2*N_WORD_BYTES, the smallest allocatable thing. for (npages = 1 ; npages <= 8; ++npages) for (fuzz = -3; fuzz <= 3; ++fuzz) { - int request = npages * GENCGC_CARD_BYTES + (N_WORD_BYTES*2)*fuzz; + int request = npages * GENCGC_PAGE_BYTES + (N_WORD_BYTES*2)*fuzz; // Mock out initial state: region is freshly initialized, linear // scan for free space from start of heap, // and pick the generation. gc_init_region(&test_region); RESET_ALLOC_START_PAGES(); - test_region.last_page = -1; gc_alloc_generation = SCRATCH_GENERATION; // Wipe out the page table and the allocation counts, @@ -51,7 +101,7 @@ void test_adjust_obj_ptes() for (gen=0; gen < NUM_GENERATIONS; ++gen) generations[gen].bytes_allocated = 0; bytes_allocated = 0; - void *result = gc_alloc_large(request, UNBOXED_PAGE_FLAG, &test_region); + void *result = gc_alloc_large(request, PAGE_TYPE_UNBOXED); // Assert some things about the reference object. gc_assert(result == (void*)DYNAMIC_SPACE_START); @@ -66,9 +116,10 @@ void test_adjust_obj_ptes() // (1) object is "moved" [sic] from boxed to unboxed page, // (2) object was initially on unboxed page, stays on unboxed page. free(page_table); - shrink_obj_test(request, BOXED_PAGE_FLAG, expected_result); - shrink_obj_test(request, UNBOXED_PAGE_FLAG, expected_result); + shrink_obj_test(request, PAGE_TYPE_MIXED, expected_result); + shrink_obj_test(request, PAGE_TYPE_UNBOXED, expected_result); } + printf("adjust_obj_ptes: PASS\n"); } void shrink_obj_test(int ending_size, int initial_type, @@ -83,18 +134,18 @@ void shrink_obj_test(int ending_size, int initial_type, // at the desired size. for (npages = 1 ; npages <= 10; ++npages) for (fuzz = -4; fuzz <= 4; ++fuzz) { - int initial_size = npages * GENCGC_CARD_BYTES + (N_WORD_BYTES*2)*fuzz; + int initial_size = npages * GENCGC_PAGE_BYTES + (N_WORD_BYTES*2)*fuzz; // Test only makes sense where the original size exceeds // or is equal to the ending size. if (initial_size >= ending_size) { gc_init_region(&test_region); RESET_ALLOC_START_PAGES(); - test_region.last_page = -1; // Start with a fresh page table page_table = calloc(1+page_table_pages, sizeof(struct page)); + gc_page_pins = calloc(page_table_pages, 1); from_space = gc_alloc_generation = 2; - void *result = gc_alloc_large(initial_size, initial_type, &test_region); + void *result = gc_alloc_large(initial_size, initial_type); // We're in trouble if pages other than expected were gotten gc_assert(result == (void*)DYNAMIC_SPACE_START); @@ -104,14 +155,14 @@ void shrink_obj_test(int ending_size, int initial_type, sword_t freed = adjust_obj_ptes(find_page_index(result), ending_size/N_WORD_BYTES, SCRATCH_GENERATION, - SINGLE_OBJECT_FLAG | UNBOXED_PAGE_FLAG); + SINGLE_OBJECT_FLAG | PAGE_TYPE_UNBOXED); // After changing the size, all pages should have the correct // number of bytes used, and the bytes freed should be as expected. gc_assert(freed == (initial_size - ending_size)); for (page=0; page<MAX_PAGES_FOR_TEST; ++page) { - gc_assert(page_table[page].bytes_used_ == - expected_result[page].bytes_used_); + gc_assert(page_table[page].words_used_ == + expected_result[page].words_used_); gc_assert(page_table[page].scan_start_offset_ == expected_result[page].scan_start_offset_); gc_assert(page_table[page].type == @@ -127,6 +178,30 @@ void shrink_obj_test(int ending_size, int initial_type, void run_gencgc_tests() { + // Assert that widetags do not satisfy is_lisp_pointer + gc_assert(!is_lisp_pointer(CHARACTER_WIDETAG)); + gc_assert(!is_lisp_pointer(SIMPLE_VECTOR_WIDETAG)); + // Check leafness + gc_assert(leaf_obj_widetag_p(FILLER_WIDETAG)); + gc_assert(leaf_obj_widetag_p(SIMPLE_ARRAY_UNSIGNED_BYTE_8_WIDETAG)); + gc_assert(leaf_obj_widetag_p(SAP_WIDETAG)); + gc_assert(leaf_obj_widetag_p(BIGNUM_WIDETAG)); + // Assert that INSTANCE_WIDETAG is 1 bit different from FUNCALLABLE_INSTANCE + gc_assert((INSTANCE_WIDETAG | (1<<FUNINSTANCE_SELECTOR_BIT_NUMBER)) + == FUNCALLABLE_INSTANCE_WIDETAG); + gc_assert(instanceoid_widetag_p(INSTANCE_WIDETAG)); + gc_assert(instanceoid_widetag_p(FUNCALLABLE_INSTANCE_WIDETAG)); + + // Assert correctness of is_header() + int i; + for(i=0; i<256; ++i) if (fixnump(i)) gc_assert(!is_header(i)); + gc_assert(!is_header(CHARACTER_WIDETAG)); + gc_assert(!is_header(UNBOUND_MARKER_WIDETAG)); + gc_assert(!is_header(NO_TLS_VALUE_MARKER & WIDETAG_MASK)); +#ifdef LISP_FEATURE_64_BIT + gc_assert(!is_header(SINGLE_FLOAT_WIDETAG)); +#endif + test_find_freeish(); test_adjust_obj_ptes(); } diff --git a/src/runtime/gc.h b/src/runtime/gc.h index 62233ffc06..6b7896da35 100644 --- a/src/runtime/gc.h +++ b/src/runtime/gc.h @@ -35,7 +35,53 @@ extern void clear_auto_gc_trigger(void); extern boolean maybe_gc(os_context_t *context); extern boolean gc_active_p; +extern int sb_sprof_enabled; extern os_vm_size_t bytes_consed_between_gcs; +#define VERIFY_VERBOSE 1 +#define VERIFY_PRE_GC 2 +#define VERIFY_POST_GC 4 +/* AGGRESSIVE = always call valid_lisp_pointer_p() on pointers. */ +#define VERIFY_AGGRESSIVE 8 +#define VERIFY_TAGS 16 +/* QUICK = skip most tests. This is intended for use when GC is believed + * to be correct per se (i.e. not for debugging GC), and so the verify + * pass executes more quickly */ +#define VERIFY_QUICK 32 +/* FINAL = warn about pointers from heap space to non-heap space. + * Such pointers would normally be ignored and do not get flagged as failure. + * This can be used in conjunction with QUICK, AGGRESSIVE, or neither. */ +#define VERIFY_FINAL 64 +#define VERIFY_DONT_LOSE 128 + +/* VERIFYING_foo indicates internal state, not a caller's option */ +/* GENERATIONAL implies formatted objects, but there are ranges of objects + * that are not generational - static, readonly, and metaspace - + * so there are no page protection checks performed for pointers from objects + * in such ranges */ +#define VERIFYING_GENERATIONAL 256 +/* UNFORMATTED implies that this is not a range of objects + * but rather a range of pointers such as a binding stack, TLS, + * lisp signal handler array, or other similar array */ +#define VERIFYING_UNFORMATTED 512 + +#define MAX_ERR_OBJS 5 +struct verify_state { + lispobj* object_addr; + lispobj object_header; + uword_t flags; + generation_index_t object_gen; + generation_index_t min_pointee_gen; + int nerrors; + lispobj err_objs[5]; +}; +void hexdump_spaces(struct verify_state*, char *reason); +int verify_heap(lispobj*, int flags); +int hexdump_and_verify_heap(lispobj*, int flags); + +page_index_t gc_find_freeish_pages(page_index_t *restart_page_ptr, sword_t nbytes, + int page_type, generation_index_t gen); + +extern void tlsf_dump_pool(void*, void*, char *pathname); #endif /* _GC_H_ */ diff --git a/src/runtime/gencgc-alloc-region.h b/src/runtime/gencgc-alloc-region.h index bfab85cb94..96bfed604c 100644 --- a/src/runtime/gencgc-alloc-region.h +++ b/src/runtime/gencgc-alloc-region.h @@ -10,29 +10,40 @@ /* Abstract out the data for an allocation region allowing a single * routine to be used for allocation and closing. */ /* Caution: if you change this, you may have to change compiler/generic/objdef - * (for the THREAD object), all the backends' allocators, and room.lisp */ + * (for the THREAD object), all the backends' allocators, and room.lisp. + * But as long as the first two words are left alone, + * it's generally OK to add or remove other words. + */ struct alloc_region { - /* These two are needed for quick allocation. */ void *free_pointer; void *end_addr; /* pointer to the byte after the last usable byte */ - - /* These are needed when closing the region. */ - /* 'last_page' is identical to 'find_page_index((char*)end_addr - 1)' - * whenever the region is in an open state. The value is preserved on - * closing so that allocation can potentially resume where it left off, - * though that's not quite how things are implemented at present. - */ - page_index_t last_page; void *start_addr; }; -// One region for each of {BOXED,UNBOXED,CODE}_PAGE_FLAG -extern struct alloc_region gc_alloc_region[3]; -#define boxed_region gc_alloc_region[BOXED_PAGE_FLAG-1] -#define unboxed_region gc_alloc_region[UNBOXED_PAGE_FLAG-1] -#define code_region gc_alloc_region[CODE_PAGE_TYPE-1] +// Macro to statically initialize instead of using set_region_empty() +#define ALLOC_REGION_INITIALIZER {(void*)0x1000, (void*)1000, 0} + +// One region for each of page type. +// These indices have no correlation to PAGE_TYPE constants. +// MIXED has to always be at array index 0 because lisp accesses +// it directly in #-sb-thread builds. +extern struct alloc_region gc_alloc_region[6]; +#define mixed_region (&gc_alloc_region[0]) +#define small_mixed_region (&gc_alloc_region[1]) +#define unboxed_region (&gc_alloc_region[2]) +#define code_region (&gc_alloc_region[3]) +#define boxed_region (&gc_alloc_region[4]) +#define cons_region (&gc_alloc_region[5]) +#define ASSERT_REGIONS_CLOSED() \ + gc_assert(!((uintptr_t)gc_alloc_region[0].start_addr \ + |(uintptr_t)gc_alloc_region[1].start_addr \ + |(uintptr_t)gc_alloc_region[2].start_addr \ + |(uintptr_t)gc_alloc_region[3].start_addr \ + |(uintptr_t)gc_alloc_region[4].start_addr \ + |(uintptr_t)gc_alloc_region[5].start_addr)) extern generation_index_t from_space, new_space; +extern int gencgc_alloc_profiler; #endif /* _GENCGC_ALLOC_REGION_H_ */ diff --git a/src/runtime/gencgc-internal.h b/src/runtime/gencgc-internal.h index 65780ae57c..2a5627d443 100644 --- a/src/runtime/gencgc-internal.h +++ b/src/runtime/gencgc-internal.h @@ -29,33 +29,65 @@ #error "GENCGC_IS_PRECISE must be #defined as 0 or 1" #endif +#define GENCGC_PAGE_WORDS (GENCGC_PAGE_BYTES/N_WORD_BYTES) extern char *page_address(page_index_t); -int gencgc_handle_wp_violation(void *); +int gencgc_handle_wp_violation(void*, void*); #if N_WORD_BITS == 64 // It's more economical to store scan_start_offset using 4 bytes than 8. - // Doing so makes struct page fit in 8 bytes if bytes_used takes 2 bytes. + // Doing so makes struct page fit in 8 bytes if words_used takes 2 bytes. // scan_start_offset = 4 - // bytes_used = 2 + // words_used = 2 // flags = 1 // gen = 1 - // If bytes_used takes 4 bytes, then the above is 10 bytes which is padded to + // If words_used takes 4 bytes, then the above is 10 bytes which is padded to // 12, which is still an improvement over the 16 that it would have been. # define CONDENSED_PAGE_TABLE 1 #else # define CONDENSED_PAGE_TABLE 0 #endif -#if GENCGC_CARD_BYTES > USHRT_MAX -# if GENCGC_CARD_BYTES > UINT_MAX -# error "GENCGC_CARD_BYTES unexpectedly large." -# else - typedef unsigned int page_bytes_t; -# endif -#else - typedef unsigned short page_bytes_t; +/* One bit of page_words_t is the need_zerofill flag. + * That leaves 15 bits to store page_words_used. This can represent + * a page size of up to 64KiB on 32-bit and 128KiB on 64-bit. + * Note that since the allocation quantum is actually 2 words + * the words_used is always an even number, and so technically + * we could store as "dualwords used" to achieve double the range */ +#if GENCGC_PAGE_WORDS > 32767 +# error "GENCGC_PAGE_WORDS unexpectedly large." #endif +typedef unsigned short page_words_t; + +#define LOCK_PAGE_TABLE 1 +#define LOCK_CODE_ALLOCATOR 2 + +/* New objects are allocated to PAGE_TYPE_MIXED or PAGE_TYPE_CONS */ +/* If you change these constants, then possibly also change the following + * functions in 'room.lisp': + * MAP-CODE-OBJECTS + * PRINT-ALL-CODE + * PRINT-LARGE-CODE + * PRINT-LARGE-UNBOXED + */ + +// 4 bits for the type, 1 bit for SINGLE_OBJECT, 1 bit for OPEN_REGION + +#define PAGE_TYPE_MASK 15 // mask out 'single-object' and 'open-region' flags +#define PAGE_TYPE_UNBOXED 1 // #b001 +#define PAGE_TYPE_BOXED 2 // #b010 +#define PAGE_TYPE_MIXED 3 // #b011 +/* Small-Mixed pages hold objects that don't span cards. This is relatively easy to + * arrange for by adding filler at the end of a card to align prior to the next object, + * subject to a maximum allowable waste. Root scavenging can respect card boundaries + * and use scavenge functions specific to each object - the best of both worlds */ +#define PAGE_TYPE_SMALL_MIXED 4 // #b100 +#define PAGE_TYPE_CONS 5 // #b101 +#define PAGE_TYPE_CODE 7 // #b111 +#define THREAD_PAGE_FLAG 8 +#define SINGLE_OBJECT_FLAG 16 +#define OPEN_REGION_PAGE_FLAG 32 +#define FREE_PAGE_FLAG 0 /* Note that this structure is also used from Lisp-side in * src/code/room.lisp, and the Lisp-side structure layout is currently @@ -84,43 +116,37 @@ struct page { os_vm_size_t scan_start_offset_; #endif - /* the number of bytes of this page that are used. This may be less - * than the actual bytes used for pages within the current - * allocation regions. MUST be 0 for unallocated pages. - * When read, the low bit has to be masked off. - */ - page_bytes_t bytes_used_; + /* the number of lispwords of this page that are used. This may be less + * than the usage at an instant in time for pages within the current + * allocation regions. The 0th bit of the physical uint16 indicates + * that the page needs to be zero-filled for the next use. + * Let the C compiler figure it out, so we can't get it wrong in C. + * But we need to reverse the order of the packed fields depending on + * endianness so that the Lisp side is easier to understand */ +#ifdef LISP_FEATURE_BIG_ENDIAN + page_words_t words_used_ : 15; + page_words_t need_zerofill : 1; +#else + page_words_t need_zerofill : 1; + page_words_t words_used_ : 15; +#endif // !!! If bit positions are changed, be sure to reflect the changes into // page_extensible_p() as well as ALLOCATION-INFORMATION in sb-introspect - unsigned char + // and WALK-DYNAMIC-SPACE. /* - * The low 4 bits of 'type' are interpreted as: + * The 4 low bits of 'type' are defined by PAGE_TYPE_x constants. * 0000 free - * ?001 boxed data - * ?010 unboxed data - * ?011 code - * 1??? open region - * The high bit indicates that the page holds part of or the entirety - * of a single object and no other objects. - * Constants for this field are defined in gc-internal.h, the - * xxx_PAGE_FLAG definitions. - * - * If the page is free, all the following fields are zero. */ - type :5, - /* This is set when the page is write-protected. This should - * always reflect the actual write_protect status of a page. - * (If the page is written into, we catch the exception, make - * the page writable, and clear this flag.) */ - write_protected :1, - /* This flag is set when the above write_protected flag is - * cleared by the SIGBUS handler (or SIGSEGV handler, for some - * OSes). This is useful for re-scavenging pages that are - * written during a GC. */ - write_protected_cleared :1, - /* If this page should not be moved during a GC then this flag - * is set. It's only valid during a GC for allocated pages. */ - pinned :1; + * ?001 strictly boxed data (pointers, immediates, object headers) + * ?010 strictly unboxed data + * ?011 mixed boxed/unboxed non-code objects + * ?111 code + * The next two bits are SINGLE_OBJECT and OPEN_REGION. + * The top two can be used for segregating objects by widetag + * which will important once we have "destructors" to run for a + * for a category of object, such as SYMBOL, hypothetically for + * recycling TLS indices or something like that. */ + unsigned char type; /* the generation that this page belongs to. This should be valid * for all pages that may have objects allocated, even current @@ -129,17 +155,85 @@ struct page { generation_index_t gen; }; extern struct page *page_table; -#ifdef LISP_FEATURE_BIG_ENDIAN -# define WP_CLEARED_FLAG (1<<1) -# define WRITE_PROTECTED_FLAG (1<<2) -#else -# define WRITE_PROTECTED_FLAG (1<<5) -# define WP_CLEARED_FLAG (1<<6) -#endif + +/* a structure to hold the state of a generation + * + * CAUTION: If you modify this, make sure to touch up the alien + * definition in src/code/gc.lisp accordingly. ...or better yes, + * deal with the FIXME there... + */ +struct generation { + /* the bytes allocated to this generation */ + os_vm_size_t bytes_allocated; + + /* the number of bytes at which to trigger a GC */ + os_vm_size_t gc_trigger; + + /* to calculate a new level for gc_trigger */ + os_vm_size_t bytes_consed_between_gc; + + /* the number of GCs since the last raise */ + int num_gc; + + /* the number of GCs to run on the generations before raising objects to the + * next generation */ + int number_of_gcs_before_promotion; + + /* the cumulative sum of the bytes allocated to this generation. It is + * cleared after a GC on this generations, and update before new + * objects are added from a GC of a younger generation. Dividing by + * the bytes_allocated will give the average age of the memory in + * this generation since its last GC. */ + os_vm_size_t cum_sum_bytes_allocated; + + /* a minimum average memory age before a GC will occur helps + * prevent a GC when a large number of new live objects have been + * added, in which case a GC could be a waste of time */ + double minimum_age_before_gc; +}; + +/* When computing a card index we never subtract the heap base, which simplifies + * code generation. The heap base is guaranteed to be GC-page-aligned. + * The low bits can wraparound from all 1s to all 0s such that lowest numbered + * page index in linear order may have a higher card index. + * Two small examples of the distinction between page index and card index. + * For both examples: heap base = 0xEB00, page-size = 256b, npages = 8. + * + * Scenario A: + * CARDS_PER_PAGE = 1, card-size = 256b, ncards = 8, right-shift = 8, mask = #b111 + * page page card + * index base index + * 0 EB00 3 + * 1 EC00 4 + * 2 ED00 5 + * 3 EE00 6 + * 4 EF00 7 + * 5 F000 0 + * 6 F100 1 + * 7 F200 2 + * + * Scenario B: + * CARDS_PER_PAGE = 2, card-size = 128b, ncards = 16, right-shift = 7, mask = #b1111 + * page page card + * index base indices + * 0 EB00, EB80 6, 7 + * 1 EC00, EC80 8, 9 + * 2 ED00, ED80 10, 11 + * 3 EE00, EE80 12, 13 + * 4 EF00, EF80 14, 15 + * 5 F000, F080 0, 1 + * 6 F100, F180 2, 3 + * 7 F200, F280 4, 5 + * + */ +extern unsigned char *gc_card_mark; +extern long gc_card_table_mask; +#define addr_to_card_index(addr) ((((uword_t)addr)>>GENCGC_CARD_SHIFT) & gc_card_table_mask) +#define page_to_card_index(n) addr_to_card_index(page_address(n)) struct __attribute__((packed)) corefile_pte { uword_t sso; // scan start offset - page_bytes_t bytes_used; + page_words_t words_used; // low bit is the 'large object' flag }; /* values for the page.allocated field */ @@ -150,25 +244,29 @@ extern page_index_t page_table_pages; /* forward declarations */ -void update_dynamic_space_free_pointer(void); -void gc_close_region(struct alloc_region *alloc_region, int page_type_flag); +void gc_close_region(struct alloc_region *alloc_region, int page_type); static inline void ensure_region_closed(struct alloc_region *alloc_region, - int page_type_flag) + int page_type) { if (alloc_region->start_addr) - gc_close_region(alloc_region, page_type_flag); + gc_close_region(alloc_region, page_type); } static inline void gc_set_region_empty(struct alloc_region *region) { + /* Free-pointer has to be not equal to 0 because it's undefined behavior + * to add any value whatsoever to the null pointer. + * Annoying, isn't it. http://c-faq.com/null/machexamp.html */ + region->free_pointer = region->end_addr = (void*)0x1000; + /* Start 0 is the indicator of closed-ness. */ + region->start_addr = 0; /* last_page is not reset. It can be used as a hint where to resume * allocating after closing and re-opening the region */ - region->start_addr = region->free_pointer = region->end_addr = 0; } static inline void gc_init_region(struct alloc_region *region) { - region->last_page = 0; // must always be a valid page index + // A distinction without a difference (it used to do one more assignment) gc_set_region_empty(region); } @@ -180,45 +278,47 @@ static inline void gc_init_region(struct alloc_region *region) /* Find the page index within the page_table for the given * address. Return -1 on failure. */ -static inline page_index_t -find_page_index(void *addr) +static inline page_index_t find_page_index(void *addr) { if (addr >= (void*)DYNAMIC_SPACE_START) { page_index_t index = ((uintptr_t)addr - - (uintptr_t)DYNAMIC_SPACE_START) / GENCGC_CARD_BYTES; + (uintptr_t)DYNAMIC_SPACE_START) / GENCGC_PAGE_BYTES; if (index < page_table_pages) return (index); } return (-1); } -#define SINGLE_OBJECT_FLAG (1<<4) #define page_single_obj_p(page) ((page_table[page].type & SINGLE_OBJECT_FLAG)!=0) -#define page_has_smallobj_pins(page) \ - (page_table[page].pinned && !page_single_obj_p(page)) +extern unsigned char* gc_page_pins; static inline boolean pinned_p(lispobj obj, page_index_t page) { extern struct hopscotch_table pinned_objects; - // FIXME: this gets called if !compacting_p, - // but most people don't run with extra debug assertions, - // and if you enable them, you'll pretty quickly crash here. - // gc_dcheck(compacting_p()); -#if !GENCGC_IS_PRECISE - return page_has_smallobj_pins(page) - && hopscotch_containsp(&pinned_objects, obj); -#else - /* There is almost never anything in the hashtable on precise platforms */ - if (!pinned_objects.count || !page_has_smallobj_pins(page)) - return 0; -# ifdef RETURN_PC_WIDETAG - /* Conceivably there could be a precise GC without RETURN-PC objects */ - if (widetag_of(native_pointer(obj)) == RETURN_PC_WIDETAG) + // Single-object pages can be pinned, but the object doesn't go + // in the hashtable. pinned_p can be queried on those pages, + // but the answer is always 'No', because if pinned, the page would + // already have had its generation changed to newspace. + if (page_single_obj_p(page)) return 0; + +#ifdef RETURN_PC_WIDETAG + // Yet another complication from the despised LRA objects- with the + // refinement of 8 pin bits per page, we either must set all possible bits + // for a simple-fun, or map LRAs to the code base address. + if (widetag_of(native_pointer(obj)) == RETURN_PC_WIDETAG) { + // The hash-table stores tagged pointers. obj = make_lispobj(fun_code_header(native_pointer(obj)), OTHER_POINTER_LOWTAG); -# endif - return hopscotch_containsp(&pinned_objects, obj); + page = find_page_index((void*)obj); + } #endif + + unsigned char pins = gc_page_pins[page]; + if (!pins) return 0; + unsigned addr_lowpart = obj & (GENCGC_PAGE_BYTES-1); + // Divide the page into 8 parts, see whether that part is pinned. + unsigned subpage = addr_lowpart / (GENCGC_PAGE_BYTES/8); + return (pins & (1<<subpage)) && hopscotch_containsp(&pinned_objects, obj); } // Return true only if 'obj' must be *physically* transported to survive gc. @@ -229,40 +329,36 @@ from_space_p(lispobj obj) { gc_dcheck(compacting_p()); page_index_t page_index = find_page_index((void*)obj); - return page_index >= 0 - && page_table[page_index].gen == from_space - && !pinned_p(obj, page_index); + // NOTE: It is legal to access page_table at index -1, + // and the 'gen' of page -1 is an otherwise unused value. + return page_table[page_index].gen == from_space && !pinned_p(obj, page_index); } static boolean __attribute__((unused)) new_space_p(lispobj obj) { gc_dcheck(compacting_p()); page_index_t page_index = find_page_index((void*)obj); - return page_index >= 0 && page_table[page_index].gen == new_space; + // NOTE: It is legal to access page_table at index -1, + // and the 'gen' of page -1 is an otherwise unused value. + return page_table[page_index].gen == new_space; } #ifdef LISP_FEATURE_IMMOBILE_SPACE -struct fixedobj_page { // 12 bytes per page +struct fixedobj_page { // 8 bytes per page + unsigned int free_index; // index is in bytes. 4 bytes union immobile_page_attr { int packed; struct { unsigned char flags; - /* space per object in Lisp words. Can exceed obj_size - to align on a larger boundary */ - unsigned char obj_align; - unsigned char obj_size; /* in Lisp words, incl. header */ + unsigned char obj_align; // object spacing expressed in lisp words + unsigned char unused1; /* Which generations have data on this page */ unsigned char gens_; // a bitmap } parts; } attr; - int free_index; // index is in bytes. 4 bytes - short int prior_gc_free_word_index; // index is in words. 2 bytes - /* page index of next page with same attributes */ - short int page_link; // 2 bytes }; extern struct fixedobj_page *fixedobj_pages; #define fixedobj_page_obj_align(i) (fixedobj_pages[i].attr.parts.obj_align<<WORD_SHIFT) -#define fixedobj_page_obj_size(i) fixedobj_pages[i].attr.parts.obj_size #endif extern page_index_t next_free_page; diff --git a/src/runtime/gencgc-private.h b/src/runtime/gencgc-private.h index 08902e23a0..65c74924fd 100644 --- a/src/runtime/gencgc-private.h +++ b/src/runtime/gencgc-private.h @@ -12,21 +12,18 @@ #ifndef _GENCGC_PRIVATE_H_ #define _GENCGC_PRIVATE_H_ -void zero_dirty_pages(page_index_t start, page_index_t end, int page_type); - -/// There is some additional cleverness that could potentially be had - -/// the "need_to_zero" bit (a/k/a "page dirty") is obviously 1 if the page -/// contains objects. Only for an empty page must we distinguish between pages -/// not needing be zero-filled before next use and those which must be. -/// Thus, masking off the dirty bit could be avoided by not storing it for -/// any in-use page. But since that's not what we do - we set the bit to 1 -/// as soon as a page is used - we do have to mask off the bit. -#define page_bytes_used(index) (page_table[index].bytes_used_ & ~1) -#define page_need_to_zero(index) (page_table[index].bytes_used_ & 1) -#define set_page_bytes_used(index,val) \ - page_table[index].bytes_used_ = (val) | page_need_to_zero(index) -#define set_page_need_to_zero(index,val) \ - page_table[index].bytes_used_ = page_bytes_used(index) | val +void zeroize_pages_if_needed(page_index_t start, page_index_t end, int page_type); + +typedef unsigned int page_bytes_t; +#define page_words_used(index) page_table[index].words_used_ +#define page_bytes_used(index) ((page_bytes_t)page_table[index].words_used_<<WORD_SHIFT) +#if defined LISP_FEATURE_RISCV && defined LISP_FEATURE_LINUX // KLUDGE +#define page_need_to_zero(index) (mmap_does_not_zero || page_table[index].need_zerofill) +#else +#define page_need_to_zero(index) page_table[index].need_zerofill +#endif +#define set_page_bytes_used(index,val) page_table[index].words_used_ = ((val)>>WORD_SHIFT) +#define set_page_need_to_zero(index,val) page_table[index].need_zerofill = val #if !CONDENSED_PAGE_TABLE @@ -51,7 +48,7 @@ static void __attribute__((unused)) set_page_scan_start_offset(page_index_t index, os_vm_size_t offset) { // If the offset is nonzero and page-aligned - unsigned int lsb = offset !=0 && IS_ALIGNED(offset, GENCGC_CARD_BYTES); + unsigned int lsb = offset !=0 && IS_ALIGNED(offset, GENCGC_PAGE_BYTES); os_vm_size_t scaled = (offset >> (lsb ? GENCGC_CARD_SHIFT-1 : WORD_SHIFT)) | lsb; if (scaled > SCAN_START_OFS_MAX) { // Assert that if offset exceed the max representable value, @@ -89,19 +86,72 @@ static os_vm_size_t __attribute__((unused)) page_scan_start_offset(page_index_t #endif +#define is_code(type) ((type & PAGE_TYPE_MASK) == PAGE_TYPE_CODE) + +// If *all* pages use soft card marks, then protection_mode() is not a thing. +// Otherwise, only pages of code use soft card marks; return an enum indicating +// whether the page protection for the specified page is applied in harware. +#ifndef LISP_FEATURE_SOFT_CARD_MARKS enum prot_mode { PHYSICAL, LOGICAL }; static inline enum prot_mode protection_mode(page_index_t page) { -#if CODE_PAGES_USE_SOFT_PROTECTION // code pages can be marked as logically read-only without OS protection, // and everything else uses hardware-based protection where applicable. - return ((page_table[page].type & PAGE_TYPE_MASK) == CODE_PAGE_TYPE) - ? LOGICAL : PHYSICAL; -#else - return PHYSICAL; // all pages, if protected, use hardware-based protection + return is_code(page_table[page].type) ? LOGICAL : PHYSICAL; +} #endif + +/* True if the page starts a contiguous block. */ +static inline boolean +page_starts_contiguous_block_p(page_index_t page_index) +{ + // Don't use the preprocessor macro: 0 means 0. + return page_table[page_index].scan_start_offset_ == 0; } -#ifndef LISP_FEATURE_SB_THREAD -#define SINGLE_THREAD_BOXED_REGION (struct alloc_region*)(STATIC_SPACE_START + 2*N_WORD_BYTES) +/* True if the page is the last page in a contiguous block. */ +static inline boolean +page_ends_contiguous_block_p(page_index_t page_index, + generation_index_t __attribute__((unused)) gen) +{ + /* Re. this next test: git rev c769dd53 said that there was a bug when we don't + * test page_bytes_used, but I fail to see how 'page_starts_contiguous_block_p' + * on the next page is not a STRONGER condition, i.e. it should imply that + * 'page_index' ends a block without regard for the number of bytes used. + * Apparently at some point I understood this and now I don't again. + * That's what comments are for, damnit. + * Anyway, I *think* the issue was, at some point, as follows: + * | page | page | + * pinned-obj + * <------------------- scan-start + * where the first of the two pages had a small object pinned. This used to + * adjust the bytes used to account _only_ for the pins. That was wrong - + * the page has to be counted as if it is completely full. + * So _maybe_ both these conditions do not need to be present now ? + */ + // There is *always* a next page in the page table. + boolean answer = page_words_used(page_index) < GENCGC_PAGE_WORDS + || page_starts_contiguous_block_p(page_index+1); +#ifdef DEBUG + boolean safe_answer = + (/* page doesn't fill block */ + (page_words_used(page_index) < GENCGC_PAGE_WORDS) + /* page is last allocated page */ + || ((page_index + 1) >= next_free_page) + /* next page contains no data */ + || !page_words_used(page_index + 1) + /* next page is in different generation */ + || (page_table[page_index + 1].gen != gen) + /* next page starts its own contiguous block */ + || (page_starts_contiguous_block_p(page_index + 1))); + gc_assert(answer == safe_answer); #endif + return answer; +} + +static inline page_index_t contiguous_block_final_page(page_index_t first) { + page_index_t last = first; + while (!page_ends_contiguous_block_p(last, page_table[first].gen)) ++last; + return last; +} + #endif /* _GENCGC_PRIVATE_H_ */ diff --git a/src/runtime/gencgc.c b/src/runtime/gencgc.c index 6e8768edcf..d7753cf074 100644 --- a/src/runtime/gencgc.c +++ b/src/runtime/gencgc.c @@ -28,9 +28,7 @@ #include <string.h> #include <inttypes.h> #include "sbcl.h" -#if defined(LISP_FEATURE_WIN32) && defined(LISP_FEATURE_SB_THREAD) -#include "pthreads_win32.h" -#else +#ifndef LISP_FEATURE_WIN32 #include <signal.h> #endif #include "runtime.h" @@ -46,7 +44,7 @@ #include "gc-private.h" #include "gencgc-private.h" #include "thread.h" -#include "getallocptr.h" +#include "pseudo-atomic.h" #include "alloc.h" #include "code.h" #include "genesis/gc-tables.h" @@ -62,10 +60,10 @@ #include "genesis/cons.h" #include "forwarding-ptr.h" #include "lispregs.h" +#include "var-io.h" /* forward declarations */ -page_index_t gc_find_freeish_pages(page_index_t *restart_page_ptr, sword_t nbytes, - int page_type_flag, generation_index_t gen); +extern FILE *gc_activitylog(); /* @@ -113,6 +111,7 @@ enum { /* Largest allocation seen since last GC. */ os_vm_size_t large_allocation = 0; +int n_gcs; /* @@ -134,15 +133,6 @@ generation_index_t verify_gens = HIGHEST_NORMAL_GENERATION + 2; /* Should we do a pre-scan of the heap before it's GCed? */ boolean pre_verify_gen_0 = 0; // FIXME: should be named 'pre_verify_gc' -/* Should we check that newly allocated regions are zero filled? */ -boolean gencgc_zero_check = 0; - -/* If defined, free pages are read-protected to ensure that nothing - * accesses them. - */ - -/* #define READ_PROTECT_FREE_PAGES */ - /* * GC structures and variables @@ -163,51 +153,51 @@ boolean gc_active_p = 0; /* should the GC be conservative on stack. If false (only right before * saving a core), don't scan the stack / mark pages pinned. */ static boolean conservative_stack = 1; +int save_lisp_gc_iteration; /* An array of page structures is allocated on gc initialization. * This helps to quickly map between an address and its page structure. * page_table_pages is set from the size of the dynamic space. */ page_index_t page_table_pages; struct page *page_table; +unsigned char *gc_page_pins; +unsigned char *gc_card_mark; lispobj gc_object_watcher; int gc_traceroot_criterion; -int gc_n_stack_pins; +// Filtered pins include code but not simple-funs, +// and must not include invalid pointers. +lispobj* gc_filtered_pins; +static int pins_alloc_size; +int gc_pin_count; struct hopscotch_table pinned_objects; /* This is always 0 except during gc_and_save() */ lispobj lisp_init_function; -/// Constants defined in gc-internal: -/// #define BOXED_PAGE_FLAG 1 -/// #define UNBOXED_PAGE_FLAG 2 -/// #define OPEN_REGION_PAGE_FLAG 8 - static inline boolean page_free_p(page_index_t page) { return (page_table[page].type == FREE_PAGE_FLAG); } +static inline boolean boxed_type_p(int type) { return type > 1; } static inline boolean page_boxed_p(page_index_t page) { - return (page_table[page].type & BOXED_PAGE_FLAG); -} - -/// Return true if low 4 'type' bits are 0zz1, false otherwise (z = don't-care) -/// i.e. true of pages which could hold boxed or partially boxed objects. -static inline boolean page_boxed_no_region_p(page_index_t page) { - return (page_table[page].type & 9) == BOXED_PAGE_FLAG; + // ignore SINGLE_OBJECT_FLAG and OPEN_REGION_PAGE_FLAG + return boxed_type_p(page_table[page].type & PAGE_TYPE_MASK); } +#ifndef LISP_FEATURE_SOFT_CARD_MARKS static inline boolean protect_page_p(page_index_t page, generation_index_t generation) { - return (page_boxed_no_region_p(page) - && (page_bytes_used(page) != 0) - && !page_table[page].pinned + return (page_boxed_p(page) + && !(page_table[page].type & OPEN_REGION_PAGE_FLAG) + && (page_words_used(page) != 0) + && !gc_page_pins[page] && (page_table[page].gen == generation)); } +#endif /* Calculate the start address for the given page number. */ -inline char * -page_address(page_index_t page_num) +inline char *page_address(page_index_t page_num) { - return (void*)(DYNAMIC_SPACE_START + (page_num * GENCGC_CARD_BYTES)); + return (void*)(DYNAMIC_SPACE_START + (page_num * GENCGC_PAGE_BYTES)); } /* Calculate the address where the allocation region associated with @@ -218,49 +208,42 @@ page_scan_start(page_index_t page_index) return page_address(page_index)-page_scan_start_offset(page_index); } -/* True if the page starts a contiguous block. */ -static inline boolean -page_starts_contiguous_block_p(page_index_t page_index) -{ - // Don't use the preprocessor macro: 0 means 0. - return page_table[page_index].scan_start_offset_ == 0; -} - -/* True if the page is the last page in a contiguous block. */ -static inline boolean -page_ends_contiguous_block_p(page_index_t page_index, - generation_index_t __attribute__((unused)) gen) -{ - // There is *always* a next page in the page table. - boolean answer = page_bytes_used(page_index) < GENCGC_CARD_BYTES - || page_starts_contiguous_block_p(page_index+1); -#ifdef DEBUG - boolean safe_answer = - (/* page doesn't fill block */ - (page_bytes_used(page_index) < GENCGC_CARD_BYTES) - /* page is last allocated page */ - || ((page_index + 1) >= next_free_page) - /* next page contains no data */ - || !page_bytes_used(page_index + 1) - /* next page is in different generation */ - || (page_table[page_index + 1].gen != gen) - /* next page starts its own contiguous block */ - || (page_starts_contiguous_block_p(page_index + 1))); - gc_assert(answer == safe_answer); -#endif - return answer; -} - /* We maintain the invariant that pages with FREE_PAGE_FLAG have * scan_start of zero, to optimize page_ends_contiguous_block_p(). - * Clear all other flags as well, since they don't mean anything, - * and a store is simpler than a bitwise operation */ + * Clear all the flags that don't pertain to a free page. + * Particularly the 'need_zerofill' bit MUST remain as-is */ static inline void reset_page_flags(page_index_t page) { page_table[page].scan_start_offset_ = 0; - // Any C compiler worth its salt should merge these into one store - page_table[page].type = page_table[page].write_protected - = page_table[page].write_protected_cleared = page_table[page].pinned = 0; +#ifdef LISP_FEATURE_DARWIN_JIT + // Whenever a page was mapped as code, it potentially needs to be remapped on the next use. + // This avoids any affect of pthread_jit_write_protect_np when next used. + if (page_table[page].type == PAGE_TYPE_CODE) set_page_need_to_zero(page, 1); +#endif + page_table[page].type = 0; + gc_page_pins[page] = 0; + // Why can't the 'gen' get cleared? It caused failures. THIS MAKES NO SENSE!!! + // page_table[page].gen = 0; + // Free pages are dirty (MARKED) because MARKED is equivalent + // to not-write-protected, which is what you want for allocation. + assign_page_card_marks(page, CARD_MARKED); +} + +/* SIMD-within-a-register algorithms + * + * from https://graphics.stanford.edu/~seander/bithacks.html + */ +#ifdef LISP_FEATURE_SOFT_CARD_MARKS +static inline uword_t word_haszero(uword_t word) { + return ((word - 0x0101010101010101LL) & ~word & 0x8080808080808080LL) != 0; +} +static inline uword_t word_has_stickymark(uword_t word) { + return word_haszero(word ^ 0x0202020202020202LL); } +#include "genesis/cardmarks.h" +int page_cards_all_marked_nonsticky(page_index_t page) { + return cardseq_all_marked_nonsticky(page_to_card_index(page)); +} +#endif /// External function for calling from Lisp. page_index_t ext_find_page_index(void *addr) { return find_page_index(addr); } @@ -269,7 +252,7 @@ static os_vm_size_t npage_bytes(page_index_t npages) { gc_assert(npages>=0); - return ((os_vm_size_t)npages)*GENCGC_CARD_BYTES; + return ((os_vm_size_t)npages)*GENCGC_PAGE_BYTES; } /* Check that X is a higher address than Y and return offset from Y to @@ -281,42 +264,6 @@ addr_diff(void *x, void *y) return (uintptr_t)x - (uintptr_t)y; } -/* a structure to hold the state of a generation - * - * CAUTION: If you modify this, make sure to touch up the alien - * definition in src/code/gc.lisp accordingly. ...or better yes, - * deal with the FIXME there... - */ -struct generation { - /* the bytes allocated to this generation */ - os_vm_size_t bytes_allocated; - - /* the number of bytes at which to trigger a GC */ - os_vm_size_t gc_trigger; - - /* to calculate a new level for gc_trigger */ - os_vm_size_t bytes_consed_between_gc; - - /* the number of GCs since the last raise */ - int num_gc; - - /* the number of GCs to run on the generations before raising objects to the - * next generation */ - int number_of_gcs_before_promotion; - - /* the cumulative sum of the bytes allocated to this generation. It is - * cleared after a GC on this generations, and update before new - * objects are added from a GC of a younger generation. Dividing by - * the bytes_allocated will give the average age of the memory in - * this generation since its last GC. */ - os_vm_size_t cum_sum_bytes_allocated; - - /* a minimum average memory age before a GC will occur helps - * prevent a GC when a large number of new live objects have been - * added, in which case a GC could be a waste of time */ - double minimum_age_before_gc; -}; - /* an array of generation structures. There needs to be one more * generation structure than actual generations as the oldest * generation is temporarily raised then lowered. */ @@ -336,11 +283,6 @@ struct generation generations[NUM_GENERATIONS]; * data can be avoided. */ generation_index_t gencgc_oldest_gen_to_gc = HIGHEST_NORMAL_GENERATION; -/* The maximum used page in the heap is maintained and used to update - * ALLOCATION_POINTER which is used by the room function to limit its - * search of the heap. XX Gencgc obviously needs to be better - * integrated with the Lisp code. */ - page_index_t next_free_page; // upper (exclusive) bound on used page range #ifdef LISP_FEATURE_SB_THREAD @@ -350,8 +292,12 @@ page_index_t next_free_page; // upper (exclusive) bound on used page range * >1 thread at a time and must be thread-safe. This lock must be * seized before all accesses to generations[] or to parts of * page_table[] that other threads may want to see */ +#ifdef LISP_FEATURE_WIN32 +static CRITICAL_SECTION free_pages_lock; +#else static pthread_mutex_t free_pages_lock = PTHREAD_MUTEX_INITIALIZER; #endif +#endif extern os_vm_size_t gencgc_release_granularity; os_vm_size_t gencgc_release_granularity = GENCGC_RELEASE_GRANULARITY; @@ -366,41 +312,42 @@ os_vm_size_t gencgc_alloc_granularity = GENCGC_ALLOC_GRANULARITY; /* Count the number of pages in the given generation. * Additionally, if 'n_write_protected' is non-NULL, then assign - * into *n_write_protected the count of write-protected pages. + * into *n_write_protected the count of marked pages. */ static page_index_t -count_generation_pages(generation_index_t generation, - page_index_t* n_write_protected) +count_generation_pages(generation_index_t generation, page_index_t* n_dirty) { - page_index_t i, total = 0, wp = 0; + page_index_t i, total = 0, dirty = 0; + int j; for (i = 0; i < next_free_page; i++) if (!page_free_p(i) && (page_table[i].gen == generation)) { total++; - if (page_table[i].write_protected) - wp++; + long card = page_to_card_index(i); + for (j=0; j<CARDS_PER_PAGE; ++j, ++card) + if (card_dirtyp(card)) ++dirty; } - if (n_write_protected) - *n_write_protected = wp; + // divide by cards per page rounding up + if (n_dirty) *n_dirty = (dirty + (CARDS_PER_PAGE-1)) / CARDS_PER_PAGE; return total; } static void show_pinnedobj_count() { page_index_t page; - int nbytes = 0; + int nwords = 0; int n_pinned_largeobj = 0; for (page = 0; page < next_free_page; ++page) { - if (page_table[page].gen == from_space && page_table[page].pinned + if (page_table[page].gen == from_space && gc_page_pins[page] && page_single_obj_p(page)) { - nbytes += page_bytes_used(page); + nwords += page_words_used(page); if (page_starts_contiguous_block_p(page)) ++n_pinned_largeobj; } } fprintf(stderr, - "/pinned objects(g%d): large=%d (%d bytes), small=%d\n", - from_space, n_pinned_largeobj, nbytes, pinned_objects.count); + "/pinned objects(g%d): large=%d (%d words), small=%d\n", + from_space, n_pinned_largeobj, nwords, pinned_objects.count); } /* Work through the pages and add up the number of bytes used for the @@ -412,9 +359,9 @@ count_generation_bytes_allocated (generation_index_t gen) os_vm_size_t result = 0; for (i = 0; i < next_free_page; i++) { if (!page_free_p(i) && page_table[i].gen == gen) - result += page_bytes_used(i); + result += page_words_used(i); } - return result; + return result*N_WORD_BYTES; } /* Return the average age of the memory in a generation. */ @@ -435,8 +382,35 @@ extern void fpu_restore(void *); #define PAGE_INDEX_FMT PRIdPTR -extern void -write_generation_stats(FILE *file) +int count_immobile_objects(__attribute__((unused)) int gen, int res[5]) +{ +#ifdef LISP_FEATURE_IMMOBILE_SPACE + lispobj* where = (lispobj*)FIXEDOBJ_SPACE_START; + lispobj* end = fixedobj_free_pointer; + while (where < end) { + if (immobile_obj_generation(where) == gen) { + switch (widetag_of(where)) { + case FUNCALLABLE_INSTANCE_WIDETAG: ++res[0]; break; + case INSTANCE_WIDETAG: ++res[1]; break; + case FDEFN_WIDETAG: ++res[2]; break; + case SYMBOL_WIDETAG: ++res[3]; break; + } + } + where += object_size(where); + } + where = (lispobj*)TEXT_SPACE_START; + end = text_space_highwatermark; + while (where < end) { + if (widetag_of(where) != FILLER_WIDETAG && immobile_obj_generation(where) == gen) + ++res[4]; + where += object_size(where); + } +#endif + return (res[0] | res[1] | res[2] | res[3] | res[4]) != 0; +} + +// You can call this with 0 and NULL to perform its assertions silently +void gc_gen_report_to_file(int filedes, FILE *file) { #ifdef LISP_FEATURE_X86 int fpu_state[27]; @@ -446,67 +420,158 @@ write_generation_stats(FILE *file) fpu_save(fpu_state); #endif - /* Print the heap stats. */ - fprintf(file, - "Gen Boxed Code Raw LgBox LgCode LgRaw Pin Alloc Waste Trig WP GCs Mem-age\n"); +#define OUTPUT(str, len) \ + {if (file) fwrite(str, 1, len, file); if (filedes>=0) ignore_value(write(filedes, str, len));} - generation_index_t i, begin, end; + /* Print the heap stats. */ + char header1[] = + " Immobile Object Counts\n"; + OUTPUT(header1, sizeof header1-1); + char header2[] = + " Gen GF type fdefn symbol code Boxed Cons Raw Code SmMix Mixed LgRaw LgCode LgMix" + " Waste% Alloc Trig Dirty GCs Mem-age\n"; + OUTPUT(header2, sizeof header2-1); + + generation_index_t gen_num, begin, end; + int immobile_matrix[8][5], have_immobile_obj = 0; + int immobile_totals[5]; + memset(immobile_matrix, 0, sizeof immobile_matrix); + memset(immobile_totals, 0, sizeof immobile_totals); + for (gen_num = 0; gen_num <= 6; ++gen_num) { + if (count_immobile_objects(gen_num, immobile_matrix[gen_num])) + have_immobile_obj |= 1 << gen_num; + immobile_totals[0] += immobile_matrix[gen_num][0]; + immobile_totals[1] += immobile_matrix[gen_num][1]; + immobile_totals[2] += immobile_matrix[gen_num][2]; + immobile_totals[3] += immobile_matrix[gen_num][3]; + immobile_totals[4] += immobile_matrix[gen_num][4]; + } // Print from the lowest gen that has any allocated pages. for (begin = 0; begin <= PSEUDO_STATIC_GENERATION; ++begin) - if (generations[begin].bytes_allocated) break; + if ((have_immobile_obj>>begin)&1 || generations[begin].bytes_allocated) break; // Print up to and including the highest gen that has any allocated pages. for (end = SCRATCH_GENERATION; end >= 0; --end) if (generations[end].bytes_allocated) break; - for (i = begin; i <= end; i++) { + char linebuf[180]; + page_index_t coltot[9]; + uword_t eden_words_allocated = 0; + page_index_t eden_pages = 0; + memset(coltot, 0, sizeof coltot); + for (gen_num = begin; gen_num <= end; gen_num++) { page_index_t page; - // page kinds: small {boxed,code,unboxed}, large {boxed,code,unboxed} - page_index_t pagect[6], pinned_cnt = 0, tot_pages = 0; - + page_index_t pagect[9]; + int *objct = immobile_matrix[gen_num]; memset(pagect, 0, sizeof pagect); + if (gen_num == 0) { // Count the eden pages + for (page = 0; page < next_free_page; page++) + if (page_table[page].gen == 0 && page_table[page].type & THREAD_PAGE_FLAG) { + int column; + switch (page_table[page].type & ~THREAD_PAGE_FLAG) { + case PAGE_TYPE_BOXED: column = 0; break; + case PAGE_TYPE_CONS: column = 1; break; + case PAGE_TYPE_CODE: column = 3; break; + case PAGE_TYPE_MIXED: column = 5; break; + default: lose("Bad eden page subtype: %x\n", page_table[page].type); + } + pagect[column]++; + coltot[column]++; + ++eden_pages; + eden_words_allocated += page_words_used(page); + } + uword_t waste = npage_bytes(eden_pages) - (eden_words_allocated<<WORD_SHIFT); + double pct_waste = eden_pages > 0 ? + (double)waste / (double)npage_bytes(eden_pages) * 100 : 0.0; + if (eden_pages) { + int linelen = snprintf(linebuf, sizeof linebuf, + " E %5d %4d %6d %6d %6d %7"PAGE_INDEX_FMT"%7"PAGE_INDEX_FMT"%14"PAGE_INDEX_FMT + "%14"PAGE_INDEX_FMT + "%28.1f %11"OS_VM_SIZE_FMT"\n", + objct[0], objct[1], objct[2], objct[3], objct[4], + pagect[0], pagect[1], pagect[3], pagect[5], + pct_waste, eden_words_allocated<<WORD_SHIFT); + OUTPUT(linebuf, linelen); + } + memset(pagect, 0, sizeof pagect); + } + uword_t words_allocated = 0; + page_index_t tot_pages = 0; for (page = 0; page < next_free_page; page++) - if (!page_free_p(page) && page_table[page].gen == i) { - int k; - switch (page_table[page].type & PAGE_TYPE_MASK) { - case CODE_PAGE_TYPE: k = 1; break; - case UNBOXED_PAGE_FLAG: k = 2; break; - default: k = 0; break; + if (!page_free_p(page) && page_table[page].gen == gen_num + && !(page_table[page].type & THREAD_PAGE_FLAG)) { + int column; + switch (page_table[page].type & (SINGLE_OBJECT_FLAG|PAGE_TYPE_MASK)) { + case PAGE_TYPE_BOXED: column = 0; break; + case PAGE_TYPE_CONS: column = 1; break; + case PAGE_TYPE_UNBOXED: column = 2; break; + case PAGE_TYPE_CODE: column = 3; break; + case PAGE_TYPE_SMALL_MIXED: column = 4; break; + case PAGE_TYPE_MIXED: column = 5; break; + case SINGLE_OBJECT_FLAG|PAGE_TYPE_UNBOXED: column = 6; break; + case SINGLE_OBJECT_FLAG|PAGE_TYPE_CODE: column = 7; break; + case SINGLE_OBJECT_FLAG|PAGE_TYPE_MIXED: column = 8; break; + default: lose("Invalid page type %#x (p%"PAGE_INDEX_FMT")", page_table[page].type, page); } - if (page_single_obj_p(page)) k += 3; - pagect[k]++; - if (page_table[page].pinned) pinned_cnt++; + pagect[column]++; + coltot[column]++; + ++tot_pages; + words_allocated += page_words_used(page); } - tot_pages = pagect[0] + pagect[1] + pagect[2] - + pagect[3] + pagect[4] + pagect[5]; - struct generation* gen = &generations[i]; - gc_assert(gen->bytes_allocated == count_generation_bytes_allocated(i)); - fprintf(file, - " %d %7"PAGE_INDEX_FMT"%7"PAGE_INDEX_FMT"%7"PAGE_INDEX_FMT - "%7"PAGE_INDEX_FMT"%7"PAGE_INDEX_FMT"%7"PAGE_INDEX_FMT - " %4"PAGE_INDEX_FMT - " %11"OS_VM_SIZE_FMT - " %9"OS_VM_SIZE_FMT - " %11"OS_VM_SIZE_FMT - " %7"PAGE_INDEX_FMT" %3d %7.4f\n", - i, + struct generation* gen = &generations[gen_num]; + if (gen_num == 0) + gc_assert(gen->bytes_allocated == + (words_allocated+eden_words_allocated) << WORD_SHIFT); + else { + gc_assert(gen->bytes_allocated == words_allocated << WORD_SHIFT); + } + page_index_t n_dirty; + count_generation_pages(gen_num, &n_dirty); + uword_t waste = npage_bytes(tot_pages) - (words_allocated<<WORD_SHIFT); + double pct_waste = tot_pages > 0 ? + (double)waste / (double)npage_bytes(tot_pages) * 100 : 0.0; + int linelen = + snprintf(linebuf, sizeof linebuf, + " %d %5d %4d %6d %6d %6d" + "%7"PAGE_INDEX_FMT"%7"PAGE_INDEX_FMT"%7"PAGE_INDEX_FMT"%7"PAGE_INDEX_FMT + "%7"PAGE_INDEX_FMT"%7"PAGE_INDEX_FMT"%7"PAGE_INDEX_FMT"%7"PAGE_INDEX_FMT + "%7"PAGE_INDEX_FMT" %6.1f %11"OS_VM_SIZE_FMT" %11"OS_VM_SIZE_FMT, + gen_num, objct[0], objct[1], objct[2], objct[3], objct[4], pagect[0], pagect[1], pagect[2], pagect[3], pagect[4], pagect[5], - pinned_cnt, - (uintptr_t)gen->bytes_allocated, - (uintptr_t)npage_bytes(tot_pages) - generations[i].bytes_allocated, - (uintptr_t)gen->gc_trigger, - count_generation_pages(i, 0), - gen->num_gc, - generation_average_age(i)); - } - fprintf(file," Total bytes allocated = %13"OS_VM_SIZE_FMT"\n", - (uintptr_t)bytes_allocated); - fprintf(file," Dynamic-space-size bytes = %13"OS_VM_SIZE_FMT"\n", - (uintptr_t)dynamic_space_size); + pagect[6], pagect[7], pagect[8], + pct_waste, words_allocated<<WORD_SHIFT, + (uintptr_t)gen->gc_trigger); + // gen0 pages are never WPed + linelen += snprintf(linebuf+linelen, sizeof linebuf-linelen, + gen_num==0?" -" : " %7"PAGE_INDEX_FMT, n_dirty); + linelen += snprintf(linebuf+linelen, sizeof linebuf-linelen, + " %3d %7.4f\n", gen->num_gc, generation_average_age(gen_num)); + OUTPUT(linebuf, linelen); + } + page_index_t tot_pages = coltot[0] + coltot[1] + coltot[2] + coltot[3] + coltot[4] + + coltot[5] + coltot[6] + coltot[7] + coltot[8]; + uword_t waste = npage_bytes(tot_pages) - bytes_allocated; + double pct_waste = (double)waste / (double)npage_bytes(tot_pages) * 100; + double heap_use_frac = 100 * (double)bytes_allocated / (double)dynamic_space_size; + int *objct = immobile_totals; + int linelen = + snprintf(linebuf, sizeof linebuf, + "Tot %5d %4d %6d %6d %6d" + "%7"PAGE_INDEX_FMT"%7"PAGE_INDEX_FMT"%7"PAGE_INDEX_FMT"%7"PAGE_INDEX_FMT + "%7"PAGE_INDEX_FMT"%7"PAGE_INDEX_FMT"%7"PAGE_INDEX_FMT"%7"PAGE_INDEX_FMT + "%7"PAGE_INDEX_FMT" %6.1f%12"OS_VM_SIZE_FMT + " [%.1f%% of %"OS_VM_SIZE_FMT" max]\n", + objct[0], objct[1], objct[2], objct[3], objct[4], + coltot[0], coltot[1], coltot[2], coltot[3], coltot[4], coltot[5], coltot[6], + coltot[7], coltot[8], pct_waste, + (uintptr_t)bytes_allocated, heap_use_frac, (uintptr_t)dynamic_space_size); + OUTPUT(linebuf, linelen); +#undef OUTPUT #ifdef LISP_FEATURE_X86 fpu_restore(fpu_state); #endif } +void write_generation_stats(FILE *file) { gc_gen_report_to_file(-1, file); } extern void write_heap_exhaustion_report(FILE *file, long available, long requested, @@ -521,7 +586,7 @@ write_heap_exhaustion_report(FILE *file, long available, long requested, fprintf(file, "GC control variables:\n"); fprintf(file, " *GC-INHIBIT* = %s\n *GC-PENDING* = %s\n", read_TLS(GC_INHIBIT,thread)==NIL ? "false" : "true", - (read_TLS(GC_PENDING, thread) == T) ? + (read_TLS(GC_PENDING, thread) == LISP_T) ? "true" : ((read_TLS(GC_PENDING, thread) == NIL) ? "false" : "in progress")); #ifdef LISP_FEATURE_SB_THREAD @@ -573,19 +638,15 @@ report_heap_exhaustion(long available, long requested, struct thread *th) } -#if defined(LISP_FEATURE_X86) -void fast_bzero(void*, size_t); /* in <arch>-assem.S */ -#else -#define fast_bzero(addr, count) memset(addr, 0, count) -#endif - /* Zero the memory at ADDR for LENGTH bytes, but use mmap/munmap instead * of zeroing it ourselves, i.e. in practice give the memory back to the * OS. Generally done after a large GC. */ static void __attribute__((unused)) zero_range_with_mmap(os_vm_address_t addr, os_vm_size_t length) { -#ifdef LISP_FEATURE_LINUX +#ifdef LISP_FEATURE_WIN32 + os_decommit_mem(addr, length); +#elif defined LISP_FEATURE_LINUX // We use MADV_DONTNEED only on Linux due to differing semantics from BSD. // Linux treats it as a demand that the memory be 0-filled, or refreshed // from a file that backs the range. BSD takes it as a hint that you don't @@ -599,17 +660,20 @@ zero_range_with_mmap(os_vm_address_t addr, os_vm_size_t length) { if ((os_vm_address_t)addr >= anon_dynamic_space_start) { if (madvise(addr, length, MADV_DONTNEED) != 0) lose("madvise failed"); - } else -#endif - { - void *new_addr; - os_invalidate(addr, length); - new_addr = os_validate(NOT_MOVABLE, addr, length); - if (new_addr == NULL || new_addr != addr) { - lose("remap_free_pages: page moved, %p ==> %p", - addr, new_addr); - } + } else { // See doc/internals-notes/zero-with-mmap-bug.txt + // Trying to see how often this happens. + // fprintf(stderr, "zero_range_with_mmap: fallback to memset()\n"); + memset(addr, 0, length); + } +#else + void *new_addr; + os_deallocate(addr, length); + new_addr = os_alloc_gc_space(DYNAMIC_CORE_SPACE_ID, NOT_MOVABLE, addr, length); + if (new_addr == NULL || new_addr != addr) { + lose("remap_free_pages: page moved, %p ==> %p", + addr, new_addr); } +#endif } /* @@ -679,91 +743,70 @@ See "Why Nothing Matters: The Impact of Zeroing" */ static inline void zero_pages(page_index_t start, page_index_t end) { if (start <= end) - fast_bzero(page_address(start), npage_bytes(1+end-start)); -} -/* Zero the address range from START up to but not including END */ -static inline void zero_range(char* start, char* end) { - if (start < end) - fast_bzero(start, end-start); +#ifdef LISP_FEATURE_DARWIN_JIT + zero_range_with_mmap(page_address(start), npage_bytes(1+end-start)); +#else + memset(page_address(start), 0, npage_bytes(1+end-start)); +#endif } -// A robustness testing flag: when true, pages claimed for purpose of the current -// GC cycle are prefilled with garbage bytes instead of zeroes. -// This is fine for GC because it always uses memcpy() from the old data. -// Lisp never directly requests unboxed pages, so this is always acceptable -// on unboxed pages. Lisp does directly request pages of code, but the code allocator -// is compatible with the non-prezeroing convention. -// The last case is boxed pages- we can only do this on boxed pages that will be -// consumed by GC and only by GC (i.e. not pages that were either directly -// allocated by lisp, or whose tail could be picked up by lisp) -// This could be made to work for those pages as well if we remember which pages -// haven't been fully used prior to returning to lisp, and then zero-filling -// any unused bytes just in case lisp picks up the remaining part of the page. -char gc_allocate_dirty = 0; /* The generation currently being allocated to. */ static generation_index_t gc_alloc_generation; +__attribute__((unused)) static const char * const page_type_description[8] = + {0, "unboxed", "boxed", "mixed", "sm_mix", "cons", "?", "code"}; /* Zero the pages from START to END (inclusive), except for those - * pages that are known to already zeroed. Mark all pages in the - * ranges as non-zeroed. + * pages which: (a) don't require pre-clearing, or (b) do but are already clear. + * For each page in the range that got cleared right now, change the + * page's need_to_zero flag to 0; otherwise, leave that flag alone. */ -void zero_dirty_pages(page_index_t start, page_index_t end, int page_type) { - page_index_t i, j; - -#ifdef READ_PROTECT_FREE_PAGES - os_protect(page_address(start), npage_bytes(1+end-start), OS_VM_PROT_ALL); +#if defined LISP_FEATURE_RISCV && defined LISP_FEATURE_LINUX // KLUDGE +int mmap_does_not_zero; #endif - // If allocating boxed pages to gen0 (or scratch which becomes gen0) then +void zeroize_pages_if_needed(page_index_t start, page_index_t end, int page_type) { + // If allocating mixed pages to gen0 (or scratch which becomes gen0) then // this allocation is potentially going to be extended by lisp (if it happens to // pick up the tail of the page as its next available region) - // and we really have to zeroize the page. Otherwise, if not boxed or allocating + // and we really have to zeroize the page. Otherwise, if not mixed or allocating // memory that is entirely within GC, then lisp will never use parts of the page. // So we can avoid pre-zeroing all codes pages, all unboxed pages, - // and all boxed pages allocated to gen>=1. + // all strictly boxed pages, and all mixed pages allocated to gen>=1. + + page_index_t i; +#ifdef LISP_FEATURE_DARWIN_JIT + /* Must always zero, as it may need changing the protection bits. */ + boolean any_need_to_zero = 0; + for (i = start; i <= end; i++) any_need_to_zero |= page_need_to_zero(i); + if (any_need_to_zero) { + zero_pages(start, end); + for (i = start; i <= end; i++) set_page_need_to_zero(i, 0); + } +#elif defined LISP_FEATURE_MIPS + /* Technically this case is for "if BACKEND_PAGE_BYTES > GENCGC_CARD_BYTES" + * but #+win32 has that, and works fine because we don't map the core to memory + * from the file directly. The issue is that load_core_bytes() has a larger + * granularity than saving thinks it used, so loading picks up junk from pages + * that are supposedly zeroed. Until I fix it better, just zeroize always. + * Basically we want to decouple the allocator's quantum of GENCGC_PAGE_BYTES + * from the OS's requirement on file mappings. I don't know why rev 2faf4b79a7 + * exposed the bug, but it seems that the older strategy for gc_and_save left + * zeroed pages in exactly the right places either by accident or by design */ + for (i = start; i <= end; i++) { + zero_pages(i, i); + set_page_need_to_zero(i, 0); + } +#else boolean usable_by_lisp = gc_alloc_generation == 0 || (gc_alloc_generation == SCRATCH_GENERATION && from_space == 0); - boolean must_zero = ((page_type == BOXED_PAGE_FLAG && usable_by_lisp) || page_type == 0); - - if (gc_allocate_dirty) { // For testing only -#ifdef LISP_FEATURE_64_BIT - lispobj word = 0x100 | 5; -#else - lispobj word = 0x100 | 2; -#endif - if (must_zero) - for (i = start; i <= end; i++) + if ((page_type == PAGE_TYPE_MIXED && usable_by_lisp) || page_type == 0) { + for (i = start; i <= end; i++) + if (page_need_to_zero(i)) { zero_pages(i, i); - else - for (i = start; i <= end; i++) { - // Write every word with a widetag which if scavenged inavertentiy would call scav_lose(). - // This is purely for testing that the lisp side can deal with unzeroed code pages. - // Non-code unboxed pages won't been seen by lisp allocation routines. - lispobj *where = (lispobj*)page_address(i); - lispobj *limit = (lispobj*)((char*)where + GENCGC_CARD_BYTES); - char* type_name[3] = {"Boxed","Raw ","Code "}; - if (gc_allocate_dirty > 1) - fprintf(stderr, "dirtying g%d %s %d (%p..%p) [%d->%d]\n", - gc_alloc_generation, type_name[page_type-1], - (int)i, where, limit, from_space, new_space); - while (where < limit) *where++ = word; + set_page_need_to_zero(i, 0); } - } else if (must_zero) { - // look for contiguous ranges. This is probably without merit, since bzero - // does not go significantly faster for 2 pages than for 1 page and 1 page. - for (i = start; i <= end; i++) { - if (!page_need_to_zero(i)) continue; - // compute 'j' as the upper exclusive page index bound - for (j = i+1; (j <= end) && page_need_to_zero(j) ; j++) - ; /* empty body */ - zero_pages(i, j-1); - i = j; - } - } - - for (i = start; i <= end; i++) { - set_page_need_to_zero(i, 1); } +#endif } @@ -813,43 +856,54 @@ void zero_dirty_pages(page_index_t start, page_index_t end, int page_type) { * unboxed objects the whole page never needs scavenging or * write-protecting. */ -/* We use three regions for the current newspace generation. */ -struct alloc_region gc_alloc_region[3]; +/* We use five regions for the current newspace generation. */ +struct alloc_region gc_alloc_region[6]; static page_index_t - alloc_start_pages[4], // one each for large, boxed, unboxed, code - gencgc_alloc_start_page; // initializer for the preceding array - + alloc_start_pages[8], // one for each value of PAGE_TYPE_x + gencgc_alloc_start_page, // initializer for the preceding array + max_alloc_start_page; // the largest of any array element + +/* Each 'start_page' informs the region-opening logic where it should + * attempt to continue allocating after closing a region associated + * with a particular page type. We aren't very clever about this - + * either the start_page has space remaining or it doesn't, and when it + * doesn't, then we should hop over *all* allocated pages regardless of + * type that intercede between the page we couldn't use up to next_free_page. + * It's kind of dumb that there is one start_page per type, + * other than it serves its purpose for picking up where it left off + * on a partially full page during GC */ #define RESET_ALLOC_START_PAGES() \ alloc_start_pages[0] = gencgc_alloc_start_page; \ alloc_start_pages[1] = gencgc_alloc_start_page; \ alloc_start_pages[2] = gencgc_alloc_start_page; \ - alloc_start_pages[3] = gencgc_alloc_start_page + alloc_start_pages[3] = gencgc_alloc_start_page; \ + alloc_start_pages[4] = gencgc_alloc_start_page; \ + alloc_start_pages[5] = gencgc_alloc_start_page; \ + alloc_start_pages[6] = gencgc_alloc_start_page; \ + alloc_start_pages[7] = gencgc_alloc_start_page; \ + max_alloc_start_page = gencgc_alloc_start_page; static inline page_index_t -alloc_start_page(int page_type_flag, int large) +get_alloc_start_page(unsigned int page_type) { - if (!(page_type_flag >= 1 && page_type_flag <= 3)) - lose("bad page_type_flag: %d", page_type_flag); - return alloc_start_pages[large ? 0 : page_type_flag]; + if (page_type > 7) lose("bad page_type: %d", page_type); + return alloc_start_pages[page_type]; } static inline void -set_alloc_start_page(int page_type_flag, int large, page_index_t page) +set_alloc_start_page(unsigned int page_type, page_index_t page) { - if (!(page_type_flag >= 1 && page_type_flag <= 3)) - lose("bad page_type_flag: %d", page_type_flag); - alloc_start_pages[large ? 0 : page_type_flag] = page; + if (page_type > 7) lose("bad page_type: %d", page_type); + if (page > max_alloc_start_page) max_alloc_start_page = page; + alloc_start_pages[page_type] = page; } #include "private-cons.inc" -static inline boolean region_closed_p(struct alloc_region* region) { - return !region->end_addr; +static inline boolean __attribute__((unused)) region_closed_p(struct alloc_region* region) { + return !region->start_addr; } -#define ASSERT_REGIONS_CLOSED() \ - gc_assert(!((uintptr_t)boxed_region.end_addr \ - |(uintptr_t)unboxed_region.end_addr \ - |(uintptr_t)code_region.end_addr)) + /* Find a new region with room for at least the given number of bytes. * @@ -874,32 +928,161 @@ static inline boolean region_closed_p(struct alloc_region* region) { * allocation call using the same pages, all the pages in the region * are allocated, although they will initially be empty. */ -static void -gc_alloc_new_region(sword_t nbytes, int page_type_flag, struct alloc_region *alloc_region) + +#ifdef LISP_FEATURE_ALLOCATOR_METRICS +#define INSTRUMENTING(expression, metric) { \ + struct timespec t0, t1; clock_gettime(CLOCK_REALTIME, &t0); expression; \ + clock_gettime(CLOCK_REALTIME, &t1); \ + struct thread* th = get_sb_vm_thread(); \ + th->metric += (t1.tv_sec - t0.tv_sec)*1000000000 + (t1.tv_nsec - t0.tv_nsec); } +#else +#define INSTRUMENTING(expression, metric) expression +#endif + +/* Test whether page 'index' can continue a non-large-object region + * having specified 'gen' and 'type' values. It must not be pinned + * and must be marked but not referenced from the stack */ +static inline boolean +page_extensible_p(page_index_t index, generation_index_t gen, int type) { +#ifdef LISP_FEATURE_BIG_ENDIAN /* TODO: implement this as single comparison */ + int attributes_match = + page_table[index].type == type + && page_table[index].gen == gen + && !gc_page_pins[index]; +#else + // FIXME: "warning: dereferencing type-punned pointer will break strict-aliasing rules" + int attributes_match = + *(int16_t*)&page_table[index].type == ((gen<<8)|type); +#endif +#ifdef LISP_FEATURE_SOFT_CARD_MARKS + return attributes_match && page_cards_all_marked_nonsticky(index); +#else + return attributes_match && !PAGE_WRITEPROTECTED_P(index); +#endif +} + +void gc_heap_exhausted_error_or_lose (sword_t available, sword_t requested) never_returns; + +/* Find a single page for conses or SMALL_MIXED objects. + * CONS differs because: + * - not all GENCGC_PAGE_BYTES of the page can be used. + * - a region can't be extended from one page to the next + * (implied by the preceding restriction). + * SMALL_MIXED is similar to cons, but all bytes of the page can be used + * for storing objects, subject to the non-card-spaning constraint. */ +static page_index_t find_single_page(int page_type, sword_t nbytes, generation_index_t gen) { - page_index_t first_page; - page_index_t last_page; - page_index_t i; - int ret; + page_index_t page = alloc_start_pages[page_type];; + // Compute the max words that could already be used while satisfying the request. + page_words_t usage_allowance = + usage_allowance = GENCGC_PAGE_BYTES/N_WORD_BYTES - (nbytes>>WORD_SHIFT); + if (page_type == PAGE_TYPE_CONS) { + gc_assert(nbytes <= CONS_PAGE_USABLE_BYTES); + usage_allowance = (CONS_SIZE*MAX_CONSES_PER_PAGE) - (nbytes>>WORD_SHIFT); + } + for ( ; page < page_table_pages ; ++page) { + if (page_words_used(page) <= usage_allowance + && (page_free_p(page) || page_extensible_p(page, gen, page_type))) return page; + } + /* Compute the "available" space for the lossage message. This is kept out of the + * search loop because it's needless overhead. Any free page would have been returned, + * so we just have to find the least full page meeting the gen+type criteria */ + sword_t min_used = GENCGC_PAGE_WORDS; + for ( page = alloc_start_pages[page_type]; page < page_table_pages ; ++page) { + if (page_words_used(page) < min_used && page_extensible_p(page, gen, page_type)) + min_used = page_words_used(page); + } + sword_t bytes_avail; + if (page_type == PAGE_TYPE_CONS) { + bytes_avail = CONS_PAGE_USABLE_BYTES - (min_used<<WORD_SHIFT); + /* The sentinel value initially in 'least_words_used' exceeds a cons + * page's capacity, so clip to 0 instead of showing a negative value + * if no page matched on gen+type */ + if (bytes_avail < 0) bytes_avail = 0; + } else { + bytes_avail = GENCGC_PAGE_BYTES - (min_used<<WORD_SHIFT); + } + gc_heap_exhausted_error_or_lose(bytes_avail, nbytes); +} - /* - FSHOW((stderr, - "/alloc_new_region for %d bytes from gen %d\n", - nbytes, gc_alloc_generation)); - */ +/* CONS pages have a subrange (about 1/128th or 1/64th of the page) + * that demands prezeroing, but the bulk of the page does not require zeroing. + * We can't accurately represent the need_to_zero state on a part of the page. + * So if the page is in need_to_zero state, clear that subrange, + * but KEEP the need_to_zero state, because overall it is in that state. */ +static inline void ensure_cons_markbits_clear(page_index_t page) +{ + // If and only if the page was already completely zeroed, skip this + if (page_need_to_zero(page)) { + char *trailer = page_address(page) + CONS_PAGE_USABLE_BYTES; + memset(trailer, 0, GENCGC_PAGE_BYTES - CONS_PAGE_USABLE_BYTES); + } +} + +#if 0 +boolean page_is_zeroed(page_index_t page) +{ + int nwords_per_page = GENCGC_PAGE_BYTES/N_WORD_BYTES; + uword_t *pagebase = (void*)page_address(page); + int i; + for (i=0; i<nwords_per_page; ++i) if (pagebase[i]) return 0; + return 1; +} +#endif +static void* +gc_alloc_new_region(sword_t nbytes, int page_type, struct alloc_region *alloc_region, int unlock) +{ /* Check that the region is in a reset state. */ - gc_assert(region_closed_p(alloc_region)); - ret = thread_mutex_lock(&free_pages_lock); - gc_assert(ret == 0); - first_page = alloc_start_page(page_type_flag, 0); + gc_dcheck(region_closed_p(alloc_region)); + + if (page_type == PAGE_TYPE_CONS || page_type == PAGE_TYPE_SMALL_MIXED) { + // No mutex release, because either this is: + // - not called from Lisp, as in the SMALL_MIXED case + // - called from lisp_alloc() which does its own unlock + gc_dcheck(!unlock); + page_index_t page; + INSTRUMENTING(page = find_single_page(page_type, nbytes, gc_alloc_generation), + et_find_freeish_page); + if (page+1 > next_free_page) next_free_page = page+1; + page_table[page].gen = gc_alloc_generation; + page_table[page].type = OPEN_REGION_PAGE_FLAG | page_type; +#ifdef LISP_FEATURE_DARWIN_JIT + if (!page_words_used(page)) + /* May need to be remapped from PAGE_TYPE_CODE */ + zeroize_pages_if_needed(page, page, page_type); +#elif defined LISP_FEATURE_WIN32 + // don't incur access violations + os_commit_memory(page_address(page), GENCGC_PAGE_BYTES); +#endif + // TODO: move this out of the mutex scope + if (page_type == PAGE_TYPE_CONS && !page_words_used(page)) + ensure_cons_markbits_clear(page); + // Don't need to set the scan_start_offset because free pages have it 0 + // (and each of these page types starts a new contiguous block) + gc_dcheck(page_table[page].scan_start_offset_ == 0); + alloc_region->start_addr = page_address(page) + page_bytes_used(page); + if (page_type == PAGE_TYPE_CONS) { + alloc_region->end_addr = page_address(page) + CONS_PAGE_USABLE_BYTES; + } else { + alloc_region->end_addr = + (char*)ALIGN_DOWN((uword_t)alloc_region->start_addr, GENCGC_CARD_BYTES) + GENCGC_CARD_BYTES; + } + alloc_region->free_pointer = alloc_region->start_addr; + gc_assert(find_page_index(alloc_region->start_addr) == page); + return alloc_region->free_pointer; + } + + page_index_t first_page = get_alloc_start_page(page_type), last_page; + + INSTRUMENTING( last_page = gc_find_freeish_pages(&first_page, nbytes, - ((nbytes >= (sword_t)GENCGC_CARD_BYTES) ? - SINGLE_OBJECT_FLAG : 0) | page_type_flag, - gc_alloc_generation); + ((nbytes >= (sword_t)GENCGC_PAGE_BYTES) ? + SINGLE_OBJECT_FLAG : 0) | page_type, + gc_alloc_generation), + et_find_freeish_page); /* Set up the alloc_region. */ - alloc_region->last_page = last_page; alloc_region->start_addr = page_address(first_page) + page_bytes_used(first_page); alloc_region->free_pointer = alloc_region->start_addr; alloc_region->end_addr = page_address(last_page+1); @@ -909,44 +1092,55 @@ gc_alloc_new_region(sword_t nbytes, int page_type_flag, struct alloc_region *all /* The first page may have already been in use. */ /* If so, just assert that it's consistent, otherwise, set it up. */ - if (page_bytes_used(first_page)) { - gc_assert(page_table[first_page].type == page_type_flag); + if (page_words_used(first_page)) { + gc_assert(page_table[first_page].type == page_type); gc_assert(page_table[first_page].gen == gc_alloc_generation); } else { page_table[first_page].gen = gc_alloc_generation; } - page_table[first_page].type = OPEN_REGION_PAGE_FLAG | page_type_flag; + page_table[first_page].type = OPEN_REGION_PAGE_FLAG | page_type; + page_index_t i; for (i = first_page+1; i <= last_page; i++) { - page_table[i].type = OPEN_REGION_PAGE_FLAG | page_type_flag; + page_table[i].type = OPEN_REGION_PAGE_FLAG | page_type; page_table[i].gen = gc_alloc_generation; set_page_scan_start_offset(i, addr_diff(page_address(i), alloc_region->start_addr)); } - ret = thread_mutex_unlock(&free_pages_lock); - gc_assert(ret == 0); - - /* If the first page was only partial, don't check whether it's - * zeroed (it won't be) and don't zero it (since the parts that - * we're interested in are guaranteed to be zeroed). - */ - if (page_bytes_used(first_page)) { - first_page++; +#ifdef LISP_FEATURE_DARWIN_JIT + if (page_type == PAGE_TYPE_CODE) { + /* Remap before releasing the mutex so that no other thread can manipulate + * this range of code until it has been correctly set up. If page(s) were + * previously utilized for code, this is not necessary, but there's no way + * to know that. If the first page was already in use, remapping would trash + * what's there, so don't do that */ + int remap_from = first_page + (page_words_used(first_page)?1:0); + if (last_page >= remap_from) { + long len = npage_bytes(1+last_page-remap_from); + os_deallocate(page_address(remap_from), len); + mmap(page_address(remap_from), len, + OS_VM_PROT_ALL, MAP_ANON|MAP_PRIVATE|MAP_JIT, -1, 0); + page_index_t p; + // Ensure that zeroize_pages_if_needed() below does ABSOLUTELY NOTHING! + for(p=remap_from; p<=last_page; ++p) set_page_need_to_zero(p,0); + } + } +#elif defined LISP_FEATURE_WIN32 + // don't incur access violations + long commit_from = first_page + (page_words_used(first_page)?1:0); + long len = npage_bytes(1+last_page-commit_from); + os_commit_memory(page_address(commit_from), len); +#endif + if (unlock) { + int __attribute__((unused)) ret = mutex_release(&free_pages_lock); + gc_assert(ret); } - zero_dirty_pages(first_page, last_page, page_type_flag); + // Like above: if first page was in use, don't zeroize + INSTRUMENTING(zeroize_pages_if_needed(first_page+(page_words_used(first_page)?1:0), + last_page, page_type), et_bzeroing); - /* we can do this after releasing free_pages_lock */ - if (gencgc_zero_check) { - lispobj *p; - for (p = alloc_region->start_addr; - (void*)p < alloc_region->end_addr; p++) { - if (*p != 0) { - lose("The new region is not zero at %p (start=%p, end=%p).", - p, alloc_region->start_addr, alloc_region->end_addr); - } - } - } + return alloc_region->free_pointer; } /* The new_object structure holds the page, byte offset, and size of @@ -1000,14 +1194,15 @@ add_new_area(page_index_t first_page, size_t offset, size_t size) size_t new_area_start = npage_bytes(first_page) + offset; int i, c; + if (GC_LOGGING) { + char* base = page_address(first_page) + offset; + fprintf(gc_activitylog(), "enqueue rescan [%p:%p]\n", base, base+size); + } /* Search backwards for a prior area that this follows from. If found this will save adding a new area. */ for (i = new_areas_index-1, c = 0; (i >= 0) && (c < 8); i--, c++) { size_t area_end = npage_bytes(new_areas[i].page) + new_areas[i].offset + new_areas[i].size; - /*FSHOW((stderr, - "/add_new_area S1 %d %d %d %d\n", - i, c, new_area_start, area_end));*/ if (new_area_start == area_end) { new_areas[i].size += size; return; @@ -1017,9 +1212,6 @@ add_new_area(page_index_t first_page, size_t offset, size_t size) new_areas[new_areas_index].page = first_page; new_areas[new_areas_index].offset = offset; new_areas[new_areas_index].size = size; - /*FSHOW((stderr, - "/new_area %d page %d offset %d size %d\n", - new_areas_index, first_page, offset, size));*/ new_areas_index++; } @@ -1033,23 +1225,39 @@ add_new_area(page_index_t first_page, size_t offset, size_t size) * * This is the internal implementation of ensure_region_closed(), * and not to be invoked as the interface to closing a region. + * + * Note that in no case will closing a region alter the need_to_zero bit + * on any page in the region. It is legal to set that bit as late as possible, + * because we only have to know just-in-time - when changing the page + * (at some point later) from FREE to non-free - whether to zeroize it. + * Therefore, we can set the need_to_zero bit only when there is otherwise + * no way to detect that it ever held nonzero data, namely immediately + * before doing reset_page_flags() or setting the words_used to 0. + * Reflecting the words_used into that bit each time we update words_used + * from a region's free pointer would be redundant (newspace scavenging + * can open/close/open/close a region several times on the same page). */ void -gc_close_region(struct alloc_region *alloc_region, int page_type_flag) +gc_close_region(struct alloc_region *alloc_region, int page_type) { page_index_t first_page = find_page_index(alloc_region->start_addr); page_index_t next_page = first_page+1; char *page_base = page_address(first_page); char *free_pointer = alloc_region->free_pointer; +#if defined LISP_FEATURE_SYSTEM_TLABS && defined DEBUG + if (alloc_region == &get_sb_vm_thread()->sys_mixed_tlab || + alloc_region == &get_sb_vm_thread()->sys_cons_tlab) { + char msg[] = "NOTE: closing a system allocation region\n"; + write(2, msg, sizeof msg-1); // signal-safe + } +#endif + // page_bytes_used() can be done without holding a lock. Nothing else // affects the usage on the first page of a region owned by this thread. page_bytes_t orig_first_page_bytes_used = page_bytes_used(first_page); gc_assert(alloc_region->start_addr == page_base + orig_first_page_bytes_used); - int ret = thread_mutex_lock(&free_pages_lock); - gc_assert(ret == 0); - // Mark the region as closed on its first page. page_table[first_page].type &= ~(OPEN_REGION_PAGE_FLAG); @@ -1062,15 +1270,15 @@ gc_close_region(struct alloc_region *alloc_region, int page_type_flag) if (!orig_first_page_bytes_used) gc_assert(page_starts_contiguous_block_p(first_page)); - gc_assert(page_table[first_page].type == page_type_flag); + gc_assert(page_table[first_page].type == page_type); gc_assert(page_table[first_page].gen == gc_alloc_generation); /* Calculate the number of bytes used in this page. This is not * always the number of new bytes, unless it was free. */ os_vm_size_t bytes_used = addr_diff(free_pointer, page_base); boolean more; - if ((more = (bytes_used > GENCGC_CARD_BYTES))) - bytes_used = GENCGC_CARD_BYTES; + if ((more = (bytes_used > GENCGC_PAGE_BYTES))) + bytes_used = GENCGC_PAGE_BYTES; set_page_bytes_used(first_page, bytes_used); /* 'region_size' will be the sum of new bytes consumed by the region, @@ -1081,18 +1289,18 @@ gc_close_region(struct alloc_region *alloc_region, int page_type_flag) /* All the rest of the pages should be accounted for. */ while (more) { gc_assert(page_table[next_page].type == - (OPEN_REGION_PAGE_FLAG | page_type_flag)); + (OPEN_REGION_PAGE_FLAG | page_type)); page_table[next_page].type ^= OPEN_REGION_PAGE_FLAG; - gc_assert(page_bytes_used(next_page) == 0); + gc_assert(page_words_used(next_page) == 0); gc_assert(page_table[next_page].gen == gc_alloc_generation); - page_base += GENCGC_CARD_BYTES; + page_base += GENCGC_PAGE_BYTES; gc_assert(page_scan_start_offset(next_page) == addr_diff(page_base, alloc_region->start_addr)); /* Calculate the number of bytes used in this page. */ bytes_used = addr_diff(free_pointer, page_base); - if ((more = (bytes_used > GENCGC_CARD_BYTES))) - bytes_used = GENCGC_CARD_BYTES; + if ((more = (bytes_used > GENCGC_PAGE_BYTES))) + bytes_used = GENCGC_PAGE_BYTES; set_page_bytes_used(next_page, bytes_used); region_size += bytes_used; @@ -1106,11 +1314,11 @@ gc_close_region(struct alloc_region *alloc_region, int page_type_flag) generations[gc_alloc_generation].bytes_allocated += region_size; /* Set the alloc restart page to the last page of the region. */ - set_alloc_start_page(page_type_flag, 0, next_page-1); + set_alloc_start_page(page_type, next_page-1); /* Add the region to the new_areas if requested. */ - if (BOXED_PAGE_FLAG & page_type_flag) - add_new_area(first_page,orig_first_page_bytes_used, region_size); + if (boxed_type_p(page_type)) + add_new_area(first_page, orig_first_page_bytes_used, region_size); } else if (!orig_first_page_bytes_used) { /* The first page is completely unused. Unallocate it */ @@ -1118,54 +1326,53 @@ gc_close_region(struct alloc_region *alloc_region, int page_type_flag) } /* Unallocate any unused pages. */ - while (next_page <= alloc_region->last_page) { - gc_assert(page_bytes_used(next_page) == 0); + page_index_t region_last_page = find_page_index((char*)alloc_region->end_addr-1); + while (next_page <= region_last_page) { + gc_assert(page_words_used(next_page) == 0); reset_page_flags(next_page); next_page++; } - ret = thread_mutex_unlock(&free_pages_lock); - gc_assert(ret == 0); - - /* alloc_region is per-thread, we're ok to do this unlocked */ gc_set_region_empty(alloc_region); } /* Allocate a possibly large object. */ -void * -gc_alloc_large(sword_t nbytes, int page_type_flag, struct alloc_region *alloc_region) +void *gc_alloc_large(sword_t nbytes, int page_type) { page_index_t first_page, last_page; - int ret; - - ret = thread_mutex_lock(&free_pages_lock); - gc_assert(ret == 0); - - first_page = alloc_start_page(page_type_flag, 1); - // FIXME: really we want to try looking for space following the highest of - // the last page of all other small object regions. That's impossible - there's - // not enough information. At best we can skip some work in only the case where - // the supplied region was the one most recently created. To do this right - // would entail a malloc-like allocator at the page granularity. - if (first_page <= alloc_region->last_page) { - first_page = alloc_region->last_page+1; + // Large BOXED would serve no purpose beyond MIXED, and "small large" is illogical. + if (page_type == PAGE_TYPE_BOXED || page_type == PAGE_TYPE_SMALL_MIXED) + page_type = PAGE_TYPE_MIXED; + + int locked = !gc_active_p; + if (locked) { + int __attribute__((unused)) ret = mutex_acquire(&free_pages_lock); + gc_assert(ret); } + first_page = max_alloc_start_page; + INSTRUMENTING( last_page = gc_find_freeish_pages(&first_page, nbytes, - SINGLE_OBJECT_FLAG | page_type_flag, - gc_alloc_generation); + SINGLE_OBJECT_FLAG | page_type, + gc_alloc_generation), + et_find_freeish_page); - // FIXME: Should this be 1+last_page ? - // (Doesn't matter too much since it'll be skipped on restart if unusable) - set_alloc_start_page(page_type_flag, 1, last_page); + // No need to check whether last_page > old max; it's gotta be. + max_alloc_start_page = last_page; /* Set up the pages. */ page_index_t page; for (page = first_page; page <= last_page; ++page) { /* Large objects don't share pages with other objects. */ - gc_assert(page_bytes_used(page) == 0); - page_table[page].type = SINGLE_OBJECT_FLAG | page_type_flag; + gc_assert(page_words_used(page) == 0); + page_table[page].type = SINGLE_OBJECT_FLAG | page_type; page_table[page].gen = gc_alloc_generation; } + +#ifdef LISP_FEATURE_WIN32 + // don't incur access violations + os_commit_memory(page_address(first_page), npage_bytes(1+last_page-first_page)); +#endif + // Store a filler so that a linear heap walk does not try to examine // these pages cons-by-cons (or whatever they happen to look like). // A concurrent walk would probably crash anyway, and most certainly @@ -1176,42 +1383,51 @@ gc_alloc_large(sword_t nbytes, int page_type_flag, struct alloc_region *alloc_re // Anyway it's best if the new page resembles a valid object ASAP. uword_t nwords = nbytes >> WORD_SHIFT; lispobj* addr = (lispobj*)page_address(first_page); - *addr = (nwords - 1) << N_WIDETAG_BITS | FILLER_WIDETAG; + if (locked) { THREAD_JIT(0); } + *addr = make_filler_header(nwords); + if (locked) { THREAD_JIT(1); } // avoid enabling while GCing os_vm_size_t scan_start_offset = 0; for (page = first_page; page < last_page; ++page) { set_page_scan_start_offset(page, scan_start_offset); - set_page_bytes_used(page, GENCGC_CARD_BYTES); - scan_start_offset += GENCGC_CARD_BYTES; + set_page_bytes_used(page, GENCGC_PAGE_BYTES); + scan_start_offset += GENCGC_PAGE_BYTES; } page_bytes_t final_bytes_used = nbytes - scan_start_offset; - gc_dcheck((nbytes % GENCGC_CARD_BYTES ? nbytes % GENCGC_CARD_BYTES - : GENCGC_CARD_BYTES) == final_bytes_used); + gc_dcheck((nbytes % GENCGC_PAGE_BYTES ? nbytes % GENCGC_PAGE_BYTES + : GENCGC_PAGE_BYTES) == final_bytes_used); set_page_scan_start_offset(last_page, scan_start_offset); set_page_bytes_used(last_page, final_bytes_used); bytes_allocated += nbytes; generations[gc_alloc_generation].bytes_allocated += nbytes; - ret = thread_mutex_unlock(&free_pages_lock); - gc_assert(ret == 0); + if (locked) { + int __attribute__((unused)) ret = mutex_release(&free_pages_lock); + gc_assert(ret); + } + INSTRUMENTING(zeroize_pages_if_needed(first_page, last_page, page_type), et_bzeroing); /* Add the region to the new_areas if requested. */ - if (BOXED_PAGE_FLAG & page_type_flag) - add_new_area(first_page, 0, nbytes); + if (boxed_type_p(page_type)) add_new_area(first_page, 0, nbytes); - zero_dirty_pages(first_page, last_page, page_type_flag); // page may have not needed zeroing, but first word was stored, // turning the putative object temporarily into a page filler object. // Now turn it back into free space. *addr = 0; +#ifdef LISP_FEATURE_DARWIN_JIT + if (page_type == PAGE_TYPE_CODE) { + os_protect(page_address(first_page), npage_bytes(1+last_page-first_page), OS_VM_PROT_ALL); + } +#endif + return addr; } void gc_heap_exhausted_error_or_lose (sword_t available, sword_t requested) { - struct thread *thread = arch_os_get_current_thread(); + struct thread *thread = get_sb_vm_thread(); /* Write basic information before doing anything else: if we don't * call to lisp this is a must, and even if we do there is always * the danger that we bounce back here before the error has been @@ -1225,9 +1441,8 @@ gc_heap_exhausted_error_or_lose (sword_t available, sword_t requested) lose("Heap exhausted, game over."); } else { - /* FIXME: assert free_pages_lock held */ - (void)thread_mutex_unlock(&free_pages_lock); -#if !(defined(LISP_FEATURE_WIN32) && defined(LISP_FEATURE_SB_THREAD)) + (void)mutex_release(&free_pages_lock); +#ifndef LISP_FEATURE_WIN32 gc_assert(get_pseudo_atomic_atomic(thread)); clear_pseudo_atomic_atomic(thread); if (get_pseudo_atomic_interrupted(thread)) @@ -1248,63 +1463,22 @@ gc_heap_exhausted_error_or_lose (sword_t available, sword_t requested) } } -/* Test whether page 'index' can continue a non-large-object region - * having specified 'gen' and 'allocated' values. */ -static inline boolean -page_extensible_p(page_index_t index, generation_index_t gen, int allocated) { -#ifdef LISP_FEATURE_BIG_ENDIAN /* TODO: implement the simpler test */ - /* Counterintuitively, gcc prefers to see sequential tests of the bitfields, - * versus one test "!(p.write_protected | p.pinned)". - * When expressed as separate tests, it figures out that this can be optimized - * as an AND. On the other hand, by attempting to *force* it to do that, - * it shifts each field to the right to line them all up at bit index 0 to - * test that 1 bit, which is a literal rendering of the user-written code. - */ - boolean result = - page_table[index].type == allocated - && page_table[index].gen == gen - && !page_table[index].write_protected - && !page_table[index].pinned; - return result; -#else - /* Test all 4 conditions above as a single comparison against a mask. - * (The C compiler doesn't understand how to do that) - * Any bit that has a 1 in this mask must match the desired input. - * Lisp allocates to generation 0 which is never write-protected, so both - * WP bits should be zero. Newspace is not write-protected during GC, - * however in the case of GC with promotion (raise=1), there may be a page - * in the 'to' generation that is currently un-write-protected but with - * write_protected_cleared flag = 1 because it was at some point WP'ed. - * Those pages are usable, so we do have to mask out the 'cleared' bit. - * - * pin -\ /--- WP - * v v - * #b11111111_10111111 - * ^ ^^^^^ -- type - * WP-clr / - * - * The flags reside at 1 byte prior to 'gen' in the page structure. - */ - return (*(int16_t*)(&page_table[index].gen-1) & 0xFFBF) == ((gen<<8)|allocated); -#endif -} - /* Search for at least nbytes of space, possibly picking up any * remaining space on the tail of a page that was not fully used. * * The found space is guaranteed to be page-aligned if the SINGLE_OBJECT_FLAG - * bit is set in page_type_flag. + * bit is set in page_type. */ page_index_t gc_find_freeish_pages(page_index_t *restart_page_ptr, sword_t nbytes, - int page_type_flag, generation_index_t gen) + int page_type, generation_index_t gen) { page_index_t most_bytes_found_from = 0, most_bytes_found_to = 0; page_index_t first_page, last_page, restart_page = *restart_page_ptr; sword_t nbytes_goal = nbytes; sword_t bytes_found = 0; sword_t most_bytes_found = 0; - int multi_object = !(page_type_flag & SINGLE_OBJECT_FLAG); + int multi_object = !(page_type & SINGLE_OBJECT_FLAG); /* FIXME: assert(free_pages_lock is held); */ if (multi_object) { @@ -1312,29 +1486,29 @@ gc_find_freeish_pages(page_index_t *restart_page_ptr, sword_t nbytes, nbytes_goal = gencgc_alloc_granularity; #if !defined(LISP_FEATURE_64_BIT) // Increase the region size to avoid excessive fragmentation - if (page_type_flag == CODE_PAGE_TYPE && nbytes_goal < 65536) + if (page_type == PAGE_TYPE_CODE && nbytes_goal < 65536) nbytes_goal = 65536; #endif } - page_type_flag &= ~SINGLE_OBJECT_FLAG; + page_type &= ~SINGLE_OBJECT_FLAG; gc_assert(nbytes>=0); first_page = restart_page; while (first_page < page_table_pages) { bytes_found = 0; if (page_free_p(first_page)) { - gc_dcheck(!page_bytes_used(first_page)); - bytes_found = GENCGC_CARD_BYTES; + gc_dcheck(!page_words_used(first_page)); + bytes_found = GENCGC_PAGE_BYTES; } else if (multi_object && // Never return a range starting with a 100% full page - (bytes_found = GENCGC_CARD_BYTES + (bytes_found = GENCGC_PAGE_BYTES - page_bytes_used(first_page)) > 0 && // "extensible" means all PTE fields are compatible - page_extensible_p(first_page, gen, page_type_flag)) { - // XXX: Prefer to start non-code on new pages. - // This is temporary until scavenging of small-object pages - // is made a little more intelligent (work in progress). - if (bytes_found < nbytes && page_type_flag != CODE_PAGE_TYPE) { + page_extensible_p(first_page, gen, page_type)) { + // TODO: Now that BOXED, CONS, and SMALL_MIXED pages exist, investigate + // whether the bias against returning partial pages is still useful. + // It probably isn't. + if (bytes_found < nbytes && !is_code(page_type)) { if (bytes_found > most_bytes_found) most_bytes_found = bytes_found; first_page++; @@ -1344,20 +1518,23 @@ gc_find_freeish_pages(page_index_t *restart_page_ptr, sword_t nbytes, first_page++; continue; } - - gc_dcheck(!page_table[first_page].write_protected); +#ifndef LISP_FEATURE_SOFT_CARD_MARKS + gc_dcheck(!PAGE_WRITEPROTECTED_P(first_page)); +#endif /* page_free_p() can legally be used at index 'page_table_pages' * because the array dimension is 1+page_table_pages */ for (last_page = first_page+1; bytes_found < nbytes_goal && page_free_p(last_page) && last_page < page_table_pages; last_page++) { - /* page_free_p() implies 0 bytes used, thus GENCGC_CARD_BYTES available. + /* page_free_p() implies 0 bytes used, thus GENCGC_PAGE_BYTES available. * It also implies !write_protected, and if the OS's conception were * otherwise, lossage would routinely occur in the fault handler) */ - bytes_found += GENCGC_CARD_BYTES; - gc_dcheck(0 == page_bytes_used(last_page)); - gc_dcheck(!page_table[last_page].write_protected); + bytes_found += GENCGC_PAGE_BYTES; + gc_dcheck(!page_words_used(last_page)); +#ifndef LISP_FEATURE_SOFT_CARD_MARKS + gc_dcheck(!PAGE_WRITEPROTECTED_P(last_page)); +#endif } if (bytes_found > most_bytes_found) { @@ -1383,58 +1560,125 @@ gc_find_freeish_pages(page_index_t *restart_page_ptr, sword_t nbytes, gc_assert(most_bytes_found_to); // most_bytes_found_to is the upper exclusive bound on the found range. // next_free_page is the high water mark of most_bytes_found_to. - if (most_bytes_found_to > next_free_page) { - next_free_page = most_bytes_found_to; - set_alloc_pointer((lispobj)(page_address(next_free_page))); - } + if (most_bytes_found_to > next_free_page) next_free_page = most_bytes_found_to; *restart_page_ptr = most_bytes_found_from; return most_bytes_found_to-1; } -/* Allocate bytes. All the rest of the special-purpose allocation - * functions will eventually call this. +/* Allocate bytes. The fast path of gc_general_alloc() calls this + * when it can't fit in the open region. * This entry point is only for use within the GC itself. * The Lisp region overflow handler either directly calls gc_alloc_large - * or closes and opens a region if the allocation is small */ -void * -gc_alloc_with_region(struct alloc_region *region, sword_t nbytes, int page_type_flag) + * or closes and opens a region if the allocation is small. + * + * There are two general approaches to handling SMALL_MIXED allocations: + * 1. always open the alloc region as whole page, but hack up gc_general_alloc + * to avoid spanning cards in the fast case. + * 2. open the region as one card, and alter the slow case to try consuming + * the next card on the same page if it can. + * Choice 2 is better because choice 1 makes an extra test for page_type + * in each call to gc_general_alloc. + */ +static void *new_region(struct alloc_region* region, sword_t nbytes, int page_type) +{ + ensure_region_closed(region, page_type); + void* new_obj = gc_alloc_new_region(nbytes, page_type, region, 0); + region->free_pointer = (char*)new_obj + nbytes; + gc_assert(region->free_pointer <= region->end_addr); + return new_obj; +} +void *collector_alloc_fallback(struct alloc_region* region, sword_t nbytes, int page_type) { - if (nbytes>=LARGE_OBJECT_SIZE) { - /* If this is a normal GC - as opposed to "final" GC just prior to saving - * a core, then we should never copy a large object (not that that's the best - * strategy always, because it entirely precludes defragmenting those objects). - * But unfortunately we can't assert that only small objects are seen here, - * because genesis does not use large-object pages. So cold-init could fail, - * depending on whether objects in the cold core are sufficiently large that - * they ought to have gone on large object pages if they could have. */ - return gc_alloc_large(nbytes, page_type_flag, region); + /* If this is a normal GC - as opposed to "final" GC just prior to saving + * a core, then we should never copy a large object (not that that's the best + * strategy always, because it entirely precludes defragmenting those objects). + * But unfortunately we can't assert that only small objects are seen here, + * because genesis does not use large-object pages. So cold-init could fail, + * depending on whether objects in the cold core are sufficiently large that + * they ought to have gone on large object pages if they could have. */ + if (nbytes >= LARGE_OBJECT_SIZE) return gc_alloc_large(nbytes, page_type); + + if (page_type != PAGE_TYPE_SMALL_MIXED) return new_region(region, nbytes, page_type); + +#define SMALL_MIXED_NWORDS_LIMIT 10 +#define SMALL_MIXED_NBYTES_LIMIT (SMALL_MIXED_NWORDS_LIMIT * N_WORD_BYTES) + /* We're want to try to place mix raw/tagged slot objects such that they don't span cards. + * There are essentially three cases: + * (1) If the object size exceeds one card, we go straight to the MIXED region. + * (2) If the object size is <= SMALL_MIXED_NWORDS_LIMIT, we will _always_ place it + * on one card. To do that, just align up to the next card or whole page + * if it would span cards based on the current free_pointer. + * This wastes at most SMALL_MIXED_NWORDS_LIMIT - 2 words, per card. + * (3) If the object is larger than that, we will waste at most the threshold number + * of words, but if it would waste more, we use the MIXED region. + * So this case opportunistically uses the subcard region if it can */ + if ((int)nbytes > (int)GENCGC_CARD_BYTES) + return new_region(mixed_region, nbytes, PAGE_TYPE_MIXED); + if (!region->start_addr) { // region is not in an open state + /* Don't try to request too much, because that might return a brand new page, + * when we could have kept going on the same page with small objects. + * Better to put the threshold-exceeding object in the MIXED region */ + int request = nbytes > SMALL_MIXED_NBYTES_LIMIT ? SMALL_MIXED_NBYTES_LIMIT : nbytes; + void* new_obj = gc_alloc_new_region(request, page_type, region, 0); + char* new_freeptr = (char*)new_obj + nbytes; + /* alloc_new_region() ensures that the page it returns has at least 'nbytes' more + * but does *not* ensure that there is that much space below the end of the region. + * This is a little weird, but doing things this way confines the filler insertion + * logic to just here instead of also being also in alloc_new_region. + * You could try to put that logic only in alloc_new_region, but doing that has + * its own down-side: to call alloc_new_region, you first have to close the region, + * which entails extra work in sync'ing the PTE when we don't really need to */ + if (new_freeptr <= (char*)region->end_addr) { + region->free_pointer = new_freeptr; + return new_obj; + } } - - void *new_obj = region->free_pointer; - void *new_free_pointer = (char*)new_obj + nbytes; - /* Check whether there is room in the current alloc region. */ - if (new_free_pointer <= region->end_addr) { - /* If so then allocate from the current alloc region. */ - region->free_pointer = new_free_pointer; + __attribute__((unused)) page_index_t fpi = find_page_index(region->start_addr); + __attribute__((unused)) page_index_t lpi = find_page_index((char*)region->end_addr-1); + gc_assert(fpi == lpi); + gc_assert(page_table[fpi].type & OPEN_REGION_PAGE_FLAG); + // Region is open, but card at free_pointer lacks sufficient space. + // See if there's another card on the same page. + char* page_base = PTR_ALIGN_DOWN(region->start_addr, GENCGC_PAGE_BYTES); + char* next_card = PTR_ALIGN_UP(region->free_pointer, GENCGC_CARD_BYTES); + if (next_card < page_base + GENCGC_PAGE_BYTES) { + int fill_nbytes = next_card - (char*)region->free_pointer; + if (fill_nbytes) { + int fill_nwords = fill_nbytes >> WORD_SHIFT; + /* Object size might strictly exceed SMALL_MIXED_NWORDS_LIMIT. + * Never insert that much filler */ + if (fill_nwords >= SMALL_MIXED_NWORDS_LIMIT) + return new_region(mixed_region, nbytes, PAGE_TYPE_MIXED); + *(lispobj*)region->free_pointer = make_filler_header(fill_nwords); + } + region->free_pointer = next_card; + region->end_addr = next_card + GENCGC_CARD_BYTES; + void* new_obj = next_card; + region->free_pointer = (char*)new_obj + nbytes; + gc_assert(region->free_pointer <= region->end_addr); return new_obj; } - /* Else not enough free space in the current region: retry with a - * new region. */ - ensure_region_closed(region, page_type_flag); - gc_alloc_new_region(nbytes, page_type_flag, region); - new_obj = region->free_pointer; - new_free_pointer = (char*)new_obj + nbytes; - gc_assert(new_free_pointer <= region->end_addr); - region->free_pointer = new_free_pointer; - return new_obj; + /* Now be careful not to waste too much at the end of the page in the following situation: + * page has 20 words more, but we need 24 words. Use the MIXED region because the subcard + * region has room for anywhere from 2 to 10 more objects depending on how small */ + if (nbytes > SMALL_MIXED_NBYTES_LIMIT) page_type = PAGE_TYPE_MIXED, region = mixed_region; + return new_region(region, nbytes, page_type); } + /* Free any trailing pages of the object starting at 'first_page' * that are currently unused due to object shrinkage. * Possibly assign different 'gen' and 'allocated' values. * * maybe_adjust_large_object() specifies 'from_space' for 'new_gen' - * and copy_large_object() specifies 'new_space' + * and copy_potential_large_object() specifies 'new_space' + * + * Note that creating a large object might not affect the 'need_to_zero' + * flag on any of pages consumed (it would if the page type demands prezeroing + * and wasn't zero), but freeing the unused pages of a shrunken object DOES + * set the need_to_zero bit unconditionally. We have to suppose that the object + * constructor wrote bytes on each of its pages, and we don't know whether the tail + * of the object got zeroed versus bashed into FILLER_WIDETAG + random bits. */ static uword_t adjust_obj_ptes(page_index_t first_page, @@ -1444,8 +1688,8 @@ static uword_t adjust_obj_ptes(page_index_t first_page, { int old_allocated = page_table[first_page].type; sword_t remaining_bytes = nwords * N_WORD_BYTES; - page_index_t n_full_pages = nwords / (GENCGC_CARD_BYTES / N_WORD_BYTES); - page_bytes_t excess = remaining_bytes & (GENCGC_CARD_BYTES - 1); + page_index_t n_full_pages = nwords / (GENCGC_PAGE_BYTES / N_WORD_BYTES); + page_bytes_t excess = remaining_bytes & (GENCGC_PAGE_BYTES - 1); // page number of ending page of this object at its new size page_index_t final_page = first_page + (n_full_pages - 1) + (excess != 0); @@ -1455,8 +1699,8 @@ static uword_t adjust_obj_ptes(page_index_t first_page, * (3) the page after that is not part of this object. * If all those conditions are met, this is the easy case, * though we may still have to change the generation and/or page type. */ - if ((!n_full_pages || page_bytes_used(first_page+(n_full_pages-1)) - == GENCGC_CARD_BYTES) && + if ((!n_full_pages || page_words_used(first_page+(n_full_pages-1)) + == GENCGC_PAGE_WORDS) && (!excess || page_bytes_used(final_page) == excess) && page_starts_contiguous_block_p(1+final_page)) { /* The 'if' below has an 'else' which subsumes the 'then' in generality. @@ -1486,16 +1730,15 @@ static uword_t adjust_obj_ptes(page_index_t first_page, gc_assert(page_table[page].type == old_allocated); \ gc_assert(page_table[page].gen == from_space); \ gc_assert(page_scan_start_offset(page) == npage_bytes(page-first_page)); \ - gc_assert(!page_table[page].write_protected); \ page_table[page].gen = new_gen; \ page_table[page].type = new_allocated gc_assert(page_starts_contiguous_block_p(first_page)); page_index_t page = first_page; - while (remaining_bytes > (sword_t)GENCGC_CARD_BYTES) { - gc_assert(page_bytes_used(page) == GENCGC_CARD_BYTES); + while (remaining_bytes > (sword_t)GENCGC_PAGE_BYTES) { + gc_assert(page_words_used(page) == GENCGC_PAGE_WORDS); CHECK_AND_SET_PTE_FIELDS(); - remaining_bytes -= GENCGC_CARD_BYTES; + remaining_bytes -= GENCGC_PAGE_BYTES; page++; } @@ -1514,12 +1757,12 @@ static uword_t adjust_obj_ptes(page_index_t first_page, /* Free unused pages that were originally allocated to this object. */ page++; - while (prev_bytes_used == GENCGC_CARD_BYTES && + while (prev_bytes_used == GENCGC_PAGE_BYTES && page_table[page].gen == from_space && page_table[page].type == old_allocated && page_scan_start_offset(page) == npage_bytes(page - first_page)) { // These pages are part of oldspace, which was un-write-protected. - gc_assert(!page_table[page].write_protected); + gc_assert(page_cards_all_marked_nonsticky(page)); /* Zeroing must have been done before shrinking the object. * (It is strictly necessary for correctness with objects other @@ -1528,7 +1771,7 @@ static uword_t adjust_obj_ptes(page_index_t first_page, #ifdef DEBUG { lispobj* words = (lispobj*)page_address(page); int i; - for(i=0; i<(int)(GENCGC_CARD_BYTES/N_WORD_BYTES); ++i) + for(i=0; i<(int)(GENCGC_PAGE_BYTES/N_WORD_BYTES); ++i) if (words[i]) lose("non-zeroed trailer of shrunken object @ %p", page_address(first_page)); @@ -1536,17 +1779,13 @@ static uword_t adjust_obj_ptes(page_index_t first_page, #endif /* It checks out OK, free the page. */ prev_bytes_used = page_bytes_used(page); - page_table[page].bytes_used_ = 0; // also clears need-to-zero bit + set_page_need_to_zero(page, 1); + set_page_bytes_used(page, 0); reset_page_flags(page); bytes_freed += prev_bytes_used; page++; } - if ((bytes_freed > 0) && gencgc_verbose) { - FSHOW((stderr, - "/adjust_obj_ptes() freed %"OS_VM_SIZE_FMT"\n", - bytes_freed)); - } // If this freed nothing, it ought to have gone through the fast path. gc_assert(bytes_freed != 0); return bytes_freed; @@ -1571,111 +1810,179 @@ static uword_t adjust_obj_ptes(page_index_t first_page, * */ lispobj -copy_large_object(lispobj object, sword_t nwords, int page_type_flag) +copy_potential_large_object(lispobj object, sword_t nwords, + struct alloc_region* region, int page_type) { page_index_t first_page; CHECK_COPY_PRECONDITIONS(object, nwords); - if ((nwords > 1024*1024) && gencgc_verbose) { - FSHOW((stderr, "/copy_large_object: %"OS_VM_SIZE_FMT"\n", nwords)); - } - /* Check whether it's a large object. */ first_page = find_page_index((void *)object); - gc_assert(first_page >= 0); + gc_dcheck(first_page >= 0); os_vm_size_t nbytes = nwords * N_WORD_BYTES; - os_vm_size_t rounded = ALIGN_UP(nbytes, GENCGC_CARD_BYTES); + os_vm_size_t rounded = ALIGN_UP(nbytes, GENCGC_PAGE_BYTES); if (page_single_obj_p(first_page) && (nbytes >= LARGE_OBJECT_SIZE || (rounded - nbytes < rounded / 128))) { + // Large BOXED would serve no purpose beyond MIXED, and "small large" is illogical. + if (page_type == PAGE_TYPE_BOXED || page_type == PAGE_TYPE_SMALL_MIXED) + page_type = PAGE_TYPE_MIXED; os_vm_size_t bytes_freed = adjust_obj_ptes(first_page, nwords, new_space, - SINGLE_OBJECT_FLAG | page_type_flag); + SINGLE_OBJECT_FLAG | page_type); generations[from_space].bytes_allocated -= (bytes_freed + nbytes); generations[new_space].bytes_allocated += nbytes; bytes_allocated -= bytes_freed; /* Add the region to the new_areas if requested. */ - if (page_type_flag & BOXED_PAGE_FLAG) - add_new_area(first_page, 0, nbytes); + gc_in_situ_live_nwords += nbytes>>WORD_SHIFT; + if (boxed_type_p(page_type)) add_new_area(first_page, 0, nbytes); return object; } - return gc_general_copy_object(object, nwords, page_type_flag); + return gc_copy_object(object, nwords, region, page_type); } /* to copy unboxed objects */ lispobj copy_unboxed_object(lispobj object, sword_t nwords) { - return gc_general_copy_object(object, nwords, UNBOXED_PAGE_FLAG); -} - -/* - * weak pointers - */ - -sword_t -scav_weak_pointer(lispobj *where, lispobj __attribute__((unused)) object) -{ - struct weak_pointer * wp = (struct weak_pointer*)where; - - if (!wp->next && weak_pointer_breakable_p(wp)) { - /* All weak pointers refer to objects at least as old as themselves, - * because there is no slot setter for WEAK-POINTER-VALUE. - * (i.e. You can't reference an object that didn't already exist, - * assuming that users don't stuff a new value in via low-level hacks) - * A weak pointer is breakable only if it points to an object in the - * condemned generation, which must be as young as, or younger than - * the weak pointer itself. Per the initial claim, it can't be younger. - * So it must be in the same generation. Therefore, if the pointee - * is condemned, the pointer itself must be condemned. Hence it must - * not be on a write-protected page. Assert this, to be sure. - * (This assertion is compiled out in a normal build, - * so even if incorrect, it should be relatively harmless) - */ - gc_dcheck(!page_table[find_page_index(wp)].write_protected); - add_to_weak_pointer_chain(wp); - } - - /* Do not let GC scavenge the value slot of the weak pointer. - * (That is why it is a weak pointer.) */ - - return WEAK_POINTER_NWORDS; + return gc_copy_object(object, nwords, unboxed_region, PAGE_TYPE_UNBOXED); } -/* a faster version for searching the dynamic space. This will work even - * if the object is in a current allocation region. */ -lispobj * -search_dynamic_space(void *pointer) +/* This may not reliably work for objects in a currently open allocation region, + * because page_words_used() is not sync'ed to the free pointer until closing. + * However it will work reliably for codeblobs, because if you can hold + * a reference to the codeblob, then either you'll find it in the generation 0 + * tree, or else can linearly scan for it in an older generation */ +#include "brothertree.h" +static lispobj dynspace_codeblob_tree_snapshot; // valid only during GC +lispobj *search_dynamic_space(void *pointer) { page_index_t page_index = find_page_index(pointer); - lispobj *start; - /* The address may be invalid, so do some checks. */ - if ((page_index == -1) || page_free_p(page_index)) - return NULL; - start = (lispobj *)page_scan_start(page_index); + /* The address may be invalid, so do some checks. + * page_index -1 is legal, and page_free_p returns true in that case. */ + if (page_free_p(page_index)) return NULL; + int type = page_table[page_index].type & PAGE_TYPE_MASK; + if (type == PAGE_TYPE_CONS) { + int wordindex = ((char*)pointer - page_address(page_index)) >> WORD_SHIFT; + if (wordindex < page_words_used(page_index)) + return (lispobj*)(page_address(page_index) + ((wordindex >> 1) << (1+WORD_SHIFT))); + else + return NULL; + } + // Generation 0 code is in the tree usually - it isn't for objects + // in generation 0 following a non-promotion cycle. + if (type == PAGE_TYPE_CODE && page_table[page_index].gen == 0) { + lispobj tree = dynspace_codeblob_tree_snapshot ? dynspace_codeblob_tree_snapshot : + SYMBOL(DYNSPACE_CODEBLOB_TREE)->value; + lispobj node = brothertree_find_lesseql((uword_t)pointer, tree); + if (node != NIL) { + lispobj *found = (lispobj*)((struct binary_node*)INSTANCE(node))->key; + int widetag = widetag_of(found); + if (widetag != CODE_HEADER_WIDETAG && widetag != FUNCALLABLE_INSTANCE_WIDETAG) + lose("header not OK for code page: @ %p = %"OBJ_FMTX"\n", found, *found); + int nwords = object_size(found); + lispobj *upper_bound = found + nwords; + if (pointer < (void*)upper_bound) return found; + } + } + lispobj *start; + if (type == PAGE_TYPE_SMALL_MIXED) { // find the nearest card boundary below 'pointer' + if ((char*)pointer > page_address(page_index)+page_bytes_used(page_index)) return NULL; + start = (lispobj*)ALIGN_DOWN((uword_t)pointer, GENCGC_CARD_BYTES); + } else { + start = (lispobj *)page_scan_start(page_index); + } return gc_search_space(start, pointer); } -/* Return true if 'addr' has a lowtag and widetag that correspond, - * given that the words at 'addr' are within range for an allocated page. - * 'addr' could be a pointer to random data, and this check is merely - * a heuristic. False positives are possible. */ -static inline boolean plausible_tag_p(lispobj addr) +/* Return true if and only if everything on the specified page is NOT subject + * to evacuation, i.e. either the page is not in 'from_space', or is entirely + * pinned. "Entirely pinned" is predicated on being marked as pinned, + * and satisfying one of two additional criteria: + * 1. the page is a single-object page + * 2. the page contains only code, and all code objects are pinned. + * + * A non-large-object page that is marked "pinned" does not suffice + * to be considered entirely pinned if it contains other than code. + */ +int pin_all_dynamic_space_code; +static inline int immune_set_memberp(page_index_t page) { - if (listp(addr)) - return is_cons_half(CONS(addr)->car) - && is_cons_half(CONS(addr)->cdr); - unsigned char widetag = widetag_of(native_pointer(addr)); - return other_immediate_lowtag_p(widetag) - && lowtag_of(addr) == lowtag_for_widetag[widetag>>2]; + return (page_table[page].gen != from_space) + || (gc_page_pins[page] && + (page_single_obj_p(page) || + (is_code(page_table[page].type) && pin_all_dynamic_space_code))); +} + +// Only a bignum, code blob, or vector could be on a single-object page. +#define potential_largeobj_p(w) \ + (w==BIGNUM_WIDETAG || w==CODE_HEADER_WIDETAG || \ + (w>=SIMPLE_VECTOR_WIDETAG && w < COMPLEX_BASE_STRING_WIDETAG)) + +static inline __attribute__((unused)) +int lowtag_ok_for_page_type(__attribute__((unused)) lispobj ptr, + __attribute__((unused)) int page_type) { + // If the young generation goes to mixed-region, this filter is not valid +#ifdef LISP_FEATURE_USE_CONS_REGION + // This doesn't currently decide on acceptability for code/non-code + if (lowtag_of(ptr) == LIST_POINTER_LOWTAG) { + if (page_type != PAGE_TYPE_CONS) return 0; + } else { + if (page_type == PAGE_TYPE_CONS) return 0; + } +#endif + return 1; } +/* + * We offer many variations on root scanning: + * 1. X86: all refs from them stack are ambiguous, and pin their referent + * if there is one. All refs from registers (interrupt contexts) + * are ambiguous, and similarly pin their referent if there is one. + * Interior pointers are disallowed to anything except code. + * (FIXME: the PC to the jump instruction into an immobile fdefn + * or self-contained trampoline GF - what does it do wrt pinning???) + * + * 2. ARM64: interior code pointers from the stack are ambiguous + * and pin their referent if there is one, + * Non-code references are unambiguous, and do NOT pin their referent. + * Only the call chain is scanned for code pointers. + * Interrupt context registers are unambiguous, and can get + * altered by GC. + * + * 3. PPC64: interior code pointers from the stack are ambiguous roots, + * and pin their referent if there is one. + * FDEFN pointers may be untagged, and are therefore ambiguous. + * They pin their referent if there is one, but only if the reference + * is from a register in an interrupt context, not the control stack. + * (codegen will never spill an untagged fdefn to the stack) + * All other non-code object pointers are unambiguous, and do NOT pin + * their referent from the stack. + * Interrupt context registers are unambiguous and DO pin their referent. + * The entire control stack is scanned for code pointers, thus avoiding + * reliance on a correct backtrace. (I doubt the veracity of all claims + * to the backtrace chain being correct in the presence of interrupts) + * + * 4. All references from the stack are tagged, and precise, and none pin + * their referent. + * Interrupt contexts registers are unambiguous, and do not pin their referent. + * (pertains to any architecture not specifically mentione above) + * + * A single boolean value for GENCGC_IS_PRECISE is inadequate to express + * the possibilities. Anything except case 1 is considered "precise". + * Because of the variations, there are many other #ifdefs surrounding + * the logic pertaining to stack and interrupt context scanning. + * Anyway, the above is the theory, but in practice, we have to treat + * some unambiguous pointers as ambiguous for lack of information + * in conservative_root_p what the intent is. + */ +#define AMBIGUOUS_POINTER 1 #if !GENCGC_IS_PRECISE // Return the starting address of the object containing 'addr' // if and only if the object is one which would be evacuated from 'from_space' @@ -1683,53 +1990,76 @@ static inline boolean plausible_tag_p(lispobj addr) // 'addr_page_index' is the page containing 'addr' and must not be -1. // Return 0 if there is no such object - that is, if addr is past the // end of the used bytes, or its pages are not in 'from_space' etc. -static lispobj* -conservative_root_p(lispobj addr, page_index_t addr_page_index) +static lispobj conservative_root_p(lispobj addr, page_index_t addr_page_index) { /* quick check 1: Address is quite likely to have been invalid. */ struct page* page = &page_table[addr_page_index]; - boolean enforce_lowtag = (page->type & PAGE_TYPE_MASK) != CODE_PAGE_TYPE; + boolean enforce_lowtag = !is_code(page->type); - if ((addr & (GENCGC_CARD_BYTES - 1)) >= page_bytes_used(addr_page_index) || + if ((addr & (GENCGC_PAGE_BYTES - 1)) >= page_bytes_used(addr_page_index) || (!is_lisp_pointer(addr) && enforce_lowtag) || - (compacting_p() && (page->gen != from_space || - (page->pinned && (page->type & SINGLE_OBJECT_FLAG))))) + (compacting_p() && immune_set_memberp(addr_page_index))) return 0; gc_assert(!(page->type & OPEN_REGION_PAGE_FLAG)); - /* quick check 2: Unless the page can hold code, the pointer's lowtag must - * correspond to the widetag of the object. The object header can safely - * be read even if it turns out that the pointer is not valid, - * because the pointer was in bounds for the page. - * Note that this can falsely pass if looking at the interior of an unboxed - * array that masquerades as a Lisp object header by pure luck. - * But if this doesn't pass, there's no point in proceeding to the - * definitive test which involves searching for the containing object. */ - - if (enforce_lowtag) { - if (!plausible_tag_p(addr)) return 0; - /* Don't gc_search_space() more than once for any object. - * Doesn't apply to code since the base address is unknown */ - /* FIXME: for non-compacting GC, either don't do this call at all - * - because it always returns 0 - or actually insert objects - * into the hashtable so that it returns a valid answer */ - if (pinned_p(addr, addr_page_index)) return 0; - } - - /* Filter out anything which can't be a pointer to a Lisp object - * (or, as a special case which also requires pinning, a return - * address referring to something in a code component). This is - * expensive but important, since it vastly reduces the - * probability that random garbage will be bogusly interpreted as - * a pointer which prevents a page from moving. */ - lispobj* object_start = search_dynamic_space((void*)addr); - if (!object_start) return 0; + /* If this page can hold only one object, the test is very simple. + * Code pages allow random interior pointers, but only a correctly + * tagged pointer to the boxed words. Tagged interior pointers to SIMPLE-FUNs + * are just as good as any untagged instruction pointer. */ + if (page_single_obj_p(addr_page_index)) { + lispobj* object_start = page_scan_start(addr_page_index); + int widetag = widetag_of(object_start); + if (instruction_ptr_p((char*)addr, object_start) || + (potential_largeobj_p(widetag) && + // Conveniently all potential largeobjs are OTHER_POINTER + make_lispobj(object_start, OTHER_POINTER_LOWTAG) == addr)) + return make_lispobj(object_start, OTHER_POINTER_LOWTAG); + return 0; + } + + /* For pages of code: + * - we can't enforce a particular lowtag on the pointer. + * - we have to find the object base, because pinning a code object + * pins its embedded simple-funs and vice-versa. + * I don't know what to think about pointing to filler objects. + * It seems like a bad idea, but what if Lisp code does that? + * Can it crash if we free the page? I'll assume we're fine + * unless someone can show otherwise */ + if (is_code(page->type)) { + lispobj* object_start = search_dynamic_space((void*)addr); + /* This search must not fail. We've already verified that the + * pointer is within range for its page. */ + gc_assert(object_start); + switch (widetag_of(object_start)) { + case CODE_HEADER_WIDETAG: + /* If 'addr' points anywhere beyond the boxed words, it's valid + * (i.e. allow it even if an incorrectly tagged pointer to a simple-fun header) + * FIXME: Do we want to allow pointing at the untagged base address too? + * It'll find a key in the codeblob tree, but why would Lisp have the + * untagged pointer and expect it to be a strong reference? */ + if (instruction_ptr_p((void*)addr, object_start) + || addr == make_lispobj(object_start, OTHER_POINTER_LOWTAG)) + return make_lispobj(object_start, OTHER_POINTER_LOWTAG); + return 0; +#ifdef LISP_FEATURE_X86_64 + case FUNCALLABLE_INSTANCE_WIDETAG: + if ((addr >= (uword_t)(object_start+2) && addr < (uword_t)(object_start+4)) + || addr == make_lispobj(object_start, FUN_POINTER_LOWTAG)) + return make_lispobj(object_start, FUN_POINTER_LOWTAG); + return 0; +#endif + } + return 0; + } - /* If the containing object is a code object and 'addr' points - * anywhere beyond the boxed words, - * presume it to be a valid unboxed return address. */ - if (instruction_ptr_p((void*)addr, object_start)) - return object_start; + /* For non-code, the pointer's lowtag and widetag must correspond. + * The putative object header can safely be read even if it turns out + * that the pointer is not valid, because 'addr' was in bounds for the page. + * Note that this can falsely pass if looking at the interior of an unboxed + * array that masquerades as a Lisp object header by random chance. */ + if (widetag_of(native_pointer(addr)) != FILLER_WIDETAG + && lowtag_ok_for_page_type(addr, page->type) + && plausible_tag_p(addr)) return AMBIGUOUS_POINTER; // FIXME: I think there is a window of GC vulnerability regarding FINs // and FDEFNs containing executable bytes. In either case if the only pointer @@ -1737,48 +2067,56 @@ conservative_root_p(lispobj addr, page_index_t addr_page_index) // garbage because there is no _tagged_ pointer to it. // This is an almost impossible situation to arise, but seems worth some study. - /* Large object pages only contain ONE object, and it will never - * be a CONS. However, arrays and bignums can be allocated larger - * than necessary and then shrunk to fit, leaving what look like - * (0 . 0) CONSes at the end. These appear valid to - * properly_tagged_descriptor_p(), so pick them off here. */ - if ((listp(addr) && page_single_obj_p(addr_page_index)) - || !properly_tagged_descriptor_p((void*)addr, object_start)) - return 0; - - return object_start; -} -#elif defined LISP_FEATURE_PPC64 -static inline int untagged_fdefn_p(lispobj addr) { - return ((addr & LOWTAG_MASK) == 0) && widetag_of((lispobj*)addr) == FDEFN_WIDETAG; + return 0; } -/* "Less conservative" than above - only consider code pointers as ambiguous - * roots, not all pointers. Eventually every architecture could use this - * because life is so much easier when on-stack code does not move */ -static lispobj* -conservative_root_p(lispobj addr, page_index_t addr_page_index) +#elif defined LISP_FEATURE_MIPS || defined LISP_FEATURE_PPC64 +/* Consider interior pointers to code as roots, and untagged fdefn pointers. + * But most other pointers are *unambiguous* conservative roots. + * This is not "less conservative" per se, than the non-precise code, + * because it's actually up to the user of this predicate to decide whehther + * the control stack as a whole is scanned for objects to pin. + * The so-called "precise" code should generally NOT scan the stack, + * and not call this on stack words. + * Anyway, this code isn't as performance-critical as the x86 variant, + * so it's not worth trying to optimize out the search for the object */ +static lispobj conservative_root_p(lispobj addr, page_index_t addr_page_index) { struct page* page = &page_table[addr_page_index]; - // We allow ambiguous pointers to code and untagged fdefn pointers. - if (!((page->type & PAGE_TYPE_MASK) == CODE_PAGE_TYPE - || untagged_fdefn_p(addr))) - return 0; - // quick check 1: within from_space and within page usage - if ((addr & (GENCGC_CARD_BYTES - 1)) >= page_bytes_used(addr_page_index) || - (compacting_p() && (page->gen != from_space || - (page->pinned && (page->type & SINGLE_OBJECT_FLAG))))) + // quick check: within from_space and within page usage + if ((addr & (GENCGC_PAGE_BYTES - 1)) >= page_bytes_used(addr_page_index) || + (compacting_p() && immune_set_memberp(addr_page_index))) return 0; gc_assert(!(page->type & OPEN_REGION_PAGE_FLAG)); - // Find the containing object, if any + /* Find the containing object, if any + * This is slightly less quick than could be: if sticky_preserve_pointer() was + * called on the contents of a boxed register, then we know that the value is + * a properly tagged descriptor, and don't really need to "search" for an object. + * (And in fact we should rule out fixnums up front) + * Unfortunately sticky_preserve_pointer() does not inform conservative_root_p() + * whether the pointer is known good. So we need a slightly different interface + * to achieve that extra bit of efficiency */ lispobj* object_start = search_dynamic_space((void*)addr); if (!object_start) return 0; - /* If 'addr' points to object_start exactly or anywhere in - * the boxed words, then it points to the object */ - if ((lispobj*)addr == object_start || instruction_ptr_p((void*)addr, object_start)) - return object_start; + // Untagged fdefn pointer or code pointer: ok + if ((widetag_of(object_start) == FDEFN_WIDETAG && addr == (uword_t)object_start) + || is_code(page->type)) + return make_lispobj(object_start, OTHER_POINTER_LOWTAG); + + /* Take special care not to return fillers. A real-world example: + * - a boxed register contains 0x528b4000 + * - the object formerly at 0x528b4000 is a filler + * - compute_lispobj(0x528b4000) returns 0x528b4000 because LOWTAG_FOR_WIDETAG + * says that FILLER_WIDTAG has a 0 lowtag. + * compute_lispobj simply ORs in the 0 which gives back the original address + * and that of course satisfies the equality test. */ + + // Correctly tagged pointer: ok + if (addr == compute_lispobj(object_start) + && widetag_of(object_start) != FILLER_WIDETAG) + return addr; return 0; } #endif @@ -1791,47 +2129,156 @@ conservative_root_p(lispobj addr, page_index_t addr_page_index) * if this is missed, just may delay the moving of objects to unboxed * pages, and the freeing of pages. */ static void -maybe_adjust_large_object(page_index_t first_page, sword_t nwords) +maybe_adjust_large_object(lispobj* where, page_index_t first_page, sword_t nwords) { - lispobj* where = (lispobj*)page_address(first_page); - int page_type_flag; + int page_type; /* Check whether it's a vector or bignum object. */ + /* There is no difference between MIXED and BOXED for large objects, + * because in any event we'll use the large simple-vector optimization + * for root scavenging if applicable. */ lispobj widetag = widetag_of(where); if (widetag == SIMPLE_VECTOR_WIDETAG) - page_type_flag = SINGLE_OBJECT_FLAG | BOXED_PAGE_FLAG; + page_type = SINGLE_OBJECT_FLAG | PAGE_TYPE_MIXED; +#ifndef LISP_FEATURE_UBSAN else if (specialized_vector_widetag_p(widetag) || widetag == BIGNUM_WIDETAG) - page_type_flag = SINGLE_OBJECT_FLAG | UNBOXED_PAGE_FLAG; + page_type = SINGLE_OBJECT_FLAG | PAGE_TYPE_UNBOXED; +#endif else return; os_vm_size_t bytes_freed = - adjust_obj_ptes(first_page, nwords, from_space, page_type_flag); + adjust_obj_ptes(first_page, nwords, from_space, page_type); generations[from_space].bytes_allocated -= bytes_freed; bytes_allocated -= bytes_freed; } /* After scavenging of the roots is done, we go back to the pinned objects - * and look within them for pointers. While heap_scavenge() could certainly - * do this, it would potentially lead to extra work, since we can't know - * whether any given object has been examined at least once, since there is - * no telltale forwarding-pointer. The easiest thing to do is defer all - * pinned objects to a subsequent pass, as is done here. + * and look within them for pointers. Additionally we delete any keys + * from the list of pins that were not legal object addresses, + * but passed through all the filters in conservative_root_p. */ -static void -scavenge_pinned_ranges() +#define SMALL_MAX_PINS 200 +static uword_t small_pins_vector[SMALL_MAX_PINS]; + +uword_t gc_pinned_nwords; +static void refine_ambiguous_roots() { - int i; + void gc_heapsort_uwords(uword_t*, int); + + int pre_deletion_count = pinned_objects.count; + gc_pin_count = pre_deletion_count; + if (pre_deletion_count == 0) return; + + /* We need a place to sort the keys of pinned_objects. If the key count is small, + * use the small_pins vector; otherwise grab some memory via mmap */ + lispobj* workspace; + if (pre_deletion_count < SMALL_MAX_PINS) { // leave room for sentinel at end + workspace = small_pins_vector; + } else { + pins_alloc_size = ALIGN_UP((pre_deletion_count+1)*N_WORD_BYTES, BACKEND_PAGE_BYTES); + workspace = (lispobj*)os_allocate(pins_alloc_size); + gc_assert(workspace); + } + gc_filtered_pins = workspace; // needed for obliterate_nonpinned_words lispobj key; - for_each_hopscotch_key(i, key, pinned_objects) { - lispobj* obj = native_pointer(key); - lispobj header = *obj; - // Never invoke scavenger on a simple-fun, just code components. - if (is_cons_half(header)) - scavenge(obj, 2); - else if (header_widetag(header) != SIMPLE_FUN_WIDETAG) - scavtab[header_widetag(header)](obj, header); + int count = 0, index; + for_each_hopscotch_key(index, key, pinned_objects) { + gc_assert(is_lisp_pointer(key)); + // Preserve only the object base addresses, including any "false" pointers. + if (listp(key) || widetag_of(native_pointer(key)) != SIMPLE_FUN_WIDETAG) + workspace[count++] = key; } + gc_heapsort_uwords(workspace, count); + /* Algorithm: + * for each group of keys with the same page_scan_start + * - scan the heap at the indicated start address + * - "intersect" the list of objects visited with the list of + * ambiguous roots (this is easy because the keys are sorted) + * - change any missed key to 0 as we go + */ + lispobj *where = 0, // as is tradition + *previous_scan_start = 0; + int removed = 0; + for (index = 0 ; index < count ; ++index) { + lispobj* key = native_pointer(workspace[index]); + lispobj* scan_start = page_scan_start(find_page_index(key)); + if (scan_start != previous_scan_start) where = previous_scan_start = scan_start; + /* Scan forward from 'where'. This does not need a termination test based + * on page_bytes_used because we know that 'key' was in-bounds for its page. + * Therefore at least as many bytes are in use on the page as are needed + * to enclose 'where'. If the next object we would visit is beyond it, + * then we're done; the key was not found */ + while (1) { + if (where < key) { + where += object_size(where); + } else if (where == key) { + break; + } else { // 'where' went past the key, so the key is bad + workspace[index] = 0; + removed = 1; + break; + } + } + } + // Delete any 0s + if (removed) { + int new_index = 0; + for (index = 0 ; index < count; ++index) { + key = workspace[index]; + if (key) workspace[new_index++] = key; + } + gc_assert(new_index < count); + count = new_index; + } + gc_pin_count = count; + if (!(gencgc_verbose & 4)) return; + // Print in multiple columns to fit more on a screen + // and sort like 'ls' (down varying fastest) + char description[24]; + fprintf(stderr, "Sorted pin list (%d):\n", count); + const int ncolumns = 4; + int nrows = ALIGN_UP(count,ncolumns) / ncolumns; + int row, col; + for (row = 0; row < nrows; ++row) { + for (col = 0; col < ncolumns; ++col) { + int index = col * nrows + row; + if (index < count) { + lispobj* obj = native_pointer(workspace[index]); + lispobj word = *obj; + strcpy(description, "cons"); + if (is_header(word)) + snprintf(description, sizeof description, "%s,%ldw", + widetag_names[header_widetag(word)>>2], + (long)object_size(obj)); + fprintf(stderr, " %"OBJ_FMTX": %-24s", (uword_t)obj, description); + } + } + putc('\n', stderr); + } +} + +/* After scavenging of the roots is done, we go back to the pinned objects + * and look within them for pointers. */ +static void +scavenge_pinned_ranges() +{ + int i; + lispobj key; + sword_t nwords = 0; + for (i = 0; i < gc_pin_count; ++i) { + key = gc_filtered_pins[i]; + gc_assert(is_lisp_pointer(key)); + lispobj* obj = native_pointer(key); + if (listp(key)) { + scavenge(obj, 2); + nwords += 2; + } else { + lispobj header = *obj; + nwords += scavtab[header_widetag(header)](obj, header); + } + } + gc_pinned_nwords = nwords; } /* visit_freed_objects() was designed to support post-GC actions such as @@ -1892,34 +2339,66 @@ void visit_freed_objects(char __attribute__((unused)) *start, while (where < end) { lispobj word = *where; if (forwarding_pointer_p(where)) { // live oject + /* CAUTION: This CAN NOT WORK RELIABLY. Due to gc_copy_object_resizing() + * we might compute the wrong size because we take it from the copy. + * Are there other places where we get this wrong??? I sure hope not */ lispobj* fwd_where = native_pointer(forwarding_pointer_value(where)); fprintf(stderr, "%p: -> %p\n", where, fwd_where); - where += OBJECT_SIZE(*fwd_where, fwd_where); + where += object_size(fwd_where); } else { // dead object fprintf(stderr, "%p: %"OBJ_FMTX" %"OBJ_FMTX"\n", where, where[0], where[1]); - if (is_cons_half(word)) { + if (is_header(word)) { + // Do something interesting + where += headerobj_size(where, word); + } else { /* Can't do much useful with conses because often we can't distinguish * filler from data. visit_freed_objects is called on ranges of pages * without regard to whether each intervening page was completely full. * (This is not usually the way, but freeing of pages is slightly - * imprecise in that regard) */ + * imprecise in that regard). + * And it's probably broken, since we leave detritus on code pages */ where += 2; - } else { - // Do something interesting - where += sizetab[header_widetag(word)](where); } } } #endif } -void deposit_filler(uword_t addr, sword_t nbytes) { - gc_assert(nbytes >= 0); - if (nbytes > 0) { - sword_t nwords = nbytes >> WORD_SHIFT; - visit_freed_objects((char*)addr, nbytes); - gc_assert((nwords - 1) <= 0x7FFFFF); - *(lispobj*)addr = (nwords - 1) << N_WIDETAG_BITS | FILLER_WIDETAG; +/* Deposit a FILLER_WIDETAG object covering one or more dead objects. + * If using more than 1 card per page, scavenge_root_gens() is able to scan + * some pages without aligning to object boundaries. For that to work, + * it must not accidentally see a raw word or leftover garbage. + * Note that while CONS and SMALL_MIXED pages never have card-spanning objects, + * deposit_filler() deals with the "mirror image" of the pinned objects, + * hence it might get a card-spanning filler. It has to do something to ensure + * that no card will see garbage if scanned from its base address. + * To achieve that, an extra filler may be needed at the start of any spanned card. + * The sizes of extra fillers don't have to sum up to the total filler size. + * They serve the vital purpose of getting descriptors_scavenge() to skip a + * portion of the card they're on, but those fillers are never visited in a + * heap walk that steps by object from a page's page_scan_start. + * The final filler must be the correct size, so any algorithm that achieves + * the desired end result is OK */ +void deposit_filler(char* from, char* to) { + sword_t nbytes = to - from; + if (!nbytes) return; + gc_assert(nbytes > 0); + sword_t nwords = nbytes >> WORD_SHIFT; + gc_assert((nwords - 1) <= 0x7FFFFF); + page_index_t page = find_page_index(from); + gc_assert(find_page_index(to-1) == page); + *(lispobj*)from = make_filler_header(nwords); + long unsigned last_card; + switch (page_table[page].type) { + case PAGE_TYPE_BOXED: + case PAGE_TYPE_CONS: + case PAGE_TYPE_SMALL_MIXED: + last_card = addr_to_card_index(to-1); + while (addr_to_card_index(from) != last_card) { + from = PTR_ALIGN_DOWN(from, GENCGC_CARD_BYTES) + GENCGC_CARD_BYTES; + nwords = (to - from) >> WORD_SHIFT; + *(lispobj*)from = make_filler_header(nwords); + } } } @@ -1927,49 +2406,11 @@ void deposit_filler(uword_t addr, sword_t nbytes) { * Also ensure that no scan_start_offset points to a page in * oldspace that will be freed. */ -static void -wipe_nonpinned_words() +static void obliterate_nonpinned_words() { - void gc_heapsort_uwords(uword_t*, int); - - if (!pinned_objects.count) - return; - - // Loop over the keys in pinned_objects and pack them densely into - // the same array - pinned_objects.keys[] - but skip any simple-funs. - // Admittedly this is abstraction breakage. - int limit = hopscotch_max_key_index(pinned_objects); - int n_pins = 0, i; - for (i = 0; i <= limit; ++i) { - lispobj key = pinned_objects.keys[i]; - if (key) { - lispobj* obj = native_pointer(key); - // No need to check for is_cons_half() - it will be false - // on a simple-fun header, and that's the correct answer. - if (widetag_of(obj) != SIMPLE_FUN_WIDETAG) - pinned_objects.keys[n_pins++] = (uword_t)obj; - } - } - // Don't touch pinned_objects.count in case the reset function uses it - // to decide how to resize for next use (which it doesn't, but could). - gc_n_stack_pins = n_pins; - // Order by ascending address, stopping short of the sentinel. - gc_heapsort_uwords(pinned_objects.keys, n_pins); -#if 0 - fprintf(stderr, "Sorted pin list (%d):\n", n_pins); - for (i = 0; i < n_pins; ++i) { - lispobj* obj = (lispobj*)pinned_objects.keys[i]; - lispobj word = *obj; - int widetag = header_widetag(word); - if (is_cons_half(word)) - fprintf(stderr, "%p: (cons)\n", obj); - else - fprintf(stderr, "%p: %d words (%s)\n", obj, - (int)sizetab[widetag](obj), widetag_names[widetag>>2]); - } -#endif + if (!gc_pin_count) return; -#define page_base(x) ALIGN_DOWN(x, GENCGC_CARD_BYTES) +#define page_base(x) ALIGN_DOWN(x, GENCGC_PAGE_BYTES) // This macro asserts that space accounting happens exactly // once per affected page (a page with any pins, no matter how many) #define adjust_gen_usage(i) \ @@ -1977,27 +2418,27 @@ wipe_nonpinned_words() bytes_moved += page_bytes_used(i); \ page_table[i].gen = new_space - // Store a sentinel at the end. Even if n_pins = table capacity (unlikely), - // it is safe to write one more word, because the hops[] array immediately - // follows the keys[] array in memory. At worst, 2 elements of hops[] - // are clobbered, which is irrelevant since the table has already been - // rendered unusable by stealing its key array for a different purpose. - pinned_objects.keys[n_pins] = ~(uword_t)0; + lispobj* keys = gc_filtered_pins; + int n_pins = gc_pin_count; + // Store a sentinel at the end. + // It is safe to write one more word than there are pins. + keys[n_pins] = ~(uword_t)0; // Each pinned object begets two ranges of bytes to be turned into filler: // - the range preceding it back to its page start or predecessor object // - the range after it, up to the lesser of page bytes used or successor object // Prime the loop - uword_t fill_from = page_base(pinned_objects.keys[0]); + uword_t fill_from = page_base(keys[0]); os_vm_size_t bytes_moved = 0; // i.e. virtually moved + int i; for (i = 0; i < n_pins; ++i) { - lispobj* obj = (lispobj*)pinned_objects.keys[i]; + lispobj* obj = native_pointer(keys[i]); page_index_t begin_page_index = find_page_index(obj); // Create a filler object occupying space from 'fill_from' up to but - // excluding 'obj'. If obj directly abuts its predecessor then don't. - deposit_filler(fill_from, (uword_t)obj - fill_from); + // excluding 'obj'. + deposit_filler((char*)fill_from, (char*)obj); if (fill_from == page_base((uword_t)obj)) { adjust_gen_usage(begin_page_index); // This pinned object started a new page of pins. @@ -2008,7 +2449,7 @@ wipe_nonpinned_words() // If 'obj' spans pages, move its successive page(s) to newspace and // ensure that those pages' scan_starts point at the same address // that this page's scan start does, which could be this page or earlier. - size_t nwords = OBJECT_SIZE(*obj, obj); + size_t nwords = object_size(obj); uword_t obj_end = (uword_t)(obj + nwords); // non-inclusive address bound page_index_t end_page_index = find_page_index((char*)obj_end - 1); // inclusive bound @@ -2025,37 +2466,66 @@ wipe_nonpinned_words() uword_t obj_end_pageaddr = page_base(obj_end - 1); // See if there's another pinned object on this page. // There is always a next object, due to the sentinel. - if (pinned_objects.keys[i+1] < obj_end_pageaddr + GENCGC_CARD_BYTES) { + if (keys[i+1] < obj_end_pageaddr + GENCGC_PAGE_BYTES) { // Next object starts within the same page. fill_from = obj_end; } else { - // Next pinned object does not start on the same page this obj ends on. - // Any bytes following 'obj' up to its page end are garbage. - uword_t page_end = obj_end_pageaddr + page_bytes_used(end_page_index); - deposit_filler(obj_end, page_end - obj_end); - fill_from = page_base(pinned_objects.keys[i+1]); + /* Next pinned object does not start on the same page this obj ends on. + * Any bytes following 'obj' up to its page end are garbage. + * The reason we don't merely reduce the page_bytes_used is that decreasing + * the grand total bytes allocated had a tendency to delay triggering the + * next GC. This phenomenon was especially bad if the only pinned objects + * were at the start of a page, as it caused the entire rest of the page to + * be unusable. :SMALLOBJ-AUTO-GC-TRIGGER from rev dfddbc8a tests this */ + deposit_filler((char*)obj_end, + (char*)obj_end_pageaddr + page_bytes_used(end_page_index)); + fill_from = page_base(keys[i+1]); } } generations[from_space].bytes_allocated -= bytes_moved; generations[new_space].bytes_allocated += bytes_moved; #undef adjust_gen_usage #undef page_base + if (pins_alloc_size) { + os_deallocate((char*)gc_filtered_pins, pins_alloc_size); + // Traceroot can't use the pinned objects in this case + // But hopefully you're not relying on traceroot + // with thousands of pins. That's not really it's intent + // (which is to find retention due to paths in the heap) + gc_filtered_pins = 0; + gc_pin_count = 0; + pins_alloc_size = 0; + } +} + +int sb_introspect_pinnedp(lispobj obj) { + return hopscotch_containsp(&pinned_objects, obj); } /* Add 'object' to the hashtable, and if the object is a code component, * then also add all of the embedded simple-funs. - * The rationale for the extra work on code components is that without it, - * every test of pinned_p() on an object would have to check if the pointer - * is to a simple-fun - entailing an extra read of the header - and mapping - * to its code component if so. Since more calls to pinned_p occur than to - * pin_object, the extra burden should be on this function. + * It is OK to call this function on an object which is already pinned- + * it will do nothing. + * But it is not OK to call this if the object is not one which merits + * pinning in the first place. i.e. It MUST be an object in from_space + * and moreover must be in the condemned set, which means that it can't + * be a code object if pin_all_dynamic_space_code is 1. + * + * The rationale for doing some extra work on code components is that without it, + * every call to pinned_p() would entail this logic: + * if the object is a simple-fun then + * read the header + * if already forwarded then return "no" + * else go backwards to the code header and test pinned_p(). + * But we can avoid that by making every embedded function pinned + * whenever the containing object is pinned. * Experimentation bears out that this is the better technique. * Also, we wouldn't often expect code components in the collected generation * so the extra work here is quite minimal, even if it can generally add to * the number of keys in the hashtable. */ -static void -pin_object(lispobj object) +#define PAGE_PINNED 0xFF +static void pin_object(lispobj object) { if (!compacting_p()) { gc_mark_obj(object); @@ -2063,65 +2533,47 @@ pin_object(lispobj object) } lispobj* object_start = native_pointer(object); - page_index_t first_page = find_page_index(object_start); - if (!page_single_obj_p(first_page) - && hopscotch_containsp(&pinned_objects, object)) + page_index_t page = find_page_index(object_start); + + /* Large object: the 'pinned' bit in the PTE on the first page should be definitive + * for that object. However, all occupied pages have to marked pinned, + * because move_pinned_pages_to_newspace() looks at pages as if they're independent. + * That seems to be the only place that cares how many pages' pinned bits are affected + * here for large objects, though I do wonder why we can't move the object right now + * and be done with it */ + if (page_single_obj_p(page)) { + if (gc_page_pins[page]) return; + sword_t nwords = object_size(object_start); + maybe_adjust_large_object(object_start, page, nwords); + page_index_t last_page = find_page_index(object_start + nwords - 1); + while (page <= last_page) gc_page_pins[page++] = PAGE_PINNED; return; - - size_t nwords = OBJECT_SIZE(*object_start, object_start); - page_index_t last_page = find_page_index(object_start + nwords - 1); - page_index_t page; - // It would be better if it were possible to touch only the PTE for the - // first page of a large object instead of touching N page table entries. - // I'm not sure how well the rest of GC would handle that. - for (page = first_page; page <= last_page; ++page) { - /* Oldspace pages were unprotected at start of GC. - * Assert this here, because the previous logic used to, - * and page protection bugs are scary */ - gc_assert(!page_table[page].write_protected); - /* Mark the page as containing pinned objects. */ - page_table[page].pinned = 1; } - if (page_single_obj_p(first_page)) { - return maybe_adjust_large_object(first_page, nwords); - } + // Multi-object page (the usual case) - presence in the hash table is the pinned criterion. + // The 'pinned' bit is a coarse-grained test of whether to bother looking in the table. + if (hopscotch_containsp(&pinned_objects, object)) return; hopscotch_insert(&pinned_objects, object, 1); + unsigned int addr_lowpart = object & (GENCGC_PAGE_BYTES-1); + // Divide the page into 8 parts, mark that part pinned + gc_page_pins[page] |= 1 << (addr_lowpart / (GENCGC_PAGE_BYTES/8)); struct code* maybe_code = (struct code*)native_pointer(object); - if (widetag_of(&maybe_code->header) == CODE_HEADER_WIDETAG) { - // Avoid reading the code trailer word until the debug info is set. - // Prior to that being set, the unboxed payload is full of random bytes, - // but neither can here be references to any of its simple-funs from - // other objects until the debug info is filled in. - if (maybe_code->debug_info) - for_each_simple_fun(i, fun, maybe_code, 0, { - hopscotch_insert(&pinned_objects, - make_lispobj(fun, FUN_POINTER_LOWTAG), - 1); - }) - } - - if (lowtag_of(object) == INSTANCE_POINTER_LOWTAG) { - struct instance* instance = (struct instance*)(object - INSTANCE_POINTER_LOWTAG); - lispobj layout = instance_layout((lispobj*)instance); - if (layout && lockfree_list_node_layout_p(LAYOUT(layout))) { - // When pinning a logically deleted lockfree list node, always pin the - // successor too, since the Lisp code will reconstruct the next node's tagged - // pointer from the native pointer. Since we're still in the object pinning phase - // of GC, layouts can't have been forwarded yet. - // Note also that this 'pin' does not need to happen for mark-only GC. - // The pin is from an address perspective, not a liveness perspective, - // because the instance scavenger would correctly trace this reference. - lispobj next = instance->slots[INSTANCE_DATA_START]; - // Be sure to ignore an uninitialized word containing 0. - if (fixnump(next) && next && from_space_p(next | INSTANCE_POINTER_LOWTAG)) - pin_object(next | INSTANCE_POINTER_LOWTAG); - } + // Avoid iterating over embedded simple-funs until the debug info is set. + // Prior to that, the unboxed payload will contain random bytes. + // There can't be references to any of the simple-funs + // until the object is fully constructed. + if (widetag_of(&maybe_code->header) == CODE_HEADER_WIDETAG && maybe_code->debug_info) { + for_each_simple_fun(i, fun, maybe_code, 0, { + hopscotch_insert(&pinned_objects, make_lispobj(fun, FUN_POINTER_LOWTAG), 1); + addr_lowpart = (uword_t)fun & (GENCGC_PAGE_BYTES-1); + gc_page_pins[find_page_index(fun)] |= + 1 << (addr_lowpart / (GENCGC_PAGE_BYTES/8)); + }) } } -#if !GENCGC_IS_PRECISE || defined LISP_FEATURE_PPC64 +#if !GENCGC_IS_PRECISE || defined LISP_FEATURE_MIPS || defined LISP_FEATURE_PPC64 /* Take a possible pointer to a Lisp object and mark its page in the * page_table so that it will not be relocated during a GC. * @@ -2135,157 +2587,179 @@ pin_object(lispobj object) * It is also assumed that the current gc_alloc() region has been * flushed and the tables updated. */ -static boolean NO_SANITIZE_MEMORY -preserve_pointer(void *addr) +static boolean NO_SANITIZE_MEMORY preserve_pointer(uword_t word) { - page_index_t page = find_page_index(addr); +#ifdef LISP_FEATURE_METASPACE + extern lispobj valid_metaspace_ptr_p(void* addr); +#endif + page_index_t page = find_page_index((void*)word); if (page < 0) { // Though immobile_space_preserve_pointer accepts any pointer, // there's a benefit to testing immobile_space_p first // because it's inlined. Either is a no-op if no immobile space. - if (immobile_space_p((lispobj)addr)) - return immobile_space_preserve_pointer(addr); + if (immobile_space_p(word)) + return immobile_space_preserve_pointer((void*)word); +#ifdef LISP_FEATURE_METASPACE + // Treat layout pointers as transparent - it's possible that no pointer + // to a wrapper exists, other than a layout which is in a CPU register. + if (word >= METASPACE_START + && word < READ_ONLY_SPACE_END + && lowtag_of(word) == INSTANCE_POINTER_LOWTAG + && valid_metaspace_ptr_p((void*)word)) { + lispobj wrapper = LAYOUT(word)->friend; + // fprintf(stderr, "stack -> metaspace ptr %p -> %p\n", addr, (void*)wrapper); + preserve_pointer((void*)wrapper); + } +#endif return 0; } - lispobj *object_start = conservative_root_p((lispobj)addr, page); - if (object_start) pin_object(compute_lispobj(object_start)); - return object_start != 0; + lispobj object = conservative_root_p(word, page); + if (!object) return 0; + if (object != AMBIGUOUS_POINTER) { + pin_object(object); + return 1; + } + // It's a non-large non-code ambiguous pointer. + if (compacting_p()) { + if (!hopscotch_containsp(&pinned_objects, word)) { + hopscotch_insert(&pinned_objects, word, 1); + unsigned int addr_lowpart = word & (GENCGC_PAGE_BYTES-1); + // Divide the page into 8 parts, mark that part pinned + gc_page_pins[page] |= 1 << (addr_lowpart / (GENCGC_PAGE_BYTES/8)); + } + return 1; + } + // Mark only: search for the object, because the mark bit is stored + // in the object. Writing to random addresses would be bad. + lispobj* found = search_dynamic_space((void*)word); + if (found) gc_mark_obj(compute_lispobj(found)); + return found != 0; +} +/* Additional logic for soft marks: any word that is potentially a + * tagged pointer to a page being written must preserve the mark regardless + * of what update_writeprotection() thinks. That's because the mark is set + * prior to storing. If GC occurs in between setting the mark and storing, + * then resetting the mark would be wrong if the subsequent store + * creates an old->young pointer. + * Mark stickiness is checked only once per invocation of collect_garbge(), + * so it when scanning interrupt contexts for generation 0 but not higher gens. + * Also note the two scenarios: + * (1) tagged pointer to a large simple-vector, but we scan card-by-card + * for specifically the marked cards. This has to be checked first + * so as not to fail to see subsequent cards if the first is marked. + * (2) tagged pointer to an object that marks only the page containing + * the object base. + * And note a subtle point: only an already-marked card can acquire stick + * status. So we can ignore any unmarked (a/k/a WRITEPROTECTED_P) card + * regardless of a context register pointing to it, because if a mark was not + * stored, then the pointer was not stored. Without examining the next few + * instructions, there's no reason even to suppose that a store occurs. + * It seems like the stop-for-GC handler must be enforcing that GC sees things + * stored in the correct order for out-of-order memory models */ +#ifdef LISP_FEATURE_SOFT_CARD_MARKS +// registers can be wider than words. This could accept uword_t as the arg type +// but I like it to be directly callable with os_context_register. +static void sticky_preserve_pointer(os_context_register_t register_word) +{ + uword_t word = register_word; + if (is_lisp_pointer(word)) { + page_index_t page = find_page_index((void*)word); + if (page >= 0 && page_boxed_p(page) // stores to raw bytes are uninteresting + && (word & (GENCGC_PAGE_BYTES - 1)) < page_bytes_used(page) + && page_table[page].gen != 0 + && lowtag_ok_for_page_type(word, page_table[page].type) + && plausible_tag_p(word)) { // "plausible" is good enough + if (page_single_obj_p(page)) { + /* if 'word' is the correctly-tagged pointer to the base of a SIMPLE-VECTOR, + * then set the sticky mark on every marked page. The only other large + * objects are CODE (writes to which are pseudo-atomic), + * and BIGNUM (which aren't on boxed pages) */ + lispobj* scan_start = page_scan_start(page); + if (widetag_of(scan_start) == SIMPLE_VECTOR_WIDETAG + && (uword_t)word == make_lispobj(scan_start, OTHER_POINTER_LOWTAG)) { + generation_index_t gen = page_table[page].gen; + while (1) { + long card = page_to_card_index(page); + int i; + for(i=0; i<CARDS_PER_PAGE; ++i) + if (gc_card_mark[card+i]==CARD_MARKED) gc_card_mark[card+i]=STICKY_MARK; + if (page_ends_contiguous_block_p(page, gen)) return; + ++page; + } + } + } else if (gc_card_mark[addr_to_card_index((void*)word)] == CARD_MARKED) { + gc_card_mark[addr_to_card_index((void*)word)] = STICKY_MARK; + } + } + } + preserve_pointer(word); } #endif +#endif /* Pin an unambiguous descriptor object which may or may not be a pointer. - * Ignore objects with immediate lowtags */ -static void __attribute__((unused)) pin_exact_root(lispobj obj) + * Ignore immediate objects, and heuristically skip some objects that are + * known to be pinned without looking in pinned_objects. + * pin_object() will always do the right thing and ignore multiple + * calls with the same object in the same collection pass. + */ +static void pin_exact_root(lispobj obj) { + // These tests are performed in approximate order of quickness to check. + + // 1. pointerness if (!is_lisp_pointer(obj)) return; + // 2. If not moving, then pinning is irrelevant. 'obj' is a-priori live given + // the reference from *PINNED-OBJECTS*, and obviously it won't move. + if (!compacting_p()) return; + // 3. If pointing off-heap, why are you pinning? Just ignore it. + // Would this need to do anything if immobile-space were ported + // to the precise GC platforms. FIXME? page_index_t page = find_page_index((void*)obj); if (page < 0) return; + // 4. Ignore if not in the condemned set. + if (immune_set_memberp(page)) return; - /* If we're in precise gencgc (non-x86oid as of this writing) then - * we are only called on valid object pointers in the first place, - * so we just have to do a bounds-check against the heap, a - * generation check, and the already-pinned check. */ - if (compacting_p() && (page_table[page].gen != from_space || - (page_single_obj_p(page) && - page_table[page].pinned))) - return; + // Never try to pin an interior pointer - always use base pointers. lispobj *object_start = native_pointer(obj); switch (widetag_of(object_start)) { case SIMPLE_FUN_WIDETAG: #ifdef RETURN_PC_WIDETAG case RETURN_PC_WIDETAG: #endif - object_start = fun_code_header(object_start); + obj = make_lispobj(fun_code_header(object_start), OTHER_POINTER_LOWTAG); } - pin_object(compute_lispobj(object_start)); + pin_object(obj); } -#define IN_REGION_P(a,kind) (kind##_region.start_addr<=a && a<=kind##_region.free_pointer) -#define IN_BOXED_REGION_P(a) IN_REGION_P(a,boxed)||IN_REGION_P(a,code) - -/* If the given page is not write-protected, then scan it for pointers - * to younger generations or the top temp. generation, if no - * suspicious pointers are found then the page is write-protected. - * - * Care is taken to check for pointers to any open allocation regions, - * which by design contain younger objects. - * - * We return 1 if the page was write-protected, else 0. - * - * Note that because of the existence of some words which have fixnum lowtag - * but are actually pointers, you might think it would be possible for this - * function to go wrong, protecting a page that contains old->young pointers. - * Indeed the edge cases are rare enough not to have manifested ever, - * as far anyone knows. - * - * Suspect A is CLOSURE-FUN, which is a fixnum (on x86) which when treated - * as a pointer indicates the entry point to call. Its function can never - * be an object younger than itself. (An invariant of any immutable object) - * - * Suspect B is FDEFN-RAW-ADDRESS. This is a problem, but only under worst-case - * assumptions. Previous remarks here mentioned pinning and/or absence of calls - * to update_page_write_prot(). That explanation was flawed, as is almost - * anything in GC comments mentioning the obsolete pinning code. - * See 'doc/internals-notes/fdefn-gc-safety' for execution schedules - * that lead to invariant loss. - */ -static int -update_page_write_prot(page_index_t page) +/* Return true if 'ptr' is OK to be on a write-protected page + * of an object in 'gen'. That is, if the pointer does not point to a younger object. + * Note: 'ptr' is _sometimes_ an ambiguous pointer - we do not utilize the layout bitmap + * when scanning instances for pointers, so we will occasionally see a raw word for 'ptr'. + * Also, 'ptr might not have a lowtag (such as lockfree list node successor), */ +static boolean ptr_ok_to_writeprotect(lispobj ptr, generation_index_t gen) { - generation_index_t gen = page_table[page].gen; - sword_t j; - int wp_it = 1; - lispobj *page_addr = (lispobj*)page_address(page); - sword_t num_words = page_bytes_used(page) / N_WORD_BYTES; + page_index_t index; + lispobj __attribute__((unused)) header; - /* Shouldn't be a free page. */ - gc_dcheck(!page_free_p(page)); // Implied by the next assertion - gc_assert(page_bytes_used(page) != 0); - - if (!ENABLE_PAGE_PROTECTION) return 0; - - /* Skip if it's unboxed, already write-protected, or pinned */ - /* The 'pinned' check is sort of bogus but sort of necessary, - * but doesn't completely fix the problem that it tries to, which is - * passing a memory address to the OS for it to write into. - * An object on a never-written protected page would still fail. - * It's probably rare to pass boxed pages to the OS, but it could be - * to read fixnums into a simple-vector. - * If we had soft write protection (mark bits) instead of physical - * protection, then we could/would protect pinned pages. - * (See git rev 216e37a316) */ - if (page_table[page].write_protected || !page_boxed_p(page) || - page_table[page].pinned) - return (0); - - /* Scan the page for pointers to younger generations or the - * temp generation, which is numerically 7 but logically younger */ - - /* This is conservative: any word satisfying is_lisp_pointer() is - * assumed to be a pointer. To do otherwise would require a family - * of scavenge-like functions. */ - for (j = 0; j < num_words; j++) { - void *ptr; - page_index_t index; - lispobj __attribute__((unused)) header; - - lispobj word = page_addr[j]; - if (is_lisp_pointer(word)) - ptr = (void*)word; -#ifdef LISP_FEATURE_COMPACT_INSTANCE_HEADER - else if (lowtag_of(word>>32)==INSTANCE_POINTER_LOWTAG && - (header_widetag(word)==INSTANCE_WIDETAG|| - header_widetag(word)==FUNCALLABLE_INSTANCE_WIDETAG)) { - ptr = (void*)(word >> 32); - } -#endif -#ifdef LISP_FEATURE_UNTAGGED_FDEFNS - else if (!(word & LOWTAG_MASK) && (find_page_index((void*)word) >= 0) - && widetag_of((lispobj*)word) == FDEFN_WIDETAG) { - ptr = (void*)word; - } -#endif - else - continue; - - /* Check that it's in the dynamic space */ - if ((index = find_page_index(ptr)) != -1) { + /* Check that it's in the dynamic space */ + if ((index = find_page_index((void*)ptr)) != -1) { int pointee_gen = page_table[index].gen; if (/* Does it point to a younger or the temp. generation? */ (pointee_gen < gen || pointee_gen == SCRATCH_GENERATION) && - - /* and an in-use part of the page? */ - (((lispobj)ptr & (GENCGC_CARD_BYTES-1)) < page_bytes_used(index) || - ((page_table[index].type & OPEN_REGION_PAGE_FLAG) - && (IN_BOXED_REGION_P(ptr) || IN_REGION_P(ptr,unboxed))))) { - wp_it = 0; - break; - } + /* and an in-use part of the page? + * Formerly this examined the bounds of each open region, + * but that is extra work with little benefit. It is faster + * to treat all of any page with an open region as in-use. + * It will self-correct when the region gets closed */ + ((page_table[index].type & OPEN_REGION_PAGE_FLAG) + || (ptr & (GENCGC_PAGE_BYTES-1)) < page_bytes_used(index))) + return 0; } #ifdef LISP_FEATURE_IMMOBILE_SPACE - else if (immobile_space_p((lispobj)ptr) && - other_immediate_lowtag_p(header = *native_pointer((lispobj)ptr))) { + else if (immobile_space_p(ptr) && + other_immediate_lowtag_p(header = *native_pointer(ptr))) { // This is *possibly* a pointer to an object in immobile space, // given that above two conditions were satisfied. // But unlike in the dynamic space case, we need to read a byte @@ -2296,8 +2770,8 @@ update_page_write_prot(page_index_t page) int pointee_gen = gen; // Make comparison fail if we fall through switch (header_widetag(header)) { case SIMPLE_FUN_WIDETAG: - if (functionp((lispobj)ptr)) { - lispobj* code = fun_code_header(FUNCTION((lispobj)ptr)); + if (functionp(ptr)) { + lispobj* code = fun_code_header(FUNCTION(ptr)); // This is a heuristic, since we're not actually looking for // an object boundary. Precise scanning of 'page' would obviate // the guard conditions here. @@ -2307,38 +2781,180 @@ update_page_write_prot(page_index_t page) } break; default: - pointee_gen = immobile_obj_generation(native_pointer((lispobj)ptr)); + pointee_gen = immobile_obj_generation(native_pointer(ptr)); } // A bogus generation number implies a not-really-pointer, // but it won't cause misbehavior. if (pointee_gen < gen || pointee_gen == SCRATCH_GENERATION) { - wp_it = 0; - break; + return 0; + } + } +#endif + return 1; +} + +#ifndef LISP_FEATURE_SOFT_CARD_MARKS +static inline void protect_page(void* page_addr) +{ + os_protect((void *)page_addr, GENCGC_PAGE_BYTES, OS_VM_PROT_JIT_READ); + gc_card_mark[addr_to_card_index(page_addr)] = CARD_UNMARKED; +} +#endif + +#define LOCKFREE_LIST_NEXT(x) ((struct instance*)x)->slots[INSTANCE_DATA_START] + +/* Helper function for update_writeprotection. + * If the [where,limit) contain an old->young pointer, then return + * the address - or approximate address - containing such pointer. + * The return value is used as a boolean, but if debugging, you might + * want to see the address */ +static lispobj* range_dirty_p(lispobj* where, lispobj* limit, generation_index_t gen) +{ + sword_t nwords; + for ( ; where < limit ; where += nwords ) { + lispobj word = *where; + if (is_cons_half(word)) { + if (is_lisp_pointer(word) && !ptr_ok_to_writeprotect(word, gen)) return where; + word = where[1]; + if (is_lisp_pointer(word) && !ptr_ok_to_writeprotect(word, gen)) return where; + nwords = 2; + continue; + } + int widetag = widetag_of(where); + gc_dcheck(widetag !== CODE_HEADER_WIDETAG); // This can't be called on a code page + nwords = sizetab[widetag](where); + if (leaf_obj_widetag_p(widetag)) continue; // Do nothing +#ifdef LISP_FEATURE_COMPACT_INSTANCE_HEADER + if (instanceoid_widetag_p(widetag)) { + // instance_layout works on funcallable or regular instances + // and we have to specially check it because it's in the upper + // bytes of the 0th word. + lispobj layout = instance_layout(where); + if (layout) { + if (!ptr_ok_to_writeprotect(layout, gen)) return where; + if (lockfree_list_node_layout_p(LAYOUT(layout)) && + !ptr_ok_to_writeprotect(LOCKFREE_LIST_NEXT(where), gen)) + return where; } } +#else + if (widetag == INSTANCE_WIDETAG) { + // instance_layout works only on regular instances, + // we don't have to treat it specially but we do have to + // check for lockfree list nodes. + lispobj layout = instance_layout(where); + if (layout && lockfree_list_node_layout_p(LAYOUT(layout)) && + !ptr_ok_to_writeprotect(LOCKFREE_LIST_NEXT(where), gen)) + return where; + } #endif + // Scan all the rest of the words even if some of them are raw bits. + // At worst this overestimates the set of pointer words. + sword_t index; + for (index=1; index<nwords; ++index) + if (is_lisp_pointer(where[index]) && !ptr_ok_to_writeprotect(where[index], gen)) + return where; } + return 0; +} + +/* Given a range of pages at least one of which is not WPed (logically or physically, + * depending on SOFT_CARD_MARKS), scan all those pages for pointers to younger generations. + * If no such pointers are found, then write-protect the range. + * + * Care is taken to check for pointers to any open allocation regions, + * which by design contain younger objects. + * + * If we find a word which is a witness for the inability to apply write-protection, + * then return the address of the object containing the witness pointer. + * Otherwise return 0. The word address is just for debugging; there are cases + * where we don't apply write protectection, but nonetheless return 0. + * + * This function is still buggy, but not in a fatal way. + * The issue is that for any kind of weak object - hash-table vector, + * weak pointer, or weak simple-vector, we skip scavenging the object + * which might leave some pointers to younger generation objects + * which will later be smashed when processing weak objects. + * That is, the referent is non-live. But when we scanned this page range, + * it looks like it still had the pointer to the younger object. + * To get this really right, we would have to wait until after weak objects + * have been processed. + * It may or may not be possible to get verify_range to croak + * about suboptimal application of WP. Possibly not, because of the hack + * for pinned pages without soft card marking (which won't WP). + * + * See also 'doc/internals-notes/fdefn-gc-safety' for execution schedules + * that lead to invariant loss with FDEFNs. This might not be a problem + * in practice. At least it seems like it never has been. + */ +static lispobj* +update_writeprotection(page_index_t first_page, page_index_t last_page, + lispobj* where, lispobj* limit) +{ + /* Shouldn't be a free page. */ + gc_dcheck(!page_free_p(first_page)); // Implied by the next assertion + gc_assert(page_words_used(first_page) != 0); + + if (!ENABLE_PAGE_PROTECTION) return 0; + if (!page_boxed_p(first_page)) return 0; + + page_index_t page; +#ifdef LISP_FEATURE_SOFT_CARD_MARKS + /* If any page is referenced from the stack (mark byte = 2), then we're + * can not apply protection even if we see no witness, because the + * absence of synchronization between mutator and GC means that the next + * instruction issued when the mutator resumes might create the witness, + * and it thinks it already marked a card */ + for (page = first_page; page <= last_page; ++page) + if (cardseq_any_sticky_mark(page_to_card_index(page))) return 0; +#else + /* Skip if any page is pinned. + * The 'pinned' check is sort of bogus but sort of necessary, + * but doesn't completely fix the problem that it tries to, which is + * passing a memory address to the OS for it to write into. + * An object on a never-written protected page would still fail. + * It's probably rare to pass boxed pages to the OS, but it could be + * to read fixnums into a simple-vector. */ + for (page = first_page; page <= last_page; ++page) + if (gc_page_pins[page]) return 0; +#endif - if (wp_it == 1) - protect_page(page_addr, page); + /* Now we attempt to find any 1 "witness" that the pages should NOT be protected. + * If such witness is found, then return without doing anything, otherwise + * apply protection to the range. */ + lispobj* witness = range_dirty_p(where, limit, page_table[first_page].gen); + if (witness) return witness; - return (wp_it); + for (page = first_page; page <= last_page; ++page) { +#ifdef LISP_FEATURE_SOFT_CARD_MARKS + // Don't worry, the cards are all clean - if any card mark was sticky, + // then we would have bailed out as the first thing (way up above). + assign_page_card_marks(page, CARD_UNMARKED); +#else + // Try to avoid a system call + if (!PAGE_WRITEPROTECTED_P(page)) protect_page(page_address(page)); +#endif + } + return 0; } -/* Is this page holding a normal (non-weak, non-hashtable) large-object - * simple-vector? */ -static inline boolean large_simple_vector_p(page_index_t page) { - if (!page_single_obj_p(page)) - return 0; +/* Decide if this single-object page holds a normal simple-vector. + * "Normal" now includes non-weak address-insensitive k/v vectors */ +static inline boolean large_scannable_vector_p(page_index_t page) { lispobj header = *(lispobj *)page_address(page); - // For hash-table vectors which are neither weak nor address-sensitive, - // it certainly would be possible to treat the vector as VectorNormal, - // though we'd lose out on the optimization that scans only below the - // high-water mark which is in general a good thing. Perhaps if the - // ratio of HWM to total size warrants it, we should prefer to use the - // large_simple_vector optimization instead. - return header_widetag(header) == SIMPLE_VECTOR_WIDETAG && - is_vector_subtype(header, VectorNormal); + if (header_widetag(header) == SIMPLE_VECTOR_WIDETAG) { + int mask = (flag_VectorWeak | flag_VectorAddrHashing) << ARRAY_FLAGS_POSITION; + if (header & mask) return 0; + if (vector_flagp(header, VectorHashing)) { + lispobj* data = ((struct vector*)page_address(page))->data; + // If not very full, use the normal path. + // The exact boundary here doesn't matter too much. + if (KV_PAIRS_HIGH_WATER_MARK(data) < (int)(GENCGC_PAGE_BYTES/N_WORD_BYTES)) + return 0; + } + return 1; + } + return 0; } /* Attempt to re-protect code from first_page to last_page inclusive. @@ -2353,112 +2969,239 @@ update_code_writeprotection(page_index_t first_page, page_index_t last_page, if (!ENABLE_PAGE_PROTECTION) return; page_index_t i; for (i=first_page+1; i <= last_page; ++i) // last_page is inclusive - gc_assert((page_table[i].type & PAGE_TYPE_MASK) == CODE_PAGE_TYPE); + gc_assert(is_code(page_table[i].type)); lispobj* where = start; - for (; where < limit; where += sizetab[widetag_of(where)](where)) { + for (; where < limit; where += headerobj_size(where)) { switch (widetag_of(where)) { case CODE_HEADER_WIDETAG: if (header_rememberedp(*where)) return; break; + case FUNCALLABLE_INSTANCE_WIDETAG: + if (range_dirty_p(where, where+headerobj_size(where), page_table[first_page].gen)) + return; + break; } } - for (i = first_page; i <= last_page; i++) - page_table[i].write_protected = 1; + for (i = first_page; i <= last_page; i++) assign_page_card_marks(i, CARD_UNMARKED); } -/* Scavenge all generations from FROM to TO, inclusive, except for - * new_space which needs special handling, as new objects may be - * added which are not checked here - use scavenge_newspace generation. +#ifdef LISP_FEATURE_SOFT_CARD_MARKS +# define card_stickymarked_p(x) (gc_card_mark[x] == STICKY_MARK) +#endif +extern int descriptors_scavenge(lispobj *, lispobj*, generation_index_t, int); +int root_boxed_words_scanned, root_vector_words_scanned, root_mixed_words_scanned; + +/* Special treatment for strictly boxed pages improves on the general case as follows: + * - It can skip determining the extent of the contiguous block up front, + * instead just blasting through the cards as it sees them. + * - If only a subset of cards in a contiguous block are dirty, the scan + * can be restricted to that subset. We don't need to align at object boundaries. + * - It is not necessary to invoke a scavenge method specific to each object type. + * - new write-protection status can be recomputed as we go. + * This combination of aspects will be especially beneficial if cards are + * are much smaller than they currently are (like 1K) + + * We have two choices for object traversal: walk object-by-object, + * or card-by-card just blasting through the words looking for pointers. + * But the latter can fail on a card-spanning object if care is not taken. + * Example: Suppose the card size is 1K, and an instance has 200 slots. + * The instance consumes around 1600 bytes (@ 8 bytes/word), which conceivably + * could use 3 cards: header + 10 slots on the end of the first card, + * 128 slots on the next, and the remainder on the final card. The soft write + * barrier marks only the card with the header, so we don't know exactly + * which card contains a modified pointer. Therefore, in all cases when using + * card-by-card scan that disregards object boundaries, we have to assume + * that 1 card beyond any marked card contains part of a marked object, + * if that next card has the same scan start as its predecessor. + * But where to stop scanning under this assumption? We shouldn't assume + * that any marked card implies scanning an unbounded number of cards. + * Therefore, a big instance should not be put on a purely boxed card. + * (And granted, a massive instance will go on single-object pages.) + * The other purely boxed objects are cons-sized, so they don't have a problem. + * And (SETF SVREF) does mark an exact card, so it's all good. + * Also, the hardware write barrier does not have this concern. + */ +#define WORDS_PER_CARD (GENCGC_CARD_BYTES/N_WORD_BYTES) +static page_index_t scan_boxed_root_cards_spanning(page_index_t page, generation_index_t gen) +{ + __attribute__((unused)) int prev_marked = 0; + do { + lispobj* start = (void*)page_address(page); + lispobj* limit = start + page_words_used(page); +#ifdef LISP_FEATURE_SOFT_CARD_MARKS + long card = addr_to_card_index(start); + /* Cards can change from marked to unmarked (just like with physical protection), + * but also unmarked to marked, if transferring the card mark from the object's + * header card to a cell in that object on a later card. + * Lisp is given leeway because marking the header is easier. So the + * algorithm accepts either way on input, but makes its output canonical. + * (similar in spirit to Postel's Law) */ + if (prev_marked || cardseq_any_marked(card)) { + if (GC_LOGGING) fprintf(gc_activitylog(), "scan_roots spanning %p\n", page_address(page)); + int j; + for (j=0; j<CARDS_PER_PAGE; ++j, ++card, start += WORDS_PER_CARD) { + int marked = card_dirtyp(card); + if (marked || prev_marked) { + lispobj* end = start + WORDS_PER_CARD; + if (end > limit) end = limit; + int dirty = descriptors_scavenge(start, end, gen, card_stickymarked_p(card)); + root_boxed_words_scanned += end - start; + gc_card_mark[card] = + (gc_card_mark[card] != STICKY_MARK) ? (dirty ? CARD_MARKED : CARD_UNMARKED) : + STICKY_MARK; + prev_marked = marked; + } + } + } +#else + if (!PAGE_WRITEPROTECTED_P(page)) { + int dirty = descriptors_scavenge(start, limit, gen, 0); + if (ENABLE_PAGE_PROTECTION && !dirty) protect_page(start); + } +#endif + ++page; + } while (!page_ends_contiguous_block_p(page-1, gen)); + return page; +} + +/* Large simple-vectors and pages of conses are even easier than strictly boxed root pages + * because individual cons cells can't span cards, and vectors always mark the card of a + * specific element. So there is no looking back 1 card to check for a marked header */ +static page_index_t scan_boxed_root_cards_non_spanning(page_index_t page, generation_index_t gen) +{ +#ifndef LISP_FEATURE_SOFT_CARD_MARKS + /* Physical protection doesn't distinguish between card-spanning and non-card-spanning, + * because the write fault always occurs on the page that is getting dirtied by a store, + * unlike soft marks which can mark an object header, but store onto the next card */ + return scan_boxed_root_cards_spanning(page, gen); +#else + do { + lispobj* start = (void*)page_address(page); + long card = addr_to_card_index(start); + if (cardseq_any_marked(card)) { + if (GC_LOGGING) fprintf(gc_activitylog(), "scan_roots non-spanning %p\n", page_address(page)); + lispobj* limit = start + page_words_used(page); + int j; + for (j=0; j<CARDS_PER_PAGE; ++j, ++card, start += WORDS_PER_CARD) { + if (card_dirtyp(card)) { + lispobj* end = start + WORDS_PER_CARD; + if (end > limit) end = limit; + int dirty = descriptors_scavenge(start, end, gen, + card_stickymarked_p(card)); + root_vector_words_scanned += end - start; + if (!dirty) gc_card_mark[card] = CARD_UNMARKED; + } + } + } + ++page; + } while (!page_ends_contiguous_block_p(page-1, gen)); + return page; +#endif +} + +#ifdef LISP_FEATURE_SOFT_CARD_MARKS +/* PAGE_TYPE_SMALL_MIXED roots are walked object-by-object to avoid affecting any raw word. + * By construction, objects will never span cards */ +static page_index_t scan_mixed_root_cards(page_index_t page, generation_index_t gen) +{ + do { + lispobj* start = (void*)page_address(page); + long card = addr_to_card_index(start); + if (cardseq_any_marked(card)) { + if (GC_LOGGING) fprintf(gc_activitylog(), "scan_roots subcard mixed %p\n", page_address(page)); + lispobj* limit = start + page_words_used(page); + int j; + for (j=0; j<CARDS_PER_PAGE; ++j, ++card, start += WORDS_PER_CARD) { + if (card_dirtyp(card)) { + lispobj* end = start + WORDS_PER_CARD; + if (end > limit) end = limit; + // heap_scavenge doesn't take kindly to inverted start+end + if (start < limit) { + heap_scavenge(start, limit); + if (!card_stickymarked_p(card) && !range_dirty_p(start, limit, gen)) + gc_card_mark[card] = CARD_UNMARKED; + } else + gc_card_mark[card] = CARD_UNMARKED; + } + } + } + ++page; + } while (!page_ends_contiguous_block_p(page-1, gen)); + return page; +} +#endif + +/* Scavenge all generations greater than or equal to FROM. * - * Write-protected pages should not have any pointers to the - * from_space so do need scavenging; thus write-protected pages are - * not always scavenged. There is some code to check that these pages - * are not written; but to check fully the write-protected pages need - * to be scavenged by disabling the code to skip them. + * Under the current scheme when a generation is GCed, the generations + * younger than it are empty. So, when a generation is being GCed it + * is only necessary to examine generations older than it for pointers. * - * Under the current scheme when a generation is GCed the younger - * generations will be empty. So, when a generation is being GCed it - * is only necessary to scavenge the older generations for pointers - * not the younger. So a page that does not have pointers to younger - * generations does not need to be scavenged. + * Logical or physical write-protection is used to note pages that don't + * contain old->young pointers. But pages can be written without having + * such pointers. After the pages are scavenged here, they are examined + * for old->young pointer, are marked clean (unprotected) if there are none. * - * The write-protection can be used to note pages that don't have - * pointers to younger pages. But pages can be written without having - * pointers to younger generations. After the pages are scavenged here - * they can be scanned for pointers to younger generations and if - * there are none the page can be write-protected. + * Write-protected pages will not have any pointers to the + * from_space so do not need scavenging, but might be visited + * as part of a contiguous range containing a relevant page. * - * One complication is when the newspace is the top temp. generation. */ static void -scavenge_root_gens(generation_index_t from, generation_index_t to) +scavenge_root_gens(generation_index_t from) { - page_index_t i; + page_index_t i = 0; + page_index_t limit = next_free_page; + gc_dcheck(compacting_p()); - for (i = 0; i < next_free_page; i++) { + while (i < limit) { generation_index_t generation = page_table[i].gen; - if (page_boxed_p(i) - && (page_bytes_used(i) != 0) - && (generation != new_space) - && (generation >= from) - && (generation <= to)) { - - /* This should be the start of a region */ - gc_assert(page_starts_contiguous_block_p(i)); + if (generation < from || generation == SCRATCH_GENERATION + /* Not sure why word_used is checked. Probably because reset_page_flags() + * does not change the page's gen to an unused number. Perhaps it should */ + || !page_boxed_p(i) || !page_words_used(i)) { + ++i; + continue; + } - if (large_simple_vector_p(i)) { - /* Scavenge only the written pages of a large vector. - * There are no other large objects of special interest. - * Bignums are non-pointer objects, so aren't roots. - * INSTANCE and CLOSURE are theoretically capable of being - * large, but the compiler can't create them. - * Code is for practical purposes read-only after creation - * (other than assigning to simple-fun-name and documentation), - * and scavenging skips the unboxed portion anyway. - * The only potential improvement would be to deal better - * with large hash-table storage vectors. */ - if (!page_table[i].write_protected) { - scavenge((lispobj*)page_address(i) + 2, - GENCGC_CARD_BYTES / N_WORD_BYTES - 2); - update_page_write_prot(i); - } - while (!page_ends_contiguous_block_p(i, generation)) { - ++i; - if (!page_table[i].write_protected) { - scavenge((lispobj*)page_address(i), - page_bytes_used(i) / N_WORD_BYTES); - update_page_write_prot(i); - } - } - } else { - page_index_t last_page; - boolean write_protected = 1; - /* Now work forward until the end of the region */ - for (last_page = i; ; last_page++) { - write_protected = - write_protected && page_table[last_page].write_protected; - if (page_ends_contiguous_block_p(last_page, generation)) - break; - } - if (!write_protected) { - lispobj* start = (lispobj*)page_address(i); - lispobj* limit = (lispobj*)(page_address(last_page) - + page_bytes_used(last_page)); - heap_scavenge(start, limit); - /* Now scan the pages and write protect those that - * don't have pointers to younger generations. */ - if (CODE_PAGES_USE_SOFT_PROTECTION && - (page_table[i].type & PAGE_TYPE_MASK) == CODE_PAGE_TYPE) { - update_code_writeprotection(i, last_page, start, limit); - } else { - page_index_t j; - for (j = i; j <= last_page; j++) // scan by page - update_page_write_prot(j); - } - } - i = last_page; + /* This should be the start of a region */ + gc_assert(page_starts_contiguous_block_p(i)); + + if (page_table[i].type == PAGE_TYPE_BOXED) { + i = scan_boxed_root_cards_spanning(i, generation); + } else if ((page_table[i].type == PAGE_TYPE_CONS) || + (page_single_obj_p(i) && large_scannable_vector_p(i))) { + i = scan_boxed_root_cards_non_spanning(i, generation); +#ifdef LISP_FEATURE_SOFT_CARD_MARKS + } else if (page_table[i].type == PAGE_TYPE_SMALL_MIXED) { + i = scan_mixed_root_cards(i, generation); +#endif + } else { + page_index_t last_page; + int marked = 0; + /* Now work forward until the end of the region */ + for (last_page = i; ; last_page++) { + long card_index = page_to_card_index(last_page); + marked = marked || cardseq_any_marked(card_index); + if (page_ends_contiguous_block_p(last_page, generation)) + break; + } + if (marked) { + lispobj* start = (lispobj*)page_address(i); + lispobj* limit = + (lispobj*)page_address(last_page) + page_words_used(last_page); + if (GC_LOGGING) fprintf(gc_activitylog(), "scan_roots mixed %p:%p\n", start, limit); + root_mixed_words_scanned += limit - start; + heap_scavenge(start, limit); + /* Now scan the pages and write protect those that + * don't have pointers to younger generations. */ + if (is_code(page_table[i].type)) + update_code_writeprotection(i, last_page, start, limit); + else + update_writeprotection(i, last_page, start, limit); } + i = 1 + last_page; } } } @@ -2495,13 +3238,10 @@ static void newspace_full_scavenge(generation_index_t generation) { page_index_t i; - FSHOW((stderr, - "/starting one full scan of newspace generation %d\n", - generation)); for (i = 0; i < next_free_page; i++) { if ((page_table[i].gen == generation) && page_boxed_p(i) - && (page_bytes_used(i) != 0) - && !page_table[i].write_protected) { + && (page_words_used(i) != 0) + && cardseq_any_marked(page_to_card_index(i))) { page_index_t last_page; /* The scavenge will start at the scan_start_offset of @@ -2518,23 +3258,22 @@ static void newspace_full_scavenge(generation_index_t generation) record_new_regions_below = 1 + last_page; heap_scavenge(page_scan_start(i), - (lispobj*)(page_address(last_page) - + page_bytes_used(last_page))); + (lispobj*)page_address(last_page) + page_words_used(last_page)); i = last_page; } } /* Enable recording of all new allocation regions */ record_new_regions_below = 1 + page_table_pages; - FSHOW((stderr, - "/done with one full scan of newspace generation %d\n", - generation)); } -static void gc_close_all_regions() +void gc_close_collector_regions(int flag) { - ensure_region_closed(&code_region, CODE_PAGE_TYPE); - ensure_region_closed(&unboxed_region, UNBOXED_PAGE_FLAG); - ensure_region_closed(&boxed_region, BOXED_PAGE_FLAG); + ensure_region_closed(code_region, flag|PAGE_TYPE_CODE); + ensure_region_closed(boxed_region, PAGE_TYPE_BOXED); + ensure_region_closed(unboxed_region, PAGE_TYPE_UNBOXED); + ensure_region_closed(mixed_region, PAGE_TYPE_MIXED); + ensure_region_closed(small_mixed_region, PAGE_TYPE_SMALL_MIXED); + ensure_region_closed(cons_region, PAGE_TYPE_CONS); } /* Do a complete scavenge of the newspace generation. */ @@ -2542,23 +3281,21 @@ static void scavenge_newspace(generation_index_t generation) { /* Flush the current regions updating the page table. */ - gc_close_all_regions(); + gc_close_collector_regions(0); /* Turn on the recording of new areas. */ gc_assert(new_areas_index == 0); new_areas = new_areas_1; /* Start with a full scavenge. */ + if (GC_LOGGING) fprintf(gc_activitylog(), "newspace full scav\n"); newspace_full_scavenge(generation); /* Flush the current regions updating the page table. */ - gc_close_all_regions(); - - /*FSHOW((stderr, - "The first scan is finished; current_new_areas_index=%d.\n", - current_new_areas_index));*/ + gc_close_collector_regions(0); while (1) { + if (GC_LOGGING) fprintf(gc_activitylog(), "newspace loop\n"); if (!new_areas_index && !immobile_scav_queue_count) { // possible stopping point if (!test_weak_triggers(0, 0)) break; // no work to do @@ -2566,7 +3303,7 @@ scavenge_newspace(generation_index_t generation) // actually entails new work - it only knows which triggers were removed // from the pending list. So check again if allocations occurred, // which is only if not all triggers referenced already-live objects. - gc_close_all_regions(); // update new_areas from regions + gc_close_collector_regions(0); // update new_areas from regions if (!new_areas_index && !immobile_scav_queue_count) break; // still no work to do } @@ -2588,10 +3325,6 @@ scavenge_newspace(generation_index_t generation) /* New areas of objects allocated have been lost so need to do a * full scan to be sure! If this becomes a problem try * increasing NUM_NEW_AREAS. */ - if (gencgc_verbose) { - SHOW("new_areas overflow, doing full scavenge"); - } - newspace_full_scavenge(generation); } else { @@ -2604,515 +3337,136 @@ scavenge_newspace(generation_index_t generation) size_t size = previous_new_areas[i].size; gc_assert(size % (2*N_WORD_BYTES) == 0); lispobj *start = (lispobj*)(page_address(page) + offset); + if (GC_LOGGING) fprintf(gc_activitylog(), "heap_scav %p..%p\n", + start, (lispobj*)((char*)start + size)); heap_scavenge(start, (lispobj*)((char*)start + size)); } } /* Flush the current regions updating the page table. */ - gc_close_all_regions(); + gc_close_collector_regions(0); } /* Turn off recording of allocation regions. */ record_new_regions_below = 0; new_areas = NULL; new_areas_index = 0; - -#ifdef SC_NS_GEN_CK - { - page_index_t i; - /* Check that none of the write_protected pages in this generation - * have been written to. */ - for (i = 0; i < page_table_pages; i++) { - if ((page_bytes_used(i) != 0) - && (page_table[i].gen == generation) - && (page_table[i].write_protected_cleared != 0) - && (page_table[i].pinned == 0)) { - lose("write protected page %d written to in scavenge_newspace\ngeneration=%d pin=%d", - i, generation, page_table[i].pinned); - } - } - } -#endif } /* Un-write-protect all the pages in from_space. This is done at the * start of a GC else there may be many page faults while scavenging * the newspace (I've seen drive the system time to 99%). These pages * would need to be unprotected anyway before unmapping in - * free_oldspace; not sure what effect this has on paging.. */ + * free_oldspace; not sure what effect this has on paging.. + * + * Here is a real-life example of what can go wrong if we don't + * unprotect oldspace: + * Scenario: + * - gc-with-promotion (raise=1) of gen2 to gen3 + * - symbol FOO in gen 3 on page 1000 + * - large vector 'v' in gen 2 on page 1300..1305 + * - 'v' points only to gen 2 objects (so it is unmarked, or "protected") + * - symbol-value of FOO is 'v' + * - root generations are 4 and higher + * - no roots point to vector 'v' or any of its contents + * Thence: + * - scavenge_newspace_full_scan visits page 1000 + * - assigns 'record_new_regions_below' = 1001 + * - traces slots of FOO, calls copy_potential_large_object(v) + * - 'v' is promoted into gen3 + * - call add_new_area on page 1300..1305 + * - 1300 exceeds 1001 so we skip this area + * So because 'v' is ahead of the wavefront, and theoretically page 1300 + * will be picked up by the remainder of the full_scan loop, we optimized out + * the addition of the area. But then the scan loop sees that page 1300 + * is protected and it decides that it can can skip it even though it was + * originally part of 'from_space' and points to other 'from_space' things. + * The consequence is that everything 'v' pointed to in gen2 becomes freed + * while 'v' holds dangling pointers to all that garbage. + */ static void unprotect_oldspace(void) { page_index_t i; char *region_addr = 0; - char *page_addr = 0; + __attribute__((unused)) char *page_addr = 0; uword_t region_bytes = 0; + /* Gen0 never has protection applied, so we can usually skip the un-protect step, + * however, in the final GC, because everything got moved to gen0 by brute force + * adjustment of the page table, we don't know the state of the protection. + * Therefore only skip out if NOT in the final GC */ + if (conservative_stack && from_space == 0) return; + for (i = 0; i < next_free_page; i++) { - if ((page_bytes_used(i) != 0) +#ifdef LISP_FEATURE_SOFT_CARD_MARKS + /* Why does this even matter? Obviously it did for physical protection + * (storing the forwarding pointers shouldn't fault) + * but there's no physical protection, so ... why bother? + * But I tried removing it and got assertion failures */ + if (page_words_used(i) && page_table[i].gen == from_space) + assign_page_card_marks(i, CARD_MARKED); +#else + if ((page_words_used(i) != 0) && (page_table[i].gen == from_space)) { /* Remove any write-protection. We should be able to rely * on the write-protect flag to avoid redundant calls. */ - if (page_table[i].write_protected) { - page_table[i].write_protected = 0; - page_addr = page_address(i); - if (!region_addr) { - /* First region. */ - region_addr = page_addr; - region_bytes = GENCGC_CARD_BYTES; - } else if (region_addr + region_bytes == page_addr) { - /* Region continue. */ - region_bytes += GENCGC_CARD_BYTES; - } else { - /* Unprotect previous region. */ - os_protect(region_addr, region_bytes, OS_VM_PROT_ALL); - /* First page in new region. */ - region_addr = page_addr; - region_bytes = GENCGC_CARD_BYTES; + if (PAGE_WRITEPROTECTED_P(i)) { + SET_PAGE_PROTECTED(i, 0); + if (protection_mode(i) == PHYSICAL) { + page_addr = page_address(i); + if (!region_addr) { + /* First region. */ + region_addr = page_addr; + region_bytes = GENCGC_PAGE_BYTES; + } else if (region_addr + region_bytes == page_addr) { + /* Region continue. */ + region_bytes += GENCGC_PAGE_BYTES; + } else { + /* Unprotect previous region. */ + os_protect(region_addr, region_bytes, OS_VM_PROT_JIT_ALL); + /* First page in new region. */ + region_addr = page_addr; + region_bytes = GENCGC_PAGE_BYTES; + } } } } +#endif } if (region_addr) { /* Unprotect last region. */ - os_protect(region_addr, region_bytes, OS_VM_PROT_ALL); + os_protect(region_addr, region_bytes, OS_VM_PROT_JIT_ALL); } } -/* Work through all the pages and free any in from_space. This - * assumes that all objects have been copied or promoted to an older - * generation. Bytes_allocated and the generation bytes_allocated - * counter are updated. The number of bytes freed is returned. */ -static uword_t -free_oldspace(void) +/* Work through all the pages and free any in from_space. + * Live non-pinned objects will have been copied to new pages. + * Pinned objects are no longer in 'from_space', as the containing + * page is now in a different generation. + * Bytes_allocated and the generation bytes_allocated + * counter are updated. */ +static void free_oldspace(void) { uword_t bytes_freed = 0; - page_index_t first_page, last_page; - - first_page = 0; - - do { - /* Find a first page for the next region of pages. */ - while ((first_page < next_free_page) - && ((page_bytes_used(first_page) == 0) - || (page_table[first_page].gen != from_space))) - first_page++; - - if (first_page >= next_free_page) - break; - - /* Find the last page of this region. */ - last_page = first_page; - - page_bytes_t last_page_bytes; - do { - /* Free the page. */ - last_page_bytes = page_bytes_used(last_page); - bytes_freed += last_page_bytes; - reset_page_flags(last_page); - set_page_bytes_used(last_page, 0); + page_index_t page; + for (page = 0; page < next_free_page; ++page) { + if (page_table[page].gen == from_space) { /* Should already be unprotected by unprotect_oldspace(). */ - gc_assert(!page_table[last_page].write_protected); - last_page++; + gc_dcheck(page_cards_all_marked_nonsticky(page)); + /* Free the page. */ + int used = page_words_used(page); + if (used) set_page_need_to_zero(page, 1); + set_page_bytes_used(page, 0); + reset_page_flags(page); + bytes_freed += used << WORD_SHIFT; } - while ((last_page < next_free_page) - && page_table[last_page].gen == from_space - && page_bytes_used(last_page)); - - /* 'last_page' is the exclusive upper bound on the page range starting - * at 'first'page'. We have an accurate count of the bytes in use on - * last_page but there may be intervening pages not 100% full which are - * treated as full. This can spuriously visit some (0 . 0) conses - * but is otherwise not a big deal */ - visit_freed_objects(page_address(first_page), - npage_bytes(last_page-first_page-1) + last_page_bytes); - -#ifdef READ_PROTECT_FREE_PAGES - os_protect(page_address(first_page), - npage_bytes(last_page-first_page), - OS_VM_PROT_NONE); -#endif - first_page = last_page; - } while (first_page < next_free_page); - + } generations[from_space].bytes_allocated -= bytes_freed; bytes_allocated -= bytes_freed; - return bytes_freed; } -static int -is_in_stack_space(lispobj ptr) -{ - /* For space verification: Pointers can be valid if they point - * to a thread stack space. This would be faster if the thread - * structures had page-table entries as if they were part of - * the heap space. */ - /* Actually, no, how would that be faster? - * If you have to examine thread structures, you have to examine - * them all. This demands something like a binary search tree */ - struct thread *th; - for_each_thread(th) { - if ((th->control_stack_start <= (lispobj *)ptr) && - (th->control_stack_end >= (lispobj *)ptr)) { - return 1; - } - } - return 0; -} - -struct verify_state { - lispobj *vaddr; - lispobj *object_start, *object_end; - lispobj tagged_object_start; - uword_t flags; - int errors; - generation_index_t object_gen; - generation_index_t min_pointee_gen; - unsigned char widetag; - lispobj *implicit_tagged_subrange_start, - *implicit_tagged_subrange_end; -}; - -#define VERIFY_VERBOSE 1 -/* AGGRESSIVE = always call valid_lisp_pointer_p() on pointers. */ -#define VERIFY_PRE_GC 2 -#define VERIFY_POST_GC 4 -#define VERIFY_AGGRESSIVE 8 -/* QUICK = skip most tests. This is intended for use when GC is believed - * to be correct per se (i.e. not for debugging GC), and so the verify - * pass executes more quickly */ -#define VERIFY_QUICK 16 -/* FINAL = warn about pointers from heap space to non-heap space. - * Such pointers would normally be ignored and do not be flagged as failure. - * This can be used in conjunction with QUICK, AGGRESSIVE, or neither. */ -#define VERIFY_FINAL 32 -/* VERIFYING_foo indicates internal state, not a caller's option */ -#define VERIFYING_HEAP_OBJECTS 64 -#define VERIFYING_GENERATIONAL 128 - -// Helpers for verify_range -generation_index_t gc_gen_of(lispobj obj, int defaultval) { - int page = find_page_index((void*)obj); - if (page >= 0) return page_table[page].gen; -#ifdef LISP_FEATURE_IMMOBILE_SPACE - if (immobile_space_p(obj)) - return immobile_obj_generation(base_pointer(obj)); -#endif - return defaultval; -} -generation_index_t gen_of(lispobj object) { return gc_gen_of(object, 8); } - -static boolean __attribute__((unused)) card_protected_p(void* addr) -{ - page_index_t page = find_page_index(addr); - if (page >= 0) return page_table[page].write_protected; -#ifdef LISP_FEATURE_IMMOBILE_SPACE - if (immobile_space_p((lispobj)addr)) - return immobile_card_protected_p(addr); -#endif - lose("card_protected_p(%p)", addr); -} - -// NOTE: This function can produces false failure indications, -// usually related to dynamic space pointing to the stack of a -// dead thread, but there may be other reasons as well. -static void -verify_range(lispobj *where, sword_t nwords, struct verify_state *state) -{ - extern int valid_lisp_pointer_p(lispobj); - - /* Strict containment: no pointer from a heap space may point - * to anything outside of a heap space. */ - boolean strict_containment = state->flags & VERIFY_FINAL; - - lispobj *end = where + nwords; - size_t count; - for ( ; where < end ; where += count) { - /* Track object boundaries unless verifying non-heap space. A 1-word - * range resulting from unpacking a quasi-descriptor (compact instance - * header, fdefn raw addr) passed in as a local var of this function, - * and identifiable with vaddr != 0, can't start a new object. */ - if (!state->vaddr && where > state->object_end && - (state->flags & VERIFYING_HEAP_OBJECTS)) { - state->object_start = where; - state->widetag = - is_cons_half(*where) ? LIST_POINTER_LOWTAG : widetag_of(where); - state->tagged_object_start = compute_lispobj(where); - state->object_end = where + OBJECT_SIZE(*where, where) - 1; - state->object_gen = gen_of((lispobj)where); - // Should not see filler after sweeping all gens - /* if (!conservative_stack && widetag_of(where) == FILLER_WIDETAG) - fprintf(stderr, "Note: filler object @ %p\n", where); */ - } - count = 1; - lispobj thing = *where; - if (where >= state->implicit_tagged_subrange_start && - where < state->implicit_tagged_subrange_end) { - if (thing != 0) thing |= OTHER_POINTER_LOWTAG; - } - - lispobj callee; - -#define GC_WARN(str) \ - fprintf(stderr, "Ptr %p @ %"OBJ_FMTX" (lispobj %"OBJ_FMTX") sees %s\n", \ - (void*)(uintptr_t)thing, \ - (lispobj)(state->vaddr ? state->vaddr : where), \ - state->tagged_object_start, str); - - if (is_lisp_pointer(thing)) { - /* DONTFAIL mode skips most tests, performing only the strict - * containinment check */ - if (strict_containment && !gc_managed_heap_space_p(thing)) - GC_WARN("non-Lisp memory"); - generation_index_t to_gen = gen_of(thing); - if (to_gen < state->min_pointee_gen) state->min_pointee_gen = to_gen; - if (state->flags & VERIFY_QUICK) - continue; - -#define FAIL_IF(what, why) if (what) { \ - if (++state->errors > 25) lose("Too many errors"); else GC_WARN(why); } - - page_index_t page_index = find_page_index((void*)thing); - if (page_index >= 0 || immobile_space_p(thing)) { - if (page_index >= 0) { - // If it's within the dynamic space it should point to a used page. - FAIL_IF(page_free_p(page_index), "free page"); - FAIL_IF(!(page_table[page_index].type & OPEN_REGION_PAGE_FLAG) - && (thing & (GENCGC_CARD_BYTES-1)) >= page_bytes_used(page_index), - "unallocated space"); - } else { - // The object pointed to must not have been discarded as garbage. - FAIL_IF(!other_immediate_lowtag_p(*native_pointer(thing)) || - filler_obj_p(native_pointer(thing)), - "trashed object"); - } - // Must not point to a forwarding pointer - FAIL_IF(*native_pointer(thing) == 0x01, "forwarding ptr"); - // Forbid pointers from R/O space into a GCed space - FAIL_IF((READ_ONLY_SPACE_START <= (uword_t)where && - where < read_only_space_free_pointer), - "dynamic space from RO space"); - if (CODE_PAGES_USE_SOFT_PROTECTION - && state->widetag == CODE_HEADER_WIDETAG - && to_gen < state->object_gen) { - // two things must be true: - // 1. the page containing object_start must not be write-protected - FAIL_IF(card_protected_p(state->object_start), - "younger obj from WP'd code header page"); - // 2. the object header must be marked as written - if (!header_rememberedp(*state->object_start)) - lose("code @ %p (g%d). word @ %p -> %"OBJ_FMTX" (g%d)", - state->object_start, state->object_gen, - where, thing, to_gen); - } else if (state->flags & VERIFYING_GENERATIONAL) { - // When testing for old->young ptrs, if from dynamic space then use - // the address of the word that holds the pointer in question, - // geting the per-page generation. Immobile space has only a generation - // per object, and you *must* use the correct object header address. - lispobj vaddr = (lispobj)(state->vaddr ? state->vaddr : where); - generation_index_t from_gen - = gen_of(find_page_index((lispobj*)vaddr) >= 0 ? - vaddr : (lispobj)state->object_start); - FAIL_IF(to_gen < from_gen && card_protected_p((lispobj*)vaddr), - "younger obj from WP page"); - } - int valid; - if (state->flags & VERIFY_AGGRESSIVE) // Extreme paranoia mode - valid = valid_lisp_pointer_p(thing); - else { - /* Efficiently decide whether 'thing' is plausible. - * This MUST NOT use properly_tagged_descriptor_p() which - * assumes a known good object base address, and would - * "dangerously" scan a code component for embedded funs. */ - valid = plausible_tag_p(thing); - } - /* If 'thing' points to a stack, we can only hope that the stack - * frame is ok, or the object at 'where' is unreachable. */ - FAIL_IF(!valid && !is_in_stack_space(thing), "junk"); - } - continue; - } - int widetag = header_widetag(thing); - if (is_lisp_immediate(thing) || widetag == NO_TLS_VALUE_MARKER_WIDETAG) { - /* skip immediates */ - } else if (!(other_immediate_lowtag_p(widetag) - && lowtag_for_widetag[widetag>>2])) { - lose("Unhandled widetag %d at %p", widetag, where); - } else if (leaf_obj_widetag_p(widetag)) { - count = sizetab[widetag](where); - if (strict_containment && gencgc_verbose - && widetag == SAP_WIDETAG && where[1]) - fprintf(stderr, "\nStrange SAP %p -> %p\n", - where, (void*)where[1]); - } else switch(widetag) { - /* boxed or partially boxed objects */ - lispobj layout_word; - // Two reasons for including funcallable instance here: - // (1) the layout may be in the header, and we need to verify it - // (2) there may be unboxed words in the object - case FUNCALLABLE_INSTANCE_WIDETAG: - case INSTANCE_WIDETAG: - layout_word = layout_of(where); - if (layout_word) { - state->vaddr = where; - verify_range(&layout_word, 1, state); - state->vaddr = 0; - gc_assert(layoutp(layout_word)); - struct layout *layout = LAYOUT(layout_word); - sword_t nslots = instance_length(thing) | 1; - lispobj bitmap = layout->bitmap; - gc_assert(fixnump(bitmap) - || widetag_of(native_pointer(bitmap))==BIGNUM_WIDETAG); - if (lockfree_list_node_layout_p(layout)) { - struct instance* node = (struct instance*)where; - lispobj next = node->slots[INSTANCE_DATA_START]; - if (fixnump(next) && next) { - state->vaddr = &node->slots[INSTANCE_DATA_START]; - next |= INSTANCE_POINTER_LOWTAG; - verify_range(&next, 1, state); - state->vaddr = 0; - } - } - instance_scan((void (*)(lispobj*, sword_t, uword_t))verify_range, - where+1, nslots, bitmap, (uintptr_t)state); - count = 1 + nslots; - } - break; - case CODE_HEADER_WIDETAG: - { - struct code *code = (struct code *) where; - sword_t nheader_words = code_header_words(code); - gc_assert(fixnump(where[1])); // boxed size - /* Verify the boxed section of the code data block */ - state->min_pointee_gen = 8; // initialize to "positive infinity" -#ifdef LISP_FEATURE_UNTAGGED_FDEFNS - state->implicit_tagged_subrange_start = - code->constants + code_n_funs(code) * 4; - state->implicit_tagged_subrange_end = - state->implicit_tagged_subrange_start + code_n_named_calls(code); -#endif - verify_range(where + 2, nheader_words - 2, state); - state->implicit_tagged_subrange_start = 0; - state->implicit_tagged_subrange_end = 0; - - /* Verify the boxed section of each simple-fun */ - for_each_simple_fun(i, fheaderp, code, 1, { -#if defined(LISP_FEATURE_COMPACT_INSTANCE_HEADER) - lispobj __attribute__((unused)) layout = - function_layout((lispobj*)fheaderp); - gc_assert(!layout || layout == LAYOUT_OF_FUNCTION); -#endif - }); -#if CODE_PAGES_USE_SOFT_PROTECTION - generation_index_t my_gen = gen_of((lispobj)where); - boolean rememberedp = header_rememberedp(*where); - /* The remembered set invariant is that an object is marked "written" - * if and only if either it points to a younger object or is pointed - * to by a register or stack. (The pointed-to case assumes that the - * very next instruction on return from GC would store an old->young - * pointer into that object). Non-compacting GC does not have the - * "only if" part of that, nor does pre-GC verification because we - * don't test the generation of the newval when storing into code. */ - if (compacting_p() && (state->flags & VERIFY_POST_GC) ? - (state->min_pointee_gen < my_gen) != rememberedp : - (state->min_pointee_gen < my_gen) && !rememberedp) - lose("object @ %p is gen%d min_pointee=gen%d %s", - where, my_gen, state->min_pointee_gen, - rememberedp ? "written" : "not written"); -#endif - count = code_total_nwords(code); - break; - } - case FDEFN_WIDETAG: - verify_range(where + 1, 2, state); - callee = fdefn_callee_lispobj((struct fdefn*)where); - /* For a more intelligible error, don't say that the word that - * contains an errant pointer is in stack space if it isn't. */ - state->vaddr = where + 3; - verify_range(&callee, 1, state); - state->vaddr = 0; - count = ALIGN_UP(sizeof (struct fdefn)/sizeof(lispobj), 2); - break; - } - } -} -static uword_t verify_space(lispobj start, lispobj* end, uword_t flags) { - struct verify_state state; - memset(&state, 0, sizeof state); - state.flags = flags; - verify_range((lispobj*)start, end-(lispobj*)start, &state); - if (state.errors) lose("verify failed: %d error(s)", state.errors); - return 0; -} -static uword_t verify_gen_aux(lispobj start, lispobj* end, struct verify_state* state) -{ - verify_range((lispobj*)start, end-(lispobj*)start, state); - return 0; -} -static void verify_generation(generation_index_t generation, uword_t flags) -{ - struct verify_state state; - memset(&state, 0, sizeof state); - state.flags = flags; - walk_generation((uword_t(*)(lispobj*,lispobj*,uword_t))verify_gen_aux, - generation, (uword_t)&state); - if (state.errors) lose("verify failed: %d error(s)", state.errors); -} - -void verify_heap(uword_t flags) -{ - int verbose = gencgc_verbose | ((flags & VERIFY_VERBOSE) != 0); - - flags |= VERIFYING_HEAP_OBJECTS; - - if (verbose) - fprintf(stderr, - flags & VERIFY_PRE_GC ? "Verify before GC" : - flags & VERIFY_POST_GC ? "Verify after GC(%d)" : - "Heap check", // if called at a random time - (int)(flags>>16)); // generation number - -#ifdef LISP_FEATURE_IMMOBILE_SPACE -# ifdef __linux__ - // Try this verification if immobile-space was compiled with extra debugging. - // But weak symbols don't work on macOS. - extern void __attribute__((weak)) check_varyobj_pages(); - if (&check_varyobj_pages) check_varyobj_pages(); -# endif - if (verbose) - fprintf(stderr, " [immobile]"); - verify_space(FIXEDOBJ_SPACE_START, - fixedobj_free_pointer, flags | VERIFYING_GENERATIONAL); - verify_space(VARYOBJ_SPACE_START, - varyobj_free_pointer, flags | VERIFYING_GENERATIONAL); -#endif - struct thread *th; - if (verbose) - fprintf(stderr, " [threads]"); - for_each_thread(th) { - verify_space((lispobj)th->binding_stack_start, - (lispobj*)get_binding_stack_pointer(th), - flags ^ VERIFYING_HEAP_OBJECTS); -#ifdef LISP_FEATURE_SB_THREAD - verify_space((lispobj)(th+1), - (lispobj*)(SymbolValue(FREE_TLS_INDEX,0) + (char*)th), - flags ^ VERIFYING_HEAP_OBJECTS); -#endif - } - if (verbose) - fprintf(stderr, " [RO]"); - verify_space(READ_ONLY_SPACE_START, read_only_space_free_pointer, flags); - if (verbose) - fprintf(stderr, " [static]"); - verify_space(STATIC_SPACE_START, static_space_free_pointer, flags); - if (verbose) - fprintf(stderr, " [dynamic]"); - verify_generation(-1, flags | VERIFYING_GENERATIONAL); - if (verbose) - fprintf(stderr, " passed\n"); -} - /* Call 'proc' with pairs of addresses demarcating ranges in the * specified generation. * Stop if any invocation returns non-zero, and return that value */ @@ -3124,7 +3478,7 @@ walk_generation(uword_t (*proc)(lispobj*,lispobj*,uword_t), int genmask = generation >= 0 ? 1 << generation : ~0; for (i = 0; i < next_free_page; i++) { - if ((page_bytes_used(i) != 0) && ((1 << page_table[i].gen) & genmask)) { + if ((page_words_used(i) != 0) && ((1 << page_table[i].gen) & genmask)) { page_index_t last_page; /* This should be the start of a contiguous block */ @@ -3143,7 +3497,7 @@ walk_generation(uword_t (*proc)(lispobj*,lispobj*,uword_t), uword_t result = proc((lispobj*)page_address(i), - (lispobj*)(page_bytes_used(last_page) + page_address(last_page)), + (lispobj*)page_address(last_page) + page_words_used(last_page), extra); if (result) return result; @@ -3158,40 +3512,54 @@ walk_generation(uword_t (*proc)(lispobj*,lispobj*,uword_t), static void write_protect_generation_pages(generation_index_t generation) { - page_index_t start = 0, end; - int n_hw_prot = 0, n_sw_prot = 0; - // Neither 0 nor scratch can be protected. Additionally, protection of // pseudo-static space is applied only in gc_load_corefile_ptes(). gc_assert(generation != 0 && generation != SCRATCH_GENERATION && generation != PSEUDO_STATIC_GENERATION); +#ifdef LISP_FEATURE_SOFT_CARD_MARKS + page_index_t page; + for (page = 0; page < next_free_page; ++page) { + if (page_table[page].gen == generation && page_boxed_p(page) + && page_words_used(page)) { + long card = page_to_card_index(page); + int j; + // must not touch a card referenced from the control stack + // because the next instruction executed by user code + // might store an old->young pointer. + // There's probably a clever SIMD-in-a-register algorithm for this... + for (j=0; j<CARDS_PER_PAGE; ++j, card++) + if (gc_card_mark[card] != STICKY_MARK) gc_card_mark[card] = CARD_UNMARKED; + } + } +#else + page_index_t start = 0, end; + int n_hw_prot = 0, n_sw_prot = 0; + while (start < next_free_page) { if (!protect_page_p(start, generation)) { ++start; continue; } if (protection_mode(start) == LOGICAL) { - page_table[start].write_protected = 1; + SET_PAGE_PROTECTED(start, 1); ++n_sw_prot; ++start; continue; } /* Note the page as protected in the page tables. */ - page_table[start].write_protected = 1; + SET_PAGE_PROTECTED(start, 1); /* Find the extent of pages desiring physical protection */ for (end = start + 1; end < next_free_page; end++) { if (!protect_page_p(end, generation) || protection_mode(end) == LOGICAL) break; - page_table[end].write_protected = 1; + SET_PAGE_PROTECTED(end, 1); } n_hw_prot += end - start; - os_protect(page_address(start), - npage_bytes(end - start), - OS_VM_PROT_READ | OS_VM_PROT_EXECUTE); + os_protect(page_address(start), npage_bytes(end - start), OS_VM_PROT_JIT_READ); start = end; } @@ -3200,10 +3568,8 @@ write_protect_generation_pages(generation_index_t generation) printf("HW protected %d, SW protected %d\n", n_hw_prot, n_sw_prot); page_index_t __attribute((unused)) n_total, n_protected; n_total = count_generation_pages(generation, &n_protected); - FSHOW((stderr, - "/write protected %d of %d pages in generation %d\n", - n_protected, n_total, generation)); } +#endif } #if !GENCGC_IS_PRECISE @@ -3212,7 +3578,6 @@ preserve_context_registers (void __attribute__((unused)) (*proc)(os_context_regi os_context_t __attribute__((unused)) *c) { #ifdef LISP_FEATURE_SB_THREAD - void **ptr; /* On Darwin the signal context isn't a contiguous block of memory, * so just preserve_pointering its contents won't be sufficient. */ @@ -3224,7 +3589,7 @@ preserve_context_registers (void __attribute__((unused)) (*proc)(os_context_regi proc(*os_context_register_addr(c,reg_EBX)); proc(*os_context_register_addr(c,reg_ESI)); proc(*os_context_register_addr(c,reg_EDI)); - proc(*os_context_pc_addr(c)); + proc(os_context_pc(c)); #elif defined LISP_FEATURE_X86_64 proc(*os_context_register_addr(c,reg_RAX)); proc(*os_context_register_addr(c,reg_RCX)); @@ -3240,12 +3605,13 @@ preserve_context_registers (void __attribute__((unused)) (*proc)(os_context_regi proc(*os_context_register_addr(c,reg_R13)); proc(*os_context_register_addr(c,reg_R14)); proc(*os_context_register_addr(c,reg_R15)); - proc(*os_context_pc_addr(c)); + proc(os_context_pc(c)); #else #error "preserve_context_registers needs to be tweaked for non-x86 Darwin" #endif #endif #if !defined(LISP_FEATURE_WIN32) + void **ptr; for(ptr = ((void **)(c+1))-1; ptr>=(void **)c; ptr--) { proc((os_context_register_t)*ptr); } @@ -3265,39 +3631,313 @@ move_pinned_pages_to_newspace() for (i = 0; i < next_free_page; i++) { /* 'pinned' is cleared lazily, so test the 'gen' field as well. */ - if (page_table[i].gen == from_space - && page_table[i].pinned && page_single_obj_p(i)) { + if (gc_page_pins[i] == PAGE_PINNED && + page_table[i].gen == from_space && + (page_single_obj_p(i) || + (is_code(page_table[i].type) && pin_all_dynamic_space_code))) { page_table[i].gen = new_space; /* And since we're moving the pages wholesale, also adjust * the generation allocation counters. */ - int used = page_bytes_used(i); + page_bytes_t used = page_bytes_used(i); generations[new_space].bytes_allocated += used; generations[from_space].bytes_allocated -= used; } } } -lispobj layout_of_layout; -void compute_layout_of_layout() +lispobj * +dynamic_space_code_from_pc(char *pc) { - // Compute layout_of_layout from some structure instance by taking the layout - // of its layout. T's package serves as an exemplar structure. - // If you use NIL, then you can't use the convenient casting macro SYMBOL - // which subtracts the wrong lowtag for ppc64 since NIL is primarily a list - // and only coincidentally a symbol if the lowtags work out right. - lispobj* package = (lispobj*)(SYMBOL(T)->package - INSTANCE_POINTER_LOWTAG); - lispobj layout = instance_layout(package); - layout_of_layout = instance_layout(LAYOUT(layout)); + /* Only look at untagged pointers, otherwise they won't be in the PC. + * (which is a valid precondition for fixed-length 4-byte instructions, + * not variable-length) */ + if((long)pc % 4 == 0 && is_code(page_table[find_page_index(pc)].type)) { + lispobj *object = search_dynamic_space(pc); + if (object != NULL && widetag_of(object) == CODE_HEADER_WIDETAG) + return object; + } + + return NULL; +} + +static void __attribute__((unused)) maybe_pin_code(lispobj addr) { + page_index_t page = find_page_index((char*)addr); + + if (page < 0) return; + if (immune_set_memberp(page)) return; + + struct code* code = (struct code*)dynamic_space_code_from_pc((char *)addr); + if (code) { + pin_exact_root(make_lispobj(code, OTHER_POINTER_LOWTAG)); + } +} + +#if defined reg_RA +static void conservative_pin_code_from_return_addresses(struct thread* th) { + lispobj *object_ptr; + // We need more information to reliably backtrace through a call + // chain, as these backends may generate leaf functions where the + // return address does not get spilled. Therefore, fall back to + // scanning the entire stack for potential interior code pointers. + for (object_ptr = th->control_stack_start; + object_ptr < access_control_stack_pointer(th); + object_ptr++) + maybe_pin_code(*object_ptr); + int i = fixnum_value(read_TLS(FREE_INTERRUPT_CONTEXT_INDEX,th)); + // Scan program counters and return registers in interrupted + // frames: They may contain interior code pointers that weren't + // spilled onto the stack, as is the case for leaf functions. + for (i = i - 1; i >= 0; --i) { + os_context_t* context = nth_interrupt_context(i, th); + maybe_pin_code(os_context_pc(context)); + maybe_pin_code((lispobj)*os_context_register_addr(context, reg_RA)); + } +} +#endif + +#if defined LISP_FEATURE_MIPS || defined LISP_FEATURE_PPC64 +static void semiconservative_pin_stack(struct thread* th, + generation_index_t gen) { + /* Stack can only pin code, since it contains return addresses. + * Non-code pointers on stack do *not* pin anything, and may be updated + * when scavenging. + * Interrupt contexts' boxed registers do pin their referents */ + lispobj *object_ptr; + for (object_ptr = th->control_stack_start; + object_ptr < access_control_stack_pointer(th); + object_ptr++) + maybe_pin_code(*object_ptr); + int i = fixnum_value(read_TLS(FREE_INTERRUPT_CONTEXT_INDEX,th)); + for (i = i - 1; i >= 0; --i) { + os_context_t* context = nth_interrupt_context(i, th); + int j; +#if defined LISP_FEATURE_MIPS + mcontext_t *mctx = &context->uc_mcontext; + for(j=1; j<32; ++j) { + // context registers have more significant bits than lispobj. + uword_t word = mctx->gregs[j]; + if (gen == 0) sticky_preserve_pointer(word); + else preserve_pointer(word); + } +#elif defined LISP_FEATURE_PPC64 + static int boxed_registers[] = BOXED_REGISTERS; + for (j = (int)(sizeof boxed_registers / sizeof boxed_registers[0])-1; j >= 0; --j) { + lispobj word = *os_context_register_addr(context, boxed_registers[j]); + if (gen == 0) sticky_preserve_pointer(word); + else preserve_pointer(word); + } + // What kinds of data do we put in the Count register? + // maybe it's count (raw word), maybe it's a PC. I just don't know. + preserve_pointer(*os_context_lr_addr(context)); + preserve_pointer(*os_context_ctr_addr(context)); +#endif + preserve_pointer(os_context_pc(context)); + } +} +#endif + +#if GENCGC_IS_PRECISE && !defined(reg_CODE) + +static int boxed_registers[] = BOXED_REGISTERS; + +/* Pin all (condemned) code objects pointed to by the chain of in-flight calls + * based on scanning from the innermost frame pointer. This relies on an exact backtrace, + * which some of our architectures have trouble obtaining. But it's theoretically + * more efficient to do it this way versus looking at all stack words to see + * whether each points to a code object. */ +static void pin_call_chain_and_boxed_registers(struct thread* th) { + lispobj *cfp = access_control_frame_pointer(th); + + if (cfp) { + while (1) { + lispobj* ocfp = (lispobj *) cfp[0]; + lispobj lr = cfp[1]; + if (ocfp == 0) + break; + maybe_pin_code(lr); + cfp = ocfp; + } + } + int i = fixnum_value(read_TLS(FREE_INTERRUPT_CONTEXT_INDEX,th)); + for (i = i - 1; i >= 0; --i) { + os_context_t* context = nth_interrupt_context(i, th); + maybe_pin_code((lispobj)*os_context_register_addr(context, reg_LR)); + + for (unsigned i = 0; i < (sizeof(boxed_registers) / sizeof(int)); i++) { + pin_exact_root(*os_context_register_addr(context, boxed_registers[i])); + } + } + } +#endif + +#if !GENCGC_IS_PRECISE +static void NO_SANITIZE_ADDRESS NO_SANITIZE_MEMORY +conservative_stack_scan(struct thread* th, + __attribute__((unused)) generation_index_t gen, + // #+sb-safepoint uses os_get_csp() and not this arg + __attribute__((unused)) lispobj* cur_thread_approx_stackptr) +{ + /* there are potentially two stacks for each thread: the main + * stack, which may contain Lisp pointers, and the alternate stack. + * We don't ever run Lisp code on the altstack, but it may + * host a sigcontext with lisp objects in it. + * Actually, STOP_FOR_GC has a signal context on the main stack, + * and the values it in will be *above* the stack-pointer in it + * at the point of interruption, so we would not scan all registers + * unless the context is scanned. + * + * For the thread which initiates GC there will usually not be a + * sigcontext, though there could, in theory be if it performs + * GC while handling an interruption */ + __attribute__((unused)) void (*context_method)(os_context_register_t) = +#ifdef LISP_FEATURE_SOFT_CARD_MARKS + gen == 0 ? sticky_preserve_pointer : (void (*)(os_context_register_t))preserve_pointer; +#else + (void (*)(os_context_register_t))preserve_pointer; +#endif + + void* esp = (void*)-1; +# if defined(LISP_FEATURE_SB_SAFEPOINT) + /* Conservative collect_garbage is always invoked with a + * foreign C call or an interrupt handler on top of every + * existing thread, so the stored SP in each thread + * structure is valid, no matter which thread we are looking + * at. For threads that were running Lisp code, the pitstop + * and edge functions maintain this value within the + * interrupt or exception handler. */ + esp = os_get_csp(th); + assert_on_stack(th, esp); + + /* And on platforms with interrupts: scavenge ctx registers. */ + + /* Disabled on Windows, because it does not have an explicit + * stack of `interrupt_contexts'. The reported CSP has been + * chosen so that the current context on the stack is + * covered by the stack scan. See also set_csp_from_context(). */ +# ifndef LISP_FEATURE_WIN32 + if (th != get_sb_vm_thread()) { + int k = fixnum_value(read_TLS(FREE_INTERRUPT_CONTEXT_INDEX,th)); + while (k > 0) { + os_context_t* context = nth_interrupt_context(--k, th); + if (context) + preserve_context_registers(context_method, context); + } + } +# endif +# elif defined(LISP_FEATURE_SB_THREAD) + int i; + /* fprintf(stderr, "Thread %p, ici=%d stack[%p:%p] (%dw)", + th, fixnum_value(read_TLS(FREE_INTERRUPT_CONTEXT_INDEX,th)), + th->control_stack_start, th->control_stack_end, + th->control_stack_end - th->control_stack_start); */ + for (i = fixnum_value(read_TLS(FREE_INTERRUPT_CONTEXT_INDEX,th))-1; i>=0; i--) { + os_context_t *c = nth_interrupt_context(i, th); + preserve_context_registers(context_method, c); + lispobj* esp1 = (lispobj*) *os_context_register_addr(c,reg_SP); + if (esp1 >= th->control_stack_start && esp1 < th->control_stack_end && (void*)esp1 < esp) + esp = esp1; + } + if (th == get_sb_vm_thread()) { + if ((void*)cur_thread_approx_stackptr < esp) esp = cur_thread_approx_stackptr; + } +# else + esp = cur_thread_approx_stackptr; +# endif + if (!esp || esp == (void*) -1) + UNKNOWN_STACK_POINTER_ERROR("garbage_collect", th); + /* fprintf(stderr, " SP=%p (%dw)%s\n", + esp, (int)(th->control_stack_end - (lispobj*)esp), + (th == get_sb_vm_thread()) ? " CURRENT":""); */ + + // Words on the stack which point into the stack are likely + // frame pointers or alien or DX object pointers. In any case + // there's no need to call preserve_pointer on them since + // they definitely don't point to the heap. + // See the picture at alloc_thread_struct() as a reminder. +#ifdef LISP_FEATURE_UNIX + lispobj exclude_from = (lispobj)th->control_stack_start; + lispobj exclude_to = (lispobj)th + dynamic_values_bytes; +#define potential_heap_pointer(word) !(exclude_from <= word && word < exclude_to) +#else + // We can't use the heuristic of excluding words that appear to point into + // 'struct thread' on win32 because ... I don't know why. + // See https://groups.google.com/g/sbcl-devel/c/8s7mrapq56s/m/UaAjYPqKBAAJ +#define potential_heap_pointer(word) 1 +#endif + + lispobj* ptr; + for (ptr = esp; ptr < th->control_stack_end; ptr++) { + lispobj word = *ptr; + // Also note that we can eliminate small fixnums from consideration + // since there is no memory on the 0th page. + // (most OSes don't let users map memory there, though they used to). + if (word >= BACKEND_PAGE_BYTES && potential_heap_pointer(word)) { + preserve_pointer(word); + } + } +} +#endif + +static void scan_explicit_pins(__attribute__((unused)) struct thread* th) +{ + lispobj pin_list = read_TLS(PINNED_OBJECTS, th); + for ( ; pin_list != NIL ; pin_list = CONS(pin_list)->cdr ) { + lispobj object = CONS(pin_list)->car; + pin_exact_root(object); + if (lowtag_of(object) == INSTANCE_POINTER_LOWTAG) { + struct instance* instance = INSTANCE(object); + lispobj layout = instance_layout((lispobj*)instance); + // Since we're still in the pinning phase of GC, layouts can't have moved yet, + // so there is no forwarding check needed here. + if (layout && lockfree_list_node_layout_p(LAYOUT(layout))) { + /* A logically-deleted explicitly-pinned lockfree list node pins its + * successor too, since Lisp reconstructs the next node's tagged pointer + * from an untagged pointer currently stored in %NEXT of this node. */ + lispobj successor = instance->slots[INSTANCE_DATA_START]; + // Be sure to ignore an uninitialized word containing 0. + if (successor && fixnump(successor)) + pin_exact_root(successor | INSTANCE_POINTER_LOWTAG); + } + } + } +} + +/* Given the slightly asymmetric formulation of page_ends_contiguous_block_p() + * you might think that it could cause the next page's assertion about start_block_p() + * to fail, but it does not seem to. That's really weird! */ +__attribute__((unused)) static void check_contiguity() +{ + page_index_t first = 0; + while (first < next_free_page) { + if (!page_words_used(first)) { ++first; continue; } + gc_assert(page_starts_contiguous_block_p(first)); + page_index_t last = first; + while (!page_ends_contiguous_block_p(last, page_table[first].gen)) ++last; + first = last + 1; + } +} + +int show_gc_generation_throughput = 0; /* Garbage collect a generation. If raise is 0 then the remains of the * generation are not raised to the next generation. */ -static void NO_SANITIZE_ADDRESS NO_SANITIZE_MEMORY -garbage_collect_generation(generation_index_t generation, int raise) +void NO_SANITIZE_ADDRESS NO_SANITIZE_MEMORY +garbage_collect_generation(generation_index_t generation, int raise, + void* cur_thread_approx_stackptr) { - page_index_t i; struct thread *th; + if (gencgc_verbose > 2) fprintf(stderr, "BEGIN gc_gen(%d,%d)\n", generation, raise); + +#ifdef COLLECT_GC_STATS + struct timespec t0; + clock_gettime(CLOCK_MONOTONIC, &t0); + uword_t gen_usage_at_start = generations[generation].bytes_allocated; + uword_t higher_gen_usage_at_start = + raise ? generations[generation+1].bytes_allocated : 0; +#endif + gc_assert(generation <= PSEUDO_STATIC_GENERATION); /* The oldest generation can't be raised. */ @@ -3315,10 +3955,23 @@ garbage_collect_generation(generation_index_t generation, int raise) } hopscotch_reset(&pinned_objects); - // for traceroot, which reads n_stack_pins from the previous GC cycle - gc_n_stack_pins = 0;; + +#ifdef LISP_FEATURE_SB_THREAD + pin_all_dynamic_space_code = 0; + for_each_thread(th) { + if (th->state_word.state != STATE_DEAD && \ + (read_TLS(GC_PIN_CODE_PAGES, th) & make_fixnum(1))) { + pin_all_dynamic_space_code = 1; + break; + } + } +#else + pin_all_dynamic_space_code = read_TLS(GC_PIN_CODE_PAGES, 0) & make_fixnum(1); +#endif /* Set the global src and dest. generations */ + generation_index_t original_alloc_generation = gc_alloc_generation; + if (generation < PSEUDO_STATIC_GENERATION) { from_space = generation; @@ -3331,190 +3984,127 @@ garbage_collect_generation(generation_index_t generation, int raise) gc_alloc_generation = new_space; RESET_ALLOC_START_PAGES(); - /* Before any pointers are preserved, the pinned flags on the - * pages need to be cleared. */ - /* FIXME: consider moving this bitmap into its own range of words, - * out of the page table. Then we can just bzero() it. - * This will also obviate the extra test at the comment - * "pinned is cleared lazily" in move_pinned_pages_to_newspace(). - */ - for (i = 0; i < next_free_page; i++) - if(page_table[i].gen==from_space) - page_table[i].pinned = 0; + if (pin_all_dynamic_space_code) { + /* This needs to happen before ambiguous root pinning, as the mechanisms + * overlap in a way that all-code pinning wouldn't do the right thing if flipped. + * FIXME: why would it not? More explanation needed! + * Code objects should never get into the pins table in this case */ + page_index_t i; + for (i = 0; i < next_free_page; i++) { + if (page_table[i].gen == from_space + && is_code(page_table[i].type) && page_words_used(i)) + gc_page_pins[i] = PAGE_PINNED; + } + } /* Un-write-protect the old-space pages. This is essential for the * promoted pages as they may contain pointers into the old-space * which need to be scavenged. It also helps avoid unnecessary page * faults as forwarding pointers are written into them. They need to * be un-protected anyway before unmapping later. */ - if (ENABLE_PAGE_PROTECTION) - unprotect_oldspace(); + unprotect_oldspace(); } else { // "full" [sic] GC + gc_assert(!pin_all_dynamic_space_code); // not supported (but could be) + /* This is a full mark-and-sweep of all generations without compacting * and without returning free space to the allocator. The intent is to * break chains of objects causing accidental reachability. * Subsequent GC cycles will compact and reclaims space as usual. */ from_space = new_space = -1; - // Unprotect the dynamic space but leave page_table bits alone - if (ENABLE_PAGE_PROTECTION) - os_protect(page_address(0), npage_bytes(next_free_page), - OS_VM_PROT_ALL); - // Allocate pages from dynamic space for the work queue. extern void prepare_for_full_mark_phase(); - prepare_for_full_mark_phase(); - - } - - /* Scavenge the stacks' conservative roots. */ - - /* there are potentially two stacks for each thread: the main - * stack, which may contain Lisp pointers, and the alternate stack. - * We don't ever run Lisp code on the altstack, but it may - * host a sigcontext with lisp objects in it */ + prepare_for_full_mark_phase(); - /* what we need to do: (1) find the stack pointer for the main - * stack; scavenge it (2) find the interrupt context on the - * alternate stack that might contain lisp values, and scavenge - * that */ + } - /* we assume that none of the preceding applies to the thread that - * initiates GC. If you ever call GC from inside an altstack - * handler, you will lose. */ + /* Possibly pin stack roots and/or *PINNED-OBJECTS*, unless saving a core. + * Scavenging (fixing up pointers) will occur later on */ -#if !GENCGC_IS_PRECISE - /* And if we're saving a core, there's no point in being conservative. */ if (conservative_stack) { for_each_thread(th) { - void* esp = (void*)-1; - if (th->state == STATE_DEAD) - continue; -# if defined(LISP_FEATURE_SB_SAFEPOINT) - /* Conservative collect_garbage is always invoked with a - * foreign C call or an interrupt handler on top of every - * existing thread, so the stored SP in each thread - * structure is valid, no matter which thread we are looking - * at. For threads that were running Lisp code, the pitstop - * and edge functions maintain this value within the - * interrupt or exception handler. */ - esp = (void*)os_get_csp(th); - assert_on_stack(th, esp); - - /* And on platforms with interrupts: scavenge ctx registers. */ - - /* Disabled on Windows, because it does not have an explicit - * stack of `interrupt_contexts'. The reported CSP has been - * chosen so that the current context on the stack is - * covered by the stack scan. See also set_csp_from_context(). */ -# ifndef LISP_FEATURE_WIN32 - if (th != arch_os_get_current_thread()) { - long k = fixnum_value( - read_TLS(FREE_INTERRUPT_CONTEXT_INDEX,th)); - while (k > 0) { - os_context_t* context = nth_interrupt_context(--k, th); - if (context) - preserve_context_registers((void(*)(os_context_register_t))preserve_pointer, - context); - } - } -# endif -# elif defined(LISP_FEATURE_SB_THREAD) - if(th==arch_os_get_current_thread()) { - esp = (void*)&raise; - } else { - sword_t i,free; - lispobj* esp1; - free=fixnum_value(read_TLS(FREE_INTERRUPT_CONTEXT_INDEX,th)); - for(i=free-1;i>=0;i--) { - os_context_t *c = nth_interrupt_context(i, th); - esp1 = (lispobj*) *os_context_register_addr(c,reg_SP); - if (esp1 >= th->control_stack_start && esp1 < th->control_stack_end) { - if ((void*)esp1<esp) esp = esp1; - preserve_context_registers((void(*)(os_context_register_t))preserve_pointer, - c); - } - } - } -# else - esp = (void*)&raise; -# endif - if (!esp || esp == (void*) -1) - UNKNOWN_STACK_POINTER_ERROR("garbage_collect", th); - - // Words on the stack which point into the stack are likely - // frame pointers or alien or DX object pointers. In any case - // there's no need to call preserve_pointer on them since - // they definitely don't point to the heap. - // See the picture at create_thread_struct() as a reminder. - lispobj exclude_from = (lispobj)th->control_stack_start; - lispobj exclude_to = (lispobj)th + dynamic_values_bytes; - - // This loop would be more naturally expressed as - // for (ptr = esp; ptr < th->control_stack_end; ++ptr) - // However there is a very subtle problem with that: 'esp = &raise' - // is not necessarily properly aligned to be a stack pointer! - void **ptr; - for (ptr = ((void **)th->control_stack_end)-1; ptr >= (void**)esp; ptr--) { - lispobj word = (lispobj)*ptr; - // Also note that we can eliminate small fixnums from consideration - // since there is no memory on the 0th page. - // (most OSes don't let users map memory there, though they used to). - if (word >= BACKEND_PAGE_BYTES && - !(exclude_from <= word && word < exclude_to)) - preserve_pointer((void*)word); - } + if (th->state_word.state == STATE_DEAD) continue; + scan_explicit_pins(th); +#if !GENCGC_IS_PRECISE + /* Pin everything in fromspace with a stack root, and also set the + * sticky card mark on any page (in any generation) + * referenced from the stack. */ + conservative_stack_scan(th, generation, cur_thread_approx_stackptr); +#elif defined LISP_FEATURE_MIPS || defined LISP_FEATURE_PPC64 + // Pin code if needed + semiconservative_pin_stack(th, generation); +#elif defined REG_RA + conservative_pin_code_from_return_addresses(th); +#elif !defined(reg_CODE) + pin_call_chain_and_boxed_registers(th); +#endif } } + + // Thread creation optionally no longer synchronizes the creating and + // created thread. When synchronized, the parent thread is responsible + // for pinning the start function for handoff to the created thread. + // When not synchronized, The startup parameters are pinned via this list + // which will always be NIL if the feature is not enabled. +#ifdef STARTING_THREADS + lispobj pin_list = SYMBOL(STARTING_THREADS)->value; + for ( ; pin_list != NIL ; pin_list = CONS(pin_list)->cdr ) { + lispobj thing = CONS(pin_list)->car; + // It might be tempting to say that only the SB-THREAD:THREAD instance + // requires pinning - because right after we access it to extract the + // primitive thread, we link into all_threads - but it may be that the code + // emitted by the C compiler in new_thread_trampoline computes untagged pointers + // when accessing the vector and the start function, so those would not be + // seen as valid lisp pointers by the implicit pinning logic. + // And the precisely GC'd platforms would not pin anything from C code. + // The tests in 'threads.impure.lisp' are good at detecting omissions here. + if (thing) { // Nothing to worry about when 'thing' is already smashed + gc_assert(instancep(thing)); + struct thread_instance *lispthread = (void*)(thing - INSTANCE_POINTER_LOWTAG); + lispobj info = lispthread->startup_info; + // INFO gets set to a fixnum when the thread is exiting. I *think* it won't + // ever be seen in the starting-threads list, but let's be cautious. + if (is_lisp_pointer(info)) { + gc_assert(simple_vector_p(info)); + gc_assert(vector_len(VECTOR(info)) >= 1); + lispobj fun = VECTOR(info)->data[0]; + gc_assert(functionp(fun)); +#ifdef LISP_FEATURE_X86_64 + /* FIXME: re. the following remark that pin_exact_root() "does not + * work", does it have to be that way? It seems the issue is that + * pin_exact_root does absolutely nothing for objects in immobile space. + * Are there other objects we call it on which could be in immobile-space + * and should it be made to deal with them? */ + // slight KLUDGE: 'fun' is a simple-fun in immobile-space, + // and pin_exact_root() doesn't work. In all probability 'fun' + // is pseudo-static, but let's use the right pinning function. + // (This line of code is so rarely executed that it doesn't + // impact performance to search for the object) + preserve_pointer(fun); #else - /* Non-x86oid systems don't have "conservative roots" as such, but - * the same mechanism is used for objects pinned for use by alien - * code. */ - for_each_thread(th) { - lispobj pin_list = read_TLS(PINNED_OBJECTS,th); - while (pin_list != NIL) { - pin_exact_root(CONS(pin_list)->car); - pin_list = CONS(pin_list)->cdr; - } -#ifdef LISP_FEATURE_PPC64 - // Scan the control stack and interrupt contexts for ambiguous code roots. - // Doing it in gc-common would be too late, since all pinned objects have - // to be discovered before transporting anything. - // I think we never store reg_CODE on the control stack (yet) - it will only - // appear in an interrupt context - so this is probably unnecessary for now. - // However, I'd like to eliminate LRAs (at least on the PPC64 backend), - // in which case all the looks-like-fixnum return PCs on the control stack, - // will need to enliven what they point to. - // So we will end up doubly traversing the control stack(s), but it should - // be a performance gain to avoid all the PC adjustments for call/return. - lispobj *object_ptr; - for (object_ptr = th->control_stack_start; - object_ptr < access_control_stack_pointer(th); - object_ptr++) - preserve_pointer((void*)*object_ptr); - int i = fixnum_value(read_TLS(FREE_INTERRUPT_CONTEXT_INDEX,th)); - for (i = i - 1; i >= 0; --i) { - os_context_t* context = nth_interrupt_context(i, th); - int j; - // FIXME: if we pick a register to consistently use with m[ft]lr - // then we would only need to examine that, and LR and CTR here. - // We may already be consistent, I just don't what the consistency is. - static int boxed_registers[] = BOXED_REGISTERS; - int __attribute__((unused)) ct = 0; - for (j = (int)(sizeof boxed_registers / sizeof boxed_registers[0])-1; j >= 0; --j) - preserve_pointer((void*)*os_context_register_addr(context, - boxed_registers[j])); - preserve_pointer((void*)*os_context_lr_addr(context)); - preserve_pointer((void*)*os_context_ctr_addr(context)); + pin_exact_root(fun); +#endif + // pin_exact_root is more efficient than preserve_pointer() + // because it does not search for the object. + pin_exact_root(thing); + pin_exact_root(info); + pin_exact_root(lispthread->name); + } } -#endif // PPC64 } #endif - if (gencgc_verbose > 1) - show_pinnedobj_count(); + /* Remove any key from pinned_objects this does not identify an object. + * This is done more efficiently by delaying until after all keys are + * inserted rather than at each insertion */ + refine_ambiguous_roots(); + + if (gencgc_verbose > 1) { + extern void dump_marked_objects(); + if (compacting_p()) show_pinnedobj_count(); /*else dump_marked_objects();*/ + } /* Now that all of the pinned pages are known, and * before we start to scavenge (and thus relocate) objects, @@ -3528,12 +4118,14 @@ garbage_collect_generation(generation_index_t generation, int raise) #if GENCGC_IS_PRECISE /* * If not x86, we need to scavenge the interrupt context(s) and the - * control stack. + * control stack, unless in final GC then don't. */ - { + if (conservative_stack) { struct thread *th; for_each_thread(th) { +#if !defined(LISP_FEATURE_MIPS) && defined(reg_CODE) // interrupt contexts already pinned everything they see scavenge_interrupt_contexts(th); +#endif scavenge_control_stack(th); } @@ -3552,22 +4144,15 @@ garbage_collect_generation(generation_index_t generation, int raise) } #endif - /* Scavenge the Lisp functions of the interrupt handlers, taking - * care to avoid SIG_DFL and SIG_IGN. */ - for (i = 0; i < NSIG; i++) { - union interrupt_handler handler = interrupt_handlers[i]; - if (!ARE_SAME_HANDLER(handler.c, SIG_IGN) && - !ARE_SAME_HANDLER(handler.c, SIG_DFL) && - // BUG: if a C function pointer can be misaligned such that it - // looks to satisfy functionp() then we do the wrong thing. - is_lisp_pointer(handler.lisp)) { - if (compacting_p()) - scavenge((lispobj *)(interrupt_handlers + i), 1); - else - gc_mark_obj(handler.lisp); - } - } + /* Scavenge the Lisp functions of the interrupt handlers */ + if (GC_LOGGING) fprintf(gc_activitylog(), "begin scavenge sighandlers\n"); + if (compacting_p()) + scavenge(lisp_sig_handlers, NSIG); + else + gc_mark_range(lisp_sig_handlers, NSIG); + /* Scavenge the binding stacks. */ + if (GC_LOGGING) fprintf(gc_activitylog(), "begin scavenge thread roots\n"); { struct thread *th; for_each_thread(th) { @@ -3576,13 +4161,13 @@ garbage_collect_generation(generation_index_t generation, int raise) compacting_p() ? 0 : gc_mark_obj); #ifdef LISP_FEATURE_SB_THREAD /* do the tls as well */ - sword_t len; - len=(SymbolValue(FREE_TLS_INDEX,0) >> WORD_SHIFT) - - (sizeof (struct thread))/(sizeof (lispobj)); + lispobj* from = &th->lisp_thread; + lispobj* to = (lispobj*)(SymbolValue(FREE_TLS_INDEX,0) + (char*)th); + sword_t nwords = to - from; if (compacting_p()) - scavenge((lispobj *) (th+1), len); + scavenge(from, nwords); else - gc_mark_range((lispobj *) (th+1), len); + gc_mark_range(from, nwords); #endif } } @@ -3595,13 +4180,9 @@ garbage_collect_generation(generation_index_t generation, int raise) goto maybe_verify; } - /* Scavenge static space. */ - if (gencgc_verbose > 1) { - FSHOW((stderr, - "/scavenge static space: %d bytes\n", - (uword_t)static_space_free_pointer - STATIC_SPACE_START)); - } - heap_scavenge((lispobj*)STATIC_SPACE_START, static_space_free_pointer); + if (GC_LOGGING) fprintf(gc_activitylog(), "begin scavenge static roots\n"); + heap_scavenge((lispobj*)NIL_SYMBOL_SLOTS_START, (lispobj*)NIL_SYMBOL_SLOTS_END); + heap_scavenge((lispobj*)STATIC_SPACE_OBJECTS_START, static_space_free_pointer); /* All generations but the generation being GCed need to be * scavenged. The new_space generation needs special handling as @@ -3612,26 +4193,119 @@ garbage_collect_generation(generation_index_t generation, int raise) // number reassigned to that generation if applicable. scavenge_immobile_roots(generation+1, SCRATCH_GENERATION); - scavenge_root_gens(generation+1, PSEUDO_STATIC_GENERATION); + // When collecting gen0, ordinarily the roots would be gen1 and higher, + // but if gen0 is getting raised to 1 on this cycle, then we skip roots in gen1 + // because we'll eventually examine all of gen1 as part of newspace. + // Similarly for higher generations. So if raising, the minimum root gen is + // always the collected generation + 2, otherwise it's the collected + 1. + if (GC_LOGGING) fprintf(gc_activitylog(), "begin scavenge_root_gens\n"); + scavenge_root_gens(generation+1+raise); scavenge_pinned_ranges(); /* The Lisp start function is stored in the core header, not a static * symbol. It is passed to gc_and_save() in this C variable */ if (lisp_init_function) scavenge(&lisp_init_function, 1); + if (lisp_package_vector) scavenge(&lisp_package_vector, 1); if (gc_object_watcher) scavenge(&gc_object_watcher, 1); if (alloc_profile_data) scavenge(&alloc_profile_data, 1); + /* If SB-SPROF was used, enliven all pages of code. + * Note that some objects may have already been transported off the page. + * Despite the extra scan, it is more efficient than scanning all trace buffers + * and potentially updating them and/or invalidating hashes. + * This really wants a better algorithm. Each code blob could have one byte + * indicating whether it is present in any trace buffer; the SIGPROF handler + * can update that byte. */ + if (sb_sprof_enabled) { + page_index_t first = 0; + while (first < next_free_page) { + if (page_table[first].gen != from_space + || !is_code(page_table[first].type) + || !page_words_used(first)) { + ++first; + continue; + } + page_index_t last = first; + while (!page_ends_contiguous_block_p(last, from_space)) ++last; + // [first,last] are inclusive bounds on a code range + /* FIXME: should 'where' be initialized to page_scan_start()? I think so, + * because ends_contiguous_block(page-1) does NOT imply + * starts_contiguous_block(page). This is very unfortunate. + * I've seen things such as the following: + * page base: 0x20000 0x21000 0x22000 + * used: 1000 10 0 + * ss: 0x20000 0x20000 0x21010 + * where the first two pages were opened together and then closed + * after consuming all of the first + 0x10 bytes more, and then the next + * page extends the region (so not to waste the entire rest of the second + * page), pointing its scan_start to the end of the range that was updated + * into the page table. In that scenario, ends_p() is true of the page + * based at 0x21000 but starts_p() is false of the next page, + * because its scan start is an earlier page than itself. + * How does this assertion NOT fail sometimes? Yet, it does not. */ + gc_assert(page_starts_contiguous_block_p(first)); + lispobj* where = (lispobj*)page_address(first); + lispobj* limit = (lispobj*)page_address(last) + page_words_used(last); + while (where < limit) { + if (forwarding_pointer_p(where)) { + // The codeblob already survived GC, so we just need to step over it. + lispobj* copy = native_pointer(forwarding_pointer_value(where)); + // NOTE: it's OK to size the newspace copy rather than the original + // because code size can't change. + where += headerobj_size(copy); + } else { + // Compute 'nwords' before potentially moving the object + // at 'where', because moving it stomps on the header word. + sword_t nwords = headerobj_size(where); + // If the object is not a filler and not a trampline, then create + // a pointer to it and eliven the pointee. + if (widetag_of(where) == CODE_HEADER_WIDETAG + && where[1] != 0 /* has at least one boxed word */ + && code_serialno((struct code*)where) != 0) { + lispobj ptr = make_lispobj(where, OTHER_POINTER_LOWTAG); + scavenge(&ptr, 1); + } + where += nwords; + } + } + first = last + 1; + } + } + /* Finally scavenge the new_space generation. Keep going until no * more objects are moved into the new generation */ scavenge_newspace(new_space); scan_binding_stack(); smash_weak_pointers(); +#ifdef LISP_FEATURE_METASPACE + // *PRIMITIVE-OBJECT-LAYOUTS* (in readonly space) is a root, but it only points + // to other objects in readonly space; however, those other objects (above + // the read_only_space_free_pointer) point weakly to dynamic space. + struct slab_header *slab = (void*)METASPACE_START; + // This is not maximally efficient, in that it visits all slabs instead of just the + // used ones, but it's not so bad, because there are only 1024 slabs. + while ((uword_t)slab < READ_ONLY_SPACE_END) { + if (slab->sizeclass) { + lispobj* chunk = (lispobj*)((char*)slab + METASPACE_SLAB_SIZE); + int i; + for (i=0; i<slab->capacity; ++i) { + chunk = (lispobj*)((char*)chunk - slab->chunksize); + if (chunk[1]) { // in-use chunk + // Freeing this layout is more involved than merely zeroing some memory, + // because freelists have to be maintained. A finalizer will do that. + TEST_WEAK_CELL(chunk[1], chunk[1], 0); + } + } + } + slab = (void*)((char*)slab + METASPACE_SLAB_SIZE); + } +#endif /* Return private-use pages to the general pool so that Lisp can have them */ gc_dispose_private_pages(); cull_weak_hash_tables(weak_ht_alivep_funs); - wipe_nonpinned_words(); - // Do this last, because until wipe_nonpinned_words() happens, + obliterate_nonpinned_words(); + // Do this last, because until obliterate_nonpinned_words() happens, // not all page table entries have the 'gen' value updated, // which we need to correctly find all old->young pointers. sweep_immobile_space(raise); @@ -3639,21 +4313,69 @@ garbage_collect_generation(generation_index_t generation, int raise) ASSERT_REGIONS_CLOSED(); hopscotch_log_stats(&pinned_objects, "pins"); - /* Free the pages in oldspace, but not those marked pinned. */ free_oldspace(); - /* If the GC is not raising the age then lower the generation back - * to its normal generation number */ + /* If this cycle was not a promotion cycle, change SCRATCH_GENERATION back + * to its correct generation number */ struct generation* g = &generations[generation]; if (!raise) { + page_index_t i; for (i = 0; i < next_free_page; i++) - if ((page_bytes_used(i) != 0) - && (page_table[i].gen == SCRATCH_GENERATION)) - page_table[i].gen = generation; + if (page_table[i].gen == SCRATCH_GENERATION) page_table[i].gen = generation; gc_assert(g->bytes_allocated == 0); g->bytes_allocated = generations[SCRATCH_GENERATION].bytes_allocated; generations[SCRATCH_GENERATION].bytes_allocated = 0; } +#ifdef COLLECT_GC_STATS + if (show_gc_generation_throughput) { + struct timespec t1; + clock_gettime(CLOCK_MONOTONIC, &t1); + long et_nsec = (t1.tv_sec - t0.tv_sec)*1000000000 + (t1.tv_nsec - t0.tv_nsec); + sword_t bytes_retained, bytes_freed; + if (raise) { + bytes_retained = (generations[generation+1].bytes_allocated + - higher_gen_usage_at_start); + } else { + bytes_retained = generations[generation].bytes_allocated; + } + bytes_freed = gen_usage_at_start - bytes_retained; + + double pct_freed = gen_usage_at_start ? (double)bytes_freed / gen_usage_at_start : 0.0; + double et_sec = (double)et_nsec / 1000000000.0; + double speed = (double)(gc_copied_nwords << WORD_SHIFT) / 1024 / et_sec; + char *units = "KiB"; + if (speed > 1024.0) speed /= 1024.0, units = "MiB"; + /* The pre-GC bytes allocated should sum to copied + pinned + freed, which it + * more-or-less does, but there can be discrepancies because structure instances + * can be extended with a stable-hash slot (which isn't accounted for at all), + * vectors can be shrunk (part being "freed" and part being "copied", depending + * on the size and partial pinning),and the finalizer hash-table can have cons + * cells allocated to record the list of functions to call. + * In particular, there could be 0 usage before, and some usage after due to + * the finalizer table, which causes "freed" to be negative. + * While those factors could be accounted for in the report, it would be needlessly + * pedantic and confusing, and not really affect the big picture. + * If the MiB per sec is low, it could be that not many bytes were copied. + * Low speed + large count is bad though */ + char buffer[200]; + // can't use fprintf() inside GC because of malloc. snprintf() can deadlock too, + // but seems to do so much less often. + int n = snprintf(buffer, sizeof buffer, + "gen%d: %ldw copied in %f sec (%.0f %s/sec), %ldw in-situ," + " %d pins (%ldw), %ldw freed (%.1f%%)\n", + generation, gc_copied_nwords, et_sec, speed, units, + gc_in_situ_live_nwords, + gc_pin_count, gc_pinned_nwords, + bytes_freed >> WORD_SHIFT, pct_freed*100.0); + write(2, buffer, n); + n = snprintf(buffer, sizeof buffer, + "root word counts: %d + %d + %d\n", root_boxed_words_scanned, + root_vector_words_scanned, root_mixed_words_scanned); + write(2, buffer, n); + } + gc_copied_nwords = gc_in_situ_live_nwords = gc_pinned_nwords = 0; + root_boxed_words_scanned = root_vector_words_scanned = root_mixed_words_scanned = 0; +#endif /* Reset the alloc_start_page for generation. */ RESET_ALLOC_START_PAGES(); @@ -3663,11 +4385,15 @@ garbage_collect_generation(generation_index_t generation, int raise) g->num_gc = raise ? 0 : (1 + g->num_gc); maybe_verify: -#ifndef LISP_FEATURE_IMMOBILE_SPACE - compute_layout_of_layout(); // if it moved -#endif + // Have to kill this structure from its root, because any of the nodes would have + // been on pages that got freed by free_oldspace. + dynspace_codeblob_tree_snapshot = 0; if (generation >= verify_gens) - verify_heap(VERIFY_POST_GC | (generation<<16)); + hexdump_and_verify_heap(cur_thread_approx_stackptr, VERIFY_POST_GC | (generation<<16)); + + extern int n_unboxed_instances; + n_unboxed_instances = 0; + gc_alloc_generation = original_alloc_generation; } static page_index_t @@ -3676,10 +4402,10 @@ find_next_free_page(void) page_index_t last_page = -1, i; for (i = 0; i < next_free_page; i++) - if (page_bytes_used(i) != 0) + if (page_words_used(i) != 0) last_page = i; - /* The last free page is actually the first available page */ + /* 1 page beyond the last used page is the next free page */ return last_page + 1; } @@ -3693,11 +4419,6 @@ find_next_free_page(void) * If the interior of the aligned range is nonempty, * perform three operations: unmap/remap, fill before, fill after. * Otherwise, just one operation to fill the whole range. - * - * This will make more sense once we do a few other things: - * - enable manual card marking in codegen - * - disable mmap-based page protection - * - enable hugepages (so the OS page is much larger than a card) */ static void remap_page_range (page_index_t from, page_index_t to) @@ -3720,17 +4441,20 @@ remap_page_range (page_index_t from, page_index_t to) char* aligned_start = PTR_ALIGN_UP(start, granularity); char* aligned_end = PTR_ALIGN_DOWN(end, granularity); + /* NOTE: this is largely pointless because gencgc-release-granularity + * is everywhere defined to be EXACTLY +backend-page-bytes+ + * which by definition is the quantum at which we'll unmap/map. + * Maybe we should remove the needless complexity? */ if (aligned_start < aligned_end) { zero_range_with_mmap(aligned_start, aligned_end-aligned_start); - zero_range(start, aligned_start); - zero_range(aligned_end, end); + memset(start, 0, aligned_start - start); + memset(aligned_end, 0, end - aligned_end); } else { zero_pages(from, to); } #endif page_index_t i; - for (i = from; i <= to; i++) - set_page_need_to_zero(i, 0); + for (i = from; i <= to; i++) set_page_need_to_zero(i, 0); } static void @@ -3758,6 +4482,16 @@ generation_index_t small_generation_limit = 1; // one pair of counters per widetag, though we're only tracking code as yet int n_scav_calls[64], n_scav_skipped[64]; +extern int finalizer_thread_runflag; + +#ifdef LISP_FEATURE_SB_THREAD +# define THREAD_ALLOC_REGION(threadvar,slot) &threadvar-> slot ##_tlab +#else +# define THREAD_ALLOC_REGION(threadvar,slot) main_thread_ ##slot ##_region +#define main_thread_mixed_region (struct alloc_region*)STATIC_SPACE_START +#define main_thread_cons_region (1+main_thread_mixed_region) +#define main_thread_boxed_region (2+main_thread_mixed_region) +#endif /* GC all generations newer than last_gen, raising the objects in each * to the next older generation - we finish when all generations below @@ -3767,9 +4501,12 @@ int n_scav_calls[64], n_scav_skipped[64]; * * We stop collecting at gencgc_oldest_gen_to_gc, even if this is less than * last_gen (oh, and note that by default it is NUM_GENERATIONS-1) */ -void +long tot_gc_nsec; +void NO_SANITIZE_ADDRESS NO_SANITIZE_MEMORY collect_garbage(generation_index_t last_gen) { + ++n_gcs; + THREAD_JIT(0); generation_index_t gen = 0, i; boolean gc_mark_only = 0; int raise, more = 0; @@ -3778,7 +4515,10 @@ collect_garbage(generation_index_t last_gen) * remap_free_pages was called. */ static page_index_t high_water_mark = 0; - FSHOW((stderr, "/entering collect_garbage(%d)\n", last_gen)); +#ifdef COLLECT_GC_STATS + struct timespec t_gc_start; + clock_gettime(CLOCK_MONOTONIC, &t_gc_start); +#endif log_generation_stats(gc_logfile, "=== GC Start ==="); gc_active_p = 1; @@ -3789,9 +4529,6 @@ collect_garbage(generation_index_t last_gen) gc_mark_only = 1; } else if (last_gen > 1+PSEUDO_STATIC_GENERATION) { // This is a completely non-obvious thing to do, but whatever... - FSHOW((stderr, - "/collect_garbage: last_gen = %d, doing a level 0 GC\n", - last_gen)); last_gen = 0; } @@ -3808,31 +4545,50 @@ collect_garbage(generation_index_t last_gen) * in a unithread build. * So we need to close them for those two cases. */ -#ifdef SINGLE_THREAD_BOXED_REGION - ensure_region_closed(SINGLE_THREAD_BOXED_REGION, BOXED_PAGE_FLAG); -#endif struct thread *th; - for_each_thread(th) { - ensure_region_closed(&th->alloc_region, BOXED_PAGE_FLAG); -#if defined(LISP_FEATURE_SB_SAFEPOINT_STRICTLY) && !defined(LISP_FEATURE_WIN32) - ensure_region_closed(&th->sprof_alloc_region, BOXED_PAGE_FLAG); -#endif - } - gc_close_all_regions(); + for_each_thread(th) gc_close_thread_regions(th, 0); + ensure_region_closed(code_region, PAGE_TYPE_CODE); + if (gencgc_verbose > 2) fprintf(stderr, "[%d] BEGIN gc(%d)\n", n_gcs, last_gen); - /* Immobile space generation bits are lazily updated for gen0 - (not touched on every object allocation) so do it now */ - update_immobile_nursery_bits(); +#ifdef LISP_FEATURE_IMMOBILE_SPACE + if (ENABLE_PAGE_PROTECTION) { + // Unprotect the in-use ranges. Any page could be written during scavenge + os_protect((os_vm_address_t)FIXEDOBJ_SPACE_START, + (lispobj)fixedobj_free_pointer - FIXEDOBJ_SPACE_START, + OS_VM_PROT_ALL); + } +#endif + lispobj* cur_thread_approx_stackptr = + (lispobj*)ALIGN_DOWN((uword_t)&last_gen, N_WORD_BYTES); /* Verify the new objects created by Lisp code. */ if (pre_verify_gen_0) - verify_heap(VERIFY_PRE_GC); + hexdump_and_verify_heap(cur_thread_approx_stackptr, VERIFY_PRE_GC); - if (gencgc_verbose > 1) + if (gencgc_verbose > 1) { + fprintf(stderr, "Pre-GC:\n"); print_generation_stats(); + } + /* After a GC, pages of code are safe to linearly scan because + * there won't be random junk on them below page_bytes_used. + * But generation 0 pages are _not_ safe to linearly scan because they aren't + * pre-zeroed. The SIGPROF handler could have a bad time if were to misread + * the header of an object mid-creation. Therefore, codeblobs newly made by Lisp + * are kept in a lock-free and threadsafe datastructure. But we don't want to + * enliven nodes of that structure for Lisp to see (absent any other references) + * because the whole thing becomes garbage after this GC. So capture the tree + * for GC's benefit, and delete the view of it from Lisp. + * Incidentally, immobile text pages have their own tree, for other purposes + * (among them being to find page scan start offsets) which is pruned as + * needed by a finalizer. */ + dynspace_codeblob_tree_snapshot = SYMBOL(DYNSPACE_CODEBLOB_TREE)->value; + SYMBOL(DYNSPACE_CODEBLOB_TREE)->value = NIL; + + page_index_t initial_nfp = next_free_page; if (gc_mark_only) { - garbage_collect_generation(PSEUDO_STATIC_GENERATION, 0); + garbage_collect_generation(PSEUDO_STATIC_GENERATION, 0, + cur_thread_approx_stackptr); goto finish; } @@ -3858,13 +4614,6 @@ collect_garbage(generation_index_t last_gen) } } - if (gencgc_verbose > 1) { - struct generation* __attribute__((unused)) g = &generations[gen]; - FSHOW((stderr, - "starting GC of generation %d with raise=%d alloc=%d trig=%d GCs=%d\n", - gen, raise, g->bytes_allocated, g->gc_trigger, g->num_gc)); - } - /* If an older generation is being filled, then update its * memory age. */ if (raise == 1) { @@ -3874,7 +4623,8 @@ collect_garbage(generation_index_t last_gen) memset(n_scav_calls, 0, sizeof n_scav_calls); memset(n_scav_skipped, 0, sizeof n_scav_skipped); - garbage_collect_generation(gen, raise); + garbage_collect_generation(gen, raise, cur_thread_approx_stackptr); + if (gencgc_verbose) fprintf(stderr, "code scavenged: %d total, %d skipped\n", @@ -3885,7 +4635,7 @@ collect_garbage(generation_index_t last_gen) generations[gen].cum_sum_bytes_allocated = 0; if (gencgc_verbose > 1) { - FSHOW((stderr, "GC of generation %d finished:\n", gen)); + fprintf(stderr, "Post-GC(gen=%d):\n", gen); print_generation_stats(); } @@ -3923,19 +4673,24 @@ collect_garbage(generation_index_t last_gen) } write_protect_generation_pages(gen_to_wp); } - - /* Set gc_alloc() back to generation 0. The global regions were - * already asserted to be closed after each generation's collection. - * i.e. no more allocations can accidentally occur to any other - * generation than 0 */ - gc_alloc_generation = 0; +#ifdef LISP_FEATURE_SOFT_CARD_MARKS + { + // Turn sticky cards marks to the regular mark. + page_index_t page; + for (page=0; page<next_free_page; ++page) { + long card = page_to_card_index(page); + int j; + for (j=0; j<CARDS_PER_PAGE; ++j, ++card) + if (gc_card_mark[card] == STICKY_MARK) gc_card_mark[card] = CARD_MARKED; + } + } +#endif /* Save the high-water mark before updating next_free_page */ if (next_free_page > high_water_mark) high_water_mark = next_free_page; next_free_page = find_next_free_page(); - set_alloc_pointer((lispobj)(page_address(next_free_page))); /* Update auto_gc_trigger. Make sure we trigger the next GC before * running out of heap! */ @@ -3961,6 +4716,12 @@ collect_garbage(generation_index_t last_gen) if (gen > small_generation_limit) { if (next_free_page > high_water_mark) high_water_mark = next_free_page; + // BUG? high_water_mark is the highest value of next_free_page, + // which means that page_table[high_water_mark] was actually NOT ever + // used, because next_free_page is an exclusive bound on the range + // of pages used. But remap_free_pages takes to 'to' as an *inclusive* + // bound. The only reason it's not an array overrun error is that + // the page_table has one more element than there are pages. remap_free_pages(0, high_water_mark); high_water_mark = 0; } @@ -3975,15 +4736,35 @@ collect_garbage(generation_index_t last_gen) #ifdef LISP_FEATURE_C_STACK_IS_CONTROL_STACK gc_prove_liveness(preserve_context_registers, gc_object_watcher, - gc_n_stack_pins, pinned_objects.keys, + gc_pin_count, gc_filtered_pins, gc_traceroot_criterion); #else gc_prove_liveness(0, gc_object_watcher, 0, 0, gc_traceroot_criterion); #endif } +#ifdef COLLECT_GC_STATS + struct timespec t_gc_done; + clock_gettime(CLOCK_MONOTONIC, &t_gc_done); + long et_nsec = (t_gc_done.tv_sec - t_gc_start.tv_sec)*1000000000 + + (t_gc_done.tv_nsec - t_gc_start.tv_nsec); + tot_gc_nsec += et_nsec; +#endif + log_generation_stats(gc_logfile, "=== GC End ==="); - SHOW("returning from collect_garbage"); + // Increment the finalizer runflag. This acts as a count of the number + // of GCs as well as a notification to wake the finalizer thread. + if (finalizer_thread_runflag != 0) { + int newval = 1 + finalizer_thread_runflag; + // check if counter wrapped around. Don't store 0 as the new value, + // as that causes the thread to exit. + finalizer_thread_runflag = newval ? newval : 1; + } + THREAD_JIT(1); + // Clear all pin bits for the next GC cycle. + // This could be done in the background somehow maybe. + page_index_t max_nfp = initial_nfp > next_free_page ? initial_nfp : next_free_page; + memset(gc_page_pins, 0, max_nfp); } /* Initialization of gencgc metadata is split into two steps: @@ -3994,30 +4775,59 @@ collect_garbage(generation_index_t last_gen) void gc_init(void) { +#ifdef LISP_FEATURE_WIN32 + InitializeCriticalSection(&free_pages_lock); +#endif #if defined(LISP_FEATURE_SB_SAFEPOINT) - alloc_gc_page(); + extern void safepoint_init(void); + safepoint_init(); #endif - // Verify that foo_BIT constants agree with the C compiler's bit packing - // and that we can compute the correct adddress of the bitfields. - // These tests can be optimized out of the emitted code by a good compiler. - struct page test; - unsigned char *pflagbits = (unsigned char*)&test.gen - 1; - memset(&test, 0, sizeof test); - *pflagbits = WRITE_PROTECTED_FLAG; - gc_assert(test.write_protected); - *pflagbits = WP_CLEARED_FLAG; - gc_assert(test.write_protected_cleared); } -static void gc_allocate_ptes() +int gc_card_table_nbits; +long gc_card_table_mask; + +static void __attribute__((unused)) gcbarrier_patch_code_range(uword_t start, void* limit) +{ + extern void gcbarrier_patch_code(void*, int); + struct varint_unpacker unpacker; + struct code* code; + lispobj *where = (lispobj*)start; + while (where < (lispobj*)limit) { + if (widetag_of(where) == CODE_HEADER_WIDETAG && ((struct code*)where)->fixups) { + code = (struct code*)where; + varint_unpacker_init(&unpacker, code->fixups); + // There are two other data streams preceding the one we want + skip_data_stream(&unpacker); + skip_data_stream(&unpacker); + char* instructions = code_text_start(code); + int prev_loc = 0, loc; + while (varint_unpack(&unpacker, &loc) && loc != 0) { + loc += prev_loc; + prev_loc = loc; + void* patch_where = instructions + loc; + gcbarrier_patch_code(patch_where, gc_card_table_nbits); + } + } + where += object_size(where); + } +} +void gc_allocate_ptes() { page_index_t i; /* Compute the number of pages needed for the dynamic space. * Dynamic space size should be aligned on page size. */ - page_table_pages = dynamic_space_size/GENCGC_CARD_BYTES; + page_table_pages = dynamic_space_size/GENCGC_PAGE_BYTES; gc_assert(dynamic_space_size == npage_bytes(page_table_pages)); + /* Assert that a cons whose car has MOST-POSITIVE-WORD + * can not be considered a valid cons, which is to say, even though + * MOST-POSITIVE-WORD seems to satisfy is_lisp_pointer(), + * it's OK to use as a filler marker. */ + if (find_page_index((void*)(uword_t)-1) >= 0) + lose("dynamic space too large"); + /* Default nursery size to 5% of the total dynamic space size, * min 1Mb. */ bytes_consed_between_gcs = dynamic_space_size/(os_vm_size_t)20; @@ -4033,15 +4843,68 @@ static void gc_allocate_ptes() #error "FREE_PAGE_FLAG is not 0" #endif - /* An extra struct exists as the end as a sentinel. Its 'scan_start_offset' - * and 'bytes_used' must be zero. - * Doing so avoids testing in page_ends_contiguous_block_p() whether the - * next page_index is within bounds, and whether that page contains data. + /* An extra 'struct page' exists at each end of the page table acting as + * a sentinel. + * + * For for leading sentinel: + * - all fields are zero except that 'gen' has an illegal value + * which makes from_space_p() and new_space_p() both return false + * + * For the trailing sentinel: + * - all fields are zero which makes page_ends_contiguous_block_p() + * return true for the last in-range page index (so the "illegal" + * index at 1+ appears to start a contiguous block even though + * it corresponds to no page) */ - page_table = calloc(1+page_table_pages, sizeof(struct page)); + page_table = calloc(page_table_pages+2, sizeof(struct page)); gc_assert(page_table); - - weakobj_init(); + page_table[0].gen = 9; // an arbitrary never-used value + ++page_table; + gc_page_pins = calloc(page_table_pages, 1); + gc_assert(gc_page_pins); + + // The card table size is a power of 2 at *least* as large + // as the number of cards. These are the default values. + int nbits = 13; + long num_gc_cards = 1L << nbits; + + // Sure there's a fancier way to round up to a power-of-2 + // but this is executed exactly once, so KISS. + while (num_gc_cards < page_table_pages*CARDS_PER_PAGE) { ++nbits; num_gc_cards <<= 1; } + // 2 Gigacards should suffice for now. That would span 2TiB of memory + // using 1Kb card size, or more if larger card size. + gc_assert(nbits < 32); + // If the space size is less than or equal to the number of cards + // that 'gc_card_table_nbits' cover, we're fine. Otherwise, problem. + // 'nbits' is what we need, 'gc_card_table_nbits' is what the core was compiled for. + if (nbits > gc_card_table_nbits) { + gc_card_table_nbits = nbits; +#if defined LISP_FEATURE_MIPS || defined LISP_FEATURE_PPC64 \ + || defined LISP_FEATURE_X86 || defined LISP_FEATURE_X86_64 + // The value needed based on dynamic space size exceeds the value that the + // core was compiled for, so we need to patch all code blobs. + gcbarrier_patch_code_range(READ_ONLY_SPACE_START, read_only_space_free_pointer); + gcbarrier_patch_code_range(STATIC_SPACE_START, static_space_free_pointer); + gcbarrier_patch_code_range(DYNAMIC_SPACE_START, (lispobj*)dynamic_space_highwatermark()); +#ifdef LISP_FEATURE_IMMOBILE_SPACE + gcbarrier_patch_code_range(TEXT_SPACE_START, text_space_highwatermark); +#endif +#endif + } + // Regardless of the mask implied by space size, it has to be gc_card_table_nbits wide + // even if that is excessive - when the core is restarted using a _smaller_ dynamic space + // size than saved at - otherwise lisp could overrun the mark table. + num_gc_cards = 1L << gc_card_table_nbits; + + gc_card_table_mask = num_gc_cards - 1; + gc_card_mark = successful_malloc(num_gc_cards); + /* The mark array used to work "by accident" if the numeric value of CARD_MARKED + * is 0 - or equivalently the "WP'ed" state - which is the value that calloc() + * fills with. If using malloc() we have to fill with CARD_MARKED, + * as I discovered when I changed that to a nonzero value */ + memset(gc_card_mark, CARD_MARKED, num_gc_cards); + + gc_common_init(); hopscotch_create(&pinned_objects, HOPSCOTCH_HASH_FUN_DEFAULT, 0 /* hashset */, 32 /* logical bin count */, 0 /* default range */); @@ -4063,9 +4926,11 @@ static void gc_allocate_ptes() /* Initialize gc_alloc. */ gc_alloc_generation = 0; - gc_init_region(&boxed_region); - gc_init_region(&unboxed_region); - gc_init_region(&code_region); + gc_init_region(mixed_region); + gc_init_region(boxed_region); + gc_init_region(unboxed_region); + gc_init_region(code_region); + gc_init_region(cons_region); } @@ -4081,13 +4946,11 @@ static void gc_allocate_ptes() * The check for a GC trigger is only performed when the current * region is full, so in most cases it's not needed. */ -NO_SANITIZE_MEMORY lispobj* -lisp_alloc(struct alloc_region *region, sword_t nbytes, - int page_type_flag, struct thread *thread) +int gencgc_alloc_profiler; +static NO_SANITIZE_MEMORY lispobj* +lisp_alloc(int flags, struct alloc_region *region, sword_t nbytes, + int page_type, struct thread *thread) { -#ifndef LISP_FEATURE_WIN32 - lispobj alloc_signal; -#endif os_vm_size_t trigger_bytes = 0; gc_assert(nbytes > 0); @@ -4096,24 +4959,36 @@ lisp_alloc(struct alloc_region *region, sword_t nbytes, gc_assert((((uword_t)region->free_pointer & LOWTAG_MASK) == 0) && ((nbytes & LOWTAG_MASK) == 0)); + ++thread->slow_path_allocs; if ((os_vm_size_t) nbytes > large_allocation) large_allocation = nbytes; /* maybe we can do this quickly ... */ + /* I'd really like this "quick" case to be more uniform in terms of whether + * it's allowed to occur at all. Some of the inconsistencies are: + * - 32-bit x86 will (or would, not sure any more) choose to use + * out-of-line allocation if lexical policy favors space. + * - PPC at git rev 28aaa39f4e had a subtle "but-not-wrong" bug at the edge + * where it trapped to C if the new free pointer was ':lge' instead of ':lgt' + * the region end, fixed in rev 05047647. + * - other architectures may have similar issues. + * So because of those reasons, even if we satisfy the allocation + * from the TLAB it might be worth a check of whether to refill + * the TLAB now. */ void *new_obj = region->free_pointer; char *new_free_pointer = (char*)new_obj + nbytes; if (new_free_pointer <= (char*)region->end_addr) { region->free_pointer = new_free_pointer; -#ifdef LISP_FEATURE_X86_64 - // Non-code allocations should never get here - it would mean there's - // something wrong in the inline allocator. This assertion pertains - // to any architecture that always uses an inline allocator. - // That's actually most of them, but I haven't tested that they're right. - // e.g. x86 forgoes inline allocation depending on policy, - // and git revision 05047647 tweaked the edge case for PPC. - gc_assert(page_type_flag == CODE_PAGE_TYPE); +#if defined LISP_FEATURE_MIPS || defined LISP_FEATURE_PPC || \ + defined LISP_FEATURE_PPC64 || defined LISP_FEATURE_X86_64 + /* Most allocations should never get here, but two page types are special. + * - CODE always comes through here. + * - CONS can come through here because when overflow occurs in lisp, + * the fallback logic will call lisp_alloc one or more times, + * obtaining possibly discontiguous pages of conses */ + gc_assert(page_type == PAGE_TYPE_CONS || page_type == PAGE_TYPE_CODE); #endif - return(new_obj); /* yup */ + return new_obj; } /* We don't want to count nbytes against auto_gc_trigger unless we @@ -4135,18 +5010,16 @@ lisp_alloc(struct alloc_region *region, sword_t nbytes, if (read_TLS(GC_PENDING,thread) == NIL) { /* set things up so that GC happens when we finish the PA * section */ - write_TLS(GC_PENDING,T,thread); + write_TLS(GC_PENDING, LISP_T, thread); if (read_TLS(GC_INHIBIT,thread) == NIL) { #ifdef LISP_FEATURE_SB_SAFEPOINT thread_register_gc_trigger(); #else set_pseudo_atomic_interrupted(thread); -#if GENCGC_IS_PRECISE - /* PPC calls alloc() from a trap - * look up the most context if it's from a trap. */ +#if HAVE_ALLOCATION_TRAP_CONTEXT { os_context_t *context = - thread->interrupt_data->allocation_trap_context; + thread_interrupt_data(thread).allocation_trap_context; maybe_save_gc_mask_and_block_deferrables (context ? os_context_sigmask_addr(context) : NULL); } @@ -4157,76 +5030,347 @@ lisp_alloc(struct alloc_region *region, sword_t nbytes, } } } - if (nbytes >= LARGE_OBJECT_SIZE && !(page_type_flag & CONS_PAGE_FLAG)) - new_obj = gc_alloc_large(nbytes, page_type_flag, region); - else { - page_type_flag &= ~CONS_PAGE_FLAG; - ensure_region_closed(region, page_type_flag); - gc_alloc_new_region(nbytes, page_type_flag, region); - new_obj = region->free_pointer; - new_free_pointer = (char*)new_obj + nbytes; - gc_assert(new_free_pointer <= (char*)region->end_addr); - region->free_pointer = new_free_pointer; - // Refill now if the region is almost empty. - // This can often avoid the next Lisp -> C -> Lisp round-trip. - if (addr_diff(region->end_addr, region->free_pointer) <= 4 * N_WORD_BYTES) { - ensure_region_closed(region, page_type_flag); - // Request > 4 words, forcing a new page to be claimed. - gc_alloc_new_region(6 * N_WORD_BYTES, page_type_flag, region); - } - } -#ifndef LISP_FEATURE_WIN32 - /* for sb-prof, and not supported on Windows yet */ - alloc_signal = read_TLS(ALLOC_SIGNAL,thread); - if ((alloc_signal & FIXNUM_TAG_MASK) == 0) { - if ((sword_t) alloc_signal <= 0) { - write_TLS(ALLOC_SIGNAL, T, thread); - raise(SIGPROF); - } else { - write_TLS(ALLOC_SIGNAL, - alloc_signal - (1 << N_FIXNUM_TAG_BITS), - thread); + /* For the architectures which do NOT use a trap instruction for allocation, + * overflow, record a backtrace now if statistical profiling is enabled. + * The ones which use a trap will backtrace from the signal handler. + * Code allocations are ignored, because every code allocation + * comes through lisp_alloc() which makes this not a statistical + * sample. Also the trapping ones don't trap for code. + * #+win32 doesn't seem to work, but neither does CPU profiling */ +#if !(defined LISP_FEATURE_PPC || defined LISP_FEATURE_PPC64 \ + || defined LISP_FEATURE_SPARC || defined LISP_FEATURE_WIN32) + extern void allocator_record_backtrace(void*, struct thread*); + if (page_type != PAGE_TYPE_CODE && gencgc_alloc_profiler + && thread->state_word.sprof_enable) + allocator_record_backtrace(__builtin_frame_address(0), thread); +#endif + + if (flags & 1) return gc_alloc_large(nbytes, page_type); + + int __attribute__((unused)) ret = mutex_acquire(&free_pages_lock); + gc_assert(ret); + ensure_region_closed(region, page_type); + // hold the lock after alloc_new_region if a cons page + int release = page_type != PAGE_TYPE_CONS; + new_obj = gc_alloc_new_region(nbytes, page_type, region, release); + region->free_pointer = (char*)new_obj + nbytes; + // addr_diff asserts that 'end' >= 'free_pointer' + int remaining = addr_diff(region->end_addr, region->free_pointer); + // Try to avoid the next Lisp -> C -> Lisp round-trip by possibly + // requesting yet another region. + if (page_type == PAGE_TYPE_CONS) { + if (remaining <= CONS_SIZE * N_WORD_BYTES) { // Refill now if <= 1 more cons to go + gc_close_region(region, page_type); + // Request > 2 words, forcing a new page to be claimed. + gc_alloc_new_region(4 * N_WORD_BYTES, page_type, region, 0); // don't release } + ret = mutex_release(&free_pages_lock); + gc_assert(ret); + } else if (remaining <= 4 * N_WORD_BYTES + && TryEnterCriticalSection(&free_pages_lock)) { + gc_close_region(region, page_type); + // Request > 4 words, forcing a new page to be claimed. + gc_alloc_new_region(6 * N_WORD_BYTES, page_type, region, 1); // do release } + + return new_obj; +} + +// Code allocation is always serialized +#ifdef LISP_FEATURE_WIN32 +CRITICAL_SECTION code_allocator_lock; // threads are mandatory for win32 +#elif defined LISP_FEATURE_SB_THREAD +static pthread_mutex_t code_allocator_lock = PTHREAD_MUTEX_INITIALIZER; +#endif + +#ifdef LISP_FEATURE_X86_64 + +// The asm routines have been modified so that alloc() and alloc_list() +// each receive the size an a single-bit flag affecting locality of the result. +#define DEFINE_LISP_ENTRYPOINT(name, largep, TLAB, page_type) \ +NO_SANITIZE_MEMORY lispobj AMD64_SYSV_ABI *name(sword_t nbytes, int systemp) { \ + struct thread *self = get_sb_vm_thread(); \ + return lisp_alloc(largep | systemp, \ + systemp ? &self->sys_##TLAB##_tlab : THREAD_ALLOC_REGION(self,TLAB), \ + nbytes, page_type, self); } + +DEFINE_LISP_ENTRYPOINT(alloc, (nbytes >= LARGE_OBJECT_SIZE), mixed, PAGE_TYPE_MIXED) +DEFINE_LISP_ENTRYPOINT(alloc_list, 0, cons, PAGE_TYPE_CONS) + +#else + +#define DEFINE_LISP_ENTRYPOINT(name, largep, tlab, page_type) \ +NO_SANITIZE_MEMORY lispobj AMD64_SYSV_ABI *name(sword_t nbytes) { \ + struct thread *self = get_sb_vm_thread(); \ + return lisp_alloc(largep, THREAD_ALLOC_REGION(self,tlab), nbytes, page_type, self); } + +DEFINE_LISP_ENTRYPOINT(alloc, nbytes >= LARGE_OBJECT_SIZE, mixed, PAGE_TYPE_MIXED) +#ifdef LISP_FEATURE_USE_CONS_REGION +// for this variant of alloc_list to work properly, the allocation vops have to know +// when to use the cons_tlab slot. Otherwise we would inadvertently allocate a CONS page +// for the mixed_tlab region, which would cause all kinds of problems. +DEFINE_LISP_ENTRYPOINT(alloc_list, 0, cons, PAGE_TYPE_CONS) +#else +// Lists will get moved to CONS pages when copied. +DEFINE_LISP_ENTRYPOINT(alloc_list, 0, mixed, PAGE_TYPE_MIXED) +#endif + #endif - return (new_obj); +lispobj AMD64_SYSV_ABI alloc_code_object(unsigned total_words, unsigned boxed) +{ + struct thread *th = get_sb_vm_thread(); + // x86-64 uses pseudo-atomic. Others should too, but instead use WITHOUT-GCING +#ifndef LISP_FEATURE_X86_64 + if (read_TLS(GC_INHIBIT, th) == NIL) + lose("alloc_code_object called with GC enabled."); +#endif + + sword_t nbytes = total_words * N_WORD_BYTES; + /* Allocations of code are all serialized. We might also acquire + * free_pages_lock depending on availability of space in the region */ + int result = mutex_acquire(&code_allocator_lock); + gc_assert(result); + struct code *code = + (void*)lisp_alloc(nbytes >= LARGE_OBJECT_SIZE, code_region, nbytes, PAGE_TYPE_CODE, th); + result = mutex_release(&code_allocator_lock); + gc_assert(result); + THREAD_JIT(0); + + code->header = ((uword_t)total_words << CODE_HEADER_SIZE_SHIFT) | CODE_HEADER_WIDETAG; + // 'boxed_size' is an untagged word expressing the number of *bytes* in the boxed section + // (so CODE-INSTRUCTIONS can simply add rather than shift and add). + code->boxed_size = boxed * N_WORD_BYTES; + code->debug_info = 0; + code->fixups = 0; + lispobj* p = &code->constants[0], *end = (lispobj*)code + boxed; + /* Must intialize to an arbitrary non-pointer value so that GC doesn't crash after the + * size is assigned (at some point prior to storing the constants) */ + for ( ; p < end ; ++p) *p = 0; + *p = 0; // 'p' now points to the jump table count word which must be 0 + ((lispobj*)code)[total_words-1] = 0; // zeroize the simple-fun table count + THREAD_JIT(1); + + return make_lispobj(code, OTHER_POINTER_LOWTAG); } -#ifdef LISP_FEATURE_SB_THREAD -# define MY_REGION &self->alloc_region +#ifdef LISP_FEATURE_X86_64 +NO_SANITIZE_MEMORY lispobj AMD64_SYSV_ABI alloc_funinstance(sword_t nbytes) +{ + struct thread *th = get_sb_vm_thread(); + int result = mutex_acquire(&code_allocator_lock); + gc_assert(result); + void* mem = lisp_alloc(0, code_region, nbytes, PAGE_TYPE_CODE, th); + result = mutex_release(&code_allocator_lock); + gc_assert(result); + memset(mem, 0, nbytes); + return (lispobj)mem; +} + +/* Make a list that couldn't be inline-allocated. Break it up into contiguous + * blocks of conses not to exceed one GC page each. */ +NO_SANITIZE_MEMORY lispobj AMD64_SYSV_ABI +make_list(lispobj element, sword_t nbytes, __attribute__((unused)) int sys) { + // Technically this overflow handler could permit garbage collection + // between separate allocation. For now the entire thing is pseudo-atomic. + struct thread *self = get_sb_vm_thread(); +#ifdef LISP_FEATURE_SYSTEM_TLABS + struct alloc_region *region = sys ? &self->sys_cons_tlab : &self->cons_tlab; +#else + struct alloc_region *region = THREAD_ALLOC_REGION(self, cons); +#endif + int partial_request = (char*)region->end_addr - (char*)region->free_pointer; + gc_assert(nbytes > (sword_t)partial_request); + // We might be even cleverer by accepting however few bytes are actually available + // on any cons page, rather than asking for the maximum. + if (partial_request == 0) partial_request = CONS_PAGE_USABLE_BYTES; + lispobj result, *tail = &result; + do { + if (nbytes < partial_request) partial_request = nbytes; + struct cons* c = (void*)lisp_alloc(0, region, partial_request, PAGE_TYPE_CONS, self); + *tail = make_lispobj((void*)c, LIST_POINTER_LOWTAG); + int ncells = partial_request >> (1+WORD_SHIFT); + nbytes -= N_WORD_BYTES * 2 * ncells; + struct cons* limit = c + ncells; + while (c < limit) { + c->car = element; c->cdr = make_lispobj(c+1, LIST_POINTER_LOWTAG); + ++c; + } + tail = &((c-1)->cdr); + partial_request = CONS_PAGE_USABLE_BYTES; + } while (nbytes); + *tail = NIL; + return result; +} +#endif + +/* Convert a &MORE context to a list. Split it up like make_list if we have to */ +#ifdef LISP_FEATURE_C_STACK_IS_CONTROL_STACK +NO_SANITIZE_MEMORY lispobj AMD64_SYSV_ABI +listify_rest_arg(lispobj* context, sword_t nbytes, __attribute__((unused)) int sys) { + // same comment as above in make_list() applies about the scope of pseudo-atomic + struct thread *self = get_sb_vm_thread(); +#ifdef LISP_FEATURE_SYSTEM_TLABS + struct alloc_region *region = sys ? &self->sys_cons_tlab : &self->cons_tlab; +#else + struct alloc_region *region = THREAD_ALLOC_REGION(self, cons); +#endif + int partial_request = (char*)region->end_addr - (char*)region->free_pointer; + gc_assert(nbytes > (sword_t)partial_request); + if (partial_request == 0) partial_request = CONS_PAGE_USABLE_BYTES; + lispobj result, *tail = &result; + do { + if (nbytes < partial_request) partial_request = nbytes; + struct cons* c = (void*)lisp_alloc(0, region, partial_request, PAGE_TYPE_CONS, self); + *tail = make_lispobj((void*)c, LIST_POINTER_LOWTAG); + int ncells = partial_request >> (1+WORD_SHIFT); + nbytes -= N_WORD_BYTES * 2 * ncells; + // Unroll x 4 + int n_unrolled_iterations = ncells >> 2; + struct cons* limit = c + n_unrolled_iterations * 4; + while (c < limit) { + c[0].car = context[ 0]; c[0].cdr = make_lispobj(c+1, LIST_POINTER_LOWTAG); + c[1].car = context[-1]; c[1].cdr = make_lispobj(c+2, LIST_POINTER_LOWTAG); + c[2].car = context[-2]; c[2].cdr = make_lispobj(c+3, LIST_POINTER_LOWTAG); + c[3].car = context[-3]; c[3].cdr = make_lispobj(c+4, LIST_POINTER_LOWTAG); + c += 4; + context -= 4; + } + ncells -= n_unrolled_iterations * 4; + while (ncells--) { + c->car = *context--; + c->cdr = make_lispobj(c+1, LIST_POINTER_LOWTAG); + c++; + } + tail = &((c-1)->cdr); + partial_request = CONS_PAGE_USABLE_BYTES; + } while (nbytes); + *tail = NIL; + return result; +} #else -# define MY_REGION SINGLE_THREAD_BOXED_REGION +/* Let's assume that all the rest of the architectures work similarly. + * There may be minor variations in how both args get passed */ +NO_SANITIZE_MEMORY lispobj listify_rest_arg(lispobj* context, sword_t context_bytes) { + // same comment as above in make_list() applies about the scope of pseudo-atomic + struct thread *self = get_sb_vm_thread(); + sword_t nbytes = context_bytes * CONS_SIZE; + struct alloc_region *region = THREAD_ALLOC_REGION(self, cons); + int partial_request = (char*)region->end_addr - (char*)region->free_pointer; + gc_assert(nbytes > (sword_t)partial_request); + if (partial_request == 0) partial_request = CONS_PAGE_USABLE_BYTES; + lispobj result, *tail = &result; + do { + if (nbytes < partial_request) partial_request = nbytes; + struct cons* c = (void*)lisp_alloc(0, region, partial_request, PAGE_TYPE_CONS, self); + *tail = make_lispobj((void*)c, LIST_POINTER_LOWTAG); + int ncells = partial_request >> (1+WORD_SHIFT); + nbytes -= N_WORD_BYTES * 2 * ncells; + // Unroll x 4 + int n_unrolled_iterations = ncells >> 2; + struct cons* limit = c + n_unrolled_iterations * 4; + while (c < limit) { + c[0].car = context[ 0]; c[0].cdr = make_lispobj(c+1, LIST_POINTER_LOWTAG); + c[1].car = context[ 1]; c[1].cdr = make_lispobj(c+2, LIST_POINTER_LOWTAG); + c[2].car = context[ 2]; c[2].cdr = make_lispobj(c+3, LIST_POINTER_LOWTAG); + c[3].car = context[ 3]; c[3].cdr = make_lispobj(c+4, LIST_POINTER_LOWTAG); + c += 4; + context += 4; + } + ncells -= n_unrolled_iterations * 4; + while (ncells--) { + c->car = *context++; + c->cdr = make_lispobj(c+1, LIST_POINTER_LOWTAG); + c++; + } + tail = &((c-1)->cdr); + partial_request = CONS_PAGE_USABLE_BYTES; + } while (nbytes); + *tail = NIL; + return result; +} #endif -#ifdef LISP_FEATURE_SB_SAFEPOINT_STRICTLY -// FIXME: I suspect that we can forgo manipulation of the PA flag, which appears -// to have been present here only to satisfy an assertion in lisp_alloc. -# define DEFINE_LISP_ENTRYPOINT(name, page_type) \ - lispobj AMD64_SYSV_ABI *name(sword_t nbytes) { \ - struct thread *self = arch_os_get_current_thread(); \ - int was_pseudo_atomic = get_pseudo_atomic_atomic(self); \ - if (!was_pseudo_atomic) set_pseudo_atomic_atomic(self); \ - lispobj *result = lisp_alloc(MY_REGION, nbytes, page_type, self); \ - if (!was_pseudo_atomic) clear_pseudo_atomic_atomic(self); \ - return result; \ - } +typedef struct { struct alloc_region* r; int type; } close_region_arg; + +static void sync_close_regions(int block_signals, int locking, + close_region_arg* a, int count) +{ + sigset_t savedmask; + __attribute__((unused)) int result; + if (block_signals) block_blockable_signals(&savedmask); + if (locking & LOCK_CODE_ALLOCATOR) { + result = mutex_acquire(&code_allocator_lock); + gc_dcheck(result); + } + if (locking & LOCK_PAGE_TABLE) { + result = mutex_acquire(&free_pages_lock); + gc_dcheck(result); + } + int i; + for(i=0; i<count; ++i) ensure_region_closed(a[i].r, a[i].type); + if (locking & LOCK_PAGE_TABLE) { + result = mutex_release(&free_pages_lock); + gc_dcheck(result); + } + if (locking & LOCK_CODE_ALLOCATOR) { + result = mutex_release(&code_allocator_lock); + gc_dcheck(result); + } + if (block_signals) thread_sigmask(SIG_SETMASK, &savedmask, 0); +} + +#define N_THREAD_TLABS(array) sizeof array / sizeof (close_region_arg) + +/* These two exported "close_x" functions are called from Lisp prior to + * heap-walking. They must never get interrupted by STOP_FOR_GC while holding + * either the free page lock or code allocation lock. + * Normally this is guaranteed by pseudo-atomic, but in the interest of simplicity, + * these are plain foreign calls without aid of a vop. */ +void close_current_thread_tlab() { + __attribute__((unused)) struct thread *self = get_sb_vm_thread(); + /* If the compiler doesn't use the cons region, neither will alloc_list(). + * i.e. we'll never see the cons region used with PAGE_TYPE_MIXED. + * Thus the invariants about page type correctness hold when closing */ + close_region_arg argv[] = { + { THREAD_ALLOC_REGION(self,mixed), PAGE_TYPE_MIXED }, + { THREAD_ALLOC_REGION(self,cons), PAGE_TYPE_CONS }, +#ifdef LISP_FEATURE_SB_THREAD_ + { THREAD_ALLOC_REGION(self,sys_mixed), PAGE_TYPE_MIXED }, + { THREAD_ALLOC_REGION(self,sys_cons), PAGE_TYPE_CONS } +#endif + }; + sync_close_regions(1, LOCK_PAGE_TABLE, argv, N_THREAD_TLABS(argv)); +} +void close_code_region() { + close_region_arg argv = { code_region, PAGE_TYPE_CODE }; + sync_close_regions(1, LOCK_PAGE_TABLE|LOCK_CODE_ALLOCATOR, &argv, 1); +} +/* When this is called by unregister_thread() with STOP_FOR_GC blocked, + * it needs to aquire the page table lock but not the code allocator lock. + * It is also called at the start of GC to close each non-dead thread's regions, + * in which case no locks are needed since all other lisp threads are stopped. */ +void gc_close_thread_regions(__attribute__((unused)) struct thread* th, + int locking) { + close_region_arg argv[] = { +#ifdef LISP_FEATURE_SB_THREAD + { &th->mixed_tlab, PAGE_TYPE_MIXED }, + { &th->cons_tlab, PAGE_TYPE_CONS }, + { &th->sys_mixed_tlab, PAGE_TYPE_MIXED }, + { &th->sys_cons_tlab, PAGE_TYPE_CONS } #else -# define DEFINE_LISP_ENTRYPOINT(name, page_type) \ - NO_SANITIZE_MEMORY lispobj AMD64_SYSV_ABI *name(sword_t nbytes) { \ - struct thread *self = arch_os_get_current_thread(); \ - gc_assert(get_pseudo_atomic_atomic(self)); \ - return lisp_alloc(MY_REGION, nbytes, page_type, self); \ - } + { main_thread_mixed_region, PAGE_TYPE_MIXED }, + { main_thread_cons_region, PAGE_TYPE_CONS }, #endif -DEFINE_LISP_ENTRYPOINT(alloc, BOXED_PAGE_FLAG) -DEFINE_LISP_ENTRYPOINT(alloc_list, BOXED_PAGE_FLAG|CONS_PAGE_FLAG) + }; + sync_close_regions(0, locking, argv, N_THREAD_TLABS(argv)); +} #ifdef LISP_FEATURE_SPARC -void boxed_region_rollback(sword_t size) +void mixed_region_rollback(sword_t size) { - struct alloc_region *region = MY_REGION; + struct alloc_region *region = main_thread_mixed_region; gc_assert(region->free_pointer > region->end_addr); region->free_pointer = (char*)region->free_pointer - size; gc_assert(region->free_pointer >= region->start_addr @@ -4260,17 +5404,10 @@ boolean ignore_memoryfaults_on_unprotected_pages = 0; extern boolean continue_after_memoryfault_on_unprotected_pages; boolean continue_after_memoryfault_on_unprotected_pages = 0; -int -gencgc_handle_wp_violation(void* fault_addr) +int gencgc_handle_wp_violation(__attribute__((unused)) void* context, void* fault_addr) { page_index_t page_index = find_page_index(fault_addr); -#if QSHOW_SIGNALS - FSHOW((stderr, - "heap WP violation? fault_addr=%p, page_index=%"PAGE_INDEX_FMT"\n", - fault_addr, page_index)); -#endif - /* Check whether the fault is within the dynamic space. */ if (page_index == (-1)) { #ifdef LISP_FEATURE_IMMOBILE_SPACE @@ -4286,56 +5423,56 @@ gencgc_handle_wp_violation(void* fault_addr) /* not within the dynamic space -- not our responsibility */ return 0; - } else { -#if CODE_PAGES_USE_SOFT_PROTECTION - gc_assert((page_table[page_index].type & PAGE_TYPE_MASK) != CODE_PAGE_TYPE); -#endif - // There can not be an open region. gc_close_region() does not attempt - // to flip that bit atomically. Other threads in the wp violation handler - // concurrently for the same page are fine because they're all doing - // the same bit operations. - gc_assert(!(page_table[page_index].type & OPEN_REGION_PAGE_FLAG)); - unsigned char *pflagbits = (unsigned char*)&page_table[page_index].gen - 1; - unsigned char flagbits = __sync_fetch_and_add(pflagbits, 0); - if (flagbits & WRITE_PROTECTED_FLAG) { - unprotect_page_index(page_index); - } else if (!ignore_memoryfaults_on_unprotected_pages) { - /* The only acceptable reason for this signal on a heap - * access is that GENCGC write-protected the page. - * However, if two CPUs hit a wp page near-simultaneously, - * we had better not have the second one lose here if it - * does this test after the first one has already set wp=0 - */ - if (!(flagbits & WP_CLEARED_FLAG)) { - void lisp_backtrace(int frames); - lisp_backtrace(10); - fprintf(stderr, - "Fault @ %p, page %"PAGE_INDEX_FMT" not marked as write-protected:\n" - " boxed_region.first_page: %"PAGE_INDEX_FMT"," - " boxed_region.last_page %"PAGE_INDEX_FMT"\n" - " page.scan_start_offset: %"OS_VM_SIZE_FMT"\n" - " page.bytes_used: %u\n" - " page.allocated: %d\n" - " page.write_protected: %d\n" - " page.write_protected_cleared: %d\n" - " page.generation: %d\n", - fault_addr, - page_index, - find_page_index(boxed_region.start_addr), - boxed_region.last_page, - (uintptr_t)page_scan_start_offset(page_index), - page_bytes_used(page_index), - page_table[page_index].type, - page_table[page_index].write_protected, - page_table[page_index].write_protected_cleared, - page_table[page_index].gen); - if (!continue_after_memoryfault_on_unprotected_pages) - lose("Feh."); - } + } +#ifdef LISP_FEATURE_SOFT_CARD_MARKS + lose("misuse of mprotect() on dynamic space @ %p", fault_addr); +#else + // Pages of code are never have MMU-based protection, except on darwin, + // where they do, but they are thread-locally-un-protected when creating + // objets on those pages. + gc_assert(!is_code(page_table[page_index].type)); + + // There can not be an open region. gc_close_region() does not attempt + // to flip that bit atomically. (What does this mean?) + gc_assert(!(page_table[page_index].type & OPEN_REGION_PAGE_FLAG)); + + // The collector should almost never incur page faults, but I haven't + // found all the trouble spots. It may or may not be worth doing. + // See git rev 8a0af65bfd24 + // if (gc_active_p && compacting_p()) lose("unexpected WP fault @ %p during GC", fault_addr); + + // Because this signal handler can not be interrupted by STOP_FOR_GC, + // the only possible state change between reading the mark and deciding how + // to proceed is due to another thread also unprotecting the address. + // That's fine; in fact it's OK to read a stale value here. + // The only harmful case would be where the mark byte says it was + // never protected, and the fault occurred nonetheless. That can't happen. + unsigned char mark = gc_card_mark[addr_to_card_index(fault_addr)]; + switch (mark) { + case CARD_UNMARKED: + case WP_CLEARED_AND_MARKED: // possible data race + unprotect_page(fault_addr, WP_CLEARED_AND_MARKED); + break; + default: + if (!ignore_memoryfaults_on_unprotected_pages) { + void lisp_backtrace(int frames); + lisp_backtrace(10); + fprintf(stderr, + "Fault @ %p, PC=%p, page %"PAGE_INDEX_FMT" (~WP) mark=%#x gc_active=%d\n" + " mixed_region=%p:%p\n" + " page.scan_start: %p .words_used: %u .type: %d .gen: %d\n", + fault_addr, (void*)(context?os_context_pc(context):(uword_t)-1), page_index, + mark, gc_active_p, + mixed_region->start_addr, mixed_region->end_addr, + page_scan_start(page_index), + page_words_used(page_index), + page_table[page_index].type, + page_table[page_index].gen); + if (!continue_after_memoryfault_on_unprotected_pages) lose("Feh."); } - /* Don't worry, we can handle it. */ - return 1; } +#endif + return 1; // Handled } /* This is to be called when we catch a SIGSEGV/SIGBUS, determine that * it's not just a case of the program hitting the write barrier, and @@ -4351,55 +5488,49 @@ zero_all_free_ranges() /* called only by gc_and_save() */ page_index_t i; for (i = 0; i < next_free_page; i++) { char* start = page_address(i); - char* page_end = start + GENCGC_CARD_BYTES; + char* page_end = start + GENCGC_PAGE_BYTES; start += page_bytes_used(i); memset(start, 0, page_end-start); } +#ifndef LISP_FEATURE_SB_THREAD + // zero the allocation regions at the start of static-space + // This gets a spurious warning: + // warning: 'memset' offset [0, 71] is out of the bounds [0, 0] [-Warray-bounds] + // which 'volatile' works around. + char * volatile region = (char*)STATIC_SPACE_START; + bzero((char*)region, 3*sizeof (struct alloc_region)); +#endif } -/* Things to do before doing a final GC before saving a core (without - * purify). +/* Things to do before doing a final GC before saving a core. * - * + Pages in singleton pages aren't moved by the GC, so we need to + * + Single-object pages aren't moved by the GC, so we need to * unset that flag from all pages. - * + The pseudo-static generation isn't normally collected, but it seems - * reasonable to collect it at least when saving a core. So move the - * pages to a normal generation. + * + Change all pages' generations to 0 so that we can do all the collection + * in a single invocation of collect_generation() + * + Instances on unboxed pages need to have their layout pointer visited, + * so all pages have to be turned to boxed. */ -static void -prepare_for_final_gc () +static void prepare_dynamic_space_for_final_gc() { page_index_t i; - prepare_immobile_space_for_final_gc (); for (i = 0; i < next_free_page; i++) { // Compaction requires that we permit large objects to be copied henceforth. // Object of size >= LARGE_OBJECT_SIZE get re-allocated to single-object pages. page_table[i].type &= ~SINGLE_OBJECT_FLAG; - if (page_table[i].gen == PSEUDO_STATIC_GENERATION) { + // Turn every page to boxed so that the layouts of instances + // which were relocated to unboxed pages get scanned and fixed. + if ((page_table[i].type & PAGE_TYPE_MASK) == PAGE_TYPE_UNBOXED) + page_table[i].type = PAGE_TYPE_MIXED; + generation_index_t gen = page_table[i].gen; + if (gen != 0) { int used = page_bytes_used(i); - page_table[i].gen = HIGHEST_NORMAL_GENERATION; - generations[PSEUDO_STATIC_GENERATION].bytes_allocated -= used; - generations[HIGHEST_NORMAL_GENERATION].bytes_allocated += used; + page_table[i].gen = 0; + generations[gen].bytes_allocated -= used; + generations[0].bytes_allocated += used; } } - -#ifdef LISP_FEATURE_SB_THREAD - // Avoid tenuring of otherwise-dead objects referenced by - // dynamic bindings which disappear on image restart. - struct thread *thread = arch_os_get_current_thread(); - char *start = (char*)(thread + 1); - char *end = (char*)thread + dynamic_values_bytes; - memset(start, 0, end-start); -#endif - // Make sure that it's done after zeroing above, the GC needs to - // see a list there -#ifdef PINNED_OBJECTS - struct thread *th; - for_each_thread(th) { - write_TLS(PINNED_OBJECTS, NIL, th); - } -#endif } /* Set this switch to 1 for coalescing of strings dumped to fasl, @@ -4407,13 +5538,25 @@ prepare_for_final_gc () * plus literal strings in code compiled to memory. */ char gc_coalesce_string_literals = 0; +extern void move_rospace_to_dynamic(int), prepare_readonly_space(int,int); + /* Do a non-conservative GC, and then save a core with the initial * function being set to the value of 'lisp_init_function' */ void -gc_and_save(char *filename, boolean prepend_runtime, +gc_and_save(char *filename, boolean prepend_runtime, boolean purify, boolean save_runtime_options, boolean compressed, int compression_level, int application_type) { +#if defined LISP_FEATURE_SPARC && defined LISP_FEATURE_LINUX + /* OS says it'll give you the memory where you want, then it says + * it won't map over it from the core file. That's news to me. + * Fragment of output from 'strace -e mmap2 src/runtime/sbcl --core output/sbcl.core': + * ... + * mmap2(0x2fb58000, 4882432, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_ANONYMOUS|MAP_NORESERVE, -1, 0) = 0x2fb58000 + * mmap2(0x2fb58000, 4882432, PROT_READ, MAP_SHARED|MAP_FIXED, 3, 0x2000) = -1 EINVAL (Invalid argument) + */ + purify = 0; +#endif FILE *file; void *runtime_bytes = NULL; size_t runtime_size; @@ -4436,10 +5579,7 @@ gc_and_save(char *filename, boolean prepend_runtime, { int i; for (i=0; i<NSIG; ++i) - // BUG: if a C function pointer can be misaligned such that it - // looks to satisfy functionp() then we do the wrong thing. - if (functionp(interrupt_handlers[i].lisp)) - interrupt_handlers[i].lisp = 0; + lisp_sig_handlers[i] = 0; } #endif @@ -4476,20 +5616,31 @@ gc_and_save(char *filename, boolean prepend_runtime, * as empty pages, because we can't represent discontiguous ranges. */ conservative_stack = 0; - /* We MUST collect all generations now, or else the coalescing by similarity - * would have to be extra cautious not to create any old->young pointers. - * Resetting oldest_gen_to_gc to its default is legal, because it is merely - * a hint to the collector that no significant amount of memory would be - * freed by increasingly aggressive levels of collection. It is NOT a mandate - * that some objects be retained despite appearing to be unreachable. - */ - gencgc_oldest_gen_to_gc = HIGHEST_NORMAL_GENERATION; + gencgc_oldest_gen_to_gc = 0; + // Avoid tenuring of otherwise-dead objects referenced by + // dynamic bindings which disappear on image restart. + struct thread *thread = get_sb_vm_thread(); + char *start = (char*)&thread->lisp_thread; + char *end = (char*)thread + dynamic_values_bytes; + memset(start, 0, end-start); + // After zeroing, make sure PINNED_OBJECTS is a list again. + write_TLS(PINNED_OBJECTS, NIL, thread); // From here on until exit, there is no chance of continuing // in Lisp if something goes wrong during GC. - prepare_for_final_gc(); + // Flush regions to ensure heap scan in copy_rospace doesn't miss anything + gc_close_thread_regions(thread, 0); + gc_close_collector_regions(0); + move_rospace_to_dynamic(0); + pre_verify_gen_0 = 1; + prepare_immobile_space_for_final_gc(); // once is enough + prepare_dynamic_space_for_final_gc(); unwind_binding_stack(); + save_lisp_gc_iteration = 1; gencgc_alloc_start_page = next_free_page; - collect_garbage(HIGHEST_NORMAL_GENERATION+1); + collect_garbage(0); + verify_heap(0, VERIFY_POST_GC); + + THREAD_JIT(0); // We always coalesce copyable numbers. Additional coalescing is done // only on request, in which case a message is shown (unless verbose=0). @@ -4497,28 +5648,28 @@ gc_and_save(char *filename, boolean prepend_runtime, printf("[coalescing similar vectors... "); fflush(stdout); } - /* FIXME: add comment explaining why coalescing is deferred until - * after the penultimate GC. Must it wait ? */ + // Now that we've GC'd to eliminate as much junk as possible... coalesce_similar_objects(); if (gc_coalesce_string_literals && verbose) printf("done]\n"); - /* FIXME: now that relocate_heap() works, can we just memmove() everything - * down and perform a relocation instead of a collection? */ + // Do a non-moving collection so that orphaned strings that result + // from coalescing STRING= symbol names do not consume read-only space. + collect_garbage(1+PSEUDO_STATIC_GENERATION); + prepare_readonly_space(purify, 0); if (verbose) { printf("[performing final GC..."); fflush(stdout); } - prepare_for_final_gc(); + prepare_dynamic_space_for_final_gc(); + save_lisp_gc_iteration = 2; gencgc_alloc_start_page = 0; - collect_garbage(HIGHEST_NORMAL_GENERATION+1); -#ifdef SINGLE_THREAD_BOXED_REGION // clean up static-space object pre-save. - gc_init_region(SINGLE_THREAD_BOXED_REGION); -#endif + collect_garbage(0); /* All global allocation regions should be empty */ ASSERT_REGIONS_CLOSED(); // Enforce (rather, warn for lack of) self-containedness of the heap - verify_heap(VERIFY_FINAL | VERIFY_QUICK); + verify_heap(0, VERIFY_FINAL | VERIFY_QUICK); if (verbose) printf(" done]\n"); + THREAD_JIT(0); // Scrub remaining garbage zero_all_free_ranges(); // Assert that defrag will not move the init_function @@ -4531,11 +5682,6 @@ gc_and_save(char *filename, boolean prepend_runtime, #endif os_unlink_runtime(); - /* The number of dynamic space pages saved is based on the allocation - * pointer, while the number of PTEs is based on next_free_page. - * Make sure they agree */ - gc_assert((char*)get_alloc_pointer() == page_address(next_free_page)); - if (prepend_runtime) save_runtime_to_filehandle(file, runtime_bytes, runtime_size, application_type); @@ -4550,20 +5696,45 @@ gc_and_save(char *filename, boolean prepend_runtime, lose("Attempt to save core after non-conservative GC failed."); } +#ifdef LISP_FEATURE_DARWIN_JIT +/* Inexplicably, an executable page can generate spurious faults if + * it's not written to after changing its protection flags. + * Touch every page... */ +void darwin_jit_code_pages_kludge () { + THREAD_JIT(0); + page_index_t page; + for (page = 0; page < next_free_page; page++) { + if(is_code(page_table[page].type)) { + char* addr = page_address(page); + for (unsigned i = 0; i < GENCGC_PAGE_BYTES; i+=4096) { + volatile char* page_start = addr + i; + page_start[0] = page_start[0]; + } + } + } + THREAD_JIT(1); +} +#endif + /* Read corefile ptes from 'fd' which has already been positioned * and store into the page table */ -void gc_load_corefile_ptes(core_entry_elt_t n_ptes, core_entry_elt_t total_bytes, - off_t offset, int fd) +void gc_load_corefile_ptes(int card_table_nbits, + core_entry_elt_t n_ptes, core_entry_elt_t total_bytes, + os_vm_offset_t offset, int fd) { - compute_layout_of_layout(); gc_assert(ALIGN_UP(n_ptes * sizeof (struct corefile_pte), N_WORD_BYTES) == (size_t)total_bytes); + if (next_free_page != n_ptes) + lose("n_PTEs=%"PAGE_INDEX_FMT" but expected %"PAGE_INDEX_FMT, + n_ptes, next_free_page); // Allocation of PTEs is delayed 'til now so that calloc() doesn't // consume addresses that would have been taken by a mapped space. + gc_card_table_nbits = card_table_nbits; gc_allocate_ptes(); - if (lseek(fd, offset, SEEK_SET) != offset) lose("failed seek"); + if (LSEEK(fd, offset, SEEK_SET) != offset) lose("failed seek"); + char data[8192]; // Process an integral number of ptes on each read. // Parentheses around sizeof (type) are necessary to suppress a @@ -4582,55 +5753,76 @@ void gc_load_corefile_ptes(core_entry_elt_t n_ptes, core_entry_elt_t total_bytes for ( i = 0 ; i < npages ; ++i, ++page ) { struct corefile_pte pte; memcpy(&pte, data+i*sizeof (struct corefile_pte), sizeof pte); - // Low 2 bits of the corefile_pte hold the 'type' flags. - // Low bit of bytes_used indicates a large (a/k/a single) object. - char type = ((pte.bytes_used & 1) ? SINGLE_OBJECT_FLAG : 0) - | (pte.sso & 0x03); + // Low 3 bits of the scan_start hold the 'type' flags. + // Low bit of words_used indicates a large (a/k/a single) object. + char type = ((pte.words_used & 1) ? SINGLE_OBJECT_FLAG : 0) + | (pte.sso & 0x07); page_table[page].type = type; - pte.bytes_used &= ~1; + pte.words_used &= ~1; + /* It is possible, though rare, for the saved page table + * to contain free pages below alloc_ptr. */ if (type != FREE_PAGE_FLAG) { - /* It is possible, though rare, for the saved page table - * to contain free pages below alloc_ptr. */ - set_page_bytes_used(page, pte.bytes_used); - set_page_scan_start_offset(page, pte.sso & ~0x03); + gc_assert(pte.words_used); + page_table[page].words_used_ = pte.words_used; + set_page_scan_start_offset(page, pte.sso & ~0x07); page_table[page].gen = gen; - set_page_need_to_zero(page, 1); } - bytes_allocated += pte.bytes_used; + bytes_allocated += pte.words_used << WORD_SHIFT; } } generations[gen].bytes_allocated = bytes_allocated; - gc_assert((ssize_t)bytes_allocated <= - ((char*)get_alloc_pointer() - page_address(0))); - // write-protecting needs the current value of next_free_page - next_free_page = n_ptes; + gc_assert((ssize_t)bytes_allocated <= (ssize_t)(n_ptes * GENCGC_PAGE_BYTES)); if (gen != 0 && ENABLE_PAGE_PROTECTION) { +#ifdef LISP_FEATURE_SOFT_CARD_MARKS + page_index_t p; + for (p = 0; p < next_free_page; ++p) + if (page_words_used(p)) assign_page_card_marks(p, CARD_UNMARKED); +#else // coreparse can avoid hundreds to thousands of mprotect() calls by // treating the whole range from the corefile as protectable, except // that soft-marked code pages must NOT be subject to mprotect. // So just watch out for empty pages and code. Unboxed object pages // will get unprotected on demand. -#define non_protectable_page_p(x) !page_bytes_used(x) || \ - (CODE_PAGES_USE_SOFT_PROTECTION && \ - (page_table[x].type & PAGE_TYPE_MASK) == CODE_PAGE_TYPE) +#define non_protectable_page_p(x) !page_words_used(x) || is_code(page_table[x].type) page_index_t start = 0, end; // cf. write_protect_generation_pages() while (start < next_free_page) { +#ifdef LISP_FEATURE_DARWIN_JIT + if(is_code(page_table[start].type)) { + SET_PAGE_PROTECTED(start,1); + for (end = start + 1; end < next_free_page; end++) { + if (!page_words_used(end) || !is_code(page_table[end].type)) + break; + SET_PAGE_PROTECTED(end,1); + } + os_protect(page_address(start), npage_bytes(end - start), OS_VM_PROT_ALL); + start = end+1; + continue; + } +#endif if (non_protectable_page_p(start)) { ++start; continue; } - page_table[start].write_protected = 1; + SET_PAGE_PROTECTED(start,1); for (end = start + 1; end < next_free_page; end++) { - if (non_protectable_page_p(end)) break; - page_table[end].write_protected = 1; + if (non_protectable_page_p(end)) + break; + SET_PAGE_PROTECTED(end,1); } - os_protect(page_address(start), - npage_bytes(end - start), - OS_VM_PROT_READ | OS_VM_PROT_EXECUTE); + os_protect(page_address(start), npage_bytes(end - start), OS_VM_PROT_JIT_READ); start = end; } +#endif } + +#ifdef LISP_FEATURE_DARWIN_JIT + darwin_jit_code_pages_kludge(); + /* For some reason doing an early pthread_jit_write_protect_np sometimes fails. + Which is weird, because it's done many times in arch_write_linkage_table_entry later. + Adding the executable bit here avoids calling pthread_jit_write_protect_np */ + os_protect((os_vm_address_t)STATIC_CODE_SPACE_START, STATIC_CODE_SPACE_SIZE, OS_VM_PROT_ALL); +#endif } /* Prepare the array of corefile_ptes for save */ @@ -4638,54 +5830,39 @@ void gc_store_corefile_ptes(struct corefile_pte *ptes) { page_index_t i; for (i = 0; i < next_free_page; i++) { - /* Thanks to alignment requirements, the two low bits + /* Thanks to alignment requirements, the two three bits * are always zero, so we can use them to store the * allocation type -- region is always closed, so only - * the two low bits of allocation flags matter. */ + * the three low bits of allocation flags matter. */ uword_t word = page_scan_start_offset(i); - gc_assert((word & 0x03) == 0); - ptes[i].sso = word | (0x03 & page_table[i].type); - page_bytes_t used = page_bytes_used(i); - gc_assert(!(used & LOWTAG_MASK)); - ptes[i].bytes_used = used | page_single_obj_p(i); + gc_assert((word & 0x07) == 0); + ptes[i].sso = word | (0x07 & page_table[i].type); + int used = page_table[i].words_used_; + gc_assert(!(used & 1)); + ptes[i].words_used = used | page_single_obj_p(i); } } -void gc_show_pte(lispobj obj) -{ - page_index_t page = find_page_index((void*)obj); - if (page>=0) { - printf("page %"PAGE_INDEX_FMT" gen %d type %x ss %p used %x%s\n", - page, page_table[page].gen, page_table[page].type, - page_scan_start(page), page_bytes_used(page), - page_table[page].write_protected? " WP":""); - return; - } +#define ARTIFICIALLY_HIGH_GEN 8 +generation_index_t gc_gen_of(lispobj obj, int defaultval) { + int page = find_page_index((void*)obj); + if (page >= 0) return page_table[page].gen; #ifdef LISP_FEATURE_IMMOBILE_SPACE - page = find_varyobj_page_index((void*)obj); - if (page>=0) { - printf("page %ld (v) ss=%p gens %x%s\n", page, - varyobj_scan_start(page), - varyobj_pages[page].generations, - card_protected_p((void*)obj)? " WP":""); - return; - } - page = find_fixedobj_page_index((void*)obj); - if (page>=0) { - printf("page %ld (f) align %d gens %x%s\n", page, - fixedobj_pages[page].attr.parts.obj_align, - fixedobj_pages[page].attr.parts.gens_, - card_protected_p((void*)obj)? " WP":""); - return; - } + if (immobile_space_p(obj)) + return immobile_obj_generation(base_pointer(obj)); #endif - printf("not in GC'ed space\n"); + return defaultval; } -// Return 1 if 'a' is strictly younger than 'b'. +/* Return 1 if 'a' is strictly younger than 'b'. + * This asserts that 'a' is pinned if in 'from_space' because it is + * specifically a helper function for scav_code_blob(), where this is + * called after scavenging the header. So if something didn't get moved + * out of from_space, then it must have been pinned. + * So don't call this for anything except that use-case. */ static inline boolean obj_gen_lessp(lispobj obj, generation_index_t b) { - generation_index_t a = gen_of(obj); + generation_index_t a = gc_gen_of(obj, ARTIFICIALLY_HIGH_GEN); if (a == from_space) { gc_assert(pinned_p(obj, find_page_index((void*)obj))); a = new_space; @@ -4693,12 +5870,16 @@ static inline boolean obj_gen_lessp(lispobj obj, generation_index_t b) return ((a==SCRATCH_GENERATION) ? from_space : a) < b; } -sword_t scav_code_header(lispobj *object, lispobj header) +sword_t scav_code_blob(lispobj *object, lispobj header) { + struct code* code = (struct code*)object; + int nboxed = code_header_words(code); + if (!nboxed) goto done; + ++n_scav_calls[CODE_HEADER_WIDETAG/4]; - int my_gen = gc_gen_of((lispobj)object, 127); - if (my_gen < 127 && ((my_gen & 7) == from_space)) { + int my_gen = gc_gen_of((lispobj)object, ARTIFICIALLY_HIGH_GEN); + if (my_gen < ARTIFICIALLY_HIGH_GEN && ((my_gen & 7) == from_space)) { // Since 'from_space' objects are not directly scavenged - they can // only be scavenged after moving to newspace, then this object // must be pinned. (It's logically in newspace). Assert that. @@ -4706,7 +5887,6 @@ sword_t scav_code_header(lispobj *object, lispobj header) find_page_index(object))); my_gen = new_space; } - struct code* code = (struct code*)object; // If the header's 'written' flag is off and it was not copied by GC // into newspace, then the object should be ignored. @@ -4719,8 +5899,8 @@ sword_t scav_code_header(lispobj *object, lispobj header) // that got copied as written, which would allow dropping the second half // of the OR condition. As is, we scavenge "too much" of newspace which // is not an issue of correctness but rather efficiency. - if (!CODE_PAGES_USE_SOFT_PROTECTION || header_rememberedp(header) - || (my_gen == new_space)) { + if (header_rememberedp(header) || (my_gen == new_space) || + ((uword_t)object >= STATIC_SPACE_START && object < static_space_free_pointer)) { // FIXME: We sometimes scavenge protected pages. // This assertion fails, but things work nonetheless. // gc_assert(!card_protected_p(object)); @@ -4731,10 +5911,9 @@ sword_t scav_code_header(lispobj *object, lispobj header) #ifdef LISP_FEATURE_UNTAGGED_FDEFNS // Process each untagged fdefn pointer. - // If CODE_PAGES_USE_SOFT_PROTECTION were enabled along with untagged fdefns, - // then the generation check at the bottom of this function would have to be - // modified to take into account untagged pointers. - lispobj* fdefns_start = code->constants + code_n_funs(code) * 4; + // TODO: assert that the generation of any fdefn is older than that of 'code'. + lispobj* fdefns_start = code->constants + code_n_funs(code) + * CODE_SLOTS_PER_SIMPLE_FUN; int n_fdefns = code_n_named_calls(code); int i; for (i=0; i<n_fdefns; ++i) { @@ -4749,12 +5928,12 @@ sword_t scav_code_header(lispobj *object, lispobj header) } #endif -#ifdef LISP_FEATURE_64_BIT +#if defined LISP_FEATURE_64_BIT && !defined LISP_FEATURE_DARWIN_JIT /* If any function in this code object redirects to a function outside * the object, then scavenge all entry points. Otherwise there is no need, * as trans_code() made necessary adjustments to internal entry points. * This test is just an optimization to avoid some work */ - if (((*object >> 8) & 0xff) == CODE_IS_TRACED) { + if (((*object >> 16) & 0xff) == CODE_IS_TRACED) { #else { /* Not enough spare bits in the header to hold random flags. * Just do the extra work always */ @@ -4773,7 +5952,7 @@ sword_t scav_code_header(lispobj *object, lispobj header) * pointers. If my_gen is newspace, there can be no such pointers * because newspace is the lowest numbered generation post-GC * (regardless of whether this is a promotion cycle) */ - if (CODE_PAGES_USE_SOFT_PROTECTION && my_gen != new_space) { + if (my_gen != new_space) { lispobj *where, *end = object + n_header_words, ptr; for (where= object + 2; where < end; ++where) if (is_lisp_pointer(ptr = *where) && obj_gen_lessp(ptr, my_gen)) @@ -4786,3 +5965,30 @@ sword_t scav_code_header(lispobj *object, lispobj header) done: return code_total_nwords(code); } + +// For the standalone ldb monitor +void recompute_gen_bytes_allocated() { + page_index_t page; + int gen; + for (gen=0; gen<NUM_GENERATIONS; ++gen) + generations[gen].bytes_allocated = 0; + for (page=0; page<next_free_page; ++page) + generations[page_table[page].gen].bytes_allocated += page_bytes_used(page); + bytes_allocated = 0; + for (gen=0; gen<NUM_GENERATIONS; ++gen) + bytes_allocated += generations[gen].bytes_allocated; +} + +void really_note_transporting(lispobj old,void*new,sword_t nwords) +{ + page_index_t p = find_page_index((void*)old); + __attribute__((unused)) uword_t page_usage_limit = (uword_t)((lispobj*)page_address(p) + page_words_used(p)); + gc_assert(old < (uword_t)page_usage_limit); // this helps find bogus pointers + if (GC_LOGGING) + fprintf(gc_activitylog(), + listp(old)?"t %"OBJ_FMTX" %"OBJ_FMTX"\n": + "t %"OBJ_FMTX" %"OBJ_FMTX" %x\n", + old, (uword_t)new, (int)nwords); +} + +#include "verify.inc" diff --git a/src/runtime/getallocptr.h b/src/runtime/getallocptr.h deleted file mode 100644 index 070df36345..0000000000 --- a/src/runtime/getallocptr.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * macros for getting/setting the end of dynamic space - * and manipulating pseudo-atomic flags (per thread, if applicable) - */ - -/* - * This software is part of the SBCL system. See the README file for - * more information. - * - * This software is derived from the CMU CL system, which was - * written at Carnegie Mellon University and released into the - * public domain. The software is in the public domain and is - * provided with absolutely no warranty. See the COPYING and CREDITS - * files for more information. - */ - -#ifndef GETALLOCPTR_H -#define GETALLOCPTR_H - -#if defined LISP_FEATURE_X86 || defined LISP_FEATURE_X86_64 -#include "allocptr-x86.inc" -#elif defined LISP_FEATURE_ARM || defined LISP_FEATURE_ARM64 || defined LISP_FEATURE_RISCV -#include "allocptr-lisp-symbol.inc" -#else -#include "allocptr-c-symbol.inc" -#endif - -#endif /* GETALLOCPTR_H */ diff --git a/src/runtime/globals.c b/src/runtime/globals.c index 652b524885..a76ec58870 100644 --- a/src/runtime/globals.c +++ b/src/runtime/globals.c @@ -50,41 +50,28 @@ lispobj *current_control_frame_pointer; lispobj *current_binding_stack_pointer; #endif -/* ARM + RISCV use ALLOCATION-POINTER, not dynamic_space_free_pointer */ - -# if !(defined LISP_FEATURE_ARM || defined LISP_FEATURE_ARM64 || defined LISP_FEATURE_RISCV) -/* The Object Formerly Known As current_dynamic_space_free_pointer */ -/* The ARM ports (32- and 64-bit) use a static-space lisp symbol for this pointer. - * They also do not have a reg_ALLOC, so there is no ambiguity as to where the - * pointer is obtained from: it is always in the static-space lisp symbol. - * We do not copy that value back and forth to the C variable. - * Moreover, because they do not have a reg_ALLOC, the pseudo-atomic flag - * is not overlayed on the reg_ALLOC but is instead in another static-space - * lisp symbol */ -lispobj *dynamic_space_free_pointer; -#endif lispobj *read_only_space_free_pointer; lispobj *static_space_free_pointer; + +#ifdef LISP_FEATURE_DARWIN_JIT +lispobj *static_code_space_free_pointer; +#endif + #ifdef LISP_FEATURE_IMMOBILE_SPACE -lispobj *varyobj_free_pointer; +lispobj *text_space_highwatermark; lispobj *fixedobj_free_pointer; +lispobj ALIEN_LINKAGE_TABLE_SPACE_START; #endif os_vm_address_t anon_dynamic_space_start; +// The end of immobile text mapped from disk, equivalently the starting address +// of new objects handed out by the code allocator. +lispobj* tlsf_mem_start; // meaningful only if immobile space #ifndef LISP_FEATURE_GENCGC /* GENCGC has its own way to record trigger */ lispobj *current_auto_gc_trigger; #endif -/* For cheneygc, this points to the start of the semi-space currently in use - * (that will become the from_space when the next GC is done). - * Gencgc defines it as DYNAMIC_SPACE_START via a C preprocessor macro. */ -#ifdef LISP_FEATURE_CHENEYGC -lispobj *current_dynamic_space; -#endif - -#if defined(LISP_FEATURE_SB_THREAD) && !defined(LISP_FEATURE_GCC_TLS) -pthread_key_t specials=0; -#endif +lispobj lisp_package_vector; void globals_init(void) { @@ -111,8 +98,4 @@ void globals_init(void) foreign_function_call_active = 1; #endif #endif - -#if defined(LISP_FEATURE_SB_THREAD) && !defined(LISP_FEATURE_GCC_TLS) - pthread_key_create(&specials,0); -#endif } diff --git a/src/runtime/globals.h b/src/runtime/globals.h index 9009df007b..88d9410d69 100644 --- a/src/runtime/globals.h +++ b/src/runtime/globals.h @@ -23,9 +23,19 @@ #ifndef __ASSEMBLER__ +extern sword_t next_free_page; +#define dynamic_space_highwatermark() (next_free_page*GENCGC_PAGE_BYTES+DYNAMIC_SPACE_START) + #ifdef LISP_FEATURE_SB_THREAD + +#ifdef LISP_FEATURE_ARM64 +#define foreign_function_call_active_p(thread) \ + (thread->control_stack_pointer) +#else #define foreign_function_call_active_p(thread) \ (thread->foreign_function_call_active) +#endif + #else extern int foreign_function_call_active; #define foreign_function_call_active_p(thread) \ @@ -35,18 +45,22 @@ extern int foreign_function_call_active; extern os_vm_size_t dynamic_space_size; extern os_vm_size_t thread_control_stack_size; +#ifndef LISP_FEATURE_DARWIN_JIT +extern uword_t READ_ONLY_SPACE_START, READ_ONLY_SPACE_END; +#endif #ifdef LISP_FEATURE_CHENEYGC extern uword_t DYNAMIC_0_SPACE_START, DYNAMIC_1_SPACE_START; #else extern uword_t DYNAMIC_SPACE_START; #endif #ifdef LISP_FEATURE_IMMOBILE_SPACE -extern uword_t FIXEDOBJ_SPACE_START, VARYOBJ_SPACE_START; +extern uword_t FIXEDOBJ_SPACE_START, TEXT_SPACE_START; extern uword_t immobile_space_lower_bound, immobile_space_max_offset; extern uword_t immobile_range_1_max_offset, immobile_range_2_min_offset; -extern unsigned int varyobj_space_size; +extern unsigned int text_space_size; #endif extern uword_t asm_routines_start, asm_routines_end; +extern int gc_card_table_nbits; static inline lispobj points_to_asm_code_p(uword_t ptr) { return asm_routines_start <= ptr && ptr < asm_routines_end; @@ -63,10 +77,6 @@ extern lispobj alloc_profile_data; // Lisp SIMPLE-VECTOR #endif extern char **ENVIRON; -#if defined(LISP_FEATURE_SB_THREAD) && !defined(LISP_FEATURE_GCC_TLS) -extern pthread_key_t specials; -#endif - #if !defined(LISP_FEATURE_SB_THREAD) extern lispobj *current_control_stack_pointer; #endif @@ -77,109 +87,81 @@ extern lispobj *current_control_frame_pointer; extern lispobj *current_binding_stack_pointer; #endif -/* FIXME: the comment below this is obsolete. Most backends do want to use - * 'dynamic_space_free_pointer' contrary to the claim that it is only intended - * for cheneygc. The exact combinations of GC kind, architecture, and threads - * vs. no threads make it extremely confusing the figure out and document - * the state of things. Somebody should do that. */ - -/* This is unused on X86 and X86_64, but is used as the global - * allocation pointer by the cheney GC, and, in some instances, as - * the global allocation pointer on PPC/GENCGC. This should probably - * be cleaned up such that it only needs to exist on cheney. At the - * moment, it is also used by the GENCGC, to hold the pseudo_atomic - * bits, and is tightly coupled to reg_ALLOC by the assembly - * routines. */ -#if !(defined LISP_FEATURE_ARM || defined LISP_FEATURE_ARM64 || defined LISP_FEATURE_RISCV) -extern lispobj *dynamic_space_free_pointer; -#endif extern lispobj *read_only_space_free_pointer; extern lispobj *static_space_free_pointer; + +static inline boolean readonly_space_p(lispobj ptr) { + return ptr >= READ_ONLY_SPACE_START && (lispobj*)ptr < read_only_space_free_pointer; +} + +#ifdef LISP_FEATURE_DARWIN_JIT +extern lispobj *static_code_space_free_pointer; +#endif + #ifdef LISP_FEATURE_IMMOBILE_SPACE -extern lispobj *varyobj_free_pointer; +extern lispobj *text_space_highwatermark; extern lispobj *fixedobj_free_pointer; +extern lispobj ALIEN_LINKAGE_TABLE_SPACE_START; #endif extern os_vm_address_t anon_dynamic_space_start; +extern lispobj* tlsf_mem_start; // meaningful only if immobile space # ifndef LISP_FEATURE_GENCGC extern lispobj *current_auto_gc_trigger; # endif -#if defined(LISP_FEATURE_GENCGC) -#define current_dynamic_space ((lispobj*)(DYNAMIC_SPACE_START)) -#elif defined(LISP_FEATURE_CHENEYGC) +#ifdef LISP_FEATURE_CHENEYGC extern lispobj *current_dynamic_space; -#else -#error "Which GC?" #endif +extern lispobj lisp_package_vector; + extern void globals_init(void); #else /* __ASSEMBLER__ */ # ifdef LISP_FEATURE_MIPS -# ifdef __linux__ -# define EXTERN(name,bytes) .globl name -# else -# define EXTERN(name,bytes) .extern name bytes -# endif +# define EXTERN(name) .globl name # endif /**/ # ifdef LISP_FEATURE_SPARC # ifdef SVR4 -# define EXTERN(name,bytes) .global name +# define EXTERN(name) .global name # else -# define EXTERN(name,bytes) .global _ ## name -# endif -# endif -/**/ -# ifdef LISP_FEATURE_ALPHA -# ifdef __linux__ -# define EXTERN(name,bytes) .globl name +# define EXTERN(name) .global _ ## name # endif # endif /**/ # if defined(LISP_FEATURE_PPC) || defined(LISP_FEATURE_PPC64) # ifdef LISP_FEATURE_DARWIN -# define EXTERN(name,bytes) .globl _ ## name +# define EXTERN(name) .globl _ ## name # else -# define EXTERN(name,bytes) .globl name +# define EXTERN(name) .globl name # endif # endif /**/ # if defined(LISP_FEATURE_X86) || defined(LISP_FEATURE_X86_64) -# define EXTERN(name,bytes) .global name +# define EXTERN(name) .global name # endif /**/ # if defined(LISP_FEATURE_ARM) || defined(LISP_FEATURE_ARM64) -# define EXTERN(name,bytes) .global name -# endif - -# if defined(LISP_FEATURE_ALPHA) || defined(LISP_FEATURE_X86_64) -# define POINTERSIZE 8 -# else -# define POINTERSIZE 4 +# define EXTERN(name) .global name # endif # if defined(LISP_FEATURE_RISCV) -# define EXTERN(name,bytes) .globl name +# define EXTERN(name) .globl name # endif #ifndef LISP_FEATURE_SB_THREAD -EXTERN(foreign_function_call_active, 4) +EXTERN(foreign_function_call_active) #endif #if !defined(LISP_FEATURE_SB_THREAD) && !defined(LISP_FEATURE_C_STACK_IS_CONTROL_STACK) -EXTERN(current_control_stack_pointer, POINTERSIZE) +EXTERN(current_control_stack_pointer) #endif -EXTERN(current_control_frame_pointer, POINTERSIZE) +EXTERN(current_control_frame_pointer) # if !defined(LISP_FEATURE_X86) && !defined(LISP_FEATURE_X86_64) -EXTERN(current_binding_stack_pointer, POINTERSIZE) -# endif -// don't want an undefined C symbol for this in 'nm' output, it's confusing -# if defined LISP_FEATURE_CHENEYGC && \ - !(defined LISP_FEATURE_ARM || defined LISP_FEATURE_ARM64 || defined LISP_FEATURE_RISCV) -EXTERN(dynamic_space_free_pointer, POINTERSIZE) +EXTERN(current_binding_stack_pointer) # endif #endif /* __ASSEMBLER__ */ diff --git a/src/runtime/haiku-os.c b/src/runtime/haiku-os.c index 812749537b..7bdfc7bb0f 100644 --- a/src/runtime/haiku-os.c +++ b/src/runtime/haiku-os.c @@ -7,7 +7,8 @@ #include <stdio.h> os_vm_address_t -os_validate(int attributes, os_vm_address_t addr, os_vm_size_t len) +os_alloc_gc_space(int __attribute__((unused)) space_id, + int attributes, os_vm_address_t addr, os_vm_size_t len) { int protection = attributes & IS_GUARD_PAGE ? OS_VM_PROT_NONE : OS_VM_PROT_ALL; attributes &= ~IS_GUARD_PAGE; @@ -36,22 +37,6 @@ os_validate(int attributes, os_vm_address_t addr, os_vm_size_t len) return actual; } -void -os_invalidate(os_vm_address_t addr, os_vm_size_t len) -{ - if (munmap(addr,len) == -1) { - perror("munmap"); - } -} - -void -os_protect(os_vm_address_t address, os_vm_size_t length, os_vm_prot_t prot) -{ - if (mprotect(address, length, prot)) { - perror("mprotect"); - } -} - char *os_get_runtime_executable_path() { int cookie = 0; @@ -60,10 +45,7 @@ char *os_get_runtime_executable_path() return (status == 0) ? copied_string(info.name) : 0; } -void -os_init(char __attribute__((unused)) *argv[], char __attribute__((unused)) *envp[]) -{ -} +void os_init() {} static void sigsegv_handler(int signal, siginfo_t *info, os_context_t *context) @@ -71,19 +53,16 @@ sigsegv_handler(int signal, siginfo_t *info, os_context_t *context) /*fprintf(stderr, "SIGSEGV: pc=%p addr=%p\n", context->uc_mcontext.rip, info->si_addr);*/ os_vm_address_t addr = arch_get_bad_addr(signal, info, context); - if (!gencgc_handle_wp_violation(addr)) - if (!handle_guard_page_triggered(context, addr)) + if (gencgc_handle_wp_violation(context, addr)) return; + + if (!handle_guard_page_triggered(context, addr)) interrupt_handle_now(signal, info, context); } void os_install_interrupt_handlers(void) { - undoably_install_low_level_interrupt_handler(SIGSEGV, sigsegv_handler); -#ifdef LISP_FEATURE_SB_THREAD - undoably_install_low_level_interrupt_handler(SIG_STOP_FOR_GC, - sig_stop_for_gc_handler); -#endif + ll_install_handler(SIGSEGV, sigsegv_handler); } int pthread_getattr_np(pthread_t thread, pthread_attr_t *attr) diff --git a/src/runtime/hopscotch.c b/src/runtime/hopscotch.c index 9e27c268a6..9aa67403f4 100644 --- a/src/runtime/hopscotch.c +++ b/src/runtime/hopscotch.c @@ -17,13 +17,24 @@ */ #include "os.h" -#include "gc-internal.h" // for os_allocate() +#include "gc-internal.h" // for sizetab[] and os_allocate() #include "hopscotch.h" #include <stdint.h> #include <stdio.h> +#ifdef LISP_FEATURE_WIN32 +/* I don't know where ffs() is prototyped */ +extern int ffs(int); +#else +/* https://www.freebsd.org/cgi/man.cgi?query=fls&sektion=3&manpath=FreeBSD+7.1-RELEASE + says strings.h */ +#include <strings.h> +#endif #include "genesis/vector.h" #include "murmur_hash.h" +#define hopscotch_allocate(nbytes) os_allocate(nbytes) +#define hopscotch_deallocate(addr,length) os_deallocate(addr, length) + typedef struct hopscotch_table* tableptr; void hopscotch_integrity_check(tableptr,char*,int); @@ -104,6 +115,20 @@ static sword_t get_val4(tableptr ht, int index) { return ((int32_t*)ht->values)[ static sword_t get_val2(tableptr ht, int index) { return ((int16_t*)ht->values)[index]; } static sword_t get_val1(tableptr ht, int index) { return ((int8_t *)ht->values)[index]; } +#ifdef LISP_FEATURE_SB_SAFEPOINT + +// We can safely use malloc + free because there should be no +// problem of holding a malloc lock from another thread. +#include <stdlib.h> +#define cached_allocate(n) calloc(1,n) +#define cached_deallocate(ptr,size) free(ptr) +void hopscotch_init() { } + +#else + +/// We can't safely use malloc because the stop-for-GC signal might be received +/// in the midst of a malloc while holding a global malloc lock. + /// Hopscotch storage allocation granularity. /// Our usual value of "page size" is the GC page size, which is /// coarser than necessary (cf {target}/backend-parms.lisp). @@ -121,9 +146,9 @@ char* cached_alloc[N_CACHED_ALLOCS]; void hopscotch_init() // Called once on runtime startup, from gc_init(). { // Prefill the cache with 2 entries, each the size of a kernel page. - int n_bytes_per_slice = getpagesize(); + int n_bytes_per_slice = os_reported_page_size; int n_bytes_total = N_CACHED_ALLOCS * n_bytes_per_slice; - char* mem = os_allocate(n_bytes_total); + char* mem = hopscotch_allocate(n_bytes_total); gc_assert(mem); cached_alloc[0] = mem + ALLOCATION_OVERHEAD; cached_alloc[1] = cached_alloc[0] + n_bytes_per_slice; @@ -158,7 +183,7 @@ static char* cached_allocate(os_vm_size_t nbytes) // not a multiple of the mmap granularity, which we'll assume is 4K. // (It doesn't actually matter.) nbytes = ALIGN_UP(nbytes, hh_allocation_granularity); - char* result = os_allocate(nbytes); + char* result = hopscotch_allocate(nbytes); gc_assert(result); result += ALLOCATION_OVERHEAD; usable_size(result) = nbytes - ALLOCATION_OVERHEAD; @@ -185,19 +210,20 @@ static void cached_deallocate(char* mem, uword_t zero_fill_length) int cached_size1 = usable_size(cached_alloc[1]); if (!(this_size > cached_size0 || this_size > cached_size1)) { // mem is not strictly larger than either cached block. Release it. - os_deallocate(mem - ALLOCATION_OVERHEAD, - usable_size(mem) + ALLOCATION_OVERHEAD); + hopscotch_deallocate(mem - ALLOCATION_OVERHEAD, + usable_size(mem) + ALLOCATION_OVERHEAD); return; } // Evict and replace the smaller of the two cache entries. if (cached_size1 < cached_size0) line = 1; - os_deallocate(cached_alloc[line] - ALLOCATION_OVERHEAD, - usable_size(cached_alloc[line]) + ALLOCATION_OVERHEAD); + hopscotch_deallocate(cached_alloc[line] - ALLOCATION_OVERHEAD, + usable_size(cached_alloc[line]) + ALLOCATION_OVERHEAD); } memset(mem, 0, zero_fill_length); cached_alloc[line] = mem; } +#endif /* Initialize 'ht' for 'size' logical bins with a max hop of 'hop_range'. * 'valuesp' makes a hash-map if true; a hash-set if false. @@ -226,9 +252,13 @@ static void hopscotch_realloc(tableptr ht, int size, char hop_range) uword_t storage_size = (sizeof (uword_t) + ht->value_size) * n_keys + sizeof (int) * size; // hop bitmasks - if (ht->keys) + if (ht->keys) { +#ifndef LISP_FEATURE_SB_SAFEPOINT + // the usable size is a private-but-visible aspect of the memory block + // if not using malloc(). But with malloc we can't really ask the question. gc_assert(usable_size(ht->keys) >= storage_size); - else +#endif + } else ht->keys = (uword_t*)cached_allocate(storage_size); ht->mem_size = storage_size; @@ -250,7 +280,7 @@ uword_t sxhash_simple_string(struct vector* string) unsigned int* char_string = (unsigned int*)(string->data); #endif unsigned char* base_string = (unsigned char*)(string->data); - sword_t len = fixnum_value(string->length); + sword_t len = vector_len(string); uword_t result = 0; sword_t i; switch (widetag_of(&string->header)) { @@ -258,6 +288,7 @@ uword_t sxhash_simple_string(struct vector* string) #ifdef SIMPLE_CHARACTER_STRING_WIDETAG case SIMPLE_CHARACTER_STRING_WIDETAG: for(i=0;i<len;++i) MIX(char_string[i]) + break; #endif case SIMPLE_BASE_STRING_WIDETAG: for(i=0;i<len;++i) MIX(base_string[i]) @@ -303,7 +334,10 @@ static boolean vector_eql(uword_t arg1, uword_t arg2) int widetag1 = header_widetag(header1); sword_t nwords = sizetab[widetag1](obj1); - if (widetag1 < SIMPLE_ARRAY_UNSIGNED_BYTE_2_WIDETAG) + // OMGWTF! Widetags have been rearranged so many times, I am not sure + // how to keep this code from regressing. + // ASSUMPTION: the range of number widetags ends with (COMPLEX DOUBLE-FLOAT) + if (widetag1 <= COMPLEX_DOUBLE_FLOAT_WIDETAG) // All words must match exactly. Start by comparing the length // (as encoded in the header) since we don't yet know that obj2 // occupies the correct number of words. @@ -312,8 +346,14 @@ static boolean vector_eql(uword_t arg1, uword_t arg2) // Vector elements must have already been coalesced // when comparing simple-vectors for similarity. - return (obj1[1] == obj2[1]) // same length vectors - && !memcmp(obj1 + 2, obj2 + 2, (nwords-2) << WORD_SHIFT); + // Note that only vectors marked "shareable" will get here, so no + // hash-table storage vectors or anything of that nature. + struct vector *v1 = (void*)obj1; + struct vector *v2 = (void*)obj2; + return (vector_len(v1) == vector_len(v2)) // same length vectors + && !memcmp(v1->data, v2->data, + // ASSUMPTION: exactly 2 non-data words + (nwords-2) << WORD_SHIFT); } /* Initialize 'ht' for first use, which entails zeroing the counters diff --git a/src/runtime/hppa-arch.c b/src/runtime/hppa-arch.c deleted file mode 100644 index ea68aedf18..0000000000 --- a/src/runtime/hppa-arch.c +++ /dev/null @@ -1,369 +0,0 @@ -/* - * This software is part of the SBCL system. See the README file for - * more information. - * - * This software is derived from the CMU CL system, which was - * written at Carnegie Mellon University and released into the - * public domain. The software is in the public domain and is - * provided with absolutely no warranty. See the COPYING and CREDITS - * files for more information. - */ -#include <stdio.h> - -/* Copied from sparc-arch.c. Not all of these are necessary, probably */ -#include "sbcl.h" -#include "runtime.h" -#include "arch.h" -#include "globals.h" -#include "validate.h" -#include "os.h" -#include "lispregs.h" -#include "signal.h" -#include "alloc.h" -#include "interrupt.h" -#include "interr.h" -#include "breakpoint.h" - -static inline unsigned int -os_context_pc(os_context_t *context) -{ - return (unsigned int)(*os_context_pc_addr(context)); -} - -os_vm_address_t arch_get_bad_addr(int signal, siginfo_t *siginfo, os_context_t *context) -{ - return (os_vm_address_t)siginfo->si_addr; -#if 0 -#ifdef LISP_FEATURE_HPUX - struct save_state *state; - os_vm_address_t addr; - - state = (struct save_state *)(&(scp->sc_sl.sl_ss)); - - if (state == NULL) - return NULL; - - /* Check the instruction address first. */ - addr = (os_vm_address_t)((unsigned long)scp->sc_pcoq_head & ~3); - if (addr < (os_vm_address_t)0x1000) - return addr; - - /* Otherwise, it must have been a data fault. */ - return (os_vm_address_t)state->ss_cr21; -#else - struct hp800_thread_state *state; - os_vm_address_t addr; - - state = (struct hp800_thread_state *)(scp->sc_ap); - - if (state == NULL) - return NULL; - - /* Check the instruction address first. */ - addr = scp->sc_pcoqh & ~3; - if (addr < 0x1000) - return addr; - - /* Otherwise, it must have been a data fault. */ - return state->cr21; -#endif -#endif -} - -unsigned char *arch_internal_error_arguments(os_context_t *context) -{ - return (unsigned char *)((*os_context_pc_addr(context) & ~3) + 4); -} - -boolean arch_pseudo_atomic_atomic(os_context_t *context) -{ - /* FIXME: this foreign_function_call_active test is dubious at - * best. If a foreign call is made in a pseudo atomic section - * (?) or more likely a pseudo atomic section is in a foreign - * call then an interrupt is executed immediately. Maybe it - * has to do with C code not maintaining pseudo atomic - * properly. MG - 2005-08-10 - * - * The foreign_function_call_active used to live at each call-site - * to arch_pseudo_atomic_atomic, but this seems clearer. - * --NS 2007-05-15 */ - -#if defined(LISP_FEATURE_HPUX) - // FIX-lav: use accessor macro instead - return (!foreign_function_call_active) && - *(&((ucontext_t *) context)->uc_mcontext.ss_wide.ss_64.ss_gr7) & 4; -#else - return (!foreign_function_call_active) && - ((*os_context_register_addr(context,reg_ALLOC)) & 4); -#endif -} - -void arch_set_pseudo_atomic_interrupted(os_context_t *context) -{ -#if defined(LISP_FEATURE_HPUX) - *(&((ucontext_t *) context)->uc_mcontext.ss_wide.ss_64.ss_gr7) |= 1; -/* on hpux do we need to watch out for the barbarian ? */ - *((os_context_register_t *) &((ucontext_t *) context)->uc_mcontext.ss_flags) - |= SS_MODIFIEDWIDE; -#else - *os_context_register_addr(context,reg_ALLOC) |= 1; -#endif -} - -/* FIXME: untested */ -void arch_clear_pseudo_atomic_interrupted(os_context_t *context) -{ -#if defined(LISP_FEATURE_HPUX) - *(&((ucontext_t *) context)->uc_mcontext.ss_wide.ss_64.ss_gr7) &= ~1; - *((os_context_register_t *) &((ucontext_t *) context)->uc_mcontext.ss_flags) - |= SS_MODIFIEDWIDE; -#else - *os_context_register_addr(context,reg_ALLOC) &= ~1; -#endif -} - -void arch_skip_instruction(os_context_t *context) -{ - *((unsigned int *) os_context_pc_addr(context)) = *((unsigned int *) os_context_npc_addr(context)); - *((unsigned int *) os_context_npc_addr(context)) += 4; -#ifdef LISP_FEATURE_HPUX - *((os_context_register_t *) &((ucontext_t *) context)->uc_mcontext.ss_flags) - |= SS_MODIFIEDWIDE; -#endif -} - -unsigned int arch_install_breakpoint(void *pc) -{ - unsigned int *ulpc = (unsigned int *)pc; - unsigned int orig_inst = *ulpc; - - *ulpc = trap_Breakpoint; - os_flush_icache((os_vm_address_t)pc, sizeof(*ulpc)); - return orig_inst; -} - -void arch_remove_breakpoint(void *pc, unsigned int orig_inst) -{ - unsigned int *ulpc = (unsigned int *)pc; - - *ulpc = orig_inst; - os_flush_icache((os_vm_address_t)pc, sizeof(*ulpc)); -} - -void arch_do_displaced_inst(os_context_t *context, unsigned int orig_inst) -{ - fprintf(stderr, "arch_do_displaced_inst() WARNING: stub.\n"); - /* FIXME: Fill this in */ -#if 0 -#ifdef LISP_FEATURE_HPUX - /* We change the next-pc to point to a breakpoint instruction, restore */ - /* the original instruction, and exit. We would like to be able to */ - /* sigreturn, but we can't, because this is hpux. */ - unsigned int *pc = (unsigned int *)(SC_PC(scp) & ~3); - - NextPc = SC_NPC(scp); - SC_NPC(scp) = (unsigned int)SingleStepTraps | (SC_NPC(scp)&3); - - BreakpointAddr = pc; - *pc = orig_inst; - os_flush_icache((os_vm_address_t)pc, sizeof(unsigned int)); -#else - /* We set the recovery counter to cover one instruction, put the */ - /* original instruction back in, and then resume. We will then trap */ - /* after executing that one instruction, at which time we can put */ - /* the breakpoint back in. */ - - ((struct hp800_thread_state *)scp->sc_ap)->cr0 = 1; - scp->sc_ps |= 0x10; - *(unsigned int *)SC_PC(scp) = orig_inst; - - sigreturn(scp); -#endif -#endif -} - -#ifdef LISP_FEATURE_HPUX -#if 0 -static void restore_breakpoint(struct sigcontext *scp) -{ - /* We just single-stepped over an instruction that we want to replace */ - /* with a breakpoint. So we put the breakpoint back in, and tweek the */ - /* state so that we will continue as if nothing happened. */ - - if (NextPc == NULL) - lose("SingleStepBreakpoint trap at strange time."); - - if ((SC_PC(scp)&~3) == (unsigned int)SingleStepTraps) { - /* The next instruction was not nullified. */ - SC_PC(scp) = NextPc; - if ((SC_NPC(scp)&~3) == (unsigned int)SingleStepTraps + 4) { - /* The instruction we just stepped over was not a branch, so */ - /* we need to fix it up. If it was a branch, it will point to */ - /* the correct place. */ - SC_NPC(scp) = NextPc + 4; - } - } - else { - /* The next instruction was nullified, so we want to skip it. */ - SC_PC(scp) = NextPc + 4; - SC_NPC(scp) = NextPc + 8; - } - NextPc = NULL; - - if (BreakpointAddr) { - *BreakpointAddr = trap_Breakpoint; - os_flush_icache((os_vm_address_t)BreakpointAddr, - sizeof(unsigned int)); - BreakpointAddr = NULL; - } -} -#endif -#endif - - - -void -arch_handle_breakpoint(os_context_t *context) -{ - /*sigsetmask(scp->sc_mask); */ - handle_breakpoint(context); -} - -void -arch_handle_fun_end_breakpoint(os_context_t *context) -{ - /*sigsetmask(scp->sc_mask); */ - unsigned long pc; - pc = (unsigned long) - handle_fun_end_breakpoint(context); - *os_context_pc_addr(context) = pc; - *os_context_npc_addr(context) = pc + 4; -#ifdef LISP_FEATURE_HPUX - *((os_context_register_t *) &((ucontext_t *) context)->uc_mcontext.ss_flags) - |= SS_MODIFIEDWIDE; -#endif -} - - -//FIX-lav: this whole is copied from mips -void -arch_handle_single_step_trap(os_context_t *context, int trap) -{ - unsigned int code = *((u32 *)(os_context_pc(context))); - int register_offset = code >> 11 & 0x1f; - handle_single_step_trap(context, trap, register_offset); - arch_skip_instruction(context); -} - -static void -sigtrap_handler(int signal, siginfo_t *siginfo, os_context_t *context) -{ - unsigned int bad_inst; - - bad_inst = *(unsigned int *)(*os_context_pc_addr(context) & ~3); - if (bad_inst & 0xfc001fe0) - interrupt_handle_now(signal, siginfo, context); - else { - int im5 = bad_inst & 0x1f; - handle_trap(context, im5); - } -} - -static void -sigill_handler(int signal, siginfo_t *siginfo, os_context_t *context) -{ - unsigned int bad_inst; - - bad_inst = *(unsigned int *)(*os_context_pc_addr(context) & ~3); - if (bad_inst == 9) { /* pending-interrupt */ - arch_clear_pseudo_atomic_interrupted(context); - arch_skip_instruction(context); - interrupt_handle_pending(context); - } else { - handle_trap(context,bad_inst); - } -} - -static void sigfpe_handler(int signal, siginfo_t *siginfo, - os_context_t *context) -{ - unsigned badinst = *(unsigned *)(*os_context_pc_addr(context) & ~3); - -#ifdef LISP_FEATURE_LINUX - if (!siginfo->si_code && /* Linux 3.14 seems to set si_code to 0 for this case */ -#else - if (siginfo->si_code == FPE_COND && -#endif - (badinst&0xfffff800) == (0xb000e000|reg_ALLOC<<21|reg_ALLOC<<16)) { - /* It is an ADDIT,OD i,ALLOC,ALLOC instruction that trapped. - * That means that it is the end of a pseudo-atomic. So do the - * add stripping off the pseudo-atomic-interrupted bit, and then - * tell the machine-independent code to process the pseudo- - * atomic. We cant skip the instruction because it holds - * extra-bytes that we must add to reg_alloc in context. - * It is so because we optimized away 'addi ,extra-bytes reg_alloc' - */ - int immed = (badinst>>1)&0x3ff; - if (badinst & 1) - immed |= -1<<10; - *os_context_register_addr(context, reg_ALLOC) += (immed-1); - arch_skip_instruction(context); - interrupt_handle_pending(context); - } else { - interrupt_handle_now(signal, siginfo, context); - } -} - -/* Merrily cut'n'pasted from sigfpe_handler. On Linux, until - 2.4.19-pa4 (hopefully), the overflow_trap wasn't implemented, - resulting in a SIGBUS instead. We adapt the sigfpe_handler here, in - the hope that it will do as a replacement until the new kernel sees - the light of day. Since the instructions that we need to fix up - tend not to be doing unaligned memory access, this should be a safe - workaround. -- CSR, 2002-08-17 */ -static void sigbus_handler(int signal, siginfo_t *siginfo, - os_context_t *context) -{ - - unsigned badinst = *(unsigned *)(*os_context_pc_addr(context) & ~3); - - /* First, test for the pseudo-atomic instruction */ - if ((badinst & 0xfffff800) == (0xb000e000 | reg_ALLOC<<21 | - reg_ALLOC<<16)) { - /* It is an ADDIT,OD i,ALLOC,ALLOC instruction that trapped. - That means that it is the end of a pseudo-atomic. So do - the add stripping off the pseudo-atomic-interrupted bit, - and then tell the machine-independent code to process the - pseudo-atomic. */ - int immed = (badinst>>1) & 0x3ff; - if (badinst & 1) - immed |= -1<<10; - *os_context_register_addr(context, reg_ALLOC) += (immed-1); - arch_skip_instruction(context); - interrupt_handle_pending(context); - } else { - interrupt_handle_now(signal, siginfo, context); - } -} - -#ifdef LISP_FEATURE_HPUX -static void -ignore_handler(int signal, siginfo_t *siginfo, os_context_t *context) -{ -} -#endif - -/* this routine installs interrupt handlers that will - * bypass the lisp interrupt handlers */ -void arch_install_interrupt_handlers(void) -{ - undoably_install_low_level_interrupt_handler(SIGTRAP,sigtrap_handler); - undoably_install_low_level_interrupt_handler(SIGILL,sigill_handler); - undoably_install_low_level_interrupt_handler(SIGFPE,sigfpe_handler); - /* FIXME: beyond 2.4.19-pa4 this shouldn't be necessary. */ - undoably_install_low_level_interrupt_handler(SIGBUS,sigbus_handler); -#ifdef LISP_FEATURE_HPUX - undoably_install_low_level_interrupt_handler(SIGXCPU,ignore_handler); - undoably_install_low_level_interrupt_handler(SIGXFSZ,ignore_handler); -#endif -} diff --git a/src/runtime/hppa-arch.h b/src/runtime/hppa-arch.h deleted file mode 100644 index 68541fda04..0000000000 --- a/src/runtime/hppa-arch.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef _HPPA_ARCH_H -#define _HPPA_ARCH_H - -#define ARCH_HAS_NPC_REGISTER -#define ALIEN_STACK_GROWS_UPWARD - -#endif /* _HPPA_ARCH_H */ diff --git a/src/runtime/hppa-assem.S b/src/runtime/hppa-assem.S deleted file mode 100644 index 6932e88132..0000000000 --- a/src/runtime/hppa-assem.S +++ /dev/null @@ -1,473 +0,0 @@ -#ifdef __ELF__ -// Mark the object as not requiring an executable stack. -.section .note.GNU-stack,"",%progbits -#endif - -#include "sbcl.h" -#include "lispregs.h" -#include "genesis/closure.h" -#include "genesis/code.h" -#include "genesis/fdefn.h" -#include "genesis/simple-fun.h" -#include "genesis/return-pc.h" -#include "genesis/static-symbols.h" -#include "genesis/funcallable-instance.h" - - .level 2.0 - .text - - .import $global$,data - .import $$dyncall,MILLICODE - .import foreign_function_call_active,data - .import current_control_stack_pointer,data - .import current_control_frame_pointer,data - .import current_binding_stack_pointer,data - .import dynamic_space_free_pointer,data -/* .import return_from_lisp_function,data */ - - -/* - * Call-into-lisp - */ - - .export call_into_lisp -call_into_lisp: - .proc - .callinfo entry_gr=18,save_rp - .entry - /* %arg0=function, %arg1=cfp, %arg2=nargs */ - - stw %rp,-0x14(%sr0,%sp) - stwm %r3,0x40(%sr0,%sp) - stw %r4,-0x3c(%sr0,%sp) - stw %r5,-0x38(%sr0,%sp) - stw %r6,-0x34(%sr0,%sp) - stw %r7,-0x30(%sr0,%sp) - stw %r8,-0x2c(%sr0,%sp) - stw %r9,-0x28(%sr0,%sp) - stw %r10,-0x24(%sr0,%sp) - stw %r11,-0x20(%sr0,%sp) - stw %r12,-0x1c(%sr0,%sp) - stw %r13,-0x18(%sr0,%sp) - stw %r14,-0x14(%sr0,%sp) - stw %r15,-0x10(%sr0,%sp) - stw %r16,-0xc(%sr0,%sp) - stw %r17,-0x8(%sr0,%sp) - stw %r18,-0x4(%sr0,%sp) - - /* Clear the descriptor regs, moving in args as approporate. */ - copy %r0,reg_CODE - copy %r0,reg_FDEFN - copy %arg0,reg_LEXENV - zdep %arg2,29,30,reg_NARGS - copy %r0,reg_OCFP - copy %r0,reg_LRA - copy %r0,reg_A0 - copy %r0,reg_A1 - copy %r0,reg_A2 - copy %r0,reg_A3 - copy %r0,reg_A4 - copy %r0,reg_A5 - copy %r0,reg_L0 - copy %r0,reg_L1 - copy %r0,reg_L2 - - /* Establish NIL. */ - ldil L%NIL,reg_NULL - ldo R%NIL(reg_NULL),reg_NULL - - /* Turn on pseudo-atomic. */ - ldo 4(%r0),reg_ALLOC - - /* No longer in foreign function call land. */ - addil L%foreign_function_call_active-$global$,%dp - stw %r0,R%foreign_function_call_active-$global$(0,%r1) - - /* Load lisp state. */ - addil L%dynamic_space_free_pointer-$global$,%dp - ldw R%dynamic_space_free_pointer-$global$(0,%r1),%r1 - add reg_ALLOC,%r1,reg_ALLOC - addil L%current_binding_stack_pointer-$global$,%dp - ldw R%current_binding_stack_pointer-$global$(0,%r1),reg_BSP - addil L%current_control_stack_pointer-$global$,%dp - ldw R%current_control_stack_pointer-$global$(0,%r1),reg_CSP - addil L%current_control_frame_pointer-$global$,%dp - ldw R%current_control_frame_pointer-$global$(0,%r1),reg_OCFP - copy %arg1,reg_CFP - - /* End of pseudo-atomic. */ - addit,od -4,reg_ALLOC,reg_ALLOC - - /* Establish lisp arguments. */ - ldw 0(reg_CFP),reg_A0 - ldw 4(reg_CFP),reg_A1 - ldw 8(reg_CFP),reg_A2 - ldw 12(reg_CFP),reg_A3 - ldw 16(reg_CFP),reg_A4 - ldw 20(reg_CFP),reg_A5 - - /* Calculate the LRA. */ - ldil L%lra-RETURN_PC_RETURN_POINT_OFFSET,reg_LRA - ldo R%lra-RETURN_PC_RETURN_POINT_OFFSET(reg_LRA),reg_LRA - - /* Indirect the closure */ - ldw CLOSURE_FUN_OFFSET(0,reg_LEXENV),reg_CODE - addi SIMPLE_FUN_INSTS_OFFSET,reg_CODE,reg_LIP - -#ifdef LISP_FEATURE_HPUX - /* Get the stub address, ie assembly-routine return-from-lisp */ - addil L%return_from_lisp_stub-$global$,%dp - ldw R%return_from_lisp_stub-$global$(0,%r1),reg_NL0 - be,n 0(%sr5,reg_NL0) -#else - be,n 0(%sr5,reg_LIP) -#endif - - break 0,0 - - .align 8 -lra: - nop /* a few nops because we dont know where we land */ - nop /* the return convention would govern this */ - nop - nop - - /* Copy CFP (%r4) into someplace else and restore r4. */ - copy reg_CFP,reg_NL1 - ldw -0x3c(0,%sp),%r4 - - /* Copy the return value. */ - copy reg_A0,%ret0 - - /* Turn on pseudo-atomic. */ - addi 4,reg_ALLOC,reg_ALLOC - - /* Store the lisp state. */ - copy reg_ALLOC,reg_NL0 - depi 0,31,3,reg_NL0 - addil L%dynamic_space_free_pointer-$global$,%dp - stw reg_NL0,R%dynamic_space_free_pointer-$global$(0,%r1) - addil L%current_binding_stack_pointer-$global$,%dp - stw reg_BSP,R%current_binding_stack_pointer-$global$(0,%r1) - addil L%current_control_stack_pointer-$global$,%dp - stw reg_CSP,R%current_control_stack_pointer-$global$(0,%r1) - addil L%current_control_frame_pointer-$global$,%dp - stw reg_NL1,R%current_control_frame_pointer-$global$(0,%r1) - - /* Back in C land. [CSP is just a handy non-zero value.] */ - addil L%foreign_function_call_active-$global$,%dp - stw reg_CSP,R%foreign_function_call_active-$global$(0,%r1) - - /* Turn off pseudo-atomic and check for traps. */ - addit,od -4,reg_ALLOC,reg_ALLOC - - ldw -0x54(%sr0,%sp),%rp - ldw -0x4(%sr0,%sp),%r18 - ldw -0x8(%sr0,%sp),%r17 - ldw -0xc(%sr0,%sp),%r16 - ldw -0x10(%sr0,%sp),%r15 - ldw -0x14(%sr0,%sp),%r14 - ldw -0x18(%sr0,%sp),%r13 - ldw -0x1c(%sr0,%sp),%r12 - ldw -0x20(%sr0,%sp),%r11 - ldw -0x24(%sr0,%sp),%r10 - ldw -0x28(%sr0,%sp),%r9 - ldw -0x2c(%sr0,%sp),%r8 - ldw -0x30(%sr0,%sp),%r7 - ldw -0x34(%sr0,%sp),%r6 - ldw -0x38(%sr0,%sp),%r5 - ldw -0x3c(%sr0,%sp),%r4 - bv %r0(%rp) - ldwm -0x40(%sr0,%sp),%r3 - - /* And thats all. */ - .exit - .procend - - -/* - * Call-into-C - */ - - .export call_into_c -call_into_c: - /* Set up a lisp stack frame. */ - copy reg_CFP, reg_OCFP - copy reg_CSP, reg_CFP - addi 32, reg_CSP, reg_CSP - stw reg_OCFP, 0(0,reg_CFP) ; save old cfp - stw reg_CFP, 4(0,reg_CFP) ; save old csp - /* convert raw return PC into a fixnum PC-offset, because we dont - have ahold of an lra object */ - sub reg_LIP, reg_CODE, reg_NL5 - addi 3-OTHER_POINTER_LOWTAG, reg_NL5, reg_NL5 - stw reg_NL5, 8(0,reg_CFP) - stw reg_CODE, 0xc(0,reg_CFP) - - /* set pseudo-atomic flag */ - addi 4, reg_ALLOC, reg_ALLOC - - /* Store the lisp state. */ - copy reg_ALLOC,reg_NL5 - depi 0,31,3,reg_NL5 - addil L%dynamic_space_free_pointer-$global$,%dp - stw reg_NL5,R%dynamic_space_free_pointer-$global$(0,%r1) - addil L%current_binding_stack_pointer-$global$,%dp - stw reg_BSP,R%current_binding_stack_pointer-$global$(0,%r1) - addil L%current_control_stack_pointer-$global$,%dp - stw reg_CSP,R%current_control_stack_pointer-$global$(0,%r1) - addil L%current_control_frame_pointer-$global$,%dp - stw reg_CFP,R%current_control_frame_pointer-$global$(0,%r1) - - /* Back in C land. [CSP is just a handy non-zero value.] */ - addil L%foreign_function_call_active-$global$,%dp - stw reg_CSP,R%foreign_function_call_active-$global$(0,%r1) - - /* Turn off pseudo-atomic and check for traps. */ - addit,od -4,reg_ALLOC,reg_ALLOC - - /* in order to be able to call incrementally linked (ld -A) functions, - we have to do some mild trickery here */ - copy reg_CFUNC, %r22 - bl $$dyncall,%r31 - copy %r31, %r2 -call_into_c_return: - /* Clear the callee saves descriptor regs. */ - copy %r0, reg_A5 - copy %r0, reg_L0 - copy %r0, reg_L1 - copy %r0, reg_L2 - - /* Turn on pseudo-atomic. */ - ldi 4, reg_ALLOC - - /* Turn off foreign function call. */ - addil L%foreign_function_call_active-$global$,%dp - stw %r0,R%foreign_function_call_active-$global$(0,%r1) - - /* Load ALLOC. */ - addil L%dynamic_space_free_pointer-$global$,%dp - ldw R%dynamic_space_free_pointer-$global$(0,%r1),%r1 - add reg_ALLOC,%r1,reg_ALLOC - - /* We don't need to load OCFP, CFP, CSP, or BSP because they are - * in caller saves registers. - */ - - /* End of pseudo-atomic. */ - addit,od -4,reg_ALLOC,reg_ALLOC - - /* Restore CODE. Even though it is in a callee saves register - * it might have been GC'ed. - */ - ldw 0xc(0,reg_CFP), reg_CODE - - /* Restore the return pc. */ - ldw 8(0,reg_CFP), reg_NL0 - addi OTHER_POINTER_LOWTAG-3, reg_NL0, reg_NL0 -/* - addi -3, reg_NL0, reg_NL0 - ldi OTHER_POINTER_LOWTAG, reg_NL1 - sub reg_NL0, reg_NL1, reg_NL0 -*/ - add reg_CODE, reg_NL0, reg_LIP - - /* Pop the lisp stack frame, and back we go. */ - ldw 4(0,reg_CFP), reg_CSP - ldw 0(0,reg_CFP), reg_OCFP - copy reg_OCFP, reg_CFP - be 0(5,reg_LIP) - nop - - -/* - * Stuff to sanctify a block of memory for execution. - */ - - .EXPORT sanctify_for_execution -sanctify_for_execution: - .proc - .callinfo - .entry - /* %arg0=start addr, %arg1=length in bytes */ - add %arg0,%arg1,%arg1 - copy %arg0,%arg2 - ldo -1(%arg1),%arg1 - depi 0,31,5,%arg0 - depi 0,31,5,%arg1 - ldsid (%arg0),%r1 - mtsp %r1,%sr1 - ldi 32,%r1 ; bytes per cache line - /* parisc 1.1 and 2.0 manuals say to flush the dcache, SYNC, - * flush the icache, SYNC again, and burn seven instructions - * before executing modified code. */ -sanctify_loop: - comb,< %arg0,%arg1,sanctify_loop - fdc,m %r1(%sr1,%arg0) - sync -sanctify_loop_2: - comb,< %arg2,%arg1,sanctify_loop_2 - fic,m %r1(%sr1,%arg2) - sync - - bv %r0(%rp) - nop - - .exit - .procend - - -/* - * Core saving/restoring support - */ - - .export call_on_stack -call_on_stack: - /* %arg0 = fn to invoke, %arg1 = new stack base */ - - /* Compute the new stack pointer. */ - addi 64,%arg1,%sp - - /* Zero out the previous stack pointer. */ - stw %r0,-4(0,%sp) - - /* Invoke the function. */ - ble 0(4,%arg0) - copy %r31, %r2 - - /* Flame out. */ - break 0,0 - - .export save_state -save_state: - .proc - .callinfo entry_gr=18,entry_fr=21,save_rp,calls - .entry - - stw %rp,-0x14(%sr0,%sp) - fstds,ma %fr12,8(%sr0,%sp) - fstds,ma %fr13,8(%sr0,%sp) - fstds,ma %fr14,8(%sr0,%sp) - fstds,ma %fr15,8(%sr0,%sp) - fstds,ma %fr16,8(%sr0,%sp) - fstds,ma %fr17,8(%sr0,%sp) - fstds,ma %fr18,8(%sr0,%sp) - fstds,ma %fr19,8(%sr0,%sp) - fstds,ma %fr20,8(%sr0,%sp) - fstds,ma %fr21,8(%sr0,%sp) - stwm %r3,0x70(%sr0,%sp) - stw %r4,-0x6c(%sr0,%sp) - stw %r5,-0x68(%sr0,%sp) - stw %r6,-0x64(%sr0,%sp) - stw %r7,-0x60(%sr0,%sp) - stw %r8,-0x5c(%sr0,%sp) - stw %r9,-0x58(%sr0,%sp) - stw %r10,-0x54(%sr0,%sp) - stw %r11,-0x50(%sr0,%sp) - stw %r12,-0x4c(%sr0,%sp) - stw %r13,-0x48(%sr0,%sp) - stw %r14,-0x44(%sr0,%sp) - stw %r15,-0x40(%sr0,%sp) - stw %r16,-0x3c(%sr0,%sp) - stw %r17,-0x38(%sr0,%sp) - stw %r18,-0x34(%sr0,%sp) - - - /* Remember the function we want to invoke */ - copy %arg0,%r19 - - /* Pass the new stack pointer in as %arg0 */ - copy %sp,%arg0 - - /* Leave %arg1 as %arg1. */ - - /* do the call. */ - ble 0(4,%r19) - copy %r31, %r2 - - .export _restore_state -_restore_state: - - ldw -0xd4(%sr0,%sp),%rp - ldw -0x34(%sr0,%sp),%r18 - ldw -0x38(%sr0,%sp),%r17 - ldw -0x3c(%sr0,%sp),%r16 - ldw -0x40(%sr0,%sp),%r15 - ldw -0x44(%sr0,%sp),%r14 - ldw -0x48(%sr0,%sp),%r13 - ldw -0x4c(%sr0,%sp),%r12 - ldw -0x50(%sr0,%sp),%r11 - ldw -0x54(%sr0,%sp),%r10 - ldw -0x58(%sr0,%sp),%r9 - ldw -0x5c(%sr0,%sp),%r8 - ldw -0x60(%sr0,%sp),%r7 - ldw -0x64(%sr0,%sp),%r6 - ldw -0x68(%sr0,%sp),%r5 - ldw -0x6c(%sr0,%sp),%r4 - ldwm -0x70(%sr0,%sp),%r3 - fldds,mb -8(%sr0,%sp),%fr21 - fldds,mb -8(%sr0,%sp),%fr20 - fldds,mb -8(%sr0,%sp),%fr19 - fldds,mb -8(%sr0,%sp),%fr18 - fldds,mb -8(%sr0,%sp),%fr17 - fldds,mb -8(%sr0,%sp),%fr16 - fldds,mb -8(%sr0,%sp),%fr15 - fldds,mb -8(%sr0,%sp),%fr14 - fldds,mb -8(%sr0,%sp),%fr13 - bv %r0(%rp) - fldds,mb -8(%sr0,%sp),%fr12 - - - .exit - .procend - - .export restore_state -restore_state: - .proc - .callinfo - copy %arg0,%sp - b _restore_state - copy %arg1,%ret0 - .procend - - - -/* FIX, add support for singlestep - break trap_SingleStepBreakpoint,0 - break trap_SingleStepBreakpoint,0 -*/ - .export SingleStepTraps -SingleStepTraps: - -/* Missing !! NOT - there's a break 0,0 in the new version here!!! -*/ - -/* - * For an explanation of the magic involved in function-end - * breakpoints, see the implementation in ppc-assem.S. - */ - - .align 8 - .export fun_end_breakpoint_guts -fun_end_breakpoint_guts: - .word (((CODE_SIZE+1)&~1)<<N_WIDETAG_BITS)|RETURN_PC_WIDETAG - /* multiple value return point -- just jump to trap. */ - b,n fun_end_breakpoint_trap - /* single value return point -- convert to multiple w/ n=1 */ - copy reg_CSP, reg_OCFP - addi 4, reg_CSP, reg_CSP - addi 4, %r0, reg_NARGS - copy reg_NULL, reg_A1 - copy reg_NULL, reg_A2 - copy reg_NULL, reg_A3 - copy reg_NULL, reg_A4 - copy reg_NULL, reg_A5 - - .export fun_end_breakpoint_trap -fun_end_breakpoint_trap: - break trap_FunEndBreakpoint,0 - b,n fun_end_breakpoint_trap - - .export fun_end_breakpoint_end -fun_end_breakpoint_end: diff --git a/src/runtime/hppa-hpux-os.c b/src/runtime/hppa-hpux-os.c deleted file mode 100644 index 9225da22e9..0000000000 --- a/src/runtime/hppa-hpux-os.c +++ /dev/null @@ -1,90 +0,0 @@ -/* - * This is the HPPA HPUX incarnation of arch-dependent OS-dependent - * routines. See also "hppa-os.c". - */ - -/* - * This software is part of the SBCL system. See the README file for - * more information. - * - * This software is derived from the CMU CL system, which was - * written at Carnegie Mellon University and released into the - * public domain. The software is in the public domain and is - * provided with absolutely no warranty. See the COPYING and CREDITS - * files for more information. - */ - -#include <stdio.h> -#include <sys/param.h> -#include <sys/file.h> -#include "sbcl.h" -#include "./signal.h" -#include "os.h" -#include "arch.h" -#include "globals.h" -#include "interrupt.h" -#include "interr.h" -#include "lispregs.h" -#include <sys/socket.h> -#include <sys/utsname.h> - -#include <sys/types.h> -#include <signal.h> -#include <sys/time.h> -#include <sys/stat.h> -#include <unistd.h> - -#include "validate.h" - -#ifdef LISP_FEATURE_SB_THREAD -#error "Define threading support functions" -#else -int arch_os_thread_init(struct thread *thread) { - return 1; /* success */ -} -int arch_os_thread_cleanup(struct thread *thread) { - return 1; /* success */ -} -#endif - -/* for hpux read /usr/include/machine/save_state.h - * os_context_register_addr() may not be used - * to modify registers without setting a state-flag too */ -os_context_register_t * -os_context_register_addr(os_context_t *context, int offset) -{ - return (os_context_register_t *) - ((unsigned int)(&((ucontext_t *) context)->uc_mcontext.ss_wide.ss_64)) + (offset * 2) + 1; -} - -os_context_register_t * -os_context_pc_addr(os_context_t *context) -{ - /* Why do I get all the silly ports? -- CSR, 2002-08-11 */ - return ((unsigned int) &((ucontext_t *) context)->uc_mcontext.ss_wide.ss_64.ss_pcoq_head + 4); -} - -os_context_register_t * -os_context_npc_addr(os_context_t *context) -{ - return ((unsigned int) &((ucontext_t *) context)->uc_mcontext.ss_wide.ss_64.ss_pcoq_tail + 4); -} - -sigset_t * -os_context_sigmask_addr(os_context_t *context) -{ - return &(((ucontext_t *)context)->uc_subcontext.__uc_sigmask); -} - -void -os_restore_fp_control(os_context_t *context) -{ - /* FIXME: Probably do something. */ -} - -void -os_flush_icache(os_vm_address_t address, os_vm_size_t length) -{ - /* FIXME: Maybe this is OK. */ - sanctify_for_execution(address,length); -} diff --git a/src/runtime/hppa-hpux-os.h b/src/runtime/hppa-hpux-os.h deleted file mode 100644 index d2d1584ca8..0000000000 --- a/src/runtime/hppa-hpux-os.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef _HPPA_HPUX_OS_H -#define _HPPA_HPUX_OS_H - -typedef struct ucontext_t os_context_t; -typedef unsigned long os_context_register_t; - -#include "arch-os-generic.inc" - -unsigned long os_context_fp_control(os_context_t *context); -void os_restore_fp_control(os_context_t *context); - -#define REGISTER_ACCESS(context,offset) ((os_context_register_t *) ((unsigned int)(&((ucontext_t *) context)->uc_mcontext.ss_wide.ss_64)) + (offset * 2) + 1) - -#endif /* _HPPA_HPUX_OS_H */ diff --git a/src/runtime/hppa-linux-os.c b/src/runtime/hppa-linux-os.c deleted file mode 100644 index d4b76a5d91..0000000000 --- a/src/runtime/hppa-linux-os.c +++ /dev/null @@ -1,96 +0,0 @@ -/* - * This is the HPPA Linux incarnation of arch-dependent OS-dependent - * routines. See also "linux-os.c". - */ - -/* - * This software is part of the SBCL system. See the README file for - * more information. - * - * This software is derived from the CMU CL system, which was - * written at Carnegie Mellon University and released into the - * public domain. The software is in the public domain and is - * provided with absolutely no warranty. See the COPYING and CREDITS - * files for more information. - */ - -#include <stdio.h> -#include <sys/param.h> -#include <sys/file.h> -#include "sbcl.h" -#include "./signal.h" -#include "os.h" -#include "arch.h" -#include "globals.h" -#include "interrupt.h" -#include "interr.h" -#include "lispregs.h" -#include <sys/socket.h> -#include <sys/utsname.h> - -#include <sys/types.h> -#include <signal.h> -#include <sys/time.h> -#include <sys/stat.h> -#include <unistd.h> - -#include "validate.h" - -#ifdef LISP_FEATURE_SB_THREAD -#error "Define threading support functions" -#else -int arch_os_thread_init(struct thread *thread) { - return 1; /* success */ -} -int arch_os_thread_cleanup(struct thread *thread) { - return 1; /* success */ -} -#endif - -os_context_register_t * -os_context_register_addr(os_context_t *context, int offset) -{ - if (offset == 0) { - /* KLUDGE: I'm not sure, but it's possible that Linux puts the - contents of the Processor Status Word in the (wired-zero) - slot in the mcontext. In any case, the following is - unlikely to do any harm: */ - static int zero; - zero = 0; - return &zero; - } else { - return &context->uc_mcontext.sc_gr[offset]; - } -} - -os_context_register_t * -os_context_pc_addr(os_context_t *context) -{ - /* Why do I get all the silly ports? -- CSR, 2002-08-11 */ - return &context->uc_mcontext.sc_iaoq[0]; -} - -os_context_register_t * -os_context_npc_addr(os_context_t *context) -{ - return &context->uc_mcontext.sc_iaoq[1]; -} - -sigset_t * -os_context_sigmask_addr(os_context_t *context) -{ - return &context->uc_sigmask; -} - -void -os_restore_fp_control(os_context_t *context) -{ - /* FIXME: Probably do something. */ -} - -void -os_flush_icache(os_vm_address_t address, os_vm_size_t length) -{ - /* FIXME: Maybe this is OK. */ - sanctify_for_execution(address,length); -} diff --git a/src/runtime/hppa-linux-os.h b/src/runtime/hppa-linux-os.h deleted file mode 100644 index 447ed050a5..0000000000 --- a/src/runtime/hppa-linux-os.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef _HPPA_LINUX_OS_H -#define _HPPA_LINUX_OS_H - -typedef struct ucontext_t os_context_t; -/* FIXME: This will change if the parisc-linux people implement - wide-sigcontext for 32-bit kernels */ -typedef unsigned long os_context_register_t; - -#include "arch-os-generic.inc" - -unsigned long os_context_fp_control(os_context_t *context); -void os_restore_fp_control(os_context_t *context); - -#define SC_REG(sc, n) (((unsigned long *)((sc)->sc_ap))[n]) -#define SC_PC(sc) ((sc)->sc_pcoqh) -#define SC_NPC(sc) ((sc)->sc_pcoqt) - -#endif /* _HPPA_LINUX_OS_H */ diff --git a/src/runtime/hppa-lispregs.h b/src/runtime/hppa-lispregs.h deleted file mode 100644 index c1821c457d..0000000000 --- a/src/runtime/hppa-lispregs.h +++ /dev/null @@ -1,40 +0,0 @@ -#define NREGS (32) - -#ifdef __ASSEMBLER__ -#define REG(num) num -#else -#define REG(num) num -#endif - -#define reg_ZERO REG(0) -#define reg_NFP REG(1) -#define reg_CFUNC REG(2) -#define reg_CSP REG(3) -#define reg_CFP REG(4) -#define reg_BSP REG(5) -#define reg_NULL REG(6) -#define reg_ALLOC REG(7) -#define reg_CODE REG(8) -#define reg_FDEFN REG(9) -#define reg_LEXENV REG(10) -#define reg_NARGS REG(11) -#define reg_OCFP REG(12) -#define reg_LRA REG(13) -#define reg_A0 REG(14) -#define reg_A1 REG(15) -#define reg_A2 REG(16) -#define reg_A3 REG(17) -#define reg_A4 REG(18) -#define reg_A5 REG(19) -#define reg_L0 REG(20) -#define reg_L1 REG(21) -#define reg_L2 REG(22) -#define reg_NL3 REG(23) -#define reg_NL2 REG(24) -#define reg_NL1 REG(25) -#define reg_NL0 REG(26) -#define reg_DP REG(27) -#define reg_NL4 REG(28) -#define reg_NL5 REG(29) -#define reg_NSP REG(30) -#define reg_LIP REG(31) diff --git a/src/runtime/hpux-os.c b/src/runtime/hpux-os.c deleted file mode 100644 index 155276ae23..0000000000 --- a/src/runtime/hpux-os.c +++ /dev/null @@ -1,113 +0,0 @@ -#include <stdio.h> -#include <stdlib.h> -#include <signal.h> -#include <sys/file.h> - -#include <unistd.h> -#include <errno.h> -#include <sys/param.h> -#include <sys/utsname.h> - -#include "sbcl.h" -#include "os.h" -#include "arch.h" -#include "interr.h" -#include "interrupt.h" -#include "globals.h" -#include "validate.h" -#include "target-arch-os.h" - -#ifdef LISP_FEATURE_GENCGC -#error gencgc not ported to hpux -#endif - -#ifdef LISP_FEATURE_C_STACK_IS_CONTROL_STACK -#error C_STACK_IS_CONTROL_STACK isnt supported -#endif - -void -os_init(char *argv[], char *envp[]) -{ -} - -os_vm_address_t -os_validate(int attributes, os_vm_address_t addr, os_vm_size_t len) -{ - int protection = attributes & IS_GUARD_PAGE ? OS_VM_PROT_NONE : OS_VM_PROT_ALL; - attributes &= ~IS_GUARD_PAGE; - os_vm_address_t actual; - int flags = MAP_PRIVATE | MAP_ANONYMOUS; - if (addr) flags |= MAP_FIXED; - - actual = mmap(addr, len, protection, flags, -1, 0); - - if (actual == MAP_FAILED) { - perror("mmap"); - lose("os_validate(): mmap() failure"); - } - - if (addr && (addr!=actual)) { - fprintf(stderr, "mmap: wanted %lu bytes at %p, actually mapped at %p\n", - (unsigned long) len, addr, actual); - return 0; - } - - return actual; -} - -void -os_invalidate(os_vm_address_t addr, os_vm_size_t len) -{ - if (munmap(addr,len) == -1) { - perror("munmap"); - lose("os_invalidate(): mmap() failure"); - } -} - -void -os_protect(os_vm_address_t addr, os_vm_size_t len, os_vm_prot_t prot) -{ - if (mprotect(addr, len, prot) == -1) { - perror("mprotect"); - } -} - -/* - * any OS-dependent special low-level handling for signals - */ - -static void -sigsegv_handler(int signal, siginfo_t *info, os_context_t *context) -{ - os_vm_address_t addr = arch_get_bad_addr(signal, info, context); - - if (!cheneygc_handle_wp_violation(context, addr)) - if (!handle_guard_page_triggered(context, addr)) - lisp_memory_fault_error(context, addr); - *((os_context_register_t *) &((ucontext_t *) context)->uc_mcontext.ss_flags) - |= SS_MODIFIEDWIDE; -} - -void -os_install_interrupt_handlers(void) -{ - undoably_install_low_level_interrupt_handler(SIG_MEMORY_FAULT, - sigsegv_handler); -} - -char *os_get_runtime_executable_path() -{ - return NULL; -} - -/* when inside call_into_lisp, we will first jump to the stub - * and then the stub will jump into the lisp function. Then - * the lisp function will return to the stub function and - * the stub will return to the call_into_lisp function. - */ -void *return_from_lisp_stub; -void -setup_return_from_lisp_stub (void *addr) -{ - return_from_lisp_stub = addr; -} diff --git a/src/runtime/hpux-os.h b/src/runtime/hpux-os.h deleted file mode 100644 index bc4d404d13..0000000000 --- a/src/runtime/hpux-os.h +++ /dev/null @@ -1,18 +0,0 @@ -#include <strings.h> /* warnings in os-common */ -#include <sys/types.h> -#include <sys/mman.h> -#include <sys/newsig.h> /* recognize signal_t */ -#include "target-arch-os.h" -#include "target-arch.h" - -typedef caddr_t os_vm_address_t; -typedef size_t os_vm_size_t; -typedef off_t os_vm_offset_t; -typedef int os_vm_prot_t; - -#define OS_VM_PROT_READ PROT_READ -#define OS_VM_PROT_WRITE PROT_WRITE -#define OS_VM_PROT_EXECUTE PROT_EXEC - -#define SIG_MEMORY_FAULT SIGSEGV - diff --git a/src/runtime/immobile-space.c b/src/runtime/immobile-space.c index 5e7b71f068..7a6a27eb38 100644 --- a/src/runtime/immobile-space.c +++ b/src/runtime/immobile-space.c @@ -45,32 +45,35 @@ #define _FORTIFY_SOURCE 0 #endif +#include "brothertree.h" +#include "code.h" +#include "forwarding-ptr.h" #include "gc.h" #include "gc-internal.h" #include "gc-private.h" -#include "genesis/gc-tables.h" #include "genesis/cons.h" -#include "genesis/vector.h" +#include "genesis/gc-tables.h" +#include "genesis/hash-table.h" #include "genesis/layout.h" -#include "forwarding-ptr.h" -#include "getallocptr.h" -#include "var-io.h" +#include "genesis/package.h" +#include "genesis/vector.h" #include "immobile-space.h" +#include "lispstring.h" +#include "pseudo-atomic.h" +#include "search.h" #include "unaligned.h" -#include "code.h" - +#include "var-io.h" #include <stdlib.h> #include <stdio.h> +#include "tlsf-bsd/tlsf/tlsf.h" #define WORDS_PER_PAGE ((int)IMMOBILE_CARD_BYTES/N_WORD_BYTES) #define DOUBLEWORDS_PER_PAGE (WORDS_PER_PAGE/2) // In case of problems while debugging, this is selectable. #define DEFRAGMENT_FIXEDOBJ_SUBSPACE 1 -#define WRITABLE_TEXT_SEGMENT 0 #undef DEBUG -#undef VERIFY_PAGE_GENS #ifdef DEBUG # define dprintf(arg) fprintf arg @@ -81,10 +84,10 @@ FILE * logfile; static void defrag_immobile_space(boolean verbose); -uword_t FIXEDOBJ_SPACE_START, VARYOBJ_SPACE_START; +uword_t FIXEDOBJ_SPACE_START, TEXT_SPACE_START; uword_t immobile_space_lower_bound, immobile_space_max_offset; uword_t immobile_range_1_max_offset, immobile_range_2_min_offset; -unsigned int varyobj_space_size = VARYOBJ_SPACE_SIZE; +unsigned int text_space_size = TEXT_SPACE_SIZE; // This table is for objects fixed in size, as opposed to variable-sized. // (Immobile objects are naturally fixed in placement) @@ -104,7 +107,7 @@ unsigned int immobile_scav_queue_count; // Packing and unpacking attributes // the low two flag bits are for write-protect status -#define MAKE_ATTR(spacing,size,flags) (((spacing)<<8)|((size)<<16)|flags) +#define MAKE_ATTR(spacing) ((spacing)<<8) #define OBJ_SPACING(attr) ((attr>>8) & 0xFF) // Ignore the write-protect bits and the generations when comparing attributes @@ -127,47 +130,121 @@ static inline lispobj* compute_fixedobj_limit(void* base, int spacing_bytes) { /// Variable-length pages: +unsigned char* text_page_genmask; +// scan-start-offset, measured in bytes from page base address. +// one per page *excluding* all pseudostatic pages. +// Unlike with dynamic-space, the scan start for a text page +// is an address not lower than the base page. +unsigned short int* tlsf_page_sso; // Array of inverted write-protect flags, 1 bit per page. -unsigned int* varyobj_page_touched_bits; +unsigned int* text_page_touched_bits; static int n_bitmap_elts; // length of array measured in 'int's +// List of FILLER_WIDETAG objects to be stuffed back into the TLSF-managed pool +// chained through the word after their header. +lispobj codeblob_freelist; boolean immobile_card_protected_p(void* addr) { low_page_index_t page; - page = find_varyobj_page_index(addr); - if (page >= 0) return !((varyobj_page_touched_bits[page/32] >> (page&31)) & 1); + page = find_text_page_index(addr); + if (page >= 0) return !((text_page_touched_bits[page/32] >> (page&31)) & 1); page = find_fixedobj_page_index(addr); if (page >= 0) return fixedobj_page_wp(page); lose("immobile_card_protected_p(%p)", addr); } -struct varyobj_page *varyobj_pages; -// Holes to be stuffed back into the managed free list. -lispobj varyobj_holes; - -#define varyobj_page_touched(x) ((varyobj_page_touched_bits[x/32] >> (x&31)) & 1) +void* tlsf_control; + +#define text_page_touched(x) ((text_page_touched_bits[x/32] >> (x&31)) & 1) +// These bits are in the same place in the code header as the ones +// in 'tlsf.c' but shifted by 8 more so that they refer to the header +// word as a whole. +static const unsigned block_header_free_bit = 1 << 8; +static const unsigned block_header_prev_free_bit = 1 << 9; +/* Indicates oversized allocation in a header bit so that we can eliminate + * 2 words of padding when saving a core (not done yet) + * This seems to occur for fewer than .5% of all allocations, + * accounting for under .01% addditional total space used. + * So there's really no need to do anything about it. +static const unsigned block_header_oversized = 1 << 10; +*/ -#ifdef VERIFY_PAGE_GENS -void check_fixedobj_page(low_page_index_t, generation_index_t, generation_index_t); -void check_varyobj_pages(); +#define IMMOBILE_CARD_SHIFT 12 +void *tlsf_alloc_codeblob(tlsf_t tlsf, int requested_nwords) +{ + // The size we request is 1 word less, because the allocator's block header + // counts as part of the resulting object as far as Lisp is concerned. + int size = (requested_nwords - 1) << WORD_SHIFT; + void* tlsf_result = tlsf_malloc(tlsf, size); + if (!tlsf_result) return 0; + struct code* c = (void*)((lispobj*)tlsf_result - 1); + gc_assert(!((uintptr_t)c & LOWTAG_MASK)); + assign_widetag(c, CODE_HEADER_WIDETAG); + c->boxed_size = c->debug_info = c->fixups = 0; + int nwords = code_total_nwords(c); + ((lispobj*)c)[nwords-1] = 0; // trailer word with the simple-fun table + lispobj* end = (lispobj*)c + nwords; + if (end > text_space_highwatermark) text_space_highwatermark = end; + // Adjust the scan start if this became the lowest addressable in-use block on its page + low_page_index_t tlsf_page = ((char*)c - (char*)tlsf_mem_start) >> IMMOBILE_CARD_SHIFT; + int offset = (uword_t)c & (IMMOBILE_CARD_BYTES-1); + if (offset < tlsf_page_sso[tlsf_page]) tlsf_page_sso[tlsf_page] = offset; + text_page_genmask[find_text_page_index(c)] |= 1; +#if 0 + if (code_total_nwords(c) > requested_nwords) + fprintf(stderr, "NOTE: asked for %d words but got %d\n", + requested_nwords, code_total_nwords(c)); #endif + return c; +} -//// Variable-length utilities - -/* Return the generation mask for objects headers on 'page_index' - including at most one object that starts before the page but ends on - or after it. - If the scan start is within the page, i.e. less than DOUBLEWORDS_PER_PAGE - (note that the scan start is measured relative to the page end) then - we don't need to OR in the generation byte from an extra object, - as all headers on the page are accounted for in the page generation mask. - Also an empty page (where scan start is zero) avoids looking - at the next page's first object by accident via the same test. */ -unsigned char varyobj_page_gens_augmented(low_page_index_t page_index) +void tlsf_unalloc_codeblob(tlsf_t tlsf, struct code* code) { - return (varyobj_pages[page_index].scan_start_offset <= DOUBLEWORDS_PER_PAGE - ? 0 : (1<<immobile_obj_generation(varyobj_scan_start(page_index)))) - | varyobj_pages[page_index].generations; + int nwords = code_total_nwords(code); + lispobj* end = (lispobj*)code + nwords; + /* If the HWM is the end of the object being freed, adjust the HWM. There are 2 cases: + * 1. if the previous block is free, then the start of the previous physical block + * is the new high water mark. The rightmost blocks in this picture get conbined. + * The block to the left of the already-free one is definitely used. + * +-------+------+----------+ + * | used | free | freeing | <- current HWM + * +-------+------+----------+ + * ^ new HWM + * + * 2. previous block is in-use: this object's address is the new HWM + */ + if (end == text_space_highwatermark) { + if (code->header & block_header_prev_free_bit) + /* The word prior to 'code' is the pointer to the previous physical block_header_t. + * The high water mark is 1 word beyond the previous physical block due to the + * discrepancy between block_header_t and where a block logically begins. */ + text_space_highwatermark = 1 + (lispobj*)((lispobj*)code)[-1]; + else + text_space_highwatermark = (lispobj*)code; + gc_assert(!((uword_t)text_space_highwatermark & LOWTAG_MASK)); + } + // See if the page scan start needs to change + low_page_index_t tlsf_page = ((char*)code - (char*)tlsf_mem_start) >> IMMOBILE_CARD_SHIFT; + int offset = (uword_t)code & (IMMOBILE_CARD_BYTES-1); + if (offset == tlsf_page_sso[tlsf_page]) { + lispobj* next = end; + if (*next & block_header_free_bit) { + next += code_total_nwords((struct code*)next); + gc_assert(!(*next & block_header_free_bit)); // adjacent free blocks can't occur + } + // If the next used block is on the same page, then it becomes the page scan start + // even if it the ending sentinel block (which counts as "used"). + if ((((uword_t)next ^ (uword_t)code) >> IMMOBILE_CARD_SHIFT) == 0) { + tlsf_page_sso[tlsf_page] = (uword_t)next & (IMMOBILE_CARD_BYTES-1); + } else { + tlsf_page_sso[tlsf_page] = USHRT_MAX; + // the tlsf_page index is based on tlsf_mem_start, but gemmask[] is based on TEXT_SPACE_START + int text_page = find_text_page_index(code); + text_page_genmask[text_page] = 0; + } + } + // point to the user data, not the header, when calling free + tlsf_free(tlsf, (lispobj*)code + 1); } //// Fixed-length object allocator @@ -232,60 +309,9 @@ static int get_freeish_page(int hint_page, int attributes) lose("No more immobile pages available"); } -/// The size classes are: 2w, 4w, 6w, 8w, ..., up to 20w. -/// Each size class can store at most 2 different alignments. So for example in -/// the size class for 14 words there will be a page hint for 14-word-aligned -/// objects and at most one other alignment. -#define MAX_SIZE_CLASSES 10 -#define MAX_HINTS_PER_CLASS 2 -long page_hints[MAX_SIZE_CLASSES*MAX_HINTS_PER_CLASS]; -static inline int hint_attributes(long hint) { return hint & 0xFFFFFFFF; } -static int hint_page(long hint) { return hint>>32; } -static long make_hint(int page, int attributes) { - return ((long)page << 32) | attributes; -} - -static int get_hint(int attributes, int *page) -{ - long hint; - unsigned int size = attributes >> 16; - int hint_index = size - 2, limit = hint_index + 1, free_slot = -1; - if (hint_index > (int)(sizeof page_hints / sizeof (long))) - lose("Unexpectedly large fixedobj allocation request"); - for ( ; hint_index <= limit; ++hint_index ) { -#ifdef __ATOMIC_SEQ_CST - __atomic_load(&page_hints[hint_index], &hint, __ATOMIC_SEQ_CST); -#else - hint = __sync_fetch_and_add(&page_hints[hint_index], 0); -#endif - if (hint_attributes(hint) == attributes) { - *page = hint_page(hint); - return hint_index; - } else if (hint == 0 && free_slot < 0) - free_slot = hint_index; - } - if (free_slot<0) - lose("Should not happen"); // TODO: evict a hint - // Linearly search for a free page from the beginning - int free_page = get_freeish_page(0, attributes); - *page = free_page; - int existing = __sync_val_compare_and_swap(&page_hints[free_slot], 0, - make_hint(free_page, attributes)); - if (existing) // collided. don't worry about it - return -1; - return free_slot; -} - -static void unset_hint(int page) -{ - int attributes = fixedobj_pages[page].attr.packed; - unsigned int size = (attributes >> 16) & 0xff; // mask off the generation bits - int hint_index = size - 2; - if (hint_page(page_hints[hint_index]) == page) - page_hints[hint_index] = 0; - if (hint_page(page_hints[hint_index+1]) == page) - page_hints[hint_index+1] = 0; -} +/// Size class is specified by lisp now +#define MAX_ALLOCATOR_SIZE_CLASSES 10 +uint32_t fixedobj_page_hint[MAX_ALLOCATOR_SIZE_CLASSES]; // Unused, but possibly will be for some kind of collision-avoidance scheme // on claiming of new free pages. @@ -311,46 +337,75 @@ long immobile_alloc_collisions; masking. if the next address is above or equal to the page start, store it in the hint, otherwise mark the page full */ -static lispobj* alloc_immobile_obj(int page_attributes, lispobj header) +lispobj AMD64_SYSV_ABI +alloc_immobile_fixedobj(int size_class, int spacing_words, uword_t header) { - int hint_index, page; + size_class = fixnum_value(size_class); + spacing_words = fixnum_value(spacing_words); + header = fixnum_value(header); + + unsigned int page; lispobj word; - char * page_data, * obj_ptr, * next_obj_ptr, * limit, * next_free; - int spacing_in_bytes = OBJ_SPACING(page_attributes) << WORD_SHIFT; + int page_attributes = MAKE_ATTR(spacing_words); + int spacing_in_bytes = spacing_words << WORD_SHIFT; const int npages = FIXEDOBJ_SPACE_SIZE / IMMOBILE_CARD_BYTES; - hint_index = get_hint(page_attributes, &page); - gc_dcheck(fixedobj_page_address(page) < (void*)fixedobj_free_pointer); + page = fixedobj_page_hint[size_class]; + if (!page) { + page = get_freeish_page(0, page_attributes); + __sync_val_compare_and_swap(&fixedobj_page_hint[size_class], 0, page); + } + + /* BUG: This assertion is itself buggy and has to be commented out + * if running with extra debug assertions. + * It's only OK in single-threaded code, but consider two threads: + * Thread A Thread B + * -------- -------- + * 1. change attributes of + * page 483 (e.g.) from 0 + * to something + * 2. observe that page 483 has + * desired page_attributes, + * and return it from get_freeish_page + * 3. read the now-obsolete value of + * fixedobj_free_pointer at the dcheck. + * 4. bump the free pointer to + * the end of page 483 + * and return that page + * 5. FAIL the dcheck + * 5. pass the dcheck */ + // gc_dcheck(fixedobj_page_address(page) < (void*)fixedobj_free_pointer); do { - page_data = fixedobj_page_address(page); - obj_ptr = page_data + fixedobj_pages[page].free_index; - limit = page_data + IMMOBILE_CARD_BYTES - spacing_in_bytes; + char *page_data = fixedobj_page_address(page); + char *limit = page_data + IMMOBILE_CARD_BYTES - spacing_in_bytes; + char *obj_ptr = page_data + fixedobj_pages[page].free_index; while (obj_ptr <= limit) { word = *(lispobj*)obj_ptr; - next_obj_ptr = obj_ptr + spacing_in_bytes; + char *next_obj_ptr = obj_ptr + spacing_in_bytes; if (fixnump(word) // a fixnum marks free space && __sync_bool_compare_and_swap((lispobj*)obj_ptr, word, header)) { // The value formerly in the header word was the offset to // the next hole. Use it to update the freelist pointer. - // Just slam it in. - fixedobj_pages[page].free_index = next_obj_ptr + word - page_data; - return (lispobj*)obj_ptr; + // Just slam it in + int new_free_index = next_obj_ptr + word - page_data; + fixedobj_pages[page].free_index = new_free_index; + // Indicate in the generation mask that there is a generation0 object + __sync_fetch_and_or(&fixedobj_pages[page].attr.parts.gens_, 1); + return compute_lispobj((lispobj*)obj_ptr); } // If some other thread updated the free_index // to a larger value, use that. (See example below) - next_free = page_data + fixedobj_pages[page].free_index; + char *next_free = page_data + fixedobj_pages[page].free_index; obj_ptr = next_free > next_obj_ptr ? next_free : next_obj_ptr; } set_page_full(page); int old_page = page; page = get_freeish_page(page+1 >= npages ? 0 : page+1, page_attributes); - if (hint_index >= 0) { // try to update the hint - __sync_val_compare_and_swap(page_hints + hint_index, - make_hint(old_page, page_attributes), - make_hint(page, page_attributes)); - } + // try to update the hint + __sync_val_compare_and_swap(&fixedobj_page_hint[size_class], + old_page, page); } while (1); } @@ -377,56 +432,31 @@ Threads A, and B, and C each want to claim index 6. // Find the high water marks for this GC scavenge phase // (avoid passing exactly IMMOBILE_SPACE_END, which has no page index) #define calc_max_used_fixedobj_page() find_fixedobj_page_index(fixedobj_free_pointer-1) -#define calc_max_used_varyobj_page() find_varyobj_page_index(varyobj_free_pointer-1) - -void update_immobile_nursery_bits() -{ - low_page_index_t max_used_fixedobj_page = calc_max_used_fixedobj_page(); - low_page_index_t page; - - if (ENABLE_PAGE_PROTECTION) { - // Unprotect the in-use ranges. Any page could be written during scavenge - os_protect((os_vm_address_t)FIXEDOBJ_SPACE_START, - (lispobj)fixedobj_free_pointer - FIXEDOBJ_SPACE_START, - OS_VM_PROT_ALL); - } - - for (page=0; page <= max_used_fixedobj_page ; ++page) { - // any page whose free index changed contains nursery objects - if (fixedobj_pages[page].free_index >> WORD_SHIFT != - fixedobj_pages[page].prior_gc_free_word_index) - fixedobj_pages[page].gens |= 1; -#ifdef VERIFY_PAGE_GENS - check_fixedobj_page(page, 0xff, 0xff); -#endif - } -#ifdef VERIFY_PAGE_GENS - check_varyobj_pages(); -#endif -} +#define calc_max_used_text_page() find_text_page_index(text_space_highwatermark-1) /* Turn a white object grey. Also enqueue the object for re-scan if required */ void enliven_immobile_obj(lispobj *ptr, int rescan) // a native pointer { gc_assert(widetag_of(ptr) != SIMPLE_FUN_WIDETAG); // can't enliven interior pointer + gc_assert(widetag_of(ptr) != FILLER_WIDETAG); gc_assert(immobile_obj_gen_bits(ptr) == from_space); int pointerish = !leaf_obj_widetag_p(widetag_of(ptr)); int bits = (pointerish ? 0 : IMMOBILE_OBJ_VISITED_FLAG); // enlivening makes the object appear as if written, so that - // scav_code_header won't skip it, thus ensuring we transitively + // scav_code_blob won't skip it, thus ensuring we transitively // scavenge + enliven newspace objects. if (widetag_of(ptr) == CODE_HEADER_WIDETAG) bits |= OBJ_WRITTEN_FLAG; assign_generation(ptr, bits | new_space); low_page_index_t page_index = find_fixedobj_page_index(ptr); - boolean varyobj = 0; + boolean is_text = 0; if (page_index < 0) { - page_index = find_varyobj_page_index(ptr); + page_index = find_text_page_index(ptr); gc_assert(page_index >= 0); - varyobj_pages[page_index].generations |= 1<<new_space; - varyobj = 1; + text_page_genmask[page_index] |= 1<<new_space; + is_text = 1; } else { fixedobj_pages[page_index].gens |= 1<<new_space; } @@ -435,8 +465,8 @@ enliven_immobile_obj(lispobj *ptr, int rescan) // a native pointer // is cleared so that the page is not skipped during root scan. if (!rescan) { if (pointerish) { - if (varyobj) - varyobj_page_touched_bits[page_index/32] |= 1U << (page_index & 31); + if (is_text) + text_page_touched_bits[page_index/32] |= 1U << (page_index & 31); else SET_WP_FLAG(page_index, WRITE_PROTECT_CLEARED); } @@ -458,6 +488,48 @@ enliven_immobile_obj(lispobj *ptr, int rescan) // a native pointer ++immobile_scav_queue_count; } +static uint32_t* loaded_codeblob_offsets; +static int loaded_codeblob_offsets_len; + +// Find the lowest addressed object on specified page, or 0 if there isn't one +lispobj* text_page_scan_start(low_page_index_t page) { + char* pagebase = text_page_address(page); + if (pagebase < (char*)tlsf_mem_start) { + uint32_t* data = loaded_codeblob_offsets; + int index = bsearch_greatereql_uint32((int)(pagebase-(char*)TEXT_SPACE_START), + data, loaded_codeblob_offsets_len); + lispobj* start = 0; + // I don't think index could ever be -1 ("not found"), could it? + if (index >= 0) start = (lispobj*)(TEXT_SPACE_START+data[index]); + // But it is possible for a page to have no scan start (nothing starts on it) + return (start && (char*)start < pagebase+IMMOBILE_CARD_BYTES) ? start : 0; + } + if (pagebase > (char*)text_space_highwatermark) return 0; + int tlsf_page = (pagebase - (char*)tlsf_mem_start) / IMMOBILE_CARD_BYTES; + unsigned short sso = tlsf_page_sso[tlsf_page]; + return (sso < IMMOBILE_CARD_BYTES) ? (lispobj*)(pagebase + sso) : 0; +} + +lispobj* search_immobile_code(char* ptr) { + if (ptr < (char*)TEXT_SPACE_START) return 0; + lispobj* candidate = 0; + if (ptr < (char*)tlsf_mem_start) { + uint32_t* data = loaded_codeblob_offsets; + int index = bsearch_lesseql_uint32((int)(ptr-(char*)TEXT_SPACE_START), + data, loaded_codeblob_offsets_len); + if (index >= 0) candidate = (lispobj*)(TEXT_SPACE_START+data[index]); + } else if (ptr < (char*)text_space_highwatermark) { + lispobj node = brothertree_find_lesseql((uword_t)ptr, + SYMBOL(IMMOBILE_CODEBLOB_TREE)->value); + if (node != NIL) candidate = (lispobj*)((struct binary_node*)INSTANCE(node))->key; + } + if (candidate && widetag_of(candidate) == CODE_HEADER_WIDETAG) { + int nwords = code_total_nwords((struct code*)candidate); + if (ptr < (char*)(candidate+nwords)) return candidate; + } + return 0; +} + /* If 'addr' points to an immobile object, then make the object live by promotion. But if the object is not in the generation being collected, do nothing */ @@ -466,25 +538,10 @@ boolean immobile_space_preserve_pointer(void* addr) unsigned char genmask = compacting_p() ? 1<<from_space : 0xff; lispobj* object_start; int valid = 0; - low_page_index_t page_index = find_varyobj_page_index(addr); - - if (page_index >= 0) { - // Restrict addr to lie below 'varyobj_free_pointer'. - // This way, if the gens byte is nonzero but there is - // a final array acting as filler on the remainder of the - // final page, we won't accidentally find that. - lispobj* scan_start; - valid = addr < (void*)varyobj_free_pointer - && (varyobj_page_gens_augmented(page_index) & genmask) - && (scan_start = varyobj_scan_start(page_index)) <= (lispobj*)addr - && (object_start = gc_search_space(scan_start, addr)) != 0 - /* gc_search_space can return filler objects, unlike - * search_immobile_space which can not */ - && !filler_obj_p(object_start) - && (instruction_ptr_p(addr, object_start) - || properly_tagged_descriptor_p(addr, object_start)); - } else if ((page_index = find_fixedobj_page_index(addr)) >= FIXEDOBJ_RESERVED_PAGES - && ((fixedobj_pages[page_index].gens & genmask) != 0)) { + low_page_index_t page_index; + + if ((page_index = find_fixedobj_page_index(addr)) >= FIXEDOBJ_RESERVED_PAGES + && ((fixedobj_pages[page_index].gens & genmask) != 0)) { int obj_spacing = fixedobj_page_obj_align(page_index); int obj_index = ((uword_t)addr & (IMMOBILE_CARD_BYTES-1)) / obj_spacing; dprintf((logfile,"Pointer %p is to immobile page %d, object %d\n", @@ -492,11 +549,14 @@ boolean immobile_space_preserve_pointer(void* addr) char* page_start_addr = PTR_ALIGN_DOWN(addr, IMMOBILE_CARD_BYTES); object_start = (lispobj*)(page_start_addr + obj_index * obj_spacing); valid = !fixnump(*object_start) - && (lispobj*)addr < object_start + fixedobj_page_obj_size(page_index) - && (properly_tagged_descriptor_p(addr, object_start) - || widetag_of(object_start) == FUNCALLABLE_INSTANCE_WIDETAG); - } else { - return 0; + && (widetag_of(object_start) == FDEFN_WIDETAG || + properly_tagged_descriptor_p(addr, object_start)); + } else if (compacting_p() && (lispobj*)addr < tlsf_mem_start) { + // Can ignore this pointer if it's point to pseudostatic text + return 0; + } else if ((object_start = search_immobile_code(addr)) != 0) { + valid = instruction_ptr_p(addr, object_start) + || properly_tagged_descriptor_p(addr, object_start); } if (valid && (!compacting_p() || immobile_obj_gen_bits(object_start) == from_space)) { @@ -538,16 +598,18 @@ static void full_scavenge_immobile_newspace() // Variable-size object pages - low_page_index_t max_used_varyobj_page = calc_max_used_varyobj_page(); + low_page_index_t max_used_text_page = calc_max_used_text_page(); page = -1; // -1 because of pre-increment while (1) { // Find the next page with anything in newspace. do { - if (++page > max_used_varyobj_page) return; - } while ((varyobj_pages[page].generations & bit) == 0); - lispobj* obj = varyobj_scan_start(page); + if (++page > max_used_text_page) return; + } while ((text_page_genmask[page] & bit) == 0); + lispobj* obj = text_page_scan_start(page); + if (!obj) continue; // page contains nothing - can this happen? do { - lispobj* limit = (lispobj*)varyobj_page_address(page) + WORDS_PER_PAGE; + lispobj* limit = (lispobj*)text_page_address(page) + WORDS_PER_PAGE; + if (limit > text_space_highwatermark) limit = text_space_highwatermark; int n_words; for ( ; obj < limit ; obj += n_words ) { lispobj header = *obj; @@ -555,15 +617,16 @@ static void full_scavenge_immobile_newspace() set_visited(obj); n_words = scavtab[header_widetag(header)](obj, header); } else { - n_words = sizetab[header_widetag(header)](obj); + n_words = headerobj_size2(obj, header); } } - page = find_varyobj_page_index(obj); + gc_assert(obj <= text_space_highwatermark); // Bail out if exact absolute end of immobile space was reached. - if (page < 0) return; + if (obj == text_space_highwatermark) break; // If 'page' should be scanned, then pick up where we left off, // without recomputing 'obj' but setting a higher 'limit'. - } while (varyobj_pages[page].generations & bit); + page = find_text_page_index(obj); + } while (text_page_genmask[page] & bit); } } @@ -615,33 +678,6 @@ void scavenge_immobile_newspace() } } -// Return a page >= page_index having potential old->young pointers, -// or -1 if there isn't one. -static int next_varyobj_root_page(unsigned int page_index, - unsigned int end_bitmap_index, - unsigned char genmask) -{ - unsigned int map_index = page_index / 32; - if (map_index >= end_bitmap_index) return -1; - int bit_index = page_index & 31; - // Look only at bits of equal or greater weight than bit_index. - unsigned int word = (0xFFFFFFFFU << bit_index) & varyobj_page_touched_bits[map_index]; - while (1) { - if (word) { - bit_index = ffs(word) - 1; - page_index = map_index * 32 + bit_index; - if (varyobj_page_gens_augmented(page_index) & genmask) - return page_index; - else { - word ^= (1U<<bit_index); - continue; - } - } - if (++map_index >= end_bitmap_index) return -1; - word = varyobj_page_touched_bits[map_index]; - } -} - void scavenge_immobile_roots(generation_index_t min_gen, generation_index_t max_gen) { @@ -669,33 +705,49 @@ scavenge_immobile_roots(generation_index_t min_gen, generation_index_t max_gen) } while (NEXT_FIXEDOBJ(obj, obj_spacing) <= limit); } - // Variable-length object pages - low_page_index_t max_used_varyobj_page = calc_max_used_varyobj_page(); - unsigned n_varyobj_pages = 1+max_used_varyobj_page; - unsigned end_bitmap_index = (n_varyobj_pages+31)/32; - page = next_varyobj_root_page(0, end_bitmap_index, genmask); - while (page >= 0) { - lispobj* obj = varyobj_scan_start(page); + // Text pages + low_page_index_t max_used_text_page = calc_max_used_text_page(); + page = 0; + while (page <= max_used_text_page) { + if (!text_page_touched(page) || !(text_page_genmask[page] & genmask)) { + ++page; + continue; + } + lispobj* obj = text_page_scan_start(page); + if (!obj) { ++page; continue; } do { - lispobj* limit = (lispobj*)varyobj_page_address(page) + WORDS_PER_PAGE; + lispobj* limit = (lispobj*)text_page_address(page) + WORDS_PER_PAGE; int n_words, gen; + if (limit > text_space_highwatermark) limit = text_space_highwatermark; for ( ; obj < limit ; obj += n_words ) { lispobj header = *obj; - // scav_code_header will do nothing if the object isn't + // scav_code_blob will do nothing if the object isn't // marked as written. if (genmask >> (gen=immobile_obj_gen_bits(obj)) & 1) { if (gen == new_space) { set_visited(obj); } n_words = scavtab[header_widetag(header)](obj, header); } else { - n_words = sizetab[header_widetag(header)](obj); + n_words = headerobj_size2(obj, header); } } - page = find_varyobj_page_index(obj); + if (obj == text_space_highwatermark) { page = -1; break; } + page = find_text_page_index(obj); } while (page > 0 - && (varyobj_pages[page].generations & genmask) - && varyobj_page_touched(page)); + && (text_page_genmask[page] & genmask) + && text_page_touched(page)); if (page < 0) break; - page = next_varyobj_root_page(1+page, end_bitmap_index, genmask); + } + if (sb_sprof_enabled) { + // Make another pass over all code and enliven all of 'from_space' + lispobj* where = (lispobj*)TEXT_SPACE_START; + lispobj* limit = text_space_highwatermark; + while (where < limit) { + if (widetag_of(where) == CODE_HEADER_WIDETAG + && immobile_obj_gen_bits(where) == from_space + && code_serialno((struct code*)where) != 0) + enliven_immobile_obj(where, 1); + where += headerobj_size(where); + } } scavenge_immobile_newspace(); } @@ -774,33 +826,29 @@ range_points_to_younger_p(lispobj* obj, lispobj* end, // Scan a fixed-size object for old-to-young pointers. // Since fixed-size objects are boxed and on known boundaries, // we never start in the middle of random bytes, so the answer is exact. -static inline boolean +static boolean fixedobj_points_to_younger_p(lispobj* obj, int n_words, int gen, int keep_gen, int new_gen) { - lispobj layout, lbitmap; + lispobj layout; switch (widetag_of(obj)) { case FDEFN_WIDETAG: - return younger_p(fdefn_callee_lispobj((struct fdefn*)obj), - gen, keep_gen, new_gen) - || range_points_to_younger_p(obj+1, obj+3, gen, keep_gen, new_gen); - case CODE_HEADER_WIDETAG: - // This is a simplifying trampoline around a closure or FIN. - // The only pointerish slot is debug_info (the called function). - // The size slot is a descriptor, though a non-pointer. - return younger_p(((struct code*)obj)->debug_info, gen, keep_gen, new_gen); + if (younger_p(decode_fdefn_rawfun((struct fdefn*)obj), gen, keep_gen, new_gen)) return 1; + break; // proceed to other slots as usual (harmlessly revisiting 'raw_addr') case INSTANCE_WIDETAG: - case FUNCALLABLE_INSTANCE_WIDETAG: layout = instance_layout(obj); + if (!layout) return 0; // object can't have pointers in it yet if (younger_p(layout, gen, keep_gen, new_gen)) return 1; - if ((lbitmap = LAYOUT(layout)->bitmap) != make_fixnum(-1)) { - gc_assert(fixnump(lbitmap)); // No bignums (yet) - sword_t bitmap = fixnum_value(lbitmap); + struct bitmap bitmap = get_layout_bitmap(LAYOUT(layout)); + gc_assert(bitmap.nwords == 1); + if (bitmap.bits[0] != (sword_t)-1) { + sword_t mask = bitmap.bits[0]; lispobj* where = obj + 1; - for ( ; --n_words ; ++where, bitmap >>= 1 ) - if ((bitmap & 1) != 0 && younger_p(*where, gen, keep_gen, new_gen)) + lispobj* limit = obj + n_words; + for ( ; where < limit ; ++where, mask >>= 1 ) + if ((mask & 1) != 0 && younger_p(*where, gen, keep_gen, new_gen)) return 1; return 0; } @@ -809,41 +857,6 @@ fixedobj_points_to_younger_p(lispobj* obj, int n_words, return range_points_to_younger_p(obj+1, obj+n_words, gen, keep_gen, new_gen); } -static boolean -varyobj_points_to_younger_p(lispobj* obj, int gen, int keep_gen, int new_gen, - os_vm_address_t page_begin, - os_vm_address_t page_end) // upper (exclusive) bound -{ - lispobj *begin, *end, word = *obj; - unsigned char widetag = header_widetag(word); - if (widetag == CODE_HEADER_WIDETAG) { // usual case. Like scav_code_header() - return header_rememberedp(word); - } else if (widetag == FDEFN_WIDETAG || - widetag == FUNCALLABLE_INSTANCE_WIDETAG) { - // both of these have non-descriptor bits in at least one word, - // thus precluding a simple range scan. - // Due to ignored address bounds, in the rare case of a FIN or fdefn in varyobj - // subspace and spanning cards, we might say that neither card can be protected, - // when one or the other could be. Not a big deal. - return fixedobj_points_to_younger_p(obj, sizetab[widetag](obj), - gen, keep_gen, new_gen); - } else if (widetag == SIMPLE_VECTOR_WIDETAG) { - sword_t length = fixnum_value(((struct vector *)obj)->length); - begin = obj + 2; // skip the header and length - end = obj + ALIGN_UP(length + 2, 2); - } else if (leaf_obj_widetag_p(widetag)) { - return 0; - } else { - lose("Unexpected widetag %x @ %p", widetag, obj); - } - // Fallthrough: scan words from begin to end - if (page_begin > (os_vm_address_t)begin) begin = (lispobj*)page_begin; - if (page_end < (os_vm_address_t)end) end = (lispobj*)page_end; - if (end > begin && range_points_to_younger_p(begin, end, gen, keep_gen, new_gen)) - return 1; - return 0; -} - /// The next two functions are analogous to 'update_page_write_prot()' /// but they differ in that they are "precise" - random code bytes that look /// like pointers are not accidentally treated as pointers. @@ -858,12 +871,12 @@ varyobj_points_to_younger_p(lispobj* obj, int gen, int keep_gen, int new_gen, static inline boolean can_wp_fixedobj_page(page_index_t page, int keep_gen, int new_gen) { int obj_spacing = fixedobj_page_obj_align(page); - int obj_size_words = fixedobj_page_obj_size(page); lispobj* obj = fixedobj_page_address(page); lispobj* limit = compute_fixedobj_limit(obj, obj_spacing); do { if (!fixnump(*obj) && // an object header - fixedobj_points_to_younger_p(obj, obj_size_words, + fixedobj_points_to_younger_p(obj, + headerobj_size(obj), immobile_obj_generation(obj), keep_gen, new_gen)) return 0; @@ -871,24 +884,15 @@ static inline boolean can_wp_fixedobj_page(page_index_t page, int keep_gen, int return 1; } -// To scan _only_ 'page' is impossible in general, but we can act like only -// one page was scanned by backing up to the first object whose end is on -// or after it, and then restricting points_to_younger within the boundaries. -// Doing it this way is probably much better than conservatively assuming -// that any word satisfying is_lisp_pointer() is a pointer. -static inline boolean can_wp_varyobj_page(page_index_t page, int keep_gen, int new_gen) +// Return 1 if any header on 'page' is in the remembered set. +static inline boolean can_wp_text_page(page_index_t page) { - lispobj *begin = varyobj_page_address(page); + lispobj *begin = text_page_address(page); lispobj *end = begin + WORDS_PER_PAGE; - lispobj *obj = varyobj_scan_start(page); - for ( ; obj < end ; obj += sizetab[widetag_of(obj)](obj) ) { + lispobj *obj = text_page_scan_start(page); + for ( ; obj < end ; obj += headerobj_size(obj) ) { gc_assert(other_immediate_lowtag_p(*obj)); - if (!filler_obj_p(obj) && - varyobj_points_to_younger_p(obj, - immobile_obj_generation(obj), - keep_gen, new_gen, - (os_vm_address_t)begin, - (os_vm_address_t)end)) + if (widetag_of(obj) == CODE_HEADER_WIDETAG && header_rememberedp(*obj)) return 0; } return 1; @@ -942,7 +946,6 @@ sweep_fixedobj_pages(int raise) // at the start of the prior GC, and subtracting from that the number // that exist now, we know how much usable space was obtained (per page). int n_holes = 0; - int word_idx; SETUP_GENS(); @@ -963,7 +966,6 @@ sweep_fixedobj_pages(int raise) continue; } int obj_spacing = fixedobj_page_obj_align(page); - int obj_size_words = fixedobj_page_obj_size(page); page_base = fixedobj_page_address(page); limit = compute_fixedobj_limit(page_base, obj_spacing); obj = (lispobj*)page_base; @@ -989,24 +991,23 @@ sweep_fixedobj_pages(int raise) hole = obj; n_holes ++; } else if ((gen = immobile_obj_gen_bits(obj)) == discard_gen) { // trash - for (word_idx=obj_size_words-1 ; word_idx > 0 ; --word_idx) - obj[word_idx] = 0; + memset(obj, 0, obj_spacing); goto trash_it; } else if (gen == keep_gen) { assign_generation(obj, gen = new_gen); #ifdef DEBUG - gc_assert(!fixedobj_points_to_younger_p(obj, obj_size_words, + gc_assert(!fixedobj_points_to_younger_p(obj, + headerobj_size(obj), gen, keep_gen, new_gen)); #endif any_kept = -1; - } else if (wp_it && fixedobj_points_to_younger_p(obj, obj_size_words, + } else if (wp_it && fixedobj_points_to_younger_p(obj, + headerobj_size(obj), gen, keep_gen, new_gen)) wp_it = 0; } while (NEXT_FIXEDOBJ(obj, obj_spacing) <= limit); if ( hole ) // terminate the chain of holes *hole = (lispobj)((char*)obj - ((char*)hole + obj_spacing)); - fixedobj_pages[page].prior_gc_free_word_index = - fixedobj_pages[page].free_index >> WORD_SHIFT; COMPUTE_NEW_MASK(mask, fixedobj_pages[page].gens); if ( mask ) { @@ -1017,7 +1018,6 @@ sweep_fixedobj_pages(int raise) } } else { dprintf((logfile,"page %d is all garbage\n", page)); - unset_hint(page); fixedobj_pages[page].attr.packed = 0; } #ifdef DEBUG @@ -1025,102 +1025,78 @@ sweep_fixedobj_pages(int raise) #endif dprintf((logfile,"page %d: %d holes\n", page, n_holes)); } -} - -static void make_filler(void* where, int nbytes) -{ - if (nbytes < 4*N_WORD_BYTES) - lose("can't place filler @ %p - too small", where); - else { // Create a filler object. - struct code* code = (struct code*)where; - code->header = ((uword_t)nbytes << (CODE_HEADER_SIZE_SHIFT-WORD_SHIFT)) - | CODE_HEADER_WIDETAG; - code->boxed_size = 0; - code->debug_info = varyobj_holes; - varyobj_holes = (lispobj)code; - } + memset(fixedobj_page_hint, 0, sizeof fixedobj_page_hint); } // Scan for freshly trashed objects and turn them into filler. // Lisp is responsible for consuming the free space // when it next allocates a variable-size object. static void -sweep_varyobj_pages(int raise) +sweep_text_pages(int raise) { + lispobj *freelist = 0, *freelist_tail = 0; SETUP_GENS(); - low_page_index_t max_used_varyobj_page = calc_max_used_varyobj_page(); - lispobj* free_pointer = varyobj_free_pointer; + low_page_index_t max_used_text_page = calc_max_used_text_page(); + lispobj* free_pointer = text_space_highwatermark; low_page_index_t page; - for (page = 0; page <= max_used_varyobj_page; ++page) { - int genmask = varyobj_pages[page].generations; + for (page = 0; page <= max_used_text_page; ++page) { + int genmask = text_page_genmask[page]; if (!(genmask & relevant_genmask)) { // Has nothing in oldspace or newspace. // Scan for old->young pointers, and WP if there are none. - if (ENABLE_PAGE_PROTECTION && varyobj_page_touched(page) - && varyobj_page_gens_augmented(page) > 1 - && can_wp_varyobj_page(page, keep_gen, new_gen)) { - varyobj_page_touched_bits[page/32] &= ~(1U<<(page & 31)); + if (ENABLE_PAGE_PROTECTION && text_page_touched(page) + && text_page_genmask[page] > 1 + && can_wp_text_page(page)) { + text_page_touched_bits[page/32] &= ~(1U<<(page & 31)); } continue; } - lispobj* page_base = varyobj_page_address(page); + lispobj* obj = text_page_scan_start(page); + gc_assert(obj); + lispobj* page_base = text_page_address(page); lispobj* limit = page_base + WORDS_PER_PAGE; if (limit > free_pointer) limit = free_pointer; int any_kept = 0; // was anything moved to the kept generation // wp_it is 1 if we should try to write-protect it now. // If already write-protected, skip the tests. - int wp_it = ENABLE_PAGE_PROTECTION && varyobj_page_touched(page); - lispobj* obj = varyobj_scan_start(page); + int wp_it = ENABLE_PAGE_PROTECTION && text_page_touched(page); int size, gen; - if (obj < page_base) { - // An object whose tail is on this page, or which spans this page, - // would have been promoted/kept while dealing with the page with - // the object header. Therefore we don't need to consider that object, - // * except * that we do need to consider whether it is an old object - // pointing to a young object. - if (wp_it // If we wanted to try write-protecting this page, - // and the object starting before this page is strictly older - // than the generation that we're moving retained objects into - && (gen = immobile_obj_gen_bits(obj)) > new_gen - // and it contains an old->young pointer - && varyobj_points_to_younger_p(obj, gen, keep_gen, new_gen, - (os_vm_address_t)page_base, - (os_vm_address_t)limit)) { - wp_it = 0; - } - // We MUST skip this object in the sweep, because in the case of - // non-promotion (raise=0), we could see an object in from_space - // and believe it to be dead. - obj += sizetab[widetag_of(obj)](obj); - // obj can't hop over this page. If it did, there would be no - // headers on the page, and genmask would have been zero. - gc_assert(obj < limit); - } for ( ; obj < limit ; obj += size ) { lispobj word = *obj; - size = sizetab[header_widetag(word)](obj); - if (filler_obj_p(obj)) { // do nothing + size = object_size2(obj, word); + if (header_widetag(word) == FILLER_WIDETAG) { // ignore } else if ((gen = immobile_obj_gen_bits(obj)) == discard_gen) { - make_filler(obj, size * N_WORD_BYTES); + gc_assert(header_widetag(word) == CODE_HEADER_WIDETAG); + assign_widetag(obj, FILLER_WIDETAG); + // ASSUMPTION: little-endian + ((char*)obj)[2] = 0; // clear the TRACED flag + ((char*)obj)[3] = 0; // clear the WRITTEN flag and the generation + // Building the list in ascending order means less work later on + // because the HWM will get adjusted once only, at the end. + // Descending order would decrease the HWM for each deallocation. + if (freelist) freelist_tail[1] = (lispobj)obj; else freelist = obj; + freelist_tail = obj; } else if (gen == keep_gen) { assign_generation(obj, gen = new_gen); #ifdef DEBUG - gc_assert(!varyobj_points_to_younger_p(obj, gen, keep_gen, new_gen, + gc_assert(!text_points_to_younger_p(obj, gen, keep_gen, new_gen, (os_vm_address_t)page_base, (os_vm_address_t)limit)); #endif any_kept = -1; - } else if (wp_it && - varyobj_points_to_younger_p(obj, gen, keep_gen, new_gen, - (os_vm_address_t)page_base, - (os_vm_address_t)limit)) + } else if (wp_it && header_rememberedp(*obj)) wp_it = 0; } - COMPUTE_NEW_MASK(mask, varyobj_pages[page].generations); - varyobj_pages[page].generations = mask; + COMPUTE_NEW_MASK(mask, text_page_genmask[page]); + text_page_genmask[page] = mask; if ( mask && wp_it ) - varyobj_page_touched_bits[page/32] &= ~(1U << (page & 31)); + text_page_touched_bits[page/32] &= ~(1U << (page & 31)); + } + // Stuff the new freelist onto the front of codeblob_freelist + if (freelist_tail) { + freelist_tail[1] = codeblob_freelist; + codeblob_freelist = (lispobj)freelist; } } @@ -1134,35 +1110,36 @@ sweep_immobile_space(int raise) { gc_assert(immobile_scav_queue_count == 0); sweep_fixedobj_pages(raise); - sweep_varyobj_pages(raise); + sweep_text_pages(raise); } -static void gc_init_immobile() +void gc_init_immobile() { #ifdef DEBUG logfile = stderr; #endif int n_fixedobj_pages = FIXEDOBJ_SPACE_SIZE / IMMOBILE_CARD_BYTES; - int n_varyobj_pages = VARYOBJ_SPACE_SIZE / IMMOBILE_CARD_BYTES; + int n_text_pages = TEXT_SPACE_SIZE / IMMOBILE_CARD_BYTES; fixedobj_pages = calloc(n_fixedobj_pages, sizeof(struct fixedobj_page)); gc_assert(fixedobj_pages); - n_bitmap_elts = ALIGN_UP(n_varyobj_pages, 32) / 32; - int request = n_bitmap_elts * sizeof (int) + n_varyobj_pages * sizeof (int); - varyobj_page_touched_bits = (unsigned int*)calloc(1, request); - gc_assert(varyobj_page_touched_bits); + n_bitmap_elts = ALIGN_UP(n_text_pages, 32) / 32; + text_page_touched_bits = (unsigned int*)calloc(n_bitmap_elts, sizeof (int)); + gc_assert(text_page_touched_bits); // The conservative value for 'touched' is 1. - memset(varyobj_page_touched_bits, 0xff, n_bitmap_elts * sizeof (int)); - varyobj_pages = (struct varyobj_page*)(varyobj_page_touched_bits + n_bitmap_elts); + memset(text_page_touched_bits, 0xff, n_bitmap_elts * sizeof (int)); + text_page_genmask = calloc(n_text_pages, 1); // Scav queue is arbitrarily located. immobile_scav_queue = malloc(QCAPACITY * sizeof(lispobj)); + tlsf_control = malloc(tlsf_size()); + tlsf_create(tlsf_control); } // Signify that scan_start is initially not reliable static int page_attributes_valid; // Set the characteristics of each used page at image startup time. -void immobile_space_coreparse(uword_t fixedobj_len, uword_t varyobj_len) +void immobile_space_coreparse(uword_t fixedobj_len, uword_t text_len) { int n_pages, word_idx, page; generation_index_t gen = CORE_PAGE_GENERATION; @@ -1176,22 +1153,24 @@ void immobile_space_coreparse(uword_t fixedobj_len, uword_t varyobj_len) end = (lispobj*)((char*)where + fixedobj_len); while (where < end) { if (!fixnump(*where)) assign_generation(where, gen); - where += OBJECT_SIZE(*where, where); + where += object_size(where); } - where = (lispobj*)VARYOBJ_SPACE_START; - end = (lispobj*)((char*)where + varyobj_len); - while (where < end) { - if (!filler_obj_p(where)) assign_generation(where, gen); - where += OBJECT_SIZE(*where, where); + where = (lispobj*)TEXT_SPACE_START; + while (where < text_space_highwatermark) { + if (widetag_of(where) != FILLER_WIDETAG) assign_generation(where, gen); + where += object_size(where); } - fprintf(stderr, "WARNING: demoted immobile objects to gen%d\n", gen); + // If the regression suite is run with core pages in gen0 (to more aggressively + // test code page transporting), we don't want to cause failures in 'script.test.sh' + // and some other things that look for an exact match on textual output. + if (gencgc_verbose) + fprintf(stderr, "WARNING: demoted immobile objects to gen%d\n", gen); } n_pages = fixedobj_len / IMMOBILE_CARD_BYTES; for (page = 0; page <= FIXEDOBJ_RESERVED_PAGES; ++page) { // set page attributes that can't match anything in get_freeish_page() fixedobj_pages[page].attr.parts.obj_align = 1; - fixedobj_pages[page].attr.parts.obj_size = 1; if (gen != 0 && ENABLE_PAGE_PROTECTION) fixedobj_pages[page].attr.parts.flags = WRITE_PROTECT; fixedobj_pages[page].gens |= 1 << gen; @@ -1203,8 +1182,7 @@ void immobile_space_coreparse(uword_t fixedobj_len, uword_t varyobj_len) lispobj header = *obj; if (!fixnump(header)) { gc_assert(other_immediate_lowtag_p(*obj)); - int size = sizetab[header_widetag(header)](obj); - fixedobj_pages[page].attr.parts.obj_size = size; + int size = object_size2(obj, header); fixedobj_pages[page].attr.parts.obj_align = size; fixedobj_pages[page].gens |= 1 << immobile_obj_gen_bits(obj); if (gen != 0 && ENABLE_PAGE_PROTECTION) @@ -1213,112 +1191,115 @@ void immobile_space_coreparse(uword_t fixedobj_len, uword_t varyobj_len) } } } - uword_t address = VARYOBJ_SPACE_START; - n_pages = varyobj_len / IMMOBILE_CARD_BYTES; - lispobj* obj = (lispobj*)address; - int n_words; - low_page_index_t last_page = 0; - // coreparse() already set varyobj_free_pointer - lispobj* limit = varyobj_free_pointer; - gc_assert(limit != 0 /* would be zero if not mmapped yet */ - && limit <= (lispobj*)(address + varyobj_len)); - for ( ; obj < limit ; obj += n_words ) { - gc_assert(other_immediate_lowtag_p(obj[0])); - n_words = sizetab[widetag_of(obj)](obj); - if (filler_obj_p(obj)) { - // Holes were chained through the debug_info slot at save. - // Just update the head of the chain. - varyobj_holes = (lispobj)obj; - continue; - } - low_page_index_t first_page = find_varyobj_page_index(obj); - last_page = find_varyobj_page_index(obj+n_words-1); - // Only the page with this object header gets a bit in its gen mask. - varyobj_pages[first_page].generations |= 1<<immobile_obj_gen_bits(obj); - // For each page touched by this object, set the page's - // scan_start_offset, unless it was already set. - int page; - for (page = first_page ; page <= last_page ; ++page) { - if (!varyobj_pages[page].scan_start_offset) { - long offset = (char*)varyobj_page_address(page+1) - (char*)obj; - varyobj_pages[page].scan_start_offset = offset >> (WORD_SHIFT + 1); - } - } - } - // Write a padding object if necessary - if ((uword_t)limit & (IMMOBILE_CARD_BYTES-1)) { - int remainder = IMMOBILE_CARD_BYTES - - ((uword_t)limit & (IMMOBILE_CARD_BYTES-1)); - lispobj array_length = make_fixnum((remainder >> WORD_SHIFT) - 2); - if (limit[0] == SIMPLE_ARRAY_FIXNUM_WIDETAG) { - gc_assert(limit[1] == array_length); - } else { - limit[0] = SIMPLE_ARRAY_FIXNUM_WIDETAG; - limit[1] = array_length; - } - int size = sizetab[SIMPLE_ARRAY_FIXNUM_WIDETAG](limit); - lispobj* __attribute__((unused)) padded_end = limit + size; - gc_assert(!((uword_t)padded_end & (IMMOBILE_CARD_BYTES-1))); + if (!TEXT_SPACE_START) { + // Don't use the space. Free pointer was initialized to the nominal + // base address. Set the start to that also so that map-objects-in-range + // sees no used space, and find_text_page_index() returns -1; + TEXT_SPACE_START = (uword_t)text_space_highwatermark; + text_space_size = 0; + page_attributes_valid = 1; // make search_immobile_space() work right + return; } + // coreparse() already set text_space_highwatermark + gc_assert(text_space_highwatermark != 0 /* would be zero if not mmapped yet */ + && text_space_highwatermark <= (lispobj*)(TEXT_SPACE_START + text_len)); + gc_assert(PTR_ALIGN_UP(text_space_highwatermark, IMMOBILE_CARD_BYTES) == text_space_highwatermark); + tlsf_mem_start = text_space_highwatermark; + struct vector* v = VECTOR(SYMBOL(IMMOBILE_CODEBLOB_VECTOR)->value); + gc_assert(widetag_of((lispobj*)v) == SIMPLE_ARRAY_UNSIGNED_BYTE_32_WIDETAG); + // The vector itself is either in R/O space, or pseudo-static in dynamic space + // depending on :PURIFY + if(gencgc_verbose) fprintf(stderr, "pseudostatic codeblob vector is %p\n", v); + loaded_codeblob_offsets = (void*)v->data; + loaded_codeblob_offsets_len = vector_len(v); + // Don't use text_len to compute n_pages because that measures backend pages (32k), + // but we're trying to compute _allocator_ pages. + n_pages = ((uword_t)text_space_highwatermark-TEXT_SPACE_START) / IMMOBILE_CARD_BYTES; + // Set the generation mask only on pages that contain some object header + // (not merely the interior of an object) + for (page = 0; page < n_pages ; ++page) + if (text_page_scan_start(page)) text_page_genmask[page] |= 1<<gen; + + // Create a TLSF pool + char *tlsf_memory_end = (char*)TEXT_SPACE_START + text_space_size; + int tlsf_memory_size = tlsf_memory_end - (char*)tlsf_mem_start; + tlsf_add_pool(tlsf_control, tlsf_mem_start, tlsf_memory_size); + int n_tlsf_pages = tlsf_memory_size / IMMOBILE_CARD_BYTES; + tlsf_page_sso = malloc(n_tlsf_pages * sizeof (short int)); + memset(tlsf_page_sso, 0xff, n_tlsf_pages * sizeof (short int)); + // Set the WP bits for pages occupied by the core file. // (There can be no inter-generation pointers.) if (gen != 0 && ENABLE_PAGE_PROTECTION) { low_page_index_t page; - for (page = 0 ; page <= last_page ; ++page) - varyobj_page_touched_bits[page/32] &= ~(1U<<(page & 31)); + for (page = 0 ; page <= n_pages ; ++page) + text_page_touched_bits[page/32] &= ~(1U<<(page & 31)); } page_attributes_valid = 1; } -// Demote pseudo-static to highest normal generation -// so that all objects become eligible for collection. +void deport_codeblob_offsets_from_heap() +{ + /* This vector is needed for the final GC to compute page scan starts + * but we don't want to preserve it in a lisp space (dynamic or R/O) + * during that GC. + * So replicate it off-heap; it'll get made anew after defrag. */ + int nbytes = sizeof (uint32_t) * loaded_codeblob_offsets_len; + lispobj* vector_copy = malloc(nbytes); + loaded_codeblob_offsets = memcpy(vector_copy, loaded_codeblob_offsets, nbytes); + SYMBOL(IMMOBILE_CODEBLOB_VECTOR)->value = NIL; +} + +// Change all objects to generation 0 void prepare_immobile_space_for_final_gc() { int page; char* page_base; char* page_end = (char*)fixedobj_free_pointer; - // The list of holes need not be saved. - SYMBOL(IMMOBILE_FREELIST)->value = NIL; - - // This scan allow dissimilar object sizes. In the grand scheme of things - // it's not terribly important to optimize out the calls to the sizing function - // for the pages which have a unique size of object. + gc_assert(!gc_managed_heap_space_p((lispobj)loaded_codeblob_offsets)); for (page = 0, page_base = fixedobj_page_address(page) ; page_base < page_end ; page_base += IMMOBILE_CARD_BYTES, ++page) { - unsigned char mask = fixedobj_pages[page].gens; - if (mask & 1<<PSEUDO_STATIC_GENERATION) { - lispobj* obj = (lispobj*)page_base; - lispobj* limit = (lispobj*)((uword_t)obj + IMMOBILE_CARD_BYTES); - for ( ; obj < limit ; obj += sizetab[widetag_of(obj)](obj) ) - if (other_immediate_lowtag_p(*obj) && - immobile_obj_gen_bits(obj) == PSEUDO_STATIC_GENERATION) - assign_generation(obj, HIGHEST_NORMAL_GENERATION); - fixedobj_pages[page].gens = (mask & ~(1<<PSEUDO_STATIC_GENERATION)) - | 1<<HIGHEST_NORMAL_GENERATION; + lispobj* obj = (lispobj*)page_base; + lispobj* limit = (lispobj*)((uword_t)obj + IMMOBILE_CARD_BYTES); + // Never set the generation mask on an empty page! + int spacing = fixedobj_page_obj_align(page) >> WORD_SHIFT; + if (spacing) { + for ( ; obj < limit ; obj += spacing ) { + if (other_immediate_lowtag_p(*obj) && immobile_obj_gen_bits(obj) != 0) + assign_generation(obj, 0); + } + fixedobj_pages[page].gens = 1; // only generation 0 is present } } - lispobj* obj = (lispobj*)VARYOBJ_SPACE_START; - lispobj* limit = varyobj_free_pointer; - for ( ; obj < limit ; obj += sizetab[widetag_of(obj)](obj) ) { - if (immobile_obj_gen_bits(obj) == PSEUDO_STATIC_GENERATION) - assign_generation(obj, HIGHEST_NORMAL_GENERATION); - } - int max_page = find_varyobj_page_index(limit-1); - for ( page = 0 ; page <= max_page ; ++page ) { - int mask = varyobj_pages[page].generations; - if (mask & (1<<PSEUDO_STATIC_GENERATION)) { - varyobj_pages[page].generations - = (mask & ~(1<<PSEUDO_STATIC_GENERATION)) - | 1<<HIGHEST_NORMAL_GENERATION; + lispobj* obj = (lispobj*)TEXT_SPACE_START; + lispobj* limit = text_space_highwatermark; + int npages = (ALIGN_UP((uword_t)limit, IMMOBILE_CARD_BYTES) - TEXT_SPACE_START) + / IMMOBILE_CARD_BYTES; + memset(text_page_genmask, 0, npages); + for ( ; obj < limit ; obj += headerobj_size(obj) ) { + if (widetag_of(obj) != FILLER_WIDETAG) { + assign_generation(obj, 0); + text_page_genmask[find_text_page_index(obj)] = 1; } } + SYMBOL(IMMOBILE_CODEBLOB_TREE)->value = NIL; } int* code_component_order; +int compute_codeblob_offsets_nwords(int* pcount) +{ + int count = 0; + lispobj* obj = (lispobj*)TEXT_SPACE_START; + for ( ; obj < text_space_highwatermark ; obj += headerobj_size(obj) ) ++count; + if (pcount) *pcount = count; + int n_data_words = ALIGN_UP(count, 2) >> 1; + return 2 + ALIGN_UP(n_data_words, 2); +} + /* Defragment the immobile space, and then promote all objects to gen6. * 'coreparse' causes all pages in dynamic space to be pseudo-static, but * each immobile object stores its own generation, so this must be done at @@ -1336,23 +1317,46 @@ void prepare_immobile_space_for_save(boolean verbose) while (obj < limit) { if (other_immediate_lowtag_p(*obj)) assign_generation(obj, PSEUDO_STATIC_GENERATION); - obj += sizetab[widetag_of(obj)](obj); + obj += object_size(obj); } - obj = (lispobj*)VARYOBJ_SPACE_START; - limit = varyobj_free_pointer; - for ( varyobj_holes = 0 ; obj < limit ; obj += sizetab[widetag_of(obj)](obj) ) { - if (filler_obj_p(obj)) { - struct code* code = (struct code*)obj; - code->debug_info = varyobj_holes; - code->fixups = 0; - varyobj_holes = (lispobj)code; - // 0-fill the unused space. - int nwords = sizetab[widetag_of(obj)](obj); - memset(code->constants, 0, - (nwords * N_WORD_BYTES) - offsetof(struct code, constants)); - } else - assign_generation(obj, PSEUDO_STATIC_GENERATION); + for ( obj = (lispobj*)TEXT_SPACE_START ; obj < text_space_highwatermark ; obj += headerobj_size(obj) ) { + *obj &= ~(uword_t)block_header_prev_free_bit; + assign_generation(obj, PSEUDO_STATIC_GENERATION); + } + // Create a vector of code offsets + int codeblob_count; + int vector_nwords = compute_codeblob_offsets_nwords(&codeblob_count); + struct vector* v; + if (read_only_space_free_pointer > (lispobj*)READ_ONLY_SPACE_START) { + v = (void*)read_only_space_free_pointer; + read_only_space_free_pointer += vector_nwords; + if (read_only_space_free_pointer > (lispobj*)READ_ONLY_SPACE_END) + lose("Didn't reserve enough R/O space?"); + } else { + v = gc_general_alloc(unboxed_region, vector_nwords<<WORD_SHIFT, + PAGE_TYPE_UNBOXED); + // might have used large-object pages, no region + ensure_region_closed(unboxed_region, PAGE_TYPE_UNBOXED); + // gc_general_alloc generally avoids pre-zeroizing, so ensure zero-fill to the end + // of dynamic space as we've aready performed zero_all_free_ranges(). + uword_t vector_end = (uword_t)((lispobj*)v + vector_nwords), + aligned_end = ALIGN_UP(vector_end, BACKEND_PAGE_BYTES); + memset((char*)vector_end, 0, aligned_end-vector_end); + } + v->header = SIMPLE_ARRAY_UNSIGNED_BYTE_32_WIDETAG; + v->length_ = make_fixnum(codeblob_count); + SYMBOL(IMMOBILE_CODEBLOB_VECTOR)->value = make_lispobj(v, OTHER_POINTER_LOWTAG); + uint32_t* data = (uint32_t*)v->data; + int i = 0; + for ( obj = (lispobj*)TEXT_SPACE_START ; obj < text_space_highwatermark ; obj += headerobj_size(obj) ) { + data[i++] = (int)((uword_t)obj - TEXT_SPACE_START); + } + // Write a filler if needed to align tlsf_mem_start + lispobj* aligned_hwm = PTR_ALIGN_UP(text_space_highwatermark, IMMOBILE_CARD_BYTES); + if (text_space_highwatermark < aligned_hwm) { + *text_space_highwatermark = make_filler_header(aligned_hwm - text_space_highwatermark); + text_space_highwatermark = aligned_hwm; } if (verbose) printf("done]\n"); } @@ -1377,23 +1381,20 @@ int immobile_space_handle_wp_violation(void* fault_addr) return 1; } +/// For defragmentation + +static struct tempspace { + char* start; + int n_bytes; +} fixedobj_tempspace, text_tempspace; + // Find the object that encloses pointer. lispobj * search_immobile_space(void *pointer) { - lispobj *start; - - if ((void*)VARYOBJ_SPACE_START <= pointer - && pointer < (void*)varyobj_free_pointer) { - low_page_index_t page_index = find_varyobj_page_index(pointer); - if (page_attributes_valid) { - start = varyobj_scan_start(page_index); - if (start > (lispobj*)pointer) return NULL; - } else { - start = (lispobj*)VARYOBJ_SPACE_START; - } - lispobj* found = gc_search_space(start, pointer); - return (found && filler_obj_p(found)) ? 0 : found; + if ((void*)TEXT_SPACE_START <= pointer && pointer < (void*)text_space_highwatermark) { + if (!page_attributes_valid)lose("Can't search"); + return search_immobile_code(pointer); } else if ((void*)FIXEDOBJ_SPACE_START <= pointer && pointer < (void*)fixedobj_free_pointer) { low_page_index_t page_index = find_fixedobj_page_index(pointer); @@ -1405,10 +1406,21 @@ search_immobile_space(void *pointer) // a root for scavenging. It resembles READ-ONLY space in that regard. if (page_attributes_valid && page_index >= FIXEDOBJ_RESERVED_PAGES) { int spacing = fixedobj_page_obj_align(page_index); + if (spacing == 0) return NULL; int index = ((char*)pointer - page_base) / spacing; - char *begin = page_base + spacing * index; - char *end = begin + (fixedobj_page_obj_size(page_index) << WORD_SHIFT); - if ((char*)pointer < end) return (lispobj*)begin; + lispobj *obj = (void*)(page_base + spacing * index); + char* end; + /* When defragmenting, there are forwarding pointers in object headers + * so the sizing functions don't work. Following the forwarding pointer + * isn't right, because it points to where the object _will_ be, + * but it isn't actually there. So we have to conservatively assume + * that the object size is the object alignment. + * It all other situations, it is OK to call the sizing function. */ + if (fixedobj_tempspace.start) // defragmenting + end = (char*)obj + spacing; + else + end = (char*)(obj + object_size(obj)); + if ((char*)pointer < end) return obj; } else { return gc_search_space((lispobj*)page_base, pointer); } @@ -1416,65 +1428,8 @@ search_immobile_space(void *pointer) return NULL; } -// For coalescing holes, we need to scan backwards, which is done by -// looking backwards for a page that contains the start of a -// block of objects one of which must abut 'obj'. -lispobj* find_preceding_object(lispobj* obj) -{ - int page = find_varyobj_page_index(obj); - gc_assert(page >= 0); - while (1) { - int offset = varyobj_pages[page].scan_start_offset; - if (offset) { // 0 means the page is empty. - lispobj* start = varyobj_scan_start(page); - if (start < obj) { // Scan from here forward - while (1) { - lispobj* end = start + sizetab[widetag_of(start)](start); - if (end == obj) return start; - gc_assert(end < obj); - start = end; - } - } - } - if (page == 0) { - gc_assert(obj == varyobj_page_address(0)); - return 0; // Predecessor does not exist - } - --page; - } -} - -lispobj* AMD64_SYSV_ABI alloc_fixedobj(int nwords, uword_t header) -{ - return alloc_immobile_obj(MAKE_ATTR(ALIGN_UP(nwords,2), // spacing - ALIGN_UP(nwords,2), // size - 0), - header); -} - -static const int LAYOUT_NWORDS = sizeof (struct layout)/N_WORD_BYTES; - -lispobj AMD64_SYSV_ABI alloc_layout() -{ - lispobj* l = - alloc_immobile_obj(MAKE_ATTR(ALIGN_UP(LAYOUT_NWORDS,2), - ALIGN_UP(LAYOUT_NWORDS,2), - 0), - (LAYOUT_NWORDS-1)<<INSTANCE_LENGTH_SHIFT | INSTANCE_WIDETAG); - return make_lispobj(l, INSTANCE_POINTER_LOWTAG); -} - -// FIXME: Figure out not to hardcode -#define FUN_TRAMP_SIZE 6 -#define GF_SIZE 6 - //// Defragmentation -static struct tempspace { - char* start; - int n_bytes; -} fixedobj_tempspace, varyobj_tempspace; - // Given an address in the target core, return the equivalent // physical address to read or write during defragmentation static lispobj* tempspace_addr(void* address) @@ -1485,10 +1440,10 @@ static lispobj* tempspace_addr(void* address) int byte_index = (char*)address - (char*)FIXEDOBJ_SPACE_START; gc_assert(byte_index < fixedobj_tempspace.n_bytes); return (void*)(fixedobj_tempspace.start + byte_index); - } else { // varyobj subspace - int byte_index = (char*)address - (char*)VARYOBJ_SPACE_START; - gc_assert(byte_index < varyobj_tempspace.n_bytes); - return (void*)(varyobj_tempspace.start + byte_index); + } else { // text subspace + int byte_index = (char*)address - (char*)TEXT_SPACE_START; + gc_assert(byte_index < text_tempspace.n_bytes); + return (void*)(text_tempspace.start + byte_index); } } @@ -1508,15 +1463,15 @@ static inline boolean tempspace_p(char* addr) { return (addr >= fixedobj_tempspace.start && addr < fixedobj_tempspace.start + fixedobj_tempspace.n_bytes) - || (addr >= varyobj_tempspace.start && - addr < varyobj_tempspace.start + varyobj_tempspace.n_bytes); + || (addr >= text_tempspace.start && + addr < text_tempspace.start + text_tempspace.n_bytes); } static inline boolean known_space_p(lispobj ptr) { return find_page_index((char*)ptr) >= 0 || tempspace_p((char*)ptr) || immobile_space_p(ptr) - || (STATIC_SPACE_START <= ptr && ptr < STATIC_SPACE_END); + || (STATIC_SPACE_OBJECTS_START <= ptr && ptr < STATIC_SPACE_END); } static boolean forwardable_ptr_p(lispobj ptr) { @@ -1525,8 +1480,7 @@ static boolean forwardable_ptr_p(lispobj ptr) forwarding_pointer_p(native_pointer(ptr)); } -static void adjust_words(lispobj *where, sword_t n_words, - uword_t __attribute__((unused)) arg) +static void adjust_words(lispobj *where, sword_t n_words) { int i; for (i=0;i<n_words;++i) { @@ -1545,41 +1499,12 @@ static lispobj adjust_fun_entrypoint(lispobj raw_addr) if (asm_routines_start <= raw_addr && raw_addr < asm_routines_end) return raw_addr; lispobj simple_fun = fun_taggedptr_from_self(raw_addr); - adjust_words(&simple_fun, 1, 0); + adjust_words(&simple_fun, 1); return fun_self_from_taggedptr(simple_fun); } -static void adjust_fdefn_raw_addr(struct fdefn* fdefn) -{ - if (!fdefn->raw_addr || points_to_asm_code_p((lispobj)fdefn->raw_addr)) - return; - lispobj* raw_addr = (lispobj*)fdefn->raw_addr; - lispobj* obj_base = 0; - lispobj header; - int i; - for (i=1; i<=4; ++i) - if ((header = raw_addr[-i]) == 1 || other_immediate_lowtag_p(header)) { - obj_base = raw_addr-i; - break; - } - gc_assert(obj_base); - int offset = (char*)raw_addr - (char*)obj_base; - if (header == 1) { - char* new = (char*)native_pointer(forwarding_pointer_value(obj_base)); - fdefn->raw_addr = new + offset; - } -} - -/* Fix the layout of OBJ, and return the layout's address in tempspace. - * If compact headers, store the layout back into the object. - * If non-compact headers, DO NOT store the layout back into the object, - * because that will be done when instance_scan() touches all slots. - * If it were wrongly done now, then the following (real example) happens: - * instance @ 0x1000000000 has layout pointer 0x203cb483. - * layout @ 0x203cb483 forwards to 0x2030c483. - * object _currently_ at 0x2030c480 (NOT a layout) forwards to 0x203c39cf. - * so the instance winds up with a non-layout in its layout after - * instance_scan() forwards that slot "again". */ +/* Fix the layout of OBJ, storing it back to the object, + * and return the layout's address in tempspace. */ static struct layout* fix_object_layout(lispobj* obj) { // This works on instances, funcallable instances (and/or closures) @@ -1591,92 +1516,92 @@ static struct layout* fix_object_layout(lispobj* obj) #else gc_assert(widetag_of(obj) == INSTANCE_WIDETAG); #endif - lispobj layout = instance_layout(obj); + lispobj layout = layout_of(obj); if (layout == 0) return 0; +#ifdef LISP_FEATURE_METASPACE + return LAYOUT(layout); +#else if (forwarding_pointer_p(native_pointer(layout))) { // usually layout = forwarding_pointer_value(native_pointer(layout)); -#ifdef LISP_FEATURE_COMPACT_INSTANCE_HEADER - instance_layout(obj) = layout; -#endif + layout_of(obj) = layout; } struct layout* native_layout = (struct layout*)tempspace_addr(LAYOUT(layout)); gc_assert(header_widetag(native_layout->header) == INSTANCE_WIDETAG); gc_assert(layoutp(make_lispobj(native_layout, INSTANCE_POINTER_LOWTAG))); return native_layout; +#endif } -static lispobj follow_fp(lispobj ptr) -{ - if (forwarding_pointer_p(native_pointer(ptr))) - return forwarding_pointer_value(native_pointer(ptr)); - else - return ptr; -} static void apply_absolute_fixups(lispobj, struct code*); /// It's tricky to try to use the scavtab[] functions for fixing up moved /// objects, because scavenger functions might invoke transport functions. /// The best approach is to do an explicit switch over all object types. -#include "genesis/hash-table.h" static void fixup_space(lispobj* where, size_t n_words) { lispobj* end = where + n_words; - lispobj header_word; int widetag; long size; - int __attribute__((unused)) static_space_p = ((lispobj)where == STATIC_SPACE_START); struct code* code; while (where < end) { gc_assert(!forwarding_pointer_p(where)); - header_word = *where; - if (is_cons_half(header_word)) { - adjust_words(where, 2, 0); // A cons. + lispobj header_word = *where; + if (!is_header(header_word)) { + adjust_words(where, 2); // A cons. (It can only be filler?) where += 2; continue; } + size = headerobj_size2(where, header_word); widetag = header_widetag(header_word); - size = sizetab[widetag](where); switch (widetag) { default: if (!leaf_obj_widetag_p(widetag)) lose("Unhandled widetag in fixup_space: %p", (void*)header_word); break; -#ifdef LISP_FEATURE_COMPACT_INSTANCE_HEADER - case FUNCALLABLE_INSTANCE_WIDETAG: -#endif case INSTANCE_WIDETAG: - instance_scan(adjust_words, where+1, size-1, - fix_object_layout(where)->bitmap, - 0); + case FUNCALLABLE_INSTANCE_WIDETAG: + { + lispobj* slots = where+1; + int i; + struct bitmap bitmap = get_layout_bitmap(fix_object_layout(where)); + for(i=0; i<(size-1); ++i) + if (bitmap_logbitp(i, bitmap)) adjust_words(slots+i, 1); + } break; case CODE_HEADER_WIDETAG: // Fixup the constant pool. code = (struct code*)where; - adjust_words(where+2, code_header_words(code)-2, 0); + adjust_words(where+2, code_header_words(code)-2); apply_absolute_fixups(code->fixups, code); break; case CLOSURE_WIDETAG: where[1] = adjust_fun_entrypoint(where[1]); - // FALLTHROUGH_INTENDED -#ifndef LISP_FEATURE_COMPACT_INSTANCE_HEADER - case FUNCALLABLE_INSTANCE_WIDETAG: -#endif - // skip the trampoline word at where[1] - adjust_words(where+2, size-2, 0); + adjust_words(where+2, size-2); break; case FDEFN_WIDETAG: - adjust_words(where+1, 2, 0); - adjust_fdefn_raw_addr((struct fdefn*)where); + adjust_words(where+1, 2); + struct fdefn *fdefn = (void*)where; + lispobj entrypoint = (lispobj)fdefn->raw_addr; + lispobj taggedptr = decode_fdefn_rawfun(fdefn); + if (taggedptr) { + int disp = entrypoint - taggedptr; + adjust_words(&taggedptr, 1); + fdefn->raw_addr = (char*)taggedptr + disp; + } + break; + case SYMBOL_WIDETAG: + // - info, name, package can not point to an immobile object + adjust_words(&((struct symbol*)where)->value, 1); + adjust_words(&((struct symbol*)where)->fdefn, 1); break; - // Special case because we might need to mark hashtables // as needing rehash. case SIMPLE_VECTOR_WIDETAG: - if (is_vector_subtype(header_word, VectorAddrHashing)) { + if (vector_flagp(header_word, VectorAddrHashing)) { struct vector* kv_vector = (struct vector*)where; lispobj* data = kv_vector->data; - gc_assert(kv_vector->length >= 5); + gc_assert(vector_len(kv_vector) >= 5); boolean needs_rehash = 0; unsigned int hwm = KV_PAIRS_HIGH_WATER_MARK(data); unsigned int i; @@ -1694,21 +1619,18 @@ static void fixup_space(lispobj* where, size_t n_words) if (needs_rehash) KV_PAIRS_REHASH(data) |= make_fixnum(1); break; - } else { - // FALLTHROUGH_INTENDED } + // INTENTIONAL FALLTHROUGH // All the other array header widetags. case SIMPLE_ARRAY_WIDETAG: #ifdef COMPLEX_CHARACTER_STRING_WIDETAG case COMPLEX_CHARACTER_STRING_WIDETAG: #endif case COMPLEX_BASE_STRING_WIDETAG: - case COMPLEX_VECTOR_NIL_WIDETAG: case COMPLEX_BIT_VECTOR_WIDETAG: case COMPLEX_VECTOR_WIDETAG: case COMPLEX_ARRAY_WIDETAG: // And the other entirely boxed objects. - case SYMBOL_WIDETAG: case VALUE_CELL_WIDETAG: case WEAK_POINTER_WIDETAG: case RATIO_WIDETAG: @@ -1716,7 +1638,7 @@ static void fixup_space(lispobj* where, size_t n_words) // Use the sizing functions for generality. // Symbols can contain strange header bytes, // and vectors might have a padding word, etc. - adjust_words(where+1, size-1, 0); + adjust_words(where+1, size-1); break; } where += size; @@ -1731,46 +1653,26 @@ static lispobj* get_load_address(lispobj* old) { if (forwarding_pointer_p(old)) return native_pointer(forwarding_pointer_value(old)); - gc_assert(filler_obj_p(old)); + gc_assert(widetag_of(old) == FILLER_WIDETAG); return 0; } #if DEFRAGMENT_FIXEDOBJ_SUBSPACE -// This does not accept (SIMPLE-ARRAY NIL (*)) -// (You'd have a pretty bad time trying making a symbol like that) -static int schar(struct vector* string, int index) -{ -#ifdef LISP_FEATURE_SB_UNICODE - if (widetag_of(&string->header) == SIMPLE_CHARACTER_STRING_WIDETAG) - return ((int*)string->data)[index]; -#endif - return ((char*)string->data)[index]; -} +#define N_SYMBOL_KINDS 4 -#include "genesis/package.h" -#define N_SYMBOL_KINDS 5 - -// Return an integer 0..4 telling which block of symbols to relocate 'sym' into. -// 0=uninterned, 1=keyword, 2=special operator with extra slot, -// 3=special var, 4=other +// Return an integer 0..3 telling which block of symbols to relocate 'sym' into. +// 0=uninterned, 1=keyword, 2=special var, 3=other static int classify_symbol(lispobj* obj) { - struct symbol* symbol = (struct symbol*)obj; - if (symbol->package == NIL) return 0; - struct vector* package_name = (struct vector*) - native_pointer(((struct package*)native_pointer(symbol->package))->_name); - if (widetag_of(&package_name->header) == SIMPLE_BASE_STRING_WIDETAG - && !strcmp((char*)package_name->data, "KEYWORD")) - return 1; - // Same criterion as SYMBOL-EXTRA-SLOT-P in src/code/room. - if ((HeaderValue(*obj) & 0xFF) > (SYMBOL_SIZE-1)) - return 2; - struct vector* symbol_name = VECTOR(symbol->name); - if (symbol_name->length >= make_fixnum(2) && - schar(symbol_name, 0) == '*' && - schar(symbol_name, fixnum_value(symbol_name->length)-1) == '*') - return 3; - return 4; + struct symbol* symbol = (struct symbol*)obj; + if (symbol_package_id(symbol) == PACKAGE_ID_NONE) return 0; + if (symbol_package_id(symbol) == PACKAGE_ID_KEYWORD) return 1; + struct vector* symbol_name = VECTOR(decode_symbol_name(symbol->name)); + if (vector_len(symbol_name) >= 2 && + schar(symbol_name, 0) == '*' && + schar(symbol_name, vector_len(symbol_name)-1) == '*') + return 2; + return 3; } static inline char* compute_defrag_start_address() @@ -1789,26 +1691,9 @@ static int calc_n_fixedobj_pages(int n_objects, int words_per_object) return (n_objects + objects_per_page - 1) / objects_per_page; } -#if WRITABLE_TEXT_SEGMENT -static int calc_n_varyobj_pages(int n_objects, int words_per_object) -{ - words_per_object = ALIGN_UP(words_per_object, 2); - int objects_per_page = WORDS_PER_PAGE / words_per_object; - // varyobj space can't have unused bytes, but filler objects - // require at least 4 words. So if there are only 2 words - // of trailing fluff, cut out one object. - // This could be improved by using 'filler' type object (not code) - // which stores the length in the header word, leaving one word - // available in which to store a pointer to the next filler object. - if (WORDS_PER_PAGE - (words_per_object * objects_per_page) == 2) - --objects_per_page; - return (n_objects + objects_per_page - 1) / objects_per_page; -} -#endif - /// Copy a fixed-size object somewhere. "somewhere" could be either a fixed- /// or variable-sized object page. The new copy never crosses page boundaries. -/// The original object may reside in either varyobj or fixedobj space. +/// The original object may reside in either text or fixedobj space. static void place_fixedobj(lispobj* obj, int size_in_bytes, char *alloc_ptrs[64], char *symbol_alloc_ptr[]) { @@ -1825,55 +1710,68 @@ static void place_fixedobj(lispobj* obj, int size_in_bytes, // compute space remaining, possibly negative, // if this object were placed on the page. int space_avail = (page_end - new) - size_in_bytes; -#if WRITABLE_TEXT_SEGMENT - // Padding consideration is different when moving onto a variable-sized - // object page. - if (widetag == FDEFN_WIDETAG || widetag == CODE_HEADER_WIDETAG - || widetag == FUNCALLABLE_INSTANCE_WIDETAG) { - // transporting into varyobj space. - // since filler objects occupy >= 4 words, consider the page - // to be overfull if exactly 2 words would remain. - if (space_avail < 0 || space_avail == 2*N_WORD_BYTES) { - make_filler(tempspace_addr(new), page_end - new); - new = page_end; - } - } else { - if (space_avail < 0) - new = page_end; - } -#else if (space_avail < 0) new = page_end; -#endif gc_assert(!*tempspace_addr(new)); // better not clobber some other object memcpy(tempspace_addr(new), obj, size_in_bytes); - set_forwarding_pointer(obj, make_lispobj(new, lowtag_for_widetag[widetag>>2])); - if (widetag == FUNCALLABLE_INSTANCE_WIDETAG) // fix the self-pointer - tempspace_addr(new)[1] = (lispobj)(new + 4*N_WORD_BYTES); + set_forwarding_pointer(obj, make_lispobj(new, LOWTAG_FOR_WIDETAG(widetag))); *alloc_ptr = new + size_in_bytes; } -static void __attribute__((unused)) add_filler_if_needed(char* from, char* to) -{ - if (to>from) - make_filler(tempspace_addr(from), to-from); +/// Like above, but specifically for layouts; +struct size_class { + char* alloc_ptr; + /* Initially this is a count of the number of layouts in the size class. + * After computing the total number of layout pages needed, this becomes a count + * of how many objects can be allocated starting from 'alloc_ptr' without + * overflowing the page. When zero, we grab the next available page. */ + int count; +}; + +/* Defragmentation needs more size classes than allocation because a + * restarted core can not discern the original (coarser) size class + * in which a layout was allocated. It can only use the actual size. + * 2n+8 words for N from 0..20 gives a range from 8 to 48 words */ +#define MAX_LAYOUT_DEFRAG_SIZE_CLASSES 21 +static inline int layout_size_class_nwords(int index) { + return 8 + 2*index ; +} +static inline int nwords_to_layout_size_class(unsigned int nwords) { + // the smallest layout size class is 8 words + int index = nwords <= 8 ? 0 : (nwords - 8)/2; + if (index >= MAX_LAYOUT_DEFRAG_SIZE_CLASSES) + lose("Oversized layout: can't defragment"); + return index; } -static boolean executable_object_p(lispobj* obj) +static void place_layout(lispobj* obj, + struct size_class size_classes[], + char** alloc_ptr, char *alloc_ptr_limit) { - int widetag = widetag_of(obj); - int answer = widetag == FDEFN_WIDETAG || - (widetag == CODE_HEADER_WIDETAG && code_header_words((struct code*)obj) >= 3 - && lowtag_of(((struct code*)obj)->debug_info) == FUN_POINTER_LOWTAG) - || widetag == FUNCALLABLE_INSTANCE_WIDETAG; -#if !WRITABLE_TEXT_SEGMENT - gc_assert(!answer); -#endif - return answer; + // Layouts may occur in different sizes. + int nwords = 1 + (instance_length(*obj) | 1); + int size_class_index = nwords_to_layout_size_class(nwords); + if (size_classes[size_class_index].count == 0) { + gc_assert(*alloc_ptr <= alloc_ptr_limit); + size_classes[size_class_index].alloc_ptr = *alloc_ptr; + size_classes[size_class_index].count = (IMMOBILE_CARD_BYTES>>WORD_SHIFT) / nwords; + *alloc_ptr += IMMOBILE_CARD_BYTES; + } else { + gc_assert(size_classes[size_class_index].alloc_ptr != 0); + gc_assert(size_classes[size_class_index].count > 0); + } + size_classes[size_class_index].count--; + char* new = size_classes[size_class_index].alloc_ptr; + gc_assert(!*tempspace_addr(new)); + memcpy(tempspace_addr(new), obj, nwords*N_WORD_BYTES); + set_forwarding_pointer(obj, make_lispobj(new, INSTANCE_POINTER_LOWTAG)); + // Use nbytes for the defragmentation size class when bumping the pointer, + // and not the object spacing for the page on which obj resides. + size_classes[size_class_index].alloc_ptr += + layout_size_class_nwords(size_class_index) << WORD_SHIFT; } static void defrag_immobile_space(boolean verbose) { - lispobj* addr; int i; int *components = code_component_order; @@ -1883,17 +1781,8 @@ static void defrag_immobile_space(boolean verbose) struct { int size, count; } sym_kind_histo[N_SYMBOL_KINDS]; bzero(obj_type_histo, sizeof obj_type_histo); bzero(sym_kind_histo, sizeof sym_kind_histo); - - // Count the fdefns, trampolines, and GFs already in varyobj sapace. - // There are 3 kinds of code objects we might see - - // (1) ordinary code, (2) trampolines, (3) filler - // Make sure only to count the trampolines on this pass. - lispobj* obj = (lispobj*)VARYOBJ_SPACE_START; - while (obj < varyobj_free_pointer) { - int widetag = widetag_of(obj); - if (executable_object_p(obj)) ++obj_type_histo[widetag/4]; - obj += sizetab[widetag](obj); - } + struct size_class layout_size_class[MAX_LAYOUT_DEFRAG_SIZE_CLASSES]; + bzero(layout_size_class, sizeof layout_size_class); #if DEFRAGMENT_FIXEDOBJ_SUBSPACE // Find the starting address of fixed-size objects that will undergo defrag. @@ -1911,27 +1800,42 @@ static void defrag_immobile_space(boolean verbose) lispobj word = *obj; if (!fixnump(word)) { int widetag = header_widetag(word); + int size = sizetab[widetag](obj); ++obj_type_histo[widetag/4]; - if (widetag == SYMBOL_WIDETAG) { + switch (widetag) { + case SYMBOL_WIDETAG: + { int kind = classify_symbol(obj); - int size = sizetab[widetag](obj); ++sym_kind_histo[kind].count; if (!sym_kind_histo[kind].size) sym_kind_histo[kind].size = size; gc_assert(sym_kind_histo[kind].size == size); + } + break; + case INSTANCE_WIDETAG: + gc_assert(layoutp(make_lispobj(obj, INSTANCE_POINTER_LOWTAG))); + int class_index = nwords_to_layout_size_class(size); + ++layout_size_class[class_index].count; + break; } } } while (NEXT_FIXEDOBJ(obj, obj_spacing) <= limit); } } +#ifndef LISP_FEATURE_METASPACE gc_assert(obj_type_histo[INSTANCE_WIDETAG/4]); +#endif // Calculate space needed for fixedobj pages after defrag. - // page order is: layouts, symbols, fdefns, trampolines, GFs - // If the text segment is writable, then the last 3 of those are - // moved into varyobj space. - int n_layout_pages = calc_n_fixedobj_pages(obj_type_histo[INSTANCE_WIDETAG/4], - LAYOUT_NWORDS); + // page order is: layouts, symbols, fdefns. + int n_layout_pages = 0; + int class_index; + for (class_index = 0; class_index < MAX_LAYOUT_DEFRAG_SIZE_CLASSES; ++class_index) { + int count = layout_size_class[class_index].count; + n_layout_pages += calc_n_fixedobj_pages(count, layout_size_class_nwords(class_index)); + layout_size_class[class_index].count = 0; + } + char* layout_alloc_ptr = defrag_base; char* symbol_alloc_ptrs[N_SYMBOL_KINDS+1]; symbol_alloc_ptrs[0] = layout_alloc_ptr + n_layout_pages * IMMOBILE_CARD_BYTES; @@ -1939,19 +1843,10 @@ static void defrag_immobile_space(boolean verbose) symbol_alloc_ptrs[i+1] = symbol_alloc_ptrs[i] + calc_n_fixedobj_pages( sym_kind_histo[i].count, sym_kind_histo[i].size) * IMMOBILE_CARD_BYTES; -#if WRITABLE_TEXT_SEGMENT - fixedobj_tempspace.n_bytes = - symbol_alloc_ptrs[N_SYMBOL_KINDS] - (char*)FIXEDOBJ_SPACE_START; -#else int n_fdefn_pages = calc_n_fixedobj_pages(obj_type_histo[FDEFN_WIDETAG/4], FDEFN_SIZE); - int n_tramp_pages = calc_n_fixedobj_pages(obj_type_histo[CODE_HEADER_WIDETAG/4], FUN_TRAMP_SIZE); - int n_gf_pages = calc_n_fixedobj_pages(obj_type_histo[FUNCALLABLE_INSTANCE_WIDETAG/4], GF_SIZE); char* fdefn_alloc_ptr = symbol_alloc_ptrs[N_SYMBOL_KINDS]; - char* tramp_alloc_ptr = fdefn_alloc_ptr + n_fdefn_pages * IMMOBILE_CARD_BYTES; - char* gf_alloc_ptr = tramp_alloc_ptr + n_tramp_pages * IMMOBILE_CARD_BYTES; fixedobj_tempspace.n_bytes = - gf_alloc_ptr + n_gf_pages * IMMOBILE_CARD_BYTES - (char*)FIXEDOBJ_SPACE_START; -#endif + fdefn_alloc_ptr + n_fdefn_pages * IMMOBILE_CARD_BYTES - (char*)FIXEDOBJ_SPACE_START; fixedobj_tempspace.start = calloc(fixedobj_tempspace.n_bytes, 1); // Copy pages below the defrag base into the temporary copy. @@ -1964,103 +1859,70 @@ static void defrag_immobile_space(boolean verbose) int n_code_bytes = 0; if (components) { +#ifdef LISP_FEATURE_METASPACE + /* Skip the 0th entry when assigning new addresses, because it is + SB-FASL::*ASSEMBLER-ROUTINES* which is in read-only space and not + itself relocatable, but does contain absolute fixups */ + for (i=1 ; components[i*2] ; ++i) { +#else for (i=0 ; components[i*2] ; ++i) { - addr = (lispobj*)(long)components[i*2]; +#endif + lispobj* addr = (lispobj*)(long)components[i*2]; gc_assert(lowtag_of((lispobj)addr) == OTHER_POINTER_LOWTAG); addr = native_pointer((lispobj)addr); int widetag = widetag_of(addr); - gc_assert(widetag == CODE_HEADER_WIDETAG); + gc_assert(widetag == CODE_HEADER_WIDETAG || widetag == FILLER_WIDETAG); lispobj new_vaddr = 0; // A code component can become garbage in the final GC // (defrag happens after the last GC) leaving a filler object // which was in components[] because it was live before GC. - if (!filler_obj_p(addr)) { - // must not be a trampoline object - if ((lispobj)addr > VARYOBJ_SPACE_START) - gc_assert(code_n_funs((struct code*)addr)); + if (widetag == CODE_HEADER_WIDETAG) { ++n_code_components; - new_vaddr = VARYOBJ_SPACE_START + n_code_bytes; + new_vaddr = TEXT_SPACE_START + n_code_bytes; n_code_bytes += sizetab[widetag](addr) << WORD_SHIFT; } components[i*2+1] = new_vaddr; } } - int aligned_nbytes = ALIGN_UP(n_code_bytes, IMMOBILE_CARD_BYTES); - if (aligned_nbytes - n_code_bytes == 2 * N_WORD_BYTES) - // waste another page because it can't be a 2-word filler - aligned_nbytes += IMMOBILE_CARD_BYTES; -#if WRITABLE_TEXT_SEGMENT - char* fdefn_alloc_ptr = (char*)VARYOBJ_SPACE_START + aligned_nbytes; - - int n_fdefn_pages = - calc_n_varyobj_pages(obj_type_histo[FDEFN_WIDETAG/4], - FDEFN_SIZE); - int n_gf_pages = - calc_n_varyobj_pages(obj_type_histo[FUNCALLABLE_INSTANCE_WIDETAG/4], - GF_SIZE); - int n_tramp_pages = - calc_n_varyobj_pages(obj_type_histo[CODE_HEADER_WIDETAG/4], - FUN_TRAMP_SIZE); - - char* tramp_alloc_ptr = fdefn_alloc_ptr + n_fdefn_pages * IMMOBILE_CARD_BYTES; - char* gf_alloc_ptr = tramp_alloc_ptr + n_tramp_pages * IMMOBILE_CARD_BYTES; - varyobj_tempspace.n_bytes = - = gf_alloc_ptr + n_gf_pages * IMMOBILE_CARD_BYTES - (char*)VARYOBJ_SPACE_START; -#else - varyobj_tempspace.n_bytes = aligned_nbytes; -#endif - varyobj_tempspace.start = calloc(varyobj_tempspace.n_bytes, 1); + text_tempspace.n_bytes = n_code_bytes; + text_tempspace.start = calloc(text_tempspace.n_bytes, 1); if (verbose) - printf("(fin,inst,fdefn,code,sym)=%d+%d+%d+%d+%d... ", - obj_type_histo[FUNCALLABLE_INSTANCE_WIDETAG/4], + printf("(inst,fdefn,code,sym)=%d+%d+%d+%d... ", obj_type_histo[INSTANCE_WIDETAG/4], obj_type_histo[FDEFN_WIDETAG/4], obj_type_histo[CODE_HEADER_WIDETAG/4] + n_code_components, obj_type_histo[SYMBOL_WIDETAG/4]); if (components) { - // Permute varyobj space into tempspace and deposit forwarding pointers. + // Permute text space into tempspace and deposit forwarding pointers. lispobj new_vaddr; for (i=0 ; components[i*2] ; ++i) { - if ((new_vaddr = components[i*2+1]) != 0) { - addr = native_pointer(components[i*2]); - memcpy(tempspace_addr((void*)new_vaddr), addr, - sizetab[widetag_of(addr)](addr) << WORD_SHIFT); - int displacement = new_vaddr - (lispobj)addr; - switch (widetag_of(addr)) { - default: - lose("What is object type %x doing here?", widetag_of(addr)); - case CODE_HEADER_WIDETAG: - for_each_simple_fun(index, fun, (struct code*)addr, 1, { - struct simple_fun *new_fun = - (struct simple_fun*)((char*)fun + displacement); - // Fix the 'self' slot for the new logical address, - // storing via the current (temporary) address. - ((struct simple_fun*)tempspace_addr(new_fun))->self = - fun_self_from_baseptr(new_fun); - set_forwarding_pointer((lispobj*)fun, - make_lispobj(new_fun, FUN_POINTER_LOWTAG)); - }); - { - // Fix any absolute jump tables - lispobj* jump_table = - code_jumptable_start((struct code*)tempspace_addr((void*)new_vaddr)); - int count = jumptable_count(jump_table); - int i; - for (i = 1; i < count; ++i) - if (jump_table[i]) jump_table[i] += displacement; - } - break; - } - set_forwarding_pointer(addr, - make_lispobj((void*)new_vaddr, - OTHER_POINTER_LOWTAG)); - } + if ((new_vaddr = components[i*2+1]) == 0) continue; + lispobj* addr = native_pointer(components[i*2]); + gc_assert(widetag_of(addr) == CODE_HEADER_WIDETAG); + memcpy(tempspace_addr((void*)new_vaddr), addr, + headerobj_size(addr) << WORD_SHIFT); + int displacement = new_vaddr - (lispobj)addr; + for_each_simple_fun(index, fun, (struct code*)addr, 1, { + struct simple_fun *new_fun = + (struct simple_fun*)((char*)fun + displacement); + // Fix the 'self' slot for the new logical address, + // storing via the current (temporary) address. + ((struct simple_fun*)tempspace_addr(new_fun))->self = + fun_self_from_baseptr(new_fun); + set_forwarding_pointer((lispobj*)fun, + make_lispobj(new_fun, FUN_POINTER_LOWTAG)); + }); + // Fix any absolute jump tables + lispobj* jump_table = + code_jumptable_start((struct code*)tempspace_addr((void*)new_vaddr)); + int count = jumptable_count(jump_table); + int i; + for (i = 1; i < count; ++i) if (jump_table[i]) jump_table[i] += displacement; + set_forwarding_pointer(addr, make_lispobj((void*)new_vaddr, + OTHER_POINTER_LOWTAG)); } - if (aligned_nbytes > n_code_bytes) - make_filler(tempspace_addr((char*)VARYOBJ_SPACE_START + n_code_bytes), - aligned_nbytes - n_code_bytes); } #if DEFRAGMENT_FIXEDOBJ_SUBSPACE @@ -2068,26 +1930,7 @@ static void defrag_immobile_space(boolean verbose) bzero(alloc_ptrs, sizeof alloc_ptrs); alloc_ptrs[INSTANCE_WIDETAG/4] = layout_alloc_ptr; alloc_ptrs[FDEFN_WIDETAG/4] = fdefn_alloc_ptr; - alloc_ptrs[CODE_HEADER_WIDETAG/4] = tramp_alloc_ptr; - alloc_ptrs[FUNCALLABLE_INSTANCE_WIDETAG/4] = gf_alloc_ptr; - -#if WRITABLE_TEXT_SEGMENT - // Copy fixed-sized objects that were already in code space - // to a possibly new address in code space. - obj = (lispobj*)VARYOBJ_SPACE_START; - while (obj < varyobj_free_pointer) { - // Use the forwarded object if forwarded, because the header was stomped on. - // This handles the code objects that were already forwarded. - lispobj* fwdobj = - forwarding_pointer_p(obj) ? - tempspace_addr(native_pointer(forwarding_pointer_value(obj))) : obj; - int size = sizetab[widetag_of(fwdobj)](fwdobj); - // Supplying symbol_kind as 0 is fine - symbols can't exist in code space. - if (executable_object_p(fwdobj)) - place_fixedobj(obj, size << WORD_SHIFT, alloc_ptrs, 0); - obj += size; - } -#endif + // Permute fixed-sized object pages and deposit forwarding pointers. for ( page_index = find_fixedobj_page_index(defrag_base) ; page_index <= max_used_fixedobj_page ; ++page_index) { @@ -2097,14 +1940,14 @@ static void defrag_immobile_space(boolean verbose) lispobj* limit = compute_fixedobj_limit(obj, obj_spacing); do { if (fixnump(*obj)) continue; - place_fixedobj(obj, obj_spacing, alloc_ptrs, symbol_alloc_ptrs); + if (widetag_of(obj) == INSTANCE_WIDETAG) { + place_layout(obj, layout_size_class, + &layout_alloc_ptr, symbol_alloc_ptrs[0]); + } else { + place_fixedobj(obj, obj_spacing, alloc_ptrs, symbol_alloc_ptrs); + } } while (NEXT_FIXEDOBJ(obj, obj_spacing) <= limit); } -#if WRITABLE_TEXT_SEGMENT - // Might require filler between inter-object-type gaps - add_filler_if_needed(alloc_ptrs[FDEFN_WIDETAG/4], tramp_alloc_ptr); - add_filler_if_needed(alloc_ptrs[CODE_HEADER_WIDETAG/4], gf_alloc_ptr); -#endif #endif /* DEFRAGMENT_FIXEDOBJ_SUBSPACE */ if (immobile_space_reloc_index) { @@ -2164,8 +2007,8 @@ static void defrag_immobile_space(boolean verbose) } // Fix Lisp pointers in static, immobile, and dynamic spaces - fixup_space((lispobj*)STATIC_SPACE_START, - static_space_free_pointer - (lispobj*)STATIC_SPACE_START); + fixup_space((lispobj*)STATIC_SPACE_OBJECTS_START, + static_space_free_pointer - (lispobj*)STATIC_SPACE_OBJECTS_START); // Objects in immobile space are physically at 'tempspace', // but logically at their natural address. Perform fixups @@ -2177,20 +2020,20 @@ static void defrag_immobile_space(boolean verbose) fixup_space((lispobj*)FIXEDOBJ_SPACE_START, FIXEDOBJ_SPACE_SIZE >> WORD_SHIFT); #endif - fixup_space((lispobj*)varyobj_tempspace.start, - varyobj_tempspace.n_bytes >> WORD_SHIFT); + fixup_space((lispobj*)text_tempspace.start, + text_tempspace.n_bytes >> WORD_SHIFT); // Dynamic space // We can safely ignore allocation region boundaries. - fixup_space(current_dynamic_space, - (lispobj*)get_alloc_pointer() - current_dynamic_space); + fixup_space((lispobj*)DYNAMIC_SPACE_START, + ((uword_t)dynamic_space_highwatermark() - DYNAMIC_SPACE_START) >> WORD_SHIFT); // Copy the spaces back where they belong. #if DEFRAGMENT_FIXEDOBJ_SUBSPACE copy_back(FIXEDOBJ_SPACE_START, &fixedobj_tempspace, &fixedobj_free_pointer); #endif #ifdef LISP_FEATURE_IMMOBILE_CODE - copy_back(VARYOBJ_SPACE_START, &varyobj_tempspace, &varyobj_free_pointer); + copy_back(TEXT_SPACE_START, &text_tempspace, &text_space_highwatermark); free(components); #endif @@ -2198,16 +2041,15 @@ static void defrag_immobile_space(boolean verbose) #if 0 // It's easy to mess things up, so assert correctness before saving a core. printf("verifying defrag\n"); - verify_heap(1); + verify_heap(&verbose, VERIFY_POST_GC|VERIFY_AGGRESSIVE); #endif free(fixedobj_tempspace.start); - free(varyobj_tempspace.start); + free(text_tempspace.start); } #endif // Fixup immediate values that encode Lisp object addresses // in immobile space. Process only the absolute fixups. -#include "forwarding-ptr.h" #ifdef LISP_FEATURE_X86_64 static void apply_absolute_fixups(lispobj fixups, struct code* code) { @@ -2233,11 +2075,15 @@ static void apply_absolute_fixups(lispobj fixups, struct code* code) UNALIGNED_STORE32(fixup_where, fixed); continue; } + // Call to asm routine or linkage table entry using "CALL [#xNNNN]" form. + // This fixup is only for whole-heap relocation on startup. if (asm_routines_start <= ptr && ptr < asm_routines_end) { - // Call to asm routine using "CALL [#xNNNN]" form. - // This fixup is only for whole-heap relocation on startup. continue; } +#ifdef LISP_FEATURE_METASPACE + // Pointers to metaspace will never move, at least not for the time being. + if (ptr >= READ_ONLY_SPACE_START && ptr < READ_ONLY_SPACE_END) continue; +#endif if (find_fixedobj_page_index((void*)ptr) >= 0) { header_addr = search_immobile_space((void*)ptr); gc_assert(header_addr); @@ -2281,211 +2127,61 @@ static void apply_absolute_fixups(lispobj fixups, struct code* code) } #endif -#ifdef VERIFY_PAGE_GENS -void check_fixedobj_page(int page, - generation_index_t keep_gen, - generation_index_t new_gen) +void dump_immobile_fixedobjs(lispobj* where, lispobj* end, FILE*f) { - // Every page should have a 'gens' mask which exactly reflects - // the aggregate over all objects on that page. Verify that invariant, - // checking all pages, not just the ones below the free pointer. - int genmask, obj_size, obj_spacing, i, all_ok = 1; - lispobj *obj, header; - int sees_younger = 0; - - obj_size = fixedobj_page_obj_size(page); - obj_spacing = fixedobj_page_obj_align(page); - obj = fixedobj_page_address(page); - lispobj *limit = compute_fixedobj_limit(obj, obj_spacing); - genmask = 0; - if (obj_size == 0) { - gc_assert(!fixedobj_pages[page].gens); - for (i=0; i<WORDS_PER_PAGE && obj[i]==0; ++i) - ; - if(i<WORDS_PER_PAGE) - lose("page %d @ %p nonempty", page, fixedobj_page_address(page)); - return; - } - do { - header = *obj; - if (!fixnump(header)) { - int gen = immobile_obj_gen_bits(obj); - gc_assert(0 <= gen && gen <= PSEUDO_STATIC_GENERATION); - genmask |= 1<<gen; - if (fixedobj_points_to_younger_p(obj, obj_size, gen, keep_gen, new_gen)) { - if (fixedobj_page_wp(page)) - lose("sees_younger @ %p + %d", obj, obj_size); - sees_younger = 1; - } - } - } while (NEXT_FIXEDOBJ(obj, obj_spacing) <= limit); - // It's not wrong if the gen0 bit is set spuriously, but it should only - // happen at most once, on the first GC after image startup. - // At all other times, the invariant should hold that if the freelist - // indicated that space was available, and the new pointer differs, - // then some gen0 object exists on the page. - // The converse is true because of pseudo-atomicity of the allocator: - // if some thread claimed a hole, then it also updated the freelist. - // If it died before doing the latter, then the object allegedly created - // was never really live, so won't contain any pointers. - if (fixedobj_pages[page].gens != genmask - && fixedobj_pages[page].gens != (genmask|1)) { - fprintf(stderr, "Page %d @ %p: stored mask=%x actual=%x\n", - page, fixedobj_page_address(page), - fixedobj_pages[page].gens, genmask); - all_ok = 0; - } - if (fixedobj_page_wp(page) && sees_younger) { - fprintf(stderr, "Page %d @ %p: WP is wrong\n", - page, fixedobj_page_address(page)); - all_ok = 0; - } - gc_assert(all_ok); -} - -int n_immobile_objects; -int *immobile_objects, *immobile_objects_limit; - -int comparator_eq(const void* a, const void* b) { - return *(int*)a - *(int*)b; -} - -// Find the largest item less than or equal. -// (useful for finding the object that contains a given pointer) -int comparator_le(const void* a, const void* b) { - int diff = *(int*)a - *(int*)b; - if (diff <= 0) return diff; - // If looking to the right would see an item strictly greater - // than the sought key, or there is nothing to the right, - // then deem this an exact match. - if (b == (void*)immobile_objects_limit || ((int*)b)[1] > *(int*)a) return 0; - return 1; + uword_t prev_page_base = 0; + for ( ; where < end ; where += object_size(where) ) { + if (ALIGN_DOWN((uword_t)where, IMMOBILE_CARD_BYTES) != prev_page_base) { + low_page_index_t page = find_fixedobj_page_index(where); + fprintf(f, "page @ %p: gens=%x free=%x%s\n", + (void*)ALIGN_DOWN((uword_t)where, IMMOBILE_CARD_BYTES), + fixedobj_pages[page].attr.parts.gens_, + fixedobj_pages[page].free_index, + (fixedobj_pages[page].attr.parts.flags & 0x80)?" WP":""); + prev_page_base = ALIGN_DOWN((uword_t)where, IMMOBILE_CARD_BYTES); + } + fprintf(f, "%"OBJ_FMTX": %"OBJ_FMTX"\n", (uword_t)where, *where); + } } -// Find the smallest item greater than or equal. -// useful for finding the lowest item at or after a page base address. -int comparator_ge(const void* a, const void* b) { - int diff = *(int*)a - *(int*)b; - if (diff >= 0) return diff; - // If looking to the left would see an item strictly less - // than the sought key, or there is nothing to the left - // then deem this an exact match. - if (b == (void*)immobile_objects || ((int*)b)[-1] < *(int*)a) return 0; - return -1; +void dump_immobile_text(lispobj* where, lispobj* end, FILE*f) +{ + int prevpage = -1; + for ( ; where < end ; where += object_size(where) ) { + int page = find_text_page_index(where); + if (page!=prevpage) { + fprintf(f, "page %d @ %p ss=%p%s\n", + page, text_page_address(page), + text_page_scan_start(page), + text_page_touched(page)?"":" WP"); + prevpage = page; + } + fprintf(f, "%p: %lx\n", where, *where); + } } -void check_varyobj_pages() +#if 0 + void verify_text_scan_starts() { - // 1. Check that a linear scan sees only valid object headers, - // and that it terminates exactly at IMMOBILE_CODE_FREE_POINTER. - lispobj* obj = (lispobj*)VARYOBJ_SPACE_START; - lispobj* end = varyobj_free_pointer; - low_page_index_t end_page = find_varyobj_page_index((char*)end-1); - - n_immobile_objects = 0; - while (obj < end) { - lispobj word = *obj; - gc_assert(other_immediate_lowtag_p(word)); - int n_words = sizetab[header_widetag(word)](obj); - obj += n_words; - ++n_immobile_objects; - } - gc_assert(obj == end); - - // 2. Check that all scan_start_offsets are plausible. - // Begin by collecting all object header locations into an array; - immobile_objects = calloc(n_immobile_objects, sizeof (lispobj)); - immobile_objects_limit = immobile_objects + n_immobile_objects - 1; - obj = (lispobj*)VARYOBJ_SPACE_START; - int i = 0; - while (obj < end) { - immobile_objects[i++] = (lispobj)obj; - lispobj word = *obj; - int n_words = sizetab[header_widetag(word)](obj); - obj += n_words; - } - // Check that each page's scan start is a known immobile object - // and that it is the right object. - low_page_index_t page; - for (page = 0; page <= end_page; ++page) { - lispobj page_addr = (lispobj)varyobj_page_address(page); - int* found_below = bsearch(&page_addr, immobile_objects, n_immobile_objects, - sizeof (int), comparator_le); - int* found_above = bsearch(&page_addr, immobile_objects, n_immobile_objects, - sizeof (int), comparator_ge); - int stored_scan_start = (int)(long)varyobj_scan_start(page); - lispobj* scan_start_obj = (lispobj*)(long)*found_below; - if (scan_start_obj != (lispobj*)(long)stored_scan_start) { - //printf("page %d: found-below=%p stored=%p\n", page, scan_start_obj, stored_scan_start); - while (filler_obj_p(scan_start_obj)) { - int nwords = sizetab[widetag_of(scan_start_obj)](scan_start_obj); - // printf("skipping %d words to %p\n", nwords, scan_start_obj + nwords); - scan_start_obj += nwords; - // the stored scan start does not guarantee that it points - // to a non-hole; we only assert that it *probably* does not. - // As such, when computing the "correct" value, we allow - // any value in between the legal bounding values for it. - if ((int)(long)scan_start_obj == stored_scan_start) - break; - // If you hit the free pointer, or run off the page, - // then the page is completely empty. - if (scan_start_obj == varyobj_free_pointer - || scan_start_obj >= (lispobj*)varyobj_page_address(page+1)) { - scan_start_obj = varyobj_page_address(page+1); - break; + lispobj* where = (lispobj*)TEXT_SPACE_START; + lispobj* limit = text_space_highwatermark; + int prevpage = -1; + for ( ; where < limit ; where += object_size(where) ) { + if (*where & block_header_free_bit) continue; + int page = find_text_page_index(where); + if (page > prevpage) { // this object had better be the scan start + gc_assert(where == text_page_scan_start(page)); + prevpage = page; } - } - } - if (scan_start_obj != (lispobj*)(long)stored_scan_start) - lose("page %d: stored_scan_start=%p does not match found %p", - page, stored_scan_start, *found_below); - if (found_below != found_above) { - // the object below must touch this page. - // if it didn't, there should be a higher object below. - lispobj* below = (lispobj*)(long)*found_below; - int n_words = sizetab[header_widetag(*below)](below); - lispobj* end = below + n_words; - gc_assert(end > (lispobj*)page_addr); } - } - free(immobile_objects); - - // 3. The generation mask for each page is exactly the union - // of generation numbers of object headers on the page. - for (page = 0; page <= end_page; ++page) { - if (!varyobj_page_scan_start_offset[page]) - continue; // page is all holes or never used - obj = varyobj_scan_start(page); - lispobj word = *obj; - int n_words = sizetab[header_widetag(word)](obj); - // Skip the first object if it doesn't start on this page. - if (obj < (lispobj*)varyobj_page_address(page)) obj += n_words; - lispobj* limit = (lispobj*)varyobj_page_address(page) + WORDS_PER_PAGE; - lispobj* freeptr = varyobj_free_pointer; - if (limit > freeptr) limit = freeptr; - int mask = 0; - for ( ; obj < limit ; obj += sizetab[widetag_of(obj)](obj) ) { - int gen = immobile_obj_gen_bits(obj); - if (filler_obj_p(obj)) { - gc_assert(gen == 0); - } else { - gc_assert(0 <= gen && gen <= PSEUDO_STATIC_GENERATION); - mask |= 1 << gen; - } + int page, max; + max = find_text_page_index(text_space_highwatermark); + for (page=0;page<=max;++page) + if (text_page_scan_start(page)==0) { + if (text_page_genmask[page]) { + fprintf(stderr, "wrong genmask on page %d\n", page); + } + gc_assert(text_page_genmask[page]==0); } - /* This assertion fails after a fullcgc which doesn't update - * the genmasks, so that they remain as overestimates */ - // gc_assert(mask == varyobj_page_gens[page]); - - int actual = varyobj_page_gens[page]; - /* Fail if any bit in (LOGANDC1 ACTUAL EXPECTED) is true: - * actual=0, expected=0 -> // ok - * actual=1, expected=1 -> // ok - * actual=1, expected=0 -> // ok - * actual=0, expected=1 -> // NOT ok - */ - if (~actual & mask) - lose("genmask wrong: actual=%x expect=%x", actual, mask); - } } #endif diff --git a/src/runtime/immobile-space.h b/src/runtime/immobile-space.h index 726f27ea98..addb50c6b8 100644 --- a/src/runtime/immobile-space.h +++ b/src/runtime/immobile-space.h @@ -23,7 +23,6 @@ extern void prepare_immobile_space_for_final_gc(void); extern void prepare_immobile_space_for_save(boolean verbose); extern boolean immobile_space_preserve_pointer(void*); -extern void update_immobile_nursery_bits(void); extern void scavenge_immobile_roots(generation_index_t,generation_index_t); extern void scavenge_immobile_newspace(void); extern void sweep_immobile_space(int raise); @@ -31,7 +30,7 @@ extern void write_protect_immobile_space(void); extern unsigned int immobile_scav_queue_count; typedef int low_page_index_t; -extern unsigned int* varyobj_page_touched_bits; +extern unsigned int* text_page_touched_bits; extern uword_t asm_routines_start, asm_routines_end; static inline void * @@ -40,33 +39,13 @@ fixedobj_page_address(low_page_index_t page_num) return (void*)(FIXEDOBJ_SPACE_START + (page_num * IMMOBILE_CARD_BYTES)); } static inline void * -varyobj_page_address(low_page_index_t page_num) +text_page_address(low_page_index_t page_num) { - return (void*)(VARYOBJ_SPACE_START + (page_num * IMMOBILE_CARD_BYTES)); + return (void*)(TEXT_SPACE_START + (page_num * IMMOBILE_CARD_BYTES)); } -struct varyobj_page { - // Generation mask for objects which start on this page. - // An object which ends on but does not start on this page - // does not set the respective bit. - unsigned int generations: 8, - // Offset backwards in double-lispwords from the page end to the - // lowest-addressed object touching the page. This offset can point to - // a hole, but we prefer that it not. If the offset is zero, the page - // has no object other than possibly a hole resulting from a freed object. - // The entire space size defaults to just over 100MiB, - // so 24 bits is more than adequate to point back to any word. - scan_start_offset: 24; -}; - -extern struct varyobj_page *varyobj_pages; -/* Calculate the address where the first object touching this page starts. */ -static inline lispobj* -varyobj_scan_start(low_page_index_t page_index) -{ - return (lispobj*)((char*)varyobj_page_address(page_index+1) - - varyobj_pages[page_index].scan_start_offset * (2 * N_WORD_BYTES)); -} +extern unsigned char* text_page_genmask; +extern unsigned short int* tlsf_page_sso; static inline low_page_index_t find_fixedobj_page_index(void *addr) { @@ -80,13 +59,13 @@ static inline low_page_index_t find_fixedobj_page_index(void *addr) } return -1; } -static inline low_page_index_t find_varyobj_page_index(void *addr) +static inline low_page_index_t find_text_page_index(void *addr) { - if (addr >= (void*)VARYOBJ_SPACE_START) { + if (addr >= (void*)TEXT_SPACE_START) { // Must use full register size here to avoid truncation of quotient // and bogus result! - size_t offset = (uintptr_t)addr - (uintptr_t)VARYOBJ_SPACE_START; - if (offset >= varyobj_space_size) + size_t offset = (uintptr_t)addr - (uintptr_t)TEXT_SPACE_START; + if (offset >= text_space_size) return -1; return offset / IMMOBILE_CARD_BYTES; } @@ -118,7 +97,6 @@ static inline boolean immobile_space_p(lispobj __attribute__((unused)) obj) { re #define scavenge_immobile_roots(dummy1,dummy2) #define scavenge_immobile_newspace(dummy) #define sweep_immobile_space(dummy) -#define update_immobile_nursery_bits() #define write_protect_immobile_space() #define immobile_scav_queue_count 0 #define immobile_card_protected_p(dummy) (0) diff --git a/src/runtime/interr.c b/src/runtime/interr.c index b10c5e04a0..03d41eda44 100644 --- a/src/runtime/interr.c +++ b/src/runtime/interr.c @@ -47,7 +47,7 @@ default_lossage_handler(void) // This may not be exactly the right condition for determining // whether it might be possible to backtrace, but at least it prevents // lose() from itself losing early in startup. - if (arch_os_get_current_thread()) lisp_backtrace(100); + if (get_sb_vm_thread()) lisp_backtrace(100); } exit(1); } @@ -99,10 +99,7 @@ void disable_lossage_handler(void) static void print_message(char *fmt, va_list ap) { - fprintf(stderr, " in SBCL pid %d",getpid()); -#if defined(LISP_FEATURE_SB_THREAD) - fprintf(stderr, "(tid %p)", (void*)thread_self()); -#endif + fprintf(stderr, " in SBCL pid %d" THREAD_ID_LABEL, getpid(), THREAD_ID_VALUE); if (fmt) { fprintf(stderr, ":\n"); vfprintf(stderr, fmt, ap); @@ -127,7 +124,14 @@ lose(char *fmt, ...) va_list ap; /* Block signals to prevent other threads, timers and such from * interfering. If only all threads could be stopped somehow. */ - block_blockable_signals(0); + +#ifdef LISP_FEATURE_WIN32 + /* pthread_sigmask is emulated on windows, if lose() happens very early + it may not be ready to work yet. */ + if (get_sb_vm_thread()) +#endif + block_blockable_signals(0); + fprintf(stderr, "fatal error encountered"); va_start(ap, fmt); print_message(fmt, ap); @@ -137,6 +141,32 @@ lose(char *fmt, ...) call_lossage_handler(); } +#if 0 +/// thread printf. This was used to produce the 2-column output +/// at the bottom of "src/code/final". The main thread'd os_kernel_tid +/// must be assigned a constant in main_thread_trampoline(). +void tprintf(char *fmt, ...) +{ + va_list ap; + char buf[200]; + char *ptr; + const char spaces[] = " "; + struct thread*th = get_sb_vm_thread(); + buf[0] = ';'; buf[1] = ' '; + ptr = buf+2; + if (th->os_kernel_tid == 'A') { + strcpy(ptr, spaces); + ptr += (sizeof spaces)-1; + } + va_start(ap, fmt); + int n = vsprintf(ptr, fmt, ap); + va_end(ap); + ptr += n; + *ptr++ = '\n'; + write(2, buf, ptr-buf); +} +#endif + boolean lose_on_corruption_p = 0; void @@ -186,38 +216,36 @@ char *internal_error_descriptions[] = {INTERNAL_ERROR_NAMES}; char internal_error_nargs[] = INTERNAL_ERROR_NARGS; void skip_internal_error (os_context_t *context) { - unsigned char *ptr = (unsigned char *)*os_context_pc_addr(context); + unsigned char *ptr = (unsigned char *)os_context_pc(context); + #ifdef LISP_FEATURE_ARM64 - // This code is broken. The program counter as received in *context - // points one instruction beyond the BRK opcode. - // I wrote a test vop that emits a cerror break thusly: - // - // ; 62C: 40A122D4 BRK #5386 ; Cerror trap - // ; 630: 30 BYTE #X30 ; R2 - // - // and added a printf to see the instruction pointer here: - // skip_internal_error: pc=0x1002441630 - // - // which got a trap code of 0. This is due to the fact that DESCRIPTOR-REG - // is the lowest SC number, so the encoded SC+OFFSET of R2 is a small - // value, and therefore shifting right by 13 bits extracts a 0. - // Internal error number 0 has 0 arguments, so we skip nothing in the varint - // decoder loop, which is the right thing for the wrong reason. - u32 trap_instruction = *(u32 *)ptr; - unsigned char code = trap_instruction >> 13 & 0xFF; - ptr += 4; -#else + uint32_t trap_instruction = *(uint32_t *)(ptr - 4); +#endif + unsigned char code = *ptr; ptr++; // skip the byte indicating the kind of trap -#endif + if (code > sizeof(internal_error_nargs)) { - printf("Unknown error code %d at %p\n", code, (void*)*os_context_pc_addr(context)); + printf("Unknown error code %d at %p\n", code, (void*)os_context_pc(context)); } int nargs = internal_error_nargs[code]; + +#ifdef LISP_FEATURE_ARM64 + /* See SB-VM::EMIT-ERROR-BREAK for the scheme */ + unsigned char first_arg = trap_instruction >> 13 & 0xFF; + if (first_arg != 31 && nargs) { + nargs--; + } +#endif + int nbytes = 0; while (nargs--) read_var_integer(ptr, &nbytes); ptr += nbytes; - *((unsigned char **)os_context_pc_addr(context)) = ptr; +#ifdef LISP_FEATURE_ARM64 + ptr=PTR_ALIGN_UP(ptr, 4); +#endif + set_os_context_pc(context, (os_context_register_t)ptr); + } /* internal error handler for when the Lisp error system doesn't exist @@ -225,120 +253,125 @@ void skip_internal_error (os_context_t *context) { * FIXME: Shouldn't error output go to stderr instead of stdout? (Alas, * this'd require changes in a number of things like brief_print(..), * or I'd have changed it immediately.) */ +void describe_error_arg(os_context_t *context, int sc_number, int offset) { +{ + int ch; + + printf(" SC: %d, Offset: %d", sc_number, offset); + switch (sc_number) { + case sc_AnyReg: + case sc_DescriptorReg: + putchar('\t'); + brief_print(*os_context_register_addr(context, offset)); + break; + + case sc_CharacterReg: + ch = *os_context_register_addr(context, offset); +#ifdef LISP_FEATURE_X86 + if (offset&1) + ch = ch>>8; + ch = ch & 0xff; +#endif + switch (ch) { + case '\n': printf("\t'\\n'\n"); break; + case '\b': printf("\t'\\b'\n"); break; + case '\t': printf("\t'\\t'\n"); break; + case '\r': printf("\t'\\r'\n"); break; + default: + if (ch < 32 || ch > 127) + printf("\\%03o", ch); + else + printf("\t'%c'\n", ch); + break; + } + break; + case sc_SapReg: +#ifdef sc_WordPointerReg + case sc_WordPointerReg: +#endif + printf("\t0x%08lx\n", (unsigned long) *os_context_register_addr(context, offset)); + break; + case sc_SignedReg: + printf("\t%ld\n", (long) *os_context_register_addr(context, offset)); + break; + case sc_UnsignedReg: + printf("\t%lu\n", (unsigned long) *os_context_register_addr(context, offset)); + break; +#ifdef sc_SingleFloatReg + case sc_SingleFloatReg: + printf("\t%g\n", *(float *)&context->sc_fpregs[offset]); + break; +#endif +#ifdef sc_DoubleFloatReg + case sc_DoubleFloatReg: + printf("\t%g\n", *(double *)&context->sc_fpregs[offset]); + break; +#endif + case sc_Constant: + print_constant(context, offset); + break; + default: + printf("\t???\n"); + break; + } +} +}; void describe_internal_error(os_context_t *context) { unsigned char *ptr = arch_internal_error_arguments(context); char count; - int position, sc_and_offset, sc_number, offset, ch; - void * pc = (void*)*os_context_pc_addr(context); + int position; + void * pc = (void*)os_context_pc(context); unsigned char code; #ifdef LISP_FEATURE_ARM64 - u32 trap_instruction = *(u32 *)ptr; - code = trap_instruction >> 13 & 0xFF; + /* See SB-VM::EMIT-ERROR-BREAK for the scheme */ + uint32_t trap_instruction = *(uint32_t *)ptr; + unsigned char trap = trap_instruction >> 5 & 0xFF; ptr += 4; +#elif defined(LISP_FEATURE_PPC64) && defined(LISP_FEATURE_LITTLE_ENDIAN) + unsigned char trap = *(ptr-4); #else unsigned char trap = *(ptr-1); +#endif + if (trap >= trap_Error) { code = trap - trap_Error; } else { code = *ptr; ptr++; } -#endif - if (code > sizeof(internal_error_nargs)) { printf("Unknown error code %d at %p\n", code, pc); } printf("Internal error #%d \"%s\" at %p\n", code, internal_error_descriptions[code], pc); + count = internal_error_nargs[code]; - for (count = internal_error_nargs[code], position = 0; - count > 0; - --count) { - sc_and_offset = read_var_integer(ptr, &position); - sc_number = sc_and_offset_sc_number(sc_and_offset); - offset = sc_and_offset_offset(sc_and_offset); - - printf(" SC: %d, Offset: %d", sc_number, offset); - switch (sc_number) { - case sc_AnyReg: - case sc_DescriptorReg: - putchar('\t'); - brief_print(*os_context_register_addr(context, offset)); - break; - - case sc_CharacterReg: - ch = *os_context_register_addr(context, offset); -#ifdef LISP_FEATURE_X86 - if (offset&1) - ch = ch>>8; - ch = ch & 0xff; -#endif - switch (ch) { - case '\n': printf("\t'\\n'\n"); break; - case '\b': printf("\t'\\b'\n"); break; - case '\t': printf("\t'\\t'\n"); break; - case '\r': printf("\t'\\r'\n"); break; - default: - if (ch < 32 || ch > 127) - printf("\\%03o", ch); - else - printf("\t'%c'\n", ch); - break; - } - break; - case sc_SapReg: -#ifdef sc_WordPointerReg - case sc_WordPointerReg: -#endif - printf("\t0x%08lx\n", (unsigned long) *os_context_register_addr(context, offset)); - break; - case sc_SignedReg: - printf("\t%ld\n", (long) *os_context_register_addr(context, offset)); - break; - case sc_UnsignedReg: - printf("\t%lu\n", (unsigned long) *os_context_register_addr(context, offset)); - break; -#ifdef sc_SingleFloatReg - case sc_SingleFloatReg: - printf("\t%g\n", *(float *)&context->sc_fpregs[offset]); - break; -#endif -#ifdef sc_DoubleFloatReg - case sc_DoubleFloatReg: - printf("\t%g\n", *(double *)&context->sc_fpregs[offset]); +#ifdef LISP_FEATURE_ARM64 + unsigned char first_arg = trap_instruction >> 13 & 0xFF; + unsigned char first_offset = first_arg & 0x1F; + unsigned char first_sc = first_arg >> 5; + if (first_arg != 31) { + char sc = 0; + switch (first_sc) { + case 1: + sc = sc_UnsignedReg; break; -#endif - case sc_Constant: - print_constant(context, offset); + case 2: + sc = sc_SignedReg; break; default: - printf("\t???\n"); - break; + sc = sc_DescriptorReg; } + describe_error_arg(context, sc, first_offset); + count--; } -} - -/* utility routines used by miscellaneous pieces of code */ +#endif -lispobj debug_print(lispobj string) -{ - /* This is a kludge. It's not actually safe - in general - to use - %primitive print on the alpha, because it skips half of the - number stack setup that should usually be done on a function - call, so the called routine (i.e. this one) ends up being able - to overwrite local variables in the caller. Rather than fix - this everywhere that %primitive print is used (it's only a - debugging aid anyway) we just guarantee our safety by putting - an unused buffer on the stack before doing anything else - here */ - char untouched[32]; - if (header_widetag(VECTOR(string)->header) != SIMPLE_BASE_STRING_WIDETAG) - fprintf(stderr, "debug_print: can't display string\n"); - else - fprintf(stderr, "%s\n", (char *)(VECTOR(string)->data)); - /* shut GCC up about not using this, because that's the point.. */ - (void)untouched; - return NIL; + for (position = 0; count > 0; --count) { + int sc_and_offset = read_var_integer(ptr, &position); + describe_error_arg(context, sc_and_offset_sc_number(sc_and_offset), + sc_and_offset_offset(sc_and_offset)); + } } diff --git a/src/runtime/interr.h b/src/runtime/interr.h index bb83b7b58f..6d69951cec 100644 --- a/src/runtime/interr.h +++ b/src/runtime/interr.h @@ -17,6 +17,7 @@ extern void lose(char *fmt, ...) __attribute__((format(printf,1,2))) // clang and gcc support this, MSVC doesn't #endif never_returns; +extern void tprintf(char *fmt, ...); extern boolean lose_on_corruption_p; extern void corruption_warning_and_maybe_lose(char *fmt, ...); extern void enable_lossage_handler(void); @@ -24,8 +25,12 @@ extern void disable_lossage_handler(void); extern void describe_internal_error(os_context_t *context); extern void skip_internal_error (os_context_t *context); -extern lispobj debug_print(lispobj string); - +#ifdef LISP_FEATURE_WIN32 +/* thread ID is a more useful identifer than thread handle */ +#define UNKNOWN_STACK_POINTER_ERROR(function_name, thread) \ + lose(function_name": no SP known for thread %p (ID %p)", \ + thread, (void*)thread->os_kernel_tid); +#else /* Portably printf()ing a pthread_t is tricky. It has to be printed * as opaque bytes by taking &id and sizeof id. * As the man page says: @@ -38,10 +43,11 @@ extern lispobj debug_print(lispobj string); * pthread_t to the list of types that are not required to be arithmetic types, * thus allowing pthread_t to be defined as a structure." * - * We assume that it can be cast to 'long' which is a total KLUDGE + * We assume that it can be cast to 'void*' */ #define UNKNOWN_STACK_POINTER_ERROR(function_name, thread) \ - lose(function_name": no SP known for thread %p (OS %ld)", \ - thread, (long)thread->os_thread); + lose(function_name": no SP known for thread %p (pthread %p)", \ + thread, (void*)thread->os_thread); +#endif #endif diff --git a/src/runtime/interrupt.c b/src/runtime/interrupt.c index b693cd88a0..4f4012cb8d 100644 --- a/src/runtime/interrupt.c +++ b/src/runtime/interrupt.c @@ -33,10 +33,10 @@ * the value from interrupt_low_level_handlers[..], instead of the * ordinary interrupt_handle_now(..) or interrupt_handle_later(..). * - * o the SIGTRAP (Linux/Alpha) which Lisp code uses to handle breakpoints, + * o the SIGTRAP which Lisp code may uses to handle breakpoints, * pseudo-atomic sections, and some classes of error (e.g. "function * not defined"). This never goes anywhere near the Lisp handlers at all. - * See runtime/alpha-arch.c and code/signal.lisp + * See src/code/signal.lisp * * - WHN 20000728, dan 20010128 */ @@ -63,11 +63,21 @@ #include "gc.h" #include "alloc.h" #include "dynbind.h" -#include "getallocptr.h" +#include "pseudo-atomic.h" #include "genesis/fdefn.h" #include "genesis/simple-fun.h" #include "genesis/cons.h" #include "genesis/vector.h" +#include "atomiclog.inc" + +#ifdef ATOMIC_LOGGING +uword_t *eventdata; +int n_logevents; +#endif + +#ifdef ADDRESS_SANITIZER +#include <sanitizer/asan_interface.h> +#endif /* * This is a workaround for some slightly silly Linux/GNU Libc @@ -96,6 +106,9 @@ static inline void sigcopyset(sigset_t *new, sigset_t *old) { +#ifdef ADDRESS_SANITIZER + sigemptyset(new); +#endif memcpy(new, old, REAL_SIGSET_SIZE_BYTES); } @@ -112,7 +125,7 @@ boolean internal_errors_enabled = 0; static void (*interrupt_low_level_handlers[NSIG]) (int, siginfo_t*, os_context_t*); #endif -union interrupt_handler interrupt_handlers[NSIG]; +lispobj lisp_sig_handlers[NSIG]; /* Under Linux on some architectures, we appear to have to restore the * FPU control word from the context, as after the signal is delivered @@ -171,56 +184,65 @@ static void sigmask_logandc(sigset_t *dest, const sigset_t *source) /* Foreign code may want to start some threads on its own. * Non-targetted, truly asynchronous signals can be delivered to - * basically any thread, but invoking Lisp handlers in such foregign + * basically any thread, but invoking Lisp handlers in such foreign * threads is really bad, so let's resignal it. * * This should at least bring attention to the problem, but it cannot * work for SIGSEGV and similar. It is good enough for timers, and * maybe all deferrables. */ -#ifndef LISP_FEATURE_WIN32 +#if defined LISP_FEATURE_DARWIN && defined LISP_FEATURE_SB_THREAD +pthread_key_t foreign_thread_ever_lispified; +int sigwait_bug_mitigation_count; +#endif + +#ifdef LISP_FEATURE_WIN32 +#define resignal_to_lisp_thread(dummy1,dummy2) {} +#else static void -add_handled_signals(sigset_t *sigset) +resignal_to_lisp_thread(int signal, os_context_t *context) { - int i; - for(i = 1; i < NSIG; i++) { - if (!(ARE_SAME_HANDLER(interrupt_low_level_handlers[i], SIG_DFL)) || - !(ARE_SAME_HANDLER(interrupt_handlers[i].c, SIG_DFL))) { - sigaddset(sigset, i); - } +#if defined LISP_FEATURE_DARWIN && defined LISP_FEATURE_SB_THREAD + if (signal == SIG_STOP_FOR_GC && pthread_getspecific(foreign_thread_ever_lispified)) { + // This may be error-prone, I'm not sure. Suppose there is a lingering + // stop-for-gc signal after we've demoted a lisp thread back to being + // a foreign thread. Suppose that thread then calls into lisp again so it re-promoted + // to a lisp thread. Is the next stop-for-gc signal real, or to be ignored? + // It'll be treated as real even if it was the lingering signal which ought to have + // been ignored. That probably won't happen, but "probably" is not a guarantee. + __sync_fetch_and_add(&sigwait_bug_mitigation_count, 1); + return; } -} #endif - -static boolean -maybe_resignal_to_lisp_thread(int signal, os_context_t *context) -{ -#ifndef LISP_FEATURE_WIN32 - if (!lisp_thread_p(context)) { - if (!(sigismember(&deferrable_sigset,signal))) { - corruption_warning_and_maybe_lose + if (!sigismember(&deferrable_sigset,signal)) { + corruption_warning_and_maybe_lose #ifdef LISP_FEATURE_SB_THREAD - ("Received signal %d in non-lisp thread %lu, resignalling to a lisp thread.", - signal, pthread_self()); + ("Received signal %d @ %lx in non-lisp"THREAD_ID_LABEL", resignaling to a lisp thread.", + signal, os_context_pc(context), THREAD_ID_VALUE); #else - ("Received signal %d in non-lisp thread, resignalling to a lisp thread.", - signal); + ("Received signal %d in non-lisp thread, resignaling to a lisp thread.", signal); #endif + } + sigset_t sigset; + sigemptyset(&sigset); + int i; + for(i = 1; i < NSIG; i++) { + // This use of SIG_DFL is a bit disingenous. It actually means "is it 0", + // because the low_level_handlers array is never explicitly initialized + // with SIG_DFL in each element, but SIG_DFL happens to be 0. + if (!ARE_SAME_HANDLER(interrupt_low_level_handlers[i], SIG_DFL) + || lisp_sig_handlers[i]) { + sigaddset(&sigset, i); } - sigset_t sigset; - sigemptyset(&sigset); - add_handled_signals(&sigset); - thread_sigmask(SIG_BLOCK, &sigset, 0); - // This arranges for every handled signal to be blocked on return from this - // handler invocation, presumably because that avoids further detours through - // this thread's handler for signals that we don't want it to handle. - sigmask_logior(os_context_sigmask_addr(context), &sigset); - kill(getpid(), signal); - return 1; - } else -#endif - return 0; + } + thread_sigmask(SIG_BLOCK, &sigset, 0); + // This arranges for every handled signal to be blocked on return from this + // handler invocation, presumably because that avoids further detours through + // this thread's handler for signals that we don't want it to handle. + sigmask_logior(os_context_sigmask_addr(context), &sigset); + kill(getpid(), signal); } +#endif #if INSTALL_SIG_MEMORY_FAULT_HANDLER && defined(THREAD_SANITIZER) /* Under TSAN, any delivered signal blocks all other signals regardless of the @@ -245,15 +267,26 @@ maybe_resignal_to_lisp_thread(int signal, os_context_t *context) # define UNBLOCK_SIGSEGV() {} #endif +/* Not safe in general, but if your thread names are all + * simple-base-string and won't move, this is slightly ok */ +__attribute__((unused)) static char* cur_thread_name() +{ + struct thread* th = get_sb_vm_thread(); + struct thread_instance *lispthread = + (void*)(th->lisp_thread - INSTANCE_POINTER_LOWTAG); + struct vector* name = VECTOR(lispthread->name); + if (widetag_of(&name->header) == SIMPLE_BASE_STRING_WIDETAG) return (char*)name->data; + return "?"; +} + /* These are to be used in signal handlers. Currently all handlers are * called from one of: * * interrupt_handle_now_handler * maybe_now_maybe_later * low_level_handle_now_handler - * low_level_maybe_now_maybe_later * - * This gives us a single point of control (or six) over errno, fp + * This gives us a single point of control (or three) over errno, fp * control word, and fixing up signal context on sparc. * * The SPARC/Linux platform doesn't quite do signals the way we want @@ -261,37 +294,83 @@ maybe_resignal_to_lisp_thread(int signal, os_context_t *context) * kernel properly, so we fix it up ourselves in the * arch_os_get_context(..) function. -- CSR, 2002-07-23 */ +#ifdef ATOMIC_LOGGING +void dump_eventlog() +{ + int i = 0; + uword_t *e = eventdata; + char buf[1024]; + int nc, nc1; // number of chars in buffer + // Define buflen to be smaller than 'buf' so that we can prefix it + // with thread pointer and suffix it with a newline + // without too much hassle. +#define buflen (sizeof buf-20) + nc = snprintf(buf, buflen, "Event log: used %d elements of %d max\n", n_logevents, EVENTBUFMAX); + write(2, buf, nc); + while (i<n_logevents) { + char *fmt = (char*)e[i+1]; + uword_t prefix = e[i]; + int nargs = prefix & 7; + void* thread_pointer = (void*)(prefix & ~7); + extern char* thread_name_from_pthread(void*); + char* name = thread_name_from_pthread(thread_pointer); + if (name) nc = sprintf(buf, "%s: ", name); else nc = sprintf(buf, "%p: ", thread_pointer); + switch (nargs) { + default: printf("busted event log"); return; + case 0: nc1 = snprintf(buf+nc, buflen, fmt, 0); break; // the 0 inhibits a warning + case 1: nc1 = snprintf(buf+nc, buflen, fmt, e[i+2]); break; + case 2: nc1 = snprintf(buf+nc, buflen, fmt, e[i+2], e[i+3]); break; + case 3: nc1 = snprintf(buf+nc, buflen, fmt, e[i+2], e[i+3], e[i+4]); break; + case 4: nc1 = snprintf(buf+nc, buflen, fmt, e[i+2], e[i+3], e[i+4], e[i+5]); break; + case 5: nc1 = snprintf(buf+nc, buflen, fmt, e[i+2], e[i+3], e[i+4], e[i+5], e[i+6]); break; + case 6: nc1 = snprintf(buf+nc, buflen, fmt, e[i+2], e[i+3], e[i+4], e[i+5], e[i+6], + e[i+7]); break; + } +#undef buflen + buf[nc+nc1] = '\n'; + write(2, buf, 1+nc+nc1); + i += nargs + 2; + } +} +void sigdump_eventlog(int __attribute__((unused)) signal, + siginfo_t __attribute__((unused)) *info, + os_context_t *context) +{ + dump_eventlog(); +} + +static void record_signal(int sig, void* context) +{ + event2("got signal %d @ pc=%p", sig, os_context_pc(context)); +} +#define RECORD_SIGNAL(sig,ctxt) if(sig!=SIGSEGV)record_signal(sig,ctxt); +#else +#define RECORD_SIGNAL(sig,ctxt) +#endif + +#ifdef LISP_FEATURE_WIN32 +# define should_handle_in_this_thread(c) (1) +#else +# define should_handle_in_this_thread(c) lisp_thread_p(c) +#endif #define SAVE_ERRNO(signal,context,void_context) \ { \ int _saved_errno = errno; \ + RECORD_SIGNAL(signal,void_context); \ UNBLOCK_SIGSEGV(); \ RESTORE_FP_CONTROL_WORD(context,void_context); \ - if (!maybe_resignal_to_lisp_thread(signal, context)) \ - { + if (should_handle_in_this_thread(context)) { #define RESTORE_ERRNO \ - } \ + } else resignal_to_lisp_thread(signal,void_context); \ errno = _saved_errno; \ } static void run_deferred_handler(struct interrupt_data *data, os_context_t *context); -#if !defined(LISP_FEATURE_WIN32) || defined(LISP_FEATURE_SB_THREAD) -static void store_signal_data_for_later (struct interrupt_data *data, - void *handler, int signal, - siginfo_t *info, - os_context_t *context); - /* Generic signal related utilities. */ -void -get_current_sigmask(sigset_t *sigset) -{ - /* Get the current sigmask, by blocking the empty set. */ - thread_sigmask(SIG_BLOCK, 0, sigset); -} - // Stringify sigset into the supplied result buffer. void sigset_tostring(const sigset_t *sigset, char* result, int result_length) @@ -309,51 +388,22 @@ sigset_tostring(const sigset_t *sigset, char* result, int result_length) } result[len] = 0; } - -/* Return 1 if all signals in sigset2 are masked in sigset, return 0 - * if all are unmasked, else die. Passing NULL for sigset is a shorthand - * for the current sigmask. */ -boolean -all_signals_blocked_p(const sigset_t *sigset, sigset_t *sigset2, - const char *name) -{ - int i; - boolean has_blocked = 0, has_unblocked = 0; - sigset_t current; - if (sigset == 0) { - get_current_sigmask(¤t); - sigset = ¤t; - } - for(i = 1; i <= MAX_SIGNUM; i++) { - if (sigismember(sigset2, i)) { - if (sigismember(sigset, i)) - has_blocked = 1; - else - has_unblocked = 1; - } - } - if (has_blocked && has_unblocked) { - char buf[3*64]; // assuming worst case 64 signals present in sigset - sigset_tostring(sigset, buf, sizeof buf); - lose("%s signals partially blocked: {%s}", name, buf); - } - if (has_blocked) - return 1; - else - return 0; -} /* Deferrables, blockables, gc signals. */ -void -sigaddset_deferrable(sigset_t *s) -{ +#ifdef LISP_FEATURE_SB_SAFEPOINT +static void sigaddset_deferrable(sigset_t *s) { + sigaddset(s, SIGURG); +} +static void sigaddset_async(sigset_t *s) { +#else +static void sigaddset_deferrable(sigset_t *s) { +#endif sigaddset(s, SIGHUP); sigaddset(s, SIGINT); sigaddset(s, SIGTERM); sigaddset(s, SIGQUIT); - sigaddset(s, SIGPIPE); sigaddset(s, SIGALRM); sigaddset(s, SIGURG); sigaddset(s, SIGTSTP); @@ -363,80 +413,149 @@ sigaddset_deferrable(sigset_t *s) #else sigaddset(s, SIGPOLL); #endif -#ifndef LISP_FEATURE_HPUX +#ifndef LISP_FEATURE_BACKTRACE_ON_SIGNAL sigaddset(s, SIGXCPU); - sigaddset(s, SIGXFSZ); #endif + sigaddset(s, SIGXFSZ); +#if !(defined SIG_STOP_FOR_GC && SIG_STOP_FOR_GC == SIGVTALRM) sigaddset(s, SIGVTALRM); - sigaddset(s, SIGPROF); +#endif +#if !(defined SIG_STOP_FOR_GC && SIG_STOP_FOR_GC == SIGWINCH) sigaddset(s, SIGWINCH); +#endif } -void -sigaddset_blockable(sigset_t *sigset) +static void +sigaddset_gc(sigset_t __attribute__((unused)) *sigset) { - sigaddset_deferrable(sigset); - sigaddset_gc(sigset); +#ifdef THREADS_USING_GCSIGNAL + sigaddset(sigset,SIG_STOP_FOR_GC); +#endif } void -sigaddset_gc(sigset_t __attribute__((unused)) *sigset) +sigaddset_blockable(sigset_t *sigset) { -#ifdef THREADS_USING_GCSIGNAL - sigaddset(sigset,SIG_STOP_FOR_GC); +#ifdef LISP_FEATURE_SB_SAFEPOINT + sigaddset_async(sigset); +#else + sigaddset_deferrable(sigset); + sigaddset_gc(sigset); #endif + // SIGPIPE is *NOT* an asynchronous signal. In normal usage you receive this signal + // synchronously in response to a system call. As such we do not place it in the + // deferrable set, but it _is_ blockable. If you're doing something wherein SIGPIPE + // interrupts a pseudo-atomic section, then you're doing something wrong for sure. + sigaddset(sigset, SIGPIPE); + // SIGPROF does not need to be deferred- our new handler is signal-safe, and trying to + // hide non-async-safety of a SIGPROF handler behind a deferral mechanism is horrible. + sigaddset(sigset, SIGPROF); } /* initialized in interrupt_init */ sigset_t deferrable_sigset; sigset_t blockable_sigset; +sigset_t thread_start_sigset; +/* gc_sigset will have exactly 1 bit on, for SIG_STOP_FOR_GC, or no bits on. + * We always use SIGUSR2 as SIG_STOP_FOR_GC, though in days past it may have + * varied by OS. Also, long ago, there was a different signal to resume after + * suspension, but now we use a semaphore for that, which is technically + * on shaky ground, but seems to work. e.g. consider an implementation of + * of sem_wait that requires a call to malloc; it could fail badly for us */ sigset_t gc_sigset; +/* Return 1 if almost all deferrable signals are blocked, 0 if not, + * and fail if there is a mixture. Explicitly ignore SIGALRM which we now + * allow to be always blocked in a thread and/or manipulated. + * Also don't bother with ones guarded by #ifdef in sigaddset_deferrable + * (SIGIO, SIGPOLL, SIGXCPU). + * The intent is to perform a best-effort check that the runtime's assumptions + * are not egregiously violated, not to enforce proper use of each and every signal. + * (Who would add a SIGTSTP handler that is not completely async safe anyway?) + */ boolean deferrables_blocked_p(sigset_t *sigset) { - return all_signals_blocked_p(sigset, &deferrable_sigset, "deferrable"); -} + sigset_t current; + if (sigset == 0) { + thread_sigmask(SIG_BLOCK, 0, ¤t); + sigset = ¤t; + } +#ifdef LISP_FEATURE_SB_SAFEPOINT + /* The only signal whose mask bit we manipulate is SIGURG. + * All other deferrable signals remain permanently in a blocked state. + * Therefore the answer to the question of whether deferrables + * are blocked is simply whether SIGURG is blocked */ + return sigismember(sigset, SIGURG); +#else + /* SIGPROF must not be here. Some people use an async-signal-safe profiler + * which not only doesn't rely on signal deferral, but wants to manipulate the + * blocked/unblocked bit completely independently of SBCL's requirements. + * Such usage would have needed to either modify the global deferrable_sigset + * at runtime, or locally patch it out of sigaddset_deferrable. + * I'd prefer to remove external access to deferrable_sigset which suggests that + * this predicate should be insensitive to whether SIGPROF is deferrable. + * The actual deferral mechanmism still works, because remember, this test does + * not affect behavior of correct code - it is just to decide whether we understand + * the signal mask to be in a valid state, but it was overly restrictive. + * + * Also SIGXCPU and SIGPWR are conspicuously absent. SB-THREAD:INTERRUPT-THREAD + * used SIGPWR long ago, but I don't know why it was never in deferrable_sigset. + */ + const int expected_mask = 0x3ff +#if (defined SIG_STOP_FOR_GC && SIG_STOP_FOR_GC == SIGVTALRM) + - (1<<1) +#endif +#if (defined SIG_STOP_FOR_GC && SIG_STOP_FOR_GC == SIGWINCH) + - (1<<0) #endif + ; + + int mask = (sigismember(sigset, SIGHUP) << 9) + | (sigismember(sigset, SIGINT) << 8) + | (sigismember(sigset, SIGTERM) << 7) + | (sigismember(sigset, SIGQUIT) << 6) + | (sigismember(sigset, SIGURG) << 5) + | (sigismember(sigset, SIGTSTP) << 4) + | (sigismember(sigset, SIGCHLD) << 3) + | (sigismember(sigset, SIGXFSZ) << 2) +#if !(defined SIG_STOP_FOR_GC && SIG_STOP_FOR_GC == SIGVTALRM) + | (sigismember(sigset, SIGVTALRM) << 1) +#endif +#if !(defined SIG_STOP_FOR_GC && SIG_STOP_FOR_GC == SIGWINCH) + | (sigismember(sigset, SIGWINCH) << 0) +#endif + ; + if (mask == expected_mask) return 1; + if (!mask) return 0; + char buf[3*64]; // assuming worst case 64 signals present in sigset + sigset_tostring(sigset, buf, sizeof buf); + lose("deferrable signals partially blocked: {%s}", buf); +#endif +} void check_deferrables_unblocked_or_lose(sigset_t *sigset) { -#if !defined(LISP_FEATURE_WIN32) || defined(LISP_FEATURE_SB_THREAD) if (deferrables_blocked_p(sigset)) lose("deferrables blocked"); -#endif } void check_deferrables_blocked_or_lose(sigset_t *sigset) { -#if !defined(LISP_FEATURE_WIN32) || defined(LISP_FEATURE_SB_THREAD) if (!deferrables_blocked_p(sigset)) lose("deferrables unblocked"); -#endif } -#if !defined(LISP_FEATURE_WIN32) || defined(LISP_FEATURE_SB_THREAD) -boolean -blockables_blocked_p(sigset_t *sigset) -{ - return all_signals_blocked_p(sigset, &blockable_sigset, "blockable"); -} +#ifdef LISP_FEATURE_RISCV +int sigaction_does_not_mask; #endif - -void -check_blockables_unblocked_or_lose(sigset_t *sigset) +static void assert_blockables_blocked() { -#if !defined(LISP_FEATURE_WIN32) || defined(LISP_FEATURE_SB_THREAD) - if (blockables_blocked_p(sigset)) - lose("blockables blocked"); +#ifdef LISP_FEATURE_RISCV + if (sigaction_does_not_mask) return; // assert nothing #endif -} - -void -check_blockables_blocked_or_lose(sigset_t *sigset) -{ #if !defined(LISP_FEATURE_WIN32) /* On Windows, there are no actual signals, but since the win32 port * tracks the sigmask and checks it explicitly, some functions are @@ -456,53 +575,52 @@ check_blockables_blocked_or_lose(sigset_t *sigset) * So we merely skip this assertion. * -- DFL, trying to expand on a comment by AK. */ - if (!blockables_blocked_p(sigset)) + sigset_t mask; + thread_sigmask(SIG_BLOCK, 0, &mask); + /* Test a representative bit from each set of signals of interest: + * (1) stop-for-GC + * (2) other blockable asynchronous signals + * (3) other blockable synchronous signals (SIGPIPE) + * If the representative bit is in the mask, say the whole set is. + * Since this is just a check of an invariant which correct execution + * will always adhere to, there is not much additional advantage to + * looking at all the signal bits, unlike the situation where the + * mask test is used as a predicate to decide on control flow. + */ + if (!( +#ifdef THREADS_USING_GCSIGNAL + sigismember(&mask, SIG_STOP_FOR_GC) && // (1) +#endif + sigismember(&mask, SIGHUP) && // (2) + sigismember(&mask, SIGPIPE))) // (3) lose("blockables unblocked"); #endif } #ifndef LISP_FEATURE_SB_SAFEPOINT -#if !defined(LISP_FEATURE_WIN32) -boolean -gc_signals_blocked_p(sigset_t *sigset) -{ - return all_signals_blocked_p(sigset, &gc_sigset, "gc"); -} -#endif - void check_gc_signals_unblocked_or_lose(sigset_t *sigset) { -#if !defined(LISP_FEATURE_WIN32) - if (gc_signals_blocked_p(sigset)) + sigset_t current; + if (!sigset) { + thread_sigmask(SIG_BLOCK, 0, ¤t); + sigset = ¤t; + } + if (sigismember(sigset, SIG_STOP_FOR_GC)) lose("gc signals blocked"); -#endif -} - -void -check_gc_signals_blocked_or_lose(sigset_t *sigset) -{ -#if !defined(LISP_FEATURE_WIN32) - if (!gc_signals_blocked_p(sigset)) - lose("gc signals unblocked"); -#endif } #endif void block_deferrable_signals(sigset_t *old) { -#if !defined(LISP_FEATURE_WIN32) || defined(LISP_FEATURE_SB_THREAD) thread_sigmask(SIG_BLOCK, &deferrable_sigset, old); -#endif } void block_blockable_signals(sigset_t *old) { -#if !defined(LISP_FEATURE_WIN32) || defined(LISP_FEATURE_SB_THREAD) thread_sigmask(SIG_BLOCK, &blockable_sigset, old); -#endif } // Do one of two things depending on whether the specified 'where' @@ -513,7 +631,6 @@ block_blockable_signals(sigset_t *old) void unblock_deferrable_signals(sigset_t *where) { -#if !defined(LISP_FEATURE_WIN32) || defined(LISP_FEATURE_SB_THREAD) if (interrupt_handler_pending_p()) lose("unblock_deferrable_signals: losing proposition"); #ifndef LISP_FEATURE_SB_SAFEPOINT @@ -521,11 +638,21 @@ unblock_deferrable_signals(sigset_t *where) // fetch the current signal mask (from the OS) and check that. check_gc_signals_unblocked_or_lose(where); #endif + sigset_t localmask, *sigset; + if (get_sb_vm_thread()->state_word.user_thread_p) { + sigset = &deferrable_sigset; + } else { + /* ASSUMPTION: system threads never want to receive SIGALRM. + * Actually, if we get here in the finalizer thread, things are + * in bad shape - stack exhaustion or something */ + localmask = deferrable_sigset; + sigdelset(&localmask, SIGALRM); + sigset = &localmask; + } if (where) - sigmask_logandc(where, &deferrable_sigset); + sigmask_logandc(where, sigset); else - thread_sigmask(SIG_UNBLOCK, &deferrable_sigset, 0); -#endif + thread_sigmask(SIG_UNBLOCK, sigset, 0); } #ifndef LISP_FEATURE_SB_SAFEPOINT @@ -539,28 +666,26 @@ void unblock_gc_signals(void) { void unblock_signals_in_context_and_maybe_warn(os_context_t *context) { -#if !defined(LISP_FEATURE_WIN32) || defined(LISP_FEATURE_SB_THREAD) sigset_t *sigset = os_context_sigmask_addr(context); #ifndef LISP_FEATURE_SB_SAFEPOINT - if (all_signals_blocked_p(sigset, &gc_sigset, "gc")) { + if (sigismember(sigset, SIG_STOP_FOR_GC)) { corruption_warning_and_maybe_lose( "Enabling blocked gc signals to allow returning to Lisp without risking\n\ gc deadlocks. Since GC signals are only blocked in signal handlers when \n\ they are not safe to interrupt at all, this is a pretty severe occurrence.\n"); - sigmask_logandc(sigset, &gc_sigset); + sigdelset(sigset, SIG_STOP_FOR_GC); } #endif if (!interrupt_handler_pending_p()) { unblock_deferrable_signals(sigset); } -#endif } inline static void check_interrupts_enabled_or_lose(os_context_t *context) { - __attribute__((unused)) struct thread *thread = arch_os_get_current_thread(); + __attribute__((unused)) struct thread *thread = get_sb_vm_thread(); if (read_TLS(INTERRUPTS_ENABLED,thread) == NIL) lose("interrupts not enabled"); if (arch_pseudo_atomic_atomic(context)) @@ -577,8 +702,8 @@ void maybe_save_gc_mask_and_block_deferrables(sigset_t *sigset) { #ifndef LISP_FEATURE_WIN32 - struct thread *thread = arch_os_get_current_thread(); - struct interrupt_data *data = thread->interrupt_data; + struct thread *thread = get_sb_vm_thread(); + struct interrupt_data *data = &thread_interrupt_data(thread); sigset_t oldset; /* Obviously, this function is called when signals may not be * blocked. Let's make sure we are not interrupted. */ @@ -591,7 +716,6 @@ maybe_save_gc_mask_and_block_deferrables(sigset_t *sigset) #endif if ((!data->pending_handler) && (!data->gc_blocked_deferrables)) { - FSHOW_SIGNAL((stderr,"/setting gc_blocked_deferrables\n")); data->gc_blocked_deferrables = 1; if (sigset) { /* This is the sigmask of some context. */ @@ -604,7 +728,7 @@ maybe_save_gc_mask_and_block_deferrables(sigset_t *sigset) * unblock gc signals. In the end, this is equivalent to * blocking the deferrables. */ sigcopyset(&data->pending_mask, &oldset); - thread_sigmask(SIG_UNBLOCK, &gc_sigset, 0); + unblock_gc_signals(); return; } } @@ -630,12 +754,11 @@ in_leaving_without_gcing_race_p(struct thread __attribute__((unused)) *thread) } /* Check our baroque invariants. */ -void +static void check_interrupt_context_or_lose(os_context_t *context) { -#if !defined(LISP_FEATURE_WIN32) || defined(LISP_FEATURE_SB_THREAD) - struct thread *thread = arch_os_get_current_thread(); - struct interrupt_data *data = thread->interrupt_data; + struct thread *thread = get_sb_vm_thread(); + struct interrupt_data *data = &thread_interrupt_data(thread); int interrupt_deferred_p = (data->pending_handler != 0); int interrupt_pending = (read_TLS(INTERRUPT_PENDING,thread) != NIL); sigset_t *sigset = os_context_sigmask_addr(context); @@ -644,7 +767,7 @@ check_interrupt_context_or_lose(os_context_t *context) #if defined(LISP_FEATURE_GENCGC) && !GENCGC_IS_PRECISE int interrupts_enabled = (read_TLS(INTERRUPTS_ENABLED,thread) != NIL); int gc_inhibit = (read_TLS(GC_INHIBIT,thread) != NIL); - int gc_pending = (read_TLS(GC_PENDING,thread) == T); + int gc_pending = (read_TLS(GC_PENDING,thread) == LISP_T); int pseudo_atomic_interrupted = get_pseudo_atomic_interrupted(thread); int in_race_p = in_leaving_without_gcing_race_p(thread); int safepoint_active = 0; @@ -705,13 +828,29 @@ check_interrupt_context_or_lose(os_context_t *context) check_gc_signals_unblocked_or_lose(sigset); #endif } -#endif } /* * utility routines used by various signal handlers */ +#ifdef LISP_FEATURE_ARM64 +static void +build_fake_control_stack_frames(struct thread __attribute__((unused)) *th, + os_context_t __attribute__((unused)) *context) +{ + + lispobj oldcont; + /* Ignore the two words above CSP, which can be used without adjusting CSP */ + lispobj* csp = (lispobj *)(uword_t) (*os_context_register_addr(context, reg_CSP)) + 2; + access_control_frame_pointer(th) = (lispobj *)(uword_t) csp; + + oldcont = (lispobj)(*os_context_register_addr(context, reg_CFP)); + access_control_frame_pointer(th)[1] = os_context_pc(context); + access_control_frame_pointer(th)[0] = oldcont; + access_control_stack_pointer(th) = csp + 2; +} +#else static void build_fake_control_stack_frames(struct thread __attribute__((unused)) *th, os_context_t __attribute__((unused)) *context) @@ -737,7 +876,11 @@ build_fake_control_stack_frames(struct thread __attribute__((unused)) *th, access_control_frame_pointer(th)[0] = *os_context_register_addr(context, reg_OCFP); access_control_frame_pointer(th)[1] = - *os_context_register_addr(context, reg_LRA); +#ifdef reg_LRA + *os_context_register_addr(context, reg_LRA); +#else + *os_context_register_addr(context, reg_RA); +#endif access_control_frame_pointer(th) += 2; /* Build our frame on top of it. */ oldcont = (lispobj)(*os_context_register_addr(context, reg_CFP)); @@ -749,11 +892,10 @@ build_fake_control_stack_frames(struct thread __attribute__((unused)) *th, } } else #elif defined (LISP_FEATURE_ARM) - access_control_frame_pointer(th) = (lispobj*) - SymbolValue(CONTROL_STACK_POINTER, th); + access_control_frame_pointer(th) = (lispobj*) SymbolValue(CONTROL_STACK_POINTER, th); #elif defined (LISP_FEATURE_ARM64) access_control_frame_pointer(th) = - (lispobj *)(uword_t) (*os_context_register_addr(context, reg_CSP)); + (lispobj *)(uword_t) (*os_context_register_addr(context, reg_CSP)) + 2; #endif /* We can't tell whether we are still in the caller if it had to * allocate a stack frame due to stack arguments. */ @@ -767,48 +909,28 @@ build_fake_control_stack_frames(struct thread __attribute__((unused)) *th, access_control_stack_pointer(th) = access_control_frame_pointer(th) + 3; access_control_frame_pointer(th)[0] = oldcont; +#ifdef reg_CODE access_control_frame_pointer(th)[1] = NIL; access_control_frame_pointer(th)[2] = (lispobj)(*os_context_register_addr(context, reg_CODE)); +#else + access_control_frame_pointer(th)[1] = os_context_pc(context); +#endif #endif } +#endif -/* Stores the context for gc to scavange and builds fake stack +/* Stores the context for gc to scavenge and builds fake stack * frames. */ -void -fake_foreign_function_call(os_context_t *context) +void fake_foreign_function_call_noassert(os_context_t *context) { int context_index; - struct thread *thread=arch_os_get_current_thread(); + struct thread *thread=get_sb_vm_thread(); - /* context_index incrementing must not be interrupted */ - check_blockables_blocked_or_lose(0); - -#ifdef reg_ALLOC -#ifdef LISP_FEATURE_SB_THREAD - thread->pseudo_atomic_bits = -#else - dynamic_space_free_pointer = - (lispobj *)(uword_t) -#endif - (*os_context_register_addr(context, reg_ALLOC)); -/* fprintf(stderr,"dynamic_space_free_pointer: %p\n", */ -/* dynamic_space_free_pointer); */ -#if defined(LISP_FEATURE_ALPHA) || defined(LISP_FEATURE_MIPS) - if ((sword_t)dynamic_space_free_pointer & 1) { - lose("dead in fake_foreign_function_call, context = %x", context); - } -#endif -/* why doesnt PPC and SPARC do something like this: */ -#if defined(LISP_FEATURE_HPPA) - if ((sword_t)dynamic_space_free_pointer & 4) { - lose("dead in fake_foreign_function_call, context = %x, d_s_f_p = %x", context, dynamic_space_free_pointer); - } -#endif -#endif #ifdef reg_BSP set_binding_stack_pointer(thread, - *os_context_register_addr(context, reg_BSP)); + // registers can be wider than uword_t (on some 64-bit machines compiling to 32-bit code) + (uword_t)*os_context_register_addr(context, reg_BSP)); #endif #if defined(LISP_FEATURE_ARM) @@ -818,30 +940,39 @@ fake_foreign_function_call(os_context_t *context) thread); #endif - build_fake_control_stack_frames(thread,context); - /* Do dynamic binding of the active interrupt context index * and save the context in the context array. */ context_index = fixnum_value(read_TLS(FREE_INTERRUPT_CONTEXT_INDEX,thread)); - if (context_index >= (MAX_INTERRUPTS-THREAD_HEADER_SLOTS)) { - lose("maximum interrupt nesting depth (%d) exceeded", - MAX_INTERRUPTS-THREAD_HEADER_SLOTS); - } + if (context_index >= MAX_INTERRUPTS) + lose("maximum interrupt nesting depth (%d) exceeded", MAX_INTERRUPTS); bind_variable(FREE_INTERRUPT_CONTEXT_INDEX, make_fixnum(context_index + 1),thread); nth_interrupt_context(context_index, thread) = context; -#if !defined(LISP_FEATURE_X86) && !defined(LISP_FEATURE_X86_64) + build_fake_control_stack_frames(thread, context); + +#if !defined(LISP_FEATURE_X86) && !defined(LISP_FEATURE_X86_64) && \ + !(defined(LISP_FEATURE_ARM64) && defined(LISP_FEATURE_SB_THREAD)) /* x86oid targets don't maintain the foreign function call flag at * all, so leave them to believe that they are never in foreign - * code. */ + * code. + + And ARM64 uses control_stack_pointer, which is set in + build_fake_control_stack_frames. */ + foreign_function_call_active_p(thread) = 1; #endif } +void fake_foreign_function_call(os_context_t *context) +{ + /* context_index incrementing must not be interrupted */ + assert_blockables_blocked(); + fake_foreign_function_call_noassert(context); +} /* blocks all blockable signals. If you are calling from a signal handler, * the usual signal mask will be restored from the context when the handler @@ -849,16 +980,14 @@ fake_foreign_function_call(os_context_t *context) void undo_fake_foreign_function_call(os_context_t __attribute__((unused)) *context) { - struct thread *thread=arch_os_get_current_thread(); + struct thread *thread=get_sb_vm_thread(); /* Block all blockable signals. */ block_blockable_signals(0); foreign_function_call_active_p(thread) = 0; -#ifdef LISP_FEATURE_SB_SAFEPOINT - /* garbage_collect_generation may access it in parallel after - FREE_INTERRUPT_CONTEXT_INDEX has been updated, stuff a zero to - keep it from being confused. */ +#ifdef LISP_FEATURE_SB_THREAD + // Never leave stale pointers in the signal context array nth_interrupt_context(fixnum_value(read_TLS(FREE_INTERRUPT_CONTEXT_INDEX,thread)) - 1, thread) = NULL; #endif /* Undo dynamic binding of FREE_INTERRUPT_CONTEXT_INDEX */ @@ -872,30 +1001,6 @@ undo_fake_foreign_function_call(os_context_t __attribute__((unused)) *context) thread); unbind(thread); #endif - -#if defined(reg_ALLOC) && !defined(LISP_FEATURE_SB_THREAD) - /* Put the dynamic space free pointer back into the context. */ - *os_context_register_addr(context, reg_ALLOC) = - (uword_t) dynamic_space_free_pointer - | (*os_context_register_addr(context, reg_ALLOC) - & LOWTAG_MASK); - /* - ((uword_t)(*os_context_register_addr(context, reg_ALLOC)) - & ~LOWTAG_MASK) - | ((uword_t) dynamic_space_free_pointer & LOWTAG_MASK); - */ -#endif -#if defined(reg_ALLOC) && defined(LISP_FEATURE_SB_THREAD) - /* Put the pseudo-atomic bits and dynamic space free pointer back - * into the context (p-a-bits for p-a, and dynamic space free - * pointer for ROOM). */ - *os_context_register_addr(context, reg_ALLOC) = - (uword_t) dynamic_space_free_pointer - | (thread->pseudo_atomic_bits & LOWTAG_MASK); - /* And clear them so we don't get bit later by call-in/call-out - * not updating them. */ - thread->pseudo_atomic_bits = 0; -#endif } /* a handler for the signal caused by execution of a trap opcode @@ -926,15 +1031,13 @@ interrupt_internal_error(os_context_t *context, boolean continuable) } #endif - SHOW("in interrupt_internal_error"); -#if QSHOW == 2 /* Display some rudimentary debugging information about the * error, so that even if the Lisp error handler gets badly * confused, we have a chance to determine what's going on. */ - describe_internal_error(context); -#endif + // describe_internal_error(context); // uncomment me for debugging + funcall2(StaticSymbolFunction(INTERNAL_ERROR), context_sap, - continuable ? T : NIL); + continuable ? LISP_T : NIL); undo_fake_foreign_function_call(context); /* blocks signals again */ if (continuable) @@ -944,14 +1047,16 @@ interrupt_internal_error(os_context_t *context, boolean continuable) boolean interrupt_handler_pending_p(void) { - struct thread *thread = arch_os_get_current_thread(); - struct interrupt_data *data = thread->interrupt_data; + struct interrupt_data *data = &thread_interrupt_data(get_sb_vm_thread()); return (data->pending_handler != 0); } void interrupt_handle_pending(os_context_t *context) { +#ifdef ADDRESS_SANITIZER + __asan_unpoison_memory_region(context, sizeof *context); +#endif /* There are three ways we can get here. First, if an interrupt * occurs within pseudo-atomic, it will be deferred, and we'll * trap to here at the end of the pseudo-atomic block. Second, if @@ -970,16 +1075,14 @@ interrupt_handle_pending(os_context_t *context) * It gets run precisely at those places where it is safe to process * pending asynchronous tasks. */ - struct thread *thread = arch_os_get_current_thread(); - struct interrupt_data *data = thread->interrupt_data; + struct thread *thread = get_sb_vm_thread(); + struct interrupt_data *data = &thread_interrupt_data(thread); if (arch_pseudo_atomic_atomic(context)) { lose("Handling pending interrupt in pseudo atomic."); } - FSHOW_SIGNAL((stderr, "/entering interrupt_handle_pending\n")); - - check_blockables_blocked_or_lose(0); + assert_blockables_blocked(); #ifndef LISP_FEATURE_SB_SAFEPOINT /* * (On safepoint builds, there is no gc_blocked_deferrables nor @@ -1003,9 +1106,7 @@ interrupt_handle_pending(os_context_t *context) * the os_context for the signal we're currently in the * handler for. This should ensure that when we return from * the handler the blocked signals are unblocked. */ -#ifndef LISP_FEATURE_WIN32 sigcopyset(os_context_sigmask_addr(context), &data->pending_mask); -#endif data->gc_blocked_deferrables = 0; } #endif @@ -1013,14 +1114,11 @@ interrupt_handle_pending(os_context_t *context) if (read_TLS(GC_INHIBIT,thread)==NIL) { void *original_pending_handler = data->pending_handler; -#if defined(LISP_FEATURE_SB_SAFEPOINT) && defined(LISP_FEATURE_SB_THREAD) +#ifdef LISP_FEATURE_SB_SAFEPOINT /* handles the STOP_FOR_GC_PENDING case, plus THRUPTIONS */ if (read_TLS(STOP_FOR_GC_PENDING,thread) != NIL -# ifdef LISP_FEATURE_SB_THRUPTION || (read_TLS(THRUPTION_PENDING,thread) != NIL - && read_TLS(INTERRUPTS_ENABLED, thread) != NIL) -# endif - ) { + && read_TLS(INTERRUPTS_ENABLED, thread) != NIL)) { /* We ought to take this chance to do a pitstop now. */ fake_foreign_function_call(context); thread_in_lisp_raised(context); @@ -1037,7 +1135,7 @@ interrupt_handle_pending(os_context_t *context) /* Test for T and not for != NIL since the value :IN-PROGRESS * used to be used in SUB-GC as part of the mechanism to * supress recursive gcs.*/ - if (read_TLS(GC_PENDING,thread) == T) { + if (read_TLS(GC_PENDING,thread) == LISP_T) { /* Two reasons for doing this. First, if there is a * pending handler we don't want to run. Second, we are @@ -1077,7 +1175,7 @@ interrupt_handle_pending(os_context_t *context) lose("Trapping to run pending handler while GC in progress."); } - check_blockables_blocked_or_lose(0); + assert_blockables_blocked(); /* No GC shall be lost. If SUB_GC triggers another GC then * that should be handled on the spot. */ @@ -1093,8 +1191,8 @@ interrupt_handle_pending(os_context_t *context) * an interrupt arrived during GC (POST-GC, really) it was * handled. */ if (original_pending_handler != data->pending_handler) - lose("pending handler changed in gc: %p -> %p.", - original_pending_handler, data->pending_handler); + lose("pending handler changed in gc: %p -> %p, signal = %d.", + original_pending_handler, data->pending_handler, data->pending_signal); } #ifndef LISP_FEATURE_WIN32 @@ -1112,8 +1210,8 @@ interrupt_handle_pending(os_context_t *context) sigcopyset(os_context_sigmask_addr(context), &data->pending_mask); run_deferred_handler(data, context); } -#ifdef LISP_FEATURE_SB_THRUPTION - if (read_TLS(THRUPTION_PENDING,thread)==T) +#ifdef LISP_FEATURE_SB_SAFEPOINT + if (read_TLS(THRUPTION_PENDING,thread)==LISP_T) /* Special case for the following situation: There is a * thruption pending, but a signal had been deferred. The * pitstop at the top of this function could only take care @@ -1129,9 +1227,8 @@ interrupt_handle_pending(os_context_t *context) lose("pseudo_atomic_interrupted after interrupt_handle_pending"); #endif /* It is possible that the end of this function was reached - * without never actually doing anything, the tests in Lisp for + * without actually doing anything, the tests in Lisp for * when to call receive-pending-interrupt are not exact. */ - FSHOW_SIGNAL((stderr, "/exiting interrupt_handle_pending\n")); } @@ -1139,88 +1236,51 @@ void interrupt_handle_now(int signal, siginfo_t *info, os_context_t *context) { boolean were_in_lisp; - union interrupt_handler handler; + lispobj handler = lisp_sig_handlers[signal]; + + if (!functionp(handler)) return; - check_blockables_blocked_or_lose(0); + assert_blockables_blocked(); -#if !defined(LISP_FEATURE_WIN32) || defined(LISP_FEATURE_SB_THREAD) if (sigismember(&deferrable_sigset,signal)) check_interrupts_enabled_or_lose(context); -#endif - - handler = interrupt_handlers[signal]; - - if (ARE_SAME_HANDLER(handler.c, SIG_IGN)) { - return; - } - were_in_lisp = !foreign_function_call_active_p(arch_os_get_current_thread()); + were_in_lisp = !foreign_function_call_active_p(get_sb_vm_thread()); if (were_in_lisp) { - fake_foreign_function_call(context); + // Use the variant of fake_ffc that doesn't do another pthread_sigmask syscall, + // as we've just asserted that signals are blocked. + fake_foreign_function_call_noassert(context); } - FSHOW_SIGNAL((stderr, - "/entering interrupt_handle_now(%d, info, context)\n", - signal)); - - if (ARE_SAME_HANDLER(handler.c, SIG_DFL)) { - - /* This can happen if someone tries to ignore or default one - * of the signals we need for runtime support, and the runtime - * support decides to pass on it. */ - lose("no handler for signal %d in interrupt_handle_now(..)", signal); - - // BUG: if a C function pointer can be misaligned such that it - // looks to satisfy functionp() then we do the wrong thing. - } else if (functionp(handler.lisp)) { /* Once we've decided what to do about contexts in a * return-elsewhere world (the original context will no longer * be available; should we copy it or was nobody using it anyway?) * then we should convert this to return-elsewhere */ -#ifndef LISP_FEATURE_SB_SAFEPOINT +#if !defined(LISP_FEATURE_SB_SAFEPOINT) && defined(LISP_FEATURE_C_STACK_IS_CONTROL_STACK) /* Leave deferrable signals blocked, the handler itself will * allow signals again when it sees fit. */ -#ifdef LISP_FEATURE_C_STACK_IS_CONTROL_STACK /* handler.lisp will hide from the GC, will be enabled in the handler itself. * Not a problem for the conservative GC. */ unblock_gc_signals(); #endif -#else + WITH_GC_AT_SAFEPOINTS_ONLY() -#endif { // the block is needed for WITH_GC_AT_SAFEPOINTS_ONLY() to work DX_ALLOC_SAP(context_sap, context); DX_ALLOC_SAP(info_sap, info); - FSHOW_SIGNAL((stderr,"/calling Lisp-level handler\n")); - - funcall3(handler.lisp, + funcall3(handler, make_fixnum(signal), info_sap, context_sap); } - } else { - /* This cannot happen in sane circumstances. */ - - FSHOW_SIGNAL((stderr,"/calling C-level handler\n")); - -#if !defined(LISP_FEATURE_WIN32) || defined(LISP_FEATURE_SB_THREAD) - /* Allow signals again. */ - thread_sigmask(SIG_SETMASK, os_context_sigmask_addr(context), 0); - (*handler.c)(signal, info, context); -#endif - } if (were_in_lisp) { undo_fake_foreign_function_call(context); /* block signals again */ } - - FSHOW_SIGNAL((stderr, - "/returning from interrupt_handle_now(%d, info, context)\n", - signal)); } /* This is called at the end of a critical section if the indications @@ -1239,26 +1299,73 @@ run_deferred_handler(struct interrupt_data *data, os_context_t *context) data->pending_handler; data->pending_handler=0; - FSHOW_SIGNAL((stderr, "/running deferred handler %p\n", pending_handler)); (*pending_handler)(data->pending_signal,&(data->pending_info), context); } #ifndef LISP_FEATURE_WIN32 -boolean -maybe_defer_handler(void *handler, struct interrupt_data *data, - int signal, siginfo_t *info, os_context_t *context) +static void +store_signal_data_for_later (struct interrupt_data *data, void *handler, + int signal, + siginfo_t *info, os_context_t *context) +{ + if (!context || !handler || data->pending_handler) + lose("can't defer signal: context=%p handler=%p pending=%p", + context, handler, data->pending_handler); + data->pending_handler = handler; + data->pending_signal = signal; + if (info) + memcpy(&data->pending_info, info, sizeof *info); + else + memset(&data->pending_info, 0, sizeof *info); + /* the signal mask in the context (from before we were + * interrupted) is copied to be restored when run_deferred_handler + * happens. Then the usually-blocked signals are added to the mask + * in the context so that we are running with blocked signals when + * the handler returns */ + sigcopyset(&data->pending_mask, os_context_sigmask_addr(context)); + sigaddset_deferrable(os_context_sigmask_addr(context)); +} + +/* What's going on ? + * + * 0: fp=0x7fa86423e7a0 pc=0x27608c Foreign function (null) + * 1: fp=0x7fa86423e7b0 pc=0x2767aa Foreign function (null) + * 2: fp=0x7fa86423e890 pc=0x2761af Foreign function (null) + * 3: fp=0x7fa86423e970 pc=0x27882f Foreign function (null) ; maybe_now_maybe_later + * 4: fp=0x7fa86423f5c0 pc=0x7fa8646bc750 Foreign function (null) ; WHICH SIGNAL ? + * 5: fp=0x7fa86423f630 pc=0x2713ce Foreign function (null) ; verify_range + * 6: fp=0x7fa86423f6c0 pc=0x2703d3 Foreign function (null) ; verify_heap + * 7: fp=0x7fa86423f780 pc=0x26e168 Foreign function collect_garbage + * 8: fp=0x7fa86423f7f0 pc=0x270298 Foreign function gc_and_save + * 9: fp=0x7fa86423f848 pc=0x52f93bf2 <??? type 45>::GC-AND-SAVE + * 10: fp=0x7fa86423f950 pc=0x52d32a7b <??? type 45>::SAVE-LISP-AND-DIE + * 11: fp=0x7fa86423fa00 pc=0x52a34179 <??? type 45>::SAVE-LISP-AND-DIE + * + * fatal error encountered in SBCL pid 9436 tid 9436: + * interrupt already pending + */ + +static boolean +can_handle_now(void *handler, struct interrupt_data *data, + int signal, siginfo_t *info, os_context_t *context) { - struct thread *thread=arch_os_get_current_thread(); +#ifdef DEBUG + // All this might prove is that you set sa_mask correctly when calling + // sigaction. That's not worth an extra system call. + assert_blockables_blocked(); +#endif - check_blockables_blocked_or_lose(0); + struct thread *thread = get_sb_vm_thread(); if (read_TLS(INTERRUPT_PENDING,thread) != NIL) - lose("interrupt already pending"); - if (thread->interrupt_data->pending_handler) + lose("interrupt already pending when sig%d received, pc=%p", signal, + (void*)os_context_pc(context)); + if (thread_interrupt_data(thread).pending_handler) lose("there is a pending handler already (PA)"); if (data->gc_blocked_deferrables) - lose("maybe_defer_handler: gc_blocked_deferrables true"); + lose("can_handle_now: gc_blocked_deferrables true"); + int answer = 1; /* If interrupts are disabled then INTERRUPT_PENDING is set and * not PSEDUO_ATOMIC_INTERRUPTED. This is important for a pseudo * atomic section inside a WITHOUT-INTERRUPTS. @@ -1269,99 +1376,42 @@ maybe_defer_handler(void *handler, struct interrupt_data *data, */ if ((read_TLS(INTERRUPTS_ENABLED,thread) == NIL) || in_leaving_without_gcing_race_p(thread)) { - FSHOW_SIGNAL((stderr, - "/maybe_defer_handler(%p,%d): deferred (RACE=%d)\n", - handler,signal, - in_leaving_without_gcing_race_p(thread))); + event3("can_handle_now(%p,%d): deferred (RACE=%d)", handler, signal, + in_leaving_without_gcing_race_p(thread)); store_signal_data_for_later(data,handler,signal,info,context); - write_TLS(INTERRUPT_PENDING, T,thread); - check_interrupt_context_or_lose(context); - return 1; + write_TLS(INTERRUPT_PENDING, LISP_T, thread); + answer = 0; } /* a slightly confusing test. arch_pseudo_atomic_atomic() doesn't * actually use its argument for anything on x86, so this branch * may succeed even when context is null (gencgc alloc()) */ - if (arch_pseudo_atomic_atomic(context)) { - FSHOW_SIGNAL((stderr, - "/maybe_defer_handler(%p,%d): deferred(PA)\n", - handler,signal)); + else if (arch_pseudo_atomic_atomic(context)) { + event2("can_handle_now(%p,%d): deferred (PA)", handler, signal); store_signal_data_for_later(data,handler,signal,info,context); arch_set_pseudo_atomic_interrupted(context); - check_interrupt_context_or_lose(context); - return 1; + answer = 0; } check_interrupt_context_or_lose(context); - FSHOW_SIGNAL((stderr, - "/maybe_defer_handler(%p,%d): not deferred\n", - handler,signal)); - return 0; -} - -static void -store_signal_data_for_later (struct interrupt_data *data, void *handler, - int signal, - siginfo_t *info, os_context_t *context) -{ - if (data->pending_handler) - lose("tried to overwrite pending interrupt handler %p with %p", - data->pending_handler, handler); - if (!handler) - lose("tried to defer null interrupt handler"); - data->pending_handler = handler; - data->pending_signal = signal; - if(info) - memcpy(&(data->pending_info), info, sizeof(siginfo_t)); - - FSHOW_SIGNAL((stderr, "/store_signal_data_for_later: signal: %d\n", - signal)); - - if(!context) - lose("Null context"); - - /* the signal mask in the context (from before we were - * interrupted) is copied to be restored when run_deferred_handler - * happens. Then the usually-blocked signals are added to the mask - * in the context so that we are running with blocked signals when - * the handler returns */ - sigcopyset(&(data->pending_mask),os_context_sigmask_addr(context)); - sigaddset_deferrable(os_context_sigmask_addr(context)); + return answer; } static void maybe_now_maybe_later(int signal, siginfo_t *info, void *void_context) { SAVE_ERRNO(signal,context,void_context); - struct thread *thread = arch_os_get_current_thread(); - struct interrupt_data *data = thread->interrupt_data; - if(!maybe_defer_handler(interrupt_handle_now,data,signal,info,context)) + struct thread *thread = get_sb_vm_thread(); + struct interrupt_data *data = &thread_interrupt_data(thread); + if (can_handle_now(interrupt_handle_now, data, signal, info, context)) interrupt_handle_now(signal, info, context); RESTORE_ERRNO; } +#endif -static void -low_level_interrupt_handle_now(int signal, siginfo_t *info, - os_context_t *context) -{ - /* No FP control fixage needed, caller has done that. */ - check_blockables_blocked_or_lose(0); - check_interrupts_enabled_or_lose(context); - (*interrupt_low_level_handlers[signal])(signal, info, context); -} - -static void -low_level_maybe_now_maybe_later(int signal, siginfo_t *info, void *void_context) -{ - SAVE_ERRNO(signal,context,void_context); - struct thread *thread = arch_os_get_current_thread(); - struct interrupt_data *data = thread->interrupt_data; - - if(!maybe_defer_handler(low_level_interrupt_handle_now,data, - signal,info,context)) - low_level_interrupt_handle_now(signal, info, context); - RESTORE_ERRNO; -} +#ifdef LISP_FEATURE_GC_METRICS +pthread_cond_t gcmetrics_condvar = PTHREAD_COND_INITIALIZER; +pthread_mutex_t gcmetrics_mutex = PTHREAD_MUTEX_INITIALIZER; #endif #ifdef THREADS_USING_GCSIGNAL @@ -1372,29 +1422,29 @@ sig_stop_for_gc_handler(int __attribute__((unused)) signal, siginfo_t __attribute__((unused)) *info, os_context_t *context) { - struct thread *thread=arch_os_get_current_thread(); + struct thread *thread=get_sb_vm_thread(); boolean was_in_lisp; /* Test for GC_INHIBIT _first_, else we'd trap on every single * pseudo atomic until gc is finally allowed. */ if (read_TLS(GC_INHIBIT,thread) != NIL) { - FSHOW_SIGNAL((stderr, "sig_stop_for_gc deferred (*GC-INHIBIT*)\n")); - write_TLS(STOP_FOR_GC_PENDING,T,thread); + event0("stop_for_gc deferred for *GC-INHIBIT*"); + write_TLS(STOP_FOR_GC_PENDING, LISP_T, thread); return; } else if (arch_pseudo_atomic_atomic(context)) { - FSHOW_SIGNAL((stderr,"sig_stop_for_gc deferred (PA)\n")); - write_TLS(STOP_FOR_GC_PENDING,T,thread); + event0("stop_for_gc deferred for PA"); + write_TLS(STOP_FOR_GC_PENDING, LISP_T, thread); arch_set_pseudo_atomic_interrupted(context); maybe_save_gc_mask_and_block_deferrables (os_context_sigmask_addr(context)); return; } - FSHOW_SIGNAL((stderr, "/sig_stop_for_gc_handler\n")); + event0("stop_for_gc"); /* Not PA and GC not inhibited -- we can stop now. */ - was_in_lisp = !foreign_function_call_active_p(arch_os_get_current_thread()); + was_in_lisp = !foreign_function_call_active_p(get_sb_vm_thread()); if (was_in_lisp) { /* need the context stored so it can have registers scavenged */ @@ -1414,23 +1464,26 @@ sig_stop_for_gc_handler(int __attribute__((unused)) signal, * pseudo_atomic_interrupted but without a pending interrupt or * GC. GC_BLOCKED_DEFERRABLES is also left at 1. So let's tidy it * up. */ - if (thread->interrupt_data->gc_blocked_deferrables) { - FSHOW_SIGNAL((stderr,"cleaning up after gc_blocked_deferrables\n")); + if (thread_interrupt_data(thread).gc_blocked_deferrables) { + event0("cleaning up after gc_blocked_deferrables"); clear_pseudo_atomic_interrupted(thread); - sigcopyset(os_context_sigmask_addr(context), - &thread->interrupt_data->pending_mask); - thread->interrupt_data->gc_blocked_deferrables = 0; + struct interrupt_data *interrupt_data = &thread_interrupt_data(thread); + sigcopyset(os_context_sigmask_addr(context), &interrupt_data->pending_mask); + interrupt_data->gc_blocked_deferrables = 0; } - if(thread_state(thread)!=STATE_RUNNING) { - // macOS warns if OBJ_FMTX is used to format a 'sword_t' - // which fixnum_value() returns. - lose("sig_stop_for_gc_handler: wrong thread state: %"OBJ_FMTX, - (lispobj)fixnum_value(thread->state)); - } + /* No need to use an atomic memory load here - this thead "owns" its state + * for now, and nobody else touches it, the sole exception being that GC + * sets it to RUNNING. The loads inside thread_wait_until_not() + * are slightly more interesting from that perspective */ + if (thread->state_word.state != STATE_RUNNING) + lose("stop_for_gc: bad thread state: %x", (int)thread->state_word.state); - set_thread_state(thread,STATE_STOPPED); - FSHOW_SIGNAL((stderr,"suspended\n")); + /* We say that the thread is "stopped" as of now, but the blocking operation + * occurs below at thread_wait_until_not(STATE_STOPPED). Note that sem_post() + * is expressly permitted in signal handlers, and set_thread_state uses it */ + set_thread_state(thread, STATE_STOPPED, 0); + event0("suspended"); /* While waiting for gc to finish occupy ourselves with zeroing * the unused portion of the control stack to reduce conservatism. @@ -1438,13 +1491,41 @@ sig_stop_for_gc_handler(int __attribute__((unused)) signal, * actually a must. */ scrub_control_stack(); - wait_for_thread_state_change(thread, STATE_STOPPED); - FSHOW_SIGNAL((stderr,"resumed\n")); + /* Now we wait on a semaphore, which, to be pedantic, is not specified as async-safe. + * Normally the way to implement a "suspend" operation is to issue any blocking + * syscall such as sigsuspend() or select(). Apparently every OS + C runtime that + * we wish to support has no problem with sem_wait() here in the signal handler. */ - if(thread_state(thread)!=STATE_RUNNING) { - lose("sig_stop_for_gc_handler: wrong thread state on wakeup: %"OBJ_FMTX, - (lispobj)fixnum_value(thread_state(thread))); +#ifdef LISP_FEATURE_GC_METRICS + int my_state; + { + struct timespec t_beginwait, t_endwait, t_runtime; + clock_gettime(CLOCK_MONOTONIC, &t_beginwait); + my_state = thread_wait_until_not(STATE_STOPPED, thread); + clock_gettime(CLOCK_MONOTONIC, &t_endwait); + clock_gettime(CLOCK_THREAD_CPUTIME_ID, &t_runtime); + // calculate CPU time in microseconds + long elapsed = ((t_endwait.tv_sec - t_beginwait.tv_sec)*1000000000L + + (t_endwait.tv_nsec - t_beginwait.tv_nsec)) / 1000; + struct extra_thread_data *data = thread_extra_data(thread); + if (elapsed > data->worst_gc_wait) data->worst_gc_wait = elapsed; + data->sum_gc_wait += elapsed; + data->avg_gc_wait = data->sum_gc_wait / ++data->n_gc_wait; + data->on_cpu_time = t_runtime.tv_sec * 1000000 + t_runtime.tv_nsec / 1000; + pthread_cond_broadcast(&gcmetrics_condvar); } +#else + int my_state = thread_wait_until_not(STATE_STOPPED, thread); +#endif + + event0("resumed"); + + /* The state can't go from STOPPED to DEAD because it's this thread is reading + * its own state, hence it must be running. + * (If we tried to observe a different thread, it could appear to change from + * STOPPED to DEAD, skipping RUNNING, because if you blink you might miss it) */ + if (my_state != STATE_RUNNING) + lose("stop_for_gc: bad state on wakeup: %x", my_state); if (was_in_lisp) { undo_fake_foreign_function_call(context); @@ -1464,7 +1545,7 @@ interrupt_handle_now_handler(int signal, siginfo_t *info, void *void_context) #endif ) corruption_warning_and_maybe_lose("Signal %d received (PC: %p)", signal, - *os_context_pc_addr(context)); + os_context_pc(context)); #endif interrupt_handle_now(signal, info, context); RESTORE_ERRNO; @@ -1476,21 +1557,19 @@ interrupt_handle_now_handler(int signal, siginfo_t *info, void *void_context) */ #if (defined(LISP_FEATURE_X86) || defined(LISP_FEATURE_X86_64)) -extern int *context_eflags_addr(os_context_t *context); +extern int *os_context_flags_addr(os_context_t *context); #endif extern lispobj call_into_lisp(lispobj fun, lispobj *args, int nargs); extern void post_signal_tramp(void); -extern void call_into_lisp_tramp(void); void arrange_return_to_c_function(os_context_t *context, call_into_lisp_lookalike funptr, lispobj function) { -#if !(defined(LISP_FEATURE_WIN32) || defined(LISP_FEATURE_SB_SAFEPOINT)) - check_gc_signals_unblocked_or_lose - (os_context_sigmask_addr(context)); +#ifndef LISP_FEATURE_SB_SAFEPOINT + check_gc_signals_unblocked_or_lose(os_context_sigmask_addr(context)); #endif #if !(defined(LISP_FEATURE_X86) || defined(LISP_FEATURE_X86_64)) void * fun=native_pointer(function); @@ -1539,17 +1618,13 @@ arrange_return_to_c_function(os_context_t *context, */ #ifndef LISP_FEATURE_DARWIN - u32 *sp=(u32 *)*os_context_register_addr(context,reg_ESP); + uint32_t *sp=(uint32_t *)*os_context_register_addr(context,reg_ESP); #endif #if defined(LISP_FEATURE_DARWIN) - u32 *register_save_area = (u32 *)os_allocate(0x40); - - FSHOW_SIGNAL((stderr, "/arrange_return_to_lisp_function: preparing to go to function %x, sp: %x\n", function, - *os_context_register_addr(context,reg_ESP))); - FSHOW_SIGNAL((stderr, "/arrange_return_to_lisp_function: context: %x, &context %x\n", context, &context)); + uint32_t *register_save_area = (uint32_t *)os_allocate(0x40); - /* 1. os_validate (malloc/mmap) register_save_block + /* 1. allocate (malloc/mmap) register_save_block * 2. copy register state into register_save_block * 3. put a pointer to register_save_block in a register in the context * 4. set the context's EIP to point to a trampoline which: @@ -1558,7 +1633,7 @@ arrange_return_to_c_function(os_context_t *context, * c. calls the function */ - *register_save_area = *os_context_pc_addr(context); + *register_save_area = os_context_pc(context); *(register_save_area + 1) = function; *(register_save_area + 2) = *os_context_register_addr(context,reg_EDI); *(register_save_area + 3) = *os_context_register_addr(context,reg_ESI); @@ -1566,16 +1641,15 @@ arrange_return_to_c_function(os_context_t *context, *(register_save_area + 5) = *os_context_register_addr(context,reg_ECX); *(register_save_area + 6) = *os_context_register_addr(context,reg_EBX); *(register_save_area + 7) = *os_context_register_addr(context,reg_EAX); - *(register_save_area + 8) = *context_eflags_addr(context); + *(register_save_area + 8) = *os_context_flags_addr(context); - *os_context_pc_addr(context) = - (os_context_register_t) funptr; + set_os_context_pc(context, (os_context_register_t) funptr); *os_context_register_addr(context,reg_ECX) = (os_context_register_t) register_save_area; #else /* return address for call_into_lisp: */ - *(sp-15) = (u32)post_signal_tramp; + *(sp-15) = (uint32_t)post_signal_tramp; *(sp-14) = function; /* args for call_into_lisp : function*/ *(sp-13) = 0; /* arg array */ *(sp-12) = 0; /* no. args */ @@ -1591,17 +1665,17 @@ arrange_return_to_c_function(os_context_t *context, *(sp-6)=*os_context_register_addr(context,reg_EDX); *(sp-5)=*os_context_register_addr(context,reg_ECX); *(sp-4)=*os_context_register_addr(context,reg_EAX); - *(sp-3)=*context_eflags_addr(context); + *(sp-3)=*os_context_flags_addr(context); *(sp-2)=*os_context_register_addr(context,reg_EBP); - *(sp-1)=*os_context_pc_addr(context); + *(sp-1)=os_context_pc(context); #endif #elif defined(LISP_FEATURE_X86_64) - u64 *sp=(u64 *)*os_context_register_addr(context,reg_RSP); + uword_t *sp=(uword_t *)*os_context_register_addr(context,reg_RSP); /* return address for call_into_lisp: */ - *(sp-18) = (u64)post_signal_tramp; + *(sp-18) = (uint64_t)post_signal_tramp; *(sp-17)=*os_context_register_addr(context,reg_R15); *(sp-16)=*os_context_register_addr(context,reg_R14); @@ -1618,23 +1692,23 @@ arrange_return_to_c_function(os_context_t *context, *(sp-6)=*os_context_register_addr(context,reg_RDX); *(sp-5)=*os_context_register_addr(context,reg_RCX); *(sp-4)=*os_context_register_addr(context,reg_RAX); - *(sp-3)=*context_eflags_addr(context); + *(sp-3)=*os_context_flags_addr(context); *(sp-2)=*os_context_register_addr(context,reg_RBP); - *(sp-1)=*os_context_pc_addr(context); + *(sp-1)=os_context_pc(context); *os_context_register_addr(context,reg_RDI) = (os_context_register_t)function; /* function */ *os_context_register_addr(context,reg_RSI) = 0; /* arg. array */ *os_context_register_addr(context,reg_RDX) = 0; /* no. args */ #else - struct thread *th=arch_os_get_current_thread(); + struct thread *th=get_sb_vm_thread(); build_fake_control_stack_frames(th,context); #endif #ifdef LISP_FEATURE_X86 #if !defined(LISP_FEATURE_DARWIN) - *os_context_pc_addr(context) = (os_context_register_t)funptr; + set_os_context_pc(context, (os_context_register_t)funptr); *os_context_register_addr(context,reg_ECX) = 0; *os_context_register_addr(context,reg_EBP) = (os_context_register_t)(sp-2); #ifdef __NetBSD__ @@ -1646,14 +1720,14 @@ arrange_return_to_c_function(os_context_t *context, #endif /* LISP_FEATURE_DARWIN */ #elif defined(LISP_FEATURE_X86_64) - *os_context_pc_addr(context) = (os_context_register_t)funptr; + set_os_context_pc(context, (os_context_register_t)funptr); *os_context_register_addr(context,reg_RCX) = 0; *os_context_register_addr(context,reg_RBP) = (os_context_register_t)(sp-2); *os_context_register_addr(context,reg_RSP) = (os_context_register_t)(sp-18); #else /* this much of the calling convention is common to all non-x86 ports */ - *os_context_pc_addr(context) = (os_context_register_t)(unsigned long)code; + set_os_context_pc(context, (os_context_register_t)(unsigned long)code); *os_context_register_addr(context,reg_NARGS) = 0; #ifdef reg_LIP *os_context_register_addr(context,reg_LIP) = @@ -1663,10 +1737,9 @@ arrange_return_to_c_function(os_context_t *context, (os_context_register_t)(unsigned long)access_control_frame_pointer(th); #endif #ifdef ARCH_HAS_NPC_REGISTER - *os_context_npc_addr(context) = - 4 + *os_context_pc_addr(context); + *os_context_npc_addr(context) = 4 + os_context_pc(context); #endif -#if defined(LISP_FEATURE_SPARC) || defined(LISP_FEATURE_ARM) || defined(LISP_FEATURE_ARM64) || defined(LISP_FEATURE_RISCV) +#if defined(LISP_FEATURE_SPARC) || defined(LISP_FEATURE_ARM) || defined(LISP_FEATURE_RISCV) *os_context_register_addr(context,reg_CODE) = (os_context_register_t)((char*)fun + FUN_POINTER_LOWTAG); #endif @@ -1677,13 +1750,7 @@ arrange_return_to_c_function(os_context_t *context, void arrange_return_to_lisp_function(os_context_t *context, lispobj function) { -#if defined(LISP_FEATURE_DARWIN) && defined(LISP_FEATURE_X86) - arrange_return_to_c_function(context, - (call_into_lisp_lookalike)call_into_lisp_tramp, - function); -#else arrange_return_to_c_function(context, call_into_lisp, function); -#endif } // These have undefined_alien_function tramp in x-assem.S @@ -1705,7 +1772,7 @@ void lower_thread_control_stack_guard_page(struct thread *th) { protect_control_stack_guard_page(0, th); protect_control_stack_return_guard_page(1, th); - th->control_stack_guard_page_protected = NIL; + th->state_word.control_stack_guard_page_protected = 0; fprintf(stderr, "INFO: Control stack guard page unprotected\n"); } @@ -1714,20 +1781,20 @@ void reset_thread_control_stack_guard_page(struct thread *th) memset(CONTROL_STACK_GUARD_PAGE(th), 0, os_vm_page_size); protect_control_stack_guard_page(1, th); protect_control_stack_return_guard_page(0, th); - th->control_stack_guard_page_protected = T; + th->state_word.control_stack_guard_page_protected = 1; fprintf(stderr, "INFO: Control stack guard page reprotected\n"); } boolean handle_guard_page_triggered(os_context_t *context,os_vm_address_t addr) { - struct thread *th=arch_os_get_current_thread(); + struct thread *th=get_sb_vm_thread(); if(addr >= CONTROL_STACK_HARD_GUARD_PAGE(th) && addr < CONTROL_STACK_HARD_GUARD_PAGE(th) + os_vm_page_size) { fake_foreign_function_call(context); lose("Control stack exhausted, fault: %p, PC: %p", - addr, (void*)*os_context_pc_addr(context)); + addr, (void*)os_context_pc(context)); } else if(addr >= CONTROL_STACK_GUARD_PAGE(th) && addr < CONTROL_STACK_GUARD_PAGE(th) + os_vm_page_size) { @@ -1738,19 +1805,19 @@ handle_guard_page_triggered(os_context_t *context,os_vm_address_t addr) if (gc_active_p) { fake_foreign_function_call(context); lose("Control stack exhausted with gc_active_p, fault: %p, PC: %p", - addr, (void*)*os_context_pc_addr(context)); + addr, (void*)os_context_pc(context)); } if (arch_pseudo_atomic_atomic(context)) { fake_foreign_function_call(context); lose("Control stack exhausted while pseudo-atomic, fault: %p, PC: %p", - addr, (void*)*os_context_pc_addr(context)); + addr, (void*)os_context_pc(context)); } if (lose_on_corruption_p) { fake_foreign_function_call(context); lose("Control stack exhausted, fault: %p, PC: %p", - addr, (void*)*os_context_pc_addr(context)); + addr, (void*)os_context_pc(context)); } - if (th->control_stack_guard_page_protected == NIL) + if (!th->state_word.control_stack_guard_page_protected) lose("control_stack_guard_page_protected NIL"); lower_thread_control_stack_guard_page(th); #ifdef LISP_FEATURE_C_STACK_IS_CONTROL_STACK @@ -1768,7 +1835,7 @@ handle_guard_page_triggered(os_context_t *context,os_vm_address_t addr) * unprotect this one. This works even if we somehow missed * the return-guard-page, and hit it on our way to new * exhaustion instead. */ - if (th->control_stack_guard_page_protected != NIL) + if (th->state_word.control_stack_guard_page_protected) lose("control_stack_guard_page_protected not NIL"); reset_thread_control_stack_guard_page(th); return 1; @@ -1841,95 +1908,12 @@ extern void restore_sbcl_signals () { int signal; for (signal = 0; signal < NSIG; signal++) { interrupt_handler_t handler = interrupt_low_level_handlers[signal]; - if (handler) { - undoably_install_low_level_interrupt_handler(signal, handler); + if ((void*)handler != (void*)SIG_DFL) { + ll_install_handler(signal, handler); } } } -#if defined(LISP_FEATURE_SB_SAFEPOINT_STRICTLY) && !defined(LISP_FEATURE_WIN32) - -static void * -signal_thread_trampoline(void *pthread_arg) -{ - intptr_t signo = (intptr_t) pthread_arg; - os_context_t fake_context; - siginfo_t fake_info; -#if defined LISP_FEATURE_PPC || defined LISP_FEATURE_PPC64 - mcontext_t uc_regs; -#endif - - memset(&fake_info, 0, sizeof(fake_info)); - memset(&fake_context, 0, sizeof(fake_context)); -#if defined LISP_FEATURE_PPC || defined LISP_FEATURE_PPC64 - memset(&uc_regs, 0, sizeof(uc_regs)); - fake_context.uc_mcontext.uc_regs = &uc_regs; -#endif - - *os_context_pc_addr(&fake_context) = (intptr_t) &signal_thread_trampoline; -#ifdef ARCH_HAS_STACK_POINTER /* aka x86(-64) */ - *os_context_sp_addr(&fake_context) = (intptr_t) __builtin_frame_address(0); -#endif - - signal_handler_callback(interrupt_handlers[signo].lisp, - signo, &fake_info, &fake_context); - return 0; -} - -static void -sigprof_handler_trampoline(int signal, siginfo_t *info, void *void_context) -{ - SAVE_ERRNO(signal,context,void_context); - struct thread *self = arch_os_get_current_thread(); - - /* alloc() is not re-entrant and still uses pseudo atomic (even though - * inline allocation does not). In this case, give up. */ - if (get_pseudo_atomic_atomic(self)) - goto cleanup; - - struct alloc_region tmp = self->alloc_region; - self->alloc_region = self->sprof_alloc_region; - self->sprof_alloc_region = tmp; - - interrupt_handle_now_handler(signal, info, void_context); - - /* And we're back. We know that the SIGPROF handler never unwinds - * non-locally, and can simply swap things back: */ - - tmp = self->alloc_region; - self->alloc_region = self->sprof_alloc_region; - self->sprof_alloc_region = tmp; - -cleanup: - ; /* Dear C compiler, it's OK to have a label here. */ - RESTORE_ERRNO; -} - -static void -spawn_signal_thread_handler(int signal, siginfo_t *info, void *void_context) -{ - SAVE_ERRNO(signal,context,void_context); - - pthread_attr_t attr; - pthread_t th; - - if (pthread_attr_init(&attr)) - goto lost; - if (pthread_attr_setstacksize(&attr, thread_control_stack_size)) - goto lost; - if (pthread_create(&th, &attr, &signal_thread_trampoline, (void*)(intptr_t) signal)) - goto lost; - if (pthread_attr_destroy(&attr)) - goto lost; - - RESTORE_ERRNO; - return; - -lost: - lose("spawn_signal_thread_handler"); -} -#endif - static void low_level_handle_now_handler(int signal, siginfo_t *info, void *void_context) { @@ -1938,121 +1922,94 @@ low_level_handle_now_handler(int signal, siginfo_t *info, void *void_context) RESTORE_ERRNO; } +/* Install a handler for a synchronous signal. These are predominantly + * SIG{SEGV, ILL, TRAP, FPE, ABRT}. Low-level handlers might or might not + * involve calling Lisp. + * As well there are two asynchronous signals installed via this function: + * - STOP_FOR_GC is low-level, but might defer the signal through + * an intricate bunch of decisions about the state of the world. + * - SIGURG without :SB-SAFEPOINT is a high-level (Lisp) handler, + * but with :SB-SAFEPOINT is low-level handler that uses different + * criteria for when to defer. */ void -undoably_install_low_level_interrupt_handler (int signal, - interrupt_handler_t handler) +ll_install_handler (int signal, interrupt_handler_t handler) { struct sigaction sa; - if (0 > signal || signal >= NSIG) { - lose("bad signal number %d", signal); - } - - if (ARE_SAME_HANDLER(handler, SIG_DFL)) - sa.sa_sigaction = (void (*)(int, siginfo_t*, void*))handler; - else if (sigismember(&deferrable_sigset,signal)) - sa.sa_sigaction = low_level_maybe_now_maybe_later; - else - sa.sa_sigaction = low_level_handle_now_handler; - -#ifdef LISP_FEATURE_SB_THRUPTION - /* It's in `deferrable_sigset' so that we block&unblock it properly, - * but we don't actually want to defer it. And if we put it only + if (0 > signal || signal >= NSIG +#ifdef LISP_FEATURE_SB_SAFEPOINT + /* SIGURG is in `deferrable_sigset' so that we block&unblock it properly, + * but we don't actually want to defer it, at least not here. + * (It might get deferred until a safepoint). And if we put it only * into blockable_sigset, we'd have to special-case it around thread * creation at least. */ - if (signal == SIGPIPE) - sa.sa_sigaction = low_level_handle_now_handler; + || (signal != SIGURG && sigismember(&deferrable_sigset,signal)) +#else + || sigismember(&deferrable_sigset,signal) #endif + || (void*)handler == (void*)SIG_DFL) + lose("ll_install_handler: bad args: sig=%d, fn=%p", signal, handler); + sa.sa_sigaction = low_level_handle_now_handler; sa.sa_mask = blockable_sigset; sa.sa_flags = SA_SIGINFO | SA_RESTART | OS_SA_NODEFER; -#if defined(LISP_FEATURE_C_STACK_IS_CONTROL_STACK) - if(signal==SIG_MEMORY_FAULT) { - sa.sa_flags |= SA_ONSTACK; -# ifdef LISP_FEATURE_SB_SAFEPOINT - sigaddset(&sa.sa_mask, SIGRTMIN); - sigaddset(&sa.sa_mask, SIGRTMIN+1); -# endif - } +#ifdef LISP_FEATURE_C_STACK_IS_CONTROL_STACK + if (signal==SIG_MEMORY_FAULT) sa.sa_flags |= SA_ONSTACK; #endif sigaction(signal, &sa, NULL); - interrupt_low_level_handlers[signal] = - (ARE_SAME_HANDLER(handler, SIG_DFL) ? 0 : handler); + interrupt_low_level_handlers[signal] = handler; } #endif +extern void sigprof_handler(int, siginfo_t*, void*); + /* This is called from Lisp. */ -uword_t -install_handler(int signal, void handler(int, siginfo_t*, os_context_t*), - lispobj ohandler, // (SIMPLE-VECTOR 1) as a tagged pointer - int __attribute__((unused)) synchronous) +void install_handler(int signal, lispobj handler) { #ifndef LISP_FEATURE_WIN32 struct sigaction sa; - sigset_t old; - - FSHOW((stderr, "/entering POSIX install_handler(%d, ..)\n", signal)); - - block_blockable_signals(&old); - - FSHOW((stderr, "/interrupt_low_level_handlers[signal]=%p\n", - interrupt_low_level_handlers[signal])); - if (interrupt_low_level_handlers[signal]==0) { - if (handler == 0) - sa.sa_sigaction = (void (*)(int, siginfo_t*, void*))SIG_DFL; - else if ((lispobj)handler == 1) - sa.sa_sigaction = (void (*)(int, siginfo_t*, void*))SIG_IGN; -#ifdef LISP_FEATURE_SB_SAFEPOINT_STRICTLY - else if (signal == SIGPROF) - sa.sa_sigaction = sigprof_handler_trampoline; - else if (!synchronous) - sa.sa_sigaction = spawn_signal_thread_handler; -#endif - else if (sigismember(&deferrable_sigset, signal)) + memset(&sa, 0, sizeof sa); + + if (interrupt_low_level_handlers[signal]) { + // When there's a low-level handler, we must leave it alone. + // Give it the lisp function to call if it decides to forward a signal. + // SIG_IGN and SIG_DFL don't always do what you think in such case. + lisp_sig_handlers[signal] = functionp(handler) ? handler : 0; + } else if (signal == SIGPROF) { + if (handler) sa.sa_sigaction = sigprof_handler; + else sa.sa_handler = SIG_DFL; + // The handler is signal-safe, but because it uses component_ptr_from_pc(), + // it must block GC, lest crashes occur from dereferencing wild pointers. + sa.sa_mask = blockable_sigset; + sa.sa_flags = SA_SIGINFO | SA_RESTART; + sigaction(signal, &sa, NULL); + return; + } else { + // Our "abstract" values for SIG_DFL and SIG_IGN are 0 and 1 + // respectively which are probably the real values from signal.h + // but this way way don't need to put them in grovel-headers.c + if (handler==0 || handler==1) { + sa.sa_handler = handler ? SIG_IGN : SIG_DFL; + // assign the OS level action before clearing the lisp function. + // (If a signal were to be delivered to the C trampoline when the lisp + // function is NIL, we'd get the effect of :IGNORE regardless + // of what the default action should be) + sigaction(signal, &sa, NULL); + lisp_sig_handlers[signal] = 0; + return; + } + if (sigismember(&deferrable_sigset, signal)) sa.sa_sigaction = maybe_now_maybe_later; else sa.sa_sigaction = interrupt_handle_now_handler; sa.sa_mask = blockable_sigset; sa.sa_flags = SA_SIGINFO | SA_RESTART | OS_SA_NODEFER; + // ensure the C handler sees a lisp function before doing sigaction() + lisp_sig_handlers[signal] = handler; sigaction(signal, &sa, NULL); } - - // We can GC-safely read interrupt_low_level_handlers[signal] and assign - // into ohandler despite that the C stack and registers are not roots on - // precise GC. That is, if GC were to occur as depicted: - // obj = old_handler - // -- GC signal occurs here -- - // result = obj - // then the register or stack word holding 'obj' could be obsolete. - // But that won't happen- the STOP_FOR_GC signal is currently blocked - // due to the block_blockable_signals() at the top of this function. - // However, there is an unlikely other reason for a wrong result - - // if the C function address does not have at least N_FIXNUM_TAG_BITS - // of alignment, then we say that it was NIL instead of a fixnum. - lispobj obj = interrupt_handlers[signal].lisp; - uword_t result = -1; - if ((void*)obj == (void*)SIG_DFL) - result = 0; - else if ((void*)obj == (void*)SIG_IGN) - result = 1; - else if (ohandler) // only store into 'ohandler' when it was supplied - VECTOR(ohandler)->data[0] = (functionp(obj)||fixnump(obj)) ? obj : NIL; - - interrupt_handlers[signal].c = handler; - - thread_sigmask(SIG_SETMASK, &old, 0); - - FSHOW((stderr, "/leaving POSIX install_handler(%d, ..)\n", signal)); - - // After the thread's signal mask is restored to the mask in 'old', - // it is not possible to GC-safely refer to a Lisp function from C code, - // which is to say, naively utilizing "return obj;" would be wrong. - return result; -#else - /* Probably-wrong Win32 hack */ - return 0; #endif } @@ -2072,31 +2029,40 @@ sigabrt_handler(int __attribute__((unused)) signal, void interrupt_init(void) { -#if !defined(LISP_FEATURE_WIN32) || defined(LISP_FEATURE_SB_THREAD) - int i; - SHOW("entering interrupt_init()"); +#ifdef ATOMIC_LOGGING + // If fetch_and_add gives us an index that is less than EVENTBUFMAX, + // we assume that there is room to record an event with up to 8 arguments + // which means the prefix, the format string, and the arguments. + eventdata = calloc(EVENTBUFMAX+10, N_WORD_BYTES); + void sigdump_eventlog(int, siginfo_t*, os_context_t*); + // pick anything not used. SIGPWR is also a good choice + ll_install_handler(SIGINFO, sigdump_eventlog); +#endif + int __attribute__((unused)) i; sigemptyset(&deferrable_sigset); sigemptyset(&blockable_sigset); sigemptyset(&gc_sigset); sigaddset_deferrable(&deferrable_sigset); sigaddset_blockable(&blockable_sigset); sigaddset_gc(&gc_sigset); + + sigaddset_deferrable(&thread_start_sigset); + /* sigprof_handler may interrupt a thread that doesn't have + current_thread set up yet, which can be a thread-local variable, + and sigprof_handler will try to allocate it, but thread-local + initialization is not guaranteed to be async safe. */ + sigaddset(&thread_start_sigset, SIGPROF); + + +#ifdef LISP_FEATURE_BACKTRACE_ON_SIGNAL + // Use this only if you know what you're doing + void backtrace_lisp_threads(int, siginfo_t*, os_context_t*); + ll_install_handler(SIGXCPU, backtrace_lisp_threads); #endif #ifndef LISP_FEATURE_WIN32 - /* Set up high level handler information. */ - for (i = 0; i < NSIG; i++) { - interrupt_handlers[i].c = - /* (The cast here blasts away the distinction between - * SA_SIGACTION-style three-argument handlers and - * signal(..)-style one-argument handlers, which is OK - * because it works to call the 1-argument form where the - * 3-argument form is expected.) */ - (void (*)(int, siginfo_t*, os_context_t*))SIG_DFL; - } - undoably_install_low_level_interrupt_handler(SIGABRT, sigabrt_handler); + ll_install_handler(SIGABRT, sigabrt_handler); #endif - SHOW("returning from interrupt_init()"); } #ifndef LISP_FEATURE_WIN32 @@ -2112,26 +2078,31 @@ lisp_memory_fault_error(os_context_t *context, os_vm_address_t addr) /* If we lose on corruption, provide LDB with debugging information. */ fake_foreign_function_call(context); + /* If it's a store to read-only space, it's not "corruption", so don't say that. + * Lisp will change its wording of the memory-fault-error string */ + + if (!readonly_space_p((uword_t)addr)) { /* To allow debugging memory faults in signal handlers and such. */ #ifdef ARCH_HAS_STACK_POINTER - char* pc = (char*)*os_context_pc_addr(context); + char* pc = (char*)os_context_pc(context); struct code* code = (struct code*)component_ptr_from_pc(pc); unsigned int offset = code ? pc - (char*)code : 0; if (offset) corruption_warning_and_maybe_lose( - "Memory fault at %p (pc=%p [code %p+0x%X ID 0x%x], fp=%p, sp=%p) tid %#lx", + "Memory fault at %p (pc=%p [code %p+0x%X ID 0x%x], fp=%p, sp=%p)" THREAD_ID_LABEL, addr, pc, code, offset, code_serialno(code), os_context_frame_pointer(context), - *os_context_sp_addr(context), thread_self()); // = 0 if -sb-thread + *os_context_sp_addr(context), THREAD_ID_VALUE); else corruption_warning_and_maybe_lose( - "Memory fault at %p (pc=%p, fp=%p, sp=%p) tid %#lx", + "Memory fault at %p (pc=%p, fp=%p, sp=%p)" THREAD_ID_LABEL, addr, pc, os_context_frame_pointer(context), - *os_context_sp_addr(context), thread_self()); // = 0 if -sb-thread + *os_context_sp_addr(context), THREAD_ID_VALUE); #else corruption_warning_and_maybe_lose("Memory fault at %p (pc=%p)", - addr, *os_context_pc_addr(context)); + addr, (void*)os_context_pc(context)); #endif + } #ifdef LISP_FEATURE_C_STACK_IS_CONTROL_STACK /* Holy hell is this more obfuscated than necessary when using @@ -2160,7 +2131,7 @@ lisp_memory_fault_error(os_context_t *context, os_vm_address_t addr) extern void memory_fault_emulation_trap(void); undo_fake_foreign_function_call(context); void **sp = (void **)*os_context_sp_addr(context); - *--sp = (void *)*os_context_pc_addr(context); + *--sp = (void *)os_context_pc(context); *--sp = addr; # ifdef LISP_FEATURE_X86 /* KLUDGE: x86-linux sp_addr doesn't affect the CPU on return */ @@ -2168,8 +2139,7 @@ lisp_memory_fault_error(os_context_t *context, os_vm_address_t addr) # else *((void **)os_context_sp_addr(context)) = sp; # endif - *os_context_pc_addr(context) = - (os_context_register_t)memory_fault_emulation_trap; + set_os_context_pc(context, (os_context_register_t)memory_fault_emulation_trap); /* We exit here, letting the signal handler return, picking up at * memory_fault_emulation_trap (in target-assem.S), which will * trap, and the handler calls the function below, where we @@ -2182,7 +2152,7 @@ handle_memory_fault_emulation_trap(os_context_t *context) { void **sp = (void **)*os_context_sp_addr(context); void *addr = *sp++; - *os_context_pc_addr(context) = (os_context_register_t)*sp++; + set_os_context_pc(context, (os_context_register_t)*sp++); # ifdef LISP_FEATURE_X86 /* KLUDGE: x86-linux sp_addr doesn't affect the CPU on return */ *((void **)os_context_register_addr(context, reg_ESP)) = sp; @@ -2226,7 +2196,7 @@ handle_trap(os_context_t *context, int trap) trap = trap_Error; } switch(trap) { -#if !(defined(LISP_FEATURE_WIN32) && defined(LISP_FEATURE_SB_THREAD)) +#ifndef LISP_FEATURE_WIN32 case trap_PendingInterrupt: FSHOW((stderr, "/<trap pending interrupt>\n")); arch_skip_instruction(context); @@ -2278,11 +2248,6 @@ handle_trap(os_context_t *context, int trap) arch_skip_instruction(context); break; #endif -#if defined(LISP_FEATURE_SPARC) && defined(LISP_FEATURE_GENCGC) - case trap_Allocation: - arch_handle_allocation_trap(context); - break; -#endif #if defined(LISP_FEATURE_C_STACK_IS_CONTROL_STACK) && !defined(LISP_FEATURE_WIN32) case trap_MemoryFaultEmulation: handle_memory_fault_emulation_trap(context); @@ -2295,3 +2260,28 @@ handle_trap(os_context_t *context, int trap) unhandled_trap_error(context); } } + +#ifndef LISP_FEATURE_WIN32 +// Return 1 if the signal was previously in the blocked set. +int sb_toggle_sigprof(os_context_t* context, int block) { + if (context) { + // This case is used with INTERRUPT-THREAD to unmask SIGPROF in any thread + // other than the current thread. + gc_assert(!block); + // Alter the mask on return from the _outermost_ signal context, which + // should usually be the supplied context, but not if nesting happened. + context = nth_interrupt_context(0, get_sb_vm_thread()); + gc_assert(context); + sigset_t *mask = os_context_sigmask_addr(context); + int was_blocked = sigismember(mask, SIGPROF); + if (block) sigaddset(mask, SIGPROF); else sigdelset(mask, SIGPROF); + return was_blocked; + } else { + sigset_t sigset, old; + sigemptyset(&sigset); + sigaddset(&sigset, SIGPROF); + thread_sigmask(block ? SIG_BLOCK : SIG_UNBLOCK, &sigset, &old); + return sigismember(&old, SIGPROF); + } +} +#endif diff --git a/src/runtime/interrupt.h b/src/runtime/interrupt.h index 5407bd4977..d60f715463 100644 --- a/src/runtime/interrupt.h +++ b/src/runtime/interrupt.h @@ -16,36 +16,28 @@ #include <string.h> #include "genesis/static-symbols.h" -extern void get_current_sigmask(sigset_t *sigset); +extern void sigset_tostring(const sigset_t *sigset, char* result, int result_length); -/* Set all deferrable signals into *s. */ -extern void sigaddset_deferrable(sigset_t *s); /* Set all blockable signals into *s. */ extern void sigaddset_blockable(sigset_t *s); -/* Set all gc signals into *s. */ -extern void sigaddset_gc(sigset_t *s); extern sigset_t deferrable_sigset; extern sigset_t blockable_sigset; extern sigset_t gc_sigset; +extern sigset_t thread_start_sigset; extern boolean deferrables_blocked_p(sigset_t *sigset); -extern boolean blockables_blocked_p(sigset_t *sigset); -extern boolean gc_signals_blocked_p(sigset_t *sigset); extern void check_deferrables_blocked_or_lose(sigset_t *sigset); -extern void check_blockables_blocked_or_lose(sigset_t *sigset); -extern void check_gc_signals_blocked_or_lose(sigset_t *sigset); extern void check_deferrables_unblocked_or_lose(sigset_t *sigset); -extern void check_blockables_unblocked_or_lose(sigset_t *sigset); extern void check_gc_signals_unblocked_or_lose(sigset_t *sigset); extern void block_deferrable_signals(sigset_t *old); extern void block_blockable_signals(sigset_t *old); extern void unblock_deferrable_signals(sigset_t *where); -extern void unblock_gc_signals(); +extern void unblock_gc_signals(void); extern void maybe_save_gc_mask_and_block_deferrables(sigset_t *sigset); @@ -74,12 +66,7 @@ extern void maybe_save_gc_mask_and_block_deferrables(sigset_t *sigset); * * -- NS 2007-01-29 */ -union interrupt_handler { - lispobj lisp; - void (*c)(int, siginfo_t*, os_context_t*); -}; - -extern union interrupt_handler interrupt_handlers[NSIG]; +extern lispobj lisp_sig_handlers[NSIG]; struct interrupt_data { /* signal information for pending signal. pending_signal=0 when there @@ -93,13 +80,17 @@ struct interrupt_data { * and with no pending handler. Both deferrable interrupt handlers * and gc are careful not to clobber each other's pending_mask. */ boolean gc_blocked_deferrables; -#if GENCGC_IS_PRECISE - /* On PPC when consing wants to turn to alloc(), it does so via a +#if defined LISP_FEATURE_MIPS || defined LISP_FEATURE_PPC \ + || defined LISP_FEATURE_PPC64 || defined LISP_FEATURE_SPARC +#define HAVE_ALLOCATION_TRAP_CONTEXT 1 + /* On these archs, when consing wants to turn to alloc(), it does so via a * trap. When alloc() wants to save the sigmask it consults * allocation_trap_context. It does not look up the most recent * context, because alloc() can be called from other places * too. */ os_context_t *allocation_trap_context; +#else +#define HAVE_ALLOCATION_TRAP_CONTEXT 0 #endif }; @@ -117,9 +108,6 @@ extern void interrupt_handle_now(int, siginfo_t*, os_context_t*); extern void interrupt_handle_pending(os_context_t*); extern void interrupt_internal_error(os_context_t*, boolean continuable); extern boolean handle_guard_page_triggered(os_context_t *,os_vm_address_t); -extern boolean maybe_defer_handler(void *handler, struct interrupt_data *data, - int signal, siginfo_t *info, - os_context_t *context); #ifdef DO_PENDING_INTERRUPT #define do_pending_interrupt ((void(*)(void))SYMBOL(DO_PENDING_INTERRUPT)->value) @@ -132,13 +120,7 @@ extern void do_pending_interrupt(void); extern void sig_stop_for_gc_handler(int, siginfo_t*, os_context_t*); #endif typedef void (*interrupt_handler_t)(int, siginfo_t *, os_context_t *); -extern void undoably_install_low_level_interrupt_handler ( - int signal, - interrupt_handler_t handler); -extern uword_t install_handler(int signal, - interrupt_handler_t handler, - lispobj ohandler, - int synchronous); +extern void ll_install_handler(int signal, interrupt_handler_t handler); /* The void* casting here avoids having to mess with the various types * of function argument lists possible for signal handlers: @@ -160,7 +142,7 @@ extern void lower_thread_control_stack_guard_page(struct thread *th); extern void reset_thread_control_stack_guard_page(struct thread *th); #if defined(LISP_FEATURE_SB_SAFEPOINT) && !defined(LISP_FEATURE_WIN32) -# ifdef LISP_FEATURE_SB_THRUPTION +# ifdef LISP_FEATURE_SB_SAFEPOINT void thruption_handler(int signal, siginfo_t *info, os_context_t *context); # endif #endif diff --git a/src/runtime/ld-script.alpha-linux b/src/runtime/ld-script.alpha-linux deleted file mode 100644 index 21551ca017..0000000000 --- a/src/runtime/ld-script.alpha-linux +++ /dev/null @@ -1,163 +0,0 @@ -/* This script allegedly has the same effect as -taso would do on Digital - * Unix - that is, it forces stuff into the low 2Gb where 32-bit pointers - * can find it */ - -/* - * This software is part of the SBCL system. See the README file for - * more information. - * - * This software is derived from the CMU CL system, which was - * written at Carnegie Mellon University and released into the - * public domain. The software is in the public domain and is - * provided with absolutely no warranty. See the COPYING and CREDITS - * files for more information. - */ - -OUTPUT_FORMAT("elf64-alpha", "elf64-alpha", - "elf64-alpha") -OUTPUT_ARCH(alpha) -ENTRY(__start) -SEARCH_DIR(/lib); SEARCH_DIR(/usr/lib); SEARCH_DIR(/usr/local/lib); SEARCH_DIR(/usr/alpha-linux/lib); -/* Do we need any of these for elf? - __DYNAMIC = 0; */ -SECTIONS -{ - /* Read-only sections, merged into text segment: */ - . = 0x08048000 + SIZEOF_HEADERS; - .interp : { *(.interp) } - .hash : { *(.hash) } - .dynsym : { *(.dynsym) } - .dynstr : { *(.dynstr) } - .gnu.version : { *(.gnu.version) } - .gnu.version_d : { *(.gnu.version_d) } - .gnu.version_r : { *(.gnu.version_r) } - .rel.text : - { *(.rel.text) *(.rel.gnu.linkonce.t*) } - .rela.text : - { *(.rela.text) *(.rela.gnu.linkonce.t*) } - .rel.data : - { *(.rel.data) *(.rel.gnu.linkonce.d*) } - .rela.data : - { *(.rela.data) *(.rela.gnu.linkonce.d*) } - .rel.rodata : - { *(.rel.rodata) *(.rel.gnu.linkonce.r*) } - .rela.rodata : - { *(.rela.rodata) *(.rela.gnu.linkonce.r*) } - .rel.got : { *(.rel.got) } - .rela.got : { *(.rela.got) } - .rel.ctors : { *(.rel.ctors) } - .rela.ctors : { *(.rela.ctors) } - .rel.dtors : { *(.rel.dtors) } - .rela.dtors : { *(.rela.dtors) } - .rel.init : { *(.rel.init) } - .rela.init : { *(.rela.init) } - .rel.fini : { *(.rel.fini) } - .rela.fini : { *(.rela.fini) } - .rel.bss : { *(.rel.bss) } - .rela.bss : { *(.rela.bss) } - .rel.plt : { *(.rel.plt) } - .rela.plt : { *(.rela.plt) } - .init : { *(.init) } =0x47ff041f - .text : - { - *(.text) - *(.stub) - /* .gnu.warning sections are handled specially by elf32.em. */ - *(.gnu.warning) - *(.gnu.linkonce.t*) - } =0x47ff041f - _etext = .; - PROVIDE (etext = .); - .fini : { *(.fini) } =0x47ff041f - .preinit_array : { - __preinit_array_start = .; - *(.preinit_array) - __preinit_array_end = .; - } - .init_array : { - __init_array_start = .; - *(.init_array) - __init_array_end = .; - } - .fini_array : { - __fini_array_start = .; - *(.fini_array) - __fini_array_end = .; - } - .rodata : { *(.rodata) *(.gnu.linkonce.r*) } - .rodata1 : { *(.rodata1) } - .reginfo : { *(.reginfo) } - /* Adjust the address for the data segment. We want to adjust up to - the same address within the page on the next page up. */ - . = ALIGN(0x100000) + (. & (0x100000 - 1)); - .data : - { - *(.data) - *(.gnu.linkonce.d*) - CONSTRUCTORS - } - .data1 : { *(.data1) } - .ctors : - { - *(.ctors) - } - .dtors : - { - *(.dtors) - } - .plt : { *(.plt) } - .got : { *(.got.plt) *(.got) } - .dynamic : { *(.dynamic) } - /* We want the small data sections together, so single-instruction offsets - can access them all, and initialized data all before uninitialized, so - we can shorten the on-disk segment size. */ - .sdata : { *(.sdata) } - _edata = .; - PROVIDE (edata = .); - __bss_start = .; - .sbss : { *(.sbss) *(.scommon) } - .bss : - { - *(.dynbss) - *(.bss) - *(COMMON) - } - . = ALIGN(64 / 8); - _end = . ; - PROVIDE (end = .); - /* Stabs debugging sections. */ - .stab 0 : { *(.stab) } - .stabstr 0 : { *(.stabstr) } - .stab.excl 0 : { *(.stab.excl) } - .stab.exclstr 0 : { *(.stab.exclstr) } - .stab.index 0 : { *(.stab.index) } - .stab.indexstr 0 : { *(.stab.indexstr) } - .comment 0 : { *(.comment) } - /* DWARF debug sections. - Symbols in the DWARF debugging sections are relative to the beginning - of the section so we begin them at 0. */ - /* DWARF 1 */ - .debug 0 : { *(.debug) } - .line 0 : { *(.line) } - /* GNU DWARF 1 extensions */ - .debug_srcinfo 0 : { *(.debug_srcinfo) } - .debug_sfnames 0 : { *(.debug_sfnames) } - /* DWARF 1.1 and DWARF 2 */ - .debug_aranges 0 : { *(.debug_aranges) } - .debug_pubnames 0 : { *(.debug_pubnames) } - /* DWARF 2 */ - .debug_info 0 : { *(.debug_info) } - .debug_abbrev 0 : { *(.debug_abbrev) } - .debug_line 0 : { *(.debug_line) } - .debug_frame 0 : { *(.debug_frame) } - .debug_str 0 : { *(.debug_str) } - .debug_loc 0 : { *(.debug_loc) } - .debug_macinfo 0 : { *(.debug_macinfo) } - /* SGI/MIPS DWARF 2 extensions */ - .debug_weaknames 0 : { *(.debug_weaknames) } - .debug_funcnames 0 : { *(.debug_funcnames) } - .debug_typenames 0 : { *(.debug_typenames) } - .debug_varnames 0 : { *(.debug_varnames) } - /* These must appear regardless of . */ -} - diff --git a/src/runtime/linux-mman.c b/src/runtime/linux-mman.c index 5b35124a0c..3248d469c2 100644 --- a/src/runtime/linux-mman.c +++ b/src/runtime/linux-mman.c @@ -7,43 +7,28 @@ #include "globals.h" #include "os.h" #include "interr.h" - -#ifdef LISP_FEATURE_ALPHA -/* The Alpha is a 64 bit CPU. SBCL is a 32 bit application. Due to all - * the places that assume we can get a pointer into a fixnum with no - * information loss, we have to make sure it allocates all its ram in the - * 0-2Gb region. */ - -static void * under_2gb_free_pointer; -os_set_cheneygc_spaces(uword_t space0_start, uword_t space1_start) -{ - uword_t max; - max = (space1_start > space0_start) ? space1_start : space0_start; - under_2gb_free_pointer = max + dynamic_space_size; -} - -#endif +#include "sys_mmap.inc" os_vm_address_t -os_validate(int attributes, os_vm_address_t addr, os_vm_size_t len) +os_alloc_gc_space(int __attribute__((unused)) space_id, + int attributes, os_vm_address_t addr, os_vm_size_t len) { int protection = attributes & IS_GUARD_PAGE ? OS_VM_PROT_NONE : OS_VM_PROT_ALL; attributes &= ~IS_GUARD_PAGE; int flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE; os_vm_address_t actual; -#ifdef LISP_FEATURE_ALPHA - if (!addr) { - addr=under_2gb_free_pointer; - } -#endif #ifdef MAP_32BIT if (attributes & ALLOCATE_LOW) flags |= MAP_32BIT; #endif - actual = mmap(addr, len, protection, flags, -1, 0); + actual = sbcl_mmap(addr, len, protection, flags, -1, 0); if (actual == MAP_FAILED) { - perror("mmap"); + if (errno == ENOMEM) + fprintf(stderr, "os_alloc_gc_space(%d,%p,%zu) failed with ENOMEM\n", + attributes, addr, len); + else + perror("mmap"); return 0; /* caller should check this */ } @@ -62,19 +47,5 @@ os_validate(int attributes, os_vm_address_t addr, os_vm_size_t len) return 0; } -#ifdef LISP_FEATURE_ALPHA - - len=(len+(os_vm_page_size-1))&(~(os_vm_page_size-1)); - under_2gb_free_pointer+=len; -#endif - return actual; } - -void -os_invalidate(os_vm_address_t addr, os_vm_size_t len) -{ - if (munmap(addr,len) == -1) { - perror("munmap"); - } -} diff --git a/src/runtime/linux-nm b/src/runtime/linux-nm deleted file mode 100755 index 65a870bac6..0000000000 --- a/src/runtime/linux-nm +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/sh - -# " A " used to be in the set of removed symbols, but it turns out -# that the alpha implementation of closure_tramp and undefined_tramp -# is as an A. Whatever that is. CSR, 2005-06-12. -# " A " is a global absolute symbol, that is a symbol with a fixed -# assembly time value (which is used for offset calculations). - -nm -p "$@" | GREP_OPTIONS='' grep -v " [abcdgIiNnrstUuvw?-] " diff --git a/src/runtime/linux-os.c b/src/runtime/linux-os.c index 3962217113..dd969c945b 100644 --- a/src/runtime/linux-os.c +++ b/src/runtime/linux-os.c @@ -35,8 +35,6 @@ #include "genesis/static-symbols.h" #include "genesis/fdefn.h" -#include <sys/socket.h> -#include <sys/utsname.h> #include <errno.h> #include <sys/types.h> @@ -51,11 +49,7 @@ #include "thread.h" #include "gc-internal.h" #include <fcntl.h> -#ifdef LISP_FEATURE_SB_WTIMER -# include <sys/timerfd.h> -#endif - -int sb_GetTID() { return syscall(SYS_gettid); } +#include <sys/prctl.h> #ifdef LISP_FEATURE_X86 /* Prototype for personality(2). Done inline here since the header file @@ -66,11 +60,98 @@ int personality (unsigned long); #include <sys/personality.h> #endif -#if defined(LISP_FEATURE_SB_THREAD) && defined(LISP_FEATURE_SB_FUTEX) && !defined(LISP_FEATURE_SB_PTHREAD_FUTEX) +#ifdef LISP_FEATURE_SB_FUTEX #include <sys/syscall.h> #include <unistd.h> #include <errno.h> +#ifdef MUTEX_EVENTRECORDING +#include "genesis/mutex.h" +#define MAXEVENTS 200 +static struct { + struct thread* th; + struct timespec ts; + char *label; + char *mutex_name; + sword_t timeout; +} events[MAXEVENTS]; +static int record_mutex_events; +static int eventcount; + +void lisp_mutex_event(char *string) { + if (record_mutex_events) { + int id = __sync_fetch_and_add(&eventcount, 1); + if (id >= MAXEVENTS) lose("event buffer overflow"); + clock_gettime(CLOCK_REALTIME, &events[id].ts); + events[id].th = get_sb_vm_thread(); + events[id].label = string; + events[id].mutex_name = 0; + events[id].timeout = -1; + } +} +void lisp_mutex_event1(char *string, char *string2) { + if (record_mutex_events) { + int id = __sync_fetch_and_add(&eventcount, 1); + if (id >= MAXEVENTS) lose("event buffer overflow"); + clock_gettime(CLOCK_REALTIME, &events[id].ts); + events[id].th = get_sb_vm_thread(); + events[id].label = string; + events[id].mutex_name = string2; + events[id].timeout = -1; + } +} +void lisp_mutex_event2(char *string, char *string2, uword_t usec) { + if (record_mutex_events) { + int id = __sync_fetch_and_add(&eventcount, 1); + if (id >= MAXEVENTS) lose("event buffer overflow"); + clock_gettime(CLOCK_REALTIME, &events[id].ts); + events[id].th = get_sb_vm_thread(); + events[id].label = string; + events[id].mutex_name = string2; + events[id].timeout = usec; + } +} +void lisp_mutex_start_eventrecording() { + eventcount = 0; + record_mutex_events = 1; +} +void lisp_mutex_done_eventrecording() { + record_mutex_events = 0; + int i; + fprintf(stderr, "event log:\n"); + struct timespec basetime = events[0].ts; + for(i=0; i<eventcount;++i) { + struct thread *th = events[i].th; + struct thread_instance *ti = (void*)native_pointer(th->lisp_thread); + struct timespec rel_time = events[i].ts; + rel_time.tv_sec -= basetime.tv_sec; + rel_time.tv_nsec -= basetime.tv_nsec; + if (rel_time.tv_nsec<0) rel_time.tv_nsec += 1000 * 1000 * 1000, rel_time.tv_sec--; + lispobj threadname = ti->name; + if (events[i].timeout >= 0) // must also have mutex_name in this case + fprintf(stderr, "[%d.%09ld] %s: %s '%s' timeout %ld\n", + (int)rel_time.tv_sec, rel_time.tv_nsec, + (char*)VECTOR(threadname)->data, + events[i].label, events[i].mutex_name, events[i].timeout); + else if (events[i].mutex_name) + fprintf(stderr, "[%d.%09ld] %s: %s '%s'\n", + (int)rel_time.tv_sec, rel_time.tv_nsec, + (char*)VECTOR(threadname)->data, + events[i].label, events[i].mutex_name); + else + fprintf(stderr, "[%d.%09ld] %s: %s\n", + (int)rel_time.tv_sec, rel_time.tv_nsec, + (char*)VECTOR(threadname)->data, + events[i].label); + } + fprintf(stderr, "-----\n"); +} +#else +#define lisp_mutex_event(x) +#define lisp_mutex_event1(x,y) +#define lisp_mutex_event2(x,y,z) +#endif + /* values taken from the kernel's linux/futex.h. This header file doesn't exist in userspace, which is our excuse for not grovelling them automatically */ @@ -116,7 +197,6 @@ futex_init() futex_private_supported_p = 1; } else { futex_private_supported_p = 0; - SHOW("No futex private suppport\n"); } } @@ -140,14 +220,21 @@ futex_wait(int *lock_word, int oldval, long sec, unsigned long usec) struct timespec timeout; int t; +#ifdef MUTEX_EVENTRECORDING + struct mutex* m = (void*)((char*)lock_word - offsetof(struct mutex,state)); + char *name = m->name != NIL ? (char*)VECTOR(m->name)->data : "(unnamed)"; +#endif if (sec<0) { + lisp_mutex_event1("start futex wait", name); t = sys_futex(lock_word, futex_wait_op(), oldval, 0); } else { timeout.tv_sec = sec; timeout.tv_nsec = usec * 1000; + lisp_mutex_event2("start futex timedwait", name, usec); t = sys_futex(lock_word, futex_wait_op(), oldval, &timeout); } + lisp_mutex_event1("back from sys_futex", name); if (t==0) return 0; else if (errno==ETIMEDOUT) @@ -162,23 +249,23 @@ futex_wait(int *lock_word, int oldval, long sec, unsigned long usec) int futex_wake(int *lock_word, int n) { +#ifdef MUTEX_EVENTRECORDING + struct mutex* m = (void*)((char*)lock_word - offsetof(struct mutex,state)); + char *name = m->name != NIL ? (char*)VECTOR(m->name)->data : "(unnamed)"; + lisp_mutex_event1("waking futex", name); +#endif return sys_futex(lock_word, futex_wake_op(),n,0); } #endif -void os_init(char __attribute__((unused)) *argv[], - char __attribute__((unused)) *envp[]) +void os_init() { -#if defined(LISP_FEATURE_SB_THREAD) && defined(LISP_FEATURE_SB_FUTEX) && !defined(LISP_FEATURE_SB_PTHREAD_FUTEX) +#ifdef LISP_FEATURE_SB_FUTEX futex_init(); #endif - -#ifdef LISP_FEATURE_X86 - /* Use SSE detector. Recent versions of Linux enable SSE support - * on SSE capable CPUs. */ - /* FIXME: Are there any old versions that does not support SSE? */ - fast_bzero_pointer = fast_bzero_detect; +#ifdef LISP_FEATURE_SB_DEVEL + prctl(PR_SET_PTRACER, PR_SET_PTRACER_ANY); #endif } @@ -191,6 +278,28 @@ void os_init(char __attribute__((unused)) *argv[], int os_preinit(char *argv[], char *envp[]) { +#ifdef LISP_FEATURE_RISCV + extern int riscv_user_emulation, mmap_does_not_zero, sigaction_does_not_mask; + /* Accomodate buggy mmap() emulation, but detect up front whether it may be. + * Full system emulation running a RISCV kernel is generally fine. User mode is not. + * There's no way to know what it _will_ do, so we have to guess based on + * whether the emulation looks bad. */ + char buf[100]; + FILE *f = fopen("/proc/cpuinfo", "r"); + fgets(buf, sizeof buf, f); + fgets(buf, sizeof buf, f); + if (!strstr(buf, "hart")) { // look for "hardware thread" string + fprintf(stderr, "WARNING: enabling mmap() workaround. GC time may be affected\n"); + rewind(f); + fprintf(stderr, "Contents of /proc/cpuinfo:\n"); + while (fgets(buf, sizeof buf, f) && strlen(buf)>1) fprintf(stderr, " | %s", buf); + fprintf(stderr, "----\n"); + riscv_user_emulation = 1; + mmap_does_not_zero = 1; + sigaction_does_not_mask = 1; + } + fclose(f); +#endif #if ALLOW_PERSONALITY_CHANGE if (getenv("SBCL_IS_RESTARTING")) { @@ -250,22 +359,6 @@ int os_preinit(char *argv[], char *envp[]) #endif return 0; } - -void -os_protect(os_vm_address_t address, os_vm_size_t length, os_vm_prot_t prot) -{ - if (mprotect(address, length, prot)) { - if (errno == ENOMEM) { - lose("An mprotect call failed with ENOMEM. This probably means that the maximum amount\n" - "of separate memory mappings was exceeded. To fix the problem, either increase\n" - "the maximum with e.g. 'echo 262144 > /proc/sys/vm/max_map_count' or recompile\n" - "SBCL with a larger value for GENCGC-CARD-BYTES in\n" - "'src/compiler/target/backend-parms.lisp'."); - } else { - perror("mprotect"); - } - } -} /* * any OS-dependent special low-level handling for signals @@ -290,32 +383,16 @@ sigsegv_handler(int signal, siginfo_t *info, os_context_t *context) { os_vm_address_t addr = arch_get_bad_addr(signal, info, context); -#ifdef LISP_FEATURE_ALPHA - /* Alpha stuff: This is the end of a pseudo-atomic section during - which a signal was received. We must deal with the pending - interrupt (see also interrupt.c, ../code/interrupt.lisp) - - (how we got here: when interrupting, we set bit 63 in reg_ALLOC. - At the end of the atomic section we tried to write to reg_ALLOC, - got a SIGSEGV (there's nothing mapped there) so ended up here. */ - if (addr != NULL && - *os_context_register_addr(context, reg_ALLOC) & (1L<<63)) { - *os_context_register_addr(context, reg_ALLOC) -= (1L<<63); - interrupt_handle_pending(context); - return; - } -#endif - #ifdef LISP_FEATURE_SB_SAFEPOINT - if (!handle_safepoint_violation(context, addr)) + if (handle_safepoint_violation(context, addr)) return; #endif #ifdef LISP_FEATURE_GENCGC - if (!gencgc_handle_wp_violation(addr)) + if (gencgc_handle_wp_violation(context, addr)) return; #else - if (!cheneygc_handle_wp_violation(context, addr)) + if (cheneygc_handle_wp_violation(context, addr)) return; #endif - if (!handle_guard_page_triggered(context, addr)) + if (!handle_guard_page_triggered(context, addr)) sbcl_fallback_sigsegv_handler(signal, info, context); } @@ -323,22 +400,8 @@ void os_install_interrupt_handlers(void) { if (INSTALL_SIG_MEMORY_FAULT_HANDLER) { - undoably_install_low_level_interrupt_handler(SIG_MEMORY_FAULT, - sigsegv_handler); + ll_install_handler(SIG_MEMORY_FAULT, sigsegv_handler); } - - /* OAOOM c.f. sunos-os.c. - * Should we have a reusable function gc_install_interrupt_handlers? */ -#ifdef LISP_FEATURE_SB_THREAD -# ifdef LISP_FEATURE_SB_SAFEPOINT -# ifdef LISP_FEATURE_SB_THRUPTION - undoably_install_low_level_interrupt_handler(SIGPIPE, thruption_handler); -# endif -# else - undoably_install_low_level_interrupt_handler(SIG_STOP_FOR_GC, - sig_stop_for_gc_handler); -# endif -#endif } char *os_get_runtime_executable_path() @@ -354,61 +417,3 @@ char *os_get_runtime_executable_path() return copied_string(path); } - -#ifdef LISP_FEATURE_SB_WTIMER -/* - * Waitable timer implementation for the safepoint-based (SIGALRM-free) - * timer facility using timerfd_create(). - */ -int -os_create_wtimer() -{ - int fd = timerfd_create(CLOCK_MONOTONIC, 0); - if (fd == -1) - lose("os_create_wtimer: timerfd_create"); - - /* Cannot count on TFD_CLOEXEC availability, so do it manually: */ - if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) - lose("os_create_wtimer: fcntl"); - - return fd; -} - -int -os_wait_for_wtimer(int fd) -{ - unsigned char buf[8]; - int n = read(fd, buf, sizeof(buf)); - if (n == -1) { - if (errno == EINTR) - return -1; - lose("os_wtimer_listen failed"); - } - if (n != sizeof(buf)) - lose("os_wtimer_listen read too little"); - return 0; -} - -void -os_close_wtimer(int fd) -{ - if (close(fd) == -1) - lose("os_close_wtimer failed"); -} - -void -os_set_wtimer(int fd, int sec, int nsec) -{ - struct itimerspec spec = { {0,0}, {0,0} }; - spec.it_value.tv_sec = sec; - spec.it_value.tv_nsec = nsec; - if (timerfd_settime(fd, 0, &spec, 0) == -1) - lose("timerfd_settime"); -} - -void -os_cancel_wtimer(int fd) -{ - os_set_wtimer(fd, 0, 0); -} -#endif diff --git a/src/runtime/linux-os.h b/src/runtime/linux-os.h index c495f7bb66..46cb776c3b 100644 --- a/src/runtime/linux-os.h +++ b/src/runtime/linux-os.h @@ -42,5 +42,9 @@ typedef int os_vm_prot_t; /* Note that this must be higher than the highest numbered * synchronously generated signal that we handle (that is SIGSEGV), * due to Linux signal handling pecularities. See thread "Signal - * delivery order" from 2009-03-14 on kernel-devel@vger.kernel.org. */ + * delivery order" from 2009-03-14 on kernel-devel@vger.kernel.org. + * https://lkml.org/lkml/2009/3/14/133 + */ +#ifndef SIG_STOP_FOR_GC // choose you own signal if you must #define SIG_STOP_FOR_GC (SIGUSR2) +#endif diff --git a/src/runtime/lispobj.h b/src/runtime/lispobj.h new file mode 100644 index 0000000000..1f5f7bc4d2 --- /dev/null +++ b/src/runtime/lispobj.h @@ -0,0 +1,9 @@ +#ifndef _RUNTIME_LISPOBJ_H_ +#define _RUNTIME_LISPOBJ_H_ + +#include <stdint.h> +typedef intptr_t sword_t; +typedef uintptr_t uword_t; +typedef uword_t lispobj; + +#endif diff --git a/src/runtime/lispstring.h b/src/runtime/lispstring.h new file mode 100644 index 0000000000..6ed9422a28 --- /dev/null +++ b/src/runtime/lispstring.h @@ -0,0 +1,35 @@ +/* + * This software is part of the SBCL system. See the README file for + * more information. + * + * This software is derived from the CMU CL system, which was + * written at Carnegie Mellon University and released into the + * public domain. The software is in the public domain and is + * provided with absolutely no warranty. See the COPYING and CREDITS + * files for more information. + */ + +#ifndef _LISPSTRING_H_ +#define _LISPSTRING_H_ + +static inline boolean string_widetag_p(int widetag) +{ + // element type of NIL can just go to hell + return widetag == SIMPLE_BASE_STRING_WIDETAG +#ifdef SIMPLE_CHARACTER_STRING_WIDETAG + || widetag == SIMPLE_CHARACTER_STRING_WIDETAG +#endif + ; +} + +// This does not accept (SIMPLE-ARRAY NIL (*)) +// (You'd have a pretty bad time trying making a symbol like that) +static inline unsigned int schar(struct vector* string, int index) +{ + if (widetag_of(&string->header) == SIMPLE_BASE_STRING_WIDETAG) + return ((char*)string->data)[index]; + else + return ((unsigned int*)string->data)[index]; +} + +#endif diff --git a/src/runtime/main.c b/src/runtime/main.c index 5dba8087a3..e71c4c3182 100644 --- a/src/runtime/main.c +++ b/src/runtime/main.c @@ -1,5 +1,9 @@ +#include "interr.h" + int main(int argc, char *argv[], char *envp[]) { - extern int sbcl_main(int argc, char *argv[], char *envp[]); - return sbcl_main(argc, argv, envp); + extern int initialize_lisp(int argc, char *argv[], char *envp[]); + initialize_lisp(argc, argv, envp); + lose("unexpected return from initial thread in main()"); + return 0; } diff --git a/src/runtime/memcpy.h b/src/runtime/memcpy.h deleted file mode 100644 index a99c5fb7e9..0000000000 --- a/src/runtime/memcpy.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifdef __linux__ -#ifdef __amd64__ -#ifdef __ASSEMBLER__ -.symver memcpy,memcpy@GLIBC_2.2.5 -#else -__asm__(".symver memcpy,memcpy@GLIBC_2.2.5"); -#endif -#endif -#ifdef __i386__ -#ifdef __ASSEMBLER__ -.symver memcpy,memcpy@GLIBC_2.0 -#else -__asm__(".symver memcpy,memcpy@GLIBC_2.0"); -#endif -#endif -#endif diff --git a/src/runtime/mips-arch.c b/src/runtime/mips-arch.c index 200f7632ab..1b6db9ac93 100644 --- a/src/runtime/mips-arch.c +++ b/src/runtime/mips-arch.c @@ -15,7 +15,7 @@ #include "os.h" #include "lispregs.h" #include "signal.h" -#include "alloc.h" +#include "pseudo-atomic.h" #include "interrupt.h" #include "interr.h" #include "breakpoint.h" @@ -39,19 +39,13 @@ os_context_register(os_context_t *context, int offset) return (unsigned int)(*os_context_register_addr(context, offset)); } -static inline unsigned int -os_context_pc(os_context_t *context) -{ - return (unsigned int)(*os_context_pc_addr(context)); -} - static inline unsigned int os_context_insn(os_context_t *context) { if (os_context_bd_cause(context)) - return *(unsigned int *)(os_context_pc(context) + INSN_LEN); + return *(unsigned int *)((unsigned)OS_CONTEXT_PC(context) + INSN_LEN); else - return *(unsigned int *)(os_context_pc(context)); + return *(unsigned int *)((unsigned)OS_CONTEXT_PC(context)); } boolean @@ -118,8 +112,8 @@ next_insn_addr(os_context_t *context, unsigned int inst) unsigned int r2 = (inst >> 16) & 0x1f; unsigned int r3 = (inst >> 11) & 0x1f; unsigned int disp = ((inst&(1<<15)) ? inst | (-1 << 16) : inst&0x7fff) << 2; - unsigned int jtgt = (os_context_pc(context) & ~0x0fffffff) | (inst&0x3ffffff) << 2; - unsigned int tgt = os_context_pc(context); + unsigned int jtgt = ((unsigned)OS_CONTEXT_PC(context) & ~0x0fffffff) | (inst&0x3ffffff) << 2; + unsigned int tgt = (unsigned)OS_CONTEXT_PC(context); switch(opcode) { case 0x0: /* jr, jalr */ @@ -130,7 +124,7 @@ next_insn_addr(os_context_t *context, unsigned int inst) case 0x09: /* jalr */ tgt = os_context_register(context, r1); *os_context_register_addr(context, r3) - = os_context_pc(context) + INSN_LEN; + = (unsigned)OS_CONTEXT_PC(context) + INSN_LEN; break; default: tgt += INSN_LEN; @@ -158,7 +152,7 @@ next_insn_addr(os_context_t *context, unsigned int inst) if(os_context_register(context, r1) < 0) { tgt += disp; *os_context_register_addr(context, 31) - = os_context_pc(context) + INSN_LEN; + = (unsigned)OS_CONTEXT_PC(context) + INSN_LEN; } else tgt += INSN_LEN; break; @@ -167,7 +161,7 @@ next_insn_addr(os_context_t *context, unsigned int inst) if(os_context_register(context, r1) >= 0) { tgt += disp; *os_context_register_addr(context, 31) - = os_context_pc(context) + INSN_LEN; + = (unsigned)OS_CONTEXT_PC(context) + INSN_LEN; } else tgt += INSN_LEN; break; @@ -182,7 +176,7 @@ next_insn_addr(os_context_t *context, unsigned int inst) case 0x3: /* jal */ tgt = jtgt; *os_context_register_addr(context, 31) - = os_context_pc(context) + INSN_LEN; + = (unsigned)OS_CONTEXT_PC(context) + INSN_LEN; break; case 0x4: /* beq */ case 0x14: /* beql */ @@ -240,37 +234,31 @@ arch_skip_instruction(os_context_t *context) /* Skip the offending instruction. Don't use os_context_insn here, since in case of a branch we want the branch insn, not the delay slot. */ - *os_context_pc_addr(context) + OS_CONTEXT_PC(context) = (os_context_register_t) next_insn_addr(context, - *(unsigned int *)(os_context_pc(context))); + *(unsigned int *)((unsigned)OS_CONTEXT_PC(context))); } unsigned char * arch_internal_error_arguments(os_context_t *context) { if (os_context_bd_cause(context)) - return (unsigned char *)(os_context_pc(context) + (INSN_LEN * 2)); + return (unsigned char *)((unsigned)OS_CONTEXT_PC(context) + (INSN_LEN * 2)); else - return (unsigned char *)(os_context_pc(context) + INSN_LEN); + return (unsigned char *)((unsigned)OS_CONTEXT_PC(context) + INSN_LEN); } -boolean -arch_pseudo_atomic_atomic(os_context_t *context) -{ - return os_context_register(context, reg_ALLOC) & 1; +boolean arch_pseudo_atomic_atomic(__attribute((unused)) os_context_t *context) { + return get_pseudo_atomic_atomic(get_sb_vm_thread()); } -void -arch_set_pseudo_atomic_interrupted(os_context_t *context) -{ - *os_context_register_addr(context, reg_NL4) |= -1LL<<31; +void arch_set_pseudo_atomic_interrupted(__attribute__((unused)) os_context_t *context) { + set_pseudo_atomic_interrupted(get_sb_vm_thread()); } -void -arch_clear_pseudo_atomic_interrupted(os_context_t *context) -{ - *os_context_register_addr(context, reg_NL4) &= ~(-1LL<<31); +void arch_clear_pseudo_atomic_interrupted(__attribute__((unused)) os_context_t *context) { + clear_pseudo_atomic_interrupted(get_sb_vm_thread()); } unsigned int @@ -342,7 +330,7 @@ static sigset_t orig_sigmask; void arch_do_displaced_inst(os_context_t *context, unsigned int orig_inst) { - unsigned int *pc = (unsigned int *)os_context_pc(context); + unsigned int *pc = (unsigned int *)(unsigned)OS_CONTEXT_PC(context); unsigned int *next_pc; orig_sigmask = *os_context_sigmask_addr(context); @@ -366,7 +354,7 @@ arch_handle_breakpoint(os_context_t *context) void arch_handle_fun_end_breakpoint(os_context_t *context) { - *os_context_pc_addr(context) + OS_CONTEXT_PC(context) = (os_context_register_t)(unsigned int) handle_fun_end_breakpoint(context); } @@ -375,7 +363,7 @@ void arch_handle_after_breakpoint(os_context_t *context) { arch_install_breakpoint(skipped_break_addr); - arch_remove_breakpoint((unsigned int *)os_context_pc(context), + arch_remove_breakpoint((unsigned int *)(unsigned)OS_CONTEXT_PC(context), displaced_after_inst); *os_context_sigmask_addr(context) = orig_sigmask; } @@ -383,24 +371,96 @@ arch_handle_after_breakpoint(os_context_t *context) void arch_handle_single_step_trap(os_context_t *context, int trap) { - unsigned int code = *((u32 *)(os_context_pc(context))); + unsigned int code = *((uint32_t *)((unsigned)OS_CONTEXT_PC(context))); int register_offset = code >> 16 & 0x1f; handle_single_step_trap(context, trap, register_offset); arch_skip_instruction(context); } +#include "genesis/cons.h" +static void +handle_allocation_trap(os_context_t * context, unsigned int insn) +{ + if (foreign_function_call_active) + lose("Allocation trap inside foreign code."); + + mcontext_t *mctx = &context->uc_mcontext; + // int rs = (insn >> 21) & 0x1f; + int rt = (insn >> 16) & 0x1f; + int code = (insn >> 6) & 0x3ff; + int alloc_tn = code & 0x3f; + int consp = code & 0x100; + // the number of bytes requested is the difference between region->free_pointer + // and the adjusted freepointer in 'rt' + struct alloc_region* r = (struct alloc_region*)STATIC_SPACE_START; + if (consp) ++r; + int request = *os_context_register_addr(context,rt) - (uword_t)r->free_pointer; + lispobj* argv = 0; // for listify_rest + if (code & 0x200) { + // alloc trap never occurs in a branch delay slot, so 'bd-cause' is 0 + unsigned int* pc = (void*)(int)OS_CONTEXT_PC(context); + unsigned int dummy_add = pc[2]; + int special = (dummy_add >> 26) & 0x3f; + int rs = (dummy_add >> 21) & 0x1f; + int rt = (dummy_add >> 16) & 0x1f; + int rd = (dummy_add >> 11) & 0x1f; + // Make sure it looks right + if (!(special == 0 && rd == 0 && rs == rt && ((dummy_add & 0x7ff) == 0x21))) + lose("Didn't see an ADDU after listify_rest trap"); + argv = (lispobj*)(uword_t)mctx->gregs[rs]; + } + // I don't undertand this. Just copying it from sparc + ppc + fake_foreign_function_call(context); + uword_t result; + { + struct thread* thread = get_sb_vm_thread(); + struct interrupt_data *data = &thread_interrupt_data(thread); + data->allocation_trap_context = context; + if (argv) { // listify_rest + extern lispobj listify_rest_arg(lispobj*, sword_t); + // listify_rest_arg wants the number of bytes in the argv[] array, + // not the number of bytes in the result list, so divide by 2. + result = listify_rest_arg(argv, request>>1); + // Skip over this instruction and 2 more + OS_CONTEXT_PC(context) += 12; + } else { // anything else + extern lispobj *alloc(sword_t), *alloc_list(sword_t); + result = (uword_t)(consp ? alloc_list(request) : alloc(request)); + // Skip over this instruction and the writeback of freeptr + OS_CONTEXT_PC(context) += 8; + } + data->allocation_trap_context = 0; + } + // store into the alloc_tn (which is encoded in 'code') + mctx->gregs[alloc_tn] = result; + undo_fake_foreign_function_call(context); +} + static void sigtrap_handler(int signal, siginfo_t *info, os_context_t *context) { - unsigned int code = (os_context_insn(context) >> 6) & 0xff; - if (code == trap_PendingInterrupt) { - /* KLUDGE: is this necessary or will handle_trap do the same? */ - arch_clear_pseudo_atomic_interrupted(context); + unsigned int insn = os_context_insn(context); + unsigned int funct = insn & 0x3f; // 6-bit field + unsigned int code = (insn >> 6) & 0x3ff; + __attribute__((unused)) int rs = (insn >> 21) & 0x1f; + __attribute__((unused)) int rt = (insn >> 16) & 0x1f; + switch (funct) { + case 0x33: // #b110011 = TLTU + return handle_allocation_trap(context, insn); + case 0x36: // #b110110 = TNE + switch (code) { + case 0: // FIXME: why is this not trap_PendingInterrupt ? + arch_clear_pseudo_atomic_interrupted(context); + OS_CONTEXT_PC(context) += 4; + return interrupt_handle_pending(context); + case trap_InvalidArgCount: + return interrupt_internal_error(context, 0); + } } handle_trap(context, code); } -static void +__attribute__((unused)) static void sigfpe_handler(int signal, siginfo_t *info, os_context_t *context) { interrupt_handle_now(signal, info, context); @@ -425,7 +485,7 @@ arch_set_fp_control(unsigned int fp) void arch_install_interrupt_handlers(void) { - undoably_install_low_level_interrupt_handler(SIGTRAP,sigtrap_handler); + ll_install_handler(SIGTRAP,sigtrap_handler); } // Calls into C are mediated by the handwritten call_into_c routine @@ -437,6 +497,26 @@ arch_write_linkage_table_entry(int index, void *target_addr, int datap) { // allocate successive entries downward char *reloc_addr = - (char*)LINKAGE_TABLE_SPACE_END - (index + 1) * LINKAGE_TABLE_ENTRY_SIZE; + (char*)ALIEN_LINKAGE_TABLE_SPACE_END - (index + 1) * ALIEN_LINKAGE_TABLE_ENTRY_SIZE; *(unsigned int *)reloc_addr = (unsigned int)target_addr; } + +void gcbarrier_patch_code(void* where, int nbits) +{ + // Replicate FIXUP-CODE-OBJECT for fixup kind :SLL-SA. + unsigned* pc = where; + unsigned inst = pc[0]; + unsigned next = pc[1]; + int left_shift = 32 - (GENCGC_CARD_SHIFT + nbits); + int right_shift = left_shift + GENCGC_CARD_SHIFT; + unsigned preserve_bits = ~(0x1f << 6); + pc[0] = (inst & preserve_bits) | (left_shift << 6); + pc[1] = (next & preserve_bits) | (right_shift << 6); +void + +*arch_read_linkage_table_entry(int index, int datap) +{ + char *reloc_addr = + (char*)ALIEN_LINKAGE_TABLE_SPACE_END - (index + 1) * ALIEN_LINKAGE_TABLE_ENTRY_SIZE; + return *(unsigned int *)reloc_addr; +} diff --git a/src/runtime/mips-arch.h b/src/runtime/mips-arch.h index 9fbbb392ce..32bfb568ca 100644 --- a/src/runtime/mips-arch.h +++ b/src/runtime/mips-arch.h @@ -1,8 +1,6 @@ #ifndef _MIPS_ARCH_H #define _MIPS_ARCH_H -#define ALIEN_STACK_GROWS_DOWNWARD - unsigned int arch_get_fp_control(void); void arch_set_fp_control(unsigned int fp); diff --git a/src/runtime/mips-assem.S b/src/runtime/mips-assem.S index c84abe4803..f5938f6dee 100644 --- a/src/runtime/mips-assem.S +++ b/src/runtime/mips-assem.S @@ -27,6 +27,7 @@ #include "genesis/funcallable-instance.h" #include "genesis/simple-fun.h" #include "genesis/static-symbols.h" +#include "genesis/symbol.h" #define zero $0 #define AT $1 @@ -103,6 +104,17 @@ symbol: .type symbol,@function; \ symbol: +/* zero (or anything non-nil) -> atomic=true and NIL -> atomic=false */ +#define BEGIN_PSEUDO_ATOMIC \ + .set noreorder ; \ + sw zero, (PSEUDO_ATOMIC_ATOMIC+SYMBOL_VALUE_OFFSET-NIL)(reg_NIL) ; \ + .set reorder +#define END_PSEUDO_ATOMIC(temp) \ + .set noreorder ; \ + sw reg_NIL, (PSEUDO_ATOMIC_ATOMIC+SYMBOL_VALUE_OFFSET-NIL)(reg_NIL) ; \ + lw temp, (PSEUDO_ATOMIC_INTERRUPTED+SYMBOL_VALUE_OFFSET-NIL)(reg_NIL) ; \ + tne zero, temp, 0 ; \ + .set reorder .text @@ -120,6 +132,7 @@ symbol: .mask 0xc0ff0000, -8 sw ra, framesize-8(sp) sw s8, framesize-12(sp) + sw $gp, framesize-16(sp) /* No .cprestore, we don't want automatic gp restoration. */ sw s7, framesize-20(sp) sw s6, framesize-24(sp) @@ -136,27 +149,14 @@ symbol: li reg_FDEFN, 0 # t6 li reg_L1, 0 # t8 - /* Turn on pseudo-atomic. */ - .set noreorder - li reg_NL4, 0 - li reg_ALLOC, 1 - .set reorder - - /* Load the allocation pointer, preserving the low-bit of alloc */ - lw reg_BSP, dynamic_space_free_pointer - addu reg_ALLOC, reg_BSP + BEGIN_PSEUDO_ATOMIC /* Load the rest of the LISP state. */ lw reg_BSP, current_binding_stack_pointer lw reg_CSP, current_control_stack_pointer lw reg_OCFP, current_control_frame_pointer - /* Check for interrupt */ - .set noreorder - bgez reg_NL4, 1f - subu reg_ALLOC, 1 - break 0x0, trap_PendingInterrupt -1: .set reorder + END_PSEUDO_ATOMIC(reg_NL4) /* Pass in args */ move reg_LEXENV, a0 @@ -179,6 +179,7 @@ symbol: /* Mark us as in Lisp land. */ sw zero, foreign_function_call_active + lw reg_CARDBASE, gc_card_mark /* Jump into lisp land. */ jr reg_LIP @@ -193,27 +194,20 @@ lra: .word RETURN_PC_WIDETAG /* Single value return spot. */ + /* Nested lisp -> C calls may have clobbered gp. */ + lw $gp, framesize-16(sp) + /* Mark us as in C land. */ sw reg_CSP, foreign_function_call_active - /* Set the pseudo-atomic flag. */ - li reg_NL4, 0 - addu reg_ALLOC, 1 - .set reorder + BEGIN_PSEUDO_ATOMIC /* Save LISP state. */ - subu reg_NL0, reg_ALLOC, 1 - sw reg_NL0, dynamic_space_free_pointer sw reg_BSP, current_binding_stack_pointer sw reg_CSP, current_control_stack_pointer sw reg_CFP, current_control_frame_pointer - /* Check for interrupt */ - .set noreorder - bgez reg_NL4, 1f - subu reg_ALLOC, 1 - break 0x0, trap_PendingInterrupt -1: .set reorder + END_PSEUDO_ATOMIC(reg_NL4) /* Pass one return value back to C land. For a 64bit value, we may need to clobber v1 aka reg_NL4. */ @@ -253,11 +247,7 @@ lra: .word RETURN_PC_WIDETAG /* Mark us as in C land. */ sw reg_CSP, foreign_function_call_active - /* Set the pseudo-atomic flag. */ - .set noreorder - li reg_NL4, 0 - addu reg_ALLOC, 1 - .set reorder + BEGIN_PSEUDO_ATOMIC /* Convert the return address to an offset and save it on the stack. */ subu reg_NFP, reg_LIP, reg_CODE @@ -265,10 +255,9 @@ lra: .word RETURN_PC_WIDETAG sw reg_OCFP, (reg_CFP) sw reg_NFP, 4(reg_CFP) sw reg_CODE, 8(reg_CFP) + sw $gp, 12(reg_CFP) // should this be saved? on the control stack? /* Save LISP state. */ - subu reg_A0, reg_ALLOC, 1 - sw reg_A0, dynamic_space_free_pointer sw reg_BSP, current_binding_stack_pointer sw reg_CSP, current_control_stack_pointer sw reg_CFP, current_control_frame_pointer @@ -277,22 +266,13 @@ lra: .word RETURN_PC_WIDETAG $25 must cotain the address of the called function." */ lw $25, (reg_CFUNC) /* linkage-table indirection */ - /* Check for interrupt */ - .set noreorder - bgez reg_NL4, 1f - /* Don't put the following 'subu' in the delay slot of the 'bgez' - * because reg_ALLOC is $25 which now contains the callee address */ - nop - subu reg_ALLOC, 1 - break 0x0, trap_PendingInterrupt - // load $25 again if 'bgez' was not taken (and reg_ALLOC was trashed) - lw $25, (reg_CFUNC) /* linkage-table indirection */ - nop -1: .set reorder + END_PSEUDO_ATOMIC(reg_NL4) /* Into C land we go. */ jalr $25 + lw $gp, 12(reg_CFP) + /* Pass 64bit return value to lisp land. */ move reg_NL0, v0 # reg_CFUNC move reg_NL1, v1 # reg_NL4 @@ -320,15 +300,7 @@ lra: .word RETURN_PC_WIDETAG li reg_CODE, 0 # s8 li reg_LIP, 0 # ra - /* Turn on pseudo-atomic. */ - .set noreorder - li reg_NL4, 0 - li reg_ALLOC, 1 - .set reorder - - /* Load the allocation pointer, preserving the low-bit of alloc */ - lw reg_BSP, dynamic_space_free_pointer - addu reg_ALLOC, reg_BSP + BEGIN_PSEUDO_ATOMIC lw reg_BSP, current_binding_stack_pointer @@ -338,12 +310,7 @@ lra: .word RETURN_PC_WIDETAG subu reg_LIP, reg_NFP, OTHER_POINTER_LOWTAG addu reg_LIP, reg_CODE - /* Check for interrupt */ - .set noreorder - bgez reg_NL4, 1f - subu reg_ALLOC, 1 - break 0x0, trap_PendingInterrupt -1: .set reorder + END_PSEUDO_ATOMIC(reg_NL4) /* Reset the lisp stack. */ /* Note: OCFP and CFP are in saved regs. */ @@ -352,6 +319,7 @@ lra: .word RETURN_PC_WIDETAG /* Mark us as in Lisp land. */ sw zero, foreign_function_call_active + lw reg_CARDBASE, gc_card_mark /* Return to LISP. */ jr reg_LIP diff --git a/src/runtime/mips-linux-os.c b/src/runtime/mips-linux-os.c index e64913af9b..5689b4d055 100644 --- a/src/runtime/mips-linux-os.c +++ b/src/runtime/mips-linux-os.c @@ -60,15 +60,6 @@ os_context_fpregister_addr(os_context_t *context, int offset) return &ctx->sc_fpregs[offset]; } -os_context_register_t * -os_context_pc_addr(os_context_t *context) -{ - /* Why do I get all the silly ports? -- CSR, 2002-08-11 */ - mcontext_t *mctx = &context->uc_mcontext; - struct sigcontext *ctx = (struct sigcontext *)mctx; - return &ctx->sc_pc; -} - sigset_t * os_context_sigmask_addr(os_context_t *context) { @@ -113,7 +104,7 @@ os_context_bd_cause(os_context_t *context) extern boolean arch_insn_with_bdelay_p(unsigned int insn); os_vm_address_t addr - = (os_vm_address_t)(unsigned int)*os_context_pc_addr(context); + = (os_vm_address_t)(unsigned int)OS_CONTEXT_PC(context); unsigned int insn = *(unsigned int *)addr; if (arch_insn_with_bdelay_p(insn)) diff --git a/src/runtime/mips-linux-os.h b/src/runtime/mips-linux-os.h index bd93877df9..78571cb050 100644 --- a/src/runtime/mips-linux-os.h +++ b/src/runtime/mips-linux-os.h @@ -10,4 +10,6 @@ unsigned int os_context_fp_control(os_context_t *context); void os_restore_fp_control(os_context_t *context); unsigned int os_context_bd_cause(os_context_t *context); +#define OS_CONTEXT_PC(context) context->uc_mcontext.pc + #endif /* _MIPS_LINUX_OS_H */ diff --git a/src/runtime/mips-lispregs.h b/src/runtime/mips-lispregs.h index c46ac4fd11..7bd9c2502e 100644 --- a/src/runtime/mips-lispregs.h +++ b/src/runtime/mips-lispregs.h @@ -31,7 +31,7 @@ #define reg_CFP REG(22) #define reg_CSP REG(23) #define reg_L1 REG(24) -#define reg_ALLOC REG(25) +#define reg_CARDBASE REG(25) #define reg_NSP REG(29) #define reg_CODE REG(30) #define reg_LIP REG(31) diff --git a/src/runtime/monitor.c b/src/runtime/monitor.c index f3b1d55bad..1777bcf8bf 100644 --- a/src/runtime/monitor.c +++ b/src/runtime/monitor.c @@ -14,13 +14,13 @@ #include <stdio.h> #include <sys/types.h> #include <stdlib.h> -#include <setjmp.h> #include <sys/time.h> #ifndef LISP_FEATURE_WIN32 #include <sys/resource.h> #endif #include <signal.h> #include <unistd.h> +#include <fcntl.h> #include "runtime.h" #include "parse.h" @@ -30,7 +30,6 @@ #include "arch.h" #include "interr.h" #include "search.h" -#include "purify.h" #include "globals.h" #include "lispregs.h" #include "interrupt.h" @@ -39,7 +38,8 @@ #include "genesis/primitive-objects.h" #include "genesis/gc-tables.h" #include "gc-internal.h" - +#include "tlsf-bsd/tlsf/tlsf.h" +extern void* tlsf_control; /* When we need to do command input, we use this stream, which is not * in general stdin, so that things will "work" (as well as being @@ -56,12 +56,275 @@ static int ldb_in_fd = -1; typedef int cmd(char **ptr); +struct crash_preamble { + uword_t signature; + uword_t static_start; + uword_t static_nbytes; + uword_t readonly_start; + uword_t readonly_nbytes; + uword_t dynspace_start; + long dynspace_npages; + int card_size; + int card_table_nbits; + // fixedobj data dumped: pages, page table + uword_t fixedobj_start, fixedobj_size, fixedobj_free_pointer; + // text data dumped: pages, touched_bits, page table + uword_t text_start, text_size; + lispobj *tlsf_mem_start, *text_space_highwatermark; + lispobj sentinel_block[3]; + void* tlsf_control_address; + int nthreads; + int tls_size; + lispobj lisp_package_vector; + int sizeof_context; + int tlsf_control_size; + char sprof_enabled; + char pin_dynspace_code; +}; +struct crash_thread_preamble { + uword_t address; + uword_t has_context; + uword_t control_stack_nbytes; + uword_t binding_stack_nbytes; +}; + +// Prevent some mixups in case you add fields to the crash dump +const int CRASH_PREAMBLE_SIGNATURE = + (sizeof (struct crash_preamble) << 16) | sizeof (struct crash_thread_preamble); + +#if defined LISP_FEATURE_X86 || defined LISP_FEATURE_X86_64 // un-tested elsewhere +#include <errno.h> +static void checked_write(char *legend, int fd, void* buf, long nbytes) +{ + ssize_t wrote = write(fd, buf, nbytes); + if (wrote != nbytes) lose("short write, errno=%d", errno); + fprintf(stderr, "%s: %lx bytes\n", legend, nbytes); +} + +#include "immobile-space.h" +void save_gc_crashdump(char *pathname, + lispobj* cur_thread_approx_stackptr) +{ + extern int pin_all_dynamic_space_code; + int fd = open(pathname, O_WRONLY|O_CREAT, 0666); + struct thread* th; + int nthreads = 0; + for_each_thread(th) ++nthreads; + fprintf(stderr, "save: %d threads\n", nthreads); + struct crash_preamble preamble; + unsigned long nbytes_heap = next_free_page * GENCGC_PAGE_BYTES; +#ifdef LISP_FEATURE_SB_THREAD + int nbytes_tls = SymbolValue(FREE_TLS_INDEX,0); +#else + int nbytes_tls = sizeof (struct thread); +#endif + preamble.signature = CRASH_PREAMBLE_SIGNATURE; + preamble.static_start = STATIC_SPACE_START; + preamble.static_nbytes = (uword_t)static_space_free_pointer - STATIC_SPACE_START; + preamble.readonly_start = READ_ONLY_SPACE_START; + preamble.readonly_nbytes = (uword_t)read_only_space_free_pointer - READ_ONLY_SPACE_START; + preamble.dynspace_start = DYNAMIC_SPACE_START; + preamble.dynspace_npages = next_free_page; + preamble.card_size = GENCGC_CARD_BYTES; + preamble.card_table_nbits = gc_card_table_nbits; + preamble.nthreads = nthreads; + preamble.tls_size = nbytes_tls; + preamble.lisp_package_vector = lisp_package_vector; + preamble.sprof_enabled = sb_sprof_enabled; + preamble.pin_dynspace_code = pin_all_dynamic_space_code; + preamble.sizeof_context = sizeof (os_context_t); +#ifdef LISP_FEATURE_IMMOBILE_SPACE + char *tlsf_memory_end = (char*)TEXT_SPACE_START + TEXT_SPACE_SIZE; + preamble.fixedobj_start = FIXEDOBJ_SPACE_START; + preamble.fixedobj_size = FIXEDOBJ_SPACE_SIZE; + preamble.fixedobj_free_pointer = (uword_t)fixedobj_free_pointer; + preamble.text_start = TEXT_SPACE_START; + preamble.text_size = TEXT_SPACE_SIZE; + preamble.text_space_highwatermark = text_space_highwatermark; + preamble.tlsf_mem_start = tlsf_mem_start; + preamble.tlsf_control_address = tlsf_control; + preamble.tlsf_control_size = tlsf_size(); + memcpy(preamble.sentinel_block, tlsf_memory_end-3*N_WORD_BYTES, 3*N_WORD_BYTES); +#endif + // write the preamble and static + readonly spaces + checked_write("preamble", fd, &preamble, sizeof preamble); + checked_write("static", fd, (char*)STATIC_SPACE_START, preamble.static_nbytes); + checked_write("R/O", fd, (char*)READ_ONLY_SPACE_START, preamble.readonly_nbytes); + + // write the dynamic-space, PTEs, card table + checked_write("dynamic", fd, (char*)DYNAMIC_SPACE_START, nbytes_heap); + checked_write("PTE", fd, page_table, sizeof (struct page) * next_free_page); + checked_write("cardmark", fd, gc_card_mark, 1+gc_card_table_mask); +#ifdef LISP_FEATURE_IMMOBILE_SPACE + int usage = (uword_t)fixedobj_free_pointer - FIXEDOBJ_SPACE_START; + checked_write("fixedobj", fd, (char*)FIXEDOBJ_SPACE_START, usage); + int total_npages = FIXEDOBJ_SPACE_SIZE / IMMOBILE_CARD_BYTES; + checked_write("fixedobj_PTE", fd, fixedobj_pages, total_npages * sizeof sizeof(struct fixedobj_page)); + usage = (uword_t)text_space_highwatermark - TEXT_SPACE_START; + // write the block_header_t that is just beyond the high water mark + checked_write("text", fd, (char*)TEXT_SPACE_START, usage+3*N_WORD_BYTES); + total_npages = TEXT_SPACE_SIZE / IMMOBILE_CARD_BYTES; + int n_bitmap_elts = ALIGN_UP(total_npages, 32) / 32; + checked_write("text_gen", fd, text_page_genmask, total_npages); // 1 byte per page + checked_write("text_WP", fd, text_page_touched_bits, n_bitmap_elts * sizeof (int)); + checked_write("TLSF_control", fd, tlsf_control, preamble.tlsf_control_size); + int tlsf_memory_size = tlsf_memory_end - (char*)tlsf_mem_start; + int n_tlsf_pages = tlsf_memory_size / IMMOBILE_CARD_BYTES; + checked_write("TLSF_sso", fd, tlsf_page_sso, n_tlsf_pages * sizeof (short)); +#endif + struct crash_thread_preamble thread_preamble; + for_each_thread(th) { + int ici = fixnum_value(read_TLS(FREE_INTERRUPT_CONTEXT_INDEX,th)); + os_context_t* threadcontext = nth_interrupt_context(0, th); + uword_t sp; + if (ici) { +#ifdef LISP_FEATURE_C_STACK_IS_CONTROL_STACK + sp = *os_context_register_addr(threadcontext, reg_SP); +#else + sp = *os_context_register_addr(threadcontext, reg_CSP); +#endif + } else if (th->state_word.state == STATE_DEAD) { + gc_assert(th->binding_stack_pointer == th->binding_stack_start); + // FIXME: assumes stack grows down + sp = (uword_t)th->control_stack_end; + } else { + if (th != get_sb_vm_thread()) { + char msg[80]; + int n = snprintf(msg, sizeof msg, + "thread %p state %d - No stackptr for crash dump\n", + th, th->state_word.state); + write(2, msg, n); + _exit(1); + } +#ifdef LISP_FEATURE_C_STACK_IS_CONTROL_STACK + sp = (uword_t)cur_thread_approx_stackptr; +#else + sp = access_control_stack_pointer(th); +#endif + } +#ifdef LISP_FEATURE_C_STACK_IS_CONTROL_STACK + int nbytes_control_stack = + (char*)th->control_stack_end - (char*)sp; // grows downward + int nbytes_binding_stack = + (char*)th->binding_stack_pointer - (char*)th->binding_stack_start; // grows upward +#else + int nbytes_control_stack = (char*)sp - (char*)th->control_stack_start; // grows upward + int nbytes_binding_stack = + (char*)get_binding_stack_pointer(th) - (char*)th->binding_stack_start; +#endif + thread_preamble.address = (uword_t)th; + thread_preamble.has_context = ici != 0; // boolean for have context or not + thread_preamble.control_stack_nbytes = nbytes_control_stack; + thread_preamble.binding_stack_nbytes = nbytes_binding_stack; + // write the preamble + checked_write("thread", fd, &thread_preamble, sizeof thread_preamble); + // write 0 or 1 contexts, control-stack, binding-stack, TLS + if (ici) checked_write(" ctxt", fd, threadcontext, preamble.sizeof_context); +#ifdef LISP_FEATURE_C_STACK_IS_CONTROL_STACK + checked_write(" stack", fd, (char*)sp, nbytes_control_stack); +#else + checked_write(" stack", fd, th->control_stack_start, nbytes_control_stack); +#endif + checked_write(" bindings", fd, th->binding_stack_start, nbytes_binding_stack); + checked_write(" TLS", fd, th, nbytes_tls); + } + checked_write("sig", fd, "SB.Crash", 8); // trailing signature + close(fd); +} +#endif + static cmd call_cmd, dump_cmd, print_cmd, quit_cmd, help_cmd; static cmd flush_cmd, regs_cmd, exit_cmd; static cmd print_context_cmd, pte_cmd, search_cmd; -static cmd backtrace_cmd, purify_cmd, catchers_cmd; -static cmd grab_sigs_cmd; -static cmd kill_cmd; +static cmd backtrace_cmd, catchers_cmd; +static cmd threads_cmd; + +extern void gc_stop_the_world(), gc_start_the_world(); +static void suspend_other_threads() { +#ifdef LISP_FEATURE_SB_THREAD + gc_stop_the_world(); +#endif + // It might make sense for each thread's stop-for-gc handler to close its region + // versus doing this loop + struct thread *th; + for_each_thread(th) { gc_close_thread_regions(th, 0); } + gc_close_collector_regions(0); +} +static void unsuspend_other_threads() { +#ifdef LISP_FEATURE_SB_THREAD + gc_start_the_world(); +#endif +} + +static int save_cmd(char **ptr) { + char *name = parse_token(ptr); + if (!name) { + fprintf(stderr, "Need filename\n"); + return 1; + } +#if (defined LISP_FEATURE_X86 || defined LISP_FEATURE_X86_64) && defined LISP_FEATURE_SB_THREAD + suspend_other_threads(); + save_gc_crashdump(name, (lispobj*)__builtin_frame_address(0)); + unsuspend_other_threads(); +#else + fprintf(stderr, "Unimplemented\n"); +#endif + return 0; +} + +static int threads_cmd(char **ptr) { + int regions = 0; + struct thread* th; + if (more_p(ptr) && !strncmp(*ptr, "-r", 2)) regions = 1; + fprintf(stderr, "(thread*,pthread,sb-vm:thread,name)\n"); + void* pthread; + for_each_thread(th) { + memcpy(&pthread, &th->os_thread, N_WORD_BYTES); + struct thread_instance* i = (void*)(th->lisp_thread - INSTANCE_POINTER_LOWTAG); + char* name = NULL; + if (i->name != NIL && + widetag_of(native_pointer(i->name)) == SIMPLE_BASE_STRING_WIDETAG) + name = (char*)VECTOR(i->name)->data; + fprintf(stderr, "%p %p %p \"%s\"\n", th, pthread, (void*)i, name); + if (regions) { +#define show_tlab(label, r) fprintf(stderr, " %s @ %p: %p %p %p\n", label, \ + &th->r, th->r.start_addr, th->r.end_addr, th->r.free_pointer) + show_tlab("usr cons ", cons_tlab); + show_tlab("usr mix ", mixed_tlab); + show_tlab("sys cons ", sys_cons_tlab); + show_tlab("sys mix ", sys_mixed_tlab); +#undef show_tlab + } + } + return 0; +} +static int verify_cmd(char __attribute__((unused)) **ptr) { + gencgc_verbose = 1; + suspend_other_threads(); + verify_heap(0, 0); + unsuspend_other_threads(); + return 0; +} +static int gc_cmd(char **ptr) { + int last_gen = 0; + extern generation_index_t verify_gens; + extern boolean pre_verify_gen_0; + if (more_p(ptr)) parse_number(ptr, &last_gen); + gencgc_verbose = 2; + pre_verify_gen_0 = 1; + verify_gens = 0; + suspend_other_threads(); + collect_garbage(last_gen); + unsuspend_other_threads(); + return 0; +} + +static int tlsf_cmd(__attribute__((unused)) char **ptr) { +#ifdef LISP_FEATURE_IMMOBILE_SPACE + tlsf_dump_pool(tlsf_control, tlsf_mem_start, "/dev/tty"); +#endif + return 0; +} static struct cmd { char *cmd, *help; @@ -77,24 +340,20 @@ static struct cmd { {"d", "(an alias for dump)", dump_cmd}, {"exit", "Exit this instance of the monitor.", exit_cmd}, {"flush", "Flush all temp variables.", flush_cmd}, - /* (Classic CMU CL had a "gc" command here, which seems like a - * reasonable idea, but the code was stale (incompatible with - * gencgc) so I just flushed it. -- WHN 20000814 */ - {"grab-signals", "Set the signal handlers to call LDB.", grab_sigs_cmd}, - {"kill", "Kill ourself with signal number N (useful if running under gdb)", - kill_cmd}, - {"purify", "Purify. (Caveat purifier!)", purify_cmd}, {"print", "Print object at ADDRESS.", print_cmd}, {"p", "(an alias for print)", print_cmd}, {"pte", "Page table entry for address", pte_cmd}, {"quit", "Quit.", quit_cmd}, {"regs", "Display current Lisp registers.", regs_cmd}, {"search", "Search heap for object.", search_cmd}, + {"save", "Produce crashdump", save_cmd}, + {"threads", "List threads", threads_cmd}, + {"tlsfdump", "Dump TLSF structures", tlsf_cmd}, + {"verify", "Check heap invariants", verify_cmd}, + {"gc", "Collect garbage", gc_cmd}, {NULL, NULL, NULL} }; -static jmp_buf curbuf; - static int visible(unsigned char c) { @@ -104,6 +363,11 @@ visible(unsigned char c) return c; } +static boolean valid_widetag_p(unsigned char widetag) { + // TODO: ensure that widetag is defined (not "unused") and is for a headered object + // (i.e. is not CHARACTER_WIDETAG and not some other things) + return other_immediate_lowtag_p(widetag); +} static int NO_SANITIZE_MEMORY dump_cmd(char **ptr) { @@ -115,14 +379,14 @@ dump_cmd(char **ptr) int force = 0, decode = 0; if (more_p(ptr)) { - // you can't both "force" and "decode" - only one or the other, - // or neither - if (!strncmp(*ptr, "-f ", 3)) { - force = 1; - *ptr += 3; - } else if (!strncmp(*ptr, "-d ", 3)) { - decode = 1; - *ptr += 3; + while (1) { + if (!strncmp(*ptr, "-f ", 3)) { + force = 1; + *ptr += 3; + } else if (!strncmp(*ptr, "-d ", 3)) { + decode = 1; + *ptr += 3; + } else break; } if (!parse_addr(ptr, !force, &addr)) return 0; @@ -151,17 +415,9 @@ dump_cmd(char **ptr) lispobj* next_object = decode ? (lispobj*)addr : 0; while (count-- > 0) { -#ifndef LISP_FEATURE_ALPHA printf("%p: ", (os_vm_address_t) addr); -#else - printf("0x%08X: ", (u32) addr); -#endif if (force || gc_managed_addr_p((lispobj)addr)) { -#ifndef LISP_FEATURE_ALPHA unsigned long *lptr = (unsigned long *)addr; -#else - u32 *lptr = (u32 *)addr; -#endif unsigned char *cptr = (unsigned char *)addr; #if N_WORD_BYTES == 8 @@ -198,9 +454,9 @@ dump_cmd(char **ptr) if (word != 0 && !is_lisp_pointer(word) && valid_widetag_p(header_widetag(word))) { printf(" %s", widetag_names[header_widetag(word)>>2]); - next_object += sizetab[header_widetag(word)](next_object); - } else if (is_cons_half(word)) { - next_object += 2; + next_object += headerobj_size2(next_object, word); + } else if (!is_header(word)) { + next_object += CONS_SIZE; } else { // disable decoder if weirdness observed decode = 0; } @@ -234,20 +490,10 @@ pte_cmd(char **ptr) return 0; } -static int -kill_cmd(char **ptr) -{ -#ifndef LISP_FEATURE_WIN32 - int sig; - if (parse_number(ptr, &sig)) kill(getpid(), sig); -#endif - return 0; -} - static int regs_cmd(char __attribute__((unused)) **ptr) { - struct thread __attribute__((unused)) *thread=arch_os_get_current_thread(); + struct thread __attribute__((unused)) *thread=get_sb_vm_thread(); printf("CSP\t=\t%p ", access_control_stack_pointer(thread)); #if !defined(LISP_FEATURE_X86) && !defined(LISP_FEATURE_X86_64) @@ -269,12 +515,6 @@ regs_cmd(char __attribute__((unused)) **ptr) printf("DYNAMIC\t=\t%p\n", (void*)current_dynamic_space); #endif -#ifndef ALLOCATION_POINTER - printf("ALLOC\t=\t%p\n", (void*)dynamic_space_free_pointer); -#else - printf("ALLOC\t=\t%p\n", (void*)SymbolValue(ALLOCATION_POINTER, thread)); -#endif - #ifndef LISP_FEATURE_GENCGC printf("TRIGGER\t=\t%p\n", (void*)current_auto_gc_trigger); #endif @@ -295,7 +535,7 @@ call_cmd(char **ptr) lispobj *obj = native_pointer(thing); switch (widetag_of(obj)) { case SYMBOL_WIDETAG: - function = symbol_function(obj); + function = symbol_function((struct symbol*)obj); if (function == NIL) { printf("Symbol 0x%08lx is undefined.\n", (long unsigned)thing); return 0; @@ -394,13 +634,6 @@ exit_cmd(char __attribute__((unused)) **ptr) return 1; // 'done' flag } -static int -purify_cmd(char __attribute__((unused)) **ptr) -{ - purify(NIL, NIL); - return 0; -} - static void print_context(os_context_t *context) { @@ -411,13 +644,8 @@ print_context(os_context_t *context) brief_print((lispobj)(*os_context_register_addr(context,i))); } -#if defined(LISP_FEATURE_DARWIN) && defined(LISP_FEATURE_PPC) - printf("DAR:\t\t 0x%08lx\n", (unsigned long)(*os_context_register_addr(context, 41))); - printf("DSISR:\t\t 0x%08lx\n", (unsigned long)(*os_context_register_addr(context, 42))); -#endif #ifndef REG_PC - printf("PC:\t\t 0x%08lx\n", - (unsigned long)(*os_context_pc_addr(context))); + printf("PC:\t\t 0x%08lx\n", (unsigned long)os_context_pc(context)); #endif } @@ -425,7 +653,7 @@ static int print_context_cmd(char **ptr) { int free_ici; - struct thread *thread=arch_os_get_current_thread(); + struct thread *thread=get_sb_vm_thread(); free_ici = fixnum_value(read_TLS(FREE_INTERRUPT_CONTEXT_INDEX,thread)); @@ -439,12 +667,11 @@ print_context_cmd(char **ptr) printf("printing context %d\n", index); print_context(nth_interrupt_context(index, thread)); } else { - printf("There aren't that many/few contexts.\n"); printf("There are %d interrupt contexts.\n", free_ici); } } else { if (free_ici == 0) - printf("There are no interrupt contexts!\n"); + printf("There are no interrupt contexts.\n"); else { printf("There are %d interrupt contexts.\n", free_ici); printf("printing context %d\n", free_ici - 1); @@ -486,24 +713,23 @@ static int catchers_cmd(char __attribute__((unused)) **ptr) { struct catch_block *catch = (struct catch_block *) - read_TLS(CURRENT_CATCH_BLOCK, arch_os_get_current_thread()); + read_TLS(CURRENT_CATCH_BLOCK, get_sb_vm_thread()); if (catch == NULL) printf("There are no active catchers!\n"); else { while (catch != NULL) { - printf("0x%08lX:\n\tuwp: 0x%08lX\n\tfp: 0x%08lX\n\t" - "code: 0x%08lX\n\tentry: 0x%08lX\n\ttag: ", - (long unsigned)catch, - (long unsigned)(catch->uwp), - (long unsigned)(catch->cfp), -#if defined(LISP_FEATURE_X86) || defined(LISP_FEATURE_X86_64) - (long unsigned)component_ptr_from_pc((void*)catch->entry_pc) - + OTHER_POINTER_LOWTAG, + printf("%p:\n\tuwp : %p\n\tfp : %p\n\t" + "code : %p\n\tentry: %p\n\ttag: ", + catch, + catch->uwp, + catch->cfp, +#if defined(LISP_FEATURE_X86) || defined(LISP_FEATURE_X86_64) || defined(LISP_FEATURE_ARM64) + component_ptr_from_pc((void*)catch->entry_pc), #else - (long unsigned)(catch->code), + (void*)catch->code, #endif - (long unsigned)(catch->entry_pc)); + (void*)(catch->entry_pc)); brief_print((lispobj)catch->tag); catch = catch->previous_catch; } @@ -511,24 +737,20 @@ catchers_cmd(char __attribute__((unused)) **ptr) return 0; } -static int -grab_sigs_cmd(char __attribute__((unused)) **ptr) -{ - extern void sigint_init(void); - - printf("Grabbing signals.\n"); - sigint_init(); - return 0; -} - -static void -sub_monitor(void) +extern boolean gc_active_p; +extern FILE *gc_activitylog_file; +void +ldb_monitor(void) { struct cmd *cmd, *found; char buf[256]; char *line, *ptr, *token; int ambig; + printf("Welcome to LDB, a low-level debugger for the Lisp runtime environment.\n"); + if (gc_active_p) printf("(GC in progress, oldspace=%d, newspace=%d)\n", + from_space, new_space); + if (gc_activitylog_file) fflush(gc_activitylog_file); if (!ldb_in) { #ifndef LISP_FEATURE_WIN32 ldb_in = fopen("/dev/tty","r+"); @@ -579,31 +801,264 @@ sub_monitor(void) } } +/* what we do when things go badly wrong at a low level */ void -ldb_monitor() +monitor_or_something() { - jmp_buf oldbuf; - - memcpy(oldbuf, curbuf, sizeof(oldbuf)); - - printf("Welcome to LDB, a low-level debugger for the Lisp runtime environment.\n"); + ldb_monitor(); +} - setjmp(curbuf); +#ifdef STANDALONE_LDB +void gc_stop_the_world() { } // do nothing +void gc_start_the_world() { } // do nothing +#include <errno.h> +#include "core.h" +#include "gencgc-private.h" +struct lisp_startup_options lisp_startup_options; + +void unwind_binding_stack() { lose("Can't unwind binding stack"); } +FILE *prepare_to_save(__attribute__((unused)) char *filename, + __attribute__((unused)) boolean prepend_runtime, + __attribute__((unused)) void **runtime_bytes, + __attribute__((unused)) size_t *runtime_size) { + lose("Can't prepare_to_save"); +} +boolean save_runtime_to_filehandle(__attribute__((unused)) FILE *output, + __attribute__((unused)) void *runtime, + __attribute__((unused)) size_t runtime_size, + __attribute__((unused)) int application_type) { + lose("Can't save_runtime_to_filehandle"); +} +boolean save_to_filehandle(__attribute__((unused)) FILE *file, + __attribute__((unused)) char *filename, + __attribute__((unused)) lispobj init_function, + __attribute__((unused)) boolean make_executable, + __attribute__((unused)) boolean save_runtime_options, + __attribute__((unused)) int core_compression_level) { + lose("Can't save_to_filehandle"); +} - sub_monitor(); +static size_t checked_read(char *legend, int fd, void* buf, size_t n) +{ + size_t result = read(fd, buf, n); + if (result != n) { lose("read failed, errno=%d", errno); } + if (legend) fprintf(stderr, "%s: %lx bytes\n", legend, n); + return result; +} - memcpy(curbuf, oldbuf, sizeof(curbuf)); +char *pagetypedesc(int type) +{ + static char what[4]; + switch (type) { + case PAGE_TYPE_CODE: return "code"; + case PAGE_TYPE_BOXED: return "boxed"; + case PAGE_TYPE_UNBOXED: return "raw"; + case PAGE_TYPE_MIXED: return "mixed"; + default: snprintf(what, 4, "%d", type); return what; + } } -void -throw_to_monitor() +extern void gc_allocate_ptes(); +extern void recompute_gen_bytes_allocated(); +extern void print_generation_stats(); +extern struct thread *alloc_thread_struct(void*); + +int load_gc_crashdump(char* pathname) { - longjmp(curbuf, 1); + int fd; + os_context_t *contexts[10], *context; + struct thread* threads = 0; + struct thread dummy; + fd = open(pathname, O_RDONLY); + if (fd < 0) { + fprintf(stderr, "can't open %s\n", pathname); + exit(1); + } + struct crash_preamble preamble; + struct crash_thread_preamble thread_preamble; + checked_read("preamble", fd, &preamble, sizeof preamble); + printf("static=%"OBJ_FMTX" nbytes=%x\n", preamble.static_start, (int)preamble.static_nbytes); + printf("heap_start=%"OBJ_FMTX" npages=%d\n", preamble.dynspace_start, (int)preamble.dynspace_npages); + // pin_dynspace_code is for display only. It gets recomputed as the + // logical OR of all threads' values of *GC-PIN-CODE-PAGES*. + printf("sprof_enabled=%d pin_dynspace_code=%d packages=%p\n", + preamble.sprof_enabled, preamble.pin_dynspace_code, + (void*)preamble.lisp_package_vector); + lisp_package_vector = preamble.lisp_package_vector; + sb_sprof_enabled = preamble.sprof_enabled; + if (preamble.signature != CRASH_PREAMBLE_SIGNATURE) + lose("Can't load crashdump: bad header (have %"OBJ_FMTX", expect %"OBJ_FMTX")", + preamble.signature, (uword_t)CRASH_PREAMBLE_SIGNATURE); + if (preamble.card_size != GENCGC_CARD_BYTES) + lose("Can't load crashdump: memory parameters differ"); + gc_card_table_nbits = preamble.card_table_nbits; + gc_allocate_ptes(); + next_free_page = preamble.dynspace_npages; + // static + readonly + checked_read("static", fd, (char*)STATIC_SPACE_START, preamble.static_nbytes); + static_space_free_pointer = (lispobj*)(STATIC_SPACE_START + preamble.static_nbytes); + if (preamble.readonly_nbytes) { + // READ_ONLY_SPACE_START = preamble.readonly_start; + os_alloc_gc_space(READ_ONLY_CORE_SPACE_ID, 0, (char*)preamble.readonly_start, + ALIGN_UP(preamble.readonly_nbytes, 4096)); + checked_read("R/O", fd, (char*)preamble.readonly_start, preamble.readonly_nbytes); + } + read_only_space_free_pointer = (lispobj*)(READ_ONLY_SPACE_START + preamble.readonly_nbytes); + // + DYNAMIC_SPACE_START = preamble.dynspace_start; + long dynspace_nbytes = preamble.dynspace_npages * GENCGC_PAGE_BYTES; + char* dynspace = os_alloc_gc_space(DYNAMIC_CORE_SPACE_ID, 0, (char*)preamble.dynspace_start, + DEFAULT_DYNAMIC_SPACE_SIZE); + if (dynspace != (char*)preamble.dynspace_start) + lose("Didn't map dynamic space where expected: %p vs %p", + dynspace, (char*)preamble.dynspace_start); + checked_read("dynamic", fd, (char*)DYNAMIC_SPACE_START, dynspace_nbytes); + fprintf(stderr, "snapshot: %"PRIdPTR" pages in use (%ld bytes)\n", + next_free_page, dynspace_nbytes); + checked_read("PTE", fd, page_table, sizeof (struct page) * next_free_page); + recompute_gen_bytes_allocated(); + checked_read("cardmark", fd, gc_card_mark, 1+gc_card_table_mask); + print_generation_stats(); +#ifdef LISP_FEATURE_IMMOBILE_SPACE + extern void gc_init_immobile(), + calc_immobile_space_bounds(), + write_protect_immobile_space(); + gc_assert(preamble.fixedobj_size == FIXEDOBJ_SPACE_SIZE); + gc_assert(preamble.text_size == TEXT_SPACE_SIZE); + FIXEDOBJ_SPACE_START = preamble.fixedobj_start; + TEXT_SPACE_START = preamble.text_start; + fixedobj_free_pointer = (lispobj*)preamble.fixedobj_free_pointer; + text_space_highwatermark = (lispobj*)preamble.text_space_highwatermark; + os_alloc_gc_space(IMMOBILE_FIXEDOBJ_CORE_SPACE_ID, 0, (char*)FIXEDOBJ_SPACE_START, + FIXEDOBJ_SPACE_SIZE); + os_alloc_gc_space(IMMOBILE_TEXT_CORE_SPACE_ID, 0, (char*)TEXT_SPACE_START, + TEXT_SPACE_SIZE); + gc_init_immobile(); // allocate the page tables + calc_immobile_space_bounds(); + // Read fixedobj space + int usage = (uword_t)fixedobj_free_pointer - FIXEDOBJ_SPACE_START; + checked_read("fixedobj", fd, (char*)FIXEDOBJ_SPACE_START, usage); + // Always read the whole page table regardless of the current space usage + int total_npages = FIXEDOBJ_SPACE_SIZE / IMMOBILE_CARD_BYTES; + checked_read("fixedobj_PTE", fd, fixedobj_pages, total_npages * sizeof sizeof(struct fixedobj_page)); + // Read text space + usage = (uword_t)text_space_highwatermark - TEXT_SPACE_START; + char *tlsf_memory_end = (char*)TEXT_SPACE_START + TEXT_SPACE_SIZE; + tlsf_mem_start = preamble.tlsf_mem_start; + fprintf(stderr, "tlsf_mem_start=%p\n", tlsf_mem_start); + int tlsf_memory_size = tlsf_memory_end - (char*)tlsf_mem_start; + checked_read("text", fd, (char*)TEXT_SPACE_START, usage+3*N_WORD_BYTES); + memcpy(tlsf_memory_end-3*N_WORD_BYTES, preamble.sentinel_block, 3*N_WORD_BYTES); + total_npages = TEXT_SPACE_SIZE / IMMOBILE_CARD_BYTES; + int n_bitmap_elts = ALIGN_UP(total_npages, 32) / 32; + checked_read("text_gen", fd, text_page_genmask, total_npages); // 1 byte per page + checked_read("text_WP", fd, text_page_touched_bits, n_bitmap_elts * sizeof (int)); + tlsf_control = preamble.tlsf_control_address; // already mapped at a fixed address + // TLSF control was mapped in gc_init_immobile() + checked_read("TLSF_control", fd, tlsf_control, preamble.tlsf_control_size); + int n_tlsf_pages = tlsf_memory_size / IMMOBILE_CARD_BYTES; + fprintf(stderr, "%d TLSF pages\n", n_tlsf_pages); + tlsf_page_sso = malloc(n_tlsf_pages * sizeof (short)); + checked_read("TLSF_sso", fd, tlsf_page_sso, n_tlsf_pages * sizeof (short)); + write_protect_immobile_space(); +#endif + fprintf(stderr, "%d threads:\n", (int)preamble.nthreads); + int i; + for(i=0; i<(int)preamble.nthreads; ++i) { + struct thread* th = alloc_thread_struct(0); + // Push it on the front + th->prev = 0; + th->next = threads; + if (threads) threads->prev = th; + threads = th; + checked_read("thread", fd, &thread_preamble, sizeof thread_preamble); + uword_t* stackptr = (uword_t*)((char*)th->control_stack_end - thread_preamble.control_stack_nbytes); + context = contexts[i] = malloc(preamble.sizeof_context); + nth_interrupt_context(0, th) = context; + if (thread_preamble.has_context) { + checked_read(" ctxt", fd, context, preamble.sizeof_context); + } +#ifdef LISP_FEATURE_C_STACK_IS_CONTROL_STACK + *os_context_sp_addr(context) = (uword_t)stackptr; +#ifdef LISP_FEATURE_X86 + *os_context_register_addr(context,reg_SP) = (os_context_register_t)stackptr; +#endif + gc_assert(*os_context_register_addr(context,reg_SP) == (os_context_register_t)stackptr); +#else + *os_context_register_addr(context, reg_CSP) = (uword_t)stackptr; +#endif + checked_read(" stack", fd, stackptr, thread_preamble.control_stack_nbytes); + checked_read(" bindings", fd, th->binding_stack_start, thread_preamble.binding_stack_nbytes); + // Skip over the initial words of the thread structure that was saved + // in the file, so that binding_stack_start remains as is in the + // newly allocated structure. The last word is the only one we want to keep. + int skip = sizeof dummy-N_WORD_BYTES; + checked_read(0, fd, &dummy, skip); + checked_read(" TLS", fd, &th->lisp_thread, preamble.tls_size-skip); + write_TLS(FREE_INTERRUPT_CONTEXT_INDEX, make_fixnum(1), th); + struct thread_instance* instance = (void*)(th->lisp_thread - INSTANCE_POINTER_LOWTAG); + lispobj name = instance->name; + char* cname = (gc_managed_addr_p(name) && + widetag_of(native_pointer(name)) == SIMPLE_BASE_STRING_WIDETAG) + ? (char*)name+1 : 0; + fprintf(stderr, "thread @ %p originally %p, %d bind_stk words, %d val_stk words '%s'\n", + th, (void*)thread_preamble.address, + (int)(thread_preamble.binding_stack_nbytes>>WORD_SHIFT), + (int)(thread_preamble.control_stack_nbytes>>WORD_SHIFT), + cname); + // Scan thread stack looking for words which could be valid pointers, + // but don't find an object when the heap is scanned. + // Realizing that failure to find isn't necessarily an error, + // there's nothing that we can do except show some information. + int nwords = thread_preamble.control_stack_nbytes>>WORD_SHIFT, wordindex; + int n_definitely_valid = 0, n_dangling = 0; + for (wordindex = 0; wordindex < nwords; ++wordindex) { + lispobj word = stackptr[wordindex]; + if (DYNAMIC_SPACE_START <= word && word < DYNAMIC_SPACE_START + dynamic_space_size + && (is_lisp_pointer(word) || + is_code(page_table[find_page_index((void*)word)].type))) { + lispobj* found = search_dynamic_space((void*)word); + if (found) { + __attribute__((unused)) page_index_t ind = find_page_index(found); +#if 0 + fprintf(stderr, " sp[%5d] = %"OBJ_FMTX" -> %p (g%d,%s)\n", + wordindex, word, found, + page_table[ind].gen, pagetypedesc(page_table[ind].type)); +#endif + ++n_definitely_valid; + } else { + fprintf(stderr, " ! sp[%5d] = %"OBJ_FMTX" (not found)\n", + wordindex, word); + ++n_dangling; + } + } + } + fprintf(stderr, "%d valid pointers", n_definitely_valid); + if (n_dangling) fprintf(stderr, " (%d dangling)", n_dangling); + putc('\n', stderr); + } + char signature[8]; + checked_read("sig", fd, signature, 8); + gc_assert(!strncmp(signature, "SB.Crash", 8)); + gc_assert(read(fd, signature, 1) == 0); + close(fd); + all_threads = threads; + return 0; } -/* what we do when things go badly wrong at a low level */ -void -monitor_or_something() +int main(int argc, char *argv[], char **envp) { + extern void calc_asm_routine_bounds(); + if (argc != 2) { + fprintf(stderr, "Usage: ldb crashdump\n"); + return 1; + } + boolean have_hardwired_spaces = os_preinit(argv, envp); + allocate_lisp_dynamic_space(have_hardwired_spaces); + gc_init(); + load_gc_crashdump(argv[1]); + calc_asm_routine_bounds(); + gencgc_verbose = 1; ldb_monitor(); } +#endif diff --git a/src/runtime/murmur_hash.c b/src/runtime/murmur_hash.c index 23ca405bfe..3340ec6a58 100644 --- a/src/runtime/murmur_hash.c +++ b/src/runtime/murmur_hash.c @@ -22,13 +22,6 @@ #define ROTL32(x, r) ((x) << (r)) | ((x) >> (32 - (r))) -#define FMIX32(h) \ - (h) ^= (h) >> 16; \ - (h) *= 0x85ebca6b; \ - (h) ^= (h) >> 13; \ - (h) *= 0xc2b2ae35; \ - (h) ^= (h) >> 16; - uint32_t gpr_murmur_hash3(const void* key, size_t len, uint32_t seed) { uint32_t h1 = seed; uint32_t k1; @@ -84,11 +77,7 @@ uint32_t murmur3_fmix32(uint32_t k) { } #ifdef LISP_FEATURE_64_BIT uint64_t murmur3_fmix64(uint64_t k) { - k ^= k >> 33; - k *= 0xff51afd7ed558ccdULL; - k ^= k >> 33; - k *= 0xc4ceb9fe1a85ec53ULL; - k ^= k >> 33; + FMIX64(k); return k; } #endif diff --git a/src/runtime/murmur_hash.h b/src/runtime/murmur_hash.h index 7e8401f647..0edfca428c 100644 --- a/src/runtime/murmur_hash.h +++ b/src/runtime/murmur_hash.h @@ -16,8 +16,8 @@ * */ -#ifndef GRPC_CORE_LIB_SUPPORT_MURMUR_HASH_H -#define GRPC_CORE_LIB_SUPPORT_MURMUR_HASH_H +#ifndef _MURMUR_HASH_H_ +#define _MURMUR_HASH_H_ #include <stdint.h> #include <stddef.h> @@ -29,4 +29,18 @@ uint32_t murmur3_fmix32(uint32_t); uint64_t murmur3_fmix64(uint64_t); #endif -#endif /* GRPC_CORE_LIB_SUPPORT_MURMUR_HASH_H */ +#define FMIX32(h) \ + (h) ^= (h) >> 16; \ + (h) *= 0x85ebca6b; \ + (h) ^= (h) >> 13; \ + (h) *= 0xc2b2ae35; \ + (h) ^= (h) >> 16 + +#define FMIX64(h) \ + (h) ^= (h) >> 33; \ + (h) *= 0xff51afd7ed558ccdULL; \ + (h) ^= (h) >> 33; \ + (h) *= 0xc4ceb9fe1a85ec53ULL; \ + (h) ^= (h) >> 33 + +#endif /* _MURMUR_HASH_H_ */ diff --git a/src/runtime/os-common.c b/src/runtime/os-common.c index 506c5c010e..0f1e455143 100644 --- a/src/runtime/os-common.c +++ b/src/runtime/os-common.c @@ -12,10 +12,12 @@ #include <stdio.h> #include <errno.h> #include <string.h> +#include <stdlib.h> #include "sbcl.h" #include "globals.h" #include "runtime.h" +#include "gc-assert.h" #include "genesis/config.h" #include "genesis/constants.h" #include "genesis/cons.h" @@ -23,11 +25,11 @@ #include "genesis/symbol.h" #include "genesis/static-symbols.h" #include "thread.h" -#include "sbcl.h" #include "os.h" #include "arch.h" #include "interr.h" #include "immobile-space.h" +#include "code.h" #if defined(LISP_FEATURE_OS_PROVIDES_DLOPEN) && !defined(LISP_FEATURE_WIN32) # include <dlfcn.h> #endif @@ -46,8 +48,7 @@ int install_sig_memory_fault_handler = INSTALL_SIG_MEMORY_FAULT_HANDLER; /* Except for os_zero, these routines are only called by Lisp code. * These routines may also be replaced by os-dependent versions - * instead. See hpux-os.c for some useful restrictions on actual - * usage. */ + * instead. */ #ifdef LISP_FEATURE_CHENEYGC void @@ -74,8 +75,8 @@ os_zero(os_vm_address_t addr, os_vm_size_t length) /* Now deallocate and allocate the block so that it faults in * zero-filled. */ - os_invalidate(block_start, block_size); - addr = os_validate(NOT_MOVABLE, block_start, block_size); + os_deallocate(block_start, block_size); + addr = os_alloc_gc_space(0, NOT_MOVABLE, block_start, block_size); if (addr == NULL || addr != block_start) lose("os_zero: block moved! %p ==> %p", block_start, addr); @@ -83,17 +84,33 @@ os_zero(os_vm_address_t addr, os_vm_size_t length) } #endif +#include "sys_mmap.inc" +#ifdef LISP_FEATURE_USE_SYS_MMAP +os_vm_address_t os_allocate(os_vm_size_t len) { + void* answer = sbcl_mmap(0, len, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, 0, 0); + if (answer == MAP_FAILED) return 0; + return answer; +} +void os_deallocate(os_vm_address_t addr, os_vm_size_t len) { + sbcl_munmap(addr, len); +} +#else os_vm_address_t os_allocate(os_vm_size_t len) { - return os_validate(MOVABLE, (os_vm_address_t)NULL, len); + return os_alloc_gc_space(0, MOVABLE, (os_vm_address_t)NULL, len); } void os_deallocate(os_vm_address_t addr, os_vm_size_t len) { - os_invalidate(addr,len); +#ifdef LISP_FEATURE_WIN32 + gc_assert(VirtualFree(addr, 0, MEM_RELEASE)); +#else + if (munmap(addr, len) == -1) perror("munmap"); +#endif } +#endif int os_get_errno(void) @@ -101,9 +118,7 @@ os_get_errno(void) return errno; } - -#if defined(LISP_FEATURE_SB_THREAD) && (!defined(CANNOT_USE_POSIX_SEM_T) || defined(LISP_FEATURE_WIN32)) - +#if defined LISP_FEATURE_SB_THREAD && defined LISP_FEATURE_UNIX && !defined USE_DARWIN_GCD_SEMAPHORES void os_sem_init(os_sem_t *sem, unsigned int value) { @@ -139,10 +154,9 @@ os_sem_destroy(os_sem_t *sem) #endif -/* When :LINKAGE-TABLE is enabled, the special category of /static/ foreign - * symbols disappears. Foreign fixups are resolved to linkage table locations - * during genesis, and for each of them a record is added to - * REQUIRED_FOREIGN_SYMBOLS vector, of the form "name" for a function reference, +/* Genesis-time foreign fixups are resolved to linkage table locations + * and for each of them a record is added to the REQUIRED_FOREIGN_SYMBOLS + * vector, of the form "name" for a function reference, * or ("name") for a data reference. "name" is a base-string. * * Before any code in lisp image can be called, we have to resolve all @@ -150,7 +164,28 @@ os_sem_destroy(os_sem_t *sem) * table entry for each element of REQUIRED_FOREIGN_SYMBOLS. */ -#if defined(LISP_FEATURE_LINKAGE_TABLE) && !defined(LISP_FEATURE_WIN32) +void os_link_from_pointer_table(lispobj* table_ptr) +{ + ALIEN_LINKAGE_TABLE_SPACE_START = + (uword_t)os_alloc_gc_space(ALIEN_LINKAGE_TABLE_CORE_SPACE_ID, 0, 0, + ALIEN_LINKAGE_TABLE_SPACE_SIZE); + // Prefill the alien linkage table so that shrinkwrapped executables which link in + // all their C library dependencies can avoid linking with -ldl + // but extern-alien still works for newly compiled code. + gc_assert(table_ptr); + int entry_index = 0; + int count; + extern int alien_linkage_table_n_prelinked; + count = alien_linkage_table_n_prelinked = *table_ptr++; + for ( ; count-- ; entry_index++ ) { + boolean datap = *table_ptr == (lispobj)-1; // -1 can't be a function address + if (datap) + ++table_ptr; + arch_write_linkage_table_entry(entry_index, (void*)*table_ptr++, datap); + } +} + +#if !defined(LISP_FEATURE_WIN32) && defined(LISP_FEATURE_OS_PROVIDES_DLOPEN) void * os_dlsym_default(char *name) { @@ -159,49 +194,37 @@ os_dlsym_default(char *name) } #endif -int lisp_linkage_table_n_prelinked; +#ifdef LISP_FEATURE_SB_PRELINK_LINKAGE_TABLE +extern lispobj lisp_linkage_values; +#endif + +int alien_linkage_table_n_prelinked; void os_link_runtime() { - // There is a potentially better technique we could use which would simplify - // this function, rendering REQUIRED_FOREIGN_SYMBOLS unnecessary, namely: - // all we need are two prefilled entries: one for dlsym() itself, and one - // for the allocation region overflow handler ("alloc" or "alloc_tramp"). - // Lisp can fill in the linkage table as the very first action on startup. -#ifdef LISP_FEATURE_LINKAGE_TABLE - int entry_index = 0; - lispobj symbol_name; - char *namechars; - boolean datap; - void* result; - int j; - - if (lisp_linkage_table_n_prelinked) + if (alien_linkage_table_n_prelinked) return; // Linkage was already performed by coreparse +#ifndef LISP_FEATURE_SB_PRELINK_LINKAGE_TABLE struct vector* symbols = VECTOR(SymbolValue(REQUIRED_FOREIGN_SYMBOLS,0)); - lisp_linkage_table_n_prelinked = fixnum_value(symbols->length); - for (j = 0 ; j < lisp_linkage_table_n_prelinked ; ++j) + alien_linkage_table_n_prelinked = vector_len(symbols); + int j; + for (j = 0 ; j < alien_linkage_table_n_prelinked ; ++j) { lispobj item = symbols->data[j]; - datap = listp(item); - symbol_name = datap ? CONS(item)->car : item; - namechars = (void*)(intptr_t)(VECTOR(symbol_name)->data); - result = os_dlsym_default(namechars); + boolean datap = listp(item); + lispobj symbol_name = datap ? CONS(item)->car : item; + char *namechars = (void*)(intptr_t)(VECTOR(symbol_name)->data); + void* result = os_dlsym_default(namechars); - if (entry_index == 0) { -#ifdef LISP_FEATURE_WIN32 - os_validate_recommit(LINKAGE_TABLE_SPACE_START, os_vm_page_size); -#endif - } if (result) { - arch_write_linkage_table_entry(entry_index, result, datap); + arch_write_linkage_table_entry(j, result, datap); } else { // startup might or might not work. ymmv fprintf(stderr, "Missing required foreign symbol '%s'\n", namechars); } - - ++entry_index; } -#endif /* LISP_FEATURE_LINKAGE_TABLE */ +#else + os_link_from_pointer_table(&lisp_linkage_values); +#endif } void os_unlink_runtime() @@ -222,6 +245,9 @@ gc_managed_heap_space_p(lispobj addr) addr < DYNAMIC_0_SPACE_START + dynamic_space_size) || (DYNAMIC_1_SPACE_START <= addr && addr < DYNAMIC_1_SPACE_START + dynamic_space_size) +#endif +#ifdef LISP_FEATURE_DARWIN_JIT + || (STATIC_CODE_SPACE_START <= addr && addr < STATIC_CODE_SPACE_END) #endif ) return 1; @@ -230,42 +256,113 @@ gc_managed_heap_space_p(lispobj addr) #ifndef LISP_FEATURE_WIN32 +#if defined LISP_FEATURE_MIPS +#include <sys/utsname.h> +#endif /* Remap a part of an already existing memory mapping from a file, * and/or create a new mapping as need be */ -void* load_core_bytes(int fd, int offset, os_vm_address_t addr, os_vm_size_t len) +void* load_core_bytes(int fd, os_vm_offset_t offset, os_vm_address_t addr, os_vm_size_t len, + int is_readonly_space) { +#if defined LISP_FEATURE_MIPS + /* Of the few MIPS machines I have access to, one definitely exhibits a + * horrible bug that mmap() persists MAP_PRIVATE pages back to disk, + * even though we alwayas open a core file as O_RDONLY. This is a kooky criterion + * to restrict the test by, but I didn't want it to be more general */ + static int buggy_map_private; + if (!buggy_map_private) { + struct utsname name; + uname(&name); + if (!strcmp(name.version, "#1 SMP PREEMPT Mon Aug 3 14:22:54 PDT 2015") && + !strcmp(name.release, "4.1.4")) { + buggy_map_private = 1; + fprintf(stderr, "WARNING: assuming that MAP_PRIVATE does not work on this kernel\n"); + } else { + // fprintf(stderr, "INFO: kernel looks OK: [%s] [%s]\n", name.release, name.version); + buggy_map_private = -1; + } + } + if (buggy_map_private == 1) { + off_t old = lseek(fd, 0, SEEK_CUR); + lseek(fd, offset, SEEK_SET); + read(fd, addr, len); + lseek(fd, old, SEEK_SET); + return addr; + } +#endif int fail = 0; -#ifdef LISP_FEATURE_HPUX - // Revision afcfb8b5da said that mmap() didn't work on HPUX, changing to use read() instead. - // Strangely it also read 4K at a time into a buffer and used memcpy to transfer the buffer. - // I don't see why, and given the lack of explanation, I've simplified to 1 read. - fail = lseek(fd, offset, SEEK_SET) == (off_t)-1 || read(fd, addr, len) != (ssize_t)len; - // This looks bogus but harmlesss, so I'm leaving it. - os_flush_icache(addr, len); -#else os_vm_address_t actual; - actual = mmap(addr, len, - // If mapping to a random address, then the assumption is - // that we're not going to execute the core; nor should we write to it. - // However, the addr=0 case is for 'editcore' which unfortunately _does_ - // write the memory. I'd prefer that it not, - // but that's not the concern here. - addr ? OS_VM_PROT_ALL : OS_VM_PROT_READ | OS_VM_PROT_WRITE, + int protection = 0, sharing = MAP_PRIVATE; + +#ifdef LISP_FEATURE_DARWIN_JIT + protection = OS_VM_PROT_READ | (is_readonly_space ? OS_VM_PROT_EXECUTE : OS_VM_PROT_WRITE); +#else + /* If mapping to an OS-chosen address, then the assumption is that we're not going to + * execute nor write at the mapped address. (Because why would we ? The spaces from + * the core have a chosen address at this point) However, the addr=0 case is for + * 'editcore' which unfortunately _does_ write the memory. I'd prefer that it not, + * but that's not the concern here. */ + protection = (addr ? (is_readonly_space ? OS_VM_PROT_READ : OS_VM_PROT_ALL) + : OS_VM_PROT_READ | OS_VM_PROT_WRITE); + if (is_readonly_space) sharing = MAP_SHARED; +#endif + +#ifdef LISP_FEATURE_64_BIT + actual = sbcl_mmap( +#else + /* FIXME: why does using sbcl_mmap cause failure here? I would guess that it can't + * pass 'offset' correctly if LARGEFILE is mandatory, which it isn't on 64-bit. + * Deadlock should be impossible this early in core loading, I suppose, hence + * on one hand I don't care; but on the other, it would be nice to not to see + * any use of a potentially hooked mmap() API within this file. */ + actual = mmap( +#endif + addr, len, protection, // Do not pass MAP_FIXED with addr of 0, because most OSes disallow that. - MAP_PRIVATE | (addr ? MAP_FIXED : 0), + sharing | (addr ? MAP_FIXED : 0), fd, (off_t) offset); if (actual == MAP_FAILED) { - perror("mmap"); + if (errno == ENOMEM) + fprintf(stderr, "load_core_bytes: mmap(%p,%zu,...) failed with ENOMEM\n", addr, len); + else + perror("mmap"); fail = 1; } else if (addr && (addr != actual)) { fail = 1; } -#endif if (fail) - lose("load_core_bytes(%d,%x,%lx,%x) failed", fd, offset, (long)addr, (int)len); + lose("load_core_bytes(%d,%p,%p,%zx) failed", fd, (void*)(uintptr_t)offset, addr, len); return (void*)actual; } +#ifdef LISP_FEATURE_DARWIN_JIT +void* load_core_bytes_jit(int fd, os_vm_offset_t offset, os_vm_address_t addr, os_vm_size_t len) +{ + ssize_t count; + + lseek(fd, offset, SEEK_SET); + + size_t n_bytes = 65536; + char* buf = malloc(n_bytes); + + while (len) { + count = read(fd, buf, n_bytes); + + if (count <= -1) { + perror("read"); + } + + memcpy(addr, buf, count); + addr += count; + len -= count; + } + free(buf); + return (void*)0; +} +#endif + +#endif + boolean gc_managed_addr_p(lispobj addr) { @@ -284,4 +381,105 @@ gc_managed_addr_p(lispobj addr) return 0; } +uword_t os_context_pc(os_context_t* context) { + return OS_CONTEXT_PC(context); +} +void set_os_context_pc(os_context_t* context, uword_t pc) { + OS_CONTEXT_PC(context) = pc; +} +os_context_register_t* os_context_pc_addr(os_context_t* context) { + return (os_context_register_t*)&(OS_CONTEXT_PC(context)); +} + +void *successful_malloc(size_t size) +{ + void* result = malloc(size); + if (0 == result) { + lose("malloc failure"); + } else { + return result; + } + return (void *) NULL; /* dummy value: return something ... */ +} + +char *copied_string(char *string) +{ + return strcpy(successful_malloc(1+strlen(string)), string); +} + +#ifdef LISP_FEATURE_UNIX +#include "gc-internal.h" +void +os_protect(os_vm_address_t address, os_vm_size_t length, os_vm_prot_t prot) +{ +#ifdef LISP_FEATURE_SOFT_CARD_MARKS + // dynamic space should not have protections manipulated + if (find_page_index(address) >= 0) + lose("unexpected call to os_protect with software card marks"); +#endif + if (mprotect(address, length, prot) < 0) { +#ifdef LISP_FEATURE_LINUX + if (errno == ENOMEM) { + lose("An mprotect call failed with ENOMEM. This probably means that the maximum amount\n" + "of separate memory mappings was exceeded. To fix the problem, either increase\n" + "the maximum with e.g. 'echo 262144 > /proc/sys/vm/max_map_count' or recompile\n" + "SBCL with a larger value for GENCGC-PAGE-BYTES in\n" + "'src/compiler/"SBCL_TARGET_ARCHITECTURE_STRING"/parms.lisp'."); + } +#endif + lose("mprotect(%p,%lx,%d) error %d", address, (long)length, prot, errno); + } +} +#endif + +lispobj* duplicate_codeblob_offheap(lispobj code) +{ + int nwords = code_total_nwords((struct code*)(code-OTHER_POINTER_LOWTAG)); + lispobj* mem = malloc((nwords+1) * N_WORD_BYTES); + if ((uword_t)mem & LOWTAG_MASK) lose("this is unexpected\n"); + // add 1 word if not dualword aligned + lispobj* copy = (lispobj*)((uword_t)mem + ((uword_t)mem & N_WORD_BYTES)); + memcpy(copy, (char*)code-OTHER_POINTER_LOWTAG, nwords<<WORD_SHIFT); + return mem; +} + +#if 0 // interceptors for debugging so I don't have to reinvent them every time +static void decode_protbits(int prot, char result[4]) { + result[0] = (prot & PROT_READ) ? 'r' : '-'; + result[1] = (prot & PROT_WRITE) ? 'w' : '-'; + result[2] = (prot & PROT_EXEC) ? 'x' : '-'; + result[3] = 0; +} +static void decode_flagbits(int flags, char result[40]) { + char *p = result; + char delim = '{'; +#define APPEND(str) { *p++ = delim; delim = '|'; strcpy(p, str); p += sizeof str-1; } + if (flags & MAP_PRIVATE) APPEND("Pvt"); + if (flags & MAP_ANON) APPEND("Anon"); + if (flags & MAP_NORESERVE) APPEND("NoRsv"); + if (flags & MAP_JIT) APPEND("JIT"); +#undef APPEND + strcpy(p, "}"); +} +void* sbcl_mmap(void* addr, size_t length, int prot, int flags, int fd, off_t offset) { + char decoded_prot[4], decoded_flags[40]; + decode_protbits(prot, decoded_prot); + decode_flagbits(flags, decoded_flags); + void* result = mmap(addr, length, prot, flags, fd, offset); + fprintf(stderr, "mmap(%p,%lx,%s,%s,%d,%llx)=%p\n", addr, length, + decoded_prot, decoded_flags, fd, offset, result); + return result; +} +int sbcl_munmap(void* addr, size_t length) { + int result = munmap(addr, length); + fprintf(stderr, "munmap(%p,%lx)=%d\n", addr, length, result); + return result; +} +int sbcl_mprotect(void* addr, size_t length, int prot) { + char decoded_prot[4]; + decode_protbits(prot, decoded_prot); + int result = mprotect(addr, length, prot); + fprintf(stderr, "mprotect(%p,%lx,%s)=%d\n", addr, length, decoded_prot, result); + return result; +} #endif diff --git a/src/runtime/os.h b/src/runtime/os.h index 599ea69a1e..e29222d117 100644 --- a/src/runtime/os.h +++ b/src/runtime/os.h @@ -31,10 +31,10 @@ #define ENABLE_PAGE_PROTECTION 1 #endif -#ifdef LISP_FEATURE_CHENEYGC +#if defined LISP_FEATURE_CHENEYGC || defined LISP_FEATURE_SB_SAFEPOINT +// safepoint traps always require a signal handler #define INSTALL_SIG_MEMORY_FAULT_HANDLER 1 -#endif -#ifdef LISP_FEATURE_GENCGC +#elif defined LISP_FEATURE_GENCGC #define INSTALL_SIG_MEMORY_FAULT_HANDLER ENABLE_PAGE_PROTECTION #endif @@ -66,8 +66,7 @@ extern os_vm_size_t os_vm_page_size; -#if (defined(LISP_FEATURE_WIN32) && defined(LISP_FEATURE_SB_THREAD)) \ - || defined(LISP_FEATURE_LINUX) +#if defined LISP_FEATURE_WIN32 || defined LISP_FEATURE_LINUX boolean os_preinit(char *argv[], char *envp[]); #else #define os_preinit(dummy1,dummy2) (0) @@ -77,7 +76,7 @@ void os_unlink_runtime(); /* Do anything we need to do when starting up the runtime environment * in this OS. */ -extern void os_init(char *argv[], char *envp[]); +extern void os_init(); /* Install any OS-dependent low-level signal handlers which are needed * by the runtime environment. E.g. the signals raised by a violation @@ -107,21 +106,22 @@ extern void os_zero(os_vm_address_t addr, os_vm_size_t length); #define IS_THREAD_STRUCT 4 #define MOVABLE_LOW (MOVABLE|ALLOCATE_LOW) #define IS_GUARD_PAGE 8 -extern os_vm_address_t os_validate(int movable, - os_vm_address_t addr, - os_vm_size_t len); +extern os_vm_address_t os_alloc_gc_space(int space_id, int attributes, + os_vm_address_t addr, os_vm_size_t len); #ifdef LISP_FEATURE_WIN32 -void* os_validate_recommit(os_vm_address_t addr, os_vm_size_t len); +void os_commit_memory(os_vm_address_t addr, os_vm_size_t len); #endif -/* This function seems to undo the effect of os_validate(..). */ -extern void os_invalidate(os_vm_address_t addr, os_vm_size_t len); - /* This maps a file into memory, or calls lose(..) for various * failures. */ extern void* load_core_bytes(int fd, - int offset, + os_vm_offset_t offset, + os_vm_address_t addr, + os_vm_size_t len, + int execute); +extern void* load_core_bytes_jit(int fd, + os_vm_offset_t offset, os_vm_address_t addr, os_vm_size_t len); @@ -154,9 +154,6 @@ os_context_register_addr(os_context_t *context, int offset); os_context_register_t * os_context_float_register_addr(os_context_t *context, int offset); -/* Given a signal context, return the address for storage of the - * program counter for that context. */ -os_context_register_t *os_context_pc_addr(os_context_t *context); #ifdef ARCH_HAS_NPC_REGISTER os_context_register_t *os_context_npc_addr(os_context_t *context); #endif @@ -168,12 +165,14 @@ os_context_register_t *os_context_lr_addr(os_context_t *context); * system stack pointer for that context. */ #ifdef ARCH_HAS_STACK_POINTER os_context_register_t *os_context_sp_addr(os_context_t *context); -#if (defined(LISP_FEATURE_X86)||defined(LISP_FEATURE_X86_64)) && \ - (defined(LISP_FEATURE_DARWIN)||defined(LISP_FEATURE_LINUX)||defined(LISP_FEATURE_WIN32)) +// os_context_fp_addr might not be defined os_context_register_t *os_context_fp_addr(os_context_t *context); -#define os_context_frame_pointer(context) *os_context_fp_addr(context) +#if defined LISP_FEATURE_X86_64 +# define os_context_frame_pointer(context) *os_context_register_addr(context,reg_RBP) +#elif defined LISP_FEATURE_X86 +# define os_context_frame_pointer(context) *os_context_register_addr(context,reg_EBP) #else -#define os_context_frame_pointer(context) 0 +# define os_context_frame_pointer(context) 0 #endif #endif /* Given a signal context, return the address for storage of the @@ -187,7 +186,7 @@ sigset_t *os_context_sigmask_addr(os_context_t *context); /* These are not architecture-specific functions, but are instead * general utilities defined in terms of the architecture-specific - * function os_validate(..) and os_invalidate(..). + * function os_alloc_gc_space(..) and os_deallocate(..). */ extern os_vm_address_t os_allocate(os_vm_size_t len); extern void os_deallocate(os_vm_address_t addr, os_vm_size_t len); @@ -221,8 +220,8 @@ extern char *os_get_runtime_executable_path(); #define OS_VM_SIZE_FMT PRIuPTR #define OS_VM_SIZE_FMTX PRIxPTR -#ifdef LISP_FEATURE_SB_THREAD -# ifndef CANNOT_USE_POSIX_SEM_T +#if defined LISP_FEATURE_SB_THREAD && defined LISP_FEATURE_UNIX +# ifndef USE_DARWIN_GCD_SEMAPHORES # include <semaphore.h> typedef sem_t os_sem_t; # endif @@ -232,4 +231,26 @@ extern char *os_get_runtime_executable_path(); void os_sem_destroy(os_sem_t *sem); #endif +extern int os_reported_page_size; + +// Opaque context accessor +uword_t os_context_pc(os_context_t*); +void set_os_context_pc(os_context_t*, uword_t); + +#ifdef LISP_FEATURE_WIN32 + +#define GETPAGESIZE 4096 +# define FTELL _ftelli64 +# define FSEEK _fseeki64 +# define LSEEK _lseeki64 +typedef __int64 ftell_type; + +#else +#define GETPAGESIZE getpagesize() +#define FTELL ftell +#define FSEEK fseek +#define LSEEK lseek +typedef long ftell_type; +#endif + #endif diff --git a/src/runtime/parse.c b/src/runtime/parse.c index 450c264e05..af1aaea633 100644 --- a/src/runtime/parse.c +++ b/src/runtime/parse.c @@ -16,7 +16,7 @@ #include <ctype.h> #include "sbcl.h" -#if defined(LISP_FEATURE_WIN32) && defined(LISP_FEATURE_SB_THREAD) +#ifdef LISP_FEATURE_WIN32 #include "pthreads_win32.h" #else #include <signal.h> @@ -34,7 +34,6 @@ #include "arch.h" #include "search.h" #include "thread.h" -#include "getallocptr.h" #include "genesis/simple-fun.h" #include "genesis/fdefn.h" @@ -208,12 +207,12 @@ int parse_addr(char **ptr, boolean safely, char **output) static lispobj lookup_symbol(char *name) { uword_t ranges[][2] = { - { STATIC_SPACE_START, (uword_t)static_space_free_pointer }, + { STATIC_SPACE_OBJECTS_START, (uword_t)static_space_free_pointer }, #ifdef LISP_FEATURE_IMMOBILE_SPACE { FIXEDOBJ_SPACE_START, (uword_t)fixedobj_free_pointer }, #endif #if defined(LISP_FEATURE_GENCGC) - { DYNAMIC_SPACE_START, (uword_t)get_alloc_pointer() } + { DYNAMIC_SPACE_START, dynamic_space_highwatermark() } #else { (uword_t)current_dynamic_space, (uword_t)get_alloc_pointer() } #endif @@ -264,7 +263,7 @@ static int parse_regnum(char *s) int parse_lispobj(char **ptr, lispobj *output) { - struct thread *thread=arch_os_get_current_thread(); + struct thread *thread=get_sb_vm_thread(); char *token = parse_token(ptr); uword_t pointer; lispobj result; diff --git a/src/runtime/ppc-arch.c b/src/runtime/ppc-arch.c index 92e1512075..17c69b6332 100644 --- a/src/runtime/ppc-arch.c +++ b/src/runtime/ppc-arch.c @@ -23,13 +23,14 @@ #include "interr.h" #include "breakpoint.h" #include "alloc.h" +#include "pseudo-atomic.h" #if defined(LISP_FEATURE_GENCGC) #include "gencgc-alloc-region.h" #endif #ifdef LISP_FEATURE_SB_THREAD -#include "getallocptr.h" +#include "pseudo-atomic.h" #endif /* The header files may not define PT_DAR/PT_DSISR. This definition @@ -45,10 +46,8 @@ Caveat callers. */ -#if defined (LISP_FEATURE_DARWIN) || defined(LISP_FEATURE_LINUX) #ifndef PT_DAR #define PT_DAR 41 -#endif #ifndef PT_DSISR #define PT_DSISR 42 @@ -79,69 +78,32 @@ arch_get_bad_addr(int sig, siginfo_t *code, os_context_t *context) void arch_skip_instruction(os_context_t *context) { - char** pcptr; - pcptr = (char**) os_context_pc_addr(context); - *pcptr += 4; + OS_CONTEXT_PC(context) += 4; } unsigned char * arch_internal_error_arguments(os_context_t *context) { - return (unsigned char *)(*os_context_pc_addr(context)+4); + return (unsigned char *)(OS_CONTEXT_PC(context)+4); } boolean arch_pseudo_atomic_atomic(os_context_t *context) { -#ifdef LISP_FEATURE_SB_THREAD - struct thread *thread = arch_os_get_current_thread(); - - if (foreign_function_call_active_p(thread)) { - return get_pseudo_atomic_atomic(thread); - } else return -#else - /* FIXME: this foreign_function_call_active test is dubious at - * best. If a foreign call is made in a pseudo atomic section - * (?) or more likely a pseudo atomic section is in a foreign - * call then an interrupt is executed immediately. Maybe it - * has to do with C code not maintaining pseudo atomic - * properly. MG - 2005-08-10 - * - * The foreign_function_call_active used to live at each call-site - * to arch_pseudo_atomic_atomic, but this seems clearer. - * --NS 2007-05-15 */ - return (!foreign_function_call_active_p(arch_os_get_current_thread())) && -#endif - ((*os_context_register_addr(context,reg_ALLOC)) & flag_PseudoAtomic); + return get_pseudo_atomic_atomic(get_sb_vm_thread()); } void arch_set_pseudo_atomic_interrupted(os_context_t *context) { -#ifdef LISP_FEATURE_SB_THREAD - struct thread *thread = arch_os_get_current_thread(); - - if (foreign_function_call_active_p(thread)) { - set_pseudo_atomic_interrupted(thread); - } else -#endif - *os_context_register_addr(context,reg_ALLOC) - |= flag_PseudoAtomicInterrupted; + set_pseudo_atomic_interrupted(get_sb_vm_thread()); } void arch_clear_pseudo_atomic_interrupted(os_context_t *context) { -#ifdef LISP_FEATURE_SB_THREAD - struct thread *thread = arch_os_get_current_thread(); - - if (foreign_function_call_active_p(thread)) { - clear_pseudo_atomic_interrupted(thread); - } else -#endif - *os_context_register_addr(context,reg_ALLOC) - &= ~flag_PseudoAtomicInterrupted; + clear_pseudo_atomic_interrupted(get_sb_vm_thread()); } unsigned int @@ -208,7 +170,7 @@ arch_do_displaced_inst(os_context_t *context, unsigned int orig_inst) { /* not sure how we ensure that we get the breakpoint reinstalled * after doing this -dan */ - unsigned int *pc = (unsigned int *)(*os_context_pc_addr(context)); + unsigned int *pc = (unsigned int *)OS_CONTEXT_PC(context); unsigned int *next_pc; int op = orig_inst >> 26; int sub_op = (orig_inst & 0x7fe) >> 1; /* XL-form sub-opcode */ @@ -262,9 +224,9 @@ arch_do_displaced_inst(os_context_t *context, unsigned int orig_inst) } #define INLINE_ALLOC_DEBUG 0 -#ifdef LISP_FEATURE_CHENEYGC -#define handle_allocation_trap(x) (0) -#else +#define ALLOC_TRAP_LISTIFY 1 +#define ALLOC_TRAP_CONS 2 +#define ALLOC_TRAP_GENERAL 3 /* * Return non-zero if the current instruction is an allocation trap */ @@ -279,25 +241,29 @@ allocation_trap_p(os_context_t * context) * |31| TO|dst|src| 4|0| TW - trap word * |31| TO|dst|src| 68|0| TD - trap doubleword * - * TO = #b00001 for LGT - * #b00101 for LGE + * TO = #b00100 for EQ + * #b00001 for LGT (logical greater-than) + * #b00101 for LGE (logical greater-or-equal) + * #b00010 for LLT (logical less-than) + * #b00110 for LLE (logical less-or-equal) */ - unsigned *pc = (unsigned int *) *os_context_pc_addr(context); + unsigned *pc = (unsigned int *)OS_CONTEXT_PC(context); unsigned inst = *pc; unsigned opcode = inst >> 26; unsigned src = (inst >> 11) & 0x1f; - // unsigned dst = (inst >> 16) & 0x1f; + unsigned dst = (inst >> 16) & 0x1f; unsigned to = (inst >> 21) & 0x1f; unsigned subcode = inst & 0x7ff; - if (opcode == 31 && (to == 1 || to == 5) && src == reg_NL3 + // recognize the listify-rest-args allocation trap + if (opcode == 31 && to == 5 && src == dst && subcode == 4<<1) + return ALLOC_TRAP_LISTIFY; + + // FIXME: we can remove the wired use of NL3 in the allocator + if (opcode == 31 && (to == 1 || to == 2) + && (src == reg_NL3 || dst == reg_NL3) && (subcode == 4<<1 || subcode == 68<<1)) { - /* It doesn't much matter which trap option we pick for "could be large" - * but I've chosen "TGE" because of the choices, that one is subject to spurious - * failure, and I'd prefer not to spuriously fail on a 2-word cons. - * (Spurious failure occurs when the EQ condition is met, meaning the allocation - * would have worked, but the trap happens regardless) */ - int success = (to == 5) ? 1 : -1; // 1 = single-object page ok, -1 = not ok + int success = (to == 2) ? ALLOC_TRAP_CONS : ALLOC_TRAP_GENERAL; /* * We got the instruction. Now, look back to make sure it was @@ -310,7 +276,7 @@ allocation_trap_p(os_context_t * context) opcode = add_inst >> 26; if ((opcode == 31) && (266 == ((add_inst >> 1) & 0x1ff))) { return success; - } else if ((opcode == 14)) { + } else if (opcode == 14) { return success; } else { fprintf(stderr, @@ -321,124 +287,73 @@ allocation_trap_p(os_context_t * context) return 0; } -#ifndef boxed_region -#define boxed_region gc_alloc_region[0] -#endif - static int handle_allocation_trap(os_context_t * context) { - int alloc_trap_p = allocation_trap_p(context); - - if (!alloc_trap_p) return 0; - gc_assert(!foreign_function_call_active_p(arch_os_get_current_thread())); - fake_foreign_function_call(context); + int alloc_trap_kind = allocation_trap_p(context); - unsigned int *pc = (unsigned int *) (*os_context_pc_addr(context)); + if (!alloc_trap_kind) return 0; - /* - * Go back and look at the add/addi instruction. The second src arg - * is the size of the allocation. Get it and call alloc to allocate - * new space. - */ + struct thread* thread = get_sb_vm_thread(); + gc_assert(!foreign_function_call_active_p(thread)); + if (gencgc_alloc_profiler && thread->state_word.sprof_enable) + record_backtrace_from_context(context, thread); - unsigned int inst = pc[-1]; - int target = (inst >> 21) & 0x1f; - unsigned int opcode = inst >> 26; -#if INLINE_ALLOC_DEBUG - fprintf(stderr, " add inst = 0x%08x, opcode = %d\n", inst, opcode); -#endif - sword_t size = 0; - if (opcode == 14) { - /* - * ADDI temp-tn, alloc-tn, size - * - * Extract the size - */ - size = (inst & 0xffff); - } else if (opcode == 31) { + fake_foreign_function_call(context); + struct interrupt_data *data = &thread_interrupt_data(thread); + data->allocation_trap_context = context; + + unsigned int *pc = (unsigned int *)OS_CONTEXT_PC(context); + + if (alloc_trap_kind == ALLOC_TRAP_LISTIFY) { + unsigned inst = pc[0]; + int count_reg = (inst >> 11) & 0x1f; + // There's a dummy trap instruction which encodes the context and result. + inst = pc[1]; + unsigned context_reg = (inst >> 16) & 0x1f; + unsigned result_reg = (inst >> 11) & 0x1f; + lispobj* argv = (void*)*os_context_register_addr(context, context_reg); + lispobj nbytes = *os_context_register_addr(context, count_reg); + extern lispobj listify_rest_arg(lispobj*, sword_t); + lispobj result = listify_rest_arg(argv, nbytes); + *os_context_register_addr(context, result_reg) = result; + // Skip this and the next instruction + OS_CONTEXT_PC(context) += 8; + } else { /* - * ADD temp-tn, alloc-tn, size-tn - * - * Extract the size + * Go back and look at the add/addi instruction. The second src arg + * is the size of the allocation. Get it and call alloc to allocate + * new space. + * (Alternatively we could look at the trap instruction to see which + * register was compared against the region free pointer. Subtracting + * the region base would yield the size) */ - int reg; - - reg = (inst >> 11) & 0x1f; -#if INLINE_ALLOC_DEBUG - fprintf(stderr, " add, reg = %s\n", lisp_register_names[reg]); -#endif - size = *os_context_register_addr(context, reg); - - } - -#if INLINE_ALLOC_DEBUG - fprintf(stderr, "Alloc %d to %s\n", size, lisp_register_names[target]); - if ((((unsigned long)boxed_region.end_addr + size) / GENCGC_CARD_BYTES) == - (((unsigned long)boxed_region.end_addr) / GENCGC_CARD_BYTES)) { - fprintf(stderr,"*** possibly bogus trap allocation of %d bytes at %p\n", - size, (void*)target_ptr); - fprintf(stderr, " dynamic_space_free_pointer: %p, boxed_region.end_addr %p\n", - dynamic_space_free_pointer, boxed_region.end_addr); - } - fprintf(stderr, "Ready to alloc\n"); - fprintf(stderr, "free_pointer = %p\n", dynamic_space_free_pointer); -#endif - - /* - * alloc-tn was incremented by size. Need to decrement it by size - * to restore its original value. This is not true on GENCGC - * anymore. d_s_f_p and reg_alloc get out of sync, but the p_a - * bits stay intact and we set it to the proper value when it - * needs to be. Keep this comment here for the moment in case - * somebody tries to figure out what happened here. - */ - /* dynamic_space_free_pointer = - (lispobj *) ((long) dynamic_space_free_pointer - size); - */ - - char *memory; - { + unsigned int inst = pc[-1]; + int target = (inst >> 21) & 0x1f; + unsigned int opcode = inst >> 26; + sword_t size = 0; + if (opcode == 14) { // ADDI temp-tn, alloc-tn, size + size = (inst & 0xffff); + } else if (opcode == 31) { // ADD temp-tn, alloc-tn, size-tn + int reg; + reg = (inst >> 11) & 0x1f; + size = *os_context_register_addr(context, reg); + } + char *memory; extern lispobj *alloc(sword_t), *alloc_list(sword_t); - struct interrupt_data *data = - arch_os_get_current_thread()->interrupt_data; - data->allocation_trap_context = context; - memory = (char*)(alloc_trap_p < 0 ? alloc_list(size) : alloc(size)); - data->allocation_trap_context = 0; + memory = (char*)(alloc_trap_kind==ALLOC_TRAP_CONS ? alloc_list(size) : alloc(size)); + // ALLOCATION wants the result to point to the end of the object! + *os_context_register_addr(context, target) = + (os_context_register_t)(memory + size); + // Skip 2 instructions: the trap, and the writeback of free pointer + OS_CONTEXT_PC(context) = (uword_t)(pc + 2); // ('pc' is of type int*) } -#if INLINE_ALLOC_DEBUG - fprintf(stderr, "alloc returned %p\n", memory); - fprintf(stderr, "free_pointer = %p\n", dynamic_space_free_pointer); -#endif - - /* - * The allocation macro wants the result to point to the end of the - * object! - */ - memory += size; - -#if INLINE_ALLOC_DEBUG - fprintf(stderr, "object end at %p\n", memory); -#endif - - *os_context_register_addr(context, target) = (unsigned long) memory; -#ifndef LISP_FEATURE_SB_THREAD - /* This is handled by the fake_foreign_function_call machinery on - * threaded targets. */ - *os_context_register_addr(context, reg_ALLOC) = - (unsigned long) dynamic_space_free_pointer - | (*os_context_register_addr(context, reg_ALLOC) - & LOWTAG_MASK); -#endif - + data->allocation_trap_context = 0; undo_fake_foreign_function_call(context); - // Skip 2 instructions: the trap, and the writeback of free pointer - (*os_context_pc_addr(context)) = (uword_t)(pc + 2); return 1; // handled } -#endif #if defined LISP_FEATURE_SB_THREAD static int @@ -467,7 +382,7 @@ handle_tls_trap(os_context_t * context, uword_t pc, unsigned int code) boolean handle_it = 0; unsigned prev_inst; if ((code & ~(31 << 16)) == ((3<<26)|(4<<21))) { // mask out RA for test - prev_inst= ((u32*)pc)[-1]; + prev_inst= ((uint32_t*)pc)[-1]; int16_t disp = (prev_inst & 0xFFFF); handle_it = (prev_inst >> 26) == 32 // a load // RT of the load must be RA of the trap @@ -476,7 +391,7 @@ handle_tls_trap(os_context_t * context, uword_t pc, unsigned int code) } if (!handle_it) return 0; - struct thread *thread = arch_os_get_current_thread(); + struct thread *thread = get_sb_vm_thread(); set_pseudo_atomic_atomic(thread); int symbol_reg = (prev_inst >> 16) & 31; @@ -534,7 +449,7 @@ arch_handle_breakpoint(os_context_t *context) void arch_handle_fun_end_breakpoint(os_context_t *context) { - *os_context_pc_addr(context) = (uword_t)handle_fun_end_breakpoint(context); + OS_CONTEXT_PC(context) = (uword_t)handle_fun_end_breakpoint(context); } void @@ -544,17 +459,17 @@ arch_handle_after_breakpoint(os_context_t *context) os_flush_icache((os_vm_address_t) skipped_break_addr, sizeof(unsigned int)); skipped_break_addr = NULL; - *(unsigned int *)*os_context_pc_addr(context) - = displaced_after_inst; + // This writes an instruction, NOT assigns to the pc. + *(unsigned int *)OS_CONTEXT_PC(context) = displaced_after_inst; *os_context_sigmask_addr(context)= orig_sigmask; - os_flush_icache((os_vm_address_t) *os_context_pc_addr(context), + os_flush_icache((os_vm_address_t) OS_CONTEXT_PC(context), sizeof(unsigned int)); } void arch_handle_single_step_trap(os_context_t *context, int trap) { - unsigned int code = *((u32 *)(*os_context_pc_addr(context))); + unsigned int code = *(uint32_t *)OS_CONTEXT_PC(context); int register_offset = code >> 8 & 0x1f; handle_single_step_trap(context, trap, register_offset); arch_skip_instruction(context); @@ -563,7 +478,6 @@ arch_handle_single_step_trap(os_context_t *context, int trap) #if 0 static void dump_cpu_state(char *reason, os_context_t* context) { - extern void sigset_tostring(const sigset_t *sigset, char* result, int result_length); int i,j,r=0; sigset_t cur_sigset; char buf[100]; @@ -573,7 +487,7 @@ static void dump_cpu_state(char *reason, os_context_t* context) pthread_sigmask(0, 0, &cur_sigset); sigset_tostring(&cur_sigset, buf, sizeof buf); fprintf(stderr, " curmask=%s\n", buf); fprintf(stderr, " $pc=%16lx $lr=%16lx $ctr=%16lx $cr=%16lx\n", - *os_context_pc_addr(context), + OS_CONTEXT_PC(context), *os_context_lr_addr(context), *os_context_ctr_addr(context), *os_context_cr_addr(context)); @@ -590,15 +504,15 @@ static void dump_cpu_state(char *reason, os_context_t* context) static void sigtrap_handler(int signal, siginfo_t *siginfo, os_context_t *context) { - uword_t pc = *os_context_pc_addr(context); - unsigned int code = *(u32*)pc; + uword_t pc = OS_CONTEXT_PC(context); + unsigned int code = *(uint32_t*)pc; #ifdef LISP_FEATURE_SIGILL_TRAPS if (signal == SIGILL) { if (code == 0x7C0002A6) { // allocation region overflow trap // there is an actual trap instruction located 2 instructions later. // pretend the trap happened there. - *os_context_pc_addr(context) = pc + 8; + OS_CONTEXT_PC(context) = pc + 8; if (handle_allocation_trap(context)) return; } if (code == 0x7C2002A6) { // pending interrupt @@ -616,9 +530,9 @@ sigtrap_handler(int signal, siginfo_t *siginfo, os_context_t *context) if (signal == SIGTRAP && handle_tls_trap(context, pc, code)) return; #endif - if (code == ((3 << 26) | (0x18 << 21) | (reg_NL3 << 16))|| + if (code == ((3 << 26) | (0x18 << 21) | (reg_NL3 << 16))|| // TWI NE,$NL3,0 /* trap instruction from do_pending_interrupt */ - code == 0x7fe00008) { + code == 0x7fe00008) { // TW T,0,0 arch_clear_pseudo_atomic_interrupted(context); arch_skip_instruction(context); /* interrupt or GC was requested in PA; now we're done with the @@ -656,8 +570,8 @@ sigtrap_handler(int signal, siginfo_t *siginfo, os_context_t *context) void arch_install_interrupt_handlers() { - undoably_install_low_level_interrupt_handler(SIGILL, sigtrap_handler); - undoably_install_low_level_interrupt_handler(SIGTRAP, sigtrap_handler); + ll_install_handler(SIGILL, sigtrap_handler); + ll_install_handler(SIGTRAP, sigtrap_handler); } void @@ -694,7 +608,7 @@ ppc_flush_icache(os_vm_address_t address, os_vm_size_t length) void arch_write_linkage_table_entry(int index, void *target_addr, int datap) { - char *reloc_addr = (char*)LINKAGE_TABLE_SPACE_START + index * LINKAGE_TABLE_ENTRY_SIZE; + char *reloc_addr = (char*)ALIEN_LINKAGE_TABLE_SPACE_START + index * ALIEN_LINKAGE_TABLE_ENTRY_SIZE; if (datap) { *(unsigned long *)reloc_addr = (unsigned long)target_addr; return; @@ -834,3 +748,61 @@ arch_write_linkage_table_entry(int index, void *target_addr, int datap) os_flush_icache((os_vm_address_t) reloc_addr, (char*) inst_ptr - reloc_addr); } + + +void +*arch_read_linkage_table_entry(int index, int datap) +{ + char *reloc_addr = (char*)ALIEN_LINKAGE_TABLE_SPACE_START + index * ALIEN_LINKAGE_TABLE_ENTRY_SIZE; + if (datap) { + return *(unsigned long *)reloc_addr; + } + +#if defined LISP_FEATURE_64_BIT +#ifdef LISP_FEATURE_LITTLE_ENDIAN + int* inst_ptr; + unsigned long a0, a16, a32, a48; + + inst_ptr = (int*) reloc_addr; + + a48 = *inst_ptr++ & 0xffff; + a32 = *inst_ptr++ & 0xffff; + inst_ptr++; + a16 = *inst_ptr++ & 0xffff; + a0 = *inst_ptr++ & 0xffff; + + return (void*) (a0 + (a16 << 16) + (a32 << 32) + (a48 << 48)); +#else + void *target_addr; + memcpy(target_addr, reloc_addr, 24); + return target_addr; +#endif +#endif + int* inst_ptr; + unsigned long hi; + unsigned long lo; + + inst_ptr = (int*) reloc_addr; + + hi = *inst_ptr++ & 0xffff; + lo = *inst_ptr++ & 0xffff; + + return (void*) (lo + (hi << 16)); +} + + +void gcbarrier_patch_code(void* where, int nbits) +{ +#ifdef LISP_FEATURE_64_BIT + int m_operand = 64 - nbits; + // the M field has a kooky encoding + int m_encoded = ((m_operand & 0x1F) << 1) | (m_operand >> 5); + unsigned int* pc = where; + unsigned int inst = *pc; + // .... ____ _xxx xxx_ ____ = 0x7E0; + // ^ deposit it here, in (BYTE 6 5) of the instruction. + *pc = (inst & ~0x7E0) | (m_encoded << 5); +#else + lose("can't patch rldicl in 32-bit"); // illegal instruction +#endif +} diff --git a/src/runtime/ppc-arch.h b/src/runtime/ppc-arch.h index e701b65667..a4b464342b 100644 --- a/src/runtime/ppc-arch.h +++ b/src/runtime/ppc-arch.h @@ -2,7 +2,6 @@ #define _PPC_ARCH_H #define ARCH_HAS_LINK_REGISTER -#define ALIEN_STACK_GROWS_DOWNWARD extern void ppc_flush_icache(os_vm_address_t address, os_vm_size_t length); diff --git a/src/runtime/ppc-assem.S b/src/runtime/ppc-assem.S index 1190bb59f3..342952dc0d 100644 --- a/src/runtime/ppc-assem.S +++ b/src/runtime/ppc-assem.S @@ -16,20 +16,8 @@ #include "genesis/static-symbols.h" #include "genesis/thread.h" -#ifdef LISP_FEATURE_DARWIN -#define CSYMBOL(x) _ ## x -#else #define CSYMBOL(x) x -#endif - -#if defined LISP_FEATURE_DARWIN -#define FUNCDEF(x) .text @ \ - .align 3 @ \ -_##x: -#define GFUNCDEF(x) .globl _ ## x @ \ - FUNCDEF(x) -#else #define FUNCDEF(x) .text ; \ .align 3 ; \ .type x,@function ; \ @@ -37,52 +25,23 @@ x: #define GFUNCDEF(x) .globl x ; \ FUNCDEF(x) -#endif -#if defined LISP_FEATURE_DARWIN -#define SET_SIZE(x) -#else #define SET_SIZE(x) .size x,.-x -#endif /* Load a register from a global, using the register as an intermediary */ /* The register will be a fixnum for one instruction, so this is gc-safe */ -#if defined LISP_FEATURE_DARWIN -#define load(reg,global) \ - lis reg,ha16(global) @ \ - lwz reg,lo16(global)(reg) ; Comment -#define store(reg,temp,global) \ - lis temp,ha16(global) @\ - stw reg,lo16(global)(temp) ; Comment -#else #define load(reg,global) \ lis reg,global@ha; lwz reg,global@l(reg) #define store(reg,temp,global) \ lis temp,global@ha; stw reg,global@l(temp) -#endif #define FIRST_SAVE_FPR 14 /* lowest-numbered non-volatile FPR */ -#ifdef LISP_FEATURE_DARWIN -#define FIRST_SAVE_GPR 13 /* lowest-numbered non-volatile GPR */ -#define NGPR_SAVE_BYTES(n) ((32-(n))*4) -#define FRAME_ARG_BYTES(n) (((((n)+6)*4)+15)&~15) -#else #define FIRST_SAVE_GPR 14 /* lowest-numbered non-volatile GPR */ #define NGPR_SAVE_BYTES(n) ((32-(~1&((n)+1)))*4) #define FRAME_ARG_BYTES(n) (((((n)+2)*4)+15)&~15) -#endif #define NFPR_SAVE_BYTES(n) ((32-(n))*8) -#ifdef LISP_FEATURE_DARWIN -#define FRAME_SIZE(first_g,first_f,out_arg_words,savecr) \ -(NFPR_SAVE_BYTES(first_f)+ NGPR_SAVE_BYTES(first_g)+ FRAME_ARG_BYTES(out_arg_words)) -#define SAVE_FPR(n) stfd f##n,-8*(32- n)(r11) -#define SAVE_GPR(n) stw r##n,-4*(32- n)(r11) -#define FULL_FRAME_SIZE (FRAME_SIZE(FIRST_SAVE_GPR,FIRST_SAVE_FPR,8,1)+15&~15) -#define RESTORE_FPR(n) lfd f##n,-8*(32- n)(r11) -#define RESTORE_GPR(n) lwz r##n,-4*(32- n)(r11) -#else #define FRAME_SIZE(first_g,first_f,out_arg_words,savecr) \ (NFPR_SAVE_BYTES(first_f)+ NGPR_SAVE_BYTES(first_g)+ FRAME_ARG_BYTES(out_arg_words+savecr)) #define SAVE_FPR(n) stfd n,-8*(32-(n))(11) @@ -91,105 +50,6 @@ x: #define RESTORE_FPR(n) lfd n,-8*(32-(n))(11) #define RESTORE_GPR(n) lwz n,-4*(32-(n))(11) -#endif - -#ifdef LISP_FEATURE_DARWIN -#define C_FULL_PROLOG \ - nop @\ - nop @ \ - mfcr REG(0) @ \ - stw REG(0),4(REG(1)) @ \ - mflr REG(0) @ \ - stw REG(0),8(REG(1)) @ \ - mr REG(11),REG(1) @ \ - stwu REG(1),-FULL_FRAME_SIZE(REG(1)) @ \ - SAVE_FPR(14) @ \ - SAVE_FPR(15) @ \ - SAVE_FPR(16) @ \ - SAVE_FPR(17) @ \ - SAVE_FPR(18) @ \ - SAVE_FPR(19) @ \ - SAVE_FPR(20) @ \ - SAVE_FPR(21) @ \ - SAVE_FPR(22) @ \ - SAVE_FPR(23) @ \ - SAVE_FPR(24) @ \ - SAVE_FPR(25) @ \ - SAVE_FPR(26) @ \ - SAVE_FPR(27) @ \ - SAVE_FPR(28) @ \ - SAVE_FPR(29) @ \ - SAVE_FPR(30) @ \ - SAVE_FPR(31) @ \ - la REG(11),-NFPR_SAVE_BYTES(FIRST_SAVE_FPR)(REG(11)) @ \ - SAVE_GPR(13) @ \ - SAVE_GPR(14) @ \ - SAVE_GPR(15) @ \ - SAVE_GPR(16) @ \ - SAVE_GPR(17) @ \ - SAVE_GPR(18) @ \ - SAVE_GPR(19) @ \ - SAVE_GPR(20) @ \ - SAVE_GPR(21) @ \ - SAVE_GPR(22) @ \ - SAVE_GPR(23) @ \ - SAVE_GPR(24) @ \ - SAVE_GPR(25) @ \ - SAVE_GPR(26) @ \ - SAVE_GPR(27) @ \ - SAVE_GPR(28) @ \ - SAVE_GPR(29) @ \ - SAVE_GPR(30) @ \ - SAVE_GPR(31) - - -#define C_FULL_EPILOG \ - la REG(11),FULL_FRAME_SIZE-NFPR_SAVE_BYTES(FIRST_SAVE_FPR)(REG(1)) @ \ - RESTORE_GPR(13) @ \ - RESTORE_GPR(14) @ \ - RESTORE_GPR(15) @ \ - RESTORE_GPR(16) @ \ - RESTORE_GPR(17) @ \ - RESTORE_GPR(18) @ \ - RESTORE_GPR(19) @ \ - RESTORE_GPR(20) @ \ - RESTORE_GPR(21) @ \ - RESTORE_GPR(22) @ \ - RESTORE_GPR(23) @ \ - RESTORE_GPR(24) @ \ - RESTORE_GPR(25) @ \ - RESTORE_GPR(26) @ \ - RESTORE_GPR(27) @ \ - RESTORE_GPR(28) @ \ - RESTORE_GPR(29) @ \ - RESTORE_GPR(30) @ \ - RESTORE_GPR(31) @ \ - la REG(11),NFPR_SAVE_BYTES(FIRST_SAVE_FPR)(REG(11)) @ \ - RESTORE_FPR(14) @ \ - RESTORE_FPR(15) @ \ - RESTORE_FPR(16) @ \ - RESTORE_FPR(17) @ \ - RESTORE_FPR(18) @ \ - RESTORE_FPR(19) @ \ - RESTORE_FPR(20) @ \ - RESTORE_FPR(21) @ \ - RESTORE_FPR(22) @ \ - RESTORE_FPR(23) @ \ - RESTORE_FPR(24) @ \ - RESTORE_FPR(25) @ \ - RESTORE_FPR(26) @ \ - RESTORE_FPR(27) @ \ - RESTORE_FPR(28) @ \ - RESTORE_FPR(29) @ \ - RESTORE_FPR(30) @ \ - RESTORE_FPR(31) @ \ - lwz REG(1),0(REG(1)) @ \ - lwz REG(0),4(REG(1)) @ \ - mtcr REG(0) @ \ - lwz REG(0),8(REG(1)) @ \ - mtlr REG(0) @ \ - -#else #define C_FULL_PROLOG \ mflr 0 ; \ @@ -281,15 +141,15 @@ x: lwz 0,4(1) ; \ mtlr 0 ; \ -#endif +#define BEGIN_PSEUDO_ATOMIC stb reg_NULL,THREAD_PSEUDO_ATOMIC_BITS_OFFSET(reg_THREAD) +#define END_PSEUDO_ATOMIC \ + stb reg_THREAD, THREAD_PSEUDO_ATOMIC_BITS_OFFSET(reg_THREAD) ; \ + lhz reg_NL3, (2+THREAD_PSEUDO_ATOMIC_BITS_OFFSET)(reg_THREAD) ; \ + twnei reg_NL3, 0 -#ifdef LISP_FEATURE_SB_SAFEPOINT -/* the CSP page sits right before the thread */ -# define THREAD_SAVED_CSP_OFFSET (-N_WORD_BYTES) -#endif .text -#ifdef OS_THREAD_STACK +#ifdef LISP_FEATURE_OS_THREAD_STACK GFUNCDEF(funcall1_switching_stack) /* The arguments are switched, funcall1_switching_stack(arg, function) to avoid shuffling registers @@ -337,10 +197,7 @@ x: mr reg_A2, reg_NL2 /* Call out to obtain our TLS block. */ - load(reg_NL0,CSYMBOL(specials)) - /* This won't work on darwin: wrong fixup style. And is it - * supposed to be lis/ori or lis/addi? Or does it differ - * between darwin and everything else again? */ + load(reg_NL0,CSYMBOL(current_thread)) lis reg_CFUNC,CSYMBOL(pthread_getspecific)@h ori reg_CFUNC,reg_CFUNC,CSYMBOL(pthread_getspecific)@l mtctr reg_CFUNC @@ -351,6 +208,8 @@ x: mr reg_NL2, reg_A2 mr reg_NL1, reg_A1 mr reg_NL0, reg_A0 +#else + load(reg_THREAD,CSYMBOL(all_threads)) #endif /* store(reg_POLL,11,saver2) */ /* Initialize tagged registers */ @@ -367,20 +226,13 @@ x: li reg_A3,0 li reg_L0,0 li reg_L1,0 -#if !defined(LISP_FEATURE_SB_THREAD) li reg_L2,0 -#endif li reg_LIP,0 -#ifdef LISP_FEATURE_DARWIN - lis reg_NULL,hi16(NIL) - ori reg_NULL,reg_NULL,lo16(NIL) -#else lis reg_NULL,NIL@h ori reg_NULL,reg_NULL,NIL@l -#endif /* Turn on pseudo-atomic */ - li reg_ALLOC,flag_PseudoAtomic + BEGIN_PSEUDO_ATOMIC #if defined(LISP_FEATURE_SB_THREAD) stw reg_ZERO,THREAD_FOREIGN_FUNCTION_CALL_ACTIVE_OFFSET(reg_THREAD) lwz reg_BSP,THREAD_BINDING_STACK_POINTER_OFFSET(reg_THREAD) @@ -392,17 +244,9 @@ x: load(reg_CSP,CSYMBOL(current_control_stack_pointer)) load(reg_OCFP,CSYMBOL(current_control_frame_pointer)) #endif - /* This is important for CHENEYGC: It's the allocation - * pointer. It's also important for ROOM on GENCGC: - * It's a pointer to the end of dynamic space, used to - * determine where to stop in MAP-ALLOCATED-OBJECTS. */ - load(reg_NL4,CSYMBOL(dynamic_space_free_pointer)) - add reg_ALLOC,reg_ALLOC,reg_NL4 /* No longer atomic, and check for interrupt */ - subi reg_ALLOC,reg_ALLOC,flag_PseudoAtomic - andi. reg_NL3, reg_ALLOC, flag_PseudoAtomicInterrupted - twnei reg_NL3, 0 + END_PSEUDO_ATOMIC /* Pass in the arguments */ @@ -414,13 +258,8 @@ x: lwz reg_A3,12(reg_CFP) /* Calculate LRA */ -#ifdef LISP_FEATURE_DARWIN - lis reg_LRA,ha16(lra) - addi reg_LRA,reg_LRA,lo16(lra) -#else lis reg_LRA,lra@h ori reg_LRA,reg_LRA,lra@l -#endif addi reg_LRA,reg_LRA,OTHER_POINTER_LOWTAG /* Function is an indirect closure */ @@ -443,7 +282,7 @@ lra: mr REG(3),reg_A0 /* Turn on pseudo-atomic */ - la reg_ALLOC,flag_PseudoAtomic(reg_ALLOC) + BEGIN_PSEUDO_ATOMIC #if defined(LISP_FEATURE_SB_THREAD) /* Store lisp state */ @@ -452,26 +291,19 @@ lra: stw reg_CFP,THREAD_CONTROL_FRAME_POINTER_OFFSET(reg_THREAD) /* No longer in Lisp. */ - stw reg_ALLOC,THREAD_FOREIGN_FUNCTION_CALL_ACTIVE_OFFSET(reg_THREAD) + stw reg_THREAD,THREAD_FOREIGN_FUNCTION_CALL_ACTIVE_OFFSET(reg_THREAD) #else /* Store lisp state */ - clrrwi reg_NL1,reg_ALLOC,3 - store(reg_NL1,reg_NL2,CSYMBOL(dynamic_space_free_pointer)) - /* store(reg_POLL,reg_NL2,poll_flag) */ - /* load(reg_NL2,current_thread) */ store(reg_BSP,reg_NL2,CSYMBOL(current_binding_stack_pointer)) store(reg_CSP,reg_NL2,CSYMBOL(current_control_stack_pointer)) store(reg_CFP,reg_NL2,CSYMBOL(current_control_frame_pointer)) - /* load(reg_POLL,saver2) */ /* No longer in Lisp. */ store(reg_NL1,reg_NL2,CSYMBOL(foreign_function_call_active)) #endif /* Check for interrupt */ - subi reg_ALLOC, reg_ALLOC, flag_PseudoAtomic - andi. reg_NL3, reg_ALLOC, flag_PseudoAtomicInterrupted - twnei reg_NL3,0 + END_PSEUDO_ATOMIC /* Back to C */ C_FULL_EPILOG @@ -501,7 +333,7 @@ lra: mr reg_NARGS,reg_NL3 /* Turn on pseudo-atomic */ - la reg_ALLOC,flag_PseudoAtomic(reg_ALLOC) + BEGIN_PSEUDO_ATOMIC /* Convert the return address to an offset and save it on the stack. */ sub reg_NFP,reg_LIP,reg_CODE @@ -518,8 +350,6 @@ lra: stw reg_CSP,THREAD_FOREIGN_FUNCTION_CALL_ACTIVE_OFFSET(reg_THREAD) #else /* Store Lisp state */ - clrrwi reg_NFP,reg_ALLOC,3 - store(reg_NFP,reg_CFUNC,CSYMBOL(dynamic_space_free_pointer)) /* load(reg_CFUNC,current_thread) */ store(reg_BSP,reg_CFUNC,CSYMBOL(current_binding_stack_pointer)) @@ -529,40 +359,17 @@ lra: /* No longer in Lisp */ store(reg_CSP,reg_CFUNC,CSYMBOL(foreign_function_call_active)) #endif - /* load(reg_POLL,saver2) */ /* Disable pseudo-atomic; check pending interrupt */ - subi reg_ALLOC, reg_ALLOC, flag_PseudoAtomic - andi. reg_NL3, reg_ALLOC, flag_PseudoAtomicInterrupted - twnei reg_NL3, 0 - -#ifdef LISP_FEATURE_SB_SAFEPOINT - /* OK to run GC without stopping this thread from this point on. */ -# ifdef LISP_FEATURE_SB_THREAD - stw reg_CSP,THREAD_SAVED_CSP_OFFSET(reg_THREAD) -# else - load(reg_CFUNC,CSYMBOL(all_threads)) - stw reg_CSP,THREAD_SAVED_CSP_OFFSET(reg_CFUNC) -# endif -#endif + END_PSEUDO_ATOMIC mr reg_NL3,reg_NARGS -#ifdef LISP_FEATURE_DARWIN - /* PowerOpen (i.e. OS X) requires the callee address in r12 - (a.k.a. CFUNC), so move it back there, too. */ - mfctr reg_CFUNC -#endif /* Into C we go. */ bctrl /* Re-establish NIL */ -#ifdef LISP_FEATURE_DARWIN - lis reg_NULL,hi16(NIL) - ori reg_NULL,reg_NULL,lo16(NIL) -#else lis reg_NULL,NIL@h ori reg_NULL,reg_NULL,NIL@l -#endif /* And reg_ZERO */ li reg_ZERO,0 @@ -582,24 +389,11 @@ lra: li reg_A3,0 li reg_L0,0 li reg_L1,0 -#if !defined(LISP_FEATURE_SB_THREAD) - /* reg_L2 is our TLS block pointer. */ li reg_L2,0 -#endif li reg_LIP,0 -# ifdef LISP_FEATURE_SB_SAFEPOINT - /* No longer OK to run GC except at safepoints. */ -# ifdef LISP_FEATURE_SB_THREAD - stw reg_ZERO,THREAD_SAVED_CSP_OFFSET(reg_THREAD) -# else - load(reg_BSP,CSYMBOL(all_threads)) - stw reg_ZERO,THREAD_SAVED_CSP_OFFSET(reg_BSP) -# endif -# endif - /* Atomic ... */ - li reg_ALLOC,flag_PseudoAtomic + BEGIN_PSEUDO_ATOMIC #if defined(LISP_FEATURE_SB_THREAD) /* No longer in foreign function call. */ @@ -617,12 +411,6 @@ lra: /* The BSP wasn't preserved by C, so load it */ load(reg_BSP,CSYMBOL(current_binding_stack_pointer)) #endif - /* This is important for CHENEYGC: It's the allocation - * pointer. It's also important for ROOM on GENCGC: - * It's a pointer to the end of dynamic space, used to - * determine where to stop in MAP-ALLOCATED-OBJECTS. */ - load(reg_NL4,CSYMBOL(dynamic_space_free_pointer)) - add reg_ALLOC,reg_ALLOC,reg_NL4 /* Other lisp stack/frame pointers were preserved by C. I can't imagine why they'd have moved */ @@ -637,9 +425,7 @@ lra: mtlr reg_LIP /* No longer atomic */ - subi reg_ALLOC, reg_ALLOC, flag_PseudoAtomic - andi. reg_NL3, reg_ALLOC, flag_PseudoAtomicInterrupted - twnei reg_NL3, 0 + END_PSEUDO_ATOMIC /* Reset the lisp stack. */ mr reg_CSP,reg_CFP @@ -660,11 +446,6 @@ lra: .globl CSYMBOL(fun_end_breakpoint_trap) .globl CSYMBOL(fun_end_breakpoint_end) - /* Due to pointer verification in MAKE-LISP-OBJ, this must - include its header data (the offset from the start of the - code-object to the LRA). */ - .long (((CODE_SIZE+1)&~1)<<N_WIDETAG_BITS)|RETURN_PC_WIDETAG - /* We are receiving unknown multiple values, thus must deal with the single-value and multiple-value cases separately. */ b fun_end_breakpoint_multiple_values @@ -676,10 +457,10 @@ lra: obtain a tagged pointer to the enclosing code component. Both values are tagged OTHER_POINTER_LOWTAG, so we just have to account for N words (see calculation for RETURN_PC_WIDETAG, above) - between the two addresses. - Restoring reg_CODE doesn't appear to be strictly necessary - here, but let's observe the niceties.*/ - addi reg_CODE, reg_LRA, ((CODE_SIZE+1)&~1)*-N_WORD_BYTES + between the two addresses. */ + /* KLUDGE: I have no idea why CODE_SIZE+4 is correct here, + let alone the general formula for keeping this maintenance-free */ + addi reg_CODE, reg_LRA, (CODE_SIZE+4)*-N_WORD_BYTES /* Multiple values are stored relative to reg_OCFP, which we set to be the current top-of-stack. */ @@ -702,6 +483,7 @@ lra: fun_end_breakpoint_multiple_values: /* Compute the correct value for reg_CODE. See the explanation for the single-value case, above. */ + /* XXX: I have literally no idea why this constant is -24 */ addi reg_CODE, reg_LRA, -24 /* The actual magic trap. */ diff --git a/src/runtime/ppc-bsd-os.c b/src/runtime/ppc-bsd-os.c index f1d03c12a6..81d1fc9053 100644 --- a/src/runtime/ppc-bsd-os.c +++ b/src/runtime/ppc-bsd-os.c @@ -25,17 +25,6 @@ os_context_sp_addr(os_context_t *context) } #endif - -int * -os_context_pc_addr(os_context_t *context) -{ -#if defined(LISP_FEATURE_NETBSD) - return &(_UC_MACHINE_PC(context)); -#elif defined(LISP_FEATURE_OPENBSD) - return &context->sc_frame.srr0; -#endif -} - int * os_context_lr_addr(os_context_t *context) { @@ -77,7 +66,6 @@ os_flush_icache(os_vm_address_t address, os_vm_size_t length) } int arch_os_thread_init(struct thread *thread) { - #ifdef LISP_FEATURE_C_STACK_IS_CONTROL_STACK stack_t sigstack; @@ -89,15 +77,9 @@ int arch_os_thread_init(struct thread *thread) { sigstack.ss_size = calc_altstack_size(thread); sigaltstack(&sigstack,0); #endif - -#if defined(LISP_FEATURE_SB_THREAD) - pthread_setspecific(specials,thread); -#endif - return 1; /* success */ } int arch_os_thread_cleanup(struct thread *thread) { - return 1; /* success */ } diff --git a/src/runtime/ppc-bsd-os.h b/src/runtime/ppc-bsd-os.h index 60cd703d23..724a67679a 100644 --- a/src/runtime/ppc-bsd-os.h +++ b/src/runtime/ppc-bsd-os.h @@ -5,4 +5,12 @@ typedef int os_context_register_t; #include "arch-os-generic.inc" +#ifdef LISP_FEATURE_NETBSD +# define OS_CONTEXT_PC(context) _UC_MACHINE_PC(context) +#elif defined LISP_FEATURE_OPENBSD +# define OS_CONTEXT_PC(context) context->sc_frame.srr0 +#else +# error "Need a definition of OS_CONTEXT_PC" +#endif + #endif /* _PPC_BSD_OS_H */ diff --git a/src/runtime/ppc-darwin-os.c b/src/runtime/ppc-darwin-os.c deleted file mode 100644 index 46c9ef0ac3..0000000000 --- a/src/runtime/ppc-darwin-os.c +++ /dev/null @@ -1,148 +0,0 @@ -/* - * This is the PowerPC/Darwin incarnation of arch-dependent - * OS-dependent routines. See also "bsdos.c". - */ - -/* - * This software is part of the SBCL system. See the README file for - * more information. - * - * This software is derived from the CMU CL system, which was - * written at Carnegie Mellon University and released into the - * public domain. The software is in the public domain and is - * provided with absolutely no warranty. See the COPYING and CREDITS - * files for more information. - */ - -#include "sbcl.h" -#include "globals.h" -#include "runtime.h" -#include <signal.h> -#include <ucontext.h> -#include <limits.h> -#include <mach-o/dyld.h> -#include "arch.h" -#include "interr.h" /* for declaration of lose */ - -#ifdef LISP_FEATURE_SB_THREAD -#error "Define threading support functions" -#else -int arch_os_thread_init(struct thread *thread) { - return 1; /* success */ -} -int arch_os_thread_cleanup(struct thread *thread) { - return 1; /* success */ -} -#endif - -os_context_register_t * -os_context_register_addr(os_context_t *context, int offset) -{ - ppc_ss_struct_t *state = &context->uc_mcontext->PPC_DARWIN_REGIFY(ss); - switch(offset) { - case 0: - return (os_context_register_t *) &state->PPC_DARWIN_REGIFY(r0); - case 1: - return (os_context_register_t *) &state->PPC_DARWIN_REGIFY(r1); - case 2: - return (os_context_register_t *) &state->PPC_DARWIN_REGIFY(r2); - case 3: - return (os_context_register_t *) &state->PPC_DARWIN_REGIFY(r3); - case 4: - return (os_context_register_t *) &state->PPC_DARWIN_REGIFY(r4); - case 5: - return (os_context_register_t *) &state->PPC_DARWIN_REGIFY(r5); - case 6: - return (os_context_register_t *) &state->PPC_DARWIN_REGIFY(r6); - case 7: - return (os_context_register_t *) &state->PPC_DARWIN_REGIFY(r7); - case 8: - return (os_context_register_t *) &state->PPC_DARWIN_REGIFY(r8); - case 9: - return (os_context_register_t *) &state->PPC_DARWIN_REGIFY(r9); - case 10: - return (os_context_register_t *) &state->PPC_DARWIN_REGIFY(r10); - case 11: - return (os_context_register_t *) &state->PPC_DARWIN_REGIFY(r11); - case 12: - return (os_context_register_t *) &state->PPC_DARWIN_REGIFY(r12); - case 13: - return (os_context_register_t *) &state->PPC_DARWIN_REGIFY(r13); - case 14: - return (os_context_register_t *) &state->PPC_DARWIN_REGIFY(r14); - case 15: - return (os_context_register_t *) &state->PPC_DARWIN_REGIFY(r15); - case 16: - return (os_context_register_t *) &state->PPC_DARWIN_REGIFY(r16); - case 17: - return (os_context_register_t *) &state->PPC_DARWIN_REGIFY(r17); - case 18: - return (os_context_register_t *) &state->PPC_DARWIN_REGIFY(r18); - case 19: - return (os_context_register_t *) &state->PPC_DARWIN_REGIFY(r19); - case 20: - return (os_context_register_t *) &state->PPC_DARWIN_REGIFY(r20); - case 21: - return (os_context_register_t *) &state->PPC_DARWIN_REGIFY(r21); - case 22: - return (os_context_register_t *) &state->PPC_DARWIN_REGIFY(r22); - case 23: - return (os_context_register_t *) &state->PPC_DARWIN_REGIFY(r23); - case 24: - return (os_context_register_t *) &state->PPC_DARWIN_REGIFY(r24); - case 25: - return (os_context_register_t *) &state->PPC_DARWIN_REGIFY(r25); - case 26: - return (os_context_register_t *) &state->PPC_DARWIN_REGIFY(r26); - case 27: - return (os_context_register_t *) &state->PPC_DARWIN_REGIFY(r27); - case 28: - return (os_context_register_t *) &state->PPC_DARWIN_REGIFY(r28); - case 29: - return (os_context_register_t *) &state->PPC_DARWIN_REGIFY(r29); - case 30: - return (os_context_register_t *) &state->PPC_DARWIN_REGIFY(r30); - case 31: - return (os_context_register_t *) &state->PPC_DARWIN_REGIFY(r31); - case 41: - /* PT_DAR */ - return (os_context_register_t *) &context->uc_mcontext->PPC_DARWIN_REGIFY(es).PPC_DARWIN_REGIFY(dar); - case 42: - /* PT_DSISR */ - return (os_context_register_t *) &context->uc_mcontext->PPC_DARWIN_REGIFY(es).PPC_DARWIN_REGIFY(dsisr); - default: - lose("bad offset to os_context_register_addr"); - } -} - -os_context_register_t * -os_context_lr_addr(os_context_t *context) -{ - return (os_context_register_t *) &context->uc_mcontext->PPC_DARWIN_REGIFY(ss).PPC_DARWIN_REGIFY(lr); -} - -os_context_register_t * -os_context_ctr_addr(os_context_t *context) -{ - return (os_context_register_t *) &context->uc_mcontext->PPC_DARWIN_REGIFY(ss).PPC_DARWIN_REGIFY(ctr); -} - -os_context_register_t * -os_context_cr_addr(os_context_t *context) -{ - return (os_context_register_t *) &context->uc_mcontext->PPC_DARWIN_REGIFY(ss).PPC_DARWIN_REGIFY(cr); -} - -os_context_register_t * -os_context_pc_addr(os_context_t *context) -{ - return &context->uc_mcontext->PPC_DARWIN_REGIFY(ss).PPC_DARWIN_REGIFY(srr0); -} - -void -os_flush_icache(os_vm_address_t address, os_vm_size_t length) -{ - /* see ppc-arch.c */ - ppc_flush_icache(address,length); -} - diff --git a/src/runtime/ppc-darwin-os.h b/src/runtime/ppc-darwin-os.h deleted file mode 100644 index 2391792c42..0000000000 --- a/src/runtime/ppc-darwin-os.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef _PPC_DARWIN_OS_H -#define _PPC_DARWIN_OS_H - -#include "darwin-os.h" - -typedef unsigned int os_context_register_t; -#include "arch-os-generic.inc" - -/* On OS X 10.5, the field names for the thread state have changed and - * now are prepended with __. Use some #define hackery to deal with - * this. - */ -#if __DARWIN_UNIX03 - -#define PPC_DARWIN_REGIFY(foo) __ ## foo - -typedef ppc_thread_state_t ppc_ss_struct_t; - -#else - -#define PPC_DARWIN_REGIFY(foo) foo - -typedef ppc_saved_state_t ppc_ss_struct_t; - -#endif /* __DARWIN_UNIX03 */ - -#endif /* _PPC_DARWIN_OS_H */ diff --git a/src/runtime/ppc-linux-os.c b/src/runtime/ppc-linux-os.c index 01aeb8ba37..7a9efada98 100644 --- a/src/runtime/ppc-linux-os.c +++ b/src/runtime/ppc-linux-os.c @@ -26,8 +26,6 @@ #include "interrupt.h" #include "interr.h" #include "lispregs.h" -#include <sys/socket.h> -#include <sys/utsname.h> #include <sys/types.h> #include <signal.h> @@ -40,10 +38,6 @@ #include "ppc-linux-mcontext.h" int arch_os_thread_init(struct thread *thread) { -#if defined(LISP_FEATURE_SB_THREAD) - pthread_setspecific(specials,thread); -#endif - /* For some reason, PPC Linux appears to default to not generating * floating point exceptions. PR_SET_FPEXC is a PPC-specific * option new in kernel 2.4.21 and 2.5.32 that allows us to @@ -76,16 +70,6 @@ os_context_register_addr(os_context_t *context, int offset) #endif } -os_context_register_t * -os_context_pc_addr(os_context_t *context) -{ -#if defined(GLIBC231_STYLE_UCONTEXT) - return &((context->uc_mcontext.regs)->nip); -#elif defined(GLIBC232_STYLE_UCONTEXT) - return &((context->uc_mcontext.uc_regs->gregs)[PT_NIP]); -#endif -} - os_context_register_t * os_context_lr_addr(os_context_t *context) { diff --git a/src/runtime/ppc-linux-os.h b/src/runtime/ppc-linux-os.h index 8c2ea87169..e624b0a10b 100644 --- a/src/runtime/ppc-linux-os.h +++ b/src/runtime/ppc-linux-os.h @@ -10,4 +10,13 @@ unsigned long os_context_fp_control(os_context_t *context); #define RESTORE_FP_CONTROL_FROM_CONTEXT void os_restore_fp_control(os_context_t *context); +#include "ppc-linux-mcontext.h" // Selects one of these two definitions +#ifdef GLIBC231_STYLE_UCONTEXT +# define OS_CONTEXT_PC(context) (context->uc_mcontext.regs)->nip +#elif defined GLIBC232_STYLE_UCONTEXT +# define OS_CONTEXT_PC(context) (context->uc_mcontext.uc_regs->gregs)[PT_NIP] +#else +# error "Need a definition of OS_CONTEXT_PC" +#endif + #endif /* _PPC_LINUX_OS_H */ diff --git a/src/runtime/ppc-lispregs.h b/src/runtime/ppc-lispregs.h index d8b734673c..35815eedc9 100644 --- a/src/runtime/ppc-lispregs.h +++ b/src/runtime/ppc-lispregs.h @@ -1,15 +1,5 @@ -#if defined LISP_FEATURE_DARWIN -#if defined __ASSEMBLER__ -#define REG(num) r##num -#define FREG(num) f##num -#else #define REG(num) num #define FREG(num) num -#endif -#else -#define REG(num) num -#define FREG(num) num -#endif #define NREGS 32 @@ -25,17 +15,12 @@ #define reg_NL6 REG(9) /* Last (7th) FF param */ #define reg_FDEFN REG(10) /* was NL7 until recently -dan */ #define reg_NARGS REG(11) -#ifdef LISP_FEATURE_DARWIN -#define reg_CFUNC REG(12) /* Silly to blow a reg on FF-name */ -#define reg_NFP REG(13) /* Lisp may save around FF-call */ -#else #define reg_NFP REG(12) /* Lisp may save around FF-call */ #define reg_CFUNC REG(13) /* Silly to blow a reg on FF-name */ -#endif #define reg_BSP REG(14) /* Binding stack pointer */ #define reg_CFP REG(15) /* Control/value stack frame pointer */ #define reg_CSP REG(16) /* Control/value stack top */ -#define reg_ALLOC REG(17) /* (Global) dynamic free pointer */ +#define reg_THREAD REG(17) /* TLS block pointer */ #define reg_NULL REG(18) /* NIL and globals nearby */ #define reg_CODE REG(19) /* Current function object */ #define reg_CNAME REG(20) /* Current function name */ @@ -48,9 +33,5 @@ #define reg_A3 REG(27) /* Last of (only) 4 arg regs */ #define reg_L0 REG(28) /* Tagged temp regs */ #define reg_L1 REG(29) -#ifdef LISP_FEATURE_SB_THREAD -#define reg_THREAD REG(30) /* TLS block pointer */ -#else #define reg_L2 REG(30) /* Last lisp temp reg */ -#endif #define reg_LIP REG(31) /* Lisp Interior Pointer, e.g., locative */ diff --git a/src/runtime/ppc64-arch.h b/src/runtime/ppc64-arch.h index 1fc7018a78..77b0504559 100644 --- a/src/runtime/ppc64-arch.h +++ b/src/runtime/ppc64-arch.h @@ -2,7 +2,6 @@ #define _PPC64_ARCH_H #define ARCH_HAS_LINK_REGISTER -#define ALIEN_STACK_GROWS_DOWNWARD extern void ppc_flush_icache(os_vm_address_t address, os_vm_size_t length); diff --git a/src/runtime/ppc64-assem.S b/src/runtime/ppc64-assem.S index 7c29e9cb75..3a068ae8f0 100644 --- a/src/runtime/ppc64-assem.S +++ b/src/runtime/ppc64-assem.S @@ -8,9 +8,7 @@ #include "genesis/code.h" #include "genesis/funcallable-instance.h" #include "genesis/static-symbols.h" -#ifdef LISP_FEATURE_SB_THREAD #include "genesis/thread.h" -#endif #define FUNCDEF(x) .text ; \ .align 3 ; \ @@ -21,16 +19,6 @@ x: FUNCDEF(x) #define SET_SIZE(x) .size x,.-x -/* Load a register from a global, using the register as an intermediary */ -/* The register will be a fixnum for one instruction, so this is gc-safe */ - -#define load(reg,csym) \ - addis reg, 2, ptr_##csym@toc@ha ; ld reg, ptr_##csym@toc@l(reg) ; ld reg, 0(reg) -#define store(reg,temp,csym) \ - addis temp, 2, ptr_##csym@toc@ha ; ld temp, ptr_##csym@toc@l(temp) ; std reg, 0(temp) -#define wordstore(reg,temp,csym) \ - addis temp, 2, ptr_##csym@toc@ha ; ld temp, ptr_##csym@toc@l(temp) ; stw reg, 0(temp) - /* From PPC-elf64abi: @@ -129,31 +117,14 @@ Low Address ld 0, 16(sp) ; mtlr 0 /* Restore LR */ ; \ lwz 0, 8(sp) ; mtcr 0 /* Restore CR */ -#ifdef LISP_FEATURE_SB_SAFEPOINT -/* the CSP page sits right before the thread */ -# define THREAD_SAVED_CSP_OFFSET (-N_WORD_BYTES) -#endif - -/* We create a pointer into the actual csymbol - This way the symbol ptr_ symbol lives within a 32 bits offset - of the TOC. See Store and Load macros in this file */ -#define indirect_ptr(csym) ptr_##csym: .quad csym -#if !defined(LISP_FEATURE_SB_THREAD) -indirect_ptr(current_binding_stack_pointer) -indirect_ptr(current_control_stack_pointer) -indirect_ptr(current_control_frame_pointer) -#endif -indirect_ptr(dynamic_space_free_pointer) -#if !defined(LISP_FEATURE_SB_THREAD) -indirect_ptr(foreign_function_call_active) -#endif -indirect_ptr(all_threads) -#if defined(LISP_FEATURE_SB_THREAD) -indirect_ptr(specials) -#endif - .text +#define BEGIN_PSEUDO_ATOMIC stb reg_NULL,THREAD_PSEUDO_ATOMIC_BITS_OFFSET(reg_THREAD) +#define END_PSEUDO_ATOMIC \ + stb reg_THREAD, THREAD_PSEUDO_ATOMIC_BITS_OFFSET(reg_THREAD) ; \ + lhz reg_NL3, (2+THREAD_PSEUDO_ATOMIC_BITS_OFFSET)(reg_THREAD) ; \ + twnei reg_NL3, 0 + /* * Function to transfer control into lisp. The lisp object to invoke is * passed as the first argument, which puts it in NL0 @@ -162,28 +133,10 @@ indirect_ptr(specials) GFUNCDEF(call_into_lisp) C_FULL_PROLOG /* NL0 - function, NL1 - frame pointer, NL2 - nargs. */ -#ifdef LISP_FEATURE_SB_THREAD - /* We need to obtain a pointer to our TLS block before we do - * anything else. For this, we call pthread_getspecific(). - * We've preserved all of the callee-saves registers, so we - * can use them to stash our arguments temporarily while we - * make the call. */ - mr reg_A0, reg_NL0 - mr reg_A1, reg_NL1 - mr reg_A2, reg_NL2 - - /* Call out to obtain our TLS block. */ - load(reg_NL0,specials) - bl pthread_getspecific - nop - - mr reg_THREAD, reg_NL0 - - /* Restore our original parameters. */ - mr reg_NL2, reg_A2 - mr reg_NL1, reg_A1 - mr reg_NL0, reg_A0 -#endif + // Copy ABI TLS value of current_thread into lisp thread base + addis reg_THREAD,13,current_thread@tprel@ha + addi reg_THREAD,reg_THREAD,current_thread@tprel@l + ld reg_THREAD,0(reg_THREAD) /* Initialize tagged registers */ li reg_ZERO,0 li reg_CODE,0 @@ -202,29 +155,14 @@ indirect_ptr(specials) ori reg_NULL,reg_NULL,NIL@l /* Turn on pseudo-atomic */ - li reg_ALLOC,flag_PseudoAtomic -#ifdef LISP_FEATURE_SB_THREAD + BEGIN_PSEUDO_ATOMIC std reg_ZERO,THREAD_FOREIGN_FUNCTION_CALL_ACTIVE_OFFSET(reg_THREAD) ld reg_BSP,THREAD_BINDING_STACK_POINTER_OFFSET(reg_THREAD) ld reg_CSP,THREAD_CONTROL_STACK_POINTER_OFFSET(reg_THREAD) ld reg_OCFP,THREAD_CONTROL_FRAME_POINTER_OFFSET(reg_THREAD) -#else - wordstore(reg_ZERO,reg_NL4,foreign_function_call_active) - load(reg_BSP,current_binding_stack_pointer) - load(reg_CSP,current_control_stack_pointer) - load(reg_OCFP,current_control_frame_pointer) -#endif - /* This is important for CHENEYGC: It's the allocation - * pointer. It's also important for ROOM on GENCGC: - * It's a pointer to the end of dynamic space, used to - * determine where to stop in MAP-ALLOCATED-OBJECTS. */ - load(reg_NL4,dynamic_space_free_pointer) - add reg_ALLOC,reg_ALLOC,reg_NL4 /* No longer atomic, and check for interrupt */ - subi reg_ALLOC,reg_ALLOC,flag_PseudoAtomic - andi. reg_NL3, reg_ALLOC, flag_PseudoAtomicInterrupted - twnei reg_NL3, 0 + END_PSEUDO_ATOMIC /* Pass in the arguments */ @@ -235,6 +173,9 @@ indirect_ptr(specials) ld reg_A2,16(reg_CFP) ld reg_A3,24(reg_CFP) + /* load card table base */ + ld reg_CARDTABLE, THREAD_CARD_TABLE_OFFSET(reg_THREAD) + /* Calculate LRA */ lis reg_LRA,lra@h ori reg_LRA,reg_LRA,lra@l @@ -260,7 +201,7 @@ lra: mr REG(3),reg_A0 /* Turn on pseudo-atomic */ - la reg_ALLOC,flag_PseudoAtomic(reg_ALLOC) + BEGIN_PSEUDO_ATOMIC /* Lisp does not understand the TOC register, so we have to restore it now - prior to the epilogue - because there are memory accesses @@ -268,31 +209,16 @@ lra: the load() and store() macros uses register 2 as the base */ ld 2, (24)(sp) -#ifdef LISP_FEATURE_SB_THREAD /* Store lisp state */ std reg_BSP,THREAD_BINDING_STACK_POINTER_OFFSET(reg_THREAD) std reg_CSP,THREAD_CONTROL_STACK_POINTER_OFFSET(reg_THREAD) std reg_CFP,THREAD_CONTROL_FRAME_POINTER_OFFSET(reg_THREAD) /* No longer in Lisp. */ - std reg_ALLOC,THREAD_FOREIGN_FUNCTION_CALL_ACTIVE_OFFSET(reg_THREAD) -#else - /* Store lisp state */ - clrrwi reg_NL1,reg_ALLOC,3 - store(reg_NL1,reg_NL2,dynamic_space_free_pointer) - /* load(reg_NL2,current_thread) */ - store(reg_BSP,reg_NL2,current_binding_stack_pointer) - store(reg_CSP,reg_NL2,current_control_stack_pointer) - store(reg_CFP,reg_NL2,current_control_frame_pointer) - - /* No longer in Lisp. */ - store(reg_NL1,reg_NL2,foreign_function_call_active) -#endif + std reg_THREAD,THREAD_FOREIGN_FUNCTION_CALL_ACTIVE_OFFSET(reg_THREAD) /* Check for interrupt */ - subi reg_ALLOC, reg_ALLOC, flag_PseudoAtomic - andi. reg_NL3, reg_ALLOC, flag_PseudoAtomicInterrupted - twnei reg_NL3,0 + END_PSEUDO_ATOMIC /* Back to C */ C_FULL_EPILOG @@ -326,7 +252,7 @@ lra: mr reg_NARGS,reg_NL3 /* Turn on pseudo-atomic */ - la reg_ALLOC,flag_PseudoAtomic(reg_ALLOC) + BEGIN_PSEUDO_ATOMIC /* Convert the return address to an offset and save it on the stack. */ sub reg_NFP,reg_LIP,reg_CODE @@ -335,7 +261,6 @@ lra: #endif std reg_NFP,8(reg_CFP) -#ifdef LISP_FEATURE_SB_THREAD /* Store Lisp state */ std reg_BSP,THREAD_BINDING_STACK_POINTER_OFFSET(reg_THREAD) std reg_CSP,THREAD_CONTROL_STACK_POINTER_OFFSET(reg_THREAD) @@ -343,35 +268,8 @@ lra: /* No longer in Lisp. */ std reg_CSP,THREAD_FOREIGN_FUNCTION_CALL_ACTIVE_OFFSET(reg_THREAD) -#else - /* Store Lisp state */ - // I have no idea what bit of state we're trying to set. - // At most this would clear the pseudo-atomic-interrupt flag. - clrrdi reg_NFP,reg_ALLOC,3 - store(reg_NFP,reg_CFUNC,dynamic_space_free_pointer) - /* load(reg_CFUNC,current_thread) */ - - store(reg_BSP,reg_CFUNC,current_binding_stack_pointer) - store(reg_CSP,reg_CFUNC,current_control_stack_pointer) - store(reg_CFP,reg_CFUNC,current_control_frame_pointer) - - /* No longer in Lisp */ - store(reg_CSP,reg_CFUNC,foreign_function_call_active) -#endif /* Disable pseudo-atomic; check pending interrupt */ - subi reg_ALLOC, reg_ALLOC, flag_PseudoAtomic - andi. reg_NL3, reg_ALLOC, flag_PseudoAtomicInterrupted - twnei reg_NL3, 0 - -#ifdef LISP_FEATURE_SB_SAFEPOINT - /* OK to run GC without stopping this thread from this point on. */ -# ifdef LISP_FEATURE_SB_THREAD - std reg_CSP,THREAD_SAVED_CSP_OFFSET(reg_THREAD) -# else - load(reg_CFUNC,all_threads) - std reg_CSP,THREAD_SAVED_CSP_OFFSET(reg_CFUNC) -# endif -#endif + END_PSEUDO_ATOMIC mr reg_NL3,reg_NARGS @@ -424,47 +322,16 @@ lra: li reg_A3,0 li reg_L0,0 li reg_L1,0 -#ifndef LISP_FEATURE_SB_THREAD - /* reg_THREAD is our TLS block pointer. */ - li reg_THREAD,0 -#endif li reg_LIP,0 -# ifdef LISP_FEATURE_SB_SAFEPOINT - /* No longer OK to run GC except at safepoints. */ -# ifdef LISP_FEATURE_SB_THREAD - std reg_ZERO,THREAD_SAVED_CSP_OFFSET(reg_THREAD) -# else - load(reg_BSP,all_threads) - std reg_ZERO,THREAD_SAVED_CSP_OFFSET(reg_BSP) -# endif -# endif - /* Atomic ... */ - li reg_ALLOC,flag_PseudoAtomic + BEGIN_PSEUDO_ATOMIC -#ifdef LISP_FEATURE_SB_THREAD /* No longer in foreign function call. */ std reg_ZERO,THREAD_FOREIGN_FUNCTION_CALL_ACTIVE_OFFSET(reg_THREAD) /* The binding stack pointer isn't preserved by C. */ ld reg_BSP,THREAD_BINDING_STACK_POINTER_OFFSET(reg_THREAD) -#else - /* No long in foreign function call. */ - store(reg_ZERO,reg_NL2,foreign_function_call_active) - - /* The free pointer may have moved */ - /* (moved below) */ - - /* The BSP wasn't preserved by C, so load it */ - load(reg_BSP,current_binding_stack_pointer) -#endif - /* This is important for CHENEYGC: It's the allocation - * pointer. It's also important for ROOM on GENCGC: - * It's a pointer to the end of dynamic space, used to - * determine where to stop in MAP-ALLOCATED-OBJECTS. */ - load(reg_NL4,dynamic_space_free_pointer) - add reg_ALLOC,reg_ALLOC,reg_NL4 /* Other lisp stack/frame pointers were preserved by C. I can't imagine why they'd have moved */ @@ -481,9 +348,7 @@ lra: mtlr reg_LIP /* No longer atomic */ - subi reg_ALLOC, reg_ALLOC, flag_PseudoAtomic - andi. reg_NL3, reg_ALLOC, flag_PseudoAtomicInterrupted - twnei reg_NL3, 0 + END_PSEUDO_ATOMIC /* Reset the lisp stack. */ mr reg_CSP,reg_CFP @@ -504,11 +369,6 @@ lra: .globl fun_end_breakpoint_trap .globl fun_end_breakpoint_end - /* Due to pointer verification in MAKE-LISP-OBJ, this must - include its header data (the offset from the start of the - code-object to the LRA). */ - .quad (((CODE_SIZE+1)&~1)<<N_WIDETAG_BITS)|RETURN_PC_WIDETAG - /* We are receiving unknown multiple values, thus must deal with the single-value and multiple-value cases separately. */ b fun_end_breakpoint_multiple_values @@ -520,10 +380,10 @@ lra: obtain a tagged pointer to the enclosing code component. Code pointers have no tag, so we have have to subtract OTHER_POINTER_LOWTAG as well as account for the number of - boxed words (see calculation for RETURN_PC_WIDETAG, above). - Restoring reg_CODE doesn't appear to be strictly necessary - here, but let's observe the niceties.*/ - addi reg_CODE, reg_LRA, ((CODE_SIZE+1)&~1)*-N_WORD_BYTES-OTHER_POINTER_LOWTAG + boxed words (see calculation for RETURN_PC_WIDETAG, above). */ + /* KLUDGE: I have no idea why CODE_SIZE+4 is correct here, + let alone the general formula for keeping this maintenance-free */ + addi reg_CODE, reg_LRA, (CODE_SIZE+4)*-N_WORD_BYTES-OTHER_POINTER_LOWTAG /* Multiple values are stored relative to reg_OCFP, which we set to be the current top-of-stack. */ diff --git a/src/runtime/ppc64-linux-os.h b/src/runtime/ppc64-linux-os.h index 264b6858d9..2cd2992e5c 100644 --- a/src/runtime/ppc64-linux-os.h +++ b/src/runtime/ppc64-linux-os.h @@ -10,4 +10,6 @@ unsigned long os_context_fp_control(os_context_t *context); #define RESTORE_FP_CONTROL_FROM_CONTEXT void os_restore_fp_control(os_context_t *context); +#define OS_CONTEXT_PC(context) context->uc_mcontext.regs->nip + #endif /* _PPC64_LINUX_OS_H */ diff --git a/src/runtime/ppc64-lispregs.h b/src/runtime/ppc64-lispregs.h index 5d8af24b8c..e0c31f7cd8 100644 --- a/src/runtime/ppc64-lispregs.h +++ b/src/runtime/ppc64-lispregs.h @@ -1,15 +1,5 @@ -#if defined LISP_FEATURE_DARWIN -#if defined __ASSEMBLER__ -#define REG(num) r##num -#define FREG(num) f##num -#else #define REG(num) num #define FREG(num) num -#endif -#else -#define REG(num) num -#define FREG(num) num -#endif #define NREGS 32 @@ -34,7 +24,7 @@ #define reg_BSP REG(14) /* Binding stack pointer */ #define reg_CFP REG(15) /* Control/value stack frame pointer */ #define reg_CSP REG(16) /* Control/value stack top */ -#define reg_ALLOC REG(17) /* (Global) dynamic free pointer */ +#define reg_CARDTABLE REG(17) /* GC Card Table address */ #define reg_NULL REG(18) /* NIL and globals nearby */ #define reg_CODE REG(19) /* Current function object */ #define reg_NFP REG(20) /* Lisp may save around FF-call */ diff --git a/src/runtime/print.c b/src/runtime/print.c index f8994be25b..893cf28129 100644 --- a/src/runtime/print.c +++ b/src/runtime/print.c @@ -25,26 +25,16 @@ #include "runtime.h" #include "code.h" #include "gc-internal.h" -#include <stdarg.h> +#include "gc-private.h" +#include "genesis/gc-tables.h" #include "thread.h" /* genesis/primitive-objects.h needs this */ #include <errno.h> #include <stdlib.h> #include <inttypes.h> - -/* FSHOW and odxprint provide debugging output for low-level information - * (signal handling, exceptions, safepoints) which is hard to debug by - * other means. - * - * If enabled at all, environment variables control whether calls of the - * form odxprint(name, ...) are enabled at run-time, e.g. using - * SBCL_DYNDEBUG="fshow fshow_signal safepoints". - * - * In the case of FSHOW and FSHOW_SIGNAL, old-style code from runtime.h - * can also be used to enable or disable these more aggressively. - */ +#include <setjmp.h> struct dyndebug_config dyndebug_config = { - QSHOW == 2, QSHOW_SIGNALS == 2 + QSHOW == 2, }; void @@ -65,7 +55,6 @@ dyndebug_init() int *ptrs[DYNDEBUG_NFLAGS]; dyndebug_init1(fshow, "FSHOW"); - dyndebug_init1(fshow_signal, "FSHOW_SIGNAL"); dyndebug_init1(gencgc_verbose, "GENCGC_VERBOSE"); dyndebug_init1(safepoints, "SAFEPOINTS"); dyndebug_init1(seh, "SEH"); @@ -128,97 +117,12 @@ dyndebug_init() #undef DYNDEBUG_NFLAGS } -/* Temporarily, odxprint merely performs the equivalent of a traditional - * FSHOW call, i.e. it merely formats to stderr. Ultimately, it should - * be restored to its full win32 branch functionality, where output to a - * file or to the debugger can be selected at runtime. */ - -void vodxprint_fun(const char *, va_list); - -void -odxprint_fun(const char *fmt, ...) -{ - va_list args; - va_start(args, fmt); - vodxprint_fun(fmt, args); - va_end(args); -} - -void -vodxprint_fun(const char *fmt, va_list args) -{ -#ifdef LISP_FEATURE_WIN32 - DWORD lastError = GetLastError(); -#endif - int original_errno = errno; - - QSHOW_BLOCK; - - char buf[1024]; - int n = 0; - -#ifdef LISP_FEATURE_SB_THREAD - struct thread *arch_os_get_current_thread(void); - struct thread *self = arch_os_get_current_thread(); - void *pth = self ? (void *) self->os_thread : 0; - snprintf(buf, sizeof(buf), "[%p/%p] ", self, pth); - n = strlen(buf); -#endif - - vsnprintf(buf + n, sizeof(buf) - n - 1, fmt, args); - /* buf is now zero-terminated (even in case of overflow). - * Our caller took care of the newline (if any) through `fmt'. */ - - /* A sufficiently POSIXy implementation of stdio will provide - * per-FILE locking, as defined in the spec for flockfile. At least - * glibc complies with this. Hence we do not need to perform - * locking ourselves here. (Should it turn out, of course, that - * other libraries opt for speed rather than safety, we need to - * revisit this decision.) */ - fputs(buf, stderr); - -#ifdef LISP_FEATURE_WIN32 - /* stdio's stderr is line-bufferred, i.e. \n ought to flush it. - * Unfortunately, MinGW does not behave the way I would expect it - * to. Let's be safe: */ - fflush(stderr); -#endif - - QSHOW_UNBLOCK; - -#ifdef LISP_FEATURE_WIN32 - SetLastError(lastError); -#endif - errno = original_errno; -} - -/* Translate the rather awkward syntax - * FSHOW((stderr, "xyz")) - * into the new and cleaner - * odxprint("xyz"). - * If we were willing to clean up all existing call sites, we could remove - * this wrapper function. (This is a function, because I don't know how to - * strip the extra parens in a macro.) */ -void -fshow_fun(void __attribute__((__unused__)) *ignored, - const char *fmt, - ...) -{ - va_list args; - va_start(args, fmt); - vodxprint_fun(fmt, args); - va_end(args); -} - #include "monitor.h" #include "vars.h" #include "os.h" #ifdef LISP_FEATURE_GENCGC #include "gencgc-alloc-region.h" /* genesis/thread.h needs this */ #endif -#if defined(LISP_FEATURE_WIN32) -# include "win32-thread-private-events.h" /* genesis/thread.h needs this */ -#endif #include "genesis/static-symbols.h" #include "genesis/primitive-objects.h" #include "genesis/static-symbols.h" @@ -246,6 +150,7 @@ static void indent(int in) fputs(spaces + 64 - in, stdout); } +static jmp_buf ldb_print_nlx; static boolean continue_p(boolean newline) { char buffer[256]; @@ -265,7 +170,7 @@ static boolean continue_p(boolean newline) if (fgets(buffer, sizeof(buffer), stdin)) { if (buffer[0] == 'n' || buffer[0] == 'N') - throw_to_monitor(); + longjmp(ldb_print_nlx, 1); else cur_lines = 0; } else { @@ -293,12 +198,7 @@ static void print_unknown(lispobj obj) printf("unknown object: %p", (void *)obj); } -/* Except for Alpha, we define sword_t as intptr_t, and 32-bit Darwin - * defines intptr_t as long, so the printf conversion is "ld", not "d". - * Alpha (32-on-64) defines sword_t as s32, so we need just "d". */ -#ifdef LISP_FEATURE_ALPHA -# define OBJ_FMTd "d" -#elif defined(PRIdPTR) +#ifdef PRIdPTR # define OBJ_FMTd PRIdPTR #else # error "Your inttypes.h is lame" @@ -406,6 +306,22 @@ static void brief_list(lispobj obj) } } +void print_list_car_ptrs(lispobj obj, FILE* f) +{ + char sep = '('; + int len = 0; + if (obj == NIL) { fprintf(f, "NIL"); return; } + do { + if (++len > 20) { fprintf(f, "...)"); return; } + fprintf(f, "%c%p", sep, (void*)CONS(obj)->car); + obj = CONS(obj)->cdr; + sep = ' '; + } while (listp(obj) && obj != NIL); + if (obj != NIL) fprintf(f, " . %p", (void*)obj); + putc(')', f); +} + + static void print_list(lispobj obj) { if (obj == NIL) { @@ -421,7 +337,7 @@ char * simple_base_stringize(struct vector * string) { if (widetag_of(&string->header) == SIMPLE_BASE_STRING_WIDETAG) return (char*)string->data; - int length = string->length; + int length = vector_len(string); char * newstring = malloc(length+1); uint32_t * data = (uint32_t*)string->data; int i; @@ -433,7 +349,7 @@ char * simple_base_stringize(struct vector * string) static void brief_struct(lispobj obj) { - struct instance *instance = (struct instance *)native_pointer(obj); + struct instance *instance = INSTANCE(obj); extern struct vector * instance_classoid_name(lispobj*); struct vector * classoid_name; classoid_name = instance_classoid_name((lispobj*)instance); @@ -449,20 +365,34 @@ static void brief_struct(lispobj obj) } #include "genesis/layout.h" +#include "genesis/defstruct-description.h" +#include "genesis/defstruct-slot-description.h" static boolean tagged_slot_p(struct layout *layout, int slot_index) { - lispobj bitmap = layout->bitmap; - sword_t fixnum = fixnum_value(bitmap); // optimistically - return fixnump(bitmap) - ? bitmap == make_fixnum(-1) || - (slot_index < N_WORD_BITS && ((fixnum >> slot_index) & 1) != 0) - : positive_bignum_logbitp(slot_index, - (struct bignum*)native_pointer(bitmap)); + // Since we're doing this scan, we could return the name + // and exact raw type. +#ifdef LISP_FEATURE_METASPACE + struct wrapper *wrapper = (void*)(layout->friend-INSTANCE_POINTER_LOWTAG); + if (instancep(wrapper->_info)) { + struct defstruct_description* dd = (void*)(wrapper->_info-INSTANCE_POINTER_LOWTAG); +#else + if (instancep(layout->_info)) { + struct defstruct_description* dd = (void*)(layout->_info-INSTANCE_POINTER_LOWTAG); +#endif + lispobj slots = dd->slots; + for ( ; slots != NIL ; slots = CONS(slots)->cdr ) { + struct defstruct_slot_description* dsd = + (void*)(CONS(slots)->car-INSTANCE_POINTER_LOWTAG); + if ((fixnum_value(dsd->bits) >> DSD_INDEX_SHIFT) == slot_index) + return (fixnum_value(dsd->bits) & DSD_RAW_TYPE_MASK) == 0; + } + } + return 0; } static void print_struct(lispobj obj) { - struct instance *instance = (struct instance *)native_pointer(obj); + struct instance *instance = INSTANCE(obj); short int i; char buffer[16]; lispobj layout = instance_layout(native_pointer(obj)); @@ -481,7 +411,7 @@ static void print_struct(lispobj obj) void show_lstring(struct vector * string, int quotes, FILE *s) { int ucs4_p = 0; - int i, len = fixnum_value(string->length); + int i, len = vector_len(string); #ifdef SIMPLE_CHARACTER_STRING_WIDETAG if (widetag_of(&string->header) == SIMPLE_CHARACTER_STRING_WIDETAG) { @@ -513,7 +443,6 @@ void show_lstring(struct vector * string, int quotes, FILE *s) static void brief_fun_or_otherptr(lispobj obj) { - extern void safely_show_lstring(struct vector*, int, FILE*); lispobj *ptr, header; int type; struct symbol *symbol; @@ -524,9 +453,10 @@ static void brief_fun_or_otherptr(lispobj obj) switch (type) { case SYMBOL_WIDETAG: symbol = (struct symbol *)ptr; - if (symbol->package == NIL) + lispobj package = symbol_package(symbol); + if (package == NIL) printf("#:"); - show_lstring(VECTOR(symbol->name), 0, stdout); + show_lstring(symbol_name(symbol), 0, stdout); break; case SIMPLE_BASE_STRING_WIDETAG: @@ -545,7 +475,7 @@ static void brief_fun_or_otherptr(lispobj obj) if (lowtag_of(name) == OTHER_POINTER_LOWTAG && widetag_of(native_pointer(name)) == SYMBOL_WIDETAG) { printf(" for "); - struct vector* str = symbol_name(native_pointer(name)); + struct vector* str = symbol_name(SYMBOL(name)); safely_show_lstring(str, 0, stdout); } } @@ -557,10 +487,14 @@ static void print_slots(char **slots, int count, lispobj *ptr) { while (count-- > 0) { if (*slots) { - // kludge for half-lispword sized slot - print_obj(*slots, - (N_WORD_BYTES == 8 && !strcmp(*slots, "boxed_size: ")) - ? *ptr & 0xFFFFFFFF : *ptr); + // kludge for encoded slots + lispobj word = *ptr; + char* slot_name = *slots; + if (N_WORD_BYTES == 8 && !strcmp(slot_name, "boxed_size: ")) word = word & 0xFFFFFFFF; +#ifdef LISP_FEATURE_COMPACT_SYMBOL + else if (!strcmp(slot_name, "name: ")) word = decode_symbol_name(word); +#endif + print_obj(slot_name, word); slots++; } else { print_obj("???: ", *ptr); @@ -569,35 +503,16 @@ static void print_slots(char **slots, int count, lispobj *ptr) } } -lispobj symbol_function(lispobj* symbol) +lispobj symbol_function(struct symbol* symbol) { - lispobj info = ((struct symbol*)symbol)->info; - if (listp(info)) - info = CONS(info)->cdr; - if (lowtag_of(info) == OTHER_POINTER_LOWTAG) { - struct vector* v = VECTOR(info); - int len = fixnum_value(v->length); - if (len != 0) { - lispobj elt = v->data[0]; // Just like INFO-VECTOR-FDEFN - if (fixnump(elt) && (fixnum_value(elt) & 07777) >= 07701) { - lispobj fdefn = v->data[len-1]; - if (lowtag_of(fdefn) == OTHER_POINTER_LOWTAG) - return FDEFN(fdefn)->fun; - } - } - } + if (symbol->fdefn) return FDEFN(symbol->fdefn)->fun; return NIL; } static void print_fun_or_otherptr(lispobj obj) { -#ifndef LISP_FEATURE_ALPHA lispobj *ptr; unsigned long header; -#else - u32 *ptr; - u32 header; -#endif int count, type, index; char buffer[16]; @@ -620,6 +535,7 @@ static void print_fun_or_otherptr(lispobj obj) switch (type) { case BIGNUM_WIDETAG: + count &= 0x7fffff; ptr += count; NEWLINE_OR_RETURN; printf("0x"); @@ -645,8 +561,21 @@ static void print_fun_or_otherptr(lispobj obj) // Only 1 byte of a symbol header conveys its size. // The other bytes may be freely used by the backend. print_slots(symbol_slots, count & 0xFF, ptr); - if (symbol_function(ptr-1) != NIL) - print_obj("fun: ", symbol_function(ptr-1)); + struct symbol* sym = (void*)(ptr - 1); + if (symbol_function(sym) != NIL) print_obj("fun: ", symbol_function(sym)); +#ifdef LISP_FEATURE_SB_THREAD + int tlsindex = tls_index_of(sym); + struct thread*th = get_sb_vm_thread(); + if (th != 0 && tlsindex != 0) { + lispobj v = *(lispobj*)(tlsindex + (char*)th); + print_obj("tlsval: ", v); + } +#endif +#ifdef LISP_FEATURE_COMPACT_SYMBOL + // print_obj doesn't understand raw words, so make it a fixnum + int pkgid = symbol_package_id(sym) << N_FIXNUM_TAG_BITS; + print_obj("package_id: ", pkgid); +#endif break; #if N_WORD_BITS == 32 @@ -713,7 +642,7 @@ static void print_fun_or_otherptr(lispobj obj) case SIMPLE_VECTOR_WIDETAG: NEWLINE_OR_RETURN; { - long length = fixnum_value(*ptr); + long length = vector_len(VECTOR(obj)); printf("length = %ld", length); ptr++; index = 0; @@ -724,15 +653,21 @@ static void print_fun_or_otherptr(lispobj obj) } break; - // FIXME: This case looks unreachable. print_struct() does it - case INSTANCE_WIDETAG: + case SIMPLE_BIT_VECTOR_WIDETAG: NEWLINE_OR_RETURN; - count = instance_length(header); - printf("length = %ld", (long) count); - index = 0; - while (count-- > 0) { - sprintf(buffer, "%d: ", index++); - print_obj(buffer, *ptr++); + { + long length = vector_len(VECTOR(obj)); + printf("length = %ld : ", length); + int bits_to_print = (length < N_WORD_BITS) ? length : N_WORD_BITS; + uword_t word = ptr[1]; + int i; + for(i=0; i<bits_to_print; ++i) { + putchar((word & 1) ? '1' : '0'); + if ((i%8)==7) putchar('_'); + word >>= 1; + } + if(bits_to_print < length) printf("..."); + printf("\n"); } break; @@ -774,11 +709,7 @@ static void print_fun_or_otherptr(lispobj obj) case SAP_WIDETAG: NEWLINE_OR_RETURN; -#ifndef LISP_FEATURE_ALPHA - printf("0x%08lx", (unsigned long) *ptr); -#else - printf("0x%016lx", *(lispobj*)(ptr+1)); -#endif + printf("%p", (void*)*ptr); break; case WEAK_POINTER_WIDETAG: @@ -793,14 +724,14 @@ static void print_fun_or_otherptr(lispobj obj) case FDEFN_WIDETAG: print_slots(fdefn_slots, 2, ptr); - print_obj("entry: ", fdefn_callee_lispobj((struct fdefn*)(ptr-1))); + print_obj("entry: ", decode_fdefn_rawfun((struct fdefn*)(ptr-1))); break; - // Make certain vectors printable from C for when all hell breaks lose + // Make some vectors printable from C, for when all hell breaks lose case SIMPLE_ARRAY_UNSIGNED_BYTE_32_WIDETAG: NEWLINE_OR_RETURN; { - long length = fixnum_value(*ptr); + long length = vector_len(VECTOR(obj)); uint32_t * data = (uint32_t*)(ptr + 1); long i; printf("#("); @@ -813,9 +744,8 @@ static void print_fun_or_otherptr(lispobj obj) break; default: NEWLINE_OR_RETURN; - if (type >= SIMPLE_ARRAY_UNSIGNED_BYTE_2_WIDETAG && - type <= SIMPLE_BIT_VECTOR_WIDETAG) - printf("length = %ld", (long)fixnum_value(*ptr)); + if (specialized_vector_widetag_p(type)) + printf("length = %"OBJ_FMTd, vector_len(VECTOR(obj))); else printf("Unknown header object?"); break; @@ -892,7 +822,8 @@ void print(lispobj obj) max_depth = 5; max_lines = 20; - print_obj("", obj); + if (!setjmp(ldb_print_nlx)) + print_obj("", obj); putchar('\n'); } @@ -915,30 +846,36 @@ void brief_print(lispobj obj) #include "forwarding-ptr.h" #include "genesis/classoid.h" -struct vector * symbol_name(lispobj * sym) +struct vector * symbol_name(struct symbol* sym) { - if (forwarding_pointer_p(sym)) - sym = native_pointer(forwarding_pointer_value(sym)); - if (lowtag_of(((struct symbol*)sym)->name) != OTHER_POINTER_LOWTAG) - return NULL; - lispobj * name = native_pointer(((struct symbol*)sym)->name); - if (forwarding_pointer_p(name)) - name = native_pointer(forwarding_pointer_value(name)); - return (struct vector*)name; + if (forwarding_pointer_p((lispobj*)sym)) + sym = (void*)native_pointer(forwarding_pointer_value((lispobj*)sym)); + lispobj name = sym->name; + if (lowtag_of(name) != OTHER_POINTER_LOWTAG) return NULL; + lispobj string = decode_symbol_name(name); + return VECTOR(follow_maybe_fp(string)); } struct vector * classoid_name(lispobj * classoid) { if (forwarding_pointer_p(classoid)) classoid = native_pointer(forwarding_pointer_value(classoid)); + // Classoids are named by symbols even though a CLASS name is arbitrary (theoretically) lispobj sym = ((struct classoid*)classoid)->name; - return lowtag_of(sym) != OTHER_POINTER_LOWTAG ? NULL - : symbol_name(native_pointer(sym)); + return lowtag_of(sym) != OTHER_POINTER_LOWTAG ? NULL : symbol_name(SYMBOL(sym)); } struct vector * layout_classoid_name(lispobj * layout) { +#ifdef LISP_FEATURE_METASPACE + // layout can't be forwarded, but wrapper could be + lispobj* wrapper = native_pointer(((struct layout*)layout)->friend); + if (forwarding_pointer_p(wrapper)) + wrapper = native_pointer(forwarding_pointer_value(wrapper)); + lispobj classoid = ((struct wrapper*)wrapper)->classoid; +#else if (forwarding_pointer_p(layout)) layout = native_pointer(forwarding_pointer_value(layout)); lispobj classoid = ((struct layout*)layout)->classoid; +#endif return instancep(classoid) ? classoid_name(native_pointer(classoid)) : NULL; } struct vector * instance_classoid_name(lispobj * instance) diff --git a/src/runtime/print.h b/src/runtime/print.h index f5b284444e..a5bc4365b3 100644 --- a/src/runtime/print.h +++ b/src/runtime/print.h @@ -18,5 +18,17 @@ extern void print(lispobj obj); extern void brief_print(lispobj obj); extern void reset_printer(void); +#include "genesis/vector.h" +#include <stdio.h> +extern void safely_show_lstring(struct vector*, int, FILE*); +extern void print_list_car_ptrs(lispobj, FILE*); + +#define odxprint(topic, fmt, ...) \ + do \ + if (dyndebug_config.dyndebug_##topic) \ + odxprint_fun(fmt "\n", ##__VA_ARGS__); \ + while (0) + +void odxprint_fun(const char *fmt, ...); #endif diff --git a/src/runtime/private-cons.inc b/src/runtime/private-cons.inc index ca561d950c..7f86804903 100644 --- a/src/runtime/private-cons.inc +++ b/src/runtime/private-cons.inc @@ -1,3 +1,5 @@ +/* -*- Mode: C -*- */ + /* GC private-use list allocator. * * A private-use list is a list of private-uses conses, @@ -60,6 +62,7 @@ static void release_pages_impl() #else static page_index_t private_cons_page_chain = -1; +#define GC_PRIVATE_CONS_GENERATION 6 static struct cons* private_cons_impl() { @@ -67,24 +70,30 @@ static struct cons* private_cons_impl() page_bytes_t bytes_used; struct cons* cons; - if (page >= 0 && (bytes_used = page_bytes_used(page)) < GENCGC_CARD_BYTES) { + if (page >= 0 && (bytes_used = page_bytes_used(page)) < GENCGC_PAGE_BYTES) { cons = (struct cons*)(page_address(page) + bytes_used); } else { - page = alloc_start_page(UNBOXED_PAGE_FLAG, 0); + page = get_alloc_start_page(PAGE_TYPE_UNBOXED); page_index_t last_page __attribute__((unused)) = - gc_find_freeish_pages(&page, GENCGC_CARD_BYTES, - SINGLE_OBJECT_FLAG | UNBOXED_PAGE_FLAG, 0); - // See question about last_page in gc_alloc_large - set_alloc_start_page(UNBOXED_PAGE_FLAG, 0, page); + gc_find_freeish_pages(&page, GENCGC_PAGE_BYTES, + SINGLE_OBJECT_FLAG | PAGE_TYPE_UNBOXED, + GC_PRIVATE_CONS_GENERATION); + set_alloc_start_page(PAGE_TYPE_UNBOXED, page); struct cons* page_header = (struct cons*)page_address(page); if (PRIVATE_CONS_DEBUG) - fprintf(stderr, "GC-private page @ %p\n", page_header); + fprintf(stderr, "GC-private page %"PAGE_INDEX_FMT" @ %p\n", page, page_header); gc_assert(last_page == page); - gc_assert(!page_table[page].write_protected); - page_table[page].gen = 0; - page_table[page].type = UNBOXED_PAGE_FLAG; - zero_dirty_pages(page, page, 0); + gc_dcheck(page_cards_all_marked_nonsticky(page)); + page_table[page].gen = GC_PRIVATE_CONS_GENERATION; + page_table[page].type = PAGE_TYPE_UNBOXED; +#ifdef LISP_FEATURE_DARWIN_JIT + // UNBOXED pages do not generally required zero-fill. + // arm64+Darwin might perform zeroing to alter MMU-based protection. + zeroize_pages_if_needed(page, page, PAGE_TYPE_UNBOXED); +#elif defined LISP_FEATURE_WIN32 + os_commit_memory(page_address(page), GENCGC_PAGE_BYTES); +#endif page_index_t tail = private_cons_page_chain; page_header->car = 0; // unused page_header->cdr = (lispobj)(tail >= 0 ? page_address(tail) : 0); @@ -98,15 +107,16 @@ static struct cons* private_cons_impl() static void release_pages_impl() { - struct cons* list; + struct cons *list, *next; if (private_cons_page_chain >= 0) { - for (list = (struct cons*)page_address(private_cons_page_chain) ; - list ; - list = (struct cons*)list->cdr) { + for (list = (struct cons*)page_address(private_cons_page_chain) ; + list ; list = next) { page_index_t index = find_page_index(list); + next = (struct cons*)list->cdr; // read prior to decommitting (if we do that) if (PRIVATE_CONS_DEBUG) fprintf(stderr, "Freeing GC-private page @ %p (index %ld)\n", list, (long)index); + set_page_need_to_zero(index, 1); set_page_bytes_used(index, 0); reset_page_flags(index); } @@ -127,12 +137,19 @@ uword_t gc_private_cons(uword_t car, uword_t cdr) cons = private_cons_impl(); cons->car = car; cons->cdr = cdr; +#if PRIVATE_CONS_DEBUG + if (cdr) fprintf(stderr, "private_cons(%p,%p)=%p\n", (void*)car, (void*)cdr, cons); +#endif return (uword_t)cons; } /* Push all the conses in 'list' onto the recycle list. */ void gc_private_free(struct cons* list) { +#if PRIVATE_CONS_DEBUG + { int n = 0; struct cons* tail = list; while(tail) ++n, tail = (void*)tail->cdr; + if (n>1) fprintf(stderr, "private_free(%p){%d}\n", list, n); } +#endif struct cons* head = list; while (list->cdr) list = (struct cons*)list->cdr; diff --git a/src/runtime/pseudo-atomic.h b/src/runtime/pseudo-atomic.h index 06dcc6a7ec..af95673cd8 100644 --- a/src/runtime/pseudo-atomic.h +++ b/src/runtime/pseudo-atomic.h @@ -1,5 +1,5 @@ /* - * macros for manipulating pseudo-atomic flags (per thread) + * macros for getting/setting the pseudo-atomic flags (per thread, if applicable) */ /* @@ -16,6 +16,35 @@ #ifndef PSEUDO_ATOMIC_H #define PSEUDO_ATOMIC_H +#if defined LISP_FEATURE_SPARC || defined LISP_FEATURE_PPC || defined LISP_FEATURE_PPC64 + +/* These architectures make no distinction between +/- sb-thread. + * They always use per-thread bit and never static symbols for the PA bits. + * The PA-Atomic field is at byte 0 of the thread slot regardless of endianness. + * The PA-Interrupted field is at byte 2 regardless of endian-ness. + * This holds for either word size. + * These values can be anything - they just have to be compatible between C and Lisp. + * Lisp uses NULL-TN to set pseudo-atomic and THREAD-TN to clear it. */ +# define get_pseudo_atomic_atomic(th) (th)->pseudo_atomic_bits[0] != 0 +# define set_pseudo_atomic_atomic(th) (th)->pseudo_atomic_bits[0] = 1 +# define clear_pseudo_atomic_atomic(th) (th)->pseudo_atomic_bits[0] = 0 +// A 2-byte field allows for 'lhz' followed by 'twi' +# define get_pseudo_atomic_interrupted(th) (th)->pseudo_atomic_bits[2] != 0 +// make it look like a fixnum in case we only have a descriptor register +// at our disposal when loading the flag +# define set_pseudo_atomic_interrupted(th) (th)->pseudo_atomic_bits[2] = 8 +# define clear_pseudo_atomic_interrupted(th) (th)->pseudo_atomic_bits[2] = 0 + +#elif defined LISP_FEATURE_ARM || defined LISP_FEATURE_ARM64 \ + || defined LISP_FEATURE_MIPS || defined LISP_FEATURE_RISCV + +/* These architectures use a thread slot if #+sb-thread, + * or else two static symbols if #-sb-thread. + * The complication is that if using a thread slot, the the values + * are stored in two bits, but otherwise the value is the entire word. */ + +#ifdef LISP_FEATURE_SB_THREAD + #define get_pseudo_atomic_atomic(thread) \ ((thread)->pseudo_atomic_bits & flag_PseudoAtomic) #define set_pseudo_atomic_atomic(thread) \ @@ -29,4 +58,125 @@ #define clear_pseudo_atomic_interrupted(thread) \ ((thread)->pseudo_atomic_bits &= ~flag_PseudoAtomicInterrupted) +#else + +static inline int +get_pseudo_atomic_atomic(struct thread *thread) +{ + return SymbolValue(PSEUDO_ATOMIC_ATOMIC, thread) != NIL; +} + +static inline void +set_pseudo_atomic_atomic(struct thread *thread) +{ + SetSymbolValue(PSEUDO_ATOMIC_ATOMIC, PSEUDO_ATOMIC_ATOMIC, thread); +} + +static inline void +clear_pseudo_atomic_atomic(struct thread *thread) +{ + SetSymbolValue(PSEUDO_ATOMIC_ATOMIC, NIL, thread); +} + +static inline int +get_pseudo_atomic_interrupted(struct thread *thread) +{ + return SymbolValue(PSEUDO_ATOMIC_INTERRUPTED, thread) != 0; +} + +static inline void +set_pseudo_atomic_interrupted(struct thread *thread) +{ + #ifndef DO_PENDING_INTERRUPT + // RISCV defines do_pending_interrupt as a lisp asm routine the address of which + // is stored in a static lisp symbol and which in C is obtained via #define. + extern void do_pending_interrupt(); + #endif + SetSymbolValue(PSEUDO_ATOMIC_INTERRUPTED, (lispobj)do_pending_interrupt, thread); +} + +static inline void +clear_pseudo_atomic_interrupted(struct thread *thread) +{ + SetSymbolValue(PSEUDO_ATOMIC_INTERRUPTED, 0, 0); +} +#endif // LISP_FEATURE_SB_THREAD + +#elif defined LISP_FEATURE_X86 || defined LISP_FEATURE_X86_64 + +/* x86 uses either a thread slot, or a single static symbol holding + * the same value as the thread slot would hold. + * The encoding of the values is strange - the entire word is onzero + * whend pseudo-atomic, and the lowest bit should be 0. + * If interrupted, the low bit becomes 1. This seems a little bogus because + * symbol->value at that point can have "illegal" bits (non-descriptor). + * I guess the reason it's allowed is GC can't ever see the bad value. + * But it sure seems like it's asking for trouble */ + +#ifdef LISP_FEATURE_X86_64 +# define LISPOBJ_ASM_SUFFIX "q" +#else +# define LISPOBJ_ASM_SUFFIX "l" #endif + +#ifdef LISP_FEATURE_SB_THREAD +# define pa_bits thread->pseudo_atomic_bits +#else +# define pa_bits SYMBOL(PSEUDO_ATOMIC_BITS)->value +#endif + +#include "interr.h" // for lose() + +static inline int +get_pseudo_atomic_atomic(struct thread __attribute__((unused)) *thread) +{ + // mask out the 'interrupted' bit before testing + return (pa_bits & ~1) != 0; +} + +// FIXME: all this seems unnecessary use of inline assembly + +static inline void +set_pseudo_atomic_atomic(struct thread __attribute__((unused)) *thread) +{ + if (pa_bits) lose("set_pseudo_atomic_atomic: bits=%"OBJ_FMTX, pa_bits); + __asm__ volatile ("or" LISPOBJ_ASM_SUFFIX " $~1, %0" : "+m" (pa_bits)); +} + +static inline void +clear_pseudo_atomic_atomic(struct thread __attribute__((unused)) *thread) +{ + __asm__ volatile ("and" LISPOBJ_ASM_SUFFIX " $1, %0" : "+m" (pa_bits)); +} + +static inline int +get_pseudo_atomic_interrupted(struct thread __attribute__((unused)) *thread) +{ + return pa_bits & 1; +} + +static inline void +set_pseudo_atomic_interrupted(struct thread *thread) +{ + if (!get_pseudo_atomic_atomic(thread)) + lose("set_pseudo_atomic_interrupted not in pseudo atomic"); + __asm__ volatile ("or" LISPOBJ_ASM_SUFFIX " $1, %0" : "+m" (pa_bits)); +} + +static inline void +clear_pseudo_atomic_interrupted(struct thread *thread) +{ + if (get_pseudo_atomic_atomic(thread)) + lose("clear_pseudo_atomic_interrupted in pseudo atomic"); + __asm__ volatile ("and" LISPOBJ_ASM_SUFFIX " $~1, %0" : "+m" (pa_bits)); +} +#undef pa_bits +#undef LISPOBJ_ASM_SUFFIX + +#else + +#error "architecture needs definition of pseudo-atomic bits" + +#endif + +#endif /* PSEUDO_ATOMIC_H */ diff --git a/src/runtime/pthread-futex.c b/src/runtime/pthread-futex.c deleted file mode 100644 index cefb274f54..0000000000 --- a/src/runtime/pthread-futex.c +++ /dev/null @@ -1,339 +0,0 @@ -/* An approximation of Linux futexes implemented using pthread mutexes - * and pthread condition variables. - */ - -/* - * This software is part of the SBCL system. See the README file for - * more information. - * - * The software is in the public domain and is provided with - * absolutely no warranty. See the COPYING and CREDITS files for more - * information. - */ - -#include "sbcl.h" - -#if defined(LISP_FEATURE_SB_THREAD) && defined(LISP_FEATURE_SB_PTHREAD_FUTEX) - -#include <errno.h> -#include <pthread.h> -#include <stdlib.h> - -#include "runtime.h" -#include "arch.h" -#include "target-arch-os.h" -#include "os.h" - -#define FUTEX_WAIT_NSEC (10000000) /* 10 msec */ - -#if 1 -# define futex_assert(ex) \ -do { \ - if (!(ex)) futex_abort(); \ -} while (0) -# define futex_assert_verbose(ex, fmt, ...) \ -do { \ - if (!(ex)) { \ - fprintf(stderr, fmt, ## __VA_ARGS__); \ - futex_abort(); \ - } \ -} while (0) -#else -# define futex_assert(ex) -# define futex_assert_verbose(ex, fmt, ...) -#endif - -#define futex_abort() \ - lose("Futex assertion failure, file \"%s\", line %d", __FILE__, __LINE__) - -struct futex { - struct futex *prev; - struct futex *next; - int *lock_word; - pthread_mutex_t mutex; - pthread_cond_t cond; - int count; -}; - -static pthread_mutex_t futex_lock = PTHREAD_MUTEX_INITIALIZER; - -static struct futex *futex_head = NULL; -static struct futex *futex_free_head = NULL; - -static struct futex * -futex_add(struct futex *head, struct futex *futex) -{ - futex->prev = NULL; - futex->next = head; - if (head != NULL) - head->prev = futex; - head = futex; - - return head; -} - -static struct futex * -futex_delete(struct futex *head, struct futex *futex) -{ - if (head == futex) - head = futex->next; - if (futex->prev != NULL) - futex->prev->next = futex->next; - if (futex->next != NULL) - futex->next->prev = futex->prev; - - return head; -} - -static struct futex * -futex_find(struct futex *head, int *lock_word) -{ - struct futex *futex; - - for (futex = head; futex != NULL; futex = futex->next) { - if (futex->lock_word == lock_word) - break; - } - - return futex; -} - -static struct futex * -futex_get(int *lock_word) -{ - int ret; - struct futex *futex; - - ret = pthread_mutex_lock(&futex_lock); - futex_assert(ret == 0); - - futex = futex_find(futex_head, lock_word); - - if (futex != NULL) - futex->count++; - - ret = pthread_mutex_unlock(&futex_lock); - futex_assert(ret == 0); - - if (futex != NULL) { - ret = pthread_mutex_lock(&futex->mutex); - futex_assert(ret == 0); - } - - return futex; -} - -static struct futex * -futex_allocate(int *lock_word) -{ - int ret; - struct futex *futex; - - ret = pthread_mutex_lock(&futex_lock); - futex_assert(ret == 0); - - futex = futex_free_head; - - if (futex != NULL) - futex_free_head = futex_delete(futex_free_head, futex); - - ret = pthread_mutex_unlock(&futex_lock); - futex_assert(ret == 0); - - if (futex == NULL) { - futex = malloc(sizeof(struct futex)); - futex_assert(futex != NULL); - - ret = pthread_mutex_init(&futex->mutex, NULL); - futex_assert(ret == 0); - - ret = pthread_cond_init(&futex->cond, NULL); - futex_assert(ret == 0); - } - - futex->lock_word = lock_word; - futex->count = 1; - - /* Lock mutex before register to avoid race conditions. */ - ret = pthread_mutex_lock(&futex->mutex); - futex_assert(ret == 0); - - ret = pthread_mutex_lock(&futex_lock); - futex_assert(ret == 0); - - futex_head = futex_add(futex_head, futex); - - ret = pthread_mutex_unlock(&futex_lock); - futex_assert(ret == 0); - - return futex; -} - -static void -futex_cleanup(void *p) -{ - struct futex *futex = (struct futex *)p; - int ret, count; - - ret = pthread_mutex_lock(&futex_lock); - futex_assert(ret == 0); - - count = --futex->count; - if (count <= 0) { - futex_head = futex_delete(futex_head, futex); - futex_free_head = futex_add(futex_free_head, futex); - } - - ret = pthread_mutex_unlock(&futex_lock); - futex_assert(ret == 0); - - ret = pthread_mutex_unlock(&futex->mutex); - futex_assert(ret == 0); -} - -static int -futex_relative_to_abs(struct timespec *tp, int relative) -{ - int ret; - struct timeval tv; - - ret = gettimeofday(&tv, NULL); - if (ret != 0) - return ret; - tp->tv_sec = tv.tv_sec + (tv.tv_usec * 1000 + relative) / 1000000000; - tp->tv_nsec = (tv.tv_usec * 1000 + relative) % 1000000000; - return 0; -} - -static int -futex_istimeout(struct timeval *timeout) -{ - int ret; - struct timeval tv; - - if (timeout == NULL) - return 0; - - ret = gettimeofday(&tv, NULL); - if (ret != 0) - return ret; - - return (tv.tv_sec > timeout->tv_sec) || - ((tv.tv_sec == timeout->tv_sec) && tv.tv_usec > timeout->tv_usec); -} - -int -futex_wait(int *lock_word, int oldval, long sec, unsigned long usec) -{ - int ret, result; - struct futex *futex; - sigset_t oldset; - struct timeval tv, *timeout; - -again: - if (sec < 0) - timeout = NULL; - else { - ret = gettimeofday(&tv, NULL); - if (ret != 0) - return ret; - tv.tv_sec = tv.tv_sec + sec + (tv.tv_usec + usec) / 1000000; - tv.tv_usec = (tv.tv_usec + usec) % 1000000; - timeout = &tv; - } - - block_deferrable_signals(&oldset); - - futex = futex_get(lock_word); - - if (futex == NULL) - futex = futex_allocate(lock_word); - - pthread_cleanup_push(futex_cleanup, futex); - - /* Compare lock_word after the lock is aquired to avoid race - * conditions. */ - if (*(volatile int *)lock_word != oldval) { - result = EWOULDBLOCK; - goto done; - } - - /* It's not possible to unwind frames across pthread_cond_wait(3). */ - for (;;) { - int i; - sigset_t pendset; - struct timespec abstime; - - ret = futex_relative_to_abs(&abstime, FUTEX_WAIT_NSEC); - futex_assert(ret == 0); - - result = pthread_cond_timedwait(&futex->cond, &futex->mutex, - &abstime); - futex_assert(result == 0 || result == ETIMEDOUT); - - if (result != ETIMEDOUT || futex_istimeout(timeout)) - break; - - /* futex system call of Linux returns with EINTR errno when - * it's interrupted by signals. Check pending signals here to - * emulate this behaviour. */ - sigpending(&pendset); - for (i = 1; i < NSIG; i++) { - if (sigismember(&pendset, i) && sigismember(&newset, i)) { - result = EINTR; - goto done; - } - } - } -done: - ; /* Null statement is required between label and pthread_cleanup_pop. */ - pthread_cleanup_pop(1); - thread_sigmask(SIG_SETMASK, &oldset, NULL); - - /* futex_wake() in linux-os.c loops when futex system call returns - * EINTR. */ - if (result == EINTR) { - sched_yield(); - goto again; - } - - if (result == ETIMEDOUT) - return 1; - - return result; -} - -int -futex_wake(int *lock_word, int n) -{ - int ret; - struct futex *futex; - sigset_t oldset; - - block_deferrable_signals(&oldset); - - futex = futex_get(lock_word); - - if (futex != NULL) { - pthread_cleanup_push(futex_cleanup, futex); - - /* The lisp-side code passes N=2**29-1 for a broadcast. */ - if (n >= ((1 << 29) - 1)) { - /* CONDITION-BROADCAST */ - ret = pthread_cond_broadcast(&futex->cond); - futex_assert(ret == 0); - } else { - while (n-- > 0) { - ret = pthread_cond_signal(&futex->cond); - futex_assert(ret == 0); - } - } - - pthread_cleanup_pop(1); - } - - thread_sigmask(SIG_SETMASK, &oldset, NULL); - - return 0; -} -#endif diff --git a/src/runtime/pthreads_win32.c b/src/runtime/pthreads_win32.c deleted file mode 100644 index 6fdad6cdec..0000000000 --- a/src/runtime/pthreads_win32.c +++ /dev/null @@ -1,1214 +0,0 @@ -#include "sbcl.h" -#ifdef LISP_FEATURE_SB_THREAD /* entire file */ - -#define PTHREAD_INTERNALS -#include "pthreads_win32.h" -#include <stdlib.h> -#include <stdio.h> -#include <time.h> -#include <sys/time.h> - -#ifdef PTHREAD_DEBUG_OUTPUT -#define pthshow(fmt,...) \ - do { \ - fprintf(stderr,fmt "\n", __VA_ARGS__); \ - fflush(stderr); \ - } while (0) - -#define DEBUG_OWN(cs) do {(cs)->owner=pthread_self(); } while(0) -#define DEBUG_RELEASE(cs) do {(cs)->owner=0;} while(0) - -#else -#define pthshow(fmt,...) do {} while (0) -#define DEBUG_OWN(cs) do {} while(0) -#define DEBUG_RELEASE(cs) do {} while(0) -#endif - - -struct freelist_cell { - struct freelist_cell * next; - void* data; -}; - -struct freelist { - void* (*create_fn)(); - pthread_mutex_t lock; - struct freelist_cell * empty; - struct freelist_cell * full; - unsigned int count; -}; - -#define FREELIST_INITIALIZER(create_fn) \ - { \ - event_create, PTHREAD_MUTEX_INITIALIZER, \ - NULL, NULL, 0 \ - } \ - - -static void* freelist_get(struct freelist *fl) -{ - void* result = NULL; - if (fl->full) { - pthread_mutex_lock(&fl->lock); - if (fl->full) { - struct freelist_cell *cell = fl->full; - fl->full = cell->next; - result = cell->data; - cell->next = fl->empty; - fl->empty = cell; - } - pthread_mutex_unlock(&fl->lock); - } - if (!result) { - result = fl->create_fn(); - } - return result; -} - -static void freelist_return(struct freelist *fl, void*data) -{ - struct freelist_cell* cell = NULL; - if (fl->empty) { - pthread_mutex_lock(&fl->lock); - if (fl->empty) { - cell = fl->empty; - fl->empty = cell->next; - goto add_locked; - } - pthread_mutex_unlock(&fl->lock); - } - if (!cell) { - int i,n=32; - cell = malloc(sizeof(*cell)*n); - for (i=0; i<(n-1); ++i) - cell[i].next = &cell[i+1]; - cell[i].next = NULL; - } - - pthread_mutex_lock(&fl->lock); - ++fl->count; - add_locked: - cell->data = data; - cell->next = fl->full; - fl->full = cell; - pthread_mutex_unlock(&fl->lock); -} - -int pthread_attr_init(pthread_attr_t *attr) -{ - attr->stack_size = 0; - return 0; -} - -int pthread_attr_destroy(pthread_attr_t *attr) -{ - return 0; -} - -int pthread_attr_setstack(pthread_attr_t *attr, void *stackaddr, size_t stacksize) -{ - fprintf(stderr, "pthread_attr_setstack called\n"); - ExitProcess(1); - return 0; -} - -int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize) -{ - attr->stack_size = stacksize; - return 0; -} - - -typedef unsigned char boolean; - -/* TLS management internals */ - -static DWORD thread_self_tls_index; - -static void (*tls_destructors[PTHREAD_KEYS_MAX])(void*); -static boolean tls_used[PTHREAD_KEYS_MAX]; -static pthread_key_t tls_max_used_key; -static pthread_mutex_t thread_key_lock = PTHREAD_MUTEX_INITIALIZER; -static void tls_call_destructors(); -static pthread_t tls_impersonate(pthread_t other) { - pthread_t old = pthread_self(); - TlsSetValue(thread_self_tls_index,other); - return old; -} - -/* Thread identity, as much as pthreads are concerned, is determined - by pthread_t structure that is stored in TLS slot - (thread_self_tls_index). This slot is reassigned when fibers are - switched with pthread_np API. - - Two reasons for not using fiber-local storage for this purpose: (1) - Fls is too young: all other things work with Win2000, it requires - WinXP; (2) this implementation works also with threads that aren't - fibers, and it's a good thing. - - There is one more case, besides fiber switching, when pthread_self - identity migrates between system threads: for non-main system - thread that is not [pthread_create]d, thread-specific data - destructors run in a thread from a system thread pool, after the - original thread dies. In order to provide compatibility with - classic pthread TSD, the system pool thread acquires dead thread's - identity for the duration of destructor calls. -*/ -pthread_t pthread_self() -{ - return (pthread_t)TlsGetValue(thread_self_tls_index); -} - -const char * state_to_str(pthread_thread_state state) -{ - switch (state) { - case pthread_state_running: return "running"; - case pthread_state_finished: return "finished"; - case pthread_state_joined: return "joined"; - default: return "unknown"; - } -} - -/* Thread function for [pthread_create]d threads. -*/ -DWORD WINAPI Thread_Function(LPVOID param) -{ - pthread_t self = (pthread_t) param; - - self->teb = NtCurrentTeb(); - - pthread_t prev = tls_impersonate(self); - void* arg = self->arg; - pthread_fn fn = self->start_routine; - - self->retval = fn(arg); - pthread_mutex_lock(&self->lock); - self->state = pthread_state_finished; - pthread_cond_broadcast(&self->cond); - while (!self->detached && self->state != pthread_state_joined) { - pthread_cond_wait(&self->cond, &self->lock); - } - pthread_mutex_unlock(&self->lock); - pthread_mutex_destroy(&self->lock); - pthread_cond_destroy(&self->cond); - tls_call_destructors(); - - CloseHandle(self->handle); - - return 0; -} - -/* Signals */ -struct sigaction signal_handlers[NSIG]; - -/* Never called for now */ -int sigaction(int signum, const struct sigaction* act, struct sigaction* oldact) -{ - struct sigaction newact = *act; - if (oldact) - *oldact = signal_handlers[signum]; - if (!(newact.sa_flags & SA_SIGINFO)) { - newact.sa_sigaction = (typeof(newact.sa_sigaction))newact.sa_handler; - } - signal_handlers[signum] = newact; - return 0; -} - -int pthread_create(pthread_t *thread, const pthread_attr_t *attr, - void *(*start_routine) (void *), void *arg) -{ - pthread_t pth = (pthread_t)calloc(sizeof(pthread_thread),1); - pthread_t self = pthread_self(); - int i; - HANDLE createdThread = NULL; - - - createdThread = CreateThread(NULL, attr ? attr->stack_size : 0, - Thread_Function, pth, CREATE_SUSPENDED, NULL); - if (!createdThread) return 1; - pth->handle = createdThread; - - pth->start_routine = start_routine; - pth->arg = arg; - if (self) { - pth->blocked_signal_set = self->blocked_signal_set; - } else { - sigemptyset(&pth->blocked_signal_set); - } - pth->state = pthread_state_running; - pthread_mutex_init(&pth->lock, NULL); - pthread_cond_init(&pth->cond, NULL); - pth->detached = 0; - if (thread) *thread = pth; - ResumeThread(createdThread); - return 0; -} - -int pthread_equal(pthread_t thread1, pthread_t thread2) -{ - return thread1 == thread2; -} - -int pthread_detach(pthread_t thread) -{ - int retval = 0; - pthread_mutex_lock(&thread->lock); - thread->detached = 1; - pthread_cond_broadcast(&thread->cond); - pthread_mutex_unlock(&thread->lock); - return retval; -} - -int pthread_join(pthread_t thread, void **retval) -{ - pthread_mutex_lock(&thread->lock); - while (thread->state != pthread_state_finished) { - pthread_cond_wait(&thread->cond, &thread->lock); - } - thread->state = pthread_state_joined; - pthread_cond_broadcast(&thread->cond); - if (retval) - *retval = thread->retval; - pthread_mutex_unlock(&thread->lock); - return 0; -} - -/* We manage our own TSD instead of relying on system TLS for anything - other than pthread identity itself. Reasons: (1) Windows NT TLS - slots are expensive, (2) pthread identity migration requires only - one TLS slot assignment, instead of massive copying. */ -int pthread_key_create(pthread_key_t *key, void (*destructor)(void*)) -{ - pthread_key_t index; - boolean success = 0; - pthread_mutex_lock(&thread_key_lock); - for (index = 0; index < PTHREAD_KEYS_MAX; ++index) { - if (!tls_used[index]) { - if (tls_max_used_key<index) - tls_max_used_key = index; - tls_destructors[index] = destructor; - tls_used[index] = 1; - success = 1; - break; - } - } - pthread_mutex_unlock(&thread_key_lock); - - if (success) { - *key = index; - return 0; - } else { - return 1; - } -} - -int pthread_key_delete(pthread_key_t key) -{ - /* tls_used flag is not a machine word. Let's lock, as there is no - atomic guarantee even on x86. */ - pthread_mutex_lock(&thread_key_lock); - tls_destructors[key] = 0; - /* No memory barrier here: application is responsible for proper - call sequence, and having the key around at this point is an - official UB. */ - tls_used[key] = 0; - pthread_mutex_unlock(&thread_key_lock); - return 0; -} - -void __attribute__((sysv_abi)) *pthread_getspecific(pthread_key_t key) -{ - return pthread_self()->specifics[key]; -} - -/* Internal function calling destructors for current pthread */ -static void tls_call_destructors() -{ - pthread_key_t key; - int i; - int called; - - for (i = 0; i<PTHREAD_DESTRUCTOR_ITERATIONS; ++i) { - called = 0; - for (key = 0; key<=tls_max_used_key; ++key) { - void *cell = pthread_getspecific(key); - pthread_setspecific(key,NULL); - if (cell && tls_destructors[key]) { - (tls_destructors[key])(cell); - called = 1; - } - } - if (!called) - break; - } -} - -/* TODO call signal handlers */ -int _sbcl_pthread_sigmask(int how, const sigset_t *set, sigset_t *oldset) -{ - pthread_t self = pthread_self(); - if (oldset) - *oldset = self->blocked_signal_set; - if (set) { - switch (how) { - case SIG_BLOCK: - self->blocked_signal_set |= *set; - break; - case SIG_UNBLOCK: - self->blocked_signal_set &= ~(*set); - break; - case SIG_SETMASK: - self->blocked_signal_set = *set; - break; - } - } - return 0; -} - -pthread_mutex_t mutex_init_lock; - -int pthread_mutex_init(pthread_mutex_t * mutex, const pthread_mutexattr_t * attr) -{ - *mutex = (struct _pthread_mutex_info*)malloc(sizeof(struct _pthread_mutex_info)); - InitializeCriticalSection(&(*mutex)->cs); - (*mutex)->file = " (free) "; - return 0; -} - -int pthread_mutexattr_init(pthread_mutexattr_t* attr) -{ - return 0; -} -int pthread_mutexattr_destroy(pthread_mutexattr_t* attr) -{ - return 0; -} - -int pthread_mutexattr_settype(pthread_mutexattr_t* attr,int mutex_type) -{ - return 0; -} - -int pthread_mutex_destroy(pthread_mutex_t *mutex) -{ - if (*mutex != PTHREAD_MUTEX_INITIALIZER) { - pthread_np_assert_live_mutex(mutex,"destroy"); - DeleteCriticalSection(&(*mutex)->cs); - free(*mutex); - *mutex = &DEAD_MUTEX; - } - return 0; -} - -/* Add pending signal to (other) thread */ -void pthread_np_add_pending_signal(pthread_t thread, int signum) -{ - /* See __sync_fetch_and_or() for gcc 4.4, at least. As some - people are still using gcc 3.x, I prefer to do this in asm. - - For win64 we'll HAVE to rewrite it. __sync_fetch_and_or() seems - to be a rational choice -- there are plenty of GCCisms in SBCL - anyway. - */ - sigset_t to_add = 1<<signum; - asm("lock orl %1,%0":"=m"(thread->pending_signal_set):"r"(to_add)); -} - -static void futex_interrupt(pthread_t thread); - -/* This pthread_kill doesn't do anything to notify target pthread of a - * new pending signal. - * - * DFL: ... or so the original comment claimed, but that was before - * futexes. Now that we wake up futexes, it's not entirely accurate - * anymore, is it? */ -int pthread_kill(pthread_t thread, int signum) -{ - pthread_np_add_pending_signal(thread,signum); - futex_interrupt(thread); - return 0; -} - -void pthread_np_remove_pending_signal(pthread_t thread, int signum) -{ - sigset_t to_and = ~(1<<signum); - asm("lock andl %1,%0":"=m"(thread->pending_signal_set):"r"(to_and)); -} - -sigset_t pthread_np_other_thread_sigpending(pthread_t thread) -{ - return - InterlockedCompareExchange((volatile LONG*)&thread->pending_signal_set, - 0, 0); -} - -/* Mutex implementation uses CRITICAL_SECTIONs. Somethings to keep in - mind: (1) uncontested locking is cheap; (2) long wait on a busy - lock causes exception, so it should never be attempted; (3) those - mutexes are recursive; (4) one thread locks, the other unlocks -> - the next one hangs. */ -int pthread_mutex_lock(pthread_mutex_t *mutex) -{ - pthread_np_assert_live_mutex(mutex,"lock"); - if (*mutex == PTHREAD_MUTEX_INITIALIZER) { - pthread_mutex_lock(&mutex_init_lock); - if (*mutex == PTHREAD_MUTEX_INITIALIZER) { - pthread_mutex_init(mutex, NULL); - } - pthread_mutex_unlock(&mutex_init_lock); - } - EnterCriticalSection(&(*mutex)->cs); - DEBUG_OWN(*mutex); - return 0; -} - -int pthread_mutex_trylock(pthread_mutex_t *mutex) -{ - pthread_np_assert_live_mutex(mutex,"trylock"); - if (*mutex == PTHREAD_MUTEX_INITIALIZER) { - pthread_mutex_lock(&mutex_init_lock); - if (*mutex == PTHREAD_MUTEX_INITIALIZER) { - pthread_mutex_init(mutex, NULL); - } - pthread_mutex_unlock(&mutex_init_lock); - } - if (TryEnterCriticalSection(&(*mutex)->cs)) { - DEBUG_OWN(*mutex); - return 0; - } - else - return EBUSY; -} - -/* Versions of lock/trylock useful for debugging. Our header file - conditionally redefines lock/trylock to call them. */ - -int pthread_mutex_lock_annotate_np(pthread_mutex_t *mutex, const char* file, int line) -{ - int contention = 0; - pthread_np_assert_live_mutex(mutex,"lock"); - if (*mutex == PTHREAD_MUTEX_INITIALIZER) { - pthread_mutex_lock(&mutex_init_lock); - if (*mutex == PTHREAD_MUTEX_INITIALIZER) { - pthread_mutex_init(mutex, NULL); - pthshow("Mutex #x%p: automatic initialization; #x%p %s +%d", - mutex, *mutex, - file, line); - } - pthread_mutex_unlock(&mutex_init_lock); - } - if ((*mutex)->owner) { - pthshow("Mutex #x%p -> #x%p: contention; owned by #x%p, wanted by #x%p", - mutex, *mutex, - (*mutex)->owner, - pthread_self()); - pthshow("Mutex #x%p -> #x%p: contention notes: old %s +%d, new %s +%d", - mutex, *mutex, - (*mutex)->file,(*mutex)->line, file, line); - contention = 1; - } - EnterCriticalSection(&(*mutex)->cs); - if (contention) { - pthshow("Mutex #x%p -> #x%p: contention end; left by #x%p, taken by #x%p", - mutex, *mutex, - (*mutex)->owner, - pthread_self()); - pthshow("Mutex #x%p -> #x%p: contention notes: old %s +%d, new %s +%d", - mutex, *mutex, - (*mutex)->file,(*mutex)->line, file, line); - } - (*mutex)->owner = pthread_self(); - (*mutex)->file = file; - (*mutex)->line = line; - return 0; -} - -int pthread_mutex_trylock_annotate_np(pthread_mutex_t *mutex, const char* file, int line) -{ - int contention = 0; - pthread_np_assert_live_mutex(mutex,"trylock"); - if (*mutex == PTHREAD_MUTEX_INITIALIZER) { - pthread_mutex_lock(&mutex_init_lock); - if (*mutex == PTHREAD_MUTEX_INITIALIZER) { - pthread_mutex_init(mutex, NULL); - } - pthread_mutex_unlock(&mutex_init_lock); - } - if ((*mutex)->owner) { - pthshow("Mutex #x%p -> #x%p: tried contention; owned by #x%p, wanted by #x%p", - mutex, *mutex, - (*mutex)->owner, - pthread_self()); - pthshow("Mutex #x%p -> #x%p: contention notes: old %s +%d, new %s +%d", - mutex, *mutex, - (*mutex)->file,(*mutex)->line, file, line); - contention = 1; - } - if (TryEnterCriticalSection(&(*mutex)->cs)) { - if (contention) { - pthshow("Mutex #x%p -> #x%p: contention end; left by #x%p, taken by #x%p", - mutex, *mutex, - (*mutex)->owner, - pthread_self()); - pthshow("Mutex #x%p -> #x%p: contention notes: old %s +%d, new %s +%d", - mutex, *mutex, - (*mutex)->file,(*mutex)->line, file, line); - } - (*mutex)->owner = pthread_self(); - (*mutex)->file = file; - (*mutex)->line = line; - return 0; - } - else - return EBUSY; -} - -int pthread_mutex_unlock(pthread_mutex_t *mutex) -{ - /* Owner is for debugging only; NB if mutex is used recursively, - owner field will lie. */ - pthread_np_assert_live_mutex(mutex,"unlock"); - DEBUG_RELEASE(*mutex); - LeaveCriticalSection(&(*mutex)->cs); - return 0; -} - -/* Condition variables implemented with events and wakeup queues. */ - -/* Thread-local wakeup events are kept in TSD to avoid kernel object - creation on each call to pthread_cond_[timed]wait */ -static pthread_key_t cv_event_key; - -/* .info field in wakeup record is an "opportunistic" indicator that - wakeup has happened. On timeout from WaitForSingleObject, thread - doesn't know (1) whether to reset event, (2) whether to (try) to - find and unlink wakeup record. Let's let it know (of course, - it will know for sure only under cv_wakeup_lock). */ - -#define WAKEUP_WAITING_NOTIMEOUT 0 -#define WAKEUP_WAITING_TIMEOUT 4 - -#define WAKEUP_HAPPENED 1 -#define WAKEUP_BY_INTERRUPT 2 - -static void* event_create() -{ - return (void*)CreateEvent(NULL,FALSE,FALSE,NULL); -} - -static struct freelist event_freelist = FREELIST_INITIALIZER(event_create); - - -unsigned int pthread_free_event_pool_size() -{ - return event_freelist.count; -} - -static HANDLE fe_get_event() -{ - return (HANDLE)freelist_get(&event_freelist); -} - -static void fe_return_event(HANDLE handle) -{ - freelist_return(&event_freelist, (void*)handle); -} - -static void cv_event_destroy(void* event) -{ - CloseHandle((HANDLE)event); -} - -static HANDLE cv_default_event_get_fn() -{ - HANDLE event = pthread_getspecific(cv_event_key); - if (!event) { - event = CreateEvent(NULL, FALSE, FALSE, NULL); - pthread_setspecific(cv_event_key, event); - } else { - /* ResetEvent(event); used to be here. Let's try without. It's - safe in pthread_cond_wait: if WaitForSingleObjectEx ever - returns, event is reset automatically, and the wakeup queue item - is removed by the signaller under wakeup_lock. - - pthread_cond_timedwait should reset the event if - cv_wakeup_remove failed to find its wakeup record, otherwise - it's safe too. */ - } - return event; -} - -static void cv_default_event_return_fn(HANDLE event) -{ - /* ResetEvent(event); could be here as well (and used to be). - Avoiding syscalls makes sense, however. */ -} - -static pthread_condattr_t cv_default_attr = { - 0, /* alertable */ - fe_get_event, - fe_return_event, - /* cv_default_event_get_fn, /\* get_fn *\/ */ - /* cv_default_event_return_fn /\* return_fn *\/ */ -}; - -int pthread_cond_init(pthread_cond_t * cv, const pthread_condattr_t * attr) -{ - if (!attr) - attr = &cv_default_attr; - pthread_mutex_init(&cv->wakeup_lock, NULL); - cv->first_wakeup = NULL; - cv->last_wakeup = NULL; - cv->alertable = attr->alertable; - cv->get_fn = attr->get_fn; - cv->return_fn = attr->return_fn; - return 0; -} - -int pthread_condattr_init(pthread_condattr_t *attr) -{ - *attr = cv_default_attr; - return 0; -} - -int pthread_condattr_destroy(pthread_condattr_t *attr) -{ - return 0; -} -int pthread_condattr_setevent_np(pthread_condattr_t *attr, - cv_event_get_fn get_fn, cv_event_return_fn ret_fn) -{ - attr->get_fn = get_fn ? get_fn : fe_get_event;// cv_default_event_get_fn; - attr->return_fn = ret_fn ? ret_fn : fe_return_event; // cv_default_event_return_fn; - return 0; -} - -int pthread_cond_destroy(pthread_cond_t *cv) -{ - pthread_mutex_destroy(&cv->wakeup_lock); - return 0; -} - -int pthread_cond_broadcast(pthread_cond_t *cv) -{ - int count = 0; - - HANDLE postponed[128]; - int npostponed = 0,i; - - /* No strict requirements to memory visibility model, because of - mutex unlock around waiting. */ - if (!cv->first_wakeup) - return 0; - pthread_mutex_lock(&cv->wakeup_lock); - while (cv->first_wakeup) - { - struct thread_wakeup * w = cv->first_wakeup; - HANDLE waitevent = w->event; - cv->first_wakeup = w->next; - w->info = WAKEUP_HAPPENED; - postponed[npostponed++] = waitevent; - if (/* w->info == WAKEUP_WAITING_TIMEOUT || */ npostponed == - sizeof(postponed)/sizeof(postponed[0])) { - for (i=0; i<npostponed; ++i) - SetEvent(postponed[i]); - npostponed = 0; - } - ++count; - } - cv->last_wakeup = NULL; - pthread_mutex_unlock(&cv->wakeup_lock); - for (i=0; i<npostponed; ++i) - SetEvent(postponed[i]); - return 0; -} - -int pthread_cond_signal(pthread_cond_t *cv) -{ - struct thread_wakeup * w; - /* No strict requirements to memory visibility model, because of - mutex unlock around waiting. */ - if (!cv->first_wakeup) - return 0; - pthread_mutex_lock(&cv->wakeup_lock); - w = cv->first_wakeup; - if (w) { - HANDLE waitevent = w->event; - cv->first_wakeup = w->next; - if (!cv->first_wakeup) - cv->last_wakeup = NULL; - w->info = WAKEUP_HAPPENED; - SetEvent(waitevent); - } - pthread_mutex_unlock(&cv->wakeup_lock); - return 0; -} - -/* Return value is used for futexes: 0=ok, 1 on unexpected word change. */ -int cv_wakeup_add(struct pthread_cond_t* cv, struct thread_wakeup* w) -{ - HANDLE event; - w->next = NULL; - pthread_mutex_lock(&cv->wakeup_lock); - if (w->uaddr) { - if (w->uval != *w->uaddr) { - pthread_mutex_unlock(&cv->wakeup_lock); - return 1; - } - pthread_self()->futex_wakeup = w; - } - event = cv->get_fn(); - w->event = event; - if (cv->last_wakeup == w) { - fprintf(stderr, "cv->last_wakeup == w\n"); - fflush(stderr); - ExitProcess(0); - } - if (cv->last_wakeup != NULL) - { - cv->last_wakeup->next = w; - cv->last_wakeup = w; - } - else - { - cv->first_wakeup = w; - cv->last_wakeup = w; - } - pthread_mutex_unlock(&cv->wakeup_lock); - return 0; -} - -/* Return true if wakeup found, false if missing */ -int cv_wakeup_remove(struct pthread_cond_t* cv, struct thread_wakeup* w) -{ - int result = 0; - if (w->info == WAKEUP_HAPPENED || w->info == WAKEUP_BY_INTERRUPT) - goto finish; - pthread_mutex_lock(&cv->wakeup_lock); - { - if (w->info == WAKEUP_HAPPENED || w->info == WAKEUP_BY_INTERRUPT) - goto unlock; - if (cv->first_wakeup == w) { - cv->first_wakeup = w->next; - if (cv->last_wakeup == w) - cv->last_wakeup = NULL; - result = 1; - } else { - struct thread_wakeup * prev = cv->first_wakeup; - while (prev && prev->next != w) - prev = prev->next; - if (!prev) { - goto unlock; - } - prev->next = w->next; - if (cv->last_wakeup == w) - cv->last_wakeup = prev; - result = 1; - } - } - unlock: - pthread_mutex_unlock(&cv->wakeup_lock); - finish: - return result; -} - - -int pthread_cond_wait(pthread_cond_t * cv, pthread_mutex_t * cs) -{ - struct thread_wakeup w; - w.uaddr = 0; - w.info = WAKEUP_WAITING_NOTIMEOUT; - cv_wakeup_add(cv, &w); - if (cv->last_wakeup->next == cv->last_wakeup) { - pthread_np_lose(5,"cv->last_wakeup->next == cv->last_wakeup\n"); - } - if (cv->last_wakeup->next != NULL) { - pthread_np_lose(5,"cv->last_wakeup->next == cv->last_wakeup\n"); - } - pthread_self()->waiting_cond = cv; - DEBUG_RELEASE(*cs); - pthread_mutex_unlock(cs); - do { - if (cv->alertable) { - while (WaitForSingleObjectEx(w.event, INFINITE, TRUE) == WAIT_IO_COMPLETION); - } else { - WaitForSingleObject(w.event, INFINITE); - } - } while (w.info == WAKEUP_WAITING_NOTIMEOUT); - pthread_self()->waiting_cond = NULL; - /* Event is signalled once, wakeup is dequeued by signaller. */ - cv->return_fn(w.event); - pthread_mutex_lock(cs); - DEBUG_OWN(*cs); - return 0; -} - -int pthread_cond_timedwait(pthread_cond_t * cv, pthread_mutex_t * cs, - const struct timespec * abstime) -{ - DWORD rv; - struct thread_wakeup w; - pthread_t self = pthread_self(); - - w.info = WAKEUP_WAITING_TIMEOUT; - w.uaddr = 0; - cv_wakeup_add(cv, &w); - if (cv->last_wakeup->next == cv->last_wakeup) { - fprintf(stderr, "cv->last_wakeup->next == cv->last_wakeup\n"); - ExitProcess(0); - } - self->waiting_cond = cv; - DEBUG_RELEASE(*cs); - /* barrier (release); waiting_cond globally visible */ - pthread_mutex_unlock(cs); - { - struct timeval cur_tm; - long sec, msec; - gettimeofday(&cur_tm, NULL); - sec = abstime->tv_sec - cur_tm.tv_sec; - msec = sec * 1000 + abstime->tv_nsec / 1000000 - cur_tm.tv_usec / 1000; - if (msec < 0) - msec = 0; - do { - if (cv->alertable) { - while ((rv = WaitForSingleObjectEx(w.event, msec, TRUE)) - == WAIT_IO_COMPLETION); - } else { - rv = WaitForSingleObject(w.event, msec); - } - } while (rv == WAIT_OBJECT_0 && w.info == WAKEUP_WAITING_TIMEOUT); - } - self->waiting_cond = NULL; - - if (rv == WAIT_TIMEOUT) { - if (!cv_wakeup_remove(cv, &w)) { - /* Someone removed our wakeup record: though we got a timeout, - event was (will be) signalled before we are here. - Consume this wakeup. */ - WaitForSingleObject(w.event, INFINITE); - } - } - cv->return_fn(w.event); - pthread_mutex_lock(cs); - DEBUG_OWN(*cs); - if (rv == WAIT_TIMEOUT) - return ETIMEDOUT; - else - return 0; -} - -int sched_yield() -{ - /* http://stackoverflow.com/questions/1383943/switchtothread-vs-sleep1 - SwitchToThread(); was here. Unsure what's better for us, just trying.. */ - - if(!SwitchToThread()) - Sleep(0); - return 0; -} - -void pthread_lock_structures() -{ - pthread_mutex_lock(&mutex_init_lock); -} - -void pthread_unlock_structures() -{ - pthread_mutex_unlock(&mutex_init_lock); -} - -static int pthread_initialized = 0; - -static pthread_cond_t futex_pseudo_cond; - -void pthreads_win32_init() -{ - if (!pthread_initialized) { - thread_self_tls_index = TlsAlloc(); - pthread_mutex_init(&mutex_init_lock, NULL); - pthread_np_notice_thread(); - pthread_key_create(&cv_event_key,cv_event_destroy); - pthread_cond_init(&futex_pseudo_cond, NULL); - pthread_initialized = 1; - } -} - -static -VOID CALLBACK pthreads_win32_unnotice(void* parameter, BOOLEAN timerOrWait) -{ - pthread_t pth = parameter; - pthread_t self = tls_impersonate(pth); - - tls_call_destructors(); - CloseHandle(pth->handle); - - UnregisterWait(pth->wait_handle); - - tls_impersonate(self); - pthread_mutex_destroy(&pth->lock); - free(pth); -} - -int pthread_np_notice_thread() -{ - if (!pthread_self()) { - pthread_t pth = (pthread_t)calloc(sizeof(pthread_thread),1); - pth->teb = NtCurrentTeb(); - pthread_mutex_init(&pth->lock,NULL); - pth->state = pthread_state_running; - - sigemptyset(&pth->blocked_signal_set); - - DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), - GetCurrentProcess(), &pth->handle, 0, TRUE, - DUPLICATE_SAME_ACCESS); - tls_impersonate(pth); - - if (pthread_initialized) { - RegisterWaitForSingleObject(&pth->wait_handle, - pth->handle, - pthreads_win32_unnotice, - pth, - INFINITE, - WT_EXECUTEONLYONCE); - } - return 1; - } else { - return 0; - } -} - -int sigemptyset(sigset_t *set) -{ - *set = 0; - return 0; -} - -int sigfillset(sigset_t *set) -{ - *set = 0xfffffffful; - return 0; -} - -int sigaddset(sigset_t *set, int signum) -{ - *set |= 1 << signum; - return 0; -} - -int sigdelset(sigset_t *set, int signum) -{ - *set &= ~(1 << signum); - return 0; -} - -int sigismember(const sigset_t *set, int signum) -{ - return (*set & (1 << signum)) != 0; -} -int sigpending(sigset_t *set) -{ - int i; - *set = InterlockedCompareExchange((volatile LONG*)&pthread_self()->pending_signal_set, - 0, 0); - return 0; -} - - -#define FUTEX_EWOULDBLOCK 3 -#define FUTEX_EINTR 2 -#define FUTEX_ETIMEDOUT 1 - -int -futex_wait(volatile intptr_t *lock_word, intptr_t oldval, long sec, unsigned long usec) -{ - struct thread_wakeup w; - pthread_t self = pthread_self(); - DWORD msec = sec<0 ? INFINITE : (sec*1000 + usec/1000); - DWORD wfso; - int result; - sigset_t pendset, blocked; - int maybeINTR; - int info = sec<0 ? WAKEUP_WAITING_NOTIMEOUT: WAKEUP_WAITING_TIMEOUT; - - sigpending(&pendset); - if (pendset & ~self->blocked_signal_set) - return FUTEX_EINTR; - w.uaddr = lock_word; - w.uval = oldval; - w.info = info; - - if (cv_wakeup_add(&futex_pseudo_cond,&w)) { - return FUTEX_EWOULDBLOCK; - } - self->futex_wakeup = &w; - do { - wfso = WaitForSingleObject(w.event, msec); - } while (wfso == WAIT_OBJECT_0 && w.info == info); - self->futex_wakeup = NULL; - sigpending(&pendset); - maybeINTR = (pendset & ~self->blocked_signal_set)? FUTEX_EINTR : 0; - - switch(wfso) { - case WAIT_TIMEOUT: - if (!cv_wakeup_remove(&futex_pseudo_cond,&w)) { - /* timeout, but someone other removed wakeup. */ - result = maybeINTR; - WaitForSingleObject(w.event,INFINITE); - } else { - result = FUTEX_ETIMEDOUT; - } - break; - case WAIT_OBJECT_0: - result = maybeINTR; - break; - default: - result = -1; - break; - } - futex_pseudo_cond.return_fn(w.event); - return result; -} - -int -futex_wake(volatile intptr_t *lock_word, int n) -{ - pthread_cond_t *cv = &futex_pseudo_cond; - int result = 0; - struct thread_wakeup *w, *prev; - HANDLE postponed[128]; - int npostponed = 0,i; - - if (n==0) return 0; - - pthread_mutex_lock(&cv->wakeup_lock); - for (w = cv->first_wakeup, prev = NULL; w && n;) { - if (w->uaddr == lock_word) { - HANDLE event = w->event; - int oldinfo = w->info; - w->info = WAKEUP_HAPPENED; - if (cv->last_wakeup == w) - cv->last_wakeup = prev; - w = w->next; - if (!prev) { - cv->first_wakeup = w; - } else { - prev->next = w; - } - n--; - postponed[npostponed++] = event; - if (npostponed == sizeof(postponed)/sizeof(postponed[0])) { - for (i=0; i<npostponed; ++i) - SetEvent(postponed[i]); - npostponed = 0; - } - } else { - prev=w, w=w->next; - } - } - pthread_mutex_unlock(&cv->wakeup_lock); - for (i=0; i<npostponed; ++i) - SetEvent(postponed[i]); - return 0; -} - - -static void futex_interrupt(pthread_t thread) -{ - if (thread->futex_wakeup) { - pthread_cond_t *cv = &futex_pseudo_cond; - struct thread_wakeup *w; - HANDLE event; - pthread_mutex_lock(&cv->wakeup_lock); - if ((w = thread->futex_wakeup)) { - /* we are taking wakeup_lock recursively - ok with - CRITICAL_SECTIONs */ - if (cv_wakeup_remove(&futex_pseudo_cond,w)) { - event = w->event; - w->info = WAKEUP_BY_INTERRUPT; - thread->futex_wakeup = NULL; - } else { - w = NULL; - } - } - if (w) { - SetEvent(event); - } - pthread_mutex_unlock(&cv->wakeup_lock); - } -} - -void pthread_np_lose(int trace_depth, const char* fmt, ...) -{ - va_list header; - void* frame; - int n = 0; - void** lastseh; - - va_start(header,fmt); - vfprintf(stderr,fmt,header); - for (lastseh = *(void**)NtCurrentTeb(); - lastseh && (lastseh!=(void*)0xFFFFFFFF); - lastseh = *lastseh); - - fprintf(stderr, "Backtrace: %s (pthread %p)\n", header, pthread_self()); - for (frame = __builtin_frame_address(0); frame; frame=*(void**)frame) - { - if ((n++)>trace_depth) - return; - fprintf(stderr, "[#%02d]: ebp = %p, ret = %p\n",n, - frame, ((void**)frame)[1]); - } - ExitProcess(0); -} - -int -sem_init(sem_t *sem, int pshared_not_implemented, unsigned int value) -{ - sem_t semh = CreateSemaphore(NULL, value, SEM_VALUE_MAX, NULL); - if (!semh) - return -1; - *sem = semh; - return 0; -} - -int -sem_post(sem_t *sem) -{ - return !ReleaseSemaphore(*sem, 1, NULL); -} - -static int -sem_wait_timeout(sem_t *sem, DWORD ms) -{ - switch (WaitForSingleObject(*sem, ms)) { - case WAIT_OBJECT_0: - return 0; - case WAIT_TIMEOUT: - /* errno = EAGAIN; */ - return -1; - default: - /* errno = EINVAL; */ - return -1; - } -} - -int -sem_wait(sem_t *sem) -{ - return sem_wait_timeout(sem, INFINITE); -} - -int -sem_trywait(sem_t *sem) -{ - return sem_wait_timeout(sem, 0); -} - -int -sem_destroy(sem_t *sem) -{ - return !CloseHandle(*sem); -} - -#endif diff --git a/src/runtime/pthreads_win32.h b/src/runtime/pthreads_win32.h index 09b24abeb8..28b20860d8 100644 --- a/src/runtime/pthreads_win32.h +++ b/src/runtime/pthreads_win32.h @@ -2,8 +2,6 @@ #define WIN32_PTHREAD_INCLUDED #include <time.h> -#include <errno.h> -#include <sys/types.h> #ifndef _SIGSET_T typedef int sigset_t; @@ -12,17 +10,9 @@ typedef int sigset_t; #define WIN32_LEAN_AND_MEAN #include <windows.h> -#include <stdint.h> /* 0 - Misc */ -#ifndef SIG_IGN -#define SIG_IGN ((void (*)(int, siginfo_t, void*))-1) -#endif -#ifndef SIG_DFL -#define SIG_DFL ((void (*)(int, siginfo_t, void*))-2) -#endif - #define SIGHUP 1 #define SIGINT 2 /* Interactive attention */ #define SIGQUIT 3 @@ -44,110 +34,15 @@ typedef int sigset_t; #define SIGBREAK 21 /* Control-break */ #define SIGABRT 22 /* Abnormal termination (abort) */ -#define SIGRTMIN 23 - #ifndef NSIG #define NSIG 32 /* maximum signal number + 1 */ #endif -/* To avoid overusing system TLS, pthread provides its own */ -#define PTHREAD_KEYS_MAX 128 - -#define PTHREAD_DESTRUCTOR_ITERATIONS 4 - -void pthreads_win32_init(); - /* 1 - Thread */ -typedef struct pthread_thread* pthread_t; - -typedef struct pthread_attr_t { - unsigned int stack_size; -} pthread_attr_t; - -int pthread_attr_init(pthread_attr_t *attr); -int pthread_attr_destroy(pthread_attr_t *attr); -int pthread_attr_setstack(pthread_attr_t *attr, void *stackaddr, size_t stacksize); -int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize); - -typedef void (*pthread_cleanup_fn)(void* arg); - -#define pthread_cleanup_push(fn, arg) { pthread_cleanup_fn __pthread_fn = fn; void *__pthread_arg = arg; -#define pthread_cleanup_pop(execute) if (execute) __pthread_fn(__pthread_arg); } - -int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg); -int pthread_equal(pthread_t thread1, pthread_t thread2); -int pthread_detach(pthread_t thread); -int pthread_join(pthread_t thread, void **retval); -int pthread_kill(pthread_t thread, int signum); - -#ifndef PTHREAD_INTERNALS -pthread_t pthread_self(void) __attribute__((__const__)); -#else -pthread_t pthread_self(void); -#endif - -typedef DWORD pthread_key_t; -int pthread_key_create(pthread_key_t *key, void (*destructor)(void*)); - #define SIG_BLOCK 1 #define SIG_UNBLOCK 2 #define SIG_SETMASK 3 -#ifdef PTHREAD_INTERNALS -int _sbcl_pthread_sigmask(int how, const sigset_t *set, sigset_t *oldset); -#endif - -/* 2 - Mutex */ - -typedef struct _pthread_mutex_info { - char padding[64]; - CRITICAL_SECTION cs; - pthread_t owner; - const char* file; - int line; -} __attribute__((aligned(128))) *pthread_mutex_t; - -typedef int pthread_mutexattr_t; -#define PTHREAD_MUTEX_INITIALIZER ((pthread_mutex_t)-1) -int pthread_mutex_init(pthread_mutex_t * mutex, const pthread_mutexattr_t * attr); -int pthread_mutexattr_init(pthread_mutexattr_t*); -int pthread_mutexattr_destroy(pthread_mutexattr_t*); -int pthread_mutexattr_settype(pthread_mutexattr_t*, int); -#define PTHREAD_MUTEX_ERRORCHECK 0 -int pthread_mutex_destroy(pthread_mutex_t *mutex); -int pthread_mutex_lock(pthread_mutex_t *mutex); -int pthread_mutex_trylock(pthread_mutex_t *mutex); -int pthread_mutex_lock_annotate_np(pthread_mutex_t *mutex, const char* file, int line); -int pthread_mutex_trylock_annotate_np(pthread_mutex_t *mutex, const char* file, int line); -int pthread_mutex_unlock(pthread_mutex_t *mutex); - -/* 3 - Condition variable */ - -typedef struct thread_wakeup { - HANDLE event; - struct thread_wakeup *next; - volatile intptr_t *uaddr; - intptr_t uval; - int info; -} thread_wakeup; - -typedef HANDLE (*cv_event_get_fn)(); -typedef void (*cv_event_return_fn)(HANDLE event); - -typedef struct pthread_cond_t { - pthread_mutex_t wakeup_lock; - struct thread_wakeup *first_wakeup; - struct thread_wakeup *last_wakeup; - unsigned char alertable; - cv_event_get_fn get_fn; - cv_event_return_fn return_fn; -} pthread_cond_t; - -typedef struct pthread_condattr_t { - unsigned char alertable; - cv_event_get_fn get_fn; - cv_event_return_fn return_fn; -} pthread_condattr_t; #ifndef _TIMESPEC_DEFINED typedef struct timespec { @@ -156,191 +51,16 @@ typedef struct timespec { } timespec; #endif -// not implemented: PTHREAD_COND_INITIALIZER -int pthread_condattr_init(pthread_condattr_t *attr); -int pthread_condattr_destroy(pthread_condattr_t *attr); -int pthread_condattr_setevent_np(pthread_condattr_t *attr, - cv_event_get_fn get_fn, cv_event_return_fn ret_fn); -int pthread_cond_destroy(pthread_cond_t *cond); -int pthread_cond_init(pthread_cond_t * cond, const pthread_condattr_t * attr); -int pthread_cond_broadcast(pthread_cond_t *cond); -int pthread_cond_signal(pthread_cond_t *cond); -int pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex, const struct timespec * abstime); -int pthread_cond_wait(pthread_cond_t * cond, pthread_mutex_t * mutex); - -/* some MinGWs seem to include it, others not: */ -#ifndef ETIMEDOUT -# define ETIMEDOUT 123 //Something -#endif - int sched_yield(); -void pthread_lock_structures(); -void pthread_unlock_structures(); - -typedef void *(*pthread_fn)(void*); - -typedef enum { - pthread_state_running, - pthread_state_finished, - pthread_state_joined -} pthread_thread_state; - -typedef struct pthread_thread { - pthread_fn start_routine; - void* arg; - HANDLE handle; - pthread_cond_t *waiting_cond; - void *futex_wakeup; - sigset_t blocked_signal_set; - volatile sigset_t pending_signal_set; - void * retval; - - pthread_mutex_t lock; - pthread_cond_t cond; - int detached; - pthread_thread_state state; - - /* For noticed foreign threads, wait_handle contains a result of - RegisterWaitForSingleObject. */ - HANDLE wait_handle; - - /* Thread TEB base (mostly informative/debugging) */ - void* teb; - - /* Pthread TLS, detached from windows system TLS */ - void *specifics[PTHREAD_KEYS_MAX]; -} pthread_thread; - -static inline int pthread_setspecific(pthread_key_t key, const void *value) -{ - pthread_self()->specifics[key] = (void*)value; - return 0; -} - typedef struct { int bogus; } siginfo_t; -#define SA_SIGINFO (1u<<1) -#define SA_NODEFER (1u<<2) -#define SA_RESTART (1u<<3) -#define SA_ONSTACK (1u<<4) - -struct sigaction { - void (*sa_handler)(int); - void (*sa_sigaction)(int, siginfo_t*, void*); - sigset_t sa_mask; - int sa_flags; -}; -int sigaction(int signum, const struct sigaction* act, struct sigaction* oldact); - -int sigpending(sigset_t *set); - -void pthread_np_add_pending_signal(pthread_t thread, int signum); -void pthread_np_remove_pending_signal(pthread_t thread, int signum); -sigset_t pthread_np_other_thread_sigpending(pthread_t thread); - -int pthread_np_notice_thread(); - int sigemptyset(sigset_t *set); int sigfillset(sigset_t *set); int sigaddset(sigset_t *set, int signum); int sigdelset(sigset_t *set, int signum); int sigismember(const sigset_t *set, int signum); -typedef int sig_atomic_t; - -/* Futexes */ -int futex_wait(volatile intptr_t *lock_word, intptr_t oldval, long sec, unsigned long usec); -int futex_wake(volatile intptr_t *lock_word, int n); - -/* Debugging */ -void pthread_np_lose(int trace_depth, const char* fmt, ...); -struct _pthread_mutex_info DEAD_MUTEX; - -static inline void pthread_np_assert_live_mutex(pthread_mutex_t* ptr, - const char *action) -{ - if (*ptr == &DEAD_MUTEX) { - pthread_np_lose(5,"Trying to %s dead mutex %p\n",action,ptr); - } -} - -typedef HANDLE sem_t; - -#define SEM_VALUE_MAX (int) (~0U >>1) - -int sem_init(sem_t *sem, int pshared_not_implemented, unsigned int value); -int sem_post(sem_t *sem); -int sem_wait(sem_t *sem); -int sem_trywait(sem_t *sem); -int sem_destroy(sem_t *sem); - -#ifndef PTHREAD_INTERNALS -static inline int _sbcl_pthread_sigmask(int how, const sigset_t *set, sigset_t *oldset) -{ - pthread_t self = pthread_self(); - if (oldset) - *oldset = self->blocked_signal_set; - if (set) { - switch (how) { - case SIG_BLOCK: - self->blocked_signal_set |= *set; - break; - case SIG_UNBLOCK: - self->blocked_signal_set &= ~(*set); - break; - case SIG_SETMASK: - self->blocked_signal_set = *set; - break; - } - } - return 0; -} - -/* Make speed-critical TLS access inline. - - We don't check key range or validity here: (1) pthread spec is - explicit about undefined behavior for bogus keys, (2) - setspecific/getspecific should be as fast as possible. */ -#define pthread_getspecific pthread_getspecific_np_inline - -static inline void *pthread_getspecific_np_inline(pthread_key_t key) -{ - return pthread_self()->specifics[key]; -} - -#ifdef PTHREAD_DEBUG_OUTPUT -#define pthread_mutex_lock(mutex) \ - pthread_mutex_lock_annotate_np(mutex, __FILE__, __LINE__ ) -#define pthread_mutex_trylock(mutex) \ - pthread_mutex_trylock_annotate_np(mutex, __FILE__ ,__LINE__) -#else - -/* I'm not after inlinining _everything_, but those two things below are - (1) fast, (2) critical (3) short */ -static inline int pthread_mutex_lock_np_inline(pthread_mutex_t *mutex) -{ - pthread_np_assert_live_mutex(mutex,"lock"); - if ((*mutex) == PTHREAD_MUTEX_INITIALIZER) { - return pthread_mutex_lock(mutex); - } else { - EnterCriticalSection(&(*mutex)->cs); - return 0; - } -} - -static inline int pthread_mutex_unlock_np_inline(pthread_mutex_t *mutex) -{ - pthread_np_assert_live_mutex(mutex,"unlock"); - LeaveCriticalSection(&(*mutex)->cs); - return 0; -} - -#define pthread_mutex_lock pthread_mutex_lock_np_inline -#define pthread_mutex_unlock pthread_mutex_unlock_np_inline - -#endif /* !PTHREAD_DEBUG_OUTPUT */ -#endif /* !PTHREAD_INTERNALS */ #endif /* WIN32_PTHREAD_INCLUDED */ diff --git a/src/runtime/purify.c b/src/runtime/purify.c index 3188e00d9b..4f92457971 100644 --- a/src/runtime/purify.c +++ b/src/runtime/purify.c @@ -38,7 +38,7 @@ #include "genesis/defstruct-description.h" #include "genesis/hash-table.h" #include "code.h" -#include "getallocptr.h" +#include "pseudo-atomic.h" /* We don't ever do purification with GENCGC as of 1.0.5.*. There was * a lot of hairy and fragile ifdeffage in here to support purify on @@ -75,8 +75,7 @@ later { static long later_count = 0; -static boolean -forwarding_pointer_p(lispobj obj) +static boolean forwarded_p(lispobj obj) { lispobj *ptr = native_pointer(obj); @@ -132,6 +131,10 @@ pscav_later(lispobj *where, long count) ++later_count; } +//FILE *xlog; +//#define XLOG(old,new) fprintf(xlog, "%x > %x\n", old, (uword_t)new) +#define XLOG(dumm1,dummy2) + static lispobj ptrans_boxed(lispobj thing, lispobj header, boolean constant) { @@ -139,6 +142,7 @@ ptrans_boxed(lispobj thing, lispobj header, boolean constant) lispobj *old = native_pointer(thing); long nwords = sizetab[header_widetag(header)](old); lispobj *new = newspace_alloc(nwords,constant); + XLOG(thing, new); /* Copy it. */ memcpy(new, old, nwords * sizeof(lispobj)); @@ -160,8 +164,8 @@ static lispobj ptrans_instance(lispobj thing, lispobj header, boolean /* ignored */ constant) { constant = 0; - lispobj info = LAYOUT(instance_layout(native_pointer(thing)))->info; - if (info != NIL) { + lispobj info = LAYOUT(instance_layout(native_pointer(thing)))->_info; + if (instancep(info)) { lispobj pure = ((struct defstruct_description*)native_pointer(info))->pure; if (pure != NIL && pure != T) { gc_abort(); @@ -179,6 +183,7 @@ ptrans_fdefn(lispobj thing, lispobj header) lispobj *old = native_pointer(thing); long nwords = sizetab[header_widetag(header)](old); lispobj *new = newspace_alloc(nwords, 0); /* inconstant */ + XLOG(thing, new); /* Copy it. */ memcpy(new, old, nwords * sizeof(lispobj)); @@ -204,6 +209,7 @@ ptrans_unboxed(lispobj thing, lispobj header) lispobj *old = native_pointer(thing); long nwords = sizetab[header_widetag(header)](old); lispobj *new = newspace_alloc(nwords, 1); /* always constant */ + XLOG(thing, new); /* copy it. */ memcpy(new, old, nwords * sizeof(lispobj)); @@ -222,6 +228,7 @@ ptrans_vector(lispobj thing, boolean boxed, boolean constant) long nwords = sizetab[header_widetag(vector->header)]((lispobj*)vector); lispobj *new = newspace_alloc(nwords, (constant || !boxed)); + XLOG(thing, new); memcpy(new, vector, nwords * sizeof(lispobj)); lispobj result = make_lispobj(new, lowtag_of(thing)); @@ -240,6 +247,7 @@ ptrans_code(lispobj thing) long nwords = code_total_nwords(code); struct code *new = (struct code *)newspace_alloc(nwords,1); /* constant */ + XLOG(thing, new); memcpy(new, code, nwords * sizeof(lispobj)); @@ -259,7 +267,7 @@ ptrans_code(lispobj thing) #endif /* Put in forwarding pointers for all the functions. */ for_each_simple_fun(i, newfunc, new, 1, { - lispobj* old = (lispobj*)LOW_WORD((char*)newfunc - displacement); + lispobj* old = (lispobj*)((char*)newfunc - displacement); *old = make_lispobj(newfunc, FUN_POINTER_LOWTAG); pscav(&newfunc->self, 1, 1); // and fix the self-pointer now }); @@ -314,6 +322,7 @@ ptrans_func(lispobj thing, lispobj header) lispobj *new = newspace_alloc (nwords,(header_widetag(header)!=FUNCALLABLE_INSTANCE_WIDETAG)); + XLOG(thing, new); /* Copy it. */ memcpy(new, old, nwords * sizeof(lispobj)); @@ -337,7 +346,7 @@ ptrans_returnpc(lispobj thing, lispobj header) /* Make sure it's been transported. */ lispobj new = *native_pointer(code); - if (!forwarding_pointer_p(new)) + if (!forwarded_p(new)) new = ptrans_code(code); /* Maintain the offset: */ @@ -353,6 +362,7 @@ ptrans_list(lispobj thing, boolean constant) long length; orig = (struct cons *) newspace_alloc(0,constant); + //fprintf(xlog, "%x > %x", thing, (uword_t)orig); length = 0; do { @@ -371,9 +381,10 @@ ptrans_list(lispobj thing, boolean constant) length++; } while (listp(thing) && dynamic_pointer_p(thing) && - !(forwarding_pointer_p(*native_pointer(thing)))); + !(forwarded_p(*native_pointer(thing)))); /* Scavenge the list we just copied. */ + //fprintf(xlog, "*%d\n", (int)length); pscav((lispobj *)orig, length * WORDS_PER_CONS, constant); return make_lispobj(orig, LIST_POINTER_LOWTAG); @@ -410,7 +421,6 @@ ptrans_otherptr(lispobj thing, lispobj header, boolean constant) case COMPLEX_CHARACTER_STRING_WIDETAG: #endif case COMPLEX_BIT_VECTOR_WIDETAG: - case COMPLEX_VECTOR_NIL_WIDETAG: case COMPLEX_VECTOR_WIDETAG: case COMPLEX_ARRAY_WIDETAG: return ptrans_boxed(thing, header, constant); @@ -473,7 +483,7 @@ pscav(lispobj *addr, long nwords, boolean constant) /* Maybe. Have we already moved it? */ thingp = native_pointer(thing); header = *thingp; - if (is_lisp_pointer(header) && forwarding_pointer_p(header)) + if (is_lisp_pointer(header) && forwarded_p(header)) /* Yep, so just copy the forwarding pointer. */ thing = header; else { @@ -529,7 +539,7 @@ pscav(lispobj *addr, long nwords, boolean constant) // [1] : vector length // [2] : element[0] = high-water mark // [3] : element[1] = rehash bit - if (is_vector_subtype(thing, VectorAddrHashing)) + if (vector_flagp(thing, VectorAddrHashing)) addr[3] = make_fixnum(1); // just flag it for rehash count = 2; break; @@ -549,7 +559,7 @@ pscav(lispobj *addr, long nwords, boolean constant) /* Weak pointers get preserved during purify, 'cause I * don't feel like figuring out how to break them. */ pscav(addr+1, 2, constant); - count = WEAK_POINTER_NWORDS; + count = ALIGN_UP(WEAK_POINTER_SIZE,2); break; case FDEFN_WIDETAG: @@ -560,23 +570,22 @@ pscav(lispobj *addr, long nwords, boolean constant) case INSTANCE_WIDETAG: { - lispobj lbitmap = LAYOUT(instance_layout(addr))->bitmap; - lispobj* slots = addr + 1; - long nslots = instance_length(*addr) | 1; - int index; - if (fixnump(lbitmap)) { - sword_t bitmap = fixnum_value(lbitmap); - for (index = 0; index < nslots ; index++, bitmap >>= 1) - if (bitmap & 1) - pscav(slots + index, 1, constant); - } else { - struct bignum * bitmap; - bitmap = (struct bignum*)native_pointer(lbitmap); - for (index = 0; index < nslots ; index++) - if (positive_bignum_logbitp(index, bitmap)) - pscav(slots + index, 1, constant); - } - count = 1 + nslots; + lispobj layout = instance_layout(addr); + lispobj layout_header = *native_pointer(layout); + if (is_lisp_pointer(layout_header)) { + gc_assert(forwarded_p(layout_header)); + layout = layout_header; + } + if (!layoutp(layout)) lose("Bad layout in instance: %p %x", addr, layout); + struct bitmap bitmap = get_layout_bitmap(LAYOUT(layout)); + gc_assert(bitmap.nwords >= 1); + long nslots = instance_length(*addr); + int index; + for (index = 0; index < nslots ; index++) + // logically treat index 0 (layout) as a tagged slot + if (index == 0 || bitmap_logbitp(index, bitmap)) + pscav((addr+1) + index, 1, constant); + count = 1 + (nslots | 1); } break; @@ -601,25 +610,7 @@ pscav(lispobj *addr, long nwords, boolean constant) return addr; } -static void -verify_range(lispobj *base, lispobj *end) -{ - lispobj* where = base; - while (where < end) { - if (widetag_of(where) == CODE_HEADER_WIDETAG) { - int n_boxed_words = code_header_words((struct code*)where); - int i; - for (i = 0; i < n_boxed_words; ++i) { - lispobj word = where[i]; - if (is_lisp_pointer(word) && dynamic_pointer_p(word)) - lose("purify failed, obj=%p, where=%p, val=%"OBJ_FMTX, - where, where+i, word); - } - } - where += OBJECT_SIZE(*where, where); - } -} - +extern void dump_space_to_file(lispobj* where, lispobj* limit, char* pathname); int purify(lispobj static_roots, lispobj read_only_roots) { @@ -634,6 +625,7 @@ purify(lispobj static_roots, lispobj read_only_roots) fflush(stderr); return 0; } + // verify_heap(0); fprintf(stderr, "pre-verify passed\n"); #ifdef PRINTNOISE printf("[doing purification:"); @@ -667,9 +659,8 @@ purify(lispobj static_roots, lispobj read_only_roots) printf(" handlers"); fflush(stdout); #endif - pscav((lispobj *) interrupt_handlers, - sizeof(interrupt_handlers) / sizeof(lispobj), - 0); + pscav(lisp_sig_handlers, NSIG, 0); + pscav(&lisp_package_vector, 1, 0); #ifdef PRINTNOISE printf(" stack"); @@ -690,25 +681,6 @@ purify(lispobj static_roots, lispobj read_only_roots) all_threads->binding_stack_start, 0); - /* The original CMU CL code had scavenge-read-only-space code - * controlled by the Lisp-level variable - * *SCAVENGE-READ-ONLY-SPACE*. It was disabled by default, and it - * wasn't documented under what circumstances it was useful or - * safe to turn it on, so it's been turned off in SBCL. If you - * want/need this functionality, and can test and document it, - * please submit a patch. */ -#if 0 - if (SymbolValue(SCAVENGE_READ_ONLY_SPACE) != UNBOUND_MARKER_WIDETAG - && SymbolValue(SCAVENGE_READ_ONLY_SPACE) != NIL) { - unsigned read_only_space_size = - read_only_space_free_pointer - (lispobj *)READ_ONLY_SPACE_START; - fprintf(stderr, - "scavenging read only space: %d bytes\n", - read_only_space_size * sizeof(lispobj)); - pscav( (lispobj *)READ_ONLY_SPACE_START, read_only_space_size, 0); - } -#endif - #ifdef PRINTNOISE printf(" static"); fflush(stdout); @@ -735,9 +707,6 @@ purify(lispobj static_roots, lispobj read_only_roots) printf(" cleanup"); fflush(stdout); #endif -#ifdef LISP_FEATURE_HPUX - clear_auto_gc_trigger(); /* restore mmap as it was given by os */ -#endif os_zero((os_vm_address_t) current_dynamic_space, dynamic_space_size); @@ -760,10 +729,11 @@ purify(lispobj static_roots, lispobj read_only_roots) os_flush_icache((os_vm_address_t)STATIC_SPACE_START, STATIC_SPACE_SIZE); #ifdef PRINTNOISE - verify_range((lispobj*)READ_ONLY_SPACE_START, read_only_space_free_pointer); + // verify_heap(1); printf(" done]\n"); fflush(stdout); #endif + //fclose(xlog); return 0; } #else /* LISP_FEATURE_GENCGC */ diff --git a/src/runtime/queue.h b/src/runtime/queue.h index 92320bc3d0..3734a27e36 100644 --- a/src/runtime/queue.h +++ b/src/runtime/queue.h @@ -19,7 +19,7 @@ struct Qblock { }; #if 1 -#define QBLOCK_BYTES GENCGC_CARD_BYTES +#define QBLOCK_BYTES GENCGC_PAGE_BYTES // 1+ because struct QBlock has space for a single element within it #define QBLOCK_CAPACITY (1+(QBLOCK_BYTES-sizeof(struct Qblock))/sizeof(lispobj)) #else diff --git a/src/runtime/riscv-arch.c b/src/runtime/riscv-arch.c index f7bd5755f6..b649f027ef 100644 --- a/src/runtime/riscv-arch.c +++ b/src/runtime/riscv-arch.c @@ -22,7 +22,7 @@ #include "interrupt.h" #include "interr.h" #include "breakpoint.h" -#include "getallocptr.h" +#include "pseudo-atomic.h" os_vm_address_t arch_get_bad_addr(int signam, siginfo_t *siginfo, os_context_t *context) @@ -34,17 +34,12 @@ void arch_skip_instruction(os_context_t *context) { /* KLUDGE: Other platforms check for trap codes and skip inlined * trap/error parameters. We should too. */ - - /* Note that we're doing integer arithmetic here, not pointer. So - * the value that the return value of os_context_pc_addr() points - * to will be incremented by 4, not 16. - */ - *os_context_pc_addr(context) += 4; + OS_CONTEXT_PC(context) += 4; } unsigned char *arch_internal_error_arguments(os_context_t *context) { - return (unsigned char*)(*os_context_pc_addr(context) + 5); + return (unsigned char*)(OS_CONTEXT_PC(context) + 5); } boolean arch_pseudo_atomic_atomic(os_context_t *context) @@ -60,7 +55,7 @@ boolean arch_pseudo_atomic_atomic(os_context_t *context) * to arch_pseudo_atomic_atomic, but this seems clearer. * --NS 2007-05-15 */ #ifdef LISP_FEATURE_GENCGC - return get_pseudo_atomic_atomic(arch_os_get_current_thread()); + return get_pseudo_atomic_atomic(get_sb_vm_thread()); #else return (!foreign_function_call_active) && (NIL != SymbolValue(PSEUDO_ATOMIC_ATOMIC,0)); @@ -69,12 +64,12 @@ boolean arch_pseudo_atomic_atomic(os_context_t *context) void arch_set_pseudo_atomic_interrupted(os_context_t *context) { - set_pseudo_atomic_interrupted(arch_os_get_current_thread()); + set_pseudo_atomic_interrupted(get_sb_vm_thread()); } void arch_clear_pseudo_atomic_interrupted(os_context_t *context) { - clear_pseudo_atomic_interrupted(arch_os_get_current_thread()); + clear_pseudo_atomic_interrupted(get_sb_vm_thread()); } unsigned int arch_install_breakpoint(void *pc) @@ -102,14 +97,14 @@ arch_handle_breakpoint(os_context_t *context) void arch_handle_fun_end_breakpoint(os_context_t *context) { - *os_context_pc_addr(context) = (long) handle_fun_end_breakpoint(context); + OS_CONTEXT_PC(context) = (long) handle_fun_end_breakpoint(context); } void arch_handle_single_step_trap(os_context_t *context, int trap) { unsigned char register_offset = - *((unsigned char *)(*os_context_pc_addr(context)) + 5); + *((unsigned char *)(OS_CONTEXT_PC(context)) + 5); handle_single_step_trap(context, trap, register_offset); /* KLUDGE: arch_skip_instruction() only skips one instruction, and * there is a following word to deal with as well, so skip @@ -118,17 +113,33 @@ arch_handle_single_step_trap(os_context_t *context, int trap) arch_skip_instruction(context); } -void +int riscv_user_emulation; + +static void sigtrap_handler(int signal, siginfo_t *info, os_context_t *context) { - u32 trap_instruction = *((u32 *)*os_context_pc_addr(context)); + uint32_t trap_instruction = *(uint32_t *)OS_CONTEXT_PC(context); + + static int sigaction_workaround; + if (riscv_user_emulation && !sigaction_workaround) { + sigset_t curmask; + thread_sigmask(SIG_BLOCK, 0, &curmask); + if (*(unsigned long int*)&curmask == 0) { + char msg[] = "WARNING: broken sigaction() workaround enabled\n"; + write(2, msg, sizeof msg-1); + sigaction_workaround = 1; + } else { + sigaction_workaround = -1; + } + } + if (sigaction_workaround == 1) thread_sigmask(SIG_BLOCK, &blockable_sigset, 0); if (trap_instruction != 0x100073) { lose("Unrecognized trap instruction %08x in sigtrap_handler()", trap_instruction); } - u32 code = *((u32 *)(4 + *os_context_pc_addr(context))); + uint32_t code = *((uint32_t *)(4 + OS_CONTEXT_PC(context))); if (code == trap_PendingInterrupt) { arch_skip_instruction(context); @@ -140,19 +151,76 @@ sigtrap_handler(int signal, siginfo_t *info, os_context_t *context) void arch_install_interrupt_handlers(void) { - undoably_install_low_level_interrupt_handler(SIGTRAP, sigtrap_handler); + ll_install_handler(SIGTRAP, sigtrap_handler); } -/* Linkage table */ +/* Linkage tables + * + * Linkage entry size is 8 or 20, because we need 2 instructions for the 32-bit case and we need 3 instructions and an 8 byte address in the 64-bit case. + */ + +#define LINKAGE_TEMP_REG reg_NL3 + void arch_write_linkage_table_entry(int index, void *target_addr, int datap) { // allocate successive entries downward char *reloc_addr = - (char*)LINKAGE_TABLE_SPACE_END - (index + 1) * LINKAGE_TABLE_ENTRY_SIZE; - *(uword_t*)reloc_addr = (uword_t)target_addr; + (char*)ALIEN_LINKAGE_TABLE_SPACE_END - (index + 1) * ALIEN_LINKAGE_TABLE_ENTRY_SIZE; + if (datap) { + *(unsigned long *)reloc_addr = (unsigned long)target_addr; + return; + } + int* inst_ptr; + unsigned inst; + + inst_ptr = (int*) reloc_addr; + +#ifndef LISP_FEATURE_64_BIT + /* + lui reg, %hi(address) + jr reg, %lo(address) + */ + unsigned int addr = (unsigned int)target_addr; + unsigned int hi = ((addr + 0x800) >> 12); + int lo = addr - (hi << 12); + + inst = 0x37 | LINKAGE_TEMP_REG << 7 | hi << 12; + *inst_ptr++ = inst; + + inst = 0x67 | LINKAGE_TEMP_REG << 15 | lo << 20; + *inst_ptr++ = inst; +#else + /* + auipc reg, 0 + load reg, 12(reg) + jr reg + address + */ + + inst = 0x17 | LINKAGE_TEMP_REG << 7; + *inst_ptr++ = inst; + + inst = 0x3 | LINKAGE_TEMP_REG << 7 | WORD_SHIFT << 12 | LINKAGE_TEMP_REG << 15 | 12 << 20; + *inst_ptr++ = inst; + + inst = 0x67 | LINKAGE_TEMP_REG << 15; + *inst_ptr++ = inst; + + *(unsigned long *)inst_ptr++ = (unsigned long)target_addr; +#endif + + os_flush_icache((os_vm_address_t) reloc_addr, (char*) inst_ptr - reloc_addr); +} + +void +*arch_read_linkage_table_entry(int index, int datap) +{ + char *reloc_addr = + (char*)ALIEN_LINKAGE_TABLE_SPACE_END - (index + 1) * ALIEN_LINKAGE_TABLE_ENTRY_SIZE; + return *(uword_t *)reloc_addr; } lispobj call_into_lisp(lispobj fun, lispobj *args, int nargs) { return ((lispobj(*)(lispobj, lispobj *, int, struct thread*))SYMBOL(CALL_INTO_LISP)->value) - (fun, args, nargs, arch_os_get_current_thread()); + (fun, args, nargs, get_sb_vm_thread()); } diff --git a/src/runtime/riscv-arch.h b/src/runtime/riscv-arch.h index b7fabc392f..bc508937f2 100644 --- a/src/runtime/riscv-arch.h +++ b/src/runtime/riscv-arch.h @@ -1,6 +1,4 @@ #ifndef _RISCV_ARCH_H #define _RISCV_ARCH_H -#define ALIEN_STACK_GROWS_DOWNWARD - #endif /* _RISCV_ARCH_H */ diff --git a/src/runtime/riscv-linux-os.c b/src/runtime/riscv-linux-os.c index 6dee254067..3c625ee729 100644 --- a/src/runtime/riscv-linux-os.c +++ b/src/runtime/riscv-linux-os.c @@ -26,8 +26,6 @@ #include "interrupt.h" #include "interr.h" #include "lispregs.h" -#include <sys/socket.h> -#include <sys/utsname.h> #include <sys/types.h> #include <signal.h> @@ -41,9 +39,6 @@ int arch_os_thread_init(struct thread *thread) { -#ifdef LISP_FEATURE_SB_THREAD - pthread_setspecific(specials,thread); -#endif return 1; /* success */ } @@ -59,12 +54,6 @@ os_context_register_addr(os_context_t *context, int offset) return (os_context_register_t*)&(context->uc_mcontext.__gregs[offset]); } -os_context_register_t * -os_context_pc_addr(os_context_t *context) -{ - return os_context_register_addr(context, 0); -} - os_context_register_t * os_context_lr_addr(os_context_t *context) { diff --git a/src/runtime/riscv-linux-os.h b/src/runtime/riscv-linux-os.h index f215569126..3c13ddb635 100644 --- a/src/runtime/riscv-linux-os.h +++ b/src/runtime/riscv-linux-os.h @@ -6,4 +6,6 @@ typedef long os_context_register_t; #include "arch-os-generic.inc" +#define OS_CONTEXT_PC(context) context->uc_mcontext.__gregs[0] + #endif /* _RISCV_LINUX_OS_H */ diff --git a/src/runtime/riscv-lispregs.h b/src/runtime/riscv-lispregs.h index 04886270d8..081e9eebdd 100644 --- a/src/runtime/riscv-lispregs.h +++ b/src/runtime/riscv-lispregs.h @@ -18,11 +18,11 @@ #define NREGS (32) #define reg_ZERO REG(0) -#define reg_LIP REG(1) +#define reg_RA REG(1) #define reg_NSP REG(2) #define reg_GLOBAL REG(3) #define reg_TP REG(4) -#define reg_LRA REG(5) +#define reg_LIP REG(5) #define reg_CFP REG(6) #define reg_OCFP REG(7) #define reg_NFP REG(8) diff --git a/src/runtime/run-program.c b/src/runtime/run-program.c index 9be922cd10..ee74273b74 100644 --- a/src/runtime/run-program.c +++ b/src/runtime/run-program.c @@ -1,5 +1,5 @@ /* - * support for the Lisp function RUN-PROGRAM and friends + * Unix support for the Lisp function RUN-PROGRAM and friends */ /* @@ -13,10 +13,12 @@ * files for more information. */ -#include "sbcl.h" - -#ifndef LISP_FEATURE_WIN32 +#ifdef __linux__ +/* glibc won't give us close_range without this */ +#define _GNU_SOURCE +#endif +#include "sbcl.h" #include <stdlib.h> #include <sys/file.h> #include <sys/types.h> @@ -29,6 +31,9 @@ #include <sys/ioctl.h> #include <termios.h> #include <errno.h> +#include <dirent.h> +#include <sys/syscall.h> +#include "interr.h" // for lose() #ifdef LISP_FEATURE_OPENBSD #include <util.h> @@ -78,7 +83,7 @@ set_pty(char *pty_name) { int fd; -#if !defined(LISP_FEATURE_HPUX) && !defined(SVR4) && !defined(__HAIKU__) +#if !defined(SVR4) && !defined(__HAIKU__) fd = open("/dev/tty", O_RDWR, 0); if (fd >= 0) { ioctl(fd, TIOCNOTTY, 0); @@ -97,6 +102,98 @@ set_pty(char *pty_name) #endif /* !LISP_FEATURE_OPENBSD */ +int closefrom_fddir(char *dir, int lowfd) +{ + DIR *d; + struct dirent *ent; + int fd; + + /* This may fail if e.g. the program is running in + * a chroot that does not include /proc, or potentially + * on old kernel versions. */ + d = opendir(dir); + if (!d) return -1; + + for (ent = readdir(d); ent; ent = readdir(d)) { + /* atoi will return bogus values for certain inputs, but lowfd will + * prevent us from closing anything we care about. */ + fd = atoi(ent->d_name); + if (fd >= 0 && fd >= lowfd) + close(fd); + } + closedir(d); + return 0; +} + +void closefds_range(unsigned int first, unsigned int last) +{ + int fds_closed = 0; + // Try using close_range syscall first. +#if defined(LISP_FEATURE_OS_PROVIDES_CLOSE_RANGE_WRAPPER) + // Prefer the libc wrapper, if it exists at build time. + fds_closed = !close_range(first, last, 0); +#elif defined(LISP_FEATURE_LINUX) && defined(__NR_close_range) + // Use syscall(2) if we could detect the syscall number at build time. + fds_closed = !syscall(__NR_close_range, first, last, 0); +#endif + // Otherwise (if the syscall information isn't availble at build time or if + // the run time kernel doesn't support the syscall), fall back to close() + // in a for loop. + if (!fds_closed) + { + unsigned int close_fd; + if (last == ~0U) + { +#ifdef SVR4 + last = sysconf(_SC_OPEN_MAX)-1; +#else + last = getdtablesize()-1; +#endif + } + for (close_fd = first; close_fd <= last; close_fd++) + { + close(close_fd); + } + } +} + +void closefds_from(int lowfd, int* dont_close) +{ + if (dont_close) { + /* dont_close is a sorted simple-array of tagged ints */ + uword_t length = fixnum_value(((uword_t*)dont_close)[-1]); + uword_t i; + for (i = 0; i < length; i++) + { + int fd = dont_close[i]; + closefds_range(lowfd, fd - 1); + lowfd = fd+1; + } + } + +#if defined(LISP_FEATURE_OPENBSD) || defined(LISP_FEATURE_NETBSD) \ + || defined(LISP_FEATURE_DRAGONFLY) || defined(LISP_FEATURE_FREEBSD) \ + || defined(LISP_FEATURE_SUNOS) + closefrom(lowfd); +#else + int fds_closed = 0; + +/* readdir() uses malloc, which is prone to deadlocking +#ifdef LISP_FEATURE_LINUX + if (!fds_closed) + fds_closed = !closefrom_fddir("/proc/self/fd/", lowfd); +#endif +#ifdef LISP_FEATURE_DARWIN + if (!fds_closed) + fds_closed = !closefrom_fddir("/dev/fd/", lowfd); +#endif +*/ + + if (!fds_closed) + closefds_range(lowfd, ~0U); +#endif +} + int wait_for_exec(int pid, int channel[2]) { if ((-1 != pid) && (-1 != channel[1])) { int child_errno = 0; @@ -138,22 +235,12 @@ extern char **environ; int spawn(char *program, char *argv[], int sin, int sout, int serr, int search, char *envp[], char *pty_name, int channel[2], - char *pwd) + char *pwd, int* dont_close) { pid_t pid; - int fd; sigset_t sset; int failure_code = 2; - channel[0] = -1; - channel[1] = -1; - if (!pipe(channel)) { - if (-1==fcntl(channel[1], F_SETFD, FD_CLOEXEC)) { - close(channel[1]); - channel[1] = -1; - } - } - pid = fork(); if (pid) { return pid; @@ -164,7 +251,7 @@ int spawn(char *program, char *argv[], int sin, int sout, int serr, * share stdin with our parent. In the latter case we claim * control of the terminal. */ if (sin >= 0) { -#if defined(LISP_FEATURE_HPUX) || defined(LISP_FEATURE_OPENBSD) +#ifdef LISP_FEATURE_OPENBSD setsid(); #elif defined(LISP_FEATURE_DARWIN) setpgid(0, getpid()); @@ -193,14 +280,17 @@ int spawn(char *program, char *argv[], int sin, int sout, int serr, if (serr >= 0) dup2(serr, 2); } - /* Close all other fds. */ -#ifdef SVR4 - for (fd = sysconf(_SC_OPEN_MAX)-1; fd >= 3; fd--) - if (fd != channel[1]) close(fd); -#else - for (fd = getdtablesize()-1; fd >= 3; fd--) - if (fd != channel[1]) close(fd); -#endif + /* Close all other fds. First arrange for the pipe fd to be the + * lowest free fd, then close every open fd above that. */ + channel[1] = dup2(channel[1], 3); + closefds_from(4, dont_close); + + if (-1 != channel[1]) { + if (-1==fcntl(channel[1], F_SETFD, FD_CLOEXEC)) { + close(channel[1]); + channel[1] = -1; + } + } if (pwd && chdir(pwd) < 0) { failure_code = 3; @@ -238,105 +328,4 @@ int spawn(char *program, char *argv[], int sin, int sout, int serr, } _exit(failure_code); } -#else /* !LISP_FEATURE_WIN32 */ - -# include <windows.h> -# include <process.h> -# include <stdio.h> -# include <stdlib.h> -# include <fcntl.h> -# include <io.h> - -#define READ_HANDLE 0 -#define WRITE_HANDLE 1 - -/* These functions do not attempt to deal with wchar_t variations. */ - -/* Get the value of _environ maintained by MSVCRT */ -char **msvcrt_environ ( void ) { - return ( _environ ); -} - -/* Set up in, out, err pipes and spawn a program, waiting or otherwise. */ -HANDLE spawn ( - const char *program, - const char *const *argv, - int in, - int out, - int err, - int search, - char *envp, - char *ptyname, - int wait, - char *pwd - ) -{ - int stdout_backup, stdin_backup, stderr_backup, wait_mode; - HANDLE hProcess; - HANDLE hReturn; - - /* Duplicate and save the original stdin/out/err handles. */ - stdout_backup = _dup ( _fileno ( stdout ) ); - stdin_backup = _dup ( _fileno ( stdin ) ); - stderr_backup = _dup ( _fileno ( stderr ) ); - - /* If we are not using stdin/out/err - * then duplicate the new pipes to current stdin/out/err handles. - * - * Default std fds are used if in, out or err parameters - * are -1. */ - - hReturn = (HANDLE)-1; - hProcess = (HANDLE)-1; - if ( ( out >= 0 ) && ( out != _fileno ( stdout ) ) ) { - if ( _dup2 ( out, _fileno ( stdout ) ) != 0 ) goto error_exit; - } - if ( ( in >= 0 ) && ( in != _fileno ( stdin ) ) ) { - if ( _dup2 ( in, _fileno ( stdin ) ) != 0 ) goto error_exit_out; - } - if ( ( err >= 0 ) && ( err != _fileno ( stderr ) ) ) { - if ( _dup2 ( err, _fileno ( stderr ) ) != 0 ) goto error_exit_in; - } - - /* Set the wait mode. */ - if ( 0 == wait ) { - wait_mode = P_NOWAIT; - } else { - wait_mode = P_WAIT; - } - - /* Change working directory if supplied. */ - if (pwd) { - if (chdir(pwd) < 0) { - goto error_exit; - } - } - - /* Spawn process given on the command line*/ - if (search) - hProcess = (HANDLE) spawnvp ( wait_mode, program, (char* const* )argv ); - else - hProcess = (HANDLE) spawnv ( wait_mode, program, (char* const* )argv ); - - /* Now that the process is launched, replace the original - * in/out/err handles and close the backups. */ - - if ( _dup2 ( stderr_backup, _fileno ( stderr ) ) != 0 ) goto error_exit; - error_exit_in: - if ( _dup2 ( stdin_backup, _fileno ( stdin ) ) != 0 ) goto error_exit; - error_exit_out: - if ( _dup2 ( stdout_backup, _fileno ( stdout ) ) != 0 ) goto error_exit; - - hReturn = hProcess; - - error_exit: - close ( stdout_backup ); - close ( stdin_backup ); - close ( stderr_backup ); - - return hReturn; - -} - -#endif /* !LISP_FEATURE_WIN32 */ diff --git a/src/runtime/runtime.c b/src/runtime/runtime.c index 0aa450d903..8c6619d9fb 100644 --- a/src/runtime/runtime.c +++ b/src/runtime/runtime.c @@ -33,16 +33,16 @@ #include "runtime.h" #ifndef LISP_FEATURE_WIN32 #include <sched.h> +#else +#include <shellapi.h> #endif #include <errno.h> #include <locale.h> #include <limits.h> -#if defined(SVR4) || defined(__linux__) #include <time.h> -#endif -#if !(defined(LISP_FEATURE_WIN32) && defined(LISP_FEATURE_SB_THREAD)) +#ifndef LISP_FEATURE_WIN32 #include "signal.h" #endif @@ -64,59 +64,17 @@ #include "genesis/static-symbols.h" #include "genesis/symbol.h" +struct timespec lisp_init_time; + static char libpath[] = "../lib/sbcl"; char *sbcl_runtime_home; char *sbcl_runtime; -#ifdef LISP_FEATURE_HPUX -extern void *return_from_lisp_stub; -#include "genesis/closure.h" -#include "genesis/simple-fun.h" -#endif - - -/* SIGINT handler that invokes the monitor (for when Lisp isn't up to it) */ -static void -sigint_handler(int __attribute__((unused)) signal, - siginfo_t __attribute__((unused)) *info, - os_context_t *context) -{ - lose("\nSIGINT hit at 0x%08lX", - (unsigned long) *os_context_pc_addr(context)); -} - -/* (This is not static, because we want to be able to call it from - * Lisp land.) */ -void -sigint_init(void) -{ - SHOW("entering sigint_init()"); - install_handler(SIGINT, sigint_handler, 0, 1); - SHOW("leaving sigint_init()"); -} /* * helper functions for dealing with command line args */ -void * -successful_malloc(size_t size) -{ - void* result = malloc(size); - if (0 == result) { - lose("malloc failure"); - } else { - return result; - } - return (void *) NULL; /* dummy value: return something ... */ -} - -char * -copied_string(char *string) -{ - return strcpy(successful_malloc(1+strlen(string)), string); -} - static char * copied_existing_filename_or_null(char *filename) { @@ -150,11 +108,15 @@ copied_realpath(const char *pathname) tidy = successful_malloc(PATH_MAX + 1); if (realpath((messy ? messy : pathname), tidy) == NULL) { - free(messy); + if (messy) + free(messy); free(tidy); return NULL; } + if (messy) + free(messy); + return tidy; } #endif /* LISP_FEATURE_WIN32 */ @@ -324,37 +286,25 @@ search_for_executable(const char *argv0) static size_t parse_size_arg(char *arg, char *arg_name) { - char *tail, *power_name; - size_t power, res; + char *tail; + size_t power = 20, res; res = strtoul(arg, &tail, 0); if (arg == tail) { lose("%s argument is not a number: %s", arg_name, arg); } else if (tail[0]) { - int i, size; - power_name = copied_string(tail); - size = strlen(power_name); - for (i=0; i<size; i++) - power_name[i] = toupper(power_name[i]); - } else { - power = 20; - power_name = NULL; - } - if (power_name) { - if ((0==strcmp("KB", power_name)) || - (0==strcmp("KIB", power_name))) { + if (!strcasecmp("KB", tail) || !strcasecmp("KIB", tail)) { power = 10; - } else if ((0==strcmp("MB", power_name)) || - (0==strcmp("MIB", power_name))) { + } else if (!strcasecmp("MB", tail) || !strcasecmp("MIB", tail)) { power = 20; - } else if ((0==strcmp("GB", power_name)) || - (0==strcmp("GIB", power_name))) { + } else if (!strcasecmp("GB", tail) || !strcasecmp("GIB", tail)) { power = 30; + } else if (!strcasecmp("TB", tail) || !strcasecmp("TIB", tail)) { + power = 40; } else { lose("%s argument has an unknown suffix: %s", arg_name, tail); } - free(power_name); } if ((res <= 0) || (res >= (SIZE_MAX >> power))) { @@ -364,12 +314,14 @@ parse_size_arg(char *arg, char *arg_name) return res; } -char **posix_argv; -char *core_string; - -#if defined(LISP_FEATURE_WIN32) && defined(LISP_FEATURE_SB_THREAD) -void pthreads_win32_init(); +#ifdef LISP_FEATURE_WIN32 + wchar_t +#else + char #endif + **posix_argv; + +char *core_string; static void print_environment(int argc, char *argv[]) { @@ -416,72 +368,128 @@ char *dir_name(char *path) { extern void write_protect_immobile_space(); struct lisp_startup_options lisp_startup_options; -int -sbcl_main(int argc, char *argv[], char *envp[]) -{ + +struct cmdline_options { + char *core; #ifdef LISP_FEATURE_WIN32 - /* Exception handling support structure. Evil Win32 hack. */ - struct lisp_exception_frame exception_frame; + wchar_t +#else + char #endif + **argv; + boolean disable_lossage_handler_p; + int merge_core_pages; +}; - /* the name of the core file we're to execute. Note that this is - * a malloc'ed string which should be freed eventually. */ - char *core = 0; - char **sbcl_argv = 0; - os_vm_offset_t embedded_core_offset = 0; +static int is_memsize_arg(char *argv[], int argi, int argc, int *merge_core_pages) +{ + char *arg = argv[argi]; + if (!strcmp(arg, "--dynamic-space-size")) { + if ((argi+1) >= argc) lose("missing argument for --dynamic-space-size"); + dynamic_space_size = parse_size_arg(argv[argi+1], + "--dynamic-space-size"); +#ifdef MAX_DYNAMIC_SPACE_END + if (!((DYNAMIC_SPACE_START < + DYNAMIC_SPACE_START+dynamic_space_size) && + (DYNAMIC_SPACE_START+dynamic_space_size <= + MAX_DYNAMIC_SPACE_END))) { + char* suffix = ""; + char* size = argv[argi-1]; + if (!strchr(size, 'B') && !strchr(size, 'b')) suffix = " [MB]"; + lose("--dynamic-space-size argument %s%s is too large, max %lu KB", + size, suffix, (MAX_DYNAMIC_SPACE_END-DYNAMIC_SPACE_START) / 1024); + } +#endif + return 2; + } + if (!strcmp(arg, "--control-stack-size")) { + if ((argi+1) >= argc) lose("missing argument for --control-stack-size"); + thread_control_stack_size = parse_size_arg(argv[argi+1], "--control-stack-size"); + return 2; + } + if (!strcmp(arg, "--tls-limit")) { + // this is not named "tls-size" because "size" is not the + // best measurement for how many symbols to allow + if ((argi+1) >= argc) lose("missing argument for --tls-limit"); + dynamic_values_bytes = N_WORD_BYTES * atoi(argv[argi+1]); + return 2; + } + if (!strcmp(arg, "--merge-core-pages")) { + *merge_core_pages = 1; + return 1; + } + if (!strcmp(arg, "--no-merge-core-pages")) { + *merge_core_pages = 0; + return 1; + } + return 0; +} +static struct cmdline_options +parse_argv(struct memsize_options memsize_options, + int argc, char *argv[], char *core) +{ +#ifdef LISP_FEATURE_WIN32 + wchar_t +#else + char +#endif + **sbcl_argv = 0; /* other command line options */ - boolean end_runtime_options = 0; boolean disable_lossage_handler_p #if defined(LISP_FEATURE_SB_LDB) = 0; #else = 1; #endif - boolean debug_environment_p = 0; - - lispobj initial_function; int merge_core_pages = -1; - struct memsize_options memsize_options; - memsize_options.present_in_core = 0; - - boolean have_hardwired_spaces = os_preinit(argv, envp); -#if defined(LISP_FEATURE_WIN32) && defined(LISP_FEATURE_SB_THREAD) - pthreads_win32_init(); -#endif - - interrupt_init(); - block_blockable_signals(0); - - /* Check early to see if this executable has an embedded core, - * which also populates runtime_options if the core has runtime - * options */ - if (!(sbcl_runtime = os_get_runtime_executable_path())) - sbcl_runtime = search_for_executable(argv[0]); - - if (!(sbcl_runtime_home = dir_name(argv[0]))) - if (!(sbcl_runtime_home = dir_name(sbcl_runtime))) - sbcl_runtime_home = libpath; - - if (sbcl_runtime) { - os_vm_offset_t offset = search_for_embedded_core(sbcl_runtime, &memsize_options); - if (offset != -1) { - embedded_core_offset = offset; - core = sbcl_runtime; - } - } - /* Parse our part of the command line (aka "runtime options"), - * stripping out those options that we handle. */ + int argi = 1; + int n_consumed; if (memsize_options.present_in_core) { + /* Our arg parsing isn't (and can't be) integrated with the application's, + * but we really want users to be able to override the heap size. + * So don't parse most options, but _do_ parse memory size options and/or + * core page merging options, wherever they occur, and strip them out. + * Any args that remain are passed through to Lisp. + * + * This does have a small semantic glitch: If your executable accepts + * flags such as "--my-opt" "--merge-core-pages" where "--merge-core-pages" + * is literally (and perversely) the value the user gives to "--my-opt", + * that's just too bad! The somewhat conventional "--" option will stop + * parsing SBCL options and pass everything else through including the "--". + * The rationale for passing "--" through is that we're trying to be + * as uninvasive as possible. Let's hope that nobody needs to put a "--" + * to the left of any of the memory size options */ dynamic_space_size = memsize_options.dynamic_space_size; thread_control_stack_size = memsize_options.thread_control_stack_size; dynamic_values_bytes = memsize_options.thread_tls_bytes; - sbcl_argv = argv; +#ifndef LISP_FEATURE_WIN32 + sbcl_argv = successful_malloc((argc + 1) * sizeof(char *)); + sbcl_argv[0] = argv[0]; + int stop_parsing = 0; // have we seen '--' + int output_index = 1; + while (argi < argc) { + if (stop_parsing) // just copy it over + sbcl_argv[output_index++] = argv[argi++]; + else if (!strcmp(argv[argi], "--")) // keep it, but parse nothing else + sbcl_argv[output_index++] = argv[argi++], stop_parsing = 1; + else if ((n_consumed = is_memsize_arg(argv, argi, argc, &merge_core_pages))) + argi += n_consumed; // eat it + else // default action - copy it + sbcl_argv[output_index++] = argv[argi++]; + } + sbcl_argv[output_index] = 0; +#else + int wargc; + sbcl_argv = CommandLineToArgvW(GetCommandLineW(), &wargc); + // Somebody who wishes this to work for #+win32 should feel free to do the same... +#endif } else { - int argi = 1; - + boolean end_runtime_options = 0; + /* Parse our any of the command-line options that we handle from C, + * stopping at the first one that we don't, and leave the rest */ while (argi < argc) { char *arg = argv[argi]; if (0 == strcmp(arg, "--script")) { @@ -518,40 +526,8 @@ sbcl_main(int argc, char *argv[], char *envp[]) /* As in "--help" case, I think this is expected. */ print_version(); exit(0); - } else if (0 == strcmp(arg, "--dynamic-space-size")) { - ++argi; - if (argi >= argc) - lose("missing argument for --dynamic-space-size"); - dynamic_space_size = parse_size_arg(argv[argi++], - "--dynamic-space-size"); -# ifdef MAX_DYNAMIC_SPACE_END - if (!((DYNAMIC_SPACE_START < - DYNAMIC_SPACE_START+dynamic_space_size) && - (DYNAMIC_SPACE_START+dynamic_space_size <= - MAX_DYNAMIC_SPACE_END))) { - char* suffix = ""; - char* size = argv[argi-1]; - if (!strchr(size, 'B') && !strchr(size, 'b')) { - suffix = " [MB]"; - } - lose("--dynamic-space-size argument %s%s is too large, max %lu KB", - size, suffix, - (MAX_DYNAMIC_SPACE_END-DYNAMIC_SPACE_START) / 1024); - } -# endif - } else if (0 == strcmp(arg, "--control-stack-size")) { - ++argi; - if (argi >= argc) - lose("missing argument for --control-stack-size"); - errno = 0; - thread_control_stack_size = parse_size_arg(argv[argi++], "--control-stack-size"); - } else if (0 == strcmp(arg, "--tls-limit")) { - // this is not named "tls-size" because "size" is not the - // best measurement for how many symbols to allow - ++argi; - if (argi >= argc) - lose("missing argument for --tls-limit"); - dynamic_values_bytes = N_WORD_BYTES * atoi(argv[argi++]); + } else if ((n_consumed = is_memsize_arg(argv, argi, argc, &merge_core_pages))) { + argi += n_consumed; } else if (0 == strcmp(arg, "--debug-environment")) { debug_environment_p = 1; ++argi; @@ -565,12 +541,6 @@ sbcl_main(int argc, char *argv[], char *envp[]) end_runtime_options = 1; ++argi; break; - } else if (0 == strcmp(arg, "--merge-core-pages")) { - ++argi; - merge_core_pages = 1; - } else if (0 == strcmp(arg, "--no-merge-core-pages")) { - ++argi; - merge_core_pages = 0; } else { /* This option was unrecognized as a runtime option, * so it must be a toplevel option or a user option, @@ -585,6 +555,7 @@ sbcl_main(int argc, char *argv[], char *envp[]) { char *argi0 = argv[argi]; int argj = 1; +#ifndef LISP_FEATURE_WIN32 /* (argc - argi) for the arguments, one for the binary, and one for the terminating NULL. */ sbcl_argv = successful_malloc((2 + argc - argi) * sizeof(char *)); @@ -602,29 +573,107 @@ sbcl_main(int argc, char *argv[], char *envp[]) } sbcl_argv[argj++] = arg; } +#else + /* The runtime options are processed as chars above, which may + * not always work but may be good enough for now, as it + * has been for a long time. */ + int wargc; + wchar_t** wargv; + wargv = CommandLineToArgvW(GetCommandLineW(), &wargc); + sbcl_argv = successful_malloc((((argi < wargc) ? (wargc - argi) : 0) + 2) + * sizeof(wchar_t *)); + sbcl_argv[0] = wargv[0]; + while (argi < wargc) { + wchar_t *warg = wargv[argi++]; + if (!end_runtime_options && + 0 == wcscmp(warg, L"--end-runtime-options")) { + lose("bad runtime option \"%s\"", argi0); + } + sbcl_argv[argj++] = warg; + } +#endif sbcl_argv[argj] = 0; } } + if (debug_environment_p) { + print_environment(argc, argv); + } + + struct cmdline_options o; + o.core = core; + o.argv = sbcl_argv; + o.disable_lossage_handler_p = disable_lossage_handler_p; + o.merge_core_pages = merge_core_pages; + return o; +} + +int +initialize_lisp(int argc, char *argv[], char *envp[]) +{ +#ifdef LISP_FEATURE_WIN32 + /* Exception handling support structure. Evil Win32 hack. */ + struct lisp_exception_frame exception_frame; +#endif +#ifdef LISP_FEATURE_UNIX + clock_gettime( +#ifdef LISP_FEATURE_LINUX + CLOCK_MONOTONIC_COARSE +#else + CLOCK_MONOTONIC +#endif + , &lisp_init_time); +#endif + + /* the name of the core file we're to execute. Note that this is + * a malloc'ed string which should be freed eventually. */ + char *core = 0; + + os_vm_offset_t embedded_core_offset = 0; + + lispobj initial_function; + struct memsize_options memsize_options; + memsize_options.present_in_core = 0; + + boolean have_hardwired_spaces = os_preinit(argv, envp); + + interrupt_init(); +#ifdef LISP_FEATURE_UNIX + /* Not sure why anyone sends signals to this process so early. + * But win32 models the signal mask as part of 'struct thread' + * which doesn't exist yet, so don't do this */ + block_blockable_signals(0); +#endif + + /* Check early to see if this executable has an embedded core, + * which also populates runtime_options if the core has runtime + * options */ + if (!(sbcl_runtime = os_get_runtime_executable_path())) + sbcl_runtime = search_for_executable(argv[0]); + + if (!(sbcl_runtime_home = dir_name(argv[0]))) + if (!(sbcl_runtime_home = dir_name(sbcl_runtime))) + sbcl_runtime_home = libpath; + + if (sbcl_runtime) { + os_vm_offset_t offset = search_for_embedded_core(sbcl_runtime, &memsize_options); + if (offset != -1) { + embedded_core_offset = offset; + core = sbcl_runtime; + } + } + + struct cmdline_options options = parse_argv(memsize_options, argc, argv, core); /* Align down to multiple of page_table page size, and to the appropriate * stack alignment. */ dynamic_space_size &= ~(sword_t)(BACKEND_PAGE_BYTES-1); #ifdef LISP_FEATURE_GENCGC - dynamic_space_size &= ~(sword_t)(GENCGC_CARD_BYTES-1); + dynamic_space_size &= ~(sword_t)(GENCGC_PAGE_BYTES-1); #endif thread_control_stack_size &= ~(sword_t)(CONTROL_STACK_ALIGNMENT_BYTES-1); - os_init(argv, envp); - if (debug_environment_p) { - print_environment(argc, argv); - } + os_init(); dyndebug_init(); -#ifdef LISP_FEATURE_ALPHA // When we remove Alpha, this #if can go away - /* KLUDGE: os_vm_page_size is set by os_init(), and on some - * systems (e.g. Alpha) arch_init() needs need os_vm_page_size, so - * it must follow os_init(). -- WHN 2000-01-26 */ - arch_init(); -#endif // FIXME: if the 'have' flag is 0 and you've disabled disabling of ASLR // then we haven't done an exec(), nor unmapped the mappings that were obtained // already obtained (if any) so it is unhelpful to try again here. @@ -632,6 +681,7 @@ sbcl_main(int argc, char *argv[], char *envp[]) gc_init(); /* If no core file was specified, look for one. */ + core = options.core; if (!core && !(core = search_for_core())) { /* Try resolving symlinks */ if (sbcl_runtime) { @@ -679,7 +729,7 @@ sbcl_main(int argc, char *argv[], char *envp[]) * of mapping dynamic space at our preferred address (if movable). * If not movable, it was already mapped in allocate_spaces(). */ initial_function = load_core_file(core, embedded_core_offset, - merge_core_pages); + options.merge_core_pages); if (initial_function == NIL) { lose("couldn't find initial function"); } @@ -689,29 +739,33 @@ sbcl_main(int argc, char *argv[], char *envp[]) #endif define_var("nil", NIL, 1); - define_var("t", T, 1); + define_var("t", LISP_T, 1); - if (!disable_lossage_handler_p) + if (!options.disable_lossage_handler_p) enable_lossage_handler(); os_link_runtime(); #ifdef LISP_FEATURE_IMMOBILE_SPACE +#ifdef CALLBACK_WRAPPER_TRAMPOLINE // not defined if #-sb-thread + // Assign the static lisp symbol's value the address of the C function + // of the same name. Needed when alien linkage table is relocatable. + extern void callback_wrapper_trampoline(); + SYMBOL(CALLBACK_WRAPPER_TRAMPOLINE)->value = (lispobj)callback_wrapper_trampoline; +#endif /* Delayed until after dynamic space has been mapped, fixups made, * and/or immobile-space linkage entries written, * since it was too soon earlier to handle write faults. */ write_protect_immobile_space(); #endif -#ifdef LISP_FEATURE_HPUX - // FIXME: obvious bitrot here. 23 isn't the offset to anything. - /* -1 = CLOSURE_FUN_OFFSET, 23 = SIMPLE_FUN_CODE_OFFSET, we are - * not in __ASSEMBLER__ so we cant reach them. */ - return_from_lisp_stub = (void *) ((char *)*((unsigned long *) - ((char *)initial_function + -1)) + 23); -#endif arch_install_interrupt_handlers(); #ifndef LISP_FEATURE_WIN32 os_install_interrupt_handlers(); +# ifdef LISP_FEATURE_SB_SAFEPOINT + ll_install_handler(SIGURG, thruption_handler); +# elif defined LISP_FEATURE_SB_THREAD + ll_install_handler(SIG_STOP_FOR_GC, sig_stop_for_gc_handler); +# endif #else /* wos_install_interrupt_handlers(handler); */ wos_install_interrupt_handlers(&exception_frame); @@ -721,11 +775,10 @@ sbcl_main(int argc, char *argv[], char *envp[]) * need to be processed further there, to do locale conversion. */ core_string = core; - posix_argv = sbcl_argv; + posix_argv = options.argv; FSHOW((stderr, "/funcalling initial_function=0x%lx\n", (unsigned long)initial_function)); - create_initial_thread(initial_function); - lose("unexpected return from initial thread in main()"); + create_main_lisp_thread(initial_function); return 0; } diff --git a/src/runtime/runtime.h b/src/runtime/runtime.h index 9448116fc2..98646341eb 100644 --- a/src/runtime/runtime.h +++ b/src/runtime/runtime.h @@ -15,7 +15,9 @@ #ifndef _SBCL_RUNTIME_H_ #define _SBCL_RUNTIME_H_ -#if defined(LISP_FEATURE_WIN32) && defined(LISP_FEATURE_SB_THREAD) +#include "lispobj.h" + +#ifdef LISP_FEATURE_WIN32 # include "pthreads_win32.h" #else # include <signal.h> @@ -28,25 +30,31 @@ #include <inttypes.h> #if defined(LISP_FEATURE_SB_THREAD) -#define thread_self() pthread_self() -#define thread_equal(a,b) pthread_equal(a,b) -#define thread_kill pthread_kill #ifdef LISP_FEATURE_WIN32 -#define thread_sigmask _sbcl_pthread_sigmask +#define thread_sigmask sb_pthread_sigmask +// wrap CriticalSection operators in a function returning 1 to satisfy assertions +static inline int cs_mutex_lock(void* l) { EnterCriticalSection(l); return 1; } +static inline int cs_mutex_unlock(void* l) { LeaveCriticalSection(l); return 1; } +#define mutex_acquire(l) cs_mutex_lock(l) +#define mutex_release(l) cs_mutex_unlock(l) #else +#define thread_self() pthread_self() +#define thread_equal(a,b) pthread_equal(a,b) #define thread_sigmask pthread_sigmask +#define mutex_acquire(l) !pthread_mutex_lock(l) +#define mutex_release(l) !pthread_mutex_unlock(l) +#define TryEnterCriticalSection(l) !pthread_mutex_trylock(l) #endif -#define thread_mutex_lock(l) pthread_mutex_lock(l) -#define thread_mutex_unlock(l) pthread_mutex_unlock(l) #else +// not SB_THREAD #define thread_self() 0 #define thread_equal(a,b) ((a)==(b)) -#define thread_kill kill_safely #define thread_sigmask sigprocmask -#define thread_mutex_lock(l) 0 -#define thread_mutex_unlock(l) 0 +#define mutex_acquire(l) 1 +#define mutex_release(l) 1 +#define TryEnterCriticalSection(l) 1 #endif #if defined(LISP_FEATURE_SB_SAFEPOINT) @@ -80,74 +88,21 @@ void gc_state_unlock(); * you are a developer and want to affect FSHOW behaviour. */ -/* Block blockable interrupts for each SHOW, if not 0. - * (On Windows, this setting has no effect.) - * - * In principle, this is a "configuration option", but I am not aware of - * any reason why or when it would be advantageous to disable it. */ -#define QSHOW_SIGNAL_SAFE 1 - -/* Enable extra-verbose low-level debugging output for signals? (You - * probably don't want this unless you're trying to debug very early - * cold boot on a new machine, or one where you've just messed up - * signal handling.) - * - * Note: It may be that doing this is fundamentally unsound, since it - * causes output from signal handlers, and the i/o libraries aren't - * necessarily reentrant. But it can still be very convenient for - * figuring out what's going on when you have a signal handling - * problem. - * - * Possible values are: - * 0 -- Never show signal-related output. There is absolutely no - * run-time overhead from FSHOW_SIGNAL in this case. - * - * 1 -- (recommended) - * Show signal-related output only if selected at run-time - * (otherwise almost no run-time overhead). - * - * 2 -- Unconditionally show signal-related output. - * Very significant overhead. - * - * For reasons of tradition, we default to 0 on POSIX and 1 on Windows - * through :SB-QSHOW. - * - * With option 1, set up environment variable SBCL_DYNDEBUG to include - * "fshow" or "fshow_signal" before starting SBCL to enable output. - * - * There is no particular advantage to option 2 except that you do not - * need to set environment variables in this case. - */ #ifdef LISP_FEATURE_SB_QSHOW -# define QSHOW_SIGNALS 1 +# define QSHOW 1 #else -# define QSHOW_SIGNALS 0 +# define QSHOW 0 #endif -/* Enable low-level debugging output, if not zero. Defaults to enabled - * if QSHOW_SIGNALS, disabled otherwise. Change it to 1 or 2 if you want - * low-level debugging output but not the whole signal mess. */ -#define QSHOW QSHOW_SIGNALS - /* * Configuration options end here -- the following defines do not * generally need customization. */ -#define odxprint(topic, fmt, ...) \ - do \ - if (dyndebug_config.dyndebug_##topic) \ - odxprint_fun(fmt "\n", ##__VA_ARGS__); \ - while (0) - -void odxprint_fun(const char *fmt, ...); -void fshow_fun(void *ignored, const char *fmt, ...); - /* Flags defined in a structure to avoid code duplication between * declaration and definition. */ extern struct dyndebug_config { int dyndebug_fshow; - int dyndebug_fshow_signal; int dyndebug_gencgc_verbose; int dyndebug_safepoints; int dyndebug_seh; @@ -165,59 +120,15 @@ extern int gencgc_verbose; void dyndebug_init(void); -#if QSHOW_SIGNAL_SAFE == 1 && !defined(LISP_FEATURE_WIN32) - -extern sigset_t blockable_sigset; - -#define QSHOW_BLOCK \ - sigset_t oldset; \ - thread_sigmask(SIG_BLOCK, &blockable_sigset, &oldset) -#define QSHOW_UNBLOCK thread_sigmask(SIG_SETMASK,&oldset,0) -#else -#define QSHOW_BLOCK -#define QSHOW_UNBLOCK -#endif - -/* The following macros duplicate the expansion of odxprint, because the - * extra level of parentheses around `args' prevents us from - * implementing FSHOW in terms of odxprint directly. (They also differ - * in a newline.) - */ - -#if QSHOW -# define FSHOW(args) \ - do if (dyndebug_config.dyndebug_fshow) fshow_fun args; while (0) -# define SHOW(string) FSHOW((stderr, "/%s\n", string)) +#if 0 +/* To see output from FSHOW - which is almost certainly a bad idea because it's + * quite likely to hinder your progress by causing deadlock in stdio - then change + * the preceding line to "#if 1" */ +# define FSHOW(args) fprintf args #else # define FSHOW(args) -# define SHOW(string) -#endif - -#if QSHOW_SIGNALS -# define FSHOW_SIGNAL(args) \ - do if (dyndebug_config.dyndebug_fshow_signal) fshow_fun args; while (0) -#else -# define FSHOW_SIGNAL(args) #endif -/* KLUDGE: These are in theory machine-dependent and OS-dependent, but - * in practice the "foo int" definitions work for all the machines - * that SBCL runs on as of 0.6.7. If we port to the Alpha or some - * other non-32-bit machine we'll probably need real machine-dependent - * and OS-dependent definitions again. */ -/* even on alpha, int happens to be 4 bytes. long is longer. */ -/* FIXME: these names really shouldn't reflect their length and this - is not quite right for some of the FFI stuff */ -#if defined(LISP_FEATURE_WIN32)&&defined(LISP_FEATURE_X86_64) -typedef unsigned long long u64; -typedef signed long long s64; -#else -typedef unsigned long u64; -typedef signed long s64; -#endif -typedef unsigned int u32; -typedef signed int s32; - #ifdef _WIN64 #define AMD64_SYSV_ABI __attribute__((sysv_abi)) #else @@ -226,33 +137,7 @@ typedef signed int s32; #include <sys/types.h> -#if defined(LISP_FEATURE_SB_THREAD) -typedef pthread_t os_thread_t; -#else -typedef pid_t os_thread_t; -#endif - -#ifndef LISP_FEATURE_ALPHA -typedef uintptr_t uword_t; -typedef intptr_t sword_t; -#else -/* The alpha32 port uses non-intptr-sized words */ -typedef u32 uword_t; -typedef s32 sword_t; -#endif - -/* FIXME: we do things this way because of the alpha32 port. once - alpha64 has arrived, all this nastiness can go away */ -#if 64 == N_WORD_BITS -#define LOW_WORD(c) ((uintptr_t)c) #define OBJ_FMTX PRIxPTR -typedef uintptr_t lispobj; -#else -#define OBJ_FMTX "x" -#define LOW_WORD(c) ((long)(c) & 0xFFFFFFFFL) -/* fake it on alpha32 */ -typedef unsigned int lispobj; -#endif static inline int lowtag_of(lispobj obj) @@ -290,41 +175,14 @@ static inline int instancep(lispobj obj) { static inline int functionp(lispobj obj) { return lowtag_of(obj) == FUN_POINTER_LOWTAG; } +static inline int other_pointer_p(lispobj obj) { + return lowtag_of(obj) == OTHER_POINTER_LOWTAG; +} static inline int simple_vector_p(lispobj obj) { - return lowtag_of(obj) == OTHER_POINTER_LOWTAG && + return other_pointer_p(obj) && widetag_of((lispobj*)(obj-OTHER_POINTER_LOWTAG)) == SIMPLE_VECTOR_WIDETAG; } -/* This is NOT the same value that lisp's %INSTANCE-LENGTH returns. - * Lisp always uses the logical length (as originally allocated), - * except when heap-walking which requires exact physical sizes */ -static inline int instance_length(lispobj header) -{ - // * Byte 3 of an instance header word holds the immobile gen# and visited bit, - // so those have to be masked off. - // * fullcgc uses bit index 31 as a mark bit, so that has to - // be cleared. Lisp does not have to clear bit 31 because fullcgc does not - // operate concurrently. - // * If the object is in hashed-and-moved state and the original instance payload - // length was odd (total object length was even), then add 1. - // This can be detected by ANDing some bits, bit 10 being the least-significant - // bit of the original size, and bit 9 being the 'hashed+moved' bit. - // * 64-bit machines do not need 'long' right-shifts, so truncate to int. - - int extra = ((unsigned int)header >> 10) & ((unsigned int)header >> 9) & 1; - return (((unsigned int)header >> INSTANCE_LENGTH_SHIFT) & 0x3FFF) + extra; -} - -/// instance_layout() macro takes a lispobj* and is an lvalue -#ifndef LISP_FEATURE_COMPACT_INSTANCE_HEADER -# define instance_layout(instance_ptr) ((lispobj*)instance_ptr)[1] -#elif defined(LISP_FEATURE_64_BIT) && defined(LISP_FEATURE_LITTLE_ENDIAN) - // so that this stays an lvalue, it can't be cast to lispobj -# define instance_layout(instance_ptr) ((uint32_t*)(instance_ptr))[1] -#else -# error "No instance_layout() defined" -#endif - /* Is the Lisp object obj something with pointer nature (as opposed to * e.g. a fixnum or character or unbound marker)? */ static inline int @@ -378,15 +236,10 @@ native_pointer(lispobj obj) static inline lispobj make_lispobj(void *o, int low_tag) { - return LOW_WORD(o) | low_tag; + return (lispobj)o | low_tag; } -#define MAKE_FIXNUM(n) (n << N_FIXNUM_TAG_BITS) -static inline lispobj -make_fixnum(uword_t n) // '<<' on negatives is _technically_ undefined behavior -{ - return MAKE_FIXNUM(n); -} +#define make_fixnum(n) ((uword_t)(n) << N_FIXNUM_TAG_BITS) static inline sword_t fixnum_value(lispobj n) @@ -394,8 +247,6 @@ fixnum_value(lispobj n) return (sword_t)n >> N_FIXNUM_TAG_BITS; } -lispobj symbol_function(lispobj* symbol); - #include "align.h" #if defined(LISP_FEATURE_WIN32) @@ -413,6 +264,16 @@ lispobj symbol_function(lispobj* symbol); #endif typedef int boolean; +// other_immediate_lowtag_p is the least strict of the tests for whether a word +// is potentially an object header, merely checking whether the bits fit the general +// pattern of header widetags without regard for whether some headered object type +// could in fact have those exact low bits. Specifically, this falsely returns 1 +// for UNBOUND_MARKER_WIDETAG, CHARACTER_WIDETAG, and on 64-bit machines, +// SINGLE_FLOAT_WIDETAG; as well as unallocated and unused widetags (e.g. LRA on x86) +// none of which denote the start of a headered object. +// The ambiguous cases are for words would start a cons - the three mentioned above. +// Other cases (NO_TLS_VALUE_MARKER_WIDETAG and other things) do not cause a problem +// in practice because they can't be the first word of a lisp object. static inline boolean other_immediate_lowtag_p(lispobj header) { @@ -420,21 +281,32 @@ other_immediate_lowtag_p(lispobj header) return (lowtag_of(header) & 3) == OTHER_IMMEDIATE_0_LOWTAG; } +// widetag_lowtag encodes in the sign bit whether the byte corresponds +// to a headered object, and in the low bits the lowtag of a tagged pointer +// pointing to this object, be it headered or a cons. +extern unsigned char widetag_lowtag[256]; +#define LOWTAG_FOR_WIDETAG(x) (widetag_lowtag[x] & LOWTAG_MASK) + +// is_header() and is_cons_half() are logical complements when invoked +// on the first word of any lisp object. However, given a word which is +// only *potentially* the first word of a lisp object, they can both be false. +// In ambiguous root detection, is_cons_half() is to be used, as it is the more +// stringent check. The set of valid bit patterns in the low byte of the car +// of a cons is smaller than the set of patterns accepted by !is_header(). +static inline int is_header(lispobj potential_header_word) { + return widetag_lowtag[potential_header_word & WIDETAG_MASK] & 0x80; +} + static inline int is_cons_half(lispobj obj) { - /* A word that satisfies other_immediate_lowtag_p is a headered object - * and can not be half of a cons, except that widetags which satisfy - * other_immediate and are Lisp immediates can be half of a cons */ - return !other_immediate_lowtag_p(obj) + if (fixnump(obj) || is_lisp_pointer(obj)) return 1; + int widetag = header_widetag(obj); + return widetag == CHARACTER_WIDETAG || #if N_WORD_BITS == 64 - || ((uword_t)IMMEDIATE_WIDETAGS_MASK >> (header_widetag(obj) >> 2)) & 1; -#else - /* The above bit-shifting approach is not applicable - * since we can't employ a 64-bit unsigned integer constant. */ - || header_widetag(obj) == CHARACTER_WIDETAG - || header_widetag(obj) == UNBOUND_MARKER_WIDETAG; + widetag == SINGLE_FLOAT_WIDETAG || #endif + widetag == UNBOUND_MARKER_WIDETAG; } /* KLUDGE: As far as I can tell there's no ANSI C way of saying @@ -457,22 +329,15 @@ extern char *copied_string (char *string); # define THREADS_USING_GCSIGNAL 1 #endif -/* Now that SPARC has precise GENCGC, several places that used to be - * #ifdef PCC need adjustment. Clearly, "PPC or SPARC" is as unhelpful - * a test as its reverse, "x86 or x86-64". However, the feature - * commonly used to differentiate between those two worlds is - * C_STACK_IS_CONTROL_STACK, and clearly (or at least in my humble - * opinion), at some point we'd like to have precise GC on x86 while - * still sharing the C stack, so stack usage ought not imply GC - * conservativeness. So let's have a helper feature that makes the code - * a bit more future-proof, even if it is itself currently defined in - * the naive way: */ +/* FIXME: this is the wrong header to make this choice */ #if defined(LISP_FEATURE_GENCGC) && !defined(LISP_FEATURE_C_STACK_IS_CONTROL_STACK) # define GENCGC_IS_PRECISE 1 #else # define GENCGC_IS_PRECISE 0 #endif +void os_link_from_pointer_table(lispobj *table_ptr); + void *os_dlsym_default(char *name); struct lisp_startup_options { diff --git a/src/runtime/safepoint.c b/src/runtime/safepoint.c index 639be3ffc7..25ff44117d 100644 --- a/src/runtime/safepoint.c +++ b/src/runtime/safepoint.c @@ -14,6 +14,7 @@ #include <stdlib.h> #include <stdio.h> #include <string.h> +#include <stdarg.h> #ifndef LISP_FEATURE_WIN32 #include <sched.h> #endif @@ -37,9 +38,9 @@ #include "interr.h" #include "alloc.h" #include "gc-internal.h" -#include "getallocptr.h" #include "interrupt.h" #include "lispregs.h" +#include "print.h" const char* gc_phase_names[GC_NPHASES] = { "GC_NONE", @@ -100,14 +101,14 @@ const char* gc_phase_names[GC_NPHASES] = { #ifdef LISP_FEATURE_SB_THREAD #define CURRENT_THREAD_VAR(name) \ - struct thread *name = arch_os_get_current_thread() + struct thread *name = get_sb_vm_thread() #define THREAD_STOP_PENDING(th) \ read_TLS(STOP_FOR_GC_PENDING, th) #define SET_THREAD_STOP_PENDING(th,state) \ write_TLS(STOP_FOR_GC_PENDING,state,th) #define WITH_ALL_THREADS_LOCK \ - pthread_mutex_lock(&all_threads_lock); \ - RUN_BODY_ONCE(all_threads_lock, pthread_mutex_unlock(&all_threads_lock)) + mutex_acquire(&all_threads_lock); \ + RUN_BODY_ONCE(all_threads_lock, mutex_release(&all_threads_lock)) #else #define CURRENT_THREAD_VAR(name) #define THREAD_STOP_PENDING(th) NIL @@ -119,12 +120,6 @@ const char* gc_phase_names[GC_NPHASES] = { /* win32-os.c covers these, but there is no unixlike-os.c, so the normal * definition goes here. Fixme: (Why) don't these work for Windows? */ -void -alloc_gc_page() -{ - os_validate(NOT_MOVABLE, GC_SAFEPOINT_PAGE_ADDR, BACKEND_PAGE_BYTES); -} - void map_gc_page() { @@ -142,15 +137,14 @@ unmap_gc_page() } #endif /* !LISP_FEATURE_WIN32 */ -struct gc_state { -#ifdef LISP_FEATURE_SB_THREAD - /* Flag: conditions are initialized */ - boolean initialized; - +static struct gc_state { +#ifdef LISP_FEATURE_WIN32 /* Per-process lock for gc_state */ - pthread_mutex_t lock; - + CRITICAL_SECTION lock;; /* Conditions: one per phase */ + CONDITION_VARIABLE phase_cond[GC_NPHASES]; +#else + pthread_mutex_t lock; pthread_cond_t phase_cond[GC_NPHASES]; #endif @@ -164,39 +158,47 @@ struct gc_state { /* Current GC phase */ gc_phase_t phase; -}; +} gc_state +#ifdef LISP_FEATURE_UNIX + = { PTHREAD_MUTEX_INITIALIZER, + { PTHREAD_COND_INITIALIZER, PTHREAD_COND_INITIALIZER, PTHREAD_COND_INITIALIZER, + PTHREAD_COND_INITIALIZER, PTHREAD_COND_INITIALIZER, PTHREAD_COND_INITIALIZER, + PTHREAD_COND_INITIALIZER }, + { 0, 0, 0, 0, 0, 0, 0 }, NULL, NULL, GC_NONE } +#endif + ; -static struct gc_state gc_state = { -#ifdef LISP_FEATURE_SB_THREAD - .lock = PTHREAD_MUTEX_INITIALIZER, +void safepoint_init() +{ +# ifdef LISP_FEATURE_WIN32 + int i; + extern void alloc_gc_page(void); + alloc_gc_page(); + for (i=GC_NONE; i<GC_NPHASES; ++i) + InitializeConditionVariable(&gc_state.phase_cond[i]); + InitializeCriticalSection(&gc_state.lock); +#else + os_alloc_gc_space(0, NOT_MOVABLE, GC_SAFEPOINT_PAGE_ADDR, BACKEND_PAGE_BYTES); #endif - .phase = GC_NONE, -}; + gc_state.phase = GC_NONE; +} void gc_state_lock() { odxprint(safepoints,"GC state to be locked"); #ifdef LISP_FEATURE_SB_THREAD - int result = pthread_mutex_lock(&gc_state.lock); - gc_assert(!result); + int result = mutex_acquire(&gc_state.lock); + gc_assert(result); #endif if (gc_state.master) { fprintf(stderr,"GC state lock glitch [%p] in thread %p phase %d (%s)\n", - gc_state.master,arch_os_get_current_thread(),gc_state.phase, + gc_state.master,get_sb_vm_thread(),gc_state.phase, gc_phase_names[gc_state.phase]); odxprint(safepoints,"GC state lock glitch [%p]",gc_state.master); } gc_assert(!gc_state.master); - gc_state.master = arch_os_get_current_thread(); -#ifdef LISP_FEATURE_SB_THREAD - if (!gc_state.initialized) { - int i; - for (i=GC_NONE; i<GC_NPHASES; ++i) - pthread_cond_init(&gc_state.phase_cond[i],NULL); - gc_state.initialized = 1; - } -#endif + gc_state.master = get_sb_vm_thread(); odxprint(safepoints,"GC state locked in phase %d (%s)", gc_state.phase, gc_phase_names[gc_state.phase]); } @@ -206,11 +208,11 @@ gc_state_unlock() { odxprint(safepoints,"GC state to be unlocked in phase %d (%s)", gc_state.phase, gc_phase_names[gc_state.phase]); - gc_assert(arch_os_get_current_thread()==gc_state.master); + gc_assert(get_sb_vm_thread()==gc_state.master); gc_state.master = NULL; #ifdef LISP_FEATURE_SB_THREAD - int result = pthread_mutex_unlock(&gc_state.lock); - gc_assert(!result); + int result = mutex_release(&gc_state.lock); + gc_assert(result); #endif odxprint(safepoints,"%s","GC state unlocked"); } @@ -218,7 +220,7 @@ gc_state_unlock() void gc_state_wait(gc_phase_t phase) { - struct thread* self = arch_os_get_current_thread(); + struct thread* self = get_sb_vm_thread(); odxprint(safepoints,"Waiting for %d (%s) -> %d (%s) [%d holders]", gc_state.phase, gc_phase_names[gc_state.phase], phase, gc_phase_names[phase], @@ -226,7 +228,9 @@ gc_state_wait(gc_phase_t phase) gc_assert(gc_state.master == self); gc_state.master = NULL; while(gc_state.phase != phase && !(phase == GC_QUIET && (gc_state.phase > GC_QUIET))) { -#ifdef LISP_FEATURE_SB_THREAD +#ifdef LISP_FEATURE_WIN32 + SleepConditionVariableCS(&gc_state.phase_cond[phase], &gc_state.lock, INFINITE); +#elif defined LISP_FEATURE_SB_THREAD pthread_cond_wait(&gc_state.phase_cond[phase],&gc_state.lock); #else lose("gc_state_wait() blocks, but we're #-SB-THREAD"); @@ -271,7 +275,7 @@ set_csp_from_context(struct thread *self, os_context_t *ctx) * disconcerting. */ void **sp = (void **) access_control_stack_pointer(self); #endif - *self->csp_around_foreign_call = (lispobj) sp; + csp_around_foreign_call(self) = (lispobj) sp; } @@ -282,17 +286,10 @@ static inline gc_phase_t gc_phase_next(gc_phase_t old) { static inline boolean thread_blocks_gc(struct thread *thread) { - /* Note that, unlike thread_may_gc(), this may be called on - * another thread, and that other thread may be in any state */ - - boolean inhibit = (read_TLS(GC_INHIBIT,thread)==T)|| - (read_TLS(IN_WITHOUT_GCING,thread)==IN_WITHOUT_GCING); - - return inhibit; + return read_TLS(GC_INHIBIT,thread)==LISP_T; } - /* set_thread_csp_access -- alter page permissions for not-in-Lisp - flag (Lisp Stack Top) of the thread `p'. The flag may be modified + flag (Lisp Stack Top) of the thread `th'. The flag may be modified if `writable' is true. Return true if there is a non-null value in the flag. @@ -309,18 +306,18 @@ thread_blocks_gc(struct thread *thread) are switched to read-only for race-free examine + wait + use scenarios. */ static inline boolean -set_thread_csp_access(struct thread* p, boolean writable) +set_thread_csp_access(struct thread* th, boolean writable) { - os_protect((char *) p->csp_around_foreign_call + N_WORD_BYTES - THREAD_CSP_PAGE_SIZE, + os_protect((char*)th - (THREAD_HEADER_SLOTS*N_WORD_BYTES) - THREAD_CSP_PAGE_SIZE, THREAD_CSP_PAGE_SIZE, writable? (OS_VM_PROT_READ|OS_VM_PROT_WRITE) : (OS_VM_PROT_READ)); - return !!*p->csp_around_foreign_call; + return csp_around_foreign_call(th) != 0; } static inline void gc_notify_early() { - struct thread *self = arch_os_get_current_thread(), *p; + struct thread *self = get_sb_vm_thread(), *p; odxprint(safepoints,"%s","global notification"); gc_assert(gc_state.phase == GC_MESSAGE); /* We're setting up the per-thread traps to make sure that all @@ -338,21 +335,21 @@ static inline void gc_notify_early() * thread. */ if (p==gc_state.collector) continue; - odxprint(safepoints,"notifying thread %p csp %p",p,*p->csp_around_foreign_call); + odxprint(safepoints,"notifying thread %p csp %p",p,csp_around_foreign_call(p)); boolean was_in_lisp = !set_thread_csp_access(p,0); if (was_in_lisp) { /* Threads "in-lisp" block leaving GC_MESSAGE, as we * need them to hit their CSP or the GSP, and we unmap * the GSP when transitioning to GC_INVOKED. */ gc_state.phase_wait[GC_MESSAGE]++; - SET_THREAD_STOP_PENDING(p,T); + SET_THREAD_STOP_PENDING(p, LISP_T); } else if (thread_blocks_gc(p)) { /* Threads "in-alien" don't block leaving GC_MESSAGE, * as the CSP trap is sufficient to catch them, but * any thread that is WITHOUT-GCING prevents exit from * GC_INVOKED. */ gc_state.phase_wait[GC_INVOKED]++; - SET_THREAD_STOP_PENDING(p,T); + SET_THREAD_STOP_PENDING(p, LISP_T); } } } @@ -372,11 +369,11 @@ static inline void gc_notify_final() for_each_thread(p) { if (p == gc_state.collector) continue; - odxprint(safepoints,"notifying thread %p csp %p",p,*p->csp_around_foreign_call); + odxprint(safepoints,"notifying thread %p csp %p",p,csp_around_foreign_call(p)); boolean was_in_lisp = !set_thread_csp_access(p,0); if (was_in_lisp) { gc_state.phase_wait[GC_SETTLED]++; - SET_THREAD_STOP_PENDING(p,T); + SET_THREAD_STOP_PENDING(p, LISP_T); } } } @@ -386,12 +383,12 @@ static inline void gc_done() { CURRENT_THREAD_VAR(self); struct thread *p; - boolean inhibit = (read_TLS(GC_INHIBIT,self)==T); + boolean inhibit = (read_TLS(GC_INHIBIT,self)==LISP_T); odxprint(safepoints,"%s","global denotification"); WITH_ALL_THREADS_LOCK { for_each_thread(p) { - if (inhibit && (read_TLS(GC_PENDING,p)==T)) + if (inhibit && (read_TLS(GC_PENDING,p)==LISP_T)) write_TLS(GC_PENDING,NIL,p); set_thread_csp_access(p,1); } @@ -456,7 +453,9 @@ static inline void gc_advance(gc_phase_t cur, gc_phase_t old) { gc_state.phase = gc_phase_next(gc_state.phase); odxprint(safepoints,"no blockers, direct advance to %d (%s)",gc_state.phase,gc_phase_names[gc_state.phase]); gc_handle_phase(); -#ifdef LISP_FEATURE_SB_THREAD +#ifdef LISP_FEATURE_WIN32 + WakeAllConditionVariable(&gc_state.phase_cond[gc_state.phase]); +#elif defined LISP_FEATURE_SB_THREAD pthread_cond_broadcast(&gc_state.phase_cond[gc_state.phase]); #endif } @@ -468,10 +467,10 @@ void thread_register_gc_trigger() { odxprint(misc, "/thread_register_gc_trigger"); - struct thread *self = arch_os_get_current_thread(); + struct thread *self = get_sb_vm_thread(); WITH_GC_STATE_LOCK { if (gc_state.phase == GC_NONE && - read_TLS(IN_SAFEPOINT,self)!=T && + read_TLS(IN_SAFEPOINT,self)!=LISP_T && !thread_blocks_gc(self)) { /* A thread (this thread), while doing allocation, has * determined that we need to run the garbage collector. @@ -486,22 +485,11 @@ thread_register_gc_trigger() } } -static inline int -thread_may_gc() -{ - /* Thread may gc if all of these are true: - * 1) GC_INHIBIT == NIL (outside of protected part of without-gcing) - * Note that we are in a safepoint here, which is always outside of PA. */ - - CURRENT_THREAD_VAR(self); - return (read_TLS(GC_INHIBIT, self) == NIL); -} - -#ifdef LISP_FEATURE_SB_THRUPTION +#ifdef LISP_FEATURE_SB_SAFEPOINT static inline int thread_may_thrupt(os_context_t *ctx) { - struct thread * self = arch_os_get_current_thread(); + struct thread * self = get_sb_vm_thread(); /* Thread may be interrupted if all of these are true: * 1) Deferrables are unblocked in the context of the signal that * went into the safepoint. -- Otherwise the surrounding code @@ -530,7 +518,7 @@ thread_may_thrupt(os_context_t *ctx) return 0; #ifdef LISP_FEATURE_WIN32 - if (deferrables_blocked_p(&self->os_thread->blocked_signal_set)) + if (deferrables_blocked_p(&thread_extra_data(self)->blocked_signal_set)) return 0; #else /* ctx is NULL if the caller wants to ignore the sigmask. */ @@ -547,17 +535,16 @@ thread_may_thrupt(os_context_t *ctx) int check_pending_thruptions(os_context_t *ctx) { - struct thread *p = arch_os_get_current_thread(); + struct thread *p = get_sb_vm_thread(); #ifdef LISP_FEATURE_WIN32 - pthread_t pself = p->os_thread; sigset_t oldset; /* On Windows, wake_thread/kill_safely does not set THRUPTION_PENDING * in the self-kill case; instead we do it here while also clearing the * "signal". */ - if (pself->pending_signal_set) - if (__sync_fetch_and_and(&pself->pending_signal_set,0)) - write_TLS(THRUPTION_PENDING, T, p); + if (thread_extra_data(p)->pending_signal_set) + if (__sync_fetch_and_and(&thread_extra_data(p)->pending_signal_set,0)) + write_TLS(THRUPTION_PENDING, LISP_T, p); #endif if (!thread_may_thrupt(ctx)) @@ -567,8 +554,8 @@ check_pending_thruptions(os_context_t *ctx) write_TLS(THRUPTION_PENDING, NIL, p); #ifdef LISP_FEATURE_WIN32 - oldset = pself->blocked_signal_set; - pself->blocked_signal_set = deferrable_sigset; + oldset = thread_extra_data(p)->blocked_signal_set; + thread_extra_data(p)->blocked_signal_set = deferrable_sigset; #else sigset_t oldset; block_deferrable_signals(&oldset); @@ -589,7 +576,7 @@ check_pending_thruptions(os_context_t *ctx) undo_fake_foreign_function_call(ctx); #ifdef LISP_FEATURE_WIN32 - pself->blocked_signal_set = oldset; + thread_extra_data(p)->blocked_signal_set = oldset; if (ctx) ctx->sigmask = oldset; #else thread_sigmask(SIG_SETMASK, &oldset, 0); @@ -630,40 +617,49 @@ assert_on_stack(struct thread *th, void *esp) if (on_altstack_p(th, esp)) lose("thread %p: esp on altstack: %p", th, esp); #endif - lose("thread %p: bogus esp: %p", th, esp); + lose("thread %p: bogus esp: %p (range=%p..%p)", th, esp, + th->control_stack_start, th->control_stack_end); +} + +/// Similar to the one in gc-common, but without the sigmask test. +static boolean can_invoke_post_gc(struct thread* th) +{ + lispobj obj = th->lisp_thread; + if (!obj) return 0; + struct thread_instance* lispthread = (void*)(obj - INSTANCE_POINTER_LOWTAG); + if (!lispthread->uw_primitive_thread) return 0; + return 1; } // returns 0 if skipped, 1 otherwise -int -check_pending_gc(os_context_t *ctx) +int check_pending_gc(__attribute((unused)) os_context_t *ctx) { odxprint(misc, "check_pending_gc"); - struct thread * self = arch_os_get_current_thread(); + struct thread * self = get_sb_vm_thread(); int done = 0; sigset_t sigset; - if ((read_TLS(IN_SAFEPOINT,self) == T) && + if ((read_TLS(IN_SAFEPOINT,self) == LISP_T) && ((read_TLS(GC_INHIBIT,self) == NIL) && (read_TLS(GC_PENDING,self) == NIL))) { write_TLS(IN_SAFEPOINT,NIL,self); } - if (thread_may_gc() && (read_TLS(IN_SAFEPOINT, self) == NIL)) { - if (read_TLS(GC_PENDING, self) == T) { + if (!thread_blocks_gc(self) && (read_TLS(IN_SAFEPOINT, self) == NIL)) { + if (read_TLS(GC_PENDING, self) == LISP_T) { lispobj gc_happened = NIL; - bind_variable(IN_SAFEPOINT,T,self); + bind_variable(IN_SAFEPOINT,LISP_T,self); block_deferrable_signals(&sigset); - if(read_TLS(GC_PENDING,self)==T) + if(read_TLS(GC_PENDING,self)==LISP_T) gc_happened = funcall1(StaticSymbolFunction(SUB_GC), 0); unbind(self); thread_sigmask(SIG_SETMASK,&sigset,NULL); - if (gc_happened == T) { + if (gc_happened == LISP_T) { /* POST_GC wants to enable interrupts */ - if (read_TLS(INTERRUPTS_ENABLED,self) == T || - read_TLS(ALLOW_WITH_INTERRUPTS,self) == T) { - odxprint(misc, "going to call POST_GC"); + if ((read_TLS(INTERRUPTS_ENABLED,self) == LISP_T || + read_TLS(ALLOW_WITH_INTERRUPTS,self) == LISP_T) + && can_invoke_post_gc(self)) funcall0(StaticSymbolFunction(POST_GC)); - } done = 1; } } @@ -674,7 +670,7 @@ check_pending_gc(os_context_t *ctx) void thread_in_lisp_raised(os_context_t *ctxptr) { - struct thread *self = arch_os_get_current_thread(); + struct thread *self = get_sb_vm_thread(); boolean check_gc_and_thruptions = 0; odxprint(safepoints,"%s","thread_in_lisp_raised"); @@ -682,9 +678,8 @@ void thread_in_lisp_raised(os_context_t *ctxptr) * there is a stop-for-GC or thruption pending. */ WITH_GC_STATE_LOCK { if (gc_state.phase == GC_FLIGHT && - read_TLS(GC_PENDING,self)==T && - !thread_blocks_gc(self) && - thread_may_gc() && read_TLS(IN_SAFEPOINT,self)!=T) { + read_TLS(GC_PENDING,self)==LISP_T && + !thread_blocks_gc(self) && read_TLS(IN_SAFEPOINT,self)!=LISP_T) { /* Some thread (possibly even this one) that does not have * GC_INHIBIT set has noticed that a GC is warranted and * advanced the phase to GC_FLIGHT, arming the GSP trap, @@ -704,9 +699,9 @@ void thread_in_lisp_raised(os_context_t *ctxptr) gc_advance(GC_NONE,GC_QUIET); } else { /* ??? Isn't this already T? */ - write_TLS(GC_PENDING,T,self); + write_TLS(GC_PENDING,LISP_T,self); } - *self->csp_around_foreign_call = 0; + csp_around_foreign_call(self) = 0; check_gc_and_thruptions = 1; } else { /* This thread isn't a candidate for running the GC @@ -727,7 +722,7 @@ void thread_in_lisp_raised(os_context_t *ctxptr) gc_advance(GC_NONE,gc_state.phase); else gc_state_wait(GC_NONE); - *self->csp_around_foreign_call = 0; + csp_around_foreign_call(self) = 0; check_gc_and_thruptions = 1; } else { /* This thread has GC_INHIBIT set, meaning that it's @@ -737,7 +732,7 @@ void thread_in_lisp_raised(os_context_t *ctxptr) * we'll take a PIT stop and wind up in the case * above... Or we'll call gc_stop_the_world(). */ gc_advance(GC_INVOKED,gc_state.phase); - SET_THREAD_STOP_PENDING(self,T); + SET_THREAD_STOP_PENDING(self,LISP_T); /* Why do we not want to run thruptions here? */ } } @@ -746,7 +741,7 @@ void thread_in_lisp_raised(os_context_t *ctxptr) * SUB-GC. Phase is either GC_QUIET or GC_NONE. */ if (check_gc_and_thruptions) { check_pending_gc(ctxptr); -#ifdef LISP_FEATURE_SB_THRUPTION +#ifdef LISP_FEATURE_SB_SAFEPOINT while(check_pending_thruptions(ctxptr)); #endif } @@ -754,7 +749,7 @@ void thread_in_lisp_raised(os_context_t *ctxptr) void thread_in_safety_transition(os_context_t *ctxptr) { - struct thread *self = arch_os_get_current_thread(); + struct thread *self = get_sb_vm_thread(); boolean was_in_alien; odxprint(safepoints,"%s","GC safety transition"); @@ -789,7 +784,7 @@ void thread_in_safety_transition(os_context_t *ctxptr) gc_advance(GC_NONE,gc_state.phase); else gc_state_wait(GC_NONE); - *self->csp_around_foreign_call = 0; + csp_around_foreign_call(self) = 0; } else { /* This thread has GC_INHIBIT set, meaning that it's * within a WITHOUT-GCING, so advance from wherever we @@ -800,11 +795,11 @@ void thread_in_safety_transition(os_context_t *ctxptr) * logic is identical to the similar case in * thread_in_lisp_raised(). */ gc_advance(GC_INVOKED,gc_state.phase); - SET_THREAD_STOP_PENDING(self,T); + SET_THREAD_STOP_PENDING(self,LISP_T); } } } -#ifdef LISP_FEATURE_SB_THRUPTION +#ifdef LISP_FEATURE_SB_SAFEPOINT if (was_in_alien) { while(check_pending_thruptions(ctxptr)); } @@ -814,7 +809,7 @@ void thread_in_safety_transition(os_context_t *ctxptr) #ifdef LISP_FEATURE_WIN32 void thread_interrupted(os_context_t *ctxptr) { - struct thread *self = arch_os_get_current_thread(); + struct thread *self = get_sb_vm_thread(); boolean gc_active, was_in_alien; odxprint(safepoints,"%s","pending interrupt trap"); @@ -832,7 +827,7 @@ void thread_interrupted(os_context_t *ctxptr) } } check_pending_gc(ctxptr); -#ifdef LISP_FEATURE_SB_THRUPTION +#ifdef LISP_FEATURE_SB_SAFEPOINT while(check_pending_thruptions(ctxptr)); #endif } @@ -841,7 +836,7 @@ void thread_interrupted(os_context_t *ctxptr) void gc_stop_the_world() { - struct thread* self = arch_os_get_current_thread(); + struct thread* self = get_sb_vm_thread(); odxprint(safepoints, "stop the world"); WITH_GC_STATE_LOCK { /* This thread is the collector, and needs special handling in @@ -897,14 +892,12 @@ void gc_start_the_world() odxprint(safepoints,"%s","start the world"); WITH_GC_STATE_LOCK { gc_state.collector = NULL; - write_TLS(IN_WITHOUT_GCING,IN_WITHOUT_GCING, - arch_os_get_current_thread()); gc_advance(GC_NONE,GC_COLLECT); } } -#ifdef LISP_FEATURE_SB_THRUPTION +#ifdef LISP_FEATURE_SB_SAFEPOINT /* wake_thread(thread) -- ensure a thruption delivery to * `thread'. */ @@ -913,29 +906,27 @@ void gc_start_the_world() void wake_thread_io(struct thread * thread) { - SetEvent(thread->private_events.events[1]); + SetEvent(thread_private_events(thread,1)); win32_maybe_interrupt_io(thread); } -void -wake_thread_win32(struct thread *thread) +void wake_thread_impl(struct thread_instance *lispthread) { - struct thread *self = arch_os_get_current_thread(); - + struct thread* thread = (void*)lispthread->uw_primitive_thread; wake_thread_io(thread); - if (read_TLS(THRUPTION_PENDING,thread)==T) + if (read_TLS(THRUPTION_PENDING,thread)==LISP_T) return; - write_TLS(THRUPTION_PENDING,T,thread); + write_TLS(THRUPTION_PENDING,LISP_T,thread); - if ((read_TLS(GC_PENDING,thread)==T) - ||(THREAD_STOP_PENDING(thread)==T) + if ((read_TLS(GC_PENDING,thread)==LISP_T) + ||(THREAD_STOP_PENDING(thread)==LISP_T) ) return; wake_thread_io(thread); - pthread_mutex_unlock(&all_threads_lock); + mutex_release(&all_threads_lock); WITH_GC_STATE_LOCK { if (gc_state.phase == GC_NONE) { @@ -944,24 +935,22 @@ wake_thread_win32(struct thread *thread) } } - pthread_mutex_lock(&all_threads_lock); + mutex_acquire(&all_threads_lock); return; } # else -int -wake_thread_posix(os_thread_t os_thread) +void wake_thread_impl(struct thread_instance *lispthread) { - int found = 0; - struct thread *thread; - struct thread *self = arch_os_get_current_thread(); + struct thread *thread = (void*)lispthread->uw_primitive_thread; + struct thread *self = get_sb_vm_thread(); /* Must not and need not attempt to signal ourselves while we're the * STW initiator. */ - if (self->os_thread == os_thread) { - write_TLS(THRUPTION_PENDING,T,self); + if (thread == self) { + write_TLS(THRUPTION_PENDING,LISP_T,self); while (check_pending_thruptions(0 /* ignore the sigmask */)) ; - return 0; + return; } /* We are not in a signal handler here, so need to block signals @@ -974,77 +963,59 @@ wake_thread_posix(os_thread_t os_thread) odxprint(safepoints, "wake_thread_posix: invoking"); gc_advance(GC_INVOKED,GC_NONE); { + /* I do not know whether WITH_ALL_THREADS_LOCK was only to avoid + * hitting wild pointers in the loop over threads (gone now) + * or whether it _also_ had an effect on the safepoint state. + * Out of caution I'm leaving it in despite removing the loop */ + /* only if in foreign code, notify using signal */ WITH_ALL_THREADS_LOCK { - for_each_thread (thread) - if (thread->os_thread == os_thread) { - /* it's still alive... */ - found = 1; - + do { odxprint(safepoints, "wake_thread_posix: found"); - write_TLS(THRUPTION_PENDING,T,thread); - if (read_TLS(GC_PENDING,thread) == T - || THREAD_STOP_PENDING(thread) == T) + write_TLS(THRUPTION_PENDING,LISP_T,thread); + if (read_TLS(GC_PENDING,thread) == LISP_T + || THREAD_STOP_PENDING(thread) == LISP_T) break; if (os_get_csp(thread)) { odxprint(safepoints, "wake_thread_posix: kill"); /* ... and in foreign code. Push it into a safety * transition. */ - int status = pthread_kill(os_thread, SIGPIPE); + int status = pthread_kill((pthread_t)lispthread->uw_os_thread, SIGURG); if (status) lose("wake_thread_posix: pthread_kill failed with %d", status); } - break; - } + } while(0); } } gc_advance(GC_NONE,GC_INVOKED); } else { odxprint(safepoints, "wake_thread_posix: passive"); - /* We are not able to wake the thread up actively, but maybe - * some other thread will take care of it. Kludge: Unless it is - * in foreign code. Let's at least try to get our return value - * right. */ - WITH_ALL_THREADS_LOCK { - for_each_thread (thread) - if (thread->os_thread == os_thread) { - write_TLS(THRUPTION_PENDING,T,thread); - found = 1; - break; - } - } + write_TLS(THRUPTION_PENDING, LISP_T, thread); } } - - odxprint(safepoints, "wake_thread_posix leaving, found=%d", found); thread_sigmask(SIG_SETMASK, &oldset, 0); - return found ? 0 : -1; } #endif /* !LISP_FEATURE_WIN32 */ -#endif /* LISP_FEATURE_SB_THRUPTION */ +#endif /* LISP_FEATURE_SB_SAFEPOINT */ -void** -os_get_csp(struct thread* th) +void* os_get_csp(struct thread* th) { - FSHOW_SIGNAL((stderr, "Thread %p has CSP *(%p) == %p, stack [%p,%p]\n", - th, - th->csp_around_foreign_call, - *(void***)th->csp_around_foreign_call, - th->control_stack_start, - th->control_stack_end)); - return *(void***)th->csp_around_foreign_call; + return (void*)csp_around_foreign_call(th); } #ifndef LISP_FEATURE_WIN32 -# ifdef LISP_FEATURE_SB_THRUPTION -void -thruption_handler(int signal, siginfo_t *info, os_context_t *ctx) +# ifdef LISP_FEATURE_SB_SAFEPOINT +/* This is basically what 'low_level_maybe_now_maybe_later' was (which doesn't exist), + * but with a different name, and different way of deciding to defer the signal */ +void thruption_handler(__attribute__((unused)) int signal, + __attribute__((unused)) siginfo_t *info, + os_context_t *ctx) { - struct thread *self = arch_os_get_current_thread(); + struct thread *self = get_sb_vm_thread(); void *transition_sp = os_get_csp(self); if (!transition_sp) @@ -1058,9 +1029,9 @@ thruption_handler(int signal, siginfo_t *info, os_context_t *ctx) #endif /* In C code. As a rule, we assume that running thruptions is OK. */ - *self->csp_around_foreign_call = 0; + csp_around_foreign_call(self) = 0; thread_in_lisp_raised(ctx); - *self->csp_around_foreign_call = (intptr_t) transition_sp; + csp_around_foreign_call(self) = (intptr_t) transition_sp; } # endif @@ -1076,12 +1047,7 @@ handle_csp_safepoint_violation(lispobj fun, lispobj *args, int nargs); int handle_safepoint_violation(os_context_t *ctx, os_vm_address_t fault_address) { - FSHOW_SIGNAL((stderr, "fault_address = %p, sp = %p, &csp = %p\n", - fault_address, - GC_SAFEPOINT_TRAP_ADDR, - arch_os_get_current_thread()->csp_around_foreign_call)); - - struct thread *self = arch_os_get_current_thread(); + struct thread *self = get_sb_vm_thread(); if (fault_address == (os_vm_address_t) GC_SAFEPOINT_TRAP_ADDR) { #ifdef LISP_FEATURE_C_STACK_IS_CONTROL_STACK @@ -1096,7 +1062,7 @@ handle_safepoint_violation(os_context_t *ctx, os_vm_address_t fault_address) return 1; } - if (fault_address == (os_vm_address_t) self->csp_around_foreign_call) { + if ((1+THREAD_HEADER_SLOTS)+(lispobj*)fault_address == (lispobj*)self) { #ifdef LISP_FEATURE_C_STACK_IS_CONTROL_STACK arrange_return_to_c_function(ctx, handle_csp_safepoint_violation, 0); #else @@ -1111,28 +1077,52 @@ handle_safepoint_violation(os_context_t *ctx, os_vm_address_t fault_address) } #endif /* LISP_FEATURE_WIN32 */ -#if defined(LISP_FEATURE_SB_SAFEPOINT_STRICTLY) && !defined(LISP_FEATURE_WIN32) void -signal_handler_callback(lispobj run_handler, int signo, void *info, void *ctx) +vodxprint_fun(const char *fmt, va_list args) { - init_thread_data scribble; - void *args[2]; - DX_ALLOC_SAP(args_sap, args); +#ifdef LISP_FEATURE_WIN32 + DWORD lastError = GetLastError(); +#endif + int original_errno = errno; - args[0] = info; - args[1] = ctx; + char buf[1024]; + int n = 0; - attach_os_thread(&scribble); + snprintf(buf, sizeof(buf), "["THREAD_ID_LABEL"] ", THREAD_ID_VALUE); + n = strlen(buf); - odxprint(misc, "callback from signal handler thread for: %d\n", signo); - WITH_GC_AT_SAFEPOINTS_ONLY() { - funcall3(StaticSymbolFunction(SIGNAL_HANDLER_CALLBACK), - run_handler, make_fixnum(signo), args_sap); - } + vsnprintf(buf + n, sizeof(buf) - n - 1, fmt, args); + /* buf is now zero-terminated (even in case of overflow). + * Our caller took care of the newline (if any) through `fmt'. */ - detach_os_thread(&scribble); - return; -} + /* A sufficiently POSIXy implementation of stdio will provide + * per-FILE locking, as defined in the spec for flockfile. At least + * glibc complies with this. Hence we do not need to perform + * locking ourselves here. (Should it turn out, of course, that + * other libraries opt for speed rather than safety, we need to + * revisit this decision.) */ + fputs(buf, stderr); + +#ifdef LISP_FEATURE_WIN32 + /* stdio's stderr is line-bufferred, i.e. \n ought to flush it. + * Unfortunately, MinGW does not behave the way I would expect it + * to. Let's be safe: */ + fflush(stderr); #endif +#ifdef LISP_FEATURE_WIN32 + SetLastError(lastError); +#endif + errno = original_errno; +} + +void +odxprint_fun(const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + vodxprint_fun(fmt, args); + va_end(args); +} + #endif /* LISP_FEATURE_SB_SAFEPOINT -- entire file */ diff --git a/src/runtime/save.c b/src/runtime/save.c index 54383fd95e..8f716ea571 100644 --- a/src/runtime/save.c +++ b/src/runtime/save.c @@ -19,7 +19,7 @@ #include <sys/file.h> #include "sbcl.h" -#if defined(LISP_FEATURE_WIN32) && defined(LISP_FEATURE_SB_THREAD) +#ifdef LISP_FEATURE_WIN32 #include "pthreads_win32.h" #else #include <signal.h> @@ -35,7 +35,6 @@ #include "gc-internal.h" #include "thread.h" #include "arch.h" -#include "getallocptr.h" #include "genesis/static-symbols.h" #include "genesis/symbol.h" #include "genesis/vector.h" @@ -43,7 +42,7 @@ #include "search.h" #ifdef LISP_FEATURE_SB_CORE_COMPRESSION -# include <zlib.h> +# include <zstd.h> #endif #define GENERAL_WRITE_FAILURE_MSG "error writing to core file" @@ -77,7 +76,7 @@ write_lispobj(lispobj obj, FILE *file) } static void -write_bytes_to_file(FILE * file, char *addr, long bytes, int compression) +write_bytes_to_file(FILE * file, char *addr, size_t bytes, int compression) { if (compression == COMPRESSION_LEVEL_NONE) { while (bytes > 0) { @@ -92,31 +91,42 @@ write_bytes_to_file(FILE * file, char *addr, long bytes, int compression) } } #ifdef LISP_FEATURE_SB_CORE_COMPRESSION - } else if ((compression >= -1) && (compression <= 9)) { -# define ZLIB_BUFFER_SIZE (1u<<16) - z_stream stream; - unsigned char* buf = successful_malloc(ZLIB_BUFFER_SIZE); + } else if ((compression >= -7) && (compression <= 22)) { + int ret; + ZSTD_inBuffer input; + input.src = addr; + input.size = bytes; + input.pos = 0; + + size_t buf_size = ZSTD_CStreamOutSize(); + unsigned char* buf = successful_malloc(buf_size); + ZSTD_outBuffer output; + output.dst = buf; + output.size = buf_size; + unsigned char * written, * end; long total_written = 0; - int ret; - stream.zalloc = NULL; - stream.zfree = NULL; - stream.opaque = NULL; - stream.avail_in = bytes; - stream.next_in = (void*)addr; - ret = deflateInit(&stream, compression); - if (ret != Z_OK) - lose("deflateInit: %i", ret); + ZSTD_CStream *stream = ZSTD_createCStream(); + if (stream == NULL) + lose("failed to create zstd compression context"); + ret = ZSTD_initCStream(stream, compression); + if (ZSTD_isError(ret)) + lose("ZSTD_initCStream failed with error: %s", + ZSTD_getErrorName(ret)); do { - stream.avail_out = ZLIB_BUFFER_SIZE; - stream.next_out = buf; - ret = deflate(&stream, Z_FINISH); - if (ret < 0) lose("zlib deflate error: %i... exiting", ret); + output.pos = 0; + if (input.pos < bytes) + ret = ZSTD_compressStream(stream, &output, &input); + else + ret = ZSTD_endStream(stream, &output); + if (ZSTD_isError(ret)) + lose("ZSTD_compressStream2 failed with error: %s", + ZSTD_getErrorName(ret)); written = buf; - end = buf+ZLIB_BUFFER_SIZE-stream.avail_out; - total_written += end - written; + end = buf + output.pos; + total_written += output.pos; while (written < end) { - long count = fwrite(written, 1, end-written, file); + long count = fwrite(written, 1, output.pos, file); if (count > 0) { written += count; } else { @@ -124,18 +134,17 @@ write_bytes_to_file(FILE * file, char *addr, long bytes, int compression) lose("core file is incomplete or corrupt"); } } - } while (stream.avail_out == 0); - deflateEnd(&stream); - free(buf); + } while (ret != 0); printf("compressed %lu bytes into %lu at level %i\n", bytes, total_written, compression); -# undef ZLIB_BUFFER_SIZE + + ZSTD_freeCStream(stream); #endif } else { #ifdef LISP_FEATURE_SB_CORE_COMPRESSION lose("Unknown core compression level %i, exiting", compression); #else - lose("zlib-compressed core support not built in this runtime"); + lose("zstd-compressed core support not built in this runtime"); #endif } @@ -145,27 +154,24 @@ write_bytes_to_file(FILE * file, char *addr, long bytes, int compression) } }; - -static long write_bytes(FILE *file, char *addr, long bytes, +static long write_bytes(FILE *file, char *addr, size_t bytes, os_vm_offset_t file_offset, int compression) { - long here, data; + ftell_type here, data; #ifdef LISP_FEATURE_WIN32 - long count; - /* touch every single page in the space to force it to be mapped. */ - for (count = 0; count < bytes; count += 0x1000) { - volatile int temp = addr[count]; - } + // I can't see how we'd ever attempt writing from uncommitted memory, + // but this is better than was was previously here (a "touch" loop over all pages) + os_commit_memory(addr, bytes); #endif fflush(file); - here = ftell(file); - fseek(file, 0, SEEK_END); - data = ALIGN_UP(ftell(file), os_vm_page_size); - fseek(file, data, SEEK_SET); + here = FTELL(file); + FSEEK(file, 0, SEEK_END); + data = ALIGN_UP(FTELL(file), os_vm_page_size); + FSEEK(file, data, SEEK_SET); write_bytes_to_file(file, addr, bytes, compression); - fseek(file, here, SEEK_SET); + FSEEK(file, here, SEEK_SET); return ((data - file_offset) / os_vm_page_size) - 1; } @@ -176,7 +182,7 @@ output_space(FILE *file, int id, lispobj *addr, lispobj *end, { size_t words, bytes, data, compressed_flag; static char *names[] = {NULL, "dynamic", "static", "read-only", - "immobile", "immobile"}; + "fixedobj", "text"}; compressed_flag = ((core_compression_level != COMPRESSION_LEVEL_NONE) @@ -186,7 +192,12 @@ output_space(FILE *file, int id, lispobj *addr, lispobj *end, words = end - addr; write_lispobj(words, file); - bytes = words * sizeof(lispobj); +#ifdef LISP_FEATURE_METASPACE + if (id == READ_ONLY_CORE_SPACE_ID) + bytes = (READ_ONLY_SPACE_END - READ_ONLY_SPACE_START); + else +#endif + bytes = words * sizeof(lispobj); #ifdef LISP_FEATURE_CHENEYGC /* KLUDGE: cheneygc can not restart a saved core if the dynamic space is empty, @@ -240,13 +251,18 @@ void unwind_binding_stack() write_TLS(CURRENT_UNWIND_PROTECT_BLOCK, 0, th); unsigned int hint = 0; char symbol_name[] = "*SAVE-LISP-CLOBBERED-GLOBALS*"; - lispobj* sym = find_symbol(symbol_name, sb_kernel_package(), &hint); + lispobj* sym = find_symbol(symbol_name, + VECTOR(lisp_package_vector)->data[PACKAGE_ID_KERNEL], + &hint); lispobj value; int i; if (!sym || !simple_vector_p(value = ((struct symbol*)sym)->value)) fprintf(stderr, "warning: bad value in %s\n", symbol_name); - else for(i=fixnum_value(VECTOR(value)->length)-1; i>=0; --i) + else for(i=vector_len(VECTOR(value))-1; i>=0; --i) SYMBOL(VECTOR(value)->data[i])->value = UNBOUND_MARKER_WIDETAG; + // these are akin to weak-pointers + lisp_package_vector = 0; + alloc_profile_data = 0; if (verbose) printf("done]\n"); } @@ -265,7 +281,7 @@ save_to_filehandle(FILE *file, char *filename, lispobj init_function, fflush(stdout); } - os_vm_offset_t core_start_pos = ftell(file); + os_vm_offset_t core_start_pos = FTELL(file); write_lispobj(CORE_MAGIC, file); /* If 'save_runtime_options' is specified then the saved thread stack size @@ -294,22 +310,33 @@ save_to_filehandle(FILE *file, char *filename, lispobj init_function, write_lispobj(/* (word count = N spaces described by 5 words each, plus the * entry type code, plus this count itself) */ (5 * MAX_CORE_SPACE_ID) + 2, file); - output_space(file, - READ_ONLY_CORE_SPACE_ID, - (lispobj *)READ_ONLY_SPACE_START, - read_only_space_free_pointer, - core_start_pos, - core_compression_level); output_space(file, STATIC_CORE_SPACE_ID, (lispobj *)STATIC_SPACE_START, static_space_free_pointer, core_start_pos, core_compression_level); +#ifdef LISP_FEATURE_DARWIN_JIT + output_space(file, + STATIC_CODE_CORE_SPACE_ID, + (lispobj *)STATIC_CODE_SPACE_START, + static_code_space_free_pointer, + core_start_pos, + core_compression_level); +#endif output_space(file, DYNAMIC_CORE_SPACE_ID, - current_dynamic_space, - (lispobj *)get_alloc_pointer(), + (void*)DYNAMIC_SPACE_START, + (void*)dynamic_space_highwatermark(), + core_start_pos, + core_compression_level); + /* FreeBSD really doesn't like to give you the address you asked for + * on dynamic space. We have a better chance at satisfying the request + * if we haven't already mapped R/O space below it. */ + output_space(file, + READ_ONLY_CORE_SPACE_ID, + (lispobj *)READ_ONLY_SPACE_START, + read_only_space_free_pointer, core_start_pos, core_compression_level); #ifdef LISP_FEATURE_IMMOBILE_SPACE @@ -324,9 +351,9 @@ save_to_filehandle(FILE *file, char *filename, lispobj init_function, // i.e. if code resided between dynamic and fixedobj space, then dynamic // space would need to have it pages renumbered when code is pulled out. output_space(file, - IMMOBILE_VARYOBJ_CORE_SPACE_ID, - (lispobj *)VARYOBJ_SPACE_START, - varyobj_free_pointer, + IMMOBILE_TEXT_CORE_SPACE_ID, + (lispobj *)TEXT_SPACE_START, + text_space_highwatermark, core_start_pos, core_compression_level); #endif @@ -346,7 +373,8 @@ save_to_filehandle(FILE *file, char *filename, lispobj init_function, memset(data + aligned_size - N_WORD_BYTES, 0, N_WORD_BYTES); gc_store_corefile_ptes((struct corefile_pte*)data); write_lispobj(PAGE_TABLE_CORE_ENTRY_TYPE_CODE, file); - write_lispobj(5, file); // 5 = # of words in this core header entry + write_lispobj(6, file); // number of words in this core header entry + write_lispobj(gc_card_table_nbits, file); write_lispobj(next_free_page, file); write_lispobj(aligned_size, file); sword_t offset = write_bytes(file, data, aligned_size, core_start_pos, diff --git a/src/runtime/search.c b/src/runtime/search.c index 06113ebdca..bb19ece2e5 100644 --- a/src/runtime/search.c +++ b/src/runtime/search.c @@ -18,10 +18,12 @@ #include "search.h" #include "thread.h" #include "gc-internal.h" +#include "gc-private.h" #include "genesis/primitive-objects.h" #include "genesis/hash-table.h" #include "genesis/package.h" -#include "getallocptr.h" // for get_alloc_pointer() +#include "brothertree.h" +#include "forwarding-ptr.h" lispobj * search_read_only_space(void *pointer) @@ -36,7 +38,7 @@ search_read_only_space(void *pointer) lispobj * search_static_space(void *pointer) { - lispobj *start = (lispobj *)STATIC_SPACE_START; + lispobj *start = (lispobj *)STATIC_SPACE_OBJECTS_START; lispobj *end = static_space_free_pointer; if ((pointer < (void *)start) || (pointer >= (void *)end)) return NULL; @@ -93,7 +95,6 @@ lispobj* search_for_symbol(char *name, lispobj start, lispobj end, boolean ignor { lispobj* where = (lispobj*)start; lispobj* limit = (lispobj*)end; - struct symbol *symbol; lispobj namelen = make_fixnum(strlen(name)); #ifdef LISP_FEATURE_GENCGC @@ -101,30 +102,28 @@ lispobj* search_for_symbol(char *name, lispobj start, lispobj end, boolean ignor // It has become even less safe now that don't prezero most pages during GC, // because we will certainly encounter remnants of forwarding pointers etc. // So if the specified range is all of dynamic space, defer to the space walker. - if (start == DYNAMIC_SPACE_START && end == (uword_t)get_alloc_pointer()) { + if (start == DYNAMIC_SPACE_START && end == dynamic_space_highwatermark()) { struct symbol_search ss = {name, ignore_case}; return (lispobj*)walk_generation(search_symbol_aux, -1, (uword_t)&ss); } #endif while (where < limit) { - lispobj word = *where; - if (header_widetag(word) == SYMBOL_WIDETAG && - lowtag_of((symbol = (struct symbol *)where)->name) == OTHER_POINTER_LOWTAG) { - struct vector *symbol_name = VECTOR(symbol->name); - if (gc_managed_addr_p((lispobj)symbol_name) && - ((widetag_of(&symbol_name->header) == SIMPLE_BASE_STRING_WIDETAG - && symbol_name->length == namelen - && !(ignore_case ? strcasecmp : strcmp)((char *)symbol_name->data, name)) + struct vector *string; + if (widetag_of(where) == SYMBOL_WIDETAG && + (string = symbol_name((struct symbol*)where)) != 0 && + string->length_ == namelen) { + if (gc_managed_addr_p((lispobj)string) && + ((widetag_of(&string->header) == SIMPLE_BASE_STRING_WIDETAG + && !(ignore_case ? strcasecmp : strcmp)((char *)string->data, name)) #ifdef LISP_FEATURE_SB_UNICODE - || (widetag_of(&symbol_name->header) == SIMPLE_CHARACTER_STRING_WIDETAG - && symbol_name->length == namelen - && !strcmp_ucs4_ascii((uint32_t*)symbol_name->data, + || (widetag_of(&string->header) == SIMPLE_CHARACTER_STRING_WIDETAG + && !strcmp_ucs4_ascii((uint32_t*)string->data, (unsigned char*)name, ignore_case)) #endif )) return where; } - where += OBJECT_SIZE(word, where); + where += object_size(where); } return 0; } @@ -147,12 +146,12 @@ struct symbol* lisp_symbol_from_tls_index(lispobj tls_index) if (widetag == SYMBOL_WIDETAG && tls_index_of(((struct symbol*)where)) == tls_index) return (struct symbol*)where; - where += OBJECT_SIZE(header, where); + where += object_size2(where, header); } if (where >= (lispobj*)DYNAMIC_SPACE_START) break; where = (lispobj*)DYNAMIC_SPACE_START; - end = (lispobj*)get_alloc_pointer(); + end = (lispobj*)dynamic_space_highwatermark(); } return 0; } @@ -160,9 +159,9 @@ struct symbol* lisp_symbol_from_tls_index(lispobj tls_index) static boolean sym_stringeq(lispobj sym, const char *string, int len) { - struct vector* name = VECTOR(SYMBOL(sym)->name); + struct vector* name = symbol_name(SYMBOL(sym)); return widetag_of(&name->header) == SIMPLE_BASE_STRING_WIDETAG - && name->length == make_fixnum(len) + && vector_len(name) == len && !memcmp(name->data, string, len); } @@ -180,7 +179,7 @@ static lispobj* search_package_symbols(lispobj package, char* symbol_name, struct vector* cells = VECTOR(symbols->slots[INSTANCE_DATA_START]); gc_assert(widetag_of(&cells->header) == SIMPLE_VECTOR_WIDETAG); lispobj namelen = strlen(symbol_name); - int cells_length = fixnum_value(cells->length); + int cells_length = vector_len(cells); int index = *hint >> 1; if (index >= cells_length) index = 0; // safeguard against vector shrinkage @@ -200,46 +199,124 @@ static lispobj* search_package_symbols(lispobj package, char* symbol_name, return 0; } -lispobj sb_kernel_package() { - return SYMBOL(FDEFN(SUB_GC_FDEFN)->name)->package; -} - -lispobj find_package(char* package_name) -{ - // Use SB-KERNEL::SUB-GC to get a hold of the SB-KERNEL package, - // which contains the symbol *PACKAGE-NAMES*. - static unsigned int kernelpkg_hint; - lispobj* package_names = search_package_symbols(sb_kernel_package(), - "*PACKAGE-NAMES*", - &kernelpkg_hint); - if (!package_names) - return 0; - lispobj namelen = strlen(package_name); - struct instance* names = (struct instance*) - native_pointer(((struct symbol*)package_names)->value); - struct vector* cells = (struct vector*) - native_pointer(names->slots[INSTANCE_DATA_START]); -#define LFHASH_KEY_OFFSET 3 /* KLUDGE */ - int n = (fixnum_value(cells->length) - LFHASH_KEY_OFFSET) >> 1; - gc_assert(make_fixnum(n) == cells->data[0]); - int i; - // Search *PACKAGE-NAMES* for the package - for (i=0; i<n; ++i) { - lispobj element = cells->data[LFHASH_KEY_OFFSET+i]; - if (is_lisp_pointer(element)) { - struct vector* string = (struct vector*)native_pointer(element); - if (widetag_of(&string->header) == SIMPLE_BASE_STRING_WIDETAG - && string->length == make_fixnum(namelen) - && !memcmp(string->data, package_name, namelen)) { - element = cells->data[LFHASH_KEY_OFFSET+n+i]; - return listp(element) ? CONS(element)->car : element; - } +lispobj* find_symbol(char* symbol_name, lispobj package, unsigned int* hint) +{ + return package ? search_package_symbols(package, symbol_name, hint) : 0; +} + +static inline boolean fringe_node_p(struct binary_node* node) +{ + int len = ((unsigned int)node->header >> INSTANCE_LENGTH_SHIFT) & INSTANCE_LENGTH_MASK; + return len <= (int)(1+INSTANCE_DATA_START); +} + +/* I anticipate using the brothertree search algorithms to find code + * while GC has already potentially moved some of the tree nodes, + * thus the use of follow_fp() before dereferencing a node pointer */ +uword_t brothertree_find_eql(uword_t key, lispobj tree) +{ + while (tree != NIL) { + tree = follow_fp(tree); + lispobj layout = follow_fp(instance_layout(INSTANCE(tree))); + if (layout_depth2_id(LAYOUT(layout)) == BROTHERTREE_UNARY_NODE_LAYOUT_ID) { + tree = ((struct unary_node*)INSTANCE(tree))->child; + } else { + struct binary_node* node = (void*)INSTANCE(tree); + if (node->key == key) return tree; + lispobj l = NIL, r = NIL; + // unless a fringe node, read the left and right pointers + if (!fringe_node_p(node)) l = node->left, r = node->right; + if (key < node->key) tree = l; else tree = r; } } return 0; } -lispobj* find_symbol(char* symbol_name, lispobj package, unsigned int* hint) +uword_t brothertree_find_lesseql(uword_t key, lispobj tree) { - return package ? search_package_symbols(package, symbol_name, hint) : 0; + lispobj best = NIL; + while (tree != NIL) { + tree = follow_fp(tree); + lispobj layout = follow_fp(instance_layout(INSTANCE(tree))); + if (layout_depth2_id(LAYOUT(layout)) == BROTHERTREE_UNARY_NODE_LAYOUT_ID) { + tree = ((struct unary_node*)INSTANCE(tree))->child; + } else { + struct binary_node* node = (void*)INSTANCE(tree); + if (node->key == key) return tree; + lispobj l = NIL, r = NIL; + // unless a fringe node, read the left and right pointers + if (!fringe_node_p(node)) l = node->left, r = node->right; + if (key < node->key) tree = l; else { best = tree; tree = r; } + } + } + return best; } + +uword_t brothertree_find_greatereql(uword_t key, lispobj tree) +{ + lispobj best = NIL; + while (tree != NIL) { + tree = follow_fp(tree); + lispobj layout = follow_fp(instance_layout(INSTANCE(tree))); + if (layout_depth2_id(LAYOUT(layout)) == BROTHERTREE_UNARY_NODE_LAYOUT_ID) { + tree = ((struct unary_node*)INSTANCE(tree))->child; + } else { + struct binary_node* node = (void*)INSTANCE(tree); + if (node->key == key) return tree; + lispobj l = NIL, r = NIL; + // unless a fringe node, read the left and right pointers + if (!fringe_node_p(node)) l = node->left, r = node->right; + if (key > node->key) tree = r; else { best = tree; tree = l; } + } + } + return best; +} + +#define BSEARCH_ALGORITHM_IMPL \ + int low = 0; \ + int high = nelements - 1; \ + while (low <= high) { \ + /* Many authors point out that this is a bug if overflow occurs \ + * and it can be avoided by using low+(high-low)/2 or similar. \ + * But we will never have so many code blobs that overflow occurs. */ \ + int mid = (low + high) / 2; \ + uword_t probe = array[mid]; \ + if (probe < item) low = mid + 1; \ + else if (probe > item) high = mid - 1; \ + else return mid; \ + } \ + +/* Binary search a sorted vector (of code base addresses). + * This might be useful for generations other than 0, + * because we only need to rebuild the vector in GC, which is + * easily done; and it's much denser than a tree */ +int bsearch_lesseql_uword(uword_t item, uword_t* array, int nelements) +{ + BSEARCH_ALGORITHM_IMPL + if (high >= 0) return high; + return -1; +} + +int bsearch_greatereql_uword(uword_t item, uword_t* array, int nelements) +{ + BSEARCH_ALGORITHM_IMPL + if (low < nelements) return low; + return -1; +} + +#ifdef LISP_FEATURE_64_BIT +/// As above, but using space-relative pointers which halve the storage requirement +int bsearch_lesseql_uint32(uint32_t item, uint32_t* array, int nelements) +{ + BSEARCH_ALGORITHM_IMPL + if (high >= 0) return high; + return -1; +} + +int bsearch_greatereql_uint32(uint32_t item, uint32_t* array, int nelements) +{ + BSEARCH_ALGORITHM_IMPL + if (low < nelements) return low; + return -1; +} +#endif diff --git a/src/runtime/search.h b/src/runtime/search.h index 980453b72e..5405e17a3f 100644 --- a/src/runtime/search.h +++ b/src/runtime/search.h @@ -15,11 +15,14 @@ extern lispobj find_package(char*); extern lispobj* find_symbol(char*, lispobj, unsigned int*); // Find in a package extern struct symbol* lisp_symbol_from_tls_index(lispobj tls_index); -extern lispobj sb_kernel_package(); // Find via heap scan extern lispobj* search_for_symbol(char *name, lispobj start, lispobj end, boolean); lispobj *search_all_gc_spaces(void *pointer); // 'search.c' provides lispobj *search_dynamic_space(void *pointer); // Provided by 'gencgc' or 'cheneygc' lispobj *search_immobile_space(void *pointer); +int bsearch_greatereql_uword(uword_t item, uword_t* array, int nelements); +int bsearch_lesseql_uword(uword_t item, uword_t* array, int nelements); +int bsearch_greatereql_uint32(uint32_t item, uint32_t* array, int nelements); +int bsearch_lesseql_uint32(uint32_t item, uint32_t* array, int nelements); #endif diff --git a/src/runtime/sparc-arch.c b/src/runtime/sparc-arch.c index 417c6285b8..78f8aa6fa9 100644 --- a/src/runtime/sparc-arch.c +++ b/src/runtime/sparc-arch.c @@ -23,65 +23,16 @@ #include "interr.h" #include "breakpoint.h" #include "monitor.h" +#include "pseudo-atomic.h" os_vm_address_t arch_get_bad_addr(int sig, siginfo_t *code, os_context_t *context) { -#if 1 /* New way. */ return (os_vm_address_t)code->si_addr; -#else /* Old way, almost certainly predates sigaction(2)-style handlers */ - unsigned int badinst; - unsigned int *pc; - int rs1; - - pc = (unsigned int *)(*os_context_pc_addr(context)); - - /* On the sparc, we have to decode the instruction. */ - - /* Make sure it's not the pc thats bogus, and that it was lisp code */ - /* that caused the fault. */ - if ((unsigned long) pc & 3) { - /* Unaligned */ - return NULL; - } - if ((pc < READ_ONLY_SPACE_START || - pc >= READ_ONLY_SPACE_START+READ_ONLY_SPACE_SIZE) && - (pc < current_dynamic_space || - pc >= current_dynamic_space + dynamic_space_size)) { - return NULL; - } - - badinst = *pc; - - if ((badinst >> 30) != 3) - /* All load/store instructions have op = 11 (binary) */ - return 0; - - rs1 = (badinst>>14)&0x1f; - - if (badinst & (1<<13)) { - /* r[rs1] + simm(13) */ - int simm13 = badinst & 0x1fff; - - if (simm13 & (1<<12)) - simm13 |= -1<<13; - - return (os_vm_address_t) - (*os_context_register_addr(context, rs1)+simm13); - } - else { - /* r[rs1] + r[rs2] */ - int rs2 = badinst & 0x1f; - - return (os_vm_address_t) - (*os_context_register_addr(context, rs1) + - *os_context_register_addr(context, rs2)); - } -#endif } void arch_skip_instruction(os_context_t *context) { - *os_context_pc_addr(context) = *os_context_npc_addr(context); + OS_CONTEXT_PC(context) = *os_context_npc_addr(context); /* Note that we're doing integer arithmetic here, not pointer. So * the value that the return value of os_context_npc_addr() points * to will be incremented by 4, not 16. @@ -91,33 +42,22 @@ void arch_skip_instruction(os_context_t *context) unsigned char *arch_internal_error_arguments(os_context_t *context) { - return (unsigned char *)(*os_context_pc_addr(context) + 4); + return (unsigned char *)(OS_CONTEXT_PC(context) + 4); } boolean arch_pseudo_atomic_atomic(os_context_t *context) { - /* FIXME: this foreign_function_call_active test is dubious at - * best. If a foreign call is made in a pseudo atomic section - * (?) or more likely a pseudo atomic section is in a foreign - * call then an interrupt is executed immediately. Maybe it - * has to do with C code not maintaining pseudo atomic - * properly. MG - 2005-08-10 - * - * The foreign_function_call_active used to live at each call-site - * to arch_pseudo_atomic_atomic, but this seems clearer. - * --NS 2007-05-15 */ - return (!foreign_function_call_active) - && ((*os_context_register_addr(context,reg_ALLOC)) & 4); + return get_pseudo_atomic_atomic(get_sb_vm_thread()); } void arch_set_pseudo_atomic_interrupted(os_context_t *context) { - *os_context_register_addr(context,reg_ALLOC) |= 1; + set_pseudo_atomic_interrupted(get_sb_vm_thread()); } void arch_clear_pseudo_atomic_interrupted(os_context_t *context) { - *os_context_register_addr(context,reg_ALLOC) &= ~1; + clear_pseudo_atomic_interrupted(get_sb_vm_thread()); } unsigned int arch_install_breakpoint(void *pc) @@ -158,7 +98,7 @@ static unsigned int *skipped_break_addr, displaced_after_inst; void arch_do_displaced_inst(os_context_t *context, unsigned int orig_inst) { - unsigned int *pc = (unsigned int *)(*os_context_pc_addr(context)); + unsigned int *pc = (unsigned int *)OS_CONTEXT_PC(context); unsigned int *npc = (unsigned int *)(*os_context_npc_addr(context)); /* orig_sigmask = context->sigmask; @@ -175,41 +115,34 @@ void arch_do_displaced_inst(os_context_t *context, unsigned int orig_inst) } +static int is_btst_reg_self(unsigned int inst) +{ + // Refer to EMIT-FORMAT-3-REG for the bit packing. + int src1 = (inst >> 14) && 0x1f; + int src2 = (inst >> 0) && 0x1f; + /* Fix both src fields to the known value of 0x1f by ORing in a constant + * and check whether it matches BTST %rN, %rn ("bit test") + * which is the same as the ANDCC instruction. + * The constant is #b1111100000000011111 = #x7C01F + * ----- ----- + * src1 src2 + */ + return (inst | 0x7C01F) == 0x808FC01F && src1 == src2; +} + static int pseudo_atomic_trap_p(os_context_t *context) { - unsigned int* pc; - unsigned int badinst; - int result; - - - pc = (unsigned int*) *os_context_pc_addr(context); - badinst = *pc; - result = 0; - - /* Check to see if the current instruction is a pseudo-atomic-trap */ - if (((badinst >> 30) == 2) && (((badinst >> 19) & 0x3f) == 0x3a) - && (((badinst >> 13) & 1) == 1) && ((badinst & 0x7f) == PSEUDO_ATOMIC_TRAP)) - { - unsigned int previnst; - previnst = pc[-1]; - /* - * Check to see if the previous instruction was an andcc alloc-tn, - * 3, zero-tn instruction. - */ - if (((previnst >> 30) == 2) && (((previnst >> 19) & 0x3f) == 0x11) - && (((previnst >> 14) & 0x1f) == reg_ALLOC) - && (((previnst >> 25) & 0x1f) == reg_ZERO) - && (((previnst >> 13) & 1) == 1) - && ((previnst & 0x1fff) == 3)) - { - result = 1; - } - else - { - fprintf(stderr, "Oops! Got a PSEUDO-ATOMIC-TRAP without a preceeding andcc!\n"); - } - } - return result; + unsigned int* pc = (unsigned int*) OS_CONTEXT_PC(context); + + // As to the choice of bit patterns, see KLUDGE at + // (defconstant pseudo-atomic-trap) in sparc/parms.lisp + return pc[0] == +#ifdef LISP_FEATURE_LINUX + 0x93D02040 // TNE 64. pseudo-atomic-trap = #x40 +#else + 0x93D02010 // TNE 16. pseudo-atomic-trap = #x10 +#endif + && is_btst_reg_self(pc[-1]); } void @@ -221,45 +154,45 @@ arch_handle_breakpoint(os_context_t *context) void arch_handle_fun_end_breakpoint(os_context_t *context) { - *os_context_pc_addr(context) = (int) handle_fun_end_breakpoint(context); - *os_context_npc_addr(context) = *os_context_pc_addr(context) + 4; + OS_CONTEXT_PC(context) = (int) handle_fun_end_breakpoint(context); + *os_context_npc_addr(context) = OS_CONTEXT_PC(context) + 4; } void arch_handle_after_breakpoint(os_context_t *context) { *skipped_break_addr = trap_Breakpoint; - os_flush_icache(skipped_break_addr, sizeof(unsigned int)); + os_flush_icache((os_vm_address_t)skipped_break_addr, sizeof(unsigned int)); skipped_break_addr = NULL; - *(unsigned long *) os_context_pc_addr(context) = displaced_after_inst; + *(unsigned long *)OS_CONTEXT_PC(context) = displaced_after_inst; /* context->sigmask = orig_sigmask; */ - os_flush_icache((os_vm_address_t) os_context_pc_addr(context), sizeof(unsigned int)); + os_flush_icache((os_vm_address_t)OS_CONTEXT_PC(context), sizeof(unsigned int)); } void arch_handle_single_step_trap(os_context_t *context, int trap) { - unsigned int code = *((u32 *)(*os_context_pc_addr(context))); + unsigned int code = *(uint32_t *)OS_CONTEXT_PC(context); int register_offset = code >> 8 & 0x1f; handle_single_step_trap(context, trap, register_offset); arch_skip_instruction(context); } -#ifdef LISP_FEATURE_GENCGC -void -arch_handle_allocation_trap(os_context_t *context) +static void handle_allocation_trap(os_context_t *context, unsigned int *pc) { - unsigned int* pc; unsigned int or_inst; int rs1; int size; int immed; - extern void boxed_region_rollback(sword_t); + extern void mixed_region_rollback(sword_t); if (foreign_function_call_active) lose("Allocation trap inside foreign code."); - pc = (unsigned int*) *os_context_pc_addr(context); + struct thread* thread = get_sb_vm_thread(); + if (gencgc_alloc_profiler && thread->state_word.sprof_enable) + record_backtrace_from_context(context, thread); + or_inst = pc[-1]; /* @@ -267,8 +200,8 @@ arch_handle_allocation_trap(os_context_t *context) * instruction! */ if (!(((or_inst >> 30) == 2) && (((or_inst >> 19) & 0x1f) == 2))) - lose("Allocation trap not preceded by an OR instruction: 0x%08x", - or_inst); + lose("Allocation trap @ %p not preceded by an OR instruction: 0x%08x", + pc, or_inst); /* * An OR instruction. RS1 is the register we want to allocate to. @@ -282,7 +215,7 @@ arch_handle_allocation_trap(os_context_t *context) size = or_inst & 0x1fff; else size = *os_context_register_addr(context, or_inst & 0x1f); - boxed_region_rollback(size); + mixed_region_rollback(size); fake_foreign_function_call(context); @@ -290,40 +223,37 @@ arch_handle_allocation_trap(os_context_t *context) * Allocate some memory, store the memory address in rs1. */ lispobj* memory; - { - struct interrupt_data *data = - arch_os_get_current_thread()->interrupt_data; - data->allocation_trap_context = context; - extern lispobj *alloc(sword_t), *alloc_list(sword_t); - memory = (rd & 1) ? alloc_list(size) : alloc(size); - data->allocation_trap_context = 0; - } + struct interrupt_data *data = &thread_interrupt_data(thread); + data->allocation_trap_context = context; + extern lispobj *alloc(sword_t), *alloc_list(sword_t); + memory = (rd & 1) ? alloc_list(size) : alloc(size); + data->allocation_trap_context = 0; *os_context_register_addr(context, rs1) = (lispobj)memory; arch_skip_instruction(context); undo_fake_foreign_function_call(context); } -#endif static void sigill_handler(int signal, siginfo_t *siginfo, os_context_t *context) { - if ((siginfo->si_code) == ILL_ILLOPC) { + if (siginfo->si_code == ILL_ILLOPC) { int trap; unsigned int inst; unsigned int* pc = (unsigned int*) siginfo->si_addr; + if (!gc_managed_heap_space_p((lispobj)pc)) + lose("Illegal instruction not in lisp: %p [%x]\n", pc, *pc); + inst = *pc; trap = inst & 0xff; - handle_trap(context,trap); + if (trap == trap_Allocation) handle_allocation_trap(context, pc); + else handle_trap(context,trap); } - else if ((siginfo->si_code) == ILL_ILLTRP) { + else if (siginfo->si_code == ILL_ILLTRP) { if (pseudo_atomic_trap_p(context)) { - /* A trap instruction from a pseudo-atomic. We just need - to fixup up alloc-tn to remove the interrupted flag, - skip over the trap instruction, and then handle the - pending interrupt(s). */ + /* A trap instruction from a pseudo-atomic. */ arch_clear_pseudo_atomic_interrupted(context); arch_skip_instruction(context); interrupt_handle_pending(context); @@ -339,7 +269,7 @@ static void sigill_handler(int signal, siginfo_t *siginfo, void arch_install_interrupt_handlers() { - undoably_install_low_level_interrupt_handler(SIGILL, sigill_handler); + ll_install_handler(SIGILL, sigill_handler); } @@ -374,7 +304,7 @@ void arch_install_interrupt_handlers() void arch_write_linkage_table_entry(int index, void *target_addr, int datap) { - char *reloc_addr = (char*)LINKAGE_TABLE_SPACE_START + index * LINKAGE_TABLE_ENTRY_SIZE; + char *reloc_addr = (char*)ALIEN_LINKAGE_TABLE_SPACE_START + index * ALIEN_LINKAGE_TABLE_ENTRY_SIZE; if (datap) { *(unsigned long *)reloc_addr = (unsigned long)target_addr; return; @@ -390,7 +320,10 @@ arch_write_linkage_table_entry(int index, void *target_addr, int datap) * nop * */ - int* inst_ptr; + + // 'volatile' works around + // "warning: writing 4 bytes into a region of size 0 [-Wstringop-overflow=]" + volatile int* inst_ptr; unsigned long hi; /* Top 22 bits of address */ unsigned long lo; /* Low 10 bits of address */ unsigned int inst; @@ -429,3 +362,22 @@ arch_write_linkage_table_entry(int index, void *target_addr, int datap) os_flush_icache((os_vm_address_t) reloc_addr, (char*) inst_ptr - reloc_addr); } + +void +*arch_read_linkage_table_entry(int index, int datap) +{ + char *reloc_addr = (char*)ALIEN_LINKAGE_TABLE_SPACE_START + index * ALIEN_LINKAGE_TABLE_ENTRY_SIZE; + if (datap) { + return (unsigned long*) *(unsigned long *)reloc_addr; + } + + int* inst_ptr; + unsigned long hi; + unsigned long lo; + + inst_ptr = (int*) reloc_addr; + hi = *inst_ptr++ & 0x3fffff; + lo = *inst_ptr & 0x3ff; + + return (void*)(lo + (hi << 10)); +} diff --git a/src/runtime/sparc-arch.h b/src/runtime/sparc-arch.h index 8fdea43195..b75247d996 100644 --- a/src/runtime/sparc-arch.h +++ b/src/runtime/sparc-arch.h @@ -2,6 +2,5 @@ #define _SPARC_ARCH_H #define ARCH_HAS_NPC_REGISTER -#define ALIEN_STACK_GROWS_DOWNWARD #endif /* _SPARC_ARCH_H */ diff --git a/src/runtime/sparc-assem.S b/src/runtime/sparc-assem.S index ec09db0cbc..111d4985cd 100644 --- a/src/runtime/sparc-assem.S +++ b/src/runtime/sparc-assem.S @@ -5,8 +5,6 @@ #define _ASM -#include "sparc-funcdef.h" - #include "lispregs.h" #include "globals.h" #include "sbcl.h" @@ -16,18 +14,25 @@ #include "genesis/fdefn.h" #include "genesis/static-symbols.h" #include "genesis/simple-fun.h" +#include "genesis/thread.h" #define load(sym, reg) \ sethi %hi(sym), reg; ld [reg+%lo(sym)], reg #define store(reg, sym) \ sethi %hi(sym), reg_L0; st reg, [reg_L0+%lo(sym)] +#define BEGIN_PSEUDO_ATOMIC stb reg_NULL, [reg_THREAD+THREAD_PSEUDO_ATOMIC_BITS_OFFSET] +#define END_PSEUDO_ATOMIC(temp) \ + stb reg_ZERO, [reg_THREAD+THREAD_PSEUDO_ATOMIC_BITS_OFFSET] ; \ + ldub [reg_THREAD+THREAD_PSEUDO_ATOMIC_BITS_OFFSET+2], temp ; \ + andcc temp, temp, reg_ZERO ; \ + tne PSEUDO_ATOMIC_TRAP + /* FIXME */ #define FRAMESIZE 0x48 #define ST_FLUSH_WINDOWS 0x03 .seg "text" .global call_into_lisp - FUNCDEF(call_into_lisp) call_into_lisp: save %sp, -FRAMESIZE, %sp @@ -50,26 +55,23 @@ call_into_lisp: /* Establish NIL */ set NIL, reg_NULL + load(all_threads, reg_THREAD) /* Set the pseudo-atomic flag. */ - set 4, reg_ALLOC + BEGIN_PSEUDO_ATOMIC /* Turn off foreign function call. */ sethi %hi(foreign_function_call_active), reg_NL0 st reg_ZERO, [reg_NL0+%lo(foreign_function_call_active)] /* Load the rest of lisp state. */ - load(dynamic_space_free_pointer, reg_NL0) - add reg_NL0, reg_ALLOC, reg_ALLOC load(current_binding_stack_pointer, reg_BSP) load(current_control_stack_pointer, reg_CSP) load(current_control_frame_pointer, reg_OCFP) /* No longer atomic, and check for interrupt. */ - sub reg_ALLOC, 4, reg_ALLOC - andcc reg_ALLOC, 3, reg_ZERO - - tne PSEUDO_ATOMIC_TRAP + END_PSEUDO_ATOMIC(reg_NL0) + /* Pass in the args. */ sll %i2, 2, reg_NARGS mov %i1, reg_CFP @@ -102,11 +104,9 @@ lra: mov reg_A0, %i0 /* Turn on pseudo_atomic */ - add reg_ALLOC, 4, reg_ALLOC + BEGIN_PSEUDO_ATOMIC /* Store LISP state */ - andn reg_ALLOC, 7, reg_NL1 - store(reg_NL1,dynamic_space_free_pointer) store(reg_BSP,current_binding_stack_pointer) store(reg_CSP,current_control_stack_pointer) store(reg_CFP,current_control_frame_pointer) @@ -115,9 +115,7 @@ lra: store(reg_NL1,foreign_function_call_active) /* Were we interrupted? */ - sub reg_ALLOC, 4, reg_ALLOC - andcc reg_ALLOC, 3, reg_ZERO - tne PSEUDO_ATOMIC_TRAP + END_PSEUDO_ATOMIC(reg_NL1) /* Back to C we go. */ ld [%sp+FRAMESIZE-4], %i7 @@ -125,7 +123,6 @@ lra: restore %sp, FRAMESIZE, %sp .global call_into_c - FUNCDEF(call_into_c) call_into_c: /* Build a lisp stack frame */ mov reg_CFP, reg_OCFP @@ -135,7 +132,7 @@ call_into_c: st reg_CODE, [reg_CFP+8] /* Turn on pseudo-atomic. */ - add reg_ALLOC, 4, reg_ALLOC + BEGIN_PSEUDO_ATOMIC /* Convert the return address to an offset and save it on the stack. */ sub reg_LIP, reg_CODE, reg_L0 @@ -146,18 +143,12 @@ call_into_c: store(reg_BSP,current_binding_stack_pointer) store(reg_CSP,current_control_stack_pointer) store(reg_CFP,current_control_frame_pointer) - /* Use reg_CFP as a work register, and restore it */ - andn reg_ALLOC, 7, reg_CFP - store(reg_CFP,dynamic_space_free_pointer) - load(current_control_frame_pointer, reg_CFP) /* No longer in Lisp. */ store(reg_CSP,foreign_function_call_active) /* Were we interrupted? */ - sub reg_ALLOC, 4, reg_ALLOC - andcc reg_ALLOC, 3, reg_ZERO - tne PSEUDO_ATOMIC_TRAP + END_PSEUDO_ATOMIC(reg_L0) /* Into C we go. */ call reg_CFUNC @@ -171,17 +162,16 @@ call_into_c: /* Re-establish NIL */ set NIL, reg_NULL + load(all_threads, reg_THREAD) /* Atomic. */ - set 4, reg_ALLOC + BEGIN_PSEUDO_ATOMIC /* No longer in foreign function call. */ sethi %hi(foreign_function_call_active), reg_NL2 st reg_ZERO, [reg_NL2+%lo(foreign_function_call_active)] /* Load the rest of lisp state. */ - load(dynamic_space_free_pointer, reg_NL2) - add reg_NL2, reg_ALLOC, reg_ALLOC load(current_binding_stack_pointer, reg_BSP) load(current_control_stack_pointer, reg_CSP) load(current_control_frame_pointer, reg_CFP) @@ -193,9 +183,7 @@ call_into_c: sub reg_LIP, OTHER_POINTER_LOWTAG, reg_LIP /* No longer atomic. */ - sub reg_ALLOC, 4, reg_ALLOC - andcc reg_ALLOC, 3, reg_ZERO - tne PSEUDO_ATOMIC_TRAP + END_PSEUDO_ATOMIC(reg_NL2) /* Reset the lisp stack. */ /* Note: OCFP is in one of the locals, it gets preserved across C. */ @@ -219,7 +207,6 @@ call_into_c: .align 8 .global fun_end_breakpoint_guts fun_end_breakpoint_guts: - .word (((CODE_SIZE+1)&~1)<<N_WIDETAG_BITS)|RETURN_PC_WIDETAG b 1f nop mov reg_CSP, reg_OCFP @@ -242,7 +229,6 @@ fun_end_breakpoint_trap: fun_end_breakpoint_end: .global sparc_flush_icache - FUNCDEF(sparc_flush_icache) sparc_flush_icache: add %o0,%o1,%o2 1: iflush %o0 ! flush instruction cache @@ -254,14 +240,12 @@ sparc_flush_icache: nop .global do_pending_interrupt - FUNCDEF(do_pending_interrupt) do_pending_interrupt: unimp trap_PendingInterrupt retl nop .global save_context - FUNCDEF(save_context) save_context: ta ST_FLUSH_WINDOWS ! flush register windows retl ! return from leaf routine diff --git a/src/runtime/sparc-bsd-os.c b/src/runtime/sparc-bsd-os.c index 3d21d9f803..ca4159e9e7 100644 --- a/src/runtime/sparc-bsd-os.c +++ b/src/runtime/sparc-bsd-os.c @@ -25,8 +25,6 @@ #include "interrupt.h" #include "interr.h" #include "lispregs.h" -#include <sys/socket.h> -#include <sys/utsname.h> #include <sys/types.h> #include <signal.h> @@ -66,12 +64,6 @@ os_context_register_addr(os_context_t *context, int offset) } } -os_context_register_t * -os_context_pc_addr(os_context_t *context) -{ - return &(context->uc_mcontext.__gregs[_REG_PC]); -} - os_context_register_t * os_context_npc_addr(os_context_t *context) { diff --git a/src/runtime/sparc-bsd-os.h b/src/runtime/sparc-bsd-os.h index a3d393b5d8..1bdb72fe55 100644 --- a/src/runtime/sparc-bsd-os.h +++ b/src/runtime/sparc-bsd-os.h @@ -8,4 +8,6 @@ static inline os_context_t *arch_os_get_context(void **void_context) { return (os_context_t *) (*void_context); } +#define OS_CONTEXT_PC(context) context->uc_mcontext.__gregs[_REG_PC] + #endif /* _SPARC_BSD_OS_H */ diff --git a/src/runtime/sparc-linux-os.c b/src/runtime/sparc-linux-os.c index 3b8d41ebd4..069fecbd4e 100644 --- a/src/runtime/sparc-linux-os.c +++ b/src/runtime/sparc-linux-os.c @@ -25,8 +25,6 @@ #include "interrupt.h" #include "interr.h" #include "lispregs.h" -#include <sys/socket.h> -#include <sys/utsname.h> #include <sys/types.h> #include <signal.h> @@ -53,22 +51,16 @@ os_context_register_addr(os_context_t *context, int offset) if (offset == 0) { static int zero; zero = 0; - return &zero; + return (os_context_register_t*)&zero; } else if (offset < 16) { return &context->si_regs.u_regs[offset]; } else if (offset < 32) { - int *sp = (int*) context->si_regs.u_regs[14]; /* Stack Pointer */ + unsigned int *sp = (unsigned int*) context->si_regs.u_regs[14]; /* Stack Pointer */ return &(sp[offset-16]); } else return 0; } -os_context_register_t * -os_context_pc_addr(os_context_t *context) -{ - return &(context->si_regs.pc); -} - os_context_register_t * os_context_npc_addr(os_context_t *context) { @@ -78,7 +70,7 @@ os_context_npc_addr(os_context_t *context) sigset_t * os_context_sigmask_addr(os_context_t *context) { - return &(context->si_mask); + return (sigset_t*)&(context->si_mask); } void @@ -99,5 +91,6 @@ void os_flush_icache(os_vm_address_t address, os_vm_size_t length) { /* This is the same for linux and solaris, so see sparc-assem.S */ + extern void sparc_flush_icache(os_vm_address_t,os_vm_size_t); sparc_flush_icache(address,length); } diff --git a/src/runtime/sparc-linux-os.h b/src/runtime/sparc-linux-os.h index 5c02fc663d..f544569df7 100644 --- a/src/runtime/sparc-linux-os.h +++ b/src/runtime/sparc-linux-os.h @@ -2,7 +2,7 @@ #define _SPARC_LINUX_OS_H typedef struct sigcontext os_context_t; -typedef unsigned long os_context_register_t; +typedef unsigned int os_context_register_t; static inline os_context_t *arch_os_get_context(void **void_context) { @@ -13,4 +13,6 @@ static inline os_context_t *arch_os_get_context(void **void_context) unsigned long os_context_fp_control(os_context_t *context); void os_restore_fp_control(os_context_t *context); +#define OS_CONTEXT_PC(context) context->si_regs.pc + #endif /* _SPARC_LINUX_OS_H */ diff --git a/src/runtime/sparc-lispregs.h b/src/runtime/sparc-lispregs.h index aaa65ef09a..91c57e941c 100644 --- a/src/runtime/sparc-lispregs.h +++ b/src/runtime/sparc-lispregs.h @@ -28,7 +28,7 @@ #endif #define reg_ZERO GREG(0) -#define reg_ALLOC GREG(1) +#define reg_THREAD GREG(1) #define reg_NULL GREG(2) #define reg_CSP GREG(3) #define reg_CFP GREG(4) diff --git a/src/runtime/sparc-sunos-os.c b/src/runtime/sparc-sunos-os.c index fc76ee7931..d621afc2f3 100644 --- a/src/runtime/sparc-sunos-os.c +++ b/src/runtime/sparc-sunos-os.c @@ -25,8 +25,6 @@ #include "interrupt.h" #include "interr.h" #include "lispregs.h" -#include <sys/socket.h> -#include <sys/utsname.h> #include <sys/types.h> #include <signal.h> @@ -66,12 +64,6 @@ os_context_register_addr(os_context_t *context, int offset) } } -os_context_register_t * -os_context_pc_addr(os_context_t *context) -{ - return &(context->uc_mcontext.gregs[REG_PC]); -} - os_context_register_t * os_context_npc_addr(os_context_t *context) { diff --git a/src/runtime/sparc-sunos-os.h b/src/runtime/sparc-sunos-os.h index 3c72cb33dd..7cc635e2ad 100644 --- a/src/runtime/sparc-sunos-os.h +++ b/src/runtime/sparc-sunos-os.h @@ -10,4 +10,6 @@ static inline os_context_t *arch_os_get_context(void **void_context) return (os_context_t *) (*void_context); } +#define OS_CONTEXT_PC(context) context->uc_mcontext.gregs[REG_PC] + #endif /* _SPARC_SOLARIS_OS_H */ diff --git a/src/runtime/sprof.c b/src/runtime/sprof.c new file mode 100644 index 0000000000..d00fbb945b --- /dev/null +++ b/src/runtime/sprof.c @@ -0,0 +1,575 @@ +#include <signal.h> +#include <stdio.h> +#include <errno.h> +#include "thread.h" +#include "murmur_hash.h" +#include "gc-assert.h" +#include "arch.h" // why is component_ptr_from_pc declared here??? +#include "gc-internal.h" +#include "gc.h" +#include "lispregs.h" +#if !defined LISP_FEATURE_X86 && !defined LISP_FEATURE_X86_64 +#include "callframe.inc" +#endif +#include "genesis/compiled-debug-fun.h" + +#ifdef MEMORY_SANITIZER +#include <sanitizer/msan_interface.h> +#endif + +#include <limits.h> +#include <fcntl.h> +#include <unistd.h> +/* Basic approach: + * each thread allocates a storage for samples (traces) and a hash-table + * to groups matching samples together. Collisions in the table are resolved + * by chaining. + * + * At each sample collection: + * 1. gather up to TRACE_BUFFER_LEN program-counter locations as the stack trace + * 2. if it exceeds MAX_RECORDED_TRACE_LEN locations, condense it to + the first and last frames with an elision marker in between. + * 3. compute a hash of the trace + * 4. if trace is present in hash-table + * then increment the count + * else + * ensure trace has stable PC locations + * add or update + * Each PC location is tentatively recorded as raw PC location. + * To ensure location stability: + * Check whether each raw PC loc is within lisp code and not pseudostatic. + * For each which is movable, express the PC as a code serial# and offset. + */ + +#define ELEMENT_SIZE 8 + +#define TRACE_BUFFER_LEN 300 +#define MAX_RECORDED_TRACE_LEN 62 +#define N_BUCKETS 0x10000 +#define HASH_MASK (N_BUCKETS-1) +#ifdef LISP_FEATURE_64_BIT + // Disable sampling if buffer has grown to 8 million elements, which is 64MiB. + // This is enough to store 128k traces if each trace has its maximum of 62 frames + // which most of them won't. ((62+2) * 8 * 128 * 1024) = 64MiB +# define CAPACITY_MAX 8*1024*1024 +#else + // Disable sampling if buffer has grown to 1 million elements, which is 8MiB. +# define CAPACITY_MAX 1024*1024 +#endif +#define INITIAL_FREE_POINTER 2 + +// Lisp and C both accesses this. +// The structure is 2 elements long, each element being 8 bytes. +struct sprof_data { + // Element 0 + uint32_t *buckets; // power-of-2-sized bucket array +#ifndef LISP_FEATURE_64_BIT + uint32_t padding0; +#endif + // Element 1 + // index into next available element of trace_buffer. + // elements are always 8 bytes regardless of machine word size. + uint32_t free_pointer; + uint32_t capacity; +}; + +// Number of elements that are not part of the locs[] array. +// An 'element' is 8 bytes. +#define TRACE_PREFIX_ELEMENTS 2 +struct trace { + uint32_t next; // next trace with identical hash + uint32_t multiplicity; // number of times hit +#ifdef LISP_FEATURE_64_BIT +#define trace_len(trace) ((int32_t)((trace)->header)) + uword_t header; // upper 32 bits are hash val, lower 32 are length + // each entry has the most-significant-bit on if the value represents + // <code-serial#, pc-offset> in the high and low 4 byte. + // If it's just an address, the uppermost bit is clear. + // As far as I know, no architecture will have code as such a large + // addresses as to make the representation ambiguous. + uword_t locs[TRACE_BUFFER_LEN]; +#else +#define trace_len(trace) trace->len + sword_t len; + uword_t hash; + // One entry is 2 lispwords. If word1 is 0, then word0 is a PC. + // Otherwise word0 is the code serial# and word1 is the pc offset. + // This could probably be reduced to 6 bytes per element by using 3 bytes to store + // a serial# and 3 bytes to store the offset within code. + // But then there would be access alignment issues to worry about. + struct loc { uint32_t word0, word1; } locs[TRACE_BUFFER_LEN]; +#endif +}; + +static inline struct trace* sprof_data_trace(struct sprof_data* data, uint32_t index) { + return (void*)((char*)data + index*ELEMENT_SIZE); +} + +static int in_stack_range(uword_t pc, struct thread* thread) +{ + return pc >= (uword_t)thread->control_stack_start + && pc < (uword_t)thread->control_stack_end; +} + +// Use the WORD-MIX algorithm from src/code/string-hash +static inline uword_t word_mix(uword_t x, uword_t y) +{ + uword_t mul = 3622009729038463111LL & UINT_MAX; + uword_t xor = 608948948376289905LL & UINT_MAX; + sword_t xy = x * mul + y; + return xor ^ xy ^ (xy >> 5); +} + +#ifdef LISP_FEATURE_64_BIT +static uint32_t compute_hash(uword_t* elements, int len) { + int i; + uword_t hash = len; + for (i = 0; i < len; i++) { + uword_t pc = elements[i]; + hash = word_mix(hash, pc); + } + return (uint32_t)murmur3_fmix64(hash); +} +#else +static uint32_t compute_hash(struct loc* elements, int len) { + int i; + uword_t hash = len; + for (i = 0; i < len; i++) { + uword_t pc = elements[i].word0; // this is either a PC or the code serial# + hash = word_mix(hash, pc); + } + return murmur3_fmix32(hash); +} +#endif + +static inline void store_trace_header(struct trace* trace, uint32_t hash, uint32_t len) +{ +#ifdef LISP_FEATURE_64_BIT + trace->header = ((uword_t)hash<<32) | len; +#else + trace->hash = hash; + trace->len = len; +#endif +} + +static int trace_equal(struct trace* a, struct trace* b) +{ + int i; +#ifdef LISP_FEATURE_64_BIT + if (a->header != b->header) return 0; + for (i=0; i<trace_len(a); ++i) if (a->locs[i] != b->locs[i]) return 0; +#else + if (a->hash != b->hash || a->len != b->len) return 0; + for (i=0; i<trace_len(a); ++i) + if (a->locs[i].word0 != b->locs[i].word0 || + a->locs[i].word1 != b->locs[i].word1) return 0; +#endif + return 1; +} + +static uint32_t* hash_get(struct sprof_data* data, struct trace* trace, uint32_t hash) +{ + int index = hash & HASH_MASK; + uint32_t entry = data->buckets[index]; + while (entry) { + struct trace* key = sprof_data_trace(data, entry); + if (trace_equal(key, trace)) return &key->multiplicity; + entry = key->next; + } + return 0; +} + +static uint32_t* hash_insert(struct sprof_data* data, struct trace* trace, uint32_t hash) +{ + // allocate a permanent copy. +2 is for the fixed overhead elements + int n_elements = TRACE_PREFIX_ELEMENTS + trace_len(trace); + struct trace* copy = sprof_data_trace(data, data->free_pointer); + memcpy(copy, trace, n_elements * ELEMENT_SIZE); + copy->multiplicity = 0; + // insert into chain for this hash + int index = hash & HASH_MASK; + copy->next = data->buckets[index]; + data->buckets[index] = data->free_pointer; + // consume the buffer elements + data->free_pointer += n_elements; + return ©->multiplicity; +} + +static int unstable_program_counter_p(uword_t addr) +{ +#ifdef LISP_FEATURE_CHENEYGC + return (DYNAMIC_0_SPACE_START <= addr && + addr < DYNAMIC_0_SPACE_START + dynamic_space_size) + || (DYNAMIC_1_SPACE_START <= addr && + addr < DYNAMIC_1_SPACE_START + dynamic_space_size); +#else + /* I think that it's a reasonable assumption that code in immobile + * space will not be garbage-collected during the profiling run. + * Similar issue for fdefns which contain an executable instruction + * as well as closure-calling trampolines and builtin-trampoline GFs. + * It might be neat to mark some objects with a bit saying + * never to move them if they appeared in a trace. + * When would the bit get cleared though? I don't know */ + page_index_t page = find_page_index((void*)addr); + return page >= 0 && page_table[page].gen != PSEUDO_STATIC_GENERATION; +#endif +} + +#ifdef LISP_FEATURE_64_BIT +#define STORE_PC(tr, indx, val) (tr).locs[indx] = val +#define STORE_REL_PC(tr, indx, ser, offs) \ + (tr).locs[indx] = ((uword_t)1 << 63) | ((offs) << 32) | (ser) +#else +#define STORE_PC(tr, indx, val) (tr).locs[indx].word0 = val; (tr).locs[indx].word1 = 0 +#define STORE_REL_PC(tr, indx, ser, offs) \ + (tr).locs[indx].word0 = ser; (tr).locs[indx].word1 = offs +#endif + +/* Represent 'trace' using code_serialno + offset for some PC locations. + * Locations in foreign and pseudo-static code may remain as-is. + * Return 1 if the trace was affected by stabilizing it. */ +static int NO_SANITIZE_MEMORY stabilize(struct trace* trace) +{ + int len = trace_len(trace); + int changedp = 0; + int i; + uword_t pc; + for(i=0; i<len; ++i) { +#ifdef LISP_FEATURE_64_BIT + pc = trace->locs[i]; +#else + pc = trace->locs[i].word0; +#endif + if (unstable_program_counter_p(pc)) { + struct code *code = (void*)component_ptr_from_pc((char*)pc); + if (code) { + STORE_REL_PC(*trace, i, code_serialno(code), (pc - (uword_t)code)); + changedp = 1; + } else { + // Can't have any unstable locations in the result + STORE_PC(*trace, i, (uword_t)-1); + } + } + } + return changedp; +} + +static int NO_SANITIZE_MEMORY +gather_trace_from_context(struct thread* thread, os_context_t* context, + struct trace* trace, int limit) +{ + uword_t pc = os_context_pc(context); + int len = 1; + STORE_PC(*trace, 0, pc); +#if defined LISP_FEATURE_X86 || defined LISP_FEATURE_X86_64 + uword_t* fp = (uword_t*)os_context_frame_pointer(context); + uword_t* sp = (uword_t*)*os_context_sp_addr(context); + if (fp >= sp && fp < thread->control_stack_end) { // plausible frame-pointer + // TODO: This should be replaced with more sophisticated backtrace routine + // that understands foreign code compiled without frame pointers. + // It's no different from what we have now though. + for(;;) { + uword_t prev_fp = *fp; + uword_t prev_pc = fp[1]; +#ifdef LISP_FEATURE_64_BIT + // If this can't possibly be a valid program counter, + // change it to the "unknown" value. + if ((sword_t)prev_pc < 0) prev_pc = (sword_t)-1; +#endif + STORE_PC(*trace, len, prev_pc); + if (++len == limit) break; + // Ensure that the next FP and PC are reasonable. + if (prev_fp <= (uword_t)fp || prev_fp >= (uword_t)thread->control_stack_end + || in_stack_range(prev_pc, thread)) break; + fp = (uword_t*)prev_fp; + } + } +#else + if (gc_managed_heap_space_p(pc) && component_ptr_from_pc((void*)pc)) { + // If the PC was in lisp code, then the frame register is probably correct, + // and so it's probably the case that 'frame->saved_lra' is a tagged PC + // in the caller. Unfortunately it is not 100% reliable in a signal handler, + // so we don't try to walk back more than one frame. + struct call_frame* frame = (void*)(*os_context_register_addr(context, reg_CFP)); + if (in_stack_range((uword_t)frame, thread) + && lowtag_of(frame->saved_lra) == OTHER_POINTER_LOWTAG + && component_ptr_from_pc((void*)frame->saved_lra)) { + STORE_PC(*trace, len, frame->saved_lra); + ++len; + } + } +#endif + return len; +} + +extern struct compiled_debug_fun* +debug_function_from_pc (struct code* code, void *pc); + +static int gather_trace_from_frame(struct thread* thread, uword_t* fp, + struct trace* trace, int limit) +{ + int len = 0; + +#if defined LISP_FEATURE_X86 || defined LISP_FEATURE_X86_64 + if (fp >= thread->control_stack_start && fp < thread->control_stack_end) { + for(;;) { + uword_t prev_fp = *fp; + uword_t prev_pc = fp[1]; +#ifdef LISP_FEATURE_64_BIT + // If this can't possibly be a valid program counter, + // change it to the "unknown" value. + if ((sword_t)prev_pc < 0) prev_pc = (sword_t)-1; +#endif + STORE_PC(*trace, len, prev_pc); + if (++len == limit) break; + // Ensure that the next FP and PC are reasonable. + if (prev_fp <= (uword_t)fp || prev_fp >= (uword_t)thread->control_stack_end + || in_stack_range(prev_pc, thread)) break; + fp = (uword_t*)prev_fp; + } + } +#else + struct call_info info; + memset(&info, 0, sizeof info); + info.frame = (struct call_frame *)access_control_frame_pointer(thread); + // Only try to step 2 frames because anything more and we may randomly crash. + // If you don't believe this claim, then just try inserting a lisp_backtrace(20) + // into the start of lisp_alloc() and watch that about half the time + // you get a nice backtrace, and half the time you get a crash. + if (lisp_frame_previous(thread, &info) && info.code) { + struct compiled_debug_fun *df; + df = (void*)debug_function_from_pc((struct code *)info.code, + (void*)((uword_t)info.code + info.pc)); + if (df) { + STORE_PC(*trace, 0, (uword_t)info.code + info.pc); + ++len; + if (lisp_frame_previous(thread, &info) && info.code) { + STORE_PC(*trace, 0, (uword_t)info.code + info.pc); + ++len; + } + } + } +#endif + return len; +} + +#define LOCKED_BY_SELF 1 +#define LOCKED_BY_OTHER 2 +#define LOCK_CONTESTED (LOCKED_BY_SELF|LOCKED_BY_OTHER) + +static void* initialize_sprof_data(struct thread* thread) +{ + void* buckets = (void*)os_allocate(N_BUCKETS * sizeof (uint32_t)); + if (!buckets) return 0; + int capacity = 128*1024; // arbitrary starting size for traces, 128K elements = 1MiB + struct sprof_data *data = (void*)os_allocate(capacity * ELEMENT_SIZE); + if (!data) { os_deallocate(buckets, N_BUCKETS * sizeof (uint32_t)); return 0; } + data->capacity = capacity; + data->free_pointer = INITIAL_FREE_POINTER; // next available element + data->buckets = buckets; + thread->sprof_data = (lispobj)data; + return data; +} + +static struct sprof_data* enlarge_buffer(struct sprof_data* current, + uint32_t new_capacity) +{ + char * new_buffer = os_allocate(new_capacity * ELEMENT_SIZE); + memcpy(new_buffer, current, current->free_pointer * ELEMENT_SIZE); + os_deallocate((void*)current, current->capacity * ELEMENT_SIZE); + current = (struct sprof_data*)new_buffer; + current->capacity = new_capacity; + return current; +} + +#define SPROF_LOCK(th) thread_extra_data(th)->sprof_lock + +#ifdef LISP_FEATURE_SB_THREAD +/* If this thread acquired an uncontested lock (old == LOCKED_BY_SELF), release it. + * If this thread didn't acquire the lock (old == 0 or old == 2), do nothing. + * The only interesting case is LOCK_CONTESTED */ +#define RELEASE_LOCK(th) \ + int oldval = __sync_val_compare_and_swap(&SPROF_LOCK(th), LOCKED_BY_SELF, 0); \ + if (oldval == LOCK_CONTESTED) { \ + oldval = __sync_val_compare_and_swap(&SPROF_LOCK(th), LOCK_CONTESTED, LOCKED_BY_OTHER); \ + gc_assert(oldval == LOCK_CONTESTED); \ + os_sem_post(&thread_extra_data(th)->sprof_sem, "sprof"); \ + } +#else +#define RELEASE_LOCK(th) SPROF_LOCK(th) = 0 +#endif + +int sb_sprof_trace_ct; +int sb_sprof_trace_ct_max; + +/* this could get false msan positives because Lisp don't mark stack words as clean + so anything may appear as unwritten from C depending on whether any C code + ever marked them. So it was basically down to luck whether this worked or not */ +static int NO_SANITIZE_MEMORY +collect_backtrace(struct thread* th, int contextp, void* context_or_fp) +{ + int oldcount = __sync_fetch_and_add(&sb_sprof_trace_ct, 1); + if (oldcount >= sb_sprof_trace_ct_max) { + __sync_fetch_and_sub(&sb_sprof_trace_ct, 1); + return -1; // sample limit exceeded + } + struct trace trace; + int len; + if (contextp) + len = gather_trace_from_context(th, context_or_fp, &trace, TRACE_BUFFER_LEN); + else + len = gather_trace_from_frame(th, context_or_fp, &trace, TRACE_BUFFER_LEN); + if (len < 1) return len; + if (len > MAX_RECORDED_TRACE_LEN) { + // change excessively long trace to "hot_end ... elision_marker ... cold_end" + int midpoint = MAX_RECORDED_TRACE_LEN/2; + int suffix = midpoint-1; + STORE_PC(trace, midpoint, (uword_t)-1); + memmove(&trace.locs[midpoint+1], &trace.locs[len-suffix], N_WORD_BYTES*suffix); + len = MAX_RECORDED_TRACE_LEN; + } + // Hash before trying to insert so that potentially the conversion of unstable + // PCs to stable PCs can be skipped, if there is a hash match. + uword_t hash = compute_hash(trace.locs, len); + store_trace_header(&trace, hash, len); + + // Try to acquire the lock + if (__sync_val_compare_and_swap(&SPROF_LOCK(th), 0, LOCKED_BY_SELF)!=0) + return -2; // already locked + + struct sprof_data* data = (void*)th->sprof_data; + if (!data) data = initialize_sprof_data(th); + uint32_t* pcount; + if ((pcount = hash_get(data, &trace, hash)) == NULL) { + if (stabilize(&trace)) { // changed ? + hash = compute_hash(trace.locs, len); // revise the hash + store_trace_header(&trace, hash, len); + pcount = hash_get(data, &trace, hash); + } + if (!pcount) { // still not found, insert it + uint32_t n_elements = TRACE_PREFIX_ELEMENTS + len; + uint32_t capacity = data->capacity; + if (data->free_pointer + n_elements > capacity) { + // If we're at maximum capacity, bail out + if (capacity == CAPACITY_MAX) return 0; + // Before enlarging the buffer, check whether anyone is trying + // to read it; if so, just bail out. + // This is not to avoid a race - that's taken care of by the + // cmpxchg - but it's preferable to drop the current sample + // versus make a bunch more system call while there is a waiter. + if (SPROF_LOCK(th) & LOCKED_BY_OTHER) return 0; + data = enlarge_buffer(data, 2*capacity); + th->sprof_data = (lispobj)data; + } + pcount = hash_insert(data, &trace, hash); + } + } + ++*pcount; + return 1; +} + +static void diagnose_failure(struct thread* thread) { + // MAX-SAMPLES bounds the memory growth within a constant factor for one thread, + // but if multithreaded, each thread could allocate a buffer and grow it an + // arbitrary number of times. The automatic disable tries to avoid an explosion + // in memory consumption. + struct sprof_data* data = (void*)thread->sprof_data; + if (data && data->capacity == CAPACITY_MAX) { + // disable the profiler in this thread + thread->state_word.sprof_enable = 0; +#ifdef LISP_FEATURE_SB_THREAD + char msg[100]; + int msglen = sprintf(msg, + "WARNING: pthread %p disabled sprof sampler to limit memory use\n", + (void*)pthread_self()); + ignore_value(write(2, msg, msglen)); +#endif + } +} + +void record_backtrace_from_context(void *context, struct thread* thread) { + int success = collect_backtrace(thread, 1, context) == 1; + // Release the lock. This synchronizes with acquire_sprof_data_lock() + // which atomically adds LOCKED_BY_OTHER to the lock field. + // If that happens first, then the cmpxchg will fail, and we'll do + // a sem_post here. If this happens first, then the thread wishing to + // acquire the data will see that 'old' is 0, and it will be happy. + RELEASE_LOCK(thread); + if (!success) diagnose_failure(thread); +} + +/* The SIGPROF handler. This used to be deferrable via the can_handle_now_test() + * check in interrupt.c, which would return false during GC, because Lisp binds + * *INTERRUPTS-ENABLED* to NIL in the thread which performs the GC; and all other + * threads are in their stop_for_gc handler which blocks async signals including + * SIGPROF, as per the sa_mask in the sigaction() call that assigned the handler. + * But now that SIGPROF is never deferred, we have to be careful around GC. + * There's a complicated solution and an easy solution. The complicated is to have + * component_ptr_from_pc() fail safely if called, so that taking a sample is fine + * provided that all PC locations are pseudo-static - in that case we do not use + * component_ptr_from_pc() in the signal handler. + * The easy out is just to drop the sample; so that's what we do, and versus + * blocking/unblocking SIGPROF in collect_garbage(), it avoids 2 system calls. */ +void sigprof_handler(int sig, __attribute__((unused)) siginfo_t* info, + void *context) +{ + if (gc_active_p) return; // no mem barrier needed to read this + int _saved_errno = errno; + struct thread* thread = get_sb_vm_thread(); + // We can only profile Lisp threads. + if (thread) { + if (thread->state_word.sprof_enable) + record_backtrace_from_context(context, thread); + else + // Block further signals it on return from the handler. + // This won't actually work if there are nested handlers on the stack, + // but that's OK, we'll just try again to block it if it occurs. + sigaddset(os_context_sigmask_addr(context), sig); + } + errno = _saved_errno; +} + +#if !(defined LISP_FEATURE_PPC || defined LISP_FEATURE_PPC64 || defined LISP_FEATURE_SPARC) +void allocator_record_backtrace(void* frame_ptr, struct thread* thread) +{ + int success = collect_backtrace(thread, 0, frame_ptr) == 1; + RELEASE_LOCK(thread); + if (!success) diagnose_failure(thread); +} +#endif + +/// Ensuring mutual exclusivity with the SIGPROF handler, +/// return the profiling data for 'thread', or 0 if none. +uword_t acquire_sprof_data(struct thread* thread) +{ + int old = __sync_fetch_and_or(&SPROF_LOCK(thread), LOCKED_BY_OTHER); +#ifdef LISP_FEATURE_SB_THREAD + if (old != 0) { + gc_assert(old == LOCKED_BY_SELF); // could not be LOCKED_BY_OTHER + // A profiled thread will sem_post() on return from its profiling signal handler + // if it observes that both lock bits were on. + // This should be called with the thread's interruption mutex held so that the thread + // whose data are being acquired can't exit and delete its sprof_sem. + os_sem_wait(&thread_extra_data(thread)->sprof_sem, "sprof"); + gc_assert(SPROF_LOCK(thread) == LOCKED_BY_OTHER); + } +#else + gc_assert(old == 0); +#endif + // sync cas prevents reading before setting the lock + uword_t retval = __sync_val_compare_and_swap(&thread->sprof_data, 0, 0); + // if data were allocated, then set the field to 0 + if (retval) { + __sync_val_compare_and_swap(&thread->sprof_data, retval, 0); +#ifdef MEMORY_SANITIZER + // Traces were recorded with the sanitizer disabled, so we either need to + // read the memory from lisp in SAFETY 0 which disables UNINITIALIZED-LOAD-TRAP, + // or simply mark the memory as clean. + int freeptr = ((struct sprof_data*)retval)->free_pointer; + __msan_unpoison((void*)retval, freeptr * ELEMENT_SIZE); +#endif + } + __sync_fetch_and_and(&SPROF_LOCK(thread), 0); + // This this thread owns that thread's data. ('This' and 'that' could be the same) + return retval; +} diff --git a/src/runtime/stringspace.c b/src/runtime/stringspace.c new file mode 100644 index 0000000000..9ec1416a0c --- /dev/null +++ b/src/runtime/stringspace.c @@ -0,0 +1,334 @@ +/* + * This software is part of the SBCL system. See the README file for + * more information. + * + * This software is derived from the CMU CL system, which was + * written at Carnegie Mellon University and released into the + * public domain. The software is in the public domain and is + * provided with absolutely no warranty. See the COPYING and CREDITS + * files for more information. + */ + +#include "gc-internal.h" +#include "gc-private.h" +#include "gencgc-private.h" +#include "genesis/gc-tables.h" +#include "globals.h" +#include "forwarding-ptr.h" +#include <stdio.h> +#include <stdlib.h> + +#ifdef LISP_FEATURE_DARWIN_JIT + +void prepare_readonly_space(__attribute__((unused)) int purify, + __attribute__((unused)) int print) {} +void move_rospace_to_dynamic(__attribute__((unused)) int print) {} + +#else + +/* This visitor is mostly like all the others, but only bothers with words that + * can possibly be adjusted to point to or from readonly space. + * So there's no dealing with fdefns at all, or closure-fun, funcallable-instance-fun, + * or a few other things. */ +static void visit_pointer_words(lispobj* object, lispobj (*func)(lispobj, uword_t), uword_t arg) +{ +#define FIX(what) { lispobj ptr = what; \ + if (is_lisp_pointer(ptr)) { lispobj new = func(ptr, arg); if (new != ptr) what = new; } } + + if (is_cons_half(*object)) { + FIX(object[0]); + FIX(object[1]); + return; + } + int widetag = widetag_of(object); + if (leaf_obj_widetag_p(widetag)) return; + if (instanceoid_widetag_p(widetag)) { + lispobj layout = layout_of(object); + if (layout) { + struct bitmap bitmap = get_layout_bitmap(LAYOUT(layout)); + int nslots = instanceoid_length(*object), i; + for (i=0; i<nslots; ++i) if (bitmap_logbitp(i, bitmap)) FIX(object[i+1]); + } + } else if (widetag == SIMPLE_VECTOR_WIDETAG) { + struct vector* v = (void*)object; + sword_t len = vector_len(v), i; + int rehash = 0; + for (i=0; i<len; ++i) { + lispobj old = v->data[i]; + if (!is_lisp_pointer(old)) continue; + lispobj new = func(old, arg); + if (new != old) v->data[i] = new, rehash = 1; + } + // The 'rehash' bit on address-sensitive hashing vectors needs to be set if + // an address-sensitive key moved, because it won't move again in final GC. + if (vector_flagp(*object, VectorAddrHashing) && rehash) v->data[1] = make_fixnum(1); + } else if (widetag == SYMBOL_WIDETAG) { + struct symbol*s = (void*)object; + FIX(s->value); + FIX(s->info); + lispobj name = decode_symbol_name(s->name); + gc_assert(is_lisp_pointer(name)); + set_symbol_name(s, func(name, arg)); + } else if (widetag == CODE_HEADER_WIDETAG) { + int boxedlen = code_header_words((struct code*)object), i; + // first 4 slots are header, boxedlen, fixups, debuginfo + for (i=2; i<boxedlen; ++i) FIX(object[i]); + } else { + int len = object_size(object), i; + for (i=1; i<len; ++i) FIX(object[i]); + } +#undef FIX +} + +static int readonly_unboxed_obj_p(lispobj* obj) +{ + if (is_cons_half(*obj)) return 0; + int widetag = widetag_of(obj); + switch (widetag) { + case BIGNUM_WIDETAG: case DOUBLE_FLOAT_WIDETAG: + case COMPLEX_SINGLE_FLOAT_WIDETAG: case COMPLEX_DOUBLE_FLOAT_WIDETAG: + case SAP_WIDETAG: case SIMPLE_ARRAY_NIL_WIDETAG: + return 1; + case RATIO_WIDETAG: case COMPLEX_WIDETAG: + return fixnump(obj[1]) && fixnump(obj[2]); +#ifdef LISP_FEATURE_SIMD_PACK + case SIMD_PACK_WIDETAG: +#endif + } + if ((widetag > SIMPLE_VECTOR_WIDETAG && widetag < COMPLEX_BASE_STRING_WIDETAG)) { + if (!vector_len((struct vector*)obj)) return 1; // length 0 vectors can't be stored into + // any vector marked shareable is a winner + if (*obj & (VECTOR_SHAREABLE|VECTOR_SHAREABLE_NONSTD)<<ARRAY_FLAGS_POSITION) return 1; + } + if (widetag == SIMPLE_VECTOR_WIDETAG) { + struct vector*v = (void*)obj; + sword_t length = vector_len(v); + if (!length) return 1; // length 0 vectors can't be stored into + if (*obj & (VECTOR_SHAREABLE|VECTOR_SHAREABLE_NONSTD)<<ARRAY_FLAGS_POSITION) { + // If every element is non-pointer, then it can go in readonly space + sword_t i; + for (i=0; i<length; ++i) + if (v->data[i] != NIL && is_lisp_pointer(v->data[i])) return 0; + return 1; + } + } + return 0; +} + +// CAUTION: don't think you can use this generally. It can only compute sizes +// of objects that do not change when forwarded. Instances can grow when forwarded +// by gencgc due to adding a stable hash slot. +static sword_t careful_object_size(lispobj* obj) { + return object_size(forwarding_pointer_p(obj) + ? native_pointer(forwarding_pointer_value(obj)) + : obj); +} + +static void walk_range(lispobj* start, lispobj* end, void (*func)(lispobj*,uword_t), uword_t arg) +{ + lispobj* where = start; + for ( ; where < end ; where += careful_object_size(where) ) func(where, arg); +} + +static void walk_all_spaces(void (*fun)(lispobj*,uword_t), uword_t arg) +{ + walk_range((lispobj*)NIL_SYMBOL_SLOTS_START, (lispobj*)NIL_SYMBOL_SLOTS_END, fun, arg); + walk_range((lispobj*)STATIC_SPACE_OBJECTS_START, static_space_free_pointer, fun, arg); +#ifdef LISP_FEATURE_IMMOBILE_SPACE + walk_range((lispobj*)FIXEDOBJ_SPACE_START, fixedobj_free_pointer, fun, arg); + walk_range((lispobj*)TEXT_SPACE_START, text_space_highwatermark, fun, arg); +#endif + page_index_t first, last; + for ( first = 0 ; first < next_free_page ; first = 1+last ) { + last = contiguous_block_final_page(first); + walk_range((lispobj*)page_address(first), + (lispobj*)page_address(last) + page_words_used(last), + fun, arg); + } +} + +static void ensure_forwarded(lispobj* obj) +{ + if (forwarding_pointer_p(obj)) return; + int nwords = object_size(obj); + lispobj* copy = read_only_space_free_pointer; + read_only_space_free_pointer += nwords; + gc_assert((uword_t)read_only_space_free_pointer <= READ_ONLY_SPACE_END); + memcpy(copy, obj, nwords << WORD_SHIFT); + set_forwarding_pointer(obj, make_lispobj(copy, OTHER_POINTER_LOWTAG)); +} + +// We have to take the unused arg for function signature compatibility. +// Lambdas in C are so crappy. +static void ensure_symbol_name_forwarded(lispobj* obj, + __attribute__((unused)) uword_t arg) { + if (widetag_of(obj) == SYMBOL_WIDETAG) { + struct symbol* s = (void*)obj; + ensure_forwarded(native_pointer(decode_symbol_name(s->name))); + } +} + +static lispobj follow_ro_fp(lispobj ptr, __attribute__((unused)) uword_t arg) { + return follow_fp(ptr); // just ignore arg +} +static void follow_rospace_ptrs(lispobj* obj, __attribute__((unused)) uword_t arg) { + if (*obj != FORWARDING_HEADER) visit_pointer_words(obj, follow_ro_fp, 0); +} +static void insert_filler(lispobj* obj, __attribute__((unused)) uword_t arg) { + if (*obj == FORWARDING_HEADER) { + sword_t nwords = object_size(native_pointer(forwarding_pointer_value(obj))); + // TODO: huge fillers aren't really used elsewhere. Can this exceed the + // bits allotted for the size field? Insert more than one filler if needed. + *obj = make_filler_header(nwords); + } +} + +void prepare_readonly_space(int purify, int print) +{ + gc_assert((uword_t)read_only_space_free_pointer == READ_ONLY_SPACE_START); + if (!purify) { + // I guess some of the architectures need a readonly page now because reasons, + // even though we're somewhat more careful in coreparse to avoid reading memory + // at READ_ONLY_SPACE_START if the free_pointer isn't higher than the start. + int string_space_size = BACKEND_PAGE_BYTES; + READ_ONLY_SPACE_START = + (uword_t)os_alloc_gc_space(READ_ONLY_CORE_SPACE_ID, + MOVABLE, (char*)DYNAMIC_SPACE_START - string_space_size, + string_space_size); + READ_ONLY_SPACE_END = READ_ONLY_SPACE_START + string_space_size; + read_only_space_free_pointer = (lispobj*)READ_ONLY_SPACE_START; + return; + } + int sum_sizes = 2; + // 1. Sum of the sizes of immutable objects, which can only be in dynamic space + if (print) fprintf(stderr, "purify: calculating size ... "); + page_index_t first, last; + for ( first = 0; first < next_free_page; first = 1+last ) { + last = contiguous_block_final_page(first); + lispobj* where = (lispobj*)page_address(first); + lispobj* limit = (lispobj*)page_address(last) + page_words_used(last); + int nwords; + for ( ; where < limit ; where += nwords ) { + nwords = object_size(where); + if ( readonly_unboxed_obj_p(where) ) sum_sizes += nwords; + } + } +#ifdef LISP_FEATURE_IMMOBILE_SPACE + extern int compute_codeblob_offsets_nwords(int*); + sum_sizes += compute_codeblob_offsets_nwords(NULL); +#endif + sum_sizes <<= WORD_SHIFT; + if (print) fprintf(stderr, "%d bytes\n", sum_sizes); + int string_space_size = ALIGN_UP(sum_sizes, BACKEND_PAGE_BYTES); + // Try to place readonly just below dynamic space, but it doesn't really matter where + READ_ONLY_SPACE_START = + (uword_t)os_alloc_gc_space(READ_ONLY_CORE_SPACE_ID, + MOVABLE, (char*)DYNAMIC_SPACE_START - string_space_size, + string_space_size); + READ_ONLY_SPACE_END = READ_ONLY_SPACE_START + string_space_size; + read_only_space_free_pointer = (lispobj*)READ_ONLY_SPACE_START; + + // 2. Forward all symbol names so that they're placed contiguously + // Could be even more clever and sort lexicographically for determistic core + if (print) fprintf(stderr, "purify: forwarding symbol names\n"); + walk_all_spaces(ensure_symbol_name_forwarded, 0); + + // Add a random delimiter object between symbol-names and everything else. + // APROPOS-LIST uses this to detect the end of the strings. + *read_only_space_free_pointer = SIMPLE_VECTOR_WIDETAG; // length 0 + read_only_space_free_pointer += 2; + + // 3. Forward everything else + if (print) fprintf(stderr, "purify: forwarding other data\n"); + for ( first = 0; first < next_free_page; first = 1+last ) { + last = contiguous_block_final_page(first); + lispobj* where = (lispobj*)page_address(first); + lispobj* limit = (lispobj*)page_address(last) + page_words_used(last); + for ( ; where < limit ; where += careful_object_size(where) ) + if (readonly_unboxed_obj_p(where)) ensure_forwarded(where); + } + + // 4. Update all objects in all spaces to point to r/o copy of anything that moved + if (print) fprintf(stderr, "purify: fixing all pointers\n"); + walk_all_spaces(follow_rospace_ptrs, 0); + walk_all_spaces(insert_filler, 0); +} + +/* Now for the opposite of 'purify' - moving back from R/O to dynamic */ + +static lispobj follow_shadow_fp(lispobj ptr, uword_t arg) { + if (!readonly_space_p(ptr)) return ptr; + lispobj* shadow_space = (lispobj*)arg; + lispobj* base = native_pointer(ptr); + int displacement = base - (lispobj*)READ_ONLY_SPACE_START; + return shadow_space[displacement]; +} + +static void undo_rospace_ptrs(lispobj* obj, uword_t arg) { + visit_pointer_words(obj, follow_shadow_fp, arg); +} + +void move_rospace_to_dynamic(__attribute__((unused)) int print) +{ +#ifdef LISP_FEATURE_IMMOBILE_SPACE + extern void deport_codeblob_offsets_from_heap(); + deport_codeblob_offsets_from_heap(); +#endif + int space_usage = (uword_t)read_only_space_free_pointer - READ_ONLY_SPACE_START; + if (!space_usage) return; + lispobj* shadow_base = calloc(space_usage, 1); + gc_assert(shadow_base); + lispobj* shadow_cursor = shadow_base; + // Forward everything in R/O to dynamic space. Record FPs outside of the objects + // since the space is not writable and we're about to unmap. + lispobj *where = (lispobj*)READ_ONLY_SPACE_START; + int nwords; + for ( ; where < read_only_space_free_pointer ; where += nwords, shadow_cursor += nwords ) { + nwords = headerobj_size(where); + lispobj *new = gc_general_alloc(unboxed_region, nwords*N_WORD_BYTES, PAGE_TYPE_BOXED); + memcpy(new, where, nwords*N_WORD_BYTES); + *shadow_cursor = make_lispobj(new, OTHER_POINTER_LOWTAG); + } + ensure_region_closed(unboxed_region, PAGE_TYPE_BOXED); + os_deallocate((void*)READ_ONLY_SPACE_START, READ_ONLY_SPACE_END - READ_ONLY_SPACE_START); + walk_all_spaces(undo_rospace_ptrs, (uword_t)shadow_base); + // Set it empty + read_only_space_free_pointer = (lispobj*)READ_ONLY_SPACE_START; +} + +/* This kludge is only for the hide-packages test after it invokes move_rospace_to_dynamic(). + * I wish there were a better way to write that test than to hack up the GC + * so badly that it can't run with its heap verifications enabled. */ +void test_dirty_all_gc_cards() +{ +#ifdef LISP_FEATURE_IMMOBILE_SPACE + int n_text_pages = TEXT_SPACE_SIZE / IMMOBILE_CARD_BYTES; + int n_bitmap_elts = ALIGN_UP(n_text_pages, 32) / 32; + memset(text_page_touched_bits, 0xFF, sizeof (int)*n_bitmap_elts); + lispobj* where = (lispobj*)TEXT_SPACE_START; + // OBJ_WRITTEN_FLAG is confusing. The '<<24' puts it in the generation byte. + for ( ; where < text_space_highwatermark ; where += object_size(where) ) + if (widetag_of(where) == CODE_HEADER_WIDETAG) *where |= (OBJ_WRITTEN_FLAG << 24); +#endif +#ifdef LISP_FEATURE_SOFT_CARD_MARKS // just touch all mark bits, no harm done + memset(gc_card_mark, 0, 1<<gc_card_table_nbits); +#endif + page_index_t first = 0; + while (first < next_free_page) { + page_index_t last = contiguous_block_final_page(first); + lispobj* where = (lispobj*)page_address(first); + lispobj* limit = (lispobj*)page_address(last) + page_words_used(last); + for ( ; where < limit ; where += object_size(where) ) + if (widetag_of(where) == CODE_HEADER_WIDETAG) { +#ifndef LISP_FEATURE_SOFT_CARD_MARKS // only touch code pages, others got WP faults + gc_card_mark[addr_to_card_index(where)] = 1; +#endif + *where |= (OBJ_WRITTEN_FLAG << 24); + } + first = 1+last; + } + extern boolean pre_verify_gen_0; + pre_verify_gen_0 = 1; +} + +#endif diff --git a/src/runtime/sunos-os.c b/src/runtime/sunos-os.c index 09d3ab3b03..e4a876b7e6 100644 --- a/src/runtime/sunos-os.c +++ b/src/runtime/sunos-os.c @@ -2,11 +2,11 @@ #include <stdlib.h> #include <signal.h> #include <sys/file.h> +#include <limits.h> #include <unistd.h> #include <errno.h> #include <sys/param.h> -#include <sys/utsname.h> #include "sbcl.h" #include "os.h" @@ -26,18 +26,10 @@ #include "gc-internal.h" #endif -#ifdef LISP_FEATURE_SB_WTIMER -# include <port.h> -# include <time.h> -# include <errno.h> -#endif - -void -os_init(char *argv[], char *envp[]) -{ -} +void os_init() {} -os_vm_address_t os_validate(int attributes, os_vm_address_t addr, os_vm_size_t len) +os_vm_address_t os_alloc_gc_space(int __attribute__((unused)) space_id, + int attributes, os_vm_address_t addr, os_vm_size_t len) { int protection = attributes & IS_GUARD_PAGE ? OS_VM_PROT_NONE : OS_VM_PROT_ALL; attributes &= ~IS_GUARD_PAGE; @@ -61,21 +53,6 @@ os_vm_address_t os_validate(int attributes, os_vm_address_t addr, os_vm_size_t l return addr; } -void os_invalidate(os_vm_address_t addr, os_vm_size_t len) -{ - if(munmap((void*) addr, len) == -1) - perror("munmap"); -} - - -void -os_protect(os_vm_address_t address, os_vm_size_t length, os_vm_prot_t prot) -{ - if(mprotect((void*)address, length, prot) == -1) { - perror("mprotect"); - } -} - #if defined LISP_FEATURE_GENCGC void @@ -83,13 +60,9 @@ sigsegv_handler(int signal, siginfo_t *info, os_context_t *context) { void* fault_addr = (void*)info->si_addr; -#ifdef LISP_FEATURE_SB_SAFEPOINT - if (handle_safepoint_violation(context, fault_addr)) - return; -#endif + if (gencgc_handle_wp_violation(context, fault_addr)) return; - if (!gencgc_handle_wp_violation(fault_addr)) - if(!handle_guard_page_triggered(context, fault_addr)) + if (!handle_guard_page_triggered(context, fault_addr)) lisp_memory_fault_error(context, fault_addr); } @@ -100,10 +73,10 @@ sigsegv_handler(int signal, siginfo_t *info, os_context_t *context) { os_vm_address_t addr = arch_get_bad_addr(signal, info, context); - if (!cheneygc_handle_wp_violation(context, addr)) { - if (!handle_guard_page_triggered(context,addr)) + if (cheneygc_handle_wp_violation(context, addr)) return; + + if (!handle_guard_page_triggered(context,addr)) lisp_memory_fault_error(context, addr); - } } #endif @@ -111,21 +84,7 @@ sigsegv_handler(int signal, siginfo_t *info, os_context_t *context) void os_install_interrupt_handlers() { - undoably_install_low_level_interrupt_handler(SIG_MEMORY_FAULT, - sigsegv_handler); - - /* OAOOM c.f. linux-os.c. - * Should we have a reusable function gc_install_interrupt_handlers? */ -#ifdef LISP_FEATURE_SB_THREAD -# ifdef LISP_FEATURE_SB_SAFEPOINT -# ifdef LISP_FEATURE_SB_THRUPTION - undoably_install_low_level_interrupt_handler(SIGPIPE, thruption_handler); -# endif -# else - undoably_install_low_level_interrupt_handler(SIG_STOP_FOR_GC, - sig_stop_for_gc_handler); -# endif -#endif + ll_install_handler(SIG_MEMORY_FAULT, sigsegv_handler); } char *os_get_runtime_executable_path() @@ -140,99 +99,3 @@ char *os_get_runtime_executable_path() return NULL; return copied_string(path); } - -#ifdef LISP_FEATURE_SB_WTIMER -/* - * Waitable timer implementation for the safepoint-based (SIGALRM-free) - * timer facility using SunOS completion ports. - */ - -struct os_wtimer { - int port; - int timer; -}; - -struct os_wtimer * -os_create_wtimer() -{ - int port = port_create(); - if (port == -1) { - perror("port_create"); - lose("os_create_wtimer"); - } - - port_notify_t pn; - pn.portnfy_port = port; - pn.portnfy_user = 0; - - struct sigevent ev; - memset(&ev, 0, sizeof(ev)); - ev.sigev_notify = SIGEV_PORT; - ev.sigev_value.sival_ptr = &pn; - - timer_t timer; - if (timer_create(CLOCK_HIGHRES, &ev, &timer) == -1 - && (errno != EPERM || timer_create(CLOCK_REALTIME, &ev, &timer) == -1)) - { - perror("timer_create"); - lose("os_create_wtimer"); - } - - struct os_wtimer *wt = malloc(sizeof(struct os_wtimer)); - if (!wt) - lose("os_create_wtimer: malloc"); - - wt->port = port; - wt->timer = timer; - return wt; -} - -int -os_wait_for_wtimer(struct os_wtimer *wt) -{ - port_event_t pe; - if (port_get(wt->port, &pe, 0) == -1) { - if (errno == EINTR) - return 1; - perror("port_get"); - lose("os_wtimer_listen failed"); - } - return 0; -} - -void -os_close_wtimer(struct os_wtimer *wt) -{ - if (close(wt->port) == -1) { - perror("close"); - lose("os_close_wtimer"); - } - if (timer_delete(wt->timer) == -1) { - perror("timer_delete"); - lose("os_close_wtimer"); - } - free(wt); -} - -void -os_set_wtimer(struct os_wtimer *wt, int sec, int nsec) -{ - struct itimerspec spec; - spec.it_value.tv_sec = sec; - spec.it_value.tv_nsec = nsec; - spec.it_interval.tv_sec = 0; - spec.it_interval.tv_nsec = 0; - if (timer_settime(wt->timer, 0, &spec, 0) == -1) { - int x = errno; - perror("timer_settime"); - if (x != EINVAL) - lose("os_set_wtimer"); - } -} - -void -os_cancel_wtimer(struct os_wtimer *wt) -{ - os_set_wtimer(wt, 0, 0); -} -#endif diff --git a/src/runtime/sys_mmap.inc b/src/runtime/sys_mmap.inc new file mode 100644 index 0000000000..01aba23297 --- /dev/null +++ b/src/runtime/sys_mmap.inc @@ -0,0 +1,40 @@ +/* -*- Mode: C -*- */ + +#ifdef LISP_FEATURE_USE_SYS_MMAP + +/// +/// ********************************** +/// * GC MUST NOT ACQUIRE ANY LOCKS * +/// ********************************** +/// +/// It's normally fine to use the mmap() system call to obtain memory for the +/// hopscotch tables, unless your C runtime intercepts mmap() and causes it +/// to sometimes (or always?) need a spinlock. That lock may be owned already, +/// so GC will patiently wait forever; meanwhile the lock owner is also +/// waiting forever on GC to finish. +/// So bypass the C library routine and call the OS directly +/// in case of a non-signal-safe interceptor such as +/// https://chromium.googlesource.com/chromium/src/third_party/tcmalloc/chromium/+/refs/heads/master/src/malloc_hook_mmap_linux.h#146 +/// +static inline void* sbcl_mmap(void* addr, size_t length, int prot, int flags, + int fd, off_t offset) { + // "linux-os.h" brings in <syscall.h>, others may need something different. + // mmap2 allows large file access with 32-bit off_t. We don't care about that, + // but _usually_ only one or the other of the syscalls exists depending on, + // various factors. Basing it on word size will pick the right one. +#ifdef LISP_FEATURE_64_BIT + return (void*)syscall(SYS_mmap, addr, length, prot, flags, fd, offset); +#else + return (void*)syscall(SYS_mmap2, addr, length, prot, flags, fd, offset); +#endif +} +static inline int sbcl_munmap(void* addr, size_t length) { + return syscall(__NR_munmap, addr, length); +} + +#else + +#define sbcl_mmap mmap +#define sbcl_munmap munmap + +#endif diff --git a/src/runtime/thread.c b/src/runtime/thread.c index 2ecaeb2452..7ce50a4984 100644 --- a/src/runtime/thread.c +++ b/src/runtime/thread.c @@ -9,6 +9,9 @@ * files for more information. */ +#ifdef __linux__ +#define _GNU_SOURCE // for pthread_setname_np() +#endif #include "sbcl.h" #include <stdlib.h> @@ -24,12 +27,6 @@ #include <sys/wait.h> #endif -#ifdef LISP_FEATURE_MACH_EXCEPTION_HANDLER -#include <mach/mach.h> -#include <mach/mach_error.h> -#include <mach/mach_types.h> -#endif - #include "runtime.h" #include "validate.h" /* for BINDING_STACK_SIZE etc */ #include "thread.h" @@ -44,50 +41,49 @@ #include "interr.h" /* for lose() */ #include "alloc.h" #include "gc-internal.h" -#include "getallocptr.h" +#include "pseudo-atomic.h" #include "interrupt.h" #include "lispregs.h" +#include "atomiclog.inc" #ifdef LISP_FEATURE_SB_THREAD -#ifdef LISP_FEATURE_OPENBSD +#if defined LISP_FEATURE_OPENBSD || defined LISP_FEATURE_FREEBSD || defined LISP_FEATURE_DRAGONFLY #include <pthread_np.h> #endif #ifdef LISP_FEATURE_SUNOS #include <thread.h> #endif - -#if defined(LISP_FEATURE_WIN32) || defined(OS_THREAD_STACK) -# define IMMEDIATE_POST_MORTEM -#else -static struct thread *postmortem_thread; -#endif - #endif int dynamic_values_bytes = 4096 * sizeof(lispobj); // same for all threads +// exposed to lisp for pthread_create if not C_STACK_IS_CONTROL_STACK +os_vm_size_t thread_alien_stack_size = ALIEN_STACK_SIZE; struct thread *all_threads; #ifdef LISP_FEATURE_SB_THREAD -pthread_mutex_t all_threads_lock = PTHREAD_MUTEX_INITIALIZER; - -static pthread_mutex_t create_thread_lock = PTHREAD_MUTEX_INITIALIZER; #ifdef LISP_FEATURE_GCC_TLS __thread struct thread *current_thread; -__thread int is_lisp_thread; +#elif !defined LISP_FEATURE_WIN32 +pthread_key_t current_thread = 0; +#endif + +#ifdef LISP_FEATURE_WIN32 +CRITICAL_SECTION all_threads_lock; +static CRITICAL_SECTION recyclebin_lock; +static CRITICAL_SECTION in_gc_lock; #else -pthread_key_t lisp_thread = 0; +pthread_mutex_t all_threads_lock = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t recyclebin_lock = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t in_gc_lock = PTHREAD_MUTEX_INITIALIZER; #endif + #endif #if defined(LISP_FEATURE_X86) || defined(LISP_FEATURE_X86_64) -extern lispobj call_into_lisp_first_time(lispobj fun, lispobj *args, int nargs) -# ifdef LISP_FEATURE_X86_64 - __attribute__((sysv_abi)) -# endif - ; +extern lispobj call_into_lisp_first_time(lispobj fun, lispobj *args, int nargs); #endif static void @@ -111,107 +107,246 @@ unlink_thread(struct thread *th) th->next->prev = th->prev; } +#define get_thread_state(thread) \ + (int)__sync_val_compare_and_swap(&thread->state_word.state, -1, -1) + #ifndef LISP_FEATURE_SB_SAFEPOINT -/* Only access thread state with blockables blocked. */ -lispobj -thread_state(struct thread *thread) -{ - lispobj state; - sigset_t old; - block_blockable_signals(&old); - os_sem_wait(thread->state_sem, "thread_state"); - state = thread->state; - os_sem_post(thread->state_sem, "thread_state"); - thread_sigmask(SIG_SETMASK, &old, NULL); - return state; -} void -set_thread_state(struct thread *thread, lispobj state) +set_thread_state(struct thread *thread, + char state, + boolean signals_already_blocked) // for foreign thread { + struct extra_thread_data *semaphores = thread_extra_data(thread); int i, waitcount = 0; sigset_t old; - block_blockable_signals(&old); - os_sem_wait(thread->state_sem, "set_thread_state"); - if (thread->state != state) { + // If we've already masked the blockable signals we can avoid two syscalls here. + if (!signals_already_blocked) + block_blockable_signals(&old); + os_sem_wait(&semaphores->state_sem, "set_thread_state"); + if (thread->state_word.state != state) { if ((STATE_STOPPED==state) || (STATE_DEAD==state)) { - waitcount = thread->state_not_running_waitcount; - thread->state_not_running_waitcount = 0; + waitcount = semaphores->state_not_running_waitcount; + semaphores->state_not_running_waitcount = 0; for (i=0; i<waitcount; i++) - os_sem_post(thread->state_not_running_sem, "set_thread_state (not running)"); + os_sem_post(&semaphores->state_not_running_sem, "set_thread_state (not running)"); } if ((STATE_RUNNING==state) || (STATE_DEAD==state)) { - waitcount = thread->state_not_stopped_waitcount; - thread->state_not_stopped_waitcount = 0; + waitcount = semaphores->state_not_stopped_waitcount; + semaphores->state_not_stopped_waitcount = 0; for (i=0; i<waitcount; i++) - os_sem_post(thread->state_not_stopped_sem, "set_thread_state (not stopped)"); + os_sem_post(&semaphores->state_not_stopped_sem, "set_thread_state (not stopped)"); } - thread->state = state; + thread->state_word.state = state; } - os_sem_post(thread->state_sem, "set_thread_state"); - thread_sigmask(SIG_SETMASK, &old, NULL); + os_sem_post(&semaphores->state_sem, "set_thread_state"); + if (!signals_already_blocked) + thread_sigmask(SIG_SETMASK, &old, NULL); } -void -wait_for_thread_state_change(struct thread *thread, lispobj state) +// Wait until "thread's" state is something other than 'undesired_state' +// and return whatever the new state is. +int thread_wait_until_not(int undesired_state, + struct thread *thread) { + struct extra_thread_data *semaphores = thread_extra_data(thread); sigset_t old; os_sem_t *wait_sem; block_blockable_signals(&old); start: - os_sem_wait(thread->state_sem, "wait_for_thread_state_change"); - if (thread->state == state) { - switch (state) { + os_sem_wait(&semaphores->state_sem, "wait_for_thread_state_change"); + /* "The following functions synchronize memory with respect to other threads: + * ... pthread_mutex_lock() ... " + * https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_11 + * But we still have to ensure no compiler reordering. + */ + int ending_state = get_thread_state(thread); + if (ending_state == undesired_state) { + switch (undesired_state) { case STATE_RUNNING: - wait_sem = thread->state_not_running_sem; - thread->state_not_running_waitcount++; + wait_sem = &semaphores->state_not_running_sem; + semaphores->state_not_running_waitcount++; break; case STATE_STOPPED: - wait_sem = thread->state_not_stopped_sem; - thread->state_not_stopped_waitcount++; + wait_sem = &semaphores->state_not_stopped_sem; + semaphores->state_not_stopped_waitcount++; break; default: - lose("Invalid state in wait_for_thread_state_change: %"OBJ_FMTX, state); + lose("thread_wait_until_not: invalid argument %x", ending_state); } } else { wait_sem = NULL; } - os_sem_post(thread->state_sem, "wait_for_thread_state_change"); + os_sem_post(&semaphores->state_sem, "wait_for_thread_state_change"); if (wait_sem) { os_sem_wait(wait_sem, "wait_for_thread_state_change"); goto start; } thread_sigmask(SIG_SETMASK, &old, NULL); + return ending_state; } #endif /* sb-safepoint */ #endif /* sb-thread */ -static int -initial_thread_trampoline(struct thread *th) +#ifdef LISP_FEATURE_WIN32 +#define sb_GetTID() GetCurrentThreadId() +#elif defined __linux__ +// gettid() was added in glibc 2.30 but we support older glibc +int sb_GetTID() { return syscall(SYS_gettid); } +#elif defined __DragonFly__ +#include <sys/lwp.h> +lwpid_t sb_GetTID() { return lwp_gettid(); } +#elif defined __FreeBSD__ +#include <sys/thr.h> +int sb_GetTID() { - lispobj function; -#if defined(LISP_FEATURE_X86) || defined(LISP_FEATURE_X86_64) - lispobj *args = NULL; + long id; + thr_self(&id); + // man thr_self(2) says: the thread identifier is an integer in the range + // from PID_MAX + 2 (100001) to INT_MAX. So casting to int is safe. + return (int)id; +} +#else +#define sb_GetTID() 0 #endif -#ifdef LISP_FEATURE_SB_THREAD -# ifdef LISP_FEATURE_GCC_TLS - is_lisp_thread = 1; -# else - pthread_setspecific(lisp_thread, (void *)1); -# endif + +/* Our futex-based lisp mutex needs an OS-assigned unique ID. + * Why not use pthread_self? I think the reason is that that on linux, + * the TID is 4 bytes, and the futex lock word is 4 bytes. + * If the unique ID needed 8 bytes, there could be spurious aliasing + * that would make the code behave incorrectly. */ +static int get_nonzero_tid() +{ + int tid = sb_GetTID(); +#ifdef LISP_FEATURE_SB_FUTEX + // If no futexes, don't need or want to assert that the TID is valid. + // (macOS etc) + gc_assert(tid != 0); #endif + return tid; +} + +// Because creation is synchronized by *MAKE-THREAD-LOCK* +// we only need a single 'attributes' object. +#if defined LISP_FEATURE_SB_THREAD && !defined LISP_FEATURE_WIN32 +pthread_attr_t new_lisp_thread_attr; +#define init_shared_attr_object() (pthread_attr_init(&new_lisp_thread_attr)==0) +#else +#define init_shared_attr_object() (1) +#endif +struct thread *alloc_thread_struct(void*); + +#ifdef LISP_FEATURE_WIN32 +#define ASSOCIATE_OS_THREAD(thread) \ + DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), \ + GetCurrentProcess(), (LPHANDLE)&thread->os_thread, 0, TRUE, \ + DUPLICATE_SAME_ACCESS) +#elif defined LISP_FEATURE_GS_SEG +#include <asm/prctl.h> +#include <sys/prctl.h> +extern int arch_prctl(int code, unsigned long *addr); +#define ASSOCIATE_OS_THREAD(thread) arch_prctl(ARCH_SET_GS, (uword_t*)thread), \ + thread->os_thread = thread_self() +#else +#define ASSOCIATE_OS_THREAD(thread) thread->os_thread = thread_self() +#endif + +#ifndef LISP_FEATURE_SB_THREAD +# define ASSIGN_CURRENT_THREAD(dummy) +#elif defined LISP_FEATURE_GCC_TLS +# define ASSIGN_CURRENT_THREAD(x) current_thread = x +#elif !defined LISP_FEATURE_WIN32 +# define ASSIGN_CURRENT_THREAD(x) pthread_setspecific(current_thread, x) +#else +# define ASSIGN_CURRENT_THREAD(x) TlsSetValue(OUR_TLS_INDEX, x) +#endif + +#ifdef LISP_FEATURE_WIN32 +// Need a function callable from assembly code, where the inline one won't do. +void* read_current_thread() { + return get_sb_vm_thread(); +} +#endif + +#if defined LISP_FEATURE_DARWIN && defined LISP_FEATURE_SB_THREAD +extern pthread_key_t foreign_thread_ever_lispified; +#endif + +#if !defined COLLECT_GC_STATS && !defined STANDALONE_LDB && \ + defined LISP_FEATURE_LINUX && defined LISP_FEATURE_SB_THREAD && defined LISP_FEATURE_64_BIT +#define COLLECT_GC_STATS +#endif +#ifdef COLLECT_GC_STATS +static struct timespec gc_start_time; +static long stw_elapsed, + stw_min_duration = LONG_MAX, stw_max_duration, stw_sum_duration, + gc_min_duration = LONG_MAX, gc_max_duration, gc_sum_duration; +int show_gc_stats, n_gcs_done; +static void summarize_gc_stats(void) { + // TODO: also collect things like number of root pages,bytes scanned + // and number of pages,bytes copied on average per GC cycle. + if (show_gc_stats && n_gcs_done) + fprintf(stderr, + "\nGC: stw_delay=%ld,%ld,%ld \u00B5s (min,avg,max) pause=%ld,%ld,%ld \u00B5s (sum=%ld) over %d GCs\n", + stw_min_duration/1000, stw_sum_duration/n_gcs_done/1000, stw_max_duration/1000, + gc_min_duration/1000, gc_sum_duration/n_gcs_done/1000, gc_max_duration/1000, + gc_sum_duration/1000, n_gcs_done); +} +void reset_gc_stats() { // after sb-posix:fork + stw_min_duration = LONG_MAX; stw_max_duration = stw_sum_duration = 0; + gc_min_duration = LONG_MAX; gc_max_duration = gc_sum_duration = 0; + n_gcs_done = 0; + show_gc_stats = 1; // won't show if never called reset +} +#endif + +#ifdef ATOMIC_LOGGING +#define THREAD_NAME_MAP_MAX 20 /* KLUDGE */ +struct { + pthread_t thread; + char *name; // strdup'ed +} thread_name_map[THREAD_NAME_MAP_MAX]; +int thread_name_map_count; + +char* thread_name_from_pthread(pthread_t pointer){ + int i; + for(i=0; i<thread_name_map_count; ++i) + if (thread_name_map[i].thread == pointer) return thread_name_map[i].name; + return 0; +} +#endif + +void create_main_lisp_thread(lispobj function) { +#ifdef LISP_FEATURE_WIN32 + InitializeCriticalSection(&all_threads_lock); + InitializeCriticalSection(&recyclebin_lock); + InitializeCriticalSection(&in_gc_lock); +#endif + struct thread *th = alloc_thread_struct(0); + if (!th || arch_os_thread_init(th)==0 || !init_shared_attr_object()) + lose("can't create initial thread"); + th->state_word.sprof_enable = 1; +#if defined LISP_FEATURE_SB_THREAD && !defined LISP_FEATURE_GCC_TLS && !defined LISP_FEATURE_WIN32 + pthread_key_create(¤t_thread, 0); +#endif +#if defined LISP_FEATURE_DARWIN && defined LISP_FEATURE_SB_THREAD + pthread_key_create(&foreign_thread_ever_lispified, 0); +#endif +#if defined(LISP_FEATURE_X86) || defined(LISP_FEATURE_X86_64) + __attribute__((unused)) lispobj *args = NULL; +#endif + ASSOCIATE_OS_THREAD(th); + ASSIGN_CURRENT_THREAD(th); #if defined THREADS_USING_GCSIGNAL && \ (defined LISP_FEATURE_PPC || defined LISP_FEATURE_PPC64 || defined LISP_FEATURE_ARM64 || defined LISP_FEATURE_RISCV) /* SIG_STOP_FOR_GC defaults to blocked on PPC? */ - unblock_gc_signals(0,0); + unblock_gc_signals(); #endif - function = th->no_tls_value_marker; - th->no_tls_value_marker = NO_TLS_VALUE_MARKER_WIDETAG; - if(arch_os_thread_init(th)==0) return 1; link_thread(th); - th->os_thread=thread_self(); + th->os_kernel_tid = get_nonzero_tid(); + #ifndef LISP_FEATURE_WIN32 protect_control_stack_hard_guard_page(1, NULL); #endif @@ -227,121 +362,35 @@ initial_thread_trampoline(struct thread *th) set_thread_stack(th->control_stack_end); #endif +#ifdef COLLECT_GC_STATS + atexit(summarize_gc_stats); +#endif /* WIN32 has a special stack arrangement, calling * call_into_lisp_first_time will put the new stack in the middle * of the current stack */ -#if !defined(LISP_FEATURE_WIN32) && (defined(LISP_FEATURE_X86) || defined(LISP_FEATURE_X86_64)) - return call_into_lisp_first_time(function,args,0); +#if !(defined(LISP_FEATURE_WIN32) && !defined(OS_THREAD_STACK)) \ + && (defined(LISP_FEATURE_X86) || defined(LISP_FEATURE_X86_64)) + call_into_lisp_first_time(function,args,0); #else - return funcall0(function); + funcall0(function); #endif -} - + // If we end up returning, clean up the initial thread. #ifdef LISP_FEATURE_SB_THREAD - -/* THREAD POST MORTEM CLEANUP - * - * Memory allocated for the thread stacks cannot be reclaimed while - * the thread is still alive, so we need a mechanism for post mortem - * cleanups. FIXME: We actually have two, for historical reasons as - * the saying goes. Do we really need two? Nikodemus guesses that - * not anymore, now that we properly call pthread_attr_destroy before - * freeing the stack. */ - -static void free_thread_struct(struct thread *th) -{ -#if defined(LISP_FEATURE_WIN32) - os_invalidate_free((os_vm_address_t) th->os_address, THREAD_STRUCT_SIZE); + unlink_thread(th); #else - os_invalidate((os_vm_address_t) th->os_address, THREAD_STRUCT_SIZE); + all_threads = NULL; #endif + arch_os_thread_cleanup(th); + ASSIGN_CURRENT_THREAD(NULL); } -# if defined(IMMEDIATE_POST_MORTEM) - -/* - * If this feature is set, we are running on a stack managed by the OS, - * and no fancy delays are required for anything. Just do it. - */ -static void -schedule_thread_post_mortem(struct thread *corpse) -{ - pthread_detach(pthread_self()); - free_thread_struct(corpse); -} - -# else - -static void -perform_thread_post_mortem(struct thread *post_mortem) -{ - gc_assert(post_mortem); - /* The thread may exit before pthread_create() has finished - initialization and it may write into already unmapped - memory. This lock doesn't actually need to protect - anything, just to make sure that at least one call to - pthread_create() has finished. - - Possible improvements: stash the address of the thread - struct for which a pthread is being created and don't lock - here if it's not the one being terminated. */ - int result = pthread_mutex_lock(&create_thread_lock); - gc_assert(result == 0); - result = pthread_mutex_unlock(&create_thread_lock); - gc_assert(result == 0); - - if ((result = pthread_join(post_mortem->os_thread, NULL))) { - lose("Error calling pthread_join in perform_thread_post_mortem:\n%s", - strerror(result)); - } - free_thread_struct(post_mortem); -} - -static inline struct thread* -fifo_buffer_shift(struct thread** dest, struct thread* value) -{ -#ifdef __ATOMIC_SEQ_CST - return __atomic_exchange_n(dest, value, __ATOMIC_SEQ_CST); -#elif defined(LISP_FEATURE_X86) || defined(LISP_FEATURE_X86_64) - /* I'd like to remove this case but I don't know whether MSVC has - * either of __atomic_exchange_n() or __sync_val_compare_and_swap() */ - lispobj old_value; - asm volatile - ("lock xchg %0,(%1)" - : "=r" (old_value) - : "r" (dest), "0" (value) - : "memory"); - return old_value; -#else - // We don't want a compare-and-swap, but if that's all we have, - // then build an atomic exchange out of compare-and-swap - lispobj old = *dest; - while (1) { - lispobj actual = __sync_val_compare_and_swap(dest, old, value); - if (actual == old) - return old; - old = actual; - } -#endif -} +#ifdef LISP_FEATURE_SB_THREAD -static void -schedule_thread_post_mortem(struct thread *corpse) +void free_thread_struct(struct thread *th) { - gc_assert(corpse); - // This strange little mechanism is a FIFO buffer of capacity 1. - // By stuffing one new thing in and reading the old one out, we ensure - // that at least one pthread_create() has completed by this point. - // In particular, the thread we're post-morteming must have completed - // because thread creation is completely serialized (which is - // somewhat unfortunate). - struct thread* previous = fifo_buffer_shift(&postmortem_thread, corpse); - if (previous) // any random thread which pre-deceased me - perform_thread_post_mortem(previous); + os_deallocate((os_vm_address_t) th->os_address, THREAD_STRUCT_SIZE); } -# endif /* !IMMEDIATE_POST_MORTEM */ - /* Note: scribble must be stack-allocated */ static void init_new_thread(struct thread *th, @@ -350,33 +399,34 @@ init_new_thread(struct thread *th, { int lock_ret; -#ifdef LISP_FEATURE_GCC_TLS - is_lisp_thread = 1; -#else - pthread_setspecific(lisp_thread, (void *)1); -#endif + ASSIGN_CURRENT_THREAD(th); if(arch_os_thread_init(th)==0) { /* FIXME: handle error */ lose("arch_os_thread_init failed"); } - th->os_thread=thread_self(); - if (guardp) +#define GUARD_CONTROL_STACK 1 +#define GUARD_BINDING_STACK 2 +#define GUARD_ALIEN_STACK 4 + + if (guardp & GUARD_CONTROL_STACK) protect_control_stack_guard_page(1, NULL); - protect_binding_stack_guard_page(1, NULL); - protect_alien_stack_guard_page(1, NULL); + if (guardp & GUARD_BINDING_STACK) + protect_binding_stack_guard_page(1, NULL); + if (guardp & GUARD_ALIEN_STACK) + protect_alien_stack_guard_page(1, NULL); + /* Since GC can only know about this thread from the all_threads * list and we're just adding this thread to it, there is no * danger of deadlocking even with SIG_STOP_FOR_GC blocked (which * it is not). */ #ifdef LISP_FEATURE_SB_SAFEPOINT - *th->csp_around_foreign_call = (lispobj)scribble; + csp_around_foreign_call(th) = (lispobj)scribble; #endif - lock_ret = pthread_mutex_lock(&all_threads_lock); - gc_assert(lock_ret == 0); + lock_ret = mutex_acquire(&all_threads_lock); + gc_assert(lock_ret); link_thread(th); - lock_ret = pthread_mutex_unlock(&all_threads_lock); - gc_assert(lock_ret == 0); + ignore_value(mutex_release(&all_threads_lock)); /* Kludge: Changed the order of some steps between the safepoint/ * non-safepoint versions of this code. Can we unify this more? @@ -390,76 +440,58 @@ init_new_thread(struct thread *th, } static void -undo_init_new_thread(struct thread *th, - init_thread_data __attribute__((unused)) *scribble) +unregister_thread(struct thread *th, + init_thread_data __attribute__((unused)) *scribble) { int lock_ret; - /* Kludge: Changed the order of some steps between the safepoint/ - * non-safepoint versions of this code. Can we unify this more? - */ -#ifdef LISP_FEATURE_SB_SAFEPOINT block_blockable_signals(0); - ensure_region_closed(&th->alloc_region, BOXED_PAGE_FLAG); -#if defined(LISP_FEATURE_SB_SAFEPOINT_STRICTLY) && !defined(LISP_FEATURE_WIN32) - ensure_region_closed(&th->sprof_alloc_region, BOXED_PAGE_FLAG); -#endif + gc_close_thread_regions(th, LOCK_PAGE_TABLE); +#ifdef LISP_FEATURE_SB_SAFEPOINT pop_gcing_safety(&scribble->safety); - lock_ret = pthread_mutex_lock(&all_threads_lock); - gc_assert(lock_ret == 0); - unlink_thread(th); - lock_ret = pthread_mutex_unlock(&all_threads_lock); - gc_assert(lock_ret == 0); #else - /* Block GC */ - block_blockable_signals(0); - set_thread_state(th, STATE_DEAD); - - /* SIG_STOP_FOR_GC is blocked and GC might be waiting for this - * thread, but since we are already dead it won't wait long. */ - lock_ret = pthread_mutex_lock(&all_threads_lock); - gc_assert(lock_ret == 0); - - ensure_region_closed(&th->alloc_region, BOXED_PAGE_FLAG); -#if defined(LISP_FEATURE_SB_SAFEPOINT_STRICTLY) && !defined(LISP_FEATURE_WIN32) - ensure_region_closed(&th->sprof_alloc_region, BOXED_PAGE_FLAG); + /* This state change serves to "acknowledge" any stop-the-world + * signal received while the STOP_FOR_GC signal is blocked */ + set_thread_state(th, STATE_DEAD, 1); #endif + /* SIG_STOP_FOR_GC is blocked and GC might be waiting for this + * thread, but since we are either exiting lisp code as a lisp + * thread that is dying, or exiting lisp code to return to + * former status as a C thread, it won't wait long. */ + lock_ret = mutex_acquire(&all_threads_lock); + gc_assert(lock_ret); unlink_thread(th); - pthread_mutex_unlock(&all_threads_lock); - gc_assert(lock_ret == 0); -#endif + lock_ret = mutex_release(&all_threads_lock); + gc_assert(lock_ret); arch_os_thread_cleanup(th); -#ifndef LISP_FEATURE_SB_SAFEPOINT - os_sem_destroy(th->state_sem); - os_sem_destroy(th->state_not_running_sem); - os_sem_destroy(th->state_not_stopped_sem); + __attribute__((unused)) struct extra_thread_data *semaphores = thread_extra_data(th); +#ifdef LISP_FEATURE_UNIX + os_sem_destroy(&semaphores->sprof_sem); #endif - - -#ifdef LISP_FEATURE_MACH_EXCEPTION_HANDLER - mach_lisp_thread_destroy(th); +#ifndef LISP_FEATURE_SB_SAFEPOINT + os_sem_destroy(&semaphores->state_sem); + os_sem_destroy(&semaphores->state_not_running_sem); + os_sem_destroy(&semaphores->state_not_stopped_sem); #endif #if defined(LISP_FEATURE_WIN32) int i; - for (i = 0; i< - (int) (sizeof(th->private_events.events)/ - sizeof(th->private_events.events[0])); ++i) { - CloseHandle(th->private_events.events[i]); - } - TlsSetValue(OUR_TLS_INDEX,NULL); + for (i = 0; i<NUM_PRIVATE_EVENTS; ++i) + CloseHandle(thread_private_events(th,i)); #endif /* Undo the association of the current pthread to its `struct thread', - * such that we can call arch_os_get_current_thread() later in this + * such that we can call get_sb_vm_thread() later in this * thread and cleanly get back NULL. */ -#ifdef LISP_FEATURE_GCC_TLS - current_thread = NULL; -#else - pthread_setspecific(specials, NULL); -#endif + /* FIXME: what if, after we blocked signals, someone uses INTERRUPT-THREAD + * on this thread? It's no longer a lisp thread; I suspect the signal + * will be redirected to a lisp thread. + * Can anything else go wrong with other signals? Nothing else should + * direct signals specifically to this thread. Per-process signals are ok + * because the kernel picks a thread in which a signal isn't blocked */ + ASSIGN_CURRENT_THREAD(NULL); } /* this is the first thing that runs in the child (which is why the @@ -467,125 +499,270 @@ undo_init_new_thread(struct thread *th, * lisp function after doing arch_os_thread_init and whatever other * bookkeeping needs to be done */ +#ifdef LISP_FEATURE_WIN32 +__stdcall unsigned int new_thread_trampoline(LPVOID arg) +#else void* new_thread_trampoline(void* arg) +#endif { - struct thread *th = (struct thread *)arg; - int result; - init_thread_data scribble; + struct thread* th = arg; + ASSOCIATE_OS_THREAD(th); - FSHOW((stderr,"/creating thread %p\n", thread_self())); - check_deferrables_blocked_or_lose(0); -#ifndef LISP_FEATURE_SB_SAFEPOINT - check_gc_signals_unblocked_or_lose(0); +#ifdef LISP_FEATURE_SB_SAFEPOINT + init_thread_data scribble; + // This "scribble" thing is really quite pointless because the original sigset_t + // was passed in the thread's startup info (unless no signals at all were blocked). + // And when terminating, why does anyone care what the signal mask was??? + // Well, there's a big "however": '&scribble' is no mere pass-by-reference arg- + // it is actually used as an approximation of the C stack pointer. +#define SCRIBBLE &scribble +#else +#define SCRIBBLE 0 +#endif + // 'th->lisp_thread' remains valid despite not being in all_threads + // due to the pinning via *STARTING-THREADS*. + struct thread_instance *lispthread = (void*)native_pointer(th->lisp_thread); + if (lispthread->_ephemeral_p == LISP_T) th->state_word.user_thread_p = 0; + + /* Potentially set the externally-visible name of this thread, + * and for a whole pile of crazy, look at get_max_thread_name_length_impl() in + * https://github.com/llvm-mirror/llvm/blob/394ea6522c69c2668bf328fc923e1a11cd785265/lib/Support/Unix/Threading.inc + * which among other things, suggests that Linux might not even have the syscall */ + lispobj name = lispthread->name; // pinned + if (other_pointer_p(name) && + header_widetag(VECTOR(name)->header) == SIMPLE_BASE_STRING_WIDETAG) { +#ifdef LISP_FEATURE_LINUX + /* "The thread name is a meaningful C language string, whose length is + * restricted to 16 characters, including the terminating null byte ('\0'). + * The pthread_setname_np() function can fail with the following error: + * ERANGE The length of the string ... exceeds the allowed limit." */ + if (vector_len(VECTOR(name)) <= 15) + pthread_setname_np(pthread_self(), (char*)VECTOR(name)->data); +#endif +#ifdef LISP_FEATURE_NETBSD + /* This constant is an upper bound on the length including the NUL. + * Exceeding it will fail the call. It happens to be 32. + * Also, don't want to printf-format a name containing a '%' */ + if (vector_len(VECTOR(name)) < PTHREAD_MAX_NAMELEN_NP) + pthread_setname_np(pthread_self(), "%s", (char*)VECTOR(name)->data); +#endif +#if defined LISP_FEATURE_FREEBSD || defined LISP_FEATURE_OPENBSD + /* Some places document that the length limit is either 16 or 32, + * but my testing showed that 12.1 seems to accept any length */ + pthread_set_name_np(pthread_self(), (char*)VECTOR(name)->data); #endif - - lispobj function = th->no_tls_value_marker; - th->no_tls_value_marker = NO_TLS_VALUE_MARKER_WIDETAG; - init_new_thread(th, &scribble, 1); - result = funcall0(function); - undo_init_new_thread(th, &scribble); - -#ifndef OS_THREAD_STACK - schedule_thread_post_mortem(th); +#ifdef LISP_FEATURE_DARWIN + if (vector_len(VECTOR(name)) < 64) + pthread_setname_np((char*)VECTOR(name)->data); #endif + } - FSHOW((stderr,"/exiting thread %p\n", thread_self())); - return (void*)(uintptr_t)result; -} +#ifdef ATOMIC_LOGGING + char* string = strdup((char*)VECTOR(name)->data); + int index = __sync_fetch_and_add(&thread_name_map_count, 1); + gc_assert(index < THREAD_NAME_MAP_MAX); + thread_name_map[index].thread = pthread_self(); + thread_name_map[index].name = string; +#endif + + struct vector* startup_info = VECTOR(lispthread->startup_info); // 'lispthread' is pinned + gc_assert(header_widetag(startup_info->header) == SIMPLE_VECTOR_WIDETAG); + lispobj startfun = startup_info->data[0]; // 'startup_info' is pinned + gc_assert(functionp(startfun)); + // GC can benefit from knowing the _effective_ end of the ambiguous root range. + // Nothing at a higher address than &arg needs to be scanned for ambiguous roots. + // For x86 + linux this optimization skips over about 800 words in the stack scan, + // and for x86-64 it skip about 550 words as observed via: + // fprintf(stderr, "%d non-lisp stack words\n", + // (int)((lispobj*)th->control_stack_end - (lispobj*)&arg)); + // ADDRESS_SANITIZER doesn't allow this optimization. + // Both of these assertions fail with the sanitizer enabled: + // gc_assert(th->control_stack_start <= (lispobj*)&arg + // && (lispobj*)&arg <= th->control_stack_end); + // gc_assert(th->control_stack_start <= (lispobj*)&startup_info + // && (lispobj*)&startup_info <= th->control_stack_end); + // It seems to subvert the "&" and "*" operators in a way that only it understands, + // while the stack pointer register is unperturbed. + // (gencgc takes '&raise' for the current thread, but it disables the sanitizers) + // + // A stop-for-GC signal that hits after init_new_thread() releases the all_threads lock + // and returns control here needs to see in the interrupt context a stack pointer + // strictly below the computed th->control_stack_end. So make sure the value we pick + // is strictly above any value of SP that the interrupt context could have. +#if defined LISP_FEATURE_C_STACK_IS_CONTROL_STACK && !defined ADDRESS_SANITIZER \ + && !defined LISP_FEATURE_SB_SAFEPOINT + th->control_stack_end = (lispobj*)&arg + 1; +#endif + th->os_kernel_tid = get_nonzero_tid(); + init_new_thread(th, SCRIBBLE, 0); + // Passing the untagged pointer ensures 2 things: + // - that the pinning mechanism works as designed, and not just by accident. + // - that the initial stack does not contain a lisp pointer after it is not needed. + // (a regression test asserts that not even a THREAD instance is on the stack) + funcall1(startfun, (lispobj)lispthread); // both pinned + // Close the GC region and unlink from all_threads + unregister_thread(th, SCRIBBLE); -#ifdef OS_THREAD_STACK -extern void* funcall1_switching_stack(void*, void *(*fun)(void *)) -# ifdef LISP_FEATURE_X86_64 - __attribute__((sysv_abi)) -# endif - ; - -void* new_thread_trampoline_switch_stack(void* arg) { - struct thread *th = (struct thread *)arg; - void* ret = funcall1_switching_stack(arg, new_thread_trampoline); + return 0; +} - schedule_thread_post_mortem(th); - return ret; +#ifdef LISP_FEATURE_OS_THREAD_STACK +extern void* funcall1_switching_stack(void*, void *(*fun)(void *)); +void* new_thread_trampoline_switch_stack(void* th) { + return funcall1_switching_stack(th, new_thread_trampoline); } #endif -static struct thread *create_thread_struct(lispobj); - -void -attach_os_thread(init_thread_data *scribble) +static struct thread* recyclebin_threads; +static struct thread* get_recyclebin_item() { - os_thread_t os = pthread_self(); - odxprint(misc, "attach_os_thread: attaching to %p", os); + struct thread* result = 0; + int rc; + rc = mutex_acquire(&recyclebin_lock); + gc_assert(rc); + if (recyclebin_threads) { + result = recyclebin_threads; + recyclebin_threads = result->next; + } + ignore_value(mutex_release(&recyclebin_lock)); + return result ? result->os_address : 0; +} +static void put_recyclebin_item(struct thread* th) +{ + int rc; + rc = mutex_acquire(&recyclebin_lock); + gc_assert(rc); + th->next = recyclebin_threads; + recyclebin_threads = th; + ignore_value(mutex_release(&recyclebin_lock)); +} +void empty_thread_recyclebin() +{ + if (!recyclebin_threads) return; + sigset_t old; + block_deferrable_signals(&old); + // no big deal if already locked (recursive GC?) + if (TryEnterCriticalSection(&recyclebin_lock)) { + struct thread* this = recyclebin_threads; + while (this) { + struct thread* next = this->next; + free_thread_struct(this); + this = next; + } + recyclebin_threads = 0; + ignore_value(mutex_release(&recyclebin_lock)); + } + thread_sigmask(SIG_SETMASK, &old, 0); +} - struct thread *th = create_thread_struct(NO_TLS_VALUE_MARKER_WIDETAG); +static void attach_os_thread(init_thread_data *scribble) +{ +#ifndef LISP_FEATURE_WIN32 // native threads have no signal maskk block_deferrable_signals(&scribble->oldset); +#endif + void* recycled_memory = get_recyclebin_item(); + struct thread *th = alloc_thread_struct(recycled_memory); #ifndef LISP_FEATURE_SB_SAFEPOINT /* new-lisp-thread-trampoline doesn't like when the GC signal is blocked */ /* FIXME: could be done using a single call to pthread_sigmask together with locking the deferrable signals above. */ - unblock_gc_signals(0, 0); + unblock_gc_signals(); #endif + th->os_kernel_tid = get_nonzero_tid(); + /* win32: While ASSOCIATE_OS_THREAD performs a relatively expensive DuplicateHandle(), + * simplicity here is preferable to the complexity entailed by memoizing the handle + * in a TLS slot and registering a waiter on the foreign thread to close to handle. + * In contrast to the previous approach, the new handle is closed in detach_os_thread(), + * and if C calls lisp again in this thread... then lather, rinse, repeat. + * A benchmark based on 'fcb-threads.impure' shows that we're still 8x faster + * at callback entry than the code as it was prior to git rev 91f86339b4 */ + ASSOCIATE_OS_THREAD(th); + #if !defined(LISP_FEATURE_WIN32) && defined(LISP_FEATURE_C_STACK_IS_CONTROL_STACK) /* On windows, arch_os_thread_init will take care of finding the * stack. */ void *stack_addr; size_t stack_size; -#ifdef LISP_FEATURE_OPENBSD +# ifdef LISP_FEATURE_OPENBSD stack_t stack; - pthread_stackseg_np(os, &stack); + pthread_stackseg_np(th->os_thread, &stack); stack_size = stack.ss_size; stack_addr = (void*)((size_t)stack.ss_sp - stack_size); -#elif defined LISP_FEATURE_SUNOS - stack_t stack; - thr_stksegment(&stack); - stack_size = stack.ss_size; - stack_addr = (void*)((size_t)stack.ss_sp - stack_size); -#elif defined(LISP_FEATURE_DARWIN) - stack_size = pthread_get_stacksize_np(os); - stack_addr = (char*)pthread_get_stackaddr_np(os) - stack_size; -#else +# elif defined LISP_FEATURE_SUNOS + stack_t stack; + thr_stksegment(&stack); + stack_size = stack.ss_size; + stack_addr = (void*)((size_t)stack.ss_sp - stack_size); +# elif defined(LISP_FEATURE_DARWIN) + stack_size = pthread_get_stacksize_np(th->os_thread); + stack_addr = (char*)pthread_get_stackaddr_np(th->os_thread) - stack_size; +# else pthread_attr_t attr; -#ifdef LISP_FEATURE_FREEBSD - pthread_attr_get_np(os, &attr); -#else + pthread_attr_init(&attr); +# if defined LISP_FEATURE_FREEBSD || defined LISP_FEATURE_DRAGONFLY + pthread_attr_get_np(th->os_thread, &attr); +# else int pthread_getattr_np(pthread_t, pthread_attr_t *); - pthread_getattr_np(os, &attr); -#endif + pthread_getattr_np(th->os_thread, &attr); +# endif pthread_attr_getstack(&attr, &stack_addr, &stack_size); pthread_attr_destroy(&attr); -#endif - +# endif th->control_stack_start = stack_addr; th->control_stack_end = (void *) (((uintptr_t) stack_addr) + stack_size); #endif - init_new_thread(th, scribble, 0); - - uword_t stacksize - = (uword_t) th->control_stack_end - (uword_t) th->control_stack_start; - odxprint(misc, "attach_os_thread: attached %p as %p (0x%lx bytes stack)", - os, th, (long) stacksize); + /* We don't protect the control stack when adopting a foreign thread + * because we wouldn't know where to put the guard */ + init_new_thread(th, scribble, + /* recycled memory already had mprotect() done, + * so avoid 2 syscalls when possible */ + recycled_memory ? 0 : GUARD_BINDING_STACK|GUARD_ALIEN_STACK); } -void -detach_os_thread(init_thread_data *scribble) +static void detach_os_thread(init_thread_data *scribble) { - struct thread *th = arch_os_get_current_thread(); - odxprint(misc, "detach_os_thread: detaching"); + struct thread *th = get_sb_vm_thread(); - undo_init_new_thread(th, scribble); +#if defined(LISP_FEATURE_WIN32) + CloseHandle((HANDLE)th->os_thread); +#endif - odxprint(misc, "deattach_os_thread: detached"); -#ifdef LISP_FEATURE_GCC_TLS - is_lisp_thread = 0; -#else - pthread_setspecific(lisp_thread, (void *)0); +#ifdef LISP_FEATURE_DARWIN + pthread_setspecific(foreign_thread_ever_lispified, (void*)1); +#endif + unregister_thread(th, scribble); + + /* We have to clear a STOP_FOR_GC signal if pending. Consider: + * - on entry to unregister_thread, we block all signals + * - simultaneously some other thread decides that it needs to initiate a GC + * - that thread observes that this thread exists in all_threads and sends + * STOP_FOR_GC, so it becomes pending but undeliverable in this thread + * - immediately after blocking signals, we change state to DEAD, + * which allows the GCing thread to ignore this thread + * (it sees the state change criterion as having been satisfied) + * - the GCing thread releases the all_threads lock + * - this thread acquires the lock and removes itself from all_threads, + * and indicates that it is no longer a lisp thread + * - but STOP_FOR_GC is pending because it was in the blocked set. + * Bad things happen unless we clear the pending GC signal. + */ +#if !defined LISP_FEATURE_SB_SAFEPOINT && !defined LISP_FEATURE_DARWIN + sigset_t pending; + sigpending(&pending); + if (sigismember(&pending, SIG_STOP_FOR_GC)) { + int sig, rc; + rc = sigwait(&gc_sigset, &sig); + gc_assert(rc == 0 && sig == SIG_STOP_FOR_GC); + } #endif + put_recyclebin_item(th); +#ifndef LISP_FEATURE_WIN32 // native threads have no signal mask thread_sigmask(SIG_SETMASK, &scribble->oldset, 0); - free_thread_struct(th); +#endif } #if defined(LISP_FEATURE_X86_64) && !defined(LISP_FEATURE_WIN32) @@ -607,16 +784,12 @@ callback_wrapper_trampoline( #endif lispobj arg0, lispobj arg1, lispobj arg2) { -#if defined(LISP_FEATURE_WIN32) - pthread_np_notice_thread(); -#endif - struct thread* th = arch_os_get_current_thread(); + struct thread* th = get_sb_vm_thread(); if (!th) { /* callback invoked in non-lisp thread */ init_thread_data scribble; attach_os_thread(&scribble); -#ifdef LISP_FEATURE_SB_SAFEPOINT + WITH_GC_AT_SAFEPOINTS_ONLY() -#endif { funcall3(StaticSymbolFunction(ENTER_FOREIGN_CALLBACK), arg0,arg1,arg2); } @@ -626,12 +799,10 @@ callback_wrapper_trampoline( #ifdef LISP_FEATURE_WIN32 /* arg2 is the pointer to a return value, which sits on the stack */ - th->carried_base_pointer = (os_context_register_t) *(((void**)arg2)-1); + thread_extra_data(th)->carried_base_pointer = (os_context_register_t) *(((void**)arg2)-1); #endif -#ifdef LISP_FEATURE_SB_SAFEPOINT WITH_GC_AT_SAFEPOINTS_ONLY() -#endif { #if defined(LISP_FEATURE_X86_64) && !defined(LISP_FEATURE_WIN32) funcall_alien_callback(arg1, arg2, arg0, th); @@ -640,6 +811,7 @@ callback_wrapper_trampoline( #endif } } + #endif /* LISP_FEATURE_SB_THREAD */ /* this is called from any other thread to create the new one, and @@ -658,83 +830,94 @@ callback_wrapper_trampoline( * |...|------------------------------------------------------------| * 2MiB 1MiB 1MiB (*) (**) * - * | (*) interrupt contexts and Lisp TLS | (**) altstack | - * |-----------|--------------------------|------------|--------------| - * | interrupt | struct + dynamically | nonpointer | sigstack | - * | contexts | thread assigned TLS | data | | - * +-----------+--------------------------|------------+--------------| - * | 1K words | <--- TLS_SIZE words ---> | ~200 bytes | 32*SIGSTKSZ | - * ^ thread base + * | Lisp TLS | (**) altstack | + * |-----------------------------------|----------|--------------| + * | thread + struct + dynamically | extra | sigstack | + * | header thread assigned TLS | data | | + * +---------+-------------------------|----------+--------------| + * | | <--- TLS_SIZE words --> | ~1kb | 32*SIGSTKSZ | + * ^ thread base * * (1) = control stack start. default size shown * (2) = binding stack start. size = BINDING_STACK_SIZE * (3) = alien stack start. size = ALIEN_STACK_SIZE * (4) = C safepoint page. size = BACKEND_PAGE_BYTES or 0 - * (5) = per_thread_data. size = (MAX_INTERRUPTS + TLS_SIZE) words - * (6) = nonpointer_thread_data and signal stack. + * (5) = per_thread_data. size = (THREAD_HEADER_SLOTS+TLS_SIZE) words + * (6) = arbitrarily-sized "extra" data and signal stack. * * (0) and (1) may coincide; (4) and (5) may coincide * * - Lisp TLS overlaps 'struct thread' so that the first N (~30) words * have preassigned TLS indices. * - * - nonpointer data are not in 'struct thread' because placing them there + * - "extra" data are not in 'struct thread' because placing them there * makes it tough to calculate addresses in 'struct thread' from Lisp. * (Every 'struct thread' slot has a known size) * * On sb-safepoint builds one page before the thread base is used for the foreign calls safepoint. */ -static struct thread * -create_thread_struct(lispobj start_routine) { -#if defined(LISP_FEATURE_SB_THREAD) || defined(LISP_FEATURE_WIN32) - unsigned int i; -#endif - - /* May as well allocate all the spaces at once: it saves us from - * having to decide what to do if only some of the allocations - * succeed. SPACES must be appropriately aligned, since the GC - * expects the control stack to start at a page boundary -- and - * the OS may have even more rigorous requirements. We can't rely - * on the alignment passed from os_validate, since that might - * assume the current (e.g. 4k) pagesize, while we calculate with - * the biggest (e.g. 64k) pagesize allowed by the ABI. */ - void *spaces = os_validate(MOVABLE|IS_THREAD_STRUCT, NULL, THREAD_STRUCT_SIZE); - if(!spaces) - return NULL; +struct thread * +alloc_thread_struct(void* spaces) { + /* Allocate the thread structure in one fell swoop as there is no way to recover + * from failing to obtain contiguous memory. Note that the OS may have a smaller + * alignment granularity than BACKEND_PAGE_BYTES so we may have to adjust the + * result to make it conform to our guard page alignment requirement. */ + boolean zeroize_stack = 0; + if (spaces) { + // If reusing memory from a previously exited thread, start by removing + // some old junk from the stack. This is imperfect since we only clear a little + // at the top, but doing so enables diagnosing some garbage-retention issues + // using a fine-toothed comb. It would not be possible at all to diagnose + // if any newly started thread could refer a dead thread's heap objects. + zeroize_stack = 1; + } else { + spaces = os_alloc_gc_space(THREAD_STRUCT_CORE_SPACE_ID, MOVABLE, + NULL, THREAD_STRUCT_SIZE); + if (!spaces) return NULL; + } /* Aligning up is safe as THREAD_STRUCT_SIZE has * THREAD_ALIGNMENT_BYTES padding. */ char *aligned_spaces = PTR_ALIGN_UP(spaces, THREAD_ALIGNMENT_BYTES); - char* csp_page= - (aligned_spaces+ - thread_control_stack_size+ - BINDING_STACK_SIZE+ - ALIEN_STACK_SIZE + - (MAX_INTERRUPTS*sizeof(os_context_t*))); + char* csp_page = aligned_spaces + thread_control_stack_size + + BINDING_STACK_SIZE + ALIEN_STACK_SIZE; // Refer to the ASCII art in the block comment above - struct thread *th = (void*)(csp_page + THREAD_CSP_PAGE_SIZE); + struct thread *th = (void*)(csp_page + THREAD_CSP_PAGE_SIZE + + THREAD_HEADER_SLOTS*N_WORD_BYTES); + +#ifdef LISP_FEATURE_SB_SAFEPOINT + // Out of caution I'm supposing that the last thread to use this memory + // might have left this page as read-only. Could it? I have no idea. + os_protect(csp_page, THREAD_CSP_PAGE_SIZE, OS_VM_PROT_READ|OS_VM_PROT_WRITE); +#endif #ifdef LISP_FEATURE_SB_THREAD - lispobj* tls = (lispobj*)th; - for(i = 0; i < (unsigned int)(dynamic_values_bytes/N_WORD_BYTES); i++) - tls[i] = NO_TLS_VALUE_MARKER_WIDETAG; + memset(th, 0, sizeof *th); + lispobj* ptr = (lispobj*)(th + 1); + lispobj* end = (lispobj*)((char*)th + dynamic_values_bytes); + memset(ptr, NO_TLS_VALUE_MARKER & 0xFF, (char*)end-(char*)ptr); th->tls_size = dynamic_values_bytes; #endif - uword_t* __attribute__((__unused__)) constants = (uword_t*)th; + + __attribute((unused)) lispobj* tls = (lispobj*)th; +#ifdef THREAD_T_NIL_CONSTANTS_SLOT + tls[THREAD_T_NIL_CONSTANTS_SLOT] = (NIL << 32) | LISP_T; +#endif +#ifdef THREAD_ALIEN_LINKAGE_TABLE_BASE_SLOT + tls[THREAD_ALIEN_LINKAGE_TABLE_BASE_SLOT] = (lispobj)ALIEN_LINKAGE_TABLE_SPACE_START; +#endif #if defined LISP_FEATURE_X86_64 && defined LISP_FEATURE_LINUX - constants[THREAD_MSAN_XOR_CONSTANT_SLOT] = 0x500000000000; + tls[THREAD_MSAN_XOR_CONSTANT_SLOT] = 0x500000000000; #endif -#ifdef LISP_FEATURE_GENCGC -#ifdef THREAD_VARYOBJ_CARD_MARKS_SLOT - extern unsigned int* varyobj_page_touched_bits; - constants[THREAD_VARYOBJ_SPACE_ADDR_SLOT] = VARYOBJ_SPACE_START; - constants[THREAD_VARYOBJ_CARD_COUNT_SLOT] = varyobj_space_size / IMMOBILE_CARD_BYTES; - constants[THREAD_VARYOBJ_CARD_MARKS_SLOT] = (lispobj)varyobj_page_touched_bits; +#ifdef LAYOUT_OF_FUNCTION + tls[THREAD_FUNCTION_LAYOUT_SLOT] = LAYOUT_OF_FUNCTION << 32; #endif - th->dynspace_addr = DYNAMIC_SPACE_START; - th->dynspace_card_count = page_table_pages; - th->dynspace_pte_base = (lispobj)page_table; +#ifdef THREAD_TEXT_CARD_MARKS_SLOT + extern unsigned int* text_page_touched_bits; + tls[THREAD_TEXT_SPACE_ADDR_SLOT] = TEXT_SPACE_START; + tls[THREAD_TEXT_CARD_COUNT_SLOT] = text_space_size / IMMOBILE_CARD_BYTES; + tls[THREAD_TEXT_CARD_MARKS_SLOT] = (lispobj)text_page_touched_bits; #endif th->os_address = spaces; @@ -742,71 +925,94 @@ create_thread_struct(lispobj start_routine) { th->binding_stack_start= (lispobj*)((char*)th->control_stack_start+thread_control_stack_size); th->control_stack_end = th->binding_stack_start; - th->control_stack_guard_page_protected = T; + + if (zeroize_stack) { +#if GENCGC_IS_PRECISE + /* Clear the entire control stack. Without this I was able to induce a GC failure + * in a test which hammered on thread creation for hours. The control stack is + * scavenged before the heap, so a stale word could point to the start (or middle) + * of an object using a bad lowtag, for whatever object formerly was there. + * Then a wrong transport function would be called and (if it worked at all) would + * place a wrongly tagged FP into a word that might not be the base of an object. + * Assume for simplicity (as is true) that stacks grow upward if GENCGC_IS_PRECISE. + * This could just call scrub_thread_control_stack but the comment there says that + * it's a lame algorithm and only mostly right - it stops after (1<<12) words + * and checks if the next is nonzero, looping again if it isn't. + * There's no reason not to be exactly right here instead of probably right */ + memset((char*)th->control_stack_start, 0, + // take off 2 pages because of the soft and hard guard pages + thread_control_stack_size - 2*os_vm_page_size); +#else + /* This is a little wasteful of cycles to pre-zero the pthread overhead (which in glibc + * resides at the highest stack addresses) comprising about 5kb, below which is the lisp + * stack. We don't need to zeroize above the lisp stack end, but we don't know exactly + * where that will be. Zeroizing more than necessary is conservative, and helps ensure + * that garbage retention from reused stacks does not pose a huge problem. */ + memset((char*)th->control_stack_end - 16384, 0, 16384); +#endif + } + + th->state_word.control_stack_guard_page_protected = 1; th->alien_stack_start= (lispobj*)((char*)th->binding_stack_start+BINDING_STACK_SIZE); set_binding_stack_pointer(th,th->binding_stack_start); - th->this=th; - th->os_thread=0; -#if defined(LAYOUT_OF_FUNCTION) && defined(LISP_FEATURE_SB_THREAD) - constants[THREAD_FUNCTION_LAYOUT_SLOT] = LAYOUT_OF_FUNCTION << 32; -#endif + th->this = th; + th->os_kernel_tid = 0; + th->os_thread = 0; // Once allocated, the allocation profiling buffer sticks around. // If present and enabled, assign into the new thread. th->profile_data = (uword_t*)(alloc_profiling ? alloc_profile_buffer : 0); -#ifdef LISP_FEATURE_SB_SAFEPOINT # ifdef LISP_FEATURE_WIN32 - th->carried_base_pointer = 0; + thread_extra_data(th)->carried_base_pointer = 0; # endif - th->csp_around_foreign_call = (lispobj *)th - 1; -#endif - - struct nonpointer_thread_data *nonpointer_data - = (void *)((char*)th + dynamic_values_bytes); - th->interrupt_data = &nonpointer_data->interrupt_data; -#ifdef LISP_FEATURE_SB_THREAD -# ifndef LISP_FEATURE_SB_SAFEPOINT - th->state_sem = &nonpointer_data->state_sem; - th->state_not_running_sem = &nonpointer_data->state_not_running_sem; - th->state_not_stopped_sem = &nonpointer_data->state_not_stopped_sem; - os_sem_init(th->state_sem, 1); - os_sem_init(th->state_not_running_sem, 0); - os_sem_init(th->state_not_stopped_sem, 0); - th->state_not_running_waitcount = 0; - th->state_not_stopped_waitcount = 0; -# endif - -#endif - th->state=STATE_RUNNING; -#ifdef ALIEN_STACK_GROWS_DOWNWARD - th->alien_stack_pointer=(lispobj*)((char*)th->alien_stack_start - + ALIEN_STACK_SIZE-N_WORD_BYTES); + struct extra_thread_data *extra_data = thread_extra_data(th); + memset(extra_data, 0, sizeof *extra_data); + +#if defined LISP_FEATURE_SB_THREAD && !defined LISP_FEATURE_SB_SAFEPOINT + os_sem_init(&extra_data->state_sem, 1); + os_sem_init(&extra_data->state_not_running_sem, 0); + os_sem_init(&extra_data->state_not_stopped_sem, 0); +#endif +#if defined LISP_FEATURE_UNIX && defined LISP_FEATURE_SB_THREAD + os_sem_init(&extra_data->sprof_sem, 0); +#endif + extra_data->sprof_lock = 0; + th->sprof_data = 0; + + th->state_word.state = STATE_RUNNING; + th->state_word.sprof_enable = 0; + th->state_word.user_thread_p = 1; + + lispobj* alien_stack_end = (lispobj*)((char*)th->alien_stack_start + ALIEN_STACK_SIZE); +#ifdef ALIEN_STACK_GROWS_UPWARD + th->alien_stack_pointer = alien_stack_start; +#elif defined LISP_FEATURE_X86 || defined LISP_FEATURE_X86_64 + /* It is not necessary to subtract a word from the starting stack pointer + * because consuming C stack space pre-decrements before using the pointer. + * So this choice has nothing to do with saving a word of memory, and everything + * to do with my lack of understanding of the conventions for non-x86. */ + th->alien_stack_pointer = alien_stack_end; #else - th->alien_stack_pointer=(lispobj*)((char*)th->alien_stack_start); + th->alien_stack_pointer = alien_stack_end - 1; #endif -#ifdef LISP_FEATURE_SB_THREAD - th->pseudo_atomic_bits=0; +#ifdef HAVE_THREAD_PSEUDO_ATOMIC_BITS_SLOT + memset(&th->pseudo_atomic_bits, 0, sizeof th->pseudo_atomic_bits); #elif defined LISP_FEATURE_GENCGC clear_pseudo_atomic_atomic(th); clear_pseudo_atomic_interrupted(th); #endif -#ifdef LISP_FEATURE_GENCGC - gc_init_region(&th->alloc_region); -# if defined(LISP_FEATURE_SB_SAFEPOINT_STRICTLY) && !defined(LISP_FEATURE_WIN32) - gc_init_region(&th->sprof_alloc_region); -# endif -#endif + INIT_THREAD_REGIONS(th); #ifdef LISP_FEATURE_SB_THREAD /* This parallels the same logic in globals.c for the * single-threaded foreign_function_call_active, KLUDGE and * all. */ #if defined(LISP_FEATURE_X86) || defined(LISP_FEATURE_X86_64) th->foreign_function_call_active = 0; -#else +#elif !defined(LISP_FEATURE_ARM64) // uses control_stack_start th->foreign_function_call_active = 1; #endif #endif @@ -827,12 +1033,22 @@ create_thread_struct(lispobj start_routine) { #endif #ifndef LISP_FEATURE_C_STACK_IS_CONTROL_STACK access_control_stack_pointer(th)=th->control_stack_start; + access_control_frame_pointer(th)=0; #endif - th->interrupt_data->pending_handler = 0; - th->interrupt_data->gc_blocked_deferrables = 0; -#if GENCGC_IS_PRECISE - th->interrupt_data->allocation_trap_context = 0; + thread_interrupt_data(th).pending_handler = 0; + thread_interrupt_data(th).gc_blocked_deferrables = 0; +#if HAVE_ALLOCATION_TRAP_CONTEXT + thread_interrupt_data(th).allocation_trap_context = 0; +#endif +#if defined LISP_FEATURE_PPC64 + /* Storing a 0 into code coverage mark bytes or GC card mark bytes + * can be done from the low byte of the thread base register. + * The thread alignment is BACKEND_PAGE_BYTES (from thread.h), but seeing as this is + * a similar-but-different requirement, it pays to double-check */ + if ((lispobj)th & 0xFF) lose("Thread struct not at least 256-byte-aligned"); + extern unsigned char* gc_card_mark; + th->card_table = (lispobj)gc_card_mark; #endif #ifdef LISP_FEATURE_SB_THREAD @@ -846,113 +1062,39 @@ create_thread_struct(lispobj start_routine) { # define INITIALIZE_TLS(sym,val) SYMBOL(sym)->value = val #endif #include "genesis/thread-init.inc" - th->no_tls_value_marker = start_routine; + th->no_tls_value_marker = NO_TLS_VALUE_MARKER; #if defined(LISP_FEATURE_WIN32) - for (i = 0; i<sizeof(th->private_events.events)/ - sizeof(th->private_events.events[0]); ++i) { - th->private_events.events[i] = CreateEvent(NULL,FALSE,FALSE,NULL); - } - th->synchronous_io_handle_and_flag = 0; + int i; + for (i = 0; i<NUM_PRIVATE_EVENTS; ++i) + thread_private_events(th,i) = CreateEvent(NULL,FALSE,FALSE,NULL); + thread_extra_data(th)->synchronous_io_handle_and_flag = 0; #endif th->stepping = 0; return th; } - -void create_initial_thread(lispobj initial_function) { - struct thread *th = create_thread_struct(initial_function); -#if defined(LISP_FEATURE_SB_THREAD) && !defined(LISP_FEATURE_GCC_TLS) - pthread_key_create(&lisp_thread, 0); -#endif - if(th) { - initial_thread_trampoline(th); /* no return */ - } else lose("can't create initial thread"); -} - #ifdef LISP_FEATURE_SB_THREAD - -#ifndef __USE_XOPEN2K -extern int pthread_attr_setstack (pthread_attr_t *__attr, void *__stackaddr, - size_t __stacksize); -#endif - -/* Call pthread_create() and return 1 for success, 0 for failure */ -boolean create_os_thread(struct thread *th,os_thread_t *kid_tid) +#ifdef LISP_FEATURE_WIN32 +uword_t create_thread(struct thread* th) { - /* The new thread inherits the restrictive signal mask set here, - * and enables signals again when it is set up properly. */ - sigset_t oldset; - int retcode = 0; - boolean success = 0; - - /* Blocking deferrable signals is enough, no need to block - * SIG_STOP_FOR_GC because the child process is not linked onto - * all_threads until it's ready. */ - block_deferrable_signals(&oldset); - - pthread_attr_t attr; - if (pthread_attr_init(&attr) == 0) { - - /* See perform_thread_post_mortem for at least one reason why this lock is necessary */ - retcode = pthread_mutex_lock(&create_thread_lock); - gc_assert(retcode == 0); - - /* call_into_lisp_first_time switches the stack for the initial - * thread. For the others, we use this. */ - if ( -#ifdef OS_THREAD_STACK - pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN) || - (retcode = pthread_create(kid_tid, &attr, new_thread_trampoline_switch_stack, th)) -#else - -# ifdef LISP_FEATURE_WIN32 - pthread_attr_setstacksize(&attr, thread_control_stack_size) || -# elif defined(LISP_FEATURE_C_STACK_IS_CONTROL_STACK) - pthread_attr_setstack(&attr, th->control_stack_start, thread_control_stack_size) || -# else - pthread_attr_setstack(&attr, th->alien_stack_start, ALIEN_STACK_SIZE) || -# endif -# ifdef LISP_FEATURE_NETBSD - /* Even though the manpage says pthread_attr_setstack - would override the guard page, it's no longer true. */ - pthread_attr_setguardsize(&attr, 0) || -# endif - - (retcode = pthread_create(kid_tid, &attr, new_thread_trampoline, th)) -#endif - ) { - perror("create_os_thread"); - } else { - success = 1; - } - retcode = pthread_mutex_unlock(&create_thread_lock); - gc_assert(retcode == 0); - pthread_attr_destroy(&attr); + unsigned int tid; + struct extra_thread_data *data = thread_extra_data(th); + data->blocked_signal_set = deferrable_sigset; + // It's somewhat customary in the win32 API to start threads as suspended. + th->os_thread = + _beginthreadex(NULL, thread_control_stack_size, new_thread_trampoline, th, + CREATE_SUSPENDED, &tid); + boolean success = th->os_thread != 0; + if (success) { + th->os_kernel_tid = tid; + ResumeThread((HANDLE)th->os_thread); } - - thread_sigmask(SIG_SETMASK,&oldset,0); return success; } +#endif -os_thread_t create_thread(lispobj start_routine) { - struct thread *th, *thread = arch_os_get_current_thread(); - os_thread_t kid_tid = 0; - - /* Must defend against async unwinds. */ - if (read_TLS(INTERRUPTS_ENABLED, thread) != NIL) - lose("create_thread is not safe when interrupts are enabled."); - - /* Assuming that a fresh thread struct has no lisp objects in it, - * linking it to all_threads can be left to the thread itself - * without fear of gc lossage. 'start_routine' violates this - * assumption and must stay pinned until the child starts up. */ - th = create_thread_struct(start_routine); - if (th && !create_os_thread(th, &kid_tid)) { - free_thread_struct(th); - kid_tid = 0; - } - return kid_tid; -} +int try_acquire_gc_lock() { return TryEnterCriticalSection(&in_gc_lock); } +int release_gc_lock() { return mutex_release(&in_gc_lock); } /* stopping the world is a two-stage process. From this thread we signal * all the others with SIG_STOP_FOR_GC. The handler for this signal does @@ -962,96 +1104,122 @@ os_thread_t create_thread(lispobj start_routine) { /* * (With SB-SAFEPOINT, see the definitions in safepoint.c instead.) */ -#ifndef LISP_FEATURE_SB_SAFEPOINT +#if !defined LISP_FEATURE_SB_SAFEPOINT && !defined STANDALONE_LDB /* To avoid deadlocks when gc stops the world all clients of each * mutex must enable or disable SIG_STOP_FOR_GC for the duration of - * holding the lock, but they must agree on which. */ + * holding the lock, but they must agree on which. + * [The preceding remark is probably wrong - STOP_FOR_GC is a signal + * that is directed to a thread, so the "wrong" thread would never + * respond to someone else's STOP_FOR_GC. I'm leaving the comment + * just case someone can decipher it and decide to delete it] + * + * A note about ESRCH: tchnically ESRCH can happen if an OS thread ceases + * to exist, while the thread library has a representation of the thread + * because pthread_join() wasn't invoked on it yet. + * ESRCH can't oocur for us because: + * - if a thread was still linked in all_threads at the acquire of all_threads lock, + * then that thread can't make progress in its termination code, because it's + * waiting on the lock. If it changed its state to DEAD, but we perceived it as + * RUNNING, it now must be blocked on the all_threads_lock and it can't disappear. + * - ESRCH is not guaranteed to be returned anyway, and Linux man page doesn't even + * list it as a possible outcome of pthread_kill. + * Also, there used to be assertion that "thread_state(p)==STATE_DEAD)" on ESRCH + * error, but that's saying that there is still memory backing 'struct thread' + * (so that dereferencing was valid), but if dereferencing was valid, then the thread + * can't have died (i.e. if ESRCH could be returned, then that implies that + * the memory shouldn't be there) */ void gc_stop_the_world() { - struct thread *p,*th=arch_os_get_current_thread(); - int status, lock_ret; - /* KLUDGE: Stopping the thread during pthread_create() causes deadlock - * on FreeBSD. */ - FSHOW_SIGNAL((stderr,"/gc_stop_the_world:waiting on create_thread_lock\n")); - lock_ret = pthread_mutex_lock(&create_thread_lock); - gc_assert(lock_ret == 0); - FSHOW_SIGNAL((stderr,"/gc_stop_the_world:got create_thread_lock\n")); - FSHOW_SIGNAL((stderr,"/gc_stop_the_world:waiting on lock\n")); - /* keep threads from starting while the world is stopped. */ - lock_ret = pthread_mutex_lock(&all_threads_lock); \ - gc_assert(lock_ret == 0); - - FSHOW_SIGNAL((stderr,"/gc_stop_the_world:got lock\n")); +#ifdef COLLECT_GC_STATS + struct timespec stw_begin_time, stw_end_time; + // Measuring the wait time has to use a realtime clock, not a thread clock + // because sleeping below in a sem_wait needs to accrue time. + clock_gettime(CLOCK_MONOTONIC, &stw_begin_time); +#endif + struct thread *th, *me = get_sb_vm_thread(); + int rc; + + /* Keep threads from registering with GC while the world is stopped. */ + rc = mutex_acquire(&all_threads_lock); + gc_assert(rc); + /* stop all other threads by sending them SIG_STOP_FOR_GC */ - for(p=all_threads; p; p=p->next) { - gc_assert(p->os_thread != 0); - FSHOW_SIGNAL((stderr,"/gc_stop_the_world: thread=%lu, state=%x\n", - p->os_thread, thread_state(p))); - if((p!=th) && ((thread_state(p)==STATE_RUNNING))) { - FSHOW_SIGNAL((stderr,"/gc_stop_the_world: suspending thread %lu\n", - p->os_thread)); - /* We already hold all_thread_lock, P can become DEAD but - * cannot exit, ergo it's safe to use pthread_kill. */ - status=pthread_kill(p->os_thread,SIG_STOP_FOR_GC); - if (status==ESRCH) { - /* This thread has exited. */ - gc_assert(thread_state(p)==STATE_DEAD); - } else if (status) { - lose("cannot send suspend thread=%lx: %d, %s", - // KLUDGE: assume that os_thread can be cast as long. + for_each_thread(th) { + if (th != me) { + gc_assert(th->os_thread != 0); + struct extra_thread_data *semaphores = thread_extra_data(th); + os_sem_wait(&semaphores->state_sem, "notify stop"); + int state = get_thread_state(th); + if (state == STATE_RUNNING) { + rc = pthread_kill(th->os_thread,SIG_STOP_FOR_GC); + /* This used to bogusly check for ESRCH. + * I changed the ESRCH case to just fall into lose() */ + if (rc) lose("cannot suspend thread %p: %d, %s", + // KLUDGE: assume that os_thread can be cast as pointer. // See comment in 'interr.h' about that. - (long)p->os_thread,status,strerror(status)); + (void*)th->os_thread, rc, strerror(rc)); } + os_sem_post(&semaphores->state_sem, "notified stop"); } } - FSHOW_SIGNAL((stderr,"/gc_stop_the_world:signals sent\n")); - for(p=all_threads;p;p=p->next) { - if (p!=th) { - FSHOW_SIGNAL - ((stderr, - "/gc_stop_the_world: waiting for thread=%lu: state=%x\n", - p->os_thread, thread_state(p))); - wait_for_thread_state_change(p, STATE_RUNNING); - if (p->state == STATE_RUNNING) - lose("/gc_stop_the_world: unexpected state"); + for_each_thread(th) { + if (th != me) { + __attribute__((unused)) int state = thread_wait_until_not(STATE_RUNNING, th); + gc_assert(state != STATE_RUNNING); } } - FSHOW_SIGNAL((stderr,"/gc_stop_the_world:end\n")); + event0("/gc_stop_the_world:end"); +#ifdef COLLECT_GC_STATS + clock_gettime(CLOCK_MONOTONIC, &stw_end_time); + stw_elapsed = (stw_end_time.tv_sec - stw_begin_time.tv_sec)*1000000000L + + (stw_end_time.tv_nsec - stw_begin_time.tv_nsec); + gc_start_time = stw_end_time; +#endif } void gc_start_the_world() { - struct thread *p,*th=arch_os_get_current_thread(); +#ifdef COLLECT_GC_STATS + struct timespec gc_end_time; + clock_gettime(CLOCK_MONOTONIC, &gc_end_time); + long gc_elapsed = (gc_end_time.tv_sec - gc_start_time.tv_sec)*1000000000L + + (gc_end_time.tv_nsec - gc_start_time.tv_nsec); + if (stw_elapsed < 0 || gc_elapsed < 0) { + char errmsg[] = "GC: Negative times?\n"; + ignore_value(write(2, errmsg, sizeof errmsg-1)); + } else { + stw_sum_duration += stw_elapsed; + if (stw_elapsed < stw_min_duration) stw_min_duration = stw_elapsed; + if (stw_elapsed > stw_max_duration) stw_max_duration = stw_elapsed; + gc_sum_duration += gc_elapsed; + if (gc_elapsed < gc_min_duration) gc_min_duration = gc_elapsed; + if (gc_elapsed > gc_max_duration) gc_max_duration = gc_elapsed; + ++n_gcs_done; + } +#endif + struct thread *th, *me = get_sb_vm_thread(); int lock_ret; /* if a resumed thread creates a new thread before we're done with - * this loop, the new thread will get consed on the front of - * all_threads, but it won't have been stopped so won't need - * restarting */ - FSHOW_SIGNAL((stderr,"/gc_start_the_world:begin\n")); - for(p=all_threads;p;p=p->next) { - gc_assert(p->os_thread!=0); - if (p!=th) { - lispobj state = thread_state(p); + * this loop, the new thread will be suspended waiting to acquire + * the all_threads lock */ + for_each_thread(th) { + gc_assert(th->os_thread); + if (th != me) { + /* I don't know if a normal load is fine here. I think we can't read + * any value other than what was already observed? + * No harm in being cautious though with regard to compiler reordering */ + int state = get_thread_state(th); if (state != STATE_DEAD) { - if(state != STATE_STOPPED) { - lose("gc_start_the_world: wrong thread state is %"OBJ_FMTX, - (lispobj)fixnum_value(state)); - } - FSHOW_SIGNAL((stderr, "/gc_start_the_world: resuming %lu\n", - p->os_thread)); - set_thread_state(p, STATE_RUNNING); + if(state != STATE_STOPPED) + lose("gc_start_the_world: bad thread state %x", state); + set_thread_state(th, STATE_RUNNING, 0); } } } - lock_ret = pthread_mutex_unlock(&all_threads_lock); - gc_assert(lock_ret == 0); - lock_ret = pthread_mutex_unlock(&create_thread_lock); - gc_assert(lock_ret == 0); - - - FSHOW_SIGNAL((stderr,"/gc_start_the_world:end\n")); + lock_ret = mutex_release(&all_threads_lock); + gc_assert(lock_ret); } #endif /* !LISP_FEATURE_SB_SAFEPOINT */ @@ -1067,18 +1235,7 @@ thread_yield() #endif } -int -wake_thread(os_thread_t os_thread) -{ -#if defined(LISP_FEATURE_WIN32) - return kill_safely(os_thread, 1); -#elif !defined(LISP_FEATURE_SB_THRUPTION) - return kill_safely(os_thread, SIGPIPE); -#else - return wake_thread_posix(os_thread); -#endif -} - +#ifdef LISP_FEATURE_SB_SAFEPOINT /* If the thread id given does not belong to a running thread (it has * exited or never even existed) pthread_kill _may_ fail with ESRCH, * but it is also allowed to just segfault, see @@ -1095,18 +1252,12 @@ wake_thread(os_thread_t os_thread) * Note (DFL, 2011-06-22): At the time of writing, this function is only * used for INTERRUPT-THREAD, hence the wake_thread special-case for * Windows is OK. */ -int -kill_safely(os_thread_t os_thread, int signal) +void wake_thread(struct thread_instance* lispthread) { - FSHOW_SIGNAL((stderr,"/kill_safely: %lu, %d\n", os_thread, signal)); - { -#ifdef LISP_FEATURE_SB_THREAD - sigset_t oldset; - struct thread *thread; - /* Frequent special case: resignalling to self. The idea is - * that leave_region safepoint will acknowledge the signal, so - * there is no need to take locks, roll thread to safepoint - * etc. */ +#ifdef LISP_FEATURE_WIN32 + /* META: why is this comment about safepoint builds mentioning + * gc_stop_the_world() ? Never the twain shall meet. */ + /* Kludge (on safepoint builds): At the moment, this isn't just * an optimization; rather it masks the fact that * gc_stop_the_world() grabs the all_threads mutex without @@ -1115,62 +1266,32 @@ kill_safely(os_thread_t os_thread, int signal) * would go wrong. Why are we running interruptions while * stopping the world though? Test case is (:ASYNC-UNWIND * :SPECIALS), especially with s/10/100/ in both loops. */ - /* From the linux man page on pthread_self() - - * "variables of type pthread_t can't portably be compared using - * the C equality operator (==); use pthread_equal(3) instead." */ - if (thread_equal(os_thread, pthread_self())) { - pthread_kill(os_thread, signal); -#ifdef LISP_FEATURE_WIN32 + + /* Frequent special case: resignalling to self. The idea is + * that leave_region safepoint will acknowledge the signal, so + * there is no need to take locks, roll thread to safepoint + * etc. */ + struct thread* thread = (void*)lispthread->uw_primitive_thread; + if (thread == get_sb_vm_thread()) { + sb_pthr_kill(thread, 1); // can't fail check_pending_thruptions(NULL); -#endif - return 0; + return; } - - /* pthread_kill is not async signal safe and we don't want to be - * interrupted while holding the lock. */ + // block_deferrables + mutex_lock looks very unnecessary here, + // but without them, make-target-contrib hangs in bsd-sockets. + sigset_t oldset; block_deferrable_signals(&oldset); - pthread_mutex_lock(&all_threads_lock); - for (thread = all_threads; thread; thread = thread->next) { - if (thread->os_thread == os_thread) { - int status = pthread_kill(os_thread, signal); - if (status) - lose("kill_safely: pthread_kill failed with %d", status); -#if defined(LISP_FEATURE_WIN32) && defined(LISP_FEATURE_SB_THRUPTION) - wake_thread_win32(thread); -#endif - break; - } - } - pthread_mutex_unlock(&all_threads_lock); + mutex_acquire(&all_threads_lock); + sb_pthr_kill(thread, 1); // can't fail +# ifdef LISP_FEATURE_SB_SAFEPOINT + wake_thread_impl(lispthread); +# endif + mutex_release(&all_threads_lock); thread_sigmask(SIG_SETMASK,&oldset,0); - if (thread) - return 0; - else - return -1; -#elif defined(LISP_FEATURE_WIN32) - return 0; -#else - int status; - if (os_thread != 0) - lose("kill_safely: who do you want to kill? %d?", os_thread); - /* Dubious (as in don't know why it works) workaround for the - * signal sometimes not being generated on darwin. */ -#ifdef LISP_FEATURE_DARWIN - { - sigset_t oldset; - sigprocmask(SIG_BLOCK, &deferrable_sigset, &oldset); - status = raise(signal); - sigprocmask(SIG_SETMASK,&oldset,0); - } +#elif defined LISP_FEATURE_SB_SAFEPOINT + wake_thread_impl(lispthread); #else - status = raise(signal); + pthread_kill(lispthread->uw_os_thread, SIGURG); #endif - if (status == 0) { - return 0; - } else { - lose("cannot raise signal %d, %d %s", - signal, status, strerror(errno)); - } -#endif - } } +#endif diff --git a/src/runtime/thread.h b/src/runtime/thread.h index bcd852c3ef..db640dae68 100644 --- a/src/runtime/thread.h +++ b/src/runtime/thread.h @@ -11,32 +11,38 @@ #ifdef LISP_FEATURE_GENCGC #include "gencgc-alloc-region.h" #endif -#ifdef LISP_FEATURE_WIN32 -#include "win32-thread-private-events.h" -#endif #include "genesis/symbol.h" #include "genesis/static-symbols.h" +struct thread_state_word { + // - control_stack_guard_page_protected is referenced from + // hand-written assembly code. (grep "THREAD_STATE_WORD_OFFSET") + // - sprof_enable is referenced with SAPs. + // (grep "sb-vm:thread-state-word-slot") + char control_stack_guard_page_protected; + char sprof_enable; // statistical CPU profiler switch + char state; + char user_thread_p; // opposite of lisp's ephemeral-p +#ifdef LISP_FEATURE_64_BIT + char padding[4]; +#endif +}; + +// (DEFCONSTANT +N-SMALL-BUCKETS+ 32) +typedef lispobj size_histogram[32+N_WORD_BITS]; + #include "genesis/thread.h" +#include "genesis/thread-instance.h" #include "genesis/fdefn.h" #include "genesis/vector.h" #include "interrupt.h" #include "validate.h" /* for BINDING_STACK_SIZE etc */ -#define STATE_RUNNING MAKE_FIXNUM(1) -#define STATE_STOPPED MAKE_FIXNUM(2) -#define STATE_DEAD MAKE_FIXNUM(3) +enum threadstate {STATE_RUNNING=1, STATE_STOPPED, STATE_DEAD}; #ifdef LISP_FEATURE_SB_THREAD -lispobj thread_state(struct thread *thread); -void set_thread_state(struct thread *thread, lispobj state); -void wait_for_thread_state_change(struct thread *thread, lispobj state); - -#ifdef LISP_FEATURE_GCC_TLS -extern __thread int is_lisp_thread; -#else -extern pthread_key_t lisp_thread; -#endif +void set_thread_state(struct thread *thread, char state, boolean); +int thread_wait_until_not(int state, struct thread *thread); #endif #if defined(LISP_FEATURE_SB_SAFEPOINT) @@ -45,44 +51,82 @@ struct gcing_safety { }; int handle_safepoint_violation(os_context_t *context, os_vm_address_t addr); -void** os_get_csp(struct thread* th); -void alloc_gc_page(); +void* os_get_csp(struct thread* th); void assert_on_stack(struct thread *th, void *esp); #endif /* defined(LISP_FEATURE_SB_SAFEPOINT) */ -extern int kill_safely(os_thread_t os_thread, int signal); - -#define THREAD_SLOT_OFFSET_WORDS(c) \ - (offsetof(struct thread,c)/(sizeof (struct thread *))) - /* The thread struct is generated from lisp during genesis and it * needs to know the sizes of all its members, but some types may have * arbitrary lengths, thus the pointers are stored instead. This - * structure is used to help allocation of those types, so that the - * pointers can be later shoved into the thread struct. */ -struct nonpointer_thread_data + * structure is used to help allocation of those types. + * This structure is located at an address computable based on a 'struct thread' + * so there is no need for a pointer from one to the other */ +struct extra_thread_data { -#ifdef LISP_FEATURE_SB_THREAD -#ifndef LISP_FEATURE_SB_SAFEPOINT + // Lisp needs to be able to access this array. KEEP IT AS THE FIRST FIELD! + os_context_t* sigcontexts[MAX_INTERRUPTS]; +#ifdef LISP_FEATURE_GC_METRICS + long on_cpu_time; + long avg_gc_wait; + long worst_gc_wait; + long n_gc_wait; + long sum_gc_wait; +#endif + + // Data from here down are never looked at from Lisp. + struct interrupt_data interrupt_data; +#if defined LISP_FEATURE_SB_THREAD && !defined LISP_FEATURE_SB_SAFEPOINT + // 'state_sem' is a binary semaphore used just like a mutex. + // I guess we figure that semaphores are OK to use in signal handlers (which is + // technically false), whereas a mutex would be more certainly wrong? os_sem_t state_sem; + // These are basically "gates" a la SB-CONCURRENCY:GATE. They might be better + // as condition variables, but condvars are not allowed in signal handlers. + // Strictly speaking, sem_wait isn't either, but it seems to work. os_sem_t state_not_running_sem; os_sem_t state_not_stopped_sem; + // We count waiters on each gate to know how many times to sem_post() to open them. + // The counts themselves are protected against concurrent access by 'state_sem'. + // Since we're not constrained by compiler/generic/objdef any more, we can + // make these "only" 4 bytes each, instead of lispwords. + uint32_t state_not_running_waitcount; + uint32_t state_not_stopped_waitcount; #endif +#if defined LISP_FEATURE_SB_THREAD && defined LISP_FEATURE_UNIX + // According to https://github.com/adrienverge/openfortivpn/issues/105 + // "using GCD semaphore in signal handlers is documented to be unsafe" + // which seems almost impossible to believe, considering that sem_t is + // documented to be safe, yet the sem_ functions produce a warning: + // warning: 'sem_init' is deprecated [-Wdeprecated-declarations] + // So how could there be no signal-safe replacement? + os_sem_t sprof_sem; +#endif + int sprof_lock; +#ifdef LISP_FEATURE_WIN32 + // these are different from the masks that interrupt_data holds + sigset_t pending_signal_set; + sigset_t blocked_signal_set; +#define NUM_PRIVATE_EVENTS 2 +#define thread_private_events(th,i) thread_extra_data(th)->private_events[i] + HANDLE private_events[NUM_PRIVATE_EVENTS]; + // Context base pointer for running on top of system libraries built using + // -fomit-frame-pointer. Currently truly required and implemented only + // for (and win32 x86-64), + os_context_register_t carried_base_pointer; + HANDLE synchronous_io_handle_and_flag; + void* waiting_on_address; // used only if #+sb-futex #endif - struct interrupt_data interrupt_data; }; +#define thread_extra_data(thread) \ + ((struct extra_thread_data*)((char*)(thread) + dynamic_values_bytes)) +#define nth_interrupt_context(n,thread) thread_extra_data(thread)->sigcontexts[n] +#define thread_interrupt_data(thread) thread_extra_data(thread)->interrupt_data extern struct thread *all_threads; extern int dynamic_values_bytes; -#if defined(LISP_FEATURE_DARWIN) -#define CONTROL_STACK_ALIGNMENT_BYTES 8192 /* darwin wants page-aligned stacks */ -#define THREAD_ALIGNMENT_BYTES CONTROL_STACK_ALIGNMENT_BYTES -#else #define THREAD_ALIGNMENT_BYTES BACKEND_PAGE_BYTES -#define CONTROL_STACK_ALIGNMENT_BYTES 16 -#endif - +#define CONTROL_STACK_ALIGNMENT_BYTES BACKEND_PAGE_BYTES #ifdef LISP_FEATURE_SB_THREAD #define for_each_thread(th) for(th=all_threads;th;th=th->next) @@ -108,18 +152,20 @@ tls_index_of(struct symbol *symbol) // untagged pointer #endif } #else -# define tls_index_of(x) (x->tls_index) +# define tls_index_of(x) (x)->tls_index #endif # define per_thread_value(sym,th) *(lispobj*)(tls_index_of(sym) + (char*)th) #endif +#define NO_TLS_VALUE_MARKER (~(uword_t)0) + static inline lispobj SymbolValue(lispobj tagged_symbol_pointer, void *thread) { struct symbol *sym = SYMBOL(tagged_symbol_pointer); - if(thread && tls_index_of(sym)) { + if (thread && tls_index_of(sym)) { lispobj r = per_thread_value(sym, thread); - if(r!=NO_TLS_VALUE_MARKER_WIDETAG) return r; + if (r != NO_TLS_VALUE_MARKER) return r; } return sym->value; } @@ -129,7 +175,7 @@ SetSymbolValue(lispobj tagged_symbol_pointer,lispobj val, void *thread) { struct symbol *sym = SYMBOL(tagged_symbol_pointer); if(thread && tls_index_of(sym)) { - if (per_thread_value(sym, thread) != NO_TLS_VALUE_MARKER_WIDETAG) { + if (per_thread_value(sym, thread) != NO_TLS_VALUE_MARKER) { per_thread_value(sym, thread) = val; return; } @@ -150,14 +196,6 @@ SetSymbolValue(lispobj tagged_symbol_pointer,lispobj val, void *thread) # define read_TLS(sym, thread) SYMBOL(sym)->value #endif -// FIXME: very random that this is defined in 'thread.h' -#define StaticSymbolFunction(x) FdefnFun(x##_FDEFN) -/* Return 'fun' given a tagged pointer to an fdefn. */ -static inline lispobj FdefnFun(lispobj fdefn) -{ - return FDEFN(fdefn)->fun; -} - /* These are for use during GC, on the current thread, or on prenatal * threads only. */ #if defined(LISP_FEATURE_SB_THREAD) @@ -191,42 +229,42 @@ static inline lispobj FdefnFun(lispobj fdefn) # endif #endif -#if defined(LISP_FEATURE_SB_THREAD) && defined(LISP_FEATURE_GCC_TLS) +#ifdef LISP_FEATURE_SB_THREAD +# ifdef LISP_FEATURE_GCC_TLS extern __thread struct thread *current_thread; +# elif !defined LISP_FEATURE_WIN32 +extern pthread_key_t current_thread; +#endif #endif #ifndef LISP_FEATURE_SB_SAFEPOINT # define THREAD_CSP_PAGE_SIZE 0 #else -# define THREAD_CSP_PAGE_SIZE BACKEND_PAGE_BYTES +# define THREAD_CSP_PAGE_SIZE os_reported_page_size #endif -#if defined(LISP_FEATURE_WIN32) || defined(LISP_FEATURE_MACH_EXCEPTION_HANDLER) +#ifdef LISP_FEATURE_WIN32 #define ALT_STACK_SIZE 0 #else #define ALT_STACK_SIZE 32 * SIGSTKSZ #endif -/* context 0 is the word immediately before the thread struct, and so on. */ -#define nth_interrupt_context(n,thread) \ - ((os_context_t**)((char*)thread - THREAD_CSP_PAGE_SIZE))[-(THREAD_HEADER_SLOTS+n+1)] - -#define THREAD_STRUCT_SIZE (thread_control_stack_size + BINDING_STACK_SIZE + \ - ALIEN_STACK_SIZE + \ - sizeof(struct nonpointer_thread_data) + \ - (MAX_INTERRUPTS*sizeof(os_context_t*)) + \ - dynamic_values_bytes + \ - ALT_STACK_SIZE + \ - THREAD_ALIGNMENT_BYTES + \ - THREAD_CSP_PAGE_SIZE) +/* As a helpful reminder of how this calculation arises, the summands should + * correspond, in the correct order, to the picture in thread.c */ +#define THREAD_STRUCT_SIZE \ + (THREAD_ALIGNMENT_BYTES + \ + thread_control_stack_size + BINDING_STACK_SIZE + ALIEN_STACK_SIZE + \ + THREAD_CSP_PAGE_SIZE + \ + (THREAD_HEADER_SLOTS*N_WORD_BYTES) + dynamic_values_bytes + \ + sizeof (struct extra_thread_data) + ALT_STACK_SIZE) /* sigaltstack() - "Signal stacks are automatically adjusted * for the direction of stack growth and alignment requirements." */ static inline void* calc_altstack_base(struct thread* thread) { - // Refer to the picture in the comment above create_thread_struct(). + // Refer to the picture in the comment above alloc_thread_struct(). // Always return the lower limit as the base even if stack grows down. return ((char*) thread) + dynamic_values_bytes - + ALIGN_UP(sizeof (struct nonpointer_thread_data), N_WORD_BYTES); + + ALIGN_UP(sizeof (struct extra_thread_data), N_WORD_BYTES); } static inline void* calc_altstack_end(struct thread* thread) { return (char*)thread->os_address + THREAD_STRUCT_SIZE; @@ -239,8 +277,9 @@ static inline int calc_altstack_size(struct thread* thread) { return (char*)calc_altstack_end(thread) - (char*)calc_altstack_base(thread); } #if defined(LISP_FEATURE_WIN32) -static inline struct thread* arch_os_get_current_thread() +static inline struct thread* get_sb_vm_thread() __attribute__((__const__)); +int sb_pthr_kill(struct thread* thread, int signum); #endif /* This is clearly per-arch and possibly even per-OS code, but we can't @@ -248,16 +287,20 @@ static inline struct thread* arch_os_get_current_thread() * much stuff like struct thread and all_threads to be defined, which * usually aren't by that time. So, it's here instead. Sorry */ -static inline struct thread *arch_os_get_current_thread(void) +static inline struct thread *get_sb_vm_thread(void) { #if !defined(LISP_FEATURE_SB_THREAD) return all_threads; #elif defined(LISP_FEATURE_X86) && defined(LISP_FEATURE_WIN32) + // FIXME: why not use TlsGetvalue(OUR_TLS_INDEX) here? register struct thread *me=0; __asm__ volatile ("movl %%fs:0xE10+(4*63), %0" : "=r"(me) :); return me; +#elif defined LISP_FEATURE_WIN32 + return (struct thread*)TlsGetValue(OUR_TLS_INDEX); + #else # if defined(LISP_FEATURE_X86) @@ -273,13 +316,12 @@ static inline struct thread *arch_os_get_current_thread(void) # ifdef LISP_FEATURE_GCC_TLS th = current_thread; # else - th = pthread_getspecific(specials); + th = pthread_getspecific(current_thread); # endif -# if defined(LISP_FEATURE_RESTORE_FS_SEGMENT_REGISTER_FROM_TLS) - /* If enabled by make-config (currently Darwin and FreeBSD only), - * re-setup %fs. This is an out-of-line call, and potentially - * expensive.*/ +# if defined LISP_FEATURE_X86 && (defined LISP_FEATURE_DARWIN || defined LISP_FEATURE_FREEBSD) + /* Restore the %FS register. This is potentially an "expensive" call. + * It rightfully belongs with RESTORE_FP_CONTROL_WORD, but I don't care to try it. */ if (th) { void arch_os_load_ldt(struct thread*); arch_os_load_ldt(th); @@ -293,9 +335,11 @@ static inline struct thread *arch_os_get_current_thread(void) inline static int lisp_thread_p(os_context_t __attribute__((unused)) *context) { #ifdef LISP_FEATURE_SB_THREAD # ifdef LISP_FEATURE_GCC_TLS - return is_lisp_thread; + return current_thread != 0; +# elif defined LISP_FEATURE_WIN32 + return TlsGetValue(OUR_TLS_INDEX) != 0; # else - return pthread_getspecific(lisp_thread) != NULL; + return pthread_getspecific(current_thread) != NULL; # endif #elif defined(LISP_FEATURE_C_STACK_IS_CONTROL_STACK) char *csp = (char *)*os_context_sp_addr(context); @@ -308,10 +352,7 @@ inline static int lisp_thread_p(os_context_t __attribute__((unused)) *context) { #endif } -#if defined(LISP_FEATURE_MACH_EXCEPTION_HANDLER) -extern kern_return_t mach_lisp_thread_init(struct thread *thread); -extern void mach_lisp_thread_destroy(struct thread *thread); -#endif +extern void record_backtrace_from_context(void*,struct thread*); typedef struct init_thread_data { sigset_t oldset; @@ -326,31 +367,29 @@ void thread_in_lisp_raised(os_context_t *ctx); void thread_interrupted(os_context_t *ctx); extern void thread_register_gc_trigger(); -# ifdef LISP_FEATURE_SB_THRUPTION -int wake_thread(os_thread_t os_thread); -# ifdef LISP_FEATURE_WIN32 -void wake_thread_win32(struct thread *thread); -# else -int wake_thread_posix(os_thread_t os_thread); -# endif +# ifdef LISP_FEATURE_SB_SAFEPOINT +void wake_thread(struct thread_instance*), + wake_thread_impl(struct thread_instance*); # endif +#define csp_around_foreign_call(thread) *(((lispobj*)thread)-(1+THREAD_HEADER_SLOTS)) + static inline void push_gcing_safety(struct gcing_safety *into) { - struct thread* th = arch_os_get_current_thread(); + struct thread* th = get_sb_vm_thread(); asm volatile (""); - into->csp_around_foreign_call = *th->csp_around_foreign_call; - *th->csp_around_foreign_call = 0; + into->csp_around_foreign_call = csp_around_foreign_call(th); + csp_around_foreign_call(th) = 0; asm volatile (""); } static inline void pop_gcing_safety(struct gcing_safety *from) { - struct thread* th = arch_os_get_current_thread(); + struct thread* th = get_sb_vm_thread(); asm volatile (""); - *th->csp_around_foreign_call = from->csp_around_foreign_call; + csp_around_foreign_call(th) = from->csp_around_foreign_call; asm volatile (""); } @@ -364,20 +403,38 @@ void pop_gcing_safety(struct gcing_safety *from) int check_pending_thruptions(os_context_t *ctx); -void attach_os_thread(init_thread_data *); -void detach_os_thread(init_thread_data *); - -# if defined(LISP_FEATURE_SB_SAFEPOINT_STRICTLY) && !defined(LISP_FEATURE_WIN32) - -void signal_handler_callback(lispobj, int, void *, void *); -# endif - +#else +#define WITH_GC_AT_SAFEPOINTS_ONLY() #endif -extern void create_initial_thread(lispobj); +extern void create_main_lisp_thread(lispobj); -#ifdef LISP_FEATURE_SB_THREAD +#ifdef LISP_FEATURE_WIN32 +extern CRITICAL_SECTION all_threads_lock; +#elif defined LISP_FEATURE_SB_THREAD extern pthread_mutex_t all_threads_lock; #endif +#ifndef LISP_FEATURE_SB_THREAD +// Put in an empty conversion to avoid warning at the point of use: +// "warning: too many arguments for format [-Wformat-extra-args]" +# define THREAD_ID_LABEL "%s" +# define THREAD_ID_VALUE "" +#elif defined LISP_FEATURE_WIN32 +# define THREAD_ID_LABEL "%ld" +# define THREAD_ID_VALUE (GetCurrentThreadId()) +#elif defined __linux__ +extern int sb_GetTID(); +# define THREAD_ID_LABEL " tid %d" +# define THREAD_ID_VALUE (sb_GetTID()) +#else +# define THREAD_ID_LABEL " pthread %p" +# define THREAD_ID_VALUE ((void*)thread_self()) +#endif + +#ifdef LISP_FEATURE_DARWIN_JIT +#define THREAD_JIT(x) pthread_jit_write_protect_np((x)) +#else +#define THREAD_JIT(x) +#endif #endif /* _INCLUDE_THREAD_H_ */ diff --git a/src/runtime/time.c b/src/runtime/time.c index 0ae34c98e2..c40f9ea8ba 100644 --- a/src/runtime/time.c +++ b/src/runtime/time.c @@ -18,11 +18,6 @@ #include "sbcl.h" #include "runtime.h" -#ifdef LISP_FEATURE_HPUX -struct tm *gmtime_r(const time_t *timer, struct tm *result); -struct tm *localtime_r(const time_t *timer, struct tm *result); -#endif - int get_timezone(time_t when, boolean *dst) { struct tm ltm, gtm; diff --git a/src/runtime/traceroot.c b/src/runtime/traceroot.c index 1bc78e697b..a6bd25e66c 100644 --- a/src/runtime/traceroot.c +++ b/src/runtime/traceroot.c @@ -14,10 +14,11 @@ #include "genesis/layout.h" #include "genesis/package.h" #include "genesis/vector.h" -#include "getallocptr.h" // for get_alloc_pointer() #include "search.h" #include "genesis/avlnode.h" #include "genesis/sap.h" +#include "genesis/thread-instance.h" +#include "print.h" #include <stdlib.h> #include <stdio.h> @@ -29,6 +30,25 @@ #include <sys/resource.h> // for getrusage() #endif +#ifndef TRACEROOT_USE_ABSL_HASHMAP +#define TRACEROOT_USE_ABSL_HASHMAP 0 +#endif + +#if TRACEROOT_USE_ABSL_HASHMAP +extern void* new_absl_hashmap(int); +extern void absl_hashmap_destroy(void*); +extern unsigned absl_hashmap_get(void*,lispobj); +extern unsigned* absl_hashmap_get_ref(void*,lispobj); +extern int absl_hashmap_size(void*,int*); +typedef void* inverted_heap_t; +#define inverted_heap_get(graph, key) absl_hashmap_get(graph, key) +#define inverted_heap_get_ref(graph, key) absl_hashmap_get_ref(graph, key) +#else +typedef struct hopscotch_table* inverted_heap_t; +#define inverted_heap_get(graph, key) hopscotch_get(graph, key, 0) +#define inverted_heap_get_ref(graph, key) hopscotch_get_ref(graph, key) +#endif + int heap_trace_verbose = 0; extern generation_index_t gencgc_oldest_gen_to_gc; @@ -60,9 +80,11 @@ struct scan_state { long n_immediates; long n_pointers; int record_ptrs; - // A hashtable mapping each object to a list of objects pointing to it - struct hopscotch_table inverted_heap; + // A hashmap from object to list of objects pointing to it + struct hopscotch_table* inverted_heap; struct scratchpad scratchpad; + lispobj ignored_objects; + int keep_leaves; }; static int traceroot_gen_of(lispobj obj) { @@ -77,8 +99,8 @@ static const char* classify_obj(lispobj ptr) switch(lowtag_of(ptr)) { case INSTANCE_POINTER_LOWTAG: name = instance_classoid_name(native_pointer(ptr)); - if (widetag_of(name) == SIMPLE_BASE_STRING_WIDETAG) - return (char*)(name + 2); + if (widetag_of(name) == SIMPLE_BASE_STRING_WIDETAG) return (char*)(name + 2); + break; case LIST_POINTER_LOWTAG: return "cons"; case FUN_POINTER_LOWTAG: @@ -115,7 +137,7 @@ static void add_to_layer(lispobj* obj, int wordindex, /// If 'obj' is a simple-fun, return its code component, /// otherwise return obj directly. -static lispobj canonical_obj(lispobj obj) +static inline lispobj canonical_obj(lispobj obj) { if (functionp(obj) && widetag_of(FUNCTION(obj)) == SIMPLE_FUN_WIDETAG) return fun_code_tagged(FUNCTION(obj)); @@ -128,31 +150,29 @@ static lispobj canonical_obj(lispobj obj) #define check_ptr(index,ptr) if(canonical_obj(ptr)==target) return index; static int find_ref(lispobj* source, lispobj target) { - lispobj layout, bitmap; + lispobj layout; int scan_limit, i; - lispobj header = *source; - if (is_cons_half(header)) { - check_ptr(0, header); + lispobj word = *source; + if (!is_header(word)) { + check_ptr(0, source[0]); check_ptr(1, source[1]); return -1; } + scan_limit = headerobj_size(source); int widetag = widetag_of(source); - scan_limit = sizetab[widetag](source); switch (widetag) { case INSTANCE_WIDETAG: -#ifdef LISP_FEATURE_COMPACT_INSTANCE_HEADER case FUNCALLABLE_INSTANCE_WIDETAG: -#endif - // mixed boxed/unboxed objects - // Unlike in scav_instance where the slot loop is unswitched for - // speed into three cases (no raw slots, fixnum bitmap, bignum bitmap), - // here we just go for clarity by abstracting out logbitp. - layout = instance_layout(source); + // Unlike in scav_instance where the slot loop is optimized for + // certain special cases, here we opt for simplicity. + layout = layout_of(source); check_ptr(0, layout); - bitmap = layout ? LAYOUT(layout)->bitmap : make_fixnum(-1); - for(i=1; i<scan_limit; ++i) - if (layout_bitmap_logbitp(i-1, bitmap)) check_ptr(i, source[i]); + if (layout) { + struct bitmap bitmap = get_layout_bitmap(LAYOUT(layout)); + for(i=1; i<scan_limit; ++i) + if (bitmap_logbitp(i-1, bitmap)) check_ptr(i, source[i]); + } // FIXME: check lockfree_list_node_p() also return -1; #if FUN_SELF_FIXNUM_TAGGED @@ -164,7 +184,7 @@ static int find_ref(lispobj* source, lispobj target) scan_limit = code_header_words((struct code*)source); break; case FDEFN_WIDETAG: - check_ptr(3, fdefn_callee_lispobj((struct fdefn*)source)); + check_ptr(3, decode_fdefn_rawfun((struct fdefn*)source)); scan_limit = 3; break; } @@ -189,7 +209,7 @@ static char* NO_SANITIZE_MEMORY deduce_thread_pc(struct thread* th, void** addr) uword_t* fp = __builtin_frame_address(0); char* return_pc = 0; - if (th != arch_os_get_current_thread()) { + if (th != get_sb_vm_thread()) { int i = fixnum_value(read_TLS(FREE_INTERRUPT_CONTEXT_INDEX,th)); os_context_t *c = nth_interrupt_context(i-1, th); fp = (uword_t*)*os_context_register_addr(c,reg_FP); @@ -223,7 +243,7 @@ deduce_thread(void (*context_scanner)(), uword_t pointer, char** pc) for_each_thread(th) { void **esp=(void **)-1; sword_t i,free; - if (th == arch_os_get_current_thread()) + if (th == get_sb_vm_thread()) esp = (void **)((void *)&pointer); else { void **esp1; @@ -255,6 +275,7 @@ deduce_thread(void (*context_scanner)(), uword_t pointer, char** pc) /* KNOWN BUG: stack reference to pinned large object or immobile object * won't be found in pins hashtable */ +/* Also: should take 'struct lisp_thread**' instead of 'struct thread**' */ static lispobj examine_threads(struct hopscotch_table* targets, void (*context_scanner)(), int n_pins, lispobj* pins, @@ -270,7 +291,7 @@ static lispobj examine_threads(struct hopscotch_table* targets, #ifdef LISP_FEATURE_SB_THREAD // Examine thread-local storage *root_kind = TLS; - where = (lispobj*)(th+1); + where = &th->lisp_thread; end = (lispobj*)((char*)th + SymbolValue(FREE_TLS_INDEX,0)); for( ; where < end ; ++where) if (interestingp(*where, targets)) { @@ -329,7 +350,7 @@ static lispobj examine_threads(struct hopscotch_table* targets, *thread_pc = 0; // Scan just the current thread's stack // (We don't know where the other stack pointers are) - th = arch_os_get_current_thread(); + th = get_sb_vm_thread(); void **esp = __builtin_frame_address(0); void **where; for (where = ((void **)th->control_stack_end)-1; where >= esp; --where) @@ -339,7 +360,7 @@ static lispobj examine_threads(struct hopscotch_table* targets, break; } } - return pin; + if (*root_thread) return pin; } #endif *root_kind = HEAP; @@ -379,12 +400,12 @@ static inline uint32_t encode_pointer(lispobj pointer) return (encoding<<1) | 1; } else #ifdef LISP_FEATURE_IMMOBILE_SPACE - if (find_varyobj_page_index((void*)pointer) >= 0) { - // A varyobj space pointer is stored as a count in doublewords + if (find_text_page_index((void*)pointer) >= 0) { + // A text space pointer is stored as a count in doublewords // from the base address. - encoding = (pointer - VARYOBJ_SPACE_START) / (2*N_WORD_BYTES); + encoding = (pointer - TEXT_SPACE_START) / (2*N_WORD_BYTES); gc_assert(encoding <= 0x3FFFFFFF); - // bit pattern #b10 signifies varyobj space compressed ptr. + // bit pattern #b10 signifies text space compressed ptr. return (encoding<<2) | 2; } else #endif @@ -400,8 +421,8 @@ static inline lispobj decode_pointer(uint32_t encoding) if (encoding & 1) // Compressed ptr to dynamic space return (encoding>>1)*(2*N_WORD_BYTES) + DYNAMIC_SPACE_START; #ifdef LISP_FEATURE_IMMOBILE_SPACE - else if ((encoding & 3) == 2) // Compressed ptr to varyobj space - return (encoding>>2)*(2*N_WORD_BYTES) + VARYOBJ_SPACE_START; + else if ((encoding & 3) == 2) // Compressed ptr to text space + return (encoding>>2)*(2*N_WORD_BYTES) + TEXT_SPACE_START; #endif else return encoding; // Literal pointer @@ -409,20 +430,20 @@ static inline lispobj decode_pointer(uint32_t encoding) static void maybe_show_object_name(lispobj obj, FILE* stream) { - extern void safely_show_lstring(lispobj* string, int quotes, FILE *s); lispobj package, package_name; if (lowtag_of(obj)==OTHER_POINTER_LOWTAG) switch(widetag_of(native_pointer(obj))) { case SYMBOL_WIDETAG: putc(',', stream); - if ((package = SYMBOL(obj)->package) == NIL) { + package = symbol_package(SYMBOL(obj)); + if (package == NIL) { fprintf(stream, "#:"); } else { package_name = ((struct package*)native_pointer(package))->_name; - safely_show_lstring(native_pointer(package_name), 0, stream); + safely_show_lstring(VECTOR(package_name), 0, stream); fputs("::", stream); } - safely_show_lstring(native_pointer(SYMBOL(obj)->name), 0, stream); + safely_show_lstring(symbol_name(SYMBOL(obj)), 0, stream); break; } } @@ -442,7 +463,7 @@ static boolean root_p(lispobj ptr, int criterion) static lispobj mkcons(lispobj car, lispobj cdr) { struct cons *cons = (struct cons*) - gc_general_alloc(sizeof(struct cons), BOXED_PAGE_FLAG); + gc_general_alloc(cons_region, sizeof(struct cons), PAGE_TYPE_CONS); cons->car = car; cons->cdr = cdr; return make_lispobj(cons, LIST_POINTER_LOWTAG); @@ -453,7 +474,7 @@ static lispobj liststar3(lispobj x, lispobj y, lispobj z) { static lispobj make_sap(char* value) { struct sap *sap = (struct sap*) - gc_general_alloc(sizeof(struct sap), BOXED_PAGE_FLAG); + gc_general_alloc(unboxed_region, sizeof(struct sap), PAGE_TYPE_UNBOXED); sap->header = (1<<N_WIDETAG_BITS) | SAP_WIDETAG; sap->pointer = value; return make_lispobj(sap, OTHER_POINTER_LOWTAG); @@ -464,7 +485,7 @@ static lispobj make_sap(char* value) static lispobj trace1(lispobj object, struct hopscotch_table* targets, struct hopscotch_table* visited, - struct hopscotch_table* inverted_heap, + inverted_heap_t graph, struct scratchpad* scratchpad, int n_pins, lispobj* pins, void (*context_scanner)(), int criterion) @@ -495,7 +516,7 @@ static lispobj trace1(lispobj object, if (heap_trace_verbose) printf("Next layer: Looking for %d object(s)\n", targets->count); for_each_hopscotch_key(i, target, (*targets)) { - uint32_t list = hopscotch_get(inverted_heap, target, 0); + uint32_t list = inverted_heap_get(graph, target); if (heap_trace_verbose>1) { uint32_t list1 = list; fprintf(stderr, "target=%p srcs=", (void*)target); @@ -505,8 +526,7 @@ static lispobj trace1(lispobj object, if (hopscotch_containsp(visited, (lispobj)ptr)) fprintf(stderr, "%p ", ptr); else { - lispobj word = *ptr; - int nwords = OBJECT_SIZE(word, ptr); + int nwords = object_size(ptr); fprintf(stderr, "%p+%d ", ptr, nwords); } list1 = cell[1]; @@ -625,7 +645,7 @@ static lispobj trace1(lispobj object, case 3: if (lowtag_of(ptr) == OTHER_POINTER_LOWTAG && widetag_of(&FDEFN(ptr)->header) == FDEFN_WIDETAG) - target = fdefn_callee_lispobj((struct fdefn*)native_pointer(ptr)); + target = decode_fdefn_rawfun((struct fdefn*)native_pointer(ptr)); break; } target = canonical_obj(target); @@ -643,13 +663,18 @@ static lispobj trace1(lispobj object, return path; } -static void record_ptr(lispobj* source, lispobj target, - struct scan_state* ss) +// Add 'source' to the list of objects keyed by 'target' in the inverted heap. +// Note that 'source' has no lowtag, and 'target' does. +// Pointer compression is used: the linked list of source objects +// is built using offsets into the scratchpad rather than absolute addresses. +// Return 1 if and only if 'target' was actually added to the graph. +static boolean record_ptr(lispobj* source, lispobj target, + struct scan_state* ss) { - // Add 'source' to the list of objects keyed by 'target' in the inverted heap. - // Note that 'source' has no lowtag, and 'target' does. - // Pointer compression occurs here as well: the linked list of source objects - // is built using offsets into the scratchpad rather than absolute addresses. + if (!ss->keep_leaves) { // expected case + if (!listp(target) && + leaf_obj_widetag_p(widetag_of(native_pointer(target)))) return 0; + } target = canonical_obj(target); uint32_t* new_cell = (uint32_t*)ss->scratchpad.free; uint32_t* next = new_cell + 2; @@ -657,56 +682,71 @@ static void record_ptr(lispobj* source, lispobj target, ss->scratchpad.free = (char*)next; if (ss->scratchpad.free > ss->scratchpad.end) lose("undersized scratchpad"); new_cell[0] = encode_pointer((lispobj)source); - uint32_t* valref = hopscotch_get_ref(&ss->inverted_heap, target); + uint32_t* valref = inverted_heap_get_ref(ss->inverted_heap, target); new_cell[1] = *valref; *valref = (uint32_t)((char*)new_cell - ss->scratchpad.base); + return 1; } -#define relevant_ptr_p(x) find_page_index(x)>=0||immobile_space_p((lispobj)x) +#define relevant_ptr_p(x) \ + (find_page_index((void*)(x))>=0||immobile_space_p((lispobj)(x))||readonly_space_p(x)) -#define check_ptr(ptr) { \ - ++n_scanned_words; \ - if (!is_lisp_pointer(ptr)) ++n_immediates; \ - else if (relevant_ptr_p((void*)(ptr))) { \ - ++n_pointers; \ - if (record_ptrs) record_ptr(where,ptr,ss); \ - }} +#define COUNT_POINTER(x) { ++n_scanned_words; \ + if (!is_lisp_pointer(x)) ++n_immediates; \ + else if (relevant_ptr_p(x)) ++n_pointers; } + +#define check_ptr(x) { \ + if (count_only) COUNT_POINTER(x) \ + else if (is_lisp_pointer(x) && relevant_ptr_p(x)) record_ptr(where,x,ss); } + +static boolean ignorep(lispobj* base_ptr, + lispobj ignored_objects) +{ + int i; + for (i = vector_len(VECTOR(ignored_objects))-1; i >= 0; --i) + if (native_pointer(VECTOR(ignored_objects)->data[i]) == base_ptr) + return 1; + return 0; +} static uword_t build_refs(lispobj* where, lispobj* end, struct scan_state* ss) { - lispobj layout, bitmap; + lispobj layout; sword_t nwords, scan_limit, i; uword_t n_objects = 0, n_scanned_words = 0, n_immediates = 0, n_pointers = 0; - boolean record_ptrs = ss->record_ptrs; + boolean count_only = !ss->record_ptrs; for ( ; where < end ; where += nwords ) { + if (ss->ignored_objects && ignorep(where, ss->ignored_objects)) { + nwords = object_size(where); + continue; + } ++n_objects; - lispobj header = *where; - if (is_cons_half(header)) { + lispobj word = *where; + if (!is_header(word)) { nwords = 2; - check_ptr(header); + check_ptr(where[0]); check_ptr(where[1]); continue; } - int widetag = widetag_of(where); - nwords = scan_limit = sizetab[widetag](where); + nwords = scan_limit = headerobj_size2(where, word); + int widetag = header_widetag(word); + if (leaf_obj_widetag_p(widetag)) continue; switch (widetag) { case INSTANCE_WIDETAG: -#ifdef LISP_FEATURE_COMPACT_INSTANCE_HEADER case FUNCALLABLE_INSTANCE_WIDETAG: -#endif // mixed boxed/unboxed objects - layout = instance_layout(where); + layout = layout_of(where); check_ptr(layout); // Partially initialized instance can't have nonzero words yet - bitmap = layout ? LAYOUT(layout)->bitmap : make_fixnum(-1); - // If no raw slots, just scan without use of the bitmap. - // FIXME: check lockfree_list_node_p() also - if (bitmap == make_fixnum(-1)) break; - for(i=1; i<scan_limit; ++i) - if (layout_bitmap_logbitp(i-1, bitmap)) check_ptr(where[i]); + if (layout) { + struct bitmap bitmap = get_layout_bitmap(LAYOUT(layout)); + // FIXME: check lockfree_list_node_p() also + for(i=1; i<scan_limit; ++i) + if (bitmap_logbitp(i-1, bitmap)) check_ptr(where[i]); + } continue; #if FUN_SELF_FIXNUM_TAGGED case CLOSURE_WIDETAG: @@ -717,7 +757,7 @@ static uword_t build_refs(lispobj* where, lispobj* end, scan_limit = code_header_words((struct code*)where); break; case FDEFN_WIDETAG: - check_ptr(fdefn_callee_lispobj((struct fdefn*)where)); + check_ptr(decode_fdefn_rawfun((struct fdefn*)where)); scan_limit = 3; break; case SIMPLE_VECTOR_WIDETAG: @@ -725,13 +765,12 @@ static uword_t build_refs(lispobj* where, lispobj* end, // a path from the root only if it does not involve whichever // object is definitely weak. This fails on weak key-OR-value // tables since we can't decide whether to allow the entry. - // Disregard the address-sensitivity bit when checking whether - // this is a weak hash-table vector. - if ((vector_subtype(*where) & ~subtype_VectorAddrHashing) - == subtype_VectorHashing + subtype_VectorWeak) { + if (vector_flagp(*where, VectorWeak)) { // if any kind of weak vector + // If not a hashtable, just skip it. + if (!vector_flagp(*where, VectorHashing)) continue; lispobj* data = where + 2; - int kv_vector_length = fixnum_value(where[1]); - lispobj lhash_table = data[kv_vector_length-1]; + int kv_vector_len = vector_len((struct vector*)where); + lispobj lhash_table = data[kv_vector_len-1]; gc_assert(instancep(lhash_table)); struct hash_table* hash_table = (struct hash_table *)native_pointer(lhash_table); @@ -746,23 +785,38 @@ static uword_t build_refs(lispobj* where, lispobj* end, continue; } } - if (is_vector_subtype(*where, VectorWeak)) - continue; break; + case FILLER_WIDETAG: continue; default: - if (!(other_immediate_lowtag_p(widetag) && lowtag_for_widetag[widetag>>2])) + if (!(other_immediate_lowtag_p(widetag) && LOWTAG_FOR_WIDETAG(widetag))) lose("Unknown widetag %x", widetag); // Skip irrelevant objects. - if (leaf_obj_widetag_p(widetag) || - (widetag == WEAK_POINTER_WIDETAG) || /* do not follow! */ + if ((widetag == WEAK_POINTER_WIDETAG) || /* do not follow! */ // These numeric types contain pointers, but are uninteresting. (widetag == COMPLEX_WIDETAG) || (widetag == RATIO_WIDETAG)) continue; } - for(i=1; i<scan_limit; ++i) check_ptr(where[i]); + if (widetag == SIMPLE_VECTOR_WIDETAG && ss->record_ptrs) { + // Try to eliminate some duplicate edges in the reversed graph. + // This is only a heuristic and will not eliminate all duplicate edges. + // It helps for vectors which get initialized like #(#:FOO #:FOO ...) + // by storing only one backpointer to #:FOO. + // It is not particularly helpful for other objects. + lispobj prev_interesting_ptr = 0; + for(i=1; i<scan_limit; ++i) { + lispobj pointer = where[i]; + if (is_lisp_pointer(pointer) + && relevant_ptr_p(pointer) + && pointer != prev_interesting_ptr + && record_ptr(where,pointer,ss)) + prev_interesting_ptr = pointer; + } + } else { + for(i=1; i<scan_limit; ++i) check_ptr(where[i]); + } } - if (!record_ptrs) { // just count them + if (count_only) { ss->n_objects += n_objects; ss->n_scanned_words += n_scanned_words; ss->n_immediates += n_immediates; @@ -781,12 +835,13 @@ static uword_t build_refs(lispobj* where, lispobj* end, static void scan_spaces(struct scan_state* ss) { struct scan_state old = *ss; - build_refs((lispobj*)STATIC_SPACE_START, static_space_free_pointer, ss); + build_refs((lispobj*)NIL_SYMBOL_SLOTS_START, (lispobj*)NIL_SYMBOL_SLOTS_END, ss); + build_refs((lispobj*)STATIC_SPACE_OBJECTS_START, static_space_free_pointer, ss); show_tally(old, ss); #ifdef LISP_FEATURE_IMMOBILE_SPACE old = *ss; build_refs((lispobj*)FIXEDOBJ_SPACE_START, fixedobj_free_pointer, ss); show_tally(old, ss); - old = *ss; build_refs((lispobj*)VARYOBJ_SPACE_START, varyobj_free_pointer, ss); + old = *ss; build_refs((lispobj*)TEXT_SPACE_START, text_space_highwatermark, ss); show_tally(old, ss); #endif old = *ss; @@ -797,11 +852,14 @@ static void scan_spaces(struct scan_state* ss) #define HASH_FUNCTION HOPSCOTCH_HASH_FUN_MIX -static void compute_heap_inverse(struct hopscotch_table* inverted_heap, - struct scratchpad* scratchpad) +static void* compute_heap_inverse(boolean keep_leaves, + lispobj ignored_objects, + struct scratchpad* scratchpad) { struct scan_state ss; memset(&ss, 0, sizeof ss); + ss.ignored_objects = ignored_objects; + ss.keep_leaves = keep_leaves; if (heap_trace_verbose) fprintf(stderr, "Pass 1: Counting heap objects...\n"); scan_spaces(&ss); // Guess at the initial size of ~ .5 million objects. @@ -810,13 +868,19 @@ static void compute_heap_inverse(struct hopscotch_table* inverted_heap, if (heap_trace_verbose) { fprintf(stderr, "Pass 2: Inverting heap. Initial size=%d objects\n", size); } - hopscotch_create(&ss.inverted_heap, HASH_FUNCTION, +#if TRACEROOT_USE_ABSL_HASHMAP + void* inverted_heap = new_absl_hashmap(size); + ss.inverted_heap = inverted_heap; +#else + ss.inverted_heap = malloc(sizeof(struct hopscotch_table)); + hopscotch_create(ss.inverted_heap, HASH_FUNCTION, 4, // XXX: half the word size if 64-bit size /* initial size */, 0 /* default hop range */); +#endif // Add one pointer due to inability to use the first // two words of the scratchpad. uword_t scratchpad_min_size = (1 + ss.n_pointers) * 2 * sizeof (uint32_t); - int pagesize = getpagesize(); + int pagesize = os_reported_page_size; uword_t scratchpad_size = ALIGN_UP(scratchpad_min_size, pagesize); ss.scratchpad.base = os_allocate(scratchpad_size); gc_assert(ss.scratchpad.base); @@ -831,36 +895,60 @@ static void compute_heap_inverse(struct hopscotch_table* inverted_heap, #endif ss.record_ptrs = 1; scan_spaces(&ss); - *inverted_heap = ss.inverted_heap; *scratchpad = ss.scratchpad; #if HAVE_GETRUSAGE getrusage(RUSAGE_SELF, &after); // We're done building the necessary structure. Show some memory stats. if (heap_trace_verbose) { + int count; + int capacity; +#if TRACEROOT_USE_ABSL_HASHMAP + count = absl_hashmap_size(ss.inverted_heap, &capacity); +#else + count = ss.inverted_heap->count; + capacity = 1+hopscotch_max_key_index(*ss.inverted_heap); +#endif #define timediff(b,a,field) \ ((a.field.tv_sec-b.field.tv_sec)*1000000+(a.field.tv_usec-b.field.tv_usec)) + float stime = timediff(before, after, ru_stime); + float utime = timediff(before, after, ru_utime); fprintf(stderr, - "Inverted heap: ct=%d, cap=%d, LF=%f ET=%ld+%ld sys+usr\n", - inverted_heap->count, - 1+hopscotch_max_key_index(*inverted_heap), - 100*(float)inverted_heap->count / (1+hopscotch_max_key_index(*inverted_heap)), - timediff(before, after, ru_stime), - timediff(before, after, ru_utime)); + "Inverted heap: ct=%d, cap=%d, LF=%f ET=%f+%f sys+usr=%f\n", + count, capacity, 100*(float)count / (capacity>0?capacity:1), + stime/1000000, utime/1000000, (stime+utime)/1000000); } #endif + return ss.inverted_heap; }; +/* Return true if the user wants to find a leaf object. + * If not, then we can omit all leaf objects from the inverted heap + * because no leaf object can point to anything */ +static boolean finding_leaf_p(lispobj weak_pointers) +{ + do { + lispobj car = CONS(weak_pointers)->car; + lispobj value = ((struct weak_pointer*)native_pointer(car))->value; + weak_pointers = CONS(weak_pointers)->cdr; + if (is_lisp_pointer(value) + && !listp(value) + && leaf_obj_widetag_p(widetag_of(native_pointer(value)))) return 1; + } while (weak_pointers != NIL); + return 0; // this is the expected (and optimal) case +} + /* Find any shortest path from a thread or tenured object * to each of the specified objects. */ static int trace_paths(void (*context_scanner)(), lispobj weak_pointers, // list of inputs lispobj paths, // vector of outputs + lispobj ignore, // vector of ignored objects int n_pins, lispobj* pins, int criterion) { int i; - struct hopscotch_table inverted_heap; + void* inverted_heap; struct scratchpad scratchpad; // A hashset of all objects in the reverse reachability graph so far struct hopscotch_table visited; // *Without* lowtag @@ -874,12 +962,14 @@ static int trace_paths(void (*context_scanner)(), fprintf(stderr, " %p%s", (void*)pins[i], ((i%8)==7||i==n_pins-1)?"\n":""); } - compute_heap_inverse(&inverted_heap, &scratchpad); + inverted_heap = compute_heap_inverse(finding_leaf_p(weak_pointers), + ignore, &scratchpad); hopscotch_create(&visited, HASH_FUNCTION, 0, 32, 0); hopscotch_create(&targets, HASH_FUNCTION, 0, 32, 0); i = 0; do { - gc_assert(make_fixnum(i) <= VECTOR(paths)->length); + // Oh dear, is this really supposed to be '<=' (vs '<') ? + gc_assert(i <= vector_len(VECTOR(paths))); lispobj car = CONS(weak_pointers)->car; lispobj value = ((struct weak_pointer*)native_pointer(car))->value; weak_pointers = CONS(weak_pointers)->cdr; @@ -890,15 +980,28 @@ static int trace_paths(void (*context_scanner)(), hopscotch_reset(&targets); lispobj path = trace1(canonical_obj(value), &targets, &visited, - &inverted_heap, &scratchpad, + inverted_heap, &scratchpad, n_pins, pins, context_scanner, criterion); - if ((VECTOR(paths)->data[i] = path) != 0) ++n_found; + lispobj* elt = VECTOR(paths)->data + i; + notice_pointer_store(elt); + if ((*elt = path) != 0) ++n_found; } ++i; } while (weak_pointers != NIL); - ensure_region_closed(&boxed_region, BOXED_PAGE_FLAG); - os_invalidate(scratchpad.base, scratchpad.end-scratchpad.base); - hopscotch_destroy(&inverted_heap); + // gc_close_collector_regions() won't suffice here. + // Depending on whether this is called from prove_liveness() or + // gc_prove_liveness() via collect_garbage(), there may be an open + // region that has the THREAD_PAGE_FLAG in its PTE. But that's not + // correct for the allocations made for traceroot's answers. + ensure_region_closed(unboxed_region, PAGE_TYPE_UNBOXED); + ensure_region_closed(cons_region, PAGE_TYPE_CONS); + os_deallocate(scratchpad.base, scratchpad.end-scratchpad.base); +#if TRACEROOT_USE_ABSL_HASHMAP + absl_hashmap_destroy(inverted_heap); +#else + hopscotch_destroy(inverted_heap); + free(inverted_heap); +#endif hopscotch_destroy(&visited); hopscotch_destroy(&targets); return n_found; @@ -912,9 +1015,10 @@ int gc_prove_liveness(void(*context_scanner)(), int criterion) { int n_watched = 0, n_live = 0, n_bad = 0, n_imm = 0, n_paths = 0; - lispobj input = CONS(objects)->car, - output = CONS(objects)->cdr, - paths = CONS(output)->cdr; + lispobj input = VECTOR(objects)->data[0], + ignore = VECTOR(objects)->data[1], + output = VECTOR(objects)->data[2], + paths = CONS(output)->cdr; lispobj list; for (list = input ; list != NIL && listp(list) ; list = CONS(list)->cdr) { ++n_watched; @@ -950,16 +1054,7 @@ int gc_prove_liveness(void(*context_scanner)(), CONS(output)->car = make_fixnum(0); return 0; } - // Put back lowtags on pinned objects, since wipe_nonpinned_words() removed - // them. But first test whether lowtags were already repaired - // in case prove_liveness() is called after gc_prove_liveness(). - if (n_pins>0 && !is_lisp_pointer(pins[0])) { - int i; - for(i=n_pins-1; i>=0; --i) { - pins[i] = compute_lispobj((lispobj*)pins[i]); - } - } - n_paths = trace_paths(context_scanner, input, paths, + n_paths = trace_paths(context_scanner, input, paths, ignore, n_pins, (lispobj*)pins, criterion); CONS(output)->car = make_fixnum(n_paths); return n_paths; @@ -971,41 +1066,7 @@ int gc_prove_liveness(void(*context_scanner)(), int prove_liveness(lispobj objects, int criterion) { extern struct hopscotch_table pinned_objects; - extern int gc_n_stack_pins; - return gc_prove_liveness(0, objects, gc_n_stack_pins, pinned_objects.keys, criterion); -} - -// These are slot offsets in (DEFSTRUCT THREAD), -// not the C structure defined in genesis/thread.h -#define LISP_THREAD_NAME_SLOT INSTANCE_DATA_START+0 -#define LISP_THREAD_OS_THREAD_SLOT INSTANCE_DATA_START+3 - -/* Perform exhaustive search on *ALL-THREADS* looking for a specific thread. - * Efficiency is not a concern. - */ -static struct instance* find_thread(os_thread_t os_thread, lispobj tree) -{ - if (tree == NIL) return 0; - struct avlnode* node = (struct avlnode*)native_pointer(tree); - struct instance* lisp_thread = (struct instance*)native_pointer(node->data); - if ((os_thread_t)lisp_thread->slots[LISP_THREAD_OS_THREAD_SLOT] == os_thread) - return lisp_thread; - if ((lisp_thread = find_thread(os_thread, node->left)) != NULL) - return lisp_thread; - if ((lisp_thread = find_thread(os_thread, node->right)) != NULL) - return lisp_thread; - return 0; -} - -struct vector* lisp_thread_name(os_thread_t os_thread) -{ - static unsigned int hint; - lispobj* sym = find_symbol("*ALL-THREADS*", find_package("SB-THREAD"), &hint); - if (sym) { - struct instance* lisp_thread = - find_thread(os_thread, ((struct symbol*)sym)->value); - if (lisp_thread) - return VECTOR(lisp_thread->slots[LISP_THREAD_NAME_SLOT]); - } - return 0; + extern int gc_pin_count; + extern lispobj* gc_filtered_pins; + return gc_prove_liveness(0, objects, gc_pin_count, gc_filtered_pins, criterion); } diff --git a/src/runtime/unaligned.h b/src/runtime/unaligned.h index 1c0128d109..0a24a1815e 100644 --- a/src/runtime/unaligned.h +++ b/src/runtime/unaligned.h @@ -19,7 +19,8 @@ static inline uint32_t UNALIGNED_LOAD32(void* p) { memcpy(&val, p, 4); return val; } -static inline void UNALIGNED_STORE32(void* p, uint32_t val) { +// 'volatile' works around a spurious GCC warning +static inline void UNALIGNED_STORE32(void* volatile p, uint32_t val) { memcpy(p, &val, 4); } #ifdef LISP_FEATURE_64_BIT diff --git a/src/runtime/validate.c b/src/runtime/validate.c index 26b021a2dc..04e496f63a 100644 --- a/src/runtime/validate.c +++ b/src/runtime/validate.c @@ -29,6 +29,9 @@ uword_t DYNAMIC_0_SPACE_START, DYNAMIC_1_SPACE_START; #else uword_t DYNAMIC_SPACE_START; #endif +#ifndef LISP_FEATURE_DARWIN_JIT +uword_t READ_ONLY_SPACE_START, READ_ONLY_SPACE_END; +#endif uword_t asm_routines_start, asm_routines_end; @@ -49,37 +52,28 @@ static const int should_allocate_low = 0; #endif -static void -ensure_space(int attributes, uword_t start, uword_t size) -{ - if (os_validate(attributes, (os_vm_address_t)start, (os_vm_size_t)size)==NULL) { - fprintf(stderr, - "ensure_space: failed to allocate %lu bytes at %p\n", - (long unsigned)size, (void*)start); - fprintf(stderr, - "(hint: Try \"ulimit -a\"; maybe you should increase memory limits.)\n"); - exit(1); - } -} - os_vm_address_t undefined_alien_address = 0; +/* As contrasted with the useless os_vm_page_size which is identical to + * the constant BACKEND_PAGE_BYTES that we define for various other purposes + * such as core file loading and generational GC, + * this is the number the OS tells us */ +int os_reported_page_size; + +#ifdef LISP_FEATURE_WIN32 +#include <sysinfoapi.h> +#endif static void ensure_undefined_alien(void) { - os_vm_address_t start = os_validate(MOVABLE|IS_GUARD_PAGE, NULL, -#ifndef LISP_FEATURE_WIN32 - /* We can/should disregard our 'os_vm_page_size' constant which tends to be - * larger than the granularity that the OS will allow you to manipulate via - * mprotect(). e.g. on x86-64-linux we use a page size of 32K but in reality - * the protection granularity is 4K. - * Moreover, since the memory protection is not changed after allocation, - * the granuarity that mprotect() operates on is immaterial. As such, it - * probably would work to put N_WORD_BYTES here since that's all we need. */ - getpagesize() -#else // Use the same value as does contrib/sb-posix/interface.lisp - 4096 +#ifdef LISP_FEATURE_WIN32 + SYSTEM_INFO info; + GetSystemInfo(&info); + os_reported_page_size = info.dwPageSize; +#else + os_reported_page_size = getpagesize(); #endif - ); + os_vm_address_t start = + os_alloc_gc_space(0, MOVABLE|IS_GUARD_PAGE, NULL, os_reported_page_size); if (start) { undefined_alien_address = start; } else { @@ -89,37 +83,37 @@ ensure_undefined_alien(void) { boolean allocate_hardwired_spaces(boolean hard_failp) { -#ifdef PRINTNOISE - printf("allocating memory ..."); - fflush(stdout); -#endif struct { uword_t start; unsigned size; + int id; } preinit_spaces[] = { - { READ_ONLY_SPACE_START, READ_ONLY_SPACE_SIZE }, - { LINKAGE_TABLE_SPACE_START, LINKAGE_TABLE_SPACE_SIZE }, - { STATIC_SPACE_START, STATIC_SPACE_SIZE }, + { READ_ONLY_SPACE_START, READ_ONLY_SPACE_SIZE, READ_ONLY_CORE_SPACE_ID }, +#ifndef LISP_FEATURE_IMMOBILE_SPACE + { ALIEN_LINKAGE_TABLE_SPACE_START, ALIEN_LINKAGE_TABLE_SPACE_SIZE, ALIEN_LINKAGE_TABLE_CORE_SPACE_ID }, +#endif + { STATIC_SPACE_START, STATIC_SPACE_SIZE, STATIC_CORE_SPACE_ID }, +#ifdef LISP_FEATURE_DARWIN_JIT + { STATIC_CODE_SPACE_START, STATIC_CODE_SPACE_SIZE, STATIC_CODE_CORE_SPACE_ID }, +#endif }; int i; int n_spaces = sizeof preinit_spaces / sizeof preinit_spaces[0]; - boolean success = 1; for (i = 0; i< n_spaces; ++i) { if (!preinit_spaces[i].size) continue; - if (hard_failp) - ensure_space(NOT_MOVABLE | should_allocate_low, - preinit_spaces[i].start, preinit_spaces[i].size); - else if (!os_validate(NOT_MOVABLE | should_allocate_low, + if (os_alloc_gc_space(preinit_spaces[i].id, + NOT_MOVABLE | should_allocate_low, (os_vm_address_t)preinit_spaces[i].start, - preinit_spaces[i].size)) { - success = 0; - break; - } + preinit_spaces[i].size)) continue; + if (!hard_failp) return 0; // soft fail. Try again after disabling ASLR + fprintf(stderr, + "failed to allocate %lu bytes at %p\n", + (long unsigned)preinit_spaces[i].size, (void*)preinit_spaces[i].start); + fprintf(stderr, + "(hint: Try \"ulimit -a\"; maybe you should increase memory limits.)\n"); + exit(1); } -#ifdef PRINTNOISE - printf(" done.\n"); -#endif - return success; + return 1; } void @@ -131,34 +125,30 @@ allocate_lisp_dynamic_space(boolean did_preinit) if (!did_preinit) allocate_hardwired_spaces(1); -#ifdef LISP_FEATURE_OS_PROVIDES_DLOPEN ensure_undefined_alien(); -#endif } static inline void -protect_page(void *page, int protect_p, os_vm_prot_t flags) { +protect_guard_page(void *page, int protect_p, os_vm_prot_t flags) { os_protect(page, os_vm_page_size, protect_p ? - flags : OS_VM_PROT_ALL); + flags : OS_VM_PROT_READ | OS_VM_PROT_WRITE); } #define DEF_PROTECT_PAGE(name,page_name,flags) \ void \ protect_##name(int protect_p, struct thread *thread) { \ if (!thread) \ - thread = arch_os_get_current_thread(); \ - protect_page(page_name(thread), protect_p, flags); \ + thread = get_sb_vm_thread(); \ + protect_guard_page(page_name(thread), protect_p, flags); \ } DEF_PROTECT_PAGE(control_stack_hard_guard_page, CONTROL_STACK_HARD_GUARD_PAGE, OS_VM_PROT_NONE) DEF_PROTECT_PAGE(control_stack_guard_page, - CONTROL_STACK_GUARD_PAGE, - OS_VM_PROT_READ|OS_VM_PROT_EXECUTE) + CONTROL_STACK_GUARD_PAGE, OS_VM_PROT_READ) DEF_PROTECT_PAGE(control_stack_return_guard_page, - CONTROL_STACK_RETURN_GUARD_PAGE, - OS_VM_PROT_READ|OS_VM_PROT_EXECUTE) + CONTROL_STACK_RETURN_GUARD_PAGE, OS_VM_PROT_READ) DEF_PROTECT_PAGE(binding_stack_hard_guard_page, BINDING_STACK_HARD_GUARD_PAGE, diff --git a/src/runtime/validate.h b/src/runtime/validate.h index 5862b97274..28a2813db2 100644 --- a/src/runtime/validate.h +++ b/src/runtime/validate.h @@ -21,13 +21,20 @@ #define ALIEN_STACK_SIZE (1024*1024) /* chosen at random */ /* eventually choosable per-thread: */ +#ifndef DEFAULT_CONTROL_STACK_SIZE // CFLAGS=-D... can set this #define DEFAULT_CONTROL_STACK_SIZE (2*1024*1024) +#endif /* constants derived from the fundamental constants in passed by GENESIS */ #define READ_ONLY_SPACE_SIZE (READ_ONLY_SPACE_END - READ_ONLY_SPACE_START) #define STATIC_SPACE_SIZE (STATIC_SPACE_END - STATIC_SPACE_START) -#define LINKAGE_TABLE_SPACE_SIZE \ - (LINKAGE_TABLE_SPACE_END - LINKAGE_TABLE_SPACE_START) + +#ifdef LISP_FEATURE_DARWIN_JIT +#define STATIC_CODE_SPACE_SIZE (STATIC_CODE_SPACE_END - STATIC_CODE_SPACE_START) +#endif + +#define ALIEN_LINKAGE_TABLE_SPACE_END \ + (ALIEN_LINKAGE_TABLE_SPACE_START + ALIEN_LINKAGE_TABLE_SPACE_SIZE) #if !defined(__ASSEMBLER__) #include "thread.h" @@ -51,7 +58,7 @@ #endif -#ifdef ALIEN_STACK_GROWS_DOWNWARD +#ifndef ALIEN_STACK_GROWS_UPWARD #define ALIEN_STACK_HARD_GUARD_PAGE(th) \ ((os_vm_address_t)(th->alien_stack_start)) @@ -60,7 +67,7 @@ #define ALIEN_STACK_RETURN_GUARD_PAGE(th) \ (ALIEN_STACK_GUARD_PAGE(th) + os_vm_page_size) -#elif defined(ALIEN_STACK_GROWS_UPWARD) +#else #define ALIEN_STACK_HARD_GUARD_PAGE(th) \ (((os_vm_address_t)th->alien_stack_start) + ALIEN_STACK_SIZE - \ @@ -70,8 +77,6 @@ #define ALIEN_STACK_RETURN_GUARD_PAGE(th) \ (ALIEN_STACK_GUARD_PAGE(th) - os_vm_page_size) -#else -#error ALIEN_STACK_GROWS_DOWNWARD or ALIEN_STACK_GROWS_UPWARD has to be defined #endif #define BINDING_STACK_HARD_GUARD_PAGE(th) \ @@ -115,7 +120,7 @@ extern os_vm_address_t undefined_alien_address; * #include "x86-validate.h" * #endif * and so forth. In SBCL, the memory map data are defined at the Lisp - * level (compiler/target/parms.lisp) and stuffed into the sbcl.h file + * level (compiler/{arch}/parms.lisp) and stuffed into the sbcl.h file * created by GENESIS, so there's no longer a need for an * architecture-dependent header file of memory map data. */ diff --git a/src/runtime/var-io.c b/src/runtime/var-io.c index 1ccec7278c..b7ed9aace4 100644 --- a/src/runtime/var-io.c +++ b/src/runtime/var-io.c @@ -9,6 +9,11 @@ * files for more information. */ +#include "genesis/config.h" +#include "genesis/bignum.h" +#include "gc-assert.h" +#include "var-io.h" + // Read a variable-length encoded 32-bit integer from SOURCE and // return its value. // @@ -35,3 +40,59 @@ int read_var_integer(unsigned char *source, int *offset) { } return result; } + +void varint_unpacker_init(struct varint_unpacker* unpacker, lispobj integer) +{ + if (fixnump(integer)) { + unpacker->word = fixnum_value(integer); + unpacker->limit = N_WORD_BYTES; + unpacker->data = (char*)&unpacker->word; + } else { + gc_assert(lowtag_of(integer) == OTHER_POINTER_LOWTAG + && widetag_of(native_pointer(integer)) == BIGNUM_WIDETAG); + struct bignum* bignum = (struct bignum*)(integer - OTHER_POINTER_LOWTAG); + unpacker->word = 0; + unpacker->limit = HeaderValue(bignum->header) * N_WORD_BYTES; + unpacker->data = (char*)bignum->digits; + } + unpacker->index = 0; +} + +// Fetch the next varint from 'unpacker' into 'result'. +// Because there is no length prefix on the number of varints encoded, +// spurious trailing zeros might be observed. The data consumer can +// circumvent that by storing a count as the first value in the series. +// Return 1 for success, 0 for EOF. +int varint_unpack(struct varint_unpacker* unpacker, int* result) +{ + if (unpacker->index >= unpacker->limit) return 0; + int accumulator = 0; + int shift = 0; + while (1) { +#ifdef LISP_FEATURE_LITTLE_ENDIAN + int byte = unpacker->data[unpacker->index]; +#else + // bignums are little-endian in word order, + // but machine-native within each word. + // We could pack bytes MSB-to-LSB in the bigdigits, + // but that seems less intuitive on the Lisp side. + int word_index = unpacker->index / N_WORD_BYTES; + int byte_index = unpacker->index % N_WORD_BYTES; + int byte = (((uword_t*)unpacker->data)[word_index] >> (byte_index * 8)) & 0xFF; +#endif + ++unpacker->index; + accumulator |= (byte & 0x7F) << shift; + if (!(byte & 0x80)) break; + gc_assert(unpacker->index < unpacker->limit); + shift += 7; + } + *result = accumulator; + return 1; +} + +void skip_data_stream(struct varint_unpacker* unpacker) +{ + // Read elements until seeing a 0 + int val; + while (varint_unpack(unpacker, &val) && val != 0) { } +} diff --git a/src/runtime/var-io.h b/src/runtime/var-io.h index 2ea8db738e..931d0a19ad 100644 --- a/src/runtime/var-io.h +++ b/src/runtime/var-io.h @@ -25,5 +25,6 @@ struct varint_unpacker { void varint_unpacker_init(struct varint_unpacker*, lispobj); int varint_unpack(struct varint_unpacker*, int*); +void skip_data_stream(struct varint_unpacker* unpacker); #endif /* _VAR_IO_H_ */ diff --git a/src/runtime/verify.inc b/src/runtime/verify.inc new file mode 100644 index 0000000000..b05232a4d2 --- /dev/null +++ b/src/runtime/verify.inc @@ -0,0 +1,660 @@ +/* -*- Mode: C -*- */ + +static int +is_in_stack_space(lispobj ptr) +{ + /* For space verification: Pointers can be valid if they point + * to a thread stack space. This would be faster if the thread + * structures had page-table entries as if they were part of + * the heap space. */ + /* Actually, no, how would that be faster? + * If you have to examine thread structures, you have to examine + * them all. This demands something like a binary search tree */ + struct thread *th; + for_each_thread(th) { + if ((th->control_stack_start <= (lispobj *)ptr) && + (th->control_stack_end >= (lispobj *)ptr)) { + return 1; + } + } + return 0; +} +static int is_in_static_space(void* ptr) { + return (uword_t)ptr >= STATIC_SPACE_START && (lispobj*)ptr < static_space_free_pointer; +} + +static boolean card_markedp(void* addr) +{ +#ifdef LISP_FEATURE_IMMOBILE_SPACE + if (immobile_space_p((lispobj)addr)) + return !immobile_card_protected_p(addr); +#endif + return gc_card_mark[addr_to_card_index(addr)] != CARD_UNMARKED; +} + +char *page_card_mark_string(page_index_t page, char *result) +{ + long card = addr_to_card_index(page_address(page)); + if (cardseq_all_marked_nonsticky(card)) + result[0] = '*', result[1] = 0; + else if (!cardseq_any_marked(card)) + result[0] = '-', result[1] = 0; + else { + int i; + for(i=0; i<CARDS_PER_PAGE; ++i) + switch (gc_card_mark[card+i] & MARK_BYTE_MASK) { + case CARD_MARKED: result[i] = '*'; break; + case CARD_UNMARKED: result[i] = '-'; break; +#ifdef LISP_FEATURE_SOFT_CARD_MARKS + case STICKY_MARK: result[i] = 'S'; break; +#else + case WP_CLEARED_AND_MARKED: result[i] = 'd'; break; // "d" is for dirty +#endif + default: result[i] = '?'; break; // illegal value + } + result[CARDS_PER_PAGE] = 0; + } + return result; +} + +#define PRINT_HEADER_ON_FAILURE 2048 + +// Check a single pointer. Return 1 if we should stop verifying due to too many errors. +// (Otherwise continue showing errors until then) +// NOTE: This function can produces false failure indications, +// usually related to dynamic space pointing to the stack of a +// dead thread, but there may be other reasons as well. +static void note_failure(lispobj thing, lispobj *where, struct verify_state *state, + char *str) +{ + if (state->flags & PRINT_HEADER_ON_FAILURE) { + if (state->flags & VERIFY_PRE_GC) fprintf(stderr, "pre-GC failure\n"); + if (state->flags & VERIFY_POST_GC) fprintf(stderr, "post-GC failure\n"); + state->flags &= ~PRINT_HEADER_ON_FAILURE; + } + if (state->object_addr) { + lispobj obj = compute_lispobj(state->object_addr); + page_index_t pg = find_page_index(state->object_addr); + fprintf(stderr, "Ptr %p @ %"OBJ_FMTX" (lispobj %"OBJ_FMTX",pg%d) sees %s\n", + (void*)thing, (uword_t)where, obj, (int)pg, str); + // Record this in state->err_objs if possible + int i; + for(i=0; i<MAX_ERR_OBJS; ++i) + if (!state->err_objs[i]) { + state->err_objs[i] = (uword_t)state->object_addr; + break; + } + } else { + fprintf(stderr, "Ptr %p @ %"OBJ_FMTX" sees %s\n", (void*)thing, (uword_t)where, str); + } +} + +static int +verify_pointer(lispobj thing, lispobj *where, struct verify_state *state) +{ + extern int valid_lisp_pointer_p(lispobj); + + /* Strict containment: no pointer from a heap space may point + * to anything outside of a heap space. */ + // boolean strict_containment = state->flags & VERIFY_FINAL; + +#define FAIL_IF(cond, why) \ + if (cond) { if (++state->nerrors > 25) return 1; note_failure(thing,where,state,why); } + + if (!is_lisp_pointer(thing)) { + FAIL_IF(!is_lisp_immediate(thing), "strange non-pointer"); + return 0; + } + // if (strict_containment && !gc_managed_heap_space_p(thing)) GC_WARN("non-Lisp memory"); + page_index_t source_page_index = find_page_index(where); + page_index_t target_page_index = find_page_index((void*)thing); + if (!(target_page_index >= 0 || immobile_space_p(thing))) return 0; // can't do much with it + if ((state->flags & VERIFY_TAGS) && target_page_index >= 0) { + if (listp(thing)) { + FAIL_IF(!(is_cons_half(CONS(thing)->car) && is_cons_half(CONS(thing)->cdr)), + "non-cons"); + } else { + FAIL_IF(LOWTAG_FOR_WIDETAG(widetag_of(native_pointer(thing))) != lowtag_of(thing), + "incompatible widetag"); + } + } + generation_index_t to_gen = +#ifdef LISP_FEATURE_IMMOBILE_SPACE + points_to_asm_code_p((uword_t)thing)? + gc_gen_of(make_lispobj((void*)asm_routines_start,OTHER_POINTER_LOWTAG),0): +#endif + gc_gen_of(thing, ARTIFICIALLY_HIGH_GEN); + if (to_gen < state->min_pointee_gen) state->min_pointee_gen = to_gen; + if (state->flags & VERIFY_QUICK) return 0; + if (target_page_index >= 0) { + // If it's within the dynamic space it should point to a used page. + FAIL_IF(page_free_p(target_page_index), "free page"); + FAIL_IF(!(page_table[target_page_index].type & OPEN_REGION_PAGE_FLAG) + && (thing & (GENCGC_PAGE_BYTES-1)) >= page_bytes_used(target_page_index), + "unallocated space"); + } else { + // The object pointed to must not have been discarded as garbage. + FAIL_IF(!other_immediate_lowtag_p(*native_pointer(thing)), "trashed object"); + } + // Must not point to a forwarding pointer + FAIL_IF(*native_pointer(thing) == FORWARDING_HEADER, "forwarding ptr"); + // Forbid pointers from R/O space into a GCed space + FAIL_IF((READ_ONLY_SPACE_START <= (uword_t)where && where < read_only_space_free_pointer), + "dynamic space from RO space"); + // Card marking invariant check, but only if the source of pointer is a heap object + if (header_widetag(state->object_header) == CODE_HEADER_WIDETAG + && ! is_in_static_space(state->object_addr) + && to_gen < state->object_gen) { + // two things must be true: + // 1. the card containing the code must be marked + FAIL_IF(!card_markedp(state->object_addr), "younger obj from WP'd code header page"); + // 2. the object header must be marked as written + if (!header_rememberedp(state->object_header)) + lose("code @ %p (g%d). word @ %p -> %"OBJ_FMTX" (g%d)", + state->object_addr, state->object_gen, where, thing, to_gen); + } else if ((state->flags & VERIFYING_GENERATIONAL) && to_gen < state->object_gen + && source_page_index >= 0) { + /* The WP criteria are: + * - CONS marks the exact card since it can't span cards + * - SIMPLE-VECTOR marks the card containing the cell with the old->young pointer. + * - Everything else marks the object header -OR- the card with the pointer. + * (either/or because Lisp marks the header card, + * but the collector marks the cell's card.) */ + int marked = card_markedp(where) +#ifdef LISP_FEATURE_SOFT_CARD_MARKS + || (state->object_header + && header_widetag(state->object_header) != SIMPLE_VECTOR_WIDETAG + && card_markedp(state->object_addr)) +#endif + ; + FAIL_IF(!marked, "younger obj from WP page"); + } + int valid; + if (state->flags & VERIFY_AGGRESSIVE) // Extreme paranoia mode + valid = valid_lisp_pointer_p(thing); + else { + /* Efficiently decide whether 'thing' is plausible. + * This MUST NOT use properly_tagged_descriptor_p() which + * assumes a known good object base address, and would + * "dangerously" scan a code component for embedded funs. */ + valid = plausible_tag_p(thing); + } + /* If 'thing' points to a stack, we can only hope that the stack + * frame is ok, or the object at 'where' is unreachable. */ + FAIL_IF(!valid && !is_in_stack_space(thing), "junk"); + return 0; +} +#define CHECK(pointer, where) if (verify_pointer(pointer, where, state)) return 1 + +/* Return 0 if good, 1 if bad */ +static int verify_headered_object(lispobj* object, sword_t nwords, + struct verify_state *state) +{ + long i; + int widetag = widetag_of(object); + if (instanceoid_widetag_p(widetag)) { + lispobj layout = layout_of(object); + if (layout) { + CHECK(layout, object); + struct bitmap bitmap = get_layout_bitmap(LAYOUT(layout)); + if (widetag_of(object) == FUNCALLABLE_INSTANCE_WIDETAG) { +#ifndef LISP_FEATURE_COMPACT_INSTANCE_HEADER + gc_assert(bitmap.bits[0] == (sword_t)-4); +#endif + } + if (lockfree_list_node_layout_p(LAYOUT(layout))) { + struct instance* node = (struct instance*)object; + lispobj next = node->slots[INSTANCE_DATA_START]; + if (fixnump(next) && next) + CHECK(next | INSTANCE_POINTER_LOWTAG, node->slots+INSTANCE_DATA_START); + } + for (i=0; i<(nwords-1); ++i) + if (bitmap_logbitp(i, bitmap)) CHECK(object[1+i], object+1+i); + } + return 0; + } + if (widetag == CODE_HEADER_WIDETAG) { + struct code *code = (struct code *)object; + gc_assert(fixnump(object[1])); // boxed size, needed for code_header_words() + sword_t nheader_words = code_header_words(code); + /* Verify the boxed section of the code data block */ + state->min_pointee_gen = ARTIFICIALLY_HIGH_GEN; +#ifdef LISP_FEATURE_UNTAGGED_FDEFNS + { + lispobj* pfdefn = code->constants + code_n_funs(code) * CODE_SLOTS_PER_SIMPLE_FUN; + lispobj* end = pfdefn + code_n_named_calls(code); + for ( ; pfdefn < end ; ++pfdefn) + if (*pfdefn) CHECK(*pfdefn | OTHER_POINTER_LOWTAG, pfdefn); + } +#endif + for (i=2; i <nheader_words; ++i) CHECK(object[i], object+i); + // Check the SIMPLE-FUN headers + for_each_simple_fun(i, fheaderp, code, 1, { +#if defined(LISP_FEATURE_COMPACT_INSTANCE_HEADER) + lispobj __attribute__((unused)) layout = funinstance_layout((lispobj*)fheaderp); + gc_assert(!layout || layout == LAYOUT_OF_FUNCTION); +#endif + }); +#if 0 // this looks redundant. It's checked with each pointer, no? + boolean rememberedp = header_rememberedp(code->header); + /* The remembered set invariant is that an object is marked "written" + * if and only if either it points to a younger object or is pointed + * to by a register or stack. (The pointed-to case assumes that the + * very next instruction on return from GC would store an old->young + * pointer into that object). Non-compacting GC does not have the + * "only if" part of that, nor does pre-GC verification because we + * don't test the generation of the newval when storing into code. */ + if (is_in_static_space(object)) { } + else if (compacting_p() && (state->flags & VERIFY_POST_GC) ? + (state->min_pointee_gen < state->object_gen) != rememberedp : + (state->min_pointee_gen < state->object_gen) && !rememberedp) + lose("object @ %p is gen%d min_pointee=gen%d %s", + (void*)state->tagged_object, state->object_gen, state->min_pointee_gen, + rememberedp ? "written" : "not written"); +#endif + return 0; + } +#ifdef LISP_FEATURE_COMPACT_SYMBOL + if (widetag == SYMBOL_WIDETAG) { + struct symbol* s = (void*)object; + CHECK(s->value, &s->value); + CHECK(s->fdefn, &s->fdefn); + CHECK(s->info, &s->info); + CHECK(decode_symbol_name(s->name), &s->name); + return 0; + } +#endif + if (widetag == FDEFN_WIDETAG) { + struct fdefn* f = (void*)object; + CHECK(f->name, &f->name); + CHECK(f->fun, &f->fun); + CHECK(decode_fdefn_rawfun(f), (lispobj*)&f->raw_addr); + return 0; + } + for (i=1; i<nwords; ++i) CHECK(object[i], object+i); + return 0; +} + +static int verify_range(lispobj* start, lispobj* end, struct verify_state* state) +{ + lispobj* where = start; + if (state->flags & VERIFYING_GENERATIONAL && find_page_index(start)>=0) { + page_index_t page = find_page_index(start); + if (page_table[page].type == PAGE_TYPE_CONS) + gc_assert(page_words_used(page) <= MAX_CONSES_PER_PAGE*CONS_SIZE); + } + if ((state->flags & VERIFYING_UNFORMATTED)) { + while (where < end) { + if (*where != NO_TLS_VALUE_MARKER) { + int result = verify_pointer(*where, where, state); + if (result) return result; + } + ++where; + } + return 0; + } + while (where < end) { + int widetag = is_header(*where) ? header_widetag(*where) : LIST_POINTER_LOWTAG; + /* Technically we should wait until after performing the widetag validity + * tests before calling the sizer. Otherwise the lossage message would + * not be as good as it could be. I guess that failure doesn't happen much */ + long nwords = object_size(where); + state->object_addr = where; + state->object_header = is_cons_half(*where) ? 0 : *where; + if (state->flags & VERIFYING_GENERATIONAL) { + page_index_t pg = find_page_index(where); + state->object_gen = pg >= 0 ? page_table[pg].gen : + gc_gen_of((lispobj)where, ARTIFICIALLY_HIGH_GEN); +#ifdef LISP_FEATURE_PPC64 + // Cons fillers (two words of all 1s) cause failure of + // the default verification logic, so brute-force skip them + // regardless of whether the page type is PAGE_TYPE_CONS. + if (*where == (uword_t)-1 && where[1] == (uword_t)-1) { + where +=2; + continue; + } +#endif + if (widetag != FILLER_WIDETAG && pg >= 0) { + // Assert proper page type + if (state->object_header) // is not a cons + gc_assert(page_table[pg].type != PAGE_TYPE_CONS); +#ifdef LISP_FEATURE_USE_CONS_REGION + else if (page_table[pg].type != PAGE_TYPE_CONS) { + if (where[0] | where[1]) // (0 . 0) cons is OK + gc_assert(where[0]==(uword_t)-1 && + (where[1]==0 || where[1]==(uword_t)-1)); + } +#endif + if (widetag == CODE_HEADER_WIDETAG) { + if (!is_code(page_table[pg].type)) + lose("object @ %p is code on non-code page", where); + } else if (widetag == FUNCALLABLE_INSTANCE_WIDETAG) { + // where these reside depends on the architecture + } else { + if (is_code(page_table[pg].type)) + lose("object @ %p is non-code on code page", where); + } + } + } + if (!state->object_header) { + if (verify_pointer(where[0], where+0, state) || + verify_pointer(where[1], where+1, state)) break; + } else if (widetag == FILLER_WIDETAG) { // do nothing + } else if (!(other_immediate_lowtag_p(widetag) && LOWTAG_FOR_WIDETAG(widetag))) { + lose("Unhandled widetag %"OBJ_FMTX" @ %p", *where, where); + } else if (leaf_obj_widetag_p(widetag)) { +#ifdef LISP_FEATURE_UBSAN + if (specialized_vector_widetag_p(widetag)) { + if (is_lisp_pointer(object[1])) { + struct vector* bits = (void*)native_pointer(object[1]); + if (header_widetag(bits->header) != SIMPLE_BIT_VECTOR_WIDETAG) + lose("bad shadow bits for %p", where); + gc_assert(header_widetag(bits->header) == SIMPLE_BIT_VECTOR_WIDETAG); + gc_assert(vector_len(bits) >= vector_len((struct vector*)object)); + } + } +#endif + boolean strict_containment = state->flags & VERIFY_FINAL; + if (strict_containment && gencgc_verbose && widetag == SAP_WIDETAG && where[1]) + fprintf(stderr, "\nStrange SAP %p -> %p\n", where, (void*)where[1]); + } else { + if (verify_headered_object(where, nwords, state)) break; + } + where += nwords; + } + return 0; +} + +static int verify(lispobj start, lispobj* end, struct verify_state* state, int flags) +{ + int savedflags = state->flags; + state->flags |= flags; + int result = verify_range((lispobj*)start, end, state); + state->flags = savedflags; + return result; +} + +extern void save_gc_crashdump(char *, lispobj*); +/* Return the number of verification errors found. + * You might want to use that as a deciding factor for dump the heap + * to a file (which takes time, and generally isn't needed). + * But if a particular verification fails, then do dump it */ +int verify_heap(__attribute__((unused)) lispobj* cur_thread_approx_stackptr, + int flags) +{ + int verbose = gencgc_verbose | ((flags & VERIFY_VERBOSE) != 0); + + struct verify_state state; + memset(&state, 0, sizeof state); + state.flags = flags; + + if (verbose) + fprintf(stderr, + flags & VERIFY_PRE_GC ? "Verify before GC" : + flags & VERIFY_POST_GC ? "Verify after GC(%d)" : + "Heap check", // if called at a random time + (int)(flags>>16)); // generation number + else + state.flags |= PRINT_HEADER_ON_FAILURE; + +#ifdef LISP_FEATURE_IMMOBILE_SPACE +# ifdef __linux__ + // Try this verification if immobile-space was compiled with extra debugging. + // But weak symbols don't work on macOS. + extern void __attribute__((weak)) check_text_pages(); + if (&check_text_pages) check_text_pages(); +# endif + if (verbose) + fprintf(stderr, " [immobile]"); + if (verify(FIXEDOBJ_SPACE_START, + fixedobj_free_pointer, &state, + flags | VERIFYING_GENERATIONAL)) goto out; + if (verify(TEXT_SPACE_START, + text_space_highwatermark, &state, + flags | VERIFYING_GENERATIONAL)) goto out; +#endif + struct thread *th; + if (verbose) + fprintf(stderr, " [threads]"); + state.object_addr = 0; + state.object_gen = 0; + for_each_thread(th) { + if (verify((lispobj)th->binding_stack_start, + (lispobj*)get_binding_stack_pointer(th), &state, + VERIFYING_UNFORMATTED)) goto out; +#ifdef LISP_FEATURE_SB_THREAD + if (verify((lispobj)&th->lisp_thread, + (lispobj*)(SymbolValue(FREE_TLS_INDEX,0) + (char*)th), &state, + VERIFYING_UNFORMATTED)) + goto out; +#endif + } + if (verbose) + fprintf(stderr, " [RO]"); + if (verify(READ_ONLY_SPACE_START, read_only_space_free_pointer, &state, 0)) goto out; +#ifdef LISP_FEATURE_METASPACE + if (verify(METASPACE_START, (lispobj*)READ_ONLY_SPACE_END, &state, 0)) goto out; +#endif + if (verbose) + fprintf(stderr, " [static]"); + // Just don't worry about NIL, it's seldom the problem + // if (verify(NIL_SYMBOL_SLOTS_START, (lispobj*)NIL_SYMBOL_SLOTS_END, &state, 0)) goto out; + if (verify(STATIC_SPACE_OBJECTS_START, static_space_free_pointer, &state, 0)) goto out; + if (verbose) + fprintf(stderr, " [dynamic]"); + state.flags |= VERIFYING_GENERATIONAL; + walk_generation((uword_t(*)(lispobj*,lispobj*,uword_t))verify_range, + -1, (uword_t)&state); + if (verbose && state.nerrors==0) fprintf(stderr, " passed\n"); + out: + if (state.nerrors && !(flags & VERIFY_DONT_LOSE)) { + // dump_spaces(&state, "verify failed"); + lose("Verify failed: %d errors", state.nerrors); + } + return state.nerrors; +} + +void gc_show_pte(lispobj obj) +{ + char marks[1+CARDS_PER_PAGE]; + page_index_t page = find_page_index((void*)obj); + if (page>=0) { + printf("page %"PAGE_INDEX_FMT" base %p gen %d type %x ss %p used %x", + page, page_address(page), page_table[page].gen, page_table[page].type, + page_scan_start(page), page_bytes_used(page)); + if (page_starts_contiguous_block_p(page)) printf(" startsblock"); + if (page_ends_contiguous_block_p(page, page_table[page].gen)) printf(" endsblock"); + printf(" (%s)\n", page_card_mark_string(page, marks)); + return; + } +#ifdef LISP_FEATURE_IMMOBILE_SPACE + page = find_text_page_index((void*)obj); + if (page>=0) { + lispobj* text_page_scan_start(low_page_index_t page); + int gens = text_page_genmask[page]; + char genstring[9]; + int i; + for (i=0;i<8;++i) genstring[i] = (gens & (1<<i)) ? '0'+i : '-'; + genstring[8] = 0; + printf("page %ld (v) base %p gens %s ss=%p%s\n", + page, text_page_address(page), genstring, + text_page_scan_start(page), + card_markedp((void*)obj)?"":" WP"); + return; + } + page = find_fixedobj_page_index((void*)obj); + if (page>=0) { + printf("page %ld (f) align %d gens %x%s\n", page, + fixedobj_pages[page].attr.parts.obj_align, + fixedobj_pages[page].attr.parts.gens_, + card_markedp((void*)obj)?"": " WP"); + return; + } +#endif + printf("not in GC'ed space\n"); +} + +#include <stdio.h> + +static int hexdump_counter; + +extern void dump_immobile_fixedobjs(lispobj* where, lispobj* end, FILE*f); +extern void dump_immobile_text(lispobj* where, lispobj* end, FILE*f); +static int dump_completely_p(lispobj* obj, struct verify_state* state) +{ + int i; + if (!state) { + page_index_t pg = find_page_index(obj); + if (pg >= 10470 && pg <= 10485) return 1; // (as an example) + return 0; + } + for (i=0; i<MAX_ERR_OBJS; ++i) + if (state->err_objs[i] == (uword_t)obj) return 1; + return 0; +} +static void hexdump_control_stacks(__attribute__((unused)) void* approximate_stackptr, + __attribute__((unused)) FILE *stream) +{ +#ifdef LISP_FEATURE_C_STACK_IS_CONTROL_STACK + struct thread* th; + for_each_thread(th) { + if (th->state_word.state == STATE_DEAD) continue; + lispobj* stackptr; + if (th == get_sb_vm_thread()) { + stackptr = approximate_stackptr; + } else { + int ici = fixnum_value(read_TLS(FREE_INTERRUPT_CONTEXT_INDEX,th))-1; + os_context_t *c = nth_interrupt_context(ici, th); + stackptr = (lispobj*) *os_context_register_addr(c,reg_SP); + } + gc_assert(((uword_t)stackptr & (LOWTAG_MASK>>1)) == 0); // lispword-aligned + lispobj* where = th->control_stack_end; + fprintf(stream, "\nThread @ %p\n", th); + for (--where; where >= stackptr; --where) { + lispobj word = *where; + if (!fixnump(word) && gc_managed_addr_p(word)) + fprintf(stream, " %p: %"OBJ_FMTX"\n", where, word); + } + } +#endif +} + +#define HEXDUMP_PATH_TEMPLATE "/var/tmp/heap-%d-%d.txt" + +/* Dump spaces as human-readable text (hexadecimal) */ +void hexdump_spaces(struct verify_state* state, char *reason) +{ + char path[100]; + + ++hexdump_counter; + sprintf(path, HEXDUMP_PATH_TEMPLATE, getpid(), hexdump_counter); + FILE *f = fopen(path, "w"); + +#ifdef LISP_FEATURE_IMMOBILE_SPACE + fprintf(f, "Fixedobj space:\n"); + dump_immobile_fixedobjs((lispobj*)FIXEDOBJ_SPACE_START, fixedobj_free_pointer, f); + fprintf(f, "Text space (tlsf mem @ %p):\n", tlsf_mem_start); + dump_immobile_text((lispobj*)TEXT_SPACE_START, text_space_highwatermark, f); +#endif + + fprintf(f, "Dynamic space:\n"); + page_index_t firstpage = 0, lastpage; + while (firstpage < next_free_page) { + lastpage = firstpage; + while (!page_ends_contiguous_block_p(lastpage, page_table[firstpage].gen)) + lastpage++; + if (!page_bytes_used(firstpage)) { + firstpage = 1+lastpage; + continue; + } + lispobj* base = (lispobj*)page_address(firstpage); + lispobj* limit = (lispobj*)page_address(lastpage) + page_words_used(lastpage); + fprintf(f, "range %d:%d (%p:%p) t%d g%d ", + (int)firstpage, (int)lastpage, base, limit, + page_table[firstpage].type, page_table[firstpage].gen); + page_index_t p; + for (p = firstpage; p <= lastpage; ++p) { + char marks[1+CARDS_PER_PAGE]; + putc((p == firstpage) ? '(' : ' ', f); + fprintf(f, "%s", page_card_mark_string(p, marks)); + } + fprintf(f, ")\n"); + lispobj *where = base; + while (where<limit){ + int nwords = object_size(where); + /* If your'e having trouble with a subset of objects, and you can get + * a reliable reproducer, this predicate can decide which objects to + * output in full. Generally you don't need that much output */ + if (widetag_of(where) == FILLER_WIDETAG) { + lispobj* end = where + (1+HeaderValue(*where)); + fprintf(f, " %06x: fill to %p\n", (int)(uword_t)where & 0xffffff, end); + } else if (dump_completely_p(where, state)) { + int i; + for(i=0;i<nwords;++i) { + uword_t word = where[i]; + if (i==0) + fprintf(f, " %06x: %"OBJ_FMTX, (int)(uword_t)(where+i) & 0xffffff, word); + else + fprintf(f, " %04x: %"OBJ_FMTX, (int)(uword_t)(where+i) & 0xffff, word); +#ifdef LISP_FEATURE_IMMOBILE_SPACE + if (i == 0 && header_widetag(word) == INSTANCE_WIDETAG) word >>= 32; +#endif + if (is_lisp_pointer(word) + && (find_page_index((void*)word)>=0 || immobile_space_p(word))) + fprintf(f, " (g%d)", gc_gen_of(word, 0xff)); + fprintf(f,"\n"); + } + } else { + int min_gen = 8; + int prefix = ' '; + if (widetag_of(where)==CODE_HEADER_WIDETAG && header_rememberedp(*where)) + prefix = '#'; + else if (card_dirtyp(addr_to_card_index(where))) + prefix = '|'; + fprintf(f, "%c%06x: %"OBJ_FMTX, prefix, (int)(uword_t)where & 0xffffff, *where); + int i; + int boxed_nwords = nwords; + // This is just a heuristic guess of pointee generation. + // For code it's (mostly) right, for other things it's slightly less right + // because we're really not respecting the tagged or raw nature of each word. + if (widetag_of(where)==CODE_HEADER_WIDETAG) + boxed_nwords = code_header_words((struct code*)where); + for (i=0; i<boxed_nwords; ++i) { + uword_t word = where[i]; + page_index_t pointee_page; + if (is_lisp_pointer(word) && (pointee_page=find_page_index((void*)word))>=0 + && page_table[pointee_page].gen < min_gen) + min_gen = page_table[pointee_page].gen; + } + if (min_gen != 8) + fprintf(f, " (>g%d)\n", min_gen); + else + fprintf(f, "\n"); + } + where += nwords; + } + fprintf(f,"--\n"); + firstpage = 1+lastpage; + } + hexdump_control_stacks(&reason, f); + fclose(f); + fprintf(stderr, "%s: wrote [%s]\n", reason, path); +} + +int hexdump_enabled = 0; + +int hexdump_and_verify_heap(lispobj* cur_thread_approx_stackptr, int flags) +{ + if (hexdump_enabled) hexdump_spaces(0, flags & VERIFY_POST_GC ? "post-GC" : "pre-GC"); +#if 0 + if (hexdump_counter >= 9) { + char pathname[128]; + sprintf(pathname, "gc-%d-%d-%d-%s.bin", + getpid(), n_gcs, from_space, + flags & VERIFY_POST_GC ? "post" : "pre"); + save_gc_crashdump(pathname, cur_thread_approx_stackptr); + fprintf(stderr, "Wrote [%s]\n", pathname); + } +#endif + return verify_heap(cur_thread_approx_stackptr, flags); +} diff --git a/src/runtime/weak-hash-pred.inc b/src/runtime/weak-hash-pred.inc index cdf839e38d..45ea04052c 100644 --- a/src/runtime/weak-hash-pred.inc +++ b/src/runtime/weak-hash-pred.inc @@ -1,3 +1,5 @@ +/* -*- Mode: C -*- */ + static int survived_gc_yet_KEY(lispobj key, lispobj __attribute__((unused)) value) { return !is_lisp_pointer(key) || pointer_survived_gc_yet(key); } diff --git a/src/runtime/win32-os.c b/src/runtime/win32-os.c index 2354bd40de..a48c29f457 100644 --- a/src/runtime/win32-os.c +++ b/src/runtime/win32-os.c @@ -22,7 +22,7 @@ /* * This file was copied from the Linux version of the same, and - * likely still has some linuxisms in it have haven't been elimiated + * likely still has some linuxisms in it have haven't been eliminated * yet. */ @@ -36,7 +36,6 @@ #include "os.h" #include "arch.h" #include "globals.h" -#include "sbcl.h" #include "interrupt.h" #include "interr.h" #include "lispregs.h" @@ -59,17 +58,15 @@ #include "validate.h" #include "thread.h" #include "align.h" - -#ifndef LISP_FEATURE_SB_THREAD -/* dummy definition to reduce ifdef clutter */ -#define WITH_GC_AT_SAFEPOINTS_ONLY() if (0) ; else -#endif +#include "unaligned.h" #include "gc.h" +#include "gc-private.h" #include "gencgc-internal.h" #include <wincrypt.h> #include <stdarg.h> #include <string.h> +#include "print.h" /* missing definitions for modern mingws */ #ifndef EH_UNWINDING @@ -79,9 +76,6 @@ #define EH_EXIT_UNWIND 0x04 #endif -/* Tired of writing arch_os_get_current_thread each time. */ -#define this_thread (arch_os_get_current_thread()) - /* Documented limit for ReadConsole/WriteConsole is 64K bytes. Real limit observed on W2K-SP3 is somewhere in between 32KiB and 64Kib... */ @@ -93,140 +87,6 @@ typedef WCHAR console_char; typedef CHAR console_char; #endif -/* wrappers for winapi calls that must be successful (like SBCL's - * (aver ...) form). */ - -/* win_aver function: basic building block for miscellaneous - * ..AVER.. macrology (below) */ - -/* To do: These routines used to be "customizable" with dyndebug_init() - * and variables like dyndebug_survive_aver, dyndebug_skip_averlax based - * on environment variables. Those features got lost on the way, but - * ought to be reintroduced. */ - -static inline -intptr_t win_aver(intptr_t value, char* comment, char* file, int line, - int justwarn) -{ - if (!value) { - LPSTR errorMessage = "<FormatMessage failed>"; - DWORD errorCode = GetLastError(), allocated=0; - int posixerrno = errno; - const char* posixstrerror = strerror(errno); - char* report_template = - "Expression unexpectedly false: %s:%d\n" - " ... %s\n" - " ===> returned #X%p, \n" - " (in thread %p)" - " ... Win32 thinks:\n" - " ===> code %u, message => %s\n" - " ... CRT thinks:\n" - " ===> code %u, message => %s\n"; - - allocated = - FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER| - FORMAT_MESSAGE_FROM_SYSTEM, - NULL, - errorCode, - MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US), - (LPSTR)&errorMessage, - 1024u, - NULL); - - if (justwarn) { - fprintf(stderr, report_template, - file, line, - comment, value, - this_thread, - (unsigned)errorCode, errorMessage, - posixerrno, posixstrerror); - } else { - lose(report_template, - file, line, - comment, value, - this_thread, - (unsigned)errorCode, errorMessage, - posixerrno, posixstrerror); - } - if (allocated) - LocalFree(errorMessage); - } - return value; -} - -/* sys_aver function: really tiny adaptor of win_aver for - * "POSIX-parody" CRT results ("lowio" and similar stuff): - * negative number means something... negative. */ -static inline -intptr_t sys_aver(long value, char* comment, char* file, int line, - int justwarn) -{ - win_aver((intptr_t)(value>=0),comment,file,line,justwarn); - return value; -} - -/* Check for (call) result being boolean true. (call) may be arbitrary - * expression now; massive attack of gccisms ensures transparent type - * conversion back and forth, so the type of AVER(expression) is the - * type of expression. Value is the same _if_ it can be losslessly - * converted to (void*) and back. - * - * Failed AVER() is normally fatal. Well, unless dyndebug_survive_aver - * flag is set. */ - -#define AVER(call) \ - ({ __typeof__(call) __attribute__((unused)) me = \ - (__typeof__(call)) \ - win_aver((intptr_t)(call), #call, __FILE__, __LINE__, 0); \ - me;}) - -/* AVERLAX(call): do the same check as AVER did, but be mild on - * failure: print an annoying unrequested message to stderr, and - * continue. With dyndebug_skip_averlax flag, AVERLAX stop even to - * check and complain. */ - -#define AVERLAX(call) \ - ({ __typeof__(call) __attribute__((unused)) me = \ - (__typeof__(call)) \ - win_aver((intptr_t)(call), #call, __FILE__, __LINE__, 1); \ - me;}) - -/* Now, when failed AVER... prints both errno and GetLastError(), two - * variants of "POSIX/lowio" style checks below are almost useless - * (they build on sys_aver like the two above do on win_aver). */ - -#define CRT_AVER_NONNEGATIVE(call) \ - ({ __typeof__(call) __attribute__((unused)) me = \ - (__typeof__(call)) \ - sys_aver((call), #call, __FILE__, __LINE__, 0); \ - me;}) - -#define CRT_AVERLAX_NONNEGATIVE(call) \ - ({ __typeof__(call) __attribute__((unused)) me = \ - (__typeof__(call)) \ - sys_aver((call), #call, __FILE__, __LINE__, 1); \ - me;}) - -/* to be removed */ -#define CRT_AVER(booly) \ - ({ __typeof__(booly) __attribute__((unused)) me = (booly); \ - sys_aver((booly)?0:-1, #booly, __FILE__, __LINE__, 0); \ - me;}) - -const char * t_nil_s(lispobj symbol); - -/* - * The following signal-mask-related alien routines are called from Lisp: - */ - -/* As of win32, deferrables _do_ matter. gc_signal doesn't. */ -unsigned long block_deferrables_and_return_mask() -{ - sigset_t sset; - block_deferrable_signals(&sset); - return (unsigned long)sset; -} - /* The exception handling function looks like this: */ EXCEPTION_DISPOSITION handle_exception(EXCEPTION_RECORD *, struct lisp_exception_frame *, @@ -239,37 +99,28 @@ EXCEPTION_DISPOSITION handle_exception(EXCEPTION_RECORD *, * exception frame on nested funcall()s also points to it. */ - -void *base_seh_frame; - HMODULE runtime_module_handle = 0u; +#ifdef LISP_FEATURE_X86 static void *get_seh_frame(void) { void* retval; -#ifdef LISP_FEATURE_X86 asm volatile ("mov %%fs:0,%0": "=r" (retval)); -#else - asm volatile ("mov %%gs:0,%0": "=r" (retval)); -#endif return retval; } static void set_seh_frame(void *frame) { -#ifdef LISP_FEATURE_X86 asm volatile ("mov %0,%%fs:0": : "r" (frame)); -#else - asm volatile ("mov %0,%%gs:0": : "r" (frame)); -#endif } +#endif #if defined(LISP_FEATURE_SB_THREAD) void alloc_gc_page() { - AVER(VirtualAlloc(GC_SAFEPOINT_PAGE_ADDR, BACKEND_PAGE_BYTES, - MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE)); + gc_assert(VirtualAlloc(GC_SAFEPOINT_PAGE_ADDR, BACKEND_PAGE_BYTES, + MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE)); } /* Permit loads from GC_SAFEPOINT_PAGE_ADDR (NB page state change is @@ -296,20 +147,19 @@ void alloc_gc_page() void map_gc_page() { DWORD oldProt; - AVER(VirtualProtect((void*) GC_SAFEPOINT_PAGE_ADDR, BACKEND_PAGE_BYTES, - PAGE_READWRITE, &oldProt)); + gc_assert(VirtualProtect((void*) GC_SAFEPOINT_PAGE_ADDR, BACKEND_PAGE_BYTES, + PAGE_READWRITE, &oldProt)); } void unmap_gc_page() { DWORD oldProt; - AVER(VirtualProtect((void*) GC_SAFEPOINT_PAGE_ADDR, BACKEND_PAGE_BYTES, - PAGE_NOACCESS, &oldProt)); + gc_assert(VirtualProtect((void*) GC_SAFEPOINT_PAGE_ADDR, BACKEND_PAGE_BYTES, + PAGE_NOACCESS, &oldProt)); } #endif -#if defined(LISP_FEATURE_LINKAGE_TABLE) /* This feature has already saved me more development time than it * took to implement. In its current state, ``dynamic RT<->core * linking'' is a protocol of initialization of C runtime and Lisp @@ -358,7 +208,7 @@ void unmap_gc_page() * bundle'' that rolls up your patch, redumps and -- presto -- 100MiB * program is fixed by sending and loading a 50KiB thingie. * - * However, until LISP_FEATURE_LINKAGE_TABLE, if your bug were fixed + * However, until LISP_FEATURE_ALIEN_LINKAGE_TABLE, if your bug were fixed * by modifying two lines of _C_ sources, a customer described above * had to be ready to receive and reinstall a new 100MiB * executable. With the aid of code below, deploying such a fix @@ -388,15 +238,6 @@ void unmap_gc_page() * ``global quiesce point'' that is generally required for this kind * of worldwide revolution -- around collect_garbage. * - * What's almost unnoticeable from the C side (where you are now, dear - * reader): using the same style for all linking is beautiful. I tried - * to leave old-style linking code in place for the sake of - * _non-linkage-table_ platforms (they probably don't have -ldl or its - * equivalent, like LL/GPA, at all) -- but i did it usually by moving - * the entire `old style' code under #-linkage-table and - * refactoring the `new style' branch, instead of cutting the tail - * piecemeal and increasing #+-ifdeffery amount & the world enthropy. - * * If we look at the majority of the ``new style'' code units, it's a * common thing to observe how #+-ifdeffery _vanishes_ instead of * multiplying: #-sb-xc, #+sb-xc-host and #-sb-xc-host end up @@ -481,7 +322,7 @@ void unmap_gc_page() * Of course, this name-parsing trick lacks conceptual clarity; we're * going to get rid of it eventually. */ -u32 os_get_build_time_shared_libraries(u32 excl_maximum, +uint32_t os_get_build_time_shared_libraries(uint32_t excl_maximum, void* opt_root, void** opt_store_handles, const char *opt_store_names[]) @@ -497,7 +338,7 @@ u32 os_get_build_time_shared_libraries(u32 excl_maximum, void* check_duplicates[excl_maximum]; - if ((*(u32*)base_magic_location)!=0x4550) { + if ((*(uint32_t*)base_magic_location)!=0x4550) { /* We don't need this DLL thingie _that_ much. If the world * has changed to a degree where PE magic isn't found, let's * silently return `no libraries detected'. */ @@ -516,7 +357,7 @@ u32 os_get_build_time_shared_libraries(u32 excl_maximum, &image_optional_header->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]; IMAGE_IMPORT_DESCRIPTOR* image_import_descriptor = base + image_import_direntry->VirtualAddress; - u32 nlibrary, j; + uint32_t nlibrary, j; for (nlibrary=0u; nlibrary < excl_maximum && image_import_descriptor->FirstThunk; @@ -584,7 +425,7 @@ u32 os_get_build_time_shared_libraries(u32 excl_maximum, } } -static u32 buildTimeImageCount = 0; +static uint32_t buildTimeImageCount = 0; static void* buildTimeImages[16]; /* Resolve symbols against the executable and its build-time dependencies */ @@ -592,6 +433,7 @@ void* os_dlsym_default(char* name) { unsigned int i; void* result = 0; + buildTimeImages[0] = (void*)runtime_module_handle; if (buildTimeImageCount == 0) { buildTimeImageCount = 1 + os_get_build_time_shared_libraries(15u, @@ -603,8 +445,6 @@ void* os_dlsym_default(char* name) return result; } -#endif /* LINKAGE_TABLE */ - #if defined(LISP_FEATURE_SB_THREAD) /* We want to get a slot in TIB that (1) is available at constant offset, (2) is our private property, so libraries wouldn't legally @@ -645,8 +485,44 @@ void* os_dlsym_default(char* name) started before _any_ TLS slot is allocated by libraries, and some C compiler vendors rely on this fact. */ +extern CRITICAL_SECTION code_allocator_lock, alloc_profiler_lock; +static CRITICAL_SECTION interrupt_io_lock; + +struct { + console_char buffer[MAX_CONSOLE_TCHARS]; + DWORD head, tail; + CRITICAL_SECTION lock; + CONDITION_VARIABLE cond_has_data; + CONDITION_VARIABLE cond_has_client; + HANDLE thread; + boolean initialized; + HANDLE handle; + boolean in_progress; +} ttyinput; + +#ifdef LISP_FEATURE_64_BIT +// 32-bit uses a hardwired value (63) as this index because codegen +// usese %FS:[a_constant] to get CURRENT-THREAD-SAP, etc. +DWORD sbcl_thread_tls_index; +#endif + int os_preinit(char *argv[], char *envp[]) { +#ifdef LISP_FEATURE_SB_FUTEX + if (GetModuleHandle("API-MS-Win-Core-Synch-l1-2-0") == NULL) { + // calling lose() here loses. Such irony. + fprintf(stderr, "This binary was compiled for Windows 8 or later but you appear to be" +" using 7 or earlier.\nRecompiling SBCL from source on the older release will" +" probably work. See also\n" + "https://support.microsoft.com/en-us/help/4057281/windows-7-support-ended-on-january-14-2020\n"); + fflush(stderr); + exit(1); + } +#endif + InitializeCriticalSection(&code_allocator_lock); + InitializeCriticalSection(&alloc_profiler_lock); + InitializeCriticalSection(&interrupt_io_lock); + InitializeCriticalSection(&ttyinput.lock); #ifdef LISP_FEATURE_X86 DWORD slots[TLS_MINIMUM_AVAILABLE]; DWORD key; @@ -657,7 +533,7 @@ int os_preinit(char *argv[], char *envp[]) if (TlsGetValue(key)!=NULL) lose("TLS slot assertion failed: fresh slot value is not NULL"); TlsSetValue(OUR_TLS_INDEX, (void*)(intptr_t)0xFEEDBAC4); - if ((intptr_t)(void*)arch_os_get_current_thread()!=(intptr_t)0xFEEDBAC4) + if ((intptr_t)(void*)get_sb_vm_thread()!=(intptr_t)0xFEEDBAC4) lose("TLS slot assertion failed: TIB layout change detected"); TlsSetValue(OUR_TLS_INDEX, NULL); break; @@ -672,61 +548,12 @@ int os_preinit(char *argv[], char *envp[]) "(last TlsAlloc() returned %u)",key); } #else - (void) argv; /* unused */ - (void) envp; /* unused */ + OUR_TLS_INDEX = TlsAlloc(); #endif return 0; } #endif /* LISP_FEATURE_SB_THREAD */ - -#ifdef LISP_FEATURE_X86_64 -/* Windows has 32-bit 'longs', so printf...%lX (and other %l patterns) doesn't - * work well with address-sized values, like it's done all over the place in - * SBCL. And msvcrt uses I64, not LL, for printing long longs. - * - * I've already had enough search/replace with longs/words/intptr_t for today, - * so I prefer to solve this problem with a format string translator. */ - -/* There is (will be) defines for printf and friends. */ - -static int translating_vfprintf(FILE*stream, const char *fmt, va_list args) -{ - char translated[1024]; - unsigned i=0, delta = 0; - - while (fmt[i-delta] && i<sizeof(translated)-1) { - if((fmt[i-delta]=='%')&& - (fmt[i-delta+1]=='l')) { - translated[i++]='%'; - translated[i++]='I'; - translated[i++]='6'; - translated[i++]='4'; - delta += 2; - } else { - translated[i]=fmt[i-delta]; - ++i; - } - } - translated[i++]=0; - return vfprintf(stream,translated,args); -} - -int printf(const char*fmt,...) -{ - va_list args; - va_start(args,fmt); - return translating_vfprintf(stdout,fmt,args); -} -int fprintf(FILE*stream,const char*fmt,...) -{ - va_list args; - va_start(args,fmt); - return translating_vfprintf(stream,fmt,args); -} - -#endif - int os_number_of_processors = 1; BOOL (*ptr_CancelIoEx)(HANDLE /*handle*/, LPOVERLAPPED /*overlapped*/); @@ -763,99 +590,184 @@ intptr_t win32_get_module_handle_by_address(os_vm_address_t addr) ? result : 0); } -void os_init(char __attribute__((__unused__)) *argv[], - char __attribute__((__unused__)) *envp[]) +/* + * x86-64 exception handling around foreign function calls. + * + * On x86-64, when an exception is raised, the Windows kernel looks up the RIP + * to retrieve an associated UNWIND_INFO object. This object informs the kernel + * whether there's an exception handler and how to find the start of the current + * frame. If there's no exception handler or it has declined to handle the + * exception, the frame's return address is looked up and the process is + * repeated, walking the stack until an exception handler handles the exception. + * If the exception goes unhandled, the process is usually terminated. Our goal, + * then, is to associate an appropriate UNWIND_INFO object with return addresses + * that point to Lisp code. We don't need to inform the kernel how to walk a + * Lisp frame, since our exception handler will always handle the exception. + * + * UNWIND_INFO objects are mapped onto their respective address ranges by + * RUNTIME_FUNCTION objects. These objects are usually stored in the .pdata + * section of an executable file, but can also be mapped dynamically via + * RtlAddFunctionTable(). + * + * A major constraint imposed by UNWIND_INFO and RUNTIME_FUNCTION is that the + * code's address range is specified by 32-bit relative addresses, which means + * we can only establish a frame-based handler for a 4 GB region at most. This + * is problematic because most Lisp code lives in dynamic space which can be + * much larger than 4 GB. Furthermore, the exception handler is also specified + * as a 32-bit relative address, so we can't directly reference our + * handle_exception() function. + * + * We work around this constraint by allocating these data structures in a fixed + * memory region at WIN64_SEH_DATA_ADDR and map an UNWIND_INFO to this region + * using RtlAddFunctionTable(). Foreign calls (see EMIT-C-CALL) place the target + * address in RBX and call a thunk within this region. The thunk swaps out the + * return address with the thunk's return address thereby establishing a + * frame-based exception handler. The original address (pointing into Lisp code) + * is stored in a non-volatile, callee-saved register, allowing the thunk to + * jump back to Lisp. The exception handler is a trampoline to + * handle_exception(). + * + * In the future, should we segregate code objects into dedicated code areas + * smaller than 4 GB, these thunks could be removed, and UNWIND_INFO could be + * associated directly with such areas. + */ + +#ifdef LISP_FEATURE_X86_64 +typedef struct _UNWIND_INFO { + uint8_t Version : 3; + uint8_t Flags : 5; + uint8_t SizeOfProlog; + uint8_t CountOfCodes; + uint8_t FrameRegister : 4; + uint8_t FrameOffset : 4; + ULONG ExceptionHandler; + ULONG ExceptionData[1]; +} UNWIND_INFO; + +struct win64_seh_data { + uint8_t direct_thunk[8]; + uint8_t indirect_thunk[8]; + uint8_t handler_trampoline[16]; + UNWIND_INFO ui; // needs to be DWORD-aligned + RUNTIME_FUNCTION rt; +}; + +static void +set_up_win64_seh_thunk(size_t page_size) +{ + if (page_size < sizeof(struct win64_seh_data)) + lose("Not enough space to allocate struct win64_seh_data"); + + gc_assert(VirtualAlloc(WIN64_SEH_DATA_ADDR, page_size, + MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE)); + + struct win64_seh_data *seh_data = (void *) WIN64_SEH_DATA_ADDR; + DWORD64 base = (DWORD64) seh_data; + + // 'volatile' works around "warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=]" + volatile uint8_t *dthunk = seh_data->direct_thunk; + dthunk[0] = 0x41; // pop r15 + dthunk[1] = 0x5F; + dthunk[2] = 0xFF; // call rbx + dthunk[3] = 0xD3; + dthunk[4] = 0x41; // push r15 + dthunk[5] = 0x57; + dthunk[6] = 0xC3; // ret + dthunk[7] = 0x90; // nop (padding) + + volatile uint8_t *ithunk = seh_data->indirect_thunk; + ithunk[0] = 0x41; // pop r15 + ithunk[1] = 0x5F; + ithunk[2] = 0xFF; // call qword ptr [rbx] + ithunk[3] = 0x13; + ithunk[4] = 0x41; // push r15 + ithunk[5] = 0x57; + ithunk[6] = 0xC3; // ret + ithunk[7] = 0x90; // nop (padding) + + volatile uint8_t *tramp = seh_data->handler_trampoline; + tramp[0] = 0xFF; // jmp qword ptr [rip+2] + tramp[1] = 0x25; + UNALIGNED_STORE32((void*volatile)(tramp+2), 2); + tramp[6] = 0x66; // 2-byte nop + tramp[7] = 0x90; + *(void **)(tramp+8) = handle_exception; + + UNWIND_INFO *ui = &seh_data->ui; + ui->Version = 1; + ui->Flags = UNW_FLAG_EHANDLER; + ui->SizeOfProlog = 0; + ui->CountOfCodes = 0; + ui->FrameRegister = 0; + ui->FrameOffset = 0; + ui->ExceptionHandler = (DWORD64) tramp - base; + ui->ExceptionData[0] = 0; + + RUNTIME_FUNCTION *rt = &seh_data->rt; + rt->BeginAddress = 0; + rt->EndAddress = 16; + rt->UnwindData = (DWORD64) ui - base; + + gc_assert(RtlAddFunctionTable(rt, 1, base)); +} +#endif + +static LARGE_INTEGER lisp_init_time; +static double qpcMultiplier; + +void os_init() { +#ifdef LISP_FEATURE_64_BIT + LARGE_INTEGER qpcFrequency; + if (!QueryPerformanceCounter(&lisp_init_time) || + !QueryPerformanceFrequency(&qpcFrequency)) + lose("Can't use monotonic realtime clock. Please report this as an SBCL bug"); + // Convert performance counter ticks per second into INTERNAL-TIME-UNITS-PER-SECOND + // (microseconds). In theory the performance counter can increment faster than + // or slower than I-T-U. Fwiw, on my machine the frequency is 10x I-T-U-P-S, + // so a single integer division by 10 would work, but I don't know in general + // what the ratio is. + qpcMultiplier = (double)1000000 / qpcFrequency.QuadPart; +#endif + SYSTEM_INFO system_info; GetSystemInfo(&system_info); os_vm_page_size = system_info.dwPageSize > BACKEND_PAGE_BYTES? system_info.dwPageSize : BACKEND_PAGE_BYTES; -#if defined(LISP_FEATURE_X86) - fast_bzero_pointer = fast_bzero_detect; -#endif os_number_of_processors = system_info.dwNumberOfProcessors; - base_seh_frame = get_seh_frame(); +#ifdef LISP_FEATURE_X86_64 + set_up_win64_seh_thunk(os_vm_page_size); +#endif resolve_optional_imports(); runtime_module_handle = (HMODULE)win32_get_module_handle_by_address(&runtime_module_handle); } -static inline boolean local_thread_stack_address_p(os_vm_address_t address) +#ifdef LISP_FEATURE_64_BIT +uword_t get_monotonic_time() { - return this_thread && - (((((u64)address >= (u64)this_thread->os_address) && - ((u64)address < ((u64)this_thread)-THREAD_CSP_PAGE_SIZE))|| - (((u64)address >= (u64)this_thread->control_stack_start)&& - ((u64)address < (u64)this_thread->control_stack_end)))); + LARGE_INTEGER t; + QueryPerformanceCounter(&t); + t.QuadPart -= lisp_init_time.QuadPart; + return (uword_t)((double)t.QuadPart * qpcMultiplier); } - -/* - * So we have three fun scenarios here. - * - * First, we could be being called to reserve the memory areas - * during initialization (prior to loading the core file). - * - * Second, we could be being called by the GC to commit a page - * that has just been decommitted (for easy zero-fill). - * - * Third, we could be being called by create_thread_struct() - * in order to create the sundry and various stacks. - * - * The third case is easy to pick out because it passes an - * addr of 0. - * - * The second case is easy to pick out because it will be for - * a range of memory that is MEM_RESERVE rather than MEM_FREE. - * - * The second case is also an easy implement, because we leave - * the memory as reserved (since we do lazy commits). - */ +#endif os_vm_address_t -os_validate(int attributes, os_vm_address_t addr, os_vm_size_t len) +os_alloc_gc_space(int space_id, int attributes, os_vm_address_t addr, os_vm_size_t len) { - MEMORY_BASIC_INFORMATION mem_info; - if (!addr) { - /* the simple case first */ int protection = attributes & IS_GUARD_PAGE ? PAGE_NOACCESS : PAGE_EXECUTE_READWRITE; - return - AVERLAX(VirtualAlloc(addr, len, MEM_RESERVE|MEM_COMMIT, protection)); + os_vm_address_t actual = VirtualAlloc(addr, len, MEM_RESERVE|MEM_COMMIT, protection); + gc_assert(actual); + return actual; } - if (!AVERLAX(VirtualQuery(addr, &mem_info, sizeof mem_info))) - return 0; - - if ((mem_info.State == MEM_RESERVE) && (mem_info.RegionSize >= len)) { - /* It would be correct to return here. However, support for Wine - * is beneficial, and Wine has a strange behavior in this - * department. It reports all memory below KERNEL32.DLL as - * reserved, but disallows MEM_COMMIT. - * - * Let's work around it: reserve the region we need for a second - * time. The second reservation is documented to fail on normal NT - * family, but it will succeed on Wine if this region is - * actually free. - */ - VirtualAlloc(addr, len, MEM_RESERVE, PAGE_EXECUTE_READWRITE); - /* If it is wine, the second call has succeeded, and now the region - * is really reserved. */ - return addr; - } - - DWORD mode; - if (mem_info.State == MEM_RESERVE) { - fprintf(stderr, "validation of reserved space too short.\n"); - fflush(stderr); - /* Oddly, we do not treat this assertion as fatal; hence also the - * provision for MEM_RESERVE in the following code, I suppose: */ - mode = MEM_COMMIT; - } else { - mode = MEM_RESERVE; - } - - os_vm_address_t actual = VirtualAlloc(addr, len, mode, PAGE_EXECUTE_READWRITE); + // Reserving the dynamic space doesn't commit it. + DWORD commit = + (space_id == DYNAMIC_CORE_SPACE_ID && (attributes & MOVABLE)) ? 0 : MEM_COMMIT; + os_vm_address_t actual = VirtualAlloc(addr, len, MEM_RESERVE|commit, PAGE_EXECUTE_READWRITE); if (!actual) { if (!(attributes & MOVABLE)) { @@ -866,81 +778,21 @@ os_validate(int attributes, os_vm_address_t addr, os_vm_size_t len) return 0; } - return AVERLAX(VirtualAlloc(NULL, len, mode, PAGE_EXECUTE_READWRITE)); + actual = VirtualAlloc(NULL, len, MEM_RESERVE|commit, PAGE_EXECUTE_READWRITE); + gc_assert(actual); } return actual; } -/* - * For os_invalidate(), we merely decommit the memory rather than - * freeing the address space. This loses when freeing per-thread - * data and related memory since it leaks address space. - * - * So far the original comment (author unknown). It used to continue as - * follows: - * - * It's not too lossy, however, since the two scenarios I'm aware of - * are fd-stream buffers, which are pooled rather than torched, and - * thread information, which I hope to pool (since windows creates - * threads at its own whim, and we probably want to be able to have - * them callback without funky magic on the part of the user, and - * full-on thread allocation is fairly heavyweight). - * - * But: As it turns out, we are no longer content with decommitting - * without freeing, and have now grown a second function - * os_invalidate_free(), sort of a really_os_invalidate(). - * - * As discussed on #lisp, this is not a satisfactory solution, and probably - * ought to be rectified in the following way: - * - * - Any cases currently going through the non-freeing version of - * os_invalidate() are ultimately meant for zero-filling applications. - * Replace those use cases with an os_revalidate_bzero() or similarly - * named function, which explicitly takes care of that aspect of - * the semantics. - * - * - The remaining uses of os_invalidate should actually free, and once - * the above is implemented, we can rename os_invalidate_free back to - * just os_invalidate(). - * - * So far the new plan, as yet unimplemented. -- DFL - */ - -void -os_invalidate(os_vm_address_t addr, os_vm_size_t len) -{ - AVERLAX(VirtualFree(addr, len, MEM_DECOMMIT)); -} - -void -os_invalidate_free(os_vm_address_t addr, - os_vm_size_t __attribute__((__unused__)) len) +void os_commit_memory(os_vm_address_t addr, os_vm_size_t len) { - AVERLAX(VirtualFree(addr, 0, MEM_RELEASE)); + if (len) gc_assert(VirtualAlloc(addr, len, MEM_COMMIT, PAGE_EXECUTE_READWRITE)); } -void -os_invalidate_free_by_any_address(os_vm_address_t addr, - os_vm_size_t __attribute__((__unused__)) len) -{ - MEMORY_BASIC_INFORMATION minfo; - AVERLAX(VirtualQuery(addr, &minfo, sizeof minfo)); - AVERLAX(minfo.AllocationBase); - AVERLAX(VirtualFree(minfo.AllocationBase, 0, MEM_RELEASE)); -} - -/* os_validate doesn't commit, i.e. doesn't actually "validate" in the - * sense that we could start using the space afterwards. Usually it's - * load_core_bytes or Lisp code that will run into that, in which case we recommit - * elsewhere in this file. For cases where C wants to write into newly - * os_validate()d memory, it needs to commit it explicitly first: - */ -os_vm_address_t -os_validate_recommit(os_vm_address_t addr, os_vm_size_t len) -{ - return - AVERLAX(VirtualAlloc(addr, len, MEM_COMMIT, PAGE_EXECUTE_READWRITE)); +void os_decommit_mem(os_vm_address_t addr, os_vm_size_t len) { + gc_assert(gc_active_p); + gc_assert(VirtualFree(addr, len, MEM_DECOMMIT)); } /* @@ -952,20 +804,33 @@ os_validate_recommit(os_vm_address_t addr, os_vm_size_t len) * a lazy read (demand page) setup, but that would mean keeping an * open file pointer for the core indefinately (and be one more * thing to maintain). + * FIXME: I would bet that we can use PAGE_EXECUTE_WRITECOPY for this, + * but I'll leave it to someone who actually cares. */ -void* load_core_bytes(int fd, int offset, os_vm_address_t addr, os_vm_size_t len) +void* load_core_bytes(int fd, os_vm_offset_t offset, os_vm_address_t addr, os_vm_size_t len, + int is_readonly_space) { - os_vm_size_t count; - - AVER(VirtualAlloc(addr, len, MEM_COMMIT, PAGE_EXECUTE_READWRITE)|| - VirtualAlloc(addr, len, MEM_RESERVE|MEM_COMMIT, - PAGE_EXECUTE_READWRITE)); - - CRT_AVER_NONNEGATIVE(lseek(fd, offset, SEEK_SET)); - - count = read(fd, addr, len); - CRT_AVER( count == len ); + os_commit_memory(addr, len); +#ifdef LISP_FEATURE_64_BIT + os_vm_offset_t res = _lseeki64(fd, offset, SEEK_SET); +#else + os_vm_offset_t res = lseek(fd, offset, SEEK_SET); +#endif + gc_assert(res == offset); + size_t count; + + os_vm_address_t original_addr = addr; + os_vm_size_t original_len = len; + while (len) { + unsigned to_read = len > INT_MAX ? INT_MAX : len; + count = read(fd, addr, to_read); + addr += count; + len -= count; + gc_assert(count == to_read); + } + DWORD old; + if (is_readonly_space) VirtualProtect(original_addr, original_len, PAGE_READONLY, &old); return (void*)0; } static DWORD os_protect_modes[8] = { @@ -985,108 +850,19 @@ os_protect(os_vm_address_t address, os_vm_size_t length, os_vm_prot_t prot) DWORD old_prot; DWORD new_prot = os_protect_modes[prot]; - AVER(VirtualProtect(address, length, new_prot, &old_prot)|| - (VirtualAlloc(address, length, MEM_COMMIT, new_prot) && - VirtualProtect(address, length, new_prot, &old_prot))); + gc_assert(VirtualProtect(address, length, new_prot, &old_prot)|| + (VirtualAlloc(address, length, MEM_COMMIT, new_prot) && + VirtualProtect(address, length, new_prot, &old_prot))); odxprint(misc,"Protecting %p + %p vmaccess %d " "newprot %08x oldprot %08x", address,length,prot,new_prot,old_prot); } -/* FIXME: Now that FOO_END, rather than FOO_SIZE, is the fundamental - * description of a space, we could probably punt this and just do - * (FOO_START <= x && x < FOO_END) everywhere it's called. */ -static boolean -in_range_p(lispobj a, lispobj sbeg, size_t slen) -{ - char* beg = (char*)((uword_t)sbeg); - char* end = (char*)((uword_t)sbeg) + slen; - char* adr = (char*)a; - return (adr >= beg && adr < end); -} - -boolean -is_linkage_table_addr(os_vm_address_t addr) -{ - return in_range_p((lispobj)addr, LINKAGE_TABLE_SPACE_START, LINKAGE_TABLE_SPACE_SIZE); -} - -static boolean is_some_thread_local_addr(os_vm_address_t addr); - -boolean -gc_managed_addr_p(lispobj addr) -{ - if(gc_managed_heap_space_p(addr) || - is_some_thread_local_addr((os_vm_address_t)addr)) - return 1; - return 0; -} - -/* test if an address is within thread-local space */ -static boolean -is_thread_local_addr(struct thread* th, os_vm_address_t addr) -{ - /* Assuming that this is correct, it would warrant further comment, - * I think. Based on what our call site is doing, we have been - * tasked to check for the address of a lisp object; not merely any - * foreign address within the thread's area. Indeed, this used to - * be a check for control and binding stack only, rather than the - * full thread "struct". So shouldn't the THREAD_STRUCT_SIZE rather - * be (thread_control_stack_size+BINDING_STACK_SIZE) instead? That - * would also do away with the LISP_FEATURE_SB_THREAD case. Or does - * it simply not matter? --DFL */ - ptrdiff_t diff = ((char*)th->os_address)-(char*)addr; - return diff > (ptrdiff_t)0 && diff < (ptrdiff_t)THREAD_STRUCT_SIZE -#ifdef LISP_FEATURE_SB_THREAD - && addr != (os_vm_address_t) th->csp_around_foreign_call -#endif - ; -} - -static boolean -is_some_thread_local_addr(os_vm_address_t addr) -{ - boolean result = 0; -#ifdef LISP_FEATURE_SB_THREAD - struct thread *th; - pthread_mutex_lock(&all_threads_lock); - for_each_thread(th) { - if(is_thread_local_addr(th,addr)) { - result = 1; - break; - } - } - pthread_mutex_unlock(&all_threads_lock); -#endif - return result; -} - - /* A tiny bit of interrupt.c state we want our paws on. */ extern boolean internal_errors_enabled; extern void exception_handler_wrapper(); -void -c_level_backtrace(const char* header, int depth) -{ - void* frame; - int n = 0; - void** lastseh; - - for (lastseh = get_seh_frame(); lastseh && (lastseh!=(void*)-1); - lastseh = *lastseh); - - fprintf(stderr, "Backtrace: %s (thread %p)\n", header, this_thread); - for (frame = __builtin_frame_address(0); frame; frame=*(void**)frame) - { - if ((n++)>depth) - return; - fprintf(stderr, "[#%02d]: ebp = %p, ret = %p\n",n, - frame, ((void**)frame)[1]); - } -} - #ifdef LISP_FEATURE_X86 #define voidreg(ctxptr,name) ((void*)((ctxptr)->E##name)) #else @@ -1119,17 +895,17 @@ static int handle_breakpoint_trap(os_context_t *ctx, struct thread* self) { #ifdef LISP_FEATURE_UD2_BREAKPOINTS - if (((unsigned short *)*os_context_pc_addr(ctx))[0] != 0x0b0f) + if (((unsigned short *)OS_CONTEXT_PC(ctx))[0] != 0x0b0f) return -1; #endif /* Unlike some other operating systems, Win32 leaves EIP * pointing to the breakpoint instruction. */ - (*os_context_pc_addr(ctx)) += TRAP_CODE_WIDTH; + OS_CONTEXT_PC(ctx) += TRAP_CODE_WIDTH; /* Now EIP points just after the INT3 byte and aims at the * 'kind' value (eg trap_Cerror). */ - unsigned trap = *(unsigned char *)(*os_context_pc_addr(ctx)); + unsigned trap = *(unsigned char *)OS_CONTEXT_PC(ctx); #ifdef LISP_FEATURE_SB_THREAD /* Before any other trap handler: gc_safepoint ensures that @@ -1196,87 +972,43 @@ handle_access_violation(os_context_t *ctx, exception_record->ExceptionInformation[0]); #endif - /* Stack: This case takes care of our various stack exhaustion - * protect pages (with the notable exception of the control stack!). */ - if (self && local_thread_stack_address_p(fault_address)) { - if (handle_guard_page_triggered(ctx, fault_address)) - return 0; /* gc safety? */ - goto try_recommit; - } - /* Safepoint pages */ -#ifdef LISP_FEATURE_SB_THREAD if (fault_address == (void *) GC_SAFEPOINT_TRAP_ADDR) { thread_in_lisp_raised(ctx); return 0; } - if ((((u64)fault_address) == ((u64)self->csp_around_foreign_call))){ + if ((1+THREAD_HEADER_SLOTS)+(lispobj*)fault_address == (lispobj*)self) { thread_in_safety_transition(ctx); return 0; } -#endif /* dynamic space */ - page_index_t index = find_page_index(fault_address); - if (index != -1) { - /* - * Now, if the page is supposedly write-protected and this - * is a write, tell the gc that it's been hit. - */ - if (page_table[index].write_protected) { - gencgc_handle_wp_violation(fault_address); - } else { - AVER(VirtualAlloc(PTR_ALIGN_DOWN(fault_address,os_vm_page_size), - os_vm_page_size, - MEM_COMMIT, PAGE_EXECUTE_READWRITE)); - } + page_index_t page = find_page_index(fault_address); +#ifdef LISP_FEATURE_SOFT_CARD_MARKS + if (page >= 0) lose("should not get access violation in dynamic space"); +#else + if (page != -1 && !PAGE_WRITEPROTECTED_P(page)) { + os_commit_memory(PTR_ALIGN_DOWN(fault_address, os_vm_page_size), + os_vm_page_size); return 0; - } else { + } + if (gencgc_handle_wp_violation(ctx, fault_address)) { + return 0; + } +#endif + #ifdef LISP_FEATURE_IMMOBILE_SPACE - extern int immobile_space_handle_wp_violation(void*); - if (immobile_space_handle_wp_violation(fault_address)) { - return 0; - } + extern int immobile_space_handle_wp_violation(void*); + if (immobile_space_handle_wp_violation(fault_address)) { + return 0; + } #endif + if (handle_guard_page_triggered(ctx, fault_address)) { + return 0; } - if (fault_address == undefined_alien_address) - return -1; - - /* linkage table or a "valid_lisp_addr" outside of dynamic space (?) */ - if (is_linkage_table_addr(fault_address) - || gc_managed_addr_p((lispobj)fault_address)) - goto try_recommit; - return -1; - -try_recommit: - /* First use of a new page, lets get some memory for it. */ - -#if defined(LISP_FEATURE_X86) - AVER(VirtualAlloc(PTR_ALIGN_DOWN(fault_address,os_vm_page_size), - os_vm_page_size, - MEM_COMMIT, PAGE_EXECUTE_READWRITE) - ||(fprintf(stderr,"Unable to recommit addr %p eip 0x%08lx\n", - fault_address, win32_context->Eip) && - (c_level_backtrace("BT",5), - fake_foreign_function_call(ctx), - lose("Lispy backtrace"), - 0))); -#else - AVER(VirtualAlloc(PTR_ALIGN_DOWN(fault_address,os_vm_page_size), - os_vm_page_size, - MEM_COMMIT, PAGE_EXECUTE_READWRITE) - ||(fprintf(stderr,"Unable to recommit addr %p eip %p\n", - fault_address, (void*)win32_context->Rip) && - (c_level_backtrace("BT",5), - fake_foreign_function_call(ctx), - lose("Lispy backtrace"), - 0))); -#endif - - return 0; } static void @@ -1333,7 +1065,7 @@ signal_internal_error_or_lose(os_context_t *ctx, (void*)(intptr_t)exception_record->ExceptionCode); fprintf(stderr, "Faulting IP: %p.\n", (void*)(intptr_t)exception_record->ExceptionAddress); - if (exception_record->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) { + if ((long int)exception_record->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) { MEMORY_BASIC_INFORMATION mem_info; if (VirtualQuery(fault_address, &mem_info, sizeof mem_info)) { @@ -1351,18 +1083,11 @@ signal_internal_error_or_lose(os_context_t *ctx, lose("Exception too early in cold init, cannot continue."); } -/* - * A good explanation of the exception handling semantics is - * http://win32assembly.online.fr/Exceptionhandling.html (possibly defunct) - * or: - * http://www.microsoft.com/msj/0197/exception/exception.aspx - */ - -EXCEPTION_DISPOSITION -handle_exception(EXCEPTION_RECORD *exception_record, - struct lisp_exception_frame *exception_frame, - CONTEXT *win32_context, - void __attribute__((__unused__)) *dispatcher_context) +static EXCEPTION_DISPOSITION +handle_exception_ex(EXCEPTION_RECORD *exception_record, + struct lisp_exception_frame *exception_frame, + CONTEXT *win32_context, + BOOL continue_search_on_unhandled_access_violation) { if (!win32_context) /* Not certain why this should be possible, but let's be safe... */ @@ -1373,7 +1098,7 @@ handle_exception(EXCEPTION_RECORD *exception_record, /* Undo any dynamic bindings. */ unbind_to_here(exception_frame->bindstack_pointer, - arch_os_get_current_thread()); + get_sb_vm_thread()); return ExceptionContinueSearch; } @@ -1389,18 +1114,16 @@ handle_exception(EXCEPTION_RECORD *exception_record, DWORD lastError = GetLastError(); DWORD lastErrno = errno; - struct thread* self = arch_os_get_current_thread(); + struct thread* self = get_sb_vm_thread(); os_context_t context, *ctx = &context; context.win32_context = win32_context; -#if defined(LISP_FEATURE_SB_THREAD) - context.sigmask = self ? self->os_thread->blocked_signal_set : 0; -#endif + context.sigmask = self ? thread_extra_data(self)->blocked_signal_set : 0; os_context_register_t oldbp = 0; if (self) { - oldbp = self ? self->carried_base_pointer : 0; - self->carried_base_pointer + oldbp = self ? thread_extra_data(self)->carried_base_pointer : 0; + thread_extra_data(self)->carried_base_pointer = (os_context_register_t) voidreg(win32_context, bp); } @@ -1424,10 +1147,14 @@ handle_exception(EXCEPTION_RECORD *exception_record, * isn't happy: */ int rc; + EXCEPTION_DISPOSITION disp = ExceptionContinueExecution; switch (code) { case EXCEPTION_ACCESS_VIOLATION: - rc = handle_access_violation( - ctx, exception_record, fault_address, self); + rc = handle_access_violation(ctx, exception_record, fault_address, self); + if (rc && continue_search_on_unhandled_access_violation) { + rc = 0; + disp = ExceptionContinueSearch; + } break; case SBCL_EXCEPTION_BREAKPOINT: @@ -1447,11 +1174,39 @@ handle_exception(EXCEPTION_RECORD *exception_record, signal_internal_error_or_lose(ctx, exception_record, fault_address); if (self) - self->carried_base_pointer = oldbp; + thread_extra_data(self)->carried_base_pointer = oldbp; errno = lastErrno; SetLastError(lastError); - return ExceptionContinueExecution; + return disp; +} + +/* + * A good explanation of the exception handling semantics is + * https://web.archive.org/web/20120628151428/http://win32assembly.online.fr/Exceptionhandling.html + * (x86-specific) + * or: + * https://docs.microsoft.com/en-us/windows/win32/debug/structured-exception-handling + * or: + * James McNellis's CppCon 2018 talk: "Unwinding the Stack: Exploring How C++ + * Exceptions Work on Windows" + * + * On x86, this function is always invoked by frame-based exception handlers, + * either the one established by call_into_lisp in x86-assem.S or the top-level + * handler established by wos_install_interrupt_handlers(). + * + * On x86-64, this function may be invoked by the frame-based exception handler + * established by set_up_win64_seh_thunk(). Our vectored exception handler, + * veh(), invokes handle_exception_ex directly. + */ + +EXCEPTION_DISPOSITION +handle_exception(EXCEPTION_RECORD *exception_record, + struct lisp_exception_frame *exception_frame, + CONTEXT *win32_context, + void __attribute__((__unused__)) *dispatcher_context) +{ + return handle_exception_ex(exception_record, exception_frame, win32_context, FALSE); } #ifdef LISP_FEATURE_X86_64 @@ -1460,26 +1215,51 @@ handle_exception(EXCEPTION_RECORD *exception_record, int sbcl__lastErrno = errno; \ RUN_BODY_ONCE(restoring_errno, errno = sbcl__lastErrno) +/* + * This vectored exception handler runs before frame-based handlers, so we only + * want to handle exceptions triggered by Lisp code. Exceptions raised by + * foreign function calls are handled by the frame-based handler established by + * set_up_win64_seh_thunk(). + * + * Access violation exceptions can be triggered by the runtime as well, and + * that's neither Lisp code nor is it covered the SEH thunk, so we handle those + * exceptions differently. + */ LONG veh(EXCEPTION_POINTERS *ep) { - EXCEPTION_DISPOSITION disp; + EXCEPTION_DISPOSITION disp = ExceptionContinueSearch; RESTORING_ERRNO() { - if (!pthread_self()) + if (!get_sb_vm_thread()) return EXCEPTION_CONTINUE_SEARCH; } - disp = handle_exception(ep->ExceptionRecord,0,ep->ContextRecord,0); - - switch (disp) - { + DWORD64 rip = ep->ContextRecord->Rip; + long int code = ep->ExceptionRecord->ExceptionCode; + BOOL from_lisp = + (rip >= DYNAMIC_SPACE_START && rip < DYNAMIC_SPACE_START+dynamic_space_size) || + (rip >= READ_ONLY_SPACE_START && rip < READ_ONLY_SPACE_END) || + (rip >= STATIC_SPACE_START && rip < (uword_t)static_space_free_pointer); + + if (code == EXCEPTION_ACCESS_VIOLATION || + code == STATUS_HEAP_CORRUPTION || + from_lisp) + disp = handle_exception_ex(ep->ExceptionRecord, 0, ep->ContextRecord, + // continue search on unhandled memory faults + // if not in Lisp code. This gives foreign + // handlers a chance to handle the + // exception. If nothing handles it, our + // frame-based handler will. + !from_lisp); + + switch (disp) { case ExceptionContinueExecution: return EXCEPTION_CONTINUE_EXECUTION; case ExceptionContinueSearch: return EXCEPTION_CONTINUE_SEARCH; default: - fprintf(stderr,"Exception handler is mad\n"); + fprintf(stderr, "Exception handler is mad\n"); fflush(stderr); ExitProcess(0); } } @@ -1488,8 +1268,8 @@ veh(EXCEPTION_POINTERS *ep) os_context_register_t carry_frame_pointer(os_context_register_t default_value) { - struct thread* self = arch_os_get_current_thread(); - os_context_register_t bp = self->carried_base_pointer; + struct thread* self = get_sb_vm_thread(); + os_context_register_t bp = thread_extra_data(self)->carried_base_pointer; return bp ? bp : default_value; } @@ -1508,30 +1288,6 @@ wos_install_interrupt_handlers #endif } -/* - * The stubs below are replacements for the windows versions, - * which can -fail- when used in our memory spaces because they - * validate the memory spaces they are passed in a way that - * denies our exception handler a chance to run. - */ - -void *memmove(void *dest, const void *src, size_t n) -{ - if (dest < src) { - size_t i; - for (i = 0; i < n; i++) *(((char *)dest)+i) = *(((char *)src)+i); - } else { - while (n--) *(((char *)dest)+n) = *(((char *)src)+n); - } - return dest; -} - -void *memcpy(void *dest, const void *src, size_t n) -{ - while (n--) *(((char *)dest)+n) = *(((char *)src)+n); - return dest; -} - char *dirname(char *path) { static char buf[PATH_MAX + 1]; @@ -1556,21 +1312,34 @@ char *dirname(char *path) // 0 - not a socket or other error, 1 - has input, 2 - has no input int -socket_input_available(HANDLE socket) +socket_input_available(HANDLE socket, long time, long utime) { - unsigned long count = 0, count_size = 0; + int count = 0; int wsaErrno = GetLastError(); - int err = WSAIoctl((SOCKET)socket, FIONREAD, NULL, 0, - &count, sizeof(count), &count_size, NULL, NULL); + TIMEVAL timeout = {time, utime}; + fd_set readfds, errfds; - int ret; + FD_ZERO(&readfds); + FD_ZERO(&errfds); + FD_SET((uword_t)socket, &readfds); + FD_SET((uword_t)socket, &errfds); - if (err == 0) { - ret = (count > 0) ? 1 : 2; - } else - ret = 0; + count = select(0, &readfds, NULL, &errfds, &timeout); SetLastError(wsaErrno); - return ret; + + if (count == SOCKET_ERROR) + /* This is an error in select() itself, not with the socket. */ + return 0; + else if (count == 0) + return 2; + /* True if there is data, or the socket has been closed (i.e. a read + * would retrieve an EOF error) */ + else if (FD_ISSET(socket, &readfds)) + return 1; + else + /* This is an error in the socket. The count was positive, and + * it wasn't in the read set, so it must be in the error set. */ + return 0; } #ifdef LISP_FEATURE_SB_THREAD @@ -1586,17 +1355,16 @@ boolean io_begin_interruptible(HANDLE handle) if (!ptr_CancelIoEx) return 1; - if (!__sync_bool_compare_and_swap(&this_thread->synchronous_io_handle_and_flag, + struct thread* this_thread = get_sb_vm_thread(); + if (!__sync_bool_compare_and_swap(&thread_extra_data(this_thread)->synchronous_io_handle_and_flag, 0, handle)) { - ResetEvent(this_thread->private_events.events[0]); - this_thread->synchronous_io_handle_and_flag = 0; + ResetEvent(thread_private_events(this_thread,0)); + thread_extra_data(this_thread)->synchronous_io_handle_and_flag = 0; return 0; } return 1; } -static pthread_mutex_t interrupt_io_lock = PTHREAD_MUTEX_INITIALIZER; - /* Unmark current thread as (probably) doing synchronous I/O; if an * I/O cancellation was requested, postpone it until next * io_begin_interruptible */ @@ -1605,10 +1373,10 @@ io_end_interruptible(HANDLE handle) { if (!ptr_CancelIoEx) return; - pthread_mutex_lock(&interrupt_io_lock); - __sync_bool_compare_and_swap(&this_thread->synchronous_io_handle_and_flag, + EnterCriticalSection(&interrupt_io_lock); + __sync_bool_compare_and_swap(&thread_extra_data(get_sb_vm_thread())->synchronous_io_handle_and_flag, handle, 0); - pthread_mutex_unlock(&interrupt_io_lock); + LeaveCriticalSection(&interrupt_io_lock); } #define WITH_INTERRUPTIBLE_IO(handle) \ if (!io_begin_interruptible(handle)) { \ @@ -1686,30 +1454,17 @@ int console_handle_p(HANDLE handle) * entered. */ -struct { - console_char buffer[MAX_CONSOLE_TCHARS]; - DWORD head, tail; - pthread_mutex_t lock; - pthread_cond_t cond_has_data; - pthread_cond_t cond_has_client; - pthread_t thread; - boolean initialized; - HANDLE handle; - boolean in_progress; -} ttyinput = {.lock = PTHREAD_MUTEX_INITIALIZER}; - -static void* -tty_read_line_server() +static __stdcall unsigned int tty_read_line_server(LPVOID arg) { - pthread_mutex_lock(&ttyinput.lock); + EnterCriticalSection(&ttyinput.lock); while (ttyinput.handle) { DWORD nchars; BOOL ok; while (!ttyinput.in_progress) - pthread_cond_wait(&ttyinput.cond_has_client,&ttyinput.lock); + SleepConditionVariableCS(&ttyinput.cond_has_client,&ttyinput.lock,INFINITE); - pthread_mutex_unlock(&ttyinput.lock); + LeaveCriticalSection(&ttyinput.lock); #ifdef LISP_FEATURE_SB_UNICODE ok = ReadConsoleW(ttyinput.handle, &ttyinput.buffer[ttyinput.tail], @@ -1722,16 +1477,16 @@ tty_read_line_server() &nchars,NULL); #endif - pthread_mutex_lock(&ttyinput.lock); + EnterCriticalSection(&ttyinput.lock); if (ok) { ttyinput.tail += nchars; - pthread_cond_broadcast(&ttyinput.cond_has_data); + WakeAllConditionVariable(&ttyinput.cond_has_data); } ttyinput.in_progress = 0; } - pthread_mutex_unlock(&ttyinput.lock); - return NULL; + LeaveCriticalSection(&ttyinput.lock); + return 0; } static boolean @@ -1743,9 +1498,13 @@ tty_maybe_initialize_unlocked(HANDLE handle) 0,FALSE,DUPLICATE_SAME_ACCESS)) { return 0; } - pthread_cond_init(&ttyinput.cond_has_data,NULL); - pthread_cond_init(&ttyinput.cond_has_client,NULL); - pthread_create(&ttyinput.thread,NULL,tty_read_line_server,NULL); + InitializeConditionVariable(&ttyinput.cond_has_data); + InitializeConditionVariable(&ttyinput.cond_has_client); + ttyinput.thread = + (HANDLE)_beginthreadex(NULL, + 0, // stack size = default + tty_read_line_server, 0, + 0, 0); ttyinput.initialized = 1; } return 1; @@ -1757,7 +1516,7 @@ win32_tty_listen(HANDLE handle) boolean result = 0; INPUT_RECORD ir; DWORD nevents; - pthread_mutex_lock(&ttyinput.lock); + EnterCriticalSection(&ttyinput.lock); if (!tty_maybe_initialize_unlocked(handle)) result = 0; @@ -1769,11 +1528,11 @@ win32_tty_listen(HANDLE handle) } else { if (PeekConsoleInput(ttyinput.handle,&ir,1,&nevents) && nevents) { ttyinput.in_progress = 1; - pthread_cond_broadcast(&ttyinput.cond_has_client); + WakeAllConditionVariable(&ttyinput.cond_has_client); } } } - pthread_mutex_unlock(&ttyinput.lock); + LeaveCriticalSection(&ttyinput.lock); return result; } @@ -1789,7 +1548,7 @@ static int win32_read_console(HANDLE handle, void* buf, int count) count = nchars*sizeof(console_char); - pthread_mutex_lock(&ttyinput.lock); + EnterCriticalSection(&ttyinput.lock); if (!tty_maybe_initialize_unlocked(handle)) { result = -1; @@ -1809,9 +1568,9 @@ static int win32_read_console(HANDLE handle, void* buf, int count) /* We are to wait */ ttyinput.in_progress=1; /* wake console reader */ - pthread_cond_broadcast(&ttyinput.cond_has_client); + WakeAllConditionVariable(&ttyinput.cond_has_client); } - pthread_cond_wait(&ttyinput.cond_has_data, &ttyinput.lock); + SleepConditionVariableCS(&ttyinput.cond_has_data, &ttyinput.lock, INFINITE); io_end_interruptible(ttyinput.handle); } } @@ -1846,7 +1605,7 @@ static int win32_read_console(HANDLE handle, void* buf, int count) } } unlock: - pthread_mutex_unlock(&ttyinput.lock); + LeaveCriticalSection(&ttyinput.lock); return result; } @@ -1856,28 +1615,33 @@ win32_maybe_interrupt_io(void* thread) struct thread *th = thread; boolean done = 0; +#ifdef LISP_FEATURE_SB_FUTEX + if (thread_extra_data(th)->waiting_on_address) + WakeByAddressAll(thread_extra_data(th)->waiting_on_address); +#endif + if (ptr_CancelIoEx) { - pthread_mutex_lock(&interrupt_io_lock); + EnterCriticalSection(&interrupt_io_lock); HANDLE h = (HANDLE) InterlockedExchangePointer((volatile LPVOID *) - &th->synchronous_io_handle_and_flag, + &thread_extra_data(th)->synchronous_io_handle_and_flag, (LPVOID)INVALID_HANDLE_VALUE); if (h && (h!=INVALID_HANDLE_VALUE)) { if (console_handle_p(h)) { - pthread_mutex_lock(&ttyinput.lock); - pthread_cond_broadcast(&ttyinput.cond_has_data); - pthread_mutex_unlock(&ttyinput.lock); + EnterCriticalSection(&ttyinput.lock); + WakeAllConditionVariable(&ttyinput.cond_has_data); + LeaveCriticalSection(&ttyinput.lock); done = 1; goto unlock; } if (ptr_CancelSynchronousIo) { - done = !!ptr_CancelSynchronousIo(th->os_thread->handle); + done = !!ptr_CancelSynchronousIo((HANDLE)th->os_thread); } done |= !!ptr_CancelIoEx(h,NULL); } unlock: - pthread_mutex_unlock(&interrupt_io_lock); + LeaveCriticalSection(&interrupt_io_lock); } return done; } @@ -1923,7 +1687,7 @@ win32_unix_write(HANDLE handle, void * buf, int count) { DWORD written_bytes; OVERLAPPED overlapped; - struct thread * self = arch_os_get_current_thread(); + struct thread * self = get_sb_vm_thread(); BOOL waitInGOR; LARGE_INTEGER file_position; BOOL seekable; @@ -1934,7 +1698,7 @@ win32_unix_write(HANDLE handle, void * buf, int count) return win32_write_console(handle,buf,count); } - overlapped.hEvent = self->private_events.events[0]; + overlapped.hEvent = thread_private_events(self,0); seekable = SetFilePointerEx(handle, zero_large_offset, &file_position, @@ -1965,7 +1729,7 @@ win32_unix_write(HANDLE handle, void * buf, int count) errno = errorCode; return -1; } else { - if(WaitForMultipleObjects(2,self->private_events.events, + if(WaitForMultipleObjects(2,thread_extra_data(self)->private_events, FALSE,INFINITE) != WAIT_OBJECT_0) { CancelIo(handle); waitInGOR = TRUE; @@ -1998,7 +1762,7 @@ win32_unix_read(HANDLE handle, void * buf, int count) { OVERLAPPED overlapped = {.Internal=0}; DWORD read_bytes = 0; - struct thread * self = arch_os_get_current_thread(); + struct thread * self = get_sb_vm_thread(); DWORD errorCode = 0; BOOL waitInGOR = FALSE; BOOL ok = FALSE; @@ -2009,7 +1773,7 @@ win32_unix_read(HANDLE handle, void * buf, int count) return win32_read_console(handle, buf, count); } - overlapped.hEvent = self->private_events.events[0]; + overlapped.hEvent = thread_private_events(self,0); /* If it has a position, we won't try overlapped */ seekable = SetFilePointerEx(handle, zero_large_offset, @@ -2051,7 +1815,7 @@ win32_unix_read(HANDLE handle, void * buf, int count) return -1; } else { int ret; - if( (ret = WaitForMultipleObjects(2,self->private_events.events, + if( (ret = WaitForMultipleObjects(2,thread_extra_data(self)->private_events, FALSE,INFINITE)) != WAIT_OBJECT_0) { CancelIo(handle); waitInGOR = TRUE; @@ -2128,8 +1892,8 @@ DWORD win32_wait_object_or_signal(HANDLE waitFor) { #ifdef LISP_FEATURE_SB_THREAD - struct thread *self = arch_os_get_current_thread(); - HANDLE handles[] = {waitFor, self->private_events.events[1]}; + struct thread *self = get_sb_vm_thread(); + HANDLE handles[] = {waitFor, thread_private_events(self,1)}; return WaitForMultipleObjects(2,handles, FALSE, INFINITE); #else @@ -2141,8 +1905,8 @@ DWORD win32_wait_for_multiple_objects_or_signal(HANDLE *handles, DWORD count) { #ifdef LISP_FEATURE_SB_THREAD - struct thread *self = arch_os_get_current_thread(); - handles[count] = self->private_events.events[1]; + struct thread *self = get_sb_vm_thread(); + handles[count] = thread_private_events(self,1); return WaitForMultipleObjects(count + 1, handles, FALSE, INFINITE); #else @@ -2196,4 +1960,98 @@ os_cancel_wtimer(HANDLE handle) } #endif +#ifdef LISP_FEATURE_SB_FUTEX +int +futex_wait(int *lock_word, int oldval, long sec, unsigned long usec) +{ + DWORD timeout = sec < 0 ? INFINITE : (sec * 1000) + (usec / 1000); + struct thread* th = get_sb_vm_thread(); + thread_extra_data(th)->waiting_on_address = lock_word; + int result = WaitOnAddress(lock_word, &oldval, 4, timeout); + thread_extra_data(th)->waiting_on_address = 0; + if (result) + return 0; + if (GetLastError() == ERROR_TIMEOUT) + return 1; + return 0; +} + +int +futex_wake(PVOID lock_word, int n) +{ + if (n == 1) + WakeByAddressSingle(lock_word); + else + WakeByAddressAll(lock_word); + return 0; +} +#endif + +int sb_pthread_sigmask(int how, const sigset_t *set, sigset_t *oldset) +{ + struct extra_thread_data* self = thread_extra_data(get_sb_vm_thread()); + if (oldset) + *oldset = self->blocked_signal_set; + if (set) { + switch (how) { + case SIG_BLOCK: + self->blocked_signal_set |= *set; + break; + case SIG_UNBLOCK: + self->blocked_signal_set &= ~(*set); + break; + case SIG_SETMASK: + self->blocked_signal_set = *set; + break; + } + } + return 0; +} + +int sb_pthr_kill(struct thread* thread, int signum) +{ + __sync_fetch_and_or(&thread_extra_data(thread)->pending_signal_set, 1<<signum); + return 0; +} + +/* Signals */ +int sched_yield() +{ + /* http://stackoverflow.com/questions/1383943/switchtothread-vs-sleep1 + SwitchToThread(); was here. Unsure what's better for us, just trying.. */ + + if(!SwitchToThread()) + Sleep(0); + return 0; +} + +int sigemptyset(sigset_t *set) +{ + *set = 0; + return 0; +} + +int sigfillset(sigset_t *set) +{ + *set = 0xfffffffful; + return 0; +} + +int sigaddset(sigset_t *set, int signum) +{ + *set |= 1 << signum; + return 0; +} + +int sigdelset(sigset_t *set, int signum) +{ + *set &= ~(1 << signum); + return 0; +} + +int sigismember(const sigset_t *set, int signum) +{ + return (*set & (1 << signum)) != 0; +} + /* EOF */ diff --git a/src/runtime/win32-os.h b/src/runtime/win32-os.h index 9662bcc36b..8c755f8ea2 100644 --- a/src/runtime/win32-os.h +++ b/src/runtime/win32-os.h @@ -15,6 +15,7 @@ #define WIN32_LEAN_AND_MEAN #include <winsock2.h> #include <windows.h> +#include <ntstatus.h> #include <stdlib.h> #include <stdint.h> @@ -28,15 +29,7 @@ #include "target-arch-os.h" #include "target-arch.h" -#ifdef LISP_FEATURE_SB_THREAD #include "pthreads_win32.h" -/* prevent inclusion of a mingw semaphore.h */ -#define CANNOT_USE_POSIX_SEM_T -typedef sem_t os_sem_t; -#else -typedef void *siginfo_t; -typedef int sigset_t; -#endif typedef LPVOID os_vm_address_t; typedef uword_t os_vm_size_t; @@ -48,24 +41,20 @@ typedef int os_vm_prot_t; #define OS_VM_PROT_WRITE 2 #define OS_VM_PROT_EXECUTE 4 -#define os_open_core(file,mode) win32_open_for_mmap(file) -#define HAVE_os_open_core - -#define os_fopen_runtime(file,mode) win32_fopen_runtime() -#define HAVE_os_fopen_runtime - extern int os_number_of_processors; #define HAVE_os_number_of_processors -extern int win32_open_for_mmap(const char* file); -extern FILE* win32_fopen_runtime(); - +// 64-bit uses whatever TLS index the kernels gives us which we store in +// 'sbcl_thread_tls_index' to hold our thread-local value of the pointer +// to struct thread. +// 32-bit uses a quasi-arbitrary fixed TLS index that we try to claim on startup. +// of the process. +#ifdef LISP_FEATURE_64_BIT +extern DWORD sbcl_thread_tls_index; +#define OUR_TLS_INDEX sbcl_thread_tls_index +#else #define OUR_TLS_INDEX 63 -#define SIG_MEMORY_FAULT SIGSEGV - -#define SIG_STOP_FOR_GC (SIGRTMIN+1) -#define SIG_DEQUEUE (SIGRTMIN+2) -#define SIG_THREAD_EXIT (SIGRTMIN+3) +#endif struct lisp_exception_frame { struct lisp_exception_frame *next_frame; @@ -76,12 +65,9 @@ struct lisp_exception_frame { void wos_install_interrupt_handlers(struct lisp_exception_frame *handler); char *dirname(char *path); -void os_invalidate_free(os_vm_address_t addr, os_vm_size_t len); - boolean win32_maybe_interrupt_io(void* thread); +void os_decommit_mem(os_vm_address_t addr, os_vm_size_t len); -struct thread; -void** os_get_csp(struct thread* th); - +int sb_pthread_sigmask(int how, const sigset_t *set, sigset_t *oldset); #endif /* SBCL_INCLUDED_WIN32_OS_H */ diff --git a/src/runtime/win32-thread-private-events.h b/src/runtime/win32-thread-private-events.h deleted file mode 100644 index 56802df02b..0000000000 --- a/src/runtime/win32-thread-private-events.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef _WIN32_THREAD_PRIVATE_EVENTS_H_ -#define _WIN32_THREAD_PRIVATE_EVENTS_H_ - -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN -#endif -#include <windows.h> - -struct private_events { - HANDLE events[2]; -}; - -#endif /* _WIN32_THREAD_PRIVATE_EVENTS_H_ */ diff --git a/src/runtime/wrap.c b/src/runtime/wrap.c index d8c73b6198..8f8999e8ad 100644 --- a/src/runtime/wrap.c +++ b/src/runtime/wrap.c @@ -523,18 +523,13 @@ int s_issock(mode_t mode) } #endif /* !LISP_FEATURE_WIN32 */ -#ifndef LISP_FEATURE_WIN32 -int sb_getrusage(int who, struct rusage *rusage) -{ - return getrusage(who, rusage); -} - -int sb_gettimeofday(struct timeval *tp) -{ - return gettimeofday(tp, NULL); -} - -#ifndef LISP_FEATURE_DARWIN /* reimplements nanosleep in darwin-os.c */ +#ifdef LISP_FEATURE_UNIX +#ifdef LISP_FEATURE_DARWIN +/* nanosleep() is not re-entrant on some versions of Darwin and is + * reimplemented using the underlying syscalls. + */ +int sb_nanosleep(time_t sec, int nsec); +#else void sb_nanosleep(time_t sec, int nsec) { struct timespec rqtp = {sec, nsec}; @@ -571,11 +566,6 @@ void sb_nanosleep(time_t sec, int nsec) */ } } -#else -/* nanosleep() is not re-entrant on some versions of Darwin and is - * reimplemented it using the underlying syscalls. - */ -int sb_nanosleep(time_t sec, int nsec); #endif void sb_nanosleep_double(double seconds) { @@ -591,6 +581,20 @@ void sb_nanosleep_double(double seconds) { void sb_nanosleep_float(float seconds) { sb_nanosleep_double(seconds); } +#endif + +#ifdef LISP_FEATURE_NETBSD +/* These thin wrappers are needed due to "linker rewriting" + * acording to git revision 9304704f68 */ +int sb_getrusage(int who, struct rusage *rusage) +{ + return getrusage(who, rusage); +} + +int sb_gettimeofday(struct timeval *tp, void *tz) +{ + return gettimeofday(tp, tz); +} int sb_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout) @@ -612,7 +616,23 @@ int sb_utimes(char *path, struct timeval times[2]) { return utimes(path, times); } -#else /* !LISP_FEATURE_WIN32 */ + +int sb_clock_gettime(clockid_t id, struct timespec* tp) +{ + return clock_gettime(id, tp); +} +#ifndef LISP_FEATURE_SB_THREAD +#include <signal.h> +int sb_sigprocmask(int how, const sigset_t *set, sigset_t *oldset) +{ + return sigprocmask(how, set, oldset); +} +#endif +#endif + +#ifdef LISP_FEATURE_WIN32 + +// These are used in src/code/irrat.lisp. Search for DEF-MATH-RTN #define SB_TRIG_WRAPPER(name) \ double sb_##name (double x) { \ return name(x); \ diff --git a/src/runtime/wrap.h b/src/runtime/wrap.h index ade600b64f..543d63cb28 100644 --- a/src/runtime/wrap.h +++ b/src/runtime/wrap.h @@ -14,7 +14,7 @@ * * FIXME: But of course we should fix the FFI so that we can use the * actual 64-bit values instead. In fact, we probably have by now - * (2003-10-03) on all working platforms except MIPS and HPPA; if some + * (2003-10-03) on all working platforms except MIPS; if some * motivated spark would simply fix those, this hack could go away. * -- CSR, 2003-10-03 * diff --git a/src/runtime/x86-64-arch.c b/src/runtime/x86-64-arch.c index 139273cc54..8f50b60248 100644 --- a/src/runtime/x86-64-arch.c +++ b/src/runtime/x86-64-arch.c @@ -9,6 +9,8 @@ * files for more information. */ +#define _GNU_SOURCE /* for REG_RAX etc. from sys/ucontext */ + #include <stdio.h> #include "sbcl.h" @@ -16,7 +18,6 @@ #include "globals.h" #include "validate.h" #include "os.h" -#include "sbcl.h" #include "arch.h" #include "lispregs.h" #include "signal.h" @@ -25,22 +26,22 @@ #include "interr.h" #include "breakpoint.h" #include "thread.h" -#include "getallocptr.h" +#include "pseudo-atomic.h" #include "unaligned.h" #include "search.h" -#include "globals.h" // for asm_routines_start,end +#include "var-io.h" #include "genesis/static-symbols.h" #include "genesis/symbol.h" #include "forwarding-ptr.h" #include "core.h" +#include "gc-private.h" #define INT3_INST 0xCC #define INTO_INST 0xCE #define UD2_INST 0x0b0f #define BREAKPOINT_WIDTH 1 -unsigned int cpuid_fn1_ecx; int avx_supported = 0, avx2_supported = 0; static void cpuid(unsigned info, unsigned subinfo, @@ -72,11 +73,27 @@ static void xgetbv(unsigned *eax, unsigned *edx) #define VECTOR_FILL_T "VECTOR-FILL/T" +void set_alloc_tramp_vectors(int ymm_enable) +{ + struct code* code = (struct code*)asm_routines_start; + lispobj* instructions = (lispobj*)code + code_header_words(code); + int index; + get_asm_routine_by_name("FPR-SAVE", &index); + if (index) + instructions[index] = + (lispobj)get_asm_routine_by_name(ymm_enable ? "SAVE-YMM" : "SAVE-XMM", 0); + get_asm_routine_by_name("FPR-RESTORE", &index); + if (index) + instructions[index] = + (lispobj)get_asm_routine_by_name(ymm_enable ? "RESTORE-YMM" : "RESTORE-XMM", 0); +} + // Poke in a byte that changes an opcode to enable faster vector fill. // Using fixed offsets and bytes is no worse than what we do elsewhere. void tune_asm_routines_for_microarch(void) { unsigned int eax, ebx, ecx, edx; + unsigned int cpuid_fn1_ecx = 0; cpuid(0, 0, &eax, &ebx, &ecx, &edx); if (eax >= 1) { // see if we can execute basic id function 1 @@ -94,7 +111,14 @@ void tune_asm_routines_for_microarch(void) } } } - SetSymbolValue(CPUID_FN1_ECX, (lispobj)make_fixnum(cpuid_fn1_ecx), 0); + set_alloc_tramp_vectors(avx_supported); + int our_cpu_feature_bits = 0; + // avx2_supported gets copied into bit 1 of *CPU-FEATURE-BITS* + if (avx2_supported) our_cpu_feature_bits |= 1; + // POPCNT = ECX bit 23, which gets copied into bit 2 in *CPU-FEATURE-BITS* + if (cpuid_fn1_ecx & (1<<23)) our_cpu_feature_bits |= 2; + SetSymbolValue(CPU_FEATURE_BITS, make_fixnum(our_cpu_feature_bits), 0); + // I don't know if this works on Windows #ifndef _MSC_VER cpuid(0, 0, &eax, &ebx, &ecx, &edx); @@ -113,6 +137,8 @@ void tune_asm_routines_for_microarch(void) void untune_asm_routines_for_microarch(void) { asm_routine_poke(VECTOR_FILL_T, 0x12, 0xEB); // Change JL to JMP + SetSymbolValue(CPU_FEATURE_BITS, 0, 0); + set_alloc_tramp_vectors(0); } #ifndef _WIN64 @@ -134,7 +160,7 @@ arch_get_bad_addr(int __attribute__((unused)) sig, */ os_context_register_t * -context_eflags_addr(os_context_t *context) +os_context_flags_addr(os_context_t *context) { #if defined __linux__ /* KLUDGE: As of kernel 2.2.14 on Red Hat 6.2, there's code in the @@ -172,7 +198,7 @@ void arch_skip_instruction(os_context_t *context) long code; /* Get and skip the Lisp interrupt code. */ - code = *(char*)(*os_context_pc_addr(context))++; + code = *(char*)(OS_CONTEXT_PC(context)++); switch (code) { case trap_Error: @@ -182,7 +208,7 @@ void arch_skip_instruction(os_context_t *context) case trap_UninitializedLoad: // Skip 1 byte. We can't encode that the internal_error_nargs is 1 // because it is not an SC+OFFSET that follows the trap code. - *os_context_pc_addr(context) += 1; + OS_CONTEXT_PC(context) += 1; break; case trap_Breakpoint: /* not tested */ case trap_FunEndBreakpoint: /* not tested */ @@ -206,33 +232,32 @@ void arch_skip_instruction(os_context_t *context) } FSHOW((stderr, - "/[arch_skip_inst resuming at %x]\n", - *os_context_pc_addr(context))); + "/[arch_skip_inst resuming at %x]\n", OS_CONTEXT_PC(context))); } unsigned char * arch_internal_error_arguments(os_context_t *context) { - return 1 + (unsigned char *)(*os_context_pc_addr(context)); + return 1 + (unsigned char *)OS_CONTEXT_PC(context); } boolean arch_pseudo_atomic_atomic(os_context_t __attribute__((unused)) *context) { - return get_pseudo_atomic_atomic(arch_os_get_current_thread()); + return get_pseudo_atomic_atomic(get_sb_vm_thread()); } void arch_set_pseudo_atomic_interrupted(os_context_t __attribute__((unused)) *context) { - struct thread *thread = arch_os_get_current_thread(); + struct thread *thread = get_sb_vm_thread(); set_pseudo_atomic_interrupted(thread); } void arch_clear_pseudo_atomic_interrupted(os_context_t __attribute__((unused)) *context) { - struct thread *thread = arch_os_get_current_thread(); + struct thread *thread = get_sb_vm_thread(); clear_pseudo_atomic_interrupted(thread); } @@ -272,7 +297,7 @@ unsigned int single_step_save3; void arch_do_displaced_inst(os_context_t *context, unsigned int orig_inst) { - unsigned int *pc = (unsigned int*)(*os_context_pc_addr(context)); + unsigned int *pc = (unsigned int*)OS_CONTEXT_PC(context); /* Put the original instruction back. */ arch_remove_breakpoint(pc, orig_inst); @@ -287,29 +312,28 @@ arch_do_displaced_inst(os_context_t *context, unsigned int orig_inst) *(pc-2) = 0x00240c81; *(pc-1) = 0x9d000001; #else - *context_eflags_addr(context) |= 0x100; + *os_context_flags_addr(context) |= 0x100; #endif single_stepping = pc; #ifdef CANNOT_GET_TO_SINGLE_STEP_FLAG - *os_context_pc_addr(context) = (os_context_register_t)((char *)pc - 9); + OS_CONTEXT_PC(context) = (os_context_register_t)((char *)pc - 9); #endif } void arch_handle_breakpoint(os_context_t *context) { - *os_context_pc_addr(context) -= BREAKPOINT_WIDTH; + OS_CONTEXT_PC(context) -= BREAKPOINT_WIDTH; handle_breakpoint(context); } void arch_handle_fun_end_breakpoint(os_context_t *context) { - *os_context_pc_addr(context) -= BREAKPOINT_WIDTH; - *os_context_pc_addr(context) = - (uword_t)handle_fun_end_breakpoint(context); + OS_CONTEXT_PC(context) -= BREAKPOINT_WIDTH; + OS_CONTEXT_PC(context) = (uword_t)handle_fun_end_breakpoint(context); } void @@ -331,13 +355,11 @@ restore_breakpoint_from_single_step(os_context_t * context) *(single_stepping-2) = single_step_save2; *(single_stepping-1) = single_step_save3; #else - *context_eflags_addr(context) &= ~0x100; + *os_context_flags_addr(context) &= ~0x100; #endif /* Re-install the breakpoint if possible. */ - if (((char *)*os_context_pc_addr(context) > - (char *)single_stepping) && - ((char *)*os_context_pc_addr(context) <= - (char *)single_stepping + BREAKPOINT_WIDTH)) { + if (((char *)OS_CONTEXT_PC(context) > (char *)single_stepping) && + ((char *)OS_CONTEXT_PC(context) <= (char *)single_stepping + BREAKPOINT_WIDTH)) { fprintf(stderr, "warning: couldn't reinstall breakpoint\n"); } else { arch_install_breakpoint(single_stepping); @@ -352,6 +374,12 @@ sigtrap_handler(int __attribute__((unused)) signal, siginfo_t __attribute__((unused)) *info, os_context_t *context) { +#ifdef LISP_FEATURE_INT1_BREAKPOINTS + // ICEBP instruction = handle-pending-interrupt following pseudo-atomic + if (((unsigned char*)OS_CONTEXT_PC(context))[-1] == 0xF1) + return interrupt_handle_pending(context); +#endif + unsigned int trap; if (single_stepping) { @@ -361,23 +389,23 @@ sigtrap_handler(int __attribute__((unused)) signal, /* This is just for info in case the monitor wants to print an * approximation. */ - access_control_stack_pointer(arch_os_get_current_thread()) = + access_control_stack_pointer(get_sb_vm_thread()) = (lispobj *)*os_context_sp_addr(context); /* On entry %rip points just after the INT3 byte and aims at the * 'kind' value (eg trap_Cerror). For error-trap and Cerror-trap a * number of bytes will follow, the first is the length of the byte * arguments to follow. */ - trap = *(unsigned char *)(*os_context_pc_addr(context)); + trap = *(unsigned char *)OS_CONTEXT_PC(context); #ifdef LISP_FEATURE_IMMOBILE_SPACE if (trap == trap_UndefinedFunction) { // The interrupted PC pins this fdefn. Sigtrap is delivered on the ordinary stack, // not the alternate stack. // (FIXME: an interior pointer to an fdefn _should_ pin it, but doesn't) - lispobj* fdefn = (lispobj*)(*os_context_pc_addr(context) & ~LOWTAG_MASK); + lispobj* fdefn = (lispobj*)(OS_CONTEXT_PC(context) & ~LOWTAG_MASK); if (fdefn && widetag_of(fdefn) == FDEFN_WIDETAG) { // Return to undefined-tramp - *os_context_pc_addr(context) = (uword_t)((struct fdefn*)fdefn)->raw_addr; + OS_CONTEXT_PC(context) = (uword_t)((struct fdefn*)fdefn)->raw_addr; // with RAX containing the FDEFN *os_context_register_addr(context,reg_RAX) = make_lispobj(fdefn, OTHER_POINTER_LOWTAG); @@ -392,20 +420,22 @@ void sigill_handler(int __attribute__((unused)) signal, siginfo_t __attribute__((unused)) *siginfo, os_context_t *context) { - unsigned char* pc = (void*)*os_context_pc_addr(context); -#ifndef LISP_FEATURE_MACH_EXCEPTION_HANDLER + unsigned char* pc = (void*)OS_CONTEXT_PC(context); if (*(unsigned short *)pc == UD2_INST) { - *os_context_pc_addr(context) += 2; + OS_CONTEXT_PC(context) += 2; return sigtrap_handler(signal, siginfo, context); } // Interrupt if overflow (INTO) raises SIGILL in 64-bit mode if (*(unsigned char *)pc == INTO_INST) { - *os_context_pc_addr(context) += 1; + OS_CONTEXT_PC(context) += 1; return sigtrap_handler(signal, siginfo, context); } -#endif fake_foreign_function_call(context); +#ifdef LISP_FEATURE_LINUX + extern void sb_dump_mcontext(char*,void*); + sb_dump_mcontext("SIGILL received", context); +#endif lose("Unhandled SIGILL at %p.", pc); } @@ -465,8 +495,6 @@ sigfpe_handler(int signal, siginfo_t *siginfo, os_context_t *context) void arch_install_interrupt_handlers() { - SHOW("entering arch_install_interrupt_handlers()"); - /* Note: The old CMU CL code here used sigtrap_handler() to handle * SIGILL as well as SIGTRAP. I couldn't see any reason to do * things that way. So, I changed to separate handlers when @@ -477,22 +505,20 @@ arch_install_interrupt_handlers() * OS I haven't tested on?) and we have to go back to the old CMU * CL way, I hope there will at least be a comment to explain * why.. -- WHN 2001-06-07 */ -#if !defined(LISP_FEATURE_MACH_EXCEPTION_HANDLER) && !defined(LISP_FEATURE_WIN32) - undoably_install_low_level_interrupt_handler(SIGILL , sigill_handler); - undoably_install_low_level_interrupt_handler(SIGTRAP, sigtrap_handler); +#ifndef LISP_FEATURE_WIN32 + ll_install_handler(SIGILL , sigill_handler); + ll_install_handler(SIGTRAP, sigtrap_handler); #endif #if defined(X86_64_SIGFPE_FIXUP) && !defined(LISP_FEATURE_WIN32) - undoably_install_low_level_interrupt_handler(SIGFPE, sigfpe_handler); + ll_install_handler(SIGFPE, sigfpe_handler); #endif - - SHOW("returning from arch_install_interrupt_handlers()"); } void arch_write_linkage_table_entry(int index, void *target_addr, int datap) { - char *reloc_addr = (char*)LINKAGE_TABLE_SPACE_START + index * LINKAGE_TABLE_ENTRY_SIZE; + char *reloc_addr = (char*)ALIEN_LINKAGE_TABLE_SPACE_START + index * ALIEN_LINKAGE_TABLE_ENTRY_SIZE; if (datap) { *(uword_t *)reloc_addr = (uword_t)target_addr; return; @@ -504,6 +530,17 @@ arch_write_linkage_table_entry(int index, void *target_addr, int datap) *(void**)(reloc_addr+8) = target_addr; } +void +*arch_read_linkage_table_entry(int index, int datap) +{ + char *reloc_addr = (char*)ALIEN_LINKAGE_TABLE_SPACE_START + index * ALIEN_LINKAGE_TABLE_ENTRY_SIZE; + if (datap) { + return (void*) *(uword_t *)reloc_addr; + } + + return *(void**)(reloc_addr+8); +} + /* These setup and check *both* the sse2 and x87 FPUs. While lisp code only uses the sse2 FPU, other code (such as libc) may use the x87 FPU. */ @@ -558,43 +595,69 @@ arch_set_fp_modes(unsigned int mxcsr) asm ("ldmxcsr %0" : : "m" (temp)); } -/// Return the Lisp object that fdefn's raw_addr slot jumps to. -/// This will either be: -/// (1) a simple-fun, -/// (2) a funcallable-instance with an embedded trampoline that makes -/// it resemble a simple-fun in terms of call convention, or -/// (3) a code-component with no simple-fun within it, that makes -/// closures and other funcallable-instances look like simple-funs. -/// If the fdefn jumps to the UNDEFINED-FDEFN routine, then return 0. -lispobj fdefn_callee_lispobj(struct fdefn* fdefn) { - lispobj* raw_addr = (lispobj*)fdefn->raw_addr; - if (!raw_addr || points_to_asm_code_p((lispobj)raw_addr)) - // technically this should return the address of the code object - // containing asm routines, but it's fine to return 0. - return 0; - // If the object to which raw_addr points was already forwarded, - // this returns the "old" pointer, prior to forwarding, so that - // scavenging that pointer alters it. Otherwise scav_fdefn would not - // decide to rewrite the raw_addr slot of the fdefn. - // This logic is rather nasty, but I don't know what else to do. - lispobj word; - if (header_widetag(word = raw_addr[-2]) == SIMPLE_FUN_WIDETAG - || (word == 1 && - widetag_of(native_pointer(forwarding_pointer_value(raw_addr-2))) - == SIMPLE_FUN_WIDETAG)) - return make_lispobj(raw_addr - 2, FUN_POINTER_LOWTAG); - int widetag; - if ((widetag = header_widetag(word = raw_addr[-4])) == CODE_HEADER_WIDETAG - || (word == 1 && - widetag_of(native_pointer(forwarding_pointer_value(raw_addr-4))) - == CODE_HEADER_WIDETAG)) - return make_lispobj(raw_addr - 4, OTHER_POINTER_LOWTAG); - if (widetag == FUNCALLABLE_INSTANCE_WIDETAG - || (word == 1 && - widetag_of(native_pointer(forwarding_pointer_value(raw_addr-4))) - == FUNCALLABLE_INSTANCE_WIDETAG)) - return make_lispobj(raw_addr - 4, FUN_POINTER_LOWTAG); - lose("Unknown object in fdefn raw addr: %p", raw_addr); +static __attribute__((unused)) boolean codeblob_p(lispobj ptr) { + return lowtag_of(ptr) == OTHER_POINTER_LOWTAG && + widetag_of((lispobj*)(ptr-OTHER_POINTER_LOWTAG)) == CODE_HEADER_WIDETAG; +} + +/* Return the tagged pointer for which 'entrypoint' is the starting address. + * This will be one of the following: + * 1. a fun-pointer which is either + * - a simple-fun header located 2 words before the entrypoint. + * N.B.: This returns the SIMPLE-FUN, and _not_ its containing codeblob. + * - a funcallable-instance with an embedded trampoline that make it + * equivalent to a simple-fun + * 2. a code-component with no simple-fun within it, that makes closures + * callable like simple-funs. The code header is at entrypoint minus 4 words. + * + * By first reading at (entrypoint - 2*N_WORD_BYTES) this does the right thing + * when 'entrypoint' is actually type 2, because the word accessed will not be + * an object header or forwarding marker (it will be whatever %CODE-DEBUG-INFO is). + * Whereis if this were type 1, but we read at (entrypoint - 4*N_WORD_BYTES) first, + * then we could perceive random uninitialized bytes of the preceding object. + */ +lispobj entrypoint_taggedptr(uword_t entrypoint) { + if (!entrypoint || points_to_asm_code_p(entrypoint)) return 0; + // First try + lispobj* phdr = (lispobj*)(entrypoint - 2*N_WORD_BYTES); + if (forwarding_pointer_p(phdr)) { + gc_dcheck(lowtag_of(forwarding_pointer_value(phdr)) == FUN_POINTER_LOWTAG); + return make_lispobj(phdr, FUN_POINTER_LOWTAG); + } + int widetag = widetag_of(phdr); + if (widetag == FUNCALLABLE_INSTANCE_WIDETAG || widetag == SIMPLE_FUN_WIDETAG) { + return make_lispobj(phdr, FUN_POINTER_LOWTAG); + } + // Second try + phdr = (lispobj*)(entrypoint - 4*N_WORD_BYTES); + /* It is nearly impossible for forwarding to arise, by this reasoning: + * Case A: if some thread references the codeblob that wraps a closure, + * then the codeblob is pinned; hence not forwarded. + * Case B: if not executing (or otherwise referenced from stack/registers), + * there can exist no other tagged reference to the codeblob. + * Aside from the FDEFN that owns it, the only other untagged reference would + * be from the search tree, which isn't scavenged. (The entire tree dies after GC.) + * It's conceivable the debugger could store a tagged pointer to this entrypoint + * in something, but I tried to make it do so, and couldn't. I was, however, able + * to artificially cause forwarding by putting closure trampolines in symbols */ + if (forwarding_pointer_p(phdr)) + gc_dcheck(codeblob_p(forwarding_pointer_value(phdr))); + else + gc_dcheck(widetag_of(phdr) == CODE_HEADER_WIDETAG); + return make_lispobj(phdr, OTHER_POINTER_LOWTAG); +} +/* Return the lisp object that fdefn's raw_addr slot jumps to. + * In the event that the referenced object was forwarded, this returns the un-forwarded + * object (the forwarded value is used to assert some invariants though). + * If the fdefn jumps to the UNDEFINED-FDEFN routine, then return 0. + * + * Some legacy baggage is evident: in the first implementation of immobile fdefns, + * an fdefn used a 'jmp rel32' (relative to itself), and so you could decode the + * jump target only given the address of the fdefn. That is no longer true; fdefns use + * absolute jumps. Therefore it is possible to call entrypoint_taggedptr() with any + * raw_addr, whether or not you know the fdefn whence the raw_addr was obtained. */ +lispobj decode_fdefn_rawfun(struct fdefn* fdefn) { + return entrypoint_taggedptr((uword_t)fdefn->raw_addr); } #include "genesis/vector.h" @@ -604,8 +667,12 @@ lispobj fdefn_callee_lispobj(struct fdefn* fdefn) { extern unsigned int alloc_profile_n_counters; extern unsigned int max_alloc_point_counters; #ifdef LISP_FEATURE_SB_THREAD +#ifdef LISP_FEATURE_WIN32 +extern CRITICAL_SECTION alloc_profiler_lock; +#else extern pthread_mutex_t alloc_profiler_lock; #endif +#endif static unsigned int claim_index(int qty) { @@ -621,10 +688,11 @@ static unsigned int claim_index(int qty) return 0; // use the overflow bin(s) } -static boolean instrumentp(uword_t* sp, uword_t** pc, uword_t* old_word) +static boolean NO_SANITIZE_MEMORY +instrumentp(uword_t* sp, uword_t** pc, uword_t* old_word) { - int __attribute__((unused)) ret = thread_mutex_lock(&alloc_profiler_lock); - gc_assert(ret == 0); + int __attribute__((unused)) ret = mutex_acquire(&alloc_profiler_lock); + gc_assert(ret); uword_t next_pc = *sp; // The instrumentation site was 8-byte aligned uword_t return_pc = ALIGN_DOWN(next_pc, 8); @@ -662,11 +730,11 @@ static void record_pc(char* pc, unsigned int index, boolean sizedp) } #if 0 if (!code) { - int ret = thread_mutex_lock(&free_pages_lock); - gc_assert(ret == 0); + int ret = mutex_acquire(&free_pages_lock); + gc_assert(ret); ensure_region_closed(code_region); - int ret = thread_mutex_unlock(&free_pages_lock); - gc_assert(ret == 0); + int ret = mutex_release(&free_pages_lock); + gc_assert(ret); code = component_ptr_from_pc(pc); } #endif @@ -676,7 +744,14 @@ static void record_pc(char* pc, unsigned int index, boolean sizedp) v->data[index] = v->data[index+1] = NIL; index += 2; } + // Wasn't the point of code serial# that you don't store + // code blob pointers into the various profiling buffers? (FIXME?) if (code) { + /* If the first of the two stores is at an even index, then the second + * "notice" call is redundant because it will certainly be on the same card. + * Doing both calls is future-proof though. */ + notice_pointer_store(&v->data[index]); + notice_pointer_store(&v->data[index+1]); v->data[index] = make_lispobj(code, OTHER_POINTER_LOWTAG); v->data[index+1] = make_fixnum((lispobj)pc - (lispobj)code); } else { @@ -694,9 +769,18 @@ allocation_tracker_counted(uword_t* sp) unsigned int index = claim_index(1); if (index == 0) index = 2; // reserved overflow counter for fixed-size alloc - // rewrite call into: LOCK INC QWORD PTR, [R11+n] ; opcode = 0xFF / 0 - uword_t new_inst = - 0xF0 | (0x49 << 8) | (0xFF << 16) | (0x83L << 24) | ((index*8L) << 32); + uword_t disp = index * 8; + int base_reg = -1; + if ((word_at_pc & 0xff) == 0xE8) { + // following is a 1-byte NOP and a dummy "TEST imm8" where the imm8 + // encodes a register number. + base_reg = word_at_pc >> 56; + } else { + lose("Unexpected instruction format @ %p", pc); + } + // rewrite call into: LOCK INC QWORD PTR, [Rbase+n] ; opcode = 0xFF / 0 + uword_t new_inst = 0xF0 | ((0x48|(base_reg>>3)) << 8) // w + possibly 'b' + | (0xFF << 16) | ((0x80L+(base_reg&7)) << 24) | (disp << 32); // Ensure atomicity of the write. A plain store would probably do, // but since this is self-modifying code, the most stringent memory // order is prudent. @@ -705,8 +789,8 @@ allocation_tracker_counted(uword_t* sp) if (index != 2) record_pc((char*)pc, index, 0); } - int __attribute__((unused)) ret = thread_mutex_unlock(&alloc_profiler_lock); - gc_assert(ret == 0); + int __attribute__((unused)) ret = mutex_release(&alloc_profiler_lock); + gc_assert(ret); } void AMD64_SYSV_ABI @@ -716,26 +800,20 @@ allocation_tracker_sized(uword_t* sp) if (instrumentp(sp, &pc, &word_at_pc)) { int index = claim_index(2); uword_t word_after_pc = pc[1]; - unsigned char prefix = word_after_pc & 0xFF; - unsigned char opcode = (word_after_pc >> 8) & 0xFF; - unsigned char modrm = (word_after_pc >> 16) & 0xFF; - if ((prefix == 0x48 || prefix == 0x4D) && /* REX w=1 or w=r=b=1 */ - (opcode == 0x85) && /* TEST */ - (modrm & 0xC0) == 0xC0 && /* register-direct mode */ - ((modrm >> 3) & 0x7) == (modrm & 0x7)) { /* same register */ - } else { - lose("Can't decode instruction @ pc %p", pc); - } + int pair = word_at_pc >> 56; + int base_reg = pair & 0xf; + int size_reg = pair >> 4; // rewrite call into: - // LOCK INC QWORD PTR, [R11+n] ; opcode = 0xFF / 0 - uword_t new_inst1 = - 0xF0 | (0x49 << 8) | (0xFF << 16) | (0x83L << 24) | ((index * 8L) << 32); - // LOCK ADD [R11+n], Rxx ; opcode = 0x01 - prefix = 0x49 | ((prefix & 1) << 2); // 'b' bit becomes 'r' bit - modrm = 0x83 | (modrm & (7<<3)); // copy 'reg' into new modrm byte + // LOCK INC QWORD PTR, [Rbase+n] ; opcode = 0xFF / 0 + uword_t disp = index * 8; + uword_t new_inst1 = 0xF0 | ((0x48 | (base_reg>>3)) << 8) // w + b + | (0xFF << 16) | ((0x80L+(base_reg&7)) << 24) | (disp << 32); + // LOCK ADD [Rbase+n+8], Rsize ; opcode = 0x01 + int prefix = 0x48 | ((size_reg >> 3) << 2) | (base_reg >> 3); // w + r + b + int modrm = 0x80 | ((size_reg & 7) << 3) | (base_reg & 7); + disp = (1 + index) * 8; uword_t new_inst2 = - 0xF0 | (prefix << 8) | (0x01 << 16) | ((long)modrm << 24) - | (((1 + index) * 8L) << 32); + 0xF0 | (prefix << 8) | (0x01 << 16) | ((long)modrm << 24) | (disp << 32); // Overwrite the second instruction first, because as soon as the CALL // opcode is changed, fallthrough to the next instruction occurs. if (!__sync_bool_compare_and_swap(pc+1, word_after_pc, new_inst2) || @@ -744,6 +822,20 @@ allocation_tracker_sized(uword_t* sp) if (index != 0) // can't record a PC for the overflow counts record_pc((char*)pc, index, 1); } - int __attribute__((unused)) ret = thread_mutex_unlock(&alloc_profiler_lock); - gc_assert(ret == 0); + int __attribute__((unused)) ret = mutex_release(&alloc_profiler_lock); + gc_assert(ret); } + +__attribute__((sysv_abi)) lispobj call_into_lisp(lispobj fun, lispobj *args, int nargs) { + extern lispobj call_into_lisp_(lispobj, lispobj *, int, struct thread *) + __attribute__((sysv_abi)); + return call_into_lisp_(fun, args, nargs, get_sb_vm_thread()); +} + +lispobj call_into_lisp_first_time(lispobj fun, lispobj *args, int nargs) { + extern lispobj call_into_lisp_first_time_(lispobj, lispobj *, int, struct thread *) + __attribute__((sysv_abi)); + return call_into_lisp_first_time_(fun, args, nargs, get_sb_vm_thread()); +} + +#include "x86-arch-shared.inc" diff --git a/src/runtime/x86-64-arch.h b/src/runtime/x86-64-arch.h index 528fa53ead..992176fddf 100644 --- a/src/runtime/x86-64-arch.h +++ b/src/runtime/x86-64-arch.h @@ -6,7 +6,6 @@ #define _X86_64_ARCH_H #define ARCH_HAS_STACK_POINTER -#define ALIEN_STACK_GROWS_DOWNWARD extern int avx_supported, avx2_supported; extern unsigned int cpuid_fn1_ecx; diff --git a/src/runtime/x86-64-assem.S b/src/runtime/x86-64-assem.S index 5bf3177e61..8959c3caaa 100644 --- a/src/runtime/x86-64-assem.S +++ b/src/runtime/x86-64-assem.S @@ -25,11 +25,6 @@ #include "genesis/fdefn.h" #include "genesis/static-symbols.h" #include "genesis/thread.h" -#ifdef MEMORY_SANITIZER -#include "genesis/symbol.h" -#endif -#include "genesis/ratio.h" -#include "genesis/complex.h" /* Minimize conditionalization for different OS naming schemes. */ #if defined __linux__ || defined LISP_FEATURE_HAIKU || defined LISP_FEATURE_FREEBSD || \ @@ -41,32 +36,18 @@ // Produce position-independent code. // macOS does not like the general way we do this, so do something different. -// I don't know about win32, so conservatively exclude that too. -#if !defined LISP_FEATURE_DARWIN && !defined LISP_FEATURE_WIN32 -#define PIC_CALL(x) x@PLT -#define LOAD_PIC_VAR(x,dest) mov GNAME(x)@GOTPCREL(%rip), dest ; mov (dest), dest -#else -#define PIC_CALL(x) x -#ifdef LISP_FEATURE_DARWIN +#if defined(LISP_FEATURE_DARWIN) || defined(LISP_FEATURE_WIN32) #define LOAD_PIC_VAR(x,dest) mov GNAME(x)(%rip), dest #else -#define LOAD_PIC_VAR(x,dest) mov GNAME(x), dest -#endif +#define LOAD_PIC_VAR(x,dest) mov GNAME(x)@GOTPCREL(%rip), dest ; mov (dest), dest #endif /* Get the right type of alignment. Linux, FreeBSD and OpenBSD * want alignment in bytes. */ #if defined(__linux__) || defined(LISP_FEATURE_FREEBSD) || defined(__OpenBSD__) || defined __NetBSD__ || defined(__sun) || defined _WIN64 || defined(__DragonFly__) -#define align_4byte 4 -#define align_8byte 8 #define align_16byte 16 -#define align_32byte 32 -#define align_page 32768 #else -#define align_4byte 2 -#define align_8byte 3 #define align_16byte 4 -#define align_page 15 #endif /* @@ -90,9 +71,20 @@ #define TRAP int3 #endif +#define CARD_TABLE_REG %r12 #define THREAD_BASE_REG %r13 -#ifdef OS_THREAD_STACK +#ifdef LISP_FEATURE_WIN32 +#define CARG1 %rcx +#define CARG2 %rdx +#define CARG3 %r8 +#else +#define CARG1 %rdi +#define CARG2 %rsi +#define CARG3 %rdx +#endif + +#ifdef LISP_FEATURE_OS_THREAD_STACK .text .globl GNAME(funcall1_switching_stack) TYPE(GNAME(funcall1_switching_stack)) @@ -104,8 +96,16 @@ GNAME(funcall1_switching_stack): push %rbp mov %rsp,%rbp - mov THREAD_CONTROL_STACK_END_OFFSET(%rdi),%rsp - call *%rsi + mov THREAD_CONTROL_STACK_END_OFFSET(CARG1),%rsp + +#ifdef LISP_FEATURE_WIN32 + /* _chkstk() is called at some unknown points and is + expecting that + */ + mov THREAD_CONTROL_STACK_START_OFFSET(CARG1), %rax + movq %rax, %gs:16 +#endif + call *CARG2 mov %rbp, %rsp pop %rbp @@ -114,8 +114,8 @@ GNAME(funcall1_switching_stack): #endif .text - .globl GNAME(call_into_lisp_first_time) - TYPE(GNAME(call_into_lisp_first_time)) + .globl GNAME(call_into_lisp_first_time_) + TYPE(GNAME(call_into_lisp_first_time_)) /* We don't worry too much about saving registers * here, because we never expect to return from the initial call to lisp @@ -123,24 +123,17 @@ GNAME(funcall1_switching_stack): .align align_16byte,0x90 .cfi_startproc -GNAME(call_into_lisp_first_time): +GNAME(call_into_lisp_first_time_): GNAME(lspmain): # so much easier to type 'b lspmain' in gdb push %rbp # Save old frame pointer. mov %rsp,%rbp # Establish new frame. -#ifdef MEMORY_SANITIZER // Presumes GCC_TLS and SB_THREAD - movq GNAME(current_thread)@GOTTPOFF(%rip), %r8 // Clobberable - movq %fs:(%r8), %r8 - movq %fs:0, %rax - leaq __msan_param_tls@TPOFF(%rax), %rax - movq %rax, THREAD_MSAN_PARAM_TLS_OFFSET(%r8) -#endif LOAD_PIC_VAR(all_threads, %rax) mov THREAD_CONTROL_STACK_END_OFFSET(%rax) ,%rsp jmp Lstack .text - .globl GNAME(call_into_lisp) - TYPE(GNAME(call_into_lisp)) + .globl GNAME(call_into_lisp_) + TYPE(GNAME(call_into_lisp_)) /* * amd64 calling convention: C expects that @@ -152,7 +145,7 @@ GNAME(lspmain): # so much easier to type 'b lspmain' in gdb # define SUPPORT_FOMIT_FRAME_POINTER #endif .align align_16byte,0x90 -GNAME(call_into_lisp): +GNAME(call_into_lisp_): #ifdef SUPPORT_FOMIT_FRAME_POINTER mov %rbp,%rax #endif @@ -176,20 +169,7 @@ Lstack: push %rdi # args from C push %rsi # push %rdx # -#ifdef LISP_FEATURE_SB_THREAD -#ifdef LISP_FEATURE_GCC_TLS - movq GNAME(current_thread)@GOTTPOFF(%rip), THREAD_BASE_REG - movq %fs:(THREAD_BASE_REG), THREAD_BASE_REG -#else - LOAD_PIC_VAR(specials, %rdi) - call PIC_CALL(GNAME(pthread_getspecific)) - mov %rax, THREAD_BASE_REG -#endif -#elif defined(LISP_FEATURE_SB_SAFEPOINT) - /* We need this to find the CSP trap page. This does no harm, - * as the compiler doesn't use THREAD_BASE_REG on non-threaded builds. */ - LOAD_PIC_VAR(all_threads, THREAD_BASE_REG) -#endif + movq %rcx, THREAD_BASE_REG pop %rcx # num args pop %rbx # arg vector pop %rax # function ptr/lexenv @@ -216,12 +196,17 @@ Lzero: push %rbp # Dummy for return address push %rbp # fp in save location S1 mov %rsp,%rbp # The current sp marks start of new frame. +#ifndef LISP_FEATURE_DARWIN + # This call frame info is valid but it makes macOS print a warning + # that I'm tired of seeing. I can't even remember why this helps. # Inform unwinder that the new frame has not been entered yet. # The CFA is what it was (old RBP+16) before the preceding mov. # This sequence encodes DW_CFA_def_cfa_expression # DW_OP_breg6 (rbp): 0 / DW_OP_deref / DW_OP_lit16 / DW_OP_plus .cfi_escape 0x0f, 5, 0x76, 0, 6, 0x40, 0x22 +#endif Lcall: + LOAD_PIC_VAR(gc_card_mark, CARD_TABLE_REG) call *CLOSURE_FUN_OFFSET(%rax) /* If the function returned multiple values, the carry flag will be set. @@ -249,7 +234,7 @@ LsingleValue: #endif ret .cfi_endproc - SIZE(GNAME(call_into_lisp)) + SIZE(GNAME(call_into_lisp_)) .text .globl GNAME(funcall_alien_callback) @@ -288,6 +273,7 @@ GNAME(funcall_alien_callback): #else mov (ENTER_ALIEN_CALLBACK_FDEFN+FDEFN_FUN_OFFSET),%rax #endif + LOAD_PIC_VAR(gc_card_mark, CARD_TABLE_REG) call *CLOSURE_FUN_OFFSET(%rax) /* Restore C regs */ @@ -444,7 +430,8 @@ ascs_check_guard_page: jae ascs_clear_loop cmp %rax, %rsi ja ascs_clear_loop - cmpq $(NIL), THREAD_CONTROL_STACK_GUARD_PAGE_PROTECTED_OFFSET(%rdi) + /* test state_word.control_stack_guard_page_protected */ + cmpb $0, THREAD_STATE_WORD_OFFSET(%rdi) jne ascs_finished /* Clear memory backwards to the start of the (4KiB) page */ diff --git a/src/runtime/x86-64-bsd-os.c b/src/runtime/x86-64-bsd-os.c index 844e74c864..f18e391b62 100644 --- a/src/runtime/x86-64-bsd-os.c +++ b/src/runtime/x86-64-bsd-os.c @@ -81,12 +81,6 @@ os_context_fp_addr(os_context_t *context) return CONTEXT_ADDR_FROM_STEM(rbp); } -os_context_register_t * -os_context_pc_addr(os_context_t *context) -{ - return CONTEXT_ADDR_FROM_STEM(rip); -} - #elif defined(LISP_FEATURE_NETBSD) os_context_register_t * os_context_register_addr(os_context_t *context, int offset) @@ -135,12 +129,6 @@ os_context_sp_addr(os_context_t *context) return CONTEXT_ADDR_FROM_STEM(RSP); } -os_context_register_t * -os_context_pc_addr(os_context_t *context) -{ - return CONTEXT_ADDR_FROM_STEM(RIP); -} - #endif void @@ -149,17 +137,6 @@ os_flush_icache(os_vm_address_t address, os_vm_size_t length) } int arch_os_thread_init(struct thread *thread) { -#ifdef LISP_FEATURE_SB_THREAD -#ifdef LISP_FEATURE_GCC_TLS - current_thread = thread; -#else - pthread_setspecific(specials,thread); -#endif -#endif - -#ifdef LISP_FEATURE_MACH_EXCEPTION_HANDLER - mach_lisp_thread_init(thread); -#elif defined(LISP_FEATURE_C_STACK_IS_CONTROL_STACK) /* Signal handlers are run on the control stack, so if it is exhausted * we had better use an alternate stack for whatever signal tells us * we've exhausted it */ @@ -168,7 +145,6 @@ int arch_os_thread_init(struct thread *thread) { sigstack.ss_flags = 0; sigstack.ss_size = calc_altstack_size(thread); sigaltstack(&sigstack,0); -#endif return 1; /* success */ } diff --git a/src/runtime/x86-64-bsd-os.h b/src/runtime/x86-64-bsd-os.h index 9a35e73e01..c73cc7563f 100644 --- a/src/runtime/x86-64-bsd-os.h +++ b/src/runtime/x86-64-bsd-os.h @@ -22,14 +22,17 @@ typedef register_t os_context_register_t; * same stems to name the structure fields, so by using this macro we * can share a fair amount of code between different variants. */ #if defined LISP_FEATURE_FREEBSD || defined(__DragonFly__) -#define CONTEXT_ADDR_FROM_STEM(stem) &context->uc_mcontext.mc_ ## stem +#define CONTEXT_SLOT(c,stem) context->uc_mcontext.mc_ ## stem #elif defined(__OpenBSD__) -#define CONTEXT_ADDR_FROM_STEM(stem) &context->sc_ ## stem +#define CONTEXT_SLOT(c,stem) context->sc_ ## stem #elif defined __NetBSD__ -#define CONTEXT_ADDR_FROM_STEM(stem) &((context)->uc_mcontext.__gregs[_REG_ ## stem]) +#define CONTEXT_SLOT(c,stem) ((context)->uc_mcontext.__gregs[_REG_ ## stem]) #else #error unsupported BSD variant #endif +// "&" binds weaker than {->,.,[]} so this does what we want +// Note that this macro is unhygienic. +#define CONTEXT_ADDR_FROM_STEM(stem) &CONTEXT_SLOT(context,stem) #if defined LISP_FEATURE_DRAGONFLY /* I am not sure if following definition is needed after this: @@ -69,4 +72,10 @@ arch_os_context_mxcsr_addr(os_context_t *context) void os_restore_fp_control(os_context_t *context); #endif +#if defined LISP_FEATURE_FREEBSD || defined LISP_FEATURE_OPENBSD || defined LISP_FEATURE_DRAGONFLY +# define OS_CONTEXT_PC(context) CONTEXT_SLOT(context,rip) +#elif defined LISP_FEATURE_NETBSD +# define OS_CONTEXT_PC(context) CONTEXT_SLOT(context,RIP) +#endif + #endif /* _X86_64_BSD_OS_H */ diff --git a/src/runtime/x86-64-darwin-os.c b/src/runtime/x86-64-darwin-os.c index 9624a19d2a..2179472827 100644 --- a/src/runtime/x86-64-darwin-os.c +++ b/src/runtime/x86-64-darwin-os.c @@ -1,36 +1,11 @@ -#ifdef LISP_FEATURE_SB_THREAD -#include <mach/mach_init.h> -#endif - +// Not sure which headers are really needed ... #include "thread.h" -#include "validate.h" -#include "runtime.h" -#include "interrupt.h" -#include "x86-64-darwin-os.h" -#include "x86-64-arch.h" -#include "genesis/fdefn.h" -#include "gc-internal.h" -#include "arch.h" - -#include <mach/mach.h> -#include <mach/mach_error.h> -#include <mach/mach_types.h> -#include <mach/sync_policy.h> -#include <mach/machine/thread_state.h> -#include <mach/machine/thread_status.h> #include <sys/_types.h> #include <sys/ucontext.h> #include <pthread.h> -#include <assert.h> -#include <stdlib.h> -#include <stdio.h> #if __DARWIN_UNIX03 #include <sys/_structs.h> -#endif - -#if __DARWIN_UNIX03 - typedef struct __darwin_ucontext darwin_ucontext; #define rip __rip @@ -59,362 +34,6 @@ typedef struct ucontext darwin_ucontext; #endif -#ifdef x86_AVX_STATE64_COUNT -typedef _STRUCT_MCONTEXT_AVX64 darwin_mcontext; -#else -typedef _STRUCT_MCONTEXT64 darwin_mcontext; -#endif - -#ifdef LISP_FEATURE_MACH_EXCEPTION_HANDLER - -void sigill_handler(int signal, siginfo_t *siginfo, os_context_t *context); -void sigtrap_handler(int signal, siginfo_t *siginfo, os_context_t *context); -void memory_fault_handler(int signal, siginfo_t *siginfo, - os_context_t *context); - -void -undefined_alien_handler(int signal, siginfo_t *siginfo, os_context_t *context) { - arrange_return_to_lisp_function - (context, StaticSymbolFunction(UNDEFINED_ALIEN_VARIABLE_ERROR)); -} - -/* This executes in the faulting thread as part of the signal - * emulation. It is passed a context with the uc_mcontext field - * pointing to a valid block of memory. */ -void build_fake_signal_context(darwin_ucontext *context, - x86_thread_state64_t *thread_state, - x86_float_state64_t *float_state) { - block_blockable_signals(&context->uc_sigmask); - context->uc_mcontext->ss = *thread_state; - context->uc_mcontext->fs = *float_state; -} - -/* This executes in the faulting thread as part of the signal - * emulation. It is effectively the inverse operation from above. */ -void update_thread_state_from_context(x86_thread_state64_t *thread_state, - x86_float_state64_t *float_state, - darwin_ucontext *context) { - *thread_state = context->uc_mcontext->ss; - *float_state = context->uc_mcontext->fs; - thread_sigmask(SIG_SETMASK, &context->uc_sigmask, NULL); -} - -boolean will_exhaust_stack(struct thread * th, x86_thread_state64_t *context, int size) { - __uint64_t sp = context->rsp - size; - - if(sp < (__uint64_t)(CONTROL_STACK_HARD_GUARD_PAGE(th) + os_vm_page_size)) { - lose("Control stack exhausted during signal emulation: PC: %llx", - context->rip); - } - - if(sp < (__uint64_t)(CONTROL_STACK_GUARD_PAGE(th) + os_vm_page_size) && - th->control_stack_guard_page_protected != NIL) { - /* We hit the end of the control stack: disable guard page - * protection so the error handler has some headroom, protect the - * previous page so that we can catch returns from the guard page - * and restore it. */ - lower_thread_control_stack_guard_page(th); - context->rsp = (__uint64_t)(CONTROL_STACK_GUARD_PAGE(th) + os_vm_page_size); - return 1; - } - return 0; -} - -/* Modify a context to push new data on its stack. */ -void push_context(u64 data, x86_thread_state64_t *context) -{ - u64* stack_pointer = (u64*)context->rsp - 1; - - context->rsp = (__uint64_t) stack_pointer; - *stack_pointer = data; -} - -void align_context_stack(x86_thread_state64_t *context) -{ - /* 16-byte align the stack. */ - context->rsp &= ~15; -} - -void *stack_allocate(struct thread * th, x86_thread_state64_t *context, size_t size) -{ - - context->rsp = context->rsp - size; - return (void*)context->rsp; -} - -void signal_emulation_wrapper(darwin_mcontext *mcontext, - int signal, - os_vm_address_t addr, - void (*handler)(int, siginfo_t *, void *)) -{ - siginfo_t siginfo; - darwin_ucontext context; - - siginfo.si_signo = signal; - siginfo.si_addr = addr; - - context.uc_mcontext = (_STRUCT_MCONTEXT64 *)mcontext; - - /* when BSD signals are fired, they mask they signals in sa_mask - which always seem to be the blockable_sigset, for us, so we - need to: - 1) save the current sigmask - 2) block blockable signals - 3) call the signal handler - 4) restore the sigmask */ - - block_blockable_signals(&context.uc_sigmask); - - handler(signal, &siginfo, &context); - - thread_sigmask(SIG_SETMASK, &context.uc_sigmask, NULL); - - /* Trap to restore the signal context. */ - asm volatile (".quad 0xffffffffffff0b0f" - : : "a" (mcontext)); -} - -void call_signal_emulator_in_context(x86_thread_state64_t *context, - darwin_mcontext *mcontext, - int signal, - os_vm_address_t addr, - void* handler) -{ - - align_context_stack(context); - push_context(context->rip, context); - context->rdi = (u64) mcontext; - context->rsi = signal; - context->rdx = (u64) addr; - context->rcx = (u64) handler; - - context->rip = (u64) signal_emulation_wrapper; -} - -/* Call CONTROL_STACK_EXHAUSTED_ERROR directly, without emulating - signals. It doesn't need any signal contexts and it's better to use - as little stack as possible. */ -void call_stack_exhausted_in_context(x86_thread_state64_t *context) -{ - align_context_stack(context); - push_context(context->rip, context); - context->rdi = (u64) StaticSymbolFunction(CONTROL_STACK_EXHAUSTED_ERROR); - context->rip = (u64) funcall0; -} - -#if defined DUMP_CONTEXT -void dump_context(x86_thread_state64_t *context) -{ - int i; - u64 *stack_pointer; - - printf("rax: %08lx rcx: %08lx rdx: %08lx rbx: %08lx\n", - context->rax, context->rcx, context->rdx, context->rbx); - printf("rsp: %08lx rbp: %08lx rsi: %08lx rdi: %08lx\n", - context->rsp, context->rbp, context->rsi, context->rdi); - printf("rip: %08lx eflags: %08lx\n", - context->rip, context->rflags); - printf("cs: %04hx ds: %04hx es: %04hx " - "ss: %04hx fs: %04hx gs: %04hx\n", - context->cs, context->ds, context->rs, - context->ss, context->fs, context->gs); - - stack_pointer = (u64 *)context->rsp; - for (i = 0; i < 48; i+=4) { - printf("%08x: %08x %08x %08x %08x\n", - context->rsp + (i * 4), - stack_pointer[i], - stack_pointer[i+1], - stack_pointer[i+2], - stack_pointer[i+3]); - } -} -#endif - -kern_return_t -catch_exception_raise(mach_port_t exception_port, - mach_port_t thread, - mach_port_t task, - exception_type_t exception, - exception_data_t code_vector, - mach_msg_type_number_t code_count) -{ - kern_return_t ret = KERN_SUCCESS, dealloc_ret; - int signal, rip_offset = 0; - void (*handler)(int, siginfo_t *, os_context_t *); - - x86_thread_state64_t thread_state; - mach_msg_type_number_t thread_state_count = x86_THREAD_STATE64_COUNT; - -#ifdef x86_AVX_STATE64_COUNT - mach_msg_type_number_t float_state_count = avx_supported? x86_AVX_STATE64_COUNT : x86_FLOAT_STATE64_COUNT; - int float_state_flavor = avx_supported? x86_AVX_STATE64 : x86_FLOAT_STATE64; -#else - mach_msg_type_number_t float_state_count = x86_FLOAT_STATE64_COUNT; - int float_state_flavor = x86_FLOAT_STATE64; -#endif - - x86_exception_state64_t exception_state; - mach_msg_type_number_t exception_state_count = x86_EXCEPTION_STATE64_COUNT; - - x86_thread_state64_t backup_thread_state; - - os_vm_address_t addr; - - thread_get_state(thread, x86_EXCEPTION_STATE64, - (thread_state_t)&exception_state, &exception_state_count); - - if (code_count && exception == EXC_BAD_ACCESS && code_vector[0] == EXC_I386_GPFLT) { - /* This can happen for addresses larger than 48 bits, - resulting in bogus faultvaddr. */ - addr = NULL; - } else { - addr = (void*)exception_state.faultvaddr; - } - - /* Just need to unprotect the page and do some bookkeeping, no need - * to run it from the faulting thread. - * And because the GC uses signals to stop the world it might - * interfere with that bookkeeping, because there's a window - * before block_blockable_signals is performed. */ - if (exception == EXC_BAD_ACCESS && gencgc_handle_wp_violation(addr)) { - goto do_not_handle; - } - - struct thread *th; - - FSHOW((stderr,"/entering catch_exception_raise with exception: %d\n", exception)); - if (mach_port_get_context(mach_task_self(), exception_port, (mach_vm_address_t *)&th) - != KERN_SUCCESS) { - lose("Can't find the thread for an exception %u", exception_port); - } - thread_get_state(thread, x86_THREAD_STATE64, - (thread_state_t)&thread_state, &thread_state_count); - - boolean stack_unprotected = 0; - - switch (exception) { - - case EXC_BAD_ACCESS: - signal = SIGBUS; - - if(addr >= CONTROL_STACK_RETURN_GUARD_PAGE(th) && - addr < CONTROL_STACK_RETURN_GUARD_PAGE(th) + os_vm_page_size) { - /* We're returning from the guard page: reprotect it, and - * unprotect this one. This works even if we somehow missed - * the return-guard-page, and hit it on our way to new - * exhaustion instead. */ - reset_thread_control_stack_guard_page(th); - goto do_not_handle; - } - - /* note the os_context hackery here. When the signal handler returns, - * it won't go back to what it was doing ... */ - if(addr >= CONTROL_STACK_GUARD_PAGE(th) && - addr < CONTROL_STACK_GUARD_PAGE(th) + os_vm_page_size) { - /* We hit the end of the control stack: disable guard page - * protection so the error handler has some headroom, protect the - * previous page so that we can catch returns from the guard page - * and restore it. */ - lower_thread_control_stack_guard_page(th); - stack_unprotected = 1; - } - else if (addr >= undefined_alien_address && - addr < undefined_alien_address + os_vm_page_size) { - handler = undefined_alien_handler; - } else { - handler = memory_fault_handler; - } - break; - case EXC_BAD_INSTRUCTION: - - if (*((u64 *)thread_state.rip) == 0xffffffffffff0b0f) { - /* Fake sigreturn. See the end of signal_emulation_wrapper() */ - - /* Apply any modifications done to the context, */ - - darwin_mcontext *mcontext = (darwin_mcontext *) thread_state.rax; - - thread_set_state(thread, x86_THREAD_STATE64, - (thread_state_t) &mcontext->ss, thread_state_count); - thread_set_state(thread, float_state_flavor, - (thread_state_t) &mcontext->fs, float_state_count); - goto do_not_handle; - } else if (*((unsigned short *)thread_state.rip) == 0x0b0f) { - signal = SIGTRAP; - rip_offset = 2; - handler = sigtrap_handler; - } else { - signal = SIGILL; - handler = sigill_handler; - } - - break; - case EXC_BREAKPOINT: - if (single_stepping) { - signal = SIGTRAP; - /* Clear TF or the signal emulation wrapper won't proceed - with single stepping enabled. */ - thread_state.rflags &= ~0x100; - handler = sigtrap_handler; - break; - } else if (*(unsigned char*)(thread_state.rip-1) == 0xCC) { - signal = SIGTRAP; - handler = sigtrap_handler; - break; - } - default: - ret = KERN_INVALID_RIGHT; - goto do_not_handle; - } - - backup_thread_state = thread_state; - - /* The ABI has a 128-byte red zone. */ - stack_allocate(th, &thread_state, 128); - - if (will_exhaust_stack(th, &thread_state, - /* Won't be passing much to stack_exhausted_error */ - stack_unprotected ? N_WORD_BYTES*4 : - ALIGN_UP(sizeof(darwin_mcontext) + - N_WORD_BYTES, /* return address */ - N_WORD_BYTES*2)) - || stack_unprotected) { - call_stack_exhausted_in_context(&thread_state); - } else { - - darwin_mcontext *mcontext = stack_allocate(th, &thread_state, sizeof(darwin_mcontext)); - - backup_thread_state.rip += rip_offset; - mcontext->ss = backup_thread_state; - - thread_get_state(thread, float_state_flavor, (thread_state_t) &mcontext->fs, &float_state_count); - - call_signal_emulator_in_context(&thread_state, - mcontext, - signal, - addr, - handler); - } - - thread_set_state(thread, x86_THREAD_STATE64, - (thread_state_t)&thread_state, thread_state_count); - do_not_handle: - - dealloc_ret = mach_port_deallocate (mach_task_self(), thread); - if (dealloc_ret) { - lose("mach_port_deallocate (thread) failed with return_code %d", dealloc_ret); - } - - dealloc_ret = mach_port_deallocate (mach_task_self(), task); - if (dealloc_ret) { - lose("mach_port_deallocate (task) failed with return_code %d", dealloc_ret); - } - - return ret; -} -#endif - void set_thread_stack(void *address) { /* KLUDGE: There is no interface to change the stack location of the initial thread, and without that backtrace(3) returns zero diff --git a/src/runtime/x86-64-darwin-os.h b/src/runtime/x86-64-darwin-os.h index 560858a16d..2d45bd9155 100644 --- a/src/runtime/x86-64-darwin-os.h +++ b/src/runtime/x86-64-darwin-os.h @@ -18,8 +18,10 @@ typedef register_t os_context_register_t; #if __DARWIN_UNIX03 #define CONTEXT_ADDR_FROM_STEM(stem) (os_context_register_t*)&context->uc_mcontext->__ss.__##stem +#define OS_CONTEXT_PC(context) context->uc_mcontext->__ss.__rip #else #define CONTEXT_ADDR_FROM_STEM(stem) &context->uc_mcontext->ss.stem +#define OS_CONTEXT_PC(context) context->uc_mcontext->__ss.rip #endif /* __DARWIN_UNIX03 */ #define RESTORE_FP_CONTROL_FROM_CONTEXT diff --git a/src/runtime/x86-64-haiku-os.c b/src/runtime/x86-64-haiku-os.c index 7b9a42f3be..7d2c183f5f 100644 --- a/src/runtime/x86-64-haiku-os.c +++ b/src/runtime/x86-64-haiku-os.c @@ -1,5 +1,6 @@ #include "os.h" #include "gencgc-alloc-region.h" +#include "thread.h" #include "genesis/thread.h" #include <signal.h> @@ -11,9 +12,6 @@ int arch_os_thread_cleanup(struct thread __attribute__((unused)) *thread) { return 1; } -os_context_register_t *os_context_pc_addr(os_context_t *context) { - return (os_context_register_t *)&context->uc_mcontext.rip; -} os_context_register_t *os_context_sp_addr(os_context_t *context) { return (os_context_register_t *)&context->uc_mcontext.rsp; } @@ -46,10 +44,10 @@ os_restore_fp_control(os_context_t *context) // just guessing here /* reset exception flags and restore control flags on SSE2 FPU */ - unsigned int temp = (context->uc_mcontext.fpu.mxcsr) & ~0x3F; + unsigned int temp = (context->uc_mcontext.fpu.fp_fxsave.mxcsr) & ~0x3F; asm ("ldmxcsr %0" : : "m" (temp)); /* same for x87 FPU. */ - asm ("fldcw %0" : : "m" (context->uc_mcontext.fpu.control)); + asm ("fldcw %0" : : "m" (context->uc_mcontext.fpu.fp_fxsave.control)); } void diff --git a/src/runtime/x86-64-haiku-os.h b/src/runtime/x86-64-haiku-os.h index e798fe4fa8..0fa3ebd32a 100644 --- a/src/runtime/x86-64-haiku-os.h +++ b/src/runtime/x86-64-haiku-os.h @@ -10,4 +10,6 @@ unsigned long os_context_fp_control(os_context_t *context); #define RESTORE_FP_CONTROL_FROM_CONTEXT void os_restore_fp_control(os_context_t *context); +#define OS_CONTEXT_PC(context) context->uc_mcontext.rip + #endif /* _X86_64_HAIKU_OS_H */ diff --git a/src/runtime/x86-64-linux-os.c b/src/runtime/x86-64-linux-os.c index 782f7d6f96..af02151f02 100644 --- a/src/runtime/x86-64-linux-os.c +++ b/src/runtime/x86-64-linux-os.c @@ -34,8 +34,6 @@ #include "interr.h" #include "lispregs.h" #include "sbcl.h" -#include <sys/socket.h> -#include <sys/utsname.h> #include <sys/types.h> #include <signal.h> @@ -52,13 +50,6 @@ int arch_os_thread_init(struct thread *thread) { stack_t sigstack; -#ifdef LISP_FEATURE_SB_THREAD -#ifdef LISP_FEATURE_GCC_TLS - current_thread = thread; -#else - pthread_setspecific(specials,thread); -#endif -#endif #ifdef LISP_FEATURE_C_STACK_IS_CONTROL_STACK /* Signal handlers are run on the control stack, so if it is exhausted * we had better use an alternate stack for whatever signal tells us @@ -71,8 +62,8 @@ int arch_os_thread_init(struct thread *thread) { } #endif #ifdef MEMORY_SANITIZER - asm("movq %%fs:0, %0\n\tleaq __msan_param_tls@TPOFF(%0), %0" - : "=r" (thread->msan_param_tls)); + extern __thread unsigned long __msan_param_tls[]; + ((lispobj*)thread)[THREAD_MSAN_PARAM_TLS_SLOT] = (uword_t)&__msan_param_tls[0]; #endif return 1; } @@ -85,25 +76,73 @@ int arch_os_thread_cleanup(struct thread __attribute__((unused)) *thread) { return 1; } +// This array is indexed by the encoding of the register in an instruction. +static unsigned char regmap[16] = { + REG_RAX, REG_RCX, REG_RDX, REG_RBX, REG_RSP, REG_RBP, REG_RSI, REG_RDI, + REG_R8, REG_R9, REG_R10, REG_R11, REG_R12, REG_R13, REG_R14, REG_R15 +}; +// So is this one, to coincide with the one above +static char *gprnames[] = { + "rax","rcx","rdx","rbx","rsp","rbp","rsi","rdi", + "r8","r9","r10","r11","r12","r13","r14","r15" +}; +static char *fprnames[] = { + "xmm0","xmm1","xmm2","xmm3","xmm4","xmm5","xmm6","xmm7", + "xmm8","xmm9","xmm10","xmm11","xmm12","xmm13","xmm14","xmm15" +}; +static char *flagbits[] = {"CF",0,"PF",0,"AF",0,"ZF","SF","TF","IF","DF","OF"}; + +void sb_dump_mcontext(char *reason, ucontext_t* context) +{ + /* In case multiple threads receive SIGILL at the same time, + * we want to try to avoid interleaving their output. + * Using a single write() call usually does the trick */ + char obuf[2048], smallbuf[100]; + int bit, ptr = 0, i, j; + smallbuf[0] = smallbuf[1] = 0; + long unsigned int flags = context->uc_mcontext.gregs[REG_EFL]; + for (bit=11; bit>=0; --bit) + if (flagbits[bit] && (flags & (1<<bit))) + ptr += sprintf(smallbuf+ptr, " %s", flagbits[bit]); +#define REMAINING sizeof obuf - ptr + ptr = 0; + ptr = snprintf(obuf, REMAINING, + THREAD_ID_LABEL" CPU state (%s): PC=%lx Flags={%s}\n", + THREAD_ID_VALUE, reason, + (uword_t)context->uc_mcontext.gregs[REG_RIP], + smallbuf+1); + // GPRs + for(i=0; i<2; ++i) { + for(j=0; j<8; ++j) ptr += snprintf(obuf+ptr, REMAINING, " %16s", gprnames[i*8+j]); + if (REMAINING) obuf[ptr++] = '\n'; + for(j=0; j<8; ++j) + ptr += snprintf(obuf+ptr, REMAINING, " %16lX", + (uword_t)context->uc_mcontext.gregs[regmap[i*8+j]]); + if (REMAINING) obuf[ptr++] = '\n'; + } + // FPRs + for(i=0; i<4; ++i) { + for(j=0; j<4; ++j) ptr += snprintf(obuf+ptr, REMAINING, " %32s", fprnames[i*4+j]); + if (REMAINING) obuf[ptr++] = '\n'; + for(j=0; j<4; ++j) { + uint32_t* e = context->uc_mcontext.fpregs->_xmm[i*4+j].element; + ptr += snprintf(obuf+ptr, REMAINING, " %08X%08X%08X%08X", e[3], e[2], e[1], e[0]); + } + if (REMAINING) obuf[ptr++] = '\n'; + } + sigset_tostring(&context->uc_sigmask, smallbuf, sizeof smallbuf); + ptr += snprintf(obuf+ptr, REMAINING, "sigmask=%s\n", smallbuf); + write(2, obuf, ptr); +} os_context_register_t * os_context_register_addr(os_context_t *context, int offset) { - static unsigned char regmap[16] = { - REG_RAX, REG_RCX, REG_RDX, REG_RBX, REG_RSP, REG_RBP, REG_RSI, REG_RDI, - REG_R8, REG_R9, REG_R10, REG_R11, REG_R12, REG_R13, REG_R14, REG_R15 - }; if (offset >= 0 && offset < 16) return (os_context_register_t*)&context->uc_mcontext.gregs[regmap[offset]]; return 0; } -os_context_register_t * -os_context_pc_addr(os_context_t *context) -{ - return (os_context_register_t*)&context->uc_mcontext.gregs[REG_RIP]; /* REG_EIP */ -} - os_context_register_t * os_context_sp_addr(os_context_t *context) { @@ -135,7 +174,7 @@ os_context_sigmask_addr(os_context_t *context) return &context->uc_sigmask; } -void +void NO_SANITIZE_ADDRESS os_restore_fp_control(os_context_t *context) { if (context->uc_mcontext.fpregs) { diff --git a/src/runtime/x86-64-linux-os.h b/src/runtime/x86-64-linux-os.h index 4351384a99..6ef1d5a067 100644 --- a/src/runtime/x86-64-linux-os.h +++ b/src/runtime/x86-64-linux-os.h @@ -10,4 +10,6 @@ unsigned long os_context_fp_control(os_context_t *context); #define RESTORE_FP_CONTROL_FROM_CONTEXT void os_restore_fp_control(os_context_t *context); +#define OS_CONTEXT_PC(context) context->uc_mcontext.gregs[REG_RIP] + #endif /* _X86_64_LINUX_OS_H */ diff --git a/src/runtime/x86-64-sunos-os.c b/src/runtime/x86-64-sunos-os.c index bf710a9a0a..1eb464d644 100644 --- a/src/runtime/x86-64-sunos-os.c +++ b/src/runtime/x86-64-sunos-os.c @@ -9,10 +9,6 @@ #include "interrupt.h" #include "interr.h" #include "lispregs.h" -#include <sys/socket.h> -#include <sys/utsname.h> -#include <sys/ucontext.h> -#include <sys/mcontext.h> #include <errno.h> #include <sys/types.h> @@ -26,14 +22,6 @@ int arch_os_thread_init(struct thread *thread) { -#ifdef LISP_FEATURE_SB_THREAD -#ifdef LISP_FEATURE_GCC_TLS - current_thread = thread; -#else - pthread_setspecific(specials,thread); -#endif -#endif - #if defined(LISP_FEATURE_C_STACK_IS_CONTROL_STACK) /* Signal handlers are run on the control stack, so if it is exhausted * we had better use an alternate stack for whatever signal tells us @@ -83,12 +71,6 @@ os_context_register_addr(os_context_t *context, int offset) return &context->uc_mcontext.gregs[offset]; } -os_context_register_t * -os_context_pc_addr(os_context_t *context) -{ - return &context->uc_mcontext.gregs[REG_RIP]; -} - os_context_register_t * os_context_sp_addr(os_context_t *context) { diff --git a/src/runtime/x86-64-sunos-os.h b/src/runtime/x86-64-sunos-os.h index 9cd2541c50..e46c401432 100644 --- a/src/runtime/x86-64-sunos-os.h +++ b/src/runtime/x86-64-sunos-os.h @@ -6,4 +6,6 @@ typedef long os_context_register_t; #include "arch-os-generic.inc" +#define OS_CONTEXT_PC(context) context->uc_mcontext.gregs[REG_RIP] + #endif /* _X86_64_SOLARIS_OS_H */ diff --git a/src/runtime/x86-64-win32-os.c b/src/runtime/x86-64-win32-os.c index 46b9727a29..e9b3828dd1 100644 --- a/src/runtime/x86-64-win32-os.c +++ b/src/runtime/x86-64-win32-os.c @@ -42,7 +42,7 @@ int arch_os_thread_init(struct thread *thread) { - +#ifndef LISP_FEATURE_OS_THREAD_STACK void *cur_stack_end; MEMORY_BASIC_INFORMATION stack_memory; @@ -75,8 +75,6 @@ int arch_os_thread_init(struct thread *thread) #endif -#ifdef LISP_FEATURE_SB_THREAD - pthread_setspecific(specials,thread); #endif return 1; } @@ -122,12 +120,6 @@ os_context_register_addr(os_context_t *context, int offset) ((void*)(context->win32_context)) + offsets[offset] : 0; } -os_context_register_t * -os_context_pc_addr(os_context_t *context) -{ - return (void*)&context->win32_context->Rip; /* REG_EIP */ -} - os_context_register_t * os_context_sp_addr(os_context_t *context) { diff --git a/src/runtime/x86-64-win32-os.h b/src/runtime/x86-64-win32-os.h index d381760d3b..6a5be62f73 100644 --- a/src/runtime/x86-64-win32-os.h +++ b/src/runtime/x86-64-win32-os.h @@ -20,4 +20,6 @@ unsigned long os_context_fp_control(os_context_t *context); void os_restore_fp_control(os_context_t *context); os_context_register_t * os_context_fp_addr(os_context_t *context); +#define OS_CONTEXT_PC(context) context->win32_context->Rip + #endif /* _X86_64_WIN32_OS_H */ diff --git a/src/runtime/x86-arch-shared.inc b/src/runtime/x86-arch-shared.inc new file mode 100644 index 0000000000..6eb47a0c8e --- /dev/null +++ b/src/runtime/x86-arch-shared.inc @@ -0,0 +1,6 @@ +/* -*- Mode: C -*- */ + +void gcbarrier_patch_code(void* where, int nbits) +{ + UNALIGNED_STORE32(where, ((1<<nbits)-1)); +} diff --git a/src/runtime/x86-arch.c b/src/runtime/x86-arch.c index fc2674be98..6cde01b690 100644 --- a/src/runtime/x86-arch.c +++ b/src/runtime/x86-arch.c @@ -23,10 +23,11 @@ #include "interr.h" #include "breakpoint.h" #include "thread.h" -#include "getallocptr.h" +#include "pseudo-atomic.h" #include "forwarding-ptr.h" #include "var-io.h" #include "code.h" +#include "unaligned.h" #include "genesis/static-symbols.h" #include "genesis/symbol.h" @@ -53,7 +54,7 @@ arch_get_bad_addr(int sig, siginfo_t *code, os_context_t *context) */ int * -context_eflags_addr(os_context_t *context) +os_context_flags_addr(os_context_t *context) { #if defined __linux__ /* KLUDGE: As of kernel 2.2.14 on Red Hat 6.2, there's code in the @@ -68,8 +69,6 @@ context_eflags_addr(os_context_t *context) return &context->uc_mcontext.mc_eflags; #elif defined __OpenBSD__ return &context->sc_eflags; -#elif defined LISP_FEATURE_DARWIN - return (int *)(&context->uc_mcontext->SS.EFLAGS); #elif defined __NetBSD__ return &(context->uc_mcontext.__gregs[_REG_EFL]); #elif defined LISP_FEATURE_WIN32 @@ -89,7 +88,7 @@ void arch_skip_instruction(os_context_t *context) int code; /* Get and skip the Lisp interrupt code. */ - code = *(char*)(*os_context_pc_addr(context))++; + code = *(char*)(OS_CONTEXT_PC(context)++); switch (code) { case trap_Error: @@ -118,33 +117,32 @@ void arch_skip_instruction(os_context_t *context) } FSHOW((stderr, - "/[arch_skip_inst resuming at %x]\n", - *os_context_pc_addr(context))); + "/[arch_skip_inst resuming at %x]\n", OS_CONTEXT_PC(context))); } unsigned char * arch_internal_error_arguments(os_context_t *context) { - return 1 + (unsigned char *)(*os_context_pc_addr(context)); + return 1 + (unsigned char *)(OS_CONTEXT_PC(context)); } boolean arch_pseudo_atomic_atomic(os_context_t *context) { - return get_pseudo_atomic_atomic(arch_os_get_current_thread()); + return get_pseudo_atomic_atomic(get_sb_vm_thread()); } void arch_set_pseudo_atomic_interrupted(os_context_t *context) { - struct thread *thread = arch_os_get_current_thread(); + struct thread *thread = get_sb_vm_thread(); set_pseudo_atomic_interrupted(thread); } void arch_clear_pseudo_atomic_interrupted(os_context_t *context) { - struct thread *thread = arch_os_get_current_thread(); + struct thread *thread = get_sb_vm_thread(); clear_pseudo_atomic_interrupted(thread); } @@ -180,7 +178,7 @@ unsigned int single_step_save3; void arch_do_displaced_inst(os_context_t *context, unsigned int orig_inst) { - unsigned int *pc = (unsigned int*)(*os_context_pc_addr(context)); + unsigned int *pc = (unsigned int*)OS_CONTEXT_PC(context); /* Put the original instruction back. */ arch_remove_breakpoint(pc, orig_inst); @@ -195,13 +193,13 @@ arch_do_displaced_inst(os_context_t *context, unsigned int orig_inst) *(pc-2) = 0x00240c81; *(pc-1) = 0x9d000001; #else - *context_eflags_addr(context) |= 0x100; + *os_context_flags_addr(context) |= 0x100; #endif single_stepping = pc; #ifdef CANNOT_GET_TO_SINGLE_STEP_FLAG - *os_context_pc_addr(context) = (os_context_register_t)((char *)pc - 9); + OS_CONTEXT_PC(context) = (os_context_register_t)((char *)pc - 9); #endif } @@ -215,13 +213,11 @@ restore_breakpoint_from_single_step(os_context_t * context) *(single_stepping-2) = single_step_save2; *(single_stepping-1) = single_step_save3; #else - *context_eflags_addr(context) &= ~0x100; + *os_context_flags_addr(context) &= ~0x100; #endif /* Re-install the breakpoint if possible. */ - if (((char *)*os_context_pc_addr(context) > - (char *)single_stepping) && - ((char *)*os_context_pc_addr(context) <= - (char *)single_stepping + BREAKPOINT_WIDTH)) { + if (((char *)OS_CONTEXT_PC(context) > (char *)single_stepping) && + ((char *)OS_CONTEXT_PC(context) <= (char *)single_stepping + BREAKPOINT_WIDTH)) { fprintf(stderr, "warning: couldn't reinstall breakpoint\n"); } else { arch_install_breakpoint(single_stepping); @@ -234,16 +230,15 @@ restore_breakpoint_from_single_step(os_context_t * context) void arch_handle_breakpoint(os_context_t *context) { - *os_context_pc_addr(context) -= BREAKPOINT_WIDTH; + OS_CONTEXT_PC(context) -= BREAKPOINT_WIDTH; handle_breakpoint(context); } void arch_handle_fun_end_breakpoint(os_context_t *context) { - *os_context_pc_addr(context) -= BREAKPOINT_WIDTH; - *os_context_pc_addr(context) = - (int)handle_fun_end_breakpoint(context); + OS_CONTEXT_PC(context) -= BREAKPOINT_WIDTH; + OS_CONTEXT_PC(context) = (int)handle_fun_end_breakpoint(context); } void @@ -268,7 +263,7 @@ sigtrap_handler(int signal, siginfo_t *info, os_context_t *context) /* This is just for info in case the monitor wants to print an * approximation. */ - access_control_stack_pointer(arch_os_get_current_thread()) = + access_control_stack_pointer(get_sb_vm_thread()) = (lispobj *)*os_context_sp_addr(context); #ifdef LISP_FEATURE_SUNOS @@ -286,28 +281,24 @@ sigtrap_handler(int signal, siginfo_t *info, os_context_t *context) * 'kind' value (eg trap_Cerror). For error-trap and Cerror-trap a * number of bytes will follow, the first is the length of the byte * arguments to follow. */ - trap = *(unsigned char *)(*os_context_pc_addr(context)); + trap = *(unsigned char *)OS_CONTEXT_PC(context); handle_trap(context, trap); } void sigill_handler(int signal, siginfo_t *siginfo, os_context_t *context) { -#ifndef LISP_FEATURE_MACH_EXCEPTION_HANDLER - if (*((unsigned short *)*os_context_pc_addr(context)) == UD2_INST) { - *os_context_pc_addr(context) += 2; + if (*(unsigned short *)OS_CONTEXT_PC(context) == UD2_INST) { + OS_CONTEXT_PC(context) += 2; return sigtrap_handler(signal, siginfo, context); } -#endif fake_foreign_function_call(context); - lose("Unhandled SIGILL at %p.", (void*)*os_context_pc_addr(context)); + lose("Unhandled SIGILL at %p.", (void*)OS_CONTEXT_PC(context)); } #endif /* not LISP_FEATURE_WIN32 */ void arch_install_interrupt_handlers() { - SHOW("entering arch_install_interrupt_handlers()"); - /* Note: The old CMU CL code here used sigtrap_handler() to handle * SIGILL as well as SIGTRAP. I couldn't see any reason to do * things that way. So, I changed to separate handlers when @@ -318,74 +309,60 @@ arch_install_interrupt_handlers() * OS I haven't tested on?) and we have to go back to the old CMU * CL way, I hope there will at least be a comment to explain * why.. -- WHN 2001-06-07 */ -#if !defined(LISP_FEATURE_WIN32) && !defined(LISP_FEATURE_MACH_EXCEPTION_HANDLER) - undoably_install_low_level_interrupt_handler(SIGILL , sigill_handler); - undoably_install_low_level_interrupt_handler(SIGTRAP, sigtrap_handler); +#ifndef LISP_FEATURE_WIN32 + ll_install_handler(SIGILL , sigill_handler); + ll_install_handler(SIGTRAP, sigtrap_handler); #endif - SHOW("returning from arch_install_interrupt_handlers()"); } void gencgc_apply_code_fixups(struct code *old_code, struct code *new_code) { - char* code_start_addr = code_text_start(new_code); - os_vm_size_t displacement = (char*)new_code - (char*)old_code; lispobj fixups = new_code->fixups; /* It will be a nonzero integer if valid, or 0 if there are no fixups */ - if (fixups == 0) - return; + if (!fixups) return; /* Could be pointing to a forwarding pointer. */ /* This is extremely unlikely, because the only referent of the fixups - is usually the code itself; so scavenging the vector won't occur + is usually the code itself; so scavenging a bignum of fixups won't occur until after the code object is known to be live. As we're just now enlivening the code, the fixups shouldn't have been forwarded. - Maybe the vector is on the special binding stack though ... */ - if (is_lisp_pointer(fixups) && - forwarding_pointer_p(native_pointer(fixups))) { - /* If so, then follow it. */ - /*SHOW("following pointer to a forwarding pointer");*/ + Maybe the bignum is otherwise referenced though ... */ + if (is_lisp_pointer(fixups) && forwarding_pointer_p(native_pointer(fixups))) fixups = forwarding_pointer_value(native_pointer(fixups)); - } - if (fixnump(fixups) || - (lowtag_of(fixups) == OTHER_POINTER_LOWTAG - && widetag_of(native_pointer(fixups)) == BIGNUM_WIDETAG)) { - /* Got the fixups for the code block. Now work through them - in order, first the absolute ones, then the relative. - Locations are sorted and delta-encoded for compactness. */ - struct varint_unpacker unpacker; - varint_unpacker_init(&unpacker, fixups); - int prev_offset = 0, offset; - // Absolute fixups all refer to this object itself (the code - // boxed constants). Add this object's displacement to the - // value that currently exists at the fixup location. - while (varint_unpack(&unpacker, &offset) && offset != 0) { - offset += prev_offset; - prev_offset = offset; - *(char**)(code_start_addr + offset) += displacement; - } - prev_offset = 0; - // Relative fixups: assembly and foreign routines. Subtract this - // object's displacement from the value that currently exists. - while (varint_unpack(&unpacker, &offset) && offset != 0) { - offset += prev_offset; - prev_offset = offset; - *(char**)(code_start_addr + offset) -= displacement; - } - } else { - /* This used to just print a note to stderr, but bogus fixups seem to - * indicate real heap corruption, so a hard failure is in order. */ - lose("fixup vector %x has a bad widetag: %#x", - fixups, widetag_of(native_pointer(fixups))); + char* code_start_addr = code_text_start(new_code); + os_vm_size_t displacement = (char*)new_code - (char*)old_code; + /* Got the fixups for the code block. Now work through them + in order, first the absolute ones, then the relative. + Locations are sorted and delta-encoded for compactness. */ + struct varint_unpacker unpacker; + varint_unpacker_init(&unpacker, fixups); + int prev_offset = 0, offset; + // Absolute fixups all refer to this object itself (the code + // boxed constants). Add this object's displacement to the + // value that currently exists at the fixup location. + while (varint_unpack(&unpacker, &offset) && offset != 0) { + offset += prev_offset; + prev_offset = offset; + *(char**)(code_start_addr + offset) += displacement; + } + prev_offset = 0; + // Relative fixups: assembly and foreign routines. Subtract this + // object's displacement from the value that currently exists. + while (varint_unpack(&unpacker, &offset) && offset != 0) { + offset += prev_offset; + prev_offset = offset; + *(char**)(code_start_addr + offset) -= displacement; } } void arch_write_linkage_table_entry(int index, void *target_addr, int datap) { - char *reloc_addr = (char*)LINKAGE_TABLE_SPACE_START + index * LINKAGE_TABLE_ENTRY_SIZE; + // 'volatile' works around a spurious GCC warning + volatile char *reloc_addr = (char*)ALIEN_LINKAGE_TABLE_SPACE_START + index * ALIEN_LINKAGE_TABLE_ENTRY_SIZE; if (datap) { *(unsigned long *)reloc_addr = (unsigned long)target_addr; return; @@ -405,3 +382,19 @@ arch_write_linkage_table_entry(int index, void *target_addr, int datap) /* write a nop for good measure. */ *reloc_addr = 0x90; } + +void +*arch_read_linkage_table_entry(int index, int datap) +{ + char *reloc_addr = (char*)ALIEN_LINKAGE_TABLE_SPACE_START + index * ALIEN_LINKAGE_TABLE_ENTRY_SIZE; + if (datap) { + return (unsigned long*) *(unsigned long *)reloc_addr; + } + + long offset = 0; + + offset = reloc_addr[1] + (reloc_addr[2] << 8) + (reloc_addr[3] << 16) + (reloc_addr[4] << 24); + return (void*) (offset + reloc_addr + 5); +} + +#include "x86-arch-shared.inc" diff --git a/src/runtime/x86-arch.h b/src/runtime/x86-arch.h index 3d99035b58..1dc800f6a5 100644 --- a/src/runtime/x86-arch.h +++ b/src/runtime/x86-arch.h @@ -14,10 +14,6 @@ #include "interr.h" /* for declaration of lose() */ #define ARCH_HAS_STACK_POINTER -#define ALIEN_STACK_GROWS_DOWNWARD - -extern void fast_bzero_detect(void *, size_t); -extern void (*fast_bzero_pointer)(void *, size_t); /* When single stepping, single_stepping holds the original instruction * PC location. */ diff --git a/src/runtime/x86-assem.S b/src/runtime/x86-assem.S index 084352caa7..974c1b10ae 100644 --- a/src/runtime/x86-assem.S +++ b/src/runtime/x86-assem.S @@ -19,10 +19,7 @@ #endif #include "sbcl.h" -#include "validate.h" #include "genesis/closure.h" -#include "genesis/funcallable-instance.h" -#include "genesis/fdefn.h" #include "genesis/static-symbols.h" #include "genesis/symbol.h" #include "genesis/thread.h" @@ -54,15 +51,9 @@ */ #if defined(__linux__) || defined(LISP_FEATURE_FREEBSD) || defined(__NetBSD__) || defined(__OpenBSD__) || \ defined(__sun) || defined(LISP_FEATURE_WIN32) || defined(__DragonFly__) -#define align_4byte 4 -#define align_8byte 8 #define align_16byte 16 -#define align_page 4096 #else -#define align_4byte 2 -#define align_8byte 3 #define align_16byte 4 -#define align_page 12 #endif /* @@ -71,7 +62,7 @@ * that are defined to be no-ops on win32. Hopefully this still works on * other platforms. */ -#if !defined(LISP_FEATURE_WIN32) && !defined(LISP_FEATURE_DARWIN) +#if !defined(LISP_FEATURE_WIN32) #define TYPE(name) .type name,@function #define SIZE(name) .size name,.-name #else @@ -165,7 +156,11 @@ /* the CSP page sits right before the thread */ #define THREAD_SAVED_CSP_OFFSET (-N_WORD_BYTES) +#ifdef LISP_FEATURE_UD2_BREAKPOINTS +#define TRAP ud2 +#else #define TRAP int3 +#endif .text .globl GNAME(all_threads) @@ -322,7 +317,7 @@ Lfp_rtn_value: SIZE(GNAME(call_into_c)) -#ifdef OS_THREAD_STACK +#ifdef LISP_FEATURE_OS_THREAD_STACK .text .globl GNAME(funcall1_switching_stack) TYPE(GNAME(funcall1_switching_stack)) @@ -619,56 +614,6 @@ GNAME(exception_handler_wrapper): SIZE(GNAME(exception_handler_wrapper)) #endif -#ifdef LISP_FEATURE_DARWIN - .align align_16byte - .globl GNAME(call_into_lisp_tramp) - TYPE(GNAME(call_into_lisp_tramp)) -GNAME(call_into_lisp_tramp): - /* 1. build the stack frame from the block that's pointed to by ECX - 2. free the block - 3. set ECX to 0 - 4. call the function via call_into_lisp - */ - pushl 0(%ecx) /* return address */ - - pushl %ebp - movl %esp, %ebp - - pushl 32(%ecx) /* eflags */ - pushl 28(%ecx) /* EAX */ - pushl 20(%ecx) /* ECX */ - pushl 16(%ecx) /* EDX */ - pushl 24(%ecx) /* EBX */ - pushl $0 /* popal is going to ignore esp */ - pushl %ebp /* is this right?? */ - pushl 12(%ecx) /* ESI */ - pushl 8(%ecx) /* EDI */ - pushl $0 /* args for call_into_lisp */ - pushl $0 - pushl 4(%ecx) /* function to call */ - - /* free our save block */ - pushl %ecx /* reserve sufficient space on stack for args */ - pushl %ecx - andl $0xfffffff0, %esp /* align stack */ - movl $0x40, 4(%esp) - movl %ecx, (%esp) - call GNAME(os_invalidate) - - /* call call_into_lisp */ - leal -48(%ebp), %esp - call GNAME(call_into_lisp) - - /* Clean up our mess */ - leal -36(%ebp), %esp - popal - popfl - leave - ret - - SIZE(call_into_lisp_tramp) -#endif - .align align_16byte,0x90 .globl GNAME(post_signal_tramp) TYPE(GNAME(post_signal_tramp)) @@ -679,151 +624,10 @@ GNAME(post_signal_tramp): addl $12,%esp /* clear call_into_lisp args from stack */ popal /* restore registers */ popfl -#ifdef LISP_FEATURE_DARWIN - /* skip two padding words */ - addl $8,%esp -#endif leave ret SIZE(GNAME(post_signal_tramp)) - - /* fast_bzero implementations and code to detect which implementation - * to use. - */ - - .globl GNAME(fast_bzero_pointer) - .data - .align align_16byte -GNAME(fast_bzero_pointer): - /* Variable containing a pointer to the bzero function to use. - * Initially points to a basic function. Change this variable - * to fast_bzero_detect if OS supports SSE. */ - .long GNAME(fast_bzero_base) - - .text - .align align_16byte,0x90 - .globl GNAME(fast_bzero) - TYPE(GNAME(fast_bzero)) -GNAME(fast_bzero): - /* Indirect function call */ - jmp *GNAME(fast_bzero_pointer) - SIZE(GNAME(fast_bzero)) - - - .text - .align align_16byte,0x90 - .globl GNAME(fast_bzero_detect) - TYPE(GNAME(fast_bzero_detect)) -GNAME(fast_bzero_detect): - /* Decide whether to use SSE, MMX or REP version */ - push %eax /* CPUID uses EAX-EDX */ - push %ebx - push %ecx - push %edx - mov $1, %eax - cpuid - test $0x04000000, %edx /* SSE2 needed for MOVNTDQ */ - jnz Lsse2 - /* Originally there was another case here for using the - * MOVNTQ instruction for processors that supported MMX but - * not SSE2. This turned out to be a loss especially on - * Athlons (where this instruction is apparently microcoded - * somewhat slowly). So for simplicity revert to REP STOSL - * for all non-SSE2 processors. - */ -Lbase: - movl $(GNAME(fast_bzero_base)), GNAME(fast_bzero_pointer) - jmp Lrestore -Lsse2: - movl $(GNAME(fast_bzero_sse)), GNAME(fast_bzero_pointer) - jmp Lrestore - -Lrestore: - pop %edx - pop %ecx - pop %ebx - pop %eax - jmp *GNAME(fast_bzero_pointer) - - SIZE(GNAME(fast_bzero_detect)) - - - .text - .align align_16byte,0x90 - .globl GNAME(fast_bzero_sse) - TYPE(GNAME(fast_bzero_sse)) - -GNAME(fast_bzero_sse): - /* A fast routine for zero-filling blocks of memory that are - * guaranteed to start and end at a 4096-byte aligned address. - */ - push %esi /* Save temporary registers */ - push %edi - mov 16(%esp), %esi /* Parameter: amount of bytes to fill */ - mov 12(%esp), %edi /* Parameter: start address */ - shr $6, %esi /* Amount of 64-byte blocks to copy */ - jz Lend_sse /* If none, stop */ - movups %xmm7, -16(%esp) /* Save XMM register */ - xorps %xmm7, %xmm7 /* Zero the XMM register */ - jmp Lloop_sse - .align align_16byte -Lloop_sse: - - /* Copy the 16 zeroes from xmm7 to memory, 4 times. MOVNTDQ is the - * non-caching double-quadword moving variant, i.e. the memory areas - * we're touching are not fetched into the L1 cache, since we're just - * going to overwrite the memory soon anyway. - */ - movntdq %xmm7, 0(%edi) - movntdq %xmm7, 16(%edi) - movntdq %xmm7, 32(%edi) - movntdq %xmm7, 48(%edi) - - add $64, %edi /* Advance pointer */ - dec %esi /* Decrement 64-byte block count */ - jnz Lloop_sse - movups -16(%esp), %xmm7 /* Restore the XMM register */ - sfence /* Ensure that weakly ordered writes are flushed. */ -Lend_sse: - mov 12(%esp), %esi /* Parameter: start address */ - prefetcht0 0(%esi) /* Prefetch the start of the block into cache, - * since it's likely to be used immediately. */ - pop %edi /* Restore temp registers */ - pop %esi - ret - SIZE(GNAME(fast_bzero_sse)) - - - .text - .align align_16byte,0x90 - .globl GNAME(fast_bzero_base) - TYPE(GNAME(fast_bzero_base)) - -GNAME(fast_bzero_base): - /* A fast routine for zero-filling blocks of memory that are - * guaranteed to start and end at a 4096-byte aligned address. - */ - push %eax /* Save temporary registers */ - push %ecx - push %edi - mov 20(%esp), %ecx /* Parameter: amount of bytes to fill */ - mov 16(%esp), %edi /* Parameter: start address */ - xor %eax, %eax /* Zero EAX */ - shr $2, %ecx /* Amount of 4-byte blocks to copy */ - jz Lend_base - - rep - stosl /* Store EAX to *EDI, ECX times, incrementing - * EDI by 4 after each store */ - -Lend_base: - pop %edi /* Restore temp registers */ - pop %ecx - pop %eax - ret - SIZE(GNAME(fast_bzero_base)) - /* When LISP_FEATURE_C_STACK_IS_CONTROL_STACK, we cannot safely scrub * the control stack from C, largely due to not knowing where the @@ -847,7 +651,7 @@ GNAME(arch_scrub_control_stack): * guard page upper bound in ECX, and our hard guard * page upper bound in EDX. */ lea -4(%esp), %eax - mov GNAME(os_vm_page_size),%edx + mov $BACKEND_PAGE_BYTES,%edx mov %edx, %ecx add 8(%esp), %ecx add 12(%esp), %edx @@ -873,7 +677,8 @@ ascs_check_guard_page: jae ascs_clear_loop cmp 8(%esp), %eax jbe ascs_clear_loop - cmpl $(NIL), THREAD_CONTROL_STACK_GUARD_PAGE_PROTECTED_OFFSET(%ecx) + /* test state_word.control_stack_guard_page_protected */ + cmpb $0, THREAD_STATE_WORD_OFFSET(%ecx) jne ascs_finished /* Clear memory backwards to the start of the (4KiB) page */ diff --git a/src/runtime/x86-bsd-os.c b/src/runtime/x86-bsd-os.c index 2c39acd17f..0597ee7eb9 100644 --- a/src/runtime/x86-bsd-os.c +++ b/src/runtime/x86-bsd-os.c @@ -6,14 +6,8 @@ #ifdef LISP_FEATURE_SB_THREAD -#ifdef LISP_FEATURE_DARWIN -#include <architecture/i386/table.h> -#include <i386/user_ldt.h> -#include <mach/mach_init.h> -#else #include <machine/segments.h> #include <machine/sysarch.h> -#endif /* LISP_FEATURE_DARWIN */ #endif #if defined(LISP_FEATURE_FREEBSD) || defined(LISP_FEATURE_DRAGONFLY) @@ -34,13 +28,9 @@ * almost every line of code. It would be nice to find some way to * factor out the commonality better; failing that, it might be best * just to split this generic-BSD code into one variant for each BSD. - * - * KLUDGE II: this split has begun with the addition of the Darwin BSD - * flavour, with the cross-architecture complications that this - * entails; unfortunately, currently the situation is worse, not - * better, than in the above paragraph. */ + */ -#if defined(LISP_FEATURE_FREEBSD) || defined(__OpenBSD__) || defined(LISP_FEATURE_DARWIN) || defined(__DragonFly__) +#if defined(LISP_FEATURE_FREEBSD) || defined(__OpenBSD__) || defined(__DragonFly__) int * os_context_register_addr(os_context_t *context, int offset) { @@ -116,23 +106,6 @@ os_context_sp_addr(os_context_t *context) #endif /* __NetBSD__ */ -int *os_context_pc_addr(os_context_t *context) -{ -#if defined(LISP_FEATURE_FREEBSD) || defined(__DragonFly__) - return CONTEXT_ADDR_FROM_STEM(eip); -#elif defined __OpenBSD__ - return CONTEXT_ADDR_FROM_STEM(pc); -#elif defined __NetBSD__ - return CONTEXT_ADDR_FROM_STEM(EIP); -#elif defined(LISP_FEATURE_DARWIN) && defined(LISP_FEATURE_X86) - return (int *)CONTEXT_ADDR_FROM_STEM(eip); -#elif defined LISP_FEATURE_DARWIN - return &context->uc_mcontext->ss.srr0; -#else -#error unsupported BSD variant -#endif -} - /* FIXME: If this can be a no-op on BSD/x86, then it * deserves a more precise name. * @@ -142,11 +115,6 @@ os_flush_icache(os_vm_address_t address, os_vm_size_t length) { } -/* Note: the Darwin versions of arch_os_thread_init found in - * x86-darwin-os.c -*/ -#if !defined(LISP_FEATURE_DARWIN) - #ifdef LISP_FEATURE_SB_THREAD void set_data_desc_size(struct segment_descriptor* desc, unsigned long size) @@ -161,9 +129,6 @@ void set_data_desc_addr(struct segment_descriptor* desc, void* addr) desc->sd_hibase = ((unsigned int)addr & 0xff000000) >> 24; } -#endif - -#ifdef LISP_FEATURE_SB_THREAD void arch_os_load_ldt(struct thread *thread) { @@ -193,17 +158,9 @@ int arch_os_thread_init(struct thread *thread) { perror("i386_set_ldt"); lose("unexpected i386_set_ldt(..) failure"); } - FSHOW_SIGNAL((stderr, "/ TLS: Allocated LDT %x\n", n)); thread->tls_cookie=n; arch_os_load_ldt(thread); - -#ifdef LISP_FEATURE_GCC_TLS - current_thread = thread; -#else - pthread_setspecific(specials,thread); #endif -#endif - #ifdef LISP_FEATURE_C_STACK_IS_CONTROL_STACK stack_t sigstack; @@ -228,8 +185,6 @@ int arch_os_thread_cleanup(struct thread *thread) { /* Set the %%fs register back to 0 and free the ldt by setting it * to NULL. */ - FSHOW_SIGNAL((stderr, "/ TLS: Freeing LDT %x\n", n)); - __asm__ __volatile__ ("mov %0, %%fs" : : "r"(0)); i386_set_ldt(n, NULL, 1); #endif @@ -237,7 +192,6 @@ int arch_os_thread_cleanup(struct thread *thread) { return 1; /* success */ } -#endif /* !LISP_FEATURE_DARWIN */ #if defined(LISP_FEATURE_FREEBSD) #if defined(LISP_FEATURE_RESTORE_TLS_SEGMENT_REGISTER_FROM_CONTEXT) diff --git a/src/runtime/x86-bsd-os.h b/src/runtime/x86-bsd-os.h index 9aea4f93cf..30cdb80b06 100644 --- a/src/runtime/x86-bsd-os.h +++ b/src/runtime/x86-bsd-os.h @@ -15,15 +15,19 @@ typedef int os_context_register_t; * same stems to name the structure fields, so by using this macro we * can share a fair amount of code between different variants. */ #if defined(LISP_FEATURE_FREEBSD) || defined(__DragonFly__) -#define CONTEXT_ADDR_FROM_STEM(stem) &context->uc_mcontext.mc_ ## stem +#define CONTEXT_SLOT(c,stem) c->uc_mcontext.mc_ ## stem #elif defined(__OpenBSD__) -#define CONTEXT_ADDR_FROM_STEM(stem) &context->sc_ ## stem +#define CONTEXT_SLOT(c,stem) c->sc_ ## stem #elif defined __NetBSD__ -#define CONTEXT_ADDR_FROM_STEM(stem) &((context)->uc_mcontext.__gregs[_REG_ ## stem]) +#define CONTEXT_SLOT(c,stem) ((c)->uc_mcontext.__gregs[_REG_ ## stem]) #else #error unsupported BSD variant #endif +// "&" binds weaker than {->,.,[]} so this does what we want +// Note that this macro is unhygienic. +#define CONTEXT_ADDR_FROM_STEM(stem) &CONTEXT_SLOT(context,stem) + #if defined LISP_FEATURE_FREEBSD #if defined(LISP_FEATURE_RESTORE_TLS_SEGMENT_REGISTER_FROM_CONTEXT) void os_restore_tls_segment_register(os_context_t *context); @@ -37,4 +41,14 @@ void os_restore_fp_control(os_context_t *context); void os_restore_fp_control(os_context_t *context); #endif +#if defined LISP_FEATURE_FREEBSD || defined __DragonFly__ +# define OS_CONTEXT_PC(context) CONTEXT_SLOT(context,eip) +#elif defined __OpenBSD__ +# define OS_CONTEXT_PC(context) CONTEXT_SLOT(context,pc) +#elif defined __NetBSD__ +# define OS_CONTEXT_PC(context) CONTEXT_SLOT(context,EIP) +#else +# error "unsupported BSD variant" +#endif + #endif /* _X86_BSD_OS_H */ diff --git a/src/runtime/x86-darwin-os.c b/src/runtime/x86-darwin-os.c deleted file mode 100644 index da56868218..0000000000 --- a/src/runtime/x86-darwin-os.c +++ /dev/null @@ -1,534 +0,0 @@ -#ifdef LISP_FEATURE_SB_THREAD -#include <architecture/i386/table.h> -#include <i386/user_ldt.h> -#include <mach/mach_init.h> -#endif - -#include "thread.h" -#include "validate.h" -#include "runtime.h" -#include "interrupt.h" -#include "x86-darwin-os.h" -#include "genesis/fdefn.h" -#include "gc-internal.h" // for gencgc_handle_wp_violation - -#include <mach/mach.h> -#include <mach/mach_error.h> -#include <mach/mach_types.h> -#include <mach/sync_policy.h> -#include <mach/vm_region.h> -#include <mach/machine/thread_state.h> -#include <mach/machine/thread_status.h> -#include <sys/_types.h> -#include <sys/ucontext.h> -#include <pthread.h> -#include <assert.h> -#include <stdlib.h> -#include <stdio.h> - -#ifdef LISP_FEATURE_SB_THREAD - -pthread_mutex_t modify_ldt_lock = PTHREAD_MUTEX_INITIALIZER; - -void set_data_desc_size(data_desc_t* desc, unsigned long size) -{ - desc->limit00 = (size - 1) & 0xffff; - desc->limit16 = ((size - 1) >> 16) &0xf; -} - -void set_data_desc_addr(data_desc_t* desc, void* addr) -{ - desc->base00 = (unsigned int)addr & 0xffff; - desc->base16 = ((unsigned int)addr & 0xff0000) >> 16; - desc->base24 = ((unsigned int)addr & 0xff000000) >> 24; -} - -#endif - -#ifdef LISP_FEATURE_SB_THREAD -void -arch_os_load_ldt(struct thread *thread) -{ - sel_t sel; - - sel.index = thread->tls_cookie; - sel.rpl = USER_PRIV; - sel.ti = SEL_LDT; - - __asm__ __volatile__ ("mov %0, %%fs" : : "r"(sel)); -} -#endif - -int arch_os_thread_init(struct thread *thread) { -#ifdef LISP_FEATURE_SB_THREAD - int n; - - data_desc_t ldt_entry = { 0, 0, 0, DESC_DATA_WRITE, - 3, 1, 0, DESC_DATA_32B, DESC_GRAN_BYTE, 0 }; - - set_data_desc_addr(&ldt_entry, thread); - set_data_desc_size(&ldt_entry, dynamic_values_bytes); - - thread_mutex_lock(&modify_ldt_lock); - n = i386_set_ldt(LDT_AUTO_ALLOC, (union ldt_entry*) &ldt_entry, 1); - - if (n < 0) { - perror("i386_set_ldt"); - lose("unexpected i386_set_ldt(..) failure"); - } - thread_mutex_unlock(&modify_ldt_lock); - - FSHOW_SIGNAL((stderr, "/ TLS: Allocated LDT %x\n", n)); - thread->tls_cookie=n; - arch_os_load_ldt(thread); - - pthread_setspecific(specials,thread); -#endif -#ifdef LISP_FEATURE_MACH_EXCEPTION_HANDLER - mach_lisp_thread_init(thread); -#elif defined(LISP_FEATURE_C_STACK_IS_CONTROL_STACK) - stack_t sigstack; - - /* Signal handlers are run on the control stack, so if it is exhausted - * we had better use an alternate stack for whatever signal tells us - * we've exhausted it */ - sigstack.ss_sp = calc_altstack_base(thread); - sigstack.ss_flags = 0; - sigstack.ss_size = calc_altstack_size(thread; - sigaltstack(&sigstack,0); -#endif - return 1; /* success */ -} - -int arch_os_thread_cleanup(struct thread *thread) { -#if defined(LISP_FEATURE_SB_THREAD) - int n = thread->tls_cookie; - - /* Set the %%fs register back to 0 and free the ldt by setting it - * to NULL. - */ - FSHOW_SIGNAL((stderr, "/ TLS: Freeing LDT %x\n", n)); - - __asm__ __volatile__ ("mov %0, %%fs" : : "r"(0)); - thread_mutex_lock(&modify_ldt_lock); - i386_set_ldt(n, NULL, 1); - thread_mutex_unlock(&modify_ldt_lock); -#endif - return 1; /* success */ -} - -#ifdef LISP_FEATURE_MACH_EXCEPTION_HANDLER - -void sigill_handler(int signal, siginfo_t *siginfo, os_context_t *context); -void sigtrap_handler(int signal, siginfo_t *siginfo, os_context_t *context); -void memory_fault_handler(int signal, siginfo_t *siginfo, - os_context_t *context); - -/* This executes in the faulting thread as part of the signal - * emulation. It is passed a context with the uc_mcontext field - * pointing to a valid block of memory. */ -void build_fake_signal_context(os_context_t *context, - x86_thread_state32_t *thread_state, - x86_float_state32_t *float_state) { - thread_sigmask(0, NULL, &context->uc_sigmask); - context->uc_mcontext->SS = *thread_state; - context->uc_mcontext->FS = *float_state; -} - -/* This executes in the faulting thread as part of the signal - * emulation. It is effectively the inverse operation from above. */ -void update_thread_state_from_context(x86_thread_state32_t *thread_state, - x86_float_state32_t *float_state, - os_context_t *context) { - *thread_state = context->uc_mcontext->SS; - *float_state = context->uc_mcontext->FS; - thread_sigmask(SIG_SETMASK, &context->uc_sigmask, NULL); -} - -/* Modify a context to push new data on its stack. */ -void push_context(u32 data, x86_thread_state32_t *thread_state) -{ - u32 *stack_pointer; - - stack_pointer = (u32*) thread_state->ESP; - *(--stack_pointer) = data; - thread_state->ESP = (unsigned int) stack_pointer; -} - -void align_context_stack(x86_thread_state32_t *thread_state) -{ - /* 16byte align the stack (provided that the stack is, as it - * should be, 4byte aligned. */ - while (thread_state->ESP & 15) push_context(0, thread_state); -} - -/* Stack allocation starts with a context that has a mod-4 ESP value - * and needs to leave a context with a mod-16 ESP that will restore - * the old ESP value and other register state when activated. The - * first part of this is the recovery trampoline, which loads ESP from - * EBP, pops EBP, and returns. */ -asm("_stack_allocation_recover: movl %ebp, %esp; popl %ebp; ret;"); - -void open_stack_allocation(x86_thread_state32_t *thread_state) -{ - void stack_allocation_recover(void); - - push_context(thread_state->EIP, thread_state); - push_context(thread_state->EBP, thread_state); - thread_state->EBP = thread_state->ESP; - thread_state->EIP = (unsigned int) stack_allocation_recover; - - align_context_stack(thread_state); -} - -/* Stack allocation of data starts with a context with a mod-16 ESP - * value and reserves some space on it by manipulating the ESP - * register. */ -void *stack_allocate(x86_thread_state32_t *thread_state, size_t size) -{ - /* round up size to 16byte multiple */ - size = (size + 15) & -16; - - thread_state->ESP = ((u32)thread_state->ESP) - size; - - return (void *)thread_state->ESP; -} - -/* Arranging to invoke a C function is tricky, as we have to assume - * cdecl calling conventions (caller removes args) and x86/darwin - * alignment requirements. The simplest way to arrange this, - * actually, is to open a new stack allocation. - * WARNING!!! THIS DOES NOT PRESERVE REGISTERS! */ -void call_c_function_in_context(x86_thread_state32_t *thread_state, - void *function, - int nargs, - ...) -{ - va_list ap; - int i; - u32 *stack_pointer; - - /* Set up to restore stack on exit. */ - open_stack_allocation(thread_state); - - /* Have to keep stack 16byte aligned on x86/darwin. */ - for (i = (3 & -nargs); i; i--) { - push_context(0, thread_state); - } - - thread_state->ESP = ((u32)thread_state->ESP) - nargs * 4; - stack_pointer = (u32 *)thread_state->ESP; - - va_start(ap, nargs); - for (i = 0; i < nargs; i++) { - //push_context(va_arg(ap, u32), thread_state); - stack_pointer[i] = va_arg(ap, u32); - } - va_end(ap); - - push_context(thread_state->EIP, thread_state); - thread_state->EIP = (unsigned int) function; -} - -void signal_emulation_wrapper(x86_thread_state32_t *thread_state, - x86_float_state32_t *float_state, - int signal, - siginfo_t *siginfo, - void (*handler)(int, siginfo_t *, void *)) -{ - - os_context_t context; - _STRUCT_MCONTEXT32 regs; - - context.uc_mcontext = ®s; - - /* when BSD signals are fired, they mask they signals in sa_mask - which always seem to be the blockable_sigset, for us, so we - need to: - 1) save the current sigmask - 2) block blockable signals - 3) call the signal handler - 4) restore the sigmask */ - build_fake_signal_context(&context, thread_state, float_state); - - block_blockable_signals(0); - - handler(signal, siginfo, &context); - - update_thread_state_from_context(thread_state, float_state, &context); - - /* Trap to restore the signal context. */ - asm volatile (".long 0xffff0b0f" - : : "a" (thread_state), "c" (float_state)); -} - -/* Convenience wrapper for the above */ -void call_handler_on_thread(mach_port_t thread, - x86_thread_state32_t *thread_state, - int signal, - siginfo_t *siginfo, - void (*handler)(int, siginfo_t *, os_context_t *)) -{ - x86_thread_state32_t new_state; - x86_thread_state32_t *save_thread_state; - x86_float_state32_t *save_float_state; - mach_msg_type_number_t state_count; - siginfo_t *save_siginfo; - kern_return_t ret; - /* Initialize the new state */ - new_state = *thread_state; - open_stack_allocation(&new_state); - stack_allocate(&new_state, 256); - /* Save old state */ - save_thread_state = (x86_thread_state32_t *)stack_allocate(&new_state, sizeof(*save_thread_state)); - *save_thread_state = *thread_state; - /* Save float state */ - save_float_state = (x86_float_state32_t *)stack_allocate(&new_state, sizeof(*save_float_state)); - state_count = x86_FLOAT_STATE32_COUNT; - if ((ret = thread_get_state(thread, - x86_FLOAT_STATE32, - (thread_state_t)save_float_state, - &state_count)) != KERN_SUCCESS) - lose("thread_get_state (x86_THREAD_STATE32) failed %d", ret); - /* Set up siginfo */ - save_siginfo = stack_allocate(&new_state, sizeof(*siginfo)); - if (siginfo == NULL) - save_siginfo = siginfo; - else - *save_siginfo = *siginfo; - /* Prepare to call */ - call_c_function_in_context(&new_state, - signal_emulation_wrapper, - 5, - save_thread_state, - save_float_state, - signal, - save_siginfo, - handler); - /* Update the thread state */ - state_count = x86_THREAD_STATE32_COUNT; - if ((ret = thread_set_state(thread, - x86_THREAD_STATE32, - (thread_state_t)&new_state, - state_count)) != KERN_SUCCESS) - lose("thread_set_state (x86_FLOAT_STATE32) failed %d", ret); - -} - -#if defined DUMP_CONTEXT -void dump_context(x86_thread_state32_t *thread_state) -{ - int i; - u32 *stack_pointer; - - printf("eax: %08lx ecx: %08lx edx: %08lx ebx: %08lx\n", - thread_state->EAX, thread_state->ECX, thread_state->EDX, thread_state->EAX); - printf("esp: %08lx ebp: %08lx esi: %08lx edi: %08lx\n", - thread_state->ESP, thread_state->EBP, thread_state->ESI, thread_state->EDI); - printf("eip: %08lx eflags: %08lx\n", - thread_state->EIP, thread_state->EFLAGS); - printf("cs: %04hx ds: %04hx es: %04hx " - "ss: %04hx fs: %04hx gs: %04hx\n", - thread_state->CS, - thread_state->DS, - thread_state->ES, - thread_state->SS, - thread_state->FS, - thread_state->GS); - - stack_pointer = (u32 *)thread_state->ESP; - for (i = 0; i < 48; i+=4) { - printf("%08x: %08x %08x %08x %08x\n", - thread_state->ESP + (i * 4), - stack_pointer[i], - stack_pointer[i+1], - stack_pointer[i+2], - stack_pointer[i+3]); - } -} -#endif - -void -control_stack_exhausted_handler(int signal, siginfo_t *siginfo, - os_context_t *context) { - extern void unblock_signals_in_context_and_maybe_warn(os_context_t*); - unblock_signals_in_context_and_maybe_warn(context); - arrange_return_to_lisp_function - (context, StaticSymbolFunction(CONTROL_STACK_EXHAUSTED_ERROR)); -} - -void -undefined_alien_handler(int signal, siginfo_t *siginfo, os_context_t *context) { - arrange_return_to_lisp_function - (context, StaticSymbolFunction(UNDEFINED_ALIEN_VARIABLE_ERROR)); -} - -kern_return_t -catch_exception_raise(mach_port_t exception_port, - mach_port_t thread, - mach_port_t task, - exception_type_t exception, - exception_data_t code_vector, - mach_msg_type_number_t code_count) -{ - x86_thread_state32_t thread_state; - mach_msg_type_number_t state_count; - void *addr = NULL; - int signal = 0; - void (*handler)(int, siginfo_t *, os_context_t *) = NULL; - siginfo_t siginfo; - kern_return_t ret = KERN_SUCCESS, dealloc_ret; - - struct thread *th; - - FSHOW((stderr,"/entering catch_exception_raise with exception: %d\n", exception)); - - if (mach_port_get_context(mach_task_self(), exception_port, (mach_vm_address_t *)&th) - != KERN_SUCCESS) { - lose("Can't find the thread for an exception %u", exception_port); - } - - /* Get state and info */ - state_count = x86_THREAD_STATE32_COUNT; - if ((ret = thread_get_state(thread, - x86_THREAD_STATE32, - (thread_state_t)&thread_state, - &state_count)) != KERN_SUCCESS) - lose("thread_get_state (x86_THREAD_STATE32) failed %d", ret); - switch (exception) { - case EXC_BAD_ACCESS: - signal = SIGBUS; - /* Check if write protection fault */ - if ((code_vector[0] & OS_VM_PROT_ALL) == 0) { - ret = KERN_INVALID_RIGHT; - break; - } - addr = (void*)code_vector[1]; - /* Just need to unprotect the page and do some bookkeeping, no need - * to run it from the faulting thread. - * And because the GC uses signals to stop the world it might - * interfere with that bookkeeping, because there's a window - * before block_blockable_signals is performed. */ - if (gencgc_handle_wp_violation(addr)) - goto do_not_handle; - - /* Undefined alien */ - if (os_trunc_to_page(addr) == undefined_alien_address) { - handler = undefined_alien_handler; - break; - } - /* At stack guard */ - if (os_trunc_to_page(addr) == CONTROL_STACK_GUARD_PAGE(th)) { - lower_thread_control_stack_guard_page(th); - handler = control_stack_exhausted_handler; - break; - } - /* Return from stack guard */ - if (os_trunc_to_page(addr) == CONTROL_STACK_RETURN_GUARD_PAGE(th)) { - reset_thread_control_stack_guard_page(th); - break; - } - /* Regular memory fault */ - handler = memory_fault_handler; - break; - case EXC_BAD_INSTRUCTION: - signal = SIGTRAP; - /* Check if illegal instruction trap */ - if (code_vector[0] != EXC_I386_INVOP) { - ret = KERN_INVALID_RIGHT; - break; - } - /* Check if UD2 instruction */ - if (*(unsigned short *)thread_state.EIP != 0x0b0f) { - /* KLUDGE: There are two ways we could get here: - * 1) We're executing data and we've hit some truly - * illegal opcode, of which there are a few, see - * Intel 64 and IA-32 Architectures - * Sofware Developer's Manual - * Volume 3A page 5-34) - * 2) The kernel started an unrelated signal handler - * before we got a chance to run. The context that - * caused the exception is saved in a stack frame - * somewhere down below. - * In either case we rely on the exception to retrigger, - * eventually bailing out if we're spinning on case 2). - */ - static mach_port_t last_thread; - static unsigned int last_eip; - if (last_thread == thread && last_eip == thread_state.EIP) - ret = KERN_INVALID_RIGHT; - else - ret = KERN_SUCCESS; - last_thread = thread; - last_eip = thread_state.EIP; - break; - } - /* Skip the trap code */ - thread_state.EIP += 2; - /* Return from handler? */ - if (*(unsigned short *)thread_state.EIP == 0xffff) { - if ((ret = thread_set_state(thread, - x86_THREAD_STATE32, - (thread_state_t)thread_state.EAX, - x86_THREAD_STATE32_COUNT)) != KERN_SUCCESS) - lose("thread_set_state (x86_THREAD_STATE32) failed %d", ret); - if ((ret = thread_set_state(thread, - x86_FLOAT_STATE32, - (thread_state_t)thread_state.ECX, - x86_FLOAT_STATE32_COUNT)) != KERN_SUCCESS) - lose("thread_set_state (x86_FLOAT_STATE32) failed %d", ret); - break; - } - /* Trap call */ - handler = sigtrap_handler; - break; - case EXC_BREAKPOINT: - if (single_stepping) { - signal = SIGTRAP; - /* Clear TF or the signal emulation wrapper won't proceed - with single stepping enabled. */ - thread_state.EFLAGS &= ~0x100; - handler = sigtrap_handler; - break; - } else if (*(unsigned char*)(thread_state.EIP-1) == 0xCC) { - signal = SIGTRAP; - handler = sigtrap_handler; - break; - } - default: - ret = KERN_INVALID_RIGHT; - } - /* Call handler */ - if (handler != 0) { - siginfo.si_signo = signal; - siginfo.si_addr = addr; - call_handler_on_thread(thread, &thread_state, signal, &siginfo, handler); - } - - do_not_handle: - dealloc_ret = mach_port_deallocate (mach_task_self(), thread); - if (dealloc_ret) { - lose("mach_port_deallocate (thread) failed with return_code %d", dealloc_ret); - } - - dealloc_ret = mach_port_deallocate (mach_task_self(), task); - if (dealloc_ret) { - lose("mach_port_deallocate (task) failed with return_code %d", dealloc_ret); - } - - return ret; -} - -void -os_restore_fp_control(os_context_t *context) -{ - /* KLUDGE: The x87 FPU control word is some nasty bitfield struct - * thing. Rather than deal with that, just grab it as a 16-bit - * integer. */ - unsigned short fpu_control_word = - *((unsigned short *)&context->uc_mcontext->FS.FPU_FCW); - /* reset exception flags and restore control flags on x87 FPU */ - asm ("fldcw %0" : : "m" (fpu_control_word)); -} - -#endif diff --git a/src/runtime/x86-darwin-os.h b/src/runtime/x86-darwin-os.h deleted file mode 100644 index 7ff303b967..0000000000 --- a/src/runtime/x86-darwin-os.h +++ /dev/null @@ -1,69 +0,0 @@ -#ifndef _X86_DARWIN_OS_H -#define _X86_DARWIN_OS_H - -#include <architecture/i386/table.h> -#include <i386/user_ldt.h> - -#include "darwin-os.h" - -typedef int os_context_register_t; - -#include "arch-os-generic.inc" - -void set_data_desc_size(data_desc_t* desc, unsigned long size); -void set_data_desc_addr(data_desc_t* desc, void* addr); - -/* On OS X 10.5, the field names for the thread state have changed and - * now are prepended with __. Use some #define hackery to deal with - * this. - */ -#if __DARWIN_UNIX03 - -#define CONTEXT_ADDR_FROM_STEM(stem) &context->uc_mcontext->__ss.__##stem -#define EIP __eip -#define ESP __esp -#define EBP __ebp -#define EAX __eax -#define EBX __ebx -#define ECX __ecx -#define EDX __edx -#define ESI __esi -#define EDI __edi -#define EFLAGS __eflags -#define CS __cs -#define DS __ds -#define ES __es -#define FS __fs -#define SS __ss -#define GS __gs - -#define FPU_FCW __fpu_fcw - -#else - -#define CONTEXT_ADDR_FROM_STEM(stem) &context->uc_mcontext->ss.stem -#define EIP eip -#define ESP esp -#define EBP ebp -#define EAX eax -#define EBX ebx -#define ECX ecx -#define EDX edx -#define ESI esi -#define EDI edi -#define EFLAGS eflags -#define CS cs -#define DS ds -#define ES es -#define FS fs -#define SS ss -#define GS gs - -#define FPU_FCW fpu_fcw - -#endif /* __DARWIN_UNIX03 */ - -#define RESTORE_FP_CONTROL_FROM_CONTEXT -void os_restore_fp_control(os_context_t *context); - -#endif /* _X86_DARWIN_OS_H */ diff --git a/src/runtime/x86-linux-os.c b/src/runtime/x86-linux-os.c index dd66b97346..429d9c8fc6 100644 --- a/src/runtime/x86-linux-os.c +++ b/src/runtime/x86-linux-os.c @@ -30,8 +30,6 @@ #include "interrupt.h" #include "interr.h" #include "lispregs.h" -#include <sys/socket.h> -#include <sys/utsname.h> #include <sys/types.h> #include <signal.h> @@ -74,11 +72,6 @@ int arch_os_thread_init(struct thread *thread) { ((entry_number << 3) + 3)); if(entry_number < 0) return 0; -#ifdef LISP_FEATURE_GCC_TLS - current_thread = thread; -#else - pthread_setspecific(specials,thread); -#endif #endif #ifdef LISP_FEATURE_C_STACK_IS_CONTROL_STACK @@ -95,7 +88,7 @@ int arch_os_thread_init(struct thread *thread) { } struct thread *debug_get_fs() { - register u32 fs; + register uint32_t fs; __asm__ __volatile__ ("movl %%fs,%0" : "=r" (fs) : ); return (struct thread *)fs; } @@ -132,12 +125,6 @@ os_context_register_addr(os_context_t *context, int offset) return &context->uc_mcontext.gregs[offset]; } -os_context_register_t * -os_context_pc_addr(os_context_t *context) -{ - return &context->uc_mcontext.gregs[14]; /* REG_EIP */ -} - os_context_register_t * os_context_sp_addr(os_context_t *context) { diff --git a/src/runtime/x86-linux-os.h b/src/runtime/x86-linux-os.h index 0fc3bae966..58309ca694 100644 --- a/src/runtime/x86-linux-os.h +++ b/src/runtime/x86-linux-os.h @@ -10,4 +10,6 @@ unsigned long os_context_fp_control(os_context_t *context); #define RESTORE_FP_CONTROL_FROM_CONTEXT void os_restore_fp_control(os_context_t *context); +#define OS_CONTEXT_PC(context) context->uc_mcontext.gregs[14] /* REG_EIP */ + #endif /* _X86_LINUX_OS_H */ diff --git a/src/runtime/x86-sunos-os.c b/src/runtime/x86-sunos-os.c index 69eaac0dc5..1c6562f02c 100644 --- a/src/runtime/x86-sunos-os.c +++ b/src/runtime/x86-sunos-os.c @@ -9,8 +9,6 @@ #include "interrupt.h" #include "interr.h" #include "lispregs.h" -#include <sys/socket.h> -#include <sys/utsname.h> #include <sys/types.h> #include <signal.h> @@ -73,7 +71,7 @@ static int install_segment (unsigned long start, unsigned long size) { int selector; - thread_mutex_lock(&modify_ldt_lock); + ignore_value(mutex_acquire(&modify_ldt_lock)); selector = ldt_index_selector(find_free_ldt_index()); struct ssd ssd = { selector, @@ -85,7 +83,7 @@ install_segment (unsigned long start, unsigned long size) { lose("Couldn't install segment for thread-local data"); } - thread_mutex_unlock(&modify_ldt_lock); + ignore_value(mutex_release(&modify_ldt_lock)); return selector; } @@ -97,12 +95,9 @@ int arch_os_thread_init(struct thread *thread) { #ifdef LISP_FEATURE_SB_THREAD int sel = install_segment((unsigned long) thread, dynamic_values_bytes); - FSHOW_SIGNAL((stderr, "/ TLS: Allocated LDT %x\n", sel)); __asm__ __volatile__ ("mov %0, %%fs" : : "r"(sel)); thread->tls_cookie = sel; - pthread_setspecific(specials,thread); - #endif #ifdef LISP_FEATURE_C_STACK_IS_CONTROL_STACK @@ -125,15 +120,13 @@ int arch_os_thread_cleanup(struct thread *thread) { /* Set the %%fs register back to 0 and free the ldt by setting it * to NULL. */ - FSHOW_SIGNAL((stderr, "/ TLS: Freeing LDT %x\n", n)); - __asm__ __volatile__ ("mov %0, %%fs" : : "r"(0)); - thread_mutex_lock(&modify_ldt_lock); + ignore_value(mutex_acquire(&modify_ldt_lock)); if (sysi86(SI86DSCR, &delete) < 0) { lose("Couldn't remove segment"); } - thread_mutex_unlock(&modify_ldt_lock); + ignore_value(mutex_release(&modify_ldt_lock)); #endif return 1; /* success */ } @@ -156,12 +149,6 @@ os_context_register_addr(os_context_t *context, int offset) return &context->uc_mcontext.gregs[offset]; } -os_context_register_t * -os_context_pc_addr(os_context_t *context) -{ - return &(context->uc_mcontext.gregs[14]); /* REG_EIP */ -} - os_context_register_t * os_context_sp_addr(os_context_t *context) { diff --git a/src/runtime/x86-sunos-os.h b/src/runtime/x86-sunos-os.h index cee07f5a0e..ec97d3e85b 100644 --- a/src/runtime/x86-sunos-os.h +++ b/src/runtime/x86-sunos-os.h @@ -6,4 +6,6 @@ typedef int os_context_register_t; #include "arch-os-generic.inc" +#define OS_CONTEXT_PC(contex) context->uc_mcontext.gregs[14] /* REG_EIP */ + #endif /* _X86_SOLARIS_OS_H */ diff --git a/src/runtime/x86-win32-os.c b/src/runtime/x86-win32-os.c index 6212222160..d4ed7f0bb9 100644 --- a/src/runtime/x86-win32-os.c +++ b/src/runtime/x86-win32-os.c @@ -123,12 +123,6 @@ os_context_register_addr(os_context_t *context, int offset) ((void*)(context->win32_context)) + offsets[offset>>1] : 0; } -os_context_register_t * -os_context_pc_addr(os_context_t *context) -{ - return (void*)&context->win32_context->Eip; /* REG_EIP */ -} - os_context_register_t * os_context_sp_addr(os_context_t *context) { @@ -163,3 +157,27 @@ void os_flush_icache(os_vm_address_t address, os_vm_size_t length) { } + +/* + * The stubs below are replacements for the windows versions, + * which can -fail- when used in our memory spaces because they + * validate the memory spaces they are passed in a way that + * denies our exception handler a chance to run. + */ + +void *memmove(void *dest, const void *src, size_t n) +{ + if (dest < src) { + size_t i; + for (i = 0; i < n; i++) *(((char *)dest)+i) = *(((char *)src)+i); + } else { + while (n--) *(((char *)dest)+n) = *(((char *)src)+n); + } + return dest; +} + +void *memcpy(void *dest, const void *src, size_t n) +{ + while (n--) *(((char *)dest)+n) = *(((char *)src)+n); + return dest; +} diff --git a/src/runtime/x86-win32-os.h b/src/runtime/x86-win32-os.h index a43fcb9b1f..98ba86efaa 100644 --- a/src/runtime/x86-win32-os.h +++ b/src/runtime/x86-win32-os.h @@ -23,4 +23,6 @@ void os_restore_fp_control(os_context_t *context); os_context_register_t * os_context_fp_addr(os_context_t *context); +#define OS_CONTEXT_PC(context) context->win32_context->Eip + #endif /* _X86_WIN32_OS_H */ diff --git a/tests/alien.impure.lisp b/tests/alien.impure.lisp index ff8c86789e..252b8067bf 100644 --- a/tests/alien.impure.lisp +++ b/tests/alien.impure.lisp @@ -286,11 +286,11 @@ ;;; Bug #316325: "return values of alien calls assumed truncated to ;;; correct width on x86" #+x86-64 -(sb-alien::define-alien-callback truncation-test (unsigned 64) +(define-alien-callable truncation-test (unsigned 64) ((foo (unsigned 64))) foo) #+x86 -(sb-alien::define-alien-callback truncation-test (unsigned 32) +(define-alien-callable truncation-test (unsigned 32) ((foo (unsigned 32))) foo) @@ -304,7 +304,7 @@ `(with-alien ((fun (* (function ,type #+x86-64 (unsigned 64) #+x86 (unsigned 32))) - :local (alien-sap truncation-test))) + :local (alien-sap (alien-callable-function 'truncation-test)))) (let ((result (alien-funcall fun ,input))) (assert (= result ,output)))))) #+x86-64 @@ -374,9 +374,10 @@ ;;; Skip for MSAN. Instead of returning 0, the intercepted malloc is configured ;;; to cause process termination by default on failure to allocate memory. +;;; Skip also for UBSAN which has a smaller ARRAY-TOTAL-SIZE-LIMIT +;;; and so doesn't get ENOMEM. (with-test (:name :malloc-failure - :skipped-on :msan - :fails-on :alpha) ;; Alpha has address space to burn + :skipped-on (or :ubsan :msan)) (assert (eq :enomem (handler-case (loop repeat 128 @@ -526,9 +527,39 @@ (with-test (:name :undefined-alien-name :skipped-on (not (or :x86-64 :arm :arm64))) - (handler-case (funcall (checked-compile `(lambda () - (alien-funcall (extern-alien "bar" (function (values))))) - :allow-style-warnings t)) - (t (c) - (assert (typep c 'sb-kernel::undefined-alien-function-error)) - (assert (equal (cell-error-name c) "bar"))))) + (dolist (memspace '(:dynamic #+immobile-space :immobile)) + (let ((lispfun + (let ((sb-c::*compile-to-memory-space* memspace)) + (checked-compile `(lambda () + (alien-funcall (extern-alien "bar" (function (values))))) + :allow-style-warnings t)))) + (handler-case (funcall lispfun) + (t (c) + (assert (typep c 'sb-kernel::undefined-alien-function-error)) + (assert (equal (cell-error-name c) "bar"))))))) + +(with-test (:name :undefined-alien-name-via-linkage-table-trampoline + :skipped-on (not (or :x86-64 :arm :arm64))) + (dolist (memspace '(:dynamic #+immobile-space :immobile)) + (let ((lispfun + (let ((sb-c::*compile-to-memory-space* memspace)) + (checked-compile + `(lambda () + (with-alien ((fn (* (function (values))) + (sb-sys:int-sap (sb-sys:foreign-symbol-address "baz")))) + (alien-funcall fn))))))) + (handler-case (funcall lispfun) + (t (c) + (assert (typep c 'sb-kernel::undefined-alien-function-error)) + (assert (equal (cell-error-name c) "baz"))))))) + +(defconstant fleem 3) +;; We used to expand into +;; (SYMBOL-MACROLET ((FLEEM (SB-ALIEN-INTERNALS:%ALIEN-VALUE +;; which conflicted with the symbol as global variable. +(with-test (:name :def-alien-rtn-use-gensym) + (checked-compile '(lambda () (define-alien-routine "fleem" int (x int))) + :allow-style-warnings (or #-(or :x86-64 :arm :arm64) t))) + +(with-test (:name :no-vector-sap-of-array-nil) + (assert-error (sb-sys:vector-sap (opaque-identity (make-array 5 :element-type nil))))) diff --git a/tests/allocator.pure.lisp b/tests/allocator.pure.lisp new file mode 100644 index 0000000000..5afa5fb954 --- /dev/null +++ b/tests/allocator.pure.lisp @@ -0,0 +1,82 @@ +#+gencgc +(progn +(defun on-large-page-p (x) + (and (eq (sb-ext:heap-allocated-p x) :dynamic) + (let ((flags + (sb-sys:with-pinned-objects (x) + (sb-alien:slot (sb-alien:deref sb-vm::page-table + (sb-vm:find-page-index + (sb-kernel:get-lisp-obj-address x))) + 'sb-vm::flags)))) + (logbitp 4 flags)))) ; SINGLE_OBJECT_FLAG +(compile 'on-large-page-p) + +;;; Pseudo-static large objects should retain the single-object flag + +;;; Prior to change 3b137be67217 ("speed up trans_list"), +;;; gc_general_alloc() would always test whether it was allocating a large +;;; object via "if (nbytes >= LARGE_OBJECT_SIZE)" and in that case it would +;;; call gc_alloc_large(). It was not overwhelmingly necessary to perform the +;;; size test - which is an extra branch for almost no reason - because large +;;; objects should end up in the slow path by default. (So we only make the +;;; slow path a little slower, and speed up the fast path) +;;; However, 32-bit machines with small page size (4Kb) have a sufficiently small +;;; "large" object size that many more objects ought to be characterized as large. +;;; In conjunction with the fact that code allocation always opens allocations +;;; regions of at least 64k (= 16 pages), we find that code blobs end up in the +;;; open region by accident. This doesn't happen for the 32-bit architectures +;;; where the GENCGC-PAGE-BYTES is defined as 64KB because the minimum +;;; of 64KB is only 1 page, but a "large" object is 4 pages or more. +;;; So the fix is for trans_code() to do the size test, and then we don't +;;; slow down the general case of gc_general_alloc. +(with-test (:name :pseudostatic-large-objects) + (sb-vm:map-allocated-objects + (lambda (obj type size) + (declare (ignore type size)) + (when (>= (sb-ext:primitive-object-size obj) (* 4 sb-vm:gencgc-page-bytes)) + (let* ((addr (sb-kernel:get-lisp-obj-address obj)) + (pte (deref sb-vm:page-table (sb-vm:find-page-index addr)))) + (when (eq (slot pte 'sb-vm::gen) sb-vm:+pseudo-static-generation+) + (assert (on-large-page-p obj)))))) + :dynamic)) + +(eval-when (:compile-toplevel :load-toplevel :execute) + (defparameter large-n-words (/ sb-vm:large-object-size sb-vm:n-word-bytes)) + (defparameter large-n-conses (/ large-n-words 2)))) + +(with-test (:name :no-&rest-on-large-object-pages :skipped-on (:not :gencgc)) + ;; adding in a 2-word vector header makes it at least large-object-size. + ;; The threshold in the allocator is exact equality for that. + (let ((definitely-large-vector (make-array (- large-n-words 2))) + ;; Decreasing by 1 word isn't enough, because of padding, so decrease by 2 words + (not-large-vector (make-array (- large-n-words 4)))) + ;; Verify the edge case for LARGE-OBJECT-P + (assert (on-large-page-p definitely-large-vector)) + (assert (not (on-large-page-p not-large-vector))) + (assert (not (on-large-page-p (list 1 2))))) + (let ((fun (checked-compile '(lambda (&rest params) params)))) + (assert (not (on-large-page-p (apply fun (make-list large-n-conses))))))) + +;;; MIPS either: (1) runs for 10 minutes just in COMPILE and then croaks in the assembler +;;; due to an overly large displacement in an instruction, (2) crashes with heap exhaustion. +;;; I don't really care enough to fix it. A flat profile shows the following top hot spots: +;;; +;;; Self Total Cumul +;;; Nr Count % Count % Count % Calls Function +;;; ------------------------------------------------------------------------ +;;; 1 813 677.5 813 677.5 813 677.5 - SB-REGALLOC::CONFLICTS-IN-SC +;;; 2 208 173.3 208 173.3 1021 850.8 - SB-C::COALESCE-MORE-LTN-NUMBERS +;;; 3 118 98.3 118 98.3 1139 949.2 - NTH +;;; 4 63 52.5 878 731.7 1202 1001.7 - (LABELS SB-REGALLOC::ATTEMPT-LOCATION :IN SB-REGALLOC::SELECT-LOCATION) +;;; +;;; (And I don't know much about math, but I don't think that's how percentages work) +;;; +;;; I don't remember what the problem is with PPC. +(with-test (:name :no-list-on-large-object-pages + :skipped-on (:or :mips :ppc :ppc64)) + (let* ((fun (checked-compile + '(lambda () + (macrolet ((expand (n) `(list ,@(loop for i from 1 to n collect i)))) + (expand #.large-n-conses))))) + (list (funcall fun))) + (assert (not (on-large-page-p list))))) diff --git a/tests/ansi-tests.sh b/tests/ansi-tests.sh index c975a986b3..088181b396 100755 --- a/tests/ansi-tests.sh +++ b/tests/ansi-tests.sh @@ -4,21 +4,24 @@ if [ ! -e ansi-test ]; then git clone --depth 1 https://github.com/sbcl/ansi-test.git fi + cd ansi-test +rm -fr sandbox/scratch ../../run-sbcl.sh --lose-on-corruption --disable-ldb \ --load gclload1.lsp --load gclload2.lsp \ --eval '(setf *default-pathname-defaults* (truename #P"sandbox/"))' \ - --eval '(time (regression-test:do-tests))' \ - --eval '(let* ((expected (list* "APROPOS-LIST.ERROR.2" "APROPOS.ERROR.2" "BOTH-CASE-P.2" "CHAR-DOWNCASE.2" - "CHAR-UPCASE.2" "COMPILE-FILE.2" - "DEFINE-COMPILER-MACRO.8" "DEFSETF.7A" "DESTRUCTURING-BIND.ERROR.10" + --eval '(in-package :cl-test)' \ + --eval '(disable-note :nil-vectors-are-strings)' \ + --eval '(time (do-tests))' \ + --eval '(let* ((expected (list* "APROPOS-LIST.ERROR.2" "APROPOS.ERROR.2" "COMPILE-FILE.2" + "DEFINE-COMPILER-MACRO.8" "DESTRUCTURING-BIND.ERROR.10" "EXP.ERROR.10" "EXP.ERROR.11" "EXP.ERROR.8" "EXP.ERROR.9" "EXPT.ERROR.10" "EXPT.ERROR.11" "EXPT.ERROR.8" "EXPT.ERROR.9" "FORMAT.A.29" "FORMAT.A.57" "FORMAT.A.58" "FORMAT.B.27" "FORMAT.B.28" "FORMAT.B.29" "FORMAT.D.27" "FORMAT.D.28" "FORMAT.D.29" "FORMAT.F.45" "FORMAT.F.46" "FORMAT.F.46B" "FORMAT.F.5" "FORMAT.F.8" "FORMAT.O.27" "FORMAT.O.28" "FORMAT.O.29" "FORMAT.R.37" "FORMAT.R.38" "FORMAT.S.29" - "FORMAT.E.1" "FORMAT.E.2" + "FORMAT.E.1" "FORMAT.E.2" "FORMAT.E.6" "FORMAT.E.20" "FORMAT.X.27" "FORMAT.X.28" "FORMAT.X.29" "FORMATTER.A.57" "FORMATTER.A.58" "FORMATTER.B.27" "FORMATTER.B.28" "FORMATTER.B.29" "FORMATTER.D.27" "FORMATTER.D.28" "FORMATTER.D.29" "FORMATTER.F.45" "FORMATTER.F.46" @@ -27,7 +30,7 @@ cd ansi-test "FORMATTER.X.29" "LOOP.1.39" "LOOP.1.40" "LOOP.1.41" "LOOP.1.42" "LOOP.1.43" "MACROLET.36" "MAKE-CONDITION.3" "MAKE-CONDITION.4" "MAKE-PATHNAME-ERROR-ABSOLUTE-WILD-INFERIORS-BACK" - "MAKE-PATHNAME-ERROR-RELATIVE-WILD-INFERIORS-BACK" "MAP.48" + "MAKE-PATHNAME-ERROR-RELATIVE-WILD-INFERIORS-BACK" "PPRINT-LOGICAL-BLOCK.ERROR.1" "PPRINT-LOGICAL-BLOCK.ERROR.1-UNSAFE" "PPRINT-LOGICAL-BLOCK.ERROR.3" "PPRINT-LOGICAL-BLOCK.ERROR.3-UNSAFE" "PRINT-LEVEL.8" "PRINT-LEVEL.9" "PRINT.BACKQUOTE.RANDOM.1" @@ -35,22 +38,31 @@ cd ansi-test "PRINT.BACKQUOTE.RANDOM.13" "PRINT.BACKQUOTE.RANDOM.14" "PRINT.BACKQUOTE.RANDOM.2" "PRINT.BACKQUOTE.RANDOM.3" "PRINT.BACKQUOTE.RANDOM.4" "PRINT.BACKQUOTE.RANDOM.5" "PROCLAIM.ERROR.7" - "READTABLE-CASE.CASE-DOWNCASE" "READTABLE-CASE.CASE-INVERT" - "READTABLE-CASE.CASE-PRESERVE" "READTABLE-CASE.CASE-UPCASE" "SHIFTF.7" - "SUBTYPEP-COMPLEX.8" "SUBTYPEP.CONS.38" "SUBTYPEP.CONS.41" "SUBTYPEP.CONS.43" + "SHIFTF.7" + "SUBTYPEP-COMPLEX.8" "SUBTYPEP.EQL.1" "SUBTYPEP.EQL.2" "SUBTYPEP.MEMBER.17" "SUBTYPEP.MEMBER.18" - "SXHASH.17" "SXHASH.18" "SXHASH.19" "TYPE-OF.1" "PRINT-STRUCTURE.1" - #+x86 (list "ACOSH.3" "SQRT.4") -#+win32 (list "ASINH.1" "ASINH.2" "ASINH.3" "ASINH.7" "ACOSH.3" "EXP.ERROR.7" - "EXPT.ERROR.4" "EXPT.ERROR.5" "EXPT.ERROR.6" "EXPT.ERROR.7" - "PROBE-FILE.4" "OPEN.OUTPUT.23" "OPEN.IO.22" "OPEN.IO.23") - #-(or win32 x86) nil)) + "SXHASH.17" "SXHASH.18" "SXHASH.19" "PRINT-STRUCTURE.1" + (append #+win32 (list "EXP.ERROR.7" + "EXPT.ERROR.4" "EXPT.ERROR.5" "EXPT.ERROR.6" "EXPT.ERROR.7" + "PROBE-FILE.4") + #+arm64 (list "EXP.ERROR.4" "EXP.ERROR.5" "EXP.ERROR.6" "EXP.ERROR.7" "EXPT.ERROR.4" + "EXPT.ERROR.5" "EXPT.ERROR.6" "EXPT.ERROR.7") + #-sb-unicode (list "MISC.638") + (if (member :sb-fasteval sb-impl:+internal-features+) + (list "INTERSECTION.FOLD.1" "UNION.FOLD.1" "SET-DIFFERENCE.FOLD.1" + "SET-EXCLUSIVE-OR.FOLD.1" "ASH.ERROR.5" + "ALL-STRUCTURE-CLASSES-ARE-SUBTYPES-OF-STRUCTURE-OBJECT.2" "TRACE.8") + (list "MAP.48" "SYMBOL-FUNCTION.ERROR.5")) + + #+sb-unicode (list "BOTH-CASE-P.2" "CHAR-DOWNCASE.2" "CHAR-UPCASE.2")))) (failing (remove "FORMAT.E.26" (mapcar (function string) regression-test:*failed-tests*) :test (function equal))) + #+sb-devel + (failing (remove "COMMON-LISP-PACKAGE-NICKNAMES" failing :test (function equal))) (diff1 (set-difference failing expected :test (function equal))) (diff2 (set-difference expected failing :test (function equal)))) (cond ((or diff1 diff2) (format t "Difference ~@[added ~a~] ~@[removed ~a~]~%" diff1 diff2) - (exit :code 1)) - ((exit))))' + (sb-ext:exit :code 1)) + ((sb-ext:exit))))' diff --git a/tests/aprof.impure.lisp b/tests/aprof.impure.lisp index 380e145c37..8d8305d10b 100644 --- a/tests/aprof.impure.lisp +++ b/tests/aprof.impure.lisp @@ -9,25 +9,26 @@ ;;;; absolutely no warranty. See the COPYING and CREDITS files for ;;;; more information. -#-(and x86-64 sb-thread) (sb-ext:exit :code 104) ;; not implemented elsewhere +#-(and x86-64 sb-thread (not win32)) (invoke-restart 'run-tests::skip-file) ;; not implemented elsewhere +(defstruct fruitbasket x y z) (with-test (:name :aprof-smoketest-struct + :skipped-on :darwin ;; reverse-engineering the allocation instructions fails but should not :fails-on (not :immobile-space)) (let ((nbytes (sb-aprof:aprof-run (checked-compile '(sb-int:named-lambda "test" () - (declare (inline sb-thread:make-mutex) + (declare (inline make-fruitbasket) (optimize sb-c::instrument-consing)) - (loop repeat 50 collect (sb-thread:make-mutex)))) + (loop repeat 50 collect (make-fruitbasket)))) :stream nil))) (assert (= nbytes - (* 50 (+ (sb-vm::primitive-object-size (sb-thread:make-mutex)) + (* 50 (+ (sb-ext:primitive-object-size (make-fruitbasket)) (* 2 sb-vm:n-word-bytes))))))) ; cons cells -(with-test (:name :aprof-smoketest-non-constant-size-vector - :broken-on :win32) +(with-test (:name :aprof-smoketest-non-constant-size-vector) (let ((nbytes (sb-aprof:aprof-run (checked-compile @@ -40,8 +41,7 @@ ;;; The profiler's disassembler expected to see a store at alloc-ptr ;;; or that + n-word-bytes, when in fact the code might write to 1 byte ;;; positioned anywhere in the word after the object header. -(with-test (:name :aprof-smoketest-bit-vector - :fails-on :win32) +(with-test (:name :aprof-smoketest-bit-vector) (let ((nbytes (sb-aprof:aprof-run (checked-compile @@ -49,11 +49,10 @@ (declare (optimize sb-c::instrument-consing)) (make-array (* 128 16) :element-type 'bit))) :stream nil))) - (assert (= nbytes (sb-vm::primitive-object-size + (assert (= nbytes (sb-ext:primitive-object-size (make-array (* 128 16) :element-type 'bit)))))) -(with-test (:name :aprof-smoketest-large-vector - :fails-on :win32) +(with-test (:name :aprof-smoketest-large-vector) (let ((nbytes (sb-aprof:aprof-run (checked-compile @@ -69,16 +68,16 @@ sb-vm:: (:node-var node) (:generator 1 (let* ((bytes large-object-size) ; payload + header total + (temp sb-vm::r11-tn) (words (- (/ bytes n-word-bytes) vector-data-offset))) - (instrument-alloc bytes node) + (instrument-alloc nil bytes node temp) (pseudo-atomic () - (allocation nil bytes 0 node nil result) + (allocation nil bytes 0 result node temp nil) (storew* simple-array-unsigned-byte-64-widetag result 0 0 t) (storew* (fixnumize words) result vector-length-slot 0 t) (inst or :byte result other-pointer-lowtag))))) -(with-test (:name :aprof-smoketest-large-vector-to-upper-register - :fails-on :win32) +(with-test (:name :aprof-smoketest-large-vector-to-upper-register) (let ((nbytes (sb-aprof:aprof-run (checked-compile @@ -98,10 +97,7 @@ sb-vm:: (declare (optimize sb-c::instrument-consing)) (list* (load-time-value(gensym)) :if-exists x)) -#-win32 -(import '(sb-vm::temp-reg-tn sb-vm::thread-base-tn - sb-vm::thread-pseudo-atomic-bits-slot sb-vm::thread-alloc-region-slot - sb-vm::rcx-tn sb-vm::rbp-tn sb-vm::r9-tn sb-vm::r10-tn sb-vm::rsi-tn +(import '(sb-vm::rcx-tn sb-vm::rbp-tn sb-vm::r9-tn sb-vm::r10-tn sb-vm::rsi-tn sb-vm:cons-size sb-vm:n-word-bytes sb-vm::ea sb-vm:nil-value sb-vm:list-pointer-lowtag sb-vm:bignum-widetag)) @@ -113,9 +109,7 @@ sb-vm:: (declare (optimize sb-c::instrument-consing)) (values (make-this-struct) (make-that-struct))) (compile 'make-structs) -#-win32 -(with-test (:name :aprof-instance - :fails-on (or (not :immobile-space) :sb-safepoint)) +(with-test (:name :aprof-instance :skipped-on (not :immobile-space)) (let (seen-this seen-that) (dolist (line (split-string (with-output-to-string (s) @@ -125,12 +119,47 @@ sb-vm:: (when (search "THAT-STRUCT" line) (setq seen-that t))) (assert (and seen-this seen-that)))) -#-win32 +(defun my-list (&rest x) + (declare (optimize sb-c::instrument-consing)) + x) +(compile 'my-list) + +(with-test (:name :listify-rest-arg) + (let ((nbytes (let ((*standard-output* (make-broadcast-stream))) + (sb-aprof:aprof-run #'my-list :arguments '(a b c))))) + (assert (= nbytes (* sb-vm:n-word-bytes 6))))) + +(defun make-new-code (n) + (let ((f + (compile nil + '(lambda (n) + (declare (optimize sb-c::instrument-consing)) + (make-array (the fixnum n)))))) + (sb-aprof:aprof-reset) ; In case the counts are already nonzero + (loop for i below n + do (funcall f i)) + f)) +(with-test (:name :make-new-code) + (let* ((n 20) + (nbytes (sb-aprof:aprof-run #'make-new-code :arguments n + :stream (make-broadcast-stream) + ;; FIXME: need to return nbytes with or without a report + #|:report nil|# + ))) + ;; If the lisp image was compiled with cons profiling, then the COMPILE + ;; inside MAKE-NEW-CODE was also instrumented, messing up the result. + ;; (The compiler conses about ~128Kb but there's no way to predict how much) + (unless (sb-c:policy nil (> sb-c:instrument-consing 0)) + (assert (= (loop for i below n + sum (sb-ext:primitive-object-size (make-array i))) + nbytes))))) + (with-test (:name :aprof-brutal-test) (with-scratch-file (fasl "fasl") ;; Just compile anything that exercises the compiler. ;; This is only useful if the compiler was compiled with cons profiling. - (sb-aprof:aprof-run (lambda () (compile-file "../src/code/shaketree" - :output-file fasl - :print nil :verbose nil)) - :stream (make-broadcast-stream)))) + (sb-aprof:aprof-run #'compile-file + :stream (make-broadcast-stream) + :arguments `("../src/code/shaketree" + :output-file ,fasl + :print nil :verbose nil)))) diff --git a/tests/arith.impure.lisp b/tests/arith-2.pure.lisp similarity index 100% rename from tests/arith.impure.lisp rename to tests/arith-2.pure.lisp diff --git a/tests/arith-combinations.pure.lisp b/tests/arith-combinations.pure.lisp new file mode 100644 index 0000000000..c9d6121a5d --- /dev/null +++ b/tests/arith-combinations.pure.lisp @@ -0,0 +1,121 @@ +;;;; This software is part of the SBCL system. See the README file for +;;;; more information. +;;;; +;;;; While most of SBCL is derived from the CMU CL system, the test +;;;; files (like this one) were written from scratch after the fork +;;;; from CMU CL. +;;;; +;;;; This software is in the public domain and is provided with +;;;; absolutely no warranty. See the COPYING and CREDITS files for +;;;; more information. + +(enable-test-parallelism) + +(defun test-ops (ops types arguments &optional (result-types types)) + (flet ((normalize-type (type) + (sb-kernel:type-specifier (sb-kernel:specifier-type type)))) + (let ((types (mapcar #'normalize-type types)) + (result-types (mapcar #'normalize-type result-types)) + (cache (make-hash-table :test #'equal))) + (loop for op in ops + do + (loop for a-type in types + do + (loop for b-type in types + do + (loop for result-type in result-types + do + (loop for a in arguments + when (typep a a-type) + do + (loop for b in arguments + for result = (funcall op a b) + when (typep b b-type) + do + (loop for lambda in (list `(lambda (a b) + (declare (,a-type a) + (,b-type b)) + (the ,result-type (,op a b))) + `(lambda (a) + (declare (,a-type a)) + (the ,result-type (,op a ,b))) + `(lambda (b) + (declare (,b-type b)) + (the ,result-type (,op ,a b)))) + for args in (list (list a b) + (list a) + (list b)) + for fun = (or (gethash lambda cache) + (setf (gethash lambda cache) + (checked-compile lambda :allow-warnings t))) + do + (handler-case + (apply fun args) + (error (c) + (if (typep result result-type) + (error "~a => ~a /= ~a" (list* lambda args) c result) + (let ((x (type-error-datum c)) + (type (type-error-expected-type c))) + (cond ((not (equal type result-type)) + (error "~a => type error ~a /= ~a" (list* lambda args) + c + result-type)) + ((not (eql x result)) + (error "~a => type error ~a /= ~a" (list* lambda args) + c + x)))))) + (:no-error (x) + (if (typep result result-type) + (unless (eql x result) + (error "~a = ~a /= ~a" (list* lambda args) x result)) + (error "~a => ~a /= type error" (list* lambda args) x)))))))))))))) + +(with-test (:name :overflow-arith) + (test-ops '(+ - *) + `(t fixnum (integer ,(- (expt 2 sb-vm:n-word-bits) 10) + ,(- (expt 2 sb-vm:n-word-bits) 1)) + (signed-byte ,sb-vm:n-word-bits) + (unsigned-byte ,sb-vm:n-word-bits) + (signed-byte 8) + (unsigned-byte 8)) + (list 0 1 2 3 4 -1 -2 -3 -4 + (- (expt 2 sb-vm:n-word-bits) 1) + (- (expt 2 sb-vm:n-word-bits) 5) + (- (expt 2 (1- sb-vm:n-word-bits)) 1) + (- (expt 2 (1- sb-vm:n-word-bits)) 5) + (- (expt 2 (1- sb-vm:n-word-bits))) + (- 10 (expt 2 (1- sb-vm:n-word-bits))) + (expt 2 (1- sb-vm:n-word-bits)) + most-positive-fixnum + most-negative-fixnum + (1- most-positive-fixnum) + (1+ most-negative-fixnum) + (floor most-positive-fixnum 2) + (floor most-negative-fixnum 2)))) + +(with-test (:name :fixnum-integer-cmp) + (test-ops '(> <) + `(t fixnum + integer + bignum + (integer ,(- (expt 2 sb-vm:n-word-bits) 10) + ,(- (expt 2 sb-vm:n-word-bits) 1)) + (signed-byte ,sb-vm:n-word-bits) + (unsigned-byte ,sb-vm:n-word-bits) + (signed-byte 8) + (unsigned-byte 8)) + (list 0 1 2 3 4 -1 -2 -3 -4 + (- (expt 2 sb-vm:n-word-bits) 1) + (- (expt 2 sb-vm:n-word-bits) 5) + (- (expt 2 (1- sb-vm:n-word-bits)) 1) + (- (expt 2 (1- sb-vm:n-word-bits)) 5) + (- (expt 2 (1- sb-vm:n-word-bits))) + (- 10 (expt 2 (1- sb-vm:n-word-bits))) + (expt 2 (1- sb-vm:n-word-bits)) + most-positive-fixnum + most-negative-fixnum + (1- most-positive-fixnum) + (1+ most-negative-fixnum) + (floor most-positive-fixnum 2) + (floor most-negative-fixnum 2)) + '(t))) diff --git a/tests/arith-slow.pure.lisp b/tests/arith-slow.pure.lisp new file mode 100644 index 0000000000..e38f8e9a33 --- /dev/null +++ b/tests/arith-slow.pure.lisp @@ -0,0 +1,35 @@ +;;; These two tests are by themselves because they consume more run time +;;; than all other tests in arith.pure combined. + +(defmacro test-guts () + #+sb-thread '(let ((t1 (sb-thread:make-thread #'doit :arguments '(-8 0))) + (t2 (sb-thread:make-thread #'doit :arguments '(1 8)))) + (sb-thread:join-thread t1) + (sb-thread:join-thread t2)) + #-sb-thread '(doit -8 8)) + +(with-test (:name (logand :complicated-identity) + :skipped-on :mips) ; too slow + (flet ((doit (k-lo k-hi) + (loop for k from k-lo upto k-hi do + (loop for min from -16 upto 16 do + (loop for max from min upto 16 do + (let ((f (checked-compile `(lambda (x) + (declare (type (integer ,min ,max) x)) + (logand x ,k))))) + (loop for x from min upto max do + (assert (eql (logand x k) (funcall f x)))))))))) + (test-guts))) + +(with-test (:name (logior :complicated-identity) + :skipped-on :mips) ; too slow + (flet ((doit (k-lo k-hi) + (loop for k from k-lo upto k-hi do + (loop for min from -16 upto 16 do + (loop for max from min upto 16 do + (let ((f (checked-compile `(lambda (x) + (declare (type (integer ,min ,max) x)) + (logior x ,k))))) + (loop for x from min upto max do + (assert (eql (logior x k) (funcall f x)))))))))) + (test-guts))) diff --git a/tests/arith.pure.lisp b/tests/arith.pure.lisp index b5a4e80ab1..a7c0b1a7b5 100644 --- a/tests/arith.pure.lisp +++ b/tests/arith.pure.lisp @@ -495,7 +495,7 @@ ;;; MOD and REM. Test that the transform is indeed triggered and test ;;; several cases for correct results. (with-test (:name (:integer-division-using-multiplication :used) - :skipped-on (not (or :x86-64 :x86))) + :skipped-on (not (or :x86-64 :x86 :arm64))) (dolist (fun '(truncate floor ceiling mod rem)) (let* ((foo (checked-compile `(lambda (x) @@ -514,8 +514,10 @@ (with-test (:name (:integer-division-using-multiplication :correctness)) (let ((*random-state* (make-random-state t))) (dolist (dividend-type `((unsigned-byte ,sb-vm:n-word-bits) + (signed-byte ,sb-vm:n-word-bits) (and fixnum unsigned-byte) - (integer 10000 10100))) + (integer 10000 10100) + fixnum)) (dolist (divisor `(;; Some special cases from the paper 7 10 14 641 274177 ;; Range extremes @@ -527,7 +529,9 @@ for r = (random (expt 2 i)) ;; We don't want 0, 1 and powers of 2. when (not (zerop (logand r (1- r)))) - collect r))) + collect r + and + collect (- r)))) (dolist (fun '(truncate ceiling floor mod rem)) (let ((foo (checked-compile `(lambda (x) @@ -544,7 +548,8 @@ ,@(loop for i from 4 to sb-vm:n-word-bits for pow = (expt 2 (1- i)) for r = (+ pow (random pow)) - collect r))) + collect r + collect (- r)))) (when (typep dividend dividend-type) (multiple-value-bind (q1 r1) (funcall foo dividend) @@ -681,26 +686,6 @@ (the (integer 21371810342718833225 21371810343571293860) b))) ((16779072918521075607 21371810342718833263) 2923729245085762055))) -(with-test (:name (logand :complicated-identity)) - (loop for k from -8 upto 8 do - (loop for min from -16 upto 16 do - (loop for max from min upto 16 do - (let ((f (checked-compile `(lambda (x) - (declare (type (integer ,min ,max) x)) - (logand x ,k))))) - (loop for x from min upto max do - (assert (eql (logand x k) (funcall f x))))))))) - -(with-test (:name (logior :complicated-identity)) - (loop for k from -8 upto 8 do - (loop for min from -16 upto 16 do - (loop for max from min upto 16 do - (let ((f (checked-compile `(lambda (x) - (declare (type (integer ,min ,max) x)) - (logior x ,k))))) - (loop for x from min upto max do - (assert (eql (logior x k) (funcall f x))))))))) - (with-test (:name (ldb :negative-index-no-error)) (checked-compile-and-assert () '(lambda (x y) (ldb (byte x y) 100)) @@ -834,3 +819,301 @@ (declare (type (integer -142 -29) a)) (eql (gcd (setq a -29) a) 1)) ((-33) nil))) + +;;; Test that LOGIOR and LOGXOR on PPC64 can correctly perform the constant 2nd-arg +;;; vop variant on a 32-bit immediate using op + op-shifted instructions. +;;; (Probably we should refactor large parts of the test suite by the CPU +;;; architecture so that you can really see clearly the areas of concern +;;; for each backend, but I'm not about to embark on that now) +(with-test (:name :ppc64-logxor-32-bit-const) + (let ((f (compile nil + '(lambda (x) + (declare (fixnum x)) + ;; The asm code went wrong only if the result was not in the same + ;; register as the source, so make sure that X is live throughout + ;; the test so that each result is in a different register. + (let ((a (logxor x #x9516A7)) + (b (logior x #x2531b4)) + (c (ash x -1))) + (list a b c x)))))) + (let ((result (funcall f 0))) + (assert (equal result + '(#x9516A7 #x2531b4 0 0)))))) + +(with-test (:name :truncate-by-zero-derivation) + (assert + (not (equal (cadr + (cdaddr (sb-kernel:%simple-fun-type + (checked-compile + `(lambda () + (truncate 5 0)) + :allow-style-warnings t)))) + '(integer 0 0))))) + +(with-test (:name :truncate-by-zero-derivation.2) + (checked-compile + `(lambda (x y) + (declare (type (unsigned-byte 8) x y) + (optimize speed (safety 0))) + (mod x y)) + :allow-notes nil)) + +(with-test (:name :ash-fixnum) + (checked-compile-and-assert + () + `(lambda (b) + (declare (type (integer -2 2) b)) + (ash b (min 13 b))) + ((-2) -1) + ((-1) -1) + ((0) 0) + ((1) 2) + ((2) 8))) + +(with-test (:name :mod-ash-cut) + (checked-compile-and-assert + () + `(lambda (b) + (logand #xFF (ash 1 (the (integer -1000 1000) b)))) + ((1) 2) + ((500) 0)) + (checked-compile-and-assert + () + `(lambda (x b) + (logand #xFF (ash (the (unsigned-byte 64) x) (the (integer -1000 1000) b)))) + (((1- (expt 2 64)) -63) 1) + (((1- (expt 2 64)) -64) 0))) + +(with-test (:name :bogus-modular-fun-widths) + (checked-compile-and-assert + () + `(lambda (b) + (logorc2 0 (- (isqrt (abs (logand (if b -1 2) 2)))))) + ((t) 0) + ((nil) 0))) + +(with-test (:name :lognot-type-derive) + (assert + (equal (caddr (sb-kernel:%simple-fun-type + (checked-compile + `(lambda (b) + (lognot (if b -1 2)))))) + '(values (or (integer -3 -3) (integer 0 0)) &optional)))) + +(with-test (:name :logand-minus-1-type-derive) + (assert + (equal (caddr (sb-kernel:%simple-fun-type + (checked-compile + `(lambda (b) + (logand #xf (if b -1 2)))))) + '(values (or (integer 2 2) (integer 15 15)) &optional)))) + +(with-test (:name :ash-vop-liftimes) + (checked-compile-and-assert + () + `(lambda (A C) + (declare ((integer 18512171785636 25543390924355) a) + ((integer -20485927966480856 54446023204744213) c)) + (dpb a (byte 20 25) (ash a (min 2 c)))) + ((23906959691249 -15632482499364879) 15512918556672) + ((23906959691249 1) 50697318833122))) + + +(with-test (:name :ash-modarith-transform-loop) + (checked-compile-and-assert + () + `(lambda (p1 p2 p3) + (declare (type (integer * 53) p1) + (type number p2) + (type + (member 21006398744832 16437837094852630852 2251799813685252 + -1597729350241882 466525164) + p3)) + (ldb (byte (the (integer -3642545987372 *) p1) p2) p3)) + ((53 2 21006398744832) 5251599686208))) + +(with-test (:name :logcount-negative-fixnum) + (checked-compile-and-assert + () + `(lambda (x) + (logcount (the fixnum x))) + ((54) 4) + ((-54) 4))) + +(with-test (:name :mod-ash64-signed) + (checked-compile-and-assert + () + `(lambda (a b) + (declare (fixnum a b)) + (logand (ash a b) (1+ most-positive-fixnum))) + ((-1 -3) (1+ most-positive-fixnum)) + ((1 3) 0))) + +(with-test (:name :zero-shift-flags) + (checked-compile-and-assert + () + `(lambda (a m) + (declare ((integer 0 5000000000) a) + (bit m)) + (zerop (ash a m))) + ((1 0) nil) + ((0 1) t))) + +(with-test (:name :signum-merged-branch-if) + (checked-compile-and-assert + () + `(lambda (a y) + (declare (fixnum a y)) + (when (< y 10) + (signum a))) + ((1 5) 1) + ((0 5) 0) + ((-1 5) -1))) + +(with-test (:name :cmov-merged-branch-if) + (checked-compile-and-assert + () + `(lambda (b c) + (declare (type (integer 0 7711851432375361987) b)) + (declare (type (integer -2 0) c)) + (let ((v9 c)) + (if (< c v9) + c + (if (= v9 c) + v9 + b)))) + ((0 -1) -1))) + +(with-test (:name :ash-amount-unsigned-comparison) + (checked-compile-and-assert + () + `(lambda (a) + (declare (type (integer -581 900) a)) + (ash 3 (ash (ash a -50) (1- sb-vm:n-word-bits)))) + ((-1) 0) + ((1) 3))) + +(with-test (:name :ash-modfx-constant-folding) + (checked-compile-and-assert + () + `(lambda (a) + (declare (type (integer -10000 5) a)) + (ldb (byte 16 28) + (ash 4611686018427387913 + (progn + (multiple-value-setq (a) -10000) + a)))) + ((0) 0))) + +(with-test (:name :fixnum*-lifetimes) + (checked-compile-and-assert + () + `(lambda (a b) + (declare ((integer -8394154896 -1950772105) b)) + a + (round (+ b 4611686018427387903) + (let ((divisor (expt b 2))) + divisor))) + ((0 -5000000000) (values 0 4611686013427387903)))) + +(with-test (:name :ash-*-cycle) + (checked-compile-and-assert + () + `(lambda (x) + (truly-the fixnum (* (the fixnum x) -4))) + ((4) -16))) + +(with-test (:name :-unsigned=>signed) + (checked-compile-and-assert + () + `(lambda (a b) + (declare ((integer #.(- (expt 2 sb-vm:n-word-bits) 10) + #.(- (expt 2 sb-vm:n-word-bits) 1)) + a b)) + (- a b)) + (((- (expt 2 sb-vm:n-word-bits) 10) (- (expt 2 sb-vm:n-word-bits) 9)) -1))) + +(with-test (:name :>=-fixnum-integer) + (checked-compile-and-assert + () + `(lambda (a b) + (declare (fixnum a)) + (and (integerp b) + (>= a b))) + ((1 2) nil) + ((2 2) t) + ((3 2) t)) + (checked-compile-and-assert + () + `(lambda (a b) + (declare (fixnum a)) + (and (integerp b) + (<= a b))) + ((1 2) t) + ((2 2) t) + ((3 2) nil))) + +(with-test (:name :ash-signed-negation-overflow) + (checked-compile-and-assert + () + `(lambda (a b) + (declare (fixnum a) + (sb-vm:signed-word b)) + (truly-the sb-vm:signed-word (ash a b))) + ((-44 (- (expt 2 (1- sb-vm:n-word-bits)))) -1) + ((44 2) 176))) + +(with-test (:name :-constant-mnf) + (checked-compile-and-assert + () + `(lambda (a) + (logand most-positive-fixnum + (- (the fixnum a) most-negative-fixnum))) + ((10) 10))) + +(with-test (:name :unary-truncate-discard-second-value) + (checked-compile-and-assert + () + `(lambda (a) + (truncate (expt (complex a 0) 0)) + 1) + ((1) 1))) + +(with-test (:name :unary-truncate-discard-second-value.2) + (checked-compile-and-assert + (:allow-style-warnings t) + `(lambda (a b) + (boole boole-nand + (dpb (* b (unwind-protect 0 b)) (byte 31 28) a) + (ignore-errors + (truncate + (eval + (values 1 2)))))) + ((1 2) -2))) + +(with-test (:name :logtest-immediate) + (checked-compile-and-assert + () + `(lambda (x) + (logtest (- (expt 2 63) 3) (the fixnum x))) + ((1) t) + ((2) nil))) + +(with-test (:name :logand-negative-derive) + (assert + (subtypep (second (third (sb-kernel:%simple-fun-type + (checked-compile + `(lambda (a b) + (declare ((not unsigned-byte) a b)) + (logand a b)))))) + '(integer * -1)))) + +(with-test (:name :ash-mod64-constant-folding) + (checked-compile-and-assert + () + `(lambda (a d) + (declare (fixnum a) + ((unsigned-byte 64) d)) + (setq a -64) + (logand d (ash -1 a))) + ((0 3) 3))) diff --git a/tests/array.pure.lisp b/tests/array.pure.lisp index 5c7f96bb2a..bf913ce2a6 100644 --- a/tests/array.pure.lisp +++ b/tests/array.pure.lisp @@ -17,7 +17,8 @@ (let ((testcases '(;; Bug 126, confusion between high-level default string ;; initial element #\SPACE and low-level default array ;; element #\NULL, is gone. - (#\null (make-array 11 :element-type 'character) simple-string) + (#\null (make-array 11 :element-type 'character :initial-element #\null) + simple-string) (#\space (make-string 11 :initial-element #\space) string) (#\* (make-string 11 :initial-element #\*)) (#\null (make-string 11)) @@ -25,10 +26,11 @@ (#\x (make-string 11 :initial-element #\x)) ;; And the other tweaks made when fixing bug 126 didn't ;; mess things up too badly either. - (0 (make-array 11) simple-vector) + (0 (make-array 11 :initial-element 0) simple-vector) (nil (make-array 11 :initial-element nil)) (12 (make-array 11 :initial-element 12)) - (0 (make-array 11 :element-type '(unsigned-byte 4)) (simple-array (unsigned-byte 4) (*))) + (0 (make-array 11 :element-type '(unsigned-byte 4) :initial-element 0) + (simple-array (unsigned-byte 4) (*))) (12 (make-array 11 :element-type '(unsigned-byte 4) :initial-element 12))))) @@ -197,6 +199,12 @@ (checked-compile `(lambda () (make-array 0 :element-type 'string))) (checked-compile `(lambda () (make-array '(0 2) :element-type 'string)))) +(with-test (:name (make-array standard-char)) + ;; Maybe this is a kludge, but STANDARD-CHAR should just work, + ;; I don't care if #\nul is nonstandard. Because, seriously? + (checked-compile '(lambda () + (make-array 5 :fill-pointer 0 :element-type 'standard-char)))) + (with-test (:name :big-array) ;; we used to have leakage from cross-compilation hosts of the INDEX ;; type, which prevented us from actually using all the large array @@ -225,9 +233,11 @@ (() 4 :test (lambda (values expected) (= (length (first values)) (first expected)))))) +;;; I have no idea how this is testing adjust-array with an initial-element ! (with-test (:name (make-array adjust-array :initial-element)) (let ((x (make-array nil :initial-element 'foo))) - (adjust-array x nil) + ;; make the result look used + (opaque-identity (adjust-array x nil)) (assert (eql (aref x) 'foo)))) ;;; BUG 315: "no bounds check for access to displaced array" @@ -295,13 +305,14 @@ (handler-case (let ((array (make-array 12))) (assert (not (array-has-fill-pointer-p array))) - (adjust-array array 12 :fill-pointer t) + ;; make the result look used + (opaque-identity (adjust-array array 12 :fill-pointer t)) array) (type-error () :good))))) (with-test (:name (adjust-array :multidimensional)) - (let ((ary (make-array '(2 2)))) + (let ((ary (make-array '(2 2) :initial-element 0))) ;; SBCL used to give multidimensional arrays a bogus fill-pointer (assert (not (array-has-fill-pointer-p (adjust-array ary '(2 2))))))) @@ -405,7 +416,10 @@ (test 'inline) (test 'notinline))) -(with-test (:name (make-array :size-overflow)) +(with-test (:name (make-array :size-overflow) + ;; size limit is small enough that this fails by not failing + ;; in the expected way + :skipped-on :ubsan) ;; 1-bit fixnum tags make array limits overflow the word length ;; when converted to bytes (when (= sb-vm:n-fixnum-tag-bits 1) @@ -433,8 +447,17 @@ (checked-compile-and-assert (:optimize '(:safety 0)) `(lambda (x) ;; Strings are null-terminated for C interoperability - (char "abcd" x)) + (char #.(coerce "abcd" 'simple-base-string) x)) ((4) #\Nul))) +(defun check-bound-multiple-reads (x i) + (let* ((x (truly-the simple-vector x)) + (l (sb-c::vector-length x))) + (sb-kernel:%check-bound x l i) + l)) +(compile 'check-bound-multiple-reads) +(with-test (:name :check-bound-vop-optimize) + ;; could have crashed with the bad optimizer + (check-bound-multiple-reads #(a b c) 2)) (with-test (:name (adjust-array :transform)) (checked-compile-and-assert () @@ -443,7 +466,7 @@ (() #(4 5 6) :test #'equalp))) (with-test (:name (adjust-array :fill-pointer)) - (let ((array (make-array 10 :fill-pointer t))) + (let ((array (make-array 10 :fill-pointer t :initial-element 0))) (assert (= (fill-pointer (adjust-array array 5 :fill-pointer 2)) 2)))) @@ -523,6 +546,24 @@ (assert (not (array-has-fill-pointer-p (funcall fun nil)))) (assert (= (length (funcall fun nil)) 3)))) +(with-test (:name (make-array :transform :non-constant-fill-pointer)) + ;; Known adjustable with any fill-pointer can be inlined + (let ((fun (checked-compile '(lambda (n fillp) + (make-array (the (mod 20) n) + :adjustable t :fill-pointer fillp))))) + (assert (not (ctu:find-named-callees fun :name 'sb-kernel:%make-array))) + (let ((a (funcall fun 10 3))) + (assert (= (length a) 3)) + (assert (= (array-dimension a 0) 10)))) + ;; Non-adjustable w/ non-constant numeric fill-pointer can be inlined + (let ((fun (checked-compile '(lambda (n) + (make-array (the (mod 20) n) + :fill-pointer (floor n 2)))))) + (assert (not (ctu:find-named-callees fun :name 'sb-kernel:%make-array))) + (let ((a (funcall fun 10))) + (assert (= (length a) 5)) + (assert (= (array-dimension a 0) 10))))) + (with-test (:name :check-bound-fixnum-check) (checked-compile-and-assert (:optimize :safe) `(lambda (x) (aref #100(a) x)) @@ -538,6 +579,10 @@ (with-test (:name (make-array :strange-type-specifiers)) (assert (stringp (make-array 10 :element-type (opaque-identity '(base-char))))) (assert (stringp (make-array 10 :element-type (opaque-identity '(standard-char))))) + ;; If there are no extended characters (as on #-sb-unicode), then EXTENDED-CHAR is + ;; the empty type. You'll get exactly what you ask for: an array which can hold + ;; nothing. It's not a string, which is the right answer. + #+sb-unicode (assert (stringp (make-array 10 :element-type (opaque-identity '(extended-char))))) (assert (bit-vector-p (make-array 10 :element-type (opaque-identity '(bit)))))) @@ -553,7 +598,7 @@ (checked-compile-and-assert () '(lambda (type) - (make-array 1 :element-type type)) + (make-array 1 :element-type type :initial-element 0)) (('(or (eql -16) unsigned-byte)) #(0) :test #'equalp))) (with-test (:name :check-bound-signed-bound-notes @@ -590,3 +635,71 @@ (lambda (x) (make-array 1 :displaced-to (the vector x) :initial-contents '(1)))) :allow-warnings t)))) + +(with-test (:name :check-bound-type-error) + (assert (nth-value 2 + (checked-compile + `(lambda (p) + (unless (svref p 0) + (svref p nil))) + :allow-warnings t)))) + +(with-test (:name :array-has-fill-pointer-p-folding) + (assert (equal (sb-kernel:%simple-fun-type + (checked-compile `(lambda (x) + (declare ((array * (* *)) x)) + (array-has-fill-pointer-p x)))) + `(function ((array * (* *))) (values null &optional))))) + +(with-test (:name :array-has-fill-pointer-p-transform) + (checked-compile-and-assert + () + `(lambda (n) + (let ((a (make-array n))) + (declare (vector a)) + (map-into a #'identity a))) + ((0) #() :test #'equalp))) + +(with-test (:name :displaced-index-offset-disallow-nil) + (assert-error (eval '(make-array 4 :displaced-index-offset nil)))) + +(with-test (:name :adjust-array-copies-above-fill-pointer) + (let ((a (make-array 4 :fill-pointer 2 :initial-contents '(a b c d)))) + (let ((b (adjust-array a 6 :initial-element 'e))) + (assert (eq (aref b 2) 'c)) + (assert (eq (aref b 3) 'd)) + (assert (eq (aref b 4) 'e)) + (assert (eq (aref b 5) 'e))))) + +(with-test (:name :test-array-dimensions-other-pointer-check) + (checked-compile-and-assert + () + `(lambda (a) + (typep a '(simple-array t (2 1)))) + ((1) nil) + ((#2A((1) (1))) t))) + +(with-test (:name :typep-constant-%array-data-folding) + (checked-compile-and-assert + () + `(lambda () + (typep "abcd" '(simple-array t 2))) + (() nil))) + +(with-test (:name :vector-push-extend-specialized) + (let ((extend (checked-compile `(lambda (e a) + (vector-push-extend e a) + a)))) + (loop for saetp across sb-vm:*specialized-array-element-type-properties* + for type = (sb-vm:saetp-specifier saetp) + when type + do + (let* ((value (sb-vm:saetp-initial-element-default saetp)) + (value (if (characterp value) + (code-char (1+ (char-code value))) + (1+ value)))) + (assert (eql (aref (funcall extend value (make-array 1 :element-type type + :adjustable t + :fill-pointer t)) + 1) + value)))))) diff --git a/tests/assembler.pure.lisp b/tests/assembler.pure.lisp index caebe585d4..a15008dc8c 100644 --- a/tests/assembler.pure.lisp +++ b/tests/assembler.pure.lisp @@ -42,49 +42,59 @@ ;;; Create some special variables that are needed for tests ;;; since they no longer exist as part of the vm definition. #+x86-64 -(progn -(defvar al-tn (reg-in-size rax-tn :byte)) -(defvar bl-tn (reg-in-size rbx-tn :byte)) -(defvar cl-tn (reg-in-size rcx-tn :byte)) -(defvar dl-tn (reg-in-size rdx-tn :byte)) -(defvar dil-tn (reg-in-size rdi-tn :byte)) -(defvar r8b-tn (reg-in-size r8-tn :byte)) -(defvar ax-tn (reg-in-size rax-tn :word)) -(defvar bx-tn (reg-in-size rbx-tn :word)) -(defvar cx-tn (reg-in-size rcx-tn :word)) -(defvar r8w-tn (reg-in-size r8-tn :word)) -(defvar eax-tn (reg-in-size rax-tn :dword)) -(defvar ebx-tn (reg-in-size rbx-tn :dword)) -(defvar ecx-tn (reg-in-size rcx-tn :dword)) -(defvar edx-tn (reg-in-size rdx-tn :dword)) -(defvar edi-tn (reg-in-size rdi-tn :dword)) -(defvar r8d-tn (reg-in-size r8-tn :dword)) -(defvar r9d-tn (reg-in-size r9-tn :dword))) +(macrolet ((define (name qword-tn size) + `(defvar ,name + (sb-x86-64-asm::sized-thing (sb-x86-64-asm::tn-reg ,qword-tn) + ,size)))) + (define al rax-tn :byte) + (define bl rbx-tn :byte) + (define cl rcx-tn :byte) + (define dl rdx-tn :byte) + (define dil rdi-tn :byte) + (define r8b r8-tn :byte) -(test-util:with-test (:name :assemble-movti-instruction :skipped-on (not :x86-64)) + (define ax rax-tn :word) + (define bx rbx-tn :word) + (define cx rcx-tn :word) + (define r8w r8-tn :word) + + (define eax rax-tn :dword) + (define ebx rbx-tn :dword) + (define ecx rcx-tn :dword) + (define edx rdx-tn :dword) + (define edi rdi-tn :dword) + (define r8d r8-tn :dword) + (define r9d r9-tn :dword)) +#+x86 +(progn (defglobal al al-tn) (defglobal ax ax-tn) (defglobal eax eax-tn) + (defglobal bl bl-tn) (defglobal bx bx-tn) (defglobal ebx ebx-tn) + (defglobal cl cl-tn) (defglobal cx cx-tn) (defglobal ecx ecx-tn) + (defglobal dl dl-tn) + (defglobal edi edi-tn)) +(test-util:with-test (:name :assemble-movnti-instruction :skipped-on (not :x86-64)) (flet ((test-movnti (dst src expect) (test-assemble `(movnti ,dst ,src) expect))) - (test-movnti (ea 57 rdi-tn) eax-tn "0FC34739 MOVNTI [RDI+57], EAX") + (test-movnti (ea 57 rdi-tn) eax "0FC34739 MOVNTI [RDI+57], EAX") (test-movnti (ea rax-tn) r12-tn "4C0FC320 MOVNTI [RAX], R12"))) (test-util:with-test (:name :assemble-crc32 :skipped-on (not :x86-64)) ;; Destination size = :DWORD - (test-assemble `(crc32 :byte ,eax-tn ,(ea rbp-tn)) + (test-assemble `(crc32 :byte ,eax ,(ea rbp-tn)) "F20F38F04500 CRC32 EAX, BYTE PTR [RBP]") - (test-assemble `(crc32 :byte ,eax-tn (,rcx-tn . :high-byte)) + (test-assemble `(crc32 :byte ,eax (,rcx-tn . :high-byte)) "F20F38F0C5 CRC32 EAX, CH") - (test-assemble `(crc32 :byte ,eax-tn ,dil-tn) + (test-assemble `(crc32 :byte ,eax ,dil) "F2400F38F0C7 CRC32 EAX, DIL") - (test-assemble `(crc32 :word ,eax-tn ,(ea rbp-tn)) + (test-assemble `(crc32 :word ,eax ,(ea rbp-tn)) "66F20F38F14500 CRC32 EAX, WORD PTR [RBP]") - (test-assemble `(crc32 :dword ,eax-tn ,(ea rbp-tn)) + (test-assemble `(crc32 :dword ,eax ,(ea rbp-tn)) "F20F38F14500 CRC32 EAX, DWORD PTR [RBP]") ;; these check that the presence of REX does not per se change the width. - (test-assemble `(crc32 :byte ,r9d-tn ,(ea r14-tn r15-tn)) + (test-assemble `(crc32 :byte ,r9d ,(ea r14-tn r15-tn)) "F2470F38F00C3E CRC32 R9D, BYTE PTR [R14+R15]") - (test-assemble `(crc32 :word ,r9d-tn ,(ea r14-tn r15-tn)) + (test-assemble `(crc32 :word ,r9d ,(ea r14-tn r15-tn)) "66F2470F38F10C3E CRC32 R9D, WORD PTR [R14+R15]") - (test-assemble `(crc32 :dword ,r9d-tn ,(ea r14-tn r15-tn)) + (test-assemble `(crc32 :dword ,r9d ,(ea r14-tn r15-tn)) "F2470F38F10C3E CRC32 R9D, DWORD PTR [R14+R15]") ;; Destination size = :QWORD (test-assemble `(crc32 :byte ,rax-tn ,(ea rbp-tn)) @@ -113,31 +123,30 @@ ;; ADD/SUB/etc (test-assemble `(and ,rax-tn #xffffffffffffff8c) "4883E08C AND RAX, -116") - (test-assemble `(sub ,eax-tn #xfffffffc) "83E8FC SUB EAX, -4") + (test-assemble `(sub ,eax #xfffffffc) "83E8FC SUB EAX, -4") ;; Register AX could use the special 1-byte opcode and non-sign-extended ;; imm16 operand; the encoding length is the same either way. - (test-assemble `(or ,ax-tn #xfff7) "6683C8F7 OR AX, -9")) + (test-assemble `(or ,ax #xfff7) "6683C8F7 OR AX, -9")) (test-util:with-test (:name :assemble-movsx :skipped-on (not :x86-64)) ;; source = :BYTE, signed - (check-does-not-assemble `(movsx (:byte :byte) ,r8b-tn ,cl-tn)) - (test-assemble `(movsx (:byte :word) ,r8w-tn ,cl-tn) "66440FBEC1 MOVSX R8W, CL") - (test-assemble `(movsx (:byte :dword) ,r8d-tn ,cl-tn) "440FBEC1 MOVSX R8D, CL") - (test-assemble `(movsx (:byte :qword) ,r8-tn ,cl-tn) "4C0FBEC1 MOVSX R8, CL") + (check-does-not-assemble `(movsx (:byte :byte) ,r8b ,cl)) + (test-assemble `(movsx (:byte :word) ,r8w ,cl) "66440FBEC1 MOVSX R8W, CL") + (test-assemble `(movsx (:byte :dword) ,r8d ,cl) "440FBEC1 MOVSX R8D, CL") + (test-assemble `(movsx (:byte :qword) ,r8-tn ,cl) "4C0FBEC1 MOVSX R8, CL") ;; source = :BYTE, unsigned - (check-does-not-assemble `(movzx (:byte :byte) ,r8b-tn ,cl-tn)) - (test-assemble `(movzx (:byte :word) ,r8w-tn ,cl-tn) "66440FB6C1 MOVZX R8W, CL") - (test-assemble `(movzx (:byte :dword) ,r8d-tn ,cl-tn) "440FB6C1 MOVZX R8D, CL") - (test-assemble `(movzx (:byte :qword) ,r8-tn ,cl-tn) "440FB6C1 MOVZX R8D, CL") ; R8D, not R8 + (check-does-not-assemble `(movzx (:byte :byte) ,r8b ,cl)) + (test-assemble `(movzx (:byte :word) ,r8w ,cl) "66440FB6C1 MOVZX R8W, CL") + (test-assemble `(movzx (:byte :dword) ,r8d ,cl) "440FB6C1 MOVZX R8D, CL") + (test-assemble `(movzx (:byte :qword) ,r8-tn ,cl) "4C0FB6C1 MOVZX R8, CL") ;; source = :WORD, signed - (test-assemble `(movsx (:word :dword) ,r8d-tn ,cx-tn) "440FBFC1 MOVSX R8D, CX") - (test-assemble `(movsx (:word :qword) ,r8-tn ,cx-tn) "4C0FBFC1 MOVSX R8, CX") + (test-assemble `(movsx (:word :dword) ,r8d ,cx) "440FBFC1 MOVSX R8D, CX") + (test-assemble `(movsx (:word :qword) ,r8-tn ,cx) "4C0FBFC1 MOVSX R8, CX") ;; source = :WORD, unsigned - (test-assemble `(movzx (:word :dword) ,r8d-tn ,cx-tn) "440FB7C1 MOVZX R8D, CX") - (test-assemble `(movzx (:word :qword) ,r8-tn ,cx-tn) "440FB7C1 MOVZX R8D, CX") ; R8D, not R8 + (test-assemble `(movzx (:word :dword) ,r8d ,cx) "440FB7C1 MOVZX R8D, CX") + (test-assemble `(movzx (:word :qword) ,r8-tn ,cx) "4C0FB7C1 MOVZX R8, CX") ;; source = :DWORD, signed and unsigned - (test-assemble `(movsx (:dword :qword) ,r8-tn ,ecx-tn) "4C63C1 MOVSX R8, ECX") - (test-assemble `(movzx (:dword :qword) ,r8-tn ,ecx-tn) "448BC1 MOV R8D, ECX")) + (test-assemble `(movsx (:dword :qword) ,r8-tn ,ecx) "4C63C1 MOVSX R8, ECX")) (test-util:with-test (:name :disassemble-movabs-instruction :skipped-on (not :x86-64)) (let* ((bytes (coerce '(#x48 #xA1 8 7 6 5 4 3 2 1 @@ -167,57 +176,68 @@ (concatenate 'string (subseq expect 0 p) #+x86 "EBP" #+x86-64 "RBP" (subseq expect (+ p 3)))))) - (test-assemble inst expect)) - (memref (size) (make-ea size :base #+x86 ebp-tn #+x86-64 rbp-tn))) - (try `(bt ,(memref :word) ,ax-tn) "660FA34500 BT WORD PTR [$fp], AX") - (try `(bt ,(memref :dword) ,eax-tn) "0FA34500 BT DWORD PTR [$fp], EAX") + (destructuring-bind (opcode operand1 operand2 . more) inst + (when (or (typep operand1 '(cons (eql memref))) + (typep operand2 '(cons (eql memref)))) + #+x86-64 + (let ((prefix (second (if (consp operand1) operand1 operand2)))) + (flet ((new-ea (operand) (if (consp operand) (ea rbp-tn) operand))) + (setf inst + (list* opcode prefix (new-ea operand1) (new-ea operand2) more)))) + #+x86 + (flet ((new-ea (operand) + (if (consp operand) (make-ea (second operand) :base ebp-tn) operand))) + (setf inst (list* opcode (new-ea operand1) (new-ea operand2) more))))) + (test-assemble inst expect))) + (try `(bt (memref :word) ,ax) "660FA34500 BT WORD PTR [$fp], AX") + (try `(bt (memref :dword) ,eax) "0FA34500 BT DWORD PTR [$fp], EAX") #+x86-64 - (try `(bt ,(memref :qword) ,rax-tn) "480FA34500 BT QWORD PTR [$fp], RAX") - (try `(bt ,(memref :word) 3) "660FBA650003 BT WORD PTR [$fp], 3") - (try `(bt ,(memref :dword) 3) "0FBA650003 BT DWORD PTR [$fp], 3") + (try `(bt (memref :qword) ,rax-tn) "480FA34500 BT QWORD PTR [$fp], RAX") + (try `(bt (memref :word) 3) "660FBA650003 BT WORD PTR [$fp], 3") + (try `(bt (memref :dword) 3) "0FBA650003 BT DWORD PTR [$fp], 3") #+x86-64 - (try `(bt ,(memref :qword) 3) "480FBA650003 BT QWORD PTR [$fp], 3") + (try `(bt (memref :qword) 3) "480FBA650003 BT QWORD PTR [$fp], 3") ;; - (try `(shld ,eax-tn ,ebx-tn :cl) "0FA5D8 SHLD EAX, EBX, CL") - (try `(shld ,(memref :word) ,bx-tn 6) "660FA45D0006 SHLD [$fp], BX, 6") - (try `(shld ,(memref :dword) ,ebx-tn 6) "0FA45D0006 SHLD [$fp], EBX, 6") + (try `(shld ,eax ,ebx :cl) "0FA5D8 SHLD EAX, EBX, CL") + (try `(shld (memref :word) ,bx 6) "660FA45D0006 SHLD [$fp], BX, 6") + (try `(shld (memref :dword) ,ebx 6) "0FA45D0006 SHLD [$fp], EBX, 6") #+x86-64 - (try `(shld ,(memref :qword) ,rbx-tn 6) "480FA45D0006 SHLD [$fp], RBX, 6") + (try `(shld (memref :qword) ,rbx-tn 6) "480FA45D0006 SHLD [$fp], RBX, 6") ;; - (try `(add ,al-tn #x7f) "047F ADD AL, 127") - (try `(add ,ax-tn #x7fff) "6605FF7F ADD AX, 32767") - (try `(add ,eax-tn #x7fffffff) "05FFFFFF7F ADD EAX, 2147483647") + (try `(add ,al #x7f) "047F ADD AL, 127") + (try `(add ,ax #x7fff) "6605FF7F ADD AX, 32767") + (try `(add ,eax #x7fffffff) "05FFFFFF7F ADD EAX, 2147483647") #+x86-64 (try `(add ,rax-tn #x7fffffff) "4805FFFFFF7F ADD RAX, 2147483647") ;; - (try `(add ,bl-tn #x7f) "80C37F ADD BL, 127") - (try `(add ,bx-tn #x7fff) "6681C3FF7F ADD BX, 32767") - (try `(add ,ebx-tn #x7fffffff) "81C3FFFFFF7F ADD EBX, 2147483647") + (try `(add ,bl #x7f) "80C37F ADD BL, 127") + (try `(add ,bx #x7fff) "6681C3FF7F ADD BX, 32767") + (try `(add ,ebx #x7fffffff) "81C3FFFFFF7F ADD EBX, 2147483647") #+x86-64 (try `(add ,rbx-tn #x7fffffff) "4881C3FFFFFF7F ADD RBX, 2147483647") ;; - (try `(add ,ax-tn #x7f) "6683C07F ADD AX, 127") - (try `(add ,eax-tn #x7f) "83C07F ADD EAX, 127") + (try `(add ,ax #x7f) "6683C07F ADD AX, 127") + (try `(add ,eax #x7f) "83C07F ADD EAX, 127") #+x86-64 (try `(add ,rax-tn #x7f) "4883C07F ADD RAX, 127") ;; - (try `(add ,(memref :byte) ,cl-tn) "004D00 ADD [$fp], CL") - (try `(add ,(memref :word) ,cx-tn) "66014D00 ADD [$fp], CX") - (try `(add ,(memref :dword) ,ecx-tn) "014D00 ADD [$fp], ECX") + (try `(add (memref :byte) ,cl) "004D00 ADD [$fp], CL") + (try `(add (memref :word) ,cx) "66014D00 ADD [$fp], CX") + (try `(add (memref :dword) ,ecx) "014D00 ADD [$fp], ECX") #+x86-64 - (try `(add ,(memref :qword) ,rcx-tn) "48014D00 ADD [$fp], RCX") - (try `(add ,cl-tn ,(memref :byte)) "024D00 ADD CL, [$fp]") - (try `(add ,cx-tn ,(memref :word)) "66034D00 ADD CX, [$fp]") - (try `(add ,ecx-tn ,(memref :dword)) "034D00 ADD ECX, [$fp]") + (try `(add (memref :qword) ,rcx-tn) "48014D00 ADD [$fp], RCX") + (try `(add ,cl (memref :byte)) "024D00 ADD CL, [$fp]") + (try `(add ,cx (memref :word)) "66034D00 ADD CX, [$fp]") + (try `(add ,ecx (memref :dword)) "034D00 ADD ECX, [$fp]") #+x86-64 - (try `(add ,rcx-tn ,(memref :qword)) "48034D00 ADD RCX, [$fp]") + (try `(add ,rcx-tn (memref :qword)) "48034D00 ADD RCX, [$fp]") )) (test-util:with-test (:name :disassemble-imul :skipped-on (not (or :x86 :x86-64))) - (test-assemble `(imul ,dl-tn) "F6EA IMUL DL") - (test-assemble `(imul ,cx-tn) "66F7E9 IMUL CX") - (test-assemble `(imul ,ebx-tn) "F7EB IMUL EBX") - (test-assemble `(imul ,edi-tn 92) "6BFF5C IMUL EDI, EDI, 92")) + (test-assemble `(imul ,dl) "F6EA IMUL DL") + (test-assemble `(imul ,cx) "66F7E9 IMUL CX") + (test-assemble `(imul ,ebx) "F7EB IMUL EBX") + (test-assemble `(imul ,edi 92) "6BFF5C IMUL EDI, EDI, 92")) (test-util:with-test (:name :disassemble-fs-prefix :skipped-on (not (or :x86-64))) (let ((bytes (coerce '(#x64 #xF0 #x44 #x08 #x04 #x25 #x00 #x04 #x10 #x20) @@ -234,7 +254,7 @@ ;;; which I guess was broken. immobile-code has no fdefns in static space. (test-util:with-test (:name :disassemble-static-fdefn :skipped-on (or (not :x86-64) :immobile-code)) - (assert (< (get-lisp-obj-address (sb-kernel::find-fdefn 'sb-impl::sub-gc)) + (assert (< (get-lisp-obj-address (sb-int:find-fdefn 'sb-impl::sub-gc)) sb-vm:static-space-end)) ;; Cause SUB-GC to become un-statically-linked (progn (trace sb-impl::sub-gc) (untrace)) @@ -267,7 +287,7 @@ "40F6C60F TEST SIL, 15") (test-assemble `(movd ,float0-tn ,rax-tn) "660F6EC0 MOVD XMM0, EAX") - (test-assemble `(movq ,float0-tn ,eax-tn) + (test-assemble `(movq ,float0-tn ,eax) "66480F6EC0 MOVQ XMM0, RAX")) (test-util:with-test (:name :assemble-high-byte-regs :skipped-on (not :x86-64)) diff --git a/tests/autoclose-stream.impure.lisp b/tests/autoclose-stream.impure.lisp new file mode 100644 index 0000000000..d51a60153a --- /dev/null +++ b/tests/autoclose-stream.impure.lisp @@ -0,0 +1,65 @@ +;;; This is in its own file to avoid being the recipient +;;; of unanticipated effects on the file descriptor space +;;; due to co-located tests. + +;;; don't know how to check validity of a HANDLE in the win32 api +#-unix (invoke-restart 'run-tests::skip-file) + +(defun fd-has-finalizer-p (fd) + ;; Finalizer function can be: + ;; 1. a function - finalizer that was not created with :DONT-SAVE. + ;; 2. a single list of a function - a finalizer that was created with :DONT-SAVE + ;; 3. a vector - more than one finalizer, each being form 1 or form 2. + (flet ((checkit (thing) + (when (and (sb-kernel:closurep thing) + (eql (sb-kernel:%closure-index-ref thing 0) fd)) + (let ((underlying (sb-kernel:%closure-fun thing))) + (when (and (sb-kernel:simple-fun-p underlying) + (equal (sb-kernel:%simple-fun-name underlying) + '(lambda () :in sb-sys:make-fd-stream))) + (return-from fd-has-finalizer-p t)))))) + (let ((v sb-impl::**finalizer-store**)) + (loop for i from 3 below (length v) + do + (let ((entry (aref v i))) + (typecase entry + (list (checkit (car entry))) + (function (checkit entry)) + (vector + (sb-int:dovector (entry entry) + (checkit (if (listp entry) (car entry) entry)))))))))) + +(defvar *fds*) +(defun make-streams () + (let (streams) + (dotimes (i 6) + (push (open "autoclose-stream.impure.lisp") streams)) + (dolist (stream streams) + (assert (fd-has-finalizer-p (sb-impl::fd-stream-fd stream)))) + (setq *fds* + (mapcar (lambda (x) + (cons (sb-impl::fd-stream-fd x) (make-weak-pointer x))) + streams)) + (dolist (fd *fds*) + (let ((errno (nth-value 1 (sb-unix:unix-lseek (car fd) 0 sb-unix:l_incr)))) + (assert (zerop errno)))))) + +(defun assert-invalid-file-descriptor (fd) + (let ((errno (nth-value 1 (sb-unix:unix-lseek fd 0 sb-unix:l_incr)))) + (assert (= errno sb-unix:ebadf)))) + +(compile 'make-streams) + +(with-test (:name :finalizer-closes-fdstream) + (make-streams) + (gc) + (sb-kernel:run-pending-finalizers) + (sb-sys:scrub-control-stack) + (let ((nsmashed 0)) + (dolist (entry *fds*) + (let ((fd (car entry)) + (wp (cdr entry))) + (unless (weak-pointer-value wp) + (incf nsmashed) + (assert-invalid-file-descriptor fd)))) + (format t "::: INFO: ~d streams closed~%" nsmashed))) diff --git a/tests/avltree.pure.lisp b/tests/avltree.pure.lisp index aefb7f6919..04e68cacb1 100644 --- a/tests/avltree.pure.lisp +++ b/tests/avltree.pure.lisp @@ -1,5 +1,10 @@ +(load "bbtree-test-util.lisp") (use-package "SB-INT") + +#-sb-thread (invoke-restart 'run-tests::skip-file) ;; some of the symbols below disappear + (import 'sb-thread::(avlnode-key avlnode-data avlnode-left avlnode-right + avl-find<= avl-find>= avl-insert avl-delete avl-find avl-balance-factor avl-count)) @@ -47,7 +52,7 @@ node [shape=record];~%") (let (tree (prev-op :delete)) (setf (fill-pointer keys) 0) (loop - repeat n-ops for event from 0 do + for event from 0 repeat n-ops do (assert (= (avl-count tree) (length keys))) (let ((op (if (< (random 10) 5) @@ -95,3 +100,9 @@ node [shape=record];~%") (test-util:with-test (:name :avltree-random-tester) (random-operations 10 10 nil) (random-operations 10 200 nil)) + +(defun test-avlfind-inexact (n-nodes n-iterations) + (bbtree-test:test-find-inexact-macro avl-insert avl-find<= avl-find>= avlnode-key)) + +(test-util:with-test (:name :avl-find-inexact) + (bbtree-test:exercise-find-inexact 'test-avlfind-inexact)) diff --git a/tests/backq-const-fold.impure-cload.lisp b/tests/backq-const-fold.impure-cload.lisp new file mode 100644 index 0000000000..f08f90d1f0 --- /dev/null +++ b/tests/backq-const-fold.impure-cload.lisp @@ -0,0 +1,20 @@ +;;; Example from Jan Moringen + +(eval-when (:compile-toplevel :load-toplevel :execute) + (defclass foo () ())) + +(defconstant +foo+ + (if (boundp '+foo+) + +foo+ + (make-instance 'foo))) + +;;; The `(,+foo+) expression was being compile-time-folded to (#<foo +;;; xxxx>). Consequently it was unclear whether the #<foo> inside that +;;; list should require a load-form. We now track whether something +;;; comes from a named constant reference and dump the constant +;;; appropriately. +(defun foo () + `(,+foo+)) + +(defun bar () + `#(,+foo+)) diff --git a/tests/backtrace.impure.lisp b/tests/backtrace.impure.lisp index 31c553e0b0..662690953f 100644 --- a/tests/backtrace.impure.lisp +++ b/tests/backtrace.impure.lisp @@ -163,7 +163,7 @@ (verify-backtrace test-function expected-frames :details details :error t)) -(defvar *p* (namestring *load-truename*)) +(defvar *p* (namestring (if sb-c::*merge-pathnames* *load-truename* *load-pathname*))) (defvar *undefined-function-frame* '("undefined function")) @@ -189,7 +189,7 @@ (with-test (:name (:backtrace :undefined-function :bug-346) :skipped-on :interpreter - ;; Failures on SPARC, and probably HPPA are due to + ;; Failures on SPARC are due to ;; not having a full and valid stack frame for the ;; undefined function frame. See PPC ;; undefined_tramp for details. @@ -264,7 +264,7 @@ (defun throw-test () (throw 'no-such-tag t)) (with-test (:name (:backtrace :throw :no-such-tag) - :fails-on (and :sparc :linux)) + :fails-on (or :mips (and :sparc :linux))) (assert-backtrace #'throw-test '((throw-test)))) (funcall (checked-compile @@ -656,3 +656,22 @@ (sb-debug:print-backtrace :count 100 :stream stream)))) (foo 100 (let ((list (list t))) (nconc list list))))))) + +(with-test (:name :uninitialized-optionals) + (let ((fun (checked-compile + `(lambda (l &optional m n) + (declare (fixnum l)) + (values l m n))))) + (checked-compile-and-assert + () + `(lambda (fun &rest args) + (block nil + (handler-bind ((error + (lambda (c) + c + (return (cdar (sb-debug:list-backtrace :count 1)))))) + (apply fun args)))) + ((fun t) (list t *unavailable-argument* *unavailable-argument*) :test #'equalp) + ((fun t 1) (list t 1 *unavailable-argument*) :test #'equalp) + ((fun t 1 2) (list t 1 2) :test #'equalp) + ((fun 1 2 3) (values 1 2 3))))) diff --git a/tests/bad-code.pure.lisp b/tests/bad-code.pure.lisp index cb0222e60a..3051c7fcc6 100644 --- a/tests/bad-code.pure.lisp +++ b/tests/bad-code.pure.lisp @@ -270,8 +270,8 @@ (macrolet ((macro () `((lambda (x) (declare (number x)) - ',@ (loop repeat 10000 - for cons = (list 1) then (list cons) + ',@ (loop for cons = (list 1) then (list cons) + repeat 10000 finally (return cons))) t))) (macro))) @@ -343,10 +343,9 @@ (with-test (:name :sequence-lvar-dimensions-dotted-list) - (assert (nth-value 3 + (assert (nth-value 1 (checked-compile '(lambda () (position 0 '(1 2 0 5 . 5))) - :allow-style-warnings t :allow-warnings t)))) (with-test (:name :source-form-context-dotted-list) @@ -430,19 +429,27 @@ (search '(a . b) x)) :allow-warnings t)))) +(with-test (:name :improper-list.3) + (assert (nth-value 1 + (checked-compile + '(lambda () + (let ((x '(1 2 . 3))) + (position c x))) + :allow-warnings t)))) + (with-test (:name :call-nil) (checked-compile-and-assert - () - `(lambda () - (funcall nil)) - (() (condition 'undefined-function))) + () + `(lambda () + (funcall nil)) + (() (condition 'undefined-function))) (checked-compile-and-assert - () - `(lambda (x) - (if x - 10 - (funcall x))) - ((nil) (condition 'undefined-function)))) + () + `(lambda (x) + (if x + 10 + (funcall x))) + ((nil) (condition 'undefined-function)))) (with-test (:name (:valid-callable-argument :toplevel-xep)) (assert (nth-value 2 (checked-compile `(lambda (l) (find-if (lambda ()) l)) @@ -522,7 +529,7 @@ (f))) :allow-style-warnings t)))) -(with-test (:name :inapprorate-declare) +(with-test (:name :inappropriate-declare) (assert (nth-value 5 (checked-compile @@ -538,3 +545,159 @@ (checked-compile `(lambda () (prog1 10 (declare (optimize)))) :allow-failure t)))) + +(with-test (:name :reduce-initial-value) + (assert + (nth-value 2 + (checked-compile + `(lambda () + (reduce (lambda (x y) + (declare (fixnum x)) + (+ x (char-code y))) + "abc")) + :allow-warnings t))) + (assert + (nth-value 2 + (checked-compile + `(lambda () + (reduce (lambda (x y) + (declare (fixnum x)) + (+ x (char-code y))) + "abc" + :initial-value #\a)) + :allow-warnings t))) + (checked-compile-and-assert + () + `(lambda (s) + (declare (string s)) + (reduce (lambda (x y) + (declare (fixnum x)) + (+ x (char-code y))) + s + :initial-value 0)) + (("abc") 294))) + +(with-test (:name :get-defined-fun-lambda-list-error) + (assert (nth-value 1 (checked-compile '(lambda () (defun x 10)) :allow-failure t)))) + +(with-test (:name :dolist-mismatch) + (assert (nth-value 2 + (checked-compile '(lambda (x) + (dolist (x (the integer x)))) + :allow-warnings 'sb-int:type-warning)))) + +(with-test (:name :loop-list-mismatch) + (assert (nth-value 2 + (checked-compile '(lambda (x) + (loop for y in (the integer x))) + :allow-warnings 'sb-int:type-warning))) + (assert (nth-value 2 + (checked-compile '(lambda (x) + (loop for y on (the integer x))) + :allow-warnings 'sb-int:type-warning)))) + +(with-test (:name :mapcar-list-mismatch) + (assert (nth-value 2 + (checked-compile '(lambda (z) + (mapl #'car (the integer z))) + :allow-warnings 'sb-int:type-warning))) + (assert (nth-value 2 + (checked-compile '(lambda (f z x) + (mapcar f (the integer z) (the integer x))) + :allow-warnings 'sb-int:type-warning)))) + +(with-test (:name :aref-too-many-subscripts) + (assert (nth-value 2 + (checked-compile `(lambda (a) (aref a ,@(loop repeat array-rank-limit collect 0))) + :allow-warnings 'warning)))) + +(with-test (:name :defclass-bad-type) + (assert (nth-value 2 + (checked-compile + `(lambda () (defclass ,(gensym) () ((s :type (2))))) + :allow-warnings 'warning)))) + +(with-test (:name :macro-as-a-function) + (assert (nth-value 2 + (checked-compile + `(lambda (x) (find-if 'and x)) + :allow-warnings 'warning))) + (assert (nth-value 2 + (checked-compile + `(lambda (x) (funcall 'if x)) + :allow-warnings 'warning))) + (assert (nth-value 2 + (checked-compile + `(lambda (x) (mapcar 'and x)) + :allow-warnings 'warning)))) + +(with-test (:name :replace-type-mismatch) + (assert (nth-value 2 + (checked-compile + `(lambda (x y) + (declare (bit-vector x) + (string y)) + (replace x y :start1 10)) + :allow-warnings 'warning)))) + +(with-test (:name :substitute-type-mismatch) + (assert (nth-value 2 + (checked-compile + `(lambda (x) + (declare (string x)) + (substitute 10 #\a x)) + :allow-warnings 'warning)))) + +(with-test (:name :make-array-initial-contents-type-mismatch) + (assert (nth-value 2 + (checked-compile + `(lambda (n c) + (make-array n :element-type 'bit :initial-contents (the string c))) + :allow-warnings 'warning)))) + +(with-test (:name :make-array-initial-contents-constant-type-mismatch) + (assert (nth-value 2 + (checked-compile + `(lambda (n) + (make-array n :element-type 'bit :initial-contents '(a b c))) + :allow-warnings 'warning)))) + + +(with-test (:name :replace-constant-type-mismatch) + (assert (nth-value 2 + (checked-compile + `(lambda (x) + (declare (string x)) + (replace x '(1 2 3))) + :allow-warnings 'warning)))) + +(with-test (:name :fill-type-mismatch) + (assert (nth-value 2 + (checked-compile + `(lambda (x) + (declare (string x)) + (fill x 1)) + :allow-warnings 'warning)))) + +(with-test (:name :vector-push-type-mismatch) + (assert (nth-value 2 + (checked-compile + `(lambda (x) + (declare (string x)) + (vector-push 1 x)) + :allow-warnings 'warning))) + (assert (nth-value 2 + (checked-compile + `(lambda (x) + (declare (string x)) + (vector-push-extend 1 x)) + :allow-warnings 'warning)))) + +(with-test (:name :defmethod-malformed-let*) + (assert (nth-value 5 + (checked-compile + `(lambda () + (cl:defmethod ,(gensym) () + (let* ((a 1 2)) + a))) + :allow-failure t)))) diff --git a/tests/bad-mlf-test.lisp b/tests/bad-mlf-test.lisp index bc758c64f8..04b17721d7 100644 --- a/tests/bad-mlf-test.lisp +++ b/tests/bad-mlf-test.lisp @@ -1,5 +1,5 @@ (defun zook () - (declare (optimize sb-c::store-source-form)) + (declare (optimize sb-c:store-source-form)) (macrolet ((foo (x) (declare (ignore x)) ''hi)) diff --git a/tests/bbtree-test-util.lisp b/tests/bbtree-test-util.lisp new file mode 100644 index 0000000000..2c60e8fce3 --- /dev/null +++ b/tests/bbtree-test-util.lisp @@ -0,0 +1,62 @@ + +(defpackage "BBTREE-TEST" + (:use :cl) + (:export #:test-find-inexact-macro + #:exercise-find-inexact)) + +;;;; Tests of two different kinds of balanced binary trees + +(defmacro bbtree-test:test-find-inexact-macro (insertion-fun find<=-fun find>=-fun node-key) + `(let (integers) + ;; Generate N random integers + (dotimes (i n-nodes) + (loop + (let ((val (+ 5 (random 1000)))) + (unless (member val integers) + (push val integers) + (return))))) + (setq integers (coerce integers 'vector)) + (dotimes (i n-iterations) + ;; Try many different shuffles of the insertion order because each + ;; potentially yields a different tree. + (test-util:shuffle integers) + ;; Convert a tree + (let ((tree nil)) + (dotimes (i (length integers)) + (setq tree (,insertion-fun tree (svref integers i) (svref integers i)))) + (setq integers (sort integers #'<)) + (dotimes (i (length integers)) + (let ((this (svref integers i)) + (pred (if (> i 0) (svref integers (1- i)))) + (succ (if (< i (1- (length integers))) (svref integers (1+ i))))) + ;; THIS should be found exactly + (let ((answer (,find<=-fun this tree))) + (assert (eql (,node-key answer) this))) + (let ((answer (,find>=-fun this tree))) + (assert (eql (,node-key answer) this))) + ;; find this node by a smaller key using FIND>= + (unless (eql pred (1- this)) + (assert (eql (,node-key (,find>=-fun (1- this) tree)) this))) + ;; find this node by a larger key using FIND<= + (unless (eql succ (1+ this)) + (assert (eql (,node-key (,find<=-fun (1+ this) tree)) this))) + ;; check the boundary case of FIND<= and/or find the predecessor + (let ((answer (,find<=-fun (1- this) tree))) + (if pred + (assert (eql (,node-key answer) pred)) + (assert (not answer)))) + ;; check the boundary case of FIND>= and/or find the successor + (let ((answer (,find>=-fun (1+ this) tree))) + (if succ + (assert (eql (,node-key answer) succ)) + (assert (not answer)))))))))) + +(defun bbtree-test:exercise-find-inexact (fun) + (loop for n-nodes from 1 to 20 + do (funcall fun n-nodes + (case n-nodes + (1 1) + (2 4) + (3 10) + (t 100))))) + diff --git a/tests/benchmark.lisp b/tests/benchmark.lisp new file mode 100644 index 0000000000..7807b27e19 --- /dev/null +++ b/tests/benchmark.lisp @@ -0,0 +1,184 @@ + +(let ((*evaluator-mode* :compile)) + (with-compilation-unit () (load"run-tests"))) + +(in-package run-tests) +(pop *posix-argv*) +(defvar *logdir* (pop *posix-argv*)) +(defvar *njobs* (parse-integer (pop *posix-argv*))) +(require :sb-posix) + +(import '(sb-alien:alien-funcall sb-alien:extern-alien + sb-alien:int sb-alien:c-string sb-alien:unsigned)) + +;;; Ordered approximately in descending order by running time +(defvar *slow-tests* '("threads.impure" + "seq.impure" + "threads.pure" + "compiler.pure" + "timer.impure" + "bug-1180102.impure" + "gethash-concurrency.impure" + "arith-slow.pure")) + +(defvar *filter* nil) +(defun choose-order (tests) + (when *filter* + (let (strings) + (with-open-file (file *filter*) + (loop (let ((line (read-line file nil))) + (if line (push line strings) (return))))) + (setq tests (remove-if (lambda (x) (not (find x strings :test #'string=))) + tests)))) + (sort tests + (lambda (a b) + (let ((posn-a (or (position a *slow-tests* :test #'string=) + most-positive-fixnum)) + (posn-b (or (position b *slow-tests* :test #'string=) + most-positive-fixnum))) + (cond ((< posn-a posn-b) t) + ((> posn-a posn-b) nil) + (t (string< a b))))))) + +(defun output-metrics (c1 c2 c3 c4 testfile comment metricsfile) + (let ((summary + ;; FORMAT NIL produces simple-base-string when it can + (format nil "(~10d ~10d ~10d ~10d ~s ~s)~%" + c1 + c2 + c3 + c4 + testfile + comment))) + (sb-unix:unix-write metricsfile summary 0 (length summary)))) + +;; Conversion factor from nanoseconds to internal-time-units +(defconstant divisor (/ 1000000000 internal-time-units-per-second)) + +(defun sort-metrics (filename) + (let (original-list) + (with-open-file (f (make-pathname :type "lisp-expr" :defaults filename)) + (loop (let ((expr (read f nil))) + (unless expr (return)) + (destructuring-bind (a b c d name pf) expr + (let ((vt-less-compiler (- d (round (+ a b) divisor)))) + (push (cons vt-less-compiler expr) original-list)))))) + (with-open-file (f (make-pathname :type "txt" :defaults filename) + :direction :output :if-exists :supersede) + (format f " +; Version: ~A +; Parallelism: ~D +; Files: ~D +; +; COMPILE- COMPILE GC Total Less +; FILE compiler +; (thread) (thread) (process) +; virtual virtual real virtual virtual +; --------- ---------- -------- ---------- ---------- +" (lisp-implementation-version) *njobs* (length original-list)) + + (let ((c1 0) (c2 0) (c3 0) (c4 0) (c5 0)) + (dolist (line (sort original-list #'> :key #'car)) + (destructuring-bind (net cfile compile gc process filename pf) line + ;; get-internal-run-time returns microseconds + ;; but we've collected the compiler time in nanoseconds + (setq cfile (round cfile divisor) + compile (round compile divisor)) + (format f "~11d~12d~10d~12d~12d ~A~A~%" + cfile compile gc process net filename (if (eql pf :fail) " FAIL" "")) + (incf c1 cfile) + (incf c2 compile) + (incf c3 gc) + (incf c4 process) + (incf c5 net))) + (format f "~11d~12d~10d~12d~12d TOTAL~%" + c1 c2 c3 c4 c5))))) + +(defun parallel-execute-tests (files &optional (max-jobs *njobs*)) + (format t "Using ~D processes~%" max-jobs) + (let* ((subprocess-count 0) + (subprocess-list nil) + ;; Start timing only after all the DIRECTORY calls are done (above) + (start-time (get-internal-real-time)) + (losing) + (metricsfilename (format nil "~A/performance" *logdir*)) + (metricsfile + (sb-unix:unix-open (namestring (make-pathname :type "lisp-expr" + :defaults metricsfilename)) + (logior sb-unix:o_creat sb-unix:o_wronly sb-unix:o_append) + #o666))) + (labels ((wait () + ;; Though far from elegant, this is an easy way to figure out + ;; which tests are getting stuck, if any are. + #+nil (format t "Runner is waiting on: ~S~%" subprocess-list) + (multiple-value-bind (pid status) (sb-posix:wait) + (decf subprocess-count) + (let ((process (assoc pid subprocess-list)) + (code (ash status -8)) + (et)) + (unless process + (warn "Whoa! Process ~D is an unexpected child" pid) + (return-from wait (wait))) + (setq subprocess-list (delete process subprocess-list)) + (destructuring-bind ((filename . iteration) start-time) (cdr process) + (setq et (elapsed-time-from start-time)) + (cond ((eq code 104) + (format t "~A: success (~d µsec)~%" filename et)) + (t + (format t "~A~@[[~d]~]: status ~D (~d µsec)~%" + filename iteration code et) + (push (list filename iteration pid) losing))))))) + (elapsed-time-from (when) ; return value in microseconds + (round (- (get-internal-real-time) when) + (/ internal-time-units-per-second 1000000)))) + (dolist (file files) + (when (>= subprocess-count max-jobs) + (wait)) + (let ((pid (sb-posix:fork))) + (when (zerop pid) + ;; FILE is (filename . test-iteration) + (with-open-file (stream (format nil "~A/~a~@[-~d~]" + *logdir* (car file) (cdr file)) + :direction :output :if-exists :supersede) + (alien-funcall (extern-alien "dup2" (function int int int)) + (sb-sys:fd-stream-fd stream) 1) + (alien-funcall (extern-alien "dup2" (function int int int)) 1 2)) + (setq file (car file)) + ;; Send this to the log file, not the terminal + (setq *debug-io* (make-two-way-stream (make-concatenated-stream) + *error-output*)) + (let ((*features* (cons :parallel-test-runner *features*)) + (run-time-start (get-internal-run-time))) + (pure-runner (list (concatenate 'string file ".lisp")) + (if (search "-cload" file) 'cload-test 'load-test) + (make-broadcast-stream)) + (output-metrics sb-c::*compile-file-elapsed-time* + sb-c::*compile-elapsed-time* + *gc-run-time* + (- (get-internal-run-time) run-time-start) + file + (if (unexpected-failures) :fail :pass) + metricsfile) + (exit :code (if (unexpected-failures) 1 104)))) + (format t "~A: pid ~d~@[ (trial ~d)~]~%" (car file) pid (cdr file)) + (incf subprocess-count) + (push (list pid file (get-internal-real-time)) subprocess-list))) + (loop (if (plusp subprocess-count) (wait) (return))) + (format t "~&Total realtime: ~,,-6f sec~%" (elapsed-time-from start-time)) + (sb-unix:unix-close metricsfile) + (sort-metrics metricsfilename) + (when losing + (format t "~&Failing files:~%") + (dolist (filename losing) + (format t "~A~%" filename)) + (format t "==== Logs are in ~A ====~%" *logdir*) + (exit :code 1))))) + +(parallel-execute-tests + (mapcar #'list + (choose-order + (mapcar #'pathname-name + (append (pure-load-files) + (pure-cload-files) + (impure-load-files) + (impure-cload-files)))))) diff --git a/tests/benchmark.sh b/tests/benchmark.sh new file mode 100755 index 0000000000..ea7af9f68b --- /dev/null +++ b/tests/benchmark.sh @@ -0,0 +1,36 @@ +#!/bin/sh + +# This is copy-and-pasted from parallel-exec, removing: +# - use of SB-APROF, SB-SPROF +# - vop usage counts, GC stop-the-world timing +# - shell tests +# - anything else extraneous to running the tests. +# Obviously it would be better if some of this +# logic could be shared, especially the +# CHOOSE-ORDER function. + +if [ $# -ne 1 ] +then + echo $0: Need arg + exit 1 +fi + +logdir=${SBCL_PAREXEC_TMP:-$HOME}/sbcl-test-logs-$$ +echo ==== Writing logs to $logdir ==== +junkdir=${SBCL_PAREXEC_TMP:-/tmp}/junk +mkdir -p $junkdir $logdir + +case `uname` in + CYGWIN* | WindowsNT | MINGW* | MSYS*) + echo ";; Using -j$1" + echo "LOGDIR=$logdir" >$logdir/Makefile + ../run-sbcl.sh --script genmakefile.lisp >>$logdir/Makefile + exec $GNUMAKE -k -j $1 -f $logdir/Makefile + ;; +esac + +export TEST_DIRECTORY SBCL_HOME +TEST_DIRECTORY=$junkdir SBCL_HOME=../obj/sbcl-home exec ../src/runtime/sbcl \ + --noinform --core ../output/sbcl.core \ + --no-userinit --no-sysinit --noprint --disable-debugger $logdir $* \ + < benchmark.lisp diff --git a/tests/bit-bash.pure.lisp b/tests/bit-bash.pure.lisp new file mode 100644 index 0000000000..8433381244 --- /dev/null +++ b/tests/bit-bash.pure.lisp @@ -0,0 +1,483 @@ + +;;; explicitly test UB{8,16,32,64}-bash-copy +;;; for all interesting combinations of src-offset, dst-offset, +;;; i.e. where the number of initial/final elements within a word +;;; varies over all possible values. + +(defun test-bash-copiers-octet-or-larger () + (dolist (bits-per-element '(8 16 32 #+64-bit 64)) + (format t "~&Testing bits-per-element = ~d~%" bits-per-element) + (let* ((len 70) + (dest-control + (make-array len :element-type `(signed-byte ,bits-per-element))) + (dest + (make-array len :element-type `(signed-byte ,bits-per-element))) + (source + (make-array len :element-type `(signed-byte ,bits-per-element))) + (function + (intern (format nil "UB~D-BASH-COPY" bits-per-element) "SB-KERNEL")) + (*print-pretty* nil)) + (loop for i from 0 below len + for val downfrom -1 do (setf (aref source i) val)) + (loop for i from 0 below len + for val from 1 do (setf (aref dest-control i) val)) + ;; (format t "Src=(~{~3d~^ ~})~%" (coerce source 'list)) + ;; (format t "Dst=(~{~3d~^ ~})~%" (coerce dest-control 'list)) + (macrolet ((reset-arrays () + ;; Don't trust REPLACE while testing the implementation of REPLACE + `(progn + #+nil + (format t "Test parameters: src-index=~d dst-index=~d count=~d~%" + src-index dest-index n-elts) + ;; Check that we're not overrunning the array + (assert (< src-index len)) + (assert (<= (+ src-index n-elts) len)) + (assert (< dest-index len)) + (assert (<= (+ dest-index n-elts) len)) + (dotimes (i len) + (setf (aref dest i) (aref dest-control i))))) + (verify (bit-bashing-source) + ;; Verify that the byte-blt copier did the same thing + ;; as would expected from a simplistic copier. + `(let ((replaced-range-end (+ dest-index n-elts))) + (dotimes (i len) + ;; If outside of the replaced range, the value should be + ;; from the control array; otherwise the source of the copy. + (let ((expect (if (or (< i dest-index) (>= i replaced-range-end)) + (aref dest-control i) + (aref ,bit-bashing-source + (+ src-index (- i dest-index)))))) + (unless (= (aref dest i) expect) + (format t "Test parameters: src-index=~d dst-index=~d count=~d~%" + src-index dest-index n-elts) + (format t "Result=~s~%" dest) + (error "Error at element ~d, should have been ~d but is ~d" + i expect (aref dest i)))))))) + (format t "~&Different arrays ...") + ;; Make sure we see all possible offsets into the intial word + (dotimes (src-index (1- len)) + (dotimes (dest-index (1- len)) + (let* ((source-available-elements (- len src-index)) + (dest-available-elements (- len dest-index)) + (available-elements + (min source-available-elements dest-available-elements))) + ;; Iterate over all possible values of number of elements to move + (dotimes (n-elts available-elements) + (reset-arrays) + ;; (format t "Count=~d src-off=~d dst-off=~d~%" n-elts src-index dest-index) + (funcall function source src-index dest dest-index n-elts) + ;; (format t "Res=(~{~3d~^ ~})~%" (coerce dest 'list)) + (verify source))))) + (format t "~&Same array ...") + ;; Make sure we see all possible offsets into the intial word + (dotimes (src-index (1- len)) + (dotimes (dest-index (1- len)) + (let* ((source-available-elements (- len src-index)) + (dest-available-elements (- len dest-index)) + (available-elements + (min source-available-elements dest-available-elements))) + (dotimes (n-elts available-elements) + (reset-arrays) + (funcall function dest src-index dest dest-index n-elts) + (verify dest-control))))) + (terpri))))) +(compile 'test-bash-copiers-octet-or-larger) +(with-test (:name :bit-bash-copiers) + (test-bash-copiers-octet-or-larger)) + +(defvar *arrays*) +(defvar *array-size*) + +(defun test-aligned (fun len n-iter) ;; copy from A into B + (declare (function fun)) + (declare (sb-int:index n-iter)) + (dotimes (i n-iter) + (loop for (a b) on *arrays* when b do (funcall fun a 0 b 0 len)))) +(defun test-misaligned (fun len n-iter) ;; copy from A+1 into B+5 + (declare (function fun)) + (declare (sb-int:index n-iter)) + (dotimes (i n-iter) + (loop for (a b) on *arrays* + when b do (funcall fun a 1 b 5 (- len 5))))) +(defun test-same-array-1 (fun len n-iter) + (declare (function fun)) + (declare (sb-int:index n-iter)) + (dotimes (i n-iter) + (loop for a in *arrays* + do (funcall fun a 1 a 5 (- len 5))))) +(defun test-same-array-2 (fun len n-iter) + (declare (function fun)) + (declare (sb-int:index n-iter)) + (dotimes (i n-iter) + (loop for a in *arrays* + do (funcall fun a 5 a 1 (- len 5))))) + +(defun compare (test arg1 arg2 bits-per-element) + (let* ((a (symbol-function + (intern (format nil "UB~D-BASH-COPY" bits-per-element) "SB-KERNEL"))) + (b (symbol-function + (intern (format nil "NEW-UB~D-BASH-COPY" bits-per-element) "SB-KERNEL"))) + (t0 (get-internal-real-time)) + (dummy1 (funcall test a arg1 arg2)) + (t1 (get-internal-real-time)) + (dummy2 (funcall test b arg1 arg2)) + (t2 (get-internal-real-time))) + dummy1 dummy2 + (let* ((et1 (- t1 t0)) + (et2 (- t2 t1)) + (delta (- et2 et1)) + (delta-pct (float (* 100 (/ delta et1))))) + (format t " ~25a: ~7d vs ~7d (delta = ~,1f%)~%" + test et1 et2 delta-pct)))) + +(defun speed-comparison (&optional bits-per-element (scale-iterations 1)) + (dolist (bits-per-element (if bits-per-element + (list bits-per-element) + '(8 16 32 64))) + (format t "Testing bits-per-element = ~d~%" bits-per-element) + (loop for (*array-size* n-iter) + ;; Try to spend roughly the same time in each test + in '(( 10 25000) + ( 20 20000) + ( 32 20000) + ( 50 20000) + ( 64 15000) + ( 128 10000) + ( 200 10000) + ( 256 10000) + ( 500 5000) + ( 512 5000) + ( 1000 1000) + ( 1024 1000) + ( 2000 1000) + ( 2048 1000) + ( 4000 1000)) + do (format t "~&Testing array len ~d, ~d iterations:~%" *array-size* n-iter) + (setq *arrays* + (loop repeat 1000 + collect (make-array *array-size* + :element-type `(unsigned-byte ,bits-per-element)))) + (gc :full t) + (let ((n-iter (floor (* n-iter scale-iterations)))) + (compare 'test-aligned *array-size* n-iter bits-per-element) + (compare 'test-misaligned *array-size* n-iter bits-per-element) + (compare 'test-same-array-1 *array-size* n-iter bits-per-element) + (compare 'test-same-array-2 *array-size* n-iter bits-per-element))) + (terpri))) + +;;;; MACHINE-DEPENDENT RESULT + +#| +This is a comparison of the new UB<n>-BASH-COPY versus old, +for n = {8,16,32,64}. I produced this by temporarily naming the new +function to NEW-UB<n>-BASH-COPY so that both could coexist. + +Testing bits-per-element = 8 +Testing array len 10, 20000 iterations: + TEST-ALIGNED : 343998 vs 287999 (delta = -16.3%) + TEST-MISALIGNED : 515998 vs 271999 (delta = -47.3%) + TEST-SAME-ARRAY-1 : 507998 vs 255998 (delta = -49.6%) + TEST-SAME-ARRAY-2 : 351999 vs 259999 (delta = -26.1%) +Testing array len 20, 20000 iterations: + TEST-ALIGNED : 359997 vs 356000 (delta = -1.1%) + TEST-MISALIGNED : 563997 vs 279998 (delta = -50.4%) + TEST-SAME-ARRAY-1 : 547999 vs 259997 (delta = -52.6%) + TEST-SAME-ARRAY-2 : 471999 vs 255999 (delta = -45.8%) +Testing array len 32, 15000 iterations: + TEST-ALIGNED : 279998 vs 240000 (delta = -14.3%) + TEST-MISALIGNED : 459998 vs 199999 (delta = -56.5%) + TEST-SAME-ARRAY-1 : 451998 vs 191999 (delta = -57.5%) + TEST-SAME-ARRAY-2 : 419997 vs 187999 (delta = -55.2%) +Testing array len 50, 10000 iterations: + TEST-ALIGNED : 212001 vs 191999 (delta = -9.4%) + TEST-MISALIGNED : 383998 vs 151998 (delta = -60.4%) + TEST-SAME-ARRAY-1 : 376000 vs 143999 (delta = -61.7%) + TEST-SAME-ARRAY-2 : 343998 vs 139999 (delta = -59.3%) +Testing array len 64, 10000 iterations: + TEST-ALIGNED : 232000 vs 203999 (delta = -12.1%) + TEST-MISALIGNED : 403997 vs 148000 (delta = -63.4%) + TEST-SAME-ARRAY-1 : 399999 vs 143999 (delta = -64.0%) + TEST-SAME-ARRAY-2 : 379997 vs 140000 (delta = -63.2%) +Testing array len 128, 8000 iterations: + TEST-ALIGNED : 252000 vs 115999 (delta = -54.0%) + TEST-MISALIGNED : 483997 vs 135999 (delta = -71.9%) + TEST-SAME-ARRAY-1 : 483999 vs 120000 (delta = -75.2%) + TEST-SAME-ARRAY-2 : 467998 vs 123999 (delta = -73.5%) +Testing array len 200, 8000 iterations: + TEST-ALIGNED : 327999 vs 147999 (delta = -54.9%) + TEST-MISALIGNED : 659997 vs 167999 (delta = -74.5%) + TEST-SAME-ARRAY-1 : 663997 vs 164000 (delta = -75.3%) + TEST-SAME-ARRAY-2 : 647996 vs 164000 (delta = -74.7%) +Testing array len 256, 8000 iterations: + TEST-ALIGNED : 443998 vs 171999 (delta = -61.3%) + TEST-MISALIGNED : 843997 vs 195998 (delta = -76.8%) + TEST-SAME-ARRAY-1 : 875997 vs 195998 (delta = -77.6%) + TEST-SAME-ARRAY-2 : 847997 vs 191999 (delta = -77.4%) +Testing array len 500, 1000 iterations: + TEST-ALIGNED : 87999 vs 40001 (delta = -54.5%) + TEST-MISALIGNED : 183999 vs 44000 (delta = -76.1%) + TEST-SAME-ARRAY-1 : 187999 vs 40000 (delta = -78.7%) + TEST-SAME-ARRAY-2 : 183999 vs 44000 (delta = -76.1%) +Testing array len 512, 1000 iterations: + TEST-ALIGNED : 87999 vs 39999 (delta = -54.5%) + TEST-MISALIGNED : 188001 vs 39999 (delta = -78.7%) + TEST-SAME-ARRAY-1 : 192000 vs 39999 (delta = -79.2%) + TEST-SAME-ARRAY-2 : 188000 vs 39999 (delta = -78.7%) +Testing array len 1000, 500 iterations: + TEST-ALIGNED : 76000 vs 36000 (delta = -52.6%) + TEST-MISALIGNED : 171998 vs 36000 (delta = -79.1%) + TEST-SAME-ARRAY-1 : 176000 vs 36000 (delta = -79.5%) + TEST-SAME-ARRAY-2 : 171999 vs 36000 (delta = -79.1%) +Testing array len 1024, 500 iterations: + TEST-ALIGNED : 80000 vs 35999 (delta = -55.0%) + TEST-MISALIGNED : 176000 vs 36000 (delta = -79.5%) + TEST-SAME-ARRAY-1 : 175998 vs 40000 (delta = -77.3%) + TEST-SAME-ARRAY-2 : 176000 vs 36000 (delta = -79.5%) +Testing array len 2000, 200 iterations: + TEST-ALIGNED : 59999 vs 24000 (delta = -60.0%) + TEST-MISALIGNED : 132000 vs 24000 (delta = -81.8%) + TEST-SAME-ARRAY-1 : 135999 vs 28000 (delta = -79.4%) + TEST-SAME-ARRAY-2 : 131999 vs 24000 (delta = -81.8%) +Testing array len 2048, 200 iterations: + TEST-ALIGNED : 60000 vs 24000 (delta = -60.0%) + TEST-MISALIGNED : 135998 vs 28000 (delta = -79.4%) + TEST-SAME-ARRAY-1 : 136000 vs 28000 (delta = -79.4%) + TEST-SAME-ARRAY-2 : 136000 vs 28000 (delta = -79.4%) +Testing array len 4000, 100 iterations: + TEST-ALIGNED : 56000 vs 20000 (delta = -64.3%) + TEST-MISALIGNED : 128000 vs 23999 (delta = -81.3%) + TEST-SAME-ARRAY-1 : 128000 vs 28000 (delta = -78.1%) + TEST-SAME-ARRAY-2 : 127998 vs 32000 (delta = -75.0%) + +Testing bits-per-element = 16 +Testing array len 10, 20000 iterations: + TEST-ALIGNED : 351999 vs 299999 (delta = -14.8%) + TEST-MISALIGNED : 403997 vs 328000 (delta = -18.8%) + TEST-SAME-ARRAY-1 : 387998 vs 367998 (delta = -5.2%) + TEST-SAME-ARRAY-2 : 379999 vs 323999 (delta = -14.7%) +Testing array len 20, 20000 iterations: + TEST-ALIGNED : 367999 vs 351998 (delta = -4.3%) + TEST-MISALIGNED : 435997 vs 396000 (delta = -9.2%) + TEST-SAME-ARRAY-1 : 423998 vs 407998 (delta = -3.8%) + TEST-SAME-ARRAY-2 : 395998 vs 379998 (delta = -4.0%) +Testing array len 32, 15000 iterations: + TEST-ALIGNED : 319999 vs 311999 (delta = -2.5%) + TEST-MISALIGNED : 375997 vs 344000 (delta = -8.5%) + TEST-SAME-ARRAY-1 : 367998 vs 355997 (delta = -3.3%) + TEST-SAME-ARRAY-2 : 340000 vs 335998 (delta = -1.2%) +Testing array len 50, 10000 iterations: + TEST-ALIGNED : 279998 vs 256000 (delta = -8.6%) + TEST-MISALIGNED : 307999 vs 279998 (delta = -9.1%) + TEST-SAME-ARRAY-1 : 303999 vs 303999 (delta = 0.0%) + TEST-SAME-ARRAY-2 : 291999 vs 271997 (delta = -6.9%) +Testing array len 64, 10000 iterations: + TEST-ALIGNED : 304000 vs 139999 (delta = -53.9%) + TEST-MISALIGNED : 343999 vs 311998 (delta = -9.3%) + TEST-SAME-ARRAY-1 : 339999 vs 319999 (delta = -5.9%) + TEST-SAME-ARRAY-2 : 315997 vs 308000 (delta = -2.5%) +Testing array len 128, 8000 iterations: + TEST-ALIGNED : 431998 vs 175998 (delta = -59.3%) + TEST-MISALIGNED : 423999 vs 211999 (delta = -50.0%) + TEST-SAME-ARRAY-1 : 423997 vs 204001 (delta = -51.9%) + TEST-SAME-ARRAY-2 : 391998 vs 195998 (delta = -50.0%) +Testing array len 200, 8000 iterations: + TEST-ALIGNED : 583998 vs 255999 (delta = -56.2%) + TEST-MISALIGNED : 671997 vs 283999 (delta = -57.7%) + TEST-SAME-ARRAY-1 : 663997 vs 283999 (delta = -57.2%) + TEST-SAME-ARRAY-2 : 595997 vs 271999 (delta = -54.4%) +Testing array len 256, 8000 iterations: + TEST-ALIGNED : 707997 vs 295999 (delta = -58.2%) + TEST-MISALIGNED : 799996 vs 331999 (delta = -58.5%) + TEST-SAME-ARRAY-1 : 799996 vs 339999 (delta = -57.5%) + TEST-SAME-ARRAY-2 : 719996 vs 331999 (delta = -53.9%) +Testing array len 500, 1000 iterations: + TEST-ALIGNED : 155999 vs 72000 (delta = -53.8%) + TEST-MISALIGNED : 168000 vs 76000 (delta = -54.8%) + TEST-SAME-ARRAY-1 : 175999 vs 76000 (delta = -56.8%) + TEST-SAME-ARRAY-2 : 155999 vs 76000 (delta = -51.3%) +Testing array len 512, 1000 iterations: + TEST-ALIGNED : 159998 vs 68000 (delta = -57.5%) + TEST-MISALIGNED : 176000 vs 72000 (delta = -59.1%) + TEST-SAME-ARRAY-1 : 179999 vs 75999 (delta = -57.8%) + TEST-SAME-ARRAY-2 : 156000 vs 75999 (delta = -51.3%) +Testing array len 1000, 500 iterations: + TEST-ALIGNED : 147999 vs 59999 (delta = -59.5%) + TEST-MISALIGNED : 160001 vs 63999 (delta = -60.0%) + TEST-SAME-ARRAY-1 : 164000 vs 71999 (delta = -56.1%) + TEST-SAME-ARRAY-2 : 144000 vs 67999 (delta = -52.8%) +Testing array len 1024, 500 iterations: + TEST-ALIGNED : 148000 vs 63998 (delta = -56.8%) + TEST-MISALIGNED : 160000 vs 68000 (delta = -57.5%) + TEST-SAME-ARRAY-1 : 168000 vs 71999 (delta = -57.1%) + TEST-SAME-ARRAY-2 : 148000 vs 71999 (delta = -51.4%) +Testing array len 2000, 200 iterations: + TEST-ALIGNED : 112000 vs 40000 (delta = -64.3%) + TEST-MISALIGNED : 123998 vs 44000 (delta = -64.5%) + TEST-SAME-ARRAY-1 : 123999 vs 52001 (delta = -58.1%) + TEST-SAME-ARRAY-2 : 116000 vs 59999 (delta = -48.3%) +Testing array len 2048, 200 iterations: + TEST-ALIGNED : 116000 vs 40000 (delta = -65.5%) + TEST-MISALIGNED : 123999 vs 52000 (delta = -58.1%) + TEST-SAME-ARRAY-1 : 127999 vs 56000 (delta = -56.2%) + TEST-SAME-ARRAY-2 : 111999 vs 63999 (delta = -42.9%) +Testing array len 4000, 100 iterations: + TEST-ALIGNED : 108001 vs 36000 (delta = -66.7%) + TEST-MISALIGNED : 115999 vs 40000 (delta = -65.5%) + TEST-SAME-ARRAY-1 : 123999 vs 52000 (delta = -58.1%) + TEST-SAME-ARRAY-2 : 112000 vs 55999 (delta = -50.0%) + +Testing bits-per-element = 32 +Testing array len 10, 20000 iterations: + TEST-ALIGNED : 379998 vs 351999 (delta = -7.4%) + TEST-MISALIGNED : 403998 vs 335999 (delta = -16.8%) + TEST-SAME-ARRAY-1 : 387998 vs 359998 (delta = -7.2%) + TEST-SAME-ARRAY-2 : 351999 vs 343998 (delta = -2.3%) +Testing array len 20, 20000 iterations: + TEST-ALIGNED : 487997 vs 455999 (delta = -6.6%) + TEST-MISALIGNED : 539997 vs 447999 (delta = -17.0%) + TEST-SAME-ARRAY-1 : 523997 vs 451999 (delta = -13.7%) + TEST-SAME-ARRAY-2 : 451997 vs 451999 (delta = 0.0%) +Testing array len 32, 15000 iterations: + TEST-ALIGNED : 463997 vs 212000 (delta = -54.3%) + TEST-MISALIGNED : 531997 vs 435997 (delta = -18.0%) + TEST-SAME-ARRAY-1 : 519999 vs 435997 (delta = -16.2%) + TEST-SAME-ARRAY-2 : 435999 vs 439997 (delta = 0.9%) +Testing array len 50, 10000 iterations: + TEST-ALIGNED : 404000 vs 179999 (delta = -55.4%) + TEST-MISALIGNED : 483997 vs 208000 (delta = -57.0%) + TEST-SAME-ARRAY-1 : 479998 vs 199998 (delta = -58.3%) + TEST-SAME-ARRAY-2 : 387999 vs 199999 (delta = -48.5%) +Testing array len 64, 10000 iterations: + TEST-ALIGNED : 543997 vs 224000 (delta = -58.8%) + TEST-MISALIGNED : 583997 vs 259998 (delta = -55.5%) + TEST-SAME-ARRAY-1 : 575998 vs 243998 (delta = -57.6%) + TEST-SAME-ARRAY-2 : 463999 vs 235999 (delta = -49.1%) +Testing array len 128, 8000 iterations: + TEST-ALIGNED : 715997 vs 295999 (delta = -58.7%) + TEST-MISALIGNED : 819996 vs 319999 (delta = -61.0%) + TEST-SAME-ARRAY-1 : 815996 vs 331998 (delta = -59.3%) + TEST-SAME-ARRAY-2 : 703998 vs 319997 (delta = -54.5%) +Testing array len 200, 8000 iterations: + TEST-ALIGNED : 1023996 vs 463999 (delta = -54.7%) + TEST-MISALIGNED : 1139995 vs 483997 (delta = -57.5%) + TEST-SAME-ARRAY-1 : 1147996 vs 487997 (delta = -57.5%) + TEST-SAME-ARRAY-2 : 1019996 vs 471998 (delta = -53.7%) +Testing array len 256, 8000 iterations: + TEST-ALIGNED : 1259994 vs 559997 (delta = -55.6%) + TEST-MISALIGNED : 1387995 vs 575996 (delta = -58.5%) + TEST-SAME-ARRAY-1 : 1403995 vs 595996 (delta = -57.5%) + TEST-SAME-ARRAY-2 : 1255996 vs 571997 (delta = -54.5%) +Testing array len 500, 1000 iterations: + TEST-ALIGNED : 288000 vs 127999 (delta = -55.6%) + TEST-MISALIGNED : 307999 vs 124000 (delta = -59.7%) + TEST-SAME-ARRAY-1 : 311997 vs 132001 (delta = -57.7%) + TEST-SAME-ARRAY-2 : 291998 vs 128000 (delta = -56.2%) +Testing array len 512, 1000 iterations: + TEST-ALIGNED : 295997 vs 128000 (delta = -56.8%) + TEST-MISALIGNED : 315999 vs 128000 (delta = -59.5%) + TEST-SAME-ARRAY-1 : 319998 vs 139999 (delta = -56.3%) + TEST-SAME-ARRAY-2 : 296000 vs 135999 (delta = -54.1%) +Testing array len 1000, 500 iterations: + TEST-ALIGNED : 279999 vs 99999 (delta = -64.3%) + TEST-MISALIGNED : 291998 vs 108000 (delta = -63.0%) + TEST-SAME-ARRAY-1 : 299999 vs 124000 (delta = -58.7%) + TEST-SAME-ARRAY-2 : 283998 vs 151999 (delta = -46.5%) +Testing array len 1024, 500 iterations: + TEST-ALIGNED : 291999 vs 104000 (delta = -64.4%) + TEST-MISALIGNED : 295999 vs 123999 (delta = -58.1%) + TEST-SAME-ARRAY-1 : 303999 vs 131999 (delta = -56.6%) + TEST-SAME-ARRAY-2 : 283999 vs 155999 (delta = -45.1%) +Testing array len 2000, 200 iterations: + TEST-ALIGNED : 219998 vs 72000 (delta = -67.3%) + TEST-MISALIGNED : 224000 vs 79999 (delta = -64.3%) + TEST-SAME-ARRAY-1 : 231999 vs 100000 (delta = -56.9%) + TEST-SAME-ARRAY-2 : 219998 vs 112000 (delta = -49.1%) +Testing array len 2048, 200 iterations: + TEST-ALIGNED : 224000 vs 76000 (delta = -66.1%) + TEST-MISALIGNED : 235999 vs 88000 (delta = -62.7%) + TEST-SAME-ARRAY-1 : 235998 vs 103999 (delta = -55.9%) + TEST-SAME-ARRAY-2 : 224000 vs 116000 (delta = -48.2%) +Testing array len 4000, 100 iterations: + TEST-ALIGNED : 215999 vs 76000 (delta = -64.8%) + TEST-MISALIGNED : 227998 vs 88000 (delta = -61.4%) + TEST-SAME-ARRAY-1 : 232000 vs 103999 (delta = -55.2%) + TEST-SAME-ARRAY-2 : 223999 vs 112000 (delta = -50.0%) + +Testing bits-per-element = 64 +Testing array len 10, 20000 iterations: + TEST-ALIGNED : 423997 vs 399999 (delta = -5.7%) + TEST-MISALIGNED : 347999 vs 327998 (delta = -5.7%) + TEST-SAME-ARRAY-1 : 335999 vs 339998 (delta = 1.2%) + TEST-SAME-ARRAY-2 : 339999 vs 343998 (delta = 1.2%) +Testing array len 20, 20000 iterations: + TEST-ALIGNED : 639997 vs 351999 (delta = -45.0%) + TEST-MISALIGNED : 571997 vs 547998 (delta = -4.2%) + TEST-SAME-ARRAY-1 : 567997 vs 551998 (delta = -2.8%) + TEST-SAME-ARRAY-2 : 555997 vs 559997 (delta = 0.7%) +Testing array len 32, 15000 iterations: + TEST-ALIGNED : 783998 vs 343997 (delta = -56.1%) + TEST-MISALIGNED : 647998 vs 383997 (delta = -40.7%) + TEST-SAME-ARRAY-1 : 651999 vs 367997 (delta = -43.6%) + TEST-SAME-ARRAY-2 : 611998 vs 351998 (delta = -42.5%) +Testing array len 50, 10000 iterations: + TEST-ALIGNED : 719998 vs 323998 (delta = -55.0%) + TEST-MISALIGNED : 735997 vs 351998 (delta = -52.2%) + TEST-SAME-ARRAY-1 : 731996 vs 348000 (delta = -52.5%) + TEST-SAME-ARRAY-2 : 675996 vs 331999 (delta = -50.9%) +Testing array len 64, 10000 iterations: + TEST-ALIGNED : 871996 vs 367999 (delta = -57.8%) + TEST-MISALIGNED : 907996 vs 399998 (delta = -55.9%) + TEST-SAME-ARRAY-1 : 911996 vs 423998 (delta = -53.5%) + TEST-SAME-ARRAY-2 : 827995 vs 396000 (delta = -52.2%) +Testing array len 128, 8000 iterations: + TEST-ALIGNED : 1247994 vs 559998 (delta = -55.1%) + TEST-MISALIGNED : 1343994 vs 579997 (delta = -56.8%) + TEST-SAME-ARRAY-1 : 1391994 vs 595998 (delta = -57.2%) + TEST-SAME-ARRAY-2 : 1215994 vs 563997 (delta = -53.6%) +Testing array len 200, 8000 iterations: + TEST-ALIGNED : 1867992 vs 811997 (delta = -56.5%) + TEST-MISALIGNED : 2047991 vs 823996 (delta = -59.8%) + TEST-SAME-ARRAY-1 : 2127991 vs 875996 (delta = -58.8%) + TEST-SAME-ARRAY-2 : 1847992 vs 839996 (delta = -54.5%) +Testing array len 256, 8000 iterations: + TEST-ALIGNED : 2351990 vs 1015995 (delta = -56.8%) + TEST-MISALIGNED : 2587989 vs 1027996 (delta = -60.3%) + TEST-SAME-ARRAY-1 : 2683987 vs 1107995 (delta = -58.7%) + TEST-SAME-ARRAY-2 : 2331991 vs 1059995 (delta = -54.5%) +Testing array len 500, 1000 iterations: + TEST-ALIGNED : 555996 vs 196001 (delta = -64.7%) + TEST-MISALIGNED : 619997 vs 219998 (delta = -64.5%) + TEST-SAME-ARRAY-1 : 639998 vs 251998 (delta = -60.6%) + TEST-SAME-ARRAY-2 : 559998 vs 295999 (delta = -47.1%) +Testing array len 512, 1000 iterations: + TEST-ALIGNED : 575998 vs 207999 (delta = -63.9%) + TEST-MISALIGNED : 635997 vs 239999 (delta = -62.3%) + TEST-SAME-ARRAY-1 : 647996 vs 264000 (delta = -59.3%) + TEST-SAME-ARRAY-2 : 571996 vs 300000 (delta = -47.6%) +Testing array len 1000, 500 iterations: + TEST-ALIGNED : 547997 vs 171999 (delta = -68.6%) + TEST-MISALIGNED : 611998 vs 195999 (delta = -68.0%) + TEST-SAME-ARRAY-1 : 627997 vs 243999 (delta = -61.1%) + TEST-SAME-ARRAY-2 : 555998 vs 275999 (delta = -50.4%) +Testing array len 1024, 500 iterations: + TEST-ALIGNED : 567996 vs 188000 (delta = -66.9%) + TEST-MISALIGNED : 627996 vs 216000 (delta = -65.6%) + TEST-SAME-ARRAY-1 : 639998 vs 251998 (delta = -60.6%) + TEST-SAME-ARRAY-2 : 563998 vs 283999 (delta = -49.6%) +Testing array len 2000, 200 iterations: + TEST-ALIGNED : 435999 vs 147999 (delta = -66.1%) + TEST-MISALIGNED : 495997 vs 172000 (delta = -65.3%) + TEST-SAME-ARRAY-1 : 507998 vs 203999 (delta = -59.8%) + TEST-SAME-ARRAY-2 : 443998 vs 219999 (delta = -50.5%) +Testing array len 2048, 200 iterations: + TEST-ALIGNED : 459997 vs 208000 (delta = -54.8%) + TEST-MISALIGNED : 511998 vs 239998 (delta = -53.1%) + TEST-SAME-ARRAY-1 : 543998 vs 243999 (delta = -55.1%) + TEST-SAME-ARRAY-2 : 487998 vs 259999 (delta = -46.7%) +Testing array len 4000, 100 iterations: + TEST-ALIGNED : 471997 vs 527999 (delta = 11.9%) + TEST-MISALIGNED : 519998 vs 491998 (delta = -5.4%) + TEST-SAME-ARRAY-1 : 639997 vs 347998 (delta = -45.6%) + TEST-SAME-ARRAY-2 : 511998 vs 355998 (delta = -30.5%) + +|# diff --git a/tests/bit-vector.impure.lisp b/tests/bit-vector.impure.lisp index c64cfd440c..9a73fd8bd1 100644 --- a/tests/bit-vector.impure.lisp +++ b/tests/bit-vector.impure.lisp @@ -41,9 +41,9 @@ ;; SPACE) (locally (declare (optimize (speed 3) (space 1))) - (let ((bv1 (make-array 5 :element-type 'bit)) - (bv2 (make-array 0 :element-type 'bit)) - (bv3 (make-array 68 :element-type 'bit))) + (let ((bv1 (make-array 5 :element-type 'bit :initial-element 0)) + (bv2 (make-array 0 :element-type 'bit :initial-element 0)) + (bv3 (make-array 68 :element-type 'bit :initial-element 0))) (declare (type simple-bit-vector bv1 bv2 bv3)) (setf (sbit bv3 42) 1) ;; bitvector smaller than the word size @@ -124,14 +124,17 @@ (logior sb-posix:map-private sb-posix:map-anon sb-posix:map-fixed) -1 0))) (setf (sb-sys:sap-ref-word addr 0) sb-vm:simple-bit-vector-widetag) - (setf (sb-sys:sap-ref-word addr sb-vm:n-word-bytes) - (ash n-bits sb-vm:n-fixnum-tag-bits)) - (multiple-value-bind (object widetag size) - (sb-vm::reconstitute-object (sb-c::mask-signed-field + (setf (sb-kernel:%array-fill-pointer + (sb-kernel:%make-lisp-obj (logior (sb-sys:sap-int addr) + sb-vm:other-pointer-lowtag))) + n-bits) + (let* ((object + (sb-vm::reconstitute-object + (sb-c::mask-signed-field sb-vm:n-fixnum-bits (ash (sb-sys:sap-int addr) - (- sb-vm:n-fixnum-tag-bits)))) - (declare (ignore widetag)) + (- sb-vm:n-fixnum-tag-bits))))) + (size (sb-ext:primitive-object-size object))) (assert (simple-bit-vector-p object)) (assert (= size n-bytes)) (assert (not (sb-kernel:%bit-position/1 object nil 0 n-bits))) diff --git a/tests/bivalent-stream.impure.lisp b/tests/bivalent-stream.pure.lisp similarity index 95% rename from tests/bivalent-stream.impure.lisp rename to tests/bivalent-stream.pure.lisp index 3370a6b79d..26695bad49 100644 --- a/tests/bivalent-stream.impure.lisp +++ b/tests/bivalent-stream.pure.lisp @@ -45,6 +45,8 @@ expected ~S.~@:>" write-call read-call result expected))) +(defun zero-string (n) (make-string n :initial-element #\nul)) + (defvar *read/write-sequence-pairs* `(;; List source and destination sequence. ((65) () ,(list 0) () 1 (#\A)) @@ -94,12 +96,12 @@ (#(#\B) () ,(cvector #\_ #\_) (:end 1) 1 #(#\B #\_)) (#(#\B) () ,(cvector #\_ #\_) (:start 1) 2 #(#\_ #\B)) ;; String destination sequence. - (#(65) () ,(make-string 1) () 1 "A") - (#(#\B) () ,(make-string 1) () 1 "B") - (#(66 #\C) () ,(make-string 2) () 2 "BC") - (#(#\B 67) () ,(make-string 2) () 2 "BC") - (#(#\B) () ,(make-string 2) (:end 1) 1 ,(coerce '(#\B #\Nul) 'string)) - (#(#\B) () ,(make-string 2) (:start 1) 2 ,(coerce '(#\Nul #\B) 'string)))) + (#(65) () ,(zero-string 1) () 1 "A") + (#(#\B) () ,(zero-string 1) () 1 "B") + (#(66 #\C) () ,(zero-string 2) () 2 "BC") + (#(#\B 67) () ,(zero-string 2) () 2 "BC") + (#(#\B) () ,(zero-string 2) (:end 1) 1 ,(coerce '(#\B #\Nul) 'string)) + (#(#\B) () ,(zero-string 2) (:start 1) 2 ,(coerce '(#\Nul #\B) 'string)))) (defun do-writes (stream pairs) (loop :for (sequence args) :in pairs diff --git a/tests/block-compile.impure.lisp b/tests/block-compile.impure.lisp new file mode 100644 index 0000000000..55e3065955 --- /dev/null +++ b/tests/block-compile.impure.lisp @@ -0,0 +1,408 @@ +(load "compiler-test-util.lisp") + +(with-test (:name :block-inline-then-notinline) + (ctu:file-compile + `((in-package :cl-user) + (declaim (inline block-inline-foo)) + (defun block-inline-foo (a b) + (+ a b)) + (defun bar-with-foo-inline (a b c) + (* c (block-inline-foo a b))) + + (declaim (notinline block-inline-foo)) + (defun bar-with-foo-call (a b c) + (* c (block-inline-foo a b)))) + :block-compile t + :load t) + (assert (not (ctu:find-named-callees (symbol-function 'bar-with-foo-inline)))) + (assert (ctu:find-named-callees (symbol-function 'bar-with-foo-call)))) + +(with-test (:name :block-defpackage-then-load-fasl) + (ctu:file-compile + `((defpackage block-defpackage (:use :cl :cl-user)) + + (in-package :block-defpackage) + + (defstruct (struct-foo (:conc-name "FOO-")) + (bar 0 :type number) + (baz nil :type list))) + :block-compile t + :before-load (lambda () (delete-package :block-defpackage)) + :load t)) + +(defvar *x*) +(defvar *y*) + +(with-test (:name :block-defpackage-top-level-form-order) + (ctu:file-compile + `((setq *x* (find-package "BLOCK-DEFPACKAGE")) + + (defpackage block-defpackage (:use :cl :cl-user)) + + (setq *y* (find-package "BLOCK-DEFPACKAGE"))) + :block-compile t + :before-load (lambda () (delete-package :block-defpackage)) + :load t) + (assert (eq *x* nil)) + (assert *y*)) + +(with-test (:name :block-defpackage-symbol-inheritance-load-fasl) + (defpackage block-defpackage2 (:use :cl)) + (ctu:file-compile + `((in-package :block-defpackage2) + + (eval-when (:compile-toplevel :load-toplevel :execute) + (shadow "+")) + + (defun + (x) (print x))) + :block-compile t + :before-load (lambda () + (delete-package :block-defpackage2) + (defpackage block-defpackage2 (:use :cl))) + :load t) + (assert (not (eq (fdefinition (find-symbol "+" "BLOCK-DEFPACKAGE2")) + #'cl:+)))) + +(defpackage block-defpackage3 + (:use :cl)) + +(with-test (:name :block-defpackage-delete-package-redefpackage) + (ctu:file-compile + `((when (find-package '#:block-defpackage3) + (delete-package '#:block-defpackage3)) + (defpackage block-defpackage3 + (:use :cl)) + (in-package block-defpackage3) + ;; This can barf if, for example, F loses its package because + ;; DELETE-PACKAGE and never gets it back when the package gets + ;; defined again. + (export '(block-defpackage3::f))) + :block-compile t + :load t) + (assert (eq (nth-value 1 (find-symbol "F" "BLOCK-DEFPACKAGE3")) + :external))) + +;;; Similar to the above test case, but with RENAME-PACKAGE. This is +;;; probably, strictly speaking, non-conforming code according to ANSI +;;; 3.2.4.4 under item 1 for symbol, taking package "same"ness to mean +;;; EQness. We don't expect this to work under block compilation. +(with-test (:name :block-defpackage-rename-package-redefpackage + :fails-on :sbcl) + (ctu:file-compile + `((eval-when (:compile-toplevel :load-toplevel :execute) + (when (find-package "BLOCK-DEFPACKAGE4") + (rename-package "BLOCK-DEFPACKAGE4" "OLD-BLOCK-DEFPACKAGE4"))) + (defpackage "BLOCK-DEFPACKAGE4" + (:use :cl)) + (in-package "BLOCK-DEFPACKAGE4") + (eval-when (:compile-toplevel :load-toplevel :execute) + (export '(f)))) + :block-compile t + :load t) + (assert (eq (nth-value 1 (find-symbol "F" "BLOCK-DEFPACKAGE4")) + :external))) + +;;; Doesn't work yet. +(with-test (:name :block-defpackage-rename-package + :fails-on :sbcl) + (ctu:file-compile + `((eval-when (:compile-toplevel :load-toplevel :execute) + (cond + ((find-package "BLOCK-DEFPACKAGE-FOO") + (rename-package "BLOCK-DEFPACKAGE-FOO" + "BLOCK-DEFPACKAGE-BAR")) + ((not (find-package "BLOCK-DEFPACKAGE-BAR")) + (make-package "BLOCK-DEFPACKAGE-BAR" :use '("CL"))))) + + (in-package "BLOCK-DEFPACKAGE-BAR") + + (defun stable-union (bar) bar)) + :block-compile t + :before-load (lambda () + (delete-package "BLOCK-DEFPACKAGE-BAR") + (defpackage block-defpackage-foo (:use :cl))) + :load t) + (assert (find-symbol "STABLE-UNION" "BLOCK-DEFPACKAGE-BAR"))) + +(with-test (:name :block-defpackage-rename-package-symbol-conflict + :fails-on :sbcl) + (with-scratch-file (fasl2 "fasl") + (compile-file "package-test-2.lisp" :output-file fasl2 + :block-compile t) + (delete-package "BAR") + (with-scratch-file (fasl1 "fasl") + (compile-file "package-test-1.lisp" :output-file fasl1 + :block-compile t) + (load fasl2))) + (assert (eq (symbol-package (find-symbol "BAZ" "BAR")) + (find-package "BAR"))) + (assert (eq (funcall (find-symbol "BAZ" "BAR")) + :good)) + (delete-package "BAR")) + +(with-test (:name :block-defpackage-rename-package-preserve-externals + :fails-on :sbcl) + (with-scratch-file (fasl4 "fasl") + (compile-file "package-test-4.lisp" :output-file fasl4 + :block-compile t) + (delete-package "FOO-NEW") + (with-scratch-file (fasl3 "fasl") + (compile-file "package-test-3.lisp" :output-file fasl3 + :block-compile t) + (load fasl4))) + (assert (eq (nth-value 1 (find-symbol "BAR" "FOO-NEW")) + :external)) + (delete-package "FOO-NEW")) + +(with-test (:name :block-defconstant-then-load-fasl) + (ctu:file-compile + ;; test a non-EQL-comparable constant. + `((defconstant testconstant '(1 2 3 4 5)) + (defun foo () + (loop for i in testconstant collect i))) + :block-compile t + :before-load (lambda () (unintern (find-symbol "TESTCONSTANT"))) + :load t)) + +(with-test (:name :block-defconstant-hairy-then-load-fasl) + (ctu:file-compile + `((sb-int:defconstant-eqx testconstant2 + (let (list) + (dotimes (i 5 list) (push i list))) + #'equal) + (defun bar () + (loop for i in testconstant2 collect i))) + :block-compile t + :before-load (lambda () (unintern (find-symbol "TESTCONSTANT2"))) + :load t)) + +(with-test (:name :block-defconstant-same-component) + (ctu:file-compile + `((defun foo-before-defconstant (x) x) + (defconstant +testconstant3+ '(1 2 3 4 5 6)) + (defun bar-after-defconstant () (foo-before-defconstant +testconstant3+))) + :block-compile t + :before-load (lambda () (unintern (find-symbol "+TESTCONSTANT3+"))) + :load t) + (assert (eq (sb-kernel::fun-code-header #'foo-before-defconstant) + (sb-kernel::fun-code-header #'bar-after-defconstant)))) + +(with-test (:name :block-defconstant-hairy-eqness-test) + (ctu:file-compile + `((sb-int:defconstant-eqx testconstant4 + (let (list) + (dotimes (i 5 list) (push i list))) + #'equal) + (defun bar () testconstant4)) + :block-compile t + :load t) + (assert (eq (bar) (symbol-value 'testconstant4)))) + +(with-test (:name :block-defconstant-hairy-backq-dumping-test) + (ctu:file-compile + `((defconstant +stuff+ + (if (boundp '+stuff+) + (symbol-value '+stuff+) + '(0 0))) + + (defvar *backq-stuff* + `((0 ,(random 10)) + (,@+stuff+ 1 2 (3 . 4)) + (5 6 ,+stuff+)))) + :block-compile t + :before-load (lambda () (unintern (find-symbol "+STUFF+"))) + :load t) + (assert (= 0 (first (third (third (symbol-value '*backq-stuff*))))))) + +(with-test (:name :block-compile-ftype-proclamation) + (ctu:file-compile + `((declaim (ftype function zoo)) + (defun bar1 (x) (zoo x)) + + (declaim (ftype (function (t) (values integer &optional)) bar1)) + + (defun foo1 (z) (bar1 z))) + :block-compile t + :load t) + (assert (ctype= (caddr (sb-kernel::%simple-fun-type (fdefinition 'foo1))) + '(values integer &optional)))) + +(with-test (:name :block-compile-variable-type-proclamation) + (ctu:file-compile + `((defvar *foo*) + (declaim (type integer *foo*)) + (defun integer-type () *foo*) + (declaim (type character *foo*)) + (defun character-type () *foo*)) + :block-compile t + :load t) + (assert (ctype= (caddr (sb-kernel::%simple-fun-type (fdefinition 'integer-type))) + '(values integer &optional))) + (assert (ctype= (caddr (sb-kernel::%simple-fun-type (fdefinition 'character-type))) + '(values character &optional)))) + +(with-test (:name :block-compile-same-block-references-functional) + (ctu:file-compile + `((declaim (inline bar)) + (defun bar (x) (cons x #'bar)) + + (defun foo (x) (cons (bar 9) #'bar))) + :block-compile t + :load t) + (let ((value (funcall (fdefinition 'foo) 9))) + (assert (eq (cdr value) (fdefinition 'bar))) + (assert (eq (cdar value) (fdefinition 'bar)))) + (assert (eq (sb-kernel::fun-code-header (fdefinition 'foo)) + (sb-kernel::fun-code-header (fdefinition 'bar)))) + ;; Should not have to reference any FDEFN objects, as we are + ;; compiling in the same block, allowing us to directly reference + ;; the (simple) function objects directly. + (assert (null (ctu:find-named-callees #'foo)))) + +(with-test (:name :block-compile-top-level-closures) + (ctu:file-compile + `(;; test forward reference + (let ((y 0)) + (defun foo2 (x) + (+ (bar2 x) (incf y)))) + + (let ((y 8)) + (defun bar2 (x) + (+ (incf y) (baz2 (+ 3 x))))) + + ;; test backward reference + (defun baz2 (x) + (if (zerop x) + (foo2 x) + x))) + :block-compile t + :load t) + ;; Make sure BAZ2 and BAR2 get a component together. FOO2 should not + ;; share a component with anyone, since it doesn't local call anyone + ;; with a compatible environment. + (assert (and (eq (sb-kernel::fun-code-header #'baz2) + (sb-kernel::fun-code-header (sb-kernel::%closure-fun #'bar2))) + (not (eq (sb-kernel::fun-code-header #'baz2) + (sb-kernel::fun-code-header (sb-kernel::%closure-fun #'foo2)))))) + (assert (= (baz2 2) 2)) + ;; Test calling the closures behave as expected. + (assert (= (baz2 0) 13)) + (assert (= (baz2 0) 15)) + (assert (= (baz2 0) 17)) + (assert (= (baz2 0) 19))) + +;;; FLET should pose no problem. +(with-test (:name :block-compile-top-level-closures.flet) + (ctu:file-compile + `(;; test forward reference + (flet ((blargh (x) + (+ x x))) + (defun boo (x) + (+ (blargh x) (blargh x)))) + (defun zoo (x) + (boo x))) + :block-compile t + :load t) + ;; Make sure the defuns all get compiled into the same code + ;; component. + (assert (eq (sb-kernel::fun-code-header #'boo) + (sb-kernel::fun-code-header #'zoo))) + (assert (null (ctu:find-named-callees #'zoo))) + (assert (= (zoo 3) 12))) + +(with-test (:name :block-compile-top-level-closures.self-call) + (ctu:file-compile + `((let ((y 9)) + (defun self-call (x) + (if (zerop x) + y + (+ (decf y) (self-call (1- x))))))) + :block-compile t + :load t) + ;; Test that we can call ourselves. + (assert (= (self-call 9) 36))) + +(with-test (:name :block-compile-top-level-closures.self-call.local-calls) + ;; Test that we can local call ourselves in the same environment despite + ;; being a top level closure. + (assert (not (member #'self-call (ctu:find-named-callees #'self-call))))) + +(with-test (:name :block-compile-top-level-closures.same-environment) + (ctu:file-compile + `(;; test forward reference + (let ((y 0)) + (defun foo3 (x) + (+ (bar2 x) (incf y))) + + (defun bar3 (x) + (+ (incf y) (baz2 (+ 3 x)))) + + ;; test backward reference + (defun baz3 (x) + (if (zerop x) + (foo2 x) + x)))) + :block-compile t + :load t) + ;; Test that calls in the same environment work. + (assert (= (baz3 0) 21)) + (assert (= (baz3 0) 23)) + (assert (= (baz3 0) 25)) + (assert (= (baz3 0) 27))) + +(with-test (:name :block-compile-top-level-closures.same-environment.local-calls + :fails-on :sbcl) + ;; FOO3, BAR3, and BAZ3 are all in the same lexical environment, so + ;; therefore have compatible runtime environments. Thus they should + ;; be able to all local call each other. (Not implemented yet.) + (assert (and (eq (sb-kernel::fun-code-header (sb-kernel::%closure-fun #'baz3)) + (sb-kernel::fun-code-header (sb-kernel::%closure-fun #'bar3))) + (eq (sb-kernel::fun-code-header (sb-kernel::%closure-fun #'baz3)) + (sb-kernel::fun-code-header (sb-kernel::%closure-fun #'foo3))))) + (assert (null (ctu:find-named-callees #'baz3)))) + +(with-test (:name :block-compile-top-level-closures.simple-fun-reference) + (ctu:file-compile + `((defun simple (chr) + (char<= #\0 chr #\9)) + + (let ((scanner 3)) + (defun closure () + (values #'simple (incf scanner))))) + :block-compile t + :load t) + ;; Closure can directly reference the simple fun for SIMPLE. + (assert (not (member #'simple (ctu:find-named-callees #'closure)))) + (multiple-value-bind (val counter) + (closure) + (assert (eq val #'simple)) + (assert (eq counter 4))) + (multiple-value-bind (val counter) + (closure) + (assert (eq val #'simple)) + (assert (eq counter 5)))) + +(with-test (:name :block-compile-top-level-closures.closure-fun-reference) + (ctu:file-compile + `((defun simple1 () + #'closure1) + + (let ((scanner 3)) + (defun closure1 (char) + (values (char<= #\0 char #\9) (incf scanner))))) + :block-compile t + :load t) + ;; SIMPLE1 cannot directly reference the simple fun for CLOSURE1. It + ;; must go through the closure function object instead through the + ;; FDEFN. TODO: It might be worthwhile in the future to treat + ;; top-level closures as load time constants, so that we can + ;; reference the closure object directly, rather than go through the + ;; FDEFN. + (multiple-value-bind (val counter) + (funcall (simple1) #\a) + (assert (eq val nil)) + (assert (eq counter 4))) + (multiple-value-bind (val counter) + (funcall (simple1) #\1) + (assert (eq val t)) + (assert (eq counter 5)))) diff --git a/tests/brothertree.impure.lisp b/tests/brothertree.impure.lisp new file mode 100644 index 0000000000..1053b7bc1a --- /dev/null +++ b/tests/brothertree.impure.lisp @@ -0,0 +1,293 @@ +#+interpreter (invoke-restart 'run-tests::skip-file) + +(let ((*evaluator-mode* :compile)) + (handler-bind ((warning #'muffle-warning)) + (load "../src/code/brothertree.lisp"))) + +(in-package sb-brothertree) + +(defun verify-invariants (root &optional print + &aux leaf-depth + (n-binary-internal 0) + (n-binary-leaf 0) + (n-unary-internal 0) + (n-unary-leaf 0)) + (sb-int:named-let recurse ((depth 0) (node root) + (min -1) + (max (1+ sb-ext:most-positive-word))) + (etypecase node + (unary-node + (assert (not (unary-node-p (child node)))) + (if (child node) + (incf n-unary-internal) + (incf n-unary-leaf)) + (recurse (1+ depth) (child node) min max)) + (binary-node + (if (fringe-binary-node-p node) + (incf n-binary-leaf) + (incf n-binary-internal)) + (multiple-value-bind (left key right) (binary-node-parts node) + ;; binary search tree invariant + (assert (< min key max)) + ;; brother tree invariant + (when (typep left 'unary-node) (assert (typep right 'binary-node))) + (when (typep right 'unary-node) (assert (typep left 'binary-node))) + ;; each descendant to the left has a key strictly less than this key + (recurse (1+ depth) left min key) + ;; each descendant to the right has a key strictly more than this key + (recurse (1+ depth) right key max))) + (null ; every leaf is at the same depth + (if leaf-depth + (assert (= depth leaf-depth)) + (setq leaf-depth depth))))) + (when print + (format t " depth : ~d~%" leaf-depth) + (format t " binary : ~d internal + ~d leaf~%" n-binary-internal n-binary-leaf) + (format t " unary : ~d internal + ~d leaf~%" n-unary-internal n-unary-leaf) + ;; The byte count is only correct if #+compact-instance-header + (format t " memory : ~d bytes~%" + (* (+ (* n-binary-internal 4) + (* (+ n-binary-leaf n-unary-internal n-unary-leaf) 2)) + sb-vm:n-word-bytes))) + (values leaf-depth (+ n-unary-internal n-unary-leaf))) +(compile 'verify-invariants) + +(defun height (tree &aux (n 0)) + (loop + (unless tree (return n)) + (incf n) + (typecase tree + (binary-node (setq tree (values (binary-node-parts tree)))) + (unary-node (setq tree (child tree)))))) + +(defun tree-count (tree) + (named-let recurse ((node tree)) + (typecase node + (binary-node + (multiple-value-bind (left key right) (binary-node-parts node) + (declare (ignore key)) + (+ 1 (recurse left) (recurse right)))) + (unary-node (recurse (child node))) + (t 0)))) + +(defun tree-from-list (list &optional (verify nil)) + (let ((tree)) + (dolist (item list tree) + (setq tree (insert item tree)) + (when verify + (verify-invariants tree))))) + +(defun tree-to-list (tree) + (let (result) + (named-let visit ((node tree)) + (typecase node + (unary-node + (visit (child node))) + (binary-node + (multiple-value-bind (left key right) (binary-node-parts node) + (visit right) + (push key result) + (visit left))))) + result)) + +(defun try-delete-everything (input) + (fill *cases* 0) + (format t "~&Pass 1: delete 1 item from original tree") + (let ((original-list (tree-to-list input))) + (dolist (item (test-util:shuffle (copy-list original-list))) + (let* ((new-tree (delete item input)) + (new-list (tree-to-list new-tree))) + ;;(format t "After deleting ~d: ~S~%" item *cases*) + (verify-invariants new-tree) + (assert (equal new-list (remove item original-list))))) + ;(print *cases*) + (fill *cases* 0) + (format t "~&Pass 2: delete all items from original tree") + (let ((deletion-order (test-util:shuffle (copy-list original-list))) + (tree input) + (list (tree-to-list input))) + (loop + (unless deletion-order (return)) + (let* ((item (pop deletion-order)) + (new-tree (delete item tree))) + (verify-invariants new-tree) + (setq list (cl:delete item list)) + (assert (equal (tree-to-list new-tree) list)) + (setq tree new-tree)))) + ;(print *cases*) + nil)) + +(defun random-big-list (count &optional (maxval (ash 1 30))) + (let ((h (make-hash-table))) + (loop + (when (zerop count) (return (loop for k being each hash-key of h collect k))) + (let ((n (random (min most-positive-fixnum maxval)))) + (unless (gethash n h) + (setf (gethash n h) t) + (decf count)))))) + +(defun insert-sequence (n &optional (verify t)) + (let ((tree)) + (loop for i from 1 to n + do (setq tree (insert (* i 10) tree)) + (when verify + (verify-invariants tree))) + tree)) +(defun insert-sequence-backwards (n &optional (verify t)) + (let ((tree)) + (loop for i downfrom n to 1 + do (setq tree (insert (* i 10) tree)) + (when verify + (verify-invariants tree))) + tree)) + +;; INSERT-SEQUENCE-BACKWARDS for N = (1- (expt 2 i)) +;; should never need unary nodes. Because magic. +(defun try-powers-of-2 (&optional (max-expt 18) print) + (loop for n = 1 then (* n 2) repeat (1+ max-expt) + do + (when print (format t "~&Trying ~d ..." n)) + (binding* ((tree (insert-sequence-backwards (1- n) nil)) + ((depth n-unary-nodes) (verify-invariants tree))) + (when print + (format t " depth=~d, ~d unary nodes~%" + depth n-unary-nodes)) + (assert (zerop n-unary-nodes))))) + +(defmacro microseconds-elapsed (form) + #+win32 + `(values 0 ,form) + #-win32 + `(multiple-value-bind (sec0 nsec0) (sb-unix::clock-gettime sb-unix:clock-realtime) + (let ((result ,form)) + (multiple-value-bind (sec1 nsec1) (sb-unix::clock-gettime sb-unix:clock-realtime) + (let ((abstime-before-usec (+ (* sec0 1000000) (floor nsec0 1000))) + (abstime-after-usec (+ (* sec1 1000000) (floor nsec1 1000)))) + (values (- abstime-after-usec abstime-before-usec) + result)))))) + +(defun tree-from-codeblobs () + (sb-sys:without-gcing + (let (blobs) + (sb-vm:map-code-objects + (lambda (x) + (push (- (sb-kernel:get-lisp-obj-address x) sb-vm:other-pointer-lowtag) + blobs))) + (format t "~&Done mapping~%") + (binding* (((et1 tree1) (microseconds-elapsed (tree-from-list blobs))) + ((et2 tree2) (microseconds-elapsed (tree-from-list (nreverse blobs))))) + (format t "~&Reverse: elapsed=~D~%" et1) + (verify-invariants tree1 t) + (format t "~&Forward: elapsed=~D~%" et2) + (terpri) + (verify-invariants tree2 t))))) + +(defun find-experiment (n) + (let* ((insertion-order (loop for i from 1 repeat n collect (* i 100))) + (tree)) +#| + ;; The AVL code is too slow to stress-test + (when (< n 4000) + (format t "~&AVL:") + (gc :full t) + (time (setq tree (build-avltree-from-ints insertion-order))) + (time (loop for i from 150 by 100 repeat n + do (let ((node (sb-thread:avl-find<= i tree))) + (assert (and node (= (sb-thread::avlnode-key node) + (- i 50)))))))) + (format t "~&Red/black:") + (gc :full t) + (time (setq tree (build-redblack-from-ints insertion-order))) + (time (loop for i from 150 by 100 repeat n + do (let ((node (sb-rbtree.word::find<= i tree))) + (assert (and node (= (sb-rbtree.word::node-key node) + (- i 50))))))) + (time (dolist (item insertion-order) + (setq tree (sb-rbtree.word:delete item tree)))) + (assert (null tree)) +|# + (format t "~&Brother:~%") + (gc :full t) + (time (setq tree (tree-from-list insertion-order))) + (time (loop for i from 150 by 100 repeat n + do (let ((node (find<= i tree))) + (assert (and node (= (binary-node-key node) + (- i 50))))))) + (time (dolist (item insertion-order) + (setq tree (delete item tree)))) + (assert (null tree)) + )) + +(defun delete-from-brothertree (tree list) + (dolist (item list tree) + (setq tree (delete item tree)))) +(defun insertion-deletion-experiment (n) + (let* ((insertion-order + (test-util:shuffle (loop for i below n collect i))) + (deletion-order + (test-util:shuffle (copy-list insertion-order))) + (tree)) +#| + (format t "~&Red/black:") + (time (setq tree (build-redblack-from-ints insertion-order))) + (format t "~&Height=~D~%" (redblack-tree-height tree)) + (time (setq tree (delete-from-redblack tree deletion-order))) + (assert (null tree)) +|# + (format t "~&Brother:~%") + (time (setq tree (tree-from-list insertion-order))) + (format t "~&Height=~D~%" (verify-invariants tree)) + (time (setq tree (delete-from-brothertree tree deletion-order))) + (assert (null tree)) + )) + +(macrolet ((define-c-wrapper (lisp-name c-name) + `(defun ,lisp-name (key tree) + (declare (sb-vm:word key)) + (sb-sys:with-pinned-objects (tree) + (let ((result + (sb-alien:alien-funcall + (sb-alien:extern-alien ,c-name + (function sb-alien:unsigned sb-alien:unsigned + sb-alien:unsigned)) + key + (sb-kernel:get-lisp-obj-address tree)))) + (unless (eql result sb-vm:nil-value) + (sb-kernel:make-lisp-obj result))))))) + (define-c-wrapper c-find<= "brothertree_find_lesseql") + (define-c-wrapper c-find>= "brothertree_find_greatereql")) + +(test-util:with-test (:name :find-inequality) + (dotimes (i 10) ; try with various trees resulting from different shuffles + (let* ((list (test-util:shuffle (loop for i from 100 by 100 repeat 25 collect i))) + (tree (tree-from-list list))) + (assert (not (find<= 99 tree))) + (assert (not (c-find<= 99 tree))) + (assert (not (find>= 10000 tree))) + (assert (not (c-find>= 10000 tree))) + (loop for key from 100 by 100 repeat 25 + do + (let ((node (find<= key tree))) + (assert (= (binary-node-key node) key)) + (assert (eq (c-find<= key tree) node))) + (let ((node (find>= key tree))) + (assert (= (binary-node-key node) key)) + (assert (eq (c-find>= key tree) node))) + (let ((node (find<= (1+ key) tree))) + (assert (= (binary-node-key node) key)) + (assert (eq (c-find<= (1+ key) tree) node))) + (let ((node (find>= (1- key) tree))) + (assert (= (binary-node-key node) key)) + (assert (eq (c-find>= (1- key) tree) node))) + (let ((node (find<= (+ key 99) tree))) + (assert (= (binary-node-key node) key)) + (assert (eq (c-find<= (+ key 99) tree) node))) + (let ((node (find>= (- key 99) tree))) + (assert (= (binary-node-key node) key)) + (assert (eq (c-find>= (- key 99) tree) node))))))) + +(test-util:with-test (:name :insert-delete) + (try-delete-everything (tree-from-list (random-big-list 2500)))) + +(test-util:with-test (:name :powers-of-2) + (try-powers-of-2)) diff --git a/tests/bsearch.pure.lisp b/tests/bsearch.pure.lisp new file mode 100644 index 0000000000..f7906301b5 --- /dev/null +++ b/tests/bsearch.pure.lisp @@ -0,0 +1,60 @@ +(macrolet ((define-c-wrapper (lisp-name c-name) + `(defun ,lisp-name (key array) + (declare (sb-vm:word key)) + (sb-sys:with-pinned-objects (array) + (let ((result + (sb-alien:alien-funcall + (sb-alien:extern-alien ,c-name + (function int sb-alien:unsigned + system-area-pointer int)) + key + (sb-sys:vector-sap array) (length array)))) + (unless (eql result -1) + (values result (aref array result)))))))) + (define-c-wrapper c-bsearch<= "bsearch_lesseql_uword") + (define-c-wrapper c-bsearch>= "bsearch_greatereql_uword")) + +(defun test-c-bsearch-sorted-vector () + (dotimes (vector-len 51) ; test the edge case of an empty vector + (let ((maxval 10000) + (a (make-array vector-len :initial-element 0 + :element-type 'sb-vm:word))) + (dotimes (i vector-len) + (let ((val (1+ (random maxval)))) + (loop while (find val a) ; repeat until unique + do (setq val (1+ (random maxval)))) + (setf (aref a i) val))) + (setq a (sort a #'<)) + (map-into a (lambda (x) (* x 5)) a) + ;; Keys less than the lowest in the array should not be found by <= + (assert (not (c-bsearch<= 0 a))) + (when (plusp vector-len) + (assert (not (c-bsearch<= (1- (aref a 0)) a)))) + ;; Keys larger than the largest item should not be found by >= + (assert (not (c-bsearch>= most-positive-fixnum a))) + (assert (not (c-bsearch>= most-positive-word a))) + (when (plusp vector-len) + (let ((greatest (aref a (1- vector-len)))) + (loop for i from 1 to 20 + do (assert (not (c-bsearch>= (+ greatest i) a)))))) + (dotimes (i vector-len) + (let ((k (aref a i))) + (assert (= (c-bsearch<= k a) i)) ; exact match + (assert (= (c-bsearch>= k a) i)) ; exact match + ;; Any key between K up to but excluding A[i+1] should find I by <= + (assert (= (c-bsearch<= (1+ k) a) i)) + (let ((higher (if (< (1+ i) vector-len) + (1- (aref a (1+ i))) + (+ k 10000)))) + (assert (= (c-bsearch<= higher a) i))) + ;; Any key down to A[i-1] should find I by >= + (assert (= (c-bsearch>= (1- k) a) i)) + (let ((lower (if (>= (1- i) 0) + (1+ (aref a (1- i))) + 0))) + (assert (= (c-bsearch>= lower a) i)))))))) + +(compile 'test-c-bsearch-sorted-vector) + +(with-test (:name :c-bsearch-sorted-vector) + (test-c-bsearch-sorted-vector)) diff --git a/tests/bug-1072739.pure.lisp b/tests/bug-1072739.pure.lisp new file mode 100644 index 0000000000..8baed8686a --- /dev/null +++ b/tests/bug-1072739.pure.lisp @@ -0,0 +1,51 @@ +;; win32 is very specific about the order in which catch blocks +;; must be allocated on the stack +;; +;; This test is extremely slow, so it deserves its own file. +(with-test (:name (compile :bug-1072739) :slow t) + (checked-compile-and-assert (:optimize :safe) + `(lambda () + (STRING= + (LET ((% 23)) + (WITH-OUTPUT-TO-STRING (G13908) + (PRINC + (LET () + (DECLARE (OPTIMIZE (SB-EXT:INHIBIT-WARNINGS 3))) + (HANDLER-CASE + (WITH-OUTPUT-TO-STRING (G13909) (PRINC %A%B% G13909) G13909) + (UNBOUND-VARIABLE NIL + (HANDLER-CASE + (WITH-OUTPUT-TO-STRING (G13914) + (PRINC %A%B% G13914) + (PRINC "" G13914) + G13914) + (UNBOUND-VARIABLE NIL + (HANDLER-CASE + (WITH-OUTPUT-TO-STRING (G13913) + (PRINC %A%B G13913) + (PRINC "%" G13913) + G13913) + (UNBOUND-VARIABLE NIL + (HANDLER-CASE + (WITH-OUTPUT-TO-STRING (G13912) + (PRINC %A% G13912) + (PRINC "b%" G13912) + G13912) + (UNBOUND-VARIABLE NIL + (HANDLER-CASE + (WITH-OUTPUT-TO-STRING (G13911) + (PRINC %A G13911) + (PRINC "%b%" G13911) + G13911) + (UNBOUND-VARIABLE NIL + (HANDLER-CASE + (WITH-OUTPUT-TO-STRING (G13910) + (PRINC % G13910) + (PRINC "a%b%" G13910) + G13910) + (UNBOUND-VARIABLE NIL + (ERROR "Interpolation error in \"%a%b%\" +")))))))))))))) + G13908))) + "23a%b%")) + (() t))) diff --git a/tests/bug-1180102.impure.lisp b/tests/bug-1180102.impure.lisp index 2a87a65833..b879694123 100644 --- a/tests/bug-1180102.impure.lisp +++ b/tests/bug-1180102.impure.lisp @@ -7,17 +7,30 @@ ;; thread already owned SB-THREAD:*MAKE-THREAD-LOCK* and the ;; interrupting code thus made a recursive lock attempt. +;; This test runs excruciatingly slowly on win32 without futexes. +;; Using n-threads = 100 with sb-futex, each trial took between .1 and .2 +;; seconds, so 200 trials took ~ 30 seconds. +;; Without sb-futex and that same number of threads, each trial took +;; between 1.5 and 2.5 seconds which would be 400 seconds total. +(defparameter *test-params* (or #+(and win32 (not sb-futex)) '(10 . 20) + '(100 . 100))) + (with-test (:name (:timer :dispatch-thread :make-thread :bug-1180102) :skipped-on (not :sb-thread)) (flet ((test (thread) (let ((timer (make-timer (lambda ()) :thread thread))) (schedule-timer timer .01 :repeat-interval 0.1) - (dotimes (i 100) - (let ((threads '())) - (dotimes (i 100) + (dotimes (i (car *test-params*)) + (let ((threads '()) + (start (get-internal-real-time))) + (declare (ignorable start)) + (dotimes (i (cdr *test-params*)) (push (sb-thread:make-thread (lambda () (sleep .01))) threads)) - (mapc #'sb-thread:join-thread threads))) + (mapc #'sb-thread:join-thread threads) + #+nil (format t "Trial ~d: ~f sec~%" i + (/ (- (get-internal-real-time) start) + internal-time-units-per-second)))) (unschedule-timer timer)))) (test t) (test sb-thread:*current-thread*))) diff --git a/tests/bug-255.lisp b/tests/bug-255.lisp new file mode 100644 index 0000000000..5503f5c732 --- /dev/null +++ b/tests/bug-255.lisp @@ -0,0 +1,24 @@ +(defpackage :bug255 (:use :cl)) +(in-package :bug255) +(declaim (optimize (safety 3) (debug 2) (speed 2) (space 1))) +(defvar *1*) +(defvar *2*) +(defstruct v a b) +(defstruct w) +(defstruct yam (v nil :type (or v null))) +(defstruct un u) +(defstruct (bod (:include un)) bo) +(defstruct (bad (:include bod)) ba) +(declaim (ftype (function ((or w bad) (or w bad)) (values)) %ufm)) +(defun %ufm (base bound) (froj base bound *1*) (values)) +(declaim (ftype (function ((vector t)) (or w bad)) %pu)) +(defun %pu (pds) (declare (ignore pds)) *2*) +(defun uu (yam) + (declare (ignore yam)) + (let ((v (yam-v az))) + (%ufm v + (flet ((project (x) (frob x 0))) + (let ((avecname *1*)) + (multiple-value-prog1 + (progn (%pu avecname)) + (frob))))))) diff --git a/tests/bug-936304.impure.lisp b/tests/bug-936304.impure.lisp index 173e15f09b..97086e758f 100644 --- a/tests/bug-936304.impure.lisp +++ b/tests/bug-936304.impure.lisp @@ -11,6 +11,7 @@ (let* ((x (make-array (truncate #-sb-safepoint (* 0.2 (dynamic-space-size)) #+sb-safepoint (* 0.1 (dynamic-space-size)) sb-vm:n-word-bytes)))) + (setf (elt x 0) t) (elt x 0))) (with-test (:name :bug-936304) diff --git a/tests/call-into-lisp.impure.lisp b/tests/call-into-lisp.impure.lisp index 8c047a9104..2320dfc88c 100644 --- a/tests/call-into-lisp.impure.lisp +++ b/tests/call-into-lisp.impure.lisp @@ -61,9 +61,9 @@ ;; Making room for 3 args aligns the stack to a 16-byte boundary ;; presuming it was at CALL to me. Darwin requires the alignment, others don't care. `((sub ,rsp-tn 24) - (mov ,(make-ea :qword :base rsp-tn :disp 16) ,(get-lisp-obj-address T)) - (mov ,(make-ea :qword :base rsp-tn :disp 8) ,(fixnumize 311)) - (mov ,(make-ea :qword :base rsp-tn :disp 0) ,(get-lisp-obj-address #\A)) + (mov :qword ,(ea 16 rsp-tn) ,(get-lisp-obj-address T)) + (mov :qword ,(ea 8 rsp-tn) ,(fixnumize 311)) + (mov :qword ,(ea 0 rsp-tn) ,(get-lisp-obj-address #\A)) (mov ,rdi-tn ,(get-lisp-obj-address #'monkeybiz)) ; C arg 0 = Lisp function (mov ,rsi-tn ,rsp-tn) ; C arg 1 = argv (mov ,rdx-tn :ARGC) ; C arg 2 = argc diff --git a/tests/callback.impure.lisp b/tests/callback.impure.lisp index 0fadd2fe10..29e93c8400 100644 --- a/tests/callback.impure.lisp +++ b/tests/callback.impure.lisp @@ -14,8 +14,11 @@ (in-package :cl-user) ;;; callbacks only on a few platforms -#-alien-callbacks -(exit :code 104) +;;; (actually, all platforms claim to support them now, +;;; and :alien-callbacks is almost everywhere defined. +;;; However mips doesn't seem to correctly implement them, +;;; making the feature indicator somewhat useless) +#+(or (not alien-callbacks) mips) (invoke-restart 'run-tests::skip-file) ;;; simple callback for a function @@ -58,7 +61,7 @@ (size int) (compar (function int (* double) (* double)))) -(sb-alien::define-alien-callback double*-cmp int ((arg1 (* double)) (arg2 (* double))) +(define-alien-callable double*-cmp int ((arg1 (* double)) (arg2 (* double))) (let ((a1 (deref arg1)) (a2 (deref arg2))) (cond ((= a1 a2) 0) @@ -73,69 +76,56 @@ (qsort (sb-sys:vector-sap vector) (length vector) (alien-size double :bytes) - double*-cmp)) + (alien-callable-function 'double*-cmp))) (assert (equalp vector sorted))) ;;; returning floats -(sb-alien::define-alien-callback redefined-fun int () - 0) +(define-alien-callable redefined-fun int () + 0) (eval - '(sb-alien::define-alien-callback redefined-fun int () + '(define-alien-callable redefined-fun int () 42)) -(assert (= 42 (alien-funcall redefined-fun))) +(assert (= 42 (alien-funcall (alien-callable-function 'redefined-fun)))) -(sb-alien::define-alien-callback return-single float ((x float)) +(define-alien-callable return-single float ((x float)) x) -(sb-alien::define-alien-callback return-double double ((x double)) +(define-alien-callable return-double double ((x double)) x) (defconstant spi (coerce pi 'single-float)) -(assert (= spi (alien-funcall return-single spi))) -(assert (= pi (alien-funcall return-double pi))) +(assert (= spi (alien-funcall (alien-callable-function 'return-single) spi))) +(assert (= pi (alien-funcall (alien-callable-function 'return-double) pi))) -;;; invalidation +;;; redefining and invalidating alien callables -(sb-alien::define-alien-callback to-be-invalidated int () - 5) +(define-alien-callable foo int () + 13) -(assert (= 5 (alien-funcall to-be-invalidated))) +(defvar *old-foo* (alien-callable-function 'foo)) -(multiple-value-bind (p valid) (sb-alien::alien-callback-p to-be-invalidated) +(multiple-value-bind (p valid) (sb-alien::alien-callback-p *old-foo*) (assert p) (assert valid)) -(sb-alien::invalidate-alien-callback to-be-invalidated) +(assert (= 13 (alien-funcall *old-foo*))) + +(define-alien-callable foo int () + 26) -(multiple-value-bind (p valid) (sb-alien::alien-callback-p to-be-invalidated) +(multiple-value-bind (p valid) (sb-alien::alien-callback-p *old-foo*) (assert p) (assert (not valid))) (multiple-value-bind (res err) - (ignore-errors (alien-funcall to-be-invalidated)) + (ignore-errors (alien-funcall *old-foo*)) (assert (and (not res) (typep err 'error)))) -;;; getting and setting the underlying function - -(sb-alien::define-alien-callback foo int () - 13) - -(defvar *foo* #'foo) - -(assert (eq #'foo (sb-alien::alien-callback-function foo))) - -(defun bar () - 26) - -(setf (sb-alien::alien-callback-function foo) #'bar) - -(assert (eq #'bar (sb-alien::alien-callback-function foo))) - -(assert (= 26 (alien-funcall foo))) +(assert (= 26 (alien-funcall (alien-callable-function 'foo)))) ;;; callbacks with void return values diff --git a/tests/ccase.pure.lisp b/tests/ccase.pure.lisp new file mode 100644 index 0000000000..e8c5e8d573 --- /dev/null +++ b/tests/ccase.pure.lisp @@ -0,0 +1,32 @@ + +(defparameter foofafoof (vector 0 0 0 0)) +(defglobal random-index nil) + +(with-test (:name :ccase-subforms-once-only) + ;; There should be exactly one use each of UNBOUND-SYMBOL and OBJECT-NOT-VECTOR. + (let ((ct-err-not-vector 0) + (ct-err-not-boundp 0) + (try-ccase (checked-compile `(lambda (x) + ;; We evaluate subforms of the keyform in CCASE (and CTYPECASE) once only. + ;; This is *not* a spec requirement because + ;; "The subforms of keyplace might be evaluated again if none of the cases holds." + ;; but it is an aspect of this particular implementation. + (ccase (svref foofafoof (let ((r (random x))) + (assert (not random-index)) + (setq random-index r) + r)) + ((a b) 'a-or-b) + (c 'see)))))) + (dolist (line (split-string + (with-output-to-string (stream) + (sb-disassem:disassemble-code-component try-ccase :stream stream)) + #\newline)) + (cond ((search "OBJECT-NOT-SIMPLE-VECTOR" line) (incf ct-err-not-vector)) + ((search "UNBOUND-SYMBOL-ERROR" line) (incf ct-err-not-boundp)))) + (assert (and (= ct-err-not-vector 1) + (= ct-err-not-boundp 1))) + (handler-bind ((type-error (lambda (condition) + (declare (ignorable condition)) + (invoke-restart 'store-value 'b)))) + (funcall try-ccase 4)) + (assert (eq (aref foofafoof random-index) 'b)))) diff --git a/tests/character.pure.lisp b/tests/character.pure.lisp index 9794c1377c..afc0b93885 100644 --- a/tests/character.pure.lisp +++ b/tests/character.pure.lisp @@ -145,7 +145,7 @@ (assert (equal `(function (t) (values (sb-kernel:character-set ((1 . ,(1- char-code-limit)))) &optional)) - (sb-impl::%fun-type f))))) + (sb-impl::%fun-ftype f))))) (with-test (:name (:case-insensitive-char-comparisons :eacute)) (assert (char-equal (code-char 201) (code-char 233)))) @@ -178,3 +178,14 @@ (with-test (:name :name-char-short-string) (name-char "") (name-char "A")) + +(with-test (:name :char-case-latin-1-base-strings) + (let ((string (map-into (make-array 10 :element-type 'character :adjustable t) + #'code-char + '(192 193 194 195 196 197 198 199 200 201)))) + (assert (equal + (map 'list #'char-code (nstring-downcase string)) + '(224 225 226 227 228 229 230 231 232 233))) + (assert (equal + (map 'list #'char-code (string-upcase string)) + '(192 193 194 195 196 197 198 199 200 201))) )) diff --git a/tests/classoid-typep.impure.lisp b/tests/classoid-typep.impure.lisp index c661cc5f75..ae37fb9dd3 100644 --- a/tests/classoid-typep.impure.lisp +++ b/tests/classoid-typep.impure.lisp @@ -9,7 +9,7 @@ ;;;; absoluely no warranty. See the COPYING and CREDITS files for ;;;; more information. -#-sb-thread (sb-ext:exit :code 104) +#-sb-thread (invoke-restart 'run-tests::skip-file) ;;; Using a fresh package as a namespace for classes is a quick-and-dirty ;;; way to create a class hierarchy without anonymous classes. @@ -35,14 +35,14 @@ (defclass baz () ()) (defclass bar (baz) (a)) (write-to-string *thing*) -(values *thing* (sb-kernel:%instance-layout *thing*)))")))) +(values *thing* (sb-kernel:%instance-wrapper *thing*)))")))) ;;; Given the PCL state set up by the above function, ;;; execute CLASSOID-TYPEP simultaneously in two threads. (defun concurrent-classoid-typep (obj) (let* ((sem (sb-thread:make-semaphore)) - (obj-layout (sb-kernel:%instance-layout obj)) - (classoid (sb-kernel:layout-classoid obj-layout)) + (obj-layout (sb-kernel:%instance-wrapper obj)) + (classoid (sb-kernel:wrapper-classoid obj-layout)) (fun (lambda () (sb-thread:wait-on-semaphore sem) (handler-case (sb-kernel:classoid-typep obj-layout classoid obj) diff --git a/tests/clos-1.impure.lisp b/tests/clos-1.impure.lisp index 670c597c4f..37a2bef25a 100644 --- a/tests/clos-1.impure.lisp +++ b/tests/clos-1.impure.lisp @@ -231,10 +231,15 @@ (:arguments &whole))) program-error)) -(define-method-combination bug-309084-b/mc nil - ((all *)) - (:arguments x &optional (y 'a yp) &key (z 'b zp) &aux (w (list y z))) - `(list ,x ,y ,yp ,z ,zp ,w)) +(let (warnings) + (handler-bind ((warning (lambda (c) (push c warnings)))) + (eval '(define-method-combination bug-309084-b/mc nil + ((all *)) + (:arguments x &optional (y 'a yp) &key (z 'b zp) &aux (w (list y z))) + `(list ,x ,y ,yp ,z ,zp ,w))) + ;; Should not get any "assigned but never read" warnings. + (assert (= (length warnings) 1)) + (assert (search "&OPTIONAL and &KEY" (princ-to-string (car warnings)))))) (defgeneric bug-309084-b/gf (a &optional b &key &allow-other-keys) (:method-combination bug-309084-b/mc) @@ -268,3 +273,46 @@ (eval '(defclass bug-1840595w () ())) (assert-error (eval '(defclass bug-1840595w () ((z :writer bug-1840595-z))))) (eval '(defclass bug-1840595w () ()))) + +(with-test (:name :bug-1909659/reader) + (eval '(defclass bug-1909659r () ((name :initarg :name :reader bug-1909659r-name)))) + (let ((one (make-instance 'bug-1909659r :name 1)) + (two (make-instance 'bug-1909659r :name 2))) + (assert-error (bug-1909659r-name one two) program-error) + (assert (eql (bug-1909659r-name one) 1)) + (assert (eql (bug-1909659r-name two) 2)))) + +(with-test (:name :bug-1909659/writer) + (eval '(defclass bug-1909659w () ((name :initarg :name :writer bug-1909659w-set-name)))) + (let ((one (make-instance 'bug-1909659w :name 1)) + (two (make-instance 'bug-1909659w :name 2))) + (assert-error (bug-1909659w-set-name one) program-error) + (assert-error (bug-1909659w-set-name two) program-error) + (bug-1909659w-set-name one two) + (assert (eql (slot-value one 'name) 1)) + (assert (eql (slot-value two 'name) one)))) + +(with-test (:name :defmethod-self-call-arg-mismatch + :skipped-on :interpreter) + (assert-signal (eval '(defmethod method-self-call (a b &key) + b + (method-self-call a))) + (and warning + (not sb-kernel:redefinition-warning))) + (assert-no-signal (eval '(defmethod method-self-call (a b &key z) + (method-self-call a b :z z))) + (and warning + (not sb-kernel:redefinition-warning))) + (assert-signal (eval '(defmethod method-self-call (a b &key j) + j + (method-self-call a b :z j))) + (and warning + (not sb-kernel:redefinition-warning))) + (eval '(defmethod method-self-call (a (b list) &key z) + (list a b z))) + + (assert-no-signal (eval '(defmethod method-self-call (a b &key j) + j + (method-self-call a b :z j :j 10))) + (and warning + (not sb-kernel:redefinition-warning)))) diff --git a/tests/clos-cache.impure.lisp b/tests/clos-cache.impure.lisp index a340e7cb67..9dbad73cbd 100644 --- a/tests/clos-cache.impure.lisp +++ b/tests/clos-cache.impure.lisp @@ -27,18 +27,18 @@ ;;; (The expression would be wrong if it reduced in the wrong direction, e.g.) (with-test (:name :compute-index-optimization) (macrolet ((optimized-way (a b c) - `(let ((a (sb-kernel:layout-clos-hash ,a)) - (b (sb-kernel:layout-clos-hash ,b)) - (c (sb-kernel:layout-clos-hash ,c))) + `(let ((a (sb-kernel:wrapper-clos-hash ,a)) + (b (sb-kernel:wrapper-clos-hash ,b)) + (c (sb-kernel:wrapper-clos-hash ,c))) ,(sb-pcl::cache-mixer-expression 'sb-int:mix '(a b c) nil)))) (let* ((l1 (sb-kernel:find-layout 'pathname)) (l2 (sb-kernel:find-layout 'cons)) (l3 (sb-kernel:find-layout 'integer)) (cache (sb-pcl::%make-cache :mask -1))) - (let ((safe-answer (sb-pcl::compute-cache-index cache (list l1 l2 l3))) + (let ((safe-answer (sb-pcl:compute-cache-index cache (list l1 l2 l3))) (optimized-answer (optimized-way l1 l2 l3))) (assert (= safe-answer optimized-answer))) - (let ((safe-answer (sb-pcl::compute-cache-index cache (list l1 l3 l2))) + (let ((safe-answer (sb-pcl:compute-cache-index cache (list l1 l3 l2))) (optimized-answer (optimized-way l1 l3 l2))) (assert (= safe-answer optimized-answer)))))) diff --git a/tests/clos-call-next-method.impure.lisp b/tests/clos-call-next-method.impure.lisp new file mode 100644 index 0000000000..4f516899d4 --- /dev/null +++ b/tests/clos-call-next-method.impure.lisp @@ -0,0 +1,134 @@ +;;;; Testing CALL-NEXT-METHOD. + +;;;; This software is part of the SBCL system. See the README file for +;;;; more information. +;;;; +;;;; While most of SBCL is derived from the CMU CL system, the test +;;;; files (like this one) were written from scratch after the fork +;;;; from CMU CL. +;;;; +;;;; This software is in the public domain and is provided with +;;;; absolutely no warranty. See the COPYING and CREDITS files for +;;;; more information. + +;;; CALL-NEXT-METHOD arguments are only fully checked on high safety. +(declaim (optimize (safety 3))) + +;;; Utilities +;;; +;;; It makes sense to cover all permutations of arguments since the +;;; order of calls can affect the construction of the CALL-NEXT-METHOD +;;; argument checker. + +;;; Assumes unique elements in SEQUENCE. +(defun map-permutations (function sequence) + (labels ((rec (partial-permutation remainder) + (if (null remainder) + (funcall function partial-permutation) + (map nil (lambda (element) + (rec (list* element partial-permutation) + (remove element remainder))) + remainder)))) + (rec '() sequence))) + +;;; RESET-FUNCTION is used to reset the generic function between +;;; permutations so caches are built up from scratch according to the +;;; following call sequence. +(defun map-test-case-permutations (reset-function check-function test-cases) + (map-permutations + (lambda (permutation) + (funcall reset-function) + (map nil (lambda (arguments-and-expected) + (destructuring-bind (arguments expected) arguments-and-expected + (funcall check-function arguments expected))) + permutation)) + test-cases)) + +;;; Make sure CALL-NEXT-METHOD calls that result in different sets of +;;; applicable methods signal errors. + +(defgeneric different-applicable-methods (thing) + (:method ((thing t)) + (list 't thing)) + (:method ((thing null)) + (list 'null thing)) + (:method ((thing list)) + (list 'list (call-next-method (rest thing)))) + (:method ((thing cons)) + (list 'cons (call-next-method (rest thing))))) + +(with-test (:name (call-next-method :different-applicable-methods)) + (map-test-case-permutations + (lambda () + (sb-pcl::update-dfun #'different-applicable-methods )) + (lambda (arguments expected) + (flet ((do-it () + (apply #'different-applicable-methods arguments))) + (case expected + (error (assert-error (do-it))) + (t (assert (equal (do-it) expected)))))) + '((((1 2 3)) (cons (list (t (3))))) + (((1 2)) error) + (((1)) error) + ((nil) (null nil))))) + +;;; Test calling the next method with non-EQL arguments of the same +;;; class. + +(defgeneric non-eql-arguments (x) + (:method ((x t)) + (list 't x)) + (:method ((x number)) + (list 'number (call-next-method (1+ x)))) + (:method ((x real)) + (list 'real (call-next-method (1+ x)))) + (:method ((x integer)) + (list 'integer (call-next-method (1+ x))))) + +(with-test (:name (call-next-method :same-applicable-methods :non-eql-arguments)) + (map-test-case-permutations + (lambda () + (sb-pcl::update-dfun #'non-eql-arguments)) + (lambda (arguments expected) + (assert (equal (apply #'non-eql-arguments arguments) expected))) + '(((1) (integer (real (number (t 4))))) + ((1/2) (real (number (t 5/2)))) + ((#C(1 2)) (number (t #C(2 2))))))) + +;;; Test EQL specializers which always require a dedicated method in +;;; the CALL-NEXT-METHOD argument checker. + +(defgeneric eql-specializer (x) + (:method ((x t)) + (list 't x)) + (:method ((x number)) + (list 'number (call-next-method (1+ x)))) + (:method ((x real)) + (list 'real (call-next-method (1+ x)))) + (:method ((x integer)) + (list 'integer (call-next-method (1+ x)))) + (:method ((x (eql 4))) + (list 'eql 4 (call-next-method (1+ x)))) + (:method ((x (eql 5))) + (list 'eql 5 (call-next-method (1+ x))))) + +(with-test (:name (call-next-method :eql-specializer)) + (map-test-case-permutations + (lambda () + (sb-pcl::update-dfun #'eql-specializer)) + (lambda (arguments expected) + (flet ((do-it () + (apply #'eql-specializer arguments))) + (case expected + (error (assert-error (do-it))) + (t (assert (equal (do-it) expected)))))) + '(((0) (integer (real (number (t 3))))) + ((1) error) + ;; ((2) error) ; too slow otherwise (exponential scaling) + ((3) error) + ;; ((4) error) + ((5) error) + ((6) (integer (real (number (t 9))))) + ((1/2) (real (number (t 5/2)))) + ((#C(1 2)) (number (t #C(2 2)))) + ((:foo) (t :foo))))) diff --git a/tests/clos-typechecking.impure.lisp b/tests/clos-typechecking.impure.lisp index e8e3e212cf..46f9a8638c 100644 --- a/tests/clos-typechecking.impure.lisp +++ b/tests/clos-typechecking.impure.lisp @@ -13,7 +13,7 @@ ;;;; more information. ;;; Typechecking should be working, but it isn't. -#+interpreter (sb-ext:exit :code 104) +#+interpreter (invoke-restart 'run-tests::skip-file) (shadow 'slot) diff --git a/tests/clos.impure-cload.lisp b/tests/clos.impure-cload.lisp index 87e3866f21..6ca8013206 100644 --- a/tests/clos.impure-cload.lisp +++ b/tests/clos.impure-cload.lisp @@ -186,10 +186,10 @@ (call-next-method))) (defvar *compile-count* 0) -(sb-int:encapsulate 'compile 'call-counter - (lambda (f name thing) +(sb-int:encapsulate 'sb-c:compile-in-lexenv 'call-counter + (lambda (realfun &rest args) (incf *compile-count*) - (funcall f name thing))) + (apply realfun args))) (defstruct mystruct-r/w (some-slot)) (defstruct mystruct-r/o (allegedly-immutable-slot 3 :read-only t)) @@ -207,6 +207,6 @@ ;; hide the slot name from the compiler so it doesn't optimize (slot-name (eval ''allegedly-immutable-slot))) (setf (slot-value myobj slot-name) :newval1) - (assert (= *compile-count* (1+ old-count))) + (assert (= *compile-count* old-count)) ; no compilation (setf (slot-value myobj slot-name) :newval2) - (assert (= *compile-count* (1+ old-count))))) ; same as before + (assert (= *compile-count* old-count)))) ; no compilation diff --git a/tests/clos.impure.lisp b/tests/clos.impure.lisp index 104d991785..af87c01443 100644 --- a/tests/clos.impure.lisp +++ b/tests/clos.impure.lisp @@ -11,7 +11,7 @@ ;;;; absolutely no warranty. See the COPYING and CREDITS files for ;;;; more information. -#+interpreter (sb-ext:exit :code 104) +#+interpreter (invoke-restart 'run-tests::skip-file) (load "compiler-test-util.lisp") (defpackage "CLOS-IMPURE" @@ -443,7 +443,7 @@ ;; FORWARD-REFERENCED-CLASS CHANGE-CLASS.FORWARD-REFERENCED.3. (defclass change-class.forward-referenced.2 (change-class.forward-referenced.3) ()) -(with-test (:name (change-class sb-pcl:forward-referenced-class)) +(with-test (:name (change-class sb-mop:forward-referenced-class)) (mapc #'change-class-test-case '(;; Changing instances of "ordinary classes" to classes which are @@ -846,16 +846,16 @@ (assert-error (defmethod incompatible-ll-test-1 (x &rest y) y)) ;;; Sneakily using a bit of MOPness to check some consistency (assert (= (length - (sb-pcl:generic-function-methods #'incompatible-ll-test-1)) 1)) + (sb-mop:generic-function-methods #'incompatible-ll-test-1)) 1)) (defmethod incompatible-ll-test-2 (x &key bar) bar) (assert-error (defmethod incompatible-ll-test-2 (x) x)) (defmethod incompatible-ll-test-2 (x &rest y) y) (assert (= (length - (sb-pcl:generic-function-methods #'incompatible-ll-test-2)) 1)) + (sb-mop:generic-function-methods #'incompatible-ll-test-2)) 1)) (defmethod incompatible-ll-test-2 ((x integer) &key bar) bar) (assert (= (length - (sb-pcl:generic-function-methods #'incompatible-ll-test-2)) 2)) + (sb-mop:generic-function-methods #'incompatible-ll-test-2)) 2)) ;;; Per Christophe, this is an illegal method call because of 7.6.5 (handler-bind ((style-warning #'muffle-warning)) @@ -1135,6 +1135,7 @@ (call-next-method)) (:method (x (y (eql nil))) (setf y t) + (opaque-identity y) ; or else "assigned but never read" style-warning (call-next-method))) (with-test (:name (:cnm-assignment :bug-1734771 1)) (assert (equal (bug-1734771 2 3) '(2 3)))) @@ -2635,7 +2636,7 @@ (eval `(defclass ,class2 (,class1) ())) (let ((instance (make-instance class2))) (sb-mop:finalize-inheritance (find-class class1)) - (assert (not (sb-kernel:layout-invalid (sb-kernel:layout-of instance))))))) + (assert (not (sb-kernel:wrapper-invalid (sb-kernel:wrapper-of instance))))))) (with-test (:name (allocate-instance :on symbol)) (let ((class (gensym "CLASS-"))) @@ -2654,7 +2655,7 @@ unbound-slot)) (with-test (:name :layouf-of-nil) - (assert (eq (sb-kernel:layout-of nil) (sb-kernel:find-layout 'null)))) + (assert (eq (sb-kernel:wrapper-of nil) (sb-kernel:find-layout 'null)))) (with-test (:name (defmethod :on-classless-type)) (handler-bind ((timeout (lambda (condition) @@ -2676,3 +2677,20 @@ (with-test (:name :removing-a-class) (sb-ext:gc :full t) (assert (not (sb-ext:weak-pointer-value *removing-a-class*)))) + +(locally (declare (optimize safety)) + (defclass setf-slot-value-restart () + ((a :type integer + :accessor setf-slot-value-restart-a)))) + +(with-test (:name :setf-slot-value-restart + :skipped-on :sparc) ; hangs + (let ((instance (make-instance 'setf-slot-value-restart))) + (handler-bind ((type-error + (lambda (c) (use-value 1 c)))) + (setf (slot-value instance 'a) 'x)) + (assert (eql (slot-value instance 'a) 1)) + (handler-bind ((type-error + (lambda (c) (use-value 2 c)))) + (setf (setf-slot-value-restart-a instance) 'y)) + (assert (eql (setf-slot-value-restart-a instance) 2)))) diff --git a/tests/clos.pure.lisp b/tests/clos.pure.lisp index a9bf897d83..33af8c6afd 100644 --- a/tests/clos.pure.lisp +++ b/tests/clos.pure.lisp @@ -39,6 +39,18 @@ (declare (ignore value)) (assert (not format-err))))) +(with-test (:name (defclass :initform type-error)) + (mapc (lambda (form) + (assert (nth-value 1 (checked-compile + `(lambda () ,form) :allow-warnings t)))) + '(;; Special-cased initforms + (defclass foo () ((%bar :type integer :initform t))) + (defclass foo () ((%bar :type integer :initform nil))) + (defclass foo () ((%bar :type boolean :initform 0))) + ;; Ordinary initforms + (defclass foo () ((%bar :type integer :initform (lisp-implementation-version)))) + (defclass foo () ((%bar :type boolean :initform (random 2))))))) + ;;; another not (user-)observable behaviour: make sure that ;;; sb-pcl::map-all-classes calls its function on each class once and ;;; exactly once. @@ -82,16 +94,26 @@ (setf (slot-value x z) (slot-value y z))) :allow-notes nil)) -(with-test (:name :slot-table-of-symbol-works) - (assert (eq :win - ;; the error that I want is about a missing slot, - ;; not a missing method, so don't let the compiler turn - ;; this into (funcall #'(SLOT-ACCESSOR :GLOBAL A READER)...) - (handler-case (eval '(slot-value 'a 'a)) - (simple-condition (c) - (and (search "slot ~S is missing" - (simple-condition-format-control c)) - :win)))))) +(defun assert-no-such-slot (obj slot-name) + (dolist (method '(slot-value slot-boundp)) + (assert (eq :win + ;; the error that I want is about a missing slot, + ;; not a missing method, so don't let the compiler turn + ;; this into (funcall #'(SLOT-ACCESSOR :GLOBAL A READER)...) + (handler-case (eval `(,method ',obj ',slot-name)) + (simple-condition (c) + (and (search "slot ~S is missing" + (simple-condition-format-control c)) + :win)))))) + ;; and of course SLOT-EXISTS-P should just return NIL + (assert (not (slot-exists-p obj slot-name)))) + +(with-test (:name :slot-table-of-builtin-classoids) + (assert-no-such-slot 'some-symbol 'some-slot) + (assert-no-such-slot #P"foo" 'some-slot) + (let ((lpn #p"sys:contrib;")) + (assert (typep lpn 'logical-pathname)) + (assert-no-such-slot lpn 'some-slot))) (with-test (:name :funcallable-instance-sxhash) (assert @@ -104,3 +126,29 @@ `(lambda (x) (typep x #.(find-class 'symbol))) (('x) t))) + +(with-test (:name :slot-value-on-not-slot-object) + (checked-compile-and-assert () + `(lambda (x) + (slot-value x 'm)) + ((nil) (condition 'sb-pcl::missing-slot))) + (checked-compile-and-assert () + `(lambda (x) + (slot-boundp x 's)) + ((1) (condition 'sb-pcl::missing-slot))) + (checked-compile-and-assert () + `(lambda (x) + (setf (slot-value x 'j) 30)) + ((1.0) (condition 'sb-pcl::missing-slot))) + (checked-compile-and-assert () + `(lambda (x) + (slot-makunbound x 'l)) + ((#\a) (condition 'sb-pcl::missing-slot)))) + + +(with-test (:name :illegal-class-name) + (checked-compile-and-assert + () + `(lambda (x) + (find-class x)) + (('(t)) (condition 'sb-kernel::illegal-class-name-error)))) diff --git a/tests/clos.test.sh b/tests/clos.test.sh index 9f8d4e1c37..b269dfb24b 100644 --- a/tests/clos.test.sh +++ b/tests/clos.test.sh @@ -69,5 +69,23 @@ cat > $tmpfilename <<EOF EOF expect_clean_compile $tmpfilename +# Test that slots with similar names don't trigger warnings if neither +# name is exported. + +cat > $tmpfilename <<EOF + (defpackage "INT" + (:use "CL") + (:export "EX")) + (in-package "INT") + (defclass ex () + ((a-slot :initarg :a-slot))) + (in-package :cl-user) + (handler-bind ((warning (lambda (c) (error "caught warning: ~A" c)))) + (defclass why (int:ex) + ((a-slot :initarg :a-slot))) + (sb-mop:finalize-inheritance (find-class 'why))) +EOF +expect_clean_cload $tmpfilename + # success exit $EXIT_TEST_WIN diff --git a/tests/coalesce.pure.lisp b/tests/coalesce.pure.lisp new file mode 100644 index 0000000000..c3facfc1c7 --- /dev/null +++ b/tests/coalesce.pure.lisp @@ -0,0 +1,6 @@ +(with-test (:name :symbol-name-coalescing) + (dolist (testcase '("LAYOUTS" "CLASS1" "DST-OFFSET" "NIL" #+sb-unicode "T")) + (let ((symbols (find-all-symbols testcase))) + (assert (> (length symbols) 1)) + (assert (every (lambda (x) (eq x (symbol-name (car symbols)))) + (mapcar 'symbol-name (cdr symbols))))))) diff --git a/tests/coerce.pure.lisp b/tests/coerce.pure.lisp index 2a304d2d1d..b43698e93d 100644 --- a/tests/coerce.pure.lisp +++ b/tests/coerce.pure.lisp @@ -121,9 +121,9 @@ ;; But at least it's generally an improvement ;; to fail earlier than later in many cases. (multiple-value-bind (fun failure-p warnings) - (checked-compile '(lambda () + (checked-compile '(lambda (z) (locally (declare (notinline sort)) - (sort () #'< :key 'and))) + (sort () z :key 'and))) :allow-warnings t) (declare (ignore failure-p)) (assert (= 1 (length warnings))) @@ -137,3 +137,30 @@ ((10) 10.0) ((1/2) 0.5) ((30d0) 30d0))) + +(with-test (:name :no-coerce-to-values-type) + (multiple-value-bind (fun warnp errorp) + (checked-compile '(lambda (x) (coerce (list x) '(values list))) + :allow-warnings t) + (assert (and warnp errorp)) + (assert-error (funcall fun 1)))) + +;; lp#1929614 +(with-test (:name :no-coerce-to-union-of-array) + (let ((fun + (checked-compile '(lambda (x) + (declare (optimize speed)) ; want to see notes + ;; safety doesn't matter now (in terms of getting + ;; the transform to try to run), but it used to matter, + ;; so keep it in. + (declare (optimize (safety 0))) + (coerce x '(or (array (signed-byte 8) (*)) + (array (unsigned-byte 8) (*)))))))) + (assert-error (funcall fun '(1 2 1))))) + +(with-test (:name :coerce-array) + (checked-compile-and-assert + () + `(lambda (a) + (coerce a 'array)) + ((#(1)) #(1) :test #'equalp))) diff --git a/tests/compare-and-swap.impure.lisp b/tests/compare-and-swap.impure.lisp index 8c155febe6..0ae716e436 100644 --- a/tests/compare-and-swap.impure.lisp +++ b/tests/compare-and-swap.impure.lisp @@ -502,20 +502,6 @@ (eval `(let (,@(mapcar 'list vars vals)) ,read-form))))))) -(let ((foo (cons :foo nil))) - (defun cas-foo (old new) - (cas (cdr foo) old new))) - -(defcas foo () cas-foo) - -(with-test (:name :cas-and-macroexpansion) - (assert (not (cas (foo) nil t))) - (assert (eq t (cas (foo) t nil))) - (symbol-macrolet ((bar (foo))) - (assert (not (cas bar nil :ok))) - (assert (eq :ok (cas bar :ok nil))) - (assert (not (cas bar nil t))))) - (with-test (:name :atomic-push :skipped-on (not :sb-thread)) (let ((store (cons nil nil)) @@ -553,17 +539,6 @@ (atomic-pop (symbol-value 'x)))))) 1))) -#+x86-64 ; missing symbol sb-vm::signed-sap-cas-32 otherwise -(with-test (:name :cas-sap-ref - :skipped-on :interpreter) - (let ((v (make-array 2 :element-type '(signed-byte 32) - :initial-element -1))) - (let ((old (sb-sys:%primitive sb-vm::signed-sap-cas-32 - (sb-sys:vector-sap v) - 0 -1 1))) - (assert (= old -1)) - (assert (eql (aref v 0) 1))))) - (in-package "SB-VM") ;;; This file defines a structure, so is an 'impure' test @@ -617,3 +592,90 @@ (and #+x86(logbitp 8 d) #+x86-64(logbitp 13 c) (test-wide-cmpxchg)))) (format t "Double-width compare-and-swap NOT TESTED~%")))) + +(test-util:with-test (:name :cas-sap-ref-smoke-test + :skipped-on (not (and :sb-thread (or :ppc64 :x86-64)))) + (let ((data (make-array 1 :element-type 'sb-vm:word))) + (sb-sys:with-pinned-objects (data) + (let ((sap (sb-sys:vector-sap data))) + ;; It's important to exercise an initial value that has lots of bits on, + ;; because I made at least two mistakes in the x86-64 lispword-sized vop: + ;; 1. it was using a :dword move where it should have used a :qword + ;; 2. it was emitting constants as bignums instead of inline raw constants + (macrolet ((test (signedp nbits newval + &aux (ref (symbolicate + (if signedp "SIGNED-" "") + "SAP-REF-" + (write-to-string nbits))) + (init (if signedp -1 + (ldb (byte nbits 0) most-positive-word)))) + `(progn + ;; (format t "Testing ~a with initial bits ~x~%" ',ref ,init) + (setf (,ref sap 0) ,init) + (let ((old (cas (,ref sap 0) 0 5))) + (assert (eql old ,init)) ; actual old + (assert (eql (,ref sap 0) ,init))) ; memory should not have changed + (let ((old (cas (,ref sap 0) ,init ,newval))) + (assert (eql old ,init)) ; actual old + (assert (eql (,ref sap 0) ,newval)))))) ; should have changed + (test nil 64 #xdeadc0fefe00) + (test t 64 most-negative-fixnum) + (test nil 32 #xbabab00e) + #-ppc64 (test nil 16 #xfafa) ; gets "illegal instruction" if unimplemented + #-ppc64 (test nil 8 #xbb) + ) + ;; SAP-REF-SAP + (setf (aref data 0) 0) + (let ((old (cas (sap-ref-sap sap 0) (int-sap 1) (int-sap #xffff)))) + (assert (sb-sys:sap= old (int-sap 0))) ; actual old + (assert (sb-sys:sap= (sap-ref-sap sap 0) (int-sap 0)))) ; memory should not have changed + (let ((old (cas (sap-ref-sap sap 0) (int-sap 0) (int-sap sb-ext:most-positive-word)))) + (assert (sb-sys:sap= old (int-sap 0))) + (assert (sb-sys:sap= (sap-ref-sap sap 0) (int-sap sb-ext:most-positive-word)))) + ;; SAP-REF-LISPOBJ + (setf (aref data 0) sb-vm:nil-value) + (let ((old (cas (sap-ref-lispobj sap 0) t '*print-base*))) + (assert (eq old nil)) ; actual old + (assert (eq (sap-ref-lispobj sap 0) nil))) ; memory should not have changed + (let ((old (cas (sap-ref-lispobj sap 0) nil t))) + (assert (eq old nil)) + (assert (eq (sap-ref-lispobj sap 0) t))))))) + +(test-util:with-test (:name :cas-sap-ref-stress-test + :skipped-on (not (and :sb-thread (or :ppc64 :x86-64)))) + (let ((data (make-array 1 :element-type 'sb-vm:word + :initial-element 0))) + (sb-sys:with-pinned-objects (data) + (let ((sap (sb-sys:vector-sap data)) + (n-threads 3) + (n-increments 100000) + (threads)) + (flet ((increment () + (let ((fails 0)) + (dotimes (i n-increments fails) + (let ((old (sap-ref-32 sap 0))) + (loop + (let ((actual (cas (sap-ref-32 sap 0) old (1+ old)))) + (if (eq actual old) (return)) + (incf fails) + (setq old actual)))))))) + (dotimes (i n-threads) + (push (sb-thread:make-thread #'increment) threads)) + (mapc 'sb-thread:join-thread threads) + (assert (= (sap-ref-32 sap 0) (* n-threads n-increments)))))))) + +(define-alien-variable "small_generation_limit" (signed 8)) +;; PPC64 shouldn't fail, but depending on the CPU revision it might not +;; have the needed instruction, and I don't know how to test for it. +;; And surely it doesn't really depend on endian-ness, but the machine +;; that I'm testing on which is little-endian passes the test. +#+(and sb-thread (or x86-64 (and ppc64 little-endian))) +(progn +(defun cas-an-alien-byte (x y) (cas small-generation-limit x y)) +(compile 'cas-an-alien-byte) +(test-util:with-test (:name :cas-alien) + (assert (= small-generation-limit 1)) + (assert (= (cas-an-alien-byte 0 5) 1)) + (assert (= (cas-an-alien-byte 1 6) 1)) + (assert (= small-generation-limit 6)) + (setf small-generation-limit 1))) diff --git a/tests/compiler-1.impure-cload.lisp b/tests/compiler-1.impure-cload.lisp index bbd005a7cb..9de222f823 100644 --- a/tests/compiler-1.impure-cload.lisp +++ b/tests/compiler-1.impure-cload.lisp @@ -24,11 +24,11 @@ ;;; inference behavior it's intended to test.) (defun emptyvalues (&rest rest) (declare (ignore rest)) (values)) (defstruct foo x y) -(defun bar () +(defun bar0 () (let ((res (emptyvalues))) (unless (typep res 'foo) 'expected-value))) -(assert (eq (bar) 'expected-value)) +(assert (eq (bar0) 'expected-value)) (declaim (ftype (function (real) (values integer single-float)) valuesify)) (defun valuesify (x) @@ -66,25 +66,25 @@ ;;; and then use them to optimize code later [and it was almost ;;; right!]. This is of course bad when functions are redefined. The ;;; problem was fixed in sbcl-0.6.12.57. -(defun foo (x) +(defun foo1 (x) (if (plusp x) 1.0 0)) (eval '(locally - (defun bar (x) - (typecase (foo x) + (defun bar1 (x) ; don't conflict with BAR from the test way up top + (typecase (foo1 x) (fixnum :fixnum) (real :real) (string :string) (t :t))) - (compile 'bar))) -(assert (eql (bar 11) :real)) -(assert (eql (bar -11) :fixnum)) -(setf (symbol-function 'foo) #'identity) -(assert (eql (bar 11) :fixnum)) -(assert (eql (bar -11.0) :real)) -(assert (eql (bar "this is a test") :string)) -(assert (eql (bar (make-hash-table)) :t)) + (compile 'bar1))) +(assert (eql (bar1 11) :real)) +(assert (eql (bar1 -11) :fixnum)) +(setf (symbol-function 'foo1) #'identity) +(assert (eql (bar1 11) :fixnum)) +(assert (eql (bar1 -11.0) :real)) +(assert (eql (bar1 "this is a test") :string)) +(assert (eql (bar1 (make-hash-table)) :t)) ;;; bug reported by Brian Spilsbury sbcl-devel 2001-09-30, fixed by ;;; Alexey Dejneka patch sbcl-devel 2001-10-02 @@ -154,28 +154,13 @@ (defun bug115-2 () (declare (optimize (speed 2) (debug 3))) (flet ((m1 () - (bar (if (foo) 1 2)) - (let ((x (foo))) - (bar x (list x))))) + (bar2 (if (foo0) 1 2)) + (let ((x (foo0))) + (bar2 x (list x))))) (if (catch nil) (m1) (m1)))) -(defun bug226 () - (declare (optimize (speed 0) (safety 3) (debug 3))) - (flet ((safe-format (stream string &rest r) - (unless (ignore-errors (progn - (apply #'format stream string r) - t)) - (format stream "~&foo ~S" string)))) - (cond - ((eq my-result :ERROR) - (cond - ((ignore-errors (typep condition result)) - (safe-format t "~&bar ~S" result)) - (t - (safe-format t "~&baz ~S (~A) ~S" condition condition result))))))) - ;;; bug 231: SETQ did not check the type of the variable being set (defun bug231a-1 (x) (declare (optimize safety) (type (integer 0 8) x)) diff --git a/tests/compiler-2.impure-cload.lisp b/tests/compiler-2.impure-cload.lisp index eb58a4b32a..4c02fda0da 100644 --- a/tests/compiler-2.impure-cload.lisp +++ b/tests/compiler-2.impure-cload.lisp @@ -54,13 +54,13 @@ (quux (1- n))))) (defun frob (x) - (setf (fdefinition x) (constantly 13))) + (setf (fdefinition x) (constantly -11))) (defun test () (list (foo 1) (bar 1) (quux 1))) (assert (equal (test) '(0 0 0))) -(assert (equal (test) '(13 13 13))) ; sanity check +(assert (equal (test) '(-11 -11 -11))) ; sanity check ;;; Bug in 1.0.2 and 1.0.3, where the XEP was compiled with the wrong ;;; policy. (Test-case derived from code posted by alexander.ekart in diff --git a/tests/compiler-2.impure.lisp b/tests/compiler-2.impure.lisp index de46d90396..20545967fc 100644 --- a/tests/compiler-2.impure.lisp +++ b/tests/compiler-2.impure.lisp @@ -56,7 +56,7 @@ (def-mystruct)) ; MAKE-MYSTRUCT captures a lexenv (rather pointlessly) ;;; Assert that throwaway code in compiled macrolets does not go in immobile space -#+immobile-space +#+immobile-code (with-test (:name :macrolet-not-immobile-space :serial t :skipped-on :interpreter) (labels ((count-code-objects () @@ -80,3 +80,10 @@ (test '(lambda (x) (macrolet ((baz (arg) `(- ,arg))) (list (baz x))))) ;; Test 2: inline a function that captured a macrolet (test '(lambda (x) (make-mystruct :a x))))) + +(with-test (:name (reduce :type-deriver :wild-array-upgraded-type)) + (checked-compile-and-assert + () + `(lambda (x) (declare (type vector x)) (reduce #'+ x)) + ((#(1 2 3)) 6) + (((make-array 3 :element-type '(unsigned-byte 8) :initial-contents '(4 5 6))) 15))) diff --git a/tests/compiler-2.pure.lisp b/tests/compiler-2.pure.lisp index 3aa5385818..bf305d9ad8 100644 --- a/tests/compiler-2.pure.lisp +++ b/tests/compiler-2.pure.lisp @@ -26,6 +26,20 @@ (defun compiles-with-warning (lambda) (assert (nth-value 2 (checked-compile lambda :allow-warnings t)))) +(with-test (:name :duplicate-labels) + (dolist (operator '(labels flet macrolet)) + (multiple-value-bind (fun warn err) + (let ((*error-output* (make-broadcast-stream))) + (compile nil `(lambda (x) + (declare (ignorable x)) + (,operator ((f (z) z 2) + (f (z) z 3)) + (f x))))) + ;; I'm not asserting on the result of calling FUN + ;; because I don't really care what it is. + (declare (ignore fun)) + (assert (and warn err))))) + (with-test (:name (position :derive-type)) (checked-compile '(lambda (x) (ash 1 (position (the (member a b c) x) #(a b c ))))) @@ -157,15 +171,14 @@ (sb-vm:map-allocated-objects #'f :dynamic) 5)))) -(with-test (:name :pack-varints-as-bignum) +(with-test (:name :pack-varints-as-bignum + :skipped-on :interpreter) ; too slow (dotimes (i 500) ; do some random testing this many times (let* ((random-numbers (loop repeat (+ (random 20) 3) collect (1+ (random 4000)))) (test-list (sort (delete-duplicates random-numbers) #'<)) - (packed-int (sb-c::pack-code-fixup-locs test-list nil)) - (result (make-array 1 :element-type 'sb-ext:word))) - ;; The packer intrinsically self-checks the packing - ;; so we don't need to assert anything about that. + (packed-int (sb-c:pack-code-fixup-locs test-list nil nil)) + (result (make-array 1 :element-type '(unsigned-byte 32)))) (sb-sys:with-pinned-objects (packed-int result) ;; Now exercise the C unpacker. ;; This hack of allocating 4 longs is terrible, but whatever. @@ -204,26 +217,7 @@ ;; Should not have a call to SET-SYMBOL-GLOBAL-VALUE> (assert (not (ctu:find-code-constants f :type 'sb-kernel:fdefn)))))) -(with-test (:name :layout-constants - :skipped-on (not (and :x86-64 :immobile-space))) - (let ((addr-of-pathname-layout - (write-to-string - (sb-kernel:get-lisp-obj-address - (sb-kernel:find-layout 'hash-table)) - :base 16 :radix t)) - (count 0)) - ;; The constant should appear in two CMP instructions - (dolist (line (split-string - (with-output-to-string (s) - (let ((sb-disassem:*disassem-location-column-width* 0)) - (disassemble 'hash-table-p :stream s))) - #\newline)) - (when (and (search "CMP" line) (search addr-of-pathname-layout line)) - (incf count))) - (assert (= count 2)))) - -;; Whoever deals with the Alpha and/or HPPA ports can make this test pass for them -(with-test (:name :linkage-table-bogosity) +(with-test (:name :alien-linkage-table-bogosity) (let ((strings (map 'list (lambda (x) (if (consp x) (car x) x)) sb-vm::+required-foreign-symbols+))) (assert (= (length (remove-duplicates strings :test 'string=)) @@ -512,6 +506,68 @@ (%f 1)))) (() 321))) +(with-test (:name :assignment-conversion-inside-deleted-lambda) + (checked-compile-and-assert + (:allow-style-warnings t) + `(lambda (b) + (tagbody + (labels ((%f13 (&optional (f13-1 0) &key &allow-other-keys) + (declare (ignore f13-1)) + b)) + (if nil + (%f13 (go tag8)) + (%f13))) + tag8)) + ((1) nil))) + +(with-test (:name :nil-type-derived-before-assignment-conversion) + (checked-compile-and-assert () + `(lambda (a) + (declare (ignore a)) + (tagbody + (labels ((f (a) + (declare (ignore a)) + (go tag1))) + (apply #'f 1 (list)) + (apply #'f (catch 'ct (go tag1)) (list))) + tag1)) + ((1) nil))) + +(with-test (:name :assignment-convert-untail-outside-calls) + (checked-compile-and-assert () + `(lambda () + (flet ((%f17 (&optional f17-1) + (declare (ignore f17-1)) + (block block608 + (block block606 + (flet ((h0 () + (return-from block606))) + (declare (dynamic-extent #'h0)) + (return-from block608 + (progn + (print #'h0) + nil))))))) + (when nil (%f17)) + (if t + (%f17) + (when nil + (%f17))))) + (() nil))) + +(with-test (:name :assignment-convert-lambda-with-deleted-bind-block) + (checked-compile-and-assert () + `(lambda () + (flet ((%f5 () + (flet ((%f2 (&optional (f2-2 (return-from %f5 1))) + 0)) + (let ((g624 1)) + (cond ((eql g624 '1) + (%f2)) + ((eql g624 '2) + (%f2))))))) + 0)) + (() 0))) + (with-test (:name :unconvert-tail-calls) (checked-compile-and-assert () `(lambda () @@ -836,6 +892,31 @@ ((t) :done) ((nil) :done))) +(with-test (:name :nested-catch-progv-compile) + (checked-compile + `(lambda (a b) + (catch 'ct + (flet ((f (x &key) x (throw 'ct b))) + (dotimes (i 1) + (if (< (progv '() (f a) 1) a) + a + (catch 'ct (f a))))))))) + +(with-test (:name (tagbody :tag-dynamic-extent)) + (checked-compile-and-assert + (:optimize '(:safety 3 :debug 2)) + `(lambda (b) + (declare (optimize (safety 3) (debug 2))) + (tagbody + (labels ((f (x &key) x (go tag6))) + (tagbody + (catch 'ct2 (f b)) + 2) + (dotimes (i 1) (f 1)) + -1) + tag6)) + ((1) nil))) + (with-test (:name :fewer-cast-conversions) (multiple-value-bind (fun failed) (checked-compile @@ -936,10 +1017,10 @@ (checked-compile-and-assert () `(lambda () - (sb-kernel:symeval nil)) + (symbol-value nil)) (() nil))) -(with-test (:name (:physenv-analyze :deleted-lambda)) +(with-test (:name (:environment-analyze :deleted-lambda)) (checked-compile-and-assert () `(lambda (log) @@ -989,6 +1070,39 @@ '(function ((complex rational)) (values null &optional)))) (assert (not (funcall fun2 #C(10 10)))))) +(with-test (:name (:numeric float rational :contagion)) + (flet ((check (operator type argument) + (let ((fun (checked-compile + `(lambda (x) + (declare (type ,type x)) + ,(ecase argument + (1 `(,operator x 1/2)) + (2 `(,operator 1/2 x))))))) + (assert (null (ctu:find-code-constants fun :type 'ratio)))))) + (dolist (operator '(+ * / - = < > <= >=)) + (dolist (type '(single-float double-float)) + (check operator type 1) + (check operator type 2) + (when (member operator '(+ * / - =)) + (check operator `(complex ,type) 1) + (check operator `(complex ,type) 2)))))) + +(with-test (:name (:numeric float float :contagion)) + (flet ((check (operator type argument) + (let ((fun (checked-compile + `(lambda (x) + (declare (type ,type x)) + ,(ecase argument + (1 `(,operator x 1.0f0)) + (2 `(,operator 1.0f0 x))))))) + (assert (null (ctu:find-code-constants fun :type 'single-float)))))) + (dolist (operator '(+ * / - = < > <= >=)) + (check operator 'double-float 1) + (check operator 'double-float 2) + (when (member operator '(+ * / - =)) + (check operator '(complex double-float) 1) + (check operator '(complex double-float) 2))))) + (with-test (:name :find-type-deriver) (checked-compile-and-assert () @@ -1564,7 +1678,7 @@ (values (funcall f x) (> x 1d0))))))) (ctu:assert-no-consing (funcall f #'identity 1d0)))) -(with-test (:name :infer-iteration-var-type) +(with-test (:name (:infer-iteration-var-type :step-is-range)) (let ((f (checked-compile '(lambda (s) (declare ((integer 1 2) s)) @@ -1575,6 +1689,41 @@ (assert (equal (sb-impl::%simple-fun-type f) '(function ((integer 1 2)) (values (integer 16 31) &optional)))))) +(with-test (:name (:infer-iteration-var-type :multiple-sets)) + (let ((f (checked-compile + '(lambda (x) + (declare (optimize speed) + (type (integer 3 10) x)) + (let ((y x)) + (tagbody + :start + (when (plusp y) + (decf y) + (when (plusp y) + (decf y) + (go :start)))) + y)) + :allow-notes nil))) + (assert (equal (sb-impl::%simple-fun-type f) + '(function ((integer 3 10)) (values (integer 0 0) &optional)))))) + +(with-test (:name (:infer-iteration-var-type :incompatible-sets)) + (checked-compile-and-assert () + '(lambda (input-total missing-amount) + (declare (fixnum input-total) (fixnum missing-amount)) + (loop with tot = 0 + repeat 1 + do (let ((difference input-total)) + (setq difference (max difference 0)) + (setq tot (+ tot difference))) + finally (when (plusp missing-amount) + (decf tot missing-amount)) + (return (if (plusp tot) :good :bad)))) + ((0 0) :bad) + ((1 0) :good) + ((0 1) :bad) + ((1 1) :bad))) + (with-test (:name :delay-transform-until-constraint-loop) (checked-compile-and-assert () @@ -1722,7 +1871,7 @@ (checked-compile-and-assert () `(lambda (type) - (make-array 4 :element-type type)) + (make-array 4 :element-type type :initial-element 0)) (('(or (cons (satisfies eval)) atom)) #(0 0 0 0) :test #'equalp))) (with-test (:name :substitute-single-use-lvar-exit-cleanups) @@ -2371,9 +2520,7 @@ (list a b))) ((1 3) '(1 3) :test #'equal))) -(with-test (:name (:mv-call :more-arg-unused) - ;; needs SB-VM::MORE-ARG-OR-NIL VOP - :broken-on (not (or :x86-64 :x86 :ppc :arm :arm64 :riscv))) +(with-test (:name (:mv-call :more-arg-unused)) (checked-compile-and-assert () '(lambda (&rest rest) @@ -2466,7 +2613,8 @@ (let ((c (sb-kernel:fun-code-header #'sb-debug::parse-trace-options))) (assert (>= (sb-kernel:code-jump-table-words c) 17)))) -(with-test (:name :modular-arith-type-derivers) +(with-test (:name :modular-arith-type-derivers + :fails-on :ppc64) (let ((f (checked-compile `(lambda (x) (declare ((and fixnum @@ -2487,13 +2635,10 @@ (push name names))))) (assert (not dup-fdefns))))) (dolist (c (sb-vm::list-allocated-objects :all :type sb-vm:code-header-widetag)) - (let* ((start (+ sb-vm:code-constants-offset - (* (sb-kernel:code-n-entries c) - sb-vm:code-slots-per-simple-fun))) - (end (+ start (sb-kernel:code-n-named-calls c)))) + (sb-int:binding* (((start count) (sb-vm::code-header-fdefn-range c)) + (end (+ start count))) ;; Within each subset of FDEFNs there should be no duplicates - ;; by name. But there could be an fdefn that is in the union of - ;; the ranges twice, if used for named call and a global ref. + ;; by name. But there could be an fdefn that is in the union of the two sets. (scan-range c start end) (scan-range c end (sb-kernel:code-header-words c)))))) @@ -2617,7 +2762,7 @@ (t :none)))))) ;; There should be no #<layout> referenced directly from the code header. ;; There is of course a vector of layouts in there to compare against. - (assert (not (ctu:find-code-constants f :type 'sb-kernel:layout))) + (assert (not (ctu:find-code-constants f :type 'sb-kernel:wrapper))) ;; The function had better work. (assert (eq (funcall f 'wat) :none)) (assert (equal (funcall f (make-broadcast-stream *error-output*)) @@ -2809,7 +2954,12 @@ (checked-compile `(lambda () (values-list (cons 1 nil))))) - '(function () (values (integer 1 1) &optional))))) + '(function () (values (integer 1 1) &optional)))) + (assert + (equal (sb-kernel:%simple-fun-type + (checked-compile + `(lambda (x) (values-list (list* x 1 x nil))))) + '(function (t) (values t (integer 1 1) t &optional))))) (with-test (:name :xeps-and-inlining) (checked-compile-and-assert @@ -2896,3 +3046,707 @@ (+ (restart-bind nil (go missing-tag)) (progv nil nil o))))))) :allow-failure t)))) + + +(with-test (:name :split-let-unused-vars) + (checked-compile-and-assert + () + `(lambda (x y) + (let ((a + (if x y)) + (b) + (c + (if y + x))) + (declare (ignore b)) + (if c (if a a c)))) + ((t t) t) + ((t nil) nil) + ((nil t) nil) + ((nil nil) nil))) + +(with-test (:name :sequence-lvar-dimensions-on-arrays) + (checked-compile-and-assert + () + `(lambda (x a) + (count a (make-string x :initial-element a))) + ((10 #\a) 10))) + +(with-test (:name :length-transform-on-arrays) + (checked-compile-and-assert + () + `(lambda () (length (make-sequence '(string *) 10 :initial-element #\a))) + (() 10))) + +(with-test (:name :constant-fold-unknown-types) + (checked-compile-and-assert + (:allow-style-warnings t) + `(lambda () + (oddp (the (or a b) -1))))) + +(with-test (:name :dead-code-no-constant-fold-errors) + (assert + (typep (nth-value 4 + (checked-compile + `(lambda (z) + (when (and (eq z 0) + (not (eq z 0))) + (/ 10 0))))) + '(cons sb-ext:code-deletion-note null)))) + +(with-test (:name :unused-assignment) + (flet ((try (expr &aux (warned 0)) + (handler-bind ((style-warning + (lambda (c) + (if (search "assigned but never read" (princ-to-string c)) + (incf warned) + (error "That's unexpected"))))) + (multiple-value-bind (fun warn error) + (let ((*error-output* (make-broadcast-stream))) (compile nil expr)) + (declare (ignore fun)) + (assert (and warn (not error) (eql warned 1))))))) + (try '(lambda (x) (let* ((a (+ x 5)) (b a)) (setq b 3) (eval ''z)))) + ;; Even if the initializer is necessary to call, it's still warning-worthy. + (try '(lambda (x) (let* ((a (+ x 5)) + (b (opaque-identity a))) + (setq b 3) + (eval ''z)))) + (try '(lambda (x) (let* ((a (+ x 5)) (b a)) + (setq b (opaque-identity 3)) + (eval ''z))))) + ;; This one uses the value of B + (checked-compile '(lambda (x) (let* ((a (+ x 5)) (b a)) + (setq b (opaque-identity 3)))))) + +(with-test (:name :unconvert-tail-calls-terminate-block) + (checked-compile-and-assert + () + `(lambda (x y) + (flet ((f () + (labels ((a () + (error "~a" x)) + (b () + (a))) + (if nil + (b) + (if y + (a) + (b)))))) + (block nil + (return (f))))) + ((t t) (condition 'error)))) + +(with-test (:name :unconvert-tail-calls-terminate-block.2) + (checked-compile-and-assert + () + `(lambda (x) + (flet ((f () + (labels ((a () + (error "foo ~a" x)) + (b () + (let (*) + (a)))) + (if nil + (b) + (if nil + (a) + (if x + (a) + (b))))))) + (f) + 10)) + ((t t) (condition 'error)))) + +(with-test (:name :fixnum-checking-boxing + :skipped-on (not :x86-64)) + (checked-compile + `(lambda (x y) + (declare (optimize speed) + (fixnum x y)) + (the fixnum (+ x y))) + :allow-notes nil)) + +(with-test (:name :ltn-analyze-mv-bind) + (checked-compile-and-assert + () + `(lambda () + (multiple-value-call #'list + 10 (apply #'values '(44 33d0)))) + (() '(10 44 33d0) :test #'equal))) + + +(with-test (:name :lp719585) + ;; Iteration variables are always "used" + (checked-compile '(lambda () (do (var) (t)))) + (checked-compile '(lambda () (do* (var) (t)))) + (checked-compile '(lambda () (do-all-symbols (var)))) + (checked-compile '(lambda () (do-external-symbols (var)))) + (checked-compile '(lambda () (do-symbols (var)))) + (checked-compile '(lambda () (dolist (var '(1 2 3)))))) + +(with-test (:name :key-default-type) + (let ((name (gensym))) + (proclaim `(ftype (function (double-float &key (:y double-float))) ,name)) + (checked-compile-and-assert + (:optimize :default) + `(sb-int:named-lambda ,name (x &key (y x)) + (values x y)) + ((1d0 :y nil) (condition 'error))))) + +(with-test (:name :deleting-unreachable-floats) + (let ((name (gensym))) + (proclaim `(inline ,name)) + (eval `(defun ,name (&key (k (eval 0f0))) + k)) + (checked-compile-and-assert + (:allow-notes nil) + `(lambda () + (,name :k 0f0)) + (() 0f0)))) + +(with-test (:name :no-*-as-type) + (multiple-value-bind (fun errorp warnings) + (checked-compile '(lambda (x) (the * x)) + :allow-failure t :allow-warnings t) + (declare (ignore fun)) + (assert errorp) + (assert (= (length warnings) 1))) + ;; (values t) parses into *wild-type* and has to be allowed + ;; even though * which parses into *wild-type* isn't. + (checked-compile '(lambda () (the (values t) t)))) + +(with-test (:name :hairy-data-vector-set-t-upgrade) + (checked-compile + '(lambda (x) (sb-kernel:hairy-data-vector-set + (the (simple-array symbol) x) 1 'hey)))) + +(with-test (:name :ir2-convert-reffer-no-lvar) + (checked-compile-and-assert + (:allow-style-warnings t) + `(lambda (a) + (/ (unwind-protect (if a + (values nil (cdr a)) + (values 1 0)) + a) + 1)) + ((nil) 1))) + +(with-test (:name :%eql-integer-fold) + (checked-compile-and-assert + () + `(lambda (d) + (declare (type fixnum d)) + (or (find d '(-98 27749116333474161060)) + t)) + ((-98) -98) + ((95) t))) + +(with-test (:name :svref-with-addend+if-eq-immediate) + (checked-compile-and-assert + () + `(lambda (a d) + (eql (svref a d) -276932090860495638)) + ((#(1 0) 0) nil) + ((#(-276932090860495638) 0) t)) + (checked-compile-and-assert + () + `(lambda (n) + (position #c(1.0 2.0) #(nil nil nil) :start n)) + ((0) nil))) + +(with-test (:name :zeroize-stack-tns) + (checked-compile-and-assert + () + `(lambda (a b d e) + (declare (type fixnum a)) + (dpb + (ash + (truncate 562949953421316 (max 97 d)) + (min 81 (expt (boole boole-and e b) 2))) + (byte 7 5) + (dotimes (i 2 a) + (count i #(61) :test '>=)))) + ((1 2 3 4) 1985))) + +(with-test (:name :logtest-derive-type-nil) + (checked-compile-and-assert + (:allow-warnings t) + `(lambda (c) + (block nil + (evenp (the integer (ignore-errors (return c)))))) + ((1) 1))) + +(with-test (:name :cast-filter-lvar) + (checked-compile-and-assert + (:allow-warnings t) + `(lambda () + (block nil + (equal + (the integer (tagbody + (let ((* (lambda () (go tag)))) + (return)) + tag)) + (the integer (block nil + (return)))))) + (() nil))) + +;;; EXPLICIT-CHECK + ETYPECASE should not produce a error message +;;; which reveals whether type-checking on entry to a standard function +;;; was performed this way or that way. +(with-test (:name :etypecase-error-simplify) + (let ((x (nth-value 1 (ignore-errors (logcount (opaque-identity #\a))))) + (y (nth-value 1 (ignore-errors (oddp (opaque-identity #\a)))))) + (assert (string= (princ-to-string x) (princ-to-string y))))) + +(with-test (:name :set-exclusive-or-inlined) + (checked-compile-and-assert + () + `(lambda (set1 set2) + (declare (inline set-exclusive-or)) + (set-exclusive-or set1 set2)))) + +(declaim (inline inline-deletion-note)) +(defun inline-deletion-note (x y) + (if y + 10 + x)) + +(with-test (:name :inline-deletion-note) + (checked-compile-and-assert + (:allow-notes nil) + `(lambda (x) + (inline-deletion-note x t)) + ((t) 10))) + +(with-test (:name :inline-type-mismatch) + (checked-compile-and-assert + (:allow-notes nil) + `(lambda (x y) + (car (inline-deletion-note x y))) + (('(a) nil) 'a)) + (checked-compile-and-assert + () + `(lambda (x y) + (1+ (position x (the list y)))) + ((1 '(1)) 1))) + +(with-test (:name :lvar-annotation-inline-type-mismatch) + (checked-compile-and-assert + () + `(lambda (x y) + (sb-kernel:the* (float :use-annotations t) (inline-deletion-note x y))) + ((1.0 nil) 1.0))) + +(with-test (:name :cast-type-preservation) + (assert + (equal (caddr + (sb-kernel:%simple-fun-type + (checked-compile + `(lambda (b) + (declare ((integer 1 1000) b)) + (declare (optimize (space 0))) + (gcd 2 b))))) + '(values (integer 1 2) &optional)))) + +(with-test (:name :lvar-substituting-non-deletable-casts) + (checked-compile-and-assert + () + `(lambda (b) + (the integer + (let (*) + (rem 2 + (let ((m + (flet ((f () + (truncate (the (integer -10 0) b) -4))) + (f)))) + (if (> m 1) + 1 + m))))) + 10) + ((-10) 10))) + +(with-test (:name :convert-mv-bind-to-let-no-casts) + (checked-compile-and-assert + () + `(lambda (a) + (declare (type (integer 7693489 168349189459797431) a)) + (max + (floor a + (min -14 + (loop for lv3 below 3 + sum (mod 77196223293181 + (max 75 (mod a (min -57 lv3))))))))) + ((8000000) -571429))) + +(with-test (:name :values-length-mismatch) + (checked-compile-and-assert + (:allow-style-warnings t :optimize :default) + `(lambda (a) + (declare (values t &optional)) + (when a + (values 1 2))) + ((nil) nil) + ((t) (condition 'type-error)))) + +(with-test (:name :substitute-single-use-lvar-type-cast-movement) + (checked-compile-and-assert + () + `(lambda (a) + (block nil + (let ((x (multiple-value-prog1 a))) + (when (< a 0) + (return :good)) + (if (minusp x) + 1 + (+ x 1))))) + ((-1) :good) + ((0) 1))) + +(with-test (:name :fold-ash-mod-0) + (checked-compile-and-assert + () + `(lambda () + (loop for i below 3 sum + (ldb (byte 6 6) + (ash i (mask-field (byte 5 8) i))))) + (() 0))) + +(with-test (:name :substitute-single-use-lvar-type-multiple-uses) + (checked-compile-and-assert + () + `(lambda (c) + (let ((z + (ceiling + (truncate 655 + (min -7 + (if c + -1000 + 3))) + 3))) + z)) + ((t) 0) + ((nil) -31))) + +(with-test (:name :division-by-multiplication-type-derivation) + (assert + (equal (caddr + (sb-kernel:%simple-fun-type + (checked-compile + `(lambda (c) + (declare (optimize speed)) + (ceiling + (truncate 65527 + (min -78 + (if c + -913097464 + 5))) + 39))))) + '(values (or (integer -21 -20) bit) (integer -38 0) &optional))) + (assert + (equal (caddr + (sb-kernel:%simple-fun-type + (checked-compile + `(lambda (c) + (declare (optimize speed)) + (ceiling + (truncate 65527 + (min 78 + (if c + 913097464 + 5))) + 39))))) + '(values (or (integer 21 22) (integer 336 337)) (integer -38 0) &optional)))) + +(with-test (:name :boundp-ir2-optimizer) + (checked-compile-and-assert + () + `(lambda (v) + (flet ((f (s) + (when (boundp s) + (symbol-value s)))) + (f v) + (f v) + v)) + ((t) t))) + +(with-test (:name :nfp-in-unwinding) + (catch 'z + (checked-compile-and-assert + () + `(lambda (x y f) + (declare (double-float x y)) + (block nil + (let ((z (+ x y))) + (unwind-protect (funcall f) + (return (+ z 1d0)))))) + ((4d0 1d0 (lambda () (throw 'z 1))) 6d0)))) + +(with-test (:name :ir1-optimize-if-same-target-type-derivation) + (checked-compile-and-assert + () + `(lambda (b c) + (declare (notinline equal)) + (multiple-value-bind (v7 v2) + (if (equal 0 0) + (values c 0) + (values b 0)) + (declare (ignore v2)) + (tagbody (progn v7)) + b)) + ((1 2) 1))) + +(with-test (:name :delete-let-source-paths) + (checked-compile-and-assert + () + `(lambda (a) + (declare (type (member -3 -54972 3) a)) + (values (floor -98740440 a))) + ((-3) 32913480) + ((3) -32913480) + ((-54972) 1796))) + +(with-test (:name :unused-debug-tns) + (checked-compile-and-assert + () + `(lambda (d) + (flet ((f (x) + (unwind-protect d + (eval x)))) + (dotimes (i 3) + (f (1+ most-positive-fixnum))))) + ((3) nil))) + +(with-test (:name :exit-becomes-single-value) + (checked-compile-and-assert + () + `(lambda (x z) + (max + (block nil + (flet ((x () (return (floor 1020 z)))) + (funcall x #'x)) + nil) + 10)) + (((lambda (x) (funcall x)) 4) 255))) + +(with-test (:name :principal-lvar-single-valuify-exit) + (checked-compile-and-assert + () + `(lambda () + ((lambda (a) + (flet ((a () + (let ((v3 a)) + (block nil (truncate (flet ((b () + (return (block b3 (values 1 v3))))) + (declare (inline b)) + (b))))))) + (declare (inline a)) + (values (a)))) + t)) + (() 1))) + +(with-test (:name :%coerce-callable-for-call-with-casts + :skipped-on (not :call-symbol)) + (let ((f (checked-compile + `(lambda (x y) + (apply x 1 2 y))))) + (assert (equal (funcall f #'list '(3)) '(1 2 3))) + (assert (not (ctu:find-named-callees f))))) + +(with-test (:name :local-fun-type-check-eliminatetion) + (let ((fun (checked-compile '(lambda () + (flet ((f (x) + (declare (fixnum x)) + (1+ x))) + (declare (inline f)) + (funcall + (the (function (&optional fixnum)) #'f) + 10)))))) + (assert (= (sb-kernel:code-n-entries (sb-kernel:fun-code-header fun)) + 1)))) + +(with-test (:name :%cleanup-point-transform) + (checked-compile-and-assert + () + `(lambda (a b c) + (declare ((integer -14 49702337) a) + ((integer -5376440588342 5921272101558) b) + ((integer 3395101368955 8345185767296289) c)) + (if (and (< c b) (> a b)) + (progv nil + (list 288230376151711735 c) + (restart-bind nil a)) + c)) + ((49702337 5921272101558 8345185767296289) 8345185767296289))) + +;;; Test from git rev e47ffa8855d4139f88f5982fe4b82a05c3498ed3. +;;; I have absolutely zero understanding of what this was doing, +;;; but the are bunch of "undefined variable" warnings, so it can't +;;; go at toplevel in a .cload test. +(with-test (:name :bug-226) + (with-scratch-file (lisp "lisp") + (with-open-file (f lisp :direction :output) + (write '(defun bug226 () + (declare (optimize (speed 0) (safety 3) (debug 3))) + (flet ((safe-format (stream string &rest r) + (unless (ignore-errors (progn + (apply #'format stream string r) + t)) + (format stream "~&foo ~S" string)))) + (cond + ((eq my-result :ERROR) + (cond + ((ignore-errors (typep condition result)) + (safe-format t "~&bar ~S" result)) + (t + (safe-format t "~&baz ~S (~A) ~S" condition condition result))))))) + :stream f :readably t)) + (with-scratch-file (fasl "fasl") + (compile-file lisp :output-file fasl)))) + +;;; I think these tests had to be present in a COMPILE-FILE (as opposed to COMPILE) +;;; to prove that the bug was fixed. +;;; Anway it's no longer going to be allowed to have deliberately bad code in '.cload' +;;; files, because any condition of type warnings or error is considered failure +;;; of the compile step. +(with-test (:name :lp-1276282) + (with-scratch-file (lisp "lisp") + (with-open-file (f lisp :direction :output) + ;; from git rev feb31fb6cfc8f89e2d75b5f2cc2ee569ac975033 + (format f "(lambda () (the string (+ 1 x)))~%") + ;; from git rev fbea35e879891723259dfa55589b498228390bb9 + (format f +"(lambda () + (macrolet ((x (&rest args) + (declare (ignore args)) + 'a)) + (let (a) + (declare (type vector a)) + (x #.#'list))))~%")) + (with-scratch-file (fasl "fasl") + (compile-file lisp :output-file fasl)))) + +(with-test (:name :substitute-single-use-lvar-mv-cast) + (checked-compile-and-assert + () + `(lambda () + (let ((r (random 10)) + (x (list 1))) + (declare (special x) + (dynamic-extent x)) + (throw 'c (the (integer 0 10) r)))))) + +(with-test (:name :list-ir2-convert) + (checked-compile '(lambda () + (declare (notinline list +)) + (list (loop for i below 2 count t))))) + +(with-test (:name :ir2-optimize-jumps-multiway-branch-if-eq-delete-branch) + (checked-compile-and-assert + () + `(lambda (a) + (declare (type (integer -345 1) a)) + (case (ldb (byte 24 5) a) + ((4 47 61 17 10 39) 1) + ((2 7 55) A) + ((42 48 16 33 40 20) A) + ((60 54 28) 3) + ((15 1 44 29 57 41 52) 32771) + ((46 64 3 18 36 49 37) 1) + (t A))) + ((-5) -5))) + +(with-test (:name :bignump-integer-<) + (checked-compile-and-assert + () + `(lambda (a) + (declare (type integer a)) + (if (and (typep a 'bignum) (< a 0)) + t + nil)) + ((-1) nil) + (((- (expt 2 300))) t))) + +(with-test (:name :cmov-branch) + (checked-compile-and-assert + () + `(lambda (x y) + (assert + (let ((res nil)) + (when x (setf res (not res))) + (when y (setf res (not res))) + (not res)))) + ((1 2) nil) + ((nil nil) nil))) + +(with-test (:name :constant-type-proclamation) + (ctu:file-compile + `((defconstant +foo+ 4) + + (defun bar () +foo+) + + (declaim (type integer +foo+))) + :load t) + (assert (eq (funcall 'bar) 4))) + +(with-test (:name :if-split-let-blocks) + (checked-compile-and-assert + () + `(lambda (a e) + (labels ((f1 (b) + (map nil + (lambda (n) + (return-from f1 n)) + b) + nil) + (f (n) + (let ((x (eval e)) + (y (f1 n))) + (if y + y + x)))) + (f a))) + ((() 1) 1) + (('(2) 1) 2))) + +(with-test (:name :duplicate-more-local-tn-overflow) + (let ((vars (loop repeat 200 collect (gensym))) + (args (loop repeat 201 for i from (random 30000) + collect i))) + (assert + (equal + (apply + (compile + () + `(lambda (a ,@vars) + (list a a ,@vars))) + args) + (cons (car args) args))))) + +(with-test (:name :aref-single-value-type) + (checked-compile-and-assert + () + `(lambda (x) + (aref (the (values (and (not simple-array) vector)) x) 0)) + (((make-array 10 :adjustable t :initial-element 3)) 3))) + +(with-test (:name :restoring-tns-after-cleanups) + (checked-compile-and-assert + () + `(lambda () + (declare (notinline values)) + (unwind-protect 1 + (let ((a (list 'list))) + (declare (dynamic-extent a)) + (unwind-protect 1 (eval a))) + (eval 1) + (eval 2))) + (() 1))) + +(defun noflush-symbol-function () + (declare (optimize safety)) + (if (functionp (symbol-function '#:notathing)) 1)) +(defun flush-symbol-function () + (if (functionp (symbol-function '#:notathing)) 1)) +(with-test (:name :flush-symbol-function :skipped-on :interpreter) + (assert (ctu:find-code-constants #'noflush-symbol-function)) + (assert (not (ctu:find-code-constants #'flush-symbol-function)))) diff --git a/tests/compiler-ir.pure.lisp b/tests/compiler-ir.pure.lisp index 9446b4ce33..ccfdad9c05 100644 --- a/tests/compiler-ir.pure.lisp +++ b/tests/compiler-ir.pure.lisp @@ -15,6 +15,7 @@ sb-c::combination-fun-source-name sb-c::*compile-component-hook* sb-c::basic-combination-p + sb-c::combination-p sb-c::basic-combination-info sb-c::node-tail-p sb-c::do-blocks @@ -24,7 +25,7 @@ (defun inspect-ir (form fun &rest checked-compile-args) (let ((*compile-component-hook* fun)) - (apply #'test-util:checked-compile form checked-compile-args))) + (apply #'checked-compile form checked-compile-args))) (defun ir-full-calls (form) (let (calls) @@ -49,7 +50,19 @@ (push node calls)))))) calls)) -(test-util:with-test (:name :%bit-pos-fwd/1-tail-called) +(defun ir2-vops (form) + (let (vops) + (inspect-ir + form + (lambda (component) + (sb-c:do-ir2-blocks (block component) + (do ((vop (sb-c::ir2-block-start-vop block) + (sb-c:vop-next vop))) + ((null vop)) + (push (sb-c:vop-name vop) vops))))) + vops)) + +(with-test (:name :%bit-pos-fwd/1-tail-called) (destructuring-bind (combination) (ir-full-calls `(lambda (x) (declare (optimize (debug 2))) @@ -57,7 +70,7 @@ (assert (eql (combination-fun-debug-name combination) '%bit-pos-fwd/1)) (assert (node-tail-p combination)))) -(test-util:with-test (:name :bounds-check-constants) +(with-test (:name :bounds-check-constants) (assert (= (count '%check-bound (ir-calls `(lambda (v) @@ -66,7 +79,16 @@ :key (lambda (x) (combination-fun-source-name x nil))) 1))) -(test-util:with-test (:name :local-call-tail-call) +(with-test (:name :bounds-check-length) + (assert (= (count '%check-bound + (ir-calls + `(lambda (x y) + (when (< x (length y)) + (svref y x)))) + :key (lambda (x) (combination-fun-source-name x nil))) + 0))) + +(with-test (:name :local-call-tail-call) (destructuring-bind (combination) (ir-full-calls `(lambda () (flet ((x () @@ -76,3 +98,265 @@ 10))) (assert (eql (combination-fun-debug-name combination) 'terpri)) (assert (node-tail-p combination)))) + +(with-test (:name :fold-derived-logand) + (assert (not (find 'logand + (ir-calls `(lambda (x) + (declare ((integer 1 4) x)) + (logand #xF00 x))) + :key #'combination-fun-debug-name))) + (assert (not (find 'logand + (ir-calls `(lambda (x) + (declare ((integer 1 4) x)) + (logand #xFF (1+ x)))) + :key #'combination-fun-debug-name))) + (assert (not (find 'logand + (ir-calls `(lambda (x) + (declare ((integer 1 4) x)) + (logand #xFF (ash 1 x)))) + :key #'combination-fun-debug-name)))) + +(with-test (:name :mod-ash + :skipped-on (not (or :arm64 :x86-64))) + (assert (not (ir-full-calls `(lambda (x y) + (declare (fixnum x y)) + (logand #xFF (ash x y))))))) + +(with-test (:name :exit-reoptimize-uses) + (assert (not (find 'cdr + (ir-calls `(lambda (a b) + (/ (unwind-protect (if a + (values b (cdr a)) + (values 1 0)) + a) + 1))) + :key (lambda (x) + (and (combination-p x) + (combination-fun-debug-name x))))))) + +(with-test (:name :no-arg-count-checking) + (assert (not (find 'sb-c:verify-arg-count + (ir2-vops '(lambda (&rest args) + (block nil + (handler-bind ((error (lambda (c) (return c)))) + (funcall (car args))))))))) + (assert (not (find 'sb-c:verify-arg-count + (ir2-vops '(lambda (&rest args) + (reduce #'+ + (car args) + :key (lambda (x) (sqrt x)))))))) + (assert (not (find 'sb-c:verify-arg-count + (ir2-vops '(lambda (&rest args) + (map 'list (lambda (x &optional z) + (declare (ignore z)) + x) + (car args))))))) + (assert (not (find 'sb-c:verify-arg-count + (ir2-vops '(lambda (&rest args) + (find 0 (car args) + :key + (lambda (x &rest z) + (declare (ignore z)) + x))))))) + (assert (not (find 'sb-c:verify-arg-count + (ir2-vops '(lambda (&rest args) + (remove 0 (car args) + :key + (lambda (&optional z) + z)))))))) + +(with-test (:name (:assignment-convert :iterative-tail)) + (let ((converted nil)) + (let ((fun (inspect-ir + '(lambda (n) + (labels ((fact (n acc) + (if (zerop n) + acc + (fact (1- n) (* acc n))))) + (fact n 1))) + (lambda (component) + (dolist (lambda (sb-c::component-lambdas component)) + (dolist (lambda-let (sb-c::lambda-lets lambda)) + (when (eq (sb-c::lambda-kind lambda-let) :assignment) + (setq converted t)))))))) + (assert (= (funcall fun 9) 362880)) + (assert converted)))) + +(with-test (:name (:assignment-convert :iterative-non-tail)) + (let ((converted nil)) + (let ((fun (inspect-ir + '(lambda (n) + (labels ((fact (n acc) + (if (zerop n) + acc + (fact (1- n) (* acc n))))) + (1+ (fact n 1)))) + (lambda (component) + (dolist (lambda (sb-c::component-lambdas component)) + (dolist (lambda-let (sb-c::lambda-lets lambda)) + (when (eq (sb-c::lambda-kind lambda-let) :assignment) + (setq converted t)))))))) + (assert (= (funcall fun 9) 362881)) + (assert converted)))) + +(with-test (:name (:assignment-convert :multiple-use)) + (let ((converted nil)) + (let ((fun (inspect-ir + '(lambda (b x y) + (labels ((f (n x) + (if (zerop n) + x + (f (1- n) (1+ x))))) + (+ 2 (if (= b 5) + (f x x) + (f b y))))) + (lambda (component) + (dolist (lambda (sb-c::component-lambdas component)) + (dolist (lambda-let (sb-c::lambda-lets lambda)) + (when (eq (sb-c::lambda-kind lambda-let) :assignment) + (setq converted t)))))))) + (assert (= (funcall fun 5 3 4) 8)) + (assert (= (funcall fun 6 3 4) 12)) + (assert converted)))) + +(with-test (:name (:assignment-convert :optional-dispatch)) + (let ((converted 0)) + (let ((fun (inspect-ir + '(lambda (mod r/m) + (flet ((make-machine-ea (base &optional disp index scale) + (list base + disp + index + scale))) + (cond ((= r/m #b100) + (make-machine-ea :so :here :we :are)) + ((/= mod #b00) (make-machine-ea :full-reg :tbf)) + ((= r/m #b101) (make-machine-ea :rip :another)) + (t (make-machine-ea :full-reg))))) + (lambda (component) + (dolist (lambda (sb-c::component-lambdas component)) + (dolist (lambda-let (sb-c::lambda-lets lambda)) + (when (eq (sb-c::lambda-kind lambda-let) :assignment) + (incf converted)))))))) + (assert (equal (funcall fun 0 5) '(:rip :another nil nil))) + ;; There should be two converted :ASSIGNMENT lambdas: one for + ;; (BASE DISP), and one for (BASE DISP INDEX SCALE). The latter + ;; gets assignment converted because it is also tail called by + ;; the entry point for (BASE DISP INDEX), which in turn was let + ;; converted into the entry point for (BASE DISP). + (assert (= converted 2))))) + +(with-test (:name (:assignment-convert :no-self-tr)) + (let ((converted nil)) + (let ((fun (inspect-ir + '(lambda (n) + (labels ((id (n) + n)) + (case n + ((a b c d e f g) + (id 1)) + ((h i j k l m n) + (id 2)) + ((o p q r s t u) + (id 3)) + ((v w x y z) + (id 4))))) + (lambda (component) + (dolist (lambda (sb-c::component-lambdas component)) + (dolist (lambda-let (sb-c::lambda-lets lambda)) + (when (eq (sb-c::lambda-kind lambda-let) :assignment) + (setf converted t)))))))) + (assert (= (funcall fun 'a) 1)) + (assert (= (funcall fun 'l) 2)) + (assert (= (funcall fun 's) 3)) + (assert (= (funcall fun 'w) 4)) + (assert converted)))) + +;;; Check that we are able to promote assignment lambdas into LETs. +(with-test (:name (:assignment-convert :can-become-let)) + (let ((assignment nil) + (let nil)) + (inspect-ir + '(lambda (x) + (labels ((id (n) + (+ n n))) + (1+ (if t + (id (read)) + (id (+ x x)))))) + (lambda (component) + (dolist (lambda (sb-c::component-lambdas component)) + (dolist (lambda-let (sb-c::lambda-lets lambda)) + (when (eq (sb-c::lambda-kind lambda-let) :assignment) + (setf assignment t)) + (when (eq (sb-c::lambda-kind lambda-let) :let) + (setf let t)))))) + (assert (not assignment)) + (assert let))) + +;;; Check assignment conversion of functions which don't return. +(with-test (:name (:assignment-convert :non-local-exit)) + (let ((assignment nil)) + (let* ((*standard-output* (make-broadcast-stream)) + (fun (inspect-ir + '(lambda (z) + (block hey + (flet ((f (x) + (print x) + (return-from hey (values 'GOOD (+ x x))))) + (values + 'BAD + (if (plusp z) + (f z) + (+ 1 (f (+ z z)))))))) + (lambda (component) + (dolist (lambda (sb-c::component-lambdas component)) + (dolist (lambda-let (sb-c::lambda-lets lambda)) + (when (eq (sb-c::lambda-kind lambda-let) :assignment) + (setf assignment t)))))))) + (assert (eq (funcall fun 3) 'GOOD)) + (assert (eq (funcall fun -3) 'GOOD)) + (assert assignment)))) + +(with-test (:name :empty-special-bindings) + (assert (not (find 'sb-c::%special-unbind + (ir-calls + `(lambda () + (let (*)) + 10)) + :key (lambda (x) (combination-fun-source-name x nil)))))) + +(with-test (:name :flushable-alien-fp-math) + (assert (not (find 'sb-c:%alien-funcall + (ir-calls + `(lambda (x) + (declare (double-float x)) + (exp x) + 10)) + :key (lambda (x) (combination-fun-source-name x nil)))))) + +(with-test (:name :values-let-conversion-reoptimization) + (assert (not (find 'list + (ir-calls + `(lambda (a) + (values + (flet ((f () + (values a (catch 'c) + (list 1)))) + (f))))) + :key (lambda (x) (combination-fun-source-name x nil)))))) + +(with-test (:name :instance-constraint-intersection) + (assert (not (find 'sb-c::%type-check-error/c + (ir-calls + `(lambda (x) + (typecase x + (stream 2) + (hash-table 1)))) + :key (lambda (x) (combination-fun-source-name x nil)))))) + +(with-test (:name :aref-full-call-no-type-check) + (assert (not (find 'sb-c::%type-check-error/c + (ir-calls + `(lambda (x) + (aref x 0))) + :key (lambda (x) (combination-fun-source-name x nil)))))) diff --git a/tests/compiler-slow.pure.lisp b/tests/compiler-slow.pure.lisp new file mode 100644 index 0000000000..3a122bc452 --- /dev/null +++ b/tests/compiler-slow.pure.lisp @@ -0,0 +1,173 @@ +(with-test (:name (compile eval the type-error)) + (checked-compile-and-assert (:optimize :safe) + '(lambda (v) + (list (the fixnum (the (real 0) (eval v))))) + ((0.1) (condition 'type-error)) + ((-1) (condition 'type-error)))) + +(defun pick-acceptable-default (specifier) + (let ((parse (sb-kernel:specifier-type specifier))) + ; (format t "~&testcase: ~s~%" specifier) + (typecase parse + (sb-kernel:character-set-type #\a) + (sb-kernel:numeric-type + (cond ((eq (sb-kernel:numeric-type-class parse) 'float) + (ecase (sb-kernel:numeric-type-complexp parse) + (:real + (ecase (sb-kernel:numeric-type-format parse) + (single-float 1009f0) + (double-float pi))) + (:complex + (ecase (sb-kernel:numeric-type-format parse) + (single-float #c(101f0 -1f0)) + (double-float #c(2d0 3.5d0)))))) + (t + 1))) + (t + (cond ((equal specifier '(or (eql 1.0d0) (eql 10.0d0))) ; KLUDGE + 1.0d0) + ((equal specifier '(member 1 2 10)) + 2) + ((equal specifier '(complex (member 10.0 20.0))) + (complex 10.0 10.0)) + (t + 'whatever)))))) + +(with-test (:name :array-type-predicates) + (dolist (et (list* '(integer -1 200) '(integer -256 1) + '(integer 0 128) + '(integer 0 (128)) + '(double-float 0d0 (1d0)) + '(single-float (0s0) (1s0)) + '(or (eql 1d0) (eql 10d0)) + '(member 1 2 10) + '(complex (member 10 20)) + '(complex (member 10d0 20d0)) + '(complex (member 10s0 20s0)) + '(or integer double-float) + '(mod 1) + '(member #\a #\b) + '(eql #\a) + #+sb-unicode 'extended-char + #+sb-unicode '(eql #\cyrillic_small_letter_yu) + (map 'list 'sb-vm:saetp-specifier + sb-vm:*specialized-array-element-type-properties*))) + (when et + (let* ((v (make-array 3 :element-type et + ;; Pick an initial element because of the (ELT ,v 0) + :initial-element (pick-acceptable-default et)))) + (checked-compile-and-assert () + `(lambda () + (list (if (typep ,v '(simple-array ,et (*))) + :good + ',et) + (if (typep (elt ,v 0) '(simple-array ,et (*))) + ',et + :good))) + (() '(:good :good))))))) + +(with-test (:name (compile equal equalp :transforms)) + (let* ((s "foo") + (bit-vector #*11001100) + (values `(nil 1 2 "test" + ;; Floats duplicated here to ensure we get newly created instances + (read-from-string "1.1") (read-from-string "1.2d0") + (read-from-string "1.1") (read-from-string "1.2d0") + 1.1 1.2d0 '("foo" "bar" "test") + #(1 2 3 4) #*101010 (make-broadcast-stream) #p"/tmp/file" + ,s (copy-seq ,s) ,bit-vector (copy-seq ,bit-vector) + ,(make-hash-table) #\a #\b #\A #\C + ,(make-random-state) 1/2 2/3))) + + (dolist (predicate '(equal equalp)) + ;; Test all permutations of different types + (loop for x in values + do (loop for y in values + do (checked-compile-and-assert (:optimize nil) + `(lambda (x y) + (,predicate (the ,(type-of x) x) + (the ,(type-of y) y))) + ((x y) (funcall predicate x y))))) + (checked-compile-and-assert () + `(lambda (x y) + (,predicate (the (cons (or simple-bit-vector simple-base-string)) + x) + (the (cons (or (and bit-vector (not simple-array)) + (simple-array character (*)))) + y))) + (((list (string 'list)) (list "LIST")) t))))) + +(with-test (:name (sb-c::mask-signed-field :randomized)) + (let (result) + (dotimes (i 1000) + (let* ((ool (checked-compile '(lambda (s i) + (sb-c::mask-signed-field s i)))) + (size (random (* sb-vm:n-word-bits 2))) + (constant (checked-compile `(lambda (i) + (sb-c::mask-signed-field ,size i)))) + (arg (- (random (* most-positive-fixnum 8)) (* most-positive-fixnum 4))) + (declared (checked-compile `(lambda (i) + (declare (type (integer ,(- (abs arg)) ,(abs arg)) i)) + (sb-c::mask-signed-field ,size i)))) + (ool-answer (funcall ool size arg)) + (constant-answer (funcall constant arg)) + (declared-answer (funcall declared arg))) + (unless (= ool-answer constant-answer declared-answer) + (push (list size arg ool-answer constant-answer declared-answer) result)))) + (assert (null result)))) + +(with-test (:name (multiple-value-call :type-checking-rest)) + (checked-compile-and-assert (:allow-warnings t + :optimize :safe) + `(lambda (list) + (multiple-value-call + (lambda (&optional a &rest r) + (declare ((satisfies eval) r) + (ignore r)) + (list a)) + (values-list list))) + (('(1 list 2)) '(1)) + (('(1)) (condition 'type-error)))) + +(with-test (:name (multiple-value-call :type-checking-rest.2)) + (checked-compile-and-assert (:allow-warnings t + :optimize :safe) + `(lambda (list) + (multiple-value-call + (lambda (&optional a &rest r) + (declare (null r) + (ignore r)) + (list a)) + (values-list list))) + (('(1 list 2)) (condition 'type-error)) + (('(1)) '(1)))) + +(with-test (:name (multiple-value-call :type-checking-rest :type-derivation)) + (checked-compile-and-assert (:allow-warnings t + :optimize :safe) + `(lambda (list) + (multiple-value-call + (lambda (&optional a &rest r) + (declare (cons r) + (ignore r)) + (list a)) + (values-list list))) + (('(1 2)) '(1)) + (('(1)) (condition 'type-error)))) + +(declaim (maybe-inline inline-recursive)) +(defun inline-recursive (x) + (declare (muffle-conditions compiler-note + style-warning)) + (if (zerop x) + x + (inline-recursive (1- x)))) +(declaim (inline inline-recursive)) + +(with-test (:name :reanalyze-functionals-when-inlining) + (checked-compile-and-assert + () + `(lambda (x) + (inline-recursive x) + (inline-recursive x)) + ((5) 0))) diff --git a/tests/compiler-test-util.lisp b/tests/compiler-test-util.lisp index 7f576ee611..a9afa07645 100644 --- a/tests/compiler-test-util.lisp +++ b/tests/compiler-test-util.lisp @@ -70,8 +70,7 @@ (defun collect-consing-stats (thunk times) (declare (type function thunk)) (declare (type fixnum times)) - #+(and sb-thread gencgc) - (sb-vm::close-current-gc-region) + #+(and sb-thread gencgc) (sb-vm::close-thread-alloc-region) (setf sb-int:*n-bytes-freed-or-purified* 0) (let ((before (sb-ext:get-bytes-consed))) (dotimes (i times) @@ -81,13 +80,14 @@ (defun check-consing (yes/no form thunk times) (multiple-value-bind (before after) (collect-consing-stats thunk times) - (let ((consed-bytes (- after before))) + (let* ((consed-bytes (- after before)) + (bytes-per-iteration (float (/ consed-bytes times)))) (assert (funcall (if yes/no #'not #'identity) - ;; I do not know why we do this comparasion, - ;; the original code did, so I let it - ;; in. Perhaps to prevent losage on GC - ;; fluctuations, or something. --TCR. - (< consed-bytes times)) + ;; If allocation really happened, it can't have been less than one cons cell + ;; per iteration (unless the test is nondeterministic - but in that case + ;; we can't really use this strategy anyway). So consider it to have consed + ;; nothing if the fraction is too small. + (< bytes-per-iteration (* 2 sb-vm:n-word-bytes))) () "~@<Expected the form ~ ~4I~@:_~A ~0I~@:_~ @@ -95,7 +95,7 @@ ~D times resulted in the allocation of ~ ~D bytes~:[ (~,3F per run)~;~].~@:>" form yes/no times consed-bytes - (zerop consed-bytes) (float (/ consed-bytes times)))) + (zerop consed-bytes) bytes-per-iteration)) (values before after))) (defparameter +times+ 10000) @@ -136,7 +136,7 @@ (defun count-full-calls (name function) (let ((code (with-output-to-string (s) (let ((*print-right-margin* 120)) - (disassemble function :stream s)))) + (sb-disassem:disassemble-code-component function :stream s)))) (n 0)) (flet ((asm-line-calls-name-p (line name) (dolist (herald '("#<FDEFN" "#<SB-KERNEL:FDEFN" "#<FUNCTION")) diff --git a/tests/compiler.impure-cload.lisp b/tests/compiler.impure-cload.lisp index 0d44c3ff80..c1f31ec227 100644 --- a/tests/compiler.impure-cload.lisp +++ b/tests/compiler.impure-cload.lisp @@ -5,6 +5,16 @@ (defpackage :bug254 (:use :cl)) (in-package :bug254) (declaim (optimize (safety 3) (debug 2) (speed 2) (space 1))) +;;; Kill all stupid useless notes, which is to say that IMHO 99.999999% of all notes +;;; are useless and stupid unless expressly requested. If a test wants notes, +;;; then it needs to do something to request them. +;;; Of course I don't know which tests wanted them, so ... maybe this causes +;;; some test to stop testing a thing. That's its fault for being badly written. +(declaim (sb-ext:muffle-conditions sb-ext:compiler-note)) +;;; Oh for f***'s sake why is INHIBIT-WARNINGS *STRONGER* *THAN* MUFFLE-CONDITIONS? +;;; (which is to say, more effective than, i.e. effective at all) +;;; Maybe one of these days we should fix MUFFLE-CONDITIONS to actually do its job ????? +(declaim (optimize (sb-ext:inhibit-warnings 3))) (defstruct foo (uhw2 nil :type (or package null))) (macrolet ((defprojection (variant &key lexpr eexpr) @@ -31,33 +41,6 @@ (in-package :cl-user) (delete-package :bug254) -;;; bug 255 -(defpackage :bug255 (:use :cl)) -(in-package :bug255) -(declaim (optimize (safety 3) (debug 2) (speed 2) (space 1))) -(defvar *1*) -(defvar *2*) -(defstruct v a b) -(defstruct w) -(defstruct yam (v nil :type (or v null))) -(defstruct un u) -(defstruct (bod (:include un)) bo) -(defstruct (bad (:include bod)) ba) -(declaim (ftype (function ((or w bad) (or w bad)) (values)) %ufm)) -(defun %ufm (base bound) (froj base bound *1*) (values)) -(declaim (ftype (function ((vector t)) (or w bad)) %pu)) -(defun %pu (pds) (declare (ignore pds)) *2*) -(defun uu (yam) - (declare (ignore yam)) - (let ((v (yam-v az))) - (%ufm v - (flet ((project (x) (frob x 0))) - (let ((avecname *1*)) - (multiple-value-prog1 - (progn (%pu avecname)) - (frob))))))) -(in-package :cl-user) -(delete-package :bug255) ;;; bug 148 (defpackage :bug148 (:use :cl)) @@ -209,7 +192,7 @@ ;;; bug 291 reported by Nikodemus Siivola (modified version) (defstruct line (%chars "")) -(defun update-window-imag (line) +(defun update-window-imag (line &aux string) (tagbody TOP (if (null line) @@ -220,7 +203,7 @@ (let* ((cc (car current)) (old-line (dis-line-line cc))) (if (eq old-line line) - (do ((chars (line-%chars line) nil)) + (do ((chars (and line (line-%chars line)) nil)) (()) (let* () (multiple-value-call @@ -587,18 +570,37 @@ (with-test (:name :optional-default-hairy-defconstant) (assert (eq (first (f)) foo-vector))) -(defun non-top-level-type-clobbering () +(eval-when (:compile-toplevel) + (setq sb-ext:*derive-function-types* nil)) + +(defun type-clobbering () 99) (when nil - (defun non-top-level-type-clobbering () + (defun type-clobbering () + 93)) + +(defun uses-type-clobbering () + (eq (type-clobbering) 99)) + +(with-test (:name :type-clobbering) + (assert (uses-type-clobbering))) + +(defun type-clobbering.2 () + 99) + +(when t + (defun type-clobbering.2 () 93)) -(defun non-top-level-type-clobbering2 () - (eq (non-top-level-type-clobbering) 99)) +(defun uses-type-clobbering.2 () + (eq (type-clobbering.2) 93)) + +(with-test (:name :type-clobbering.2) + (assert (uses-type-clobbering.2))) -(with-test (:name :non-top-level-type-clobbering) - (assert (non-top-level-type-clobbering2))) +(eval-when (:compile-toplevel) + (setq sb-ext:*derive-function-types* :same-file)) (macrolet ((x () '#(a b c d))) (defun constant-test-1 () diff --git a/tests/compiler.impure.lisp b/tests/compiler.impure.lisp index f4ef232fe0..5b0c15a5b4 100644 --- a/tests/compiler.impure.lisp +++ b/tests/compiler.impure.lisp @@ -20,7 +20,7 @@ ;; or actually reasonable things to test. (when (and (eq sb-ext:*evaluator-mode* :interpret) (not (member :sb-fasteval *features*))) - (sb-ext:exit :code 104)) + (invoke-restart 'run-tests::skip-file)) (load "compiler-test-util.lisp") @@ -72,7 +72,7 @@ ;;; As reported by Alexey Dejneka (sbcl-devel 2002-01-30), in ;;; sbcl-0.7.1 plus his patch (i.e. essentially sbcl-0.7.1.2), the -;;; compiler barfed on this, blowing up in FIND-IN-PHYSENV looking for +;;; compiler barfed on this, blowing up in FIND-IN-ENVIRONMENT looking for ;;; the LAMBDA-VAR named NUM. That was fixed in sbcl-0.7.1.3. (defun parse-num (index) (let (num x) @@ -955,7 +955,7 @@ ;;;; MUFFLE-CONDITIONS test (corresponds to the test in the manual) ; FIXME: make a better test! -(with-test (:name muffle-conditions :skipped-on (or :alpha :ppc64 :x86-64)) +(with-test (:name muffle-conditions :skipped-on (or :ppc64 :x86-64)) (multiple-value-bind (fun failure-p warnings style-warnings notes) (checked-compile '(lambda (x) @@ -1045,7 +1045,7 @@ (with-test (:name :bug-405) ;; These used to break with a TYPE-ERROR - ;; The value NIL is not of type SB-C::PHYSENV. + ;; The value NIL is not of type SB-C::ENVIRONMENT. ;; in MERGE-LETS. (ctu:file-compile '((LET (outer-let-var) @@ -1082,7 +1082,16 @@ (assert (eq 'number (type-error-expected-type e))) :error)))))) -(with-test (:name :compiled-debug-funs-leak) +;;; This tested something which is no longer a thing. There was a hash-table +;;; named *COMPILED-DEBUG-FUNS* which held on to an arbitrary number of code blobs, +;;; and it was made weak in git rev 9abfd1a2b2 and then removed in rev a2aa5eceb5 +;;; (except for cheneygc - and I'm not entirely sure that there isn't a way to +;;; remove it from cheneygc as well, but it wasn't interesting). +;;; So really it's testing nothing, except that maybe it is. +;;; But the test doesn't pass with parallel-exec because profiling the code causes +;;; potentially any and every lambda to be retained when a stack sample is taken. +;;; So I'm not sure whether to delete or disable this. I guess disable. +(with-test (:name :compiled-debug-funs-leak :fails-on :parallel-test-runner) (sb-ext:gc :full t) (let ((usage-before (sb-kernel::dynamic-usage))) (dotimes (x 10000) @@ -1166,7 +1175,8 @@ (assert (every #'= '(-1.0 0.0 0.0 0.0 0.0 -1.0 0.0 0.0 0.0 0.0 -1.0 0.0 0.0 0.0 0.0 1.0) (rotate-around - (make-array 3 :element-type 'single-float) (coerce pi 'single-float)))) + (make-array 3 :element-type 'single-float :initial-element 0f0) + (coerce pi 'single-float)))) ;; Same bug manifests in COMPLEX-ATANH as well. (assert (= (atanh #C(-0.7d0 1.1d0)) #C(-0.28715567731069275d0 0.9394245539093365d0)))) @@ -1311,12 +1321,15 @@ (with-test (:name (load-time-value :errors)) (multiple-value-bind (warn fail) - (ctu:file-compile - `((defvar *load-time-value-error-value* 10) - (declaim (fixnum *load-time-value-error-value*)) - (defun load-time-value-error-test-1 () - (the list (load-time-value *load-time-value-error-value*)))) - :load t) + (progn + (ctu:file-compile + `((defvar *load-time-value-error-value* 10) + (declaim (fixnum *load-time-value-error-value*))) + :load t) + (ctu:file-compile + `((defun load-time-value-error-test-1 () + (the list (load-time-value *load-time-value-error-value*)))) + :load t)) (assert warn) (assert fail)) (handler-case (load-time-value-error-test-1) @@ -2190,23 +2203,12 @@ (ignore-errors (delete-file lisp)) (ignore-errors (delete-file fasl))))) -;; named and unnamed -(defconstant +born-to-coalesce+ '.born-to-coalesce.) -(test-util:with-test (:name (compile compile-file :coalescing symbol)) - (multiple-value-bind (file-fun core-fun) - (compile2 '(lambda () - (let ((x (cons +born-to-coalesce+ nil)) - (y (cons '.born-to-coalesce. nil))) - (list x y)))) - (assert (= 1 (count-code-constants '.born-to-coalesce. file-fun))) - (assert (= 1 (count-code-constants '.born-to-coalesce. core-fun))))) - ;; some things must retain identity under COMPILE, but we want to coalesce them under COMPILE-FILE (defun assert-coalescing (constant) - (let ((value (copy-seq (symbol-value constant)))) + (let ((value (copy-seq constant))) (multiple-value-bind (file-fun core-fun) (compile2 `(lambda () - (let ((x (cons ,constant nil)) + (let ((x (cons ',constant nil)) (y (cons ',value nil))) (list x y)))) (assert (= 1 (count-code-constants value file-fun))) @@ -2224,17 +2226,14 @@ (equal a b) (not (eq a b)))))))) -(defconstant +born-to-coalesce2+ "maybe coalesce me!") (test-util:with-test (:name (compile compile-file :coalescing string)) - (assert-coalescing '+born-to-coalesce2+)) + (assert-coalescing "maybe coalesce me!")) -(defconstant +born-to-coalesce3+ #*01101001011101110100011) (test-util:with-test (:name (compile compile-file :coalescing bit-vector)) - (assert-coalescing '+born-to-coalesce3+)) + (assert-coalescing #*01101001011101110100011)) -(defconstant +born-to-coalesce4+ '(foo bar "zot" 123 (nested "quux") #*0101110010)) (test-util:with-test (:name (compile compile-file :coalescing :mixed)) - (assert-coalescing '+born-to-coalesce4+)) + (assert-coalescing '(foo bar "zot" 123 (nested "quux") #*0101110010))) (defclass some-constant-thing () ()) @@ -2260,20 +2259,20 @@ ;;; check that non-trivial constants are EQ across different files: this is ;;; not something ANSI either guarantees or requires, but we want to do it ;;; anyways. -(defconstant +share-me-1+ #-inline-constants 123.456d0 #+inline-constants nil) +(defconstant +share-me-1+ 123.456d0) (defconstant +share-me-2+ "a string to share") (defconstant +share-me-3+ (vector 1 2 3)) (defconstant +share-me-4+ (* 2 most-positive-fixnum)) -(multiple-value-bind (f1 c1) (compile2 '(lambda () (values +share-me-1+ +(multiple-value-bind (f1 c1) (compile2 `(lambda () (values +share-me-1+ +share-me-2+ +share-me-3+ +share-me-4+ - #-inline-constants pi))) - (multiple-value-bind (f2 c2) (compile2 '(lambda () (values +share-me-1+ + pi))) + (multiple-value-bind (f2 c2) (compile2 `(lambda () (values +share-me-1+ +share-me-2+ +share-me-3+ +share-me-4+ - #-inline-constants pi))) + pi))) (flet ((test (fa fb) (mapc (lambda (a b) (assert (eq a b))) @@ -2283,6 +2282,21 @@ (test f1 f2) (test f1 c2)))) +;;;; backq const folding tests +(test-util:with-test (:name :backq-const-named-reference-folding) + (ctu:file-compile + `((defconstant +izero+ 0) + (defconstant +fzero+ 0f0) + (defconstant +dzero+ 0d0) + (defparameter *dzero* 0d0) + (defun test-1 () `(,+izero+ ,+fzero+ ,+dzero+)) + (defun test-2 () `(,+izero+ ,+fzero+ ,+dzero+ ,*dzero*)) + (defun test-3 () (list +izero+ +fzero+ +dzero+))) + :load t) + (assert (equal (test-1) '(0 0.0 0.0d0))) + (assert (equal (test-2) '(0 0.0 0.0d0 0.0d0))) + (assert (equal (test-3) '(0 0.0 0.0d0)))) + ;;; user-defined satisfies-types cannot be folded (deftype mystery () '(satisfies mysteryp)) (defvar *mystery* nil) @@ -2464,10 +2478,7 @@ (assert (equal type1 (sb-kernel:%simple-fun-type g))) (assert (equal type0 (sb-kernel:%simple-fun-type h))))) -;;; I think *CHECK-CONSISTENCY* is confused in the presence of dynamic-extent. -;;; A simpler example not involving package iteration also fails in COMPILE-FILE: -;;; (let ((l (mapcar #'string *features*))) (defun g () l)) -(test-util:with-test (:name :bug-308921 :fails-on :sbcl) +(test-util:with-test (:name :bug-308921) (let ((*check-consistency* t)) (ctu:file-compile `((let ((exported-symbols-alist @@ -2482,13 +2493,12 @@ (test-util:with-test (:name :bug-308941) (multiple-value-bind (warn fail) - (let ((*check-consistency* t)) - (ctu:file-compile - "(eval-when (:compile-toplevel :load-toplevel :execute) + (ctu:file-compile + "(eval-when (:compile-toplevel :load-toplevel :execute) (defstruct foo3)) (defstruct bar (foo #.(make-foo3)))" - :load nil)) + :load nil) ;; ...but the compiler should not break. (assert (and warn fail)))) @@ -2603,42 +2613,6 @@ (assert (string= (funcall f) "Weird transform answer is 14")))) -(defun skip-1-passthrough (a b sb-int:&more context count) - (declare (ignore a b)) - (multiple-value-call 'list - 'start - (sb-c:%more-arg-values context 1 (1- (truly-the fixnum count))) - 'end)) -(defun skip-2-passthrough (a b sb-int:&more context count) - (declare (ignore a b)) - (multiple-value-call 'list - 'start - (sb-c:%more-arg-values context 2 (- (truly-the fixnum count) 2)) - 'end)) -(defun skip-n-passthrough (n-skip n-copy sb-int:&more context count) - (assert (>= count (+ n-copy n-skip))) ; prevent crashes - (multiple-value-call 'list - 'start - (sb-c:%more-arg-values context n-skip n-copy) - 'end)) - -;; %MORE-ARG-VALUES was wrong on x86 and x86-64 with nonzero 'skip'. -;; It's entirely possible that other backends are also not working. -(test-util:with-test (:name :more-arg-fancy - :skipped-on :interpreter) - (assert (equal (skip-1-passthrough 0 0 'a 'b 'c 'd 'e 'f) - '(start b c d e f end))) - (assert (equal (skip-2-passthrough 0 0 'a 'b 'c 'd 'e 'f) - '(start c d e f end))) - (assert (equal (skip-n-passthrough 1 5 'a 'b 'c 'd 'e 'f) - '(start b c d e f end))) - (assert (equal (skip-n-passthrough 1 5 'a 'b 'c 'd 'e 'f 'g) - '(start b c d e f end))) - (assert (equal (skip-n-passthrough 2 5 'a 'b 'c 'd 'e 'f 'g) - '(start c d e f g end))) - (assert (equal (skip-n-passthrough 2 5 'a 'b 'c 'd 'e 'f 'g 'h) - '(start c d e f g end)))) - (test-util:with-test (:name :macro-policy) (flet ((count-notes () (let ((count 0)) @@ -2775,9 +2749,22 @@ #'test-case `(((function ()) "(FUNCTION NIL)") ((function *) "(FUNCTION *)") - ((function (function *)) "(FUNCTION (FUNCTION *))") + ((function (function t)) "(FUNCTION (FUNCTION T))") ((function (function (eql 1))) "(FUNCTION (FUNCTION (EQL 1))"))))) +(with-test (:name (:compiler-messages function :lambda-list)) + ;; Previously, function lambda lists were sometimes printed + ;; confusingly, e.g.: + ;; + ;; (function collection) => #'COLLECTION + ;; ((function t)) => (#'T) + ;; + (handler-case + (sb-c::parse-lambda-list '((function t) . a) :context 'defmethod) + (error (condition) + (assert (search "illegal dotted lambda list: ((FUNCTION T) . A)" + (princ-to-string condition)))))) + (with-test (:name :boxed-ref-setf-special :skipped-on :interpreter) (let* ((var (gensym)) @@ -3005,7 +2992,7 @@ (assert (eql (foo1 10 1) 3628800)) (let ((code (sb-kernel::fun-code-header #'foo1))) (assert (= (sb-kernel::code-n-entries code) 1)) - (assert (eq (aref (sb-kernel::code-entry-points code) 0) + (assert (eq (sb-kernel:%code-entry-point code 0) #'foo1))))) (with-test (:name (:block-compile :inline)) @@ -3066,3 +3053,63 @@ (with-test (:name :fopcompile-specials) (ctu:file-compile "(locally (declare (special foo)) (print foo))")) + +(with-test (:name :local-call-context) + (ctu:file-compile + "(lambda (&optional b) (declare (type integer b)) b)" + :load t)) + +(defstruct entry-info-type-struct) + +(defvar *entry-info-type-struct* (make-entry-info-type-struct)) + +(defmethod make-load-form ((struct entry-info-type-struct) &optional env) + (declare (ignore env)) + '*entry-info-type-struct*) + +(declaim (ftype (function () (member #.*entry-info-type-struct*)) entry-info-type-func)) + +(with-test (:name :dump-entry-info-type) + (ctu:file-compile + "(lambda () (entry-info-type-func))" + :load t)) + +(deftype member-abc () '(member #\a #\b #\c)) +(with-test (:name (make-array :initial-element style-warning)) + (multiple-value-bind (warnp failp) + (ctu:file-compile + "(defun make-... (len) (make-array len :element-type '(or member-abc condition) :initial-element #\\e))") + (assert warnp) + (assert (not failp)))) + +(let ((false #\a) + (true #\z)) + (defun is-probability? (inp) + (and (characterp inp) (char<= false inp true))) + (deftype probability () '(satisfies is-probability?))) +(with-test (:name (make-array :initial-element satisfies)) + (multiple-value-bind (warnp failp) + (ctu:file-compile + "(defun make-... (len) (make-array len :element-type '(or probability condition) :initial-element #\\e))") + (assert (not warnp)) + (assert (not failp)))) +(with-test (:name (make-sequence :initial-element satisfies)) + (multiple-value-bind (warnp failp) + (ctu:file-compile + "(defun make-... (len) (make-sequence '(simple-array (or probability condition) (*)) len :initial-element #\\e))") + (assert (not warnp)) + (assert (not failp)))) + +;;; Test from git rev 0b39d68b05ef669f812a6bf570126505d931bf96 +;;; I do not understand why, if placed in a '.pure' file, it causes: +;;; There is no applicable method for the generic function +;;; #<STANDARD-GENERIC-FUNCTION SB-MOP:REMOVE-DIRECT-SUBCLASS (1)> +;;; when called with arguments +;;; (#<STRUCTURE-CLASS COMMON-LISP:STRUCTURE-OBJECT> NIL). +;;; when the test runner attempts to purge the classoid namespace +;;; of test artifacts. +;;; (It does define structures, but that's supposed to be allowed now) +(with-test (:name :bug-255) + (with-scratch-file (fasl "fasl") + (compile-file "bug-255" :output-file fasl)) + (delete-package :bug255)) diff --git a/tests/compiler.pure-cload.lisp b/tests/compiler.pure-cload.lisp index 88fd5e590c..f9016082c6 100644 --- a/tests/compiler.pure-cload.lisp +++ b/tests/compiler.pure-cload.lisp @@ -27,7 +27,8 @@ ;;; isn't declared as a variable, but to set its SYMBOL-VALUE anyway. ;;; ;;; This bug was in sbcl-0.6.11.13. -(print (setq improperly-declared-var '(1 2))) +(locally (declare (sb-ext:muffle-conditions warning)) + (print (setq improperly-declared-var '(1 2)))) (assert (equal (symbol-value 'improperly-declared-var) '(1 2))) (makunbound 'improperly-declared-var) ;;; This is a slightly different way of getting the same symptoms out @@ -168,22 +169,36 @@ ,@(loop for saetp across sb-vm:*specialized-array-element-type-properties* for specifier = (sb-vm:saetp-specifier saetp) - for array = (make-array (if specifier 10 0) - :element-type specifier) + for init = (cond ((member specifier '(character base-char)) + '(:initial-element #\X)) + ((eq specifier 't) '(:initial-element :hello)) + (specifier + `(:initial-element + ,(sb-vm:saetp-initial-element-default saetp)))) + for array = (apply 'make-array (if specifier 10 0) + :element-type specifier init) for make-array = `(make-array ,(if specifier 10 0) - :element-type ',specifier) + :element-type ',specifier + ,@init) collect `(assert (and (equal (type-of ,array) ',(type-of array)) (equalp ,array ,make-array))))))) (make-tests))) -(lambda () (the string (+ 1 x))) - -(lambda () - (macrolet ((x (&rest args) - (declare (ignore args)) - 'a)) - (let (a) - (declare (type vector a)) - (x #.#'list)))) +(defparameter *my-type-test-ran* 0) +(deftype some-weird-type () '(satisfies my-thing-p)) +(defun my-thing-p (x) + (incf *my-type-test-ran*) + (member x '(nil :foo))) + +(defun make-array-fill-nil () + (sb-int:dx-let ((a (make-array 5 :initial-element nil + :element-type '(or (and complex) some-weird-type)))) + (values (stack-allocated-p a) + *my-type-test-ran*))) + +(with-test (:name :splat-nil) + (multiple-value-bind (ok tested) (make-array-fill-nil) + ;; should not inhibit stack allocation, should check that NIL is OK + (assert (and ok (eql tested 1))))) diff --git a/tests/compiler.pure.lisp b/tests/compiler.pure.lisp index af38d24aed..0a1adfd57b 100644 --- a/tests/compiler.pure.lisp +++ b/tests/compiler.pure.lisp @@ -573,13 +573,6 @@ (with-test (:name (the values)) (assert (= (the (values integer symbol) (values 1 'foo 13)) 1))) -(with-test (:name (compile eval the type-error)) - (checked-compile-and-assert (:optimize :safe) - '(lambda (v) - (list (the fixnum (the (real 0) (eval v))))) - ((0.1) (condition 'type-error)) - ((-1) (condition 'type-error)))) - ;;; the implicit block does not enclose lambda list (with-test (:name (compile :implicit block :does-not-enclose :lambda-list)) (let ((forms '((defmacro #1=#:foo (&optional (x (return-from #1#))) @@ -2333,7 +2326,7 @@ x))) (assert (= a (random most-positive-fixnum))))) -;;; MISC.641: LET-conversion after physical environment analysis lost NLX-INFOs +;;; MISC.641: LET-conversion after environment analysis lost NLX-INFOs (with-test (:name (compile let :conversion :lost :nlx-infos :misc.641)) (checked-compile-and-assert (:allow-style-warnings t :optimize nil) `(lambda () @@ -2433,7 +2426,7 @@ (with-test (:name (compile lambda declare values)) (let ((fun (checked-compile '(lambda (x) (declare (values list)) x)))) - (assert (equal (sb-impl::%fun-type fun) + (assert (equal (sb-impl::%fun-ftype fun) '(function (t) (values list &optional)))))) ;;; test for some problems with too large immediates in x86-64 modular @@ -2918,7 +2911,7 @@ (when x (setf args x)) (ctu:compiler-derived-type args))))) 42) - (assert (equal '(or cons null integer) type)) + (assert (equal '(or list integer) type)) (assert derivedp))) (with-test (:name (compile base-char typep :elimination)) @@ -3107,7 +3100,7 @@ (setq x (make-array '(4 4))) (adjust-array y '(3 5)) (array-dimension y 0))) - (((make-array '(4 4) :adjustable t)) 3))) + (((make-array '(4 4) :initial-element nil :adjustable t)) 3))) (with-test (:name :with-timeout-code-deletion-note) (checked-compile `(lambda () @@ -3281,6 +3274,7 @@ (with-test (:name :float-division-using-exact-reciprocal) (flet ((test (lambda-form arg res &key (check-insts t)) + (declare (ignorable check-insts)) (let* ((fun (checked-compile lambda-form)) (disassembly (with-output-to-string (s) (disassemble fun :stream s)))) @@ -3329,6 +3323,7 @@ (disassemble fun1 :stream s))) (disassembly2 (with-output-to-string (s) (disassemble fun2 :stream s)))) + (declare (ignorable disassembly1 disassembly2)) ;; Multiplication at runtime should be eliminated only with ;; FLOAT-ACCURACY=0. (To catch SNaNs.) #+(or x86 x86-64) @@ -3359,6 +3354,7 @@ (disassemble fun1 :stream s))) (disassembly2 (with-output-to-string (s) (disassemble fun2 :stream s)))) + (declare (ignorable disassembly1 disassembly2)) ;; Let's make sure there is no addition at runtime: for x86 and ;; x86-64 that implies an FADD, ADDSS, or ADDSD instruction, so ;; look for the ADDs in the disassembly. It's a terrible KLUDGE, @@ -3382,7 +3378,7 @@ (test `(lambda (x) (declare (double-float x)) (+ x 0.0)) 543.21d0) (test `(lambda (x) (declare (double-float x)) (+ x 0.0d0)) 42.d0))) -(with-test (:name :float-substraction-of-zero) +(with-test (:name :float-subtraction-of-zero) (flet ((test (lambda-form arg &optional (result arg)) (let* ((fun1 (checked-compile lambda-form)) (fun2 (funcall (checked-compile @@ -3393,6 +3389,7 @@ (disassemble fun1 :stream s))) (disassembly2 (with-output-to-string (s) (disassemble fun2 :stream s)))) + (declare (ignorable disassembly1 disassembly2)) ;; Let's make sure there is no substraction at runtime: for x86 ;; and x86-64 that implies an FSUB, SUBSS, or SUBSD instruction, ;; so look for SUB in the disassembly. It's a terrible KLUDGE, @@ -3426,6 +3423,7 @@ (disassemble fun1 :stream s))) (disassembly2 (with-output-to-string (s) (disassemble fun2 :stream s)))) + (declare (ignorable disassembly1 disassembly2)) ;; Let's make sure there is no multiplication at runtime: for x86 ;; and x86-64 that implies an FMUL, MULSS, or MULSD instruction, ;; so look for MUL in the disassembly. It's a terrible KLUDGE, @@ -3464,37 +3462,6 @@ t)))) (ctu:assert-no-consing (funcall f)))) -(with-test (:name :array-type-predicates) - (dolist (et (list* '(integer -1 200) '(integer -256 1) - '(integer 0 128) - '(integer 0 (128)) - '(double-float 0d0 (1d0)) - '(single-float (0s0) (1s0)) - '(or (eql 1d0) (eql 10d0)) - '(member 1 2 10) - '(complex (member 10 20)) - '(complex (member 10d0 20d0)) - '(complex (member 10s0 20s0)) - '(or integer double-float) - '(mod 1) - '(member #\a #\b) - '(eql #\a) - #+sb-unicode 'extended-char - #+sb-unicode '(eql #\cyrillic_small_letter_yu) - (map 'list 'sb-vm:saetp-specifier - sb-vm:*specialized-array-element-type-properties*))) - (when et - (let* ((v (make-array 3 :element-type et))) - (checked-compile-and-assert () - `(lambda () - (list (if (typep ,v '(simple-array ,et (*))) - :good - ',et) - (if (typep (elt ,v 0) '(simple-array ,et (*))) - ',et - :good))) - (() '(:good :good))))))) - (with-test (:name :truncate-float) (let ((s (checked-compile `(lambda (x) (declare (single-float x)) @@ -3836,22 +3803,18 @@ (let ((f (checked-compile `(lambda (x) (declare (optimize (safety 3))) - (aref (locally (declare (optimize (safety 0))) - (coerce x '(simple-vector 128))) - 60)))) + (let ((coerced + (locally (declare (optimize (safety 0))) + (coerce x '(simple-vector 128))))) + (values coerced (aref coerced 60)))))) (long (make-array 100 :element-type 'fixnum))) (dotimes (i 100) (setf (aref long i) i)) ;; 1. COERCE doesn't check the length in unsafe code. - (assert (eql 60 (funcall f long))) - ;; 2. The compiler doesn't trust the length from COERCE - (assert (eq :caught - (handler-case - (funcall f (list 1 2 3)) - (sb-int:invalid-array-index-error (e) - (assert (eql 60 (type-error-datum e))) - (assert (equal '(integer 0 (3)) (type-error-expected-type e))) - :caught)))))) + (assert (eql 60 (nth-value 1 (funcall f long)))) + ;; 2. The compiler forces the result of COERCE to have the specified length + (assert (= (length (funcall f long)) 128)) + (assert (= (length (funcall f #*1001)) 128)))) (with-test (:name (compile :bug-655203-regression)) (let ((fun (checked-compile @@ -3914,12 +3877,14 @@ (let* ((start (get-internal-run-time)) (iterations 0) (fun (if times - (loop repeat times - for result = (checked-compile lambda) + (loop for result = (checked-compile lambda) + repeat times finally (return result)) (loop for result = (checked-compile lambda) do (incf iterations) - until (> (get-internal-run-time) (+ start 10)) + until (> (get-internal-run-time) (+ start (* 10 + (/ internal-time-units-per-second + 1000)))) finally (return result)))) (end (get-internal-run-time)) (got (funcall fun))) @@ -4315,17 +4280,16 @@ (((cons 1.0 2.0) :test '=) t))) (with-test (:name (compile truncate :wild-values)) - (let ((sb-c::*check-consistency* t)) - (checked-compile-and-assert () - `(lambda (a) - (declare (type (member 1d0 2d0) a)) - (block return-value-tag - (funcall - (the function - (catch 'debug-catch-tag - (return-from return-value-tag - (progn (truncate a)))))))) - ((2d0) (values 2 0d0))))) + (checked-compile-and-assert () + `(lambda (a) + (declare (type (member 1d0 2d0) a)) + (block return-value-tag + (funcall + (the function + (catch 'debug-catch-tag + (return-from return-value-tag + (progn (truncate a)))))))) + ((2d0) (values 2 0d0)))) (with-test (:name (compile :boxed-fp-constant-for-full-call)) (let ((fun (checked-compile @@ -4575,8 +4539,8 @@ (with-test (:name (:bug-1050768 :cause)) (let ((types `((string string) - ((or (simple-array character 24) (vector t 24)) - (or (simple-array character 24) (vector t)))))) + ((or (simple-array character 9) (vector t 9)) + (or (simple-array character 9) (vector t)))))) (dolist (pair types) (destructuring-bind (orig conservative) pair (assert (sb-kernel:type= (sb-kernel:specifier-type conservative) @@ -4809,7 +4773,7 @@ (checked-compile-and-assert () `(lambda (i) (if (typep i '(integer -31 31)) - (aref #. (make-array 63) (+ i 31)) + (aref #.(make-array 63 :initial-element 0) (+ i 31)) (error "foo"))) ((-31) 0))) @@ -4862,12 +4826,19 @@ (with-test (:name :data-vector-set-with-offset-signed-index) (let ((dvr (find-symbol "DATA-VECTOR-SET-WITH-OFFSET" "SB-KERNEL"))) (when dvr + ;; I have no idea what this test is trying to say, or what user-visible + ;; behavior would change if this assertion didn't hold. + ;; But it seems unhappy with my changes to SIMPLE-BIT-VECTOR. + ;; But we never fold indexes for bit-vector. So ignore it. (assert (null (loop for info in (sb-c::fun-info-templates (sb-c::fun-info-or-lose dvr)) for (nil second-arg third-arg) = (sb-c::vop-info-arg-types info) - unless (or (typep second-arg '(cons (eql :constant))) + unless (or (string= (sb-c::vop-info-name info) + ;; don't violate package lock if symbol isn't there + "DATA-VECTOR-SET-WITH-OFFSET/SIMPLE-BIT-VECTOR") + (typep second-arg '(cons (eql :constant))) (equal third-arg '(:constant . (integer 0 0))) (equal second-arg `(:or ,(sb-c::primitive-type-or-lose @@ -4945,93 +4916,7 @@ (logand (lognand a -6) (* b -502823994))) ((-1491588365 -3745511761) 1084329992))) -;; win32 is very specific about the order in which catch blocks -;; must be allocated on the stack -;; -;; This test is on the critical path. When started as the very first test, -;; it finishes as the last. -(with-test (:name (compile :bug-1072739) :slow t) - (checked-compile-and-assert (:optimize :safe) - `(lambda () - (STRING= - (LET ((% 23)) - (WITH-OUTPUT-TO-STRING (G13908) - (PRINC - (LET () - (DECLARE (OPTIMIZE (SB-EXT:INHIBIT-WARNINGS 3))) - (HANDLER-CASE - (WITH-OUTPUT-TO-STRING (G13909) (PRINC %A%B% G13909) G13909) - (UNBOUND-VARIABLE NIL - (HANDLER-CASE - (WITH-OUTPUT-TO-STRING (G13914) - (PRINC %A%B% G13914) - (PRINC "" G13914) - G13914) - (UNBOUND-VARIABLE NIL - (HANDLER-CASE - (WITH-OUTPUT-TO-STRING (G13913) - (PRINC %A%B G13913) - (PRINC "%" G13913) - G13913) - (UNBOUND-VARIABLE NIL - (HANDLER-CASE - (WITH-OUTPUT-TO-STRING (G13912) - (PRINC %A% G13912) - (PRINC "b%" G13912) - G13912) - (UNBOUND-VARIABLE NIL - (HANDLER-CASE - (WITH-OUTPUT-TO-STRING (G13911) - (PRINC %A G13911) - (PRINC "%b%" G13911) - G13911) - (UNBOUND-VARIABLE NIL - (HANDLER-CASE - (WITH-OUTPUT-TO-STRING (G13910) - (PRINC % G13910) - (PRINC "a%b%" G13910) - G13910) - (UNBOUND-VARIABLE NIL - (ERROR "Interpolation error in \"%a%b%\" -")))))))))))))) - G13908))) - "23a%b%")) - (() t))) - -(with-test (:name (compile equal equalp :transforms)) - (let* ((s "foo") - (bit-vector #*11001100) - (values `(nil 1 2 "test" - ;; Floats duplicated here to ensure we get newly created instances - (read-from-string "1.1") (read-from-string "1.2d0") - (read-from-string "1.1") (read-from-string "1.2d0") - 1.1 1.2d0 '("foo" "bar" "test") - #(1 2 3 4) #*101010 (make-broadcast-stream) #p"/tmp/file" - ,s (copy-seq ,s) ,bit-vector (copy-seq ,bit-vector) - ,(make-hash-table) #\a #\b #\A #\C - ,(make-random-state) 1/2 2/3))) - - (dolist (predicate '(equal equalp)) - ;; Test all permutations of different types - (loop for x in values - do (loop for y in values - do (checked-compile-and-assert (:optimize nil) - `(lambda (x y) - (,predicate (the ,(type-of x) x) - (the ,(type-of y) y))) - ((x y) (funcall predicate x y))))) - (checked-compile-and-assert () - `(lambda (x y) - (,predicate (the (cons (or simple-bit-vector simple-base-string)) - x) - (the (cons (or (and bit-vector (not simple-array)) - (simple-array character (*)))) - y))) - (((list (string 'list)) (list "LIST")) t))))) - -(with-test (:name (compile restart-case optimize speed compiler-note) - ;; Cannot-DX note crashes test driver unless we have this: - :skipped-on (not :stack-allocatable-fixed-objects)) +(with-test (:name (compile restart-case optimize speed compiler-note)) (checked-compile '(lambda () (declare (optimize speed)) (restart-case () (c ())))) @@ -5043,7 +4928,7 @@ x)))) (with-test (:name (compile :copy-more-arg) - :fails-on (or :alpha :hppa :mips :sparc)) + :fails-on (or :mips :sparc)) ;; copy-more-arg might not copy in the right direction ;; when there are more fixed args than stack frame slots, ;; and thus end up splatting a single argument everywhere. @@ -5085,8 +4970,7 @@ ;; quantifiers shouldn't cons themselves. (with-test (:name :quantifiers-no-consing :serial t - :skipped-on (or :interpreter - (not :stack-allocatable-closures))) + :skipped-on :interpreter) (let ((constantly-t (lambda (x) x t)) (constantly-nil (lambda (x) x nil)) (list (make-list 1000 :initial-element nil)) @@ -5192,13 +5076,12 @@ (with-test (:name :interr-type-specifier-hashing) (let ((specifiers - (remove - 'simple-vector + (remove nil (map 'list - (lambda (saetp) - (sb-c::type-specifier - (sb-c::specifier-type - `(simple-array ,(sb-vm:saetp-specifier saetp) (*))))) + (lambda (saetp &aux (et (sb-vm:saetp-specifier saetp))) + (unless (member et '(nil t)) + (sb-c::type-specifier + (sb-c::specifier-type `(simple-array ,et (*)))))) sb-vm:*specialized-array-element-type-properties*)))) (assert (sb-c::%interr-symbol-for-type-spec `(or ,@specifiers))) (assert (sb-c::%interr-symbol-for-type-spec @@ -5227,12 +5110,13 @@ :skipped-on (:not (:or :x86 :x86-64))) (flet ((approx-lines-of-assembly-code (type-expr) (count #\Newline - (with-output-to-string (s) - (disassemble - `(lambda (x) - (declare (optimize (sb-c:verify-arg-count 0))) - (typep x ',type-expr)) - :stream s))))) + (let ((sb-ext:*disassemble-annotate* nil)) + (with-output-to-string (s) + (disassemble + `(lambda (x) + (declare (optimize (sb-c:verify-arg-count 0))) + (typep x ',type-expr)) + :stream s)))))) ;; These are fragile, but less bad than the possibility of messing up ;; any vops, especially since the generic code in 'vm-type' checks for ;; a vop by its name in a place that would otherwise be agnostic of the @@ -5561,17 +5445,6 @@ ;; The function can not return YIKES (assert (not (ctu:find-code-constants f :type '(eql yikes)))))) -(with-test (:name :compile-file-error-position-reporting - :serial t) - (dolist (input '("data/wonky1.lisp" "data/wonky2.lisp" "data/wonky3.lisp")) - (let ((expect (with-open-file (f input) (read f)))) - (assert (stringp expect)) - (let ((err-string (with-output-to-string (*error-output*) - (compile-file input :print nil - :output-file - (scratch-file-name "fasl"))))) - (assert (search expect err-string)))))) - (with-test (:name (coerce :derive-type)) (macrolet ((check (type ll form &rest values) `(assert (equal (funcall (checked-compile @@ -5727,7 +5600,7 @@ (let ((f (checked-compile '(lambda (x) (oddp x))))) (ctu:assert-no-consing (funcall f most-positive-fixnum)))) (with-test (:name (oddp bignum :no-consing) - :serial t :skipped-on :interpreter) + :serial t :skipped-on :interpreter :fails-on :ppc) (let ((f (checked-compile '(lambda (x) (oddp x)))) (x (* most-positive-fixnum most-positive-fixnum 3))) (ctu:assert-no-consing (funcall f x)))) @@ -5736,30 +5609,11 @@ (let ((f (checked-compile '(lambda (x) (logtest x most-positive-fixnum))))) (ctu:assert-no-consing (funcall f 1)))) (with-test (:name (logtest bignum :no-consing) - :serial t :skipped-on :interpreter) + :serial t :skipped-on :interpreter :fails-on :ppc) (let ((f (checked-compile '(lambda (x) (logtest x 1)))) (x (* most-positive-fixnum most-positive-fixnum 3))) (ctu:assert-no-consing (funcall f x)))) -(with-test (:name (sb-c::mask-signed-field :randomized)) - (let (result) - (dotimes (i 1000) - (let* ((ool (checked-compile '(lambda (s i) - (sb-c::mask-signed-field s i)))) - (size (random (* sb-vm:n-word-bits 2))) - (constant (checked-compile `(lambda (i) - (sb-c::mask-signed-field ,size i)))) - (arg (- (random (* most-positive-fixnum 8)) (* most-positive-fixnum 4))) - (declared (checked-compile `(lambda (i) - (declare (type (integer ,(- (abs arg)) ,(abs arg)) i)) - (sb-c::mask-signed-field ,size i)))) - (ool-answer (funcall ool size arg)) - (constant-answer (funcall constant arg)) - (declared-answer (funcall declared arg))) - (unless (= ool-answer constant-answer declared-answer) - (push (list size arg ool-answer constant-answer declared-answer) result)))) - (assert (null result)))) - (with-test (:name (array-dimension *)) (checked-compile-and-assert () `(lambda (array) @@ -5774,12 +5628,10 @@ (map a 'list (the vector b) #*)) (('vector #()) #() :test #'equalp))) -(with-test (:name (make-list :large 1)) +(with-test (:name (make-list :large) + :skipped-on (or :ubsan (not :64-bit))) (checked-compile `(lambda () - (make-list (expt 2 28) :initial-element 0)))) - -(with-test (:name (make-list :large 2) - :skipped-on (not :64-bit)) + (make-list (expt 2 28) :initial-element 0))) (checked-compile `(lambda () (make-list (expt 2 30) :initial-element 0)))) @@ -5835,6 +5687,19 @@ (assert (search "NINTERSECTION" (princ-to-string c)))))) +(with-test (:name :adjust-array-semi-important-result) + (macrolet ((try (type assert-what) + `(multiple-value-bind (fun failure warnings style-warnings) + (checked-compile '(lambda (v) + (declare (,type v)) + (adjust-array v (* (length v) 2)) + (bit v 0)) + :allow-style-warnings t) + (declare (ignore fun failure warnings)) + (assert ,assert-what)))) + (try simple-bit-vector style-warnings) + (try bit-vector (not style-warnings)))) + (with-test (:name :destroyed-constant-warning) (multiple-value-bind (fun failure warnings) (checked-compile '(lambda () @@ -6106,45 +5971,6 @@ s))) (('(1 2) 3) 6))) -(with-test (:name (multiple-value-call :type-checking-rest)) - (checked-compile-and-assert (:allow-warnings t - :optimize :safe) - `(lambda (list) - (multiple-value-call - (lambda (&optional a &rest r) - (declare ((satisfies eval) r) - (ignore r)) - (list a)) - (values-list list))) - (('(1 list 2)) '(1)) - (('(1)) (condition 'type-error)))) - -(with-test (:name (multiple-value-call :type-checking-rest.2)) - (checked-compile-and-assert (:allow-warnings t - :optimize :safe) - `(lambda (list) - (multiple-value-call - (lambda (&optional a &rest r) - (declare (null r) - (ignore r)) - (list a)) - (values-list list))) - (('(1 list 2)) (condition 'type-error)) - (('(1)) '(1)))) - -(with-test (:name (multiple-value-call :type-checking-rest :type-derivation)) - (checked-compile-and-assert (:allow-warnings t - :optimize :safe) - `(lambda (list) - (multiple-value-call - (lambda (&optional a &rest r) - (declare (cons r) - (ignore r)) - (list a)) - (values-list list))) - (('(1 2)) '(1)) - (('(1)) (condition 'type-error)))) - (with-test (:name :delete-optional-dispatch-xep) (let ((name (gensym))) (checked-compile-and-assert () @@ -6154,6 +5980,20 @@ (multiple-value-call #',name (1- x)))) ((3) 10)))) +(with-test (:name :bug-1951889) + (checked-compile-and-assert + (:optimize '(:debug 2)) + `(lambda () + (block nil + (flet ((%f6 (x &key) + (declare (ignore x)) + (return 0))) + (loop for lv3 below 1 count + (if (%f6 0) + (%f6 0) + (eval (%f6 0))))))) + (() 0))) + (with-test (:name (yes-or-no-p type)) (checked-compile `(lambda () (yes-or-no-p nil))) @@ -6353,8 +6193,15 @@ (assert (search "is not a proper list." (princ-to-string (first compiler-errors))))))) (test '(cons 1 . 2)) - (test '((lambda (x) x) . 1)) - (test '(let () . 1)))) + (test '((lambda (x) x) . 3)) + (test '(let () . 4)))) +(with-test (:name (compile :macro-dotted-list)) + (checked-compile-and-assert () + `(lambda (i j) + (macrolet ((k (a . b) + `(+ ,a ,b))) + (k i . j))) + ((1 2) 3))) (with-test (:name (ldb :rlwinm)) (checked-compile-and-assert () @@ -6476,3 +6323,10 @@ ;;; pointer arithmetic is not what's being tested. (with-test (:name :sap+-immediate) (compile nil '(lambda (x) (sb-sys:sap+ x 65536)))) + +(with-test (:name (compile handler-bind :no-note)) + (checked-compile + `(lambda (x) + (handler-bind ((error (constantly nil))) + (pathname-type x))) + :allow-notes nil)) diff --git a/tests/compiler.test.sh b/tests/compiler.test.sh index 5ecc027d16..4d22c0ded4 100644 --- a/tests/compiler.test.sh +++ b/tests/compiler.test.sh @@ -15,6 +15,31 @@ use_test_subdirectory +# It's unclear why the majority of these tests are written in shell script when +# many look as though they would be perfectly happy as lisp tests. +# This test, on the other hand, would have a tough time as a lisp test, +# because it needs to make a symlink which would either mean calling run-program +# or using alien-funcall on symlink(). Shell is easier. +mkdir -p inscrutable/f00 +echo '(defun zook (x) (declare (integer x)) (length x))' > inscrutable/f00/f00_xyz_bad +ln -s inscrutable/f00/f00_xyz_bad good.lisp +run_sbcl --eval '(setq *default-pathname-defaults* #P"")' \ + --eval '(compile-file "good.lisp" :verbose t)' --quit >stdout.out 2>stderr.out +egrep -q 'compiling file ".*good' stdout.out +stdout_ok=$? +egrep -q 'file:.+good' stderr.out +stderr_ok=$? +if [ $stdout_ok = 0 -a $stderr_ok = 0 ] ; then + rm -r good.* stdout.out stderr.out inscrutable + echo "untruenames: PASS" +else + cat stdout.out stderr.out + echo "untruenames: FAIL" + exit $EXIT_LOSE +fi + +## FIXME: all these tests need to be more silent. Too much noise to parse + tmpfilename="$TEST_FILESTEM.lisp" # This should fail, as type inference should show that the call to FOO @@ -239,6 +264,15 @@ cat > $tmpfilename <<EOF EOF fail_on_condition_during_compile sb-ext:compiler-note $tmpfilename +cat > $tmpfilename <<EOF + (declaim (optimize debug) + (muffle-conditions compiler-note)) + (defun foo (x y) + (declare (optimize speed)) + (+ x y)) +EOF +fail_on_condition_during_compile sb-ext:compiler-note $tmpfilename + cat > $tmpfilename <<EOF (declaim (muffle-conditions compiler-note)) (defun foo (x y) @@ -272,6 +306,23 @@ cat > $tmpfilename <<EOF EOF expect_failed_compile $tmpfilename +cat > $tmpfilename <<EOF + (declaim (optimize debug)) + (locally + (declare (muffle-conditions warning)) + (defun foo () x)) + (defun bar () x) +EOF +expect_failed_compile $tmpfilename + +cat > $tmpfilename <<EOF + (defun foo () + (locally (declare (muffle-conditions warning)) + (+ x x)) + x) +EOF +expect_failed_compile $tmpfilename + # This should fail, and fail nicely -- not eg. loop trying to dump # references to the unbound variable. cat > $tmpfilename <<EOF @@ -513,5 +564,65 @@ cat > $tmpfilename <<EOF EOF fail_on_condition_during_compile sb-ext:compiler-note $tmpfilename +cat > $tmpfilename <<EOF +(in-package :cl-user) + +(eval-when (:compile-toplevel :load-toplevel :execute) + (defclass subclass (superclass) ((zslot2 :initarg :zslot2 :accessor zslot2)))) + +(eval-when (:compile-toplevel :load-toplevel :execute) + (defclass superclass () ((c :initarg c :accessor c)))) + +(eval-when (:compile-toplevel :load-toplevel :execute) + (sb-kernel::%invalidate-layout (sb-pcl::class-wrapper (find-class 'subclass)))) + +;; This test file is weird. It expects to see warnings from a COMPILE inside +;; a method body that is compiled (and not necessarily invoked). +;; To force the warnings to happen, we have to force the method to get called, +;; which we can do by asking a SUBTYPEP question. +(eval-when (:compile-toplevel :load-toplevel :execute) + (defmethod sb-mop:finalize-inheritance :after (class) + (eval '(defmethod z (x) (abcde))) + (funcall (compile nil '(lambda () (defun zz (x) (defgh)))))) + (assert (not (sb-kernel:csubtypep (sb-kernel:specifier-type 'subclass) + (sb-kernel:specifier-type 'condition))))) + +(defun subclass-p (x) + (typep x 'subclass)) +EOF +expect_warned_compile $tmpfilename + +cat > $tmpfilename <<EOF +(let ((a (load-time-value (funcall (lambda () 128))))) + (declare (fixnum a)) + (print a) + (terpri)) +EOF +expect_clean_cload $tmpfilename + +# Test compiler warning generation for unbound variables from type declaration... +cat > $tmpfilename <<EOF +(defun foo (bar) + (declare (type vector baz)) + (length bar)) +EOF +expect_failed_compile $tmpfilename + +# ... extent declaration ... +cat > $tmpfilename <<EOF +(defun foo (n) + (declare (type (mod 32) n)) + (let ((vect (make-array n :element-type 'fixnum))) + (declare (dynamic-extent vec)) + (1+ (length vect)))) +EOF +expect_failed_compile $tmpfilename + +# ... and setq +cat > $tmpfilename <<EOF +(setq nonexistent t) +EOF +expect_failed_compile $tmpfilename + # success exit $EXIT_TEST_WIN diff --git a/tests/compound-cons.impure.lisp b/tests/compound-cons.pure.lisp similarity index 100% rename from tests/compound-cons.impure.lisp rename to tests/compound-cons.pure.lisp diff --git a/tests/concurrent-rename-package.impure.lisp b/tests/concurrent-rename-package.impure.lisp new file mode 100644 index 0000000000..e0a9ac34c6 --- /dev/null +++ b/tests/concurrent-rename-package.impure.lisp @@ -0,0 +1,48 @@ + +(defparameter *pkgname* "SOME-FINE-PACKAGE") +(unless (find-package *pkgname*) + (make-package *pkgname*)) + +(defglobal *count-found* 0) +(declaim (fixnum *count-found*)) + +;;; We most certainly don't want to synchronize all calls to FIND-PACKAGE +;;; and FIND-SYMBOL with mutators of the package name graph. +;;; Unfortunately there is an interesting and not too far-fetched use which +;;; involves one thread looking up a package by its primary name while some +;;; other thread adds a nickname to that package. This used to potentially +;;; fail in the looking-up thread because RENAME-PACKAGE started by deleting +;;; all names of the package being altered. That is no longer the case. +(defun renaming-experiment (n-trials n-threads) + (let* ((trigger-sem (sb-thread:make-semaphore)) + (trial-completion-sem (sb-thread:make-semaphore)) + (threadfun + (lambda () + (dotimes (i n-trials) + (sb-thread:wait-on-semaphore trigger-sem) + (when (find-package *pkgname*) (atomic-incf *count-found*)) + (sb-thread:signal-semaphore trial-completion-sem)))) + (threads + (loop for i from 1 to n-threads + collect (sb-thread:make-thread threadfun + :name (format nil "thread ~d" i)))) + (wins 0)) + (dotimes (i n-trials) + (setq *count-found* 0) + (sb-thread:signal-semaphore trigger-sem n-threads) + (rename-package *pkgname* *pkgname* '("SFP")) + (sb-thread:wait-on-semaphore trial-completion-sem :n n-threads) + (rename-package *pkgname* *pkgname* nil) + ;; (format t "~&Trial ~d: ~d~%" (1+ i) *count-found*) + (when (= *count-found* n-threads) + (incf wins))) + (mapc 'sb-thread:join-thread threads) + wins)) + +(with-test (:name :renamed-package-does-not-disappear + :skipped-on (:not :sb-thread)) + (let* ((n-trials 100) + (wins (renaming-experiment n-trials 4))) + ;; This was getting about 50% to 70% success prior to the fix. + ;; (format t "~&Win percent: ~,,2f~%" (/ wins n-trials)) + (assert (= wins n-trials)))) diff --git a/tests/concurrent-syscalls.impure.lisp b/tests/concurrent-syscalls.impure.lisp index fce8c3942f..6de1638624 100644 --- a/tests/concurrent-syscalls.impure.lisp +++ b/tests/concurrent-syscalls.impure.lisp @@ -1,4 +1,4 @@ -#-sb-thread (sb-ext:exit :code 104) +#-sb-thread (invoke-restart 'run-tests::skip-file) (use-package "SB-THREAD") (defun exercise-syscall (fn reference-errno) diff --git a/tests/condition.impure.lisp b/tests/condition-2.pure.lisp similarity index 92% rename from tests/condition.impure.lisp rename to tests/condition-2.pure.lisp index 6d4053fd2c..74d3f01484 100644 --- a/tests/condition.impure.lisp +++ b/tests/condition-2.pure.lisp @@ -9,46 +9,49 @@ ;;;; absolutely no warranty. See the COPYING and CREDITS files for ;;;; more information. -(cl:in-package :cl-user) - -(use-package :test-util) - ;;; Bug from CLOCC. +;;; http://clocc.sourceforge.net/ (defpackage :p1 (:use :cl) (:export #:code #:code-msg #:%code-msg)) -(in-package :p1) -(define-condition code () - ((msg :reader code-msg :reader %code-msg :initarg :msg))) +(define-condition p1:code () + ((p1::msg :reader p1:code-msg :reader p1:%code-msg :initarg :msg))) (defpackage :p2 (:use :cl :p1)) -(in-package :p2) -(define-condition code1 (code) - ((msg :accessor code-msg :initarg :msg))) - -(let ((code (make-condition 'code :msg 1))) - (assert (typep code 'code)) - (assert (eql (code-msg code) 1)) - (assert (eql (%code-msg code) 1))) -(let ((code (make-condition 'code1 :msg 1))) - (assert (typep code 'code)) - (assert (eql (code-msg code) 1)) - (assert (eql (%code-msg code) 1)) - (setf (code-msg code) 2) - (assert (eql (code-msg code) 2)) - (assert (eql (%code-msg code) 1))) - -(in-package :cl-user) +(define-condition p2::code1 (p1:code) + ((p2::msg :accessor p1:code-msg :initarg :msg))) + +;;; This test asserts that: +;;; - distinct symbols create distinct slots, unlike with DEFSTRUCT +;;; where slots are compared by string= +;;; - two slots can be initialized by one initarg +;;; - an accessor can shadow an identically-named inherited accessor +;;; and read/write a different slot +(with-test (:name :condition-slot-package-confusion) + (let ((code (make-condition 'p1:code :msg 1))) + (assert (typep code 'p1:code)) + (assert (eql (p1:code-msg code) 1)) + (assert (eql (p1:%code-msg code) 1))) + (let ((code (make-condition 'p2::code1 :msg 1))) + (assert (typep code 'p1:code)) + (assert (eql (p1:code-msg code) 1)) + (assert (eql (p1:%code-msg code) 1)) + (setf (p1:code-msg code) 2) + (assert (eql (p1:code-msg code) 2)) + (assert (eql (p1:%code-msg code) 1)))) ;;; Check that initializing the condition class metaobject doesn't create ;;; any instances. Reported by Marco Baringer on sbcl-devel Mon, 05 Jul 2004. (defvar *condition-count* 0) (define-condition counted-condition () ((slot :initform (incf *condition-count*)))) -(defmethod frob-counted-condition ((x counted-condition)) x) +;; What purpose was this DEFMETHOD serving? None as far as I can tell. +;; (defmethod frob-counted-condition ((x counted-condition)) x) (assert (= 0 *condition-count*)) (assert (typep (sb-mop:class-prototype (find-class 'counted-condition)) '(and condition counted-condition))) +(opaque-identity (make-condition 'counted-condition)) +(assert (= 1 *condition-count*)) (define-condition picky-condition () ()) @@ -464,7 +467,7 @@ (locally (declare (muffle-conditions style-warning)) (handler-bind (((satisfies some-silly-fun) #'print)) (let ((test (caaar sb-kernel:*handler-clusters*))) - (assert (eq test (sb-int:find-fdefn 'some-silly-fun)))))) + (assert (eq test 'some-silly-fun))))) (handler-bind (((or warning error) #'print)) (let ((test (caaar sb-kernel:*handler-clusters*))) (assert (functionp test)))) @@ -481,7 +484,7 @@ (handler-bind ((warning 'some-silly-handler)) (let ((fn (cdaar sb-kernel:*handler-clusters*))) ;; the function is stored as an fdefn - (assert (typep fn 'sb-kernel::fdefn)))) + (assert (eq fn 'some-silly-handler)))) (handler-bind ((warning 'muffle-warning)) (let ((fn (cdaar sb-kernel:*handler-clusters*))) @@ -494,6 +497,7 @@ ;; the real handler function. (defun this-should-fail () (declare (muffle-conditions style-warning)) + (declare (optimize safety)) (handler-bind ((condition #'some-nonexistent-handler)) (random 100))) @@ -550,7 +554,8 @@ (test-use-value #'(setf thing)) (test-use-value '(setf thing)))) -(with-test (:name :unknown-key-restart) +(with-test (:name :unknown-key-restart + :fails-on :sparc) (handler-bind ((sb-ext:unknown-keyword-argument (lambda (c) (assert (eq (sb-ext:unknown-keyword-argument-name c) @@ -590,23 +595,23 @@ (defun ggg+1 () (1+ *ggg*)) (with-test (:name :restart-unbound-variable - :skipped-on (not (and :x86-64 :sb-thread))) - (let ((success nil)) + :skipped-on (not (and (or :arm64 :x86-64) :sb-thread))) + (handler-bind + ((type-error + (lambda (c) + (assert (eql (type-error-datum c) :nope)) + (use-value 1 c))) + (unbound-variable + (lambda (e) + (store-value :nope e)))) + (assert (eql (ggg+1) 2)))) + +(with-test (:name :restart-type-error + :skipped-on :sparc) ; hangs + (let ((fun (checked-compile '(lambda (x) + (sb-kernel:the* (fixnum :restart t) x))))) (handler-bind - ((unbound-variable - (lambda (e) - ;; This is kinda whacky, I'd have preferred to - ;; see a TYPE-ERROR here, but instead we signal - ;; RETRY-UNBOUND-VARIABLE which is a system-internal - ;; type name, and a format control describing the problem - ;; Apparently I don't understand anything anyway, - ;; because why is this *same* handler still accessible? - (cond ((typep e 'sb-kernel::retry-unbound-variable) - (when (search ":NOPE is not of type INTEGER" - (write-to-string e :escape nil)) - (setq success t)) - (invoke-restart 'use-value 1)) - (t - (invoke-restart 'store-value :nope)))))) - (ggg+1) - (assert success)))) + ((type-error + (lambda (c) + (use-value 2 c)))) + (assert (eql (funcall fun 'a) 2))))) diff --git a/tests/condition-notify.impure.lisp b/tests/condition-notify.pure.lisp similarity index 96% rename from tests/condition-notify.impure.lisp rename to tests/condition-notify.pure.lisp index 7c777078fe..664664bea7 100644 --- a/tests/condition-notify.impure.lisp +++ b/tests/condition-notify.pure.lisp @@ -1,4 +1,4 @@ -#-sb-thread (sb-ext:exit :code 104) +#-sb-thread (invoke-restart 'run-tests::skip-file) (use-package "SB-THREAD") (with-test (:name (:condition-variable :notify-multiple) diff --git a/tests/condition.pure.lisp b/tests/condition.pure.lisp index 23e4cc4d0b..a1d2dc9e82 100644 --- a/tests/condition.pure.lisp +++ b/tests/condition.pure.lisp @@ -288,13 +288,20 @@ ;; should print the stream position information. (with-test (:name (reader-error :stream-error-position-info :open-stream :bug-1264902)) - (assert - (search + (locally + ;; High debug avoids stack-allocating the stream. + ;; It would be fine to stack-allocate it, because the handler-case does not + ;; use the stream outside of its extent, however, because ALLOCATE-CONDITION + ;; doesn't know when you will use the stream, it always replaces a DX stream + ;; with a dummy. The dummy stream would not have position information. + (declare (optimize debug)) + (assert + (search "Line: 1, Column: 22, File-Position: 22" (with-input-from-string (stream "no-such-package::symbol") (handler-case (read stream) - (reader-error (condition) (princ-to-string condition))))))) + (reader-error (condition) (princ-to-string condition)))))))) ;; Printing a READER-ERROR when the underlying stream has been closed ;; should still work, but the stream information will not be printed. @@ -416,10 +423,11 @@ is not of type ;;; Instances of LAYOUT for condition classoids created by genesis ;;; should resemble ones created normally. Due to a bug, they did not. +;;; (The LENGTH slot had the wrong value) (with-test (:name :condition-layout-lengths) - (loop for layout being each hash-value of (sb-kernel:classoid-subclasses - (sb-kernel:find-classoid 'condition)) - for len = (sb-kernel:layout-length layout) + (loop for wrapper being each hash-value of (sb-kernel:classoid-subclasses + (sb-kernel:find-classoid 'condition)) + for len = (sb-kernel:wrapper-length wrapper) minimize len into min maximize len into max finally (assert (= min max)))) @@ -430,3 +438,33 @@ is not of type (declare (ignore newcond)) (assert (string= (write-to-string error :escape nil) "odd-length initializer list: (:A 1 :B).")))) + +(with-test (:name :type-error-on-dx-object + :skipped-on :interpreter) + (handler-case + (sb-int:dx-let ((a (make-array 3))) + (setf (aref a 0) a) + (print (1+ (aref a 0)))) + (error (e) + (assert (equal (sb-kernel:type-error-datum-stored-type e) + '(simple-vector 3)))))) + +(with-test (:name (:handler-bind-evaluation-count :lp1916302)) + (let (list) + (handler-bind ((condition (let ((x 0)) + (lambda (c) + (declare (ignore c)) + (push (incf x) list))))) + (signal 'condition) + (signal 'condition)) + (assert (equalp '(2 1) list)))) + +(with-test (:name (:handler-bind-evaluation-count :separate-establishment)) + (let (list) + (dotimes (i 2) + (handler-bind ((condition (let ((x 0)) + (lambda (c) + (declare (ignore c)) + (push (incf x) list))))) + (signal 'condition))) + (assert (equalp '(1 1) list)))) diff --git a/tests/constantp.pure.lisp b/tests/constantp.pure.lisp index 7b57705341..034b3e628a 100644 --- a/tests/constantp.pure.lisp +++ b/tests/constantp.pure.lisp @@ -13,6 +13,7 @@ :allow-failure t))) (assert (not (constantp '(block 1 10))))) +(sb-ext:defglobal *some-global-var* nil) (with-test (:name (constantp progv)) (assert (not (constantp '(progv '(*s*) nil *s*)))) @@ -31,8 +32,9 @@ (assert (not (constantp '(progv '(pi) '(10) 10)))) (assert - (not (constantp '(progv '(sb-c::**world-lock**) '(10) 10))))) + (not (constantp '(progv '(*some-global-var*) '(10) 10))))) +(declaim (muffle-conditions style-warning)) ; unknown type ABC (with-test (:name (constantp the)) (assert (not (constantp '(the (satisfies eval) 10)))) diff --git a/tests/constraint.pure.lisp b/tests/constraint.pure.lisp index 62040fa23a..91a9b925f5 100644 --- a/tests/constraint.pure.lisp +++ b/tests/constraint.pure.lisp @@ -98,3 +98,266 @@ ((= i 1) 3) (t i)))))) '(values (integer 2) &optional)))) + +(with-test (:name :ir1-phases-delay) + (assert + (equal (third (sb-kernel:%simple-fun-type + (checked-compile + '(lambda (n z) + (when (typep n 'fixnum) + (let ((ar (if (integerp n) + (make-array n) + z))) + (declare (type vector ar)) + (print ar) + (array-has-fill-pointer-p ar))))))) + '(values null &optional)))) + +(with-test (:name :--sign) + (assert + (equal (third (sb-kernel:%simple-fun-type + (checked-compile + '(lambda (x y) + (declare (integer x y)) + (if (<= x y) + (- x y) + -10))))) + '(values (integer * 0) &optional)))) + +(with-test (:name :--type) + (assert + (equal (third (sb-kernel:%simple-fun-type + (checked-compile + '(lambda (x y) + (if (> x y) + (- x y) + 1))))) + '(values real &optional)))) + +(with-test (:name :remove-equivalent-blocks-clear-constraints) + (checked-compile-and-assert + () + `(lambda (a c) + (declare ((and fixnum unsigned-byte) a) + (fixnum c)) + (eql c + (if (eql a c) + c + a))) + ((3 1) nil) + ((3 3) t))) + +(with-test (:name :type-constraint-joining) + (assert + (equal (caddr + (sb-kernel:%simple-fun-type + (checked-compile + `(lambda () + (let ((x 'foo)) + (if (read) + (setq x 3) + (setq x 5)) + x))))) + '(values (or (integer 5 5) (integer 3 3)) &optional)))) + +(with-test (:name :type-constraint-joining.2) + (assert + (equal (caddr + (sb-kernel:%simple-fun-type + (checked-compile + `(lambda (x) + (etypecase x + (integer (read)) + (float (read))) + x)))) + '(values (or float integer) &optional)))) + +(with-test (:name :type-constraint-joining.3) + (assert + (equal (caddr + (sb-kernel:%simple-fun-type + (checked-compile + `(lambda (x) + (if (read) + (setq x (random 10)) + (setq x (random 10.0))) + x)))) + '(values (or (single-float 0.0 (10.0)) (mod 10)) &optional)))) + +(with-test (:name :type-constraint-joining-terminates) + (checked-compile + sb-c:: + `(lambda (name vop) + (block foo + (do* ((block (vop-block vop) (ir2-block-prev block)) + (last vop (ir2-block-last-vop block))) + (nil) + (aver (eq (ir2-block-block block) (ir2-block-block (vop-block vop)))) + (do ((current last (vop-prev current))) + ((null current)) + (when (eq (vop-name current) name) + (return-from foo current)))))))) + +(with-test (:name :type-constraint-joining-conflicts) + (assert (nth-value + 1 + (checked-compile + '(lambda (y) + (let ((x 'foo)) + (ecase y + (1 (setq x (random 10))) + (2 (setq x (make-array 10))) + (3 (setq x (make-hash-table)))) + (symbol-name x))) + :allow-warnings t)))) + +(with-test (:name :type-constraint-joining.eql) + (assert + (equal (caddr + (sb-kernel:%simple-fun-type + (checked-compile + `(lambda (x) + (ecase x + (1 (read)) + (2 (read))) + x)))) + '(values (integer 1 2) &optional)))) + +(with-test (:name :type-constraint-joining.</=) + (assert + (ctype= (caddr + (sb-kernel:%simple-fun-type + (checked-compile + `(lambda (x) + (declare (integer x)) + (cond ((= x 20)) + ((< x 5)) + ((< x 10)) + (t (error ""))) x)))) + '(values (or + (integer * 9) + (integer 20 20)) + &optional)))) + +(with-test (:name :type-constraint-joining.</=.2) + (assert + (ctype= (caddr + (sb-kernel:%simple-fun-type + (checked-compile + `(lambda (x) + (if (typep x 'rational) + (cond ((= x 20)) + ((< x 5)) + ((< x 10)) + (t (error ""))) + (setf x :foo)) + x)))) + '(values (or + (integer 20 20) + (rational * (10)) + (member :foo)) + &optional)))) + +(with-test (:name :type-constraint-joining.</=.3) + (assert + (ctype= (caddr + (sb-kernel:%simple-fun-type + (checked-compile + `(lambda (x) + (cond ((< x 5)) + ((< x 10)) + (t (error ""))) + x)))) + '(values (or + (double-float * (10.0d0)) + (single-float * (10.0)) + (rational * (10))) + &optional)))) + +(with-test (:name :type-constraint-joining.>/=) + (assert + (ctype= (caddr + (sb-kernel:%simple-fun-type + (checked-compile + `(lambda (x) + (declare (integer x)) + (cond ((= x 5)) + ((> x 20)) + ((> x 10)) + (t (error ""))) x)))) + '(values (or + (integer 11) + (integer 5 5)) + &optional)))) + +(with-test (:name :type-constraint-joining.complement) + (assert + (equal (caddr + (sb-kernel:%simple-fun-type + (checked-compile + `(lambda (x) + (if (read) + (cond ((typep x 'integer) + (error "")) + (t (print ""))) + (cond ((typep x 'float) + (print "")) + (t (error "")))) + x)))) + '(values (not integer) &optional)))) + +(with-test (:name (:type-constraint-joining :infinities 1)) + (assert + (ctype= (caddr + (sb-kernel:%simple-fun-type + (checked-compile + `(lambda (number) + (declare (type (or number null) number)) + (cond ((null number) nil) + ((sb-ext:float-nan-p number) :nan) + ((= number sb-ext:double-float-positive-infinity) :inf) + ((= number sb-ext:double-float-negative-infinity) :-inf) + (number)))))) + '(values (or (member nil :nan :inf :-inf) float) &optional)))) + +(with-test (:name (:type-constraint-joining :infinities 2)) + (assert + (ctype= (caddr + (sb-kernel:%simple-fun-type + (checked-compile + `(lambda (number) + (declare (type (or number null) number)) + (cond ((null number) nil) + ((sb-ext:float-nan-p number) :nan) + ((= number sb-ext:double-float-positive-infinity) number) + ((= number sb-ext:double-float-negative-infinity) number) + (t :number)))))) + `(values (or (single-float ,sb-ext:single-float-negative-infinity + ,sb-ext:single-float-negative-infinity) + (double-float ,sb-ext:double-float-negative-infinity + ,sb-ext:double-float-negative-infinity) + (single-float ,sb-ext:single-float-positive-infinity + ,sb-ext:single-float-positive-infinity) + (double-float ,sb-ext:double-float-positive-infinity + ,sb-ext:double-float-positive-infinity) + (member nil :nan :number)) + &optional)))) + +(with-test (:name (:type-constraint-joining :infinities 3)) + (assert + (ctype= (caddr + (sb-kernel:%simple-fun-type + (checked-compile + `(lambda (number) + (declare (type (or number null) number)) + (cond ((null number) nil) + ((sb-ext:float-nan-p number) :nan) + ((eql number sb-ext:double-float-positive-infinity) number) + ((eql number sb-ext:double-float-negative-infinity) number) + (t :number)))))) + `(values (or (double-float ,sb-ext:double-float-negative-infinity + ,sb-ext:double-float-negative-infinity) + (double-float ,sb-ext:double-float-positive-infinity + ,sb-ext:double-float-positive-infinity) + (member nil :nan :number)) + &optional)))) diff --git a/tests/ctor.impure.lisp b/tests/ctor.impure.lisp index 558cbf5e70..4e377a4910 100644 --- a/tests/ctor.impure.lisp +++ b/tests/ctor.impure.lisp @@ -135,7 +135,7 @@ (with-test (:name (make-instance :ctor-inline-cache-resize)) (let* ((f (checked-compile `(lambda (name) (make-instance name)))) - (classes (loop repeat (* 2 sb-pcl::+ctor-table-max-size+) + (classes (loop repeat (* 2 sb-pcl:+ctor-table-max-size+) collect (class-name (eval `(defclass ,(gentemp) () ()))))) (count 0) (caches (find-ctor-caches f)) @@ -146,7 +146,7 @@ (dolist (class classes) (assert (typep (funcall f (if (oddp count) class (find-class class))) class)) (incf count) - (cond ((<= count sb-pcl::+ctor-list-max-size+) + (cond ((<= count sb-pcl:+ctor-list-max-size+) (unless (consp (cdr cache)) (error "oops, wanted list cache, got: ~S" cache)) (unless (= count (length (cdr cache))) diff --git a/tests/data/CollationTest_SHIFTED_SHORT.txt b/tests/data/CollationTest_SHIFTED_SHORT.txt index 1218f220d4..2aff0cfdef 100644 --- a/tests/data/CollationTest_SHIFTED_SHORT.txt +++ b/tests/data/CollationTest_SHIFTED_SHORT.txt @@ -1,7 +1,10 @@ -# File: CollationTest_SHIFTED_SHORT.txt -# UCA Version: 8.0.0 -# UCD Version: 8.0.0 -# Generated: 2015-05-14 [MS] +# CollationTest_SHIFTED_SHORT.txt +# Date: 2017-06-05, 23:16:56 GMT +# © 2017 Unicode®, Inc. +# Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries. +# For terms of use, see http://www.unicode.org/terms_of_use.html +# UCA Version: 10.0.0 +# UCD Version: 10.0.0 # For a description of the format and usage, see CollationTest.html 0009 0021 @@ -120,6 +123,8 @@ FE58 003F 2E3B 003F 2053 0021 2053 003F +2E43 0021 +2E43 003F 2E17 0021 2E17 003F 2E40 0021 @@ -200,6 +205,8 @@ FF1B 003F 2E35 003F A6F6 0021 A6F6 003F +2E49 0021 +2E49 003F 2A74 0021 2A74 003F 003A 0021 @@ -431,6 +438,21 @@ A6F4 003F 0749 0021 074A 0021 07FA 0021 +08D4 0021 +08D5 0021 +08D6 0021 +08D7 0021 +08D8 0021 +08D9 0021 +08DA 0021 +08DB 0021 +08DC 0021 +08DD 0021 +08DE 0021 +08DF 0021 +08E0 0021 +08E1 0021 +08E2 0021 08EA 0021 08EB 0021 08EC 0021 @@ -495,6 +517,7 @@ A6F4 003F 1CE7 0021 1CE8 0021 1CF4 0021 +1CF7 0021 1CF8 0021 1CF9 0021 200B 0021 @@ -1126,6 +1149,9 @@ FF01 003F 07F9 003F 1944 0021 1944 003F +1E95E 0334 +1E95E 0021 +1E95E 003F 0000 003F 0001 003F 0002 003F @@ -1271,6 +1297,21 @@ FF01 003F 0749 003F 074A 003F 07FA 003F +08D4 003F +08D5 003F +08D6 003F +08D7 003F +08D8 003F +08D9 003F +08DA 003F +08DB 003F +08DC 003F +08DD 003F +08DE 003F +08DF 003F +08E0 003F +08E1 003F +08E2 003F 08EA 003F 08EB 003F 08EC 003F @@ -1335,6 +1376,7 @@ FF01 003F 1CE7 003F 1CE8 003F 1CF4 003F +1CF7 003F 1CF8 003F 1CF9 003F 200B 003F @@ -1985,6 +2027,9 @@ AAF1 003F 11143 0334 11143 0021 11143 003F +1E95F 0334 +1E95F 0021 +1E95F 003F 203D 0021 203D 003F 2E18 0021 @@ -2149,6 +2194,12 @@ ABEB 003F 11239 0334 11239 0021 11239 003F +1144B 0334 +1144B 0021 +1144B 003F +1144C 0334 +1144C 0021 +1144C 003F 115C2 0334 115C2 0021 115C2 003F @@ -2167,6 +2218,12 @@ ABEB 003F 1173D 0334 1173D 0021 1173D 003F +11C41 0334 +11C41 0021 +11C41 003F +11C42 0334 +11C42 0021 +11C42 003F 16A6E 0334 16A6E 0021 16A6E 003F @@ -2850,6 +2907,16 @@ FF05 003F 2E1E 003F 2E1F 0021 2E1F 003F +2E44 0021 +2E44 003F +2E45 0021 +2E45 003F +2E46 0021 +2E46 003F +2E47 0021 +2E47 003F +2E48 0021 +2E48 003F A67E 0021 A67E 003F 055A 0021 @@ -2882,6 +2949,45 @@ A67E 003F 085E 003F 1800 0021 1800 003F +11660 0334 +11660 0021 +11660 003F +11661 0334 +11661 0021 +11661 003F +11662 0334 +11662 0021 +11662 003F +11663 0334 +11663 0021 +11663 003F +11664 0334 +11664 0021 +11664 003F +11665 0334 +11665 0021 +11665 003F +11666 0334 +11666 0021 +11666 003F +11667 0334 +11667 0021 +11667 003F +11668 0334 +11668 0021 +11668 003F +11669 0334 +11669 0021 +11669 003F +1166A 0334 +1166A 0021 +1166A 003F +1166B 0334 +1166B 0021 +1166B 003F +1166C 0334 +1166C 0021 +1166C 003F 0970 0021 0970 003F A8F8 0021 @@ -2892,6 +2998,8 @@ A8FA 0021 A8FA 003F A8FC 0021 A8FC 003F +09FD 0021 +09FD 003F 0AF0 0021 0AF0 003F 0DF4 0021 @@ -2952,6 +3060,60 @@ AADF 003F 0FD9 003F 0FDA 0021 0FDA 003F +11A3F 0334 +11A3F 0021 +11A3F 003F +11A40 0334 +11A40 0021 +11A40 003F +11A41 0334 +11A41 0021 +11A41 003F +11A42 0334 +11A42 0021 +11A42 003F +11A43 0334 +11A43 0021 +11A43 003F +11A44 0334 +11A44 0021 +11A44 003F +11A45 0334 +11A45 0021 +11A45 003F +11A46 0334 +11A46 0021 +11A46 003F +11A9A 0334 +11A9A 0021 +11A9A 003F +11A9B 0334 +11A9B 0021 +11A9B 003F +11A9C 0334 +11A9C 0021 +11A9C 003F +11A9E 0334 +11A9E 0021 +11A9E 003F +11A9F 0334 +11A9F 0021 +11A9F 003F +11AA0 0334 +11AA0 0021 +11AA0 003F +11AA1 0334 +11AA1 0021 +11AA1 003F +11AA2 0334 +11AA2 0021 +11AA2 003F +11C70 0334 +11C70 0021 +11C70 003F +11C71 0334 +11C71 0021 +11C71 003F 1C3D 0021 1C3D 003F 1C3E 0021 @@ -3069,6 +3231,15 @@ AA5C 003F 10A58 0334 10A58 0021 10A58 003F +11C43 0334 +11C43 0021 +11C43 003F +11C44 0334 +11C44 0021 +11C44 003F +11C45 0334 +11C45 0021 +11C45 003F 10B39 0334 10B39 0021 10B39 003F @@ -3144,6 +3315,21 @@ AA5C 003F 1123D 0334 1123D 0021 1123D 003F +1144D 0334 +1144D 0021 +1144D 003F +1144E 0334 +1144E 0021 +1144E 003F +1144F 0334 +1144F 0021 +1144F 003F +1145B 0334 +1145B 0021 +1145B 003F +1145D 0334 +1145D 0021 +1145D 003F 114C6 0334 114C6 0021 114C6 003F @@ -3273,12 +3459,12 @@ FFE3 003F 02D9 0021 02D9 003F 00A8 0300 0334 +00A8 0334 0300 00A8 0334 0340 -00A8 0340 0334 1FED 0334 00A8 0301 0334 +00A8 0334 0301 00A8 0334 0341 -00A8 0341 0334 1FEE 0334 00A8 0334 0342 00A8 0342 0334 @@ -3301,13 +3487,13 @@ FFE3 003F 00B8 003F 02DB 0021 02DB 003F +1FBF 0300 0334 1FBF 0334 0300 -1FBF 0334 0340 1FBF 0340 0334 1FCD 0334 1FBF 0301 0334 1FBF 0334 0301 -1FBF 0334 0341 +1FBF 0341 0334 1FCE 0334 1FBF 0334 0342 1FBF 0342 0334 @@ -3323,13 +3509,13 @@ FFE3 003F 1FCE 003F 1FCF 003F 1FDD 0334 +1FFE 0300 0334 1FFE 0334 0300 1FFE 0334 0340 -1FFE 0340 0334 1FDE 0334 1FFE 0301 0334 +1FFE 0334 0301 1FFE 0334 0341 -1FFE 0341 0334 1FDF 0334 1FFE 0334 0342 1FFE 0342 0334 @@ -3627,6 +3813,8 @@ FBC1 003F 0BFA 003F 0C7F 0021 0C7F 003F +0D4F 0021 +0D4F 003F 0D79 0021 0D79 003F A828 0021 @@ -5312,6 +5500,16 @@ FF5E 003F 23F9 003F 23FA 0021 23FA 003F +23FB 0021 +23FB 003F +23FC 0021 +23FC 003F +23FD 0021 +23FD 003F +23FE 0021 +23FE 003F +23FF 0021 +23FF 003F 2400 0021 2400 003F 2401 0021 @@ -8252,6 +8450,8 @@ FFEE 003F 2BD0 003F 2BD1 0021 2BD1 003F +2BD2 0021 +2BD2 003F 2BEC 0021 2BEC 003F 2BED 0021 @@ -9392,6 +9592,12 @@ A4C6 003F 1018C 0334 1018C 0021 1018C 003F +1018D 0334 +1018D 0021 +1018D 003F +1018E 0334 +1018E 0021 +1018E 003F 10190 0334 10190 0021 10190 003F @@ -10600,24 +10806,24 @@ A4C6 003F 1D15F 0334 1D158 0334 1D165 1D16E 1D158 1D165 0334 1D16E -1D158 1D165 1D16E 0334 +1D15F 0334 1D16E 1D15F 1D16E 0334 1D160 0334 1D158 1D165 0334 1D16F -1D158 1D165 1D16F 0334 +1D15F 0334 1D16F 1D15F 1D16F 0334 1D161 0334 -1D158 0334 1D165 1D170 1D158 1D165 0334 1D170 +1D158 1D165 1D170 0334 1D15F 1D170 0334 1D162 0334 -1D158 0334 1D165 1D171 1D158 1D165 0334 1D171 -1D15F 0334 1D171 +1D158 1D165 1D171 0334 +1D15F 1D171 0334 1D163 0334 -1D158 0334 1D165 1D172 1D158 1D165 0334 1D172 -1D15F 0334 1D172 +1D158 1D165 1D172 0334 +1D15F 1D172 0334 1D164 0334 1D158 0021 1D15F 0021 @@ -10791,12 +10997,13 @@ A4C6 003F 1D1B9 1D165 0334 1D1BB 0334 1D1B9 0334 1D165 1D16E -1D1B9 1D165 0334 1D16E +1D1B9 1D165 1D16E 0334 1D1BB 0334 1D16E +1D1BB 1D16E 0334 1D1BD 0334 1D1B9 0334 1D165 1D16F 1D1B9 1D165 0334 1D16F -1D1BB 0334 1D16F +1D1B9 1D165 1D16F 0334 1D1BB 1D16F 0334 1D1BF 0334 1D1B9 0021 @@ -10811,14 +11018,15 @@ A4C6 003F 1D1BA 0334 1D165 1D1BA 1D165 0334 1D1BC 0334 +1D1BA 1D165 0334 1D16E 1D1BA 1D165 1D16E 0334 1D1BC 0334 1D16E 1D1BC 1D16E 0334 1D1BE 0334 1D1BA 0334 1D165 1D16F -1D1BA 1D165 0334 1D16F 1D1BA 1D165 1D16F 0334 1D1BC 0334 1D16F +1D1BC 1D16F 0334 1D1C0 0334 1D1BA 0021 1D1BC 0021 @@ -11830,6 +12038,24 @@ A4C6 003F 1F0F5 0334 1F0F5 0021 1F0F5 003F +1F260 0334 +1F260 0021 +1F260 003F +1F261 0334 +1F261 0021 +1F261 003F +1F262 0334 +1F262 0021 +1F262 003F +1F263 0334 +1F263 0021 +1F263 003F +1F264 0334 +1F264 0021 +1F264 003F +1F265 0334 +1F265 0021 +1F265 003F 1F300 0334 1F300 0021 1F300 003F @@ -13732,6 +13958,9 @@ A4C6 003F 1F579 0334 1F579 0021 1F579 003F +1F57A 0334 +1F57A 0021 +1F57A 003F 1F57B 0334 1F57B 0021 1F57B 003F @@ -13855,6 +14084,9 @@ A4C6 003F 1F5A3 0334 1F5A3 0021 1F5A3 003F +1F5A4 0334 +1F5A4 0021 +1F5A4 003F 1F5A5 0334 1F5A5 0021 1F5A5 003F @@ -14128,6 +14360,42 @@ A4C6 003F 1F5FF 0334 1F5FF 0021 1F5FF 003F +1F900 0334 +1F900 0021 +1F900 003F +1F901 0334 +1F901 0021 +1F901 003F +1F902 0334 +1F902 0021 +1F902 003F +1F903 0334 +1F903 0021 +1F903 003F +1F904 0334 +1F904 0021 +1F904 003F +1F905 0334 +1F905 0021 +1F905 003F +1F906 0334 +1F906 0021 +1F906 003F +1F907 0334 +1F907 0021 +1F907 003F +1F908 0334 +1F908 0021 +1F908 003F +1F909 0334 +1F909 0021 +1F909 003F +1F90A 0334 +1F90A 0021 +1F90A 003F +1F90B 0334 +1F90B 0021 +1F90B 003F 1F910 0334 1F910 0021 1F910 003F @@ -14155,6 +14423,243 @@ A4C6 003F 1F918 0334 1F918 0021 1F918 003F +1F919 0334 +1F919 0021 +1F919 003F +1F91A 0334 +1F91A 0021 +1F91A 003F +1F91B 0334 +1F91B 0021 +1F91B 003F +1F91C 0334 +1F91C 0021 +1F91C 003F +1F91D 0334 +1F91D 0021 +1F91D 003F +1F91E 0334 +1F91E 0021 +1F91E 003F +1F91F 0334 +1F91F 0021 +1F91F 003F +1F920 0334 +1F920 0021 +1F920 003F +1F921 0334 +1F921 0021 +1F921 003F +1F922 0334 +1F922 0021 +1F922 003F +1F923 0334 +1F923 0021 +1F923 003F +1F924 0334 +1F924 0021 +1F924 003F +1F925 0334 +1F925 0021 +1F925 003F +1F926 0334 +1F926 0021 +1F926 003F +1F927 0334 +1F927 0021 +1F927 003F +1F928 0334 +1F928 0021 +1F928 003F +1F929 0334 +1F929 0021 +1F929 003F +1F92A 0334 +1F92A 0021 +1F92A 003F +1F92B 0334 +1F92B 0021 +1F92B 003F +1F92C 0334 +1F92C 0021 +1F92C 003F +1F92D 0334 +1F92D 0021 +1F92D 003F +1F92E 0334 +1F92E 0021 +1F92E 003F +1F92F 0334 +1F92F 0021 +1F92F 003F +1F930 0334 +1F930 0021 +1F930 003F +1F931 0334 +1F931 0021 +1F931 003F +1F932 0334 +1F932 0021 +1F932 003F +1F933 0334 +1F933 0021 +1F933 003F +1F934 0334 +1F934 0021 +1F934 003F +1F935 0334 +1F935 0021 +1F935 003F +1F936 0334 +1F936 0021 +1F936 003F +1F937 0334 +1F937 0021 +1F937 003F +1F938 0334 +1F938 0021 +1F938 003F +1F939 0334 +1F939 0021 +1F939 003F +1F93A 0334 +1F93A 0021 +1F93A 003F +1F93B 0334 +1F93B 0021 +1F93B 003F +1F93C 0334 +1F93C 0021 +1F93C 003F +1F93D 0334 +1F93D 0021 +1F93D 003F +1F93E 0334 +1F93E 0021 +1F93E 003F +1F940 0334 +1F940 0021 +1F940 003F +1F941 0334 +1F941 0021 +1F941 003F +1F942 0334 +1F942 0021 +1F942 003F +1F943 0334 +1F943 0021 +1F943 003F +1F944 0334 +1F944 0021 +1F944 003F +1F945 0334 +1F945 0021 +1F945 003F +1F946 0334 +1F946 0021 +1F946 003F +1F947 0334 +1F947 0021 +1F947 003F +1F948 0334 +1F948 0021 +1F948 003F +1F949 0334 +1F949 0021 +1F949 003F +1F94A 0334 +1F94A 0021 +1F94A 003F +1F94B 0334 +1F94B 0021 +1F94B 003F +1F94C 0334 +1F94C 0021 +1F94C 003F +1F950 0334 +1F950 0021 +1F950 003F +1F951 0334 +1F951 0021 +1F951 003F +1F952 0334 +1F952 0021 +1F952 003F +1F953 0334 +1F953 0021 +1F953 003F +1F954 0334 +1F954 0021 +1F954 003F +1F955 0334 +1F955 0021 +1F955 003F +1F956 0334 +1F956 0021 +1F956 003F +1F957 0334 +1F957 0021 +1F957 003F +1F958 0334 +1F958 0021 +1F958 003F +1F959 0334 +1F959 0021 +1F959 003F +1F95A 0334 +1F95A 0021 +1F95A 003F +1F95B 0334 +1F95B 0021 +1F95B 003F +1F95C 0334 +1F95C 0021 +1F95C 003F +1F95D 0334 +1F95D 0021 +1F95D 003F +1F95E 0334 +1F95E 0021 +1F95E 003F +1F95F 0334 +1F95F 0021 +1F95F 003F +1F960 0334 +1F960 0021 +1F960 003F +1F961 0334 +1F961 0021 +1F961 003F +1F962 0334 +1F962 0021 +1F962 003F +1F963 0334 +1F963 0021 +1F963 003F +1F964 0334 +1F964 0021 +1F964 003F +1F965 0334 +1F965 0021 +1F965 003F +1F966 0334 +1F966 0021 +1F966 003F +1F967 0334 +1F967 0021 +1F967 003F +1F968 0334 +1F968 0021 +1F968 003F +1F969 0334 +1F969 0021 +1F969 003F +1F96A 0334 +1F96A 0021 +1F96A 003F +1F96B 0334 +1F96B 0021 +1F96B 003F 1F980 0334 1F980 0021 1F980 003F @@ -14170,9 +14675,135 @@ A4C6 003F 1F984 0334 1F984 0021 1F984 003F +1F985 0334 +1F985 0021 +1F985 003F +1F986 0334 +1F986 0021 +1F986 003F +1F987 0334 +1F987 0021 +1F987 003F +1F988 0334 +1F988 0021 +1F988 003F +1F989 0334 +1F989 0021 +1F989 003F +1F98A 0334 +1F98A 0021 +1F98A 003F +1F98B 0334 +1F98B 0021 +1F98B 003F +1F98C 0334 +1F98C 0021 +1F98C 003F +1F98D 0334 +1F98D 0021 +1F98D 003F +1F98E 0334 +1F98E 0021 +1F98E 003F +1F98F 0334 +1F98F 0021 +1F98F 003F +1F990 0334 +1F990 0021 +1F990 003F +1F991 0334 +1F991 0021 +1F991 003F +1F992 0334 +1F992 0021 +1F992 003F +1F993 0334 +1F993 0021 +1F993 003F +1F994 0334 +1F994 0021 +1F994 003F +1F995 0334 +1F995 0021 +1F995 003F +1F996 0334 +1F996 0021 +1F996 003F +1F997 0334 +1F997 0021 +1F997 003F 1F9C0 0334 1F9C0 0021 1F9C0 003F +1F9D0 0334 +1F9D0 0021 +1F9D0 003F +1F9D1 0334 +1F9D1 0021 +1F9D1 003F +1F9D2 0334 +1F9D2 0021 +1F9D2 003F +1F9D3 0334 +1F9D3 0021 +1F9D3 003F +1F9D4 0334 +1F9D4 0021 +1F9D4 003F +1F9D5 0334 +1F9D5 0021 +1F9D5 003F +1F9D6 0334 +1F9D6 0021 +1F9D6 003F +1F9D7 0334 +1F9D7 0021 +1F9D7 003F +1F9D8 0334 +1F9D8 0021 +1F9D8 003F +1F9D9 0334 +1F9D9 0021 +1F9D9 003F +1F9DA 0334 +1F9DA 0021 +1F9DA 003F +1F9DB 0334 +1F9DB 0021 +1F9DB 003F +1F9DC 0334 +1F9DC 0021 +1F9DC 003F +1F9DD 0334 +1F9DD 0021 +1F9DD 003F +1F9DE 0334 +1F9DE 0021 +1F9DE 003F +1F9DF 0334 +1F9DF 0021 +1F9DF 003F +1F9E0 0334 +1F9E0 0021 +1F9E0 003F +1F9E1 0334 +1F9E1 0021 +1F9E1 003F +1F9E2 0334 +1F9E2 0021 +1F9E2 003F +1F9E3 0334 +1F9E3 0021 +1F9E3 003F +1F9E4 0334 +1F9E4 0021 +1F9E4 003F +1F9E5 0334 +1F9E5 0021 +1F9E5 003F +1F9E6 0334 +1F9E6 0021 +1F9E6 003F 1F600 0334 1F600 0021 1F600 003F @@ -14800,6 +15431,18 @@ A4C6 003F 1F6D0 0334 1F6D0 0021 1F6D0 003F +1F6D1 0334 +1F6D1 0021 +1F6D1 003F +1F6D2 0334 +1F6D2 0021 +1F6D2 003F +1F6D3 0334 +1F6D3 0021 +1F6D3 003F +1F6D4 0334 +1F6D4 0021 +1F6D4 003F 1F6E0 0334 1F6E0 0021 1F6E0 003F @@ -14851,6 +15494,21 @@ A4C6 003F 1F6F3 0334 1F6F3 0021 1F6F3 003F +1F6F4 0334 +1F6F4 0021 +1F6F4 003F +1F6F5 0334 +1F6F5 0021 +1F6F5 003F +1F6F6 0334 +1F6F6 0021 +1F6F6 003F +1F6F7 0334 +1F6F7 0021 +1F6F7 003F +1F6F8 0334 +1F6F8 0021 +1F6F8 003F 1F700 0334 1F700 0021 1F700 003F @@ -17680,6 +18338,20 @@ A835 003F 0BF1 003F 0BF2 0021 0BF2 003F +0D58 0021 +0D58 003F +0D59 0021 +0D59 003F +0D5A 0021 +0D5A 003F +0D5B 0021 +0D5B 003F +0D5C 0021 +0D5C 003F +0D5D 0021 +0D5D 003F +0D5E 0021 +0D5E 003F 0D70 0021 0D70 003F 0D71 0021 @@ -17692,6 +18364,12 @@ A835 003F 0D74 003F 0D75 0021 0D75 003F +0D76 0021 +0D76 003F +0D77 0021 +0D77 003F +0D78 0021 +0D78 003F 1372 0021 1372 003F 1373 0021 @@ -18271,6 +18949,36 @@ A835 003F 10A47 0334 10A47 0021 10A47 003F +11C63 0334 +11C63 0021 +11C63 003F +11C64 0334 +11C64 0021 +11C64 003F +11C65 0334 +11C65 0021 +11C65 003F +11C66 0334 +11C66 0021 +11C66 003F +11C67 0334 +11C67 0021 +11C67 003F +11C68 0334 +11C68 0021 +11C68 003F +11C69 0334 +11C69 0021 +11C69 003F +11C6A 0334 +11C6A 0021 +11C6A 003F +11C6B 0334 +11C6B 0021 +11C6B 003F +11C6C 0334 +11C6C 0021 +11C6C 003F 111EA 0334 111EA 0021 111EA 003F @@ -18705,6 +19413,10 @@ A835 003F 1DCE 0021 1DD1 0021 1DF5 0021 +1DF6 0021 +1DF7 0021 +1DF8 0021 +1DFB 0021 1DFE 0021 20F0 0021 2CEF 0021 @@ -18765,6 +19477,10 @@ A67D 0021 1DCE 003F 1DD1 003F 1DF5 003F +1DF6 003F +1DF7 003F +1DF8 003F +1DFB 003F 1DFE 003F 20F0 003F 2CEF 003F @@ -18820,6 +19536,7 @@ A67D 003F 1DC2 0021 1DCF 0021 1DD0 0021 +1DF9 0021 1DFC 0021 1DFD 0021 1DFF 0021 @@ -18877,6 +19594,7 @@ FE27 0021 1DC2 003F 1DCF 003F 1DD0 003F +1DF9 003F 1DFC 003F 1DFD 003F 1DFF 003F @@ -19115,6 +19833,34 @@ FF9F 003F 0749 0334 0334 074A 074A 0334 +0334 08D4 +08D4 0334 +0334 08D5 +08D5 0334 +0334 08D6 +08D6 0334 +0334 08D7 +08D7 0334 +0334 08D8 +08D8 0334 +0334 08D9 +08D9 0334 +0334 08DA +08DA 0334 +0334 08DB +08DB 0334 +0334 08DC +08DC 0334 +0334 08DD +08DD 0334 +0334 08DE +08DE 0334 +0334 08DF +08DF 0334 +0334 08E0 +08E0 0334 +0334 08E1 +08E1 0334 0334 08EA 08EA 0334 0334 08EB @@ -19265,6 +20011,7 @@ FE2B 0334 FE2C 0334 0334 FE2D FE2D 0334 +0334 FE2F FE2F 0334 0334 102E0 102E0 0334 @@ -19896,8 +20643,8 @@ E01EF 0334 0342 0334 0308 0334 0334 0308 -0308 0334 0301 -0308 0334 0341 +0308 0301 0334 +0308 0341 0334 0334 0344 0344 0334 030B 0334 @@ -20004,6 +20751,14 @@ E01EF 0334 1DD1 0334 0334 1DF5 1DF5 0334 +0334 1DF6 +1DF6 0334 +0334 1DF7 +1DF7 0334 +0334 1DF8 +1DF8 0334 +0334 1DFB +1DFB 0334 0334 1DFE 1DFE 0334 0334 20F0 @@ -20110,6 +20865,8 @@ A67D 0334 1DCF 0334 0334 1DD0 1DD0 0334 +0334 1DF9 +1DF9 0334 0334 1DFC 1DFC 0334 0334 1DFD @@ -20185,6 +20942,7 @@ FE29 0334 FE20 0334 0334 0483 0483 0334 +0334 FE2E FE2E 0334 0334 A66F A66F 0334 @@ -20330,6 +21088,7 @@ FB1E 0334 065D 0334 0334 065E 065E 0334 +0334 08E3 08E3 0334 0334 08F7 08F7 0334 @@ -20409,6 +21168,20 @@ FB1E 0334 A6F0 0334 0334 A6F1 A6F1 0334 +0334 1E944 +1E944 0334 +0334 1E945 +1E945 0334 +0334 1E946 +1E946 0334 +0334 1E94A +1E94A 0334 +0334 1E947 +1E947 0334 +0334 1E948 +1E948 0334 +0334 1E949 +1E949 0334 0334 093C 093C 0334 0334 09BC @@ -20433,6 +21206,7 @@ A9B3 0334 110BA 0334 0334 11173 11173 0334 +0334 111CA 111CA 0334 0334 11236 11236 0334 @@ -20440,12 +21214,16 @@ A9B3 0334 112E9 0334 0334 1133C 1133C 0334 +0334 11446 +11446 0334 0334 114C3 114C3 0334 0334 115C0 115C0 0334 0334 116B7 116B7 0334 +0334 11D42 +11D42 0334 0334 11100 11100 0334 0334 1CED @@ -20737,8 +21515,10 @@ FC62 003F 08F6 0021 08F6 003F 0651 0021 +0AFB 0021 11237 0021 0651 003F +0AFB 003F 11237 003F FE7D 0021 FE7D 003F @@ -20748,13 +21528,20 @@ FE7C 003F FC63 0021 FC63 003F 0652 0021 +0AFA 0021 +1123E 0021 0652 003F +0AFA 003F +1123E 003F FE7F 0021 FE7F 003F FE7E 0021 FE7E 003F +1123E 0334 0653 0021 +0AFC 0021 0653 003F +0AFC 003F 0654 0021 0654 003F 0655 0021 @@ -20876,10 +21663,27 @@ A6F1 003F 16AF4 0021 16AF4 003F 16AF4 0334 +1E944 0021 +1E945 0021 +1E946 0021 +1E944 003F +1E945 003F +1E946 003F +1E94A 0021 +1E94A 003F +1E947 0021 +1E947 003F +1E948 0021 +1E948 003F +1E949 0021 +1E949 003F 093C 0021 09BC 0021 0A3C 0021 0ABC 0021 +0AFD 0021 +0AFE 0021 +0AFF 0021 0B3C 0021 0CBC 0021 1B34 0021 @@ -20892,13 +21696,19 @@ A9B3 0021 11236 0021 112E9 0021 1133C 0021 +11446 0021 114C3 0021 115C0 0021 116B7 0021 +11A33 0021 +11D42 0021 093C 003F 09BC 003F 0A3C 003F 0ABC 003F +0AFD 003F +0AFE 003F +0AFF 003F 0B3C 003F 0CBC 003F 1B34 003F @@ -20911,9 +21721,13 @@ A9B3 003F 11236 003F 112E9 003F 1133C 003F +11446 003F 114C3 003F 115C0 003F 116B7 003F +11A33 003F +11D42 003F +11A33 0334 0900 0021 0901 0021 0981 0021 @@ -20926,15 +21740,23 @@ A9B3 003F 0D01 0021 1B00 0021 1B01 0021 +A8C5 0021 A980 0021 11000 0021 11080 0021 11100 0021 11180 0021 11301 0021 +11443 0021 114BF 0021 115BC 0021 11640 0021 +11A35 0021 +11A36 0021 +11A37 0021 +11C3C 0021 +11CB6 0021 +11D43 0021 0900 003F 0901 003F 0981 003F @@ -20947,22 +21769,37 @@ A980 0021 0D01 003F 1B00 003F 1B01 003F +A8C5 003F A980 003F 11000 003F 11080 003F 11100 003F 11180 003F 11301 003F +11443 003F 114BF 003F 115BC 003F 11640 003F +11A35 003F +11A36 003F +11A37 003F +11C3C 003F +11CB6 003F +11D43 003F 11000 0334 11080 0334 11180 0334 11301 0334 +11443 0334 114BF 0334 115BC 0334 11640 0334 +11A35 0334 +11A36 0334 +11A37 0334 +11C3C 0334 +11CB6 0334 +11D43 0334 0902 0021 0982 0021 0A02 0021 @@ -20971,6 +21808,7 @@ A980 003F 0B82 0021 0C02 0021 0C82 0021 +0D00 0021 0D02 0021 0D82 0021 0F7E 0021 @@ -20992,10 +21830,16 @@ A981 0021 112DF 0021 11300 0021 11302 0021 +11444 0021 114C0 0021 115BD 0021 1163D 0021 116AB 0021 +11A38 0021 +11A96 0021 +11C3D 0021 +11CB5 0021 +11D40 0021 0902 003F 0982 003F 0A02 003F @@ -21004,6 +21848,7 @@ A981 0021 0B82 003F 0C02 003F 0C82 003F +0D00 003F 0D02 003F 0D82 003F 0F7E 003F @@ -21025,10 +21870,16 @@ A981 003F 112DF 003F 11300 003F 11302 003F +11444 003F 114C0 003F 115BD 003F 1163D 003F 116AB 003F +11A38 003F +11A96 003F +11C3D 003F +11CB5 003F +11D40 003F 10A0E 0334 11001 0334 11081 0334 @@ -21037,10 +21888,16 @@ A981 003F 112DF 0334 11300 0334 11302 0334 +11444 0334 114C0 0334 115BD 0334 1163D 0334 116AB 0334 +11A38 0334 +11A96 0334 +11C3D 0334 +11CB5 0334 +11D40 0334 0903 0021 0983 0021 0A03 0021 @@ -21065,10 +21922,15 @@ A983 0021 11102 0021 11182 0021 11303 0021 +11445 0021 114C1 0021 115BE 0021 1163E 0021 116AC 0021 +11A39 0021 +11A97 0021 +11C3E 0021 +11D41 0021 0903 003F 0983 003F 0A03 003F @@ -21093,18 +21955,28 @@ A983 003F 11102 003F 11182 003F 11303 003F +11445 003F 114C1 003F 115BE 003F 1163E 003F 116AC 003F +11A39 003F +11A97 003F +11C3E 003F +11D41 003F 11002 0334 11082 0334 11182 0334 11303 0334 +11445 0334 114C1 0334 115BE 0334 1163E 0334 116AC 0334 +11A39 0334 +11A97 0334 +11C3E 0334 +11D41 0334 0A70 0021 0A70 003F 0A71 0021 @@ -21130,6 +22002,9 @@ ABEC 003F 111CC 0021 111CC 003F 111CC 0334 +11A98 0021 +11A98 003F +11A98 0334 0E4E 0021 0E4E 003F 0E47 0021 @@ -21348,6 +22223,18 @@ AAF4 0062 303B 0061 303B 0041 303B 0062 +16FE0 0021 +16FE0 003F +16FE0 0334 +16FE0 0061 +16FE0 0041 +16FE0 0062 +16FE1 0021 +16FE1 003F +16FE1 0334 +16FE1 0061 +16FE1 0041 +16FE1 0062 3031 0021 3031 003F 3032 0021 @@ -21664,6 +22551,11 @@ FFE6 0062 20BE 0061 20BE 0041 20BE 0062 +20BF 0021 +20BF 003F +20BF 0061 +20BF 0041 +20BF 0062 0030 0021 0660 0021 06F0 0021 @@ -21710,13 +22602,17 @@ ABF0 0021 11136 0021 111D0 0021 112F0 0021 +11450 0021 114D0 0021 11650 0021 116C0 0021 11730 0021 118E0 0021 +11C50 0021 +11D50 0021 16A60 0021 16B50 0021 +1E950 0021 0030 003F 0660 003F 06F0 003F @@ -21763,13 +22659,17 @@ ABF0 003F 11136 003F 111D0 003F 112F0 003F +11450 003F 114D0 003F 11650 003F 116C0 003F 11730 003F 118E0 003F +11C50 003F +11D50 003F 16A60 003F 16B50 003F +1E950 003F FF10 0021 FF10 003F 1F101 0334 @@ -21809,13 +22709,17 @@ FF10 003F 11136 0334 111D0 0334 112F0 0334 +11450 0334 114D0 0334 11650 0334 116C0 0334 11730 0334 118E0 0334 +11C50 0334 +11D50 0334 16A60 0334 16B50 0334 +1E950 0334 1D7CE 0334 1D7D8 0334 1D7E2 0334 @@ -21874,13 +22778,17 @@ ABF0 0061 11136 0061 111D0 0061 112F0 0061 +11450 0061 114D0 0061 11650 0061 116C0 0061 11730 0061 118E0 0061 +11C50 0061 +11D50 0061 16A60 0061 16B50 0061 +1E950 0061 0030 0041 0660 0041 06F0 0041 @@ -21927,13 +22835,17 @@ ABF0 0041 11136 0041 111D0 0041 112F0 0041 +11450 0041 114D0 0041 11650 0041 116C0 0041 11730 0041 118E0 0041 +11C50 0041 +11D50 0041 16A60 0041 16B50 0041 +1E950 0041 FF10 0061 FF10 0041 1F101 0061 @@ -22010,13 +22922,17 @@ ABF0 0062 11136 0062 111D0 0062 112F0 0062 +11450 0062 114D0 0062 11650 0062 116C0 0062 11730 0062 118E0 0062 +11C50 0062 +11D50 0062 16A60 0062 16B50 0062 +1E950 0062 FF10 0062 1F101 0062 1F100 0062 @@ -22110,11 +23026,15 @@ ABF1 0021 111D1 0021 111E1 0021 112F1 0021 +11451 0021 114D1 0021 11651 0021 116C1 0021 11731 0021 118E1 0021 +11C51 0021 +11C5A 0021 +11D51 0021 12415 0021 1241E 0021 1242C 0021 @@ -22125,6 +23045,7 @@ ABF1 0021 16B51 0021 1D360 0021 1E8C7 0021 +1E951 0021 0031 003F 0661 003F 06F1 003F @@ -22198,11 +23119,15 @@ ABF1 003F 111D1 003F 111E1 003F 112F1 003F +11451 003F 114D1 003F 11651 003F 116C1 003F 11731 003F 118E1 003F +11C51 003F +11C5A 003F +11D51 003F 12415 003F 1241E 003F 1242C 003F @@ -22213,6 +23138,7 @@ ABF1 003F 16B51 003F 1D360 003F 1E8C7 003F +1E951 003F FF11 0021 FF11 003F 2474 0021 @@ -22281,11 +23207,15 @@ FF11 003F 111D1 0334 111E1 0334 112F1 0334 +11451 0334 114D1 0334 11651 0334 116C1 0334 11731 0334 118E1 0334 +11C51 0334 +11C5A 0334 +11D51 0334 12415 0334 1241E 0334 1242C 0334 @@ -22296,6 +23226,7 @@ FF11 003F 16B51 0334 1D360 0334 1E8C7 0334 +1E951 0334 1D7CF 0334 1D7D9 0334 1D7E3 0334 @@ -22406,6 +23337,12 @@ FF11 003F 24EC 003F 00BD 0021 00BD 003F +1F1A4 0021 +1F1A4 003F +1F1A4 0334 +1F1A4 0061 +1F1A4 0041 +1F1A4 0062 247F 0061 2493 0061 247F 0041 @@ -22754,11 +23691,15 @@ ABF1 0061 111D1 0061 111E1 0061 112F1 0061 +11451 0061 114D1 0061 11651 0061 116C1 0061 11731 0061 118E1 0061 +11C51 0061 +11C5A 0061 +11D51 0061 12415 0061 1241E 0061 1242C 0061 @@ -22769,6 +23710,7 @@ ABF1 0061 16B51 0061 1D360 0061 1E8C7 0061 +1E951 0061 0031 0041 0661 0041 06F1 0041 @@ -22842,11 +23784,15 @@ ABF1 0041 111D1 0041 111E1 0041 112F1 0041 +11451 0041 114D1 0041 11651 0041 116C1 0041 11731 0041 118E1 0041 +11C51 0041 +11C5A 0041 +11D51 0041 12415 0041 1241E 0041 1242C 0041 @@ -22857,6 +23803,7 @@ ABF1 0041 16B51 0041 1D360 0041 1E8C7 0041 +1E951 0041 FF11 0061 FF11 0041 2474 0061 @@ -22966,11 +23913,15 @@ ABF1 0062 111D1 0062 111E1 0062 112F1 0062 +11451 0062 114D1 0062 11651 0062 116C1 0062 11731 0062 118E1 0062 +11C51 0062 +11C5A 0062 +11D51 0062 12415 0062 1241E 0062 1242C 0062 @@ -22981,6 +23932,7 @@ ABF1 0062 16B51 0062 1D360 0062 1E8C7 0062 +1E951 0062 FF11 0062 2474 0062 1F102 0062 @@ -23080,11 +24032,15 @@ ABF2 0021 111D2 0021 111E2 0021 112F2 0021 +11452 0021 114D2 0021 11652 0021 116C2 0021 11732 0021 118E2 0021 +11C52 0021 +11C5B 0021 +11D52 0021 12400 0021 12416 0021 1241F 0021 @@ -23099,6 +24055,7 @@ ABF2 0021 16B52 0021 1D361 0021 1E8C8 0021 +1E952 0021 0032 003F 0662 003F 06F2 003F @@ -23165,11 +24122,15 @@ ABF2 003F 111D2 003F 111E2 003F 112F2 003F +11452 003F 114D2 003F 11652 003F 116C2 003F 11732 003F 118E2 003F +11C52 003F +11C5B 003F +11D52 003F 12400 003F 12416 003F 1241F 003F @@ -23184,6 +24145,7 @@ ABF2 003F 16B52 003F 1D361 003F 1E8C8 003F +1E952 003F FF12 0021 FF12 003F 2475 0021 @@ -23244,11 +24206,15 @@ FF12 003F 111D2 0334 111E2 0334 112F2 0334 +11452 0334 114D2 0334 11652 0334 116C2 0334 11732 0334 118E2 0334 +11C52 0334 +11C5B 0334 +11D52 0334 12400 0334 12416 0334 1241F 0334 @@ -23263,6 +24229,7 @@ FF12 003F 16B52 0334 1D361 0334 1E8C8 0334 +1E952 0334 1D7D0 0334 1D7DA 0334 1D7E4 0334 @@ -23320,6 +24287,12 @@ FF12 003F 336D 0062 3252 0021 3252 003F +1F1A2 0021 +1F1A2 003F +1F1A2 0334 +1F1A2 0061 +1F1A2 0041 +1F1A2 0062 3252 0061 3252 0041 3252 0062 @@ -23489,11 +24462,15 @@ ABF2 0061 111D2 0061 111E2 0061 112F2 0061 +11452 0061 114D2 0061 11652 0061 116C2 0061 11732 0061 118E2 0061 +11C52 0061 +11C5B 0061 +11D52 0061 12400 0061 12416 0061 1241F 0061 @@ -23508,6 +24485,7 @@ ABF2 0061 16B52 0061 1D361 0061 1E8C8 0061 +1E952 0061 0032 0041 0662 0041 06F2 0041 @@ -23574,11 +24552,15 @@ ABF2 0041 111D2 0041 111E2 0041 112F2 0041 +11452 0041 114D2 0041 11652 0041 116C2 0041 11732 0041 118E2 0041 +11C52 0041 +11C5B 0041 +11D52 0041 12400 0041 12416 0041 1241F 0041 @@ -23593,6 +24575,7 @@ ABF2 0041 16B52 0041 1D361 0041 1E8C8 0041 +1E952 0041 FF12 0061 FF12 0041 2475 0061 @@ -23693,11 +24676,15 @@ ABF2 0062 111D2 0062 111E2 0062 112F2 0062 +11452 0062 114D2 0062 11652 0062 116C2 0062 11732 0062 118E2 0062 +11C52 0062 +11C5B 0062 +11D52 0062 12400 0062 12416 0062 1241F 0062 @@ -23712,6 +24699,7 @@ ABF2 0062 16B52 0062 1D361 0062 1E8C8 0062 +1E952 0062 FF12 0062 2475 0062 1F103 0062 @@ -23729,6 +24717,18 @@ FF12 0062 278B 0062 00B2 0062 2082 0062 +1F19D 0021 +1F19D 003F +1F19D 0334 +1F19D 0061 +1F19D 0041 +1F19D 0062 +1F19C 0021 +1F19C 003F +1F19C 0334 +1F19C 0061 +1F19C 0041 +1F19C 0062 33E1 0021 33E1 003F 33E1 0061 @@ -23805,11 +24805,15 @@ ABF3 0021 111D3 0021 111E3 0021 112F3 0021 +11453 0021 114D3 0021 11653 0021 116C3 0021 11733 0021 118E3 0021 +11C53 0021 +11C5C 0021 +11D53 0021 12401 0021 12408 0021 12417 0021 @@ -23829,6 +24833,7 @@ ABF3 0021 16B53 0021 1D362 0021 1E8C9 0021 +1E953 0021 0033 003F 0663 003F 06F3 003F @@ -23890,11 +24895,15 @@ ABF3 003F 111D3 003F 111E3 003F 112F3 003F +11453 003F 114D3 003F 11653 003F 116C3 003F 11733 003F 118E3 003F +11C53 003F +11C5C 003F +11D53 003F 12401 003F 12408 003F 12417 003F @@ -23914,6 +24923,7 @@ ABF3 003F 16B53 003F 1D362 003F 1E8C9 003F +1E953 003F FF13 0021 FF13 003F 2476 0021 @@ -23969,11 +24979,15 @@ FF13 003F 111D3 0334 111E3 0334 112F3 0334 +11453 0334 114D3 0334 11653 0334 116C3 0334 11733 0334 118E3 0334 +11C53 0334 +11C5C 0334 +11D53 0334 12401 0334 12408 0334 12417 0334 @@ -23993,6 +25007,7 @@ FF13 003F 16B53 0334 1D362 0334 1E8C9 0334 +1E953 0334 1D7D1 0334 1D7DB 0334 1D7E5 0334 @@ -24139,11 +25154,15 @@ ABF3 0061 111D3 0061 111E3 0061 112F3 0061 +11453 0061 114D3 0061 11653 0061 116C3 0061 11733 0061 118E3 0061 +11C53 0061 +11C5C 0061 +11D53 0061 12401 0061 12408 0061 12417 0061 @@ -24163,6 +25182,7 @@ ABF3 0061 16B53 0061 1D362 0061 1E8C9 0061 +1E953 0061 0033 0041 0663 0041 06F3 0041 @@ -24224,11 +25244,15 @@ ABF3 0041 111D3 0041 111E3 0041 112F3 0041 +11453 0041 114D3 0041 11653 0041 116C3 0041 11733 0041 118E3 0041 +11C53 0041 +11C5C 0041 +11D53 0041 12401 0041 12408 0041 12417 0041 @@ -24248,6 +25272,7 @@ ABF3 0041 16B53 0041 1D362 0041 1E8C9 0041 +1E953 0041 FF13 0061 FF13 0041 2476 0061 @@ -24343,11 +25368,15 @@ ABF3 0062 111D3 0062 111E3 0062 112F3 0062 +11453 0062 114D3 0062 11653 0062 116C3 0062 11733 0062 118E3 0062 +11C53 0062 +11C5C 0062 +11D53 0062 12401 0062 12408 0062 12417 0062 @@ -24367,6 +25396,7 @@ ABF3 0062 16B53 0062 1D362 0062 1E8C9 0062 +1E953 0062 FF13 0062 2476 0062 1F104 0062 @@ -24384,6 +25414,12 @@ FF13 0062 278C 0062 00B3 0062 2083 0062 +1F19B 0021 +1F19B 003F +1F19B 0334 +1F19B 0061 +1F19B 0041 +1F19B 0062 33E2 0021 33E2 003F 33E2 0061 @@ -24457,11 +25493,15 @@ ABF4 0021 111D4 0021 111E4 0021 112F4 0021 +11454 0021 114D4 0021 11654 0021 116C4 0021 11734 0021 118E4 0021 +11C54 0021 +11C5D 0021 +11D54 0021 12402 0021 12409 0021 1240F 0021 @@ -24482,6 +25522,7 @@ ABF4 0021 16B54 0021 1D363 0021 1E8CA 0021 +1E954 0021 0034 003F 0664 003F 06F4 003F @@ -24540,11 +25581,15 @@ ABF4 003F 111D4 003F 111E4 003F 112F4 003F +11454 003F 114D4 003F 11654 003F 116C4 003F 11734 003F 118E4 003F +11C54 003F +11C5D 003F +11D54 003F 12402 003F 12409 003F 1240F 003F @@ -24565,6 +25610,7 @@ ABF4 003F 16B54 003F 1D363 003F 1E8CA 003F +1E954 003F FF14 0021 FF14 003F 2477 0021 @@ -24619,11 +25665,15 @@ FF14 003F 111D4 0334 111E4 0334 112F4 0334 +11454 0334 114D4 0334 11654 0334 116C4 0334 11734 0334 118E4 0334 +11C54 0334 +11C5D 0334 +11D54 0334 12402 0334 12409 0334 1240F 0334 @@ -24644,6 +25694,7 @@ FF14 003F 16B54 0334 1D363 0334 1E8CA 0334 +1E954 0334 1D7D2 0334 1D7DC 0334 1D7E6 0334 @@ -24767,11 +25818,15 @@ ABF4 0061 111D4 0061 111E4 0061 112F4 0061 +11454 0061 114D4 0061 11654 0061 116C4 0061 11734 0061 118E4 0061 +11C54 0061 +11C5D 0061 +11D54 0061 12402 0061 12409 0061 1240F 0061 @@ -24792,6 +25847,7 @@ ABF4 0061 16B54 0061 1D363 0061 1E8CA 0061 +1E954 0061 0034 0041 0664 0041 06F4 0041 @@ -24850,11 +25906,15 @@ ABF4 0041 111D4 0041 111E4 0041 112F4 0041 +11454 0041 114D4 0041 11654 0041 116C4 0041 11734 0041 118E4 0041 +11C54 0041 +11C5D 0041 +11D54 0041 12402 0041 12409 0041 1240F 0041 @@ -24875,6 +25935,7 @@ ABF4 0041 16B54 0041 1D363 0041 1E8CA 0041 +1E954 0041 FF14 0061 FF14 0041 2477 0061 @@ -24967,11 +26028,15 @@ ABF4 0062 111D4 0062 111E4 0062 112F4 0062 +11454 0062 114D4 0062 11654 0062 116C4 0062 11734 0062 118E4 0062 +11C54 0062 +11C5D 0062 +11D54 0062 12402 0062 12409 0062 1240F 0062 @@ -24992,6 +26057,7 @@ ABF4 0062 16B54 0062 1D363 0062 1E8CA 0062 +1E954 0062 FF14 0062 2477 0062 1F105 0062 @@ -25009,6 +26075,12 @@ FF14 0062 278D 0062 2074 0062 2084 0062 +1F19E 0021 +1F19E 003F +1F19E 0334 +1F19E 0061 +1F19E 0041 +1F19E 0062 33E3 0021 33E3 003F 33E3 0061 @@ -25086,11 +26158,15 @@ ABF5 0021 111D5 0021 111E5 0021 112F5 0021 +11455 0021 114D5 0021 11655 0021 116C5 0021 11735 0021 118E5 0021 +11C55 0021 +11C5E 0021 +11D55 0021 12403 0021 1240A 0021 12410 0021 @@ -25107,6 +26183,7 @@ ABF5 0021 16B55 0021 1D364 0021 1E8CB 0021 +1E955 0021 0035 003F 0665 003F 06F5 003F @@ -25169,11 +26246,15 @@ ABF5 003F 111D5 003F 111E5 003F 112F5 003F +11455 003F 114D5 003F 11655 003F 116C5 003F 11735 003F 118E5 003F +11C55 003F +11C5E 003F +11D55 003F 12403 003F 1240A 003F 12410 003F @@ -25190,6 +26271,7 @@ ABF5 003F 16B55 003F 1D364 003F 1E8CB 003F +1E955 003F FF15 0021 FF15 003F 2478 0021 @@ -25248,11 +26330,15 @@ FF15 003F 111D5 0334 111E5 0334 112F5 0334 +11455 0334 114D5 0334 11655 0334 116C5 0334 11735 0334 118E5 0334 +11C55 0334 +11C5E 0334 +11D55 0334 12403 0334 1240A 0334 12410 0334 @@ -25269,6 +26355,7 @@ FF15 003F 16B55 0334 1D364 0334 1E8CB 0334 +1E955 0334 1D7D3 0334 1D7DD 0334 1D7E7 0334 @@ -25284,6 +26371,12 @@ FF15 003F 32BF 0041 324C 0062 32BF 0062 +1F1A0 0021 +1F1A0 003F +1F1A0 0334 +1F1A0 0061 +1F1A0 0041 +1F1A0 0062 215A 0021 215A 003F 215A 0061 @@ -25356,11 +26449,15 @@ ABF5 0061 111D5 0061 111E5 0061 112F5 0061 +11455 0061 114D5 0061 11655 0061 116C5 0061 11735 0061 118E5 0061 +11C55 0061 +11C5E 0061 +11D55 0061 12403 0061 1240A 0061 12410 0061 @@ -25377,6 +26474,7 @@ ABF5 0061 16B55 0061 1D364 0061 1E8CB 0061 +1E955 0061 0035 0041 0665 0041 06F5 0041 @@ -25439,11 +26537,15 @@ ABF5 0041 111D5 0041 111E5 0041 112F5 0041 +11455 0041 114D5 0041 11655 0041 116C5 0041 11735 0041 118E5 0041 +11C55 0041 +11C5E 0041 +11D55 0041 12403 0041 1240A 0041 12410 0041 @@ -25460,6 +26562,7 @@ ABF5 0041 16B55 0041 1D364 0041 1E8CB 0041 +1E955 0041 FF15 0061 FF15 0041 2478 0061 @@ -25556,11 +26659,15 @@ ABF5 0062 111D5 0062 111E5 0062 112F5 0062 +11455 0062 114D5 0062 11655 0062 116C5 0062 11735 0062 118E5 0062 +11C55 0062 +11C5E 0062 +11D55 0062 12403 0062 1240A 0062 12410 0062 @@ -25577,6 +26684,7 @@ ABF5 0062 16B55 0062 1D364 0062 1E8CB 0062 +1E955 0062 FF15 0062 2478 0062 1F106 0062 @@ -25661,11 +26769,15 @@ ABF6 0021 111D6 0021 111E6 0021 112F6 0021 +11456 0021 114D6 0021 11656 0021 116C6 0021 11736 0021 118E6 0021 +11C56 0021 +11C5F 0021 +11D56 0021 12404 0021 1240B 0021 12411 0021 @@ -25678,6 +26790,7 @@ ABF6 0021 16B56 0021 1D365 0021 1E8CC 0021 +1E956 0021 0036 003F 0666 003F 06F6 003F @@ -25730,11 +26843,15 @@ ABF6 003F 111D6 003F 111E6 003F 112F6 003F +11456 003F 114D6 003F 11656 003F 116C6 003F 11736 003F 118E6 003F +11C56 003F +11C5F 003F +11D56 003F 12404 003F 1240B 003F 12411 003F @@ -25747,6 +26864,7 @@ ABF6 003F 16B56 003F 1D365 003F 1E8CC 003F +1E956 003F FF16 0021 FF16 003F 2479 0021 @@ -25794,11 +26912,15 @@ FF16 003F 111D6 0334 111E6 0334 112F6 0334 +11456 0334 114D6 0334 11656 0334 116C6 0334 11736 0334 118E6 0334 +11C56 0334 +11C5F 0334 +11D56 0334 12404 0334 1240B 0334 12411 0334 @@ -25811,6 +26933,7 @@ FF16 003F 16B56 0334 1D365 0334 1E8CC 0334 +1E956 0334 1D7D4 0334 1D7DE 0334 1D7E8 0334 @@ -25821,6 +26944,12 @@ FF16 003F 324D 0061 324D 0041 324D 0062 +1F1A3 0021 +1F1A3 003F +1F1A3 0334 +1F1A3 0061 +1F1A3 0041 +1F1A3 0062 0036 0061 0666 0061 06F6 0061 @@ -25873,11 +27002,15 @@ ABF6 0061 111D6 0061 111E6 0061 112F6 0061 +11456 0061 114D6 0061 11656 0061 116C6 0061 11736 0061 118E6 0061 +11C56 0061 +11C5F 0061 +11D56 0061 12404 0061 1240B 0061 12411 0061 @@ -25890,6 +27023,7 @@ ABF6 0061 16B56 0061 1D365 0061 1E8CC 0061 +1E956 0061 0036 0041 0666 0041 06F6 0041 @@ -25942,11 +27076,15 @@ ABF6 0041 111D6 0041 111E6 0041 112F6 0041 +11456 0041 114D6 0041 11656 0041 116C6 0041 11736 0041 118E6 0041 +11C56 0041 +11C5F 0041 +11D56 0041 12404 0041 1240B 0041 12411 0041 @@ -25959,6 +27097,7 @@ ABF6 0041 16B56 0041 1D365 0041 1E8CC 0041 +1E956 0041 FF16 0061 FF16 0041 2479 0061 @@ -26045,11 +27184,15 @@ ABF6 0062 111D6 0062 111E6 0062 112F6 0062 +11456 0062 114D6 0062 11656 0062 116C6 0062 11736 0062 118E6 0062 +11C56 0062 +11C5F 0062 +11D56 0062 12404 0062 1240B 0062 12411 0062 @@ -26062,6 +27205,7 @@ ABF6 0062 16B56 0062 1D365 0062 1E8CC 0062 +1E956 0062 FF16 0062 2479 0062 1F107 0062 @@ -26145,11 +27289,15 @@ ABF7 0021 111D7 0021 111E7 0021 112F7 0021 +11457 0021 114D7 0021 11657 0021 116C7 0021 11737 0021 118E7 0021 +11C57 0021 +11C60 0021 +11D57 0021 12405 0021 1240C 0021 12412 0021 @@ -26163,6 +27311,7 @@ ABF7 0021 16B57 0021 1D366 0021 1E8CD 0021 +1E957 0021 0037 003F 0667 003F 06F7 003F @@ -26214,11 +27363,15 @@ ABF7 003F 111D7 003F 111E7 003F 112F7 003F +11457 003F 114D7 003F 11657 003F 116C7 003F 11737 003F 118E7 003F +11C57 003F +11C60 003F +11D57 003F 12405 003F 1240C 003F 12412 003F @@ -26232,6 +27385,7 @@ ABF7 003F 16B57 003F 1D366 003F 1E8CD 003F +1E957 003F FF17 0021 FF17 003F 247A 0021 @@ -26279,11 +27433,15 @@ FF17 003F 111D7 0334 111E7 0334 112F7 0334 +11457 0334 114D7 0334 11657 0334 116C7 0334 11737 0334 118E7 0334 +11C57 0334 +11C60 0334 +11D57 0334 12405 0334 1240C 0334 12412 0334 @@ -26297,6 +27455,7 @@ FF17 003F 16B57 0334 1D366 0334 1E8CD 0334 +1E957 0334 1D7D5 0334 1D7DF 0334 1D7E9 0334 @@ -26307,6 +27466,12 @@ FF17 003F 324E 0061 324E 0041 324E 0062 +1F1A1 0021 +1F1A1 003F +1F1A1 0334 +1F1A1 0061 +1F1A1 0041 +1F1A1 0062 215E 0021 215E 003F 215E 0061 @@ -26363,11 +27528,15 @@ ABF7 0061 111D7 0061 111E7 0061 112F7 0061 +11457 0061 114D7 0061 11657 0061 116C7 0061 11737 0061 118E7 0061 +11C57 0061 +11C60 0061 +11D57 0061 12405 0061 1240C 0061 12412 0061 @@ -26381,6 +27550,7 @@ ABF7 0061 16B57 0061 1D366 0061 1E8CD 0061 +1E957 0061 0037 0041 0667 0041 06F7 0041 @@ -26432,11 +27602,15 @@ ABF7 0041 111D7 0041 111E7 0041 112F7 0041 +11457 0041 114D7 0041 11657 0041 116C7 0041 11737 0041 118E7 0041 +11C57 0041 +11C60 0041 +11D57 0041 12405 0041 1240C 0041 12412 0041 @@ -26450,6 +27624,7 @@ ABF7 0041 16B57 0041 1D366 0041 1E8CD 0041 +1E957 0041 FF17 0061 FF17 0041 247A 0061 @@ -26535,11 +27710,15 @@ ABF7 0062 111D7 0062 111E7 0062 112F7 0062 +11457 0062 114D7 0062 11657 0062 116C7 0062 11737 0062 118E7 0062 +11C57 0062 +11C60 0062 +11D57 0062 12405 0062 1240C 0062 12412 0062 @@ -26553,6 +27732,7 @@ ABF7 0062 16B57 0062 1D366 0062 1E8CD 0062 +1E957 0062 FF17 0062 247A 0062 1F108 0062 @@ -26636,11 +27816,15 @@ ABF8 0021 111D8 0021 111E8 0021 112F8 0021 +11458 0021 114D8 0021 11658 0021 116C8 0021 11738 0021 118E8 0021 +11C58 0021 +11C61 0021 +11D58 0021 12406 0021 1240D 0021 12413 0021 @@ -26653,6 +27837,7 @@ ABF8 0021 16B58 0021 1D367 0021 1E8CE 0021 +1E958 0021 0038 003F 0668 003F 06F8 003F @@ -26704,11 +27889,15 @@ ABF8 003F 111D8 003F 111E8 003F 112F8 003F +11458 003F 114D8 003F 11658 003F 116C8 003F 11738 003F 118E8 003F +11C58 003F +11C61 003F +11D58 003F 12406 003F 1240D 003F 12413 003F @@ -26721,6 +27910,7 @@ ABF8 003F 16B58 003F 1D367 003F 1E8CE 003F +1E958 003F FF18 0021 FF18 003F 247B 0021 @@ -26768,11 +27958,15 @@ FF18 003F 111D8 0334 111E8 0334 112F8 0334 +11458 0334 114D8 0334 11658 0334 116C8 0334 11738 0334 118E8 0334 +11C58 0334 +11C61 0334 +11D58 0334 12406 0334 1240D 0334 12413 0334 @@ -26785,6 +27979,7 @@ FF18 003F 16B58 0334 1D367 0334 1E8CE 0334 +1E958 0334 1D7D6 0334 1D7E0 0334 1D7EA 0334 @@ -26846,11 +28041,15 @@ ABF8 0061 111D8 0061 111E8 0061 112F8 0061 +11458 0061 114D8 0061 11658 0061 116C8 0061 11738 0061 118E8 0061 +11C58 0061 +11C61 0061 +11D58 0061 12406 0061 1240D 0061 12413 0061 @@ -26863,6 +28062,7 @@ ABF8 0061 16B58 0061 1D367 0061 1E8CE 0061 +1E958 0061 0038 0041 0668 0041 06F8 0041 @@ -26914,11 +28114,15 @@ ABF8 0041 111D8 0041 111E8 0041 112F8 0041 +11458 0041 114D8 0041 11658 0041 116C8 0041 11738 0041 118E8 0041 +11C58 0041 +11C61 0041 +11D58 0041 12406 0041 1240D 0041 12413 0041 @@ -26931,6 +28135,7 @@ ABF8 0041 16B58 0041 1D367 0041 1E8CE 0041 +1E958 0041 FF18 0061 FF18 0041 247B 0061 @@ -27016,11 +28221,15 @@ ABF8 0062 111D8 0062 111E8 0062 112F8 0062 +11458 0062 114D8 0062 11658 0062 116C8 0062 11738 0062 118E8 0062 +11C58 0062 +11C61 0062 +11D58 0062 12406 0062 1240D 0062 12413 0062 @@ -27033,6 +28242,7 @@ ABF8 0062 16B58 0062 1D367 0062 1E8CE 0062 +1E958 0062 FF18 0062 247B 0062 1F109 0062 @@ -27050,6 +28260,12 @@ FF18 0062 2791 0062 2078 0062 2088 0062 +1F19F 0021 +1F19F 003F +1F19F 0334 +1F19F 0061 +1F19F 0041 +1F19F 0062 33E7 0021 33E7 003F 33E7 0061 @@ -27116,11 +28332,15 @@ ABF9 0021 111D9 0021 111E9 0021 112F9 0021 +11459 0021 114D9 0021 11659 0021 116C9 0021 11739 0021 118E9 0021 +11C59 0021 +11C62 0021 +11D59 0021 12407 0021 1240E 0021 12414 0021 @@ -27135,6 +28355,7 @@ ABF9 0021 16B59 0021 1D368 0021 1E8CF 0021 +1E959 0021 0039 003F 0669 003F 06F9 003F @@ -27186,11 +28407,15 @@ ABF9 003F 111D9 003F 111E9 003F 112F9 003F +11459 003F 114D9 003F 11659 003F 116C9 003F 11739 003F 118E9 003F +11C59 003F +11C62 003F +11D59 003F 12407 003F 1240E 003F 12414 003F @@ -27205,6 +28430,7 @@ ABF9 003F 16B59 003F 1D368 003F 1E8CF 003F +1E959 003F FF19 0021 FF19 003F 247C 0021 @@ -27252,11 +28478,15 @@ FF19 003F 111D9 0334 111E9 0334 112F9 0334 +11459 0334 114D9 0334 11659 0334 116C9 0334 11739 0334 118E9 0334 +11C59 0334 +11C62 0334 +11D59 0334 12407 0334 1240E 0334 12414 0334 @@ -27271,6 +28501,7 @@ FF19 003F 16B59 0334 1D368 0334 1E8CF 0334 +1E959 0334 1D7D7 0334 1D7E1 0334 1D7EB 0334 @@ -27327,11 +28558,15 @@ ABF9 0061 111D9 0061 111E9 0061 112F9 0061 +11459 0061 114D9 0061 11659 0061 116C9 0061 11739 0061 118E9 0061 +11C59 0061 +11C62 0061 +11D59 0061 12407 0061 1240E 0061 12414 0061 @@ -27346,6 +28581,7 @@ ABF9 0061 16B59 0061 1D368 0061 1E8CF 0061 +1E959 0061 0039 0041 0669 0041 06F9 0041 @@ -27397,11 +28633,15 @@ ABF9 0041 111D9 0041 111E9 0041 112F9 0041 +11459 0041 114D9 0041 11659 0041 116C9 0041 11739 0041 118E9 0041 +11C59 0041 +11C62 0041 +11D59 0041 12407 0041 1240E 0041 12414 0041 @@ -27416,6 +28656,7 @@ ABF9 0041 16B59 0041 1D368 0041 1E8CF 0041 +1E959 0041 FF19 0061 FF19 0041 247C 0061 @@ -27501,11 +28742,15 @@ ABF9 0062 111D9 0062 111E9 0062 112F9 0062 +11459 0062 114D9 0062 11659 0062 116C9 0062 11739 0062 118E9 0062 +11C59 0062 +11C62 0062 +11D59 0062 12407 0062 1240E 0062 12414 0062 @@ -27520,6 +28765,7 @@ ABF9 0062 16B59 0062 1D368 0062 1E8CF 0062 +1E959 0062 FF19 0062 247C 0062 1F10A 0062 @@ -27610,6 +28856,7 @@ FE58 0061 2E3A 0061 2E3B 0061 2053 0061 +2E43 0061 2E17 0061 2E40 0061 301C 0061 @@ -27650,6 +28897,7 @@ FF1B 0061 204F 0061 2E35 0061 A6F6 0061 +2E49 0061 2A74 0061 003A 0061 FE13 0061 @@ -27703,6 +28951,7 @@ FF01 0061 055C 0061 07F9 0061 1944 0061 +1E95E 0061 2048 0061 2047 0061 003F 0061 @@ -27722,6 +28971,7 @@ A60F 0061 A6F7 0061 AAF1 0061 11143 0061 +1E95F 0061 203D 0061 2E18 0061 2026 0061 @@ -27797,12 +29047,16 @@ ABEB 0061 111C6 0061 11238 0061 11239 0061 +1144B 0061 +1144C 0061 115C2 0061 115C3 0061 11641 0061 11642 0061 1173C 0061 1173D 0061 +11C41 0061 +11C42 0061 16A6E 0061 16A6F 0061 1C7E 0061 @@ -28130,6 +29384,11 @@ FF05 0061 2E1B 0061 2E1E 0061 2E1F 0061 +2E44 0061 +2E45 0061 +2E46 0061 +2E47 0061 +2E48 0061 A67E 0061 055A 0061 055B 0061 @@ -28146,11 +29405,25 @@ A67E 0061 070D 0061 085E 0061 1800 0061 +11660 0061 +11661 0061 +11662 0061 +11663 0061 +11664 0061 +11665 0061 +11666 0061 +11667 0061 +11668 0061 +11669 0061 +1166A 0061 +1166B 0061 +1166C 0061 0970 0061 A8F8 0061 A8F9 0061 A8FA 0061 A8FC 0061 +09FD 0061 0AF0 0061 0DF4 0061 0E4F 0061 @@ -28181,6 +29454,24 @@ AADF 0061 0FD4 0061 0FD9 0061 0FDA 0061 +11A3F 0061 +11A40 0061 +11A41 0061 +11A42 0061 +11A43 0061 +11A44 0061 +11A45 0061 +11A46 0061 +11A9A 0061 +11A9B 0061 +11A9C 0061 +11A9E 0061 +11A9F 0061 +11AA0 0061 +11AA1 0061 +11AA2 0061 +11C70 0061 +11C71 0061 1C3D 0061 1C3E 0061 1C3F 0061 @@ -28233,6 +29524,9 @@ AA5C 0061 10A54 0061 10A55 0061 10A58 0061 +11C43 0061 +11C44 0061 +11C45 0061 10B39 0061 10AF0 0061 10AF1 0061 @@ -28258,6 +29552,11 @@ AA5C 0061 1123B 0061 1123C 0061 1123D 0061 +1144D 0061 +1144E 0061 +1144F 0061 +1145B 0061 +1145D 0061 114C6 0061 115C1 0061 115C4 0061 @@ -28465,6 +29764,7 @@ FBC1 0061 0BF8 0061 0BFA 0061 0C7F 0061 +0D4F 0061 0D79 0061 A828 0061 A829 0061 @@ -29258,6 +30558,11 @@ FF5E 0061 23F8 0061 23F9 0061 23FA 0061 +23FB 0061 +23FC 0061 +23FD 0061 +23FE 0061 +23FF 0061 2400 0061 2401 0061 2402 0061 @@ -30714,6 +32019,7 @@ FFEE 0061 2BCF 0061 2BD0 0061 2BD1 0061 +2BD2 0061 2BEC 0061 2BED 0061 2BEE 0061 @@ -31227,6 +32533,8 @@ A4C6 0061 10188 0061 10189 0061 1018C 0061 +1018D 0061 +1018E 0061 10190 0061 10191 0061 10192 0061 @@ -32028,6 +33336,12 @@ A4C6 0061 1F0F3 0061 1F0F4 0061 1F0F5 0061 +1F260 0061 +1F261 0061 +1F262 0061 +1F263 0061 +1F264 0061 +1F265 0061 1F300 0061 1F301 0061 1F302 0061 @@ -32662,6 +33976,7 @@ A4C6 0061 1F577 0061 1F578 0061 1F579 0061 +1F57A 0061 1F57B 0061 1F57C 0061 1F57D 0061 @@ -32703,6 +34018,7 @@ A4C6 0061 1F5A1 0061 1F5A2 0061 1F5A3 0061 +1F5A4 0061 1F5A5 0061 1F5A6 0061 1F5A7 0061 @@ -32794,6 +34110,18 @@ A4C6 0061 1F5FD 0061 1F5FE 0061 1F5FF 0061 +1F900 0061 +1F901 0061 +1F902 0061 +1F903 0061 +1F904 0061 +1F905 0061 +1F906 0061 +1F907 0061 +1F908 0061 +1F909 0061 +1F90A 0061 +1F90B 0061 1F910 0061 1F911 0061 1F912 0061 @@ -32803,12 +34131,133 @@ A4C6 0061 1F916 0061 1F917 0061 1F918 0061 +1F919 0061 +1F91A 0061 +1F91B 0061 +1F91C 0061 +1F91D 0061 +1F91E 0061 +1F91F 0061 +1F920 0061 +1F921 0061 +1F922 0061 +1F923 0061 +1F924 0061 +1F925 0061 +1F926 0061 +1F927 0061 +1F928 0061 +1F929 0061 +1F92A 0061 +1F92B 0061 +1F92C 0061 +1F92D 0061 +1F92E 0061 +1F92F 0061 +1F930 0061 +1F931 0061 +1F932 0061 +1F933 0061 +1F934 0061 +1F935 0061 +1F936 0061 +1F937 0061 +1F938 0061 +1F939 0061 +1F93A 0061 +1F93B 0061 +1F93C 0061 +1F93D 0061 +1F93E 0061 +1F940 0061 +1F941 0061 +1F942 0061 +1F943 0061 +1F944 0061 +1F945 0061 +1F946 0061 +1F947 0061 +1F948 0061 +1F949 0061 +1F94A 0061 +1F94B 0061 +1F94C 0061 +1F950 0061 +1F951 0061 +1F952 0061 +1F953 0061 +1F954 0061 +1F955 0061 +1F956 0061 +1F957 0061 +1F958 0061 +1F959 0061 +1F95A 0061 +1F95B 0061 +1F95C 0061 +1F95D 0061 +1F95E 0061 +1F95F 0061 +1F960 0061 +1F961 0061 +1F962 0061 +1F963 0061 +1F964 0061 +1F965 0061 +1F966 0061 +1F967 0061 +1F968 0061 +1F969 0061 +1F96A 0061 +1F96B 0061 1F980 0061 1F981 0061 1F982 0061 1F983 0061 1F984 0061 +1F985 0061 +1F986 0061 +1F987 0061 +1F988 0061 +1F989 0061 +1F98A 0061 +1F98B 0061 +1F98C 0061 +1F98D 0061 +1F98E 0061 +1F98F 0061 +1F990 0061 +1F991 0061 +1F992 0061 +1F993 0061 +1F994 0061 +1F995 0061 +1F996 0061 +1F997 0061 1F9C0 0061 +1F9D0 0061 +1F9D1 0061 +1F9D2 0061 +1F9D3 0061 +1F9D4 0061 +1F9D5 0061 +1F9D6 0061 +1F9D7 0061 +1F9D8 0061 +1F9D9 0061 +1F9DA 0061 +1F9DB 0061 +1F9DC 0061 +1F9DD 0061 +1F9DE 0061 +1F9DF 0061 +1F9E0 0061 +1F9E1 0061 +1F9E2 0061 +1F9E3 0061 +1F9E4 0061 +1F9E5 0061 +1F9E6 0061 1F600 0061 1F601 0061 1F602 0061 @@ -33018,6 +34467,10 @@ A4C6 0061 1F6CE 0061 1F6CF 0061 1F6D0 0061 +1F6D1 0061 +1F6D2 0061 +1F6D3 0061 +1F6D4 0061 1F6E0 0061 1F6E1 0061 1F6E2 0061 @@ -33035,6 +34488,11 @@ A4C6 0061 1F6F1 0061 1F6F2 0061 1F6F3 0061 +1F6F4 0061 +1F6F5 0061 +1F6F6 0061 +1F6F7 0061 +1F6F8 0061 1F700 0061 1F701 0061 1F702 0061 @@ -34005,12 +35463,22 @@ A835 0061 0BF0 0061 0BF1 0061 0BF2 0061 +0D58 0061 +0D59 0061 +0D5A 0061 +0D5B 0061 +0D5C 0061 +0D5D 0061 +0D5E 0061 0D70 0061 0D71 0061 0D72 0061 0D73 0061 0D74 0061 0D75 0061 +0D76 0061 +0D77 0061 +0D78 0061 1372 0061 1373 0061 1374 0061 @@ -34210,6 +35678,16 @@ A835 0061 10A45 0061 10A46 0061 10A47 0061 +11C63 0061 +11C64 0061 +11C65 0061 +11C66 0061 +11C67 0061 +11C68 0061 +11C69 0061 +11C6A 0061 +11C6B 0061 +11C6C 0061 111EA 0061 111EB 0061 111EC 0061 @@ -34463,6 +35941,21 @@ A835 0061 0749 0061 074A 0061 07FA 0061 +08D4 0061 +08D5 0061 +08D6 0061 +08D7 0061 +08D8 0061 +08D9 0061 +08DA 0061 +08DB 0061 +08DC 0061 +08DD 0061 +08DE 0061 +08DF 0061 +08E0 0061 +08E1 0061 +08E2 0061 08EA 0061 08EB 0061 08EC 0061 @@ -34527,6 +36020,7 @@ A835 0061 1CE7 0061 1CE8 0061 1CF4 0061 +1CF7 0061 1CF8 0061 1CF9 0061 200B 0061 @@ -35232,6 +36726,7 @@ FE58 0041 2E3A 0041 2E3B 0041 2053 0041 +2E43 0041 2E17 0041 2E40 0041 301C 0041 @@ -35272,6 +36767,7 @@ FF1B 0041 204F 0041 2E35 0041 A6F6 0041 +2E49 0041 2A74 0041 003A 0041 FE13 0041 @@ -35325,6 +36821,7 @@ FF01 0041 055C 0041 07F9 0041 1944 0041 +1E95E 0041 2048 0041 2047 0041 003F 0041 @@ -35344,6 +36841,7 @@ A60F 0041 A6F7 0041 AAF1 0041 11143 0041 +1E95F 0041 203D 0041 2E18 0041 2026 0041 @@ -35419,12 +36917,16 @@ ABEB 0041 111C6 0041 11238 0041 11239 0041 +1144B 0041 +1144C 0041 115C2 0041 115C3 0041 11641 0041 11642 0041 1173C 0041 1173D 0041 +11C41 0041 +11C42 0041 16A6E 0041 16A6F 0041 1C7E 0041 @@ -35752,6 +37254,11 @@ FF05 0041 2E1B 0041 2E1E 0041 2E1F 0041 +2E44 0041 +2E45 0041 +2E46 0041 +2E47 0041 +2E48 0041 A67E 0041 055A 0041 055B 0041 @@ -35768,11 +37275,25 @@ A67E 0041 070D 0041 085E 0041 1800 0041 +11660 0041 +11661 0041 +11662 0041 +11663 0041 +11664 0041 +11665 0041 +11666 0041 +11667 0041 +11668 0041 +11669 0041 +1166A 0041 +1166B 0041 +1166C 0041 0970 0041 A8F8 0041 A8F9 0041 A8FA 0041 A8FC 0041 +09FD 0041 0AF0 0041 0DF4 0041 0E4F 0041 @@ -35803,6 +37324,24 @@ AADF 0041 0FD4 0041 0FD9 0041 0FDA 0041 +11A3F 0041 +11A40 0041 +11A41 0041 +11A42 0041 +11A43 0041 +11A44 0041 +11A45 0041 +11A46 0041 +11A9A 0041 +11A9B 0041 +11A9C 0041 +11A9E 0041 +11A9F 0041 +11AA0 0041 +11AA1 0041 +11AA2 0041 +11C70 0041 +11C71 0041 1C3D 0041 1C3E 0041 1C3F 0041 @@ -35855,6 +37394,9 @@ AA5C 0041 10A54 0041 10A55 0041 10A58 0041 +11C43 0041 +11C44 0041 +11C45 0041 10B39 0041 10AF0 0041 10AF1 0041 @@ -35880,6 +37422,11 @@ AA5C 0041 1123B 0041 1123C 0041 1123D 0041 +1144D 0041 +1144E 0041 +1144F 0041 +1145B 0041 +1145D 0041 114C6 0041 115C1 0041 115C4 0041 @@ -36087,6 +37634,7 @@ FBC1 0041 0BF8 0041 0BFA 0041 0C7F 0041 +0D4F 0041 0D79 0041 A828 0041 A829 0041 @@ -36880,6 +38428,11 @@ FF5E 0041 23F8 0041 23F9 0041 23FA 0041 +23FB 0041 +23FC 0041 +23FD 0041 +23FE 0041 +23FF 0041 2400 0041 2401 0041 2402 0041 @@ -38336,6 +39889,7 @@ FFEE 0041 2BCF 0041 2BD0 0041 2BD1 0041 +2BD2 0041 2BEC 0041 2BED 0041 2BEE 0041 @@ -38849,6 +40403,8 @@ A4C6 0041 10188 0041 10189 0041 1018C 0041 +1018D 0041 +1018E 0041 10190 0041 10191 0041 10192 0041 @@ -39650,6 +41206,12 @@ A4C6 0041 1F0F3 0041 1F0F4 0041 1F0F5 0041 +1F260 0041 +1F261 0041 +1F262 0041 +1F263 0041 +1F264 0041 +1F265 0041 1F300 0041 1F301 0041 1F302 0041 @@ -40284,6 +41846,7 @@ A4C6 0041 1F577 0041 1F578 0041 1F579 0041 +1F57A 0041 1F57B 0041 1F57C 0041 1F57D 0041 @@ -40325,6 +41888,7 @@ A4C6 0041 1F5A1 0041 1F5A2 0041 1F5A3 0041 +1F5A4 0041 1F5A5 0041 1F5A6 0041 1F5A7 0041 @@ -40416,6 +41980,18 @@ A4C6 0041 1F5FD 0041 1F5FE 0041 1F5FF 0041 +1F900 0041 +1F901 0041 +1F902 0041 +1F903 0041 +1F904 0041 +1F905 0041 +1F906 0041 +1F907 0041 +1F908 0041 +1F909 0041 +1F90A 0041 +1F90B 0041 1F910 0041 1F911 0041 1F912 0041 @@ -40425,12 +42001,133 @@ A4C6 0041 1F916 0041 1F917 0041 1F918 0041 +1F919 0041 +1F91A 0041 +1F91B 0041 +1F91C 0041 +1F91D 0041 +1F91E 0041 +1F91F 0041 +1F920 0041 +1F921 0041 +1F922 0041 +1F923 0041 +1F924 0041 +1F925 0041 +1F926 0041 +1F927 0041 +1F928 0041 +1F929 0041 +1F92A 0041 +1F92B 0041 +1F92C 0041 +1F92D 0041 +1F92E 0041 +1F92F 0041 +1F930 0041 +1F931 0041 +1F932 0041 +1F933 0041 +1F934 0041 +1F935 0041 +1F936 0041 +1F937 0041 +1F938 0041 +1F939 0041 +1F93A 0041 +1F93B 0041 +1F93C 0041 +1F93D 0041 +1F93E 0041 +1F940 0041 +1F941 0041 +1F942 0041 +1F943 0041 +1F944 0041 +1F945 0041 +1F946 0041 +1F947 0041 +1F948 0041 +1F949 0041 +1F94A 0041 +1F94B 0041 +1F94C 0041 +1F950 0041 +1F951 0041 +1F952 0041 +1F953 0041 +1F954 0041 +1F955 0041 +1F956 0041 +1F957 0041 +1F958 0041 +1F959 0041 +1F95A 0041 +1F95B 0041 +1F95C 0041 +1F95D 0041 +1F95E 0041 +1F95F 0041 +1F960 0041 +1F961 0041 +1F962 0041 +1F963 0041 +1F964 0041 +1F965 0041 +1F966 0041 +1F967 0041 +1F968 0041 +1F969 0041 +1F96A 0041 +1F96B 0041 1F980 0041 1F981 0041 1F982 0041 1F983 0041 1F984 0041 +1F985 0041 +1F986 0041 +1F987 0041 +1F988 0041 +1F989 0041 +1F98A 0041 +1F98B 0041 +1F98C 0041 +1F98D 0041 +1F98E 0041 +1F98F 0041 +1F990 0041 +1F991 0041 +1F992 0041 +1F993 0041 +1F994 0041 +1F995 0041 +1F996 0041 +1F997 0041 1F9C0 0041 +1F9D0 0041 +1F9D1 0041 +1F9D2 0041 +1F9D3 0041 +1F9D4 0041 +1F9D5 0041 +1F9D6 0041 +1F9D7 0041 +1F9D8 0041 +1F9D9 0041 +1F9DA 0041 +1F9DB 0041 +1F9DC 0041 +1F9DD 0041 +1F9DE 0041 +1F9DF 0041 +1F9E0 0041 +1F9E1 0041 +1F9E2 0041 +1F9E3 0041 +1F9E4 0041 +1F9E5 0041 +1F9E6 0041 1F600 0041 1F601 0041 1F602 0041 @@ -40640,6 +42337,10 @@ A4C6 0041 1F6CE 0041 1F6CF 0041 1F6D0 0041 +1F6D1 0041 +1F6D2 0041 +1F6D3 0041 +1F6D4 0041 1F6E0 0041 1F6E1 0041 1F6E2 0041 @@ -40657,6 +42358,11 @@ A4C6 0041 1F6F1 0041 1F6F2 0041 1F6F3 0041 +1F6F4 0041 +1F6F5 0041 +1F6F6 0041 +1F6F7 0041 +1F6F8 0041 1F700 0041 1F701 0041 1F702 0041 @@ -41627,12 +43333,22 @@ A835 0041 0BF0 0041 0BF1 0041 0BF2 0041 +0D58 0041 +0D59 0041 +0D5A 0041 +0D5B 0041 +0D5C 0041 +0D5D 0041 +0D5E 0041 0D70 0041 0D71 0041 0D72 0041 0D73 0041 0D74 0041 0D75 0041 +0D76 0041 +0D77 0041 +0D78 0041 1372 0041 1373 0041 1374 0041 @@ -41832,6 +43548,16 @@ A835 0041 10A45 0041 10A46 0041 10A47 0041 +11C63 0041 +11C64 0041 +11C65 0041 +11C66 0041 +11C67 0041 +11C68 0041 +11C69 0041 +11C6A 0041 +11C6B 0041 +11C6C 0041 111EA 0041 111EB 0041 111EC 0041 @@ -42085,6 +43811,21 @@ A835 0041 0749 0041 074A 0041 07FA 0041 +08D4 0041 +08D5 0041 +08D6 0041 +08D7 0041 +08D8 0041 +08D9 0041 +08DA 0041 +08DB 0041 +08DC 0041 +08DD 0041 +08DE 0041 +08DF 0041 +08E0 0041 +08E1 0041 +08E2 0041 08EA 0041 08EB 0041 08EC 0041 @@ -42149,6 +43890,7 @@ A835 0041 1CE7 0041 1CE8 0041 1CF4 0041 +1CF7 0041 1CF8 0041 1CF9 0041 200B 0041 @@ -42968,14 +44710,14 @@ A79A 003F 00E1 0334 0041 0301 0334 0041 0334 0301 -0041 0334 0341 0041 0341 0334 +00C1 0334 0061 0300 0334 0061 0334 0300 0061 0340 0334 00E0 0334 +0041 0300 0334 0041 0334 0300 -0041 0334 0340 0041 0340 0334 00C0 0334 0061 0306 0334 @@ -42984,35 +44726,35 @@ A79A 003F 0041 0306 0334 0041 0334 0306 0102 0334 -0061 0306 0301 0334 -0061 0334 0306 0301 -0061 0334 0306 0341 0103 0301 0334 +0103 0334 0301 +0103 0334 0341 +0103 0341 0334 0041 0306 0301 0334 -0041 0306 0334 0301 -0041 0306 0334 0341 0041 0306 0341 0334 -0061 0306 0340 0334 +0102 0301 0334 +0102 0341 0334 0061 0334 0306 0300 -0103 0334 0340 +0103 0300 0334 +0103 0340 0334 1EB1 0334 -0041 0306 0334 0300 -0041 0306 0334 0340 +0041 0306 0300 0334 0041 0306 0340 0334 -1EB0 0334 +0102 0300 0334 +0102 0340 0334 +0061 0306 0303 0334 0061 0306 0334 0303 -0061 0334 0306 0303 0103 0303 0334 -1EB5 0334 -0041 0306 0303 0334 -0041 0306 0334 0303 +0103 0334 0303 0041 0334 0306 0303 0102 0303 0334 +0102 0334 0303 +1EB4 0334 0061 0306 0309 0334 -0061 0306 0334 0309 +0103 0309 0334 0103 0334 0309 1EB3 0334 -0041 0334 0306 0309 +0041 0306 0334 0309 0102 0309 0334 0102 0334 0309 1EB2 0334 @@ -43023,33 +44765,33 @@ A79A 003F 0041 0334 0302 00C2 0334 0061 0302 0301 0334 -0061 0302 0334 0341 -0061 0334 0302 0301 -00E2 0334 0301 -0041 0302 0301 0334 +0061 0302 0341 0334 +00E2 0301 0334 +00E2 0341 0334 0041 0302 0334 0301 -00C2 0334 0301 +00C2 0301 0334 00C2 0341 0334 -0061 0302 0334 0340 -0061 0334 0302 0300 -00E2 0334 0300 -1EA7 0334 +1EA4 0334 +0061 0302 0300 0334 +0061 0302 0340 0334 +00E2 0300 0334 +00E2 0340 0334 0041 0302 0334 0300 +0041 0302 0334 0340 00C2 0300 0334 00C2 0340 0334 -1EA6 0334 0061 0302 0303 0334 0061 0302 0334 0303 -0061 0334 0302 0303 00E2 0303 0334 -0041 0302 0303 0334 +00E2 0334 0303 0041 0302 0334 0303 -0041 0334 0302 0303 +00C2 0303 0334 00C2 0334 0303 -0061 0302 0309 0334 +1EAA 0334 0061 0302 0334 0309 0061 0334 0302 0309 00E2 0334 0309 +1EA9 0334 0041 0302 0309 0334 0041 0334 0302 0309 00C2 0309 0334 @@ -43067,14 +44809,14 @@ A79A 003F 0041 0334 030A 00C5 0334 212B 0334 +0061 030A 0334 0301 0061 030A 0334 0341 -0061 0334 030A 0341 00E5 0334 0301 -01FB 0334 -0041 030A 0301 0334 +00E5 0334 0341 0041 0334 030A 0301 0041 0334 030A 0341 -00C5 0341 0334 +212B 0301 0334 +212B 0341 0334 0061 0308 0334 0061 0334 0308 00E4 0334 @@ -43083,12 +44825,12 @@ A79A 003F 00C4 0334 0061 0308 0304 0334 0061 0308 0334 0304 -00E4 0304 0334 -00E4 0334 0304 -0041 0308 0304 0334 -0041 0308 0334 0304 +0061 0334 0308 0304 +01DF 0334 0041 0334 0308 0304 00C4 0304 0334 +00C4 0334 0304 +01DE 0334 0061 0303 0334 0061 0334 0303 00E3 0334 @@ -43101,14 +44843,14 @@ A79A 003F 0041 0307 0334 0041 0334 0307 0226 0334 +0061 0307 0304 0334 0061 0307 0334 0304 0061 0334 0307 0304 -0227 0304 0334 -0227 0334 0304 -0041 0307 0304 0334 -0041 0307 0334 0304 +01E1 0334 0041 0334 0307 0304 01E0 0334 +0226 0304 0334 +0226 0334 0304 0061 0328 0334 0061 0334 0328 0105 0334 @@ -43145,22 +44887,22 @@ A79A 003F 0041 0323 0334 0041 0334 0323 1EA0 0334 -0061 0323 0306 0334 -0061 0334 0306 0323 -0061 0334 0323 0306 -1EA1 0306 0334 +0061 0306 0323 0334 +0061 0306 0334 0323 +0103 0323 0334 +1EA1 0334 0306 0041 0334 0306 0323 -0041 0334 0323 0306 0102 0323 0334 -1EB6 0334 -0061 0302 0334 0323 -0061 0334 0323 0302 +0102 0334 0323 +1EA0 0334 0306 +00E2 0323 0334 +00E2 0334 0323 1EA1 0302 0334 -1EA1 0334 0302 +1EAD 0334 0041 0302 0334 0323 00C2 0323 0334 +00C2 0334 0323 1EA0 0302 0334 -1EAC 0334 0061 0325 0334 0061 0334 0325 1E01 0334 @@ -43278,6 +45020,10 @@ A79A 003F 1DCE 0061 1DD1 0061 1DF5 0061 +1DF6 0061 +1DF7 0061 +1DF8 0061 +1DFB 0061 1DFE 0061 20F0 0061 2CEF 0061 @@ -43338,6 +45084,10 @@ A67D 0061 1DCE 0041 1DD1 0041 1DF5 0041 +1DF6 0041 +1DF7 0041 +1DF8 0041 +1DFB 0041 1DFE 0041 20F0 0041 2CEF 0041 @@ -43392,6 +45142,7 @@ A67D 0041 1DC2 0061 1DCF 0061 1DD0 0061 +1DF9 0061 1DFC 0061 1DFD 0061 1DFF 0061 @@ -43449,6 +45200,7 @@ FE27 0061 1DC2 0041 1DCF 0041 1DD0 0041 +1DF9 0041 1DFC 0041 1DFD 0041 1DFF 0041 @@ -43716,8 +45468,10 @@ FC62 0041 08F6 0061 08F6 0041 0651 0061 +0AFB 0061 11237 0061 0651 0041 +0AFB 0041 11237 0041 FE7D 0061 FE7D 0041 @@ -43726,13 +45480,19 @@ FE7C 0041 FC63 0061 FC63 0041 0652 0061 +0AFA 0061 +1123E 0061 0652 0041 +0AFA 0041 +1123E 0041 FE7F 0061 FE7F 0041 FE7E 0061 FE7E 0041 0653 0061 +0AFC 0061 0653 0041 +0AFC 0041 0654 0061 0654 0041 0655 0061 @@ -43849,10 +45609,27 @@ A6F1 0041 16AF3 0041 16AF4 0061 16AF4 0041 +1E944 0061 +1E945 0061 +1E946 0061 +1E944 0041 +1E945 0041 +1E946 0041 +1E94A 0061 +1E94A 0041 +1E947 0061 +1E947 0041 +1E948 0061 +1E948 0041 +1E949 0061 +1E949 0041 093C 0061 09BC 0061 0A3C 0061 0ABC 0061 +0AFD 0061 +0AFE 0061 +0AFF 0061 0B3C 0061 0CBC 0061 1B34 0061 @@ -43865,13 +45642,19 @@ A9B3 0061 11236 0061 112E9 0061 1133C 0061 +11446 0061 114C3 0061 115C0 0061 116B7 0061 +11A33 0061 +11D42 0061 093C 0041 09BC 0041 0A3C 0041 0ABC 0041 +0AFD 0041 +0AFE 0041 +0AFF 0041 0B3C 0041 0CBC 0041 1B34 0041 @@ -43884,9 +45667,12 @@ A9B3 0041 11236 0041 112E9 0041 1133C 0041 +11446 0041 114C3 0041 115C0 0041 116B7 0041 +11A33 0041 +11D42 0041 0900 0061 0901 0061 0981 0061 @@ -43899,15 +45685,23 @@ A9B3 0041 0D01 0061 1B00 0061 1B01 0061 +A8C5 0061 A980 0061 11000 0061 11080 0061 11100 0061 11180 0061 11301 0061 +11443 0061 114BF 0061 115BC 0061 11640 0061 +11A35 0061 +11A36 0061 +11A37 0061 +11C3C 0061 +11CB6 0061 +11D43 0061 0900 0041 0901 0041 0981 0041 @@ -43920,15 +45714,23 @@ A980 0061 0D01 0041 1B00 0041 1B01 0041 +A8C5 0041 A980 0041 11000 0041 11080 0041 11100 0041 11180 0041 11301 0041 +11443 0041 114BF 0041 115BC 0041 11640 0041 +11A35 0041 +11A36 0041 +11A37 0041 +11C3C 0041 +11CB6 0041 +11D43 0041 0902 0061 0982 0061 0A02 0061 @@ -43937,6 +45739,7 @@ A980 0041 0B82 0061 0C02 0061 0C82 0061 +0D00 0061 0D02 0061 0D82 0061 0F7E 0061 @@ -43958,10 +45761,16 @@ A981 0061 112DF 0061 11300 0061 11302 0061 +11444 0061 114C0 0061 115BD 0061 1163D 0061 116AB 0061 +11A38 0061 +11A96 0061 +11C3D 0061 +11CB5 0061 +11D40 0061 0902 0041 0982 0041 0A02 0041 @@ -43970,6 +45779,7 @@ A981 0061 0B82 0041 0C02 0041 0C82 0041 +0D00 0041 0D02 0041 0D82 0041 0F7E 0041 @@ -43991,10 +45801,16 @@ A981 0041 112DF 0041 11300 0041 11302 0041 +11444 0041 114C0 0041 115BD 0041 1163D 0041 116AB 0041 +11A38 0041 +11A96 0041 +11C3D 0041 +11CB5 0041 +11D40 0041 0903 0061 0983 0061 0A03 0061 @@ -44019,10 +45835,15 @@ A983 0061 11102 0061 11182 0061 11303 0061 +11445 0061 114C1 0061 115BE 0061 1163E 0061 116AC 0061 +11A39 0061 +11A97 0061 +11C3E 0061 +11D41 0061 0903 0041 0983 0041 0A03 0041 @@ -44047,10 +45868,15 @@ A983 0041 11102 0041 11182 0041 11303 0041 +11445 0041 114C1 0041 115BE 0041 1163E 0041 116AC 0041 +11A39 0041 +11A97 0041 +11C3E 0041 +11D41 0041 0A70 0061 0A70 0041 0A71 0061 @@ -44073,6 +45899,8 @@ ABEC 0041 111CB 0041 111CC 0061 111CC 0041 +11A98 0061 +11A98 0041 0E4E 0061 0E4E 0041 0E47 0061 @@ -44557,9 +46385,9 @@ A79A 0062 00E6 0334 0301 00E6 0334 0341 01FD 0334 +00C6 0301 0334 00C6 0334 0301 00C6 0334 0341 -00C6 0341 0334 01FC 0334 00E6 0304 0334 00E6 0334 0304 @@ -44852,6 +46680,7 @@ FE58 0062 2E3A 0062 2E3B 0062 2053 0062 +2E43 0062 2E17 0062 2E40 0062 301C 0062 @@ -44892,6 +46721,7 @@ FF1B 0062 204F 0062 2E35 0062 A6F6 0062 +2E49 0062 2A74 0062 003A 0062 FE13 0062 @@ -44945,6 +46775,7 @@ FF01 0062 055C 0062 07F9 0062 1944 0062 +1E95E 0062 2048 0062 2047 0062 003F 0062 @@ -44964,6 +46795,7 @@ A60F 0062 A6F7 0062 AAF1 0062 11143 0062 +1E95F 0062 203D 0062 2E18 0062 2026 0062 @@ -45039,12 +46871,16 @@ ABEB 0062 111C6 0062 11238 0062 11239 0062 +1144B 0062 +1144C 0062 115C2 0062 115C3 0062 11641 0062 11642 0062 1173C 0062 1173D 0062 +11C41 0062 +11C42 0062 16A6E 0062 16A6F 0062 1C7E 0062 @@ -45372,6 +47208,11 @@ FF05 0062 2E1B 0062 2E1E 0062 2E1F 0062 +2E44 0062 +2E45 0062 +2E46 0062 +2E47 0062 +2E48 0062 A67E 0062 055A 0062 055B 0062 @@ -45388,11 +47229,25 @@ A67E 0062 070D 0062 085E 0062 1800 0062 +11660 0062 +11661 0062 +11662 0062 +11663 0062 +11664 0062 +11665 0062 +11666 0062 +11667 0062 +11668 0062 +11669 0062 +1166A 0062 +1166B 0062 +1166C 0062 0970 0062 A8F8 0062 A8F9 0062 A8FA 0062 A8FC 0062 +09FD 0062 0AF0 0062 0DF4 0062 0E4F 0062 @@ -45423,6 +47278,24 @@ AADF 0062 0FD4 0062 0FD9 0062 0FDA 0062 +11A3F 0062 +11A40 0062 +11A41 0062 +11A42 0062 +11A43 0062 +11A44 0062 +11A45 0062 +11A46 0062 +11A9A 0062 +11A9B 0062 +11A9C 0062 +11A9E 0062 +11A9F 0062 +11AA0 0062 +11AA1 0062 +11AA2 0062 +11C70 0062 +11C71 0062 1C3D 0062 1C3E 0062 1C3F 0062 @@ -45475,6 +47348,9 @@ AA5C 0062 10A54 0062 10A55 0062 10A58 0062 +11C43 0062 +11C44 0062 +11C45 0062 10B39 0062 10AF0 0062 10AF1 0062 @@ -45500,6 +47376,11 @@ AA5C 0062 1123B 0062 1123C 0062 1123D 0062 +1144D 0062 +1144E 0062 +1144F 0062 +1145B 0062 +1145D 0062 114C6 0062 115C1 0062 115C4 0062 @@ -45707,6 +47588,7 @@ FBC1 0062 0BF8 0062 0BFA 0062 0C7F 0062 +0D4F 0062 0D79 0062 A828 0062 A829 0062 @@ -46500,6 +48382,11 @@ FF5E 0062 23F8 0062 23F9 0062 23FA 0062 +23FB 0062 +23FC 0062 +23FD 0062 +23FE 0062 +23FF 0062 2400 0062 2401 0062 2402 0062 @@ -47956,6 +49843,7 @@ FFEE 0062 2BCF 0062 2BD0 0062 2BD1 0062 +2BD2 0062 2BEC 0062 2BED 0062 2BEE 0062 @@ -48469,6 +50357,8 @@ A4C6 0062 10188 0062 10189 0062 1018C 0062 +1018D 0062 +1018E 0062 10190 0062 10191 0062 10192 0062 @@ -49270,6 +51160,12 @@ A4C6 0062 1F0F3 0062 1F0F4 0062 1F0F5 0062 +1F260 0062 +1F261 0062 +1F262 0062 +1F263 0062 +1F264 0062 +1F265 0062 1F300 0062 1F301 0062 1F302 0062 @@ -49904,6 +51800,7 @@ A4C6 0062 1F577 0062 1F578 0062 1F579 0062 +1F57A 0062 1F57B 0062 1F57C 0062 1F57D 0062 @@ -49945,6 +51842,7 @@ A4C6 0062 1F5A1 0062 1F5A2 0062 1F5A3 0062 +1F5A4 0062 1F5A5 0062 1F5A6 0062 1F5A7 0062 @@ -50036,6 +51934,18 @@ A4C6 0062 1F5FD 0062 1F5FE 0062 1F5FF 0062 +1F900 0062 +1F901 0062 +1F902 0062 +1F903 0062 +1F904 0062 +1F905 0062 +1F906 0062 +1F907 0062 +1F908 0062 +1F909 0062 +1F90A 0062 +1F90B 0062 1F910 0062 1F911 0062 1F912 0062 @@ -50045,12 +51955,133 @@ A4C6 0062 1F916 0062 1F917 0062 1F918 0062 +1F919 0062 +1F91A 0062 +1F91B 0062 +1F91C 0062 +1F91D 0062 +1F91E 0062 +1F91F 0062 +1F920 0062 +1F921 0062 +1F922 0062 +1F923 0062 +1F924 0062 +1F925 0062 +1F926 0062 +1F927 0062 +1F928 0062 +1F929 0062 +1F92A 0062 +1F92B 0062 +1F92C 0062 +1F92D 0062 +1F92E 0062 +1F92F 0062 +1F930 0062 +1F931 0062 +1F932 0062 +1F933 0062 +1F934 0062 +1F935 0062 +1F936 0062 +1F937 0062 +1F938 0062 +1F939 0062 +1F93A 0062 +1F93B 0062 +1F93C 0062 +1F93D 0062 +1F93E 0062 +1F940 0062 +1F941 0062 +1F942 0062 +1F943 0062 +1F944 0062 +1F945 0062 +1F946 0062 +1F947 0062 +1F948 0062 +1F949 0062 +1F94A 0062 +1F94B 0062 +1F94C 0062 +1F950 0062 +1F951 0062 +1F952 0062 +1F953 0062 +1F954 0062 +1F955 0062 +1F956 0062 +1F957 0062 +1F958 0062 +1F959 0062 +1F95A 0062 +1F95B 0062 +1F95C 0062 +1F95D 0062 +1F95E 0062 +1F95F 0062 +1F960 0062 +1F961 0062 +1F962 0062 +1F963 0062 +1F964 0062 +1F965 0062 +1F966 0062 +1F967 0062 +1F968 0062 +1F969 0062 +1F96A 0062 +1F96B 0062 1F980 0062 1F981 0062 1F982 0062 1F983 0062 1F984 0062 +1F985 0062 +1F986 0062 +1F987 0062 +1F988 0062 +1F989 0062 +1F98A 0062 +1F98B 0062 +1F98C 0062 +1F98D 0062 +1F98E 0062 +1F98F 0062 +1F990 0062 +1F991 0062 +1F992 0062 +1F993 0062 +1F994 0062 +1F995 0062 +1F996 0062 +1F997 0062 1F9C0 0062 +1F9D0 0062 +1F9D1 0062 +1F9D2 0062 +1F9D3 0062 +1F9D4 0062 +1F9D5 0062 +1F9D6 0062 +1F9D7 0062 +1F9D8 0062 +1F9D9 0062 +1F9DA 0062 +1F9DB 0062 +1F9DC 0062 +1F9DD 0062 +1F9DE 0062 +1F9DF 0062 +1F9E0 0062 +1F9E1 0062 +1F9E2 0062 +1F9E3 0062 +1F9E4 0062 +1F9E5 0062 +1F9E6 0062 1F600 0062 1F601 0062 1F602 0062 @@ -50260,6 +52291,10 @@ A4C6 0062 1F6CE 0062 1F6CF 0062 1F6D0 0062 +1F6D1 0062 +1F6D2 0062 +1F6D3 0062 +1F6D4 0062 1F6E0 0062 1F6E1 0062 1F6E2 0062 @@ -50277,6 +52312,11 @@ A4C6 0062 1F6F1 0062 1F6F2 0062 1F6F3 0062 +1F6F4 0062 +1F6F5 0062 +1F6F6 0062 +1F6F7 0062 +1F6F8 0062 1F700 0062 1F701 0062 1F702 0062 @@ -51247,12 +53287,22 @@ A835 0062 0BF0 0062 0BF1 0062 0BF2 0062 +0D58 0062 +0D59 0062 +0D5A 0062 +0D5B 0062 +0D5C 0062 +0D5D 0062 +0D5E 0062 0D70 0062 0D71 0062 0D72 0062 0D73 0062 0D74 0062 0D75 0062 +0D76 0062 +0D77 0062 +0D78 0062 1372 0062 1373 0062 1374 0062 @@ -51452,6 +53502,16 @@ A835 0062 10A45 0062 10A46 0062 10A47 0062 +11C63 0062 +11C64 0062 +11C65 0062 +11C66 0062 +11C67 0062 +11C68 0062 +11C69 0062 +11C6A 0062 +11C6B 0062 +11C6C 0062 111EA 0062 111EB 0062 111EC 0062 @@ -51705,6 +53765,21 @@ A835 0062 0749 0062 074A 0062 07FA 0062 +08D4 0062 +08D5 0062 +08D6 0062 +08D7 0062 +08D8 0062 +08D9 0062 +08DA 0062 +08DB 0062 +08DC 0062 +08DD 0062 +08DE 0062 +08DF 0062 +08E0 0062 +08E1 0062 +08E2 0062 08EA 0062 08EB 0062 08EC 0062 @@ -51769,6 +53844,7 @@ A835 0062 1CE7 0062 1CE8 0062 1CF4 0062 +1CF7 0062 1CF8 0062 1CF9 0062 200B 0062 @@ -52600,6 +54676,10 @@ FF22 003F 1DCE 0062 1DD1 0062 1DF5 0062 +1DF6 0062 +1DF7 0062 +1DF8 0062 +1DFB 0062 1DFE 0062 20F0 0062 2CEF 0062 @@ -52654,6 +54734,7 @@ A67D 0062 1DC2 0062 1DCF 0062 1DD0 0062 +1DF9 0062 1DFC 0062 1DFD 0062 1DFF 0062 @@ -52792,14 +54873,18 @@ FC62 0062 08E6 0062 08F6 0062 0651 0062 +0AFB 0062 11237 0062 FE7D 0062 FE7C 0062 FC63 0062 0652 0062 +0AFA 0062 +1123E 0062 FE7F 0062 FE7E 0062 0653 0062 +0AFC 0062 0654 0062 0655 0062 065F 0062 @@ -52858,10 +54943,20 @@ A6F1 0062 16AF2 0062 16AF3 0062 16AF4 0062 +1E944 0062 +1E945 0062 +1E946 0062 +1E94A 0062 +1E947 0062 +1E948 0062 +1E949 0062 093C 0062 09BC 0062 0A3C 0062 0ABC 0062 +0AFD 0062 +0AFE 0062 +0AFF 0062 0B3C 0062 0CBC 0062 1B34 0062 @@ -52874,9 +54969,12 @@ A9B3 0062 11236 0062 112E9 0062 1133C 0062 +11446 0062 114C3 0062 115C0 0062 116B7 0062 +11A33 0062 +11D42 0062 0900 0062 0901 0062 0981 0062 @@ -52889,15 +54987,23 @@ A9B3 0062 0D01 0062 1B00 0062 1B01 0062 +A8C5 0062 A980 0062 11000 0062 11080 0062 11100 0062 11180 0062 11301 0062 +11443 0062 114BF 0062 115BC 0062 11640 0062 +11A35 0062 +11A36 0062 +11A37 0062 +11C3C 0062 +11CB6 0062 +11D43 0062 0902 0062 0982 0062 0A02 0062 @@ -52906,6 +55012,7 @@ A980 0062 0B82 0062 0C02 0062 0C82 0062 +0D00 0062 0D02 0062 0D82 0062 0F7E 0062 @@ -52927,10 +55034,16 @@ A981 0062 112DF 0062 11300 0062 11302 0062 +11444 0062 114C0 0062 115BD 0062 1163D 0062 116AB 0062 +11A38 0062 +11A96 0062 +11C3D 0062 +11CB5 0062 +11D40 0062 0903 0062 0983 0062 0A03 0062 @@ -52955,10 +55068,15 @@ A983 0062 11102 0062 11182 0062 11303 0062 +11445 0062 114C1 0062 115BE 0062 1163E 0062 116AC 0062 +11A39 0062 +11A97 0062 +11C3E 0062 +11D41 0062 0A70 0062 0A71 0062 1B03 0062 @@ -52970,6 +55088,7 @@ ABEC 0062 10A3A 0062 111CB 0062 111CC 0062 +11A98 0062 0E4E 0062 0E47 0062 0E48 0062 @@ -53407,12 +55526,12 @@ FF23 003F 1F172 0334 0063 0301 0334 0063 0334 0301 +0063 0334 0341 0063 0341 0334 -0107 0334 0043 0301 0334 0043 0334 0301 0043 0334 0341 -0106 0334 +0043 0341 0334 0063 0302 0334 0063 0334 0302 0109 0334 @@ -53438,13 +55557,13 @@ FF23 003F 0043 0334 0327 00C7 0334 0063 0327 0334 0301 -0063 0334 0301 0327 -00E7 0341 0334 -0107 0334 0327 +0063 0327 0334 0341 +0063 0341 0334 0327 +1E09 0334 +0043 0301 0327 0334 0043 0334 0327 0301 0043 0334 0327 0341 -0043 0334 0341 0327 -0106 0327 0334 +0043 0341 0327 0334 0334 0368 0368 0334 0334 1DD7 @@ -53838,6 +55957,8 @@ FF24 003F 1F153 003F 1D48 0021 1D48 003F +1F1A5 0021 +1F1A5 003F 1D30 0021 1F133 0021 1F173 0021 @@ -53899,6 +56020,7 @@ FF24 003F 1D63F 0334 1D673 0334 1F153 0334 +1F1A5 0334 1F133 0334 1F173 0334 0064 030C 0334 @@ -54039,6 +56161,8 @@ FF24 0041 1F153 0041 1D48 0061 1D48 0041 +1F1A5 0061 +1F1A5 0041 3372 0021 3372 003F 1D30 0061 @@ -54135,6 +56259,7 @@ FF24 0062 24B9 0062 1F153 0062 1D48 0062 +1F1A5 0062 33C8 0021 33C8 003F 1D30 0062 @@ -54521,17 +56646,17 @@ FF25 003F 1F134 0334 1F174 0334 0065 0301 0334 +0065 0334 0301 0065 0334 0341 0065 0341 0334 -00E9 0334 0045 0301 0334 0045 0334 0301 +0045 0334 0341 0045 0341 0334 -00C9 0334 0065 0300 0334 +0065 0334 0300 0065 0334 0340 0065 0340 0334 -00E8 0334 0045 0300 0334 0045 0334 0300 0045 0334 0340 @@ -54548,34 +56673,34 @@ FF25 003F 0045 0302 0334 0045 0334 0302 00CA 0334 +0065 0302 0334 0301 0065 0302 0334 0341 0065 0334 0302 0301 -00EA 0301 0334 -1EBF 0334 +00EA 0334 0301 +0045 0302 0334 0301 0045 0302 0334 0341 -0045 0334 0302 0341 00CA 0334 0301 -00CA 0341 0334 +00CA 0334 0341 +0065 0302 0334 0300 0065 0302 0334 0340 -0065 0334 0302 0300 -0065 0334 0302 0340 -00EA 0300 0334 +00EA 0334 0300 +1EC1 0334 +0045 0302 0334 0300 0045 0302 0334 0340 -0045 0334 0302 0340 00CA 0334 0300 -1EC0 0334 +00CA 0334 0340 +0065 0302 0303 0334 0065 0302 0334 0303 0065 0334 0302 0303 00EA 0303 0334 -00EA 0334 0303 0045 0302 0303 0334 0045 0302 0334 0303 -0045 0334 0302 0303 00CA 0303 0334 +1EC4 0334 0065 0302 0309 0334 0065 0302 0334 0309 -0065 0334 0302 0309 -00EA 0334 0309 +00EA 0309 0334 +1EC3 0334 0045 0302 0309 0334 0045 0302 0334 0309 00CA 0309 0334 @@ -54610,14 +56735,14 @@ FF25 003F 0045 0327 0334 0045 0334 0327 0228 0334 -0065 0327 0334 0306 -0065 0334 0306 0327 -0115 0334 0327 +0065 0334 0327 0306 +0115 0327 0334 +0229 0334 0306 1E1D 0334 -0045 0327 0334 0306 -0045 0334 0306 0327 -0045 0334 0327 0306 +0045 0306 0327 0334 0114 0327 0334 +0114 0334 0327 +0228 0334 0306 0065 0328 0334 0065 0334 0328 0119 0334 @@ -54630,8 +56755,8 @@ FF25 003F 0045 0304 0334 0045 0334 0304 0112 0334 -0065 0304 0334 0301 -0065 0334 0304 0341 +0113 0301 0334 +0113 0334 0301 0113 0334 0341 0113 0341 0334 0045 0304 0334 0301 @@ -54639,13 +56764,13 @@ FF25 003F 0112 0301 0334 0112 0341 0334 0065 0304 0334 0300 +0065 0304 0334 0340 0065 0334 0304 0300 -0113 0340 0334 -1E15 0334 +0065 0334 0304 0340 0045 0304 0334 0300 -0112 0300 0334 -0112 0334 0300 -0112 0340 0334 +0045 0304 0334 0340 +0045 0334 0304 0300 +0045 0334 0304 0340 0065 0309 0334 0065 0334 0309 1EBB 0334 @@ -54671,13 +56796,13 @@ FF25 003F 0045 0334 0323 1EB8 0334 0065 0302 0334 0323 -0065 0323 0302 0334 -0065 0334 0302 0323 -00EA 0334 0323 +0065 0323 0334 0302 +0065 0334 0323 0302 +1EB9 0334 0302 0045 0302 0323 0334 0045 0302 0334 0323 -0045 0323 0334 0302 -00CA 0323 0334 +0045 0334 0323 0302 +1EB8 0334 0302 0065 032D 0334 0065 0334 032D 1E19 0334 @@ -55654,13 +57779,13 @@ A7A0 003F 1F156 0334 1F136 0334 1F176 0334 +0067 0301 0334 0067 0334 0301 0067 0334 0341 0067 0341 0334 -01F5 0334 0047 0301 0334 +0047 0334 0301 0047 0334 0341 -0047 0341 0334 01F4 0334 0067 0306 0334 0067 0334 0306 @@ -56383,11 +58508,29 @@ A7F8 0062 1E2B 0062 1E2A 0062 1E96 0062 +1F1A6 0021 +1F1A6 003F +1F1A6 0334 +1F1A6 0061 +1F1A6 0041 +1F1A6 0062 +1F1A7 0021 +1F1A7 003F +1F1A7 0334 +1F1A7 0061 +1F1A7 0041 +1F1A7 0062 32CC 0021 32CC 003F 32CC 0061 32CC 0041 32CC 0062 +1F1A8 0021 +1F1A8 003F +1F1A8 0334 +1F1A8 0061 +1F1A8 0041 +1F1A8 0062 33CB 0021 33CB 003F 3371 0021 @@ -56675,20 +58818,20 @@ FF29 003F 1F138 0334 1F178 0334 0069 0301 0334 +0069 0334 0301 0069 0334 0341 -0069 0341 0334 00ED 0334 0049 0301 0334 0049 0334 0301 0049 0334 0341 00CD 0334 0069 0300 0334 +0069 0334 0300 0069 0334 0340 -0069 0340 0334 00EC 0334 +0049 0300 0334 0049 0334 0300 0049 0334 0340 -0049 0340 0334 00CC 0334 0069 0306 0334 0069 0334 0306 @@ -56715,13 +58858,13 @@ FF29 003F 0049 0334 0308 00CF 0334 0069 0308 0301 0334 -0069 0308 0334 0341 00EF 0301 0334 -00EF 0334 0341 +00EF 0341 0334 +1E2F 0334 0049 0308 0334 0301 -0049 0308 0341 0334 -00CF 0334 0301 -1E2E 0334 +0049 0308 0334 0341 +00CF 0301 0334 +00CF 0341 0334 0069 0303 0334 0069 0334 0303 0129 0334 @@ -57088,13 +59231,18 @@ FF29 0062 1D6A4 0062 026A 0021 026A 003F +A7AE 0021 +A7AE 003F 1DA6 0021 1DA6 003F 026A 0061 026A 0041 +A7AE 0061 +A7AE 0041 1DA6 0061 1DA6 0041 026A 0062 +A7AE 0062 1DA6 0062 A7FE 0021 A7FE 003F @@ -57622,10 +59770,10 @@ A7A2 003F 006B 0301 0334 006B 0334 0301 006B 0334 0341 -006B 0341 0334 -004B 0301 0334 -004B 0334 0341 -212A 0334 0341 +1E31 0334 +004B 0334 0301 +1E30 0334 +212A 0301 0334 212A 0341 0334 006B 030C 0334 006B 0334 030C @@ -57638,9 +59786,9 @@ A7A2 003F 006B 0334 0327 0137 0334 004B 0327 0334 -004B 0334 0327 0136 0334 212A 0327 0334 +212A 0334 0327 006B 0323 0334 006B 0334 0323 1E33 0334 @@ -58120,11 +60268,11 @@ FF2C 003F 1F17B 0334 006C 0301 0334 006C 0334 0301 -006C 0341 0334 +006C 0334 0341 013A 0334 004C 0301 0334 +004C 0334 0301 004C 0334 0341 -004C 0341 0334 0139 0334 006C 030C 0334 006C 0334 030C @@ -58145,13 +60293,13 @@ FF2C 003F 004C 0334 0323 1E36 0334 006C 0304 0323 0334 -006C 0323 0304 0334 -006C 0334 0304 0323 006C 0334 0323 0304 -004C 0323 0304 0334 -004C 0334 0304 0323 +1E37 0304 0334 +1E37 0334 0304 +004C 0304 0323 0334 004C 0334 0323 0304 1E36 0304 0334 +1E36 0334 0304 006C 032D 0334 006C 0334 032D 1E3D 0334 @@ -58428,6 +60576,12 @@ FF2C 0062 33D2 0061 33D2 0041 33D2 0062 +1F1A9 0021 +1F1A9 003F +1F1A9 0334 +1F1A9 0061 +1F1A9 0041 +1F1A9 0062 02AA 0021 02AA 003F 02AA 0061 @@ -58750,11 +60904,11 @@ FF2D 003F 1F13C 0334 1F17C 0334 006D 0301 0334 -006D 0334 0341 +006D 0334 0301 006D 0341 0334 1E3F 0334 +004D 0301 0334 004D 0334 0301 -004D 0334 0341 004D 0341 0334 1E3E 0334 006D 0307 0334 @@ -59255,21 +61409,21 @@ A7A4 003F 1F13D 0334 1F17D 0334 006E 0301 0334 -006E 0334 0341 +006E 0334 0301 006E 0341 0334 0144 0334 004E 0301 0334 004E 0334 0301 -004E 0334 0341 +004E 0341 0334 0143 0334 006E 0300 0334 +006E 0334 0300 006E 0334 0340 006E 0340 0334 -01F9 0334 004E 0300 0334 004E 0334 0300 004E 0334 0340 -01F8 0334 +004E 0340 0334 006E 030C 0334 006E 0334 030C 0148 0334 @@ -59847,13 +62001,13 @@ A79C 003F 01FF 003F 01FE 0021 01FE 003F +00F8 0301 0334 00F8 0334 0301 00F8 0334 0341 -00F8 0341 0334 01FF 0334 00D8 0301 0334 +00D8 0334 0301 00D8 0334 0341 -00D8 0341 0334 01FE 0334 01EB 0021 01EB 003F @@ -59951,14 +62105,14 @@ A79C 003F 1F17E 0334 006F 0301 0334 006F 0334 0301 -006F 0334 0341 +006F 0341 0334 00F3 0334 004F 0301 0334 004F 0334 0301 004F 0341 0334 00D3 0334 +006F 0300 0334 006F 0334 0300 -006F 0334 0340 006F 0340 0334 00F2 0334 004F 0300 0334 @@ -59977,36 +62131,36 @@ A79C 003F 004F 0302 0334 004F 0334 0302 00D4 0334 -006F 0302 0334 0301 -006F 0302 0334 0341 +00F4 0301 0334 +00F4 0334 0301 00F4 0334 0341 -00F4 0341 0334 -004F 0302 0334 0341 -004F 0334 0302 0301 -004F 0334 0302 0341 +1ED1 0334 +00D4 0301 0334 +00D4 0334 0301 +00D4 0334 0341 00D4 0341 0334 006F 0302 0334 0300 006F 0302 0334 0340 -00F4 0334 0340 +00F4 0334 0300 1ED3 0334 +004F 0302 0334 0300 +004F 0302 0334 0340 004F 0334 0302 0300 -004F 0334 0302 0340 -00D4 0300 0334 -00D4 0340 0334 +1ED2 0334 006F 0302 0303 0334 -006F 0302 0334 0303 +006F 0334 0302 0303 00F4 0303 0334 -1ED7 0334 +00F4 0334 0303 004F 0302 0303 0334 -004F 0302 0334 0303 004F 0334 0302 0303 -1ED6 0334 +00D4 0303 0334 +00D4 0334 0303 006F 0302 0309 0334 +006F 0302 0334 0309 006F 0334 0302 0309 00F4 0334 0309 -1ED5 0334 004F 0302 0309 0334 -00D4 0309 0334 +004F 0302 0334 0309 00D4 0334 0309 1ED4 0334 006F 030C 0334 @@ -60024,11 +62178,11 @@ A79C 003F 006F 0308 0304 0334 006F 0308 0334 0304 00F6 0304 0334 -022B 0334 +00F6 0334 0304 004F 0308 0334 0304 +004F 0334 0308 0304 00D6 0304 0334 00D6 0334 0304 -022A 0334 006F 030B 0334 006F 0334 030B 0151 0334 @@ -60042,28 +62196,28 @@ A79C 003F 004F 0334 0303 00D5 0334 006F 0303 0301 0334 -006F 0303 0341 0334 -00F5 0301 0334 00F5 0334 0301 -004F 0303 0334 0301 -004F 0303 0341 0334 +00F5 0334 0341 +1E4D 0334 004F 0334 0303 0301 004F 0334 0303 0341 -006F 0303 0308 0334 +00D5 0334 0301 +00D5 0334 0341 +006F 0303 0334 0308 006F 0334 0303 0308 00F5 0308 0334 -00F5 0334 0308 +1E4F 0334 +004F 0303 0334 0308 004F 0334 0303 0308 00D5 0308 0334 -00D5 0334 0308 1E4E 0334 -006F 0303 0304 0334 -006F 0303 0334 0304 +006F 0334 0303 0304 +00F5 0304 0334 00F5 0334 0304 022D 0334 -004F 0303 0304 0334 -004F 0303 0334 0304 004F 0334 0303 0304 +00D5 0304 0334 +00D5 0334 0304 022C 0334 006F 0307 0334 006F 0334 0307 @@ -60072,27 +62226,27 @@ A79C 003F 004F 0334 0307 022E 0334 006F 0307 0304 0334 -006F 0334 0307 0304 -022F 0304 0334 +006F 0307 0334 0304 022F 0334 0304 -004F 0307 0304 0334 +0231 0334 004F 0334 0307 0304 022E 0304 0334 022E 0334 0304 +0230 0334 006F 0328 0334 006F 0334 0328 01EB 0334 004F 0328 0334 004F 0334 0328 01EA 0334 -006F 0304 0328 0334 006F 0304 0334 0328 -006F 0334 0328 0304 -01EB 0334 0304 +006F 0334 0304 0328 +014D 0334 0328 +01ED 0334 004F 0304 0334 0328 -004F 0328 0334 0304 +004F 0334 0328 0304 014C 0334 0328 -01EA 0334 0304 +01EC 0334 006F 0304 0334 006F 0334 0304 014D 0334 @@ -60101,20 +62255,20 @@ A79C 003F 014C 0334 006F 0304 0301 0334 014D 0301 0334 -014D 0334 0341 +014D 0341 0334 1E53 0334 004F 0304 0301 0334 004F 0334 0304 0301 004F 0334 0304 0341 -014C 0341 0334 +1E52 0334 +006F 0304 0300 0334 014D 0300 0334 -014D 0334 0340 014D 0340 0334 1E51 0334 -004F 0304 0300 0334 004F 0334 0304 0300 004F 0334 0304 0340 014C 0300 0334 +014C 0340 0334 006F 0309 0334 006F 0334 0309 1ECF 0334 @@ -60139,45 +62293,45 @@ A79C 003F 004F 031B 0334 004F 0334 031B 01A0 0334 -006F 0301 0334 031B 006F 031B 0301 0334 -006F 031B 0334 0341 -00F3 0334 031B -004F 0301 0334 031B -004F 031B 0341 0334 +006F 031B 0341 0334 +006F 0334 0301 031B +006F 0334 0341 031B +004F 0301 031B 0334 004F 0341 0334 031B +01A0 0334 0301 01A0 0334 0341 +006F 0300 0334 031B +006F 031B 0334 0300 006F 031B 0334 0340 -006F 031B 0340 0334 006F 0340 0334 031B -01A1 0340 0334 -004F 0300 0334 031B -01A0 0334 0340 -01A0 0340 0334 -1EDC 0334 -006F 0303 031B 0334 -006F 031B 0334 0303 +004F 0300 031B 0334 +004F 0340 0334 031B +00D2 031B 0334 +01A0 0334 0300 +006F 031B 0303 0334 006F 0334 0303 031B -01A1 0334 0303 -004F 0334 031B 0303 -00D5 031B 0334 -00D5 0334 031B -01A0 0303 0334 +006F 0334 031B 0303 +1EE1 0334 +004F 0303 031B 0334 +004F 0303 0334 031B +004F 031B 0303 0334 +004F 031B 0334 0303 006F 0334 0309 031B -006F 0334 031B 0309 01A1 0334 0309 1ECF 0334 031B -004F 0309 0334 031B -01A0 0309 0334 +1EDF 0334 +004F 0334 031B 0309 01A0 0334 0309 +1ECE 031B 0334 1ECE 0334 031B -006F 031B 0323 0334 -006F 031B 0334 0323 -006F 0323 031B 0334 -01A1 0323 0334 -004F 0323 0334 031B -004F 0334 031B 0323 -01A0 0334 0323 +006F 0334 0323 031B +1ECD 031B 0334 +1ECD 0334 031B +1EE3 0334 +004F 031B 0323 0334 +004F 031B 0334 0323 +1ECC 031B 0334 1EE2 0334 006F 0323 0334 006F 0334 0323 @@ -60185,14 +62339,14 @@ A79C 003F 004F 0323 0334 004F 0334 0323 1ECC 0334 -006F 0302 0323 0334 -006F 0302 0334 0323 -006F 0334 0323 0302 -1ECD 0334 0302 -004F 0302 0323 0334 -004F 0323 0302 0334 -1ECC 0302 0334 -1ECC 0334 0302 +006F 0334 0302 0323 +00F4 0323 0334 +00F4 0334 0323 +1ED9 0334 +004F 0323 0334 0302 +004F 0334 0323 0302 +00D4 0323 0334 +00D4 0334 0323 0334 0366 0366 0334 0334 1DF3 @@ -60908,8 +63062,8 @@ FF30 003F 1F18A 0334 0070 0301 0334 0070 0334 0301 -0070 0334 0341 0070 0341 0334 +1E55 0334 0050 0301 0334 0050 0334 0301 0050 0341 0334 @@ -61632,12 +63786,12 @@ A7A6 003F 1F181 0334 0072 0301 0334 0072 0334 0301 +0072 0334 0341 0072 0341 0334 -0155 0334 0052 0301 0334 0052 0334 0301 -0052 0334 0341 0052 0341 0334 +0154 0334 0072 030C 0334 0072 0334 030C 0159 0334 @@ -61674,14 +63828,14 @@ A7A6 003F 0052 0323 0334 0052 0334 0323 1E5A 0334 -0072 0323 0304 0334 +0072 0334 0304 0323 0072 0334 0323 0304 1E5B 0334 0304 1E5D 0334 +0052 0304 0334 0323 0052 0323 0304 0334 +0052 0323 0334 0304 0052 0334 0304 0323 -0052 0334 0323 0304 -1E5C 0334 0072 0331 0334 0072 0334 0331 1E5F 0334 @@ -62263,21 +64417,21 @@ A7A8 003F 1F142 0334 1F182 0334 0073 0301 0334 +0073 0334 0301 0073 0334 0341 0073 0341 0334 -015B 0334 +0053 0301 0334 0053 0334 0301 0053 0334 0341 0053 0341 0334 -015A 0334 0073 0301 0307 0334 0073 0334 0301 0307 0073 0334 0341 0307 -1E65 0334 +0073 0341 0334 0307 0053 0301 0334 0307 -0053 0334 0301 0307 -0053 0341 0307 0334 0053 0341 0334 0307 +015A 0307 0334 +1E64 0334 0073 0302 0334 0073 0334 0302 015D 0334 @@ -62292,12 +64446,12 @@ A7A8 003F 0160 0334 0073 030C 0307 0334 0073 030C 0334 0307 -0073 0334 030C 0307 +0161 0307 0334 0161 0334 0307 0053 030C 0307 0334 -0053 030C 0334 0307 -0053 0334 030C 0307 0160 0307 0334 +0160 0334 0307 +1E66 0334 0073 0307 0334 0073 0334 0307 1E61 0334 @@ -62317,13 +64471,13 @@ A7A8 003F 0053 0334 0323 1E62 0334 0073 0323 0334 0307 -0073 0334 0323 0307 +1E61 0323 0334 1E61 0334 0323 1E63 0307 0334 -0053 0323 0307 0334 -0053 0334 0307 0323 -1E62 0307 0334 -1E62 0334 0307 +0053 0307 0323 0334 +0053 0307 0334 0323 +0053 0323 0334 0307 +1E60 0323 0334 0073 0326 0334 0073 0334 0326 0219 0334 @@ -62563,6 +64717,12 @@ A784 0062 1F14C 0061 1F14C 0041 1F14C 0062 +1F1AA 0021 +1F1AA 003F +1F1AA 0334 +1F1AA 0061 +1F1AA 0041 +1F1AA 0062 2120 0021 2120 003F 2120 0061 @@ -63451,7 +65611,7 @@ A79E 003F 0055 0301 0334 0055 0334 0301 0055 0334 0341 -00DA 0334 +0055 0341 0334 0075 0300 0334 0075 0334 0300 0075 0334 0340 @@ -63459,7 +65619,7 @@ A79E 003F 0055 0300 0334 0055 0334 0300 0055 0334 0340 -00D9 0334 +0055 0340 0334 0075 0306 0334 0075 0334 0306 016D 0334 @@ -63490,38 +65650,38 @@ A79E 003F 0055 0308 0334 0055 0334 0308 00DC 0334 +0075 0308 0301 0334 0075 0308 0334 0301 -0075 0334 0344 -0075 0344 0334 -01D8 0334 -0055 0308 0301 0334 -0055 0334 0308 0301 -00DC 0301 0334 +0075 0308 0334 0341 +0075 0308 0341 0334 +0055 0334 0344 +0055 0344 0334 00DC 0334 0301 -0075 0308 0340 0334 +00DC 0334 0341 +0075 0334 0308 0300 0075 0334 0308 0340 00FC 0300 0334 -00FC 0334 0340 -0055 0308 0300 0334 -0055 0308 0334 0300 -0055 0308 0340 0334 -00DC 0334 0300 -0075 0308 0334 030C +00FC 0340 0334 +0055 0334 0308 0300 +0055 0334 0308 0340 +00DC 0300 0334 +00DC 0340 0334 0075 0334 0308 030C +00FC 030C 0334 00FC 0334 030C 01DA 0334 0055 0308 030C 0334 -0055 0308 0334 030C +0055 0334 0308 030C 00DC 030C 0334 -01D9 0334 +00DC 0334 030C 0075 0308 0304 0334 0075 0308 0334 0304 00FC 0304 0334 -01D6 0334 +00FC 0334 0304 +0055 0308 0304 0334 0055 0308 0334 0304 0055 0334 0308 0304 00DC 0334 0304 -01D5 0334 0075 030B 0334 0075 0334 030B 0171 0334 @@ -63534,14 +65694,14 @@ A79E 003F 0055 0303 0334 0055 0334 0303 0168 0334 -0075 0303 0334 0301 -0075 0303 0334 0341 -0169 0301 0334 +0075 0303 0301 0334 +0075 0303 0341 0334 +0169 0334 0301 0169 0334 0341 0055 0303 0301 0334 -0055 0303 0334 0301 -0168 0301 0334 -1E78 0334 +0055 0303 0341 0334 +0168 0334 0301 +0168 0334 0341 0075 0328 0334 0075 0334 0328 0173 0334 @@ -63554,14 +65714,14 @@ A79E 003F 0055 0304 0334 0055 0334 0304 016A 0334 -0075 0304 0308 0334 0075 0304 0334 0308 +0075 0334 0304 0308 016B 0308 0334 -1E7B 0334 +016B 0334 0308 +0055 0304 0308 0334 0055 0304 0334 0308 0055 0334 0304 0308 016A 0308 0334 -016A 0334 0308 0075 0309 0334 0075 0334 0309 1EE7 0334 @@ -63586,46 +65746,46 @@ A79E 003F 0055 031B 0334 0055 0334 031B 01AF 0334 -0075 0301 0334 031B -0075 031B 0341 0334 -01B0 0301 0334 -1EE9 0334 -0055 0334 0341 031B -01AF 0334 0301 -01AF 0334 0341 -1EE8 0334 -0075 031B 0340 0334 -0075 0334 0340 031B -0075 0340 0334 031B -00F9 031B 0334 -0055 0300 031B 0334 -00D9 0334 031B -01AF 0334 0340 -01AF 0340 0334 -0075 0303 031B 0334 +0075 0301 031B 0334 +0075 0334 031B 0301 +0075 0334 031B 0341 +0075 0341 031B 0334 +0055 0301 0334 031B +0055 031B 0334 0301 +0055 031B 0334 0341 +0055 0341 0334 031B +0075 0300 031B 0334 +00F9 0334 031B +01B0 0300 0334 +01B0 0340 0334 +0055 0300 0334 031B +0055 031B 0334 0300 +0055 031B 0334 0340 +0055 0340 0334 031B +0075 0303 0334 031B 0075 031B 0334 0303 +0075 0334 031B 0303 0169 0334 031B -01B0 0303 0334 -0055 0303 0334 031B 0055 031B 0303 0334 -01AF 0303 0334 -01AF 0334 0303 -0075 0309 0334 031B -01B0 0309 0334 +0055 0334 0303 031B +0055 0334 031B 0303 +0168 031B 0334 +0075 031B 0309 0334 +0075 0334 0309 031B 01B0 0334 0309 -1EE7 0334 031B +1EED 0334 0055 031B 0309 0334 -0055 031B 0334 0309 -0055 0334 031B 0309 -01AF 0309 0334 -0075 031B 0323 0334 +0055 0334 0309 031B +01AF 0334 0309 +1EE6 0334 031B 0075 031B 0334 0323 0075 0323 0334 031B 0075 0334 031B 0323 +1EF1 0334 +0055 031B 0323 0334 0055 0323 031B 0334 -01AF 0323 0334 -01AF 0334 0323 -1EE4 031B 0334 +0055 0334 031B 0323 +0055 0334 0323 031B 0075 0323 0334 0075 0334 0323 1EE5 0334 @@ -63971,6 +66131,12 @@ A79E 0062 1E76 0062 1E75 0062 1E74 0062 +1F1AB 0021 +1F1AB 003F +1F1AB 0334 +1F1AB 0061 +1F1AB 0041 +1F1AB 0062 1F199 0334 1F199 0021 1F199 003F @@ -64456,6 +66622,12 @@ FF36 0062 33DE 0061 33DE 0041 33DE 0062 +1F1AC 0021 +1F1AC 003F +1F1AC 0334 +1F1AC 0061 +1F1AC 0041 +1F1AC 0062 1F19A 0021 1F19A 003F 1F19A 0334 @@ -64679,20 +66851,20 @@ FF37 003F 1F146 0334 1F186 0334 0077 0301 0334 +0077 0334 0301 0077 0334 0341 -0077 0341 0334 1E83 0334 0057 0301 0334 0057 0334 0301 0057 0334 0341 -0057 0341 0334 +1E82 0334 0077 0300 0334 0077 0334 0300 0077 0334 0340 -0077 0340 0334 +1E81 0334 0057 0300 0334 +0057 0334 0300 0057 0334 0340 -0057 0340 0334 1E80 0334 0077 0302 0334 0077 0334 0302 @@ -65411,18 +67583,18 @@ FF39 003F 0079 0301 0334 0079 0334 0301 0079 0334 0341 -0079 0341 0334 +00FD 0334 0059 0301 0334 0059 0334 0301 -0059 0341 0334 +0059 0334 0341 00DD 0334 +0079 0300 0334 0079 0334 0300 0079 0334 0340 -0079 0340 0334 1EF3 0334 +0059 0300 0334 0059 0334 0300 0059 0334 0340 -0059 0340 0334 1EF2 0334 0079 0302 0334 0079 0334 0302 @@ -65822,11 +67994,11 @@ FF3A 003F 1F189 0334 007A 0301 0334 007A 0334 0301 -007A 0341 0334 +007A 0334 0341 017A 0334 005A 0301 0334 +005A 0334 0301 005A 0334 0341 -005A 0341 0334 0179 0334 007A 0302 0334 007A 0334 0302 @@ -66639,63 +68811,63 @@ A724 0062 0391 0313 0334 0391 0334 0313 0391 0334 0343 -1F08 0334 -03B1 0313 0341 0334 -03B1 0334 0343 0301 -03B1 0334 0343 0341 -1F00 0334 0301 -0391 0334 0313 0301 -0391 0334 0313 0341 -1F08 0301 0334 -1F0C 0334 -03B1 0334 0313 0301 0345 -03B1 0334 0345 0313 0301 -03B1 0343 0301 0345 0334 -1F00 0334 0345 0301 -0391 0334 0343 0301 0345 -0391 0343 0334 0345 0341 -0391 0345 0313 0334 0341 -1FBC 0334 0343 0341 -03B1 0334 0343 0300 -03B1 0334 0343 0340 -1F00 0334 0300 -1F02 0334 -0391 0334 0313 0300 -0391 0334 0313 0340 -1F08 0300 0334 -1F0A 0334 -03B1 0343 0300 0345 0334 -03B1 0343 0345 0334 0340 -03B1 0345 0313 0300 0334 -1F00 0345 0340 0334 -0391 0343 0334 0345 0340 -0391 0345 0313 0334 0340 -1F08 0300 0345 0334 -1FBC 0334 0343 0340 +0391 0343 0334 +03B1 0343 0334 0301 +03B1 0343 0334 0341 +1F00 0301 0334 +1F00 0341 0334 +0391 0313 0334 0301 +0391 0313 0334 0341 +1F08 0334 0301 +1F08 0334 0341 +03B1 0345 0334 0313 0341 +03B1 0345 0343 0334 0301 +1FB3 0334 0343 0341 +1FB3 0343 0334 0341 +0391 0313 0341 0334 0345 +0391 0313 0345 0334 0341 +0391 0313 0345 0341 0334 +0391 0334 0345 0343 0341 +03B1 0343 0334 0300 +03B1 0343 0334 0340 +1F00 0300 0334 +1F00 0340 0334 +0391 0313 0334 0300 +0391 0313 0334 0340 +1F08 0334 0300 +1F08 0334 0340 +03B1 0313 0334 0340 0345 +03B1 0313 0345 0300 0334 +03B1 0345 0334 0313 0340 +1FB3 0313 0300 0334 +0391 0334 0313 0345 0340 +0391 0345 0313 0334 0300 +1F88 0340 0334 +1FBC 0343 0300 0334 03B1 0313 0334 0342 -03B1 0313 0342 0334 03B1 0334 0343 0342 -03B1 0343 0342 0334 +03B1 0343 0334 0342 +1F00 0342 0334 0391 0334 0313 0342 -0391 0343 0334 0342 -0391 0343 0342 0334 -1F08 0342 0334 -03B1 0334 0343 0342 0345 -03B1 0345 0343 0342 0334 -1F00 0334 0345 0342 -1FB3 0343 0342 0334 -0391 0345 0313 0334 0342 -1F08 0342 0345 0334 -1FBC 0313 0334 0342 -1FBC 0334 0343 0342 -03B1 0313 0334 0345 -03B1 0343 0334 0345 -03B1 0345 0313 0334 -03B1 0345 0343 0334 -0391 0334 0313 0345 -0391 0334 0345 0343 -0391 0345 0313 0334 -1FBC 0334 0313 +0391 0334 0343 0342 +1F08 0334 0342 +1F0E 0334 +03B1 0313 0334 0342 0345 +03B1 0313 0345 0342 0334 +03B1 0345 0334 0313 0342 +1F80 0342 0334 +0391 0313 0342 0334 0345 +0391 0313 0345 0334 0342 +0391 0334 0345 0343 0342 +1FBC 0343 0342 0334 +03B1 0313 0345 0334 +1F00 0334 0345 +1FB3 0313 0334 +1FB3 0334 0313 +0391 0343 0334 0345 +0391 0345 0334 0343 +1F08 0345 0334 +1FBC 0313 0334 03B1 0314 0334 03B1 0334 0314 1F01 0334 @@ -66703,85 +68875,85 @@ A724 0062 0391 0334 0314 1F09 0334 03B1 0314 0334 0301 -03B1 0334 0314 0341 +03B1 0334 0314 0301 1F01 0301 0334 -1F05 0334 -0391 0314 0301 0334 -0391 0334 0314 0301 -0391 0334 0314 0341 -1F09 0341 0334 -03B1 0334 0314 0301 0345 -03B1 0334 0314 0345 0301 -03B1 0345 0334 0314 0341 -1F01 0334 0341 0345 -0391 0334 0314 0341 0345 -1F09 0301 0334 0345 -1F09 0334 0345 0301 -1F09 0345 0341 0334 -03B1 0314 0300 0334 -03B1 0314 0334 0340 -03B1 0314 0340 0334 -03B1 0334 0314 0300 -0391 0314 0334 0300 -0391 0314 0334 0340 -1F09 0300 0334 -1F09 0340 0334 -03B1 0314 0334 0300 0345 -03B1 0314 0345 0340 0334 -1F81 0340 0334 -1F83 0334 -0391 0334 0345 0314 0300 -1F09 0334 0345 0300 -1F0B 0345 0334 -1FBC 0314 0300 0334 +1F01 0341 0334 +1F09 0301 0334 +1F09 0334 0301 +1F09 0334 0341 +1F0D 0334 +03B1 0314 0334 0341 0345 +03B1 0314 0345 0301 0334 +1F01 0301 0345 0334 +1F01 0334 0345 0341 +0391 0345 0334 0314 0301 +1F09 0301 0345 0334 +1F09 0334 0341 0345 +1F09 0345 0334 0301 +03B1 0314 0334 0300 +1F01 0300 0334 +1F01 0340 0334 +1F03 0334 +0391 0334 0314 0300 +0391 0334 0314 0340 +1F09 0334 0300 +1F09 0334 0340 +1F01 0334 0345 0340 +1F01 0340 0345 0334 +1F81 0300 0334 +1FB3 0314 0340 0334 +0391 0314 0334 0340 0345 +0391 0314 0345 0300 0334 +1F09 0340 0334 0345 +1F09 0345 0334 0300 03B1 0314 0334 0342 -03B1 0314 0342 0334 03B1 0334 0314 0342 +1F01 0334 0342 1F01 0342 0334 -0391 0314 0342 0334 +0391 0314 0334 0342 0391 0334 0314 0342 -1F09 0342 0334 +1F09 0334 0342 1F0F 0334 03B1 0314 0342 0334 0345 -03B1 0314 0345 0342 0334 -03B1 0345 0334 0314 0342 +03B1 0314 0345 0334 0342 1F81 0342 0334 -0391 0314 0342 0334 0345 +1FB3 0314 0342 0334 +0391 0314 0334 0342 0345 0391 0314 0345 0342 0334 -1F09 0342 0334 0345 -1F8F 0334 -03B1 0334 0314 0345 -03B1 0334 0345 0314 +1F09 0334 0345 0342 +1F09 0342 0345 0334 1F01 0345 0334 +1F81 0334 1FB3 0314 0334 -0391 0334 0314 0345 -0391 0345 0314 0334 -1F09 0334 0345 +1FB3 0334 0314 +0391 0314 0345 0334 +0391 0334 0345 0314 1F89 0334 +1FBC 0334 0314 03AC 0334 -03B1 0301 0334 -03B1 0341 0334 +03B1 0334 0301 +03B1 0334 0341 1F71 0334 0391 0301 0334 0391 0334 0301 0391 0334 0341 0391 0341 0334 -03AC 0345 0334 -03B1 0301 0334 0345 -03B1 0301 0345 0334 -03B1 0334 0341 0345 +03B1 0334 0345 0301 +03B1 0334 0345 0341 +03B1 0341 0345 0334 +1FB4 0334 03B1 0300 0334 03B1 0334 0300 03B1 0334 0340 1F70 0334 +0391 0300 0334 0391 0334 0300 0391 0334 0340 0391 0340 0334 -1FBA 0334 -03B1 0334 0300 0345 -03B1 0340 0334 0345 -03B1 0345 0300 0334 -1FB3 0300 0334 +03B1 0334 0345 0300 +03B1 0334 0345 0340 +03B1 0340 0345 0334 +1FB2 0334 03B1 0306 0334 03B1 0334 0306 1FB0 0334 @@ -66791,10 +68963,10 @@ A724 0062 03B1 0334 0342 03B1 0342 0334 1FB6 0334 -03B1 0334 0342 0345 +1FB3 0334 0342 1FB3 0342 0334 1FB6 0334 0345 -1FB7 0334 +1FB6 0345 0334 03B1 0304 0334 03B1 0334 0304 1FB1 0334 @@ -67338,63 +69510,63 @@ A724 0062 03B5 0343 0334 1F10 0334 0395 0313 0334 +0395 0334 0313 0395 0334 0343 0395 0343 0334 -1F18 0334 -03B5 0313 0301 0334 -03B5 0343 0301 0334 -03B5 0343 0341 0334 -1F10 0334 0301 -0395 0313 0341 0334 -0395 0343 0334 0341 -1F18 0301 0334 -1F18 0334 0301 -03B5 0313 0300 0334 +03B5 0334 0343 0301 +03B5 0334 0343 0341 +03B5 0343 0334 0301 +1F14 0334 +0395 0313 0334 0301 +0395 0313 0334 0341 +0395 0334 0313 0301 +0395 0334 0313 0341 +03B5 0334 0343 0300 +03B5 0343 0334 0300 03B5 0343 0334 0340 -1F10 0334 0300 -1F10 0334 0340 +1F12 0334 +0395 0313 0334 0300 0395 0313 0334 0340 -0395 0313 0340 0334 -0395 0343 0334 0340 -1F18 0334 0300 +0395 0334 0313 0300 +0395 0334 0313 0340 03B5 0314 0334 03B5 0334 0314 1F11 0334 0395 0314 0334 0395 0334 0314 1F19 0334 -03B5 0314 0334 0341 -03B5 0314 0341 0334 +03B5 0314 0334 0301 03B5 0334 0314 0301 -1F15 0334 +1F11 0301 0334 +1F11 0341 0334 0395 0314 0334 0301 0395 0314 0334 0341 0395 0334 0314 0301 -1F19 0341 0334 -03B5 0314 0300 0334 +0395 0334 0314 0341 03B5 0314 0334 0300 03B5 0314 0334 0340 03B5 0334 0314 0300 -0395 0314 0334 0340 -0395 0314 0340 0334 +03B5 0334 0314 0340 0395 0334 0314 0300 -1F19 0340 0334 +0395 0334 0314 0340 +1F19 0334 0300 +1F19 0334 0340 03AD 0334 -03B5 0334 0301 -03B5 0334 0341 +03B5 0301 0334 +03B5 0341 0334 1F73 0334 0388 0334 0395 0301 0334 -0395 0334 0301 +0395 0341 0334 1FC9 0334 +03B5 0300 0334 03B5 0334 0300 -03B5 0334 0340 03B5 0340 0334 1F72 0334 0395 0300 0334 0395 0334 0300 +0395 0334 0340 0395 0340 0334 -1FC8 0334 03B5 0061 03B5 0041 03F5 0061 @@ -67743,162 +69915,162 @@ A724 0062 1D722 0334 1D75C 0334 1D796 0334 +03B7 0313 0334 03B7 0334 0313 -03B7 0334 0343 03B7 0343 0334 1F20 0334 0397 0313 0334 0397 0334 0313 0397 0334 0343 -1F28 0334 -03B7 0334 0313 0341 -03B7 0334 0343 0341 +0397 0343 0334 +03B7 0343 0301 0334 +03B7 0343 0334 0301 +03B7 0343 0334 0341 03B7 0343 0341 0334 -1F20 0341 0334 -0397 0313 0334 0301 +0397 0313 0301 0334 0397 0313 0341 0334 -0397 0334 0313 0301 -0397 0334 0313 0341 -03B7 0313 0301 0334 0345 -03B7 0313 0345 0334 0301 -03B7 0343 0341 0334 0345 -03B7 0345 0343 0341 0334 -0397 0343 0334 0341 0345 -0397 0343 0334 0345 0341 -1FCC 0313 0341 0334 -1FCC 0343 0341 0334 -03B7 0334 0313 0340 -03B7 0334 0343 0340 +1F28 0334 0301 +1F28 0334 0341 +03B7 0345 0343 0334 0341 +1F20 0301 0345 0334 +1F20 0345 0334 0301 +1FC3 0313 0334 0301 +0397 0334 0313 0345 0301 +1F28 0334 0341 0345 +1F28 0345 0301 0334 +1FCC 0343 0334 0301 +03B7 0343 0334 0300 +03B7 0343 0334 0340 1F20 0300 0334 -1F20 0334 0340 -0397 0313 0300 0334 +1F20 0340 0334 0397 0334 0313 0300 0397 0334 0313 0340 -0397 0343 0300 0334 -03B7 0313 0345 0334 0300 -03B7 0313 0345 0340 0334 -03B7 0343 0345 0340 0334 -1FC3 0334 0313 0300 -0397 0313 0334 0300 0345 -0397 0343 0334 0345 0340 -0397 0343 0340 0345 0334 -1F28 0300 0334 0345 +1F28 0334 0300 +1F28 0334 0340 +03B7 0334 0313 0340 0345 +03B7 0343 0334 0345 0340 +03B7 0345 0334 0343 0340 +1FC3 0313 0334 0300 +0397 0334 0313 0345 0300 +0397 0345 0313 0334 0340 +1FCC 0334 0343 0300 +1FCC 0343 0334 0300 03B7 0313 0342 0334 03B7 0334 0313 0342 -1F20 0334 0342 -1F20 0342 0334 +03B7 0334 0343 0342 +03B7 0343 0342 0334 +0397 0313 0342 0334 0397 0334 0313 0342 -0397 0343 0334 0342 -1F28 0334 0342 -1F2E 0334 -03B7 0313 0345 0334 0342 -03B7 0313 0345 0342 0334 -03B7 0334 0313 0342 0345 -1F20 0334 0345 0342 -0397 0334 0343 0342 0345 -0397 0343 0334 0345 0342 -1F28 0334 0345 0342 -1F28 0342 0345 0334 +0397 0334 0343 0342 +0397 0343 0342 0334 +03B7 0345 0343 0334 0342 +1F20 0342 0334 0345 +1F20 0345 0334 0342 +1F26 0345 0334 +0397 0334 0313 0345 0342 +1F2E 0345 0334 +1FCC 0334 0343 0342 +1FCC 0343 0334 0342 03B7 0334 0343 0345 +03B7 0343 0334 0345 +03B7 0345 0334 0343 03B7 0345 0343 0334 -1FC3 0313 0334 -1FC3 0343 0334 +0397 0313 0334 0345 0397 0334 0313 0345 0397 0345 0313 0334 -1FCC 0313 0334 -1FCC 0343 0334 +1F28 0345 0334 03B7 0314 0334 03B7 0334 0314 1F21 0334 0397 0314 0334 0397 0334 0314 1F29 0334 -03B7 0314 0301 0334 -03B7 0314 0341 0334 +03B7 0314 0334 0301 03B7 0334 0314 0301 -1F21 0334 0341 -0397 0314 0301 0334 +1F21 0301 0334 +1F21 0341 0334 0397 0334 0314 0301 1F29 0334 0301 +1F29 0334 0341 1F2D 0334 -03B7 0314 0301 0345 0334 -03B7 0314 0334 0345 0301 -03B7 0314 0334 0345 0341 -03B7 0314 0345 0334 0301 -0397 0314 0334 0345 0341 -0397 0334 0314 0345 0301 -1F29 0334 0301 0345 -1F29 0341 0345 0334 -03B7 0334 0314 0300 -03B7 0334 0314 0340 -1F21 0334 0300 -1F21 0334 0340 +1F25 0334 0345 +1F25 0345 0334 +1FC3 0314 0334 0341 +1FC3 0334 0314 0301 +0397 0334 0314 0345 0341 +0397 0334 0345 0314 0341 +0397 0345 0314 0301 0334 +1F2D 0345 0334 +03B7 0314 0334 0300 +1F21 0300 0334 +1F21 0340 0334 +1F23 0334 +0397 0314 0334 0300 0397 0314 0334 0340 -0397 0334 0314 0300 1F29 0334 0300 -1F2B 0334 -03B7 0314 0334 0345 0340 -03B7 0314 0345 0340 0334 -1F21 0300 0334 0345 -1FC3 0314 0334 0300 -0397 0314 0340 0334 0345 -0397 0334 0314 0345 0300 -1F29 0334 0340 0345 -1F9B 0334 +1F29 0334 0340 +1F23 0334 0345 +1F93 0334 +1FC3 0314 0334 0340 +1FC3 0334 0314 0300 +0397 0334 0314 0345 0340 +0397 0334 0345 0314 0340 +1F29 0334 0300 0345 +1F29 0345 0340 0334 03B7 0314 0334 0342 +03B7 0314 0342 0334 03B7 0334 0314 0342 -1F21 0334 0342 1F21 0342 0334 0397 0314 0334 0342 +0397 0314 0342 0334 0397 0334 0314 0342 1F29 0334 0342 -1F29 0342 0334 -03B7 0314 0334 0345 0342 -1F21 0334 0345 0342 -1F27 0334 0345 -1F97 0334 -0397 0314 0334 0345 0342 -0397 0314 0342 0334 0345 +03B7 0334 0314 0342 0345 +1F27 0345 0334 +1FC3 0314 0334 0342 +1FC3 0334 0314 0342 +0397 0334 0314 0345 0342 +0397 0334 0345 0314 0342 +0397 0345 0314 0334 0342 1F2F 0345 0334 -1FCC 0314 0342 0334 -03B7 0314 0334 0345 +03B7 0314 0345 0334 03B7 0334 0314 0345 -03B7 0345 0314 0334 -1FC3 0334 0314 +03B7 0334 0345 0314 +1F91 0334 0397 0314 0345 0334 0397 0334 0314 0345 0397 0345 0314 0334 -1FCC 0314 0334 +0397 0345 0334 0314 +03AE 0334 03B7 0301 0334 -03B7 0334 0341 +03B7 0334 0301 03B7 0341 0334 -1F75 0334 -0389 0334 +0397 0301 0334 0397 0334 0301 0397 0334 0341 -1FCB 0334 -03B7 0334 0301 0345 -03B7 0334 0345 0301 -03B7 0345 0334 0341 -1FC3 0334 0301 +0397 0341 0334 +03B7 0301 0334 0345 +03B7 0301 0345 0334 +1FC3 0301 0334 +1FC3 0341 0334 03B7 0300 0334 03B7 0334 0300 -03B7 0334 0340 03B7 0340 0334 +1F74 0334 +0397 0300 0334 0397 0334 0300 -0397 0334 0340 0397 0340 0334 1FCA 0334 -03B7 0334 0345 0300 -03B7 0340 0334 0345 -03B7 0345 0334 0340 -1FC2 0334 +03B7 0300 0334 0345 +03B7 0300 0345 0334 +1FC3 0300 0334 +1FC3 0340 0334 03B7 0334 0342 03B7 0342 0334 1FC6 0334 -03B7 0342 0345 0334 +03B7 0342 0334 0345 03B7 0345 0334 0342 -1FC3 0342 0334 +1FC6 0334 0345 1FC6 0345 0334 03B7 0334 0345 03B7 0345 0334 @@ -68327,96 +70499,96 @@ A724 0062 1D724 0334 1D75E 0334 1D798 0334 +03B9 0313 0334 03B9 0334 0313 03B9 0334 0343 -1FBE 0313 0334 -1FBE 0343 0334 +03B9 0343 0334 0399 0313 0334 +0399 0334 0313 0399 0334 0343 0399 0343 0334 -1F38 0334 +03B9 0334 0343 0301 +03B9 0343 0301 0334 +03B9 0343 0341 0334 1F34 0334 -1FBE 0313 0334 0301 -1FBE 0313 0334 0341 -1FBE 0343 0341 0334 0399 0313 0301 0334 -0399 0343 0341 0334 -1F38 0341 0334 -1F3C 0334 +0399 0313 0341 0334 +0399 0334 0313 0301 +0399 0334 0313 0341 03B9 0334 0343 0300 -1F30 0340 0334 -1FBE 0313 0334 0300 -1FBE 0313 0334 0340 +1F32 0334 +1FBE 0343 0300 0334 +1FBE 0343 0340 0334 0399 0313 0300 0334 -0399 0343 0340 0334 -1F38 0340 0334 -1F3A 0334 -1FBE 0313 0334 0342 -1FBE 0313 0342 0334 -1FBE 0334 0313 0342 +0399 0313 0340 0334 +0399 0334 0313 0300 +0399 0334 0313 0340 +03B9 0334 0343 0342 +03B9 0343 0334 0342 +03B9 0343 0342 0334 1FBE 0343 0334 0342 0399 0313 0342 0334 0399 0334 0313 0342 +0399 0343 0342 0334 1F38 0334 0342 -1F3E 0334 03B9 0314 0334 03B9 0334 0314 1F31 0334 -1FBE 0314 0334 +1FBE 0334 0314 0399 0314 0334 0399 0334 0314 1F39 0334 -03B9 0314 0301 0334 -03B9 0314 0341 0334 -1F31 0341 0334 -1FBE 0334 0314 0301 +1F31 0334 0301 +1F31 0334 0341 +1FBE 0314 0301 0334 +1FBE 0314 0341 0334 0399 0314 0301 0334 0399 0314 0341 0334 1F39 0334 0301 -1F39 0341 0334 -03B9 0314 0340 0334 +1F39 0334 0341 +1F31 0300 0334 +1F31 0334 0300 +1F31 0334 0340 1F33 0334 -1FBE 0314 0334 0340 -1FBE 0334 0314 0300 -0399 0314 0334 0300 -0399 0314 0334 0340 -1F39 0300 0334 +0399 0314 0300 0334 +0399 0314 0340 0334 1F39 0334 0300 +1F39 0334 0340 +03B9 0314 0334 0342 03B9 0314 0342 0334 03B9 0334 0314 0342 -1F31 0334 0342 -1F31 0342 0334 +1FBE 0314 0342 0334 0399 0314 0342 0334 0399 0334 0314 0342 -1F39 0342 0334 +1F39 0334 0342 1F3F 0334 +03AF 0334 03B9 0301 0334 -1FBE 0334 0301 -1FBE 0334 0341 -1FBE 0341 0334 +03B9 0341 0334 +1FBE 0301 0334 038A 0334 -0399 0334 0301 -0399 0334 0341 +0399 0301 0334 +0399 0341 0334 1FDB 0334 +03B9 0300 0334 03B9 0340 0334 -1F76 0334 1FBE 0300 0334 1FBE 0340 0334 0399 0300 0334 0399 0334 0300 0399 0334 0340 -1FDA 0334 +0399 0340 0334 +03B9 0306 0334 03B9 0334 0306 -1FBE 0306 0334 1FBE 0334 0306 1FD0 0334 0399 0306 0334 0399 0334 0306 1FD8 0334 +03B9 0334 0342 03B9 0342 0334 1FBE 0334 0342 1FBE 0342 0334 -1FD6 0334 03B9 0308 0334 03B9 0334 0308 03CA 0334 @@ -68424,22 +70596,22 @@ A724 0062 0399 0308 0334 0399 0334 0308 03AA 0334 -03B9 0308 0301 0334 -03B9 0334 0344 -1FBE 0308 0341 0334 -1FBE 0344 0334 -03B9 0308 0334 0340 -03B9 0308 0340 0334 -03CA 0340 0334 +0390 0334 +03B9 0308 0334 0301 +03B9 0308 0334 0341 +1FD3 0334 +03B9 0308 0334 0300 +1FBE 0308 0300 0334 1FBE 0308 0340 0334 +1FD2 0334 03B9 0308 0334 0342 -03B9 0334 0308 0342 +03CA 0342 0334 1FBE 0308 0334 0342 1FBE 0308 0342 0334 03B9 0304 0334 03B9 0334 0304 -1FBE 0304 0334 1FBE 0334 0304 +1FD1 0334 0399 0304 0334 0399 0334 0304 1FD9 0334 @@ -69110,59 +71282,59 @@ A724 0062 1D764 0334 1D79E 0334 03BF 0313 0334 +03BF 0334 0313 03BF 0334 0343 -03BF 0343 0334 1F40 0334 039F 0313 0334 039F 0334 0313 039F 0334 0343 -1F48 0334 -03BF 0313 0334 0301 -03BF 0313 0334 0341 -03BF 0313 0341 0334 -03BF 0334 0343 0341 -039F 0313 0334 0301 -039F 0313 0341 0334 -039F 0343 0301 0334 -1F48 0341 0334 -03BF 0313 0334 0300 -03BF 0313 0334 0340 -03BF 0313 0340 0334 -03BF 0343 0300 0334 -039F 0313 0334 0300 -039F 0313 0340 0334 -039F 0343 0300 0334 -1F48 0340 0334 +039F 0343 0334 +03BF 0334 0313 0301 +03BF 0334 0313 0341 +1F40 0301 0334 +1F40 0341 0334 +039F 0334 0343 0301 +039F 0334 0343 0341 +1F48 0334 0301 +1F48 0334 0341 +03BF 0334 0313 0300 +03BF 0334 0313 0340 +1F40 0300 0334 +1F40 0340 0334 +039F 0343 0334 0300 +039F 0343 0334 0340 +1F48 0334 0300 +1F48 0334 0340 03BF 0314 0334 03BF 0334 0314 1F41 0334 039F 0314 0334 039F 0334 0314 1F49 0334 -03BF 0314 0334 0301 +03BF 0334 0314 0301 +03BF 0334 0314 0341 1F41 0301 0334 -1F41 0334 0341 -1F45 0334 -039F 0314 0301 0334 -039F 0314 0334 0341 +1F41 0341 0334 +039F 0314 0334 0301 039F 0334 0314 0301 +1F49 0334 0301 1F49 0334 0341 -03BF 0314 0334 0300 -03BF 0314 0340 0334 -1F41 0334 0340 -1F43 0334 -039F 0314 0300 0334 -039F 0314 0334 0340 +03BF 0334 0314 0300 +03BF 0334 0314 0340 +1F41 0300 0334 +1F41 0340 0334 +039F 0314 0334 0300 +039F 0334 0314 0300 +1F49 0334 0300 1F49 0334 0340 -1F49 0340 0334 03BF 0334 0301 03BF 0334 0341 -03BF 0341 0334 03CC 0334 -039F 0301 0334 +1F79 0334 +038C 0334 039F 0334 0301 039F 0334 0341 -039F 0341 0334 +1FF9 0334 03BF 0300 0334 03BF 0334 0300 03BF 0334 0340 @@ -69470,8 +71642,8 @@ A724 0062 1D72C 0334 1D766 0334 1D7A0 0334 +03C1 0313 0334 03C1 0334 0313 -03C1 0334 0343 03C1 0343 0334 1FE4 0334 03C1 0314 0334 @@ -69871,20 +72043,20 @@ A724 0062 1D7A4 0334 03C5 0313 0334 03C5 0334 0313 -03C5 0334 0343 03C5 0343 0334 -03C5 0334 0313 0341 -03C5 0334 0343 0341 +1F50 0334 +03C5 0313 0301 0334 +03C5 0313 0341 0334 1F50 0334 0301 -1F50 0334 0341 +1F54 0334 +03C5 0313 0300 0334 03C5 0313 0340 0334 -03C5 0334 0343 0340 -1F50 0334 0340 +1F50 0334 0300 1F52 0334 -03C5 0334 0313 0342 -03C5 0334 0343 0342 -03C5 0343 0334 0342 +03C5 0313 0342 0334 +03C5 0343 0342 0334 1F50 0334 0342 +1F50 0342 0334 03C5 0314 0334 03C5 0334 0314 1F51 0334 @@ -69892,48 +72064,48 @@ A724 0062 03A5 0334 0314 1F59 0334 03C5 0314 0301 0334 -03C5 0314 0334 0341 -03C5 0334 0314 0341 -1F51 0334 0301 -03A5 0314 0341 0334 -03A5 0334 0314 0341 +03C5 0314 0341 0334 +1F51 0301 0334 +1F51 0341 0334 +03A5 0314 0301 0334 +1F59 0334 0301 1F59 0334 0341 1F5D 0334 -03C5 0314 0334 0340 -03C5 0334 0314 0300 -1F51 0334 0300 -1F53 0334 +03C5 0314 0300 0334 +03C5 0314 0340 0334 +1F51 0300 0334 +1F51 0340 0334 +03A5 0314 0300 0334 03A5 0314 0340 0334 -03A5 0334 0314 0340 +1F59 0334 0300 1F59 0334 0340 -1F59 0340 0334 -03C5 0314 0334 0342 +03C5 0314 0342 0334 03C5 0334 0314 0342 +1F51 0334 0342 1F51 0342 0334 -1F57 0334 +03A5 0314 0334 0342 03A5 0314 0342 0334 -03A5 0334 0314 0342 1F59 0334 0342 -1F59 0342 0334 -03C5 0334 0301 +1F5F 0334 +03C5 0301 0334 03C5 0341 0334 03CD 0334 1F7B 0334 038E 0334 03A5 0301 0334 -03A5 0334 0341 03A5 0341 0334 +1FEB 0334 03D2 0301 0334 03D2 0334 0301 -03D2 0341 0334 +03D2 0334 0341 03D3 0334 03C5 0300 0334 03C5 0334 0300 -03C5 0334 0340 03C5 0340 0334 +1F7A 0334 03A5 0300 0334 03A5 0334 0300 -03A5 0334 0340 +03A5 0340 0334 1FEA 0334 03C5 0306 0334 03C5 0334 0306 @@ -69954,17 +72126,17 @@ A724 0062 03D2 0334 0308 03D4 0334 03B0 0334 -03C5 0308 0341 0334 -03C5 0344 0334 -03CB 0341 0334 -03C5 0308 0300 0334 -03C5 0308 0340 0334 +03C5 0334 0308 0301 +03C5 0334 0308 0341 +03CB 0301 0334 +03C5 0334 0308 0300 03CB 0300 0334 -03CB 0334 0300 -03C5 0334 0308 0342 +03CB 0340 0334 +1FE2 0334 +03C5 0308 0334 0342 +03C5 0308 0342 0334 03CB 0334 0342 03CB 0342 0334 -1FE7 0334 03C5 0304 0334 03C5 0334 0304 1FE1 0334 @@ -70493,70 +72665,70 @@ A724 0062 1D734 0334 1D76E 0334 1D7A8 0334 +03C9 0313 0334 03C9 0334 0313 03C9 0334 0343 03C9 0343 0334 -1F60 0334 03A9 0313 0334 +03A9 0334 0313 +03A9 0334 0343 03A9 0343 0334 -2126 0334 0313 -2126 0334 0343 -03C9 0313 0334 0301 -03C9 0334 0343 0301 +03C9 0343 0334 0301 +03C9 0343 0334 0341 +1F60 0301 0334 1F60 0341 0334 -1F64 0334 1F68 0334 0301 -1F6C 0334 -2126 0313 0341 0334 +1F68 0334 0341 2126 0334 0313 0301 -03C9 0334 0313 0301 0345 -03C9 0345 0313 0334 0341 -1F60 0341 0334 0345 -1FA0 0334 0301 +2126 0334 0313 0341 +1F64 0334 0345 +1F64 0345 0334 +1FA0 0301 0334 +1FF3 0313 0341 0334 +03A9 0313 0334 0345 0341 +03A9 0343 0345 0341 0334 1FFC 0343 0334 0341 -2126 0313 0334 0345 0301 -2126 0313 0345 0341 0334 -2126 0345 0343 0334 0301 -03C9 0313 0334 0300 -03C9 0334 0343 0300 +2126 0345 0313 0334 0341 +03C9 0343 0334 0300 +03C9 0343 0334 0340 +1F60 0300 0334 1F60 0340 0334 -1F62 0334 1F68 0334 0300 +1F68 0334 0340 2126 0334 0313 0300 2126 0334 0313 0340 -2126 0343 0334 0300 -03C9 0313 0345 0334 0300 -03C9 0345 0313 0334 0340 -1F60 0345 0340 0334 -1FA0 0334 0300 -03A9 0343 0345 0340 0334 -1FFC 0313 0340 0334 +03C9 0334 0343 0300 0345 +03C9 0343 0334 0340 0345 +03C9 0343 0345 0300 0334 +1F62 0334 0345 +03A9 0313 0334 0345 0340 +03A9 0313 0340 0334 0345 +03A9 0313 0340 0345 0334 1FFC 0343 0334 0340 -2126 0334 0343 0340 0345 -03C9 0313 0334 0342 03C9 0313 0342 0334 -03C9 0334 0343 0342 -03C9 0343 0334 0342 -1F68 0342 0334 +03C9 0343 0342 0334 +1F60 0334 0342 +1F60 0342 0334 +1F68 0334 0342 1F6E 0334 +2126 0313 0342 0334 2126 0334 0313 0342 -2126 0343 0342 0334 -03C9 0343 0342 0345 0334 -03C9 0345 0313 0334 0342 -03C9 0345 0343 0342 0334 -1FF3 0313 0342 0334 -1F6E 0334 0345 -1FA8 0334 0342 -1FFC 0343 0334 0342 -2126 0313 0342 0345 0334 -03C9 0313 0334 0345 -03C9 0313 0345 0334 -03C9 0334 0345 0313 -1FF3 0334 0343 -03A9 0345 0334 0343 -1F68 0334 0345 -2126 0345 0313 0334 -2126 0345 0343 0334 +03C9 0343 0334 0342 0345 +03C9 0343 0345 0342 0334 +1F66 0334 0345 +1F66 0345 0334 +03A9 0313 0334 0345 0342 +03A9 0313 0342 0345 0334 +03A9 0334 0343 0345 0342 +1FFC 0334 0343 0342 +03C9 0334 0343 0345 +03C9 0345 0343 0334 +1F60 0334 0345 +1FF3 0334 0313 +03A9 0334 0313 0345 +03A9 0345 0313 0334 +1F68 0345 0334 +1FFC 0313 0334 03C9 0314 0334 03C9 0334 0314 1F61 0334 @@ -70564,100 +72736,100 @@ A724 0062 03A9 0334 0314 1F69 0334 2126 0334 0314 -03C9 0314 0301 0334 -03C9 0314 0341 0334 +1F61 0301 0334 1F61 0334 0301 -1F65 0334 -1F69 0301 0334 +1F61 0334 0341 +1F61 0341 0334 1F69 0334 0301 -2126 0334 0314 0301 -2126 0334 0314 0341 -03C9 0314 0334 0345 0301 -03C9 0345 0314 0334 0301 +1F69 0334 0341 +1F6D 0334 +2126 0314 0334 0301 +03C9 0314 0334 0301 0345 1F61 0301 0345 0334 -1F65 0345 0334 -03A9 0314 0301 0345 0334 -03A9 0345 0334 0314 0301 -2126 0314 0345 0341 0334 +1F61 0345 0334 0301 +1FA1 0341 0334 +1FA9 0334 0341 +2126 0334 0345 0314 0341 +2126 0345 0314 0334 0301 2126 0345 0334 0314 0341 03C9 0314 0334 0300 03C9 0314 0334 0340 -03C9 0314 0340 0334 03C9 0334 0314 0300 -1F69 0300 0334 -2126 0314 0300 0334 -2126 0314 0334 0340 -2126 0334 0314 0340 +1F63 0334 +03A9 0314 0334 0300 +03A9 0314 0334 0340 +03A9 0334 0314 0300 +03A9 0334 0314 0340 +03C9 0314 0300 0345 0334 03C9 0314 0334 0345 0300 -03C9 0314 0345 0300 0334 -03C9 0345 0314 0300 0334 -03C9 0345 0314 0334 0300 -03A9 0314 0300 0345 0334 -03A9 0345 0334 0314 0300 -1F6B 0345 0334 -2126 0345 0334 0314 0340 +1F61 0340 0334 0345 +1F61 0345 0334 0300 +03A9 0314 0334 0300 0345 +1FA9 0334 0340 +2126 0334 0345 0314 0340 +2126 0345 0314 0334 0300 +03C9 0314 0334 0342 03C9 0314 0342 0334 -03C9 0334 0314 0342 1F61 0334 0342 -1F67 0334 -03A9 0314 0334 0342 -1F69 0342 0334 +1F61 0342 0334 +1F69 0334 0342 1F6F 0334 2126 0314 0334 0342 -03C9 0314 0334 0345 0342 -03C9 0334 0314 0342 0345 -03C9 0345 0314 0334 0342 -1FF3 0314 0342 0334 -03A9 0334 0345 0314 0342 -03A9 0345 0334 0314 0342 -2126 0314 0334 0342 0345 -2126 0345 0334 0314 0342 -03C9 0334 0345 0314 -03C9 0345 0314 0334 +2126 0334 0314 0342 +03C9 0314 0345 0334 0342 +1F61 0334 0345 0342 +1F61 0342 0345 0334 +1F67 0345 0334 +1F6F 0345 0334 +1FA9 0334 0342 +2126 0334 0345 0314 0342 +2126 0345 0314 0334 0342 +03C9 0334 0314 0345 +1F61 0334 0345 1F61 0345 0334 -1FF3 0334 0314 -1F69 0334 0345 -2126 0314 0334 0345 +1FA1 0334 2126 0314 0345 0334 -2126 0334 0314 0345 -03C9 0334 0301 -03C9 0334 0341 +2126 0334 0345 0314 +2126 0345 0314 0334 +2126 0345 0334 0314 +03C9 0301 0334 03C9 0341 0334 03CE 0334 +1F7D 0334 +038F 0334 03A9 0301 0334 -03A9 0334 0341 +03A9 0341 0334 2126 0301 0334 -2126 0341 0334 -03C9 0345 0301 0334 -1F7D 0334 0345 -1FF3 0334 0341 +03C9 0301 0345 0334 +03C9 0334 0345 0301 +03C9 0341 0345 0334 1FF4 0334 +03C9 0300 0334 03C9 0334 0300 -03C9 0334 0340 03C9 0340 0334 1F7C 0334 03A9 0300 0334 -03A9 0334 0300 -03A9 0334 0340 +03A9 0340 0334 2126 0300 0334 -03C9 0340 0334 0345 -03C9 0345 0334 0340 -1F7C 0334 0345 +2126 0340 0334 +03C9 0300 0345 0334 +03C9 0334 0345 0300 +03C9 0334 0345 0340 1FF2 0334 03C9 0334 0342 03C9 0342 0334 1FF6 0334 +03C9 0334 0342 0345 03C9 0334 0345 0342 03C9 0345 0342 0334 1FF3 0334 0342 -1FF6 0334 0345 03C9 0334 0345 03C9 0345 0334 1FF3 0334 03A9 0334 0345 03A9 0345 0334 1FFC 0334 -2126 0334 0345 +2126 0345 0334 1FF3 0021 1FF3 003F 1FFC 0021 @@ -71577,7 +73749,9 @@ AB65 0062 0411 0062 0432 0021 0432 003F +1C80 0021 2DE1 0021 +1C80 003F 2DE1 003F 0412 0021 0412 003F @@ -71585,11 +73759,14 @@ AB65 0062 2DE1 0334 0432 0061 0432 0041 +1C80 0061 2DE1 0061 +1C80 0041 2DE1 0041 0412 0061 0412 0041 0432 0062 +1C80 0062 2DE1 0062 0412 0062 0433 0021 @@ -71605,10 +73782,10 @@ AB65 0062 0433 0301 0334 0433 0334 0301 0433 0334 0341 -0433 0341 0334 +0453 0334 0403 0334 +0413 0301 0334 0413 0334 0301 -0413 0334 0341 0413 0341 0334 0491 0021 0491 003F @@ -71679,7 +73856,9 @@ AB65 0062 04F6 0062 0434 0021 0434 003F +1C81 0021 2DE3 0021 +1C81 003F 2DE3 003F 0414 0021 0414 003F @@ -71687,11 +73866,14 @@ AB65 0062 2DE3 0334 0434 0061 0434 0041 +1C81 0061 2DE3 0061 +1C81 0041 2DE3 0041 0414 0061 0414 0041 0434 0062 +1C81 0062 2DE3 0062 0414 0062 0501 0021 @@ -71772,13 +73954,13 @@ A662 0062 0451 003F 0401 0021 0401 003F +0435 0300 0334 0435 0334 0300 0435 0334 0340 -0435 0340 0334 0450 0334 +0400 0334 0415 0300 0334 0415 0334 0300 -0415 0334 0340 0415 0340 0334 0435 0306 0334 0435 0334 0306 @@ -72071,10 +74253,10 @@ A675 003F 0438 0300 0334 0438 0334 0300 0438 0334 0340 -0438 0340 0334 +045D 0334 040D 0334 0418 0300 0334 -0418 0334 0340 +0418 0334 0300 0418 0340 0334 0438 0308 0334 0438 0334 0308 @@ -72577,6 +74759,7 @@ A666 0062 050A 0062 043E 0021 043E 003F +1C82 0021 2DEA 0021 A669 0021 A66B 0021 @@ -72584,6 +74767,7 @@ A66D 0021 A66E 0021 A699 0021 A69B 0021 +1C82 003F 2DEA 003F A669 003F A66B 003F @@ -72617,6 +74801,7 @@ A69A 003F 2DEA 0334 043E 0061 043E 0041 +1C82 0061 2DEA 0061 A669 0061 A66B 0061 @@ -72624,6 +74809,7 @@ A66D 0061 A66E 0061 A699 0061 A69B 0061 +1C82 0041 2DEA 0041 A669 0041 A66B 0041 @@ -72648,6 +74834,7 @@ A69A 0041 04E6 0061 04E6 0041 043E 0062 +1C82 0062 2DEA 0062 A669 0062 A66B 0062 @@ -72775,7 +74962,9 @@ A69A 0062 0516 0062 0441 0021 0441 003F +1C83 0021 2DED 0021 +1C83 003F 2DED 003F 0421 0021 0421 003F @@ -72783,11 +74972,14 @@ A69A 0062 2DED 0334 0441 0061 0441 0041 +1C83 0061 2DED 0061 +1C83 0041 2DED 0041 0421 0061 0421 0041 0441 0062 +1C83 0062 2DED 0062 0421 0062 2DF5 0021 @@ -72819,7 +75011,11 @@ A69A 0062 04AA 0062 0442 0021 0442 003F +1C84 0021 +1C85 0021 2DEE 0021 +1C84 003F +1C85 003F 2DEE 003F 0422 0021 0422 003F @@ -72827,11 +75023,17 @@ A69A 0062 2DEE 0334 0442 0061 0442 0041 +1C84 0061 +1C85 0061 2DEE 0061 +1C84 0041 +1C85 0041 2DEE 0041 0422 0061 0422 0041 0442 0062 +1C84 0062 +1C85 0062 2DEE 0062 0422 0062 A68D 0021 @@ -72987,7 +75189,9 @@ A677 0062 04B0 0062 A64B 0021 A64B 003F +1C88 0021 2DF9 0021 +1C88 003F 2DF9 003F A64A 0021 A64A 003F @@ -72995,11 +75199,14 @@ A64A 003F 2DF9 0334 A64B 0061 A64B 0041 +1C88 0061 2DF9 0061 +1C88 0041 2DF9 0041 A64A 0061 A64A 0041 A64B 0062 +1C88 0062 2DF9 0062 A64A 0062 0479 0021 @@ -73018,6 +75225,7 @@ A69E 0021 A69E 003F 0424 0021 0424 003F +0334 A69E A69E 0334 0444 0061 0444 0041 @@ -73408,7 +75616,9 @@ A67F 0041 A67F 0062 044A 0021 044A 003F +1C86 0021 A678 0021 +1C86 003F A678 003F 042A 0021 042A 003F @@ -73418,13 +75628,16 @@ A69C 003F A678 0334 044A 0061 044A 0041 +1C86 0061 A678 0061 +1C86 0041 A678 0041 042A 0061 042A 0041 A69C 0061 A69C 0041 044A 0062 +1C86 0062 A678 0062 042A 0062 A69C 0062 @@ -73505,7 +75718,9 @@ A69D 0062 048C 0062 0463 0021 0463 003F +1C87 0021 2DFA 0021 +1C87 003F 2DFA 003F 0462 0021 0462 003F @@ -73513,11 +75728,14 @@ A69D 0062 2DFA 0334 0463 0061 0463 0041 +1C87 0061 2DFA 0061 +1C87 0041 2DFA 0041 0462 0061 0462 0041 0463 0062 +1C87 0062 2DFA 0062 0462 0062 A653 0021 @@ -73833,73 +76051,122 @@ A65E 0062 04C0 0062 2C30 0021 2C30 003F +1E000 0021 +1E000 003F 2C00 0021 2C00 003F +0334 1E000 +1E000 0334 2C30 0061 2C30 0041 +1E000 0061 +1E000 0041 2C00 0061 2C00 0041 2C30 0062 +1E000 0062 2C00 0062 2C31 0021 2C31 003F +1E001 0021 +1E001 003F 2C01 0021 2C01 003F +0334 1E001 +1E001 0334 2C31 0061 2C31 0041 +1E001 0061 +1E001 0041 2C01 0061 2C01 0041 2C31 0062 +1E001 0062 2C01 0062 2C32 0021 2C32 003F +1E002 0021 +1E002 003F 2C02 0021 2C02 003F +0334 1E002 +1E002 0334 2C32 0061 2C32 0041 +1E002 0061 +1E002 0041 2C02 0061 2C02 0041 2C32 0062 +1E002 0062 2C02 0062 2C33 0021 2C33 003F +1E003 0021 +1E003 003F 2C03 0021 2C03 003F +0334 1E003 +1E003 0334 2C33 0061 2C33 0041 +1E003 0061 +1E003 0041 2C03 0061 2C03 0041 2C33 0062 +1E003 0062 2C03 0062 2C34 0021 2C34 003F +1E004 0021 +1E004 003F 2C04 0021 2C04 003F +0334 1E004 +1E004 0334 2C34 0061 2C34 0041 +1E004 0061 +1E004 0041 2C04 0061 2C04 0041 2C34 0062 +1E004 0062 2C04 0062 2C35 0021 2C35 003F +1E005 0021 +1E005 003F 2C05 0021 2C05 003F +0334 1E005 +1E005 0334 2C35 0061 2C35 0041 +1E005 0061 +1E005 0041 2C05 0061 2C05 0041 2C35 0062 +1E005 0062 2C05 0062 2C36 0021 2C36 003F +1E006 0021 +1E006 003F 2C06 0021 2C06 003F +0334 1E006 +1E006 0334 2C36 0061 2C36 0041 +1E006 0061 +1E006 0041 2C06 0061 2C06 0041 2C36 0062 +1E006 0062 2C06 0062 2C37 0021 2C37 003F @@ -73913,173 +76180,292 @@ A65E 0062 2C07 0062 2C38 0021 2C38 003F +1E008 0021 +1E008 003F 2C08 0021 2C08 003F +0334 1E008 +1E008 0334 2C38 0061 2C38 0041 +1E008 0061 +1E008 0041 2C08 0061 2C08 0041 2C38 0062 +1E008 0062 2C08 0062 2C39 0021 2C39 003F +1E009 0021 +1E009 003F 2C09 0021 2C09 003F +0334 1E009 +1E009 0334 2C39 0061 2C39 0041 +1E009 0061 +1E009 0041 2C09 0061 2C09 0041 2C39 0062 +1E009 0062 2C09 0062 2C3A 0021 2C3A 003F +1E00A 0021 +1E00A 003F 2C0A 0021 2C0A 003F +0334 1E00A +1E00A 0334 2C3A 0061 2C3A 0041 +1E00A 0061 +1E00A 0041 2C0A 0061 2C0A 0041 2C3A 0062 +1E00A 0062 2C0A 0062 2C3B 0021 2C3B 003F +1E00B 0021 +1E00B 003F 2C0B 0021 2C0B 003F +0334 1E00B +1E00B 0334 2C3B 0061 2C3B 0041 +1E00B 0061 +1E00B 0041 2C0B 0061 2C0B 0041 2C3B 0062 +1E00B 0062 2C0B 0062 2C3C 0021 2C3C 003F +1E00C 0021 +1E00C 003F 2C0C 0021 2C0C 003F +0334 1E00C +1E00C 0334 2C3C 0061 2C3C 0041 +1E00C 0061 +1E00C 0041 2C0C 0061 2C0C 0041 2C3C 0062 +1E00C 0062 2C0C 0062 2C3D 0021 2C3D 003F +1E00D 0021 +1E00D 003F 2C0D 0021 2C0D 003F +0334 1E00D +1E00D 0334 2C3D 0061 2C3D 0041 +1E00D 0061 +1E00D 0041 2C0D 0061 2C0D 0041 2C3D 0062 +1E00D 0062 2C0D 0062 2C3E 0021 2C3E 003F +1E00E 0021 +1E00E 003F 2C0E 0021 2C0E 003F +0334 1E00E +1E00E 0334 2C3E 0061 2C3E 0041 +1E00E 0061 +1E00E 0041 2C0E 0061 2C0E 0041 2C3E 0062 +1E00E 0062 2C0E 0062 2C3F 0021 2C3F 003F +1E00F 0021 +1E00F 003F 2C0F 0021 2C0F 003F +0334 1E00F +1E00F 0334 2C3F 0061 2C3F 0041 +1E00F 0061 +1E00F 0041 2C0F 0061 2C0F 0041 2C3F 0062 +1E00F 0062 2C0F 0062 2C40 0021 2C40 003F +1E010 0021 +1E010 003F 2C10 0021 2C10 003F +0334 1E010 +1E010 0334 2C40 0061 2C40 0041 +1E010 0061 +1E010 0041 2C10 0061 2C10 0041 2C40 0062 +1E010 0062 2C10 0062 2C41 0021 2C41 003F +1E011 0021 +1E011 003F 2C11 0021 2C11 003F +0334 1E011 +1E011 0334 2C41 0061 2C41 0041 +1E011 0061 +1E011 0041 2C11 0061 2C11 0041 2C41 0062 +1E011 0062 2C11 0062 2C42 0021 2C42 003F +1E012 0021 +1E012 003F 2C12 0021 2C12 003F +0334 1E012 +1E012 0334 2C42 0061 2C42 0041 +1E012 0061 +1E012 0041 2C12 0061 2C12 0041 2C42 0062 +1E012 0062 2C12 0062 2C43 0021 2C43 003F +1E013 0021 +1E013 003F 2C13 0021 2C13 003F +0334 1E013 +1E013 0334 2C43 0061 2C43 0041 +1E013 0061 +1E013 0041 2C13 0061 2C13 0041 2C43 0062 +1E013 0062 2C13 0062 2C44 0021 2C44 003F +1E014 0021 +1E014 003F 2C14 0021 2C14 003F +0334 1E014 +1E014 0334 2C44 0061 2C44 0041 +1E014 0061 +1E014 0041 2C14 0061 2C14 0041 2C44 0062 +1E014 0062 2C14 0062 2C45 0021 2C45 003F +1E015 0021 +1E015 003F 2C15 0021 2C15 003F +0334 1E015 +1E015 0334 2C45 0061 2C45 0041 +1E015 0061 +1E015 0041 2C15 0061 2C15 0041 2C45 0062 +1E015 0062 2C15 0062 2C46 0021 2C46 003F +1E016 0021 +1E016 003F 2C16 0021 2C16 003F +0334 1E016 +1E016 0334 2C46 0061 2C46 0041 +1E016 0061 +1E016 0041 2C16 0061 2C16 0041 2C46 0062 +1E016 0062 2C16 0062 2C47 0021 2C47 003F +1E017 0021 +1E017 003F 2C17 0021 2C17 003F +0334 1E017 +1E017 0334 2C47 0061 2C47 0041 +1E017 0061 +1E017 0041 2C17 0061 2C17 0041 2C47 0062 +1E017 0062 2C17 0062 2C48 0021 2C48 003F +1E018 0021 +1E018 003F 2C18 0021 2C18 003F +0334 1E018 +1E018 0334 2C48 0061 2C48 0041 +1E018 0061 +1E018 0041 2C18 0061 2C18 0041 2C48 0062 +1E018 0062 2C18 0062 2C49 0021 2C49 003F @@ -74103,73 +76489,122 @@ A65E 0062 2C1A 0062 2C4B 0021 2C4B 003F +1E01B 0021 +1E01B 003F 2C1B 0021 2C1B 003F +0334 1E01B +1E01B 0334 2C4B 0061 2C4B 0041 +1E01B 0061 +1E01B 0041 2C1B 0061 2C1B 0041 2C4B 0062 +1E01B 0062 2C1B 0062 2C4C 0021 2C4C 003F +1E01C 0021 +1E01C 003F 2C1C 0021 2C1C 003F +0334 1E01C +1E01C 0334 2C4C 0061 2C4C 0041 +1E01C 0061 +1E01C 0041 2C1C 0061 2C1C 0041 2C4C 0062 +1E01C 0062 2C1C 0062 2C4D 0021 2C4D 003F +1E01D 0021 +1E01D 003F 2C1D 0021 2C1D 003F +0334 1E01D +1E01D 0334 2C4D 0061 2C4D 0041 +1E01D 0061 +1E01D 0041 2C1D 0061 2C1D 0041 2C4D 0062 +1E01D 0062 2C1D 0062 2C4E 0021 2C4E 003F +1E01E 0021 +1E01E 003F 2C1E 0021 2C1E 003F +0334 1E01E +1E01E 0334 2C4E 0061 2C4E 0041 +1E01E 0061 +1E01E 0041 2C1E 0061 2C1E 0041 2C4E 0062 +1E01E 0062 2C1E 0062 2C4F 0021 2C4F 003F +1E01F 0021 +1E01F 003F 2C1F 0021 2C1F 003F +0334 1E01F +1E01F 0334 2C4F 0061 2C4F 0041 +1E01F 0061 +1E01F 0041 2C1F 0061 2C1F 0041 2C4F 0062 +1E01F 0062 2C1F 0062 2C50 0021 2C50 003F +1E020 0021 +1E020 003F 2C20 0021 2C20 003F +0334 1E020 +1E020 0334 2C50 0061 2C50 0041 +1E020 0061 +1E020 0041 2C20 0061 2C20 0041 2C50 0062 +1E020 0062 2C20 0062 2C51 0021 2C51 003F +1E021 0021 +1E021 003F 2C21 0021 2C21 003F +0334 1E021 +1E021 0334 2C51 0061 2C51 0041 +1E021 0061 +1E021 0041 2C21 0061 2C21 0041 2C51 0062 +1E021 0062 2C21 0062 2C52 0021 2C52 003F @@ -74183,23 +76618,37 @@ A65E 0062 2C22 0062 2C53 0021 2C53 003F +1E023 0021 +1E023 003F 2C23 0021 2C23 003F +0334 1E023 +1E023 0334 2C53 0061 2C53 0041 +1E023 0061 +1E023 0041 2C23 0061 2C23 0041 2C53 0062 +1E023 0062 2C23 0062 2C54 0021 2C54 003F +1E024 0021 +1E024 003F 2C24 0021 2C24 003F +0334 1E024 +1E024 0334 2C54 0061 2C54 0041 +1E024 0061 +1E024 0041 2C24 0061 2C24 0041 2C54 0062 +1E024 0062 2C24 0062 2C55 0021 2C55 003F @@ -74213,53 +76662,88 @@ A65E 0062 2C25 0062 2C56 0021 2C56 003F +1E026 0021 +1E026 003F 2C26 0021 2C26 003F +0334 1E026 +1E026 0334 2C56 0061 2C56 0041 +1E026 0061 +1E026 0041 2C26 0061 2C26 0041 2C56 0062 +1E026 0062 2C26 0062 2C57 0021 2C57 003F +1E027 0021 +1E027 003F 2C27 0021 2C27 003F +0334 1E027 +1E027 0334 2C57 0061 2C57 0041 +1E027 0061 +1E027 0041 2C27 0061 2C27 0041 2C57 0062 +1E027 0062 2C27 0062 2C58 0021 2C58 003F +1E028 0021 +1E028 003F 2C28 0021 2C28 003F +0334 1E028 +1E028 0334 2C58 0061 2C58 0041 +1E028 0061 +1E028 0041 2C28 0061 2C28 0041 2C58 0062 +1E028 0062 2C28 0062 2C59 0021 2C59 003F +1E029 0021 +1E029 003F 2C29 0021 2C29 003F +0334 1E029 +1E029 0334 2C59 0061 2C59 0041 +1E029 0061 +1E029 0041 2C29 0061 2C29 0041 2C59 0062 +1E029 0062 2C29 0062 2C5A 0021 2C5A 003F +1E02A 0021 +1E02A 003F 2C2A 0021 2C2A 003F +0334 1E02A +1E02A 0334 2C5A 0061 2C5A 0041 +1E02A 0061 +1E02A 0041 2C2A 0061 2C2A 0041 2C5A 0062 +1E02A 0062 2C2A 0062 2C5B 0021 2C5B 003F @@ -76054,14 +78538,14 @@ FB2A 0334 05E9 0334 05BC 05E9 05BC 0334 FB49 0334 -05E9 0334 05C2 05BC +05E9 05BC 0334 05C2 +05E9 05BC 05C2 0334 05E9 05C2 0334 05BC 05E9 05C2 05BC 0334 -FB49 0334 05C2 -05E9 0334 05C1 05BC 05E9 05BC 0334 05C1 +05E9 05BC 05C1 0334 +05E9 05C1 0334 05BC FB2C 0334 -FB49 0334 05C1 FB2B 0021 FB2B 003F FB2A 0021 @@ -77118,6 +79602,16 @@ FB5A 0062 08A1 0061 08A1 0041 08A1 0062 +08B6 0021 +08B6 003F +08B6 0061 +08B6 0041 +08B6 0062 +08B7 0021 +08B7 003F +08B7 0061 +08B7 0041 +08B7 0062 0629 0021 0629 003F FE94 0021 @@ -77558,6 +80052,11 @@ FB64 0062 FB65 0062 FB63 0062 FB62 0062 +08B8 0021 +08B8 003F +08B8 0061 +08B8 0041 +08B8 0062 062C 0021 062C 003F 1EE02 0021 @@ -78428,6 +80927,11 @@ FB8A 0062 08B2 0061 08B2 0041 08B2 0062 +08B9 0021 +08B9 003F +08B9 0061 +08B9 0041 +08B9 0062 0633 0021 0633 003F 1EE0E 0021 @@ -79859,6 +82363,11 @@ FC32 0062 06A2 0061 06A2 0041 06A2 0062 +08BB 0021 +08BB 003F +08BB 0061 +08BB 0041 +08BB 0062 06A3 0021 06A3 003F 06A3 0061 @@ -80082,6 +82591,11 @@ FC36 0062 06A7 0061 06A7 0041 06A7 0062 +08BC 0021 +08BC 003F +08BC 0061 +08BC 0041 +08BC 0062 06A8 0021 06A8 003F 06A8 0061 @@ -81153,6 +83667,11 @@ FB9E 0041 1EE5D 0062 FB9F 0062 FB9E 0062 +08BD 0021 +08BD 003F +08BD 0061 +08BD 0041 +08BD 0062 06BB 0021 06BB 003F FBA2 0021 @@ -81898,6 +84417,11 @@ FBE4 0062 0777 0061 0777 0041 0777 0062 +08BA 0021 +08BA 003F +08BA 0061 +08BA 0041 +08BA 0062 06D2 0021 06D2 003F FBAF 0021 @@ -82111,6 +84635,61 @@ FBB0 0062 072C 0061 072C 0041 072C 0062 +0860 0021 +0860 003F +0860 0061 +0860 0041 +0860 0062 +0861 0021 +0861 003F +0861 0061 +0861 0041 +0861 0062 +0862 0021 +0862 003F +0862 0061 +0862 0041 +0862 0062 +0863 0021 +0863 003F +0863 0061 +0863 0041 +0863 0062 +0864 0021 +0864 003F +0864 0061 +0864 0041 +0864 0062 +0865 0021 +0865 003F +0865 0061 +0865 0041 +0865 0062 +0866 0021 +0866 003F +0866 0061 +0866 0041 +0866 0062 +0867 0021 +0867 003F +0867 0061 +0867 0041 +0867 0062 +0868 0021 +0868 003F +0868 0061 +0868 0041 +0868 0062 +0869 0021 +0869 003F +0869 0061 +0869 0041 +0869 0062 +086A 0021 +086A 003F +086A 0061 +086A 0041 +086A 0062 0840 0021 0840 003F 0840 0061 @@ -86233,6 +88812,11 @@ A8FB 0062 09D7 0061 09D7 0041 09D7 0062 +09FC 0021 +09FC 003F +09FC 0061 +09FC 0041 +09FC 0062 0A74 0021 0A74 003F 0A74 0061 @@ -88238,6 +90822,11 @@ A8FB 0062 0CF2 0061 0CF2 0041 0CF2 0062 +0C80 0021 +0C80 003F +0C80 0061 +0C80 0041 +0C80 0062 0CBE 0021 0CBE 003F 0CBE 0061 @@ -88611,11 +91200,21 @@ A8FB 0062 0D2E 0061 0D2E 0041 0D2E 0062 +0D54 0021 +0D54 003F +0D54 0061 +0D54 0041 +0D54 0062 0D2F 0021 0D2F 003F 0D2F 0061 0D2F 0041 0D2F 0062 +0D55 0021 +0D55 003F +0D55 0061 +0D55 0041 +0D55 0062 0D30 0021 0D30 003F 0D30 0061 @@ -88681,6 +91280,11 @@ A8FB 0062 0D34 0061 0D34 0041 0D34 0062 +0D56 0021 +0D56 003F +0D56 0061 +0D56 0041 +0D56 0062 0D31 0021 0D31 003F 0D31 0061 @@ -88802,11 +91406,25 @@ A8FB 0062 0D57 0062 0D4D 0021 0D4D 003F +0D3B 0021 +0D3C 0021 +0D3B 003F +0D3C 003F 0334 0D4D 0D4D 0334 +0334 0D3B +0D3B 0334 +0334 0D3C +0D3C 0334 0D4D 0061 0D4D 0041 +0D3B 0061 +0D3C 0061 +0D3B 0041 +0D3C 0041 0D4D 0062 +0D3B 0062 +0D3C 0062 0D85 0021 0D85 003F 0D85 0061 @@ -89213,7 +91831,7 @@ A8FB 0062 0DD9 0DCF 0334 0DCA 0DD9 0DCF 0DCA 0334 0DDC 0334 0DCA -0DDD 0334 +0DDC 0DCA 0334 0DD9 0DCF 0DCA 0061 0DDC 0DCA 0061 0DDD 0061 @@ -92364,6 +94982,433 @@ A8C4 0062 1135D 0061 1135D 0041 1135D 0062 +11449 0021 +11449 003F +11449 0334 +11449 0061 +11449 0041 +11449 0062 +1144A 0021 +1144A 003F +1144A 0334 +1144A 0061 +1144A 0041 +1144A 0062 +11400 0021 +11400 003F +11400 0334 +11400 0061 +11400 0041 +11400 0062 +11401 0021 +11401 003F +11401 0334 +11401 0061 +11401 0041 +11401 0062 +11402 0021 +11402 003F +11402 0334 +11402 0061 +11402 0041 +11402 0062 +11403 0021 +11403 003F +11403 0334 +11403 0061 +11403 0041 +11403 0062 +11404 0021 +11404 003F +11404 0334 +11404 0061 +11404 0041 +11404 0062 +11405 0021 +11405 003F +11405 0334 +11405 0061 +11405 0041 +11405 0062 +11406 0021 +11406 003F +11406 0334 +11406 0061 +11406 0041 +11406 0062 +11407 0021 +11407 003F +11407 0334 +11407 0061 +11407 0041 +11407 0062 +11408 0021 +11408 003F +11408 0334 +11408 0061 +11408 0041 +11408 0062 +11409 0021 +11409 003F +11409 0334 +11409 0061 +11409 0041 +11409 0062 +1140A 0021 +1140A 003F +1140A 0334 +1140A 0061 +1140A 0041 +1140A 0062 +1140B 0021 +1140B 003F +1140B 0334 +1140B 0061 +1140B 0041 +1140B 0062 +1140C 0021 +1140C 003F +1140C 0334 +1140C 0061 +1140C 0041 +1140C 0062 +1140D 0021 +1140D 003F +1140D 0334 +1140D 0061 +1140D 0041 +1140D 0062 +1140E 0021 +1140E 003F +1140E 0334 +1140E 0061 +1140E 0041 +1140E 0062 +1140F 0021 +1140F 003F +1140F 0334 +1140F 0061 +1140F 0041 +1140F 0062 +11410 0021 +11410 003F +11410 0334 +11410 0061 +11410 0041 +11410 0062 +11411 0021 +11411 003F +11411 0334 +11411 0061 +11411 0041 +11411 0062 +11412 0021 +11412 003F +11412 0334 +11412 0061 +11412 0041 +11412 0062 +11413 0021 +11413 003F +11413 0334 +11413 0061 +11413 0041 +11413 0062 +11414 0021 +11414 003F +11414 0334 +11414 0061 +11414 0041 +11414 0062 +11415 0021 +11415 003F +11415 0334 +11415 0061 +11415 0041 +11415 0062 +11416 0021 +11416 003F +11416 0334 +11416 0061 +11416 0041 +11416 0062 +11417 0021 +11417 003F +11417 0334 +11417 0061 +11417 0041 +11417 0062 +11418 0021 +11418 003F +11418 0334 +11418 0061 +11418 0041 +11418 0062 +11419 0021 +11419 003F +11419 0334 +11419 0061 +11419 0041 +11419 0062 +1141A 0021 +1141A 003F +1141A 0334 +1141A 0061 +1141A 0041 +1141A 0062 +1141B 0021 +1141B 003F +1141B 0334 +1141B 0061 +1141B 0041 +1141B 0062 +1141C 0021 +1141C 003F +1141C 0334 +1141C 0061 +1141C 0041 +1141C 0062 +1141D 0021 +1141D 003F +1141D 0334 +1141D 0061 +1141D 0041 +1141D 0062 +1141E 0021 +1141E 003F +1141E 0334 +1141E 0061 +1141E 0041 +1141E 0062 +1141F 0021 +1141F 003F +1141F 0334 +1141F 0061 +1141F 0041 +1141F 0062 +11420 0021 +11420 003F +11420 0334 +11420 0061 +11420 0041 +11420 0062 +11421 0021 +11421 003F +11421 0334 +11421 0061 +11421 0041 +11421 0062 +11422 0021 +11422 003F +11422 0334 +11422 0061 +11422 0041 +11422 0062 +11423 0021 +11423 003F +11423 0334 +11423 0061 +11423 0041 +11423 0062 +11424 0021 +11424 003F +11424 0334 +11424 0061 +11424 0041 +11424 0062 +11425 0021 +11425 003F +11425 0334 +11425 0061 +11425 0041 +11425 0062 +11426 0021 +11426 003F +11426 0334 +11426 0061 +11426 0041 +11426 0062 +11427 0021 +11427 003F +11427 0334 +11427 0061 +11427 0041 +11427 0062 +11428 0021 +11428 003F +11428 0334 +11428 0061 +11428 0041 +11428 0062 +11429 0021 +11429 003F +11429 0334 +11429 0061 +11429 0041 +11429 0062 +1142A 0021 +1142A 003F +1142A 0334 +1142A 0061 +1142A 0041 +1142A 0062 +1142B 0021 +1142B 003F +1142B 0334 +1142B 0061 +1142B 0041 +1142B 0062 +1142C 0021 +1142C 003F +1142C 0334 +1142C 0061 +1142C 0041 +1142C 0062 +1142D 0021 +1142D 003F +1142D 0334 +1142D 0061 +1142D 0041 +1142D 0062 +1142E 0021 +1142E 003F +1142E 0334 +1142E 0061 +1142E 0041 +1142E 0062 +1142F 0021 +1142F 003F +1142F 0334 +1142F 0061 +1142F 0041 +1142F 0062 +11430 0021 +11430 003F +11430 0334 +11430 0061 +11430 0041 +11430 0062 +11431 0021 +11431 003F +11431 0334 +11431 0061 +11431 0041 +11431 0062 +11432 0021 +11432 003F +11432 0334 +11432 0061 +11432 0041 +11432 0062 +11433 0021 +11433 003F +11433 0334 +11433 0061 +11433 0041 +11433 0062 +11434 0021 +11434 003F +11434 0334 +11434 0061 +11434 0041 +11434 0062 +11447 0021 +11447 003F +11447 0334 +11447 0061 +11447 0041 +11447 0062 +11448 0021 +11448 003F +11448 0334 +11448 0061 +11448 0041 +11448 0062 +11435 0021 +11435 003F +11435 0334 +11435 0061 +11435 0041 +11435 0062 +11436 0021 +11436 003F +11436 0334 +11436 0061 +11436 0041 +11436 0062 +11437 0021 +11437 003F +11437 0334 +11437 0061 +11437 0041 +11437 0062 +11438 0021 +11438 003F +11438 0334 +11438 0061 +11438 0041 +11438 0062 +11439 0021 +11439 003F +11439 0334 +11439 0061 +11439 0041 +11439 0062 +1143A 0021 +1143A 003F +1143A 0334 +1143A 0061 +1143A 0041 +1143A 0062 +1143B 0021 +1143B 003F +1143B 0334 +1143B 0061 +1143B 0041 +1143B 0062 +1143C 0021 +1143C 003F +1143C 0334 +1143C 0061 +1143C 0041 +1143C 0062 +1143D 0021 +1143D 003F +1143D 0334 +1143D 0061 +1143D 0041 +1143D 0062 +1143E 0021 +1143E 003F +1143E 0334 +1143E 0061 +1143E 0041 +1143E 0062 +1143F 0021 +1143F 003F +1143F 0334 +1143F 0061 +1143F 0041 +1143F 0062 +11440 0021 +11440 003F +11440 0334 +11440 0061 +11440 0041 +11440 0062 +11441 0021 +11441 003F +11441 0334 +11441 0061 +11441 0041 +11441 0062 +11442 0021 +11442 003F +0334 11442 +11442 0334 +11442 0061 +11442 0041 +11442 0062 114C7 0021 114C7 003F 114C7 0334 @@ -94125,6 +97170,7 @@ A8C4 0062 1172A 0062 1172B 0021 1172B 003F +0334 1172B 1172B 0334 1172B 0061 1172B 0041 @@ -94147,6 +97193,374 @@ A8C4 0062 1171F 0061 1171F 0041 1171F 0062 +11D00 0021 +11D00 003F +11D00 0334 +11D00 0061 +11D00 0041 +11D00 0062 +11D01 0021 +11D01 003F +11D01 0334 +11D01 0061 +11D01 0041 +11D01 0062 +11D02 0021 +11D02 003F +11D02 0334 +11D02 0061 +11D02 0041 +11D02 0062 +11D03 0021 +11D03 003F +11D03 0334 +11D03 0061 +11D03 0041 +11D03 0062 +11D04 0021 +11D04 003F +11D04 0334 +11D04 0061 +11D04 0041 +11D04 0062 +11D05 0021 +11D05 003F +11D05 0334 +11D05 0061 +11D05 0041 +11D05 0062 +11D06 0021 +11D06 003F +11D06 0334 +11D06 0061 +11D06 0041 +11D06 0062 +11D08 0021 +11D08 003F +11D08 0334 +11D08 0061 +11D08 0041 +11D08 0062 +11D09 0021 +11D09 003F +11D09 0334 +11D09 0061 +11D09 0041 +11D09 0062 +11D0B 0021 +11D0B 003F +11D0B 0334 +11D0B 0061 +11D0B 0041 +11D0B 0062 +11D0C 0021 +11D0C 003F +11D0C 0334 +11D0C 0061 +11D0C 0041 +11D0C 0062 +11D0D 0021 +11D0D 003F +11D0D 0334 +11D0D 0061 +11D0D 0041 +11D0D 0062 +11D0E 0021 +11D0E 003F +11D0E 0334 +11D0E 0061 +11D0E 0041 +11D0E 0062 +11D0F 0021 +11D0F 003F +11D0F 0334 +11D0F 0061 +11D0F 0041 +11D0F 0062 +11D10 0021 +11D10 003F +11D10 0334 +11D10 0061 +11D10 0041 +11D10 0062 +11D11 0021 +11D11 003F +11D11 0334 +11D11 0061 +11D11 0041 +11D11 0062 +11D12 0021 +11D12 003F +11D12 0334 +11D12 0061 +11D12 0041 +11D12 0062 +11D13 0021 +11D13 003F +11D13 0334 +11D13 0061 +11D13 0041 +11D13 0062 +11D14 0021 +11D14 003F +11D14 0334 +11D14 0061 +11D14 0041 +11D14 0062 +11D15 0021 +11D15 003F +11D15 0334 +11D15 0061 +11D15 0041 +11D15 0062 +11D16 0021 +11D16 003F +11D16 0334 +11D16 0061 +11D16 0041 +11D16 0062 +11D17 0021 +11D17 003F +11D17 0334 +11D17 0061 +11D17 0041 +11D17 0062 +11D18 0021 +11D18 003F +11D18 0334 +11D18 0061 +11D18 0041 +11D18 0062 +11D19 0021 +11D19 003F +11D19 0334 +11D19 0061 +11D19 0041 +11D19 0062 +11D1A 0021 +11D1A 003F +11D1A 0334 +11D1A 0061 +11D1A 0041 +11D1A 0062 +11D1B 0021 +11D1B 003F +11D1B 0334 +11D1B 0061 +11D1B 0041 +11D1B 0062 +11D1C 0021 +11D1C 003F +11D1C 0334 +11D1C 0061 +11D1C 0041 +11D1C 0062 +11D1D 0021 +11D1D 003F +11D1D 0334 +11D1D 0061 +11D1D 0041 +11D1D 0062 +11D1E 0021 +11D1E 003F +11D1E 0334 +11D1E 0061 +11D1E 0041 +11D1E 0062 +11D1F 0021 +11D1F 003F +11D1F 0334 +11D1F 0061 +11D1F 0041 +11D1F 0062 +11D20 0021 +11D20 003F +11D20 0334 +11D20 0061 +11D20 0041 +11D20 0062 +11D21 0021 +11D21 003F +11D21 0334 +11D21 0061 +11D21 0041 +11D21 0062 +11D22 0021 +11D22 003F +11D22 0334 +11D22 0061 +11D22 0041 +11D22 0062 +11D23 0021 +11D23 003F +11D23 0334 +11D23 0061 +11D23 0041 +11D23 0062 +11D24 0021 +11D24 003F +11D24 0334 +11D24 0061 +11D24 0041 +11D24 0062 +11D25 0021 +11D25 003F +11D25 0334 +11D25 0061 +11D25 0041 +11D25 0062 +11D26 0021 +11D26 003F +11D46 0021 +11D46 003F +11D47 0021 +11D47 003F +11D26 0334 +11D46 0334 +11D47 0334 +11D26 0061 +11D26 0041 +11D46 0061 +11D46 0041 +11D47 0061 +11D47 0041 +11D26 0062 +11D46 0062 +11D47 0062 +11D27 0021 +11D27 003F +11D27 0334 +11D27 0061 +11D27 0041 +11D27 0062 +11D28 0021 +11D28 003F +11D28 0334 +11D28 0061 +11D28 0041 +11D28 0062 +11D29 0021 +11D29 003F +11D29 0334 +11D29 0061 +11D29 0041 +11D29 0062 +11D2A 0021 +11D2A 003F +11D2A 0334 +11D2A 0061 +11D2A 0041 +11D2A 0062 +11D2B 0021 +11D2B 003F +11D2B 0334 +11D2B 0061 +11D2B 0041 +11D2B 0062 +11D2C 0021 +11D2C 003F +11D2C 0334 +11D2C 0061 +11D2C 0041 +11D2C 0062 +11D2D 0021 +11D2D 003F +11D2D 0334 +11D2D 0061 +11D2D 0041 +11D2D 0062 +11D2E 0021 +11D2E 003F +11D2E 0334 +11D2E 0061 +11D2E 0041 +11D2E 0062 +11D2F 0021 +11D2F 003F +11D2F 0334 +11D2F 0061 +11D2F 0041 +11D2F 0062 +11D30 0021 +11D30 003F +11D30 0334 +11D30 0061 +11D30 0041 +11D30 0062 +11D31 0021 +11D31 003F +11D31 0334 +11D31 0061 +11D31 0041 +11D31 0062 +11D32 0021 +11D32 003F +11D32 0334 +11D32 0061 +11D32 0041 +11D32 0062 +11D33 0021 +11D33 003F +11D33 0334 +11D33 0061 +11D33 0041 +11D33 0062 +11D34 0021 +11D34 003F +11D34 0334 +11D34 0061 +11D34 0041 +11D34 0062 +11D35 0021 +11D35 003F +11D35 0334 +11D35 0061 +11D35 0041 +11D35 0062 +11D36 0021 +11D36 003F +11D36 0334 +11D36 0061 +11D36 0041 +11D36 0062 +11D3A 0021 +11D3A 003F +11D3A 0334 +11D3A 0061 +11D3A 0041 +11D3A 0062 +11D3C 0021 +11D3C 003F +11D3C 0334 +11D3C 0061 +11D3C 0041 +11D3C 0062 +11D3D 0021 +11D3D 003F +11D3D 0334 +11D3D 0061 +11D3D 0041 +11D3D 0062 +11D3F 0021 +11D3F 003F +11D3F 0334 +11D3F 0061 +11D3F 0041 +11D3F 0062 +11D44 0021 +11D44 003F +0334 11D44 +11D44 0334 +11D44 0061 +11D44 0041 +11D44 0062 +11D45 0021 +11D45 003F +0334 11D45 +11D45 0334 +11D45 0061 +11D45 0041 +11D45 0062 1B83 0021 1B83 003F 1BBA 0021 @@ -95075,6 +98489,367 @@ A8C4 0062 10A3F 0061 10A3F 0041 10A3F 0062 +11C00 0021 +11C00 003F +11C00 0334 +11C00 0061 +11C00 0041 +11C00 0062 +11C01 0021 +11C01 003F +11C01 0334 +11C01 0061 +11C01 0041 +11C01 0062 +11C02 0021 +11C02 003F +11C02 0334 +11C02 0061 +11C02 0041 +11C02 0062 +11C03 0021 +11C03 003F +11C03 0334 +11C03 0061 +11C03 0041 +11C03 0062 +11C04 0021 +11C04 003F +11C04 0334 +11C04 0061 +11C04 0041 +11C04 0062 +11C05 0021 +11C05 003F +11C05 0334 +11C05 0061 +11C05 0041 +11C05 0062 +11C06 0021 +11C06 003F +11C06 0334 +11C06 0061 +11C06 0041 +11C06 0062 +11C07 0021 +11C07 003F +11C07 0334 +11C07 0061 +11C07 0041 +11C07 0062 +11C08 0021 +11C08 003F +11C08 0334 +11C08 0061 +11C08 0041 +11C08 0062 +11C0A 0021 +11C0A 003F +11C0A 0334 +11C0A 0061 +11C0A 0041 +11C0A 0062 +11C0B 0021 +11C0B 003F +11C0B 0334 +11C0B 0061 +11C0B 0041 +11C0B 0062 +11C0C 0021 +11C0C 003F +11C0C 0334 +11C0C 0061 +11C0C 0041 +11C0C 0062 +11C0D 0021 +11C0D 003F +11C0D 0334 +11C0D 0061 +11C0D 0041 +11C0D 0062 +11C0E 0021 +11C0E 003F +11C0E 0334 +11C0E 0061 +11C0E 0041 +11C0E 0062 +11C0F 0021 +11C0F 003F +11C0F 0334 +11C0F 0061 +11C0F 0041 +11C0F 0062 +11C10 0021 +11C10 003F +11C10 0334 +11C10 0061 +11C10 0041 +11C10 0062 +11C11 0021 +11C11 003F +11C11 0334 +11C11 0061 +11C11 0041 +11C11 0062 +11C12 0021 +11C12 003F +11C12 0334 +11C12 0061 +11C12 0041 +11C12 0062 +11C13 0021 +11C13 003F +11C13 0334 +11C13 0061 +11C13 0041 +11C13 0062 +11C14 0021 +11C14 003F +11C14 0334 +11C14 0061 +11C14 0041 +11C14 0062 +11C15 0021 +11C15 003F +11C15 0334 +11C15 0061 +11C15 0041 +11C15 0062 +11C16 0021 +11C16 003F +11C16 0334 +11C16 0061 +11C16 0041 +11C16 0062 +11C17 0021 +11C17 003F +11C17 0334 +11C17 0061 +11C17 0041 +11C17 0062 +11C18 0021 +11C18 003F +11C18 0334 +11C18 0061 +11C18 0041 +11C18 0062 +11C19 0021 +11C19 003F +11C19 0334 +11C19 0061 +11C19 0041 +11C19 0062 +11C1A 0021 +11C1A 003F +11C1A 0334 +11C1A 0061 +11C1A 0041 +11C1A 0062 +11C1B 0021 +11C1B 003F +11C1B 0334 +11C1B 0061 +11C1B 0041 +11C1B 0062 +11C1C 0021 +11C1C 003F +11C1C 0334 +11C1C 0061 +11C1C 0041 +11C1C 0062 +11C1D 0021 +11C1D 003F +11C1D 0334 +11C1D 0061 +11C1D 0041 +11C1D 0062 +11C1E 0021 +11C1E 003F +11C1E 0334 +11C1E 0061 +11C1E 0041 +11C1E 0062 +11C1F 0021 +11C1F 003F +11C1F 0334 +11C1F 0061 +11C1F 0041 +11C1F 0062 +11C20 0021 +11C20 003F +11C20 0334 +11C20 0061 +11C20 0041 +11C20 0062 +11C21 0021 +11C21 003F +11C21 0334 +11C21 0061 +11C21 0041 +11C21 0062 +11C22 0021 +11C22 003F +11C22 0334 +11C22 0061 +11C22 0041 +11C22 0062 +11C23 0021 +11C23 003F +11C23 0334 +11C23 0061 +11C23 0041 +11C23 0062 +11C24 0021 +11C24 003F +11C24 0334 +11C24 0061 +11C24 0041 +11C24 0062 +11C25 0021 +11C25 003F +11C25 0334 +11C25 0061 +11C25 0041 +11C25 0062 +11C26 0021 +11C26 003F +11C26 0334 +11C26 0061 +11C26 0041 +11C26 0062 +11C27 0021 +11C27 003F +11C27 0334 +11C27 0061 +11C27 0041 +11C27 0062 +11C28 0021 +11C28 003F +11C28 0334 +11C28 0061 +11C28 0041 +11C28 0062 +11C29 0021 +11C29 003F +11C29 0334 +11C29 0061 +11C29 0041 +11C29 0062 +11C2A 0021 +11C2A 003F +11C2A 0334 +11C2A 0061 +11C2A 0041 +11C2A 0062 +11C2B 0021 +11C2B 003F +11C2B 0334 +11C2B 0061 +11C2B 0041 +11C2B 0062 +11C2C 0021 +11C2C 003F +11C2C 0334 +11C2C 0061 +11C2C 0041 +11C2C 0062 +11C2D 0021 +11C2D 003F +11C2D 0334 +11C2D 0061 +11C2D 0041 +11C2D 0062 +11C2E 0021 +11C2E 003F +11C2E 0334 +11C2E 0061 +11C2E 0041 +11C2E 0062 +11C40 0021 +11C40 003F +11C40 0334 +11C40 0061 +11C40 0041 +11C40 0062 +11C2F 0021 +11C2F 003F +11C2F 0334 +11C2F 0061 +11C2F 0041 +11C2F 0062 +11C30 0021 +11C30 003F +11C30 0334 +11C30 0061 +11C30 0041 +11C30 0062 +11C31 0021 +11C31 003F +11C31 0334 +11C31 0061 +11C31 0041 +11C31 0062 +11C32 0021 +11C32 003F +11C32 0334 +11C32 0061 +11C32 0041 +11C32 0062 +11C33 0021 +11C33 003F +11C33 0334 +11C33 0061 +11C33 0041 +11C33 0062 +11C34 0021 +11C34 003F +11C34 0334 +11C34 0061 +11C34 0041 +11C34 0062 +11C35 0021 +11C35 003F +11C35 0334 +11C35 0061 +11C35 0041 +11C35 0062 +11C36 0021 +11C36 003F +11C36 0334 +11C36 0061 +11C36 0041 +11C36 0062 +11C38 0021 +11C38 003F +11C38 0334 +11C38 0061 +11C38 0041 +11C38 0062 +11C39 0021 +11C39 003F +11C39 0334 +11C39 0061 +11C39 0041 +11C39 0062 +11C3A 0021 +11C3A 003F +11C3A 0334 +11C3A 0061 +11C3A 0041 +11C3A 0062 +11C3B 0021 +11C3B 003F +11C3B 0334 +11C3B 0061 +11C3B 0041 +11C3B 0062 +11C3F 0021 +11C3F 003F +0334 11C3F +11C3F 0334 +11C3F 0061 +11C3F 0041 +11C3F 0062 0E01 0021 0E01 003F 0E01 0061 @@ -101534,10 +105309,10 @@ AADC 0062 0F73 0021 0F71 0F72 003F 0F73 003F -0334 0F73 +0334 0F71 0F72 +0F71 0334 0F72 0F71 0F72 0334 0F72 0334 0F71 -0F72 0F71 0334 0F71 0F72 0061 0F73 0061 0F71 0591 0F72 0061 @@ -101560,7 +105335,7 @@ AADC 0062 0334 0F80 0F71 0334 0F81 0F71 0334 0F80 -0F71 0F80 0334 +0F80 0334 0F71 0F71 0F80 0061 0F81 0061 0F71 0591 0F80 0061 @@ -101580,10 +105355,10 @@ AADC 0062 0F75 0021 0F71 0F74 003F 0F75 003F -0334 0F74 0F71 +0334 0F71 0F74 +0334 0F75 0F71 0334 0F74 0F71 0F74 0334 -0F74 0334 0F71 0F71 0F74 0061 0F75 0061 0F71 0591 0F74 0061 @@ -101608,9 +105383,9 @@ AADC 0062 0F76 0062 0FB2 0F80 0062 0F76 0F71 0334 +0FB2 0334 0F71 0F80 +0FB2 0334 0F80 0F71 0FB2 0334 0F81 -0FB2 0F80 0334 0F71 -0FB2 0F80 0F71 0334 0F77 0021 0FB2 0F71 0F80 0021 0FB2 0F81 0021 @@ -101647,10 +105422,10 @@ AADC 0062 0FB3 0F80 0041 0F78 0062 0FB3 0F80 0062 -0F78 0334 0F71 0F78 0F71 0334 0FB3 0334 0F71 0F80 -0FB3 0334 0F81 +0FB3 0334 0F80 0F71 +0FB3 0F71 0334 0F80 0F79 0021 0FB3 0F71 0F80 0021 0FB3 0F81 0021 @@ -101707,6 +105482,1155 @@ AADC 0062 0F84 0061 0F84 0041 0F84 0062 +11A0B 0021 +11A0B 003F +11A0B 0334 +11A0B 0061 +11A0B 0041 +11A0B 0062 +11A32 0021 +11A32 003F +11A32 0334 +11A32 0061 +11A32 0041 +11A32 0062 +11A0C 0021 +11A0C 003F +11A0C 0334 +11A0C 0061 +11A0C 0041 +11A0C 0062 +11A0D 0021 +11A0D 003F +11A0D 0334 +11A0D 0061 +11A0D 0041 +11A0D 0062 +11A0E 0021 +11A0E 003F +11A0E 0334 +11A0E 0061 +11A0E 0041 +11A0E 0062 +11A0F 0021 +11A0F 003F +11A0F 0334 +11A0F 0061 +11A0F 0041 +11A0F 0062 +11A10 0021 +11A10 003F +11A10 0334 +11A10 0061 +11A10 0041 +11A10 0062 +11A11 0021 +11A11 003F +11A11 0334 +11A11 0061 +11A11 0041 +11A11 0062 +11A12 0021 +11A12 003F +11A12 0334 +11A12 0061 +11A12 0041 +11A12 0062 +11A13 0021 +11A13 003F +11A13 0334 +11A13 0061 +11A13 0041 +11A13 0062 +11A14 0021 +11A14 003F +11A14 0334 +11A14 0061 +11A14 0041 +11A14 0062 +11A15 0021 +11A15 003F +11A15 0334 +11A15 0061 +11A15 0041 +11A15 0062 +11A16 0021 +11A16 003F +11A16 0334 +11A16 0061 +11A16 0041 +11A16 0062 +11A17 0021 +11A17 003F +11A17 0334 +11A17 0061 +11A17 0041 +11A17 0062 +11A18 0021 +11A18 003F +11A18 0334 +11A18 0061 +11A18 0041 +11A18 0062 +11A19 0021 +11A19 003F +11A19 0334 +11A19 0061 +11A19 0041 +11A19 0062 +11A1A 0021 +11A1A 003F +11A1A 0334 +11A1A 0061 +11A1A 0041 +11A1A 0062 +11A1B 0021 +11A1B 003F +11A1B 0334 +11A1B 0061 +11A1B 0041 +11A1B 0062 +11A1C 0021 +11A1C 003F +11A1C 0334 +11A1C 0061 +11A1C 0041 +11A1C 0062 +11A1D 0021 +11A1D 003F +11A1D 0334 +11A1D 0061 +11A1D 0041 +11A1D 0062 +11A1E 0021 +11A1E 003F +11A1E 0334 +11A1E 0061 +11A1E 0041 +11A1E 0062 +11A1F 0021 +11A1F 003F +11A1F 0334 +11A1F 0061 +11A1F 0041 +11A1F 0062 +11A20 0021 +11A20 003F +11A20 0334 +11A20 0061 +11A20 0041 +11A20 0062 +11A21 0021 +11A21 003F +11A21 0334 +11A21 0061 +11A21 0041 +11A21 0062 +11A22 0021 +11A22 003F +11A22 0334 +11A22 0061 +11A22 0041 +11A22 0062 +11A23 0021 +11A23 003F +11A23 0334 +11A23 0061 +11A23 0041 +11A23 0062 +11A24 0021 +11A24 003F +11A24 0334 +11A24 0061 +11A24 0041 +11A24 0062 +11A25 0021 +11A25 003F +11A25 0334 +11A25 0061 +11A25 0041 +11A25 0062 +11A26 0021 +11A26 003F +11A26 0334 +11A26 0061 +11A26 0041 +11A26 0062 +11A27 0021 +11A27 003F +11A27 0334 +11A27 0061 +11A27 0041 +11A27 0062 +11A28 0021 +11A28 003F +11A28 0334 +11A28 0061 +11A28 0041 +11A28 0062 +11A29 0021 +11A29 003F +11A29 0334 +11A29 0061 +11A29 0041 +11A29 0062 +11A2A 0021 +11A2A 003F +11A3B 0021 +11A3B 003F +11A2A 0334 +11A3B 0334 +11A2A 0061 +11A2A 0041 +11A3B 0061 +11A3B 0041 +11A2A 0062 +11A3B 0062 +11A2B 0021 +11A2B 003F +11A3A 0021 +11A3A 003F +11A3C 0021 +11A3C 003F +11A2B 0334 +11A3A 0334 +11A3C 0334 +11A2B 0061 +11A2B 0041 +11A3A 0061 +11A3A 0041 +11A3C 0061 +11A3C 0041 +11A2B 0062 +11A3A 0062 +11A3C 0062 +11A2C 0021 +11A2C 003F +11A3D 0021 +11A3D 003F +11A2C 0334 +11A3D 0334 +11A2C 0061 +11A2C 0041 +11A3D 0061 +11A3D 0041 +11A2C 0062 +11A3D 0062 +11A2D 0021 +11A2D 003F +11A3E 0021 +11A3E 003F +11A2D 0334 +11A3E 0334 +11A2D 0061 +11A2D 0041 +11A3E 0061 +11A3E 0041 +11A2D 0062 +11A3E 0062 +11A2E 0021 +11A2E 003F +11A2E 0334 +11A2E 0061 +11A2E 0041 +11A2E 0062 +11A2F 0021 +11A2F 003F +11A2F 0334 +11A2F 0061 +11A2F 0041 +11A2F 0062 +11A30 0021 +11A30 003F +11A30 0334 +11A30 0061 +11A30 0041 +11A30 0062 +11A31 0021 +11A31 003F +11A31 0334 +11A31 0061 +11A31 0041 +11A31 0062 +11A00 0021 +11A00 003F +11A00 0334 +11A00 0061 +11A00 0041 +11A00 0062 +11A01 0021 +11A01 003F +11A01 0334 +11A01 0061 +11A01 0041 +11A01 0062 +11A02 0021 +11A02 003F +11A02 0334 +11A02 0061 +11A02 0041 +11A02 0062 +11A03 0021 +11A03 003F +11A03 0334 +11A03 0061 +11A03 0041 +11A03 0062 +11A04 0021 +11A04 003F +11A04 0334 +11A04 0061 +11A04 0041 +11A04 0062 +11A05 0021 +11A05 003F +11A05 0334 +11A05 0061 +11A05 0041 +11A05 0062 +11A06 0021 +11A06 003F +11A06 0334 +11A06 0061 +11A06 0041 +11A06 0062 +11A07 0021 +11A07 003F +11A07 0334 +11A07 0061 +11A07 0041 +11A07 0062 +11A08 0021 +11A08 003F +11A08 0334 +11A08 0061 +11A08 0041 +11A08 0062 +11A09 0021 +11A09 003F +11A09 0334 +11A09 0061 +11A09 0041 +11A09 0062 +11A0A 0021 +11A0A 003F +11A0A 0334 +11A0A 0061 +11A0A 0041 +11A0A 0062 +11A34 0021 +11A34 003F +0334 11A34 +11A34 0334 +11A34 0061 +11A34 0041 +11A34 0062 +11A47 0021 +11A47 003F +0334 11A47 +11A47 0334 +11A47 0061 +11A47 0041 +11A47 0062 +11A50 0021 +11A50 003F +11A50 0334 +11A50 0061 +11A50 0041 +11A50 0062 +11A51 0021 +11A51 003F +11A51 0334 +11A51 0061 +11A51 0041 +11A51 0062 +11A52 0021 +11A52 003F +11A52 0334 +11A52 0061 +11A52 0041 +11A52 0062 +11A53 0021 +11A53 003F +11A53 0334 +11A53 0061 +11A53 0041 +11A53 0062 +11A59 0021 +11A59 003F +11A59 0334 +11A59 0061 +11A59 0041 +11A59 0062 +11A5A 0021 +11A5A 003F +11A5A 0334 +11A5A 0061 +11A5A 0041 +11A5A 0062 +11A54 0021 +11A54 003F +11A54 0334 +11A54 0061 +11A54 0041 +11A54 0062 +11A56 0021 +11A56 003F +11A56 0334 +11A56 0061 +11A56 0041 +11A56 0062 +11A55 0021 +11A55 003F +11A55 0334 +11A55 0061 +11A55 0041 +11A55 0062 +11A57 0021 +11A57 003F +11A57 0334 +11A57 0061 +11A57 0041 +11A57 0062 +11A58 0021 +11A58 003F +11A58 0334 +11A58 0061 +11A58 0041 +11A58 0062 +11A5B 0021 +11A5B 003F +11A5B 0334 +11A5B 0061 +11A5B 0041 +11A5B 0062 +11A5C 0021 +11A5C 003F +11A8A 0021 +11A8A 003F +11A5C 0334 +11A8A 0334 +11A5C 0061 +11A5C 0041 +11A8A 0061 +11A8A 0041 +11A5C 0062 +11A8A 0062 +11A83 0021 +11A83 003F +11A83 0334 +11A83 0061 +11A83 0041 +11A83 0062 +11A5D 0021 +11A5D 003F +11A8B 0021 +11A8B 003F +11A5D 0334 +11A8B 0334 +11A5D 0061 +11A5D 0041 +11A8B 0061 +11A8B 0041 +11A5D 0062 +11A8B 0062 +11A5E 0021 +11A5E 003F +11A5E 0334 +11A5E 0061 +11A5E 0041 +11A5E 0062 +11A5F 0021 +11A5F 003F +11A5F 0334 +11A5F 0061 +11A5F 0041 +11A5F 0062 +11A60 0021 +11A60 003F +11A8C 0021 +11A8C 003F +11A60 0334 +11A8C 0334 +11A60 0061 +11A60 0041 +11A8C 0061 +11A8C 0041 +11A60 0062 +11A8C 0062 +11A61 0021 +11A61 003F +11A61 0334 +11A61 0061 +11A61 0041 +11A61 0062 +11A62 0021 +11A62 003F +11A62 0334 +11A62 0061 +11A62 0041 +11A62 0062 +11A63 0021 +11A63 003F +11A63 0334 +11A63 0061 +11A63 0041 +11A63 0062 +11A64 0021 +11A64 003F +11A64 0334 +11A64 0061 +11A64 0041 +11A64 0062 +11A65 0021 +11A65 003F +11A65 0334 +11A65 0061 +11A65 0041 +11A65 0062 +11A66 0021 +11A66 003F +11A66 0334 +11A66 0061 +11A66 0041 +11A66 0062 +11A67 0021 +11A67 003F +11A67 0334 +11A67 0061 +11A67 0041 +11A67 0062 +11A68 0021 +11A68 003F +11A68 0334 +11A68 0061 +11A68 0041 +11A68 0062 +11A69 0021 +11A69 003F +11A69 0334 +11A69 0061 +11A69 0041 +11A69 0062 +11A6A 0021 +11A6A 003F +11A6A 0334 +11A6A 0061 +11A6A 0041 +11A6A 0062 +11A6B 0021 +11A6B 003F +11A8D 0021 +11A8D 003F +11A6B 0334 +11A8D 0334 +11A6B 0061 +11A6B 0041 +11A8D 0061 +11A8D 0041 +11A6B 0062 +11A8D 0062 +11A6C 0021 +11A6C 003F +11A6C 0334 +11A6C 0061 +11A6C 0041 +11A6C 0062 +11A6D 0021 +11A6D 003F +11A6D 0334 +11A6D 0061 +11A6D 0041 +11A6D 0062 +11A6E 0021 +11A6E 003F +11A6E 0334 +11A6E 0061 +11A6E 0041 +11A6E 0062 +11A6F 0021 +11A6F 003F +11A8E 0021 +11A8E 003F +11A6F 0334 +11A8E 0334 +11A6F 0061 +11A6F 0041 +11A8E 0061 +11A8E 0041 +11A6F 0062 +11A8E 0062 +11A70 0021 +11A70 003F +11A8F 0021 +11A8F 003F +11A70 0334 +11A8F 0334 +11A70 0061 +11A70 0041 +11A8F 0061 +11A8F 0041 +11A70 0062 +11A8F 0062 +11A71 0021 +11A71 003F +11A71 0334 +11A71 0061 +11A71 0041 +11A71 0062 +11A72 0021 +11A72 003F +11A72 0334 +11A72 0061 +11A72 0041 +11A72 0062 +11A73 0021 +11A73 003F +11A73 0334 +11A73 0061 +11A73 0041 +11A73 0062 +11A74 0021 +11A74 003F +11A90 0021 +11A90 003F +11A74 0334 +11A90 0334 +11A74 0061 +11A74 0041 +11A90 0061 +11A90 0041 +11A74 0062 +11A90 0062 +11A75 0021 +11A75 003F +11A75 0334 +11A75 0061 +11A75 0041 +11A75 0062 +11A76 0021 +11A76 003F +11A76 0334 +11A76 0061 +11A76 0041 +11A76 0062 +11A77 0021 +11A77 003F +11A77 0334 +11A77 0061 +11A77 0041 +11A77 0062 +11A78 0021 +11A78 003F +11A78 0334 +11A78 0061 +11A78 0041 +11A78 0062 +11A79 0021 +11A79 003F +11A79 0334 +11A79 0061 +11A79 0041 +11A79 0062 +11A7A 0021 +11A7A 003F +11A95 0021 +11A95 003F +11A7A 0334 +11A95 0334 +11A7A 0061 +11A7A 0041 +11A95 0061 +11A95 0041 +11A7A 0062 +11A95 0062 +11A7B 0021 +11A7B 003F +11A7B 0334 +11A7B 0061 +11A7B 0041 +11A7B 0062 +11A7C 0021 +11A7C 003F +11A86 0021 +11A86 003F +11A91 0021 +11A91 003F +11A7C 0334 +11A86 0334 +11A91 0334 +11A7C 0061 +11A7C 0041 +11A86 0061 +11A86 0041 +11A91 0061 +11A91 0041 +11A7C 0062 +11A86 0062 +11A91 0062 +11A7D 0021 +11A7D 003F +11A87 0021 +11A87 003F +11A92 0021 +11A92 003F +11A7D 0334 +11A87 0334 +11A92 0334 +11A7D 0061 +11A7D 0041 +11A87 0061 +11A87 0041 +11A92 0061 +11A92 0041 +11A7D 0062 +11A87 0062 +11A92 0062 +11A7E 0021 +11A7E 003F +11A7E 0334 +11A7E 0061 +11A7E 0041 +11A7E 0062 +11A7F 0021 +11A7F 003F +11A88 0021 +11A88 003F +11A93 0021 +11A93 003F +11A7F 0334 +11A88 0334 +11A93 0334 +11A7F 0061 +11A7F 0041 +11A88 0061 +11A88 0041 +11A93 0061 +11A93 0041 +11A7F 0062 +11A88 0062 +11A93 0062 +11A80 0021 +11A80 003F +11A80 0334 +11A80 0061 +11A80 0041 +11A80 0062 +11A81 0021 +11A81 003F +11A89 0021 +11A89 003F +11A94 0021 +11A94 003F +11A81 0334 +11A89 0334 +11A94 0334 +11A81 0061 +11A81 0041 +11A89 0061 +11A89 0041 +11A94 0061 +11A94 0041 +11A81 0062 +11A89 0062 +11A94 0062 +11A82 0021 +11A82 003F +11A82 0334 +11A82 0061 +11A82 0041 +11A82 0062 +11A99 0021 +11A99 003F +0334 11A99 +11A99 0334 +11A99 0061 +11A99 0041 +11A99 0062 +11C72 0021 +11C72 003F +11C72 0334 +11C72 0061 +11C72 0041 +11C72 0062 +11C92 0021 +11C92 003F +11C92 0334 +11C92 0061 +11C92 0041 +11C92 0062 +11C73 0021 +11C73 003F +11C73 0334 +11C73 0061 +11C73 0041 +11C73 0062 +11C93 0021 +11C93 003F +11C93 0334 +11C93 0061 +11C93 0041 +11C93 0062 +11C74 0021 +11C74 003F +11C74 0334 +11C74 0061 +11C74 0041 +11C74 0062 +11C94 0021 +11C94 003F +11C94 0334 +11C94 0061 +11C94 0041 +11C94 0062 +11C75 0021 +11C75 003F +11C75 0334 +11C75 0061 +11C75 0041 +11C75 0062 +11C95 0021 +11C95 003F +11C95 0334 +11C95 0061 +11C95 0041 +11C95 0062 +11C76 0021 +11C76 003F +11C76 0334 +11C76 0061 +11C76 0041 +11C76 0062 +11C96 0021 +11C96 003F +11C96 0334 +11C96 0061 +11C96 0041 +11C96 0062 +11C77 0021 +11C77 003F +11C77 0334 +11C77 0061 +11C77 0041 +11C77 0062 +11C97 0021 +11C97 003F +11C97 0334 +11C97 0061 +11C97 0041 +11C97 0062 +11C78 0021 +11C78 003F +11C78 0334 +11C78 0061 +11C78 0041 +11C78 0062 +11C98 0021 +11C98 003F +11C98 0334 +11C98 0061 +11C98 0041 +11C98 0062 +11C79 0021 +11C79 003F +11C79 0334 +11C79 0061 +11C79 0041 +11C79 0062 +11C99 0021 +11C99 003F +11C99 0334 +11C99 0061 +11C99 0041 +11C99 0062 +11C7A 0021 +11C7A 003F +11C7A 0334 +11C7A 0061 +11C7A 0041 +11C7A 0062 +11C9A 0021 +11C9A 003F +11C9A 0334 +11C9A 0061 +11C9A 0041 +11C9A 0062 +11C7B 0021 +11C7B 003F +11C7B 0334 +11C7B 0061 +11C7B 0041 +11C7B 0062 +11C9B 0021 +11C9B 003F +11C9B 0334 +11C9B 0061 +11C9B 0041 +11C9B 0062 +11C7C 0021 +11C7C 003F +11C7C 0334 +11C7C 0061 +11C7C 0041 +11C7C 0062 +11C9C 0021 +11C9C 003F +11C9C 0334 +11C9C 0061 +11C9C 0041 +11C9C 0062 +11C7D 0021 +11C7D 003F +11C7D 0334 +11C7D 0061 +11C7D 0041 +11C7D 0062 +11C9D 0021 +11C9D 003F +11C9D 0334 +11C9D 0061 +11C9D 0041 +11C9D 0062 +11C7E 0021 +11C7E 003F +11C7E 0334 +11C7E 0061 +11C7E 0041 +11C7E 0062 +11C9E 0021 +11C9E 003F +11C9E 0334 +11C9E 0061 +11C9E 0041 +11C9E 0062 +11C7F 0021 +11C7F 003F +11C7F 0334 +11C7F 0061 +11C7F 0041 +11C7F 0062 +11C9F 0021 +11C9F 003F +11C9F 0334 +11C9F 0061 +11C9F 0041 +11C9F 0062 +11C80 0021 +11C80 003F +11C80 0334 +11C80 0061 +11C80 0041 +11C80 0062 +11CA0 0021 +11CA0 003F +11CA0 0334 +11CA0 0061 +11CA0 0041 +11CA0 0062 +11C81 0021 +11C81 003F +11C81 0334 +11C81 0061 +11C81 0041 +11C81 0062 +11CA1 0021 +11CA1 003F +11CA1 0334 +11CA1 0061 +11CA1 0041 +11CA1 0062 +11C82 0021 +11C82 003F +11C82 0334 +11C82 0061 +11C82 0041 +11C82 0062 +11CA2 0021 +11CA2 003F +11CA2 0334 +11CA2 0061 +11CA2 0041 +11CA2 0062 +11C83 0021 +11C83 003F +11C83 0334 +11C83 0061 +11C83 0041 +11C83 0062 +11CA3 0021 +11CA3 003F +11CA3 0334 +11CA3 0061 +11CA3 0041 +11CA3 0062 +11C84 0021 +11C84 003F +11C84 0334 +11C84 0061 +11C84 0041 +11C84 0062 +11CA4 0021 +11CA4 003F +11CA4 0334 +11CA4 0061 +11CA4 0041 +11CA4 0062 +11C85 0021 +11C85 003F +11C85 0334 +11C85 0061 +11C85 0041 +11C85 0062 +11CA5 0021 +11CA5 003F +11CA5 0334 +11CA5 0061 +11CA5 0041 +11CA5 0062 +11C86 0021 +11C86 003F +11C86 0334 +11C86 0061 +11C86 0041 +11C86 0062 +11CA6 0021 +11CA6 003F +11CA6 0334 +11CA6 0061 +11CA6 0041 +11CA6 0062 +11C87 0021 +11C87 003F +11C87 0334 +11C87 0061 +11C87 0041 +11C87 0062 +11CA7 0021 +11CA7 003F +11CA7 0334 +11CA7 0061 +11CA7 0041 +11CA7 0062 +11C88 0021 +11C88 003F +11C88 0334 +11C88 0061 +11C88 0041 +11C88 0062 +11C89 0021 +11C89 003F +11C89 0334 +11C89 0061 +11C89 0041 +11C89 0062 +11CA9 0021 +11CA9 003F +11CA9 0334 +11CA9 0061 +11CA9 0041 +11CA9 0062 +11C8A 0021 +11C8A 003F +11C8A 0334 +11C8A 0061 +11C8A 0041 +11C8A 0062 +11CAA 0021 +11CAA 003F +11CAA 0334 +11CAA 0061 +11CAA 0041 +11CAA 0062 +11C8B 0021 +11C8B 003F +11C8B 0334 +11C8B 0061 +11C8B 0041 +11C8B 0062 +11CAB 0021 +11CAB 003F +11CAB 0334 +11CAB 0061 +11CAB 0041 +11CAB 0062 +11C8C 0021 +11C8C 003F +11C8C 0334 +11C8C 0061 +11C8C 0041 +11C8C 0062 +11CAC 0021 +11CAC 003F +11CAC 0334 +11CAC 0061 +11CAC 0041 +11CAC 0062 +11C8D 0021 +11C8D 003F +11C8D 0334 +11C8D 0061 +11C8D 0041 +11C8D 0062 +11CAD 0021 +11CAD 003F +11CAD 0334 +11CAD 0061 +11CAD 0041 +11CAD 0062 +11C8E 0021 +11C8E 003F +11C8E 0334 +11C8E 0061 +11C8E 0041 +11C8E 0062 +11CAE 0021 +11CAE 003F +11CAE 0334 +11CAE 0061 +11CAE 0041 +11CAE 0062 +11C8F 0021 +11C8F 003F +11C8F 0334 +11C8F 0061 +11C8F 0041 +11C8F 0062 +11CAF 0021 +11CAF 003F +11CAF 0334 +11CAF 0061 +11CAF 0041 +11CAF 0062 +11CB0 0021 +11CB0 003F +11CB0 0334 +11CB0 0061 +11CB0 0041 +11CB0 0062 +11CB1 0021 +11CB1 003F +11CB1 0334 +11CB1 0061 +11CB1 0041 +11CB1 0062 +11CB2 0021 +11CB2 003F +11CB2 0334 +11CB2 0061 +11CB2 0041 +11CB2 0062 +11CB3 0021 +11CB3 003F +11CB3 0334 +11CB3 0061 +11CB3 0041 +11CB3 0062 +11CB4 0021 +11CB4 003F +11CB4 0334 +11CB4 0061 +11CB4 0041 +11CB4 0062 1C00 0021 1C00 003F 1C00 0061 @@ -110381,6 +115305,438 @@ ABBF 0062 13F5 0041 13FD 0062 13F5 0062 +104D8 0021 +104D8 003F +104B0 0021 +104B0 003F +104D8 0334 +104B0 0334 +104D8 0061 +104D8 0041 +104B0 0061 +104B0 0041 +104D8 0062 +104B0 0062 +104D9 0021 +104D9 003F +104B1 0021 +104B1 003F +104D9 0334 +104B1 0334 +104D9 0061 +104D9 0041 +104B1 0061 +104B1 0041 +104D9 0062 +104B1 0062 +104DA 0021 +104DA 003F +104B2 0021 +104B2 003F +104DA 0334 +104B2 0334 +104DA 0061 +104DA 0041 +104B2 0061 +104B2 0041 +104DA 0062 +104B2 0062 +104DB 0021 +104DB 003F +104B3 0021 +104B3 003F +104DB 0334 +104B3 0334 +104DB 0061 +104DB 0041 +104B3 0061 +104B3 0041 +104DB 0062 +104B3 0062 +104DC 0021 +104DC 003F +104B4 0021 +104B4 003F +104DC 0334 +104B4 0334 +104DC 0061 +104DC 0041 +104B4 0061 +104B4 0041 +104DC 0062 +104B4 0062 +104DD 0021 +104DD 003F +104B5 0021 +104B5 003F +104DD 0334 +104B5 0334 +104DD 0061 +104DD 0041 +104B5 0061 +104B5 0041 +104DD 0062 +104B5 0062 +104DE 0021 +104DE 003F +104B6 0021 +104B6 003F +104DE 0334 +104B6 0334 +104DE 0061 +104DE 0041 +104B6 0061 +104B6 0041 +104DE 0062 +104B6 0062 +104DF 0021 +104DF 003F +104B7 0021 +104B7 003F +104DF 0334 +104B7 0334 +104DF 0061 +104DF 0041 +104B7 0061 +104B7 0041 +104DF 0062 +104B7 0062 +104E0 0021 +104E0 003F +104B8 0021 +104B8 003F +104E0 0334 +104B8 0334 +104E0 0061 +104E0 0041 +104B8 0061 +104B8 0041 +104E0 0062 +104B8 0062 +104E1 0021 +104E1 003F +104B9 0021 +104B9 003F +104E1 0334 +104B9 0334 +104E1 0061 +104E1 0041 +104B9 0061 +104B9 0041 +104E1 0062 +104B9 0062 +104E2 0021 +104E2 003F +104BA 0021 +104BA 003F +104E2 0334 +104BA 0334 +104E2 0061 +104E2 0041 +104BA 0061 +104BA 0041 +104E2 0062 +104BA 0062 +104E3 0021 +104E3 003F +104BB 0021 +104BB 003F +104E3 0334 +104BB 0334 +104E3 0061 +104E3 0041 +104BB 0061 +104BB 0041 +104E3 0062 +104BB 0062 +104E4 0021 +104E4 003F +104BC 0021 +104BC 003F +104E4 0334 +104BC 0334 +104E4 0061 +104E4 0041 +104BC 0061 +104BC 0041 +104E4 0062 +104BC 0062 +104E5 0021 +104E5 003F +104BD 0021 +104BD 003F +104E5 0334 +104BD 0334 +104E5 0061 +104E5 0041 +104BD 0061 +104BD 0041 +104E5 0062 +104BD 0062 +104E6 0021 +104E6 003F +104BE 0021 +104BE 003F +104E6 0334 +104BE 0334 +104E6 0061 +104E6 0041 +104BE 0061 +104BE 0041 +104E6 0062 +104BE 0062 +104E7 0021 +104E7 003F +104BF 0021 +104BF 003F +104E7 0334 +104BF 0334 +104E7 0061 +104E7 0041 +104BF 0061 +104BF 0041 +104E7 0062 +104BF 0062 +104E8 0021 +104E8 003F +104C0 0021 +104C0 003F +104E8 0334 +104C0 0334 +104E8 0061 +104E8 0041 +104C0 0061 +104C0 0041 +104E8 0062 +104C0 0062 +104E9 0021 +104E9 003F +104C1 0021 +104C1 003F +104E9 0334 +104C1 0334 +104E9 0061 +104E9 0041 +104C1 0061 +104C1 0041 +104E9 0062 +104C1 0062 +104EA 0021 +104EA 003F +104C2 0021 +104C2 003F +104EA 0334 +104C2 0334 +104EA 0061 +104EA 0041 +104C2 0061 +104C2 0041 +104EA 0062 +104C2 0062 +104EB 0021 +104EB 003F +104C3 0021 +104C3 003F +104EB 0334 +104C3 0334 +104EB 0061 +104EB 0041 +104C3 0061 +104C3 0041 +104EB 0062 +104C3 0062 +104EC 0021 +104EC 003F +104C4 0021 +104C4 003F +104EC 0334 +104C4 0334 +104EC 0061 +104EC 0041 +104C4 0061 +104C4 0041 +104EC 0062 +104C4 0062 +104ED 0021 +104ED 003F +104C5 0021 +104C5 003F +104ED 0334 +104C5 0334 +104ED 0061 +104ED 0041 +104C5 0061 +104C5 0041 +104ED 0062 +104C5 0062 +104EE 0021 +104EE 003F +104C6 0021 +104C6 003F +104EE 0334 +104C6 0334 +104EE 0061 +104EE 0041 +104C6 0061 +104C6 0041 +104EE 0062 +104C6 0062 +104EF 0021 +104EF 003F +104C7 0021 +104C7 003F +104EF 0334 +104C7 0334 +104EF 0061 +104EF 0041 +104C7 0061 +104C7 0041 +104EF 0062 +104C7 0062 +104F0 0021 +104F0 003F +104C8 0021 +104C8 003F +104F0 0334 +104C8 0334 +104F0 0061 +104F0 0041 +104C8 0061 +104C8 0041 +104F0 0062 +104C8 0062 +104F1 0021 +104F1 003F +104C9 0021 +104C9 003F +104F1 0334 +104C9 0334 +104F1 0061 +104F1 0041 +104C9 0061 +104C9 0041 +104F1 0062 +104C9 0062 +104F2 0021 +104F2 003F +104CA 0021 +104CA 003F +104F2 0334 +104CA 0334 +104F2 0061 +104F2 0041 +104CA 0061 +104CA 0041 +104F2 0062 +104CA 0062 +104F3 0021 +104F3 003F +104CB 0021 +104CB 003F +104F3 0334 +104CB 0334 +104F3 0061 +104F3 0041 +104CB 0061 +104CB 0041 +104F3 0062 +104CB 0062 +104F4 0021 +104F4 003F +104CC 0021 +104CC 003F +104F4 0334 +104CC 0334 +104F4 0061 +104F4 0041 +104CC 0061 +104CC 0041 +104F4 0062 +104CC 0062 +104F5 0021 +104F5 003F +104CD 0021 +104CD 003F +104F5 0334 +104CD 0334 +104F5 0061 +104F5 0041 +104CD 0061 +104CD 0041 +104F5 0062 +104CD 0062 +104F6 0021 +104F6 003F +104CE 0021 +104CE 003F +104F6 0334 +104CE 0334 +104F6 0061 +104F6 0041 +104CE 0061 +104CE 0041 +104F6 0062 +104CE 0062 +104F7 0021 +104F7 003F +104CF 0021 +104CF 003F +104F7 0334 +104CF 0334 +104F7 0061 +104F7 0041 +104CF 0061 +104CF 0041 +104F7 0062 +104CF 0062 +104F8 0021 +104F8 003F +104D0 0021 +104D0 003F +104F8 0334 +104D0 0334 +104F8 0061 +104F8 0041 +104D0 0061 +104D0 0041 +104F8 0062 +104D0 0062 +104F9 0021 +104F9 003F +104D1 0021 +104D1 003F +104F9 0334 +104D1 0334 +104F9 0061 +104F9 0041 +104D1 0061 +104D1 0041 +104F9 0062 +104D1 0062 +104FA 0021 +104FA 003F +104D2 0021 +104D2 003F +104FA 0334 +104D2 0334 +104FA 0061 +104FA 0041 +104D2 0061 +104D2 0041 +104FA 0062 +104D2 0062 +104FB 0021 +104FB 003F +104D3 0021 +104D3 003F +104FB 0334 +104D3 0334 +104FB 0061 +104FB 0041 +104D3 0061 +104D3 0041 +104FB 0062 +104D3 0062 1401 0021 1401 003F 1401 0061 @@ -122137,6 +127493,414 @@ A6EF 0062 1E8C4 0061 1E8C4 0041 1E8C4 0062 +1E922 0021 +1E922 003F +1E900 0021 +1E900 003F +1E922 0334 +1E900 0334 +1E922 0061 +1E922 0041 +1E900 0061 +1E900 0041 +1E922 0062 +1E900 0062 +1E923 0021 +1E923 003F +1E901 0021 +1E901 003F +1E923 0334 +1E901 0334 +1E923 0061 +1E923 0041 +1E901 0061 +1E901 0041 +1E923 0062 +1E901 0062 +1E924 0021 +1E924 003F +1E902 0021 +1E902 003F +1E924 0334 +1E902 0334 +1E924 0061 +1E924 0041 +1E902 0061 +1E902 0041 +1E924 0062 +1E902 0062 +1E925 0021 +1E925 003F +1E903 0021 +1E903 003F +1E925 0334 +1E903 0334 +1E925 0061 +1E925 0041 +1E903 0061 +1E903 0041 +1E925 0062 +1E903 0062 +1E926 0021 +1E926 003F +1E904 0021 +1E904 003F +1E926 0334 +1E904 0334 +1E926 0061 +1E926 0041 +1E904 0061 +1E904 0041 +1E926 0062 +1E904 0062 +1E927 0021 +1E927 003F +1E905 0021 +1E905 003F +1E927 0334 +1E905 0334 +1E927 0061 +1E927 0041 +1E905 0061 +1E905 0041 +1E927 0062 +1E905 0062 +1E928 0021 +1E928 003F +1E906 0021 +1E906 003F +1E928 0334 +1E906 0334 +1E928 0061 +1E928 0041 +1E906 0061 +1E906 0041 +1E928 0062 +1E906 0062 +1E929 0021 +1E929 003F +1E907 0021 +1E907 003F +1E929 0334 +1E907 0334 +1E929 0061 +1E929 0041 +1E907 0061 +1E907 0041 +1E929 0062 +1E907 0062 +1E92A 0021 +1E92A 003F +1E908 0021 +1E908 003F +1E92A 0334 +1E908 0334 +1E92A 0061 +1E92A 0041 +1E908 0061 +1E908 0041 +1E92A 0062 +1E908 0062 +1E92B 0021 +1E92B 003F +1E909 0021 +1E909 003F +1E92B 0334 +1E909 0334 +1E92B 0061 +1E92B 0041 +1E909 0061 +1E909 0041 +1E92B 0062 +1E909 0062 +1E92C 0021 +1E92C 003F +1E90A 0021 +1E90A 003F +1E92C 0334 +1E90A 0334 +1E92C 0061 +1E92C 0041 +1E90A 0061 +1E90A 0041 +1E92C 0062 +1E90A 0062 +1E92D 0021 +1E92D 003F +1E90B 0021 +1E90B 003F +1E92D 0334 +1E90B 0334 +1E92D 0061 +1E92D 0041 +1E90B 0061 +1E90B 0041 +1E92D 0062 +1E90B 0062 +1E92E 0021 +1E92E 003F +1E90C 0021 +1E90C 003F +1E92E 0334 +1E90C 0334 +1E92E 0061 +1E92E 0041 +1E90C 0061 +1E90C 0041 +1E92E 0062 +1E90C 0062 +1E92F 0021 +1E92F 003F +1E90D 0021 +1E90D 003F +1E92F 0334 +1E90D 0334 +1E92F 0061 +1E92F 0041 +1E90D 0061 +1E90D 0041 +1E92F 0062 +1E90D 0062 +1E930 0021 +1E930 003F +1E90E 0021 +1E90E 003F +1E930 0334 +1E90E 0334 +1E930 0061 +1E930 0041 +1E90E 0061 +1E90E 0041 +1E930 0062 +1E90E 0062 +1E931 0021 +1E931 003F +1E90F 0021 +1E90F 003F +1E931 0334 +1E90F 0334 +1E931 0061 +1E931 0041 +1E90F 0061 +1E90F 0041 +1E931 0062 +1E90F 0062 +1E932 0021 +1E932 003F +1E910 0021 +1E910 003F +1E932 0334 +1E910 0334 +1E932 0061 +1E932 0041 +1E910 0061 +1E910 0041 +1E932 0062 +1E910 0062 +1E933 0021 +1E933 003F +1E911 0021 +1E911 003F +1E933 0334 +1E911 0334 +1E933 0061 +1E933 0041 +1E911 0061 +1E911 0041 +1E933 0062 +1E911 0062 +1E934 0021 +1E934 003F +1E912 0021 +1E912 003F +1E934 0334 +1E912 0334 +1E934 0061 +1E934 0041 +1E912 0061 +1E912 0041 +1E934 0062 +1E912 0062 +1E935 0021 +1E935 003F +1E913 0021 +1E913 003F +1E935 0334 +1E913 0334 +1E935 0061 +1E935 0041 +1E913 0061 +1E913 0041 +1E935 0062 +1E913 0062 +1E936 0021 +1E936 003F +1E914 0021 +1E914 003F +1E936 0334 +1E914 0334 +1E936 0061 +1E936 0041 +1E914 0061 +1E914 0041 +1E936 0062 +1E914 0062 +1E937 0021 +1E937 003F +1E915 0021 +1E915 003F +1E937 0334 +1E915 0334 +1E937 0061 +1E937 0041 +1E915 0061 +1E915 0041 +1E937 0062 +1E915 0062 +1E938 0021 +1E938 003F +1E916 0021 +1E916 003F +1E938 0334 +1E916 0334 +1E938 0061 +1E938 0041 +1E916 0061 +1E916 0041 +1E938 0062 +1E916 0062 +1E939 0021 +1E939 003F +1E917 0021 +1E917 003F +1E939 0334 +1E917 0334 +1E939 0061 +1E939 0041 +1E917 0061 +1E917 0041 +1E939 0062 +1E917 0062 +1E93A 0021 +1E93A 003F +1E918 0021 +1E918 003F +1E93A 0334 +1E918 0334 +1E93A 0061 +1E93A 0041 +1E918 0061 +1E918 0041 +1E93A 0062 +1E918 0062 +1E93B 0021 +1E93B 003F +1E919 0021 +1E919 003F +1E93B 0334 +1E919 0334 +1E93B 0061 +1E93B 0041 +1E919 0061 +1E919 0041 +1E93B 0062 +1E919 0062 +1E93C 0021 +1E93C 003F +1E91A 0021 +1E91A 003F +1E93C 0334 +1E91A 0334 +1E93C 0061 +1E93C 0041 +1E91A 0061 +1E91A 0041 +1E93C 0062 +1E91A 0062 +1E93D 0021 +1E93D 003F +1E91B 0021 +1E91B 003F +1E93D 0334 +1E91B 0334 +1E93D 0061 +1E93D 0041 +1E91B 0061 +1E91B 0041 +1E93D 0062 +1E91B 0062 +1E93E 0021 +1E93E 003F +1E91C 0021 +1E91C 003F +1E93E 0334 +1E91C 0334 +1E93E 0061 +1E93E 0041 +1E91C 0061 +1E91C 0041 +1E93E 0062 +1E91C 0062 +1E93F 0021 +1E93F 003F +1E91D 0021 +1E91D 003F +1E93F 0334 +1E91D 0334 +1E93F 0061 +1E93F 0041 +1E91D 0061 +1E91D 0041 +1E93F 0062 +1E91D 0062 +1E940 0021 +1E940 003F +1E91E 0021 +1E91E 003F +1E940 0334 +1E91E 0334 +1E940 0061 +1E940 0041 +1E91E 0061 +1E91E 0041 +1E940 0062 +1E91E 0062 +1E941 0021 +1E941 003F +1E91F 0021 +1E91F 003F +1E941 0334 +1E91F 0334 +1E941 0061 +1E941 0041 +1E91F 0061 +1E91F 0041 +1E941 0062 +1E91F 0062 +1E942 0021 +1E942 003F +1E920 0021 +1E920 003F +1E942 0334 +1E920 0334 +1E942 0061 +1E942 0041 +1E920 0061 +1E920 0041 +1E942 0062 +1E920 0062 +1E943 0021 +1E943 003F +1E921 0021 +1E921 003F +1E943 0334 +1E921 0334 +1E943 0061 +1E943 0041 +1E921 0061 +1E921 0041 +1E943 0062 +1E921 0062 1100 0021 1100 003F 3200 0021 @@ -126887,12 +132651,6 @@ FF95 0062 3350 0061 3350 0041 3350 0062 -1B001 0021 -1B001 003F -1B001 0334 -1B001 0061 -1B001 0041 -1B001 0062 3087 0021 3087 003F 3088 0021 @@ -127220,6 +132978,1722 @@ FF9D 0041 3093 0062 30F3 0062 FF9D 0062 +1B002 0021 +1B002 003F +1B002 0334 +1B002 0061 +1B002 0041 +1B002 0062 +1B003 0021 +1B003 003F +1B003 0334 +1B003 0061 +1B003 0041 +1B003 0062 +1B004 0021 +1B004 003F +1B004 0334 +1B004 0061 +1B004 0041 +1B004 0062 +1B005 0021 +1B005 003F +1B005 0334 +1B005 0061 +1B005 0041 +1B005 0062 +1B006 0021 +1B006 003F +1B006 0334 +1B006 0061 +1B006 0041 +1B006 0062 +1B007 0021 +1B007 003F +1B007 0334 +1B007 0061 +1B007 0041 +1B007 0062 +1B008 0021 +1B008 003F +1B008 0334 +1B008 0061 +1B008 0041 +1B008 0062 +1B009 0021 +1B009 003F +1B009 0334 +1B009 0061 +1B009 0041 +1B009 0062 +1B00A 0021 +1B00A 003F +1B00A 0334 +1B00A 0061 +1B00A 0041 +1B00A 0062 +1B00B 0021 +1B00B 003F +1B00B 0334 +1B00B 0061 +1B00B 0041 +1B00B 0062 +1B00C 0021 +1B00C 003F +1B00C 0334 +1B00C 0061 +1B00C 0041 +1B00C 0062 +1B00D 0021 +1B00D 003F +1B00D 0334 +1B00D 0061 +1B00D 0041 +1B00D 0062 +1B00E 0021 +1B00E 003F +1B00E 0334 +1B00E 0061 +1B00E 0041 +1B00E 0062 +1B001 0021 +1B001 003F +1B001 0334 +1B001 0061 +1B001 0041 +1B001 0062 +1B00F 0021 +1B00F 003F +1B00F 0334 +1B00F 0061 +1B00F 0041 +1B00F 0062 +1B010 0021 +1B010 003F +1B010 0334 +1B010 0061 +1B010 0041 +1B010 0062 +1B011 0021 +1B011 003F +1B011 0334 +1B011 0061 +1B011 0041 +1B011 0062 +1B012 0021 +1B012 003F +1B012 0334 +1B012 0061 +1B012 0041 +1B012 0062 +1B013 0021 +1B013 003F +1B013 0334 +1B013 0061 +1B013 0041 +1B013 0062 +1B014 0021 +1B014 003F +1B014 0334 +1B014 0061 +1B014 0041 +1B014 0062 +1B015 0021 +1B015 003F +1B015 0334 +1B015 0061 +1B015 0041 +1B015 0062 +1B016 0021 +1B016 003F +1B016 0334 +1B016 0061 +1B016 0041 +1B016 0062 +1B017 0021 +1B017 003F +1B017 0334 +1B017 0061 +1B017 0041 +1B017 0062 +1B018 0021 +1B018 003F +1B018 0334 +1B018 0061 +1B018 0041 +1B018 0062 +1B019 0021 +1B019 003F +1B019 0334 +1B019 0061 +1B019 0041 +1B019 0062 +1B01A 0021 +1B01A 003F +1B01A 0334 +1B01A 0061 +1B01A 0041 +1B01A 0062 +1B01B 0021 +1B01B 003F +1B01B 0334 +1B01B 0061 +1B01B 0041 +1B01B 0062 +1B01C 0021 +1B01C 003F +1B01C 0334 +1B01C 0061 +1B01C 0041 +1B01C 0062 +1B01D 0021 +1B01D 003F +1B01D 0334 +1B01D 0061 +1B01D 0041 +1B01D 0062 +1B01E 0021 +1B01E 003F +1B01E 0334 +1B01E 0061 +1B01E 0041 +1B01E 0062 +1B01F 0021 +1B01F 003F +1B01F 0334 +1B01F 0061 +1B01F 0041 +1B01F 0062 +1B020 0021 +1B020 003F +1B020 0334 +1B020 0061 +1B020 0041 +1B020 0062 +1B021 0021 +1B021 003F +1B021 0334 +1B021 0061 +1B021 0041 +1B021 0062 +1B022 0021 +1B022 003F +1B022 0334 +1B022 0061 +1B022 0041 +1B022 0062 +1B023 0021 +1B023 003F +1B023 0334 +1B023 0061 +1B023 0041 +1B023 0062 +1B024 0021 +1B024 003F +1B024 0334 +1B024 0061 +1B024 0041 +1B024 0062 +1B025 0021 +1B025 003F +1B025 0334 +1B025 0061 +1B025 0041 +1B025 0062 +1B026 0021 +1B026 003F +1B026 0334 +1B026 0061 +1B026 0041 +1B026 0062 +1B027 0021 +1B027 003F +1B027 0334 +1B027 0061 +1B027 0041 +1B027 0062 +1B028 0021 +1B028 003F +1B028 0334 +1B028 0061 +1B028 0041 +1B028 0062 +1B029 0021 +1B029 003F +1B029 0334 +1B029 0061 +1B029 0041 +1B029 0062 +1B02A 0021 +1B02A 003F +1B02A 0334 +1B02A 0061 +1B02A 0041 +1B02A 0062 +1B02B 0021 +1B02B 003F +1B02B 0334 +1B02B 0061 +1B02B 0041 +1B02B 0062 +1B02C 0021 +1B02C 003F +1B02C 0334 +1B02C 0061 +1B02C 0041 +1B02C 0062 +1B02D 0021 +1B02D 003F +1B02D 0334 +1B02D 0061 +1B02D 0041 +1B02D 0062 +1B02E 0021 +1B02E 003F +1B02E 0334 +1B02E 0061 +1B02E 0041 +1B02E 0062 +1B02F 0021 +1B02F 003F +1B02F 0334 +1B02F 0061 +1B02F 0041 +1B02F 0062 +1B030 0021 +1B030 003F +1B030 0334 +1B030 0061 +1B030 0041 +1B030 0062 +1B031 0021 +1B031 003F +1B031 0334 +1B031 0061 +1B031 0041 +1B031 0062 +1B032 0021 +1B032 003F +1B032 0334 +1B032 0061 +1B032 0041 +1B032 0062 +1B033 0021 +1B033 003F +1B033 0334 +1B033 0061 +1B033 0041 +1B033 0062 +1B034 0021 +1B034 003F +1B034 0334 +1B034 0061 +1B034 0041 +1B034 0062 +1B035 0021 +1B035 003F +1B035 0334 +1B035 0061 +1B035 0041 +1B035 0062 +1B036 0021 +1B036 003F +1B036 0334 +1B036 0061 +1B036 0041 +1B036 0062 +1B037 0021 +1B037 003F +1B037 0334 +1B037 0061 +1B037 0041 +1B037 0062 +1B038 0021 +1B038 003F +1B038 0334 +1B038 0061 +1B038 0041 +1B038 0062 +1B039 0021 +1B039 003F +1B039 0334 +1B039 0061 +1B039 0041 +1B039 0062 +1B03A 0021 +1B03A 003F +1B03A 0334 +1B03A 0061 +1B03A 0041 +1B03A 0062 +1B03B 0021 +1B03B 003F +1B03B 0334 +1B03B 0061 +1B03B 0041 +1B03B 0062 +1B03C 0021 +1B03C 003F +1B03C 0334 +1B03C 0061 +1B03C 0041 +1B03C 0062 +1B03D 0021 +1B03D 003F +1B03D 0334 +1B03D 0061 +1B03D 0041 +1B03D 0062 +1B03E 0021 +1B03E 003F +1B03E 0334 +1B03E 0061 +1B03E 0041 +1B03E 0062 +1B03F 0021 +1B03F 003F +1B03F 0334 +1B03F 0061 +1B03F 0041 +1B03F 0062 +1B040 0021 +1B040 003F +1B040 0334 +1B040 0061 +1B040 0041 +1B040 0062 +1B041 0021 +1B041 003F +1B041 0334 +1B041 0061 +1B041 0041 +1B041 0062 +1B042 0021 +1B042 003F +1B042 0334 +1B042 0061 +1B042 0041 +1B042 0062 +1B043 0021 +1B043 003F +1B043 0334 +1B043 0061 +1B043 0041 +1B043 0062 +1B044 0021 +1B044 003F +1B044 0334 +1B044 0061 +1B044 0041 +1B044 0062 +1B045 0021 +1B045 003F +1B045 0334 +1B045 0061 +1B045 0041 +1B045 0062 +1B046 0021 +1B046 003F +1B046 0334 +1B046 0061 +1B046 0041 +1B046 0062 +1B047 0021 +1B047 003F +1B047 0334 +1B047 0061 +1B047 0041 +1B047 0062 +1B048 0021 +1B048 003F +1B048 0334 +1B048 0061 +1B048 0041 +1B048 0062 +1B049 0021 +1B049 003F +1B049 0334 +1B049 0061 +1B049 0041 +1B049 0062 +1B04A 0021 +1B04A 003F +1B04A 0334 +1B04A 0061 +1B04A 0041 +1B04A 0062 +1B04B 0021 +1B04B 003F +1B04B 0334 +1B04B 0061 +1B04B 0041 +1B04B 0062 +1B04C 0021 +1B04C 003F +1B04C 0334 +1B04C 0061 +1B04C 0041 +1B04C 0062 +1B04D 0021 +1B04D 003F +1B04D 0334 +1B04D 0061 +1B04D 0041 +1B04D 0062 +1B04E 0021 +1B04E 003F +1B04E 0334 +1B04E 0061 +1B04E 0041 +1B04E 0062 +1B04F 0021 +1B04F 003F +1B04F 0334 +1B04F 0061 +1B04F 0041 +1B04F 0062 +1B050 0021 +1B050 003F +1B050 0334 +1B050 0061 +1B050 0041 +1B050 0062 +1B051 0021 +1B051 003F +1B051 0334 +1B051 0061 +1B051 0041 +1B051 0062 +1B052 0021 +1B052 003F +1B052 0334 +1B052 0061 +1B052 0041 +1B052 0062 +1B053 0021 +1B053 003F +1B053 0334 +1B053 0061 +1B053 0041 +1B053 0062 +1B054 0021 +1B054 003F +1B054 0334 +1B054 0061 +1B054 0041 +1B054 0062 +1B055 0021 +1B055 003F +1B055 0334 +1B055 0061 +1B055 0041 +1B055 0062 +1B056 0021 +1B056 003F +1B056 0334 +1B056 0061 +1B056 0041 +1B056 0062 +1B057 0021 +1B057 003F +1B057 0334 +1B057 0061 +1B057 0041 +1B057 0062 +1B058 0021 +1B058 003F +1B058 0334 +1B058 0061 +1B058 0041 +1B058 0062 +1B059 0021 +1B059 003F +1B059 0334 +1B059 0061 +1B059 0041 +1B059 0062 +1B05A 0021 +1B05A 003F +1B05A 0334 +1B05A 0061 +1B05A 0041 +1B05A 0062 +1B05B 0021 +1B05B 003F +1B05B 0334 +1B05B 0061 +1B05B 0041 +1B05B 0062 +1B05C 0021 +1B05C 003F +1B05C 0334 +1B05C 0061 +1B05C 0041 +1B05C 0062 +1B05D 0021 +1B05D 003F +1B05D 0334 +1B05D 0061 +1B05D 0041 +1B05D 0062 +1B05E 0021 +1B05E 003F +1B05E 0334 +1B05E 0061 +1B05E 0041 +1B05E 0062 +1B05F 0021 +1B05F 003F +1B05F 0334 +1B05F 0061 +1B05F 0041 +1B05F 0062 +1B060 0021 +1B060 003F +1B060 0334 +1B060 0061 +1B060 0041 +1B060 0062 +1B061 0021 +1B061 003F +1B061 0334 +1B061 0061 +1B061 0041 +1B061 0062 +1B062 0021 +1B062 003F +1B062 0334 +1B062 0061 +1B062 0041 +1B062 0062 +1B063 0021 +1B063 003F +1B063 0334 +1B063 0061 +1B063 0041 +1B063 0062 +1B064 0021 +1B064 003F +1B064 0334 +1B064 0061 +1B064 0041 +1B064 0062 +1B065 0021 +1B065 003F +1B065 0334 +1B065 0061 +1B065 0041 +1B065 0062 +1B066 0021 +1B066 003F +1B066 0334 +1B066 0061 +1B066 0041 +1B066 0062 +1B067 0021 +1B067 003F +1B067 0334 +1B067 0061 +1B067 0041 +1B067 0062 +1B068 0021 +1B068 003F +1B068 0334 +1B068 0061 +1B068 0041 +1B068 0062 +1B069 0021 +1B069 003F +1B069 0334 +1B069 0061 +1B069 0041 +1B069 0062 +1B06A 0021 +1B06A 003F +1B06A 0334 +1B06A 0061 +1B06A 0041 +1B06A 0062 +1B06B 0021 +1B06B 003F +1B06B 0334 +1B06B 0061 +1B06B 0041 +1B06B 0062 +1B06C 0021 +1B06C 003F +1B06C 0334 +1B06C 0061 +1B06C 0041 +1B06C 0062 +1B06D 0021 +1B06D 003F +1B06D 0334 +1B06D 0061 +1B06D 0041 +1B06D 0062 +1B06E 0021 +1B06E 003F +1B06E 0334 +1B06E 0061 +1B06E 0041 +1B06E 0062 +1B06F 0021 +1B06F 003F +1B06F 0334 +1B06F 0061 +1B06F 0041 +1B06F 0062 +1B070 0021 +1B070 003F +1B070 0334 +1B070 0061 +1B070 0041 +1B070 0062 +1B071 0021 +1B071 003F +1B071 0334 +1B071 0061 +1B071 0041 +1B071 0062 +1B072 0021 +1B072 003F +1B072 0334 +1B072 0061 +1B072 0041 +1B072 0062 +1B073 0021 +1B073 003F +1B073 0334 +1B073 0061 +1B073 0041 +1B073 0062 +1B074 0021 +1B074 003F +1B074 0334 +1B074 0061 +1B074 0041 +1B074 0062 +1B075 0021 +1B075 003F +1B075 0334 +1B075 0061 +1B075 0041 +1B075 0062 +1B076 0021 +1B076 003F +1B076 0334 +1B076 0061 +1B076 0041 +1B076 0062 +1B077 0021 +1B077 003F +1B077 0334 +1B077 0061 +1B077 0041 +1B077 0062 +1B078 0021 +1B078 003F +1B078 0334 +1B078 0061 +1B078 0041 +1B078 0062 +1B079 0021 +1B079 003F +1B079 0334 +1B079 0061 +1B079 0041 +1B079 0062 +1B07A 0021 +1B07A 003F +1B07A 0334 +1B07A 0061 +1B07A 0041 +1B07A 0062 +1B07B 0021 +1B07B 003F +1B07B 0334 +1B07B 0061 +1B07B 0041 +1B07B 0062 +1B07C 0021 +1B07C 003F +1B07C 0334 +1B07C 0061 +1B07C 0041 +1B07C 0062 +1B07D 0021 +1B07D 003F +1B07D 0334 +1B07D 0061 +1B07D 0041 +1B07D 0062 +1B07E 0021 +1B07E 003F +1B07E 0334 +1B07E 0061 +1B07E 0041 +1B07E 0062 +1B07F 0021 +1B07F 003F +1B07F 0334 +1B07F 0061 +1B07F 0041 +1B07F 0062 +1B080 0021 +1B080 003F +1B080 0334 +1B080 0061 +1B080 0041 +1B080 0062 +1B081 0021 +1B081 003F +1B081 0334 +1B081 0061 +1B081 0041 +1B081 0062 +1B082 0021 +1B082 003F +1B082 0334 +1B082 0061 +1B082 0041 +1B082 0062 +1B083 0021 +1B083 003F +1B083 0334 +1B083 0061 +1B083 0041 +1B083 0062 +1B084 0021 +1B084 003F +1B084 0334 +1B084 0061 +1B084 0041 +1B084 0062 +1B085 0021 +1B085 003F +1B085 0334 +1B085 0061 +1B085 0041 +1B085 0062 +1B086 0021 +1B086 003F +1B086 0334 +1B086 0061 +1B086 0041 +1B086 0062 +1B087 0021 +1B087 003F +1B087 0334 +1B087 0061 +1B087 0041 +1B087 0062 +1B088 0021 +1B088 003F +1B088 0334 +1B088 0061 +1B088 0041 +1B088 0062 +1B089 0021 +1B089 003F +1B089 0334 +1B089 0061 +1B089 0041 +1B089 0062 +1B08A 0021 +1B08A 003F +1B08A 0334 +1B08A 0061 +1B08A 0041 +1B08A 0062 +1B08B 0021 +1B08B 003F +1B08B 0334 +1B08B 0061 +1B08B 0041 +1B08B 0062 +1B08C 0021 +1B08C 003F +1B08C 0334 +1B08C 0061 +1B08C 0041 +1B08C 0062 +1B08D 0021 +1B08D 003F +1B08D 0334 +1B08D 0061 +1B08D 0041 +1B08D 0062 +1B08E 0021 +1B08E 003F +1B08E 0334 +1B08E 0061 +1B08E 0041 +1B08E 0062 +1B08F 0021 +1B08F 003F +1B08F 0334 +1B08F 0061 +1B08F 0041 +1B08F 0062 +1B090 0021 +1B090 003F +1B090 0334 +1B090 0061 +1B090 0041 +1B090 0062 +1B091 0021 +1B091 003F +1B091 0334 +1B091 0061 +1B091 0041 +1B091 0062 +1B092 0021 +1B092 003F +1B092 0334 +1B092 0061 +1B092 0041 +1B092 0062 +1B093 0021 +1B093 003F +1B093 0334 +1B093 0061 +1B093 0041 +1B093 0062 +1B094 0021 +1B094 003F +1B094 0334 +1B094 0061 +1B094 0041 +1B094 0062 +1B095 0021 +1B095 003F +1B095 0334 +1B095 0061 +1B095 0041 +1B095 0062 +1B096 0021 +1B096 003F +1B096 0334 +1B096 0061 +1B096 0041 +1B096 0062 +1B097 0021 +1B097 003F +1B097 0334 +1B097 0061 +1B097 0041 +1B097 0062 +1B098 0021 +1B098 003F +1B098 0334 +1B098 0061 +1B098 0041 +1B098 0062 +1B099 0021 +1B099 003F +1B099 0334 +1B099 0061 +1B099 0041 +1B099 0062 +1B09A 0021 +1B09A 003F +1B09A 0334 +1B09A 0061 +1B09A 0041 +1B09A 0062 +1B09B 0021 +1B09B 003F +1B09B 0334 +1B09B 0061 +1B09B 0041 +1B09B 0062 +1B09C 0021 +1B09C 003F +1B09C 0334 +1B09C 0061 +1B09C 0041 +1B09C 0062 +1B09D 0021 +1B09D 003F +1B09D 0334 +1B09D 0061 +1B09D 0041 +1B09D 0062 +1B09E 0021 +1B09E 003F +1B09E 0334 +1B09E 0061 +1B09E 0041 +1B09E 0062 +1B09F 0021 +1B09F 003F +1B09F 0334 +1B09F 0061 +1B09F 0041 +1B09F 0062 +1B0A0 0021 +1B0A0 003F +1B0A0 0334 +1B0A0 0061 +1B0A0 0041 +1B0A0 0062 +1B0A1 0021 +1B0A1 003F +1B0A1 0334 +1B0A1 0061 +1B0A1 0041 +1B0A1 0062 +1B0A2 0021 +1B0A2 003F +1B0A2 0334 +1B0A2 0061 +1B0A2 0041 +1B0A2 0062 +1B0A3 0021 +1B0A3 003F +1B0A3 0334 +1B0A3 0061 +1B0A3 0041 +1B0A3 0062 +1B0A4 0021 +1B0A4 003F +1B0A4 0334 +1B0A4 0061 +1B0A4 0041 +1B0A4 0062 +1B0A5 0021 +1B0A5 003F +1B0A5 0334 +1B0A5 0061 +1B0A5 0041 +1B0A5 0062 +1B0A6 0021 +1B0A6 003F +1B0A6 0334 +1B0A6 0061 +1B0A6 0041 +1B0A6 0062 +1B0A7 0021 +1B0A7 003F +1B0A7 0334 +1B0A7 0061 +1B0A7 0041 +1B0A7 0062 +1B0A8 0021 +1B0A8 003F +1B0A8 0334 +1B0A8 0061 +1B0A8 0041 +1B0A8 0062 +1B0A9 0021 +1B0A9 003F +1B0A9 0334 +1B0A9 0061 +1B0A9 0041 +1B0A9 0062 +1B0AA 0021 +1B0AA 003F +1B0AA 0334 +1B0AA 0061 +1B0AA 0041 +1B0AA 0062 +1B0AB 0021 +1B0AB 003F +1B0AB 0334 +1B0AB 0061 +1B0AB 0041 +1B0AB 0062 +1B0AC 0021 +1B0AC 003F +1B0AC 0334 +1B0AC 0061 +1B0AC 0041 +1B0AC 0062 +1B0AD 0021 +1B0AD 003F +1B0AD 0334 +1B0AD 0061 +1B0AD 0041 +1B0AD 0062 +1B0AE 0021 +1B0AE 003F +1B0AE 0334 +1B0AE 0061 +1B0AE 0041 +1B0AE 0062 +1B0AF 0021 +1B0AF 003F +1B0AF 0334 +1B0AF 0061 +1B0AF 0041 +1B0AF 0062 +1B0B0 0021 +1B0B0 003F +1B0B0 0334 +1B0B0 0061 +1B0B0 0041 +1B0B0 0062 +1B0B1 0021 +1B0B1 003F +1B0B1 0334 +1B0B1 0061 +1B0B1 0041 +1B0B1 0062 +1B0B2 0021 +1B0B2 003F +1B0B2 0334 +1B0B2 0061 +1B0B2 0041 +1B0B2 0062 +1B0B3 0021 +1B0B3 003F +1B0B3 0334 +1B0B3 0061 +1B0B3 0041 +1B0B3 0062 +1B0B4 0021 +1B0B4 003F +1B0B4 0334 +1B0B4 0061 +1B0B4 0041 +1B0B4 0062 +1B0B5 0021 +1B0B5 003F +1B0B5 0334 +1B0B5 0061 +1B0B5 0041 +1B0B5 0062 +1B0B6 0021 +1B0B6 003F +1B0B6 0334 +1B0B6 0061 +1B0B6 0041 +1B0B6 0062 +1B0B7 0021 +1B0B7 003F +1B0B7 0334 +1B0B7 0061 +1B0B7 0041 +1B0B7 0062 +1B0B8 0021 +1B0B8 003F +1B0B8 0334 +1B0B8 0061 +1B0B8 0041 +1B0B8 0062 +1B0B9 0021 +1B0B9 003F +1B0B9 0334 +1B0B9 0061 +1B0B9 0041 +1B0B9 0062 +1B0BA 0021 +1B0BA 003F +1B0BA 0334 +1B0BA 0061 +1B0BA 0041 +1B0BA 0062 +1B0BB 0021 +1B0BB 003F +1B0BB 0334 +1B0BB 0061 +1B0BB 0041 +1B0BB 0062 +1B0BC 0021 +1B0BC 003F +1B0BC 0334 +1B0BC 0061 +1B0BC 0041 +1B0BC 0062 +1B0BD 0021 +1B0BD 003F +1B0BD 0334 +1B0BD 0061 +1B0BD 0041 +1B0BD 0062 +1B0BE 0021 +1B0BE 003F +1B0BE 0334 +1B0BE 0061 +1B0BE 0041 +1B0BE 0062 +1B0BF 0021 +1B0BF 003F +1B0BF 0334 +1B0BF 0061 +1B0BF 0041 +1B0BF 0062 +1B0C0 0021 +1B0C0 003F +1B0C0 0334 +1B0C0 0061 +1B0C0 0041 +1B0C0 0062 +1B0C1 0021 +1B0C1 003F +1B0C1 0334 +1B0C1 0061 +1B0C1 0041 +1B0C1 0062 +1B0C2 0021 +1B0C2 003F +1B0C2 0334 +1B0C2 0061 +1B0C2 0041 +1B0C2 0062 +1B0C3 0021 +1B0C3 003F +1B0C3 0334 +1B0C3 0061 +1B0C3 0041 +1B0C3 0062 +1B0C4 0021 +1B0C4 003F +1B0C4 0334 +1B0C4 0061 +1B0C4 0041 +1B0C4 0062 +1B0C5 0021 +1B0C5 003F +1B0C5 0334 +1B0C5 0061 +1B0C5 0041 +1B0C5 0062 +1B0C6 0021 +1B0C6 003F +1B0C6 0334 +1B0C6 0061 +1B0C6 0041 +1B0C6 0062 +1B0C7 0021 +1B0C7 003F +1B0C7 0334 +1B0C7 0061 +1B0C7 0041 +1B0C7 0062 +1B0C8 0021 +1B0C8 003F +1B0C8 0334 +1B0C8 0061 +1B0C8 0041 +1B0C8 0062 +1B0C9 0021 +1B0C9 003F +1B0C9 0334 +1B0C9 0061 +1B0C9 0041 +1B0C9 0062 +1B0CA 0021 +1B0CA 003F +1B0CA 0334 +1B0CA 0061 +1B0CA 0041 +1B0CA 0062 +1B0CB 0021 +1B0CB 003F +1B0CB 0334 +1B0CB 0061 +1B0CB 0041 +1B0CB 0062 +1B0CC 0021 +1B0CC 003F +1B0CC 0334 +1B0CC 0061 +1B0CC 0041 +1B0CC 0062 +1B0CD 0021 +1B0CD 003F +1B0CD 0334 +1B0CD 0061 +1B0CD 0041 +1B0CD 0062 +1B0CE 0021 +1B0CE 003F +1B0CE 0334 +1B0CE 0061 +1B0CE 0041 +1B0CE 0062 +1B0CF 0021 +1B0CF 003F +1B0CF 0334 +1B0CF 0061 +1B0CF 0041 +1B0CF 0062 +1B0D0 0021 +1B0D0 003F +1B0D0 0334 +1B0D0 0061 +1B0D0 0041 +1B0D0 0062 +1B0D1 0021 +1B0D1 003F +1B0D1 0334 +1B0D1 0061 +1B0D1 0041 +1B0D1 0062 +1B0D2 0021 +1B0D2 003F +1B0D2 0334 +1B0D2 0061 +1B0D2 0041 +1B0D2 0062 +1B0D3 0021 +1B0D3 003F +1B0D3 0334 +1B0D3 0061 +1B0D3 0041 +1B0D3 0062 +1B0D4 0021 +1B0D4 003F +1B0D4 0334 +1B0D4 0061 +1B0D4 0041 +1B0D4 0062 +1B0D5 0021 +1B0D5 003F +1B0D5 0334 +1B0D5 0061 +1B0D5 0041 +1B0D5 0062 +1B0D6 0021 +1B0D6 003F +1B0D6 0334 +1B0D6 0061 +1B0D6 0041 +1B0D6 0062 +1B0D7 0021 +1B0D7 003F +1B0D7 0334 +1B0D7 0061 +1B0D7 0041 +1B0D7 0062 +1B0D8 0021 +1B0D8 003F +1B0D8 0334 +1B0D8 0061 +1B0D8 0041 +1B0D8 0062 +1B0D9 0021 +1B0D9 003F +1B0D9 0334 +1B0D9 0061 +1B0D9 0041 +1B0D9 0062 +1B0DA 0021 +1B0DA 003F +1B0DA 0334 +1B0DA 0061 +1B0DA 0041 +1B0DA 0062 +1B0DB 0021 +1B0DB 003F +1B0DB 0334 +1B0DB 0061 +1B0DB 0041 +1B0DB 0062 +1B0DC 0021 +1B0DC 003F +1B0DC 0334 +1B0DC 0061 +1B0DC 0041 +1B0DC 0062 +1B0DD 0021 +1B0DD 003F +1B0DD 0334 +1B0DD 0061 +1B0DD 0041 +1B0DD 0062 +1B0DE 0021 +1B0DE 003F +1B0DE 0334 +1B0DE 0061 +1B0DE 0041 +1B0DE 0062 +1B0DF 0021 +1B0DF 003F +1B0DF 0334 +1B0DF 0061 +1B0DF 0041 +1B0DF 0062 +1B0E0 0021 +1B0E0 003F +1B0E0 0334 +1B0E0 0061 +1B0E0 0041 +1B0E0 0062 +1B0E1 0021 +1B0E1 003F +1B0E1 0334 +1B0E1 0061 +1B0E1 0041 +1B0E1 0062 +1B0E2 0021 +1B0E2 003F +1B0E2 0334 +1B0E2 0061 +1B0E2 0041 +1B0E2 0062 +1B0E3 0021 +1B0E3 003F +1B0E3 0334 +1B0E3 0061 +1B0E3 0041 +1B0E3 0062 +1B0E4 0021 +1B0E4 003F +1B0E4 0334 +1B0E4 0061 +1B0E4 0041 +1B0E4 0062 +1B0E5 0021 +1B0E5 003F +1B0E5 0334 +1B0E5 0061 +1B0E5 0041 +1B0E5 0062 +1B0E6 0021 +1B0E6 003F +1B0E6 0334 +1B0E6 0061 +1B0E6 0041 +1B0E6 0062 +1B0E7 0021 +1B0E7 003F +1B0E7 0334 +1B0E7 0061 +1B0E7 0041 +1B0E7 0062 +1B0E8 0021 +1B0E8 003F +1B0E8 0334 +1B0E8 0061 +1B0E8 0041 +1B0E8 0062 +1B0E9 0021 +1B0E9 003F +1B0E9 0334 +1B0E9 0061 +1B0E9 0041 +1B0E9 0062 +1B0EA 0021 +1B0EA 003F +1B0EA 0334 +1B0EA 0061 +1B0EA 0041 +1B0EA 0062 +1B0EB 0021 +1B0EB 003F +1B0EB 0334 +1B0EB 0061 +1B0EB 0041 +1B0EB 0062 +1B0EC 0021 +1B0EC 003F +1B0EC 0334 +1B0EC 0061 +1B0EC 0041 +1B0EC 0062 +1B0ED 0021 +1B0ED 003F +1B0ED 0334 +1B0ED 0061 +1B0ED 0041 +1B0ED 0062 +1B0EE 0021 +1B0EE 003F +1B0EE 0334 +1B0EE 0061 +1B0EE 0041 +1B0EE 0062 +1B0EF 0021 +1B0EF 003F +1B0EF 0334 +1B0EF 0061 +1B0EF 0041 +1B0EF 0062 +1B0F0 0021 +1B0F0 003F +1B0F0 0334 +1B0F0 0061 +1B0F0 0041 +1B0F0 0062 +1B0F1 0021 +1B0F1 003F +1B0F1 0334 +1B0F1 0061 +1B0F1 0041 +1B0F1 0062 +1B0F2 0021 +1B0F2 003F +1B0F2 0334 +1B0F2 0061 +1B0F2 0041 +1B0F2 0062 +1B0F3 0021 +1B0F3 003F +1B0F3 0334 +1B0F3 0061 +1B0F3 0041 +1B0F3 0062 +1B0F4 0021 +1B0F4 003F +1B0F4 0334 +1B0F4 0061 +1B0F4 0041 +1B0F4 0062 +1B0F5 0021 +1B0F5 003F +1B0F5 0334 +1B0F5 0061 +1B0F5 0041 +1B0F5 0062 +1B0F6 0021 +1B0F6 003F +1B0F6 0334 +1B0F6 0061 +1B0F6 0041 +1B0F6 0062 +1B0F7 0021 +1B0F7 003F +1B0F7 0334 +1B0F7 0061 +1B0F7 0041 +1B0F7 0062 +1B0F8 0021 +1B0F8 003F +1B0F8 0334 +1B0F8 0061 +1B0F8 0041 +1B0F8 0062 +1B0F9 0021 +1B0F9 003F +1B0F9 0334 +1B0F9 0061 +1B0F9 0041 +1B0F9 0062 +1B0FA 0021 +1B0FA 003F +1B0FA 0334 +1B0FA 0061 +1B0FA 0041 +1B0FA 0062 +1B0FB 0021 +1B0FB 003F +1B0FB 0334 +1B0FB 0061 +1B0FB 0041 +1B0FB 0062 +1B0FC 0021 +1B0FC 003F +1B0FC 0334 +1B0FC 0061 +1B0FC 0041 +1B0FC 0062 +1B0FD 0021 +1B0FD 003F +1B0FD 0334 +1B0FD 0061 +1B0FD 0041 +1B0FD 0062 +1B0FE 0021 +1B0FE 003F +1B0FE 0334 +1B0FE 0061 +1B0FE 0041 +1B0FE 0062 +1B0FF 0021 +1B0FF 003F +1B0FF 0334 +1B0FF 0061 +1B0FF 0041 +1B0FF 0062 +1B100 0021 +1B100 003F +1B100 0334 +1B100 0061 +1B100 0041 +1B100 0062 +1B101 0021 +1B101 003F +1B101 0334 +1B101 0061 +1B101 0041 +1B101 0062 +1B102 0021 +1B102 003F +1B102 0334 +1B102 0061 +1B102 0041 +1B102 0062 +1B103 0021 +1B103 003F +1B103 0334 +1B103 0061 +1B103 0041 +1B103 0062 +1B104 0021 +1B104 003F +1B104 0334 +1B104 0061 +1B104 0041 +1B104 0062 +1B105 0021 +1B105 003F +1B105 0334 +1B105 0061 +1B105 0041 +1B105 0062 +1B106 0021 +1B106 003F +1B106 0334 +1B106 0061 +1B106 0041 +1B106 0062 +1B107 0021 +1B107 003F +1B107 0334 +1B107 0061 +1B107 0041 +1B107 0062 +1B108 0021 +1B108 003F +1B108 0334 +1B108 0061 +1B108 0041 +1B108 0062 +1B109 0021 +1B109 003F +1B109 0334 +1B109 0061 +1B109 0041 +1B109 0062 +1B10A 0021 +1B10A 003F +1B10A 0334 +1B10A 0061 +1B10A 0041 +1B10A 0062 +1B10B 0021 +1B10B 003F +1B10B 0334 +1B10B 0061 +1B10B 0041 +1B10B 0062 +1B10C 0021 +1B10C 003F +1B10C 0334 +1B10C 0061 +1B10C 0041 +1B10C 0062 +1B10D 0021 +1B10D 003F +1B10D 0334 +1B10D 0061 +1B10D 0041 +1B10D 0062 +1B10E 0021 +1B10E 003F +1B10E 0334 +1B10E 0061 +1B10E 0041 +1B10E 0062 +1B10F 0021 +1B10F 003F +1B10F 0334 +1B10F 0061 +1B10F 0041 +1B10F 0062 +1B110 0021 +1B110 003F +1B110 0334 +1B110 0061 +1B110 0041 +1B110 0062 +1B111 0021 +1B111 003F +1B111 0334 +1B111 0061 +1B111 0041 +1B111 0062 +1B112 0021 +1B112 003F +1B112 0334 +1B112 0061 +1B112 0041 +1B112 0062 +1B113 0021 +1B113 003F +1B113 0334 +1B113 0061 +1B113 0041 +1B113 0062 +1B114 0021 +1B114 003F +1B114 0334 +1B114 0061 +1B114 0041 +1B114 0062 +1B115 0021 +1B115 003F +1B115 0334 +1B115 0061 +1B115 0041 +1B115 0062 +1B116 0021 +1B116 003F +1B116 0334 +1B116 0061 +1B116 0041 +1B116 0062 +1B117 0021 +1B117 003F +1B117 0334 +1B117 0061 +1B117 0041 +1B117 0062 +1B118 0021 +1B118 003F +1B118 0334 +1B118 0061 +1B118 0041 +1B118 0062 +1B119 0021 +1B119 003F +1B119 0334 +1B119 0061 +1B119 0041 +1B119 0062 +1B11A 0021 +1B11A 003F +1B11A 0334 +1B11A 0061 +1B11A 0041 +1B11A 0062 +1B11B 0021 +1B11B 003F +1B11B 0334 +1B11B 0061 +1B11B 0041 +1B11B 0062 +1B11C 0021 +1B11C 003F +1B11C 0334 +1B11C 0061 +1B11C 0041 +1B11C 0062 +1B11D 0021 +1B11D 003F +1B11D 0334 +1B11D 0061 +1B11D 0041 +1B11D 0062 +1B11E 0021 +1B11E 003F +1B11E 0334 +1B11E 0061 +1B11E 0041 +1B11E 0062 3105 0021 3105 003F 31A0 0021 @@ -127427,9 +134901,14 @@ FF9D 0062 31A6 0062 311C 0021 311C 003F +312E 0021 +312E 003F 311C 0061 311C 0041 +312E 0061 +312E 0041 311C 0062 +312E 0062 311D 0021 311D 003F 311D 0061 @@ -136501,6 +143980,24 @@ A4F7 0062 1031E 0061 1031E 0041 1031E 0062 +1032D 0021 +1032D 003F +1032D 0334 +1032D 0061 +1032D 0041 +1032D 0062 +1032E 0021 +1032E 003F +1032E 0334 +1032E 0061 +1032E 0041 +1032E 0062 +1032F 0021 +1032F 003F +1032F 0334 +1032F 0061 +1032F 0041 +1032F 0062 10330 0021 10330 003F 10330 0334 @@ -162229,6 +169726,90 @@ A4F7 0062 14646 0061 14646 0041 14646 0062 +17000 0021 +17000 003F +17000 0334 +17000 0061 +17000 0041 +17000 0062 +17001 0021 +17001 003F +17001 0334 +17001 0061 +17001 0041 +17001 0062 +17002 0021 +17002 003F +17002 0334 +17002 0061 +17002 0041 +17002 0062 +17003 0021 +17003 003F +17003 0334 +17003 0061 +17003 0041 +17003 0062 +18800 0021 +18800 003F +18800 0334 +18800 0061 +18800 0041 +18800 0062 +18801 0021 +18801 003F +18801 0334 +18801 0061 +18801 0041 +18801 0062 +18802 0021 +18802 003F +18802 0334 +18802 0061 +18802 0041 +18802 0062 +18803 0021 +18803 003F +18803 0334 +18803 0061 +18803 0041 +18803 0062 +18AF2 0021 +18AF2 003F +18AF2 0334 +18AF2 0061 +18AF2 0041 +18AF2 0062 +1B170 0021 +1B170 003F +1B170 0334 +1B170 0061 +1B170 0041 +1B170 0062 +1B171 0021 +1B171 003F +1B171 0334 +1B171 0061 +1B171 0041 +1B171 0062 +1B172 0021 +1B172 003F +1B172 0334 +1B172 0061 +1B172 0041 +1B172 0062 +1B173 0021 +1B173 003F +1B173 0334 +1B173 0061 +1B173 0041 +1B173 0062 +1B2FB 0021 +1B2FB 003F +1B2FB 0334 +1B2FB 0061 +1B2FB 0041 +1B2FB 0062 4E00 0021 4E00 003F 3220 0021 @@ -168327,6 +175908,12 @@ FA26 0062 2FA3 0061 2FA3 0041 2FA3 0062 +1F23B 0021 +1F23B 003F +1F23B 0334 +1F23B 0061 +1F23B 0041 +1F23B 0062 F919 0021 F919 003F F919 0061 @@ -169247,31 +176834,31 @@ FACE 0062 2FD5 0061 2FD5 0041 2FD5 0062 -9FD1 0021 -9FD1 003F -9FD1 0061 -9FD1 0041 -9FD1 0062 -9FD2 0021 -9FD2 003F -9FD2 0061 -9FD2 0041 -9FD2 0062 -9FD3 0021 -9FD3 003F -9FD3 0061 -9FD3 0041 -9FD3 0062 -9FD4 0021 -9FD4 003F -9FD4 0061 -9FD4 0041 -9FD4 0062 -9FD5 0021 -9FD5 003F -9FD5 0061 -9FD5 0041 -9FD5 0062 +9FE6 0021 +9FE6 003F +9FE6 0061 +9FE6 0041 +9FE6 0062 +9FE7 0021 +9FE7 003F +9FE7 0061 +9FE7 0041 +9FE7 0062 +9FE8 0021 +9FE8 003F +9FE8 0061 +9FE8 0041 +9FE8 0062 +9FE9 0021 +9FE9 003F +9FE9 0061 +9FE9 0041 +9FE9 0062 +9FEA 0021 +9FEA 003F +9FEA 0061 +9FEA 0041 +9FEA 0062 FA0E 0021 FA0E 003F FA0E 0061 @@ -203588,6 +211175,72 @@ FAD7 0062 2CEA1 0061 2CEA1 0041 2CEA1 0062 +2CEB0 0021 +2CEB0 003F +2CEB0 0334 +2CEB0 0061 +2CEB0 0041 +2CEB0 0062 +2CEB1 0021 +2CEB1 003F +2CEB1 0334 +2CEB1 0061 +2CEB1 0041 +2CEB1 0062 +2CEB2 0021 +2CEB2 003F +2CEB2 0334 +2CEB2 0061 +2CEB2 0041 +2CEB2 0062 +2CEB3 0021 +2CEB3 003F +2CEB3 0334 +2CEB3 0061 +2CEB3 0041 +2CEB3 0062 +2CEB4 0021 +2CEB4 003F +2CEB4 0334 +2CEB4 0061 +2CEB4 0041 +2CEB4 0062 +2CEB5 0021 +2CEB5 003F +2CEB5 0334 +2CEB5 0061 +2CEB5 0041 +2CEB5 0062 +2EBDC 0021 +2EBDC 003F +2EBDC 0334 +2EBDC 0061 +2EBDC 0041 +2EBDC 0062 +2EBDD 0021 +2EBDD 003F +2EBDD 0334 +2EBDD 0061 +2EBDD 0041 +2EBDD 0062 +2EBDE 0021 +2EBDE 003F +2EBDE 0334 +2EBDE 0061 +2EBDE 0041 +2EBDE 0062 +2EBDF 0021 +2EBDF 003F +2EBDF 0334 +2EBDF 0061 +2EBDF 0041 +2EBDF 0062 +2EBE0 0021 +2EBE0 003F +2EBE0 0334 +2EBE0 0061 +2EBE0 0041 +2EBE0 0062 0378 0021 0378 003F 0378 0061 @@ -203598,11 +211251,11 @@ FAD7 0062 4DB6 0061 4DB6 0041 4DB6 0062 -9FD6 0021 -9FD6 003F -9FD6 0061 -9FD6 0041 -9FD6 0062 +9FEB 0021 +9FEB 003F +9FEB 0061 +9FEB 0041 +9FEB 0062 D800 0021 D800 003F D800 0061 @@ -203623,11 +211276,6 @@ D803 003F D803 0061 D803 0041 D803 0062 -D804 0021 -D804 003F -D804 0061 -D804 0041 -D804 0062 DC00 0021 DC00 003F DC00 0061 @@ -203718,11 +211366,6 @@ FDD3 003F FDD3 0061 FDD3 0041 FDD3 0062 -FDD4 0021 -FDD4 003F -FDD4 0061 -FDD4 0041 -FDD4 0062 FFF0 0021 FFF0 003F FFF0 0061 @@ -203774,6 +211417,12 @@ FFFF 0062 2CEA2 0061 2CEA2 0041 2CEA2 0062 +2EBE1 0021 +2EBE1 003F +2EBE1 0334 +2EBE1 0061 +2EBE1 0041 +2EBE1 0062 2FFFE 0021 2FFFE 003F 2FFFE 0334 diff --git a/tests/data/DerivedBidiClass.txt b/tests/data/DerivedBidiClass.txt index 9ec885e719..ca9cc6ad9a 100644 --- a/tests/data/DerivedBidiClass.txt +++ b/tests/data/DerivedBidiClass.txt @@ -1,10 +1,11 @@ -# DerivedBidiClass-8.0.0.txt -# Date: 2015-02-13, 13:47:08 GMT [MD] +# DerivedBidiClass-10.0.0.txt +# Date: 2017-03-08, 08:41:46 GMT +# © 2017 Unicode®, Inc. +# Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries. +# For terms of use, see http://www.unicode.org/terms_of_use.html # # Unicode Character Database -# Copyright (c) 1991-2015 Unicode, Inc. -# For terms of use, see http://www.unicode.org/terms_of_use.html -# For documentation, see http://www.unicode.org/reports/tr44/ +# For documentation, see http://www.unicode.org/reports/tr44/ # ================================================ @@ -13,44 +14,21 @@ # reserved for right-to-left scripts are given either types R or AL. # # The unassigned code points that default to AL are in the ranges: -# [\u0600-\u07BF \u08A0-\u08FF \uFB50-\uFDCF \uFDF0-\uFDFF \uFE70-\uFEFF \U0001EE00-\U0001EEFF] +# [\u0600-\u07BF \u0860-\u086F \u08A0-\u08FF +# \uFB50-\uFDCF \uFDF0-\uFDFF \uFE70-\uFEFF \U0001EE00-\U0001EEFF] # -# Arabic: U+0600 - U+06FF -# Syriac: U+0700 - U+074F -# Arabic_Supplement: U+0750 - U+077F -# Thaana: U+0780 - U+07BF -# Arabic Extended-A: U+08A0 - U+08FF -# Arabic_Presentation_Forms_A: -# U+FB50 - U+FDCF -# U+FDF0 - U+FDFF -# Arabic_Presentation_Forms_B: -# U+FE70 - U+FEFF -# Arabic Mathematical Alphabetic Symbols: -# U+1EE00 - U+1EEFF +# This includes code points in the Arabic, Syriac, and Thaana blocks, among others. # # The unassigned code points that default to R are in the ranges: -# [\u0590-\u05FF \u07C0-\u089F \uFB1D-\uFB4F \U00010800-\U00010FFF \U0001E800-\U0001EDFF \U0001EF00-\U0001EFFF] +# [\u0590-\u05FF \u07C0-\u085F \u0870-\u089F \uFB1D-\uFB4F +# \U00010800-\U00010FFF \U0001E800-\U0001EDFF \U0001EF00-\U0001EFFF] # -# Hebrew: U+0590 - U+05FF -# NKo: U+07C0 - U+07FF -# Cypriot_Syllabary: U+10800 - U+1083F -# Phoenician: U+10900 - U+1091F -# Lydian: U+10920 - U+1093F -# Meroitic Hieroglyphs: -# U+10980 - U+1099F -# Meroitic Cursive: U+109A0 - U+109FF -# Kharoshthi: U+10A00 - U+10A5F -# and any others in the ranges: -# U+0800 - U+089F, -# U+FB1D - U+FB4F, -# U+10840 - U+10FFF, -# U+1E800 - U+1EDFF, -# U+1EF00 - U+1EFFF +# This includes code points in the Hebrew, NKo, and Phoenician blocks, among others. # # The unassigned code points that default to ET are in the range: # [\u20A0-\u20CF] # -# Currency Symbols: U+20A0 - U+20CF +# This consists of code points in the Currency Symbols block. # # The unassigned code points that default to BN have one of the following properties: # Default_Ignorable_Code_Point @@ -137,6 +115,8 @@ 09F0..09F1 ; L # Lo [2] BENGALI LETTER RA WITH MIDDLE DIAGONAL..BENGALI LETTER RA WITH LOWER DIAGONAL 09F4..09F9 ; L # No [6] BENGALI CURRENCY NUMERATOR ONE..BENGALI CURRENCY DENOMINATOR SIXTEEN 09FA ; L # So BENGALI ISSHAR +09FC ; L # Lo BENGALI LETTER VEDIC ANUSVARA +09FD ; L # Po BENGALI ABBREVIATION SIGN 0A03 ; L # Mc GURMUKHI SIGN VISARGA 0A05..0A0A ; L # Lo [6] GURMUKHI LETTER A..GURMUKHI LETTER UU 0A0F..0A10 ; L # Lo [2] GURMUKHI LETTER EE..GURMUKHI LETTER AI @@ -214,6 +194,7 @@ 0C60..0C61 ; L # Lo [2] TELUGU LETTER VOCALIC RR..TELUGU LETTER VOCALIC LL 0C66..0C6F ; L # Nd [10] TELUGU DIGIT ZERO..TELUGU DIGIT NINE 0C7F ; L # So TELUGU SIGN TUUMU +0C80 ; L # Lo KANNADA SIGN SPACING CANDRABINDU 0C82..0C83 ; L # Mc [2] KANNADA SIGN ANUSVARA..KANNADA SIGN VISARGA 0C85..0C8C ; L # Lo [8] KANNADA LETTER A..KANNADA LETTER VOCALIC L 0C8E..0C90 ; L # Lo [3] KANNADA LETTER E..KANNADA LETTER AI @@ -241,10 +222,13 @@ 0D46..0D48 ; L # Mc [3] MALAYALAM VOWEL SIGN E..MALAYALAM VOWEL SIGN AI 0D4A..0D4C ; L # Mc [3] MALAYALAM VOWEL SIGN O..MALAYALAM VOWEL SIGN AU 0D4E ; L # Lo MALAYALAM LETTER DOT REPH +0D4F ; L # So MALAYALAM SIGN PARA +0D54..0D56 ; L # Lo [3] MALAYALAM LETTER CHILLU M..MALAYALAM LETTER CHILLU LLL 0D57 ; L # Mc MALAYALAM AU LENGTH MARK +0D58..0D5E ; L # No [7] MALAYALAM FRACTION ONE ONE-HUNDRED-AND-SIXTIETH..MALAYALAM FRACTION ONE FIFTH 0D5F..0D61 ; L # Lo [3] MALAYALAM LETTER ARCHAIC II..MALAYALAM LETTER VOCALIC LL 0D66..0D6F ; L # Nd [10] MALAYALAM DIGIT ZERO..MALAYALAM DIGIT NINE -0D70..0D75 ; L # No [6] MALAYALAM NUMBER TEN..MALAYALAM FRACTION THREE QUARTERS +0D70..0D78 ; L # No [9] MALAYALAM NUMBER TEN..MALAYALAM FRACTION THREE SIXTEENTHS 0D79 ; L # So MALAYALAM DATE MARK 0D7A..0D7F ; L # Lo [6] MALAYALAM LETTER CHILLU NN..MALAYALAM LETTER CHILLU K 0D82..0D83 ; L # Mc [2] SINHALA SIGN ANUSVARAYA..SINHALA SIGN VISARGAYA @@ -386,7 +370,8 @@ 1820..1842 ; L # Lo [35] MONGOLIAN LETTER A..MONGOLIAN LETTER CHI 1843 ; L # Lm MONGOLIAN LETTER TODO LONG VOWEL SIGN 1844..1877 ; L # Lo [52] MONGOLIAN LETTER TODO E..MONGOLIAN LETTER MANCHU ZHA -1880..18A8 ; L # Lo [41] MONGOLIAN LETTER ALI GALI ANUSVARA ONE..MONGOLIAN LETTER MANCHU ALI GALI BHA +1880..1884 ; L # Lo [5] MONGOLIAN LETTER ALI GALI ANUSVARA ONE..MONGOLIAN LETTER ALI GALI INVERTED UBADAMA +1887..18A8 ; L # Lo [34] MONGOLIAN LETTER ALI GALI A..MONGOLIAN LETTER MANCHU ALI GALI BHA 18AA ; L # Lo MONGOLIAN LETTER MANCHU ALI GALI LHA 18B0..18F5 ; L # Lo [70] CANADIAN SYLLABICS OY..CANADIAN SYLLABICS CARRIER DENTAL S 1900..191E ; L # Lo [31] LIMBU VOWEL-CARRIER LETTER..LIMBU LETTER TRA @@ -449,6 +434,7 @@ 1C5A..1C77 ; L # Lo [30] OL CHIKI LETTER LA..OL CHIKI LETTER OH 1C78..1C7D ; L # Lm [6] OL CHIKI MU TTUDDAG..OL CHIKI AHAD 1C7E..1C7F ; L # Po [2] OL CHIKI PUNCTUATION MUCAAD..OL CHIKI PUNCTUATION DOUBLE MUCAAD +1C80..1C88 ; L # L& [9] CYRILLIC SMALL LETTER ROUNDED VE..CYRILLIC SMALL LETTER UNBLENDED UK 1CC0..1CC7 ; L # Po [8] SUNDANESE PUNCTUATION BINDU SURYA..SUNDANESE PUNCTUATION BINDU BA SATANGA 1CD3 ; L # Po VEDIC SIGN NIHSHVASA 1CE1 ; L # Mc VEDIC TONE ATHARVAVEDIC INDEPENDENT SVARITA @@ -456,6 +442,7 @@ 1CEE..1CF1 ; L # Lo [4] VEDIC SIGN HEXIFORM LONG ANUSVARA..VEDIC SIGN ANUSVARA UBHAYATO MUKHA 1CF2..1CF3 ; L # Mc [2] VEDIC SIGN ARDHAVISARGA..VEDIC SIGN ROTATED ARDHAVISARGA 1CF5..1CF6 ; L # Lo [2] VEDIC SIGN JIHVAMULIYA..VEDIC SIGN UPADHMANIYA +1CF7 ; L # Mc VEDIC SIGN ATIKRAMA 1D00..1D2B ; L # L& [44] LATIN LETTER SMALL CAPITAL A..CYRILLIC LETTER SMALL CAPITAL EL 1D2C..1D6A ; L # Lm [63] MODIFIER LETTER CAPITAL A..GREEK SUBSCRIPT SMALL LETTER CHI 1D6B..1D77 ; L # L& [13] LATIN SMALL LETTER UE..LATIN SMALL LETTER TURNED G @@ -546,7 +533,7 @@ 30A1..30FA ; L # Lo [90] KATAKANA LETTER SMALL A..KATAKANA LETTER VO 30FC..30FE ; L # Lm [3] KATAKANA-HIRAGANA PROLONGED SOUND MARK..KATAKANA VOICED ITERATION MARK 30FF ; L # Lo KATAKANA DIGRAPH KOTO -3105..312D ; L # Lo [41] BOPOMOFO LETTER B..BOPOMOFO LETTER IH +3105..312E ; L # Lo [42] BOPOMOFO LETTER B..BOPOMOFO LETTER O WITH DOT ABOVE 3131..318E ; L # Lo [94] HANGUL LETTER KIYEOK..HANGUL LETTER ARAEAE 3190..3191 ; L # So [2] IDEOGRAPHIC ANNOTATION LINKING MARK..IDEOGRAPHIC ANNOTATION REVERSE MARK 3192..3195 ; L # No [4] IDEOGRAPHIC ANNOTATION ONE MARK..IDEOGRAPHIC ANNOTATION FOUR MARK @@ -567,7 +554,7 @@ 337B..33DD ; L # So [99] SQUARE ERA NAME HEISEI..SQUARE WB 33E0..33FE ; L # So [31] IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY ONE..IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY THIRTY-ONE 3400..4DB5 ; L # Lo [6582] CJK UNIFIED IDEOGRAPH-3400..CJK UNIFIED IDEOGRAPH-4DB5 -4E00..9FD5 ; L # Lo [20950] CJK UNIFIED IDEOGRAPH-4E00..CJK UNIFIED IDEOGRAPH-9FD5 +4E00..9FEA ; L # Lo [20971] CJK UNIFIED IDEOGRAPH-4E00..CJK UNIFIED IDEOGRAPH-9FEA A000..A014 ; L # Lo [21] YI SYLLABLE IT..YI SYLLABLE E A015 ; L # Lm YI SYLLABLE WU A016..A48C ; L # Lo [1143] YI SYLLABLE BIT..YI SYLLABLE YYR @@ -592,7 +579,7 @@ A771..A787 ; L # L& [23] LATIN SMALL LETTER DUM..LATIN SMALL LETTER INSULAR A789..A78A ; L # Sk [2] MODIFIER LETTER COLON..MODIFIER LETTER SHORT EQUALS SIGN A78B..A78E ; L # L& [4] LATIN CAPITAL LETTER SALTILLO..LATIN SMALL LETTER L WITH RETROFLEX HOOK AND BELT A78F ; L # Lo LATIN LETTER SINOLOGICAL DOT -A790..A7AD ; L # L& [30] LATIN CAPITAL LETTER N WITH DESCENDER..LATIN CAPITAL LETTER L WITH BELT +A790..A7AE ; L # L& [31] LATIN CAPITAL LETTER N WITH DESCENDER..LATIN CAPITAL LETTER SMALL CAPITAL I A7B0..A7B7 ; L # L& [8] LATIN CAPITAL LETTER TURNED K..LATIN SMALL LETTER OMEGA A7F7 ; L # Lo LATIN EPIGRAPHIC LETTER SIDEWAYS I A7F8..A7F9 ; L # Lm [2] MODIFIER LETTER CAPITAL H WITH STROKE..MODIFIER LETTER SMALL LIGATURE OE @@ -715,12 +702,13 @@ FFDA..FFDC ; L # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGUL LETTER 10102 ; L # Po AEGEAN CHECK MARK 10107..10133 ; L # No [45] AEGEAN NUMBER ONE..AEGEAN NUMBER NINETY THOUSAND 10137..1013F ; L # So [9] AEGEAN WEIGHT BASE UNIT..AEGEAN MEASURE THIRD SUBUNIT +1018D..1018E ; L # So [2] GREEK INDICTION SIGN..NOMISMA SIGN 101D0..101FC ; L # So [45] PHAISTOS DISC SIGN PEDESTRIAN..PHAISTOS DISC SIGN WAVY BAND 10280..1029C ; L # Lo [29] LYCIAN LETTER A..LYCIAN LETTER X 102A0..102D0 ; L # Lo [49] CARIAN LETTER A..CARIAN LETTER UUU3 10300..1031F ; L # Lo [32] OLD ITALIC LETTER A..OLD ITALIC LETTER ESS 10320..10323 ; L # No [4] OLD ITALIC NUMERAL ONE..OLD ITALIC NUMERAL FIFTY -10330..10340 ; L # Lo [17] GOTHIC LETTER AHSA..GOTHIC LETTER PAIRTHRA +1032D..10340 ; L # Lo [20] OLD ITALIC LETTER YE..GOTHIC LETTER PAIRTHRA 10341 ; L # Nl GOTHIC LETTER NINETY 10342..10349 ; L # Lo [8] GOTHIC LETTER RAIDA..GOTHIC LETTER OTHAL 1034A ; L # Nl GOTHIC LETTER NINE HUNDRED @@ -734,6 +722,8 @@ FFDA..FFDC ; L # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGUL LETTER 10400..1044F ; L # L& [80] DESERET CAPITAL LETTER LONG I..DESERET SMALL LETTER EW 10450..1049D ; L # Lo [78] SHAVIAN LETTER PEEP..OSMANYA LETTER OO 104A0..104A9 ; L # Nd [10] OSMANYA DIGIT ZERO..OSMANYA DIGIT NINE +104B0..104D3 ; L # L& [36] OSAGE CAPITAL LETTER A..OSAGE CAPITAL LETTER ZHA +104D8..104FB ; L # L& [36] OSAGE SMALL LETTER A..OSAGE SMALL LETTER ZHA 10500..10527 ; L # Lo [40] ELBASAN LETTER A..ELBASAN LETTER KHE 10530..10563 ; L # Lo [52] CAUCASIAN ALBANIAN LETTER ALT..CAUCASIAN ALBANIAN LETTER KIW 1056F ; L # Po CAUCASIAN ALBANIAN CITATION MARK @@ -805,6 +795,15 @@ FFDA..FFDC ; L # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGUL LETTER 11357 ; L # Mc GRANTHA AU LENGTH MARK 1135D..11361 ; L # Lo [5] GRANTHA SIGN PLUTA..GRANTHA LETTER VOCALIC LL 11362..11363 ; L # Mc [2] GRANTHA VOWEL SIGN VOCALIC L..GRANTHA VOWEL SIGN VOCALIC LL +11400..11434 ; L # Lo [53] NEWA LETTER A..NEWA LETTER HA +11435..11437 ; L # Mc [3] NEWA VOWEL SIGN AA..NEWA VOWEL SIGN II +11440..11441 ; L # Mc [2] NEWA VOWEL SIGN O..NEWA VOWEL SIGN AU +11445 ; L # Mc NEWA SIGN VISARGA +11447..1144A ; L # Lo [4] NEWA SIGN AVAGRAHA..NEWA SIDDHI +1144B..1144F ; L # Po [5] NEWA DANDA..NEWA ABBREVIATION SIGN +11450..11459 ; L # Nd [10] NEWA DIGIT ZERO..NEWA DIGIT NINE +1145B ; L # Po NEWA PLACEHOLDER MARK +1145D ; L # Po NEWA INSERTION SIGN 11480..114AF ; L # Lo [48] TIRHUTA ANJI..TIRHUTA LETTER HA 114B0..114B2 ; L # Mc [3] TIRHUTA VOWEL SIGN AA..TIRHUTA VOWEL SIGN II 114B9 ; L # Mc TIRHUTA VOWEL SIGN E @@ -843,7 +842,39 @@ FFDA..FFDC ; L # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGUL LETTER 118E0..118E9 ; L # Nd [10] WARANG CITI DIGIT ZERO..WARANG CITI DIGIT NINE 118EA..118F2 ; L # No [9] WARANG CITI NUMBER TEN..WARANG CITI NUMBER NINETY 118FF ; L # Lo WARANG CITI OM +11A00 ; L # Lo ZANABAZAR SQUARE LETTER A +11A07..11A08 ; L # Mc [2] ZANABAZAR SQUARE VOWEL SIGN AI..ZANABAZAR SQUARE VOWEL SIGN AU +11A0B..11A32 ; L # Lo [40] ZANABAZAR SQUARE LETTER KA..ZANABAZAR SQUARE LETTER KSSA +11A39 ; L # Mc ZANABAZAR SQUARE SIGN VISARGA +11A3A ; L # Lo ZANABAZAR SQUARE CLUSTER-INITIAL LETTER RA +11A3F..11A46 ; L # Po [8] ZANABAZAR SQUARE INITIAL HEAD MARK..ZANABAZAR SQUARE CLOSING DOUBLE-LINED HEAD MARK +11A50 ; L # Lo SOYOMBO LETTER A +11A57..11A58 ; L # Mc [2] SOYOMBO VOWEL SIGN AI..SOYOMBO VOWEL SIGN AU +11A5C..11A83 ; L # Lo [40] SOYOMBO LETTER KA..SOYOMBO LETTER KSSA +11A86..11A89 ; L # Lo [4] SOYOMBO CLUSTER-INITIAL LETTER RA..SOYOMBO CLUSTER-INITIAL LETTER SA +11A97 ; L # Mc SOYOMBO SIGN VISARGA +11A9A..11A9C ; L # Po [3] SOYOMBO MARK TSHEG..SOYOMBO MARK DOUBLE SHAD +11A9E..11AA2 ; L # Po [5] SOYOMBO HEAD MARK WITH MOON AND SUN AND TRIPLE FLAME..SOYOMBO TERMINAL MARK-2 11AC0..11AF8 ; L # Lo [57] PAU CIN HAU LETTER PA..PAU CIN HAU GLOTTAL STOP FINAL +11C00..11C08 ; L # Lo [9] BHAIKSUKI LETTER A..BHAIKSUKI LETTER VOCALIC L +11C0A..11C2E ; L # Lo [37] BHAIKSUKI LETTER E..BHAIKSUKI LETTER HA +11C2F ; L # Mc BHAIKSUKI VOWEL SIGN AA +11C3E ; L # Mc BHAIKSUKI SIGN VISARGA +11C3F ; L # Mn BHAIKSUKI SIGN VIRAMA +11C40 ; L # Lo BHAIKSUKI SIGN AVAGRAHA +11C41..11C45 ; L # Po [5] BHAIKSUKI DANDA..BHAIKSUKI GAP FILLER-2 +11C50..11C59 ; L # Nd [10] BHAIKSUKI DIGIT ZERO..BHAIKSUKI DIGIT NINE +11C5A..11C6C ; L # No [19] BHAIKSUKI NUMBER ONE..BHAIKSUKI HUNDREDS UNIT MARK +11C70..11C71 ; L # Po [2] MARCHEN HEAD MARK..MARCHEN MARK SHAD +11C72..11C8F ; L # Lo [30] MARCHEN LETTER KA..MARCHEN LETTER A +11CA9 ; L # Mc MARCHEN SUBJOINED LETTER YA +11CB1 ; L # Mc MARCHEN VOWEL SIGN I +11CB4 ; L # Mc MARCHEN VOWEL SIGN O +11D00..11D06 ; L # Lo [7] MASARAM GONDI LETTER A..MASARAM GONDI LETTER E +11D08..11D09 ; L # Lo [2] MASARAM GONDI LETTER AI..MASARAM GONDI LETTER O +11D0B..11D30 ; L # Lo [38] MASARAM GONDI LETTER AU..MASARAM GONDI LETTER TRA +11D46 ; L # Lo MASARAM GONDI REPHA +11D50..11D59 ; L # Nd [10] MASARAM GONDI DIGIT ZERO..MASARAM GONDI DIGIT NINE 12000..12399 ; L # Lo [922] CUNEIFORM SIGN A..CUNEIFORM SIGN U U 12400..1246E ; L # Nl [111] CUNEIFORM NUMERIC SIGN TWO ASH..CUNEIFORM NUMERIC SIGN NINE U VARIANT FORM 12470..12474 ; L # Po [5] CUNEIFORM PUNCTUATION SIGN OLD ASSYRIAN WORD DIVIDER..CUNEIFORM PUNCTUATION SIGN DIAGONAL QUADCOLON @@ -870,7 +901,11 @@ FFDA..FFDC ; L # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGUL LETTER 16F50 ; L # Lo MIAO LETTER NASALIZATION 16F51..16F7E ; L # Mc [46] MIAO SIGN ASPIRATION..MIAO VOWEL SIGN NG 16F93..16F9F ; L # Lm [13] MIAO LETTER TONE-2..MIAO LETTER REFORMED TONE-8 -1B000..1B001 ; L # Lo [2] KATAKANA LETTER ARCHAIC E..HIRAGANA LETTER ARCHAIC YE +16FE0..16FE1 ; L # Lm [2] TANGUT ITERATION MARK..NUSHU ITERATION MARK +17000..187EC ; L # Lo [6125] TANGUT IDEOGRAPH-17000..TANGUT IDEOGRAPH-187EC +18800..18AF2 ; L # Lo [755] TANGUT COMPONENT-001..TANGUT COMPONENT-755 +1B000..1B11E ; L # Lo [287] KATAKANA LETTER ARCHAIC E..HENTAIGANA LETTER N-MU-MO-2 +1B170..1B2FB ; L # Lo [396] NUSHU CHARACTER-1B170..NUSHU CHARACTER-1B2FB 1BC00..1BC6A ; L # Lo [107] DUPLOYAN LETTER H..DUPLOYAN LETTER VOCALIC M 1BC70..1BC7C ; L # Lo [13] DUPLOYAN AFFIX LEFT HORIZONTAL SECANT..DUPLOYAN AFFIX ATTACHED TANGENT HOOK 1BC80..1BC88 ; L # Lo [9] DUPLOYAN AFFIX HIGH ACUTE..DUPLOYAN AFFIX HIGH VERTICAL @@ -930,21 +965,22 @@ FFDA..FFDC ; L # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGUL LETTER 1DA87..1DA8B ; L # Po [5] SIGNWRITING COMMA..SIGNWRITING PARENTHESIS 1F110..1F12E ; L # So [31] PARENTHESIZED LATIN CAPITAL LETTER A..CIRCLED WZ 1F130..1F169 ; L # So [58] SQUARED LATIN CAPITAL LETTER A..NEGATIVE CIRCLED LATIN CAPITAL LETTER Z -1F170..1F19A ; L # So [43] NEGATIVE SQUARED LATIN CAPITAL LETTER A..SQUARED VS +1F170..1F1AC ; L # So [61] NEGATIVE SQUARED LATIN CAPITAL LETTER A..SQUARED VOD 1F1E6..1F202 ; L # So [29] REGIONAL INDICATOR SYMBOL LETTER A..SQUARED KATAKANA SA -1F210..1F23A ; L # So [43] SQUARED CJK UNIFIED IDEOGRAPH-624B..SQUARED CJK UNIFIED IDEOGRAPH-55B6 +1F210..1F23B ; L # So [44] SQUARED CJK UNIFIED IDEOGRAPH-624B..SQUARED CJK UNIFIED IDEOGRAPH-914D 1F240..1F248 ; L # So [9] TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-672C..TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-6557 1F250..1F251 ; L # So [2] CIRCLED IDEOGRAPH ADVANTAGE..CIRCLED IDEOGRAPH ACCEPT 20000..2A6D6 ; L # Lo [42711] CJK UNIFIED IDEOGRAPH-20000..CJK UNIFIED IDEOGRAPH-2A6D6 2A700..2B734 ; L # Lo [4149] CJK UNIFIED IDEOGRAPH-2A700..CJK UNIFIED IDEOGRAPH-2B734 2B740..2B81D ; L # Lo [222] CJK UNIFIED IDEOGRAPH-2B740..CJK UNIFIED IDEOGRAPH-2B81D 2B820..2CEA1 ; L # Lo [5762] CJK UNIFIED IDEOGRAPH-2B820..CJK UNIFIED IDEOGRAPH-2CEA1 +2CEB0..2EBE0 ; L # Lo [7473] CJK UNIFIED IDEOGRAPH-2CEB0..CJK UNIFIED IDEOGRAPH-2EBE0 2F800..2FA1D ; L # Lo [542] CJK COMPATIBILITY IDEOGRAPH-2F800..CJK COMPATIBILITY IDEOGRAPH-2FA1D F0000..FFFFD ; L # Co [65534] <private-use-F0000>..<private-use-FFFFD> 100000..10FFFD; L # Co [65534] <private-use-100000>..<private-use-10FFFD> -# The above property value applies to 848999 code points not listed here. -# Total code points: 1097474 +# The above property value applies to 833103 code points not listed here. +# Total code points: 1097124 # ================================================ @@ -976,7 +1012,8 @@ F0000..FFFFD ; L # Co [65534] <private-use-F0000>..<private-use-FFFFD> 0840..0858 ; R # Lo [25] MANDAIC LETTER HALQA..MANDAIC LETTER AIN 085C..085D ; R # Cn [2] <reserved-085C>..<reserved-085D> 085E ; R # Po MANDAIC PUNCTUATION -085F..089F ; R # Cn [65] <reserved-085F>..<reserved-089F> +085F ; R # Cn <reserved-085F> +0870..089F ; R # Cn [48] <reserved-0870>..<reserved-089F> 200F ; R # Cf RIGHT-TO-LEFT MARK FB1D ; R # Lo HEBREW LETTER YOD WITH HIRIQ FB1F..FB28 ; R # Lo [10] HEBREW LIGATURE YIDDISH YOD YOD PATAH..HEBREW LETTER WIDE TAV @@ -1084,10 +1121,16 @@ FB46..FB4F ; R # Lo [10] HEBREW LETTER TSADI WITH DAGESH..HEBREW LIGATURE AL 1E800..1E8C4 ; R # Lo [197] MENDE KIKAKUI SYLLABLE M001 KI..MENDE KIKAKUI SYLLABLE M060 NYON 1E8C5..1E8C6 ; R # Cn [2] <reserved-1E8C5>..<reserved-1E8C6> 1E8C7..1E8CF ; R # No [9] MENDE KIKAKUI DIGIT ONE..MENDE KIKAKUI DIGIT NINE -1E8D7..1EDFF ; R # Cn [1321] <reserved-1E8D7>..<reserved-1EDFF> +1E8D7..1E8FF ; R # Cn [41] <reserved-1E8D7>..<reserved-1E8FF> +1E900..1E943 ; R # L& [68] ADLAM CAPITAL LETTER ALIF..ADLAM SMALL LETTER SHA +1E94B..1E94F ; R # Cn [5] <reserved-1E94B>..<reserved-1E94F> +1E950..1E959 ; R # Nd [10] ADLAM DIGIT ZERO..ADLAM DIGIT NINE +1E95A..1E95D ; R # Cn [4] <reserved-1E95A>..<reserved-1E95D> +1E95E..1E95F ; R # Po [2] ADLAM INITIAL EXCLAMATION MARK..ADLAM INITIAL QUESTION MARK +1E960..1EDFF ; R # Cn [1184] <reserved-1E960>..<reserved-1EDFF> 1EF00..1EFFF ; R # Cn [256] <reserved-1EF00>..<reserved-1EFFF> -# Total code points: 4077 +# Total code points: 4054 # ================================================ @@ -1145,8 +1188,8 @@ FF0D ; ES # Pd FULLWIDTH HYPHEN-MINUS 0E3F ; ET # Sc THAI CURRENCY SYMBOL BAHT 17DB ; ET # Sc KHMER CURRENCY SYMBOL RIEL 2030..2034 ; ET # Po [5] PER MILLE SIGN..TRIPLE PRIME -20A0..20BE ; ET # Sc [31] EURO-CURRENCY SIGN..LARI SIGN -20BF..20CF ; ET # Cn [17] <reserved-20BF>..<reserved-20CF> +20A0..20BF ; ET # Sc [32] EURO-CURRENCY SIGN..BITCOIN SIGN +20C0..20CF ; ET # Cn [16] <reserved-20C0>..<reserved-20CF> 212E ; ET # So ESTIMATED SYMBOL 2213 ; ET # Sm MINUS-OR-PLUS SIGN A838 ; ET # Sc NORTH INDIC RUPEE MARK @@ -1170,9 +1213,10 @@ FFE5..FFE6 ; ET # Sc [2] FULLWIDTH YEN SIGN..FULLWIDTH WON SIGN 0660..0669 ; AN # Nd [10] ARABIC-INDIC DIGIT ZERO..ARABIC-INDIC DIGIT NINE 066B..066C ; AN # Po [2] ARABIC DECIMAL SEPARATOR..ARABIC THOUSANDS SEPARATOR 06DD ; AN # Cf ARABIC END OF AYAH +08E2 ; AN # Cf ARABIC DISPUTED END OF AYAH 10E60..10E7E ; AN # No [31] RUMI DIGIT ONE..RUMI FRACTION TWO THIRDS -# Total code points: 50 +# Total code points: 51 # ================================================ @@ -1400,8 +1444,7 @@ FF1A ; CS # Po FULLWIDTH COLON 239B..23B3 ; ON # Sm [25] LEFT PARENTHESIS UPPER HOOK..SUMMATION BOTTOM 23B4..23DB ; ON # So [40] TOP SQUARE BRACKET..FUSE 23DC..23E1 ; ON # Sm [6] TOP PARENTHESIS..BOTTOM TORTOISE SHELL BRACKET -23E2..23FA ; ON # So [25] WHITE TRAPEZIUM..BLACK CIRCLE FOR RECORD -2400..2426 ; ON # So [39] SYMBOL FOR NULL..SYMBOL FOR SUBSTITUTE FORM TWO +23E2..2426 ; ON # So [69] WHITE TRAPEZIUM..SYMBOL FOR SUBSTITUTE FORM TWO 2440..244A ; ON # So [11] OCR HOOK..OCR DOUBLE BACKSLASH 2460..2487 ; ON # No [40] CIRCLED DIGIT ONE..PARENTHESIZED NUMBER TWENTY 24EA..24FF ; ON # No [22] CIRCLED DIGIT ZERO..NEGATIVE CIRCLED DIGIT ZERO @@ -1486,7 +1529,7 @@ FF1A ; CS # Po FULLWIDTH COLON 2B76..2B95 ; ON # So [32] NORTH WEST TRIANGLE-HEADED ARROW TO BAR..RIGHTWARDS BLACK ARROW 2B98..2BB9 ; ON # So [34] THREE-D TOP-LIGHTED LEFTWARDS EQUILATERAL ARROWHEAD..UP ARROWHEAD IN A RECTANGLE BOX 2BBD..2BC8 ; ON # So [12] BALLOT BOX WITH LIGHT X..BLACK MEDIUM RIGHT-POINTING TRIANGLE CENTRED -2BCA..2BD1 ; ON # So [8] TOP HALF BLACK CIRCLE..UNCERTAINTY SIGN +2BCA..2BD2 ; ON # So [9] TOP HALF BLACK CIRCLE..GROUP MARK 2BEC..2BEF ; ON # So [4] LEFTWARDS TWO-HEADED ARROW WITH TRIANGLE ARROWHEADS..DOWNWARDS TWO-HEADED ARROW WITH TRIANGLE ARROWHEADS 2CE5..2CEA ; ON # So [6] COPTIC SYMBOL MI RO..COPTIC SYMBOL SHIMA SIMA 2CF9..2CFC ; ON # Po [4] COPTIC OLD NUBIAN FULL STOP..COPTIC OLD NUBIAN VERSE DIVIDER @@ -1529,6 +1572,7 @@ FF1A ; CS # Po FULLWIDTH COLON 2E40 ; ON # Pd DOUBLE HYPHEN 2E41 ; ON # Po REVERSED COMMA 2E42 ; ON # Ps DOUBLE LOW-REVERSED-9 QUOTATION MARK +2E43..2E49 ; ON # Po [7] DASH WITH LEFT UPTURN..DOUBLE STACKED COMMA 2E80..2E99 ; ON # So [26] CJK RADICAL REPEAT..CJK RADICAL RAP 2E9B..2EF3 ; ON # So [89] CJK RADICAL CHOKE..CJK RADICAL C-SIMPLIFIED TURTLE 2F00..2FD5 ; ON # So [214] KANGXI RADICAL ONE..KANGXI RADICAL FLUTE @@ -1675,6 +1719,7 @@ FFFC..FFFD ; ON # So [2] OBJECT REPLACEMENT CHARACTER..REPLACEMENT CHARACTE 1091F ; ON # Po PHOENICIAN WORD SEPARATOR 10B39..10B3F ; ON # Po [7] AVESTAN ABBREVIATION MARK..LARGE ONE RING OVER TWO RINGS PUNCTUATION 11052..11065 ; ON # No [20] BRAHMI NUMBER ONE..BRAHMI NUMBER ONE THOUSAND +11660..1166C ; ON # Po [13] MONGOLIAN BIRGA WITH ORNAMENT..MONGOLIAN TURNED SWIRL BIRGA WITH DOUBLE ORNAMENT 1D200..1D241 ; ON # So [66] GREEK VOCAL NOTATION SYMBOL-1..GREEK INSTRUMENTAL NOTATION SYMBOL-54 1D245 ; ON # So GREEK MUSICAL LEIMMA 1D300..1D356 ; ON # So [87] MONOGRAM FOR EARTH..TETRAGRAM FOR FOSTERING @@ -1692,13 +1737,12 @@ FFFC..FFFD ; ON # So [2] OBJECT REPLACEMENT CHARACTER..REPLACEMENT CHARACTE 1F0D1..1F0F5 ; ON # So [37] PLAYING CARD ACE OF CLUBS..PLAYING CARD TRUMP-21 1F10B..1F10C ; ON # No [2] DINGBAT CIRCLED SANS-SERIF DIGIT ZERO..DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT ZERO 1F16A..1F16B ; ON # So [2] RAISED MC SIGN..RAISED MD SIGN +1F260..1F265 ; ON # So [6] ROUNDED SYMBOL FOR FU..ROUNDED SYMBOL FOR CAI 1F300..1F3FA ; ON # So [251] CYCLONE..AMPHORA 1F3FB..1F3FF ; ON # Sk [5] EMOJI MODIFIER FITZPATRICK TYPE-1-2..EMOJI MODIFIER FITZPATRICK TYPE-6 -1F400..1F579 ; ON # So [378] RAT..JOYSTICK -1F57B..1F5A3 ; ON # So [41] LEFT HAND TELEPHONE RECEIVER..BLACK DOWN POINTING BACKHAND INDEX -1F5A5..1F6D0 ; ON # So [300] DESKTOP COMPUTER..PLACE OF WORSHIP +1F400..1F6D4 ; ON # So [725] RAT..PAGODA 1F6E0..1F6EC ; ON # So [13] HAMMER AND WRENCH..AIRPLANE ARRIVING -1F6F0..1F6F3 ; ON # So [4] SATELLITE..PASSENGER SHIP +1F6F0..1F6F8 ; ON # So [9] SATELLITE..FLYING SAUCER 1F700..1F773 ; ON # So [116] ALCHEMICAL SYMBOL FOR QUINTESSENCE..ALCHEMICAL SYMBOL FOR HALF OUNCE 1F780..1F7D4 ; ON # So [85] BLACK LEFT-POINTING ISOSCELES RIGHT TRIANGLE..HEAVY TWELVE POINTED PINWHEEL STAR 1F800..1F80B ; ON # So [12] LEFTWARDS ARROW WITH SMALL TRIANGLE ARROWHEAD..DOWNWARDS ARROW WITH LARGE TRIANGLE ARROWHEAD @@ -1706,11 +1750,15 @@ FFFC..FFFD ; ON # So [2] OBJECT REPLACEMENT CHARACTER..REPLACEMENT CHARACTE 1F850..1F859 ; ON # So [10] LEFTWARDS SANS-SERIF ARROW..UP DOWN SANS-SERIF ARROW 1F860..1F887 ; ON # So [40] WIDE-HEADED LEFTWARDS LIGHT BARB ARROW..WIDE-HEADED SOUTH WEST VERY HEAVY BARB ARROW 1F890..1F8AD ; ON # So [30] LEFTWARDS TRIANGLE ARROWHEAD..WHITE ARROW SHAFT WIDTH TWO THIRDS -1F910..1F918 ; ON # So [9] ZIPPER-MOUTH FACE..SIGN OF THE HORNS -1F980..1F984 ; ON # So [5] CRAB..UNICORN FACE +1F900..1F90B ; ON # So [12] CIRCLED CROSS FORMEE WITH FOUR DOTS..DOWNWARD FACING NOTCHED HOOK WITH DOT +1F910..1F93E ; ON # So [47] ZIPPER-MOUTH FACE..HANDBALL +1F940..1F94C ; ON # So [13] WILTED FLOWER..CURLING STONE +1F950..1F96B ; ON # So [28] CROISSANT..CANNED FOOD +1F980..1F997 ; ON # So [24] CRAB..CRICKET 1F9C0 ; ON # So CHEESE WEDGE +1F9D0..1F9E6 ; ON # So [23] FACE WITH MONOCLE..SOCKS -# Total code points: 5174 +# Total code points: 5350 # ================================================ @@ -1784,6 +1832,7 @@ FFFFE..FFFFF ; BN # Cn [2] <noncharacter-FFFFE>..<noncharacter-FFFFF> 0825..0827 ; NSM # Mn [3] SAMARITAN VOWEL SIGN SHORT A..SAMARITAN VOWEL SIGN U 0829..082D ; NSM # Mn [5] SAMARITAN VOWEL SIGN LONG I..SAMARITAN MARK NEQUDAA 0859..085B ; NSM # Mn [3] MANDAIC AFFRICATION MARK..MANDAIC GEMINATION MARK +08D4..08E1 ; NSM # Mn [14] ARABIC SMALL HIGH WORD AR-RUB..ARABIC SMALL HIGH SIGN SAFHA 08E3..0902 ; NSM # Mn [32] ARABIC TURNED DAMMA BELOW..DEVANAGARI SIGN ANUSVARA 093A ; NSM # Mn DEVANAGARI VOWEL SIGN OE 093C ; NSM # Mn DEVANAGARI SIGN NUKTA @@ -1810,6 +1859,7 @@ FFFFE..FFFFF ; BN # Cn [2] <noncharacter-FFFFE>..<noncharacter-FFFFF> 0AC7..0AC8 ; NSM # Mn [2] GUJARATI VOWEL SIGN E..GUJARATI VOWEL SIGN AI 0ACD ; NSM # Mn GUJARATI SIGN VIRAMA 0AE2..0AE3 ; NSM # Mn [2] GUJARATI VOWEL SIGN VOCALIC L..GUJARATI VOWEL SIGN VOCALIC LL +0AFA..0AFF ; NSM # Mn [6] GUJARATI SIGN SUKUN..GUJARATI SIGN TWO-CIRCLE NUKTA ABOVE 0B01 ; NSM # Mn ORIYA SIGN CANDRABINDU 0B3C ; NSM # Mn ORIYA SIGN NUKTA 0B3F ; NSM # Mn ORIYA VOWEL SIGN I @@ -1830,7 +1880,8 @@ FFFFE..FFFFF ; BN # Cn [2] <noncharacter-FFFFE>..<noncharacter-FFFFF> 0CBC ; NSM # Mn KANNADA SIGN NUKTA 0CCC..0CCD ; NSM # Mn [2] KANNADA VOWEL SIGN AU..KANNADA SIGN VIRAMA 0CE2..0CE3 ; NSM # Mn [2] KANNADA VOWEL SIGN VOCALIC L..KANNADA VOWEL SIGN VOCALIC LL -0D01 ; NSM # Mn MALAYALAM SIGN CANDRABINDU +0D00..0D01 ; NSM # Mn [2] MALAYALAM SIGN COMBINING ANUSVARA ABOVE..MALAYALAM SIGN CANDRABINDU +0D3B..0D3C ; NSM # Mn [2] MALAYALAM SIGN VERTICAL BAR VIRAMA..MALAYALAM SIGN CIRCULAR VIRAMA 0D41..0D44 ; NSM # Mn [4] MALAYALAM VOWEL SIGN U..MALAYALAM VOWEL SIGN VOCALIC RR 0D4D ; NSM # Mn MALAYALAM SIGN VIRAMA 0D62..0D63 ; NSM # Mn [2] MALAYALAM VOWEL SIGN VOCALIC L..MALAYALAM VOWEL SIGN VOCALIC LL @@ -1876,6 +1927,7 @@ FFFFE..FFFFF ; BN # Cn [2] <noncharacter-FFFFE>..<noncharacter-FFFFF> 17C9..17D3 ; NSM # Mn [11] KHMER SIGN MUUSIKATOAN..KHMER SIGN BATHAMASAT 17DD ; NSM # Mn KHMER SIGN ATTHACAN 180B..180D ; NSM # Mn [3] MONGOLIAN FREE VARIATION SELECTOR ONE..MONGOLIAN FREE VARIATION SELECTOR THREE +1885..1886 ; NSM # Mn [2] MONGOLIAN LETTER ALI GALI BALUDA..MONGOLIAN LETTER ALI GALI THREE BALUDA 18A9 ; NSM # Mn MONGOLIAN LETTER ALI GALI DAGALGA 1920..1922 ; NSM # Mn [3] LIMBU VOWEL SIGN A..LIMBU VOWEL SIGN U 1927..1928 ; NSM # Mn [2] LIMBU VOWEL SIGN E..LIMBU VOWEL SIGN O @@ -1914,8 +1966,8 @@ FFFFE..FFFFF ; BN # Cn [2] <noncharacter-FFFFE>..<noncharacter-FFFFF> 1CED ; NSM # Mn VEDIC SIGN TIRYAK 1CF4 ; NSM # Mn VEDIC TONE CANDRA ABOVE 1CF8..1CF9 ; NSM # Mn [2] VEDIC TONE RING ABOVE..VEDIC TONE DOUBLE RING ABOVE -1DC0..1DF5 ; NSM # Mn [54] COMBINING DOTTED GRAVE ACCENT..COMBINING UP TACK ABOVE -1DFC..1DFF ; NSM # Mn [4] COMBINING DOUBLE INVERTED BREVE BELOW..COMBINING RIGHT ARROWHEAD AND DOWN ARROWHEAD BELOW +1DC0..1DF9 ; NSM # Mn [58] COMBINING DOTTED GRAVE ACCENT..COMBINING WIDE INVERTED BRIDGE BELOW +1DFB..1DFF ; NSM # Mn [5] COMBINING DELETION MARK..COMBINING RIGHT ARROWHEAD AND DOWN ARROWHEAD BELOW 20D0..20DC ; NSM # Mn [13] COMBINING LEFT HARPOON ABOVE..COMBINING FOUR DOTS ABOVE 20DD..20E0 ; NSM # Me [4] COMBINING ENCLOSING CIRCLE..COMBINING ENCLOSING CIRCLE BACKSLASH 20E1 ; NSM # Mn COMBINING LEFT RIGHT ARROW ABOVE @@ -1935,7 +1987,7 @@ A802 ; NSM # Mn SYLOTI NAGRI SIGN DVISVARA A806 ; NSM # Mn SYLOTI NAGRI SIGN HASANTA A80B ; NSM # Mn SYLOTI NAGRI SIGN ANUSVARA A825..A826 ; NSM # Mn [2] SYLOTI NAGRI VOWEL SIGN U..SYLOTI NAGRI VOWEL SIGN E -A8C4 ; NSM # Mn SAURASHTRA SIGN VIRAMA +A8C4..A8C5 ; NSM # Mn [2] SAURASHTRA SIGN VIRAMA..SAURASHTRA SIGN CANDRABINDU A8E0..A8F1 ; NSM # Mn [18] COMBINING DEVANAGARI DIGIT ZERO..COMBINING DEVANAGARI SIGN AVAGRAHA A926..A92D ; NSM # Mn [8] KAYAH LI VOWEL UE..KAYAH LI TONE CALYA PLOPHU A947..A951 ; NSM # Mn [11] REJANG VOWEL SIGN I..REJANG CONSONANT SIGN R @@ -1987,6 +2039,7 @@ FE20..FE2F ; NSM # Mn [16] COMBINING LIGATURE LEFT HALF..COMBINING CYRILLIC 1122F..11231 ; NSM # Mn [3] KHOJKI VOWEL SIGN U..KHOJKI VOWEL SIGN AI 11234 ; NSM # Mn KHOJKI SIGN ANUSVARA 11236..11237 ; NSM # Mn [2] KHOJKI SIGN NUKTA..KHOJKI SIGN SHADDA +1123E ; NSM # Mn KHOJKI SIGN SUKUN 112DF ; NSM # Mn KHUDAWADI SIGN ANUSVARA 112E3..112EA ; NSM # Mn [8] KHUDAWADI VOWEL SIGN U..KHUDAWADI SIGN VIRAMA 11300..11301 ; NSM # Mn [2] GRANTHA SIGN COMBINING ANUSVARA ABOVE..GRANTHA SIGN CANDRABINDU @@ -1994,6 +2047,9 @@ FE20..FE2F ; NSM # Mn [16] COMBINING LIGATURE LEFT HALF..COMBINING CYRILLIC 11340 ; NSM # Mn GRANTHA VOWEL SIGN II 11366..1136C ; NSM # Mn [7] COMBINING GRANTHA DIGIT ZERO..COMBINING GRANTHA DIGIT SIX 11370..11374 ; NSM # Mn [5] COMBINING GRANTHA LETTER A..COMBINING GRANTHA LETTER PA +11438..1143F ; NSM # Mn [8] NEWA VOWEL SIGN U..NEWA VOWEL SIGN AI +11442..11444 ; NSM # Mn [3] NEWA SIGN VIRAMA..NEWA SIGN ANUSVARA +11446 ; NSM # Mn NEWA SIGN NUKTA 114B3..114B8 ; NSM # Mn [6] TIRHUTA VOWEL SIGN U..TIRHUTA VOWEL SIGN VOCALIC LL 114BA ; NSM # Mn TIRHUTA VOWEL SIGN SHORT E 114BF..114C0 ; NSM # Mn [2] TIRHUTA SIGN CANDRABINDU..TIRHUTA SIGN ANUSVARA @@ -2012,6 +2068,26 @@ FE20..FE2F ; NSM # Mn [16] COMBINING LIGATURE LEFT HALF..COMBINING CYRILLIC 1171D..1171F ; NSM # Mn [3] AHOM CONSONANT SIGN MEDIAL LA..AHOM CONSONANT SIGN MEDIAL LIGATING RA 11722..11725 ; NSM # Mn [4] AHOM VOWEL SIGN I..AHOM VOWEL SIGN UU 11727..1172B ; NSM # Mn [5] AHOM VOWEL SIGN AW..AHOM SIGN KILLER +11A01..11A06 ; NSM # Mn [6] ZANABAZAR SQUARE VOWEL SIGN I..ZANABAZAR SQUARE VOWEL SIGN O +11A09..11A0A ; NSM # Mn [2] ZANABAZAR SQUARE VOWEL SIGN REVERSED I..ZANABAZAR SQUARE VOWEL LENGTH MARK +11A33..11A38 ; NSM # Mn [6] ZANABAZAR SQUARE FINAL CONSONANT MARK..ZANABAZAR SQUARE SIGN ANUSVARA +11A3B..11A3E ; NSM # Mn [4] ZANABAZAR SQUARE CLUSTER-FINAL LETTER YA..ZANABAZAR SQUARE CLUSTER-FINAL LETTER VA +11A47 ; NSM # Mn ZANABAZAR SQUARE SUBJOINER +11A51..11A56 ; NSM # Mn [6] SOYOMBO VOWEL SIGN I..SOYOMBO VOWEL SIGN OE +11A59..11A5B ; NSM # Mn [3] SOYOMBO VOWEL SIGN VOCALIC R..SOYOMBO VOWEL LENGTH MARK +11A8A..11A96 ; NSM # Mn [13] SOYOMBO FINAL CONSONANT SIGN G..SOYOMBO SIGN ANUSVARA +11A98..11A99 ; NSM # Mn [2] SOYOMBO GEMINATION MARK..SOYOMBO SUBJOINER +11C30..11C36 ; NSM # Mn [7] BHAIKSUKI VOWEL SIGN I..BHAIKSUKI VOWEL SIGN VOCALIC L +11C38..11C3D ; NSM # Mn [6] BHAIKSUKI VOWEL SIGN E..BHAIKSUKI SIGN ANUSVARA +11C92..11CA7 ; NSM # Mn [22] MARCHEN SUBJOINED LETTER KA..MARCHEN SUBJOINED LETTER ZA +11CAA..11CB0 ; NSM # Mn [7] MARCHEN SUBJOINED LETTER RA..MARCHEN VOWEL SIGN AA +11CB2..11CB3 ; NSM # Mn [2] MARCHEN VOWEL SIGN U..MARCHEN VOWEL SIGN E +11CB5..11CB6 ; NSM # Mn [2] MARCHEN SIGN ANUSVARA..MARCHEN SIGN CANDRABINDU +11D31..11D36 ; NSM # Mn [6] MASARAM GONDI VOWEL SIGN AA..MASARAM GONDI VOWEL SIGN VOCALIC R +11D3A ; NSM # Mn MASARAM GONDI VOWEL SIGN E +11D3C..11D3D ; NSM # Mn [2] MASARAM GONDI VOWEL SIGN AI..MASARAM GONDI VOWEL SIGN O +11D3F..11D45 ; NSM # Mn [7] MASARAM GONDI VOWEL SIGN AU..MASARAM GONDI VIRAMA +11D47 ; NSM # Mn MASARAM GONDI RA-KARA 16AF0..16AF4 ; NSM # Mn [5] BASSA VAH COMBINING HIGH TONE..BASSA VAH COMBINING HIGH-LOW TONE 16B30..16B36 ; NSM # Mn [7] PAHAWH HMONG MARK CIM TUB..PAHAWH HMONG MARK CIM TAUM 16F8F..16F92 ; NSM # Mn [4] MIAO TONE RIGHT..MIAO TONE BELOW @@ -2027,10 +2103,16 @@ FE20..FE2F ; NSM # Mn [16] COMBINING LIGATURE LEFT HALF..COMBINING CYRILLIC 1DA84 ; NSM # Mn SIGNWRITING LOCATION HEAD NECK 1DA9B..1DA9F ; NSM # Mn [5] SIGNWRITING FILL MODIFIER-2..SIGNWRITING FILL MODIFIER-6 1DAA1..1DAAF ; NSM # Mn [15] SIGNWRITING ROTATION MODIFIER-2..SIGNWRITING ROTATION MODIFIER-16 +1E000..1E006 ; NSM # Mn [7] COMBINING GLAGOLITIC LETTER AZU..COMBINING GLAGOLITIC LETTER ZHIVETE +1E008..1E018 ; NSM # Mn [17] COMBINING GLAGOLITIC LETTER ZEMLJA..COMBINING GLAGOLITIC LETTER HERU +1E01B..1E021 ; NSM # Mn [7] COMBINING GLAGOLITIC LETTER SHTA..COMBINING GLAGOLITIC LETTER YATI +1E023..1E024 ; NSM # Mn [2] COMBINING GLAGOLITIC LETTER YU..COMBINING GLAGOLITIC LETTER SMALL YUS +1E026..1E02A ; NSM # Mn [5] COMBINING GLAGOLITIC LETTER YO..COMBINING GLAGOLITIC LETTER FITA 1E8D0..1E8D6 ; NSM # Mn [7] MENDE KIKAKUI COMBINING NUMBER TEENS..MENDE KIKAKUI COMBINING NUMBER MILLIONS +1E944..1E94A ; NSM # Mn [7] ADLAM ALIF LENGTHENER..ADLAM NUKTA E0100..E01EF ; NSM # Mn [240] VARIATION SELECTOR-17..VARIATION SELECTOR-256 -# Total code points: 1578 +# Total code points: 1773 # ================================================ @@ -2065,8 +2147,12 @@ E0100..E01EF ; NSM # Mn [240] VARIATION SELECTOR-17..VARIATION SELECTOR-256 074D..07A5 ; AL # Lo [89] SYRIAC LETTER SOGDIAN ZHAIN..THAANA LETTER WAAVU 07B1 ; AL # Lo THAANA LETTER NAA 07B2..07BF ; AL # Cn [14] <reserved-07B2>..<reserved-07BF> +0860..086A ; AL # Lo [11] SYRIAC LETTER MALAYALAM NGA..SYRIAC LETTER MALAYALAM SSA +086B..086F ; AL # Cn [5] <reserved-086B>..<reserved-086F> 08A0..08B4 ; AL # Lo [21] ARABIC LETTER BEH WITH SMALL V BELOW..ARABIC LETTER KAF WITH DOT BELOW -08B5..08E2 ; AL # Cn [46] <reserved-08B5>..<reserved-08E2> +08B5 ; AL # Cn <reserved-08B5> +08B6..08BD ; AL # Lo [8] ARABIC LETTER BEH WITH SMALL MEEM ABOVE..ARABIC LETTER AFRICAN NOON +08BE..08D3 ; AL # Cn [22] <reserved-08BE>..<reserved-08D3> FB50..FBB1 ; AL # Lo [98] ARABIC LETTER ALEF WASLA ISOLATED FORM..ARABIC LETTER YEH BARREE WITH HAMZA ABOVE FINAL FORM FBB2..FBC1 ; AL # Sk [16] ARABIC SYMBOL DOT ABOVE..ARABIC SYMBOL SMALL TAH BELOW FBC2..FBD2 ; AL # Cn [17] <reserved-FBC2>..<reserved-FBD2> @@ -2151,7 +2237,7 @@ FEFD..FEFE ; AL # Cn [2] <reserved-FEFD>..<reserved-FEFE> 1EEBC..1EEEF ; AL # Cn [52] <reserved-1EEBC>..<reserved-1EEEF> 1EEF2..1EEFF ; AL # Cn [14] <reserved-1EEF2>..<reserved-1EEFF> -# Total code points: 1435 +# Total code points: 1436 # ================================================ diff --git a/tests/data/GraphemeBreakProperty.txt b/tests/data/GraphemeBreakProperty.txt index fba2ee8793..32bb12e47e 100644 --- a/tests/data/GraphemeBreakProperty.txt +++ b/tests/data/GraphemeBreakProperty.txt @@ -1,10 +1,11 @@ -# GraphemeBreakProperty-8.0.0.txt -# Date: 2015-02-13, 13:47:14 GMT [MD] +# GraphemeBreakProperty-10.0.0.txt +# Date: 2017-03-12, 07:03:41 GMT +# © 2017 Unicode®, Inc. +# Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries. +# For terms of use, see http://www.unicode.org/terms_of_use.html # # Unicode Character Database -# Copyright (c) 1991-2015 Unicode, Inc. -# For terms of use, see http://www.unicode.org/terms_of_use.html -# For documentation, see http://www.unicode.org/reports/tr44/ +# For documentation, see http://www.unicode.org/reports/tr44/ # ================================================ @@ -17,6 +18,21 @@ # ================================================ +0600..0605 ; Prepend # Cf [6] ARABIC NUMBER SIGN..ARABIC NUMBER MARK ABOVE +06DD ; Prepend # Cf ARABIC END OF AYAH +070F ; Prepend # Cf SYRIAC ABBREVIATION MARK +08E2 ; Prepend # Cf ARABIC DISPUTED END OF AYAH +0D4E ; Prepend # Lo MALAYALAM LETTER DOT REPH +110BD ; Prepend # Cf KAITHI NUMBER SIGN +111C2..111C3 ; Prepend # Lo [2] SHARADA SIGN JIHVAMULIYA..SHARADA SIGN UPADHMANIYA +11A3A ; Prepend # Lo ZANABAZAR SQUARE CLUSTER-INITIAL LETTER RA +11A86..11A89 ; Prepend # Lo [4] SOYOMBO CLUSTER-INITIAL LETTER RA..SOYOMBO CLUSTER-INITIAL LETTER SA +11D46 ; Prepend # Lo MASARAM GONDI REPHA + +# Total code points: 19 + +# ================================================ + 000D ; CR # Cc <control-000D> # Total code points: 1 @@ -34,10 +50,7 @@ 000E..001F ; Control # Cc [18] <control-000E>..<control-001F> 007F..009F ; Control # Cc [33] <control-007F>..<control-009F> 00AD ; Control # Cf SOFT HYPHEN -0600..0605 ; Control # Cf [6] ARABIC NUMBER SIGN..ARABIC NUMBER MARK ABOVE 061C ; Control # Cf ARABIC LETTER MARK -06DD ; Control # Cf ARABIC END OF AYAH -070F ; Control # Cf SYRIAC ABBREVIATION MARK 180E ; Control # Cf MONGOLIAN VOWEL SEPARATOR 200B ; Control # Cf ZERO WIDTH SPACE 200E..200F ; Control # Cf [2] LEFT-TO-RIGHT MARK..RIGHT-TO-LEFT MARK @@ -51,17 +64,15 @@ D800..DFFF ; Control # Cs [2048] <surrogate-D800>..<surrogate-DFFF> FEFF ; Control # Cf ZERO WIDTH NO-BREAK SPACE FFF0..FFF8 ; Control # Cn [9] <reserved-FFF0>..<reserved-FFF8> FFF9..FFFB ; Control # Cf [3] INTERLINEAR ANNOTATION ANCHOR..INTERLINEAR ANNOTATION TERMINATOR -110BD ; Control # Cf KAITHI NUMBER SIGN 1BCA0..1BCA3 ; Control # Cf [4] SHORTHAND FORMAT LETTER OVERLAP..SHORTHAND FORMAT UP STEP 1D173..1D17A ; Control # Cf [8] MUSICAL SYMBOL BEGIN BEAM..MUSICAL SYMBOL END PHRASE E0000 ; Control # Cn <reserved-E0000> E0001 ; Control # Cf LANGUAGE TAG E0002..E001F ; Control # Cn [30] <reserved-E0002>..<reserved-E001F> -E0020..E007F ; Control # Cf [96] TAG SPACE..CANCEL TAG E0080..E00FF ; Control # Cn [128] <reserved-E0080>..<reserved-E00FF> E01F0..E0FFF ; Control # Cn [3600] <reserved-E01F0>..<reserved-E0FFF> -# Total code points: 6030 +# Total code points: 5925 # ================================================ @@ -89,6 +100,7 @@ E01F0..E0FFF ; Control # Cn [3600] <reserved-E01F0>..<reserved-E0FFF> 0825..0827 ; Extend # Mn [3] SAMARITAN VOWEL SIGN SHORT A..SAMARITAN VOWEL SIGN U 0829..082D ; Extend # Mn [5] SAMARITAN VOWEL SIGN LONG I..SAMARITAN MARK NEQUDAA 0859..085B ; Extend # Mn [3] MANDAIC AFFRICATION MARK..MANDAIC GEMINATION MARK +08D4..08E1 ; Extend # Mn [14] ARABIC SMALL HIGH WORD AR-RUB..ARABIC SMALL HIGH SIGN SAFHA 08E3..0902 ; Extend # Mn [32] ARABIC TURNED DAMMA BELOW..DEVANAGARI SIGN ANUSVARA 093A ; Extend # Mn DEVANAGARI VOWEL SIGN OE 093C ; Extend # Mn DEVANAGARI SIGN NUKTA @@ -117,6 +129,7 @@ E01F0..E0FFF ; Control # Cn [3600] <reserved-E01F0>..<reserved-E0FFF> 0AC7..0AC8 ; Extend # Mn [2] GUJARATI VOWEL SIGN E..GUJARATI VOWEL SIGN AI 0ACD ; Extend # Mn GUJARATI SIGN VIRAMA 0AE2..0AE3 ; Extend # Mn [2] GUJARATI VOWEL SIGN VOCALIC L..GUJARATI VOWEL SIGN VOCALIC LL +0AFA..0AFF ; Extend # Mn [6] GUJARATI SIGN SUKUN..GUJARATI SIGN TWO-CIRCLE NUKTA ABOVE 0B01 ; Extend # Mn ORIYA SIGN CANDRABINDU 0B3C ; Extend # Mn ORIYA SIGN NUKTA 0B3E ; Extend # Mc ORIYA VOWEL SIGN AA @@ -145,7 +158,8 @@ E01F0..E0FFF ; Control # Cn [3600] <reserved-E01F0>..<reserved-E0FFF> 0CCC..0CCD ; Extend # Mn [2] KANNADA VOWEL SIGN AU..KANNADA SIGN VIRAMA 0CD5..0CD6 ; Extend # Mc [2] KANNADA LENGTH MARK..KANNADA AI LENGTH MARK 0CE2..0CE3 ; Extend # Mn [2] KANNADA VOWEL SIGN VOCALIC L..KANNADA VOWEL SIGN VOCALIC LL -0D01 ; Extend # Mn MALAYALAM SIGN CANDRABINDU +0D00..0D01 ; Extend # Mn [2] MALAYALAM SIGN COMBINING ANUSVARA ABOVE..MALAYALAM SIGN CANDRABINDU +0D3B..0D3C ; Extend # Mn [2] MALAYALAM SIGN VERTICAL BAR VIRAMA..MALAYALAM SIGN CIRCULAR VIRAMA 0D3E ; Extend # Mc MALAYALAM VOWEL SIGN AA 0D41..0D44 ; Extend # Mn [4] MALAYALAM VOWEL SIGN U..MALAYALAM VOWEL SIGN VOCALIC RR 0D4D ; Extend # Mn MALAYALAM SIGN VIRAMA @@ -195,6 +209,7 @@ E01F0..E0FFF ; Control # Cn [3600] <reserved-E01F0>..<reserved-E0FFF> 17C9..17D3 ; Extend # Mn [11] KHMER SIGN MUUSIKATOAN..KHMER SIGN BATHAMASAT 17DD ; Extend # Mn KHMER SIGN ATTHACAN 180B..180D ; Extend # Mn [3] MONGOLIAN FREE VARIATION SELECTOR ONE..MONGOLIAN FREE VARIATION SELECTOR THREE +1885..1886 ; Extend # Mn [2] MONGOLIAN LETTER ALI GALI BALUDA..MONGOLIAN LETTER ALI GALI THREE BALUDA 18A9 ; Extend # Mn MONGOLIAN LETTER ALI GALI DAGALGA 1920..1922 ; Extend # Mn [3] LIMBU VOWEL SIGN A..LIMBU VOWEL SIGN U 1927..1928 ; Extend # Mn [2] LIMBU VOWEL SIGN E..LIMBU VOWEL SIGN O @@ -233,9 +248,9 @@ E01F0..E0FFF ; Control # Cn [3600] <reserved-E01F0>..<reserved-E0FFF> 1CED ; Extend # Mn VEDIC SIGN TIRYAK 1CF4 ; Extend # Mn VEDIC TONE CANDRA ABOVE 1CF8..1CF9 ; Extend # Mn [2] VEDIC TONE RING ABOVE..VEDIC TONE DOUBLE RING ABOVE -1DC0..1DF5 ; Extend # Mn [54] COMBINING DOTTED GRAVE ACCENT..COMBINING UP TACK ABOVE -1DFC..1DFF ; Extend # Mn [4] COMBINING DOUBLE INVERTED BREVE BELOW..COMBINING RIGHT ARROWHEAD AND DOWN ARROWHEAD BELOW -200C..200D ; Extend # Cf [2] ZERO WIDTH NON-JOINER..ZERO WIDTH JOINER +1DC0..1DF9 ; Extend # Mn [58] COMBINING DOTTED GRAVE ACCENT..COMBINING WIDE INVERTED BRIDGE BELOW +1DFB..1DFF ; Extend # Mn [5] COMBINING DELETION MARK..COMBINING RIGHT ARROWHEAD AND DOWN ARROWHEAD BELOW +200C ; Extend # Cf ZERO WIDTH NON-JOINER 20D0..20DC ; Extend # Mn [13] COMBINING LEFT HARPOON ABOVE..COMBINING FOUR DOTS ABOVE 20DD..20E0 ; Extend # Me [4] COMBINING ENCLOSING CIRCLE..COMBINING ENCLOSING CIRCLE BACKSLASH 20E1 ; Extend # Mn COMBINING LEFT RIGHT ARROW ABOVE @@ -256,7 +271,7 @@ A802 ; Extend # Mn SYLOTI NAGRI SIGN DVISVARA A806 ; Extend # Mn SYLOTI NAGRI SIGN HASANTA A80B ; Extend # Mn SYLOTI NAGRI SIGN ANUSVARA A825..A826 ; Extend # Mn [2] SYLOTI NAGRI VOWEL SIGN U..SYLOTI NAGRI VOWEL SIGN E -A8C4 ; Extend # Mn SAURASHTRA SIGN VIRAMA +A8C4..A8C5 ; Extend # Mn [2] SAURASHTRA SIGN VIRAMA..SAURASHTRA SIGN CANDRABINDU A8E0..A8F1 ; Extend # Mn [18] COMBINING DEVANAGARI DIGIT ZERO..COMBINING DEVANAGARI SIGN AVAGRAHA A926..A92D ; Extend # Mn [8] KAYAH LI VOWEL UE..KAYAH LI TONE CALYA PLOPHU A947..A951 ; Extend # Mn [11] REJANG VOWEL SIGN I..REJANG CONSONANT SIGN R @@ -309,6 +324,7 @@ FF9E..FF9F ; Extend # Lm [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDT 1122F..11231 ; Extend # Mn [3] KHOJKI VOWEL SIGN U..KHOJKI VOWEL SIGN AI 11234 ; Extend # Mn KHOJKI SIGN ANUSVARA 11236..11237 ; Extend # Mn [2] KHOJKI SIGN NUKTA..KHOJKI SIGN SHADDA +1123E ; Extend # Mn KHOJKI SIGN SUKUN 112DF ; Extend # Mn KHUDAWADI SIGN ANUSVARA 112E3..112EA ; Extend # Mn [8] KHUDAWADI VOWEL SIGN U..KHUDAWADI SIGN VIRAMA 11300..11301 ; Extend # Mn [2] GRANTHA SIGN COMBINING ANUSVARA ABOVE..GRANTHA SIGN CANDRABINDU @@ -318,6 +334,9 @@ FF9E..FF9F ; Extend # Lm [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDT 11357 ; Extend # Mc GRANTHA AU LENGTH MARK 11366..1136C ; Extend # Mn [7] COMBINING GRANTHA DIGIT ZERO..COMBINING GRANTHA DIGIT SIX 11370..11374 ; Extend # Mn [5] COMBINING GRANTHA LETTER A..COMBINING GRANTHA LETTER PA +11438..1143F ; Extend # Mn [8] NEWA VOWEL SIGN U..NEWA VOWEL SIGN AI +11442..11444 ; Extend # Mn [3] NEWA SIGN VIRAMA..NEWA SIGN ANUSVARA +11446 ; Extend # Mn NEWA SIGN NUKTA 114B0 ; Extend # Mc TIRHUTA VOWEL SIGN AA 114B3..114B8 ; Extend # Mn [6] TIRHUTA VOWEL SIGN U..TIRHUTA VOWEL SIGN VOCALIC LL 114BA ; Extend # Mn TIRHUTA VOWEL SIGN SHORT E @@ -339,6 +358,27 @@ FF9E..FF9F ; Extend # Lm [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDT 1171D..1171F ; Extend # Mn [3] AHOM CONSONANT SIGN MEDIAL LA..AHOM CONSONANT SIGN MEDIAL LIGATING RA 11722..11725 ; Extend # Mn [4] AHOM VOWEL SIGN I..AHOM VOWEL SIGN UU 11727..1172B ; Extend # Mn [5] AHOM VOWEL SIGN AW..AHOM SIGN KILLER +11A01..11A06 ; Extend # Mn [6] ZANABAZAR SQUARE VOWEL SIGN I..ZANABAZAR SQUARE VOWEL SIGN O +11A09..11A0A ; Extend # Mn [2] ZANABAZAR SQUARE VOWEL SIGN REVERSED I..ZANABAZAR SQUARE VOWEL LENGTH MARK +11A33..11A38 ; Extend # Mn [6] ZANABAZAR SQUARE FINAL CONSONANT MARK..ZANABAZAR SQUARE SIGN ANUSVARA +11A3B..11A3E ; Extend # Mn [4] ZANABAZAR SQUARE CLUSTER-FINAL LETTER YA..ZANABAZAR SQUARE CLUSTER-FINAL LETTER VA +11A47 ; Extend # Mn ZANABAZAR SQUARE SUBJOINER +11A51..11A56 ; Extend # Mn [6] SOYOMBO VOWEL SIGN I..SOYOMBO VOWEL SIGN OE +11A59..11A5B ; Extend # Mn [3] SOYOMBO VOWEL SIGN VOCALIC R..SOYOMBO VOWEL LENGTH MARK +11A8A..11A96 ; Extend # Mn [13] SOYOMBO FINAL CONSONANT SIGN G..SOYOMBO SIGN ANUSVARA +11A98..11A99 ; Extend # Mn [2] SOYOMBO GEMINATION MARK..SOYOMBO SUBJOINER +11C30..11C36 ; Extend # Mn [7] BHAIKSUKI VOWEL SIGN I..BHAIKSUKI VOWEL SIGN VOCALIC L +11C38..11C3D ; Extend # Mn [6] BHAIKSUKI VOWEL SIGN E..BHAIKSUKI SIGN ANUSVARA +11C3F ; Extend # Mn BHAIKSUKI SIGN VIRAMA +11C92..11CA7 ; Extend # Mn [22] MARCHEN SUBJOINED LETTER KA..MARCHEN SUBJOINED LETTER ZA +11CAA..11CB0 ; Extend # Mn [7] MARCHEN SUBJOINED LETTER RA..MARCHEN VOWEL SIGN AA +11CB2..11CB3 ; Extend # Mn [2] MARCHEN VOWEL SIGN U..MARCHEN VOWEL SIGN E +11CB5..11CB6 ; Extend # Mn [2] MARCHEN SIGN ANUSVARA..MARCHEN SIGN CANDRABINDU +11D31..11D36 ; Extend # Mn [6] MASARAM GONDI VOWEL SIGN AA..MASARAM GONDI VOWEL SIGN VOCALIC R +11D3A ; Extend # Mn MASARAM GONDI VOWEL SIGN E +11D3C..11D3D ; Extend # Mn [2] MASARAM GONDI VOWEL SIGN AI..MASARAM GONDI VOWEL SIGN O +11D3F..11D45 ; Extend # Mn [7] MASARAM GONDI VOWEL SIGN AU..MASARAM GONDI VIRAMA +11D47 ; Extend # Mn MASARAM GONDI RA-KARA 16AF0..16AF4 ; Extend # Mn [5] BASSA VAH COMBINING HIGH TONE..BASSA VAH COMBINING HIGH-LOW TONE 16B30..16B36 ; Extend # Mn [7] PAHAWH HMONG MARK CIM TUB..PAHAWH HMONG MARK CIM TAUM 16F8F..16F92 ; Extend # Mn [4] MIAO TONE RIGHT..MIAO TONE BELOW @@ -356,10 +396,17 @@ FF9E..FF9F ; Extend # Lm [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDT 1DA84 ; Extend # Mn SIGNWRITING LOCATION HEAD NECK 1DA9B..1DA9F ; Extend # Mn [5] SIGNWRITING FILL MODIFIER-2..SIGNWRITING FILL MODIFIER-6 1DAA1..1DAAF ; Extend # Mn [15] SIGNWRITING ROTATION MODIFIER-2..SIGNWRITING ROTATION MODIFIER-16 +1E000..1E006 ; Extend # Mn [7] COMBINING GLAGOLITIC LETTER AZU..COMBINING GLAGOLITIC LETTER ZHIVETE +1E008..1E018 ; Extend # Mn [17] COMBINING GLAGOLITIC LETTER ZEMLJA..COMBINING GLAGOLITIC LETTER HERU +1E01B..1E021 ; Extend # Mn [7] COMBINING GLAGOLITIC LETTER SHTA..COMBINING GLAGOLITIC LETTER YATI +1E023..1E024 ; Extend # Mn [2] COMBINING GLAGOLITIC LETTER YU..COMBINING GLAGOLITIC LETTER SMALL YUS +1E026..1E02A ; Extend # Mn [5] COMBINING GLAGOLITIC LETTER YO..COMBINING GLAGOLITIC LETTER FITA 1E8D0..1E8D6 ; Extend # Mn [7] MENDE KIKAKUI COMBINING NUMBER TEENS..MENDE KIKAKUI COMBINING NUMBER MILLIONS +1E944..1E94A ; Extend # Mn [7] ADLAM ALIF LENGTHENER..ADLAM NUKTA +E0020..E007F ; Extend # Cf [96] TAG SPACE..CANCEL TAG E0100..E01EF ; Extend # Mn [240] VARIATION SELECTOR-17..VARIATION SELECTOR-256 -# Total code points: 1610 +# Total code points: 1901 # ================================================ @@ -444,6 +491,7 @@ E0100..E01EF ; Extend # Mn [240] VARIATION SELECTOR-17..VARIATION SELECTOR-256 1C34..1C35 ; SpacingMark # Mc [2] LEPCHA CONSONANT SIGN NYIN-DO..LEPCHA CONSONANT SIGN KANG 1CE1 ; SpacingMark # Mc VEDIC TONE ATHARVAVEDIC INDEPENDENT SVARITA 1CF2..1CF3 ; SpacingMark # Mc [2] VEDIC SIGN ARDHAVISARGA..VEDIC SIGN ROTATED ARDHAVISARGA +1CF7 ; SpacingMark # Mc VEDIC SIGN ATIKRAMA A823..A824 ; SpacingMark # Mc [2] SYLOTI NAGRI VOWEL SIGN A..SYLOTI NAGRI VOWEL SIGN I A827 ; SpacingMark # Mc SYLOTI NAGRI VOWEL SIGN OO A880..A881 ; SpacingMark # Mc [2] SAURASHTRA SIGN ANUSVARA..SAURASHTRA SIGN VISARGA @@ -482,6 +530,9 @@ ABEC ; SpacingMark # Mc MEETEI MAYEK LUM IYEK 11347..11348 ; SpacingMark # Mc [2] GRANTHA VOWEL SIGN EE..GRANTHA VOWEL SIGN AI 1134B..1134D ; SpacingMark # Mc [3] GRANTHA VOWEL SIGN OO..GRANTHA SIGN VIRAMA 11362..11363 ; SpacingMark # Mc [2] GRANTHA VOWEL SIGN VOCALIC L..GRANTHA VOWEL SIGN VOCALIC LL +11435..11437 ; SpacingMark # Mc [3] NEWA VOWEL SIGN AA..NEWA VOWEL SIGN II +11440..11441 ; SpacingMark # Mc [2] NEWA VOWEL SIGN O..NEWA VOWEL SIGN AU +11445 ; SpacingMark # Mc NEWA SIGN VISARGA 114B1..114B2 ; SpacingMark # Mc [2] TIRHUTA VOWEL SIGN I..TIRHUTA VOWEL SIGN II 114B9 ; SpacingMark # Mc TIRHUTA VOWEL SIGN E 114BB..114BC ; SpacingMark # Mc [2] TIRHUTA VOWEL SIGN AI..TIRHUTA VOWEL SIGN O @@ -498,11 +549,20 @@ ABEC ; SpacingMark # Mc MEETEI MAYEK LUM IYEK 116B6 ; SpacingMark # Mc TAKRI SIGN VIRAMA 11720..11721 ; SpacingMark # Mc [2] AHOM VOWEL SIGN A..AHOM VOWEL SIGN AA 11726 ; SpacingMark # Mc AHOM VOWEL SIGN E +11A07..11A08 ; SpacingMark # Mc [2] ZANABAZAR SQUARE VOWEL SIGN AI..ZANABAZAR SQUARE VOWEL SIGN AU +11A39 ; SpacingMark # Mc ZANABAZAR SQUARE SIGN VISARGA +11A57..11A58 ; SpacingMark # Mc [2] SOYOMBO VOWEL SIGN AI..SOYOMBO VOWEL SIGN AU +11A97 ; SpacingMark # Mc SOYOMBO SIGN VISARGA +11C2F ; SpacingMark # Mc BHAIKSUKI VOWEL SIGN AA +11C3E ; SpacingMark # Mc BHAIKSUKI SIGN VISARGA +11CA9 ; SpacingMark # Mc MARCHEN SUBJOINED LETTER YA +11CB1 ; SpacingMark # Mc MARCHEN VOWEL SIGN I +11CB4 ; SpacingMark # Mc MARCHEN VOWEL SIGN O 16F51..16F7E ; SpacingMark # Mc [46] MIAO SIGN ASPIRATION..MIAO VOWEL SIGN NG 1D166 ; SpacingMark # Mc MUSICAL SYMBOL COMBINING SPRECHGESANG STEM 1D16D ; SpacingMark # Mc MUSICAL SYMBOL COMBINING AUGMENTATION DOT -# Total code points: 330 +# Total code points: 348 # ================================================ @@ -1333,4 +1393,83 @@ D789..D7A3 ; LVT # Lo [27] HANGUL SYLLABLE HIG..HANGUL SYLLABLE HIH # Total code points: 10773 +# ================================================ + +261D ; E_Base # So WHITE UP POINTING INDEX +26F9 ; E_Base # So PERSON WITH BALL +270A..270D ; E_Base # So [4] RAISED FIST..WRITING HAND +1F385 ; E_Base # So FATHER CHRISTMAS +1F3C2..1F3C4 ; E_Base # So [3] SNOWBOARDER..SURFER +1F3C7 ; E_Base # So HORSE RACING +1F3CA..1F3CC ; E_Base # So [3] SWIMMER..GOLFER +1F442..1F443 ; E_Base # So [2] EAR..NOSE +1F446..1F450 ; E_Base # So [11] WHITE UP POINTING BACKHAND INDEX..OPEN HANDS SIGN +1F46E ; E_Base # So POLICE OFFICER +1F470..1F478 ; E_Base # So [9] BRIDE WITH VEIL..PRINCESS +1F47C ; E_Base # So BABY ANGEL +1F481..1F483 ; E_Base # So [3] INFORMATION DESK PERSON..DANCER +1F485..1F487 ; E_Base # So [3] NAIL POLISH..HAIRCUT +1F4AA ; E_Base # So FLEXED BICEPS +1F574..1F575 ; E_Base # So [2] MAN IN BUSINESS SUIT LEVITATING..SLEUTH OR SPY +1F57A ; E_Base # So MAN DANCING +1F590 ; E_Base # So RAISED HAND WITH FINGERS SPLAYED +1F595..1F596 ; E_Base # So [2] REVERSED HAND WITH MIDDLE FINGER EXTENDED..RAISED HAND WITH PART BETWEEN MIDDLE AND RING FINGERS +1F645..1F647 ; E_Base # So [3] FACE WITH NO GOOD GESTURE..PERSON BOWING DEEPLY +1F64B..1F64F ; E_Base # So [5] HAPPY PERSON RAISING ONE HAND..PERSON WITH FOLDED HANDS +1F6A3 ; E_Base # So ROWBOAT +1F6B4..1F6B6 ; E_Base # So [3] BICYCLIST..PEDESTRIAN +1F6C0 ; E_Base # So BATH +1F6CC ; E_Base # So SLEEPING ACCOMMODATION +1F918..1F91C ; E_Base # So [5] SIGN OF THE HORNS..RIGHT-FACING FIST +1F91E..1F91F ; E_Base # So [2] HAND WITH INDEX AND MIDDLE FINGERS CROSSED..I LOVE YOU HAND SIGN +1F926 ; E_Base # So FACE PALM +1F930..1F939 ; E_Base # So [10] PREGNANT WOMAN..JUGGLING +1F93D..1F93E ; E_Base # So [2] WATER POLO..HANDBALL +1F9D1..1F9DD ; E_Base # So [13] ADULT..ELF + +# Total code points: 98 + +# ================================================ + +1F3FB..1F3FF ; E_Modifier # Sk [5] EMOJI MODIFIER FITZPATRICK TYPE-1-2..EMOJI MODIFIER FITZPATRICK TYPE-6 + +# Total code points: 5 + +# ================================================ + +200D ; ZWJ # Cf ZERO WIDTH JOINER + +# Total code points: 1 + +# ================================================ + +2640 ; Glue_After_Zwj # So FEMALE SIGN +2642 ; Glue_After_Zwj # So MALE SIGN +2695..2696 ; Glue_After_Zwj # So [2] STAFF OF AESCULAPIUS..SCALES +2708 ; Glue_After_Zwj # So AIRPLANE +2764 ; Glue_After_Zwj # So HEAVY BLACK HEART +1F308 ; Glue_After_Zwj # So RAINBOW +1F33E ; Glue_After_Zwj # So EAR OF RICE +1F373 ; Glue_After_Zwj # So COOKING +1F393 ; Glue_After_Zwj # So GRADUATION CAP +1F3A4 ; Glue_After_Zwj # So MICROPHONE +1F3A8 ; Glue_After_Zwj # So ARTIST PALETTE +1F3EB ; Glue_After_Zwj # So SCHOOL +1F3ED ; Glue_After_Zwj # So FACTORY +1F48B ; Glue_After_Zwj # So KISS MARK +1F4BB..1F4BC ; Glue_After_Zwj # So [2] PERSONAL COMPUTER..BRIEFCASE +1F527 ; Glue_After_Zwj # So WRENCH +1F52C ; Glue_After_Zwj # So MICROSCOPE +1F5E8 ; Glue_After_Zwj # So LEFT SPEECH BUBBLE +1F680 ; Glue_After_Zwj # So ROCKET +1F692 ; Glue_After_Zwj # So FIRE ENGINE + +# Total code points: 22 + +# ================================================ + +1F466..1F469 ; E_Base_GAZ # So [4] BOY..WOMAN + +# Total code points: 4 + # EOF diff --git a/tests/data/GraphemeBreakTest.txt b/tests/data/GraphemeBreakTest.txt index a3ed239c95..d7d8f90de0 100644 --- a/tests/data/GraphemeBreakTest.txt +++ b/tests/data/GraphemeBreakTest.txt @@ -1,22 +1,24 @@ -# GraphemeBreakTest-8.0.0.txt -# Date: 2015-02-13, 13:47:15 GMT [MD] +# GraphemeBreakTest-10.0.0.txt +# Date: 2017-04-14, 05:40:29 GMT +# © 2017 Unicode®, Inc. +# Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries. +# For terms of use, see http://www.unicode.org/terms_of_use.html # # Unicode Character Database -# Copyright (c) 1991-2015 Unicode, Inc. -# For terms of use, see http://www.unicode.org/terms_of_use.html -# For documentation, see http://www.unicode.org/reports/tr44/ +# For documentation, see http://www.unicode.org/reports/tr44/ # -# Default Grapheme Break Test +# Default Grapheme_Cluster_Break Test # # Format: -# <string> (# <comment>)? -# <string> contains hex Unicode code points, with -# ÷ wherever there is a break opportunity, and +# <string> (# <comment>)? +# <string> contains hex Unicode code points, with +# ÷ wherever there is a break opportunity, and # × wherever there is not. # <comment> the format can change, but currently it shows: # - the sample character name # - (x) the Grapheme_Cluster_Break property value for the sample character -# - [x] the rule that determines whether there is a break or not +# - [x] the rule that determines whether there is a break or not, +# as listed in the Rules section of GraphemeBreakTest.html # # These samples may be extended or changed in the future. # @@ -30,6 +32,8 @@ ÷ 0020 × 0308 ÷ 0001 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3] ÷ 0020 × 0300 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3] ÷ 0020 × 0308 × 0300 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3] +÷ 0020 ÷ 0600 ÷ # ÷ [0.2] SPACE (Other) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ 0020 × 0308 ÷ 0600 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] ÷ 0020 × 0903 ÷ # ÷ [0.2] SPACE (Other) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] ÷ 0020 × 0308 × 0903 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] ÷ 0020 ÷ 1100 ÷ # ÷ [0.2] SPACE (Other) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] @@ -42,8 +46,18 @@ ÷ 0020 × 0308 ÷ AC00 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] ÷ 0020 ÷ AC01 ÷ # ÷ [0.2] SPACE (Other) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] ÷ 0020 × 0308 ÷ AC01 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 0020 ÷ 1F1E6 ÷ # ÷ [0.2] SPACE (Other) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [0.3] -÷ 0020 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [0.3] +÷ 0020 ÷ 1F1E6 ÷ # ÷ [0.2] SPACE (Other) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0020 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0020 ÷ 261D ÷ # ÷ [0.2] SPACE (Other) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ 0020 × 0308 ÷ 261D ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ 0020 ÷ 1F3FB ÷ # ÷ [0.2] SPACE (Other) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ 0020 × 0308 ÷ 1F3FB ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ 0020 × 200D ÷ # ÷ [0.2] SPACE (Other) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3] +÷ 0020 × 0308 × 200D ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3] +÷ 0020 ÷ 2640 ÷ # ÷ [0.2] SPACE (Other) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ 0020 × 0308 ÷ 2640 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ 0020 ÷ 1F466 ÷ # ÷ [0.2] SPACE (Other) ÷ [999.0] BOY (EBG) ÷ [0.3] +÷ 0020 × 0308 ÷ 1F466 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] BOY (EBG) ÷ [0.3] ÷ 0020 ÷ 0378 ÷ # ÷ [0.2] SPACE (Other) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3] ÷ 0020 × 0308 ÷ 0378 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3] ÷ 0020 ÷ D800 ÷ # ÷ [0.2] SPACE (Other) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3] @@ -58,6 +72,8 @@ ÷ 000D ÷ 0308 ÷ 0001 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3] ÷ 000D ÷ 0300 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3] ÷ 000D ÷ 0308 × 0300 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3] +÷ 000D ÷ 0600 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ 000D ÷ 0308 ÷ 0600 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] ÷ 000D ÷ 0903 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] ÷ 000D ÷ 0308 × 0903 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] ÷ 000D ÷ 1100 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] @@ -70,8 +86,18 @@ ÷ 000D ÷ 0308 ÷ AC00 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] ÷ 000D ÷ AC01 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] ÷ 000D ÷ 0308 ÷ AC01 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 000D ÷ 1F1E6 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [0.3] -÷ 000D ÷ 0308 ÷ 1F1E6 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [0.3] +÷ 000D ÷ 1F1E6 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 000D ÷ 0308 ÷ 1F1E6 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 000D ÷ 261D ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ 000D ÷ 0308 ÷ 261D ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ 000D ÷ 1F3FB ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ 000D ÷ 0308 ÷ 1F3FB ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ 000D ÷ 200D ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3] +÷ 000D ÷ 0308 × 200D ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3] +÷ 000D ÷ 2640 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ 000D ÷ 0308 ÷ 2640 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ 000D ÷ 1F466 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] BOY (EBG) ÷ [0.3] +÷ 000D ÷ 0308 ÷ 1F466 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] BOY (EBG) ÷ [0.3] ÷ 000D ÷ 0378 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] <reserved-0378> (Other) ÷ [0.3] ÷ 000D ÷ 0308 ÷ 0378 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3] ÷ 000D ÷ D800 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] <surrogate-D800> (Control) ÷ [0.3] @@ -86,6 +112,8 @@ ÷ 000A ÷ 0308 ÷ 0001 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3] ÷ 000A ÷ 0300 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3] ÷ 000A ÷ 0308 × 0300 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3] +÷ 000A ÷ 0600 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ 000A ÷ 0308 ÷ 0600 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] ÷ 000A ÷ 0903 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] ÷ 000A ÷ 0308 × 0903 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] ÷ 000A ÷ 1100 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] @@ -98,8 +126,18 @@ ÷ 000A ÷ 0308 ÷ AC00 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] ÷ 000A ÷ AC01 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] ÷ 000A ÷ 0308 ÷ AC01 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 000A ÷ 1F1E6 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [0.3] -÷ 000A ÷ 0308 ÷ 1F1E6 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [0.3] +÷ 000A ÷ 1F1E6 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 000A ÷ 0308 ÷ 1F1E6 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 000A ÷ 261D ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ 000A ÷ 0308 ÷ 261D ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ 000A ÷ 1F3FB ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ 000A ÷ 0308 ÷ 1F3FB ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ 000A ÷ 200D ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3] +÷ 000A ÷ 0308 × 200D ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3] +÷ 000A ÷ 2640 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ 000A ÷ 0308 ÷ 2640 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ 000A ÷ 1F466 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] BOY (EBG) ÷ [0.3] +÷ 000A ÷ 0308 ÷ 1F466 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] BOY (EBG) ÷ [0.3] ÷ 000A ÷ 0378 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] <reserved-0378> (Other) ÷ [0.3] ÷ 000A ÷ 0308 ÷ 0378 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3] ÷ 000A ÷ D800 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] <surrogate-D800> (Control) ÷ [0.3] @@ -114,6 +152,8 @@ ÷ 0001 ÷ 0308 ÷ 0001 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3] ÷ 0001 ÷ 0300 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3] ÷ 0001 ÷ 0308 × 0300 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3] +÷ 0001 ÷ 0600 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ 0001 ÷ 0308 ÷ 0600 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] ÷ 0001 ÷ 0903 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] ÷ 0001 ÷ 0308 × 0903 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] ÷ 0001 ÷ 1100 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] @@ -126,8 +166,18 @@ ÷ 0001 ÷ 0308 ÷ AC00 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] ÷ 0001 ÷ AC01 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] ÷ 0001 ÷ 0308 ÷ AC01 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 0001 ÷ 1F1E6 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [0.3] -÷ 0001 ÷ 0308 ÷ 1F1E6 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [0.3] +÷ 0001 ÷ 1F1E6 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0001 ÷ 0308 ÷ 1F1E6 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0001 ÷ 261D ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ 0001 ÷ 0308 ÷ 261D ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ 0001 ÷ 1F3FB ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ 0001 ÷ 0308 ÷ 1F3FB ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ 0001 ÷ 200D ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3] +÷ 0001 ÷ 0308 × 200D ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3] +÷ 0001 ÷ 2640 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ 0001 ÷ 0308 ÷ 2640 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ 0001 ÷ 1F466 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] BOY (EBG) ÷ [0.3] +÷ 0001 ÷ 0308 ÷ 1F466 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] BOY (EBG) ÷ [0.3] ÷ 0001 ÷ 0378 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] <reserved-0378> (Other) ÷ [0.3] ÷ 0001 ÷ 0308 ÷ 0378 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3] ÷ 0001 ÷ D800 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] <surrogate-D800> (Control) ÷ [0.3] @@ -142,6 +192,8 @@ ÷ 0300 × 0308 ÷ 0001 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3] ÷ 0300 × 0300 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3] ÷ 0300 × 0308 × 0300 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) × [9.0] COMBINING DIAERESIS (Extend) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3] +÷ 0300 ÷ 0600 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ 0300 × 0308 ÷ 0600 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] ÷ 0300 × 0903 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] ÷ 0300 × 0308 × 0903 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) × [9.0] COMBINING DIAERESIS (Extend) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] ÷ 0300 ÷ 1100 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] @@ -154,12 +206,62 @@ ÷ 0300 × 0308 ÷ AC00 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] ÷ 0300 ÷ AC01 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] ÷ 0300 × 0308 ÷ AC01 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 0300 ÷ 1F1E6 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [0.3] -÷ 0300 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [0.3] +÷ 0300 ÷ 1F1E6 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0300 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0300 ÷ 261D ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ 0300 × 0308 ÷ 261D ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ 0300 ÷ 1F3FB ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ 0300 × 0308 ÷ 1F3FB ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ 0300 × 200D ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3] +÷ 0300 × 0308 × 200D ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) × [9.0] COMBINING DIAERESIS (Extend) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3] +÷ 0300 ÷ 2640 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ 0300 × 0308 ÷ 2640 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ 0300 ÷ 1F466 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) ÷ [999.0] BOY (EBG) ÷ [0.3] +÷ 0300 × 0308 ÷ 1F466 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] BOY (EBG) ÷ [0.3] ÷ 0300 ÷ 0378 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3] ÷ 0300 × 0308 ÷ 0378 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3] ÷ 0300 ÷ D800 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3] ÷ 0300 × 0308 ÷ D800 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3] +÷ 0600 × 0020 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.2] SPACE (Other) ÷ [0.3] +÷ 0600 × 0308 ÷ 0020 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] SPACE (Other) ÷ [0.3] +÷ 0600 ÷ 000D ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +÷ 0600 × 0308 ÷ 000D ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +÷ 0600 ÷ 000A ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3] +÷ 0600 × 0308 ÷ 000A ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3] +÷ 0600 ÷ 0001 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3] +÷ 0600 × 0308 ÷ 0001 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3] +÷ 0600 × 0300 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3] +÷ 0600 × 0308 × 0300 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3] +÷ 0600 × 0600 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.2] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ 0600 × 0308 ÷ 0600 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ 0600 × 0903 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 0600 × 0308 × 0903 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 0600 × 1100 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.2] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 0600 × 0308 ÷ 1100 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 0600 × 1160 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.2] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 0600 × 0308 ÷ 1160 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 0600 × 11A8 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.2] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 0600 × 0308 ÷ 11A8 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 0600 × AC00 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.2] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 0600 × 0308 ÷ AC00 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 0600 × AC01 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.2] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 0600 × 0308 ÷ AC01 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 0600 × 1F1E6 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0600 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0600 × 261D ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.2] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ 0600 × 0308 ÷ 261D ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ 0600 × 1F3FB ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ 0600 × 0308 ÷ 1F3FB ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ 0600 × 200D ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3] +÷ 0600 × 0308 × 200D ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3] +÷ 0600 × 2640 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.2] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ 0600 × 0308 ÷ 2640 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ 0600 × 1F466 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.2] BOY (EBG) ÷ [0.3] +÷ 0600 × 0308 ÷ 1F466 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] BOY (EBG) ÷ [0.3] +÷ 0600 × 0378 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.2] <reserved-0378> (Other) ÷ [0.3] +÷ 0600 × 0308 ÷ 0378 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3] +÷ 0600 ÷ D800 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3] +÷ 0600 × 0308 ÷ D800 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3] ÷ 0903 ÷ 0020 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [999.0] SPACE (Other) ÷ [0.3] ÷ 0903 × 0308 ÷ 0020 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] SPACE (Other) ÷ [0.3] ÷ 0903 ÷ 000D ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] @@ -170,6 +272,8 @@ ÷ 0903 × 0308 ÷ 0001 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3] ÷ 0903 × 0300 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3] ÷ 0903 × 0308 × 0300 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3] +÷ 0903 ÷ 0600 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ 0903 × 0308 ÷ 0600 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] ÷ 0903 × 0903 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] ÷ 0903 × 0308 × 0903 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] ÷ 0903 ÷ 1100 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] @@ -182,8 +286,18 @@ ÷ 0903 × 0308 ÷ AC00 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] ÷ 0903 ÷ AC01 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] ÷ 0903 × 0308 ÷ AC01 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 0903 ÷ 1F1E6 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [0.3] -÷ 0903 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [0.3] +÷ 0903 ÷ 1F1E6 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0903 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0903 ÷ 261D ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ 0903 × 0308 ÷ 261D ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ 0903 ÷ 1F3FB ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ 0903 × 0308 ÷ 1F3FB ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ 0903 × 200D ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3] +÷ 0903 × 0308 × 200D ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3] +÷ 0903 ÷ 2640 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ 0903 × 0308 ÷ 2640 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ 0903 ÷ 1F466 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [999.0] BOY (EBG) ÷ [0.3] +÷ 0903 × 0308 ÷ 1F466 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] BOY (EBG) ÷ [0.3] ÷ 0903 ÷ 0378 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3] ÷ 0903 × 0308 ÷ 0378 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3] ÷ 0903 ÷ D800 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3] @@ -198,6 +312,8 @@ ÷ 1100 × 0308 ÷ 0001 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3] ÷ 1100 × 0300 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3] ÷ 1100 × 0308 × 0300 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3] +÷ 1100 ÷ 0600 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ 1100 × 0308 ÷ 0600 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] ÷ 1100 × 0903 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] ÷ 1100 × 0308 × 0903 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] ÷ 1100 × 1100 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [6.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] @@ -210,8 +326,18 @@ ÷ 1100 × 0308 ÷ AC00 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] ÷ 1100 × AC01 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [6.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] ÷ 1100 × 0308 ÷ AC01 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 1100 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [0.3] -÷ 1100 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [0.3] +÷ 1100 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 1100 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 1100 ÷ 261D ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ 1100 × 0308 ÷ 261D ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ 1100 ÷ 1F3FB ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ 1100 × 0308 ÷ 1F3FB ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ 1100 × 200D ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3] +÷ 1100 × 0308 × 200D ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3] +÷ 1100 ÷ 2640 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ 1100 × 0308 ÷ 2640 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ 1100 ÷ 1F466 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) ÷ [999.0] BOY (EBG) ÷ [0.3] +÷ 1100 × 0308 ÷ 1F466 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] BOY (EBG) ÷ [0.3] ÷ 1100 ÷ 0378 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3] ÷ 1100 × 0308 ÷ 0378 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3] ÷ 1100 ÷ D800 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3] @@ -226,6 +352,8 @@ ÷ 1160 × 0308 ÷ 0001 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3] ÷ 1160 × 0300 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3] ÷ 1160 × 0308 × 0300 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3] +÷ 1160 ÷ 0600 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ 1160 × 0308 ÷ 0600 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] ÷ 1160 × 0903 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] ÷ 1160 × 0308 × 0903 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] ÷ 1160 ÷ 1100 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] @@ -238,8 +366,18 @@ ÷ 1160 × 0308 ÷ AC00 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] ÷ 1160 ÷ AC01 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] ÷ 1160 × 0308 ÷ AC01 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 1160 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [0.3] -÷ 1160 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [0.3] +÷ 1160 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 1160 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 1160 ÷ 261D ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ 1160 × 0308 ÷ 261D ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ 1160 ÷ 1F3FB ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ 1160 × 0308 ÷ 1F3FB ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ 1160 × 200D ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3] +÷ 1160 × 0308 × 200D ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3] +÷ 1160 ÷ 2640 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ 1160 × 0308 ÷ 2640 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ 1160 ÷ 1F466 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [999.0] BOY (EBG) ÷ [0.3] +÷ 1160 × 0308 ÷ 1F466 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] BOY (EBG) ÷ [0.3] ÷ 1160 ÷ 0378 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3] ÷ 1160 × 0308 ÷ 0378 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3] ÷ 1160 ÷ D800 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3] @@ -254,6 +392,8 @@ ÷ 11A8 × 0308 ÷ 0001 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3] ÷ 11A8 × 0300 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3] ÷ 11A8 × 0308 × 0300 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3] +÷ 11A8 ÷ 0600 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ 11A8 × 0308 ÷ 0600 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] ÷ 11A8 × 0903 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] ÷ 11A8 × 0308 × 0903 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] ÷ 11A8 ÷ 1100 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] @@ -266,8 +406,18 @@ ÷ 11A8 × 0308 ÷ AC00 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] ÷ 11A8 ÷ AC01 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] ÷ 11A8 × 0308 ÷ AC01 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 11A8 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [0.3] -÷ 11A8 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [0.3] +÷ 11A8 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 11A8 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 11A8 ÷ 261D ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ 11A8 × 0308 ÷ 261D ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ 11A8 ÷ 1F3FB ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ 11A8 × 0308 ÷ 1F3FB ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ 11A8 × 200D ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3] +÷ 11A8 × 0308 × 200D ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3] +÷ 11A8 ÷ 2640 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ 11A8 × 0308 ÷ 2640 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ 11A8 ÷ 1F466 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] BOY (EBG) ÷ [0.3] +÷ 11A8 × 0308 ÷ 1F466 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] BOY (EBG) ÷ [0.3] ÷ 11A8 ÷ 0378 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3] ÷ 11A8 × 0308 ÷ 0378 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3] ÷ 11A8 ÷ D800 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3] @@ -282,6 +432,8 @@ ÷ AC00 × 0308 ÷ 0001 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3] ÷ AC00 × 0300 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3] ÷ AC00 × 0308 × 0300 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3] +÷ AC00 ÷ 0600 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ AC00 × 0308 ÷ 0600 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] ÷ AC00 × 0903 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] ÷ AC00 × 0308 × 0903 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] ÷ AC00 ÷ 1100 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] @@ -294,8 +446,18 @@ ÷ AC00 × 0308 ÷ AC00 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] ÷ AC00 ÷ AC01 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] ÷ AC00 × 0308 ÷ AC01 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ AC00 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [0.3] -÷ AC00 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [0.3] +÷ AC00 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ AC00 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ AC00 ÷ 261D ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ AC00 × 0308 ÷ 261D ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ AC00 ÷ 1F3FB ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ AC00 × 0308 ÷ 1F3FB ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ AC00 × 200D ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3] +÷ AC00 × 0308 × 200D ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3] +÷ AC00 ÷ 2640 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ AC00 × 0308 ÷ 2640 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ AC00 ÷ 1F466 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [999.0] BOY (EBG) ÷ [0.3] +÷ AC00 × 0308 ÷ 1F466 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] BOY (EBG) ÷ [0.3] ÷ AC00 ÷ 0378 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3] ÷ AC00 × 0308 ÷ 0378 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3] ÷ AC00 ÷ D800 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3] @@ -310,6 +472,8 @@ ÷ AC01 × 0308 ÷ 0001 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3] ÷ AC01 × 0300 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3] ÷ AC01 × 0308 × 0300 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3] +÷ AC01 ÷ 0600 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ AC01 × 0308 ÷ 0600 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] ÷ AC01 × 0903 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] ÷ AC01 × 0308 × 0903 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] ÷ AC01 ÷ 1100 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] @@ -322,40 +486,262 @@ ÷ AC01 × 0308 ÷ AC00 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] ÷ AC01 ÷ AC01 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] ÷ AC01 × 0308 ÷ AC01 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ AC01 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [0.3] -÷ AC01 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [0.3] +÷ AC01 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ AC01 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ AC01 ÷ 261D ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ AC01 × 0308 ÷ 261D ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ AC01 ÷ 1F3FB ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ AC01 × 0308 ÷ 1F3FB ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ AC01 × 200D ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3] +÷ AC01 × 0308 × 200D ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3] +÷ AC01 ÷ 2640 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ AC01 × 0308 ÷ 2640 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ AC01 ÷ 1F466 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [999.0] BOY (EBG) ÷ [0.3] +÷ AC01 × 0308 ÷ 1F466 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] BOY (EBG) ÷ [0.3] ÷ AC01 ÷ 0378 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3] ÷ AC01 × 0308 ÷ 0378 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3] ÷ AC01 ÷ D800 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3] ÷ AC01 × 0308 ÷ D800 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3] -÷ 1F1E6 ÷ 0020 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [999.0] SPACE (Other) ÷ [0.3] -÷ 1F1E6 × 0308 ÷ 0020 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] SPACE (Other) ÷ [0.3] -÷ 1F1E6 ÷ 000D ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -÷ 1F1E6 × 0308 ÷ 000D ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -÷ 1F1E6 ÷ 000A ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3] -÷ 1F1E6 × 0308 ÷ 000A ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3] -÷ 1F1E6 ÷ 0001 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3] -÷ 1F1E6 × 0308 ÷ 0001 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3] -÷ 1F1E6 × 0300 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3] -÷ 1F1E6 × 0308 × 0300 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) × [9.0] COMBINING DIAERESIS (Extend) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3] -÷ 1F1E6 × 0903 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] -÷ 1F1E6 × 0308 × 0903 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) × [9.0] COMBINING DIAERESIS (Extend) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] -÷ 1F1E6 ÷ 1100 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] -÷ 1F1E6 × 0308 ÷ 1100 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] -÷ 1F1E6 ÷ 1160 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] -÷ 1F1E6 × 0308 ÷ 1160 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] -÷ 1F1E6 ÷ 11A8 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] -÷ 1F1E6 × 0308 ÷ 11A8 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] -÷ 1F1E6 ÷ AC00 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] -÷ 1F1E6 × 0308 ÷ AC00 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] -÷ 1F1E6 ÷ AC01 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 1F1E6 × 0308 ÷ AC01 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 1F1E6 × 1F1E6 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) × [8.1] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [0.3] -÷ 1F1E6 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [0.3] -÷ 1F1E6 ÷ 0378 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3] -÷ 1F1E6 × 0308 ÷ 0378 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3] -÷ 1F1E6 ÷ D800 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3] -÷ 1F1E6 × 0308 ÷ D800 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3] +÷ 1F1E6 ÷ 0020 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] SPACE (Other) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 0020 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] SPACE (Other) ÷ [0.3] +÷ 1F1E6 ÷ 000D ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 000D ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +÷ 1F1E6 ÷ 000A ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 000A ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3] +÷ 1F1E6 ÷ 0001 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 0001 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3] +÷ 1F1E6 × 0300 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3] +÷ 1F1E6 × 0308 × 0300 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3] +÷ 1F1E6 ÷ 0600 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 0600 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ 1F1E6 × 0903 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 1F1E6 × 0308 × 0903 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 1F1E6 ÷ 1100 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 1100 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 1F1E6 ÷ 1160 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 1160 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 1F1E6 ÷ 11A8 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 11A8 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 1F1E6 ÷ AC00 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ AC00 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 1F1E6 ÷ AC01 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ AC01 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 1F1E6 × 1F1E6 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [12.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 1F1E6 ÷ 261D ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 261D ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ 1F1E6 ÷ 1F3FB ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 1F3FB ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ 1F1E6 × 200D ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3] +÷ 1F1E6 × 0308 × 200D ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3] +÷ 1F1E6 ÷ 2640 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 2640 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ 1F1E6 ÷ 1F466 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] BOY (EBG) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 1F466 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] BOY (EBG) ÷ [0.3] +÷ 1F1E6 ÷ 0378 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 0378 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3] +÷ 1F1E6 ÷ D800 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ D800 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3] +÷ 261D ÷ 0020 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) ÷ [999.0] SPACE (Other) ÷ [0.3] +÷ 261D × 0308 ÷ 0020 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] SPACE (Other) ÷ [0.3] +÷ 261D ÷ 000D ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +÷ 261D × 0308 ÷ 000D ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +÷ 261D ÷ 000A ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3] +÷ 261D × 0308 ÷ 000A ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3] +÷ 261D ÷ 0001 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3] +÷ 261D × 0308 ÷ 0001 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3] +÷ 261D × 0300 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3] +÷ 261D × 0308 × 0300 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [9.0] COMBINING DIAERESIS (Extend) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3] +÷ 261D ÷ 0600 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ 261D × 0308 ÷ 0600 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ 261D × 0903 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 261D × 0308 × 0903 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [9.0] COMBINING DIAERESIS (Extend) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 261D ÷ 1100 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 261D × 0308 ÷ 1100 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 261D ÷ 1160 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 261D × 0308 ÷ 1160 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 261D ÷ 11A8 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 261D × 0308 ÷ 11A8 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 261D ÷ AC00 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 261D × 0308 ÷ AC00 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 261D ÷ AC01 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 261D × 0308 ÷ AC01 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 261D ÷ 1F1E6 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 261D × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 261D ÷ 261D ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ 261D × 0308 ÷ 261D ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ 261D × 1F3FB ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [10.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ 261D × 0308 × 1F3FB ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [9.0] COMBINING DIAERESIS (Extend) × [10.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ 261D × 200D ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3] +÷ 261D × 0308 × 200D ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [9.0] COMBINING DIAERESIS (Extend) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3] +÷ 261D ÷ 2640 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ 261D × 0308 ÷ 2640 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ 261D ÷ 1F466 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) ÷ [999.0] BOY (EBG) ÷ [0.3] +÷ 261D × 0308 ÷ 1F466 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] BOY (EBG) ÷ [0.3] +÷ 261D ÷ 0378 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3] +÷ 261D × 0308 ÷ 0378 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3] +÷ 261D ÷ D800 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3] +÷ 261D × 0308 ÷ D800 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3] +÷ 1F3FB ÷ 0020 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [999.0] SPACE (Other) ÷ [0.3] +÷ 1F3FB × 0308 ÷ 0020 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] SPACE (Other) ÷ [0.3] +÷ 1F3FB ÷ 000D ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +÷ 1F3FB × 0308 ÷ 000D ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +÷ 1F3FB ÷ 000A ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3] +÷ 1F3FB × 0308 ÷ 000A ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3] +÷ 1F3FB ÷ 0001 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3] +÷ 1F3FB × 0308 ÷ 0001 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3] +÷ 1F3FB × 0300 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3] +÷ 1F3FB × 0308 × 0300 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [9.0] COMBINING DIAERESIS (Extend) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3] +÷ 1F3FB ÷ 0600 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ 1F3FB × 0308 ÷ 0600 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ 1F3FB × 0903 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 1F3FB × 0308 × 0903 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [9.0] COMBINING DIAERESIS (Extend) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 1F3FB ÷ 1100 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 1F3FB × 0308 ÷ 1100 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 1F3FB ÷ 1160 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 1F3FB × 0308 ÷ 1160 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 1F3FB ÷ 11A8 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 1F3FB × 0308 ÷ 11A8 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 1F3FB ÷ AC00 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 1F3FB × 0308 ÷ AC00 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 1F3FB ÷ AC01 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 1F3FB × 0308 ÷ AC01 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 1F3FB ÷ 1F1E6 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 1F3FB × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 1F3FB ÷ 261D ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ 1F3FB × 0308 ÷ 261D ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ 1F3FB ÷ 1F3FB ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ 1F3FB × 0308 ÷ 1F3FB ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ 1F3FB × 200D ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3] +÷ 1F3FB × 0308 × 200D ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [9.0] COMBINING DIAERESIS (Extend) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3] +÷ 1F3FB ÷ 2640 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ 1F3FB × 0308 ÷ 2640 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ 1F3FB ÷ 1F466 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [999.0] BOY (EBG) ÷ [0.3] +÷ 1F3FB × 0308 ÷ 1F466 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] BOY (EBG) ÷ [0.3] +÷ 1F3FB ÷ 0378 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3] +÷ 1F3FB × 0308 ÷ 0378 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3] +÷ 1F3FB ÷ D800 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3] +÷ 1F3FB × 0308 ÷ D800 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3] +÷ 200D ÷ 0020 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) ÷ [999.0] SPACE (Other) ÷ [0.3] +÷ 200D × 0308 ÷ 0020 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] SPACE (Other) ÷ [0.3] +÷ 200D ÷ 000D ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +÷ 200D × 0308 ÷ 000D ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +÷ 200D ÷ 000A ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3] +÷ 200D × 0308 ÷ 000A ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3] +÷ 200D ÷ 0001 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3] +÷ 200D × 0308 ÷ 0001 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3] +÷ 200D × 0300 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3] +÷ 200D × 0308 × 0300 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [9.0] COMBINING DIAERESIS (Extend) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3] +÷ 200D ÷ 0600 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ 200D × 0308 ÷ 0600 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ 200D × 0903 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 200D × 0308 × 0903 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [9.0] COMBINING DIAERESIS (Extend) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 200D ÷ 1100 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 200D × 0308 ÷ 1100 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 200D ÷ 1160 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 200D × 0308 ÷ 1160 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 200D ÷ 11A8 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 200D × 0308 ÷ 11A8 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 200D ÷ AC00 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 200D × 0308 ÷ AC00 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 200D ÷ AC01 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 200D × 0308 ÷ AC01 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 200D ÷ 1F1E6 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 200D × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 200D ÷ 261D ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ 200D × 0308 ÷ 261D ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ 200D ÷ 1F3FB ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ 200D × 0308 ÷ 1F3FB ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ 200D × 200D ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3] +÷ 200D × 0308 × 200D ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [9.0] COMBINING DIAERESIS (Extend) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3] +÷ 200D × 2640 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [11.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ 200D × 0308 ÷ 2640 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ 200D × 1F466 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [11.0] BOY (EBG) ÷ [0.3] +÷ 200D × 0308 ÷ 1F466 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] BOY (EBG) ÷ [0.3] +÷ 200D ÷ 0378 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3] +÷ 200D × 0308 ÷ 0378 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3] +÷ 200D ÷ D800 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3] +÷ 200D × 0308 ÷ D800 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3] +÷ 2640 ÷ 0020 ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) ÷ [999.0] SPACE (Other) ÷ [0.3] +÷ 2640 × 0308 ÷ 0020 ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] SPACE (Other) ÷ [0.3] +÷ 2640 ÷ 000D ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +÷ 2640 × 0308 ÷ 000D ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +÷ 2640 ÷ 000A ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3] +÷ 2640 × 0308 ÷ 000A ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3] +÷ 2640 ÷ 0001 ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3] +÷ 2640 × 0308 ÷ 0001 ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3] +÷ 2640 × 0300 ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3] +÷ 2640 × 0308 × 0300 ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) × [9.0] COMBINING DIAERESIS (Extend) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3] +÷ 2640 ÷ 0600 ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ 2640 × 0308 ÷ 0600 ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ 2640 × 0903 ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 2640 × 0308 × 0903 ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) × [9.0] COMBINING DIAERESIS (Extend) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 2640 ÷ 1100 ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 2640 × 0308 ÷ 1100 ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 2640 ÷ 1160 ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 2640 × 0308 ÷ 1160 ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 2640 ÷ 11A8 ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 2640 × 0308 ÷ 11A8 ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 2640 ÷ AC00 ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 2640 × 0308 ÷ AC00 ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 2640 ÷ AC01 ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 2640 × 0308 ÷ AC01 ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 2640 ÷ 1F1E6 ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 2640 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 2640 ÷ 261D ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ 2640 × 0308 ÷ 261D ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ 2640 ÷ 1F3FB ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ 2640 × 0308 ÷ 1F3FB ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ 2640 × 200D ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3] +÷ 2640 × 0308 × 200D ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) × [9.0] COMBINING DIAERESIS (Extend) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3] +÷ 2640 ÷ 2640 ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ 2640 × 0308 ÷ 2640 ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ 2640 ÷ 1F466 ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) ÷ [999.0] BOY (EBG) ÷ [0.3] +÷ 2640 × 0308 ÷ 1F466 ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] BOY (EBG) ÷ [0.3] +÷ 2640 ÷ 0378 ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3] +÷ 2640 × 0308 ÷ 0378 ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3] +÷ 2640 ÷ D800 ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3] +÷ 2640 × 0308 ÷ D800 ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3] +÷ 1F466 ÷ 0020 ÷ # ÷ [0.2] BOY (EBG) ÷ [999.0] SPACE (Other) ÷ [0.3] +÷ 1F466 × 0308 ÷ 0020 ÷ # ÷ [0.2] BOY (EBG) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] SPACE (Other) ÷ [0.3] +÷ 1F466 ÷ 000D ÷ # ÷ [0.2] BOY (EBG) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +÷ 1F466 × 0308 ÷ 000D ÷ # ÷ [0.2] BOY (EBG) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +÷ 1F466 ÷ 000A ÷ # ÷ [0.2] BOY (EBG) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3] +÷ 1F466 × 0308 ÷ 000A ÷ # ÷ [0.2] BOY (EBG) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3] +÷ 1F466 ÷ 0001 ÷ # ÷ [0.2] BOY (EBG) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3] +÷ 1F466 × 0308 ÷ 0001 ÷ # ÷ [0.2] BOY (EBG) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3] +÷ 1F466 × 0300 ÷ # ÷ [0.2] BOY (EBG) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3] +÷ 1F466 × 0308 × 0300 ÷ # ÷ [0.2] BOY (EBG) × [9.0] COMBINING DIAERESIS (Extend) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3] +÷ 1F466 ÷ 0600 ÷ # ÷ [0.2] BOY (EBG) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ 1F466 × 0308 ÷ 0600 ÷ # ÷ [0.2] BOY (EBG) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ 1F466 × 0903 ÷ # ÷ [0.2] BOY (EBG) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 1F466 × 0308 × 0903 ÷ # ÷ [0.2] BOY (EBG) × [9.0] COMBINING DIAERESIS (Extend) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] +÷ 1F466 ÷ 1100 ÷ # ÷ [0.2] BOY (EBG) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 1F466 × 0308 ÷ 1100 ÷ # ÷ [0.2] BOY (EBG) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 1F466 ÷ 1160 ÷ # ÷ [0.2] BOY (EBG) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 1F466 × 0308 ÷ 1160 ÷ # ÷ [0.2] BOY (EBG) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3] +÷ 1F466 ÷ 11A8 ÷ # ÷ [0.2] BOY (EBG) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 1F466 × 0308 ÷ 11A8 ÷ # ÷ [0.2] BOY (EBG) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3] +÷ 1F466 ÷ AC00 ÷ # ÷ [0.2] BOY (EBG) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 1F466 × 0308 ÷ AC00 ÷ # ÷ [0.2] BOY (EBG) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] +÷ 1F466 ÷ AC01 ÷ # ÷ [0.2] BOY (EBG) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 1F466 × 0308 ÷ AC01 ÷ # ÷ [0.2] BOY (EBG) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] +÷ 1F466 ÷ 1F1E6 ÷ # ÷ [0.2] BOY (EBG) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 1F466 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] BOY (EBG) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 1F466 ÷ 261D ÷ # ÷ [0.2] BOY (EBG) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ 1F466 × 0308 ÷ 261D ÷ # ÷ [0.2] BOY (EBG) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ 1F466 × 1F3FB ÷ # ÷ [0.2] BOY (EBG) × [10.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ 1F466 × 0308 × 1F3FB ÷ # ÷ [0.2] BOY (EBG) × [9.0] COMBINING DIAERESIS (Extend) × [10.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ 1F466 × 200D ÷ # ÷ [0.2] BOY (EBG) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3] +÷ 1F466 × 0308 × 200D ÷ # ÷ [0.2] BOY (EBG) × [9.0] COMBINING DIAERESIS (Extend) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3] +÷ 1F466 ÷ 2640 ÷ # ÷ [0.2] BOY (EBG) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ 1F466 × 0308 ÷ 2640 ÷ # ÷ [0.2] BOY (EBG) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ 1F466 ÷ 1F466 ÷ # ÷ [0.2] BOY (EBG) ÷ [999.0] BOY (EBG) ÷ [0.3] +÷ 1F466 × 0308 ÷ 1F466 ÷ # ÷ [0.2] BOY (EBG) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] BOY (EBG) ÷ [0.3] +÷ 1F466 ÷ 0378 ÷ # ÷ [0.2] BOY (EBG) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3] +÷ 1F466 × 0308 ÷ 0378 ÷ # ÷ [0.2] BOY (EBG) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3] +÷ 1F466 ÷ D800 ÷ # ÷ [0.2] BOY (EBG) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3] +÷ 1F466 × 0308 ÷ D800 ÷ # ÷ [0.2] BOY (EBG) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3] ÷ 0378 ÷ 0020 ÷ # ÷ [0.2] <reserved-0378> (Other) ÷ [999.0] SPACE (Other) ÷ [0.3] ÷ 0378 × 0308 ÷ 0020 ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] SPACE (Other) ÷ [0.3] ÷ 0378 ÷ 000D ÷ # ÷ [0.2] <reserved-0378> (Other) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] @@ -366,6 +752,8 @@ ÷ 0378 × 0308 ÷ 0001 ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3] ÷ 0378 × 0300 ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3] ÷ 0378 × 0308 × 0300 ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] COMBINING DIAERESIS (Extend) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3] +÷ 0378 ÷ 0600 ÷ # ÷ [0.2] <reserved-0378> (Other) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ 0378 × 0308 ÷ 0600 ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] ÷ 0378 × 0903 ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] ÷ 0378 × 0308 × 0903 ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] COMBINING DIAERESIS (Extend) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] ÷ 0378 ÷ 1100 ÷ # ÷ [0.2] <reserved-0378> (Other) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] @@ -378,8 +766,18 @@ ÷ 0378 × 0308 ÷ AC00 ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] ÷ 0378 ÷ AC01 ÷ # ÷ [0.2] <reserved-0378> (Other) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] ÷ 0378 × 0308 ÷ AC01 ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ 0378 ÷ 1F1E6 ÷ # ÷ [0.2] <reserved-0378> (Other) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [0.3] -÷ 0378 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [0.3] +÷ 0378 ÷ 1F1E6 ÷ # ÷ [0.2] <reserved-0378> (Other) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0378 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0378 ÷ 261D ÷ # ÷ [0.2] <reserved-0378> (Other) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ 0378 × 0308 ÷ 261D ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ 0378 ÷ 1F3FB ÷ # ÷ [0.2] <reserved-0378> (Other) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ 0378 × 0308 ÷ 1F3FB ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ 0378 × 200D ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3] +÷ 0378 × 0308 × 200D ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] COMBINING DIAERESIS (Extend) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3] +÷ 0378 ÷ 2640 ÷ # ÷ [0.2] <reserved-0378> (Other) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ 0378 × 0308 ÷ 2640 ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ 0378 ÷ 1F466 ÷ # ÷ [0.2] <reserved-0378> (Other) ÷ [999.0] BOY (EBG) ÷ [0.3] +÷ 0378 × 0308 ÷ 1F466 ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] BOY (EBG) ÷ [0.3] ÷ 0378 ÷ 0378 ÷ # ÷ [0.2] <reserved-0378> (Other) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3] ÷ 0378 × 0308 ÷ 0378 ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3] ÷ 0378 ÷ D800 ÷ # ÷ [0.2] <reserved-0378> (Other) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3] @@ -394,6 +792,8 @@ ÷ D800 ÷ 0308 ÷ 0001 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3] ÷ D800 ÷ 0300 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3] ÷ D800 ÷ 0308 × 0300 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3] +÷ D800 ÷ 0600 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] +÷ D800 ÷ 0308 ÷ 0600 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3] ÷ D800 ÷ 0903 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] ÷ D800 ÷ 0308 × 0903 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3] ÷ D800 ÷ 1100 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] @@ -406,23 +806,45 @@ ÷ D800 ÷ 0308 ÷ AC00 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3] ÷ D800 ÷ AC01 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] ÷ D800 ÷ 0308 ÷ AC01 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3] -÷ D800 ÷ 1F1E6 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [0.3] -÷ D800 ÷ 0308 ÷ 1F1E6 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [0.3] +÷ D800 ÷ 1F1E6 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ D800 ÷ 0308 ÷ 1F1E6 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ D800 ÷ 261D ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ D800 ÷ 0308 ÷ 261D ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ D800 ÷ 1F3FB ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ D800 ÷ 0308 ÷ 1F3FB ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ D800 ÷ 200D ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3] +÷ D800 ÷ 0308 × 200D ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3] +÷ D800 ÷ 2640 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ D800 ÷ 0308 ÷ 2640 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ D800 ÷ 1F466 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] BOY (EBG) ÷ [0.3] +÷ D800 ÷ 0308 ÷ 1F466 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] BOY (EBG) ÷ [0.3] ÷ D800 ÷ 0378 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] <reserved-0378> (Other) ÷ [0.3] ÷ D800 ÷ 0308 ÷ 0378 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3] ÷ D800 ÷ D800 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] <surrogate-D800> (Control) ÷ [0.3] ÷ D800 ÷ 0308 ÷ D800 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3] -÷ 0061 ÷ 1F1E6 ÷ 0062 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [999.0] LATIN SMALL LETTER B (Other) ÷ [0.3] -÷ 1F1F7 × 1F1FA ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER R (Regional_Indicator) × [8.1] REGIONAL INDICATOR SYMBOL LETTER U (Regional_Indicator) ÷ [0.3] -÷ 1F1F7 × 1F1FA × 1F1F8 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER R (Regional_Indicator) × [8.1] REGIONAL INDICATOR SYMBOL LETTER U (Regional_Indicator) × [8.1] REGIONAL INDICATOR SYMBOL LETTER S (Regional_Indicator) ÷ [0.3] -÷ 1F1F7 × 1F1FA × 1F1F8 × 1F1EA ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER R (Regional_Indicator) × [8.1] REGIONAL INDICATOR SYMBOL LETTER U (Regional_Indicator) × [8.1] REGIONAL INDICATOR SYMBOL LETTER S (Regional_Indicator) × [8.1] REGIONAL INDICATOR SYMBOL LETTER E (Regional_Indicator) ÷ [0.3] -÷ 1F1F7 × 1F1FA ÷ 200B ÷ 1F1F8 × 1F1EA ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER R (Regional_Indicator) × [8.1] REGIONAL INDICATOR SYMBOL LETTER U (Regional_Indicator) ÷ [5.0] ZERO WIDTH SPACE (Control) ÷ [4.0] REGIONAL INDICATOR SYMBOL LETTER S (Regional_Indicator) × [8.1] REGIONAL INDICATOR SYMBOL LETTER E (Regional_Indicator) ÷ [0.3] -÷ 1F1E6 × 1F1E7 × 1F1E8 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) × [8.1] REGIONAL INDICATOR SYMBOL LETTER B (Regional_Indicator) × [8.1] REGIONAL INDICATOR SYMBOL LETTER C (Regional_Indicator) ÷ [0.3] -÷ 1F1E6 × 200D ÷ 1F1E7 × 1F1E8 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) × [9.0] ZERO WIDTH JOINER (Extend) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER B (Regional_Indicator) × [8.1] REGIONAL INDICATOR SYMBOL LETTER C (Regional_Indicator) ÷ [0.3] -÷ 1F1E6 × 1F1E7 × 200D ÷ 1F1E8 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) × [8.1] REGIONAL INDICATOR SYMBOL LETTER B (Regional_Indicator) × [9.0] ZERO WIDTH JOINER (Extend) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER C (Regional_Indicator) ÷ [0.3] -÷ 0020 × 200D ÷ 0646 ÷ # ÷ [0.2] SPACE (Other) × [9.0] ZERO WIDTH JOINER (Extend) ÷ [999.0] ARABIC LETTER NOON (Other) ÷ [0.3] -÷ 0646 × 200D ÷ 0020 ÷ # ÷ [0.2] ARABIC LETTER NOON (Other) × [9.0] ZERO WIDTH JOINER (Extend) ÷ [999.0] SPACE (Other) ÷ [0.3] +÷ 000D × 000A ÷ 0061 ÷ 000A ÷ 0308 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) × [3.0] <LINE FEED (LF)> (LF) ÷ [4.0] LATIN SMALL LETTER A (Other) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [0.3] +÷ 0061 × 0308 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) × [9.0] COMBINING DIAERESIS (Extend) ÷ [0.3] +÷ 0020 × 200D ÷ 0646 ÷ # ÷ [0.2] SPACE (Other) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [999.0] ARABIC LETTER NOON (Other) ÷ [0.3] +÷ 0646 × 200D ÷ 0020 ÷ # ÷ [0.2] ARABIC LETTER NOON (Other) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [999.0] SPACE (Other) ÷ [0.3] +÷ 1100 × 1100 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [6.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ AC00 × 11A8 ÷ 1100 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [7.0] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ AC01 × 11A8 ÷ 1100 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [8.0] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3] +÷ 1F1E6 × 1F1E7 ÷ 1F1E8 ÷ 0062 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [12.0] REGIONAL INDICATOR SYMBOL LETTER B (RI) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER C (RI) ÷ [999.0] LATIN SMALL LETTER B (Other) ÷ [0.3] +÷ 0061 ÷ 1F1E6 × 1F1E7 ÷ 1F1E8 ÷ 0062 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [13.0] REGIONAL INDICATOR SYMBOL LETTER B (RI) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER C (RI) ÷ [999.0] LATIN SMALL LETTER B (Other) ÷ [0.3] +÷ 0061 ÷ 1F1E6 × 1F1E7 × 200D ÷ 1F1E8 ÷ 0062 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [13.0] REGIONAL INDICATOR SYMBOL LETTER B (RI) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER C (RI) ÷ [999.0] LATIN SMALL LETTER B (Other) ÷ [0.3] +÷ 0061 ÷ 1F1E6 × 200D ÷ 1F1E7 × 1F1E8 ÷ 0062 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER B (RI) × [13.0] REGIONAL INDICATOR SYMBOL LETTER C (RI) ÷ [999.0] LATIN SMALL LETTER B (Other) ÷ [0.3] +÷ 0061 ÷ 1F1E6 × 1F1E7 ÷ 1F1E8 × 1F1E9 ÷ 0062 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [13.0] REGIONAL INDICATOR SYMBOL LETTER B (RI) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER C (RI) × [13.0] REGIONAL INDICATOR SYMBOL LETTER D (RI) ÷ [999.0] LATIN SMALL LETTER B (Other) ÷ [0.3] +÷ 0061 × 200D ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3] +÷ 0061 × 0308 ÷ 0062 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] LATIN SMALL LETTER B (Other) ÷ [0.3] +÷ 0061 × 0903 ÷ 0062 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [999.0] LATIN SMALL LETTER B (Other) ÷ [0.3] +÷ 0061 ÷ 0600 × 0062 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) × [9.2] LATIN SMALL LETTER B (Other) ÷ [0.3] +÷ 261D × 1F3FB ÷ 261D ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [10.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ 1F466 × 1F3FB ÷ # ÷ [0.2] BOY (EBG) × [10.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ 200D × 1F466 × 1F3FB ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [11.0] BOY (EBG) × [10.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ 200D × 2640 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [11.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ 200D × 1F466 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [11.0] BOY (EBG) ÷ [0.3] +÷ 1F466 ÷ 1F466 ÷ # ÷ [0.2] BOY (EBG) ÷ [999.0] BOY (EBG) ÷ [0.3] # -# Lines: 402 +# Lines: 822 # # EOF diff --git a/tests/data/HangulSyllableType.txt b/tests/data/HangulSyllableType.txt index f15f592699..9c990d7aba 100644 --- a/tests/data/HangulSyllableType.txt +++ b/tests/data/HangulSyllableType.txt @@ -1,10 +1,11 @@ -# HangulSyllableType-7.0.0.txt -# Date: 2013-11-27, 09:54:39 GMT [MD] +# HangulSyllableType-10.0.0.txt +# Date: 2017-02-14, 04:26:11 GMT +# © 2017 Unicode®, Inc. +# Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries. +# For terms of use, see http://www.unicode.org/terms_of_use.html # # Unicode Character Database -# Copyright (c) 1991-2013 Unicode, Inc. -# For terms of use, see http://www.unicode.org/terms_of_use.html -# For documentation, see http://www.unicode.org/reports/tr44/ +# For documentation, see http://www.unicode.org/reports/tr44/ # ================================================ diff --git a/tests/data/LineBreakTest.txt b/tests/data/LineBreakTest.txt index 7f2e2cc54f..6715446aba 100644 --- a/tests/data/LineBreakTest.txt +++ b/tests/data/LineBreakTest.txt @@ -1,6111 +1,7121 @@ -# LineBreakTest-8.0.0.txt -# Date: 2015-04-30, 09:40:15 GMT [MD] +# LineBreakTest-10.0.0.txt +# Date: 2017-04-14, 05:40:30 GMT +# © 2017 Unicode®, Inc. +# Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries. +# For terms of use, see http://www.unicode.org/terms_of_use.html # # Unicode Character Database -# Copyright (c) 1991-2015 Unicode, Inc. -# For terms of use, see http://www.unicode.org/terms_of_use.html -# For documentation, see http://www.unicode.org/reports/tr44/ +# For documentation, see http://www.unicode.org/reports/tr44/ # -# Default Line Break Test +# Default Line_Break Test # # Format: -# <string> (# <comment>)? -# <string> contains hex Unicode code points, with -# ÷ wherever there is a break opportunity, and +# <string> (# <comment>)? +# <string> contains hex Unicode code points, with +# ÷ wherever there is a break opportunity, and # × wherever there is not. # <comment> the format can change, but currently it shows: # - the sample character name # - (x) the Line_Break property value for the sample character -# - [x] the rule that determines whether there is a break or not -# Note: The Line Break tests use tailoring of numbers described in Example 7 of Section 8.2 Examples of Customization. -# They also differ from the results produced by a pair table implementation in sequences like: ZW SP CL. +# - [x] the rule that determines whether there is a break or not, +# as listed in the Rules section of LineBreakTest.html +# +# Note: +# The Line_Break tests use tailoring of numbers described in +# Example 7 of Section 8.2, "Examples of Customization" of UAX #14. # # These samples may be extended or changed in the future. # × 0023 × 0023 ÷ # × [0.3] NUMBER SIGN (AL) × [28.0] NUMBER SIGN (AL) ÷ [0.3] × 0023 × 0020 ÷ 0023 ÷ # × [0.3] NUMBER SIGN (AL) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] -× 0023 × 0308 × 0023 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM) × [28.0] NUMBER SIGN (AL) ÷ [0.3] -× 0023 × 0308 × 0020 ÷ 0023 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] +× 0023 × 0308 × 0023 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [28.0] NUMBER SIGN (AL) ÷ [0.3] +× 0023 × 0308 × 0020 ÷ 0023 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] × 0023 ÷ 2014 ÷ # × [0.3] NUMBER SIGN (AL) ÷ [999.0] EM DASH (B2) ÷ [0.3] × 0023 × 0020 ÷ 2014 ÷ # × [0.3] NUMBER SIGN (AL) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] -× 0023 × 0308 ÷ 2014 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] EM DASH (B2) ÷ [0.3] -× 0023 × 0308 × 0020 ÷ 2014 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] +× 0023 × 0308 ÷ 2014 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] EM DASH (B2) ÷ [0.3] +× 0023 × 0308 × 0020 ÷ 2014 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] × 0023 × 0009 ÷ # × [0.3] NUMBER SIGN (AL) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] × 0023 × 0020 ÷ 0009 ÷ # × [0.3] NUMBER SIGN (AL) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] -× 0023 × 0308 × 0009 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] -× 0023 × 0308 × 0020 ÷ 0009 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] +× 0023 × 0308 × 0009 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] +× 0023 × 0308 × 0020 ÷ 0009 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] × 0023 ÷ 00B4 ÷ # × [0.3] NUMBER SIGN (AL) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3] × 0023 × 0020 ÷ 00B4 ÷ # × [0.3] NUMBER SIGN (AL) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] -× 0023 × 0308 ÷ 00B4 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3] -× 0023 × 0308 × 0020 ÷ 00B4 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] +× 0023 × 0308 ÷ 00B4 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3] +× 0023 × 0308 × 0020 ÷ 00B4 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] × 0023 × 000B ÷ # × [0.3] NUMBER SIGN (AL) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] × 0023 × 0020 × 000B ÷ # × [0.3] NUMBER SIGN (AL) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] -× 0023 × 0308 × 000B ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] -× 0023 × 0308 × 0020 × 000B ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] +× 0023 × 0308 × 000B ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] +× 0023 × 0308 × 0020 × 000B ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] × 0023 ÷ FFFC ÷ # × [0.3] NUMBER SIGN (AL) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] × 0023 × 0020 ÷ FFFC ÷ # × [0.3] NUMBER SIGN (AL) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] -× 0023 × 0308 ÷ FFFC ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] -× 0023 × 0308 × 0020 ÷ FFFC ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] +× 0023 × 0308 ÷ FFFC ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] +× 0023 × 0308 × 0020 ÷ FFFC ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] × 0023 × 007D ÷ # × [0.3] NUMBER SIGN (AL) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] × 0023 × 0020 × 007D ÷ # × [0.3] NUMBER SIGN (AL) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] -× 0023 × 0308 × 007D ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM) × [13.03] RIGHT CURLY BRACKET (CL) ÷ [0.3] -× 0023 × 0308 × 0020 × 007D ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] +× 0023 × 0308 × 007D ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] RIGHT CURLY BRACKET (CL) ÷ [0.3] +× 0023 × 0308 × 0020 × 007D ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] × 0023 × 0029 ÷ # × [0.3] NUMBER SIGN (AL) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] × 0023 × 0020 × 0029 ÷ # × [0.3] NUMBER SIGN (AL) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 0023 × 0308 × 0029 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM) × [13.03] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 0023 × 0308 × 0020 × 0029 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 0023 × 0001 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] <START OF HEADING> (CM) ÷ [0.3] -× 0023 × 0020 ÷ 0001 ÷ # × [0.3] NUMBER SIGN (AL) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM) ÷ [0.3] -× 0023 × 0308 × 0001 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM) × [9.0] <START OF HEADING> (CM) ÷ [0.3] -× 0023 × 0308 × 0020 ÷ 0001 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM) ÷ [0.3] +× 0023 × 0308 × 0029 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] RIGHT PARENTHESIS (CP) ÷ [0.3] +× 0023 × 0308 × 0020 × 0029 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] × 0023 × 000D ÷ # × [0.3] NUMBER SIGN (AL) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] × 0023 × 0020 × 000D ÷ # × [0.3] NUMBER SIGN (AL) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -× 0023 × 0308 × 000D ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -× 0023 × 0308 × 0020 × 000D ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +× 0023 × 0308 × 000D ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +× 0023 × 0308 × 0020 × 000D ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] × 0023 × 0021 ÷ # × [0.3] NUMBER SIGN (AL) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] × 0023 × 0020 × 0021 ÷ # × [0.3] NUMBER SIGN (AL) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] -× 0023 × 0308 × 0021 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] -× 0023 × 0308 × 0020 × 0021 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] +× 0023 × 0308 × 0021 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] +× 0023 × 0308 × 0020 × 0021 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] × 0023 × 00A0 ÷ # × [0.3] NUMBER SIGN (AL) × [12.1] NO-BREAK SPACE (GL) ÷ [0.3] × 0023 × 0020 ÷ 00A0 ÷ # × [0.3] NUMBER SIGN (AL) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] -× 0023 × 0308 × 00A0 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM) × [12.2] NO-BREAK SPACE (GL) ÷ [0.3] -× 0023 × 0308 × 0020 ÷ 00A0 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] +× 0023 × 0308 × 00A0 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [12.2] NO-BREAK SPACE (GL) ÷ [0.3] +× 0023 × 0308 × 0020 ÷ 00A0 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] × 0023 ÷ AC00 ÷ # × [0.3] NUMBER SIGN (AL) ÷ [999.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] × 0023 × 0020 ÷ AC00 ÷ # × [0.3] NUMBER SIGN (AL) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] -× 0023 × 0308 ÷ AC00 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] -× 0023 × 0308 × 0020 ÷ AC00 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] +× 0023 × 0308 ÷ AC00 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] +× 0023 × 0308 × 0020 ÷ AC00 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] × 0023 ÷ AC01 ÷ # × [0.3] NUMBER SIGN (AL) ÷ [999.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] × 0023 × 0020 ÷ AC01 ÷ # × [0.3] NUMBER SIGN (AL) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] -× 0023 × 0308 ÷ AC01 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] -× 0023 × 0308 × 0020 ÷ AC01 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] +× 0023 × 0308 ÷ AC01 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] +× 0023 × 0308 × 0020 ÷ AC01 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] × 0023 × 05D0 ÷ # × [0.3] NUMBER SIGN (AL) × [28.0] HEBREW LETTER ALEF (HL) ÷ [0.3] × 0023 × 0020 ÷ 05D0 ÷ # × [0.3] NUMBER SIGN (AL) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] -× 0023 × 0308 × 05D0 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM) × [28.0] HEBREW LETTER ALEF (HL) ÷ [0.3] -× 0023 × 0308 × 0020 ÷ 05D0 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] +× 0023 × 0308 × 05D0 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [28.0] HEBREW LETTER ALEF (HL) ÷ [0.3] +× 0023 × 0308 × 0020 ÷ 05D0 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] × 0023 × 002D ÷ # × [0.3] NUMBER SIGN (AL) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] × 0023 × 0020 ÷ 002D ÷ # × [0.3] NUMBER SIGN (AL) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] -× 0023 × 0308 × 002D ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] -× 0023 × 0308 × 0020 ÷ 002D ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] +× 0023 × 0308 × 002D ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] +× 0023 × 0308 × 0020 ÷ 002D ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] × 0023 ÷ 231A ÷ # × [0.3] NUMBER SIGN (AL) ÷ [999.0] WATCH (ID) ÷ [0.3] × 0023 × 0020 ÷ 231A ÷ # × [0.3] NUMBER SIGN (AL) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] -× 0023 × 0308 ÷ 231A ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] WATCH (ID) ÷ [0.3] -× 0023 × 0308 × 0020 ÷ 231A ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] +× 0023 × 0308 ÷ 231A ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] WATCH (ID) ÷ [0.3] +× 0023 × 0308 × 0020 ÷ 231A ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] × 0023 × 2024 ÷ # × [0.3] NUMBER SIGN (AL) × [22.01] ONE DOT LEADER (IN) ÷ [0.3] × 0023 × 0020 ÷ 2024 ÷ # × [0.3] NUMBER SIGN (AL) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] -× 0023 × 0308 × 2024 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM) × [22.01] ONE DOT LEADER (IN) ÷ [0.3] -× 0023 × 0308 × 0020 ÷ 2024 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] +× 0023 × 0308 × 2024 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [22.01] ONE DOT LEADER (IN) ÷ [0.3] +× 0023 × 0308 × 0020 ÷ 2024 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] × 0023 × 002C ÷ # × [0.3] NUMBER SIGN (AL) × [13.02] COMMA (IS) ÷ [0.3] × 0023 × 0020 × 002C ÷ # × [0.3] NUMBER SIGN (AL) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] -× 0023 × 0308 × 002C ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM) × [13.03] COMMA (IS) ÷ [0.3] -× 0023 × 0308 × 0020 × 002C ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] +× 0023 × 0308 × 002C ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] COMMA (IS) ÷ [0.3] +× 0023 × 0308 × 0020 × 002C ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] × 0023 ÷ 1100 ÷ # × [0.3] NUMBER SIGN (AL) ÷ [999.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] × 0023 × 0020 ÷ 1100 ÷ # × [0.3] NUMBER SIGN (AL) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] -× 0023 × 0308 ÷ 1100 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] -× 0023 × 0308 × 0020 ÷ 1100 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] +× 0023 × 0308 ÷ 1100 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] +× 0023 × 0308 × 0020 ÷ 1100 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] × 0023 ÷ 11A8 ÷ # × [0.3] NUMBER SIGN (AL) ÷ [999.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] × 0023 × 0020 ÷ 11A8 ÷ # × [0.3] NUMBER SIGN (AL) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] -× 0023 × 0308 ÷ 11A8 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] -× 0023 × 0308 × 0020 ÷ 11A8 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] +× 0023 × 0308 ÷ 11A8 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] +× 0023 × 0308 × 0020 ÷ 11A8 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] × 0023 ÷ 1160 ÷ # × [0.3] NUMBER SIGN (AL) ÷ [999.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] × 0023 × 0020 ÷ 1160 ÷ # × [0.3] NUMBER SIGN (AL) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] -× 0023 × 0308 ÷ 1160 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] -× 0023 × 0308 × 0020 ÷ 1160 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] +× 0023 × 0308 ÷ 1160 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] +× 0023 × 0308 × 0020 ÷ 1160 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] × 0023 × 000A ÷ # × [0.3] NUMBER SIGN (AL) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] × 0023 × 0020 × 000A ÷ # × [0.3] NUMBER SIGN (AL) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] -× 0023 × 0308 × 000A ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] -× 0023 × 0308 × 0020 × 000A ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] +× 0023 × 0308 × 000A ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] +× 0023 × 0308 × 0020 × 000A ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] × 0023 × 0085 ÷ # × [0.3] NUMBER SIGN (AL) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] × 0023 × 0020 × 0085 ÷ # × [0.3] NUMBER SIGN (AL) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] -× 0023 × 0308 × 0085 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] -× 0023 × 0308 × 0020 × 0085 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] +× 0023 × 0308 × 0085 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] +× 0023 × 0308 × 0020 × 0085 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] × 0023 × 17D6 ÷ # × [0.3] NUMBER SIGN (AL) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] × 0023 × 0020 ÷ 17D6 ÷ # × [0.3] NUMBER SIGN (AL) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] -× 0023 × 0308 × 17D6 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] -× 0023 × 0308 × 0020 ÷ 17D6 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] +× 0023 × 0308 × 17D6 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] +× 0023 × 0308 × 0020 ÷ 17D6 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] × 0023 × 0030 ÷ # × [0.3] NUMBER SIGN (AL) × [23.02] DIGIT ZERO (NU) ÷ [0.3] × 0023 × 0020 ÷ 0030 ÷ # × [0.3] NUMBER SIGN (AL) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] -× 0023 × 0308 × 0030 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM) × [23.02] DIGIT ZERO (NU) ÷ [0.3] -× 0023 × 0308 × 0020 ÷ 0030 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] +× 0023 × 0308 × 0030 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [23.02] DIGIT ZERO (NU) ÷ [0.3] +× 0023 × 0308 × 0020 ÷ 0030 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] × 0023 × 0028 ÷ # × [0.3] NUMBER SIGN (AL) × [30.01] LEFT PARENTHESIS (OP) ÷ [0.3] × 0023 × 0020 ÷ 0028 ÷ # × [0.3] NUMBER SIGN (AL) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] -× 0023 × 0308 × 0028 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM) × [30.01] LEFT PARENTHESIS (OP) ÷ [0.3] -× 0023 × 0308 × 0020 ÷ 0028 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] -× 0023 ÷ 0025 ÷ # × [0.3] NUMBER SIGN (AL) ÷ [999.0] PERCENT SIGN (PO) ÷ [0.3] +× 0023 × 0308 × 0028 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [30.01] LEFT PARENTHESIS (OP) ÷ [0.3] +× 0023 × 0308 × 0020 ÷ 0028 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] +× 0023 × 0025 ÷ # × [0.3] NUMBER SIGN (AL) × [24.03] PERCENT SIGN (PO) ÷ [0.3] × 0023 × 0020 ÷ 0025 ÷ # × [0.3] NUMBER SIGN (AL) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] -× 0023 × 0308 ÷ 0025 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] PERCENT SIGN (PO) ÷ [0.3] -× 0023 × 0308 × 0020 ÷ 0025 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] -× 0023 ÷ 0024 ÷ # × [0.3] NUMBER SIGN (AL) ÷ [999.0] DOLLAR SIGN (PR) ÷ [0.3] +× 0023 × 0308 × 0025 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [24.03] PERCENT SIGN (PO) ÷ [0.3] +× 0023 × 0308 × 0020 ÷ 0025 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] +× 0023 × 0024 ÷ # × [0.3] NUMBER SIGN (AL) × [24.03] DOLLAR SIGN (PR) ÷ [0.3] × 0023 × 0020 ÷ 0024 ÷ # × [0.3] NUMBER SIGN (AL) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] -× 0023 × 0308 ÷ 0024 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] DOLLAR SIGN (PR) ÷ [0.3] -× 0023 × 0308 × 0020 ÷ 0024 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] +× 0023 × 0308 × 0024 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [24.03] DOLLAR SIGN (PR) ÷ [0.3] +× 0023 × 0308 × 0020 ÷ 0024 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] × 0023 × 0022 ÷ # × [0.3] NUMBER SIGN (AL) × [19.01] QUOTATION MARK (QU) ÷ [0.3] × 0023 × 0020 ÷ 0022 ÷ # × [0.3] NUMBER SIGN (AL) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] -× 0023 × 0308 × 0022 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM) × [19.01] QUOTATION MARK (QU) ÷ [0.3] -× 0023 × 0308 × 0020 ÷ 0022 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] +× 0023 × 0308 × 0022 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [19.01] QUOTATION MARK (QU) ÷ [0.3] +× 0023 × 0308 × 0020 ÷ 0022 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] × 0023 × 0020 ÷ # × [0.3] NUMBER SIGN (AL) × [7.01] SPACE (SP) ÷ [0.3] × 0023 × 0020 × 0020 ÷ # × [0.3] NUMBER SIGN (AL) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] -× 0023 × 0308 × 0020 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [0.3] -× 0023 × 0308 × 0020 × 0020 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] +× 0023 × 0308 × 0020 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [0.3] +× 0023 × 0308 × 0020 × 0020 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] × 0023 × 002F ÷ # × [0.3] NUMBER SIGN (AL) × [13.02] SOLIDUS (SY) ÷ [0.3] × 0023 × 0020 × 002F ÷ # × [0.3] NUMBER SIGN (AL) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] -× 0023 × 0308 × 002F ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM) × [13.03] SOLIDUS (SY) ÷ [0.3] -× 0023 × 0308 × 0020 × 002F ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] +× 0023 × 0308 × 002F ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] SOLIDUS (SY) ÷ [0.3] +× 0023 × 0308 × 0020 × 002F ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] × 0023 × 2060 ÷ # × [0.3] NUMBER SIGN (AL) × [11.01] WORD JOINER (WJ) ÷ [0.3] × 0023 × 0020 × 2060 ÷ # × [0.3] NUMBER SIGN (AL) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] -× 0023 × 0308 × 2060 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM) × [11.01] WORD JOINER (WJ) ÷ [0.3] -× 0023 × 0308 × 0020 × 2060 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] +× 0023 × 0308 × 2060 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [11.01] WORD JOINER (WJ) ÷ [0.3] +× 0023 × 0308 × 0020 × 2060 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] × 0023 × 200B ÷ # × [0.3] NUMBER SIGN (AL) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] × 0023 × 0020 × 200B ÷ # × [0.3] NUMBER SIGN (AL) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] -× 0023 × 0308 × 200B ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] -× 0023 × 0308 × 0020 × 200B ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] +× 0023 × 0308 × 200B ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] +× 0023 × 0308 × 0020 × 200B ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] × 0023 ÷ 1F1E6 ÷ # × [0.3] NUMBER SIGN (AL) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] × 0023 × 0020 ÷ 1F1E6 ÷ # × [0.3] NUMBER SIGN (AL) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -× 0023 × 0308 ÷ 1F1E6 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -× 0023 × 0308 × 0020 ÷ 1F1E6 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 0023 × 0308 ÷ 1F1E6 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 0023 × 0308 × 0020 ÷ 1F1E6 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 0023 ÷ 261D ÷ # × [0.3] NUMBER SIGN (AL) ÷ [999.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 0023 × 0020 ÷ 261D ÷ # × [0.3] NUMBER SIGN (AL) × [7.01] SPACE (SP) ÷ [18.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 0023 × 0308 ÷ 261D ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 0023 × 0308 × 0020 ÷ 261D ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 0023 ÷ 1F3FB ÷ # × [0.3] NUMBER SIGN (AL) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 0023 × 0020 ÷ 1F3FB ÷ # × [0.3] NUMBER SIGN (AL) × [7.01] SPACE (SP) ÷ [18.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 0023 × 0308 ÷ 1F3FB ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 0023 × 0308 × 0020 ÷ 1F3FB ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 0023 × 0001 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 0023 × 0020 ÷ 0001 ÷ # × [0.3] NUMBER SIGN (AL) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 0023 × 0308 × 0001 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [9.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 0023 × 0308 × 0020 ÷ 0001 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 0023 × 200D ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 0023 × 0020 ÷ 200D ÷ # × [0.3] NUMBER SIGN (AL) × [7.01] SPACE (SP) ÷ [18.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 0023 × 0308 × 200D ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [9.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 0023 × 0308 × 0020 ÷ 200D ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] × 0023 × 00A7 ÷ # × [0.3] NUMBER SIGN (AL) × [28.0] SECTION SIGN (AI_AL) ÷ [0.3] × 0023 × 0020 ÷ 00A7 ÷ # × [0.3] NUMBER SIGN (AL) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] -× 0023 × 0308 × 00A7 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM) × [28.0] SECTION SIGN (AI_AL) ÷ [0.3] -× 0023 × 0308 × 0020 ÷ 00A7 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] +× 0023 × 0308 × 00A7 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [28.0] SECTION SIGN (AI_AL) ÷ [0.3] +× 0023 × 0308 × 0020 ÷ 00A7 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] × 0023 × 50005 ÷ # × [0.3] NUMBER SIGN (AL) × [28.0] <reserved-50005> (XX_AL) ÷ [0.3] × 0023 × 0020 ÷ 50005 ÷ # × [0.3] NUMBER SIGN (AL) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] -× 0023 × 0308 × 50005 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM) × [28.0] <reserved-50005> (XX_AL) ÷ [0.3] -× 0023 × 0308 × 0020 ÷ 50005 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] +× 0023 × 0308 × 50005 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [28.0] <reserved-50005> (XX_AL) ÷ [0.3] +× 0023 × 0308 × 0020 ÷ 50005 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] × 0023 × 0E01 ÷ # × [0.3] NUMBER SIGN (AL) × [28.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] × 0023 × 0020 ÷ 0E01 ÷ # × [0.3] NUMBER SIGN (AL) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] -× 0023 × 0308 × 0E01 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM) × [28.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] -× 0023 × 0308 × 0020 ÷ 0E01 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] +× 0023 × 0308 × 0E01 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [28.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] +× 0023 × 0308 × 0020 ÷ 0E01 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] × 0023 × 3041 ÷ # × [0.3] NUMBER SIGN (AL) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] × 0023 × 0020 ÷ 3041 ÷ # × [0.3] NUMBER SIGN (AL) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] -× 0023 × 0308 × 3041 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] -× 0023 × 0308 × 0020 ÷ 3041 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] +× 0023 × 0308 × 3041 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] +× 0023 × 0308 × 0020 ÷ 3041 ÷ # × [0.3] NUMBER SIGN (AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] × 2014 ÷ 0023 ÷ # × [0.3] EM DASH (B2) ÷ [999.0] NUMBER SIGN (AL) ÷ [0.3] × 2014 × 0020 ÷ 0023 ÷ # × [0.3] EM DASH (B2) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] -× 2014 × 0308 ÷ 0023 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] NUMBER SIGN (AL) ÷ [0.3] -× 2014 × 0308 × 0020 ÷ 0023 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] +× 2014 × 0308 ÷ 0023 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] NUMBER SIGN (AL) ÷ [0.3] +× 2014 × 0308 × 0020 ÷ 0023 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] × 2014 × 2014 ÷ # × [0.3] EM DASH (B2) × [17.0] EM DASH (B2) ÷ [0.3] × 2014 × 0020 × 2014 ÷ # × [0.3] EM DASH (B2) × [7.01] SPACE (SP) × [17.0] EM DASH (B2) ÷ [0.3] -× 2014 × 0308 × 2014 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM) × [17.0] EM DASH (B2) ÷ [0.3] -× 2014 × 0308 × 0020 × 2014 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [17.0] EM DASH (B2) ÷ [0.3] +× 2014 × 0308 × 2014 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [17.0] EM DASH (B2) ÷ [0.3] +× 2014 × 0308 × 0020 × 2014 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [17.0] EM DASH (B2) ÷ [0.3] × 2014 × 0009 ÷ # × [0.3] EM DASH (B2) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] × 2014 × 0020 ÷ 0009 ÷ # × [0.3] EM DASH (B2) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] -× 2014 × 0308 × 0009 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] -× 2014 × 0308 × 0020 ÷ 0009 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] +× 2014 × 0308 × 0009 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] +× 2014 × 0308 × 0020 ÷ 0009 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] × 2014 ÷ 00B4 ÷ # × [0.3] EM DASH (B2) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3] × 2014 × 0020 ÷ 00B4 ÷ # × [0.3] EM DASH (B2) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] -× 2014 × 0308 ÷ 00B4 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3] -× 2014 × 0308 × 0020 ÷ 00B4 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] +× 2014 × 0308 ÷ 00B4 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3] +× 2014 × 0308 × 0020 ÷ 00B4 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] × 2014 × 000B ÷ # × [0.3] EM DASH (B2) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] × 2014 × 0020 × 000B ÷ # × [0.3] EM DASH (B2) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] -× 2014 × 0308 × 000B ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] -× 2014 × 0308 × 0020 × 000B ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] +× 2014 × 0308 × 000B ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] +× 2014 × 0308 × 0020 × 000B ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] × 2014 ÷ FFFC ÷ # × [0.3] EM DASH (B2) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] × 2014 × 0020 ÷ FFFC ÷ # × [0.3] EM DASH (B2) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] -× 2014 × 0308 ÷ FFFC ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] -× 2014 × 0308 × 0020 ÷ FFFC ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] +× 2014 × 0308 ÷ FFFC ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] +× 2014 × 0308 × 0020 ÷ FFFC ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] × 2014 × 007D ÷ # × [0.3] EM DASH (B2) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] × 2014 × 0020 × 007D ÷ # × [0.3] EM DASH (B2) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] -× 2014 × 0308 × 007D ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM) × [13.03] RIGHT CURLY BRACKET (CL) ÷ [0.3] -× 2014 × 0308 × 0020 × 007D ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] +× 2014 × 0308 × 007D ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] RIGHT CURLY BRACKET (CL) ÷ [0.3] +× 2014 × 0308 × 0020 × 007D ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] × 2014 × 0029 ÷ # × [0.3] EM DASH (B2) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] × 2014 × 0020 × 0029 ÷ # × [0.3] EM DASH (B2) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 2014 × 0308 × 0029 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM) × [13.03] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 2014 × 0308 × 0020 × 0029 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 2014 × 0001 ÷ # × [0.3] EM DASH (B2) × [9.0] <START OF HEADING> (CM) ÷ [0.3] -× 2014 × 0020 ÷ 0001 ÷ # × [0.3] EM DASH (B2) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM) ÷ [0.3] -× 2014 × 0308 × 0001 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM) × [9.0] <START OF HEADING> (CM) ÷ [0.3] -× 2014 × 0308 × 0020 ÷ 0001 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM) ÷ [0.3] +× 2014 × 0308 × 0029 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] RIGHT PARENTHESIS (CP) ÷ [0.3] +× 2014 × 0308 × 0020 × 0029 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] × 2014 × 000D ÷ # × [0.3] EM DASH (B2) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] × 2014 × 0020 × 000D ÷ # × [0.3] EM DASH (B2) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -× 2014 × 0308 × 000D ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -× 2014 × 0308 × 0020 × 000D ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +× 2014 × 0308 × 000D ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +× 2014 × 0308 × 0020 × 000D ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] × 2014 × 0021 ÷ # × [0.3] EM DASH (B2) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] × 2014 × 0020 × 0021 ÷ # × [0.3] EM DASH (B2) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] -× 2014 × 0308 × 0021 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] -× 2014 × 0308 × 0020 × 0021 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] +× 2014 × 0308 × 0021 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] +× 2014 × 0308 × 0020 × 0021 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] × 2014 × 00A0 ÷ # × [0.3] EM DASH (B2) × [12.1] NO-BREAK SPACE (GL) ÷ [0.3] × 2014 × 0020 ÷ 00A0 ÷ # × [0.3] EM DASH (B2) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] -× 2014 × 0308 × 00A0 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM) × [12.2] NO-BREAK SPACE (GL) ÷ [0.3] -× 2014 × 0308 × 0020 ÷ 00A0 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] +× 2014 × 0308 × 00A0 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [12.2] NO-BREAK SPACE (GL) ÷ [0.3] +× 2014 × 0308 × 0020 ÷ 00A0 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] × 2014 ÷ AC00 ÷ # × [0.3] EM DASH (B2) ÷ [999.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] × 2014 × 0020 ÷ AC00 ÷ # × [0.3] EM DASH (B2) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] -× 2014 × 0308 ÷ AC00 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] -× 2014 × 0308 × 0020 ÷ AC00 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] +× 2014 × 0308 ÷ AC00 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] +× 2014 × 0308 × 0020 ÷ AC00 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] × 2014 ÷ AC01 ÷ # × [0.3] EM DASH (B2) ÷ [999.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] × 2014 × 0020 ÷ AC01 ÷ # × [0.3] EM DASH (B2) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] -× 2014 × 0308 ÷ AC01 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] -× 2014 × 0308 × 0020 ÷ AC01 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] +× 2014 × 0308 ÷ AC01 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] +× 2014 × 0308 × 0020 ÷ AC01 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] × 2014 ÷ 05D0 ÷ # × [0.3] EM DASH (B2) ÷ [999.0] HEBREW LETTER ALEF (HL) ÷ [0.3] × 2014 × 0020 ÷ 05D0 ÷ # × [0.3] EM DASH (B2) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] -× 2014 × 0308 ÷ 05D0 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HEBREW LETTER ALEF (HL) ÷ [0.3] -× 2014 × 0308 × 0020 ÷ 05D0 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] +× 2014 × 0308 ÷ 05D0 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HEBREW LETTER ALEF (HL) ÷ [0.3] +× 2014 × 0308 × 0020 ÷ 05D0 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] × 2014 × 002D ÷ # × [0.3] EM DASH (B2) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] × 2014 × 0020 ÷ 002D ÷ # × [0.3] EM DASH (B2) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] -× 2014 × 0308 × 002D ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] -× 2014 × 0308 × 0020 ÷ 002D ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] +× 2014 × 0308 × 002D ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] +× 2014 × 0308 × 0020 ÷ 002D ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] × 2014 ÷ 231A ÷ # × [0.3] EM DASH (B2) ÷ [999.0] WATCH (ID) ÷ [0.3] × 2014 × 0020 ÷ 231A ÷ # × [0.3] EM DASH (B2) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] -× 2014 × 0308 ÷ 231A ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] WATCH (ID) ÷ [0.3] -× 2014 × 0308 × 0020 ÷ 231A ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] +× 2014 × 0308 ÷ 231A ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] WATCH (ID) ÷ [0.3] +× 2014 × 0308 × 0020 ÷ 231A ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] × 2014 ÷ 2024 ÷ # × [0.3] EM DASH (B2) ÷ [999.0] ONE DOT LEADER (IN) ÷ [0.3] × 2014 × 0020 ÷ 2024 ÷ # × [0.3] EM DASH (B2) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] -× 2014 × 0308 ÷ 2024 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] ONE DOT LEADER (IN) ÷ [0.3] -× 2014 × 0308 × 0020 ÷ 2024 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] +× 2014 × 0308 ÷ 2024 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] ONE DOT LEADER (IN) ÷ [0.3] +× 2014 × 0308 × 0020 ÷ 2024 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] × 2014 × 002C ÷ # × [0.3] EM DASH (B2) × [13.02] COMMA (IS) ÷ [0.3] × 2014 × 0020 × 002C ÷ # × [0.3] EM DASH (B2) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] -× 2014 × 0308 × 002C ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM) × [13.03] COMMA (IS) ÷ [0.3] -× 2014 × 0308 × 0020 × 002C ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] +× 2014 × 0308 × 002C ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] COMMA (IS) ÷ [0.3] +× 2014 × 0308 × 0020 × 002C ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] × 2014 ÷ 1100 ÷ # × [0.3] EM DASH (B2) ÷ [999.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] × 2014 × 0020 ÷ 1100 ÷ # × [0.3] EM DASH (B2) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] -× 2014 × 0308 ÷ 1100 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] -× 2014 × 0308 × 0020 ÷ 1100 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] +× 2014 × 0308 ÷ 1100 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] +× 2014 × 0308 × 0020 ÷ 1100 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] × 2014 ÷ 11A8 ÷ # × [0.3] EM DASH (B2) ÷ [999.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] × 2014 × 0020 ÷ 11A8 ÷ # × [0.3] EM DASH (B2) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] -× 2014 × 0308 ÷ 11A8 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] -× 2014 × 0308 × 0020 ÷ 11A8 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] +× 2014 × 0308 ÷ 11A8 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] +× 2014 × 0308 × 0020 ÷ 11A8 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] × 2014 ÷ 1160 ÷ # × [0.3] EM DASH (B2) ÷ [999.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] × 2014 × 0020 ÷ 1160 ÷ # × [0.3] EM DASH (B2) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] -× 2014 × 0308 ÷ 1160 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] -× 2014 × 0308 × 0020 ÷ 1160 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] +× 2014 × 0308 ÷ 1160 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] +× 2014 × 0308 × 0020 ÷ 1160 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] × 2014 × 000A ÷ # × [0.3] EM DASH (B2) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] × 2014 × 0020 × 000A ÷ # × [0.3] EM DASH (B2) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] -× 2014 × 0308 × 000A ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] -× 2014 × 0308 × 0020 × 000A ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] +× 2014 × 0308 × 000A ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] +× 2014 × 0308 × 0020 × 000A ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] × 2014 × 0085 ÷ # × [0.3] EM DASH (B2) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] × 2014 × 0020 × 0085 ÷ # × [0.3] EM DASH (B2) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] -× 2014 × 0308 × 0085 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] -× 2014 × 0308 × 0020 × 0085 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] +× 2014 × 0308 × 0085 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] +× 2014 × 0308 × 0020 × 0085 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] × 2014 × 17D6 ÷ # × [0.3] EM DASH (B2) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] × 2014 × 0020 ÷ 17D6 ÷ # × [0.3] EM DASH (B2) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] -× 2014 × 0308 × 17D6 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] -× 2014 × 0308 × 0020 ÷ 17D6 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] +× 2014 × 0308 × 17D6 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] +× 2014 × 0308 × 0020 ÷ 17D6 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] × 2014 ÷ 0030 ÷ # × [0.3] EM DASH (B2) ÷ [999.0] DIGIT ZERO (NU) ÷ [0.3] × 2014 × 0020 ÷ 0030 ÷ # × [0.3] EM DASH (B2) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] -× 2014 × 0308 ÷ 0030 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] DIGIT ZERO (NU) ÷ [0.3] -× 2014 × 0308 × 0020 ÷ 0030 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] +× 2014 × 0308 ÷ 0030 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] DIGIT ZERO (NU) ÷ [0.3] +× 2014 × 0308 × 0020 ÷ 0030 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] × 2014 ÷ 0028 ÷ # × [0.3] EM DASH (B2) ÷ [999.0] LEFT PARENTHESIS (OP) ÷ [0.3] × 2014 × 0020 ÷ 0028 ÷ # × [0.3] EM DASH (B2) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] -× 2014 × 0308 ÷ 0028 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] LEFT PARENTHESIS (OP) ÷ [0.3] -× 2014 × 0308 × 0020 ÷ 0028 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] +× 2014 × 0308 ÷ 0028 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] LEFT PARENTHESIS (OP) ÷ [0.3] +× 2014 × 0308 × 0020 ÷ 0028 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] × 2014 ÷ 0025 ÷ # × [0.3] EM DASH (B2) ÷ [999.0] PERCENT SIGN (PO) ÷ [0.3] × 2014 × 0020 ÷ 0025 ÷ # × [0.3] EM DASH (B2) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] -× 2014 × 0308 ÷ 0025 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] PERCENT SIGN (PO) ÷ [0.3] -× 2014 × 0308 × 0020 ÷ 0025 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] +× 2014 × 0308 ÷ 0025 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] PERCENT SIGN (PO) ÷ [0.3] +× 2014 × 0308 × 0020 ÷ 0025 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] × 2014 ÷ 0024 ÷ # × [0.3] EM DASH (B2) ÷ [999.0] DOLLAR SIGN (PR) ÷ [0.3] × 2014 × 0020 ÷ 0024 ÷ # × [0.3] EM DASH (B2) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] -× 2014 × 0308 ÷ 0024 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] DOLLAR SIGN (PR) ÷ [0.3] -× 2014 × 0308 × 0020 ÷ 0024 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] +× 2014 × 0308 ÷ 0024 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] DOLLAR SIGN (PR) ÷ [0.3] +× 2014 × 0308 × 0020 ÷ 0024 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] × 2014 × 0022 ÷ # × [0.3] EM DASH (B2) × [19.01] QUOTATION MARK (QU) ÷ [0.3] × 2014 × 0020 ÷ 0022 ÷ # × [0.3] EM DASH (B2) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] -× 2014 × 0308 × 0022 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM) × [19.01] QUOTATION MARK (QU) ÷ [0.3] -× 2014 × 0308 × 0020 ÷ 0022 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] +× 2014 × 0308 × 0022 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [19.01] QUOTATION MARK (QU) ÷ [0.3] +× 2014 × 0308 × 0020 ÷ 0022 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] × 2014 × 0020 ÷ # × [0.3] EM DASH (B2) × [7.01] SPACE (SP) ÷ [0.3] × 2014 × 0020 × 0020 ÷ # × [0.3] EM DASH (B2) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] -× 2014 × 0308 × 0020 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [0.3] -× 2014 × 0308 × 0020 × 0020 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] +× 2014 × 0308 × 0020 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [0.3] +× 2014 × 0308 × 0020 × 0020 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] × 2014 × 002F ÷ # × [0.3] EM DASH (B2) × [13.02] SOLIDUS (SY) ÷ [0.3] × 2014 × 0020 × 002F ÷ # × [0.3] EM DASH (B2) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] -× 2014 × 0308 × 002F ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM) × [13.03] SOLIDUS (SY) ÷ [0.3] -× 2014 × 0308 × 0020 × 002F ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] +× 2014 × 0308 × 002F ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] SOLIDUS (SY) ÷ [0.3] +× 2014 × 0308 × 0020 × 002F ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] × 2014 × 2060 ÷ # × [0.3] EM DASH (B2) × [11.01] WORD JOINER (WJ) ÷ [0.3] × 2014 × 0020 × 2060 ÷ # × [0.3] EM DASH (B2) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] -× 2014 × 0308 × 2060 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM) × [11.01] WORD JOINER (WJ) ÷ [0.3] -× 2014 × 0308 × 0020 × 2060 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] +× 2014 × 0308 × 2060 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [11.01] WORD JOINER (WJ) ÷ [0.3] +× 2014 × 0308 × 0020 × 2060 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] × 2014 × 200B ÷ # × [0.3] EM DASH (B2) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] × 2014 × 0020 × 200B ÷ # × [0.3] EM DASH (B2) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] -× 2014 × 0308 × 200B ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] -× 2014 × 0308 × 0020 × 200B ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] +× 2014 × 0308 × 200B ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] +× 2014 × 0308 × 0020 × 200B ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] × 2014 ÷ 1F1E6 ÷ # × [0.3] EM DASH (B2) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] × 2014 × 0020 ÷ 1F1E6 ÷ # × [0.3] EM DASH (B2) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -× 2014 × 0308 ÷ 1F1E6 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -× 2014 × 0308 × 0020 ÷ 1F1E6 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 2014 × 0308 ÷ 1F1E6 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 2014 × 0308 × 0020 ÷ 1F1E6 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 2014 ÷ 261D ÷ # × [0.3] EM DASH (B2) ÷ [999.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 2014 × 0020 ÷ 261D ÷ # × [0.3] EM DASH (B2) × [7.01] SPACE (SP) ÷ [18.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 2014 × 0308 ÷ 261D ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 2014 × 0308 × 0020 ÷ 261D ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 2014 ÷ 1F3FB ÷ # × [0.3] EM DASH (B2) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 2014 × 0020 ÷ 1F3FB ÷ # × [0.3] EM DASH (B2) × [7.01] SPACE (SP) ÷ [18.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 2014 × 0308 ÷ 1F3FB ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 2014 × 0308 × 0020 ÷ 1F3FB ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 2014 × 0001 ÷ # × [0.3] EM DASH (B2) × [9.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 2014 × 0020 ÷ 0001 ÷ # × [0.3] EM DASH (B2) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 2014 × 0308 × 0001 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [9.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 2014 × 0308 × 0020 ÷ 0001 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 2014 × 200D ÷ # × [0.3] EM DASH (B2) × [9.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 2014 × 0020 ÷ 200D ÷ # × [0.3] EM DASH (B2) × [7.01] SPACE (SP) ÷ [18.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 2014 × 0308 × 200D ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [9.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 2014 × 0308 × 0020 ÷ 200D ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] × 2014 ÷ 00A7 ÷ # × [0.3] EM DASH (B2) ÷ [999.0] SECTION SIGN (AI_AL) ÷ [0.3] × 2014 × 0020 ÷ 00A7 ÷ # × [0.3] EM DASH (B2) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] -× 2014 × 0308 ÷ 00A7 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] SECTION SIGN (AI_AL) ÷ [0.3] -× 2014 × 0308 × 0020 ÷ 00A7 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] +× 2014 × 0308 ÷ 00A7 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] SECTION SIGN (AI_AL) ÷ [0.3] +× 2014 × 0308 × 0020 ÷ 00A7 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] × 2014 ÷ 50005 ÷ # × [0.3] EM DASH (B2) ÷ [999.0] <reserved-50005> (XX_AL) ÷ [0.3] × 2014 × 0020 ÷ 50005 ÷ # × [0.3] EM DASH (B2) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] -× 2014 × 0308 ÷ 50005 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] <reserved-50005> (XX_AL) ÷ [0.3] -× 2014 × 0308 × 0020 ÷ 50005 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] +× 2014 × 0308 ÷ 50005 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] <reserved-50005> (XX_AL) ÷ [0.3] +× 2014 × 0308 × 0020 ÷ 50005 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] × 2014 ÷ 0E01 ÷ # × [0.3] EM DASH (B2) ÷ [999.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] × 2014 × 0020 ÷ 0E01 ÷ # × [0.3] EM DASH (B2) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] -× 2014 × 0308 ÷ 0E01 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] -× 2014 × 0308 × 0020 ÷ 0E01 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] +× 2014 × 0308 ÷ 0E01 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] +× 2014 × 0308 × 0020 ÷ 0E01 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] × 2014 × 3041 ÷ # × [0.3] EM DASH (B2) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] × 2014 × 0020 ÷ 3041 ÷ # × [0.3] EM DASH (B2) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] -× 2014 × 0308 × 3041 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] -× 2014 × 0308 × 0020 ÷ 3041 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] +× 2014 × 0308 × 3041 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] +× 2014 × 0308 × 0020 ÷ 3041 ÷ # × [0.3] EM DASH (B2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] × 0009 ÷ 0023 ÷ # × [0.3] <CHARACTER TABULATION> (BA) ÷ [999.0] NUMBER SIGN (AL) ÷ [0.3] × 0009 × 0020 ÷ 0023 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] -× 0009 × 0308 ÷ 0023 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] NUMBER SIGN (AL) ÷ [0.3] -× 0009 × 0308 × 0020 ÷ 0023 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] +× 0009 × 0308 ÷ 0023 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] NUMBER SIGN (AL) ÷ [0.3] +× 0009 × 0308 × 0020 ÷ 0023 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] × 0009 ÷ 2014 ÷ # × [0.3] <CHARACTER TABULATION> (BA) ÷ [999.0] EM DASH (B2) ÷ [0.3] × 0009 × 0020 ÷ 2014 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] -× 0009 × 0308 ÷ 2014 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] EM DASH (B2) ÷ [0.3] -× 0009 × 0308 × 0020 ÷ 2014 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] +× 0009 × 0308 ÷ 2014 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] EM DASH (B2) ÷ [0.3] +× 0009 × 0308 × 0020 ÷ 2014 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] × 0009 × 0009 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] × 0009 × 0020 ÷ 0009 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] -× 0009 × 0308 × 0009 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] -× 0009 × 0308 × 0020 ÷ 0009 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] +× 0009 × 0308 × 0009 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] +× 0009 × 0308 × 0020 ÷ 0009 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] × 0009 ÷ 00B4 ÷ # × [0.3] <CHARACTER TABULATION> (BA) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3] × 0009 × 0020 ÷ 00B4 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] -× 0009 × 0308 ÷ 00B4 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3] -× 0009 × 0308 × 0020 ÷ 00B4 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] +× 0009 × 0308 ÷ 00B4 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3] +× 0009 × 0308 × 0020 ÷ 00B4 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] × 0009 × 000B ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] × 0009 × 0020 × 000B ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] -× 0009 × 0308 × 000B ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] -× 0009 × 0308 × 0020 × 000B ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] +× 0009 × 0308 × 000B ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] +× 0009 × 0308 × 0020 × 000B ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] × 0009 ÷ FFFC ÷ # × [0.3] <CHARACTER TABULATION> (BA) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] × 0009 × 0020 ÷ FFFC ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] -× 0009 × 0308 ÷ FFFC ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] -× 0009 × 0308 × 0020 ÷ FFFC ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] +× 0009 × 0308 ÷ FFFC ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] +× 0009 × 0308 × 0020 ÷ FFFC ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] × 0009 × 007D ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] × 0009 × 0020 × 007D ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] -× 0009 × 0308 × 007D ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM) × [13.03] RIGHT CURLY BRACKET (CL) ÷ [0.3] -× 0009 × 0308 × 0020 × 007D ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] +× 0009 × 0308 × 007D ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] RIGHT CURLY BRACKET (CL) ÷ [0.3] +× 0009 × 0308 × 0020 × 007D ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] × 0009 × 0029 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] × 0009 × 0020 × 0029 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 0009 × 0308 × 0029 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM) × [13.03] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 0009 × 0308 × 0020 × 0029 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 0009 × 0001 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] <START OF HEADING> (CM) ÷ [0.3] -× 0009 × 0020 ÷ 0001 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM) ÷ [0.3] -× 0009 × 0308 × 0001 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM) × [9.0] <START OF HEADING> (CM) ÷ [0.3] -× 0009 × 0308 × 0020 ÷ 0001 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM) ÷ [0.3] +× 0009 × 0308 × 0029 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] RIGHT PARENTHESIS (CP) ÷ [0.3] +× 0009 × 0308 × 0020 × 0029 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] × 0009 × 000D ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] × 0009 × 0020 × 000D ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -× 0009 × 0308 × 000D ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -× 0009 × 0308 × 0020 × 000D ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +× 0009 × 0308 × 000D ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +× 0009 × 0308 × 0020 × 000D ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] × 0009 × 0021 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] × 0009 × 0020 × 0021 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] -× 0009 × 0308 × 0021 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] -× 0009 × 0308 × 0020 × 0021 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] +× 0009 × 0308 × 0021 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] +× 0009 × 0308 × 0020 × 0021 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] × 0009 ÷ 00A0 ÷ # × [0.3] <CHARACTER TABULATION> (BA) ÷ [999.0] NO-BREAK SPACE (GL) ÷ [0.3] × 0009 × 0020 ÷ 00A0 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] -× 0009 × 0308 ÷ 00A0 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] NO-BREAK SPACE (GL) ÷ [0.3] -× 0009 × 0308 × 0020 ÷ 00A0 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] +× 0009 × 0308 ÷ 00A0 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] NO-BREAK SPACE (GL) ÷ [0.3] +× 0009 × 0308 × 0020 ÷ 00A0 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] × 0009 ÷ AC00 ÷ # × [0.3] <CHARACTER TABULATION> (BA) ÷ [999.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] × 0009 × 0020 ÷ AC00 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] -× 0009 × 0308 ÷ AC00 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] -× 0009 × 0308 × 0020 ÷ AC00 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] +× 0009 × 0308 ÷ AC00 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] +× 0009 × 0308 × 0020 ÷ AC00 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] × 0009 ÷ AC01 ÷ # × [0.3] <CHARACTER TABULATION> (BA) ÷ [999.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] × 0009 × 0020 ÷ AC01 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] -× 0009 × 0308 ÷ AC01 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] -× 0009 × 0308 × 0020 ÷ AC01 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] +× 0009 × 0308 ÷ AC01 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] +× 0009 × 0308 × 0020 ÷ AC01 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] × 0009 ÷ 05D0 ÷ # × [0.3] <CHARACTER TABULATION> (BA) ÷ [999.0] HEBREW LETTER ALEF (HL) ÷ [0.3] × 0009 × 0020 ÷ 05D0 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] -× 0009 × 0308 ÷ 05D0 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HEBREW LETTER ALEF (HL) ÷ [0.3] -× 0009 × 0308 × 0020 ÷ 05D0 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] +× 0009 × 0308 ÷ 05D0 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HEBREW LETTER ALEF (HL) ÷ [0.3] +× 0009 × 0308 × 0020 ÷ 05D0 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] × 0009 × 002D ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] × 0009 × 0020 ÷ 002D ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] -× 0009 × 0308 × 002D ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] -× 0009 × 0308 × 0020 ÷ 002D ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] +× 0009 × 0308 × 002D ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] +× 0009 × 0308 × 0020 ÷ 002D ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] × 0009 ÷ 231A ÷ # × [0.3] <CHARACTER TABULATION> (BA) ÷ [999.0] WATCH (ID) ÷ [0.3] × 0009 × 0020 ÷ 231A ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] -× 0009 × 0308 ÷ 231A ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] WATCH (ID) ÷ [0.3] -× 0009 × 0308 × 0020 ÷ 231A ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] +× 0009 × 0308 ÷ 231A ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] WATCH (ID) ÷ [0.3] +× 0009 × 0308 × 0020 ÷ 231A ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] × 0009 ÷ 2024 ÷ # × [0.3] <CHARACTER TABULATION> (BA) ÷ [999.0] ONE DOT LEADER (IN) ÷ [0.3] × 0009 × 0020 ÷ 2024 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] -× 0009 × 0308 ÷ 2024 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] ONE DOT LEADER (IN) ÷ [0.3] -× 0009 × 0308 × 0020 ÷ 2024 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] +× 0009 × 0308 ÷ 2024 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] ONE DOT LEADER (IN) ÷ [0.3] +× 0009 × 0308 × 0020 ÷ 2024 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] × 0009 × 002C ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [13.02] COMMA (IS) ÷ [0.3] × 0009 × 0020 × 002C ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] -× 0009 × 0308 × 002C ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM) × [13.03] COMMA (IS) ÷ [0.3] -× 0009 × 0308 × 0020 × 002C ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] +× 0009 × 0308 × 002C ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] COMMA (IS) ÷ [0.3] +× 0009 × 0308 × 0020 × 002C ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] × 0009 ÷ 1100 ÷ # × [0.3] <CHARACTER TABULATION> (BA) ÷ [999.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] × 0009 × 0020 ÷ 1100 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] -× 0009 × 0308 ÷ 1100 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] -× 0009 × 0308 × 0020 ÷ 1100 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] +× 0009 × 0308 ÷ 1100 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] +× 0009 × 0308 × 0020 ÷ 1100 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] × 0009 ÷ 11A8 ÷ # × [0.3] <CHARACTER TABULATION> (BA) ÷ [999.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] × 0009 × 0020 ÷ 11A8 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] -× 0009 × 0308 ÷ 11A8 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] -× 0009 × 0308 × 0020 ÷ 11A8 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] +× 0009 × 0308 ÷ 11A8 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] +× 0009 × 0308 × 0020 ÷ 11A8 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] × 0009 ÷ 1160 ÷ # × [0.3] <CHARACTER TABULATION> (BA) ÷ [999.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] × 0009 × 0020 ÷ 1160 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] -× 0009 × 0308 ÷ 1160 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] -× 0009 × 0308 × 0020 ÷ 1160 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] +× 0009 × 0308 ÷ 1160 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] +× 0009 × 0308 × 0020 ÷ 1160 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] × 0009 × 000A ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] × 0009 × 0020 × 000A ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] -× 0009 × 0308 × 000A ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] -× 0009 × 0308 × 0020 × 000A ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] +× 0009 × 0308 × 000A ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] +× 0009 × 0308 × 0020 × 000A ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] × 0009 × 0085 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] × 0009 × 0020 × 0085 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] -× 0009 × 0308 × 0085 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] -× 0009 × 0308 × 0020 × 0085 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] +× 0009 × 0308 × 0085 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] +× 0009 × 0308 × 0020 × 0085 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] × 0009 × 17D6 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] × 0009 × 0020 ÷ 17D6 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] -× 0009 × 0308 × 17D6 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] -× 0009 × 0308 × 0020 ÷ 17D6 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] +× 0009 × 0308 × 17D6 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] +× 0009 × 0308 × 0020 ÷ 17D6 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] × 0009 ÷ 0030 ÷ # × [0.3] <CHARACTER TABULATION> (BA) ÷ [999.0] DIGIT ZERO (NU) ÷ [0.3] × 0009 × 0020 ÷ 0030 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] -× 0009 × 0308 ÷ 0030 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] DIGIT ZERO (NU) ÷ [0.3] -× 0009 × 0308 × 0020 ÷ 0030 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] +× 0009 × 0308 ÷ 0030 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] DIGIT ZERO (NU) ÷ [0.3] +× 0009 × 0308 × 0020 ÷ 0030 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] × 0009 ÷ 0028 ÷ # × [0.3] <CHARACTER TABULATION> (BA) ÷ [999.0] LEFT PARENTHESIS (OP) ÷ [0.3] × 0009 × 0020 ÷ 0028 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] -× 0009 × 0308 ÷ 0028 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] LEFT PARENTHESIS (OP) ÷ [0.3] -× 0009 × 0308 × 0020 ÷ 0028 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] +× 0009 × 0308 ÷ 0028 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] LEFT PARENTHESIS (OP) ÷ [0.3] +× 0009 × 0308 × 0020 ÷ 0028 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] × 0009 ÷ 0025 ÷ # × [0.3] <CHARACTER TABULATION> (BA) ÷ [999.0] PERCENT SIGN (PO) ÷ [0.3] × 0009 × 0020 ÷ 0025 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] -× 0009 × 0308 ÷ 0025 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] PERCENT SIGN (PO) ÷ [0.3] -× 0009 × 0308 × 0020 ÷ 0025 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] +× 0009 × 0308 ÷ 0025 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] PERCENT SIGN (PO) ÷ [0.3] +× 0009 × 0308 × 0020 ÷ 0025 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] × 0009 ÷ 0024 ÷ # × [0.3] <CHARACTER TABULATION> (BA) ÷ [999.0] DOLLAR SIGN (PR) ÷ [0.3] × 0009 × 0020 ÷ 0024 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] -× 0009 × 0308 ÷ 0024 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] DOLLAR SIGN (PR) ÷ [0.3] -× 0009 × 0308 × 0020 ÷ 0024 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] +× 0009 × 0308 ÷ 0024 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] DOLLAR SIGN (PR) ÷ [0.3] +× 0009 × 0308 × 0020 ÷ 0024 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] × 0009 × 0022 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [19.01] QUOTATION MARK (QU) ÷ [0.3] × 0009 × 0020 ÷ 0022 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] -× 0009 × 0308 × 0022 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM) × [19.01] QUOTATION MARK (QU) ÷ [0.3] -× 0009 × 0308 × 0020 ÷ 0022 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] +× 0009 × 0308 × 0022 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM1_CM) × [19.01] QUOTATION MARK (QU) ÷ [0.3] +× 0009 × 0308 × 0020 ÷ 0022 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] × 0009 × 0020 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [7.01] SPACE (SP) ÷ [0.3] × 0009 × 0020 × 0020 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] -× 0009 × 0308 × 0020 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [0.3] -× 0009 × 0308 × 0020 × 0020 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] +× 0009 × 0308 × 0020 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [0.3] +× 0009 × 0308 × 0020 × 0020 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] × 0009 × 002F ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [13.02] SOLIDUS (SY) ÷ [0.3] × 0009 × 0020 × 002F ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] -× 0009 × 0308 × 002F ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM) × [13.03] SOLIDUS (SY) ÷ [0.3] -× 0009 × 0308 × 0020 × 002F ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] +× 0009 × 0308 × 002F ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] SOLIDUS (SY) ÷ [0.3] +× 0009 × 0308 × 0020 × 002F ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] × 0009 × 2060 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [11.01] WORD JOINER (WJ) ÷ [0.3] × 0009 × 0020 × 2060 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] -× 0009 × 0308 × 2060 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM) × [11.01] WORD JOINER (WJ) ÷ [0.3] -× 0009 × 0308 × 0020 × 2060 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] +× 0009 × 0308 × 2060 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM1_CM) × [11.01] WORD JOINER (WJ) ÷ [0.3] +× 0009 × 0308 × 0020 × 2060 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] × 0009 × 200B ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] × 0009 × 0020 × 200B ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] -× 0009 × 0308 × 200B ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] -× 0009 × 0308 × 0020 × 200B ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] +× 0009 × 0308 × 200B ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] +× 0009 × 0308 × 0020 × 200B ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] × 0009 ÷ 1F1E6 ÷ # × [0.3] <CHARACTER TABULATION> (BA) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] × 0009 × 0020 ÷ 1F1E6 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -× 0009 × 0308 ÷ 1F1E6 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -× 0009 × 0308 × 0020 ÷ 1F1E6 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 0009 × 0308 ÷ 1F1E6 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 0009 × 0308 × 0020 ÷ 1F1E6 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 0009 ÷ 261D ÷ # × [0.3] <CHARACTER TABULATION> (BA) ÷ [999.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 0009 × 0020 ÷ 261D ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [7.01] SPACE (SP) ÷ [18.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 0009 × 0308 ÷ 261D ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 0009 × 0308 × 0020 ÷ 261D ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 0009 ÷ 1F3FB ÷ # × [0.3] <CHARACTER TABULATION> (BA) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 0009 × 0020 ÷ 1F3FB ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [7.01] SPACE (SP) ÷ [18.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 0009 × 0308 ÷ 1F3FB ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 0009 × 0308 × 0020 ÷ 1F3FB ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 0009 × 0001 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 0009 × 0020 ÷ 0001 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 0009 × 0308 × 0001 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM1_CM) × [9.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 0009 × 0308 × 0020 ÷ 0001 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 0009 × 200D ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 0009 × 0020 ÷ 200D ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [7.01] SPACE (SP) ÷ [18.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 0009 × 0308 × 200D ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM1_CM) × [9.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 0009 × 0308 × 0020 ÷ 200D ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] × 0009 ÷ 00A7 ÷ # × [0.3] <CHARACTER TABULATION> (BA) ÷ [999.0] SECTION SIGN (AI_AL) ÷ [0.3] × 0009 × 0020 ÷ 00A7 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] -× 0009 × 0308 ÷ 00A7 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] SECTION SIGN (AI_AL) ÷ [0.3] -× 0009 × 0308 × 0020 ÷ 00A7 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] +× 0009 × 0308 ÷ 00A7 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] SECTION SIGN (AI_AL) ÷ [0.3] +× 0009 × 0308 × 0020 ÷ 00A7 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] × 0009 ÷ 50005 ÷ # × [0.3] <CHARACTER TABULATION> (BA) ÷ [999.0] <reserved-50005> (XX_AL) ÷ [0.3] × 0009 × 0020 ÷ 50005 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] -× 0009 × 0308 ÷ 50005 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] <reserved-50005> (XX_AL) ÷ [0.3] -× 0009 × 0308 × 0020 ÷ 50005 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] +× 0009 × 0308 ÷ 50005 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] <reserved-50005> (XX_AL) ÷ [0.3] +× 0009 × 0308 × 0020 ÷ 50005 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] × 0009 ÷ 0E01 ÷ # × [0.3] <CHARACTER TABULATION> (BA) ÷ [999.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] × 0009 × 0020 ÷ 0E01 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] -× 0009 × 0308 ÷ 0E01 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] -× 0009 × 0308 × 0020 ÷ 0E01 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] +× 0009 × 0308 ÷ 0E01 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] +× 0009 × 0308 × 0020 ÷ 0E01 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] × 0009 × 3041 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] × 0009 × 0020 ÷ 3041 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] -× 0009 × 0308 × 3041 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] -× 0009 × 0308 × 0020 ÷ 3041 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] +× 0009 × 0308 × 3041 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] +× 0009 × 0308 × 0020 ÷ 3041 ÷ # × [0.3] <CHARACTER TABULATION> (BA) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] × 00B4 × 0023 ÷ # × [0.3] ACUTE ACCENT (BB) × [21.04] NUMBER SIGN (AL) ÷ [0.3] × 00B4 × 0020 ÷ 0023 ÷ # × [0.3] ACUTE ACCENT (BB) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] -× 00B4 × 0308 × 0023 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM) × [21.04] NUMBER SIGN (AL) ÷ [0.3] -× 00B4 × 0308 × 0020 ÷ 0023 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] +× 00B4 × 0308 × 0023 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.04] NUMBER SIGN (AL) ÷ [0.3] +× 00B4 × 0308 × 0020 ÷ 0023 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] × 00B4 × 2014 ÷ # × [0.3] ACUTE ACCENT (BB) × [21.04] EM DASH (B2) ÷ [0.3] × 00B4 × 0020 ÷ 2014 ÷ # × [0.3] ACUTE ACCENT (BB) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] -× 00B4 × 0308 × 2014 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM) × [21.04] EM DASH (B2) ÷ [0.3] -× 00B4 × 0308 × 0020 ÷ 2014 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] +× 00B4 × 0308 × 2014 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.04] EM DASH (B2) ÷ [0.3] +× 00B4 × 0308 × 0020 ÷ 2014 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] × 00B4 × 0009 ÷ # × [0.3] ACUTE ACCENT (BB) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] × 00B4 × 0020 ÷ 0009 ÷ # × [0.3] ACUTE ACCENT (BB) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] -× 00B4 × 0308 × 0009 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] -× 00B4 × 0308 × 0020 ÷ 0009 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] +× 00B4 × 0308 × 0009 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] +× 00B4 × 0308 × 0020 ÷ 0009 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] × 00B4 × 00B4 ÷ # × [0.3] ACUTE ACCENT (BB) × [21.04] ACUTE ACCENT (BB) ÷ [0.3] × 00B4 × 0020 ÷ 00B4 ÷ # × [0.3] ACUTE ACCENT (BB) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] -× 00B4 × 0308 × 00B4 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM) × [21.04] ACUTE ACCENT (BB) ÷ [0.3] -× 00B4 × 0308 × 0020 ÷ 00B4 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] +× 00B4 × 0308 × 00B4 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.04] ACUTE ACCENT (BB) ÷ [0.3] +× 00B4 × 0308 × 0020 ÷ 00B4 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] × 00B4 × 000B ÷ # × [0.3] ACUTE ACCENT (BB) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] × 00B4 × 0020 × 000B ÷ # × [0.3] ACUTE ACCENT (BB) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] -× 00B4 × 0308 × 000B ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] -× 00B4 × 0308 × 0020 × 000B ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] +× 00B4 × 0308 × 000B ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] +× 00B4 × 0308 × 0020 × 000B ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] × 00B4 ÷ FFFC ÷ # × [0.3] ACUTE ACCENT (BB) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] × 00B4 × 0020 ÷ FFFC ÷ # × [0.3] ACUTE ACCENT (BB) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] -× 00B4 × 0308 ÷ FFFC ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] -× 00B4 × 0308 × 0020 ÷ FFFC ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] +× 00B4 × 0308 ÷ FFFC ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] +× 00B4 × 0308 × 0020 ÷ FFFC ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] × 00B4 × 007D ÷ # × [0.3] ACUTE ACCENT (BB) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] × 00B4 × 0020 × 007D ÷ # × [0.3] ACUTE ACCENT (BB) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] -× 00B4 × 0308 × 007D ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM) × [13.03] RIGHT CURLY BRACKET (CL) ÷ [0.3] -× 00B4 × 0308 × 0020 × 007D ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] +× 00B4 × 0308 × 007D ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] RIGHT CURLY BRACKET (CL) ÷ [0.3] +× 00B4 × 0308 × 0020 × 007D ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] × 00B4 × 0029 ÷ # × [0.3] ACUTE ACCENT (BB) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] × 00B4 × 0020 × 0029 ÷ # × [0.3] ACUTE ACCENT (BB) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 00B4 × 0308 × 0029 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM) × [13.03] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 00B4 × 0308 × 0020 × 0029 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 00B4 × 0001 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] <START OF HEADING> (CM) ÷ [0.3] -× 00B4 × 0020 ÷ 0001 ÷ # × [0.3] ACUTE ACCENT (BB) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM) ÷ [0.3] -× 00B4 × 0308 × 0001 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM) × [9.0] <START OF HEADING> (CM) ÷ [0.3] -× 00B4 × 0308 × 0020 ÷ 0001 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM) ÷ [0.3] +× 00B4 × 0308 × 0029 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] RIGHT PARENTHESIS (CP) ÷ [0.3] +× 00B4 × 0308 × 0020 × 0029 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] × 00B4 × 000D ÷ # × [0.3] ACUTE ACCENT (BB) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] × 00B4 × 0020 × 000D ÷ # × [0.3] ACUTE ACCENT (BB) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -× 00B4 × 0308 × 000D ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -× 00B4 × 0308 × 0020 × 000D ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +× 00B4 × 0308 × 000D ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +× 00B4 × 0308 × 0020 × 000D ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] × 00B4 × 0021 ÷ # × [0.3] ACUTE ACCENT (BB) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] × 00B4 × 0020 × 0021 ÷ # × [0.3] ACUTE ACCENT (BB) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] -× 00B4 × 0308 × 0021 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] -× 00B4 × 0308 × 0020 × 0021 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] +× 00B4 × 0308 × 0021 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] +× 00B4 × 0308 × 0020 × 0021 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] × 00B4 × 00A0 ÷ # × [0.3] ACUTE ACCENT (BB) × [12.1] NO-BREAK SPACE (GL) ÷ [0.3] × 00B4 × 0020 ÷ 00A0 ÷ # × [0.3] ACUTE ACCENT (BB) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] -× 00B4 × 0308 × 00A0 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM) × [12.2] NO-BREAK SPACE (GL) ÷ [0.3] -× 00B4 × 0308 × 0020 ÷ 00A0 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] +× 00B4 × 0308 × 00A0 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [12.2] NO-BREAK SPACE (GL) ÷ [0.3] +× 00B4 × 0308 × 0020 ÷ 00A0 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] × 00B4 × AC00 ÷ # × [0.3] ACUTE ACCENT (BB) × [21.04] HANGUL SYLLABLE GA (H2) ÷ [0.3] × 00B4 × 0020 ÷ AC00 ÷ # × [0.3] ACUTE ACCENT (BB) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] -× 00B4 × 0308 × AC00 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM) × [21.04] HANGUL SYLLABLE GA (H2) ÷ [0.3] -× 00B4 × 0308 × 0020 ÷ AC00 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] +× 00B4 × 0308 × AC00 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.04] HANGUL SYLLABLE GA (H2) ÷ [0.3] +× 00B4 × 0308 × 0020 ÷ AC00 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] × 00B4 × AC01 ÷ # × [0.3] ACUTE ACCENT (BB) × [21.04] HANGUL SYLLABLE GAG (H3) ÷ [0.3] × 00B4 × 0020 ÷ AC01 ÷ # × [0.3] ACUTE ACCENT (BB) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] -× 00B4 × 0308 × AC01 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM) × [21.04] HANGUL SYLLABLE GAG (H3) ÷ [0.3] -× 00B4 × 0308 × 0020 ÷ AC01 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] +× 00B4 × 0308 × AC01 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.04] HANGUL SYLLABLE GAG (H3) ÷ [0.3] +× 00B4 × 0308 × 0020 ÷ AC01 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] × 00B4 × 05D0 ÷ # × [0.3] ACUTE ACCENT (BB) × [21.04] HEBREW LETTER ALEF (HL) ÷ [0.3] × 00B4 × 0020 ÷ 05D0 ÷ # × [0.3] ACUTE ACCENT (BB) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] -× 00B4 × 0308 × 05D0 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM) × [21.04] HEBREW LETTER ALEF (HL) ÷ [0.3] -× 00B4 × 0308 × 0020 ÷ 05D0 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] +× 00B4 × 0308 × 05D0 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.04] HEBREW LETTER ALEF (HL) ÷ [0.3] +× 00B4 × 0308 × 0020 ÷ 05D0 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] × 00B4 × 002D ÷ # × [0.3] ACUTE ACCENT (BB) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] × 00B4 × 0020 ÷ 002D ÷ # × [0.3] ACUTE ACCENT (BB) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] -× 00B4 × 0308 × 002D ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] -× 00B4 × 0308 × 0020 ÷ 002D ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] +× 00B4 × 0308 × 002D ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] +× 00B4 × 0308 × 0020 ÷ 002D ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] × 00B4 × 231A ÷ # × [0.3] ACUTE ACCENT (BB) × [21.04] WATCH (ID) ÷ [0.3] × 00B4 × 0020 ÷ 231A ÷ # × [0.3] ACUTE ACCENT (BB) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] -× 00B4 × 0308 × 231A ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM) × [21.04] WATCH (ID) ÷ [0.3] -× 00B4 × 0308 × 0020 ÷ 231A ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] +× 00B4 × 0308 × 231A ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.04] WATCH (ID) ÷ [0.3] +× 00B4 × 0308 × 0020 ÷ 231A ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] × 00B4 × 2024 ÷ # × [0.3] ACUTE ACCENT (BB) × [21.04] ONE DOT LEADER (IN) ÷ [0.3] × 00B4 × 0020 ÷ 2024 ÷ # × [0.3] ACUTE ACCENT (BB) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] -× 00B4 × 0308 × 2024 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM) × [21.04] ONE DOT LEADER (IN) ÷ [0.3] -× 00B4 × 0308 × 0020 ÷ 2024 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] +× 00B4 × 0308 × 2024 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.04] ONE DOT LEADER (IN) ÷ [0.3] +× 00B4 × 0308 × 0020 ÷ 2024 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] × 00B4 × 002C ÷ # × [0.3] ACUTE ACCENT (BB) × [13.02] COMMA (IS) ÷ [0.3] × 00B4 × 0020 × 002C ÷ # × [0.3] ACUTE ACCENT (BB) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] -× 00B4 × 0308 × 002C ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM) × [13.03] COMMA (IS) ÷ [0.3] -× 00B4 × 0308 × 0020 × 002C ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] +× 00B4 × 0308 × 002C ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] COMMA (IS) ÷ [0.3] +× 00B4 × 0308 × 0020 × 002C ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] × 00B4 × 1100 ÷ # × [0.3] ACUTE ACCENT (BB) × [21.04] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] × 00B4 × 0020 ÷ 1100 ÷ # × [0.3] ACUTE ACCENT (BB) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] -× 00B4 × 0308 × 1100 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM) × [21.04] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] -× 00B4 × 0308 × 0020 ÷ 1100 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] +× 00B4 × 0308 × 1100 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.04] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] +× 00B4 × 0308 × 0020 ÷ 1100 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] × 00B4 × 11A8 ÷ # × [0.3] ACUTE ACCENT (BB) × [21.04] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] × 00B4 × 0020 ÷ 11A8 ÷ # × [0.3] ACUTE ACCENT (BB) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] -× 00B4 × 0308 × 11A8 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM) × [21.04] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] -× 00B4 × 0308 × 0020 ÷ 11A8 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] +× 00B4 × 0308 × 11A8 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.04] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] +× 00B4 × 0308 × 0020 ÷ 11A8 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] × 00B4 × 1160 ÷ # × [0.3] ACUTE ACCENT (BB) × [21.04] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] × 00B4 × 0020 ÷ 1160 ÷ # × [0.3] ACUTE ACCENT (BB) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] -× 00B4 × 0308 × 1160 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM) × [21.04] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] -× 00B4 × 0308 × 0020 ÷ 1160 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] +× 00B4 × 0308 × 1160 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.04] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] +× 00B4 × 0308 × 0020 ÷ 1160 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] × 00B4 × 000A ÷ # × [0.3] ACUTE ACCENT (BB) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] × 00B4 × 0020 × 000A ÷ # × [0.3] ACUTE ACCENT (BB) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] -× 00B4 × 0308 × 000A ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] -× 00B4 × 0308 × 0020 × 000A ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] +× 00B4 × 0308 × 000A ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] +× 00B4 × 0308 × 0020 × 000A ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] × 00B4 × 0085 ÷ # × [0.3] ACUTE ACCENT (BB) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] × 00B4 × 0020 × 0085 ÷ # × [0.3] ACUTE ACCENT (BB) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] -× 00B4 × 0308 × 0085 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] -× 00B4 × 0308 × 0020 × 0085 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] +× 00B4 × 0308 × 0085 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] +× 00B4 × 0308 × 0020 × 0085 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] × 00B4 × 17D6 ÷ # × [0.3] ACUTE ACCENT (BB) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] × 00B4 × 0020 ÷ 17D6 ÷ # × [0.3] ACUTE ACCENT (BB) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] -× 00B4 × 0308 × 17D6 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] -× 00B4 × 0308 × 0020 ÷ 17D6 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] +× 00B4 × 0308 × 17D6 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] +× 00B4 × 0308 × 0020 ÷ 17D6 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] × 00B4 × 0030 ÷ # × [0.3] ACUTE ACCENT (BB) × [21.04] DIGIT ZERO (NU) ÷ [0.3] × 00B4 × 0020 ÷ 0030 ÷ # × [0.3] ACUTE ACCENT (BB) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] -× 00B4 × 0308 × 0030 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM) × [21.04] DIGIT ZERO (NU) ÷ [0.3] -× 00B4 × 0308 × 0020 ÷ 0030 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] +× 00B4 × 0308 × 0030 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.04] DIGIT ZERO (NU) ÷ [0.3] +× 00B4 × 0308 × 0020 ÷ 0030 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] × 00B4 × 0028 ÷ # × [0.3] ACUTE ACCENT (BB) × [21.04] LEFT PARENTHESIS (OP) ÷ [0.3] × 00B4 × 0020 ÷ 0028 ÷ # × [0.3] ACUTE ACCENT (BB) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] -× 00B4 × 0308 × 0028 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM) × [21.04] LEFT PARENTHESIS (OP) ÷ [0.3] -× 00B4 × 0308 × 0020 ÷ 0028 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] +× 00B4 × 0308 × 0028 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.04] LEFT PARENTHESIS (OP) ÷ [0.3] +× 00B4 × 0308 × 0020 ÷ 0028 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] × 00B4 × 0025 ÷ # × [0.3] ACUTE ACCENT (BB) × [21.04] PERCENT SIGN (PO) ÷ [0.3] × 00B4 × 0020 ÷ 0025 ÷ # × [0.3] ACUTE ACCENT (BB) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] -× 00B4 × 0308 × 0025 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM) × [21.04] PERCENT SIGN (PO) ÷ [0.3] -× 00B4 × 0308 × 0020 ÷ 0025 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] +× 00B4 × 0308 × 0025 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.04] PERCENT SIGN (PO) ÷ [0.3] +× 00B4 × 0308 × 0020 ÷ 0025 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] × 00B4 × 0024 ÷ # × [0.3] ACUTE ACCENT (BB) × [21.04] DOLLAR SIGN (PR) ÷ [0.3] × 00B4 × 0020 ÷ 0024 ÷ # × [0.3] ACUTE ACCENT (BB) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] -× 00B4 × 0308 × 0024 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM) × [21.04] DOLLAR SIGN (PR) ÷ [0.3] -× 00B4 × 0308 × 0020 ÷ 0024 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] +× 00B4 × 0308 × 0024 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.04] DOLLAR SIGN (PR) ÷ [0.3] +× 00B4 × 0308 × 0020 ÷ 0024 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] × 00B4 × 0022 ÷ # × [0.3] ACUTE ACCENT (BB) × [19.01] QUOTATION MARK (QU) ÷ [0.3] × 00B4 × 0020 ÷ 0022 ÷ # × [0.3] ACUTE ACCENT (BB) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] -× 00B4 × 0308 × 0022 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM) × [19.01] QUOTATION MARK (QU) ÷ [0.3] -× 00B4 × 0308 × 0020 ÷ 0022 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] +× 00B4 × 0308 × 0022 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [19.01] QUOTATION MARK (QU) ÷ [0.3] +× 00B4 × 0308 × 0020 ÷ 0022 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] × 00B4 × 0020 ÷ # × [0.3] ACUTE ACCENT (BB) × [7.01] SPACE (SP) ÷ [0.3] × 00B4 × 0020 × 0020 ÷ # × [0.3] ACUTE ACCENT (BB) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] -× 00B4 × 0308 × 0020 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [0.3] -× 00B4 × 0308 × 0020 × 0020 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] +× 00B4 × 0308 × 0020 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [0.3] +× 00B4 × 0308 × 0020 × 0020 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] × 00B4 × 002F ÷ # × [0.3] ACUTE ACCENT (BB) × [13.02] SOLIDUS (SY) ÷ [0.3] × 00B4 × 0020 × 002F ÷ # × [0.3] ACUTE ACCENT (BB) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] -× 00B4 × 0308 × 002F ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM) × [13.03] SOLIDUS (SY) ÷ [0.3] -× 00B4 × 0308 × 0020 × 002F ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] +× 00B4 × 0308 × 002F ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] SOLIDUS (SY) ÷ [0.3] +× 00B4 × 0308 × 0020 × 002F ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] × 00B4 × 2060 ÷ # × [0.3] ACUTE ACCENT (BB) × [11.01] WORD JOINER (WJ) ÷ [0.3] × 00B4 × 0020 × 2060 ÷ # × [0.3] ACUTE ACCENT (BB) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] -× 00B4 × 0308 × 2060 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM) × [11.01] WORD JOINER (WJ) ÷ [0.3] -× 00B4 × 0308 × 0020 × 2060 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] +× 00B4 × 0308 × 2060 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [11.01] WORD JOINER (WJ) ÷ [0.3] +× 00B4 × 0308 × 0020 × 2060 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] × 00B4 × 200B ÷ # × [0.3] ACUTE ACCENT (BB) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] × 00B4 × 0020 × 200B ÷ # × [0.3] ACUTE ACCENT (BB) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] -× 00B4 × 0308 × 200B ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] -× 00B4 × 0308 × 0020 × 200B ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] +× 00B4 × 0308 × 200B ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] +× 00B4 × 0308 × 0020 × 200B ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] × 00B4 × 1F1E6 ÷ # × [0.3] ACUTE ACCENT (BB) × [21.04] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] × 00B4 × 0020 ÷ 1F1E6 ÷ # × [0.3] ACUTE ACCENT (BB) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -× 00B4 × 0308 × 1F1E6 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM) × [21.04] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -× 00B4 × 0308 × 0020 ÷ 1F1E6 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 00B4 × 0308 × 1F1E6 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.04] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 00B4 × 0308 × 0020 ÷ 1F1E6 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 00B4 × 261D ÷ # × [0.3] ACUTE ACCENT (BB) × [21.04] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 00B4 × 0020 ÷ 261D ÷ # × [0.3] ACUTE ACCENT (BB) × [7.01] SPACE (SP) ÷ [18.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 00B4 × 0308 × 261D ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.04] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 00B4 × 0308 × 0020 ÷ 261D ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 00B4 × 1F3FB ÷ # × [0.3] ACUTE ACCENT (BB) × [21.04] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 00B4 × 0020 ÷ 1F3FB ÷ # × [0.3] ACUTE ACCENT (BB) × [7.01] SPACE (SP) ÷ [18.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 00B4 × 0308 × 1F3FB ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.04] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 00B4 × 0308 × 0020 ÷ 1F3FB ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 00B4 × 0001 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 00B4 × 0020 ÷ 0001 ÷ # × [0.3] ACUTE ACCENT (BB) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 00B4 × 0308 × 0001 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [9.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 00B4 × 0308 × 0020 ÷ 0001 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 00B4 × 200D ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 00B4 × 0020 ÷ 200D ÷ # × [0.3] ACUTE ACCENT (BB) × [7.01] SPACE (SP) ÷ [18.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 00B4 × 0308 × 200D ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [9.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 00B4 × 0308 × 0020 ÷ 200D ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] × 00B4 × 00A7 ÷ # × [0.3] ACUTE ACCENT (BB) × [21.04] SECTION SIGN (AI_AL) ÷ [0.3] × 00B4 × 0020 ÷ 00A7 ÷ # × [0.3] ACUTE ACCENT (BB) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] -× 00B4 × 0308 × 00A7 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM) × [21.04] SECTION SIGN (AI_AL) ÷ [0.3] -× 00B4 × 0308 × 0020 ÷ 00A7 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] +× 00B4 × 0308 × 00A7 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.04] SECTION SIGN (AI_AL) ÷ [0.3] +× 00B4 × 0308 × 0020 ÷ 00A7 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] × 00B4 × 50005 ÷ # × [0.3] ACUTE ACCENT (BB) × [21.04] <reserved-50005> (XX_AL) ÷ [0.3] × 00B4 × 0020 ÷ 50005 ÷ # × [0.3] ACUTE ACCENT (BB) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] -× 00B4 × 0308 × 50005 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM) × [21.04] <reserved-50005> (XX_AL) ÷ [0.3] -× 00B4 × 0308 × 0020 ÷ 50005 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] +× 00B4 × 0308 × 50005 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.04] <reserved-50005> (XX_AL) ÷ [0.3] +× 00B4 × 0308 × 0020 ÷ 50005 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] × 00B4 × 0E01 ÷ # × [0.3] ACUTE ACCENT (BB) × [21.04] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] × 00B4 × 0020 ÷ 0E01 ÷ # × [0.3] ACUTE ACCENT (BB) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] -× 00B4 × 0308 × 0E01 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM) × [21.04] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] -× 00B4 × 0308 × 0020 ÷ 0E01 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] +× 00B4 × 0308 × 0E01 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.04] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] +× 00B4 × 0308 × 0020 ÷ 0E01 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] × 00B4 × 3041 ÷ # × [0.3] ACUTE ACCENT (BB) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] × 00B4 × 0020 ÷ 3041 ÷ # × [0.3] ACUTE ACCENT (BB) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] -× 00B4 × 0308 × 3041 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] -× 00B4 × 0308 × 0020 ÷ 3041 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] +× 00B4 × 0308 × 3041 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] +× 00B4 × 0308 × 0020 ÷ 3041 ÷ # × [0.3] ACUTE ACCENT (BB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] × 000B ÷ 0023 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] NUMBER SIGN (AL) ÷ [0.3] × 000B ÷ 0020 ÷ 0023 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] -× 000B ÷ 0308 × 0023 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM) × [28.0] NUMBER SIGN (AL) ÷ [0.3] -× 000B ÷ 0308 × 0020 ÷ 0023 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] +× 000B ÷ 0308 × 0023 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM1_CM) × [28.0] NUMBER SIGN (AL) ÷ [0.3] +× 000B ÷ 0308 × 0020 ÷ 0023 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] × 000B ÷ 2014 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] EM DASH (B2) ÷ [0.3] × 000B ÷ 0020 ÷ 2014 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] -× 000B ÷ 0308 ÷ 2014 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM) ÷ [999.0] EM DASH (B2) ÷ [0.3] -× 000B ÷ 0308 × 0020 ÷ 2014 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] +× 000B ÷ 0308 ÷ 2014 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] EM DASH (B2) ÷ [0.3] +× 000B ÷ 0308 × 0020 ÷ 2014 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] × 000B ÷ 0009 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] <CHARACTER TABULATION> (BA) ÷ [0.3] × 000B ÷ 0020 ÷ 0009 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] -× 000B ÷ 0308 × 0009 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] -× 000B ÷ 0308 × 0020 ÷ 0009 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] +× 000B ÷ 0308 × 0009 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM1_CM) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] +× 000B ÷ 0308 × 0020 ÷ 0009 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] × 000B ÷ 00B4 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] ACUTE ACCENT (BB) ÷ [0.3] × 000B ÷ 0020 ÷ 00B4 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] -× 000B ÷ 0308 ÷ 00B4 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3] -× 000B ÷ 0308 × 0020 ÷ 00B4 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] +× 000B ÷ 0308 ÷ 00B4 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3] +× 000B ÷ 0308 × 0020 ÷ 00B4 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] × 000B ÷ 000B ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] <LINE TABULATION> (BK) ÷ [0.3] × 000B ÷ 0020 × 000B ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] -× 000B ÷ 0308 × 000B ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] -× 000B ÷ 0308 × 0020 × 000B ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] +× 000B ÷ 0308 × 000B ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] +× 000B ÷ 0308 × 0020 × 000B ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] × 000B ÷ FFFC ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] × 000B ÷ 0020 ÷ FFFC ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] -× 000B ÷ 0308 ÷ FFFC ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] -× 000B ÷ 0308 × 0020 ÷ FFFC ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] +× 000B ÷ 0308 ÷ FFFC ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM1_CM) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] +× 000B ÷ 0308 × 0020 ÷ FFFC ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] × 000B ÷ 007D ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] RIGHT CURLY BRACKET (CL) ÷ [0.3] × 000B ÷ 0020 × 007D ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] -× 000B ÷ 0308 × 007D ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM) × [13.03] RIGHT CURLY BRACKET (CL) ÷ [0.3] -× 000B ÷ 0308 × 0020 × 007D ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] +× 000B ÷ 0308 × 007D ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM1_CM) × [13.03] RIGHT CURLY BRACKET (CL) ÷ [0.3] +× 000B ÷ 0308 × 0020 × 007D ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] × 000B ÷ 0029 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] RIGHT PARENTHESIS (CP) ÷ [0.3] × 000B ÷ 0020 × 0029 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 000B ÷ 0308 × 0029 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM) × [13.03] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 000B ÷ 0308 × 0020 × 0029 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 000B ÷ 0001 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] <START OF HEADING> (CM) ÷ [0.3] -× 000B ÷ 0020 ÷ 0001 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM) ÷ [0.3] -× 000B ÷ 0308 × 0001 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM) × [9.0] <START OF HEADING> (CM) ÷ [0.3] -× 000B ÷ 0308 × 0020 ÷ 0001 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM) ÷ [0.3] +× 000B ÷ 0308 × 0029 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM1_CM) × [13.03] RIGHT PARENTHESIS (CP) ÷ [0.3] +× 000B ÷ 0308 × 0020 × 0029 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] × 000B ÷ 000D ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] × 000B ÷ 0020 × 000D ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -× 000B ÷ 0308 × 000D ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -× 000B ÷ 0308 × 0020 × 000D ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +× 000B ÷ 0308 × 000D ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +× 000B ÷ 0308 × 0020 × 000D ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] × 000B ÷ 0021 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] EXCLAMATION MARK (EX) ÷ [0.3] × 000B ÷ 0020 × 0021 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] -× 000B ÷ 0308 × 0021 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] -× 000B ÷ 0308 × 0020 × 0021 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] +× 000B ÷ 0308 × 0021 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM1_CM) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] +× 000B ÷ 0308 × 0020 × 0021 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] × 000B ÷ 00A0 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] NO-BREAK SPACE (GL) ÷ [0.3] × 000B ÷ 0020 ÷ 00A0 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] -× 000B ÷ 0308 × 00A0 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM) × [12.2] NO-BREAK SPACE (GL) ÷ [0.3] -× 000B ÷ 0308 × 0020 ÷ 00A0 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] +× 000B ÷ 0308 × 00A0 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM1_CM) × [12.2] NO-BREAK SPACE (GL) ÷ [0.3] +× 000B ÷ 0308 × 0020 ÷ 00A0 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] × 000B ÷ AC00 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] × 000B ÷ 0020 ÷ AC00 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] -× 000B ÷ 0308 ÷ AC00 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] -× 000B ÷ 0308 × 0020 ÷ AC00 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] +× 000B ÷ 0308 ÷ AC00 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] +× 000B ÷ 0308 × 0020 ÷ AC00 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] × 000B ÷ AC01 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] × 000B ÷ 0020 ÷ AC01 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] -× 000B ÷ 0308 ÷ AC01 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] -× 000B ÷ 0308 × 0020 ÷ AC01 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] +× 000B ÷ 0308 ÷ AC01 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] +× 000B ÷ 0308 × 0020 ÷ AC01 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] × 000B ÷ 05D0 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] HEBREW LETTER ALEF (HL) ÷ [0.3] × 000B ÷ 0020 ÷ 05D0 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] -× 000B ÷ 0308 × 05D0 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM) × [28.0] HEBREW LETTER ALEF (HL) ÷ [0.3] -× 000B ÷ 0308 × 0020 ÷ 05D0 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] +× 000B ÷ 0308 × 05D0 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM1_CM) × [28.0] HEBREW LETTER ALEF (HL) ÷ [0.3] +× 000B ÷ 0308 × 0020 ÷ 05D0 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] × 000B ÷ 002D ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] HYPHEN-MINUS (HY) ÷ [0.3] × 000B ÷ 0020 ÷ 002D ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] -× 000B ÷ 0308 × 002D ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] -× 000B ÷ 0308 × 0020 ÷ 002D ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] +× 000B ÷ 0308 × 002D ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM1_CM) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] +× 000B ÷ 0308 × 0020 ÷ 002D ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] × 000B ÷ 231A ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] WATCH (ID) ÷ [0.3] × 000B ÷ 0020 ÷ 231A ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] -× 000B ÷ 0308 ÷ 231A ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM) ÷ [999.0] WATCH (ID) ÷ [0.3] -× 000B ÷ 0308 × 0020 ÷ 231A ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] +× 000B ÷ 0308 ÷ 231A ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] WATCH (ID) ÷ [0.3] +× 000B ÷ 0308 × 0020 ÷ 231A ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] × 000B ÷ 2024 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] ONE DOT LEADER (IN) ÷ [0.3] × 000B ÷ 0020 ÷ 2024 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] -× 000B ÷ 0308 × 2024 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM) × [22.01] ONE DOT LEADER (IN) ÷ [0.3] -× 000B ÷ 0308 × 0020 ÷ 2024 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] +× 000B ÷ 0308 × 2024 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM1_CM) × [22.01] ONE DOT LEADER (IN) ÷ [0.3] +× 000B ÷ 0308 × 0020 ÷ 2024 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] × 000B ÷ 002C ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMMA (IS) ÷ [0.3] × 000B ÷ 0020 × 002C ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] -× 000B ÷ 0308 × 002C ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM) × [13.03] COMMA (IS) ÷ [0.3] -× 000B ÷ 0308 × 0020 × 002C ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] +× 000B ÷ 0308 × 002C ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM1_CM) × [13.03] COMMA (IS) ÷ [0.3] +× 000B ÷ 0308 × 0020 × 002C ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] × 000B ÷ 1100 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] × 000B ÷ 0020 ÷ 1100 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] -× 000B ÷ 0308 ÷ 1100 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] -× 000B ÷ 0308 × 0020 ÷ 1100 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] +× 000B ÷ 0308 ÷ 1100 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] +× 000B ÷ 0308 × 0020 ÷ 1100 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] × 000B ÷ 11A8 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] × 000B ÷ 0020 ÷ 11A8 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] -× 000B ÷ 0308 ÷ 11A8 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] -× 000B ÷ 0308 × 0020 ÷ 11A8 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] +× 000B ÷ 0308 ÷ 11A8 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] +× 000B ÷ 0308 × 0020 ÷ 11A8 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] × 000B ÷ 1160 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] × 000B ÷ 0020 ÷ 1160 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] -× 000B ÷ 0308 ÷ 1160 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] -× 000B ÷ 0308 × 0020 ÷ 1160 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] +× 000B ÷ 0308 ÷ 1160 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] +× 000B ÷ 0308 × 0020 ÷ 1160 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] × 000B ÷ 000A ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] <LINE FEED (LF)> (LF) ÷ [0.3] × 000B ÷ 0020 × 000A ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] -× 000B ÷ 0308 × 000A ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] -× 000B ÷ 0308 × 0020 × 000A ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] +× 000B ÷ 0308 × 000A ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] +× 000B ÷ 0308 × 0020 × 000A ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] × 000B ÷ 0085 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] × 000B ÷ 0020 × 0085 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] -× 000B ÷ 0308 × 0085 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] -× 000B ÷ 0308 × 0020 × 0085 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] +× 000B ÷ 0308 × 0085 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] +× 000B ÷ 0308 × 0020 × 0085 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] × 000B ÷ 17D6 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] × 000B ÷ 0020 ÷ 17D6 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] -× 000B ÷ 0308 × 17D6 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] -× 000B ÷ 0308 × 0020 ÷ 17D6 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] +× 000B ÷ 0308 × 17D6 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM1_CM) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] +× 000B ÷ 0308 × 0020 ÷ 17D6 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] × 000B ÷ 0030 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] DIGIT ZERO (NU) ÷ [0.3] × 000B ÷ 0020 ÷ 0030 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] -× 000B ÷ 0308 × 0030 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM) × [23.02] DIGIT ZERO (NU) ÷ [0.3] -× 000B ÷ 0308 × 0020 ÷ 0030 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] +× 000B ÷ 0308 × 0030 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM1_CM) × [23.02] DIGIT ZERO (NU) ÷ [0.3] +× 000B ÷ 0308 × 0020 ÷ 0030 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] × 000B ÷ 0028 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] LEFT PARENTHESIS (OP) ÷ [0.3] × 000B ÷ 0020 ÷ 0028 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] -× 000B ÷ 0308 × 0028 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM) × [30.01] LEFT PARENTHESIS (OP) ÷ [0.3] -× 000B ÷ 0308 × 0020 ÷ 0028 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] +× 000B ÷ 0308 × 0028 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM1_CM) × [30.01] LEFT PARENTHESIS (OP) ÷ [0.3] +× 000B ÷ 0308 × 0020 ÷ 0028 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] × 000B ÷ 0025 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] PERCENT SIGN (PO) ÷ [0.3] × 000B ÷ 0020 ÷ 0025 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] -× 000B ÷ 0308 ÷ 0025 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM) ÷ [999.0] PERCENT SIGN (PO) ÷ [0.3] -× 000B ÷ 0308 × 0020 ÷ 0025 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] +× 000B ÷ 0308 × 0025 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM1_CM) × [24.03] PERCENT SIGN (PO) ÷ [0.3] +× 000B ÷ 0308 × 0020 ÷ 0025 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] × 000B ÷ 0024 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] DOLLAR SIGN (PR) ÷ [0.3] × 000B ÷ 0020 ÷ 0024 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] -× 000B ÷ 0308 ÷ 0024 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM) ÷ [999.0] DOLLAR SIGN (PR) ÷ [0.3] -× 000B ÷ 0308 × 0020 ÷ 0024 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] +× 000B ÷ 0308 × 0024 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM1_CM) × [24.03] DOLLAR SIGN (PR) ÷ [0.3] +× 000B ÷ 0308 × 0020 ÷ 0024 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] × 000B ÷ 0022 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] QUOTATION MARK (QU) ÷ [0.3] × 000B ÷ 0020 ÷ 0022 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] -× 000B ÷ 0308 × 0022 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM) × [19.01] QUOTATION MARK (QU) ÷ [0.3] -× 000B ÷ 0308 × 0020 ÷ 0022 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] +× 000B ÷ 0308 × 0022 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM1_CM) × [19.01] QUOTATION MARK (QU) ÷ [0.3] +× 000B ÷ 0308 × 0020 ÷ 0022 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] × 000B ÷ 0020 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] SPACE (SP) ÷ [0.3] × 000B ÷ 0020 × 0020 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] -× 000B ÷ 0308 × 0020 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [0.3] -× 000B ÷ 0308 × 0020 × 0020 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] +× 000B ÷ 0308 × 0020 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [0.3] +× 000B ÷ 0308 × 0020 × 0020 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] × 000B ÷ 002F ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] SOLIDUS (SY) ÷ [0.3] × 000B ÷ 0020 × 002F ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] -× 000B ÷ 0308 × 002F ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM) × [13.03] SOLIDUS (SY) ÷ [0.3] -× 000B ÷ 0308 × 0020 × 002F ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] +× 000B ÷ 0308 × 002F ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM1_CM) × [13.03] SOLIDUS (SY) ÷ [0.3] +× 000B ÷ 0308 × 0020 × 002F ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] × 000B ÷ 2060 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] WORD JOINER (WJ) ÷ [0.3] × 000B ÷ 0020 × 2060 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] -× 000B ÷ 0308 × 2060 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM) × [11.01] WORD JOINER (WJ) ÷ [0.3] -× 000B ÷ 0308 × 0020 × 2060 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] +× 000B ÷ 0308 × 2060 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM1_CM) × [11.01] WORD JOINER (WJ) ÷ [0.3] +× 000B ÷ 0308 × 0020 × 2060 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] × 000B ÷ 200B ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] ZERO WIDTH SPACE (ZW) ÷ [0.3] × 000B ÷ 0020 × 200B ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] -× 000B ÷ 0308 × 200B ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] -× 000B ÷ 0308 × 0020 × 200B ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] +× 000B ÷ 0308 × 200B ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM1_CM) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] +× 000B ÷ 0308 × 0020 × 200B ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] × 000B ÷ 1F1E6 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] × 000B ÷ 0020 ÷ 1F1E6 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -× 000B ÷ 0308 ÷ 1F1E6 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -× 000B ÷ 0308 × 0020 ÷ 1F1E6 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 000B ÷ 0308 ÷ 1F1E6 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 000B ÷ 0308 × 0020 ÷ 1F1E6 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 000B ÷ 261D ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 000B ÷ 0020 ÷ 261D ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] SPACE (SP) ÷ [18.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 000B ÷ 0308 ÷ 261D ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 000B ÷ 0308 × 0020 ÷ 261D ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 000B ÷ 1F3FB ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 000B ÷ 0020 ÷ 1F3FB ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] SPACE (SP) ÷ [18.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 000B ÷ 0308 ÷ 1F3FB ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 000B ÷ 0308 × 0020 ÷ 1F3FB ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 000B ÷ 0001 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 000B ÷ 0020 ÷ 0001 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 000B ÷ 0308 × 0001 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM1_CM) × [9.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 000B ÷ 0308 × 0020 ÷ 0001 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 000B ÷ 200D ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 000B ÷ 0020 ÷ 200D ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] SPACE (SP) ÷ [18.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 000B ÷ 0308 × 200D ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM1_CM) × [9.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 000B ÷ 0308 × 0020 ÷ 200D ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] × 000B ÷ 00A7 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] SECTION SIGN (AI_AL) ÷ [0.3] × 000B ÷ 0020 ÷ 00A7 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] -× 000B ÷ 0308 × 00A7 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM) × [28.0] SECTION SIGN (AI_AL) ÷ [0.3] -× 000B ÷ 0308 × 0020 ÷ 00A7 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] +× 000B ÷ 0308 × 00A7 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM1_CM) × [28.0] SECTION SIGN (AI_AL) ÷ [0.3] +× 000B ÷ 0308 × 0020 ÷ 00A7 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] × 000B ÷ 50005 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] <reserved-50005> (XX_AL) ÷ [0.3] × 000B ÷ 0020 ÷ 50005 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] -× 000B ÷ 0308 × 50005 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM) × [28.0] <reserved-50005> (XX_AL) ÷ [0.3] -× 000B ÷ 0308 × 0020 ÷ 50005 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] +× 000B ÷ 0308 × 50005 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM1_CM) × [28.0] <reserved-50005> (XX_AL) ÷ [0.3] +× 000B ÷ 0308 × 0020 ÷ 50005 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] × 000B ÷ 0E01 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] × 000B ÷ 0020 ÷ 0E01 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] -× 000B ÷ 0308 × 0E01 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM) × [28.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] -× 000B ÷ 0308 × 0020 ÷ 0E01 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] +× 000B ÷ 0308 × 0E01 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM1_CM) × [28.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] +× 000B ÷ 0308 × 0020 ÷ 0E01 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] × 000B ÷ 3041 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] × 000B ÷ 0020 ÷ 3041 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] -× 000B ÷ 0308 × 3041 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] -× 000B ÷ 0308 × 0020 ÷ 3041 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] +× 000B ÷ 0308 × 3041 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM1_CM) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] +× 000B ÷ 0308 × 0020 ÷ 3041 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] × FFFC ÷ 0023 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) ÷ [20.02] NUMBER SIGN (AL) ÷ [0.3] × FFFC × 0020 ÷ 0023 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] -× FFFC × 0308 ÷ 0023 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM) ÷ [20.02] NUMBER SIGN (AL) ÷ [0.3] -× FFFC × 0308 × 0020 ÷ 0023 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] +× FFFC × 0308 ÷ 0023 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [20.02] NUMBER SIGN (AL) ÷ [0.3] +× FFFC × 0308 × 0020 ÷ 0023 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] × FFFC ÷ 2014 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) ÷ [20.02] EM DASH (B2) ÷ [0.3] × FFFC × 0020 ÷ 2014 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] -× FFFC × 0308 ÷ 2014 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM) ÷ [20.02] EM DASH (B2) ÷ [0.3] -× FFFC × 0308 × 0020 ÷ 2014 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] +× FFFC × 0308 ÷ 2014 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [20.02] EM DASH (B2) ÷ [0.3] +× FFFC × 0308 × 0020 ÷ 2014 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] × FFFC ÷ 0009 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) ÷ [20.02] <CHARACTER TABULATION> (BA) ÷ [0.3] × FFFC × 0020 ÷ 0009 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] -× FFFC × 0308 ÷ 0009 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM) ÷ [20.02] <CHARACTER TABULATION> (BA) ÷ [0.3] -× FFFC × 0308 × 0020 ÷ 0009 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] +× FFFC × 0308 ÷ 0009 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [20.02] <CHARACTER TABULATION> (BA) ÷ [0.3] +× FFFC × 0308 × 0020 ÷ 0009 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] × FFFC ÷ 00B4 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) ÷ [20.02] ACUTE ACCENT (BB) ÷ [0.3] × FFFC × 0020 ÷ 00B4 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] -× FFFC × 0308 ÷ 00B4 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM) ÷ [20.02] ACUTE ACCENT (BB) ÷ [0.3] -× FFFC × 0308 × 0020 ÷ 00B4 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] +× FFFC × 0308 ÷ 00B4 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [20.02] ACUTE ACCENT (BB) ÷ [0.3] +× FFFC × 0308 × 0020 ÷ 00B4 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] × FFFC × 000B ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] × FFFC × 0020 × 000B ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] -× FFFC × 0308 × 000B ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] -× FFFC × 0308 × 0020 × 000B ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] +× FFFC × 0308 × 000B ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] +× FFFC × 0308 × 0020 × 000B ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] × FFFC ÷ FFFC ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] × FFFC × 0020 ÷ FFFC ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] -× FFFC × 0308 ÷ FFFC ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] -× FFFC × 0308 × 0020 ÷ FFFC ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] +× FFFC × 0308 ÷ FFFC ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] +× FFFC × 0308 × 0020 ÷ FFFC ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] × FFFC × 007D ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] × FFFC × 0020 × 007D ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] -× FFFC × 0308 × 007D ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM) × [13.03] RIGHT CURLY BRACKET (CL) ÷ [0.3] -× FFFC × 0308 × 0020 × 007D ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] +× FFFC × 0308 × 007D ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] RIGHT CURLY BRACKET (CL) ÷ [0.3] +× FFFC × 0308 × 0020 × 007D ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] × FFFC × 0029 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] × FFFC × 0020 × 0029 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] -× FFFC × 0308 × 0029 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM) × [13.03] RIGHT PARENTHESIS (CP) ÷ [0.3] -× FFFC × 0308 × 0020 × 0029 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] -× FFFC × 0001 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] <START OF HEADING> (CM) ÷ [0.3] -× FFFC × 0020 ÷ 0001 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM) ÷ [0.3] -× FFFC × 0308 × 0001 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM) × [9.0] <START OF HEADING> (CM) ÷ [0.3] -× FFFC × 0308 × 0020 ÷ 0001 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM) ÷ [0.3] +× FFFC × 0308 × 0029 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] RIGHT PARENTHESIS (CP) ÷ [0.3] +× FFFC × 0308 × 0020 × 0029 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] × FFFC × 000D ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] × FFFC × 0020 × 000D ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -× FFFC × 0308 × 000D ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -× FFFC × 0308 × 0020 × 000D ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +× FFFC × 0308 × 000D ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +× FFFC × 0308 × 0020 × 000D ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] × FFFC × 0021 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] × FFFC × 0020 × 0021 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] -× FFFC × 0308 × 0021 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] -× FFFC × 0308 × 0020 × 0021 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] +× FFFC × 0308 × 0021 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] +× FFFC × 0308 × 0020 × 0021 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] × FFFC × 00A0 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [12.1] NO-BREAK SPACE (GL) ÷ [0.3] × FFFC × 0020 ÷ 00A0 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] -× FFFC × 0308 × 00A0 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM) × [12.2] NO-BREAK SPACE (GL) ÷ [0.3] -× FFFC × 0308 × 0020 ÷ 00A0 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] +× FFFC × 0308 × 00A0 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [12.2] NO-BREAK SPACE (GL) ÷ [0.3] +× FFFC × 0308 × 0020 ÷ 00A0 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] × FFFC ÷ AC00 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) ÷ [20.02] HANGUL SYLLABLE GA (H2) ÷ [0.3] × FFFC × 0020 ÷ AC00 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] -× FFFC × 0308 ÷ AC00 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM) ÷ [20.02] HANGUL SYLLABLE GA (H2) ÷ [0.3] -× FFFC × 0308 × 0020 ÷ AC00 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] +× FFFC × 0308 ÷ AC00 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [20.02] HANGUL SYLLABLE GA (H2) ÷ [0.3] +× FFFC × 0308 × 0020 ÷ AC00 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] × FFFC ÷ AC01 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) ÷ [20.02] HANGUL SYLLABLE GAG (H3) ÷ [0.3] × FFFC × 0020 ÷ AC01 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] -× FFFC × 0308 ÷ AC01 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM) ÷ [20.02] HANGUL SYLLABLE GAG (H3) ÷ [0.3] -× FFFC × 0308 × 0020 ÷ AC01 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] +× FFFC × 0308 ÷ AC01 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [20.02] HANGUL SYLLABLE GAG (H3) ÷ [0.3] +× FFFC × 0308 × 0020 ÷ AC01 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] × FFFC ÷ 05D0 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) ÷ [20.02] HEBREW LETTER ALEF (HL) ÷ [0.3] × FFFC × 0020 ÷ 05D0 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] -× FFFC × 0308 ÷ 05D0 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM) ÷ [20.02] HEBREW LETTER ALEF (HL) ÷ [0.3] -× FFFC × 0308 × 0020 ÷ 05D0 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] +× FFFC × 0308 ÷ 05D0 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [20.02] HEBREW LETTER ALEF (HL) ÷ [0.3] +× FFFC × 0308 × 0020 ÷ 05D0 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] × FFFC ÷ 002D ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) ÷ [20.02] HYPHEN-MINUS (HY) ÷ [0.3] × FFFC × 0020 ÷ 002D ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] -× FFFC × 0308 ÷ 002D ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM) ÷ [20.02] HYPHEN-MINUS (HY) ÷ [0.3] -× FFFC × 0308 × 0020 ÷ 002D ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] +× FFFC × 0308 ÷ 002D ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [20.02] HYPHEN-MINUS (HY) ÷ [0.3] +× FFFC × 0308 × 0020 ÷ 002D ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] × FFFC ÷ 231A ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) ÷ [20.02] WATCH (ID) ÷ [0.3] × FFFC × 0020 ÷ 231A ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] -× FFFC × 0308 ÷ 231A ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM) ÷ [20.02] WATCH (ID) ÷ [0.3] -× FFFC × 0308 × 0020 ÷ 231A ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] +× FFFC × 0308 ÷ 231A ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [20.02] WATCH (ID) ÷ [0.3] +× FFFC × 0308 × 0020 ÷ 231A ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] × FFFC ÷ 2024 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) ÷ [20.02] ONE DOT LEADER (IN) ÷ [0.3] × FFFC × 0020 ÷ 2024 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] -× FFFC × 0308 ÷ 2024 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM) ÷ [20.02] ONE DOT LEADER (IN) ÷ [0.3] -× FFFC × 0308 × 0020 ÷ 2024 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] +× FFFC × 0308 ÷ 2024 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [20.02] ONE DOT LEADER (IN) ÷ [0.3] +× FFFC × 0308 × 0020 ÷ 2024 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] × FFFC × 002C ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [13.02] COMMA (IS) ÷ [0.3] × FFFC × 0020 × 002C ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] -× FFFC × 0308 × 002C ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM) × [13.03] COMMA (IS) ÷ [0.3] -× FFFC × 0308 × 0020 × 002C ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] +× FFFC × 0308 × 002C ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] COMMA (IS) ÷ [0.3] +× FFFC × 0308 × 0020 × 002C ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] × FFFC ÷ 1100 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) ÷ [20.02] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] × FFFC × 0020 ÷ 1100 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] -× FFFC × 0308 ÷ 1100 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM) ÷ [20.02] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] -× FFFC × 0308 × 0020 ÷ 1100 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] +× FFFC × 0308 ÷ 1100 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [20.02] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] +× FFFC × 0308 × 0020 ÷ 1100 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] × FFFC ÷ 11A8 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) ÷ [20.02] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] × FFFC × 0020 ÷ 11A8 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] -× FFFC × 0308 ÷ 11A8 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM) ÷ [20.02] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] -× FFFC × 0308 × 0020 ÷ 11A8 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] +× FFFC × 0308 ÷ 11A8 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [20.02] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] +× FFFC × 0308 × 0020 ÷ 11A8 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] × FFFC ÷ 1160 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) ÷ [20.02] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] × FFFC × 0020 ÷ 1160 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] -× FFFC × 0308 ÷ 1160 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM) ÷ [20.02] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] -× FFFC × 0308 × 0020 ÷ 1160 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] +× FFFC × 0308 ÷ 1160 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [20.02] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] +× FFFC × 0308 × 0020 ÷ 1160 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] × FFFC × 000A ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] × FFFC × 0020 × 000A ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] -× FFFC × 0308 × 000A ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] -× FFFC × 0308 × 0020 × 000A ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] +× FFFC × 0308 × 000A ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] +× FFFC × 0308 × 0020 × 000A ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] × FFFC × 0085 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] × FFFC × 0020 × 0085 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] -× FFFC × 0308 × 0085 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] -× FFFC × 0308 × 0020 × 0085 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] +× FFFC × 0308 × 0085 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] +× FFFC × 0308 × 0020 × 0085 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] × FFFC ÷ 17D6 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) ÷ [20.02] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] × FFFC × 0020 ÷ 17D6 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] -× FFFC × 0308 ÷ 17D6 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM) ÷ [20.02] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] -× FFFC × 0308 × 0020 ÷ 17D6 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] +× FFFC × 0308 ÷ 17D6 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [20.02] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] +× FFFC × 0308 × 0020 ÷ 17D6 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] × FFFC ÷ 0030 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) ÷ [20.02] DIGIT ZERO (NU) ÷ [0.3] × FFFC × 0020 ÷ 0030 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] -× FFFC × 0308 ÷ 0030 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM) ÷ [20.02] DIGIT ZERO (NU) ÷ [0.3] -× FFFC × 0308 × 0020 ÷ 0030 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] +× FFFC × 0308 ÷ 0030 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [20.02] DIGIT ZERO (NU) ÷ [0.3] +× FFFC × 0308 × 0020 ÷ 0030 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] × FFFC ÷ 0028 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) ÷ [20.02] LEFT PARENTHESIS (OP) ÷ [0.3] × FFFC × 0020 ÷ 0028 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] -× FFFC × 0308 ÷ 0028 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM) ÷ [20.02] LEFT PARENTHESIS (OP) ÷ [0.3] -× FFFC × 0308 × 0020 ÷ 0028 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] +× FFFC × 0308 ÷ 0028 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [20.02] LEFT PARENTHESIS (OP) ÷ [0.3] +× FFFC × 0308 × 0020 ÷ 0028 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] × FFFC ÷ 0025 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) ÷ [20.02] PERCENT SIGN (PO) ÷ [0.3] × FFFC × 0020 ÷ 0025 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] -× FFFC × 0308 ÷ 0025 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM) ÷ [20.02] PERCENT SIGN (PO) ÷ [0.3] -× FFFC × 0308 × 0020 ÷ 0025 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] +× FFFC × 0308 ÷ 0025 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [20.02] PERCENT SIGN (PO) ÷ [0.3] +× FFFC × 0308 × 0020 ÷ 0025 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] × FFFC ÷ 0024 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) ÷ [20.02] DOLLAR SIGN (PR) ÷ [0.3] × FFFC × 0020 ÷ 0024 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] -× FFFC × 0308 ÷ 0024 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM) ÷ [20.02] DOLLAR SIGN (PR) ÷ [0.3] -× FFFC × 0308 × 0020 ÷ 0024 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] +× FFFC × 0308 ÷ 0024 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [20.02] DOLLAR SIGN (PR) ÷ [0.3] +× FFFC × 0308 × 0020 ÷ 0024 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] × FFFC × 0022 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [19.01] QUOTATION MARK (QU) ÷ [0.3] × FFFC × 0020 ÷ 0022 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] -× FFFC × 0308 × 0022 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM) × [19.01] QUOTATION MARK (QU) ÷ [0.3] -× FFFC × 0308 × 0020 ÷ 0022 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] +× FFFC × 0308 × 0022 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [19.01] QUOTATION MARK (QU) ÷ [0.3] +× FFFC × 0308 × 0020 ÷ 0022 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] × FFFC × 0020 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [7.01] SPACE (SP) ÷ [0.3] × FFFC × 0020 × 0020 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] -× FFFC × 0308 × 0020 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [0.3] -× FFFC × 0308 × 0020 × 0020 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] +× FFFC × 0308 × 0020 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [0.3] +× FFFC × 0308 × 0020 × 0020 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] × FFFC × 002F ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [13.02] SOLIDUS (SY) ÷ [0.3] × FFFC × 0020 × 002F ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] -× FFFC × 0308 × 002F ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM) × [13.03] SOLIDUS (SY) ÷ [0.3] -× FFFC × 0308 × 0020 × 002F ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] +× FFFC × 0308 × 002F ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] SOLIDUS (SY) ÷ [0.3] +× FFFC × 0308 × 0020 × 002F ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] × FFFC × 2060 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [11.01] WORD JOINER (WJ) ÷ [0.3] × FFFC × 0020 × 2060 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] -× FFFC × 0308 × 2060 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM) × [11.01] WORD JOINER (WJ) ÷ [0.3] -× FFFC × 0308 × 0020 × 2060 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] +× FFFC × 0308 × 2060 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [11.01] WORD JOINER (WJ) ÷ [0.3] +× FFFC × 0308 × 0020 × 2060 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] × FFFC × 200B ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] × FFFC × 0020 × 200B ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] -× FFFC × 0308 × 200B ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] -× FFFC × 0308 × 0020 × 200B ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] +× FFFC × 0308 × 200B ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] +× FFFC × 0308 × 0020 × 200B ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] × FFFC ÷ 1F1E6 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) ÷ [20.02] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] × FFFC × 0020 ÷ 1F1E6 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -× FFFC × 0308 ÷ 1F1E6 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM) ÷ [20.02] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -× FFFC × 0308 × 0020 ÷ 1F1E6 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× FFFC × 0308 ÷ 1F1E6 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [20.02] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× FFFC × 0308 × 0020 ÷ 1F1E6 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× FFFC ÷ 261D ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) ÷ [20.02] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× FFFC × 0020 ÷ 261D ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [7.01] SPACE (SP) ÷ [18.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× FFFC × 0308 ÷ 261D ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [20.02] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× FFFC × 0308 × 0020 ÷ 261D ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× FFFC ÷ 1F3FB ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) ÷ [20.02] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× FFFC × 0020 ÷ 1F3FB ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [7.01] SPACE (SP) ÷ [18.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× FFFC × 0308 ÷ 1F3FB ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [20.02] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× FFFC × 0308 × 0020 ÷ 1F3FB ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× FFFC × 0001 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× FFFC × 0020 ÷ 0001 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× FFFC × 0308 × 0001 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [9.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× FFFC × 0308 × 0020 ÷ 0001 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× FFFC × 200D ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× FFFC × 0020 ÷ 200D ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [7.01] SPACE (SP) ÷ [18.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× FFFC × 0308 × 200D ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [9.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× FFFC × 0308 × 0020 ÷ 200D ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] × FFFC ÷ 00A7 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) ÷ [20.02] SECTION SIGN (AI_AL) ÷ [0.3] × FFFC × 0020 ÷ 00A7 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] -× FFFC × 0308 ÷ 00A7 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM) ÷ [20.02] SECTION SIGN (AI_AL) ÷ [0.3] -× FFFC × 0308 × 0020 ÷ 00A7 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] +× FFFC × 0308 ÷ 00A7 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [20.02] SECTION SIGN (AI_AL) ÷ [0.3] +× FFFC × 0308 × 0020 ÷ 00A7 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] × FFFC ÷ 50005 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) ÷ [20.02] <reserved-50005> (XX_AL) ÷ [0.3] × FFFC × 0020 ÷ 50005 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] -× FFFC × 0308 ÷ 50005 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM) ÷ [20.02] <reserved-50005> (XX_AL) ÷ [0.3] -× FFFC × 0308 × 0020 ÷ 50005 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] +× FFFC × 0308 ÷ 50005 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [20.02] <reserved-50005> (XX_AL) ÷ [0.3] +× FFFC × 0308 × 0020 ÷ 50005 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] × FFFC ÷ 0E01 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) ÷ [20.02] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] × FFFC × 0020 ÷ 0E01 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] -× FFFC × 0308 ÷ 0E01 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM) ÷ [20.02] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] -× FFFC × 0308 × 0020 ÷ 0E01 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] +× FFFC × 0308 ÷ 0E01 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [20.02] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] +× FFFC × 0308 × 0020 ÷ 0E01 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] × FFFC ÷ 3041 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) ÷ [20.02] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] × FFFC × 0020 ÷ 3041 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] -× FFFC × 0308 ÷ 3041 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM) ÷ [20.02] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] -× FFFC × 0308 × 0020 ÷ 3041 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] +× FFFC × 0308 ÷ 3041 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [20.02] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] +× FFFC × 0308 × 0020 ÷ 3041 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] × 007D ÷ 0023 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) ÷ [999.0] NUMBER SIGN (AL) ÷ [0.3] × 007D × 0020 ÷ 0023 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] -× 007D × 0308 ÷ 0023 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] NUMBER SIGN (AL) ÷ [0.3] -× 007D × 0308 × 0020 ÷ 0023 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] +× 007D × 0308 ÷ 0023 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] NUMBER SIGN (AL) ÷ [0.3] +× 007D × 0308 × 0020 ÷ 0023 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] × 007D ÷ 2014 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) ÷ [999.0] EM DASH (B2) ÷ [0.3] × 007D × 0020 ÷ 2014 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] -× 007D × 0308 ÷ 2014 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] EM DASH (B2) ÷ [0.3] -× 007D × 0308 × 0020 ÷ 2014 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] +× 007D × 0308 ÷ 2014 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] EM DASH (B2) ÷ [0.3] +× 007D × 0308 × 0020 ÷ 2014 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] × 007D × 0009 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] × 007D × 0020 ÷ 0009 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] -× 007D × 0308 × 0009 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] -× 007D × 0308 × 0020 ÷ 0009 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] +× 007D × 0308 × 0009 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] +× 007D × 0308 × 0020 ÷ 0009 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] × 007D ÷ 00B4 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3] × 007D × 0020 ÷ 00B4 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] -× 007D × 0308 ÷ 00B4 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3] -× 007D × 0308 × 0020 ÷ 00B4 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] +× 007D × 0308 ÷ 00B4 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3] +× 007D × 0308 × 0020 ÷ 00B4 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] × 007D × 000B ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] × 007D × 0020 × 000B ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] -× 007D × 0308 × 000B ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] -× 007D × 0308 × 0020 × 000B ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] +× 007D × 0308 × 000B ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] +× 007D × 0308 × 0020 × 000B ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] × 007D ÷ FFFC ÷ # × [0.3] RIGHT CURLY BRACKET (CL) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] × 007D × 0020 ÷ FFFC ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] -× 007D × 0308 ÷ FFFC ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] -× 007D × 0308 × 0020 ÷ FFFC ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] +× 007D × 0308 ÷ FFFC ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] +× 007D × 0308 × 0020 ÷ FFFC ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] × 007D × 007D ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] × 007D × 0020 × 007D ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] -× 007D × 0308 × 007D ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM) × [13.03] RIGHT CURLY BRACKET (CL) ÷ [0.3] -× 007D × 0308 × 0020 × 007D ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] +× 007D × 0308 × 007D ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] RIGHT CURLY BRACKET (CL) ÷ [0.3] +× 007D × 0308 × 0020 × 007D ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] × 007D × 0029 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] × 007D × 0020 × 0029 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 007D × 0308 × 0029 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM) × [13.03] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 007D × 0308 × 0020 × 0029 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 007D × 0001 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] <START OF HEADING> (CM) ÷ [0.3] -× 007D × 0020 ÷ 0001 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM) ÷ [0.3] -× 007D × 0308 × 0001 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM) × [9.0] <START OF HEADING> (CM) ÷ [0.3] -× 007D × 0308 × 0020 ÷ 0001 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM) ÷ [0.3] +× 007D × 0308 × 0029 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] RIGHT PARENTHESIS (CP) ÷ [0.3] +× 007D × 0308 × 0020 × 0029 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] × 007D × 000D ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] × 007D × 0020 × 000D ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -× 007D × 0308 × 000D ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -× 007D × 0308 × 0020 × 000D ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +× 007D × 0308 × 000D ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +× 007D × 0308 × 0020 × 000D ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] × 007D × 0021 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] × 007D × 0020 × 0021 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] -× 007D × 0308 × 0021 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] -× 007D × 0308 × 0020 × 0021 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] +× 007D × 0308 × 0021 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] +× 007D × 0308 × 0020 × 0021 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] × 007D × 00A0 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [12.1] NO-BREAK SPACE (GL) ÷ [0.3] × 007D × 0020 ÷ 00A0 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] -× 007D × 0308 × 00A0 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM) × [12.2] NO-BREAK SPACE (GL) ÷ [0.3] -× 007D × 0308 × 0020 ÷ 00A0 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] +× 007D × 0308 × 00A0 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [12.2] NO-BREAK SPACE (GL) ÷ [0.3] +× 007D × 0308 × 0020 ÷ 00A0 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] × 007D ÷ AC00 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) ÷ [999.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] × 007D × 0020 ÷ AC00 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] -× 007D × 0308 ÷ AC00 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] -× 007D × 0308 × 0020 ÷ AC00 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] +× 007D × 0308 ÷ AC00 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] +× 007D × 0308 × 0020 ÷ AC00 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] × 007D ÷ AC01 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) ÷ [999.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] × 007D × 0020 ÷ AC01 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] -× 007D × 0308 ÷ AC01 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] -× 007D × 0308 × 0020 ÷ AC01 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] +× 007D × 0308 ÷ AC01 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] +× 007D × 0308 × 0020 ÷ AC01 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] × 007D ÷ 05D0 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) ÷ [999.0] HEBREW LETTER ALEF (HL) ÷ [0.3] × 007D × 0020 ÷ 05D0 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] -× 007D × 0308 ÷ 05D0 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HEBREW LETTER ALEF (HL) ÷ [0.3] -× 007D × 0308 × 0020 ÷ 05D0 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] +× 007D × 0308 ÷ 05D0 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HEBREW LETTER ALEF (HL) ÷ [0.3] +× 007D × 0308 × 0020 ÷ 05D0 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] × 007D × 002D ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] × 007D × 0020 ÷ 002D ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] -× 007D × 0308 × 002D ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] -× 007D × 0308 × 0020 ÷ 002D ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] +× 007D × 0308 × 002D ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] +× 007D × 0308 × 0020 ÷ 002D ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] × 007D ÷ 231A ÷ # × [0.3] RIGHT CURLY BRACKET (CL) ÷ [999.0] WATCH (ID) ÷ [0.3] × 007D × 0020 ÷ 231A ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] -× 007D × 0308 ÷ 231A ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] WATCH (ID) ÷ [0.3] -× 007D × 0308 × 0020 ÷ 231A ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] +× 007D × 0308 ÷ 231A ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] WATCH (ID) ÷ [0.3] +× 007D × 0308 × 0020 ÷ 231A ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] × 007D ÷ 2024 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) ÷ [999.0] ONE DOT LEADER (IN) ÷ [0.3] × 007D × 0020 ÷ 2024 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] -× 007D × 0308 ÷ 2024 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] ONE DOT LEADER (IN) ÷ [0.3] -× 007D × 0308 × 0020 ÷ 2024 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] +× 007D × 0308 ÷ 2024 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] ONE DOT LEADER (IN) ÷ [0.3] +× 007D × 0308 × 0020 ÷ 2024 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] × 007D × 002C ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [13.02] COMMA (IS) ÷ [0.3] × 007D × 0020 × 002C ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] -× 007D × 0308 × 002C ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM) × [13.03] COMMA (IS) ÷ [0.3] -× 007D × 0308 × 0020 × 002C ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] +× 007D × 0308 × 002C ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] COMMA (IS) ÷ [0.3] +× 007D × 0308 × 0020 × 002C ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] × 007D ÷ 1100 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) ÷ [999.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] × 007D × 0020 ÷ 1100 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] -× 007D × 0308 ÷ 1100 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] -× 007D × 0308 × 0020 ÷ 1100 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] +× 007D × 0308 ÷ 1100 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] +× 007D × 0308 × 0020 ÷ 1100 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] × 007D ÷ 11A8 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) ÷ [999.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] × 007D × 0020 ÷ 11A8 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] -× 007D × 0308 ÷ 11A8 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] -× 007D × 0308 × 0020 ÷ 11A8 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] +× 007D × 0308 ÷ 11A8 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] +× 007D × 0308 × 0020 ÷ 11A8 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] × 007D ÷ 1160 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) ÷ [999.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] × 007D × 0020 ÷ 1160 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] -× 007D × 0308 ÷ 1160 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] -× 007D × 0308 × 0020 ÷ 1160 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] +× 007D × 0308 ÷ 1160 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] +× 007D × 0308 × 0020 ÷ 1160 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] × 007D × 000A ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] × 007D × 0020 × 000A ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] -× 007D × 0308 × 000A ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] -× 007D × 0308 × 0020 × 000A ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] +× 007D × 0308 × 000A ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] +× 007D × 0308 × 0020 × 000A ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] × 007D × 0085 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] × 007D × 0020 × 0085 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] -× 007D × 0308 × 0085 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] -× 007D × 0308 × 0020 × 0085 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] +× 007D × 0308 × 0085 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] +× 007D × 0308 × 0020 × 0085 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] × 007D × 17D6 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [16.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] × 007D × 0020 × 17D6 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [7.01] SPACE (SP) × [16.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] -× 007D × 0308 × 17D6 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM) × [16.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] -× 007D × 0308 × 0020 × 17D6 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [16.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] +× 007D × 0308 × 17D6 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [16.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] +× 007D × 0308 × 0020 × 17D6 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [16.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] × 007D ÷ 0030 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) ÷ [999.0] DIGIT ZERO (NU) ÷ [0.3] × 007D × 0020 ÷ 0030 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] -× 007D × 0308 ÷ 0030 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] DIGIT ZERO (NU) ÷ [0.3] -× 007D × 0308 × 0020 ÷ 0030 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] +× 007D × 0308 ÷ 0030 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] DIGIT ZERO (NU) ÷ [0.3] +× 007D × 0308 × 0020 ÷ 0030 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] × 007D ÷ 0028 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) ÷ [999.0] LEFT PARENTHESIS (OP) ÷ [0.3] × 007D × 0020 ÷ 0028 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] -× 007D × 0308 ÷ 0028 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] LEFT PARENTHESIS (OP) ÷ [0.3] -× 007D × 0308 × 0020 ÷ 0028 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] +× 007D × 0308 ÷ 0028 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] LEFT PARENTHESIS (OP) ÷ [0.3] +× 007D × 0308 × 0020 ÷ 0028 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] × 007D ÷ 0025 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) ÷ [999.0] PERCENT SIGN (PO) ÷ [0.3] × 007D × 0020 ÷ 0025 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] -× 007D × 0308 ÷ 0025 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] PERCENT SIGN (PO) ÷ [0.3] -× 007D × 0308 × 0020 ÷ 0025 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] +× 007D × 0308 ÷ 0025 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] PERCENT SIGN (PO) ÷ [0.3] +× 007D × 0308 × 0020 ÷ 0025 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] × 007D ÷ 0024 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) ÷ [999.0] DOLLAR SIGN (PR) ÷ [0.3] × 007D × 0020 ÷ 0024 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] -× 007D × 0308 ÷ 0024 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] DOLLAR SIGN (PR) ÷ [0.3] -× 007D × 0308 × 0020 ÷ 0024 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] +× 007D × 0308 ÷ 0024 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] DOLLAR SIGN (PR) ÷ [0.3] +× 007D × 0308 × 0020 ÷ 0024 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] × 007D × 0022 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [19.01] QUOTATION MARK (QU) ÷ [0.3] × 007D × 0020 ÷ 0022 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] -× 007D × 0308 × 0022 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM) × [19.01] QUOTATION MARK (QU) ÷ [0.3] -× 007D × 0308 × 0020 ÷ 0022 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] +× 007D × 0308 × 0022 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [19.01] QUOTATION MARK (QU) ÷ [0.3] +× 007D × 0308 × 0020 ÷ 0022 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] × 007D × 0020 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [7.01] SPACE (SP) ÷ [0.3] × 007D × 0020 × 0020 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] -× 007D × 0308 × 0020 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [0.3] -× 007D × 0308 × 0020 × 0020 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] +× 007D × 0308 × 0020 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [0.3] +× 007D × 0308 × 0020 × 0020 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] × 007D × 002F ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [13.02] SOLIDUS (SY) ÷ [0.3] × 007D × 0020 × 002F ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] -× 007D × 0308 × 002F ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM) × [13.03] SOLIDUS (SY) ÷ [0.3] -× 007D × 0308 × 0020 × 002F ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] +× 007D × 0308 × 002F ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] SOLIDUS (SY) ÷ [0.3] +× 007D × 0308 × 0020 × 002F ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] × 007D × 2060 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [11.01] WORD JOINER (WJ) ÷ [0.3] × 007D × 0020 × 2060 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] -× 007D × 0308 × 2060 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM) × [11.01] WORD JOINER (WJ) ÷ [0.3] -× 007D × 0308 × 0020 × 2060 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] +× 007D × 0308 × 2060 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [11.01] WORD JOINER (WJ) ÷ [0.3] +× 007D × 0308 × 0020 × 2060 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] × 007D × 200B ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] × 007D × 0020 × 200B ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] -× 007D × 0308 × 200B ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] -× 007D × 0308 × 0020 × 200B ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] +× 007D × 0308 × 200B ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] +× 007D × 0308 × 0020 × 200B ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] × 007D ÷ 1F1E6 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] × 007D × 0020 ÷ 1F1E6 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -× 007D × 0308 ÷ 1F1E6 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -× 007D × 0308 × 0020 ÷ 1F1E6 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 007D × 0308 ÷ 1F1E6 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 007D × 0308 × 0020 ÷ 1F1E6 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 007D ÷ 261D ÷ # × [0.3] RIGHT CURLY BRACKET (CL) ÷ [999.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 007D × 0020 ÷ 261D ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [7.01] SPACE (SP) ÷ [18.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 007D × 0308 ÷ 261D ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 007D × 0308 × 0020 ÷ 261D ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 007D ÷ 1F3FB ÷ # × [0.3] RIGHT CURLY BRACKET (CL) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 007D × 0020 ÷ 1F3FB ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [7.01] SPACE (SP) ÷ [18.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 007D × 0308 ÷ 1F3FB ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 007D × 0308 × 0020 ÷ 1F3FB ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 007D × 0001 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 007D × 0020 ÷ 0001 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 007D × 0308 × 0001 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [9.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 007D × 0308 × 0020 ÷ 0001 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 007D × 200D ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 007D × 0020 ÷ 200D ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [7.01] SPACE (SP) ÷ [18.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 007D × 0308 × 200D ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [9.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 007D × 0308 × 0020 ÷ 200D ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] × 007D ÷ 00A7 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) ÷ [999.0] SECTION SIGN (AI_AL) ÷ [0.3] × 007D × 0020 ÷ 00A7 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] -× 007D × 0308 ÷ 00A7 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] SECTION SIGN (AI_AL) ÷ [0.3] -× 007D × 0308 × 0020 ÷ 00A7 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] +× 007D × 0308 ÷ 00A7 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] SECTION SIGN (AI_AL) ÷ [0.3] +× 007D × 0308 × 0020 ÷ 00A7 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] × 007D ÷ 50005 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) ÷ [999.0] <reserved-50005> (XX_AL) ÷ [0.3] × 007D × 0020 ÷ 50005 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] -× 007D × 0308 ÷ 50005 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] <reserved-50005> (XX_AL) ÷ [0.3] -× 007D × 0308 × 0020 ÷ 50005 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] +× 007D × 0308 ÷ 50005 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] <reserved-50005> (XX_AL) ÷ [0.3] +× 007D × 0308 × 0020 ÷ 50005 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] × 007D ÷ 0E01 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) ÷ [999.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] × 007D × 0020 ÷ 0E01 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] -× 007D × 0308 ÷ 0E01 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] -× 007D × 0308 × 0020 ÷ 0E01 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] +× 007D × 0308 ÷ 0E01 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] +× 007D × 0308 × 0020 ÷ 0E01 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] × 007D × 3041 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [16.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] × 007D × 0020 × 3041 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [7.01] SPACE (SP) × [16.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] -× 007D × 0308 × 3041 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM) × [16.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] -× 007D × 0308 × 0020 × 3041 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [16.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] +× 007D × 0308 × 3041 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [16.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] +× 007D × 0308 × 0020 × 3041 ÷ # × [0.3] RIGHT CURLY BRACKET (CL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [16.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] × 0029 × 0023 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [30.02] NUMBER SIGN (AL) ÷ [0.3] × 0029 × 0020 ÷ 0023 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] -× 0029 × 0308 × 0023 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM) × [30.02] NUMBER SIGN (AL) ÷ [0.3] -× 0029 × 0308 × 0020 ÷ 0023 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] +× 0029 × 0308 × 0023 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [30.02] NUMBER SIGN (AL) ÷ [0.3] +× 0029 × 0308 × 0020 ÷ 0023 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] × 0029 ÷ 2014 ÷ # × [0.3] RIGHT PARENTHESIS (CP) ÷ [999.0] EM DASH (B2) ÷ [0.3] × 0029 × 0020 ÷ 2014 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] -× 0029 × 0308 ÷ 2014 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] EM DASH (B2) ÷ [0.3] -× 0029 × 0308 × 0020 ÷ 2014 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] +× 0029 × 0308 ÷ 2014 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] EM DASH (B2) ÷ [0.3] +× 0029 × 0308 × 0020 ÷ 2014 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] × 0029 × 0009 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] × 0029 × 0020 ÷ 0009 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] -× 0029 × 0308 × 0009 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] -× 0029 × 0308 × 0020 ÷ 0009 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] +× 0029 × 0308 × 0009 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] +× 0029 × 0308 × 0020 ÷ 0009 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] × 0029 ÷ 00B4 ÷ # × [0.3] RIGHT PARENTHESIS (CP) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3] × 0029 × 0020 ÷ 00B4 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] -× 0029 × 0308 ÷ 00B4 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3] -× 0029 × 0308 × 0020 ÷ 00B4 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] +× 0029 × 0308 ÷ 00B4 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3] +× 0029 × 0308 × 0020 ÷ 00B4 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] × 0029 × 000B ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] × 0029 × 0020 × 000B ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] -× 0029 × 0308 × 000B ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] -× 0029 × 0308 × 0020 × 000B ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] +× 0029 × 0308 × 000B ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] +× 0029 × 0308 × 0020 × 000B ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] × 0029 ÷ FFFC ÷ # × [0.3] RIGHT PARENTHESIS (CP) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] × 0029 × 0020 ÷ FFFC ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] -× 0029 × 0308 ÷ FFFC ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] -× 0029 × 0308 × 0020 ÷ FFFC ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] +× 0029 × 0308 ÷ FFFC ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] +× 0029 × 0308 × 0020 ÷ FFFC ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] × 0029 × 007D ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] × 0029 × 0020 × 007D ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] -× 0029 × 0308 × 007D ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM) × [13.03] RIGHT CURLY BRACKET (CL) ÷ [0.3] -× 0029 × 0308 × 0020 × 007D ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] +× 0029 × 0308 × 007D ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] RIGHT CURLY BRACKET (CL) ÷ [0.3] +× 0029 × 0308 × 0020 × 007D ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] × 0029 × 0029 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] × 0029 × 0020 × 0029 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 0029 × 0308 × 0029 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM) × [13.03] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 0029 × 0308 × 0020 × 0029 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 0029 × 0001 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] <START OF HEADING> (CM) ÷ [0.3] -× 0029 × 0020 ÷ 0001 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM) ÷ [0.3] -× 0029 × 0308 × 0001 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM) × [9.0] <START OF HEADING> (CM) ÷ [0.3] -× 0029 × 0308 × 0020 ÷ 0001 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM) ÷ [0.3] +× 0029 × 0308 × 0029 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] RIGHT PARENTHESIS (CP) ÷ [0.3] +× 0029 × 0308 × 0020 × 0029 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] × 0029 × 000D ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] × 0029 × 0020 × 000D ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -× 0029 × 0308 × 000D ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -× 0029 × 0308 × 0020 × 000D ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +× 0029 × 0308 × 000D ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +× 0029 × 0308 × 0020 × 000D ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] × 0029 × 0021 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] × 0029 × 0020 × 0021 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] -× 0029 × 0308 × 0021 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] -× 0029 × 0308 × 0020 × 0021 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] +× 0029 × 0308 × 0021 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] +× 0029 × 0308 × 0020 × 0021 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] × 0029 × 00A0 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [12.1] NO-BREAK SPACE (GL) ÷ [0.3] × 0029 × 0020 ÷ 00A0 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] -× 0029 × 0308 × 00A0 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM) × [12.2] NO-BREAK SPACE (GL) ÷ [0.3] -× 0029 × 0308 × 0020 ÷ 00A0 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] +× 0029 × 0308 × 00A0 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [12.2] NO-BREAK SPACE (GL) ÷ [0.3] +× 0029 × 0308 × 0020 ÷ 00A0 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] × 0029 ÷ AC00 ÷ # × [0.3] RIGHT PARENTHESIS (CP) ÷ [999.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] × 0029 × 0020 ÷ AC00 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] -× 0029 × 0308 ÷ AC00 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] -× 0029 × 0308 × 0020 ÷ AC00 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] +× 0029 × 0308 ÷ AC00 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] +× 0029 × 0308 × 0020 ÷ AC00 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] × 0029 ÷ AC01 ÷ # × [0.3] RIGHT PARENTHESIS (CP) ÷ [999.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] × 0029 × 0020 ÷ AC01 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] -× 0029 × 0308 ÷ AC01 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] -× 0029 × 0308 × 0020 ÷ AC01 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] +× 0029 × 0308 ÷ AC01 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] +× 0029 × 0308 × 0020 ÷ AC01 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] × 0029 × 05D0 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [30.02] HEBREW LETTER ALEF (HL) ÷ [0.3] × 0029 × 0020 ÷ 05D0 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] -× 0029 × 0308 × 05D0 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM) × [30.02] HEBREW LETTER ALEF (HL) ÷ [0.3] -× 0029 × 0308 × 0020 ÷ 05D0 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] +× 0029 × 0308 × 05D0 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [30.02] HEBREW LETTER ALEF (HL) ÷ [0.3] +× 0029 × 0308 × 0020 ÷ 05D0 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] × 0029 × 002D ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] × 0029 × 0020 ÷ 002D ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] -× 0029 × 0308 × 002D ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] -× 0029 × 0308 × 0020 ÷ 002D ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] +× 0029 × 0308 × 002D ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] +× 0029 × 0308 × 0020 ÷ 002D ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] × 0029 ÷ 231A ÷ # × [0.3] RIGHT PARENTHESIS (CP) ÷ [999.0] WATCH (ID) ÷ [0.3] × 0029 × 0020 ÷ 231A ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] -× 0029 × 0308 ÷ 231A ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] WATCH (ID) ÷ [0.3] -× 0029 × 0308 × 0020 ÷ 231A ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] +× 0029 × 0308 ÷ 231A ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] WATCH (ID) ÷ [0.3] +× 0029 × 0308 × 0020 ÷ 231A ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] × 0029 ÷ 2024 ÷ # × [0.3] RIGHT PARENTHESIS (CP) ÷ [999.0] ONE DOT LEADER (IN) ÷ [0.3] × 0029 × 0020 ÷ 2024 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] -× 0029 × 0308 ÷ 2024 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] ONE DOT LEADER (IN) ÷ [0.3] -× 0029 × 0308 × 0020 ÷ 2024 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] +× 0029 × 0308 ÷ 2024 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] ONE DOT LEADER (IN) ÷ [0.3] +× 0029 × 0308 × 0020 ÷ 2024 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] × 0029 × 002C ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [13.02] COMMA (IS) ÷ [0.3] × 0029 × 0020 × 002C ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] -× 0029 × 0308 × 002C ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM) × [13.03] COMMA (IS) ÷ [0.3] -× 0029 × 0308 × 0020 × 002C ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] +× 0029 × 0308 × 002C ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] COMMA (IS) ÷ [0.3] +× 0029 × 0308 × 0020 × 002C ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] × 0029 ÷ 1100 ÷ # × [0.3] RIGHT PARENTHESIS (CP) ÷ [999.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] × 0029 × 0020 ÷ 1100 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] -× 0029 × 0308 ÷ 1100 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] -× 0029 × 0308 × 0020 ÷ 1100 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] +× 0029 × 0308 ÷ 1100 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] +× 0029 × 0308 × 0020 ÷ 1100 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] × 0029 ÷ 11A8 ÷ # × [0.3] RIGHT PARENTHESIS (CP) ÷ [999.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] × 0029 × 0020 ÷ 11A8 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] -× 0029 × 0308 ÷ 11A8 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] -× 0029 × 0308 × 0020 ÷ 11A8 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] +× 0029 × 0308 ÷ 11A8 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] +× 0029 × 0308 × 0020 ÷ 11A8 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] × 0029 ÷ 1160 ÷ # × [0.3] RIGHT PARENTHESIS (CP) ÷ [999.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] × 0029 × 0020 ÷ 1160 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] -× 0029 × 0308 ÷ 1160 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] -× 0029 × 0308 × 0020 ÷ 1160 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] +× 0029 × 0308 ÷ 1160 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] +× 0029 × 0308 × 0020 ÷ 1160 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] × 0029 × 000A ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] × 0029 × 0020 × 000A ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] -× 0029 × 0308 × 000A ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] -× 0029 × 0308 × 0020 × 000A ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] +× 0029 × 0308 × 000A ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] +× 0029 × 0308 × 0020 × 000A ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] × 0029 × 0085 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] × 0029 × 0020 × 0085 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] -× 0029 × 0308 × 0085 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] -× 0029 × 0308 × 0020 × 0085 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] +× 0029 × 0308 × 0085 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] +× 0029 × 0308 × 0020 × 0085 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] × 0029 × 17D6 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [16.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] × 0029 × 0020 × 17D6 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [7.01] SPACE (SP) × [16.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] -× 0029 × 0308 × 17D6 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM) × [16.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] -× 0029 × 0308 × 0020 × 17D6 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [16.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] +× 0029 × 0308 × 17D6 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [16.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] +× 0029 × 0308 × 0020 × 17D6 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [16.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] × 0029 × 0030 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [30.02] DIGIT ZERO (NU) ÷ [0.3] × 0029 × 0020 ÷ 0030 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] -× 0029 × 0308 × 0030 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM) × [30.02] DIGIT ZERO (NU) ÷ [0.3] -× 0029 × 0308 × 0020 ÷ 0030 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] +× 0029 × 0308 × 0030 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [30.02] DIGIT ZERO (NU) ÷ [0.3] +× 0029 × 0308 × 0020 ÷ 0030 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] × 0029 ÷ 0028 ÷ # × [0.3] RIGHT PARENTHESIS (CP) ÷ [999.0] LEFT PARENTHESIS (OP) ÷ [0.3] × 0029 × 0020 ÷ 0028 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] -× 0029 × 0308 ÷ 0028 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] LEFT PARENTHESIS (OP) ÷ [0.3] -× 0029 × 0308 × 0020 ÷ 0028 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] +× 0029 × 0308 ÷ 0028 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] LEFT PARENTHESIS (OP) ÷ [0.3] +× 0029 × 0308 × 0020 ÷ 0028 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] × 0029 ÷ 0025 ÷ # × [0.3] RIGHT PARENTHESIS (CP) ÷ [999.0] PERCENT SIGN (PO) ÷ [0.3] × 0029 × 0020 ÷ 0025 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] -× 0029 × 0308 ÷ 0025 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] PERCENT SIGN (PO) ÷ [0.3] -× 0029 × 0308 × 0020 ÷ 0025 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] +× 0029 × 0308 ÷ 0025 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] PERCENT SIGN (PO) ÷ [0.3] +× 0029 × 0308 × 0020 ÷ 0025 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] × 0029 ÷ 0024 ÷ # × [0.3] RIGHT PARENTHESIS (CP) ÷ [999.0] DOLLAR SIGN (PR) ÷ [0.3] × 0029 × 0020 ÷ 0024 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] -× 0029 × 0308 ÷ 0024 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] DOLLAR SIGN (PR) ÷ [0.3] -× 0029 × 0308 × 0020 ÷ 0024 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] +× 0029 × 0308 ÷ 0024 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] DOLLAR SIGN (PR) ÷ [0.3] +× 0029 × 0308 × 0020 ÷ 0024 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] × 0029 × 0022 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [19.01] QUOTATION MARK (QU) ÷ [0.3] × 0029 × 0020 ÷ 0022 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] -× 0029 × 0308 × 0022 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM) × [19.01] QUOTATION MARK (QU) ÷ [0.3] -× 0029 × 0308 × 0020 ÷ 0022 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] +× 0029 × 0308 × 0022 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [19.01] QUOTATION MARK (QU) ÷ [0.3] +× 0029 × 0308 × 0020 ÷ 0022 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] × 0029 × 0020 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [7.01] SPACE (SP) ÷ [0.3] × 0029 × 0020 × 0020 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] -× 0029 × 0308 × 0020 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [0.3] -× 0029 × 0308 × 0020 × 0020 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] +× 0029 × 0308 × 0020 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [0.3] +× 0029 × 0308 × 0020 × 0020 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] × 0029 × 002F ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [13.02] SOLIDUS (SY) ÷ [0.3] × 0029 × 0020 × 002F ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] -× 0029 × 0308 × 002F ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM) × [13.03] SOLIDUS (SY) ÷ [0.3] -× 0029 × 0308 × 0020 × 002F ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] +× 0029 × 0308 × 002F ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] SOLIDUS (SY) ÷ [0.3] +× 0029 × 0308 × 0020 × 002F ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] × 0029 × 2060 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [11.01] WORD JOINER (WJ) ÷ [0.3] × 0029 × 0020 × 2060 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] -× 0029 × 0308 × 2060 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM) × [11.01] WORD JOINER (WJ) ÷ [0.3] -× 0029 × 0308 × 0020 × 2060 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] +× 0029 × 0308 × 2060 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [11.01] WORD JOINER (WJ) ÷ [0.3] +× 0029 × 0308 × 0020 × 2060 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] × 0029 × 200B ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] × 0029 × 0020 × 200B ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] -× 0029 × 0308 × 200B ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] -× 0029 × 0308 × 0020 × 200B ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] +× 0029 × 0308 × 200B ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] +× 0029 × 0308 × 0020 × 200B ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] × 0029 ÷ 1F1E6 ÷ # × [0.3] RIGHT PARENTHESIS (CP) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] × 0029 × 0020 ÷ 1F1E6 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -× 0029 × 0308 ÷ 1F1E6 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -× 0029 × 0308 × 0020 ÷ 1F1E6 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 0029 × 0308 ÷ 1F1E6 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 0029 × 0308 × 0020 ÷ 1F1E6 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 0029 ÷ 261D ÷ # × [0.3] RIGHT PARENTHESIS (CP) ÷ [999.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 0029 × 0020 ÷ 261D ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [7.01] SPACE (SP) ÷ [18.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 0029 × 0308 ÷ 261D ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 0029 × 0308 × 0020 ÷ 261D ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 0029 ÷ 1F3FB ÷ # × [0.3] RIGHT PARENTHESIS (CP) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 0029 × 0020 ÷ 1F3FB ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [7.01] SPACE (SP) ÷ [18.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 0029 × 0308 ÷ 1F3FB ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 0029 × 0308 × 0020 ÷ 1F3FB ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 0029 × 0001 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 0029 × 0020 ÷ 0001 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 0029 × 0308 × 0001 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [9.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 0029 × 0308 × 0020 ÷ 0001 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 0029 × 200D ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 0029 × 0020 ÷ 200D ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [7.01] SPACE (SP) ÷ [18.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 0029 × 0308 × 200D ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [9.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 0029 × 0308 × 0020 ÷ 200D ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] × 0029 × 00A7 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [30.02] SECTION SIGN (AI_AL) ÷ [0.3] × 0029 × 0020 ÷ 00A7 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] -× 0029 × 0308 × 00A7 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM) × [30.02] SECTION SIGN (AI_AL) ÷ [0.3] -× 0029 × 0308 × 0020 ÷ 00A7 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] +× 0029 × 0308 × 00A7 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [30.02] SECTION SIGN (AI_AL) ÷ [0.3] +× 0029 × 0308 × 0020 ÷ 00A7 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] × 0029 × 50005 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [30.02] <reserved-50005> (XX_AL) ÷ [0.3] × 0029 × 0020 ÷ 50005 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] -× 0029 × 0308 × 50005 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM) × [30.02] <reserved-50005> (XX_AL) ÷ [0.3] -× 0029 × 0308 × 0020 ÷ 50005 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] +× 0029 × 0308 × 50005 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [30.02] <reserved-50005> (XX_AL) ÷ [0.3] +× 0029 × 0308 × 0020 ÷ 50005 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] × 0029 × 0E01 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [30.02] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] × 0029 × 0020 ÷ 0E01 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] -× 0029 × 0308 × 0E01 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM) × [30.02] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] -× 0029 × 0308 × 0020 ÷ 0E01 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] +× 0029 × 0308 × 0E01 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [30.02] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] +× 0029 × 0308 × 0020 ÷ 0E01 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] × 0029 × 3041 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [16.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] × 0029 × 0020 × 3041 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [7.01] SPACE (SP) × [16.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] -× 0029 × 0308 × 3041 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM) × [16.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] -× 0029 × 0308 × 0020 × 3041 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [16.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] -× 0001 × 0023 ÷ # × [0.3] <START OF HEADING> (CM) × [28.0] NUMBER SIGN (AL) ÷ [0.3] -× 0001 × 0020 ÷ 0023 ÷ # × [0.3] <START OF HEADING> (CM) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] -× 0001 × 0308 × 0023 ÷ # × [0.3] <START OF HEADING> (CM) × [9.0] COMBINING DIAERESIS (CM) × [28.0] NUMBER SIGN (AL) ÷ [0.3] -× 0001 × 0308 × 0020 ÷ 0023 ÷ # × [0.3] <START OF HEADING> (CM) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] -× 0001 ÷ 2014 ÷ # × [0.3] <START OF HEADING> (CM) ÷ [999.0] EM DASH (B2) ÷ [0.3] -× 0001 × 0020 ÷ 2014 ÷ # × [0.3] <START OF HEADING> (CM) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] -× 0001 × 0308 ÷ 2014 ÷ # × [0.3] <START OF HEADING> (CM) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] EM DASH (B2) ÷ [0.3] -× 0001 × 0308 × 0020 ÷ 2014 ÷ # × [0.3] <START OF HEADING> (CM) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] -× 0001 × 0009 ÷ # × [0.3] <START OF HEADING> (CM) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] -× 0001 × 0020 ÷ 0009 ÷ # × [0.3] <START OF HEADING> (CM) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] -× 0001 × 0308 × 0009 ÷ # × [0.3] <START OF HEADING> (CM) × [9.0] COMBINING DIAERESIS (CM) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] -× 0001 × 0308 × 0020 ÷ 0009 ÷ # × [0.3] <START OF HEADING> (CM) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] -× 0001 ÷ 00B4 ÷ # × [0.3] <START OF HEADING> (CM) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3] -× 0001 × 0020 ÷ 00B4 ÷ # × [0.3] <START OF HEADING> (CM) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] -× 0001 × 0308 ÷ 00B4 ÷ # × [0.3] <START OF HEADING> (CM) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3] -× 0001 × 0308 × 0020 ÷ 00B4 ÷ # × [0.3] <START OF HEADING> (CM) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] -× 0001 × 000B ÷ # × [0.3] <START OF HEADING> (CM) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] -× 0001 × 0020 × 000B ÷ # × [0.3] <START OF HEADING> (CM) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] -× 0001 × 0308 × 000B ÷ # × [0.3] <START OF HEADING> (CM) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] -× 0001 × 0308 × 0020 × 000B ÷ # × [0.3] <START OF HEADING> (CM) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] -× 0001 ÷ FFFC ÷ # × [0.3] <START OF HEADING> (CM) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] -× 0001 × 0020 ÷ FFFC ÷ # × [0.3] <START OF HEADING> (CM) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] -× 0001 × 0308 ÷ FFFC ÷ # × [0.3] <START OF HEADING> (CM) × [9.0] COMBINING DIAERESIS (CM) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] -× 0001 × 0308 × 0020 ÷ FFFC ÷ # × [0.3] <START OF HEADING> (CM) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] -× 0001 × 007D ÷ # × [0.3] <START OF HEADING> (CM) × [13.04] RIGHT CURLY BRACKET (CL) ÷ [0.3] -× 0001 × 0020 × 007D ÷ # × [0.3] <START OF HEADING> (CM) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] -× 0001 × 0308 × 007D ÷ # × [0.3] <START OF HEADING> (CM) × [9.0] COMBINING DIAERESIS (CM) × [13.04] RIGHT CURLY BRACKET (CL) ÷ [0.3] -× 0001 × 0308 × 0020 × 007D ÷ # × [0.3] <START OF HEADING> (CM) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] -× 0001 × 0029 ÷ # × [0.3] <START OF HEADING> (CM) × [13.04] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 0001 × 0020 × 0029 ÷ # × [0.3] <START OF HEADING> (CM) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 0001 × 0308 × 0029 ÷ # × [0.3] <START OF HEADING> (CM) × [9.0] COMBINING DIAERESIS (CM) × [13.04] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 0001 × 0308 × 0020 × 0029 ÷ # × [0.3] <START OF HEADING> (CM) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 0001 × 0001 ÷ # × [0.3] <START OF HEADING> (CM) × [9.0] <START OF HEADING> (CM) ÷ [0.3] -× 0001 × 0020 ÷ 0001 ÷ # × [0.3] <START OF HEADING> (CM) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM) ÷ [0.3] -× 0001 × 0308 × 0001 ÷ # × [0.3] <START OF HEADING> (CM) × [9.0] COMBINING DIAERESIS (CM) × [9.0] <START OF HEADING> (CM) ÷ [0.3] -× 0001 × 0308 × 0020 ÷ 0001 ÷ # × [0.3] <START OF HEADING> (CM) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM) ÷ [0.3] -× 0001 × 000D ÷ # × [0.3] <START OF HEADING> (CM) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -× 0001 × 0020 × 000D ÷ # × [0.3] <START OF HEADING> (CM) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -× 0001 × 0308 × 000D ÷ # × [0.3] <START OF HEADING> (CM) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -× 0001 × 0308 × 0020 × 000D ÷ # × [0.3] <START OF HEADING> (CM) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -× 0001 × 0021 ÷ # × [0.3] <START OF HEADING> (CM) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] -× 0001 × 0020 × 0021 ÷ # × [0.3] <START OF HEADING> (CM) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] -× 0001 × 0308 × 0021 ÷ # × [0.3] <START OF HEADING> (CM) × [9.0] COMBINING DIAERESIS (CM) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] -× 0001 × 0308 × 0020 × 0021 ÷ # × [0.3] <START OF HEADING> (CM) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] -× 0001 × 00A0 ÷ # × [0.3] <START OF HEADING> (CM) × [12.3] NO-BREAK SPACE (GL) ÷ [0.3] -× 0001 × 0020 ÷ 00A0 ÷ # × [0.3] <START OF HEADING> (CM) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] -× 0001 × 0308 × 00A0 ÷ # × [0.3] <START OF HEADING> (CM) × [9.0] COMBINING DIAERESIS (CM) × [12.3] NO-BREAK SPACE (GL) ÷ [0.3] -× 0001 × 0308 × 0020 ÷ 00A0 ÷ # × [0.3] <START OF HEADING> (CM) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] -× 0001 ÷ AC00 ÷ # × [0.3] <START OF HEADING> (CM) ÷ [999.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] -× 0001 × 0020 ÷ AC00 ÷ # × [0.3] <START OF HEADING> (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] -× 0001 × 0308 ÷ AC00 ÷ # × [0.3] <START OF HEADING> (CM) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] -× 0001 × 0308 × 0020 ÷ AC00 ÷ # × [0.3] <START OF HEADING> (CM) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] -× 0001 ÷ AC01 ÷ # × [0.3] <START OF HEADING> (CM) ÷ [999.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] -× 0001 × 0020 ÷ AC01 ÷ # × [0.3] <START OF HEADING> (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] -× 0001 × 0308 ÷ AC01 ÷ # × [0.3] <START OF HEADING> (CM) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] -× 0001 × 0308 × 0020 ÷ AC01 ÷ # × [0.3] <START OF HEADING> (CM) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] -× 0001 × 05D0 ÷ # × [0.3] <START OF HEADING> (CM) × [28.0] HEBREW LETTER ALEF (HL) ÷ [0.3] -× 0001 × 0020 ÷ 05D0 ÷ # × [0.3] <START OF HEADING> (CM) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] -× 0001 × 0308 × 05D0 ÷ # × [0.3] <START OF HEADING> (CM) × [9.0] COMBINING DIAERESIS (CM) × [28.0] HEBREW LETTER ALEF (HL) ÷ [0.3] -× 0001 × 0308 × 0020 ÷ 05D0 ÷ # × [0.3] <START OF HEADING> (CM) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] -× 0001 × 002D ÷ # × [0.3] <START OF HEADING> (CM) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] -× 0001 × 0020 ÷ 002D ÷ # × [0.3] <START OF HEADING> (CM) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] -× 0001 × 0308 × 002D ÷ # × [0.3] <START OF HEADING> (CM) × [9.0] COMBINING DIAERESIS (CM) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] -× 0001 × 0308 × 0020 ÷ 002D ÷ # × [0.3] <START OF HEADING> (CM) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] -× 0001 ÷ 231A ÷ # × [0.3] <START OF HEADING> (CM) ÷ [999.0] WATCH (ID) ÷ [0.3] -× 0001 × 0020 ÷ 231A ÷ # × [0.3] <START OF HEADING> (CM) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] -× 0001 × 0308 ÷ 231A ÷ # × [0.3] <START OF HEADING> (CM) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] WATCH (ID) ÷ [0.3] -× 0001 × 0308 × 0020 ÷ 231A ÷ # × [0.3] <START OF HEADING> (CM) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] -× 0001 × 2024 ÷ # × [0.3] <START OF HEADING> (CM) × [22.01] ONE DOT LEADER (IN) ÷ [0.3] -× 0001 × 0020 ÷ 2024 ÷ # × [0.3] <START OF HEADING> (CM) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] -× 0001 × 0308 × 2024 ÷ # × [0.3] <START OF HEADING> (CM) × [9.0] COMBINING DIAERESIS (CM) × [22.01] ONE DOT LEADER (IN) ÷ [0.3] -× 0001 × 0308 × 0020 ÷ 2024 ÷ # × [0.3] <START OF HEADING> (CM) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] -× 0001 × 002C ÷ # × [0.3] <START OF HEADING> (CM) × [13.04] COMMA (IS) ÷ [0.3] -× 0001 × 0020 × 002C ÷ # × [0.3] <START OF HEADING> (CM) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] -× 0001 × 0308 × 002C ÷ # × [0.3] <START OF HEADING> (CM) × [9.0] COMBINING DIAERESIS (CM) × [13.04] COMMA (IS) ÷ [0.3] -× 0001 × 0308 × 0020 × 002C ÷ # × [0.3] <START OF HEADING> (CM) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] -× 0001 ÷ 1100 ÷ # × [0.3] <START OF HEADING> (CM) ÷ [999.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] -× 0001 × 0020 ÷ 1100 ÷ # × [0.3] <START OF HEADING> (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] -× 0001 × 0308 ÷ 1100 ÷ # × [0.3] <START OF HEADING> (CM) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] -× 0001 × 0308 × 0020 ÷ 1100 ÷ # × [0.3] <START OF HEADING> (CM) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] -× 0001 ÷ 11A8 ÷ # × [0.3] <START OF HEADING> (CM) ÷ [999.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] -× 0001 × 0020 ÷ 11A8 ÷ # × [0.3] <START OF HEADING> (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] -× 0001 × 0308 ÷ 11A8 ÷ # × [0.3] <START OF HEADING> (CM) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] -× 0001 × 0308 × 0020 ÷ 11A8 ÷ # × [0.3] <START OF HEADING> (CM) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] -× 0001 ÷ 1160 ÷ # × [0.3] <START OF HEADING> (CM) ÷ [999.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] -× 0001 × 0020 ÷ 1160 ÷ # × [0.3] <START OF HEADING> (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] -× 0001 × 0308 ÷ 1160 ÷ # × [0.3] <START OF HEADING> (CM) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] -× 0001 × 0308 × 0020 ÷ 1160 ÷ # × [0.3] <START OF HEADING> (CM) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] -× 0001 × 000A ÷ # × [0.3] <START OF HEADING> (CM) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] -× 0001 × 0020 × 000A ÷ # × [0.3] <START OF HEADING> (CM) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] -× 0001 × 0308 × 000A ÷ # × [0.3] <START OF HEADING> (CM) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] -× 0001 × 0308 × 0020 × 000A ÷ # × [0.3] <START OF HEADING> (CM) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] -× 0001 × 0085 ÷ # × [0.3] <START OF HEADING> (CM) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] -× 0001 × 0020 × 0085 ÷ # × [0.3] <START OF HEADING> (CM) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] -× 0001 × 0308 × 0085 ÷ # × [0.3] <START OF HEADING> (CM) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] -× 0001 × 0308 × 0020 × 0085 ÷ # × [0.3] <START OF HEADING> (CM) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] -× 0001 × 17D6 ÷ # × [0.3] <START OF HEADING> (CM) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] -× 0001 × 0020 ÷ 17D6 ÷ # × [0.3] <START OF HEADING> (CM) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] -× 0001 × 0308 × 17D6 ÷ # × [0.3] <START OF HEADING> (CM) × [9.0] COMBINING DIAERESIS (CM) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] -× 0001 × 0308 × 0020 ÷ 17D6 ÷ # × [0.3] <START OF HEADING> (CM) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] -× 0001 × 0030 ÷ # × [0.3] <START OF HEADING> (CM) × [23.02] DIGIT ZERO (NU) ÷ [0.3] -× 0001 × 0020 ÷ 0030 ÷ # × [0.3] <START OF HEADING> (CM) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] -× 0001 × 0308 × 0030 ÷ # × [0.3] <START OF HEADING> (CM) × [9.0] COMBINING DIAERESIS (CM) × [23.02] DIGIT ZERO (NU) ÷ [0.3] -× 0001 × 0308 × 0020 ÷ 0030 ÷ # × [0.3] <START OF HEADING> (CM) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] -× 0001 × 0028 ÷ # × [0.3] <START OF HEADING> (CM) × [30.01] LEFT PARENTHESIS (OP) ÷ [0.3] -× 0001 × 0020 ÷ 0028 ÷ # × [0.3] <START OF HEADING> (CM) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] -× 0001 × 0308 × 0028 ÷ # × [0.3] <START OF HEADING> (CM) × [9.0] COMBINING DIAERESIS (CM) × [30.01] LEFT PARENTHESIS (OP) ÷ [0.3] -× 0001 × 0308 × 0020 ÷ 0028 ÷ # × [0.3] <START OF HEADING> (CM) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] -× 0001 ÷ 0025 ÷ # × [0.3] <START OF HEADING> (CM) ÷ [999.0] PERCENT SIGN (PO) ÷ [0.3] -× 0001 × 0020 ÷ 0025 ÷ # × [0.3] <START OF HEADING> (CM) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] -× 0001 × 0308 ÷ 0025 ÷ # × [0.3] <START OF HEADING> (CM) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] PERCENT SIGN (PO) ÷ [0.3] -× 0001 × 0308 × 0020 ÷ 0025 ÷ # × [0.3] <START OF HEADING> (CM) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] -× 0001 ÷ 0024 ÷ # × [0.3] <START OF HEADING> (CM) ÷ [999.0] DOLLAR SIGN (PR) ÷ [0.3] -× 0001 × 0020 ÷ 0024 ÷ # × [0.3] <START OF HEADING> (CM) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] -× 0001 × 0308 ÷ 0024 ÷ # × [0.3] <START OF HEADING> (CM) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] DOLLAR SIGN (PR) ÷ [0.3] -× 0001 × 0308 × 0020 ÷ 0024 ÷ # × [0.3] <START OF HEADING> (CM) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] -× 0001 × 0022 ÷ # × [0.3] <START OF HEADING> (CM) × [19.01] QUOTATION MARK (QU) ÷ [0.3] -× 0001 × 0020 ÷ 0022 ÷ # × [0.3] <START OF HEADING> (CM) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] -× 0001 × 0308 × 0022 ÷ # × [0.3] <START OF HEADING> (CM) × [9.0] COMBINING DIAERESIS (CM) × [19.01] QUOTATION MARK (QU) ÷ [0.3] -× 0001 × 0308 × 0020 ÷ 0022 ÷ # × [0.3] <START OF HEADING> (CM) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] -× 0001 × 0020 ÷ # × [0.3] <START OF HEADING> (CM) × [7.01] SPACE (SP) ÷ [0.3] -× 0001 × 0020 × 0020 ÷ # × [0.3] <START OF HEADING> (CM) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] -× 0001 × 0308 × 0020 ÷ # × [0.3] <START OF HEADING> (CM) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [0.3] -× 0001 × 0308 × 0020 × 0020 ÷ # × [0.3] <START OF HEADING> (CM) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] -× 0001 × 002F ÷ # × [0.3] <START OF HEADING> (CM) × [13.04] SOLIDUS (SY) ÷ [0.3] -× 0001 × 0020 × 002F ÷ # × [0.3] <START OF HEADING> (CM) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] -× 0001 × 0308 × 002F ÷ # × [0.3] <START OF HEADING> (CM) × [9.0] COMBINING DIAERESIS (CM) × [13.04] SOLIDUS (SY) ÷ [0.3] -× 0001 × 0308 × 0020 × 002F ÷ # × [0.3] <START OF HEADING> (CM) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] -× 0001 × 2060 ÷ # × [0.3] <START OF HEADING> (CM) × [11.01] WORD JOINER (WJ) ÷ [0.3] -× 0001 × 0020 × 2060 ÷ # × [0.3] <START OF HEADING> (CM) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] -× 0001 × 0308 × 2060 ÷ # × [0.3] <START OF HEADING> (CM) × [9.0] COMBINING DIAERESIS (CM) × [11.01] WORD JOINER (WJ) ÷ [0.3] -× 0001 × 0308 × 0020 × 2060 ÷ # × [0.3] <START OF HEADING> (CM) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] -× 0001 × 200B ÷ # × [0.3] <START OF HEADING> (CM) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] -× 0001 × 0020 × 200B ÷ # × [0.3] <START OF HEADING> (CM) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] -× 0001 × 0308 × 200B ÷ # × [0.3] <START OF HEADING> (CM) × [9.0] COMBINING DIAERESIS (CM) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] -× 0001 × 0308 × 0020 × 200B ÷ # × [0.3] <START OF HEADING> (CM) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] -× 0001 ÷ 1F1E6 ÷ # × [0.3] <START OF HEADING> (CM) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -× 0001 × 0020 ÷ 1F1E6 ÷ # × [0.3] <START OF HEADING> (CM) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -× 0001 × 0308 ÷ 1F1E6 ÷ # × [0.3] <START OF HEADING> (CM) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -× 0001 × 0308 × 0020 ÷ 1F1E6 ÷ # × [0.3] <START OF HEADING> (CM) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -× 0001 × 00A7 ÷ # × [0.3] <START OF HEADING> (CM) × [28.0] SECTION SIGN (AI_AL) ÷ [0.3] -× 0001 × 0020 ÷ 00A7 ÷ # × [0.3] <START OF HEADING> (CM) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] -× 0001 × 0308 × 00A7 ÷ # × [0.3] <START OF HEADING> (CM) × [9.0] COMBINING DIAERESIS (CM) × [28.0] SECTION SIGN (AI_AL) ÷ [0.3] -× 0001 × 0308 × 0020 ÷ 00A7 ÷ # × [0.3] <START OF HEADING> (CM) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] -× 0001 × 50005 ÷ # × [0.3] <START OF HEADING> (CM) × [28.0] <reserved-50005> (XX_AL) ÷ [0.3] -× 0001 × 0020 ÷ 50005 ÷ # × [0.3] <START OF HEADING> (CM) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] -× 0001 × 0308 × 50005 ÷ # × [0.3] <START OF HEADING> (CM) × [9.0] COMBINING DIAERESIS (CM) × [28.0] <reserved-50005> (XX_AL) ÷ [0.3] -× 0001 × 0308 × 0020 ÷ 50005 ÷ # × [0.3] <START OF HEADING> (CM) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] -× 0001 × 0E01 ÷ # × [0.3] <START OF HEADING> (CM) × [28.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] -× 0001 × 0020 ÷ 0E01 ÷ # × [0.3] <START OF HEADING> (CM) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] -× 0001 × 0308 × 0E01 ÷ # × [0.3] <START OF HEADING> (CM) × [9.0] COMBINING DIAERESIS (CM) × [28.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] -× 0001 × 0308 × 0020 ÷ 0E01 ÷ # × [0.3] <START OF HEADING> (CM) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] -× 0001 × 3041 ÷ # × [0.3] <START OF HEADING> (CM) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] -× 0001 × 0020 ÷ 3041 ÷ # × [0.3] <START OF HEADING> (CM) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] -× 0001 × 0308 × 3041 ÷ # × [0.3] <START OF HEADING> (CM) × [9.0] COMBINING DIAERESIS (CM) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] -× 0001 × 0308 × 0020 ÷ 3041 ÷ # × [0.3] <START OF HEADING> (CM) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] +× 0029 × 0308 × 3041 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [16.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] +× 0029 × 0308 × 0020 × 3041 ÷ # × [0.3] RIGHT PARENTHESIS (CP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [16.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] × 000D ÷ 0023 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] NUMBER SIGN (AL) ÷ [0.3] × 000D ÷ 0020 ÷ 0023 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] -× 000D ÷ 0308 × 0023 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM) × [28.0] NUMBER SIGN (AL) ÷ [0.3] -× 000D ÷ 0308 × 0020 ÷ 0023 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] +× 000D ÷ 0308 × 0023 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM1_CM) × [28.0] NUMBER SIGN (AL) ÷ [0.3] +× 000D ÷ 0308 × 0020 ÷ 0023 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] × 000D ÷ 2014 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] EM DASH (B2) ÷ [0.3] × 000D ÷ 0020 ÷ 2014 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] -× 000D ÷ 0308 ÷ 2014 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM) ÷ [999.0] EM DASH (B2) ÷ [0.3] -× 000D ÷ 0308 × 0020 ÷ 2014 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] +× 000D ÷ 0308 ÷ 2014 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] EM DASH (B2) ÷ [0.3] +× 000D ÷ 0308 × 0020 ÷ 2014 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] × 000D ÷ 0009 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] <CHARACTER TABULATION> (BA) ÷ [0.3] × 000D ÷ 0020 ÷ 0009 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] -× 000D ÷ 0308 × 0009 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] -× 000D ÷ 0308 × 0020 ÷ 0009 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] +× 000D ÷ 0308 × 0009 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM1_CM) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] +× 000D ÷ 0308 × 0020 ÷ 0009 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] × 000D ÷ 00B4 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] ACUTE ACCENT (BB) ÷ [0.3] × 000D ÷ 0020 ÷ 00B4 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] -× 000D ÷ 0308 ÷ 00B4 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3] -× 000D ÷ 0308 × 0020 ÷ 00B4 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] +× 000D ÷ 0308 ÷ 00B4 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3] +× 000D ÷ 0308 × 0020 ÷ 00B4 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] × 000D ÷ 000B ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] <LINE TABULATION> (BK) ÷ [0.3] × 000D ÷ 0020 × 000B ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] -× 000D ÷ 0308 × 000B ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] -× 000D ÷ 0308 × 0020 × 000B ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] +× 000D ÷ 0308 × 000B ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM1_CM) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] +× 000D ÷ 0308 × 0020 × 000B ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] × 000D ÷ FFFC ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] × 000D ÷ 0020 ÷ FFFC ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] -× 000D ÷ 0308 ÷ FFFC ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] -× 000D ÷ 0308 × 0020 ÷ FFFC ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] +× 000D ÷ 0308 ÷ FFFC ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM1_CM) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] +× 000D ÷ 0308 × 0020 ÷ FFFC ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] × 000D ÷ 007D ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] × 000D ÷ 0020 × 007D ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] -× 000D ÷ 0308 × 007D ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM) × [13.03] RIGHT CURLY BRACKET (CL) ÷ [0.3] -× 000D ÷ 0308 × 0020 × 007D ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] +× 000D ÷ 0308 × 007D ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM1_CM) × [13.03] RIGHT CURLY BRACKET (CL) ÷ [0.3] +× 000D ÷ 0308 × 0020 × 007D ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] × 000D ÷ 0029 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] RIGHT PARENTHESIS (CP) ÷ [0.3] × 000D ÷ 0020 × 0029 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 000D ÷ 0308 × 0029 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM) × [13.03] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 000D ÷ 0308 × 0020 × 0029 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 000D ÷ 0001 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] <START OF HEADING> (CM) ÷ [0.3] -× 000D ÷ 0020 ÷ 0001 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM) ÷ [0.3] -× 000D ÷ 0308 × 0001 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM) × [9.0] <START OF HEADING> (CM) ÷ [0.3] -× 000D ÷ 0308 × 0020 ÷ 0001 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM) ÷ [0.3] +× 000D ÷ 0308 × 0029 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM1_CM) × [13.03] RIGHT PARENTHESIS (CP) ÷ [0.3] +× 000D ÷ 0308 × 0020 × 0029 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] × 000D ÷ 000D ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] × 000D ÷ 0020 × 000D ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -× 000D ÷ 0308 × 000D ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -× 000D ÷ 0308 × 0020 × 000D ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +× 000D ÷ 0308 × 000D ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM1_CM) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +× 000D ÷ 0308 × 0020 × 000D ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] × 000D ÷ 0021 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] EXCLAMATION MARK (EX) ÷ [0.3] × 000D ÷ 0020 × 0021 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] -× 000D ÷ 0308 × 0021 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] -× 000D ÷ 0308 × 0020 × 0021 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] +× 000D ÷ 0308 × 0021 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM1_CM) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] +× 000D ÷ 0308 × 0020 × 0021 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] × 000D ÷ 00A0 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] NO-BREAK SPACE (GL) ÷ [0.3] × 000D ÷ 0020 ÷ 00A0 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] -× 000D ÷ 0308 × 00A0 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM) × [12.2] NO-BREAK SPACE (GL) ÷ [0.3] -× 000D ÷ 0308 × 0020 ÷ 00A0 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] +× 000D ÷ 0308 × 00A0 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM1_CM) × [12.2] NO-BREAK SPACE (GL) ÷ [0.3] +× 000D ÷ 0308 × 0020 ÷ 00A0 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] × 000D ÷ AC00 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] HANGUL SYLLABLE GA (H2) ÷ [0.3] × 000D ÷ 0020 ÷ AC00 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] -× 000D ÷ 0308 ÷ AC00 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] -× 000D ÷ 0308 × 0020 ÷ AC00 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] +× 000D ÷ 0308 ÷ AC00 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] +× 000D ÷ 0308 × 0020 ÷ AC00 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] × 000D ÷ AC01 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] HANGUL SYLLABLE GAG (H3) ÷ [0.3] × 000D ÷ 0020 ÷ AC01 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] -× 000D ÷ 0308 ÷ AC01 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] -× 000D ÷ 0308 × 0020 ÷ AC01 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] +× 000D ÷ 0308 ÷ AC01 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] +× 000D ÷ 0308 × 0020 ÷ AC01 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] × 000D ÷ 05D0 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] HEBREW LETTER ALEF (HL) ÷ [0.3] × 000D ÷ 0020 ÷ 05D0 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] -× 000D ÷ 0308 × 05D0 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM) × [28.0] HEBREW LETTER ALEF (HL) ÷ [0.3] -× 000D ÷ 0308 × 0020 ÷ 05D0 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] +× 000D ÷ 0308 × 05D0 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM1_CM) × [28.0] HEBREW LETTER ALEF (HL) ÷ [0.3] +× 000D ÷ 0308 × 0020 ÷ 05D0 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] × 000D ÷ 002D ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] HYPHEN-MINUS (HY) ÷ [0.3] × 000D ÷ 0020 ÷ 002D ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] -× 000D ÷ 0308 × 002D ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] -× 000D ÷ 0308 × 0020 ÷ 002D ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] +× 000D ÷ 0308 × 002D ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM1_CM) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] +× 000D ÷ 0308 × 0020 ÷ 002D ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] × 000D ÷ 231A ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] WATCH (ID) ÷ [0.3] × 000D ÷ 0020 ÷ 231A ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] -× 000D ÷ 0308 ÷ 231A ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM) ÷ [999.0] WATCH (ID) ÷ [0.3] -× 000D ÷ 0308 × 0020 ÷ 231A ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] +× 000D ÷ 0308 ÷ 231A ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] WATCH (ID) ÷ [0.3] +× 000D ÷ 0308 × 0020 ÷ 231A ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] × 000D ÷ 2024 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] ONE DOT LEADER (IN) ÷ [0.3] × 000D ÷ 0020 ÷ 2024 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] -× 000D ÷ 0308 × 2024 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM) × [22.01] ONE DOT LEADER (IN) ÷ [0.3] -× 000D ÷ 0308 × 0020 ÷ 2024 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] +× 000D ÷ 0308 × 2024 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM1_CM) × [22.01] ONE DOT LEADER (IN) ÷ [0.3] +× 000D ÷ 0308 × 0020 ÷ 2024 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] × 000D ÷ 002C ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMMA (IS) ÷ [0.3] × 000D ÷ 0020 × 002C ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] -× 000D ÷ 0308 × 002C ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM) × [13.03] COMMA (IS) ÷ [0.3] -× 000D ÷ 0308 × 0020 × 002C ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] +× 000D ÷ 0308 × 002C ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM1_CM) × [13.03] COMMA (IS) ÷ [0.3] +× 000D ÷ 0308 × 0020 × 002C ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] × 000D ÷ 1100 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] × 000D ÷ 0020 ÷ 1100 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] -× 000D ÷ 0308 ÷ 1100 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] -× 000D ÷ 0308 × 0020 ÷ 1100 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] +× 000D ÷ 0308 ÷ 1100 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] +× 000D ÷ 0308 × 0020 ÷ 1100 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] × 000D ÷ 11A8 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] × 000D ÷ 0020 ÷ 11A8 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] -× 000D ÷ 0308 ÷ 11A8 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] -× 000D ÷ 0308 × 0020 ÷ 11A8 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] +× 000D ÷ 0308 ÷ 11A8 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] +× 000D ÷ 0308 × 0020 ÷ 11A8 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] × 000D ÷ 1160 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] × 000D ÷ 0020 ÷ 1160 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] -× 000D ÷ 0308 ÷ 1160 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] -× 000D ÷ 0308 × 0020 ÷ 1160 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] +× 000D ÷ 0308 ÷ 1160 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] +× 000D ÷ 0308 × 0020 ÷ 1160 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] × 000D × 000A ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) × [5.01] <LINE FEED (LF)> (LF) ÷ [0.3] × 000D ÷ 0020 × 000A ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] -× 000D ÷ 0308 × 000A ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] -× 000D ÷ 0308 × 0020 × 000A ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] +× 000D ÷ 0308 × 000A ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM1_CM) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] +× 000D ÷ 0308 × 0020 × 000A ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] × 000D ÷ 0085 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] <NEXT LINE (NEL)> (NL) ÷ [0.3] × 000D ÷ 0020 × 0085 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] -× 000D ÷ 0308 × 0085 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] -× 000D ÷ 0308 × 0020 × 0085 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] +× 000D ÷ 0308 × 0085 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM1_CM) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] +× 000D ÷ 0308 × 0020 × 0085 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] × 000D ÷ 17D6 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] × 000D ÷ 0020 ÷ 17D6 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] -× 000D ÷ 0308 × 17D6 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] -× 000D ÷ 0308 × 0020 ÷ 17D6 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] +× 000D ÷ 0308 × 17D6 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM1_CM) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] +× 000D ÷ 0308 × 0020 ÷ 17D6 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] × 000D ÷ 0030 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] DIGIT ZERO (NU) ÷ [0.3] × 000D ÷ 0020 ÷ 0030 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] -× 000D ÷ 0308 × 0030 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM) × [23.02] DIGIT ZERO (NU) ÷ [0.3] -× 000D ÷ 0308 × 0020 ÷ 0030 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] +× 000D ÷ 0308 × 0030 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM1_CM) × [23.02] DIGIT ZERO (NU) ÷ [0.3] +× 000D ÷ 0308 × 0020 ÷ 0030 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] × 000D ÷ 0028 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] LEFT PARENTHESIS (OP) ÷ [0.3] × 000D ÷ 0020 ÷ 0028 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] -× 000D ÷ 0308 × 0028 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM) × [30.01] LEFT PARENTHESIS (OP) ÷ [0.3] -× 000D ÷ 0308 × 0020 ÷ 0028 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] +× 000D ÷ 0308 × 0028 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM1_CM) × [30.01] LEFT PARENTHESIS (OP) ÷ [0.3] +× 000D ÷ 0308 × 0020 ÷ 0028 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] × 000D ÷ 0025 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] PERCENT SIGN (PO) ÷ [0.3] × 000D ÷ 0020 ÷ 0025 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] -× 000D ÷ 0308 ÷ 0025 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM) ÷ [999.0] PERCENT SIGN (PO) ÷ [0.3] -× 000D ÷ 0308 × 0020 ÷ 0025 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] +× 000D ÷ 0308 × 0025 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM1_CM) × [24.03] PERCENT SIGN (PO) ÷ [0.3] +× 000D ÷ 0308 × 0020 ÷ 0025 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] × 000D ÷ 0024 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] DOLLAR SIGN (PR) ÷ [0.3] × 000D ÷ 0020 ÷ 0024 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] -× 000D ÷ 0308 ÷ 0024 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM) ÷ [999.0] DOLLAR SIGN (PR) ÷ [0.3] -× 000D ÷ 0308 × 0020 ÷ 0024 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] +× 000D ÷ 0308 × 0024 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM1_CM) × [24.03] DOLLAR SIGN (PR) ÷ [0.3] +× 000D ÷ 0308 × 0020 ÷ 0024 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] × 000D ÷ 0022 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] QUOTATION MARK (QU) ÷ [0.3] × 000D ÷ 0020 ÷ 0022 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] -× 000D ÷ 0308 × 0022 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM) × [19.01] QUOTATION MARK (QU) ÷ [0.3] -× 000D ÷ 0308 × 0020 ÷ 0022 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] +× 000D ÷ 0308 × 0022 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM1_CM) × [19.01] QUOTATION MARK (QU) ÷ [0.3] +× 000D ÷ 0308 × 0020 ÷ 0022 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] × 000D ÷ 0020 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] SPACE (SP) ÷ [0.3] × 000D ÷ 0020 × 0020 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] -× 000D ÷ 0308 × 0020 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [0.3] -× 000D ÷ 0308 × 0020 × 0020 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] +× 000D ÷ 0308 × 0020 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [0.3] +× 000D ÷ 0308 × 0020 × 0020 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] × 000D ÷ 002F ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] SOLIDUS (SY) ÷ [0.3] × 000D ÷ 0020 × 002F ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] -× 000D ÷ 0308 × 002F ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM) × [13.03] SOLIDUS (SY) ÷ [0.3] -× 000D ÷ 0308 × 0020 × 002F ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] +× 000D ÷ 0308 × 002F ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM1_CM) × [13.03] SOLIDUS (SY) ÷ [0.3] +× 000D ÷ 0308 × 0020 × 002F ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] × 000D ÷ 2060 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] WORD JOINER (WJ) ÷ [0.3] × 000D ÷ 0020 × 2060 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] -× 000D ÷ 0308 × 2060 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM) × [11.01] WORD JOINER (WJ) ÷ [0.3] -× 000D ÷ 0308 × 0020 × 2060 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] +× 000D ÷ 0308 × 2060 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM1_CM) × [11.01] WORD JOINER (WJ) ÷ [0.3] +× 000D ÷ 0308 × 0020 × 2060 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] × 000D ÷ 200B ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] × 000D ÷ 0020 × 200B ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] -× 000D ÷ 0308 × 200B ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] -× 000D ÷ 0308 × 0020 × 200B ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] +× 000D ÷ 0308 × 200B ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM1_CM) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] +× 000D ÷ 0308 × 0020 × 200B ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] × 000D ÷ 1F1E6 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] × 000D ÷ 0020 ÷ 1F1E6 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -× 000D ÷ 0308 ÷ 1F1E6 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -× 000D ÷ 0308 × 0020 ÷ 1F1E6 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 000D ÷ 0308 ÷ 1F1E6 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 000D ÷ 0308 × 0020 ÷ 1F1E6 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 000D ÷ 261D ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 000D ÷ 0020 ÷ 261D ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] SPACE (SP) ÷ [18.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 000D ÷ 0308 ÷ 261D ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 000D ÷ 0308 × 0020 ÷ 261D ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 000D ÷ 1F3FB ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 000D ÷ 0020 ÷ 1F3FB ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] SPACE (SP) ÷ [18.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 000D ÷ 0308 ÷ 1F3FB ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 000D ÷ 0308 × 0020 ÷ 1F3FB ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 000D ÷ 0001 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 000D ÷ 0020 ÷ 0001 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 000D ÷ 0308 × 0001 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM1_CM) × [9.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 000D ÷ 0308 × 0020 ÷ 0001 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 000D ÷ 200D ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 000D ÷ 0020 ÷ 200D ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] SPACE (SP) ÷ [18.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 000D ÷ 0308 × 200D ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM1_CM) × [9.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 000D ÷ 0308 × 0020 ÷ 200D ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] × 000D ÷ 00A7 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] SECTION SIGN (AI_AL) ÷ [0.3] × 000D ÷ 0020 ÷ 00A7 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] -× 000D ÷ 0308 × 00A7 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM) × [28.0] SECTION SIGN (AI_AL) ÷ [0.3] -× 000D ÷ 0308 × 0020 ÷ 00A7 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] +× 000D ÷ 0308 × 00A7 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM1_CM) × [28.0] SECTION SIGN (AI_AL) ÷ [0.3] +× 000D ÷ 0308 × 0020 ÷ 00A7 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] × 000D ÷ 50005 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] <reserved-50005> (XX_AL) ÷ [0.3] × 000D ÷ 0020 ÷ 50005 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] -× 000D ÷ 0308 × 50005 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM) × [28.0] <reserved-50005> (XX_AL) ÷ [0.3] -× 000D ÷ 0308 × 0020 ÷ 50005 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] +× 000D ÷ 0308 × 50005 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM1_CM) × [28.0] <reserved-50005> (XX_AL) ÷ [0.3] +× 000D ÷ 0308 × 0020 ÷ 50005 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] × 000D ÷ 0E01 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] × 000D ÷ 0020 ÷ 0E01 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] -× 000D ÷ 0308 × 0E01 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM) × [28.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] -× 000D ÷ 0308 × 0020 ÷ 0E01 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] +× 000D ÷ 0308 × 0E01 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM1_CM) × [28.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] +× 000D ÷ 0308 × 0020 ÷ 0E01 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] × 000D ÷ 3041 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] × 000D ÷ 0020 ÷ 3041 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] -× 000D ÷ 0308 × 3041 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] -× 000D ÷ 0308 × 0020 ÷ 3041 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] +× 000D ÷ 0308 × 3041 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM1_CM) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] +× 000D ÷ 0308 × 0020 ÷ 3041 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] × 0021 ÷ 0023 ÷ # × [0.3] EXCLAMATION MARK (EX) ÷ [999.0] NUMBER SIGN (AL) ÷ [0.3] × 0021 × 0020 ÷ 0023 ÷ # × [0.3] EXCLAMATION MARK (EX) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] -× 0021 × 0308 ÷ 0023 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] NUMBER SIGN (AL) ÷ [0.3] -× 0021 × 0308 × 0020 ÷ 0023 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] +× 0021 × 0308 ÷ 0023 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] NUMBER SIGN (AL) ÷ [0.3] +× 0021 × 0308 × 0020 ÷ 0023 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] × 0021 ÷ 2014 ÷ # × [0.3] EXCLAMATION MARK (EX) ÷ [999.0] EM DASH (B2) ÷ [0.3] × 0021 × 0020 ÷ 2014 ÷ # × [0.3] EXCLAMATION MARK (EX) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] -× 0021 × 0308 ÷ 2014 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] EM DASH (B2) ÷ [0.3] -× 0021 × 0308 × 0020 ÷ 2014 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] +× 0021 × 0308 ÷ 2014 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] EM DASH (B2) ÷ [0.3] +× 0021 × 0308 × 0020 ÷ 2014 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] × 0021 × 0009 ÷ # × [0.3] EXCLAMATION MARK (EX) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] × 0021 × 0020 ÷ 0009 ÷ # × [0.3] EXCLAMATION MARK (EX) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] -× 0021 × 0308 × 0009 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] -× 0021 × 0308 × 0020 ÷ 0009 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] +× 0021 × 0308 × 0009 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] +× 0021 × 0308 × 0020 ÷ 0009 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] × 0021 ÷ 00B4 ÷ # × [0.3] EXCLAMATION MARK (EX) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3] × 0021 × 0020 ÷ 00B4 ÷ # × [0.3] EXCLAMATION MARK (EX) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] -× 0021 × 0308 ÷ 00B4 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3] -× 0021 × 0308 × 0020 ÷ 00B4 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] +× 0021 × 0308 ÷ 00B4 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3] +× 0021 × 0308 × 0020 ÷ 00B4 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] × 0021 × 000B ÷ # × [0.3] EXCLAMATION MARK (EX) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] × 0021 × 0020 × 000B ÷ # × [0.3] EXCLAMATION MARK (EX) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] -× 0021 × 0308 × 000B ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] -× 0021 × 0308 × 0020 × 000B ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] +× 0021 × 0308 × 000B ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] +× 0021 × 0308 × 0020 × 000B ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] × 0021 ÷ FFFC ÷ # × [0.3] EXCLAMATION MARK (EX) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] × 0021 × 0020 ÷ FFFC ÷ # × [0.3] EXCLAMATION MARK (EX) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] -× 0021 × 0308 ÷ FFFC ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] -× 0021 × 0308 × 0020 ÷ FFFC ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] +× 0021 × 0308 ÷ FFFC ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] +× 0021 × 0308 × 0020 ÷ FFFC ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] × 0021 × 007D ÷ # × [0.3] EXCLAMATION MARK (EX) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] × 0021 × 0020 × 007D ÷ # × [0.3] EXCLAMATION MARK (EX) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] -× 0021 × 0308 × 007D ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM) × [13.03] RIGHT CURLY BRACKET (CL) ÷ [0.3] -× 0021 × 0308 × 0020 × 007D ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] +× 0021 × 0308 × 007D ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] RIGHT CURLY BRACKET (CL) ÷ [0.3] +× 0021 × 0308 × 0020 × 007D ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] × 0021 × 0029 ÷ # × [0.3] EXCLAMATION MARK (EX) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] × 0021 × 0020 × 0029 ÷ # × [0.3] EXCLAMATION MARK (EX) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 0021 × 0308 × 0029 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM) × [13.03] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 0021 × 0308 × 0020 × 0029 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 0021 × 0001 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] <START OF HEADING> (CM) ÷ [0.3] -× 0021 × 0020 ÷ 0001 ÷ # × [0.3] EXCLAMATION MARK (EX) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM) ÷ [0.3] -× 0021 × 0308 × 0001 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM) × [9.0] <START OF HEADING> (CM) ÷ [0.3] -× 0021 × 0308 × 0020 ÷ 0001 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM) ÷ [0.3] +× 0021 × 0308 × 0029 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] RIGHT PARENTHESIS (CP) ÷ [0.3] +× 0021 × 0308 × 0020 × 0029 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] × 0021 × 000D ÷ # × [0.3] EXCLAMATION MARK (EX) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] × 0021 × 0020 × 000D ÷ # × [0.3] EXCLAMATION MARK (EX) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -× 0021 × 0308 × 000D ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -× 0021 × 0308 × 0020 × 000D ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +× 0021 × 0308 × 000D ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +× 0021 × 0308 × 0020 × 000D ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] × 0021 × 0021 ÷ # × [0.3] EXCLAMATION MARK (EX) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] × 0021 × 0020 × 0021 ÷ # × [0.3] EXCLAMATION MARK (EX) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] -× 0021 × 0308 × 0021 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] -× 0021 × 0308 × 0020 × 0021 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] +× 0021 × 0308 × 0021 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] +× 0021 × 0308 × 0020 × 0021 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] × 0021 × 00A0 ÷ # × [0.3] EXCLAMATION MARK (EX) × [12.1] NO-BREAK SPACE (GL) ÷ [0.3] × 0021 × 0020 ÷ 00A0 ÷ # × [0.3] EXCLAMATION MARK (EX) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] -× 0021 × 0308 × 00A0 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM) × [12.2] NO-BREAK SPACE (GL) ÷ [0.3] -× 0021 × 0308 × 0020 ÷ 00A0 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] +× 0021 × 0308 × 00A0 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM1_CM) × [12.2] NO-BREAK SPACE (GL) ÷ [0.3] +× 0021 × 0308 × 0020 ÷ 00A0 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] × 0021 ÷ AC00 ÷ # × [0.3] EXCLAMATION MARK (EX) ÷ [999.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] × 0021 × 0020 ÷ AC00 ÷ # × [0.3] EXCLAMATION MARK (EX) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] -× 0021 × 0308 ÷ AC00 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] -× 0021 × 0308 × 0020 ÷ AC00 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] +× 0021 × 0308 ÷ AC00 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] +× 0021 × 0308 × 0020 ÷ AC00 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] × 0021 ÷ AC01 ÷ # × [0.3] EXCLAMATION MARK (EX) ÷ [999.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] × 0021 × 0020 ÷ AC01 ÷ # × [0.3] EXCLAMATION MARK (EX) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] -× 0021 × 0308 ÷ AC01 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] -× 0021 × 0308 × 0020 ÷ AC01 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] +× 0021 × 0308 ÷ AC01 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] +× 0021 × 0308 × 0020 ÷ AC01 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] × 0021 ÷ 05D0 ÷ # × [0.3] EXCLAMATION MARK (EX) ÷ [999.0] HEBREW LETTER ALEF (HL) ÷ [0.3] × 0021 × 0020 ÷ 05D0 ÷ # × [0.3] EXCLAMATION MARK (EX) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] -× 0021 × 0308 ÷ 05D0 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HEBREW LETTER ALEF (HL) ÷ [0.3] -× 0021 × 0308 × 0020 ÷ 05D0 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] +× 0021 × 0308 ÷ 05D0 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HEBREW LETTER ALEF (HL) ÷ [0.3] +× 0021 × 0308 × 0020 ÷ 05D0 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] × 0021 × 002D ÷ # × [0.3] EXCLAMATION MARK (EX) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] × 0021 × 0020 ÷ 002D ÷ # × [0.3] EXCLAMATION MARK (EX) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] -× 0021 × 0308 × 002D ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] -× 0021 × 0308 × 0020 ÷ 002D ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] +× 0021 × 0308 × 002D ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] +× 0021 × 0308 × 0020 ÷ 002D ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] × 0021 ÷ 231A ÷ # × [0.3] EXCLAMATION MARK (EX) ÷ [999.0] WATCH (ID) ÷ [0.3] × 0021 × 0020 ÷ 231A ÷ # × [0.3] EXCLAMATION MARK (EX) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] -× 0021 × 0308 ÷ 231A ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] WATCH (ID) ÷ [0.3] -× 0021 × 0308 × 0020 ÷ 231A ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] +× 0021 × 0308 ÷ 231A ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] WATCH (ID) ÷ [0.3] +× 0021 × 0308 × 0020 ÷ 231A ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] × 0021 × 2024 ÷ # × [0.3] EXCLAMATION MARK (EX) × [22.02] ONE DOT LEADER (IN) ÷ [0.3] × 0021 × 0020 ÷ 2024 ÷ # × [0.3] EXCLAMATION MARK (EX) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] -× 0021 × 0308 × 2024 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM) × [22.02] ONE DOT LEADER (IN) ÷ [0.3] -× 0021 × 0308 × 0020 ÷ 2024 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] +× 0021 × 0308 × 2024 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM1_CM) × [22.02] ONE DOT LEADER (IN) ÷ [0.3] +× 0021 × 0308 × 0020 ÷ 2024 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] × 0021 × 002C ÷ # × [0.3] EXCLAMATION MARK (EX) × [13.02] COMMA (IS) ÷ [0.3] × 0021 × 0020 × 002C ÷ # × [0.3] EXCLAMATION MARK (EX) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] -× 0021 × 0308 × 002C ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM) × [13.03] COMMA (IS) ÷ [0.3] -× 0021 × 0308 × 0020 × 002C ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] +× 0021 × 0308 × 002C ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] COMMA (IS) ÷ [0.3] +× 0021 × 0308 × 0020 × 002C ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] × 0021 ÷ 1100 ÷ # × [0.3] EXCLAMATION MARK (EX) ÷ [999.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] × 0021 × 0020 ÷ 1100 ÷ # × [0.3] EXCLAMATION MARK (EX) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] -× 0021 × 0308 ÷ 1100 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] -× 0021 × 0308 × 0020 ÷ 1100 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] +× 0021 × 0308 ÷ 1100 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] +× 0021 × 0308 × 0020 ÷ 1100 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] × 0021 ÷ 11A8 ÷ # × [0.3] EXCLAMATION MARK (EX) ÷ [999.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] × 0021 × 0020 ÷ 11A8 ÷ # × [0.3] EXCLAMATION MARK (EX) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] -× 0021 × 0308 ÷ 11A8 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] -× 0021 × 0308 × 0020 ÷ 11A8 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] +× 0021 × 0308 ÷ 11A8 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] +× 0021 × 0308 × 0020 ÷ 11A8 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] × 0021 ÷ 1160 ÷ # × [0.3] EXCLAMATION MARK (EX) ÷ [999.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] × 0021 × 0020 ÷ 1160 ÷ # × [0.3] EXCLAMATION MARK (EX) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] -× 0021 × 0308 ÷ 1160 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] -× 0021 × 0308 × 0020 ÷ 1160 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] +× 0021 × 0308 ÷ 1160 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] +× 0021 × 0308 × 0020 ÷ 1160 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] × 0021 × 000A ÷ # × [0.3] EXCLAMATION MARK (EX) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] × 0021 × 0020 × 000A ÷ # × [0.3] EXCLAMATION MARK (EX) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] -× 0021 × 0308 × 000A ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] -× 0021 × 0308 × 0020 × 000A ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] +× 0021 × 0308 × 000A ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] +× 0021 × 0308 × 0020 × 000A ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] × 0021 × 0085 ÷ # × [0.3] EXCLAMATION MARK (EX) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] × 0021 × 0020 × 0085 ÷ # × [0.3] EXCLAMATION MARK (EX) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] -× 0021 × 0308 × 0085 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] -× 0021 × 0308 × 0020 × 0085 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] +× 0021 × 0308 × 0085 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] +× 0021 × 0308 × 0020 × 0085 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] × 0021 × 17D6 ÷ # × [0.3] EXCLAMATION MARK (EX) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] × 0021 × 0020 ÷ 17D6 ÷ # × [0.3] EXCLAMATION MARK (EX) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] -× 0021 × 0308 × 17D6 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] -× 0021 × 0308 × 0020 ÷ 17D6 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] +× 0021 × 0308 × 17D6 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] +× 0021 × 0308 × 0020 ÷ 17D6 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] × 0021 ÷ 0030 ÷ # × [0.3] EXCLAMATION MARK (EX) ÷ [999.0] DIGIT ZERO (NU) ÷ [0.3] × 0021 × 0020 ÷ 0030 ÷ # × [0.3] EXCLAMATION MARK (EX) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] -× 0021 × 0308 ÷ 0030 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] DIGIT ZERO (NU) ÷ [0.3] -× 0021 × 0308 × 0020 ÷ 0030 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] +× 0021 × 0308 ÷ 0030 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] DIGIT ZERO (NU) ÷ [0.3] +× 0021 × 0308 × 0020 ÷ 0030 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] × 0021 ÷ 0028 ÷ # × [0.3] EXCLAMATION MARK (EX) ÷ [999.0] LEFT PARENTHESIS (OP) ÷ [0.3] × 0021 × 0020 ÷ 0028 ÷ # × [0.3] EXCLAMATION MARK (EX) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] -× 0021 × 0308 ÷ 0028 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] LEFT PARENTHESIS (OP) ÷ [0.3] -× 0021 × 0308 × 0020 ÷ 0028 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] +× 0021 × 0308 ÷ 0028 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] LEFT PARENTHESIS (OP) ÷ [0.3] +× 0021 × 0308 × 0020 ÷ 0028 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] × 0021 ÷ 0025 ÷ # × [0.3] EXCLAMATION MARK (EX) ÷ [999.0] PERCENT SIGN (PO) ÷ [0.3] × 0021 × 0020 ÷ 0025 ÷ # × [0.3] EXCLAMATION MARK (EX) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] -× 0021 × 0308 ÷ 0025 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] PERCENT SIGN (PO) ÷ [0.3] -× 0021 × 0308 × 0020 ÷ 0025 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] +× 0021 × 0308 ÷ 0025 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] PERCENT SIGN (PO) ÷ [0.3] +× 0021 × 0308 × 0020 ÷ 0025 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] × 0021 ÷ 0024 ÷ # × [0.3] EXCLAMATION MARK (EX) ÷ [999.0] DOLLAR SIGN (PR) ÷ [0.3] × 0021 × 0020 ÷ 0024 ÷ # × [0.3] EXCLAMATION MARK (EX) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] -× 0021 × 0308 ÷ 0024 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] DOLLAR SIGN (PR) ÷ [0.3] -× 0021 × 0308 × 0020 ÷ 0024 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] +× 0021 × 0308 ÷ 0024 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] DOLLAR SIGN (PR) ÷ [0.3] +× 0021 × 0308 × 0020 ÷ 0024 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] × 0021 × 0022 ÷ # × [0.3] EXCLAMATION MARK (EX) × [19.01] QUOTATION MARK (QU) ÷ [0.3] × 0021 × 0020 ÷ 0022 ÷ # × [0.3] EXCLAMATION MARK (EX) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] -× 0021 × 0308 × 0022 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM) × [19.01] QUOTATION MARK (QU) ÷ [0.3] -× 0021 × 0308 × 0020 ÷ 0022 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] +× 0021 × 0308 × 0022 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM1_CM) × [19.01] QUOTATION MARK (QU) ÷ [0.3] +× 0021 × 0308 × 0020 ÷ 0022 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] × 0021 × 0020 ÷ # × [0.3] EXCLAMATION MARK (EX) × [7.01] SPACE (SP) ÷ [0.3] × 0021 × 0020 × 0020 ÷ # × [0.3] EXCLAMATION MARK (EX) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] -× 0021 × 0308 × 0020 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [0.3] -× 0021 × 0308 × 0020 × 0020 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] +× 0021 × 0308 × 0020 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [0.3] +× 0021 × 0308 × 0020 × 0020 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] × 0021 × 002F ÷ # × [0.3] EXCLAMATION MARK (EX) × [13.02] SOLIDUS (SY) ÷ [0.3] × 0021 × 0020 × 002F ÷ # × [0.3] EXCLAMATION MARK (EX) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] -× 0021 × 0308 × 002F ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM) × [13.03] SOLIDUS (SY) ÷ [0.3] -× 0021 × 0308 × 0020 × 002F ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] +× 0021 × 0308 × 002F ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] SOLIDUS (SY) ÷ [0.3] +× 0021 × 0308 × 0020 × 002F ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] × 0021 × 2060 ÷ # × [0.3] EXCLAMATION MARK (EX) × [11.01] WORD JOINER (WJ) ÷ [0.3] × 0021 × 0020 × 2060 ÷ # × [0.3] EXCLAMATION MARK (EX) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] -× 0021 × 0308 × 2060 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM) × [11.01] WORD JOINER (WJ) ÷ [0.3] -× 0021 × 0308 × 0020 × 2060 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] +× 0021 × 0308 × 2060 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM1_CM) × [11.01] WORD JOINER (WJ) ÷ [0.3] +× 0021 × 0308 × 0020 × 2060 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] × 0021 × 200B ÷ # × [0.3] EXCLAMATION MARK (EX) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] × 0021 × 0020 × 200B ÷ # × [0.3] EXCLAMATION MARK (EX) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] -× 0021 × 0308 × 200B ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] -× 0021 × 0308 × 0020 × 200B ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] +× 0021 × 0308 × 200B ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] +× 0021 × 0308 × 0020 × 200B ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] × 0021 ÷ 1F1E6 ÷ # × [0.3] EXCLAMATION MARK (EX) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] × 0021 × 0020 ÷ 1F1E6 ÷ # × [0.3] EXCLAMATION MARK (EX) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -× 0021 × 0308 ÷ 1F1E6 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -× 0021 × 0308 × 0020 ÷ 1F1E6 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 0021 × 0308 ÷ 1F1E6 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 0021 × 0308 × 0020 ÷ 1F1E6 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 0021 ÷ 261D ÷ # × [0.3] EXCLAMATION MARK (EX) ÷ [999.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 0021 × 0020 ÷ 261D ÷ # × [0.3] EXCLAMATION MARK (EX) × [7.01] SPACE (SP) ÷ [18.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 0021 × 0308 ÷ 261D ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 0021 × 0308 × 0020 ÷ 261D ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 0021 ÷ 1F3FB ÷ # × [0.3] EXCLAMATION MARK (EX) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 0021 × 0020 ÷ 1F3FB ÷ # × [0.3] EXCLAMATION MARK (EX) × [7.01] SPACE (SP) ÷ [18.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 0021 × 0308 ÷ 1F3FB ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 0021 × 0308 × 0020 ÷ 1F3FB ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 0021 × 0001 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 0021 × 0020 ÷ 0001 ÷ # × [0.3] EXCLAMATION MARK (EX) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 0021 × 0308 × 0001 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM1_CM) × [9.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 0021 × 0308 × 0020 ÷ 0001 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 0021 × 200D ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 0021 × 0020 ÷ 200D ÷ # × [0.3] EXCLAMATION MARK (EX) × [7.01] SPACE (SP) ÷ [18.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 0021 × 0308 × 200D ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM1_CM) × [9.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 0021 × 0308 × 0020 ÷ 200D ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] × 0021 ÷ 00A7 ÷ # × [0.3] EXCLAMATION MARK (EX) ÷ [999.0] SECTION SIGN (AI_AL) ÷ [0.3] × 0021 × 0020 ÷ 00A7 ÷ # × [0.3] EXCLAMATION MARK (EX) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] -× 0021 × 0308 ÷ 00A7 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] SECTION SIGN (AI_AL) ÷ [0.3] -× 0021 × 0308 × 0020 ÷ 00A7 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] +× 0021 × 0308 ÷ 00A7 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] SECTION SIGN (AI_AL) ÷ [0.3] +× 0021 × 0308 × 0020 ÷ 00A7 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] × 0021 ÷ 50005 ÷ # × [0.3] EXCLAMATION MARK (EX) ÷ [999.0] <reserved-50005> (XX_AL) ÷ [0.3] × 0021 × 0020 ÷ 50005 ÷ # × [0.3] EXCLAMATION MARK (EX) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] -× 0021 × 0308 ÷ 50005 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] <reserved-50005> (XX_AL) ÷ [0.3] -× 0021 × 0308 × 0020 ÷ 50005 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] +× 0021 × 0308 ÷ 50005 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] <reserved-50005> (XX_AL) ÷ [0.3] +× 0021 × 0308 × 0020 ÷ 50005 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] × 0021 ÷ 0E01 ÷ # × [0.3] EXCLAMATION MARK (EX) ÷ [999.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] × 0021 × 0020 ÷ 0E01 ÷ # × [0.3] EXCLAMATION MARK (EX) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] -× 0021 × 0308 ÷ 0E01 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] -× 0021 × 0308 × 0020 ÷ 0E01 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] +× 0021 × 0308 ÷ 0E01 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] +× 0021 × 0308 × 0020 ÷ 0E01 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] × 0021 × 3041 ÷ # × [0.3] EXCLAMATION MARK (EX) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] × 0021 × 0020 ÷ 3041 ÷ # × [0.3] EXCLAMATION MARK (EX) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] -× 0021 × 0308 × 3041 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] -× 0021 × 0308 × 0020 ÷ 3041 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] +× 0021 × 0308 × 3041 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] +× 0021 × 0308 × 0020 ÷ 3041 ÷ # × [0.3] EXCLAMATION MARK (EX) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] × 00A0 × 0023 ÷ # × [0.3] NO-BREAK SPACE (GL) × [12.0] NUMBER SIGN (AL) ÷ [0.3] × 00A0 × 0020 ÷ 0023 ÷ # × [0.3] NO-BREAK SPACE (GL) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] -× 00A0 × 0308 × 0023 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM) × [12.0] NUMBER SIGN (AL) ÷ [0.3] -× 00A0 × 0308 × 0020 ÷ 0023 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] +× 00A0 × 0308 × 0023 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [12.0] NUMBER SIGN (AL) ÷ [0.3] +× 00A0 × 0308 × 0020 ÷ 0023 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] × 00A0 × 2014 ÷ # × [0.3] NO-BREAK SPACE (GL) × [12.0] EM DASH (B2) ÷ [0.3] × 00A0 × 0020 ÷ 2014 ÷ # × [0.3] NO-BREAK SPACE (GL) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] -× 00A0 × 0308 × 2014 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM) × [12.0] EM DASH (B2) ÷ [0.3] -× 00A0 × 0308 × 0020 ÷ 2014 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] +× 00A0 × 0308 × 2014 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [12.0] EM DASH (B2) ÷ [0.3] +× 00A0 × 0308 × 0020 ÷ 2014 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] × 00A0 × 0009 ÷ # × [0.3] NO-BREAK SPACE (GL) × [12.0] <CHARACTER TABULATION> (BA) ÷ [0.3] × 00A0 × 0020 ÷ 0009 ÷ # × [0.3] NO-BREAK SPACE (GL) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] -× 00A0 × 0308 × 0009 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM) × [12.0] <CHARACTER TABULATION> (BA) ÷ [0.3] -× 00A0 × 0308 × 0020 ÷ 0009 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] +× 00A0 × 0308 × 0009 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [12.0] <CHARACTER TABULATION> (BA) ÷ [0.3] +× 00A0 × 0308 × 0020 ÷ 0009 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] × 00A0 × 00B4 ÷ # × [0.3] NO-BREAK SPACE (GL) × [12.0] ACUTE ACCENT (BB) ÷ [0.3] × 00A0 × 0020 ÷ 00B4 ÷ # × [0.3] NO-BREAK SPACE (GL) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] -× 00A0 × 0308 × 00B4 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM) × [12.0] ACUTE ACCENT (BB) ÷ [0.3] -× 00A0 × 0308 × 0020 ÷ 00B4 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] +× 00A0 × 0308 × 00B4 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [12.0] ACUTE ACCENT (BB) ÷ [0.3] +× 00A0 × 0308 × 0020 ÷ 00B4 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] × 00A0 × 000B ÷ # × [0.3] NO-BREAK SPACE (GL) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] × 00A0 × 0020 × 000B ÷ # × [0.3] NO-BREAK SPACE (GL) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] -× 00A0 × 0308 × 000B ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] -× 00A0 × 0308 × 0020 × 000B ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] +× 00A0 × 0308 × 000B ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] +× 00A0 × 0308 × 0020 × 000B ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] × 00A0 × FFFC ÷ # × [0.3] NO-BREAK SPACE (GL) × [12.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] × 00A0 × 0020 ÷ FFFC ÷ # × [0.3] NO-BREAK SPACE (GL) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] -× 00A0 × 0308 × FFFC ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM) × [12.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] -× 00A0 × 0308 × 0020 ÷ FFFC ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] +× 00A0 × 0308 × FFFC ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [12.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] +× 00A0 × 0308 × 0020 ÷ FFFC ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] × 00A0 × 007D ÷ # × [0.3] NO-BREAK SPACE (GL) × [12.0] RIGHT CURLY BRACKET (CL) ÷ [0.3] × 00A0 × 0020 × 007D ÷ # × [0.3] NO-BREAK SPACE (GL) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] -× 00A0 × 0308 × 007D ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM) × [12.0] RIGHT CURLY BRACKET (CL) ÷ [0.3] -× 00A0 × 0308 × 0020 × 007D ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] +× 00A0 × 0308 × 007D ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [12.0] RIGHT CURLY BRACKET (CL) ÷ [0.3] +× 00A0 × 0308 × 0020 × 007D ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] × 00A0 × 0029 ÷ # × [0.3] NO-BREAK SPACE (GL) × [12.0] RIGHT PARENTHESIS (CP) ÷ [0.3] × 00A0 × 0020 × 0029 ÷ # × [0.3] NO-BREAK SPACE (GL) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 00A0 × 0308 × 0029 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM) × [12.0] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 00A0 × 0308 × 0020 × 0029 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 00A0 × 0001 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] <START OF HEADING> (CM) ÷ [0.3] -× 00A0 × 0020 ÷ 0001 ÷ # × [0.3] NO-BREAK SPACE (GL) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM) ÷ [0.3] -× 00A0 × 0308 × 0001 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM) × [9.0] <START OF HEADING> (CM) ÷ [0.3] -× 00A0 × 0308 × 0020 ÷ 0001 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM) ÷ [0.3] +× 00A0 × 0308 × 0029 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [12.0] RIGHT PARENTHESIS (CP) ÷ [0.3] +× 00A0 × 0308 × 0020 × 0029 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] × 00A0 × 000D ÷ # × [0.3] NO-BREAK SPACE (GL) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] × 00A0 × 0020 × 000D ÷ # × [0.3] NO-BREAK SPACE (GL) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -× 00A0 × 0308 × 000D ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -× 00A0 × 0308 × 0020 × 000D ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +× 00A0 × 0308 × 000D ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +× 00A0 × 0308 × 0020 × 000D ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] × 00A0 × 0021 ÷ # × [0.3] NO-BREAK SPACE (GL) × [12.0] EXCLAMATION MARK (EX) ÷ [0.3] × 00A0 × 0020 × 0021 ÷ # × [0.3] NO-BREAK SPACE (GL) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] -× 00A0 × 0308 × 0021 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM) × [12.0] EXCLAMATION MARK (EX) ÷ [0.3] -× 00A0 × 0308 × 0020 × 0021 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] +× 00A0 × 0308 × 0021 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [12.0] EXCLAMATION MARK (EX) ÷ [0.3] +× 00A0 × 0308 × 0020 × 0021 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] × 00A0 × 00A0 ÷ # × [0.3] NO-BREAK SPACE (GL) × [12.0] NO-BREAK SPACE (GL) ÷ [0.3] × 00A0 × 0020 ÷ 00A0 ÷ # × [0.3] NO-BREAK SPACE (GL) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] -× 00A0 × 0308 × 00A0 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM) × [12.0] NO-BREAK SPACE (GL) ÷ [0.3] -× 00A0 × 0308 × 0020 ÷ 00A0 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] +× 00A0 × 0308 × 00A0 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [12.0] NO-BREAK SPACE (GL) ÷ [0.3] +× 00A0 × 0308 × 0020 ÷ 00A0 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] × 00A0 × AC00 ÷ # × [0.3] NO-BREAK SPACE (GL) × [12.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] × 00A0 × 0020 ÷ AC00 ÷ # × [0.3] NO-BREAK SPACE (GL) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] -× 00A0 × 0308 × AC00 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM) × [12.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] -× 00A0 × 0308 × 0020 ÷ AC00 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] +× 00A0 × 0308 × AC00 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [12.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] +× 00A0 × 0308 × 0020 ÷ AC00 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] × 00A0 × AC01 ÷ # × [0.3] NO-BREAK SPACE (GL) × [12.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] × 00A0 × 0020 ÷ AC01 ÷ # × [0.3] NO-BREAK SPACE (GL) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] -× 00A0 × 0308 × AC01 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM) × [12.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] -× 00A0 × 0308 × 0020 ÷ AC01 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] +× 00A0 × 0308 × AC01 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [12.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] +× 00A0 × 0308 × 0020 ÷ AC01 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] × 00A0 × 05D0 ÷ # × [0.3] NO-BREAK SPACE (GL) × [12.0] HEBREW LETTER ALEF (HL) ÷ [0.3] × 00A0 × 0020 ÷ 05D0 ÷ # × [0.3] NO-BREAK SPACE (GL) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] -× 00A0 × 0308 × 05D0 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM) × [12.0] HEBREW LETTER ALEF (HL) ÷ [0.3] -× 00A0 × 0308 × 0020 ÷ 05D0 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] +× 00A0 × 0308 × 05D0 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [12.0] HEBREW LETTER ALEF (HL) ÷ [0.3] +× 00A0 × 0308 × 0020 ÷ 05D0 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] × 00A0 × 002D ÷ # × [0.3] NO-BREAK SPACE (GL) × [12.0] HYPHEN-MINUS (HY) ÷ [0.3] × 00A0 × 0020 ÷ 002D ÷ # × [0.3] NO-BREAK SPACE (GL) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] -× 00A0 × 0308 × 002D ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM) × [12.0] HYPHEN-MINUS (HY) ÷ [0.3] -× 00A0 × 0308 × 0020 ÷ 002D ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] +× 00A0 × 0308 × 002D ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [12.0] HYPHEN-MINUS (HY) ÷ [0.3] +× 00A0 × 0308 × 0020 ÷ 002D ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] × 00A0 × 231A ÷ # × [0.3] NO-BREAK SPACE (GL) × [12.0] WATCH (ID) ÷ [0.3] × 00A0 × 0020 ÷ 231A ÷ # × [0.3] NO-BREAK SPACE (GL) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] -× 00A0 × 0308 × 231A ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM) × [12.0] WATCH (ID) ÷ [0.3] -× 00A0 × 0308 × 0020 ÷ 231A ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] +× 00A0 × 0308 × 231A ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [12.0] WATCH (ID) ÷ [0.3] +× 00A0 × 0308 × 0020 ÷ 231A ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] × 00A0 × 2024 ÷ # × [0.3] NO-BREAK SPACE (GL) × [12.0] ONE DOT LEADER (IN) ÷ [0.3] × 00A0 × 0020 ÷ 2024 ÷ # × [0.3] NO-BREAK SPACE (GL) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] -× 00A0 × 0308 × 2024 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM) × [12.0] ONE DOT LEADER (IN) ÷ [0.3] -× 00A0 × 0308 × 0020 ÷ 2024 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] +× 00A0 × 0308 × 2024 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [12.0] ONE DOT LEADER (IN) ÷ [0.3] +× 00A0 × 0308 × 0020 ÷ 2024 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] × 00A0 × 002C ÷ # × [0.3] NO-BREAK SPACE (GL) × [12.0] COMMA (IS) ÷ [0.3] × 00A0 × 0020 × 002C ÷ # × [0.3] NO-BREAK SPACE (GL) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] -× 00A0 × 0308 × 002C ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM) × [12.0] COMMA (IS) ÷ [0.3] -× 00A0 × 0308 × 0020 × 002C ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] +× 00A0 × 0308 × 002C ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [12.0] COMMA (IS) ÷ [0.3] +× 00A0 × 0308 × 0020 × 002C ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] × 00A0 × 1100 ÷ # × [0.3] NO-BREAK SPACE (GL) × [12.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] × 00A0 × 0020 ÷ 1100 ÷ # × [0.3] NO-BREAK SPACE (GL) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] -× 00A0 × 0308 × 1100 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM) × [12.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] -× 00A0 × 0308 × 0020 ÷ 1100 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] +× 00A0 × 0308 × 1100 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [12.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] +× 00A0 × 0308 × 0020 ÷ 1100 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] × 00A0 × 11A8 ÷ # × [0.3] NO-BREAK SPACE (GL) × [12.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] × 00A0 × 0020 ÷ 11A8 ÷ # × [0.3] NO-BREAK SPACE (GL) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] -× 00A0 × 0308 × 11A8 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM) × [12.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] -× 00A0 × 0308 × 0020 ÷ 11A8 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] +× 00A0 × 0308 × 11A8 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [12.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] +× 00A0 × 0308 × 0020 ÷ 11A8 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] × 00A0 × 1160 ÷ # × [0.3] NO-BREAK SPACE (GL) × [12.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] × 00A0 × 0020 ÷ 1160 ÷ # × [0.3] NO-BREAK SPACE (GL) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] -× 00A0 × 0308 × 1160 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM) × [12.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] -× 00A0 × 0308 × 0020 ÷ 1160 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] +× 00A0 × 0308 × 1160 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [12.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] +× 00A0 × 0308 × 0020 ÷ 1160 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] × 00A0 × 000A ÷ # × [0.3] NO-BREAK SPACE (GL) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] × 00A0 × 0020 × 000A ÷ # × [0.3] NO-BREAK SPACE (GL) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] -× 00A0 × 0308 × 000A ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] -× 00A0 × 0308 × 0020 × 000A ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] +× 00A0 × 0308 × 000A ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] +× 00A0 × 0308 × 0020 × 000A ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] × 00A0 × 0085 ÷ # × [0.3] NO-BREAK SPACE (GL) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] × 00A0 × 0020 × 0085 ÷ # × [0.3] NO-BREAK SPACE (GL) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] -× 00A0 × 0308 × 0085 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] -× 00A0 × 0308 × 0020 × 0085 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] +× 00A0 × 0308 × 0085 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] +× 00A0 × 0308 × 0020 × 0085 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] × 00A0 × 17D6 ÷ # × [0.3] NO-BREAK SPACE (GL) × [12.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] × 00A0 × 0020 ÷ 17D6 ÷ # × [0.3] NO-BREAK SPACE (GL) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] -× 00A0 × 0308 × 17D6 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM) × [12.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] -× 00A0 × 0308 × 0020 ÷ 17D6 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] +× 00A0 × 0308 × 17D6 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [12.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] +× 00A0 × 0308 × 0020 ÷ 17D6 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] × 00A0 × 0030 ÷ # × [0.3] NO-BREAK SPACE (GL) × [12.0] DIGIT ZERO (NU) ÷ [0.3] × 00A0 × 0020 ÷ 0030 ÷ # × [0.3] NO-BREAK SPACE (GL) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] -× 00A0 × 0308 × 0030 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM) × [12.0] DIGIT ZERO (NU) ÷ [0.3] -× 00A0 × 0308 × 0020 ÷ 0030 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] +× 00A0 × 0308 × 0030 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [12.0] DIGIT ZERO (NU) ÷ [0.3] +× 00A0 × 0308 × 0020 ÷ 0030 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] × 00A0 × 0028 ÷ # × [0.3] NO-BREAK SPACE (GL) × [12.0] LEFT PARENTHESIS (OP) ÷ [0.3] × 00A0 × 0020 ÷ 0028 ÷ # × [0.3] NO-BREAK SPACE (GL) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] -× 00A0 × 0308 × 0028 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM) × [12.0] LEFT PARENTHESIS (OP) ÷ [0.3] -× 00A0 × 0308 × 0020 ÷ 0028 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] +× 00A0 × 0308 × 0028 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [12.0] LEFT PARENTHESIS (OP) ÷ [0.3] +× 00A0 × 0308 × 0020 ÷ 0028 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] × 00A0 × 0025 ÷ # × [0.3] NO-BREAK SPACE (GL) × [12.0] PERCENT SIGN (PO) ÷ [0.3] × 00A0 × 0020 ÷ 0025 ÷ # × [0.3] NO-BREAK SPACE (GL) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] -× 00A0 × 0308 × 0025 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM) × [12.0] PERCENT SIGN (PO) ÷ [0.3] -× 00A0 × 0308 × 0020 ÷ 0025 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] +× 00A0 × 0308 × 0025 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [12.0] PERCENT SIGN (PO) ÷ [0.3] +× 00A0 × 0308 × 0020 ÷ 0025 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] × 00A0 × 0024 ÷ # × [0.3] NO-BREAK SPACE (GL) × [12.0] DOLLAR SIGN (PR) ÷ [0.3] × 00A0 × 0020 ÷ 0024 ÷ # × [0.3] NO-BREAK SPACE (GL) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] -× 00A0 × 0308 × 0024 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM) × [12.0] DOLLAR SIGN (PR) ÷ [0.3] -× 00A0 × 0308 × 0020 ÷ 0024 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] +× 00A0 × 0308 × 0024 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [12.0] DOLLAR SIGN (PR) ÷ [0.3] +× 00A0 × 0308 × 0020 ÷ 0024 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] × 00A0 × 0022 ÷ # × [0.3] NO-BREAK SPACE (GL) × [12.0] QUOTATION MARK (QU) ÷ [0.3] × 00A0 × 0020 ÷ 0022 ÷ # × [0.3] NO-BREAK SPACE (GL) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] -× 00A0 × 0308 × 0022 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM) × [12.0] QUOTATION MARK (QU) ÷ [0.3] -× 00A0 × 0308 × 0020 ÷ 0022 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] +× 00A0 × 0308 × 0022 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [12.0] QUOTATION MARK (QU) ÷ [0.3] +× 00A0 × 0308 × 0020 ÷ 0022 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] × 00A0 × 0020 ÷ # × [0.3] NO-BREAK SPACE (GL) × [7.01] SPACE (SP) ÷ [0.3] × 00A0 × 0020 × 0020 ÷ # × [0.3] NO-BREAK SPACE (GL) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] -× 00A0 × 0308 × 0020 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [0.3] -× 00A0 × 0308 × 0020 × 0020 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] +× 00A0 × 0308 × 0020 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [0.3] +× 00A0 × 0308 × 0020 × 0020 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] × 00A0 × 002F ÷ # × [0.3] NO-BREAK SPACE (GL) × [12.0] SOLIDUS (SY) ÷ [0.3] × 00A0 × 0020 × 002F ÷ # × [0.3] NO-BREAK SPACE (GL) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] -× 00A0 × 0308 × 002F ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM) × [12.0] SOLIDUS (SY) ÷ [0.3] -× 00A0 × 0308 × 0020 × 002F ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] +× 00A0 × 0308 × 002F ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [12.0] SOLIDUS (SY) ÷ [0.3] +× 00A0 × 0308 × 0020 × 002F ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] × 00A0 × 2060 ÷ # × [0.3] NO-BREAK SPACE (GL) × [11.01] WORD JOINER (WJ) ÷ [0.3] × 00A0 × 0020 × 2060 ÷ # × [0.3] NO-BREAK SPACE (GL) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] -× 00A0 × 0308 × 2060 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM) × [11.01] WORD JOINER (WJ) ÷ [0.3] -× 00A0 × 0308 × 0020 × 2060 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] +× 00A0 × 0308 × 2060 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [11.01] WORD JOINER (WJ) ÷ [0.3] +× 00A0 × 0308 × 0020 × 2060 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] × 00A0 × 200B ÷ # × [0.3] NO-BREAK SPACE (GL) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] × 00A0 × 0020 × 200B ÷ # × [0.3] NO-BREAK SPACE (GL) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] -× 00A0 × 0308 × 200B ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] -× 00A0 × 0308 × 0020 × 200B ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] +× 00A0 × 0308 × 200B ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] +× 00A0 × 0308 × 0020 × 200B ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] × 00A0 × 1F1E6 ÷ # × [0.3] NO-BREAK SPACE (GL) × [12.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] × 00A0 × 0020 ÷ 1F1E6 ÷ # × [0.3] NO-BREAK SPACE (GL) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -× 00A0 × 0308 × 1F1E6 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM) × [12.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -× 00A0 × 0308 × 0020 ÷ 1F1E6 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 00A0 × 0308 × 1F1E6 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [12.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 00A0 × 0308 × 0020 ÷ 1F1E6 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 00A0 × 261D ÷ # × [0.3] NO-BREAK SPACE (GL) × [12.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 00A0 × 0020 ÷ 261D ÷ # × [0.3] NO-BREAK SPACE (GL) × [7.01] SPACE (SP) ÷ [18.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 00A0 × 0308 × 261D ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [12.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 00A0 × 0308 × 0020 ÷ 261D ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 00A0 × 1F3FB ÷ # × [0.3] NO-BREAK SPACE (GL) × [12.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 00A0 × 0020 ÷ 1F3FB ÷ # × [0.3] NO-BREAK SPACE (GL) × [7.01] SPACE (SP) ÷ [18.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 00A0 × 0308 × 1F3FB ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [12.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 00A0 × 0308 × 0020 ÷ 1F3FB ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 00A0 × 0001 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 00A0 × 0020 ÷ 0001 ÷ # × [0.3] NO-BREAK SPACE (GL) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 00A0 × 0308 × 0001 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [9.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 00A0 × 0308 × 0020 ÷ 0001 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 00A0 × 200D ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 00A0 × 0020 ÷ 200D ÷ # × [0.3] NO-BREAK SPACE (GL) × [7.01] SPACE (SP) ÷ [18.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 00A0 × 0308 × 200D ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [9.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 00A0 × 0308 × 0020 ÷ 200D ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] × 00A0 × 00A7 ÷ # × [0.3] NO-BREAK SPACE (GL) × [12.0] SECTION SIGN (AI_AL) ÷ [0.3] × 00A0 × 0020 ÷ 00A7 ÷ # × [0.3] NO-BREAK SPACE (GL) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] -× 00A0 × 0308 × 00A7 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM) × [12.0] SECTION SIGN (AI_AL) ÷ [0.3] -× 00A0 × 0308 × 0020 ÷ 00A7 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] +× 00A0 × 0308 × 00A7 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [12.0] SECTION SIGN (AI_AL) ÷ [0.3] +× 00A0 × 0308 × 0020 ÷ 00A7 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] × 00A0 × 50005 ÷ # × [0.3] NO-BREAK SPACE (GL) × [12.0] <reserved-50005> (XX_AL) ÷ [0.3] × 00A0 × 0020 ÷ 50005 ÷ # × [0.3] NO-BREAK SPACE (GL) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] -× 00A0 × 0308 × 50005 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM) × [12.0] <reserved-50005> (XX_AL) ÷ [0.3] -× 00A0 × 0308 × 0020 ÷ 50005 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] +× 00A0 × 0308 × 50005 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [12.0] <reserved-50005> (XX_AL) ÷ [0.3] +× 00A0 × 0308 × 0020 ÷ 50005 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] × 00A0 × 0E01 ÷ # × [0.3] NO-BREAK SPACE (GL) × [12.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] × 00A0 × 0020 ÷ 0E01 ÷ # × [0.3] NO-BREAK SPACE (GL) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] -× 00A0 × 0308 × 0E01 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM) × [12.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] -× 00A0 × 0308 × 0020 ÷ 0E01 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] +× 00A0 × 0308 × 0E01 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [12.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] +× 00A0 × 0308 × 0020 ÷ 0E01 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] × 00A0 × 3041 ÷ # × [0.3] NO-BREAK SPACE (GL) × [12.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] × 00A0 × 0020 ÷ 3041 ÷ # × [0.3] NO-BREAK SPACE (GL) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] -× 00A0 × 0308 × 3041 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM) × [12.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] -× 00A0 × 0308 × 0020 ÷ 3041 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] +× 00A0 × 0308 × 3041 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [12.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] +× 00A0 × 0308 × 0020 ÷ 3041 ÷ # × [0.3] NO-BREAK SPACE (GL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] × AC00 ÷ 0023 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) ÷ [999.0] NUMBER SIGN (AL) ÷ [0.3] × AC00 × 0020 ÷ 0023 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] -× AC00 × 0308 ÷ 0023 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] NUMBER SIGN (AL) ÷ [0.3] -× AC00 × 0308 × 0020 ÷ 0023 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] +× AC00 × 0308 ÷ 0023 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] NUMBER SIGN (AL) ÷ [0.3] +× AC00 × 0308 × 0020 ÷ 0023 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] × AC00 ÷ 2014 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) ÷ [999.0] EM DASH (B2) ÷ [0.3] × AC00 × 0020 ÷ 2014 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] -× AC00 × 0308 ÷ 2014 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] EM DASH (B2) ÷ [0.3] -× AC00 × 0308 × 0020 ÷ 2014 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] +× AC00 × 0308 ÷ 2014 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] EM DASH (B2) ÷ [0.3] +× AC00 × 0308 × 0020 ÷ 2014 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] × AC00 × 0009 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] × AC00 × 0020 ÷ 0009 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] -× AC00 × 0308 × 0009 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] -× AC00 × 0308 × 0020 ÷ 0009 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] +× AC00 × 0308 × 0009 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] +× AC00 × 0308 × 0020 ÷ 0009 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] × AC00 ÷ 00B4 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3] × AC00 × 0020 ÷ 00B4 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] -× AC00 × 0308 ÷ 00B4 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3] -× AC00 × 0308 × 0020 ÷ 00B4 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] +× AC00 × 0308 ÷ 00B4 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3] +× AC00 × 0308 × 0020 ÷ 00B4 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] × AC00 × 000B ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] × AC00 × 0020 × 000B ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] -× AC00 × 0308 × 000B ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] -× AC00 × 0308 × 0020 × 000B ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] +× AC00 × 0308 × 000B ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] +× AC00 × 0308 × 0020 × 000B ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] × AC00 ÷ FFFC ÷ # × [0.3] HANGUL SYLLABLE GA (H2) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] × AC00 × 0020 ÷ FFFC ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] -× AC00 × 0308 ÷ FFFC ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] -× AC00 × 0308 × 0020 ÷ FFFC ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] +× AC00 × 0308 ÷ FFFC ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] +× AC00 × 0308 × 0020 ÷ FFFC ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] × AC00 × 007D ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] × AC00 × 0020 × 007D ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] -× AC00 × 0308 × 007D ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM) × [13.03] RIGHT CURLY BRACKET (CL) ÷ [0.3] -× AC00 × 0308 × 0020 × 007D ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] +× AC00 × 0308 × 007D ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] RIGHT CURLY BRACKET (CL) ÷ [0.3] +× AC00 × 0308 × 0020 × 007D ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] × AC00 × 0029 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] × AC00 × 0020 × 0029 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] -× AC00 × 0308 × 0029 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM) × [13.03] RIGHT PARENTHESIS (CP) ÷ [0.3] -× AC00 × 0308 × 0020 × 0029 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] -× AC00 × 0001 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] <START OF HEADING> (CM) ÷ [0.3] -× AC00 × 0020 ÷ 0001 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM) ÷ [0.3] -× AC00 × 0308 × 0001 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM) × [9.0] <START OF HEADING> (CM) ÷ [0.3] -× AC00 × 0308 × 0020 ÷ 0001 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM) ÷ [0.3] +× AC00 × 0308 × 0029 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] RIGHT PARENTHESIS (CP) ÷ [0.3] +× AC00 × 0308 × 0020 × 0029 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] × AC00 × 000D ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] × AC00 × 0020 × 000D ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -× AC00 × 0308 × 000D ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -× AC00 × 0308 × 0020 × 000D ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +× AC00 × 0308 × 000D ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +× AC00 × 0308 × 0020 × 000D ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] × AC00 × 0021 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] × AC00 × 0020 × 0021 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] -× AC00 × 0308 × 0021 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] -× AC00 × 0308 × 0020 × 0021 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] +× AC00 × 0308 × 0021 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] +× AC00 × 0308 × 0020 × 0021 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] × AC00 × 00A0 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [12.1] NO-BREAK SPACE (GL) ÷ [0.3] × AC00 × 0020 ÷ 00A0 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] -× AC00 × 0308 × 00A0 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM) × [12.2] NO-BREAK SPACE (GL) ÷ [0.3] -× AC00 × 0308 × 0020 ÷ 00A0 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] +× AC00 × 0308 × 00A0 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [12.2] NO-BREAK SPACE (GL) ÷ [0.3] +× AC00 × 0308 × 0020 ÷ 00A0 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] × AC00 ÷ AC00 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) ÷ [999.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] × AC00 × 0020 ÷ AC00 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] -× AC00 × 0308 ÷ AC00 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] -× AC00 × 0308 × 0020 ÷ AC00 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] +× AC00 × 0308 ÷ AC00 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] +× AC00 × 0308 × 0020 ÷ AC00 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] × AC00 ÷ AC01 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) ÷ [999.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] × AC00 × 0020 ÷ AC01 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] -× AC00 × 0308 ÷ AC01 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] -× AC00 × 0308 × 0020 ÷ AC01 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] +× AC00 × 0308 ÷ AC01 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] +× AC00 × 0308 × 0020 ÷ AC01 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] × AC00 ÷ 05D0 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) ÷ [999.0] HEBREW LETTER ALEF (HL) ÷ [0.3] × AC00 × 0020 ÷ 05D0 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] -× AC00 × 0308 ÷ 05D0 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HEBREW LETTER ALEF (HL) ÷ [0.3] -× AC00 × 0308 × 0020 ÷ 05D0 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] +× AC00 × 0308 ÷ 05D0 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HEBREW LETTER ALEF (HL) ÷ [0.3] +× AC00 × 0308 × 0020 ÷ 05D0 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] × AC00 × 002D ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] × AC00 × 0020 ÷ 002D ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] -× AC00 × 0308 × 002D ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] -× AC00 × 0308 × 0020 ÷ 002D ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] +× AC00 × 0308 × 002D ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] +× AC00 × 0308 × 0020 ÷ 002D ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] × AC00 ÷ 231A ÷ # × [0.3] HANGUL SYLLABLE GA (H2) ÷ [999.0] WATCH (ID) ÷ [0.3] × AC00 × 0020 ÷ 231A ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] -× AC00 × 0308 ÷ 231A ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] WATCH (ID) ÷ [0.3] -× AC00 × 0308 × 0020 ÷ 231A ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] +× AC00 × 0308 ÷ 231A ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] WATCH (ID) ÷ [0.3] +× AC00 × 0308 × 0020 ÷ 231A ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] × AC00 × 2024 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [27.01] ONE DOT LEADER (IN) ÷ [0.3] × AC00 × 0020 ÷ 2024 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] -× AC00 × 0308 × 2024 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM) × [27.01] ONE DOT LEADER (IN) ÷ [0.3] -× AC00 × 0308 × 0020 ÷ 2024 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] +× AC00 × 0308 × 2024 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [27.01] ONE DOT LEADER (IN) ÷ [0.3] +× AC00 × 0308 × 0020 ÷ 2024 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] × AC00 × 002C ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [13.02] COMMA (IS) ÷ [0.3] × AC00 × 0020 × 002C ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] -× AC00 × 0308 × 002C ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM) × [13.03] COMMA (IS) ÷ [0.3] -× AC00 × 0308 × 0020 × 002C ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] +× AC00 × 0308 × 002C ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] COMMA (IS) ÷ [0.3] +× AC00 × 0308 × 0020 × 002C ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] × AC00 ÷ 1100 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) ÷ [999.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] × AC00 × 0020 ÷ 1100 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] -× AC00 × 0308 ÷ 1100 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] -× AC00 × 0308 × 0020 ÷ 1100 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] +× AC00 × 0308 ÷ 1100 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] +× AC00 × 0308 × 0020 ÷ 1100 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] × AC00 × 11A8 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [26.02] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] × AC00 × 0020 ÷ 11A8 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] -× AC00 × 0308 × 11A8 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM) × [26.02] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] -× AC00 × 0308 × 0020 ÷ 11A8 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] +× AC00 × 0308 × 11A8 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [26.02] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] +× AC00 × 0308 × 0020 ÷ 11A8 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] × AC00 × 1160 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [26.02] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] × AC00 × 0020 ÷ 1160 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] -× AC00 × 0308 × 1160 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM) × [26.02] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] -× AC00 × 0308 × 0020 ÷ 1160 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] +× AC00 × 0308 × 1160 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [26.02] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] +× AC00 × 0308 × 0020 ÷ 1160 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] × AC00 × 000A ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] × AC00 × 0020 × 000A ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] -× AC00 × 0308 × 000A ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] -× AC00 × 0308 × 0020 × 000A ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] +× AC00 × 0308 × 000A ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] +× AC00 × 0308 × 0020 × 000A ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] × AC00 × 0085 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] × AC00 × 0020 × 0085 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] -× AC00 × 0308 × 0085 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] -× AC00 × 0308 × 0020 × 0085 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] +× AC00 × 0308 × 0085 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] +× AC00 × 0308 × 0020 × 0085 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] × AC00 × 17D6 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] × AC00 × 0020 ÷ 17D6 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] -× AC00 × 0308 × 17D6 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] -× AC00 × 0308 × 0020 ÷ 17D6 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] +× AC00 × 0308 × 17D6 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] +× AC00 × 0308 × 0020 ÷ 17D6 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] × AC00 ÷ 0030 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) ÷ [999.0] DIGIT ZERO (NU) ÷ [0.3] × AC00 × 0020 ÷ 0030 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] -× AC00 × 0308 ÷ 0030 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] DIGIT ZERO (NU) ÷ [0.3] -× AC00 × 0308 × 0020 ÷ 0030 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] +× AC00 × 0308 ÷ 0030 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] DIGIT ZERO (NU) ÷ [0.3] +× AC00 × 0308 × 0020 ÷ 0030 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] × AC00 ÷ 0028 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) ÷ [999.0] LEFT PARENTHESIS (OP) ÷ [0.3] × AC00 × 0020 ÷ 0028 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] -× AC00 × 0308 ÷ 0028 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] LEFT PARENTHESIS (OP) ÷ [0.3] -× AC00 × 0308 × 0020 ÷ 0028 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] +× AC00 × 0308 ÷ 0028 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] LEFT PARENTHESIS (OP) ÷ [0.3] +× AC00 × 0308 × 0020 ÷ 0028 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] × AC00 × 0025 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [27.02] PERCENT SIGN (PO) ÷ [0.3] × AC00 × 0020 ÷ 0025 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] -× AC00 × 0308 × 0025 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM) × [27.02] PERCENT SIGN (PO) ÷ [0.3] -× AC00 × 0308 × 0020 ÷ 0025 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] +× AC00 × 0308 × 0025 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [27.02] PERCENT SIGN (PO) ÷ [0.3] +× AC00 × 0308 × 0020 ÷ 0025 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] × AC00 ÷ 0024 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) ÷ [999.0] DOLLAR SIGN (PR) ÷ [0.3] × AC00 × 0020 ÷ 0024 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] -× AC00 × 0308 ÷ 0024 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] DOLLAR SIGN (PR) ÷ [0.3] -× AC00 × 0308 × 0020 ÷ 0024 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] +× AC00 × 0308 ÷ 0024 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] DOLLAR SIGN (PR) ÷ [0.3] +× AC00 × 0308 × 0020 ÷ 0024 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] × AC00 × 0022 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [19.01] QUOTATION MARK (QU) ÷ [0.3] × AC00 × 0020 ÷ 0022 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] -× AC00 × 0308 × 0022 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM) × [19.01] QUOTATION MARK (QU) ÷ [0.3] -× AC00 × 0308 × 0020 ÷ 0022 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] +× AC00 × 0308 × 0022 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [19.01] QUOTATION MARK (QU) ÷ [0.3] +× AC00 × 0308 × 0020 ÷ 0022 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] × AC00 × 0020 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [7.01] SPACE (SP) ÷ [0.3] × AC00 × 0020 × 0020 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] -× AC00 × 0308 × 0020 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [0.3] -× AC00 × 0308 × 0020 × 0020 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] +× AC00 × 0308 × 0020 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [0.3] +× AC00 × 0308 × 0020 × 0020 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] × AC00 × 002F ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [13.02] SOLIDUS (SY) ÷ [0.3] × AC00 × 0020 × 002F ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] -× AC00 × 0308 × 002F ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM) × [13.03] SOLIDUS (SY) ÷ [0.3] -× AC00 × 0308 × 0020 × 002F ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] +× AC00 × 0308 × 002F ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] SOLIDUS (SY) ÷ [0.3] +× AC00 × 0308 × 0020 × 002F ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] × AC00 × 2060 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [11.01] WORD JOINER (WJ) ÷ [0.3] × AC00 × 0020 × 2060 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] -× AC00 × 0308 × 2060 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM) × [11.01] WORD JOINER (WJ) ÷ [0.3] -× AC00 × 0308 × 0020 × 2060 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] +× AC00 × 0308 × 2060 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [11.01] WORD JOINER (WJ) ÷ [0.3] +× AC00 × 0308 × 0020 × 2060 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] × AC00 × 200B ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] × AC00 × 0020 × 200B ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] -× AC00 × 0308 × 200B ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] -× AC00 × 0308 × 0020 × 200B ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] +× AC00 × 0308 × 200B ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] +× AC00 × 0308 × 0020 × 200B ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] × AC00 ÷ 1F1E6 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] × AC00 × 0020 ÷ 1F1E6 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -× AC00 × 0308 ÷ 1F1E6 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -× AC00 × 0308 × 0020 ÷ 1F1E6 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× AC00 × 0308 ÷ 1F1E6 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× AC00 × 0308 × 0020 ÷ 1F1E6 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× AC00 ÷ 261D ÷ # × [0.3] HANGUL SYLLABLE GA (H2) ÷ [999.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× AC00 × 0020 ÷ 261D ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [7.01] SPACE (SP) ÷ [18.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× AC00 × 0308 ÷ 261D ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× AC00 × 0308 × 0020 ÷ 261D ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× AC00 ÷ 1F3FB ÷ # × [0.3] HANGUL SYLLABLE GA (H2) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× AC00 × 0020 ÷ 1F3FB ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [7.01] SPACE (SP) ÷ [18.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× AC00 × 0308 ÷ 1F3FB ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× AC00 × 0308 × 0020 ÷ 1F3FB ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× AC00 × 0001 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× AC00 × 0020 ÷ 0001 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× AC00 × 0308 × 0001 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [9.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× AC00 × 0308 × 0020 ÷ 0001 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× AC00 × 200D ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× AC00 × 0020 ÷ 200D ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [7.01] SPACE (SP) ÷ [18.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× AC00 × 0308 × 200D ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [9.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× AC00 × 0308 × 0020 ÷ 200D ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] × AC00 ÷ 00A7 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) ÷ [999.0] SECTION SIGN (AI_AL) ÷ [0.3] × AC00 × 0020 ÷ 00A7 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] -× AC00 × 0308 ÷ 00A7 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] SECTION SIGN (AI_AL) ÷ [0.3] -× AC00 × 0308 × 0020 ÷ 00A7 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] +× AC00 × 0308 ÷ 00A7 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] SECTION SIGN (AI_AL) ÷ [0.3] +× AC00 × 0308 × 0020 ÷ 00A7 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] × AC00 ÷ 50005 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) ÷ [999.0] <reserved-50005> (XX_AL) ÷ [0.3] × AC00 × 0020 ÷ 50005 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] -× AC00 × 0308 ÷ 50005 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] <reserved-50005> (XX_AL) ÷ [0.3] -× AC00 × 0308 × 0020 ÷ 50005 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] +× AC00 × 0308 ÷ 50005 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] <reserved-50005> (XX_AL) ÷ [0.3] +× AC00 × 0308 × 0020 ÷ 50005 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] × AC00 ÷ 0E01 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) ÷ [999.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] × AC00 × 0020 ÷ 0E01 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] -× AC00 × 0308 ÷ 0E01 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] -× AC00 × 0308 × 0020 ÷ 0E01 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] +× AC00 × 0308 ÷ 0E01 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] +× AC00 × 0308 × 0020 ÷ 0E01 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] × AC00 × 3041 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] × AC00 × 0020 ÷ 3041 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] -× AC00 × 0308 × 3041 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] -× AC00 × 0308 × 0020 ÷ 3041 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] +× AC00 × 0308 × 3041 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] +× AC00 × 0308 × 0020 ÷ 3041 ÷ # × [0.3] HANGUL SYLLABLE GA (H2) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] × AC01 ÷ 0023 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) ÷ [999.0] NUMBER SIGN (AL) ÷ [0.3] × AC01 × 0020 ÷ 0023 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] -× AC01 × 0308 ÷ 0023 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] NUMBER SIGN (AL) ÷ [0.3] -× AC01 × 0308 × 0020 ÷ 0023 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] +× AC01 × 0308 ÷ 0023 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] NUMBER SIGN (AL) ÷ [0.3] +× AC01 × 0308 × 0020 ÷ 0023 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] × AC01 ÷ 2014 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) ÷ [999.0] EM DASH (B2) ÷ [0.3] × AC01 × 0020 ÷ 2014 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] -× AC01 × 0308 ÷ 2014 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] EM DASH (B2) ÷ [0.3] -× AC01 × 0308 × 0020 ÷ 2014 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] +× AC01 × 0308 ÷ 2014 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] EM DASH (B2) ÷ [0.3] +× AC01 × 0308 × 0020 ÷ 2014 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] × AC01 × 0009 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] × AC01 × 0020 ÷ 0009 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] -× AC01 × 0308 × 0009 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] -× AC01 × 0308 × 0020 ÷ 0009 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] +× AC01 × 0308 × 0009 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] +× AC01 × 0308 × 0020 ÷ 0009 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] × AC01 ÷ 00B4 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3] × AC01 × 0020 ÷ 00B4 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] -× AC01 × 0308 ÷ 00B4 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3] -× AC01 × 0308 × 0020 ÷ 00B4 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] +× AC01 × 0308 ÷ 00B4 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3] +× AC01 × 0308 × 0020 ÷ 00B4 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] × AC01 × 000B ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] × AC01 × 0020 × 000B ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] -× AC01 × 0308 × 000B ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] -× AC01 × 0308 × 0020 × 000B ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] +× AC01 × 0308 × 000B ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] +× AC01 × 0308 × 0020 × 000B ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] × AC01 ÷ FFFC ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] × AC01 × 0020 ÷ FFFC ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] -× AC01 × 0308 ÷ FFFC ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] -× AC01 × 0308 × 0020 ÷ FFFC ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] +× AC01 × 0308 ÷ FFFC ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] +× AC01 × 0308 × 0020 ÷ FFFC ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] × AC01 × 007D ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] × AC01 × 0020 × 007D ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] -× AC01 × 0308 × 007D ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM) × [13.03] RIGHT CURLY BRACKET (CL) ÷ [0.3] -× AC01 × 0308 × 0020 × 007D ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] +× AC01 × 0308 × 007D ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] RIGHT CURLY BRACKET (CL) ÷ [0.3] +× AC01 × 0308 × 0020 × 007D ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] × AC01 × 0029 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] × AC01 × 0020 × 0029 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] -× AC01 × 0308 × 0029 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM) × [13.03] RIGHT PARENTHESIS (CP) ÷ [0.3] -× AC01 × 0308 × 0020 × 0029 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] -× AC01 × 0001 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] <START OF HEADING> (CM) ÷ [0.3] -× AC01 × 0020 ÷ 0001 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM) ÷ [0.3] -× AC01 × 0308 × 0001 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM) × [9.0] <START OF HEADING> (CM) ÷ [0.3] -× AC01 × 0308 × 0020 ÷ 0001 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM) ÷ [0.3] +× AC01 × 0308 × 0029 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] RIGHT PARENTHESIS (CP) ÷ [0.3] +× AC01 × 0308 × 0020 × 0029 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] × AC01 × 000D ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] × AC01 × 0020 × 000D ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -× AC01 × 0308 × 000D ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -× AC01 × 0308 × 0020 × 000D ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +× AC01 × 0308 × 000D ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +× AC01 × 0308 × 0020 × 000D ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] × AC01 × 0021 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] × AC01 × 0020 × 0021 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] -× AC01 × 0308 × 0021 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] -× AC01 × 0308 × 0020 × 0021 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] +× AC01 × 0308 × 0021 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] +× AC01 × 0308 × 0020 × 0021 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] × AC01 × 00A0 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [12.1] NO-BREAK SPACE (GL) ÷ [0.3] × AC01 × 0020 ÷ 00A0 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] -× AC01 × 0308 × 00A0 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM) × [12.2] NO-BREAK SPACE (GL) ÷ [0.3] -× AC01 × 0308 × 0020 ÷ 00A0 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] +× AC01 × 0308 × 00A0 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM1_CM) × [12.2] NO-BREAK SPACE (GL) ÷ [0.3] +× AC01 × 0308 × 0020 ÷ 00A0 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] × AC01 ÷ AC00 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) ÷ [999.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] × AC01 × 0020 ÷ AC00 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] -× AC01 × 0308 ÷ AC00 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] -× AC01 × 0308 × 0020 ÷ AC00 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] +× AC01 × 0308 ÷ AC00 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] +× AC01 × 0308 × 0020 ÷ AC00 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] × AC01 ÷ AC01 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) ÷ [999.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] × AC01 × 0020 ÷ AC01 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] -× AC01 × 0308 ÷ AC01 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] -× AC01 × 0308 × 0020 ÷ AC01 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] +× AC01 × 0308 ÷ AC01 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] +× AC01 × 0308 × 0020 ÷ AC01 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] × AC01 ÷ 05D0 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) ÷ [999.0] HEBREW LETTER ALEF (HL) ÷ [0.3] × AC01 × 0020 ÷ 05D0 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] -× AC01 × 0308 ÷ 05D0 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HEBREW LETTER ALEF (HL) ÷ [0.3] -× AC01 × 0308 × 0020 ÷ 05D0 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] +× AC01 × 0308 ÷ 05D0 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HEBREW LETTER ALEF (HL) ÷ [0.3] +× AC01 × 0308 × 0020 ÷ 05D0 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] × AC01 × 002D ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] × AC01 × 0020 ÷ 002D ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] -× AC01 × 0308 × 002D ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] -× AC01 × 0308 × 0020 ÷ 002D ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] +× AC01 × 0308 × 002D ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] +× AC01 × 0308 × 0020 ÷ 002D ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] × AC01 ÷ 231A ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) ÷ [999.0] WATCH (ID) ÷ [0.3] × AC01 × 0020 ÷ 231A ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] -× AC01 × 0308 ÷ 231A ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] WATCH (ID) ÷ [0.3] -× AC01 × 0308 × 0020 ÷ 231A ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] +× AC01 × 0308 ÷ 231A ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] WATCH (ID) ÷ [0.3] +× AC01 × 0308 × 0020 ÷ 231A ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] × AC01 × 2024 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [27.01] ONE DOT LEADER (IN) ÷ [0.3] × AC01 × 0020 ÷ 2024 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] -× AC01 × 0308 × 2024 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM) × [27.01] ONE DOT LEADER (IN) ÷ [0.3] -× AC01 × 0308 × 0020 ÷ 2024 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] +× AC01 × 0308 × 2024 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM1_CM) × [27.01] ONE DOT LEADER (IN) ÷ [0.3] +× AC01 × 0308 × 0020 ÷ 2024 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] × AC01 × 002C ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [13.02] COMMA (IS) ÷ [0.3] × AC01 × 0020 × 002C ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] -× AC01 × 0308 × 002C ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM) × [13.03] COMMA (IS) ÷ [0.3] -× AC01 × 0308 × 0020 × 002C ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] +× AC01 × 0308 × 002C ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] COMMA (IS) ÷ [0.3] +× AC01 × 0308 × 0020 × 002C ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] × AC01 ÷ 1100 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) ÷ [999.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] × AC01 × 0020 ÷ 1100 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] -× AC01 × 0308 ÷ 1100 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] -× AC01 × 0308 × 0020 ÷ 1100 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] +× AC01 × 0308 ÷ 1100 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] +× AC01 × 0308 × 0020 ÷ 1100 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] × AC01 × 11A8 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [26.03] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] × AC01 × 0020 ÷ 11A8 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] -× AC01 × 0308 × 11A8 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM) × [26.03] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] -× AC01 × 0308 × 0020 ÷ 11A8 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] +× AC01 × 0308 × 11A8 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM1_CM) × [26.03] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] +× AC01 × 0308 × 0020 ÷ 11A8 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] × AC01 ÷ 1160 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) ÷ [999.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] × AC01 × 0020 ÷ 1160 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] -× AC01 × 0308 ÷ 1160 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] -× AC01 × 0308 × 0020 ÷ 1160 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] +× AC01 × 0308 ÷ 1160 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] +× AC01 × 0308 × 0020 ÷ 1160 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] × AC01 × 000A ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] × AC01 × 0020 × 000A ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] -× AC01 × 0308 × 000A ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] -× AC01 × 0308 × 0020 × 000A ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] +× AC01 × 0308 × 000A ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] +× AC01 × 0308 × 0020 × 000A ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] × AC01 × 0085 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] × AC01 × 0020 × 0085 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] -× AC01 × 0308 × 0085 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] -× AC01 × 0308 × 0020 × 0085 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] +× AC01 × 0308 × 0085 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] +× AC01 × 0308 × 0020 × 0085 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] × AC01 × 17D6 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] × AC01 × 0020 ÷ 17D6 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] -× AC01 × 0308 × 17D6 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] -× AC01 × 0308 × 0020 ÷ 17D6 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] +× AC01 × 0308 × 17D6 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] +× AC01 × 0308 × 0020 ÷ 17D6 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] × AC01 ÷ 0030 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) ÷ [999.0] DIGIT ZERO (NU) ÷ [0.3] × AC01 × 0020 ÷ 0030 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] -× AC01 × 0308 ÷ 0030 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] DIGIT ZERO (NU) ÷ [0.3] -× AC01 × 0308 × 0020 ÷ 0030 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] +× AC01 × 0308 ÷ 0030 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] DIGIT ZERO (NU) ÷ [0.3] +× AC01 × 0308 × 0020 ÷ 0030 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] × AC01 ÷ 0028 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) ÷ [999.0] LEFT PARENTHESIS (OP) ÷ [0.3] × AC01 × 0020 ÷ 0028 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] -× AC01 × 0308 ÷ 0028 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] LEFT PARENTHESIS (OP) ÷ [0.3] -× AC01 × 0308 × 0020 ÷ 0028 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] +× AC01 × 0308 ÷ 0028 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] LEFT PARENTHESIS (OP) ÷ [0.3] +× AC01 × 0308 × 0020 ÷ 0028 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] × AC01 × 0025 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [27.02] PERCENT SIGN (PO) ÷ [0.3] × AC01 × 0020 ÷ 0025 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] -× AC01 × 0308 × 0025 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM) × [27.02] PERCENT SIGN (PO) ÷ [0.3] -× AC01 × 0308 × 0020 ÷ 0025 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] +× AC01 × 0308 × 0025 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM1_CM) × [27.02] PERCENT SIGN (PO) ÷ [0.3] +× AC01 × 0308 × 0020 ÷ 0025 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] × AC01 ÷ 0024 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) ÷ [999.0] DOLLAR SIGN (PR) ÷ [0.3] × AC01 × 0020 ÷ 0024 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] -× AC01 × 0308 ÷ 0024 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] DOLLAR SIGN (PR) ÷ [0.3] -× AC01 × 0308 × 0020 ÷ 0024 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] +× AC01 × 0308 ÷ 0024 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] DOLLAR SIGN (PR) ÷ [0.3] +× AC01 × 0308 × 0020 ÷ 0024 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] × AC01 × 0022 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [19.01] QUOTATION MARK (QU) ÷ [0.3] × AC01 × 0020 ÷ 0022 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] -× AC01 × 0308 × 0022 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM) × [19.01] QUOTATION MARK (QU) ÷ [0.3] -× AC01 × 0308 × 0020 ÷ 0022 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] +× AC01 × 0308 × 0022 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM1_CM) × [19.01] QUOTATION MARK (QU) ÷ [0.3] +× AC01 × 0308 × 0020 ÷ 0022 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] × AC01 × 0020 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [7.01] SPACE (SP) ÷ [0.3] × AC01 × 0020 × 0020 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] -× AC01 × 0308 × 0020 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [0.3] -× AC01 × 0308 × 0020 × 0020 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] +× AC01 × 0308 × 0020 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [0.3] +× AC01 × 0308 × 0020 × 0020 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] × AC01 × 002F ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [13.02] SOLIDUS (SY) ÷ [0.3] × AC01 × 0020 × 002F ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] -× AC01 × 0308 × 002F ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM) × [13.03] SOLIDUS (SY) ÷ [0.3] -× AC01 × 0308 × 0020 × 002F ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] +× AC01 × 0308 × 002F ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] SOLIDUS (SY) ÷ [0.3] +× AC01 × 0308 × 0020 × 002F ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] × AC01 × 2060 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [11.01] WORD JOINER (WJ) ÷ [0.3] × AC01 × 0020 × 2060 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] -× AC01 × 0308 × 2060 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM) × [11.01] WORD JOINER (WJ) ÷ [0.3] -× AC01 × 0308 × 0020 × 2060 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] +× AC01 × 0308 × 2060 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM1_CM) × [11.01] WORD JOINER (WJ) ÷ [0.3] +× AC01 × 0308 × 0020 × 2060 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] × AC01 × 200B ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] × AC01 × 0020 × 200B ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] -× AC01 × 0308 × 200B ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] -× AC01 × 0308 × 0020 × 200B ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] +× AC01 × 0308 × 200B ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] +× AC01 × 0308 × 0020 × 200B ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] × AC01 ÷ 1F1E6 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] × AC01 × 0020 ÷ 1F1E6 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -× AC01 × 0308 ÷ 1F1E6 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -× AC01 × 0308 × 0020 ÷ 1F1E6 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× AC01 × 0308 ÷ 1F1E6 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× AC01 × 0308 × 0020 ÷ 1F1E6 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× AC01 ÷ 261D ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) ÷ [999.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× AC01 × 0020 ÷ 261D ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [7.01] SPACE (SP) ÷ [18.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× AC01 × 0308 ÷ 261D ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× AC01 × 0308 × 0020 ÷ 261D ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× AC01 ÷ 1F3FB ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× AC01 × 0020 ÷ 1F3FB ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [7.01] SPACE (SP) ÷ [18.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× AC01 × 0308 ÷ 1F3FB ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× AC01 × 0308 × 0020 ÷ 1F3FB ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× AC01 × 0001 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× AC01 × 0020 ÷ 0001 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× AC01 × 0308 × 0001 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM1_CM) × [9.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× AC01 × 0308 × 0020 ÷ 0001 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× AC01 × 200D ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× AC01 × 0020 ÷ 200D ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [7.01] SPACE (SP) ÷ [18.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× AC01 × 0308 × 200D ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM1_CM) × [9.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× AC01 × 0308 × 0020 ÷ 200D ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] × AC01 ÷ 00A7 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) ÷ [999.0] SECTION SIGN (AI_AL) ÷ [0.3] × AC01 × 0020 ÷ 00A7 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] -× AC01 × 0308 ÷ 00A7 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] SECTION SIGN (AI_AL) ÷ [0.3] -× AC01 × 0308 × 0020 ÷ 00A7 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] +× AC01 × 0308 ÷ 00A7 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] SECTION SIGN (AI_AL) ÷ [0.3] +× AC01 × 0308 × 0020 ÷ 00A7 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] × AC01 ÷ 50005 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) ÷ [999.0] <reserved-50005> (XX_AL) ÷ [0.3] × AC01 × 0020 ÷ 50005 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] -× AC01 × 0308 ÷ 50005 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] <reserved-50005> (XX_AL) ÷ [0.3] -× AC01 × 0308 × 0020 ÷ 50005 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] +× AC01 × 0308 ÷ 50005 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] <reserved-50005> (XX_AL) ÷ [0.3] +× AC01 × 0308 × 0020 ÷ 50005 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] × AC01 ÷ 0E01 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) ÷ [999.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] × AC01 × 0020 ÷ 0E01 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] -× AC01 × 0308 ÷ 0E01 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] -× AC01 × 0308 × 0020 ÷ 0E01 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] +× AC01 × 0308 ÷ 0E01 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] +× AC01 × 0308 × 0020 ÷ 0E01 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] × AC01 × 3041 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] × AC01 × 0020 ÷ 3041 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] -× AC01 × 0308 × 3041 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] -× AC01 × 0308 × 0020 ÷ 3041 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] +× AC01 × 0308 × 3041 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] +× AC01 × 0308 × 0020 ÷ 3041 ÷ # × [0.3] HANGUL SYLLABLE GAG (H3) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] × 05D0 × 0023 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [28.0] NUMBER SIGN (AL) ÷ [0.3] × 05D0 × 0020 ÷ 0023 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] -× 05D0 × 0308 × 0023 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM) × [28.0] NUMBER SIGN (AL) ÷ [0.3] -× 05D0 × 0308 × 0020 ÷ 0023 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] +× 05D0 × 0308 × 0023 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [28.0] NUMBER SIGN (AL) ÷ [0.3] +× 05D0 × 0308 × 0020 ÷ 0023 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] × 05D0 ÷ 2014 ÷ # × [0.3] HEBREW LETTER ALEF (HL) ÷ [999.0] EM DASH (B2) ÷ [0.3] × 05D0 × 0020 ÷ 2014 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] -× 05D0 × 0308 ÷ 2014 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] EM DASH (B2) ÷ [0.3] -× 05D0 × 0308 × 0020 ÷ 2014 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] +× 05D0 × 0308 ÷ 2014 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] EM DASH (B2) ÷ [0.3] +× 05D0 × 0308 × 0020 ÷ 2014 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] × 05D0 × 0009 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] × 05D0 × 0020 ÷ 0009 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] -× 05D0 × 0308 × 0009 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] -× 05D0 × 0308 × 0020 ÷ 0009 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] +× 05D0 × 0308 × 0009 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] +× 05D0 × 0308 × 0020 ÷ 0009 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] × 05D0 ÷ 00B4 ÷ # × [0.3] HEBREW LETTER ALEF (HL) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3] × 05D0 × 0020 ÷ 00B4 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] -× 05D0 × 0308 ÷ 00B4 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3] -× 05D0 × 0308 × 0020 ÷ 00B4 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] +× 05D0 × 0308 ÷ 00B4 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3] +× 05D0 × 0308 × 0020 ÷ 00B4 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] × 05D0 × 000B ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] × 05D0 × 0020 × 000B ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] -× 05D0 × 0308 × 000B ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] -× 05D0 × 0308 × 0020 × 000B ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] +× 05D0 × 0308 × 000B ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] +× 05D0 × 0308 × 0020 × 000B ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] × 05D0 ÷ FFFC ÷ # × [0.3] HEBREW LETTER ALEF (HL) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] × 05D0 × 0020 ÷ FFFC ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] -× 05D0 × 0308 ÷ FFFC ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] -× 05D0 × 0308 × 0020 ÷ FFFC ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] +× 05D0 × 0308 ÷ FFFC ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] +× 05D0 × 0308 × 0020 ÷ FFFC ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] × 05D0 × 007D ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] × 05D0 × 0020 × 007D ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] -× 05D0 × 0308 × 007D ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM) × [13.03] RIGHT CURLY BRACKET (CL) ÷ [0.3] -× 05D0 × 0308 × 0020 × 007D ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] +× 05D0 × 0308 × 007D ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] RIGHT CURLY BRACKET (CL) ÷ [0.3] +× 05D0 × 0308 × 0020 × 007D ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] × 05D0 × 0029 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] × 05D0 × 0020 × 0029 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 05D0 × 0308 × 0029 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM) × [13.03] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 05D0 × 0308 × 0020 × 0029 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 05D0 × 0001 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] <START OF HEADING> (CM) ÷ [0.3] -× 05D0 × 0020 ÷ 0001 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM) ÷ [0.3] -× 05D0 × 0308 × 0001 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM) × [9.0] <START OF HEADING> (CM) ÷ [0.3] -× 05D0 × 0308 × 0020 ÷ 0001 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM) ÷ [0.3] +× 05D0 × 0308 × 0029 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] RIGHT PARENTHESIS (CP) ÷ [0.3] +× 05D0 × 0308 × 0020 × 0029 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] × 05D0 × 000D ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] × 05D0 × 0020 × 000D ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -× 05D0 × 0308 × 000D ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -× 05D0 × 0308 × 0020 × 000D ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +× 05D0 × 0308 × 000D ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +× 05D0 × 0308 × 0020 × 000D ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] × 05D0 × 0021 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] × 05D0 × 0020 × 0021 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] -× 05D0 × 0308 × 0021 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] -× 05D0 × 0308 × 0020 × 0021 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] +× 05D0 × 0308 × 0021 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] +× 05D0 × 0308 × 0020 × 0021 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] × 05D0 × 00A0 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [12.1] NO-BREAK SPACE (GL) ÷ [0.3] × 05D0 × 0020 ÷ 00A0 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] -× 05D0 × 0308 × 00A0 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM) × [12.2] NO-BREAK SPACE (GL) ÷ [0.3] -× 05D0 × 0308 × 0020 ÷ 00A0 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] +× 05D0 × 0308 × 00A0 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [12.2] NO-BREAK SPACE (GL) ÷ [0.3] +× 05D0 × 0308 × 0020 ÷ 00A0 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] × 05D0 ÷ AC00 ÷ # × [0.3] HEBREW LETTER ALEF (HL) ÷ [999.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] × 05D0 × 0020 ÷ AC00 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] -× 05D0 × 0308 ÷ AC00 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] -× 05D0 × 0308 × 0020 ÷ AC00 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] +× 05D0 × 0308 ÷ AC00 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] +× 05D0 × 0308 × 0020 ÷ AC00 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] × 05D0 ÷ AC01 ÷ # × [0.3] HEBREW LETTER ALEF (HL) ÷ [999.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] × 05D0 × 0020 ÷ AC01 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] -× 05D0 × 0308 ÷ AC01 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] -× 05D0 × 0308 × 0020 ÷ AC01 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] +× 05D0 × 0308 ÷ AC01 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] +× 05D0 × 0308 × 0020 ÷ AC01 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] × 05D0 × 05D0 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [28.0] HEBREW LETTER ALEF (HL) ÷ [0.3] × 05D0 × 0020 ÷ 05D0 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] -× 05D0 × 0308 × 05D0 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM) × [28.0] HEBREW LETTER ALEF (HL) ÷ [0.3] -× 05D0 × 0308 × 0020 ÷ 05D0 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] +× 05D0 × 0308 × 05D0 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [28.0] HEBREW LETTER ALEF (HL) ÷ [0.3] +× 05D0 × 0308 × 0020 ÷ 05D0 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] × 05D0 × 002D ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] × 05D0 × 0020 ÷ 002D ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] -× 05D0 × 0308 × 002D ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] -× 05D0 × 0308 × 0020 ÷ 002D ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] +× 05D0 × 0308 × 002D ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] +× 05D0 × 0308 × 0020 ÷ 002D ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] × 05D0 ÷ 231A ÷ # × [0.3] HEBREW LETTER ALEF (HL) ÷ [999.0] WATCH (ID) ÷ [0.3] × 05D0 × 0020 ÷ 231A ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] -× 05D0 × 0308 ÷ 231A ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] WATCH (ID) ÷ [0.3] -× 05D0 × 0308 × 0020 ÷ 231A ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] +× 05D0 × 0308 ÷ 231A ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] WATCH (ID) ÷ [0.3] +× 05D0 × 0308 × 0020 ÷ 231A ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] × 05D0 × 2024 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [22.01] ONE DOT LEADER (IN) ÷ [0.3] × 05D0 × 0020 ÷ 2024 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] -× 05D0 × 0308 × 2024 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM) × [22.01] ONE DOT LEADER (IN) ÷ [0.3] -× 05D0 × 0308 × 0020 ÷ 2024 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] +× 05D0 × 0308 × 2024 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [22.01] ONE DOT LEADER (IN) ÷ [0.3] +× 05D0 × 0308 × 0020 ÷ 2024 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] × 05D0 × 002C ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [13.02] COMMA (IS) ÷ [0.3] × 05D0 × 0020 × 002C ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] -× 05D0 × 0308 × 002C ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM) × [13.03] COMMA (IS) ÷ [0.3] -× 05D0 × 0308 × 0020 × 002C ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] +× 05D0 × 0308 × 002C ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] COMMA (IS) ÷ [0.3] +× 05D0 × 0308 × 0020 × 002C ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] × 05D0 ÷ 1100 ÷ # × [0.3] HEBREW LETTER ALEF (HL) ÷ [999.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] × 05D0 × 0020 ÷ 1100 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] -× 05D0 × 0308 ÷ 1100 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] -× 05D0 × 0308 × 0020 ÷ 1100 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] +× 05D0 × 0308 ÷ 1100 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] +× 05D0 × 0308 × 0020 ÷ 1100 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] × 05D0 ÷ 11A8 ÷ # × [0.3] HEBREW LETTER ALEF (HL) ÷ [999.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] × 05D0 × 0020 ÷ 11A8 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] -× 05D0 × 0308 ÷ 11A8 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] -× 05D0 × 0308 × 0020 ÷ 11A8 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] +× 05D0 × 0308 ÷ 11A8 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] +× 05D0 × 0308 × 0020 ÷ 11A8 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] × 05D0 ÷ 1160 ÷ # × [0.3] HEBREW LETTER ALEF (HL) ÷ [999.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] × 05D0 × 0020 ÷ 1160 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] -× 05D0 × 0308 ÷ 1160 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] -× 05D0 × 0308 × 0020 ÷ 1160 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] +× 05D0 × 0308 ÷ 1160 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] +× 05D0 × 0308 × 0020 ÷ 1160 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] × 05D0 × 000A ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] × 05D0 × 0020 × 000A ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] -× 05D0 × 0308 × 000A ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] -× 05D0 × 0308 × 0020 × 000A ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] +× 05D0 × 0308 × 000A ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] +× 05D0 × 0308 × 0020 × 000A ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] × 05D0 × 0085 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] × 05D0 × 0020 × 0085 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] -× 05D0 × 0308 × 0085 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] -× 05D0 × 0308 × 0020 × 0085 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] +× 05D0 × 0308 × 0085 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] +× 05D0 × 0308 × 0020 × 0085 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] × 05D0 × 17D6 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] × 05D0 × 0020 ÷ 17D6 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] -× 05D0 × 0308 × 17D6 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] -× 05D0 × 0308 × 0020 ÷ 17D6 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] +× 05D0 × 0308 × 17D6 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] +× 05D0 × 0308 × 0020 ÷ 17D6 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] × 05D0 × 0030 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [23.02] DIGIT ZERO (NU) ÷ [0.3] × 05D0 × 0020 ÷ 0030 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] -× 05D0 × 0308 × 0030 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM) × [23.02] DIGIT ZERO (NU) ÷ [0.3] -× 05D0 × 0308 × 0020 ÷ 0030 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] +× 05D0 × 0308 × 0030 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [23.02] DIGIT ZERO (NU) ÷ [0.3] +× 05D0 × 0308 × 0020 ÷ 0030 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] × 05D0 × 0028 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [30.01] LEFT PARENTHESIS (OP) ÷ [0.3] × 05D0 × 0020 ÷ 0028 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] -× 05D0 × 0308 × 0028 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM) × [30.01] LEFT PARENTHESIS (OP) ÷ [0.3] -× 05D0 × 0308 × 0020 ÷ 0028 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] -× 05D0 ÷ 0025 ÷ # × [0.3] HEBREW LETTER ALEF (HL) ÷ [999.0] PERCENT SIGN (PO) ÷ [0.3] +× 05D0 × 0308 × 0028 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [30.01] LEFT PARENTHESIS (OP) ÷ [0.3] +× 05D0 × 0308 × 0020 ÷ 0028 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] +× 05D0 × 0025 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [24.03] PERCENT SIGN (PO) ÷ [0.3] × 05D0 × 0020 ÷ 0025 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] -× 05D0 × 0308 ÷ 0025 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] PERCENT SIGN (PO) ÷ [0.3] -× 05D0 × 0308 × 0020 ÷ 0025 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] -× 05D0 ÷ 0024 ÷ # × [0.3] HEBREW LETTER ALEF (HL) ÷ [999.0] DOLLAR SIGN (PR) ÷ [0.3] +× 05D0 × 0308 × 0025 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [24.03] PERCENT SIGN (PO) ÷ [0.3] +× 05D0 × 0308 × 0020 ÷ 0025 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] +× 05D0 × 0024 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [24.03] DOLLAR SIGN (PR) ÷ [0.3] × 05D0 × 0020 ÷ 0024 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] -× 05D0 × 0308 ÷ 0024 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] DOLLAR SIGN (PR) ÷ [0.3] -× 05D0 × 0308 × 0020 ÷ 0024 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] +× 05D0 × 0308 × 0024 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [24.03] DOLLAR SIGN (PR) ÷ [0.3] +× 05D0 × 0308 × 0020 ÷ 0024 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] × 05D0 × 0022 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [19.01] QUOTATION MARK (QU) ÷ [0.3] × 05D0 × 0020 ÷ 0022 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] -× 05D0 × 0308 × 0022 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM) × [19.01] QUOTATION MARK (QU) ÷ [0.3] -× 05D0 × 0308 × 0020 ÷ 0022 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] +× 05D0 × 0308 × 0022 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [19.01] QUOTATION MARK (QU) ÷ [0.3] +× 05D0 × 0308 × 0020 ÷ 0022 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] × 05D0 × 0020 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [7.01] SPACE (SP) ÷ [0.3] × 05D0 × 0020 × 0020 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] -× 05D0 × 0308 × 0020 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [0.3] -× 05D0 × 0308 × 0020 × 0020 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] +× 05D0 × 0308 × 0020 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [0.3] +× 05D0 × 0308 × 0020 × 0020 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] × 05D0 × 002F ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [13.02] SOLIDUS (SY) ÷ [0.3] × 05D0 × 0020 × 002F ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] -× 05D0 × 0308 × 002F ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM) × [13.03] SOLIDUS (SY) ÷ [0.3] -× 05D0 × 0308 × 0020 × 002F ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] +× 05D0 × 0308 × 002F ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] SOLIDUS (SY) ÷ [0.3] +× 05D0 × 0308 × 0020 × 002F ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] × 05D0 × 2060 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [11.01] WORD JOINER (WJ) ÷ [0.3] × 05D0 × 0020 × 2060 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] -× 05D0 × 0308 × 2060 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM) × [11.01] WORD JOINER (WJ) ÷ [0.3] -× 05D0 × 0308 × 0020 × 2060 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] +× 05D0 × 0308 × 2060 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [11.01] WORD JOINER (WJ) ÷ [0.3] +× 05D0 × 0308 × 0020 × 2060 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] × 05D0 × 200B ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] × 05D0 × 0020 × 200B ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] -× 05D0 × 0308 × 200B ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] -× 05D0 × 0308 × 0020 × 200B ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] +× 05D0 × 0308 × 200B ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] +× 05D0 × 0308 × 0020 × 200B ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] × 05D0 ÷ 1F1E6 ÷ # × [0.3] HEBREW LETTER ALEF (HL) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] × 05D0 × 0020 ÷ 1F1E6 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -× 05D0 × 0308 ÷ 1F1E6 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -× 05D0 × 0308 × 0020 ÷ 1F1E6 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 05D0 × 0308 ÷ 1F1E6 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 05D0 × 0308 × 0020 ÷ 1F1E6 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 05D0 ÷ 261D ÷ # × [0.3] HEBREW LETTER ALEF (HL) ÷ [999.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 05D0 × 0020 ÷ 261D ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [7.01] SPACE (SP) ÷ [18.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 05D0 × 0308 ÷ 261D ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 05D0 × 0308 × 0020 ÷ 261D ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 05D0 ÷ 1F3FB ÷ # × [0.3] HEBREW LETTER ALEF (HL) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 05D0 × 0020 ÷ 1F3FB ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [7.01] SPACE (SP) ÷ [18.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 05D0 × 0308 ÷ 1F3FB ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 05D0 × 0308 × 0020 ÷ 1F3FB ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 05D0 × 0001 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 05D0 × 0020 ÷ 0001 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 05D0 × 0308 × 0001 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [9.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 05D0 × 0308 × 0020 ÷ 0001 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 05D0 × 200D ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 05D0 × 0020 ÷ 200D ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [7.01] SPACE (SP) ÷ [18.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 05D0 × 0308 × 200D ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [9.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 05D0 × 0308 × 0020 ÷ 200D ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] × 05D0 × 00A7 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [28.0] SECTION SIGN (AI_AL) ÷ [0.3] × 05D0 × 0020 ÷ 00A7 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] -× 05D0 × 0308 × 00A7 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM) × [28.0] SECTION SIGN (AI_AL) ÷ [0.3] -× 05D0 × 0308 × 0020 ÷ 00A7 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] +× 05D0 × 0308 × 00A7 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [28.0] SECTION SIGN (AI_AL) ÷ [0.3] +× 05D0 × 0308 × 0020 ÷ 00A7 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] × 05D0 × 50005 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [28.0] <reserved-50005> (XX_AL) ÷ [0.3] × 05D0 × 0020 ÷ 50005 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] -× 05D0 × 0308 × 50005 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM) × [28.0] <reserved-50005> (XX_AL) ÷ [0.3] -× 05D0 × 0308 × 0020 ÷ 50005 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] +× 05D0 × 0308 × 50005 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [28.0] <reserved-50005> (XX_AL) ÷ [0.3] +× 05D0 × 0308 × 0020 ÷ 50005 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] × 05D0 × 0E01 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [28.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] × 05D0 × 0020 ÷ 0E01 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] -× 05D0 × 0308 × 0E01 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM) × [28.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] -× 05D0 × 0308 × 0020 ÷ 0E01 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] +× 05D0 × 0308 × 0E01 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [28.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] +× 05D0 × 0308 × 0020 ÷ 0E01 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] × 05D0 × 3041 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] × 05D0 × 0020 ÷ 3041 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] -× 05D0 × 0308 × 3041 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] -× 05D0 × 0308 × 0020 ÷ 3041 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] +× 05D0 × 0308 × 3041 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] +× 05D0 × 0308 × 0020 ÷ 3041 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] × 002D ÷ 0023 ÷ # × [0.3] HYPHEN-MINUS (HY) ÷ [999.0] NUMBER SIGN (AL) ÷ [0.3] × 002D × 0020 ÷ 0023 ÷ # × [0.3] HYPHEN-MINUS (HY) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] -× 002D × 0308 ÷ 0023 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] NUMBER SIGN (AL) ÷ [0.3] -× 002D × 0308 × 0020 ÷ 0023 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] +× 002D × 0308 ÷ 0023 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] NUMBER SIGN (AL) ÷ [0.3] +× 002D × 0308 × 0020 ÷ 0023 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] × 002D ÷ 2014 ÷ # × [0.3] HYPHEN-MINUS (HY) ÷ [999.0] EM DASH (B2) ÷ [0.3] × 002D × 0020 ÷ 2014 ÷ # × [0.3] HYPHEN-MINUS (HY) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] -× 002D × 0308 ÷ 2014 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] EM DASH (B2) ÷ [0.3] -× 002D × 0308 × 0020 ÷ 2014 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] +× 002D × 0308 ÷ 2014 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] EM DASH (B2) ÷ [0.3] +× 002D × 0308 × 0020 ÷ 2014 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] × 002D × 0009 ÷ # × [0.3] HYPHEN-MINUS (HY) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] × 002D × 0020 ÷ 0009 ÷ # × [0.3] HYPHEN-MINUS (HY) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] -× 002D × 0308 × 0009 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] -× 002D × 0308 × 0020 ÷ 0009 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] +× 002D × 0308 × 0009 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] +× 002D × 0308 × 0020 ÷ 0009 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] × 002D ÷ 00B4 ÷ # × [0.3] HYPHEN-MINUS (HY) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3] × 002D × 0020 ÷ 00B4 ÷ # × [0.3] HYPHEN-MINUS (HY) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] -× 002D × 0308 ÷ 00B4 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3] -× 002D × 0308 × 0020 ÷ 00B4 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] +× 002D × 0308 ÷ 00B4 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3] +× 002D × 0308 × 0020 ÷ 00B4 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] × 002D × 000B ÷ # × [0.3] HYPHEN-MINUS (HY) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] × 002D × 0020 × 000B ÷ # × [0.3] HYPHEN-MINUS (HY) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] -× 002D × 0308 × 000B ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] -× 002D × 0308 × 0020 × 000B ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] +× 002D × 0308 × 000B ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] +× 002D × 0308 × 0020 × 000B ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] × 002D ÷ FFFC ÷ # × [0.3] HYPHEN-MINUS (HY) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] × 002D × 0020 ÷ FFFC ÷ # × [0.3] HYPHEN-MINUS (HY) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] -× 002D × 0308 ÷ FFFC ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] -× 002D × 0308 × 0020 ÷ FFFC ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] +× 002D × 0308 ÷ FFFC ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] +× 002D × 0308 × 0020 ÷ FFFC ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] × 002D × 007D ÷ # × [0.3] HYPHEN-MINUS (HY) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] × 002D × 0020 × 007D ÷ # × [0.3] HYPHEN-MINUS (HY) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] -× 002D × 0308 × 007D ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM) × [13.03] RIGHT CURLY BRACKET (CL) ÷ [0.3] -× 002D × 0308 × 0020 × 007D ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] +× 002D × 0308 × 007D ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] RIGHT CURLY BRACKET (CL) ÷ [0.3] +× 002D × 0308 × 0020 × 007D ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] × 002D × 0029 ÷ # × [0.3] HYPHEN-MINUS (HY) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] × 002D × 0020 × 0029 ÷ # × [0.3] HYPHEN-MINUS (HY) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 002D × 0308 × 0029 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM) × [13.03] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 002D × 0308 × 0020 × 0029 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 002D × 0001 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] <START OF HEADING> (CM) ÷ [0.3] -× 002D × 0020 ÷ 0001 ÷ # × [0.3] HYPHEN-MINUS (HY) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM) ÷ [0.3] -× 002D × 0308 × 0001 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM) × [9.0] <START OF HEADING> (CM) ÷ [0.3] -× 002D × 0308 × 0020 ÷ 0001 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM) ÷ [0.3] +× 002D × 0308 × 0029 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] RIGHT PARENTHESIS (CP) ÷ [0.3] +× 002D × 0308 × 0020 × 0029 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] × 002D × 000D ÷ # × [0.3] HYPHEN-MINUS (HY) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] × 002D × 0020 × 000D ÷ # × [0.3] HYPHEN-MINUS (HY) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -× 002D × 0308 × 000D ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -× 002D × 0308 × 0020 × 000D ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +× 002D × 0308 × 000D ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +× 002D × 0308 × 0020 × 000D ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] × 002D × 0021 ÷ # × [0.3] HYPHEN-MINUS (HY) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] × 002D × 0020 × 0021 ÷ # × [0.3] HYPHEN-MINUS (HY) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] -× 002D × 0308 × 0021 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] -× 002D × 0308 × 0020 × 0021 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] +× 002D × 0308 × 0021 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] +× 002D × 0308 × 0020 × 0021 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] × 002D ÷ 00A0 ÷ # × [0.3] HYPHEN-MINUS (HY) ÷ [999.0] NO-BREAK SPACE (GL) ÷ [0.3] × 002D × 0020 ÷ 00A0 ÷ # × [0.3] HYPHEN-MINUS (HY) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] -× 002D × 0308 ÷ 00A0 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] NO-BREAK SPACE (GL) ÷ [0.3] -× 002D × 0308 × 0020 ÷ 00A0 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] +× 002D × 0308 ÷ 00A0 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] NO-BREAK SPACE (GL) ÷ [0.3] +× 002D × 0308 × 0020 ÷ 00A0 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] × 002D ÷ AC00 ÷ # × [0.3] HYPHEN-MINUS (HY) ÷ [999.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] × 002D × 0020 ÷ AC00 ÷ # × [0.3] HYPHEN-MINUS (HY) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] -× 002D × 0308 ÷ AC00 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] -× 002D × 0308 × 0020 ÷ AC00 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] +× 002D × 0308 ÷ AC00 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] +× 002D × 0308 × 0020 ÷ AC00 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] × 002D ÷ AC01 ÷ # × [0.3] HYPHEN-MINUS (HY) ÷ [999.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] × 002D × 0020 ÷ AC01 ÷ # × [0.3] HYPHEN-MINUS (HY) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] -× 002D × 0308 ÷ AC01 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] -× 002D × 0308 × 0020 ÷ AC01 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] +× 002D × 0308 ÷ AC01 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] +× 002D × 0308 × 0020 ÷ AC01 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] × 002D ÷ 05D0 ÷ # × [0.3] HYPHEN-MINUS (HY) ÷ [999.0] HEBREW LETTER ALEF (HL) ÷ [0.3] × 002D × 0020 ÷ 05D0 ÷ # × [0.3] HYPHEN-MINUS (HY) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] -× 002D × 0308 ÷ 05D0 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HEBREW LETTER ALEF (HL) ÷ [0.3] -× 002D × 0308 × 0020 ÷ 05D0 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] +× 002D × 0308 ÷ 05D0 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HEBREW LETTER ALEF (HL) ÷ [0.3] +× 002D × 0308 × 0020 ÷ 05D0 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] × 002D × 002D ÷ # × [0.3] HYPHEN-MINUS (HY) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] × 002D × 0020 ÷ 002D ÷ # × [0.3] HYPHEN-MINUS (HY) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] -× 002D × 0308 × 002D ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] -× 002D × 0308 × 0020 ÷ 002D ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] +× 002D × 0308 × 002D ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] +× 002D × 0308 × 0020 ÷ 002D ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] × 002D ÷ 231A ÷ # × [0.3] HYPHEN-MINUS (HY) ÷ [999.0] WATCH (ID) ÷ [0.3] × 002D × 0020 ÷ 231A ÷ # × [0.3] HYPHEN-MINUS (HY) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] -× 002D × 0308 ÷ 231A ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] WATCH (ID) ÷ [0.3] -× 002D × 0308 × 0020 ÷ 231A ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] +× 002D × 0308 ÷ 231A ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] WATCH (ID) ÷ [0.3] +× 002D × 0308 × 0020 ÷ 231A ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] × 002D ÷ 2024 ÷ # × [0.3] HYPHEN-MINUS (HY) ÷ [999.0] ONE DOT LEADER (IN) ÷ [0.3] × 002D × 0020 ÷ 2024 ÷ # × [0.3] HYPHEN-MINUS (HY) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] -× 002D × 0308 ÷ 2024 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] ONE DOT LEADER (IN) ÷ [0.3] -× 002D × 0308 × 0020 ÷ 2024 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] +× 002D × 0308 ÷ 2024 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] ONE DOT LEADER (IN) ÷ [0.3] +× 002D × 0308 × 0020 ÷ 2024 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] × 002D × 002C ÷ # × [0.3] HYPHEN-MINUS (HY) × [13.02] COMMA (IS) ÷ [0.3] × 002D × 0020 × 002C ÷ # × [0.3] HYPHEN-MINUS (HY) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] -× 002D × 0308 × 002C ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM) × [13.03] COMMA (IS) ÷ [0.3] -× 002D × 0308 × 0020 × 002C ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] +× 002D × 0308 × 002C ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] COMMA (IS) ÷ [0.3] +× 002D × 0308 × 0020 × 002C ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] × 002D ÷ 1100 ÷ # × [0.3] HYPHEN-MINUS (HY) ÷ [999.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] × 002D × 0020 ÷ 1100 ÷ # × [0.3] HYPHEN-MINUS (HY) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] -× 002D × 0308 ÷ 1100 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] -× 002D × 0308 × 0020 ÷ 1100 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] +× 002D × 0308 ÷ 1100 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] +× 002D × 0308 × 0020 ÷ 1100 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] × 002D ÷ 11A8 ÷ # × [0.3] HYPHEN-MINUS (HY) ÷ [999.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] × 002D × 0020 ÷ 11A8 ÷ # × [0.3] HYPHEN-MINUS (HY) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] -× 002D × 0308 ÷ 11A8 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] -× 002D × 0308 × 0020 ÷ 11A8 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] +× 002D × 0308 ÷ 11A8 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] +× 002D × 0308 × 0020 ÷ 11A8 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] × 002D ÷ 1160 ÷ # × [0.3] HYPHEN-MINUS (HY) ÷ [999.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] × 002D × 0020 ÷ 1160 ÷ # × [0.3] HYPHEN-MINUS (HY) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] -× 002D × 0308 ÷ 1160 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] -× 002D × 0308 × 0020 ÷ 1160 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] +× 002D × 0308 ÷ 1160 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] +× 002D × 0308 × 0020 ÷ 1160 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] × 002D × 000A ÷ # × [0.3] HYPHEN-MINUS (HY) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] × 002D × 0020 × 000A ÷ # × [0.3] HYPHEN-MINUS (HY) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] -× 002D × 0308 × 000A ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] -× 002D × 0308 × 0020 × 000A ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] +× 002D × 0308 × 000A ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] +× 002D × 0308 × 0020 × 000A ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] × 002D × 0085 ÷ # × [0.3] HYPHEN-MINUS (HY) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] × 002D × 0020 × 0085 ÷ # × [0.3] HYPHEN-MINUS (HY) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] -× 002D × 0308 × 0085 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] -× 002D × 0308 × 0020 × 0085 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] +× 002D × 0308 × 0085 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] +× 002D × 0308 × 0020 × 0085 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] × 002D × 17D6 ÷ # × [0.3] HYPHEN-MINUS (HY) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] × 002D × 0020 ÷ 17D6 ÷ # × [0.3] HYPHEN-MINUS (HY) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] -× 002D × 0308 × 17D6 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] -× 002D × 0308 × 0020 ÷ 17D6 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] +× 002D × 0308 × 17D6 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] +× 002D × 0308 × 0020 ÷ 17D6 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] × 002D × 0030 ÷ # × [0.3] HYPHEN-MINUS (HY) × [25.02] DIGIT ZERO (NU) ÷ [0.3] × 002D × 0020 ÷ 0030 ÷ # × [0.3] HYPHEN-MINUS (HY) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] -× 002D × 0308 × 0030 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM) × [25.02] DIGIT ZERO (NU) ÷ [0.3] -× 002D × 0308 × 0020 ÷ 0030 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] +× 002D × 0308 × 0030 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [25.02] DIGIT ZERO (NU) ÷ [0.3] +× 002D × 0308 × 0020 ÷ 0030 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] × 002D ÷ 0028 ÷ # × [0.3] HYPHEN-MINUS (HY) ÷ [999.0] LEFT PARENTHESIS (OP) ÷ [0.3] × 002D × 0020 ÷ 0028 ÷ # × [0.3] HYPHEN-MINUS (HY) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] -× 002D × 0308 ÷ 0028 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] LEFT PARENTHESIS (OP) ÷ [0.3] -× 002D × 0308 × 0020 ÷ 0028 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] +× 002D × 0308 ÷ 0028 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] LEFT PARENTHESIS (OP) ÷ [0.3] +× 002D × 0308 × 0020 ÷ 0028 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] × 002D ÷ 0025 ÷ # × [0.3] HYPHEN-MINUS (HY) ÷ [999.0] PERCENT SIGN (PO) ÷ [0.3] × 002D × 0020 ÷ 0025 ÷ # × [0.3] HYPHEN-MINUS (HY) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] -× 002D × 0308 ÷ 0025 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] PERCENT SIGN (PO) ÷ [0.3] -× 002D × 0308 × 0020 ÷ 0025 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] +× 002D × 0308 ÷ 0025 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] PERCENT SIGN (PO) ÷ [0.3] +× 002D × 0308 × 0020 ÷ 0025 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] × 002D ÷ 0024 ÷ # × [0.3] HYPHEN-MINUS (HY) ÷ [999.0] DOLLAR SIGN (PR) ÷ [0.3] × 002D × 0020 ÷ 0024 ÷ # × [0.3] HYPHEN-MINUS (HY) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] -× 002D × 0308 ÷ 0024 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] DOLLAR SIGN (PR) ÷ [0.3] -× 002D × 0308 × 0020 ÷ 0024 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] +× 002D × 0308 ÷ 0024 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] DOLLAR SIGN (PR) ÷ [0.3] +× 002D × 0308 × 0020 ÷ 0024 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] × 002D × 0022 ÷ # × [0.3] HYPHEN-MINUS (HY) × [19.01] QUOTATION MARK (QU) ÷ [0.3] × 002D × 0020 ÷ 0022 ÷ # × [0.3] HYPHEN-MINUS (HY) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] -× 002D × 0308 × 0022 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM) × [19.01] QUOTATION MARK (QU) ÷ [0.3] -× 002D × 0308 × 0020 ÷ 0022 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] +× 002D × 0308 × 0022 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [19.01] QUOTATION MARK (QU) ÷ [0.3] +× 002D × 0308 × 0020 ÷ 0022 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] × 002D × 0020 ÷ # × [0.3] HYPHEN-MINUS (HY) × [7.01] SPACE (SP) ÷ [0.3] × 002D × 0020 × 0020 ÷ # × [0.3] HYPHEN-MINUS (HY) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] -× 002D × 0308 × 0020 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [0.3] -× 002D × 0308 × 0020 × 0020 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] +× 002D × 0308 × 0020 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [0.3] +× 002D × 0308 × 0020 × 0020 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] × 002D × 002F ÷ # × [0.3] HYPHEN-MINUS (HY) × [13.02] SOLIDUS (SY) ÷ [0.3] × 002D × 0020 × 002F ÷ # × [0.3] HYPHEN-MINUS (HY) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] -× 002D × 0308 × 002F ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM) × [13.03] SOLIDUS (SY) ÷ [0.3] -× 002D × 0308 × 0020 × 002F ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] +× 002D × 0308 × 002F ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] SOLIDUS (SY) ÷ [0.3] +× 002D × 0308 × 0020 × 002F ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] × 002D × 2060 ÷ # × [0.3] HYPHEN-MINUS (HY) × [11.01] WORD JOINER (WJ) ÷ [0.3] × 002D × 0020 × 2060 ÷ # × [0.3] HYPHEN-MINUS (HY) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] -× 002D × 0308 × 2060 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM) × [11.01] WORD JOINER (WJ) ÷ [0.3] -× 002D × 0308 × 0020 × 2060 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] +× 002D × 0308 × 2060 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [11.01] WORD JOINER (WJ) ÷ [0.3] +× 002D × 0308 × 0020 × 2060 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] × 002D × 200B ÷ # × [0.3] HYPHEN-MINUS (HY) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] × 002D × 0020 × 200B ÷ # × [0.3] HYPHEN-MINUS (HY) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] -× 002D × 0308 × 200B ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] -× 002D × 0308 × 0020 × 200B ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] +× 002D × 0308 × 200B ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] +× 002D × 0308 × 0020 × 200B ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] × 002D ÷ 1F1E6 ÷ # × [0.3] HYPHEN-MINUS (HY) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] × 002D × 0020 ÷ 1F1E6 ÷ # × [0.3] HYPHEN-MINUS (HY) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -× 002D × 0308 ÷ 1F1E6 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -× 002D × 0308 × 0020 ÷ 1F1E6 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 002D × 0308 ÷ 1F1E6 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 002D × 0308 × 0020 ÷ 1F1E6 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 002D ÷ 261D ÷ # × [0.3] HYPHEN-MINUS (HY) ÷ [999.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 002D × 0020 ÷ 261D ÷ # × [0.3] HYPHEN-MINUS (HY) × [7.01] SPACE (SP) ÷ [18.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 002D × 0308 ÷ 261D ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 002D × 0308 × 0020 ÷ 261D ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 002D ÷ 1F3FB ÷ # × [0.3] HYPHEN-MINUS (HY) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 002D × 0020 ÷ 1F3FB ÷ # × [0.3] HYPHEN-MINUS (HY) × [7.01] SPACE (SP) ÷ [18.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 002D × 0308 ÷ 1F3FB ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 002D × 0308 × 0020 ÷ 1F3FB ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 002D × 0001 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 002D × 0020 ÷ 0001 ÷ # × [0.3] HYPHEN-MINUS (HY) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 002D × 0308 × 0001 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [9.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 002D × 0308 × 0020 ÷ 0001 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 002D × 200D ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 002D × 0020 ÷ 200D ÷ # × [0.3] HYPHEN-MINUS (HY) × [7.01] SPACE (SP) ÷ [18.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 002D × 0308 × 200D ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [9.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 002D × 0308 × 0020 ÷ 200D ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] × 002D ÷ 00A7 ÷ # × [0.3] HYPHEN-MINUS (HY) ÷ [999.0] SECTION SIGN (AI_AL) ÷ [0.3] × 002D × 0020 ÷ 00A7 ÷ # × [0.3] HYPHEN-MINUS (HY) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] -× 002D × 0308 ÷ 00A7 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] SECTION SIGN (AI_AL) ÷ [0.3] -× 002D × 0308 × 0020 ÷ 00A7 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] +× 002D × 0308 ÷ 00A7 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] SECTION SIGN (AI_AL) ÷ [0.3] +× 002D × 0308 × 0020 ÷ 00A7 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] × 002D ÷ 50005 ÷ # × [0.3] HYPHEN-MINUS (HY) ÷ [999.0] <reserved-50005> (XX_AL) ÷ [0.3] × 002D × 0020 ÷ 50005 ÷ # × [0.3] HYPHEN-MINUS (HY) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] -× 002D × 0308 ÷ 50005 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] <reserved-50005> (XX_AL) ÷ [0.3] -× 002D × 0308 × 0020 ÷ 50005 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] +× 002D × 0308 ÷ 50005 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] <reserved-50005> (XX_AL) ÷ [0.3] +× 002D × 0308 × 0020 ÷ 50005 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] × 002D ÷ 0E01 ÷ # × [0.3] HYPHEN-MINUS (HY) ÷ [999.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] × 002D × 0020 ÷ 0E01 ÷ # × [0.3] HYPHEN-MINUS (HY) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] -× 002D × 0308 ÷ 0E01 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] -× 002D × 0308 × 0020 ÷ 0E01 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] +× 002D × 0308 ÷ 0E01 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] +× 002D × 0308 × 0020 ÷ 0E01 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] × 002D × 3041 ÷ # × [0.3] HYPHEN-MINUS (HY) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] × 002D × 0020 ÷ 3041 ÷ # × [0.3] HYPHEN-MINUS (HY) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] -× 002D × 0308 × 3041 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] -× 002D × 0308 × 0020 ÷ 3041 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] +× 002D × 0308 × 3041 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] +× 002D × 0308 × 0020 ÷ 3041 ÷ # × [0.3] HYPHEN-MINUS (HY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] × 231A ÷ 0023 ÷ # × [0.3] WATCH (ID) ÷ [999.0] NUMBER SIGN (AL) ÷ [0.3] × 231A × 0020 ÷ 0023 ÷ # × [0.3] WATCH (ID) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] -× 231A × 0308 ÷ 0023 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] NUMBER SIGN (AL) ÷ [0.3] -× 231A × 0308 × 0020 ÷ 0023 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] +× 231A × 0308 ÷ 0023 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] NUMBER SIGN (AL) ÷ [0.3] +× 231A × 0308 × 0020 ÷ 0023 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] × 231A ÷ 2014 ÷ # × [0.3] WATCH (ID) ÷ [999.0] EM DASH (B2) ÷ [0.3] × 231A × 0020 ÷ 2014 ÷ # × [0.3] WATCH (ID) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] -× 231A × 0308 ÷ 2014 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] EM DASH (B2) ÷ [0.3] -× 231A × 0308 × 0020 ÷ 2014 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] +× 231A × 0308 ÷ 2014 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] EM DASH (B2) ÷ [0.3] +× 231A × 0308 × 0020 ÷ 2014 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] × 231A × 0009 ÷ # × [0.3] WATCH (ID) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] × 231A × 0020 ÷ 0009 ÷ # × [0.3] WATCH (ID) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] -× 231A × 0308 × 0009 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] -× 231A × 0308 × 0020 ÷ 0009 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] +× 231A × 0308 × 0009 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] +× 231A × 0308 × 0020 ÷ 0009 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] × 231A ÷ 00B4 ÷ # × [0.3] WATCH (ID) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3] × 231A × 0020 ÷ 00B4 ÷ # × [0.3] WATCH (ID) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] -× 231A × 0308 ÷ 00B4 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3] -× 231A × 0308 × 0020 ÷ 00B4 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] +× 231A × 0308 ÷ 00B4 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3] +× 231A × 0308 × 0020 ÷ 00B4 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] × 231A × 000B ÷ # × [0.3] WATCH (ID) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] × 231A × 0020 × 000B ÷ # × [0.3] WATCH (ID) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] -× 231A × 0308 × 000B ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] -× 231A × 0308 × 0020 × 000B ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] +× 231A × 0308 × 000B ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] +× 231A × 0308 × 0020 × 000B ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] × 231A ÷ FFFC ÷ # × [0.3] WATCH (ID) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] × 231A × 0020 ÷ FFFC ÷ # × [0.3] WATCH (ID) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] -× 231A × 0308 ÷ FFFC ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] -× 231A × 0308 × 0020 ÷ FFFC ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] +× 231A × 0308 ÷ FFFC ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] +× 231A × 0308 × 0020 ÷ FFFC ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] × 231A × 007D ÷ # × [0.3] WATCH (ID) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] × 231A × 0020 × 007D ÷ # × [0.3] WATCH (ID) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] -× 231A × 0308 × 007D ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM) × [13.03] RIGHT CURLY BRACKET (CL) ÷ [0.3] -× 231A × 0308 × 0020 × 007D ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] +× 231A × 0308 × 007D ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] RIGHT CURLY BRACKET (CL) ÷ [0.3] +× 231A × 0308 × 0020 × 007D ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] × 231A × 0029 ÷ # × [0.3] WATCH (ID) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] × 231A × 0020 × 0029 ÷ # × [0.3] WATCH (ID) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 231A × 0308 × 0029 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM) × [13.03] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 231A × 0308 × 0020 × 0029 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 231A × 0001 ÷ # × [0.3] WATCH (ID) × [9.0] <START OF HEADING> (CM) ÷ [0.3] -× 231A × 0020 ÷ 0001 ÷ # × [0.3] WATCH (ID) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM) ÷ [0.3] -× 231A × 0308 × 0001 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM) × [9.0] <START OF HEADING> (CM) ÷ [0.3] -× 231A × 0308 × 0020 ÷ 0001 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM) ÷ [0.3] +× 231A × 0308 × 0029 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] RIGHT PARENTHESIS (CP) ÷ [0.3] +× 231A × 0308 × 0020 × 0029 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] × 231A × 000D ÷ # × [0.3] WATCH (ID) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] × 231A × 0020 × 000D ÷ # × [0.3] WATCH (ID) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -× 231A × 0308 × 000D ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -× 231A × 0308 × 0020 × 000D ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +× 231A × 0308 × 000D ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +× 231A × 0308 × 0020 × 000D ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] × 231A × 0021 ÷ # × [0.3] WATCH (ID) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] × 231A × 0020 × 0021 ÷ # × [0.3] WATCH (ID) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] -× 231A × 0308 × 0021 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] -× 231A × 0308 × 0020 × 0021 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] +× 231A × 0308 × 0021 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] +× 231A × 0308 × 0020 × 0021 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] × 231A × 00A0 ÷ # × [0.3] WATCH (ID) × [12.1] NO-BREAK SPACE (GL) ÷ [0.3] × 231A × 0020 ÷ 00A0 ÷ # × [0.3] WATCH (ID) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] -× 231A × 0308 × 00A0 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM) × [12.2] NO-BREAK SPACE (GL) ÷ [0.3] -× 231A × 0308 × 0020 ÷ 00A0 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] +× 231A × 0308 × 00A0 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM1_CM) × [12.2] NO-BREAK SPACE (GL) ÷ [0.3] +× 231A × 0308 × 0020 ÷ 00A0 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] × 231A ÷ AC00 ÷ # × [0.3] WATCH (ID) ÷ [999.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] × 231A × 0020 ÷ AC00 ÷ # × [0.3] WATCH (ID) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] -× 231A × 0308 ÷ AC00 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] -× 231A × 0308 × 0020 ÷ AC00 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] +× 231A × 0308 ÷ AC00 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] +× 231A × 0308 × 0020 ÷ AC00 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] × 231A ÷ AC01 ÷ # × [0.3] WATCH (ID) ÷ [999.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] × 231A × 0020 ÷ AC01 ÷ # × [0.3] WATCH (ID) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] -× 231A × 0308 ÷ AC01 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] -× 231A × 0308 × 0020 ÷ AC01 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] +× 231A × 0308 ÷ AC01 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] +× 231A × 0308 × 0020 ÷ AC01 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] × 231A ÷ 05D0 ÷ # × [0.3] WATCH (ID) ÷ [999.0] HEBREW LETTER ALEF (HL) ÷ [0.3] × 231A × 0020 ÷ 05D0 ÷ # × [0.3] WATCH (ID) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] -× 231A × 0308 ÷ 05D0 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HEBREW LETTER ALEF (HL) ÷ [0.3] -× 231A × 0308 × 0020 ÷ 05D0 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] +× 231A × 0308 ÷ 05D0 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HEBREW LETTER ALEF (HL) ÷ [0.3] +× 231A × 0308 × 0020 ÷ 05D0 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] × 231A × 002D ÷ # × [0.3] WATCH (ID) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] × 231A × 0020 ÷ 002D ÷ # × [0.3] WATCH (ID) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] -× 231A × 0308 × 002D ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] -× 231A × 0308 × 0020 ÷ 002D ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] +× 231A × 0308 × 002D ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] +× 231A × 0308 × 0020 ÷ 002D ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] × 231A ÷ 231A ÷ # × [0.3] WATCH (ID) ÷ [999.0] WATCH (ID) ÷ [0.3] × 231A × 0020 ÷ 231A ÷ # × [0.3] WATCH (ID) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] -× 231A × 0308 ÷ 231A ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] WATCH (ID) ÷ [0.3] -× 231A × 0308 × 0020 ÷ 231A ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] +× 231A × 0308 ÷ 231A ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] WATCH (ID) ÷ [0.3] +× 231A × 0308 × 0020 ÷ 231A ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] × 231A × 2024 ÷ # × [0.3] WATCH (ID) × [22.03] ONE DOT LEADER (IN) ÷ [0.3] × 231A × 0020 ÷ 2024 ÷ # × [0.3] WATCH (ID) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] -× 231A × 0308 × 2024 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM) × [22.03] ONE DOT LEADER (IN) ÷ [0.3] -× 231A × 0308 × 0020 ÷ 2024 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] +× 231A × 0308 × 2024 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM1_CM) × [22.03] ONE DOT LEADER (IN) ÷ [0.3] +× 231A × 0308 × 0020 ÷ 2024 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] × 231A × 002C ÷ # × [0.3] WATCH (ID) × [13.02] COMMA (IS) ÷ [0.3] × 231A × 0020 × 002C ÷ # × [0.3] WATCH (ID) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] -× 231A × 0308 × 002C ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM) × [13.03] COMMA (IS) ÷ [0.3] -× 231A × 0308 × 0020 × 002C ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] +× 231A × 0308 × 002C ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] COMMA (IS) ÷ [0.3] +× 231A × 0308 × 0020 × 002C ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] × 231A ÷ 1100 ÷ # × [0.3] WATCH (ID) ÷ [999.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] × 231A × 0020 ÷ 1100 ÷ # × [0.3] WATCH (ID) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] -× 231A × 0308 ÷ 1100 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] -× 231A × 0308 × 0020 ÷ 1100 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] +× 231A × 0308 ÷ 1100 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] +× 231A × 0308 × 0020 ÷ 1100 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] × 231A ÷ 11A8 ÷ # × [0.3] WATCH (ID) ÷ [999.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] × 231A × 0020 ÷ 11A8 ÷ # × [0.3] WATCH (ID) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] -× 231A × 0308 ÷ 11A8 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] -× 231A × 0308 × 0020 ÷ 11A8 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] +× 231A × 0308 ÷ 11A8 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] +× 231A × 0308 × 0020 ÷ 11A8 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] × 231A ÷ 1160 ÷ # × [0.3] WATCH (ID) ÷ [999.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] × 231A × 0020 ÷ 1160 ÷ # × [0.3] WATCH (ID) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] -× 231A × 0308 ÷ 1160 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] -× 231A × 0308 × 0020 ÷ 1160 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] +× 231A × 0308 ÷ 1160 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] +× 231A × 0308 × 0020 ÷ 1160 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] × 231A × 000A ÷ # × [0.3] WATCH (ID) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] × 231A × 0020 × 000A ÷ # × [0.3] WATCH (ID) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] -× 231A × 0308 × 000A ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] -× 231A × 0308 × 0020 × 000A ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] +× 231A × 0308 × 000A ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] +× 231A × 0308 × 0020 × 000A ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] × 231A × 0085 ÷ # × [0.3] WATCH (ID) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] × 231A × 0020 × 0085 ÷ # × [0.3] WATCH (ID) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] -× 231A × 0308 × 0085 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] -× 231A × 0308 × 0020 × 0085 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] +× 231A × 0308 × 0085 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] +× 231A × 0308 × 0020 × 0085 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] × 231A × 17D6 ÷ # × [0.3] WATCH (ID) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] × 231A × 0020 ÷ 17D6 ÷ # × [0.3] WATCH (ID) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] -× 231A × 0308 × 17D6 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] -× 231A × 0308 × 0020 ÷ 17D6 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] +× 231A × 0308 × 17D6 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] +× 231A × 0308 × 0020 ÷ 17D6 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] × 231A ÷ 0030 ÷ # × [0.3] WATCH (ID) ÷ [999.0] DIGIT ZERO (NU) ÷ [0.3] × 231A × 0020 ÷ 0030 ÷ # × [0.3] WATCH (ID) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] -× 231A × 0308 ÷ 0030 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] DIGIT ZERO (NU) ÷ [0.3] -× 231A × 0308 × 0020 ÷ 0030 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] +× 231A × 0308 ÷ 0030 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] DIGIT ZERO (NU) ÷ [0.3] +× 231A × 0308 × 0020 ÷ 0030 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] × 231A ÷ 0028 ÷ # × [0.3] WATCH (ID) ÷ [999.0] LEFT PARENTHESIS (OP) ÷ [0.3] × 231A × 0020 ÷ 0028 ÷ # × [0.3] WATCH (ID) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] -× 231A × 0308 ÷ 0028 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] LEFT PARENTHESIS (OP) ÷ [0.3] -× 231A × 0308 × 0020 ÷ 0028 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] -× 231A × 0025 ÷ # × [0.3] WATCH (ID) × [23.01] PERCENT SIGN (PO) ÷ [0.3] +× 231A × 0308 ÷ 0028 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] LEFT PARENTHESIS (OP) ÷ [0.3] +× 231A × 0308 × 0020 ÷ 0028 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] +× 231A × 0025 ÷ # × [0.3] WATCH (ID) × [23.13] PERCENT SIGN (PO) ÷ [0.3] × 231A × 0020 ÷ 0025 ÷ # × [0.3] WATCH (ID) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] -× 231A × 0308 × 0025 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM) × [23.01] PERCENT SIGN (PO) ÷ [0.3] -× 231A × 0308 × 0020 ÷ 0025 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] +× 231A × 0308 × 0025 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM1_CM) × [23.13] PERCENT SIGN (PO) ÷ [0.3] +× 231A × 0308 × 0020 ÷ 0025 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] × 231A ÷ 0024 ÷ # × [0.3] WATCH (ID) ÷ [999.0] DOLLAR SIGN (PR) ÷ [0.3] × 231A × 0020 ÷ 0024 ÷ # × [0.3] WATCH (ID) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] -× 231A × 0308 ÷ 0024 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] DOLLAR SIGN (PR) ÷ [0.3] -× 231A × 0308 × 0020 ÷ 0024 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] +× 231A × 0308 ÷ 0024 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] DOLLAR SIGN (PR) ÷ [0.3] +× 231A × 0308 × 0020 ÷ 0024 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] × 231A × 0022 ÷ # × [0.3] WATCH (ID) × [19.01] QUOTATION MARK (QU) ÷ [0.3] × 231A × 0020 ÷ 0022 ÷ # × [0.3] WATCH (ID) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] -× 231A × 0308 × 0022 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM) × [19.01] QUOTATION MARK (QU) ÷ [0.3] -× 231A × 0308 × 0020 ÷ 0022 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] +× 231A × 0308 × 0022 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM1_CM) × [19.01] QUOTATION MARK (QU) ÷ [0.3] +× 231A × 0308 × 0020 ÷ 0022 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] × 231A × 0020 ÷ # × [0.3] WATCH (ID) × [7.01] SPACE (SP) ÷ [0.3] × 231A × 0020 × 0020 ÷ # × [0.3] WATCH (ID) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] -× 231A × 0308 × 0020 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [0.3] -× 231A × 0308 × 0020 × 0020 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] +× 231A × 0308 × 0020 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [0.3] +× 231A × 0308 × 0020 × 0020 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] × 231A × 002F ÷ # × [0.3] WATCH (ID) × [13.02] SOLIDUS (SY) ÷ [0.3] × 231A × 0020 × 002F ÷ # × [0.3] WATCH (ID) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] -× 231A × 0308 × 002F ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM) × [13.03] SOLIDUS (SY) ÷ [0.3] -× 231A × 0308 × 0020 × 002F ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] +× 231A × 0308 × 002F ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] SOLIDUS (SY) ÷ [0.3] +× 231A × 0308 × 0020 × 002F ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] × 231A × 2060 ÷ # × [0.3] WATCH (ID) × [11.01] WORD JOINER (WJ) ÷ [0.3] × 231A × 0020 × 2060 ÷ # × [0.3] WATCH (ID) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] -× 231A × 0308 × 2060 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM) × [11.01] WORD JOINER (WJ) ÷ [0.3] -× 231A × 0308 × 0020 × 2060 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] +× 231A × 0308 × 2060 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM1_CM) × [11.01] WORD JOINER (WJ) ÷ [0.3] +× 231A × 0308 × 0020 × 2060 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] × 231A × 200B ÷ # × [0.3] WATCH (ID) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] × 231A × 0020 × 200B ÷ # × [0.3] WATCH (ID) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] -× 231A × 0308 × 200B ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] -× 231A × 0308 × 0020 × 200B ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] +× 231A × 0308 × 200B ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] +× 231A × 0308 × 0020 × 200B ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] × 231A ÷ 1F1E6 ÷ # × [0.3] WATCH (ID) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] × 231A × 0020 ÷ 1F1E6 ÷ # × [0.3] WATCH (ID) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -× 231A × 0308 ÷ 1F1E6 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -× 231A × 0308 × 0020 ÷ 1F1E6 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 231A × 0308 ÷ 1F1E6 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 231A × 0308 × 0020 ÷ 1F1E6 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 231A ÷ 261D ÷ # × [0.3] WATCH (ID) ÷ [999.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 231A × 0020 ÷ 261D ÷ # × [0.3] WATCH (ID) × [7.01] SPACE (SP) ÷ [18.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 231A × 0308 ÷ 261D ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 231A × 0308 × 0020 ÷ 261D ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 231A ÷ 1F3FB ÷ # × [0.3] WATCH (ID) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 231A × 0020 ÷ 1F3FB ÷ # × [0.3] WATCH (ID) × [7.01] SPACE (SP) ÷ [18.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 231A × 0308 ÷ 1F3FB ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 231A × 0308 × 0020 ÷ 1F3FB ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 231A × 0001 ÷ # × [0.3] WATCH (ID) × [9.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 231A × 0020 ÷ 0001 ÷ # × [0.3] WATCH (ID) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 231A × 0308 × 0001 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM1_CM) × [9.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 231A × 0308 × 0020 ÷ 0001 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 231A × 200D ÷ # × [0.3] WATCH (ID) × [9.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 231A × 0020 ÷ 200D ÷ # × [0.3] WATCH (ID) × [7.01] SPACE (SP) ÷ [18.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 231A × 0308 × 200D ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM1_CM) × [9.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 231A × 0308 × 0020 ÷ 200D ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] × 231A ÷ 00A7 ÷ # × [0.3] WATCH (ID) ÷ [999.0] SECTION SIGN (AI_AL) ÷ [0.3] × 231A × 0020 ÷ 00A7 ÷ # × [0.3] WATCH (ID) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] -× 231A × 0308 ÷ 00A7 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] SECTION SIGN (AI_AL) ÷ [0.3] -× 231A × 0308 × 0020 ÷ 00A7 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] +× 231A × 0308 ÷ 00A7 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] SECTION SIGN (AI_AL) ÷ [0.3] +× 231A × 0308 × 0020 ÷ 00A7 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] × 231A ÷ 50005 ÷ # × [0.3] WATCH (ID) ÷ [999.0] <reserved-50005> (XX_AL) ÷ [0.3] × 231A × 0020 ÷ 50005 ÷ # × [0.3] WATCH (ID) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] -× 231A × 0308 ÷ 50005 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] <reserved-50005> (XX_AL) ÷ [0.3] -× 231A × 0308 × 0020 ÷ 50005 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] +× 231A × 0308 ÷ 50005 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] <reserved-50005> (XX_AL) ÷ [0.3] +× 231A × 0308 × 0020 ÷ 50005 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] × 231A ÷ 0E01 ÷ # × [0.3] WATCH (ID) ÷ [999.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] × 231A × 0020 ÷ 0E01 ÷ # × [0.3] WATCH (ID) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] -× 231A × 0308 ÷ 0E01 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] -× 231A × 0308 × 0020 ÷ 0E01 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] +× 231A × 0308 ÷ 0E01 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] +× 231A × 0308 × 0020 ÷ 0E01 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] × 231A × 3041 ÷ # × [0.3] WATCH (ID) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] × 231A × 0020 ÷ 3041 ÷ # × [0.3] WATCH (ID) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] -× 231A × 0308 × 3041 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] -× 231A × 0308 × 0020 ÷ 3041 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] +× 231A × 0308 × 3041 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] +× 231A × 0308 × 0020 ÷ 3041 ÷ # × [0.3] WATCH (ID) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] × 2024 ÷ 0023 ÷ # × [0.3] ONE DOT LEADER (IN) ÷ [999.0] NUMBER SIGN (AL) ÷ [0.3] × 2024 × 0020 ÷ 0023 ÷ # × [0.3] ONE DOT LEADER (IN) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] -× 2024 × 0308 ÷ 0023 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] NUMBER SIGN (AL) ÷ [0.3] -× 2024 × 0308 × 0020 ÷ 0023 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] +× 2024 × 0308 ÷ 0023 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] NUMBER SIGN (AL) ÷ [0.3] +× 2024 × 0308 × 0020 ÷ 0023 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] × 2024 ÷ 2014 ÷ # × [0.3] ONE DOT LEADER (IN) ÷ [999.0] EM DASH (B2) ÷ [0.3] × 2024 × 0020 ÷ 2014 ÷ # × [0.3] ONE DOT LEADER (IN) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] -× 2024 × 0308 ÷ 2014 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] EM DASH (B2) ÷ [0.3] -× 2024 × 0308 × 0020 ÷ 2014 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] +× 2024 × 0308 ÷ 2014 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] EM DASH (B2) ÷ [0.3] +× 2024 × 0308 × 0020 ÷ 2014 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] × 2024 × 0009 ÷ # × [0.3] ONE DOT LEADER (IN) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] × 2024 × 0020 ÷ 0009 ÷ # × [0.3] ONE DOT LEADER (IN) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] -× 2024 × 0308 × 0009 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] -× 2024 × 0308 × 0020 ÷ 0009 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] +× 2024 × 0308 × 0009 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] +× 2024 × 0308 × 0020 ÷ 0009 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] × 2024 ÷ 00B4 ÷ # × [0.3] ONE DOT LEADER (IN) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3] × 2024 × 0020 ÷ 00B4 ÷ # × [0.3] ONE DOT LEADER (IN) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] -× 2024 × 0308 ÷ 00B4 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3] -× 2024 × 0308 × 0020 ÷ 00B4 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] +× 2024 × 0308 ÷ 00B4 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3] +× 2024 × 0308 × 0020 ÷ 00B4 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] × 2024 × 000B ÷ # × [0.3] ONE DOT LEADER (IN) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] × 2024 × 0020 × 000B ÷ # × [0.3] ONE DOT LEADER (IN) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] -× 2024 × 0308 × 000B ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] -× 2024 × 0308 × 0020 × 000B ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] +× 2024 × 0308 × 000B ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] +× 2024 × 0308 × 0020 × 000B ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] × 2024 ÷ FFFC ÷ # × [0.3] ONE DOT LEADER (IN) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] × 2024 × 0020 ÷ FFFC ÷ # × [0.3] ONE DOT LEADER (IN) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] -× 2024 × 0308 ÷ FFFC ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] -× 2024 × 0308 × 0020 ÷ FFFC ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] +× 2024 × 0308 ÷ FFFC ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] +× 2024 × 0308 × 0020 ÷ FFFC ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] × 2024 × 007D ÷ # × [0.3] ONE DOT LEADER (IN) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] × 2024 × 0020 × 007D ÷ # × [0.3] ONE DOT LEADER (IN) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] -× 2024 × 0308 × 007D ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM) × [13.03] RIGHT CURLY BRACKET (CL) ÷ [0.3] -× 2024 × 0308 × 0020 × 007D ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] +× 2024 × 0308 × 007D ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] RIGHT CURLY BRACKET (CL) ÷ [0.3] +× 2024 × 0308 × 0020 × 007D ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] × 2024 × 0029 ÷ # × [0.3] ONE DOT LEADER (IN) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] × 2024 × 0020 × 0029 ÷ # × [0.3] ONE DOT LEADER (IN) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 2024 × 0308 × 0029 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM) × [13.03] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 2024 × 0308 × 0020 × 0029 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 2024 × 0001 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] <START OF HEADING> (CM) ÷ [0.3] -× 2024 × 0020 ÷ 0001 ÷ # × [0.3] ONE DOT LEADER (IN) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM) ÷ [0.3] -× 2024 × 0308 × 0001 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM) × [9.0] <START OF HEADING> (CM) ÷ [0.3] -× 2024 × 0308 × 0020 ÷ 0001 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM) ÷ [0.3] +× 2024 × 0308 × 0029 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] RIGHT PARENTHESIS (CP) ÷ [0.3] +× 2024 × 0308 × 0020 × 0029 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] × 2024 × 000D ÷ # × [0.3] ONE DOT LEADER (IN) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] × 2024 × 0020 × 000D ÷ # × [0.3] ONE DOT LEADER (IN) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -× 2024 × 0308 × 000D ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -× 2024 × 0308 × 0020 × 000D ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +× 2024 × 0308 × 000D ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +× 2024 × 0308 × 0020 × 000D ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] × 2024 × 0021 ÷ # × [0.3] ONE DOT LEADER (IN) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] × 2024 × 0020 × 0021 ÷ # × [0.3] ONE DOT LEADER (IN) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] -× 2024 × 0308 × 0021 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] -× 2024 × 0308 × 0020 × 0021 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] +× 2024 × 0308 × 0021 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] +× 2024 × 0308 × 0020 × 0021 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] × 2024 × 00A0 ÷ # × [0.3] ONE DOT LEADER (IN) × [12.1] NO-BREAK SPACE (GL) ÷ [0.3] × 2024 × 0020 ÷ 00A0 ÷ # × [0.3] ONE DOT LEADER (IN) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] -× 2024 × 0308 × 00A0 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM) × [12.2] NO-BREAK SPACE (GL) ÷ [0.3] -× 2024 × 0308 × 0020 ÷ 00A0 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] +× 2024 × 0308 × 00A0 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM1_CM) × [12.2] NO-BREAK SPACE (GL) ÷ [0.3] +× 2024 × 0308 × 0020 ÷ 00A0 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] × 2024 ÷ AC00 ÷ # × [0.3] ONE DOT LEADER (IN) ÷ [999.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] × 2024 × 0020 ÷ AC00 ÷ # × [0.3] ONE DOT LEADER (IN) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] -× 2024 × 0308 ÷ AC00 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] -× 2024 × 0308 × 0020 ÷ AC00 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] +× 2024 × 0308 ÷ AC00 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] +× 2024 × 0308 × 0020 ÷ AC00 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] × 2024 ÷ AC01 ÷ # × [0.3] ONE DOT LEADER (IN) ÷ [999.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] × 2024 × 0020 ÷ AC01 ÷ # × [0.3] ONE DOT LEADER (IN) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] -× 2024 × 0308 ÷ AC01 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] -× 2024 × 0308 × 0020 ÷ AC01 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] +× 2024 × 0308 ÷ AC01 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] +× 2024 × 0308 × 0020 ÷ AC01 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] × 2024 ÷ 05D0 ÷ # × [0.3] ONE DOT LEADER (IN) ÷ [999.0] HEBREW LETTER ALEF (HL) ÷ [0.3] × 2024 × 0020 ÷ 05D0 ÷ # × [0.3] ONE DOT LEADER (IN) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] -× 2024 × 0308 ÷ 05D0 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HEBREW LETTER ALEF (HL) ÷ [0.3] -× 2024 × 0308 × 0020 ÷ 05D0 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] +× 2024 × 0308 ÷ 05D0 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HEBREW LETTER ALEF (HL) ÷ [0.3] +× 2024 × 0308 × 0020 ÷ 05D0 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] × 2024 × 002D ÷ # × [0.3] ONE DOT LEADER (IN) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] × 2024 × 0020 ÷ 002D ÷ # × [0.3] ONE DOT LEADER (IN) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] -× 2024 × 0308 × 002D ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] -× 2024 × 0308 × 0020 ÷ 002D ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] +× 2024 × 0308 × 002D ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] +× 2024 × 0308 × 0020 ÷ 002D ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] × 2024 ÷ 231A ÷ # × [0.3] ONE DOT LEADER (IN) ÷ [999.0] WATCH (ID) ÷ [0.3] × 2024 × 0020 ÷ 231A ÷ # × [0.3] ONE DOT LEADER (IN) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] -× 2024 × 0308 ÷ 231A ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] WATCH (ID) ÷ [0.3] -× 2024 × 0308 × 0020 ÷ 231A ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] +× 2024 × 0308 ÷ 231A ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] WATCH (ID) ÷ [0.3] +× 2024 × 0308 × 0020 ÷ 231A ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] × 2024 × 2024 ÷ # × [0.3] ONE DOT LEADER (IN) × [22.04] ONE DOT LEADER (IN) ÷ [0.3] × 2024 × 0020 ÷ 2024 ÷ # × [0.3] ONE DOT LEADER (IN) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] -× 2024 × 0308 × 2024 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM) × [22.04] ONE DOT LEADER (IN) ÷ [0.3] -× 2024 × 0308 × 0020 ÷ 2024 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] +× 2024 × 0308 × 2024 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM1_CM) × [22.04] ONE DOT LEADER (IN) ÷ [0.3] +× 2024 × 0308 × 0020 ÷ 2024 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] × 2024 × 002C ÷ # × [0.3] ONE DOT LEADER (IN) × [13.02] COMMA (IS) ÷ [0.3] × 2024 × 0020 × 002C ÷ # × [0.3] ONE DOT LEADER (IN) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] -× 2024 × 0308 × 002C ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM) × [13.03] COMMA (IS) ÷ [0.3] -× 2024 × 0308 × 0020 × 002C ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] +× 2024 × 0308 × 002C ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] COMMA (IS) ÷ [0.3] +× 2024 × 0308 × 0020 × 002C ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] × 2024 ÷ 1100 ÷ # × [0.3] ONE DOT LEADER (IN) ÷ [999.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] × 2024 × 0020 ÷ 1100 ÷ # × [0.3] ONE DOT LEADER (IN) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] -× 2024 × 0308 ÷ 1100 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] -× 2024 × 0308 × 0020 ÷ 1100 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] +× 2024 × 0308 ÷ 1100 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] +× 2024 × 0308 × 0020 ÷ 1100 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] × 2024 ÷ 11A8 ÷ # × [0.3] ONE DOT LEADER (IN) ÷ [999.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] × 2024 × 0020 ÷ 11A8 ÷ # × [0.3] ONE DOT LEADER (IN) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] -× 2024 × 0308 ÷ 11A8 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] -× 2024 × 0308 × 0020 ÷ 11A8 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] +× 2024 × 0308 ÷ 11A8 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] +× 2024 × 0308 × 0020 ÷ 11A8 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] × 2024 ÷ 1160 ÷ # × [0.3] ONE DOT LEADER (IN) ÷ [999.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] × 2024 × 0020 ÷ 1160 ÷ # × [0.3] ONE DOT LEADER (IN) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] -× 2024 × 0308 ÷ 1160 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] -× 2024 × 0308 × 0020 ÷ 1160 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] +× 2024 × 0308 ÷ 1160 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] +× 2024 × 0308 × 0020 ÷ 1160 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] × 2024 × 000A ÷ # × [0.3] ONE DOT LEADER (IN) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] × 2024 × 0020 × 000A ÷ # × [0.3] ONE DOT LEADER (IN) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] -× 2024 × 0308 × 000A ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] -× 2024 × 0308 × 0020 × 000A ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] +× 2024 × 0308 × 000A ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] +× 2024 × 0308 × 0020 × 000A ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] × 2024 × 0085 ÷ # × [0.3] ONE DOT LEADER (IN) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] × 2024 × 0020 × 0085 ÷ # × [0.3] ONE DOT LEADER (IN) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] -× 2024 × 0308 × 0085 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] -× 2024 × 0308 × 0020 × 0085 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] +× 2024 × 0308 × 0085 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] +× 2024 × 0308 × 0020 × 0085 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] × 2024 × 17D6 ÷ # × [0.3] ONE DOT LEADER (IN) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] × 2024 × 0020 ÷ 17D6 ÷ # × [0.3] ONE DOT LEADER (IN) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] -× 2024 × 0308 × 17D6 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] -× 2024 × 0308 × 0020 ÷ 17D6 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] +× 2024 × 0308 × 17D6 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] +× 2024 × 0308 × 0020 ÷ 17D6 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] × 2024 ÷ 0030 ÷ # × [0.3] ONE DOT LEADER (IN) ÷ [999.0] DIGIT ZERO (NU) ÷ [0.3] × 2024 × 0020 ÷ 0030 ÷ # × [0.3] ONE DOT LEADER (IN) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] -× 2024 × 0308 ÷ 0030 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] DIGIT ZERO (NU) ÷ [0.3] -× 2024 × 0308 × 0020 ÷ 0030 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] +× 2024 × 0308 ÷ 0030 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] DIGIT ZERO (NU) ÷ [0.3] +× 2024 × 0308 × 0020 ÷ 0030 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] × 2024 ÷ 0028 ÷ # × [0.3] ONE DOT LEADER (IN) ÷ [999.0] LEFT PARENTHESIS (OP) ÷ [0.3] × 2024 × 0020 ÷ 0028 ÷ # × [0.3] ONE DOT LEADER (IN) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] -× 2024 × 0308 ÷ 0028 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] LEFT PARENTHESIS (OP) ÷ [0.3] -× 2024 × 0308 × 0020 ÷ 0028 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] +× 2024 × 0308 ÷ 0028 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] LEFT PARENTHESIS (OP) ÷ [0.3] +× 2024 × 0308 × 0020 ÷ 0028 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] × 2024 ÷ 0025 ÷ # × [0.3] ONE DOT LEADER (IN) ÷ [999.0] PERCENT SIGN (PO) ÷ [0.3] × 2024 × 0020 ÷ 0025 ÷ # × [0.3] ONE DOT LEADER (IN) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] -× 2024 × 0308 ÷ 0025 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] PERCENT SIGN (PO) ÷ [0.3] -× 2024 × 0308 × 0020 ÷ 0025 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] +× 2024 × 0308 ÷ 0025 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] PERCENT SIGN (PO) ÷ [0.3] +× 2024 × 0308 × 0020 ÷ 0025 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] × 2024 ÷ 0024 ÷ # × [0.3] ONE DOT LEADER (IN) ÷ [999.0] DOLLAR SIGN (PR) ÷ [0.3] × 2024 × 0020 ÷ 0024 ÷ # × [0.3] ONE DOT LEADER (IN) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] -× 2024 × 0308 ÷ 0024 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] DOLLAR SIGN (PR) ÷ [0.3] -× 2024 × 0308 × 0020 ÷ 0024 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] +× 2024 × 0308 ÷ 0024 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] DOLLAR SIGN (PR) ÷ [0.3] +× 2024 × 0308 × 0020 ÷ 0024 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] × 2024 × 0022 ÷ # × [0.3] ONE DOT LEADER (IN) × [19.01] QUOTATION MARK (QU) ÷ [0.3] × 2024 × 0020 ÷ 0022 ÷ # × [0.3] ONE DOT LEADER (IN) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] -× 2024 × 0308 × 0022 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM) × [19.01] QUOTATION MARK (QU) ÷ [0.3] -× 2024 × 0308 × 0020 ÷ 0022 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] +× 2024 × 0308 × 0022 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM1_CM) × [19.01] QUOTATION MARK (QU) ÷ [0.3] +× 2024 × 0308 × 0020 ÷ 0022 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] × 2024 × 0020 ÷ # × [0.3] ONE DOT LEADER (IN) × [7.01] SPACE (SP) ÷ [0.3] × 2024 × 0020 × 0020 ÷ # × [0.3] ONE DOT LEADER (IN) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] -× 2024 × 0308 × 0020 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [0.3] -× 2024 × 0308 × 0020 × 0020 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] +× 2024 × 0308 × 0020 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [0.3] +× 2024 × 0308 × 0020 × 0020 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] × 2024 × 002F ÷ # × [0.3] ONE DOT LEADER (IN) × [13.02] SOLIDUS (SY) ÷ [0.3] × 2024 × 0020 × 002F ÷ # × [0.3] ONE DOT LEADER (IN) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] -× 2024 × 0308 × 002F ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM) × [13.03] SOLIDUS (SY) ÷ [0.3] -× 2024 × 0308 × 0020 × 002F ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] +× 2024 × 0308 × 002F ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] SOLIDUS (SY) ÷ [0.3] +× 2024 × 0308 × 0020 × 002F ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] × 2024 × 2060 ÷ # × [0.3] ONE DOT LEADER (IN) × [11.01] WORD JOINER (WJ) ÷ [0.3] × 2024 × 0020 × 2060 ÷ # × [0.3] ONE DOT LEADER (IN) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] -× 2024 × 0308 × 2060 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM) × [11.01] WORD JOINER (WJ) ÷ [0.3] -× 2024 × 0308 × 0020 × 2060 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] +× 2024 × 0308 × 2060 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM1_CM) × [11.01] WORD JOINER (WJ) ÷ [0.3] +× 2024 × 0308 × 0020 × 2060 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] × 2024 × 200B ÷ # × [0.3] ONE DOT LEADER (IN) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] × 2024 × 0020 × 200B ÷ # × [0.3] ONE DOT LEADER (IN) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] -× 2024 × 0308 × 200B ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] -× 2024 × 0308 × 0020 × 200B ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] +× 2024 × 0308 × 200B ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] +× 2024 × 0308 × 0020 × 200B ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] × 2024 ÷ 1F1E6 ÷ # × [0.3] ONE DOT LEADER (IN) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] × 2024 × 0020 ÷ 1F1E6 ÷ # × [0.3] ONE DOT LEADER (IN) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -× 2024 × 0308 ÷ 1F1E6 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -× 2024 × 0308 × 0020 ÷ 1F1E6 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 2024 × 0308 ÷ 1F1E6 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 2024 × 0308 × 0020 ÷ 1F1E6 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 2024 ÷ 261D ÷ # × [0.3] ONE DOT LEADER (IN) ÷ [999.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 2024 × 0020 ÷ 261D ÷ # × [0.3] ONE DOT LEADER (IN) × [7.01] SPACE (SP) ÷ [18.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 2024 × 0308 ÷ 261D ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 2024 × 0308 × 0020 ÷ 261D ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 2024 ÷ 1F3FB ÷ # × [0.3] ONE DOT LEADER (IN) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 2024 × 0020 ÷ 1F3FB ÷ # × [0.3] ONE DOT LEADER (IN) × [7.01] SPACE (SP) ÷ [18.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 2024 × 0308 ÷ 1F3FB ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 2024 × 0308 × 0020 ÷ 1F3FB ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 2024 × 0001 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 2024 × 0020 ÷ 0001 ÷ # × [0.3] ONE DOT LEADER (IN) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 2024 × 0308 × 0001 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM1_CM) × [9.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 2024 × 0308 × 0020 ÷ 0001 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 2024 × 200D ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 2024 × 0020 ÷ 200D ÷ # × [0.3] ONE DOT LEADER (IN) × [7.01] SPACE (SP) ÷ [18.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 2024 × 0308 × 200D ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM1_CM) × [9.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 2024 × 0308 × 0020 ÷ 200D ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] × 2024 ÷ 00A7 ÷ # × [0.3] ONE DOT LEADER (IN) ÷ [999.0] SECTION SIGN (AI_AL) ÷ [0.3] × 2024 × 0020 ÷ 00A7 ÷ # × [0.3] ONE DOT LEADER (IN) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] -× 2024 × 0308 ÷ 00A7 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] SECTION SIGN (AI_AL) ÷ [0.3] -× 2024 × 0308 × 0020 ÷ 00A7 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] +× 2024 × 0308 ÷ 00A7 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] SECTION SIGN (AI_AL) ÷ [0.3] +× 2024 × 0308 × 0020 ÷ 00A7 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] × 2024 ÷ 50005 ÷ # × [0.3] ONE DOT LEADER (IN) ÷ [999.0] <reserved-50005> (XX_AL) ÷ [0.3] × 2024 × 0020 ÷ 50005 ÷ # × [0.3] ONE DOT LEADER (IN) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] -× 2024 × 0308 ÷ 50005 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] <reserved-50005> (XX_AL) ÷ [0.3] -× 2024 × 0308 × 0020 ÷ 50005 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] +× 2024 × 0308 ÷ 50005 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] <reserved-50005> (XX_AL) ÷ [0.3] +× 2024 × 0308 × 0020 ÷ 50005 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] × 2024 ÷ 0E01 ÷ # × [0.3] ONE DOT LEADER (IN) ÷ [999.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] × 2024 × 0020 ÷ 0E01 ÷ # × [0.3] ONE DOT LEADER (IN) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] -× 2024 × 0308 ÷ 0E01 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] -× 2024 × 0308 × 0020 ÷ 0E01 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] +× 2024 × 0308 ÷ 0E01 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] +× 2024 × 0308 × 0020 ÷ 0E01 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] × 2024 × 3041 ÷ # × [0.3] ONE DOT LEADER (IN) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] × 2024 × 0020 ÷ 3041 ÷ # × [0.3] ONE DOT LEADER (IN) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] -× 2024 × 0308 × 3041 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] -× 2024 × 0308 × 0020 ÷ 3041 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] +× 2024 × 0308 × 3041 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] +× 2024 × 0308 × 0020 ÷ 3041 ÷ # × [0.3] ONE DOT LEADER (IN) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] × 002C × 0023 ÷ # × [0.3] COMMA (IS) × [29.0] NUMBER SIGN (AL) ÷ [0.3] × 002C × 0020 ÷ 0023 ÷ # × [0.3] COMMA (IS) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] -× 002C × 0308 × 0023 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM) × [29.0] NUMBER SIGN (AL) ÷ [0.3] -× 002C × 0308 × 0020 ÷ 0023 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] +× 002C × 0308 × 0023 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [29.0] NUMBER SIGN (AL) ÷ [0.3] +× 002C × 0308 × 0020 ÷ 0023 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] × 002C ÷ 2014 ÷ # × [0.3] COMMA (IS) ÷ [999.0] EM DASH (B2) ÷ [0.3] × 002C × 0020 ÷ 2014 ÷ # × [0.3] COMMA (IS) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] -× 002C × 0308 ÷ 2014 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] EM DASH (B2) ÷ [0.3] -× 002C × 0308 × 0020 ÷ 2014 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] +× 002C × 0308 ÷ 2014 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] EM DASH (B2) ÷ [0.3] +× 002C × 0308 × 0020 ÷ 2014 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] × 002C × 0009 ÷ # × [0.3] COMMA (IS) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] × 002C × 0020 ÷ 0009 ÷ # × [0.3] COMMA (IS) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] -× 002C × 0308 × 0009 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] -× 002C × 0308 × 0020 ÷ 0009 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] +× 002C × 0308 × 0009 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] +× 002C × 0308 × 0020 ÷ 0009 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] × 002C ÷ 00B4 ÷ # × [0.3] COMMA (IS) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3] × 002C × 0020 ÷ 00B4 ÷ # × [0.3] COMMA (IS) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] -× 002C × 0308 ÷ 00B4 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3] -× 002C × 0308 × 0020 ÷ 00B4 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] +× 002C × 0308 ÷ 00B4 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3] +× 002C × 0308 × 0020 ÷ 00B4 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] × 002C × 000B ÷ # × [0.3] COMMA (IS) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] × 002C × 0020 × 000B ÷ # × [0.3] COMMA (IS) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] -× 002C × 0308 × 000B ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] -× 002C × 0308 × 0020 × 000B ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] +× 002C × 0308 × 000B ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] +× 002C × 0308 × 0020 × 000B ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] × 002C ÷ FFFC ÷ # × [0.3] COMMA (IS) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] × 002C × 0020 ÷ FFFC ÷ # × [0.3] COMMA (IS) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] -× 002C × 0308 ÷ FFFC ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] -× 002C × 0308 × 0020 ÷ FFFC ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] +× 002C × 0308 ÷ FFFC ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] +× 002C × 0308 × 0020 ÷ FFFC ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] × 002C × 007D ÷ # × [0.3] COMMA (IS) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] × 002C × 0020 × 007D ÷ # × [0.3] COMMA (IS) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] -× 002C × 0308 × 007D ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM) × [13.03] RIGHT CURLY BRACKET (CL) ÷ [0.3] -× 002C × 0308 × 0020 × 007D ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] +× 002C × 0308 × 007D ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] RIGHT CURLY BRACKET (CL) ÷ [0.3] +× 002C × 0308 × 0020 × 007D ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] × 002C × 0029 ÷ # × [0.3] COMMA (IS) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] × 002C × 0020 × 0029 ÷ # × [0.3] COMMA (IS) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 002C × 0308 × 0029 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM) × [13.03] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 002C × 0308 × 0020 × 0029 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 002C × 0001 ÷ # × [0.3] COMMA (IS) × [9.0] <START OF HEADING> (CM) ÷ [0.3] -× 002C × 0020 ÷ 0001 ÷ # × [0.3] COMMA (IS) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM) ÷ [0.3] -× 002C × 0308 × 0001 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM) × [9.0] <START OF HEADING> (CM) ÷ [0.3] -× 002C × 0308 × 0020 ÷ 0001 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM) ÷ [0.3] +× 002C × 0308 × 0029 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] RIGHT PARENTHESIS (CP) ÷ [0.3] +× 002C × 0308 × 0020 × 0029 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] × 002C × 000D ÷ # × [0.3] COMMA (IS) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] × 002C × 0020 × 000D ÷ # × [0.3] COMMA (IS) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -× 002C × 0308 × 000D ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -× 002C × 0308 × 0020 × 000D ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +× 002C × 0308 × 000D ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +× 002C × 0308 × 0020 × 000D ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] × 002C × 0021 ÷ # × [0.3] COMMA (IS) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] × 002C × 0020 × 0021 ÷ # × [0.3] COMMA (IS) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] -× 002C × 0308 × 0021 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] -× 002C × 0308 × 0020 × 0021 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] +× 002C × 0308 × 0021 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] +× 002C × 0308 × 0020 × 0021 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] × 002C × 00A0 ÷ # × [0.3] COMMA (IS) × [12.1] NO-BREAK SPACE (GL) ÷ [0.3] × 002C × 0020 ÷ 00A0 ÷ # × [0.3] COMMA (IS) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] -× 002C × 0308 × 00A0 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM) × [12.2] NO-BREAK SPACE (GL) ÷ [0.3] -× 002C × 0308 × 0020 ÷ 00A0 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] +× 002C × 0308 × 00A0 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [12.2] NO-BREAK SPACE (GL) ÷ [0.3] +× 002C × 0308 × 0020 ÷ 00A0 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] × 002C ÷ AC00 ÷ # × [0.3] COMMA (IS) ÷ [999.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] × 002C × 0020 ÷ AC00 ÷ # × [0.3] COMMA (IS) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] -× 002C × 0308 ÷ AC00 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] -× 002C × 0308 × 0020 ÷ AC00 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] +× 002C × 0308 ÷ AC00 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] +× 002C × 0308 × 0020 ÷ AC00 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] × 002C ÷ AC01 ÷ # × [0.3] COMMA (IS) ÷ [999.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] × 002C × 0020 ÷ AC01 ÷ # × [0.3] COMMA (IS) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] -× 002C × 0308 ÷ AC01 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] -× 002C × 0308 × 0020 ÷ AC01 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] +× 002C × 0308 ÷ AC01 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] +× 002C × 0308 × 0020 ÷ AC01 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] × 002C × 05D0 ÷ # × [0.3] COMMA (IS) × [29.0] HEBREW LETTER ALEF (HL) ÷ [0.3] × 002C × 0020 ÷ 05D0 ÷ # × [0.3] COMMA (IS) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] -× 002C × 0308 × 05D0 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM) × [29.0] HEBREW LETTER ALEF (HL) ÷ [0.3] -× 002C × 0308 × 0020 ÷ 05D0 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] +× 002C × 0308 × 05D0 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [29.0] HEBREW LETTER ALEF (HL) ÷ [0.3] +× 002C × 0308 × 0020 ÷ 05D0 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] × 002C × 002D ÷ # × [0.3] COMMA (IS) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] × 002C × 0020 ÷ 002D ÷ # × [0.3] COMMA (IS) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] -× 002C × 0308 × 002D ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] -× 002C × 0308 × 0020 ÷ 002D ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] +× 002C × 0308 × 002D ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] +× 002C × 0308 × 0020 ÷ 002D ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] × 002C ÷ 231A ÷ # × [0.3] COMMA (IS) ÷ [999.0] WATCH (ID) ÷ [0.3] × 002C × 0020 ÷ 231A ÷ # × [0.3] COMMA (IS) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] -× 002C × 0308 ÷ 231A ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] WATCH (ID) ÷ [0.3] -× 002C × 0308 × 0020 ÷ 231A ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] +× 002C × 0308 ÷ 231A ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] WATCH (ID) ÷ [0.3] +× 002C × 0308 × 0020 ÷ 231A ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] × 002C ÷ 2024 ÷ # × [0.3] COMMA (IS) ÷ [999.0] ONE DOT LEADER (IN) ÷ [0.3] × 002C × 0020 ÷ 2024 ÷ # × [0.3] COMMA (IS) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] -× 002C × 0308 ÷ 2024 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] ONE DOT LEADER (IN) ÷ [0.3] -× 002C × 0308 × 0020 ÷ 2024 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] +× 002C × 0308 ÷ 2024 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] ONE DOT LEADER (IN) ÷ [0.3] +× 002C × 0308 × 0020 ÷ 2024 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] × 002C × 002C ÷ # × [0.3] COMMA (IS) × [13.02] COMMA (IS) ÷ [0.3] × 002C × 0020 × 002C ÷ # × [0.3] COMMA (IS) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] -× 002C × 0308 × 002C ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM) × [13.03] COMMA (IS) ÷ [0.3] -× 002C × 0308 × 0020 × 002C ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] +× 002C × 0308 × 002C ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] COMMA (IS) ÷ [0.3] +× 002C × 0308 × 0020 × 002C ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] × 002C ÷ 1100 ÷ # × [0.3] COMMA (IS) ÷ [999.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] × 002C × 0020 ÷ 1100 ÷ # × [0.3] COMMA (IS) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] -× 002C × 0308 ÷ 1100 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] -× 002C × 0308 × 0020 ÷ 1100 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] +× 002C × 0308 ÷ 1100 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] +× 002C × 0308 × 0020 ÷ 1100 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] × 002C ÷ 11A8 ÷ # × [0.3] COMMA (IS) ÷ [999.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] × 002C × 0020 ÷ 11A8 ÷ # × [0.3] COMMA (IS) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] -× 002C × 0308 ÷ 11A8 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] -× 002C × 0308 × 0020 ÷ 11A8 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] +× 002C × 0308 ÷ 11A8 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] +× 002C × 0308 × 0020 ÷ 11A8 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] × 002C ÷ 1160 ÷ # × [0.3] COMMA (IS) ÷ [999.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] × 002C × 0020 ÷ 1160 ÷ # × [0.3] COMMA (IS) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] -× 002C × 0308 ÷ 1160 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] -× 002C × 0308 × 0020 ÷ 1160 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] +× 002C × 0308 ÷ 1160 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] +× 002C × 0308 × 0020 ÷ 1160 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] × 002C × 000A ÷ # × [0.3] COMMA (IS) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] × 002C × 0020 × 000A ÷ # × [0.3] COMMA (IS) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] -× 002C × 0308 × 000A ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] -× 002C × 0308 × 0020 × 000A ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] +× 002C × 0308 × 000A ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] +× 002C × 0308 × 0020 × 000A ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] × 002C × 0085 ÷ # × [0.3] COMMA (IS) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] × 002C × 0020 × 0085 ÷ # × [0.3] COMMA (IS) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] -× 002C × 0308 × 0085 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] -× 002C × 0308 × 0020 × 0085 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] +× 002C × 0308 × 0085 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] +× 002C × 0308 × 0020 × 0085 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] × 002C × 17D6 ÷ # × [0.3] COMMA (IS) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] × 002C × 0020 ÷ 17D6 ÷ # × [0.3] COMMA (IS) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] -× 002C × 0308 × 17D6 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] -× 002C × 0308 × 0020 ÷ 17D6 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] +× 002C × 0308 × 17D6 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] +× 002C × 0308 × 0020 ÷ 17D6 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] × 002C ÷ 0030 ÷ # × [0.3] COMMA (IS) ÷ [999.0] DIGIT ZERO (NU) ÷ [0.3] × 002C × 0020 ÷ 0030 ÷ # × [0.3] COMMA (IS) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] -× 002C × 0308 ÷ 0030 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] DIGIT ZERO (NU) ÷ [0.3] -× 002C × 0308 × 0020 ÷ 0030 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] +× 002C × 0308 ÷ 0030 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] DIGIT ZERO (NU) ÷ [0.3] +× 002C × 0308 × 0020 ÷ 0030 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] × 002C ÷ 0028 ÷ # × [0.3] COMMA (IS) ÷ [999.0] LEFT PARENTHESIS (OP) ÷ [0.3] × 002C × 0020 ÷ 0028 ÷ # × [0.3] COMMA (IS) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] -× 002C × 0308 ÷ 0028 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] LEFT PARENTHESIS (OP) ÷ [0.3] -× 002C × 0308 × 0020 ÷ 0028 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] +× 002C × 0308 ÷ 0028 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] LEFT PARENTHESIS (OP) ÷ [0.3] +× 002C × 0308 × 0020 ÷ 0028 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] × 002C ÷ 0025 ÷ # × [0.3] COMMA (IS) ÷ [999.0] PERCENT SIGN (PO) ÷ [0.3] × 002C × 0020 ÷ 0025 ÷ # × [0.3] COMMA (IS) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] -× 002C × 0308 ÷ 0025 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] PERCENT SIGN (PO) ÷ [0.3] -× 002C × 0308 × 0020 ÷ 0025 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] +× 002C × 0308 ÷ 0025 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] PERCENT SIGN (PO) ÷ [0.3] +× 002C × 0308 × 0020 ÷ 0025 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] × 002C ÷ 0024 ÷ # × [0.3] COMMA (IS) ÷ [999.0] DOLLAR SIGN (PR) ÷ [0.3] × 002C × 0020 ÷ 0024 ÷ # × [0.3] COMMA (IS) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] -× 002C × 0308 ÷ 0024 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] DOLLAR SIGN (PR) ÷ [0.3] -× 002C × 0308 × 0020 ÷ 0024 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] +× 002C × 0308 ÷ 0024 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] DOLLAR SIGN (PR) ÷ [0.3] +× 002C × 0308 × 0020 ÷ 0024 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] × 002C × 0022 ÷ # × [0.3] COMMA (IS) × [19.01] QUOTATION MARK (QU) ÷ [0.3] × 002C × 0020 ÷ 0022 ÷ # × [0.3] COMMA (IS) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] -× 002C × 0308 × 0022 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM) × [19.01] QUOTATION MARK (QU) ÷ [0.3] -× 002C × 0308 × 0020 ÷ 0022 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] +× 002C × 0308 × 0022 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [19.01] QUOTATION MARK (QU) ÷ [0.3] +× 002C × 0308 × 0020 ÷ 0022 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] × 002C × 0020 ÷ # × [0.3] COMMA (IS) × [7.01] SPACE (SP) ÷ [0.3] × 002C × 0020 × 0020 ÷ # × [0.3] COMMA (IS) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] -× 002C × 0308 × 0020 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [0.3] -× 002C × 0308 × 0020 × 0020 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] +× 002C × 0308 × 0020 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [0.3] +× 002C × 0308 × 0020 × 0020 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] × 002C × 002F ÷ # × [0.3] COMMA (IS) × [13.02] SOLIDUS (SY) ÷ [0.3] × 002C × 0020 × 002F ÷ # × [0.3] COMMA (IS) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] -× 002C × 0308 × 002F ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM) × [13.03] SOLIDUS (SY) ÷ [0.3] -× 002C × 0308 × 0020 × 002F ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] +× 002C × 0308 × 002F ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] SOLIDUS (SY) ÷ [0.3] +× 002C × 0308 × 0020 × 002F ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] × 002C × 2060 ÷ # × [0.3] COMMA (IS) × [11.01] WORD JOINER (WJ) ÷ [0.3] × 002C × 0020 × 2060 ÷ # × [0.3] COMMA (IS) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] -× 002C × 0308 × 2060 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM) × [11.01] WORD JOINER (WJ) ÷ [0.3] -× 002C × 0308 × 0020 × 2060 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] +× 002C × 0308 × 2060 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [11.01] WORD JOINER (WJ) ÷ [0.3] +× 002C × 0308 × 0020 × 2060 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] × 002C × 200B ÷ # × [0.3] COMMA (IS) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] × 002C × 0020 × 200B ÷ # × [0.3] COMMA (IS) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] -× 002C × 0308 × 200B ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] -× 002C × 0308 × 0020 × 200B ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] +× 002C × 0308 × 200B ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] +× 002C × 0308 × 0020 × 200B ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] × 002C ÷ 1F1E6 ÷ # × [0.3] COMMA (IS) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] × 002C × 0020 ÷ 1F1E6 ÷ # × [0.3] COMMA (IS) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -× 002C × 0308 ÷ 1F1E6 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -× 002C × 0308 × 0020 ÷ 1F1E6 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 002C × 0308 ÷ 1F1E6 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 002C × 0308 × 0020 ÷ 1F1E6 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 002C ÷ 261D ÷ # × [0.3] COMMA (IS) ÷ [999.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 002C × 0020 ÷ 261D ÷ # × [0.3] COMMA (IS) × [7.01] SPACE (SP) ÷ [18.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 002C × 0308 ÷ 261D ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 002C × 0308 × 0020 ÷ 261D ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 002C ÷ 1F3FB ÷ # × [0.3] COMMA (IS) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 002C × 0020 ÷ 1F3FB ÷ # × [0.3] COMMA (IS) × [7.01] SPACE (SP) ÷ [18.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 002C × 0308 ÷ 1F3FB ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 002C × 0308 × 0020 ÷ 1F3FB ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 002C × 0001 ÷ # × [0.3] COMMA (IS) × [9.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 002C × 0020 ÷ 0001 ÷ # × [0.3] COMMA (IS) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 002C × 0308 × 0001 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [9.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 002C × 0308 × 0020 ÷ 0001 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 002C × 200D ÷ # × [0.3] COMMA (IS) × [9.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 002C × 0020 ÷ 200D ÷ # × [0.3] COMMA (IS) × [7.01] SPACE (SP) ÷ [18.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 002C × 0308 × 200D ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [9.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 002C × 0308 × 0020 ÷ 200D ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] × 002C × 00A7 ÷ # × [0.3] COMMA (IS) × [29.0] SECTION SIGN (AI_AL) ÷ [0.3] × 002C × 0020 ÷ 00A7 ÷ # × [0.3] COMMA (IS) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] -× 002C × 0308 × 00A7 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM) × [29.0] SECTION SIGN (AI_AL) ÷ [0.3] -× 002C × 0308 × 0020 ÷ 00A7 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] +× 002C × 0308 × 00A7 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [29.0] SECTION SIGN (AI_AL) ÷ [0.3] +× 002C × 0308 × 0020 ÷ 00A7 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] × 002C × 50005 ÷ # × [0.3] COMMA (IS) × [29.0] <reserved-50005> (XX_AL) ÷ [0.3] × 002C × 0020 ÷ 50005 ÷ # × [0.3] COMMA (IS) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] -× 002C × 0308 × 50005 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM) × [29.0] <reserved-50005> (XX_AL) ÷ [0.3] -× 002C × 0308 × 0020 ÷ 50005 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] +× 002C × 0308 × 50005 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [29.0] <reserved-50005> (XX_AL) ÷ [0.3] +× 002C × 0308 × 0020 ÷ 50005 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] × 002C × 0E01 ÷ # × [0.3] COMMA (IS) × [29.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] × 002C × 0020 ÷ 0E01 ÷ # × [0.3] COMMA (IS) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] -× 002C × 0308 × 0E01 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM) × [29.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] -× 002C × 0308 × 0020 ÷ 0E01 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] +× 002C × 0308 × 0E01 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [29.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] +× 002C × 0308 × 0020 ÷ 0E01 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] × 002C × 3041 ÷ # × [0.3] COMMA (IS) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] × 002C × 0020 ÷ 3041 ÷ # × [0.3] COMMA (IS) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] -× 002C × 0308 × 3041 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] -× 002C × 0308 × 0020 ÷ 3041 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] +× 002C × 0308 × 3041 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] +× 002C × 0308 × 0020 ÷ 3041 ÷ # × [0.3] COMMA (IS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] × 1100 ÷ 0023 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) ÷ [999.0] NUMBER SIGN (AL) ÷ [0.3] × 1100 × 0020 ÷ 0023 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] -× 1100 × 0308 ÷ 0023 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] NUMBER SIGN (AL) ÷ [0.3] -× 1100 × 0308 × 0020 ÷ 0023 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] +× 1100 × 0308 ÷ 0023 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] NUMBER SIGN (AL) ÷ [0.3] +× 1100 × 0308 × 0020 ÷ 0023 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] × 1100 ÷ 2014 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) ÷ [999.0] EM DASH (B2) ÷ [0.3] × 1100 × 0020 ÷ 2014 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] -× 1100 × 0308 ÷ 2014 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] EM DASH (B2) ÷ [0.3] -× 1100 × 0308 × 0020 ÷ 2014 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] +× 1100 × 0308 ÷ 2014 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] EM DASH (B2) ÷ [0.3] +× 1100 × 0308 × 0020 ÷ 2014 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] × 1100 × 0009 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] × 1100 × 0020 ÷ 0009 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] -× 1100 × 0308 × 0009 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] -× 1100 × 0308 × 0020 ÷ 0009 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] +× 1100 × 0308 × 0009 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] +× 1100 × 0308 × 0020 ÷ 0009 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] × 1100 ÷ 00B4 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3] × 1100 × 0020 ÷ 00B4 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] -× 1100 × 0308 ÷ 00B4 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3] -× 1100 × 0308 × 0020 ÷ 00B4 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] +× 1100 × 0308 ÷ 00B4 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3] +× 1100 × 0308 × 0020 ÷ 00B4 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] × 1100 × 000B ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] × 1100 × 0020 × 000B ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] -× 1100 × 0308 × 000B ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] -× 1100 × 0308 × 0020 × 000B ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] +× 1100 × 0308 × 000B ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] +× 1100 × 0308 × 0020 × 000B ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] × 1100 ÷ FFFC ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] × 1100 × 0020 ÷ FFFC ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] -× 1100 × 0308 ÷ FFFC ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] -× 1100 × 0308 × 0020 ÷ FFFC ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] +× 1100 × 0308 ÷ FFFC ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] +× 1100 × 0308 × 0020 ÷ FFFC ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] × 1100 × 007D ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] × 1100 × 0020 × 007D ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] -× 1100 × 0308 × 007D ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM) × [13.03] RIGHT CURLY BRACKET (CL) ÷ [0.3] -× 1100 × 0308 × 0020 × 007D ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] +× 1100 × 0308 × 007D ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] RIGHT CURLY BRACKET (CL) ÷ [0.3] +× 1100 × 0308 × 0020 × 007D ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] × 1100 × 0029 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] × 1100 × 0020 × 0029 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 1100 × 0308 × 0029 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM) × [13.03] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 1100 × 0308 × 0020 × 0029 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 1100 × 0001 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] <START OF HEADING> (CM) ÷ [0.3] -× 1100 × 0020 ÷ 0001 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM) ÷ [0.3] -× 1100 × 0308 × 0001 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM) × [9.0] <START OF HEADING> (CM) ÷ [0.3] -× 1100 × 0308 × 0020 ÷ 0001 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM) ÷ [0.3] +× 1100 × 0308 × 0029 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] RIGHT PARENTHESIS (CP) ÷ [0.3] +× 1100 × 0308 × 0020 × 0029 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] × 1100 × 000D ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] × 1100 × 0020 × 000D ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -× 1100 × 0308 × 000D ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -× 1100 × 0308 × 0020 × 000D ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +× 1100 × 0308 × 000D ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +× 1100 × 0308 × 0020 × 000D ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] × 1100 × 0021 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] × 1100 × 0020 × 0021 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] -× 1100 × 0308 × 0021 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] -× 1100 × 0308 × 0020 × 0021 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] +× 1100 × 0308 × 0021 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] +× 1100 × 0308 × 0020 × 0021 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] × 1100 × 00A0 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [12.1] NO-BREAK SPACE (GL) ÷ [0.3] × 1100 × 0020 ÷ 00A0 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] -× 1100 × 0308 × 00A0 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM) × [12.2] NO-BREAK SPACE (GL) ÷ [0.3] -× 1100 × 0308 × 0020 ÷ 00A0 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] +× 1100 × 0308 × 00A0 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [12.2] NO-BREAK SPACE (GL) ÷ [0.3] +× 1100 × 0308 × 0020 ÷ 00A0 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] × 1100 × AC00 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [26.01] HANGUL SYLLABLE GA (H2) ÷ [0.3] × 1100 × 0020 ÷ AC00 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] -× 1100 × 0308 × AC00 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM) × [26.01] HANGUL SYLLABLE GA (H2) ÷ [0.3] -× 1100 × 0308 × 0020 ÷ AC00 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] +× 1100 × 0308 × AC00 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [26.01] HANGUL SYLLABLE GA (H2) ÷ [0.3] +× 1100 × 0308 × 0020 ÷ AC00 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] × 1100 × AC01 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [26.01] HANGUL SYLLABLE GAG (H3) ÷ [0.3] × 1100 × 0020 ÷ AC01 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] -× 1100 × 0308 × AC01 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM) × [26.01] HANGUL SYLLABLE GAG (H3) ÷ [0.3] -× 1100 × 0308 × 0020 ÷ AC01 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] +× 1100 × 0308 × AC01 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [26.01] HANGUL SYLLABLE GAG (H3) ÷ [0.3] +× 1100 × 0308 × 0020 ÷ AC01 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] × 1100 ÷ 05D0 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) ÷ [999.0] HEBREW LETTER ALEF (HL) ÷ [0.3] × 1100 × 0020 ÷ 05D0 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] -× 1100 × 0308 ÷ 05D0 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HEBREW LETTER ALEF (HL) ÷ [0.3] -× 1100 × 0308 × 0020 ÷ 05D0 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] +× 1100 × 0308 ÷ 05D0 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HEBREW LETTER ALEF (HL) ÷ [0.3] +× 1100 × 0308 × 0020 ÷ 05D0 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] × 1100 × 002D ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] × 1100 × 0020 ÷ 002D ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] -× 1100 × 0308 × 002D ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] -× 1100 × 0308 × 0020 ÷ 002D ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] +× 1100 × 0308 × 002D ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] +× 1100 × 0308 × 0020 ÷ 002D ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] × 1100 ÷ 231A ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) ÷ [999.0] WATCH (ID) ÷ [0.3] × 1100 × 0020 ÷ 231A ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] -× 1100 × 0308 ÷ 231A ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] WATCH (ID) ÷ [0.3] -× 1100 × 0308 × 0020 ÷ 231A ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] +× 1100 × 0308 ÷ 231A ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] WATCH (ID) ÷ [0.3] +× 1100 × 0308 × 0020 ÷ 231A ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] × 1100 × 2024 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [27.01] ONE DOT LEADER (IN) ÷ [0.3] × 1100 × 0020 ÷ 2024 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] -× 1100 × 0308 × 2024 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM) × [27.01] ONE DOT LEADER (IN) ÷ [0.3] -× 1100 × 0308 × 0020 ÷ 2024 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] +× 1100 × 0308 × 2024 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [27.01] ONE DOT LEADER (IN) ÷ [0.3] +× 1100 × 0308 × 0020 ÷ 2024 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] × 1100 × 002C ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [13.02] COMMA (IS) ÷ [0.3] × 1100 × 0020 × 002C ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] -× 1100 × 0308 × 002C ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM) × [13.03] COMMA (IS) ÷ [0.3] -× 1100 × 0308 × 0020 × 002C ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] +× 1100 × 0308 × 002C ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] COMMA (IS) ÷ [0.3] +× 1100 × 0308 × 0020 × 002C ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] × 1100 × 1100 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [26.01] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] × 1100 × 0020 ÷ 1100 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] -× 1100 × 0308 × 1100 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM) × [26.01] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] -× 1100 × 0308 × 0020 ÷ 1100 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] +× 1100 × 0308 × 1100 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [26.01] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] +× 1100 × 0308 × 0020 ÷ 1100 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] × 1100 ÷ 11A8 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) ÷ [999.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] × 1100 × 0020 ÷ 11A8 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] -× 1100 × 0308 ÷ 11A8 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] -× 1100 × 0308 × 0020 ÷ 11A8 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] +× 1100 × 0308 ÷ 11A8 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] +× 1100 × 0308 × 0020 ÷ 11A8 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] × 1100 × 1160 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [26.01] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] × 1100 × 0020 ÷ 1160 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] -× 1100 × 0308 × 1160 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM) × [26.01] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] -× 1100 × 0308 × 0020 ÷ 1160 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] +× 1100 × 0308 × 1160 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [26.01] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] +× 1100 × 0308 × 0020 ÷ 1160 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] × 1100 × 000A ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] × 1100 × 0020 × 000A ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] -× 1100 × 0308 × 000A ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] -× 1100 × 0308 × 0020 × 000A ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] +× 1100 × 0308 × 000A ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] +× 1100 × 0308 × 0020 × 000A ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] × 1100 × 0085 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] × 1100 × 0020 × 0085 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] -× 1100 × 0308 × 0085 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] -× 1100 × 0308 × 0020 × 0085 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] +× 1100 × 0308 × 0085 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] +× 1100 × 0308 × 0020 × 0085 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] × 1100 × 17D6 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] × 1100 × 0020 ÷ 17D6 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] -× 1100 × 0308 × 17D6 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] -× 1100 × 0308 × 0020 ÷ 17D6 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] +× 1100 × 0308 × 17D6 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] +× 1100 × 0308 × 0020 ÷ 17D6 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] × 1100 ÷ 0030 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) ÷ [999.0] DIGIT ZERO (NU) ÷ [0.3] × 1100 × 0020 ÷ 0030 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] -× 1100 × 0308 ÷ 0030 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] DIGIT ZERO (NU) ÷ [0.3] -× 1100 × 0308 × 0020 ÷ 0030 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] +× 1100 × 0308 ÷ 0030 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] DIGIT ZERO (NU) ÷ [0.3] +× 1100 × 0308 × 0020 ÷ 0030 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] × 1100 ÷ 0028 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) ÷ [999.0] LEFT PARENTHESIS (OP) ÷ [0.3] × 1100 × 0020 ÷ 0028 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] -× 1100 × 0308 ÷ 0028 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] LEFT PARENTHESIS (OP) ÷ [0.3] -× 1100 × 0308 × 0020 ÷ 0028 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] +× 1100 × 0308 ÷ 0028 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] LEFT PARENTHESIS (OP) ÷ [0.3] +× 1100 × 0308 × 0020 ÷ 0028 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] × 1100 × 0025 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [27.02] PERCENT SIGN (PO) ÷ [0.3] × 1100 × 0020 ÷ 0025 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] -× 1100 × 0308 × 0025 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM) × [27.02] PERCENT SIGN (PO) ÷ [0.3] -× 1100 × 0308 × 0020 ÷ 0025 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] +× 1100 × 0308 × 0025 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [27.02] PERCENT SIGN (PO) ÷ [0.3] +× 1100 × 0308 × 0020 ÷ 0025 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] × 1100 ÷ 0024 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) ÷ [999.0] DOLLAR SIGN (PR) ÷ [0.3] × 1100 × 0020 ÷ 0024 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] -× 1100 × 0308 ÷ 0024 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] DOLLAR SIGN (PR) ÷ [0.3] -× 1100 × 0308 × 0020 ÷ 0024 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] +× 1100 × 0308 ÷ 0024 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] DOLLAR SIGN (PR) ÷ [0.3] +× 1100 × 0308 × 0020 ÷ 0024 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] × 1100 × 0022 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [19.01] QUOTATION MARK (QU) ÷ [0.3] × 1100 × 0020 ÷ 0022 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] -× 1100 × 0308 × 0022 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM) × [19.01] QUOTATION MARK (QU) ÷ [0.3] -× 1100 × 0308 × 0020 ÷ 0022 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] +× 1100 × 0308 × 0022 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [19.01] QUOTATION MARK (QU) ÷ [0.3] +× 1100 × 0308 × 0020 ÷ 0022 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] × 1100 × 0020 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [7.01] SPACE (SP) ÷ [0.3] × 1100 × 0020 × 0020 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] -× 1100 × 0308 × 0020 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [0.3] -× 1100 × 0308 × 0020 × 0020 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] +× 1100 × 0308 × 0020 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [0.3] +× 1100 × 0308 × 0020 × 0020 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] × 1100 × 002F ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [13.02] SOLIDUS (SY) ÷ [0.3] × 1100 × 0020 × 002F ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] -× 1100 × 0308 × 002F ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM) × [13.03] SOLIDUS (SY) ÷ [0.3] -× 1100 × 0308 × 0020 × 002F ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] +× 1100 × 0308 × 002F ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] SOLIDUS (SY) ÷ [0.3] +× 1100 × 0308 × 0020 × 002F ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] × 1100 × 2060 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [11.01] WORD JOINER (WJ) ÷ [0.3] × 1100 × 0020 × 2060 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] -× 1100 × 0308 × 2060 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM) × [11.01] WORD JOINER (WJ) ÷ [0.3] -× 1100 × 0308 × 0020 × 2060 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] +× 1100 × 0308 × 2060 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [11.01] WORD JOINER (WJ) ÷ [0.3] +× 1100 × 0308 × 0020 × 2060 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] × 1100 × 200B ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] × 1100 × 0020 × 200B ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] -× 1100 × 0308 × 200B ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] -× 1100 × 0308 × 0020 × 200B ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] +× 1100 × 0308 × 200B ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] +× 1100 × 0308 × 0020 × 200B ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] × 1100 ÷ 1F1E6 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] × 1100 × 0020 ÷ 1F1E6 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -× 1100 × 0308 ÷ 1F1E6 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -× 1100 × 0308 × 0020 ÷ 1F1E6 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 1100 × 0308 ÷ 1F1E6 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 1100 × 0308 × 0020 ÷ 1F1E6 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 1100 ÷ 261D ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) ÷ [999.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 1100 × 0020 ÷ 261D ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [7.01] SPACE (SP) ÷ [18.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 1100 × 0308 ÷ 261D ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 1100 × 0308 × 0020 ÷ 261D ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 1100 ÷ 1F3FB ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 1100 × 0020 ÷ 1F3FB ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [7.01] SPACE (SP) ÷ [18.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 1100 × 0308 ÷ 1F3FB ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 1100 × 0308 × 0020 ÷ 1F3FB ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 1100 × 0001 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 1100 × 0020 ÷ 0001 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 1100 × 0308 × 0001 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [9.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 1100 × 0308 × 0020 ÷ 0001 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 1100 × 200D ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 1100 × 0020 ÷ 200D ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [7.01] SPACE (SP) ÷ [18.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 1100 × 0308 × 200D ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [9.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 1100 × 0308 × 0020 ÷ 200D ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] × 1100 ÷ 00A7 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) ÷ [999.0] SECTION SIGN (AI_AL) ÷ [0.3] × 1100 × 0020 ÷ 00A7 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] -× 1100 × 0308 ÷ 00A7 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] SECTION SIGN (AI_AL) ÷ [0.3] -× 1100 × 0308 × 0020 ÷ 00A7 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] +× 1100 × 0308 ÷ 00A7 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] SECTION SIGN (AI_AL) ÷ [0.3] +× 1100 × 0308 × 0020 ÷ 00A7 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] × 1100 ÷ 50005 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) ÷ [999.0] <reserved-50005> (XX_AL) ÷ [0.3] × 1100 × 0020 ÷ 50005 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] -× 1100 × 0308 ÷ 50005 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] <reserved-50005> (XX_AL) ÷ [0.3] -× 1100 × 0308 × 0020 ÷ 50005 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] +× 1100 × 0308 ÷ 50005 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] <reserved-50005> (XX_AL) ÷ [0.3] +× 1100 × 0308 × 0020 ÷ 50005 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] × 1100 ÷ 0E01 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) ÷ [999.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] × 1100 × 0020 ÷ 0E01 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] -× 1100 × 0308 ÷ 0E01 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] -× 1100 × 0308 × 0020 ÷ 0E01 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] +× 1100 × 0308 ÷ 0E01 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] +× 1100 × 0308 × 0020 ÷ 0E01 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] × 1100 × 3041 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] × 1100 × 0020 ÷ 3041 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] -× 1100 × 0308 × 3041 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] -× 1100 × 0308 × 0020 ÷ 3041 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] +× 1100 × 0308 × 3041 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] +× 1100 × 0308 × 0020 ÷ 3041 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] × 11A8 ÷ 0023 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) ÷ [999.0] NUMBER SIGN (AL) ÷ [0.3] × 11A8 × 0020 ÷ 0023 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] -× 11A8 × 0308 ÷ 0023 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] NUMBER SIGN (AL) ÷ [0.3] -× 11A8 × 0308 × 0020 ÷ 0023 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] +× 11A8 × 0308 ÷ 0023 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] NUMBER SIGN (AL) ÷ [0.3] +× 11A8 × 0308 × 0020 ÷ 0023 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] × 11A8 ÷ 2014 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) ÷ [999.0] EM DASH (B2) ÷ [0.3] × 11A8 × 0020 ÷ 2014 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] -× 11A8 × 0308 ÷ 2014 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] EM DASH (B2) ÷ [0.3] -× 11A8 × 0308 × 0020 ÷ 2014 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] +× 11A8 × 0308 ÷ 2014 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] EM DASH (B2) ÷ [0.3] +× 11A8 × 0308 × 0020 ÷ 2014 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] × 11A8 × 0009 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] × 11A8 × 0020 ÷ 0009 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] -× 11A8 × 0308 × 0009 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] -× 11A8 × 0308 × 0020 ÷ 0009 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] +× 11A8 × 0308 × 0009 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] +× 11A8 × 0308 × 0020 ÷ 0009 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] × 11A8 ÷ 00B4 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3] × 11A8 × 0020 ÷ 00B4 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] -× 11A8 × 0308 ÷ 00B4 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3] -× 11A8 × 0308 × 0020 ÷ 00B4 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] +× 11A8 × 0308 ÷ 00B4 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3] +× 11A8 × 0308 × 0020 ÷ 00B4 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] × 11A8 × 000B ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] × 11A8 × 0020 × 000B ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] -× 11A8 × 0308 × 000B ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] -× 11A8 × 0308 × 0020 × 000B ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] +× 11A8 × 0308 × 000B ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] +× 11A8 × 0308 × 0020 × 000B ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] × 11A8 ÷ FFFC ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] × 11A8 × 0020 ÷ FFFC ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] -× 11A8 × 0308 ÷ FFFC ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] -× 11A8 × 0308 × 0020 ÷ FFFC ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] +× 11A8 × 0308 ÷ FFFC ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] +× 11A8 × 0308 × 0020 ÷ FFFC ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] × 11A8 × 007D ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] × 11A8 × 0020 × 007D ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] -× 11A8 × 0308 × 007D ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM) × [13.03] RIGHT CURLY BRACKET (CL) ÷ [0.3] -× 11A8 × 0308 × 0020 × 007D ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] +× 11A8 × 0308 × 007D ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] RIGHT CURLY BRACKET (CL) ÷ [0.3] +× 11A8 × 0308 × 0020 × 007D ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] × 11A8 × 0029 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] × 11A8 × 0020 × 0029 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 11A8 × 0308 × 0029 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM) × [13.03] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 11A8 × 0308 × 0020 × 0029 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 11A8 × 0001 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] <START OF HEADING> (CM) ÷ [0.3] -× 11A8 × 0020 ÷ 0001 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM) ÷ [0.3] -× 11A8 × 0308 × 0001 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM) × [9.0] <START OF HEADING> (CM) ÷ [0.3] -× 11A8 × 0308 × 0020 ÷ 0001 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM) ÷ [0.3] +× 11A8 × 0308 × 0029 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] RIGHT PARENTHESIS (CP) ÷ [0.3] +× 11A8 × 0308 × 0020 × 0029 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] × 11A8 × 000D ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] × 11A8 × 0020 × 000D ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -× 11A8 × 0308 × 000D ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -× 11A8 × 0308 × 0020 × 000D ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +× 11A8 × 0308 × 000D ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +× 11A8 × 0308 × 0020 × 000D ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] × 11A8 × 0021 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] × 11A8 × 0020 × 0021 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] -× 11A8 × 0308 × 0021 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] -× 11A8 × 0308 × 0020 × 0021 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] +× 11A8 × 0308 × 0021 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] +× 11A8 × 0308 × 0020 × 0021 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] × 11A8 × 00A0 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [12.1] NO-BREAK SPACE (GL) ÷ [0.3] × 11A8 × 0020 ÷ 00A0 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] -× 11A8 × 0308 × 00A0 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM) × [12.2] NO-BREAK SPACE (GL) ÷ [0.3] -× 11A8 × 0308 × 0020 ÷ 00A0 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] +× 11A8 × 0308 × 00A0 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM1_CM) × [12.2] NO-BREAK SPACE (GL) ÷ [0.3] +× 11A8 × 0308 × 0020 ÷ 00A0 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] × 11A8 ÷ AC00 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) ÷ [999.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] × 11A8 × 0020 ÷ AC00 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] -× 11A8 × 0308 ÷ AC00 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] -× 11A8 × 0308 × 0020 ÷ AC00 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] +× 11A8 × 0308 ÷ AC00 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] +× 11A8 × 0308 × 0020 ÷ AC00 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] × 11A8 ÷ AC01 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) ÷ [999.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] × 11A8 × 0020 ÷ AC01 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] -× 11A8 × 0308 ÷ AC01 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] -× 11A8 × 0308 × 0020 ÷ AC01 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] +× 11A8 × 0308 ÷ AC01 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] +× 11A8 × 0308 × 0020 ÷ AC01 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] × 11A8 ÷ 05D0 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) ÷ [999.0] HEBREW LETTER ALEF (HL) ÷ [0.3] × 11A8 × 0020 ÷ 05D0 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] -× 11A8 × 0308 ÷ 05D0 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HEBREW LETTER ALEF (HL) ÷ [0.3] -× 11A8 × 0308 × 0020 ÷ 05D0 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] +× 11A8 × 0308 ÷ 05D0 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HEBREW LETTER ALEF (HL) ÷ [0.3] +× 11A8 × 0308 × 0020 ÷ 05D0 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] × 11A8 × 002D ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] × 11A8 × 0020 ÷ 002D ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] -× 11A8 × 0308 × 002D ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] -× 11A8 × 0308 × 0020 ÷ 002D ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] +× 11A8 × 0308 × 002D ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] +× 11A8 × 0308 × 0020 ÷ 002D ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] × 11A8 ÷ 231A ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) ÷ [999.0] WATCH (ID) ÷ [0.3] × 11A8 × 0020 ÷ 231A ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] -× 11A8 × 0308 ÷ 231A ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] WATCH (ID) ÷ [0.3] -× 11A8 × 0308 × 0020 ÷ 231A ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] +× 11A8 × 0308 ÷ 231A ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] WATCH (ID) ÷ [0.3] +× 11A8 × 0308 × 0020 ÷ 231A ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] × 11A8 × 2024 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [27.01] ONE DOT LEADER (IN) ÷ [0.3] × 11A8 × 0020 ÷ 2024 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] -× 11A8 × 0308 × 2024 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM) × [27.01] ONE DOT LEADER (IN) ÷ [0.3] -× 11A8 × 0308 × 0020 ÷ 2024 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] +× 11A8 × 0308 × 2024 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM1_CM) × [27.01] ONE DOT LEADER (IN) ÷ [0.3] +× 11A8 × 0308 × 0020 ÷ 2024 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] × 11A8 × 002C ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [13.02] COMMA (IS) ÷ [0.3] × 11A8 × 0020 × 002C ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] -× 11A8 × 0308 × 002C ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM) × [13.03] COMMA (IS) ÷ [0.3] -× 11A8 × 0308 × 0020 × 002C ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] +× 11A8 × 0308 × 002C ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] COMMA (IS) ÷ [0.3] +× 11A8 × 0308 × 0020 × 002C ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] × 11A8 ÷ 1100 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) ÷ [999.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] × 11A8 × 0020 ÷ 1100 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] -× 11A8 × 0308 ÷ 1100 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] -× 11A8 × 0308 × 0020 ÷ 1100 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] +× 11A8 × 0308 ÷ 1100 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] +× 11A8 × 0308 × 0020 ÷ 1100 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] × 11A8 × 11A8 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [26.03] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] × 11A8 × 0020 ÷ 11A8 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] -× 11A8 × 0308 × 11A8 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM) × [26.03] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] -× 11A8 × 0308 × 0020 ÷ 11A8 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] +× 11A8 × 0308 × 11A8 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM1_CM) × [26.03] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] +× 11A8 × 0308 × 0020 ÷ 11A8 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] × 11A8 ÷ 1160 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) ÷ [999.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] × 11A8 × 0020 ÷ 1160 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] -× 11A8 × 0308 ÷ 1160 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] -× 11A8 × 0308 × 0020 ÷ 1160 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] +× 11A8 × 0308 ÷ 1160 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] +× 11A8 × 0308 × 0020 ÷ 1160 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] × 11A8 × 000A ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] × 11A8 × 0020 × 000A ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] -× 11A8 × 0308 × 000A ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] -× 11A8 × 0308 × 0020 × 000A ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] +× 11A8 × 0308 × 000A ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] +× 11A8 × 0308 × 0020 × 000A ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] × 11A8 × 0085 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] × 11A8 × 0020 × 0085 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] -× 11A8 × 0308 × 0085 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] -× 11A8 × 0308 × 0020 × 0085 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] +× 11A8 × 0308 × 0085 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] +× 11A8 × 0308 × 0020 × 0085 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] × 11A8 × 17D6 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] × 11A8 × 0020 ÷ 17D6 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] -× 11A8 × 0308 × 17D6 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] -× 11A8 × 0308 × 0020 ÷ 17D6 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] +× 11A8 × 0308 × 17D6 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] +× 11A8 × 0308 × 0020 ÷ 17D6 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] × 11A8 ÷ 0030 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) ÷ [999.0] DIGIT ZERO (NU) ÷ [0.3] × 11A8 × 0020 ÷ 0030 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] -× 11A8 × 0308 ÷ 0030 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] DIGIT ZERO (NU) ÷ [0.3] -× 11A8 × 0308 × 0020 ÷ 0030 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] +× 11A8 × 0308 ÷ 0030 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] DIGIT ZERO (NU) ÷ [0.3] +× 11A8 × 0308 × 0020 ÷ 0030 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] × 11A8 ÷ 0028 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) ÷ [999.0] LEFT PARENTHESIS (OP) ÷ [0.3] × 11A8 × 0020 ÷ 0028 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] -× 11A8 × 0308 ÷ 0028 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] LEFT PARENTHESIS (OP) ÷ [0.3] -× 11A8 × 0308 × 0020 ÷ 0028 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] +× 11A8 × 0308 ÷ 0028 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] LEFT PARENTHESIS (OP) ÷ [0.3] +× 11A8 × 0308 × 0020 ÷ 0028 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] × 11A8 × 0025 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [27.02] PERCENT SIGN (PO) ÷ [0.3] × 11A8 × 0020 ÷ 0025 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] -× 11A8 × 0308 × 0025 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM) × [27.02] PERCENT SIGN (PO) ÷ [0.3] -× 11A8 × 0308 × 0020 ÷ 0025 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] +× 11A8 × 0308 × 0025 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM1_CM) × [27.02] PERCENT SIGN (PO) ÷ [0.3] +× 11A8 × 0308 × 0020 ÷ 0025 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] × 11A8 ÷ 0024 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) ÷ [999.0] DOLLAR SIGN (PR) ÷ [0.3] × 11A8 × 0020 ÷ 0024 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] -× 11A8 × 0308 ÷ 0024 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] DOLLAR SIGN (PR) ÷ [0.3] -× 11A8 × 0308 × 0020 ÷ 0024 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] +× 11A8 × 0308 ÷ 0024 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] DOLLAR SIGN (PR) ÷ [0.3] +× 11A8 × 0308 × 0020 ÷ 0024 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] × 11A8 × 0022 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [19.01] QUOTATION MARK (QU) ÷ [0.3] × 11A8 × 0020 ÷ 0022 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] -× 11A8 × 0308 × 0022 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM) × [19.01] QUOTATION MARK (QU) ÷ [0.3] -× 11A8 × 0308 × 0020 ÷ 0022 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] +× 11A8 × 0308 × 0022 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM1_CM) × [19.01] QUOTATION MARK (QU) ÷ [0.3] +× 11A8 × 0308 × 0020 ÷ 0022 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] × 11A8 × 0020 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [7.01] SPACE (SP) ÷ [0.3] × 11A8 × 0020 × 0020 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] -× 11A8 × 0308 × 0020 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [0.3] -× 11A8 × 0308 × 0020 × 0020 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] +× 11A8 × 0308 × 0020 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [0.3] +× 11A8 × 0308 × 0020 × 0020 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] × 11A8 × 002F ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [13.02] SOLIDUS (SY) ÷ [0.3] × 11A8 × 0020 × 002F ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] -× 11A8 × 0308 × 002F ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM) × [13.03] SOLIDUS (SY) ÷ [0.3] -× 11A8 × 0308 × 0020 × 002F ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] +× 11A8 × 0308 × 002F ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] SOLIDUS (SY) ÷ [0.3] +× 11A8 × 0308 × 0020 × 002F ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] × 11A8 × 2060 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [11.01] WORD JOINER (WJ) ÷ [0.3] × 11A8 × 0020 × 2060 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] -× 11A8 × 0308 × 2060 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM) × [11.01] WORD JOINER (WJ) ÷ [0.3] -× 11A8 × 0308 × 0020 × 2060 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] +× 11A8 × 0308 × 2060 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM1_CM) × [11.01] WORD JOINER (WJ) ÷ [0.3] +× 11A8 × 0308 × 0020 × 2060 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] × 11A8 × 200B ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] × 11A8 × 0020 × 200B ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] -× 11A8 × 0308 × 200B ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] -× 11A8 × 0308 × 0020 × 200B ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] +× 11A8 × 0308 × 200B ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] +× 11A8 × 0308 × 0020 × 200B ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] × 11A8 ÷ 1F1E6 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] × 11A8 × 0020 ÷ 1F1E6 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -× 11A8 × 0308 ÷ 1F1E6 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -× 11A8 × 0308 × 0020 ÷ 1F1E6 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 11A8 × 0308 ÷ 1F1E6 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 11A8 × 0308 × 0020 ÷ 1F1E6 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 11A8 ÷ 261D ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) ÷ [999.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 11A8 × 0020 ÷ 261D ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [7.01] SPACE (SP) ÷ [18.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 11A8 × 0308 ÷ 261D ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 11A8 × 0308 × 0020 ÷ 261D ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 11A8 ÷ 1F3FB ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 11A8 × 0020 ÷ 1F3FB ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [7.01] SPACE (SP) ÷ [18.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 11A8 × 0308 ÷ 1F3FB ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 11A8 × 0308 × 0020 ÷ 1F3FB ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 11A8 × 0001 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 11A8 × 0020 ÷ 0001 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 11A8 × 0308 × 0001 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM1_CM) × [9.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 11A8 × 0308 × 0020 ÷ 0001 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 11A8 × 200D ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 11A8 × 0020 ÷ 200D ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [7.01] SPACE (SP) ÷ [18.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 11A8 × 0308 × 200D ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM1_CM) × [9.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 11A8 × 0308 × 0020 ÷ 200D ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] × 11A8 ÷ 00A7 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) ÷ [999.0] SECTION SIGN (AI_AL) ÷ [0.3] × 11A8 × 0020 ÷ 00A7 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] -× 11A8 × 0308 ÷ 00A7 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] SECTION SIGN (AI_AL) ÷ [0.3] -× 11A8 × 0308 × 0020 ÷ 00A7 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] +× 11A8 × 0308 ÷ 00A7 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] SECTION SIGN (AI_AL) ÷ [0.3] +× 11A8 × 0308 × 0020 ÷ 00A7 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] × 11A8 ÷ 50005 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) ÷ [999.0] <reserved-50005> (XX_AL) ÷ [0.3] × 11A8 × 0020 ÷ 50005 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] -× 11A8 × 0308 ÷ 50005 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] <reserved-50005> (XX_AL) ÷ [0.3] -× 11A8 × 0308 × 0020 ÷ 50005 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] +× 11A8 × 0308 ÷ 50005 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] <reserved-50005> (XX_AL) ÷ [0.3] +× 11A8 × 0308 × 0020 ÷ 50005 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] × 11A8 ÷ 0E01 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) ÷ [999.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] × 11A8 × 0020 ÷ 0E01 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] -× 11A8 × 0308 ÷ 0E01 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] -× 11A8 × 0308 × 0020 ÷ 0E01 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] +× 11A8 × 0308 ÷ 0E01 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] +× 11A8 × 0308 × 0020 ÷ 0E01 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] × 11A8 × 3041 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] × 11A8 × 0020 ÷ 3041 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] -× 11A8 × 0308 × 3041 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] -× 11A8 × 0308 × 0020 ÷ 3041 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] +× 11A8 × 0308 × 3041 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] +× 11A8 × 0308 × 0020 ÷ 3041 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] × 1160 ÷ 0023 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) ÷ [999.0] NUMBER SIGN (AL) ÷ [0.3] × 1160 × 0020 ÷ 0023 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] -× 1160 × 0308 ÷ 0023 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] NUMBER SIGN (AL) ÷ [0.3] -× 1160 × 0308 × 0020 ÷ 0023 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] +× 1160 × 0308 ÷ 0023 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] NUMBER SIGN (AL) ÷ [0.3] +× 1160 × 0308 × 0020 ÷ 0023 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] × 1160 ÷ 2014 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) ÷ [999.0] EM DASH (B2) ÷ [0.3] × 1160 × 0020 ÷ 2014 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] -× 1160 × 0308 ÷ 2014 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] EM DASH (B2) ÷ [0.3] -× 1160 × 0308 × 0020 ÷ 2014 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] +× 1160 × 0308 ÷ 2014 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] EM DASH (B2) ÷ [0.3] +× 1160 × 0308 × 0020 ÷ 2014 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] × 1160 × 0009 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] × 1160 × 0020 ÷ 0009 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] -× 1160 × 0308 × 0009 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] -× 1160 × 0308 × 0020 ÷ 0009 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] +× 1160 × 0308 × 0009 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] +× 1160 × 0308 × 0020 ÷ 0009 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] × 1160 ÷ 00B4 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3] × 1160 × 0020 ÷ 00B4 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] -× 1160 × 0308 ÷ 00B4 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3] -× 1160 × 0308 × 0020 ÷ 00B4 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] +× 1160 × 0308 ÷ 00B4 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3] +× 1160 × 0308 × 0020 ÷ 00B4 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] × 1160 × 000B ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] × 1160 × 0020 × 000B ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] -× 1160 × 0308 × 000B ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] -× 1160 × 0308 × 0020 × 000B ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] +× 1160 × 0308 × 000B ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] +× 1160 × 0308 × 0020 × 000B ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] × 1160 ÷ FFFC ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] × 1160 × 0020 ÷ FFFC ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] -× 1160 × 0308 ÷ FFFC ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] -× 1160 × 0308 × 0020 ÷ FFFC ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] +× 1160 × 0308 ÷ FFFC ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] +× 1160 × 0308 × 0020 ÷ FFFC ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] × 1160 × 007D ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] × 1160 × 0020 × 007D ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] -× 1160 × 0308 × 007D ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM) × [13.03] RIGHT CURLY BRACKET (CL) ÷ [0.3] -× 1160 × 0308 × 0020 × 007D ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] +× 1160 × 0308 × 007D ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] RIGHT CURLY BRACKET (CL) ÷ [0.3] +× 1160 × 0308 × 0020 × 007D ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] × 1160 × 0029 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] × 1160 × 0020 × 0029 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 1160 × 0308 × 0029 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM) × [13.03] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 1160 × 0308 × 0020 × 0029 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 1160 × 0001 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] <START OF HEADING> (CM) ÷ [0.3] -× 1160 × 0020 ÷ 0001 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM) ÷ [0.3] -× 1160 × 0308 × 0001 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM) × [9.0] <START OF HEADING> (CM) ÷ [0.3] -× 1160 × 0308 × 0020 ÷ 0001 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM) ÷ [0.3] +× 1160 × 0308 × 0029 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] RIGHT PARENTHESIS (CP) ÷ [0.3] +× 1160 × 0308 × 0020 × 0029 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] × 1160 × 000D ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] × 1160 × 0020 × 000D ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -× 1160 × 0308 × 000D ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -× 1160 × 0308 × 0020 × 000D ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +× 1160 × 0308 × 000D ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +× 1160 × 0308 × 0020 × 000D ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] × 1160 × 0021 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] × 1160 × 0020 × 0021 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] -× 1160 × 0308 × 0021 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] -× 1160 × 0308 × 0020 × 0021 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] +× 1160 × 0308 × 0021 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] +× 1160 × 0308 × 0020 × 0021 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] × 1160 × 00A0 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [12.1] NO-BREAK SPACE (GL) ÷ [0.3] × 1160 × 0020 ÷ 00A0 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] -× 1160 × 0308 × 00A0 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM) × [12.2] NO-BREAK SPACE (GL) ÷ [0.3] -× 1160 × 0308 × 0020 ÷ 00A0 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] +× 1160 × 0308 × 00A0 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM1_CM) × [12.2] NO-BREAK SPACE (GL) ÷ [0.3] +× 1160 × 0308 × 0020 ÷ 00A0 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] × 1160 ÷ AC00 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) ÷ [999.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] × 1160 × 0020 ÷ AC00 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] -× 1160 × 0308 ÷ AC00 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] -× 1160 × 0308 × 0020 ÷ AC00 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] +× 1160 × 0308 ÷ AC00 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] +× 1160 × 0308 × 0020 ÷ AC00 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] × 1160 ÷ AC01 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) ÷ [999.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] × 1160 × 0020 ÷ AC01 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] -× 1160 × 0308 ÷ AC01 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] -× 1160 × 0308 × 0020 ÷ AC01 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] +× 1160 × 0308 ÷ AC01 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] +× 1160 × 0308 × 0020 ÷ AC01 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] × 1160 ÷ 05D0 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) ÷ [999.0] HEBREW LETTER ALEF (HL) ÷ [0.3] × 1160 × 0020 ÷ 05D0 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] -× 1160 × 0308 ÷ 05D0 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HEBREW LETTER ALEF (HL) ÷ [0.3] -× 1160 × 0308 × 0020 ÷ 05D0 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] +× 1160 × 0308 ÷ 05D0 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HEBREW LETTER ALEF (HL) ÷ [0.3] +× 1160 × 0308 × 0020 ÷ 05D0 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] × 1160 × 002D ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] × 1160 × 0020 ÷ 002D ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] -× 1160 × 0308 × 002D ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] -× 1160 × 0308 × 0020 ÷ 002D ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] +× 1160 × 0308 × 002D ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] +× 1160 × 0308 × 0020 ÷ 002D ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] × 1160 ÷ 231A ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) ÷ [999.0] WATCH (ID) ÷ [0.3] × 1160 × 0020 ÷ 231A ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] -× 1160 × 0308 ÷ 231A ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] WATCH (ID) ÷ [0.3] -× 1160 × 0308 × 0020 ÷ 231A ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] +× 1160 × 0308 ÷ 231A ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] WATCH (ID) ÷ [0.3] +× 1160 × 0308 × 0020 ÷ 231A ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] × 1160 × 2024 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [27.01] ONE DOT LEADER (IN) ÷ [0.3] × 1160 × 0020 ÷ 2024 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] -× 1160 × 0308 × 2024 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM) × [27.01] ONE DOT LEADER (IN) ÷ [0.3] -× 1160 × 0308 × 0020 ÷ 2024 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] +× 1160 × 0308 × 2024 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM1_CM) × [27.01] ONE DOT LEADER (IN) ÷ [0.3] +× 1160 × 0308 × 0020 ÷ 2024 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] × 1160 × 002C ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [13.02] COMMA (IS) ÷ [0.3] × 1160 × 0020 × 002C ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] -× 1160 × 0308 × 002C ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM) × [13.03] COMMA (IS) ÷ [0.3] -× 1160 × 0308 × 0020 × 002C ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] +× 1160 × 0308 × 002C ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] COMMA (IS) ÷ [0.3] +× 1160 × 0308 × 0020 × 002C ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] × 1160 ÷ 1100 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) ÷ [999.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] × 1160 × 0020 ÷ 1100 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] -× 1160 × 0308 ÷ 1100 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] -× 1160 × 0308 × 0020 ÷ 1100 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] +× 1160 × 0308 ÷ 1100 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] +× 1160 × 0308 × 0020 ÷ 1100 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] × 1160 × 11A8 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [26.02] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] × 1160 × 0020 ÷ 11A8 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] -× 1160 × 0308 × 11A8 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM) × [26.02] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] -× 1160 × 0308 × 0020 ÷ 11A8 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] +× 1160 × 0308 × 11A8 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM1_CM) × [26.02] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] +× 1160 × 0308 × 0020 ÷ 11A8 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] × 1160 × 1160 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [26.02] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] × 1160 × 0020 ÷ 1160 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] -× 1160 × 0308 × 1160 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM) × [26.02] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] -× 1160 × 0308 × 0020 ÷ 1160 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] +× 1160 × 0308 × 1160 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM1_CM) × [26.02] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] +× 1160 × 0308 × 0020 ÷ 1160 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] × 1160 × 000A ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] × 1160 × 0020 × 000A ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] -× 1160 × 0308 × 000A ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] -× 1160 × 0308 × 0020 × 000A ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] +× 1160 × 0308 × 000A ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] +× 1160 × 0308 × 0020 × 000A ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] × 1160 × 0085 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] × 1160 × 0020 × 0085 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] -× 1160 × 0308 × 0085 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] -× 1160 × 0308 × 0020 × 0085 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] +× 1160 × 0308 × 0085 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] +× 1160 × 0308 × 0020 × 0085 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] × 1160 × 17D6 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] × 1160 × 0020 ÷ 17D6 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] -× 1160 × 0308 × 17D6 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] -× 1160 × 0308 × 0020 ÷ 17D6 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] +× 1160 × 0308 × 17D6 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] +× 1160 × 0308 × 0020 ÷ 17D6 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] × 1160 ÷ 0030 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) ÷ [999.0] DIGIT ZERO (NU) ÷ [0.3] × 1160 × 0020 ÷ 0030 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] -× 1160 × 0308 ÷ 0030 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] DIGIT ZERO (NU) ÷ [0.3] -× 1160 × 0308 × 0020 ÷ 0030 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] +× 1160 × 0308 ÷ 0030 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] DIGIT ZERO (NU) ÷ [0.3] +× 1160 × 0308 × 0020 ÷ 0030 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] × 1160 ÷ 0028 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) ÷ [999.0] LEFT PARENTHESIS (OP) ÷ [0.3] × 1160 × 0020 ÷ 0028 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] -× 1160 × 0308 ÷ 0028 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] LEFT PARENTHESIS (OP) ÷ [0.3] -× 1160 × 0308 × 0020 ÷ 0028 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] +× 1160 × 0308 ÷ 0028 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] LEFT PARENTHESIS (OP) ÷ [0.3] +× 1160 × 0308 × 0020 ÷ 0028 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] × 1160 × 0025 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [27.02] PERCENT SIGN (PO) ÷ [0.3] × 1160 × 0020 ÷ 0025 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] -× 1160 × 0308 × 0025 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM) × [27.02] PERCENT SIGN (PO) ÷ [0.3] -× 1160 × 0308 × 0020 ÷ 0025 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] +× 1160 × 0308 × 0025 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM1_CM) × [27.02] PERCENT SIGN (PO) ÷ [0.3] +× 1160 × 0308 × 0020 ÷ 0025 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] × 1160 ÷ 0024 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) ÷ [999.0] DOLLAR SIGN (PR) ÷ [0.3] × 1160 × 0020 ÷ 0024 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] -× 1160 × 0308 ÷ 0024 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] DOLLAR SIGN (PR) ÷ [0.3] -× 1160 × 0308 × 0020 ÷ 0024 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] +× 1160 × 0308 ÷ 0024 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] DOLLAR SIGN (PR) ÷ [0.3] +× 1160 × 0308 × 0020 ÷ 0024 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] × 1160 × 0022 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [19.01] QUOTATION MARK (QU) ÷ [0.3] × 1160 × 0020 ÷ 0022 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] -× 1160 × 0308 × 0022 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM) × [19.01] QUOTATION MARK (QU) ÷ [0.3] -× 1160 × 0308 × 0020 ÷ 0022 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] +× 1160 × 0308 × 0022 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM1_CM) × [19.01] QUOTATION MARK (QU) ÷ [0.3] +× 1160 × 0308 × 0020 ÷ 0022 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] × 1160 × 0020 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [7.01] SPACE (SP) ÷ [0.3] × 1160 × 0020 × 0020 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] -× 1160 × 0308 × 0020 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [0.3] -× 1160 × 0308 × 0020 × 0020 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] +× 1160 × 0308 × 0020 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [0.3] +× 1160 × 0308 × 0020 × 0020 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] × 1160 × 002F ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [13.02] SOLIDUS (SY) ÷ [0.3] × 1160 × 0020 × 002F ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] -× 1160 × 0308 × 002F ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM) × [13.03] SOLIDUS (SY) ÷ [0.3] -× 1160 × 0308 × 0020 × 002F ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] +× 1160 × 0308 × 002F ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] SOLIDUS (SY) ÷ [0.3] +× 1160 × 0308 × 0020 × 002F ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] × 1160 × 2060 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [11.01] WORD JOINER (WJ) ÷ [0.3] × 1160 × 0020 × 2060 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] -× 1160 × 0308 × 2060 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM) × [11.01] WORD JOINER (WJ) ÷ [0.3] -× 1160 × 0308 × 0020 × 2060 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] +× 1160 × 0308 × 2060 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM1_CM) × [11.01] WORD JOINER (WJ) ÷ [0.3] +× 1160 × 0308 × 0020 × 2060 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] × 1160 × 200B ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] × 1160 × 0020 × 200B ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] -× 1160 × 0308 × 200B ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] -× 1160 × 0308 × 0020 × 200B ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] +× 1160 × 0308 × 200B ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] +× 1160 × 0308 × 0020 × 200B ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] × 1160 ÷ 1F1E6 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] × 1160 × 0020 ÷ 1F1E6 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -× 1160 × 0308 ÷ 1F1E6 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -× 1160 × 0308 × 0020 ÷ 1F1E6 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 1160 × 0308 ÷ 1F1E6 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 1160 × 0308 × 0020 ÷ 1F1E6 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 1160 ÷ 261D ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) ÷ [999.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 1160 × 0020 ÷ 261D ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [7.01] SPACE (SP) ÷ [18.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 1160 × 0308 ÷ 261D ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 1160 × 0308 × 0020 ÷ 261D ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 1160 ÷ 1F3FB ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 1160 × 0020 ÷ 1F3FB ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [7.01] SPACE (SP) ÷ [18.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 1160 × 0308 ÷ 1F3FB ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 1160 × 0308 × 0020 ÷ 1F3FB ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 1160 × 0001 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 1160 × 0020 ÷ 0001 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 1160 × 0308 × 0001 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM1_CM) × [9.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 1160 × 0308 × 0020 ÷ 0001 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 1160 × 200D ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 1160 × 0020 ÷ 200D ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [7.01] SPACE (SP) ÷ [18.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 1160 × 0308 × 200D ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM1_CM) × [9.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 1160 × 0308 × 0020 ÷ 200D ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] × 1160 ÷ 00A7 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) ÷ [999.0] SECTION SIGN (AI_AL) ÷ [0.3] × 1160 × 0020 ÷ 00A7 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] -× 1160 × 0308 ÷ 00A7 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] SECTION SIGN (AI_AL) ÷ [0.3] -× 1160 × 0308 × 0020 ÷ 00A7 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] +× 1160 × 0308 ÷ 00A7 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] SECTION SIGN (AI_AL) ÷ [0.3] +× 1160 × 0308 × 0020 ÷ 00A7 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] × 1160 ÷ 50005 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) ÷ [999.0] <reserved-50005> (XX_AL) ÷ [0.3] × 1160 × 0020 ÷ 50005 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] -× 1160 × 0308 ÷ 50005 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] <reserved-50005> (XX_AL) ÷ [0.3] -× 1160 × 0308 × 0020 ÷ 50005 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] +× 1160 × 0308 ÷ 50005 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] <reserved-50005> (XX_AL) ÷ [0.3] +× 1160 × 0308 × 0020 ÷ 50005 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] × 1160 ÷ 0E01 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) ÷ [999.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] × 1160 × 0020 ÷ 0E01 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] -× 1160 × 0308 ÷ 0E01 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] -× 1160 × 0308 × 0020 ÷ 0E01 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] +× 1160 × 0308 ÷ 0E01 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] +× 1160 × 0308 × 0020 ÷ 0E01 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] × 1160 × 3041 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] × 1160 × 0020 ÷ 3041 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] -× 1160 × 0308 × 3041 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] -× 1160 × 0308 × 0020 ÷ 3041 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] +× 1160 × 0308 × 3041 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] +× 1160 × 0308 × 0020 ÷ 3041 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] × 000A ÷ 0023 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] NUMBER SIGN (AL) ÷ [0.3] × 000A ÷ 0020 ÷ 0023 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] -× 000A ÷ 0308 × 0023 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM) × [28.0] NUMBER SIGN (AL) ÷ [0.3] -× 000A ÷ 0308 × 0020 ÷ 0023 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] +× 000A ÷ 0308 × 0023 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM1_CM) × [28.0] NUMBER SIGN (AL) ÷ [0.3] +× 000A ÷ 0308 × 0020 ÷ 0023 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] × 000A ÷ 2014 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] EM DASH (B2) ÷ [0.3] × 000A ÷ 0020 ÷ 2014 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] -× 000A ÷ 0308 ÷ 2014 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM) ÷ [999.0] EM DASH (B2) ÷ [0.3] -× 000A ÷ 0308 × 0020 ÷ 2014 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] +× 000A ÷ 0308 ÷ 2014 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] EM DASH (B2) ÷ [0.3] +× 000A ÷ 0308 × 0020 ÷ 2014 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] × 000A ÷ 0009 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] <CHARACTER TABULATION> (BA) ÷ [0.3] × 000A ÷ 0020 ÷ 0009 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] -× 000A ÷ 0308 × 0009 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] -× 000A ÷ 0308 × 0020 ÷ 0009 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] +× 000A ÷ 0308 × 0009 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM1_CM) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] +× 000A ÷ 0308 × 0020 ÷ 0009 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] × 000A ÷ 00B4 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] ACUTE ACCENT (BB) ÷ [0.3] × 000A ÷ 0020 ÷ 00B4 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] -× 000A ÷ 0308 ÷ 00B4 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3] -× 000A ÷ 0308 × 0020 ÷ 00B4 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] +× 000A ÷ 0308 ÷ 00B4 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3] +× 000A ÷ 0308 × 0020 ÷ 00B4 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] × 000A ÷ 000B ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] <LINE TABULATION> (BK) ÷ [0.3] × 000A ÷ 0020 × 000B ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] -× 000A ÷ 0308 × 000B ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] -× 000A ÷ 0308 × 0020 × 000B ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] +× 000A ÷ 0308 × 000B ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM1_CM) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] +× 000A ÷ 0308 × 0020 × 000B ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] × 000A ÷ FFFC ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] × 000A ÷ 0020 ÷ FFFC ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] -× 000A ÷ 0308 ÷ FFFC ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] -× 000A ÷ 0308 × 0020 ÷ FFFC ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] +× 000A ÷ 0308 ÷ FFFC ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM1_CM) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] +× 000A ÷ 0308 × 0020 ÷ FFFC ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] × 000A ÷ 007D ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] RIGHT CURLY BRACKET (CL) ÷ [0.3] × 000A ÷ 0020 × 007D ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] -× 000A ÷ 0308 × 007D ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM) × [13.03] RIGHT CURLY BRACKET (CL) ÷ [0.3] -× 000A ÷ 0308 × 0020 × 007D ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] +× 000A ÷ 0308 × 007D ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM1_CM) × [13.03] RIGHT CURLY BRACKET (CL) ÷ [0.3] +× 000A ÷ 0308 × 0020 × 007D ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] × 000A ÷ 0029 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] RIGHT PARENTHESIS (CP) ÷ [0.3] × 000A ÷ 0020 × 0029 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 000A ÷ 0308 × 0029 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM) × [13.03] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 000A ÷ 0308 × 0020 × 0029 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 000A ÷ 0001 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] <START OF HEADING> (CM) ÷ [0.3] -× 000A ÷ 0020 ÷ 0001 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM) ÷ [0.3] -× 000A ÷ 0308 × 0001 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM) × [9.0] <START OF HEADING> (CM) ÷ [0.3] -× 000A ÷ 0308 × 0020 ÷ 0001 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM) ÷ [0.3] +× 000A ÷ 0308 × 0029 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM1_CM) × [13.03] RIGHT PARENTHESIS (CP) ÷ [0.3] +× 000A ÷ 0308 × 0020 × 0029 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] × 000A ÷ 000D ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] × 000A ÷ 0020 × 000D ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -× 000A ÷ 0308 × 000D ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -× 000A ÷ 0308 × 0020 × 000D ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +× 000A ÷ 0308 × 000D ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM1_CM) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +× 000A ÷ 0308 × 0020 × 000D ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] × 000A ÷ 0021 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] EXCLAMATION MARK (EX) ÷ [0.3] × 000A ÷ 0020 × 0021 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] -× 000A ÷ 0308 × 0021 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] -× 000A ÷ 0308 × 0020 × 0021 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] +× 000A ÷ 0308 × 0021 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM1_CM) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] +× 000A ÷ 0308 × 0020 × 0021 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] × 000A ÷ 00A0 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] NO-BREAK SPACE (GL) ÷ [0.3] × 000A ÷ 0020 ÷ 00A0 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] -× 000A ÷ 0308 × 00A0 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM) × [12.2] NO-BREAK SPACE (GL) ÷ [0.3] -× 000A ÷ 0308 × 0020 ÷ 00A0 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] +× 000A ÷ 0308 × 00A0 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM1_CM) × [12.2] NO-BREAK SPACE (GL) ÷ [0.3] +× 000A ÷ 0308 × 0020 ÷ 00A0 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] × 000A ÷ AC00 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] HANGUL SYLLABLE GA (H2) ÷ [0.3] × 000A ÷ 0020 ÷ AC00 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] -× 000A ÷ 0308 ÷ AC00 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] -× 000A ÷ 0308 × 0020 ÷ AC00 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] +× 000A ÷ 0308 ÷ AC00 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] +× 000A ÷ 0308 × 0020 ÷ AC00 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] × 000A ÷ AC01 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] HANGUL SYLLABLE GAG (H3) ÷ [0.3] × 000A ÷ 0020 ÷ AC01 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] -× 000A ÷ 0308 ÷ AC01 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] -× 000A ÷ 0308 × 0020 ÷ AC01 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] +× 000A ÷ 0308 ÷ AC01 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] +× 000A ÷ 0308 × 0020 ÷ AC01 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] × 000A ÷ 05D0 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] HEBREW LETTER ALEF (HL) ÷ [0.3] × 000A ÷ 0020 ÷ 05D0 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] -× 000A ÷ 0308 × 05D0 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM) × [28.0] HEBREW LETTER ALEF (HL) ÷ [0.3] -× 000A ÷ 0308 × 0020 ÷ 05D0 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] +× 000A ÷ 0308 × 05D0 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM1_CM) × [28.0] HEBREW LETTER ALEF (HL) ÷ [0.3] +× 000A ÷ 0308 × 0020 ÷ 05D0 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] × 000A ÷ 002D ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] HYPHEN-MINUS (HY) ÷ [0.3] × 000A ÷ 0020 ÷ 002D ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] -× 000A ÷ 0308 × 002D ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] -× 000A ÷ 0308 × 0020 ÷ 002D ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] +× 000A ÷ 0308 × 002D ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM1_CM) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] +× 000A ÷ 0308 × 0020 ÷ 002D ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] × 000A ÷ 231A ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] WATCH (ID) ÷ [0.3] × 000A ÷ 0020 ÷ 231A ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] -× 000A ÷ 0308 ÷ 231A ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM) ÷ [999.0] WATCH (ID) ÷ [0.3] -× 000A ÷ 0308 × 0020 ÷ 231A ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] +× 000A ÷ 0308 ÷ 231A ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] WATCH (ID) ÷ [0.3] +× 000A ÷ 0308 × 0020 ÷ 231A ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] × 000A ÷ 2024 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] ONE DOT LEADER (IN) ÷ [0.3] × 000A ÷ 0020 ÷ 2024 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] -× 000A ÷ 0308 × 2024 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM) × [22.01] ONE DOT LEADER (IN) ÷ [0.3] -× 000A ÷ 0308 × 0020 ÷ 2024 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] +× 000A ÷ 0308 × 2024 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM1_CM) × [22.01] ONE DOT LEADER (IN) ÷ [0.3] +× 000A ÷ 0308 × 0020 ÷ 2024 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] × 000A ÷ 002C ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMMA (IS) ÷ [0.3] × 000A ÷ 0020 × 002C ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] -× 000A ÷ 0308 × 002C ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM) × [13.03] COMMA (IS) ÷ [0.3] -× 000A ÷ 0308 × 0020 × 002C ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] +× 000A ÷ 0308 × 002C ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM1_CM) × [13.03] COMMA (IS) ÷ [0.3] +× 000A ÷ 0308 × 0020 × 002C ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] × 000A ÷ 1100 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] × 000A ÷ 0020 ÷ 1100 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] -× 000A ÷ 0308 ÷ 1100 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] -× 000A ÷ 0308 × 0020 ÷ 1100 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] +× 000A ÷ 0308 ÷ 1100 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] +× 000A ÷ 0308 × 0020 ÷ 1100 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] × 000A ÷ 11A8 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] × 000A ÷ 0020 ÷ 11A8 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] -× 000A ÷ 0308 ÷ 11A8 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] -× 000A ÷ 0308 × 0020 ÷ 11A8 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] +× 000A ÷ 0308 ÷ 11A8 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] +× 000A ÷ 0308 × 0020 ÷ 11A8 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] × 000A ÷ 1160 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] × 000A ÷ 0020 ÷ 1160 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] -× 000A ÷ 0308 ÷ 1160 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] -× 000A ÷ 0308 × 0020 ÷ 1160 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] +× 000A ÷ 0308 ÷ 1160 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] +× 000A ÷ 0308 × 0020 ÷ 1160 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] × 000A ÷ 000A ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] <LINE FEED (LF)> (LF) ÷ [0.3] × 000A ÷ 0020 × 000A ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] -× 000A ÷ 0308 × 000A ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] -× 000A ÷ 0308 × 0020 × 000A ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] +× 000A ÷ 0308 × 000A ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM1_CM) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] +× 000A ÷ 0308 × 0020 × 000A ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] × 000A ÷ 0085 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] <NEXT LINE (NEL)> (NL) ÷ [0.3] × 000A ÷ 0020 × 0085 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] -× 000A ÷ 0308 × 0085 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] -× 000A ÷ 0308 × 0020 × 0085 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] +× 000A ÷ 0308 × 0085 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM1_CM) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] +× 000A ÷ 0308 × 0020 × 0085 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] × 000A ÷ 17D6 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] × 000A ÷ 0020 ÷ 17D6 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] -× 000A ÷ 0308 × 17D6 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] -× 000A ÷ 0308 × 0020 ÷ 17D6 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] +× 000A ÷ 0308 × 17D6 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM1_CM) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] +× 000A ÷ 0308 × 0020 ÷ 17D6 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] × 000A ÷ 0030 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] DIGIT ZERO (NU) ÷ [0.3] × 000A ÷ 0020 ÷ 0030 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] -× 000A ÷ 0308 × 0030 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM) × [23.02] DIGIT ZERO (NU) ÷ [0.3] -× 000A ÷ 0308 × 0020 ÷ 0030 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] +× 000A ÷ 0308 × 0030 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM1_CM) × [23.02] DIGIT ZERO (NU) ÷ [0.3] +× 000A ÷ 0308 × 0020 ÷ 0030 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] × 000A ÷ 0028 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] LEFT PARENTHESIS (OP) ÷ [0.3] × 000A ÷ 0020 ÷ 0028 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] -× 000A ÷ 0308 × 0028 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM) × [30.01] LEFT PARENTHESIS (OP) ÷ [0.3] -× 000A ÷ 0308 × 0020 ÷ 0028 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] +× 000A ÷ 0308 × 0028 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM1_CM) × [30.01] LEFT PARENTHESIS (OP) ÷ [0.3] +× 000A ÷ 0308 × 0020 ÷ 0028 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] × 000A ÷ 0025 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] PERCENT SIGN (PO) ÷ [0.3] × 000A ÷ 0020 ÷ 0025 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] -× 000A ÷ 0308 ÷ 0025 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM) ÷ [999.0] PERCENT SIGN (PO) ÷ [0.3] -× 000A ÷ 0308 × 0020 ÷ 0025 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] +× 000A ÷ 0308 × 0025 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM1_CM) × [24.03] PERCENT SIGN (PO) ÷ [0.3] +× 000A ÷ 0308 × 0020 ÷ 0025 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] × 000A ÷ 0024 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] DOLLAR SIGN (PR) ÷ [0.3] × 000A ÷ 0020 ÷ 0024 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] -× 000A ÷ 0308 ÷ 0024 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM) ÷ [999.0] DOLLAR SIGN (PR) ÷ [0.3] -× 000A ÷ 0308 × 0020 ÷ 0024 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] +× 000A ÷ 0308 × 0024 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM1_CM) × [24.03] DOLLAR SIGN (PR) ÷ [0.3] +× 000A ÷ 0308 × 0020 ÷ 0024 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] × 000A ÷ 0022 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] QUOTATION MARK (QU) ÷ [0.3] × 000A ÷ 0020 ÷ 0022 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] -× 000A ÷ 0308 × 0022 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM) × [19.01] QUOTATION MARK (QU) ÷ [0.3] -× 000A ÷ 0308 × 0020 ÷ 0022 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] +× 000A ÷ 0308 × 0022 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM1_CM) × [19.01] QUOTATION MARK (QU) ÷ [0.3] +× 000A ÷ 0308 × 0020 ÷ 0022 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] × 000A ÷ 0020 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] SPACE (SP) ÷ [0.3] × 000A ÷ 0020 × 0020 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] -× 000A ÷ 0308 × 0020 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [0.3] -× 000A ÷ 0308 × 0020 × 0020 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] +× 000A ÷ 0308 × 0020 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [0.3] +× 000A ÷ 0308 × 0020 × 0020 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] × 000A ÷ 002F ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] SOLIDUS (SY) ÷ [0.3] × 000A ÷ 0020 × 002F ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] -× 000A ÷ 0308 × 002F ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM) × [13.03] SOLIDUS (SY) ÷ [0.3] -× 000A ÷ 0308 × 0020 × 002F ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] +× 000A ÷ 0308 × 002F ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM1_CM) × [13.03] SOLIDUS (SY) ÷ [0.3] +× 000A ÷ 0308 × 0020 × 002F ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] × 000A ÷ 2060 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] WORD JOINER (WJ) ÷ [0.3] × 000A ÷ 0020 × 2060 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] -× 000A ÷ 0308 × 2060 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM) × [11.01] WORD JOINER (WJ) ÷ [0.3] -× 000A ÷ 0308 × 0020 × 2060 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] +× 000A ÷ 0308 × 2060 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM1_CM) × [11.01] WORD JOINER (WJ) ÷ [0.3] +× 000A ÷ 0308 × 0020 × 2060 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] × 000A ÷ 200B ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] ZERO WIDTH SPACE (ZW) ÷ [0.3] × 000A ÷ 0020 × 200B ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] -× 000A ÷ 0308 × 200B ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] -× 000A ÷ 0308 × 0020 × 200B ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] +× 000A ÷ 0308 × 200B ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM1_CM) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] +× 000A ÷ 0308 × 0020 × 200B ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] × 000A ÷ 1F1E6 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] × 000A ÷ 0020 ÷ 1F1E6 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -× 000A ÷ 0308 ÷ 1F1E6 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -× 000A ÷ 0308 × 0020 ÷ 1F1E6 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 000A ÷ 0308 ÷ 1F1E6 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 000A ÷ 0308 × 0020 ÷ 1F1E6 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 000A ÷ 261D ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 000A ÷ 0020 ÷ 261D ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] SPACE (SP) ÷ [18.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 000A ÷ 0308 ÷ 261D ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 000A ÷ 0308 × 0020 ÷ 261D ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 000A ÷ 1F3FB ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 000A ÷ 0020 ÷ 1F3FB ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] SPACE (SP) ÷ [18.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 000A ÷ 0308 ÷ 1F3FB ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 000A ÷ 0308 × 0020 ÷ 1F3FB ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 000A ÷ 0001 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 000A ÷ 0020 ÷ 0001 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 000A ÷ 0308 × 0001 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM1_CM) × [9.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 000A ÷ 0308 × 0020 ÷ 0001 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 000A ÷ 200D ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 000A ÷ 0020 ÷ 200D ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] SPACE (SP) ÷ [18.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 000A ÷ 0308 × 200D ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM1_CM) × [9.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 000A ÷ 0308 × 0020 ÷ 200D ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] × 000A ÷ 00A7 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] SECTION SIGN (AI_AL) ÷ [0.3] × 000A ÷ 0020 ÷ 00A7 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] -× 000A ÷ 0308 × 00A7 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM) × [28.0] SECTION SIGN (AI_AL) ÷ [0.3] -× 000A ÷ 0308 × 0020 ÷ 00A7 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] +× 000A ÷ 0308 × 00A7 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM1_CM) × [28.0] SECTION SIGN (AI_AL) ÷ [0.3] +× 000A ÷ 0308 × 0020 ÷ 00A7 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] × 000A ÷ 50005 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] <reserved-50005> (XX_AL) ÷ [0.3] × 000A ÷ 0020 ÷ 50005 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] -× 000A ÷ 0308 × 50005 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM) × [28.0] <reserved-50005> (XX_AL) ÷ [0.3] -× 000A ÷ 0308 × 0020 ÷ 50005 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] +× 000A ÷ 0308 × 50005 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM1_CM) × [28.0] <reserved-50005> (XX_AL) ÷ [0.3] +× 000A ÷ 0308 × 0020 ÷ 50005 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] × 000A ÷ 0E01 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] × 000A ÷ 0020 ÷ 0E01 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] -× 000A ÷ 0308 × 0E01 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM) × [28.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] -× 000A ÷ 0308 × 0020 ÷ 0E01 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] +× 000A ÷ 0308 × 0E01 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM1_CM) × [28.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] +× 000A ÷ 0308 × 0020 ÷ 0E01 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] × 000A ÷ 3041 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] × 000A ÷ 0020 ÷ 3041 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] -× 000A ÷ 0308 × 3041 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] -× 000A ÷ 0308 × 0020 ÷ 3041 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] +× 000A ÷ 0308 × 3041 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM1_CM) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] +× 000A ÷ 0308 × 0020 ÷ 3041 ÷ # × [0.3] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] × 0085 ÷ 0023 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] NUMBER SIGN (AL) ÷ [0.3] × 0085 ÷ 0020 ÷ 0023 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] -× 0085 ÷ 0308 × 0023 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM) × [28.0] NUMBER SIGN (AL) ÷ [0.3] -× 0085 ÷ 0308 × 0020 ÷ 0023 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] +× 0085 ÷ 0308 × 0023 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM1_CM) × [28.0] NUMBER SIGN (AL) ÷ [0.3] +× 0085 ÷ 0308 × 0020 ÷ 0023 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] × 0085 ÷ 2014 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] EM DASH (B2) ÷ [0.3] × 0085 ÷ 0020 ÷ 2014 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] -× 0085 ÷ 0308 ÷ 2014 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM) ÷ [999.0] EM DASH (B2) ÷ [0.3] -× 0085 ÷ 0308 × 0020 ÷ 2014 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] +× 0085 ÷ 0308 ÷ 2014 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] EM DASH (B2) ÷ [0.3] +× 0085 ÷ 0308 × 0020 ÷ 2014 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] × 0085 ÷ 0009 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] <CHARACTER TABULATION> (BA) ÷ [0.3] × 0085 ÷ 0020 ÷ 0009 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] -× 0085 ÷ 0308 × 0009 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] -× 0085 ÷ 0308 × 0020 ÷ 0009 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] +× 0085 ÷ 0308 × 0009 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM1_CM) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] +× 0085 ÷ 0308 × 0020 ÷ 0009 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] × 0085 ÷ 00B4 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] ACUTE ACCENT (BB) ÷ [0.3] × 0085 ÷ 0020 ÷ 00B4 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] -× 0085 ÷ 0308 ÷ 00B4 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3] -× 0085 ÷ 0308 × 0020 ÷ 00B4 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] +× 0085 ÷ 0308 ÷ 00B4 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3] +× 0085 ÷ 0308 × 0020 ÷ 00B4 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] × 0085 ÷ 000B ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] <LINE TABULATION> (BK) ÷ [0.3] × 0085 ÷ 0020 × 000B ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] -× 0085 ÷ 0308 × 000B ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] -× 0085 ÷ 0308 × 0020 × 000B ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] +× 0085 ÷ 0308 × 000B ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM1_CM) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] +× 0085 ÷ 0308 × 0020 × 000B ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] × 0085 ÷ FFFC ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] × 0085 ÷ 0020 ÷ FFFC ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] -× 0085 ÷ 0308 ÷ FFFC ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] -× 0085 ÷ 0308 × 0020 ÷ FFFC ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] +× 0085 ÷ 0308 ÷ FFFC ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM1_CM) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] +× 0085 ÷ 0308 × 0020 ÷ FFFC ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] × 0085 ÷ 007D ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] RIGHT CURLY BRACKET (CL) ÷ [0.3] × 0085 ÷ 0020 × 007D ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] -× 0085 ÷ 0308 × 007D ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM) × [13.03] RIGHT CURLY BRACKET (CL) ÷ [0.3] -× 0085 ÷ 0308 × 0020 × 007D ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] +× 0085 ÷ 0308 × 007D ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM1_CM) × [13.03] RIGHT CURLY BRACKET (CL) ÷ [0.3] +× 0085 ÷ 0308 × 0020 × 007D ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] × 0085 ÷ 0029 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] RIGHT PARENTHESIS (CP) ÷ [0.3] × 0085 ÷ 0020 × 0029 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 0085 ÷ 0308 × 0029 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM) × [13.03] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 0085 ÷ 0308 × 0020 × 0029 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 0085 ÷ 0001 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] <START OF HEADING> (CM) ÷ [0.3] -× 0085 ÷ 0020 ÷ 0001 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM) ÷ [0.3] -× 0085 ÷ 0308 × 0001 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM) × [9.0] <START OF HEADING> (CM) ÷ [0.3] -× 0085 ÷ 0308 × 0020 ÷ 0001 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM) ÷ [0.3] +× 0085 ÷ 0308 × 0029 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM1_CM) × [13.03] RIGHT PARENTHESIS (CP) ÷ [0.3] +× 0085 ÷ 0308 × 0020 × 0029 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] × 0085 ÷ 000D ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] × 0085 ÷ 0020 × 000D ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -× 0085 ÷ 0308 × 000D ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -× 0085 ÷ 0308 × 0020 × 000D ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +× 0085 ÷ 0308 × 000D ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM1_CM) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +× 0085 ÷ 0308 × 0020 × 000D ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] × 0085 ÷ 0021 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] EXCLAMATION MARK (EX) ÷ [0.3] × 0085 ÷ 0020 × 0021 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] -× 0085 ÷ 0308 × 0021 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] -× 0085 ÷ 0308 × 0020 × 0021 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] +× 0085 ÷ 0308 × 0021 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM1_CM) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] +× 0085 ÷ 0308 × 0020 × 0021 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] × 0085 ÷ 00A0 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] NO-BREAK SPACE (GL) ÷ [0.3] × 0085 ÷ 0020 ÷ 00A0 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] -× 0085 ÷ 0308 × 00A0 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM) × [12.2] NO-BREAK SPACE (GL) ÷ [0.3] -× 0085 ÷ 0308 × 0020 ÷ 00A0 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] +× 0085 ÷ 0308 × 00A0 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM1_CM) × [12.2] NO-BREAK SPACE (GL) ÷ [0.3] +× 0085 ÷ 0308 × 0020 ÷ 00A0 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] × 0085 ÷ AC00 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] HANGUL SYLLABLE GA (H2) ÷ [0.3] × 0085 ÷ 0020 ÷ AC00 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] -× 0085 ÷ 0308 ÷ AC00 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] -× 0085 ÷ 0308 × 0020 ÷ AC00 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] +× 0085 ÷ 0308 ÷ AC00 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] +× 0085 ÷ 0308 × 0020 ÷ AC00 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] × 0085 ÷ AC01 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] HANGUL SYLLABLE GAG (H3) ÷ [0.3] × 0085 ÷ 0020 ÷ AC01 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] -× 0085 ÷ 0308 ÷ AC01 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] -× 0085 ÷ 0308 × 0020 ÷ AC01 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] +× 0085 ÷ 0308 ÷ AC01 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] +× 0085 ÷ 0308 × 0020 ÷ AC01 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] × 0085 ÷ 05D0 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] HEBREW LETTER ALEF (HL) ÷ [0.3] × 0085 ÷ 0020 ÷ 05D0 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] -× 0085 ÷ 0308 × 05D0 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM) × [28.0] HEBREW LETTER ALEF (HL) ÷ [0.3] -× 0085 ÷ 0308 × 0020 ÷ 05D0 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] +× 0085 ÷ 0308 × 05D0 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM1_CM) × [28.0] HEBREW LETTER ALEF (HL) ÷ [0.3] +× 0085 ÷ 0308 × 0020 ÷ 05D0 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] × 0085 ÷ 002D ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] HYPHEN-MINUS (HY) ÷ [0.3] × 0085 ÷ 0020 ÷ 002D ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] -× 0085 ÷ 0308 × 002D ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] -× 0085 ÷ 0308 × 0020 ÷ 002D ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] +× 0085 ÷ 0308 × 002D ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM1_CM) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] +× 0085 ÷ 0308 × 0020 ÷ 002D ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] × 0085 ÷ 231A ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] WATCH (ID) ÷ [0.3] × 0085 ÷ 0020 ÷ 231A ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] -× 0085 ÷ 0308 ÷ 231A ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM) ÷ [999.0] WATCH (ID) ÷ [0.3] -× 0085 ÷ 0308 × 0020 ÷ 231A ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] +× 0085 ÷ 0308 ÷ 231A ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] WATCH (ID) ÷ [0.3] +× 0085 ÷ 0308 × 0020 ÷ 231A ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] × 0085 ÷ 2024 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] ONE DOT LEADER (IN) ÷ [0.3] × 0085 ÷ 0020 ÷ 2024 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] -× 0085 ÷ 0308 × 2024 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM) × [22.01] ONE DOT LEADER (IN) ÷ [0.3] -× 0085 ÷ 0308 × 0020 ÷ 2024 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] +× 0085 ÷ 0308 × 2024 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM1_CM) × [22.01] ONE DOT LEADER (IN) ÷ [0.3] +× 0085 ÷ 0308 × 0020 ÷ 2024 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] × 0085 ÷ 002C ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMMA (IS) ÷ [0.3] × 0085 ÷ 0020 × 002C ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] -× 0085 ÷ 0308 × 002C ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM) × [13.03] COMMA (IS) ÷ [0.3] -× 0085 ÷ 0308 × 0020 × 002C ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] +× 0085 ÷ 0308 × 002C ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM1_CM) × [13.03] COMMA (IS) ÷ [0.3] +× 0085 ÷ 0308 × 0020 × 002C ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] × 0085 ÷ 1100 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] × 0085 ÷ 0020 ÷ 1100 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] -× 0085 ÷ 0308 ÷ 1100 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] -× 0085 ÷ 0308 × 0020 ÷ 1100 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] +× 0085 ÷ 0308 ÷ 1100 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] +× 0085 ÷ 0308 × 0020 ÷ 1100 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] × 0085 ÷ 11A8 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] × 0085 ÷ 0020 ÷ 11A8 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] -× 0085 ÷ 0308 ÷ 11A8 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] -× 0085 ÷ 0308 × 0020 ÷ 11A8 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] +× 0085 ÷ 0308 ÷ 11A8 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] +× 0085 ÷ 0308 × 0020 ÷ 11A8 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] × 0085 ÷ 1160 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] × 0085 ÷ 0020 ÷ 1160 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] -× 0085 ÷ 0308 ÷ 1160 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] -× 0085 ÷ 0308 × 0020 ÷ 1160 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] +× 0085 ÷ 0308 ÷ 1160 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] +× 0085 ÷ 0308 × 0020 ÷ 1160 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] × 0085 ÷ 000A ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] <LINE FEED (LF)> (LF) ÷ [0.3] × 0085 ÷ 0020 × 000A ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] -× 0085 ÷ 0308 × 000A ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] -× 0085 ÷ 0308 × 0020 × 000A ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] +× 0085 ÷ 0308 × 000A ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM1_CM) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] +× 0085 ÷ 0308 × 0020 × 000A ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] × 0085 ÷ 0085 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] <NEXT LINE (NEL)> (NL) ÷ [0.3] × 0085 ÷ 0020 × 0085 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] -× 0085 ÷ 0308 × 0085 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] -× 0085 ÷ 0308 × 0020 × 0085 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] +× 0085 ÷ 0308 × 0085 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM1_CM) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] +× 0085 ÷ 0308 × 0020 × 0085 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] × 0085 ÷ 17D6 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] × 0085 ÷ 0020 ÷ 17D6 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] -× 0085 ÷ 0308 × 17D6 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] -× 0085 ÷ 0308 × 0020 ÷ 17D6 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] +× 0085 ÷ 0308 × 17D6 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM1_CM) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] +× 0085 ÷ 0308 × 0020 ÷ 17D6 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] × 0085 ÷ 0030 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] DIGIT ZERO (NU) ÷ [0.3] × 0085 ÷ 0020 ÷ 0030 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] -× 0085 ÷ 0308 × 0030 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM) × [23.02] DIGIT ZERO (NU) ÷ [0.3] -× 0085 ÷ 0308 × 0020 ÷ 0030 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] +× 0085 ÷ 0308 × 0030 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM1_CM) × [23.02] DIGIT ZERO (NU) ÷ [0.3] +× 0085 ÷ 0308 × 0020 ÷ 0030 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] × 0085 ÷ 0028 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] LEFT PARENTHESIS (OP) ÷ [0.3] × 0085 ÷ 0020 ÷ 0028 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] -× 0085 ÷ 0308 × 0028 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM) × [30.01] LEFT PARENTHESIS (OP) ÷ [0.3] -× 0085 ÷ 0308 × 0020 ÷ 0028 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] +× 0085 ÷ 0308 × 0028 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM1_CM) × [30.01] LEFT PARENTHESIS (OP) ÷ [0.3] +× 0085 ÷ 0308 × 0020 ÷ 0028 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] × 0085 ÷ 0025 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] PERCENT SIGN (PO) ÷ [0.3] × 0085 ÷ 0020 ÷ 0025 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] -× 0085 ÷ 0308 ÷ 0025 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM) ÷ [999.0] PERCENT SIGN (PO) ÷ [0.3] -× 0085 ÷ 0308 × 0020 ÷ 0025 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] +× 0085 ÷ 0308 × 0025 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM1_CM) × [24.03] PERCENT SIGN (PO) ÷ [0.3] +× 0085 ÷ 0308 × 0020 ÷ 0025 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] × 0085 ÷ 0024 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] DOLLAR SIGN (PR) ÷ [0.3] × 0085 ÷ 0020 ÷ 0024 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] -× 0085 ÷ 0308 ÷ 0024 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM) ÷ [999.0] DOLLAR SIGN (PR) ÷ [0.3] -× 0085 ÷ 0308 × 0020 ÷ 0024 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] +× 0085 ÷ 0308 × 0024 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM1_CM) × [24.03] DOLLAR SIGN (PR) ÷ [0.3] +× 0085 ÷ 0308 × 0020 ÷ 0024 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] × 0085 ÷ 0022 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] QUOTATION MARK (QU) ÷ [0.3] × 0085 ÷ 0020 ÷ 0022 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] -× 0085 ÷ 0308 × 0022 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM) × [19.01] QUOTATION MARK (QU) ÷ [0.3] -× 0085 ÷ 0308 × 0020 ÷ 0022 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] +× 0085 ÷ 0308 × 0022 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM1_CM) × [19.01] QUOTATION MARK (QU) ÷ [0.3] +× 0085 ÷ 0308 × 0020 ÷ 0022 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] × 0085 ÷ 0020 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] SPACE (SP) ÷ [0.3] × 0085 ÷ 0020 × 0020 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] -× 0085 ÷ 0308 × 0020 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [0.3] -× 0085 ÷ 0308 × 0020 × 0020 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] +× 0085 ÷ 0308 × 0020 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [0.3] +× 0085 ÷ 0308 × 0020 × 0020 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] × 0085 ÷ 002F ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] SOLIDUS (SY) ÷ [0.3] × 0085 ÷ 0020 × 002F ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] -× 0085 ÷ 0308 × 002F ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM) × [13.03] SOLIDUS (SY) ÷ [0.3] -× 0085 ÷ 0308 × 0020 × 002F ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] +× 0085 ÷ 0308 × 002F ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM1_CM) × [13.03] SOLIDUS (SY) ÷ [0.3] +× 0085 ÷ 0308 × 0020 × 002F ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] × 0085 ÷ 2060 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] WORD JOINER (WJ) ÷ [0.3] × 0085 ÷ 0020 × 2060 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] -× 0085 ÷ 0308 × 2060 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM) × [11.01] WORD JOINER (WJ) ÷ [0.3] -× 0085 ÷ 0308 × 0020 × 2060 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] +× 0085 ÷ 0308 × 2060 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM1_CM) × [11.01] WORD JOINER (WJ) ÷ [0.3] +× 0085 ÷ 0308 × 0020 × 2060 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] × 0085 ÷ 200B ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] ZERO WIDTH SPACE (ZW) ÷ [0.3] × 0085 ÷ 0020 × 200B ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] -× 0085 ÷ 0308 × 200B ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] -× 0085 ÷ 0308 × 0020 × 200B ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] +× 0085 ÷ 0308 × 200B ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM1_CM) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] +× 0085 ÷ 0308 × 0020 × 200B ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] × 0085 ÷ 1F1E6 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] × 0085 ÷ 0020 ÷ 1F1E6 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -× 0085 ÷ 0308 ÷ 1F1E6 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -× 0085 ÷ 0308 × 0020 ÷ 1F1E6 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 0085 ÷ 0308 ÷ 1F1E6 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 0085 ÷ 0308 × 0020 ÷ 1F1E6 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 0085 ÷ 261D ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 0085 ÷ 0020 ÷ 261D ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] SPACE (SP) ÷ [18.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 0085 ÷ 0308 ÷ 261D ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 0085 ÷ 0308 × 0020 ÷ 261D ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 0085 ÷ 1F3FB ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 0085 ÷ 0020 ÷ 1F3FB ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] SPACE (SP) ÷ [18.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 0085 ÷ 0308 ÷ 1F3FB ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 0085 ÷ 0308 × 0020 ÷ 1F3FB ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 0085 ÷ 0001 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 0085 ÷ 0020 ÷ 0001 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 0085 ÷ 0308 × 0001 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM1_CM) × [9.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 0085 ÷ 0308 × 0020 ÷ 0001 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 0085 ÷ 200D ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 0085 ÷ 0020 ÷ 200D ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] SPACE (SP) ÷ [18.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 0085 ÷ 0308 × 200D ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM1_CM) × [9.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 0085 ÷ 0308 × 0020 ÷ 200D ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] × 0085 ÷ 00A7 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] SECTION SIGN (AI_AL) ÷ [0.3] × 0085 ÷ 0020 ÷ 00A7 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] -× 0085 ÷ 0308 × 00A7 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM) × [28.0] SECTION SIGN (AI_AL) ÷ [0.3] -× 0085 ÷ 0308 × 0020 ÷ 00A7 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] +× 0085 ÷ 0308 × 00A7 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM1_CM) × [28.0] SECTION SIGN (AI_AL) ÷ [0.3] +× 0085 ÷ 0308 × 0020 ÷ 00A7 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] × 0085 ÷ 50005 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] <reserved-50005> (XX_AL) ÷ [0.3] × 0085 ÷ 0020 ÷ 50005 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] -× 0085 ÷ 0308 × 50005 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM) × [28.0] <reserved-50005> (XX_AL) ÷ [0.3] -× 0085 ÷ 0308 × 0020 ÷ 50005 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] +× 0085 ÷ 0308 × 50005 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM1_CM) × [28.0] <reserved-50005> (XX_AL) ÷ [0.3] +× 0085 ÷ 0308 × 0020 ÷ 50005 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] × 0085 ÷ 0E01 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] × 0085 ÷ 0020 ÷ 0E01 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] -× 0085 ÷ 0308 × 0E01 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM) × [28.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] -× 0085 ÷ 0308 × 0020 ÷ 0E01 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] +× 0085 ÷ 0308 × 0E01 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM1_CM) × [28.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] +× 0085 ÷ 0308 × 0020 ÷ 0E01 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] × 0085 ÷ 3041 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] × 0085 ÷ 0020 ÷ 3041 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] -× 0085 ÷ 0308 × 3041 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] -× 0085 ÷ 0308 × 0020 ÷ 3041 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] +× 0085 ÷ 0308 × 3041 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM1_CM) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] +× 0085 ÷ 0308 × 0020 ÷ 3041 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] × 17D6 ÷ 0023 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [999.0] NUMBER SIGN (AL) ÷ [0.3] × 17D6 × 0020 ÷ 0023 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] -× 17D6 × 0308 ÷ 0023 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] NUMBER SIGN (AL) ÷ [0.3] -× 17D6 × 0308 × 0020 ÷ 0023 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] +× 17D6 × 0308 ÷ 0023 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] NUMBER SIGN (AL) ÷ [0.3] +× 17D6 × 0308 × 0020 ÷ 0023 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] × 17D6 ÷ 2014 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [999.0] EM DASH (B2) ÷ [0.3] × 17D6 × 0020 ÷ 2014 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] -× 17D6 × 0308 ÷ 2014 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] EM DASH (B2) ÷ [0.3] -× 17D6 × 0308 × 0020 ÷ 2014 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] +× 17D6 × 0308 ÷ 2014 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] EM DASH (B2) ÷ [0.3] +× 17D6 × 0308 × 0020 ÷ 2014 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] × 17D6 × 0009 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] × 17D6 × 0020 ÷ 0009 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] -× 17D6 × 0308 × 0009 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] -× 17D6 × 0308 × 0020 ÷ 0009 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] +× 17D6 × 0308 × 0009 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] +× 17D6 × 0308 × 0020 ÷ 0009 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] × 17D6 ÷ 00B4 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3] × 17D6 × 0020 ÷ 00B4 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] -× 17D6 × 0308 ÷ 00B4 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3] -× 17D6 × 0308 × 0020 ÷ 00B4 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] +× 17D6 × 0308 ÷ 00B4 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3] +× 17D6 × 0308 × 0020 ÷ 00B4 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] × 17D6 × 000B ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] × 17D6 × 0020 × 000B ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] -× 17D6 × 0308 × 000B ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] -× 17D6 × 0308 × 0020 × 000B ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] +× 17D6 × 0308 × 000B ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] +× 17D6 × 0308 × 0020 × 000B ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] × 17D6 ÷ FFFC ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] × 17D6 × 0020 ÷ FFFC ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] -× 17D6 × 0308 ÷ FFFC ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] -× 17D6 × 0308 × 0020 ÷ FFFC ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] +× 17D6 × 0308 ÷ FFFC ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] +× 17D6 × 0308 × 0020 ÷ FFFC ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] × 17D6 × 007D ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] × 17D6 × 0020 × 007D ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] -× 17D6 × 0308 × 007D ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM) × [13.03] RIGHT CURLY BRACKET (CL) ÷ [0.3] -× 17D6 × 0308 × 0020 × 007D ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] +× 17D6 × 0308 × 007D ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] RIGHT CURLY BRACKET (CL) ÷ [0.3] +× 17D6 × 0308 × 0020 × 007D ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] × 17D6 × 0029 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] × 17D6 × 0020 × 0029 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 17D6 × 0308 × 0029 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM) × [13.03] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 17D6 × 0308 × 0020 × 0029 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 17D6 × 0001 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] <START OF HEADING> (CM) ÷ [0.3] -× 17D6 × 0020 ÷ 0001 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM) ÷ [0.3] -× 17D6 × 0308 × 0001 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM) × [9.0] <START OF HEADING> (CM) ÷ [0.3] -× 17D6 × 0308 × 0020 ÷ 0001 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM) ÷ [0.3] +× 17D6 × 0308 × 0029 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] RIGHT PARENTHESIS (CP) ÷ [0.3] +× 17D6 × 0308 × 0020 × 0029 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] × 17D6 × 000D ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] × 17D6 × 0020 × 000D ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -× 17D6 × 0308 × 000D ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -× 17D6 × 0308 × 0020 × 000D ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +× 17D6 × 0308 × 000D ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +× 17D6 × 0308 × 0020 × 000D ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] × 17D6 × 0021 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] × 17D6 × 0020 × 0021 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] -× 17D6 × 0308 × 0021 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] -× 17D6 × 0308 × 0020 × 0021 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] +× 17D6 × 0308 × 0021 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] +× 17D6 × 0308 × 0020 × 0021 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] × 17D6 × 00A0 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [12.1] NO-BREAK SPACE (GL) ÷ [0.3] × 17D6 × 0020 ÷ 00A0 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] -× 17D6 × 0308 × 00A0 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM) × [12.2] NO-BREAK SPACE (GL) ÷ [0.3] -× 17D6 × 0308 × 0020 ÷ 00A0 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] +× 17D6 × 0308 × 00A0 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [12.2] NO-BREAK SPACE (GL) ÷ [0.3] +× 17D6 × 0308 × 0020 ÷ 00A0 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] × 17D6 ÷ AC00 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [999.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] × 17D6 × 0020 ÷ AC00 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] -× 17D6 × 0308 ÷ AC00 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] -× 17D6 × 0308 × 0020 ÷ AC00 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] +× 17D6 × 0308 ÷ AC00 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] +× 17D6 × 0308 × 0020 ÷ AC00 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] × 17D6 ÷ AC01 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [999.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] × 17D6 × 0020 ÷ AC01 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] -× 17D6 × 0308 ÷ AC01 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] -× 17D6 × 0308 × 0020 ÷ AC01 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] +× 17D6 × 0308 ÷ AC01 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] +× 17D6 × 0308 × 0020 ÷ AC01 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] × 17D6 ÷ 05D0 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [999.0] HEBREW LETTER ALEF (HL) ÷ [0.3] × 17D6 × 0020 ÷ 05D0 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] -× 17D6 × 0308 ÷ 05D0 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HEBREW LETTER ALEF (HL) ÷ [0.3] -× 17D6 × 0308 × 0020 ÷ 05D0 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] +× 17D6 × 0308 ÷ 05D0 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HEBREW LETTER ALEF (HL) ÷ [0.3] +× 17D6 × 0308 × 0020 ÷ 05D0 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] × 17D6 × 002D ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] × 17D6 × 0020 ÷ 002D ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] -× 17D6 × 0308 × 002D ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] -× 17D6 × 0308 × 0020 ÷ 002D ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] +× 17D6 × 0308 × 002D ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] +× 17D6 × 0308 × 0020 ÷ 002D ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] × 17D6 ÷ 231A ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [999.0] WATCH (ID) ÷ [0.3] × 17D6 × 0020 ÷ 231A ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] -× 17D6 × 0308 ÷ 231A ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] WATCH (ID) ÷ [0.3] -× 17D6 × 0308 × 0020 ÷ 231A ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] +× 17D6 × 0308 ÷ 231A ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] WATCH (ID) ÷ [0.3] +× 17D6 × 0308 × 0020 ÷ 231A ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] × 17D6 ÷ 2024 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [999.0] ONE DOT LEADER (IN) ÷ [0.3] × 17D6 × 0020 ÷ 2024 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] -× 17D6 × 0308 ÷ 2024 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] ONE DOT LEADER (IN) ÷ [0.3] -× 17D6 × 0308 × 0020 ÷ 2024 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] +× 17D6 × 0308 ÷ 2024 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] ONE DOT LEADER (IN) ÷ [0.3] +× 17D6 × 0308 × 0020 ÷ 2024 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] × 17D6 × 002C ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [13.02] COMMA (IS) ÷ [0.3] × 17D6 × 0020 × 002C ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] -× 17D6 × 0308 × 002C ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM) × [13.03] COMMA (IS) ÷ [0.3] -× 17D6 × 0308 × 0020 × 002C ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] +× 17D6 × 0308 × 002C ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] COMMA (IS) ÷ [0.3] +× 17D6 × 0308 × 0020 × 002C ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] × 17D6 ÷ 1100 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [999.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] × 17D6 × 0020 ÷ 1100 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] -× 17D6 × 0308 ÷ 1100 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] -× 17D6 × 0308 × 0020 ÷ 1100 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] +× 17D6 × 0308 ÷ 1100 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] +× 17D6 × 0308 × 0020 ÷ 1100 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] × 17D6 ÷ 11A8 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [999.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] × 17D6 × 0020 ÷ 11A8 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] -× 17D6 × 0308 ÷ 11A8 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] -× 17D6 × 0308 × 0020 ÷ 11A8 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] +× 17D6 × 0308 ÷ 11A8 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] +× 17D6 × 0308 × 0020 ÷ 11A8 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] × 17D6 ÷ 1160 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [999.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] × 17D6 × 0020 ÷ 1160 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] -× 17D6 × 0308 ÷ 1160 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] -× 17D6 × 0308 × 0020 ÷ 1160 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] +× 17D6 × 0308 ÷ 1160 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] +× 17D6 × 0308 × 0020 ÷ 1160 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] × 17D6 × 000A ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] × 17D6 × 0020 × 000A ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] -× 17D6 × 0308 × 000A ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] -× 17D6 × 0308 × 0020 × 000A ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] +× 17D6 × 0308 × 000A ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] +× 17D6 × 0308 × 0020 × 000A ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] × 17D6 × 0085 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] × 17D6 × 0020 × 0085 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] -× 17D6 × 0308 × 0085 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] -× 17D6 × 0308 × 0020 × 0085 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] +× 17D6 × 0308 × 0085 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] +× 17D6 × 0308 × 0020 × 0085 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] × 17D6 × 17D6 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] × 17D6 × 0020 ÷ 17D6 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] -× 17D6 × 0308 × 17D6 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] -× 17D6 × 0308 × 0020 ÷ 17D6 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] +× 17D6 × 0308 × 17D6 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] +× 17D6 × 0308 × 0020 ÷ 17D6 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] × 17D6 ÷ 0030 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [999.0] DIGIT ZERO (NU) ÷ [0.3] × 17D6 × 0020 ÷ 0030 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] -× 17D6 × 0308 ÷ 0030 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] DIGIT ZERO (NU) ÷ [0.3] -× 17D6 × 0308 × 0020 ÷ 0030 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] +× 17D6 × 0308 ÷ 0030 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] DIGIT ZERO (NU) ÷ [0.3] +× 17D6 × 0308 × 0020 ÷ 0030 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] × 17D6 ÷ 0028 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [999.0] LEFT PARENTHESIS (OP) ÷ [0.3] × 17D6 × 0020 ÷ 0028 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] -× 17D6 × 0308 ÷ 0028 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] LEFT PARENTHESIS (OP) ÷ [0.3] -× 17D6 × 0308 × 0020 ÷ 0028 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] +× 17D6 × 0308 ÷ 0028 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] LEFT PARENTHESIS (OP) ÷ [0.3] +× 17D6 × 0308 × 0020 ÷ 0028 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] × 17D6 ÷ 0025 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [999.0] PERCENT SIGN (PO) ÷ [0.3] × 17D6 × 0020 ÷ 0025 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] -× 17D6 × 0308 ÷ 0025 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] PERCENT SIGN (PO) ÷ [0.3] -× 17D6 × 0308 × 0020 ÷ 0025 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] +× 17D6 × 0308 ÷ 0025 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] PERCENT SIGN (PO) ÷ [0.3] +× 17D6 × 0308 × 0020 ÷ 0025 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] × 17D6 ÷ 0024 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [999.0] DOLLAR SIGN (PR) ÷ [0.3] × 17D6 × 0020 ÷ 0024 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] -× 17D6 × 0308 ÷ 0024 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] DOLLAR SIGN (PR) ÷ [0.3] -× 17D6 × 0308 × 0020 ÷ 0024 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] +× 17D6 × 0308 ÷ 0024 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] DOLLAR SIGN (PR) ÷ [0.3] +× 17D6 × 0308 × 0020 ÷ 0024 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] × 17D6 × 0022 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [19.01] QUOTATION MARK (QU) ÷ [0.3] × 17D6 × 0020 ÷ 0022 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] -× 17D6 × 0308 × 0022 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM) × [19.01] QUOTATION MARK (QU) ÷ [0.3] -× 17D6 × 0308 × 0020 ÷ 0022 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] +× 17D6 × 0308 × 0022 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [19.01] QUOTATION MARK (QU) ÷ [0.3] +× 17D6 × 0308 × 0020 ÷ 0022 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] × 17D6 × 0020 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [7.01] SPACE (SP) ÷ [0.3] × 17D6 × 0020 × 0020 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] -× 17D6 × 0308 × 0020 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [0.3] -× 17D6 × 0308 × 0020 × 0020 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] +× 17D6 × 0308 × 0020 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [0.3] +× 17D6 × 0308 × 0020 × 0020 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] × 17D6 × 002F ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [13.02] SOLIDUS (SY) ÷ [0.3] × 17D6 × 0020 × 002F ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] -× 17D6 × 0308 × 002F ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM) × [13.03] SOLIDUS (SY) ÷ [0.3] -× 17D6 × 0308 × 0020 × 002F ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] +× 17D6 × 0308 × 002F ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] SOLIDUS (SY) ÷ [0.3] +× 17D6 × 0308 × 0020 × 002F ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] × 17D6 × 2060 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [11.01] WORD JOINER (WJ) ÷ [0.3] × 17D6 × 0020 × 2060 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] -× 17D6 × 0308 × 2060 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM) × [11.01] WORD JOINER (WJ) ÷ [0.3] -× 17D6 × 0308 × 0020 × 2060 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] +× 17D6 × 0308 × 2060 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [11.01] WORD JOINER (WJ) ÷ [0.3] +× 17D6 × 0308 × 0020 × 2060 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] × 17D6 × 200B ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] × 17D6 × 0020 × 200B ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] -× 17D6 × 0308 × 200B ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] -× 17D6 × 0308 × 0020 × 200B ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] +× 17D6 × 0308 × 200B ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] +× 17D6 × 0308 × 0020 × 200B ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] × 17D6 ÷ 1F1E6 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] × 17D6 × 0020 ÷ 1F1E6 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -× 17D6 × 0308 ÷ 1F1E6 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -× 17D6 × 0308 × 0020 ÷ 1F1E6 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 17D6 × 0308 ÷ 1F1E6 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 17D6 × 0308 × 0020 ÷ 1F1E6 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 17D6 ÷ 261D ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [999.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 17D6 × 0020 ÷ 261D ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [7.01] SPACE (SP) ÷ [18.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 17D6 × 0308 ÷ 261D ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 17D6 × 0308 × 0020 ÷ 261D ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 17D6 ÷ 1F3FB ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 17D6 × 0020 ÷ 1F3FB ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [7.01] SPACE (SP) ÷ [18.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 17D6 × 0308 ÷ 1F3FB ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 17D6 × 0308 × 0020 ÷ 1F3FB ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 17D6 × 0001 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 17D6 × 0020 ÷ 0001 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 17D6 × 0308 × 0001 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [9.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 17D6 × 0308 × 0020 ÷ 0001 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 17D6 × 200D ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 17D6 × 0020 ÷ 200D ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [7.01] SPACE (SP) ÷ [18.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 17D6 × 0308 × 200D ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [9.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 17D6 × 0308 × 0020 ÷ 200D ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] × 17D6 ÷ 00A7 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [999.0] SECTION SIGN (AI_AL) ÷ [0.3] × 17D6 × 0020 ÷ 00A7 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] -× 17D6 × 0308 ÷ 00A7 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] SECTION SIGN (AI_AL) ÷ [0.3] -× 17D6 × 0308 × 0020 ÷ 00A7 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] +× 17D6 × 0308 ÷ 00A7 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] SECTION SIGN (AI_AL) ÷ [0.3] +× 17D6 × 0308 × 0020 ÷ 00A7 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] × 17D6 ÷ 50005 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [999.0] <reserved-50005> (XX_AL) ÷ [0.3] × 17D6 × 0020 ÷ 50005 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] -× 17D6 × 0308 ÷ 50005 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] <reserved-50005> (XX_AL) ÷ [0.3] -× 17D6 × 0308 × 0020 ÷ 50005 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] +× 17D6 × 0308 ÷ 50005 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] <reserved-50005> (XX_AL) ÷ [0.3] +× 17D6 × 0308 × 0020 ÷ 50005 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] × 17D6 ÷ 0E01 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [999.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] × 17D6 × 0020 ÷ 0E01 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] -× 17D6 × 0308 ÷ 0E01 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] -× 17D6 × 0308 × 0020 ÷ 0E01 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] +× 17D6 × 0308 ÷ 0E01 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] +× 17D6 × 0308 × 0020 ÷ 0E01 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] × 17D6 × 3041 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] × 17D6 × 0020 ÷ 3041 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] -× 17D6 × 0308 × 3041 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] -× 17D6 × 0308 × 0020 ÷ 3041 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] +× 17D6 × 0308 × 3041 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] +× 17D6 × 0308 × 0020 ÷ 3041 ÷ # × [0.3] KHMER SIGN CAMNUC PII KUUH (NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] × 0030 × 0023 ÷ # × [0.3] DIGIT ZERO (NU) × [23.03] NUMBER SIGN (AL) ÷ [0.3] × 0030 × 0020 ÷ 0023 ÷ # × [0.3] DIGIT ZERO (NU) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] -× 0030 × 0308 × 0023 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM) × [23.03] NUMBER SIGN (AL) ÷ [0.3] -× 0030 × 0308 × 0020 ÷ 0023 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] +× 0030 × 0308 × 0023 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [23.03] NUMBER SIGN (AL) ÷ [0.3] +× 0030 × 0308 × 0020 ÷ 0023 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] × 0030 ÷ 2014 ÷ # × [0.3] DIGIT ZERO (NU) ÷ [999.0] EM DASH (B2) ÷ [0.3] × 0030 × 0020 ÷ 2014 ÷ # × [0.3] DIGIT ZERO (NU) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] -× 0030 × 0308 ÷ 2014 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] EM DASH (B2) ÷ [0.3] -× 0030 × 0308 × 0020 ÷ 2014 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] +× 0030 × 0308 ÷ 2014 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] EM DASH (B2) ÷ [0.3] +× 0030 × 0308 × 0020 ÷ 2014 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] × 0030 × 0009 ÷ # × [0.3] DIGIT ZERO (NU) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] × 0030 × 0020 ÷ 0009 ÷ # × [0.3] DIGIT ZERO (NU) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] -× 0030 × 0308 × 0009 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] -× 0030 × 0308 × 0020 ÷ 0009 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] +× 0030 × 0308 × 0009 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] +× 0030 × 0308 × 0020 ÷ 0009 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] × 0030 ÷ 00B4 ÷ # × [0.3] DIGIT ZERO (NU) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3] × 0030 × 0020 ÷ 00B4 ÷ # × [0.3] DIGIT ZERO (NU) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] -× 0030 × 0308 ÷ 00B4 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3] -× 0030 × 0308 × 0020 ÷ 00B4 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] +× 0030 × 0308 ÷ 00B4 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3] +× 0030 × 0308 × 0020 ÷ 00B4 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] × 0030 × 000B ÷ # × [0.3] DIGIT ZERO (NU) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] × 0030 × 0020 × 000B ÷ # × [0.3] DIGIT ZERO (NU) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] -× 0030 × 0308 × 000B ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] -× 0030 × 0308 × 0020 × 000B ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] +× 0030 × 0308 × 000B ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] +× 0030 × 0308 × 0020 × 000B ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] × 0030 ÷ FFFC ÷ # × [0.3] DIGIT ZERO (NU) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] × 0030 × 0020 ÷ FFFC ÷ # × [0.3] DIGIT ZERO (NU) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] -× 0030 × 0308 ÷ FFFC ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] -× 0030 × 0308 × 0020 ÷ FFFC ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] +× 0030 × 0308 ÷ FFFC ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] +× 0030 × 0308 × 0020 ÷ FFFC ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] × 0030 × 007D ÷ # × [0.3] DIGIT ZERO (NU) × [25.04] RIGHT CURLY BRACKET (CL) ÷ [0.3] × 0030 × 0020 × 007D ÷ # × [0.3] DIGIT ZERO (NU) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] -× 0030 × 0308 × 007D ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM) × [25.04] RIGHT CURLY BRACKET (CL) ÷ [0.3] -× 0030 × 0308 × 0020 × 007D ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] +× 0030 × 0308 × 007D ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [25.04] RIGHT CURLY BRACKET (CL) ÷ [0.3] +× 0030 × 0308 × 0020 × 007D ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] × 0030 × 0029 ÷ # × [0.3] DIGIT ZERO (NU) × [25.04] RIGHT PARENTHESIS (CP) ÷ [0.3] × 0030 × 0020 × 0029 ÷ # × [0.3] DIGIT ZERO (NU) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 0030 × 0308 × 0029 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM) × [25.04] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 0030 × 0308 × 0020 × 0029 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 0030 × 0001 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] <START OF HEADING> (CM) ÷ [0.3] -× 0030 × 0020 ÷ 0001 ÷ # × [0.3] DIGIT ZERO (NU) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM) ÷ [0.3] -× 0030 × 0308 × 0001 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM) × [9.0] <START OF HEADING> (CM) ÷ [0.3] -× 0030 × 0308 × 0020 ÷ 0001 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM) ÷ [0.3] +× 0030 × 0308 × 0029 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [25.04] RIGHT PARENTHESIS (CP) ÷ [0.3] +× 0030 × 0308 × 0020 × 0029 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] × 0030 × 000D ÷ # × [0.3] DIGIT ZERO (NU) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] × 0030 × 0020 × 000D ÷ # × [0.3] DIGIT ZERO (NU) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -× 0030 × 0308 × 000D ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -× 0030 × 0308 × 0020 × 000D ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +× 0030 × 0308 × 000D ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +× 0030 × 0308 × 0020 × 000D ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] × 0030 × 0021 ÷ # × [0.3] DIGIT ZERO (NU) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] × 0030 × 0020 × 0021 ÷ # × [0.3] DIGIT ZERO (NU) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] -× 0030 × 0308 × 0021 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] -× 0030 × 0308 × 0020 × 0021 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] +× 0030 × 0308 × 0021 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] +× 0030 × 0308 × 0020 × 0021 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] × 0030 × 00A0 ÷ # × [0.3] DIGIT ZERO (NU) × [12.1] NO-BREAK SPACE (GL) ÷ [0.3] × 0030 × 0020 ÷ 00A0 ÷ # × [0.3] DIGIT ZERO (NU) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] -× 0030 × 0308 × 00A0 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM) × [12.2] NO-BREAK SPACE (GL) ÷ [0.3] -× 0030 × 0308 × 0020 ÷ 00A0 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] +× 0030 × 0308 × 00A0 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [12.2] NO-BREAK SPACE (GL) ÷ [0.3] +× 0030 × 0308 × 0020 ÷ 00A0 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] × 0030 ÷ AC00 ÷ # × [0.3] DIGIT ZERO (NU) ÷ [999.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] × 0030 × 0020 ÷ AC00 ÷ # × [0.3] DIGIT ZERO (NU) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] -× 0030 × 0308 ÷ AC00 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] -× 0030 × 0308 × 0020 ÷ AC00 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] +× 0030 × 0308 ÷ AC00 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] +× 0030 × 0308 × 0020 ÷ AC00 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] × 0030 ÷ AC01 ÷ # × [0.3] DIGIT ZERO (NU) ÷ [999.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] × 0030 × 0020 ÷ AC01 ÷ # × [0.3] DIGIT ZERO (NU) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] -× 0030 × 0308 ÷ AC01 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] -× 0030 × 0308 × 0020 ÷ AC01 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] +× 0030 × 0308 ÷ AC01 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] +× 0030 × 0308 × 0020 ÷ AC01 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] × 0030 × 05D0 ÷ # × [0.3] DIGIT ZERO (NU) × [23.03] HEBREW LETTER ALEF (HL) ÷ [0.3] × 0030 × 0020 ÷ 05D0 ÷ # × [0.3] DIGIT ZERO (NU) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] -× 0030 × 0308 × 05D0 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM) × [23.03] HEBREW LETTER ALEF (HL) ÷ [0.3] -× 0030 × 0308 × 0020 ÷ 05D0 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] +× 0030 × 0308 × 05D0 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [23.03] HEBREW LETTER ALEF (HL) ÷ [0.3] +× 0030 × 0308 × 0020 ÷ 05D0 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] × 0030 × 002D ÷ # × [0.3] DIGIT ZERO (NU) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] × 0030 × 0020 ÷ 002D ÷ # × [0.3] DIGIT ZERO (NU) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] -× 0030 × 0308 × 002D ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] -× 0030 × 0308 × 0020 ÷ 002D ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] +× 0030 × 0308 × 002D ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] +× 0030 × 0308 × 0020 ÷ 002D ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] × 0030 ÷ 231A ÷ # × [0.3] DIGIT ZERO (NU) ÷ [999.0] WATCH (ID) ÷ [0.3] × 0030 × 0020 ÷ 231A ÷ # × [0.3] DIGIT ZERO (NU) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] -× 0030 × 0308 ÷ 231A ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] WATCH (ID) ÷ [0.3] -× 0030 × 0308 × 0020 ÷ 231A ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] +× 0030 × 0308 ÷ 231A ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] WATCH (ID) ÷ [0.3] +× 0030 × 0308 × 0020 ÷ 231A ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] × 0030 × 2024 ÷ # × [0.3] DIGIT ZERO (NU) × [22.05] ONE DOT LEADER (IN) ÷ [0.3] × 0030 × 0020 ÷ 2024 ÷ # × [0.3] DIGIT ZERO (NU) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] -× 0030 × 0308 × 2024 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM) × [22.05] ONE DOT LEADER (IN) ÷ [0.3] -× 0030 × 0308 × 0020 ÷ 2024 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] +× 0030 × 0308 × 2024 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [22.05] ONE DOT LEADER (IN) ÷ [0.3] +× 0030 × 0308 × 0020 ÷ 2024 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] × 0030 × 002C ÷ # × [0.3] DIGIT ZERO (NU) × [25.03] COMMA (IS) ÷ [0.3] × 0030 × 0020 × 002C ÷ # × [0.3] DIGIT ZERO (NU) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] -× 0030 × 0308 × 002C ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM) × [25.03] COMMA (IS) ÷ [0.3] -× 0030 × 0308 × 0020 × 002C ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] +× 0030 × 0308 × 002C ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [25.03] COMMA (IS) ÷ [0.3] +× 0030 × 0308 × 0020 × 002C ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] × 0030 ÷ 1100 ÷ # × [0.3] DIGIT ZERO (NU) ÷ [999.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] × 0030 × 0020 ÷ 1100 ÷ # × [0.3] DIGIT ZERO (NU) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] -× 0030 × 0308 ÷ 1100 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] -× 0030 × 0308 × 0020 ÷ 1100 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] +× 0030 × 0308 ÷ 1100 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] +× 0030 × 0308 × 0020 ÷ 1100 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] × 0030 ÷ 11A8 ÷ # × [0.3] DIGIT ZERO (NU) ÷ [999.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] × 0030 × 0020 ÷ 11A8 ÷ # × [0.3] DIGIT ZERO (NU) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] -× 0030 × 0308 ÷ 11A8 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] -× 0030 × 0308 × 0020 ÷ 11A8 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] +× 0030 × 0308 ÷ 11A8 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] +× 0030 × 0308 × 0020 ÷ 11A8 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] × 0030 ÷ 1160 ÷ # × [0.3] DIGIT ZERO (NU) ÷ [999.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] × 0030 × 0020 ÷ 1160 ÷ # × [0.3] DIGIT ZERO (NU) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] -× 0030 × 0308 ÷ 1160 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] -× 0030 × 0308 × 0020 ÷ 1160 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] +× 0030 × 0308 ÷ 1160 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] +× 0030 × 0308 × 0020 ÷ 1160 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] × 0030 × 000A ÷ # × [0.3] DIGIT ZERO (NU) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] × 0030 × 0020 × 000A ÷ # × [0.3] DIGIT ZERO (NU) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] -× 0030 × 0308 × 000A ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] -× 0030 × 0308 × 0020 × 000A ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] +× 0030 × 0308 × 000A ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] +× 0030 × 0308 × 0020 × 000A ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] × 0030 × 0085 ÷ # × [0.3] DIGIT ZERO (NU) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] × 0030 × 0020 × 0085 ÷ # × [0.3] DIGIT ZERO (NU) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] -× 0030 × 0308 × 0085 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] -× 0030 × 0308 × 0020 × 0085 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] +× 0030 × 0308 × 0085 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] +× 0030 × 0308 × 0020 × 0085 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] × 0030 × 17D6 ÷ # × [0.3] DIGIT ZERO (NU) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] × 0030 × 0020 ÷ 17D6 ÷ # × [0.3] DIGIT ZERO (NU) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] -× 0030 × 0308 × 17D6 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] -× 0030 × 0308 × 0020 ÷ 17D6 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] +× 0030 × 0308 × 17D6 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] +× 0030 × 0308 × 0020 ÷ 17D6 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] × 0030 × 0030 ÷ # × [0.3] DIGIT ZERO (NU) × [25.03] DIGIT ZERO (NU) ÷ [0.3] × 0030 × 0020 ÷ 0030 ÷ # × [0.3] DIGIT ZERO (NU) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] -× 0030 × 0308 × 0030 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM) × [25.03] DIGIT ZERO (NU) ÷ [0.3] -× 0030 × 0308 × 0020 ÷ 0030 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] +× 0030 × 0308 × 0030 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [25.03] DIGIT ZERO (NU) ÷ [0.3] +× 0030 × 0308 × 0020 ÷ 0030 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] × 0030 × 0028 ÷ # × [0.3] DIGIT ZERO (NU) × [30.01] LEFT PARENTHESIS (OP) ÷ [0.3] × 0030 × 0020 ÷ 0028 ÷ # × [0.3] DIGIT ZERO (NU) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] -× 0030 × 0308 × 0028 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM) × [30.01] LEFT PARENTHESIS (OP) ÷ [0.3] -× 0030 × 0308 × 0020 ÷ 0028 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] +× 0030 × 0308 × 0028 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [30.01] LEFT PARENTHESIS (OP) ÷ [0.3] +× 0030 × 0308 × 0020 ÷ 0028 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] × 0030 × 0025 ÷ # × [0.3] DIGIT ZERO (NU) × [25.05] PERCENT SIGN (PO) ÷ [0.3] × 0030 × 0020 ÷ 0025 ÷ # × [0.3] DIGIT ZERO (NU) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] -× 0030 × 0308 × 0025 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM) × [25.05] PERCENT SIGN (PO) ÷ [0.3] -× 0030 × 0308 × 0020 ÷ 0025 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] +× 0030 × 0308 × 0025 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [25.05] PERCENT SIGN (PO) ÷ [0.3] +× 0030 × 0308 × 0020 ÷ 0025 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] × 0030 × 0024 ÷ # × [0.3] DIGIT ZERO (NU) × [25.05] DOLLAR SIGN (PR) ÷ [0.3] × 0030 × 0020 ÷ 0024 ÷ # × [0.3] DIGIT ZERO (NU) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] -× 0030 × 0308 × 0024 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM) × [25.05] DOLLAR SIGN (PR) ÷ [0.3] -× 0030 × 0308 × 0020 ÷ 0024 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] +× 0030 × 0308 × 0024 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [25.05] DOLLAR SIGN (PR) ÷ [0.3] +× 0030 × 0308 × 0020 ÷ 0024 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] × 0030 × 0022 ÷ # × [0.3] DIGIT ZERO (NU) × [19.01] QUOTATION MARK (QU) ÷ [0.3] × 0030 × 0020 ÷ 0022 ÷ # × [0.3] DIGIT ZERO (NU) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] -× 0030 × 0308 × 0022 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM) × [19.01] QUOTATION MARK (QU) ÷ [0.3] -× 0030 × 0308 × 0020 ÷ 0022 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] +× 0030 × 0308 × 0022 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [19.01] QUOTATION MARK (QU) ÷ [0.3] +× 0030 × 0308 × 0020 ÷ 0022 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] × 0030 × 0020 ÷ # × [0.3] DIGIT ZERO (NU) × [7.01] SPACE (SP) ÷ [0.3] × 0030 × 0020 × 0020 ÷ # × [0.3] DIGIT ZERO (NU) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] -× 0030 × 0308 × 0020 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [0.3] -× 0030 × 0308 × 0020 × 0020 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] +× 0030 × 0308 × 0020 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [0.3] +× 0030 × 0308 × 0020 × 0020 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] × 0030 × 002F ÷ # × [0.3] DIGIT ZERO (NU) × [25.03] SOLIDUS (SY) ÷ [0.3] × 0030 × 0020 × 002F ÷ # × [0.3] DIGIT ZERO (NU) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] -× 0030 × 0308 × 002F ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM) × [25.03] SOLIDUS (SY) ÷ [0.3] -× 0030 × 0308 × 0020 × 002F ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] +× 0030 × 0308 × 002F ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [25.03] SOLIDUS (SY) ÷ [0.3] +× 0030 × 0308 × 0020 × 002F ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] × 0030 × 2060 ÷ # × [0.3] DIGIT ZERO (NU) × [11.01] WORD JOINER (WJ) ÷ [0.3] × 0030 × 0020 × 2060 ÷ # × [0.3] DIGIT ZERO (NU) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] -× 0030 × 0308 × 2060 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM) × [11.01] WORD JOINER (WJ) ÷ [0.3] -× 0030 × 0308 × 0020 × 2060 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] +× 0030 × 0308 × 2060 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [11.01] WORD JOINER (WJ) ÷ [0.3] +× 0030 × 0308 × 0020 × 2060 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] × 0030 × 200B ÷ # × [0.3] DIGIT ZERO (NU) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] × 0030 × 0020 × 200B ÷ # × [0.3] DIGIT ZERO (NU) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] -× 0030 × 0308 × 200B ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] -× 0030 × 0308 × 0020 × 200B ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] +× 0030 × 0308 × 200B ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] +× 0030 × 0308 × 0020 × 200B ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] × 0030 ÷ 1F1E6 ÷ # × [0.3] DIGIT ZERO (NU) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] × 0030 × 0020 ÷ 1F1E6 ÷ # × [0.3] DIGIT ZERO (NU) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -× 0030 × 0308 ÷ 1F1E6 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -× 0030 × 0308 × 0020 ÷ 1F1E6 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 0030 × 0308 ÷ 1F1E6 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 0030 × 0308 × 0020 ÷ 1F1E6 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 0030 ÷ 261D ÷ # × [0.3] DIGIT ZERO (NU) ÷ [999.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 0030 × 0020 ÷ 261D ÷ # × [0.3] DIGIT ZERO (NU) × [7.01] SPACE (SP) ÷ [18.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 0030 × 0308 ÷ 261D ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 0030 × 0308 × 0020 ÷ 261D ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 0030 ÷ 1F3FB ÷ # × [0.3] DIGIT ZERO (NU) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 0030 × 0020 ÷ 1F3FB ÷ # × [0.3] DIGIT ZERO (NU) × [7.01] SPACE (SP) ÷ [18.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 0030 × 0308 ÷ 1F3FB ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 0030 × 0308 × 0020 ÷ 1F3FB ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 0030 × 0001 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 0030 × 0020 ÷ 0001 ÷ # × [0.3] DIGIT ZERO (NU) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 0030 × 0308 × 0001 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [9.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 0030 × 0308 × 0020 ÷ 0001 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 0030 × 200D ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 0030 × 0020 ÷ 200D ÷ # × [0.3] DIGIT ZERO (NU) × [7.01] SPACE (SP) ÷ [18.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 0030 × 0308 × 200D ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [9.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 0030 × 0308 × 0020 ÷ 200D ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] × 0030 × 00A7 ÷ # × [0.3] DIGIT ZERO (NU) × [23.03] SECTION SIGN (AI_AL) ÷ [0.3] × 0030 × 0020 ÷ 00A7 ÷ # × [0.3] DIGIT ZERO (NU) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] -× 0030 × 0308 × 00A7 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM) × [23.03] SECTION SIGN (AI_AL) ÷ [0.3] -× 0030 × 0308 × 0020 ÷ 00A7 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] +× 0030 × 0308 × 00A7 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [23.03] SECTION SIGN (AI_AL) ÷ [0.3] +× 0030 × 0308 × 0020 ÷ 00A7 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] × 0030 × 50005 ÷ # × [0.3] DIGIT ZERO (NU) × [23.03] <reserved-50005> (XX_AL) ÷ [0.3] × 0030 × 0020 ÷ 50005 ÷ # × [0.3] DIGIT ZERO (NU) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] -× 0030 × 0308 × 50005 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM) × [23.03] <reserved-50005> (XX_AL) ÷ [0.3] -× 0030 × 0308 × 0020 ÷ 50005 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] +× 0030 × 0308 × 50005 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [23.03] <reserved-50005> (XX_AL) ÷ [0.3] +× 0030 × 0308 × 0020 ÷ 50005 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] × 0030 × 0E01 ÷ # × [0.3] DIGIT ZERO (NU) × [23.03] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] × 0030 × 0020 ÷ 0E01 ÷ # × [0.3] DIGIT ZERO (NU) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] -× 0030 × 0308 × 0E01 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM) × [23.03] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] -× 0030 × 0308 × 0020 ÷ 0E01 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] +× 0030 × 0308 × 0E01 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [23.03] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] +× 0030 × 0308 × 0020 ÷ 0E01 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] × 0030 × 3041 ÷ # × [0.3] DIGIT ZERO (NU) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] × 0030 × 0020 ÷ 3041 ÷ # × [0.3] DIGIT ZERO (NU) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] -× 0030 × 0308 × 3041 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] -× 0030 × 0308 × 0020 ÷ 3041 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] +× 0030 × 0308 × 3041 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] +× 0030 × 0308 × 0020 ÷ 3041 ÷ # × [0.3] DIGIT ZERO (NU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] × 0028 × 0023 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [14.0] NUMBER SIGN (AL) ÷ [0.3] × 0028 × 0020 × 0023 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [7.01] SPACE (SP) × [14.0] NUMBER SIGN (AL) ÷ [0.3] -× 0028 × 0308 × 0023 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM) × [14.0] NUMBER SIGN (AL) ÷ [0.3] -× 0028 × 0308 × 0020 × 0023 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [14.0] NUMBER SIGN (AL) ÷ [0.3] +× 0028 × 0308 × 0023 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [14.0] NUMBER SIGN (AL) ÷ [0.3] +× 0028 × 0308 × 0020 × 0023 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [14.0] NUMBER SIGN (AL) ÷ [0.3] × 0028 × 2014 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [14.0] EM DASH (B2) ÷ [0.3] × 0028 × 0020 × 2014 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [7.01] SPACE (SP) × [14.0] EM DASH (B2) ÷ [0.3] -× 0028 × 0308 × 2014 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM) × [14.0] EM DASH (B2) ÷ [0.3] -× 0028 × 0308 × 0020 × 2014 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [14.0] EM DASH (B2) ÷ [0.3] +× 0028 × 0308 × 2014 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [14.0] EM DASH (B2) ÷ [0.3] +× 0028 × 0308 × 0020 × 2014 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [14.0] EM DASH (B2) ÷ [0.3] × 0028 × 0009 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [14.0] <CHARACTER TABULATION> (BA) ÷ [0.3] × 0028 × 0020 × 0009 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [7.01] SPACE (SP) × [14.0] <CHARACTER TABULATION> (BA) ÷ [0.3] -× 0028 × 0308 × 0009 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM) × [14.0] <CHARACTER TABULATION> (BA) ÷ [0.3] -× 0028 × 0308 × 0020 × 0009 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [14.0] <CHARACTER TABULATION> (BA) ÷ [0.3] +× 0028 × 0308 × 0009 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [14.0] <CHARACTER TABULATION> (BA) ÷ [0.3] +× 0028 × 0308 × 0020 × 0009 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [14.0] <CHARACTER TABULATION> (BA) ÷ [0.3] × 0028 × 00B4 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [14.0] ACUTE ACCENT (BB) ÷ [0.3] × 0028 × 0020 × 00B4 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [7.01] SPACE (SP) × [14.0] ACUTE ACCENT (BB) ÷ [0.3] -× 0028 × 0308 × 00B4 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM) × [14.0] ACUTE ACCENT (BB) ÷ [0.3] -× 0028 × 0308 × 0020 × 00B4 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [14.0] ACUTE ACCENT (BB) ÷ [0.3] +× 0028 × 0308 × 00B4 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [14.0] ACUTE ACCENT (BB) ÷ [0.3] +× 0028 × 0308 × 0020 × 00B4 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [14.0] ACUTE ACCENT (BB) ÷ [0.3] × 0028 × 000B ÷ # × [0.3] LEFT PARENTHESIS (OP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] × 0028 × 0020 × 000B ÷ # × [0.3] LEFT PARENTHESIS (OP) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] -× 0028 × 0308 × 000B ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] -× 0028 × 0308 × 0020 × 000B ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] +× 0028 × 0308 × 000B ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] +× 0028 × 0308 × 0020 × 000B ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] × 0028 × FFFC ÷ # × [0.3] LEFT PARENTHESIS (OP) × [14.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] × 0028 × 0020 × FFFC ÷ # × [0.3] LEFT PARENTHESIS (OP) × [7.01] SPACE (SP) × [14.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] -× 0028 × 0308 × FFFC ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM) × [14.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] -× 0028 × 0308 × 0020 × FFFC ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [14.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] +× 0028 × 0308 × FFFC ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [14.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] +× 0028 × 0308 × 0020 × FFFC ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [14.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] × 0028 × 007D ÷ # × [0.3] LEFT PARENTHESIS (OP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] × 0028 × 0020 × 007D ÷ # × [0.3] LEFT PARENTHESIS (OP) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] -× 0028 × 0308 × 007D ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM) × [13.03] RIGHT CURLY BRACKET (CL) ÷ [0.3] -× 0028 × 0308 × 0020 × 007D ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] +× 0028 × 0308 × 007D ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] RIGHT CURLY BRACKET (CL) ÷ [0.3] +× 0028 × 0308 × 0020 × 007D ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] × 0028 × 0029 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] × 0028 × 0020 × 0029 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 0028 × 0308 × 0029 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM) × [13.03] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 0028 × 0308 × 0020 × 0029 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 0028 × 0001 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] <START OF HEADING> (CM) ÷ [0.3] -× 0028 × 0020 × 0001 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [7.01] SPACE (SP) × [14.0] <START OF HEADING> (CM) ÷ [0.3] -× 0028 × 0308 × 0001 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM) × [9.0] <START OF HEADING> (CM) ÷ [0.3] -× 0028 × 0308 × 0020 × 0001 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [14.0] <START OF HEADING> (CM) ÷ [0.3] +× 0028 × 0308 × 0029 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] RIGHT PARENTHESIS (CP) ÷ [0.3] +× 0028 × 0308 × 0020 × 0029 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] × 0028 × 000D ÷ # × [0.3] LEFT PARENTHESIS (OP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] × 0028 × 0020 × 000D ÷ # × [0.3] LEFT PARENTHESIS (OP) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -× 0028 × 0308 × 000D ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -× 0028 × 0308 × 0020 × 000D ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +× 0028 × 0308 × 000D ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +× 0028 × 0308 × 0020 × 000D ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] × 0028 × 0021 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] × 0028 × 0020 × 0021 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] -× 0028 × 0308 × 0021 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] -× 0028 × 0308 × 0020 × 0021 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] +× 0028 × 0308 × 0021 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] +× 0028 × 0308 × 0020 × 0021 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] × 0028 × 00A0 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [12.1] NO-BREAK SPACE (GL) ÷ [0.3] × 0028 × 0020 × 00A0 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [7.01] SPACE (SP) × [14.0] NO-BREAK SPACE (GL) ÷ [0.3] -× 0028 × 0308 × 00A0 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM) × [12.2] NO-BREAK SPACE (GL) ÷ [0.3] -× 0028 × 0308 × 0020 × 00A0 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [14.0] NO-BREAK SPACE (GL) ÷ [0.3] +× 0028 × 0308 × 00A0 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [12.2] NO-BREAK SPACE (GL) ÷ [0.3] +× 0028 × 0308 × 0020 × 00A0 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [14.0] NO-BREAK SPACE (GL) ÷ [0.3] × 0028 × AC00 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [14.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] × 0028 × 0020 × AC00 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [7.01] SPACE (SP) × [14.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] -× 0028 × 0308 × AC00 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM) × [14.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] -× 0028 × 0308 × 0020 × AC00 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [14.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] +× 0028 × 0308 × AC00 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [14.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] +× 0028 × 0308 × 0020 × AC00 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [14.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] × 0028 × AC01 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [14.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] × 0028 × 0020 × AC01 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [7.01] SPACE (SP) × [14.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] -× 0028 × 0308 × AC01 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM) × [14.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] -× 0028 × 0308 × 0020 × AC01 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [14.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] +× 0028 × 0308 × AC01 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [14.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] +× 0028 × 0308 × 0020 × AC01 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [14.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] × 0028 × 05D0 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [14.0] HEBREW LETTER ALEF (HL) ÷ [0.3] × 0028 × 0020 × 05D0 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [7.01] SPACE (SP) × [14.0] HEBREW LETTER ALEF (HL) ÷ [0.3] -× 0028 × 0308 × 05D0 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM) × [14.0] HEBREW LETTER ALEF (HL) ÷ [0.3] -× 0028 × 0308 × 0020 × 05D0 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [14.0] HEBREW LETTER ALEF (HL) ÷ [0.3] +× 0028 × 0308 × 05D0 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [14.0] HEBREW LETTER ALEF (HL) ÷ [0.3] +× 0028 × 0308 × 0020 × 05D0 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [14.0] HEBREW LETTER ALEF (HL) ÷ [0.3] × 0028 × 002D ÷ # × [0.3] LEFT PARENTHESIS (OP) × [14.0] HYPHEN-MINUS (HY) ÷ [0.3] × 0028 × 0020 × 002D ÷ # × [0.3] LEFT PARENTHESIS (OP) × [7.01] SPACE (SP) × [14.0] HYPHEN-MINUS (HY) ÷ [0.3] -× 0028 × 0308 × 002D ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM) × [14.0] HYPHEN-MINUS (HY) ÷ [0.3] -× 0028 × 0308 × 0020 × 002D ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [14.0] HYPHEN-MINUS (HY) ÷ [0.3] +× 0028 × 0308 × 002D ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [14.0] HYPHEN-MINUS (HY) ÷ [0.3] +× 0028 × 0308 × 0020 × 002D ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [14.0] HYPHEN-MINUS (HY) ÷ [0.3] × 0028 × 231A ÷ # × [0.3] LEFT PARENTHESIS (OP) × [14.0] WATCH (ID) ÷ [0.3] × 0028 × 0020 × 231A ÷ # × [0.3] LEFT PARENTHESIS (OP) × [7.01] SPACE (SP) × [14.0] WATCH (ID) ÷ [0.3] -× 0028 × 0308 × 231A ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM) × [14.0] WATCH (ID) ÷ [0.3] -× 0028 × 0308 × 0020 × 231A ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [14.0] WATCH (ID) ÷ [0.3] +× 0028 × 0308 × 231A ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [14.0] WATCH (ID) ÷ [0.3] +× 0028 × 0308 × 0020 × 231A ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [14.0] WATCH (ID) ÷ [0.3] × 0028 × 2024 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [14.0] ONE DOT LEADER (IN) ÷ [0.3] × 0028 × 0020 × 2024 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [7.01] SPACE (SP) × [14.0] ONE DOT LEADER (IN) ÷ [0.3] -× 0028 × 0308 × 2024 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM) × [14.0] ONE DOT LEADER (IN) ÷ [0.3] -× 0028 × 0308 × 0020 × 2024 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [14.0] ONE DOT LEADER (IN) ÷ [0.3] +× 0028 × 0308 × 2024 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [14.0] ONE DOT LEADER (IN) ÷ [0.3] +× 0028 × 0308 × 0020 × 2024 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [14.0] ONE DOT LEADER (IN) ÷ [0.3] × 0028 × 002C ÷ # × [0.3] LEFT PARENTHESIS (OP) × [13.02] COMMA (IS) ÷ [0.3] × 0028 × 0020 × 002C ÷ # × [0.3] LEFT PARENTHESIS (OP) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] -× 0028 × 0308 × 002C ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM) × [13.03] COMMA (IS) ÷ [0.3] -× 0028 × 0308 × 0020 × 002C ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] +× 0028 × 0308 × 002C ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] COMMA (IS) ÷ [0.3] +× 0028 × 0308 × 0020 × 002C ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] × 0028 × 1100 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [14.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] × 0028 × 0020 × 1100 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [7.01] SPACE (SP) × [14.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] -× 0028 × 0308 × 1100 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM) × [14.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] -× 0028 × 0308 × 0020 × 1100 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [14.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] +× 0028 × 0308 × 1100 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [14.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] +× 0028 × 0308 × 0020 × 1100 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [14.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] × 0028 × 11A8 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [14.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] × 0028 × 0020 × 11A8 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [7.01] SPACE (SP) × [14.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] -× 0028 × 0308 × 11A8 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM) × [14.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] -× 0028 × 0308 × 0020 × 11A8 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [14.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] +× 0028 × 0308 × 11A8 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [14.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] +× 0028 × 0308 × 0020 × 11A8 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [14.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] × 0028 × 1160 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [14.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] × 0028 × 0020 × 1160 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [7.01] SPACE (SP) × [14.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] -× 0028 × 0308 × 1160 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM) × [14.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] -× 0028 × 0308 × 0020 × 1160 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [14.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] +× 0028 × 0308 × 1160 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [14.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] +× 0028 × 0308 × 0020 × 1160 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [14.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] × 0028 × 000A ÷ # × [0.3] LEFT PARENTHESIS (OP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] × 0028 × 0020 × 000A ÷ # × [0.3] LEFT PARENTHESIS (OP) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] -× 0028 × 0308 × 000A ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] -× 0028 × 0308 × 0020 × 000A ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] +× 0028 × 0308 × 000A ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] +× 0028 × 0308 × 0020 × 000A ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] × 0028 × 0085 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] × 0028 × 0020 × 0085 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] -× 0028 × 0308 × 0085 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] -× 0028 × 0308 × 0020 × 0085 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] +× 0028 × 0308 × 0085 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] +× 0028 × 0308 × 0020 × 0085 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] × 0028 × 17D6 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [14.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] × 0028 × 0020 × 17D6 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [7.01] SPACE (SP) × [14.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] -× 0028 × 0308 × 17D6 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM) × [14.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] -× 0028 × 0308 × 0020 × 17D6 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [14.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] +× 0028 × 0308 × 17D6 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [14.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] +× 0028 × 0308 × 0020 × 17D6 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [14.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] × 0028 × 0030 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [14.0] DIGIT ZERO (NU) ÷ [0.3] × 0028 × 0020 × 0030 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [7.01] SPACE (SP) × [14.0] DIGIT ZERO (NU) ÷ [0.3] -× 0028 × 0308 × 0030 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM) × [14.0] DIGIT ZERO (NU) ÷ [0.3] -× 0028 × 0308 × 0020 × 0030 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [14.0] DIGIT ZERO (NU) ÷ [0.3] +× 0028 × 0308 × 0030 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [14.0] DIGIT ZERO (NU) ÷ [0.3] +× 0028 × 0308 × 0020 × 0030 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [14.0] DIGIT ZERO (NU) ÷ [0.3] × 0028 × 0028 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [14.0] LEFT PARENTHESIS (OP) ÷ [0.3] × 0028 × 0020 × 0028 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [7.01] SPACE (SP) × [14.0] LEFT PARENTHESIS (OP) ÷ [0.3] -× 0028 × 0308 × 0028 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM) × [14.0] LEFT PARENTHESIS (OP) ÷ [0.3] -× 0028 × 0308 × 0020 × 0028 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [14.0] LEFT PARENTHESIS (OP) ÷ [0.3] +× 0028 × 0308 × 0028 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [14.0] LEFT PARENTHESIS (OP) ÷ [0.3] +× 0028 × 0308 × 0020 × 0028 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [14.0] LEFT PARENTHESIS (OP) ÷ [0.3] × 0028 × 0025 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [14.0] PERCENT SIGN (PO) ÷ [0.3] × 0028 × 0020 × 0025 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [7.01] SPACE (SP) × [14.0] PERCENT SIGN (PO) ÷ [0.3] -× 0028 × 0308 × 0025 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM) × [14.0] PERCENT SIGN (PO) ÷ [0.3] -× 0028 × 0308 × 0020 × 0025 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [14.0] PERCENT SIGN (PO) ÷ [0.3] +× 0028 × 0308 × 0025 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [14.0] PERCENT SIGN (PO) ÷ [0.3] +× 0028 × 0308 × 0020 × 0025 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [14.0] PERCENT SIGN (PO) ÷ [0.3] × 0028 × 0024 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [14.0] DOLLAR SIGN (PR) ÷ [0.3] × 0028 × 0020 × 0024 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [7.01] SPACE (SP) × [14.0] DOLLAR SIGN (PR) ÷ [0.3] -× 0028 × 0308 × 0024 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM) × [14.0] DOLLAR SIGN (PR) ÷ [0.3] -× 0028 × 0308 × 0020 × 0024 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [14.0] DOLLAR SIGN (PR) ÷ [0.3] +× 0028 × 0308 × 0024 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [14.0] DOLLAR SIGN (PR) ÷ [0.3] +× 0028 × 0308 × 0020 × 0024 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [14.0] DOLLAR SIGN (PR) ÷ [0.3] × 0028 × 0022 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [14.0] QUOTATION MARK (QU) ÷ [0.3] × 0028 × 0020 × 0022 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [7.01] SPACE (SP) × [14.0] QUOTATION MARK (QU) ÷ [0.3] -× 0028 × 0308 × 0022 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM) × [14.0] QUOTATION MARK (QU) ÷ [0.3] -× 0028 × 0308 × 0020 × 0022 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [14.0] QUOTATION MARK (QU) ÷ [0.3] +× 0028 × 0308 × 0022 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [14.0] QUOTATION MARK (QU) ÷ [0.3] +× 0028 × 0308 × 0020 × 0022 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [14.0] QUOTATION MARK (QU) ÷ [0.3] × 0028 × 0020 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [7.01] SPACE (SP) ÷ [0.3] × 0028 × 0020 × 0020 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] -× 0028 × 0308 × 0020 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [0.3] -× 0028 × 0308 × 0020 × 0020 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] +× 0028 × 0308 × 0020 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [0.3] +× 0028 × 0308 × 0020 × 0020 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] × 0028 × 002F ÷ # × [0.3] LEFT PARENTHESIS (OP) × [13.02] SOLIDUS (SY) ÷ [0.3] × 0028 × 0020 × 002F ÷ # × [0.3] LEFT PARENTHESIS (OP) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] -× 0028 × 0308 × 002F ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM) × [13.03] SOLIDUS (SY) ÷ [0.3] -× 0028 × 0308 × 0020 × 002F ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] +× 0028 × 0308 × 002F ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] SOLIDUS (SY) ÷ [0.3] +× 0028 × 0308 × 0020 × 002F ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] × 0028 × 2060 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [11.01] WORD JOINER (WJ) ÷ [0.3] × 0028 × 0020 × 2060 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] -× 0028 × 0308 × 2060 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM) × [11.01] WORD JOINER (WJ) ÷ [0.3] -× 0028 × 0308 × 0020 × 2060 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] +× 0028 × 0308 × 2060 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [11.01] WORD JOINER (WJ) ÷ [0.3] +× 0028 × 0308 × 0020 × 2060 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] × 0028 × 200B ÷ # × [0.3] LEFT PARENTHESIS (OP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] × 0028 × 0020 × 200B ÷ # × [0.3] LEFT PARENTHESIS (OP) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] -× 0028 × 0308 × 200B ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] -× 0028 × 0308 × 0020 × 200B ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] +× 0028 × 0308 × 200B ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] +× 0028 × 0308 × 0020 × 200B ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] × 0028 × 1F1E6 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [14.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] × 0028 × 0020 × 1F1E6 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [7.01] SPACE (SP) × [14.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -× 0028 × 0308 × 1F1E6 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM) × [14.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -× 0028 × 0308 × 0020 × 1F1E6 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [14.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 0028 × 0308 × 1F1E6 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [14.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 0028 × 0308 × 0020 × 1F1E6 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [14.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 0028 × 261D ÷ # × [0.3] LEFT PARENTHESIS (OP) × [14.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 0028 × 0020 × 261D ÷ # × [0.3] LEFT PARENTHESIS (OP) × [7.01] SPACE (SP) × [14.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 0028 × 0308 × 261D ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [14.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 0028 × 0308 × 0020 × 261D ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [14.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 0028 × 1F3FB ÷ # × [0.3] LEFT PARENTHESIS (OP) × [14.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 0028 × 0020 × 1F3FB ÷ # × [0.3] LEFT PARENTHESIS (OP) × [7.01] SPACE (SP) × [14.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 0028 × 0308 × 1F3FB ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [14.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 0028 × 0308 × 0020 × 1F3FB ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [14.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 0028 × 0001 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 0028 × 0020 × 0001 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [7.01] SPACE (SP) × [14.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 0028 × 0308 × 0001 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [9.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 0028 × 0308 × 0020 × 0001 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [14.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 0028 × 200D ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 0028 × 0020 × 200D ÷ # × [0.3] LEFT PARENTHESIS (OP) × [7.01] SPACE (SP) × [14.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 0028 × 0308 × 200D ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [9.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 0028 × 0308 × 0020 × 200D ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [14.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] × 0028 × 00A7 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [14.0] SECTION SIGN (AI_AL) ÷ [0.3] × 0028 × 0020 × 00A7 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [7.01] SPACE (SP) × [14.0] SECTION SIGN (AI_AL) ÷ [0.3] -× 0028 × 0308 × 00A7 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM) × [14.0] SECTION SIGN (AI_AL) ÷ [0.3] -× 0028 × 0308 × 0020 × 00A7 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [14.0] SECTION SIGN (AI_AL) ÷ [0.3] +× 0028 × 0308 × 00A7 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [14.0] SECTION SIGN (AI_AL) ÷ [0.3] +× 0028 × 0308 × 0020 × 00A7 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [14.0] SECTION SIGN (AI_AL) ÷ [0.3] × 0028 × 50005 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [14.0] <reserved-50005> (XX_AL) ÷ [0.3] × 0028 × 0020 × 50005 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [7.01] SPACE (SP) × [14.0] <reserved-50005> (XX_AL) ÷ [0.3] -× 0028 × 0308 × 50005 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM) × [14.0] <reserved-50005> (XX_AL) ÷ [0.3] -× 0028 × 0308 × 0020 × 50005 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [14.0] <reserved-50005> (XX_AL) ÷ [0.3] +× 0028 × 0308 × 50005 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [14.0] <reserved-50005> (XX_AL) ÷ [0.3] +× 0028 × 0308 × 0020 × 50005 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [14.0] <reserved-50005> (XX_AL) ÷ [0.3] × 0028 × 0E01 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [14.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] × 0028 × 0020 × 0E01 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [7.01] SPACE (SP) × [14.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] -× 0028 × 0308 × 0E01 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM) × [14.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] -× 0028 × 0308 × 0020 × 0E01 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [14.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] +× 0028 × 0308 × 0E01 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [14.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] +× 0028 × 0308 × 0020 × 0E01 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [14.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] × 0028 × 3041 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [14.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] × 0028 × 0020 × 3041 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [7.01] SPACE (SP) × [14.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] -× 0028 × 0308 × 3041 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM) × [14.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] -× 0028 × 0308 × 0020 × 3041 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [14.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] -× 0025 × 0023 ÷ # × [0.3] PERCENT SIGN (PO) × [24.03] NUMBER SIGN (AL) ÷ [0.3] +× 0028 × 0308 × 3041 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [14.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] +× 0028 × 0308 × 0020 × 3041 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [14.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] +× 0025 × 0023 ÷ # × [0.3] PERCENT SIGN (PO) × [24.02] NUMBER SIGN (AL) ÷ [0.3] × 0025 × 0020 ÷ 0023 ÷ # × [0.3] PERCENT SIGN (PO) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] -× 0025 × 0308 × 0023 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM) × [24.03] NUMBER SIGN (AL) ÷ [0.3] -× 0025 × 0308 × 0020 ÷ 0023 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] +× 0025 × 0308 × 0023 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM1_CM) × [24.02] NUMBER SIGN (AL) ÷ [0.3] +× 0025 × 0308 × 0020 ÷ 0023 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] × 0025 ÷ 2014 ÷ # × [0.3] PERCENT SIGN (PO) ÷ [999.0] EM DASH (B2) ÷ [0.3] × 0025 × 0020 ÷ 2014 ÷ # × [0.3] PERCENT SIGN (PO) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] -× 0025 × 0308 ÷ 2014 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] EM DASH (B2) ÷ [0.3] -× 0025 × 0308 × 0020 ÷ 2014 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] +× 0025 × 0308 ÷ 2014 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] EM DASH (B2) ÷ [0.3] +× 0025 × 0308 × 0020 ÷ 2014 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] × 0025 × 0009 ÷ # × [0.3] PERCENT SIGN (PO) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] × 0025 × 0020 ÷ 0009 ÷ # × [0.3] PERCENT SIGN (PO) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] -× 0025 × 0308 × 0009 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] -× 0025 × 0308 × 0020 ÷ 0009 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] +× 0025 × 0308 × 0009 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] +× 0025 × 0308 × 0020 ÷ 0009 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] × 0025 ÷ 00B4 ÷ # × [0.3] PERCENT SIGN (PO) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3] × 0025 × 0020 ÷ 00B4 ÷ # × [0.3] PERCENT SIGN (PO) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] -× 0025 × 0308 ÷ 00B4 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3] -× 0025 × 0308 × 0020 ÷ 00B4 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] +× 0025 × 0308 ÷ 00B4 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3] +× 0025 × 0308 × 0020 ÷ 00B4 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] × 0025 × 000B ÷ # × [0.3] PERCENT SIGN (PO) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] × 0025 × 0020 × 000B ÷ # × [0.3] PERCENT SIGN (PO) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] -× 0025 × 0308 × 000B ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] -× 0025 × 0308 × 0020 × 000B ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] +× 0025 × 0308 × 000B ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] +× 0025 × 0308 × 0020 × 000B ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] × 0025 ÷ FFFC ÷ # × [0.3] PERCENT SIGN (PO) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] × 0025 × 0020 ÷ FFFC ÷ # × [0.3] PERCENT SIGN (PO) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] -× 0025 × 0308 ÷ FFFC ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] -× 0025 × 0308 × 0020 ÷ FFFC ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] +× 0025 × 0308 ÷ FFFC ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] +× 0025 × 0308 × 0020 ÷ FFFC ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] × 0025 × 007D ÷ # × [0.3] PERCENT SIGN (PO) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] × 0025 × 0020 × 007D ÷ # × [0.3] PERCENT SIGN (PO) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] -× 0025 × 0308 × 007D ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM) × [13.03] RIGHT CURLY BRACKET (CL) ÷ [0.3] -× 0025 × 0308 × 0020 × 007D ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] +× 0025 × 0308 × 007D ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] RIGHT CURLY BRACKET (CL) ÷ [0.3] +× 0025 × 0308 × 0020 × 007D ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] × 0025 × 0029 ÷ # × [0.3] PERCENT SIGN (PO) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] × 0025 × 0020 × 0029 ÷ # × [0.3] PERCENT SIGN (PO) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 0025 × 0308 × 0029 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM) × [13.03] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 0025 × 0308 × 0020 × 0029 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 0025 × 0001 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] <START OF HEADING> (CM) ÷ [0.3] -× 0025 × 0020 ÷ 0001 ÷ # × [0.3] PERCENT SIGN (PO) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM) ÷ [0.3] -× 0025 × 0308 × 0001 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM) × [9.0] <START OF HEADING> (CM) ÷ [0.3] -× 0025 × 0308 × 0020 ÷ 0001 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM) ÷ [0.3] +× 0025 × 0308 × 0029 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] RIGHT PARENTHESIS (CP) ÷ [0.3] +× 0025 × 0308 × 0020 × 0029 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] × 0025 × 000D ÷ # × [0.3] PERCENT SIGN (PO) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] × 0025 × 0020 × 000D ÷ # × [0.3] PERCENT SIGN (PO) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -× 0025 × 0308 × 000D ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -× 0025 × 0308 × 0020 × 000D ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +× 0025 × 0308 × 000D ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +× 0025 × 0308 × 0020 × 000D ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] × 0025 × 0021 ÷ # × [0.3] PERCENT SIGN (PO) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] × 0025 × 0020 × 0021 ÷ # × [0.3] PERCENT SIGN (PO) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] -× 0025 × 0308 × 0021 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] -× 0025 × 0308 × 0020 × 0021 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] +× 0025 × 0308 × 0021 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] +× 0025 × 0308 × 0020 × 0021 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] × 0025 × 00A0 ÷ # × [0.3] PERCENT SIGN (PO) × [12.1] NO-BREAK SPACE (GL) ÷ [0.3] × 0025 × 0020 ÷ 00A0 ÷ # × [0.3] PERCENT SIGN (PO) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] -× 0025 × 0308 × 00A0 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM) × [12.2] NO-BREAK SPACE (GL) ÷ [0.3] -× 0025 × 0308 × 0020 ÷ 00A0 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] +× 0025 × 0308 × 00A0 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM1_CM) × [12.2] NO-BREAK SPACE (GL) ÷ [0.3] +× 0025 × 0308 × 0020 ÷ 00A0 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] × 0025 ÷ AC00 ÷ # × [0.3] PERCENT SIGN (PO) ÷ [999.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] × 0025 × 0020 ÷ AC00 ÷ # × [0.3] PERCENT SIGN (PO) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] -× 0025 × 0308 ÷ AC00 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] -× 0025 × 0308 × 0020 ÷ AC00 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] +× 0025 × 0308 ÷ AC00 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] +× 0025 × 0308 × 0020 ÷ AC00 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] × 0025 ÷ AC01 ÷ # × [0.3] PERCENT SIGN (PO) ÷ [999.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] × 0025 × 0020 ÷ AC01 ÷ # × [0.3] PERCENT SIGN (PO) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] -× 0025 × 0308 ÷ AC01 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] -× 0025 × 0308 × 0020 ÷ AC01 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] -× 0025 × 05D0 ÷ # × [0.3] PERCENT SIGN (PO) × [24.03] HEBREW LETTER ALEF (HL) ÷ [0.3] +× 0025 × 0308 ÷ AC01 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] +× 0025 × 0308 × 0020 ÷ AC01 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] +× 0025 × 05D0 ÷ # × [0.3] PERCENT SIGN (PO) × [24.02] HEBREW LETTER ALEF (HL) ÷ [0.3] × 0025 × 0020 ÷ 05D0 ÷ # × [0.3] PERCENT SIGN (PO) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] -× 0025 × 0308 × 05D0 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM) × [24.03] HEBREW LETTER ALEF (HL) ÷ [0.3] -× 0025 × 0308 × 0020 ÷ 05D0 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] +× 0025 × 0308 × 05D0 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM1_CM) × [24.02] HEBREW LETTER ALEF (HL) ÷ [0.3] +× 0025 × 0308 × 0020 ÷ 05D0 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] × 0025 × 002D ÷ # × [0.3] PERCENT SIGN (PO) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] × 0025 × 0020 ÷ 002D ÷ # × [0.3] PERCENT SIGN (PO) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] -× 0025 × 0308 × 002D ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] -× 0025 × 0308 × 0020 ÷ 002D ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] +× 0025 × 0308 × 002D ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] +× 0025 × 0308 × 0020 ÷ 002D ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] × 0025 ÷ 231A ÷ # × [0.3] PERCENT SIGN (PO) ÷ [999.0] WATCH (ID) ÷ [0.3] × 0025 × 0020 ÷ 231A ÷ # × [0.3] PERCENT SIGN (PO) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] -× 0025 × 0308 ÷ 231A ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] WATCH (ID) ÷ [0.3] -× 0025 × 0308 × 0020 ÷ 231A ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] +× 0025 × 0308 ÷ 231A ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] WATCH (ID) ÷ [0.3] +× 0025 × 0308 × 0020 ÷ 231A ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] × 0025 ÷ 2024 ÷ # × [0.3] PERCENT SIGN (PO) ÷ [999.0] ONE DOT LEADER (IN) ÷ [0.3] × 0025 × 0020 ÷ 2024 ÷ # × [0.3] PERCENT SIGN (PO) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] -× 0025 × 0308 ÷ 2024 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] ONE DOT LEADER (IN) ÷ [0.3] -× 0025 × 0308 × 0020 ÷ 2024 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] +× 0025 × 0308 ÷ 2024 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] ONE DOT LEADER (IN) ÷ [0.3] +× 0025 × 0308 × 0020 ÷ 2024 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] × 0025 × 002C ÷ # × [0.3] PERCENT SIGN (PO) × [13.02] COMMA (IS) ÷ [0.3] × 0025 × 0020 × 002C ÷ # × [0.3] PERCENT SIGN (PO) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] -× 0025 × 0308 × 002C ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM) × [13.03] COMMA (IS) ÷ [0.3] -× 0025 × 0308 × 0020 × 002C ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] +× 0025 × 0308 × 002C ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] COMMA (IS) ÷ [0.3] +× 0025 × 0308 × 0020 × 002C ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] × 0025 ÷ 1100 ÷ # × [0.3] PERCENT SIGN (PO) ÷ [999.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] × 0025 × 0020 ÷ 1100 ÷ # × [0.3] PERCENT SIGN (PO) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] -× 0025 × 0308 ÷ 1100 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] -× 0025 × 0308 × 0020 ÷ 1100 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] +× 0025 × 0308 ÷ 1100 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] +× 0025 × 0308 × 0020 ÷ 1100 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] × 0025 ÷ 11A8 ÷ # × [0.3] PERCENT SIGN (PO) ÷ [999.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] × 0025 × 0020 ÷ 11A8 ÷ # × [0.3] PERCENT SIGN (PO) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] -× 0025 × 0308 ÷ 11A8 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] -× 0025 × 0308 × 0020 ÷ 11A8 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] +× 0025 × 0308 ÷ 11A8 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] +× 0025 × 0308 × 0020 ÷ 11A8 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] × 0025 ÷ 1160 ÷ # × [0.3] PERCENT SIGN (PO) ÷ [999.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] × 0025 × 0020 ÷ 1160 ÷ # × [0.3] PERCENT SIGN (PO) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] -× 0025 × 0308 ÷ 1160 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] -× 0025 × 0308 × 0020 ÷ 1160 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] +× 0025 × 0308 ÷ 1160 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] +× 0025 × 0308 × 0020 ÷ 1160 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] × 0025 × 000A ÷ # × [0.3] PERCENT SIGN (PO) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] × 0025 × 0020 × 000A ÷ # × [0.3] PERCENT SIGN (PO) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] -× 0025 × 0308 × 000A ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] -× 0025 × 0308 × 0020 × 000A ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] +× 0025 × 0308 × 000A ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] +× 0025 × 0308 × 0020 × 000A ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] × 0025 × 0085 ÷ # × [0.3] PERCENT SIGN (PO) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] × 0025 × 0020 × 0085 ÷ # × [0.3] PERCENT SIGN (PO) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] -× 0025 × 0308 × 0085 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] -× 0025 × 0308 × 0020 × 0085 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] +× 0025 × 0308 × 0085 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] +× 0025 × 0308 × 0020 × 0085 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] × 0025 × 17D6 ÷ # × [0.3] PERCENT SIGN (PO) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] × 0025 × 0020 ÷ 17D6 ÷ # × [0.3] PERCENT SIGN (PO) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] -× 0025 × 0308 × 17D6 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] -× 0025 × 0308 × 0020 ÷ 17D6 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] +× 0025 × 0308 × 17D6 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] +× 0025 × 0308 × 0020 ÷ 17D6 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] × 0025 × 0030 ÷ # × [0.3] PERCENT SIGN (PO) × [25.01] DIGIT ZERO (NU) ÷ [0.3] × 0025 × 0020 ÷ 0030 ÷ # × [0.3] PERCENT SIGN (PO) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] -× 0025 × 0308 × 0030 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM) × [25.01] DIGIT ZERO (NU) ÷ [0.3] -× 0025 × 0308 × 0020 ÷ 0030 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] +× 0025 × 0308 × 0030 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM1_CM) × [25.01] DIGIT ZERO (NU) ÷ [0.3] +× 0025 × 0308 × 0020 ÷ 0030 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] × 0025 ÷ 0028 ÷ # × [0.3] PERCENT SIGN (PO) ÷ [999.0] LEFT PARENTHESIS (OP) ÷ [0.3] × 0025 × 0020 ÷ 0028 ÷ # × [0.3] PERCENT SIGN (PO) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] -× 0025 × 0308 ÷ 0028 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] LEFT PARENTHESIS (OP) ÷ [0.3] -× 0025 × 0308 × 0020 ÷ 0028 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] +× 0025 × 0308 ÷ 0028 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] LEFT PARENTHESIS (OP) ÷ [0.3] +× 0025 × 0308 × 0020 ÷ 0028 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] × 0025 ÷ 0025 ÷ # × [0.3] PERCENT SIGN (PO) ÷ [999.0] PERCENT SIGN (PO) ÷ [0.3] × 0025 × 0020 ÷ 0025 ÷ # × [0.3] PERCENT SIGN (PO) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] -× 0025 × 0308 ÷ 0025 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] PERCENT SIGN (PO) ÷ [0.3] -× 0025 × 0308 × 0020 ÷ 0025 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] +× 0025 × 0308 ÷ 0025 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] PERCENT SIGN (PO) ÷ [0.3] +× 0025 × 0308 × 0020 ÷ 0025 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] × 0025 ÷ 0024 ÷ # × [0.3] PERCENT SIGN (PO) ÷ [999.0] DOLLAR SIGN (PR) ÷ [0.3] × 0025 × 0020 ÷ 0024 ÷ # × [0.3] PERCENT SIGN (PO) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] -× 0025 × 0308 ÷ 0024 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] DOLLAR SIGN (PR) ÷ [0.3] -× 0025 × 0308 × 0020 ÷ 0024 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] +× 0025 × 0308 ÷ 0024 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] DOLLAR SIGN (PR) ÷ [0.3] +× 0025 × 0308 × 0020 ÷ 0024 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] × 0025 × 0022 ÷ # × [0.3] PERCENT SIGN (PO) × [19.01] QUOTATION MARK (QU) ÷ [0.3] × 0025 × 0020 ÷ 0022 ÷ # × [0.3] PERCENT SIGN (PO) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] -× 0025 × 0308 × 0022 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM) × [19.01] QUOTATION MARK (QU) ÷ [0.3] -× 0025 × 0308 × 0020 ÷ 0022 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] +× 0025 × 0308 × 0022 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM1_CM) × [19.01] QUOTATION MARK (QU) ÷ [0.3] +× 0025 × 0308 × 0020 ÷ 0022 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] × 0025 × 0020 ÷ # × [0.3] PERCENT SIGN (PO) × [7.01] SPACE (SP) ÷ [0.3] × 0025 × 0020 × 0020 ÷ # × [0.3] PERCENT SIGN (PO) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] -× 0025 × 0308 × 0020 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [0.3] -× 0025 × 0308 × 0020 × 0020 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] +× 0025 × 0308 × 0020 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [0.3] +× 0025 × 0308 × 0020 × 0020 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] × 0025 × 002F ÷ # × [0.3] PERCENT SIGN (PO) × [13.02] SOLIDUS (SY) ÷ [0.3] × 0025 × 0020 × 002F ÷ # × [0.3] PERCENT SIGN (PO) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] -× 0025 × 0308 × 002F ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM) × [13.03] SOLIDUS (SY) ÷ [0.3] -× 0025 × 0308 × 0020 × 002F ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] +× 0025 × 0308 × 002F ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] SOLIDUS (SY) ÷ [0.3] +× 0025 × 0308 × 0020 × 002F ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] × 0025 × 2060 ÷ # × [0.3] PERCENT SIGN (PO) × [11.01] WORD JOINER (WJ) ÷ [0.3] × 0025 × 0020 × 2060 ÷ # × [0.3] PERCENT SIGN (PO) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] -× 0025 × 0308 × 2060 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM) × [11.01] WORD JOINER (WJ) ÷ [0.3] -× 0025 × 0308 × 0020 × 2060 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] +× 0025 × 0308 × 2060 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM1_CM) × [11.01] WORD JOINER (WJ) ÷ [0.3] +× 0025 × 0308 × 0020 × 2060 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] × 0025 × 200B ÷ # × [0.3] PERCENT SIGN (PO) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] × 0025 × 0020 × 200B ÷ # × [0.3] PERCENT SIGN (PO) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] -× 0025 × 0308 × 200B ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] -× 0025 × 0308 × 0020 × 200B ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] +× 0025 × 0308 × 200B ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] +× 0025 × 0308 × 0020 × 200B ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] × 0025 ÷ 1F1E6 ÷ # × [0.3] PERCENT SIGN (PO) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] × 0025 × 0020 ÷ 1F1E6 ÷ # × [0.3] PERCENT SIGN (PO) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -× 0025 × 0308 ÷ 1F1E6 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -× 0025 × 0308 × 0020 ÷ 1F1E6 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -× 0025 × 00A7 ÷ # × [0.3] PERCENT SIGN (PO) × [24.03] SECTION SIGN (AI_AL) ÷ [0.3] +× 0025 × 0308 ÷ 1F1E6 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 0025 × 0308 × 0020 ÷ 1F1E6 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 0025 ÷ 261D ÷ # × [0.3] PERCENT SIGN (PO) ÷ [999.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 0025 × 0020 ÷ 261D ÷ # × [0.3] PERCENT SIGN (PO) × [7.01] SPACE (SP) ÷ [18.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 0025 × 0308 ÷ 261D ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 0025 × 0308 × 0020 ÷ 261D ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 0025 ÷ 1F3FB ÷ # × [0.3] PERCENT SIGN (PO) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 0025 × 0020 ÷ 1F3FB ÷ # × [0.3] PERCENT SIGN (PO) × [7.01] SPACE (SP) ÷ [18.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 0025 × 0308 ÷ 1F3FB ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 0025 × 0308 × 0020 ÷ 1F3FB ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 0025 × 0001 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 0025 × 0020 ÷ 0001 ÷ # × [0.3] PERCENT SIGN (PO) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 0025 × 0308 × 0001 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM1_CM) × [9.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 0025 × 0308 × 0020 ÷ 0001 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 0025 × 200D ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 0025 × 0020 ÷ 200D ÷ # × [0.3] PERCENT SIGN (PO) × [7.01] SPACE (SP) ÷ [18.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 0025 × 0308 × 200D ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM1_CM) × [9.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 0025 × 0308 × 0020 ÷ 200D ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 0025 × 00A7 ÷ # × [0.3] PERCENT SIGN (PO) × [24.02] SECTION SIGN (AI_AL) ÷ [0.3] × 0025 × 0020 ÷ 00A7 ÷ # × [0.3] PERCENT SIGN (PO) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] -× 0025 × 0308 × 00A7 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM) × [24.03] SECTION SIGN (AI_AL) ÷ [0.3] -× 0025 × 0308 × 0020 ÷ 00A7 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] -× 0025 × 50005 ÷ # × [0.3] PERCENT SIGN (PO) × [24.03] <reserved-50005> (XX_AL) ÷ [0.3] +× 0025 × 0308 × 00A7 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM1_CM) × [24.02] SECTION SIGN (AI_AL) ÷ [0.3] +× 0025 × 0308 × 0020 ÷ 00A7 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] +× 0025 × 50005 ÷ # × [0.3] PERCENT SIGN (PO) × [24.02] <reserved-50005> (XX_AL) ÷ [0.3] × 0025 × 0020 ÷ 50005 ÷ # × [0.3] PERCENT SIGN (PO) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] -× 0025 × 0308 × 50005 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM) × [24.03] <reserved-50005> (XX_AL) ÷ [0.3] -× 0025 × 0308 × 0020 ÷ 50005 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] -× 0025 × 0E01 ÷ # × [0.3] PERCENT SIGN (PO) × [24.03] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] +× 0025 × 0308 × 50005 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM1_CM) × [24.02] <reserved-50005> (XX_AL) ÷ [0.3] +× 0025 × 0308 × 0020 ÷ 50005 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] +× 0025 × 0E01 ÷ # × [0.3] PERCENT SIGN (PO) × [24.02] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] × 0025 × 0020 ÷ 0E01 ÷ # × [0.3] PERCENT SIGN (PO) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] -× 0025 × 0308 × 0E01 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM) × [24.03] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] -× 0025 × 0308 × 0020 ÷ 0E01 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] +× 0025 × 0308 × 0E01 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM1_CM) × [24.02] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] +× 0025 × 0308 × 0020 ÷ 0E01 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] × 0025 × 3041 ÷ # × [0.3] PERCENT SIGN (PO) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] × 0025 × 0020 ÷ 3041 ÷ # × [0.3] PERCENT SIGN (PO) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] -× 0025 × 0308 × 3041 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] -× 0025 × 0308 × 0020 ÷ 3041 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] +× 0025 × 0308 × 3041 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] +× 0025 × 0308 × 0020 ÷ 3041 ÷ # × [0.3] PERCENT SIGN (PO) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] × 0024 × 0023 ÷ # × [0.3] DOLLAR SIGN (PR) × [24.02] NUMBER SIGN (AL) ÷ [0.3] × 0024 × 0020 ÷ 0023 ÷ # × [0.3] DOLLAR SIGN (PR) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] -× 0024 × 0308 × 0023 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM) × [24.02] NUMBER SIGN (AL) ÷ [0.3] -× 0024 × 0308 × 0020 ÷ 0023 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] +× 0024 × 0308 × 0023 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) × [24.02] NUMBER SIGN (AL) ÷ [0.3] +× 0024 × 0308 × 0020 ÷ 0023 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] × 0024 ÷ 2014 ÷ # × [0.3] DOLLAR SIGN (PR) ÷ [999.0] EM DASH (B2) ÷ [0.3] × 0024 × 0020 ÷ 2014 ÷ # × [0.3] DOLLAR SIGN (PR) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] -× 0024 × 0308 ÷ 2014 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] EM DASH (B2) ÷ [0.3] -× 0024 × 0308 × 0020 ÷ 2014 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] +× 0024 × 0308 ÷ 2014 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] EM DASH (B2) ÷ [0.3] +× 0024 × 0308 × 0020 ÷ 2014 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] × 0024 × 0009 ÷ # × [0.3] DOLLAR SIGN (PR) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] × 0024 × 0020 ÷ 0009 ÷ # × [0.3] DOLLAR SIGN (PR) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] -× 0024 × 0308 × 0009 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] -× 0024 × 0308 × 0020 ÷ 0009 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] +× 0024 × 0308 × 0009 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] +× 0024 × 0308 × 0020 ÷ 0009 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] × 0024 ÷ 00B4 ÷ # × [0.3] DOLLAR SIGN (PR) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3] × 0024 × 0020 ÷ 00B4 ÷ # × [0.3] DOLLAR SIGN (PR) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] -× 0024 × 0308 ÷ 00B4 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3] -× 0024 × 0308 × 0020 ÷ 00B4 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] +× 0024 × 0308 ÷ 00B4 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3] +× 0024 × 0308 × 0020 ÷ 00B4 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] × 0024 × 000B ÷ # × [0.3] DOLLAR SIGN (PR) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] × 0024 × 0020 × 000B ÷ # × [0.3] DOLLAR SIGN (PR) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] -× 0024 × 0308 × 000B ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] -× 0024 × 0308 × 0020 × 000B ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] +× 0024 × 0308 × 000B ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] +× 0024 × 0308 × 0020 × 000B ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] × 0024 ÷ FFFC ÷ # × [0.3] DOLLAR SIGN (PR) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] × 0024 × 0020 ÷ FFFC ÷ # × [0.3] DOLLAR SIGN (PR) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] -× 0024 × 0308 ÷ FFFC ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] -× 0024 × 0308 × 0020 ÷ FFFC ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] +× 0024 × 0308 ÷ FFFC ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] +× 0024 × 0308 × 0020 ÷ FFFC ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] × 0024 × 007D ÷ # × [0.3] DOLLAR SIGN (PR) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] × 0024 × 0020 × 007D ÷ # × [0.3] DOLLAR SIGN (PR) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] -× 0024 × 0308 × 007D ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM) × [13.03] RIGHT CURLY BRACKET (CL) ÷ [0.3] -× 0024 × 0308 × 0020 × 007D ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] +× 0024 × 0308 × 007D ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] RIGHT CURLY BRACKET (CL) ÷ [0.3] +× 0024 × 0308 × 0020 × 007D ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] × 0024 × 0029 ÷ # × [0.3] DOLLAR SIGN (PR) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] × 0024 × 0020 × 0029 ÷ # × [0.3] DOLLAR SIGN (PR) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 0024 × 0308 × 0029 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM) × [13.03] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 0024 × 0308 × 0020 × 0029 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 0024 × 0001 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] <START OF HEADING> (CM) ÷ [0.3] -× 0024 × 0020 ÷ 0001 ÷ # × [0.3] DOLLAR SIGN (PR) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM) ÷ [0.3] -× 0024 × 0308 × 0001 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM) × [9.0] <START OF HEADING> (CM) ÷ [0.3] -× 0024 × 0308 × 0020 ÷ 0001 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM) ÷ [0.3] +× 0024 × 0308 × 0029 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] RIGHT PARENTHESIS (CP) ÷ [0.3] +× 0024 × 0308 × 0020 × 0029 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] × 0024 × 000D ÷ # × [0.3] DOLLAR SIGN (PR) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] × 0024 × 0020 × 000D ÷ # × [0.3] DOLLAR SIGN (PR) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -× 0024 × 0308 × 000D ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -× 0024 × 0308 × 0020 × 000D ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +× 0024 × 0308 × 000D ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +× 0024 × 0308 × 0020 × 000D ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] × 0024 × 0021 ÷ # × [0.3] DOLLAR SIGN (PR) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] × 0024 × 0020 × 0021 ÷ # × [0.3] DOLLAR SIGN (PR) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] -× 0024 × 0308 × 0021 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] -× 0024 × 0308 × 0020 × 0021 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] +× 0024 × 0308 × 0021 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] +× 0024 × 0308 × 0020 × 0021 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] × 0024 × 00A0 ÷ # × [0.3] DOLLAR SIGN (PR) × [12.1] NO-BREAK SPACE (GL) ÷ [0.3] × 0024 × 0020 ÷ 00A0 ÷ # × [0.3] DOLLAR SIGN (PR) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] -× 0024 × 0308 × 00A0 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM) × [12.2] NO-BREAK SPACE (GL) ÷ [0.3] -× 0024 × 0308 × 0020 ÷ 00A0 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] +× 0024 × 0308 × 00A0 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) × [12.2] NO-BREAK SPACE (GL) ÷ [0.3] +× 0024 × 0308 × 0020 ÷ 00A0 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] × 0024 × AC00 ÷ # × [0.3] DOLLAR SIGN (PR) × [27.03] HANGUL SYLLABLE GA (H2) ÷ [0.3] × 0024 × 0020 ÷ AC00 ÷ # × [0.3] DOLLAR SIGN (PR) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] -× 0024 × 0308 × AC00 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM) × [27.03] HANGUL SYLLABLE GA (H2) ÷ [0.3] -× 0024 × 0308 × 0020 ÷ AC00 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] +× 0024 × 0308 × AC00 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) × [27.03] HANGUL SYLLABLE GA (H2) ÷ [0.3] +× 0024 × 0308 × 0020 ÷ AC00 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] × 0024 × AC01 ÷ # × [0.3] DOLLAR SIGN (PR) × [27.03] HANGUL SYLLABLE GAG (H3) ÷ [0.3] × 0024 × 0020 ÷ AC01 ÷ # × [0.3] DOLLAR SIGN (PR) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] -× 0024 × 0308 × AC01 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM) × [27.03] HANGUL SYLLABLE GAG (H3) ÷ [0.3] -× 0024 × 0308 × 0020 ÷ AC01 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] +× 0024 × 0308 × AC01 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) × [27.03] HANGUL SYLLABLE GAG (H3) ÷ [0.3] +× 0024 × 0308 × 0020 ÷ AC01 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] × 0024 × 05D0 ÷ # × [0.3] DOLLAR SIGN (PR) × [24.02] HEBREW LETTER ALEF (HL) ÷ [0.3] × 0024 × 0020 ÷ 05D0 ÷ # × [0.3] DOLLAR SIGN (PR) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] -× 0024 × 0308 × 05D0 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM) × [24.02] HEBREW LETTER ALEF (HL) ÷ [0.3] -× 0024 × 0308 × 0020 ÷ 05D0 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] +× 0024 × 0308 × 05D0 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) × [24.02] HEBREW LETTER ALEF (HL) ÷ [0.3] +× 0024 × 0308 × 0020 ÷ 05D0 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] × 0024 × 002D ÷ # × [0.3] DOLLAR SIGN (PR) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] × 0024 × 0020 ÷ 002D ÷ # × [0.3] DOLLAR SIGN (PR) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] -× 0024 × 0308 × 002D ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] -× 0024 × 0308 × 0020 ÷ 002D ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] -× 0024 × 231A ÷ # × [0.3] DOLLAR SIGN (PR) × [24.01] WATCH (ID) ÷ [0.3] +× 0024 × 0308 × 002D ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] +× 0024 × 0308 × 0020 ÷ 002D ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] +× 0024 × 231A ÷ # × [0.3] DOLLAR SIGN (PR) × [23.12] WATCH (ID) ÷ [0.3] × 0024 × 0020 ÷ 231A ÷ # × [0.3] DOLLAR SIGN (PR) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] -× 0024 × 0308 × 231A ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM) × [24.01] WATCH (ID) ÷ [0.3] -× 0024 × 0308 × 0020 ÷ 231A ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] +× 0024 × 0308 × 231A ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) × [23.12] WATCH (ID) ÷ [0.3] +× 0024 × 0308 × 0020 ÷ 231A ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] × 0024 ÷ 2024 ÷ # × [0.3] DOLLAR SIGN (PR) ÷ [999.0] ONE DOT LEADER (IN) ÷ [0.3] × 0024 × 0020 ÷ 2024 ÷ # × [0.3] DOLLAR SIGN (PR) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] -× 0024 × 0308 ÷ 2024 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] ONE DOT LEADER (IN) ÷ [0.3] -× 0024 × 0308 × 0020 ÷ 2024 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] +× 0024 × 0308 ÷ 2024 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] ONE DOT LEADER (IN) ÷ [0.3] +× 0024 × 0308 × 0020 ÷ 2024 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] × 0024 × 002C ÷ # × [0.3] DOLLAR SIGN (PR) × [13.02] COMMA (IS) ÷ [0.3] × 0024 × 0020 × 002C ÷ # × [0.3] DOLLAR SIGN (PR) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] -× 0024 × 0308 × 002C ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM) × [13.03] COMMA (IS) ÷ [0.3] -× 0024 × 0308 × 0020 × 002C ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] +× 0024 × 0308 × 002C ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] COMMA (IS) ÷ [0.3] +× 0024 × 0308 × 0020 × 002C ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] × 0024 × 1100 ÷ # × [0.3] DOLLAR SIGN (PR) × [27.03] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] × 0024 × 0020 ÷ 1100 ÷ # × [0.3] DOLLAR SIGN (PR) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] -× 0024 × 0308 × 1100 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM) × [27.03] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] -× 0024 × 0308 × 0020 ÷ 1100 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] +× 0024 × 0308 × 1100 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) × [27.03] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] +× 0024 × 0308 × 0020 ÷ 1100 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] × 0024 × 11A8 ÷ # × [0.3] DOLLAR SIGN (PR) × [27.03] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] × 0024 × 0020 ÷ 11A8 ÷ # × [0.3] DOLLAR SIGN (PR) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] -× 0024 × 0308 × 11A8 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM) × [27.03] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] -× 0024 × 0308 × 0020 ÷ 11A8 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] +× 0024 × 0308 × 11A8 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) × [27.03] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] +× 0024 × 0308 × 0020 ÷ 11A8 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] × 0024 × 1160 ÷ # × [0.3] DOLLAR SIGN (PR) × [27.03] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] × 0024 × 0020 ÷ 1160 ÷ # × [0.3] DOLLAR SIGN (PR) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] -× 0024 × 0308 × 1160 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM) × [27.03] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] -× 0024 × 0308 × 0020 ÷ 1160 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] +× 0024 × 0308 × 1160 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) × [27.03] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] +× 0024 × 0308 × 0020 ÷ 1160 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] × 0024 × 000A ÷ # × [0.3] DOLLAR SIGN (PR) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] × 0024 × 0020 × 000A ÷ # × [0.3] DOLLAR SIGN (PR) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] -× 0024 × 0308 × 000A ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] -× 0024 × 0308 × 0020 × 000A ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] +× 0024 × 0308 × 000A ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] +× 0024 × 0308 × 0020 × 000A ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] × 0024 × 0085 ÷ # × [0.3] DOLLAR SIGN (PR) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] × 0024 × 0020 × 0085 ÷ # × [0.3] DOLLAR SIGN (PR) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] -× 0024 × 0308 × 0085 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] -× 0024 × 0308 × 0020 × 0085 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] +× 0024 × 0308 × 0085 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] +× 0024 × 0308 × 0020 × 0085 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] × 0024 × 17D6 ÷ # × [0.3] DOLLAR SIGN (PR) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] × 0024 × 0020 ÷ 17D6 ÷ # × [0.3] DOLLAR SIGN (PR) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] -× 0024 × 0308 × 17D6 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] -× 0024 × 0308 × 0020 ÷ 17D6 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] +× 0024 × 0308 × 17D6 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] +× 0024 × 0308 × 0020 ÷ 17D6 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] × 0024 × 0030 ÷ # × [0.3] DOLLAR SIGN (PR) × [25.01] DIGIT ZERO (NU) ÷ [0.3] × 0024 × 0020 ÷ 0030 ÷ # × [0.3] DOLLAR SIGN (PR) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] -× 0024 × 0308 × 0030 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM) × [25.01] DIGIT ZERO (NU) ÷ [0.3] -× 0024 × 0308 × 0020 ÷ 0030 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] +× 0024 × 0308 × 0030 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) × [25.01] DIGIT ZERO (NU) ÷ [0.3] +× 0024 × 0308 × 0020 ÷ 0030 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] × 0024 ÷ 0028 ÷ # × [0.3] DOLLAR SIGN (PR) ÷ [999.0] LEFT PARENTHESIS (OP) ÷ [0.3] × 0024 × 0020 ÷ 0028 ÷ # × [0.3] DOLLAR SIGN (PR) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] -× 0024 × 0308 ÷ 0028 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] LEFT PARENTHESIS (OP) ÷ [0.3] -× 0024 × 0308 × 0020 ÷ 0028 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] +× 0024 × 0308 ÷ 0028 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] LEFT PARENTHESIS (OP) ÷ [0.3] +× 0024 × 0308 × 0020 ÷ 0028 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] × 0024 ÷ 0025 ÷ # × [0.3] DOLLAR SIGN (PR) ÷ [999.0] PERCENT SIGN (PO) ÷ [0.3] × 0024 × 0020 ÷ 0025 ÷ # × [0.3] DOLLAR SIGN (PR) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] -× 0024 × 0308 ÷ 0025 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] PERCENT SIGN (PO) ÷ [0.3] -× 0024 × 0308 × 0020 ÷ 0025 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] +× 0024 × 0308 ÷ 0025 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] PERCENT SIGN (PO) ÷ [0.3] +× 0024 × 0308 × 0020 ÷ 0025 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] × 0024 ÷ 0024 ÷ # × [0.3] DOLLAR SIGN (PR) ÷ [999.0] DOLLAR SIGN (PR) ÷ [0.3] × 0024 × 0020 ÷ 0024 ÷ # × [0.3] DOLLAR SIGN (PR) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] -× 0024 × 0308 ÷ 0024 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] DOLLAR SIGN (PR) ÷ [0.3] -× 0024 × 0308 × 0020 ÷ 0024 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] +× 0024 × 0308 ÷ 0024 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] DOLLAR SIGN (PR) ÷ [0.3] +× 0024 × 0308 × 0020 ÷ 0024 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] × 0024 × 0022 ÷ # × [0.3] DOLLAR SIGN (PR) × [19.01] QUOTATION MARK (QU) ÷ [0.3] × 0024 × 0020 ÷ 0022 ÷ # × [0.3] DOLLAR SIGN (PR) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] -× 0024 × 0308 × 0022 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM) × [19.01] QUOTATION MARK (QU) ÷ [0.3] -× 0024 × 0308 × 0020 ÷ 0022 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] +× 0024 × 0308 × 0022 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) × [19.01] QUOTATION MARK (QU) ÷ [0.3] +× 0024 × 0308 × 0020 ÷ 0022 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] × 0024 × 0020 ÷ # × [0.3] DOLLAR SIGN (PR) × [7.01] SPACE (SP) ÷ [0.3] × 0024 × 0020 × 0020 ÷ # × [0.3] DOLLAR SIGN (PR) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] -× 0024 × 0308 × 0020 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [0.3] -× 0024 × 0308 × 0020 × 0020 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] +× 0024 × 0308 × 0020 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [0.3] +× 0024 × 0308 × 0020 × 0020 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] × 0024 × 002F ÷ # × [0.3] DOLLAR SIGN (PR) × [13.02] SOLIDUS (SY) ÷ [0.3] × 0024 × 0020 × 002F ÷ # × [0.3] DOLLAR SIGN (PR) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] -× 0024 × 0308 × 002F ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM) × [13.03] SOLIDUS (SY) ÷ [0.3] -× 0024 × 0308 × 0020 × 002F ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] +× 0024 × 0308 × 002F ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] SOLIDUS (SY) ÷ [0.3] +× 0024 × 0308 × 0020 × 002F ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] × 0024 × 2060 ÷ # × [0.3] DOLLAR SIGN (PR) × [11.01] WORD JOINER (WJ) ÷ [0.3] × 0024 × 0020 × 2060 ÷ # × [0.3] DOLLAR SIGN (PR) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] -× 0024 × 0308 × 2060 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM) × [11.01] WORD JOINER (WJ) ÷ [0.3] -× 0024 × 0308 × 0020 × 2060 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] +× 0024 × 0308 × 2060 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) × [11.01] WORD JOINER (WJ) ÷ [0.3] +× 0024 × 0308 × 0020 × 2060 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] × 0024 × 200B ÷ # × [0.3] DOLLAR SIGN (PR) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] × 0024 × 0020 × 200B ÷ # × [0.3] DOLLAR SIGN (PR) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] -× 0024 × 0308 × 200B ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] -× 0024 × 0308 × 0020 × 200B ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] +× 0024 × 0308 × 200B ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] +× 0024 × 0308 × 0020 × 200B ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] × 0024 ÷ 1F1E6 ÷ # × [0.3] DOLLAR SIGN (PR) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] × 0024 × 0020 ÷ 1F1E6 ÷ # × [0.3] DOLLAR SIGN (PR) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -× 0024 × 0308 ÷ 1F1E6 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -× 0024 × 0308 × 0020 ÷ 1F1E6 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 0024 × 0308 ÷ 1F1E6 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 0024 × 0308 × 0020 ÷ 1F1E6 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 0024 × 261D ÷ # × [0.3] DOLLAR SIGN (PR) × [23.12] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 0024 × 0020 ÷ 261D ÷ # × [0.3] DOLLAR SIGN (PR) × [7.01] SPACE (SP) ÷ [18.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 0024 × 0308 × 261D ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) × [23.12] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 0024 × 0308 × 0020 ÷ 261D ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 0024 × 1F3FB ÷ # × [0.3] DOLLAR SIGN (PR) × [23.12] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 0024 × 0020 ÷ 1F3FB ÷ # × [0.3] DOLLAR SIGN (PR) × [7.01] SPACE (SP) ÷ [18.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 0024 × 0308 × 1F3FB ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) × [23.12] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 0024 × 0308 × 0020 ÷ 1F3FB ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 0024 × 0001 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 0024 × 0020 ÷ 0001 ÷ # × [0.3] DOLLAR SIGN (PR) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 0024 × 0308 × 0001 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) × [9.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 0024 × 0308 × 0020 ÷ 0001 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 0024 × 200D ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 0024 × 0020 ÷ 200D ÷ # × [0.3] DOLLAR SIGN (PR) × [7.01] SPACE (SP) ÷ [18.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 0024 × 0308 × 200D ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) × [9.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 0024 × 0308 × 0020 ÷ 200D ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] × 0024 × 00A7 ÷ # × [0.3] DOLLAR SIGN (PR) × [24.02] SECTION SIGN (AI_AL) ÷ [0.3] × 0024 × 0020 ÷ 00A7 ÷ # × [0.3] DOLLAR SIGN (PR) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] -× 0024 × 0308 × 00A7 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM) × [24.02] SECTION SIGN (AI_AL) ÷ [0.3] -× 0024 × 0308 × 0020 ÷ 00A7 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] +× 0024 × 0308 × 00A7 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) × [24.02] SECTION SIGN (AI_AL) ÷ [0.3] +× 0024 × 0308 × 0020 ÷ 00A7 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] × 0024 × 50005 ÷ # × [0.3] DOLLAR SIGN (PR) × [24.02] <reserved-50005> (XX_AL) ÷ [0.3] × 0024 × 0020 ÷ 50005 ÷ # × [0.3] DOLLAR SIGN (PR) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] -× 0024 × 0308 × 50005 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM) × [24.02] <reserved-50005> (XX_AL) ÷ [0.3] -× 0024 × 0308 × 0020 ÷ 50005 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] +× 0024 × 0308 × 50005 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) × [24.02] <reserved-50005> (XX_AL) ÷ [0.3] +× 0024 × 0308 × 0020 ÷ 50005 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] × 0024 × 0E01 ÷ # × [0.3] DOLLAR SIGN (PR) × [24.02] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] × 0024 × 0020 ÷ 0E01 ÷ # × [0.3] DOLLAR SIGN (PR) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] -× 0024 × 0308 × 0E01 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM) × [24.02] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] -× 0024 × 0308 × 0020 ÷ 0E01 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] +× 0024 × 0308 × 0E01 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) × [24.02] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] +× 0024 × 0308 × 0020 ÷ 0E01 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] × 0024 × 3041 ÷ # × [0.3] DOLLAR SIGN (PR) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] × 0024 × 0020 ÷ 3041 ÷ # × [0.3] DOLLAR SIGN (PR) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] -× 0024 × 0308 × 3041 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] -× 0024 × 0308 × 0020 ÷ 3041 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] +× 0024 × 0308 × 3041 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] +× 0024 × 0308 × 0020 ÷ 3041 ÷ # × [0.3] DOLLAR SIGN (PR) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] × 0022 × 0023 ÷ # × [0.3] QUOTATION MARK (QU) × [19.02] NUMBER SIGN (AL) ÷ [0.3] × 0022 × 0020 ÷ 0023 ÷ # × [0.3] QUOTATION MARK (QU) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] -× 0022 × 0308 × 0023 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM) × [19.02] NUMBER SIGN (AL) ÷ [0.3] -× 0022 × 0308 × 0020 ÷ 0023 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] +× 0022 × 0308 × 0023 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [19.02] NUMBER SIGN (AL) ÷ [0.3] +× 0022 × 0308 × 0020 ÷ 0023 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] × 0022 × 2014 ÷ # × [0.3] QUOTATION MARK (QU) × [19.02] EM DASH (B2) ÷ [0.3] × 0022 × 0020 ÷ 2014 ÷ # × [0.3] QUOTATION MARK (QU) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] -× 0022 × 0308 × 2014 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM) × [19.02] EM DASH (B2) ÷ [0.3] -× 0022 × 0308 × 0020 ÷ 2014 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] +× 0022 × 0308 × 2014 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [19.02] EM DASH (B2) ÷ [0.3] +× 0022 × 0308 × 0020 ÷ 2014 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] × 0022 × 0009 ÷ # × [0.3] QUOTATION MARK (QU) × [19.02] <CHARACTER TABULATION> (BA) ÷ [0.3] × 0022 × 0020 ÷ 0009 ÷ # × [0.3] QUOTATION MARK (QU) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] -× 0022 × 0308 × 0009 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM) × [19.02] <CHARACTER TABULATION> (BA) ÷ [0.3] -× 0022 × 0308 × 0020 ÷ 0009 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] +× 0022 × 0308 × 0009 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [19.02] <CHARACTER TABULATION> (BA) ÷ [0.3] +× 0022 × 0308 × 0020 ÷ 0009 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] × 0022 × 00B4 ÷ # × [0.3] QUOTATION MARK (QU) × [19.02] ACUTE ACCENT (BB) ÷ [0.3] × 0022 × 0020 ÷ 00B4 ÷ # × [0.3] QUOTATION MARK (QU) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] -× 0022 × 0308 × 00B4 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM) × [19.02] ACUTE ACCENT (BB) ÷ [0.3] -× 0022 × 0308 × 0020 ÷ 00B4 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] +× 0022 × 0308 × 00B4 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [19.02] ACUTE ACCENT (BB) ÷ [0.3] +× 0022 × 0308 × 0020 ÷ 00B4 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] × 0022 × 000B ÷ # × [0.3] QUOTATION MARK (QU) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] × 0022 × 0020 × 000B ÷ # × [0.3] QUOTATION MARK (QU) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] -× 0022 × 0308 × 000B ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] -× 0022 × 0308 × 0020 × 000B ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] +× 0022 × 0308 × 000B ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] +× 0022 × 0308 × 0020 × 000B ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] × 0022 × FFFC ÷ # × [0.3] QUOTATION MARK (QU) × [19.02] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] × 0022 × 0020 ÷ FFFC ÷ # × [0.3] QUOTATION MARK (QU) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] -× 0022 × 0308 × FFFC ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM) × [19.02] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] -× 0022 × 0308 × 0020 ÷ FFFC ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] +× 0022 × 0308 × FFFC ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [19.02] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] +× 0022 × 0308 × 0020 ÷ FFFC ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] × 0022 × 007D ÷ # × [0.3] QUOTATION MARK (QU) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] × 0022 × 0020 × 007D ÷ # × [0.3] QUOTATION MARK (QU) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] -× 0022 × 0308 × 007D ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM) × [13.03] RIGHT CURLY BRACKET (CL) ÷ [0.3] -× 0022 × 0308 × 0020 × 007D ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] +× 0022 × 0308 × 007D ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] RIGHT CURLY BRACKET (CL) ÷ [0.3] +× 0022 × 0308 × 0020 × 007D ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] × 0022 × 0029 ÷ # × [0.3] QUOTATION MARK (QU) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] × 0022 × 0020 × 0029 ÷ # × [0.3] QUOTATION MARK (QU) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 0022 × 0308 × 0029 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM) × [13.03] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 0022 × 0308 × 0020 × 0029 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 0022 × 0001 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] <START OF HEADING> (CM) ÷ [0.3] -× 0022 × 0020 ÷ 0001 ÷ # × [0.3] QUOTATION MARK (QU) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM) ÷ [0.3] -× 0022 × 0308 × 0001 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM) × [9.0] <START OF HEADING> (CM) ÷ [0.3] -× 0022 × 0308 × 0020 ÷ 0001 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM) ÷ [0.3] +× 0022 × 0308 × 0029 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] RIGHT PARENTHESIS (CP) ÷ [0.3] +× 0022 × 0308 × 0020 × 0029 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] × 0022 × 000D ÷ # × [0.3] QUOTATION MARK (QU) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] × 0022 × 0020 × 000D ÷ # × [0.3] QUOTATION MARK (QU) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -× 0022 × 0308 × 000D ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -× 0022 × 0308 × 0020 × 000D ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +× 0022 × 0308 × 000D ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +× 0022 × 0308 × 0020 × 000D ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] × 0022 × 0021 ÷ # × [0.3] QUOTATION MARK (QU) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] × 0022 × 0020 × 0021 ÷ # × [0.3] QUOTATION MARK (QU) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] -× 0022 × 0308 × 0021 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] -× 0022 × 0308 × 0020 × 0021 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] +× 0022 × 0308 × 0021 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] +× 0022 × 0308 × 0020 × 0021 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] × 0022 × 00A0 ÷ # × [0.3] QUOTATION MARK (QU) × [12.1] NO-BREAK SPACE (GL) ÷ [0.3] × 0022 × 0020 ÷ 00A0 ÷ # × [0.3] QUOTATION MARK (QU) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] -× 0022 × 0308 × 00A0 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM) × [12.2] NO-BREAK SPACE (GL) ÷ [0.3] -× 0022 × 0308 × 0020 ÷ 00A0 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] +× 0022 × 0308 × 00A0 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [12.2] NO-BREAK SPACE (GL) ÷ [0.3] +× 0022 × 0308 × 0020 ÷ 00A0 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] × 0022 × AC00 ÷ # × [0.3] QUOTATION MARK (QU) × [19.02] HANGUL SYLLABLE GA (H2) ÷ [0.3] × 0022 × 0020 ÷ AC00 ÷ # × [0.3] QUOTATION MARK (QU) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] -× 0022 × 0308 × AC00 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM) × [19.02] HANGUL SYLLABLE GA (H2) ÷ [0.3] -× 0022 × 0308 × 0020 ÷ AC00 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] +× 0022 × 0308 × AC00 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [19.02] HANGUL SYLLABLE GA (H2) ÷ [0.3] +× 0022 × 0308 × 0020 ÷ AC00 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] × 0022 × AC01 ÷ # × [0.3] QUOTATION MARK (QU) × [19.02] HANGUL SYLLABLE GAG (H3) ÷ [0.3] × 0022 × 0020 ÷ AC01 ÷ # × [0.3] QUOTATION MARK (QU) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] -× 0022 × 0308 × AC01 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM) × [19.02] HANGUL SYLLABLE GAG (H3) ÷ [0.3] -× 0022 × 0308 × 0020 ÷ AC01 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] +× 0022 × 0308 × AC01 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [19.02] HANGUL SYLLABLE GAG (H3) ÷ [0.3] +× 0022 × 0308 × 0020 ÷ AC01 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] × 0022 × 05D0 ÷ # × [0.3] QUOTATION MARK (QU) × [19.02] HEBREW LETTER ALEF (HL) ÷ [0.3] × 0022 × 0020 ÷ 05D0 ÷ # × [0.3] QUOTATION MARK (QU) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] -× 0022 × 0308 × 05D0 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM) × [19.02] HEBREW LETTER ALEF (HL) ÷ [0.3] -× 0022 × 0308 × 0020 ÷ 05D0 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] +× 0022 × 0308 × 05D0 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [19.02] HEBREW LETTER ALEF (HL) ÷ [0.3] +× 0022 × 0308 × 0020 ÷ 05D0 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] × 0022 × 002D ÷ # × [0.3] QUOTATION MARK (QU) × [19.02] HYPHEN-MINUS (HY) ÷ [0.3] × 0022 × 0020 ÷ 002D ÷ # × [0.3] QUOTATION MARK (QU) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] -× 0022 × 0308 × 002D ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM) × [19.02] HYPHEN-MINUS (HY) ÷ [0.3] -× 0022 × 0308 × 0020 ÷ 002D ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] +× 0022 × 0308 × 002D ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [19.02] HYPHEN-MINUS (HY) ÷ [0.3] +× 0022 × 0308 × 0020 ÷ 002D ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] × 0022 × 231A ÷ # × [0.3] QUOTATION MARK (QU) × [19.02] WATCH (ID) ÷ [0.3] × 0022 × 0020 ÷ 231A ÷ # × [0.3] QUOTATION MARK (QU) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] -× 0022 × 0308 × 231A ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM) × [19.02] WATCH (ID) ÷ [0.3] -× 0022 × 0308 × 0020 ÷ 231A ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] +× 0022 × 0308 × 231A ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [19.02] WATCH (ID) ÷ [0.3] +× 0022 × 0308 × 0020 ÷ 231A ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] × 0022 × 2024 ÷ # × [0.3] QUOTATION MARK (QU) × [19.02] ONE DOT LEADER (IN) ÷ [0.3] × 0022 × 0020 ÷ 2024 ÷ # × [0.3] QUOTATION MARK (QU) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] -× 0022 × 0308 × 2024 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM) × [19.02] ONE DOT LEADER (IN) ÷ [0.3] -× 0022 × 0308 × 0020 ÷ 2024 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] +× 0022 × 0308 × 2024 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [19.02] ONE DOT LEADER (IN) ÷ [0.3] +× 0022 × 0308 × 0020 ÷ 2024 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] × 0022 × 002C ÷ # × [0.3] QUOTATION MARK (QU) × [13.02] COMMA (IS) ÷ [0.3] × 0022 × 0020 × 002C ÷ # × [0.3] QUOTATION MARK (QU) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] -× 0022 × 0308 × 002C ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM) × [13.03] COMMA (IS) ÷ [0.3] -× 0022 × 0308 × 0020 × 002C ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] +× 0022 × 0308 × 002C ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] COMMA (IS) ÷ [0.3] +× 0022 × 0308 × 0020 × 002C ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] × 0022 × 1100 ÷ # × [0.3] QUOTATION MARK (QU) × [19.02] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] × 0022 × 0020 ÷ 1100 ÷ # × [0.3] QUOTATION MARK (QU) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] -× 0022 × 0308 × 1100 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM) × [19.02] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] -× 0022 × 0308 × 0020 ÷ 1100 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] +× 0022 × 0308 × 1100 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [19.02] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] +× 0022 × 0308 × 0020 ÷ 1100 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] × 0022 × 11A8 ÷ # × [0.3] QUOTATION MARK (QU) × [19.02] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] × 0022 × 0020 ÷ 11A8 ÷ # × [0.3] QUOTATION MARK (QU) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] -× 0022 × 0308 × 11A8 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM) × [19.02] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] -× 0022 × 0308 × 0020 ÷ 11A8 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] +× 0022 × 0308 × 11A8 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [19.02] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] +× 0022 × 0308 × 0020 ÷ 11A8 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] × 0022 × 1160 ÷ # × [0.3] QUOTATION MARK (QU) × [19.02] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] × 0022 × 0020 ÷ 1160 ÷ # × [0.3] QUOTATION MARK (QU) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] -× 0022 × 0308 × 1160 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM) × [19.02] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] -× 0022 × 0308 × 0020 ÷ 1160 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] +× 0022 × 0308 × 1160 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [19.02] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] +× 0022 × 0308 × 0020 ÷ 1160 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] × 0022 × 000A ÷ # × [0.3] QUOTATION MARK (QU) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] × 0022 × 0020 × 000A ÷ # × [0.3] QUOTATION MARK (QU) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] -× 0022 × 0308 × 000A ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] -× 0022 × 0308 × 0020 × 000A ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] +× 0022 × 0308 × 000A ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] +× 0022 × 0308 × 0020 × 000A ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] × 0022 × 0085 ÷ # × [0.3] QUOTATION MARK (QU) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] × 0022 × 0020 × 0085 ÷ # × [0.3] QUOTATION MARK (QU) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] -× 0022 × 0308 × 0085 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] -× 0022 × 0308 × 0020 × 0085 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] +× 0022 × 0308 × 0085 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] +× 0022 × 0308 × 0020 × 0085 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] × 0022 × 17D6 ÷ # × [0.3] QUOTATION MARK (QU) × [19.02] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] × 0022 × 0020 ÷ 17D6 ÷ # × [0.3] QUOTATION MARK (QU) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] -× 0022 × 0308 × 17D6 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM) × [19.02] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] -× 0022 × 0308 × 0020 ÷ 17D6 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] +× 0022 × 0308 × 17D6 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [19.02] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] +× 0022 × 0308 × 0020 ÷ 17D6 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] × 0022 × 0030 ÷ # × [0.3] QUOTATION MARK (QU) × [19.02] DIGIT ZERO (NU) ÷ [0.3] × 0022 × 0020 ÷ 0030 ÷ # × [0.3] QUOTATION MARK (QU) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] -× 0022 × 0308 × 0030 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM) × [19.02] DIGIT ZERO (NU) ÷ [0.3] -× 0022 × 0308 × 0020 ÷ 0030 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] +× 0022 × 0308 × 0030 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [19.02] DIGIT ZERO (NU) ÷ [0.3] +× 0022 × 0308 × 0020 ÷ 0030 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] × 0022 × 0028 ÷ # × [0.3] QUOTATION MARK (QU) × [15.0] LEFT PARENTHESIS (OP) ÷ [0.3] × 0022 × 0020 × 0028 ÷ # × [0.3] QUOTATION MARK (QU) × [7.01] SPACE (SP) × [15.0] LEFT PARENTHESIS (OP) ÷ [0.3] -× 0022 × 0308 × 0028 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM) × [15.0] LEFT PARENTHESIS (OP) ÷ [0.3] -× 0022 × 0308 × 0020 × 0028 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [15.0] LEFT PARENTHESIS (OP) ÷ [0.3] +× 0022 × 0308 × 0028 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [15.0] LEFT PARENTHESIS (OP) ÷ [0.3] +× 0022 × 0308 × 0020 × 0028 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [15.0] LEFT PARENTHESIS (OP) ÷ [0.3] × 0022 × 0025 ÷ # × [0.3] QUOTATION MARK (QU) × [19.02] PERCENT SIGN (PO) ÷ [0.3] × 0022 × 0020 ÷ 0025 ÷ # × [0.3] QUOTATION MARK (QU) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] -× 0022 × 0308 × 0025 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM) × [19.02] PERCENT SIGN (PO) ÷ [0.3] -× 0022 × 0308 × 0020 ÷ 0025 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] +× 0022 × 0308 × 0025 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [19.02] PERCENT SIGN (PO) ÷ [0.3] +× 0022 × 0308 × 0020 ÷ 0025 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] × 0022 × 0024 ÷ # × [0.3] QUOTATION MARK (QU) × [19.02] DOLLAR SIGN (PR) ÷ [0.3] × 0022 × 0020 ÷ 0024 ÷ # × [0.3] QUOTATION MARK (QU) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] -× 0022 × 0308 × 0024 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM) × [19.02] DOLLAR SIGN (PR) ÷ [0.3] -× 0022 × 0308 × 0020 ÷ 0024 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] +× 0022 × 0308 × 0024 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [19.02] DOLLAR SIGN (PR) ÷ [0.3] +× 0022 × 0308 × 0020 ÷ 0024 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] × 0022 × 0022 ÷ # × [0.3] QUOTATION MARK (QU) × [19.01] QUOTATION MARK (QU) ÷ [0.3] × 0022 × 0020 ÷ 0022 ÷ # × [0.3] QUOTATION MARK (QU) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] -× 0022 × 0308 × 0022 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM) × [19.01] QUOTATION MARK (QU) ÷ [0.3] -× 0022 × 0308 × 0020 ÷ 0022 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] +× 0022 × 0308 × 0022 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [19.01] QUOTATION MARK (QU) ÷ [0.3] +× 0022 × 0308 × 0020 ÷ 0022 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] × 0022 × 0020 ÷ # × [0.3] QUOTATION MARK (QU) × [7.01] SPACE (SP) ÷ [0.3] × 0022 × 0020 × 0020 ÷ # × [0.3] QUOTATION MARK (QU) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] -× 0022 × 0308 × 0020 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [0.3] -× 0022 × 0308 × 0020 × 0020 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] +× 0022 × 0308 × 0020 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [0.3] +× 0022 × 0308 × 0020 × 0020 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] × 0022 × 002F ÷ # × [0.3] QUOTATION MARK (QU) × [13.02] SOLIDUS (SY) ÷ [0.3] × 0022 × 0020 × 002F ÷ # × [0.3] QUOTATION MARK (QU) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] -× 0022 × 0308 × 002F ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM) × [13.03] SOLIDUS (SY) ÷ [0.3] -× 0022 × 0308 × 0020 × 002F ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] +× 0022 × 0308 × 002F ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] SOLIDUS (SY) ÷ [0.3] +× 0022 × 0308 × 0020 × 002F ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] × 0022 × 2060 ÷ # × [0.3] QUOTATION MARK (QU) × [11.01] WORD JOINER (WJ) ÷ [0.3] × 0022 × 0020 × 2060 ÷ # × [0.3] QUOTATION MARK (QU) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] -× 0022 × 0308 × 2060 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM) × [11.01] WORD JOINER (WJ) ÷ [0.3] -× 0022 × 0308 × 0020 × 2060 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] +× 0022 × 0308 × 2060 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [11.01] WORD JOINER (WJ) ÷ [0.3] +× 0022 × 0308 × 0020 × 2060 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] × 0022 × 200B ÷ # × [0.3] QUOTATION MARK (QU) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] × 0022 × 0020 × 200B ÷ # × [0.3] QUOTATION MARK (QU) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] -× 0022 × 0308 × 200B ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] -× 0022 × 0308 × 0020 × 200B ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] +× 0022 × 0308 × 200B ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] +× 0022 × 0308 × 0020 × 200B ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] × 0022 × 1F1E6 ÷ # × [0.3] QUOTATION MARK (QU) × [19.02] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] × 0022 × 0020 ÷ 1F1E6 ÷ # × [0.3] QUOTATION MARK (QU) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -× 0022 × 0308 × 1F1E6 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM) × [19.02] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -× 0022 × 0308 × 0020 ÷ 1F1E6 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 0022 × 0308 × 1F1E6 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [19.02] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 0022 × 0308 × 0020 ÷ 1F1E6 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 0022 × 261D ÷ # × [0.3] QUOTATION MARK (QU) × [19.02] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 0022 × 0020 ÷ 261D ÷ # × [0.3] QUOTATION MARK (QU) × [7.01] SPACE (SP) ÷ [18.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 0022 × 0308 × 261D ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [19.02] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 0022 × 0308 × 0020 ÷ 261D ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 0022 × 1F3FB ÷ # × [0.3] QUOTATION MARK (QU) × [19.02] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 0022 × 0020 ÷ 1F3FB ÷ # × [0.3] QUOTATION MARK (QU) × [7.01] SPACE (SP) ÷ [18.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 0022 × 0308 × 1F3FB ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [19.02] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 0022 × 0308 × 0020 ÷ 1F3FB ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 0022 × 0001 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 0022 × 0020 ÷ 0001 ÷ # × [0.3] QUOTATION MARK (QU) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 0022 × 0308 × 0001 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [9.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 0022 × 0308 × 0020 ÷ 0001 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 0022 × 200D ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 0022 × 0020 ÷ 200D ÷ # × [0.3] QUOTATION MARK (QU) × [7.01] SPACE (SP) ÷ [18.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 0022 × 0308 × 200D ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [9.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 0022 × 0308 × 0020 ÷ 200D ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] × 0022 × 00A7 ÷ # × [0.3] QUOTATION MARK (QU) × [19.02] SECTION SIGN (AI_AL) ÷ [0.3] × 0022 × 0020 ÷ 00A7 ÷ # × [0.3] QUOTATION MARK (QU) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] -× 0022 × 0308 × 00A7 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM) × [19.02] SECTION SIGN (AI_AL) ÷ [0.3] -× 0022 × 0308 × 0020 ÷ 00A7 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] +× 0022 × 0308 × 00A7 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [19.02] SECTION SIGN (AI_AL) ÷ [0.3] +× 0022 × 0308 × 0020 ÷ 00A7 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] × 0022 × 50005 ÷ # × [0.3] QUOTATION MARK (QU) × [19.02] <reserved-50005> (XX_AL) ÷ [0.3] × 0022 × 0020 ÷ 50005 ÷ # × [0.3] QUOTATION MARK (QU) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] -× 0022 × 0308 × 50005 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM) × [19.02] <reserved-50005> (XX_AL) ÷ [0.3] -× 0022 × 0308 × 0020 ÷ 50005 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] +× 0022 × 0308 × 50005 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [19.02] <reserved-50005> (XX_AL) ÷ [0.3] +× 0022 × 0308 × 0020 ÷ 50005 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] × 0022 × 0E01 ÷ # × [0.3] QUOTATION MARK (QU) × [19.02] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] × 0022 × 0020 ÷ 0E01 ÷ # × [0.3] QUOTATION MARK (QU) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] -× 0022 × 0308 × 0E01 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM) × [19.02] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] -× 0022 × 0308 × 0020 ÷ 0E01 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] +× 0022 × 0308 × 0E01 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [19.02] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] +× 0022 × 0308 × 0020 ÷ 0E01 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] × 0022 × 3041 ÷ # × [0.3] QUOTATION MARK (QU) × [19.02] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] × 0022 × 0020 ÷ 3041 ÷ # × [0.3] QUOTATION MARK (QU) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] -× 0022 × 0308 × 3041 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM) × [19.02] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] -× 0022 × 0308 × 0020 ÷ 3041 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] +× 0022 × 0308 × 3041 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [19.02] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] +× 0022 × 0308 × 0020 ÷ 3041 ÷ # × [0.3] QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] × 0020 ÷ 0023 ÷ # × [0.3] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] × 0020 × 0020 ÷ 0023 ÷ # × [0.3] SPACE (SP) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] -× 0020 ÷ 0308 × 0023 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM) × [28.0] NUMBER SIGN (AL) ÷ [0.3] -× 0020 ÷ 0308 × 0020 ÷ 0023 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] +× 0020 ÷ 0308 × 0023 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM1_CM) × [28.0] NUMBER SIGN (AL) ÷ [0.3] +× 0020 ÷ 0308 × 0020 ÷ 0023 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] × 0020 ÷ 2014 ÷ # × [0.3] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] × 0020 × 0020 ÷ 2014 ÷ # × [0.3] SPACE (SP) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] -× 0020 ÷ 0308 ÷ 2014 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM) ÷ [999.0] EM DASH (B2) ÷ [0.3] -× 0020 ÷ 0308 × 0020 ÷ 2014 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] +× 0020 ÷ 0308 ÷ 2014 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] EM DASH (B2) ÷ [0.3] +× 0020 ÷ 0308 × 0020 ÷ 2014 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] × 0020 ÷ 0009 ÷ # × [0.3] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] × 0020 × 0020 ÷ 0009 ÷ # × [0.3] SPACE (SP) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] -× 0020 ÷ 0308 × 0009 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] -× 0020 ÷ 0308 × 0020 ÷ 0009 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] +× 0020 ÷ 0308 × 0009 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM1_CM) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] +× 0020 ÷ 0308 × 0020 ÷ 0009 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] × 0020 ÷ 00B4 ÷ # × [0.3] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] × 0020 × 0020 ÷ 00B4 ÷ # × [0.3] SPACE (SP) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] -× 0020 ÷ 0308 ÷ 00B4 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3] -× 0020 ÷ 0308 × 0020 ÷ 00B4 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] +× 0020 ÷ 0308 ÷ 00B4 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3] +× 0020 ÷ 0308 × 0020 ÷ 00B4 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] × 0020 × 000B ÷ # × [0.3] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] × 0020 × 0020 × 000B ÷ # × [0.3] SPACE (SP) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] -× 0020 ÷ 0308 × 000B ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] -× 0020 ÷ 0308 × 0020 × 000B ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] +× 0020 ÷ 0308 × 000B ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] +× 0020 ÷ 0308 × 0020 × 000B ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] × 0020 ÷ FFFC ÷ # × [0.3] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] × 0020 × 0020 ÷ FFFC ÷ # × [0.3] SPACE (SP) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] -× 0020 ÷ 0308 ÷ FFFC ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] -× 0020 ÷ 0308 × 0020 ÷ FFFC ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] +× 0020 ÷ 0308 ÷ FFFC ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM1_CM) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] +× 0020 ÷ 0308 × 0020 ÷ FFFC ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] × 0020 × 007D ÷ # × [0.3] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] × 0020 × 0020 × 007D ÷ # × [0.3] SPACE (SP) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] -× 0020 ÷ 0308 × 007D ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM) × [13.03] RIGHT CURLY BRACKET (CL) ÷ [0.3] -× 0020 ÷ 0308 × 0020 × 007D ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] +× 0020 ÷ 0308 × 007D ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM1_CM) × [13.03] RIGHT CURLY BRACKET (CL) ÷ [0.3] +× 0020 ÷ 0308 × 0020 × 007D ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] × 0020 × 0029 ÷ # × [0.3] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] × 0020 × 0020 × 0029 ÷ # × [0.3] SPACE (SP) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 0020 ÷ 0308 × 0029 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM) × [13.03] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 0020 ÷ 0308 × 0020 × 0029 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 0020 ÷ 0001 ÷ # × [0.3] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM) ÷ [0.3] -× 0020 × 0020 ÷ 0001 ÷ # × [0.3] SPACE (SP) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM) ÷ [0.3] -× 0020 ÷ 0308 × 0001 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM) × [9.0] <START OF HEADING> (CM) ÷ [0.3] -× 0020 ÷ 0308 × 0020 ÷ 0001 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM) ÷ [0.3] +× 0020 ÷ 0308 × 0029 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM1_CM) × [13.03] RIGHT PARENTHESIS (CP) ÷ [0.3] +× 0020 ÷ 0308 × 0020 × 0029 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] × 0020 × 000D ÷ # × [0.3] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] × 0020 × 0020 × 000D ÷ # × [0.3] SPACE (SP) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -× 0020 ÷ 0308 × 000D ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -× 0020 ÷ 0308 × 0020 × 000D ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +× 0020 ÷ 0308 × 000D ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +× 0020 ÷ 0308 × 0020 × 000D ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] × 0020 × 0021 ÷ # × [0.3] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] × 0020 × 0020 × 0021 ÷ # × [0.3] SPACE (SP) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] -× 0020 ÷ 0308 × 0021 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] -× 0020 ÷ 0308 × 0020 × 0021 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] +× 0020 ÷ 0308 × 0021 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM1_CM) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] +× 0020 ÷ 0308 × 0020 × 0021 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] × 0020 ÷ 00A0 ÷ # × [0.3] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] × 0020 × 0020 ÷ 00A0 ÷ # × [0.3] SPACE (SP) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] -× 0020 ÷ 0308 × 00A0 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM) × [12.2] NO-BREAK SPACE (GL) ÷ [0.3] -× 0020 ÷ 0308 × 0020 ÷ 00A0 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] +× 0020 ÷ 0308 × 00A0 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM1_CM) × [12.2] NO-BREAK SPACE (GL) ÷ [0.3] +× 0020 ÷ 0308 × 0020 ÷ 00A0 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] × 0020 ÷ AC00 ÷ # × [0.3] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] × 0020 × 0020 ÷ AC00 ÷ # × [0.3] SPACE (SP) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] -× 0020 ÷ 0308 ÷ AC00 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] -× 0020 ÷ 0308 × 0020 ÷ AC00 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] +× 0020 ÷ 0308 ÷ AC00 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] +× 0020 ÷ 0308 × 0020 ÷ AC00 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] × 0020 ÷ AC01 ÷ # × [0.3] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] × 0020 × 0020 ÷ AC01 ÷ # × [0.3] SPACE (SP) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] -× 0020 ÷ 0308 ÷ AC01 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] -× 0020 ÷ 0308 × 0020 ÷ AC01 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] +× 0020 ÷ 0308 ÷ AC01 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] +× 0020 ÷ 0308 × 0020 ÷ AC01 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] × 0020 ÷ 05D0 ÷ # × [0.3] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] × 0020 × 0020 ÷ 05D0 ÷ # × [0.3] SPACE (SP) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] -× 0020 ÷ 0308 × 05D0 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM) × [28.0] HEBREW LETTER ALEF (HL) ÷ [0.3] -× 0020 ÷ 0308 × 0020 ÷ 05D0 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] +× 0020 ÷ 0308 × 05D0 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM1_CM) × [28.0] HEBREW LETTER ALEF (HL) ÷ [0.3] +× 0020 ÷ 0308 × 0020 ÷ 05D0 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] × 0020 ÷ 002D ÷ # × [0.3] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] × 0020 × 0020 ÷ 002D ÷ # × [0.3] SPACE (SP) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] -× 0020 ÷ 0308 × 002D ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] -× 0020 ÷ 0308 × 0020 ÷ 002D ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] +× 0020 ÷ 0308 × 002D ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM1_CM) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] +× 0020 ÷ 0308 × 0020 ÷ 002D ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] × 0020 ÷ 231A ÷ # × [0.3] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] × 0020 × 0020 ÷ 231A ÷ # × [0.3] SPACE (SP) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] -× 0020 ÷ 0308 ÷ 231A ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM) ÷ [999.0] WATCH (ID) ÷ [0.3] -× 0020 ÷ 0308 × 0020 ÷ 231A ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] +× 0020 ÷ 0308 ÷ 231A ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] WATCH (ID) ÷ [0.3] +× 0020 ÷ 0308 × 0020 ÷ 231A ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] × 0020 ÷ 2024 ÷ # × [0.3] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] × 0020 × 0020 ÷ 2024 ÷ # × [0.3] SPACE (SP) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] -× 0020 ÷ 0308 × 2024 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM) × [22.01] ONE DOT LEADER (IN) ÷ [0.3] -× 0020 ÷ 0308 × 0020 ÷ 2024 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] +× 0020 ÷ 0308 × 2024 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM1_CM) × [22.01] ONE DOT LEADER (IN) ÷ [0.3] +× 0020 ÷ 0308 × 0020 ÷ 2024 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] × 0020 × 002C ÷ # × [0.3] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] × 0020 × 0020 × 002C ÷ # × [0.3] SPACE (SP) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] -× 0020 ÷ 0308 × 002C ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM) × [13.03] COMMA (IS) ÷ [0.3] -× 0020 ÷ 0308 × 0020 × 002C ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] +× 0020 ÷ 0308 × 002C ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM1_CM) × [13.03] COMMA (IS) ÷ [0.3] +× 0020 ÷ 0308 × 0020 × 002C ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] × 0020 ÷ 1100 ÷ # × [0.3] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] × 0020 × 0020 ÷ 1100 ÷ # × [0.3] SPACE (SP) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] -× 0020 ÷ 0308 ÷ 1100 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] -× 0020 ÷ 0308 × 0020 ÷ 1100 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] +× 0020 ÷ 0308 ÷ 1100 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] +× 0020 ÷ 0308 × 0020 ÷ 1100 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] × 0020 ÷ 11A8 ÷ # × [0.3] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] × 0020 × 0020 ÷ 11A8 ÷ # × [0.3] SPACE (SP) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] -× 0020 ÷ 0308 ÷ 11A8 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] -× 0020 ÷ 0308 × 0020 ÷ 11A8 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] +× 0020 ÷ 0308 ÷ 11A8 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] +× 0020 ÷ 0308 × 0020 ÷ 11A8 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] × 0020 ÷ 1160 ÷ # × [0.3] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] × 0020 × 0020 ÷ 1160 ÷ # × [0.3] SPACE (SP) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] -× 0020 ÷ 0308 ÷ 1160 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] -× 0020 ÷ 0308 × 0020 ÷ 1160 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] +× 0020 ÷ 0308 ÷ 1160 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] +× 0020 ÷ 0308 × 0020 ÷ 1160 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] × 0020 × 000A ÷ # × [0.3] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] × 0020 × 0020 × 000A ÷ # × [0.3] SPACE (SP) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] -× 0020 ÷ 0308 × 000A ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] -× 0020 ÷ 0308 × 0020 × 000A ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] +× 0020 ÷ 0308 × 000A ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] +× 0020 ÷ 0308 × 0020 × 000A ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] × 0020 × 0085 ÷ # × [0.3] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] × 0020 × 0020 × 0085 ÷ # × [0.3] SPACE (SP) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] -× 0020 ÷ 0308 × 0085 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] -× 0020 ÷ 0308 × 0020 × 0085 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] +× 0020 ÷ 0308 × 0085 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] +× 0020 ÷ 0308 × 0020 × 0085 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] × 0020 ÷ 17D6 ÷ # × [0.3] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] × 0020 × 0020 ÷ 17D6 ÷ # × [0.3] SPACE (SP) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] -× 0020 ÷ 0308 × 17D6 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] -× 0020 ÷ 0308 × 0020 ÷ 17D6 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] +× 0020 ÷ 0308 × 17D6 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM1_CM) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] +× 0020 ÷ 0308 × 0020 ÷ 17D6 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] × 0020 ÷ 0030 ÷ # × [0.3] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] × 0020 × 0020 ÷ 0030 ÷ # × [0.3] SPACE (SP) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] -× 0020 ÷ 0308 × 0030 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM) × [23.02] DIGIT ZERO (NU) ÷ [0.3] -× 0020 ÷ 0308 × 0020 ÷ 0030 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] +× 0020 ÷ 0308 × 0030 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM1_CM) × [23.02] DIGIT ZERO (NU) ÷ [0.3] +× 0020 ÷ 0308 × 0020 ÷ 0030 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] × 0020 ÷ 0028 ÷ # × [0.3] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] × 0020 × 0020 ÷ 0028 ÷ # × [0.3] SPACE (SP) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] -× 0020 ÷ 0308 × 0028 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM) × [30.01] LEFT PARENTHESIS (OP) ÷ [0.3] -× 0020 ÷ 0308 × 0020 ÷ 0028 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] +× 0020 ÷ 0308 × 0028 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM1_CM) × [30.01] LEFT PARENTHESIS (OP) ÷ [0.3] +× 0020 ÷ 0308 × 0020 ÷ 0028 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] × 0020 ÷ 0025 ÷ # × [0.3] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] × 0020 × 0020 ÷ 0025 ÷ # × [0.3] SPACE (SP) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] -× 0020 ÷ 0308 ÷ 0025 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM) ÷ [999.0] PERCENT SIGN (PO) ÷ [0.3] -× 0020 ÷ 0308 × 0020 ÷ 0025 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] +× 0020 ÷ 0308 × 0025 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM1_CM) × [24.03] PERCENT SIGN (PO) ÷ [0.3] +× 0020 ÷ 0308 × 0020 ÷ 0025 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] × 0020 ÷ 0024 ÷ # × [0.3] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] × 0020 × 0020 ÷ 0024 ÷ # × [0.3] SPACE (SP) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] -× 0020 ÷ 0308 ÷ 0024 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM) ÷ [999.0] DOLLAR SIGN (PR) ÷ [0.3] -× 0020 ÷ 0308 × 0020 ÷ 0024 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] +× 0020 ÷ 0308 × 0024 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM1_CM) × [24.03] DOLLAR SIGN (PR) ÷ [0.3] +× 0020 ÷ 0308 × 0020 ÷ 0024 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] × 0020 ÷ 0022 ÷ # × [0.3] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] × 0020 × 0020 ÷ 0022 ÷ # × [0.3] SPACE (SP) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] -× 0020 ÷ 0308 × 0022 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM) × [19.01] QUOTATION MARK (QU) ÷ [0.3] -× 0020 ÷ 0308 × 0020 ÷ 0022 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] +× 0020 ÷ 0308 × 0022 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM1_CM) × [19.01] QUOTATION MARK (QU) ÷ [0.3] +× 0020 ÷ 0308 × 0020 ÷ 0022 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] × 0020 × 0020 ÷ # × [0.3] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] × 0020 × 0020 × 0020 ÷ # × [0.3] SPACE (SP) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] -× 0020 ÷ 0308 × 0020 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [0.3] -× 0020 ÷ 0308 × 0020 × 0020 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] +× 0020 ÷ 0308 × 0020 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [0.3] +× 0020 ÷ 0308 × 0020 × 0020 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] × 0020 × 002F ÷ # × [0.3] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] × 0020 × 0020 × 002F ÷ # × [0.3] SPACE (SP) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] -× 0020 ÷ 0308 × 002F ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM) × [13.03] SOLIDUS (SY) ÷ [0.3] -× 0020 ÷ 0308 × 0020 × 002F ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] +× 0020 ÷ 0308 × 002F ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM1_CM) × [13.03] SOLIDUS (SY) ÷ [0.3] +× 0020 ÷ 0308 × 0020 × 002F ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] × 0020 × 2060 ÷ # × [0.3] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] × 0020 × 0020 × 2060 ÷ # × [0.3] SPACE (SP) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] -× 0020 ÷ 0308 × 2060 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM) × [11.01] WORD JOINER (WJ) ÷ [0.3] -× 0020 ÷ 0308 × 0020 × 2060 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] +× 0020 ÷ 0308 × 2060 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM1_CM) × [11.01] WORD JOINER (WJ) ÷ [0.3] +× 0020 ÷ 0308 × 0020 × 2060 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] × 0020 × 200B ÷ # × [0.3] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] × 0020 × 0020 × 200B ÷ # × [0.3] SPACE (SP) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] -× 0020 ÷ 0308 × 200B ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] -× 0020 ÷ 0308 × 0020 × 200B ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] +× 0020 ÷ 0308 × 200B ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM1_CM) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] +× 0020 ÷ 0308 × 0020 × 200B ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] × 0020 ÷ 1F1E6 ÷ # × [0.3] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] × 0020 × 0020 ÷ 1F1E6 ÷ # × [0.3] SPACE (SP) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -× 0020 ÷ 0308 ÷ 1F1E6 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -× 0020 ÷ 0308 × 0020 ÷ 1F1E6 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 0020 ÷ 0308 ÷ 1F1E6 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 0020 ÷ 0308 × 0020 ÷ 1F1E6 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 0020 ÷ 261D ÷ # × [0.3] SPACE (SP) ÷ [18.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 0020 × 0020 ÷ 261D ÷ # × [0.3] SPACE (SP) × [7.01] SPACE (SP) ÷ [18.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 0020 ÷ 0308 ÷ 261D ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 0020 ÷ 0308 × 0020 ÷ 261D ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 0020 ÷ 1F3FB ÷ # × [0.3] SPACE (SP) ÷ [18.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 0020 × 0020 ÷ 1F3FB ÷ # × [0.3] SPACE (SP) × [7.01] SPACE (SP) ÷ [18.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 0020 ÷ 0308 ÷ 1F3FB ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 0020 ÷ 0308 × 0020 ÷ 1F3FB ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 0020 ÷ 0001 ÷ # × [0.3] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 0020 × 0020 ÷ 0001 ÷ # × [0.3] SPACE (SP) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 0020 ÷ 0308 × 0001 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM1_CM) × [9.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 0020 ÷ 0308 × 0020 ÷ 0001 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 0020 ÷ 200D ÷ # × [0.3] SPACE (SP) ÷ [18.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 0020 × 0020 ÷ 200D ÷ # × [0.3] SPACE (SP) × [7.01] SPACE (SP) ÷ [18.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 0020 ÷ 0308 × 200D ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM1_CM) × [9.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 0020 ÷ 0308 × 0020 ÷ 200D ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] × 0020 ÷ 00A7 ÷ # × [0.3] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] × 0020 × 0020 ÷ 00A7 ÷ # × [0.3] SPACE (SP) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] -× 0020 ÷ 0308 × 00A7 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM) × [28.0] SECTION SIGN (AI_AL) ÷ [0.3] -× 0020 ÷ 0308 × 0020 ÷ 00A7 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] +× 0020 ÷ 0308 × 00A7 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM1_CM) × [28.0] SECTION SIGN (AI_AL) ÷ [0.3] +× 0020 ÷ 0308 × 0020 ÷ 00A7 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] × 0020 ÷ 50005 ÷ # × [0.3] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] × 0020 × 0020 ÷ 50005 ÷ # × [0.3] SPACE (SP) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] -× 0020 ÷ 0308 × 50005 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM) × [28.0] <reserved-50005> (XX_AL) ÷ [0.3] -× 0020 ÷ 0308 × 0020 ÷ 50005 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] +× 0020 ÷ 0308 × 50005 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM1_CM) × [28.0] <reserved-50005> (XX_AL) ÷ [0.3] +× 0020 ÷ 0308 × 0020 ÷ 50005 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] × 0020 ÷ 0E01 ÷ # × [0.3] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] × 0020 × 0020 ÷ 0E01 ÷ # × [0.3] SPACE (SP) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] -× 0020 ÷ 0308 × 0E01 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM) × [28.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] -× 0020 ÷ 0308 × 0020 ÷ 0E01 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] +× 0020 ÷ 0308 × 0E01 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM1_CM) × [28.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] +× 0020 ÷ 0308 × 0020 ÷ 0E01 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] × 0020 ÷ 3041 ÷ # × [0.3] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] × 0020 × 0020 ÷ 3041 ÷ # × [0.3] SPACE (SP) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] -× 0020 ÷ 0308 × 3041 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] -× 0020 ÷ 0308 × 0020 ÷ 3041 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] +× 0020 ÷ 0308 × 3041 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM1_CM) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] +× 0020 ÷ 0308 × 0020 ÷ 3041 ÷ # × [0.3] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] × 002F ÷ 0023 ÷ # × [0.3] SOLIDUS (SY) ÷ [999.0] NUMBER SIGN (AL) ÷ [0.3] × 002F × 0020 ÷ 0023 ÷ # × [0.3] SOLIDUS (SY) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] -× 002F × 0308 ÷ 0023 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] NUMBER SIGN (AL) ÷ [0.3] -× 002F × 0308 × 0020 ÷ 0023 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] +× 002F × 0308 ÷ 0023 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] NUMBER SIGN (AL) ÷ [0.3] +× 002F × 0308 × 0020 ÷ 0023 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] × 002F ÷ 2014 ÷ # × [0.3] SOLIDUS (SY) ÷ [999.0] EM DASH (B2) ÷ [0.3] × 002F × 0020 ÷ 2014 ÷ # × [0.3] SOLIDUS (SY) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] -× 002F × 0308 ÷ 2014 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] EM DASH (B2) ÷ [0.3] -× 002F × 0308 × 0020 ÷ 2014 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] +× 002F × 0308 ÷ 2014 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] EM DASH (B2) ÷ [0.3] +× 002F × 0308 × 0020 ÷ 2014 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] × 002F × 0009 ÷ # × [0.3] SOLIDUS (SY) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] × 002F × 0020 ÷ 0009 ÷ # × [0.3] SOLIDUS (SY) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] -× 002F × 0308 × 0009 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] -× 002F × 0308 × 0020 ÷ 0009 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] +× 002F × 0308 × 0009 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] +× 002F × 0308 × 0020 ÷ 0009 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] × 002F ÷ 00B4 ÷ # × [0.3] SOLIDUS (SY) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3] × 002F × 0020 ÷ 00B4 ÷ # × [0.3] SOLIDUS (SY) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] -× 002F × 0308 ÷ 00B4 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3] -× 002F × 0308 × 0020 ÷ 00B4 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] +× 002F × 0308 ÷ 00B4 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3] +× 002F × 0308 × 0020 ÷ 00B4 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] × 002F × 000B ÷ # × [0.3] SOLIDUS (SY) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] × 002F × 0020 × 000B ÷ # × [0.3] SOLIDUS (SY) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] -× 002F × 0308 × 000B ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] -× 002F × 0308 × 0020 × 000B ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] +× 002F × 0308 × 000B ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] +× 002F × 0308 × 0020 × 000B ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] × 002F ÷ FFFC ÷ # × [0.3] SOLIDUS (SY) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] × 002F × 0020 ÷ FFFC ÷ # × [0.3] SOLIDUS (SY) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] -× 002F × 0308 ÷ FFFC ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] -× 002F × 0308 × 0020 ÷ FFFC ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] +× 002F × 0308 ÷ FFFC ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] +× 002F × 0308 × 0020 ÷ FFFC ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] × 002F × 007D ÷ # × [0.3] SOLIDUS (SY) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] × 002F × 0020 × 007D ÷ # × [0.3] SOLIDUS (SY) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] -× 002F × 0308 × 007D ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM) × [13.03] RIGHT CURLY BRACKET (CL) ÷ [0.3] -× 002F × 0308 × 0020 × 007D ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] +× 002F × 0308 × 007D ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] RIGHT CURLY BRACKET (CL) ÷ [0.3] +× 002F × 0308 × 0020 × 007D ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] × 002F × 0029 ÷ # × [0.3] SOLIDUS (SY) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] × 002F × 0020 × 0029 ÷ # × [0.3] SOLIDUS (SY) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 002F × 0308 × 0029 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM) × [13.03] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 002F × 0308 × 0020 × 0029 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 002F × 0001 ÷ # × [0.3] SOLIDUS (SY) × [9.0] <START OF HEADING> (CM) ÷ [0.3] -× 002F × 0020 ÷ 0001 ÷ # × [0.3] SOLIDUS (SY) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM) ÷ [0.3] -× 002F × 0308 × 0001 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM) × [9.0] <START OF HEADING> (CM) ÷ [0.3] -× 002F × 0308 × 0020 ÷ 0001 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM) ÷ [0.3] +× 002F × 0308 × 0029 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] RIGHT PARENTHESIS (CP) ÷ [0.3] +× 002F × 0308 × 0020 × 0029 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] × 002F × 000D ÷ # × [0.3] SOLIDUS (SY) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] × 002F × 0020 × 000D ÷ # × [0.3] SOLIDUS (SY) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -× 002F × 0308 × 000D ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -× 002F × 0308 × 0020 × 000D ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +× 002F × 0308 × 000D ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +× 002F × 0308 × 0020 × 000D ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] × 002F × 0021 ÷ # × [0.3] SOLIDUS (SY) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] × 002F × 0020 × 0021 ÷ # × [0.3] SOLIDUS (SY) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] -× 002F × 0308 × 0021 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] -× 002F × 0308 × 0020 × 0021 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] +× 002F × 0308 × 0021 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] +× 002F × 0308 × 0020 × 0021 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] × 002F × 00A0 ÷ # × [0.3] SOLIDUS (SY) × [12.1] NO-BREAK SPACE (GL) ÷ [0.3] × 002F × 0020 ÷ 00A0 ÷ # × [0.3] SOLIDUS (SY) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] -× 002F × 0308 × 00A0 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM) × [12.2] NO-BREAK SPACE (GL) ÷ [0.3] -× 002F × 0308 × 0020 ÷ 00A0 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] +× 002F × 0308 × 00A0 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [12.2] NO-BREAK SPACE (GL) ÷ [0.3] +× 002F × 0308 × 0020 ÷ 00A0 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] × 002F ÷ AC00 ÷ # × [0.3] SOLIDUS (SY) ÷ [999.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] × 002F × 0020 ÷ AC00 ÷ # × [0.3] SOLIDUS (SY) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] -× 002F × 0308 ÷ AC00 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] -× 002F × 0308 × 0020 ÷ AC00 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] +× 002F × 0308 ÷ AC00 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] +× 002F × 0308 × 0020 ÷ AC00 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] × 002F ÷ AC01 ÷ # × [0.3] SOLIDUS (SY) ÷ [999.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] × 002F × 0020 ÷ AC01 ÷ # × [0.3] SOLIDUS (SY) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] -× 002F × 0308 ÷ AC01 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] -× 002F × 0308 × 0020 ÷ AC01 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] +× 002F × 0308 ÷ AC01 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] +× 002F × 0308 × 0020 ÷ AC01 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] × 002F × 05D0 ÷ # × [0.3] SOLIDUS (SY) × [21.2] HEBREW LETTER ALEF (HL) ÷ [0.3] × 002F × 0020 ÷ 05D0 ÷ # × [0.3] SOLIDUS (SY) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] -× 002F × 0308 × 05D0 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM) × [21.2] HEBREW LETTER ALEF (HL) ÷ [0.3] -× 002F × 0308 × 0020 ÷ 05D0 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] +× 002F × 0308 × 05D0 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.2] HEBREW LETTER ALEF (HL) ÷ [0.3] +× 002F × 0308 × 0020 ÷ 05D0 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] × 002F × 002D ÷ # × [0.3] SOLIDUS (SY) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] × 002F × 0020 ÷ 002D ÷ # × [0.3] SOLIDUS (SY) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] -× 002F × 0308 × 002D ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] -× 002F × 0308 × 0020 ÷ 002D ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] +× 002F × 0308 × 002D ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] +× 002F × 0308 × 0020 ÷ 002D ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] × 002F ÷ 231A ÷ # × [0.3] SOLIDUS (SY) ÷ [999.0] WATCH (ID) ÷ [0.3] × 002F × 0020 ÷ 231A ÷ # × [0.3] SOLIDUS (SY) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] -× 002F × 0308 ÷ 231A ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] WATCH (ID) ÷ [0.3] -× 002F × 0308 × 0020 ÷ 231A ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] +× 002F × 0308 ÷ 231A ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] WATCH (ID) ÷ [0.3] +× 002F × 0308 × 0020 ÷ 231A ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] × 002F ÷ 2024 ÷ # × [0.3] SOLIDUS (SY) ÷ [999.0] ONE DOT LEADER (IN) ÷ [0.3] × 002F × 0020 ÷ 2024 ÷ # × [0.3] SOLIDUS (SY) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] -× 002F × 0308 ÷ 2024 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] ONE DOT LEADER (IN) ÷ [0.3] -× 002F × 0308 × 0020 ÷ 2024 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] +× 002F × 0308 ÷ 2024 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] ONE DOT LEADER (IN) ÷ [0.3] +× 002F × 0308 × 0020 ÷ 2024 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] × 002F × 002C ÷ # × [0.3] SOLIDUS (SY) × [13.02] COMMA (IS) ÷ [0.3] × 002F × 0020 × 002C ÷ # × [0.3] SOLIDUS (SY) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] -× 002F × 0308 × 002C ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM) × [13.03] COMMA (IS) ÷ [0.3] -× 002F × 0308 × 0020 × 002C ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] +× 002F × 0308 × 002C ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] COMMA (IS) ÷ [0.3] +× 002F × 0308 × 0020 × 002C ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] × 002F ÷ 1100 ÷ # × [0.3] SOLIDUS (SY) ÷ [999.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] × 002F × 0020 ÷ 1100 ÷ # × [0.3] SOLIDUS (SY) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] -× 002F × 0308 ÷ 1100 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] -× 002F × 0308 × 0020 ÷ 1100 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] +× 002F × 0308 ÷ 1100 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] +× 002F × 0308 × 0020 ÷ 1100 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] × 002F ÷ 11A8 ÷ # × [0.3] SOLIDUS (SY) ÷ [999.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] × 002F × 0020 ÷ 11A8 ÷ # × [0.3] SOLIDUS (SY) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] -× 002F × 0308 ÷ 11A8 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] -× 002F × 0308 × 0020 ÷ 11A8 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] +× 002F × 0308 ÷ 11A8 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] +× 002F × 0308 × 0020 ÷ 11A8 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] × 002F ÷ 1160 ÷ # × [0.3] SOLIDUS (SY) ÷ [999.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] × 002F × 0020 ÷ 1160 ÷ # × [0.3] SOLIDUS (SY) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] -× 002F × 0308 ÷ 1160 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] -× 002F × 0308 × 0020 ÷ 1160 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] +× 002F × 0308 ÷ 1160 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] +× 002F × 0308 × 0020 ÷ 1160 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] × 002F × 000A ÷ # × [0.3] SOLIDUS (SY) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] × 002F × 0020 × 000A ÷ # × [0.3] SOLIDUS (SY) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] -× 002F × 0308 × 000A ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] -× 002F × 0308 × 0020 × 000A ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] +× 002F × 0308 × 000A ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] +× 002F × 0308 × 0020 × 000A ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] × 002F × 0085 ÷ # × [0.3] SOLIDUS (SY) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] × 002F × 0020 × 0085 ÷ # × [0.3] SOLIDUS (SY) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] -× 002F × 0308 × 0085 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] -× 002F × 0308 × 0020 × 0085 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] +× 002F × 0308 × 0085 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] +× 002F × 0308 × 0020 × 0085 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] × 002F × 17D6 ÷ # × [0.3] SOLIDUS (SY) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] × 002F × 0020 ÷ 17D6 ÷ # × [0.3] SOLIDUS (SY) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] -× 002F × 0308 × 17D6 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] -× 002F × 0308 × 0020 ÷ 17D6 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] +× 002F × 0308 × 17D6 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] +× 002F × 0308 × 0020 ÷ 17D6 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] × 002F ÷ 0030 ÷ # × [0.3] SOLIDUS (SY) ÷ [999.0] DIGIT ZERO (NU) ÷ [0.3] × 002F × 0020 ÷ 0030 ÷ # × [0.3] SOLIDUS (SY) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] -× 002F × 0308 ÷ 0030 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] DIGIT ZERO (NU) ÷ [0.3] -× 002F × 0308 × 0020 ÷ 0030 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] +× 002F × 0308 ÷ 0030 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] DIGIT ZERO (NU) ÷ [0.3] +× 002F × 0308 × 0020 ÷ 0030 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] × 002F ÷ 0028 ÷ # × [0.3] SOLIDUS (SY) ÷ [999.0] LEFT PARENTHESIS (OP) ÷ [0.3] × 002F × 0020 ÷ 0028 ÷ # × [0.3] SOLIDUS (SY) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] -× 002F × 0308 ÷ 0028 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] LEFT PARENTHESIS (OP) ÷ [0.3] -× 002F × 0308 × 0020 ÷ 0028 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] +× 002F × 0308 ÷ 0028 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] LEFT PARENTHESIS (OP) ÷ [0.3] +× 002F × 0308 × 0020 ÷ 0028 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] × 002F ÷ 0025 ÷ # × [0.3] SOLIDUS (SY) ÷ [999.0] PERCENT SIGN (PO) ÷ [0.3] × 002F × 0020 ÷ 0025 ÷ # × [0.3] SOLIDUS (SY) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] -× 002F × 0308 ÷ 0025 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] PERCENT SIGN (PO) ÷ [0.3] -× 002F × 0308 × 0020 ÷ 0025 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] +× 002F × 0308 ÷ 0025 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] PERCENT SIGN (PO) ÷ [0.3] +× 002F × 0308 × 0020 ÷ 0025 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] × 002F ÷ 0024 ÷ # × [0.3] SOLIDUS (SY) ÷ [999.0] DOLLAR SIGN (PR) ÷ [0.3] × 002F × 0020 ÷ 0024 ÷ # × [0.3] SOLIDUS (SY) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] -× 002F × 0308 ÷ 0024 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] DOLLAR SIGN (PR) ÷ [0.3] -× 002F × 0308 × 0020 ÷ 0024 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] +× 002F × 0308 ÷ 0024 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] DOLLAR SIGN (PR) ÷ [0.3] +× 002F × 0308 × 0020 ÷ 0024 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] × 002F × 0022 ÷ # × [0.3] SOLIDUS (SY) × [19.01] QUOTATION MARK (QU) ÷ [0.3] × 002F × 0020 ÷ 0022 ÷ # × [0.3] SOLIDUS (SY) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] -× 002F × 0308 × 0022 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM) × [19.01] QUOTATION MARK (QU) ÷ [0.3] -× 002F × 0308 × 0020 ÷ 0022 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] +× 002F × 0308 × 0022 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [19.01] QUOTATION MARK (QU) ÷ [0.3] +× 002F × 0308 × 0020 ÷ 0022 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] × 002F × 0020 ÷ # × [0.3] SOLIDUS (SY) × [7.01] SPACE (SP) ÷ [0.3] × 002F × 0020 × 0020 ÷ # × [0.3] SOLIDUS (SY) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] -× 002F × 0308 × 0020 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [0.3] -× 002F × 0308 × 0020 × 0020 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] +× 002F × 0308 × 0020 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [0.3] +× 002F × 0308 × 0020 × 0020 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] × 002F × 002F ÷ # × [0.3] SOLIDUS (SY) × [13.02] SOLIDUS (SY) ÷ [0.3] × 002F × 0020 × 002F ÷ # × [0.3] SOLIDUS (SY) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] -× 002F × 0308 × 002F ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM) × [13.03] SOLIDUS (SY) ÷ [0.3] -× 002F × 0308 × 0020 × 002F ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] +× 002F × 0308 × 002F ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] SOLIDUS (SY) ÷ [0.3] +× 002F × 0308 × 0020 × 002F ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] × 002F × 2060 ÷ # × [0.3] SOLIDUS (SY) × [11.01] WORD JOINER (WJ) ÷ [0.3] × 002F × 0020 × 2060 ÷ # × [0.3] SOLIDUS (SY) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] -× 002F × 0308 × 2060 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM) × [11.01] WORD JOINER (WJ) ÷ [0.3] -× 002F × 0308 × 0020 × 2060 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] +× 002F × 0308 × 2060 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [11.01] WORD JOINER (WJ) ÷ [0.3] +× 002F × 0308 × 0020 × 2060 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] × 002F × 200B ÷ # × [0.3] SOLIDUS (SY) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] × 002F × 0020 × 200B ÷ # × [0.3] SOLIDUS (SY) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] -× 002F × 0308 × 200B ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] -× 002F × 0308 × 0020 × 200B ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] +× 002F × 0308 × 200B ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] +× 002F × 0308 × 0020 × 200B ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] × 002F ÷ 1F1E6 ÷ # × [0.3] SOLIDUS (SY) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] × 002F × 0020 ÷ 1F1E6 ÷ # × [0.3] SOLIDUS (SY) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -× 002F × 0308 ÷ 1F1E6 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -× 002F × 0308 × 0020 ÷ 1F1E6 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 002F × 0308 ÷ 1F1E6 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 002F × 0308 × 0020 ÷ 1F1E6 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 002F ÷ 261D ÷ # × [0.3] SOLIDUS (SY) ÷ [999.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 002F × 0020 ÷ 261D ÷ # × [0.3] SOLIDUS (SY) × [7.01] SPACE (SP) ÷ [18.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 002F × 0308 ÷ 261D ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 002F × 0308 × 0020 ÷ 261D ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 002F ÷ 1F3FB ÷ # × [0.3] SOLIDUS (SY) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 002F × 0020 ÷ 1F3FB ÷ # × [0.3] SOLIDUS (SY) × [7.01] SPACE (SP) ÷ [18.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 002F × 0308 ÷ 1F3FB ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 002F × 0308 × 0020 ÷ 1F3FB ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 002F × 0001 ÷ # × [0.3] SOLIDUS (SY) × [9.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 002F × 0020 ÷ 0001 ÷ # × [0.3] SOLIDUS (SY) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 002F × 0308 × 0001 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [9.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 002F × 0308 × 0020 ÷ 0001 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 002F × 200D ÷ # × [0.3] SOLIDUS (SY) × [9.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 002F × 0020 ÷ 200D ÷ # × [0.3] SOLIDUS (SY) × [7.01] SPACE (SP) ÷ [18.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 002F × 0308 × 200D ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [9.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 002F × 0308 × 0020 ÷ 200D ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] × 002F ÷ 00A7 ÷ # × [0.3] SOLIDUS (SY) ÷ [999.0] SECTION SIGN (AI_AL) ÷ [0.3] × 002F × 0020 ÷ 00A7 ÷ # × [0.3] SOLIDUS (SY) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] -× 002F × 0308 ÷ 00A7 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] SECTION SIGN (AI_AL) ÷ [0.3] -× 002F × 0308 × 0020 ÷ 00A7 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] +× 002F × 0308 ÷ 00A7 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] SECTION SIGN (AI_AL) ÷ [0.3] +× 002F × 0308 × 0020 ÷ 00A7 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] × 002F ÷ 50005 ÷ # × [0.3] SOLIDUS (SY) ÷ [999.0] <reserved-50005> (XX_AL) ÷ [0.3] × 002F × 0020 ÷ 50005 ÷ # × [0.3] SOLIDUS (SY) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] -× 002F × 0308 ÷ 50005 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] <reserved-50005> (XX_AL) ÷ [0.3] -× 002F × 0308 × 0020 ÷ 50005 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] +× 002F × 0308 ÷ 50005 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] <reserved-50005> (XX_AL) ÷ [0.3] +× 002F × 0308 × 0020 ÷ 50005 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] × 002F ÷ 0E01 ÷ # × [0.3] SOLIDUS (SY) ÷ [999.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] × 002F × 0020 ÷ 0E01 ÷ # × [0.3] SOLIDUS (SY) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] -× 002F × 0308 ÷ 0E01 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] -× 002F × 0308 × 0020 ÷ 0E01 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] +× 002F × 0308 ÷ 0E01 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] +× 002F × 0308 × 0020 ÷ 0E01 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] × 002F × 3041 ÷ # × [0.3] SOLIDUS (SY) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] × 002F × 0020 ÷ 3041 ÷ # × [0.3] SOLIDUS (SY) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] -× 002F × 0308 × 3041 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] -× 002F × 0308 × 0020 ÷ 3041 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] +× 002F × 0308 × 3041 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] +× 002F × 0308 × 0020 ÷ 3041 ÷ # × [0.3] SOLIDUS (SY) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] × 2060 × 0023 ÷ # × [0.3] WORD JOINER (WJ) × [11.02] NUMBER SIGN (AL) ÷ [0.3] × 2060 × 0020 ÷ 0023 ÷ # × [0.3] WORD JOINER (WJ) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] -× 2060 × 0308 × 0023 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM) × [11.02] NUMBER SIGN (AL) ÷ [0.3] -× 2060 × 0308 × 0020 ÷ 0023 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] +× 2060 × 0308 × 0023 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM1_CM) × [11.02] NUMBER SIGN (AL) ÷ [0.3] +× 2060 × 0308 × 0020 ÷ 0023 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] × 2060 × 2014 ÷ # × [0.3] WORD JOINER (WJ) × [11.02] EM DASH (B2) ÷ [0.3] × 2060 × 0020 ÷ 2014 ÷ # × [0.3] WORD JOINER (WJ) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] -× 2060 × 0308 × 2014 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM) × [11.02] EM DASH (B2) ÷ [0.3] -× 2060 × 0308 × 0020 ÷ 2014 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] +× 2060 × 0308 × 2014 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM1_CM) × [11.02] EM DASH (B2) ÷ [0.3] +× 2060 × 0308 × 0020 ÷ 2014 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] × 2060 × 0009 ÷ # × [0.3] WORD JOINER (WJ) × [11.02] <CHARACTER TABULATION> (BA) ÷ [0.3] × 2060 × 0020 ÷ 0009 ÷ # × [0.3] WORD JOINER (WJ) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] -× 2060 × 0308 × 0009 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM) × [11.02] <CHARACTER TABULATION> (BA) ÷ [0.3] -× 2060 × 0308 × 0020 ÷ 0009 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] +× 2060 × 0308 × 0009 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM1_CM) × [11.02] <CHARACTER TABULATION> (BA) ÷ [0.3] +× 2060 × 0308 × 0020 ÷ 0009 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] × 2060 × 00B4 ÷ # × [0.3] WORD JOINER (WJ) × [11.02] ACUTE ACCENT (BB) ÷ [0.3] × 2060 × 0020 ÷ 00B4 ÷ # × [0.3] WORD JOINER (WJ) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] -× 2060 × 0308 × 00B4 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM) × [11.02] ACUTE ACCENT (BB) ÷ [0.3] -× 2060 × 0308 × 0020 ÷ 00B4 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] +× 2060 × 0308 × 00B4 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM1_CM) × [11.02] ACUTE ACCENT (BB) ÷ [0.3] +× 2060 × 0308 × 0020 ÷ 00B4 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] × 2060 × 000B ÷ # × [0.3] WORD JOINER (WJ) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] × 2060 × 0020 × 000B ÷ # × [0.3] WORD JOINER (WJ) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] -× 2060 × 0308 × 000B ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] -× 2060 × 0308 × 0020 × 000B ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] +× 2060 × 0308 × 000B ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] +× 2060 × 0308 × 0020 × 000B ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] × 2060 × FFFC ÷ # × [0.3] WORD JOINER (WJ) × [11.02] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] × 2060 × 0020 ÷ FFFC ÷ # × [0.3] WORD JOINER (WJ) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] -× 2060 × 0308 × FFFC ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM) × [11.02] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] -× 2060 × 0308 × 0020 ÷ FFFC ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] +× 2060 × 0308 × FFFC ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM1_CM) × [11.02] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] +× 2060 × 0308 × 0020 ÷ FFFC ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] × 2060 × 007D ÷ # × [0.3] WORD JOINER (WJ) × [11.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] × 2060 × 0020 × 007D ÷ # × [0.3] WORD JOINER (WJ) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] -× 2060 × 0308 × 007D ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM) × [11.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] -× 2060 × 0308 × 0020 × 007D ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] +× 2060 × 0308 × 007D ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM1_CM) × [11.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] +× 2060 × 0308 × 0020 × 007D ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] × 2060 × 0029 ÷ # × [0.3] WORD JOINER (WJ) × [11.02] RIGHT PARENTHESIS (CP) ÷ [0.3] × 2060 × 0020 × 0029 ÷ # × [0.3] WORD JOINER (WJ) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 2060 × 0308 × 0029 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM) × [11.02] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 2060 × 0308 × 0020 × 0029 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 2060 × 0001 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] <START OF HEADING> (CM) ÷ [0.3] -× 2060 × 0020 ÷ 0001 ÷ # × [0.3] WORD JOINER (WJ) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM) ÷ [0.3] -× 2060 × 0308 × 0001 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM) × [9.0] <START OF HEADING> (CM) ÷ [0.3] -× 2060 × 0308 × 0020 ÷ 0001 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM) ÷ [0.3] +× 2060 × 0308 × 0029 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM1_CM) × [11.02] RIGHT PARENTHESIS (CP) ÷ [0.3] +× 2060 × 0308 × 0020 × 0029 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] × 2060 × 000D ÷ # × [0.3] WORD JOINER (WJ) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] × 2060 × 0020 × 000D ÷ # × [0.3] WORD JOINER (WJ) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -× 2060 × 0308 × 000D ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -× 2060 × 0308 × 0020 × 000D ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +× 2060 × 0308 × 000D ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +× 2060 × 0308 × 0020 × 000D ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] × 2060 × 0021 ÷ # × [0.3] WORD JOINER (WJ) × [11.02] EXCLAMATION MARK (EX) ÷ [0.3] × 2060 × 0020 × 0021 ÷ # × [0.3] WORD JOINER (WJ) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] -× 2060 × 0308 × 0021 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM) × [11.02] EXCLAMATION MARK (EX) ÷ [0.3] -× 2060 × 0308 × 0020 × 0021 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] +× 2060 × 0308 × 0021 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM1_CM) × [11.02] EXCLAMATION MARK (EX) ÷ [0.3] +× 2060 × 0308 × 0020 × 0021 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] × 2060 × 00A0 ÷ # × [0.3] WORD JOINER (WJ) × [11.02] NO-BREAK SPACE (GL) ÷ [0.3] × 2060 × 0020 ÷ 00A0 ÷ # × [0.3] WORD JOINER (WJ) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] -× 2060 × 0308 × 00A0 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM) × [11.02] NO-BREAK SPACE (GL) ÷ [0.3] -× 2060 × 0308 × 0020 ÷ 00A0 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] +× 2060 × 0308 × 00A0 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM1_CM) × [11.02] NO-BREAK SPACE (GL) ÷ [0.3] +× 2060 × 0308 × 0020 ÷ 00A0 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] × 2060 × AC00 ÷ # × [0.3] WORD JOINER (WJ) × [11.02] HANGUL SYLLABLE GA (H2) ÷ [0.3] × 2060 × 0020 ÷ AC00 ÷ # × [0.3] WORD JOINER (WJ) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] -× 2060 × 0308 × AC00 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM) × [11.02] HANGUL SYLLABLE GA (H2) ÷ [0.3] -× 2060 × 0308 × 0020 ÷ AC00 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] +× 2060 × 0308 × AC00 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM1_CM) × [11.02] HANGUL SYLLABLE GA (H2) ÷ [0.3] +× 2060 × 0308 × 0020 ÷ AC00 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] × 2060 × AC01 ÷ # × [0.3] WORD JOINER (WJ) × [11.02] HANGUL SYLLABLE GAG (H3) ÷ [0.3] × 2060 × 0020 ÷ AC01 ÷ # × [0.3] WORD JOINER (WJ) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] -× 2060 × 0308 × AC01 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM) × [11.02] HANGUL SYLLABLE GAG (H3) ÷ [0.3] -× 2060 × 0308 × 0020 ÷ AC01 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] +× 2060 × 0308 × AC01 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM1_CM) × [11.02] HANGUL SYLLABLE GAG (H3) ÷ [0.3] +× 2060 × 0308 × 0020 ÷ AC01 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] × 2060 × 05D0 ÷ # × [0.3] WORD JOINER (WJ) × [11.02] HEBREW LETTER ALEF (HL) ÷ [0.3] × 2060 × 0020 ÷ 05D0 ÷ # × [0.3] WORD JOINER (WJ) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] -× 2060 × 0308 × 05D0 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM) × [11.02] HEBREW LETTER ALEF (HL) ÷ [0.3] -× 2060 × 0308 × 0020 ÷ 05D0 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] +× 2060 × 0308 × 05D0 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM1_CM) × [11.02] HEBREW LETTER ALEF (HL) ÷ [0.3] +× 2060 × 0308 × 0020 ÷ 05D0 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] × 2060 × 002D ÷ # × [0.3] WORD JOINER (WJ) × [11.02] HYPHEN-MINUS (HY) ÷ [0.3] × 2060 × 0020 ÷ 002D ÷ # × [0.3] WORD JOINER (WJ) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] -× 2060 × 0308 × 002D ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM) × [11.02] HYPHEN-MINUS (HY) ÷ [0.3] -× 2060 × 0308 × 0020 ÷ 002D ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] +× 2060 × 0308 × 002D ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM1_CM) × [11.02] HYPHEN-MINUS (HY) ÷ [0.3] +× 2060 × 0308 × 0020 ÷ 002D ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] × 2060 × 231A ÷ # × [0.3] WORD JOINER (WJ) × [11.02] WATCH (ID) ÷ [0.3] × 2060 × 0020 ÷ 231A ÷ # × [0.3] WORD JOINER (WJ) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] -× 2060 × 0308 × 231A ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM) × [11.02] WATCH (ID) ÷ [0.3] -× 2060 × 0308 × 0020 ÷ 231A ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] +× 2060 × 0308 × 231A ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM1_CM) × [11.02] WATCH (ID) ÷ [0.3] +× 2060 × 0308 × 0020 ÷ 231A ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] × 2060 × 2024 ÷ # × [0.3] WORD JOINER (WJ) × [11.02] ONE DOT LEADER (IN) ÷ [0.3] × 2060 × 0020 ÷ 2024 ÷ # × [0.3] WORD JOINER (WJ) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] -× 2060 × 0308 × 2024 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM) × [11.02] ONE DOT LEADER (IN) ÷ [0.3] -× 2060 × 0308 × 0020 ÷ 2024 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] +× 2060 × 0308 × 2024 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM1_CM) × [11.02] ONE DOT LEADER (IN) ÷ [0.3] +× 2060 × 0308 × 0020 ÷ 2024 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] × 2060 × 002C ÷ # × [0.3] WORD JOINER (WJ) × [11.02] COMMA (IS) ÷ [0.3] × 2060 × 0020 × 002C ÷ # × [0.3] WORD JOINER (WJ) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] -× 2060 × 0308 × 002C ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM) × [11.02] COMMA (IS) ÷ [0.3] -× 2060 × 0308 × 0020 × 002C ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] +× 2060 × 0308 × 002C ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM1_CM) × [11.02] COMMA (IS) ÷ [0.3] +× 2060 × 0308 × 0020 × 002C ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] × 2060 × 1100 ÷ # × [0.3] WORD JOINER (WJ) × [11.02] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] × 2060 × 0020 ÷ 1100 ÷ # × [0.3] WORD JOINER (WJ) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] -× 2060 × 0308 × 1100 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM) × [11.02] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] -× 2060 × 0308 × 0020 ÷ 1100 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] +× 2060 × 0308 × 1100 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM1_CM) × [11.02] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] +× 2060 × 0308 × 0020 ÷ 1100 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] × 2060 × 11A8 ÷ # × [0.3] WORD JOINER (WJ) × [11.02] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] × 2060 × 0020 ÷ 11A8 ÷ # × [0.3] WORD JOINER (WJ) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] -× 2060 × 0308 × 11A8 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM) × [11.02] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] -× 2060 × 0308 × 0020 ÷ 11A8 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] +× 2060 × 0308 × 11A8 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM1_CM) × [11.02] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] +× 2060 × 0308 × 0020 ÷ 11A8 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] × 2060 × 1160 ÷ # × [0.3] WORD JOINER (WJ) × [11.02] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] × 2060 × 0020 ÷ 1160 ÷ # × [0.3] WORD JOINER (WJ) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] -× 2060 × 0308 × 1160 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM) × [11.02] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] -× 2060 × 0308 × 0020 ÷ 1160 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] +× 2060 × 0308 × 1160 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM1_CM) × [11.02] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] +× 2060 × 0308 × 0020 ÷ 1160 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] × 2060 × 000A ÷ # × [0.3] WORD JOINER (WJ) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] × 2060 × 0020 × 000A ÷ # × [0.3] WORD JOINER (WJ) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] -× 2060 × 0308 × 000A ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] -× 2060 × 0308 × 0020 × 000A ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] +× 2060 × 0308 × 000A ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] +× 2060 × 0308 × 0020 × 000A ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] × 2060 × 0085 ÷ # × [0.3] WORD JOINER (WJ) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] × 2060 × 0020 × 0085 ÷ # × [0.3] WORD JOINER (WJ) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] -× 2060 × 0308 × 0085 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] -× 2060 × 0308 × 0020 × 0085 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] +× 2060 × 0308 × 0085 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] +× 2060 × 0308 × 0020 × 0085 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] × 2060 × 17D6 ÷ # × [0.3] WORD JOINER (WJ) × [11.02] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] × 2060 × 0020 ÷ 17D6 ÷ # × [0.3] WORD JOINER (WJ) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] -× 2060 × 0308 × 17D6 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM) × [11.02] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] -× 2060 × 0308 × 0020 ÷ 17D6 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] +× 2060 × 0308 × 17D6 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM1_CM) × [11.02] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] +× 2060 × 0308 × 0020 ÷ 17D6 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] × 2060 × 0030 ÷ # × [0.3] WORD JOINER (WJ) × [11.02] DIGIT ZERO (NU) ÷ [0.3] × 2060 × 0020 ÷ 0030 ÷ # × [0.3] WORD JOINER (WJ) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] -× 2060 × 0308 × 0030 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM) × [11.02] DIGIT ZERO (NU) ÷ [0.3] -× 2060 × 0308 × 0020 ÷ 0030 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] +× 2060 × 0308 × 0030 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM1_CM) × [11.02] DIGIT ZERO (NU) ÷ [0.3] +× 2060 × 0308 × 0020 ÷ 0030 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] × 2060 × 0028 ÷ # × [0.3] WORD JOINER (WJ) × [11.02] LEFT PARENTHESIS (OP) ÷ [0.3] × 2060 × 0020 ÷ 0028 ÷ # × [0.3] WORD JOINER (WJ) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] -× 2060 × 0308 × 0028 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM) × [11.02] LEFT PARENTHESIS (OP) ÷ [0.3] -× 2060 × 0308 × 0020 ÷ 0028 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] +× 2060 × 0308 × 0028 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM1_CM) × [11.02] LEFT PARENTHESIS (OP) ÷ [0.3] +× 2060 × 0308 × 0020 ÷ 0028 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] × 2060 × 0025 ÷ # × [0.3] WORD JOINER (WJ) × [11.02] PERCENT SIGN (PO) ÷ [0.3] × 2060 × 0020 ÷ 0025 ÷ # × [0.3] WORD JOINER (WJ) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] -× 2060 × 0308 × 0025 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM) × [11.02] PERCENT SIGN (PO) ÷ [0.3] -× 2060 × 0308 × 0020 ÷ 0025 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] +× 2060 × 0308 × 0025 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM1_CM) × [11.02] PERCENT SIGN (PO) ÷ [0.3] +× 2060 × 0308 × 0020 ÷ 0025 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] × 2060 × 0024 ÷ # × [0.3] WORD JOINER (WJ) × [11.02] DOLLAR SIGN (PR) ÷ [0.3] × 2060 × 0020 ÷ 0024 ÷ # × [0.3] WORD JOINER (WJ) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] -× 2060 × 0308 × 0024 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM) × [11.02] DOLLAR SIGN (PR) ÷ [0.3] -× 2060 × 0308 × 0020 ÷ 0024 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] +× 2060 × 0308 × 0024 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM1_CM) × [11.02] DOLLAR SIGN (PR) ÷ [0.3] +× 2060 × 0308 × 0020 ÷ 0024 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] × 2060 × 0022 ÷ # × [0.3] WORD JOINER (WJ) × [11.02] QUOTATION MARK (QU) ÷ [0.3] × 2060 × 0020 ÷ 0022 ÷ # × [0.3] WORD JOINER (WJ) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] -× 2060 × 0308 × 0022 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM) × [11.02] QUOTATION MARK (QU) ÷ [0.3] -× 2060 × 0308 × 0020 ÷ 0022 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] +× 2060 × 0308 × 0022 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM1_CM) × [11.02] QUOTATION MARK (QU) ÷ [0.3] +× 2060 × 0308 × 0020 ÷ 0022 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] × 2060 × 0020 ÷ # × [0.3] WORD JOINER (WJ) × [7.01] SPACE (SP) ÷ [0.3] × 2060 × 0020 × 0020 ÷ # × [0.3] WORD JOINER (WJ) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] -× 2060 × 0308 × 0020 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [0.3] -× 2060 × 0308 × 0020 × 0020 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] +× 2060 × 0308 × 0020 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [0.3] +× 2060 × 0308 × 0020 × 0020 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] × 2060 × 002F ÷ # × [0.3] WORD JOINER (WJ) × [11.02] SOLIDUS (SY) ÷ [0.3] × 2060 × 0020 × 002F ÷ # × [0.3] WORD JOINER (WJ) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] -× 2060 × 0308 × 002F ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM) × [11.02] SOLIDUS (SY) ÷ [0.3] -× 2060 × 0308 × 0020 × 002F ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] +× 2060 × 0308 × 002F ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM1_CM) × [11.02] SOLIDUS (SY) ÷ [0.3] +× 2060 × 0308 × 0020 × 002F ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] × 2060 × 2060 ÷ # × [0.3] WORD JOINER (WJ) × [11.01] WORD JOINER (WJ) ÷ [0.3] × 2060 × 0020 × 2060 ÷ # × [0.3] WORD JOINER (WJ) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] -× 2060 × 0308 × 2060 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM) × [11.01] WORD JOINER (WJ) ÷ [0.3] -× 2060 × 0308 × 0020 × 2060 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] +× 2060 × 0308 × 2060 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM1_CM) × [11.01] WORD JOINER (WJ) ÷ [0.3] +× 2060 × 0308 × 0020 × 2060 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] × 2060 × 200B ÷ # × [0.3] WORD JOINER (WJ) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] × 2060 × 0020 × 200B ÷ # × [0.3] WORD JOINER (WJ) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] -× 2060 × 0308 × 200B ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] -× 2060 × 0308 × 0020 × 200B ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] +× 2060 × 0308 × 200B ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] +× 2060 × 0308 × 0020 × 200B ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] × 2060 × 1F1E6 ÷ # × [0.3] WORD JOINER (WJ) × [11.02] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] × 2060 × 0020 ÷ 1F1E6 ÷ # × [0.3] WORD JOINER (WJ) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -× 2060 × 0308 × 1F1E6 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM) × [11.02] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -× 2060 × 0308 × 0020 ÷ 1F1E6 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 2060 × 0308 × 1F1E6 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM1_CM) × [11.02] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 2060 × 0308 × 0020 ÷ 1F1E6 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 2060 × 261D ÷ # × [0.3] WORD JOINER (WJ) × [11.02] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 2060 × 0020 ÷ 261D ÷ # × [0.3] WORD JOINER (WJ) × [7.01] SPACE (SP) ÷ [18.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 2060 × 0308 × 261D ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM1_CM) × [11.02] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 2060 × 0308 × 0020 ÷ 261D ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 2060 × 1F3FB ÷ # × [0.3] WORD JOINER (WJ) × [11.02] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 2060 × 0020 ÷ 1F3FB ÷ # × [0.3] WORD JOINER (WJ) × [7.01] SPACE (SP) ÷ [18.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 2060 × 0308 × 1F3FB ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM1_CM) × [11.02] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 2060 × 0308 × 0020 ÷ 1F3FB ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 2060 × 0001 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 2060 × 0020 ÷ 0001 ÷ # × [0.3] WORD JOINER (WJ) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 2060 × 0308 × 0001 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM1_CM) × [9.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 2060 × 0308 × 0020 ÷ 0001 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 2060 × 200D ÷ # × [0.3] WORD JOINER (WJ) × [9.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 2060 × 0020 ÷ 200D ÷ # × [0.3] WORD JOINER (WJ) × [7.01] SPACE (SP) ÷ [18.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 2060 × 0308 × 200D ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM1_CM) × [9.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 2060 × 0308 × 0020 ÷ 200D ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] × 2060 × 00A7 ÷ # × [0.3] WORD JOINER (WJ) × [11.02] SECTION SIGN (AI_AL) ÷ [0.3] × 2060 × 0020 ÷ 00A7 ÷ # × [0.3] WORD JOINER (WJ) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] -× 2060 × 0308 × 00A7 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM) × [11.02] SECTION SIGN (AI_AL) ÷ [0.3] -× 2060 × 0308 × 0020 ÷ 00A7 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] +× 2060 × 0308 × 00A7 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM1_CM) × [11.02] SECTION SIGN (AI_AL) ÷ [0.3] +× 2060 × 0308 × 0020 ÷ 00A7 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] × 2060 × 50005 ÷ # × [0.3] WORD JOINER (WJ) × [11.02] <reserved-50005> (XX_AL) ÷ [0.3] × 2060 × 0020 ÷ 50005 ÷ # × [0.3] WORD JOINER (WJ) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] -× 2060 × 0308 × 50005 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM) × [11.02] <reserved-50005> (XX_AL) ÷ [0.3] -× 2060 × 0308 × 0020 ÷ 50005 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] +× 2060 × 0308 × 50005 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM1_CM) × [11.02] <reserved-50005> (XX_AL) ÷ [0.3] +× 2060 × 0308 × 0020 ÷ 50005 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] × 2060 × 0E01 ÷ # × [0.3] WORD JOINER (WJ) × [11.02] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] × 2060 × 0020 ÷ 0E01 ÷ # × [0.3] WORD JOINER (WJ) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] -× 2060 × 0308 × 0E01 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM) × [11.02] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] -× 2060 × 0308 × 0020 ÷ 0E01 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] +× 2060 × 0308 × 0E01 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM1_CM) × [11.02] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] +× 2060 × 0308 × 0020 ÷ 0E01 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] × 2060 × 3041 ÷ # × [0.3] WORD JOINER (WJ) × [11.02] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] × 2060 × 0020 ÷ 3041 ÷ # × [0.3] WORD JOINER (WJ) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] -× 2060 × 0308 × 3041 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM) × [11.02] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] -× 2060 × 0308 × 0020 ÷ 3041 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] +× 2060 × 0308 × 3041 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM1_CM) × [11.02] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] +× 2060 × 0308 × 0020 ÷ 3041 ÷ # × [0.3] WORD JOINER (WJ) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] × 200B ÷ 0023 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] NUMBER SIGN (AL) ÷ [0.3] × 200B × 0020 ÷ 0023 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) × [7.01] SPACE (SP) ÷ [8.0] NUMBER SIGN (AL) ÷ [0.3] -× 200B ÷ 0308 × 0023 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM) × [28.0] NUMBER SIGN (AL) ÷ [0.3] -× 200B ÷ 0308 × 0020 ÷ 0023 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] +× 200B ÷ 0308 × 0023 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM1_CM) × [28.0] NUMBER SIGN (AL) ÷ [0.3] +× 200B ÷ 0308 × 0020 ÷ 0023 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] × 200B ÷ 2014 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] EM DASH (B2) ÷ [0.3] × 200B × 0020 ÷ 2014 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) × [7.01] SPACE (SP) ÷ [8.0] EM DASH (B2) ÷ [0.3] -× 200B ÷ 0308 ÷ 2014 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM) ÷ [999.0] EM DASH (B2) ÷ [0.3] -× 200B ÷ 0308 × 0020 ÷ 2014 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] +× 200B ÷ 0308 ÷ 2014 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] EM DASH (B2) ÷ [0.3] +× 200B ÷ 0308 × 0020 ÷ 2014 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] × 200B ÷ 0009 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] <CHARACTER TABULATION> (BA) ÷ [0.3] × 200B × 0020 ÷ 0009 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) × [7.01] SPACE (SP) ÷ [8.0] <CHARACTER TABULATION> (BA) ÷ [0.3] -× 200B ÷ 0308 × 0009 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] -× 200B ÷ 0308 × 0020 ÷ 0009 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] +× 200B ÷ 0308 × 0009 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM1_CM) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] +× 200B ÷ 0308 × 0020 ÷ 0009 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] × 200B ÷ 00B4 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] ACUTE ACCENT (BB) ÷ [0.3] × 200B × 0020 ÷ 00B4 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) × [7.01] SPACE (SP) ÷ [8.0] ACUTE ACCENT (BB) ÷ [0.3] -× 200B ÷ 0308 ÷ 00B4 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3] -× 200B ÷ 0308 × 0020 ÷ 00B4 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] +× 200B ÷ 0308 ÷ 00B4 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3] +× 200B ÷ 0308 × 0020 ÷ 00B4 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] × 200B × 000B ÷ # × [0.3] ZERO WIDTH SPACE (ZW) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] × 200B × 0020 × 000B ÷ # × [0.3] ZERO WIDTH SPACE (ZW) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] -× 200B ÷ 0308 × 000B ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] -× 200B ÷ 0308 × 0020 × 000B ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] +× 200B ÷ 0308 × 000B ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] +× 200B ÷ 0308 × 0020 × 000B ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] × 200B ÷ FFFC ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] × 200B × 0020 ÷ FFFC ÷ # × [0.3] ZERO WIDTH SPACE (ZW) × [7.01] SPACE (SP) ÷ [8.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] -× 200B ÷ 0308 ÷ FFFC ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] -× 200B ÷ 0308 × 0020 ÷ FFFC ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] +× 200B ÷ 0308 ÷ FFFC ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM1_CM) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] +× 200B ÷ 0308 × 0020 ÷ FFFC ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] × 200B ÷ 007D ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] RIGHT CURLY BRACKET (CL) ÷ [0.3] × 200B × 0020 ÷ 007D ÷ # × [0.3] ZERO WIDTH SPACE (ZW) × [7.01] SPACE (SP) ÷ [8.0] RIGHT CURLY BRACKET (CL) ÷ [0.3] -× 200B ÷ 0308 × 007D ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM) × [13.03] RIGHT CURLY BRACKET (CL) ÷ [0.3] -× 200B ÷ 0308 × 0020 × 007D ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] +× 200B ÷ 0308 × 007D ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM1_CM) × [13.03] RIGHT CURLY BRACKET (CL) ÷ [0.3] +× 200B ÷ 0308 × 0020 × 007D ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] × 200B ÷ 0029 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] RIGHT PARENTHESIS (CP) ÷ [0.3] × 200B × 0020 ÷ 0029 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) × [7.01] SPACE (SP) ÷ [8.0] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 200B ÷ 0308 × 0029 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM) × [13.03] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 200B ÷ 0308 × 0020 × 0029 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 200B ÷ 0001 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] <START OF HEADING> (CM) ÷ [0.3] -× 200B × 0020 ÷ 0001 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) × [7.01] SPACE (SP) ÷ [8.0] <START OF HEADING> (CM) ÷ [0.3] -× 200B ÷ 0308 × 0001 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM) × [9.0] <START OF HEADING> (CM) ÷ [0.3] -× 200B ÷ 0308 × 0020 ÷ 0001 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM) ÷ [0.3] +× 200B ÷ 0308 × 0029 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM1_CM) × [13.03] RIGHT PARENTHESIS (CP) ÷ [0.3] +× 200B ÷ 0308 × 0020 × 0029 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] × 200B × 000D ÷ # × [0.3] ZERO WIDTH SPACE (ZW) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] × 200B × 0020 × 000D ÷ # × [0.3] ZERO WIDTH SPACE (ZW) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -× 200B ÷ 0308 × 000D ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -× 200B ÷ 0308 × 0020 × 000D ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +× 200B ÷ 0308 × 000D ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +× 200B ÷ 0308 × 0020 × 000D ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] × 200B ÷ 0021 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] EXCLAMATION MARK (EX) ÷ [0.3] × 200B × 0020 ÷ 0021 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) × [7.01] SPACE (SP) ÷ [8.0] EXCLAMATION MARK (EX) ÷ [0.3] -× 200B ÷ 0308 × 0021 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] -× 200B ÷ 0308 × 0020 × 0021 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] +× 200B ÷ 0308 × 0021 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM1_CM) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] +× 200B ÷ 0308 × 0020 × 0021 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] × 200B ÷ 00A0 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] NO-BREAK SPACE (GL) ÷ [0.3] × 200B × 0020 ÷ 00A0 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) × [7.01] SPACE (SP) ÷ [8.0] NO-BREAK SPACE (GL) ÷ [0.3] -× 200B ÷ 0308 × 00A0 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM) × [12.2] NO-BREAK SPACE (GL) ÷ [0.3] -× 200B ÷ 0308 × 0020 ÷ 00A0 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] +× 200B ÷ 0308 × 00A0 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM1_CM) × [12.2] NO-BREAK SPACE (GL) ÷ [0.3] +× 200B ÷ 0308 × 0020 ÷ 00A0 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] × 200B ÷ AC00 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] × 200B × 0020 ÷ AC00 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) × [7.01] SPACE (SP) ÷ [8.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] -× 200B ÷ 0308 ÷ AC00 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] -× 200B ÷ 0308 × 0020 ÷ AC00 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] +× 200B ÷ 0308 ÷ AC00 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] +× 200B ÷ 0308 × 0020 ÷ AC00 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] × 200B ÷ AC01 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] × 200B × 0020 ÷ AC01 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) × [7.01] SPACE (SP) ÷ [8.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] -× 200B ÷ 0308 ÷ AC01 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] -× 200B ÷ 0308 × 0020 ÷ AC01 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] +× 200B ÷ 0308 ÷ AC01 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] +× 200B ÷ 0308 × 0020 ÷ AC01 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] × 200B ÷ 05D0 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] HEBREW LETTER ALEF (HL) ÷ [0.3] × 200B × 0020 ÷ 05D0 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) × [7.01] SPACE (SP) ÷ [8.0] HEBREW LETTER ALEF (HL) ÷ [0.3] -× 200B ÷ 0308 × 05D0 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM) × [28.0] HEBREW LETTER ALEF (HL) ÷ [0.3] -× 200B ÷ 0308 × 0020 ÷ 05D0 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] +× 200B ÷ 0308 × 05D0 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM1_CM) × [28.0] HEBREW LETTER ALEF (HL) ÷ [0.3] +× 200B ÷ 0308 × 0020 ÷ 05D0 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] × 200B ÷ 002D ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] HYPHEN-MINUS (HY) ÷ [0.3] × 200B × 0020 ÷ 002D ÷ # × [0.3] ZERO WIDTH SPACE (ZW) × [7.01] SPACE (SP) ÷ [8.0] HYPHEN-MINUS (HY) ÷ [0.3] -× 200B ÷ 0308 × 002D ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] -× 200B ÷ 0308 × 0020 ÷ 002D ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] +× 200B ÷ 0308 × 002D ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM1_CM) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] +× 200B ÷ 0308 × 0020 ÷ 002D ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] × 200B ÷ 231A ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] WATCH (ID) ÷ [0.3] × 200B × 0020 ÷ 231A ÷ # × [0.3] ZERO WIDTH SPACE (ZW) × [7.01] SPACE (SP) ÷ [8.0] WATCH (ID) ÷ [0.3] -× 200B ÷ 0308 ÷ 231A ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM) ÷ [999.0] WATCH (ID) ÷ [0.3] -× 200B ÷ 0308 × 0020 ÷ 231A ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] +× 200B ÷ 0308 ÷ 231A ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] WATCH (ID) ÷ [0.3] +× 200B ÷ 0308 × 0020 ÷ 231A ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] × 200B ÷ 2024 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] ONE DOT LEADER (IN) ÷ [0.3] × 200B × 0020 ÷ 2024 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) × [7.01] SPACE (SP) ÷ [8.0] ONE DOT LEADER (IN) ÷ [0.3] -× 200B ÷ 0308 × 2024 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM) × [22.01] ONE DOT LEADER (IN) ÷ [0.3] -× 200B ÷ 0308 × 0020 ÷ 2024 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] +× 200B ÷ 0308 × 2024 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM1_CM) × [22.01] ONE DOT LEADER (IN) ÷ [0.3] +× 200B ÷ 0308 × 0020 ÷ 2024 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] × 200B ÷ 002C ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMMA (IS) ÷ [0.3] × 200B × 0020 ÷ 002C ÷ # × [0.3] ZERO WIDTH SPACE (ZW) × [7.01] SPACE (SP) ÷ [8.0] COMMA (IS) ÷ [0.3] -× 200B ÷ 0308 × 002C ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM) × [13.03] COMMA (IS) ÷ [0.3] -× 200B ÷ 0308 × 0020 × 002C ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] +× 200B ÷ 0308 × 002C ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM1_CM) × [13.03] COMMA (IS) ÷ [0.3] +× 200B ÷ 0308 × 0020 × 002C ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] × 200B ÷ 1100 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] × 200B × 0020 ÷ 1100 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) × [7.01] SPACE (SP) ÷ [8.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] -× 200B ÷ 0308 ÷ 1100 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] -× 200B ÷ 0308 × 0020 ÷ 1100 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] +× 200B ÷ 0308 ÷ 1100 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] +× 200B ÷ 0308 × 0020 ÷ 1100 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] × 200B ÷ 11A8 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] × 200B × 0020 ÷ 11A8 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) × [7.01] SPACE (SP) ÷ [8.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] -× 200B ÷ 0308 ÷ 11A8 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] -× 200B ÷ 0308 × 0020 ÷ 11A8 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] +× 200B ÷ 0308 ÷ 11A8 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] +× 200B ÷ 0308 × 0020 ÷ 11A8 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] × 200B ÷ 1160 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] × 200B × 0020 ÷ 1160 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) × [7.01] SPACE (SP) ÷ [8.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] -× 200B ÷ 0308 ÷ 1160 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] -× 200B ÷ 0308 × 0020 ÷ 1160 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] +× 200B ÷ 0308 ÷ 1160 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] +× 200B ÷ 0308 × 0020 ÷ 1160 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] × 200B × 000A ÷ # × [0.3] ZERO WIDTH SPACE (ZW) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] × 200B × 0020 × 000A ÷ # × [0.3] ZERO WIDTH SPACE (ZW) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] -× 200B ÷ 0308 × 000A ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] -× 200B ÷ 0308 × 0020 × 000A ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] +× 200B ÷ 0308 × 000A ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] +× 200B ÷ 0308 × 0020 × 000A ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] × 200B × 0085 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] × 200B × 0020 × 0085 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] -× 200B ÷ 0308 × 0085 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] -× 200B ÷ 0308 × 0020 × 0085 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] +× 200B ÷ 0308 × 0085 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] +× 200B ÷ 0308 × 0020 × 0085 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] × 200B ÷ 17D6 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] × 200B × 0020 ÷ 17D6 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) × [7.01] SPACE (SP) ÷ [8.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] -× 200B ÷ 0308 × 17D6 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] -× 200B ÷ 0308 × 0020 ÷ 17D6 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] +× 200B ÷ 0308 × 17D6 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM1_CM) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] +× 200B ÷ 0308 × 0020 ÷ 17D6 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] × 200B ÷ 0030 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] DIGIT ZERO (NU) ÷ [0.3] × 200B × 0020 ÷ 0030 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) × [7.01] SPACE (SP) ÷ [8.0] DIGIT ZERO (NU) ÷ [0.3] -× 200B ÷ 0308 × 0030 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM) × [23.02] DIGIT ZERO (NU) ÷ [0.3] -× 200B ÷ 0308 × 0020 ÷ 0030 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] +× 200B ÷ 0308 × 0030 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM1_CM) × [23.02] DIGIT ZERO (NU) ÷ [0.3] +× 200B ÷ 0308 × 0020 ÷ 0030 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] × 200B ÷ 0028 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] LEFT PARENTHESIS (OP) ÷ [0.3] × 200B × 0020 ÷ 0028 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) × [7.01] SPACE (SP) ÷ [8.0] LEFT PARENTHESIS (OP) ÷ [0.3] -× 200B ÷ 0308 × 0028 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM) × [30.01] LEFT PARENTHESIS (OP) ÷ [0.3] -× 200B ÷ 0308 × 0020 ÷ 0028 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] +× 200B ÷ 0308 × 0028 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM1_CM) × [30.01] LEFT PARENTHESIS (OP) ÷ [0.3] +× 200B ÷ 0308 × 0020 ÷ 0028 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] × 200B ÷ 0025 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] PERCENT SIGN (PO) ÷ [0.3] × 200B × 0020 ÷ 0025 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) × [7.01] SPACE (SP) ÷ [8.0] PERCENT SIGN (PO) ÷ [0.3] -× 200B ÷ 0308 ÷ 0025 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM) ÷ [999.0] PERCENT SIGN (PO) ÷ [0.3] -× 200B ÷ 0308 × 0020 ÷ 0025 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] +× 200B ÷ 0308 × 0025 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM1_CM) × [24.03] PERCENT SIGN (PO) ÷ [0.3] +× 200B ÷ 0308 × 0020 ÷ 0025 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] × 200B ÷ 0024 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] DOLLAR SIGN (PR) ÷ [0.3] × 200B × 0020 ÷ 0024 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) × [7.01] SPACE (SP) ÷ [8.0] DOLLAR SIGN (PR) ÷ [0.3] -× 200B ÷ 0308 ÷ 0024 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM) ÷ [999.0] DOLLAR SIGN (PR) ÷ [0.3] -× 200B ÷ 0308 × 0020 ÷ 0024 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] +× 200B ÷ 0308 × 0024 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM1_CM) × [24.03] DOLLAR SIGN (PR) ÷ [0.3] +× 200B ÷ 0308 × 0020 ÷ 0024 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] × 200B ÷ 0022 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] QUOTATION MARK (QU) ÷ [0.3] × 200B × 0020 ÷ 0022 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) × [7.01] SPACE (SP) ÷ [8.0] QUOTATION MARK (QU) ÷ [0.3] -× 200B ÷ 0308 × 0022 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM) × [19.01] QUOTATION MARK (QU) ÷ [0.3] -× 200B ÷ 0308 × 0020 ÷ 0022 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] +× 200B ÷ 0308 × 0022 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM1_CM) × [19.01] QUOTATION MARK (QU) ÷ [0.3] +× 200B ÷ 0308 × 0020 ÷ 0022 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] × 200B × 0020 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) × [7.01] SPACE (SP) ÷ [0.3] × 200B × 0020 × 0020 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] -× 200B ÷ 0308 × 0020 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [0.3] -× 200B ÷ 0308 × 0020 × 0020 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] +× 200B ÷ 0308 × 0020 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [0.3] +× 200B ÷ 0308 × 0020 × 0020 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] × 200B ÷ 002F ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] SOLIDUS (SY) ÷ [0.3] × 200B × 0020 ÷ 002F ÷ # × [0.3] ZERO WIDTH SPACE (ZW) × [7.01] SPACE (SP) ÷ [8.0] SOLIDUS (SY) ÷ [0.3] -× 200B ÷ 0308 × 002F ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM) × [13.03] SOLIDUS (SY) ÷ [0.3] -× 200B ÷ 0308 × 0020 × 002F ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] +× 200B ÷ 0308 × 002F ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM1_CM) × [13.03] SOLIDUS (SY) ÷ [0.3] +× 200B ÷ 0308 × 0020 × 002F ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] × 200B ÷ 2060 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] WORD JOINER (WJ) ÷ [0.3] × 200B × 0020 ÷ 2060 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) × [7.01] SPACE (SP) ÷ [8.0] WORD JOINER (WJ) ÷ [0.3] -× 200B ÷ 0308 × 2060 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM) × [11.01] WORD JOINER (WJ) ÷ [0.3] -× 200B ÷ 0308 × 0020 × 2060 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] +× 200B ÷ 0308 × 2060 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM1_CM) × [11.01] WORD JOINER (WJ) ÷ [0.3] +× 200B ÷ 0308 × 0020 × 2060 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] × 200B × 200B ÷ # × [0.3] ZERO WIDTH SPACE (ZW) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] × 200B × 0020 × 200B ÷ # × [0.3] ZERO WIDTH SPACE (ZW) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] -× 200B ÷ 0308 × 200B ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] -× 200B ÷ 0308 × 0020 × 200B ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] +× 200B ÷ 0308 × 200B ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM1_CM) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] +× 200B ÷ 0308 × 0020 × 200B ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] × 200B ÷ 1F1E6 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] × 200B × 0020 ÷ 1F1E6 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) × [7.01] SPACE (SP) ÷ [8.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -× 200B ÷ 0308 ÷ 1F1E6 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -× 200B ÷ 0308 × 0020 ÷ 1F1E6 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 200B ÷ 0308 ÷ 1F1E6 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 200B ÷ 0308 × 0020 ÷ 1F1E6 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 200B ÷ 261D ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 200B × 0020 ÷ 261D ÷ # × [0.3] ZERO WIDTH SPACE (ZW) × [7.01] SPACE (SP) ÷ [8.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 200B ÷ 0308 ÷ 261D ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 200B ÷ 0308 × 0020 ÷ 261D ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 200B ÷ 1F3FB ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 200B × 0020 ÷ 1F3FB ÷ # × [0.3] ZERO WIDTH SPACE (ZW) × [7.01] SPACE (SP) ÷ [8.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 200B ÷ 0308 ÷ 1F3FB ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 200B ÷ 0308 × 0020 ÷ 1F3FB ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 200B ÷ 0001 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 200B × 0020 ÷ 0001 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) × [7.01] SPACE (SP) ÷ [8.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 200B ÷ 0308 × 0001 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM1_CM) × [9.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 200B ÷ 0308 × 0020 ÷ 0001 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 200B ÷ 200D ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 200B × 0020 ÷ 200D ÷ # × [0.3] ZERO WIDTH SPACE (ZW) × [7.01] SPACE (SP) ÷ [8.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 200B ÷ 0308 × 200D ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM1_CM) × [9.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 200B ÷ 0308 × 0020 ÷ 200D ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] × 200B ÷ 00A7 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] SECTION SIGN (AI_AL) ÷ [0.3] × 200B × 0020 ÷ 00A7 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) × [7.01] SPACE (SP) ÷ [8.0] SECTION SIGN (AI_AL) ÷ [0.3] -× 200B ÷ 0308 × 00A7 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM) × [28.0] SECTION SIGN (AI_AL) ÷ [0.3] -× 200B ÷ 0308 × 0020 ÷ 00A7 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] +× 200B ÷ 0308 × 00A7 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM1_CM) × [28.0] SECTION SIGN (AI_AL) ÷ [0.3] +× 200B ÷ 0308 × 0020 ÷ 00A7 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] × 200B ÷ 50005 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] <reserved-50005> (XX_AL) ÷ [0.3] × 200B × 0020 ÷ 50005 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) × [7.01] SPACE (SP) ÷ [8.0] <reserved-50005> (XX_AL) ÷ [0.3] -× 200B ÷ 0308 × 50005 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM) × [28.0] <reserved-50005> (XX_AL) ÷ [0.3] -× 200B ÷ 0308 × 0020 ÷ 50005 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] +× 200B ÷ 0308 × 50005 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM1_CM) × [28.0] <reserved-50005> (XX_AL) ÷ [0.3] +× 200B ÷ 0308 × 0020 ÷ 50005 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] × 200B ÷ 0E01 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] × 200B × 0020 ÷ 0E01 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) × [7.01] SPACE (SP) ÷ [8.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] -× 200B ÷ 0308 × 0E01 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM) × [28.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] -× 200B ÷ 0308 × 0020 ÷ 0E01 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] +× 200B ÷ 0308 × 0E01 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM1_CM) × [28.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] +× 200B ÷ 0308 × 0020 ÷ 0E01 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] × 200B ÷ 3041 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] × 200B × 0020 ÷ 3041 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) × [7.01] SPACE (SP) ÷ [8.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] -× 200B ÷ 0308 × 3041 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] -× 200B ÷ 0308 × 0020 ÷ 3041 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] +× 200B ÷ 0308 × 3041 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM1_CM) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] +× 200B ÷ 0308 × 0020 ÷ 3041 ÷ # × [0.3] ZERO WIDTH SPACE (ZW) ÷ [8.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] × 1F1E6 ÷ 0023 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] NUMBER SIGN (AL) ÷ [0.3] × 1F1E6 × 0020 ÷ 0023 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] -× 1F1E6 × 0308 ÷ 0023 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] NUMBER SIGN (AL) ÷ [0.3] -× 1F1E6 × 0308 × 0020 ÷ 0023 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] +× 1F1E6 × 0308 ÷ 0023 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] NUMBER SIGN (AL) ÷ [0.3] +× 1F1E6 × 0308 × 0020 ÷ 0023 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] × 1F1E6 ÷ 2014 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] EM DASH (B2) ÷ [0.3] × 1F1E6 × 0020 ÷ 2014 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] -× 1F1E6 × 0308 ÷ 2014 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] EM DASH (B2) ÷ [0.3] -× 1F1E6 × 0308 × 0020 ÷ 2014 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] +× 1F1E6 × 0308 ÷ 2014 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] EM DASH (B2) ÷ [0.3] +× 1F1E6 × 0308 × 0020 ÷ 2014 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] × 1F1E6 × 0009 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] × 1F1E6 × 0020 ÷ 0009 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] -× 1F1E6 × 0308 × 0009 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] -× 1F1E6 × 0308 × 0020 ÷ 0009 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] +× 1F1E6 × 0308 × 0009 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] +× 1F1E6 × 0308 × 0020 ÷ 0009 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] × 1F1E6 ÷ 00B4 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3] × 1F1E6 × 0020 ÷ 00B4 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] -× 1F1E6 × 0308 ÷ 00B4 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3] -× 1F1E6 × 0308 × 0020 ÷ 00B4 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] +× 1F1E6 × 0308 ÷ 00B4 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3] +× 1F1E6 × 0308 × 0020 ÷ 00B4 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] × 1F1E6 × 000B ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] × 1F1E6 × 0020 × 000B ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] -× 1F1E6 × 0308 × 000B ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] -× 1F1E6 × 0308 × 0020 × 000B ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] +× 1F1E6 × 0308 × 000B ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] +× 1F1E6 × 0308 × 0020 × 000B ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] × 1F1E6 ÷ FFFC ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] × 1F1E6 × 0020 ÷ FFFC ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] -× 1F1E6 × 0308 ÷ FFFC ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] -× 1F1E6 × 0308 × 0020 ÷ FFFC ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] +× 1F1E6 × 0308 ÷ FFFC ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] +× 1F1E6 × 0308 × 0020 ÷ FFFC ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] × 1F1E6 × 007D ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] × 1F1E6 × 0020 × 007D ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] -× 1F1E6 × 0308 × 007D ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM) × [13.03] RIGHT CURLY BRACKET (CL) ÷ [0.3] -× 1F1E6 × 0308 × 0020 × 007D ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] +× 1F1E6 × 0308 × 007D ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] RIGHT CURLY BRACKET (CL) ÷ [0.3] +× 1F1E6 × 0308 × 0020 × 007D ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] × 1F1E6 × 0029 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] × 1F1E6 × 0020 × 0029 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 1F1E6 × 0308 × 0029 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM) × [13.03] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 1F1E6 × 0308 × 0020 × 0029 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 1F1E6 × 0001 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] <START OF HEADING> (CM) ÷ [0.3] -× 1F1E6 × 0020 ÷ 0001 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM) ÷ [0.3] -× 1F1E6 × 0308 × 0001 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM) × [9.0] <START OF HEADING> (CM) ÷ [0.3] -× 1F1E6 × 0308 × 0020 ÷ 0001 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM) ÷ [0.3] +× 1F1E6 × 0308 × 0029 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] RIGHT PARENTHESIS (CP) ÷ [0.3] +× 1F1E6 × 0308 × 0020 × 0029 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] × 1F1E6 × 000D ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] × 1F1E6 × 0020 × 000D ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -× 1F1E6 × 0308 × 000D ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -× 1F1E6 × 0308 × 0020 × 000D ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +× 1F1E6 × 0308 × 000D ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +× 1F1E6 × 0308 × 0020 × 000D ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] × 1F1E6 × 0021 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] × 1F1E6 × 0020 × 0021 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] -× 1F1E6 × 0308 × 0021 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] -× 1F1E6 × 0308 × 0020 × 0021 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] +× 1F1E6 × 0308 × 0021 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] +× 1F1E6 × 0308 × 0020 × 0021 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] × 1F1E6 × 00A0 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [12.1] NO-BREAK SPACE (GL) ÷ [0.3] × 1F1E6 × 0020 ÷ 00A0 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] -× 1F1E6 × 0308 × 00A0 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM) × [12.2] NO-BREAK SPACE (GL) ÷ [0.3] -× 1F1E6 × 0308 × 0020 ÷ 00A0 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] +× 1F1E6 × 0308 × 00A0 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM1_CM) × [12.2] NO-BREAK SPACE (GL) ÷ [0.3] +× 1F1E6 × 0308 × 0020 ÷ 00A0 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] × 1F1E6 ÷ AC00 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] × 1F1E6 × 0020 ÷ AC00 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] -× 1F1E6 × 0308 ÷ AC00 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] -× 1F1E6 × 0308 × 0020 ÷ AC00 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] +× 1F1E6 × 0308 ÷ AC00 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] +× 1F1E6 × 0308 × 0020 ÷ AC00 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] × 1F1E6 ÷ AC01 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] × 1F1E6 × 0020 ÷ AC01 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] -× 1F1E6 × 0308 ÷ AC01 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] -× 1F1E6 × 0308 × 0020 ÷ AC01 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] +× 1F1E6 × 0308 ÷ AC01 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] +× 1F1E6 × 0308 × 0020 ÷ AC01 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] × 1F1E6 ÷ 05D0 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] HEBREW LETTER ALEF (HL) ÷ [0.3] × 1F1E6 × 0020 ÷ 05D0 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] -× 1F1E6 × 0308 ÷ 05D0 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HEBREW LETTER ALEF (HL) ÷ [0.3] -× 1F1E6 × 0308 × 0020 ÷ 05D0 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] +× 1F1E6 × 0308 ÷ 05D0 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HEBREW LETTER ALEF (HL) ÷ [0.3] +× 1F1E6 × 0308 × 0020 ÷ 05D0 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] × 1F1E6 × 002D ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] × 1F1E6 × 0020 ÷ 002D ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] -× 1F1E6 × 0308 × 002D ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] -× 1F1E6 × 0308 × 0020 ÷ 002D ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] +× 1F1E6 × 0308 × 002D ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] +× 1F1E6 × 0308 × 0020 ÷ 002D ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] × 1F1E6 ÷ 231A ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] WATCH (ID) ÷ [0.3] × 1F1E6 × 0020 ÷ 231A ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] -× 1F1E6 × 0308 ÷ 231A ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] WATCH (ID) ÷ [0.3] -× 1F1E6 × 0308 × 0020 ÷ 231A ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] +× 1F1E6 × 0308 ÷ 231A ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] WATCH (ID) ÷ [0.3] +× 1F1E6 × 0308 × 0020 ÷ 231A ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] × 1F1E6 ÷ 2024 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] ONE DOT LEADER (IN) ÷ [0.3] × 1F1E6 × 0020 ÷ 2024 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] -× 1F1E6 × 0308 ÷ 2024 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] ONE DOT LEADER (IN) ÷ [0.3] -× 1F1E6 × 0308 × 0020 ÷ 2024 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] +× 1F1E6 × 0308 ÷ 2024 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] ONE DOT LEADER (IN) ÷ [0.3] +× 1F1E6 × 0308 × 0020 ÷ 2024 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] × 1F1E6 × 002C ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [13.02] COMMA (IS) ÷ [0.3] × 1F1E6 × 0020 × 002C ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] -× 1F1E6 × 0308 × 002C ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM) × [13.03] COMMA (IS) ÷ [0.3] -× 1F1E6 × 0308 × 0020 × 002C ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] +× 1F1E6 × 0308 × 002C ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] COMMA (IS) ÷ [0.3] +× 1F1E6 × 0308 × 0020 × 002C ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] × 1F1E6 ÷ 1100 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] × 1F1E6 × 0020 ÷ 1100 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] -× 1F1E6 × 0308 ÷ 1100 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] -× 1F1E6 × 0308 × 0020 ÷ 1100 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] +× 1F1E6 × 0308 ÷ 1100 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] +× 1F1E6 × 0308 × 0020 ÷ 1100 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] × 1F1E6 ÷ 11A8 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] × 1F1E6 × 0020 ÷ 11A8 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] -× 1F1E6 × 0308 ÷ 11A8 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] -× 1F1E6 × 0308 × 0020 ÷ 11A8 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] +× 1F1E6 × 0308 ÷ 11A8 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] +× 1F1E6 × 0308 × 0020 ÷ 11A8 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] × 1F1E6 ÷ 1160 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] × 1F1E6 × 0020 ÷ 1160 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] -× 1F1E6 × 0308 ÷ 1160 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] -× 1F1E6 × 0308 × 0020 ÷ 1160 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] +× 1F1E6 × 0308 ÷ 1160 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] +× 1F1E6 × 0308 × 0020 ÷ 1160 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] × 1F1E6 × 000A ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] × 1F1E6 × 0020 × 000A ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] -× 1F1E6 × 0308 × 000A ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] -× 1F1E6 × 0308 × 0020 × 000A ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] +× 1F1E6 × 0308 × 000A ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] +× 1F1E6 × 0308 × 0020 × 000A ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] × 1F1E6 × 0085 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] × 1F1E6 × 0020 × 0085 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] -× 1F1E6 × 0308 × 0085 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] -× 1F1E6 × 0308 × 0020 × 0085 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] +× 1F1E6 × 0308 × 0085 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] +× 1F1E6 × 0308 × 0020 × 0085 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] × 1F1E6 × 17D6 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] × 1F1E6 × 0020 ÷ 17D6 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] -× 1F1E6 × 0308 × 17D6 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] -× 1F1E6 × 0308 × 0020 ÷ 17D6 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] +× 1F1E6 × 0308 × 17D6 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] +× 1F1E6 × 0308 × 0020 ÷ 17D6 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] × 1F1E6 ÷ 0030 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] DIGIT ZERO (NU) ÷ [0.3] × 1F1E6 × 0020 ÷ 0030 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] -× 1F1E6 × 0308 ÷ 0030 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] DIGIT ZERO (NU) ÷ [0.3] -× 1F1E6 × 0308 × 0020 ÷ 0030 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] +× 1F1E6 × 0308 ÷ 0030 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] DIGIT ZERO (NU) ÷ [0.3] +× 1F1E6 × 0308 × 0020 ÷ 0030 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] × 1F1E6 ÷ 0028 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] LEFT PARENTHESIS (OP) ÷ [0.3] × 1F1E6 × 0020 ÷ 0028 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] -× 1F1E6 × 0308 ÷ 0028 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] LEFT PARENTHESIS (OP) ÷ [0.3] -× 1F1E6 × 0308 × 0020 ÷ 0028 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] +× 1F1E6 × 0308 ÷ 0028 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] LEFT PARENTHESIS (OP) ÷ [0.3] +× 1F1E6 × 0308 × 0020 ÷ 0028 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] × 1F1E6 ÷ 0025 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] PERCENT SIGN (PO) ÷ [0.3] × 1F1E6 × 0020 ÷ 0025 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] -× 1F1E6 × 0308 ÷ 0025 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] PERCENT SIGN (PO) ÷ [0.3] -× 1F1E6 × 0308 × 0020 ÷ 0025 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] +× 1F1E6 × 0308 ÷ 0025 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] PERCENT SIGN (PO) ÷ [0.3] +× 1F1E6 × 0308 × 0020 ÷ 0025 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] × 1F1E6 ÷ 0024 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] DOLLAR SIGN (PR) ÷ [0.3] × 1F1E6 × 0020 ÷ 0024 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] -× 1F1E6 × 0308 ÷ 0024 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] DOLLAR SIGN (PR) ÷ [0.3] -× 1F1E6 × 0308 × 0020 ÷ 0024 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] +× 1F1E6 × 0308 ÷ 0024 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] DOLLAR SIGN (PR) ÷ [0.3] +× 1F1E6 × 0308 × 0020 ÷ 0024 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] × 1F1E6 × 0022 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [19.01] QUOTATION MARK (QU) ÷ [0.3] × 1F1E6 × 0020 ÷ 0022 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] -× 1F1E6 × 0308 × 0022 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM) × [19.01] QUOTATION MARK (QU) ÷ [0.3] -× 1F1E6 × 0308 × 0020 ÷ 0022 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] +× 1F1E6 × 0308 × 0022 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM1_CM) × [19.01] QUOTATION MARK (QU) ÷ [0.3] +× 1F1E6 × 0308 × 0020 ÷ 0022 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] × 1F1E6 × 0020 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [7.01] SPACE (SP) ÷ [0.3] × 1F1E6 × 0020 × 0020 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] -× 1F1E6 × 0308 × 0020 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [0.3] -× 1F1E6 × 0308 × 0020 × 0020 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] +× 1F1E6 × 0308 × 0020 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [0.3] +× 1F1E6 × 0308 × 0020 × 0020 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] × 1F1E6 × 002F ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [13.02] SOLIDUS (SY) ÷ [0.3] × 1F1E6 × 0020 × 002F ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] -× 1F1E6 × 0308 × 002F ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM) × [13.03] SOLIDUS (SY) ÷ [0.3] -× 1F1E6 × 0308 × 0020 × 002F ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] +× 1F1E6 × 0308 × 002F ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] SOLIDUS (SY) ÷ [0.3] +× 1F1E6 × 0308 × 0020 × 002F ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] × 1F1E6 × 2060 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [11.01] WORD JOINER (WJ) ÷ [0.3] × 1F1E6 × 0020 × 2060 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] -× 1F1E6 × 0308 × 2060 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM) × [11.01] WORD JOINER (WJ) ÷ [0.3] -× 1F1E6 × 0308 × 0020 × 2060 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] +× 1F1E6 × 0308 × 2060 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM1_CM) × [11.01] WORD JOINER (WJ) ÷ [0.3] +× 1F1E6 × 0308 × 0020 × 2060 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] × 1F1E6 × 200B ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] × 1F1E6 × 0020 × 200B ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] -× 1F1E6 × 0308 × 200B ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] -× 1F1E6 × 0308 × 0020 × 200B ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] +× 1F1E6 × 0308 × 200B ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] +× 1F1E6 × 0308 × 0020 × 200B ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] × 1F1E6 × 1F1E6 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [30.11] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] × 1F1E6 × 0020 ÷ 1F1E6 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -× 1F1E6 × 0308 × 1F1E6 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM) × [30.11] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -× 1F1E6 × 0308 × 0020 ÷ 1F1E6 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 1F1E6 × 0308 × 1F1E6 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM1_CM) × [30.11] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 1F1E6 × 0308 × 0020 ÷ 1F1E6 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 1F1E6 ÷ 261D ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 1F1E6 × 0020 ÷ 261D ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [7.01] SPACE (SP) ÷ [18.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 1F1E6 × 0308 ÷ 261D ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 1F1E6 × 0308 × 0020 ÷ 261D ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 1F1E6 ÷ 1F3FB ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 1F1E6 × 0020 ÷ 1F3FB ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [7.01] SPACE (SP) ÷ [18.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 1F1E6 × 0308 ÷ 1F3FB ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 1F1E6 × 0308 × 0020 ÷ 1F3FB ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 1F1E6 × 0001 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 1F1E6 × 0020 ÷ 0001 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 1F1E6 × 0308 × 0001 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM1_CM) × [9.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 1F1E6 × 0308 × 0020 ÷ 0001 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 1F1E6 × 200D ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 1F1E6 × 0020 ÷ 200D ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [7.01] SPACE (SP) ÷ [18.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 1F1E6 × 0308 × 200D ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM1_CM) × [9.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 1F1E6 × 0308 × 0020 ÷ 200D ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] × 1F1E6 ÷ 00A7 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] SECTION SIGN (AI_AL) ÷ [0.3] × 1F1E6 × 0020 ÷ 00A7 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] -× 1F1E6 × 0308 ÷ 00A7 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] SECTION SIGN (AI_AL) ÷ [0.3] -× 1F1E6 × 0308 × 0020 ÷ 00A7 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] +× 1F1E6 × 0308 ÷ 00A7 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] SECTION SIGN (AI_AL) ÷ [0.3] +× 1F1E6 × 0308 × 0020 ÷ 00A7 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] × 1F1E6 ÷ 50005 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] <reserved-50005> (XX_AL) ÷ [0.3] × 1F1E6 × 0020 ÷ 50005 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] -× 1F1E6 × 0308 ÷ 50005 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] <reserved-50005> (XX_AL) ÷ [0.3] -× 1F1E6 × 0308 × 0020 ÷ 50005 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] +× 1F1E6 × 0308 ÷ 50005 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] <reserved-50005> (XX_AL) ÷ [0.3] +× 1F1E6 × 0308 × 0020 ÷ 50005 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] × 1F1E6 ÷ 0E01 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] × 1F1E6 × 0020 ÷ 0E01 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] -× 1F1E6 × 0308 ÷ 0E01 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] -× 1F1E6 × 0308 × 0020 ÷ 0E01 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] +× 1F1E6 × 0308 ÷ 0E01 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] +× 1F1E6 × 0308 × 0020 ÷ 0E01 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] × 1F1E6 × 3041 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] × 1F1E6 × 0020 ÷ 3041 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] -× 1F1E6 × 0308 × 3041 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] -× 1F1E6 × 0308 × 0020 ÷ 3041 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] +× 1F1E6 × 0308 × 3041 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] +× 1F1E6 × 0308 × 0020 ÷ 3041 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] +× 261D ÷ 0023 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) ÷ [999.0] NUMBER SIGN (AL) ÷ [0.3] +× 261D × 0020 ÷ 0023 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] +× 261D × 0308 ÷ 0023 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] NUMBER SIGN (AL) ÷ [0.3] +× 261D × 0308 × 0020 ÷ 0023 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] +× 261D ÷ 2014 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) ÷ [999.0] EM DASH (B2) ÷ [0.3] +× 261D × 0020 ÷ 2014 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] +× 261D × 0308 ÷ 2014 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] EM DASH (B2) ÷ [0.3] +× 261D × 0308 × 0020 ÷ 2014 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] +× 261D × 0009 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] +× 261D × 0020 ÷ 0009 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] +× 261D × 0308 × 0009 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] +× 261D × 0308 × 0020 ÷ 0009 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] +× 261D ÷ 00B4 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3] +× 261D × 0020 ÷ 00B4 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] +× 261D × 0308 ÷ 00B4 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3] +× 261D × 0308 × 0020 ÷ 00B4 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] +× 261D × 000B ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] +× 261D × 0020 × 000B ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] +× 261D × 0308 × 000B ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] +× 261D × 0308 × 0020 × 000B ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] +× 261D ÷ FFFC ÷ # × [0.3] WHITE UP POINTING INDEX (EB) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] +× 261D × 0020 ÷ FFFC ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] +× 261D × 0308 ÷ FFFC ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] +× 261D × 0308 × 0020 ÷ FFFC ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] +× 261D × 007D ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] +× 261D × 0020 × 007D ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] +× 261D × 0308 × 007D ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] RIGHT CURLY BRACKET (CL) ÷ [0.3] +× 261D × 0308 × 0020 × 007D ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] +× 261D × 0029 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] +× 261D × 0020 × 0029 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] +× 261D × 0308 × 0029 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] RIGHT PARENTHESIS (CP) ÷ [0.3] +× 261D × 0308 × 0020 × 0029 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] +× 261D × 000D ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +× 261D × 0020 × 000D ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +× 261D × 0308 × 000D ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +× 261D × 0308 × 0020 × 000D ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +× 261D × 0021 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] +× 261D × 0020 × 0021 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] +× 261D × 0308 × 0021 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] +× 261D × 0308 × 0020 × 0021 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] +× 261D × 00A0 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [12.1] NO-BREAK SPACE (GL) ÷ [0.3] +× 261D × 0020 ÷ 00A0 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] +× 261D × 0308 × 00A0 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [12.2] NO-BREAK SPACE (GL) ÷ [0.3] +× 261D × 0308 × 0020 ÷ 00A0 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] +× 261D ÷ AC00 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) ÷ [999.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] +× 261D × 0020 ÷ AC00 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] +× 261D × 0308 ÷ AC00 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] +× 261D × 0308 × 0020 ÷ AC00 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] +× 261D ÷ AC01 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) ÷ [999.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] +× 261D × 0020 ÷ AC01 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] +× 261D × 0308 ÷ AC01 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] +× 261D × 0308 × 0020 ÷ AC01 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] +× 261D ÷ 05D0 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) ÷ [999.0] HEBREW LETTER ALEF (HL) ÷ [0.3] +× 261D × 0020 ÷ 05D0 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] +× 261D × 0308 ÷ 05D0 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HEBREW LETTER ALEF (HL) ÷ [0.3] +× 261D × 0308 × 0020 ÷ 05D0 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] +× 261D × 002D ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] +× 261D × 0020 ÷ 002D ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] +× 261D × 0308 × 002D ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] +× 261D × 0308 × 0020 ÷ 002D ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] +× 261D ÷ 231A ÷ # × [0.3] WHITE UP POINTING INDEX (EB) ÷ [999.0] WATCH (ID) ÷ [0.3] +× 261D × 0020 ÷ 231A ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] +× 261D × 0308 ÷ 231A ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] WATCH (ID) ÷ [0.3] +× 261D × 0308 × 0020 ÷ 231A ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] +× 261D × 2024 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [22.03] ONE DOT LEADER (IN) ÷ [0.3] +× 261D × 0020 ÷ 2024 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] +× 261D × 0308 × 2024 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [22.03] ONE DOT LEADER (IN) ÷ [0.3] +× 261D × 0308 × 0020 ÷ 2024 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] +× 261D × 002C ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [13.02] COMMA (IS) ÷ [0.3] +× 261D × 0020 × 002C ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] +× 261D × 0308 × 002C ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] COMMA (IS) ÷ [0.3] +× 261D × 0308 × 0020 × 002C ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] +× 261D ÷ 1100 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) ÷ [999.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] +× 261D × 0020 ÷ 1100 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] +× 261D × 0308 ÷ 1100 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] +× 261D × 0308 × 0020 ÷ 1100 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] +× 261D ÷ 11A8 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) ÷ [999.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] +× 261D × 0020 ÷ 11A8 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] +× 261D × 0308 ÷ 11A8 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] +× 261D × 0308 × 0020 ÷ 11A8 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] +× 261D ÷ 1160 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) ÷ [999.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] +× 261D × 0020 ÷ 1160 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] +× 261D × 0308 ÷ 1160 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] +× 261D × 0308 × 0020 ÷ 1160 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] +× 261D × 000A ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] +× 261D × 0020 × 000A ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] +× 261D × 0308 × 000A ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] +× 261D × 0308 × 0020 × 000A ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] +× 261D × 0085 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] +× 261D × 0020 × 0085 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] +× 261D × 0308 × 0085 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] +× 261D × 0308 × 0020 × 0085 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] +× 261D × 17D6 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] +× 261D × 0020 ÷ 17D6 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] +× 261D × 0308 × 17D6 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] +× 261D × 0308 × 0020 ÷ 17D6 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] +× 261D ÷ 0030 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) ÷ [999.0] DIGIT ZERO (NU) ÷ [0.3] +× 261D × 0020 ÷ 0030 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] +× 261D × 0308 ÷ 0030 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] DIGIT ZERO (NU) ÷ [0.3] +× 261D × 0308 × 0020 ÷ 0030 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] +× 261D ÷ 0028 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) ÷ [999.0] LEFT PARENTHESIS (OP) ÷ [0.3] +× 261D × 0020 ÷ 0028 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] +× 261D × 0308 ÷ 0028 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] LEFT PARENTHESIS (OP) ÷ [0.3] +× 261D × 0308 × 0020 ÷ 0028 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] +× 261D × 0025 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [23.13] PERCENT SIGN (PO) ÷ [0.3] +× 261D × 0020 ÷ 0025 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] +× 261D × 0308 × 0025 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [23.13] PERCENT SIGN (PO) ÷ [0.3] +× 261D × 0308 × 0020 ÷ 0025 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] +× 261D ÷ 0024 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) ÷ [999.0] DOLLAR SIGN (PR) ÷ [0.3] +× 261D × 0020 ÷ 0024 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] +× 261D × 0308 ÷ 0024 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] DOLLAR SIGN (PR) ÷ [0.3] +× 261D × 0308 × 0020 ÷ 0024 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] +× 261D × 0022 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [19.01] QUOTATION MARK (QU) ÷ [0.3] +× 261D × 0020 ÷ 0022 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] +× 261D × 0308 × 0022 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [19.01] QUOTATION MARK (QU) ÷ [0.3] +× 261D × 0308 × 0020 ÷ 0022 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] +× 261D × 0020 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [7.01] SPACE (SP) ÷ [0.3] +× 261D × 0020 × 0020 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] +× 261D × 0308 × 0020 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [0.3] +× 261D × 0308 × 0020 × 0020 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] +× 261D × 002F ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [13.02] SOLIDUS (SY) ÷ [0.3] +× 261D × 0020 × 002F ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] +× 261D × 0308 × 002F ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] SOLIDUS (SY) ÷ [0.3] +× 261D × 0308 × 0020 × 002F ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] +× 261D × 2060 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [11.01] WORD JOINER (WJ) ÷ [0.3] +× 261D × 0020 × 2060 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] +× 261D × 0308 × 2060 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [11.01] WORD JOINER (WJ) ÷ [0.3] +× 261D × 0308 × 0020 × 2060 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] +× 261D × 200B ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] +× 261D × 0020 × 200B ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] +× 261D × 0308 × 200B ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] +× 261D × 0308 × 0020 × 200B ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] +× 261D ÷ 1F1E6 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 261D × 0020 ÷ 1F1E6 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 261D × 0308 ÷ 1F1E6 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 261D × 0308 × 0020 ÷ 1F1E6 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 261D ÷ 261D ÷ # × [0.3] WHITE UP POINTING INDEX (EB) ÷ [999.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 261D × 0020 ÷ 261D ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [7.01] SPACE (SP) ÷ [18.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 261D × 0308 ÷ 261D ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 261D × 0308 × 0020 ÷ 261D ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 261D × 1F3FB ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [30.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 261D × 0020 ÷ 1F3FB ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [7.01] SPACE (SP) ÷ [18.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 261D × 0308 × 1F3FB ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [30.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 261D × 0308 × 0020 ÷ 1F3FB ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 261D × 0001 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [9.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 261D × 0020 ÷ 0001 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 261D × 0308 × 0001 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [9.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 261D × 0308 × 0020 ÷ 0001 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 261D × 200D ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [9.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 261D × 0020 ÷ 200D ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [7.01] SPACE (SP) ÷ [18.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 261D × 0308 × 200D ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [9.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 261D × 0308 × 0020 ÷ 200D ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 261D ÷ 00A7 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) ÷ [999.0] SECTION SIGN (AI_AL) ÷ [0.3] +× 261D × 0020 ÷ 00A7 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] +× 261D × 0308 ÷ 00A7 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] SECTION SIGN (AI_AL) ÷ [0.3] +× 261D × 0308 × 0020 ÷ 00A7 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] +× 261D ÷ 50005 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) ÷ [999.0] <reserved-50005> (XX_AL) ÷ [0.3] +× 261D × 0020 ÷ 50005 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] +× 261D × 0308 ÷ 50005 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] <reserved-50005> (XX_AL) ÷ [0.3] +× 261D × 0308 × 0020 ÷ 50005 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] +× 261D ÷ 0E01 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) ÷ [999.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] +× 261D × 0020 ÷ 0E01 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] +× 261D × 0308 ÷ 0E01 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] +× 261D × 0308 × 0020 ÷ 0E01 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] +× 261D × 3041 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] +× 261D × 0020 ÷ 3041 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] +× 261D × 0308 × 3041 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] +× 261D × 0308 × 0020 ÷ 3041 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] +× 1F3FB ÷ 0023 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [999.0] NUMBER SIGN (AL) ÷ [0.3] +× 1F3FB × 0020 ÷ 0023 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] +× 1F3FB × 0308 ÷ 0023 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] NUMBER SIGN (AL) ÷ [0.3] +× 1F3FB × 0308 × 0020 ÷ 0023 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] +× 1F3FB ÷ 2014 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [999.0] EM DASH (B2) ÷ [0.3] +× 1F3FB × 0020 ÷ 2014 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] +× 1F3FB × 0308 ÷ 2014 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] EM DASH (B2) ÷ [0.3] +× 1F3FB × 0308 × 0020 ÷ 2014 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] +× 1F3FB × 0009 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] +× 1F3FB × 0020 ÷ 0009 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] +× 1F3FB × 0308 × 0009 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] +× 1F3FB × 0308 × 0020 ÷ 0009 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] +× 1F3FB ÷ 00B4 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3] +× 1F3FB × 0020 ÷ 00B4 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] +× 1F3FB × 0308 ÷ 00B4 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3] +× 1F3FB × 0308 × 0020 ÷ 00B4 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] +× 1F3FB × 000B ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] +× 1F3FB × 0020 × 000B ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] +× 1F3FB × 0308 × 000B ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] +× 1F3FB × 0308 × 0020 × 000B ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] +× 1F3FB ÷ FFFC ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] +× 1F3FB × 0020 ÷ FFFC ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] +× 1F3FB × 0308 ÷ FFFC ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] +× 1F3FB × 0308 × 0020 ÷ FFFC ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] +× 1F3FB × 007D ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] +× 1F3FB × 0020 × 007D ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] +× 1F3FB × 0308 × 007D ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] RIGHT CURLY BRACKET (CL) ÷ [0.3] +× 1F3FB × 0308 × 0020 × 007D ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] +× 1F3FB × 0029 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] +× 1F3FB × 0020 × 0029 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] +× 1F3FB × 0308 × 0029 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] RIGHT PARENTHESIS (CP) ÷ [0.3] +× 1F3FB × 0308 × 0020 × 0029 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] +× 1F3FB × 000D ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +× 1F3FB × 0020 × 000D ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +× 1F3FB × 0308 × 000D ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +× 1F3FB × 0308 × 0020 × 000D ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +× 1F3FB × 0021 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] +× 1F3FB × 0020 × 0021 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] +× 1F3FB × 0308 × 0021 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] +× 1F3FB × 0308 × 0020 × 0021 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] +× 1F3FB × 00A0 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [12.1] NO-BREAK SPACE (GL) ÷ [0.3] +× 1F3FB × 0020 ÷ 00A0 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] +× 1F3FB × 0308 × 00A0 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [12.2] NO-BREAK SPACE (GL) ÷ [0.3] +× 1F3FB × 0308 × 0020 ÷ 00A0 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] +× 1F3FB ÷ AC00 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [999.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] +× 1F3FB × 0020 ÷ AC00 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] +× 1F3FB × 0308 ÷ AC00 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] +× 1F3FB × 0308 × 0020 ÷ AC00 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] +× 1F3FB ÷ AC01 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [999.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] +× 1F3FB × 0020 ÷ AC01 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] +× 1F3FB × 0308 ÷ AC01 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] +× 1F3FB × 0308 × 0020 ÷ AC01 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] +× 1F3FB ÷ 05D0 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [999.0] HEBREW LETTER ALEF (HL) ÷ [0.3] +× 1F3FB × 0020 ÷ 05D0 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] +× 1F3FB × 0308 ÷ 05D0 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HEBREW LETTER ALEF (HL) ÷ [0.3] +× 1F3FB × 0308 × 0020 ÷ 05D0 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] +× 1F3FB × 002D ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] +× 1F3FB × 0020 ÷ 002D ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] +× 1F3FB × 0308 × 002D ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] +× 1F3FB × 0308 × 0020 ÷ 002D ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] +× 1F3FB ÷ 231A ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [999.0] WATCH (ID) ÷ [0.3] +× 1F3FB × 0020 ÷ 231A ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] +× 1F3FB × 0308 ÷ 231A ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] WATCH (ID) ÷ [0.3] +× 1F3FB × 0308 × 0020 ÷ 231A ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] +× 1F3FB × 2024 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [22.03] ONE DOT LEADER (IN) ÷ [0.3] +× 1F3FB × 0020 ÷ 2024 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] +× 1F3FB × 0308 × 2024 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [22.03] ONE DOT LEADER (IN) ÷ [0.3] +× 1F3FB × 0308 × 0020 ÷ 2024 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] +× 1F3FB × 002C ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [13.02] COMMA (IS) ÷ [0.3] +× 1F3FB × 0020 × 002C ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] +× 1F3FB × 0308 × 002C ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] COMMA (IS) ÷ [0.3] +× 1F3FB × 0308 × 0020 × 002C ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] +× 1F3FB ÷ 1100 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [999.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] +× 1F3FB × 0020 ÷ 1100 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] +× 1F3FB × 0308 ÷ 1100 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] +× 1F3FB × 0308 × 0020 ÷ 1100 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] +× 1F3FB ÷ 11A8 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [999.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] +× 1F3FB × 0020 ÷ 11A8 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] +× 1F3FB × 0308 ÷ 11A8 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] +× 1F3FB × 0308 × 0020 ÷ 11A8 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] +× 1F3FB ÷ 1160 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [999.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] +× 1F3FB × 0020 ÷ 1160 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] +× 1F3FB × 0308 ÷ 1160 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] +× 1F3FB × 0308 × 0020 ÷ 1160 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] +× 1F3FB × 000A ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] +× 1F3FB × 0020 × 000A ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] +× 1F3FB × 0308 × 000A ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] +× 1F3FB × 0308 × 0020 × 000A ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] +× 1F3FB × 0085 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] +× 1F3FB × 0020 × 0085 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] +× 1F3FB × 0308 × 0085 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] +× 1F3FB × 0308 × 0020 × 0085 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] +× 1F3FB × 17D6 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] +× 1F3FB × 0020 ÷ 17D6 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] +× 1F3FB × 0308 × 17D6 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] +× 1F3FB × 0308 × 0020 ÷ 17D6 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] +× 1F3FB ÷ 0030 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [999.0] DIGIT ZERO (NU) ÷ [0.3] +× 1F3FB × 0020 ÷ 0030 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] +× 1F3FB × 0308 ÷ 0030 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] DIGIT ZERO (NU) ÷ [0.3] +× 1F3FB × 0308 × 0020 ÷ 0030 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] +× 1F3FB ÷ 0028 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [999.0] LEFT PARENTHESIS (OP) ÷ [0.3] +× 1F3FB × 0020 ÷ 0028 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] +× 1F3FB × 0308 ÷ 0028 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] LEFT PARENTHESIS (OP) ÷ [0.3] +× 1F3FB × 0308 × 0020 ÷ 0028 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] +× 1F3FB × 0025 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [23.13] PERCENT SIGN (PO) ÷ [0.3] +× 1F3FB × 0020 ÷ 0025 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] +× 1F3FB × 0308 × 0025 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [23.13] PERCENT SIGN (PO) ÷ [0.3] +× 1F3FB × 0308 × 0020 ÷ 0025 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] +× 1F3FB ÷ 0024 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [999.0] DOLLAR SIGN (PR) ÷ [0.3] +× 1F3FB × 0020 ÷ 0024 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] +× 1F3FB × 0308 ÷ 0024 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] DOLLAR SIGN (PR) ÷ [0.3] +× 1F3FB × 0308 × 0020 ÷ 0024 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] +× 1F3FB × 0022 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [19.01] QUOTATION MARK (QU) ÷ [0.3] +× 1F3FB × 0020 ÷ 0022 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] +× 1F3FB × 0308 × 0022 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [19.01] QUOTATION MARK (QU) ÷ [0.3] +× 1F3FB × 0308 × 0020 ÷ 0022 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] +× 1F3FB × 0020 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [7.01] SPACE (SP) ÷ [0.3] +× 1F3FB × 0020 × 0020 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] +× 1F3FB × 0308 × 0020 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [0.3] +× 1F3FB × 0308 × 0020 × 0020 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] +× 1F3FB × 002F ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [13.02] SOLIDUS (SY) ÷ [0.3] +× 1F3FB × 0020 × 002F ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] +× 1F3FB × 0308 × 002F ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] SOLIDUS (SY) ÷ [0.3] +× 1F3FB × 0308 × 0020 × 002F ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] +× 1F3FB × 2060 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [11.01] WORD JOINER (WJ) ÷ [0.3] +× 1F3FB × 0020 × 2060 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] +× 1F3FB × 0308 × 2060 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [11.01] WORD JOINER (WJ) ÷ [0.3] +× 1F3FB × 0308 × 0020 × 2060 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] +× 1F3FB × 200B ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] +× 1F3FB × 0020 × 200B ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] +× 1F3FB × 0308 × 200B ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] +× 1F3FB × 0308 × 0020 × 200B ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] +× 1F3FB ÷ 1F1E6 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 1F3FB × 0020 ÷ 1F1E6 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 1F3FB × 0308 ÷ 1F1E6 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 1F3FB × 0308 × 0020 ÷ 1F1E6 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 1F3FB ÷ 261D ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [999.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 1F3FB × 0020 ÷ 261D ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [7.01] SPACE (SP) ÷ [18.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 1F3FB × 0308 ÷ 261D ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 1F3FB × 0308 × 0020 ÷ 261D ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 1F3FB ÷ 1F3FB ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 1F3FB × 0020 ÷ 1F3FB ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [7.01] SPACE (SP) ÷ [18.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 1F3FB × 0308 ÷ 1F3FB ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 1F3FB × 0308 × 0020 ÷ 1F3FB ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 1F3FB × 0001 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [9.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 1F3FB × 0020 ÷ 0001 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 1F3FB × 0308 × 0001 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [9.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 1F3FB × 0308 × 0020 ÷ 0001 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 1F3FB × 200D ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [9.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 1F3FB × 0020 ÷ 200D ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [7.01] SPACE (SP) ÷ [18.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 1F3FB × 0308 × 200D ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [9.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 1F3FB × 0308 × 0020 ÷ 200D ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 1F3FB ÷ 00A7 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [999.0] SECTION SIGN (AI_AL) ÷ [0.3] +× 1F3FB × 0020 ÷ 00A7 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] +× 1F3FB × 0308 ÷ 00A7 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] SECTION SIGN (AI_AL) ÷ [0.3] +× 1F3FB × 0308 × 0020 ÷ 00A7 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] +× 1F3FB ÷ 50005 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [999.0] <reserved-50005> (XX_AL) ÷ [0.3] +× 1F3FB × 0020 ÷ 50005 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] +× 1F3FB × 0308 ÷ 50005 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] <reserved-50005> (XX_AL) ÷ [0.3] +× 1F3FB × 0308 × 0020 ÷ 50005 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] +× 1F3FB ÷ 0E01 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [999.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] +× 1F3FB × 0020 ÷ 0E01 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] +× 1F3FB × 0308 ÷ 0E01 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] +× 1F3FB × 0308 × 0020 ÷ 0E01 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] +× 1F3FB × 3041 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] +× 1F3FB × 0020 ÷ 3041 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] +× 1F3FB × 0308 × 3041 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] +× 1F3FB × 0308 × 0020 ÷ 3041 ÷ # × [0.3] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] +× 0001 × 0023 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [28.0] NUMBER SIGN (AL) ÷ [0.3] +× 0001 × 0020 ÷ 0023 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] +× 0001 × 0308 × 0023 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [28.0] NUMBER SIGN (AL) ÷ [0.3] +× 0001 × 0308 × 0020 ÷ 0023 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] +× 0001 ÷ 2014 ÷ # × [0.3] <START OF HEADING> (CM1_CM) ÷ [999.0] EM DASH (B2) ÷ [0.3] +× 0001 × 0020 ÷ 2014 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] +× 0001 × 0308 ÷ 2014 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] EM DASH (B2) ÷ [0.3] +× 0001 × 0308 × 0020 ÷ 2014 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] +× 0001 × 0009 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] +× 0001 × 0020 ÷ 0009 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] +× 0001 × 0308 × 0009 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] +× 0001 × 0308 × 0020 ÷ 0009 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] +× 0001 ÷ 00B4 ÷ # × [0.3] <START OF HEADING> (CM1_CM) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3] +× 0001 × 0020 ÷ 00B4 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] +× 0001 × 0308 ÷ 00B4 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3] +× 0001 × 0308 × 0020 ÷ 00B4 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] +× 0001 × 000B ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] +× 0001 × 0020 × 000B ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] +× 0001 × 0308 × 000B ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] +× 0001 × 0308 × 0020 × 000B ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] +× 0001 ÷ FFFC ÷ # × [0.3] <START OF HEADING> (CM1_CM) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] +× 0001 × 0020 ÷ FFFC ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] +× 0001 × 0308 ÷ FFFC ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] +× 0001 × 0308 × 0020 ÷ FFFC ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] +× 0001 × 007D ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [13.04] RIGHT CURLY BRACKET (CL) ÷ [0.3] +× 0001 × 0020 × 007D ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] +× 0001 × 0308 × 007D ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.04] RIGHT CURLY BRACKET (CL) ÷ [0.3] +× 0001 × 0308 × 0020 × 007D ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] +× 0001 × 0029 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [13.04] RIGHT PARENTHESIS (CP) ÷ [0.3] +× 0001 × 0020 × 0029 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] +× 0001 × 0308 × 0029 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.04] RIGHT PARENTHESIS (CP) ÷ [0.3] +× 0001 × 0308 × 0020 × 0029 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] +× 0001 × 000D ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +× 0001 × 0020 × 000D ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +× 0001 × 0308 × 000D ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +× 0001 × 0308 × 0020 × 000D ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +× 0001 × 0021 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] +× 0001 × 0020 × 0021 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] +× 0001 × 0308 × 0021 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] +× 0001 × 0308 × 0020 × 0021 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] +× 0001 × 00A0 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [12.3] NO-BREAK SPACE (GL) ÷ [0.3] +× 0001 × 0020 ÷ 00A0 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] +× 0001 × 0308 × 00A0 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [12.3] NO-BREAK SPACE (GL) ÷ [0.3] +× 0001 × 0308 × 0020 ÷ 00A0 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] +× 0001 ÷ AC00 ÷ # × [0.3] <START OF HEADING> (CM1_CM) ÷ [999.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] +× 0001 × 0020 ÷ AC00 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] +× 0001 × 0308 ÷ AC00 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] +× 0001 × 0308 × 0020 ÷ AC00 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] +× 0001 ÷ AC01 ÷ # × [0.3] <START OF HEADING> (CM1_CM) ÷ [999.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] +× 0001 × 0020 ÷ AC01 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] +× 0001 × 0308 ÷ AC01 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] +× 0001 × 0308 × 0020 ÷ AC01 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] +× 0001 × 05D0 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [28.0] HEBREW LETTER ALEF (HL) ÷ [0.3] +× 0001 × 0020 ÷ 05D0 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] +× 0001 × 0308 × 05D0 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [28.0] HEBREW LETTER ALEF (HL) ÷ [0.3] +× 0001 × 0308 × 0020 ÷ 05D0 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] +× 0001 × 002D ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] +× 0001 × 0020 ÷ 002D ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] +× 0001 × 0308 × 002D ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] +× 0001 × 0308 × 0020 ÷ 002D ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] +× 0001 ÷ 231A ÷ # × [0.3] <START OF HEADING> (CM1_CM) ÷ [999.0] WATCH (ID) ÷ [0.3] +× 0001 × 0020 ÷ 231A ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] +× 0001 × 0308 ÷ 231A ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] WATCH (ID) ÷ [0.3] +× 0001 × 0308 × 0020 ÷ 231A ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] +× 0001 × 2024 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [22.01] ONE DOT LEADER (IN) ÷ [0.3] +× 0001 × 0020 ÷ 2024 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] +× 0001 × 0308 × 2024 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [22.01] ONE DOT LEADER (IN) ÷ [0.3] +× 0001 × 0308 × 0020 ÷ 2024 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] +× 0001 × 002C ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [13.04] COMMA (IS) ÷ [0.3] +× 0001 × 0020 × 002C ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] +× 0001 × 0308 × 002C ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.04] COMMA (IS) ÷ [0.3] +× 0001 × 0308 × 0020 × 002C ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] +× 0001 ÷ 1100 ÷ # × [0.3] <START OF HEADING> (CM1_CM) ÷ [999.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] +× 0001 × 0020 ÷ 1100 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] +× 0001 × 0308 ÷ 1100 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] +× 0001 × 0308 × 0020 ÷ 1100 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] +× 0001 ÷ 11A8 ÷ # × [0.3] <START OF HEADING> (CM1_CM) ÷ [999.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] +× 0001 × 0020 ÷ 11A8 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] +× 0001 × 0308 ÷ 11A8 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] +× 0001 × 0308 × 0020 ÷ 11A8 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] +× 0001 ÷ 1160 ÷ # × [0.3] <START OF HEADING> (CM1_CM) ÷ [999.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] +× 0001 × 0020 ÷ 1160 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] +× 0001 × 0308 ÷ 1160 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] +× 0001 × 0308 × 0020 ÷ 1160 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] +× 0001 × 000A ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] +× 0001 × 0020 × 000A ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] +× 0001 × 0308 × 000A ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] +× 0001 × 0308 × 0020 × 000A ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] +× 0001 × 0085 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] +× 0001 × 0020 × 0085 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] +× 0001 × 0308 × 0085 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] +× 0001 × 0308 × 0020 × 0085 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] +× 0001 × 17D6 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] +× 0001 × 0020 ÷ 17D6 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] +× 0001 × 0308 × 17D6 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] +× 0001 × 0308 × 0020 ÷ 17D6 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] +× 0001 × 0030 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [23.02] DIGIT ZERO (NU) ÷ [0.3] +× 0001 × 0020 ÷ 0030 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] +× 0001 × 0308 × 0030 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [23.02] DIGIT ZERO (NU) ÷ [0.3] +× 0001 × 0308 × 0020 ÷ 0030 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] +× 0001 × 0028 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [30.01] LEFT PARENTHESIS (OP) ÷ [0.3] +× 0001 × 0020 ÷ 0028 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] +× 0001 × 0308 × 0028 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [30.01] LEFT PARENTHESIS (OP) ÷ [0.3] +× 0001 × 0308 × 0020 ÷ 0028 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] +× 0001 × 0025 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [24.03] PERCENT SIGN (PO) ÷ [0.3] +× 0001 × 0020 ÷ 0025 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] +× 0001 × 0308 × 0025 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [24.03] PERCENT SIGN (PO) ÷ [0.3] +× 0001 × 0308 × 0020 ÷ 0025 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] +× 0001 × 0024 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [24.03] DOLLAR SIGN (PR) ÷ [0.3] +× 0001 × 0020 ÷ 0024 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] +× 0001 × 0308 × 0024 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [24.03] DOLLAR SIGN (PR) ÷ [0.3] +× 0001 × 0308 × 0020 ÷ 0024 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] +× 0001 × 0022 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [19.01] QUOTATION MARK (QU) ÷ [0.3] +× 0001 × 0020 ÷ 0022 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] +× 0001 × 0308 × 0022 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [19.01] QUOTATION MARK (QU) ÷ [0.3] +× 0001 × 0308 × 0020 ÷ 0022 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] +× 0001 × 0020 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [7.01] SPACE (SP) ÷ [0.3] +× 0001 × 0020 × 0020 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] +× 0001 × 0308 × 0020 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [0.3] +× 0001 × 0308 × 0020 × 0020 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] +× 0001 × 002F ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [13.04] SOLIDUS (SY) ÷ [0.3] +× 0001 × 0020 × 002F ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] +× 0001 × 0308 × 002F ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.04] SOLIDUS (SY) ÷ [0.3] +× 0001 × 0308 × 0020 × 002F ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] +× 0001 × 2060 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [11.01] WORD JOINER (WJ) ÷ [0.3] +× 0001 × 0020 × 2060 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] +× 0001 × 0308 × 2060 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [11.01] WORD JOINER (WJ) ÷ [0.3] +× 0001 × 0308 × 0020 × 2060 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] +× 0001 × 200B ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] +× 0001 × 0020 × 200B ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] +× 0001 × 0308 × 200B ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] +× 0001 × 0308 × 0020 × 200B ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] +× 0001 ÷ 1F1E6 ÷ # × [0.3] <START OF HEADING> (CM1_CM) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 0001 × 0020 ÷ 1F1E6 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 0001 × 0308 ÷ 1F1E6 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 0001 × 0308 × 0020 ÷ 1F1E6 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 0001 ÷ 261D ÷ # × [0.3] <START OF HEADING> (CM1_CM) ÷ [999.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 0001 × 0020 ÷ 261D ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 0001 × 0308 ÷ 261D ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 0001 × 0308 × 0020 ÷ 261D ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 0001 ÷ 1F3FB ÷ # × [0.3] <START OF HEADING> (CM1_CM) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 0001 × 0020 ÷ 1F3FB ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 0001 × 0308 ÷ 1F3FB ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 0001 × 0308 × 0020 ÷ 1F3FB ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 0001 × 0001 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [9.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 0001 × 0020 ÷ 0001 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 0001 × 0308 × 0001 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [9.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 0001 × 0308 × 0020 ÷ 0001 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 0001 × 200D ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [9.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 0001 × 0020 ÷ 200D ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 0001 × 0308 × 200D ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [9.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 0001 × 0308 × 0020 ÷ 200D ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 0001 × 00A7 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [28.0] SECTION SIGN (AI_AL) ÷ [0.3] +× 0001 × 0020 ÷ 00A7 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] +× 0001 × 0308 × 00A7 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [28.0] SECTION SIGN (AI_AL) ÷ [0.3] +× 0001 × 0308 × 0020 ÷ 00A7 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] +× 0001 × 50005 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [28.0] <reserved-50005> (XX_AL) ÷ [0.3] +× 0001 × 0020 ÷ 50005 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] +× 0001 × 0308 × 50005 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [28.0] <reserved-50005> (XX_AL) ÷ [0.3] +× 0001 × 0308 × 0020 ÷ 50005 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] +× 0001 × 0E01 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [28.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] +× 0001 × 0020 ÷ 0E01 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] +× 0001 × 0308 × 0E01 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [28.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] +× 0001 × 0308 × 0020 ÷ 0E01 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] +× 0001 × 3041 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] +× 0001 × 0020 ÷ 3041 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] +× 0001 × 0308 × 3041 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] +× 0001 × 0308 × 0020 ÷ 3041 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] +× 200D × 0023 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [28.0] NUMBER SIGN (AL) ÷ [0.3] +× 200D × 0020 ÷ 0023 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] +× 200D × 0308 × 0023 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [28.0] NUMBER SIGN (AL) ÷ [0.3] +× 200D × 0308 × 0020 ÷ 0023 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] +× 200D ÷ 2014 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [999.0] EM DASH (B2) ÷ [0.3] +× 200D × 0020 ÷ 2014 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] +× 200D × 0308 ÷ 2014 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] EM DASH (B2) ÷ [0.3] +× 200D × 0308 × 0020 ÷ 2014 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] +× 200D × 0009 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] +× 200D × 0020 ÷ 0009 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] +× 200D × 0308 × 0009 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] +× 200D × 0308 × 0020 ÷ 0009 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] +× 200D ÷ 00B4 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3] +× 200D × 0020 ÷ 00B4 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] +× 200D × 0308 ÷ 00B4 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3] +× 200D × 0308 × 0020 ÷ 00B4 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] +× 200D × 000B ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] +× 200D × 0020 × 000B ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] +× 200D × 0308 × 000B ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] +× 200D × 0308 × 0020 × 000B ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] +× 200D ÷ FFFC ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] +× 200D × 0020 ÷ FFFC ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] +× 200D × 0308 ÷ FFFC ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] +× 200D × 0308 × 0020 ÷ FFFC ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] +× 200D × 007D ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [13.04] RIGHT CURLY BRACKET (CL) ÷ [0.3] +× 200D × 0020 × 007D ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] +× 200D × 0308 × 007D ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.04] RIGHT CURLY BRACKET (CL) ÷ [0.3] +× 200D × 0308 × 0020 × 007D ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] +× 200D × 0029 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [13.04] RIGHT PARENTHESIS (CP) ÷ [0.3] +× 200D × 0020 × 0029 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] +× 200D × 0308 × 0029 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.04] RIGHT PARENTHESIS (CP) ÷ [0.3] +× 200D × 0308 × 0020 × 0029 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] +× 200D × 000D ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +× 200D × 0020 × 000D ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +× 200D × 0308 × 000D ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +× 200D × 0308 × 0020 × 000D ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +× 200D × 0021 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] +× 200D × 0020 × 0021 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] +× 200D × 0308 × 0021 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] +× 200D × 0308 × 0020 × 0021 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] +× 200D × 00A0 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [12.3] NO-BREAK SPACE (GL) ÷ [0.3] +× 200D × 0020 ÷ 00A0 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] +× 200D × 0308 × 00A0 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [12.3] NO-BREAK SPACE (GL) ÷ [0.3] +× 200D × 0308 × 0020 ÷ 00A0 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] +× 200D ÷ AC00 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [999.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] +× 200D × 0020 ÷ AC00 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] +× 200D × 0308 ÷ AC00 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] +× 200D × 0308 × 0020 ÷ AC00 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] +× 200D ÷ AC01 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [999.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] +× 200D × 0020 ÷ AC01 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] +× 200D × 0308 ÷ AC01 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] +× 200D × 0308 × 0020 ÷ AC01 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] +× 200D × 05D0 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [28.0] HEBREW LETTER ALEF (HL) ÷ [0.3] +× 200D × 0020 ÷ 05D0 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] +× 200D × 0308 × 05D0 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [28.0] HEBREW LETTER ALEF (HL) ÷ [0.3] +× 200D × 0308 × 0020 ÷ 05D0 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] +× 200D × 002D ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] +× 200D × 0020 ÷ 002D ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] +× 200D × 0308 × 002D ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] +× 200D × 0308 × 0020 ÷ 002D ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] +× 200D × 231A ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] WATCH (ID) ÷ [0.3] +× 200D × 0020 ÷ 231A ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] +× 200D × 0308 ÷ 231A ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] WATCH (ID) ÷ [0.3] +× 200D × 0308 × 0020 ÷ 231A ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] +× 200D × 2024 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [22.01] ONE DOT LEADER (IN) ÷ [0.3] +× 200D × 0020 ÷ 2024 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] +× 200D × 0308 × 2024 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [22.01] ONE DOT LEADER (IN) ÷ [0.3] +× 200D × 0308 × 0020 ÷ 2024 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] +× 200D × 002C ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [13.04] COMMA (IS) ÷ [0.3] +× 200D × 0020 × 002C ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] +× 200D × 0308 × 002C ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.04] COMMA (IS) ÷ [0.3] +× 200D × 0308 × 0020 × 002C ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] +× 200D ÷ 1100 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [999.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] +× 200D × 0020 ÷ 1100 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] +× 200D × 0308 ÷ 1100 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] +× 200D × 0308 × 0020 ÷ 1100 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] +× 200D ÷ 11A8 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [999.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] +× 200D × 0020 ÷ 11A8 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] +× 200D × 0308 ÷ 11A8 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] +× 200D × 0308 × 0020 ÷ 11A8 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] +× 200D ÷ 1160 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [999.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] +× 200D × 0020 ÷ 1160 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] +× 200D × 0308 ÷ 1160 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] +× 200D × 0308 × 0020 ÷ 1160 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] +× 200D × 000A ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] +× 200D × 0020 × 000A ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] +× 200D × 0308 × 000A ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] +× 200D × 0308 × 0020 × 000A ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] +× 200D × 0085 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] +× 200D × 0020 × 0085 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] +× 200D × 0308 × 0085 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] +× 200D × 0308 × 0020 × 0085 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] +× 200D × 17D6 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] +× 200D × 0020 ÷ 17D6 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] +× 200D × 0308 × 17D6 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] +× 200D × 0308 × 0020 ÷ 17D6 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] +× 200D × 0030 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [23.02] DIGIT ZERO (NU) ÷ [0.3] +× 200D × 0020 ÷ 0030 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] +× 200D × 0308 × 0030 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [23.02] DIGIT ZERO (NU) ÷ [0.3] +× 200D × 0308 × 0020 ÷ 0030 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] +× 200D × 0028 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [30.01] LEFT PARENTHESIS (OP) ÷ [0.3] +× 200D × 0020 ÷ 0028 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] +× 200D × 0308 × 0028 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [30.01] LEFT PARENTHESIS (OP) ÷ [0.3] +× 200D × 0308 × 0020 ÷ 0028 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] +× 200D × 0025 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [24.03] PERCENT SIGN (PO) ÷ [0.3] +× 200D × 0020 ÷ 0025 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] +× 200D × 0308 × 0025 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [24.03] PERCENT SIGN (PO) ÷ [0.3] +× 200D × 0308 × 0020 ÷ 0025 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] +× 200D × 0024 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [24.03] DOLLAR SIGN (PR) ÷ [0.3] +× 200D × 0020 ÷ 0024 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] +× 200D × 0308 × 0024 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [24.03] DOLLAR SIGN (PR) ÷ [0.3] +× 200D × 0308 × 0020 ÷ 0024 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] +× 200D × 0022 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [19.01] QUOTATION MARK (QU) ÷ [0.3] +× 200D × 0020 ÷ 0022 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] +× 200D × 0308 × 0022 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [19.01] QUOTATION MARK (QU) ÷ [0.3] +× 200D × 0308 × 0020 ÷ 0022 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] +× 200D × 0020 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) ÷ [0.3] +× 200D × 0020 × 0020 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] +× 200D × 0308 × 0020 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [0.3] +× 200D × 0308 × 0020 × 0020 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] +× 200D × 002F ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [13.04] SOLIDUS (SY) ÷ [0.3] +× 200D × 0020 × 002F ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] +× 200D × 0308 × 002F ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.04] SOLIDUS (SY) ÷ [0.3] +× 200D × 0308 × 0020 × 002F ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] +× 200D × 2060 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [11.01] WORD JOINER (WJ) ÷ [0.3] +× 200D × 0020 × 2060 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] +× 200D × 0308 × 2060 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [11.01] WORD JOINER (WJ) ÷ [0.3] +× 200D × 0308 × 0020 × 2060 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] +× 200D × 200B ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] +× 200D × 0020 × 200B ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] +× 200D × 0308 × 200B ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] +× 200D × 0308 × 0020 × 200B ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] +× 200D ÷ 1F1E6 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 200D × 0020 ÷ 1F1E6 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 200D × 0308 ÷ 1F1E6 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 200D × 0308 × 0020 ÷ 1F1E6 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 200D × 261D ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 200D × 0020 ÷ 261D ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) ÷ [18.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 200D × 0308 ÷ 261D ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 200D × 0308 × 0020 ÷ 261D ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 200D × 1F3FB ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 200D × 0020 ÷ 1F3FB ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) ÷ [18.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 200D × 0308 ÷ 1F3FB ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 200D × 0308 × 0020 ÷ 1F3FB ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 200D × 0001 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 200D × 0020 ÷ 0001 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 200D × 0308 × 0001 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [9.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 200D × 0308 × 0020 ÷ 0001 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 200D × 200D ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 200D × 0020 ÷ 200D ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) ÷ [18.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 200D × 0308 × 200D ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [9.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 200D × 0308 × 0020 ÷ 200D ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 200D × 00A7 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [28.0] SECTION SIGN (AI_AL) ÷ [0.3] +× 200D × 0020 ÷ 00A7 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] +× 200D × 0308 × 00A7 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [28.0] SECTION SIGN (AI_AL) ÷ [0.3] +× 200D × 0308 × 0020 ÷ 00A7 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] +× 200D × 50005 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [28.0] <reserved-50005> (XX_AL) ÷ [0.3] +× 200D × 0020 ÷ 50005 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] +× 200D × 0308 × 50005 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [28.0] <reserved-50005> (XX_AL) ÷ [0.3] +× 200D × 0308 × 0020 ÷ 50005 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] +× 200D × 0E01 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [28.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] +× 200D × 0020 ÷ 0E01 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] +× 200D × 0308 × 0E01 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [28.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] +× 200D × 0308 × 0020 ÷ 0E01 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] +× 200D × 3041 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] +× 200D × 0020 ÷ 3041 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] +× 200D × 0308 × 3041 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] +× 200D × 0308 × 0020 ÷ 3041 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] × 00A7 × 0023 ÷ # × [0.3] SECTION SIGN (AI_AL) × [28.0] NUMBER SIGN (AL) ÷ [0.3] × 00A7 × 0020 ÷ 0023 ÷ # × [0.3] SECTION SIGN (AI_AL) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] -× 00A7 × 0308 × 0023 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM) × [28.0] NUMBER SIGN (AL) ÷ [0.3] -× 00A7 × 0308 × 0020 ÷ 0023 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] +× 00A7 × 0308 × 0023 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [28.0] NUMBER SIGN (AL) ÷ [0.3] +× 00A7 × 0308 × 0020 ÷ 0023 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] × 00A7 ÷ 2014 ÷ # × [0.3] SECTION SIGN (AI_AL) ÷ [999.0] EM DASH (B2) ÷ [0.3] × 00A7 × 0020 ÷ 2014 ÷ # × [0.3] SECTION SIGN (AI_AL) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] -× 00A7 × 0308 ÷ 2014 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] EM DASH (B2) ÷ [0.3] -× 00A7 × 0308 × 0020 ÷ 2014 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] +× 00A7 × 0308 ÷ 2014 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] EM DASH (B2) ÷ [0.3] +× 00A7 × 0308 × 0020 ÷ 2014 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] × 00A7 × 0009 ÷ # × [0.3] SECTION SIGN (AI_AL) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] × 00A7 × 0020 ÷ 0009 ÷ # × [0.3] SECTION SIGN (AI_AL) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] -× 00A7 × 0308 × 0009 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] -× 00A7 × 0308 × 0020 ÷ 0009 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] +× 00A7 × 0308 × 0009 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] +× 00A7 × 0308 × 0020 ÷ 0009 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] × 00A7 ÷ 00B4 ÷ # × [0.3] SECTION SIGN (AI_AL) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3] × 00A7 × 0020 ÷ 00B4 ÷ # × [0.3] SECTION SIGN (AI_AL) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] -× 00A7 × 0308 ÷ 00B4 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3] -× 00A7 × 0308 × 0020 ÷ 00B4 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] +× 00A7 × 0308 ÷ 00B4 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3] +× 00A7 × 0308 × 0020 ÷ 00B4 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] × 00A7 × 000B ÷ # × [0.3] SECTION SIGN (AI_AL) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] × 00A7 × 0020 × 000B ÷ # × [0.3] SECTION SIGN (AI_AL) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] -× 00A7 × 0308 × 000B ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] -× 00A7 × 0308 × 0020 × 000B ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] +× 00A7 × 0308 × 000B ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] +× 00A7 × 0308 × 0020 × 000B ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] × 00A7 ÷ FFFC ÷ # × [0.3] SECTION SIGN (AI_AL) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] × 00A7 × 0020 ÷ FFFC ÷ # × [0.3] SECTION SIGN (AI_AL) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] -× 00A7 × 0308 ÷ FFFC ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] -× 00A7 × 0308 × 0020 ÷ FFFC ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] +× 00A7 × 0308 ÷ FFFC ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] +× 00A7 × 0308 × 0020 ÷ FFFC ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] × 00A7 × 007D ÷ # × [0.3] SECTION SIGN (AI_AL) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] × 00A7 × 0020 × 007D ÷ # × [0.3] SECTION SIGN (AI_AL) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] -× 00A7 × 0308 × 007D ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM) × [13.03] RIGHT CURLY BRACKET (CL) ÷ [0.3] -× 00A7 × 0308 × 0020 × 007D ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] +× 00A7 × 0308 × 007D ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] RIGHT CURLY BRACKET (CL) ÷ [0.3] +× 00A7 × 0308 × 0020 × 007D ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] × 00A7 × 0029 ÷ # × [0.3] SECTION SIGN (AI_AL) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] × 00A7 × 0020 × 0029 ÷ # × [0.3] SECTION SIGN (AI_AL) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 00A7 × 0308 × 0029 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM) × [13.03] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 00A7 × 0308 × 0020 × 0029 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 00A7 × 0001 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] <START OF HEADING> (CM) ÷ [0.3] -× 00A7 × 0020 ÷ 0001 ÷ # × [0.3] SECTION SIGN (AI_AL) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM) ÷ [0.3] -× 00A7 × 0308 × 0001 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM) × [9.0] <START OF HEADING> (CM) ÷ [0.3] -× 00A7 × 0308 × 0020 ÷ 0001 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM) ÷ [0.3] +× 00A7 × 0308 × 0029 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] RIGHT PARENTHESIS (CP) ÷ [0.3] +× 00A7 × 0308 × 0020 × 0029 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] × 00A7 × 000D ÷ # × [0.3] SECTION SIGN (AI_AL) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] × 00A7 × 0020 × 000D ÷ # × [0.3] SECTION SIGN (AI_AL) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -× 00A7 × 0308 × 000D ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -× 00A7 × 0308 × 0020 × 000D ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +× 00A7 × 0308 × 000D ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +× 00A7 × 0308 × 0020 × 000D ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] × 00A7 × 0021 ÷ # × [0.3] SECTION SIGN (AI_AL) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] × 00A7 × 0020 × 0021 ÷ # × [0.3] SECTION SIGN (AI_AL) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] -× 00A7 × 0308 × 0021 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] -× 00A7 × 0308 × 0020 × 0021 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] +× 00A7 × 0308 × 0021 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] +× 00A7 × 0308 × 0020 × 0021 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] × 00A7 × 00A0 ÷ # × [0.3] SECTION SIGN (AI_AL) × [12.1] NO-BREAK SPACE (GL) ÷ [0.3] × 00A7 × 0020 ÷ 00A0 ÷ # × [0.3] SECTION SIGN (AI_AL) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] -× 00A7 × 0308 × 00A0 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM) × [12.2] NO-BREAK SPACE (GL) ÷ [0.3] -× 00A7 × 0308 × 0020 ÷ 00A0 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] +× 00A7 × 0308 × 00A0 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [12.2] NO-BREAK SPACE (GL) ÷ [0.3] +× 00A7 × 0308 × 0020 ÷ 00A0 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] × 00A7 ÷ AC00 ÷ # × [0.3] SECTION SIGN (AI_AL) ÷ [999.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] × 00A7 × 0020 ÷ AC00 ÷ # × [0.3] SECTION SIGN (AI_AL) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] -× 00A7 × 0308 ÷ AC00 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] -× 00A7 × 0308 × 0020 ÷ AC00 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] +× 00A7 × 0308 ÷ AC00 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] +× 00A7 × 0308 × 0020 ÷ AC00 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] × 00A7 ÷ AC01 ÷ # × [0.3] SECTION SIGN (AI_AL) ÷ [999.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] × 00A7 × 0020 ÷ AC01 ÷ # × [0.3] SECTION SIGN (AI_AL) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] -× 00A7 × 0308 ÷ AC01 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] -× 00A7 × 0308 × 0020 ÷ AC01 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] +× 00A7 × 0308 ÷ AC01 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] +× 00A7 × 0308 × 0020 ÷ AC01 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] × 00A7 × 05D0 ÷ # × [0.3] SECTION SIGN (AI_AL) × [28.0] HEBREW LETTER ALEF (HL) ÷ [0.3] × 00A7 × 0020 ÷ 05D0 ÷ # × [0.3] SECTION SIGN (AI_AL) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] -× 00A7 × 0308 × 05D0 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM) × [28.0] HEBREW LETTER ALEF (HL) ÷ [0.3] -× 00A7 × 0308 × 0020 ÷ 05D0 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] +× 00A7 × 0308 × 05D0 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [28.0] HEBREW LETTER ALEF (HL) ÷ [0.3] +× 00A7 × 0308 × 0020 ÷ 05D0 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] × 00A7 × 002D ÷ # × [0.3] SECTION SIGN (AI_AL) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] × 00A7 × 0020 ÷ 002D ÷ # × [0.3] SECTION SIGN (AI_AL) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] -× 00A7 × 0308 × 002D ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] -× 00A7 × 0308 × 0020 ÷ 002D ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] +× 00A7 × 0308 × 002D ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] +× 00A7 × 0308 × 0020 ÷ 002D ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] × 00A7 ÷ 231A ÷ # × [0.3] SECTION SIGN (AI_AL) ÷ [999.0] WATCH (ID) ÷ [0.3] × 00A7 × 0020 ÷ 231A ÷ # × [0.3] SECTION SIGN (AI_AL) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] -× 00A7 × 0308 ÷ 231A ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] WATCH (ID) ÷ [0.3] -× 00A7 × 0308 × 0020 ÷ 231A ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] +× 00A7 × 0308 ÷ 231A ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] WATCH (ID) ÷ [0.3] +× 00A7 × 0308 × 0020 ÷ 231A ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] × 00A7 × 2024 ÷ # × [0.3] SECTION SIGN (AI_AL) × [22.01] ONE DOT LEADER (IN) ÷ [0.3] × 00A7 × 0020 ÷ 2024 ÷ # × [0.3] SECTION SIGN (AI_AL) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] -× 00A7 × 0308 × 2024 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM) × [22.01] ONE DOT LEADER (IN) ÷ [0.3] -× 00A7 × 0308 × 0020 ÷ 2024 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] +× 00A7 × 0308 × 2024 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [22.01] ONE DOT LEADER (IN) ÷ [0.3] +× 00A7 × 0308 × 0020 ÷ 2024 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] × 00A7 × 002C ÷ # × [0.3] SECTION SIGN (AI_AL) × [13.02] COMMA (IS) ÷ [0.3] × 00A7 × 0020 × 002C ÷ # × [0.3] SECTION SIGN (AI_AL) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] -× 00A7 × 0308 × 002C ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM) × [13.03] COMMA (IS) ÷ [0.3] -× 00A7 × 0308 × 0020 × 002C ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] +× 00A7 × 0308 × 002C ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] COMMA (IS) ÷ [0.3] +× 00A7 × 0308 × 0020 × 002C ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] × 00A7 ÷ 1100 ÷ # × [0.3] SECTION SIGN (AI_AL) ÷ [999.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] × 00A7 × 0020 ÷ 1100 ÷ # × [0.3] SECTION SIGN (AI_AL) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] -× 00A7 × 0308 ÷ 1100 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] -× 00A7 × 0308 × 0020 ÷ 1100 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] +× 00A7 × 0308 ÷ 1100 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] +× 00A7 × 0308 × 0020 ÷ 1100 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] × 00A7 ÷ 11A8 ÷ # × [0.3] SECTION SIGN (AI_AL) ÷ [999.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] × 00A7 × 0020 ÷ 11A8 ÷ # × [0.3] SECTION SIGN (AI_AL) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] -× 00A7 × 0308 ÷ 11A8 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] -× 00A7 × 0308 × 0020 ÷ 11A8 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] +× 00A7 × 0308 ÷ 11A8 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] +× 00A7 × 0308 × 0020 ÷ 11A8 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] × 00A7 ÷ 1160 ÷ # × [0.3] SECTION SIGN (AI_AL) ÷ [999.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] × 00A7 × 0020 ÷ 1160 ÷ # × [0.3] SECTION SIGN (AI_AL) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] -× 00A7 × 0308 ÷ 1160 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] -× 00A7 × 0308 × 0020 ÷ 1160 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] +× 00A7 × 0308 ÷ 1160 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] +× 00A7 × 0308 × 0020 ÷ 1160 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] × 00A7 × 000A ÷ # × [0.3] SECTION SIGN (AI_AL) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] × 00A7 × 0020 × 000A ÷ # × [0.3] SECTION SIGN (AI_AL) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] -× 00A7 × 0308 × 000A ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] -× 00A7 × 0308 × 0020 × 000A ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] +× 00A7 × 0308 × 000A ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] +× 00A7 × 0308 × 0020 × 000A ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] × 00A7 × 0085 ÷ # × [0.3] SECTION SIGN (AI_AL) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] × 00A7 × 0020 × 0085 ÷ # × [0.3] SECTION SIGN (AI_AL) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] -× 00A7 × 0308 × 0085 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] -× 00A7 × 0308 × 0020 × 0085 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] +× 00A7 × 0308 × 0085 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] +× 00A7 × 0308 × 0020 × 0085 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] × 00A7 × 17D6 ÷ # × [0.3] SECTION SIGN (AI_AL) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] × 00A7 × 0020 ÷ 17D6 ÷ # × [0.3] SECTION SIGN (AI_AL) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] -× 00A7 × 0308 × 17D6 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] -× 00A7 × 0308 × 0020 ÷ 17D6 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] +× 00A7 × 0308 × 17D6 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] +× 00A7 × 0308 × 0020 ÷ 17D6 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] × 00A7 × 0030 ÷ # × [0.3] SECTION SIGN (AI_AL) × [23.02] DIGIT ZERO (NU) ÷ [0.3] × 00A7 × 0020 ÷ 0030 ÷ # × [0.3] SECTION SIGN (AI_AL) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] -× 00A7 × 0308 × 0030 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM) × [23.02] DIGIT ZERO (NU) ÷ [0.3] -× 00A7 × 0308 × 0020 ÷ 0030 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] +× 00A7 × 0308 × 0030 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [23.02] DIGIT ZERO (NU) ÷ [0.3] +× 00A7 × 0308 × 0020 ÷ 0030 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] × 00A7 × 0028 ÷ # × [0.3] SECTION SIGN (AI_AL) × [30.01] LEFT PARENTHESIS (OP) ÷ [0.3] × 00A7 × 0020 ÷ 0028 ÷ # × [0.3] SECTION SIGN (AI_AL) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] -× 00A7 × 0308 × 0028 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM) × [30.01] LEFT PARENTHESIS (OP) ÷ [0.3] -× 00A7 × 0308 × 0020 ÷ 0028 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] -× 00A7 ÷ 0025 ÷ # × [0.3] SECTION SIGN (AI_AL) ÷ [999.0] PERCENT SIGN (PO) ÷ [0.3] +× 00A7 × 0308 × 0028 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [30.01] LEFT PARENTHESIS (OP) ÷ [0.3] +× 00A7 × 0308 × 0020 ÷ 0028 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] +× 00A7 × 0025 ÷ # × [0.3] SECTION SIGN (AI_AL) × [24.03] PERCENT SIGN (PO) ÷ [0.3] × 00A7 × 0020 ÷ 0025 ÷ # × [0.3] SECTION SIGN (AI_AL) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] -× 00A7 × 0308 ÷ 0025 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] PERCENT SIGN (PO) ÷ [0.3] -× 00A7 × 0308 × 0020 ÷ 0025 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] -× 00A7 ÷ 0024 ÷ # × [0.3] SECTION SIGN (AI_AL) ÷ [999.0] DOLLAR SIGN (PR) ÷ [0.3] +× 00A7 × 0308 × 0025 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [24.03] PERCENT SIGN (PO) ÷ [0.3] +× 00A7 × 0308 × 0020 ÷ 0025 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] +× 00A7 × 0024 ÷ # × [0.3] SECTION SIGN (AI_AL) × [24.03] DOLLAR SIGN (PR) ÷ [0.3] × 00A7 × 0020 ÷ 0024 ÷ # × [0.3] SECTION SIGN (AI_AL) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] -× 00A7 × 0308 ÷ 0024 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] DOLLAR SIGN (PR) ÷ [0.3] -× 00A7 × 0308 × 0020 ÷ 0024 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] +× 00A7 × 0308 × 0024 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [24.03] DOLLAR SIGN (PR) ÷ [0.3] +× 00A7 × 0308 × 0020 ÷ 0024 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] × 00A7 × 0022 ÷ # × [0.3] SECTION SIGN (AI_AL) × [19.01] QUOTATION MARK (QU) ÷ [0.3] × 00A7 × 0020 ÷ 0022 ÷ # × [0.3] SECTION SIGN (AI_AL) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] -× 00A7 × 0308 × 0022 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM) × [19.01] QUOTATION MARK (QU) ÷ [0.3] -× 00A7 × 0308 × 0020 ÷ 0022 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] +× 00A7 × 0308 × 0022 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [19.01] QUOTATION MARK (QU) ÷ [0.3] +× 00A7 × 0308 × 0020 ÷ 0022 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] × 00A7 × 0020 ÷ # × [0.3] SECTION SIGN (AI_AL) × [7.01] SPACE (SP) ÷ [0.3] × 00A7 × 0020 × 0020 ÷ # × [0.3] SECTION SIGN (AI_AL) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] -× 00A7 × 0308 × 0020 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [0.3] -× 00A7 × 0308 × 0020 × 0020 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] +× 00A7 × 0308 × 0020 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [0.3] +× 00A7 × 0308 × 0020 × 0020 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] × 00A7 × 002F ÷ # × [0.3] SECTION SIGN (AI_AL) × [13.02] SOLIDUS (SY) ÷ [0.3] × 00A7 × 0020 × 002F ÷ # × [0.3] SECTION SIGN (AI_AL) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] -× 00A7 × 0308 × 002F ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM) × [13.03] SOLIDUS (SY) ÷ [0.3] -× 00A7 × 0308 × 0020 × 002F ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] +× 00A7 × 0308 × 002F ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] SOLIDUS (SY) ÷ [0.3] +× 00A7 × 0308 × 0020 × 002F ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] × 00A7 × 2060 ÷ # × [0.3] SECTION SIGN (AI_AL) × [11.01] WORD JOINER (WJ) ÷ [0.3] × 00A7 × 0020 × 2060 ÷ # × [0.3] SECTION SIGN (AI_AL) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] -× 00A7 × 0308 × 2060 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM) × [11.01] WORD JOINER (WJ) ÷ [0.3] -× 00A7 × 0308 × 0020 × 2060 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] +× 00A7 × 0308 × 2060 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [11.01] WORD JOINER (WJ) ÷ [0.3] +× 00A7 × 0308 × 0020 × 2060 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] × 00A7 × 200B ÷ # × [0.3] SECTION SIGN (AI_AL) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] × 00A7 × 0020 × 200B ÷ # × [0.3] SECTION SIGN (AI_AL) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] -× 00A7 × 0308 × 200B ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] -× 00A7 × 0308 × 0020 × 200B ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] +× 00A7 × 0308 × 200B ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] +× 00A7 × 0308 × 0020 × 200B ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] × 00A7 ÷ 1F1E6 ÷ # × [0.3] SECTION SIGN (AI_AL) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] × 00A7 × 0020 ÷ 1F1E6 ÷ # × [0.3] SECTION SIGN (AI_AL) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -× 00A7 × 0308 ÷ 1F1E6 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -× 00A7 × 0308 × 0020 ÷ 1F1E6 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 00A7 × 0308 ÷ 1F1E6 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 00A7 × 0308 × 0020 ÷ 1F1E6 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 00A7 ÷ 261D ÷ # × [0.3] SECTION SIGN (AI_AL) ÷ [999.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 00A7 × 0020 ÷ 261D ÷ # × [0.3] SECTION SIGN (AI_AL) × [7.01] SPACE (SP) ÷ [18.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 00A7 × 0308 ÷ 261D ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 00A7 × 0308 × 0020 ÷ 261D ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 00A7 ÷ 1F3FB ÷ # × [0.3] SECTION SIGN (AI_AL) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 00A7 × 0020 ÷ 1F3FB ÷ # × [0.3] SECTION SIGN (AI_AL) × [7.01] SPACE (SP) ÷ [18.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 00A7 × 0308 ÷ 1F3FB ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 00A7 × 0308 × 0020 ÷ 1F3FB ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 00A7 × 0001 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 00A7 × 0020 ÷ 0001 ÷ # × [0.3] SECTION SIGN (AI_AL) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 00A7 × 0308 × 0001 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [9.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 00A7 × 0308 × 0020 ÷ 0001 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 00A7 × 200D ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 00A7 × 0020 ÷ 200D ÷ # × [0.3] SECTION SIGN (AI_AL) × [7.01] SPACE (SP) ÷ [18.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 00A7 × 0308 × 200D ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [9.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 00A7 × 0308 × 0020 ÷ 200D ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] × 00A7 × 00A7 ÷ # × [0.3] SECTION SIGN (AI_AL) × [28.0] SECTION SIGN (AI_AL) ÷ [0.3] × 00A7 × 0020 ÷ 00A7 ÷ # × [0.3] SECTION SIGN (AI_AL) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] -× 00A7 × 0308 × 00A7 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM) × [28.0] SECTION SIGN (AI_AL) ÷ [0.3] -× 00A7 × 0308 × 0020 ÷ 00A7 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] +× 00A7 × 0308 × 00A7 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [28.0] SECTION SIGN (AI_AL) ÷ [0.3] +× 00A7 × 0308 × 0020 ÷ 00A7 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] × 00A7 × 50005 ÷ # × [0.3] SECTION SIGN (AI_AL) × [28.0] <reserved-50005> (XX_AL) ÷ [0.3] × 00A7 × 0020 ÷ 50005 ÷ # × [0.3] SECTION SIGN (AI_AL) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] -× 00A7 × 0308 × 50005 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM) × [28.0] <reserved-50005> (XX_AL) ÷ [0.3] -× 00A7 × 0308 × 0020 ÷ 50005 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] +× 00A7 × 0308 × 50005 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [28.0] <reserved-50005> (XX_AL) ÷ [0.3] +× 00A7 × 0308 × 0020 ÷ 50005 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] × 00A7 × 0E01 ÷ # × [0.3] SECTION SIGN (AI_AL) × [28.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] × 00A7 × 0020 ÷ 0E01 ÷ # × [0.3] SECTION SIGN (AI_AL) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] -× 00A7 × 0308 × 0E01 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM) × [28.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] -× 00A7 × 0308 × 0020 ÷ 0E01 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] +× 00A7 × 0308 × 0E01 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [28.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] +× 00A7 × 0308 × 0020 ÷ 0E01 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] × 00A7 × 3041 ÷ # × [0.3] SECTION SIGN (AI_AL) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] × 00A7 × 0020 ÷ 3041 ÷ # × [0.3] SECTION SIGN (AI_AL) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] -× 00A7 × 0308 × 3041 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] -× 00A7 × 0308 × 0020 ÷ 3041 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] +× 00A7 × 0308 × 3041 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] +× 00A7 × 0308 × 0020 ÷ 3041 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] × 50005 × 0023 ÷ # × [0.3] <reserved-50005> (XX_AL) × [28.0] NUMBER SIGN (AL) ÷ [0.3] × 50005 × 0020 ÷ 0023 ÷ # × [0.3] <reserved-50005> (XX_AL) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] -× 50005 × 0308 × 0023 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM) × [28.0] NUMBER SIGN (AL) ÷ [0.3] -× 50005 × 0308 × 0020 ÷ 0023 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] +× 50005 × 0308 × 0023 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [28.0] NUMBER SIGN (AL) ÷ [0.3] +× 50005 × 0308 × 0020 ÷ 0023 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] × 50005 ÷ 2014 ÷ # × [0.3] <reserved-50005> (XX_AL) ÷ [999.0] EM DASH (B2) ÷ [0.3] × 50005 × 0020 ÷ 2014 ÷ # × [0.3] <reserved-50005> (XX_AL) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] -× 50005 × 0308 ÷ 2014 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] EM DASH (B2) ÷ [0.3] -× 50005 × 0308 × 0020 ÷ 2014 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] +× 50005 × 0308 ÷ 2014 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] EM DASH (B2) ÷ [0.3] +× 50005 × 0308 × 0020 ÷ 2014 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] × 50005 × 0009 ÷ # × [0.3] <reserved-50005> (XX_AL) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] × 50005 × 0020 ÷ 0009 ÷ # × [0.3] <reserved-50005> (XX_AL) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] -× 50005 × 0308 × 0009 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] -× 50005 × 0308 × 0020 ÷ 0009 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] +× 50005 × 0308 × 0009 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] +× 50005 × 0308 × 0020 ÷ 0009 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] × 50005 ÷ 00B4 ÷ # × [0.3] <reserved-50005> (XX_AL) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3] × 50005 × 0020 ÷ 00B4 ÷ # × [0.3] <reserved-50005> (XX_AL) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] -× 50005 × 0308 ÷ 00B4 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3] -× 50005 × 0308 × 0020 ÷ 00B4 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] +× 50005 × 0308 ÷ 00B4 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3] +× 50005 × 0308 × 0020 ÷ 00B4 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] × 50005 × 000B ÷ # × [0.3] <reserved-50005> (XX_AL) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] × 50005 × 0020 × 000B ÷ # × [0.3] <reserved-50005> (XX_AL) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] -× 50005 × 0308 × 000B ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] -× 50005 × 0308 × 0020 × 000B ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] +× 50005 × 0308 × 000B ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] +× 50005 × 0308 × 0020 × 000B ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] × 50005 ÷ FFFC ÷ # × [0.3] <reserved-50005> (XX_AL) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] × 50005 × 0020 ÷ FFFC ÷ # × [0.3] <reserved-50005> (XX_AL) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] -× 50005 × 0308 ÷ FFFC ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] -× 50005 × 0308 × 0020 ÷ FFFC ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] +× 50005 × 0308 ÷ FFFC ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] +× 50005 × 0308 × 0020 ÷ FFFC ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] × 50005 × 007D ÷ # × [0.3] <reserved-50005> (XX_AL) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] × 50005 × 0020 × 007D ÷ # × [0.3] <reserved-50005> (XX_AL) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] -× 50005 × 0308 × 007D ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM) × [13.03] RIGHT CURLY BRACKET (CL) ÷ [0.3] -× 50005 × 0308 × 0020 × 007D ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] +× 50005 × 0308 × 007D ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] RIGHT CURLY BRACKET (CL) ÷ [0.3] +× 50005 × 0308 × 0020 × 007D ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] × 50005 × 0029 ÷ # × [0.3] <reserved-50005> (XX_AL) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] × 50005 × 0020 × 0029 ÷ # × [0.3] <reserved-50005> (XX_AL) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 50005 × 0308 × 0029 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM) × [13.03] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 50005 × 0308 × 0020 × 0029 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 50005 × 0001 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] <START OF HEADING> (CM) ÷ [0.3] -× 50005 × 0020 ÷ 0001 ÷ # × [0.3] <reserved-50005> (XX_AL) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM) ÷ [0.3] -× 50005 × 0308 × 0001 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM) × [9.0] <START OF HEADING> (CM) ÷ [0.3] -× 50005 × 0308 × 0020 ÷ 0001 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM) ÷ [0.3] +× 50005 × 0308 × 0029 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] RIGHT PARENTHESIS (CP) ÷ [0.3] +× 50005 × 0308 × 0020 × 0029 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] × 50005 × 000D ÷ # × [0.3] <reserved-50005> (XX_AL) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] × 50005 × 0020 × 000D ÷ # × [0.3] <reserved-50005> (XX_AL) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -× 50005 × 0308 × 000D ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -× 50005 × 0308 × 0020 × 000D ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +× 50005 × 0308 × 000D ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +× 50005 × 0308 × 0020 × 000D ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] × 50005 × 0021 ÷ # × [0.3] <reserved-50005> (XX_AL) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] × 50005 × 0020 × 0021 ÷ # × [0.3] <reserved-50005> (XX_AL) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] -× 50005 × 0308 × 0021 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] -× 50005 × 0308 × 0020 × 0021 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] +× 50005 × 0308 × 0021 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] +× 50005 × 0308 × 0020 × 0021 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] × 50005 × 00A0 ÷ # × [0.3] <reserved-50005> (XX_AL) × [12.1] NO-BREAK SPACE (GL) ÷ [0.3] × 50005 × 0020 ÷ 00A0 ÷ # × [0.3] <reserved-50005> (XX_AL) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] -× 50005 × 0308 × 00A0 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM) × [12.2] NO-BREAK SPACE (GL) ÷ [0.3] -× 50005 × 0308 × 0020 ÷ 00A0 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] +× 50005 × 0308 × 00A0 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [12.2] NO-BREAK SPACE (GL) ÷ [0.3] +× 50005 × 0308 × 0020 ÷ 00A0 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] × 50005 ÷ AC00 ÷ # × [0.3] <reserved-50005> (XX_AL) ÷ [999.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] × 50005 × 0020 ÷ AC00 ÷ # × [0.3] <reserved-50005> (XX_AL) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] -× 50005 × 0308 ÷ AC00 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] -× 50005 × 0308 × 0020 ÷ AC00 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] +× 50005 × 0308 ÷ AC00 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] +× 50005 × 0308 × 0020 ÷ AC00 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] × 50005 ÷ AC01 ÷ # × [0.3] <reserved-50005> (XX_AL) ÷ [999.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] × 50005 × 0020 ÷ AC01 ÷ # × [0.3] <reserved-50005> (XX_AL) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] -× 50005 × 0308 ÷ AC01 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] -× 50005 × 0308 × 0020 ÷ AC01 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] +× 50005 × 0308 ÷ AC01 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] +× 50005 × 0308 × 0020 ÷ AC01 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] × 50005 × 05D0 ÷ # × [0.3] <reserved-50005> (XX_AL) × [28.0] HEBREW LETTER ALEF (HL) ÷ [0.3] × 50005 × 0020 ÷ 05D0 ÷ # × [0.3] <reserved-50005> (XX_AL) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] -× 50005 × 0308 × 05D0 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM) × [28.0] HEBREW LETTER ALEF (HL) ÷ [0.3] -× 50005 × 0308 × 0020 ÷ 05D0 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] +× 50005 × 0308 × 05D0 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [28.0] HEBREW LETTER ALEF (HL) ÷ [0.3] +× 50005 × 0308 × 0020 ÷ 05D0 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] × 50005 × 002D ÷ # × [0.3] <reserved-50005> (XX_AL) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] × 50005 × 0020 ÷ 002D ÷ # × [0.3] <reserved-50005> (XX_AL) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] -× 50005 × 0308 × 002D ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] -× 50005 × 0308 × 0020 ÷ 002D ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] +× 50005 × 0308 × 002D ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] +× 50005 × 0308 × 0020 ÷ 002D ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] × 50005 ÷ 231A ÷ # × [0.3] <reserved-50005> (XX_AL) ÷ [999.0] WATCH (ID) ÷ [0.3] × 50005 × 0020 ÷ 231A ÷ # × [0.3] <reserved-50005> (XX_AL) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] -× 50005 × 0308 ÷ 231A ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] WATCH (ID) ÷ [0.3] -× 50005 × 0308 × 0020 ÷ 231A ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] +× 50005 × 0308 ÷ 231A ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] WATCH (ID) ÷ [0.3] +× 50005 × 0308 × 0020 ÷ 231A ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] × 50005 × 2024 ÷ # × [0.3] <reserved-50005> (XX_AL) × [22.01] ONE DOT LEADER (IN) ÷ [0.3] × 50005 × 0020 ÷ 2024 ÷ # × [0.3] <reserved-50005> (XX_AL) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] -× 50005 × 0308 × 2024 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM) × [22.01] ONE DOT LEADER (IN) ÷ [0.3] -× 50005 × 0308 × 0020 ÷ 2024 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] +× 50005 × 0308 × 2024 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [22.01] ONE DOT LEADER (IN) ÷ [0.3] +× 50005 × 0308 × 0020 ÷ 2024 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] × 50005 × 002C ÷ # × [0.3] <reserved-50005> (XX_AL) × [13.02] COMMA (IS) ÷ [0.3] × 50005 × 0020 × 002C ÷ # × [0.3] <reserved-50005> (XX_AL) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] -× 50005 × 0308 × 002C ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM) × [13.03] COMMA (IS) ÷ [0.3] -× 50005 × 0308 × 0020 × 002C ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] +× 50005 × 0308 × 002C ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] COMMA (IS) ÷ [0.3] +× 50005 × 0308 × 0020 × 002C ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] × 50005 ÷ 1100 ÷ # × [0.3] <reserved-50005> (XX_AL) ÷ [999.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] × 50005 × 0020 ÷ 1100 ÷ # × [0.3] <reserved-50005> (XX_AL) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] -× 50005 × 0308 ÷ 1100 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] -× 50005 × 0308 × 0020 ÷ 1100 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] +× 50005 × 0308 ÷ 1100 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] +× 50005 × 0308 × 0020 ÷ 1100 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] × 50005 ÷ 11A8 ÷ # × [0.3] <reserved-50005> (XX_AL) ÷ [999.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] × 50005 × 0020 ÷ 11A8 ÷ # × [0.3] <reserved-50005> (XX_AL) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] -× 50005 × 0308 ÷ 11A8 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] -× 50005 × 0308 × 0020 ÷ 11A8 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] +× 50005 × 0308 ÷ 11A8 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] +× 50005 × 0308 × 0020 ÷ 11A8 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] × 50005 ÷ 1160 ÷ # × [0.3] <reserved-50005> (XX_AL) ÷ [999.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] × 50005 × 0020 ÷ 1160 ÷ # × [0.3] <reserved-50005> (XX_AL) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] -× 50005 × 0308 ÷ 1160 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] -× 50005 × 0308 × 0020 ÷ 1160 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] +× 50005 × 0308 ÷ 1160 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] +× 50005 × 0308 × 0020 ÷ 1160 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] × 50005 × 000A ÷ # × [0.3] <reserved-50005> (XX_AL) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] × 50005 × 0020 × 000A ÷ # × [0.3] <reserved-50005> (XX_AL) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] -× 50005 × 0308 × 000A ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] -× 50005 × 0308 × 0020 × 000A ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] +× 50005 × 0308 × 000A ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] +× 50005 × 0308 × 0020 × 000A ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] × 50005 × 0085 ÷ # × [0.3] <reserved-50005> (XX_AL) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] × 50005 × 0020 × 0085 ÷ # × [0.3] <reserved-50005> (XX_AL) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] -× 50005 × 0308 × 0085 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] -× 50005 × 0308 × 0020 × 0085 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] +× 50005 × 0308 × 0085 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] +× 50005 × 0308 × 0020 × 0085 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] × 50005 × 17D6 ÷ # × [0.3] <reserved-50005> (XX_AL) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] × 50005 × 0020 ÷ 17D6 ÷ # × [0.3] <reserved-50005> (XX_AL) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] -× 50005 × 0308 × 17D6 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] -× 50005 × 0308 × 0020 ÷ 17D6 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] +× 50005 × 0308 × 17D6 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] +× 50005 × 0308 × 0020 ÷ 17D6 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] × 50005 × 0030 ÷ # × [0.3] <reserved-50005> (XX_AL) × [23.02] DIGIT ZERO (NU) ÷ [0.3] × 50005 × 0020 ÷ 0030 ÷ # × [0.3] <reserved-50005> (XX_AL) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] -× 50005 × 0308 × 0030 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM) × [23.02] DIGIT ZERO (NU) ÷ [0.3] -× 50005 × 0308 × 0020 ÷ 0030 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] +× 50005 × 0308 × 0030 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [23.02] DIGIT ZERO (NU) ÷ [0.3] +× 50005 × 0308 × 0020 ÷ 0030 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] × 50005 × 0028 ÷ # × [0.3] <reserved-50005> (XX_AL) × [30.01] LEFT PARENTHESIS (OP) ÷ [0.3] × 50005 × 0020 ÷ 0028 ÷ # × [0.3] <reserved-50005> (XX_AL) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] -× 50005 × 0308 × 0028 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM) × [30.01] LEFT PARENTHESIS (OP) ÷ [0.3] -× 50005 × 0308 × 0020 ÷ 0028 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] -× 50005 ÷ 0025 ÷ # × [0.3] <reserved-50005> (XX_AL) ÷ [999.0] PERCENT SIGN (PO) ÷ [0.3] +× 50005 × 0308 × 0028 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [30.01] LEFT PARENTHESIS (OP) ÷ [0.3] +× 50005 × 0308 × 0020 ÷ 0028 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] +× 50005 × 0025 ÷ # × [0.3] <reserved-50005> (XX_AL) × [24.03] PERCENT SIGN (PO) ÷ [0.3] × 50005 × 0020 ÷ 0025 ÷ # × [0.3] <reserved-50005> (XX_AL) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] -× 50005 × 0308 ÷ 0025 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] PERCENT SIGN (PO) ÷ [0.3] -× 50005 × 0308 × 0020 ÷ 0025 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] -× 50005 ÷ 0024 ÷ # × [0.3] <reserved-50005> (XX_AL) ÷ [999.0] DOLLAR SIGN (PR) ÷ [0.3] +× 50005 × 0308 × 0025 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [24.03] PERCENT SIGN (PO) ÷ [0.3] +× 50005 × 0308 × 0020 ÷ 0025 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] +× 50005 × 0024 ÷ # × [0.3] <reserved-50005> (XX_AL) × [24.03] DOLLAR SIGN (PR) ÷ [0.3] × 50005 × 0020 ÷ 0024 ÷ # × [0.3] <reserved-50005> (XX_AL) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] -× 50005 × 0308 ÷ 0024 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] DOLLAR SIGN (PR) ÷ [0.3] -× 50005 × 0308 × 0020 ÷ 0024 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] +× 50005 × 0308 × 0024 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [24.03] DOLLAR SIGN (PR) ÷ [0.3] +× 50005 × 0308 × 0020 ÷ 0024 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] × 50005 × 0022 ÷ # × [0.3] <reserved-50005> (XX_AL) × [19.01] QUOTATION MARK (QU) ÷ [0.3] × 50005 × 0020 ÷ 0022 ÷ # × [0.3] <reserved-50005> (XX_AL) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] -× 50005 × 0308 × 0022 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM) × [19.01] QUOTATION MARK (QU) ÷ [0.3] -× 50005 × 0308 × 0020 ÷ 0022 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] +× 50005 × 0308 × 0022 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [19.01] QUOTATION MARK (QU) ÷ [0.3] +× 50005 × 0308 × 0020 ÷ 0022 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] × 50005 × 0020 ÷ # × [0.3] <reserved-50005> (XX_AL) × [7.01] SPACE (SP) ÷ [0.3] × 50005 × 0020 × 0020 ÷ # × [0.3] <reserved-50005> (XX_AL) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] -× 50005 × 0308 × 0020 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [0.3] -× 50005 × 0308 × 0020 × 0020 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] +× 50005 × 0308 × 0020 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [0.3] +× 50005 × 0308 × 0020 × 0020 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] × 50005 × 002F ÷ # × [0.3] <reserved-50005> (XX_AL) × [13.02] SOLIDUS (SY) ÷ [0.3] × 50005 × 0020 × 002F ÷ # × [0.3] <reserved-50005> (XX_AL) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] -× 50005 × 0308 × 002F ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM) × [13.03] SOLIDUS (SY) ÷ [0.3] -× 50005 × 0308 × 0020 × 002F ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] +× 50005 × 0308 × 002F ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] SOLIDUS (SY) ÷ [0.3] +× 50005 × 0308 × 0020 × 002F ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] × 50005 × 2060 ÷ # × [0.3] <reserved-50005> (XX_AL) × [11.01] WORD JOINER (WJ) ÷ [0.3] × 50005 × 0020 × 2060 ÷ # × [0.3] <reserved-50005> (XX_AL) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] -× 50005 × 0308 × 2060 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM) × [11.01] WORD JOINER (WJ) ÷ [0.3] -× 50005 × 0308 × 0020 × 2060 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] +× 50005 × 0308 × 2060 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [11.01] WORD JOINER (WJ) ÷ [0.3] +× 50005 × 0308 × 0020 × 2060 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] × 50005 × 200B ÷ # × [0.3] <reserved-50005> (XX_AL) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] × 50005 × 0020 × 200B ÷ # × [0.3] <reserved-50005> (XX_AL) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] -× 50005 × 0308 × 200B ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] -× 50005 × 0308 × 0020 × 200B ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] +× 50005 × 0308 × 200B ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] +× 50005 × 0308 × 0020 × 200B ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] × 50005 ÷ 1F1E6 ÷ # × [0.3] <reserved-50005> (XX_AL) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] × 50005 × 0020 ÷ 1F1E6 ÷ # × [0.3] <reserved-50005> (XX_AL) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -× 50005 × 0308 ÷ 1F1E6 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -× 50005 × 0308 × 0020 ÷ 1F1E6 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 50005 × 0308 ÷ 1F1E6 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 50005 × 0308 × 0020 ÷ 1F1E6 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 50005 ÷ 261D ÷ # × [0.3] <reserved-50005> (XX_AL) ÷ [999.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 50005 × 0020 ÷ 261D ÷ # × [0.3] <reserved-50005> (XX_AL) × [7.01] SPACE (SP) ÷ [18.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 50005 × 0308 ÷ 261D ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 50005 × 0308 × 0020 ÷ 261D ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 50005 ÷ 1F3FB ÷ # × [0.3] <reserved-50005> (XX_AL) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 50005 × 0020 ÷ 1F3FB ÷ # × [0.3] <reserved-50005> (XX_AL) × [7.01] SPACE (SP) ÷ [18.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 50005 × 0308 ÷ 1F3FB ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 50005 × 0308 × 0020 ÷ 1F3FB ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 50005 × 0001 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 50005 × 0020 ÷ 0001 ÷ # × [0.3] <reserved-50005> (XX_AL) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 50005 × 0308 × 0001 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [9.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 50005 × 0308 × 0020 ÷ 0001 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 50005 × 200D ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 50005 × 0020 ÷ 200D ÷ # × [0.3] <reserved-50005> (XX_AL) × [7.01] SPACE (SP) ÷ [18.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 50005 × 0308 × 200D ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [9.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 50005 × 0308 × 0020 ÷ 200D ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] × 50005 × 00A7 ÷ # × [0.3] <reserved-50005> (XX_AL) × [28.0] SECTION SIGN (AI_AL) ÷ [0.3] × 50005 × 0020 ÷ 00A7 ÷ # × [0.3] <reserved-50005> (XX_AL) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] -× 50005 × 0308 × 00A7 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM) × [28.0] SECTION SIGN (AI_AL) ÷ [0.3] -× 50005 × 0308 × 0020 ÷ 00A7 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] +× 50005 × 0308 × 00A7 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [28.0] SECTION SIGN (AI_AL) ÷ [0.3] +× 50005 × 0308 × 0020 ÷ 00A7 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] × 50005 × 50005 ÷ # × [0.3] <reserved-50005> (XX_AL) × [28.0] <reserved-50005> (XX_AL) ÷ [0.3] × 50005 × 0020 ÷ 50005 ÷ # × [0.3] <reserved-50005> (XX_AL) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] -× 50005 × 0308 × 50005 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM) × [28.0] <reserved-50005> (XX_AL) ÷ [0.3] -× 50005 × 0308 × 0020 ÷ 50005 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] +× 50005 × 0308 × 50005 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [28.0] <reserved-50005> (XX_AL) ÷ [0.3] +× 50005 × 0308 × 0020 ÷ 50005 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] × 50005 × 0E01 ÷ # × [0.3] <reserved-50005> (XX_AL) × [28.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] × 50005 × 0020 ÷ 0E01 ÷ # × [0.3] <reserved-50005> (XX_AL) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] -× 50005 × 0308 × 0E01 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM) × [28.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] -× 50005 × 0308 × 0020 ÷ 0E01 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] +× 50005 × 0308 × 0E01 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [28.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] +× 50005 × 0308 × 0020 ÷ 0E01 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] × 50005 × 3041 ÷ # × [0.3] <reserved-50005> (XX_AL) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] × 50005 × 0020 ÷ 3041 ÷ # × [0.3] <reserved-50005> (XX_AL) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] -× 50005 × 0308 × 3041 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] -× 50005 × 0308 × 0020 ÷ 3041 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] +× 50005 × 0308 × 3041 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] +× 50005 × 0308 × 0020 ÷ 3041 ÷ # × [0.3] <reserved-50005> (XX_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] × 0E01 × 0023 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [28.0] NUMBER SIGN (AL) ÷ [0.3] × 0E01 × 0020 ÷ 0023 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] -× 0E01 × 0308 × 0023 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM) × [28.0] NUMBER SIGN (AL) ÷ [0.3] -× 0E01 × 0308 × 0020 ÷ 0023 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] +× 0E01 × 0308 × 0023 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [28.0] NUMBER SIGN (AL) ÷ [0.3] +× 0E01 × 0308 × 0020 ÷ 0023 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] × 0E01 ÷ 2014 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) ÷ [999.0] EM DASH (B2) ÷ [0.3] × 0E01 × 0020 ÷ 2014 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] -× 0E01 × 0308 ÷ 2014 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] EM DASH (B2) ÷ [0.3] -× 0E01 × 0308 × 0020 ÷ 2014 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] +× 0E01 × 0308 ÷ 2014 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] EM DASH (B2) ÷ [0.3] +× 0E01 × 0308 × 0020 ÷ 2014 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] × 0E01 × 0009 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] × 0E01 × 0020 ÷ 0009 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] -× 0E01 × 0308 × 0009 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] -× 0E01 × 0308 × 0020 ÷ 0009 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] +× 0E01 × 0308 × 0009 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] +× 0E01 × 0308 × 0020 ÷ 0009 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] × 0E01 ÷ 00B4 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3] × 0E01 × 0020 ÷ 00B4 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] -× 0E01 × 0308 ÷ 00B4 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3] -× 0E01 × 0308 × 0020 ÷ 00B4 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] +× 0E01 × 0308 ÷ 00B4 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3] +× 0E01 × 0308 × 0020 ÷ 00B4 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] × 0E01 × 000B ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] × 0E01 × 0020 × 000B ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] -× 0E01 × 0308 × 000B ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] -× 0E01 × 0308 × 0020 × 000B ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] +× 0E01 × 0308 × 000B ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] +× 0E01 × 0308 × 0020 × 000B ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] × 0E01 ÷ FFFC ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] × 0E01 × 0020 ÷ FFFC ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] -× 0E01 × 0308 ÷ FFFC ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] -× 0E01 × 0308 × 0020 ÷ FFFC ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] +× 0E01 × 0308 ÷ FFFC ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] +× 0E01 × 0308 × 0020 ÷ FFFC ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] × 0E01 × 007D ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] × 0E01 × 0020 × 007D ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] -× 0E01 × 0308 × 007D ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM) × [13.03] RIGHT CURLY BRACKET (CL) ÷ [0.3] -× 0E01 × 0308 × 0020 × 007D ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] +× 0E01 × 0308 × 007D ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] RIGHT CURLY BRACKET (CL) ÷ [0.3] +× 0E01 × 0308 × 0020 × 007D ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] × 0E01 × 0029 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] × 0E01 × 0020 × 0029 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 0E01 × 0308 × 0029 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM) × [13.03] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 0E01 × 0308 × 0020 × 0029 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 0E01 × 0001 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] <START OF HEADING> (CM) ÷ [0.3] -× 0E01 × 0020 ÷ 0001 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM) ÷ [0.3] -× 0E01 × 0308 × 0001 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM) × [9.0] <START OF HEADING> (CM) ÷ [0.3] -× 0E01 × 0308 × 0020 ÷ 0001 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM) ÷ [0.3] +× 0E01 × 0308 × 0029 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] RIGHT PARENTHESIS (CP) ÷ [0.3] +× 0E01 × 0308 × 0020 × 0029 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] × 0E01 × 000D ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] × 0E01 × 0020 × 000D ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -× 0E01 × 0308 × 000D ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -× 0E01 × 0308 × 0020 × 000D ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +× 0E01 × 0308 × 000D ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +× 0E01 × 0308 × 0020 × 000D ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] × 0E01 × 0021 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] × 0E01 × 0020 × 0021 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] -× 0E01 × 0308 × 0021 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] -× 0E01 × 0308 × 0020 × 0021 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] +× 0E01 × 0308 × 0021 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] +× 0E01 × 0308 × 0020 × 0021 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] × 0E01 × 00A0 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [12.1] NO-BREAK SPACE (GL) ÷ [0.3] × 0E01 × 0020 ÷ 00A0 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] -× 0E01 × 0308 × 00A0 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM) × [12.2] NO-BREAK SPACE (GL) ÷ [0.3] -× 0E01 × 0308 × 0020 ÷ 00A0 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] +× 0E01 × 0308 × 00A0 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [12.2] NO-BREAK SPACE (GL) ÷ [0.3] +× 0E01 × 0308 × 0020 ÷ 00A0 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] × 0E01 ÷ AC00 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) ÷ [999.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] × 0E01 × 0020 ÷ AC00 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] -× 0E01 × 0308 ÷ AC00 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] -× 0E01 × 0308 × 0020 ÷ AC00 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] +× 0E01 × 0308 ÷ AC00 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] +× 0E01 × 0308 × 0020 ÷ AC00 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] × 0E01 ÷ AC01 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) ÷ [999.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] × 0E01 × 0020 ÷ AC01 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] -× 0E01 × 0308 ÷ AC01 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] -× 0E01 × 0308 × 0020 ÷ AC01 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] +× 0E01 × 0308 ÷ AC01 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] +× 0E01 × 0308 × 0020 ÷ AC01 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] × 0E01 × 05D0 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [28.0] HEBREW LETTER ALEF (HL) ÷ [0.3] × 0E01 × 0020 ÷ 05D0 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] -× 0E01 × 0308 × 05D0 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM) × [28.0] HEBREW LETTER ALEF (HL) ÷ [0.3] -× 0E01 × 0308 × 0020 ÷ 05D0 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] +× 0E01 × 0308 × 05D0 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [28.0] HEBREW LETTER ALEF (HL) ÷ [0.3] +× 0E01 × 0308 × 0020 ÷ 05D0 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] × 0E01 × 002D ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] × 0E01 × 0020 ÷ 002D ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] -× 0E01 × 0308 × 002D ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] -× 0E01 × 0308 × 0020 ÷ 002D ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] +× 0E01 × 0308 × 002D ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] +× 0E01 × 0308 × 0020 ÷ 002D ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] × 0E01 ÷ 231A ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) ÷ [999.0] WATCH (ID) ÷ [0.3] × 0E01 × 0020 ÷ 231A ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] -× 0E01 × 0308 ÷ 231A ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] WATCH (ID) ÷ [0.3] -× 0E01 × 0308 × 0020 ÷ 231A ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] +× 0E01 × 0308 ÷ 231A ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] WATCH (ID) ÷ [0.3] +× 0E01 × 0308 × 0020 ÷ 231A ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] × 0E01 × 2024 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [22.01] ONE DOT LEADER (IN) ÷ [0.3] × 0E01 × 0020 ÷ 2024 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] -× 0E01 × 0308 × 2024 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM) × [22.01] ONE DOT LEADER (IN) ÷ [0.3] -× 0E01 × 0308 × 0020 ÷ 2024 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] +× 0E01 × 0308 × 2024 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [22.01] ONE DOT LEADER (IN) ÷ [0.3] +× 0E01 × 0308 × 0020 ÷ 2024 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] × 0E01 × 002C ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [13.02] COMMA (IS) ÷ [0.3] × 0E01 × 0020 × 002C ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] -× 0E01 × 0308 × 002C ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM) × [13.03] COMMA (IS) ÷ [0.3] -× 0E01 × 0308 × 0020 × 002C ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] +× 0E01 × 0308 × 002C ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] COMMA (IS) ÷ [0.3] +× 0E01 × 0308 × 0020 × 002C ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] × 0E01 ÷ 1100 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) ÷ [999.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] × 0E01 × 0020 ÷ 1100 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] -× 0E01 × 0308 ÷ 1100 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] -× 0E01 × 0308 × 0020 ÷ 1100 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] +× 0E01 × 0308 ÷ 1100 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] +× 0E01 × 0308 × 0020 ÷ 1100 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] × 0E01 ÷ 11A8 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) ÷ [999.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] × 0E01 × 0020 ÷ 11A8 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] -× 0E01 × 0308 ÷ 11A8 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] -× 0E01 × 0308 × 0020 ÷ 11A8 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] +× 0E01 × 0308 ÷ 11A8 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] +× 0E01 × 0308 × 0020 ÷ 11A8 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] × 0E01 ÷ 1160 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) ÷ [999.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] × 0E01 × 0020 ÷ 1160 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] -× 0E01 × 0308 ÷ 1160 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] -× 0E01 × 0308 × 0020 ÷ 1160 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] +× 0E01 × 0308 ÷ 1160 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] +× 0E01 × 0308 × 0020 ÷ 1160 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] × 0E01 × 000A ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] × 0E01 × 0020 × 000A ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] -× 0E01 × 0308 × 000A ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] -× 0E01 × 0308 × 0020 × 000A ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] +× 0E01 × 0308 × 000A ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] +× 0E01 × 0308 × 0020 × 000A ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] × 0E01 × 0085 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] × 0E01 × 0020 × 0085 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] -× 0E01 × 0308 × 0085 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] -× 0E01 × 0308 × 0020 × 0085 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] +× 0E01 × 0308 × 0085 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] +× 0E01 × 0308 × 0020 × 0085 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] × 0E01 × 17D6 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] × 0E01 × 0020 ÷ 17D6 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] -× 0E01 × 0308 × 17D6 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] -× 0E01 × 0308 × 0020 ÷ 17D6 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] +× 0E01 × 0308 × 17D6 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] +× 0E01 × 0308 × 0020 ÷ 17D6 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] × 0E01 × 0030 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [23.02] DIGIT ZERO (NU) ÷ [0.3] × 0E01 × 0020 ÷ 0030 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] -× 0E01 × 0308 × 0030 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM) × [23.02] DIGIT ZERO (NU) ÷ [0.3] -× 0E01 × 0308 × 0020 ÷ 0030 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] +× 0E01 × 0308 × 0030 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [23.02] DIGIT ZERO (NU) ÷ [0.3] +× 0E01 × 0308 × 0020 ÷ 0030 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] × 0E01 × 0028 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [30.01] LEFT PARENTHESIS (OP) ÷ [0.3] × 0E01 × 0020 ÷ 0028 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] -× 0E01 × 0308 × 0028 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM) × [30.01] LEFT PARENTHESIS (OP) ÷ [0.3] -× 0E01 × 0308 × 0020 ÷ 0028 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] -× 0E01 ÷ 0025 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) ÷ [999.0] PERCENT SIGN (PO) ÷ [0.3] +× 0E01 × 0308 × 0028 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [30.01] LEFT PARENTHESIS (OP) ÷ [0.3] +× 0E01 × 0308 × 0020 ÷ 0028 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] +× 0E01 × 0025 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [24.03] PERCENT SIGN (PO) ÷ [0.3] × 0E01 × 0020 ÷ 0025 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] -× 0E01 × 0308 ÷ 0025 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] PERCENT SIGN (PO) ÷ [0.3] -× 0E01 × 0308 × 0020 ÷ 0025 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] -× 0E01 ÷ 0024 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) ÷ [999.0] DOLLAR SIGN (PR) ÷ [0.3] +× 0E01 × 0308 × 0025 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [24.03] PERCENT SIGN (PO) ÷ [0.3] +× 0E01 × 0308 × 0020 ÷ 0025 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] +× 0E01 × 0024 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [24.03] DOLLAR SIGN (PR) ÷ [0.3] × 0E01 × 0020 ÷ 0024 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] -× 0E01 × 0308 ÷ 0024 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] DOLLAR SIGN (PR) ÷ [0.3] -× 0E01 × 0308 × 0020 ÷ 0024 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] +× 0E01 × 0308 × 0024 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [24.03] DOLLAR SIGN (PR) ÷ [0.3] +× 0E01 × 0308 × 0020 ÷ 0024 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] × 0E01 × 0022 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [19.01] QUOTATION MARK (QU) ÷ [0.3] × 0E01 × 0020 ÷ 0022 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] -× 0E01 × 0308 × 0022 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM) × [19.01] QUOTATION MARK (QU) ÷ [0.3] -× 0E01 × 0308 × 0020 ÷ 0022 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] +× 0E01 × 0308 × 0022 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [19.01] QUOTATION MARK (QU) ÷ [0.3] +× 0E01 × 0308 × 0020 ÷ 0022 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] × 0E01 × 0020 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [7.01] SPACE (SP) ÷ [0.3] × 0E01 × 0020 × 0020 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] -× 0E01 × 0308 × 0020 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [0.3] -× 0E01 × 0308 × 0020 × 0020 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] +× 0E01 × 0308 × 0020 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [0.3] +× 0E01 × 0308 × 0020 × 0020 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] × 0E01 × 002F ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [13.02] SOLIDUS (SY) ÷ [0.3] × 0E01 × 0020 × 002F ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] -× 0E01 × 0308 × 002F ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM) × [13.03] SOLIDUS (SY) ÷ [0.3] -× 0E01 × 0308 × 0020 × 002F ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] +× 0E01 × 0308 × 002F ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] SOLIDUS (SY) ÷ [0.3] +× 0E01 × 0308 × 0020 × 002F ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] × 0E01 × 2060 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [11.01] WORD JOINER (WJ) ÷ [0.3] × 0E01 × 0020 × 2060 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] -× 0E01 × 0308 × 2060 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM) × [11.01] WORD JOINER (WJ) ÷ [0.3] -× 0E01 × 0308 × 0020 × 2060 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] +× 0E01 × 0308 × 2060 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [11.01] WORD JOINER (WJ) ÷ [0.3] +× 0E01 × 0308 × 0020 × 2060 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] × 0E01 × 200B ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] × 0E01 × 0020 × 200B ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] -× 0E01 × 0308 × 200B ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] -× 0E01 × 0308 × 0020 × 200B ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] +× 0E01 × 0308 × 200B ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] +× 0E01 × 0308 × 0020 × 200B ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] × 0E01 ÷ 1F1E6 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] × 0E01 × 0020 ÷ 1F1E6 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -× 0E01 × 0308 ÷ 1F1E6 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -× 0E01 × 0308 × 0020 ÷ 1F1E6 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 0E01 × 0308 ÷ 1F1E6 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 0E01 × 0308 × 0020 ÷ 1F1E6 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 0E01 ÷ 261D ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) ÷ [999.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 0E01 × 0020 ÷ 261D ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [7.01] SPACE (SP) ÷ [18.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 0E01 × 0308 ÷ 261D ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 0E01 × 0308 × 0020 ÷ 261D ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 0E01 ÷ 1F3FB ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 0E01 × 0020 ÷ 1F3FB ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [7.01] SPACE (SP) ÷ [18.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 0E01 × 0308 ÷ 1F3FB ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 0E01 × 0308 × 0020 ÷ 1F3FB ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 0E01 × 0001 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 0E01 × 0020 ÷ 0001 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 0E01 × 0308 × 0001 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [9.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 0E01 × 0308 × 0020 ÷ 0001 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 0E01 × 200D ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 0E01 × 0020 ÷ 200D ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [7.01] SPACE (SP) ÷ [18.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 0E01 × 0308 × 200D ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [9.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 0E01 × 0308 × 0020 ÷ 200D ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] × 0E01 × 00A7 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [28.0] SECTION SIGN (AI_AL) ÷ [0.3] × 0E01 × 0020 ÷ 00A7 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] -× 0E01 × 0308 × 00A7 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM) × [28.0] SECTION SIGN (AI_AL) ÷ [0.3] -× 0E01 × 0308 × 0020 ÷ 00A7 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] +× 0E01 × 0308 × 00A7 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [28.0] SECTION SIGN (AI_AL) ÷ [0.3] +× 0E01 × 0308 × 0020 ÷ 00A7 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] × 0E01 × 50005 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [28.0] <reserved-50005> (XX_AL) ÷ [0.3] × 0E01 × 0020 ÷ 50005 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] -× 0E01 × 0308 × 50005 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM) × [28.0] <reserved-50005> (XX_AL) ÷ [0.3] -× 0E01 × 0308 × 0020 ÷ 50005 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] +× 0E01 × 0308 × 50005 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [28.0] <reserved-50005> (XX_AL) ÷ [0.3] +× 0E01 × 0308 × 0020 ÷ 50005 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] × 0E01 × 0E01 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [28.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] × 0E01 × 0020 ÷ 0E01 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] -× 0E01 × 0308 × 0E01 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM) × [28.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] -× 0E01 × 0308 × 0020 ÷ 0E01 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] +× 0E01 × 0308 × 0E01 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [28.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] +× 0E01 × 0308 × 0020 ÷ 0E01 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] × 0E01 × 3041 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] × 0E01 × 0020 ÷ 3041 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] -× 0E01 × 0308 × 3041 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] -× 0E01 × 0308 × 0020 ÷ 3041 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] +× 0E01 × 0308 × 3041 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] +× 0E01 × 0308 × 0020 ÷ 3041 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] × 3041 ÷ 0023 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [999.0] NUMBER SIGN (AL) ÷ [0.3] × 3041 × 0020 ÷ 0023 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] -× 3041 × 0308 ÷ 0023 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] NUMBER SIGN (AL) ÷ [0.3] -× 3041 × 0308 × 0020 ÷ 0023 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] +× 3041 × 0308 ÷ 0023 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] NUMBER SIGN (AL) ÷ [0.3] +× 3041 × 0308 × 0020 ÷ 0023 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3] × 3041 ÷ 2014 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [999.0] EM DASH (B2) ÷ [0.3] × 3041 × 0020 ÷ 2014 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] -× 3041 × 0308 ÷ 2014 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] EM DASH (B2) ÷ [0.3] -× 3041 × 0308 × 0020 ÷ 2014 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] +× 3041 × 0308 ÷ 2014 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] EM DASH (B2) ÷ [0.3] +× 3041 × 0308 × 0020 ÷ 2014 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3] × 3041 × 0009 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] × 3041 × 0020 ÷ 0009 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] -× 3041 × 0308 × 0009 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] -× 3041 × 0308 × 0020 ÷ 0009 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] +× 3041 × 0308 × 0009 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3] +× 3041 × 0308 × 0020 ÷ 0009 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3] × 3041 ÷ 00B4 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3] × 3041 × 0020 ÷ 00B4 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] -× 3041 × 0308 ÷ 00B4 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3] -× 3041 × 0308 × 0020 ÷ 00B4 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] +× 3041 × 0308 ÷ 00B4 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3] +× 3041 × 0308 × 0020 ÷ 00B4 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3] × 3041 × 000B ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] × 3041 × 0020 × 000B ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] -× 3041 × 0308 × 000B ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] -× 3041 × 0308 × 0020 × 000B ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] +× 3041 × 0308 × 000B ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] +× 3041 × 0308 × 0020 × 000B ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3] × 3041 ÷ FFFC ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] × 3041 × 0020 ÷ FFFC ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] -× 3041 × 0308 ÷ FFFC ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] -× 3041 × 0308 × 0020 ÷ FFFC ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] +× 3041 × 0308 ÷ FFFC ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] +× 3041 × 0308 × 0020 ÷ FFFC ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] × 3041 × 007D ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] × 3041 × 0020 × 007D ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] -× 3041 × 0308 × 007D ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM) × [13.03] RIGHT CURLY BRACKET (CL) ÷ [0.3] -× 3041 × 0308 × 0020 × 007D ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] +× 3041 × 0308 × 007D ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] RIGHT CURLY BRACKET (CL) ÷ [0.3] +× 3041 × 0308 × 0020 × 007D ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] × 3041 × 0029 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] × 3041 × 0020 × 0029 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 3041 × 0308 × 0029 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM) × [13.03] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 3041 × 0308 × 0020 × 0029 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 3041 × 0001 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] <START OF HEADING> (CM) ÷ [0.3] -× 3041 × 0020 ÷ 0001 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM) ÷ [0.3] -× 3041 × 0308 × 0001 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM) × [9.0] <START OF HEADING> (CM) ÷ [0.3] -× 3041 × 0308 × 0020 ÷ 0001 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM) ÷ [0.3] +× 3041 × 0308 × 0029 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] RIGHT PARENTHESIS (CP) ÷ [0.3] +× 3041 × 0308 × 0020 × 0029 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] × 3041 × 000D ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] × 3041 × 0020 × 000D ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -× 3041 × 0308 × 000D ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -× 3041 × 0308 × 0020 × 000D ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +× 3041 × 0308 × 000D ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +× 3041 × 0308 × 0020 × 000D ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] × 3041 × 0021 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] × 3041 × 0020 × 0021 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] -× 3041 × 0308 × 0021 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] -× 3041 × 0308 × 0020 × 0021 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] +× 3041 × 0308 × 0021 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] +× 3041 × 0308 × 0020 × 0021 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] × 3041 × 00A0 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [12.1] NO-BREAK SPACE (GL) ÷ [0.3] × 3041 × 0020 ÷ 00A0 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] -× 3041 × 0308 × 00A0 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM) × [12.2] NO-BREAK SPACE (GL) ÷ [0.3] -× 3041 × 0308 × 0020 ÷ 00A0 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] +× 3041 × 0308 × 00A0 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [12.2] NO-BREAK SPACE (GL) ÷ [0.3] +× 3041 × 0308 × 0020 ÷ 00A0 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3] × 3041 ÷ AC00 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [999.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] × 3041 × 0020 ÷ AC00 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] -× 3041 × 0308 ÷ AC00 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] -× 3041 × 0308 × 0020 ÷ AC00 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] +× 3041 × 0308 ÷ AC00 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] +× 3041 × 0308 × 0020 ÷ AC00 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3] × 3041 ÷ AC01 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [999.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] × 3041 × 0020 ÷ AC01 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] -× 3041 × 0308 ÷ AC01 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] -× 3041 × 0308 × 0020 ÷ AC01 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] +× 3041 × 0308 ÷ AC01 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] +× 3041 × 0308 × 0020 ÷ AC01 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3] × 3041 ÷ 05D0 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [999.0] HEBREW LETTER ALEF (HL) ÷ [0.3] × 3041 × 0020 ÷ 05D0 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] -× 3041 × 0308 ÷ 05D0 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HEBREW LETTER ALEF (HL) ÷ [0.3] -× 3041 × 0308 × 0020 ÷ 05D0 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] +× 3041 × 0308 ÷ 05D0 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HEBREW LETTER ALEF (HL) ÷ [0.3] +× 3041 × 0308 × 0020 ÷ 05D0 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3] × 3041 × 002D ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] × 3041 × 0020 ÷ 002D ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] -× 3041 × 0308 × 002D ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] -× 3041 × 0308 × 0020 ÷ 002D ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] +× 3041 × 0308 × 002D ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] +× 3041 × 0308 × 0020 ÷ 002D ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3] × 3041 ÷ 231A ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [999.0] WATCH (ID) ÷ [0.3] × 3041 × 0020 ÷ 231A ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] -× 3041 × 0308 ÷ 231A ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] WATCH (ID) ÷ [0.3] -× 3041 × 0308 × 0020 ÷ 231A ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] +× 3041 × 0308 ÷ 231A ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] WATCH (ID) ÷ [0.3] +× 3041 × 0308 × 0020 ÷ 231A ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3] × 3041 ÷ 2024 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [999.0] ONE DOT LEADER (IN) ÷ [0.3] × 3041 × 0020 ÷ 2024 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] -× 3041 × 0308 ÷ 2024 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] ONE DOT LEADER (IN) ÷ [0.3] -× 3041 × 0308 × 0020 ÷ 2024 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] +× 3041 × 0308 ÷ 2024 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] ONE DOT LEADER (IN) ÷ [0.3] +× 3041 × 0308 × 0020 ÷ 2024 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3] × 3041 × 002C ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [13.02] COMMA (IS) ÷ [0.3] × 3041 × 0020 × 002C ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] -× 3041 × 0308 × 002C ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM) × [13.03] COMMA (IS) ÷ [0.3] -× 3041 × 0308 × 0020 × 002C ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] +× 3041 × 0308 × 002C ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] COMMA (IS) ÷ [0.3] +× 3041 × 0308 × 0020 × 002C ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3] × 3041 ÷ 1100 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [999.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] × 3041 × 0020 ÷ 1100 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] -× 3041 × 0308 ÷ 1100 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] -× 3041 × 0308 × 0020 ÷ 1100 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] +× 3041 × 0308 ÷ 1100 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] +× 3041 × 0308 × 0020 ÷ 1100 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3] × 3041 ÷ 11A8 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [999.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] × 3041 × 0020 ÷ 11A8 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] -× 3041 × 0308 ÷ 11A8 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] -× 3041 × 0308 × 0020 ÷ 11A8 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] +× 3041 × 0308 ÷ 11A8 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] +× 3041 × 0308 × 0020 ÷ 11A8 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] × 3041 ÷ 1160 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [999.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] × 3041 × 0020 ÷ 1160 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] -× 3041 × 0308 ÷ 1160 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] -× 3041 × 0308 × 0020 ÷ 1160 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] +× 3041 × 0308 ÷ 1160 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] +× 3041 × 0308 × 0020 ÷ 1160 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] × 3041 × 000A ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] × 3041 × 0020 × 000A ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] -× 3041 × 0308 × 000A ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] -× 3041 × 0308 × 0020 × 000A ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] +× 3041 × 0308 × 000A ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] +× 3041 × 0308 × 0020 × 000A ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3] × 3041 × 0085 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] × 3041 × 0020 × 0085 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] -× 3041 × 0308 × 0085 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] -× 3041 × 0308 × 0020 × 0085 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] +× 3041 × 0308 × 0085 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] +× 3041 × 0308 × 0020 × 0085 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3] × 3041 × 17D6 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] × 3041 × 0020 ÷ 17D6 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] -× 3041 × 0308 × 17D6 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] -× 3041 × 0308 × 0020 ÷ 17D6 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] +× 3041 × 0308 × 17D6 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] +× 3041 × 0308 × 0020 ÷ 17D6 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3] × 3041 ÷ 0030 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [999.0] DIGIT ZERO (NU) ÷ [0.3] × 3041 × 0020 ÷ 0030 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] -× 3041 × 0308 ÷ 0030 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] DIGIT ZERO (NU) ÷ [0.3] -× 3041 × 0308 × 0020 ÷ 0030 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] +× 3041 × 0308 ÷ 0030 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] DIGIT ZERO (NU) ÷ [0.3] +× 3041 × 0308 × 0020 ÷ 0030 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3] × 3041 ÷ 0028 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [999.0] LEFT PARENTHESIS (OP) ÷ [0.3] × 3041 × 0020 ÷ 0028 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] -× 3041 × 0308 ÷ 0028 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] LEFT PARENTHESIS (OP) ÷ [0.3] -× 3041 × 0308 × 0020 ÷ 0028 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] +× 3041 × 0308 ÷ 0028 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] LEFT PARENTHESIS (OP) ÷ [0.3] +× 3041 × 0308 × 0020 ÷ 0028 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3] × 3041 ÷ 0025 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [999.0] PERCENT SIGN (PO) ÷ [0.3] × 3041 × 0020 ÷ 0025 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] -× 3041 × 0308 ÷ 0025 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] PERCENT SIGN (PO) ÷ [0.3] -× 3041 × 0308 × 0020 ÷ 0025 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] +× 3041 × 0308 ÷ 0025 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] PERCENT SIGN (PO) ÷ [0.3] +× 3041 × 0308 × 0020 ÷ 0025 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3] × 3041 ÷ 0024 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [999.0] DOLLAR SIGN (PR) ÷ [0.3] × 3041 × 0020 ÷ 0024 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] -× 3041 × 0308 ÷ 0024 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] DOLLAR SIGN (PR) ÷ [0.3] -× 3041 × 0308 × 0020 ÷ 0024 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] +× 3041 × 0308 ÷ 0024 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] DOLLAR SIGN (PR) ÷ [0.3] +× 3041 × 0308 × 0020 ÷ 0024 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3] × 3041 × 0022 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [19.01] QUOTATION MARK (QU) ÷ [0.3] × 3041 × 0020 ÷ 0022 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] -× 3041 × 0308 × 0022 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM) × [19.01] QUOTATION MARK (QU) ÷ [0.3] -× 3041 × 0308 × 0020 ÷ 0022 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] +× 3041 × 0308 × 0022 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [19.01] QUOTATION MARK (QU) ÷ [0.3] +× 3041 × 0308 × 0020 ÷ 0022 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3] × 3041 × 0020 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [7.01] SPACE (SP) ÷ [0.3] × 3041 × 0020 × 0020 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] -× 3041 × 0308 × 0020 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [0.3] -× 3041 × 0308 × 0020 × 0020 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] +× 3041 × 0308 × 0020 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [0.3] +× 3041 × 0308 × 0020 × 0020 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3] × 3041 × 002F ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [13.02] SOLIDUS (SY) ÷ [0.3] × 3041 × 0020 × 002F ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] -× 3041 × 0308 × 002F ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM) × [13.03] SOLIDUS (SY) ÷ [0.3] -× 3041 × 0308 × 0020 × 002F ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] +× 3041 × 0308 × 002F ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] SOLIDUS (SY) ÷ [0.3] +× 3041 × 0308 × 0020 × 002F ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3] × 3041 × 2060 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [11.01] WORD JOINER (WJ) ÷ [0.3] × 3041 × 0020 × 2060 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] -× 3041 × 0308 × 2060 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM) × [11.01] WORD JOINER (WJ) ÷ [0.3] -× 3041 × 0308 × 0020 × 2060 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] +× 3041 × 0308 × 2060 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [11.01] WORD JOINER (WJ) ÷ [0.3] +× 3041 × 0308 × 0020 × 2060 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3] × 3041 × 200B ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] × 3041 × 0020 × 200B ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] -× 3041 × 0308 × 200B ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] -× 3041 × 0308 × 0020 × 200B ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] +× 3041 × 0308 × 200B ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] +× 3041 × 0308 × 0020 × 200B ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3] × 3041 ÷ 1F1E6 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] × 3041 × 0020 ÷ 1F1E6 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -× 3041 × 0308 ÷ 1F1E6 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] -× 3041 × 0308 × 0020 ÷ 1F1E6 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 3041 × 0308 ÷ 1F1E6 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 3041 × 0308 × 0020 ÷ 1F1E6 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +× 3041 ÷ 261D ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [999.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 3041 × 0020 ÷ 261D ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [7.01] SPACE (SP) ÷ [18.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 3041 × 0308 ÷ 261D ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 3041 × 0308 × 0020 ÷ 261D ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 3041 ÷ 1F3FB ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 3041 × 0020 ÷ 1F3FB ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [7.01] SPACE (SP) ÷ [18.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 3041 × 0308 ÷ 1F3FB ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 3041 × 0308 × 0020 ÷ 1F3FB ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 3041 × 0001 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 3041 × 0020 ÷ 0001 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 3041 × 0308 × 0001 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [9.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 3041 × 0308 × 0020 ÷ 0001 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM1_CM) ÷ [0.3] +× 3041 × 200D ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 3041 × 0020 ÷ 200D ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [7.01] SPACE (SP) ÷ [18.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 3041 × 0308 × 200D ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [9.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] +× 3041 × 0308 × 0020 ÷ 200D ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3] × 3041 ÷ 00A7 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [999.0] SECTION SIGN (AI_AL) ÷ [0.3] × 3041 × 0020 ÷ 00A7 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] -× 3041 × 0308 ÷ 00A7 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] SECTION SIGN (AI_AL) ÷ [0.3] -× 3041 × 0308 × 0020 ÷ 00A7 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] +× 3041 × 0308 ÷ 00A7 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] SECTION SIGN (AI_AL) ÷ [0.3] +× 3041 × 0308 × 0020 ÷ 00A7 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3] × 3041 ÷ 50005 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [999.0] <reserved-50005> (XX_AL) ÷ [0.3] × 3041 × 0020 ÷ 50005 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] -× 3041 × 0308 ÷ 50005 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] <reserved-50005> (XX_AL) ÷ [0.3] -× 3041 × 0308 × 0020 ÷ 50005 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] +× 3041 × 0308 ÷ 50005 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] <reserved-50005> (XX_AL) ÷ [0.3] +× 3041 × 0308 × 0020 ÷ 50005 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3] × 3041 ÷ 0E01 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [999.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] × 3041 × 0020 ÷ 0E01 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] -× 3041 × 0308 ÷ 0E01 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM) ÷ [999.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] -× 3041 × 0308 × 0020 ÷ 0E01 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] +× 3041 × 0308 ÷ 0E01 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] +× 3041 × 0308 × 0020 ÷ 0E01 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] × 3041 × 3041 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] × 3041 × 0020 ÷ 3041 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] -× 3041 × 0308 × 3041 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] -× 3041 × 0308 × 0020 ÷ 3041 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] +× 3041 × 0308 × 3041 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] +× 3041 × 0308 × 0020 ÷ 3041 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] +× 000D × 000A ÷ 0061 × 000A ÷ 0308 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) × [5.01] <LINE FEED (LF)> (LF) ÷ [5.03] LATIN SMALL LETTER A (AL) × [6.0] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM1_CM) ÷ [0.3] +× 0061 × 0308 ÷ # × [0.3] LATIN SMALL LETTER A (AL) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [0.3] +× 0020 ÷ 200D × 0646 ÷ # × [0.3] SPACE (SP) ÷ [18.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [28.0] ARABIC LETTER NOON (AL) ÷ [0.3] +× 0646 × 200D × 0020 ÷ # × [0.3] ARABIC LETTER NOON (AL) × [9.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) ÷ [0.3] +× 000B ÷ 3041 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] +× 000D ÷ 3041 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] +× 0085 ÷ 3041 ÷ # × [0.3] <NEXT LINE (NEL)> (NL) ÷ [5.04] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] +× 200D × 261D ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 3041 × 2060 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [11.01] WORD JOINER (WJ) ÷ [0.3] +× 2060 × 3041 ÷ # × [0.3] WORD JOINER (WJ) × [11.02] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] +× 3041 × 0308 × 00A0 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [12.2] NO-BREAK SPACE (GL) ÷ [0.3] +× 200D × 00A0 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [12.3] NO-BREAK SPACE (GL) ÷ [0.3] +× 200D × 002F ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [13.04] SOLIDUS (SY) ÷ [0.3] +× 2014 × 2014 ÷ # × [0.3] EM DASH (B2) × [17.0] EM DASH (B2) ÷ [0.3] +× 3041 ÷ FFFC ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3] +× FFFC ÷ 3041 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) ÷ [20.02] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3] +× 3041 × 002D ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3] +× 0E01 × 2024 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [22.01] ONE DOT LEADER (IN) ÷ [0.3] +× 0021 × 2024 ÷ # × [0.3] EXCLAMATION MARK (EX) × [22.02] ONE DOT LEADER (IN) ÷ [0.3] +× 2024 × 2024 ÷ # × [0.3] ONE DOT LEADER (IN) × [22.04] ONE DOT LEADER (IN) ÷ [0.3] +× 0030 × 2024 ÷ # × [0.3] DIGIT ZERO (NU) × [22.05] ONE DOT LEADER (IN) ÷ [0.3] +× 261D × 0025 ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [23.13] PERCENT SIGN (PO) ÷ [0.3] +× 0E01 × 0030 ÷ # × [0.3] THAI CHARACTER KO KAI (SA_AL) × [23.02] DIGIT ZERO (NU) ÷ [0.3] +× 0024 × 261D ÷ # × [0.3] DOLLAR SIGN (PR) × [23.12] WHITE UP POINTING INDEX (EB) ÷ [0.3] +× 0024 × 0E01 ÷ # × [0.3] DOLLAR SIGN (PR) × [24.02] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] +× 0025 × 0E01 ÷ # × [0.3] PERCENT SIGN (PO) × [24.02] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3] +× 1100 × 1160 ÷ # × [0.3] HANGUL CHOSEONG KIYEOK (JL) × [26.01] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] +× 1160 × 1160 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [26.02] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] +× 11A8 × 11A8 ÷ # × [0.3] HANGUL JONGSEONG KIYEOK (JT) × [26.03] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3] +× 1160 × 2024 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [27.01] ONE DOT LEADER (IN) ÷ [0.3] +× 1160 × 0025 ÷ # × [0.3] HANGUL JUNGSEONG FILLER (JV) × [27.02] PERCENT SIGN (PO) ÷ [0.3] +× 0024 × 1160 ÷ # × [0.3] DOLLAR SIGN (PR) × [27.03] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3] +× 261D × 1F3FB ÷ # × [0.3] WHITE UP POINTING INDEX (EB) × [30.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3] +× 0066 × 0069 × 006E × 0061 × 006C ÷ # × [0.3] LATIN SMALL LETTER F (AL) × [28.0] LATIN SMALL LETTER I (AL) × [28.0] LATIN SMALL LETTER N (AL) × [28.0] LATIN SMALL LETTER A (AL) × [28.0] LATIN SMALL LETTER L (AL) ÷ [0.3] × 0063 × 0061 × 006E × 0027 × 0074 ÷ # × [0.3] LATIN SMALL LETTER C (AL) × [28.0] LATIN SMALL LETTER A (AL) × [28.0] LATIN SMALL LETTER N (AL) × [19.01] APOSTROPHE (QU) × [19.02] LATIN SMALL LETTER T (AL) ÷ [0.3] × 0063 × 0061 × 006E × 2019 × 0074 ÷ # × [0.3] LATIN SMALL LETTER C (AL) × [28.0] LATIN SMALL LETTER A (AL) × [28.0] LATIN SMALL LETTER N (AL) × [19.01] RIGHT SINGLE QUOTATION MARK (QU) × [19.02] LATIN SMALL LETTER T (AL) ÷ [0.3] × 0027 × 0063 × 0061 × 006E × 0027 × 0020 ÷ 006E × 006F × 0074 ÷ # × [0.3] APOSTROPHE (QU) × [19.02] LATIN SMALL LETTER C (AL) × [28.0] LATIN SMALL LETTER A (AL) × [28.0] LATIN SMALL LETTER N (AL) × [19.01] APOSTROPHE (QU) × [7.01] SPACE (SP) ÷ [18.0] LATIN SMALL LETTER N (AL) × [28.0] LATIN SMALL LETTER O (AL) × [28.0] LATIN SMALL LETTER T (AL) ÷ [0.3] @@ -6119,8 +7129,8 @@ × 4E00 × 002E ÷ 4E00 × 002E ÷ # × [0.3] CJK UNIFIED IDEOGRAPH-4E00 (ID) × [13.02] FULL STOP (IS) ÷ [999.0] CJK UNIFIED IDEOGRAPH-4E00 (ID) × [13.02] FULL STOP (IS) ÷ [0.3] × 0061 × 0020 × 0020 ÷ 0062 ÷ # × [0.3] LATIN SMALL LETTER A (AL) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [18.0] LATIN SMALL LETTER B (AL) ÷ [0.3] × 0061 × 0020 × 0020 × 200B ÷ 0062 ÷ # × [0.3] LATIN SMALL LETTER A (AL) × [7.01] SPACE (SP) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [8.0] LATIN SMALL LETTER B (AL) ÷ [0.3] -× 0061 × 0020 ÷ 0308 × 0062 ÷ # × [0.3] LATIN SMALL LETTER A (AL) × [7.01] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM) × [28.0] LATIN SMALL LETTER B (AL) ÷ [0.3] -× 0031 × 0308 × 0062 × 0028 × 0061 × 0029 × 002D ÷ 0028 × 0062 × 0029 ÷ # × [0.3] DIGIT ONE (NU) × [9.0] COMBINING DIAERESIS (CM) × [23.03] LATIN SMALL LETTER B (AL) × [30.01] LEFT PARENTHESIS (OP) × [14.0] LATIN SMALL LETTER A (AL) × [13.02] RIGHT PARENTHESIS (CP) × [21.02] HYPHEN-MINUS (HY) ÷ [999.0] LEFT PARENTHESIS (OP) × [14.0] LATIN SMALL LETTER B (AL) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] +× 0061 × 0020 ÷ 0308 × 0062 ÷ # × [0.3] LATIN SMALL LETTER A (AL) × [7.01] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM1_CM) × [28.0] LATIN SMALL LETTER B (AL) ÷ [0.3] +× 0031 × 0308 × 0062 × 0028 × 0061 × 0029 × 002D ÷ 0028 × 0062 × 0029 ÷ # × [0.3] DIGIT ONE (NU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [23.03] LATIN SMALL LETTER B (AL) × [30.01] LEFT PARENTHESIS (OP) × [14.0] LATIN SMALL LETTER A (AL) × [13.02] RIGHT PARENTHESIS (CP) × [21.02] HYPHEN-MINUS (HY) ÷ [999.0] LEFT PARENTHESIS (OP) × [14.0] LATIN SMALL LETTER B (AL) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] × 0067 × 0069 × 0076 × 0065 × 0020 ÷ 0062 × 006F × 006F × 006B × 0028 × 0073 × 0029 × 002E ÷ # × [0.3] LATIN SMALL LETTER G (AL) × [28.0] LATIN SMALL LETTER I (AL) × [28.0] LATIN SMALL LETTER V (AL) × [28.0] LATIN SMALL LETTER E (AL) × [7.01] SPACE (SP) ÷ [18.0] LATIN SMALL LETTER B (AL) × [28.0] LATIN SMALL LETTER O (AL) × [28.0] LATIN SMALL LETTER O (AL) × [28.0] LATIN SMALL LETTER K (AL) × [30.01] LEFT PARENTHESIS (OP) × [14.0] LATIN SMALL LETTER S (AL) × [13.02] RIGHT PARENTHESIS (CP) × [13.02] FULL STOP (IS) ÷ [0.3] × 307E ÷ 0028 × 3059 × 0029 ÷ # × [0.3] HIRAGANA LETTER MA (ID) ÷ [999.0] LEFT PARENTHESIS (OP) × [14.0] HIRAGANA LETTER SU (ID) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] × 0066 × 0069 × 006E × 0064 × 0020 × 002E × 0063 × 006F × 006D ÷ # × [0.3] LATIN SMALL LETTER F (AL) × [28.0] LATIN SMALL LETTER I (AL) × [28.0] LATIN SMALL LETTER N (AL) × [28.0] LATIN SMALL LETTER D (AL) × [7.01] SPACE (SP) × [13.02] FULL STOP (IS) × [29.0] LATIN SMALL LETTER C (AL) × [28.0] LATIN SMALL LETTER O (AL) × [28.0] LATIN SMALL LETTER M (AL) ÷ [0.3] @@ -6133,12 +7143,12 @@ × 0063 × 006F × 0064 × 0065 × 0028 × 0073 × 002E × 0029 ÷ # × [0.3] LATIN SMALL LETTER C (AL) × [28.0] LATIN SMALL LETTER O (AL) × [28.0] LATIN SMALL LETTER D (AL) × [28.0] LATIN SMALL LETTER E (AL) × [30.01] LEFT PARENTHESIS (OP) × [14.0] LATIN SMALL LETTER S (AL) × [13.02] FULL STOP (IS) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] × 0063 × 006F × 0064 × 0065 × 0028 × 0073 × 0029 × 0021 ÷ # × [0.3] LATIN SMALL LETTER C (AL) × [28.0] LATIN SMALL LETTER O (AL) × [28.0] LATIN SMALL LETTER D (AL) × [28.0] LATIN SMALL LETTER E (AL) × [30.01] LEFT PARENTHESIS (OP) × [14.0] LATIN SMALL LETTER S (AL) × [13.02] RIGHT PARENTHESIS (CP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] × 0063 × 006F × 0064 × 0065 × 0028 × 0073 × 0021 × 0029 ÷ # × [0.3] LATIN SMALL LETTER C (AL) × [28.0] LATIN SMALL LETTER O (AL) × [28.0] LATIN SMALL LETTER D (AL) × [28.0] LATIN SMALL LETTER E (AL) × [30.01] LEFT PARENTHESIS (OP) × [14.0] LATIN SMALL LETTER S (AL) × [13.01] EXCLAMATION MARK (EX) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 0063 × 006F × 0064 × 0065 ÷ 005C ÷ 0028 × 0073 ÷ 005C × 0029 ÷ # × [0.3] LATIN SMALL LETTER C (AL) × [28.0] LATIN SMALL LETTER O (AL) × [28.0] LATIN SMALL LETTER D (AL) × [28.0] LATIN SMALL LETTER E (AL) ÷ [999.0] REVERSE SOLIDUS (PR) ÷ [999.0] LEFT PARENTHESIS (OP) × [14.0] LATIN SMALL LETTER S (AL) ÷ [999.0] REVERSE SOLIDUS (PR) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] +× 0063 × 006F × 0064 × 0065 × 005C ÷ 0028 × 0073 × 005C × 0029 ÷ # × [0.3] LATIN SMALL LETTER C (AL) × [28.0] LATIN SMALL LETTER O (AL) × [28.0] LATIN SMALL LETTER D (AL) × [28.0] LATIN SMALL LETTER E (AL) × [24.03] REVERSE SOLIDUS (PR) ÷ [999.0] LEFT PARENTHESIS (OP) × [14.0] LATIN SMALL LETTER S (AL) × [24.03] REVERSE SOLIDUS (PR) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] × 0063 × 006F × 0064 × 0065 × 0028 × 0020 × 0073 × 0020 × 0029 ÷ # × [0.3] LATIN SMALL LETTER C (AL) × [28.0] LATIN SMALL LETTER O (AL) × [28.0] LATIN SMALL LETTER D (AL) × [28.0] LATIN SMALL LETTER E (AL) × [30.01] LEFT PARENTHESIS (OP) × [7.01] SPACE (SP) × [14.0] LATIN SMALL LETTER S (AL) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] × 0063 × 006F × 0064 × 0065 × 007B × 0073 × 007D ÷ # × [0.3] LATIN SMALL LETTER C (AL) × [28.0] LATIN SMALL LETTER O (AL) × [28.0] LATIN SMALL LETTER D (AL) × [28.0] LATIN SMALL LETTER E (AL) × [30.01] LEFT CURLY BRACKET (OP) × [14.0] LATIN SMALL LETTER S (AL) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] × 0063 × 006F × 0064 × 0065 × 007B × 0073 × 007D × 002E ÷ # × [0.3] LATIN SMALL LETTER C (AL) × [28.0] LATIN SMALL LETTER O (AL) × [28.0] LATIN SMALL LETTER D (AL) × [28.0] LATIN SMALL LETTER E (AL) × [30.01] LEFT CURLY BRACKET (OP) × [14.0] LATIN SMALL LETTER S (AL) × [13.02] RIGHT CURLY BRACKET (CL) × [13.02] FULL STOP (IS) ÷ [0.3] × 0063 × 006F × 0064 × 0065 × 007B × 0073 × 007D × 0021 ÷ # × [0.3] LATIN SMALL LETTER C (AL) × [28.0] LATIN SMALL LETTER O (AL) × [28.0] LATIN SMALL LETTER D (AL) × [28.0] LATIN SMALL LETTER E (AL) × [30.01] LEFT CURLY BRACKET (OP) × [14.0] LATIN SMALL LETTER S (AL) × [13.02] RIGHT CURLY BRACKET (CL) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3] -× 0063 × 006F × 0064 × 0065 ÷ 005C ÷ 007B × 0073 ÷ 005C × 007D ÷ # × [0.3] LATIN SMALL LETTER C (AL) × [28.0] LATIN SMALL LETTER O (AL) × [28.0] LATIN SMALL LETTER D (AL) × [28.0] LATIN SMALL LETTER E (AL) ÷ [999.0] REVERSE SOLIDUS (PR) ÷ [999.0] LEFT CURLY BRACKET (OP) × [14.0] LATIN SMALL LETTER S (AL) ÷ [999.0] REVERSE SOLIDUS (PR) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] +× 0063 × 006F × 0064 × 0065 × 005C ÷ 007B × 0073 × 005C × 007D ÷ # × [0.3] LATIN SMALL LETTER C (AL) × [28.0] LATIN SMALL LETTER O (AL) × [28.0] LATIN SMALL LETTER D (AL) × [28.0] LATIN SMALL LETTER E (AL) × [24.03] REVERSE SOLIDUS (PR) ÷ [999.0] LEFT CURLY BRACKET (OP) × [14.0] LATIN SMALL LETTER S (AL) × [24.03] REVERSE SOLIDUS (PR) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] × 0063 × 006F × 0064 × 0065 × 007B × 0020 × 0073 × 0020 × 007D ÷ # × [0.3] LATIN SMALL LETTER C (AL) × [28.0] LATIN SMALL LETTER O (AL) × [28.0] LATIN SMALL LETTER D (AL) × [28.0] LATIN SMALL LETTER E (AL) × [30.01] LEFT CURLY BRACKET (OP) × [7.01] SPACE (SP) × [14.0] LATIN SMALL LETTER S (AL) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] × 0063 × 006F × 0064 × 0028 × 0065 × 0029 ÷ 2026 ÷ 0028 × 0073 × 0029 ÷ # × [0.3] LATIN SMALL LETTER C (AL) × [28.0] LATIN SMALL LETTER O (AL) × [28.0] LATIN SMALL LETTER D (AL) × [30.01] LEFT PARENTHESIS (OP) × [14.0] LATIN SMALL LETTER E (AL) × [13.02] RIGHT PARENTHESIS (CP) ÷ [999.0] HORIZONTAL ELLIPSIS (IN) ÷ [999.0] LEFT PARENTHESIS (OP) × [14.0] LATIN SMALL LETTER S (AL) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] × 0028 × 0063 × 006F × 0064 × 0028 × 0065 × 0029 ÷ 2026 × 0029 × 0073 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [14.0] LATIN SMALL LETTER C (AL) × [28.0] LATIN SMALL LETTER O (AL) × [28.0] LATIN SMALL LETTER D (AL) × [30.01] LEFT PARENTHESIS (OP) × [14.0] LATIN SMALL LETTER E (AL) × [13.02] RIGHT PARENTHESIS (CP) ÷ [999.0] HORIZONTAL ELLIPSIS (IN) × [13.02] RIGHT PARENTHESIS (CP) × [30.02] LATIN SMALL LETTER S (AL) ÷ [0.3] @@ -6156,19 +7166,19 @@ × 007B × 0063 × 006F × 006E × 007D × 002D ÷ 006C × 0061 × 006E × 0067 ÷ # × [0.3] LEFT CURLY BRACKET (OP) × [14.0] LATIN SMALL LETTER C (AL) × [28.0] LATIN SMALL LETTER O (AL) × [28.0] LATIN SMALL LETTER N (AL) × [13.02] RIGHT CURLY BRACKET (CL) × [21.02] HYPHEN-MINUS (HY) ÷ [999.0] LATIN SMALL LETTER L (AL) × [28.0] LATIN SMALL LETTER A (AL) × [28.0] LATIN SMALL LETTER N (AL) × [28.0] LATIN SMALL LETTER G (AL) ÷ [0.3] × 007B × 0063 × 006F × 006E × 007D × 00AD ÷ 006C × 0061 × 006E × 0067 ÷ # × [0.3] LEFT CURLY BRACKET (OP) × [14.0] LATIN SMALL LETTER C (AL) × [28.0] LATIN SMALL LETTER O (AL) × [28.0] LATIN SMALL LETTER N (AL) × [13.02] RIGHT CURLY BRACKET (CL) × [21.01] SOFT HYPHEN (BA) ÷ [999.0] LATIN SMALL LETTER L (AL) × [28.0] LATIN SMALL LETTER A (AL) × [28.0] LATIN SMALL LETTER N (AL) × [28.0] LATIN SMALL LETTER G (AL) ÷ [0.3] × 007B × 0063 × 006F × 006E × 007D × 2011 × 006C × 0061 × 006E × 0067 ÷ # × [0.3] LEFT CURLY BRACKET (OP) × [14.0] LATIN SMALL LETTER C (AL) × [28.0] LATIN SMALL LETTER O (AL) × [28.0] LATIN SMALL LETTER N (AL) × [13.02] RIGHT CURLY BRACKET (CL) × [12.1] NON-BREAKING HYPHEN (GL) × [12.0] LATIN SMALL LETTER L (AL) × [28.0] LATIN SMALL LETTER A (AL) × [28.0] LATIN SMALL LETTER N (AL) × [28.0] LATIN SMALL LETTER G (AL) ÷ [0.3] -× 0063 × 0072 × 0065 × 0301 × 0028 × 0065 × 0301 × 0029 ÷ 0028 × 0065 × 0029 ÷ # × [0.3] LATIN SMALL LETTER C (AL) × [28.0] LATIN SMALL LETTER R (AL) × [28.0] LATIN SMALL LETTER E (AL) × [9.0] COMBINING ACUTE ACCENT (CM) × [30.01] LEFT PARENTHESIS (OP) × [14.0] LATIN SMALL LETTER E (AL) × [9.0] COMBINING ACUTE ACCENT (CM) × [13.03] RIGHT PARENTHESIS (CP) ÷ [999.0] LEFT PARENTHESIS (OP) × [14.0] LATIN SMALL LETTER E (AL) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 0063 × 0072 × 0065 × 0301 × 005B × 0065 × 0072 × 007C ÷ 0065 × 0301 × 0028 × 0065 × 0029 ÷ 0028 × 0073 × 0029 × 005D ÷ # × [0.3] LATIN SMALL LETTER C (AL) × [28.0] LATIN SMALL LETTER R (AL) × [28.0] LATIN SMALL LETTER E (AL) × [9.0] COMBINING ACUTE ACCENT (CM) × [30.01] LEFT SQUARE BRACKET (OP) × [14.0] LATIN SMALL LETTER E (AL) × [28.0] LATIN SMALL LETTER R (AL) × [21.01] VERTICAL LINE (BA) ÷ [999.0] LATIN SMALL LETTER E (AL) × [9.0] COMBINING ACUTE ACCENT (CM) × [30.01] LEFT PARENTHESIS (OP) × [14.0] LATIN SMALL LETTER E (AL) × [13.02] RIGHT PARENTHESIS (CP) ÷ [999.0] LEFT PARENTHESIS (OP) × [14.0] LATIN SMALL LETTER S (AL) × [13.02] RIGHT PARENTHESIS (CP) × [13.02] RIGHT SQUARE BRACKET (CP) ÷ [0.3] -× 0063 × 0072 × 0065 × 0301 × 007B × 0065 × 0072 × 007C ÷ 0065 × 0301 × 0028 × 0065 × 0029 ÷ 0028 × 0073 × 0029 × 007D ÷ # × [0.3] LATIN SMALL LETTER C (AL) × [28.0] LATIN SMALL LETTER R (AL) × [28.0] LATIN SMALL LETTER E (AL) × [9.0] COMBINING ACUTE ACCENT (CM) × [30.01] LEFT CURLY BRACKET (OP) × [14.0] LATIN SMALL LETTER E (AL) × [28.0] LATIN SMALL LETTER R (AL) × [21.01] VERTICAL LINE (BA) ÷ [999.0] LATIN SMALL LETTER E (AL) × [9.0] COMBINING ACUTE ACCENT (CM) × [30.01] LEFT PARENTHESIS (OP) × [14.0] LATIN SMALL LETTER E (AL) × [13.02] RIGHT PARENTHESIS (CP) ÷ [999.0] LEFT PARENTHESIS (OP) × [14.0] LATIN SMALL LETTER S (AL) × [13.02] RIGHT PARENTHESIS (CP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] -× 0061 × 006D × 0062 × 0069 × 0067 × 0075 × 0028 × 0308 × 0029 ÷ 0028 × 0065 × 0308 × 0029 ÷ # × [0.3] LATIN SMALL LETTER A (AL) × [28.0] LATIN SMALL LETTER M (AL) × [28.0] LATIN SMALL LETTER B (AL) × [28.0] LATIN SMALL LETTER I (AL) × [28.0] LATIN SMALL LETTER G (AL) × [28.0] LATIN SMALL LETTER U (AL) × [30.01] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM) × [13.03] RIGHT PARENTHESIS (CP) ÷ [999.0] LEFT PARENTHESIS (OP) × [14.0] LATIN SMALL LETTER E (AL) × [9.0] COMBINING DIAERESIS (CM) × [13.03] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 0061 × 006D × 0062 × 0069 × 0067 × 0075 × 0028 × 00AB × 0308 × 00BB × 0029 ÷ 0028 × 0065 × 0308 × 0029 ÷ # × [0.3] LATIN SMALL LETTER A (AL) × [28.0] LATIN SMALL LETTER M (AL) × [28.0] LATIN SMALL LETTER B (AL) × [28.0] LATIN SMALL LETTER I (AL) × [28.0] LATIN SMALL LETTER G (AL) × [28.0] LATIN SMALL LETTER U (AL) × [30.01] LEFT PARENTHESIS (OP) × [14.0] LEFT-POINTING DOUBLE ANGLE QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM) × [19.01] RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK (QU) × [13.02] RIGHT PARENTHESIS (CP) ÷ [999.0] LEFT PARENTHESIS (OP) × [14.0] LATIN SMALL LETTER E (AL) × [9.0] COMBINING DIAERESIS (CM) × [13.03] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 0061 × 006D × 0062 × 0069 × 0067 × 0075 × 0028 × 00AB × 0020 ÷ 0308 × 0020 ÷ 00BB × 0029 ÷ 0028 × 0065 × 0308 × 0029 ÷ # × [0.3] LATIN SMALL LETTER A (AL) × [28.0] LATIN SMALL LETTER M (AL) × [28.0] LATIN SMALL LETTER B (AL) × [28.0] LATIN SMALL LETTER I (AL) × [28.0] LATIN SMALL LETTER G (AL) × [28.0] LATIN SMALL LETTER U (AL) × [30.01] LEFT PARENTHESIS (OP) × [14.0] LEFT-POINTING DOUBLE ANGLE QUOTATION MARK (QU) × [7.01] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK (QU) × [13.02] RIGHT PARENTHESIS (CP) ÷ [999.0] LEFT PARENTHESIS (OP) × [14.0] LATIN SMALL LETTER E (AL) × [9.0] COMBINING DIAERESIS (CM) × [13.03] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 0061 × 006D × 0062 × 0069 × 0067 × 0075 × 00AB × 0020 × 0028 × 0020 × 0308 × 0020 × 0029 × 0020 ÷ 00BB × 0028 × 0065 × 0308 × 0029 ÷ # × [0.3] LATIN SMALL LETTER A (AL) × [28.0] LATIN SMALL LETTER M (AL) × [28.0] LATIN SMALL LETTER B (AL) × [28.0] LATIN SMALL LETTER I (AL) × [28.0] LATIN SMALL LETTER G (AL) × [28.0] LATIN SMALL LETTER U (AL) × [19.01] LEFT-POINTING DOUBLE ANGLE QUOTATION MARK (QU) × [7.01] SPACE (SP) × [15.0] LEFT PARENTHESIS (OP) × [7.01] SPACE (SP) × [14.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) × [7.01] SPACE (SP) ÷ [18.0] RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK (QU) × [15.0] LEFT PARENTHESIS (OP) × [14.0] LATIN SMALL LETTER E (AL) × [9.0] COMBINING DIAERESIS (CM) × [13.03] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 0061 × 006D × 0062 × 0069 × 0067 × 0075 × 00AB × 202F × 0028 × 0020 × 0308 × 0020 × 0029 × 202F × 00BB × 0028 × 0065 × 0308 × 0029 ÷ # × [0.3] LATIN SMALL LETTER A (AL) × [28.0] LATIN SMALL LETTER M (AL) × [28.0] LATIN SMALL LETTER B (AL) × [28.0] LATIN SMALL LETTER I (AL) × [28.0] LATIN SMALL LETTER G (AL) × [28.0] LATIN SMALL LETTER U (AL) × [19.01] LEFT-POINTING DOUBLE ANGLE QUOTATION MARK (QU) × [12.1] NARROW NO-BREAK SPACE (GL) × [12.0] LEFT PARENTHESIS (OP) × [7.01] SPACE (SP) × [14.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) × [12.1] NARROW NO-BREAK SPACE (GL) × [12.0] RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK (QU) × [15.0] LEFT PARENTHESIS (OP) × [14.0] LATIN SMALL LETTER E (AL) × [9.0] COMBINING DIAERESIS (CM) × [13.03] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 0061 × 006D × 0062 × 0069 × 0067 × 0075 × 007B × 0308 × 007D ÷ 0028 × 0065 × 0308 × 0029 ÷ # × [0.3] LATIN SMALL LETTER A (AL) × [28.0] LATIN SMALL LETTER M (AL) × [28.0] LATIN SMALL LETTER B (AL) × [28.0] LATIN SMALL LETTER I (AL) × [28.0] LATIN SMALL LETTER G (AL) × [28.0] LATIN SMALL LETTER U (AL) × [30.01] LEFT CURLY BRACKET (OP) × [9.0] COMBINING DIAERESIS (CM) × [13.03] RIGHT CURLY BRACKET (CL) ÷ [999.0] LEFT PARENTHESIS (OP) × [14.0] LATIN SMALL LETTER E (AL) × [9.0] COMBINING DIAERESIS (CM) × [13.03] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 0061 × 006D × 0062 × 0069 × 0067 × 0075 × 007B × 00AB × 0308 × 00BB × 007D ÷ 0028 × 0065 × 0308 × 0029 ÷ # × [0.3] LATIN SMALL LETTER A (AL) × [28.0] LATIN SMALL LETTER M (AL) × [28.0] LATIN SMALL LETTER B (AL) × [28.0] LATIN SMALL LETTER I (AL) × [28.0] LATIN SMALL LETTER G (AL) × [28.0] LATIN SMALL LETTER U (AL) × [30.01] LEFT CURLY BRACKET (OP) × [14.0] LEFT-POINTING DOUBLE ANGLE QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM) × [19.01] RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK (QU) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [999.0] LEFT PARENTHESIS (OP) × [14.0] LATIN SMALL LETTER E (AL) × [9.0] COMBINING DIAERESIS (CM) × [13.03] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 0061 × 006D × 0062 × 0069 × 0067 × 0075 × 007B × 00AB × 0020 ÷ 0308 × 0020 ÷ 00BB × 007D ÷ 0028 × 0065 × 0308 × 0029 ÷ # × [0.3] LATIN SMALL LETTER A (AL) × [28.0] LATIN SMALL LETTER M (AL) × [28.0] LATIN SMALL LETTER B (AL) × [28.0] LATIN SMALL LETTER I (AL) × [28.0] LATIN SMALL LETTER G (AL) × [28.0] LATIN SMALL LETTER U (AL) × [30.01] LEFT CURLY BRACKET (OP) × [14.0] LEFT-POINTING DOUBLE ANGLE QUOTATION MARK (QU) × [7.01] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) ÷ [18.0] RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK (QU) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [999.0] LEFT PARENTHESIS (OP) × [14.0] LATIN SMALL LETTER E (AL) × [9.0] COMBINING DIAERESIS (CM) × [13.03] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 0061 × 006D × 0062 × 0069 × 0067 × 0075 × 00AB × 0020 × 007B × 0020 × 0308 × 0020 × 007D × 0020 ÷ 00BB × 0028 × 0065 × 0308 × 0029 ÷ # × [0.3] LATIN SMALL LETTER A (AL) × [28.0] LATIN SMALL LETTER M (AL) × [28.0] LATIN SMALL LETTER B (AL) × [28.0] LATIN SMALL LETTER I (AL) × [28.0] LATIN SMALL LETTER G (AL) × [28.0] LATIN SMALL LETTER U (AL) × [19.01] LEFT-POINTING DOUBLE ANGLE QUOTATION MARK (QU) × [7.01] SPACE (SP) × [15.0] LEFT CURLY BRACKET (OP) × [7.01] SPACE (SP) × [14.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) × [7.01] SPACE (SP) ÷ [18.0] RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK (QU) × [15.0] LEFT PARENTHESIS (OP) × [14.0] LATIN SMALL LETTER E (AL) × [9.0] COMBINING DIAERESIS (CM) × [13.03] RIGHT PARENTHESIS (CP) ÷ [0.3] -× 0061 × 006D × 0062 × 0069 × 0067 × 0075 × 00AB × 202F × 007B × 0020 × 0308 × 0020 × 007D × 202F × 00BB × 0028 × 0065 × 0308 × 0029 ÷ # × [0.3] LATIN SMALL LETTER A (AL) × [28.0] LATIN SMALL LETTER M (AL) × [28.0] LATIN SMALL LETTER B (AL) × [28.0] LATIN SMALL LETTER I (AL) × [28.0] LATIN SMALL LETTER G (AL) × [28.0] LATIN SMALL LETTER U (AL) × [19.01] LEFT-POINTING DOUBLE ANGLE QUOTATION MARK (QU) × [12.1] NARROW NO-BREAK SPACE (GL) × [12.0] LEFT CURLY BRACKET (OP) × [7.01] SPACE (SP) × [14.0] COMBINING DIAERESIS (CM) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) × [12.1] NARROW NO-BREAK SPACE (GL) × [12.0] RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK (QU) × [15.0] LEFT PARENTHESIS (OP) × [14.0] LATIN SMALL LETTER E (AL) × [9.0] COMBINING DIAERESIS (CM) × [13.03] RIGHT PARENTHESIS (CP) ÷ [0.3] +× 0063 × 0072 × 0065 × 0301 × 0028 × 0065 × 0301 × 0029 ÷ 0028 × 0065 × 0029 ÷ # × [0.3] LATIN SMALL LETTER C (AL) × [28.0] LATIN SMALL LETTER R (AL) × [28.0] LATIN SMALL LETTER E (AL) × [9.0] COMBINING ACUTE ACCENT (CM1_CM) × [30.01] LEFT PARENTHESIS (OP) × [14.0] LATIN SMALL LETTER E (AL) × [9.0] COMBINING ACUTE ACCENT (CM1_CM) × [13.03] RIGHT PARENTHESIS (CP) ÷ [999.0] LEFT PARENTHESIS (OP) × [14.0] LATIN SMALL LETTER E (AL) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3] +× 0063 × 0072 × 0065 × 0301 × 005B × 0065 × 0072 × 007C ÷ 0065 × 0301 × 0028 × 0065 × 0029 ÷ 0028 × 0073 × 0029 × 005D ÷ # × [0.3] LATIN SMALL LETTER C (AL) × [28.0] LATIN SMALL LETTER R (AL) × [28.0] LATIN SMALL LETTER E (AL) × [9.0] COMBINING ACUTE ACCENT (CM1_CM) × [30.01] LEFT SQUARE BRACKET (OP) × [14.0] LATIN SMALL LETTER E (AL) × [28.0] LATIN SMALL LETTER R (AL) × [21.01] VERTICAL LINE (BA) ÷ [999.0] LATIN SMALL LETTER E (AL) × [9.0] COMBINING ACUTE ACCENT (CM1_CM) × [30.01] LEFT PARENTHESIS (OP) × [14.0] LATIN SMALL LETTER E (AL) × [13.02] RIGHT PARENTHESIS (CP) ÷ [999.0] LEFT PARENTHESIS (OP) × [14.0] LATIN SMALL LETTER S (AL) × [13.02] RIGHT PARENTHESIS (CP) × [13.02] RIGHT SQUARE BRACKET (CP) ÷ [0.3] +× 0063 × 0072 × 0065 × 0301 × 007B × 0065 × 0072 × 007C ÷ 0065 × 0301 × 0028 × 0065 × 0029 ÷ 0028 × 0073 × 0029 × 007D ÷ # × [0.3] LATIN SMALL LETTER C (AL) × [28.0] LATIN SMALL LETTER R (AL) × [28.0] LATIN SMALL LETTER E (AL) × [9.0] COMBINING ACUTE ACCENT (CM1_CM) × [30.01] LEFT CURLY BRACKET (OP) × [14.0] LATIN SMALL LETTER E (AL) × [28.0] LATIN SMALL LETTER R (AL) × [21.01] VERTICAL LINE (BA) ÷ [999.0] LATIN SMALL LETTER E (AL) × [9.0] COMBINING ACUTE ACCENT (CM1_CM) × [30.01] LEFT PARENTHESIS (OP) × [14.0] LATIN SMALL LETTER E (AL) × [13.02] RIGHT PARENTHESIS (CP) ÷ [999.0] LEFT PARENTHESIS (OP) × [14.0] LATIN SMALL LETTER S (AL) × [13.02] RIGHT PARENTHESIS (CP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3] +× 0061 × 006D × 0062 × 0069 × 0067 × 0075 × 0028 × 0308 × 0029 ÷ 0028 × 0065 × 0308 × 0029 ÷ # × [0.3] LATIN SMALL LETTER A (AL) × [28.0] LATIN SMALL LETTER M (AL) × [28.0] LATIN SMALL LETTER B (AL) × [28.0] LATIN SMALL LETTER I (AL) × [28.0] LATIN SMALL LETTER G (AL) × [28.0] LATIN SMALL LETTER U (AL) × [30.01] LEFT PARENTHESIS (OP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] RIGHT PARENTHESIS (CP) ÷ [999.0] LEFT PARENTHESIS (OP) × [14.0] LATIN SMALL LETTER E (AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] RIGHT PARENTHESIS (CP) ÷ [0.3] +× 0061 × 006D × 0062 × 0069 × 0067 × 0075 × 0028 × 00AB × 0308 × 00BB × 0029 ÷ 0028 × 0065 × 0308 × 0029 ÷ # × [0.3] LATIN SMALL LETTER A (AL) × [28.0] LATIN SMALL LETTER M (AL) × [28.0] LATIN SMALL LETTER B (AL) × [28.0] LATIN SMALL LETTER I (AL) × [28.0] LATIN SMALL LETTER G (AL) × [28.0] LATIN SMALL LETTER U (AL) × [30.01] LEFT PARENTHESIS (OP) × [14.0] LEFT-POINTING DOUBLE ANGLE QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [19.01] RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK (QU) × [13.02] RIGHT PARENTHESIS (CP) ÷ [999.0] LEFT PARENTHESIS (OP) × [14.0] LATIN SMALL LETTER E (AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] RIGHT PARENTHESIS (CP) ÷ [0.3] +× 0061 × 006D × 0062 × 0069 × 0067 × 0075 × 0028 × 00AB × 0020 ÷ 0308 × 0020 ÷ 00BB × 0029 ÷ 0028 × 0065 × 0308 × 0029 ÷ # × [0.3] LATIN SMALL LETTER A (AL) × [28.0] LATIN SMALL LETTER M (AL) × [28.0] LATIN SMALL LETTER B (AL) × [28.0] LATIN SMALL LETTER I (AL) × [28.0] LATIN SMALL LETTER G (AL) × [28.0] LATIN SMALL LETTER U (AL) × [30.01] LEFT PARENTHESIS (OP) × [14.0] LEFT-POINTING DOUBLE ANGLE QUOTATION MARK (QU) × [7.01] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK (QU) × [13.02] RIGHT PARENTHESIS (CP) ÷ [999.0] LEFT PARENTHESIS (OP) × [14.0] LATIN SMALL LETTER E (AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] RIGHT PARENTHESIS (CP) ÷ [0.3] +× 0061 × 006D × 0062 × 0069 × 0067 × 0075 × 00AB × 0020 × 0028 × 0020 × 0308 × 0020 × 0029 × 0020 ÷ 00BB × 0028 × 0065 × 0308 × 0029 ÷ # × [0.3] LATIN SMALL LETTER A (AL) × [28.0] LATIN SMALL LETTER M (AL) × [28.0] LATIN SMALL LETTER B (AL) × [28.0] LATIN SMALL LETTER I (AL) × [28.0] LATIN SMALL LETTER G (AL) × [28.0] LATIN SMALL LETTER U (AL) × [19.01] LEFT-POINTING DOUBLE ANGLE QUOTATION MARK (QU) × [7.01] SPACE (SP) × [15.0] LEFT PARENTHESIS (OP) × [7.01] SPACE (SP) × [14.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) × [7.01] SPACE (SP) ÷ [18.0] RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK (QU) × [15.0] LEFT PARENTHESIS (OP) × [14.0] LATIN SMALL LETTER E (AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] RIGHT PARENTHESIS (CP) ÷ [0.3] +× 0061 × 006D × 0062 × 0069 × 0067 × 0075 × 00AB × 202F × 0028 × 0020 × 0308 × 0020 × 0029 × 202F × 00BB × 0028 × 0065 × 0308 × 0029 ÷ # × [0.3] LATIN SMALL LETTER A (AL) × [28.0] LATIN SMALL LETTER M (AL) × [28.0] LATIN SMALL LETTER B (AL) × [28.0] LATIN SMALL LETTER I (AL) × [28.0] LATIN SMALL LETTER G (AL) × [28.0] LATIN SMALL LETTER U (AL) × [19.01] LEFT-POINTING DOUBLE ANGLE QUOTATION MARK (QU) × [12.1] NARROW NO-BREAK SPACE (GL) × [12.0] LEFT PARENTHESIS (OP) × [7.01] SPACE (SP) × [14.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) × [12.1] NARROW NO-BREAK SPACE (GL) × [12.0] RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK (QU) × [15.0] LEFT PARENTHESIS (OP) × [14.0] LATIN SMALL LETTER E (AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] RIGHT PARENTHESIS (CP) ÷ [0.3] +× 0061 × 006D × 0062 × 0069 × 0067 × 0075 × 007B × 0308 × 007D ÷ 0028 × 0065 × 0308 × 0029 ÷ # × [0.3] LATIN SMALL LETTER A (AL) × [28.0] LATIN SMALL LETTER M (AL) × [28.0] LATIN SMALL LETTER B (AL) × [28.0] LATIN SMALL LETTER I (AL) × [28.0] LATIN SMALL LETTER G (AL) × [28.0] LATIN SMALL LETTER U (AL) × [30.01] LEFT CURLY BRACKET (OP) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] RIGHT CURLY BRACKET (CL) ÷ [999.0] LEFT PARENTHESIS (OP) × [14.0] LATIN SMALL LETTER E (AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] RIGHT PARENTHESIS (CP) ÷ [0.3] +× 0061 × 006D × 0062 × 0069 × 0067 × 0075 × 007B × 00AB × 0308 × 00BB × 007D ÷ 0028 × 0065 × 0308 × 0029 ÷ # × [0.3] LATIN SMALL LETTER A (AL) × [28.0] LATIN SMALL LETTER M (AL) × [28.0] LATIN SMALL LETTER B (AL) × [28.0] LATIN SMALL LETTER I (AL) × [28.0] LATIN SMALL LETTER G (AL) × [28.0] LATIN SMALL LETTER U (AL) × [30.01] LEFT CURLY BRACKET (OP) × [14.0] LEFT-POINTING DOUBLE ANGLE QUOTATION MARK (QU) × [9.0] COMBINING DIAERESIS (CM1_CM) × [19.01] RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK (QU) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [999.0] LEFT PARENTHESIS (OP) × [14.0] LATIN SMALL LETTER E (AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] RIGHT PARENTHESIS (CP) ÷ [0.3] +× 0061 × 006D × 0062 × 0069 × 0067 × 0075 × 007B × 00AB × 0020 ÷ 0308 × 0020 ÷ 00BB × 007D ÷ 0028 × 0065 × 0308 × 0029 ÷ # × [0.3] LATIN SMALL LETTER A (AL) × [28.0] LATIN SMALL LETTER M (AL) × [28.0] LATIN SMALL LETTER B (AL) × [28.0] LATIN SMALL LETTER I (AL) × [28.0] LATIN SMALL LETTER G (AL) × [28.0] LATIN SMALL LETTER U (AL) × [30.01] LEFT CURLY BRACKET (OP) × [14.0] LEFT-POINTING DOUBLE ANGLE QUOTATION MARK (QU) × [7.01] SPACE (SP) ÷ [18.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK (QU) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [999.0] LEFT PARENTHESIS (OP) × [14.0] LATIN SMALL LETTER E (AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] RIGHT PARENTHESIS (CP) ÷ [0.3] +× 0061 × 006D × 0062 × 0069 × 0067 × 0075 × 00AB × 0020 × 007B × 0020 × 0308 × 0020 × 007D × 0020 ÷ 00BB × 0028 × 0065 × 0308 × 0029 ÷ # × [0.3] LATIN SMALL LETTER A (AL) × [28.0] LATIN SMALL LETTER M (AL) × [28.0] LATIN SMALL LETTER B (AL) × [28.0] LATIN SMALL LETTER I (AL) × [28.0] LATIN SMALL LETTER G (AL) × [28.0] LATIN SMALL LETTER U (AL) × [19.01] LEFT-POINTING DOUBLE ANGLE QUOTATION MARK (QU) × [7.01] SPACE (SP) × [15.0] LEFT CURLY BRACKET (OP) × [7.01] SPACE (SP) × [14.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) × [7.01] SPACE (SP) ÷ [18.0] RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK (QU) × [15.0] LEFT PARENTHESIS (OP) × [14.0] LATIN SMALL LETTER E (AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] RIGHT PARENTHESIS (CP) ÷ [0.3] +× 0061 × 006D × 0062 × 0069 × 0067 × 0075 × 00AB × 202F × 007B × 0020 × 0308 × 0020 × 007D × 202F × 00BB × 0028 × 0065 × 0308 × 0029 ÷ # × [0.3] LATIN SMALL LETTER A (AL) × [28.0] LATIN SMALL LETTER M (AL) × [28.0] LATIN SMALL LETTER B (AL) × [28.0] LATIN SMALL LETTER I (AL) × [28.0] LATIN SMALL LETTER G (AL) × [28.0] LATIN SMALL LETTER U (AL) × [19.01] LEFT-POINTING DOUBLE ANGLE QUOTATION MARK (QU) × [12.1] NARROW NO-BREAK SPACE (GL) × [12.0] LEFT CURLY BRACKET (OP) × [7.01] SPACE (SP) × [14.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) × [12.1] NARROW NO-BREAK SPACE (GL) × [12.0] RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK (QU) × [15.0] LEFT PARENTHESIS (OP) × [14.0] LATIN SMALL LETTER E (AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.03] RIGHT PARENTHESIS (CP) ÷ [0.3] × 0028 × 0063 × 007A × 0065 × 0072 × 0077 × 006F × 006E × 006F × 00AD ÷ 2011 × 0029 × 006E × 0069 × 0065 × 0062 × 0069 × 0065 × 0073 × 006B × 0061 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [14.0] LATIN SMALL LETTER C (AL) × [28.0] LATIN SMALL LETTER Z (AL) × [28.0] LATIN SMALL LETTER E (AL) × [28.0] LATIN SMALL LETTER R (AL) × [28.0] LATIN SMALL LETTER W (AL) × [28.0] LATIN SMALL LETTER O (AL) × [28.0] LATIN SMALL LETTER N (AL) × [28.0] LATIN SMALL LETTER O (AL) × [21.01] SOFT HYPHEN (BA) ÷ [999.0] NON-BREAKING HYPHEN (GL) × [12.0] RIGHT PARENTHESIS (CP) × [30.02] LATIN SMALL LETTER N (AL) × [28.0] LATIN SMALL LETTER I (AL) × [28.0] LATIN SMALL LETTER E (AL) × [28.0] LATIN SMALL LETTER B (AL) × [28.0] LATIN SMALL LETTER I (AL) × [28.0] LATIN SMALL LETTER E (AL) × [28.0] LATIN SMALL LETTER S (AL) × [28.0] LATIN SMALL LETTER K (AL) × [28.0] LATIN SMALL LETTER A (AL) ÷ [0.3] × 0028 × 0063 × 007A × 0065 × 0072 × 0077 × 006F × 006E × 006F × 00AD × 0029 × 2011 × 006E × 0069 × 0065 × 0062 × 0069 × 0065 × 0073 × 006B × 0061 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [14.0] LATIN SMALL LETTER C (AL) × [28.0] LATIN SMALL LETTER Z (AL) × [28.0] LATIN SMALL LETTER E (AL) × [28.0] LATIN SMALL LETTER R (AL) × [28.0] LATIN SMALL LETTER W (AL) × [28.0] LATIN SMALL LETTER O (AL) × [28.0] LATIN SMALL LETTER N (AL) × [28.0] LATIN SMALL LETTER O (AL) × [21.01] SOFT HYPHEN (BA) × [13.02] RIGHT PARENTHESIS (CP) × [12.1] NON-BREAKING HYPHEN (GL) × [12.0] LATIN SMALL LETTER N (AL) × [28.0] LATIN SMALL LETTER I (AL) × [28.0] LATIN SMALL LETTER E (AL) × [28.0] LATIN SMALL LETTER B (AL) × [28.0] LATIN SMALL LETTER I (AL) × [28.0] LATIN SMALL LETTER E (AL) × [28.0] LATIN SMALL LETTER S (AL) × [28.0] LATIN SMALL LETTER K (AL) × [28.0] LATIN SMALL LETTER A (AL) ÷ [0.3] × 0028 × 0063 × 007A × 0065 × 0072 × 0077 × 006F × 006E × 006F × 0029 × 00AD ÷ 2011 × 006E × 0069 × 0065 × 0062 × 0069 × 0065 × 0073 × 006B × 0061 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [14.0] LATIN SMALL LETTER C (AL) × [28.0] LATIN SMALL LETTER Z (AL) × [28.0] LATIN SMALL LETTER E (AL) × [28.0] LATIN SMALL LETTER R (AL) × [28.0] LATIN SMALL LETTER W (AL) × [28.0] LATIN SMALL LETTER O (AL) × [28.0] LATIN SMALL LETTER N (AL) × [28.0] LATIN SMALL LETTER O (AL) × [13.02] RIGHT PARENTHESIS (CP) × [21.01] SOFT HYPHEN (BA) ÷ [999.0] NON-BREAKING HYPHEN (GL) × [12.0] LATIN SMALL LETTER N (AL) × [28.0] LATIN SMALL LETTER I (AL) × [28.0] LATIN SMALL LETTER E (AL) × [28.0] LATIN SMALL LETTER B (AL) × [28.0] LATIN SMALL LETTER I (AL) × [28.0] LATIN SMALL LETTER E (AL) × [28.0] LATIN SMALL LETTER S (AL) × [28.0] LATIN SMALL LETTER K (AL) × [28.0] LATIN SMALL LETTER A (AL) ÷ [0.3] @@ -6187,10 +7197,10 @@ × 0028 × 30CB × 30E5 × 30FC × 0029 × 30FB ÷ 30E8 × 30FC ÷ 30AF ÷ # × [0.3] LEFT PARENTHESIS (OP) × [14.0] KATAKANA LETTER NI (ID) × [21.03] KATAKANA LETTER SMALL YU (CJ_NS) × [21.03] KATAKANA-HIRAGANA PROLONGED SOUND MARK (CJ_NS) × [13.02] RIGHT PARENTHESIS (CP) × [16.0] KATAKANA MIDDLE DOT (NS) ÷ [999.0] KATAKANA LETTER YO (ID) × [21.03] KATAKANA-HIRAGANA PROLONGED SOUND MARK (CJ_NS) ÷ [999.0] KATAKANA LETTER KU (ID) ÷ [0.3] × 007B × 30CB × 30E5 × 30FC × 30FB × 007D ÷ 30E8 × 30FC ÷ 30AF ÷ # × [0.3] LEFT CURLY BRACKET (OP) × [14.0] KATAKANA LETTER NI (ID) × [21.03] KATAKANA LETTER SMALL YU (CJ_NS) × [21.03] KATAKANA-HIRAGANA PROLONGED SOUND MARK (CJ_NS) × [21.03] KATAKANA MIDDLE DOT (NS) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [999.0] KATAKANA LETTER YO (ID) × [21.03] KATAKANA-HIRAGANA PROLONGED SOUND MARK (CJ_NS) ÷ [999.0] KATAKANA LETTER KU (ID) ÷ [0.3] × 007B × 30CB × 30E5 × 30FC × 007D × 30FB ÷ 30E8 × 30FC ÷ 30AF ÷ # × [0.3] LEFT CURLY BRACKET (OP) × [14.0] KATAKANA LETTER NI (ID) × [21.03] KATAKANA LETTER SMALL YU (CJ_NS) × [21.03] KATAKANA-HIRAGANA PROLONGED SOUND MARK (CJ_NS) × [13.02] RIGHT CURLY BRACKET (CL) × [16.0] KATAKANA MIDDLE DOT (NS) ÷ [999.0] KATAKANA LETTER YO (ID) × [21.03] KATAKANA-HIRAGANA PROLONGED SOUND MARK (CJ_NS) ÷ [999.0] KATAKANA LETTER KU (ID) ÷ [0.3] -× 0028 × 1850 × 1846 × 1851 × 1846 ÷ 1806 × 0029 × 182A × 1822 × 1834 × 1822 × 182D × 180C ÷ # × [0.3] LEFT PARENTHESIS (OP) × [14.0] MONGOLIAN LETTER TODO TA (AL) × [28.0] MONGOLIAN LETTER TODO O (AL) × [28.0] MONGOLIAN LETTER TODO DA (AL) × [28.0] MONGOLIAN LETTER TODO O (AL) ÷ [999.0] MONGOLIAN TODO SOFT HYPHEN (BB) × [13.02] RIGHT PARENTHESIS (CP) × [30.02] MONGOLIAN LETTER BA (AL) × [28.0] MONGOLIAN LETTER I (AL) × [28.0] MONGOLIAN LETTER CHA (AL) × [28.0] MONGOLIAN LETTER I (AL) × [28.0] MONGOLIAN LETTER GA (AL) × [9.0] MONGOLIAN FREE VARIATION SELECTOR TWO (CM) ÷ [0.3] -× 0028 × 1850 × 1846 × 1851 × 1846 × 0029 ÷ 1806 × 182A × 1822 × 1834 × 1822 × 182D × 180C ÷ # × [0.3] LEFT PARENTHESIS (OP) × [14.0] MONGOLIAN LETTER TODO TA (AL) × [28.0] MONGOLIAN LETTER TODO O (AL) × [28.0] MONGOLIAN LETTER TODO DA (AL) × [28.0] MONGOLIAN LETTER TODO O (AL) × [13.02] RIGHT PARENTHESIS (CP) ÷ [999.0] MONGOLIAN TODO SOFT HYPHEN (BB) × [21.04] MONGOLIAN LETTER BA (AL) × [28.0] MONGOLIAN LETTER I (AL) × [28.0] MONGOLIAN LETTER CHA (AL) × [28.0] MONGOLIAN LETTER I (AL) × [28.0] MONGOLIAN LETTER GA (AL) × [9.0] MONGOLIAN FREE VARIATION SELECTOR TWO (CM) ÷ [0.3] -× 007B × 1850 × 1846 × 1851 × 1846 ÷ 1806 × 007D ÷ 182A × 1822 × 1834 × 1822 × 182D × 180C ÷ # × [0.3] LEFT CURLY BRACKET (OP) × [14.0] MONGOLIAN LETTER TODO TA (AL) × [28.0] MONGOLIAN LETTER TODO O (AL) × [28.0] MONGOLIAN LETTER TODO DA (AL) × [28.0] MONGOLIAN LETTER TODO O (AL) ÷ [999.0] MONGOLIAN TODO SOFT HYPHEN (BB) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [999.0] MONGOLIAN LETTER BA (AL) × [28.0] MONGOLIAN LETTER I (AL) × [28.0] MONGOLIAN LETTER CHA (AL) × [28.0] MONGOLIAN LETTER I (AL) × [28.0] MONGOLIAN LETTER GA (AL) × [9.0] MONGOLIAN FREE VARIATION SELECTOR TWO (CM) ÷ [0.3] -× 007B × 1850 × 1846 × 1851 × 1846 × 007D ÷ 1806 × 182A × 1822 × 1834 × 1822 × 182D × 180C ÷ # × [0.3] LEFT CURLY BRACKET (OP) × [14.0] MONGOLIAN LETTER TODO TA (AL) × [28.0] MONGOLIAN LETTER TODO O (AL) × [28.0] MONGOLIAN LETTER TODO DA (AL) × [28.0] MONGOLIAN LETTER TODO O (AL) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [999.0] MONGOLIAN TODO SOFT HYPHEN (BB) × [21.04] MONGOLIAN LETTER BA (AL) × [28.0] MONGOLIAN LETTER I (AL) × [28.0] MONGOLIAN LETTER CHA (AL) × [28.0] MONGOLIAN LETTER I (AL) × [28.0] MONGOLIAN LETTER GA (AL) × [9.0] MONGOLIAN FREE VARIATION SELECTOR TWO (CM) ÷ [0.3] +× 0028 × 1850 × 1846 × 1851 × 1846 ÷ 1806 × 0029 × 182A × 1822 × 1834 × 1822 × 182D × 180C ÷ # × [0.3] LEFT PARENTHESIS (OP) × [14.0] MONGOLIAN LETTER TODO TA (AL) × [28.0] MONGOLIAN LETTER TODO O (AL) × [28.0] MONGOLIAN LETTER TODO DA (AL) × [28.0] MONGOLIAN LETTER TODO O (AL) ÷ [999.0] MONGOLIAN TODO SOFT HYPHEN (BB) × [13.02] RIGHT PARENTHESIS (CP) × [30.02] MONGOLIAN LETTER BA (AL) × [28.0] MONGOLIAN LETTER I (AL) × [28.0] MONGOLIAN LETTER CHA (AL) × [28.0] MONGOLIAN LETTER I (AL) × [28.0] MONGOLIAN LETTER GA (AL) × [9.0] MONGOLIAN FREE VARIATION SELECTOR TWO (CM1_CM) ÷ [0.3] +× 0028 × 1850 × 1846 × 1851 × 1846 × 0029 ÷ 1806 × 182A × 1822 × 1834 × 1822 × 182D × 180C ÷ # × [0.3] LEFT PARENTHESIS (OP) × [14.0] MONGOLIAN LETTER TODO TA (AL) × [28.0] MONGOLIAN LETTER TODO O (AL) × [28.0] MONGOLIAN LETTER TODO DA (AL) × [28.0] MONGOLIAN LETTER TODO O (AL) × [13.02] RIGHT PARENTHESIS (CP) ÷ [999.0] MONGOLIAN TODO SOFT HYPHEN (BB) × [21.04] MONGOLIAN LETTER BA (AL) × [28.0] MONGOLIAN LETTER I (AL) × [28.0] MONGOLIAN LETTER CHA (AL) × [28.0] MONGOLIAN LETTER I (AL) × [28.0] MONGOLIAN LETTER GA (AL) × [9.0] MONGOLIAN FREE VARIATION SELECTOR TWO (CM1_CM) ÷ [0.3] +× 007B × 1850 × 1846 × 1851 × 1846 ÷ 1806 × 007D ÷ 182A × 1822 × 1834 × 1822 × 182D × 180C ÷ # × [0.3] LEFT CURLY BRACKET (OP) × [14.0] MONGOLIAN LETTER TODO TA (AL) × [28.0] MONGOLIAN LETTER TODO O (AL) × [28.0] MONGOLIAN LETTER TODO DA (AL) × [28.0] MONGOLIAN LETTER TODO O (AL) ÷ [999.0] MONGOLIAN TODO SOFT HYPHEN (BB) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [999.0] MONGOLIAN LETTER BA (AL) × [28.0] MONGOLIAN LETTER I (AL) × [28.0] MONGOLIAN LETTER CHA (AL) × [28.0] MONGOLIAN LETTER I (AL) × [28.0] MONGOLIAN LETTER GA (AL) × [9.0] MONGOLIAN FREE VARIATION SELECTOR TWO (CM1_CM) ÷ [0.3] +× 007B × 1850 × 1846 × 1851 × 1846 × 007D ÷ 1806 × 182A × 1822 × 1834 × 1822 × 182D × 180C ÷ # × [0.3] LEFT CURLY BRACKET (OP) × [14.0] MONGOLIAN LETTER TODO TA (AL) × [28.0] MONGOLIAN LETTER TODO O (AL) × [28.0] MONGOLIAN LETTER TODO DA (AL) × [28.0] MONGOLIAN LETTER TODO O (AL) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [999.0] MONGOLIAN TODO SOFT HYPHEN (BB) × [21.04] MONGOLIAN LETTER BA (AL) × [28.0] MONGOLIAN LETTER I (AL) × [28.0] MONGOLIAN LETTER CHA (AL) × [28.0] MONGOLIAN LETTER I (AL) × [28.0] MONGOLIAN LETTER GA (AL) × [9.0] MONGOLIAN FREE VARIATION SELECTOR TWO (CM1_CM) ÷ [0.3] × 0028 × 0068 × 0074 × 0074 × 0070 × 003A × 002F × 002F × 0029 × 0078 × 006E × 002D × 002D ÷ 0061 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [14.0] LATIN SMALL LETTER H (AL) × [28.0] LATIN SMALL LETTER T (AL) × [28.0] LATIN SMALL LETTER T (AL) × [28.0] LATIN SMALL LETTER P (AL) × [13.02] COLON (IS) × [13.02] SOLIDUS (SY) × [13.02] SOLIDUS (SY) × [13.02] RIGHT PARENTHESIS (CP) × [30.02] LATIN SMALL LETTER X (AL) × [28.0] LATIN SMALL LETTER N (AL) × [21.02] HYPHEN-MINUS (HY) × [21.02] HYPHEN-MINUS (HY) ÷ [999.0] LATIN SMALL LETTER A (AL) ÷ [0.3] × 007B × 0068 × 0074 × 0074 × 0070 × 003A × 002F × 002F × 007D ÷ 0078 × 006E × 002D × 002D ÷ 0061 ÷ # × [0.3] LEFT CURLY BRACKET (OP) × [14.0] LATIN SMALL LETTER H (AL) × [28.0] LATIN SMALL LETTER T (AL) × [28.0] LATIN SMALL LETTER T (AL) × [28.0] LATIN SMALL LETTER P (AL) × [13.02] COLON (IS) × [13.02] SOLIDUS (SY) × [13.02] SOLIDUS (SY) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [999.0] LATIN SMALL LETTER X (AL) × [28.0] LATIN SMALL LETTER N (AL) × [21.02] HYPHEN-MINUS (HY) × [21.02] HYPHEN-MINUS (HY) ÷ [999.0] LATIN SMALL LETTER A (AL) ÷ [0.3] × 0028 × 0030 × 002C × 0031 × 0029 × 002B × 0028 × 0032 × 002C × 0033 × 0029 × 2295 × 0028 × 2212 × 0034 × 002C × 0035 × 0029 × 2296 × 0028 × 0036 × 002C × 0037 × 0029 ÷ # × [0.3] LEFT PARENTHESIS (OP) × [14.0] DIGIT ZERO (NU) × [25.03] COMMA (IS) × [25.04] DIGIT ONE (NU) × [25.04] RIGHT PARENTHESIS (CP) × [25.05] PLUS SIGN (PR) × [25.01] LEFT PARENTHESIS (OP) × [14.0] DIGIT TWO (NU) × [25.03] COMMA (IS) × [25.04] DIGIT THREE (NU) × [25.04] RIGHT PARENTHESIS (CP) × [30.02] CIRCLED PLUS (AI_AL) × [30.01] LEFT PARENTHESIS (OP) × [14.0] MINUS SIGN (PR) × [25.01] DIGIT FOUR (NU) × [25.03] COMMA (IS) × [25.04] DIGIT FIVE (NU) × [25.04] RIGHT PARENTHESIS (CP) × [30.02] CIRCLED MINUS (AL) × [30.01] LEFT PARENTHESIS (OP) × [14.0] DIGIT SIX (NU) × [25.03] COMMA (IS) × [25.04] DIGIT SEVEN (NU) × [25.04] RIGHT PARENTHESIS (CP) ÷ [0.3] @@ -6199,8 +7209,8 @@ × 0061 × 0062 × 0020 ÷ # × [0.3] LATIN SMALL LETTER A (AL) × [28.0] LATIN SMALL LETTER B (AL) × [7.01] SPACE (SP) ÷ [0.3] × 0061 × 0062 × 0020 ÷ 0063 ÷ # × [0.3] LATIN SMALL LETTER A (AL) × [28.0] LATIN SMALL LETTER B (AL) × [7.01] SPACE (SP) ÷ [18.0] LATIN SMALL LETTER C (AL) ÷ [0.3] × 0061 ÷ 307E ÷ # × [0.3] LATIN SMALL LETTER A (AL) ÷ [999.0] HIRAGANA LETTER MA (ID) ÷ [0.3] -× 0939 × 093F × 0928 × 094D × 0926 × 0940 × 0020 ÷ # × [0.3] DEVANAGARI LETTER HA (AL) × [9.0] DEVANAGARI VOWEL SIGN I (CM) × [28.0] DEVANAGARI LETTER NA (AL) × [9.0] DEVANAGARI SIGN VIRAMA (CM) × [28.0] DEVANAGARI LETTER DA (AL) × [9.0] DEVANAGARI VOWEL SIGN II (CM) × [7.01] SPACE (SP) ÷ [0.3] -× 092F × 0938 × 0917 × 0941 × 091A × 093F × 0924 × 0940 × 092F × 0938 × 093E × 0020 ÷ # × [0.3] DEVANAGARI LETTER YA (AL) × [28.0] DEVANAGARI LETTER SA (AL) × [28.0] DEVANAGARI LETTER GA (AL) × [9.0] DEVANAGARI VOWEL SIGN U (CM) × [28.0] DEVANAGARI LETTER CA (AL) × [9.0] DEVANAGARI VOWEL SIGN I (CM) × [28.0] DEVANAGARI LETTER TA (AL) × [9.0] DEVANAGARI VOWEL SIGN II (CM) × [28.0] DEVANAGARI LETTER YA (AL) × [28.0] DEVANAGARI LETTER SA (AL) × [9.0] DEVANAGARI VOWEL SIGN AA (CM) × [7.01] SPACE (SP) ÷ [0.3] +× 0939 × 093F × 0928 × 094D × 0926 × 0940 × 0020 ÷ # × [0.3] DEVANAGARI LETTER HA (AL) × [9.0] DEVANAGARI VOWEL SIGN I (CM1_CM) × [28.0] DEVANAGARI LETTER NA (AL) × [9.0] DEVANAGARI SIGN VIRAMA (CM1_CM) × [28.0] DEVANAGARI LETTER DA (AL) × [9.0] DEVANAGARI VOWEL SIGN II (CM1_CM) × [7.01] SPACE (SP) ÷ [0.3] +× 092F × 0938 × 0917 × 0941 × 091A × 093F × 0924 × 0940 × 092F × 0938 × 093E × 0020 ÷ # × [0.3] DEVANAGARI LETTER YA (AL) × [28.0] DEVANAGARI LETTER SA (AL) × [28.0] DEVANAGARI LETTER GA (AL) × [9.0] DEVANAGARI VOWEL SIGN U (CM1_CM) × [28.0] DEVANAGARI LETTER CA (AL) × [9.0] DEVANAGARI VOWEL SIGN I (CM1_CM) × [28.0] DEVANAGARI LETTER TA (AL) × [9.0] DEVANAGARI VOWEL SIGN II (CM1_CM) × [28.0] DEVANAGARI LETTER YA (AL) × [28.0] DEVANAGARI LETTER SA (AL) × [9.0] DEVANAGARI VOWEL SIGN AA (CM1_CM) × [7.01] SPACE (SP) ÷ [0.3] × 5370 ÷ 672C ÷ # × [0.3] CJK UNIFIED IDEOGRAPH-5370 (ID) ÷ [999.0] CJK UNIFIED IDEOGRAPH-672C (ID) ÷ [0.3] × 8AAD ÷ 3080 ÷ # × [0.3] CJK UNIFIED IDEOGRAPH-8AAD (ID) ÷ [999.0] HIRAGANA LETTER MU (ID) ÷ [0.3] × 5165 ÷ 529B ÷ 3057 ÷ 30A8 ÷ # × [0.3] CJK UNIFIED IDEOGRAPH-5165 (ID) ÷ [999.0] CJK UNIFIED IDEOGRAPH-529B (ID) ÷ [999.0] HIRAGANA LETTER SI (ID) ÷ [999.0] KATAKANA LETTER E (ID) ÷ [0.3] @@ -6324,16 +7334,11 @@ × 3057 × 3001 ÷ 0061 × 0062 ÷ 3068 ÷ # × [0.3] HIRAGANA LETTER SI (ID) × [13.02] IDEOGRAPHIC COMMA (CL) ÷ [999.0] LATIN SMALL LETTER A (AL) × [28.0] LATIN SMALL LETTER B (AL) ÷ [999.0] HIRAGANA LETTER TO (ID) ÷ [0.3] × 0061 ÷ 1F1E6 ÷ 0062 ÷ # × [0.3] LATIN SMALL LETTER A (AL) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] LATIN SMALL LETTER B (AL) ÷ [0.3] × 1F1F7 × 1F1FA ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER R (RI) × [30.11] REGIONAL INDICATOR SYMBOL LETTER U (RI) ÷ [0.3] -× 1F1F7 × 1F1FA × 1F1F8 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER R (RI) × [30.11] REGIONAL INDICATOR SYMBOL LETTER U (RI) × [30.11] REGIONAL INDICATOR SYMBOL LETTER S (RI) ÷ [0.3] -× 1F1F7 × 1F1FA × 1F1F8 × 1F1EA ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER R (RI) × [30.11] REGIONAL INDICATOR SYMBOL LETTER U (RI) × [30.11] REGIONAL INDICATOR SYMBOL LETTER S (RI) × [30.11] REGIONAL INDICATOR SYMBOL LETTER E (RI) ÷ [0.3] -× 1F1F7 × 1F1FA × 200B ÷ 1F1F8 × 1F1EA ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER R (RI) × [30.11] REGIONAL INDICATOR SYMBOL LETTER U (RI) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [8.0] REGIONAL INDICATOR SYMBOL LETTER S (RI) × [30.11] REGIONAL INDICATOR SYMBOL LETTER E (RI) ÷ [0.3] +× 1F1F7 × 1F1FA ÷ 1F1F8 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER R (RI) × [30.11] REGIONAL INDICATOR SYMBOL LETTER U (RI) ÷ [30.13] REGIONAL INDICATOR SYMBOL LETTER S (RI) ÷ [0.3] +× 1F1F7 × 1F1FA ÷ 1F1F8 × 1F1EA ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER R (RI) × [30.11] REGIONAL INDICATOR SYMBOL LETTER U (RI) ÷ [30.13] REGIONAL INDICATOR SYMBOL LETTER S (RI) × [30.11] REGIONAL INDICATOR SYMBOL LETTER E (RI) ÷ [0.3] +× 1F1F7 × 1F1FA × 200B ÷ 1F1F8 × 1F1EA ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER R (RI) × [30.11] REGIONAL INDICATOR SYMBOL LETTER U (RI) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [8.0] REGIONAL INDICATOR SYMBOL LETTER S (RI) × [30.12] REGIONAL INDICATOR SYMBOL LETTER E (RI) ÷ [0.3] × 05D0 × 002D × 05D0 ÷ # × [0.3] HEBREW LETTER ALEF (HL) × [21.02] HYPHEN-MINUS (HY) × [21.1] HEBREW LETTER ALEF (HL) ÷ [0.3] -× 1F1E6 × 1F1E7 × 1F1E8 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [30.11] REGIONAL INDICATOR SYMBOL LETTER B (RI) × [30.11] REGIONAL INDICATOR SYMBOL LETTER C (RI) ÷ [0.3] -× 1F1E6 × 200D × 1F1E7 × 1F1E8 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] ZERO WIDTH JOINER (CM) × [30.11] REGIONAL INDICATOR SYMBOL LETTER B (RI) × [30.11] REGIONAL INDICATOR SYMBOL LETTER C (RI) ÷ [0.3] -× 1F1E6 × 1F1E7 × 200D × 1F1E8 ÷ # × [0.3] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [30.11] REGIONAL INDICATOR SYMBOL LETTER B (RI) × [9.0] ZERO WIDTH JOINER (CM) × [30.11] REGIONAL INDICATOR SYMBOL LETTER C (RI) ÷ [0.3] -× 0020 ÷ 200D × 0646 ÷ # × [0.3] SPACE (SP) ÷ [18.0] ZERO WIDTH JOINER (CM) × [28.0] ARABIC LETTER NOON (AL) ÷ [0.3] -× 0646 × 200D × 0020 ÷ # × [0.3] ARABIC LETTER NOON (AL) × [9.0] ZERO WIDTH JOINER (CM) × [7.01] SPACE (SP) ÷ [0.3] # -# Lines: 6311 +# Lines: 7312 # # EOF diff --git a/tests/data/NormalizationTest.txt b/tests/data/NormalizationTest.txt index 23c1e51d5f..71f2371c5e 100644 --- a/tests/data/NormalizationTest.txt +++ b/tests/data/NormalizationTest.txt @@ -1,10 +1,11 @@ -# NormalizationTest-7.0.0.txt -# Date: 2013-11-27, 09:54:41 GMT [MD] +# NormalizationTest-10.0.0.txt +# Date: 2017-03-08, 08:41:55 GMT +# © 2017 Unicode®, Inc. +# Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries. +# For terms of use, see http://www.unicode.org/terms_of_use.html # # Unicode Character Database -# Copyright (c) 1991-2013 Unicode, Inc. -# For terms of use, see http://www.unicode.org/terms_of_use.html -# For documentation, see http://www.unicode.org/reports/tr44/ +# For documentation, see http://www.unicode.org/reports/tr44/ # # Normalization Test Suite # Format: @@ -63,6 +64,8 @@ 0045 0300 0304;00C8 0304;0045 0300 0304;00C8 0304;0045 0300 0304; # (E◌̀◌̄; È◌̄; E◌̀◌̄; È◌̄; E◌̀◌̄; ) LATIN CAPITAL LETTER E, COMBINING GRAVE ACCENT, COMBINING MACRON 05B8 05B9 05B1 0591 05C3 05B0 05AC 059F;05B1 05B8 05B9 0591 05C3 05B0 05AC 059F;05B1 05B8 05B9 0591 05C3 05B0 05AC 059F;05B1 05B8 05B9 0591 05C3 05B0 05AC 059F;05B1 05B8 05B9 0591 05C3 05B0 05AC 059F; # (◌ָ◌ֹ◌ֱ◌֑׃◌ְ◌֬◌֟; ◌ֱ◌ָ◌ֹ◌֑׃◌ְ◌֬◌֟; ◌ֱ◌ָ◌ֹ◌֑׃◌ְ◌֬◌֟; ◌ֱ◌ָ◌ֹ◌֑׃◌ְ◌֬◌֟; ◌ֱ◌ָ◌ֹ◌֑׃◌ְ◌֬◌֟; ) HEBREW POINT QAMATS, HEBREW POINT HOLAM, HEBREW POINT HATAF SEGOL, HEBREW ACCENT ETNAHTA, HEBREW PUNCTUATION SOF PASUQ, HEBREW POINT SHEVA, HEBREW ACCENT ILUY, HEBREW ACCENT QARNEY PARA 0592 05B7 05BC 05A5 05B0 05C0 05C4 05AD;05B0 05B7 05BC 05A5 0592 05C0 05AD 05C4;05B0 05B7 05BC 05A5 0592 05C0 05AD 05C4;05B0 05B7 05BC 05A5 0592 05C0 05AD 05C4;05B0 05B7 05BC 05A5 0592 05C0 05AD 05C4; # (◌֒◌ַ◌ּ◌֥◌ְ׀◌ׄ◌֭; ◌ְ◌ַ◌ּ◌֥◌֒׀◌֭◌ׄ; ◌ְ◌ַ◌ּ◌֥◌֒׀◌֭◌ׄ; ◌ְ◌ַ◌ּ◌֥◌֒׀◌֭◌ׄ; ◌ְ◌ַ◌ּ◌֥◌֒׀◌֭◌ׄ; ) HEBREW ACCENT SEGOL, HEBREW POINT PATAH, HEBREW POINT DAGESH OR MAPIQ, HEBREW ACCENT MERKHA, HEBREW POINT SHEVA, HEBREW PUNCTUATION PASEQ, HEBREW MARK UPPER DOT, HEBREW ACCENT DEHI +1100 AC00 11A8;1100 AC01;1100 1100 1161 11A8;1100 AC01;1100 1100 1161 11A8; # (ᄀ각; ᄀ각; ᄀ각; ᄀ각; ᄀ각; ) HANGUL CHOSEONG KIYEOK, HANGUL SYLLABLE GA, HANGUL JONGSEONG KIYEOK +1100 AC00 11A8 11A8;1100 AC01 11A8;1100 1100 1161 11A8 11A8;1100 AC01 11A8;1100 1100 1161 11A8 11A8; # (ᄀ각ᆨ; ᄀ각ᆨ; ᄀ각ᆨ; ᄀ각ᆨ; ᄀ각ᆨ; ) HANGUL CHOSEONG KIYEOK, HANGUL SYLLABLE GA, HANGUL JONGSEONG KIYEOK, HANGUL JONGSEONG KIYEOK # @Part1 # Character by character test # All characters not explicitly occurring in c1 of Part 1 have identical NFC, D, KC, KD forms. @@ -16407,6 +16410,7 @@ FFEE;FFEE;FFEE;25CB;25CB; # (○; ○; ○; ○; ○; ) HALFWIDTH WHITE CIRCLE 1F238;1F238;1F238;7533;7533; # (🈸; 🈸; 🈸; 申; 申; ) SQUARED CJK UNIFIED IDEOGRAPH-7533 1F239;1F239;1F239;5272;5272; # (🈹; 🈹; 🈹; 割; 割; ) SQUARED CJK UNIFIED IDEOGRAPH-5272 1F23A;1F23A;1F23A;55B6;55B6; # (🈺; 🈺; 🈺; 営; 営; ) SQUARED CJK UNIFIED IDEOGRAPH-55B6 +1F23B;1F23B;1F23B;914D;914D; # (🈻; 🈻; 🈻; 配; 配; ) SQUARED CJK UNIFIED IDEOGRAPH-914D 1F240;1F240;1F240;3014 672C 3015;3014 672C 3015; # (🉀; 🉀; 🉀; 〔本〕; 〔本〕; ) TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-672C 1F241;1F241;1F241;3014 4E09 3015;3014 4E09 3015; # (🉁; 🉁; 🉁; 〔三〕; 〔三〕; ) TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-4E09 1F242;1F242;1F242;3014 4E8C 3015;3014 4E8C 3015; # (🉂; 🉂; 🉂; 〔二〕; 〔二〕; ) TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-4E8C @@ -17523,6 +17527,36 @@ FFEE;FFEE;FFEE;25CB;25CB; # (○; ○; ○; ○; ○; ) HALFWIDTH WHITE CIRCLE 0061 085A 059A 0316 302A 0062;0061 302A 085A 0316 059A 0062;0061 302A 085A 0316 059A 0062;0061 302A 085A 0316 059A 0062;0061 302A 085A 0316 059A 0062; # (a◌࡚◌֚◌̖◌〪b; a◌〪◌࡚◌̖◌֚b; a◌〪◌࡚◌̖◌֚b; a◌〪◌࡚◌̖◌֚b; a◌〪◌࡚◌̖◌֚b; ) LATIN SMALL LETTER A, MANDAIC VOCALIZATION MARK, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B 0061 059A 0316 302A 085B 0062;0061 302A 0316 085B 059A 0062;0061 302A 0316 085B 059A 0062;0061 302A 0316 085B 059A 0062;0061 302A 0316 085B 059A 0062; # (a◌֚◌̖◌〪◌࡛b; a◌〪◌̖◌࡛◌֚b; a◌〪◌̖◌࡛◌֚b; a◌〪◌̖◌࡛◌֚b; a◌〪◌̖◌࡛◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, MANDAIC GEMINATION MARK, LATIN SMALL LETTER B 0061 085B 059A 0316 302A 0062;0061 302A 085B 0316 059A 0062;0061 302A 085B 0316 059A 0062;0061 302A 085B 0316 059A 0062;0061 302A 085B 0316 059A 0062; # (a◌࡛◌֚◌̖◌〪b; a◌〪◌࡛◌̖◌֚b; a◌〪◌࡛◌̖◌֚b; a◌〪◌࡛◌̖◌֚b; a◌〪◌࡛◌̖◌֚b; ) LATIN SMALL LETTER A, MANDAIC GEMINATION MARK, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 0315 0300 05AE 08D4 0062;00E0 05AE 08D4 0315 0062;0061 05AE 0300 08D4 0315 0062;00E0 05AE 08D4 0315 0062;0061 05AE 0300 08D4 0315 0062; # (a◌̕◌̀◌֮◌ࣔb; à◌֮◌ࣔ◌̕b; a◌֮◌̀◌ࣔ◌̕b; à◌֮◌ࣔ◌̕b; a◌֮◌̀◌ࣔ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC SMALL HIGH WORD AR-RUB, LATIN SMALL LETTER B +0061 08D4 0315 0300 05AE 0062;0061 05AE 08D4 0300 0315 0062;0061 05AE 08D4 0300 0315 0062;0061 05AE 08D4 0300 0315 0062;0061 05AE 08D4 0300 0315 0062; # (a◌ࣔ◌̕◌̀◌֮b; a◌֮◌ࣔ◌̀◌̕b; a◌֮◌ࣔ◌̀◌̕b; a◌֮◌ࣔ◌̀◌̕b; a◌֮◌ࣔ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC SMALL HIGH WORD AR-RUB, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 08D5 0062;00E0 05AE 08D5 0315 0062;0061 05AE 0300 08D5 0315 0062;00E0 05AE 08D5 0315 0062;0061 05AE 0300 08D5 0315 0062; # (a◌̕◌̀◌֮◌ࣕb; à◌֮◌ࣕ◌̕b; a◌֮◌̀◌ࣕ◌̕b; à◌֮◌ࣕ◌̕b; a◌֮◌̀◌ࣕ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC SMALL HIGH SAD, LATIN SMALL LETTER B +0061 08D5 0315 0300 05AE 0062;0061 05AE 08D5 0300 0315 0062;0061 05AE 08D5 0300 0315 0062;0061 05AE 08D5 0300 0315 0062;0061 05AE 08D5 0300 0315 0062; # (a◌ࣕ◌̕◌̀◌֮b; a◌֮◌ࣕ◌̀◌̕b; a◌֮◌ࣕ◌̀◌̕b; a◌֮◌ࣕ◌̀◌̕b; a◌֮◌ࣕ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC SMALL HIGH SAD, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 08D6 0062;00E0 05AE 08D6 0315 0062;0061 05AE 0300 08D6 0315 0062;00E0 05AE 08D6 0315 0062;0061 05AE 0300 08D6 0315 0062; # (a◌̕◌̀◌֮◌ࣖb; à◌֮◌ࣖ◌̕b; a◌֮◌̀◌ࣖ◌̕b; à◌֮◌ࣖ◌̕b; a◌֮◌̀◌ࣖ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC SMALL HIGH AIN, LATIN SMALL LETTER B +0061 08D6 0315 0300 05AE 0062;0061 05AE 08D6 0300 0315 0062;0061 05AE 08D6 0300 0315 0062;0061 05AE 08D6 0300 0315 0062;0061 05AE 08D6 0300 0315 0062; # (a◌ࣖ◌̕◌̀◌֮b; a◌֮◌ࣖ◌̀◌̕b; a◌֮◌ࣖ◌̀◌̕b; a◌֮◌ࣖ◌̀◌̕b; a◌֮◌ࣖ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC SMALL HIGH AIN, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 08D7 0062;00E0 05AE 08D7 0315 0062;0061 05AE 0300 08D7 0315 0062;00E0 05AE 08D7 0315 0062;0061 05AE 0300 08D7 0315 0062; # (a◌̕◌̀◌֮◌ࣗb; à◌֮◌ࣗ◌̕b; a◌֮◌̀◌ࣗ◌̕b; à◌֮◌ࣗ◌̕b; a◌֮◌̀◌ࣗ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC SMALL HIGH QAF, LATIN SMALL LETTER B +0061 08D7 0315 0300 05AE 0062;0061 05AE 08D7 0300 0315 0062;0061 05AE 08D7 0300 0315 0062;0061 05AE 08D7 0300 0315 0062;0061 05AE 08D7 0300 0315 0062; # (a◌ࣗ◌̕◌̀◌֮b; a◌֮◌ࣗ◌̀◌̕b; a◌֮◌ࣗ◌̀◌̕b; a◌֮◌ࣗ◌̀◌̕b; a◌֮◌ࣗ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC SMALL HIGH QAF, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 08D8 0062;00E0 05AE 08D8 0315 0062;0061 05AE 0300 08D8 0315 0062;00E0 05AE 08D8 0315 0062;0061 05AE 0300 08D8 0315 0062; # (a◌̕◌̀◌֮◌ࣘb; à◌֮◌ࣘ◌̕b; a◌֮◌̀◌ࣘ◌̕b; à◌֮◌ࣘ◌̕b; a◌֮◌̀◌ࣘ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC SMALL HIGH NOON WITH KASRA, LATIN SMALL LETTER B +0061 08D8 0315 0300 05AE 0062;0061 05AE 08D8 0300 0315 0062;0061 05AE 08D8 0300 0315 0062;0061 05AE 08D8 0300 0315 0062;0061 05AE 08D8 0300 0315 0062; # (a◌ࣘ◌̕◌̀◌֮b; a◌֮◌ࣘ◌̀◌̕b; a◌֮◌ࣘ◌̀◌̕b; a◌֮◌ࣘ◌̀◌̕b; a◌֮◌ࣘ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC SMALL HIGH NOON WITH KASRA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 08D9 0062;00E0 05AE 08D9 0315 0062;0061 05AE 0300 08D9 0315 0062;00E0 05AE 08D9 0315 0062;0061 05AE 0300 08D9 0315 0062; # (a◌̕◌̀◌֮◌ࣙb; à◌֮◌ࣙ◌̕b; a◌֮◌̀◌ࣙ◌̕b; à◌֮◌ࣙ◌̕b; a◌֮◌̀◌ࣙ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC SMALL LOW NOON WITH KASRA, LATIN SMALL LETTER B +0061 08D9 0315 0300 05AE 0062;0061 05AE 08D9 0300 0315 0062;0061 05AE 08D9 0300 0315 0062;0061 05AE 08D9 0300 0315 0062;0061 05AE 08D9 0300 0315 0062; # (a◌ࣙ◌̕◌̀◌֮b; a◌֮◌ࣙ◌̀◌̕b; a◌֮◌ࣙ◌̀◌̕b; a◌֮◌ࣙ◌̀◌̕b; a◌֮◌ࣙ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC SMALL LOW NOON WITH KASRA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 08DA 0062;00E0 05AE 08DA 0315 0062;0061 05AE 0300 08DA 0315 0062;00E0 05AE 08DA 0315 0062;0061 05AE 0300 08DA 0315 0062; # (a◌̕◌̀◌֮◌ࣚb; à◌֮◌ࣚ◌̕b; a◌֮◌̀◌ࣚ◌̕b; à◌֮◌ࣚ◌̕b; a◌֮◌̀◌ࣚ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC SMALL HIGH WORD ATH-THALATHA, LATIN SMALL LETTER B +0061 08DA 0315 0300 05AE 0062;0061 05AE 08DA 0300 0315 0062;0061 05AE 08DA 0300 0315 0062;0061 05AE 08DA 0300 0315 0062;0061 05AE 08DA 0300 0315 0062; # (a◌ࣚ◌̕◌̀◌֮b; a◌֮◌ࣚ◌̀◌̕b; a◌֮◌ࣚ◌̀◌̕b; a◌֮◌ࣚ◌̀◌̕b; a◌֮◌ࣚ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC SMALL HIGH WORD ATH-THALATHA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 08DB 0062;00E0 05AE 08DB 0315 0062;0061 05AE 0300 08DB 0315 0062;00E0 05AE 08DB 0315 0062;0061 05AE 0300 08DB 0315 0062; # (a◌̕◌̀◌֮◌ࣛb; à◌֮◌ࣛ◌̕b; a◌֮◌̀◌ࣛ◌̕b; à◌֮◌ࣛ◌̕b; a◌֮◌̀◌ࣛ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC SMALL HIGH WORD AS-SAJDA, LATIN SMALL LETTER B +0061 08DB 0315 0300 05AE 0062;0061 05AE 08DB 0300 0315 0062;0061 05AE 08DB 0300 0315 0062;0061 05AE 08DB 0300 0315 0062;0061 05AE 08DB 0300 0315 0062; # (a◌ࣛ◌̕◌̀◌֮b; a◌֮◌ࣛ◌̀◌̕b; a◌֮◌ࣛ◌̀◌̕b; a◌֮◌ࣛ◌̀◌̕b; a◌֮◌ࣛ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC SMALL HIGH WORD AS-SAJDA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 08DC 0062;00E0 05AE 08DC 0315 0062;0061 05AE 0300 08DC 0315 0062;00E0 05AE 08DC 0315 0062;0061 05AE 0300 08DC 0315 0062; # (a◌̕◌̀◌֮◌ࣜb; à◌֮◌ࣜ◌̕b; a◌֮◌̀◌ࣜ◌̕b; à◌֮◌ࣜ◌̕b; a◌֮◌̀◌ࣜ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC SMALL HIGH WORD AN-NISF, LATIN SMALL LETTER B +0061 08DC 0315 0300 05AE 0062;0061 05AE 08DC 0300 0315 0062;0061 05AE 08DC 0300 0315 0062;0061 05AE 08DC 0300 0315 0062;0061 05AE 08DC 0300 0315 0062; # (a◌ࣜ◌̕◌̀◌֮b; a◌֮◌ࣜ◌̀◌̕b; a◌֮◌ࣜ◌̀◌̕b; a◌֮◌ࣜ◌̀◌̕b; a◌֮◌ࣜ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC SMALL HIGH WORD AN-NISF, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 08DD 0062;00E0 05AE 08DD 0315 0062;0061 05AE 0300 08DD 0315 0062;00E0 05AE 08DD 0315 0062;0061 05AE 0300 08DD 0315 0062; # (a◌̕◌̀◌֮◌ࣝb; à◌֮◌ࣝ◌̕b; a◌֮◌̀◌ࣝ◌̕b; à◌֮◌ࣝ◌̕b; a◌֮◌̀◌ࣝ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC SMALL HIGH WORD SAKTA, LATIN SMALL LETTER B +0061 08DD 0315 0300 05AE 0062;0061 05AE 08DD 0300 0315 0062;0061 05AE 08DD 0300 0315 0062;0061 05AE 08DD 0300 0315 0062;0061 05AE 08DD 0300 0315 0062; # (a◌ࣝ◌̕◌̀◌֮b; a◌֮◌ࣝ◌̀◌̕b; a◌֮◌ࣝ◌̀◌̕b; a◌֮◌ࣝ◌̀◌̕b; a◌֮◌ࣝ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC SMALL HIGH WORD SAKTA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 08DE 0062;00E0 05AE 08DE 0315 0062;0061 05AE 0300 08DE 0315 0062;00E0 05AE 08DE 0315 0062;0061 05AE 0300 08DE 0315 0062; # (a◌̕◌̀◌֮◌ࣞb; à◌֮◌ࣞ◌̕b; a◌֮◌̀◌ࣞ◌̕b; à◌֮◌ࣞ◌̕b; a◌֮◌̀◌ࣞ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC SMALL HIGH WORD QIF, LATIN SMALL LETTER B +0061 08DE 0315 0300 05AE 0062;0061 05AE 08DE 0300 0315 0062;0061 05AE 08DE 0300 0315 0062;0061 05AE 08DE 0300 0315 0062;0061 05AE 08DE 0300 0315 0062; # (a◌ࣞ◌̕◌̀◌֮b; a◌֮◌ࣞ◌̀◌̕b; a◌֮◌ࣞ◌̀◌̕b; a◌֮◌ࣞ◌̀◌̕b; a◌֮◌ࣞ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC SMALL HIGH WORD QIF, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 08DF 0062;00E0 05AE 08DF 0315 0062;0061 05AE 0300 08DF 0315 0062;00E0 05AE 08DF 0315 0062;0061 05AE 0300 08DF 0315 0062; # (a◌̕◌̀◌֮◌ࣟb; à◌֮◌ࣟ◌̕b; a◌֮◌̀◌ࣟ◌̕b; à◌֮◌ࣟ◌̕b; a◌֮◌̀◌ࣟ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC SMALL HIGH WORD WAQFA, LATIN SMALL LETTER B +0061 08DF 0315 0300 05AE 0062;0061 05AE 08DF 0300 0315 0062;0061 05AE 08DF 0300 0315 0062;0061 05AE 08DF 0300 0315 0062;0061 05AE 08DF 0300 0315 0062; # (a◌ࣟ◌̕◌̀◌֮b; a◌֮◌ࣟ◌̀◌̕b; a◌֮◌ࣟ◌̀◌̕b; a◌֮◌ࣟ◌̀◌̕b; a◌֮◌ࣟ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC SMALL HIGH WORD WAQFA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 08E0 0062;00E0 05AE 08E0 0315 0062;0061 05AE 0300 08E0 0315 0062;00E0 05AE 08E0 0315 0062;0061 05AE 0300 08E0 0315 0062; # (a◌̕◌̀◌֮◌࣠b; à◌֮◌࣠◌̕b; a◌֮◌̀◌࣠◌̕b; à◌֮◌࣠◌̕b; a◌֮◌̀◌࣠◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC SMALL HIGH FOOTNOTE MARKER, LATIN SMALL LETTER B +0061 08E0 0315 0300 05AE 0062;0061 05AE 08E0 0300 0315 0062;0061 05AE 08E0 0300 0315 0062;0061 05AE 08E0 0300 0315 0062;0061 05AE 08E0 0300 0315 0062; # (a◌࣠◌̕◌̀◌֮b; a◌֮◌࣠◌̀◌̕b; a◌֮◌࣠◌̀◌̕b; a◌֮◌࣠◌̀◌̕b; a◌֮◌࣠◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC SMALL HIGH FOOTNOTE MARKER, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 08E1 0062;00E0 05AE 08E1 0315 0062;0061 05AE 0300 08E1 0315 0062;00E0 05AE 08E1 0315 0062;0061 05AE 0300 08E1 0315 0062; # (a◌̕◌̀◌֮◌࣡b; à◌֮◌࣡◌̕b; a◌֮◌̀◌࣡◌̕b; à◌֮◌࣡◌̕b; a◌֮◌̀◌࣡◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC SMALL HIGH SIGN SAFHA, LATIN SMALL LETTER B +0061 08E1 0315 0300 05AE 0062;0061 05AE 08E1 0300 0315 0062;0061 05AE 08E1 0300 0315 0062;0061 05AE 08E1 0300 0315 0062;0061 05AE 08E1 0300 0315 0062; # (a◌࣡◌̕◌̀◌֮b; a◌֮◌࣡◌̀◌̕b; a◌֮◌࣡◌̀◌̕b; a◌֮◌࣡◌̀◌̕b; a◌֮◌࣡◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC SMALL HIGH SIGN SAFHA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 059A 0316 302A 08E3 0062;0061 302A 0316 08E3 059A 0062;0061 302A 0316 08E3 059A 0062;0061 302A 0316 08E3 059A 0062;0061 302A 0316 08E3 059A 0062; # (a◌֚◌̖◌〪◌ࣣb; a◌〪◌̖◌ࣣ◌֚b; a◌〪◌̖◌ࣣ◌֚b; a◌〪◌̖◌ࣣ◌֚b; a◌〪◌̖◌ࣣ◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, ARABIC TURNED DAMMA BELOW, LATIN SMALL LETTER B +0061 08E3 059A 0316 302A 0062;0061 302A 08E3 0316 059A 0062;0061 302A 08E3 0316 059A 0062;0061 302A 08E3 0316 059A 0062;0061 302A 08E3 0316 059A 0062; # (a◌ࣣ◌֚◌̖◌〪b; a◌〪◌ࣣ◌̖◌֚b; a◌〪◌ࣣ◌̖◌֚b; a◌〪◌ࣣ◌̖◌֚b; a◌〪◌ࣣ◌̖◌֚b; ) LATIN SMALL LETTER A, ARABIC TURNED DAMMA BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B 0061 0315 0300 05AE 08E4 0062;00E0 05AE 08E4 0315 0062;0061 05AE 0300 08E4 0315 0062;00E0 05AE 08E4 0315 0062;0061 05AE 0300 08E4 0315 0062; # (a◌̕◌̀◌֮◌ࣤb; à◌֮◌ࣤ◌̕b; a◌֮◌̀◌ࣤ◌̕b; à◌֮◌ࣤ◌̕b; a◌֮◌̀◌ࣤ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC CURLY FATHA, LATIN SMALL LETTER B 0061 08E4 0315 0300 05AE 0062;0061 05AE 08E4 0300 0315 0062;0061 05AE 08E4 0300 0315 0062;0061 05AE 08E4 0300 0315 0062;0061 05AE 08E4 0300 0315 0062; # (a◌ࣤ◌̕◌̀◌֮b; a◌֮◌ࣤ◌̀◌̕b; a◌֮◌ࣤ◌̀◌̕b; a◌֮◌ࣤ◌̀◌̕b; a◌֮◌ࣤ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC CURLY FATHA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B 0061 0315 0300 05AE 08E5 0062;00E0 05AE 08E5 0315 0062;0061 05AE 0300 08E5 0315 0062;00E0 05AE 08E5 0315 0062;0061 05AE 0300 08E5 0315 0062; # (a◌̕◌̀◌֮◌ࣥb; à◌֮◌ࣥ◌̕b; a◌֮◌̀◌ࣥ◌̕b; à◌֮◌ࣥ◌̕b; a◌֮◌̀◌ࣥ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC CURLY DAMMA, LATIN SMALL LETTER B @@ -17619,6 +17653,10 @@ FFEE;FFEE;FFEE;25CB;25CB; # (○; ○; ○; ○; ○; ) HALFWIDTH WHITE CIRCLE 0061 0CBC 3099 093C 0334 0062;0061 0334 0CBC 093C 3099 0062;0061 0334 0CBC 093C 3099 0062;0061 0334 0CBC 093C 3099 0062;0061 0334 0CBC 093C 3099 0062; # (a◌಼◌゙◌़◌̴b; a◌̴◌಼◌़◌゙b; a◌̴◌಼◌़◌゙b; a◌̴◌಼◌़◌゙b; a◌̴◌಼◌़◌゙b; ) LATIN SMALL LETTER A, KANNADA SIGN NUKTA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, COMBINING TILDE OVERLAY, LATIN SMALL LETTER B 0061 05B0 094D 3099 0CCD 0062;0061 3099 094D 0CCD 05B0 0062;0061 3099 094D 0CCD 05B0 0062;0061 3099 094D 0CCD 05B0 0062;0061 3099 094D 0CCD 05B0 0062; # (a◌ְ◌्◌゙◌್b; a◌゙◌्◌್◌ְb; a◌゙◌्◌್◌ְb; a◌゙◌्◌್◌ְb; a◌゙◌्◌್◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, KANNADA SIGN VIRAMA, LATIN SMALL LETTER B 0061 0CCD 05B0 094D 3099 0062;0061 3099 0CCD 094D 05B0 0062;0061 3099 0CCD 094D 05B0 0062;0061 3099 0CCD 094D 05B0 0062;0061 3099 0CCD 094D 05B0 0062; # (a◌್◌ְ◌्◌゙b; a◌゙◌್◌्◌ְb; a◌゙◌್◌्◌ְb; a◌゙◌್◌्◌ְb; a◌゙◌್◌्◌ְb; ) LATIN SMALL LETTER A, KANNADA SIGN VIRAMA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B +0061 05B0 094D 3099 0D3B 0062;0061 3099 094D 0D3B 05B0 0062;0061 3099 094D 0D3B 05B0 0062;0061 3099 094D 0D3B 05B0 0062;0061 3099 094D 0D3B 05B0 0062; # (a◌ְ◌्◌゙◌഻b; a◌゙◌्◌഻◌ְb; a◌゙◌्◌഻◌ְb; a◌゙◌्◌഻◌ְb; a◌゙◌्◌഻◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, MALAYALAM SIGN VERTICAL BAR VIRAMA, LATIN SMALL LETTER B +0061 0D3B 05B0 094D 3099 0062;0061 3099 0D3B 094D 05B0 0062;0061 3099 0D3B 094D 05B0 0062;0061 3099 0D3B 094D 05B0 0062;0061 3099 0D3B 094D 05B0 0062; # (a◌഻◌ְ◌्◌゙b; a◌゙◌഻◌्◌ְb; a◌゙◌഻◌्◌ְb; a◌゙◌഻◌्◌ְb; a◌゙◌഻◌्◌ְb; ) LATIN SMALL LETTER A, MALAYALAM SIGN VERTICAL BAR VIRAMA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B +0061 05B0 094D 3099 0D3C 0062;0061 3099 094D 0D3C 05B0 0062;0061 3099 094D 0D3C 05B0 0062;0061 3099 094D 0D3C 05B0 0062;0061 3099 094D 0D3C 05B0 0062; # (a◌ְ◌्◌゙◌഼b; a◌゙◌्◌഼◌ְb; a◌゙◌्◌഼◌ְb; a◌゙◌्◌഼◌ְb; a◌゙◌्◌഼◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, MALAYALAM SIGN CIRCULAR VIRAMA, LATIN SMALL LETTER B +0061 0D3C 05B0 094D 3099 0062;0061 3099 0D3C 094D 05B0 0062;0061 3099 0D3C 094D 05B0 0062;0061 3099 0D3C 094D 05B0 0062;0061 3099 0D3C 094D 05B0 0062; # (a◌഼◌ְ◌्◌゙b; a◌゙◌഼◌्◌ְb; a◌゙◌഼◌्◌ְb; a◌゙◌഼◌्◌ְb; a◌゙◌഼◌्◌ְb; ) LATIN SMALL LETTER A, MALAYALAM SIGN CIRCULAR VIRAMA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B 0061 05B0 094D 3099 0D4D 0062;0061 3099 094D 0D4D 05B0 0062;0061 3099 094D 0D4D 05B0 0062;0061 3099 094D 0D4D 05B0 0062;0061 3099 094D 0D4D 05B0 0062; # (a◌ְ◌्◌゙◌്b; a◌゙◌्◌്◌ְb; a◌゙◌्◌്◌ְb; a◌゙◌्◌്◌ְb; a◌゙◌्◌്◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, MALAYALAM SIGN VIRAMA, LATIN SMALL LETTER B 0061 0D4D 05B0 094D 3099 0062;0061 3099 0D4D 094D 05B0 0062;0061 3099 0D4D 094D 05B0 0062;0061 3099 0D4D 094D 05B0 0062;0061 3099 0D4D 094D 05B0 0062; # (a◌്◌ְ◌्◌゙b; a◌゙◌്◌्◌ְb; a◌゙◌്◌्◌ְb; a◌゙◌്◌्◌ְb; a◌゙◌്◌्◌ְb; ) LATIN SMALL LETTER A, MALAYALAM SIGN VIRAMA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B 0061 05B0 094D 3099 0DCA 0062;0061 3099 094D 0DCA 05B0 0062;0061 3099 094D 0DCA 05B0 0062;0061 3099 094D 0DCA 05B0 0062;0061 3099 094D 0DCA 05B0 0062; # (a◌ְ◌्◌゙◌්b; a◌゙◌्◌්◌ְb; a◌゙◌्◌්◌ְb; a◌゙◌्◌්◌ְb; a◌゙◌्◌්◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, SINHALA SIGN AL-LAKUNA, LATIN SMALL LETTER B @@ -17965,6 +18003,16 @@ FFEE;FFEE;FFEE;25CB;25CB; # (○; ○; ○; ○; ○; ) HALFWIDTH WHITE CIRCLE 0061 1DF4 0315 0300 05AE 0062;0061 05AE 1DF4 0300 0315 0062;0061 05AE 1DF4 0300 0315 0062;0061 05AE 1DF4 0300 0315 0062;0061 05AE 1DF4 0300 0315 0062; # (a◌ᷴ◌̕◌̀◌֮b; a◌֮◌ᷴ◌̀◌̕b; a◌֮◌ᷴ◌̀◌̕b; a◌֮◌ᷴ◌̀◌̕b; a◌֮◌ᷴ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING LATIN SMALL LETTER U WITH DIAERESIS, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B 0061 0315 0300 05AE 1DF5 0062;00E0 05AE 1DF5 0315 0062;0061 05AE 0300 1DF5 0315 0062;00E0 05AE 1DF5 0315 0062;0061 05AE 0300 1DF5 0315 0062; # (a◌̕◌̀◌֮◌᷵b; à◌֮◌᷵◌̕b; a◌֮◌̀◌᷵◌̕b; à◌֮◌᷵◌̕b; a◌֮◌̀◌᷵◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING UP TACK ABOVE, LATIN SMALL LETTER B 0061 1DF5 0315 0300 05AE 0062;0061 05AE 1DF5 0300 0315 0062;0061 05AE 1DF5 0300 0315 0062;0061 05AE 1DF5 0300 0315 0062;0061 05AE 1DF5 0300 0315 0062; # (a◌᷵◌̕◌̀◌֮b; a◌֮◌᷵◌̀◌̕b; a◌֮◌᷵◌̀◌̕b; a◌֮◌᷵◌̀◌̕b; a◌֮◌᷵◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING UP TACK ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 035C 0315 0300 1DF6 0062;00E0 0315 1DF6 035C 0062;0061 0300 0315 1DF6 035C 0062;00E0 0315 1DF6 035C 0062;0061 0300 0315 1DF6 035C 0062; # (a◌͜◌̕◌̀◌᷶b; à◌̕◌᷶◌͜b; a◌̀◌̕◌᷶◌͜b; à◌̕◌᷶◌͜b; a◌̀◌̕◌᷶◌͜b; ) LATIN SMALL LETTER A, COMBINING DOUBLE BREVE BELOW, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, COMBINING KAVYKA ABOVE RIGHT, LATIN SMALL LETTER B +0061 1DF6 035C 0315 0300 0062;00E0 1DF6 0315 035C 0062;0061 0300 1DF6 0315 035C 0062;00E0 1DF6 0315 035C 0062;0061 0300 1DF6 0315 035C 0062; # (a◌᷶◌͜◌̕◌̀b; à◌᷶◌̕◌͜b; a◌̀◌᷶◌̕◌͜b; à◌᷶◌̕◌͜b; a◌̀◌᷶◌̕◌͜b; ) LATIN SMALL LETTER A, COMBINING KAVYKA ABOVE RIGHT, COMBINING DOUBLE BREVE BELOW, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, LATIN SMALL LETTER B +0061 0300 05AE 1D16D 1DF7 0062;00E0 1D16D 05AE 1DF7 0062;0061 1D16D 05AE 1DF7 0300 0062;00E0 1D16D 05AE 1DF7 0062;0061 1D16D 05AE 1DF7 0300 0062; # (a◌̀◌𝅭֮◌᷷b; à𝅭◌֮◌᷷b; a𝅭◌֮◌᷷◌̀b; à𝅭◌֮◌᷷b; a𝅭◌֮◌᷷◌̀b; ) LATIN SMALL LETTER A, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, MUSICAL SYMBOL COMBINING AUGMENTATION DOT, COMBINING KAVYKA ABOVE LEFT, LATIN SMALL LETTER B +0061 1DF7 0300 05AE 1D16D 0062;00E0 1D16D 1DF7 05AE 0062;0061 1D16D 1DF7 05AE 0300 0062;00E0 1D16D 1DF7 05AE 0062;0061 1D16D 1DF7 05AE 0300 0062; # (a◌᷷◌̀◌𝅭֮b; à𝅭◌᷷◌֮b; a𝅭◌᷷◌֮◌̀b; à𝅭◌᷷◌֮b; a𝅭◌᷷◌֮◌̀b; ) LATIN SMALL LETTER A, COMBINING KAVYKA ABOVE LEFT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, MUSICAL SYMBOL COMBINING AUGMENTATION DOT, LATIN SMALL LETTER B +0061 0300 05AE 1D16D 1DF8 0062;00E0 1D16D 05AE 1DF8 0062;0061 1D16D 05AE 1DF8 0300 0062;00E0 1D16D 05AE 1DF8 0062;0061 1D16D 05AE 1DF8 0300 0062; # (a◌̀◌𝅭֮◌᷸b; à𝅭◌֮◌᷸b; a𝅭◌֮◌᷸◌̀b; à𝅭◌֮◌᷸b; a𝅭◌֮◌᷸◌̀b; ) LATIN SMALL LETTER A, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, MUSICAL SYMBOL COMBINING AUGMENTATION DOT, COMBINING DOT ABOVE LEFT, LATIN SMALL LETTER B +0061 1DF8 0300 05AE 1D16D 0062;00E0 1D16D 1DF8 05AE 0062;0061 1D16D 1DF8 05AE 0300 0062;00E0 1D16D 1DF8 05AE 0062;0061 1D16D 1DF8 05AE 0300 0062; # (a◌᷸◌̀◌𝅭֮b; à𝅭◌᷸◌֮b; a𝅭◌᷸◌֮◌̀b; à𝅭◌᷸◌֮b; a𝅭◌᷸◌֮◌̀b; ) LATIN SMALL LETTER A, COMBINING DOT ABOVE LEFT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, MUSICAL SYMBOL COMBINING AUGMENTATION DOT, LATIN SMALL LETTER B +0061 059A 0316 302A 1DF9 0062;0061 302A 0316 1DF9 059A 0062;0061 302A 0316 1DF9 059A 0062;0061 302A 0316 1DF9 059A 0062;0061 302A 0316 1DF9 059A 0062; # (a◌֚◌̖◌〪◌᷹b; a◌〪◌̖◌᷹◌֚b; a◌〪◌̖◌᷹◌֚b; a◌〪◌̖◌᷹◌֚b; a◌〪◌̖◌᷹◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING WIDE INVERTED BRIDGE BELOW, LATIN SMALL LETTER B +0061 1DF9 059A 0316 302A 0062;0061 302A 1DF9 0316 059A 0062;0061 302A 1DF9 0316 059A 0062;0061 302A 1DF9 0316 059A 0062;0061 302A 1DF9 0316 059A 0062; # (a◌᷹◌֚◌̖◌〪b; a◌〪◌᷹◌̖◌֚b; a◌〪◌᷹◌̖◌֚b; a◌〪◌᷹◌̖◌֚b; a◌〪◌᷹◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING WIDE INVERTED BRIDGE BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 0315 0300 05AE 1DFB 0062;00E0 05AE 1DFB 0315 0062;0061 05AE 0300 1DFB 0315 0062;00E0 05AE 1DFB 0315 0062;0061 05AE 0300 1DFB 0315 0062; # (a◌̕◌̀◌֮◌᷻b; à◌֮◌᷻◌̕b; a◌֮◌̀◌᷻◌̕b; à◌֮◌᷻◌̕b; a◌֮◌̀◌᷻◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING DELETION MARK, LATIN SMALL LETTER B +0061 1DFB 0315 0300 05AE 0062;0061 05AE 1DFB 0300 0315 0062;0061 05AE 1DFB 0300 0315 0062;0061 05AE 1DFB 0300 0315 0062;0061 05AE 1DFB 0300 0315 0062; # (a◌᷻◌̕◌̀◌֮b; a◌֮◌᷻◌̀◌̕b; a◌֮◌᷻◌̀◌̕b; a◌֮◌᷻◌̀◌̕b; a◌֮◌᷻◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING DELETION MARK, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B 0061 035D 035C 0315 1DFC 0062;0061 0315 035C 1DFC 035D 0062;0061 0315 035C 1DFC 035D 0062;0061 0315 035C 1DFC 035D 0062;0061 0315 035C 1DFC 035D 0062; # (a◌͝◌͜◌̕◌᷼b; a◌̕◌͜◌᷼◌͝b; a◌̕◌͜◌᷼◌͝b; a◌̕◌͜◌᷼◌͝b; a◌̕◌͜◌᷼◌͝b; ) LATIN SMALL LETTER A, COMBINING DOUBLE BREVE, COMBINING DOUBLE BREVE BELOW, COMBINING COMMA ABOVE RIGHT, COMBINING DOUBLE INVERTED BREVE BELOW, LATIN SMALL LETTER B 0061 1DFC 035D 035C 0315 0062;0061 0315 1DFC 035C 035D 0062;0061 0315 1DFC 035C 035D 0062;0061 0315 1DFC 035C 035D 0062;0061 0315 1DFC 035C 035D 0062; # (a◌᷼◌͝◌͜◌̕b; a◌̕◌᷼◌͜◌͝b; a◌̕◌᷼◌͜◌͝b; a◌̕◌᷼◌͜◌͝b; a◌̕◌᷼◌͜◌͝b; ) LATIN SMALL LETTER A, COMBINING DOUBLE INVERTED BREVE BELOW, COMBINING DOUBLE BREVE, COMBINING DOUBLE BREVE BELOW, COMBINING COMMA ABOVE RIGHT, LATIN SMALL LETTER B 0061 059A 0316 302A 1DFD 0062;0061 302A 0316 1DFD 059A 0062;0061 302A 0316 1DFD 059A 0062;0061 302A 0316 1DFD 059A 0062;0061 302A 0316 1DFD 059A 0062; # (a◌֚◌̖◌〪◌᷽b; a◌〪◌̖◌᷽◌֚b; a◌〪◌̖◌᷽◌֚b; a◌〪◌̖◌᷽◌֚b; a◌〪◌̖◌᷽◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING ALMOST EQUAL TO BELOW, LATIN SMALL LETTER B @@ -18135,6 +18183,8 @@ FFEE;FFEE;FFEE;25CB;25CB; # (○; ○; ○; ○; ○; ) HALFWIDTH WHITE CIRCLE 0061 A67C 0315 0300 05AE 0062;0061 05AE A67C 0300 0315 0062;0061 05AE A67C 0300 0315 0062;0061 05AE A67C 0300 0315 0062;0061 05AE A67C 0300 0315 0062; # (a◌꙼◌̕◌̀◌֮b; a◌֮◌꙼◌̀◌̕b; a◌֮◌꙼◌̀◌̕b; a◌֮◌꙼◌̀◌̕b; a◌֮◌꙼◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING CYRILLIC KAVYKA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B 0061 0315 0300 05AE A67D 0062;00E0 05AE A67D 0315 0062;0061 05AE 0300 A67D 0315 0062;00E0 05AE A67D 0315 0062;0061 05AE 0300 A67D 0315 0062; # (a◌̕◌̀◌֮◌꙽b; à◌֮◌꙽◌̕b; a◌֮◌̀◌꙽◌̕b; à◌֮◌꙽◌̕b; a◌֮◌̀◌꙽◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING CYRILLIC PAYEROK, LATIN SMALL LETTER B 0061 A67D 0315 0300 05AE 0062;0061 05AE A67D 0300 0315 0062;0061 05AE A67D 0300 0315 0062;0061 05AE A67D 0300 0315 0062;0061 05AE A67D 0300 0315 0062; # (a◌꙽◌̕◌̀◌֮b; a◌֮◌꙽◌̀◌̕b; a◌֮◌꙽◌̀◌̕b; a◌֮◌꙽◌̀◌̕b; a◌֮◌꙽◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING CYRILLIC PAYEROK, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE A69E 0062;00E0 05AE A69E 0315 0062;0061 05AE 0300 A69E 0315 0062;00E0 05AE A69E 0315 0062;0061 05AE 0300 A69E 0315 0062; # (a◌̕◌̀◌֮◌ꚞb; à◌֮◌ꚞ◌̕b; a◌֮◌̀◌ꚞ◌̕b; à◌֮◌ꚞ◌̕b; a◌֮◌̀◌ꚞ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING CYRILLIC LETTER EF, LATIN SMALL LETTER B +0061 A69E 0315 0300 05AE 0062;0061 05AE A69E 0300 0315 0062;0061 05AE A69E 0300 0315 0062;0061 05AE A69E 0300 0315 0062;0061 05AE A69E 0300 0315 0062; # (a◌ꚞ◌̕◌̀◌֮b; a◌֮◌ꚞ◌̀◌̕b; a◌֮◌ꚞ◌̀◌̕b; a◌֮◌ꚞ◌̀◌̕b; a◌֮◌ꚞ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING CYRILLIC LETTER EF, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B 0061 0315 0300 05AE A69F 0062;00E0 05AE A69F 0315 0062;0061 05AE 0300 A69F 0315 0062;00E0 05AE A69F 0315 0062;0061 05AE 0300 A69F 0315 0062; # (a◌̕◌̀◌֮◌ꚟb; à◌֮◌ꚟ◌̕b; a◌֮◌̀◌ꚟ◌̕b; à◌֮◌ꚟ◌̕b; a◌֮◌̀◌ꚟ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING CYRILLIC LETTER IOTIFIED E, LATIN SMALL LETTER B 0061 A69F 0315 0300 05AE 0062;0061 05AE A69F 0300 0315 0062;0061 05AE A69F 0300 0315 0062;0061 05AE A69F 0300 0315 0062;0061 05AE A69F 0300 0315 0062; # (a◌ꚟ◌̕◌̀◌֮b; a◌֮◌ꚟ◌̀◌̕b; a◌֮◌ꚟ◌̀◌̕b; a◌֮◌ꚟ◌̀◌̕b; a◌֮◌ꚟ◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING CYRILLIC LETTER IOTIFIED E, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B 0061 0315 0300 05AE A6F0 0062;00E0 05AE A6F0 0315 0062;0061 05AE 0300 A6F0 0315 0062;00E0 05AE A6F0 0315 0062;0061 05AE 0300 A6F0 0315 0062; # (a◌̕◌̀◌֮◌꛰b; à◌֮◌꛰◌̕b; a◌֮◌̀◌꛰◌̕b; à◌֮◌꛰◌̕b; a◌֮◌̀◌꛰◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, BAMUM COMBINING MARK KOQNDON, LATIN SMALL LETTER B @@ -18245,6 +18295,10 @@ FFEE;FFEE;FFEE;25CB;25CB; # (○; ○; ○; ○; ○; ) HALFWIDTH WHITE CIRCLE 0061 FE2C 059A 0316 302A 0062;0061 302A FE2C 0316 059A 0062;0061 302A FE2C 0316 059A 0062;0061 302A FE2C 0316 059A 0062;0061 302A FE2C 0316 059A 0062; # (a◌︬◌֚◌̖◌〪b; a◌〪◌︬◌̖◌֚b; a◌〪◌︬◌̖◌֚b; a◌〪◌︬◌̖◌֚b; a◌〪◌︬◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING MACRON RIGHT HALF BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B 0061 059A 0316 302A FE2D 0062;0061 302A 0316 FE2D 059A 0062;0061 302A 0316 FE2D 059A 0062;0061 302A 0316 FE2D 059A 0062;0061 302A 0316 FE2D 059A 0062; # (a◌֚◌̖◌〪◌︭b; a◌〪◌̖◌︭◌֚b; a◌〪◌̖◌︭◌֚b; a◌〪◌̖◌︭◌֚b; a◌〪◌̖◌︭◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COMBINING CONJOINING MACRON BELOW, LATIN SMALL LETTER B 0061 FE2D 059A 0316 302A 0062;0061 302A FE2D 0316 059A 0062;0061 302A FE2D 0316 059A 0062;0061 302A FE2D 0316 059A 0062;0061 302A FE2D 0316 059A 0062; # (a◌︭◌֚◌̖◌〪b; a◌〪◌︭◌̖◌֚b; a◌〪◌︭◌̖◌֚b; a◌〪◌︭◌̖◌֚b; a◌〪◌︭◌̖◌֚b; ) LATIN SMALL LETTER A, COMBINING CONJOINING MACRON BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 0315 0300 05AE FE2E 0062;00E0 05AE FE2E 0315 0062;0061 05AE 0300 FE2E 0315 0062;00E0 05AE FE2E 0315 0062;0061 05AE 0300 FE2E 0315 0062; # (a◌̕◌̀◌֮◌︮b; à◌֮◌︮◌̕b; a◌֮◌̀◌︮◌̕b; à◌֮◌︮◌̕b; a◌֮◌̀◌︮◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING CYRILLIC TITLO LEFT HALF, LATIN SMALL LETTER B +0061 FE2E 0315 0300 05AE 0062;0061 05AE FE2E 0300 0315 0062;0061 05AE FE2E 0300 0315 0062;0061 05AE FE2E 0300 0315 0062;0061 05AE FE2E 0300 0315 0062; # (a◌︮◌̕◌̀◌֮b; a◌֮◌︮◌̀◌̕b; a◌֮◌︮◌̀◌̕b; a◌֮◌︮◌̀◌̕b; a◌֮◌︮◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING CYRILLIC TITLO LEFT HALF, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE FE2F 0062;00E0 05AE FE2F 0315 0062;0061 05AE 0300 FE2F 0315 0062;00E0 05AE FE2F 0315 0062;0061 05AE 0300 FE2F 0315 0062; # (a◌̕◌̀◌֮◌︯b; à◌֮◌︯◌̕b; a◌֮◌̀◌︯◌̕b; à◌֮◌︯◌̕b; a◌֮◌̀◌︯◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING CYRILLIC TITLO RIGHT HALF, LATIN SMALL LETTER B +0061 FE2F 0315 0300 05AE 0062;0061 05AE FE2F 0300 0315 0062;0061 05AE FE2F 0300 0315 0062;0061 05AE FE2F 0300 0315 0062;0061 05AE FE2F 0300 0315 0062; # (a◌︯◌̕◌̀◌֮b; a◌֮◌︯◌̀◌̕b; a◌֮◌︯◌̀◌̕b; a◌֮◌︯◌̀◌̕b; a◌֮◌︯◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING CYRILLIC TITLO RIGHT HALF, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B 0061 059A 0316 302A 101FD 0062;0061 302A 0316 101FD 059A 0062;0061 302A 0316 101FD 059A 0062;0061 302A 0316 101FD 059A 0062;0061 302A 0316 101FD 059A 0062; # (a◌֚◌̖◌〪◌𐇽b; a◌〪◌̖◌𐇽◌֚b; a◌〪◌̖◌𐇽◌֚b; a◌〪◌̖◌𐇽◌֚b; a◌〪◌̖◌𐇽◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, PHAISTOS DISC SIGN COMBINING OBLIQUE STROKE, LATIN SMALL LETTER B 0061 101FD 059A 0316 302A 0062;0061 302A 101FD 0316 059A 0062;0061 302A 101FD 0316 059A 0062;0061 302A 101FD 0316 059A 0062;0061 302A 101FD 0316 059A 0062; # (a◌𐇽◌֚◌̖◌〪b; a◌〪◌𐇽◌̖◌֚b; a◌〪◌𐇽◌̖◌֚b; a◌〪◌𐇽◌̖◌֚b; a◌〪◌𐇽◌̖◌֚b; ) LATIN SMALL LETTER A, PHAISTOS DISC SIGN COMBINING OBLIQUE STROKE, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B 0061 059A 0316 302A 102E0 0062;0061 302A 0316 102E0 059A 0062;0061 302A 0316 102E0 059A 0062;0061 302A 0316 102E0 059A 0062;0061 302A 0316 102E0 059A 0062; # (a◌֚◌̖◌〪◌𐋠b; a◌〪◌̖◌𐋠◌֚b; a◌〪◌̖◌𐋠◌֚b; a◌〪◌̖◌𐋠◌֚b; a◌〪◌̖◌𐋠◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, COPTIC EPACT THOUSANDS MARK, LATIN SMALL LETTER B @@ -18297,6 +18351,8 @@ FFEE;FFEE;FFEE;25CB;25CB; # (○; ○; ○; ○; ○; ) HALFWIDTH WHITE CIRCLE 0061 11173 3099 093C 0334 0062;0061 0334 11173 093C 3099 0062;0061 0334 11173 093C 3099 0062;0061 0334 11173 093C 3099 0062;0061 0334 11173 093C 3099 0062; # (a◌𑅳◌゙◌़◌̴b; a◌̴◌𑅳◌़◌゙b; a◌̴◌𑅳◌़◌゙b; a◌̴◌𑅳◌़◌゙b; a◌̴◌𑅳◌़◌゙b; ) LATIN SMALL LETTER A, MAHAJANI SIGN NUKTA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, COMBINING TILDE OVERLAY, LATIN SMALL LETTER B 0061 05B0 094D 3099 111C0 0062;0061 3099 094D 111C0 05B0 0062;0061 3099 094D 111C0 05B0 0062;0061 3099 094D 111C0 05B0 0062;0061 3099 094D 111C0 05B0 0062; # (a◌ְ◌्◌゙𑇀b; a◌゙◌्𑇀◌ְb; a◌゙◌्𑇀◌ְb; a◌゙◌्𑇀◌ְb; a◌゙◌्𑇀◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, SHARADA SIGN VIRAMA, LATIN SMALL LETTER B 0061 111C0 05B0 094D 3099 0062;0061 3099 111C0 094D 05B0 0062;0061 3099 111C0 094D 05B0 0062;0061 3099 111C0 094D 05B0 0062;0061 3099 111C0 094D 05B0 0062; # (a𑇀◌ְ◌्◌゙b; a◌゙𑇀◌्◌ְb; a◌゙𑇀◌्◌ְb; a◌゙𑇀◌्◌ְb; a◌゙𑇀◌्◌ְb; ) LATIN SMALL LETTER A, SHARADA SIGN VIRAMA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B +0061 3099 093C 0334 111CA 0062;0061 0334 093C 111CA 3099 0062;0061 0334 093C 111CA 3099 0062;0061 0334 093C 111CA 3099 0062;0061 0334 093C 111CA 3099 0062; # (a◌゙◌़◌̴◌𑇊b; a◌̴◌़◌𑇊◌゙b; a◌̴◌़◌𑇊◌゙b; a◌̴◌़◌𑇊◌゙b; a◌̴◌़◌𑇊◌゙b; ) LATIN SMALL LETTER A, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, COMBINING TILDE OVERLAY, SHARADA SIGN NUKTA, LATIN SMALL LETTER B +0061 111CA 3099 093C 0334 0062;0061 0334 111CA 093C 3099 0062;0061 0334 111CA 093C 3099 0062;0061 0334 111CA 093C 3099 0062;0061 0334 111CA 093C 3099 0062; # (a◌𑇊◌゙◌़◌̴b; a◌̴◌𑇊◌़◌゙b; a◌̴◌𑇊◌़◌゙b; a◌̴◌𑇊◌़◌゙b; a◌̴◌𑇊◌़◌゙b; ) LATIN SMALL LETTER A, SHARADA SIGN NUKTA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, COMBINING TILDE OVERLAY, LATIN SMALL LETTER B 0061 05B0 094D 3099 11235 0062;0061 3099 094D 11235 05B0 0062;0061 3099 094D 11235 05B0 0062;0061 3099 094D 11235 05B0 0062;0061 3099 094D 11235 05B0 0062; # (a◌ְ◌्◌゙𑈵b; a◌゙◌्𑈵◌ְb; a◌゙◌्𑈵◌ְb; a◌゙◌्𑈵◌ְb; a◌゙◌्𑈵◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, KHOJKI SIGN VIRAMA, LATIN SMALL LETTER B 0061 11235 05B0 094D 3099 0062;0061 3099 11235 094D 05B0 0062;0061 3099 11235 094D 05B0 0062;0061 3099 11235 094D 05B0 0062;0061 3099 11235 094D 05B0 0062; # (a𑈵◌ְ◌्◌゙b; a◌゙𑈵◌्◌ְb; a◌゙𑈵◌्◌ְb; a◌゙𑈵◌्◌ְb; a◌゙𑈵◌्◌ְb; ) LATIN SMALL LETTER A, KHOJKI SIGN VIRAMA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B 0061 3099 093C 0334 11236 0062;0061 0334 093C 11236 3099 0062;0061 0334 093C 11236 3099 0062;0061 0334 093C 11236 3099 0062;0061 0334 093C 11236 3099 0062; # (a◌゙◌़◌̴◌𑈶b; a◌̴◌़◌𑈶◌゙b; a◌̴◌़◌𑈶◌゙b; a◌̴◌़◌𑈶◌゙b; a◌̴◌़◌𑈶◌゙b; ) LATIN SMALL LETTER A, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, COMBINING TILDE OVERLAY, KHOJKI SIGN NUKTA, LATIN SMALL LETTER B @@ -18333,6 +18389,10 @@ FFEE;FFEE;FFEE;25CB;25CB; # (○; ○; ○; ○; ○; ) HALFWIDTH WHITE CIRCLE 0061 11373 0315 0300 05AE 0062;0061 05AE 11373 0300 0315 0062;0061 05AE 11373 0300 0315 0062;0061 05AE 11373 0300 0315 0062;0061 05AE 11373 0300 0315 0062; # (a◌𑍳◌̕◌̀◌֮b; a◌֮◌𑍳◌̀◌̕b; a◌֮◌𑍳◌̀◌̕b; a◌֮◌𑍳◌̀◌̕b; a◌֮◌𑍳◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GRANTHA LETTER VI, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B 0061 0315 0300 05AE 11374 0062;00E0 05AE 11374 0315 0062;0061 05AE 0300 11374 0315 0062;00E0 05AE 11374 0315 0062;0061 05AE 0300 11374 0315 0062; # (a◌̕◌̀◌֮◌𑍴b; à◌֮◌𑍴◌̕b; a◌֮◌̀◌𑍴◌̕b; à◌֮◌𑍴◌̕b; a◌֮◌̀◌𑍴◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GRANTHA LETTER PA, LATIN SMALL LETTER B 0061 11374 0315 0300 05AE 0062;0061 05AE 11374 0300 0315 0062;0061 05AE 11374 0300 0315 0062;0061 05AE 11374 0300 0315 0062;0061 05AE 11374 0300 0315 0062; # (a◌𑍴◌̕◌̀◌֮b; a◌֮◌𑍴◌̀◌̕b; a◌֮◌𑍴◌̀◌̕b; a◌֮◌𑍴◌̀◌̕b; a◌֮◌𑍴◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GRANTHA LETTER PA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 05B0 094D 3099 11442 0062;0061 3099 094D 11442 05B0 0062;0061 3099 094D 11442 05B0 0062;0061 3099 094D 11442 05B0 0062;0061 3099 094D 11442 05B0 0062; # (a◌ְ◌्◌゙◌𑑂b; a◌゙◌्◌𑑂◌ְb; a◌゙◌्◌𑑂◌ְb; a◌゙◌्◌𑑂◌ְb; a◌゙◌्◌𑑂◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, NEWA SIGN VIRAMA, LATIN SMALL LETTER B +0061 11442 05B0 094D 3099 0062;0061 3099 11442 094D 05B0 0062;0061 3099 11442 094D 05B0 0062;0061 3099 11442 094D 05B0 0062;0061 3099 11442 094D 05B0 0062; # (a◌𑑂◌ְ◌्◌゙b; a◌゙◌𑑂◌्◌ְb; a◌゙◌𑑂◌्◌ְb; a◌゙◌𑑂◌्◌ְb; a◌゙◌𑑂◌्◌ְb; ) LATIN SMALL LETTER A, NEWA SIGN VIRAMA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B +0061 3099 093C 0334 11446 0062;0061 0334 093C 11446 3099 0062;0061 0334 093C 11446 3099 0062;0061 0334 093C 11446 3099 0062;0061 0334 093C 11446 3099 0062; # (a◌゙◌़◌̴◌𑑆b; a◌̴◌़◌𑑆◌゙b; a◌̴◌़◌𑑆◌゙b; a◌̴◌़◌𑑆◌゙b; a◌̴◌़◌𑑆◌゙b; ) LATIN SMALL LETTER A, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, COMBINING TILDE OVERLAY, NEWA SIGN NUKTA, LATIN SMALL LETTER B +0061 11446 3099 093C 0334 0062;0061 0334 11446 093C 3099 0062;0061 0334 11446 093C 3099 0062;0061 0334 11446 093C 3099 0062;0061 0334 11446 093C 3099 0062; # (a◌𑑆◌゙◌़◌̴b; a◌̴◌𑑆◌़◌゙b; a◌̴◌𑑆◌़◌゙b; a◌̴◌𑑆◌़◌゙b; a◌̴◌𑑆◌़◌゙b; ) LATIN SMALL LETTER A, NEWA SIGN NUKTA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, COMBINING TILDE OVERLAY, LATIN SMALL LETTER B 0061 05B0 094D 3099 114C2 0062;0061 3099 094D 114C2 05B0 0062;0061 3099 094D 114C2 05B0 0062;0061 3099 094D 114C2 05B0 0062;0061 3099 094D 114C2 05B0 0062; # (a◌ְ◌्◌゙◌𑓂b; a◌゙◌्◌𑓂◌ְb; a◌゙◌्◌𑓂◌ְb; a◌゙◌्◌𑓂◌ְb; a◌゙◌्◌𑓂◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, TIRHUTA SIGN VIRAMA, LATIN SMALL LETTER B 0061 114C2 05B0 094D 3099 0062;0061 3099 114C2 094D 05B0 0062;0061 3099 114C2 094D 05B0 0062;0061 3099 114C2 094D 05B0 0062;0061 3099 114C2 094D 05B0 0062; # (a◌𑓂◌ְ◌्◌゙b; a◌゙◌𑓂◌्◌ְb; a◌゙◌𑓂◌्◌ְb; a◌゙◌𑓂◌्◌ְb; a◌゙◌𑓂◌्◌ְb; ) LATIN SMALL LETTER A, TIRHUTA SIGN VIRAMA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B 0061 3099 093C 0334 114C3 0062;0061 0334 093C 114C3 3099 0062;0061 0334 093C 114C3 3099 0062;0061 0334 093C 114C3 3099 0062;0061 0334 093C 114C3 3099 0062; # (a◌゙◌़◌̴◌𑓃b; a◌̴◌़◌𑓃◌゙b; a◌̴◌़◌𑓃◌゙b; a◌̴◌़◌𑓃◌゙b; a◌̴◌़◌𑓃◌゙b; ) LATIN SMALL LETTER A, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, COMBINING TILDE OVERLAY, TIRHUTA SIGN NUKTA, LATIN SMALL LETTER B @@ -18347,6 +18407,22 @@ FFEE;FFEE;FFEE;25CB;25CB; # (○; ○; ○; ○; ○; ) HALFWIDTH WHITE CIRCLE 0061 116B6 05B0 094D 3099 0062;0061 3099 116B6 094D 05B0 0062;0061 3099 116B6 094D 05B0 0062;0061 3099 116B6 094D 05B0 0062;0061 3099 116B6 094D 05B0 0062; # (a𑚶◌ְ◌्◌゙b; a◌゙𑚶◌्◌ְb; a◌゙𑚶◌्◌ְb; a◌゙𑚶◌्◌ְb; a◌゙𑚶◌्◌ְb; ) LATIN SMALL LETTER A, TAKRI SIGN VIRAMA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B 0061 3099 093C 0334 116B7 0062;0061 0334 093C 116B7 3099 0062;0061 0334 093C 116B7 3099 0062;0061 0334 093C 116B7 3099 0062;0061 0334 093C 116B7 3099 0062; # (a◌゙◌़◌̴◌𑚷b; a◌̴◌़◌𑚷◌゙b; a◌̴◌़◌𑚷◌゙b; a◌̴◌़◌𑚷◌゙b; a◌̴◌़◌𑚷◌゙b; ) LATIN SMALL LETTER A, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, COMBINING TILDE OVERLAY, TAKRI SIGN NUKTA, LATIN SMALL LETTER B 0061 116B7 3099 093C 0334 0062;0061 0334 116B7 093C 3099 0062;0061 0334 116B7 093C 3099 0062;0061 0334 116B7 093C 3099 0062;0061 0334 116B7 093C 3099 0062; # (a◌𑚷◌゙◌़◌̴b; a◌̴◌𑚷◌़◌゙b; a◌̴◌𑚷◌़◌゙b; a◌̴◌𑚷◌़◌゙b; a◌̴◌𑚷◌़◌゙b; ) LATIN SMALL LETTER A, TAKRI SIGN NUKTA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, COMBINING TILDE OVERLAY, LATIN SMALL LETTER B +0061 05B0 094D 3099 1172B 0062;0061 3099 094D 1172B 05B0 0062;0061 3099 094D 1172B 05B0 0062;0061 3099 094D 1172B 05B0 0062;0061 3099 094D 1172B 05B0 0062; # (a◌ְ◌्◌゙◌𑜫b; a◌゙◌्◌𑜫◌ְb; a◌゙◌्◌𑜫◌ְb; a◌゙◌्◌𑜫◌ְb; a◌゙◌्◌𑜫◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, AHOM SIGN KILLER, LATIN SMALL LETTER B +0061 1172B 05B0 094D 3099 0062;0061 3099 1172B 094D 05B0 0062;0061 3099 1172B 094D 05B0 0062;0061 3099 1172B 094D 05B0 0062;0061 3099 1172B 094D 05B0 0062; # (a◌𑜫◌ְ◌्◌゙b; a◌゙◌𑜫◌्◌ְb; a◌゙◌𑜫◌्◌ְb; a◌゙◌𑜫◌्◌ְb; a◌゙◌𑜫◌्◌ְb; ) LATIN SMALL LETTER A, AHOM SIGN KILLER, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B +0061 05B0 094D 3099 11A34 0062;0061 3099 094D 11A34 05B0 0062;0061 3099 094D 11A34 05B0 0062;0061 3099 094D 11A34 05B0 0062;0061 3099 094D 11A34 05B0 0062; # (a◌ְ◌्◌゙◌𑨴b; a◌゙◌्◌𑨴◌ְb; a◌゙◌्◌𑨴◌ְb; a◌゙◌्◌𑨴◌ְb; a◌゙◌्◌𑨴◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, ZANABAZAR SQUARE SIGN VIRAMA, LATIN SMALL LETTER B +0061 11A34 05B0 094D 3099 0062;0061 3099 11A34 094D 05B0 0062;0061 3099 11A34 094D 05B0 0062;0061 3099 11A34 094D 05B0 0062;0061 3099 11A34 094D 05B0 0062; # (a◌𑨴◌ְ◌्◌゙b; a◌゙◌𑨴◌्◌ְb; a◌゙◌𑨴◌्◌ְb; a◌゙◌𑨴◌्◌ְb; a◌゙◌𑨴◌्◌ְb; ) LATIN SMALL LETTER A, ZANABAZAR SQUARE SIGN VIRAMA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B +0061 05B0 094D 3099 11A47 0062;0061 3099 094D 11A47 05B0 0062;0061 3099 094D 11A47 05B0 0062;0061 3099 094D 11A47 05B0 0062;0061 3099 094D 11A47 05B0 0062; # (a◌ְ◌्◌゙◌𑩇b; a◌゙◌्◌𑩇◌ְb; a◌゙◌्◌𑩇◌ְb; a◌゙◌्◌𑩇◌ְb; a◌゙◌्◌𑩇◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, ZANABAZAR SQUARE SUBJOINER, LATIN SMALL LETTER B +0061 11A47 05B0 094D 3099 0062;0061 3099 11A47 094D 05B0 0062;0061 3099 11A47 094D 05B0 0062;0061 3099 11A47 094D 05B0 0062;0061 3099 11A47 094D 05B0 0062; # (a◌𑩇◌ְ◌्◌゙b; a◌゙◌𑩇◌्◌ְb; a◌゙◌𑩇◌्◌ְb; a◌゙◌𑩇◌्◌ְb; a◌゙◌𑩇◌्◌ְb; ) LATIN SMALL LETTER A, ZANABAZAR SQUARE SUBJOINER, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B +0061 05B0 094D 3099 11A99 0062;0061 3099 094D 11A99 05B0 0062;0061 3099 094D 11A99 05B0 0062;0061 3099 094D 11A99 05B0 0062;0061 3099 094D 11A99 05B0 0062; # (a◌ְ◌्◌゙◌𑪙b; a◌゙◌्◌𑪙◌ְb; a◌゙◌्◌𑪙◌ְb; a◌゙◌्◌𑪙◌ְb; a◌゙◌्◌𑪙◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, SOYOMBO SUBJOINER, LATIN SMALL LETTER B +0061 11A99 05B0 094D 3099 0062;0061 3099 11A99 094D 05B0 0062;0061 3099 11A99 094D 05B0 0062;0061 3099 11A99 094D 05B0 0062;0061 3099 11A99 094D 05B0 0062; # (a◌𑪙◌ְ◌्◌゙b; a◌゙◌𑪙◌्◌ְb; a◌゙◌𑪙◌्◌ְb; a◌゙◌𑪙◌्◌ְb; a◌゙◌𑪙◌्◌ְb; ) LATIN SMALL LETTER A, SOYOMBO SUBJOINER, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B +0061 05B0 094D 3099 11C3F 0062;0061 3099 094D 11C3F 05B0 0062;0061 3099 094D 11C3F 05B0 0062;0061 3099 094D 11C3F 05B0 0062;0061 3099 094D 11C3F 05B0 0062; # (a◌ְ◌्◌゙◌𑰿b; a◌゙◌्◌𑰿◌ְb; a◌゙◌्◌𑰿◌ְb; a◌゙◌्◌𑰿◌ְb; a◌゙◌्◌𑰿◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, BHAIKSUKI SIGN VIRAMA, LATIN SMALL LETTER B +0061 11C3F 05B0 094D 3099 0062;0061 3099 11C3F 094D 05B0 0062;0061 3099 11C3F 094D 05B0 0062;0061 3099 11C3F 094D 05B0 0062;0061 3099 11C3F 094D 05B0 0062; # (a◌𑰿◌ְ◌्◌゙b; a◌゙◌𑰿◌्◌ְb; a◌゙◌𑰿◌्◌ְb; a◌゙◌𑰿◌्◌ְb; a◌゙◌𑰿◌्◌ְb; ) LATIN SMALL LETTER A, BHAIKSUKI SIGN VIRAMA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B +0061 3099 093C 0334 11D42 0062;0061 0334 093C 11D42 3099 0062;0061 0334 093C 11D42 3099 0062;0061 0334 093C 11D42 3099 0062;0061 0334 093C 11D42 3099 0062; # (a◌゙◌़◌̴◌𑵂b; a◌̴◌़◌𑵂◌゙b; a◌̴◌़◌𑵂◌゙b; a◌̴◌़◌𑵂◌゙b; a◌̴◌़◌𑵂◌゙b; ) LATIN SMALL LETTER A, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, COMBINING TILDE OVERLAY, MASARAM GONDI SIGN NUKTA, LATIN SMALL LETTER B +0061 11D42 3099 093C 0334 0062;0061 0334 11D42 093C 3099 0062;0061 0334 11D42 093C 3099 0062;0061 0334 11D42 093C 3099 0062;0061 0334 11D42 093C 3099 0062; # (a◌𑵂◌゙◌़◌̴b; a◌̴◌𑵂◌़◌゙b; a◌̴◌𑵂◌़◌゙b; a◌̴◌𑵂◌़◌゙b; a◌̴◌𑵂◌़◌゙b; ) LATIN SMALL LETTER A, MASARAM GONDI SIGN NUKTA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, COMBINING TILDE OVERLAY, LATIN SMALL LETTER B +0061 05B0 094D 3099 11D44 0062;0061 3099 094D 11D44 05B0 0062;0061 3099 094D 11D44 05B0 0062;0061 3099 094D 11D44 05B0 0062;0061 3099 094D 11D44 05B0 0062; # (a◌ְ◌्◌゙◌𑵄b; a◌゙◌्◌𑵄◌ְb; a◌゙◌्◌𑵄◌ְb; a◌゙◌्◌𑵄◌ְb; a◌゙◌्◌𑵄◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, MASARAM GONDI SIGN HALANTA, LATIN SMALL LETTER B +0061 11D44 05B0 094D 3099 0062;0061 3099 11D44 094D 05B0 0062;0061 3099 11D44 094D 05B0 0062;0061 3099 11D44 094D 05B0 0062;0061 3099 11D44 094D 05B0 0062; # (a◌𑵄◌ְ◌्◌゙b; a◌゙◌𑵄◌्◌ְb; a◌゙◌𑵄◌्◌ְb; a◌゙◌𑵄◌्◌ְb; a◌゙◌𑵄◌्◌ְb; ) LATIN SMALL LETTER A, MASARAM GONDI SIGN HALANTA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B +0061 05B0 094D 3099 11D45 0062;0061 3099 094D 11D45 05B0 0062;0061 3099 094D 11D45 05B0 0062;0061 3099 094D 11D45 05B0 0062;0061 3099 094D 11D45 05B0 0062; # (a◌ְ◌्◌゙◌𑵅b; a◌゙◌्◌𑵅◌ְb; a◌゙◌्◌𑵅◌ְb; a◌゙◌्◌𑵅◌ְb; a◌゙◌्◌𑵅◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, MASARAM GONDI VIRAMA, LATIN SMALL LETTER B +0061 11D45 05B0 094D 3099 0062;0061 3099 11D45 094D 05B0 0062;0061 3099 11D45 094D 05B0 0062;0061 3099 11D45 094D 05B0 0062;0061 3099 11D45 094D 05B0 0062; # (a◌𑵅◌ְ◌्◌゙b; a◌゙◌𑵅◌्◌ְb; a◌゙◌𑵅◌्◌ְb; a◌゙◌𑵅◌्◌ְb; a◌゙◌𑵅◌्◌ְb; ) LATIN SMALL LETTER A, MASARAM GONDI VIRAMA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B 0061 093C 0334 16AF0 0062;0061 0334 16AF0 093C 0062;0061 0334 16AF0 093C 0062;0061 0334 16AF0 093C 0062;0061 0334 16AF0 093C 0062; # (a◌़◌̴◌𖫰b; a◌̴◌𖫰◌़b; a◌̴◌𖫰◌़b; a◌̴◌𖫰◌़b; a◌̴◌𖫰◌़b; ) LATIN SMALL LETTER A, DEVANAGARI SIGN NUKTA, COMBINING TILDE OVERLAY, BASSA VAH COMBINING HIGH TONE, LATIN SMALL LETTER B 0061 16AF0 093C 0334 0062;0061 16AF0 0334 093C 0062;0061 16AF0 0334 093C 0062;0061 16AF0 0334 093C 0062;0061 16AF0 0334 093C 0062; # (a◌𖫰◌़◌̴b; a◌𖫰◌̴◌़b; a◌𖫰◌̴◌़b; a◌𖫰◌̴◌़b; a◌𖫰◌̴◌़b; ) LATIN SMALL LETTER A, BASSA VAH COMBINING HIGH TONE, DEVANAGARI SIGN NUKTA, COMBINING TILDE OVERLAY, LATIN SMALL LETTER B 0061 093C 0334 16AF1 0062;0061 0334 16AF1 093C 0062;0061 0334 16AF1 093C 0062;0061 0334 16AF1 093C 0062;0061 0334 16AF1 093C 0062; # (a◌़◌̴◌𖫱b; a◌̴◌𖫱◌़b; a◌̴◌𖫱◌़b; a◌̴◌𖫱◌़b; a◌̴◌𖫱◌़b; ) LATIN SMALL LETTER A, DEVANAGARI SIGN NUKTA, COMBINING TILDE OVERLAY, BASSA VAH COMBINING LOW TONE, LATIN SMALL LETTER B @@ -18439,6 +18515,82 @@ FFEE;FFEE;FFEE;25CB;25CB; # (○; ○; ○; ○; ○; ) HALFWIDTH WHITE CIRCLE 0061 1D243 0315 0300 05AE 0062;0061 05AE 1D243 0300 0315 0062;0061 05AE 1D243 0300 0315 0062;0061 05AE 1D243 0300 0315 0062;0061 05AE 1D243 0300 0315 0062; # (a◌𝉃◌̕◌̀◌֮b; a◌֮◌𝉃◌̀◌̕b; a◌֮◌𝉃◌̀◌̕b; a◌֮◌𝉃◌̀◌̕b; a◌֮◌𝉃◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GREEK MUSICAL TETRASEME, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B 0061 0315 0300 05AE 1D244 0062;00E0 05AE 1D244 0315 0062;0061 05AE 0300 1D244 0315 0062;00E0 05AE 1D244 0315 0062;0061 05AE 0300 1D244 0315 0062; # (a◌̕◌̀◌֮◌𝉄b; à◌֮◌𝉄◌̕b; a◌֮◌̀◌𝉄◌̕b; à◌֮◌𝉄◌̕b; a◌֮◌̀◌𝉄◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GREEK MUSICAL PENTASEME, LATIN SMALL LETTER B 0061 1D244 0315 0300 05AE 0062;0061 05AE 1D244 0300 0315 0062;0061 05AE 1D244 0300 0315 0062;0061 05AE 1D244 0300 0315 0062;0061 05AE 1D244 0300 0315 0062; # (a◌𝉄◌̕◌̀◌֮b; a◌֮◌𝉄◌̀◌̕b; a◌֮◌𝉄◌̀◌̕b; a◌֮◌𝉄◌̀◌̕b; a◌֮◌𝉄◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GREEK MUSICAL PENTASEME, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E000 0062;00E0 05AE 1E000 0315 0062;0061 05AE 0300 1E000 0315 0062;00E0 05AE 1E000 0315 0062;0061 05AE 0300 1E000 0315 0062; # (a◌̕◌̀◌֮◌𞀀b; à◌֮◌𞀀◌̕b; a◌֮◌̀◌𞀀◌̕b; à◌֮◌𞀀◌̕b; a◌֮◌̀◌𞀀◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GLAGOLITIC LETTER AZU, LATIN SMALL LETTER B +0061 1E000 0315 0300 05AE 0062;0061 05AE 1E000 0300 0315 0062;0061 05AE 1E000 0300 0315 0062;0061 05AE 1E000 0300 0315 0062;0061 05AE 1E000 0300 0315 0062; # (a◌𞀀◌̕◌̀◌֮b; a◌֮◌𞀀◌̀◌̕b; a◌֮◌𞀀◌̀◌̕b; a◌֮◌𞀀◌̀◌̕b; a◌֮◌𞀀◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GLAGOLITIC LETTER AZU, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E001 0062;00E0 05AE 1E001 0315 0062;0061 05AE 0300 1E001 0315 0062;00E0 05AE 1E001 0315 0062;0061 05AE 0300 1E001 0315 0062; # (a◌̕◌̀◌֮◌𞀁b; à◌֮◌𞀁◌̕b; a◌֮◌̀◌𞀁◌̕b; à◌֮◌𞀁◌̕b; a◌֮◌̀◌𞀁◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GLAGOLITIC LETTER BUKY, LATIN SMALL LETTER B +0061 1E001 0315 0300 05AE 0062;0061 05AE 1E001 0300 0315 0062;0061 05AE 1E001 0300 0315 0062;0061 05AE 1E001 0300 0315 0062;0061 05AE 1E001 0300 0315 0062; # (a◌𞀁◌̕◌̀◌֮b; a◌֮◌𞀁◌̀◌̕b; a◌֮◌𞀁◌̀◌̕b; a◌֮◌𞀁◌̀◌̕b; a◌֮◌𞀁◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GLAGOLITIC LETTER BUKY, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E002 0062;00E0 05AE 1E002 0315 0062;0061 05AE 0300 1E002 0315 0062;00E0 05AE 1E002 0315 0062;0061 05AE 0300 1E002 0315 0062; # (a◌̕◌̀◌֮◌𞀂b; à◌֮◌𞀂◌̕b; a◌֮◌̀◌𞀂◌̕b; à◌֮◌𞀂◌̕b; a◌֮◌̀◌𞀂◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GLAGOLITIC LETTER VEDE, LATIN SMALL LETTER B +0061 1E002 0315 0300 05AE 0062;0061 05AE 1E002 0300 0315 0062;0061 05AE 1E002 0300 0315 0062;0061 05AE 1E002 0300 0315 0062;0061 05AE 1E002 0300 0315 0062; # (a◌𞀂◌̕◌̀◌֮b; a◌֮◌𞀂◌̀◌̕b; a◌֮◌𞀂◌̀◌̕b; a◌֮◌𞀂◌̀◌̕b; a◌֮◌𞀂◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GLAGOLITIC LETTER VEDE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E003 0062;00E0 05AE 1E003 0315 0062;0061 05AE 0300 1E003 0315 0062;00E0 05AE 1E003 0315 0062;0061 05AE 0300 1E003 0315 0062; # (a◌̕◌̀◌֮◌𞀃b; à◌֮◌𞀃◌̕b; a◌֮◌̀◌𞀃◌̕b; à◌֮◌𞀃◌̕b; a◌֮◌̀◌𞀃◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GLAGOLITIC LETTER GLAGOLI, LATIN SMALL LETTER B +0061 1E003 0315 0300 05AE 0062;0061 05AE 1E003 0300 0315 0062;0061 05AE 1E003 0300 0315 0062;0061 05AE 1E003 0300 0315 0062;0061 05AE 1E003 0300 0315 0062; # (a◌𞀃◌̕◌̀◌֮b; a◌֮◌𞀃◌̀◌̕b; a◌֮◌𞀃◌̀◌̕b; a◌֮◌𞀃◌̀◌̕b; a◌֮◌𞀃◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GLAGOLITIC LETTER GLAGOLI, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E004 0062;00E0 05AE 1E004 0315 0062;0061 05AE 0300 1E004 0315 0062;00E0 05AE 1E004 0315 0062;0061 05AE 0300 1E004 0315 0062; # (a◌̕◌̀◌֮◌𞀄b; à◌֮◌𞀄◌̕b; a◌֮◌̀◌𞀄◌̕b; à◌֮◌𞀄◌̕b; a◌֮◌̀◌𞀄◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GLAGOLITIC LETTER DOBRO, LATIN SMALL LETTER B +0061 1E004 0315 0300 05AE 0062;0061 05AE 1E004 0300 0315 0062;0061 05AE 1E004 0300 0315 0062;0061 05AE 1E004 0300 0315 0062;0061 05AE 1E004 0300 0315 0062; # (a◌𞀄◌̕◌̀◌֮b; a◌֮◌𞀄◌̀◌̕b; a◌֮◌𞀄◌̀◌̕b; a◌֮◌𞀄◌̀◌̕b; a◌֮◌𞀄◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GLAGOLITIC LETTER DOBRO, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E005 0062;00E0 05AE 1E005 0315 0062;0061 05AE 0300 1E005 0315 0062;00E0 05AE 1E005 0315 0062;0061 05AE 0300 1E005 0315 0062; # (a◌̕◌̀◌֮◌𞀅b; à◌֮◌𞀅◌̕b; a◌֮◌̀◌𞀅◌̕b; à◌֮◌𞀅◌̕b; a◌֮◌̀◌𞀅◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GLAGOLITIC LETTER YESTU, LATIN SMALL LETTER B +0061 1E005 0315 0300 05AE 0062;0061 05AE 1E005 0300 0315 0062;0061 05AE 1E005 0300 0315 0062;0061 05AE 1E005 0300 0315 0062;0061 05AE 1E005 0300 0315 0062; # (a◌𞀅◌̕◌̀◌֮b; a◌֮◌𞀅◌̀◌̕b; a◌֮◌𞀅◌̀◌̕b; a◌֮◌𞀅◌̀◌̕b; a◌֮◌𞀅◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GLAGOLITIC LETTER YESTU, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E006 0062;00E0 05AE 1E006 0315 0062;0061 05AE 0300 1E006 0315 0062;00E0 05AE 1E006 0315 0062;0061 05AE 0300 1E006 0315 0062; # (a◌̕◌̀◌֮◌𞀆b; à◌֮◌𞀆◌̕b; a◌֮◌̀◌𞀆◌̕b; à◌֮◌𞀆◌̕b; a◌֮◌̀◌𞀆◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GLAGOLITIC LETTER ZHIVETE, LATIN SMALL LETTER B +0061 1E006 0315 0300 05AE 0062;0061 05AE 1E006 0300 0315 0062;0061 05AE 1E006 0300 0315 0062;0061 05AE 1E006 0300 0315 0062;0061 05AE 1E006 0300 0315 0062; # (a◌𞀆◌̕◌̀◌֮b; a◌֮◌𞀆◌̀◌̕b; a◌֮◌𞀆◌̀◌̕b; a◌֮◌𞀆◌̀◌̕b; a◌֮◌𞀆◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GLAGOLITIC LETTER ZHIVETE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E008 0062;00E0 05AE 1E008 0315 0062;0061 05AE 0300 1E008 0315 0062;00E0 05AE 1E008 0315 0062;0061 05AE 0300 1E008 0315 0062; # (a◌̕◌̀◌֮◌𞀈b; à◌֮◌𞀈◌̕b; a◌֮◌̀◌𞀈◌̕b; à◌֮◌𞀈◌̕b; a◌֮◌̀◌𞀈◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GLAGOLITIC LETTER ZEMLJA, LATIN SMALL LETTER B +0061 1E008 0315 0300 05AE 0062;0061 05AE 1E008 0300 0315 0062;0061 05AE 1E008 0300 0315 0062;0061 05AE 1E008 0300 0315 0062;0061 05AE 1E008 0300 0315 0062; # (a◌𞀈◌̕◌̀◌֮b; a◌֮◌𞀈◌̀◌̕b; a◌֮◌𞀈◌̀◌̕b; a◌֮◌𞀈◌̀◌̕b; a◌֮◌𞀈◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GLAGOLITIC LETTER ZEMLJA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E009 0062;00E0 05AE 1E009 0315 0062;0061 05AE 0300 1E009 0315 0062;00E0 05AE 1E009 0315 0062;0061 05AE 0300 1E009 0315 0062; # (a◌̕◌̀◌֮◌𞀉b; à◌֮◌𞀉◌̕b; a◌֮◌̀◌𞀉◌̕b; à◌֮◌𞀉◌̕b; a◌֮◌̀◌𞀉◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GLAGOLITIC LETTER IZHE, LATIN SMALL LETTER B +0061 1E009 0315 0300 05AE 0062;0061 05AE 1E009 0300 0315 0062;0061 05AE 1E009 0300 0315 0062;0061 05AE 1E009 0300 0315 0062;0061 05AE 1E009 0300 0315 0062; # (a◌𞀉◌̕◌̀◌֮b; a◌֮◌𞀉◌̀◌̕b; a◌֮◌𞀉◌̀◌̕b; a◌֮◌𞀉◌̀◌̕b; a◌֮◌𞀉◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GLAGOLITIC LETTER IZHE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E00A 0062;00E0 05AE 1E00A 0315 0062;0061 05AE 0300 1E00A 0315 0062;00E0 05AE 1E00A 0315 0062;0061 05AE 0300 1E00A 0315 0062; # (a◌̕◌̀◌֮◌𞀊b; à◌֮◌𞀊◌̕b; a◌֮◌̀◌𞀊◌̕b; à◌֮◌𞀊◌̕b; a◌֮◌̀◌𞀊◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GLAGOLITIC LETTER INITIAL IZHE, LATIN SMALL LETTER B +0061 1E00A 0315 0300 05AE 0062;0061 05AE 1E00A 0300 0315 0062;0061 05AE 1E00A 0300 0315 0062;0061 05AE 1E00A 0300 0315 0062;0061 05AE 1E00A 0300 0315 0062; # (a◌𞀊◌̕◌̀◌֮b; a◌֮◌𞀊◌̀◌̕b; a◌֮◌𞀊◌̀◌̕b; a◌֮◌𞀊◌̀◌̕b; a◌֮◌𞀊◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GLAGOLITIC LETTER INITIAL IZHE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E00B 0062;00E0 05AE 1E00B 0315 0062;0061 05AE 0300 1E00B 0315 0062;00E0 05AE 1E00B 0315 0062;0061 05AE 0300 1E00B 0315 0062; # (a◌̕◌̀◌֮◌𞀋b; à◌֮◌𞀋◌̕b; a◌֮◌̀◌𞀋◌̕b; à◌֮◌𞀋◌̕b; a◌֮◌̀◌𞀋◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GLAGOLITIC LETTER I, LATIN SMALL LETTER B +0061 1E00B 0315 0300 05AE 0062;0061 05AE 1E00B 0300 0315 0062;0061 05AE 1E00B 0300 0315 0062;0061 05AE 1E00B 0300 0315 0062;0061 05AE 1E00B 0300 0315 0062; # (a◌𞀋◌̕◌̀◌֮b; a◌֮◌𞀋◌̀◌̕b; a◌֮◌𞀋◌̀◌̕b; a◌֮◌𞀋◌̀◌̕b; a◌֮◌𞀋◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GLAGOLITIC LETTER I, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E00C 0062;00E0 05AE 1E00C 0315 0062;0061 05AE 0300 1E00C 0315 0062;00E0 05AE 1E00C 0315 0062;0061 05AE 0300 1E00C 0315 0062; # (a◌̕◌̀◌֮◌𞀌b; à◌֮◌𞀌◌̕b; a◌֮◌̀◌𞀌◌̕b; à◌֮◌𞀌◌̕b; a◌֮◌̀◌𞀌◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GLAGOLITIC LETTER DJERVI, LATIN SMALL LETTER B +0061 1E00C 0315 0300 05AE 0062;0061 05AE 1E00C 0300 0315 0062;0061 05AE 1E00C 0300 0315 0062;0061 05AE 1E00C 0300 0315 0062;0061 05AE 1E00C 0300 0315 0062; # (a◌𞀌◌̕◌̀◌֮b; a◌֮◌𞀌◌̀◌̕b; a◌֮◌𞀌◌̀◌̕b; a◌֮◌𞀌◌̀◌̕b; a◌֮◌𞀌◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GLAGOLITIC LETTER DJERVI, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E00D 0062;00E0 05AE 1E00D 0315 0062;0061 05AE 0300 1E00D 0315 0062;00E0 05AE 1E00D 0315 0062;0061 05AE 0300 1E00D 0315 0062; # (a◌̕◌̀◌֮◌𞀍b; à◌֮◌𞀍◌̕b; a◌֮◌̀◌𞀍◌̕b; à◌֮◌𞀍◌̕b; a◌֮◌̀◌𞀍◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GLAGOLITIC LETTER KAKO, LATIN SMALL LETTER B +0061 1E00D 0315 0300 05AE 0062;0061 05AE 1E00D 0300 0315 0062;0061 05AE 1E00D 0300 0315 0062;0061 05AE 1E00D 0300 0315 0062;0061 05AE 1E00D 0300 0315 0062; # (a◌𞀍◌̕◌̀◌֮b; a◌֮◌𞀍◌̀◌̕b; a◌֮◌𞀍◌̀◌̕b; a◌֮◌𞀍◌̀◌̕b; a◌֮◌𞀍◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GLAGOLITIC LETTER KAKO, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E00E 0062;00E0 05AE 1E00E 0315 0062;0061 05AE 0300 1E00E 0315 0062;00E0 05AE 1E00E 0315 0062;0061 05AE 0300 1E00E 0315 0062; # (a◌̕◌̀◌֮◌𞀎b; à◌֮◌𞀎◌̕b; a◌֮◌̀◌𞀎◌̕b; à◌֮◌𞀎◌̕b; a◌֮◌̀◌𞀎◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GLAGOLITIC LETTER LJUDIJE, LATIN SMALL LETTER B +0061 1E00E 0315 0300 05AE 0062;0061 05AE 1E00E 0300 0315 0062;0061 05AE 1E00E 0300 0315 0062;0061 05AE 1E00E 0300 0315 0062;0061 05AE 1E00E 0300 0315 0062; # (a◌𞀎◌̕◌̀◌֮b; a◌֮◌𞀎◌̀◌̕b; a◌֮◌𞀎◌̀◌̕b; a◌֮◌𞀎◌̀◌̕b; a◌֮◌𞀎◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GLAGOLITIC LETTER LJUDIJE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E00F 0062;00E0 05AE 1E00F 0315 0062;0061 05AE 0300 1E00F 0315 0062;00E0 05AE 1E00F 0315 0062;0061 05AE 0300 1E00F 0315 0062; # (a◌̕◌̀◌֮◌𞀏b; à◌֮◌𞀏◌̕b; a◌֮◌̀◌𞀏◌̕b; à◌֮◌𞀏◌̕b; a◌֮◌̀◌𞀏◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GLAGOLITIC LETTER MYSLITE, LATIN SMALL LETTER B +0061 1E00F 0315 0300 05AE 0062;0061 05AE 1E00F 0300 0315 0062;0061 05AE 1E00F 0300 0315 0062;0061 05AE 1E00F 0300 0315 0062;0061 05AE 1E00F 0300 0315 0062; # (a◌𞀏◌̕◌̀◌֮b; a◌֮◌𞀏◌̀◌̕b; a◌֮◌𞀏◌̀◌̕b; a◌֮◌𞀏◌̀◌̕b; a◌֮◌𞀏◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GLAGOLITIC LETTER MYSLITE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E010 0062;00E0 05AE 1E010 0315 0062;0061 05AE 0300 1E010 0315 0062;00E0 05AE 1E010 0315 0062;0061 05AE 0300 1E010 0315 0062; # (a◌̕◌̀◌֮◌𞀐b; à◌֮◌𞀐◌̕b; a◌֮◌̀◌𞀐◌̕b; à◌֮◌𞀐◌̕b; a◌֮◌̀◌𞀐◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GLAGOLITIC LETTER NASHI, LATIN SMALL LETTER B +0061 1E010 0315 0300 05AE 0062;0061 05AE 1E010 0300 0315 0062;0061 05AE 1E010 0300 0315 0062;0061 05AE 1E010 0300 0315 0062;0061 05AE 1E010 0300 0315 0062; # (a◌𞀐◌̕◌̀◌֮b; a◌֮◌𞀐◌̀◌̕b; a◌֮◌𞀐◌̀◌̕b; a◌֮◌𞀐◌̀◌̕b; a◌֮◌𞀐◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GLAGOLITIC LETTER NASHI, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E011 0062;00E0 05AE 1E011 0315 0062;0061 05AE 0300 1E011 0315 0062;00E0 05AE 1E011 0315 0062;0061 05AE 0300 1E011 0315 0062; # (a◌̕◌̀◌֮◌𞀑b; à◌֮◌𞀑◌̕b; a◌֮◌̀◌𞀑◌̕b; à◌֮◌𞀑◌̕b; a◌֮◌̀◌𞀑◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GLAGOLITIC LETTER ONU, LATIN SMALL LETTER B +0061 1E011 0315 0300 05AE 0062;0061 05AE 1E011 0300 0315 0062;0061 05AE 1E011 0300 0315 0062;0061 05AE 1E011 0300 0315 0062;0061 05AE 1E011 0300 0315 0062; # (a◌𞀑◌̕◌̀◌֮b; a◌֮◌𞀑◌̀◌̕b; a◌֮◌𞀑◌̀◌̕b; a◌֮◌𞀑◌̀◌̕b; a◌֮◌𞀑◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GLAGOLITIC LETTER ONU, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E012 0062;00E0 05AE 1E012 0315 0062;0061 05AE 0300 1E012 0315 0062;00E0 05AE 1E012 0315 0062;0061 05AE 0300 1E012 0315 0062; # (a◌̕◌̀◌֮◌𞀒b; à◌֮◌𞀒◌̕b; a◌֮◌̀◌𞀒◌̕b; à◌֮◌𞀒◌̕b; a◌֮◌̀◌𞀒◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GLAGOLITIC LETTER POKOJI, LATIN SMALL LETTER B +0061 1E012 0315 0300 05AE 0062;0061 05AE 1E012 0300 0315 0062;0061 05AE 1E012 0300 0315 0062;0061 05AE 1E012 0300 0315 0062;0061 05AE 1E012 0300 0315 0062; # (a◌𞀒◌̕◌̀◌֮b; a◌֮◌𞀒◌̀◌̕b; a◌֮◌𞀒◌̀◌̕b; a◌֮◌𞀒◌̀◌̕b; a◌֮◌𞀒◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GLAGOLITIC LETTER POKOJI, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E013 0062;00E0 05AE 1E013 0315 0062;0061 05AE 0300 1E013 0315 0062;00E0 05AE 1E013 0315 0062;0061 05AE 0300 1E013 0315 0062; # (a◌̕◌̀◌֮◌𞀓b; à◌֮◌𞀓◌̕b; a◌֮◌̀◌𞀓◌̕b; à◌֮◌𞀓◌̕b; a◌֮◌̀◌𞀓◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GLAGOLITIC LETTER RITSI, LATIN SMALL LETTER B +0061 1E013 0315 0300 05AE 0062;0061 05AE 1E013 0300 0315 0062;0061 05AE 1E013 0300 0315 0062;0061 05AE 1E013 0300 0315 0062;0061 05AE 1E013 0300 0315 0062; # (a◌𞀓◌̕◌̀◌֮b; a◌֮◌𞀓◌̀◌̕b; a◌֮◌𞀓◌̀◌̕b; a◌֮◌𞀓◌̀◌̕b; a◌֮◌𞀓◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GLAGOLITIC LETTER RITSI, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E014 0062;00E0 05AE 1E014 0315 0062;0061 05AE 0300 1E014 0315 0062;00E0 05AE 1E014 0315 0062;0061 05AE 0300 1E014 0315 0062; # (a◌̕◌̀◌֮◌𞀔b; à◌֮◌𞀔◌̕b; a◌֮◌̀◌𞀔◌̕b; à◌֮◌𞀔◌̕b; a◌֮◌̀◌𞀔◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GLAGOLITIC LETTER SLOVO, LATIN SMALL LETTER B +0061 1E014 0315 0300 05AE 0062;0061 05AE 1E014 0300 0315 0062;0061 05AE 1E014 0300 0315 0062;0061 05AE 1E014 0300 0315 0062;0061 05AE 1E014 0300 0315 0062; # (a◌𞀔◌̕◌̀◌֮b; a◌֮◌𞀔◌̀◌̕b; a◌֮◌𞀔◌̀◌̕b; a◌֮◌𞀔◌̀◌̕b; a◌֮◌𞀔◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GLAGOLITIC LETTER SLOVO, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E015 0062;00E0 05AE 1E015 0315 0062;0061 05AE 0300 1E015 0315 0062;00E0 05AE 1E015 0315 0062;0061 05AE 0300 1E015 0315 0062; # (a◌̕◌̀◌֮◌𞀕b; à◌֮◌𞀕◌̕b; a◌֮◌̀◌𞀕◌̕b; à◌֮◌𞀕◌̕b; a◌֮◌̀◌𞀕◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GLAGOLITIC LETTER TVRIDO, LATIN SMALL LETTER B +0061 1E015 0315 0300 05AE 0062;0061 05AE 1E015 0300 0315 0062;0061 05AE 1E015 0300 0315 0062;0061 05AE 1E015 0300 0315 0062;0061 05AE 1E015 0300 0315 0062; # (a◌𞀕◌̕◌̀◌֮b; a◌֮◌𞀕◌̀◌̕b; a◌֮◌𞀕◌̀◌̕b; a◌֮◌𞀕◌̀◌̕b; a◌֮◌𞀕◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GLAGOLITIC LETTER TVRIDO, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E016 0062;00E0 05AE 1E016 0315 0062;0061 05AE 0300 1E016 0315 0062;00E0 05AE 1E016 0315 0062;0061 05AE 0300 1E016 0315 0062; # (a◌̕◌̀◌֮◌𞀖b; à◌֮◌𞀖◌̕b; a◌֮◌̀◌𞀖◌̕b; à◌֮◌𞀖◌̕b; a◌֮◌̀◌𞀖◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GLAGOLITIC LETTER UKU, LATIN SMALL LETTER B +0061 1E016 0315 0300 05AE 0062;0061 05AE 1E016 0300 0315 0062;0061 05AE 1E016 0300 0315 0062;0061 05AE 1E016 0300 0315 0062;0061 05AE 1E016 0300 0315 0062; # (a◌𞀖◌̕◌̀◌֮b; a◌֮◌𞀖◌̀◌̕b; a◌֮◌𞀖◌̀◌̕b; a◌֮◌𞀖◌̀◌̕b; a◌֮◌𞀖◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GLAGOLITIC LETTER UKU, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E017 0062;00E0 05AE 1E017 0315 0062;0061 05AE 0300 1E017 0315 0062;00E0 05AE 1E017 0315 0062;0061 05AE 0300 1E017 0315 0062; # (a◌̕◌̀◌֮◌𞀗b; à◌֮◌𞀗◌̕b; a◌֮◌̀◌𞀗◌̕b; à◌֮◌𞀗◌̕b; a◌֮◌̀◌𞀗◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GLAGOLITIC LETTER FRITU, LATIN SMALL LETTER B +0061 1E017 0315 0300 05AE 0062;0061 05AE 1E017 0300 0315 0062;0061 05AE 1E017 0300 0315 0062;0061 05AE 1E017 0300 0315 0062;0061 05AE 1E017 0300 0315 0062; # (a◌𞀗◌̕◌̀◌֮b; a◌֮◌𞀗◌̀◌̕b; a◌֮◌𞀗◌̀◌̕b; a◌֮◌𞀗◌̀◌̕b; a◌֮◌𞀗◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GLAGOLITIC LETTER FRITU, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E018 0062;00E0 05AE 1E018 0315 0062;0061 05AE 0300 1E018 0315 0062;00E0 05AE 1E018 0315 0062;0061 05AE 0300 1E018 0315 0062; # (a◌̕◌̀◌֮◌𞀘b; à◌֮◌𞀘◌̕b; a◌֮◌̀◌𞀘◌̕b; à◌֮◌𞀘◌̕b; a◌֮◌̀◌𞀘◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GLAGOLITIC LETTER HERU, LATIN SMALL LETTER B +0061 1E018 0315 0300 05AE 0062;0061 05AE 1E018 0300 0315 0062;0061 05AE 1E018 0300 0315 0062;0061 05AE 1E018 0300 0315 0062;0061 05AE 1E018 0300 0315 0062; # (a◌𞀘◌̕◌̀◌֮b; a◌֮◌𞀘◌̀◌̕b; a◌֮◌𞀘◌̀◌̕b; a◌֮◌𞀘◌̀◌̕b; a◌֮◌𞀘◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GLAGOLITIC LETTER HERU, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E01B 0062;00E0 05AE 1E01B 0315 0062;0061 05AE 0300 1E01B 0315 0062;00E0 05AE 1E01B 0315 0062;0061 05AE 0300 1E01B 0315 0062; # (a◌̕◌̀◌֮◌𞀛b; à◌֮◌𞀛◌̕b; a◌֮◌̀◌𞀛◌̕b; à◌֮◌𞀛◌̕b; a◌֮◌̀◌𞀛◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GLAGOLITIC LETTER SHTA, LATIN SMALL LETTER B +0061 1E01B 0315 0300 05AE 0062;0061 05AE 1E01B 0300 0315 0062;0061 05AE 1E01B 0300 0315 0062;0061 05AE 1E01B 0300 0315 0062;0061 05AE 1E01B 0300 0315 0062; # (a◌𞀛◌̕◌̀◌֮b; a◌֮◌𞀛◌̀◌̕b; a◌֮◌𞀛◌̀◌̕b; a◌֮◌𞀛◌̀◌̕b; a◌֮◌𞀛◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GLAGOLITIC LETTER SHTA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E01C 0062;00E0 05AE 1E01C 0315 0062;0061 05AE 0300 1E01C 0315 0062;00E0 05AE 1E01C 0315 0062;0061 05AE 0300 1E01C 0315 0062; # (a◌̕◌̀◌֮◌𞀜b; à◌֮◌𞀜◌̕b; a◌֮◌̀◌𞀜◌̕b; à◌֮◌𞀜◌̕b; a◌֮◌̀◌𞀜◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GLAGOLITIC LETTER TSI, LATIN SMALL LETTER B +0061 1E01C 0315 0300 05AE 0062;0061 05AE 1E01C 0300 0315 0062;0061 05AE 1E01C 0300 0315 0062;0061 05AE 1E01C 0300 0315 0062;0061 05AE 1E01C 0300 0315 0062; # (a◌𞀜◌̕◌̀◌֮b; a◌֮◌𞀜◌̀◌̕b; a◌֮◌𞀜◌̀◌̕b; a◌֮◌𞀜◌̀◌̕b; a◌֮◌𞀜◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GLAGOLITIC LETTER TSI, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E01D 0062;00E0 05AE 1E01D 0315 0062;0061 05AE 0300 1E01D 0315 0062;00E0 05AE 1E01D 0315 0062;0061 05AE 0300 1E01D 0315 0062; # (a◌̕◌̀◌֮◌𞀝b; à◌֮◌𞀝◌̕b; a◌֮◌̀◌𞀝◌̕b; à◌֮◌𞀝◌̕b; a◌֮◌̀◌𞀝◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GLAGOLITIC LETTER CHRIVI, LATIN SMALL LETTER B +0061 1E01D 0315 0300 05AE 0062;0061 05AE 1E01D 0300 0315 0062;0061 05AE 1E01D 0300 0315 0062;0061 05AE 1E01D 0300 0315 0062;0061 05AE 1E01D 0300 0315 0062; # (a◌𞀝◌̕◌̀◌֮b; a◌֮◌𞀝◌̀◌̕b; a◌֮◌𞀝◌̀◌̕b; a◌֮◌𞀝◌̀◌̕b; a◌֮◌𞀝◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GLAGOLITIC LETTER CHRIVI, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E01E 0062;00E0 05AE 1E01E 0315 0062;0061 05AE 0300 1E01E 0315 0062;00E0 05AE 1E01E 0315 0062;0061 05AE 0300 1E01E 0315 0062; # (a◌̕◌̀◌֮◌𞀞b; à◌֮◌𞀞◌̕b; a◌֮◌̀◌𞀞◌̕b; à◌֮◌𞀞◌̕b; a◌֮◌̀◌𞀞◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GLAGOLITIC LETTER SHA, LATIN SMALL LETTER B +0061 1E01E 0315 0300 05AE 0062;0061 05AE 1E01E 0300 0315 0062;0061 05AE 1E01E 0300 0315 0062;0061 05AE 1E01E 0300 0315 0062;0061 05AE 1E01E 0300 0315 0062; # (a◌𞀞◌̕◌̀◌֮b; a◌֮◌𞀞◌̀◌̕b; a◌֮◌𞀞◌̀◌̕b; a◌֮◌𞀞◌̀◌̕b; a◌֮◌𞀞◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GLAGOLITIC LETTER SHA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E01F 0062;00E0 05AE 1E01F 0315 0062;0061 05AE 0300 1E01F 0315 0062;00E0 05AE 1E01F 0315 0062;0061 05AE 0300 1E01F 0315 0062; # (a◌̕◌̀◌֮◌𞀟b; à◌֮◌𞀟◌̕b; a◌֮◌̀◌𞀟◌̕b; à◌֮◌𞀟◌̕b; a◌֮◌̀◌𞀟◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GLAGOLITIC LETTER YERU, LATIN SMALL LETTER B +0061 1E01F 0315 0300 05AE 0062;0061 05AE 1E01F 0300 0315 0062;0061 05AE 1E01F 0300 0315 0062;0061 05AE 1E01F 0300 0315 0062;0061 05AE 1E01F 0300 0315 0062; # (a◌𞀟◌̕◌̀◌֮b; a◌֮◌𞀟◌̀◌̕b; a◌֮◌𞀟◌̀◌̕b; a◌֮◌𞀟◌̀◌̕b; a◌֮◌𞀟◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GLAGOLITIC LETTER YERU, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E020 0062;00E0 05AE 1E020 0315 0062;0061 05AE 0300 1E020 0315 0062;00E0 05AE 1E020 0315 0062;0061 05AE 0300 1E020 0315 0062; # (a◌̕◌̀◌֮◌𞀠b; à◌֮◌𞀠◌̕b; a◌֮◌̀◌𞀠◌̕b; à◌֮◌𞀠◌̕b; a◌֮◌̀◌𞀠◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GLAGOLITIC LETTER YERI, LATIN SMALL LETTER B +0061 1E020 0315 0300 05AE 0062;0061 05AE 1E020 0300 0315 0062;0061 05AE 1E020 0300 0315 0062;0061 05AE 1E020 0300 0315 0062;0061 05AE 1E020 0300 0315 0062; # (a◌𞀠◌̕◌̀◌֮b; a◌֮◌𞀠◌̀◌̕b; a◌֮◌𞀠◌̀◌̕b; a◌֮◌𞀠◌̀◌̕b; a◌֮◌𞀠◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GLAGOLITIC LETTER YERI, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E021 0062;00E0 05AE 1E021 0315 0062;0061 05AE 0300 1E021 0315 0062;00E0 05AE 1E021 0315 0062;0061 05AE 0300 1E021 0315 0062; # (a◌̕◌̀◌֮◌𞀡b; à◌֮◌𞀡◌̕b; a◌֮◌̀◌𞀡◌̕b; à◌֮◌𞀡◌̕b; a◌֮◌̀◌𞀡◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GLAGOLITIC LETTER YATI, LATIN SMALL LETTER B +0061 1E021 0315 0300 05AE 0062;0061 05AE 1E021 0300 0315 0062;0061 05AE 1E021 0300 0315 0062;0061 05AE 1E021 0300 0315 0062;0061 05AE 1E021 0300 0315 0062; # (a◌𞀡◌̕◌̀◌֮b; a◌֮◌𞀡◌̀◌̕b; a◌֮◌𞀡◌̀◌̕b; a◌֮◌𞀡◌̀◌̕b; a◌֮◌𞀡◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GLAGOLITIC LETTER YATI, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E023 0062;00E0 05AE 1E023 0315 0062;0061 05AE 0300 1E023 0315 0062;00E0 05AE 1E023 0315 0062;0061 05AE 0300 1E023 0315 0062; # (a◌̕◌̀◌֮◌𞀣b; à◌֮◌𞀣◌̕b; a◌֮◌̀◌𞀣◌̕b; à◌֮◌𞀣◌̕b; a◌֮◌̀◌𞀣◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GLAGOLITIC LETTER YU, LATIN SMALL LETTER B +0061 1E023 0315 0300 05AE 0062;0061 05AE 1E023 0300 0315 0062;0061 05AE 1E023 0300 0315 0062;0061 05AE 1E023 0300 0315 0062;0061 05AE 1E023 0300 0315 0062; # (a◌𞀣◌̕◌̀◌֮b; a◌֮◌𞀣◌̀◌̕b; a◌֮◌𞀣◌̀◌̕b; a◌֮◌𞀣◌̀◌̕b; a◌֮◌𞀣◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GLAGOLITIC LETTER YU, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E024 0062;00E0 05AE 1E024 0315 0062;0061 05AE 0300 1E024 0315 0062;00E0 05AE 1E024 0315 0062;0061 05AE 0300 1E024 0315 0062; # (a◌̕◌̀◌֮◌𞀤b; à◌֮◌𞀤◌̕b; a◌֮◌̀◌𞀤◌̕b; à◌֮◌𞀤◌̕b; a◌֮◌̀◌𞀤◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GLAGOLITIC LETTER SMALL YUS, LATIN SMALL LETTER B +0061 1E024 0315 0300 05AE 0062;0061 05AE 1E024 0300 0315 0062;0061 05AE 1E024 0300 0315 0062;0061 05AE 1E024 0300 0315 0062;0061 05AE 1E024 0300 0315 0062; # (a◌𞀤◌̕◌̀◌֮b; a◌֮◌𞀤◌̀◌̕b; a◌֮◌𞀤◌̀◌̕b; a◌֮◌𞀤◌̀◌̕b; a◌֮◌𞀤◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GLAGOLITIC LETTER SMALL YUS, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E026 0062;00E0 05AE 1E026 0315 0062;0061 05AE 0300 1E026 0315 0062;00E0 05AE 1E026 0315 0062;0061 05AE 0300 1E026 0315 0062; # (a◌̕◌̀◌֮◌𞀦b; à◌֮◌𞀦◌̕b; a◌֮◌̀◌𞀦◌̕b; à◌֮◌𞀦◌̕b; a◌֮◌̀◌𞀦◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GLAGOLITIC LETTER YO, LATIN SMALL LETTER B +0061 1E026 0315 0300 05AE 0062;0061 05AE 1E026 0300 0315 0062;0061 05AE 1E026 0300 0315 0062;0061 05AE 1E026 0300 0315 0062;0061 05AE 1E026 0300 0315 0062; # (a◌𞀦◌̕◌̀◌֮b; a◌֮◌𞀦◌̀◌̕b; a◌֮◌𞀦◌̀◌̕b; a◌֮◌𞀦◌̀◌̕b; a◌֮◌𞀦◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GLAGOLITIC LETTER YO, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E027 0062;00E0 05AE 1E027 0315 0062;0061 05AE 0300 1E027 0315 0062;00E0 05AE 1E027 0315 0062;0061 05AE 0300 1E027 0315 0062; # (a◌̕◌̀◌֮◌𞀧b; à◌֮◌𞀧◌̕b; a◌֮◌̀◌𞀧◌̕b; à◌֮◌𞀧◌̕b; a◌֮◌̀◌𞀧◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GLAGOLITIC LETTER IOTATED SMALL YUS, LATIN SMALL LETTER B +0061 1E027 0315 0300 05AE 0062;0061 05AE 1E027 0300 0315 0062;0061 05AE 1E027 0300 0315 0062;0061 05AE 1E027 0300 0315 0062;0061 05AE 1E027 0300 0315 0062; # (a◌𞀧◌̕◌̀◌֮b; a◌֮◌𞀧◌̀◌̕b; a◌֮◌𞀧◌̀◌̕b; a◌֮◌𞀧◌̀◌̕b; a◌֮◌𞀧◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GLAGOLITIC LETTER IOTATED SMALL YUS, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E028 0062;00E0 05AE 1E028 0315 0062;0061 05AE 0300 1E028 0315 0062;00E0 05AE 1E028 0315 0062;0061 05AE 0300 1E028 0315 0062; # (a◌̕◌̀◌֮◌𞀨b; à◌֮◌𞀨◌̕b; a◌֮◌̀◌𞀨◌̕b; à◌֮◌𞀨◌̕b; a◌֮◌̀◌𞀨◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GLAGOLITIC LETTER BIG YUS, LATIN SMALL LETTER B +0061 1E028 0315 0300 05AE 0062;0061 05AE 1E028 0300 0315 0062;0061 05AE 1E028 0300 0315 0062;0061 05AE 1E028 0300 0315 0062;0061 05AE 1E028 0300 0315 0062; # (a◌𞀨◌̕◌̀◌֮b; a◌֮◌𞀨◌̀◌̕b; a◌֮◌𞀨◌̀◌̕b; a◌֮◌𞀨◌̀◌̕b; a◌֮◌𞀨◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GLAGOLITIC LETTER BIG YUS, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E029 0062;00E0 05AE 1E029 0315 0062;0061 05AE 0300 1E029 0315 0062;00E0 05AE 1E029 0315 0062;0061 05AE 0300 1E029 0315 0062; # (a◌̕◌̀◌֮◌𞀩b; à◌֮◌𞀩◌̕b; a◌֮◌̀◌𞀩◌̕b; à◌֮◌𞀩◌̕b; a◌֮◌̀◌𞀩◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GLAGOLITIC LETTER IOTATED BIG YUS, LATIN SMALL LETTER B +0061 1E029 0315 0300 05AE 0062;0061 05AE 1E029 0300 0315 0062;0061 05AE 1E029 0300 0315 0062;0061 05AE 1E029 0300 0315 0062;0061 05AE 1E029 0300 0315 0062; # (a◌𞀩◌̕◌̀◌֮b; a◌֮◌𞀩◌̀◌̕b; a◌֮◌𞀩◌̀◌̕b; a◌֮◌𞀩◌̀◌̕b; a◌֮◌𞀩◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GLAGOLITIC LETTER IOTATED BIG YUS, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E02A 0062;00E0 05AE 1E02A 0315 0062;0061 05AE 0300 1E02A 0315 0062;00E0 05AE 1E02A 0315 0062;0061 05AE 0300 1E02A 0315 0062; # (a◌̕◌̀◌֮◌𞀪b; à◌֮◌𞀪◌̕b; a◌֮◌̀◌𞀪◌̕b; à◌֮◌𞀪◌̕b; a◌֮◌̀◌𞀪◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, COMBINING GLAGOLITIC LETTER FITA, LATIN SMALL LETTER B +0061 1E02A 0315 0300 05AE 0062;0061 05AE 1E02A 0300 0315 0062;0061 05AE 1E02A 0300 0315 0062;0061 05AE 1E02A 0300 0315 0062;0061 05AE 1E02A 0300 0315 0062; # (a◌𞀪◌̕◌̀◌֮b; a◌֮◌𞀪◌̀◌̕b; a◌֮◌𞀪◌̀◌̕b; a◌֮◌𞀪◌̀◌̕b; a◌֮◌𞀪◌̀◌̕b; ) LATIN SMALL LETTER A, COMBINING GLAGOLITIC LETTER FITA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B 0061 059A 0316 302A 1E8D0 0062;0061 302A 0316 1E8D0 059A 0062;0061 302A 0316 1E8D0 059A 0062;0061 302A 0316 1E8D0 059A 0062;0061 302A 0316 1E8D0 059A 0062; # (a◌֚◌̖◌〪◌𞣐b; a◌〪◌̖◌𞣐◌֚b; a◌〪◌̖◌𞣐◌֚b; a◌〪◌̖◌𞣐◌֚b; a◌〪◌̖◌𞣐◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, MENDE KIKAKUI COMBINING NUMBER TEENS, LATIN SMALL LETTER B 0061 1E8D0 059A 0316 302A 0062;0061 302A 1E8D0 0316 059A 0062;0061 302A 1E8D0 0316 059A 0062;0061 302A 1E8D0 0316 059A 0062;0061 302A 1E8D0 0316 059A 0062; # (a◌𞣐◌֚◌̖◌〪b; a◌〪◌𞣐◌̖◌֚b; a◌〪◌𞣐◌̖◌֚b; a◌〪◌𞣐◌̖◌֚b; a◌〪◌𞣐◌̖◌֚b; ) LATIN SMALL LETTER A, MENDE KIKAKUI COMBINING NUMBER TEENS, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B 0061 059A 0316 302A 1E8D1 0062;0061 302A 0316 1E8D1 059A 0062;0061 302A 0316 1E8D1 059A 0062;0061 302A 0316 1E8D1 059A 0062;0061 302A 0316 1E8D1 059A 0062; # (a◌֚◌̖◌〪◌𞣑b; a◌〪◌̖◌𞣑◌֚b; a◌〪◌̖◌𞣑◌֚b; a◌〪◌̖◌𞣑◌֚b; a◌〪◌̖◌𞣑◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, MENDE KIKAKUI COMBINING NUMBER TENS, LATIN SMALL LETTER B @@ -18453,6 +18605,20 @@ FFEE;FFEE;FFEE;25CB;25CB; # (○; ○; ○; ○; ○; ) HALFWIDTH WHITE CIRCLE 0061 1E8D5 059A 0316 302A 0062;0061 302A 1E8D5 0316 059A 0062;0061 302A 1E8D5 0316 059A 0062;0061 302A 1E8D5 0316 059A 0062;0061 302A 1E8D5 0316 059A 0062; # (a◌𞣕◌֚◌̖◌〪b; a◌〪◌𞣕◌̖◌֚b; a◌〪◌𞣕◌̖◌֚b; a◌〪◌𞣕◌̖◌֚b; a◌〪◌𞣕◌̖◌֚b; ) LATIN SMALL LETTER A, MENDE KIKAKUI COMBINING NUMBER HUNDRED THOUSANDS, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B 0061 059A 0316 302A 1E8D6 0062;0061 302A 0316 1E8D6 059A 0062;0061 302A 0316 1E8D6 059A 0062;0061 302A 0316 1E8D6 059A 0062;0061 302A 0316 1E8D6 059A 0062; # (a◌֚◌̖◌〪◌𞣖b; a◌〪◌̖◌𞣖◌֚b; a◌〪◌̖◌𞣖◌֚b; a◌〪◌̖◌𞣖◌֚b; a◌〪◌̖◌𞣖◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, MENDE KIKAKUI COMBINING NUMBER MILLIONS, LATIN SMALL LETTER B 0061 1E8D6 059A 0316 302A 0062;0061 302A 1E8D6 0316 059A 0062;0061 302A 1E8D6 0316 059A 0062;0061 302A 1E8D6 0316 059A 0062;0061 302A 1E8D6 0316 059A 0062; # (a◌𞣖◌֚◌̖◌〪b; a◌〪◌𞣖◌̖◌֚b; a◌〪◌𞣖◌̖◌֚b; a◌〪◌𞣖◌̖◌֚b; a◌〪◌𞣖◌̖◌֚b; ) LATIN SMALL LETTER A, MENDE KIKAKUI COMBINING NUMBER MILLIONS, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E944 0062;00E0 05AE 1E944 0315 0062;0061 05AE 0300 1E944 0315 0062;00E0 05AE 1E944 0315 0062;0061 05AE 0300 1E944 0315 0062; # (a◌̕◌̀◌֮◌𞥄b; à◌֮◌𞥄◌̕b; a◌֮◌̀◌𞥄◌̕b; à◌֮◌𞥄◌̕b; a◌֮◌̀◌𞥄◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ADLAM ALIF LENGTHENER, LATIN SMALL LETTER B +0061 1E944 0315 0300 05AE 0062;0061 05AE 1E944 0300 0315 0062;0061 05AE 1E944 0300 0315 0062;0061 05AE 1E944 0300 0315 0062;0061 05AE 1E944 0300 0315 0062; # (a◌𞥄◌̕◌̀◌֮b; a◌֮◌𞥄◌̀◌̕b; a◌֮◌𞥄◌̀◌̕b; a◌֮◌𞥄◌̀◌̕b; a◌֮◌𞥄◌̀◌̕b; ) LATIN SMALL LETTER A, ADLAM ALIF LENGTHENER, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E945 0062;00E0 05AE 1E945 0315 0062;0061 05AE 0300 1E945 0315 0062;00E0 05AE 1E945 0315 0062;0061 05AE 0300 1E945 0315 0062; # (a◌̕◌̀◌֮◌𞥅b; à◌֮◌𞥅◌̕b; a◌֮◌̀◌𞥅◌̕b; à◌֮◌𞥅◌̕b; a◌֮◌̀◌𞥅◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ADLAM VOWEL LENGTHENER, LATIN SMALL LETTER B +0061 1E945 0315 0300 05AE 0062;0061 05AE 1E945 0300 0315 0062;0061 05AE 1E945 0300 0315 0062;0061 05AE 1E945 0300 0315 0062;0061 05AE 1E945 0300 0315 0062; # (a◌𞥅◌̕◌̀◌֮b; a◌֮◌𞥅◌̀◌̕b; a◌֮◌𞥅◌̀◌̕b; a◌֮◌𞥅◌̀◌̕b; a◌֮◌𞥅◌̀◌̕b; ) LATIN SMALL LETTER A, ADLAM VOWEL LENGTHENER, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E946 0062;00E0 05AE 1E946 0315 0062;0061 05AE 0300 1E946 0315 0062;00E0 05AE 1E946 0315 0062;0061 05AE 0300 1E946 0315 0062; # (a◌̕◌̀◌֮◌𞥆b; à◌֮◌𞥆◌̕b; a◌֮◌̀◌𞥆◌̕b; à◌֮◌𞥆◌̕b; a◌֮◌̀◌𞥆◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ADLAM GEMINATION MARK, LATIN SMALL LETTER B +0061 1E946 0315 0300 05AE 0062;0061 05AE 1E946 0300 0315 0062;0061 05AE 1E946 0300 0315 0062;0061 05AE 1E946 0300 0315 0062;0061 05AE 1E946 0300 0315 0062; # (a◌𞥆◌̕◌̀◌֮b; a◌֮◌𞥆◌̀◌̕b; a◌֮◌𞥆◌̀◌̕b; a◌֮◌𞥆◌̀◌̕b; a◌֮◌𞥆◌̀◌̕b; ) LATIN SMALL LETTER A, ADLAM GEMINATION MARK, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E947 0062;00E0 05AE 1E947 0315 0062;0061 05AE 0300 1E947 0315 0062;00E0 05AE 1E947 0315 0062;0061 05AE 0300 1E947 0315 0062; # (a◌̕◌̀◌֮◌𞥇b; à◌֮◌𞥇◌̕b; a◌֮◌̀◌𞥇◌̕b; à◌֮◌𞥇◌̕b; a◌֮◌̀◌𞥇◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ADLAM HAMZA, LATIN SMALL LETTER B +0061 1E947 0315 0300 05AE 0062;0061 05AE 1E947 0300 0315 0062;0061 05AE 1E947 0300 0315 0062;0061 05AE 1E947 0300 0315 0062;0061 05AE 1E947 0300 0315 0062; # (a◌𞥇◌̕◌̀◌֮b; a◌֮◌𞥇◌̀◌̕b; a◌֮◌𞥇◌̀◌̕b; a◌֮◌𞥇◌̀◌̕b; a◌֮◌𞥇◌̀◌̕b; ) LATIN SMALL LETTER A, ADLAM HAMZA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E948 0062;00E0 05AE 1E948 0315 0062;0061 05AE 0300 1E948 0315 0062;00E0 05AE 1E948 0315 0062;0061 05AE 0300 1E948 0315 0062; # (a◌̕◌̀◌֮◌𞥈b; à◌֮◌𞥈◌̕b; a◌֮◌̀◌𞥈◌̕b; à◌֮◌𞥈◌̕b; a◌֮◌̀◌𞥈◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ADLAM CONSONANT MODIFIER, LATIN SMALL LETTER B +0061 1E948 0315 0300 05AE 0062;0061 05AE 1E948 0300 0315 0062;0061 05AE 1E948 0300 0315 0062;0061 05AE 1E948 0300 0315 0062;0061 05AE 1E948 0300 0315 0062; # (a◌𞥈◌̕◌̀◌֮b; a◌֮◌𞥈◌̀◌̕b; a◌֮◌𞥈◌̀◌̕b; a◌֮◌𞥈◌̀◌̕b; a◌֮◌𞥈◌̀◌̕b; ) LATIN SMALL LETTER A, ADLAM CONSONANT MODIFIER, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 0315 0300 05AE 1E949 0062;00E0 05AE 1E949 0315 0062;0061 05AE 0300 1E949 0315 0062;00E0 05AE 1E949 0315 0062;0061 05AE 0300 1E949 0315 0062; # (a◌̕◌̀◌֮◌𞥉b; à◌֮◌𞥉◌̕b; a◌֮◌̀◌𞥉◌̕b; à◌֮◌𞥉◌̕b; a◌֮◌̀◌𞥉◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ADLAM GEMINATE CONSONANT MODIFIER, LATIN SMALL LETTER B +0061 1E949 0315 0300 05AE 0062;0061 05AE 1E949 0300 0315 0062;0061 05AE 1E949 0300 0315 0062;0061 05AE 1E949 0300 0315 0062;0061 05AE 1E949 0300 0315 0062; # (a◌𞥉◌̕◌̀◌֮b; a◌֮◌𞥉◌̀◌̕b; a◌֮◌𞥉◌̀◌̕b; a◌֮◌𞥉◌̀◌̕b; a◌֮◌𞥉◌̀◌̕b; ) LATIN SMALL LETTER A, ADLAM GEMINATE CONSONANT MODIFIER, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B +0061 3099 093C 0334 1E94A 0062;0061 0334 093C 1E94A 3099 0062;0061 0334 093C 1E94A 3099 0062;0061 0334 093C 1E94A 3099 0062;0061 0334 093C 1E94A 3099 0062; # (a◌゙◌़◌̴◌𞥊b; a◌̴◌़◌𞥊◌゙b; a◌̴◌़◌𞥊◌゙b; a◌̴◌़◌𞥊◌゙b; a◌̴◌़◌𞥊◌゙b; ) LATIN SMALL LETTER A, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, COMBINING TILDE OVERLAY, ADLAM NUKTA, LATIN SMALL LETTER B +0061 1E94A 3099 093C 0334 0062;0061 0334 1E94A 093C 3099 0062;0061 0334 1E94A 093C 3099 0062;0061 0334 1E94A 093C 3099 0062;0061 0334 1E94A 093C 3099 0062; # (a◌𞥊◌゙◌़◌̴b; a◌̴◌𞥊◌़◌゙b; a◌̴◌𞥊◌़◌゙b; a◌̴◌𞥊◌़◌゙b; a◌̴◌𞥊◌़◌゙b; ) LATIN SMALL LETTER A, ADLAM NUKTA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, COMBINING TILDE OVERLAY, LATIN SMALL LETTER B # @Part3 # PRI #29 Test # diff --git a/tests/data/SentenceBreakProperty.txt b/tests/data/SentenceBreakProperty.txt index 8dd1abff0f..cd698150f4 100644 --- a/tests/data/SentenceBreakProperty.txt +++ b/tests/data/SentenceBreakProperty.txt @@ -1,10 +1,11 @@ -# SentenceBreakProperty-8.0.0.txt -# Date: 2015-03-11, 22:29:43 GMT [MD] +# SentenceBreakProperty-10.0.0.txt +# Date: 2017-03-08, 08:42:08 GMT +# © 2017 Unicode®, Inc. +# Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries. +# For terms of use, see http://www.unicode.org/terms_of_use.html # # Unicode Character Database -# Copyright (c) 1991-2015 Unicode, Inc. -# For terms of use, see http://www.unicode.org/terms_of_use.html -# For documentation, see http://www.unicode.org/reports/tr44/ +# For documentation, see http://www.unicode.org/reports/tr44/ # ================================================ @@ -53,6 +54,7 @@ 0825..0827 ; Extend # Mn [3] SAMARITAN VOWEL SIGN SHORT A..SAMARITAN VOWEL SIGN U 0829..082D ; Extend # Mn [5] SAMARITAN VOWEL SIGN LONG I..SAMARITAN MARK NEQUDAA 0859..085B ; Extend # Mn [3] MANDAIC AFFRICATION MARK..MANDAIC GEMINATION MARK +08D4..08E1 ; Extend # Mn [14] ARABIC SMALL HIGH WORD AR-RUB..ARABIC SMALL HIGH SIGN SAFHA 08E3..0902 ; Extend # Mn [32] ARABIC TURNED DAMMA BELOW..DEVANAGARI SIGN ANUSVARA 0903 ; Extend # Mc DEVANAGARI SIGN VISARGA 093A ; Extend # Mn DEVANAGARI VOWEL SIGN OE @@ -95,6 +97,7 @@ 0ACB..0ACC ; Extend # Mc [2] GUJARATI VOWEL SIGN O..GUJARATI VOWEL SIGN AU 0ACD ; Extend # Mn GUJARATI SIGN VIRAMA 0AE2..0AE3 ; Extend # Mn [2] GUJARATI VOWEL SIGN VOCALIC L..GUJARATI VOWEL SIGN VOCALIC LL +0AFA..0AFF ; Extend # Mn [6] GUJARATI SIGN SUKUN..GUJARATI SIGN TWO-CIRCLE NUKTA ABOVE 0B01 ; Extend # Mn ORIYA SIGN CANDRABINDU 0B02..0B03 ; Extend # Mc [2] ORIYA SIGN ANUSVARA..ORIYA SIGN VISARGA 0B3C ; Extend # Mn ORIYA SIGN NUKTA @@ -136,8 +139,9 @@ 0CCC..0CCD ; Extend # Mn [2] KANNADA VOWEL SIGN AU..KANNADA SIGN VIRAMA 0CD5..0CD6 ; Extend # Mc [2] KANNADA LENGTH MARK..KANNADA AI LENGTH MARK 0CE2..0CE3 ; Extend # Mn [2] KANNADA VOWEL SIGN VOCALIC L..KANNADA VOWEL SIGN VOCALIC LL -0D01 ; Extend # Mn MALAYALAM SIGN CANDRABINDU +0D00..0D01 ; Extend # Mn [2] MALAYALAM SIGN COMBINING ANUSVARA ABOVE..MALAYALAM SIGN CANDRABINDU 0D02..0D03 ; Extend # Mc [2] MALAYALAM SIGN ANUSVARA..MALAYALAM SIGN VISARGA +0D3B..0D3C ; Extend # Mn [2] MALAYALAM SIGN VERTICAL BAR VIRAMA..MALAYALAM SIGN CIRCULAR VIRAMA 0D3E..0D40 ; Extend # Mc [3] MALAYALAM VOWEL SIGN AA..MALAYALAM VOWEL SIGN II 0D41..0D44 ; Extend # Mn [4] MALAYALAM VOWEL SIGN U..MALAYALAM VOWEL SIGN VOCALIC RR 0D46..0D48 ; Extend # Mc [3] MALAYALAM VOWEL SIGN E..MALAYALAM VOWEL SIGN AI @@ -207,6 +211,7 @@ 17C9..17D3 ; Extend # Mn [11] KHMER SIGN MUUSIKATOAN..KHMER SIGN BATHAMASAT 17DD ; Extend # Mn KHMER SIGN ATTHACAN 180B..180D ; Extend # Mn [3] MONGOLIAN FREE VARIATION SELECTOR ONE..MONGOLIAN FREE VARIATION SELECTOR THREE +1885..1886 ; Extend # Mn [2] MONGOLIAN LETTER ALI GALI BALUDA..MONGOLIAN LETTER ALI GALI THREE BALUDA 18A9 ; Extend # Mn MONGOLIAN LETTER ALI GALI DAGALGA 1920..1922 ; Extend # Mn [3] LIMBU VOWEL SIGN A..LIMBU VOWEL SIGN U 1923..1926 ; Extend # Mc [4] LIMBU VOWEL SIGN EE..LIMBU VOWEL SIGN AU @@ -271,9 +276,10 @@ 1CED ; Extend # Mn VEDIC SIGN TIRYAK 1CF2..1CF3 ; Extend # Mc [2] VEDIC SIGN ARDHAVISARGA..VEDIC SIGN ROTATED ARDHAVISARGA 1CF4 ; Extend # Mn VEDIC TONE CANDRA ABOVE +1CF7 ; Extend # Mc VEDIC SIGN ATIKRAMA 1CF8..1CF9 ; Extend # Mn [2] VEDIC TONE RING ABOVE..VEDIC TONE DOUBLE RING ABOVE -1DC0..1DF5 ; Extend # Mn [54] COMBINING DOTTED GRAVE ACCENT..COMBINING UP TACK ABOVE -1DFC..1DFF ; Extend # Mn [4] COMBINING DOUBLE INVERTED BREVE BELOW..COMBINING RIGHT ARROWHEAD AND DOWN ARROWHEAD BELOW +1DC0..1DF9 ; Extend # Mn [58] COMBINING DOTTED GRAVE ACCENT..COMBINING WIDE INVERTED BRIDGE BELOW +1DFB..1DFF ; Extend # Mn [5] COMBINING DELETION MARK..COMBINING RIGHT ARROWHEAD AND DOWN ARROWHEAD BELOW 200C..200D ; Extend # Cf [2] ZERO WIDTH NON-JOINER..ZERO WIDTH JOINER 20D0..20DC ; Extend # Mn [13] COMBINING LEFT HARPOON ABOVE..COMBINING FOUR DOTS ABOVE 20DD..20E0 ; Extend # Me [4] COMBINING ENCLOSING CIRCLE..COMBINING ENCLOSING CIRCLE BACKSLASH @@ -299,7 +305,7 @@ A825..A826 ; Extend # Mn [2] SYLOTI NAGRI VOWEL SIGN U..SYLOTI NAGRI VOWEL A827 ; Extend # Mc SYLOTI NAGRI VOWEL SIGN OO A880..A881 ; Extend # Mc [2] SAURASHTRA SIGN ANUSVARA..SAURASHTRA SIGN VISARGA A8B4..A8C3 ; Extend # Mc [16] SAURASHTRA CONSONANT SIGN HAARU..SAURASHTRA VOWEL SIGN AU -A8C4 ; Extend # Mn SAURASHTRA SIGN VIRAMA +A8C4..A8C5 ; Extend # Mn [2] SAURASHTRA SIGN VIRAMA..SAURASHTRA SIGN CANDRABINDU A8E0..A8F1 ; Extend # Mn [18] COMBINING DEVANAGARI DIGIT ZERO..COMBINING DEVANAGARI SIGN AVAGRAHA A926..A92D ; Extend # Mn [8] KAYAH LI VOWEL UE..KAYAH LI TONE CALYA PLOPHU A947..A951 ; Extend # Mn [11] REJANG VOWEL SIGN I..REJANG CONSONANT SIGN R @@ -381,6 +387,7 @@ FF9E..FF9F ; Extend # Lm [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDT 11234 ; Extend # Mn KHOJKI SIGN ANUSVARA 11235 ; Extend # Mc KHOJKI SIGN VIRAMA 11236..11237 ; Extend # Mn [2] KHOJKI SIGN NUKTA..KHOJKI SIGN SHADDA +1123E ; Extend # Mn KHOJKI SIGN SUKUN 112DF ; Extend # Mn KHUDAWADI SIGN ANUSVARA 112E0..112E2 ; Extend # Mc [3] KHUDAWADI VOWEL SIGN AA..KHUDAWADI VOWEL SIGN II 112E3..112EA ; Extend # Mn [8] KHUDAWADI VOWEL SIGN U..KHUDAWADI SIGN VIRAMA @@ -396,6 +403,12 @@ FF9E..FF9F ; Extend # Lm [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDT 11362..11363 ; Extend # Mc [2] GRANTHA VOWEL SIGN VOCALIC L..GRANTHA VOWEL SIGN VOCALIC LL 11366..1136C ; Extend # Mn [7] COMBINING GRANTHA DIGIT ZERO..COMBINING GRANTHA DIGIT SIX 11370..11374 ; Extend # Mn [5] COMBINING GRANTHA LETTER A..COMBINING GRANTHA LETTER PA +11435..11437 ; Extend # Mc [3] NEWA VOWEL SIGN AA..NEWA VOWEL SIGN II +11438..1143F ; Extend # Mn [8] NEWA VOWEL SIGN U..NEWA VOWEL SIGN AI +11440..11441 ; Extend # Mc [2] NEWA VOWEL SIGN O..NEWA VOWEL SIGN AU +11442..11444 ; Extend # Mn [3] NEWA SIGN VIRAMA..NEWA SIGN ANUSVARA +11445 ; Extend # Mc NEWA SIGN VISARGA +11446 ; Extend # Mn NEWA SIGN NUKTA 114B0..114B2 ; Extend # Mc [3] TIRHUTA VOWEL SIGN AA..TIRHUTA VOWEL SIGN II 114B3..114B8 ; Extend # Mn [6] TIRHUTA VOWEL SIGN U..TIRHUTA VOWEL SIGN VOCALIC LL 114B9 ; Extend # Mc TIRHUTA VOWEL SIGN E @@ -429,6 +442,36 @@ FF9E..FF9F ; Extend # Lm [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDT 11722..11725 ; Extend # Mn [4] AHOM VOWEL SIGN I..AHOM VOWEL SIGN UU 11726 ; Extend # Mc AHOM VOWEL SIGN E 11727..1172B ; Extend # Mn [5] AHOM VOWEL SIGN AW..AHOM SIGN KILLER +11A01..11A06 ; Extend # Mn [6] ZANABAZAR SQUARE VOWEL SIGN I..ZANABAZAR SQUARE VOWEL SIGN O +11A07..11A08 ; Extend # Mc [2] ZANABAZAR SQUARE VOWEL SIGN AI..ZANABAZAR SQUARE VOWEL SIGN AU +11A09..11A0A ; Extend # Mn [2] ZANABAZAR SQUARE VOWEL SIGN REVERSED I..ZANABAZAR SQUARE VOWEL LENGTH MARK +11A33..11A38 ; Extend # Mn [6] ZANABAZAR SQUARE FINAL CONSONANT MARK..ZANABAZAR SQUARE SIGN ANUSVARA +11A39 ; Extend # Mc ZANABAZAR SQUARE SIGN VISARGA +11A3B..11A3E ; Extend # Mn [4] ZANABAZAR SQUARE CLUSTER-FINAL LETTER YA..ZANABAZAR SQUARE CLUSTER-FINAL LETTER VA +11A47 ; Extend # Mn ZANABAZAR SQUARE SUBJOINER +11A51..11A56 ; Extend # Mn [6] SOYOMBO VOWEL SIGN I..SOYOMBO VOWEL SIGN OE +11A57..11A58 ; Extend # Mc [2] SOYOMBO VOWEL SIGN AI..SOYOMBO VOWEL SIGN AU +11A59..11A5B ; Extend # Mn [3] SOYOMBO VOWEL SIGN VOCALIC R..SOYOMBO VOWEL LENGTH MARK +11A8A..11A96 ; Extend # Mn [13] SOYOMBO FINAL CONSONANT SIGN G..SOYOMBO SIGN ANUSVARA +11A97 ; Extend # Mc SOYOMBO SIGN VISARGA +11A98..11A99 ; Extend # Mn [2] SOYOMBO GEMINATION MARK..SOYOMBO SUBJOINER +11C2F ; Extend # Mc BHAIKSUKI VOWEL SIGN AA +11C30..11C36 ; Extend # Mn [7] BHAIKSUKI VOWEL SIGN I..BHAIKSUKI VOWEL SIGN VOCALIC L +11C38..11C3D ; Extend # Mn [6] BHAIKSUKI VOWEL SIGN E..BHAIKSUKI SIGN ANUSVARA +11C3E ; Extend # Mc BHAIKSUKI SIGN VISARGA +11C3F ; Extend # Mn BHAIKSUKI SIGN VIRAMA +11C92..11CA7 ; Extend # Mn [22] MARCHEN SUBJOINED LETTER KA..MARCHEN SUBJOINED LETTER ZA +11CA9 ; Extend # Mc MARCHEN SUBJOINED LETTER YA +11CAA..11CB0 ; Extend # Mn [7] MARCHEN SUBJOINED LETTER RA..MARCHEN VOWEL SIGN AA +11CB1 ; Extend # Mc MARCHEN VOWEL SIGN I +11CB2..11CB3 ; Extend # Mn [2] MARCHEN VOWEL SIGN U..MARCHEN VOWEL SIGN E +11CB4 ; Extend # Mc MARCHEN VOWEL SIGN O +11CB5..11CB6 ; Extend # Mn [2] MARCHEN SIGN ANUSVARA..MARCHEN SIGN CANDRABINDU +11D31..11D36 ; Extend # Mn [6] MASARAM GONDI VOWEL SIGN AA..MASARAM GONDI VOWEL SIGN VOCALIC R +11D3A ; Extend # Mn MASARAM GONDI VOWEL SIGN E +11D3C..11D3D ; Extend # Mn [2] MASARAM GONDI VOWEL SIGN AI..MASARAM GONDI VOWEL SIGN O +11D3F..11D45 ; Extend # Mn [7] MASARAM GONDI VOWEL SIGN AU..MASARAM GONDI VIRAMA +11D47 ; Extend # Mn MASARAM GONDI RA-KARA 16AF0..16AF4 ; Extend # Mn [5] BASSA VAH COMBINING HIGH TONE..BASSA VAH COMBINING HIGH-LOW TONE 16B30..16B36 ; Extend # Mn [7] PAHAWH HMONG MARK CIM TUB..PAHAWH HMONG MARK CIM TAUM 16F51..16F7E ; Extend # Mc [46] MIAO SIGN ASPIRATION..MIAO VOWEL SIGN NG @@ -447,10 +490,17 @@ FF9E..FF9F ; Extend # Lm [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDT 1DA84 ; Extend # Mn SIGNWRITING LOCATION HEAD NECK 1DA9B..1DA9F ; Extend # Mn [5] SIGNWRITING FILL MODIFIER-2..SIGNWRITING FILL MODIFIER-6 1DAA1..1DAAF ; Extend # Mn [15] SIGNWRITING ROTATION MODIFIER-2..SIGNWRITING ROTATION MODIFIER-16 +1E000..1E006 ; Extend # Mn [7] COMBINING GLAGOLITIC LETTER AZU..COMBINING GLAGOLITIC LETTER ZHIVETE +1E008..1E018 ; Extend # Mn [17] COMBINING GLAGOLITIC LETTER ZEMLJA..COMBINING GLAGOLITIC LETTER HERU +1E01B..1E021 ; Extend # Mn [7] COMBINING GLAGOLITIC LETTER SHTA..COMBINING GLAGOLITIC LETTER YATI +1E023..1E024 ; Extend # Mn [2] COMBINING GLAGOLITIC LETTER YU..COMBINING GLAGOLITIC LETTER SMALL YUS +1E026..1E02A ; Extend # Mn [5] COMBINING GLAGOLITIC LETTER YO..COMBINING GLAGOLITIC LETTER FITA 1E8D0..1E8D6 ; Extend # Mn [7] MENDE KIKAKUI COMBINING NUMBER TEENS..MENDE KIKAKUI COMBINING NUMBER MILLIONS +1E944..1E94A ; Extend # Mn [7] ADLAM ALIF LENGTHENER..ADLAM NUKTA +E0020..E007F ; Extend # Cf [96] TAG SPACE..CANCEL TAG E0100..E01EF ; Extend # Mn [240] VARIATION SELECTOR-17..VARIATION SELECTOR-256 -# Total code points: 1967 +# Total code points: 2277 # ================================================ @@ -467,6 +517,7 @@ E0100..E01EF ; Extend # Mn [240] VARIATION SELECTOR-17..VARIATION SELECTOR-256 061C ; Format # Cf ARABIC LETTER MARK 06DD ; Format # Cf ARABIC END OF AYAH 070F ; Format # Cf SYRIAC ABBREVIATION MARK +08E2 ; Format # Cf ARABIC DISPUTED END OF AYAH 180E ; Format # Cf MONGOLIAN VOWEL SEPARATOR 200B ; Format # Cf ZERO WIDTH SPACE 200E..200F ; Format # Cf [2] LEFT-TO-RIGHT MARK..RIGHT-TO-LEFT MARK @@ -479,9 +530,8 @@ FFF9..FFFB ; Format # Cf [3] INTERLINEAR ANNOTATION ANCHOR..INTERLINEAR ANN 1BCA0..1BCA3 ; Format # Cf [4] SHORTHAND FORMAT LETTER OVERLAP..SHORTHAND FORMAT UP STEP 1D173..1D17A ; Format # Cf [8] MUSICAL SYMBOL BEGIN BEAM..MUSICAL SYMBOL END PHRASE E0001 ; Format # Cf LANGUAGE TAG -E0020..E007F ; Format # Cf [96] TAG SPACE..CANCEL TAG -# Total code points: 148 +# Total code points: 53 # ================================================ @@ -776,6 +826,7 @@ E0020..E007F ; Format # Cf [96] TAG SPACE..CANCEL TAG 052F ; Lower # L& CYRILLIC SMALL LETTER EL WITH DESCENDER 0561..0587 ; Lower # L& [39] ARMENIAN SMALL LETTER AYB..ARMENIAN SMALL LIGATURE ECH YIWN 13F8..13FD ; Lower # L& [6] CHEROKEE SMALL LETTER YE..CHEROKEE SMALL LETTER MV +1C80..1C88 ; Lower # L& [9] CYRILLIC SMALL LETTER ROUNDED VE..CYRILLIC SMALL LETTER UNBLENDED UK 1D00..1D2B ; Lower # L& [44] LATIN LETTER SMALL CAPITAL A..CYRILLIC LETTER SMALL CAPITAL EL 1D2C..1D6A ; Lower # Lm [63] MODIFIER LETTER CAPITAL A..GREEK SUBSCRIPT SMALL LETTER CHI 1D6B..1D77 ; Lower # L& [13] LATIN SMALL LETTER UE..LATIN SMALL LETTER TURNED G @@ -1118,6 +1169,7 @@ FB00..FB06 ; Lower # L& [7] LATIN SMALL LIGATURE FF..LATIN SMALL LIGATURE S FB13..FB17 ; Lower # L& [5] ARMENIAN SMALL LIGATURE MEN NOW..ARMENIAN SMALL LIGATURE MEN XEH FF41..FF5A ; Lower # L& [26] FULLWIDTH LATIN SMALL LETTER A..FULLWIDTH LATIN SMALL LETTER Z 10428..1044F ; Lower # L& [40] DESERET SMALL LETTER LONG I..DESERET SMALL LETTER EW +104D8..104FB ; Lower # L& [36] OSAGE SMALL LETTER A..OSAGE SMALL LETTER ZHA 10CC0..10CF2 ; Lower # L& [51] OLD HUNGARIAN SMALL LETTER A..OLD HUNGARIAN SMALL LETTER US 118C0..118DF ; Lower # L& [32] WARANG CITI SMALL LETTER NGAA..WARANG CITI SMALL LETTER VIYO 1D41A..1D433 ; Lower # L& [26] MATHEMATICAL BOLD SMALL A..MATHEMATICAL BOLD SMALL Z @@ -1148,8 +1200,9 @@ FF41..FF5A ; Lower # L& [26] FULLWIDTH LATIN SMALL LETTER A..FULLWIDTH LATIN 1D7AA..1D7C2 ; Lower # L& [25] MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL ALPHA..MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL OMEGA 1D7C4..1D7C9 ; Lower # L& [6] MATHEMATICAL SANS-SERIF BOLD ITALIC EPSILON SYMBOL..MATHEMATICAL SANS-SERIF BOLD ITALIC PI SYMBOL 1D7CB ; Lower # L& MATHEMATICAL BOLD SMALL DIGAMMA +1E922..1E943 ; Lower # L& [34] ADLAM SMALL LETTER ALIF..ADLAM SMALL LETTER SHA -# Total code points: 2172 +# Total code points: 2251 # ================================================ @@ -1745,11 +1798,12 @@ A7A2 ; Upper # L& LATIN CAPITAL LETTER K WITH OBLIQUE STROKE A7A4 ; Upper # L& LATIN CAPITAL LETTER N WITH OBLIQUE STROKE A7A6 ; Upper # L& LATIN CAPITAL LETTER R WITH OBLIQUE STROKE A7A8 ; Upper # L& LATIN CAPITAL LETTER S WITH OBLIQUE STROKE -A7AA..A7AD ; Upper # L& [4] LATIN CAPITAL LETTER H WITH HOOK..LATIN CAPITAL LETTER L WITH BELT +A7AA..A7AE ; Upper # L& [5] LATIN CAPITAL LETTER H WITH HOOK..LATIN CAPITAL LETTER SMALL CAPITAL I A7B0..A7B4 ; Upper # L& [5] LATIN CAPITAL LETTER TURNED K..LATIN CAPITAL LETTER BETA A7B6 ; Upper # L& LATIN CAPITAL LETTER OMEGA FF21..FF3A ; Upper # L& [26] FULLWIDTH LATIN CAPITAL LETTER A..FULLWIDTH LATIN CAPITAL LETTER Z 10400..10427 ; Upper # L& [40] DESERET CAPITAL LETTER LONG I..DESERET CAPITAL LETTER EW +104B0..104D3 ; Upper # L& [36] OSAGE CAPITAL LETTER A..OSAGE CAPITAL LETTER ZHA 10C80..10CB2 ; Upper # L& [51] OLD HUNGARIAN CAPITAL LETTER A..OLD HUNGARIAN CAPITAL LETTER US 118A0..118BF ; Upper # L& [32] WARANG CITI CAPITAL LETTER NGAA..WARANG CITI CAPITAL LETTER VIYO 1D400..1D419 ; Upper # L& [26] MATHEMATICAL BOLD CAPITAL A..MATHEMATICAL BOLD CAPITAL Z @@ -1783,11 +1837,12 @@ FF21..FF3A ; Upper # L& [26] FULLWIDTH LATIN CAPITAL LETTER A..FULLWIDTH LAT 1D756..1D76E ; Upper # L& [25] MATHEMATICAL SANS-SERIF BOLD CAPITAL ALPHA..MATHEMATICAL SANS-SERIF BOLD CAPITAL OMEGA 1D790..1D7A8 ; Upper # L& [25] MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL ALPHA..MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL OMEGA 1D7CA ; Upper # L& MATHEMATICAL BOLD CAPITAL DIGAMMA +1E900..1E921 ; Upper # L& [34] ADLAM CAPITAL LETTER ALIF..ADLAM CAPITAL LETTER SHA 1F130..1F149 ; Upper # So [26] SQUARED LATIN CAPITAL LETTER A..SQUARED LATIN CAPITAL LETTER Z 1F150..1F169 ; Upper # So [26] NEGATIVE CIRCLED LATIN CAPITAL LETTER A..NEGATIVE CIRCLED LATIN CAPITAL LETTER Z 1F170..1F189 ; Upper # So [26] NEGATIVE SQUARED LATIN CAPITAL LETTER A..NEGATIVE SQUARED LATIN CAPITAL LETTER Z -# Total code points: 1782 +# Total code points: 1853 # ================================================ @@ -1825,7 +1880,9 @@ FF21..FF3A ; Upper # L& [26] FULLWIDTH LATIN CAPITAL LETTER A..FULLWIDTH LAT 0824 ; OLetter # Lm SAMARITAN MODIFIER LETTER SHORT A 0828 ; OLetter # Lm SAMARITAN MODIFIER LETTER I 0840..0858 ; OLetter # Lo [25] MANDAIC LETTER HALQA..MANDAIC LETTER AIN +0860..086A ; OLetter # Lo [11] SYRIAC LETTER MALAYALAM NGA..SYRIAC LETTER MALAYALAM SSA 08A0..08B4 ; OLetter # Lo [21] ARABIC LETTER BEH WITH SMALL V BELOW..ARABIC LETTER KAF WITH DOT BELOW +08B6..08BD ; OLetter # Lo [8] ARABIC LETTER BEH WITH SMALL MEEM ABOVE..ARABIC LETTER AFRICAN NOON 0904..0939 ; OLetter # Lo [54] DEVANAGARI LETTER SHORT A..DEVANAGARI LETTER HA 093D ; OLetter # Lo DEVANAGARI SIGN AVAGRAHA 0950 ; OLetter # Lo DEVANAGARI OM @@ -1843,6 +1900,7 @@ FF21..FF3A ; Upper # L& [26] FULLWIDTH LATIN CAPITAL LETTER A..FULLWIDTH LAT 09DC..09DD ; OLetter # Lo [2] BENGALI LETTER RRA..BENGALI LETTER RHA 09DF..09E1 ; OLetter # Lo [3] BENGALI LETTER YYA..BENGALI LETTER VOCALIC LL 09F0..09F1 ; OLetter # Lo [2] BENGALI LETTER RA WITH MIDDLE DIAGONAL..BENGALI LETTER RA WITH LOWER DIAGONAL +09FC ; OLetter # Lo BENGALI LETTER VEDIC ANUSVARA 0A05..0A0A ; OLetter # Lo [6] GURMUKHI LETTER A..GURMUKHI LETTER UU 0A0F..0A10 ; OLetter # Lo [2] GURMUKHI LETTER EE..GURMUKHI LETTER AI 0A13..0A28 ; OLetter # Lo [22] GURMUKHI LETTER OO..GURMUKHI LETTER NA @@ -1891,6 +1949,7 @@ FF21..FF3A ; Upper # L& [26] FULLWIDTH LATIN CAPITAL LETTER A..FULLWIDTH LAT 0C3D ; OLetter # Lo TELUGU SIGN AVAGRAHA 0C58..0C5A ; OLetter # Lo [3] TELUGU LETTER TSA..TELUGU LETTER RRRA 0C60..0C61 ; OLetter # Lo [2] TELUGU LETTER VOCALIC RR..TELUGU LETTER VOCALIC LL +0C80 ; OLetter # Lo KANNADA SIGN SPACING CANDRABINDU 0C85..0C8C ; OLetter # Lo [8] KANNADA LETTER A..KANNADA LETTER VOCALIC L 0C8E..0C90 ; OLetter # Lo [3] KANNADA LETTER E..KANNADA LETTER AI 0C92..0CA8 ; OLetter # Lo [23] KANNADA LETTER O..KANNADA LETTER NA @@ -1905,6 +1964,7 @@ FF21..FF3A ; Upper # L& [26] FULLWIDTH LATIN CAPITAL LETTER A..FULLWIDTH LAT 0D12..0D3A ; OLetter # Lo [41] MALAYALAM LETTER O..MALAYALAM LETTER TTTA 0D3D ; OLetter # Lo MALAYALAM SIGN AVAGRAHA 0D4E ; OLetter # Lo MALAYALAM LETTER DOT REPH +0D54..0D56 ; OLetter # Lo [3] MALAYALAM LETTER CHILLU M..MALAYALAM LETTER CHILLU LLL 0D5F..0D61 ; OLetter # Lo [3] MALAYALAM LETTER ARCHAIC II..MALAYALAM LETTER VOCALIC LL 0D7A..0D7F ; OLetter # Lo [6] MALAYALAM LETTER CHILLU NN..MALAYALAM LETTER CHILLU K 0D85..0D96 ; OLetter # Lo [18] SINHALA LETTER AYANNA..SINHALA LETTER AUYANNA @@ -1983,7 +2043,8 @@ FF21..FF3A ; Upper # L& [26] FULLWIDTH LATIN CAPITAL LETTER A..FULLWIDTH LAT 1820..1842 ; OLetter # Lo [35] MONGOLIAN LETTER A..MONGOLIAN LETTER CHI 1843 ; OLetter # Lm MONGOLIAN LETTER TODO LONG VOWEL SIGN 1844..1877 ; OLetter # Lo [52] MONGOLIAN LETTER TODO E..MONGOLIAN LETTER MANCHU ZHA -1880..18A8 ; OLetter # Lo [41] MONGOLIAN LETTER ALI GALI ANUSVARA ONE..MONGOLIAN LETTER MANCHU ALI GALI BHA +1880..1884 ; OLetter # Lo [5] MONGOLIAN LETTER ALI GALI ANUSVARA ONE..MONGOLIAN LETTER ALI GALI INVERTED UBADAMA +1887..18A8 ; OLetter # Lo [34] MONGOLIAN LETTER ALI GALI A..MONGOLIAN LETTER MANCHU ALI GALI BHA 18AA ; OLetter # Lo MONGOLIAN LETTER MANCHU ALI GALI LHA 18B0..18F5 ; OLetter # Lo [70] CANADIAN SYLLABICS OY..CANADIAN SYLLABICS CARRIER DENTAL S 1900..191E ; OLetter # Lo [31] LIMBU VOWEL-CARRIER LETTER..LIMBU LETTER TRA @@ -2035,12 +2096,12 @@ FF21..FF3A ; Upper # L& [26] FULLWIDTH LATIN CAPITAL LETTER A..FULLWIDTH LAT 30A1..30FA ; OLetter # Lo [90] KATAKANA LETTER SMALL A..KATAKANA LETTER VO 30FC..30FE ; OLetter # Lm [3] KATAKANA-HIRAGANA PROLONGED SOUND MARK..KATAKANA VOICED ITERATION MARK 30FF ; OLetter # Lo KATAKANA DIGRAPH KOTO -3105..312D ; OLetter # Lo [41] BOPOMOFO LETTER B..BOPOMOFO LETTER IH +3105..312E ; OLetter # Lo [42] BOPOMOFO LETTER B..BOPOMOFO LETTER O WITH DOT ABOVE 3131..318E ; OLetter # Lo [94] HANGUL LETTER KIYEOK..HANGUL LETTER ARAEAE 31A0..31BA ; OLetter # Lo [27] BOPOMOFO LETTER BU..BOPOMOFO LETTER ZY 31F0..31FF ; OLetter # Lo [16] KATAKANA LETTER SMALL KU..KATAKANA LETTER SMALL RO 3400..4DB5 ; OLetter # Lo [6582] CJK UNIFIED IDEOGRAPH-3400..CJK UNIFIED IDEOGRAPH-4DB5 -4E00..9FD5 ; OLetter # Lo [20950] CJK UNIFIED IDEOGRAPH-4E00..CJK UNIFIED IDEOGRAPH-9FD5 +4E00..9FEA ; OLetter # Lo [20971] CJK UNIFIED IDEOGRAPH-4E00..CJK UNIFIED IDEOGRAPH-9FEA A000..A014 ; OLetter # Lo [21] YI SYLLABLE IT..YI SYLLABLE E A015 ; OLetter # Lm YI SYLLABLE WU A016..A48C ; OLetter # Lo [1143] YI SYLLABLE BIT..YI SYLLABLE YYR @@ -2138,7 +2199,7 @@ FFDA..FFDC ; OLetter # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGUL 10280..1029C ; OLetter # Lo [29] LYCIAN LETTER A..LYCIAN LETTER X 102A0..102D0 ; OLetter # Lo [49] CARIAN LETTER A..CARIAN LETTER UUU3 10300..1031F ; OLetter # Lo [32] OLD ITALIC LETTER A..OLD ITALIC LETTER ESS -10330..10340 ; OLetter # Lo [17] GOTHIC LETTER AHSA..GOTHIC LETTER PAIRTHRA +1032D..10340 ; OLetter # Lo [20] OLD ITALIC LETTER YE..GOTHIC LETTER PAIRTHRA 10341 ; OLetter # Nl GOTHIC LETTER NINETY 10342..10349 ; OLetter # Lo [8] GOTHIC LETTER RAIDA..GOTHIC LETTER OTHAL 1034A ; OLetter # Nl GOTHIC LETTER NINE HUNDRED @@ -2207,6 +2268,8 @@ FFDA..FFDC ; OLetter # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGUL 1133D ; OLetter # Lo GRANTHA SIGN AVAGRAHA 11350 ; OLetter # Lo GRANTHA OM 1135D..11361 ; OLetter # Lo [5] GRANTHA SIGN PLUTA..GRANTHA LETTER VOCALIC LL +11400..11434 ; OLetter # Lo [53] NEWA LETTER A..NEWA LETTER HA +11447..1144A ; OLetter # Lo [4] NEWA SIGN AVAGRAHA..NEWA SIDDHI 11480..114AF ; OLetter # Lo [48] TIRHUTA ANJI..TIRHUTA LETTER HA 114C4..114C5 ; OLetter # Lo [2] TIRHUTA SIGN AVAGRAHA..TIRHUTA GVANG 114C7 ; OLetter # Lo TIRHUTA OM @@ -2217,7 +2280,21 @@ FFDA..FFDC ; OLetter # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGUL 11680..116AA ; OLetter # Lo [43] TAKRI LETTER A..TAKRI LETTER RRA 11700..11719 ; OLetter # Lo [26] AHOM LETTER KA..AHOM LETTER JHA 118FF ; OLetter # Lo WARANG CITI OM +11A00 ; OLetter # Lo ZANABAZAR SQUARE LETTER A +11A0B..11A32 ; OLetter # Lo [40] ZANABAZAR SQUARE LETTER KA..ZANABAZAR SQUARE LETTER KSSA +11A3A ; OLetter # Lo ZANABAZAR SQUARE CLUSTER-INITIAL LETTER RA +11A50 ; OLetter # Lo SOYOMBO LETTER A +11A5C..11A83 ; OLetter # Lo [40] SOYOMBO LETTER KA..SOYOMBO LETTER KSSA +11A86..11A89 ; OLetter # Lo [4] SOYOMBO CLUSTER-INITIAL LETTER RA..SOYOMBO CLUSTER-INITIAL LETTER SA 11AC0..11AF8 ; OLetter # Lo [57] PAU CIN HAU LETTER PA..PAU CIN HAU GLOTTAL STOP FINAL +11C00..11C08 ; OLetter # Lo [9] BHAIKSUKI LETTER A..BHAIKSUKI LETTER VOCALIC L +11C0A..11C2E ; OLetter # Lo [37] BHAIKSUKI LETTER E..BHAIKSUKI LETTER HA +11C40 ; OLetter # Lo BHAIKSUKI SIGN AVAGRAHA +11C72..11C8F ; OLetter # Lo [30] MARCHEN LETTER KA..MARCHEN LETTER A +11D00..11D06 ; OLetter # Lo [7] MASARAM GONDI LETTER A..MASARAM GONDI LETTER E +11D08..11D09 ; OLetter # Lo [2] MASARAM GONDI LETTER AI..MASARAM GONDI LETTER O +11D0B..11D30 ; OLetter # Lo [38] MASARAM GONDI LETTER AU..MASARAM GONDI LETTER TRA +11D46 ; OLetter # Lo MASARAM GONDI REPHA 12000..12399 ; OLetter # Lo [922] CUNEIFORM SIGN A..CUNEIFORM SIGN U U 12400..1246E ; OLetter # Nl [111] CUNEIFORM NUMERIC SIGN TWO ASH..CUNEIFORM NUMERIC SIGN NINE U VARIANT FORM 12480..12543 ; OLetter # Lo [196] CUNEIFORM SIGN AB TIMES NUN TENU..CUNEIFORM SIGN ZU5 TIMES THREE DISH TENU @@ -2233,7 +2310,11 @@ FFDA..FFDC ; OLetter # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGUL 16F00..16F44 ; OLetter # Lo [69] MIAO LETTER PA..MIAO LETTER HHA 16F50 ; OLetter # Lo MIAO LETTER NASALIZATION 16F93..16F9F ; OLetter # Lm [13] MIAO LETTER TONE-2..MIAO LETTER REFORMED TONE-8 -1B000..1B001 ; OLetter # Lo [2] KATAKANA LETTER ARCHAIC E..HIRAGANA LETTER ARCHAIC YE +16FE0..16FE1 ; OLetter # Lm [2] TANGUT ITERATION MARK..NUSHU ITERATION MARK +17000..187EC ; OLetter # Lo [6125] TANGUT IDEOGRAPH-17000..TANGUT IDEOGRAPH-187EC +18800..18AF2 ; OLetter # Lo [755] TANGUT COMPONENT-001..TANGUT COMPONENT-755 +1B000..1B11E ; OLetter # Lo [287] KATAKANA LETTER ARCHAIC E..HENTAIGANA LETTER N-MU-MO-2 +1B170..1B2FB ; OLetter # Lo [396] NUSHU CHARACTER-1B170..NUSHU CHARACTER-1B2FB 1BC00..1BC6A ; OLetter # Lo [107] DUPLOYAN LETTER H..DUPLOYAN LETTER VOCALIC M 1BC70..1BC7C ; OLetter # Lo [13] DUPLOYAN AFFIX LEFT HORIZONTAL SECANT..DUPLOYAN AFFIX ATTACHED TANGENT HOOK 1BC80..1BC88 ; OLetter # Lo [9] DUPLOYAN AFFIX HIGH ACUTE..DUPLOYAN AFFIX HIGH VERTICAL @@ -2276,9 +2357,10 @@ FFDA..FFDC ; OLetter # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGUL 2A700..2B734 ; OLetter # Lo [4149] CJK UNIFIED IDEOGRAPH-2A700..CJK UNIFIED IDEOGRAPH-2B734 2B740..2B81D ; OLetter # Lo [222] CJK UNIFIED IDEOGRAPH-2B740..CJK UNIFIED IDEOGRAPH-2B81D 2B820..2CEA1 ; OLetter # Lo [5762] CJK UNIFIED IDEOGRAPH-2B820..CJK UNIFIED IDEOGRAPH-2CEA1 +2CEB0..2EBE0 ; OLetter # Lo [7473] CJK UNIFIED IDEOGRAPH-2CEB0..CJK UNIFIED IDEOGRAPH-2EBE0 2F800..2FA1D ; OLetter # Lo [542] CJK COMPATIBILITY IDEOGRAPH-2F800..CJK COMPATIBILITY IDEOGRAPH-2FA1D -# Total code points: 106002 +# Total code points: 121354 # ================================================ @@ -2325,16 +2407,20 @@ ABF0..ABF9 ; Numeric # Nd [10] MEETEI MAYEK DIGIT ZERO..MEETEI MAYEK DIGIT N 11136..1113F ; Numeric # Nd [10] CHAKMA DIGIT ZERO..CHAKMA DIGIT NINE 111D0..111D9 ; Numeric # Nd [10] SHARADA DIGIT ZERO..SHARADA DIGIT NINE 112F0..112F9 ; Numeric # Nd [10] KHUDAWADI DIGIT ZERO..KHUDAWADI DIGIT NINE +11450..11459 ; Numeric # Nd [10] NEWA DIGIT ZERO..NEWA DIGIT NINE 114D0..114D9 ; Numeric # Nd [10] TIRHUTA DIGIT ZERO..TIRHUTA DIGIT NINE 11650..11659 ; Numeric # Nd [10] MODI DIGIT ZERO..MODI DIGIT NINE 116C0..116C9 ; Numeric # Nd [10] TAKRI DIGIT ZERO..TAKRI DIGIT NINE 11730..11739 ; Numeric # Nd [10] AHOM DIGIT ZERO..AHOM DIGIT NINE 118E0..118E9 ; Numeric # Nd [10] WARANG CITI DIGIT ZERO..WARANG CITI DIGIT NINE +11C50..11C59 ; Numeric # Nd [10] BHAIKSUKI DIGIT ZERO..BHAIKSUKI DIGIT NINE +11D50..11D59 ; Numeric # Nd [10] MASARAM GONDI DIGIT ZERO..MASARAM GONDI DIGIT NINE 16A60..16A69 ; Numeric # Nd [10] MRO DIGIT ZERO..MRO DIGIT NINE 16B50..16B59 ; Numeric # Nd [10] PAHAWH HMONG DIGIT ZERO..PAHAWH HMONG DIGIT NINE 1D7CE..1D7FF ; Numeric # Nd [50] MATHEMATICAL BOLD DIGIT ZERO..MATHEMATICAL MONOSPACE DIGIT NINE +1E950..1E959 ; Numeric # Nd [10] ADLAM DIGIT ZERO..ADLAM DIGIT NINE -# Total code points: 542 +# Total code points: 582 # ================================================ @@ -2398,10 +2484,14 @@ FF61 ; STerm # Po HALFWIDTH IDEOGRAPHIC FULL STOP 11238..11239 ; STerm # Po [2] KHOJKI DANDA..KHOJKI DOUBLE DANDA 1123B..1123C ; STerm # Po [2] KHOJKI SECTION MARK..KHOJKI DOUBLE SECTION MARK 112A9 ; STerm # Po MULTANI SECTION MARK +1144B..1144C ; STerm # Po [2] NEWA DANDA..NEWA DOUBLE DANDA 115C2..115C3 ; STerm # Po [2] SIDDHAM DANDA..SIDDHAM DOUBLE DANDA 115C9..115D7 ; STerm # Po [15] SIDDHAM END OF TEXT MARK..SIDDHAM SECTION MARK WITH CIRCLES AND FOUR ENCLOSURES 11641..11642 ; STerm # Po [2] MODI DANDA..MODI DOUBLE DANDA 1173C..1173E ; STerm # Po [3] AHOM SIGN SMALL SECTION..AHOM SIGN RULAI +11A42..11A43 ; STerm # Po [2] ZANABAZAR SQUARE MARK SHAD..ZANABAZAR SQUARE MARK DOUBLE SHAD +11A9B..11A9C ; STerm # Po [2] SOYOMBO MARK SHAD..SOYOMBO MARK DOUBLE SHAD +11C41..11C42 ; STerm # Po [2] BHAIKSUKI DANDA..BHAIKSUKI DOUBLE DANDA 16A6E..16A6F ; STerm # Po [2] MRO DANDA..MRO DOUBLE DANDA 16AF5 ; STerm # Po BASSA VAH FULL STOP 16B37..16B38 ; STerm # Po [2] PAHAWH HMONG SIGN VOS THOM..PAHAWH HMONG SIGN VOS TSHAB CEEB @@ -2409,7 +2499,7 @@ FF61 ; STerm # Po HALFWIDTH IDEOGRAPHIC FULL STOP 1BC9F ; STerm # Po DUPLOYAN PUNCTUATION CHINOOK FULL STOP 1DA88 ; STerm # Po SIGNWRITING FULL STOP -# Total code points: 117 +# Total code points: 125 # ================================================ diff --git a/tests/data/SentenceBreakTest.txt b/tests/data/SentenceBreakTest.txt index 279e6db06d..2985b84cf8 100644 --- a/tests/data/SentenceBreakTest.txt +++ b/tests/data/SentenceBreakTest.txt @@ -1,291 +1,293 @@ -# SentenceBreakTest-8.0.0.txt -# Date: 2015-04-30, 09:40:15 GMT [MD] +# SentenceBreakTest-10.0.0.txt +# Date: 2017-04-14, 05:40:43 GMT +# © 2017 Unicode®, Inc. +# Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries. +# For terms of use, see http://www.unicode.org/terms_of_use.html # # Unicode Character Database -# Copyright (c) 1991-2015 Unicode, Inc. -# For terms of use, see http://www.unicode.org/terms_of_use.html -# For documentation, see http://www.unicode.org/reports/tr44/ +# For documentation, see http://www.unicode.org/reports/tr44/ # -# Default Sentence Break Test +# Default Sentence_Break Test # # Format: -# <string> (# <comment>)? -# <string> contains hex Unicode code points, with -# ÷ wherever there is a break opportunity, and +# <string> (# <comment>)? +# <string> contains hex Unicode code points, with +# ÷ wherever there is a break opportunity, and # × wherever there is not. # <comment> the format can change, but currently it shows: # - the sample character name # - (x) the Sentence_Break property value for the sample character -# - [x] the rule that determines whether there is a break or not +# - [x] the rule that determines whether there is a break or not, +# as listed in the Rules section of SentenceBreakTest.html # # These samples may be extended or changed in the future. # -÷ 0001 × 0001 ÷ # ÷ [0.2] <START OF HEADING> (Other) × [12.0] <START OF HEADING> (Other) ÷ [0.3] -÷ 0001 × 0308 × 0001 ÷ # ÷ [0.2] <START OF HEADING> (Other) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] <START OF HEADING> (Other) ÷ [0.3] -÷ 0001 × 000D ÷ # ÷ [0.2] <START OF HEADING> (Other) × [12.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -÷ 0001 × 0308 × 000D ÷ # ÷ [0.2] <START OF HEADING> (Other) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -÷ 0001 × 000A ÷ # ÷ [0.2] <START OF HEADING> (Other) × [12.0] <LINE FEED (LF)> (LF) ÷ [0.3] -÷ 0001 × 0308 × 000A ÷ # ÷ [0.2] <START OF HEADING> (Other) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] <LINE FEED (LF)> (LF) ÷ [0.3] -÷ 0001 × 0085 ÷ # ÷ [0.2] <START OF HEADING> (Other) × [12.0] <NEXT LINE (NEL)> (Sep) ÷ [0.3] -÷ 0001 × 0308 × 0085 ÷ # ÷ [0.2] <START OF HEADING> (Other) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] <NEXT LINE (NEL)> (Sep) ÷ [0.3] -÷ 0001 × 0009 ÷ # ÷ [0.2] <START OF HEADING> (Other) × [12.0] <CHARACTER TABULATION> (Sp) ÷ [0.3] -÷ 0001 × 0308 × 0009 ÷ # ÷ [0.2] <START OF HEADING> (Other) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] <CHARACTER TABULATION> (Sp) ÷ [0.3] -÷ 0001 × 0061 ÷ # ÷ [0.2] <START OF HEADING> (Other) × [12.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] -÷ 0001 × 0308 × 0061 ÷ # ÷ [0.2] <START OF HEADING> (Other) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] -÷ 0001 × 0041 ÷ # ÷ [0.2] <START OF HEADING> (Other) × [12.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] -÷ 0001 × 0308 × 0041 ÷ # ÷ [0.2] <START OF HEADING> (Other) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] -÷ 0001 × 01BB ÷ # ÷ [0.2] <START OF HEADING> (Other) × [12.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] -÷ 0001 × 0308 × 01BB ÷ # ÷ [0.2] <START OF HEADING> (Other) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] -÷ 0001 × 0030 ÷ # ÷ [0.2] <START OF HEADING> (Other) × [12.0] DIGIT ZERO (Numeric) ÷ [0.3] -÷ 0001 × 0308 × 0030 ÷ # ÷ [0.2] <START OF HEADING> (Other) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] DIGIT ZERO (Numeric) ÷ [0.3] -÷ 0001 × 002E ÷ # ÷ [0.2] <START OF HEADING> (Other) × [12.0] FULL STOP (ATerm) ÷ [0.3] -÷ 0001 × 0308 × 002E ÷ # ÷ [0.2] <START OF HEADING> (Other) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] FULL STOP (ATerm) ÷ [0.3] -÷ 0001 × 0021 ÷ # ÷ [0.2] <START OF HEADING> (Other) × [12.0] EXCLAMATION MARK (STerm) ÷ [0.3] -÷ 0001 × 0308 × 0021 ÷ # ÷ [0.2] <START OF HEADING> (Other) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] EXCLAMATION MARK (STerm) ÷ [0.3] -÷ 0001 × 0022 ÷ # ÷ [0.2] <START OF HEADING> (Other) × [12.0] QUOTATION MARK (Close) ÷ [0.3] -÷ 0001 × 0308 × 0022 ÷ # ÷ [0.2] <START OF HEADING> (Other) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] QUOTATION MARK (Close) ÷ [0.3] -÷ 0001 × 002C ÷ # ÷ [0.2] <START OF HEADING> (Other) × [12.0] COMMA (SContinue) ÷ [0.3] -÷ 0001 × 0308 × 002C ÷ # ÷ [0.2] <START OF HEADING> (Other) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] COMMA (SContinue) ÷ [0.3] +÷ 0001 × 0001 ÷ # ÷ [0.2] <START OF HEADING> (Other) × [998.0] <START OF HEADING> (Other) ÷ [0.3] +÷ 0001 × 0308 × 0001 ÷ # ÷ [0.2] <START OF HEADING> (Other) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] <START OF HEADING> (Other) ÷ [0.3] +÷ 0001 × 000D ÷ # ÷ [0.2] <START OF HEADING> (Other) × [998.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +÷ 0001 × 0308 × 000D ÷ # ÷ [0.2] <START OF HEADING> (Other) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +÷ 0001 × 000A ÷ # ÷ [0.2] <START OF HEADING> (Other) × [998.0] <LINE FEED (LF)> (LF) ÷ [0.3] +÷ 0001 × 0308 × 000A ÷ # ÷ [0.2] <START OF HEADING> (Other) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] <LINE FEED (LF)> (LF) ÷ [0.3] +÷ 0001 × 0085 ÷ # ÷ [0.2] <START OF HEADING> (Other) × [998.0] <NEXT LINE (NEL)> (Sep) ÷ [0.3] +÷ 0001 × 0308 × 0085 ÷ # ÷ [0.2] <START OF HEADING> (Other) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] <NEXT LINE (NEL)> (Sep) ÷ [0.3] +÷ 0001 × 0009 ÷ # ÷ [0.2] <START OF HEADING> (Other) × [998.0] <CHARACTER TABULATION> (Sp) ÷ [0.3] +÷ 0001 × 0308 × 0009 ÷ # ÷ [0.2] <START OF HEADING> (Other) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] <CHARACTER TABULATION> (Sp) ÷ [0.3] +÷ 0001 × 0061 ÷ # ÷ [0.2] <START OF HEADING> (Other) × [998.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] +÷ 0001 × 0308 × 0061 ÷ # ÷ [0.2] <START OF HEADING> (Other) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] +÷ 0001 × 0041 ÷ # ÷ [0.2] <START OF HEADING> (Other) × [998.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] +÷ 0001 × 0308 × 0041 ÷ # ÷ [0.2] <START OF HEADING> (Other) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] +÷ 0001 × 01BB ÷ # ÷ [0.2] <START OF HEADING> (Other) × [998.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] +÷ 0001 × 0308 × 01BB ÷ # ÷ [0.2] <START OF HEADING> (Other) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] +÷ 0001 × 0030 ÷ # ÷ [0.2] <START OF HEADING> (Other) × [998.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0001 × 0308 × 0030 ÷ # ÷ [0.2] <START OF HEADING> (Other) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0001 × 002E ÷ # ÷ [0.2] <START OF HEADING> (Other) × [998.0] FULL STOP (ATerm) ÷ [0.3] +÷ 0001 × 0308 × 002E ÷ # ÷ [0.2] <START OF HEADING> (Other) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] FULL STOP (ATerm) ÷ [0.3] +÷ 0001 × 0021 ÷ # ÷ [0.2] <START OF HEADING> (Other) × [998.0] EXCLAMATION MARK (STerm) ÷ [0.3] +÷ 0001 × 0308 × 0021 ÷ # ÷ [0.2] <START OF HEADING> (Other) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] EXCLAMATION MARK (STerm) ÷ [0.3] +÷ 0001 × 0022 ÷ # ÷ [0.2] <START OF HEADING> (Other) × [998.0] QUOTATION MARK (Close) ÷ [0.3] +÷ 0001 × 0308 × 0022 ÷ # ÷ [0.2] <START OF HEADING> (Other) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] QUOTATION MARK (Close) ÷ [0.3] +÷ 0001 × 002C ÷ # ÷ [0.2] <START OF HEADING> (Other) × [998.0] COMMA (SContinue) ÷ [0.3] +÷ 0001 × 0308 × 002C ÷ # ÷ [0.2] <START OF HEADING> (Other) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] COMMA (SContinue) ÷ [0.3] ÷ 0001 × 00AD ÷ # ÷ [0.2] <START OF HEADING> (Other) × [5.0] SOFT HYPHEN (Format_FE) ÷ [0.3] ÷ 0001 × 0308 × 00AD ÷ # ÷ [0.2] <START OF HEADING> (Other) × [5.0] COMBINING DIAERESIS (Extend_FE) × [5.0] SOFT HYPHEN (Format_FE) ÷ [0.3] ÷ 0001 × 0300 ÷ # ÷ [0.2] <START OF HEADING> (Other) × [5.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] ÷ 0001 × 0308 × 0300 ÷ # ÷ [0.2] <START OF HEADING> (Other) × [5.0] COMBINING DIAERESIS (Extend_FE) × [5.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] ÷ 000D ÷ 0001 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] <START OF HEADING> (Other) ÷ [0.3] -÷ 000D ÷ 0308 × 0001 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [12.0] <START OF HEADING> (Other) ÷ [0.3] +÷ 000D ÷ 0308 × 0001 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] <START OF HEADING> (Other) ÷ [0.3] ÷ 000D ÷ 000D ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -÷ 000D ÷ 0308 × 000D ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [12.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +÷ 000D ÷ 0308 × 000D ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] ÷ 000D × 000A ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) × [3.0] <LINE FEED (LF)> (LF) ÷ [0.3] -÷ 000D ÷ 0308 × 000A ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [12.0] <LINE FEED (LF)> (LF) ÷ [0.3] +÷ 000D ÷ 0308 × 000A ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] <LINE FEED (LF)> (LF) ÷ [0.3] ÷ 000D ÷ 0085 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] <NEXT LINE (NEL)> (Sep) ÷ [0.3] -÷ 000D ÷ 0308 × 0085 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [12.0] <NEXT LINE (NEL)> (Sep) ÷ [0.3] +÷ 000D ÷ 0308 × 0085 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] <NEXT LINE (NEL)> (Sep) ÷ [0.3] ÷ 000D ÷ 0009 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] <CHARACTER TABULATION> (Sp) ÷ [0.3] -÷ 000D ÷ 0308 × 0009 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [12.0] <CHARACTER TABULATION> (Sp) ÷ [0.3] +÷ 000D ÷ 0308 × 0009 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] <CHARACTER TABULATION> (Sp) ÷ [0.3] ÷ 000D ÷ 0061 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] -÷ 000D ÷ 0308 × 0061 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [12.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] +÷ 000D ÷ 0308 × 0061 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] ÷ 000D ÷ 0041 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] -÷ 000D ÷ 0308 × 0041 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [12.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] +÷ 000D ÷ 0308 × 0041 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] ÷ 000D ÷ 01BB ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] -÷ 000D ÷ 0308 × 01BB ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [12.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] +÷ 000D ÷ 0308 × 01BB ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] ÷ 000D ÷ 0030 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] DIGIT ZERO (Numeric) ÷ [0.3] -÷ 000D ÷ 0308 × 0030 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [12.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 000D ÷ 0308 × 0030 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] DIGIT ZERO (Numeric) ÷ [0.3] ÷ 000D ÷ 002E ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] FULL STOP (ATerm) ÷ [0.3] -÷ 000D ÷ 0308 × 002E ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [12.0] FULL STOP (ATerm) ÷ [0.3] +÷ 000D ÷ 0308 × 002E ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] FULL STOP (ATerm) ÷ [0.3] ÷ 000D ÷ 0021 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] EXCLAMATION MARK (STerm) ÷ [0.3] -÷ 000D ÷ 0308 × 0021 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [12.0] EXCLAMATION MARK (STerm) ÷ [0.3] +÷ 000D ÷ 0308 × 0021 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] EXCLAMATION MARK (STerm) ÷ [0.3] ÷ 000D ÷ 0022 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] QUOTATION MARK (Close) ÷ [0.3] -÷ 000D ÷ 0308 × 0022 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [12.0] QUOTATION MARK (Close) ÷ [0.3] +÷ 000D ÷ 0308 × 0022 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] QUOTATION MARK (Close) ÷ [0.3] ÷ 000D ÷ 002C ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMMA (SContinue) ÷ [0.3] -÷ 000D ÷ 0308 × 002C ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [12.0] COMMA (SContinue) ÷ [0.3] +÷ 000D ÷ 0308 × 002C ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] COMMA (SContinue) ÷ [0.3] ÷ 000D ÷ 00AD ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] ÷ 000D ÷ 0308 × 00AD ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [5.0] SOFT HYPHEN (Format_FE) ÷ [0.3] ÷ 000D ÷ 0300 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] ÷ 000D ÷ 0308 × 0300 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [5.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] ÷ 000A ÷ 0001 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] <START OF HEADING> (Other) ÷ [0.3] -÷ 000A ÷ 0308 × 0001 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [12.0] <START OF HEADING> (Other) ÷ [0.3] +÷ 000A ÷ 0308 × 0001 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] <START OF HEADING> (Other) ÷ [0.3] ÷ 000A ÷ 000D ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -÷ 000A ÷ 0308 × 000D ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [12.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +÷ 000A ÷ 0308 × 000D ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] ÷ 000A ÷ 000A ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] <LINE FEED (LF)> (LF) ÷ [0.3] -÷ 000A ÷ 0308 × 000A ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [12.0] <LINE FEED (LF)> (LF) ÷ [0.3] +÷ 000A ÷ 0308 × 000A ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] <LINE FEED (LF)> (LF) ÷ [0.3] ÷ 000A ÷ 0085 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] <NEXT LINE (NEL)> (Sep) ÷ [0.3] -÷ 000A ÷ 0308 × 0085 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [12.0] <NEXT LINE (NEL)> (Sep) ÷ [0.3] +÷ 000A ÷ 0308 × 0085 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] <NEXT LINE (NEL)> (Sep) ÷ [0.3] ÷ 000A ÷ 0009 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] <CHARACTER TABULATION> (Sp) ÷ [0.3] -÷ 000A ÷ 0308 × 0009 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [12.0] <CHARACTER TABULATION> (Sp) ÷ [0.3] +÷ 000A ÷ 0308 × 0009 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] <CHARACTER TABULATION> (Sp) ÷ [0.3] ÷ 000A ÷ 0061 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] -÷ 000A ÷ 0308 × 0061 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [12.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] +÷ 000A ÷ 0308 × 0061 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] ÷ 000A ÷ 0041 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] -÷ 000A ÷ 0308 × 0041 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [12.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] +÷ 000A ÷ 0308 × 0041 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] ÷ 000A ÷ 01BB ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] -÷ 000A ÷ 0308 × 01BB ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [12.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] +÷ 000A ÷ 0308 × 01BB ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] ÷ 000A ÷ 0030 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] DIGIT ZERO (Numeric) ÷ [0.3] -÷ 000A ÷ 0308 × 0030 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [12.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 000A ÷ 0308 × 0030 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] DIGIT ZERO (Numeric) ÷ [0.3] ÷ 000A ÷ 002E ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] FULL STOP (ATerm) ÷ [0.3] -÷ 000A ÷ 0308 × 002E ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [12.0] FULL STOP (ATerm) ÷ [0.3] +÷ 000A ÷ 0308 × 002E ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] FULL STOP (ATerm) ÷ [0.3] ÷ 000A ÷ 0021 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] EXCLAMATION MARK (STerm) ÷ [0.3] -÷ 000A ÷ 0308 × 0021 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [12.0] EXCLAMATION MARK (STerm) ÷ [0.3] +÷ 000A ÷ 0308 × 0021 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] EXCLAMATION MARK (STerm) ÷ [0.3] ÷ 000A ÷ 0022 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] QUOTATION MARK (Close) ÷ [0.3] -÷ 000A ÷ 0308 × 0022 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [12.0] QUOTATION MARK (Close) ÷ [0.3] +÷ 000A ÷ 0308 × 0022 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] QUOTATION MARK (Close) ÷ [0.3] ÷ 000A ÷ 002C ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMMA (SContinue) ÷ [0.3] -÷ 000A ÷ 0308 × 002C ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [12.0] COMMA (SContinue) ÷ [0.3] +÷ 000A ÷ 0308 × 002C ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] COMMA (SContinue) ÷ [0.3] ÷ 000A ÷ 00AD ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] ÷ 000A ÷ 0308 × 00AD ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [5.0] SOFT HYPHEN (Format_FE) ÷ [0.3] ÷ 000A ÷ 0300 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] ÷ 000A ÷ 0308 × 0300 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [5.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] ÷ 0085 ÷ 0001 ÷ # ÷ [0.2] <NEXT LINE (NEL)> (Sep) ÷ [4.0] <START OF HEADING> (Other) ÷ [0.3] -÷ 0085 ÷ 0308 × 0001 ÷ # ÷ [0.2] <NEXT LINE (NEL)> (Sep) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [12.0] <START OF HEADING> (Other) ÷ [0.3] +÷ 0085 ÷ 0308 × 0001 ÷ # ÷ [0.2] <NEXT LINE (NEL)> (Sep) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] <START OF HEADING> (Other) ÷ [0.3] ÷ 0085 ÷ 000D ÷ # ÷ [0.2] <NEXT LINE (NEL)> (Sep) ÷ [4.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -÷ 0085 ÷ 0308 × 000D ÷ # ÷ [0.2] <NEXT LINE (NEL)> (Sep) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [12.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +÷ 0085 ÷ 0308 × 000D ÷ # ÷ [0.2] <NEXT LINE (NEL)> (Sep) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] ÷ 0085 ÷ 000A ÷ # ÷ [0.2] <NEXT LINE (NEL)> (Sep) ÷ [4.0] <LINE FEED (LF)> (LF) ÷ [0.3] -÷ 0085 ÷ 0308 × 000A ÷ # ÷ [0.2] <NEXT LINE (NEL)> (Sep) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [12.0] <LINE FEED (LF)> (LF) ÷ [0.3] +÷ 0085 ÷ 0308 × 000A ÷ # ÷ [0.2] <NEXT LINE (NEL)> (Sep) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] <LINE FEED (LF)> (LF) ÷ [0.3] ÷ 0085 ÷ 0085 ÷ # ÷ [0.2] <NEXT LINE (NEL)> (Sep) ÷ [4.0] <NEXT LINE (NEL)> (Sep) ÷ [0.3] -÷ 0085 ÷ 0308 × 0085 ÷ # ÷ [0.2] <NEXT LINE (NEL)> (Sep) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [12.0] <NEXT LINE (NEL)> (Sep) ÷ [0.3] +÷ 0085 ÷ 0308 × 0085 ÷ # ÷ [0.2] <NEXT LINE (NEL)> (Sep) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] <NEXT LINE (NEL)> (Sep) ÷ [0.3] ÷ 0085 ÷ 0009 ÷ # ÷ [0.2] <NEXT LINE (NEL)> (Sep) ÷ [4.0] <CHARACTER TABULATION> (Sp) ÷ [0.3] -÷ 0085 ÷ 0308 × 0009 ÷ # ÷ [0.2] <NEXT LINE (NEL)> (Sep) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [12.0] <CHARACTER TABULATION> (Sp) ÷ [0.3] +÷ 0085 ÷ 0308 × 0009 ÷ # ÷ [0.2] <NEXT LINE (NEL)> (Sep) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] <CHARACTER TABULATION> (Sp) ÷ [0.3] ÷ 0085 ÷ 0061 ÷ # ÷ [0.2] <NEXT LINE (NEL)> (Sep) ÷ [4.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] -÷ 0085 ÷ 0308 × 0061 ÷ # ÷ [0.2] <NEXT LINE (NEL)> (Sep) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [12.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] +÷ 0085 ÷ 0308 × 0061 ÷ # ÷ [0.2] <NEXT LINE (NEL)> (Sep) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] ÷ 0085 ÷ 0041 ÷ # ÷ [0.2] <NEXT LINE (NEL)> (Sep) ÷ [4.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] -÷ 0085 ÷ 0308 × 0041 ÷ # ÷ [0.2] <NEXT LINE (NEL)> (Sep) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [12.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] +÷ 0085 ÷ 0308 × 0041 ÷ # ÷ [0.2] <NEXT LINE (NEL)> (Sep) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] ÷ 0085 ÷ 01BB ÷ # ÷ [0.2] <NEXT LINE (NEL)> (Sep) ÷ [4.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] -÷ 0085 ÷ 0308 × 01BB ÷ # ÷ [0.2] <NEXT LINE (NEL)> (Sep) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [12.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] +÷ 0085 ÷ 0308 × 01BB ÷ # ÷ [0.2] <NEXT LINE (NEL)> (Sep) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] ÷ 0085 ÷ 0030 ÷ # ÷ [0.2] <NEXT LINE (NEL)> (Sep) ÷ [4.0] DIGIT ZERO (Numeric) ÷ [0.3] -÷ 0085 ÷ 0308 × 0030 ÷ # ÷ [0.2] <NEXT LINE (NEL)> (Sep) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [12.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0085 ÷ 0308 × 0030 ÷ # ÷ [0.2] <NEXT LINE (NEL)> (Sep) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] DIGIT ZERO (Numeric) ÷ [0.3] ÷ 0085 ÷ 002E ÷ # ÷ [0.2] <NEXT LINE (NEL)> (Sep) ÷ [4.0] FULL STOP (ATerm) ÷ [0.3] -÷ 0085 ÷ 0308 × 002E ÷ # ÷ [0.2] <NEXT LINE (NEL)> (Sep) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [12.0] FULL STOP (ATerm) ÷ [0.3] +÷ 0085 ÷ 0308 × 002E ÷ # ÷ [0.2] <NEXT LINE (NEL)> (Sep) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] FULL STOP (ATerm) ÷ [0.3] ÷ 0085 ÷ 0021 ÷ # ÷ [0.2] <NEXT LINE (NEL)> (Sep) ÷ [4.0] EXCLAMATION MARK (STerm) ÷ [0.3] -÷ 0085 ÷ 0308 × 0021 ÷ # ÷ [0.2] <NEXT LINE (NEL)> (Sep) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [12.0] EXCLAMATION MARK (STerm) ÷ [0.3] +÷ 0085 ÷ 0308 × 0021 ÷ # ÷ [0.2] <NEXT LINE (NEL)> (Sep) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] EXCLAMATION MARK (STerm) ÷ [0.3] ÷ 0085 ÷ 0022 ÷ # ÷ [0.2] <NEXT LINE (NEL)> (Sep) ÷ [4.0] QUOTATION MARK (Close) ÷ [0.3] -÷ 0085 ÷ 0308 × 0022 ÷ # ÷ [0.2] <NEXT LINE (NEL)> (Sep) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [12.0] QUOTATION MARK (Close) ÷ [0.3] +÷ 0085 ÷ 0308 × 0022 ÷ # ÷ [0.2] <NEXT LINE (NEL)> (Sep) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] QUOTATION MARK (Close) ÷ [0.3] ÷ 0085 ÷ 002C ÷ # ÷ [0.2] <NEXT LINE (NEL)> (Sep) ÷ [4.0] COMMA (SContinue) ÷ [0.3] -÷ 0085 ÷ 0308 × 002C ÷ # ÷ [0.2] <NEXT LINE (NEL)> (Sep) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [12.0] COMMA (SContinue) ÷ [0.3] +÷ 0085 ÷ 0308 × 002C ÷ # ÷ [0.2] <NEXT LINE (NEL)> (Sep) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] COMMA (SContinue) ÷ [0.3] ÷ 0085 ÷ 00AD ÷ # ÷ [0.2] <NEXT LINE (NEL)> (Sep) ÷ [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] ÷ 0085 ÷ 0308 × 00AD ÷ # ÷ [0.2] <NEXT LINE (NEL)> (Sep) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [5.0] SOFT HYPHEN (Format_FE) ÷ [0.3] ÷ 0085 ÷ 0300 ÷ # ÷ [0.2] <NEXT LINE (NEL)> (Sep) ÷ [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] ÷ 0085 ÷ 0308 × 0300 ÷ # ÷ [0.2] <NEXT LINE (NEL)> (Sep) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [5.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] -÷ 0009 × 0001 ÷ # ÷ [0.2] <CHARACTER TABULATION> (Sp) × [12.0] <START OF HEADING> (Other) ÷ [0.3] -÷ 0009 × 0308 × 0001 ÷ # ÷ [0.2] <CHARACTER TABULATION> (Sp) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] <START OF HEADING> (Other) ÷ [0.3] -÷ 0009 × 000D ÷ # ÷ [0.2] <CHARACTER TABULATION> (Sp) × [12.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -÷ 0009 × 0308 × 000D ÷ # ÷ [0.2] <CHARACTER TABULATION> (Sp) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -÷ 0009 × 000A ÷ # ÷ [0.2] <CHARACTER TABULATION> (Sp) × [12.0] <LINE FEED (LF)> (LF) ÷ [0.3] -÷ 0009 × 0308 × 000A ÷ # ÷ [0.2] <CHARACTER TABULATION> (Sp) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] <LINE FEED (LF)> (LF) ÷ [0.3] -÷ 0009 × 0085 ÷ # ÷ [0.2] <CHARACTER TABULATION> (Sp) × [12.0] <NEXT LINE (NEL)> (Sep) ÷ [0.3] -÷ 0009 × 0308 × 0085 ÷ # ÷ [0.2] <CHARACTER TABULATION> (Sp) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] <NEXT LINE (NEL)> (Sep) ÷ [0.3] -÷ 0009 × 0009 ÷ # ÷ [0.2] <CHARACTER TABULATION> (Sp) × [12.0] <CHARACTER TABULATION> (Sp) ÷ [0.3] -÷ 0009 × 0308 × 0009 ÷ # ÷ [0.2] <CHARACTER TABULATION> (Sp) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] <CHARACTER TABULATION> (Sp) ÷ [0.3] -÷ 0009 × 0061 ÷ # ÷ [0.2] <CHARACTER TABULATION> (Sp) × [12.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] -÷ 0009 × 0308 × 0061 ÷ # ÷ [0.2] <CHARACTER TABULATION> (Sp) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] -÷ 0009 × 0041 ÷ # ÷ [0.2] <CHARACTER TABULATION> (Sp) × [12.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] -÷ 0009 × 0308 × 0041 ÷ # ÷ [0.2] <CHARACTER TABULATION> (Sp) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] -÷ 0009 × 01BB ÷ # ÷ [0.2] <CHARACTER TABULATION> (Sp) × [12.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] -÷ 0009 × 0308 × 01BB ÷ # ÷ [0.2] <CHARACTER TABULATION> (Sp) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] -÷ 0009 × 0030 ÷ # ÷ [0.2] <CHARACTER TABULATION> (Sp) × [12.0] DIGIT ZERO (Numeric) ÷ [0.3] -÷ 0009 × 0308 × 0030 ÷ # ÷ [0.2] <CHARACTER TABULATION> (Sp) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] DIGIT ZERO (Numeric) ÷ [0.3] -÷ 0009 × 002E ÷ # ÷ [0.2] <CHARACTER TABULATION> (Sp) × [12.0] FULL STOP (ATerm) ÷ [0.3] -÷ 0009 × 0308 × 002E ÷ # ÷ [0.2] <CHARACTER TABULATION> (Sp) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] FULL STOP (ATerm) ÷ [0.3] -÷ 0009 × 0021 ÷ # ÷ [0.2] <CHARACTER TABULATION> (Sp) × [12.0] EXCLAMATION MARK (STerm) ÷ [0.3] -÷ 0009 × 0308 × 0021 ÷ # ÷ [0.2] <CHARACTER TABULATION> (Sp) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] EXCLAMATION MARK (STerm) ÷ [0.3] -÷ 0009 × 0022 ÷ # ÷ [0.2] <CHARACTER TABULATION> (Sp) × [12.0] QUOTATION MARK (Close) ÷ [0.3] -÷ 0009 × 0308 × 0022 ÷ # ÷ [0.2] <CHARACTER TABULATION> (Sp) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] QUOTATION MARK (Close) ÷ [0.3] -÷ 0009 × 002C ÷ # ÷ [0.2] <CHARACTER TABULATION> (Sp) × [12.0] COMMA (SContinue) ÷ [0.3] -÷ 0009 × 0308 × 002C ÷ # ÷ [0.2] <CHARACTER TABULATION> (Sp) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] COMMA (SContinue) ÷ [0.3] +÷ 0009 × 0001 ÷ # ÷ [0.2] <CHARACTER TABULATION> (Sp) × [998.0] <START OF HEADING> (Other) ÷ [0.3] +÷ 0009 × 0308 × 0001 ÷ # ÷ [0.2] <CHARACTER TABULATION> (Sp) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] <START OF HEADING> (Other) ÷ [0.3] +÷ 0009 × 000D ÷ # ÷ [0.2] <CHARACTER TABULATION> (Sp) × [998.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +÷ 0009 × 0308 × 000D ÷ # ÷ [0.2] <CHARACTER TABULATION> (Sp) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +÷ 0009 × 000A ÷ # ÷ [0.2] <CHARACTER TABULATION> (Sp) × [998.0] <LINE FEED (LF)> (LF) ÷ [0.3] +÷ 0009 × 0308 × 000A ÷ # ÷ [0.2] <CHARACTER TABULATION> (Sp) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] <LINE FEED (LF)> (LF) ÷ [0.3] +÷ 0009 × 0085 ÷ # ÷ [0.2] <CHARACTER TABULATION> (Sp) × [998.0] <NEXT LINE (NEL)> (Sep) ÷ [0.3] +÷ 0009 × 0308 × 0085 ÷ # ÷ [0.2] <CHARACTER TABULATION> (Sp) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] <NEXT LINE (NEL)> (Sep) ÷ [0.3] +÷ 0009 × 0009 ÷ # ÷ [0.2] <CHARACTER TABULATION> (Sp) × [998.0] <CHARACTER TABULATION> (Sp) ÷ [0.3] +÷ 0009 × 0308 × 0009 ÷ # ÷ [0.2] <CHARACTER TABULATION> (Sp) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] <CHARACTER TABULATION> (Sp) ÷ [0.3] +÷ 0009 × 0061 ÷ # ÷ [0.2] <CHARACTER TABULATION> (Sp) × [998.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] +÷ 0009 × 0308 × 0061 ÷ # ÷ [0.2] <CHARACTER TABULATION> (Sp) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] +÷ 0009 × 0041 ÷ # ÷ [0.2] <CHARACTER TABULATION> (Sp) × [998.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] +÷ 0009 × 0308 × 0041 ÷ # ÷ [0.2] <CHARACTER TABULATION> (Sp) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] +÷ 0009 × 01BB ÷ # ÷ [0.2] <CHARACTER TABULATION> (Sp) × [998.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] +÷ 0009 × 0308 × 01BB ÷ # ÷ [0.2] <CHARACTER TABULATION> (Sp) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] +÷ 0009 × 0030 ÷ # ÷ [0.2] <CHARACTER TABULATION> (Sp) × [998.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0009 × 0308 × 0030 ÷ # ÷ [0.2] <CHARACTER TABULATION> (Sp) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0009 × 002E ÷ # ÷ [0.2] <CHARACTER TABULATION> (Sp) × [998.0] FULL STOP (ATerm) ÷ [0.3] +÷ 0009 × 0308 × 002E ÷ # ÷ [0.2] <CHARACTER TABULATION> (Sp) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] FULL STOP (ATerm) ÷ [0.3] +÷ 0009 × 0021 ÷ # ÷ [0.2] <CHARACTER TABULATION> (Sp) × [998.0] EXCLAMATION MARK (STerm) ÷ [0.3] +÷ 0009 × 0308 × 0021 ÷ # ÷ [0.2] <CHARACTER TABULATION> (Sp) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] EXCLAMATION MARK (STerm) ÷ [0.3] +÷ 0009 × 0022 ÷ # ÷ [0.2] <CHARACTER TABULATION> (Sp) × [998.0] QUOTATION MARK (Close) ÷ [0.3] +÷ 0009 × 0308 × 0022 ÷ # ÷ [0.2] <CHARACTER TABULATION> (Sp) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] QUOTATION MARK (Close) ÷ [0.3] +÷ 0009 × 002C ÷ # ÷ [0.2] <CHARACTER TABULATION> (Sp) × [998.0] COMMA (SContinue) ÷ [0.3] +÷ 0009 × 0308 × 002C ÷ # ÷ [0.2] <CHARACTER TABULATION> (Sp) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] COMMA (SContinue) ÷ [0.3] ÷ 0009 × 00AD ÷ # ÷ [0.2] <CHARACTER TABULATION> (Sp) × [5.0] SOFT HYPHEN (Format_FE) ÷ [0.3] ÷ 0009 × 0308 × 00AD ÷ # ÷ [0.2] <CHARACTER TABULATION> (Sp) × [5.0] COMBINING DIAERESIS (Extend_FE) × [5.0] SOFT HYPHEN (Format_FE) ÷ [0.3] ÷ 0009 × 0300 ÷ # ÷ [0.2] <CHARACTER TABULATION> (Sp) × [5.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] ÷ 0009 × 0308 × 0300 ÷ # ÷ [0.2] <CHARACTER TABULATION> (Sp) × [5.0] COMBINING DIAERESIS (Extend_FE) × [5.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] -÷ 0061 × 0001 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [12.0] <START OF HEADING> (Other) ÷ [0.3] -÷ 0061 × 0308 × 0001 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] <START OF HEADING> (Other) ÷ [0.3] -÷ 0061 × 000D ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [12.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -÷ 0061 × 0308 × 000D ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -÷ 0061 × 000A ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [12.0] <LINE FEED (LF)> (LF) ÷ [0.3] -÷ 0061 × 0308 × 000A ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] <LINE FEED (LF)> (LF) ÷ [0.3] -÷ 0061 × 0085 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [12.0] <NEXT LINE (NEL)> (Sep) ÷ [0.3] -÷ 0061 × 0308 × 0085 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] <NEXT LINE (NEL)> (Sep) ÷ [0.3] -÷ 0061 × 0009 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [12.0] <CHARACTER TABULATION> (Sp) ÷ [0.3] -÷ 0061 × 0308 × 0009 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] <CHARACTER TABULATION> (Sp) ÷ [0.3] -÷ 0061 × 0061 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [12.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] -÷ 0061 × 0308 × 0061 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] -÷ 0061 × 0041 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [12.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] -÷ 0061 × 0308 × 0041 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] -÷ 0061 × 01BB ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [12.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] -÷ 0061 × 0308 × 01BB ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] -÷ 0061 × 0030 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [12.0] DIGIT ZERO (Numeric) ÷ [0.3] -÷ 0061 × 0308 × 0030 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] DIGIT ZERO (Numeric) ÷ [0.3] -÷ 0061 × 002E ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [12.0] FULL STOP (ATerm) ÷ [0.3] -÷ 0061 × 0308 × 002E ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] FULL STOP (ATerm) ÷ [0.3] -÷ 0061 × 0021 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [12.0] EXCLAMATION MARK (STerm) ÷ [0.3] -÷ 0061 × 0308 × 0021 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] EXCLAMATION MARK (STerm) ÷ [0.3] -÷ 0061 × 0022 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [12.0] QUOTATION MARK (Close) ÷ [0.3] -÷ 0061 × 0308 × 0022 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] QUOTATION MARK (Close) ÷ [0.3] -÷ 0061 × 002C ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [12.0] COMMA (SContinue) ÷ [0.3] -÷ 0061 × 0308 × 002C ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] COMMA (SContinue) ÷ [0.3] +÷ 0061 × 0001 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [998.0] <START OF HEADING> (Other) ÷ [0.3] +÷ 0061 × 0308 × 0001 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] <START OF HEADING> (Other) ÷ [0.3] +÷ 0061 × 000D ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [998.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +÷ 0061 × 0308 × 000D ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +÷ 0061 × 000A ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [998.0] <LINE FEED (LF)> (LF) ÷ [0.3] +÷ 0061 × 0308 × 000A ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] <LINE FEED (LF)> (LF) ÷ [0.3] +÷ 0061 × 0085 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [998.0] <NEXT LINE (NEL)> (Sep) ÷ [0.3] +÷ 0061 × 0308 × 0085 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] <NEXT LINE (NEL)> (Sep) ÷ [0.3] +÷ 0061 × 0009 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [998.0] <CHARACTER TABULATION> (Sp) ÷ [0.3] +÷ 0061 × 0308 × 0009 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] <CHARACTER TABULATION> (Sp) ÷ [0.3] +÷ 0061 × 0061 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [998.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] +÷ 0061 × 0308 × 0061 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] +÷ 0061 × 0041 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [998.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] +÷ 0061 × 0308 × 0041 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] +÷ 0061 × 01BB ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [998.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] +÷ 0061 × 0308 × 01BB ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] +÷ 0061 × 0030 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [998.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0061 × 0308 × 0030 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0061 × 002E ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [998.0] FULL STOP (ATerm) ÷ [0.3] +÷ 0061 × 0308 × 002E ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] FULL STOP (ATerm) ÷ [0.3] +÷ 0061 × 0021 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [998.0] EXCLAMATION MARK (STerm) ÷ [0.3] +÷ 0061 × 0308 × 0021 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] EXCLAMATION MARK (STerm) ÷ [0.3] +÷ 0061 × 0022 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [998.0] QUOTATION MARK (Close) ÷ [0.3] +÷ 0061 × 0308 × 0022 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] QUOTATION MARK (Close) ÷ [0.3] +÷ 0061 × 002C ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [998.0] COMMA (SContinue) ÷ [0.3] +÷ 0061 × 0308 × 002C ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] COMMA (SContinue) ÷ [0.3] ÷ 0061 × 00AD ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [5.0] SOFT HYPHEN (Format_FE) ÷ [0.3] ÷ 0061 × 0308 × 00AD ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [5.0] COMBINING DIAERESIS (Extend_FE) × [5.0] SOFT HYPHEN (Format_FE) ÷ [0.3] ÷ 0061 × 0300 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [5.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] ÷ 0061 × 0308 × 0300 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [5.0] COMBINING DIAERESIS (Extend_FE) × [5.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] -÷ 0041 × 0001 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [12.0] <START OF HEADING> (Other) ÷ [0.3] -÷ 0041 × 0308 × 0001 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] <START OF HEADING> (Other) ÷ [0.3] -÷ 0041 × 000D ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [12.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -÷ 0041 × 0308 × 000D ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -÷ 0041 × 000A ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [12.0] <LINE FEED (LF)> (LF) ÷ [0.3] -÷ 0041 × 0308 × 000A ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] <LINE FEED (LF)> (LF) ÷ [0.3] -÷ 0041 × 0085 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [12.0] <NEXT LINE (NEL)> (Sep) ÷ [0.3] -÷ 0041 × 0308 × 0085 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] <NEXT LINE (NEL)> (Sep) ÷ [0.3] -÷ 0041 × 0009 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [12.0] <CHARACTER TABULATION> (Sp) ÷ [0.3] -÷ 0041 × 0308 × 0009 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] <CHARACTER TABULATION> (Sp) ÷ [0.3] -÷ 0041 × 0061 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [12.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] -÷ 0041 × 0308 × 0061 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] -÷ 0041 × 0041 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [12.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] -÷ 0041 × 0308 × 0041 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] -÷ 0041 × 01BB ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [12.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] -÷ 0041 × 0308 × 01BB ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] -÷ 0041 × 0030 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [12.0] DIGIT ZERO (Numeric) ÷ [0.3] -÷ 0041 × 0308 × 0030 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] DIGIT ZERO (Numeric) ÷ [0.3] -÷ 0041 × 002E ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [12.0] FULL STOP (ATerm) ÷ [0.3] -÷ 0041 × 0308 × 002E ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] FULL STOP (ATerm) ÷ [0.3] -÷ 0041 × 0021 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [12.0] EXCLAMATION MARK (STerm) ÷ [0.3] -÷ 0041 × 0308 × 0021 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] EXCLAMATION MARK (STerm) ÷ [0.3] -÷ 0041 × 0022 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [12.0] QUOTATION MARK (Close) ÷ [0.3] -÷ 0041 × 0308 × 0022 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] QUOTATION MARK (Close) ÷ [0.3] -÷ 0041 × 002C ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [12.0] COMMA (SContinue) ÷ [0.3] -÷ 0041 × 0308 × 002C ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] COMMA (SContinue) ÷ [0.3] +÷ 0041 × 0001 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [998.0] <START OF HEADING> (Other) ÷ [0.3] +÷ 0041 × 0308 × 0001 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] <START OF HEADING> (Other) ÷ [0.3] +÷ 0041 × 000D ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [998.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +÷ 0041 × 0308 × 000D ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +÷ 0041 × 000A ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [998.0] <LINE FEED (LF)> (LF) ÷ [0.3] +÷ 0041 × 0308 × 000A ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] <LINE FEED (LF)> (LF) ÷ [0.3] +÷ 0041 × 0085 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [998.0] <NEXT LINE (NEL)> (Sep) ÷ [0.3] +÷ 0041 × 0308 × 0085 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] <NEXT LINE (NEL)> (Sep) ÷ [0.3] +÷ 0041 × 0009 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [998.0] <CHARACTER TABULATION> (Sp) ÷ [0.3] +÷ 0041 × 0308 × 0009 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] <CHARACTER TABULATION> (Sp) ÷ [0.3] +÷ 0041 × 0061 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [998.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] +÷ 0041 × 0308 × 0061 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] +÷ 0041 × 0041 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [998.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] +÷ 0041 × 0308 × 0041 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] +÷ 0041 × 01BB ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [998.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] +÷ 0041 × 0308 × 01BB ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] +÷ 0041 × 0030 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [998.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0041 × 0308 × 0030 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0041 × 002E ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [998.0] FULL STOP (ATerm) ÷ [0.3] +÷ 0041 × 0308 × 002E ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] FULL STOP (ATerm) ÷ [0.3] +÷ 0041 × 0021 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [998.0] EXCLAMATION MARK (STerm) ÷ [0.3] +÷ 0041 × 0308 × 0021 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] EXCLAMATION MARK (STerm) ÷ [0.3] +÷ 0041 × 0022 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [998.0] QUOTATION MARK (Close) ÷ [0.3] +÷ 0041 × 0308 × 0022 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] QUOTATION MARK (Close) ÷ [0.3] +÷ 0041 × 002C ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [998.0] COMMA (SContinue) ÷ [0.3] +÷ 0041 × 0308 × 002C ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] COMMA (SContinue) ÷ [0.3] ÷ 0041 × 00AD ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [5.0] SOFT HYPHEN (Format_FE) ÷ [0.3] ÷ 0041 × 0308 × 00AD ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [5.0] COMBINING DIAERESIS (Extend_FE) × [5.0] SOFT HYPHEN (Format_FE) ÷ [0.3] ÷ 0041 × 0300 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [5.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] ÷ 0041 × 0308 × 0300 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (Upper) × [5.0] COMBINING DIAERESIS (Extend_FE) × [5.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] -÷ 01BB × 0001 ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [12.0] <START OF HEADING> (Other) ÷ [0.3] -÷ 01BB × 0308 × 0001 ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] <START OF HEADING> (Other) ÷ [0.3] -÷ 01BB × 000D ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [12.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -÷ 01BB × 0308 × 000D ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -÷ 01BB × 000A ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [12.0] <LINE FEED (LF)> (LF) ÷ [0.3] -÷ 01BB × 0308 × 000A ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] <LINE FEED (LF)> (LF) ÷ [0.3] -÷ 01BB × 0085 ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [12.0] <NEXT LINE (NEL)> (Sep) ÷ [0.3] -÷ 01BB × 0308 × 0085 ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] <NEXT LINE (NEL)> (Sep) ÷ [0.3] -÷ 01BB × 0009 ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [12.0] <CHARACTER TABULATION> (Sp) ÷ [0.3] -÷ 01BB × 0308 × 0009 ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] <CHARACTER TABULATION> (Sp) ÷ [0.3] -÷ 01BB × 0061 ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [12.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] -÷ 01BB × 0308 × 0061 ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] -÷ 01BB × 0041 ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [12.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] -÷ 01BB × 0308 × 0041 ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] -÷ 01BB × 01BB ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [12.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] -÷ 01BB × 0308 × 01BB ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] -÷ 01BB × 0030 ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [12.0] DIGIT ZERO (Numeric) ÷ [0.3] -÷ 01BB × 0308 × 0030 ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] DIGIT ZERO (Numeric) ÷ [0.3] -÷ 01BB × 002E ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [12.0] FULL STOP (ATerm) ÷ [0.3] -÷ 01BB × 0308 × 002E ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] FULL STOP (ATerm) ÷ [0.3] -÷ 01BB × 0021 ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [12.0] EXCLAMATION MARK (STerm) ÷ [0.3] -÷ 01BB × 0308 × 0021 ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] EXCLAMATION MARK (STerm) ÷ [0.3] -÷ 01BB × 0022 ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [12.0] QUOTATION MARK (Close) ÷ [0.3] -÷ 01BB × 0308 × 0022 ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] QUOTATION MARK (Close) ÷ [0.3] -÷ 01BB × 002C ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [12.0] COMMA (SContinue) ÷ [0.3] -÷ 01BB × 0308 × 002C ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] COMMA (SContinue) ÷ [0.3] +÷ 01BB × 0001 ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [998.0] <START OF HEADING> (Other) ÷ [0.3] +÷ 01BB × 0308 × 0001 ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] <START OF HEADING> (Other) ÷ [0.3] +÷ 01BB × 000D ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [998.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +÷ 01BB × 0308 × 000D ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +÷ 01BB × 000A ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [998.0] <LINE FEED (LF)> (LF) ÷ [0.3] +÷ 01BB × 0308 × 000A ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] <LINE FEED (LF)> (LF) ÷ [0.3] +÷ 01BB × 0085 ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [998.0] <NEXT LINE (NEL)> (Sep) ÷ [0.3] +÷ 01BB × 0308 × 0085 ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] <NEXT LINE (NEL)> (Sep) ÷ [0.3] +÷ 01BB × 0009 ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [998.0] <CHARACTER TABULATION> (Sp) ÷ [0.3] +÷ 01BB × 0308 × 0009 ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] <CHARACTER TABULATION> (Sp) ÷ [0.3] +÷ 01BB × 0061 ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [998.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] +÷ 01BB × 0308 × 0061 ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] +÷ 01BB × 0041 ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [998.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] +÷ 01BB × 0308 × 0041 ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] +÷ 01BB × 01BB ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [998.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] +÷ 01BB × 0308 × 01BB ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] +÷ 01BB × 0030 ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [998.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 01BB × 0308 × 0030 ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 01BB × 002E ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [998.0] FULL STOP (ATerm) ÷ [0.3] +÷ 01BB × 0308 × 002E ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] FULL STOP (ATerm) ÷ [0.3] +÷ 01BB × 0021 ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [998.0] EXCLAMATION MARK (STerm) ÷ [0.3] +÷ 01BB × 0308 × 0021 ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] EXCLAMATION MARK (STerm) ÷ [0.3] +÷ 01BB × 0022 ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [998.0] QUOTATION MARK (Close) ÷ [0.3] +÷ 01BB × 0308 × 0022 ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] QUOTATION MARK (Close) ÷ [0.3] +÷ 01BB × 002C ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [998.0] COMMA (SContinue) ÷ [0.3] +÷ 01BB × 0308 × 002C ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] COMMA (SContinue) ÷ [0.3] ÷ 01BB × 00AD ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [5.0] SOFT HYPHEN (Format_FE) ÷ [0.3] ÷ 01BB × 0308 × 00AD ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [5.0] COMBINING DIAERESIS (Extend_FE) × [5.0] SOFT HYPHEN (Format_FE) ÷ [0.3] ÷ 01BB × 0300 ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [5.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] ÷ 01BB × 0308 × 0300 ÷ # ÷ [0.2] LATIN LETTER TWO WITH STROKE (OLetter) × [5.0] COMBINING DIAERESIS (Extend_FE) × [5.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] -÷ 0030 × 0001 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [12.0] <START OF HEADING> (Other) ÷ [0.3] -÷ 0030 × 0308 × 0001 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] <START OF HEADING> (Other) ÷ [0.3] -÷ 0030 × 000D ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [12.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -÷ 0030 × 0308 × 000D ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -÷ 0030 × 000A ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [12.0] <LINE FEED (LF)> (LF) ÷ [0.3] -÷ 0030 × 0308 × 000A ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] <LINE FEED (LF)> (LF) ÷ [0.3] -÷ 0030 × 0085 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [12.0] <NEXT LINE (NEL)> (Sep) ÷ [0.3] -÷ 0030 × 0308 × 0085 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] <NEXT LINE (NEL)> (Sep) ÷ [0.3] -÷ 0030 × 0009 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [12.0] <CHARACTER TABULATION> (Sp) ÷ [0.3] -÷ 0030 × 0308 × 0009 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] <CHARACTER TABULATION> (Sp) ÷ [0.3] -÷ 0030 × 0061 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [12.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] -÷ 0030 × 0308 × 0061 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] -÷ 0030 × 0041 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [12.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] -÷ 0030 × 0308 × 0041 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] -÷ 0030 × 01BB ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [12.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] -÷ 0030 × 0308 × 01BB ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] -÷ 0030 × 0030 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [12.0] DIGIT ZERO (Numeric) ÷ [0.3] -÷ 0030 × 0308 × 0030 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] DIGIT ZERO (Numeric) ÷ [0.3] -÷ 0030 × 002E ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [12.0] FULL STOP (ATerm) ÷ [0.3] -÷ 0030 × 0308 × 002E ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] FULL STOP (ATerm) ÷ [0.3] -÷ 0030 × 0021 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [12.0] EXCLAMATION MARK (STerm) ÷ [0.3] -÷ 0030 × 0308 × 0021 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] EXCLAMATION MARK (STerm) ÷ [0.3] -÷ 0030 × 0022 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [12.0] QUOTATION MARK (Close) ÷ [0.3] -÷ 0030 × 0308 × 0022 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] QUOTATION MARK (Close) ÷ [0.3] -÷ 0030 × 002C ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [12.0] COMMA (SContinue) ÷ [0.3] -÷ 0030 × 0308 × 002C ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] COMMA (SContinue) ÷ [0.3] +÷ 0030 × 0001 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [998.0] <START OF HEADING> (Other) ÷ [0.3] +÷ 0030 × 0308 × 0001 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] <START OF HEADING> (Other) ÷ [0.3] +÷ 0030 × 000D ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [998.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +÷ 0030 × 0308 × 000D ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +÷ 0030 × 000A ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [998.0] <LINE FEED (LF)> (LF) ÷ [0.3] +÷ 0030 × 0308 × 000A ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] <LINE FEED (LF)> (LF) ÷ [0.3] +÷ 0030 × 0085 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [998.0] <NEXT LINE (NEL)> (Sep) ÷ [0.3] +÷ 0030 × 0308 × 0085 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] <NEXT LINE (NEL)> (Sep) ÷ [0.3] +÷ 0030 × 0009 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [998.0] <CHARACTER TABULATION> (Sp) ÷ [0.3] +÷ 0030 × 0308 × 0009 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] <CHARACTER TABULATION> (Sp) ÷ [0.3] +÷ 0030 × 0061 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [998.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] +÷ 0030 × 0308 × 0061 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] +÷ 0030 × 0041 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [998.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] +÷ 0030 × 0308 × 0041 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] +÷ 0030 × 01BB ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [998.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] +÷ 0030 × 0308 × 01BB ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] +÷ 0030 × 0030 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [998.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0030 × 0308 × 0030 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0030 × 002E ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [998.0] FULL STOP (ATerm) ÷ [0.3] +÷ 0030 × 0308 × 002E ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] FULL STOP (ATerm) ÷ [0.3] +÷ 0030 × 0021 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [998.0] EXCLAMATION MARK (STerm) ÷ [0.3] +÷ 0030 × 0308 × 0021 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] EXCLAMATION MARK (STerm) ÷ [0.3] +÷ 0030 × 0022 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [998.0] QUOTATION MARK (Close) ÷ [0.3] +÷ 0030 × 0308 × 0022 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] QUOTATION MARK (Close) ÷ [0.3] +÷ 0030 × 002C ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [998.0] COMMA (SContinue) ÷ [0.3] +÷ 0030 × 0308 × 002C ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] COMMA (SContinue) ÷ [0.3] ÷ 0030 × 00AD ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [5.0] SOFT HYPHEN (Format_FE) ÷ [0.3] ÷ 0030 × 0308 × 00AD ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [5.0] COMBINING DIAERESIS (Extend_FE) × [5.0] SOFT HYPHEN (Format_FE) ÷ [0.3] ÷ 0030 × 0300 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [5.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] @@ -350,180 +352,179 @@ ÷ 0021 × 0308 × 00AD ÷ # ÷ [0.2] EXCLAMATION MARK (STerm) × [5.0] COMBINING DIAERESIS (Extend_FE) × [5.0] SOFT HYPHEN (Format_FE) ÷ [0.3] ÷ 0021 × 0300 ÷ # ÷ [0.2] EXCLAMATION MARK (STerm) × [5.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] ÷ 0021 × 0308 × 0300 ÷ # ÷ [0.2] EXCLAMATION MARK (STerm) × [5.0] COMBINING DIAERESIS (Extend_FE) × [5.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] -÷ 0022 × 0001 ÷ # ÷ [0.2] QUOTATION MARK (Close) × [12.0] <START OF HEADING> (Other) ÷ [0.3] -÷ 0022 × 0308 × 0001 ÷ # ÷ [0.2] QUOTATION MARK (Close) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] <START OF HEADING> (Other) ÷ [0.3] -÷ 0022 × 000D ÷ # ÷ [0.2] QUOTATION MARK (Close) × [12.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -÷ 0022 × 0308 × 000D ÷ # ÷ [0.2] QUOTATION MARK (Close) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -÷ 0022 × 000A ÷ # ÷ [0.2] QUOTATION MARK (Close) × [12.0] <LINE FEED (LF)> (LF) ÷ [0.3] -÷ 0022 × 0308 × 000A ÷ # ÷ [0.2] QUOTATION MARK (Close) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] <LINE FEED (LF)> (LF) ÷ [0.3] -÷ 0022 × 0085 ÷ # ÷ [0.2] QUOTATION MARK (Close) × [12.0] <NEXT LINE (NEL)> (Sep) ÷ [0.3] -÷ 0022 × 0308 × 0085 ÷ # ÷ [0.2] QUOTATION MARK (Close) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] <NEXT LINE (NEL)> (Sep) ÷ [0.3] -÷ 0022 × 0009 ÷ # ÷ [0.2] QUOTATION MARK (Close) × [12.0] <CHARACTER TABULATION> (Sp) ÷ [0.3] -÷ 0022 × 0308 × 0009 ÷ # ÷ [0.2] QUOTATION MARK (Close) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] <CHARACTER TABULATION> (Sp) ÷ [0.3] -÷ 0022 × 0061 ÷ # ÷ [0.2] QUOTATION MARK (Close) × [12.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] -÷ 0022 × 0308 × 0061 ÷ # ÷ [0.2] QUOTATION MARK (Close) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] -÷ 0022 × 0041 ÷ # ÷ [0.2] QUOTATION MARK (Close) × [12.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] -÷ 0022 × 0308 × 0041 ÷ # ÷ [0.2] QUOTATION MARK (Close) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] -÷ 0022 × 01BB ÷ # ÷ [0.2] QUOTATION MARK (Close) × [12.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] -÷ 0022 × 0308 × 01BB ÷ # ÷ [0.2] QUOTATION MARK (Close) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] -÷ 0022 × 0030 ÷ # ÷ [0.2] QUOTATION MARK (Close) × [12.0] DIGIT ZERO (Numeric) ÷ [0.3] -÷ 0022 × 0308 × 0030 ÷ # ÷ [0.2] QUOTATION MARK (Close) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] DIGIT ZERO (Numeric) ÷ [0.3] -÷ 0022 × 002E ÷ # ÷ [0.2] QUOTATION MARK (Close) × [12.0] FULL STOP (ATerm) ÷ [0.3] -÷ 0022 × 0308 × 002E ÷ # ÷ [0.2] QUOTATION MARK (Close) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] FULL STOP (ATerm) ÷ [0.3] -÷ 0022 × 0021 ÷ # ÷ [0.2] QUOTATION MARK (Close) × [12.0] EXCLAMATION MARK (STerm) ÷ [0.3] -÷ 0022 × 0308 × 0021 ÷ # ÷ [0.2] QUOTATION MARK (Close) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] EXCLAMATION MARK (STerm) ÷ [0.3] -÷ 0022 × 0022 ÷ # ÷ [0.2] QUOTATION MARK (Close) × [12.0] QUOTATION MARK (Close) ÷ [0.3] -÷ 0022 × 0308 × 0022 ÷ # ÷ [0.2] QUOTATION MARK (Close) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] QUOTATION MARK (Close) ÷ [0.3] -÷ 0022 × 002C ÷ # ÷ [0.2] QUOTATION MARK (Close) × [12.0] COMMA (SContinue) ÷ [0.3] -÷ 0022 × 0308 × 002C ÷ # ÷ [0.2] QUOTATION MARK (Close) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] COMMA (SContinue) ÷ [0.3] +÷ 0022 × 0001 ÷ # ÷ [0.2] QUOTATION MARK (Close) × [998.0] <START OF HEADING> (Other) ÷ [0.3] +÷ 0022 × 0308 × 0001 ÷ # ÷ [0.2] QUOTATION MARK (Close) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] <START OF HEADING> (Other) ÷ [0.3] +÷ 0022 × 000D ÷ # ÷ [0.2] QUOTATION MARK (Close) × [998.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +÷ 0022 × 0308 × 000D ÷ # ÷ [0.2] QUOTATION MARK (Close) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +÷ 0022 × 000A ÷ # ÷ [0.2] QUOTATION MARK (Close) × [998.0] <LINE FEED (LF)> (LF) ÷ [0.3] +÷ 0022 × 0308 × 000A ÷ # ÷ [0.2] QUOTATION MARK (Close) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] <LINE FEED (LF)> (LF) ÷ [0.3] +÷ 0022 × 0085 ÷ # ÷ [0.2] QUOTATION MARK (Close) × [998.0] <NEXT LINE (NEL)> (Sep) ÷ [0.3] +÷ 0022 × 0308 × 0085 ÷ # ÷ [0.2] QUOTATION MARK (Close) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] <NEXT LINE (NEL)> (Sep) ÷ [0.3] +÷ 0022 × 0009 ÷ # ÷ [0.2] QUOTATION MARK (Close) × [998.0] <CHARACTER TABULATION> (Sp) ÷ [0.3] +÷ 0022 × 0308 × 0009 ÷ # ÷ [0.2] QUOTATION MARK (Close) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] <CHARACTER TABULATION> (Sp) ÷ [0.3] +÷ 0022 × 0061 ÷ # ÷ [0.2] QUOTATION MARK (Close) × [998.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] +÷ 0022 × 0308 × 0061 ÷ # ÷ [0.2] QUOTATION MARK (Close) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] +÷ 0022 × 0041 ÷ # ÷ [0.2] QUOTATION MARK (Close) × [998.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] +÷ 0022 × 0308 × 0041 ÷ # ÷ [0.2] QUOTATION MARK (Close) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] +÷ 0022 × 01BB ÷ # ÷ [0.2] QUOTATION MARK (Close) × [998.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] +÷ 0022 × 0308 × 01BB ÷ # ÷ [0.2] QUOTATION MARK (Close) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] +÷ 0022 × 0030 ÷ # ÷ [0.2] QUOTATION MARK (Close) × [998.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0022 × 0308 × 0030 ÷ # ÷ [0.2] QUOTATION MARK (Close) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0022 × 002E ÷ # ÷ [0.2] QUOTATION MARK (Close) × [998.0] FULL STOP (ATerm) ÷ [0.3] +÷ 0022 × 0308 × 002E ÷ # ÷ [0.2] QUOTATION MARK (Close) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] FULL STOP (ATerm) ÷ [0.3] +÷ 0022 × 0021 ÷ # ÷ [0.2] QUOTATION MARK (Close) × [998.0] EXCLAMATION MARK (STerm) ÷ [0.3] +÷ 0022 × 0308 × 0021 ÷ # ÷ [0.2] QUOTATION MARK (Close) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] EXCLAMATION MARK (STerm) ÷ [0.3] +÷ 0022 × 0022 ÷ # ÷ [0.2] QUOTATION MARK (Close) × [998.0] QUOTATION MARK (Close) ÷ [0.3] +÷ 0022 × 0308 × 0022 ÷ # ÷ [0.2] QUOTATION MARK (Close) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] QUOTATION MARK (Close) ÷ [0.3] +÷ 0022 × 002C ÷ # ÷ [0.2] QUOTATION MARK (Close) × [998.0] COMMA (SContinue) ÷ [0.3] +÷ 0022 × 0308 × 002C ÷ # ÷ [0.2] QUOTATION MARK (Close) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] COMMA (SContinue) ÷ [0.3] ÷ 0022 × 00AD ÷ # ÷ [0.2] QUOTATION MARK (Close) × [5.0] SOFT HYPHEN (Format_FE) ÷ [0.3] ÷ 0022 × 0308 × 00AD ÷ # ÷ [0.2] QUOTATION MARK (Close) × [5.0] COMBINING DIAERESIS (Extend_FE) × [5.0] SOFT HYPHEN (Format_FE) ÷ [0.3] ÷ 0022 × 0300 ÷ # ÷ [0.2] QUOTATION MARK (Close) × [5.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] ÷ 0022 × 0308 × 0300 ÷ # ÷ [0.2] QUOTATION MARK (Close) × [5.0] COMBINING DIAERESIS (Extend_FE) × [5.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] -÷ 002C × 0001 ÷ # ÷ [0.2] COMMA (SContinue) × [12.0] <START OF HEADING> (Other) ÷ [0.3] -÷ 002C × 0308 × 0001 ÷ # ÷ [0.2] COMMA (SContinue) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] <START OF HEADING> (Other) ÷ [0.3] -÷ 002C × 000D ÷ # ÷ [0.2] COMMA (SContinue) × [12.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -÷ 002C × 0308 × 000D ÷ # ÷ [0.2] COMMA (SContinue) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -÷ 002C × 000A ÷ # ÷ [0.2] COMMA (SContinue) × [12.0] <LINE FEED (LF)> (LF) ÷ [0.3] -÷ 002C × 0308 × 000A ÷ # ÷ [0.2] COMMA (SContinue) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] <LINE FEED (LF)> (LF) ÷ [0.3] -÷ 002C × 0085 ÷ # ÷ [0.2] COMMA (SContinue) × [12.0] <NEXT LINE (NEL)> (Sep) ÷ [0.3] -÷ 002C × 0308 × 0085 ÷ # ÷ [0.2] COMMA (SContinue) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] <NEXT LINE (NEL)> (Sep) ÷ [0.3] -÷ 002C × 0009 ÷ # ÷ [0.2] COMMA (SContinue) × [12.0] <CHARACTER TABULATION> (Sp) ÷ [0.3] -÷ 002C × 0308 × 0009 ÷ # ÷ [0.2] COMMA (SContinue) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] <CHARACTER TABULATION> (Sp) ÷ [0.3] -÷ 002C × 0061 ÷ # ÷ [0.2] COMMA (SContinue) × [12.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] -÷ 002C × 0308 × 0061 ÷ # ÷ [0.2] COMMA (SContinue) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] -÷ 002C × 0041 ÷ # ÷ [0.2] COMMA (SContinue) × [12.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] -÷ 002C × 0308 × 0041 ÷ # ÷ [0.2] COMMA (SContinue) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] -÷ 002C × 01BB ÷ # ÷ [0.2] COMMA (SContinue) × [12.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] -÷ 002C × 0308 × 01BB ÷ # ÷ [0.2] COMMA (SContinue) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] -÷ 002C × 0030 ÷ # ÷ [0.2] COMMA (SContinue) × [12.0] DIGIT ZERO (Numeric) ÷ [0.3] -÷ 002C × 0308 × 0030 ÷ # ÷ [0.2] COMMA (SContinue) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] DIGIT ZERO (Numeric) ÷ [0.3] -÷ 002C × 002E ÷ # ÷ [0.2] COMMA (SContinue) × [12.0] FULL STOP (ATerm) ÷ [0.3] -÷ 002C × 0308 × 002E ÷ # ÷ [0.2] COMMA (SContinue) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] FULL STOP (ATerm) ÷ [0.3] -÷ 002C × 0021 ÷ # ÷ [0.2] COMMA (SContinue) × [12.0] EXCLAMATION MARK (STerm) ÷ [0.3] -÷ 002C × 0308 × 0021 ÷ # ÷ [0.2] COMMA (SContinue) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] EXCLAMATION MARK (STerm) ÷ [0.3] -÷ 002C × 0022 ÷ # ÷ [0.2] COMMA (SContinue) × [12.0] QUOTATION MARK (Close) ÷ [0.3] -÷ 002C × 0308 × 0022 ÷ # ÷ [0.2] COMMA (SContinue) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] QUOTATION MARK (Close) ÷ [0.3] -÷ 002C × 002C ÷ # ÷ [0.2] COMMA (SContinue) × [12.0] COMMA (SContinue) ÷ [0.3] -÷ 002C × 0308 × 002C ÷ # ÷ [0.2] COMMA (SContinue) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] COMMA (SContinue) ÷ [0.3] +÷ 002C × 0001 ÷ # ÷ [0.2] COMMA (SContinue) × [998.0] <START OF HEADING> (Other) ÷ [0.3] +÷ 002C × 0308 × 0001 ÷ # ÷ [0.2] COMMA (SContinue) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] <START OF HEADING> (Other) ÷ [0.3] +÷ 002C × 000D ÷ # ÷ [0.2] COMMA (SContinue) × [998.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +÷ 002C × 0308 × 000D ÷ # ÷ [0.2] COMMA (SContinue) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +÷ 002C × 000A ÷ # ÷ [0.2] COMMA (SContinue) × [998.0] <LINE FEED (LF)> (LF) ÷ [0.3] +÷ 002C × 0308 × 000A ÷ # ÷ [0.2] COMMA (SContinue) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] <LINE FEED (LF)> (LF) ÷ [0.3] +÷ 002C × 0085 ÷ # ÷ [0.2] COMMA (SContinue) × [998.0] <NEXT LINE (NEL)> (Sep) ÷ [0.3] +÷ 002C × 0308 × 0085 ÷ # ÷ [0.2] COMMA (SContinue) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] <NEXT LINE (NEL)> (Sep) ÷ [0.3] +÷ 002C × 0009 ÷ # ÷ [0.2] COMMA (SContinue) × [998.0] <CHARACTER TABULATION> (Sp) ÷ [0.3] +÷ 002C × 0308 × 0009 ÷ # ÷ [0.2] COMMA (SContinue) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] <CHARACTER TABULATION> (Sp) ÷ [0.3] +÷ 002C × 0061 ÷ # ÷ [0.2] COMMA (SContinue) × [998.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] +÷ 002C × 0308 × 0061 ÷ # ÷ [0.2] COMMA (SContinue) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] +÷ 002C × 0041 ÷ # ÷ [0.2] COMMA (SContinue) × [998.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] +÷ 002C × 0308 × 0041 ÷ # ÷ [0.2] COMMA (SContinue) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] +÷ 002C × 01BB ÷ # ÷ [0.2] COMMA (SContinue) × [998.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] +÷ 002C × 0308 × 01BB ÷ # ÷ [0.2] COMMA (SContinue) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] +÷ 002C × 0030 ÷ # ÷ [0.2] COMMA (SContinue) × [998.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 002C × 0308 × 0030 ÷ # ÷ [0.2] COMMA (SContinue) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 002C × 002E ÷ # ÷ [0.2] COMMA (SContinue) × [998.0] FULL STOP (ATerm) ÷ [0.3] +÷ 002C × 0308 × 002E ÷ # ÷ [0.2] COMMA (SContinue) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] FULL STOP (ATerm) ÷ [0.3] +÷ 002C × 0021 ÷ # ÷ [0.2] COMMA (SContinue) × [998.0] EXCLAMATION MARK (STerm) ÷ [0.3] +÷ 002C × 0308 × 0021 ÷ # ÷ [0.2] COMMA (SContinue) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] EXCLAMATION MARK (STerm) ÷ [0.3] +÷ 002C × 0022 ÷ # ÷ [0.2] COMMA (SContinue) × [998.0] QUOTATION MARK (Close) ÷ [0.3] +÷ 002C × 0308 × 0022 ÷ # ÷ [0.2] COMMA (SContinue) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] QUOTATION MARK (Close) ÷ [0.3] +÷ 002C × 002C ÷ # ÷ [0.2] COMMA (SContinue) × [998.0] COMMA (SContinue) ÷ [0.3] +÷ 002C × 0308 × 002C ÷ # ÷ [0.2] COMMA (SContinue) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] COMMA (SContinue) ÷ [0.3] ÷ 002C × 00AD ÷ # ÷ [0.2] COMMA (SContinue) × [5.0] SOFT HYPHEN (Format_FE) ÷ [0.3] ÷ 002C × 0308 × 00AD ÷ # ÷ [0.2] COMMA (SContinue) × [5.0] COMBINING DIAERESIS (Extend_FE) × [5.0] SOFT HYPHEN (Format_FE) ÷ [0.3] ÷ 002C × 0300 ÷ # ÷ [0.2] COMMA (SContinue) × [5.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] ÷ 002C × 0308 × 0300 ÷ # ÷ [0.2] COMMA (SContinue) × [5.0] COMBINING DIAERESIS (Extend_FE) × [5.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] -÷ 00AD × 0001 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [12.0] <START OF HEADING> (Other) ÷ [0.3] -÷ 00AD × 0308 × 0001 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] <START OF HEADING> (Other) ÷ [0.3] -÷ 00AD × 000D ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [12.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -÷ 00AD × 0308 × 000D ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -÷ 00AD × 000A ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [12.0] <LINE FEED (LF)> (LF) ÷ [0.3] -÷ 00AD × 0308 × 000A ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] <LINE FEED (LF)> (LF) ÷ [0.3] -÷ 00AD × 0085 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [12.0] <NEXT LINE (NEL)> (Sep) ÷ [0.3] -÷ 00AD × 0308 × 0085 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] <NEXT LINE (NEL)> (Sep) ÷ [0.3] -÷ 00AD × 0009 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [12.0] <CHARACTER TABULATION> (Sp) ÷ [0.3] -÷ 00AD × 0308 × 0009 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] <CHARACTER TABULATION> (Sp) ÷ [0.3] -÷ 00AD × 0061 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [12.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] -÷ 00AD × 0308 × 0061 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] -÷ 00AD × 0041 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [12.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] -÷ 00AD × 0308 × 0041 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] -÷ 00AD × 01BB ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [12.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] -÷ 00AD × 0308 × 01BB ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] -÷ 00AD × 0030 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [12.0] DIGIT ZERO (Numeric) ÷ [0.3] -÷ 00AD × 0308 × 0030 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] DIGIT ZERO (Numeric) ÷ [0.3] -÷ 00AD × 002E ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [12.0] FULL STOP (ATerm) ÷ [0.3] -÷ 00AD × 0308 × 002E ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] FULL STOP (ATerm) ÷ [0.3] -÷ 00AD × 0021 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [12.0] EXCLAMATION MARK (STerm) ÷ [0.3] -÷ 00AD × 0308 × 0021 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] EXCLAMATION MARK (STerm) ÷ [0.3] -÷ 00AD × 0022 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [12.0] QUOTATION MARK (Close) ÷ [0.3] -÷ 00AD × 0308 × 0022 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] QUOTATION MARK (Close) ÷ [0.3] -÷ 00AD × 002C ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [12.0] COMMA (SContinue) ÷ [0.3] -÷ 00AD × 0308 × 002C ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] COMMA (SContinue) ÷ [0.3] +÷ 00AD × 0001 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [998.0] <START OF HEADING> (Other) ÷ [0.3] +÷ 00AD × 0308 × 0001 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] <START OF HEADING> (Other) ÷ [0.3] +÷ 00AD × 000D ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [998.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +÷ 00AD × 0308 × 000D ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +÷ 00AD × 000A ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [998.0] <LINE FEED (LF)> (LF) ÷ [0.3] +÷ 00AD × 0308 × 000A ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] <LINE FEED (LF)> (LF) ÷ [0.3] +÷ 00AD × 0085 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [998.0] <NEXT LINE (NEL)> (Sep) ÷ [0.3] +÷ 00AD × 0308 × 0085 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] <NEXT LINE (NEL)> (Sep) ÷ [0.3] +÷ 00AD × 0009 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [998.0] <CHARACTER TABULATION> (Sp) ÷ [0.3] +÷ 00AD × 0308 × 0009 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] <CHARACTER TABULATION> (Sp) ÷ [0.3] +÷ 00AD × 0061 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [998.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] +÷ 00AD × 0308 × 0061 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] +÷ 00AD × 0041 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [998.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] +÷ 00AD × 0308 × 0041 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] +÷ 00AD × 01BB ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [998.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] +÷ 00AD × 0308 × 01BB ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] +÷ 00AD × 0030 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [998.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 00AD × 0308 × 0030 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 00AD × 002E ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [998.0] FULL STOP (ATerm) ÷ [0.3] +÷ 00AD × 0308 × 002E ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] FULL STOP (ATerm) ÷ [0.3] +÷ 00AD × 0021 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [998.0] EXCLAMATION MARK (STerm) ÷ [0.3] +÷ 00AD × 0308 × 0021 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] EXCLAMATION MARK (STerm) ÷ [0.3] +÷ 00AD × 0022 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [998.0] QUOTATION MARK (Close) ÷ [0.3] +÷ 00AD × 0308 × 0022 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] QUOTATION MARK (Close) ÷ [0.3] +÷ 00AD × 002C ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [998.0] COMMA (SContinue) ÷ [0.3] +÷ 00AD × 0308 × 002C ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] COMMA (SContinue) ÷ [0.3] ÷ 00AD × 00AD ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [5.0] SOFT HYPHEN (Format_FE) ÷ [0.3] ÷ 00AD × 0308 × 00AD ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [5.0] SOFT HYPHEN (Format_FE) ÷ [0.3] ÷ 00AD × 0300 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [5.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] ÷ 00AD × 0308 × 0300 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [5.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] -÷ 0300 × 0001 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [12.0] <START OF HEADING> (Other) ÷ [0.3] -÷ 0300 × 0308 × 0001 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] <START OF HEADING> (Other) ÷ [0.3] -÷ 0300 × 000D ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [12.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -÷ 0300 × 0308 × 000D ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -÷ 0300 × 000A ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [12.0] <LINE FEED (LF)> (LF) ÷ [0.3] -÷ 0300 × 0308 × 000A ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] <LINE FEED (LF)> (LF) ÷ [0.3] -÷ 0300 × 0085 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [12.0] <NEXT LINE (NEL)> (Sep) ÷ [0.3] -÷ 0300 × 0308 × 0085 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] <NEXT LINE (NEL)> (Sep) ÷ [0.3] -÷ 0300 × 0009 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [12.0] <CHARACTER TABULATION> (Sp) ÷ [0.3] -÷ 0300 × 0308 × 0009 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] <CHARACTER TABULATION> (Sp) ÷ [0.3] -÷ 0300 × 0061 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [12.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] -÷ 0300 × 0308 × 0061 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] -÷ 0300 × 0041 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [12.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] -÷ 0300 × 0308 × 0041 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] -÷ 0300 × 01BB ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [12.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] -÷ 0300 × 0308 × 01BB ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] -÷ 0300 × 0030 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [12.0] DIGIT ZERO (Numeric) ÷ [0.3] -÷ 0300 × 0308 × 0030 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] DIGIT ZERO (Numeric) ÷ [0.3] -÷ 0300 × 002E ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [12.0] FULL STOP (ATerm) ÷ [0.3] -÷ 0300 × 0308 × 002E ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] FULL STOP (ATerm) ÷ [0.3] -÷ 0300 × 0021 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [12.0] EXCLAMATION MARK (STerm) ÷ [0.3] -÷ 0300 × 0308 × 0021 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] EXCLAMATION MARK (STerm) ÷ [0.3] -÷ 0300 × 0022 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [12.0] QUOTATION MARK (Close) ÷ [0.3] -÷ 0300 × 0308 × 0022 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] QUOTATION MARK (Close) ÷ [0.3] -÷ 0300 × 002C ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [12.0] COMMA (SContinue) ÷ [0.3] -÷ 0300 × 0308 × 002C ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [12.0] COMMA (SContinue) ÷ [0.3] +÷ 0300 × 0001 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [998.0] <START OF HEADING> (Other) ÷ [0.3] +÷ 0300 × 0308 × 0001 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] <START OF HEADING> (Other) ÷ [0.3] +÷ 0300 × 000D ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [998.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +÷ 0300 × 0308 × 000D ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +÷ 0300 × 000A ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [998.0] <LINE FEED (LF)> (LF) ÷ [0.3] +÷ 0300 × 0308 × 000A ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] <LINE FEED (LF)> (LF) ÷ [0.3] +÷ 0300 × 0085 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [998.0] <NEXT LINE (NEL)> (Sep) ÷ [0.3] +÷ 0300 × 0308 × 0085 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] <NEXT LINE (NEL)> (Sep) ÷ [0.3] +÷ 0300 × 0009 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [998.0] <CHARACTER TABULATION> (Sp) ÷ [0.3] +÷ 0300 × 0308 × 0009 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] <CHARACTER TABULATION> (Sp) ÷ [0.3] +÷ 0300 × 0061 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [998.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] +÷ 0300 × 0308 × 0061 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN SMALL LETTER A (Lower) ÷ [0.3] +÷ 0300 × 0041 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [998.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] +÷ 0300 × 0308 × 0041 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN CAPITAL LETTER A (Upper) ÷ [0.3] +÷ 0300 × 01BB ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [998.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] +÷ 0300 × 0308 × 01BB ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN LETTER TWO WITH STROKE (OLetter) ÷ [0.3] +÷ 0300 × 0030 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [998.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0300 × 0308 × 0030 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0300 × 002E ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [998.0] FULL STOP (ATerm) ÷ [0.3] +÷ 0300 × 0308 × 002E ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] FULL STOP (ATerm) ÷ [0.3] +÷ 0300 × 0021 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [998.0] EXCLAMATION MARK (STerm) ÷ [0.3] +÷ 0300 × 0308 × 0021 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] EXCLAMATION MARK (STerm) ÷ [0.3] +÷ 0300 × 0022 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [998.0] QUOTATION MARK (Close) ÷ [0.3] +÷ 0300 × 0308 × 0022 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] QUOTATION MARK (Close) ÷ [0.3] +÷ 0300 × 002C ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [998.0] COMMA (SContinue) ÷ [0.3] +÷ 0300 × 0308 × 002C ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [998.0] COMMA (SContinue) ÷ [0.3] ÷ 0300 × 00AD ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [5.0] SOFT HYPHEN (Format_FE) ÷ [0.3] ÷ 0300 × 0308 × 00AD ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [5.0] SOFT HYPHEN (Format_FE) ÷ [0.3] ÷ 0300 × 0300 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [5.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] ÷ 0300 × 0308 × 0300 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [5.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] -÷ 0028 × 0022 × 0047 × 006F × 002E × 0022 × 0029 × 0020 ÷ 0028 × 0048 × 0065 × 0020 × 0064 × 0069 × 0064 × 002E × 0029 ÷ # ÷ [0.2] LEFT PARENTHESIS (Close) × [12.0] QUOTATION MARK (Close) × [12.0] LATIN CAPITAL LETTER G (Upper) × [12.0] LATIN SMALL LETTER O (Lower) × [12.0] FULL STOP (ATerm) × [9.0] QUOTATION MARK (Close) × [9.0] RIGHT PARENTHESIS (Close) × [9.0] SPACE (Sp) ÷ [11.0] LEFT PARENTHESIS (Close) × [12.0] LATIN CAPITAL LETTER H (Upper) × [12.0] LATIN SMALL LETTER E (Lower) × [12.0] SPACE (Sp) × [12.0] LATIN SMALL LETTER D (Lower) × [12.0] LATIN SMALL LETTER I (Lower) × [12.0] LATIN SMALL LETTER D (Lower) × [12.0] FULL STOP (ATerm) × [9.0] RIGHT PARENTHESIS (Close) ÷ [0.3] -÷ 0028 × 201C × 0047 × 006F × 003F × 201D × 0029 × 0020 ÷ 0028 × 0048 × 0065 × 0020 × 0064 × 0069 × 0064 × 002E × 0029 ÷ # ÷ [0.2] LEFT PARENTHESIS (Close) × [12.0] LEFT DOUBLE QUOTATION MARK (Close) × [12.0] LATIN CAPITAL LETTER G (Upper) × [12.0] LATIN SMALL LETTER O (Lower) × [12.0] QUESTION MARK (STerm) × [9.0] RIGHT DOUBLE QUOTATION MARK (Close) × [9.0] RIGHT PARENTHESIS (Close) × [9.0] SPACE (Sp) ÷ [11.0] LEFT PARENTHESIS (Close) × [12.0] LATIN CAPITAL LETTER H (Upper) × [12.0] LATIN SMALL LETTER E (Lower) × [12.0] SPACE (Sp) × [12.0] LATIN SMALL LETTER D (Lower) × [12.0] LATIN SMALL LETTER I (Lower) × [12.0] LATIN SMALL LETTER D (Lower) × [12.0] FULL STOP (ATerm) × [9.0] RIGHT PARENTHESIS (Close) ÷ [0.3] -÷ 0055 × 002E × 0053 × 002E × 0041 × 0300 × 002E × 0020 × 0069 × 0073 ÷ # ÷ [0.2] LATIN CAPITAL LETTER U (Upper) × [12.0] FULL STOP (ATerm) × [7.0] LATIN CAPITAL LETTER S (Upper) × [12.0] FULL STOP (ATerm) × [7.0] LATIN CAPITAL LETTER A (Upper) × [5.0] COMBINING GRAVE ACCENT (Extend_FE) × [12.0] FULL STOP (ATerm) × [8.0] SPACE (Sp) × [8.0] LATIN SMALL LETTER I (Lower) × [12.0] LATIN SMALL LETTER S (Lower) ÷ [0.3] -÷ 0055 × 002E × 0053 × 002E × 0041 × 0300 × 003F × 0020 ÷ 0048 × 0065 ÷ # ÷ [0.2] LATIN CAPITAL LETTER U (Upper) × [12.0] FULL STOP (ATerm) × [7.0] LATIN CAPITAL LETTER S (Upper) × [12.0] FULL STOP (ATerm) × [7.0] LATIN CAPITAL LETTER A (Upper) × [5.0] COMBINING GRAVE ACCENT (Extend_FE) × [12.0] QUESTION MARK (STerm) × [9.0] SPACE (Sp) ÷ [11.0] LATIN CAPITAL LETTER H (Upper) × [12.0] LATIN SMALL LETTER E (Lower) ÷ [0.3] -÷ 0055 × 002E × 0053 × 002E × 0041 × 0300 × 002E ÷ # ÷ [0.2] LATIN CAPITAL LETTER U (Upper) × [12.0] FULL STOP (ATerm) × [7.0] LATIN CAPITAL LETTER S (Upper) × [12.0] FULL STOP (ATerm) × [7.0] LATIN CAPITAL LETTER A (Upper) × [5.0] COMBINING GRAVE ACCENT (Extend_FE) × [12.0] FULL STOP (ATerm) ÷ [0.3] -÷ 0033 × 002E × 0034 ÷ # ÷ [0.2] DIGIT THREE (Numeric) × [12.0] FULL STOP (ATerm) × [6.0] DIGIT FOUR (Numeric) ÷ [0.3] -÷ 0063 × 002E × 0064 ÷ # ÷ [0.2] LATIN SMALL LETTER C (Lower) × [12.0] FULL STOP (ATerm) × [8.0] LATIN SMALL LETTER D (Lower) ÷ [0.3] -÷ 0043 × 002E × 0064 ÷ # ÷ [0.2] LATIN CAPITAL LETTER C (Upper) × [12.0] FULL STOP (ATerm) × [8.0] LATIN SMALL LETTER D (Lower) ÷ [0.3] -÷ 0063 × 002E × 0044 ÷ # ÷ [0.2] LATIN SMALL LETTER C (Lower) × [12.0] FULL STOP (ATerm) × [7.0] LATIN CAPITAL LETTER D (Upper) ÷ [0.3] -÷ 0043 × 002E × 0044 ÷ # ÷ [0.2] LATIN CAPITAL LETTER C (Upper) × [12.0] FULL STOP (ATerm) × [7.0] LATIN CAPITAL LETTER D (Upper) ÷ [0.3] -÷ 0065 × 0074 × 0063 × 002E × 0029 × 2019 × 00A0 × 0074 × 0068 × 0065 ÷ # ÷ [0.2] LATIN SMALL LETTER E (Lower) × [12.0] LATIN SMALL LETTER T (Lower) × [12.0] LATIN SMALL LETTER C (Lower) × [12.0] FULL STOP (ATerm) × [8.0] RIGHT PARENTHESIS (Close) × [8.0] RIGHT SINGLE QUOTATION MARK (Close) × [8.0] NO-BREAK SPACE (Sp) × [8.0] LATIN SMALL LETTER T (Lower) × [12.0] LATIN SMALL LETTER H (Lower) × [12.0] LATIN SMALL LETTER E (Lower) ÷ [0.3] -÷ 0065 × 0074 × 0063 × 002E × 0029 × 2019 × 00A0 ÷ 0054 × 0068 × 0065 ÷ # ÷ [0.2] LATIN SMALL LETTER E (Lower) × [12.0] LATIN SMALL LETTER T (Lower) × [12.0] LATIN SMALL LETTER C (Lower) × [12.0] FULL STOP (ATerm) × [9.0] RIGHT PARENTHESIS (Close) × [9.0] RIGHT SINGLE QUOTATION MARK (Close) × [9.0] NO-BREAK SPACE (Sp) ÷ [11.0] LATIN CAPITAL LETTER T (Upper) × [12.0] LATIN SMALL LETTER H (Lower) × [12.0] LATIN SMALL LETTER E (Lower) ÷ [0.3] -÷ 0065 × 0074 × 0063 × 002E × 0029 × 2019 × 00A0 × 2018 × 0028 × 0074 × 0068 × 0065 ÷ # ÷ [0.2] LATIN SMALL LETTER E (Lower) × [12.0] LATIN SMALL LETTER T (Lower) × [12.0] LATIN SMALL LETTER C (Lower) × [12.0] FULL STOP (ATerm) × [8.0] RIGHT PARENTHESIS (Close) × [8.0] RIGHT SINGLE QUOTATION MARK (Close) × [8.0] NO-BREAK SPACE (Sp) × [8.0] LEFT SINGLE QUOTATION MARK (Close) × [12.0] LEFT PARENTHESIS (Close) × [12.0] LATIN SMALL LETTER T (Lower) × [12.0] LATIN SMALL LETTER H (Lower) × [12.0] LATIN SMALL LETTER E (Lower) ÷ [0.3] -÷ 0065 × 0074 × 0063 × 002E × 0029 × 2019 × 00A0 ÷ 2018 × 0028 × 0054 × 0068 × 0065 ÷ # ÷ [0.2] LATIN SMALL LETTER E (Lower) × [12.0] LATIN SMALL LETTER T (Lower) × [12.0] LATIN SMALL LETTER C (Lower) × [12.0] FULL STOP (ATerm) × [9.0] RIGHT PARENTHESIS (Close) × [9.0] RIGHT SINGLE QUOTATION MARK (Close) × [9.0] NO-BREAK SPACE (Sp) ÷ [11.0] LEFT SINGLE QUOTATION MARK (Close) × [12.0] LEFT PARENTHESIS (Close) × [12.0] LATIN CAPITAL LETTER T (Upper) × [12.0] LATIN SMALL LETTER H (Lower) × [12.0] LATIN SMALL LETTER E (Lower) ÷ [0.3] -÷ 0065 × 0074 × 0063 × 002E × 0029 × 2019 × 00A0 × 0308 × 0074 × 0068 × 0065 ÷ # ÷ [0.2] LATIN SMALL LETTER E (Lower) × [12.0] LATIN SMALL LETTER T (Lower) × [12.0] LATIN SMALL LETTER C (Lower) × [12.0] FULL STOP (ATerm) × [8.0] RIGHT PARENTHESIS (Close) × [8.0] RIGHT SINGLE QUOTATION MARK (Close) × [8.0] NO-BREAK SPACE (Sp) × [5.0] COMBINING DIAERESIS (Extend_FE) × [8.0] LATIN SMALL LETTER T (Lower) × [12.0] LATIN SMALL LETTER H (Lower) × [12.0] LATIN SMALL LETTER E (Lower) ÷ [0.3] -÷ 0065 × 0074 × 0063 × 002E × 0029 × 2019 × 00A0 × 0308 ÷ 0054 × 0068 × 0065 ÷ # ÷ [0.2] LATIN SMALL LETTER E (Lower) × [12.0] LATIN SMALL LETTER T (Lower) × [12.0] LATIN SMALL LETTER C (Lower) × [12.0] FULL STOP (ATerm) × [9.0] RIGHT PARENTHESIS (Close) × [9.0] RIGHT SINGLE QUOTATION MARK (Close) × [9.0] NO-BREAK SPACE (Sp) × [5.0] COMBINING DIAERESIS (Extend_FE) ÷ [11.0] LATIN CAPITAL LETTER T (Upper) × [12.0] LATIN SMALL LETTER H (Lower) × [12.0] LATIN SMALL LETTER E (Lower) ÷ [0.3] -÷ 0065 × 0074 × 0063 × 002E × 0029 × 2019 × 0308 ÷ 0054 × 0068 × 0065 ÷ # ÷ [0.2] LATIN SMALL LETTER E (Lower) × [12.0] LATIN SMALL LETTER T (Lower) × [12.0] LATIN SMALL LETTER C (Lower) × [12.0] FULL STOP (ATerm) × [9.0] RIGHT PARENTHESIS (Close) × [9.0] RIGHT SINGLE QUOTATION MARK (Close) × [5.0] COMBINING DIAERESIS (Extend_FE) ÷ [11.0] LATIN CAPITAL LETTER T (Upper) × [12.0] LATIN SMALL LETTER H (Lower) × [12.0] LATIN SMALL LETTER E (Lower) ÷ [0.3] -÷ 0065 × 0074 × 0063 × 002E × 0029 × 000A ÷ 0308 × 0054 × 0068 × 0065 ÷ # ÷ [0.2] LATIN SMALL LETTER E (Lower) × [12.0] LATIN SMALL LETTER T (Lower) × [12.0] LATIN SMALL LETTER C (Lower) × [12.0] FULL STOP (ATerm) × [9.0] RIGHT PARENTHESIS (Close) × [9.0] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [12.0] LATIN CAPITAL LETTER T (Upper) × [12.0] LATIN SMALL LETTER H (Lower) × [12.0] LATIN SMALL LETTER E (Lower) ÷ [0.3] -÷ 0074 × 0068 × 0065 × 0020 × 0072 × 0065 × 0073 × 0070 × 002E × 0020 × 006C × 0065 × 0061 × 0064 × 0065 × 0072 × 0073 × 0020 × 0061 × 0072 × 0065 ÷ # ÷ [0.2] LATIN SMALL LETTER T (Lower) × [12.0] LATIN SMALL LETTER H (Lower) × [12.0] LATIN SMALL LETTER E (Lower) × [12.0] SPACE (Sp) × [12.0] LATIN SMALL LETTER R (Lower) × [12.0] LATIN SMALL LETTER E (Lower) × [12.0] LATIN SMALL LETTER S (Lower) × [12.0] LATIN SMALL LETTER P (Lower) × [12.0] FULL STOP (ATerm) × [8.0] SPACE (Sp) × [8.0] LATIN SMALL LETTER L (Lower) × [12.0] LATIN SMALL LETTER E (Lower) × [12.0] LATIN SMALL LETTER A (Lower) × [12.0] LATIN SMALL LETTER D (Lower) × [12.0] LATIN SMALL LETTER E (Lower) × [12.0] LATIN SMALL LETTER R (Lower) × [12.0] LATIN SMALL LETTER S (Lower) × [12.0] SPACE (Sp) × [12.0] LATIN SMALL LETTER A (Lower) × [12.0] LATIN SMALL LETTER R (Lower) × [12.0] LATIN SMALL LETTER E (Lower) ÷ [0.3] -÷ 5B57 × 002E ÷ 5B57 ÷ # ÷ [0.2] CJK UNIFIED IDEOGRAPH-5B57 (OLetter) × [12.0] FULL STOP (ATerm) ÷ [11.0] CJK UNIFIED IDEOGRAPH-5B57 (OLetter) ÷ [0.3] -÷ 0065 × 0074 × 0063 × 002E ÷ 5B83 ÷ # ÷ [0.2] LATIN SMALL LETTER E (Lower) × [12.0] LATIN SMALL LETTER T (Lower) × [12.0] LATIN SMALL LETTER C (Lower) × [12.0] FULL STOP (ATerm) ÷ [11.0] CJK UNIFIED IDEOGRAPH-5B83 (OLetter) ÷ [0.3] -÷ 0065 × 0074 × 0063 × 002E × 3002 ÷ # ÷ [0.2] LATIN SMALL LETTER E (Lower) × [12.0] LATIN SMALL LETTER T (Lower) × [12.0] LATIN SMALL LETTER C (Lower) × [12.0] FULL STOP (ATerm) × [8.1] IDEOGRAPHIC FULL STOP (STerm) ÷ [0.3] -÷ 5B57 × 3002 ÷ 5B83 ÷ # ÷ [0.2] CJK UNIFIED IDEOGRAPH-5B57 (OLetter) × [12.0] IDEOGRAPHIC FULL STOP (STerm) ÷ [11.0] CJK UNIFIED IDEOGRAPH-5B83 (OLetter) ÷ [0.3] +÷ 000D × 000A ÷ 0061 × 000A ÷ 0308 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) × [3.0] <LINE FEED (LF)> (LF) ÷ [4.0] LATIN SMALL LETTER A (Lower) × [998.0] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [0.3] +÷ 0061 × 0308 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Lower) × [5.0] COMBINING DIAERESIS (Extend_FE) ÷ [0.3] +÷ 0020 × 200D × 0646 ÷ # ÷ [0.2] SPACE (Sp) × [5.0] ZERO WIDTH JOINER (Extend_FE) × [998.0] ARABIC LETTER NOON (OLetter) ÷ [0.3] +÷ 0646 × 200D × 0020 ÷ # ÷ [0.2] ARABIC LETTER NOON (OLetter) × [5.0] ZERO WIDTH JOINER (Extend_FE) × [998.0] SPACE (Sp) ÷ [0.3] +÷ 0028 × 0022 × 0047 × 006F × 002E × 0022 × 0029 × 0020 ÷ 0028 × 0048 × 0065 × 0020 × 0064 × 0069 × 0064 × 002E × 0029 ÷ # ÷ [0.2] LEFT PARENTHESIS (Close) × [998.0] QUOTATION MARK (Close) × [998.0] LATIN CAPITAL LETTER G (Upper) × [998.0] LATIN SMALL LETTER O (Lower) × [998.0] FULL STOP (ATerm) × [9.0] QUOTATION MARK (Close) × [9.0] RIGHT PARENTHESIS (Close) × [9.0] SPACE (Sp) ÷ [11.0] LEFT PARENTHESIS (Close) × [998.0] LATIN CAPITAL LETTER H (Upper) × [998.0] LATIN SMALL LETTER E (Lower) × [998.0] SPACE (Sp) × [998.0] LATIN SMALL LETTER D (Lower) × [998.0] LATIN SMALL LETTER I (Lower) × [998.0] LATIN SMALL LETTER D (Lower) × [998.0] FULL STOP (ATerm) × [9.0] RIGHT PARENTHESIS (Close) ÷ [0.3] +÷ 0028 × 201C × 0047 × 006F × 003F × 201D × 0029 × 0020 ÷ 0028 × 0048 × 0065 × 0020 × 0064 × 0069 × 0064 × 002E × 0029 ÷ # ÷ [0.2] LEFT PARENTHESIS (Close) × [998.0] LEFT DOUBLE QUOTATION MARK (Close) × [998.0] LATIN CAPITAL LETTER G (Upper) × [998.0] LATIN SMALL LETTER O (Lower) × [998.0] QUESTION MARK (STerm) × [9.0] RIGHT DOUBLE QUOTATION MARK (Close) × [9.0] RIGHT PARENTHESIS (Close) × [9.0] SPACE (Sp) ÷ [11.0] LEFT PARENTHESIS (Close) × [998.0] LATIN CAPITAL LETTER H (Upper) × [998.0] LATIN SMALL LETTER E (Lower) × [998.0] SPACE (Sp) × [998.0] LATIN SMALL LETTER D (Lower) × [998.0] LATIN SMALL LETTER I (Lower) × [998.0] LATIN SMALL LETTER D (Lower) × [998.0] FULL STOP (ATerm) × [9.0] RIGHT PARENTHESIS (Close) ÷ [0.3] +÷ 0055 × 002E × 0053 × 002E × 0041 × 0300 × 002E × 0020 × 0069 × 0073 ÷ # ÷ [0.2] LATIN CAPITAL LETTER U (Upper) × [998.0] FULL STOP (ATerm) × [7.0] LATIN CAPITAL LETTER S (Upper) × [998.0] FULL STOP (ATerm) × [7.0] LATIN CAPITAL LETTER A (Upper) × [5.0] COMBINING GRAVE ACCENT (Extend_FE) × [998.0] FULL STOP (ATerm) × [8.0] SPACE (Sp) × [8.0] LATIN SMALL LETTER I (Lower) × [998.0] LATIN SMALL LETTER S (Lower) ÷ [0.3] +÷ 0055 × 002E × 0053 × 002E × 0041 × 0300 × 003F × 0020 ÷ 0048 × 0065 ÷ # ÷ [0.2] LATIN CAPITAL LETTER U (Upper) × [998.0] FULL STOP (ATerm) × [7.0] LATIN CAPITAL LETTER S (Upper) × [998.0] FULL STOP (ATerm) × [7.0] LATIN CAPITAL LETTER A (Upper) × [5.0] COMBINING GRAVE ACCENT (Extend_FE) × [998.0] QUESTION MARK (STerm) × [9.0] SPACE (Sp) ÷ [11.0] LATIN CAPITAL LETTER H (Upper) × [998.0] LATIN SMALL LETTER E (Lower) ÷ [0.3] +÷ 0055 × 002E × 0053 × 002E × 0041 × 0300 × 002E ÷ # ÷ [0.2] LATIN CAPITAL LETTER U (Upper) × [998.0] FULL STOP (ATerm) × [7.0] LATIN CAPITAL LETTER S (Upper) × [998.0] FULL STOP (ATerm) × [7.0] LATIN CAPITAL LETTER A (Upper) × [5.0] COMBINING GRAVE ACCENT (Extend_FE) × [998.0] FULL STOP (ATerm) ÷ [0.3] +÷ 0033 × 002E × 0034 ÷ # ÷ [0.2] DIGIT THREE (Numeric) × [998.0] FULL STOP (ATerm) × [6.0] DIGIT FOUR (Numeric) ÷ [0.3] +÷ 0063 × 002E × 0064 ÷ # ÷ [0.2] LATIN SMALL LETTER C (Lower) × [998.0] FULL STOP (ATerm) × [8.0] LATIN SMALL LETTER D (Lower) ÷ [0.3] +÷ 0043 × 002E × 0064 ÷ # ÷ [0.2] LATIN CAPITAL LETTER C (Upper) × [998.0] FULL STOP (ATerm) × [8.0] LATIN SMALL LETTER D (Lower) ÷ [0.3] +÷ 0063 × 002E × 0044 ÷ # ÷ [0.2] LATIN SMALL LETTER C (Lower) × [998.0] FULL STOP (ATerm) × [7.0] LATIN CAPITAL LETTER D (Upper) ÷ [0.3] +÷ 0043 × 002E × 0044 ÷ # ÷ [0.2] LATIN CAPITAL LETTER C (Upper) × [998.0] FULL STOP (ATerm) × [7.0] LATIN CAPITAL LETTER D (Upper) ÷ [0.3] +÷ 0065 × 0074 × 0063 × 002E × 0029 × 2019 × 00A0 × 0074 × 0068 × 0065 ÷ # ÷ [0.2] LATIN SMALL LETTER E (Lower) × [998.0] LATIN SMALL LETTER T (Lower) × [998.0] LATIN SMALL LETTER C (Lower) × [998.0] FULL STOP (ATerm) × [8.0] RIGHT PARENTHESIS (Close) × [8.0] RIGHT SINGLE QUOTATION MARK (Close) × [8.0] NO-BREAK SPACE (Sp) × [8.0] LATIN SMALL LETTER T (Lower) × [998.0] LATIN SMALL LETTER H (Lower) × [998.0] LATIN SMALL LETTER E (Lower) ÷ [0.3] +÷ 0065 × 0074 × 0063 × 002E × 0029 × 2019 × 00A0 ÷ 0054 × 0068 × 0065 ÷ # ÷ [0.2] LATIN SMALL LETTER E (Lower) × [998.0] LATIN SMALL LETTER T (Lower) × [998.0] LATIN SMALL LETTER C (Lower) × [998.0] FULL STOP (ATerm) × [9.0] RIGHT PARENTHESIS (Close) × [9.0] RIGHT SINGLE QUOTATION MARK (Close) × [9.0] NO-BREAK SPACE (Sp) ÷ [11.0] LATIN CAPITAL LETTER T (Upper) × [998.0] LATIN SMALL LETTER H (Lower) × [998.0] LATIN SMALL LETTER E (Lower) ÷ [0.3] +÷ 0065 × 0074 × 0063 × 002E × 0029 × 2019 × 00A0 × 2018 × 0028 × 0074 × 0068 × 0065 ÷ # ÷ [0.2] LATIN SMALL LETTER E (Lower) × [998.0] LATIN SMALL LETTER T (Lower) × [998.0] LATIN SMALL LETTER C (Lower) × [998.0] FULL STOP (ATerm) × [8.0] RIGHT PARENTHESIS (Close) × [8.0] RIGHT SINGLE QUOTATION MARK (Close) × [8.0] NO-BREAK SPACE (Sp) × [8.0] LEFT SINGLE QUOTATION MARK (Close) × [998.0] LEFT PARENTHESIS (Close) × [998.0] LATIN SMALL LETTER T (Lower) × [998.0] LATIN SMALL LETTER H (Lower) × [998.0] LATIN SMALL LETTER E (Lower) ÷ [0.3] +÷ 0065 × 0074 × 0063 × 002E × 0029 × 2019 × 00A0 ÷ 2018 × 0028 × 0054 × 0068 × 0065 ÷ # ÷ [0.2] LATIN SMALL LETTER E (Lower) × [998.0] LATIN SMALL LETTER T (Lower) × [998.0] LATIN SMALL LETTER C (Lower) × [998.0] FULL STOP (ATerm) × [9.0] RIGHT PARENTHESIS (Close) × [9.0] RIGHT SINGLE QUOTATION MARK (Close) × [9.0] NO-BREAK SPACE (Sp) ÷ [11.0] LEFT SINGLE QUOTATION MARK (Close) × [998.0] LEFT PARENTHESIS (Close) × [998.0] LATIN CAPITAL LETTER T (Upper) × [998.0] LATIN SMALL LETTER H (Lower) × [998.0] LATIN SMALL LETTER E (Lower) ÷ [0.3] +÷ 0065 × 0074 × 0063 × 002E × 0029 × 2019 × 00A0 × 0308 × 0074 × 0068 × 0065 ÷ # ÷ [0.2] LATIN SMALL LETTER E (Lower) × [998.0] LATIN SMALL LETTER T (Lower) × [998.0] LATIN SMALL LETTER C (Lower) × [998.0] FULL STOP (ATerm) × [8.0] RIGHT PARENTHESIS (Close) × [8.0] RIGHT SINGLE QUOTATION MARK (Close) × [8.0] NO-BREAK SPACE (Sp) × [5.0] COMBINING DIAERESIS (Extend_FE) × [8.0] LATIN SMALL LETTER T (Lower) × [998.0] LATIN SMALL LETTER H (Lower) × [998.0] LATIN SMALL LETTER E (Lower) ÷ [0.3] +÷ 0065 × 0074 × 0063 × 002E × 0029 × 2019 × 00A0 × 0308 ÷ 0054 × 0068 × 0065 ÷ # ÷ [0.2] LATIN SMALL LETTER E (Lower) × [998.0] LATIN SMALL LETTER T (Lower) × [998.0] LATIN SMALL LETTER C (Lower) × [998.0] FULL STOP (ATerm) × [9.0] RIGHT PARENTHESIS (Close) × [9.0] RIGHT SINGLE QUOTATION MARK (Close) × [9.0] NO-BREAK SPACE (Sp) × [5.0] COMBINING DIAERESIS (Extend_FE) ÷ [11.0] LATIN CAPITAL LETTER T (Upper) × [998.0] LATIN SMALL LETTER H (Lower) × [998.0] LATIN SMALL LETTER E (Lower) ÷ [0.3] +÷ 0065 × 0074 × 0063 × 002E × 0029 × 2019 × 0308 ÷ 0054 × 0068 × 0065 ÷ # ÷ [0.2] LATIN SMALL LETTER E (Lower) × [998.0] LATIN SMALL LETTER T (Lower) × [998.0] LATIN SMALL LETTER C (Lower) × [998.0] FULL STOP (ATerm) × [9.0] RIGHT PARENTHESIS (Close) × [9.0] RIGHT SINGLE QUOTATION MARK (Close) × [5.0] COMBINING DIAERESIS (Extend_FE) ÷ [11.0] LATIN CAPITAL LETTER T (Upper) × [998.0] LATIN SMALL LETTER H (Lower) × [998.0] LATIN SMALL LETTER E (Lower) ÷ [0.3] +÷ 0065 × 0074 × 0063 × 002E × 0029 × 000A ÷ 0308 × 0054 × 0068 × 0065 ÷ # ÷ [0.2] LATIN SMALL LETTER E (Lower) × [998.0] LATIN SMALL LETTER T (Lower) × [998.0] LATIN SMALL LETTER C (Lower) × [998.0] FULL STOP (ATerm) × [9.0] RIGHT PARENTHESIS (Close) × [9.0] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_FE) × [998.0] LATIN CAPITAL LETTER T (Upper) × [998.0] LATIN SMALL LETTER H (Lower) × [998.0] LATIN SMALL LETTER E (Lower) ÷ [0.3] +÷ 0074 × 0068 × 0065 × 0020 × 0072 × 0065 × 0073 × 0070 × 002E × 0020 × 006C × 0065 × 0061 × 0064 × 0065 × 0072 × 0073 × 0020 × 0061 × 0072 × 0065 ÷ # ÷ [0.2] LATIN SMALL LETTER T (Lower) × [998.0] LATIN SMALL LETTER H (Lower) × [998.0] LATIN SMALL LETTER E (Lower) × [998.0] SPACE (Sp) × [998.0] LATIN SMALL LETTER R (Lower) × [998.0] LATIN SMALL LETTER E (Lower) × [998.0] LATIN SMALL LETTER S (Lower) × [998.0] LATIN SMALL LETTER P (Lower) × [998.0] FULL STOP (ATerm) × [8.0] SPACE (Sp) × [8.0] LATIN SMALL LETTER L (Lower) × [998.0] LATIN SMALL LETTER E (Lower) × [998.0] LATIN SMALL LETTER A (Lower) × [998.0] LATIN SMALL LETTER D (Lower) × [998.0] LATIN SMALL LETTER E (Lower) × [998.0] LATIN SMALL LETTER R (Lower) × [998.0] LATIN SMALL LETTER S (Lower) × [998.0] SPACE (Sp) × [998.0] LATIN SMALL LETTER A (Lower) × [998.0] LATIN SMALL LETTER R (Lower) × [998.0] LATIN SMALL LETTER E (Lower) ÷ [0.3] +÷ 5B57 × 002E ÷ 5B57 ÷ # ÷ [0.2] CJK UNIFIED IDEOGRAPH-5B57 (OLetter) × [998.0] FULL STOP (ATerm) ÷ [11.0] CJK UNIFIED IDEOGRAPH-5B57 (OLetter) ÷ [0.3] +÷ 0065 × 0074 × 0063 × 002E ÷ 5B83 ÷ # ÷ [0.2] LATIN SMALL LETTER E (Lower) × [998.0] LATIN SMALL LETTER T (Lower) × [998.0] LATIN SMALL LETTER C (Lower) × [998.0] FULL STOP (ATerm) ÷ [11.0] CJK UNIFIED IDEOGRAPH-5B83 (OLetter) ÷ [0.3] +÷ 0065 × 0074 × 0063 × 002E × 3002 ÷ # ÷ [0.2] LATIN SMALL LETTER E (Lower) × [998.0] LATIN SMALL LETTER T (Lower) × [998.0] LATIN SMALL LETTER C (Lower) × [998.0] FULL STOP (ATerm) × [8.1] IDEOGRAPHIC FULL STOP (STerm) ÷ [0.3] +÷ 5B57 × 3002 ÷ 5B83 ÷ # ÷ [0.2] CJK UNIFIED IDEOGRAPH-5B57 (OLetter) × [998.0] IDEOGRAPHIC FULL STOP (STerm) ÷ [11.0] CJK UNIFIED IDEOGRAPH-5B83 (OLetter) ÷ [0.3] ÷ 0021 × 0020 × 0020 ÷ # ÷ [0.2] EXCLAMATION MARK (STerm) × [9.0] SPACE (Sp) × [10.0] SPACE (Sp) ÷ [0.3] -÷ 2060 × 0028 × 2060 × 0022 × 2060 × 0047 × 2060 × 006F × 2060 × 002E × 2060 × 0022 × 2060 × 0029 × 2060 × 0020 × 2060 ÷ 0028 × 2060 × 0048 × 2060 × 0065 × 2060 × 0020 × 2060 × 0064 × 2060 × 0069 × 2060 × 0064 × 2060 × 002E × 2060 × 0029 × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) × [12.0] LEFT PARENTHESIS (Close) × [5.0] WORD JOINER (Format_FE) × [12.0] QUOTATION MARK (Close) × [5.0] WORD JOINER (Format_FE) × [12.0] LATIN CAPITAL LETTER G (Upper) × [5.0] WORD JOINER (Format_FE) × [12.0] LATIN SMALL LETTER O (Lower) × [5.0] WORD JOINER (Format_FE) × [12.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [9.0] QUOTATION MARK (Close) × [5.0] WORD JOINER (Format_FE) × [9.0] RIGHT PARENTHESIS (Close) × [5.0] WORD JOINER (Format_FE) × [9.0] SPACE (Sp) × [5.0] WORD JOINER (Format_FE) ÷ [11.0] LEFT PARENTHESIS (Close) × [5.0] WORD JOINER (Format_FE) × [12.0] LATIN CAPITAL LETTER H (Upper) × [5.0] WORD JOINER (Format_FE) × [12.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [12.0] SPACE (Sp) × [5.0] WORD JOINER (Format_FE) × [12.0] LATIN SMALL LETTER D (Lower) × [5.0] WORD JOINER (Format_FE) × [12.0] LATIN SMALL LETTER I (Lower) × [5.0] WORD JOINER (Format_FE) × [12.0] LATIN SMALL LETTER D (Lower) × [5.0] WORD JOINER (Format_FE) × [12.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [9.0] RIGHT PARENTHESIS (Close) × [5.0] WORD JOINER (Format_FE) × [5.0] WORD JOINER (Format_FE) ÷ [0.3] -÷ 2060 × 0028 × 2060 × 201C × 2060 × 0047 × 2060 × 006F × 2060 × 003F × 2060 × 201D × 2060 × 0029 × 2060 × 0020 × 2060 ÷ 0028 × 2060 × 0048 × 2060 × 0065 × 2060 × 0020 × 2060 × 0064 × 2060 × 0069 × 2060 × 0064 × 2060 × 002E × 2060 × 0029 × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) × [12.0] LEFT PARENTHESIS (Close) × [5.0] WORD JOINER (Format_FE) × [12.0] LEFT DOUBLE QUOTATION MARK (Close) × [5.0] WORD JOINER (Format_FE) × [12.0] LATIN CAPITAL LETTER G (Upper) × [5.0] WORD JOINER (Format_FE) × [12.0] LATIN SMALL LETTER O (Lower) × [5.0] WORD JOINER (Format_FE) × [12.0] QUESTION MARK (STerm) × [5.0] WORD JOINER (Format_FE) × [9.0] RIGHT DOUBLE QUOTATION MARK (Close) × [5.0] WORD JOINER (Format_FE) × [9.0] RIGHT PARENTHESIS (Close) × [5.0] WORD JOINER (Format_FE) × [9.0] SPACE (Sp) × [5.0] WORD JOINER (Format_FE) ÷ [11.0] LEFT PARENTHESIS (Close) × [5.0] WORD JOINER (Format_FE) × [12.0] LATIN CAPITAL LETTER H (Upper) × [5.0] WORD JOINER (Format_FE) × [12.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [12.0] SPACE (Sp) × [5.0] WORD JOINER (Format_FE) × [12.0] LATIN SMALL LETTER D (Lower) × [5.0] WORD JOINER (Format_FE) × [12.0] LATIN SMALL LETTER I (Lower) × [5.0] WORD JOINER (Format_FE) × [12.0] LATIN SMALL LETTER D (Lower) × [5.0] WORD JOINER (Format_FE) × [12.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [9.0] RIGHT PARENTHESIS (Close) × [5.0] WORD JOINER (Format_FE) × [5.0] WORD JOINER (Format_FE) ÷ [0.3] -÷ 2060 × 0055 × 2060 × 002E × 2060 × 0053 × 2060 × 002E × 2060 × 0041 × 2060 × 0300 × 002E × 2060 × 0020 × 2060 × 0069 × 2060 × 0073 × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) × [12.0] LATIN CAPITAL LETTER U (Upper) × [5.0] WORD JOINER (Format_FE) × [12.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [7.0] LATIN CAPITAL LETTER S (Upper) × [5.0] WORD JOINER (Format_FE) × [12.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [7.0] LATIN CAPITAL LETTER A (Upper) × [5.0] WORD JOINER (Format_FE) × [5.0] COMBINING GRAVE ACCENT (Extend_FE) × [12.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [8.0] SPACE (Sp) × [5.0] WORD JOINER (Format_FE) × [8.0] LATIN SMALL LETTER I (Lower) × [5.0] WORD JOINER (Format_FE) × [12.0] LATIN SMALL LETTER S (Lower) × [5.0] WORD JOINER (Format_FE) × [5.0] WORD JOINER (Format_FE) ÷ [0.3] -÷ 2060 × 0055 × 2060 × 002E × 2060 × 0053 × 2060 × 002E × 2060 × 0041 × 2060 × 0300 × 003F × 2060 × 0020 × 2060 ÷ 0048 × 2060 × 0065 × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) × [12.0] LATIN CAPITAL LETTER U (Upper) × [5.0] WORD JOINER (Format_FE) × [12.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [7.0] LATIN CAPITAL LETTER S (Upper) × [5.0] WORD JOINER (Format_FE) × [12.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [7.0] LATIN CAPITAL LETTER A (Upper) × [5.0] WORD JOINER (Format_FE) × [5.0] COMBINING GRAVE ACCENT (Extend_FE) × [12.0] QUESTION MARK (STerm) × [5.0] WORD JOINER (Format_FE) × [9.0] SPACE (Sp) × [5.0] WORD JOINER (Format_FE) ÷ [11.0] LATIN CAPITAL LETTER H (Upper) × [5.0] WORD JOINER (Format_FE) × [12.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [5.0] WORD JOINER (Format_FE) ÷ [0.3] -÷ 2060 × 0055 × 2060 × 002E × 2060 × 0053 × 2060 × 002E × 2060 × 0041 × 2060 × 0300 × 002E × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) × [12.0] LATIN CAPITAL LETTER U (Upper) × [5.0] WORD JOINER (Format_FE) × [12.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [7.0] LATIN CAPITAL LETTER S (Upper) × [5.0] WORD JOINER (Format_FE) × [12.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [7.0] LATIN CAPITAL LETTER A (Upper) × [5.0] WORD JOINER (Format_FE) × [5.0] COMBINING GRAVE ACCENT (Extend_FE) × [12.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [5.0] WORD JOINER (Format_FE) ÷ [0.3] -÷ 2060 × 0033 × 2060 × 002E × 2060 × 0034 × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) × [12.0] DIGIT THREE (Numeric) × [5.0] WORD JOINER (Format_FE) × [12.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [6.0] DIGIT FOUR (Numeric) × [5.0] WORD JOINER (Format_FE) × [5.0] WORD JOINER (Format_FE) ÷ [0.3] -÷ 2060 × 0063 × 2060 × 002E × 2060 × 0064 × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) × [12.0] LATIN SMALL LETTER C (Lower) × [5.0] WORD JOINER (Format_FE) × [12.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [8.0] LATIN SMALL LETTER D (Lower) × [5.0] WORD JOINER (Format_FE) × [5.0] WORD JOINER (Format_FE) ÷ [0.3] -÷ 2060 × 0043 × 2060 × 002E × 2060 × 0064 × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) × [12.0] LATIN CAPITAL LETTER C (Upper) × [5.0] WORD JOINER (Format_FE) × [12.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [8.0] LATIN SMALL LETTER D (Lower) × [5.0] WORD JOINER (Format_FE) × [5.0] WORD JOINER (Format_FE) ÷ [0.3] -÷ 2060 × 0063 × 2060 × 002E × 2060 × 0044 × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) × [12.0] LATIN SMALL LETTER C (Lower) × [5.0] WORD JOINER (Format_FE) × [12.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [7.0] LATIN CAPITAL LETTER D (Upper) × [5.0] WORD JOINER (Format_FE) × [5.0] WORD JOINER (Format_FE) ÷ [0.3] -÷ 2060 × 0043 × 2060 × 002E × 2060 × 0044 × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) × [12.0] LATIN CAPITAL LETTER C (Upper) × [5.0] WORD JOINER (Format_FE) × [12.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [7.0] LATIN CAPITAL LETTER D (Upper) × [5.0] WORD JOINER (Format_FE) × [5.0] WORD JOINER (Format_FE) ÷ [0.3] -÷ 2060 × 0065 × 2060 × 0074 × 2060 × 0063 × 2060 × 002E × 2060 × 0029 × 2060 × 2019 × 2060 × 00A0 × 2060 × 0074 × 2060 × 0068 × 2060 × 0065 × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) × [12.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [12.0] LATIN SMALL LETTER T (Lower) × [5.0] WORD JOINER (Format_FE) × [12.0] LATIN SMALL LETTER C (Lower) × [5.0] WORD JOINER (Format_FE) × [12.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [8.0] RIGHT PARENTHESIS (Close) × [5.0] WORD JOINER (Format_FE) × [8.0] RIGHT SINGLE QUOTATION MARK (Close) × [5.0] WORD JOINER (Format_FE) × [8.0] NO-BREAK SPACE (Sp) × [5.0] WORD JOINER (Format_FE) × [8.0] LATIN SMALL LETTER T (Lower) × [5.0] WORD JOINER (Format_FE) × [12.0] LATIN SMALL LETTER H (Lower) × [5.0] WORD JOINER (Format_FE) × [12.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [5.0] WORD JOINER (Format_FE) ÷ [0.3] -÷ 2060 × 0065 × 2060 × 0074 × 2060 × 0063 × 2060 × 002E × 2060 × 0029 × 2060 × 2019 × 2060 × 00A0 × 2060 ÷ 0054 × 2060 × 0068 × 2060 × 0065 × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) × [12.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [12.0] LATIN SMALL LETTER T (Lower) × [5.0] WORD JOINER (Format_FE) × [12.0] LATIN SMALL LETTER C (Lower) × [5.0] WORD JOINER (Format_FE) × [12.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [9.0] RIGHT PARENTHESIS (Close) × [5.0] WORD JOINER (Format_FE) × [9.0] RIGHT SINGLE QUOTATION MARK (Close) × [5.0] WORD JOINER (Format_FE) × [9.0] NO-BREAK SPACE (Sp) × [5.0] WORD JOINER (Format_FE) ÷ [11.0] LATIN CAPITAL LETTER T (Upper) × [5.0] WORD JOINER (Format_FE) × [12.0] LATIN SMALL LETTER H (Lower) × [5.0] WORD JOINER (Format_FE) × [12.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [5.0] WORD JOINER (Format_FE) ÷ [0.3] -÷ 2060 × 0065 × 2060 × 0074 × 2060 × 0063 × 2060 × 002E × 2060 × 0029 × 2060 × 2019 × 2060 × 00A0 × 2060 × 2018 × 2060 × 0028 × 2060 × 0074 × 2060 × 0068 × 2060 × 0065 × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) × [12.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [12.0] LATIN SMALL LETTER T (Lower) × [5.0] WORD JOINER (Format_FE) × [12.0] LATIN SMALL LETTER C (Lower) × [5.0] WORD JOINER (Format_FE) × [12.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [8.0] RIGHT PARENTHESIS (Close) × [5.0] WORD JOINER (Format_FE) × [8.0] RIGHT SINGLE QUOTATION MARK (Close) × [5.0] WORD JOINER (Format_FE) × [8.0] NO-BREAK SPACE (Sp) × [5.0] WORD JOINER (Format_FE) × [8.0] LEFT SINGLE QUOTATION MARK (Close) × [5.0] WORD JOINER (Format_FE) × [12.0] LEFT PARENTHESIS (Close) × [5.0] WORD JOINER (Format_FE) × [12.0] LATIN SMALL LETTER T (Lower) × [5.0] WORD JOINER (Format_FE) × [12.0] LATIN SMALL LETTER H (Lower) × [5.0] WORD JOINER (Format_FE) × [12.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [5.0] WORD JOINER (Format_FE) ÷ [0.3] -÷ 2060 × 0065 × 2060 × 0074 × 2060 × 0063 × 2060 × 002E × 2060 × 0029 × 2060 × 2019 × 2060 × 00A0 × 2060 ÷ 2018 × 2060 × 0028 × 2060 × 0054 × 2060 × 0068 × 2060 × 0065 × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) × [12.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [12.0] LATIN SMALL LETTER T (Lower) × [5.0] WORD JOINER (Format_FE) × [12.0] LATIN SMALL LETTER C (Lower) × [5.0] WORD JOINER (Format_FE) × [12.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [9.0] RIGHT PARENTHESIS (Close) × [5.0] WORD JOINER (Format_FE) × [9.0] RIGHT SINGLE QUOTATION MARK (Close) × [5.0] WORD JOINER (Format_FE) × [9.0] NO-BREAK SPACE (Sp) × [5.0] WORD JOINER (Format_FE) ÷ [11.0] LEFT SINGLE QUOTATION MARK (Close) × [5.0] WORD JOINER (Format_FE) × [12.0] LEFT PARENTHESIS (Close) × [5.0] WORD JOINER (Format_FE) × [12.0] LATIN CAPITAL LETTER T (Upper) × [5.0] WORD JOINER (Format_FE) × [12.0] LATIN SMALL LETTER H (Lower) × [5.0] WORD JOINER (Format_FE) × [12.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [5.0] WORD JOINER (Format_FE) ÷ [0.3] -÷ 2060 × 0065 × 2060 × 0074 × 2060 × 0063 × 2060 × 002E × 2060 × 0029 × 2060 × 2019 × 2060 × 00A0 × 2060 × 0308 × 0074 × 2060 × 0068 × 2060 × 0065 × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) × [12.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [12.0] LATIN SMALL LETTER T (Lower) × [5.0] WORD JOINER (Format_FE) × [12.0] LATIN SMALL LETTER C (Lower) × [5.0] WORD JOINER (Format_FE) × [12.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [8.0] RIGHT PARENTHESIS (Close) × [5.0] WORD JOINER (Format_FE) × [8.0] RIGHT SINGLE QUOTATION MARK (Close) × [5.0] WORD JOINER (Format_FE) × [8.0] NO-BREAK SPACE (Sp) × [5.0] WORD JOINER (Format_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [8.0] LATIN SMALL LETTER T (Lower) × [5.0] WORD JOINER (Format_FE) × [12.0] LATIN SMALL LETTER H (Lower) × [5.0] WORD JOINER (Format_FE) × [12.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [5.0] WORD JOINER (Format_FE) ÷ [0.3] -÷ 2060 × 0065 × 2060 × 0074 × 2060 × 0063 × 2060 × 002E × 2060 × 0029 × 2060 × 2019 × 2060 × 00A0 × 2060 × 0308 ÷ 0054 × 2060 × 0068 × 2060 × 0065 × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) × [12.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [12.0] LATIN SMALL LETTER T (Lower) × [5.0] WORD JOINER (Format_FE) × [12.0] LATIN SMALL LETTER C (Lower) × [5.0] WORD JOINER (Format_FE) × [12.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [9.0] RIGHT PARENTHESIS (Close) × [5.0] WORD JOINER (Format_FE) × [9.0] RIGHT SINGLE QUOTATION MARK (Close) × [5.0] WORD JOINER (Format_FE) × [9.0] NO-BREAK SPACE (Sp) × [5.0] WORD JOINER (Format_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) ÷ [11.0] LATIN CAPITAL LETTER T (Upper) × [5.0] WORD JOINER (Format_FE) × [12.0] LATIN SMALL LETTER H (Lower) × [5.0] WORD JOINER (Format_FE) × [12.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [5.0] WORD JOINER (Format_FE) ÷ [0.3] -÷ 2060 × 0065 × 2060 × 0074 × 2060 × 0063 × 2060 × 002E × 2060 × 0029 × 2060 × 2019 × 2060 × 0308 ÷ 0054 × 2060 × 0068 × 2060 × 0065 × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) × [12.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [12.0] LATIN SMALL LETTER T (Lower) × [5.0] WORD JOINER (Format_FE) × [12.0] LATIN SMALL LETTER C (Lower) × [5.0] WORD JOINER (Format_FE) × [12.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [9.0] RIGHT PARENTHESIS (Close) × [5.0] WORD JOINER (Format_FE) × [9.0] RIGHT SINGLE QUOTATION MARK (Close) × [5.0] WORD JOINER (Format_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) ÷ [11.0] LATIN CAPITAL LETTER T (Upper) × [5.0] WORD JOINER (Format_FE) × [12.0] LATIN SMALL LETTER H (Lower) × [5.0] WORD JOINER (Format_FE) × [12.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [5.0] WORD JOINER (Format_FE) ÷ [0.3] -÷ 2060 × 0065 × 2060 × 0074 × 2060 × 0063 × 2060 × 002E × 2060 × 0029 × 2060 × 000A ÷ 2060 × 0308 × 2060 × 0054 × 2060 × 0068 × 2060 × 0065 × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) × [12.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [12.0] LATIN SMALL LETTER T (Lower) × [5.0] WORD JOINER (Format_FE) × [12.0] LATIN SMALL LETTER C (Lower) × [5.0] WORD JOINER (Format_FE) × [12.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [9.0] RIGHT PARENTHESIS (Close) × [5.0] WORD JOINER (Format_FE) × [9.0] <LINE FEED (LF)> (LF) ÷ [4.0] WORD JOINER (Format_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [5.0] WORD JOINER (Format_FE) × [12.0] LATIN CAPITAL LETTER T (Upper) × [5.0] WORD JOINER (Format_FE) × [12.0] LATIN SMALL LETTER H (Lower) × [5.0] WORD JOINER (Format_FE) × [12.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [5.0] WORD JOINER (Format_FE) ÷ [0.3] -÷ 2060 × 0074 × 2060 × 0068 × 2060 × 0065 × 2060 × 0020 × 2060 × 0072 × 2060 × 0065 × 2060 × 0073 × 2060 × 0070 × 2060 × 002E × 2060 × 0020 × 2060 × 006C × 2060 × 0065 × 2060 × 0061 × 2060 × 0064 × 2060 × 0065 × 2060 × 0072 × 2060 × 0073 × 2060 × 0020 × 2060 × 0061 × 2060 × 0072 × 2060 × 0065 × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) × [12.0] LATIN SMALL LETTER T (Lower) × [5.0] WORD JOINER (Format_FE) × [12.0] LATIN SMALL LETTER H (Lower) × [5.0] WORD JOINER (Format_FE) × [12.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [12.0] SPACE (Sp) × [5.0] WORD JOINER (Format_FE) × [12.0] LATIN SMALL LETTER R (Lower) × [5.0] WORD JOINER (Format_FE) × [12.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [12.0] LATIN SMALL LETTER S (Lower) × [5.0] WORD JOINER (Format_FE) × [12.0] LATIN SMALL LETTER P (Lower) × [5.0] WORD JOINER (Format_FE) × [12.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [8.0] SPACE (Sp) × [5.0] WORD JOINER (Format_FE) × [8.0] LATIN SMALL LETTER L (Lower) × [5.0] WORD JOINER (Format_FE) × [12.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [12.0] LATIN SMALL LETTER A (Lower) × [5.0] WORD JOINER (Format_FE) × [12.0] LATIN SMALL LETTER D (Lower) × [5.0] WORD JOINER (Format_FE) × [12.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [12.0] LATIN SMALL LETTER R (Lower) × [5.0] WORD JOINER (Format_FE) × [12.0] LATIN SMALL LETTER S (Lower) × [5.0] WORD JOINER (Format_FE) × [12.0] SPACE (Sp) × [5.0] WORD JOINER (Format_FE) × [12.0] LATIN SMALL LETTER A (Lower) × [5.0] WORD JOINER (Format_FE) × [12.0] LATIN SMALL LETTER R (Lower) × [5.0] WORD JOINER (Format_FE) × [12.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [5.0] WORD JOINER (Format_FE) ÷ [0.3] -÷ 2060 × 5B57 × 2060 × 002E × 2060 ÷ 5B57 × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) × [12.0] CJK UNIFIED IDEOGRAPH-5B57 (OLetter) × [5.0] WORD JOINER (Format_FE) × [12.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) ÷ [11.0] CJK UNIFIED IDEOGRAPH-5B57 (OLetter) × [5.0] WORD JOINER (Format_FE) × [5.0] WORD JOINER (Format_FE) ÷ [0.3] -÷ 2060 × 0065 × 2060 × 0074 × 2060 × 0063 × 2060 × 002E × 2060 ÷ 5B83 × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) × [12.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [12.0] LATIN SMALL LETTER T (Lower) × [5.0] WORD JOINER (Format_FE) × [12.0] LATIN SMALL LETTER C (Lower) × [5.0] WORD JOINER (Format_FE) × [12.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) ÷ [11.0] CJK UNIFIED IDEOGRAPH-5B83 (OLetter) × [5.0] WORD JOINER (Format_FE) × [5.0] WORD JOINER (Format_FE) ÷ [0.3] -÷ 2060 × 0065 × 2060 × 0074 × 2060 × 0063 × 2060 × 002E × 2060 × 3002 × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) × [12.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [12.0] LATIN SMALL LETTER T (Lower) × [5.0] WORD JOINER (Format_FE) × [12.0] LATIN SMALL LETTER C (Lower) × [5.0] WORD JOINER (Format_FE) × [12.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [8.1] IDEOGRAPHIC FULL STOP (STerm) × [5.0] WORD JOINER (Format_FE) × [5.0] WORD JOINER (Format_FE) ÷ [0.3] -÷ 2060 × 5B57 × 2060 × 3002 × 2060 ÷ 5B83 × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) × [12.0] CJK UNIFIED IDEOGRAPH-5B57 (OLetter) × [5.0] WORD JOINER (Format_FE) × [12.0] IDEOGRAPHIC FULL STOP (STerm) × [5.0] WORD JOINER (Format_FE) ÷ [11.0] CJK UNIFIED IDEOGRAPH-5B83 (OLetter) × [5.0] WORD JOINER (Format_FE) × [5.0] WORD JOINER (Format_FE) ÷ [0.3] -÷ 2060 × 0021 × 2060 × 0020 × 2060 × 0020 × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) × [12.0] EXCLAMATION MARK (STerm) × [5.0] WORD JOINER (Format_FE) × [9.0] SPACE (Sp) × [5.0] WORD JOINER (Format_FE) × [10.0] SPACE (Sp) × [5.0] WORD JOINER (Format_FE) × [5.0] WORD JOINER (Format_FE) ÷ [0.3] -÷ 1F1E6 × 1F1E7 × 1F1E8 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (Other) × [12.0] REGIONAL INDICATOR SYMBOL LETTER B (Other) × [12.0] REGIONAL INDICATOR SYMBOL LETTER C (Other) ÷ [0.3] -÷ 1F1E6 × 200D × 1F1E7 × 1F1E8 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (Other) × [5.0] ZERO WIDTH JOINER (Extend_FE) × [12.0] REGIONAL INDICATOR SYMBOL LETTER B (Other) × [12.0] REGIONAL INDICATOR SYMBOL LETTER C (Other) ÷ [0.3] -÷ 1F1E6 × 1F1E7 × 200D × 1F1E8 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (Other) × [12.0] REGIONAL INDICATOR SYMBOL LETTER B (Other) × [5.0] ZERO WIDTH JOINER (Extend_FE) × [12.0] REGIONAL INDICATOR SYMBOL LETTER C (Other) ÷ [0.3] -÷ 0020 × 200D × 0646 ÷ # ÷ [0.2] SPACE (Sp) × [5.0] ZERO WIDTH JOINER (Extend_FE) × [12.0] ARABIC LETTER NOON (OLetter) ÷ [0.3] -÷ 0646 × 200D × 0020 ÷ # ÷ [0.2] ARABIC LETTER NOON (OLetter) × [5.0] ZERO WIDTH JOINER (Extend_FE) × [12.0] SPACE (Sp) ÷ [0.3] +÷ 2060 × 0028 × 2060 × 0022 × 2060 × 0047 × 2060 × 006F × 2060 × 002E × 2060 × 0022 × 2060 × 0029 × 2060 × 0020 × 2060 ÷ 0028 × 2060 × 0048 × 2060 × 0065 × 2060 × 0020 × 2060 × 0064 × 2060 × 0069 × 2060 × 0064 × 2060 × 002E × 2060 × 0029 × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) × [998.0] LEFT PARENTHESIS (Close) × [5.0] WORD JOINER (Format_FE) × [998.0] QUOTATION MARK (Close) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN CAPITAL LETTER G (Upper) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER O (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [9.0] QUOTATION MARK (Close) × [5.0] WORD JOINER (Format_FE) × [9.0] RIGHT PARENTHESIS (Close) × [5.0] WORD JOINER (Format_FE) × [9.0] SPACE (Sp) × [5.0] WORD JOINER (Format_FE) ÷ [11.0] LEFT PARENTHESIS (Close) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN CAPITAL LETTER H (Upper) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] SPACE (Sp) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER D (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER I (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER D (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [9.0] RIGHT PARENTHESIS (Close) × [5.0] WORD JOINER (Format_FE) × [5.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 2060 × 0028 × 2060 × 201C × 2060 × 0047 × 2060 × 006F × 2060 × 003F × 2060 × 201D × 2060 × 0029 × 2060 × 0020 × 2060 ÷ 0028 × 2060 × 0048 × 2060 × 0065 × 2060 × 0020 × 2060 × 0064 × 2060 × 0069 × 2060 × 0064 × 2060 × 002E × 2060 × 0029 × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) × [998.0] LEFT PARENTHESIS (Close) × [5.0] WORD JOINER (Format_FE) × [998.0] LEFT DOUBLE QUOTATION MARK (Close) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN CAPITAL LETTER G (Upper) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER O (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] QUESTION MARK (STerm) × [5.0] WORD JOINER (Format_FE) × [9.0] RIGHT DOUBLE QUOTATION MARK (Close) × [5.0] WORD JOINER (Format_FE) × [9.0] RIGHT PARENTHESIS (Close) × [5.0] WORD JOINER (Format_FE) × [9.0] SPACE (Sp) × [5.0] WORD JOINER (Format_FE) ÷ [11.0] LEFT PARENTHESIS (Close) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN CAPITAL LETTER H (Upper) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] SPACE (Sp) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER D (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER I (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER D (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [9.0] RIGHT PARENTHESIS (Close) × [5.0] WORD JOINER (Format_FE) × [5.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 2060 × 0055 × 2060 × 002E × 2060 × 0053 × 2060 × 002E × 2060 × 0041 × 2060 × 0300 × 002E × 2060 × 0020 × 2060 × 0069 × 2060 × 0073 × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) × [998.0] LATIN CAPITAL LETTER U (Upper) × [5.0] WORD JOINER (Format_FE) × [998.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [7.0] LATIN CAPITAL LETTER S (Upper) × [5.0] WORD JOINER (Format_FE) × [998.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [7.0] LATIN CAPITAL LETTER A (Upper) × [5.0] WORD JOINER (Format_FE) × [5.0] COMBINING GRAVE ACCENT (Extend_FE) × [998.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [8.0] SPACE (Sp) × [5.0] WORD JOINER (Format_FE) × [8.0] LATIN SMALL LETTER I (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER S (Lower) × [5.0] WORD JOINER (Format_FE) × [5.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 2060 × 0055 × 2060 × 002E × 2060 × 0053 × 2060 × 002E × 2060 × 0041 × 2060 × 0300 × 003F × 2060 × 0020 × 2060 ÷ 0048 × 2060 × 0065 × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) × [998.0] LATIN CAPITAL LETTER U (Upper) × [5.0] WORD JOINER (Format_FE) × [998.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [7.0] LATIN CAPITAL LETTER S (Upper) × [5.0] WORD JOINER (Format_FE) × [998.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [7.0] LATIN CAPITAL LETTER A (Upper) × [5.0] WORD JOINER (Format_FE) × [5.0] COMBINING GRAVE ACCENT (Extend_FE) × [998.0] QUESTION MARK (STerm) × [5.0] WORD JOINER (Format_FE) × [9.0] SPACE (Sp) × [5.0] WORD JOINER (Format_FE) ÷ [11.0] LATIN CAPITAL LETTER H (Upper) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [5.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 2060 × 0055 × 2060 × 002E × 2060 × 0053 × 2060 × 002E × 2060 × 0041 × 2060 × 0300 × 002E × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) × [998.0] LATIN CAPITAL LETTER U (Upper) × [5.0] WORD JOINER (Format_FE) × [998.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [7.0] LATIN CAPITAL LETTER S (Upper) × [5.0] WORD JOINER (Format_FE) × [998.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [7.0] LATIN CAPITAL LETTER A (Upper) × [5.0] WORD JOINER (Format_FE) × [5.0] COMBINING GRAVE ACCENT (Extend_FE) × [998.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [5.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 2060 × 0033 × 2060 × 002E × 2060 × 0034 × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) × [998.0] DIGIT THREE (Numeric) × [5.0] WORD JOINER (Format_FE) × [998.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [6.0] DIGIT FOUR (Numeric) × [5.0] WORD JOINER (Format_FE) × [5.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 2060 × 0063 × 2060 × 002E × 2060 × 0064 × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER C (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [8.0] LATIN SMALL LETTER D (Lower) × [5.0] WORD JOINER (Format_FE) × [5.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 2060 × 0043 × 2060 × 002E × 2060 × 0064 × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) × [998.0] LATIN CAPITAL LETTER C (Upper) × [5.0] WORD JOINER (Format_FE) × [998.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [8.0] LATIN SMALL LETTER D (Lower) × [5.0] WORD JOINER (Format_FE) × [5.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 2060 × 0063 × 2060 × 002E × 2060 × 0044 × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER C (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [7.0] LATIN CAPITAL LETTER D (Upper) × [5.0] WORD JOINER (Format_FE) × [5.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 2060 × 0043 × 2060 × 002E × 2060 × 0044 × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) × [998.0] LATIN CAPITAL LETTER C (Upper) × [5.0] WORD JOINER (Format_FE) × [998.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [7.0] LATIN CAPITAL LETTER D (Upper) × [5.0] WORD JOINER (Format_FE) × [5.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 2060 × 0065 × 2060 × 0074 × 2060 × 0063 × 2060 × 002E × 2060 × 0029 × 2060 × 2019 × 2060 × 00A0 × 2060 × 0074 × 2060 × 0068 × 2060 × 0065 × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER T (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER C (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [8.0] RIGHT PARENTHESIS (Close) × [5.0] WORD JOINER (Format_FE) × [8.0] RIGHT SINGLE QUOTATION MARK (Close) × [5.0] WORD JOINER (Format_FE) × [8.0] NO-BREAK SPACE (Sp) × [5.0] WORD JOINER (Format_FE) × [8.0] LATIN SMALL LETTER T (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER H (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [5.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 2060 × 0065 × 2060 × 0074 × 2060 × 0063 × 2060 × 002E × 2060 × 0029 × 2060 × 2019 × 2060 × 00A0 × 2060 ÷ 0054 × 2060 × 0068 × 2060 × 0065 × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER T (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER C (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [9.0] RIGHT PARENTHESIS (Close) × [5.0] WORD JOINER (Format_FE) × [9.0] RIGHT SINGLE QUOTATION MARK (Close) × [5.0] WORD JOINER (Format_FE) × [9.0] NO-BREAK SPACE (Sp) × [5.0] WORD JOINER (Format_FE) ÷ [11.0] LATIN CAPITAL LETTER T (Upper) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER H (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [5.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 2060 × 0065 × 2060 × 0074 × 2060 × 0063 × 2060 × 002E × 2060 × 0029 × 2060 × 2019 × 2060 × 00A0 × 2060 × 2018 × 2060 × 0028 × 2060 × 0074 × 2060 × 0068 × 2060 × 0065 × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER T (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER C (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [8.0] RIGHT PARENTHESIS (Close) × [5.0] WORD JOINER (Format_FE) × [8.0] RIGHT SINGLE QUOTATION MARK (Close) × [5.0] WORD JOINER (Format_FE) × [8.0] NO-BREAK SPACE (Sp) × [5.0] WORD JOINER (Format_FE) × [8.0] LEFT SINGLE QUOTATION MARK (Close) × [5.0] WORD JOINER (Format_FE) × [998.0] LEFT PARENTHESIS (Close) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER T (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER H (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [5.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 2060 × 0065 × 2060 × 0074 × 2060 × 0063 × 2060 × 002E × 2060 × 0029 × 2060 × 2019 × 2060 × 00A0 × 2060 ÷ 2018 × 2060 × 0028 × 2060 × 0054 × 2060 × 0068 × 2060 × 0065 × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER T (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER C (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [9.0] RIGHT PARENTHESIS (Close) × [5.0] WORD JOINER (Format_FE) × [9.0] RIGHT SINGLE QUOTATION MARK (Close) × [5.0] WORD JOINER (Format_FE) × [9.0] NO-BREAK SPACE (Sp) × [5.0] WORD JOINER (Format_FE) ÷ [11.0] LEFT SINGLE QUOTATION MARK (Close) × [5.0] WORD JOINER (Format_FE) × [998.0] LEFT PARENTHESIS (Close) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN CAPITAL LETTER T (Upper) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER H (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [5.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 2060 × 0065 × 2060 × 0074 × 2060 × 0063 × 2060 × 002E × 2060 × 0029 × 2060 × 2019 × 2060 × 00A0 × 2060 × 0308 × 0074 × 2060 × 0068 × 2060 × 0065 × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER T (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER C (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [8.0] RIGHT PARENTHESIS (Close) × [5.0] WORD JOINER (Format_FE) × [8.0] RIGHT SINGLE QUOTATION MARK (Close) × [5.0] WORD JOINER (Format_FE) × [8.0] NO-BREAK SPACE (Sp) × [5.0] WORD JOINER (Format_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [8.0] LATIN SMALL LETTER T (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER H (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [5.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 2060 × 0065 × 2060 × 0074 × 2060 × 0063 × 2060 × 002E × 2060 × 0029 × 2060 × 2019 × 2060 × 00A0 × 2060 × 0308 ÷ 0054 × 2060 × 0068 × 2060 × 0065 × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER T (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER C (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [9.0] RIGHT PARENTHESIS (Close) × [5.0] WORD JOINER (Format_FE) × [9.0] RIGHT SINGLE QUOTATION MARK (Close) × [5.0] WORD JOINER (Format_FE) × [9.0] NO-BREAK SPACE (Sp) × [5.0] WORD JOINER (Format_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) ÷ [11.0] LATIN CAPITAL LETTER T (Upper) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER H (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [5.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 2060 × 0065 × 2060 × 0074 × 2060 × 0063 × 2060 × 002E × 2060 × 0029 × 2060 × 2019 × 2060 × 0308 ÷ 0054 × 2060 × 0068 × 2060 × 0065 × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER T (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER C (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [9.0] RIGHT PARENTHESIS (Close) × [5.0] WORD JOINER (Format_FE) × [9.0] RIGHT SINGLE QUOTATION MARK (Close) × [5.0] WORD JOINER (Format_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) ÷ [11.0] LATIN CAPITAL LETTER T (Upper) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER H (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [5.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 2060 × 0065 × 2060 × 0074 × 2060 × 0063 × 2060 × 002E × 2060 × 0029 × 2060 × 000A ÷ 2060 × 0308 × 2060 × 0054 × 2060 × 0068 × 2060 × 0065 × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER T (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER C (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [9.0] RIGHT PARENTHESIS (Close) × [5.0] WORD JOINER (Format_FE) × [9.0] <LINE FEED (LF)> (LF) ÷ [4.0] WORD JOINER (Format_FE) × [5.0] COMBINING DIAERESIS (Extend_FE) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN CAPITAL LETTER T (Upper) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER H (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [5.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 2060 × 0074 × 2060 × 0068 × 2060 × 0065 × 2060 × 0020 × 2060 × 0072 × 2060 × 0065 × 2060 × 0073 × 2060 × 0070 × 2060 × 002E × 2060 × 0020 × 2060 × 006C × 2060 × 0065 × 2060 × 0061 × 2060 × 0064 × 2060 × 0065 × 2060 × 0072 × 2060 × 0073 × 2060 × 0020 × 2060 × 0061 × 2060 × 0072 × 2060 × 0065 × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER T (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER H (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] SPACE (Sp) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER R (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER S (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER P (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [8.0] SPACE (Sp) × [5.0] WORD JOINER (Format_FE) × [8.0] LATIN SMALL LETTER L (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER A (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER D (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER R (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER S (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] SPACE (Sp) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER A (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER R (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [5.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 2060 × 5B57 × 2060 × 002E × 2060 ÷ 5B57 × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) × [998.0] CJK UNIFIED IDEOGRAPH-5B57 (OLetter) × [5.0] WORD JOINER (Format_FE) × [998.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) ÷ [11.0] CJK UNIFIED IDEOGRAPH-5B57 (OLetter) × [5.0] WORD JOINER (Format_FE) × [5.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 2060 × 0065 × 2060 × 0074 × 2060 × 0063 × 2060 × 002E × 2060 ÷ 5B83 × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER T (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER C (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) ÷ [11.0] CJK UNIFIED IDEOGRAPH-5B83 (OLetter) × [5.0] WORD JOINER (Format_FE) × [5.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 2060 × 0065 × 2060 × 0074 × 2060 × 0063 × 2060 × 002E × 2060 × 3002 × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER E (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER T (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] LATIN SMALL LETTER C (Lower) × [5.0] WORD JOINER (Format_FE) × [998.0] FULL STOP (ATerm) × [5.0] WORD JOINER (Format_FE) × [8.1] IDEOGRAPHIC FULL STOP (STerm) × [5.0] WORD JOINER (Format_FE) × [5.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 2060 × 5B57 × 2060 × 3002 × 2060 ÷ 5B83 × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) × [998.0] CJK UNIFIED IDEOGRAPH-5B57 (OLetter) × [5.0] WORD JOINER (Format_FE) × [998.0] IDEOGRAPHIC FULL STOP (STerm) × [5.0] WORD JOINER (Format_FE) ÷ [11.0] CJK UNIFIED IDEOGRAPH-5B83 (OLetter) × [5.0] WORD JOINER (Format_FE) × [5.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 2060 × 0021 × 2060 × 0020 × 2060 × 0020 × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) × [998.0] EXCLAMATION MARK (STerm) × [5.0] WORD JOINER (Format_FE) × [9.0] SPACE (Sp) × [5.0] WORD JOINER (Format_FE) × [10.0] SPACE (Sp) × [5.0] WORD JOINER (Format_FE) × [5.0] WORD JOINER (Format_FE) ÷ [0.3] # -# Lines: 503 +# Lines: 502 # # EOF diff --git a/tests/data/WordBreakProperty.txt b/tests/data/WordBreakProperty.txt index dc8e82020f..4c5440a894 100644 --- a/tests/data/WordBreakProperty.txt +++ b/tests/data/WordBreakProperty.txt @@ -1,10 +1,11 @@ -# WordBreakProperty-8.0.0.txt -# Date: 2015-02-14, 10:26:15 GMT [MD] +# WordBreakProperty-10.0.0.txt +# Date: 2017-03-10, 02:00:42 GMT +# © 2017 Unicode®, Inc. +# Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries. +# For terms of use, see http://www.unicode.org/terms_of_use.html # # Unicode Character Database -# Copyright (c) 1991-2015 Unicode, Inc. -# For terms of use, see http://www.unicode.org/terms_of_use.html -# For documentation, see http://www.unicode.org/reports/tr44/ +# For documentation, see http://www.unicode.org/reports/tr44/ # ================================================ @@ -89,6 +90,7 @@ FB46..FB4F ; Hebrew_Letter # Lo [10] HEBREW LETTER TSADI WITH DAGESH..HEBREW 0825..0827 ; Extend # Mn [3] SAMARITAN VOWEL SIGN SHORT A..SAMARITAN VOWEL SIGN U 0829..082D ; Extend # Mn [5] SAMARITAN VOWEL SIGN LONG I..SAMARITAN MARK NEQUDAA 0859..085B ; Extend # Mn [3] MANDAIC AFFRICATION MARK..MANDAIC GEMINATION MARK +08D4..08E1 ; Extend # Mn [14] ARABIC SMALL HIGH WORD AR-RUB..ARABIC SMALL HIGH SIGN SAFHA 08E3..0902 ; Extend # Mn [32] ARABIC TURNED DAMMA BELOW..DEVANAGARI SIGN ANUSVARA 0903 ; Extend # Mc DEVANAGARI SIGN VISARGA 093A ; Extend # Mn DEVANAGARI VOWEL SIGN OE @@ -131,6 +133,7 @@ FB46..FB4F ; Hebrew_Letter # Lo [10] HEBREW LETTER TSADI WITH DAGESH..HEBREW 0ACB..0ACC ; Extend # Mc [2] GUJARATI VOWEL SIGN O..GUJARATI VOWEL SIGN AU 0ACD ; Extend # Mn GUJARATI SIGN VIRAMA 0AE2..0AE3 ; Extend # Mn [2] GUJARATI VOWEL SIGN VOCALIC L..GUJARATI VOWEL SIGN VOCALIC LL +0AFA..0AFF ; Extend # Mn [6] GUJARATI SIGN SUKUN..GUJARATI SIGN TWO-CIRCLE NUKTA ABOVE 0B01 ; Extend # Mn ORIYA SIGN CANDRABINDU 0B02..0B03 ; Extend # Mc [2] ORIYA SIGN ANUSVARA..ORIYA SIGN VISARGA 0B3C ; Extend # Mn ORIYA SIGN NUKTA @@ -172,8 +175,9 @@ FB46..FB4F ; Hebrew_Letter # Lo [10] HEBREW LETTER TSADI WITH DAGESH..HEBREW 0CCC..0CCD ; Extend # Mn [2] KANNADA VOWEL SIGN AU..KANNADA SIGN VIRAMA 0CD5..0CD6 ; Extend # Mc [2] KANNADA LENGTH MARK..KANNADA AI LENGTH MARK 0CE2..0CE3 ; Extend # Mn [2] KANNADA VOWEL SIGN VOCALIC L..KANNADA VOWEL SIGN VOCALIC LL -0D01 ; Extend # Mn MALAYALAM SIGN CANDRABINDU +0D00..0D01 ; Extend # Mn [2] MALAYALAM SIGN COMBINING ANUSVARA ABOVE..MALAYALAM SIGN CANDRABINDU 0D02..0D03 ; Extend # Mc [2] MALAYALAM SIGN ANUSVARA..MALAYALAM SIGN VISARGA +0D3B..0D3C ; Extend # Mn [2] MALAYALAM SIGN VERTICAL BAR VIRAMA..MALAYALAM SIGN CIRCULAR VIRAMA 0D3E..0D40 ; Extend # Mc [3] MALAYALAM VOWEL SIGN AA..MALAYALAM VOWEL SIGN II 0D41..0D44 ; Extend # Mn [4] MALAYALAM VOWEL SIGN U..MALAYALAM VOWEL SIGN VOCALIC RR 0D46..0D48 ; Extend # Mc [3] MALAYALAM VOWEL SIGN E..MALAYALAM VOWEL SIGN AI @@ -243,6 +247,7 @@ FB46..FB4F ; Hebrew_Letter # Lo [10] HEBREW LETTER TSADI WITH DAGESH..HEBREW 17C9..17D3 ; Extend # Mn [11] KHMER SIGN MUUSIKATOAN..KHMER SIGN BATHAMASAT 17DD ; Extend # Mn KHMER SIGN ATTHACAN 180B..180D ; Extend # Mn [3] MONGOLIAN FREE VARIATION SELECTOR ONE..MONGOLIAN FREE VARIATION SELECTOR THREE +1885..1886 ; Extend # Mn [2] MONGOLIAN LETTER ALI GALI BALUDA..MONGOLIAN LETTER ALI GALI THREE BALUDA 18A9 ; Extend # Mn MONGOLIAN LETTER ALI GALI DAGALGA 1920..1922 ; Extend # Mn [3] LIMBU VOWEL SIGN A..LIMBU VOWEL SIGN U 1923..1926 ; Extend # Mc [4] LIMBU VOWEL SIGN EE..LIMBU VOWEL SIGN AU @@ -307,10 +312,11 @@ FB46..FB4F ; Hebrew_Letter # Lo [10] HEBREW LETTER TSADI WITH DAGESH..HEBREW 1CED ; Extend # Mn VEDIC SIGN TIRYAK 1CF2..1CF3 ; Extend # Mc [2] VEDIC SIGN ARDHAVISARGA..VEDIC SIGN ROTATED ARDHAVISARGA 1CF4 ; Extend # Mn VEDIC TONE CANDRA ABOVE +1CF7 ; Extend # Mc VEDIC SIGN ATIKRAMA 1CF8..1CF9 ; Extend # Mn [2] VEDIC TONE RING ABOVE..VEDIC TONE DOUBLE RING ABOVE -1DC0..1DF5 ; Extend # Mn [54] COMBINING DOTTED GRAVE ACCENT..COMBINING UP TACK ABOVE -1DFC..1DFF ; Extend # Mn [4] COMBINING DOUBLE INVERTED BREVE BELOW..COMBINING RIGHT ARROWHEAD AND DOWN ARROWHEAD BELOW -200C..200D ; Extend # Cf [2] ZERO WIDTH NON-JOINER..ZERO WIDTH JOINER +1DC0..1DF9 ; Extend # Mn [58] COMBINING DOTTED GRAVE ACCENT..COMBINING WIDE INVERTED BRIDGE BELOW +1DFB..1DFF ; Extend # Mn [5] COMBINING DELETION MARK..COMBINING RIGHT ARROWHEAD AND DOWN ARROWHEAD BELOW +200C ; Extend # Cf ZERO WIDTH NON-JOINER 20D0..20DC ; Extend # Mn [13] COMBINING LEFT HARPOON ABOVE..COMBINING FOUR DOTS ABOVE 20DD..20E0 ; Extend # Me [4] COMBINING ENCLOSING CIRCLE..COMBINING ENCLOSING CIRCLE BACKSLASH 20E1 ; Extend # Mn COMBINING LEFT RIGHT ARROW ABOVE @@ -335,7 +341,7 @@ A825..A826 ; Extend # Mn [2] SYLOTI NAGRI VOWEL SIGN U..SYLOTI NAGRI VOWEL A827 ; Extend # Mc SYLOTI NAGRI VOWEL SIGN OO A880..A881 ; Extend # Mc [2] SAURASHTRA SIGN ANUSVARA..SAURASHTRA SIGN VISARGA A8B4..A8C3 ; Extend # Mc [16] SAURASHTRA CONSONANT SIGN HAARU..SAURASHTRA VOWEL SIGN AU -A8C4 ; Extend # Mn SAURASHTRA SIGN VIRAMA +A8C4..A8C5 ; Extend # Mn [2] SAURASHTRA SIGN VIRAMA..SAURASHTRA SIGN CANDRABINDU A8E0..A8F1 ; Extend # Mn [18] COMBINING DEVANAGARI DIGIT ZERO..COMBINING DEVANAGARI SIGN AVAGRAHA A926..A92D ; Extend # Mn [8] KAYAH LI VOWEL UE..KAYAH LI TONE CALYA PLOPHU A947..A951 ; Extend # Mn [11] REJANG VOWEL SIGN I..REJANG CONSONANT SIGN R @@ -417,6 +423,7 @@ FF9E..FF9F ; Extend # Lm [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDT 11234 ; Extend # Mn KHOJKI SIGN ANUSVARA 11235 ; Extend # Mc KHOJKI SIGN VIRAMA 11236..11237 ; Extend # Mn [2] KHOJKI SIGN NUKTA..KHOJKI SIGN SHADDA +1123E ; Extend # Mn KHOJKI SIGN SUKUN 112DF ; Extend # Mn KHUDAWADI SIGN ANUSVARA 112E0..112E2 ; Extend # Mc [3] KHUDAWADI VOWEL SIGN AA..KHUDAWADI VOWEL SIGN II 112E3..112EA ; Extend # Mn [8] KHUDAWADI VOWEL SIGN U..KHUDAWADI SIGN VIRAMA @@ -432,6 +439,12 @@ FF9E..FF9F ; Extend # Lm [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDT 11362..11363 ; Extend # Mc [2] GRANTHA VOWEL SIGN VOCALIC L..GRANTHA VOWEL SIGN VOCALIC LL 11366..1136C ; Extend # Mn [7] COMBINING GRANTHA DIGIT ZERO..COMBINING GRANTHA DIGIT SIX 11370..11374 ; Extend # Mn [5] COMBINING GRANTHA LETTER A..COMBINING GRANTHA LETTER PA +11435..11437 ; Extend # Mc [3] NEWA VOWEL SIGN AA..NEWA VOWEL SIGN II +11438..1143F ; Extend # Mn [8] NEWA VOWEL SIGN U..NEWA VOWEL SIGN AI +11440..11441 ; Extend # Mc [2] NEWA VOWEL SIGN O..NEWA VOWEL SIGN AU +11442..11444 ; Extend # Mn [3] NEWA SIGN VIRAMA..NEWA SIGN ANUSVARA +11445 ; Extend # Mc NEWA SIGN VISARGA +11446 ; Extend # Mn NEWA SIGN NUKTA 114B0..114B2 ; Extend # Mc [3] TIRHUTA VOWEL SIGN AA..TIRHUTA VOWEL SIGN II 114B3..114B8 ; Extend # Mn [6] TIRHUTA VOWEL SIGN U..TIRHUTA VOWEL SIGN VOCALIC LL 114B9 ; Extend # Mc TIRHUTA VOWEL SIGN E @@ -465,6 +478,36 @@ FF9E..FF9F ; Extend # Lm [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDT 11722..11725 ; Extend # Mn [4] AHOM VOWEL SIGN I..AHOM VOWEL SIGN UU 11726 ; Extend # Mc AHOM VOWEL SIGN E 11727..1172B ; Extend # Mn [5] AHOM VOWEL SIGN AW..AHOM SIGN KILLER +11A01..11A06 ; Extend # Mn [6] ZANABAZAR SQUARE VOWEL SIGN I..ZANABAZAR SQUARE VOWEL SIGN O +11A07..11A08 ; Extend # Mc [2] ZANABAZAR SQUARE VOWEL SIGN AI..ZANABAZAR SQUARE VOWEL SIGN AU +11A09..11A0A ; Extend # Mn [2] ZANABAZAR SQUARE VOWEL SIGN REVERSED I..ZANABAZAR SQUARE VOWEL LENGTH MARK +11A33..11A38 ; Extend # Mn [6] ZANABAZAR SQUARE FINAL CONSONANT MARK..ZANABAZAR SQUARE SIGN ANUSVARA +11A39 ; Extend # Mc ZANABAZAR SQUARE SIGN VISARGA +11A3B..11A3E ; Extend # Mn [4] ZANABAZAR SQUARE CLUSTER-FINAL LETTER YA..ZANABAZAR SQUARE CLUSTER-FINAL LETTER VA +11A47 ; Extend # Mn ZANABAZAR SQUARE SUBJOINER +11A51..11A56 ; Extend # Mn [6] SOYOMBO VOWEL SIGN I..SOYOMBO VOWEL SIGN OE +11A57..11A58 ; Extend # Mc [2] SOYOMBO VOWEL SIGN AI..SOYOMBO VOWEL SIGN AU +11A59..11A5B ; Extend # Mn [3] SOYOMBO VOWEL SIGN VOCALIC R..SOYOMBO VOWEL LENGTH MARK +11A8A..11A96 ; Extend # Mn [13] SOYOMBO FINAL CONSONANT SIGN G..SOYOMBO SIGN ANUSVARA +11A97 ; Extend # Mc SOYOMBO SIGN VISARGA +11A98..11A99 ; Extend # Mn [2] SOYOMBO GEMINATION MARK..SOYOMBO SUBJOINER +11C2F ; Extend # Mc BHAIKSUKI VOWEL SIGN AA +11C30..11C36 ; Extend # Mn [7] BHAIKSUKI VOWEL SIGN I..BHAIKSUKI VOWEL SIGN VOCALIC L +11C38..11C3D ; Extend # Mn [6] BHAIKSUKI VOWEL SIGN E..BHAIKSUKI SIGN ANUSVARA +11C3E ; Extend # Mc BHAIKSUKI SIGN VISARGA +11C3F ; Extend # Mn BHAIKSUKI SIGN VIRAMA +11C92..11CA7 ; Extend # Mn [22] MARCHEN SUBJOINED LETTER KA..MARCHEN SUBJOINED LETTER ZA +11CA9 ; Extend # Mc MARCHEN SUBJOINED LETTER YA +11CAA..11CB0 ; Extend # Mn [7] MARCHEN SUBJOINED LETTER RA..MARCHEN VOWEL SIGN AA +11CB1 ; Extend # Mc MARCHEN VOWEL SIGN I +11CB2..11CB3 ; Extend # Mn [2] MARCHEN VOWEL SIGN U..MARCHEN VOWEL SIGN E +11CB4 ; Extend # Mc MARCHEN VOWEL SIGN O +11CB5..11CB6 ; Extend # Mn [2] MARCHEN SIGN ANUSVARA..MARCHEN SIGN CANDRABINDU +11D31..11D36 ; Extend # Mn [6] MASARAM GONDI VOWEL SIGN AA..MASARAM GONDI VOWEL SIGN VOCALIC R +11D3A ; Extend # Mn MASARAM GONDI VOWEL SIGN E +11D3C..11D3D ; Extend # Mn [2] MASARAM GONDI VOWEL SIGN AI..MASARAM GONDI VOWEL SIGN O +11D3F..11D45 ; Extend # Mn [7] MASARAM GONDI VOWEL SIGN AU..MASARAM GONDI VIRAMA +11D47 ; Extend # Mn MASARAM GONDI RA-KARA 16AF0..16AF4 ; Extend # Mn [5] BASSA VAH COMBINING HIGH TONE..BASSA VAH COMBINING HIGH-LOW TONE 16B30..16B36 ; Extend # Mn [7] PAHAWH HMONG MARK CIM TUB..PAHAWH HMONG MARK CIM TAUM 16F51..16F7E ; Extend # Mc [46] MIAO SIGN ASPIRATION..MIAO VOWEL SIGN NG @@ -483,10 +526,17 @@ FF9E..FF9F ; Extend # Lm [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDT 1DA84 ; Extend # Mn SIGNWRITING LOCATION HEAD NECK 1DA9B..1DA9F ; Extend # Mn [5] SIGNWRITING FILL MODIFIER-2..SIGNWRITING FILL MODIFIER-6 1DAA1..1DAAF ; Extend # Mn [15] SIGNWRITING ROTATION MODIFIER-2..SIGNWRITING ROTATION MODIFIER-16 +1E000..1E006 ; Extend # Mn [7] COMBINING GLAGOLITIC LETTER AZU..COMBINING GLAGOLITIC LETTER ZHIVETE +1E008..1E018 ; Extend # Mn [17] COMBINING GLAGOLITIC LETTER ZEMLJA..COMBINING GLAGOLITIC LETTER HERU +1E01B..1E021 ; Extend # Mn [7] COMBINING GLAGOLITIC LETTER SHTA..COMBINING GLAGOLITIC LETTER YATI +1E023..1E024 ; Extend # Mn [2] COMBINING GLAGOLITIC LETTER YU..COMBINING GLAGOLITIC LETTER SMALL YUS +1E026..1E02A ; Extend # Mn [5] COMBINING GLAGOLITIC LETTER YO..COMBINING GLAGOLITIC LETTER FITA 1E8D0..1E8D6 ; Extend # Mn [7] MENDE KIKAKUI COMBINING NUMBER TEENS..MENDE KIKAKUI COMBINING NUMBER MILLIONS +1E944..1E94A ; Extend # Mn [7] ADLAM ALIF LENGTHENER..ADLAM NUKTA +E0020..E007F ; Extend # Cf [96] TAG SPACE..CANCEL TAG E0100..E01EF ; Extend # Mn [240] VARIATION SELECTOR-17..VARIATION SELECTOR-256 -# Total code points: 1967 +# Total code points: 2276 # ================================================ @@ -501,6 +551,7 @@ E0100..E01EF ; Extend # Mn [240] VARIATION SELECTOR-17..VARIATION SELECTOR-256 061C ; Format # Cf ARABIC LETTER MARK 06DD ; Format # Cf ARABIC END OF AYAH 070F ; Format # Cf SYRIAC ABBREVIATION MARK +08E2 ; Format # Cf ARABIC DISPUTED END OF AYAH 180E ; Format # Cf MONGOLIAN VOWEL SEPARATOR 200E..200F ; Format # Cf [2] LEFT-TO-RIGHT MARK..RIGHT-TO-LEFT MARK 202A..202E ; Format # Cf [5] LEFT-TO-RIGHT EMBEDDING..RIGHT-TO-LEFT OVERRIDE @@ -512,9 +563,8 @@ FFF9..FFFB ; Format # Cf [3] INTERLINEAR ANNOTATION ANCHOR..INTERLINEAR ANN 1BCA0..1BCA3 ; Format # Cf [4] SHORTHAND FORMAT LETTER OVERLAP..SHORTHAND FORMAT UP STEP 1D173..1D17A ; Format # Cf [8] MUSICAL SYMBOL BEGIN BEAM..MUSICAL SYMBOL END PHRASE E0001 ; Format # Cf LANGUAGE TAG -E0020..E007F ; Format # Cf [96] TAG SPACE..CANCEL TAG -# Total code points: 147 +# Total code points: 52 # ================================================ @@ -551,10 +601,15 @@ FF71..FF9D ; Katakana # Lo [45] HALFWIDTH KATAKANA LETTER A..HALFWIDTH KATAK 0294 ; ALetter # Lo LATIN LETTER GLOTTAL STOP 0295..02AF ; ALetter # L& [27] LATIN LETTER PHARYNGEAL VOICED FRICATIVE..LATIN SMALL LETTER TURNED H WITH FISHHOOK AND TAIL 02B0..02C1 ; ALetter # Lm [18] MODIFIER LETTER SMALL H..MODIFIER LETTER REVERSED GLOTTAL STOP +02C2..02C5 ; ALetter # Sk [4] MODIFIER LETTER LEFT ARROWHEAD..MODIFIER LETTER DOWN ARROWHEAD 02C6..02D1 ; ALetter # Lm [12] MODIFIER LETTER CIRCUMFLEX ACCENT..MODIFIER LETTER HALF TRIANGULAR COLON +02D2..02D7 ; ALetter # Sk [6] MODIFIER LETTER CENTRED RIGHT HALF RING..MODIFIER LETTER MINUS SIGN +02DE..02DF ; ALetter # Sk [2] MODIFIER LETTER RHOTIC HOOK..MODIFIER LETTER CROSS ACCENT 02E0..02E4 ; ALetter # Lm [5] MODIFIER LETTER SMALL GAMMA..MODIFIER LETTER SMALL REVERSED GLOTTAL STOP 02EC ; ALetter # Lm MODIFIER LETTER VOICING +02ED ; ALetter # Sk MODIFIER LETTER UNASPIRATED 02EE ; ALetter # Lm MODIFIER LETTER DOUBLE APOSTROPHE +02EF..02FF ; ALetter # Sk [17] MODIFIER LETTER LOW DOWN ARROWHEAD..MODIFIER LETTER LOW LEFT ARROW 0370..0373 ; ALetter # L& [4] GREEK CAPITAL LETTER HETA..GREEK SMALL LETTER ARCHAIC SAMPI 0374 ; ALetter # Lm GREEK NUMERAL SIGN 0376..0377 ; ALetter # L& [2] GREEK CAPITAL LETTER PAMPHYLIAN DIGAMMA..GREEK SMALL LETTER PAMPHYLIAN DIGAMMA @@ -594,7 +649,9 @@ FF71..FF9D ; Katakana # Lo [45] HALFWIDTH KATAKANA LETTER A..HALFWIDTH KATAK 0824 ; ALetter # Lm SAMARITAN MODIFIER LETTER SHORT A 0828 ; ALetter # Lm SAMARITAN MODIFIER LETTER I 0840..0858 ; ALetter # Lo [25] MANDAIC LETTER HALQA..MANDAIC LETTER AIN +0860..086A ; ALetter # Lo [11] SYRIAC LETTER MALAYALAM NGA..SYRIAC LETTER MALAYALAM SSA 08A0..08B4 ; ALetter # Lo [21] ARABIC LETTER BEH WITH SMALL V BELOW..ARABIC LETTER KAF WITH DOT BELOW +08B6..08BD ; ALetter # Lo [8] ARABIC LETTER BEH WITH SMALL MEEM ABOVE..ARABIC LETTER AFRICAN NOON 0904..0939 ; ALetter # Lo [54] DEVANAGARI LETTER SHORT A..DEVANAGARI LETTER HA 093D ; ALetter # Lo DEVANAGARI SIGN AVAGRAHA 0950 ; ALetter # Lo DEVANAGARI OM @@ -612,6 +669,7 @@ FF71..FF9D ; Katakana # Lo [45] HALFWIDTH KATAKANA LETTER A..HALFWIDTH KATAK 09DC..09DD ; ALetter # Lo [2] BENGALI LETTER RRA..BENGALI LETTER RHA 09DF..09E1 ; ALetter # Lo [3] BENGALI LETTER YYA..BENGALI LETTER VOCALIC LL 09F0..09F1 ; ALetter # Lo [2] BENGALI LETTER RA WITH MIDDLE DIAGONAL..BENGALI LETTER RA WITH LOWER DIAGONAL +09FC ; ALetter # Lo BENGALI LETTER VEDIC ANUSVARA 0A05..0A0A ; ALetter # Lo [6] GURMUKHI LETTER A..GURMUKHI LETTER UU 0A0F..0A10 ; ALetter # Lo [2] GURMUKHI LETTER EE..GURMUKHI LETTER AI 0A13..0A28 ; ALetter # Lo [22] GURMUKHI LETTER OO..GURMUKHI LETTER NA @@ -660,6 +718,7 @@ FF71..FF9D ; Katakana # Lo [45] HALFWIDTH KATAKANA LETTER A..HALFWIDTH KATAK 0C3D ; ALetter # Lo TELUGU SIGN AVAGRAHA 0C58..0C5A ; ALetter # Lo [3] TELUGU LETTER TSA..TELUGU LETTER RRRA 0C60..0C61 ; ALetter # Lo [2] TELUGU LETTER VOCALIC RR..TELUGU LETTER VOCALIC LL +0C80 ; ALetter # Lo KANNADA SIGN SPACING CANDRABINDU 0C85..0C8C ; ALetter # Lo [8] KANNADA LETTER A..KANNADA LETTER VOCALIC L 0C8E..0C90 ; ALetter # Lo [3] KANNADA LETTER E..KANNADA LETTER AI 0C92..0CA8 ; ALetter # Lo [23] KANNADA LETTER O..KANNADA LETTER NA @@ -674,6 +733,7 @@ FF71..FF9D ; Katakana # Lo [45] HALFWIDTH KATAKANA LETTER A..HALFWIDTH KATAK 0D12..0D3A ; ALetter # Lo [41] MALAYALAM LETTER O..MALAYALAM LETTER TTTA 0D3D ; ALetter # Lo MALAYALAM SIGN AVAGRAHA 0D4E ; ALetter # Lo MALAYALAM LETTER DOT REPH +0D54..0D56 ; ALetter # Lo [3] MALAYALAM LETTER CHILLU M..MALAYALAM LETTER CHILLU LLL 0D5F..0D61 ; ALetter # Lo [3] MALAYALAM LETTER ARCHAIC II..MALAYALAM LETTER VOCALIC LL 0D7A..0D7F ; ALetter # Lo [6] MALAYALAM LETTER CHILLU NN..MALAYALAM LETTER CHILLU K 0D85..0D96 ; ALetter # Lo [18] SINHALA LETTER AYANNA..SINHALA LETTER AUYANNA @@ -724,7 +784,8 @@ FF71..FF9D ; Katakana # Lo [45] HALFWIDTH KATAKANA LETTER A..HALFWIDTH KATAK 1820..1842 ; ALetter # Lo [35] MONGOLIAN LETTER A..MONGOLIAN LETTER CHI 1843 ; ALetter # Lm MONGOLIAN LETTER TODO LONG VOWEL SIGN 1844..1877 ; ALetter # Lo [52] MONGOLIAN LETTER TODO E..MONGOLIAN LETTER MANCHU ZHA -1880..18A8 ; ALetter # Lo [41] MONGOLIAN LETTER ALI GALI ANUSVARA ONE..MONGOLIAN LETTER MANCHU ALI GALI BHA +1880..1884 ; ALetter # Lo [5] MONGOLIAN LETTER ALI GALI ANUSVARA ONE..MONGOLIAN LETTER ALI GALI INVERTED UBADAMA +1887..18A8 ; ALetter # Lo [34] MONGOLIAN LETTER ALI GALI A..MONGOLIAN LETTER MANCHU ALI GALI BHA 18AA ; ALetter # Lo MONGOLIAN LETTER MANCHU ALI GALI LHA 18B0..18F5 ; ALetter # Lo [70] CANADIAN SYLLABICS OY..CANADIAN SYLLABICS CARRIER DENTAL S 1900..191E ; ALetter # Lo [31] LIMBU VOWEL-CARRIER LETTER..LIMBU LETTER TRA @@ -738,6 +799,7 @@ FF71..FF9D ; Katakana # Lo [45] HALFWIDTH KATAKANA LETTER A..HALFWIDTH KATAK 1C4D..1C4F ; ALetter # Lo [3] LEPCHA LETTER TTA..LEPCHA LETTER DDA 1C5A..1C77 ; ALetter # Lo [30] OL CHIKI LETTER LA..OL CHIKI LETTER OH 1C78..1C7D ; ALetter # Lm [6] OL CHIKI MU TTUDDAG..OL CHIKI AHAD +1C80..1C88 ; ALetter # L& [9] CYRILLIC SMALL LETTER ROUNDED VE..CYRILLIC SMALL LETTER UNBLENDED UK 1CE9..1CEC ; ALetter # Lo [4] VEDIC SIGN ANUSVARA ANTARGOMUKHA..VEDIC SIGN ANUSVARA VAMAGOMUKHA WITH TAIL 1CEE..1CF1 ; ALetter # Lo [4] VEDIC SIGN HEXIFORM LONG ANUSVARA..VEDIC SIGN ANUSVARA UBHAYATO MUKHA 1CF5..1CF6 ; ALetter # Lo [2] VEDIC SIGN JIHVAMULIYA..VEDIC SIGN UPADHMANIYA @@ -813,7 +875,7 @@ FF71..FF9D ; Katakana # Lo [45] HALFWIDTH KATAKANA LETTER A..HALFWIDTH KATAK 3005 ; ALetter # Lm IDEOGRAPHIC ITERATION MARK 303B ; ALetter # Lm VERTICAL IDEOGRAPHIC ITERATION MARK 303C ; ALetter # Lo MASU MARK -3105..312D ; ALetter # Lo [41] BOPOMOFO LETTER B..BOPOMOFO LETTER IH +3105..312E ; ALetter # Lo [42] BOPOMOFO LETTER B..BOPOMOFO LETTER O WITH DOT ABOVE 3131..318E ; ALetter # Lo [94] HANGUL LETTER KIYEOK..HANGUL LETTER ARAEAE 31A0..31BA ; ALetter # Lo [27] BOPOMOFO LETTER BU..BOPOMOFO LETTER ZY A000..A014 ; ALetter # Lo [21] YI SYLLABLE IT..YI SYLLABLE E @@ -833,13 +895,15 @@ A69C..A69D ; ALetter # Lm [2] MODIFIER LETTER CYRILLIC HARD SIGN..MODIFIER A6A0..A6E5 ; ALetter # Lo [70] BAMUM LETTER A..BAMUM LETTER KI A6E6..A6EF ; ALetter # Nl [10] BAMUM LETTER MO..BAMUM LETTER KOGHOM A717..A71F ; ALetter # Lm [9] MODIFIER LETTER DOT VERTICAL BAR..MODIFIER LETTER LOW INVERTED EXCLAMATION MARK +A720..A721 ; ALetter # Sk [2] MODIFIER LETTER STRESS AND HIGH TONE..MODIFIER LETTER STRESS AND LOW TONE A722..A76F ; ALetter # L& [78] LATIN CAPITAL LETTER EGYPTOLOGICAL ALEF..LATIN SMALL LETTER CON A770 ; ALetter # Lm MODIFIER LETTER US A771..A787 ; ALetter # L& [23] LATIN SMALL LETTER DUM..LATIN SMALL LETTER INSULAR T A788 ; ALetter # Lm MODIFIER LETTER LOW CIRCUMFLEX ACCENT +A789..A78A ; ALetter # Sk [2] MODIFIER LETTER COLON..MODIFIER LETTER SHORT EQUALS SIGN A78B..A78E ; ALetter # L& [4] LATIN CAPITAL LETTER SALTILLO..LATIN SMALL LETTER L WITH RETROFLEX HOOK AND BELT A78F ; ALetter # Lo LATIN LETTER SINOLOGICAL DOT -A790..A7AD ; ALetter # L& [30] LATIN CAPITAL LETTER N WITH DESCENDER..LATIN CAPITAL LETTER L WITH BELT +A790..A7AE ; ALetter # L& [31] LATIN CAPITAL LETTER N WITH DESCENDER..LATIN CAPITAL LETTER SMALL CAPITAL I A7B0..A7B7 ; ALetter # L& [8] LATIN CAPITAL LETTER TURNED K..LATIN SMALL LETTER OMEGA A7F7 ; ALetter # Lo LATIN EPIGRAPHIC LETTER SIDEWAYS I A7F8..A7F9 ; ALetter # Lm [2] MODIFIER LETTER CAPITAL H WITH STROKE..MODIFIER LETTER SMALL LIGATURE OE @@ -870,6 +934,7 @@ AB11..AB16 ; ALetter # Lo [6] ETHIOPIC SYLLABLE DZU..ETHIOPIC SYLLABLE DZO AB20..AB26 ; ALetter # Lo [7] ETHIOPIC SYLLABLE CCHHA..ETHIOPIC SYLLABLE CCHHO AB28..AB2E ; ALetter # Lo [7] ETHIOPIC SYLLABLE BBA..ETHIOPIC SYLLABLE BBO AB30..AB5A ; ALetter # L& [43] LATIN SMALL LETTER BARRED ALPHA..LATIN SMALL LETTER Y WITH SHORT RIGHT LEG +AB5B ; ALetter # Sk MODIFIER BREVE WITH INVERTED BREVE AB5C..AB5F ; ALetter # Lm [4] MODIFIER LETTER SMALL HENG..MODIFIER LETTER SMALL U WITH LEFT HOOK AB60..AB65 ; ALetter # L& [6] LATIN SMALL LETTER SAKHA YAT..GREEK LETTER SMALL CAPITAL OMEGA AB70..ABBF ; ALetter # L& [80] CHEROKEE SMALL LETTER A..CHEROKEE SMALL LETTER YA @@ -904,7 +969,7 @@ FFDA..FFDC ; ALetter # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGUL 10280..1029C ; ALetter # Lo [29] LYCIAN LETTER A..LYCIAN LETTER X 102A0..102D0 ; ALetter # Lo [49] CARIAN LETTER A..CARIAN LETTER UUU3 10300..1031F ; ALetter # Lo [32] OLD ITALIC LETTER A..OLD ITALIC LETTER ESS -10330..10340 ; ALetter # Lo [17] GOTHIC LETTER AHSA..GOTHIC LETTER PAIRTHRA +1032D..10340 ; ALetter # Lo [20] OLD ITALIC LETTER YE..GOTHIC LETTER PAIRTHRA 10341 ; ALetter # Nl GOTHIC LETTER NINETY 10342..10349 ; ALetter # Lo [8] GOTHIC LETTER RAIDA..GOTHIC LETTER OTHAL 1034A ; ALetter # Nl GOTHIC LETTER NINE HUNDRED @@ -915,6 +980,8 @@ FFDA..FFDC ; ALetter # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGUL 103D1..103D5 ; ALetter # Nl [5] OLD PERSIAN NUMBER ONE..OLD PERSIAN NUMBER HUNDRED 10400..1044F ; ALetter # L& [80] DESERET CAPITAL LETTER LONG I..DESERET SMALL LETTER EW 10450..1049D ; ALetter # Lo [78] SHAVIAN LETTER PEEP..OSMANYA LETTER OO +104B0..104D3 ; ALetter # L& [36] OSAGE CAPITAL LETTER A..OSAGE CAPITAL LETTER ZHA +104D8..104FB ; ALetter # L& [36] OSAGE SMALL LETTER A..OSAGE SMALL LETTER ZHA 10500..10527 ; ALetter # Lo [40] ELBASAN LETTER A..ELBASAN LETTER KHE 10530..10563 ; ALetter # Lo [52] CAUCASIAN ALBANIAN LETTER ALT..CAUCASIAN ALBANIAN LETTER KIW 10600..10736 ; ALetter # Lo [311] LINEAR A SIGN AB001..LINEAR A SIGN A664 @@ -976,6 +1043,8 @@ FFDA..FFDC ; ALetter # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGUL 1133D ; ALetter # Lo GRANTHA SIGN AVAGRAHA 11350 ; ALetter # Lo GRANTHA OM 1135D..11361 ; ALetter # Lo [5] GRANTHA SIGN PLUTA..GRANTHA LETTER VOCALIC LL +11400..11434 ; ALetter # Lo [53] NEWA LETTER A..NEWA LETTER HA +11447..1144A ; ALetter # Lo [4] NEWA SIGN AVAGRAHA..NEWA SIDDHI 11480..114AF ; ALetter # Lo [48] TIRHUTA ANJI..TIRHUTA LETTER HA 114C4..114C5 ; ALetter # Lo [2] TIRHUTA SIGN AVAGRAHA..TIRHUTA GVANG 114C7 ; ALetter # Lo TIRHUTA OM @@ -986,7 +1055,21 @@ FFDA..FFDC ; ALetter # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGUL 11680..116AA ; ALetter # Lo [43] TAKRI LETTER A..TAKRI LETTER RRA 118A0..118DF ; ALetter # L& [64] WARANG CITI CAPITAL LETTER NGAA..WARANG CITI SMALL LETTER VIYO 118FF ; ALetter # Lo WARANG CITI OM +11A00 ; ALetter # Lo ZANABAZAR SQUARE LETTER A +11A0B..11A32 ; ALetter # Lo [40] ZANABAZAR SQUARE LETTER KA..ZANABAZAR SQUARE LETTER KSSA +11A3A ; ALetter # Lo ZANABAZAR SQUARE CLUSTER-INITIAL LETTER RA +11A50 ; ALetter # Lo SOYOMBO LETTER A +11A5C..11A83 ; ALetter # Lo [40] SOYOMBO LETTER KA..SOYOMBO LETTER KSSA +11A86..11A89 ; ALetter # Lo [4] SOYOMBO CLUSTER-INITIAL LETTER RA..SOYOMBO CLUSTER-INITIAL LETTER SA 11AC0..11AF8 ; ALetter # Lo [57] PAU CIN HAU LETTER PA..PAU CIN HAU GLOTTAL STOP FINAL +11C00..11C08 ; ALetter # Lo [9] BHAIKSUKI LETTER A..BHAIKSUKI LETTER VOCALIC L +11C0A..11C2E ; ALetter # Lo [37] BHAIKSUKI LETTER E..BHAIKSUKI LETTER HA +11C40 ; ALetter # Lo BHAIKSUKI SIGN AVAGRAHA +11C72..11C8F ; ALetter # Lo [30] MARCHEN LETTER KA..MARCHEN LETTER A +11D00..11D06 ; ALetter # Lo [7] MASARAM GONDI LETTER A..MASARAM GONDI LETTER E +11D08..11D09 ; ALetter # Lo [2] MASARAM GONDI LETTER AI..MASARAM GONDI LETTER O +11D0B..11D30 ; ALetter # Lo [38] MASARAM GONDI LETTER AU..MASARAM GONDI LETTER TRA +11D46 ; ALetter # Lo MASARAM GONDI REPHA 12000..12399 ; ALetter # Lo [922] CUNEIFORM SIGN A..CUNEIFORM SIGN U U 12400..1246E ; ALetter # Nl [111] CUNEIFORM NUMERIC SIGN TWO ASH..CUNEIFORM NUMERIC SIGN NINE U VARIANT FORM 12480..12543 ; ALetter # Lo [196] CUNEIFORM SIGN AB TIMES NUN TENU..CUNEIFORM SIGN ZU5 TIMES THREE DISH TENU @@ -1002,6 +1085,7 @@ FFDA..FFDC ; ALetter # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGUL 16F00..16F44 ; ALetter # Lo [69] MIAO LETTER PA..MIAO LETTER HHA 16F50 ; ALetter # Lo MIAO LETTER NASALIZATION 16F93..16F9F ; ALetter # Lm [13] MIAO LETTER TONE-2..MIAO LETTER REFORMED TONE-8 +16FE0..16FE1 ; ALetter # Lm [2] TANGUT ITERATION MARK..NUSHU ITERATION MARK 1BC00..1BC6A ; ALetter # Lo [107] DUPLOYAN LETTER H..DUPLOYAN LETTER VOCALIC M 1BC70..1BC7C ; ALetter # Lo [13] DUPLOYAN AFFIX LEFT HORIZONTAL SECANT..DUPLOYAN AFFIX ATTACHED TANGENT HOOK 1BC80..1BC88 ; ALetter # Lo [9] DUPLOYAN AFFIX HIGH ACUTE..DUPLOYAN AFFIX HIGH VERTICAL @@ -1037,6 +1121,7 @@ FFDA..FFDC ; ALetter # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGUL 1D7AA..1D7C2 ; ALetter # L& [25] MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL ALPHA..MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL OMEGA 1D7C4..1D7CB ; ALetter # L& [8] MATHEMATICAL SANS-SERIF BOLD ITALIC EPSILON SYMBOL..MATHEMATICAL BOLD SMALL DIGAMMA 1E800..1E8C4 ; ALetter # Lo [197] MENDE KIKAKUI SYLLABLE M001 KI..MENDE KIKAKUI SYLLABLE M060 NYON +1E900..1E943 ; ALetter # L& [68] ADLAM CAPITAL LETTER ALIF..ADLAM SMALL LETTER SHA 1EE00..1EE03 ; ALetter # Lo [4] ARABIC MATHEMATICAL ALEF..ARABIC MATHEMATICAL DAL 1EE05..1EE1F ; ALetter # Lo [27] ARABIC MATHEMATICAL WAW..ARABIC MATHEMATICAL DOTLESS QAF 1EE21..1EE22 ; ALetter # Lo [2] ARABIC MATHEMATICAL INITIAL BEH..ARABIC MATHEMATICAL INITIAL JEEM @@ -1074,13 +1159,12 @@ FFDA..FFDC ; ALetter # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGUL 1F150..1F169 ; ALetter # So [26] NEGATIVE CIRCLED LATIN CAPITAL LETTER A..NEGATIVE CIRCLED LATIN CAPITAL LETTER Z 1F170..1F189 ; ALetter # So [26] NEGATIVE SQUARED LATIN CAPITAL LETTER A..NEGATIVE SQUARED LATIN CAPITAL LETTER Z -# Total code points: 27697 +# Total code points: 28179 # ================================================ 003A ; MidLetter # Po COLON 00B7 ; MidLetter # Po MIDDLE DOT -02D7 ; MidLetter # Sk MODIFIER LETTER MINUS SIGN 0387 ; MidLetter # Po GREEK ANO TELEIA 05F4 ; MidLetter # Po HEBREW PUNCTUATION GERSHAYIM 2027 ; MidLetter # Po HYPHENATION POINT @@ -1088,7 +1172,7 @@ FE13 ; MidLetter # Po PRESENTATION FORM FOR VERTICAL COLON FE55 ; MidLetter # Po SMALL COLON FF1A ; MidLetter # Po FULLWIDTH COLON -# Total code points: 9 +# Total code points: 8 # ================================================ @@ -1166,26 +1250,110 @@ ABF0..ABF9 ; Numeric # Nd [10] MEETEI MAYEK DIGIT ZERO..MEETEI MAYEK DIGIT N 11136..1113F ; Numeric # Nd [10] CHAKMA DIGIT ZERO..CHAKMA DIGIT NINE 111D0..111D9 ; Numeric # Nd [10] SHARADA DIGIT ZERO..SHARADA DIGIT NINE 112F0..112F9 ; Numeric # Nd [10] KHUDAWADI DIGIT ZERO..KHUDAWADI DIGIT NINE +11450..11459 ; Numeric # Nd [10] NEWA DIGIT ZERO..NEWA DIGIT NINE 114D0..114D9 ; Numeric # Nd [10] TIRHUTA DIGIT ZERO..TIRHUTA DIGIT NINE 11650..11659 ; Numeric # Nd [10] MODI DIGIT ZERO..MODI DIGIT NINE 116C0..116C9 ; Numeric # Nd [10] TAKRI DIGIT ZERO..TAKRI DIGIT NINE 11730..11739 ; Numeric # Nd [10] AHOM DIGIT ZERO..AHOM DIGIT NINE 118E0..118E9 ; Numeric # Nd [10] WARANG CITI DIGIT ZERO..WARANG CITI DIGIT NINE +11C50..11C59 ; Numeric # Nd [10] BHAIKSUKI DIGIT ZERO..BHAIKSUKI DIGIT NINE +11D50..11D59 ; Numeric # Nd [10] MASARAM GONDI DIGIT ZERO..MASARAM GONDI DIGIT NINE 16A60..16A69 ; Numeric # Nd [10] MRO DIGIT ZERO..MRO DIGIT NINE 16B50..16B59 ; Numeric # Nd [10] PAHAWH HMONG DIGIT ZERO..PAHAWH HMONG DIGIT NINE 1D7CE..1D7FF ; Numeric # Nd [50] MATHEMATICAL BOLD DIGIT ZERO..MATHEMATICAL MONOSPACE DIGIT NINE +1E950..1E959 ; Numeric # Nd [10] ADLAM DIGIT ZERO..ADLAM DIGIT NINE -# Total code points: 541 +# Total code points: 581 # ================================================ 005F ; ExtendNumLet # Pc LOW LINE +202F ; ExtendNumLet # Zs NARROW NO-BREAK SPACE 203F..2040 ; ExtendNumLet # Pc [2] UNDERTIE..CHARACTER TIE 2054 ; ExtendNumLet # Pc INVERTED UNDERTIE FE33..FE34 ; ExtendNumLet # Pc [2] PRESENTATION FORM FOR VERTICAL LOW LINE..PRESENTATION FORM FOR VERTICAL WAVY LOW LINE FE4D..FE4F ; ExtendNumLet # Pc [3] DASHED LOW LINE..WAVY LOW LINE FF3F ; ExtendNumLet # Pc FULLWIDTH LOW LINE -# Total code points: 10 +# Total code points: 11 + +# ================================================ + +261D ; E_Base # So WHITE UP POINTING INDEX +26F9 ; E_Base # So PERSON WITH BALL +270A..270D ; E_Base # So [4] RAISED FIST..WRITING HAND +1F385 ; E_Base # So FATHER CHRISTMAS +1F3C2..1F3C4 ; E_Base # So [3] SNOWBOARDER..SURFER +1F3C7 ; E_Base # So HORSE RACING +1F3CA..1F3CC ; E_Base # So [3] SWIMMER..GOLFER +1F442..1F443 ; E_Base # So [2] EAR..NOSE +1F446..1F450 ; E_Base # So [11] WHITE UP POINTING BACKHAND INDEX..OPEN HANDS SIGN +1F46E ; E_Base # So POLICE OFFICER +1F470..1F478 ; E_Base # So [9] BRIDE WITH VEIL..PRINCESS +1F47C ; E_Base # So BABY ANGEL +1F481..1F483 ; E_Base # So [3] INFORMATION DESK PERSON..DANCER +1F485..1F487 ; E_Base # So [3] NAIL POLISH..HAIRCUT +1F4AA ; E_Base # So FLEXED BICEPS +1F574..1F575 ; E_Base # So [2] MAN IN BUSINESS SUIT LEVITATING..SLEUTH OR SPY +1F57A ; E_Base # So MAN DANCING +1F590 ; E_Base # So RAISED HAND WITH FINGERS SPLAYED +1F595..1F596 ; E_Base # So [2] REVERSED HAND WITH MIDDLE FINGER EXTENDED..RAISED HAND WITH PART BETWEEN MIDDLE AND RING FINGERS +1F645..1F647 ; E_Base # So [3] FACE WITH NO GOOD GESTURE..PERSON BOWING DEEPLY +1F64B..1F64F ; E_Base # So [5] HAPPY PERSON RAISING ONE HAND..PERSON WITH FOLDED HANDS +1F6A3 ; E_Base # So ROWBOAT +1F6B4..1F6B6 ; E_Base # So [3] BICYCLIST..PEDESTRIAN +1F6C0 ; E_Base # So BATH +1F6CC ; E_Base # So SLEEPING ACCOMMODATION +1F918..1F91C ; E_Base # So [5] SIGN OF THE HORNS..RIGHT-FACING FIST +1F91E..1F91F ; E_Base # So [2] HAND WITH INDEX AND MIDDLE FINGERS CROSSED..I LOVE YOU HAND SIGN +1F926 ; E_Base # So FACE PALM +1F930..1F939 ; E_Base # So [10] PREGNANT WOMAN..JUGGLING +1F93D..1F93E ; E_Base # So [2] WATER POLO..HANDBALL +1F9D1..1F9DD ; E_Base # So [13] ADULT..ELF + +# Total code points: 98 + +# ================================================ + +1F3FB..1F3FF ; E_Modifier # Sk [5] EMOJI MODIFIER FITZPATRICK TYPE-1-2..EMOJI MODIFIER FITZPATRICK TYPE-6 + +# Total code points: 5 + +# ================================================ + +200D ; ZWJ # Cf ZERO WIDTH JOINER + +# Total code points: 1 + +# ================================================ + +2640 ; Glue_After_Zwj # So FEMALE SIGN +2642 ; Glue_After_Zwj # So MALE SIGN +2695..2696 ; Glue_After_Zwj # So [2] STAFF OF AESCULAPIUS..SCALES +2708 ; Glue_After_Zwj # So AIRPLANE +2764 ; Glue_After_Zwj # So HEAVY BLACK HEART +1F308 ; Glue_After_Zwj # So RAINBOW +1F33E ; Glue_After_Zwj # So EAR OF RICE +1F373 ; Glue_After_Zwj # So COOKING +1F393 ; Glue_After_Zwj # So GRADUATION CAP +1F3A4 ; Glue_After_Zwj # So MICROPHONE +1F3A8 ; Glue_After_Zwj # So ARTIST PALETTE +1F3EB ; Glue_After_Zwj # So SCHOOL +1F3ED ; Glue_After_Zwj # So FACTORY +1F48B ; Glue_After_Zwj # So KISS MARK +1F4BB..1F4BC ; Glue_After_Zwj # So [2] PERSONAL COMPUTER..BRIEFCASE +1F527 ; Glue_After_Zwj # So WRENCH +1F52C ; Glue_After_Zwj # So MICROSCOPE +1F5E8 ; Glue_After_Zwj # So LEFT SPEECH BUBBLE +1F680 ; Glue_After_Zwj # So ROCKET +1F692 ; Glue_After_Zwj # So FIRE ENGINE + +# Total code points: 22 + +# ================================================ + +1F466..1F469 ; E_Base_GAZ # So [4] BOY..WOMAN + +# Total code points: 4 # EOF diff --git a/tests/data/WordBreakTest.txt b/tests/data/WordBreakTest.txt index 7e163f1e41..63761026ce 100644 --- a/tests/data/WordBreakTest.txt +++ b/tests/data/WordBreakTest.txt @@ -1,22 +1,24 @@ -# WordBreakTest-8.0.0.txt -# Date: 2015-05-02, 14:48:55 GMT [MD] +# WordBreakTest-10.0.0.txt +# Date: 2017-04-14, 05:40:44 GMT +# © 2017 Unicode®, Inc. +# Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries. +# For terms of use, see http://www.unicode.org/terms_of_use.html # # Unicode Character Database -# Copyright (c) 1991-2015 Unicode, Inc. -# For terms of use, see http://www.unicode.org/terms_of_use.html -# For documentation, see http://www.unicode.org/reports/tr44/ +# For documentation, see http://www.unicode.org/reports/tr44/ # -# Default Word Break Test +# Default Word_Break Test # # Format: -# <string> (# <comment>)? -# <string> contains hex Unicode code points, with -# ÷ wherever there is a break opportunity, and +# <string> (# <comment>)? +# <string> contains hex Unicode code points, with +# ÷ wherever there is a break opportunity, and # × wherever there is not. # <comment> the format can change, but currently it shows: # - the sample character name # - (x) the Word_Break property value for the sample character -# - [x] the rule that determines whether there is a break or not +# - [x] the rule that determines whether there is a break or not, +# as listed in the Rules section of WordBreakTest.html # # These samples may be extended or changed in the future. # @@ -42,18 +44,28 @@ ÷ 0001 × 0308 ÷ 0030 ÷ # ÷ [0.2] <START OF HEADING> (Other) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] ÷ 0001 ÷ 005F ÷ # ÷ [0.2] <START OF HEADING> (Other) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] ÷ 0001 × 0308 ÷ 005F ÷ # ÷ [0.2] <START OF HEADING> (Other) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] -÷ 0001 ÷ 1F1E6 ÷ # ÷ [0.2] <START OF HEADING> (Other) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [0.3] -÷ 0001 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] <START OF HEADING> (Other) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [0.3] +÷ 0001 ÷ 1F1E6 ÷ # ÷ [0.2] <START OF HEADING> (Other) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0001 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] <START OF HEADING> (Other) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ 0001 ÷ 05D0 ÷ # ÷ [0.2] <START OF HEADING> (Other) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] ÷ 0001 × 0308 ÷ 05D0 ÷ # ÷ [0.2] <START OF HEADING> (Other) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] ÷ 0001 ÷ 0022 ÷ # ÷ [0.2] <START OF HEADING> (Other) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] ÷ 0001 × 0308 ÷ 0022 ÷ # ÷ [0.2] <START OF HEADING> (Other) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] ÷ 0001 ÷ 0027 ÷ # ÷ [0.2] <START OF HEADING> (Other) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] ÷ 0001 × 0308 ÷ 0027 ÷ # ÷ [0.2] <START OF HEADING> (Other) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0001 ÷ 261D ÷ # ÷ [0.2] <START OF HEADING> (Other) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ 0001 × 0308 ÷ 261D ÷ # ÷ [0.2] <START OF HEADING> (Other) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ 0001 ÷ 1F3FB ÷ # ÷ [0.2] <START OF HEADING> (Other) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ 0001 × 0308 ÷ 1F3FB ÷ # ÷ [0.2] <START OF HEADING> (Other) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ 0001 ÷ 2640 ÷ # ÷ [0.2] <START OF HEADING> (Other) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ 0001 × 0308 ÷ 2640 ÷ # ÷ [0.2] <START OF HEADING> (Other) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ 0001 ÷ 1F466 ÷ # ÷ [0.2] <START OF HEADING> (Other) ÷ [999.0] BOY (EBG) ÷ [0.3] +÷ 0001 × 0308 ÷ 1F466 ÷ # ÷ [0.2] <START OF HEADING> (Other) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] BOY (EBG) ÷ [0.3] ÷ 0001 × 00AD ÷ # ÷ [0.2] <START OF HEADING> (Other) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] ÷ 0001 × 0308 × 00AD ÷ # ÷ [0.2] <START OF HEADING> (Other) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] ÷ 0001 × 0300 ÷ # ÷ [0.2] <START OF HEADING> (Other) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] ÷ 0001 × 0308 × 0300 ÷ # ÷ [0.2] <START OF HEADING> (Other) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0001 × 200D ÷ # ÷ [0.2] <START OF HEADING> (Other) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 0001 × 0308 × 200D ÷ # ÷ [0.2] <START OF HEADING> (Other) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] ÷ 0001 ÷ 0061 × 2060 ÷ # ÷ [0.2] <START OF HEADING> (Other) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] ÷ 0001 × 0308 ÷ 0061 × 2060 ÷ # ÷ [0.2] <START OF HEADING> (Other) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] ÷ 0001 ÷ 0061 ÷ 003A ÷ # ÷ [0.2] <START OF HEADING> (Other) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] @@ -94,18 +106,28 @@ ÷ 000D ÷ 0308 ÷ 0030 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] ÷ 000D ÷ 005F ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [3.1] LOW LINE (ExtendNumLet) ÷ [0.3] ÷ 000D ÷ 0308 ÷ 005F ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] -÷ 000D ÷ 1F1E6 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [3.1] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [0.3] -÷ 000D ÷ 0308 ÷ 1F1E6 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [0.3] +÷ 000D ÷ 1F1E6 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [3.1] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 000D ÷ 0308 ÷ 1F1E6 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ 000D ÷ 05D0 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [3.1] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] ÷ 000D ÷ 0308 ÷ 05D0 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] ÷ 000D ÷ 0022 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [3.1] QUOTATION MARK (Double_Quote) ÷ [0.3] ÷ 000D ÷ 0308 ÷ 0022 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] ÷ 000D ÷ 0027 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [3.1] APOSTROPHE (Single_Quote) ÷ [0.3] ÷ 000D ÷ 0308 ÷ 0027 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 000D ÷ 261D ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [3.1] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ 000D ÷ 0308 ÷ 261D ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ 000D ÷ 1F3FB ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [3.1] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ 000D ÷ 0308 ÷ 1F3FB ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ 000D ÷ 2640 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [3.1] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ 000D ÷ 0308 ÷ 2640 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ 000D ÷ 1F466 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [3.1] BOY (EBG) ÷ [0.3] +÷ 000D ÷ 0308 ÷ 1F466 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] BOY (EBG) ÷ [0.3] ÷ 000D ÷ 00AD ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [3.1] SOFT HYPHEN (Format_FE) ÷ [0.3] ÷ 000D ÷ 0308 × 00AD ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] ÷ 000D ÷ 0300 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [3.1] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] ÷ 000D ÷ 0308 × 0300 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 000D ÷ 200D ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [3.1] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 000D ÷ 0308 × 200D ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] ÷ 000D ÷ 0061 × 2060 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [3.1] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] ÷ 000D ÷ 0308 ÷ 0061 × 2060 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] ÷ 000D ÷ 0061 ÷ 003A ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [3.1] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] @@ -146,18 +168,28 @@ ÷ 000A ÷ 0308 ÷ 0030 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] ÷ 000A ÷ 005F ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [3.1] LOW LINE (ExtendNumLet) ÷ [0.3] ÷ 000A ÷ 0308 ÷ 005F ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] -÷ 000A ÷ 1F1E6 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [3.1] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [0.3] -÷ 000A ÷ 0308 ÷ 1F1E6 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [0.3] +÷ 000A ÷ 1F1E6 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [3.1] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 000A ÷ 0308 ÷ 1F1E6 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ 000A ÷ 05D0 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [3.1] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] ÷ 000A ÷ 0308 ÷ 05D0 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] ÷ 000A ÷ 0022 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [3.1] QUOTATION MARK (Double_Quote) ÷ [0.3] ÷ 000A ÷ 0308 ÷ 0022 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] ÷ 000A ÷ 0027 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [3.1] APOSTROPHE (Single_Quote) ÷ [0.3] ÷ 000A ÷ 0308 ÷ 0027 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 000A ÷ 261D ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [3.1] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ 000A ÷ 0308 ÷ 261D ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ 000A ÷ 1F3FB ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [3.1] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ 000A ÷ 0308 ÷ 1F3FB ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ 000A ÷ 2640 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [3.1] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ 000A ÷ 0308 ÷ 2640 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ 000A ÷ 1F466 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [3.1] BOY (EBG) ÷ [0.3] +÷ 000A ÷ 0308 ÷ 1F466 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] BOY (EBG) ÷ [0.3] ÷ 000A ÷ 00AD ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [3.1] SOFT HYPHEN (Format_FE) ÷ [0.3] ÷ 000A ÷ 0308 × 00AD ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] ÷ 000A ÷ 0300 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [3.1] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] ÷ 000A ÷ 0308 × 0300 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 000A ÷ 200D ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [3.1] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 000A ÷ 0308 × 200D ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] ÷ 000A ÷ 0061 × 2060 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [3.1] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] ÷ 000A ÷ 0308 ÷ 0061 × 2060 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] ÷ 000A ÷ 0061 ÷ 003A ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [3.1] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] @@ -198,18 +230,28 @@ ÷ 000B ÷ 0308 ÷ 0030 ÷ # ÷ [0.2] <LINE TABULATION> (Newline) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] ÷ 000B ÷ 005F ÷ # ÷ [0.2] <LINE TABULATION> (Newline) ÷ [3.1] LOW LINE (ExtendNumLet) ÷ [0.3] ÷ 000B ÷ 0308 ÷ 005F ÷ # ÷ [0.2] <LINE TABULATION> (Newline) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] -÷ 000B ÷ 1F1E6 ÷ # ÷ [0.2] <LINE TABULATION> (Newline) ÷ [3.1] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [0.3] -÷ 000B ÷ 0308 ÷ 1F1E6 ÷ # ÷ [0.2] <LINE TABULATION> (Newline) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [0.3] +÷ 000B ÷ 1F1E6 ÷ # ÷ [0.2] <LINE TABULATION> (Newline) ÷ [3.1] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 000B ÷ 0308 ÷ 1F1E6 ÷ # ÷ [0.2] <LINE TABULATION> (Newline) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ 000B ÷ 05D0 ÷ # ÷ [0.2] <LINE TABULATION> (Newline) ÷ [3.1] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] ÷ 000B ÷ 0308 ÷ 05D0 ÷ # ÷ [0.2] <LINE TABULATION> (Newline) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] ÷ 000B ÷ 0022 ÷ # ÷ [0.2] <LINE TABULATION> (Newline) ÷ [3.1] QUOTATION MARK (Double_Quote) ÷ [0.3] ÷ 000B ÷ 0308 ÷ 0022 ÷ # ÷ [0.2] <LINE TABULATION> (Newline) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] ÷ 000B ÷ 0027 ÷ # ÷ [0.2] <LINE TABULATION> (Newline) ÷ [3.1] APOSTROPHE (Single_Quote) ÷ [0.3] ÷ 000B ÷ 0308 ÷ 0027 ÷ # ÷ [0.2] <LINE TABULATION> (Newline) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 000B ÷ 261D ÷ # ÷ [0.2] <LINE TABULATION> (Newline) ÷ [3.1] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ 000B ÷ 0308 ÷ 261D ÷ # ÷ [0.2] <LINE TABULATION> (Newline) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ 000B ÷ 1F3FB ÷ # ÷ [0.2] <LINE TABULATION> (Newline) ÷ [3.1] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ 000B ÷ 0308 ÷ 1F3FB ÷ # ÷ [0.2] <LINE TABULATION> (Newline) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ 000B ÷ 2640 ÷ # ÷ [0.2] <LINE TABULATION> (Newline) ÷ [3.1] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ 000B ÷ 0308 ÷ 2640 ÷ # ÷ [0.2] <LINE TABULATION> (Newline) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ 000B ÷ 1F466 ÷ # ÷ [0.2] <LINE TABULATION> (Newline) ÷ [3.1] BOY (EBG) ÷ [0.3] +÷ 000B ÷ 0308 ÷ 1F466 ÷ # ÷ [0.2] <LINE TABULATION> (Newline) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] BOY (EBG) ÷ [0.3] ÷ 000B ÷ 00AD ÷ # ÷ [0.2] <LINE TABULATION> (Newline) ÷ [3.1] SOFT HYPHEN (Format_FE) ÷ [0.3] ÷ 000B ÷ 0308 × 00AD ÷ # ÷ [0.2] <LINE TABULATION> (Newline) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] ÷ 000B ÷ 0300 ÷ # ÷ [0.2] <LINE TABULATION> (Newline) ÷ [3.1] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] ÷ 000B ÷ 0308 × 0300 ÷ # ÷ [0.2] <LINE TABULATION> (Newline) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 000B ÷ 200D ÷ # ÷ [0.2] <LINE TABULATION> (Newline) ÷ [3.1] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 000B ÷ 0308 × 200D ÷ # ÷ [0.2] <LINE TABULATION> (Newline) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] ÷ 000B ÷ 0061 × 2060 ÷ # ÷ [0.2] <LINE TABULATION> (Newline) ÷ [3.1] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] ÷ 000B ÷ 0308 ÷ 0061 × 2060 ÷ # ÷ [0.2] <LINE TABULATION> (Newline) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] ÷ 000B ÷ 0061 ÷ 003A ÷ # ÷ [0.2] <LINE TABULATION> (Newline) ÷ [3.1] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] @@ -250,18 +292,28 @@ ÷ 3031 × 0308 ÷ 0030 ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] ÷ 3031 × 005F ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) × [13.1] LOW LINE (ExtendNumLet) ÷ [0.3] ÷ 3031 × 0308 × 005F ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) × [4.0] COMBINING DIAERESIS (Extend_FE) × [13.1] LOW LINE (ExtendNumLet) ÷ [0.3] -÷ 3031 ÷ 1F1E6 ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [0.3] -÷ 3031 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [0.3] +÷ 3031 ÷ 1F1E6 ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 3031 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ 3031 ÷ 05D0 ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] ÷ 3031 × 0308 ÷ 05D0 ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] ÷ 3031 ÷ 0022 ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] ÷ 3031 × 0308 ÷ 0022 ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] ÷ 3031 ÷ 0027 ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] ÷ 3031 × 0308 ÷ 0027 ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 3031 ÷ 261D ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ 3031 × 0308 ÷ 261D ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ 3031 ÷ 1F3FB ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ 3031 × 0308 ÷ 1F3FB ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ 3031 ÷ 2640 ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ 3031 × 0308 ÷ 2640 ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ 3031 ÷ 1F466 ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) ÷ [999.0] BOY (EBG) ÷ [0.3] +÷ 3031 × 0308 ÷ 1F466 ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] BOY (EBG) ÷ [0.3] ÷ 3031 × 00AD ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] ÷ 3031 × 0308 × 00AD ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] ÷ 3031 × 0300 ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] ÷ 3031 × 0308 × 0300 ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 3031 × 200D ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 3031 × 0308 × 200D ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] ÷ 3031 ÷ 0061 × 2060 ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] ÷ 3031 × 0308 ÷ 0061 × 2060 ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] ÷ 3031 ÷ 0061 ÷ 003A ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] @@ -302,18 +354,28 @@ ÷ 0041 × 0308 × 0030 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [9.0] DIGIT ZERO (Numeric) ÷ [0.3] ÷ 0041 × 005F ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [13.1] LOW LINE (ExtendNumLet) ÷ [0.3] ÷ 0041 × 0308 × 005F ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [13.1] LOW LINE (ExtendNumLet) ÷ [0.3] -÷ 0041 ÷ 1F1E6 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [0.3] -÷ 0041 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [0.3] +÷ 0041 ÷ 1F1E6 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0041 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ 0041 × 05D0 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [5.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] ÷ 0041 × 0308 × 05D0 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [5.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] ÷ 0041 ÷ 0022 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] ÷ 0041 × 0308 ÷ 0022 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] ÷ 0041 ÷ 0027 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] ÷ 0041 × 0308 ÷ 0027 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0041 ÷ 261D ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ 0041 × 0308 ÷ 261D ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ 0041 ÷ 1F3FB ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ 0041 × 0308 ÷ 1F3FB ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ 0041 ÷ 2640 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ 0041 × 0308 ÷ 2640 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ 0041 ÷ 1F466 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) ÷ [999.0] BOY (EBG) ÷ [0.3] +÷ 0041 × 0308 ÷ 1F466 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] BOY (EBG) ÷ [0.3] ÷ 0041 × 00AD ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] ÷ 0041 × 0308 × 00AD ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] ÷ 0041 × 0300 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] ÷ 0041 × 0308 × 0300 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0041 × 200D ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 0041 × 0308 × 200D ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] ÷ 0041 × 0061 × 2060 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [5.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] ÷ 0041 × 0308 × 0061 × 2060 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [5.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] ÷ 0041 × 0061 ÷ 003A ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [5.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] @@ -354,18 +416,28 @@ ÷ 003A × 0308 ÷ 0030 ÷ # ÷ [0.2] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] ÷ 003A ÷ 005F ÷ # ÷ [0.2] COLON (MidLetter) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] ÷ 003A × 0308 ÷ 005F ÷ # ÷ [0.2] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] -÷ 003A ÷ 1F1E6 ÷ # ÷ [0.2] COLON (MidLetter) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [0.3] -÷ 003A × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [0.3] +÷ 003A ÷ 1F1E6 ÷ # ÷ [0.2] COLON (MidLetter) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 003A × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ 003A ÷ 05D0 ÷ # ÷ [0.2] COLON (MidLetter) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] ÷ 003A × 0308 ÷ 05D0 ÷ # ÷ [0.2] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] ÷ 003A ÷ 0022 ÷ # ÷ [0.2] COLON (MidLetter) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] ÷ 003A × 0308 ÷ 0022 ÷ # ÷ [0.2] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] ÷ 003A ÷ 0027 ÷ # ÷ [0.2] COLON (MidLetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] ÷ 003A × 0308 ÷ 0027 ÷ # ÷ [0.2] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 003A ÷ 261D ÷ # ÷ [0.2] COLON (MidLetter) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ 003A × 0308 ÷ 261D ÷ # ÷ [0.2] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ 003A ÷ 1F3FB ÷ # ÷ [0.2] COLON (MidLetter) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ 003A × 0308 ÷ 1F3FB ÷ # ÷ [0.2] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ 003A ÷ 2640 ÷ # ÷ [0.2] COLON (MidLetter) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ 003A × 0308 ÷ 2640 ÷ # ÷ [0.2] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ 003A ÷ 1F466 ÷ # ÷ [0.2] COLON (MidLetter) ÷ [999.0] BOY (EBG) ÷ [0.3] +÷ 003A × 0308 ÷ 1F466 ÷ # ÷ [0.2] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] BOY (EBG) ÷ [0.3] ÷ 003A × 00AD ÷ # ÷ [0.2] COLON (MidLetter) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] ÷ 003A × 0308 × 00AD ÷ # ÷ [0.2] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] ÷ 003A × 0300 ÷ # ÷ [0.2] COLON (MidLetter) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] ÷ 003A × 0308 × 0300 ÷ # ÷ [0.2] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 003A × 200D ÷ # ÷ [0.2] COLON (MidLetter) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 003A × 0308 × 200D ÷ # ÷ [0.2] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] ÷ 003A ÷ 0061 × 2060 ÷ # ÷ [0.2] COLON (MidLetter) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] ÷ 003A × 0308 ÷ 0061 × 2060 ÷ # ÷ [0.2] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] ÷ 003A ÷ 0061 ÷ 003A ÷ # ÷ [0.2] COLON (MidLetter) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] @@ -406,18 +478,28 @@ ÷ 002C × 0308 ÷ 0030 ÷ # ÷ [0.2] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] ÷ 002C ÷ 005F ÷ # ÷ [0.2] COMMA (MidNum) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] ÷ 002C × 0308 ÷ 005F ÷ # ÷ [0.2] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] -÷ 002C ÷ 1F1E6 ÷ # ÷ [0.2] COMMA (MidNum) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [0.3] -÷ 002C × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [0.3] +÷ 002C ÷ 1F1E6 ÷ # ÷ [0.2] COMMA (MidNum) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 002C × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ 002C ÷ 05D0 ÷ # ÷ [0.2] COMMA (MidNum) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] ÷ 002C × 0308 ÷ 05D0 ÷ # ÷ [0.2] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] ÷ 002C ÷ 0022 ÷ # ÷ [0.2] COMMA (MidNum) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] ÷ 002C × 0308 ÷ 0022 ÷ # ÷ [0.2] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] ÷ 002C ÷ 0027 ÷ # ÷ [0.2] COMMA (MidNum) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] ÷ 002C × 0308 ÷ 0027 ÷ # ÷ [0.2] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 002C ÷ 261D ÷ # ÷ [0.2] COMMA (MidNum) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ 002C × 0308 ÷ 261D ÷ # ÷ [0.2] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ 002C ÷ 1F3FB ÷ # ÷ [0.2] COMMA (MidNum) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ 002C × 0308 ÷ 1F3FB ÷ # ÷ [0.2] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ 002C ÷ 2640 ÷ # ÷ [0.2] COMMA (MidNum) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ 002C × 0308 ÷ 2640 ÷ # ÷ [0.2] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ 002C ÷ 1F466 ÷ # ÷ [0.2] COMMA (MidNum) ÷ [999.0] BOY (EBG) ÷ [0.3] +÷ 002C × 0308 ÷ 1F466 ÷ # ÷ [0.2] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] BOY (EBG) ÷ [0.3] ÷ 002C × 00AD ÷ # ÷ [0.2] COMMA (MidNum) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] ÷ 002C × 0308 × 00AD ÷ # ÷ [0.2] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] ÷ 002C × 0300 ÷ # ÷ [0.2] COMMA (MidNum) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] ÷ 002C × 0308 × 0300 ÷ # ÷ [0.2] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 002C × 200D ÷ # ÷ [0.2] COMMA (MidNum) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 002C × 0308 × 200D ÷ # ÷ [0.2] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] ÷ 002C ÷ 0061 × 2060 ÷ # ÷ [0.2] COMMA (MidNum) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] ÷ 002C × 0308 ÷ 0061 × 2060 ÷ # ÷ [0.2] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] ÷ 002C ÷ 0061 ÷ 003A ÷ # ÷ [0.2] COMMA (MidNum) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] @@ -458,18 +540,28 @@ ÷ 002E × 0308 ÷ 0030 ÷ # ÷ [0.2] FULL STOP (MidNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] ÷ 002E ÷ 005F ÷ # ÷ [0.2] FULL STOP (MidNumLet) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] ÷ 002E × 0308 ÷ 005F ÷ # ÷ [0.2] FULL STOP (MidNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] -÷ 002E ÷ 1F1E6 ÷ # ÷ [0.2] FULL STOP (MidNumLet) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [0.3] -÷ 002E × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] FULL STOP (MidNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [0.3] +÷ 002E ÷ 1F1E6 ÷ # ÷ [0.2] FULL STOP (MidNumLet) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 002E × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] FULL STOP (MidNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ 002E ÷ 05D0 ÷ # ÷ [0.2] FULL STOP (MidNumLet) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] ÷ 002E × 0308 ÷ 05D0 ÷ # ÷ [0.2] FULL STOP (MidNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] ÷ 002E ÷ 0022 ÷ # ÷ [0.2] FULL STOP (MidNumLet) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] ÷ 002E × 0308 ÷ 0022 ÷ # ÷ [0.2] FULL STOP (MidNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] ÷ 002E ÷ 0027 ÷ # ÷ [0.2] FULL STOP (MidNumLet) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] ÷ 002E × 0308 ÷ 0027 ÷ # ÷ [0.2] FULL STOP (MidNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 002E ÷ 261D ÷ # ÷ [0.2] FULL STOP (MidNumLet) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ 002E × 0308 ÷ 261D ÷ # ÷ [0.2] FULL STOP (MidNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ 002E ÷ 1F3FB ÷ # ÷ [0.2] FULL STOP (MidNumLet) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ 002E × 0308 ÷ 1F3FB ÷ # ÷ [0.2] FULL STOP (MidNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ 002E ÷ 2640 ÷ # ÷ [0.2] FULL STOP (MidNumLet) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ 002E × 0308 ÷ 2640 ÷ # ÷ [0.2] FULL STOP (MidNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ 002E ÷ 1F466 ÷ # ÷ [0.2] FULL STOP (MidNumLet) ÷ [999.0] BOY (EBG) ÷ [0.3] +÷ 002E × 0308 ÷ 1F466 ÷ # ÷ [0.2] FULL STOP (MidNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] BOY (EBG) ÷ [0.3] ÷ 002E × 00AD ÷ # ÷ [0.2] FULL STOP (MidNumLet) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] ÷ 002E × 0308 × 00AD ÷ # ÷ [0.2] FULL STOP (MidNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] ÷ 002E × 0300 ÷ # ÷ [0.2] FULL STOP (MidNumLet) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] ÷ 002E × 0308 × 0300 ÷ # ÷ [0.2] FULL STOP (MidNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 002E × 200D ÷ # ÷ [0.2] FULL STOP (MidNumLet) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 002E × 0308 × 200D ÷ # ÷ [0.2] FULL STOP (MidNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] ÷ 002E ÷ 0061 × 2060 ÷ # ÷ [0.2] FULL STOP (MidNumLet) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] ÷ 002E × 0308 ÷ 0061 × 2060 ÷ # ÷ [0.2] FULL STOP (MidNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] ÷ 002E ÷ 0061 ÷ 003A ÷ # ÷ [0.2] FULL STOP (MidNumLet) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] @@ -510,18 +602,28 @@ ÷ 0030 × 0308 × 0030 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [4.0] COMBINING DIAERESIS (Extend_FE) × [8.0] DIGIT ZERO (Numeric) ÷ [0.3] ÷ 0030 × 005F ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [13.1] LOW LINE (ExtendNumLet) ÷ [0.3] ÷ 0030 × 0308 × 005F ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [4.0] COMBINING DIAERESIS (Extend_FE) × [13.1] LOW LINE (ExtendNumLet) ÷ [0.3] -÷ 0030 ÷ 1F1E6 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [0.3] -÷ 0030 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [0.3] +÷ 0030 ÷ 1F1E6 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0030 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ 0030 × 05D0 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [10.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] ÷ 0030 × 0308 × 05D0 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [4.0] COMBINING DIAERESIS (Extend_FE) × [10.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] ÷ 0030 ÷ 0022 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] ÷ 0030 × 0308 ÷ 0022 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] ÷ 0030 ÷ 0027 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] ÷ 0030 × 0308 ÷ 0027 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0030 ÷ 261D ÷ # ÷ [0.2] DIGIT ZERO (Numeric) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ 0030 × 0308 ÷ 261D ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ 0030 ÷ 1F3FB ÷ # ÷ [0.2] DIGIT ZERO (Numeric) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ 0030 × 0308 ÷ 1F3FB ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ 0030 ÷ 2640 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ 0030 × 0308 ÷ 2640 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ 0030 ÷ 1F466 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) ÷ [999.0] BOY (EBG) ÷ [0.3] +÷ 0030 × 0308 ÷ 1F466 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] BOY (EBG) ÷ [0.3] ÷ 0030 × 00AD ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] ÷ 0030 × 0308 × 00AD ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] ÷ 0030 × 0300 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] ÷ 0030 × 0308 × 0300 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0030 × 200D ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 0030 × 0308 × 200D ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] ÷ 0030 × 0061 × 2060 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [10.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] ÷ 0030 × 0308 × 0061 × 2060 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [4.0] COMBINING DIAERESIS (Extend_FE) × [10.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] ÷ 0030 × 0061 ÷ 003A ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [10.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] @@ -562,18 +664,28 @@ ÷ 005F × 0308 × 0030 ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) × [13.2] DIGIT ZERO (Numeric) ÷ [0.3] ÷ 005F × 005F ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [13.1] LOW LINE (ExtendNumLet) ÷ [0.3] ÷ 005F × 0308 × 005F ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) × [13.1] LOW LINE (ExtendNumLet) ÷ [0.3] -÷ 005F ÷ 1F1E6 ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [0.3] -÷ 005F × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [0.3] +÷ 005F ÷ 1F1E6 ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 005F × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ 005F × 05D0 ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [13.2] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] ÷ 005F × 0308 × 05D0 ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) × [13.2] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] ÷ 005F ÷ 0022 ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] ÷ 005F × 0308 ÷ 0022 ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] ÷ 005F ÷ 0027 ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] ÷ 005F × 0308 ÷ 0027 ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 005F ÷ 261D ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ 005F × 0308 ÷ 261D ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ 005F ÷ 1F3FB ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ 005F × 0308 ÷ 1F3FB ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ 005F ÷ 2640 ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ 005F × 0308 ÷ 2640 ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ 005F ÷ 1F466 ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) ÷ [999.0] BOY (EBG) ÷ [0.3] +÷ 005F × 0308 ÷ 1F466 ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] BOY (EBG) ÷ [0.3] ÷ 005F × 00AD ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] ÷ 005F × 0308 × 00AD ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] ÷ 005F × 0300 ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] ÷ 005F × 0308 × 0300 ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 005F × 200D ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 005F × 0308 × 200D ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] ÷ 005F × 0061 × 2060 ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [13.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] ÷ 005F × 0308 × 0061 × 2060 ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) × [13.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] ÷ 005F × 0061 ÷ 003A ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [13.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] @@ -592,58 +704,68 @@ ÷ 005F × 0308 × 0031 ÷ 002C ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) × [13.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] ÷ 005F × 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [13.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] ÷ 005F × 0308 × 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] LOW LINE (ExtendNumLet) × [4.0] COMBINING DIAERESIS (Extend_FE) × [13.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] -÷ 1F1E6 ÷ 0001 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [999.0] <START OF HEADING> (Other) ÷ [0.3] -÷ 1F1E6 × 0308 ÷ 0001 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] <START OF HEADING> (Other) ÷ [0.3] -÷ 1F1E6 ÷ 000D ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [3.2] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -÷ 1F1E6 × 0308 ÷ 000D ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] -÷ 1F1E6 ÷ 000A ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [3.2] <LINE FEED (LF)> (LF) ÷ [0.3] -÷ 1F1E6 × 0308 ÷ 000A ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] <LINE FEED (LF)> (LF) ÷ [0.3] -÷ 1F1E6 ÷ 000B ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [3.2] <LINE TABULATION> (Newline) ÷ [0.3] -÷ 1F1E6 × 0308 ÷ 000B ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] <LINE TABULATION> (Newline) ÷ [0.3] -÷ 1F1E6 ÷ 3031 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] -÷ 1F1E6 × 0308 ÷ 3031 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] -÷ 1F1E6 ÷ 0041 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [999.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] -÷ 1F1E6 × 0308 ÷ 0041 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] -÷ 1F1E6 ÷ 003A ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [999.0] COLON (MidLetter) ÷ [0.3] -÷ 1F1E6 × 0308 ÷ 003A ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COLON (MidLetter) ÷ [0.3] -÷ 1F1E6 ÷ 002C ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [999.0] COMMA (MidNum) ÷ [0.3] -÷ 1F1E6 × 0308 ÷ 002C ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COMMA (MidNum) ÷ [0.3] -÷ 1F1E6 ÷ 002E ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] -÷ 1F1E6 × 0308 ÷ 002E ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] -÷ 1F1E6 ÷ 0030 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] -÷ 1F1E6 × 0308 ÷ 0030 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] -÷ 1F1E6 ÷ 005F ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] -÷ 1F1E6 × 0308 ÷ 005F ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] -÷ 1F1E6 × 1F1E6 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) × [13.3] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [0.3] -÷ 1F1E6 × 0308 × 1F1E6 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) × [4.0] COMBINING DIAERESIS (Extend_FE) × [13.3] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [0.3] -÷ 1F1E6 ÷ 05D0 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] -÷ 1F1E6 × 0308 ÷ 05D0 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] -÷ 1F1E6 ÷ 0022 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] -÷ 1F1E6 × 0308 ÷ 0022 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] -÷ 1F1E6 ÷ 0027 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] -÷ 1F1E6 × 0308 ÷ 0027 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] -÷ 1F1E6 × 00AD ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] -÷ 1F1E6 × 0308 × 00AD ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] -÷ 1F1E6 × 0300 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] -÷ 1F1E6 × 0308 × 0300 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] -÷ 1F1E6 ÷ 0061 × 2060 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] -÷ 1F1E6 × 0308 ÷ 0061 × 2060 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] -÷ 1F1E6 ÷ 0061 ÷ 003A ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] -÷ 1F1E6 × 0308 ÷ 0061 ÷ 003A ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] -÷ 1F1E6 ÷ 0061 ÷ 0027 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] -÷ 1F1E6 × 0308 ÷ 0061 ÷ 0027 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] -÷ 1F1E6 ÷ 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] -÷ 1F1E6 × 0308 ÷ 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] -÷ 1F1E6 ÷ 0061 ÷ 002C ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] -÷ 1F1E6 × 0308 ÷ 0061 ÷ 002C ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] -÷ 1F1E6 ÷ 0031 ÷ 003A ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] -÷ 1F1E6 × 0308 ÷ 0031 ÷ 003A ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] -÷ 1F1E6 ÷ 0031 ÷ 0027 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] -÷ 1F1E6 × 0308 ÷ 0031 ÷ 0027 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] -÷ 1F1E6 ÷ 0031 ÷ 002C ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] -÷ 1F1E6 × 0308 ÷ 0031 ÷ 002C ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] -÷ 1F1E6 ÷ 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] -÷ 1F1E6 × 0308 ÷ 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 1F1E6 ÷ 0001 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] <START OF HEADING> (Other) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 0001 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] <START OF HEADING> (Other) ÷ [0.3] +÷ 1F1E6 ÷ 000D ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [3.2] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 000D ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +÷ 1F1E6 ÷ 000A ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [3.2] <LINE FEED (LF)> (LF) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 000A ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] <LINE FEED (LF)> (LF) ÷ [0.3] +÷ 1F1E6 ÷ 000B ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [3.2] <LINE TABULATION> (Newline) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 000B ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] <LINE TABULATION> (Newline) ÷ [0.3] +÷ 1F1E6 ÷ 3031 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 3031 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 1F1E6 ÷ 0041 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 0041 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 1F1E6 ÷ 003A ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 003A ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 1F1E6 ÷ 002C ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 002C ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 1F1E6 ÷ 002E ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 002E ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 1F1E6 ÷ 0030 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 0030 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 1F1E6 ÷ 005F ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 005F ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 1F1E6 × 1F1E6 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [15.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 1F1E6 × 0308 × 1F1E6 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [4.0] COMBINING DIAERESIS (Extend_FE) × [15.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 1F1E6 ÷ 05D0 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 05D0 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 1F1E6 ÷ 0022 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 0022 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 1F1E6 ÷ 0027 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 0027 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 1F1E6 ÷ 261D ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 261D ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ 1F1E6 ÷ 1F3FB ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 1F3FB ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ 1F1E6 ÷ 2640 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 2640 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ 1F1E6 ÷ 1F466 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] BOY (EBG) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 1F466 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] BOY (EBG) ÷ [0.3] +÷ 1F1E6 × 00AD ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 1F1E6 × 0308 × 00AD ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 1F1E6 × 0300 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 1F1E6 × 0308 × 0300 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 1F1E6 × 200D ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 1F1E6 × 0308 × 200D ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 1F1E6 ÷ 0061 × 2060 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 0061 × 2060 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 1F1E6 ÷ 0061 ÷ 003A ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 0061 ÷ 003A ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 1F1E6 ÷ 0061 ÷ 0027 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 0061 ÷ 0027 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 1F1E6 ÷ 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 1F1E6 ÷ 0061 ÷ 002C ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 0061 ÷ 002C ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 1F1E6 ÷ 0031 ÷ 003A ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 0031 ÷ 003A ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 1F1E6 ÷ 0031 ÷ 0027 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 0031 ÷ 0027 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 1F1E6 ÷ 0031 ÷ 002C ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 0031 ÷ 002C ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 1F1E6 ÷ 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 1F1E6 × 0308 ÷ 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] ÷ 05D0 ÷ 0001 ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [999.0] <START OF HEADING> (Other) ÷ [0.3] ÷ 05D0 × 0308 ÷ 0001 ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] <START OF HEADING> (Other) ÷ [0.3] ÷ 05D0 ÷ 000D ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [3.2] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] @@ -666,18 +788,28 @@ ÷ 05D0 × 0308 × 0030 ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [9.0] DIGIT ZERO (Numeric) ÷ [0.3] ÷ 05D0 × 005F ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [13.1] LOW LINE (ExtendNumLet) ÷ [0.3] ÷ 05D0 × 0308 × 005F ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [13.1] LOW LINE (ExtendNumLet) ÷ [0.3] -÷ 05D0 ÷ 1F1E6 ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [0.3] -÷ 05D0 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [0.3] +÷ 05D0 ÷ 1F1E6 ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 05D0 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ 05D0 × 05D0 ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [5.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] ÷ 05D0 × 0308 × 05D0 ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [5.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] ÷ 05D0 ÷ 0022 ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] ÷ 05D0 × 0308 ÷ 0022 ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] ÷ 05D0 × 0027 ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [7.1] APOSTROPHE (Single_Quote) ÷ [0.3] ÷ 05D0 × 0308 × 0027 ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [7.1] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 05D0 ÷ 261D ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ 05D0 × 0308 ÷ 261D ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ 05D0 ÷ 1F3FB ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ 05D0 × 0308 ÷ 1F3FB ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ 05D0 ÷ 2640 ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ 05D0 × 0308 ÷ 2640 ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ 05D0 ÷ 1F466 ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [999.0] BOY (EBG) ÷ [0.3] +÷ 05D0 × 0308 ÷ 1F466 ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] BOY (EBG) ÷ [0.3] ÷ 05D0 × 00AD ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] ÷ 05D0 × 0308 × 00AD ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] ÷ 05D0 × 0300 ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] ÷ 05D0 × 0308 × 0300 ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 05D0 × 200D ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 05D0 × 0308 × 200D ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] ÷ 05D0 × 0061 × 2060 ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [5.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] ÷ 05D0 × 0308 × 0061 × 2060 ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [5.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] ÷ 05D0 × 0061 ÷ 003A ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [5.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] @@ -718,18 +850,28 @@ ÷ 0022 × 0308 ÷ 0030 ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] ÷ 0022 ÷ 005F ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] ÷ 0022 × 0308 ÷ 005F ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] -÷ 0022 ÷ 1F1E6 ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [0.3] -÷ 0022 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [0.3] +÷ 0022 ÷ 1F1E6 ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0022 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ 0022 ÷ 05D0 ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] ÷ 0022 × 0308 ÷ 05D0 ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] ÷ 0022 ÷ 0022 ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] ÷ 0022 × 0308 ÷ 0022 ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] ÷ 0022 ÷ 0027 ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] ÷ 0022 × 0308 ÷ 0027 ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0022 ÷ 261D ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ 0022 × 0308 ÷ 261D ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ 0022 ÷ 1F3FB ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ 0022 × 0308 ÷ 1F3FB ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ 0022 ÷ 2640 ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ 0022 × 0308 ÷ 2640 ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ 0022 ÷ 1F466 ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) ÷ [999.0] BOY (EBG) ÷ [0.3] +÷ 0022 × 0308 ÷ 1F466 ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] BOY (EBG) ÷ [0.3] ÷ 0022 × 00AD ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] ÷ 0022 × 0308 × 00AD ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] ÷ 0022 × 0300 ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] ÷ 0022 × 0308 × 0300 ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0022 × 200D ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 0022 × 0308 × 200D ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] ÷ 0022 ÷ 0061 × 2060 ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] ÷ 0022 × 0308 ÷ 0061 × 2060 ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] ÷ 0022 ÷ 0061 ÷ 003A ÷ # ÷ [0.2] QUOTATION MARK (Double_Quote) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] @@ -770,18 +912,28 @@ ÷ 0027 × 0308 ÷ 0030 ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] ÷ 0027 ÷ 005F ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] ÷ 0027 × 0308 ÷ 005F ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] -÷ 0027 ÷ 1F1E6 ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [0.3] -÷ 0027 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [0.3] +÷ 0027 ÷ 1F1E6 ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0027 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ 0027 ÷ 05D0 ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] ÷ 0027 × 0308 ÷ 05D0 ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] ÷ 0027 ÷ 0022 ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] ÷ 0027 × 0308 ÷ 0022 ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] ÷ 0027 ÷ 0027 ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] ÷ 0027 × 0308 ÷ 0027 ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0027 ÷ 261D ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ 0027 × 0308 ÷ 261D ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ 0027 ÷ 1F3FB ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ 0027 × 0308 ÷ 1F3FB ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ 0027 ÷ 2640 ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ 0027 × 0308 ÷ 2640 ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ 0027 ÷ 1F466 ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) ÷ [999.0] BOY (EBG) ÷ [0.3] +÷ 0027 × 0308 ÷ 1F466 ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] BOY (EBG) ÷ [0.3] ÷ 0027 × 00AD ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] ÷ 0027 × 0308 × 00AD ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] ÷ 0027 × 0300 ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] ÷ 0027 × 0308 × 0300 ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0027 × 200D ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 0027 × 0308 × 200D ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] ÷ 0027 ÷ 0061 × 2060 ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] ÷ 0027 × 0308 ÷ 0061 × 2060 ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] ÷ 0027 ÷ 0061 ÷ 003A ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] @@ -800,6 +952,254 @@ ÷ 0027 × 0308 ÷ 0031 ÷ 002C ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] ÷ 0027 ÷ 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] ÷ 0027 × 0308 ÷ 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 261D ÷ 0001 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) ÷ [999.0] <START OF HEADING> (Other) ÷ [0.3] +÷ 261D × 0308 ÷ 0001 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] <START OF HEADING> (Other) ÷ [0.3] +÷ 261D ÷ 000D ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) ÷ [3.2] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +÷ 261D × 0308 ÷ 000D ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +÷ 261D ÷ 000A ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) ÷ [3.2] <LINE FEED (LF)> (LF) ÷ [0.3] +÷ 261D × 0308 ÷ 000A ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] <LINE FEED (LF)> (LF) ÷ [0.3] +÷ 261D ÷ 000B ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) ÷ [3.2] <LINE TABULATION> (Newline) ÷ [0.3] +÷ 261D × 0308 ÷ 000B ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] <LINE TABULATION> (Newline) ÷ [0.3] +÷ 261D ÷ 3031 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 261D × 0308 ÷ 3031 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 261D ÷ 0041 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) ÷ [999.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 261D × 0308 ÷ 0041 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 261D ÷ 003A ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 261D × 0308 ÷ 003A ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 261D ÷ 002C ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 261D × 0308 ÷ 002C ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 261D ÷ 002E ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 261D × 0308 ÷ 002E ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 261D ÷ 0030 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 261D × 0308 ÷ 0030 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 261D ÷ 005F ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 261D × 0308 ÷ 005F ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 261D ÷ 1F1E6 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 261D × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 261D ÷ 05D0 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 261D × 0308 ÷ 05D0 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 261D ÷ 0022 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 261D × 0308 ÷ 0022 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 261D ÷ 0027 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 261D × 0308 ÷ 0027 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 261D ÷ 261D ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ 261D × 0308 ÷ 261D ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ 261D × 1F3FB ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [14.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ 261D × 0308 × 1F3FB ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [4.0] COMBINING DIAERESIS (Extend_FE) × [14.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ 261D ÷ 2640 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ 261D × 0308 ÷ 2640 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ 261D ÷ 1F466 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) ÷ [999.0] BOY (EBG) ÷ [0.3] +÷ 261D × 0308 ÷ 1F466 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] BOY (EBG) ÷ [0.3] +÷ 261D × 00AD ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 261D × 0308 × 00AD ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 261D × 0300 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 261D × 0308 × 0300 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 261D × 200D ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 261D × 0308 × 200D ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 261D ÷ 0061 × 2060 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 261D × 0308 ÷ 0061 × 2060 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 261D ÷ 0061 ÷ 003A ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 261D × 0308 ÷ 0061 ÷ 003A ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 261D ÷ 0061 ÷ 0027 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 261D × 0308 ÷ 0061 ÷ 0027 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 261D ÷ 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 261D × 0308 ÷ 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 261D ÷ 0061 ÷ 002C ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 261D × 0308 ÷ 0061 ÷ 002C ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 261D ÷ 0031 ÷ 003A ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 261D × 0308 ÷ 0031 ÷ 003A ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 261D ÷ 0031 ÷ 0027 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 261D × 0308 ÷ 0031 ÷ 0027 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 261D ÷ 0031 ÷ 002C ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 261D × 0308 ÷ 0031 ÷ 002C ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 261D ÷ 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 261D × 0308 ÷ 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 1F3FB ÷ 0001 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [999.0] <START OF HEADING> (Other) ÷ [0.3] +÷ 1F3FB × 0308 ÷ 0001 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] <START OF HEADING> (Other) ÷ [0.3] +÷ 1F3FB ÷ 000D ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [3.2] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +÷ 1F3FB × 0308 ÷ 000D ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +÷ 1F3FB ÷ 000A ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [3.2] <LINE FEED (LF)> (LF) ÷ [0.3] +÷ 1F3FB × 0308 ÷ 000A ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] <LINE FEED (LF)> (LF) ÷ [0.3] +÷ 1F3FB ÷ 000B ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [3.2] <LINE TABULATION> (Newline) ÷ [0.3] +÷ 1F3FB × 0308 ÷ 000B ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] <LINE TABULATION> (Newline) ÷ [0.3] +÷ 1F3FB ÷ 3031 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 1F3FB × 0308 ÷ 3031 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 1F3FB ÷ 0041 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [999.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 1F3FB × 0308 ÷ 0041 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 1F3FB ÷ 003A ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 1F3FB × 0308 ÷ 003A ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 1F3FB ÷ 002C ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 1F3FB × 0308 ÷ 002C ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 1F3FB ÷ 002E ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 1F3FB × 0308 ÷ 002E ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 1F3FB ÷ 0030 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 1F3FB × 0308 ÷ 0030 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 1F3FB ÷ 005F ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 1F3FB × 0308 ÷ 005F ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 1F3FB ÷ 1F1E6 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 1F3FB × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 1F3FB ÷ 05D0 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 1F3FB × 0308 ÷ 05D0 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 1F3FB ÷ 0022 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 1F3FB × 0308 ÷ 0022 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 1F3FB ÷ 0027 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 1F3FB × 0308 ÷ 0027 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 1F3FB ÷ 261D ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ 1F3FB × 0308 ÷ 261D ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ 1F3FB ÷ 1F3FB ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ 1F3FB × 0308 ÷ 1F3FB ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ 1F3FB ÷ 2640 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ 1F3FB × 0308 ÷ 2640 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ 1F3FB ÷ 1F466 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [999.0] BOY (EBG) ÷ [0.3] +÷ 1F3FB × 0308 ÷ 1F466 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] BOY (EBG) ÷ [0.3] +÷ 1F3FB × 00AD ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 1F3FB × 0308 × 00AD ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 1F3FB × 0300 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 1F3FB × 0308 × 0300 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 1F3FB × 200D ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 1F3FB × 0308 × 200D ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 1F3FB ÷ 0061 × 2060 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 1F3FB × 0308 ÷ 0061 × 2060 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 1F3FB ÷ 0061 ÷ 003A ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 1F3FB × 0308 ÷ 0061 ÷ 003A ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 1F3FB ÷ 0061 ÷ 0027 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 1F3FB × 0308 ÷ 0061 ÷ 0027 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 1F3FB ÷ 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 1F3FB × 0308 ÷ 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 1F3FB ÷ 0061 ÷ 002C ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 1F3FB × 0308 ÷ 0061 ÷ 002C ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 1F3FB ÷ 0031 ÷ 003A ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 1F3FB × 0308 ÷ 0031 ÷ 003A ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 1F3FB ÷ 0031 ÷ 0027 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 1F3FB × 0308 ÷ 0031 ÷ 0027 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 1F3FB ÷ 0031 ÷ 002C ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 1F3FB × 0308 ÷ 0031 ÷ 002C ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 1F3FB ÷ 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 1F3FB × 0308 ÷ 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 2640 ÷ 0001 ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) ÷ [999.0] <START OF HEADING> (Other) ÷ [0.3] +÷ 2640 × 0308 ÷ 0001 ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] <START OF HEADING> (Other) ÷ [0.3] +÷ 2640 ÷ 000D ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) ÷ [3.2] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +÷ 2640 × 0308 ÷ 000D ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +÷ 2640 ÷ 000A ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) ÷ [3.2] <LINE FEED (LF)> (LF) ÷ [0.3] +÷ 2640 × 0308 ÷ 000A ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] <LINE FEED (LF)> (LF) ÷ [0.3] +÷ 2640 ÷ 000B ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) ÷ [3.2] <LINE TABULATION> (Newline) ÷ [0.3] +÷ 2640 × 0308 ÷ 000B ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] <LINE TABULATION> (Newline) ÷ [0.3] +÷ 2640 ÷ 3031 ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 2640 × 0308 ÷ 3031 ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 2640 ÷ 0041 ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) ÷ [999.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 2640 × 0308 ÷ 0041 ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 2640 ÷ 003A ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 2640 × 0308 ÷ 003A ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 2640 ÷ 002C ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 2640 × 0308 ÷ 002C ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 2640 ÷ 002E ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 2640 × 0308 ÷ 002E ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 2640 ÷ 0030 ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 2640 × 0308 ÷ 0030 ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 2640 ÷ 005F ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 2640 × 0308 ÷ 005F ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 2640 ÷ 1F1E6 ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 2640 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 2640 ÷ 05D0 ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 2640 × 0308 ÷ 05D0 ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 2640 ÷ 0022 ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 2640 × 0308 ÷ 0022 ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 2640 ÷ 0027 ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 2640 × 0308 ÷ 0027 ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 2640 ÷ 261D ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ 2640 × 0308 ÷ 261D ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ 2640 ÷ 1F3FB ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ 2640 × 0308 ÷ 1F3FB ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ 2640 ÷ 2640 ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ 2640 × 0308 ÷ 2640 ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ 2640 ÷ 1F466 ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) ÷ [999.0] BOY (EBG) ÷ [0.3] +÷ 2640 × 0308 ÷ 1F466 ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] BOY (EBG) ÷ [0.3] +÷ 2640 × 00AD ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 2640 × 0308 × 00AD ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 2640 × 0300 ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 2640 × 0308 × 0300 ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 2640 × 200D ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 2640 × 0308 × 200D ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 2640 ÷ 0061 × 2060 ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 2640 × 0308 ÷ 0061 × 2060 ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 2640 ÷ 0061 ÷ 003A ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 2640 × 0308 ÷ 0061 ÷ 003A ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 2640 ÷ 0061 ÷ 0027 ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 2640 × 0308 ÷ 0061 ÷ 0027 ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 2640 ÷ 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 2640 × 0308 ÷ 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 2640 ÷ 0061 ÷ 002C ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 2640 × 0308 ÷ 0061 ÷ 002C ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 2640 ÷ 0031 ÷ 003A ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 2640 × 0308 ÷ 0031 ÷ 003A ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 2640 ÷ 0031 ÷ 0027 ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 2640 × 0308 ÷ 0031 ÷ 0027 ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 2640 ÷ 0031 ÷ 002C ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 2640 × 0308 ÷ 0031 ÷ 002C ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 2640 ÷ 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 2640 × 0308 ÷ 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 1F466 ÷ 0001 ÷ # ÷ [0.2] BOY (EBG) ÷ [999.0] <START OF HEADING> (Other) ÷ [0.3] +÷ 1F466 × 0308 ÷ 0001 ÷ # ÷ [0.2] BOY (EBG) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] <START OF HEADING> (Other) ÷ [0.3] +÷ 1F466 ÷ 000D ÷ # ÷ [0.2] BOY (EBG) ÷ [3.2] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +÷ 1F466 × 0308 ÷ 000D ÷ # ÷ [0.2] BOY (EBG) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +÷ 1F466 ÷ 000A ÷ # ÷ [0.2] BOY (EBG) ÷ [3.2] <LINE FEED (LF)> (LF) ÷ [0.3] +÷ 1F466 × 0308 ÷ 000A ÷ # ÷ [0.2] BOY (EBG) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] <LINE FEED (LF)> (LF) ÷ [0.3] +÷ 1F466 ÷ 000B ÷ # ÷ [0.2] BOY (EBG) ÷ [3.2] <LINE TABULATION> (Newline) ÷ [0.3] +÷ 1F466 × 0308 ÷ 000B ÷ # ÷ [0.2] BOY (EBG) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] <LINE TABULATION> (Newline) ÷ [0.3] +÷ 1F466 ÷ 3031 ÷ # ÷ [0.2] BOY (EBG) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 1F466 × 0308 ÷ 3031 ÷ # ÷ [0.2] BOY (EBG) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 1F466 ÷ 0041 ÷ # ÷ [0.2] BOY (EBG) ÷ [999.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 1F466 × 0308 ÷ 0041 ÷ # ÷ [0.2] BOY (EBG) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 1F466 ÷ 003A ÷ # ÷ [0.2] BOY (EBG) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 1F466 × 0308 ÷ 003A ÷ # ÷ [0.2] BOY (EBG) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 1F466 ÷ 002C ÷ # ÷ [0.2] BOY (EBG) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 1F466 × 0308 ÷ 002C ÷ # ÷ [0.2] BOY (EBG) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 1F466 ÷ 002E ÷ # ÷ [0.2] BOY (EBG) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 1F466 × 0308 ÷ 002E ÷ # ÷ [0.2] BOY (EBG) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 1F466 ÷ 0030 ÷ # ÷ [0.2] BOY (EBG) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 1F466 × 0308 ÷ 0030 ÷ # ÷ [0.2] BOY (EBG) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 1F466 ÷ 005F ÷ # ÷ [0.2] BOY (EBG) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 1F466 × 0308 ÷ 005F ÷ # ÷ [0.2] BOY (EBG) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 1F466 ÷ 1F1E6 ÷ # ÷ [0.2] BOY (EBG) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 1F466 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] BOY (EBG) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 1F466 ÷ 05D0 ÷ # ÷ [0.2] BOY (EBG) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 1F466 × 0308 ÷ 05D0 ÷ # ÷ [0.2] BOY (EBG) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 1F466 ÷ 0022 ÷ # ÷ [0.2] BOY (EBG) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 1F466 × 0308 ÷ 0022 ÷ # ÷ [0.2] BOY (EBG) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 1F466 ÷ 0027 ÷ # ÷ [0.2] BOY (EBG) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 1F466 × 0308 ÷ 0027 ÷ # ÷ [0.2] BOY (EBG) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 1F466 ÷ 261D ÷ # ÷ [0.2] BOY (EBG) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ 1F466 × 0308 ÷ 261D ÷ # ÷ [0.2] BOY (EBG) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ 1F466 × 1F3FB ÷ # ÷ [0.2] BOY (EBG) × [14.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ 1F466 × 0308 × 1F3FB ÷ # ÷ [0.2] BOY (EBG) × [4.0] COMBINING DIAERESIS (Extend_FE) × [14.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ 1F466 ÷ 2640 ÷ # ÷ [0.2] BOY (EBG) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ 1F466 × 0308 ÷ 2640 ÷ # ÷ [0.2] BOY (EBG) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ 1F466 ÷ 1F466 ÷ # ÷ [0.2] BOY (EBG) ÷ [999.0] BOY (EBG) ÷ [0.3] +÷ 1F466 × 0308 ÷ 1F466 ÷ # ÷ [0.2] BOY (EBG) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] BOY (EBG) ÷ [0.3] +÷ 1F466 × 00AD ÷ # ÷ [0.2] BOY (EBG) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 1F466 × 0308 × 00AD ÷ # ÷ [0.2] BOY (EBG) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 1F466 × 0300 ÷ # ÷ [0.2] BOY (EBG) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 1F466 × 0308 × 0300 ÷ # ÷ [0.2] BOY (EBG) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 1F466 × 200D ÷ # ÷ [0.2] BOY (EBG) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 1F466 × 0308 × 200D ÷ # ÷ [0.2] BOY (EBG) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 1F466 ÷ 0061 × 2060 ÷ # ÷ [0.2] BOY (EBG) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 1F466 × 0308 ÷ 0061 × 2060 ÷ # ÷ [0.2] BOY (EBG) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 1F466 ÷ 0061 ÷ 003A ÷ # ÷ [0.2] BOY (EBG) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 1F466 × 0308 ÷ 0061 ÷ 003A ÷ # ÷ [0.2] BOY (EBG) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 1F466 ÷ 0061 ÷ 0027 ÷ # ÷ [0.2] BOY (EBG) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 1F466 × 0308 ÷ 0061 ÷ 0027 ÷ # ÷ [0.2] BOY (EBG) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 1F466 ÷ 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] BOY (EBG) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 1F466 × 0308 ÷ 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] BOY (EBG) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 1F466 ÷ 0061 ÷ 002C ÷ # ÷ [0.2] BOY (EBG) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 1F466 × 0308 ÷ 0061 ÷ 002C ÷ # ÷ [0.2] BOY (EBG) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 1F466 ÷ 0031 ÷ 003A ÷ # ÷ [0.2] BOY (EBG) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 1F466 × 0308 ÷ 0031 ÷ 003A ÷ # ÷ [0.2] BOY (EBG) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 1F466 ÷ 0031 ÷ 0027 ÷ # ÷ [0.2] BOY (EBG) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 1F466 × 0308 ÷ 0031 ÷ 0027 ÷ # ÷ [0.2] BOY (EBG) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 1F466 ÷ 0031 ÷ 002C ÷ # ÷ [0.2] BOY (EBG) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 1F466 × 0308 ÷ 0031 ÷ 002C ÷ # ÷ [0.2] BOY (EBG) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 1F466 ÷ 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] BOY (EBG) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 1F466 × 0308 ÷ 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] BOY (EBG) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] ÷ 00AD ÷ 0001 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) ÷ [999.0] <START OF HEADING> (Other) ÷ [0.3] ÷ 00AD × 0308 ÷ 0001 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] <START OF HEADING> (Other) ÷ [0.3] ÷ 00AD ÷ 000D ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) ÷ [3.2] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] @@ -822,18 +1222,28 @@ ÷ 00AD × 0308 ÷ 0030 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] ÷ 00AD ÷ 005F ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] ÷ 00AD × 0308 ÷ 005F ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] -÷ 00AD ÷ 1F1E6 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [0.3] -÷ 00AD × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [0.3] +÷ 00AD ÷ 1F1E6 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 00AD × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ 00AD ÷ 05D0 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] ÷ 00AD × 0308 ÷ 05D0 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] ÷ 00AD ÷ 0022 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] ÷ 00AD × 0308 ÷ 0022 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] ÷ 00AD ÷ 0027 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] ÷ 00AD × 0308 ÷ 0027 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 00AD ÷ 261D ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ 00AD × 0308 ÷ 261D ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ 00AD ÷ 1F3FB ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ 00AD × 0308 ÷ 1F3FB ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ 00AD ÷ 2640 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ 00AD × 0308 ÷ 2640 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ 00AD ÷ 1F466 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) ÷ [999.0] BOY (EBG) ÷ [0.3] +÷ 00AD × 0308 ÷ 1F466 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] BOY (EBG) ÷ [0.3] ÷ 00AD × 00AD ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] ÷ 00AD × 0308 × 00AD ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] ÷ 00AD × 0300 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] ÷ 00AD × 0308 × 0300 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 00AD × 200D ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 00AD × 0308 × 200D ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] ÷ 00AD ÷ 0061 × 2060 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] ÷ 00AD × 0308 ÷ 0061 × 2060 ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] ÷ 00AD ÷ 0061 ÷ 003A ÷ # ÷ [0.2] SOFT HYPHEN (Format_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] @@ -874,18 +1284,28 @@ ÷ 0300 × 0308 ÷ 0030 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] ÷ 0300 ÷ 005F ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] ÷ 0300 × 0308 ÷ 005F ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] -÷ 0300 ÷ 1F1E6 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [0.3] -÷ 0300 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [0.3] +÷ 0300 ÷ 1F1E6 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0300 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ 0300 ÷ 05D0 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] ÷ 0300 × 0308 ÷ 05D0 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] ÷ 0300 ÷ 0022 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] ÷ 0300 × 0308 ÷ 0022 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] ÷ 0300 ÷ 0027 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] ÷ 0300 × 0308 ÷ 0027 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0300 ÷ 261D ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ 0300 × 0308 ÷ 261D ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ 0300 ÷ 1F3FB ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ 0300 × 0308 ÷ 1F3FB ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ 0300 ÷ 2640 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ 0300 × 0308 ÷ 2640 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ 0300 ÷ 1F466 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) ÷ [999.0] BOY (EBG) ÷ [0.3] +÷ 0300 × 0308 ÷ 1F466 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] BOY (EBG) ÷ [0.3] ÷ 0300 × 00AD ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] ÷ 0300 × 0308 × 00AD ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] ÷ 0300 × 0300 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] ÷ 0300 × 0308 × 0300 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0300 × 200D ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 0300 × 0308 × 200D ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] ÷ 0300 ÷ 0061 × 2060 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] ÷ 0300 × 0308 ÷ 0061 × 2060 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] ÷ 0300 ÷ 0061 ÷ 003A ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] @@ -904,6 +1324,68 @@ ÷ 0300 × 0308 ÷ 0031 ÷ 002C ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] ÷ 0300 ÷ 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] ÷ 0300 × 0308 ÷ 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 200D ÷ 0001 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) ÷ [999.0] <START OF HEADING> (Other) ÷ [0.3] +÷ 200D × 0308 ÷ 0001 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] <START OF HEADING> (Other) ÷ [0.3] +÷ 200D ÷ 000D ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) ÷ [3.2] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +÷ 200D × 0308 ÷ 000D ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] +÷ 200D ÷ 000A ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) ÷ [3.2] <LINE FEED (LF)> (LF) ÷ [0.3] +÷ 200D × 0308 ÷ 000A ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] <LINE FEED (LF)> (LF) ÷ [0.3] +÷ 200D ÷ 000B ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) ÷ [3.2] <LINE TABULATION> (Newline) ÷ [0.3] +÷ 200D × 0308 ÷ 000B ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [3.2] <LINE TABULATION> (Newline) ÷ [0.3] +÷ 200D ÷ 3031 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 200D × 0308 ÷ 3031 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 200D ÷ 0041 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) ÷ [999.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 200D × 0308 ÷ 0041 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 200D ÷ 003A ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 200D × 0308 ÷ 003A ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 200D ÷ 002C ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 200D × 0308 ÷ 002C ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 200D ÷ 002E ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 200D × 0308 ÷ 002E ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] FULL STOP (MidNumLet) ÷ [0.3] +÷ 200D ÷ 0030 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 200D × 0308 ÷ 0030 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 200D ÷ 005F ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 200D × 0308 ÷ 005F ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 200D ÷ 1F1E6 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 200D × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 200D ÷ 05D0 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 200D × 0308 ÷ 05D0 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] +÷ 200D ÷ 0022 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 200D × 0308 ÷ 0022 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] +÷ 200D ÷ 0027 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 200D × 0308 ÷ 0027 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 200D ÷ 261D ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ 200D × 0308 ÷ 261D ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ 200D ÷ 1F3FB ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ 200D × 0308 ÷ 1F3FB ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ 200D × 2640 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [3.3] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ 200D × 0308 ÷ 2640 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ 200D × 1F466 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [3.3] BOY (EBG) ÷ [0.3] +÷ 200D × 0308 ÷ 1F466 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] BOY (EBG) ÷ [0.3] +÷ 200D × 00AD ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 200D × 0308 × 00AD ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] +÷ 200D × 0300 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 200D × 0308 × 0300 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 200D × 200D ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 200D × 0308 × 200D ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 200D ÷ 0061 × 2060 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 200D × 0308 ÷ 0061 × 2060 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 200D ÷ 0061 ÷ 003A ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 200D × 0308 ÷ 0061 ÷ 003A ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 200D ÷ 0061 ÷ 0027 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 200D × 0308 ÷ 0061 ÷ 0027 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 200D ÷ 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 200D × 0308 ÷ 0061 ÷ 0027 × 2060 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 200D ÷ 0061 ÷ 002C ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 200D × 0308 ÷ 0061 ÷ 002C ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 200D ÷ 0031 ÷ 003A ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 200D × 0308 ÷ 0031 ÷ 003A ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [0.3] +÷ 200D ÷ 0031 ÷ 0027 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 200D × 0308 ÷ 0031 ÷ 0027 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 200D ÷ 0031 ÷ 002C ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 200D × 0308 ÷ 0031 ÷ 002C ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] +÷ 200D ÷ 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] +÷ 200D × 0308 ÷ 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] ÷ 0061 × 2060 ÷ 0001 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] <START OF HEADING> (Other) ÷ [0.3] ÷ 0061 × 2060 × 0308 ÷ 0001 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] <START OF HEADING> (Other) ÷ [0.3] ÷ 0061 × 2060 ÷ 000D ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [3.2] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3] @@ -926,18 +1408,28 @@ ÷ 0061 × 2060 × 0308 × 0030 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [9.0] DIGIT ZERO (Numeric) ÷ [0.3] ÷ 0061 × 2060 × 005F ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [13.1] LOW LINE (ExtendNumLet) ÷ [0.3] ÷ 0061 × 2060 × 0308 × 005F ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [13.1] LOW LINE (ExtendNumLet) ÷ [0.3] -÷ 0061 × 2060 ÷ 1F1E6 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [0.3] -÷ 0061 × 2060 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [0.3] +÷ 0061 × 2060 ÷ 1F1E6 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0061 × 2060 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ 0061 × 2060 × 05D0 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [5.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] ÷ 0061 × 2060 × 0308 × 05D0 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [5.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] ÷ 0061 × 2060 ÷ 0022 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] ÷ 0061 × 2060 × 0308 ÷ 0022 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] ÷ 0061 × 2060 ÷ 0027 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] ÷ 0061 × 2060 × 0308 ÷ 0027 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0061 × 2060 ÷ 261D ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ 0061 × 2060 × 0308 ÷ 261D ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ 0061 × 2060 ÷ 1F3FB ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ 0061 × 2060 × 0308 ÷ 1F3FB ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ 0061 × 2060 ÷ 2640 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ 0061 × 2060 × 0308 ÷ 2640 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ 0061 × 2060 ÷ 1F466 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] BOY (EBG) ÷ [0.3] +÷ 0061 × 2060 × 0308 ÷ 1F466 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] BOY (EBG) ÷ [0.3] ÷ 0061 × 2060 × 00AD ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] ÷ 0061 × 2060 × 0308 × 00AD ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] ÷ 0061 × 2060 × 0300 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] ÷ 0061 × 2060 × 0308 × 0300 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0061 × 2060 × 200D ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 0061 × 2060 × 0308 × 200D ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] ÷ 0061 × 2060 × 0061 × 2060 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [5.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] ÷ 0061 × 2060 × 0308 × 0061 × 2060 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [5.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] ÷ 0061 × 2060 × 0061 ÷ 003A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [5.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] @@ -978,18 +1470,28 @@ ÷ 0061 ÷ 003A × 0308 ÷ 0030 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] ÷ 0061 ÷ 003A ÷ 005F ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] ÷ 0061 ÷ 003A × 0308 ÷ 005F ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] -÷ 0061 ÷ 003A ÷ 1F1E6 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [0.3] -÷ 0061 ÷ 003A × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [0.3] +÷ 0061 ÷ 003A ÷ 1F1E6 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0061 ÷ 003A × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ 0061 × 003A × 05D0 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [6.0] COLON (MidLetter) × [7.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] ÷ 0061 × 003A × 0308 × 05D0 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [6.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [7.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] ÷ 0061 ÷ 003A ÷ 0022 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] ÷ 0061 ÷ 003A × 0308 ÷ 0022 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] ÷ 0061 ÷ 003A ÷ 0027 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] ÷ 0061 ÷ 003A × 0308 ÷ 0027 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0061 ÷ 003A ÷ 261D ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ 0061 ÷ 003A × 0308 ÷ 261D ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ 0061 ÷ 003A ÷ 1F3FB ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ 0061 ÷ 003A × 0308 ÷ 1F3FB ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ 0061 ÷ 003A ÷ 2640 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ 0061 ÷ 003A × 0308 ÷ 2640 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ 0061 ÷ 003A ÷ 1F466 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] BOY (EBG) ÷ [0.3] +÷ 0061 ÷ 003A × 0308 ÷ 1F466 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] BOY (EBG) ÷ [0.3] ÷ 0061 ÷ 003A × 00AD ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] ÷ 0061 ÷ 003A × 0308 × 00AD ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] ÷ 0061 ÷ 003A × 0300 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] ÷ 0061 ÷ 003A × 0308 × 0300 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0061 ÷ 003A × 200D ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 0061 ÷ 003A × 0308 × 200D ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] ÷ 0061 × 003A × 0061 × 2060 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [6.0] COLON (MidLetter) × [7.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] ÷ 0061 × 003A × 0308 × 0061 × 2060 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [6.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [7.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] ÷ 0061 × 003A × 0061 ÷ 003A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [6.0] COLON (MidLetter) × [7.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] @@ -1030,18 +1532,28 @@ ÷ 0061 ÷ 0027 × 0308 ÷ 0030 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] ÷ 0061 ÷ 0027 ÷ 005F ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] ÷ 0061 ÷ 0027 × 0308 ÷ 005F ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] -÷ 0061 ÷ 0027 ÷ 1F1E6 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [0.3] -÷ 0061 ÷ 0027 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [0.3] +÷ 0061 ÷ 0027 ÷ 1F1E6 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0061 ÷ 0027 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ 0061 × 0027 × 05D0 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [6.0] APOSTROPHE (Single_Quote) × [7.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] ÷ 0061 × 0027 × 0308 × 05D0 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [6.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) × [7.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] ÷ 0061 ÷ 0027 ÷ 0022 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] ÷ 0061 ÷ 0027 × 0308 ÷ 0022 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] ÷ 0061 ÷ 0027 ÷ 0027 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] ÷ 0061 ÷ 0027 × 0308 ÷ 0027 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0061 ÷ 0027 ÷ 261D ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ 0061 ÷ 0027 × 0308 ÷ 261D ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ 0061 ÷ 0027 ÷ 1F3FB ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ 0061 ÷ 0027 × 0308 ÷ 1F3FB ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ 0061 ÷ 0027 ÷ 2640 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ 0061 ÷ 0027 × 0308 ÷ 2640 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ 0061 ÷ 0027 ÷ 1F466 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [999.0] BOY (EBG) ÷ [0.3] +÷ 0061 ÷ 0027 × 0308 ÷ 1F466 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] BOY (EBG) ÷ [0.3] ÷ 0061 ÷ 0027 × 00AD ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] ÷ 0061 ÷ 0027 × 0308 × 00AD ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] ÷ 0061 ÷ 0027 × 0300 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] ÷ 0061 ÷ 0027 × 0308 × 0300 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0061 ÷ 0027 × 200D ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 0061 ÷ 0027 × 0308 × 200D ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] ÷ 0061 × 0027 × 0061 × 2060 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [6.0] APOSTROPHE (Single_Quote) × [7.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] ÷ 0061 × 0027 × 0308 × 0061 × 2060 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [6.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) × [7.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] ÷ 0061 × 0027 × 0061 ÷ 003A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [6.0] APOSTROPHE (Single_Quote) × [7.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] @@ -1082,18 +1594,28 @@ ÷ 0061 ÷ 0027 × 2060 × 0308 ÷ 0030 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] ÷ 0061 ÷ 0027 × 2060 ÷ 005F ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] ÷ 0061 ÷ 0027 × 2060 × 0308 ÷ 005F ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] -÷ 0061 ÷ 0027 × 2060 ÷ 1F1E6 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [0.3] -÷ 0061 ÷ 0027 × 2060 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [0.3] +÷ 0061 ÷ 0027 × 2060 ÷ 1F1E6 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0061 ÷ 0027 × 2060 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ 0061 × 0027 × 2060 × 05D0 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [6.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) × [7.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] ÷ 0061 × 0027 × 2060 × 0308 × 05D0 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [6.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [7.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] ÷ 0061 ÷ 0027 × 2060 ÷ 0022 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] ÷ 0061 ÷ 0027 × 2060 × 0308 ÷ 0022 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] ÷ 0061 ÷ 0027 × 2060 ÷ 0027 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] ÷ 0061 ÷ 0027 × 2060 × 0308 ÷ 0027 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0061 ÷ 0027 × 2060 ÷ 261D ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ 0061 ÷ 0027 × 2060 × 0308 ÷ 261D ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ 0061 ÷ 0027 × 2060 ÷ 1F3FB ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ 0061 ÷ 0027 × 2060 × 0308 ÷ 1F3FB ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ 0061 ÷ 0027 × 2060 ÷ 2640 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ 0061 ÷ 0027 × 2060 × 0308 ÷ 2640 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ 0061 ÷ 0027 × 2060 ÷ 1F466 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] BOY (EBG) ÷ [0.3] +÷ 0061 ÷ 0027 × 2060 × 0308 ÷ 1F466 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] BOY (EBG) ÷ [0.3] ÷ 0061 ÷ 0027 × 2060 × 00AD ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] ÷ 0061 ÷ 0027 × 2060 × 0308 × 00AD ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] ÷ 0061 ÷ 0027 × 2060 × 0300 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] ÷ 0061 ÷ 0027 × 2060 × 0308 × 0300 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0061 ÷ 0027 × 2060 × 200D ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 0061 ÷ 0027 × 2060 × 0308 × 200D ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] ÷ 0061 × 0027 × 2060 × 0061 × 2060 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [6.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) × [7.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] ÷ 0061 × 0027 × 2060 × 0308 × 0061 × 2060 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [6.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [7.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] ÷ 0061 × 0027 × 2060 × 0061 ÷ 003A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [6.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) × [7.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] @@ -1134,18 +1656,28 @@ ÷ 0061 ÷ 002C × 0308 ÷ 0030 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] ÷ 0061 ÷ 002C ÷ 005F ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] ÷ 0061 ÷ 002C × 0308 ÷ 005F ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] -÷ 0061 ÷ 002C ÷ 1F1E6 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [0.3] -÷ 0061 ÷ 002C × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [0.3] +÷ 0061 ÷ 002C ÷ 1F1E6 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0061 ÷ 002C × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ 0061 ÷ 002C ÷ 05D0 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] ÷ 0061 ÷ 002C × 0308 ÷ 05D0 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] ÷ 0061 ÷ 002C ÷ 0022 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] ÷ 0061 ÷ 002C × 0308 ÷ 0022 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] ÷ 0061 ÷ 002C ÷ 0027 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] ÷ 0061 ÷ 002C × 0308 ÷ 0027 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0061 ÷ 002C ÷ 261D ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ 0061 ÷ 002C × 0308 ÷ 261D ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ 0061 ÷ 002C ÷ 1F3FB ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ 0061 ÷ 002C × 0308 ÷ 1F3FB ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ 0061 ÷ 002C ÷ 2640 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ 0061 ÷ 002C × 0308 ÷ 2640 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ 0061 ÷ 002C ÷ 1F466 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] BOY (EBG) ÷ [0.3] +÷ 0061 ÷ 002C × 0308 ÷ 1F466 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] BOY (EBG) ÷ [0.3] ÷ 0061 ÷ 002C × 00AD ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] ÷ 0061 ÷ 002C × 0308 × 00AD ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] ÷ 0061 ÷ 002C × 0300 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] ÷ 0061 ÷ 002C × 0308 × 0300 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0061 ÷ 002C × 200D ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 0061 ÷ 002C × 0308 × 200D ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] ÷ 0061 ÷ 002C ÷ 0061 × 2060 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] ÷ 0061 ÷ 002C × 0308 ÷ 0061 × 2060 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] ÷ 0061 ÷ 002C ÷ 0061 ÷ 003A ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] @@ -1186,18 +1718,28 @@ ÷ 0031 ÷ 003A × 0308 ÷ 0030 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] ÷ 0031 ÷ 003A ÷ 005F ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] ÷ 0031 ÷ 003A × 0308 ÷ 005F ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] -÷ 0031 ÷ 003A ÷ 1F1E6 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [0.3] -÷ 0031 ÷ 003A × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [0.3] +÷ 0031 ÷ 003A ÷ 1F1E6 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0031 ÷ 003A × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ 0031 ÷ 003A ÷ 05D0 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] ÷ 0031 ÷ 003A × 0308 ÷ 05D0 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] ÷ 0031 ÷ 003A ÷ 0022 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] ÷ 0031 ÷ 003A × 0308 ÷ 0022 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] ÷ 0031 ÷ 003A ÷ 0027 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] ÷ 0031 ÷ 003A × 0308 ÷ 0027 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0031 ÷ 003A ÷ 261D ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ 0031 ÷ 003A × 0308 ÷ 261D ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ 0031 ÷ 003A ÷ 1F3FB ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ 0031 ÷ 003A × 0308 ÷ 1F3FB ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ 0031 ÷ 003A ÷ 2640 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ 0031 ÷ 003A × 0308 ÷ 2640 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ 0031 ÷ 003A ÷ 1F466 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [999.0] BOY (EBG) ÷ [0.3] +÷ 0031 ÷ 003A × 0308 ÷ 1F466 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] BOY (EBG) ÷ [0.3] ÷ 0031 ÷ 003A × 00AD ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] ÷ 0031 ÷ 003A × 0308 × 00AD ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] ÷ 0031 ÷ 003A × 0300 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] ÷ 0031 ÷ 003A × 0308 × 0300 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0031 ÷ 003A × 200D ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 0031 ÷ 003A × 0308 × 200D ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] ÷ 0031 ÷ 003A ÷ 0061 × 2060 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] ÷ 0031 ÷ 003A × 0308 ÷ 0061 × 2060 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] ÷ 0031 ÷ 003A ÷ 0061 ÷ 003A ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] @@ -1238,18 +1780,28 @@ ÷ 0031 × 0027 × 0308 × 0030 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [12.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) × [11.0] DIGIT ZERO (Numeric) ÷ [0.3] ÷ 0031 ÷ 0027 ÷ 005F ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] ÷ 0031 ÷ 0027 × 0308 ÷ 005F ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] -÷ 0031 ÷ 0027 ÷ 1F1E6 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [0.3] -÷ 0031 ÷ 0027 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [0.3] +÷ 0031 ÷ 0027 ÷ 1F1E6 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0031 ÷ 0027 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ 0031 ÷ 0027 ÷ 05D0 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] ÷ 0031 ÷ 0027 × 0308 ÷ 05D0 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] ÷ 0031 ÷ 0027 ÷ 0022 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] ÷ 0031 ÷ 0027 × 0308 ÷ 0022 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] ÷ 0031 ÷ 0027 ÷ 0027 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] ÷ 0031 ÷ 0027 × 0308 ÷ 0027 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0031 ÷ 0027 ÷ 261D ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ 0031 ÷ 0027 × 0308 ÷ 261D ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ 0031 ÷ 0027 ÷ 1F3FB ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ 0031 ÷ 0027 × 0308 ÷ 1F3FB ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ 0031 ÷ 0027 ÷ 2640 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ 0031 ÷ 0027 × 0308 ÷ 2640 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ 0031 ÷ 0027 ÷ 1F466 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [999.0] BOY (EBG) ÷ [0.3] +÷ 0031 ÷ 0027 × 0308 ÷ 1F466 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] BOY (EBG) ÷ [0.3] ÷ 0031 ÷ 0027 × 00AD ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] ÷ 0031 ÷ 0027 × 0308 × 00AD ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] ÷ 0031 ÷ 0027 × 0300 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] ÷ 0031 ÷ 0027 × 0308 × 0300 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0031 ÷ 0027 × 200D ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 0031 ÷ 0027 × 0308 × 200D ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] ÷ 0031 ÷ 0027 ÷ 0061 × 2060 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] ÷ 0031 ÷ 0027 × 0308 ÷ 0061 × 2060 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] ÷ 0031 ÷ 0027 ÷ 0061 ÷ 003A ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] @@ -1290,18 +1842,28 @@ ÷ 0031 × 002C × 0308 × 0030 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [12.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) × [11.0] DIGIT ZERO (Numeric) ÷ [0.3] ÷ 0031 ÷ 002C ÷ 005F ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] ÷ 0031 ÷ 002C × 0308 ÷ 005F ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] -÷ 0031 ÷ 002C ÷ 1F1E6 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [0.3] -÷ 0031 ÷ 002C × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [0.3] +÷ 0031 ÷ 002C ÷ 1F1E6 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0031 ÷ 002C × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ 0031 ÷ 002C ÷ 05D0 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] ÷ 0031 ÷ 002C × 0308 ÷ 05D0 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] ÷ 0031 ÷ 002C ÷ 0022 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] ÷ 0031 ÷ 002C × 0308 ÷ 0022 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] ÷ 0031 ÷ 002C ÷ 0027 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] ÷ 0031 ÷ 002C × 0308 ÷ 0027 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0031 ÷ 002C ÷ 261D ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ 0031 ÷ 002C × 0308 ÷ 261D ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ 0031 ÷ 002C ÷ 1F3FB ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ 0031 ÷ 002C × 0308 ÷ 1F3FB ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ 0031 ÷ 002C ÷ 2640 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ 0031 ÷ 002C × 0308 ÷ 2640 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ 0031 ÷ 002C ÷ 1F466 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [999.0] BOY (EBG) ÷ [0.3] +÷ 0031 ÷ 002C × 0308 ÷ 1F466 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] BOY (EBG) ÷ [0.3] ÷ 0031 ÷ 002C × 00AD ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] ÷ 0031 ÷ 002C × 0308 × 00AD ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] ÷ 0031 ÷ 002C × 0300 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] ÷ 0031 ÷ 002C × 0308 × 0300 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0031 ÷ 002C × 200D ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 0031 ÷ 002C × 0308 × 200D ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] ÷ 0031 ÷ 002C ÷ 0061 × 2060 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] ÷ 0031 ÷ 002C × 0308 ÷ 0061 × 2060 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] ÷ 0031 ÷ 002C ÷ 0061 ÷ 003A ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] @@ -1342,18 +1904,28 @@ ÷ 0031 × 002E × 2060 × 0308 × 0030 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [12.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [11.0] DIGIT ZERO (Numeric) ÷ [0.3] ÷ 0031 ÷ 002E × 2060 ÷ 005F ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] ÷ 0031 ÷ 002E × 2060 × 0308 ÷ 005F ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LOW LINE (ExtendNumLet) ÷ [0.3] -÷ 0031 ÷ 002E × 2060 ÷ 1F1E6 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [0.3] -÷ 0031 ÷ 002E × 2060 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 ÷ 1F1E6 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3] ÷ 0031 ÷ 002E × 2060 ÷ 05D0 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] ÷ 0031 ÷ 002E × 2060 × 0308 ÷ 05D0 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] ÷ 0031 ÷ 002E × 2060 ÷ 0022 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] ÷ 0031 ÷ 002E × 2060 × 0308 ÷ 0022 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] QUOTATION MARK (Double_Quote) ÷ [0.3] ÷ 0031 ÷ 002E × 2060 ÷ 0027 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] ÷ 0031 ÷ 002E × 2060 × 0308 ÷ 0027 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] APOSTROPHE (Single_Quote) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 ÷ 261D ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 × 0308 ÷ 261D ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 ÷ 1F3FB ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 × 0308 ÷ 1F3FB ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 ÷ 2640 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 × 0308 ÷ 2640 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 ÷ 1F466 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] BOY (EBG) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 × 0308 ÷ 1F466 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] BOY (EBG) ÷ [0.3] ÷ 0031 ÷ 002E × 2060 × 00AD ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] ÷ 0031 ÷ 002E × 2060 × 0308 × 00AD ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] SOFT HYPHEN (Format_FE) ÷ [0.3] ÷ 0031 ÷ 002E × 2060 × 0300 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] ÷ 0031 ÷ 002E × 2060 × 0308 × 0300 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] COMBINING GRAVE ACCENT (Extend_FE) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 × 200D ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] +÷ 0031 ÷ 002E × 2060 × 0308 × 200D ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [0.3] ÷ 0031 ÷ 002E × 2060 ÷ 0061 × 2060 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] ÷ 0031 ÷ 002E × 2060 × 0308 ÷ 0061 × 2060 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] ÷ 0031 ÷ 002E × 2060 ÷ 0061 ÷ 003A ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [0.3] @@ -1372,35 +1944,33 @@ ÷ 0031 × 002E × 2060 × 0308 × 0031 ÷ 002C ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [12.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [11.0] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [0.3] ÷ 0031 × 002E × 2060 × 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [12.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) × [11.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] ÷ 0031 × 002E × 2060 × 0308 × 0031 ÷ 002E × 2060 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [12.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [11.0] DIGIT ONE (Numeric) ÷ [999.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] -÷ 0063 × 0061 × 006E × 0027 × 0074 ÷ # ÷ [0.2] LATIN SMALL LETTER C (ALetter) × [5.0] LATIN SMALL LETTER A (ALetter) × [5.0] LATIN SMALL LETTER N (ALetter) × [6.0] APOSTROPHE (Single_Quote) × [7.0] LATIN SMALL LETTER T (ALetter) ÷ [0.3] -÷ 0063 × 0061 × 006E × 2019 × 0074 ÷ # ÷ [0.2] LATIN SMALL LETTER C (ALetter) × [5.0] LATIN SMALL LETTER A (ALetter) × [5.0] LATIN SMALL LETTER N (ALetter) × [6.0] RIGHT SINGLE QUOTATION MARK (MidNumLet) × [7.0] LATIN SMALL LETTER T (ALetter) ÷ [0.3] -÷ 0061 × 0062 × 00AD × 0062 × 0079 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [5.0] LATIN SMALL LETTER B (ALetter) × [4.0] SOFT HYPHEN (Format_FE) × [5.0] LATIN SMALL LETTER B (ALetter) × [5.0] LATIN SMALL LETTER Y (ALetter) ÷ [0.3] -÷ 0061 ÷ 0024 ÷ 002D ÷ 0033 × 0034 × 002C × 0035 × 0036 × 0037 × 002E × 0031 × 0034 ÷ 0025 ÷ 0062 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] DOLLAR SIGN (Other) ÷ [999.0] HYPHEN-MINUS (Other) ÷ [999.0] DIGIT THREE (Numeric) × [8.0] DIGIT FOUR (Numeric) × [12.0] COMMA (MidNum) × [11.0] DIGIT FIVE (Numeric) × [8.0] DIGIT SIX (Numeric) × [8.0] DIGIT SEVEN (Numeric) × [12.0] FULL STOP (MidNumLet) × [11.0] DIGIT ONE (Numeric) × [8.0] DIGIT FOUR (Numeric) ÷ [999.0] PERCENT SIGN (Other) ÷ [999.0] LATIN SMALL LETTER B (ALetter) ÷ [0.3] -÷ 0033 × 0061 ÷ # ÷ [0.2] DIGIT THREE (Numeric) × [10.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] -÷ 0063 × 002E × 0064 ÷ # ÷ [0.2] LATIN SMALL LETTER C (ALetter) × [6.0] FULL STOP (MidNumLet) × [7.0] LATIN SMALL LETTER D (ALetter) ÷ [0.3] -÷ 0043 × 002E × 0064 ÷ # ÷ [0.2] LATIN CAPITAL LETTER C (ALetter) × [6.0] FULL STOP (MidNumLet) × [7.0] LATIN SMALL LETTER D (ALetter) ÷ [0.3] -÷ 0063 × 002E × 0044 ÷ # ÷ [0.2] LATIN SMALL LETTER C (ALetter) × [6.0] FULL STOP (MidNumLet) × [7.0] LATIN CAPITAL LETTER D (ALetter) ÷ [0.3] -÷ 0043 × 002E × 0044 ÷ # ÷ [0.2] LATIN CAPITAL LETTER C (ALetter) × [6.0] FULL STOP (MidNumLet) × [7.0] LATIN CAPITAL LETTER D (ALetter) ÷ [0.3] -÷ 2060 ÷ 0063 × 2060 × 0061 × 2060 × 006E × 2060 × 0027 × 2060 × 0074 × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) ÷ [999.0] LATIN SMALL LETTER C (ALetter) × [4.0] WORD JOINER (Format_FE) × [5.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [5.0] LATIN SMALL LETTER N (ALetter) × [4.0] WORD JOINER (Format_FE) × [6.0] APOSTROPHE (Single_Quote) × [4.0] WORD JOINER (Format_FE) × [7.0] LATIN SMALL LETTER T (ALetter) × [4.0] WORD JOINER (Format_FE) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] -÷ 2060 ÷ 0063 × 2060 × 0061 × 2060 × 006E × 2060 × 2019 × 2060 × 0074 × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) ÷ [999.0] LATIN SMALL LETTER C (ALetter) × [4.0] WORD JOINER (Format_FE) × [5.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [5.0] LATIN SMALL LETTER N (ALetter) × [4.0] WORD JOINER (Format_FE) × [6.0] RIGHT SINGLE QUOTATION MARK (MidNumLet) × [4.0] WORD JOINER (Format_FE) × [7.0] LATIN SMALL LETTER T (ALetter) × [4.0] WORD JOINER (Format_FE) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] -÷ 2060 ÷ 0061 × 2060 × 0062 × 2060 × 00AD × 2060 × 0062 × 2060 × 0079 × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [5.0] LATIN SMALL LETTER B (ALetter) × [4.0] WORD JOINER (Format_FE) × [4.0] SOFT HYPHEN (Format_FE) × [4.0] WORD JOINER (Format_FE) × [5.0] LATIN SMALL LETTER B (ALetter) × [4.0] WORD JOINER (Format_FE) × [5.0] LATIN SMALL LETTER Y (ALetter) × [4.0] WORD JOINER (Format_FE) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] -÷ 2060 ÷ 0061 × 2060 ÷ 0024 × 2060 ÷ 002D × 2060 ÷ 0033 × 2060 × 0034 × 2060 × 002C × 2060 × 0035 × 2060 × 0036 × 2060 × 0037 × 2060 × 002E × 2060 × 0031 × 2060 × 0034 × 2060 ÷ 0025 × 2060 ÷ 0062 × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) ÷ [999.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] DOLLAR SIGN (Other) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] HYPHEN-MINUS (Other) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] DIGIT THREE (Numeric) × [4.0] WORD JOINER (Format_FE) × [8.0] DIGIT FOUR (Numeric) × [4.0] WORD JOINER (Format_FE) × [12.0] COMMA (MidNum) × [4.0] WORD JOINER (Format_FE) × [11.0] DIGIT FIVE (Numeric) × [4.0] WORD JOINER (Format_FE) × [8.0] DIGIT SIX (Numeric) × [4.0] WORD JOINER (Format_FE) × [8.0] DIGIT SEVEN (Numeric) × [4.0] WORD JOINER (Format_FE) × [12.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) × [11.0] DIGIT ONE (Numeric) × [4.0] WORD JOINER (Format_FE) × [8.0] DIGIT FOUR (Numeric) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] PERCENT SIGN (Other) × [4.0] WORD JOINER (Format_FE) ÷ [999.0] LATIN SMALL LETTER B (ALetter) × [4.0] WORD JOINER (Format_FE) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] -÷ 2060 ÷ 0033 × 2060 × 0061 × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) ÷ [999.0] DIGIT THREE (Numeric) × [4.0] WORD JOINER (Format_FE) × [10.0] LATIN SMALL LETTER A (ALetter) × [4.0] WORD JOINER (Format_FE) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] -÷ 2060 ÷ 0063 × 2060 × 002E × 2060 × 0064 × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) ÷ [999.0] LATIN SMALL LETTER C (ALetter) × [4.0] WORD JOINER (Format_FE) × [6.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) × [7.0] LATIN SMALL LETTER D (ALetter) × [4.0] WORD JOINER (Format_FE) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] -÷ 2060 ÷ 0043 × 2060 × 002E × 2060 × 0064 × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) ÷ [999.0] LATIN CAPITAL LETTER C (ALetter) × [4.0] WORD JOINER (Format_FE) × [6.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) × [7.0] LATIN SMALL LETTER D (ALetter) × [4.0] WORD JOINER (Format_FE) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] -÷ 2060 ÷ 0063 × 2060 × 002E × 2060 × 0044 × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) ÷ [999.0] LATIN SMALL LETTER C (ALetter) × [4.0] WORD JOINER (Format_FE) × [6.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) × [7.0] LATIN CAPITAL LETTER D (ALetter) × [4.0] WORD JOINER (Format_FE) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] -÷ 2060 ÷ 0043 × 2060 × 002E × 2060 × 0044 × 2060 × 2060 ÷ # ÷ [0.2] WORD JOINER (Format_FE) ÷ [999.0] LATIN CAPITAL LETTER C (ALetter) × [4.0] WORD JOINER (Format_FE) × [6.0] FULL STOP (MidNumLet) × [4.0] WORD JOINER (Format_FE) × [7.0] LATIN CAPITAL LETTER D (ALetter) × [4.0] WORD JOINER (Format_FE) × [4.0] WORD JOINER (Format_FE) ÷ [0.3] -÷ 0061 ÷ 1F1E6 ÷ 0062 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) ÷ [999.0] LATIN SMALL LETTER B (ALetter) ÷ [0.3] -÷ 1F1F7 × 1F1FA ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER R (Regional_Indicator) × [13.3] REGIONAL INDICATOR SYMBOL LETTER U (Regional_Indicator) ÷ [0.3] -÷ 1F1F7 × 1F1FA × 1F1F8 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER R (Regional_Indicator) × [13.3] REGIONAL INDICATOR SYMBOL LETTER U (Regional_Indicator) × [13.3] REGIONAL INDICATOR SYMBOL LETTER S (Regional_Indicator) ÷ [0.3] -÷ 1F1F7 × 1F1FA × 1F1F8 × 1F1EA ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER R (Regional_Indicator) × [13.3] REGIONAL INDICATOR SYMBOL LETTER U (Regional_Indicator) × [13.3] REGIONAL INDICATOR SYMBOL LETTER S (Regional_Indicator) × [13.3] REGIONAL INDICATOR SYMBOL LETTER E (Regional_Indicator) ÷ [0.3] -÷ 1F1F7 × 1F1FA ÷ 200B ÷ 1F1F8 × 1F1EA ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER R (Regional_Indicator) × [13.3] REGIONAL INDICATOR SYMBOL LETTER U (Regional_Indicator) ÷ [999.0] ZERO WIDTH SPACE (Other) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER S (Regional_Indicator) × [13.3] REGIONAL INDICATOR SYMBOL LETTER E (Regional_Indicator) ÷ [0.3] +÷ 000D × 000A ÷ 0061 ÷ 000A ÷ 0308 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) × [3.0] <LINE FEED (LF)> (LF) ÷ [3.1] LATIN SMALL LETTER A (ALetter) ÷ [3.2] <LINE FEED (LF)> (LF) ÷ [3.1] COMBINING DIAERESIS (Extend_FE) ÷ [0.3] +÷ 0061 × 0308 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] COMBINING DIAERESIS (Extend_FE) ÷ [0.3] +÷ 0020 × 200D ÷ 0646 ÷ # ÷ [0.2] SPACE (Other) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [999.0] ARABIC LETTER NOON (ALetter) ÷ [0.3] +÷ 0646 × 200D ÷ 0020 ÷ # ÷ [0.2] ARABIC LETTER NOON (ALetter) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [999.0] SPACE (Other) ÷ [0.3] +÷ 0041 × 0041 × 0041 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [5.0] LATIN CAPITAL LETTER A (ALetter) × [5.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 0041 × 003A × 0041 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [6.0] COLON (MidLetter) × [7.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 0041 ÷ 003A ÷ 003A ÷ 0041 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 05D0 × 0027 ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [7.1] APOSTROPHE (Single_Quote) ÷ [0.3] ÷ 05D0 × 0022 × 05D0 ÷ # ÷ [0.2] HEBREW LETTER ALEF (Hebrew_Letter) × [7.2] QUOTATION MARK (Double_Quote) × [7.3] HEBREW LETTER ALEF (Hebrew_Letter) ÷ [0.3] -÷ 1F1E6 × 1F1E7 × 1F1E8 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) × [13.3] REGIONAL INDICATOR SYMBOL LETTER B (Regional_Indicator) × [13.3] REGIONAL INDICATOR SYMBOL LETTER C (Regional_Indicator) ÷ [0.3] -÷ 1F1E6 × 200D × 1F1E7 × 1F1E8 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) × [4.0] ZERO WIDTH JOINER (Extend_FE) × [13.3] REGIONAL INDICATOR SYMBOL LETTER B (Regional_Indicator) × [13.3] REGIONAL INDICATOR SYMBOL LETTER C (Regional_Indicator) ÷ [0.3] -÷ 1F1E6 × 1F1E7 × 200D × 1F1E8 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (Regional_Indicator) × [13.3] REGIONAL INDICATOR SYMBOL LETTER B (Regional_Indicator) × [4.0] ZERO WIDTH JOINER (Extend_FE) × [13.3] REGIONAL INDICATOR SYMBOL LETTER C (Regional_Indicator) ÷ [0.3] -÷ 0020 × 200D ÷ 0646 ÷ # ÷ [0.2] SPACE (Other) × [4.0] ZERO WIDTH JOINER (Extend_FE) ÷ [999.0] ARABIC LETTER NOON (ALetter) ÷ [0.3] -÷ 0646 × 200D ÷ 0020 ÷ # ÷ [0.2] ARABIC LETTER NOON (ALetter) × [4.0] ZERO WIDTH JOINER (Extend_FE) ÷ [999.0] SPACE (Other) ÷ [0.3] +÷ 0041 × 0030 × 0030 × 0041 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [9.0] DIGIT ZERO (Numeric) × [8.0] DIGIT ZERO (Numeric) × [10.0] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 0030 × 002C × 0030 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) × [12.0] COMMA (MidNum) × [11.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 0030 ÷ 002C ÷ 002C ÷ 0030 ÷ # ÷ [0.2] DIGIT ZERO (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [999.0] COMMA (MidNum) ÷ [999.0] DIGIT ZERO (Numeric) ÷ [0.3] +÷ 3031 × 3031 ÷ # ÷ [0.2] VERTICAL KANA REPEAT MARK (Katakana) × [13.0] VERTICAL KANA REPEAT MARK (Katakana) ÷ [0.3] +÷ 0041 × 005F × 0030 × 005F × 3031 × 005F ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [13.1] LOW LINE (ExtendNumLet) × [13.2] DIGIT ZERO (Numeric) × [13.1] LOW LINE (ExtendNumLet) × [13.2] VERTICAL KANA REPEAT MARK (Katakana) × [13.1] LOW LINE (ExtendNumLet) ÷ [0.3] +÷ 0041 × 005F × 005F × 0041 ÷ # ÷ [0.2] LATIN CAPITAL LETTER A (ALetter) × [13.1] LOW LINE (ExtendNumLet) × [13.1] LOW LINE (ExtendNumLet) × [13.2] LATIN CAPITAL LETTER A (ALetter) ÷ [0.3] +÷ 1F1E6 × 1F1E7 ÷ 1F1E8 ÷ 0062 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [15.0] REGIONAL INDICATOR SYMBOL LETTER B (RI) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER C (RI) ÷ [999.0] LATIN SMALL LETTER B (ALetter) ÷ [0.3] +÷ 0061 ÷ 1F1E6 × 1F1E7 ÷ 1F1E8 ÷ 0062 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [16.0] REGIONAL INDICATOR SYMBOL LETTER B (RI) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER C (RI) ÷ [999.0] LATIN SMALL LETTER B (ALetter) ÷ [0.3] +÷ 0061 ÷ 1F1E6 × 1F1E7 × 200D ÷ 1F1E8 ÷ 0062 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [16.0] REGIONAL INDICATOR SYMBOL LETTER B (RI) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER C (RI) ÷ [999.0] LATIN SMALL LETTER B (ALetter) ÷ [0.3] +÷ 0061 ÷ 1F1E6 × 200D × 1F1E7 ÷ 1F1E8 ÷ 0062 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) × [16.0] REGIONAL INDICATOR SYMBOL LETTER B (RI) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER C (RI) ÷ [999.0] LATIN SMALL LETTER B (ALetter) ÷ [0.3] +÷ 0061 ÷ 1F1E6 × 1F1E7 ÷ 1F1E8 × 1F1E9 ÷ 0062 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [16.0] REGIONAL INDICATOR SYMBOL LETTER B (RI) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER C (RI) × [16.0] REGIONAL INDICATOR SYMBOL LETTER D (RI) ÷ [999.0] LATIN SMALL LETTER B (ALetter) ÷ [0.3] +÷ 261D × 1F3FB ÷ 261D ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [14.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3] +÷ 1F466 × 1F3FB ÷ # ÷ [0.2] BOY (EBG) × [14.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ 200D × 1F466 × 1F3FB ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [3.3] BOY (EBG) × [14.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3] +÷ 200D × 2640 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [3.3] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3] +÷ 200D × 1F466 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_FE) × [3.3] BOY (EBG) ÷ [0.3] +÷ 1F466 ÷ 1F466 ÷ # ÷ [0.2] BOY (EBG) ÷ [999.0] BOY (EBG) ÷ [0.3] +÷ 0061 × 0308 × 200D × 0308 × 0062 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [4.0] COMBINING DIAERESIS (Extend_FE) × [4.0] ZERO WIDTH JOINER (ZWJ_FE) × [4.0] COMBINING DIAERESIS (Extend_FE) × [5.0] LATIN SMALL LETTER B (ALetter) ÷ [0.3] ÷ 0031 ÷ 003A ÷ 003A ÷ 0031 ÷ # ÷ [0.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] ÷ 0031 × 005F × 0031 ÷ 003A ÷ 003A ÷ 0031 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [13.1] LOW LINE (ExtendNumLet) × [13.2] DIGIT ONE (Numeric) ÷ [999.0] COLON (MidLetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] ÷ 0031 × 005F × 0061 ÷ 003A ÷ 003A ÷ 0031 ÷ # ÷ [0.2] DIGIT ONE (Numeric) × [13.1] LOW LINE (ExtendNumLet) × [13.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] COLON (MidLetter) ÷ [999.0] DIGIT ONE (Numeric) ÷ [0.3] @@ -1510,6 +2080,6 @@ ÷ 0061 × 005F × 0031 ÷ 002C ÷ 002C ÷ 0061 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [13.1] LOW LINE (ExtendNumLet) × [13.2] DIGIT ONE (Numeric) ÷ [999.0] COMMA (MidNum) ÷ [999.0] COMMA (MidNum) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] ÷ 0061 × 005F × 0061 ÷ 002C ÷ 002C ÷ 0061 ÷ # ÷ [0.2] LATIN SMALL LETTER A (ALetter) × [13.1] LOW LINE (ExtendNumLet) × [13.2] LATIN SMALL LETTER A (ALetter) ÷ [999.0] COMMA (MidNum) ÷ [999.0] COMMA (MidNum) ÷ [999.0] LATIN SMALL LETTER A (ALetter) ÷ [0.3] # -# Lines: 1489 +# Lines: 2057 # # EOF diff --git a/tests/data/line-break-exceptions.lisp-expr b/tests/data/line-break-exceptions.lisp-expr index ad393a8337..944337aab4 100644 --- a/tests/data/line-break-exceptions.lisp-expr +++ b/tests/data/line-break-exceptions.lisp-expr @@ -20,8 +20,8 @@ "× 002F ÷ 0030 ÷" ; "/0" UAX#14 25.14: SY × NU "× 002F × 0308 ÷ 0030 ÷" ; "/<combining diaresis>0" UAX#14 25.14: SY × NU "× 0065 × 0071 × 0075 × 0061 × 006C × 0073 × 0020 × 002E ÷ 0033 × 0035 × 0020 ÷ 0063 × 0065 × 006E × 0074 × 0073 ÷" ; "equals .35 cents" UAX#14 25.12: IS × NU - "× 0063 × 006F × 0064 × 0065 ÷ 005C ÷ 0028 × 0073 ÷ 005C × 0029 ÷" ; "code\(s\)" UAX#14 25.9: PR × OP - "× 0063 × 006F × 0064 × 0065 ÷ 005C ÷ 007B × 0073 ÷ 005C × 007D ÷" ; "code\{s\}" UAX#14 25.9: PR × OP + "× 0063 × 006F × 0064 × 0065 × 005C ÷ 0028 × 0073 × 005C × 0029 ÷" ; "code\(s\)" UAX#14 25.9: PR × OP + "× 0063 × 006F × 0064 × 0065 × 005C ÷ 007B × 0073 × 005C × 007D ÷" ; "code\{s\}" UAX#14 25.9: PR × OP "× 0061 × 002E ÷ 0032 × 0020 ÷" ; "a.2 " UAX#14 25.12: IS × NU "× 0061 × 002E ÷ 0032 × 0020 ÷ 0915 ÷" ; "a.2 क" UAX#14 25.12: IS × NU "× 0061 × 002E ÷ 0032 × 0020 ÷ 672C ÷" ; "a.2 本" UAX#14 25.12: IS × NU diff --git a/tests/deadline.impure.lisp b/tests/deadline.impure.lisp index d03506d487..e797d9123c 100644 --- a/tests/deadline.impure.lisp +++ b/tests/deadline.impure.lisp @@ -190,3 +190,209 @@ (sb-sys:cancel-deadline condition)))) (sb-sys:with-deadline (:seconds .1) (sleep 1))) sb-sys:deadline-timeout)) + +(defmacro timestamp (string &optional mutex) + (declare (ignorable string mutex)) + #+nil + `(let ((s ,string)) + (sb-sys:with-pinned-objects (s) + ,(if mutex + `(alien-funcall (extern-alien "lisp_mutex_event1" (function void system-area-pointer system-area-pointer)) + (sb-sys:vector-sap s) + (sb-sys:vector-sap (or (mutex-name ,mutex) "unnamed"))) + `(alien-funcall (extern-alien "lisp_mutex_event" (function void system-area-pointer)) + (sb-sys:vector-sap s)))))) + +;;; I observed (at least) four different ways this next test can flake: +;;; +;;; 1. one of the first CONDITION-WAITs at the initial deadline can be spuriously woken. +;;; This is easy to see: +;;; Thread A Thread B +;;; -------- -------- +;;; mutex.acquire +;;; cv.wait +;;; set wakeup token +;;; mutex.release +;;; mutex.acquire +;;; cv.wait +;;; set wakeup token +;;; mutex.release +;;; sys_futex +;;; sys_futex +;;; (* no waiting - "wrong" token *) +;;; So this causes the (:UNKNOWN :UNKNOWN) result for one thread, +;;; because it never enters its deadline handler and because the customary +;;; ("obligatory" one might say) loop around condition-wait is absent. +;;; This is so common that it is no longer considered a failure. +;;; +;;; 2. one of the threads could be scheduled entirely before the other- +;;; that is, it runs from start to finish before the other thread does anything. +;;; This causes them both to conclude they acquired the mutex, +;;; though the deadline handlers were completely nonoverlapping. +;;; +;;; 3. one of the calls to SYS_futex with a timeout can wait significantly more than +;;; requested. This essentially reduces to case 2 but in a more convoluted way, +;;; which I've somewhat mitigated this by scaling up the timeouts so that we're +;;; not skating at the edge of the granularity the system is willing to give you. +;;; This mode of flakiness is likely to happen on a cloud compute environment. +;;; +;;; 4. the deadline handler can be invoked twice in one thread because +;;; - I don't know why. +;;; +;;; Here's an example with MUTEX_EVENTRECORDING #defined that was +;;; considered a "failure": +;;; [0.000000000] main thread: try-mutex: acquired 'Make-Thread Lock' +;;; [0.000038478] main thread: released 'Make-Thread Lock' +;;; [0.000053675] main thread: try-mutex: acquired 'Make-Thread Lock' +;;; [0.000068255] main thread: released 'Make-Thread Lock' +;;; [0.000069415] main thread: try-mutex: acquired 'gate sem mutex' +;;; [0.000069781] main thread: released 'gate sem mutex' +;;; [0.000071536] main thread: start futex wait 'thread result lock' +;;; [0.000094761] B: try-mutex: acquired 'gate sem mutex' +;;; [0.000095494] B: released 'gate sem mutex' +;;; [0.000096646] B: deadline established +;;; [0.000097026] B: try-mutex: acquired 'testmut' +;;; [0.000097931] B: released 'testmut' +;;; [0.000098251] B: start futex timedwait 'testcv' timeout 300000 +;;; [0.300161614] B: back from sys_futex 'testcv' +;;; [0.300163763] B: try-mutex: acquired 'testmut' +;;; [0.300172833] B: enter deadline handler +;;; [0.300173184] B: start sleep +;;; [0.601937423] A: try-mutex: acquired 'gate sem mutex' +;;; [0.601940795] A: released 'gate sem mutex' +;;; [0.601945635] A: deadline established +;;; [0.601952083] A: start futex timedwait 'testmut' timeout 300000 +;;; [0.900264670] B: end sleep +;;; [0.900266124] B: waking futex 'testcv' +;;; [0.900280645] B: waking futex 'testmut' +;;; [0.900285623] B: released 'testmut' +;;; [0.900290563] B: try-mutex: acquired 'thread interruptions lock' +;;; [0.900290777] B: released 'thread interruptions lock' +;;; [0.900292127] B: try-mutex: acquired 'session lock' +;;; [0.900293214] B: released 'session lock' +;;; [0.900293703] B: released 'thread result lock' +;;; [0.900294381] A: back from sys_futex 'testmut' +;;; [0.900296267] A: %wait-for-mutex: acquired 'testmut' +;;; [0.900299208] A: waking futex 'testmut' +;;; [0.900300544] A: released 'testmut' +;;; [0.900301101] A: start futex timedwait 'testcv' timeout 1000 +;;; [0.901358710] A: back from sys_futex 'testcv' +;;; [0.901359680] A: try-mutex: acquired 'testmut' +;;; [0.901369935] A: enter deadline handler +;;; [0.901370203] A: start sleep +;;; [1.501418757] A: end sleep +;;; [1.501419570] A: waking futex 'testcv' +;;; [1.501456896] A: released 'testmut' +;;; [1.501460896] A: try-mutex: acquired 'thread interruptions lock' +;;; [1.501461171] A: released 'thread interruptions lock' +;;; [1.501462039] A: try-mutex: acquired 'session lock' +;;; [1.501463001] A: released 'session lock' +;;; [1.501463544] A: waking futex 'thread result lock' +;;; [1.501465881] A: released 'thread result lock' +;;; [1.501474477] main thread: back from sys_futex 'thread result lock' +;;; [1.501476447] main thread: %wait-for-mutex: acquired 'thread result lock' +;;; [1.501477283] main thread: waking futex 'thread result lock' +;;; [1.501478429] main thread: released 'thread result lock' +;;; [1.501479467] main thread: try-mutex: acquired 'thread result lock' +;;; [1.501479600] main thread: released 'thread result lock' +;;; +;;; Basically I give up trying to fix this test any more. +(defun signal-dealine-check-interrupt-enablement () + (let ((mutex (sb-thread:make-mutex :name "testmut")) + (waitq (sb-thread:make-waitqueue :name "testcv")) + (A-holds? :unknown) + (B-holds? :unknown) + (A-interrupts-enabled? :unknown) + (B-interrupts-enabled? :unknown) + (gate (sb-thread:make-semaphore :name "testsem")) + (initial-deadline .3) + (sleep-amount .6) + (A) + (B)) + ;; The gate semaphore is just a half-assed attempt to trigger both worker threads + ;; to start running their bodies at the exact same time. If they don't do that, + ;; then it's entirely possible that one thread gets run start to finish before + ;; the other thread does anything at all. So obviously the test will fail. + (let ((m (sb-thread::semaphore-mutex gate))) + (setf (sb-thread:mutex-name m) "gate sem mutex")) + (let ((cv (sb-thread::semaphore-queue gate))) + (setf (sb-thread:waitqueue-name cv) "gate sem cv")) + #+nil (alien-funcall (extern-alien "lisp_mutex_start_eventrecording" (function void))) + (setq A (sb-thread:make-thread + (lambda () + (sb-thread:wait-on-semaphore gate) + (handler-bind + ((sb-sys:deadline-timeout + (lambda (c) + (timestamp "enter deadline handler") + ;; We came here through the call to DECODE-TIMEOUT + ;; in CONDITION-WAIT; hence both here are supposed + ;; to evaluate to T. + (setq A-holds? (sb-thread:holding-mutex-p mutex)) + (setq A-interrupts-enabled? + sb-sys:*interrupts-enabled*) + (timestamp "start sleep") + (sleep sleep-amount) + (timestamp "end sleep") + (sb-thread:condition-broadcast waitq) + (sb-sys:defer-deadline 10.0 c) + (timestamp "leave deadline handler")))) + (sb-sys:with-deadline (:seconds initial-deadline) + (timestamp "deadline established") + (sb-thread:with-mutex (mutex) + (sb-thread:condition-wait waitq mutex))))) + :name "A")) + (setq B (sb-thread:make-thread + (lambda () + (sb-thread:wait-on-semaphore gate) + (handler-bind + ((sb-sys:deadline-timeout + (lambda (c) + (timestamp "enter deadline handler") + ;; We came here through the call to DECODE-TIMEOUT + ;; in CONDITION-WAIT (contended case of + ;; reaquiring the mutex) - so the former will + ;; be NIL, but interrupts should still be enabled. + (setq B-holds? (sb-thread:holding-mutex-p mutex)) + (setq B-interrupts-enabled? + sb-sys:*interrupts-enabled*) + (timestamp "start sleep") + (sleep sleep-amount) + (timestamp "end sleep") + (sb-thread:condition-broadcast waitq) + (sb-sys:defer-deadline 10.0 c) + (timestamp "leave deadline handler")))) + (sb-sys:with-deadline (:seconds initial-deadline) + (timestamp "deadline established") + (sb-thread:with-mutex (mutex) + (sb-thread:condition-wait waitq mutex))))) + :name "B")) + (sb-thread:signal-semaphore gate 3) + (sb-thread:join-thread A) + (sb-thread:join-thread B) + #+nil (alien-funcall (extern-alien "lisp_mutex_done_eventrecording" (function void))) + (let ((A-result (list A-holds? A-interrupts-enabled?)) + (B-result (list B-holds? B-interrupts-enabled?))) + ;; We also check some subtle behaviour w.r.t. whether a deadline + ;; handler in CONDITION-WAIT got the mutex, or not. This is most + ;; probably very internal behaviour (so user should not depend + ;; on it) -- I added the testing here just to manifest current + ;; behaviour. + (cond ((equal A-result '(t t)) + (or (equal B-result '(nil t)) + (equal B-result '(:unknown :unknown)) + (error "thread B result: ~s" B-result))) + ((equal B-result '(t t)) + (or (equal A-result '(nil t)) + (equal A-result '(:unknown :unknown)) + (error "thread A result: ~s" A-result))) + (t + (error "Failure: fell through with A: ~S, B: ~S" + A-result + B-result)))))) + +;;; Test from git rev 5e55f426de8fa579a0d6cfbfb3ac5433d530d3c9 formerly in threads.impure +(test-util:with-test (:name (:deadline :interrupts-enabled) :skipped-on (:not :sb-thread)) + ;; I cranked this up to 1000 (and ran it on lots of machines) to get examples of failure, + ;; but that's more than a reasonable amount of time to spend in the test. + (loop repeat 2 do (signal-dealine-check-interrupt-enablement))) diff --git a/tests/deadlock.impure.lisp b/tests/deadlock.impure.lisp index 8bc7d95624..95100d00f6 100644 --- a/tests/deadlock.impure.lisp +++ b/tests/deadlock.impure.lisp @@ -1,4 +1,144 @@ -#-sb-thread (sb-ext:exit :code 104) +#-sb-thread (invoke-restart 'run-tests::skip-file) + +(import '(sb-thread:join-thread + sb-thread:make-mutex + sb-thread:make-semaphore + sb-thread:make-thread + sb-thread:signal-semaphore + sb-thread:thread-deadlock + sb-thread:wait-on-semaphore + sb-thread:with-mutex)) + +(when (sb-sys:find-dynamic-foreign-symbol-address "show_gc_generation_throughput") + (setf (extern-alien "show_gc_generation_throughput" int) 0)) + +(with-test (:name :deadlock-detection.1) + (loop + repeat 1000 + do (flet ((test (ma mb sa sb) + (lambda () + (handler-case + (with-mutex (ma) + (signal-semaphore sa) + (wait-on-semaphore sb) + (with-mutex (mb) + :ok)) + (thread-deadlock (e) + ;; (assert (plusp (length ...))) prevents + ;; flushing. + (assert (plusp (length (princ-to-string e)))) + :deadlock))))) + (let* ((m1 (make-mutex :name "M1")) + (m2 (make-mutex :name "M2")) + (s1 (make-semaphore :name "S1")) + (s2 (make-semaphore :name "S2")) + (t1 (make-thread (test m1 m2 s1 s2) :name "T1")) + (t2 (make-thread (test m2 m1 s2 s1) :name "T2"))) + ;; One will deadlock, and the other will then complete normally. + (let ((res (list (join-thread t1) + (join-thread t2)))) + (assert (or (equal '(:deadlock :ok) res) + (equal '(:ok :deadlock) res)))))))) + +(with-test (:name :deadlock-detection.2) + (let* ((m1 (make-mutex :name "M1")) + (m2 (make-mutex :name "M2")) + (s1 (make-semaphore :name "S1")) + (s2 (make-semaphore :name "S2")) + (t1 (make-thread + (lambda () + (with-mutex (m1) + (signal-semaphore s1) + (wait-on-semaphore s2) + (with-mutex (m2) + :ok))) + :name "T1"))) + (prog (err) + :retry + (handler-bind ((thread-deadlock + (lambda (e) + (unless err + ;; Make sure we can print the condition + ;; while it's active + (let ((*print-circle* nil)) + (setf err (princ-to-string e))) + (go :retry))))) + (when err + (sleep 1)) + (assert (eq :ok (with-mutex (m2) + (unless err + (signal-semaphore s2) + (wait-on-semaphore s1) + (sleep 1)) + (with-mutex (m1) + :ok))))) + (assert (stringp err))) + (assert (eq :ok (join-thread t1))))) + +(with-test (:name :deadlock-detection.3) + (let* ((m1 (make-mutex :name "M1")) + (m2 (make-mutex :name "M2")) + (s1 (make-semaphore :name "S1")) + (s2 (make-semaphore :name "S2")) + (t1 (make-thread + (lambda () + (with-mutex (m1) + (signal-semaphore s1) + (wait-on-semaphore s2) + (with-mutex (m2) + :ok))) + :name "T1"))) + ;; Currently we don't consider it a deadlock + ;; if there is a timeout in the chain. + (assert (eq :deadline + (handler-case + (with-mutex (m2) + (signal-semaphore s2) + (wait-on-semaphore s1) + (sleep 1) + (sb-sys:with-deadline (:seconds 0.1) + (with-mutex (m1) + :ok))) + (sb-sys:deadline-timeout () + :deadline) + (thread-deadlock () + :deadlock)))) + (assert (eq :ok (join-thread t1))))) + +(with-test (:name (:deadlock-detection :interrupts) + :broken-on :win32) + (let* ((m1 (sb-thread:make-mutex :name "M1")) + (m2 (sb-thread:make-mutex :name "M2")) + (t1-can-go (sb-thread:make-semaphore :name "T1 can go")) + (t2-can-go (sb-thread:make-semaphore :name "T2 can go")) + (t1 (sb-thread:make-thread + (lambda () + (sb-thread:with-mutex (m1) + (sb-thread:wait-on-semaphore t1-can-go) + :ok1)) + :name "T1")) + (t2 (sb-thread:make-thread + (lambda () + (sb-ext:wait-for (eq t1 (sb-thread:mutex-owner m1))) + (sb-thread:with-mutex (m1 :wait-p t) + (sb-thread:wait-on-semaphore t2-can-go) + :ok2)) + :name "T2"))) + (sb-ext:wait-for (eq m1 (sb-thread::thread-waiting-for t2))) + (sb-thread:interrupt-thread t2 (lambda () + (sb-thread:with-mutex (m2 :wait-p t) + (sb-ext:wait-for + (eq m2 (sb-thread::thread-waiting-for t1))) + (sb-thread:signal-semaphore t2-can-go)))) + (sb-ext:wait-for (eq t2 (sb-thread:mutex-owner m2))) + (sb-thread:interrupt-thread t1 (lambda () + (sb-thread:with-mutex (m2 :wait-p t) + (sb-thread:signal-semaphore t1-can-go)))) + ;; both threads should finish without a deadlock or deadlock + ;; detection error + (let ((res (list (sb-thread:join-thread t1) + (sb-thread:join-thread t2)))) + (assert (equal '(:ok1 :ok2) res))))) (with-test (:name (:deadlock-detection :gc)) ;; To semi-reliably trigger the error (in SBCL's where) @@ -22,39 +162,216 @@ (sb-thread:join-thread t2)))) (assert (equal '(:ok :ok) res))))) +(defun clock-gettime () + (sb-int:dx-let ((a (make-array 2 :element-type 'sb-ext:word))) + (alien-funcall (extern-alien "clock_gettime" (function void int system-area-pointer)) + 0 (sb-sys:vector-sap a)) + (values (aref a 0) (aref a 1)))) + +(defun seconds-since (start_sec start_nsec) + (sb-int:dx-let ((a (make-array 2 :element-type 'sb-ext:word))) + (alien-funcall (extern-alien "clock_gettime" (function void int system-area-pointer)) + 0 (sb-sys:vector-sap a)) + (+ (/ (coerce (- (aref a 1) start_nsec) 'double-float) 1000000000) + (- (aref a 0) start_sec)))) + +(defglobal *max-avl-tree-total* 0) +(defglobal *max-avl-tree-born* 0) +(defglobal *max-avl-tree-running* 0) +(defglobal *max-avl-tree-died* 0) + +(defun avl-maptree (fun tree) + (sb-int:named-let recurse ((node tree)) + (when node + (funcall fun node) + (recurse (sb-thread::avlnode-left node)) + (recurse (sb-thread::avlnode-right node))))) + +(defun thread-count (&optional (tree sb-thread::*all-threads*)) + (let ((born 0) + (running 0) + (died 0)) + #-pauseless-thread-start (setq running (sb-thread::avl-count tree)) + #+pauseless-thread-start + (sb-int:dx-flet ((mapfun (node) + (ecase (sb-thread::thread-%visible (sb-thread::avlnode-data node)) + (0 (incf born)) ; "can't happen" ? + (1 (incf running)) + (-1 (incf died))))) + (avl-maptree #'mapfun tree)) + (let ((total (+ born running died))) + (macrolet ((max-into (global mine) + `(let ((old ,global)) + (loop + (when (<= ,mine old) (return)) + (let ((actual (cas ,global old ,mine))) + (if (>= actual old) (return)) (setq old actual)))))) + (max-into *max-avl-tree-total* total) + (max-into *max-avl-tree-born* born) + (max-into *max-avl-tree-running* running) + (max-into *max-avl-tree-died* died)) + (list total born running died)))) + +;;; I would optimistically guess that this test can no longer fail, +;;; even for :win32, since there is no lisp mutex around *all-threads*. +;;; (There is still the C one) +;;; +;;; With the sesion lock acquisition as part of thread startup, +;;; but with a patch that allows the thread creator to run while +;;; the child is waiting, all this test managed to do was create thousands +;;; of threads all blocked on the *SESSION-LOCK*, because MAKE-THREAD could +;;; return the created thread did anything at all. +;;; The way that happens is as follows: +;;; thread 0: grab session lock, initiate GC +;;; ... return from GC but not release session lock yet +;;; thread 1: start sleeping +;;; thread 2: try to grab session lock, enter a wait +;;; thread 3: start sleeping +;;; thread 4: try to grab session lock, enter a wait +;;; thread 5: start sleeping +;;; ... +;;; So the number of threads running simultaneously depends entirely on when +;;; the even numbered threads get CPU time to release the session lock. +;;; +;;; That said, I was curious why this test complete _so_ much slowly +;;; with faster thread start, and more quickly with slower thread start. +;;; Enabling the :deadlock-test-timing feature shows: +;;; +;;; Maxima attained: 2923 1 2923 2916 current=(2923 0 1 2922) +;;; ---- ---- +;;; tree node count ^ ^ nunber of threads in "run" state +;;; +;;; The answer is obvious: the time spent in each GC is proportional to +;;; the number of threads, and with faster thread start, we can actually +;;; achieve *nearly* 3000 threads running at the same time. +;;; With each thread allocating slightly over 4MiB of memory, that's +;;; about 12GiB of additional memory for the OS to manage which has +;;; a 2nd-order effect on our runtime as well. +;;; Contrast this with the "old way" where we were essentially +;;; firing off two threads at a time and letting them finish +;;; before getting to the next two. + +;; (pushnew :deadlock-test-timing *features*) + +(defglobal *message-in-counter* 0) +(defglobal *message-out-counter* 0) +(declaim (fixnum *message-in-counter* *message-out-counter*)) +(defparameter *huge-n-threads* 3000) +(defglobal *messages* (make-array (* 2 *huge-n-threads*))) +(declaim (simple-vector *messages*)) + +(defun show-queued-messages () + (loop while (< *message-out-counter* *message-in-counter*) + do (let ((args (aref *messages* *message-out-counter*))) + ;; If a store did not get into the array yet, bail out + ;; and hope it shows up by the next time we're here. + (when (eql args 0) + (return-from show-queued-messages)) + (apply #'format t (concatenate 'string "~4d " (car args)) (cdr args)) + (terpri)) + (incf *message-out-counter*))) + +;;; Atomically log a message for output by the main thread (to avoid interleaving) +(defun message (control &rest args) + (let* ((data (cons control args)) + (index (atomic-incf *message-in-counter*))) + (setf (aref *messages* index) data))) + +#+darwin +(test-util::disable-profiling) + +;;; This encounters the "backing off for retry" error if attempting +;;; to start too many threads. +(defparameter *max-runnable-threads* #+x86-64 100 #-x86-64 5) (with-test (:name :gc-deadlock :broken-on :win32) - (write-line "WARNING: THIS TEST WILL HANG ON FAILURE!") + #+nil (write-line "WARNING: THIS TEST WILL HANG ON FAILURE!") ;; Prior to 0.9.16.46 thread exit potentially deadlocked the ;; GC due to *all-threads-lock* and session lock. On earlier ;; versions and at least on one specific box this test is good enough ;; to catch that typically well before the 1500th iteration. (loop with i = 0 - with n = 3000 + with n = *huge-n-threads* + with running = nil while (< i n) do + (show-queued-messages) (incf i) + #-deadlock-test-timing (when (zerop (mod i 100)) (write-char #\.) (force-output)) + (when (> (length running) *max-runnable-threads*) + (let ((last (car (last running)))) + (sb-thread:join-thread last) + (setq running (nbutlast running)))) (handler-case + (push (if (oddp i) (make-join-thread - (lambda () - (sleep (random 0.001))) + (lambda (i &aux (rand (random 0.001))) + (declare (ignorable i)) + #-deadlock-test-timing + (sleep rand) + #+deadlock-test-timing + (multiple-value-bind (t0_sec t0_nsec) (clock-gettime) + (message "Sleep ~f, threads=~d" i rand (thread-count)) + (sleep rand) + (message "Done (~f sec)" i (seconds-since t0_sec t0_nsec)))) + :arguments i :name (format nil "SLEEP-~D" i)) (make-join-thread - (lambda () + (lambda (i) + (declare (ignorable i)) ;; KLUDGE: what we are doing here is explicit, ;; but the same can happen because of a regular ;; MAKE-THREAD or LIST-ALL-THREADS, and various ;; session functions. - (sb-thread::with-all-threads-lock + #-deadlock-test-timing + (progn + (sb-thread::with-session-lock (sb-thread::*session*) + (sb-ext:gc))) + #+deadlock-test-timing + (sb-int:binding* (((t0_sec t0_nsec) (clock-gettime)) + ((t1_sec t1_nsec wait-time) (values nil nil nil))) + (message "GC, threads=~d" i (thread-count)) (sb-thread::with-session-lock (sb-thread::*session*) - (sb-ext:gc)))) + (setq wait-time (seconds-since t0_sec t0_nsec)) + (multiple-value-setq (t1_sec t1_nsec) (clock-gettime)) + (sb-ext:gc)) + (let ((gc-time (seconds-since t1_sec t1_nsec))) + (message "GC Done (~f wait + ~f gc)~A" + i wait-time gc-time + (if (> gc-time .5) "***" ""))))) + :arguments i :name (format nil "GC-~D" i))) + running) (error (e) + ;; Not sure why this needs to back off - at most it was running 2 threads. (format t "~%error creating thread ~D: ~A -- backing off for retry~%" i e) (sleep 0.1) - (incf i))))) + (incf i)))) + #+deadlock-test-timing + (progn + (format t "~&Main thread: draining messages~%") (force-output) + (loop while (< (cas *message-out-counter* 0 0) (length *messages*)) + do (show-queued-messages) + (sleep .05)) + (format t "Maxima attained: ~d ~d ~d ~d current=~d~%" + *max-avl-tree-total* + *max-avl-tree-born* + *max-avl-tree-running* + *max-avl-tree-died* + (thread-count)) + (sb-thread:make-thread #'list :name "list") + (format t "After another make-thread: current=~d~%" (thread-count)) + (let (gc-times) + (sb-int:dovector (x *messages*) + (when (string= (first x) "GC Done" :end1 7) + (push (fourth x) gc-times))) + (let ((min (reduce #'min gc-times)) + (max (reduce #'max gc-times)) + (sum (reduce #'+ gc-times))) + (format t "~&GC time: min=~f max=~f avg=~f sum=~f~%" + min max (/ sum (length gc-times)) sum))))) diff --git a/tests/debug.impure.lisp b/tests/debug.impure.lisp index 5a709cd9bb..bad4ca2289 100644 --- a/tests/debug.impure.lisp +++ b/tests/debug.impure.lisp @@ -17,7 +17,16 @@ ;;; The debugger doesn't have any native knowledge of the interpreter (when (eq sb-ext:*evaluator-mode* :interpret) - (sb-ext:exit :code 104)) + (invoke-restart 'run-tests::skip-file)) + +#+(or x86 x86-64) +(with-test (:name :legal-bpt-lra-object) + (sb-int:binding* ((code (sb-kernel:fun-code-header #'read)) + (sap (sb-sys:sap+ (sb-kernel:code-instructions code) 13)) ; random + ((bpt-sap bpt-code-obj) (sb-di::make-bpt-lra sap))) + (declare (ignore bpt-sap)) + ;; This was causing heap corruption + (assert (zerop (sb-kernel:code-jump-table-words bpt-code-obj))))) ;;;; Check that we get debug arglists right. @@ -58,10 +67,42 @@ ,@body) (ignore-errors (untrace ,name))))) +(defun call-collecting-traces (fn trace-arguments) + (let ((traces nil)) + (flet ((collect (depth what when frame values) + (declare (ignore frame)) + (flet ((ensure-readable (x) + (typecase x + (function (sb-impl::%fun-name x)) + (sb-debug::unprintable-object + (sb-debug::unprintable-object-string x)) + (t x)))) + (push (list* depth + (ensure-readable what) + when + (mapcar #'ensure-readable values)) + traces)))) + (unwind-protect + (let ((sb-debug:*trace-report-default* #'collect)) + (eval `(trace ,@trace-arguments)) + (funcall fn)) + (ignore-errors (untrace)) + (assert (null (trace))))) + (nreverse traces))) + +(defmacro collecting-traces ((&rest trace-arguments) &body body) + `(call-collecting-traces (lambda () ,@body) ',trace-arguments)) + (defun trace-this (&optional arg) (declare (ignore arg)) 'ok) +(defun mv-trace-this (&optional arg) + (case arg + (2 (values 'ok "hi")) + (3 (values 'ok "hi" :foo)) + (4 (values 'ok "hi" :foo :bar)))) + (defun trace-fact (n) (if (zerop n) 1 @@ -96,18 +137,37 @@ (lambda (f &rest stuff) (declare (ignore f stuff)))))) +(defparameter *breakpoint-tracing-expectations* + '(:fails-on (or :arm :arm64) + :broken-on (or :freebsd :ppc :ppc64))) + ;;; bug 379 (with-test (:name (trace :encapsulate nil) - :fails-on (or (and :ppc (not :linux)) :sparc :arm64) - :broken-on (or :hppa :freebsd)) + . #.*breakpoint-tracing-expectations*) (let ((output (with-traced-function (trace-this :encapsulate nil) (assert (eq 'ok (trace-this)))))) (assert (search "TRACE-THIS" output)) (assert (search "returned OK" output)))) +(with-test (:name :breakpoint-trace-multival . #.*breakpoint-tracing-expectations*) + (let ((output (with-traced-function (mv-trace-this :encapsulate nil) + (assert (equal (multiple-value-list (mv-trace-this 2)) + '(ok "hi")))))) + (assert (search "MV-TRACE-THIS" output)) + (assert (search "returned OK" output))) + (let ((output (with-traced-function (mv-trace-this :encapsulate nil) + (assert (equal (multiple-value-list (mv-trace-this 3)) + '(ok "hi" :foo)))))) + (assert (search "MV-TRACE-THIS" output)) + (assert (search "returned OK" output))) + (let ((output (with-traced-function (mv-trace-this :encapsulate nil) + (assert (equal (multiple-value-list (mv-trace-this 4)) + '(ok "hi" :foo :bar)))))) + (assert (search "MV-TRACE-THIS" output)) + (assert (search "returned OK" output)))) + (with-test (:name (trace :encapsulate nil :recursive) - :fails-on (or (and :ppc (not :linux)) :sparc :arm64) - :broken-on (or :hppa :freebsd)) + . #.*breakpoint-tracing-expectations*) (let ((output (with-traced-function (trace-fact :encapsulate nil) (assert (= 120 (trace-fact 5)))))) (assert (search "TRACE-FACT" output)) @@ -139,6 +199,439 @@ 1~@ 0~%"))))) +(defvar *collected-traces*) +(defun custom-trace-report (depth what when frame values) + (push (list* depth what when (sb-debug::frame-p frame) values) + *collected-traces*)) + +(with-test (:name (trace :custom-report)) + (let ((*collected-traces* nil)) + (let ((output (with-traced-function (trace-fact :report custom-trace-report) + (trace-fact 2)))) + (assert (zerop (length output))) + (assert (equalp (reverse *collected-traces*) + '((0 trace-fact :enter t 2) + (1 trace-fact :enter t 1) + (2 trace-fact :enter t 0) + (2 trace-fact :exit t 1) + (1 trace-fact :exit t 1) + (0 trace-fact :exit t 2))))))) + +(with-test (:name (trace :anonymous) . #.*breakpoint-tracing-expectations*) + (assert (equalp (call-collecting-traces + (lambda () + (trace-fact 1)) + `(:function ,#'trace-fact :condition (plusp (sb-debug:arg 0)))) + '((0 trace-fact :enter 1) + (0 trace-fact :exit 1))))) + +(defgeneric trace-gf (x) + (:method ((x float)) (+ x (call-next-method))) + (:method :before ((x float)) 'bf) + (:method :around ((x float)) (call-next-method)) + (:method :after ((x float)) 'af) + (:method ((x number)) (+ x (call-next-method))) + (:method :before ((x number)) 'bn) + (:method :around ((x number)) (call-next-method)) + (:method :after ((x number)) 'an) + (:method ((x (eql 21.0))) (call-next-method)) + (:method (x) 0)) + +(with-test (:name (trace :all-methods)) + (assert (equal (collecting-traces (trace-gf :methods t) + (trace-gf 21.0)) + '((0 trace-gf :enter 21.0) + (1 (method trace-gf :around (float)) :enter 21.0) + (2 (method trace-gf :around (number)) :enter 21.0) + (3 (sb-pcl::combined-method trace-gf) :enter 21.0) + (4 (method trace-gf :before (float)) :enter 21.0) + (4 (method trace-gf :before (float)) :exit bf) + (4 (method trace-gf :before (number)) :enter 21.0) + (4 (method trace-gf :before (number)) :exit bn) + (4 (method trace-gf ((eql 21.0))) :enter 21.0) + (5 (method trace-gf (float)) :enter 21.0) + (6 (method trace-gf (number)) :enter 21.0) + (7 (method trace-gf (t)) :enter 21.0) + (7 (method trace-gf (t)) :exit 0) + (6 (method trace-gf (number)) :exit 21.0) + (5 (method trace-gf (float)) :exit 42.0) + (4 (method trace-gf ((eql 21.0))) :exit 42.0) + (4 (method trace-gf :after (number)) :enter 21.0) + (4 (method trace-gf :after (number)) :exit an) + (4 (method trace-gf :after (float)) :enter 21.0) + (4 (method trace-gf :after (float)) :exit af) + (3 (sb-pcl::combined-method trace-gf) :exit 42.0) + (2 (method trace-gf :around (number)) :exit 42.0) + (1 (method trace-gf :around (float)) :exit 42.0) + (0 trace-gf :exit 42.0))))) + +(with-test (:name (trace :methods)) + (assert (equal (collecting-traces ((method trace-gf :after (float)) + (method trace-gf :around (number)) + (method trace-gf (t))) + (trace-gf 42.0)) + '((0 (method trace-gf :around (number)) :enter 42.0) + (1 (method trace-gf (t)) :enter 42.0) + (1 (method trace-gf (t)) :exit 0) + (1 (method trace-gf :after (float)) :enter 42.0) + (1 (method trace-gf :after (float)) :exit af) + (0 (method trace-gf :around (number)) :exit 84.0))))) + +(with-test (:name (trace :methods :encapsulate nil) + . #.*breakpoint-tracing-expectations*) + (assert (equal (collecting-traces (:encapsulate nil + (method trace-gf :after (float)) + (method trace-gf :around (number)) + (method trace-gf (t))) + (trace-gf 42.0)) + '((0 (sb-pcl::fast-method trace-gf :around (number)) :enter 42.0) + (1 (sb-pcl::fast-method trace-gf (t)) :enter "unused argument") + (1 (sb-pcl::fast-method trace-gf (t)) :exit 0) + (1 (sb-pcl::fast-method trace-gf :after (float)) :enter "unused argument") + (1 (sb-pcl::fast-method trace-gf :after (float)) :exit af) + (0 (sb-pcl::fast-method trace-gf :around (number)) :exit 84.0))))) + +(defparameter *expected-trace-gf-number+t-trace* + '((0 (method trace-gf :around (number)) :enter 42.0) + (1 (method trace-gf (t)) :enter 42.0) + (1 (method trace-gf (t)) :exit 0) + (0 (method trace-gf :around (number)) :exit 84.0))) + +(with-test (:name (trace :methods :untrace-some)) + (assert (equal (collecting-traces ((method trace-gf :after (float)) + (method trace-gf :around (number)) + (method trace-gf (t))) + (untrace (method trace-gf :after (float))) + (trace-gf 42.0)) + *expected-trace-gf-number+t-trace*))) + +(with-test (:name (trace :methods :untrace-many)) + (assert (equal (collecting-traces ((method trace-gf :around (number)) + (method trace-gf (t)) + trace-gf :methods t) + (untrace trace-gf) + (trace-gf 42.0)) + *expected-trace-gf-number+t-trace*))) + +(with-test (:name (trace :methods :trace-more)) + (assert (equal (collecting-traces ((method trace-gf (t))) + (eval '(trace (method trace-gf :around (number)))) + (trace-gf 42.0)) + *expected-trace-gf-number+t-trace*))) + +(defgeneric (setf trace-gf) (value) + (:method ((x float)) (call-next-method)) + (:method :before ((x number)) 'before) + (:method ((x number)) x)) + +(with-test (:name (trace :setf-methods)) + (assert (equal (collecting-traces ((method (setf trace-gf) (float)) + (method (setf trace-gf) (number)) + (method (setf trace-gf) :before (number))) + (setf (trace-gf) 42.0)) + '((0 (method (setf trace-gf) :before (number)) :enter 42.0) + (0 (method (setf trace-gf) :before (number)) :exit before) + (0 (method (setf trace-gf) (float)) :enter 42.0) + (1 (method (setf trace-gf) (number)) :enter 42.0) + (1 (method (setf trace-gf) (number)) :exit 42.0) + (0 (method (setf trace-gf) (float)) :exit 42.0))))) + +(defun global-fact (x) + (declare (optimize (debug 3))) ; suppress inlining + (labels ((fact (x) + (flet ((multiply (x y) + (* x y))) + (if (zerop x) + 1 + (multiply x (fact (1- x))))))) + (fact x))) + +(with-test (:name (trace :labels) . #.*breakpoint-tracing-expectations*) + (assert (equal (collecting-traces ((labels fact :in global-fact) + (flet multiply :in global-fact)) + (global-fact 1)) + '((0 (labels fact :in global-fact) :enter 1) + (1 (labels fact :in global-fact) :enter 0) + (1 (labels fact :in global-fact) :exit 1) + (1 (flet multiply :in global-fact) :enter 1 1) + (1 (flet multiply :in global-fact) :exit 1) + (0 (labels fact :in global-fact) :exit 1))))) + +(defgeneric gfact (x) + (:method ((x number)) + (declare (optimize (debug 3))) ; suppress inlining + (flet ((fact (x) (global-fact x))) + (fact x)))) + +(with-test (:name (trace :labels :within-method) + . #.*breakpoint-tracing-expectations*) + (assert (equal (collecting-traces ((flet fact :in (method gfact (number)))) + (gfact 3)) + '((0 (flet fact :in (method gfact (number))) :enter 3) + (0 (flet fact :in (method gfact (number))) :exit 6))))) + +(with-test (:name (trace :labels :within-untraced-method) + . #.*breakpoint-tracing-expectations*) + (assert (equal (collecting-traces ((method gfact (number)) + (flet fact :in (method gfact (number)))) + (untrace (method gfact (number))) + (gfact 3)) + '((0 (flet fact :in (method gfact (number))) :enter 3) + (0 (flet fact :in (method gfact (number))) :exit 6))))) + +(defun trace-foo () + (declare (optimize (debug 3))) + (flet ((body () 'original-foo)) + (body))) + +(defun call-with-trace-foo-redefined (fn) + (let ((original (fdefinition 'trace-foo))) + ;; the local function will be named (FLET BODY) instead of (FLET + ;; BODY :IN TRACE-FOO) unless we use EVAL here. + (eval '(defun trace-foo () + (declare (optimize (debug 3))) + (flet ((body () 'redefined-foo)) + (body)))) + (unwind-protect + (funcall fn) + (setf (fdefinition 'trace-foo) original)))) + +(with-test (:name (trace :labels :redefined) + . #.*breakpoint-tracing-expectations*) + (assert (equal (collecting-traces ((flet body :in trace-foo)) + (trace-foo) + (call-with-trace-foo-redefined 'trace-foo)) + '((0 (flet body :in trace-foo) :enter) + (0 (flet body :in trace-foo) :exit original-foo) + (0 (flet body :in trace-foo) :enter) + (0 (flet body :in trace-foo) :exit redefined-foo))))) + +(defmethod trace-foo-gf () + (declare (optimize (debug 3))) + (flet ((body () 'original-foo)) + (body))) + +(defun call-with-trace-foo-gf-redefined (fn) + ;; using ADD-METHOD and REMOVE-METHOD yields outdated DEBUG-FUN + ;; info, so work around that using EVAL. + (eval '(defmethod trace-foo-gf () + (declare (optimize (debug 3))) + (flet ((body () 'redefined-foo)) + (body)))) + (unwind-protect + (funcall fn) + (eval '(defmethod trace-foo-gf () + (declare (optimize (debug 3))) + (flet ((body () 'original-foo)) + (body)))))) + +(with-test (:name (trace :labels :redefined-method) + . #.*breakpoint-tracing-expectations*) + (assert (equal (collecting-traces ((flet body :in (method trace-foo-gf ()))) + (trace-foo-gf) + (call-with-trace-foo-gf-redefined 'trace-foo-gf)) + '((0 (flet body :in (method trace-foo-gf ())) :enter) + (0 (flet body :in (method trace-foo-gf ())) :exit original-foo) + (0 (flet body :in (method trace-foo-gf ())) :enter) + (0 (flet body :in (method trace-foo-gf ())) :exit redefined-foo))))) + +(defun fn-with-cmac (x) x) + +(define-compiler-macro fn-with-cmac (x) + (declare (ignore x) (optimize (debug 3))) ; suppress flet inlining + (flet ((body () 42)) + (body))) + +(with-test (:name (trace :compiler-macro) + . #.*breakpoint-tracing-expectations*) + (assert (equal (collecting-traces ((compiler-macro fn-with-cmac)) + (compile nil '(lambda () (fn-with-cmac 0)))) + '((0 (compiler-macro fn-with-cmac) :enter (fn-with-cmac 0) "unused argument") + (0 (compiler-macro fn-with-cmac) :exit 42))))) + +(with-test (:name (trace :flet :within-compiler-macro) + . #.*breakpoint-tracing-expectations*) + (assert (equal (collecting-traces ((flet body :in (compiler-macro fn-with-cmac))) + (compile nil '(lambda () (fn-with-cmac 0)))) + '((0 (flet body :in (compiler-macro fn-with-cmac)) :enter) + (0 (flet body :in (compiler-macro fn-with-cmac)) :exit 42))))) + +(defun call-with-compiler-macro-redefined (fn) + (eval `(define-compiler-macro fn-with-cmac (x) + (declare (ignore x) (optimize (debug 3))) + (flet ((body () ''redefined)) + (body)))) + (unwind-protect + (funcall fn) + (eval `(define-compiler-macro fn-with-cmac (x) + (declare (ignore x) (optimize (debug 3))) + (flet ((body () 42)) + (body)))))) + +#-(or ppc ppc64) +(with-test (:name (trace :compiler-macro :redefined) + . #.*breakpoint-tracing-expectations*) + (assert (equal (collecting-traces ((compiler-macro fn-with-cmac) + (flet body :in (compiler-macro fn-with-cmac))) + (compile nil '(lambda () (fn-with-cmac 0))) + (call-with-compiler-macro-redefined + (lambda () (compile nil '(lambda () (fn-with-cmac 0)))))) + '((0 (compiler-macro fn-with-cmac) :enter (fn-with-cmac 0) "unused argument") + (1 (flet body :in (compiler-macro fn-with-cmac)) :enter) + (1 (flet body :in (compiler-macro fn-with-cmac)) :exit 42) + (0 (compiler-macro fn-with-cmac) :exit 42) + (0 (compiler-macro fn-with-cmac) :enter (fn-with-cmac 0) "unused argument") + (1 (flet body :in (compiler-macro fn-with-cmac)) :enter) + (1 (flet body :in (compiler-macro fn-with-cmac)) :exit 'redefined) + (0 (compiler-macro fn-with-cmac) :exit 'redefined))))) + +(defun throw-foo () + (throw 'foo 42)) + +(defun catch-foo () + (catch 'foo (throw-foo))) + +(with-test (:name (trace :non-local-exit)) + (assert (equal (collecting-traces (throw-foo) + (catch-foo)) + '((0 throw-foo :enter) + (0 throw-foo :non-local-exit))))) + +(with-test (:name (trace :non-local-exit :standard-report)) + (let ((output (with-traced-function (throw-foo) + (catch-foo)))) + (assert (search "exited non-locally" output)))) + +(defun trace-inner-function (x) + x) + +(defun trace-outer-function (x) + (declare (optimize (debug 3))) ; avoid tail call optimization + (trace-inner-function x)) + +(defun test-trace-inner-function (&key encapsulate) + (assert (equal (let ((sb-debug:*trace-encapsulate-default* encapsulate)) + (collecting-traces (trace-inner-function + :wherein trace-outer-function) + (trace-outer-function 'outer-value) + (trace-inner-function 'inner-value))) + '((0 trace-inner-function :enter outer-value) + (0 trace-inner-function :exit outer-value))))) + +(with-test (:name (trace :wherein :encapsulate t)) + (test-trace-inner-function :encapsulate t)) + +(with-test (:name (trace :wherein :encapsulate nil) + . #.*breakpoint-tracing-expectations*) + (test-trace-inner-function :encapsulate nil)) + +(defun test-trace-fact-wherein (&key encapsulate) + (assert (equal (let ((sb-debug:*trace-encapsulate-default* encapsulate)) + (collecting-traces (trace-fact :wherein trace-fact) + (trace-fact 1))) + '((0 trace-fact :enter 0) + (0 trace-fact :exit 1))))) + +(with-test (:name (trace :wherein :recursive :encapsulate t)) + (test-trace-fact-wherein :encapsulate t)) + +(with-test (:name (trace :wherein :recursive :encapsulate nil) + . #.*breakpoint-tracing-expectations*) + (test-trace-fact-wherein :encapsulate nil)) + +(defmacro macro-fact (x) + (labels ((fact (x) (if (zerop x) 1 (* x (fact (1- x)))))) + (fact x))) + +(with-test (:name (trace :macro) + . #.*breakpoint-tracing-expectations*) + (assert (equal (collecting-traces (macro-fact) + (macroexpand-1 '(macro-fact 3))) + '((0 macro-fact :enter (macro-fact 3) "unused argument") + (0 macro-fact :exit 6))))) + +(with-test (:name (trace :labels :within-macro) + . #.*breakpoint-tracing-expectations*) + (assert (equal (collecting-traces ((labels fact :in macro-fact)) + (macroexpand-1 '(macro-fact 0))) + '((0 (labels fact :in macro-fact) :enter 0) + (0 (labels fact :in macro-fact) :exit 1))))) + +(defun call-with-macro-fact-redefined (fn) + (handler-bind ((sb-kernel:redefinition-with-defmacro #'muffle-warning)) + (eval `(defmacro macro-fact (x) + (declare (ignore x) (optimize (debug 3))) + (labels ((fact () 'redefined)) (fact)))) + (unwind-protect + (funcall fn) + (eval `(defmacro macro-fact (x) + (labels ((fact (x) (if (zerop x) 1 (* x (fact (1- x)))))) + (fact x))))))) + +#-(or ppc ppc64) +(with-test (:name (trace :macro :redefined) + . #.*breakpoint-tracing-expectations*) + (assert (equal (collecting-traces (macro-fact + (labels fact :in macro-fact)) + (macroexpand-1 '(macro-fact 0)) + (call-with-macro-fact-redefined + (lambda () (macroexpand-1 '(macro-fact 0))))) + '((0 macro-fact :enter (macro-fact 0) "unused argument") + (1 (labels fact :in macro-fact) :enter 0) + (1 (labels fact :in macro-fact) :exit 1) (0 macro-fact :exit 1) + (0 macro-fact :enter (macro-fact 0) "unused argument") + (1 (labels fact :in macro-fact) :enter) + (1 (labels fact :in macro-fact) :exit redefined) + (0 macro-fact :exit redefined))))) + +(defun (cas trace-cas) (old new x) + (declare (optimize (debug 3))) + (flet (((cas body) (o n) + (+ o n x))) + (cas (body) old new))) + +(with-test (:name (trace :cas) + . #.*breakpoint-tracing-expectations*) + (assert (equal (collecting-traces ((cas trace-cas) + (flet (cas body) :in (cas trace-cas))) + (cas (trace-cas 1) 21 20)) + '((0 (cas trace-cas) :enter 21 20 1) + (1 (flet (cas body) :in (cas trace-cas)) :enter 21 20) + (1 (flet (cas body) :in (cas trace-cas)) :exit 42) + (0 (cas trace-cas) :exit 42))))) + +(defmethod (cas trace-cas-gf) (old new x) + (declare (optimize (debug 3))) + (flet (((cas body) (o n) + (+ o n x))) + (cas (body) old new))) + +(with-test (:name (trace :cas :generic) + . #.*breakpoint-tracing-expectations*) + (assert (equal (collecting-traces ((method (cas trace-cas-gf) (t t t)) + (flet (cas body) :in (method (cas trace-cas-gf) (t t t)))) + (cas (trace-cas-gf 1) 21 20)) + '((0 (method (cas trace-cas-gf) (t t t)) :enter 21 20 1) + (1 (flet (cas body) :in (method (cas trace-cas-gf) (t t t))) :enter 21 20) + (1 (flet (cas body) :in (method (cas trace-cas-gf) (t t t))) :exit 42) + (0 (method (cas trace-cas-gf) (t t t)) :exit 42))))) + +(defun (setf trace-setf) (value x) + (declare (optimize (debug 3))) + (flet (((setf body) (value) + (+ value x))) + (setf (body) value))) + +(with-test (:name (trace :setf) + . #.*breakpoint-tracing-expectations*) + (assert (equal (collecting-traces ((setf trace-setf) + (flet (setf body) :in (setf trace-setf))) + (setf (trace-setf 11) 31)) + '((0 (setf trace-setf) :enter 31 11) + (1 (flet (setf body) :in (setf trace-setf)) :enter 31) + (1 (flet (setf body) :in (setf trace-setf)) :exit 42) + (0 (setf trace-setf) :exit 42))))) + (with-test (:name :bug-414) (handler-bind ((warning #'error)) (with-scratch-file (output "fasl") @@ -168,7 +661,7 @@ (untrace) (assert (>= (count #\Newline (get-output-stream-string s)) 4)))) -(with-test (:name :bug-310175 :fails-on (not :stack-allocatable-lists)) +(with-test (:name :bug-310175) ;; KLUDGE: Not all DX-enabled platforms DX CONS, and the compiler ;; transforms two-arg-LIST* (and one-arg-LIST) to CONS. Therefore, ;; use two-arg-LIST, which should get through to VOP LIST, and thus @@ -376,7 +869,7 @@ "(FUNCALL CONT (1- X) CONT)" "1]")) -(with-test (:name (:debugger :bogus-debug-fun :source)) +(with-test (:name (:debugger :bogus-debug-fun :source) :skipped-on :ppc) (test-debugger "d debugger-test-done!" @@ -441,7 +934,8 @@ (with-test (:name (:print-frame-call :respect *debug-print-variable-alist* *print-length* :bug-1261646)) - (let* ((printed (print-backtrace-to-string/debug-print-variable-alist (make-array 200))) + (let* ((printed (print-backtrace-to-string/debug-print-variable-alist + (make-array 200 :initial-element 0))) (call "(PRINT-BACKTRACE-TO-STRING/DEBUG-PRINT-VARIABLE-ALIST ") (position (+ (search call printed) (length call)))) (assert (eql position (search "#(0 0 0 0 0 ...)" printed :start2 position))))) @@ -653,22 +1147,26 @@ '(error)))) (assert (= count 1)))) -(with-test (:name :properly-tagged-p-internal - :fails-on (not (or :x86 :x86-64))) +(with-test (:name :properly-tagged-p-internal) ;; Pick a code component that has a ton of restarts. (let* ((code (sb-kernel:fun-code-header #'sb-impl::update-package-with-variance)) (n (sb-kernel:code-n-entries code))) (sb-sys:with-pinned-objects (code) (let* ((base (logandc2 (sb-kernel:get-lisp-obj-address code) sb-vm:lowtag-mask)) - (limit (+ base (sb-vm::primitive-object-size code)))) + (limit (+ base (sb-ext:primitive-object-size code)))) (flet ((properly-tagged-p (ptr) (eql (alien-funcall (extern-alien "properly_tagged_p_internal" (function int unsigned unsigned)) ptr base) 1))) - ;; Test that there are exactly n-entries properly tagged interior pointers. - (assert (= (loop for ptr from (+ base (* 2 sb-vm:n-word-bytes)) + ;; For architectures that don't use LRAs, there are exactly 'n-entries' + ;; properly tagged interior pointers. For those which do use LRAs, + ;; there are at least that many, because we allow pointing to LRAs, + ;; but they aren't enumerable so we don't know the actual count. + (assert (#+(or x86 x86-64 arm64) = + #-(or x86 x86-64 arm64) > + (loop for ptr from (+ base (* 2 sb-vm:n-word-bytes)) below limit count (properly-tagged-p ptr)) n)) ;; Verify that the binary search algorithm for simple-fun-index works. @@ -700,3 +1198,45 @@ (assert (= (file-length fasl1) (file-length fasl2))) (loop repeat (file-length fasl1) do (assert (= (read-byte fasl1) (read-byte fasl2))))))))) + +;; lp#1901781 +(defun ll-unknown (x y) (declare (optimize (debug 0))) (+ x y)) +(compile 'll-unknown) +(with-test (:name :unknown-lambda-list) + (assert (eq (sb-kernel:%fun-lambda-list #'ll-unknown) :unknown))) + +;;;; SB-DEBUG:*STACK-TOP-HINT* management + +(defun buggy-handler (c) + (declare (ignore c)) + ;; signal a nondescript condition to avoid triggering WITH-TEST's error + ;; handling. + (error 'simple-condition :format-control "buggy handler")) + +(defun signal-and-handle-with-buggy-handler () + (handler-bind ((program-error #'buggy-handler)) + (signal 'program-error))) + +(defun call-getting-stack-top-on-invoke-debugger (fn) + (block nil + (let ((*invoke-debugger-hook* + (lambda (condition hook) + (declare (ignore condition hook)) + (let ((top (sb-debug::resolve-stack-top-hint))) + (return (caar (sb-debug:list-backtrace :from top))))))) + (funcall fn)))) + +;; If an error occurs within a signal handler, we want to see the handling +;; frames in the backtrace. +(with-test (:name (:stack-top-hint :signal)) + (assert (eq 'buggy-handler + (call-getting-stack-top-on-invoke-debugger + #'signal-and-handle-with-buggy-handler)))) + +;; When breaking on signals, we don't need to see the SIGNAL frame or other +;; frames above that. +(with-test (:name (:stack-top-hint :signal :break-on-signals)) + (assert (eq 'signal-and-handle-with-buggy-handler + (let ((*break-on-signals* t)) + (call-getting-stack-top-on-invoke-debugger + #'signal-and-handle-with-buggy-handler))))) diff --git a/tests/debug.pure.lisp b/tests/debug.pure.lisp new file mode 100644 index 0000000000..9d20bfdaeb --- /dev/null +++ b/tests/debug.pure.lisp @@ -0,0 +1,68 @@ + +;;; Cross-check the C and lisp implementations of varint decoding +;;; the compiled debug fun locations. +(with-test (:name :c-decode-compiled-debug-fun-locs) + (let ((ok t)) + (with-alien ((df-decode-locs (function int unsigned (* int) (* int)) + :extern) + (offset int) + (elsewhere-pc int)) + (dolist (code (sb-vm::list-allocated-objects + :all :type sb-vm:code-header-widetag)) + (when (typep (sb-kernel:%code-debug-info code) + 'sb-c::compiled-debug-info) + (do ((cdf (sb-c::compiled-debug-info-fun-map + (sb-kernel:%code-debug-info code)) + (sb-c::compiled-debug-fun-next cdf))) + ((null cdf)) + (let* ((locs (sb-c::compiled-debug-fun-encoded-locs cdf)) + (res (sb-sys:with-pinned-objects (locs) + (alien-funcall df-decode-locs (sb-kernel:get-lisp-obj-address locs) + (addr offset) (addr elsewhere-pc))))) + (assert (= res 1)) + (multiple-value-bind (start-pc expect-elsewhere-pc form-number expect-offset) + (sb-c::cdf-decode-locs cdf) + (declare (ignore start-pc form-number)) + (unless (and (= offset expect-offset) + (= elsewhere-pc expect-elsewhere-pc)) + (setq ok nil) + (format t "Fail: ~X ~S ~S ~S ~S~%" + (sb-kernel:get-lisp-obj-address cdf) + offset expect-offset + elsewhere-pc expect-elsewhere-pc)))))))) + (assert ok))) + +;;; Check that valid_lisp_pointer_p is correct for all pure boxed objects +;;; using the super quick check of header validity. +(defun randomly-probe-pure-boxed-objects () + (let (list) + (sb-vm:map-allocated-objects + (lambda (obj widetag size) + (declare (ignore widetag)) + (let* ((index + (sb-vm::find-page-index (sb-kernel:get-lisp-obj-address obj))) + (type (sb-alien:slot (sb-alien:deref sb-vm::page-table index) + 'sb-vm::flags))) + ;; mask off the SINGLE_OBJECT and OPEN_REGION bits + (when (and (eq (logand type 7) 2) ; PAGE_TYPE_BOXED + ;; Cons cells on boxed pags are page filler + (not (listp obj))) + (push (cons obj size) list)))) + :dynamic) + (dolist (cell list) + (let ((obj (car cell)) (size (cdr cell))) + (sb-sys:with-pinned-objects (obj) + ;; Check a random selection of pointers in between the untagged + ;; base address up to the last byte in the object. + ;; Exactly 1 should be OK. + (let* ((taggedptr (sb-kernel:get-lisp-obj-address obj)) + (base (logandc2 taggedptr sb-vm:lowtag-mask))) + (dotimes (i 40) + (let* ((ptr (+ base (random size))) + (valid (sb-di::valid-lisp-pointer-p (sb-sys:int-sap ptr)))) + (if (= ptr taggedptr) + (assert (= valid 1)) + (assert (= valid 0))))))))))) +(compile 'randomly-probe-pure-boxed-objects) +(with-test (:name :fast-valid-lisp-pointer-p) + (randomly-probe-pure-boxed-objects)) diff --git a/tests/defglobal.impure-cload.lisp b/tests/defglobal.pure-cload.lisp similarity index 100% rename from tests/defglobal.impure-cload.lisp rename to tests/defglobal.pure-cload.lisp diff --git a/tests/defstruct.impure-cload.lisp b/tests/defstruct.impure-cload.lisp index 5a8962d255..34c98de18f 100644 --- a/tests/defstruct.impure-cload.lisp +++ b/tests/defstruct.impure-cload.lisp @@ -12,6 +12,11 @@ (eval-when (:compile-toplevel) (load "compiler-test-util.lisp")) +;;; This test asserts that each constructor for a defstruct involved in a +;;; mutually referential cycle with other defstructs inlines the test of the +;;; as-yet-unseen type when the DEFSTRUCT form is first read. +;;; We can tell that they're inlined because they use layout-IDs, so the only +;;; boxed constant is for the constructor to deposit a layout. (with-test (:name (:block-compile :defstruct-slot-type-circularity)) (with-scratch-file (fasl "fasl") (compile-file "block-compile-defstruct-test.lisp" :output-file fasl :block-compile t) @@ -19,28 +24,77 @@ (dolist (symbol '(make-s1 make-s2 make-s3)) (let ((constants (ctu:find-code-constants (symbol-function symbol) - :type 'sb-kernel:layout))) - (assert (= (length constants) 3))))) - -;;; Check an organic (not contrived) use of mutually referential types. -;;; NEWLINE is defined after SECTION-START, because it is a subtype. -;;; One of SECTION-START's slot setters refers to type NEWLINE. -(with-test (:name :pretty-stream-structs) - (let ((layouts - (ctu:find-code-constants #'(setf sb-pretty::section-start-section-end) - :type 'sb-kernel:layout))) - ;; expect 3 layouts: one for SECTION-START to check the instance itself, - ;; one for NEWLINE and one for BLOCK-END. - ;; It's entirely coincidental that the above test also has 3. - (assert (= (length layouts) 3)) - (assert (find (sb-kernel:find-layout 'sb-pretty::newline) - layouts)))) + :type 'sb-kernel:wrapper))) + (assert (= (length constants) 1))))) (with-test (:name :mutex-owner-typecheck) (let ((layouts (ctu:find-code-constants #'(setf sb-thread::mutex-%owner) - :type 'sb-kernel:layout))) - ;; expect 3 layouts: one for THREAD, one for MUTEX, and one for FOREIGN-THREAD - (assert (= (length layouts) 3)) - (assert (find (sb-kernel:find-layout 'sb-thread:thread) + :type 'sb-kernel:wrapper))) + ;; expect exactly 1 layout, that of MUTEX, for signaling OBJECT-NOT-TYPE. + ;; To be really pedantic we'd want to assert that in the source file + ;; the defstruct of MUTEX appears prior to the defstruct of THREAD, + ;; proving without a doubt that block compilation worked. + (assert (= (length layouts) 1)) + (assert (find (sb-kernel:find-layout 'sb-thread:mutex) layouts)))) + +(defstruct (parent) + (bv #* :type bit-vector) + (x 0d0 :type double-float)) +(defstruct (child (:include parent)) + (w 0 :type word)) +(defstruct (child2 (:include parent + (bv #* :type simple-bit-vector)))) + +#| +Timing result: +(defparameter *l1* + (coerce (loop repeat 1000 + for i from 2 + collect (make-child :x (coerce i 'double-float) + :w (1+ i))) + 'vector)) + +(defparameter *l2* (map 'vector 'copy-structure *l1*)) + +(defun test (n) + (loop repeat (The fixnum n) + sum (loop for s1 across *l1* + for s2 across *l2* + count (equalp s1 s2) fixnum) fixnum)) + +* (time (test 1000)) +Old: +Evaluation took: + 0.046 seconds of real time + 127,769,104 processor cycles +New: +Evaluation took: + 0.024 seconds of real time + 66,055,457 processor cycles +|# + +(with-test (:name :custom-equalp) + (assert (equalp (make-child :x -0d0 :w #xf00f :bv #*10101) + (make-child :x +0d0 :w #xf00f :bv #*10101)))) + +(with-test (:name :no-equalp-calls) + (dolist (type '(parent child child2)) + (let* ((equalp-impl + (sb-kernel:wrapper-equalp-impl (sb-kernel:find-layout type))) + (constants + (ctu:find-code-constants equalp-impl))) + (case type + ((parent child) + (assert (and (sb-int:singleton-p constants) + (eq (car constants) + (sb-int:find-fdefn 'sb-int:bit-vector-=))))) + (child2 + ;; FIXME: why does CHILD2-EQUALP reference a boxed constant + ;; equal to MOST-POSITIVE-WORD as a bignum? + ;; Something strange about the bit-vector-= xform on simple-bit-vector. + (assert (or (not constants) + (and (sb-int:singleton-p constants) + (not (typep (car constants) + 'sb-kernel:fdefn)))))))))) diff --git a/tests/defstruct.impure.lisp b/tests/defstruct.impure.lisp index 4ddd68f732..a247046374 100644 --- a/tests/defstruct.impure.lisp +++ b/tests/defstruct.impure.lisp @@ -34,19 +34,15 @@ (defstruct (boa-kid (:include boa-saux))) (defstruct (boa-grandkid (:include boa-kid))) (with-test (:name :defstruct-boa-typecheck) - (flet ((dsd-always-boundp (dsd) - ;; A copy of sb-kernel::dsd-always-boundp, which may not - ;; survive make-target-2's shake-packages. - (logbitp 3 (sb-kernel::dsd-bits dsd)))) (dolist (dsd (sb-kernel:dd-slots (sb-kernel:find-defstruct-description 'boa-saux))) (let ((name (sb-kernel:dsd-name dsd)) - (always-boundp (dsd-always-boundp dsd))) + (always-boundp (sb-kernel:dsd-always-boundp dsd))) (ecase name ((a c) (assert (not always-boundp))) (b (assert always-boundp))))) (let ((dd (sb-kernel:find-defstruct-description 'boa-grandkid))) - (assert (not (dsd-always-boundp (car (sb-kernel:dd-slots dd)))))) + (assert (not (sb-kernel:dsd-always-boundp (car (sb-kernel:dd-slots dd)))))) (let ((s (make-boa-saux))) (locally (declare (optimize (safety 3)) (inline boa-saux-a)) @@ -55,7 +51,7 @@ (setf (boa-saux-c s) 5) (assert (eql (boa-saux-a s) 1)) (assert (eql (boa-saux-b s) 3)) - (assert (eql (boa-saux-c s) 5))))) + (assert (eql (boa-saux-c s) 5)))) (with-test (:name :defstruct-boa-nice-error :skipped-on :interpreter) (let ((err (nth-value 1 (ignore-errors (boa-saux-a (make-boa-saux)))))) @@ -252,9 +248,10 @@ (declaim (optimize (debug 2))) +(declaim (muffle-conditions style-warning)) ; &OPTIONAL and &KEY + (defmacro test-variant (defstructname &key colontype boa-constructor-p) `(locally - (declare (muffle-conditions style-warning)) ; &OPTIONAL and &KEY #+nil(format t "~&/beginning PROGN for COLONTYPE=~S~%" ',colontype) (defstruct (,defstructname ,@(when colontype `((:type ,colontype))) @@ -530,6 +527,15 @@ (sb-kernel:dd-slots (sb-kernel:find-defstruct-description 'hugest-manyraw)))))) +(with-test (:name :dd-bitmap-vs-layout-bitmap) + (dolist (typename '(huge-manyraw hugest-manyraw)) + (let* ((layout (sb-kernel:find-layout typename)) + (info (sb-kernel:wrapper-dd layout)) + (bitmap (sb-kernel::dd-bitmap info))) + (assert (typep bitmap 'bignum)) + (assert (= (sb-bignum:%bignum-length bitmap) + (sb-kernel:bitmap-nwords layout)))))) + (defun check-huge-manyraw (s) (assert (and (eql (huge-manyraw-df s) 8.207880688335944d-304) (eql (huge-manyraw-aaa s) 'aaa) @@ -541,7 +547,7 @@ (eql (huge-manyraw-w1 s) #xffee) (eql (huge-manyraw-w2 s) #xeeee))) (dolist (slot (sb-kernel:dd-slots - (sb-kernel:layout-info (sb-kernel:layout-of s)))) + (sb-kernel:wrapper-info (sb-kernel:wrapper-of s)))) (let ((name (string (sb-kernel:dsd-name slot)))) (cond ((eql (mismatch name "SLOT-") 5) (let ((n (parse-integer name :start 5))) @@ -764,33 +770,19 @@ (aref (vector x) (incf i))) (bug-348-x x))))) -;;; obsolete instance trapping -;;; -;;; FIXME: Both error conditions below should possibly be instances -;;; of the same class. (Putting this FIXME here, since this is the only -;;; place where they appear together.) - (with-test (:name :obsolete-defstruct/print-object) (eval '(defstruct born-to-change)) (let ((x (make-born-to-change))) (handler-bind ((error 'continue)) (eval '(defstruct born-to-change slot))) - (assert (eq :error - (handler-case - (princ-to-string x) - (sb-pcl::obsolete-structure () - :error)))))) + (assert (search "UNPRINTABLE instance" (princ-to-string x))))) (with-test (:name :obsolete-defstruct/typep) (eval '(defstruct born-to-change-2)) (let ((x (make-born-to-change-2))) (handler-bind ((error 'continue)) (eval '(defstruct born-to-change-2 slot))) - (assert (eq :error2 - (handler-case - (typep x (find-class 'standard-class)) - (sb-kernel:layout-invalid () - :error2)))))) + (assert (not (typep x (find-class 'standard-class)))))) ;; EQUALP didn't work for structures with float slots (reported by ;; Vjacheslav Fyodorov). @@ -911,13 +903,8 @@ redefinition." (defun assert-is (predicate instance) (assert (funcall predicate instance))) -;;; It used to call the predicate function, but out-of-line predicate -;;; functions now don't signal layout-invalid, just like inlined -;;; predicates didn't signal it. (defun assert-invalid (instance) - (declare (notinline typep)) - (assert (typep (nth-value 1 (ignore-errors (typep instance 'structure-object))) - 'sb-kernel::layout-invalid))) + (assert (sb-kernel:wrapper-invalid (sb-kernel:%instance-wrapper instance)))) ;; Don't try to understand this macro; just look at its expansion. (defmacro with-defstruct-redefinition-test (name @@ -1448,3 +1435,10 @@ redefinition." `(defstruct foo4131 bar bar)) (assert-that "slot name BAR duplicated via included FOO4130" `(defstruct (foo4132 (:include foo4130)) bar)))) + +(test-util:with-test (:name :specialized-equalp) + ;; make sure we didn't mess up PATHNAME and HASH-TABLE + (let ((f (sb-kernel:wrapper-equalp-impl (sb-kernel:find-layout 'pathname)))) + (assert (eq f #'sb-int:pathname=))) + (let ((f (sb-kernel:wrapper-equalp-impl (sb-kernel:find-layout 'hash-table)))) + (assert (eq f #'sb-int:hash-table-equalp)))) diff --git a/tests/deprecation.impure.lisp b/tests/deprecation.impure.lisp index a6747ce751..2604dab1dd 100644 --- a/tests/deprecation.impure.lisp +++ b/tests/deprecation.impure.lisp @@ -352,9 +352,8 @@ (write-string "(defun b () (please-dont-use-this 1) (really-dont-do-it 2))" f) (write-string "(defun c () (you-cant-use-this 3))" f)) ;; We expect four deprecation warnings from compiling the source - ;; (four uses of deprecated things) and three from loading it - ;; (loading three functions that contain uses of deprecated - ;; things). + ;; and four from loading it, as there are four uses of deprecated + ;; things) (unwind-protect (progn (setq fasl (assert-signal @@ -363,6 +362,6 @@ late-deprecation-warning final-deprecation-warning) 4)) - (assert-signal (load fasl) warning 3)) + (assert-signal (load fasl) warning 4)) (delete-file fasl) (delete-file source)))) diff --git a/tests/describe.impure.lisp b/tests/describe.impure.lisp index a013ed943b..c5104d9784 100644 --- a/tests/describe.impure.lisp +++ b/tests/describe.impure.lisp @@ -154,3 +154,10 @@ (with-output-to-string (stream) (describe (make-array 1 :displaced-to (make-array 1)) stream))))) + +(with-test (:name :bad-second-arg) + (assert-error + (describe 'describe + (opaque-identity + (make-array 256 :element-type 'character :fill-pointer 0))) + type-error)) diff --git a/tests/disassem.impure.lisp b/tests/disassem.impure.lisp index 9eb73b3612..3ee01ce133 100644 --- a/tests/disassem.impure.lisp +++ b/tests/disassem.impure.lisp @@ -41,7 +41,8 @@ ;;; I'm not sure how to implement CLISP-compatibility and ABCL-compatibility ;;; via the standard interface now, so test the nonstandard interface. -(with-test (:name :disassemble-method) +(with-test (:name :disassemble-method + :skipped-on :interpreter) (with-output-to-string (s) (sb-c:dis (defmethod hello ((self cons)) "here i am") s))) @@ -60,13 +61,17 @@ ;;; Unfortunately I think is too slow to make part of the test suite, ;;; which speaks to the terrible performance of our disassembler. (in-package "SB-DISASSEM") -(defun disassemble-everything (&optional (show-progress t) +(defun list-all-code () + (sb-vm::list-allocated-objects :all :type sb-vm:code-header-widetag)) + +(defun disassemble-everything (objects + &optional (show-progress t) &aux (dstate (make-dstate)) (i 0)) (declare (inline %make-segment)) (when show-progress (format t "~&Start ... ") (force-output)) - (dolist (code (funcall 'sb-vm::list-allocated-objects :all :type sb-vm:code-header-widetag)) + (dolist (code objects) (when show-progress (write-char #\backspace) (write-char (aref "\\|/-" (mod (incf i) 4))) @@ -92,6 +97,17 @@ (format t " done~%"))) (compile 'disassemble-everything) +(defun install-counting-wrapper (discount) + (declare (ignorable discount)) + #+x86-64 + (sb-int:encapsulate + 'sb-x86-64-asm::print-mem-ref 'test + (lambda (realfun &rest args) + ;; Each mem ref disassembled is one cons cell + (incf (car discount) (* sb-vm:cons-size sb-vm:n-word-bytes)) + (apply realfun args)))) +(compile 'install-counting-wrapper) + ;;; Disassembling everything takes around .8 seconds and conses ~14MB for me. ;;; To ensure that things don't get drastically worse, assert that we're within ;;; some fuzz factor of the expected consing. One small mistake in target-disassem @@ -100,11 +116,20 @@ ;; Only the x86-64 disassembler is able to disassemble ;; with output into the dstate rather than a stream. ;; The others choke with "NIL is not of type STREAM" - :skipped-on (:not (:and :x86-64 :linux))) - (multiple-value-bind (before after) - (sb-sys:without-gcing - (values (get-bytes-consed) - (progn - (disassemble-everything nil) - (get-bytes-consed)))) - (assert (< (- after before) 17000000)))) + :skipped-on (:not :x86-64)) + (let ((code (list-all-code)) ;; Avoid counting bytes consed in the list + (discount (list 0))) + (install-counting-wrapper discount) + ;; Build the inst space outside the test to avoid influencing bytes consed + (sb-disassem:get-inst-space) + (multiple-value-bind (before after) + (sb-sys:without-gcing + (values (get-bytes-consed) + (progn + (disassemble-everything code nil) + (get-bytes-consed)))) + (let* ((after (- after (car discount))) + (delta (- after before))) + (format t "~&Consed ~D bytes discounting ~D bytes~%" delta (car discount)) + ;; Should be less than this amount of overhead + (assert (< delta 500000)))))) diff --git a/tests/do-refs.impure.lisp b/tests/do-refs.impure.lisp index 968dc6800a..d78f2c637f 100644 --- a/tests/do-refs.impure.lisp +++ b/tests/do-refs.impure.lisp @@ -4,17 +4,22 @@ ;;;; While most of SBCL is derived from the CMU CL system, the test ;;;; files (like this one) were written from scratch after the fork ;;;; from CMU CL. -;;; +;;;; ;;;; This software is in the public domain and is provided with ;;;; absoluely no warranty. See the COPYING and CREDITS files for ;;;; more information. (in-package sb-vm) -(defun collect-slot-values (obj) - (collect ((slots)) +(test-util:with-test (:name :safe-layoutless-instance) + (assert (not (sb-vm::references-p (sb-kernel:%make-instance 5) '(foo))))) + +(defun collect-slot-values (obj &aux result) + (flet ((slots (x) + #+metaspace (if (typep x 'sb-vm:layout) (setq x (sb-kernel::layout-friend x))) + (push x result))) (do-referenced-object (obj slots)) - (slots))) + (nreverse result))) (defun walk-slots-test (obj expect) (assert (equal (collect-slot-values obj) expect))) @@ -23,7 +28,8 @@ (defstruct foo (z 0 :type sb-ext:word) (x 'x) (y 'y)) -(test-util:with-test (:name :walk-slots-trivial) ; lists and vectors +(test-util:with-test (:name :walk-slots-trivial ; lists and vectors + :fails-on :interpreter) (walk-slots-test '(a . b) '(a b)) (walk-slots-test #(a b c) '(a b c)) (walk-slots-test #(a b c d) '(a b c d)) @@ -49,7 +55,8 @@ (info '((bork 42)))) (import s "CL-USER") (set s 'hi) - (setf (symbol-info s) info) + (setf (symbol-plist s) (car info) info (sb-kernel:symbol-%info s)) + ;; ASSUMPTION: slot ordering (walk-slots-test s `(hi ,info ,name ,(find-package "CL-USER"))))) (test-util:with-test (:name :walk-slots-closure) @@ -64,46 +71,64 @@ :key 'widetag-of :test #'/=))))))) (test-util:with-test (:name :walk-slots-fdefn) - (walk-slots-test* - (sb-kernel::find-fdefn 'constantly-t) - (lambda (slots) - #+immobile-code - (and (= (length slots) 3) - (symbolp (first slots)) - (closurep (second slots)) - (code-component-p (third slots))) - #-immobile-code - (and (= (length slots) 2) - (symbolp (first slots)) - (closurep (second slots)))))) + (let* ((closure (funcall (compile nil '(lambda (x) (lambda () x))) t)) + (symbol (gensym))) + (setf (fdefinition symbol) closure) + (walk-slots-test* + (sb-int:find-fdefn symbol) + (lambda (slots) + #+immobile-code + (and (= (length slots) 3) + (symbolp (first slots)) + (closurep (second slots)) + (code-component-p (third slots))) + #-immobile-code + (and (= (length slots) 2) + (symbolp (first slots)) + (closurep (second slots))))))) (defclass mystdinst () ((a :initform 1) (b :initform 2) (c :initform 3) (d :initform 4) (e :initform 5))) -(test-util:with-test (:name :walk-slots-standard-instance) +(test-util:with-test (:name :walk-slots-standard-instance + :fails-on :interpreter) (let ((o (make-instance 'mystdinst))) (walk-slots-test* o (lambda (slots) (destructuring-bind (layout clos-slots) slots - (and (eq layout (%instance-layout o)) + (and (eq layout (%instance-wrapper o)) (eq clos-slots (sb-pcl::std-instance-slots o)))))))) (define-condition cfoo (simple-condition) ((a :initarg :a) (b :initarg :b) (c :initform 'c))) -(test-util:with-test (:name :walk-slots-condition-instance) +(test-util:with-test (:name :walk-slots-condition-instance + :fails-on :interpreter) (let ((instance (make-condition 'cfoo :a 'ay :b 'bee :format-arguments "wat"))) (walk-slots-test instance - `(,(find-layout 'cfoo) - (c c format-control nil) + `(,(find-layout 'cfoo) (c c format-control nil) :a ay :b bee :format-arguments "wat")))) +(defun make-random-funinstance (&rest values) + (let* ((ctor (apply #'sb-pcl::%make-ctor values)) + (wrapper (sb-kernel:%fun-wrapper ctor))) + ;; If the number of payload words is even, then there's a padding word + ;; because adding the header makes the unaligned total an odd number. + ;; Fill that padding word with something - it should not be visible. + ;; Whether GC should trace the word is a different question, + ;; on whose correct answer I waver back and forth. + (when (evenp (sb-kernel:get-closure-length ctor)) ; payload length + (let ((max (reduce #'max (sb-kernel:dd-slots (sb-kernel:wrapper-dd wrapper)) + :key 'sb-kernel:dsd-index))) + (setf (sb-kernel:%funcallable-instance-info ctor (1+ max)) + (elt sb-vm:+static-symbols+ 0)))) + ;; stuff in a random function as the implementation + (setf (sb-kernel:%funcallable-instance-fun ctor) #'error) + ctor)) +(compile 'make-random-funinstance) + (test-util:with-test (:name :walk-slots-pcl-ctor) (let* ((slot-vals '("A" "B" "C" "D" "E" "F")) - (f (apply (compile nil '(lambda (&rest args) - (let ((ctor (apply #'sb-pcl::%make-ctor args))) - (setf (%funcallable-instance-fun ctor) #'error) - ctor))) - slot-vals))) + (f (apply #'make-random-funinstance slot-vals))) (walk-slots-test f `(,(find-layout 'sb-pcl::ctor) ,#'error ,@slot-vals)))) #+sb-fasteval @@ -113,9 +138,9 @@ (funcall f 1 2 3) ; compute the digested slots (walk-slots-test* f (lambda (slots) - (destructuring-bind (layout fin-fun a b c d) slots + (destructuring-bind (type fin-fun a b c d) slots (declare (ignore a b c)) - (and (typep layout 'layout) + (and (typep type 'wrapper) (typep fin-fun 'closure) (typep d '(and integer (not (eql 0)))))))))) @@ -129,7 +154,7 @@ (defun deep-size (obj &optional (leafp (lambda (x) (typep x '(or package symbol fdefn function code-component - layout classoid))))) + wrapper classoid))))) (let ((worklist (list obj)) (seen (make-hash-table :test 'eq)) (tot-bytes 0)) diff --git a/tests/dump.impure-cload.lisp b/tests/dump.impure-cload.lisp index 1521628581..8cdac39bd3 100644 --- a/tests/dump.impure-cload.lisp +++ b/tests/dump.impure-cload.lisp @@ -15,6 +15,7 @@ (load "compiler-test-util.lisp")) (declaim (optimize (debug 3) (speed 2) (space 1))) +(declaim (muffle-conditions compiler-note)) ;;; this would fail an AVER in NOTE-POTENTIAL-CIRCULARITY (defparameter *circular-2d-array* #1=#2A((a b) (#1# x))) @@ -228,6 +229,14 @@ )) ; end EVAL-WHEN +(defun load-form-is-default-mlfss-p (object) + (multiple-value-bind (creation-form init-form) + (make-load-form object) + (multiple-value-bind (ss-creation-form ss-init-form) + (make-load-form-saving-slots object) + (and (equal creation-form ss-creation-form) + (equal init-form ss-init-form))))) + ;; Redefine the MAKE-LOAD-FORM method on FOO. (remove-method #'make-load-form (find-method #'make-load-form nil (list 'foo))) (defvar *foo-save-slots* nil) @@ -240,13 +249,13 @@ (let ((foo (make-foo :x 'x :y 'y))) (flet ((assert-canonical (slots) (let ((*foo-save-slots* slots)) - (assert (sb-fasl:load-form-is-default-mlfss-p foo))))) + (assert (load-form-is-default-mlfss-p foo))))) (assert-canonical :all) (assert-canonical '(x y)) ; specifying all slots explicitly is still canonical (assert-canonical '(y x))) ;; specifying only one slot is not canonical - (assert (equal (let ((*foo-save-slots* '(x))) (sb-c::%make-load-form foo)) - '(sb-kernel::new-instance foo))))) + (let ((*foo-save-slots* '(x))) + (assert (not (load-form-is-default-mlfss-p foo)))))) ;; A huge constant vector. This took 9 seconds to compile (on a MacBook Pro) ;; prior to the optimization for using fops to dump. @@ -335,7 +344,7 @@ ;; Track the make-load-form FOPs as they fly by at load-time. (defvar *call-tracker* nil) -(dolist (fop-name 'sb-fasl::(fop-allocate-instance fop-set-slot-values)) +(dolist (fop-name '(sb-fasl::fop-instance)) (let* ((index (position fop-name sb-fasl::**fop-funs** :key (lambda (x) (and (functionp x) (sb-kernel:%fun-name x))))) @@ -354,8 +363,7 @@ (b p q r s) (c d e g)))) -(assert (= 14 (count 'sb-fasl::fop-allocate-instance *call-tracker*))) -(assert (= 14 (count 'sb-fasl::fop-set-slot-values *call-tracker*))) +(assert (= 14 (count 'sb-fasl::fop-instance *call-tracker*))) (with-test (:name :tree-with-parent-m-l-f-s-s) (verify-tree *y*)) @@ -422,6 +430,17 @@ (assert (eq (aref pairs 2) 'first)) (assert (eq (aref pairs 4) 'second)))) +(defun int= (a b) (= (the integer a) (the integer b))) +(define-hash-table-test int= sb-impl::number-sxhash) +(defun get-sync-hash-table () #.(make-hash-table :synchronized t)) +(with-test (:name :dump-hash-tables) + ;; Don't lose the :synchronized option. + (assert (hash-table-synchronized-p (get-sync-hash-table))) + ;; Disallow nonstandard hash that disagrees with test. + (assert-error (make-load-form (make-hash-table :test 'int= :hash-function 'sxhash))) + ;; Allow nonstandard test as long as it was registered + (assert (make-load-form (make-hash-table :test 'int=)))) + (defun list-coalescing-test-fun-1 () (declare (optimize (debug 1))) ;; base coalesces with base, non-base coalesces with non-base @@ -460,3 +479,75 @@ (with-test (:name (:cdr-eq-detection :lp1583753)) (constant-folding-cdr-test-fun)) + +(locally + (declare (optimize (debug 2) (safety 3))) + (defconstant +consy-constant+ (if (boundp '+consy-constant+) (symbol-value '+consy-constant+) '(message-id CAOrNaszM=eSufoqA4KFVNq4CUpjSJym-ktQnufQgj7a5g2sHmg@mail.gmail.com))) + (defun test-constant-identity (x) + (list '(message-id CAOrNaszM=eSufoqA4KFVNq4CUpjSJym-ktQnufQgj7a5g2sHmg@mail.gmail.com) + (eq x +consy-constant+)))) + +(with-test (:name (defconstant :reference :identity)) + (let ((z (eval `(test-constant-identity ,(intern "+CONSY-CONSTANT+"))))) + (assert (equal (car z) +consy-constant+)) + (assert (cadr z)))) + +(macrolet ((expand () + (declare (muffle-conditions compiler-note)) ; why is DECLAIM not enough? + `(progn + ,@(loop for i from 0 below sb-vm:n-word-bits + collect + `(sb-int:defconstant-eqx ,(intern (format nil "MYSAP~d" i)) + ,(sb-sys:int-sap (ash 1 i)) + #'sb-sys:sap=))))) + (expand)) +(with-test (:name :dump-sap) + (dotimes (i sb-vm:n-word-bits) + (let ((s (intern (format nil "MYSAP~d" i)))) + (assert (= (sb-sys:sap-int (symbol-value s)) + (ash 1 i)))))) + +(eval-when (:compile-toplevel :load-toplevel) + (defstruct monkey + (x t) + (y 1 :type fixnum) + (data (cons 1 2)) + (str "hi")) + + (defmethod make-load-form ((self monkey) &optional e) + (make-load-form-saving-slots self :slot-names '(data) :environment e))) + +(defvar *amonkey* #.(make-monkey :x nil :y 3 :data '(ok))) +(eval-when (:compile-toplevel) (makunbound '*amonkey*)) +(with-test (:name :dump-monkey) + (let ((a *amonkey*)) + (assert (sb-kernel::unbound-marker-p (monkey-x a))) + (assert (sb-kernel::unbound-marker-p (monkey-y a))) + (assert (sb-kernel::unbound-marker-p (monkey-str a))) + (assert (equal (monkey-data a) '(ok))))) + +(defun use-numeric-vector-a () + #.(make-array 5 :element-type '(signed-byte 8) :initial-contents '(90 100 5 -2 3))) + +(defun use-numeric-vector-b () + #.(make-array 5 :element-type '(signed-byte 8) :initial-contents '(90 100 5 -2 3))) + +(with-test (:name :coalesce-numeric-arrays) + (assert (eq (use-numeric-vector-a) (use-numeric-vector-b)))) + +(eval-when (:compile-toplevel :load-toplevel :execute) +(defstruct person id) +(defstruct (spy (:include person (id " " :type (simple-string 2)))) gadgetry) +(defmethod make-load-form ((self spy) &optional environment) + (declare (ignore environment)) + (make-load-form-saving-slots self))) + +(defvar *agent* #.(let ((s (make-spy :id "86" :gadgetry '(shoe-phone)))) + (setf (person-id s) "max") + s)) + +;;; If lp#1969318 is fixed, then *AGENT* should not be reconstructed +;;; from its load form, let alone dumped in the first place. +;;; But thankfully we trap the read of the ID slot. +(with-test (:name :illegal-typed-slot-value) + (assert-error (spy-id *agent*))) diff --git a/tests/dynamic-extent.impure.lisp b/tests/dynamic-extent.pure.lisp similarity index 90% rename from tests/dynamic-extent.impure.lisp rename to tests/dynamic-extent.pure.lisp index 8cf02f6834..718a52b9d0 100644 --- a/tests/dynamic-extent.impure.lisp +++ b/tests/dynamic-extent.pure.lisp @@ -12,9 +12,8 @@ ;;;; more information. (when (eq sb-ext:*evaluator-mode* :interpret) - (sb-ext:exit :code 104)) + (invoke-restart 'run-tests::skip-file)) -(load "compiler-test-util.lisp") (use-package :ctu) (setq sb-c::*check-consistency* t @@ -174,7 +173,7 @@ (defun-with-dx dx-value-cell (x) ;; Not implemented everywhere, yet. - #+(or x86 x86-64 mips hppa) + #+(or x86 x86-64 mips) (let ((cell x)) (declare (sb-int:truly-dynamic-extent cell)) (flet ((f () @@ -330,7 +329,7 @@ (defun make-var-length-dx-list (n thunk) (sb-int:dx-let ((s (make-list-container :listy-slot (make-list n)))) (funcall thunk s))) -;; :stack-allocatable-lists is necessary but not sufficient +;; stack-allocatable lists are necessary but not sufficient (with-test (:name (:dx-list :make-list) :skipped-on (not :x86-64)) (assert (null (ctu:find-named-callees #'make-var-length-dx-list))) (assert-no-consing (make-var-length-dx-list @@ -338,12 +337,12 @@ ;;; MAKE-STRUCTURE -;; :stack-allocatable-fixed-objects is necessary but not sufficient +;; stack-allocatable fixed-size objects are necessary but not sufficient (with-test (:name :copy-structure-dx :skipped-on (not (or :x86 :x86-64))) (let ((thing sb-c::*backend-parsed-vops*)) ;; check some preconditions (assert (typep thing 'hash-table)) - (assert (/= (sb-kernel:layout-bitmap (sb-kernel:%instance-layout thing)) + (assert (/= (sb-kernel:wrapper-bitmap (sb-kernel:%instance-wrapper thing)) sb-kernel:+layout-all-tagged+)) (assert-no-consing (sb-int:dx-let ((x (copy-structure thing))) @@ -703,12 +702,10 @@ (defvar *a-cons* (cons nil nil)) -(with-test (:name (:no-consing :dx-closures) :skipped-on (not :stack-allocatable-closures)) +(with-test (:name (:no-consing :dx-closures)) (assert-no-consing (dxclosure 42))) -(with-test (:name (:no-consing :dx-lists) - :skipped-on (not (and :stack-allocatable-lists - :stack-allocatable-fixed-objects))) +(with-test (:name (:no-consing :dx-lists)) (assert-no-consing (dxlength 1 2 3)) (assert-no-consing (dxlength t t t t t t)) (assert-no-consing (dxlength)) @@ -725,13 +722,10 @@ (assert-no-consing (list-delete-some-stuff)) (assert-no-consing (multiple-dx-uses))) -(with-test (:name (:no-consing :dx-value-cell) - :skipped-on (not :stack-allocatable-closures)) +(with-test (:name (:no-consing :dx-value-cell)) (assert-no-consing (dx-value-cell 13))) -(with-test (:name (:no-consing :dx-fixed-objects) - :skipped-on (not (and :stack-allocatable-fixed-objects - :stack-allocatable-closures))) +(with-test (:name (:no-consing :dx-fixed-objects)) (assert-no-consing (cons-on-stack 42)) (assert-no-consing (make-foo1-on-stack 123)) (assert-no-consing (nested-good 42)) @@ -739,7 +733,7 @@ (assert-no-consing (dx-handler-bind 2)) (assert-no-consing (dx-handler-case 2))) -(with-test (:name (:no-consing :dx-vectors) :skipped-on (not :stack-allocatable-vectors)) +(with-test (:name (:no-consing :dx-vectors)) (assert-no-consing (force-make-array-on-stack 128)) (assert-no-consing (make-array-on-stack-2 5 '(1 2.0 3 4.0 5))) (assert-no-consing (make-array-on-stack-3 9 8 7)) @@ -747,7 +741,7 @@ (assert-no-consing (make-array-on-stack-5)) (assert-no-consing (vector-on-stack :x :y))) -(with-test (:name (:no-consing :dx-arrays) :skipped-on (not :stack-allocatable-vectors)) +(with-test (:name (:no-consing :dx-arrays)) (assert-no-consing (make-3d-fixed-array-on-stack-1)) (assert-no-consing (make-2d-variable-array-on-stack)) (assert-no-consing (make-2d-array-function-initializer 1)) @@ -755,13 +749,11 @@ (assert-no-consing (make-2d-array-function-initializer 3))) (with-test (:name (:no-consing :dx-specialized-arrays) - :skipped-on (not (and :stack-allocatable-vectors - :c-stack-is-control-stack))) + :skipped-on (not :c-stack-is-control-stack)) (assert-no-consing (make-3d-fixed-array-on-stack-2 0 0 1 1))) (with-test (:name (:no-consing :specialized-dx-vectors) - :skipped-on (not (and :stack-allocatable-vectors - :c-stack-is-control-stack))) + :skipped-on (not :c-stack-is-control-stack)) (assert-no-consing (make-array-on-stack-1)) (assert-no-consing (make-array-on-stack-6)) (assert-no-consing (make-array-on-stack-7)) @@ -770,11 +762,8 @@ (assert-no-consing (make-array-on-stack-10)) (assert-no-consing (make-array-on-stack-11))) -(when (gethash 'sb-vm::raw-instance-init/word sb-c::*backend-parsed-vops*) - (pushnew :raw-instance-init-vops *features*)) (with-test (:name (:no-consing :dx-raw-instances) - :skipped-on (or (not :raw-instance-init-vops) - (not (and :gencgc :c-stack-is-control-stack)))) + :skipped-on (not (and :gencgc :c-stack-is-control-stack))) (let (a b) (setf a 1.24 b 1.23d0) (assert-no-consing (make-foo2-on-stack a b))) @@ -786,9 +775,12 @@ (defun test-hash-table () (setf (gethash 5 *table*) 13) - (gethash 5 *table*)) + (setf (gethash 6 *table*) 14) + (values (gethash 5 *table*) + (gethash 6 *table*))) (with-test (:name (:no-consing :hash-tables)) + (test-hash-table) ;; initialize all the vectors first (assert-no-consing (test-hash-table))) ;;; Both with-pinned-objects and without-gcing should not cons @@ -880,7 +872,7 @@ (assert (every (lambda (x) (eql x 0)) a)))) (with-test (:name (:dx-bug-misc :bdowning-2005-iv-16)) - #+(or hppa mips x86 x86-64) + #+(or mips x86 x86-64) (assert-no-consing (bdowning-2005-iv-16)) (bdowning-2005-iv-16)) @@ -903,11 +895,11 @@ (b (list x y z)) (c (list a b))) (declare (dynamic-extent c)) - (values (first c) (second c)))) + (values a b))) (with-test (:name :let-converted-vars-dx-allocated-bug) - (multiple-value-bind (i j) (let-converted-vars-dx-allocated-bug 1 2 3) - (assert (and (equal i j) - (equal i (list 1 2 3)))))) + (multiple-value-bind (i j) (let-converted-vars-dx-allocated-bug-default 1 2 3) + (assert (equal i j)) + (assert (equal i (list 1 2 3))))) ;;; workaround for bug 419 -- real issue remains, but check that the ;;; bandaid holds. @@ -935,12 +927,12 @@ (multiple-value-bind (y pos2) (read-from-string res nil nil :start pos) (assert (equalp f2 y)) (assert (equalp f3 (read-from-string res nil nil :start pos2)))))) - #+(or hppa mips x86 x86-64) + #+(or mips x86 x86-64) (assert-no-consing (assert (eql n (funcall fun nil)))) (assert (eql n (funcall fun nil)))) (macrolet ((def (n f1 f2 f3) - (let ((name (sb-pcl::format-symbol :cl-user "DX-FLET-TEST.~A" n))) + (let ((name (sb-int:package-symbolicate "DX-FLET-TEST." (write-to-string n)))) `(progn (defun-with-dx ,name (s) (flet ((f (x) @@ -956,7 +948,7 @@ (with-test (:name (:dx-flet-test ,n)) (test-dx-flet-test #',name ,n ,f1 ,f2 ,f3)))))) (def 0 (list :one) (list :two) (list :three)) - (def 1 (make-array 128) (list 1 2 3 4 5 6 7 8) (list 'list)) + (def 1 (make-array 128 :initial-element nil) (list 1 2 3 4 5 6 7 8) (list 'list)) (def 2 (list 1) (list 2 3) (list 4 5 6 7))) ;;; Test that unknown-values coming after a DX value won't mess up the @@ -1016,9 +1008,7 @@ (with-test (:name :length-and-words-packed-in-same-tn) (assert (= 1 (length-and-words-packed-in-same-tn -3)))) -(with-test (:name :handler-case-bogus-compiler-note - :skipped-on (not (and :stack-allocatable-fixed-objects - :stack-allocatable-closures))) +(with-test (:name :handler-case-bogus-compiler-note) ;; Taken from SWANK, used to signal a bogus stack allocation ;; failure note. (checked-compile @@ -1045,8 +1035,6 @@ (defun barvector (x y z) (make-array 3 :initial-contents (list x y z))) (with-test (:name :dx-compiler-notes - :skipped-on (not (and :stack-allocatable-vectors - :stack-allocatable-closures)) :fails-on (and)) (flet ((assert-notes (j lambda) (let ((notes (nth 4 (multiple-value-list (checked-compile lambda))))) ; TODO @@ -1098,9 +1086,7 @@ (if sp (assert (= sp (sb-c::%primitive sb-c:current-stack-pointer))) (setf sp (sb-c::%primitive sb-c:current-stack-pointer)))))) -(with-test (:name :handler-case-eating-stack - :skipped-on (not (and :stack-allocatable-fixed-objects - :stack-allocatable-closures))) +(with-test (:name :handler-case-eating-stack) (assert-no-consing (handler-case-eating-stack))) ;;; A nasty bug where RECHECK-DYNAMIC-EXTENT-LVARS thought something was going @@ -1118,8 +1104,7 @@ (let ((vec (vec (aref vec 0) (aref vec 1) (aref vec 2)))) (declare (dynamic-extent vec)) (funcall fun vec)))) -(with-test (:name :recheck-nested-dx-bug - :skipped-on (not :stack-allocatable-vectors)) +(with-test (:name :recheck-nested-dx-bug) (assert (funcall (bad-boy (vec 1.0 2.0 3.3)) (lambda (vec) (equalp vec (vec 1.0 2.0 3.3))))) (flet ((foo (x) (declare (ignore x)))) @@ -1135,7 +1120,7 @@ (test `(lambda () (declare (dynamic-extent #'bar))) :allow-style-warnings 'style-warning) (test `(lambda () (declare (dynamic-extent bar))) - :allow-style-warnings 'style-warning) + :allow-warnings 'warning) (test `(lambda (bar) (cons bar (lambda () (declare (dynamic-extent bar))))) :allow-notes 'sb-ext:compiler-note) (test `(lambda () @@ -1143,9 +1128,7 @@ (cons #'bar (lambda () (declare (dynamic-extent #'bar)))))) :allow-notes 'sb-ext:compiler-note))) -(with-test (:name :bug-586105 - :skipped-on (not (and :stack-allocatable-vectors - :stack-allocatable-lists))) +(with-test (:name :bug-586105) (flet ((test (x) (let ((vec1 (make-array 1 :initial-contents (list (list x)))) (vec2 (make-array 1 :initial-contents `((,x)))) @@ -1448,14 +1431,12 @@ t)) (assert (and (= i 1) (= j 1)))) -(with-test (:name (:no-consing :auto-dx-closures) - :skipped-on (not :stack-allocatable-closures)) +(with-test (:name (:no-consing :auto-dx-closures)) (assert-no-consing (autodxclosure1 42)) (assert-no-consing (autodxclosure2))) #+gencgc -(with-test (:name (:no-consing :more-auto-dx-closures) - :skipped-on (not :stack-allocatable-closures)) +(with-test (:name (:no-consing :more-auto-dx-closures)) (assert-no-consing (let ((ct 0)) (sb-vm:map-allocated-objects @@ -1475,9 +1456,7 @@ 1) :allow-notes nil)) -(with-test (:name :stack-alloc-p - :skipped-on (or (not :stack-allocatable-lists) - (not :sb-thread))) +(with-test (:name :stack-alloc-p :skipped-on (not :sb-thread)) (let* ((sem1 (sb-thread:make-semaphore)) (sem2 (sb-thread:make-semaphore)) (blah nil) @@ -1601,3 +1580,132 @@ 0)) :allow-notes nil))) (assert-no-consing (funcall fun)))) + +(with-test (:name :with-output-to-string) + (let ((s (make-array 20000 :fill-pointer 0 :element-type 'character))) + (assert-no-consing + (with-output-to-string (*standard-output* s) + (write-char #\x))))) + +(with-test (:name :cycles-without-dx-lvars) + (checked-compile-and-assert + () + `(lambda (f x z) + (let ((l (if x + (loop while z) + (list (list 1))))) + (declare (dynamic-extent l)) + (funcall f l))) + (((lambda (l) (equal l '((1)))) nil nil) t) + (((lambda (l) (equal l nil)) t nil) t))) + +;;; Test that we don't preserve UVLs too long because of DX in stack +;;; analysis. +(with-test (:name :uvl-preserved-by-dx-too-long) + (checked-compile + '(lambda (f1 test args) + (flet ((f3 (&rest m) (apply test m))) + (declare (dynamic-extent #'f3)) + (apply f1 #'f3 args))))) + +;;; Test that we don't preserve LVARs that just happen to be in the +;;; same block. +(with-test (:name :uvl-preserved-incidentally) + (checked-compile + '(lambda (b) + (catch 'ct2 + (multiple-value-prog1 (multiple-value-prog1 (restart-case 0)) + (restart-case 0) + b + 0))))) + +(with-test (:name :uvl-preserved-incidentally.2) + (checked-compile + '(lambda () + (multiple-value-prog1 + (multiple-value-prog1 (catch 'ct2 0)) + (restart-bind nil + (flet ((%f () 0)) + (declare (dynamic-extent (function %f))) + (%f))))))) + +;;; After dx entries no longer started delimiting their blocks, there +;;; was no reason for propagate-dx to end its own blocks either. In +;;; fact propagate-dx started causing problems instead. +(with-test (:name :propagate-dx-ended-block) + (checked-compile + '(lambda (c) + (declare (notinline - svref)) + (let* ((v1 (svref #(1 3 4 6) 0))) + (declare (dynamic-extent v1)) + (- c v1))))) + +(with-test (:name :dx-for-optional-entries) + (checked-compile-and-assert + () + `(lambda (a b c) + (declare (notinline funcall max)) + (labels ((%f14 + (f14-1 f14-2 + &optional (f14-3 (setq a (min 13 (max 1 0)))) + (f14-4 (setq c 0))) + (declare (ignore f14-1 f14-2 f14-3 f14-4)) + 0)) + (declare (dynamic-extent (function %f14))) + (funcall #'%f14 + (%f14 + (min 11 (max 0 c)) + (funcall #'%f14 a b 1) + 1 + b) + 0))) + ((1 2 3) 0))) + +(with-test (:name :dx-for-optional-entries.2) + (checked-compile-and-assert + (:optimize '(:speed 3)) + `(lambda (b) + (declare (notinline funcall)) + (labels ((%f1 (&optional f1-1) + (declare (ignore f1-1)) + (shiftf b 0))) + (declare (dynamic-extent (function %f1))) + (funcall #'%f1 :bad))) + ((10) 10))) + +(with-test (:name :no-stack-cleanup-before-return) + (checked-compile-and-assert + () + `(lambda () + (let ((identity (eval '#'identity)) + (continuation (eval '(lambda (&rest args) + args)))) + (flet ((f (n fn) + (funcall fn n (vector)))) + (f 1 + (lambda (j &rest points) + (apply continuation j (mapcar identity points))))))) + (() '(1 #()) :test #'equalp))) + +(with-test (:name :special-bind-removal) + (checked-compile-and-assert + () + `(lambda (a) + (multiple-value-prog1 (eval a) + (let ((* (let ((x (list 1))) + (setf (car x) 1) + x))) + (declare (dynamic-extent *))))) + ((1) 1))) + +(with-test (:name :let-setf-aref) + (checked-compile + `(lambda () + (declare (optimize debug)) + (let ((x (let ((z (make-array 3))) + (setf (aref z 0) 10) + (setf (aref z 0) 20) + z))) + (declare (dynamic-extent x)) + (aref x 0))) + :allow-notes nil)) diff --git a/tests/elfcore.test.sh b/tests/elfcore.test.sh index 790d9cb4dc..b194d8c364 100755 --- a/tests/elfcore.test.sh +++ b/tests/elfcore.test.sh @@ -16,8 +16,8 @@ export TEST_BASEDIR=${TMPDIR:-/tmp} . ./subr.sh -run_sbcl --noinform <<EOF - #+(and elf sb-thread) +run_sbcl <<EOF + #+(and linux elf sb-thread) (let ((s (find-symbol "IMMOBILE-SPACE-OBJ-P" "SB-KERNEL"))) (when (and s (funcall s #'car)) (exit :code 0))) ; good (exit :code 2) ; otherwise @@ -33,11 +33,41 @@ set -e # exit on error # Ensure that we're not running a stale shrinkwrap-sbcl (cd $SBCL_PWD/../src/runtime ; rm -f shrinkwrap-sbcl ; make shrinkwrap-sbcl) -$SBCL_PWD/../src/runtime/shrinkwrap-sbcl --disable-debugger --noprint <<EOF +# Prevent style-warnings in the editcore script, but don't assume that it +# can be compiled in the first place unless actually doing the ELFcore tests. +run_sbcl <<EOF + (let ((*evaluator-mode* :interpret)) + (load "../tests/test-util") + (load "../tools-for-build/corefile")) + (test-util:with-scratch-file (fasl "fasl") + (assert (not (nth-value 1 + (compile-file "../tools-for-build/editcore" + :output-file fasl :print nil))))) +EOF + +$SBCL_PWD/../src/runtime/shrinkwrap-sbcl --disable-debugger --no-sysinit --no-userinit --noprint <<EOF +(sb-vm::make-immobile-symbol "junk") ; crashed 'cause I forgot to use rip-relative-EA +;; I think this tests immobile space exhaustion (dotimes (i 100000) (sb-vm::alloc-immobile-fdefn)) + +;; Test that the link step did not use --export-dynamic +(assert (gethash '("TEXT_SPACE_START") (car sb-sys:*linkage-info*))) ; C symbol exists +; but dlsym() can't see it +(assert (not (sb-sys:find-dynamic-foreign-symbol-address "TEXT_SPACE_START"))) +; but we can read the value +(assert (funcall (compile nil '(lambda () sb-vm:text-space-start)))) + +;; Test that CODE-SERIAL# is never 0 except for simple-fun-less objects +(sb-vm:map-allocated-objects + (lambda (obj type size) + (declare (ignore size)) + (when (and (= type sb-vm:code-header-widetag) + (> (sb-kernel:code-n-entries obj) 0)) + (assert (/= (sb-kernel:%code-serialno obj) 0)))) + :all) ;; This just needs any function that when ELFinated has its packed fixups rewritten. ;; If the packed value is a bignum, it goes into a C data section. -(let* ((code (sb-kernel:fun-code-header #'sb-impl::schedule-timer)) +(let* ((code (sb-kernel:fun-code-header #'compile-file)) (fixups (sb-vm::%code-fixups code))) (assert (typep fixups 'bignum)) (assert (not (heap-allocated-p fixups)))) @@ -51,15 +81,21 @@ echo Basic smoke test: PASS create_test_subdirectory tmpcore=$TEST_DIRECTORY/$TEST_FILESTEM.tmpcore -run_sbcl --noinform <<EOF +run_sbcl <<EOF (setq sb-c:*compile-to-memory-space* :dynamic) ;; Call an assembly routine from dynamic space (defun f (x y z) (+ x (- y z))) (compile 'f) + ;; :AUTO physically allocates code in immobile space (unless it fills up) + ;; using instruction forms that do not assume immobile space + ;; (for that same reason) which caused a glitch in editcore. + (setq sb-c:*compile-to-memory-space* :auto) + (defun g (fun &rest args) (apply fun args)) ; exercise TAIL-CALL-VARIABLE + (compile 'g) (save-lisp-and-die "${tmpcore}") EOF -m_arg=`run_sbcl --eval '(progn #+sb-core-compression (princ " -lz") #+x86 (princ " -m32"))' --quit` +m_arg=`run_sbcl --eval '(progn #+sb-core-compression (princ " -lzstd") #+x86 (princ " -m32"))' --quit` (cd $SBCL_PWD/../src/runtime ; rm -f libsbcl.a; make libsbcl.a) run_sbcl --script ../tools-for-build/editcore.lisp split \ diff --git a/tests/enc-cn.impure.lisp b/tests/enc-cn.pure.lisp similarity index 94% rename from tests/enc-cn.impure.lisp rename to tests/enc-cn.pure.lisp index 4b9569acbb..0460a828b7 100644 --- a/tests/enc-cn.impure.lisp +++ b/tests/enc-cn.pure.lisp @@ -1,7 +1,6 @@ ;;; -*- coding: utf-8 -*- ;;; enc-cn.impure.lisp: test case for enc-cn.lisp and enc-cn-tbl.lisp -#-sb-unicode -(sb-ext:exit :code 104) +#+(or (not sb-unicode) unicode-lite) (invoke-restart 'run-tests::skip-file) (let ((str (coerce '(#\u0031 #\u0041 #\uff21 #\u3042 #\u80e1 #\u73a5 #\u59ee) 'string)) diff --git a/tests/enc-jpn.impure.lisp b/tests/enc-jpn.pure.lisp similarity index 95% rename from tests/enc-jpn.impure.lisp rename to tests/enc-jpn.pure.lisp index 52a01285fa..681f855add 100644 --- a/tests/enc-jpn.impure.lisp +++ b/tests/enc-jpn.pure.lisp @@ -1,6 +1,5 @@ ;; -*- coding: utf-8 -*- -#-sb-unicode -(sb-ext:exit :code 104) +#+(or (not sb-unicode) unicode-lite) (invoke-restart 'run-tests::skip-file) (let ((str (coerce '(#\u0041 #\uff71 #\uff21 #\u3042 #\u6f3e #\u71f9 #\u91ed) 'string)) diff --git a/tests/error-source-path.impure.lisp b/tests/error-source-path.impure.lisp index 301699b206..f79d6eb597 100644 --- a/tests/error-source-path.impure.lisp +++ b/tests/error-source-path.impure.lisp @@ -137,7 +137,7 @@ (locally (declare (optimize (safety 0))) (defstruct f (x (print t) :type fixnum))) - (2 2)) + (1 2 2)) (assert-condition-source-paths (locally (declare (optimize (safety 0))) (defstruct f @@ -277,4 +277,52 @@ (with-test (:name (:source-path typep :invalid-type-specifier)) (assert-condition-source-paths (typep 1 'undefined-type) - (2))) + ;; both the style-warning and the note count + (2) (2))) + +(with-test (:name :dead-code-note-after-transforms) + (assert + (typep (nth-value 4 + (checked-compile + `(lambda (x) + (when nil + (funcall x))))) + '(cons sb-ext:code-deletion-note null)))) + +(with-test (:name :ignore-deleted-subforms) + (assert-condition-source-paths + (lambda (x m) + (when nil + (funcall x + (if m + (print 20) + (print x))))) + (2 2))) + +(with-test (:name :ignore-deleted-subforms.2) + (assert-condition-source-paths + (lambda () + (when nil + (let ((z (print 10))) + z))) + (2 2))) + +(with-test (:name :ignore-deleted-subforms.3) + (assert-condition-source-paths + (lambda (x) + (when x + (unless x + (let ((z (print 10))) + (if z + 10 + (funcall x)))))) + (2 2 2))) + +(with-test (:name :ignore-deleted-subforms.4) + (assert-condition-source-paths + (lambda (x) + (when nil + (if (print 10) + 10 + x))) + (2 2))) diff --git a/tests/exhaust.impure.lisp b/tests/exhaust.impure.lisp index 55266f7ba1..6a9b1d1c98 100644 --- a/tests/exhaust.impure.lisp +++ b/tests/exhaust.impure.lisp @@ -11,8 +11,9 @@ ;;;; absolutely no warranty. See the COPYING and CREDITS files for ;;;; more information. -#+interpreter (sb-ext:exit :code 104) +#+interpreter (invoke-restart 'run-tests::skip-file) +(test-util::disable-profiling) ;;; Prior to sbcl-0.7.1.38, doing something like (RECURSE), even in ;;; safe code, would crash the entire Lisp process. Then the soft @@ -30,6 +31,11 @@ (defvar *count* 100) +;; Don't want to keep seeing failures that happen under parallel-exec +;; (It's not even "random" now - it's pretty reliable) +;; Gotta do with fork() or something that I don't care to diagnose. +#+(and darwin x86-64 parallel-test-runner) (invoke-restart 'run-tests::skip-file) + ;;; Base-case: detecting exhaustion (with-test (:name (:exhaust :basic)) (assert (eq :exhausted diff --git a/tests/exit-hang.impure.lisp b/tests/exit-hang.impure.lisp new file mode 100644 index 0000000000..d88cb789e8 --- /dev/null +++ b/tests/exit-hang.impure.lisp @@ -0,0 +1,76 @@ +#+(or (not sb-thread) win32) (invoke-restart 'run-tests::skip-file) + +;;; Not an exactly an "exit hang" test, but there was a different hang +;;; regarding concurrent JOIN-THREAD on 1 thread. +;;; Even though POSIX threads would consider this to be undefined behavior with +;;; its thread abstraction, it's not undefined behavior in SBCL (for now) +;;; though I do think it's slightly suspicious to depend on this. +(with-test (:name :concurrent-join-thread) + (let* ((other-guy (sb-thread:make-thread #'sleep :arguments .2 :name "sleepyhead")) + (joiners + (loop repeat 4 + collect (sb-thread:make-thread #'sb-thread:join-thread + :arguments other-guy)))) + ;; The joiners should all return + (mapc 'sb-thread:join-thread joiners))) + +;;; This uses the same C source file as fcb-threads. +;;; This is OK in the parallel test runner because WITH-SCRATCH-FILE +;;; includes the PID in the temp file name. +(if (probe-file "fcb-threads.so") + ;; Assume the test automator built this for us + (load-shared-object (truename "fcb-threads.so")) + ;; Otherwise, write into /tmp so that we never fail to rebuild + ;; the '.so' if it gets changed, and assume that it's OK to + ;; delete a mapped file (which it is for *nix). + (with-scratch-file (solib "so") + (sb-ext:run-program "/bin/sh" + `("run-compiler.sh" "-sbcl-pic" "-sbcl-shared" + "-o" ,solib "fcb-threads.c")) + (sb-alien:load-shared-object solib))) + +;;; Final test: EXIT does not lock up due to (simulated) C++ destructors +;;; or free() or most anything else involved in stopping the main thread. +;;; The point of the test is to mock a Lisp thread that uses foreign code +;;; that uses malloc and free or equivalent from C++. +;;; The behavior being tested is the effect of SB-THREAD:ABORT-THREAD on +;;; a thread that happened to be just at that moment in the foreign code. +;;; We can't - or don't need to - exactly replicate the behavior +;;; of doing a lot of memory allocation. All we need to demonstrate is +;;; that we won't interrupt a malloc() or free(). +(defglobal *should-i-keep-going* t) +(defun mess-around-with-foreign-calls () + ;; In reality the thread would not permanently own the lock, but this is the + ;; simplest way to simulate the random occurrence that it does own the lock + ;; exactly when terminated. + ;; So make it own the lock forever unless politely (i.e. not forcibly) terminated. + (alien-funcall (extern-alien "acquire_a_global_lock" (function void))) + (loop (sb-thread:barrier (:read)) + (unless *should-i-keep-going* (return)) + (sleep .75)) + (format *error-output* "~&Worker thread politely exiting~%") + (alien-funcall (extern-alien "release_a_global_lock" (function void)))) + +(sb-thread:make-thread #'mess-around-with-foreign-calls) + +(push (compile nil + '(lambda () + (format t "~&Invoked exit hook~%") + (setq *should-i-keep-going* nil))) + *exit-hooks*) + +;;; The actual code under test involved C++ destructors that are +;;; interposed between our call to OS-EXIT and the OS call per se. +;;; Acquiring a globally shared mutex in OS-EXIT simulates that. +(sb-int:encapsulate + 'sb-sys:os-exit + 'simulate-c++-destructors + (lambda (realfun code &key abort) + (format t "~&Enter OS-EXIT ~s ~s~%" code abort) + (alien-funcall (extern-alien "acquire_a_global_lock" (function void))) + (alien-funcall (extern-alien "release_a_global_lock" (function void))) + (funcall realfun code :abort abort))) + +;;; Give ourselves 3 seconds to exit. +(alien-funcall (extern-alien "prepare_exit_test" (function void int)) 3) +(setq sb-ext:*forcibly-terminate-threads-on-exit* nil) diff --git a/tests/extended-sequences.impure.lisp b/tests/extended-sequences.impure.lisp index 30eebe96e7..ae3a1dd177 100644 --- a/tests/extended-sequences.impure.lisp +++ b/tests/extended-sequences.impure.lisp @@ -95,3 +95,44 @@ (x :from-end t) (loop until (stop) collect (value) do (next)))) (('(a b c d)) '(d c b a) :test #'equal))) + +(defclass my-list (sequence standard-object) + ((%nilp :initarg :nilp :initform nil :accessor nilp) + (%kar :initarg :kar :accessor kar) + (%kdr :initarg :kdr :accessor kdr))) + +(defun my-list (&rest elems) + (if (null elems) + (load-time-value (make-instance 'my-list :nilp t) t) + (make-instance 'my-list + :kar (first elems) :kdr (apply #'my-list (rest elems))))) + +(defmethod sequence:length ((sequence my-list)) + (if (nilp sequence) + 0 + (1+ (length (kdr sequence))))) + +(defmethod sequence:make-sequence-iterator + ((sequence my-list) &key from-end start end) + (declare (ignore from-end start end)) + (values sequence (my-list) nil + (lambda (sequence iterator from-end) + (declare (ignore sequence from-end)) + (kdr iterator)) + (lambda (sequence iterator limit from-end) + (declare (ignore sequence from-end)) + (eq iterator limit)) + (lambda (sequence iterator) + (declare (ignore sequence)) + (kar iterator)) + (lambda (new sequence iterator) + (declare (ignore sequence)) + (setf (kar iterator) new)) + (constantly 0) + (lambda (sequence iterator) + (declare (ignore sequence)) + iterator))) + +(with-test (:name :map-into) + (assert (equal (coerce (map-into (my-list 1 2 3) #'identity '(4 5 6)) 'list) + '(4 5 6)))) diff --git a/tests/external-format.impure.lisp b/tests/external-format.pure.lisp similarity index 90% rename from tests/external-format.impure.lisp rename to tests/external-format.pure.lisp index d422b4000d..920f6e0938 100644 --- a/tests/external-format.impure.lisp +++ b/tests/external-format.pure.lisp @@ -15,6 +15,17 @@ ;;;; absolutely no warranty. See the COPYING and CREDITS files for ;;;; more information. +;;; I have absolutely no idea what's going on with ppc64 little-endian, +;;; but this file's realtime is just ridiculous on the test machine +;;; and it totally dominates the time taken in parallel-exec: +;;; big-endian: real 0m3.265s +;;; little-endian: real 2m53.039s +;;; Whereas, with this one file eliminated on ppc64le, the total wallclock +;;; time for parallel-exec (with 12 workers) is approximately 94 seconds +;;; on either machine. What is so horrible about our external-format codecs +;;; that it antagonizes the little-endian CPU so badly? +#+(and ppc64 little-endian) (invoke-restart 'run-tests::skip-file) + (defmacro do-external-formats ((xf) &body body) (let ((nxf (gensym))) `(sb-int:dovector (,nxf sb-impl::*external-formats*) @@ -22,6 +33,15 @@ (let ((,xf (first (sb-impl::ef-names (car (sb-int:ensure-list ,nxf)))))) ,@body))))) +(defmacro with-ef-test (options &rest rest) + (let* ((test-name (getf options :name)) + (ef-name (car (last test-name)))) + (if (sb-impl::get-external-format ef-name) + `(with-test ,options ,@rest) + `(format t "::: INFO: no external format named ~S~%" ',ef-name)))) + +(defun try-delete-file (x) (when (probe-file x) (delete-file x))) + (defvar *test-path* (scratch-file-name)) (with-test (:name :end-of-file) @@ -54,7 +74,7 @@ #-sb-unicode (progn (test-util:report-test-status) - (sb-ext:exit :code 104)) + (invoke-restart 'run-tests::skip-file)) ;;; Test UTF-8 writing and reading of 1, 2, 3 and 4 octet characters with ;;; all possible offsets. Tests for buffer edge bugs. fd-stream buffers are @@ -223,6 +243,8 @@ ;;;; KOI8-R external format +#-unicode-lite +(progn (with-open-file (s *test-path* :direction :output :if-exists :supersede :external-format :koi8-r) (write-char (code-char #xB0) s) @@ -242,7 +264,6 @@ :external-format :koi8-r) (let ((char (read-char s))) (assert (= (char-code (eval char)) #xB0)))) -(delete-file *test-path*) (let* ((koi8-r-codes (coerce '(240 210 201 215 197 212 33) '(vector (unsigned-byte 8)))) (uni-codes #(1055 1088 1080 1074 1077 1090 33)) @@ -254,6 +275,9 @@ uni-codes)) (assert (equalp (string-to-octets (map 'string #'code-char uni-codes) :external-format :koi8-r) koi8-r-codes))) +) +(try-delete-file *test-path*) + ;;; tests of FILE-STRING-LENGTH (let ((standard-characters "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!$\"'(),_-./:;?+<=>#%&*@[\\]{|}`^~")) @@ -363,19 +387,19 @@ (list (code-char 195)) (list (code-char 164))))))) -(with-test (:name (:sb-alien :ebcdic :ebcdic)) +(with-ef-test (:name (:sb-alien :ebcdic :ebcdic-us)) (define-alien-routine (#-win32 "strdup" #+win32 "_strdup" strdup) (c-string :external-format :ebcdic-us) (str (c-string :external-format :ebcdic-us))) (assert (equal "foo" (strdup "foo")))) -(with-test (:name (:sb-alien :latin-1 :ebcdic)) +(with-ef-test (:name (:sb-alien :latin-1 :ebcdic-us)) (define-alien-routine (#-win32 "strdup" #+win32 "_strdup" strdup) (c-string :external-format :latin-1) (str (c-string :external-format :ebcdic-us))) (assert (not (equal "foo" (strdup "foo"))))) -(with-test (:name (:sb-alien :simple-base-string)) +(with-ef-test (:name (:sb-alien :simple-base-string :ebcdic-us)) (define-alien-routine (#-win32 "strdup" #+win32 "_strdup" strdup) (c-string :external-format :ebcdic-us :element-type base-char) @@ -396,7 +420,7 @@ (assert (or (= i (char-code #\?)) (> i 127)))) (t (assert (and (not (= i (char-code #\?))) (< i 128))))))))) -(with-test (:name (:unibyte-invalid-codepoints :cp857)) +(with-ef-test (:name (:unibyte-invalid-codepoints :cp857)) (dotimes (i 256) (with-open-file (s *test-path* :direction :output :if-exists :supersede :element-type '(unsigned-byte 8)) (write-byte i s)) @@ -404,9 +428,9 @@ (handler-case (read-char s) (error () (assert (member i '(#xd5 #xe7 #xf2)))) (:no-error (char) char (assert (not (member i '(#xd5 #xe7 #xf2))))))))) -(delete-file *test-path*) +(try-delete-file *test-path*) -(with-test (:name (:unibyte-input-replacement :cp857)) +(with-ef-test (:name (:unibyte-input-replacement :cp857)) (dotimes (i 256) (with-open-file (s *test-path* :direction :output :if-exists :supersede :element-type '(unsigned-byte 8)) (write-byte i s)) @@ -416,9 +440,9 @@ ((eq char #\?) (assert (member i `(,(char-code #\?) #xd5 #xe7 #xf2)))) (t (assert (not (member i `(,(char-code #\?) #xd5 #xe7 #xf2)))))))))) -(delete-file *test-path*) +(try-delete-file *test-path*) -(with-test (:name (:unibyte-output-replacement :cp857)) +(with-ef-test (:name (:unibyte-output-replacement :cp857)) (with-open-file (s *test-path* :direction :output :if-exists :supersede :external-format '(:cp857 :replacement #\?)) (dotimes (i 256) (write-char (code-char i) s))) @@ -428,7 +452,7 @@ (dotimes (i 128) (assert (= (char-code (char string i)) i))) (assert (= 38 (count #\? string :start 128)))))) -(delete-file *test-path*) +(try-delete-file *test-path*) (with-test (:name (:unibyte-input-replacement :ascii)) (dotimes (i 256) @@ -476,7 +500,7 @@ (delete-file *test-path*) ;;; latin-2 tests -(with-test (:name (:unibyte-input-replacement :latin-2)) +(with-ef-test (:name (:unibyte-input-replacement :latin-2)) (dotimes (i 256) (with-open-file (s *test-path* :direction :output :if-exists :supersede :element-type '(unsigned-byte 8)) (write-byte i s)) @@ -486,9 +510,9 @@ ((< i #xa1) (assert (= (char-code char) i))) ;; FIXME: more tests ))))) -(delete-file *test-path*) +(try-delete-file *test-path*) -(with-test (:name (:unibyte-output-replacement :latin-2)) +(with-ef-test (:name (:unibyte-output-replacement :latin-2)) (with-open-file (s *test-path* :direction :output :if-exists :supersede :external-format '(:latin-2 :replacement #\?)) (dotimes (i 256) (write-char (code-char i) s))) @@ -498,10 +522,10 @@ (dotimes (i #xa1) (assert (= (char-code (char string i)) i))) (assert (= 57 (count #\? string :start #xa1)))))) -(delete-file *test-path*) +(try-delete-file *test-path*) ;;; latin-3 tests -(with-test (:name (:unibyte-input-replacement :latin-3)) +(with-ef-test (:name (:unibyte-input-replacement :latin-3)) (dotimes (i 256) (with-open-file (s *test-path* :direction :output :if-exists :supersede :element-type '(unsigned-byte 8)) (write-byte i s)) @@ -512,9 +536,9 @@ (assert #1=(or (= i (char-code #\?)) (member i '(#xa5 #xae #xbe #xc3 #xd0 #xe3 #xf0))))) (t (assert (not #1#)))))))) -(delete-file *test-path*) +(try-delete-file *test-path*) -(with-test (:name (:unibyte-output-replacement :latin-3)) +(with-ef-test (:name (:unibyte-output-replacement :latin-3)) (with-open-file (s *test-path* :direction :output :if-exists :supersede :external-format '(:latin-3 :replacement #\?)) (dotimes (i 256) (write-char (code-char i) s))) @@ -524,10 +548,10 @@ (dotimes (i #xa1) (assert (= (char-code (char string i)) i))) (assert (= 35 (count #\? string :start #xa1)))))) -(delete-file *test-path*) +(try-delete-file *test-path*) ;;; latin-4 tests -(with-test (:name (:unibyte-input-replacement :latin-4)) +(with-ef-test (:name (:unibyte-input-replacement :latin-4)) (dotimes (i 256) (with-open-file (s *test-path* :direction :output :if-exists :supersede :element-type '(unsigned-byte 8)) (write-byte i s)) @@ -537,9 +561,9 @@ ((< i #xa1) (assert (= (char-code char) i))) ;; FIXME: more tests ))))) -(delete-file *test-path*) +(try-delete-file *test-path*) -(with-test (:name (:unibyte-output-replacement :latin-4)) +(with-ef-test (:name (:unibyte-output-replacement :latin-4)) (with-open-file (s *test-path* :direction :output :if-exists :supersede :external-format '(:latin-4 :replacement #\?)) (dotimes (i 256) (write-char (code-char i) s))) @@ -549,10 +573,10 @@ (dotimes (i #xa1) (assert (= (char-code (char string i)) i))) (assert (= 50 (count #\? string :start #xa1)))))) -(delete-file *test-path*) +(try-delete-file *test-path*) ;;; iso-8859-5 tests -(with-test (:name (:unibyte-input-replacement :iso-8859-5)) +(with-ef-test (:name (:unibyte-input-replacement :iso-8859-5)) (dotimes (i 256) (with-open-file (s *test-path* :direction :output :if-exists :supersede :element-type '(unsigned-byte 8)) (write-byte i s)) @@ -562,9 +586,9 @@ ((= (char-code char) i) (assert (or (< i #xa1) (= i #xad)))) (t (assert (and (>= i #xa1) (/= i #xad))))))))) -(delete-file *test-path*) +(try-delete-file *test-path*) -(with-test (:name (:unibyte-output-replacement :iso-8859-5)) +(with-ef-test (:name (:unibyte-output-replacement :iso-8859-5)) (with-open-file (s *test-path* :direction :output :if-exists :supersede :external-format '(:iso-8859-5 :replacement #\?)) (dotimes (i 256) (write-char (code-char i) s))) @@ -574,10 +598,10 @@ (dotimes (i #xa1) (assert (= (char-code (char string i)) i))) (assert (= 93 (count #\? string :start #xa1)))))) -(delete-file *test-path*) +(try-delete-file *test-path*) ;;; iso-8859-6 tests -(with-test (:name (:unibyte-input-replacement :iso-8859-6)) +(with-ef-test (:name (:unibyte-input-replacement :iso-8859-6)) (dotimes (i 256) (with-open-file (s *test-path* :direction :output :if-exists :supersede :element-type '(unsigned-byte 8)) (write-byte i s)) @@ -590,9 +614,9 @@ (<= #xbc i #xbe) (= i #xc0) (<= #xdb i #xdf) (<= #xf3 i)))) (t (assert (not #1#)))))))) -(delete-file *test-path*) +(try-delete-file *test-path*) -(with-test (:name (:unibyte-output-replacement :iso-8859-6)) +(with-ef-test (:name (:unibyte-output-replacement :iso-8859-6)) (with-open-file (s *test-path* :direction :output :if-exists :supersede :external-format '(:iso-8859-6 :replacement #\?)) (dotimes (i 256) (write-char (code-char i) s))) @@ -602,10 +626,10 @@ (dotimes (i #xa1) (assert (= (char-code (char string i)) i))) (assert (= 93 (count #\? string :start #xa1)))))) -(delete-file *test-path*) +(try-delete-file *test-path*) ;;; iso-8859-7 tests -(with-test (:name (:unibyte-input-replacement :iso-8859-7)) +(with-ef-test (:name (:unibyte-input-replacement :iso-8859-7)) (dotimes (i 256) (with-open-file (s *test-path* :direction :output :if-exists :supersede :element-type '(unsigned-byte 8)) (write-byte i s)) @@ -616,9 +640,9 @@ (assert #1=(or (= i (char-code #\?)) (member i '(#xa4 #xa5 #xaa #xae #xd2 #xff))))) (t (assert (not #1#)))))))) -(delete-file *test-path*) +(try-delete-file *test-path*) -(with-test (:name (:unibyte-output-replacement :iso-8859-7)) +(with-ef-test (:name (:unibyte-output-replacement :iso-8859-7)) (with-open-file (s *test-path* :direction :output :if-exists :supersede :external-format '(:iso-8859-7 :replacement #\?)) (dotimes (i 256) (write-char (code-char i) s))) @@ -628,10 +652,10 @@ (dotimes (i #xa1) (assert (= (char-code (char string i)) i))) (assert (= 80 (count #\? string :start #xa1)))))) -(delete-file *test-path*) +(try-delete-file *test-path*) ;;; iso-8859-8 tests -(with-test (:name (:unibyte-input-replacement :iso-8859-8)) +(with-ef-test (:name (:unibyte-input-replacement :iso-8859-8)) (dotimes (i 256) (with-open-file (s *test-path* :direction :output :if-exists :supersede :element-type '(unsigned-byte 8)) (write-byte i s)) @@ -642,9 +666,9 @@ (assert #1=(or (= i (char-code #\?)) (= i #xa1) (<= #xbf i #xde) (>= i #xfb)))) (t (assert (not #1#)))))))) -(delete-file *test-path*) +(try-delete-file *test-path*) -(with-test (:name (:unibyte-output-replacement :iso-8859-8)) +(with-ef-test (:name (:unibyte-output-replacement :iso-8859-8)) (with-open-file (s *test-path* :direction :output :if-exists :supersede :external-format '(:iso-8859-8 :replacement #\?)) (dotimes (i 256) (write-char (code-char i) s))) @@ -654,10 +678,10 @@ (dotimes (i #xa1) (assert (= (char-code (char string i)) i))) (assert (= 67 (count #\? string :start #xa1)))))) -(delete-file *test-path*) +(try-delete-file *test-path*) ;;; latin-5 tests -(with-test (:name (:unibyte-input-replacement :latin-5)) +(with-ef-test (:name (:unibyte-input-replacement :latin-5)) (dotimes (i 256) (with-open-file (s *test-path* :direction :output :if-exists :supersede :element-type '(unsigned-byte 8)) (write-byte i s)) @@ -667,9 +691,9 @@ (not (member i '(#xd0 #xdd #xde #xf0 #xfd #xfe)))) (and (member i '(#xd0 #xdd #xde #xf0 #xfd #xfe)) (not (char= char #\?))))))))) -(delete-file *test-path*) +(try-delete-file *test-path*) -(with-test (:name (:unibyte-output-replacement :latin-5)) +(with-ef-test (:name (:unibyte-output-replacement :latin-5)) (with-open-file (s *test-path* :direction :output :if-exists :supersede :external-format '(:latin-5 :replacement #\?)) (dotimes (i 256) (write-char (code-char i) s))) @@ -679,10 +703,10 @@ (dotimes (i #xd0) (assert (= (char-code (char string i)) i))) (assert (= 6 (count #\? string :start #xd0)))))) -(delete-file *test-path*) +(try-delete-file *test-path*) ;;; latin-6 tests -(with-test (:name (:unibyte-input-replacement :latin-6)) +(with-ef-test (:name (:unibyte-input-replacement :latin-6)) (dotimes (i 256) (with-open-file (s *test-path* :direction :output :if-exists :supersede :element-type '(unsigned-byte 8)) (write-byte i s)) @@ -691,9 +715,9 @@ (assert (or (= (char-code char) i) (and (<= #xa1 i #xff) (not (char= char #\?))))))))) -(delete-file *test-path*) +(try-delete-file *test-path*) -(with-test (:name (:unibyte-output-replacement :latin-6)) +(with-ef-test (:name (:unibyte-output-replacement :latin-6)) (with-open-file (s *test-path* :direction :output :if-exists :supersede :external-format '(:latin-6 :replacement #\?)) (dotimes (i 256) (write-char (code-char i) s))) @@ -703,10 +727,10 @@ (dotimes (i #xa1) (assert (= (char-code (char string i)) i))) (assert (= 46 (count #\? string :start #xa1)))))) -(delete-file *test-path*) +(try-delete-file *test-path*) ;;; iso-8859-11 tests -(with-test (:name (:unibyte-input-replacement :iso-8859-11)) +(with-ef-test (:name (:unibyte-input-replacement :iso-8859-11)) (dotimes (i 256) (with-open-file (s *test-path* :direction :output :if-exists :supersede :element-type '(unsigned-byte 8)) (write-byte i s)) @@ -716,9 +740,9 @@ ((eq char #\?) (assert (member i #1=`(,(char-code #\?) #xdb #xdc #xdd #xde #xfc #xfd #xfe #xff)))) (t (assert (not (member i #1#))))))))) -(delete-file *test-path*) +(try-delete-file *test-path*) -(with-test (:name (:unibyte-output-replacement :iso-8859-11)) +(with-ef-test (:name (:unibyte-output-replacement :iso-8859-11)) (with-open-file (s *test-path* :direction :output :if-exists :supersede :external-format '(:iso-8859-11 :replacement #\?)) (dotimes (i 256) (write-char (code-char i) s))) @@ -728,10 +752,10 @@ (dotimes (i #xa1) (assert (= (char-code (char string i)) i))) (assert (= 95 (count #\? string :start #xa1)))))) -(delete-file *test-path*) +(try-delete-file *test-path*) ;;; latin-7 tests -(with-test (:name (:unibyte-input-replacement :latin-7)) +(with-ef-test (:name (:unibyte-input-replacement :latin-7)) (dotimes (i 256) (with-open-file (s *test-path* :direction :output :if-exists :supersede :element-type '(unsigned-byte 8)) (write-byte i s)) @@ -740,9 +764,9 @@ (assert (or (= (char-code char) i) (and (<= #xa1 i #xff) (not (char= char #\?))))))))) -(delete-file *test-path*) +(try-delete-file *test-path*) -(with-test (:name (:unibyte-output-replacement :latin-7)) +(with-ef-test (:name (:unibyte-output-replacement :latin-7)) (with-open-file (s *test-path* :direction :output :if-exists :supersede :external-format '(:latin-7 :replacement #\?)) (dotimes (i 256) (write-char (code-char i) s))) @@ -754,10 +778,10 @@ (dolist (i '(#xd8 #xc6 #xf8 #xe6)) (assert (char/= (char string i) #\?))) (assert (= 52 (count #\? string :start #xa1)))))) -(delete-file *test-path*) +(try-delete-file *test-path*) ;;; latin-8 tests -(with-test (:name (:unibyte-input-replacement :latin-8)) +(with-ef-test (:name (:unibyte-input-replacement :latin-8)) (dotimes (i 256) (with-open-file (s *test-path* :direction :output :if-exists :supersede :element-type '(unsigned-byte 8)) (write-byte i s)) @@ -766,9 +790,9 @@ (assert (or (= (char-code char) i) (and (<= #xa1 i #xfe) (not (char= char #\?))))))))) -(delete-file *test-path*) +(try-delete-file *test-path*) -(with-test (:name (:unibyte-output-replacement :latin-8)) +(with-ef-test (:name (:unibyte-output-replacement :latin-8)) (with-open-file (s *test-path* :direction :output :if-exists :supersede :external-format '(:latin-8 :replacement #\?)) (dotimes (i 256) (write-char (code-char i) s))) @@ -778,10 +802,10 @@ (dotimes (i #xa1) (assert (= (char-code (char string i)) i))) (assert (= 31 (count #\? string :start #xa1)))))) -(delete-file *test-path*) +(try-delete-file *test-path*) ;;; latin-9 tests -(with-test (:name (:unibyte-input-replacement :latin-9)) +(with-ef-test (:name (:unibyte-input-replacement :latin-9)) (dotimes (i 256) (with-open-file (s *test-path* :direction :output :if-exists :supersede :element-type '(unsigned-byte 8)) (write-byte i s)) @@ -791,9 +815,9 @@ (not (member i '(#xa4 #xa6 #xa8 #xb4 #xb8 #xbc #xbd #xbe)))) (and (member i '(#xa4 #xa6 #xa8 #xb4 #xb8 #xbc #xbd #xbe)) (not (char= char #\?))))))))) -(delete-file *test-path*) +(try-delete-file *test-path*) -(with-test (:name (:unibyte-output-replacement :latin-9)) +(with-ef-test (:name (:unibyte-output-replacement :latin-9)) (with-open-file (s *test-path* :direction :output :if-exists :supersede :external-format '(:latin-9 :replacement #\?)) (dotimes (i 256) (write-char (code-char i) s))) @@ -803,10 +827,11 @@ (dotimes (i #xa4) (assert (= (char-code (char string i)) i))) (assert (= 8 (count #\? string :start #xa4)))))) -(delete-file *test-path*) +(try-delete-file *test-path*) ;;; koi8-r tests -(with-test (:name (:unibyte-input-replacement :koi8-r)) +(with-ef-test (:name (:unibyte-input-replacement :koi8-r) + :skipped-on :unicode-lite) (dotimes (i 256) (with-open-file (s *test-path* :direction :output :if-exists :supersede :element-type '(unsigned-byte 8)) (write-byte i s)) @@ -815,9 +840,9 @@ (cond ((= (char-code char) i) (assert (< i 128))) (t (assert (> i 127)))))))) -(delete-file *test-path*) +(try-delete-file *test-path*) -(with-test (:name (:unibyte-output-replacement :koi8-r)) +(with-ef-test (:name (:unibyte-output-replacement :koi8-r)) (with-open-file (s *test-path* :direction :output :if-exists :supersede :external-format '(:koi8-r :replacement #\?)) (dotimes (i 256) (write-char (code-char i) s))) @@ -827,10 +852,10 @@ (dotimes (i #x80) (assert (= (char-code (char string i)) i))) (assert (= 122 (count #\? string :start #x80)))))) -(delete-file *test-path*) +(try-delete-file *test-path*) ;;; koi8-u tests -(with-test (:name (:unibyte-input-replacement :koi8-u)) +(with-ef-test (:name (:unibyte-input-replacement :koi8-u)) (dotimes (i 256) (with-open-file (s *test-path* :direction :output :if-exists :supersede :element-type '(unsigned-byte 8)) (write-byte i s)) @@ -839,9 +864,9 @@ (cond ((= (char-code char) i) (assert (< i 128))) (t (assert (> i 127)))))))) -(delete-file *test-path*) +(try-delete-file *test-path*) -(with-test (:name (:unibyte-output-replacement :koi8-u)) +(with-ef-test (:name (:unibyte-output-replacement :koi8-u)) (with-open-file (s *test-path* :direction :output :if-exists :supersede :external-format '(:koi8-u :replacement #\?)) (dotimes (i 256) (write-char (code-char i) s))) @@ -851,10 +876,10 @@ (dotimes (i #x80) (assert (= (char-code (char string i)) i))) (assert (= 122 (count #\? string :start #x80)))))) -(delete-file *test-path*) +(try-delete-file *test-path*) ;;; x-mac-cyrillic tests -(with-test (:name (:unibyte-input-replacement :x-mac-cyrillic)) +(with-ef-test (:name (:unibyte-input-replacement :x-mac-cyrillic)) (dotimes (i 256) (with-open-file (s *test-path* :direction :output :if-exists :supersede :element-type '(unsigned-byte 8)) (write-byte i s)) @@ -864,9 +889,9 @@ (assert (or (< i 128) (member i '(#xa2 #xa3 #xa9 #xb1 #xb5))))) (t (assert (and (> i 127) (not (member i '(#xa2 #xa3 #xa9 #xb1 #xb5))))))))))) -(delete-file *test-path*) +(try-delete-file *test-path*) -(with-test (:name (:unibyte-output-replacement :x-mac-cyrillic)) +(with-ef-test (:name (:unibyte-output-replacement :x-mac-cyrillic)) (with-open-file (s *test-path* :direction :output :if-exists :supersede :external-format '(:x-mac-cyrillic :replacement #\?)) (dotimes (i 256) (write-char (code-char i) s))) @@ -876,7 +901,7 @@ (dotimes (i #x80) (assert (= (char-code (char string i)) i))) (assert (= 113 (count #\? string :start #x80)))))) -(delete-file *test-path*) +(try-delete-file *test-path*) ;;; ucs-2 tests (with-test (:name (:multibyte :ucs2le)) @@ -1014,7 +1039,7 @@ (with-open-file (s *test-path* :external-format :utf-32be) (assert (string= " ???? " (read-line s)))))) -(with-test (:name :invalid-external-format :fails-on :win32) +(with-test (:name :invalid-external-format) (labels ((test-error (e) (assert (typep e 'error)) (unless (equal "Undefined external-format: :BAD-FORMAT" @@ -1023,7 +1048,7 @@ (test (direction) (test-error (handler-case - (open "/dev/null" :direction direction :external-format :bad-format + (open #-win32 "/dev/null" #+win32 "nul" :direction direction :external-format :bad-format :if-exists :overwrite) (error (e) e))))) (test :input) @@ -1043,7 +1068,7 @@ (octets-to-string octets :external-format :bad-format) (error (e) e)))))) -(with-test (:name :lp713063) +(with-ef-test (:name (:lp713063 :euc-jp)) (with-open-file (f *test-path* :direction :output :external-format '(:euc-jp :replacement #\?) diff --git a/tests/fast-eval.impure.lisp b/tests/fast-eval.impure.lisp index a97ff6ce98..4ac68f3bea 100644 --- a/tests/fast-eval.impure.lisp +++ b/tests/fast-eval.impure.lisp @@ -11,8 +11,7 @@ ;;;; absolutely no warranty. See the COPYING and CREDITS files for ;;;; more information. -#-sb-fasteval -(sb-ext:exit :code 104) +#-sb-fasteval (invoke-restart 'run-tests::skip-file) (setf sb-ext:*evaluator-mode* :interpret) @@ -299,6 +298,10 @@ 'foo)) (defstruct testme x) +(test-util:with-test (:name :compiled-equalp-method) + (assert (compiled-function-p + (sb-kernel:wrapper-equalp-impl + (sb-kernel:find-layout 'testme))))) (let ((f #'testme-x)) (let ((source-loc (sb-interpreter:fun-source-location f))) (setf (slot-value source-loc 'sb-c::namestring) "myfile.lisp"))) @@ -321,3 +324,16 @@ (assert (nth-value 1 (function-lambda-expression (sb-int:info :type :expander 'thingz)))) ;; and make sure the expander actually works (assert (typep "hey" '(thingz 3)))) + +(defpackage fancypkg (:use "CL" "SB-EXT") (:export make-mystruct mystruct-x)) +(in-package fancypkg) +(defstruct mystruct (x 3) y) +(in-package "CL-USER") +(lock-package "FANCYPKG") + +(defun f () + (fancypkg:mystruct-x (fancypkg:make-mystruct))) +(test-util:with-test (:name :jit-compiled-struct-accessor-locked-pkg) + (assert (eql (f) 3)) + (assert (not (compiled-function-p #'f))) + (assert (compiled-function-p #'fancypkg:mystruct-x))) diff --git a/tests/fcb-threads.c b/tests/fcb-threads.c new file mode 100644 index 0000000000..3b5bc1083b --- /dev/null +++ b/tests/fcb-threads.c @@ -0,0 +1,162 @@ +/* In as much as this file simulates "foreign" code, + * we don't include "sbcl.h" and we use the native thread API + * for the platform */ + +#ifdef _WIN32 +# include <handleapi.h> +# include <process.h> +# include <processthreadsapi.h> +# include <synchapi.h> // for WaitForSingleObject +#else +# include <pthread.h> +#endif +#include <stdio.h> +#include <stdint.h> +#include <string.h> + +struct thread_arg { void * funkyfun; int index; int n_calls; }; + +char *salutations[8] = { + "Hello", "Hi there!", "Hey", "Hi!", "Ahoy there", "What's up!", "Hola", + "That's a winner" +}; +int sharedvar; + +#ifdef _WIN32 +__stdcall unsigned int perftest_thread(LPVOID void_arg) +#else +void* perftest_thread(void* void_arg) +#endif +{ + struct thread_arg* arg = void_arg; + int (*lispfun)() = arg->funkyfun; + int ncalls = arg->n_calls; + int i; + for (i=0; i<ncalls; ++i) lispfun(); + return 0; +} + +int minimal_perftest(void* ptr, int n_calls) +{ + struct thread_arg arg; + arg.funkyfun = ptr; + arg.n_calls = n_calls; +#ifdef _WIN32 + HANDLE thr; + thr = (HANDLE)_beginthreadex(NULL, 0, perftest_thread, &arg, 0, NULL); + WaitForSingleObject(thr,0xffffffff); + CloseHandle(thr); +#else + pthread_t thr; + pthread_create(&thr, 0, perftest_thread, &arg); + pthread_join(thr,0); +#endif + return 0; +} + +#ifdef _WIN32 +__stdcall unsigned int doThatThing(void* void_arg) +#else +void* doThatThing(void* void_arg) +#endif +{ + struct thread_arg* arg = void_arg; + int thread_result = 0xC0FEFE; + int (*lispfun)(char*,double) = arg->funkyfun; + int i; + // fprintf(stderr, "enter doThatThing %p\n", void_arg); fflush(stderr); + for(i=0; i<arg->n_calls; ++i) { + int index = __sync_fetch_and_add(&sharedvar,1); + char *salutation = salutations[index % 8]; + int answer = lispfun(salutation, arg->index + i); + if (answer != (arg->index + i) * strlen(salutation)) thread_result = 0; + } + return (void*)(uintptr_t)thread_result; +} + +int call_thing_from_threads(void* ptr, int n_threads, int n_calls) +{ + struct { +#ifdef _WIN32 + HANDLE handle; + DWORD result; +#else + pthread_t pthread_id; + void* result; +#endif + struct thread_arg arg; + } threads[50]; + if (n_threads>50) { + fprintf(stderr, "pick a smaller number\n"); + return -1; + } + int i; + for(i=0; i<n_threads; ++i) { + threads[i].arg.funkyfun = ptr; + threads[i].arg.index = i + 1; + threads[i].arg.n_calls = n_calls; +#ifdef _WIN32 + threads[i].handle = (HANDLE)_beginthreadex(NULL, 0, doThatThing, &threads[i].arg, 0, NULL); +#else + pthread_create(&threads[i].pthread_id, 0, doThatThing, &threads[i].arg); +#endif + } + int all_ok = 1; + for(i=0; i<n_threads; ++i) { +#ifdef _WIN32 + DWORD result; + // I don't know which header file defines INFINITE (for the timeout) + // so any large value should do. + result = WaitForSingleObject(threads[i].handle, 0xffffffff); + GetExitCodeThread(threads[i].handle, &threads[i].result); + CloseHandle(threads[i].handle); + if (threads[i].result != 0xC0FEFE) all_ok = 0; +#else + pthread_join(threads[i].pthread_id, &threads[i].result); +#if 0 + fprintf(stderr, "%d: pthread %lx returned %p\n", + i, (long)threads[i].pthread_id, threads[i].result); +#endif + if ((uintptr_t)threads[i].result != 0xC0FEFE) all_ok = 0; +#endif + } + return all_ok; +} + +/// The code following is for the no-lockup-on-exit test, unrelated to the above +/// FIXME: implement a watchdog timer for win32 +#ifndef _WIN32 +#include <signal.h> +#include <sys/time.h> +#include <unistd.h> + +static pthread_mutex_t some_global_lock = PTHREAD_MUTEX_INITIALIZER; + +void acquire_a_global_lock() { + pthread_mutex_lock(&some_global_lock); +} +void release_a_global_lock() { + pthread_mutex_unlock(&some_global_lock); +} +static void alarmclock_expired(int sig) +{ + char msg[] = "timed out\n"; + write(2, msg, sizeof msg-1); + _exit(1); +} + +/// Exit with failure if we can't exit within a set time. +void prepare_exit_test(int seconds) +{ + struct sigaction sa; + sa.sa_handler = alarmclock_expired; + sigemptyset(&sa.sa_mask); + sa.sa_flags = 0; + sigaction(SIGALRM, &sa, 0); + struct itimerval it; + it.it_value.tv_sec = seconds; + it.it_value.tv_usec = 0; + it.it_interval.tv_sec = it.it_interval.tv_usec = 0; + setitimer(ITIMER_REAL, &it, 0); +} +#endif diff --git a/tests/fcb-threads.impure.lisp b/tests/fcb-threads.impure.lisp new file mode 100644 index 0000000000..a2c47a21b3 --- /dev/null +++ b/tests/fcb-threads.impure.lisp @@ -0,0 +1,199 @@ +;;;; callback tests + +;;;; This software is part of the SBCL system. See the README file for +;;;; more information. +;;;; +;;;; While most of SBCL is derived from the CMU CL system, the test +;;;; files (like this one) were written from scratch after the fork +;;;; from CMU CL. +;;;; +;;;; This software is in the public domain and is provided with +;;;; absolutely no warranty. See the COPYING and CREDITS files for +;;;; more information. + +;;; This reliably fails with two crashes (both in the same run) on FreeBSD: +;;; - garbage_collect: no SP known for thread 0x802bea000 (OS 34367133952) +;;; - failed AVER: (NOT (SB-THREAD::AVL-FIND ADDR SB-THREAD::OLD)) + +#+(or (not sb-thread) freebsd) (invoke-restart 'run-tests::skip-file) + +(setf (generation-number-of-gcs-before-promotion 0) 5) +(setf (generation-number-of-gcs-before-promotion 1) 3) + +#+win32 +(with-scratch-file (solib "dll") + (sb-ext:run-program "gcc" + `("-shared" "-o" ,solib "fcb-threads.c") + :search t) + (sb-alien:load-shared-object solib)) + +#-win32 +(if (probe-file "fcb-threads.so") + ;; Assume the test automator built this for us + (load-shared-object (truename "fcb-threads.so")) + ;; Otherwise, write into /tmp so that we never fail to rebuild + ;; the '.so' if it gets changed, and assume that it's OK to + ;; delete a mapped file (which it is for *nix). + (with-scratch-file (solib "so") + (sb-ext:run-program "/bin/sh" + `("run-compiler.sh" "-sbcl-pic" "-sbcl-shared" + "-o" ,solib "fcb-threads.c") + :output t :error :output) + (sb-alien:load-shared-object solib))) + +;;;; Just exercise a ton of calls from 1 thread +(define-alien-callable perftestcb int () 0) +(defun trivial-call-test (n) + (with-alien ((testfun (function int system-area-pointer int) :extern "minimal_perftest")) + (alien-funcall testfun (alien-sap (alien-callable-function 'perftestcb)) n))) +(time (trivial-call-test 200000)) + +;;;; +(defglobal *counter* 0) +(declaim (fixnum *counter*)) +(defglobal *ok* (list t)) + +(defglobal *seen-threads* nil) + +;;; A variable commissioned by the department of needless and unnecessary redundancy department +(defglobal *print-greetings-and-salutations* (or #+linux t)) + +(defglobal *semaphore* nil) +(define-alien-callable testcb int ((arg1 c-string) (arg2 double)) + (when *semaphore* (sb-thread:signal-semaphore *semaphore*)) + (let ((cell (assoc sb-thread:*current-thread* *seen-threads*)) + (result (floor (* (length arg1) arg2)))) + (unless cell + (let* ((thr sb-thread:*current-thread*) + (string + (format nil "~s,~f from [~@[TID ~d ~]C-thread ~x] ~s => ~x~%" + arg1 arg2 + (or #+linux (sb-thread::thread-os-tid thr)) + (sb-thread::thread-primitive-thread thr) + thr result))) + ;; This WRITE kind of has to stay here for timing purposes - + ;; With it, we get >100 GCs, without it only 3 or 4, + ;; and the intent of the test is to exercise GC and foreign + ;; calbacks together, which was formerly bug prone. + (when *print-greetings-and-salutations* + #+win32 (progn (write-string string) (force-output)) + #-win32 (sb-sys:with-pinned-objects (string) ; avoid interleaved output this way + (sb-unix:unix-write 1 (sb-sys:vector-sap string) 0 (length string)))) + (setq cell (cons thr (1- (floor arg2)))) + (atomic-push cell *seen-threads*))) + (assert (eql (coerce (incf (cdr cell)) 'double-float) + arg2)) + result)) + +(defglobal *keepon* t) +(defglobal *n-gcs* 0) + +(defun f (n-trials n-threads n-calls enable-gcing) + (dotimes (trialno n-trials) + (setq *n-gcs* 0) + (setq *semaphore* (sb-thread:make-semaphore)) + (let ((watchdog-thread + (sb-thread:make-thread + (lambda () + ;; Each trial, when it works, takes between .01 to .4 sec + ;; (which is a tremendous spread), + ;; so after 20 seconds (50x more than needed), say it failed. + (let ((result + (sb-thread:wait-on-semaphore *semaphore* + :n (* n-threads n-calls) + ;; :timeout 20 + ))) + (if result + (format t "OK!~%") + (sb-sys:os-exit 1)))))) + (gc-thr + (when enable-gcing + (sb-thread:make-thread + (lambda() + (loop + (gc) + (incf *n-gcs*) + (sleep .0005) + (sb-thread:barrier (:read)) + (if (not *keepon*) (return))))))) + (start (get-internal-real-time))) + (setq *keepon* t) + (with-alien ((testfun (function int system-area-pointer int int) + :extern "call_thing_from_threads")) + (assert (eql (alien-funcall testfun (alien-sap (alien-callable-function 'testcb)) n-threads n-calls) + 1))) + (setq *keepon* nil) + (sb-thread:barrier (:write)) + (let ((stop (get-internal-real-time))) + #+darwin + (with-alien ((count int :extern "sigwait_bug_mitigation_count")) + (when (plusp count) + (format t "Bug mitigation strategy applied ~D time~:P~%" count) + (setf count 0))) + (sb-thread:join-thread watchdog-thread) + (when gc-thr + (sb-thread:join-thread gc-thr) + (format t "Trial ~d: GC'd ~d times (Elapsed=~f sec)~%" + (1+ trialno) *n-gcs* + (/ (- stop start) internal-time-units-per-second))))))) + +(with-test (:name :call-me-from-1-thread-no-gc + :skipped-on (or :interpreter)) + ;; smoke test and no GCing + (setq *print-greetings-and-salutations* t) + (f 1 1 1 nil) + (setq *print-greetings-and-salutations* nil)) + +(with-test (:name :call-me-from-many-threads-and-gc + :skipped-on (or :interpreter (and :x86 :win32))) + ;; two trials, 5 threads, 40 calls each + (f 2 5 40 t) + ;; one trial, 10 threads, 10 calls + (f 1 10 10 t) + ;; Crank the number of trials up if you're trying to investigate + ;; flakes in this test. The larger number of calls is usually + ;; what gets it to fail. + ;; 5 trials, 5 threads, 200 calls each + (f 5 5 200 t)) + +;;; The next test hasn't been made to run on windows, but should. +#+win32 (invoke-restart 'run-tests::skip-file) + +;;; Check that you get an error trying to join a foreign thread +(defglobal *my-foreign-thread* nil) +(define-alien-callable tryjointhis int () + (setq *my-foreign-thread* sb-thread:*current-thread*) + (dotimes (i 10) + (write-char #\.) (force-output) + (sleep .01)) + 0) + +(defun tryjoiner () + (setq *my-foreign-thread* nil) + (sb-int:dx-let ((pthread (make-array 1 :element-type 'sb-vm:word))) + (alien-funcall + (extern-alien "pthread_create" + (function int system-area-pointer unsigned + system-area-pointer unsigned)) + (sb-sys:vector-sap pthread) 0 (alien-sap (alien-callable-function 'tryjointhis)) 0) + (format t "Alien pthread is ~x~%" (aref pthread 0)) + (let (found) + (loop + (setq found *my-foreign-thread*) + (when found (return)) + (sleep .05)) + (format t "Got ~s~%" found) + (let ((result (handler-case (sb-thread:join-thread found) + (sb-thread:join-thread-error () 'ok)))) + (when (eq result 'ok) + ;; actually join it to avoid resource leak + (alien-funcall + (extern-alien "pthread_join" (function int unsigned unsigned)) + (aref pthread 0) + 0)) + (format t "Pthread joined ~s~%" found) + result)))) + +(with-test (:name :try-join-foreign-thread) + (assert (eq (tryjoiner) 'ok))) + diff --git a/tests/compiler-3.impure-cload.lisp b/tests/filecompile.impure-cload.lisp similarity index 100% rename from tests/compiler-3.impure-cload.lisp rename to tests/filecompile.impure-cload.lisp diff --git a/tests/filecompile.impure.lisp b/tests/filecompile.impure.lisp new file mode 100644 index 0000000000..9604f5e85c --- /dev/null +++ b/tests/filecompile.impure.lisp @@ -0,0 +1,57 @@ +(with-test (:name :compile-file-error-position-reporting + :serial t) + (dolist (input '("data/wonky1.lisp" "data/wonky2.lisp" "data/wonky3.lisp")) + (let ((expect (with-open-file (f input) (read f)))) + (assert (stringp expect)) + (let ((err-string (with-output-to-string (*error-output*) + (compile-file input :print nil + :output-file + (scratch-file-name "fasl"))))) + (assert (search expect err-string)))))) + +#-sb-thread (invoke-restart 'run-tests::skip-file) + +(unlock-package "SB-INT") +(unlock-package "SB-IMPL") +(unlock-package "CL") +(rename-package "COMMON-LISP" "COMMON-LISP" '("CL" "SB-XC")) + +(defun slurp (filename) + (with-open-file (stream filename :element-type '(unsigned-byte 8)) + (let ((res (make-array (file-length stream) :element-type '(unsigned-byte 8)))) + (read-sequence res stream) + res))) + +;;; Assert that concurrent threads doing the same thing +;;; produce identical output. +(with-test (:name :parallel-compile-file) + (with-scratch-file (thr1-out "fasl") + (with-scratch-file (thr2-out "fasl") + (with-scratch-file (thr3-out "fasl") + (flet ((work (result) + (let* ((*standard-output* (make-string-output-stream)) + (*error-output* *standard-output*)) + (compile-file "../src/code/primordial-extensions" + :output-file result) + (get-output-stream-string *standard-output*)))) + (dotimes (i 1) + (let ((thr1 (sb-thread:make-thread #'work :arguments (list thr1-out))) + (thr2 (sb-thread:make-thread #'work :arguments (list thr2-out))) + (thr3 (sb-thread:make-thread #'work :arguments (list thr3-out)))) + (let ((string1 (sb-thread:join-thread thr1)) + (string2 (sb-thread:join-thread thr2)) + (string3 (sb-thread:join-thread thr3))) + (declare (ignorable string1 string2 string3)) + #+nil + (progn + (format t "1:~%~A~%" string1) + (format t "2:~%~A~%" string2) + (format t "3:~%~A~%" string3))) + (let ((bytes1 (slurp thr1-out)) + (bytes2 (slurp thr2-out)) + (bytes3 (slurp thr3-out))) + (assert (equalp bytes1 bytes2)) + (assert (equalp bytes2 bytes3))) + (delete-file thr1-out) + (delete-file thr2-out) + (delete-file thr3-out)))))))) diff --git a/tests/filesys.pure.lisp b/tests/filesys.pure.lisp index ef25779546..5ea7b4313f 100644 --- a/tests/filesys.pure.lisp +++ b/tests/filesys.pure.lisp @@ -67,44 +67,53 @@ ;;; DIRECTORY used to treat */** as **. (with-test (:name (directory :*/**)) + ;; FIXME: this test should be redone to construct a controlled file + ;; hierarchy for listing. If test files or test runners ever get + ;; reorganized and it turns out there are no subdirectories under + ;; the *DEFAULT-PATHNAME-DEFAULTS* when this gets run, this test + ;; will pass but fail to test the behavior it's supposed to. (assert (equal (directory "*/**/*.*") - (mapcan (lambda (directory) - (directory (merge-pathnames "**/*.*" directory))) - (directory "*/"))))) + ;; Each call to DIRECTORY sorts its results, but if + ;; our files' truenames are random (e.g., if files + ;; here are symlinks to hashes of file content), then + ;; we need to merge the results of the inner + ;; DIRECTORY calls. + (reduce + (lambda (list1 list2) + ;; Depends on all truenames having namestrings. + ;; (Which they do; noted for future reference.) + (merge 'list list1 list2 'string< :key 'namestring)) + (mapcar (lambda (directory) + (directory (merge-pathnames "**/*.*" directory))) + (directory "*/")))))) (with-test (:name (directory *default-pathname-defaults* :bug-1740563)) - ;; FIXME: this writes into the source directory depending on whether - ;; TEST_DIRECTORY has been made to point elsewhere or not. - (let ((test-directory (concatenate 'string (sb-ext:posix-getenv "TEST_DIRECTORY") "/"))) - (ensure-directories-exist test-directory) - (close (open (merge-pathnames "a.txt" test-directory) :if-does-not-exist :create)) - (close (open (merge-pathnames "b.lisp" test-directory) :if-does-not-exist :create)) - (unwind-protect - (flet ((directory* (pattern &rest d-p-d-components) - (let ((*default-pathname-defaults* - (apply #'make-pathname - :defaults *default-pathname-defaults* - d-p-d-components))) - (directory pattern)))) - (let* ((*default-pathname-defaults* (pathname test-directory)) - (expected-wild (directory "*.*")) - (expected-one-file (directory "a.txt")) - (cases '((:name nil :type "txt") - (:name nil :type :wild) - (:name "a" :type nil) - (:name "a" :type "txt") - (:name "a" :type :wild) - (:name :wild :type nil) - (:name :wild :type :wild) - (:name :wild :type "txt")))) - (dolist (components cases) - (assert (equal (apply #'directory* "*.*" components) - expected-wild)) - (assert (equal (apply #'directory* "a.txt" components) - expected-one-file))) - (assert (equal (directory* "" :name :wild :type :wild) - expected-wild)))) - (delete-directory test-directory :recursive t)))) + (with-test-directory () + (close (open "a.txt" :if-does-not-exist :create)) + (close (open "b.lisp" :if-does-not-exist :create)) + (flet ((directory* (pattern &rest d-p-d-components) + (let ((*default-pathname-defaults* + (apply #'make-pathname + :defaults *default-pathname-defaults* + d-p-d-components))) + (directory pattern)))) + (let* ((expected-wild (directory "*.*")) + (expected-one-file (directory "a.txt")) + (cases '((:name nil :type "txt") + (:name nil :type :wild) + (:name "a" :type nil) + (:name "a" :type "txt") + (:name "a" :type :wild) + (:name :wild :type nil) + (:name :wild :type :wild) + (:name :wild :type "txt")))) + (dolist (components cases) + (assert (equal (apply #'directory* "*.*" components) + expected-wild)) + (assert (equal (apply #'directory* "a.txt" components) + expected-one-file))) + (assert (equal (directory* "" :name :wild :type :wild) + expected-wild)))))) ;;;; OPEN @@ -215,8 +224,7 @@ (if p (canon (concatenate 'string (subseq s 0 p) (subseq s (1+ p)))) s)))) - (loop repeat 1000 - for length = (random 32) + (loop for length = (random 32) for native-namestring = (coerce (loop repeat length collect @@ -225,11 +233,11 @@ 'simple-base-string) for pathname = (native-pathname native-namestring) for nnn = (native-namestring pathname) + repeat 1000 do (setf native-namestring (canon native-namestring)) (unless (string= nnn native-namestring) (error "1: wanted ~S, got ~S" native-namestring nnn))) - (loop repeat 1000 - for native-namestring = (with-output-to-string (s) + (loop for native-namestring = (with-output-to-string (s) (write-string "mu" s) (loop (let ((r (random 1.0))) @@ -247,6 +255,7 @@ s)))))) for pathname = (native-pathname native-namestring) for tricky-nnn = (native-namestring pathname) + repeat 1000 do (setf native-namestring (canon native-namestring)) (unless (string= tricky-nnn native-namestring) (error "2: wanted ~S, got ~S" native-namestring tricky-nnn)))))) @@ -389,22 +398,17 @@ (append (when namep '(:name :unspecific)) (when typep '(:type :unspecific))))) (test (as-file as-directory) - (let* ((test-directory (concatenate - 'string - (sb-ext:posix-getenv "TEST_DIRECTORY") "/")) - (delete-directory (merge-pathnames - (typecase as-file - (string (prepare as-file)) - (pathname as-file)) - test-directory))) - (ensure-directories-exist (merge-pathnames - (prepare as-directory) - test-directory)) - (unwind-protect - (progn - (delete-directory delete-directory) - (assert (not (probe-file (prepare as-directory))))) - (delete-directory test-directory :recursive t))))) + (with-test-directory (test-directory) + (let ((delete-directory (merge-pathnames + (typecase as-file + (string (prepare as-file)) + (pathname as-file)) + test-directory))) + (ensure-directories-exist (merge-pathnames + (prepare as-directory) + test-directory)) + (delete-directory delete-directory) + (assert (not (probe-file (prepare as-directory)))))))) ;; Name component present #-win32 (test "aE?b" "aE?b/") #-win32 (test "aE*b" "aE*b/") @@ -425,3 +429,14 @@ (test (make-unspecific nil t) "foo/") (test (make-unspecific t nil) "foo/") (test (make-unspecific t t) "foo/"))) + +(with-test (:name (rename-file :overwrite)) + (with-test-directory () + (with-open-file (s "a" :direction :output) + (write-line "a" s)) + (with-open-file (s "b" :direction :output) + (write-line "b" s)) + (rename-file "a" "b") + (assert (null (probe-file "a"))) + (with-open-file (s "b") + (assert (equal "a" (read-line s)))))) diff --git a/tests/fin-call.impure.lisp b/tests/fin-call.impure.lisp index 968ccfe954..64f34e9d92 100644 --- a/tests/fin-call.impure.lisp +++ b/tests/fin-call.impure.lisp @@ -18,7 +18,7 @@ (setf (fdefinition 'zonk) (make-instance 'foo :function (lambda (y) y))) (with-test (:name :call-nonstandard-funcallable-instance) - #+immobile-code + #+nil (let* ((fdefn (sb-int:find-fdefn 'zonk)) (raw-entry-point (sb-sys:sap-ref-sap (sb-sys:int-sap (sb-kernel:get-lisp-obj-address fdefn)) diff --git a/tests/fin-threadsafety.impure.lisp b/tests/fin-threadsafety.pure.lisp similarity index 56% rename from tests/fin-threadsafety.impure.lisp rename to tests/fin-threadsafety.pure.lisp index 9794e6e328..88c32249b3 100644 --- a/tests/fin-threadsafety.impure.lisp +++ b/tests/fin-threadsafety.pure.lisp @@ -1,6 +1,4 @@ -#-sb-thread (sb-ext:exit :code 104) - -(use-package "SB-THREAD") +#-sb-thread (invoke-restart 'run-tests::skip-file) (let ((count (make-array 8 :initial-element 0))) (defun closure-one () @@ -32,35 +30,45 @@ ;;; fruitful to concentrate their efforts around this test... (with-test (:name (:funcallable-instances) - :broken-on (or :win32 - (and :sb-safepoint - (not :c-stack-is-control-stack)))) + :broken-on (and :sb-safepoint (not :c-stack-is-control-stack))) ;; the funcallable-instance implementation used not to be threadsafe ;; against setting the funcallable-instance function to a closure ;; (because the code and lexenv were set separately). (let ((fun (sb-kernel:%make-funcallable-instance 0)) + (stop nil) (condition nil)) + ;; If the %FUN-LAYOUT were unset or its bitmap were 0, then the + ;; %FUNCALLABLE-INSTANCE-FUN slot would not be visited in GC because + ;; it assumes the instance is wholly empty in that case. + ;; It doesn't matter too much what the layout is, but it has to be something + ;; whose bitmap satisfies the assertion in "verify_headered_object()" + ;; concerning the potentially valid bitmaps for a funcallable instance. + ;; FUNCALLABLE-INSTANCE itself has a 0 bitmap which implies 0 tagged slots + ;; (which seems dubious to be sure), and FUNCTION has a bitmap indicating + ;; 1 raw slot and all the rest tagged. Neither of those is right. + ;; GENERIC-FUNCTION is ok even though this is not an instance of it. + ;; I _think_ this makes the test reliable with pre_verify_gen_0 enabled. + (sb-kernel:%set-fun-layout fun (sb-kernel:find-layout 'generic-function)) (setf (sb-kernel:%funcallable-instance-fun fun) #'closure-one) (flet ((changer () - (loop (setf (sb-kernel:%funcallable-instance-fun fun) #'closure-one) + (loop (sb-thread:barrier (:read)) + (when stop (return)) + (setf (sb-kernel:%funcallable-instance-fun fun) #'closure-one) (setf (sb-kernel:%funcallable-instance-fun fun) #'closure-two))) (test () - (handler-case (loop (funcall fun)) + (handler-case (loop (sb-thread:barrier (:read)) + (when stop (return)) + (funcall fun)) (serious-condition (c) (setf condition c))))) - (let ((changer (make-thread #'changer)) - (test (make-thread #'test))) - (handler-case - (progn + (let ((changer (sb-thread:make-thread #'changer :name "changer")) + (test (sb-thread:make-thread #'test :name "test"))) ;; The two closures above are fairly carefully crafted ;; so that if given the wrong lexenv they will tend to ;; do some serious damage, but it is of course difficult ;; to predict where the various bits and pieces will be ;; allocated. Five seconds failed fairly reliably on ;; both my x86 and x86-64 systems. -- CSR, 2006-09-27. - (sb-ext:with-timeout 5 - (wait-for-threads (list test))) - (error "~@<test thread got condition:~2I~_~A~@:>" condition)) - (sb-ext:timeout () - (terminate-thread changer) - (terminate-thread test) - (wait-for-threads (list changer test)))))))) + (sleep 5) + (setq stop t) + (sb-thread:barrier (:write)) + (wait-for-threads (list changer test)))))) diff --git a/tests/finalize.impure.lisp b/tests/finalize.impure.lisp new file mode 100644 index 0000000000..85b5cfb350 --- /dev/null +++ b/tests/finalize.impure.lisp @@ -0,0 +1,131 @@ +#+(or sb-safepoint interpreter) (invoke-restart 'run-tests::skip-file) + +(defvar *tmp* 0.0) ; don't remove - used by the setq below +(defglobal *count* 0) +(declaim (fixnum *count*)) + +(defun foo (_) + (declare (ignore _)) + nil) + +(defglobal *maxdepth* 0) +;; Be gentler on 32-bit platforms +(defglobal *n-finalized-things* (or #+(and 64-bit (not sb-safepoint)) 20000 10000)) +(defglobal *weak-pointers* nil) + +(defun makejunk (_) + (declare (ignore _)) + (let ((x (gensym))) + (push (make-weak-pointer x) *weak-pointers*) + (finalize x (lambda () + (setq *maxdepth* + (max sb-kernel:*free-interrupt-context-index* + *maxdepth*)) + ;; cons 320K in the finalizer for #+64-bit, + ;; or 80K for #-64-bit + (setf *tmp* (make-list *n-finalized-things*)) + (sb-ext:atomic-incf *count*))) + x)) +(compile 'makejunk) + +(defun scrubstack () + (sb-int:dx-let ((b (make-array 20))) (eval b)) + (sb-sys:scrub-control-stack)) + +(defun run-consy-thing () + (dotimes (iter 10) + (let ((junk (mapcar #'makejunk + (make-list (/ *n-finalized-things* 10))))) + (setf junk (foo junk)) + (foo junk)) + (scrubstack) + (gc :full t))) + +; no threads - hope for the best with respect to conservative root retention +#-sb-thread (run-consy-thing) + +#+sb-thread +(progn + (sb-thread:join-thread (sb-thread:make-thread #'run-consy-thing)) + (gc :full t)) ; one more time to clean everything up + +;;; Verify that the thread was started. +#+sb-thread +(with-test (:name :finalizer-thread-started) + (assert (typep sb-impl::*finalizer-thread* 'sb-thread::thread)) + ;; We're going to assert on an approximate count of finalizers that ran, + ;; which is a bit sketchy. + ;; So call RUN-PENDING-FINALIZERS which actually does the work of helping out + ;; the finalizer thread. + ;; This also shows that it works to run finalization actions in two threads - + ;; the finalizer thread and this. Hence the need for ATOMIC-INCF on *count*. + (sb-impl::run-pending-finalizers) + + ;; Make sure the thread is done. + ;; This JOIN-THREADs it, so we know it's not executing. + (sb-impl::finalizer-thread-stop)) + +;;; This was failing with something like: +;;; The assertion (<= *MAXDEPTH* 1) failed with *MAXDEPTH* = 232. +;;; The test parameters for 64-bit are quite severe, but should not exhaust the heap. +(with-test (:name :finalizers-dont-nest-garbage-collections) + (assert (<= *maxdepth* 1))) + +;;; Regardless of anything else, check representational invariants. +;;; - each ID in the id-recycle-list is not a value in the hash-table +;;; - each value in the hash-table is not in the id-recycle-list +(with-test (:name :finalizer-id-uniqueness) + (let* ((hash-table (elt sb-impl::**finalizer-store** 1)) + (used-ids (loop for v being each hash-value of hash-table + collect v)) + (available-ids (cdr (elt sb-impl::**finalizer-store** 0)))) + (assert (null (intersection used-ids available-ids))))) + +(with-test (:name :finalizers-ran) + ;; expect that 97% of the finalizers ran + (assert (>= *count* (* *n-finalized-things* 97/100))) + #+gencgc + (unless (= *count* *n-finalized-things*) + ;; show how the junk was reachable + (search-roots *weak-pointers* :print :verbose))) + +;;; For finalizers that didn't run (if any), we had better find +;;; that the object still exists in *weak-pointers*. +;;; Conversely, for each intact weak pointer, there had better be +;;; a finalizer for that object. +(with-test (:name :finalizer-state) + (setq *weak-pointers* + (delete-if (lambda (x) (null (weak-pointer-value x))) + *weak-pointers*)) + (let ((hash-table (elt sb-impl::**finalizer-store** 1))) + (loop for k being each hash-key of hash-table + when (and (symbolp k) (not (symbol-package k))) + do (assert (find k *weak-pointers* :key #'weak-pointer-value))) + (dolist (wp *weak-pointers*) + (assert (gethash (weak-pointer-value wp) hash-table))))) + +;;; A super-smart GC and/or compiler might prove that the object passed to +;;; FINALIZE is instantly garbage. Like maybe (FINALIZE (CONS 1 2) 'somefun) +;;; with the object otherwise unreachable. And so the system might reasonably +;;; call #'SOMEFUN right away. Hence it had better be a function so that the +;;; error isn't just shoved over to the finalizer thread. +;;; Also, as a special case caught by the general case, I'd rather not see NILs +;;; in the finalizer table, because NIL could never be defined as a function. +(with-test (:name :finalizer-funarg) + ;; The :no-function-conversion option in fndb was removed, for two reasons: + ;; - unlike with SET-MACRO-CHARACTER there is no "inquiry" function that you + ;; could use to determine what symbol was given as the funarg. + ;; Whereas I prefer lazy resolution in readtables because GET-MACRO-CHARACTER + ;; should return 'FUN if that's what you had set, and not #'FUN. + ;; - I can't particularly see anyone making the claim that a weird use such as + ;; (FINALIZE (CONS 1 2) 'STRING=))) should not emit e a warning about #'STRING= + ;; being funcalled with zero args when it should receive two. + (assert (nth-value 1 (compile nil '(lambda () (finalize (cons 1 2) 'string=))))) + ;; I make this mistake sometimes in GC testing - forgetting to wrap + ;; a FORMAT in a LAMBDA. So this had better fail early and often. + (assert-error (finalize (cons 'a 'b) (format t "The object died~%"))) + ;; This too, even if you think this is a little different, because + ;; you _could_ define this function. But it's not different. + ;; The attempted call to #'no-function-for-you may arbitrarily occur + ;; (in theory) as soon as the system is able to detect garbage. + (assert-error (finalize (cons 1 2) 'no-function-for-you))) diff --git a/tests/finalize.test.sh b/tests/finalize.test.sh old mode 100755 new mode 100644 index 03581fa4af..46afb7a0d8 --- a/tests/finalize.test.sh +++ b/tests/finalize.test.sh @@ -1,79 +1,25 @@ -#!/bin/sh -# -# This test is as convoluted as it is to avoid having failing tests -# hang the test-suite, as the typical failure mode used to be SBCL -# hanging uninterruptible in GC. - . ./subr.sh -use_test_subdirectory - -echo //entering finalize.test.sh - -# $! is not set correctly when calling run_sbcl, do it directly -"$SBCL_RUNTIME" --core "$SBCL_CORE" $SBCL_ARGS <<EOF > /dev/null & -(defvar *tmp* 0.0) -(defvar *count* 0) - -(defun foo (_) - (declare (ignore _)) - nil) - -(let ((junk (mapcar (compile nil '(lambda (_) - (declare (ignore _)) - (let ((x (gensym))) - (finalize x (lambda () - ;; cons in finalizer - (setf *tmp* (make-list 10000)) - (incf *count*))) - x))) - (make-list 10000)))) - (setf junk (foo junk)) - (foo junk)) - -(gc :full t) -(gc :full t) -;; Stopping the finalizer thread ensures that queued finalizers execute. -;; [I don't think it's possible for it to stop before draining the queue, -;; but that isn't part of the contract with stopping. If this test fails, -;; try inserting a call to RUN-PENDING-FINALIZERS after this line] -#+sb-thread (sb-impl::finalizer-thread-stop) -;; FIXME: turns out, it does fail: -(sb-kernel:run-pending-finalizers) - -(if (= *count* 10000) - (with-open-file (f "finalize-test-passed" :direction :output) - (write-line "OK" f)) - (with-open-file (f "finalize-test-failed" :direction :output) - (format f "OOPS: ~A~%" *count*) - (sb-kernel:run-pending-finalizers) - (format f "After sb-kernel:run-pending-finalizers: ~A~%" *count*))) - -(sb-ext:quit) +# This was failing with: +# Verify after GC(6) [immobile] +# Ptr 0x1001100c9f @ 503c1028 (lispobj 503c1003,pg-1) sees junk +# Ptr 0x1001100ebf @ 503c10a8 (lispobj 503c1083,pg-1) sees junk +# Ptr 0x100110102f @ 503c1128 (lispobj 503c1103,pg-1) sees junk +# ... +run_sbcl <<EOF + (setf (extern-alien "verify_gens" char) 0) + ;; simple-streams causes invalidation of many layouts + ;; that are at low addresses, like for FUNDAMENTAL-STREAM + (require :sb-simple-streams) + (defun foo () + ;; we need a *lot* of finalizers for cull_weak_hash_tables + ;; to use up so much dynamic space that the mark bit + ;; calculation would go wrong + (dotimes (i 50000) + (finalize (cons i i) (lambda ())))) + (compile 'foo) + (foo) + (gc :gen 7) EOF -SBCL_PID=$! -WAITED=x - -echo "Waiting for SBCL to finish stress-testing finalizers" -while true; do - if [ -f finalize-test-passed ]; then - echo "OK" - rm finalize-test-passed - exit $EXIT_TEST_WIN - elif [ -f finalize-test-failed ]; then - wait - cat finalize-test-failed - rm finalize-test-failed - exit $EXIT_LOSE - fi - sleep 1 - WAITED="x$WAITED" - if [ $WAITED = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" ]; then - echo - echo "timeout, killing SBCL" - kill -9 $SBCL_PID - exit $EXIT_LOSE # Failure, SBCL probably hanging in GC - fi -done - +exit $EXIT_TEST_WIN diff --git a/tests/float.impure.lisp b/tests/float-2.pure.lisp similarity index 90% rename from tests/float.impure.lisp rename to tests/float-2.pure.lisp index aef72a50ec..28a1417ee9 100644 --- a/tests/float.impure.lisp +++ b/tests/float-2.pure.lisp @@ -1,6 +1,3 @@ -;;;; This file is for floating-point-related tests which have side -;;;; effects (e.g. executing DEFUN). - ;;;; This software is part of the SBCL system. See the README file for ;;;; more information. ;;;; @@ -12,8 +9,6 @@ ;;;; absolutely no warranty. See the COPYING and CREDITS files for ;;;; more information. -(cl:in-package :cl-user) - ;;; Hannu Rummukainen reported a CMU CL bug on cmucl-imp@cons.org 26 ;;; Jun 2000. This is the test case for it. ;;; @@ -356,7 +351,13 @@ fractional bits." (dolist (op '(sin cos tan)) (dolist (val `(,(coerce most-positive-fixnum 'double-float) ,@(loop for v = most-positive-double-float - then (expt v 4/5) + ;; EXPT calls %POW which directly calls the libm pow() function. + ;; Some libm's might internally cause an *expected* overflow on + ;; certain inputs. So instead of computing an answer for + ;; (EXPT 1.7976931348623157d308 4/5) it would trap. + ;; I'll bet that's why we disabled the test on openbsd, + ;; but I don't care to find out. + then (sb-int:with-float-traps-masked (:overflow) (expt v 4/5)) while (> v (expt 2 50)) collect v) ;; The following values cover all eight combinations @@ -372,3 +373,27 @@ fractional bits." 4.2766818550391727d188 1.635888515419299d28)) (test op val)))))) + +(with-test (:name :truncate-bignum-type-derivation) + (checked-compile `(lambda (x) + (declare ((or (integer 1208925819614629174706175) + (integer * -1208925819614629174706175)) + x)) + (truncate (float x 4d0)))) + (checked-compile `(lambda (x) + (declare ((or (integer 1208925819614629174706175) + (integer * -1208925819614629174706175)) + x)) + (truncate (float x 1d0) 4d0)))) + +(with-test (:name :bignum-float-compare) + (flet ((test (integer) + (assert (= (float integer 1d0) + (truncate (float integer 1d0)))) + (assert (= (float integer) + (truncate (float integer)))))) + (loop for i from 80 to 100 by 4 + do (test (expt 2 i)) + (test (- (expt 2 i))) + (test (1+ (expt 2 i))) + (test (- (expt 2 i)))))) diff --git a/tests/float.pure.lisp b/tests/float.pure.lisp index ee27b69ed0..95c6106182 100644 --- a/tests/float.pure.lisp +++ b/tests/float.pure.lisp @@ -98,7 +98,7 @@ (assert (= 0.0d0 (scale-float 1.0d0 (1- most-negative-fixnum))))) (with-test (:name (:scale-float-overflow :bug-372) - :fails-on (or :arm64 (and :darwin :ppc))) + :fails-on (or :arm64)) (flet ((test (form) (assert-error (funcall (checked-compile `(lambda () ,form) :allow-style-warnings t)) @@ -135,7 +135,6 @@ (with-test (:name (:addition-overflow :bug-372) :fails-on (or :arm64 (and :ppc :openbsd) - (and :ppc :darwin) (and :x86 :netbsd))) (assert-error (sb-sys:without-interrupts @@ -156,7 +155,6 @@ (with-test (:name (:addition-overflow :bug-372 :take-2) :fails-on (or :arm64 (and :ppc :openbsd) - (and :ppc :darwin) (and :x86 :netbsd))) (assert-error (sb-sys:without-interrupts @@ -528,12 +526,12 @@ (with-test (:name :conservative-floor-bounds) (assert - (equal (sb-kernel:%simple-fun-type - (checked-compile - `(lambda (x) - (declare (unsigned-byte x)) - (values (truncate 1.0 x))))) - '(function (unsigned-byte) (values unsigned-byte &optional))))) + (subtypep (second (third (sb-kernel:%simple-fun-type + (checked-compile + `(lambda (x) + (declare (unsigned-byte x)) + (values (truncate 1.0 x))))))) + 'unsigned-byte))) (with-test (:name :single-float-sign-stubs) (checked-compile-and-assert @@ -544,3 +542,203 @@ (the single-float (labels ((%f () (the real p1))) (%f))))) ((-96088.234) -1.0))) + +(with-test (:name :inline-signum) + (assert (ctu:find-named-callees ; should be a full call + (compile nil '(lambda (x) + (signum (truly-the number x)))))) + ;; should not be a full call + (dolist (type '(integer + (or (integer 1 10) (integer 50 90)) + rational + single-float + (or (single-float -10f0 0f0) (single-float 1f0 20f0)) + double-float + (or (double-float -10d0 0d0) (double-float 1d0 20d0)))) + (assert (null (ctu:find-named-callees + (compile nil `(lambda (x) + (signum (truly-the ,type x)))))))) + ;; check signed zero + (let ((f (compile nil '(lambda (x) (signum (the single-float x)))))) + (assert (eql (funcall f -0f0) -0f0)) + (assert (eql (funcall f +0f0) +0f0))) + (let ((f (compile nil '(lambda (x) (signum (the double-float x)))))) + (assert (eql (funcall f -0d0) -0d0)) + (assert (eql (funcall f +0d0) +0d0)))) + + +(with-test (:name :expt-double-no-complex) + (checked-compile-and-assert + (:allow-notes nil) + `(lambda (x y) + (> (expt (the double-float x) 4d0) + (the double-float y))) + ((1d0 0d0) t)) + (checked-compile-and-assert + (:allow-notes nil) + `(lambda (x y) + (> (expt (the (double-float 0d0) x) (the double-float y)) + y)) + ((1d0 0d0) t))) + +(with-test (:name :ftruncate-inline + :skipped-on (not :64-bit)) + (checked-compile + `(lambda (v d) + (declare (optimize speed) + (double-float d) + ((simple-array double-float (2)) v)) + (setf (aref v 0) (ffloor (aref v 0) d)) + v) + :allow-notes nil)) + +(with-test (:name :ctype-of-nan) + (checked-compile '(lambda () #.(sb-kernel:make-single-float -1)))) + +;; bug #1914094 +(with-test (:name :float-type-derivation :skipped-on (not :64-bit)) + (labels ((car-type-equal (x y) + (and (subtypep (car x) (car y)) + (subtypep (car y) (car x))))) + (let ((long #+long-float 'long-float + #-long-float 'double-float)) + (checked-compile-and-assert () '(lambda (x) (ctu:compiler-derived-type (* 3d0 x))) + ((1) (values `(or ,long (complex ,long)) t) :test #'car-type-equal)) + (checked-compile-and-assert () '(lambda (x) (ctu:compiler-derived-type (* 3f0 x))) + ((1) (values `(or single-float ,long (complex single-float) (complex ,long)) t) + :test #'car-type-equal)) + (checked-compile-and-assert () '(lambda (x) (ctu:compiler-derived-type (* 3f0 x))) + ((1) (values `(or single-float ,long (complex single-float) (complex ,long)) t) + :test #'car-type-equal)) + (checked-compile-and-assert () '(lambda (x y) (ctu:compiler-derived-type (atan x y))) + ((1 2) (values `(or ,long single-float (complex ,long) (complex single-float)) t) :test #'car-type-equal))))) + +(with-test (:name :comparison-transform-overflow) + (checked-compile-and-assert + () + `(lambda (a) + (declare (float a)) + (= a 1854150818890592943838975159000134470424763027560)) + ((1d0) nil) + ((1f0) nil))) + +(with-test (:name :comparison-merging) + (checked-compile-and-assert + () + `(lambda (a b) + (declare (double-float a b)) + (cond ((= a b) 0) + ((< a b) 1) + (t 2))) + ((1d0 1d0) 0) + ((1d0 3d0) 1) + ((3d0 1d0) 2))) + +;; Based on example in lp#1926383 +(defun idf (x) (multiple-value-list (cl:integer-decode-float x))) +(defun testfloat (k) + (let* ((kidf (idf k)) + (kff (float (* (car kidf) (expt 2 (cadr kidf))) k)) + (kss (scale-float (float (car kidf) k) (cadr kidf)))) + (format t "Input k(~a): ~,15e, IDF ~{~b ~d ~d~}~%" (type-of k) k kidf) + (format t "float k(~a): ~,15e, IDF ~{~b ~d ~d~}, diff ~,5e~%" (type-of k) kff (idf kff) (- k kff)) + (format t "scale k(~a): ~,15e, IDF ~{~b ~d ~d~}, diff ~,5e~%" (type-of k) kff (idf kss) (- k kss)))) + +;;; (time (exhaustive-test-single-floats)) +;;; Evaluation took: +;;; 12.873 seconds of real time +;;; 12.666938 seconds of total run time (12.629706 user, 0.037232 system) +;;; [ Run times consist of 0.055 seconds GC time, and 12.612 seconds non-GC time. ] +;;; 98.40% CPU +;;; 36,149,296,946 processor cycles +;;; 5,033,148,304 bytes consed +;;; +#+nil ; This is too slow to be a regression test. And why does it cons? +(defun exhaustive-test-single-floats () + (loop for i from 1 to (1- (ash 1 23)) + do (let ((k (sb-kernel:make-lisp-obj (logior (ash i 32) sb-vm:single-float-widetag)))) + (multiple-value-bind (mant exp sign) (integer-decode-float k) + (declare (ignore sign)) + (let ((way1 (float (* mant (expt 2 exp)) k)) + (way2 (scale-float (float mant k) exp))) + ;; Do bitwise comparison + (assert (= (sb-kernel:single-float-bits k) + (sb-kernel:single-float-bits way1))) + (assert (= (sb-kernel:single-float-bits k) + (sb-kernel:single-float-bits way2)))))))) + +;;; For #+64-bit we could eradicate the legacy interface +;;; to MAKE-DOUBLE-FLOAT, and just take the bits. +(defun mdf (x) + (let ((f (sb-sys:%primitive sb-vm::fixed-alloc + 'make-double-float 2 sb-vm:double-float-widetag + sb-vm:other-pointer-lowtag nil))) + (setf (sb-sys:sap-ref-word (sb-sys:int-sap (sb-kernel:get-lisp-obj-address f)) + (- 8 sb-vm:other-pointer-lowtag)) + (the sb-vm:word x)) + f)) +(compile 'mdf) + +#+64-bit +(progn +(defun test-single-floats (n) + (dotimes (i n) + (let* ((bits (random (ash 1 23))) + ;; This isn't a valid call to MAKE-LISP-OBJ for 32 bit words + (k (sb-kernel:make-lisp-obj (logior (ash i 32) sb-vm:single-float-widetag)))) + (when (zerop bits) (incf bits)) + (multiple-value-bind (mant exp sign) (integer-decode-float k) + (declare (ignore sign)) + (let ((way1 (float (* mant (expt 2 exp)) k)) + (way2 (scale-float (float mant k) exp))) + ;; Do bitwise comparison + (assert (= (sb-kernel:single-float-bits k) + (sb-kernel:single-float-bits way1))) + (assert (= (sb-kernel:single-float-bits k) + (sb-kernel:single-float-bits way2)))))))) + +(defun test-double-floats (n) + (dotimes (i n) + (let ((bits (random (ash 1 52)))) + (when (zerop bits) (incf bits)) + (let ((k (mdf bits))) + (multiple-value-bind (mant exp sign) (integer-decode-float k) + (declare (ignore sign)) + (let ((way1 (float (* mant (expt 2 exp)) k)) + (way2 (scale-float (float mant k) exp))) + ;; Do bitwise comparison + (assert (= (sb-kernel:double-float-bits k) + (sb-kernel:double-float-bits way1))) + (assert (= (sb-kernel:double-float-bits k) + (sb-kernel:double-float-bits way2))))))))) + +(with-test (:name :round-trip-decode-recompose) + (test-single-floats 10000) + (test-double-floats 10000)) +) + +;; lp#1920931 +(with-test (:name :coerce-to-float-no-warning) + (let ((f (checked-compile '(lambda (y) (coerce (sqrt y) 'float))))) + (assert (floatp (funcall f 3))) + (assert-error (funcall f #c(1 2))))) + +(with-test (:name :imagpart-real-negative-zero-derived-type) + (checked-compile-and-assert + () + `(lambda (x) + (eql (imagpart (the real x)) -0.0)) + ((-1.0) t))) + +(with-test (:name :negative-zero-in-ranges) + (checked-compile-and-assert + () + `(lambda (x y) + (declare ((OR (INTEGER 0 0) (DOUBLE-FLOAT 0.0d0 0.0d0)) x) + ((OR (RATIONAL -10 0) (DOUBLE-FLOAT -10.0d0 -0.0d0)) y)) + (= x y)) + ((0 0) t) + ((0 0d0) t) + ((0 -0d0) t) + ((0d0 -0d0) t) + ((0 -1d0) nil))) diff --git a/tests/fopcompiler.impure-cload.lisp b/tests/fopcompiler.impure-cload.lisp deleted file mode 100644 index 6f7f48a02a..0000000000 --- a/tests/fopcompiler.impure-cload.lisp +++ /dev/null @@ -1,150 +0,0 @@ -;;;; tests of the fop compiler - -;;;; This software is part of the SBCL system. See the README file for -;;;; more information. -;;;; -;;;; While most of SBCL is derived from the CMU CL system, the test -;;;; files (like this one) were written from scratch after the fork -;;;; from CMU CL. -;;;; -;;;; This software is in the public domain and is provided with -;;;; absolutely no warranty. See the COPYING and CREDITS files for -;;;; more information. - -(in-package "CL-USER") - -;; Can't use normal ASSERT, since it is not fopcompilable... -(defun assert* (value) - (unless value - (error "assert failed"))) - -;;; Test that the forms that are supposed to be fopcompilable are, and -;;; the ones that aren't aren't. The body might contain further tests to -;;; ensure that the fopcompiled code works as intended. -(defmacro fopcompile-test (fopcompilable-p &body body) - (assert (eql (sb-c::fopcompilable-p `(progn ,@body)) - fopcompilable-p)) - `(progn ,@body)) - -(fopcompile-test t - (let ((a 1)) - (assert* (eql a 1)))) - -(fopcompile-test t - (let ((a 3)) - (let ((a 4)) - (assert* (eql a 4))))) - -(fopcompile-test t - (let* ((a 5)) - (let* ((a 6)) - (assert* (eql a 6))))) - -(fopcompile-test nil - (let ((a 7)) - (assert* (eql (funcall (lambda () a)) 7)))) - -(fopcompile-test nil - (let* ((a 8)) - (assert* (eql (funcall (lambda () a)) 8)))) - -(fopcompile-test t - (let ((a 8) - (b (lambda () 1))) - nil)) - -(fopcompile-test t - (let* ((a (lambda () 1))) - nil)) - -(fopcompile-test nil - (let* ((a 8) - (b (lambda () 1))) - nil)) - -(fopcompile-test nil - (let* ((a 9) - (b (funcall (lambda () a)))) - (assert* (eql b 9)))) - -(fopcompile-test t - (let ((a 10)) - (let ((a 11) - (b a)) - (assert* (eql b 10))))) - -(fopcompile-test t - (let ((a 12)) - (let* ((a 13) - (b a)) - (assert* (eql b 13))))) - -(setf (symbol-value 'fopcompile-test-foo) 1) -(assert* (eql fopcompile-test-foo 1)) - -;;; Ensure that we're passing sensible environments to macros during -;;; fopcompilation. Reported by Samium Gromoff. - -(defmacro bar (vars &environment env) - (assert (equal vars - (mapcar #'car (sb-c::lexenv-vars env))))) - -(symbol-macrolet ((foo 1)) - (let* ((x (bar (foo))) - (y (bar (x foo)))) - (bar (y x foo)))) - -;;; Some tests involving compiler-macros. - -(defvar *cmacro-result* nil) - -(defun baz (x) (declare (ignore x))) - -;; functional foo - a function with a compiler-macro -(defun ffoo (x) (push `(regular-ffoo ,x) *cmacro-result*)) -(define-compiler-macro ffoo (x) - `(push `(cmacro-ffoo ,,x) *cmacro-result*)) - -;; macro foo - a macro with a compiler-macro -(defmacro mfoo (x) `(push `(regular-mfoo ,,x) *cmacro-result*)) -(define-compiler-macro mfoo (x) - `(push `(cmacro-mfoo ,,x) *cmacro-result*)) - -(defun get-s () (declare (special s)) s) - -;; Verify some assumptions that the tests will test what was intended. -(eval-when (:compile-toplevel) - (let ((sb-c::*lexenv* (sb-kernel:make-null-lexenv))) - (assert (sb-c::fopcompilable-p '(baz (ffoo 3)))) - (assert (sb-c::fopcompilable-p '(baz (mfoo 3)))) - ;; The special binding of S makes these forms not fopcompilable. - (assert (not (sb-c::fopcompilable-p - '(ffoo (let ((s 3)) (declare (special s)) (get-s)))))) - (assert (not (sb-c::fopcompilable-p - '(mfoo (let ((s 3)) (declare (special s)) (get-s)))))))) - -;; fopcompilable toplevel form should execute the compiler macro -(ffoo 1) -(mfoo 1) -;; fopcompilable form expands embedded compiler-macro -(baz (ffoo 2)) -(baz (mfoo 2)) -;; not-fopcompilable toplevel form should execute the compiler macro. -;; This was ok if the toplevel call was a function with a compiler-macro, -;; but was not working for a toplevel macro having a compiler-macro. -(ffoo (let ((s 3)) (declare (special s)) (get-s))) -(mfoo (let ((s 3)) (declare (special s)) (get-s))) - -(with-test (:name :compiler-macros-at-toplevel) - ;; Now assert about the macroexpansions that happened. - (assert (equal *cmacro-result* - '((CMACRO-MFOO 3) (CMACRO-FFOO 3) - (CMACRO-MFOO 2) (CMACRO-FFOO 2) - (CMACRO-MFOO 1) (CMACRO-FFOO 1))))) - -(when (eval nil) - (lambda () #.(find-package "CL"))) - -(with-test (:name :skip-load-form) - (assert (eq #.(find-package "CL") - (eval '(find-package "CL"))))) diff --git a/tests/fopcompiler.impure.lisp b/tests/fopcompiler.impure.lisp deleted file mode 100644 index cea42b83c9..0000000000 --- a/tests/fopcompiler.impure.lisp +++ /dev/null @@ -1,71 +0,0 @@ -;;;; This software is part of the SBCL system. See the README file for -;;;; more information. -;;;; -;;;; While most of SBCL is derived from the CMU CL system, the test -;;;; files (like this one) were written from scratch after the fork -;;;; from CMU CL. -;;;; -;;;; This software is in the public domain and is provided with -;;;; absolutely no warranty. See the COPYING and CREDITS files for -;;;; more information. - -;;; These tests don't need to be processed by the compiler before -;;; being executed, in fact mustn't go in "fopcompiler.impure-cload.lisp" -;;; because the call to COMPILE-FILE needs to be wrapped in HANDLER-BIND. - -(defvar *tmp-filename* (scratch-file-name)) - -;; Assert that FORM is handled by the fopcompiler, then compile it. -(defun assert-fopcompilable-and-compile-it (form) - ;; Since FOPCOMPILABLE-P now expands compiler-macros, and the macro for - ;; SOURCE-LOCATION expands to a literal structure, we end up calling - ;; CONSTANT-FOPCOMPILABLE-P which needs *COMPILE-OBJECT* to be bound. - (let ((sb-c::*compile-object* - (sb-fasl::make-fasl-output :stream (make-broadcast-stream))) - (sb-c::*lexenv* (sb-kernel:make-null-lexenv))) - (assert (sb-c::fopcompilable-p form)) - (with-open-file (stream *tmp-filename* - :direction :output :if-exists :supersede) - (prin1 form stream)) - (let (warning) - (handler-bind ((warning - (lambda (c) - (when (null warning) - (setq warning c) - (muffle-warning))))) - (multiple-value-bind (output warningp errorp) - (compile-file *tmp-filename*) - (when output - (delete-file output)) - (if (and (not warningp) (not errorp)) - ;; return muffled warning, which didn't count as a warning - warning)))))) - -;; Ensure we can get a style-warning about undefined functions from FOPCOMPILE. -(with-test (:name :fopcompiler-undefined-warning) - ;; Make sure some wiseacre didn't defconstant *FOO* - (assert (eq (sb-int:info :variable :kind '*foo*) :unknown)) - ;; ... or define the I-DO-NOT-EXIST function. - (assert (eq (sb-int:info :function :where-from 'i-do-not-exist) :assumed)) - (let ((w (assert-fopcompilable-and-compile-it - '(defvar *foo* (i-do-not-exist))))) - (assert (and (typep w 'sb-int:simple-style-warning) - (eql (search "undefined" - (write-to-string w :escape nil)) - 0))))) - -;; Note: This tests fails, but for a bad reason, as opposed to the wrong reason -;; (which was also bad). It used to fail because the name of the variable that it -;; used was completely removed, so it failed with "unknown variable". -;; Nobody noticed because the test got marked as failing when the variable was -;; removed. But now despite addition of a new deprecated variable, it fails -;; because it's *actually* failing, because the thing it tests got broken. -;; Ensure that FOPCOMPILE warns about deprecated variables. -(sb-int:define-deprecated-variable :late "1.1.4.9" *i-am-deprecated*) -(with-test (:name :fopcompiler-deprecated-var-warning - :fails-on :sbcl) - (assert (typep (assert-fopcompilable-and-compile-it - '(defvar *frob* (if *i-am-deprecated* 'yes 'no))) - 'sb-ext:deprecation-condition))) - -(ignore-errors (delete-file *tmp-filename*)) diff --git a/tests/foreign-stack-alignment.impure.lisp b/tests/foreign-stack-alignment.impure.lisp index a4b89a210d..bd505938dc 100644 --- a/tests/foreign-stack-alignment.impure.lisp +++ b/tests/foreign-stack-alignment.impure.lisp @@ -18,47 +18,47 @@ (import 'sb-alien::alien-lambda) (defun run (program &rest arguments) - (let* ((proc nil) - (output - (with-output-to-string (s) - (setf proc (run-program program arguments - :output s))))) + (let* ((stringstream (make-string-output-stream)) + (proc (run-program program arguments + :output stringstream :error sb-sys:*tty* + :search (or #+win32 t))) + (output (get-output-stream-string stringstream))) (unless (zerop (process-exit-code proc)) (error "Bad exit code: ~S~%Output:~% ~S" (process-exit-code proc) output)) output)) +(defun cc (&rest arguments) + (apply #'run #+unix "./run-compiler.sh" #+win32 "gcc" arguments)) (defvar *required-alignment* (or #+arm 8 #+mips 8 - #+(and ppc darwin) 16 - #+(and ppc (not darwin)) 8 + #+ppc 8 #+(or arm64 x86 x86-64 riscv ppc64) 16 #+sparc 8 - #+alpha 16 - #+hppa 64 (error "Unknown platform"))) ;;;; Build the offset-tool as regular excutable, and run it with ;;;; fork/exec, so that no lisp is on the stack. This is our known-good ;;;; number. -#-win32 +(defvar *exename* (format nil "stackalign-test~a" (or #+win32 ".exe" ""))) +(defvar *soname* (format nil "stackalign-test~a" (or #+win32 ".dll" ".so"))) + (progn - (run "/bin/sh" "run-compiler.sh" "-sbcl-pic" - "stack-alignment-offset.c" "-o" "stack-alignment-offset") + (cc #+unix "-sbcl-pic" "-o" *exename* "stack-alignment-offset.c") (defparameter *good-offset* - (parse-integer (run "./stack-alignment-offset" + (parse-integer (run (format nil "./~a" *exename*) (princ-to-string *required-alignment*)))) - + (format t "~s is ~d~%" '*good-offset* *good-offset*) ;; Build the tool again, this time as a shared object, and load it - (run "/bin/sh" "run-compiler.sh" "-sbcl-pic" "-sbcl-shared" - "stack-alignment-offset.c" "-o" "stack-alignment-offset.so") + #+unix (cc "-sbcl-shared" "-sbcl-pic" "-o" *soname* "stack-alignment-offset.c") + #+win32 (cc "-shared" "-o" *soname* "stack-alignment-offset.c") - (load-shared-object (truename "stack-alignment-offset.so")) + (load-shared-object (truename *soname*)) (define-alien-routine stack-alignment-offset int (alignment int)) #+alien-callbacks @@ -67,17 +67,16 @@ ;;;; Now get the offset by calling from lisp, first with a regular foreign function ;;;; call, then with an intervening callback. -(with-test (:name :regular :fails-on :win32) +(with-test (:name :regular) (assert (= *good-offset* (stack-alignment-offset *required-alignment*)))) #+alien-callbacks -(with-test (:name :callback :fails-on :win32) +(with-test (:name :callback) (assert (= *good-offset* (trampoline (alien-lambda int () (stack-alignment-offset *required-alignment*)))))) -(when (probe-file "stack-alignment-offset.so") - (delete-file "stack-alignment-offset") - (delete-file "stack-alignment-offset.so")) +(ignore-errors (delete-file *exename*)) +(ignore-errors (delete-file *soname*)) ;;;; success! diff --git a/tests/foreign.test.sh b/tests/foreign.test.sh index d46d0f3033..55e3f38dba 100755 --- a/tests/foreign.test.sh +++ b/tests/foreign.test.sh @@ -23,11 +23,6 @@ use_test_subdirectory echo //entering foreign.test.sh -# simple way to make sure we're not punting by accident: -# setting PUNT to anything other than 104 will make non-dlopen -# and non-linkage-table platforms fail this -PUNT=$EXIT_TEST_WIN - ## Make some shared object files to test with. build_so() ( @@ -137,6 +132,7 @@ echo 'int foo = 42;' > $TEST_FILESTEM-b2.c # some constants in the functions), so that the test will fail if we accidentally # call the new bar() at the old address - as might happen if the OS maps both '.so' # files at the same place - as a consequence of failing to update the linkage table. +echo 'int bar(void);' >> $TEST_FILESTEM-b2.c echo 'int somerandomfun(int x) { return x?-x:bar(); }' >> $TEST_FILESTEM-b2.c echo 'int bar() { return 13; }' >> $TEST_FILESTEM-b2.c build_so $TEST_FILESTEM-b2 @@ -150,6 +146,7 @@ cat > $TEST_FILESTEM-noop-dlclose-test.c <<EOF #include <stddef.h> int dlclose_is_noop () { +#ifdef RTLD_NOLOAD void * handle = dlopen("./$TEST_FILESTEM-noop-dlclose-test-helper.so", RTLD_NOW | RTLD_GLOBAL); dlclose(handle); @@ -157,6 +154,7 @@ int dlclose_is_noop () { if (handle != NULL) { return 1; } +#endif return 0; } EOF @@ -208,10 +206,6 @@ cat > $TEST_FILESTEM.base.lisp <<EOF (define-alien-routine return-int-test int (p int :copy)) (define-alien-routine return-uint-test unsigned-int (p unsigned-int :copy)) - ;; compiling this gets us the FOP-FOREIGN-DATAREF-FIXUP on - ;; linkage-table ports - (defvar *extern* (extern-alien "negative_short" short)) - ;; Test that loading an object file didn't screw up our records ;; of variables visible in runtime. (This was a bug until ;; Nikodemus Siivola's patch in sbcl-0.8.5.50.) @@ -483,5 +477,27 @@ cat > $TEST_FILESTEM.alien.enum.lisp <<EOF EOF expect_clean_compile $TEST_FILESTEM.alien.enum.lisp +# If dlopen is available, check that the address we get for a symbol +# from dlsym and from backing it out of the linkage table match. +run_sbcl <<EOF + (eval-when (:compile-toplevel :load-toplevel :execute) + (setq *features* (union *features* sb-impl:+internal-features+))) + #+os-provides-dlopen + (progn + (extern-alien "posix_argv" (* (* char))) + (extern-alien "sin" (function double double)) + + ;; Test that data pointers are the same. + (assert (= (sb-sys:find-dynamic-foreign-symbol-address "posix_argv") + (sb-sys:find-linkage-table-foreign-symbol-address "posix_argv"))) + + ;; Test that function pointers are the same. + (assert (= (sb-sys:find-dynamic-foreign-symbol-address "sin") + (sb-sys:find-linkage-table-foreign-symbol-address "sin")))) + + (exit :code $EXIT_LISP_WIN) +EOF +check_status_maybe_lose "arch-read-linkage-table-entry" $? + # success convention for script exit $EXIT_TEST_WIN diff --git a/tests/format.pure.lisp b/tests/format.pure.lisp index d67e8119e2..0edb2405d7 100644 --- a/tests/format.pure.lisp +++ b/tests/format.pure.lisp @@ -116,12 +116,14 @@ (try "~{~0%~ ~0|~0~~}"))) -(with-test (:name :nowarn-princ) +(with-test (:name :no-compiler-notes) ;; you should't see optimization notes from compiling format strings. ;; (the FORMATTER macro is a heavy user of PRINC) (checked-compile '(lambda (x) (declare (optimize speed)) (princ x)) - :allow-notes nil)) + :allow-notes nil) + (checked-compile + '(lambda () (declare (optimize speed)) (formatter "~:*")))) (defun format-to-string-stream (thing string-stream) (declare (notinline format)) diff --git a/tests/full-eval.impure.lisp b/tests/full-eval.impure.lisp index 5e229bbeb4..515c6be59e 100644 --- a/tests/full-eval.impure.lisp +++ b/tests/full-eval.impure.lisp @@ -11,8 +11,7 @@ ;;;; absolutely no warranty. See the COPYING and CREDITS files for ;;;; more information. -#-(or sb-eval sb-fasteval) -(sb-ext:exit :code 104) +#-(or sb-eval sb-fasteval) (invoke-restart 'run-tests::skip-file) (setf sb-ext:*evaluator-mode* :interpret) @@ -122,7 +121,7 @@ (sb-c::cif 'c) (sb-c::cset 'd) (sb-c::ref 'e) - (sb-kernel:layout 'winner))) + (sb-kernel:wrapper 'winner))) (with-test (:name :interpreted-type-constraint) (assert (eq (typecase-test (sb-kernel:find-layout 'cons)) 'winner))) diff --git a/tests/fun-names.pure.lisp b/tests/fun-names.pure.lisp index b024cb57eb..8aae2a42d7 100644 --- a/tests/fun-names.pure.lisp +++ b/tests/fun-names.pure.lisp @@ -12,7 +12,7 @@ ;;;; more information. (defun makec1 (a) (lambda () "doc" (values a))) -(defun makec2 (a b) (lambda () (values a b))) +(defun makec2 (a b) (lambda () "doc" (values a b))) (compile 'makec1) (compile 'makec2) @@ -48,7 +48,8 @@ (dolist (name `("afun" afun (afun) (afun . "guy") (afun . guy) (afun guy) ,sb-pcl:+slot-unbound+ nil)) (dolist (doc `("what's up" nil ,sb-pcl:+slot-unbound+)) - (let ((closure (makec1 :a))) + (dolist (closure (list (makec1 :a) + (makec2 :a :b))) (sb-impl::set-closure-extra-values closure nil (sb-impl::pack-closure-extra-values name doc)) (multiple-value-bind (stored-name stored-doc) @@ -57,3 +58,15 @@ (assert (eq stored-doc doc))) (assert (string= (documentation closure t) (if (eq doc sb-pcl:+slot-unbound+) "doc" doc))))))) + +(with-test (:name :no-funcall-of-extended-name) + (multiple-value-bind (fun warnp errorp) + (checked-compile '(lambda (x y) (funcall '(setf foo) x y)) + :allow-warnings t) + (assert (and warnp errorp)) + (assert-error (funcall fun nil 1) type-error)) + (multiple-value-bind (fun warnp errorp) + (checked-compile '(lambda (x y) (multiple-value-call '(setf foo) x (floor y 2))) + :allow-warnings t) + (assert (and warnp errorp)) + (assert-error (funcall fun nil 1) type-error))) diff --git a/tests/futex-wait.test.sh b/tests/futex-wait.test.sh new file mode 100755 index 0000000000..7d49e34e13 --- /dev/null +++ b/tests/futex-wait.test.sh @@ -0,0 +1,151 @@ +#!/bin/sh + +. ./subr.sh + +run_sbcl <<EOF + ;; The desired output differs by many factors, but an arbitrary slop allowance + ;; could let the old bug creep back in. + #+(and linux sb-thread) (exit :code #+(or x86 x86-64) 45 + #-(or x86 x86-64) 100) + ;; can't run the test + (exit :code 0) +EOF +expect_test_outcome=$? +if [ $expect_test_outcome -eq 0 ] ; then # test can't be executed + # we don't have a way to exit shell tests with "inapplicable" as the result + exit $EXIT_TEST_WIN +fi + +# Some distributions do not have strace by default or restrict the +# ptrace system call. +if which strace > /dev/null && ! strace ls > /dev/null 2>&1 ; then + exit $EXIT_TEST_WIN +fi + +set -e + +tracelog=`mktemp ${TMPDIR:-/tmp}/$TEST_FILESTEM.XXXXXX` + +strace -f -e futex -e signal=\!sigsegv -o $tracelog \ + $SBCL_RUNTIME --core "$SBCL_CORE" $SBCL_ARGS <<EOF +(defvar *m* (sb-thread:make-mutex :name "stupid")) +(defvar *thr*) + +(sb-thread:grab-mutex *m*) + +;; We need to simulate some thread observing the mutex in a contested state, while +;; the thread that currently holds it releases and re-grabs it again quickly enough +;; to place it in state 1, not state 2 (but having correctly notified waiters). +;; It's also possible to have more than 2 threads involved because any number +;; of threads can be woken by futex_wait even with a parameter of N=1. +;; Due to a flaw in our rendition of Mutex Algorithm 2 from the reference paper, +;; when this happened, any of the waiters might never get put into a sleep +;; in its futex wait - it would get EWOULDBLOCK every time, which is acceptable +;; in that the algorithm wasn't broken, but it was highly inefficient. + +;; There's no way to force this situation to arise other than by poking at the +;; state of the mutex. So we want to simulate this sequence of events: +;;; step 1: set state 0 (available) | +;;; step 2: futex wake | from one thread +;;; step 3: set state 1 (taken) | +;;; But we're actually going to do this instead: +;;; step 1: set state 1 (taken) +;;; step 2: futex wake +;;; By doing this, the awakened waiter is sure to observe state 1 and only state 1. +;;; +;;; Our bug turned the futex algorithm into the world's most expensive spinlock. +;;; Each "spin" on the lock bit would require a system call and return. + +(defun test () +(setf (sb-thread::mutex-state *m*) 2) ; contested state +(setq *thr* + (sb-thread:make-thread + (lambda () + ;; thr will see the mutex in state 2 + (format t "~&thread ~s started~%" sb-thread:*current-thread*) + (sb-thread:grab-mutex *m*) + (format t "~&thread gets mutex~%")))) + +;; Give the thread some time to enter its futex wait the normal way, but observing +;; that the initial state is already contested. Therefore it avoids doing one compare-and-swap +;; to set it to contested. And due to the bug, it was treating the state as *always* +;; contested even when it was not. And the optimization to avoid changing the state +;; to contested therefore caused every futex_wait call to return immediately. +(sleep .025) +;; Now pretend this thread grabbed/notified/re-grabbed sooner than the other thread +;; could execute enough of its retry loop to win the grab. i.e. it's going to sleep +;; again on the futex word, but where it would incorrectly think the mutex is already +;; in state 2 and would not change it, thus failing the match condition in futex_wait. +(setf (sb-thread::mutex-state *m*) 1) +(sb-sys:with-pinned-objects (*m*) + (let ((disp + (- (* (+ sb-vm:instance-slots-offset + (sb-kernel:get-dsd-index sb-thread::mutex sb-thread::state)) + sb-vm:n-word-bytes) + sb-vm:instance-pointer-lowtag))) + (sb-thread::futex-wake (+ (sb-kernel:get-lisp-obj-address *m*) disp + #+(and 64-bit big-endian) 4) + 1))) + +(format t "~&looks like mutex state is ~d~%" (sb-thread::mutex-state *m*)) +(sleep .05) ; let that thread lose for a while +(sb-thread:release-mutex *m*) +(sb-thread:join-thread *thr*)) +(compile 'test) +(test) +EOF + +n=`awk 'END{print NR}' < $tracelog` +rm $tracelog + +if [ $n -le $expect_test_outcome ] +then + exit $EXIT_TEST_WIN +fi +# This test was seeing >1500 calls to futex_wait due to the bug +echo N was $n +exit 0 + +# SBCL had a bug in %%WAIT-FOR-MUTEX. This is an examination of why one should not +# endeavor to make the slightest alteration to researched and published code, +# potentially even so far as eschewing gratuitious abtractions such as introduction +# of symbolic constants that if anything make it difficult to compare against +# the reference algorithm. +# +# value of C as-is STATE value +# from top of PROG after futex-wait outcome +# ================ ================ ======= +# +# 1 1 same as reference algorithm +# after wait: cmpxchg(val,0,2) fails +# reference algorithm assigns C := 1 here. SBCL did not assign, +# but the value of C is that anyway. +# at retry : cmpxchg(val,1,2) suceeds +# +# ---------------------------------------------------------------------------- +# +# 2 1 extra futex_wait/wake cycles +# after wait: cmpxchg(val,0,2) fails +# reference algorithm assigns C := 1 here +# SBCL incorrectly omits the next cmpxchg, which was needed. +# at retry : cmpxchg(val,1,2) succeeds ; SBCL omits by mistake +# +# by omitting a required cmpxchg, the state is perceived as 2 when it isn't. +# futex_wait() returns EWOULDBLOCK. This cycle continues forever +# until the mutex is released. +# +# ---------------------------------------------------------------------------- +# +# 1 2 one extra cmpxchg +# after wait: cmpxchg(val,0,2) fails +# reference algorithm assigns C := 2 here but SBCL algorithm did not, +# therefore the reference algorithm does not attempt next cmpxchg. +# at retry : cmpxchg(val,1,2) fails ; this cmpxchg is not needed. +# +# ---------------------------------------------------------------------------- +# +# 2 2 +# after wait: cmpxchg(val,0,2) fails +# reference algorithm assigns C := 2 here. SBCL did not assign, +# but the value of C is that anyway. +# diff --git a/tests/fwdref-layout.impure.lisp b/tests/fwdref-layout.impure.lisp new file mode 100644 index 0000000000..2c14147825 --- /dev/null +++ b/tests/fwdref-layout.impure.lisp @@ -0,0 +1,51 @@ + +;;; Regression tests for bugs cited in +;;; https://groups.google.com/g/sbcl-devel/c/4XTJ9hEUngM/m/B5-iQxdTAAAJ + +;;; 1. loading an externalized literal prior to seeing a %DEFSTRUCT +;;; and %TARGET-DEFSTRUCT for the type. +;; Presence of raw slots is irrelevant. +(with-test (:name :literal-before-defstruct) + (with-scratch-file (srcname "lisp") + (with-scratch-file (fasl "fasl") + (with-open-file (src srcname :direction :output) + (print '(in-package "STRUCT") src) + (print '(eval-when (:compile-toplevel :load-toplevel) + (defstruct charstruc (c #\a :type character))) + src) + (print '(eval-when (:compile-toplevel) + (defmethod make-load-form ((x charstruc) &optional e) + (make-load-form-saving-slots x :environment e))) + src) + ;; Write as a string because #S() won't work until CHARSTRUC is compiled + (write-string "(defparameter *s* #s(charstruc :c #\\z))" src)) + (make-package "STRUCT" :use '("CL")) + (compile-file srcname :output-file fasl :verbose nil) + (delete-package "STRUCT") + (make-package "STRUCT" :use '("CL")) + (load fasl)))) + +;;; 2. referencing a layout and then defining the structure +;;; could fail if there are raw slots. +(with-test (:name :no-spurious-redef-warning) + (with-scratch-file (srcname "lisp") + (with-scratch-file (fasl "fasl") + (with-open-file (src srcname :direction :output) + (let ((defstruct + `(defstruct (big (:predicate nil)) + (first t) + ,@(loop for i below sb-vm:n-word-bits + collect `(,(sb-int:symbolicate "RAW" (write-to-string i)) + 0 :type cl:double-float)) + ,@(loop for i below 5 + collect `(,(sb-int:symbolicate "MORE" (write-to-string i)) nil))))) + (print '(in-package "STRUCT") src) + (print `(eval-when (:compile-toplevel) ,defstruct) src) ; for compiling a type-check + (print `(defun bigp (x) (typep x 'big)) src) + (print defstruct src))) + ;; Reusing the same package as from test #1 + ;; (make-package "STRUCT" :use '("CL")) + (compile-file srcname :output-file fasl :verbose nil) + (delete-package "STRUCT") + (make-package "STRUCT" :use '("CL")) + (load fasl)))) diff --git a/tests/gc-cardmark.impure.lisp b/tests/gc-cardmark.impure.lisp new file mode 100644 index 0000000000..fe4c50dbc3 --- /dev/null +++ b/tests/gc-cardmark.impure.lisp @@ -0,0 +1,28 @@ + +;;; The layout of FOO must not get promoted from gen0 to gen1. +;;; Due to random variation, there might be a gc-with-promotion cycle +;;; just after the defstruct. So prevent that. +#+gencgc (setf (generation-number-of-gcs-before-promotion 0) 1000000) +(defstruct foo x) +(defun get-layouts-for-test () + ;; Return a young layout and an old layout + (vector (sb-kernel:find-layout 'foo) + (sb-kernel:find-layout 'class))) + +(with-test (:name :compact-instance-header-layout + :skipped-on (:not (:and :compact-instance-header :soft-card-marks))) + (unless (probe-file "gc-testlib.so") + (sb-ext:run-program "sh" + `("run-compiler.sh" "-sbcl-pic" "-sbcl-shared" + #+darwin ,@'("-flat_namespace" "-undefined" "suppress") + "-I../src/runtime" + "gc-testlib.c" "-o" "gc-testlib.so") + :search t + :output t :error t)) + (load-shared-object (truename "gc-testlib.so")) + #+sb-thread (sb-impl::finalizer-thread-stop) + (let ((v (get-layouts-for-test))) + (sb-sys:with-pinned-objects (v) + (alien-funcall (extern-alien "compact_instance_layout_pointer_test" + (function int unsigned)) + (sb-kernel:get-lisp-obj-address v))))) diff --git a/tests/gc-search.impure.lisp b/tests/gc-search.impure.lisp new file mode 100644 index 0000000000..696479f1f4 --- /dev/null +++ b/tests/gc-search.impure.lisp @@ -0,0 +1,67 @@ + +#-immobile-space (invoke-restart 'run-tests::skip-file) + +(defun make-page-full-of-fdefns () + ;; Make a bunch of fdefns until we're aligned at a page boundary. + (let* ((page-size 4096) + (n-per-page (floor page-size sb-vm:symbol-size)) + (fdefn) + (page-base) + (list) + (retries 0)) + (tagbody + try-again + (format t "~&Try ~D~%" (1+ retries)) + (dotimes (i n-per-page) + (setq fdefn (sb-vm::alloc-immobile-fdefn)) + (when (not (logtest (logandc2 (sb-kernel:get-lisp-obj-address fdefn) + sb-vm:lowtag-mask) + (1- page-size))) + ;; Yay! This fdefn is immobile-page-aligned + (return))) + (setq page-base (logandc2 (sb-kernel:get-lisp-obj-address fdefn) + sb-vm:lowtag-mask)) + (setq list (list fdefn)) + ;; Now try to allocate enough more to fill up the page so that + ;; it is assured that there are not other (older) random fdefns + ;; on that page. + (dotimes (i (1- n-per-page)) + (let* ((other-fdefn (sb-vm::alloc-immobile-fdefn)) + (addr (logandc2 (sb-kernel:get-lisp-obj-address other-fdefn) + sb-vm:lowtag-mask))) + (cond ((= addr (+ page-base (* (1+ i) sb-vm:fdefn-size sb-vm:n-word-bytes))) + ;; (format t "Winner~%") + (push fdefn list)) ; ensure liveness + (t + ;; (format t "Oops~%") + (setq list nil) + (if (<= (incf retries) 10) + (go try-again) + (error "Test fails"))))))) + (format t "~&Made page of fdefns~%") + (let ((wps (mapcar 'make-weak-pointer list))) + (setq fdefn nil list nil) + ;; Now we need to make one more fdefn (or anything really) so that it gets + ;; a higher address than the "victim" page, so that the high-water-mark + ;; of allocated pages is strictly higher than PAGE-BASE, thus ensuring that + ;; after GC it looks like the page at PAGE-BASE could be in use. + (let ((another (sb-vm::alloc-immobile-fdefn))) + (assert (>= (sb-kernel:get-lisp-obj-address another) + (+ page-base page-size)))) + ;; And return page-base so we don't read any weak-pointer-value henceforth. + (values wps page-base)))) + +;;; This could get SIGFPE in search_immobile_space() with the following unfortunate result: +;;; UNEXPECTED-FAILURE :FIND-ON-EMPTY-FIXEDOBJ-PAGE +;;; due to SB-KERNEL:FLOATING-POINT-EXCEPTION: +;;; "An arithmetic error SB-KERNEL:FLOATING-POINT-EXCEPTION was signalled. +;;; No traps are enabled? How can this be? +(with-test (:name :find-on-empty-fixedobj-page + :skipped-on (not :sb-thread)) ;; fails intermittently + (multiple-value-bind (wps page-base) (make-page-full-of-fdefns) + (format t "~&Fdefn page base = ~x~%" page-base) + (sb-sys:scrub-control-stack) + (gc :full t) + (dolist (wp wps) (assert (not (weak-pointer-value wp)))) + (assert (not (sb-di::code-header-from-pc + (logior page-base sb-vm:other-pointer-lowtag)))))) diff --git a/tests/gc-slow.impure.lisp b/tests/gc-slow.impure.lisp new file mode 100644 index 0000000000..510e6dd271 --- /dev/null +++ b/tests/gc-slow.impure.lisp @@ -0,0 +1,76 @@ +(defparameter *x* ()) + +(defun cons-madly () + (loop repeat 10000 do + (setq *x* (make-string 100000)))) + +;; check that WITHOUT-INTERRUPTS doesn't block the gc trigger +(with-test (:name :cons-madly-without-interrupts) + (sb-sys:without-interrupts (cons-madly))) + +(with-test (:name :without-gcing) + (let ((gc-happend nil)) + (push (lambda () (setq gc-happend t)) sb-ext:*after-gc-hooks*) + + ;; check that WITHOUT-GCING defers explicit gc + (sb-sys:without-gcing + (gc) + (assert (not gc-happend))) + (assert gc-happend) + + ;; check that WITHOUT-GCING defers SIG_STOP_FOR_GC + #+sb-thread + (let ((in-without-gcing nil)) + (setq gc-happend nil) + (sb-thread:make-thread (lambda () + (loop while (not in-without-gcing)) + (sb-ext:gc))) + (sb-sys:without-gcing + (setq in-without-gcing t) + (sleep 3) + (assert (not gc-happend))) + ;; give the hook time to run + (sleep 1) + (assert gc-happend)))) + +;;; After each iteration of FOO there are a few pinned conses. +;;; On alternate GC cycles, those get promoted to generation 1. +;;; When the logic for page-spanning-object zeroing incorrectly decreased +;;; the upper bound on bytes used for partially pinned pages, it caused +;;; an accumulation of pages in generation 1 each with 2 objects' worth +;;; of bytes, and the remainder waste. Because the waste was not accounted +;;; for, it did not trigger GC enough to avoid heap exhaustion. +(with-test (:name :smallobj-auto-gc-trigger) + ;; Ensure that these are compiled functions because the interpreter + ;; would make lots of objects of various sizes which is insufficient + ;; to provoke the bug. + (setf (symbol-function 'foo) + (compile nil '(lambda () (list 1 2)))) + ;; 500 million iterations of this loop seems to be reliable enough + ;; to show that GC happens. + (setf (symbol-function 'callfoo) + (compile nil '(lambda () (loop repeat 500000000 do (foo))))) + (funcall 'callfoo)) + +#+sb-thread +(with-test (:name :concurrently-alloc-code) + ;; this debug setting may or may not find a problem, but it can't hurt to try + (setf (extern-alien "pre_verify_gen_0" int) 1) + (let ((worker-th + (sb-thread:make-thread + (let ((stop (+ (get-internal-real-time) + (* 1.5 internal-time-units-per-second)))) + (lambda (&aux (n 0)) + (loop while (<= (get-internal-real-time) stop) + do (compile nil `(lambda () (print 20))) + (incf n)) + n))))) + (let ((gcs 0)) + (loop (gc) (incf gcs) + (unless (sb-thread:thread-alive-p worker-th) + (return)) + (sb-unix:nanosleep 0 (+ 1000000 (random 100000)))) + (let ((compiles (sb-thread:join-thread worker-th))) + (format t "~&Compiled ~D times, GC'ed ~D times~%" + compiles gcs)))) + (setf (extern-alien "pre_verify_gen_0" int) 0)) diff --git a/tests/gc-smoketest.pure.lisp b/tests/gc-smoketest.pure.lisp new file mode 100644 index 0000000000..aa76fde930 --- /dev/null +++ b/tests/gc-smoketest.pure.lisp @@ -0,0 +1,14 @@ + +;;; Please keep all the "smoke" tests in this file fairly lightweight. + +;;; Don't crash on layoutless instances. It's that simple! +(defvar *l* nil) +(defun f (n) (dotimes (i n) (push (sb-kernel:%make-instance 5) *l*))) +(with-test (:name :layoutless-instance-no-crash) + (f 20) + (gc)) + +;;; Don't loop infinitely in mark_obj() on circular lists +(defvar *foo* (cons nil nil)) +(rplacd *foo* *foo*) +(with-test (:name :circular-list) (gc :gen 7)) diff --git a/tests/gc-testlib.c b/tests/gc-testlib.c new file mode 100644 index 0000000000..181723218e --- /dev/null +++ b/tests/gc-testlib.c @@ -0,0 +1,172 @@ +/* Test that layout pointer in a compact instance header + * isn't overlooked by scan_boxed_root_cards_spanning() + * or update_writeprotection() */ + +#include <stdio.h> +#include "sbcl.h" +#include "gc-internal.h" +#include "gc-private.h" + +extern struct generation generations[]; +extern os_vm_size_t bytes_allocated; + +// Create a 2-word instance and a 6-word funcallable instance. +// Ensure they are on different GC cards. +static void make_instances(int page_type, generation_index_t gen, lispobj result[2]) +{ + page_index_t page = 0, last; + // Passing SINGLE_OBJECT_FLAG avoids combining with a previous page + last = gc_find_freeish_pages(&page, GENCGC_PAGE_BYTES, + SINGLE_OBJECT_FLAG | page_type, gen); + gc_assert(last == page); + lispobj* where = (void*)page_address(page); + page_table[page].type = page_type; + page_table[page].gen = 1; + gc_assert(page_table[page].scan_start_offset_ == 0); + page_table[page].words_used_ = (2 * GENCGC_CARD_BYTES) >> WORD_SHIFT; + page_table[page].need_zerofill = 1; + bytes_allocated += 2 * GENCGC_CARD_BYTES; + generations[gen].bytes_allocated += 2 * GENCGC_CARD_BYTES; + + // Create the ordinary instance, total length 2 words + lispobj instance = make_lispobj(where, INSTANCE_POINTER_LOWTAG); + where[0] = (1 << INSTANCE_LENGTH_SHIFT) | INSTANCE_WIDETAG; + where[1] = 0; + where += 2; + + // Fill to the end of the card + int filler_nwords = (GENCGC_CARD_BYTES >> WORD_SHIFT) - 2; + *where = make_filler_header(filler_nwords); + + // Assert that no tagged pointer can point to the filler + // fprintf(stderr, "Filler @ %p: %"OBJ_FMTX"\n", where, *where); + int lowtag; + for (lowtag=1; lowtag<=LOWTAG_MASK; ++lowtag) { + lispobj addr = make_lispobj(where, lowtag); + gc_assert(!plausible_tag_p(addr)); + } + + where += filler_nwords; + + // Create the funcallable instance, total length 6 words + lispobj funinstance = make_lispobj(where, FUN_POINTER_LOWTAG); + where[0] = (1 << N_WIDETAG_BITS) | FUNCALLABLE_INSTANCE_WIDETAG; + where[1] = where[2] = where[3] = where[4] = where[5] = 0; + where += 6; + + // Fill to the end of the card + filler_nwords = (GENCGC_CARD_BYTES >> WORD_SHIFT) - 6; + *where = make_filler_header(filler_nwords); + where += filler_nwords; + + result[0] = instance; + result[1] = funinstance; +} + +static void perform_gc(lispobj* stackptr) +{ + extern void close_current_thread_tlab(); + extern void garbage_collect_generation(generation_index_t, int, void*); + + gc_active_p = 1; + gc_close_collector_regions(0); // TODO: should be THREAD_PAGE_FLAG + close_current_thread_tlab(); + + /* We have to clobber the dynamic space codeblob tree because ordinarily + * it gets smashed at the start of collect_garbage(), and since this test + * bypasses collect_garbage(), the GC might have problems later. + * (Not exactly sure how, but "header not OK for code page" was triggering) + * So, handily, since there are no concurrency issues in this test, + * it doesn't matter that the GC can't utilize the tree. It falls back + * to scanning code pages linearly in preserve_pointer which is fine. */ + SYMBOL(DYNSPACE_CODEBLOB_TREE)->value = NIL; + + verify_heap(stackptr, VERIFY_PRE_GC); + garbage_collect_generation(0, 0, stackptr); + gc_active_p = 0; +} + +void run_cardmark_test(int page_type, + lispobj young_layout, lispobj old_layout, + lispobj* stackptr) +{ + lispobj instances[2]; + make_instances(page_type, 1, instances); + lispobj instance = instances[0], funinstance = instances[1]; + fprintf(stderr, "allocated @ %p and %p\n", (void*)instance, (void*)funinstance); + long instance_card = addr_to_card_index((void*)instance); + long funinstance_card = addr_to_card_index((void*)funinstance); + + // Assert something about the card indices + fprintf(stderr, "page = %d, cards = %d and %d\n", + (int)find_page_index((void*)instance), + (int)instance_card, (int)funinstance_card); + gc_assert(funinstance_card == instance_card+1); + + perform_gc(stackptr); + // the cards containing the instances should be unmarked + gc_assert(gc_card_mark[instance_card] == CARD_UNMARKED); + gc_assert(gc_card_mark[funinstance_card] == CARD_UNMARKED); + instance_layout(native_pointer(instance)) = old_layout; + instance_layout(native_pointer(funinstance)) = old_layout; + gc_card_mark[instance_card] = CARD_MARKED; + gc_card_mark[funinstance_card] = CARD_MARKED; + perform_gc(stackptr); + // should have gotten unmarked + gc_assert(gc_card_mark[instance_card] == CARD_UNMARKED); + gc_assert(gc_card_mark[funinstance_card] == CARD_UNMARKED); + + // Test 1: regular instance + instance_layout(native_pointer(instance)) = young_layout; + gc_card_mark[instance_card] = CARD_MARKED; + gc_card_mark[funinstance_card] = CARD_MARKED; // "spuriously" marked + perform_gc(stackptr); + // should stay marked + gc_assert(gc_card_mark[instance_card] == CARD_MARKED); + // BOXED pages can undirty at the card granularity, but MIXED pages can't + if (page_type == PAGE_TYPE_BOXED) + gc_assert(gc_card_mark[funinstance_card] == CARD_UNMARKED); + + instance_layout(native_pointer(instance)) = old_layout; + perform_gc(stackptr); + // both cards are clean + gc_assert(gc_card_mark[instance_card] == CARD_UNMARKED); + gc_assert(gc_card_mark[funinstance_card] == CARD_UNMARKED); + + // Test 2: funinstance + instance_layout(native_pointer(funinstance)) = young_layout; + gc_card_mark[funinstance_card] = CARD_MARKED; + gc_card_mark[instance_card] = CARD_MARKED; // "spuriously" marked + perform_gc(stackptr); + // should stay marked + gc_assert(gc_card_mark[funinstance_card] == CARD_MARKED); + // BOXED pages can undirty at the card granularity, but MIXED pages can't + if (page_type == PAGE_TYPE_BOXED) + gc_assert(gc_card_mark[instance_card] == CARD_UNMARKED); + + funinstance_layout(native_pointer(funinstance)) = old_layout; + perform_gc(stackptr); + // both cards are clean + gc_assert(gc_card_mark[instance_card] == CARD_UNMARKED); + gc_assert(gc_card_mark[funinstance_card] == CARD_UNMARKED); + printf("PASS\n"); +} + +int compact_instance_layout_pointer_test(lispobj arg) +{ + // Capture the approximate stack pointer on entry + lispobj* stackptr = &arg; + struct vector* layouts = (void*)native_pointer(arg); + lispobj young_layout = layouts->data[0]; + lispobj old_layout = layouts->data[1]; + gc_assert(immobile_obj_generation(native_pointer(young_layout))==0); + // Don't want sticky marks messing up the test. + // It suffices to check that there are no register contexts. + struct thread* self = get_sb_vm_thread(); + gc_assert(read_TLS(FREE_INTERRUPT_CONTEXT_INDEX, self) == 0); + printf("PAGE_TYPE_MIXED:\n"); fflush(stdout); + run_cardmark_test(PAGE_TYPE_MIXED, young_layout, old_layout, stackptr); + printf("PAGE_TYPE_BOXED:\n"); fflush(stdout); + run_cardmark_test(PAGE_TYPE_BOXED, young_layout, old_layout, stackptr); + return 0; +} diff --git a/tests/gc-threads.impure.lisp b/tests/gc-threads.impure.lisp new file mode 100644 index 0000000000..a2bf0e58cb --- /dev/null +++ b/tests/gc-threads.impure.lisp @@ -0,0 +1,47 @@ +#-sb-thread (invoke-restart 'run-tests::skip-file) + +(with-test (:name (:two-threads-running-gc) + :broken-on :sb-safepoint) + (let (a-done b-done) + (make-join-thread (lambda () + (dotimes (i 100) + (sb-ext:gc) (princ "\\") (force-output)) + (setf a-done t))) + (make-join-thread (lambda () + (dotimes (i 25) + (sb-ext:gc :full t) + (princ "/") (force-output)) + (setf b-done t))) + (loop + (when (and a-done b-done) (return)) + (sleep 1)))) + +(defun waste (&optional (n 1000)) + (loop repeat n do (test-util:opaque-identity (make-string 16384)))) + +(compile 'waste) + +(with-test (:name (:one-thread-runs-gc-while-other-conses) + :broken-on :win32) + (loop for i below 100 do + (princ "!") + (force-output) + (make-join-thread + #'(lambda () + (waste))) + (waste) + (sb-ext:gc))) + +(defparameter *aaa* nil) +(with-test (:name (:one-thread-runs-gc-while-other-conses :again) + :broken-on :win32) + (loop for i below 100 do + (princ "!") + (force-output) + (make-join-thread + #'(lambda () + (let ((*aaa* (waste))) + (waste)))) + (let ((*aaa* (waste))) + (waste)) + (sb-ext:gc))) diff --git a/tests/gc.impure-cload.lisp b/tests/gc.impure-cload.lisp deleted file mode 100644 index ae3694c57c..0000000000 --- a/tests/gc.impure-cload.lisp +++ /dev/null @@ -1,220 +0,0 @@ -;;;; more gc tests - -;;;; This software is part of the SBCL system. See the README file for -;;;; more information. -;;;; -;;;; While most of SBCL is derived from the CMU CL system, the test -;;;; files (like this one) were written from scratch after the fork -;;;; from CMU CL. -;;; -;;;; This software is in the public domain and is provided with -;;;; absoluely no warranty. See the COPYING and CREDITS files for -;;;; more information. - -#-gencgc -(eval-when (:compile-toplevel :load-toplevel :execute) - (sb-ext:exit :code 104)) - -(defconstant min-code-header-bytes - (let ((min-header-words (* 2 (ceiling sb-vm:code-constants-offset 2)))) - (* min-header-words sb-vm:n-word-bytes))) - -;;; A newly opened region must not start on a page that has 0 bytes available. -;;; The effect of that was to cause start_addr to be the next page's address, -;;; where the OPEN_REGION_PAGE_FLAG was already set on each page in the region -;;; including the one that was completely full. This caused a failure when -;;; closing the region because find_page_index(start_addr) was not the *first* -;;; page on which the open flag should be removed. -;;; Strangely, the assertion that caught this was far removed from the -;;; point of failure, in conservative_root_p() -(with-test (:name :gc-region-pickup :skipped-on (not (or :x86 :x86-64)) - ;; (and apparently can also fail on linux with larger card size) - :fails-on :win32) - (flet ((allocate-code-bytes (nbytes) - ;; Make a code component occupying exactly NBYTES bytes in total. - (assert (zerop (mod nbytes (* 2 sb-vm:n-word-bytes)))) - (assert (>= nbytes min-code-header-bytes)) - (sb-c:allocate-code-object nil 0 - sb-vm:code-constants-offset - (- nbytes min-code-header-bytes))) - (get-code-region (a) - (declare (type (simple-array sb-ext:word (4)) a)) - ;; Return array of 4: free-ptr, end-addr, last-page, start-addr - (dotimes (i 4 a) - (setf (aref a i) - (deref (extern-alien "gc_alloc_region" (array unsigned 12)) - ;; code region is the third region in the GC global - ;; regions. Each region is described by 4 words. - (+ 8 i)))))) - (let ((a (make-array 4 :element-type 'sb-ext:word)) - (code-size - #+64-bit 10240 - #-64-bit (- (* 4 sb-vm:gencgc-card-bytes) (* 2 sb-vm:n-word-bytes))) - (saved-region-start) - (saved-region-end)) - (symbol-macrolet ((free-ptr (aref a 0)) - (end-addr (aref a 1)) - (last-page (aref a 2)) - (start-addr (aref a 3))) - (gc) ; This will leave the code region in a closed state - (get-code-region a) - (assert (= free-ptr end-addr)) - ;; Allocate a teency amount to start a new region - (sb-c:allocate-code-object nil 0 sb-vm:code-constants-offset 0) - (get-code-region a) - (setq saved-region-start start-addr - saved-region-end end-addr) - (multiple-value-bind (n-chunks remainder) - (floor (- end-addr free-ptr) code-size) - ;; (Maybe) use up a few bytes more so that the larger objects - ;; exactly consume the entirety of the region. - (when (plusp remainder) - (allocate-code-bytes (max remainder min-code-header-bytes)) - (get-code-region a) - (multiple-value-setq (n-chunks remainder) - (floor (- end-addr free-ptr) code-size))) - (when (plusp remainder) - ;; This happens only if the MAX expression above bumped the - ;; remainder up, so now there is a different remainder. - (allocate-code-bytes remainder)) - (dotimes (i (1- n-chunks)) - (allocate-code-bytes code-size)) - ;; Now make two more objects, one consuming almost the entirety - ;; of the region, and one touching just the final page. - (allocate-code-bytes (- code-size 128)) - (let ((c (allocate-code-bytes 128))) - (get-code-region a) - ;; The region should be the same region we started with, - ;; not a new one. - (assert (= start-addr saved-region-start)) - (assert (= end-addr saved-region-end)) - ;; It should be totally full - (assert (= free-ptr end-addr)) - ;; Create an object to open a new region where the last one - ;; ended. It should start on the next completely empty page, - ;; not the prior totally full page. - (allocate-code-bytes 128) - ;; This GC failed - (gc) - ;; Return C (so that it has to be kept live on the stack). - c)))))) - -;;; This test pertains only to the compact-instance-header feature. -;;; It should pass regardless of the feature presence though. - -;;; Everything from here down to the WITH-TEST is the setup to try -;;; to hit "implausible layout" in verify_gc() which would occur -;;; prior to the associated fix in update_page_write_prot(). -;;; GC has to use care if the sole pointer to a layout is the header -;;; of an obsolete instance, so not to miss any old -> young pointers -;;; where the layout pointer is in the high half of the header word. -(setf (extern-alien "verify_gens" char) 0) - -(defstruct foo) - -(defun change-foo-layout (myfoo) - ;; Slam a new layout (a copy of the existing one) into a FOO - ;; The new layout will be *younger* than the FOO itself, - ;; which is exactly the situation that tickled the GC bug. - (flet ((copy-layout (layout) - ;; don't just COPY-STRUCTURE - that would place it in dynamic space - (let ((new-layout - (sb-kernel:make-layout (sb-kernel::hash-layout-name nil) - (sb-kernel:layout-classoid layout)))) - (sb-kernel:%byte-blt - (sb-sys:int-sap - (- (sb-kernel:get-lisp-obj-address layout) - sb-vm:instance-pointer-lowtag)) - sb-vm:n-word-bytes ; do not copy the header! - (sb-sys:int-sap - (- (sb-kernel:get-lisp-obj-address new-layout) - sb-vm:instance-pointer-lowtag)) - sb-vm:n-word-bytes ; correspondingly with above - (* (1+ (sb-kernel:%instance-length layout)) - sb-vm:n-word-bytes)) - new-layout))) - (setf (sb-kernel:%instance-layout myfoo) - (copy-layout (sb-kernel:%instance-layout myfoo))) - nil)) - -(defconstant n-conses-per-page - (/ sb-vm:gencgc-card-bytes (* 2 sb-vm:n-word-bytes))) - -(defparameter *junk* - (make-array (1+ (* 2 n-conses-per-page)))) - -;;; In order to get a FOO on a page by itself, we pad the page -;;; with conses of immediate values, before and after. -;;; So it doesn't matter where the FOO is, but there won't be -;;; other objects with pointers in them (the conses don't have pointers). -;;; And we point at all those conses from a single vector -;;; so that scavenging is forced to linearize them onto one page, -;;; along with the FOO, after discovering that the vector is live. -(defun filljunk (n) - (let ((j -1)) - (dotimes (i n) - (setf (svref *junk* (incf j)) (cons 1 2))) - (setf (svref *junk* (incf j)) (make-foo)) - (dotimes (i n) - (setf (svref *junk* (incf j)) (cons 1 2))))) - -(filljunk n-conses-per-page) - -;; Promote *junk* and all its referenced objects into generation 1 -;; With luck, they should be in order, and the page on which the FOO -;; resides should have some leading and trailing conses. -;; (The conses ensure that nothing else is on the page impeding -;; validity of the test) -(gc :gen 1) -(assert (= (sb-kernel:generation-of *junk*) 1)) - -;;; This test is very contrived, but this bug was observed in real life, -;;; having something to do with SB-PCL::CHECK-WRAPPER-VALIDITY. -(with-test (:name :gc-anonymous-layout) - ;;; The page on which the FOO instance resides should be WPed - ;;; and should have nothing else but conses on it. - (let* ((foo (svref *junk* n-conses-per-page)) - (page (sb-vm::find-page-index (sb-kernel:get-lisp-obj-address foo))) - (gen (slot (deref sb-vm::page-table page) 'sb-vm::gen)) - (flags (slot (deref sb-vm::page-table page) 'sb-vm::flags)) - (wp (logbitp 3 flags)) - (page-addr (+ sb-vm:dynamic-space-start - (* sb-vm:gencgc-card-bytes page))) - (aok t)) - (declare (ignorable gen wp)) - ; (format t "~&page ~d: gen=~d flags=~b (wp=~a)~%" page gen flags wp)) - ;; Check that the page holding the FOO has those conses and nothing else - (sb-vm::map-objects-in-range - (lambda (obj type size) - (declare (ignore type size)) - (unless (typep obj '(or (cons (eql 1) (eql 2)) foo)) - (setq aok nil))) - (sb-kernel:%make-lisp-obj page-addr) - (sb-kernel:%make-lisp-obj (+ page-addr sb-vm:gencgc-card-bytes))) - (assert aok) ; page should have nothing but a foo and the conses - - (change-foo-layout foo) - - ;; Assert that we didn't accidentally copy the header word of the layout, - ;; which would place it in generation 1 (and probably break other parts of GC) - (assert (= (sb-kernel:generation-of (sb-kernel:%instance-layout foo)) 0)) - - ;; And the page with FOO must have gotten touched - (assert (not (logbitp 3 (slot (deref sb-vm::page-table page) 'sb-vm::flags)))) - - ;; It requires *two* GCs, not one, to cause this bug. - ;; The first GC sees that the page with the FOO on it was touched, - ;; and so GC is required to scavenge the whole page. - ;; This scavenge pass enlivens the wonky layout that we created, - ;; but it INCORRECTLY would re-protect the page, because there did - ;; not seem to be any pointer to younger. (The conses are immediates, - ;; the FOO has no slots, and its compact header was opaque) - (gc) - #+nil - (format t "~&page ~d: wp=~a~%" - page - (logbitp 3 (slot (deref sb-vm::page-table page) 'sb-vm::flags))) - - ;; This GC would fail in the verify step because it trashes the apparently - ;; orphaned layout, which actually does have a referer. - (gc))) diff --git a/tests/gc.impure.lisp b/tests/gc.impure.lisp index 85cc98010e..007990427d 100644 --- a/tests/gc.impure.lisp +++ b/tests/gc.impure.lisp @@ -35,22 +35,7 @@ (assert (= (aref a 4) 18)) ;; broken cells are the cons, string, bignum, hash-table, plus one NIL ;; cell that was never assigned into - (assert (= (count nil *weak-vect*) 5)))) - -;;; Make sure MAP-REFERENCING-OBJECTS doesn't spuriously treat raw bits as -;;; potential pointers. Also make sure it sees the SYMBOL-INFO slot. -(defstruct afoo (slot nil :type sb-ext:word)) -(defvar *afoo* (make-afoo :slot (sb-kernel:get-lisp-obj-address '*posix-argv*))) -(with-test (:name :map-referencing-objs) - (sb-vm::map-referencing-objects (lambda (x) (assert (not (typep x 'afoo)))) - :dynamic '*posix-argv*) - (let ((v (sb-kernel:symbol-info 'satisfies)) referers) - (sb-vm::map-referencing-objects (lambda (referer) (push referer referers)) - #+gencgc :dynamic #-gencgc :static v) - #+immobile-space - (sb-vm::map-referencing-objects (lambda (referer) (push referer referers)) - :immobile v) - (assert (member 'satisfies referers)))) + *weak-vect*)) ;; Assert something about *CURRENT-THREAD* seeing objects that it just consed. (with-test (:name :m-a-o-threadlocally-precise @@ -122,16 +107,6 @@ ;; Really we could just assert /= 1000. (assert (< (length l) 15)))) -(defparameter *x* ()) - -(defun cons-madly () - (loop repeat 10000 do - (setq *x* (make-string 100000)))) - -;; check that WITHOUT-INTERRUPTS doesn't block the gc trigger -(with-test (:name :cons-madly-without-interrupts) - (sb-sys:without-interrupts (cons-madly))) - ;; check that WITHOUT-INTERRUPTS doesn't block SIG_STOP_FOR_GC (with-test (:name :gc-without-interrupts :skipped-on (not :sb-thread)) @@ -139,45 +114,54 @@ (let ((thread (sb-thread:make-thread (lambda () (sb-ext:gc))))) (loop while (sb-thread:thread-alive-p thread))))) -(with-test (:name :without-gcing) - (let ((gc-happend nil)) - (push (lambda () (setq gc-happend t)) sb-ext:*after-gc-hooks*) - - ;; check that WITHOUT-GCING defers explicit gc - (sb-sys:without-gcing - (gc) - (assert (not gc-happend))) - (assert gc-happend) - - ;; check that WITHOUT-GCING defers SIG_STOP_FOR_GC - #+sb-thread - (let ((in-without-gcing nil)) - (setq gc-happend nil) - (sb-thread:make-thread (lambda () - (loop while (not in-without-gcing)) - (sb-ext:gc))) - (sb-sys:without-gcing - (setq in-without-gcing t) - (sleep 3) - (assert (not gc-happend))) - ;; give the hook time to run - (sleep 1) - (assert gc-happend)))) - +(defglobal *some-object-handles* nil) +(defun make-some-objects () + (declare (notinline format)) + (let* ((string-one (format nil "~a~a~a" "pot" "ayt" "o")) + (string-two (concatenate 'string "two " string-one)) + (afunction + (let (#+immobile-space (sb-c::*compile-to-memory-space* :dynamic)) + (compile nil `(sb-int:named-lambda ,string-two (x) (coerce x 'float)))))) + (setq *some-object-handles* + (list (sb-kernel:get-lisp-obj-address afunction) + (sb-kernel:get-lisp-obj-address string-one) + (sb-kernel:get-lisp-obj-address string-two))))) +#+gencgc +(with-test (:name :pin-all-code-with-gc-enabled + :skipped-on :interpreter) + (gc) + #+sb-thread (sb-thread:join-thread (sb-thread:make-thread #'make-some-objects)) + #-sb-thread (progn (make-some-objects) (sb-sys:scrub-control-stack)) + (sb-sys:with-code-pages-pinned (:dynamic) (gc)) + ;; this should not fail to find FUN at its old address + (let ((fun (sb-kernel:make-lisp-obj (first *some-object-handles*)))) + ;; To prove that _some_ things moved in memory, + ;; assert that we don't see the arbitrary string at its old address. + (multiple-value-bind (thing existsp) + (sb-kernel:make-lisp-obj (second *some-object-handles*) nil) + (assert (or (not existsp) (not (typep thing '(string 7)))))) + ;; this should similarly fail- STRING-TWO was transitively reachable but movable + (multiple-value-bind (obj validp) (sb-kernel:make-lisp-obj (third *some-object-handles*) nil) + (if validp + (warn "Weird: obj=~s" obj))) + ;; (assert (not (nth-value 1 (sb-kernel:make-lisp-obj (third *some-object-handles*) nil)))) + (assert (string= (sb-kernel:%simple-fun-name fun) "two potayto")))) -#+immobile-space (with-test (:name :generation-of-fdefn) - ;; generation-of broke when fdefns stopped storing a generation in word 0 - (assert (= (sb-kernel:generation-of (sb-kernel::find-fdefn 'car)) - sb-vm:+pseudo-static-generation+))) + ;; GENERATION-OF broke when fdefns stopped storing a generation in word 0. + ;; Normally we expect to see SB-VM:+PSEUDO-STATIC-GENERATION+ + ;; but allow for varied definition of CORE_PAGE_GENERATION. + (assert (= (sb-kernel:generation-of (sb-int:find-fdefn 'car)) + (sb-kernel:generation-of #'car)))) (with-test (:name :static-fdefn-space) (sb-int:dovector (name sb-vm:+static-fdefns+) - (assert (eq (sb-ext:heap-allocated-p (sb-kernel::find-fdefn name)) + (assert (eq (sb-ext:heap-allocated-p (sb-int:find-fdefn name)) (or #+immobile-code :immobile :static))))) ;;; SB-EXT:GENERATION-* accessors returned bogus values for generation > 0 -(with-test (:name :bug-529014 :skipped-on (not :gencgc)) +#+gencgc ; sb-ext: symbol was removed for cheneygc +(with-test (:name :bug-529014) (loop for i from 0 to sb-vm:+pseudo-static-generation+ do (assert (= (sb-ext:generation-bytes-consed-between-gcs i) (truncate (sb-ext:bytes-consed-between-gcs) @@ -219,12 +203,13 @@ :skipped-on :cheneygc) ;; The interpreters (both sb-eval and sb-fasteval) special-case ;; WITH-PINNED-OBJECTS as a "special form", because the x86oid - ;; version of WITH-PINNED-OBJECTS uses black magic that isn't - ;; supportable outside of the compiler. The non-x86oid versions of - ;; WITH-PINNED-OBJECTS don't use black magic, but are overridden - ;; anyway. But the special-case logic was, historically broken, and - ;; this affects all gencgc targets (cheneygc isn't affected because - ;; cheneygc WITH-PINNED-OBJECTS devolves to WITHOUT-GC>ING). + ;; version of WITH-PINNED-OBJECTS uses special functionality that + ;; isn't supportable outside of the compiler. The non-x86oid + ;; versions of WITH-PINNED-OBJECTS don't use this special + ;; functionality, but are overridden anyway. But the special-case + ;; logic was, historically broken, and this affects all gencgc + ;; targets (cheneygc isn't affected because cheneygc + ;; WITH-PINNED-OBJECTS devolves to WITHOUT-GCING). ;; ;; Our basic approach is to allocate some kind of object and stuff ;; it where it doesn't need to be on the control stack. We then pin @@ -242,15 +227,17 @@ #+gencgc (defun ensure-code/data-separation () (let* ((n-bits (+ sb-vm:next-free-page 10)) - (code-bits (make-array n-bits :element-type 'bit)) - (data-bits (make-array n-bits :element-type 'bit)) + (code-bits (make-array n-bits :element-type 'bit :initial-element 0)) + (data-bits (make-array n-bits :element-type 'bit :initial-element 0)) (total-code-size 0)) (sb-vm:map-allocated-objects (lambda (obj type size) (declare ((and fixnum (integer 1)) size)) ;; M-A-O disables GC, therefore GET-LISP-OBJ-ADDRESS is safe (let ((obj-addr (sb-kernel:get-lisp-obj-address obj)) - (array (cond ((= type sb-vm:code-header-widetag) + (array (cond ((member type `(,sb-vm:code-header-widetag + #+compact-instance-header + ,sb-vm:funcallable-instance-widetag)) (incf total-code-size size) code-bits) (t @@ -266,7 +253,7 @@ :dynamic) (assert (not (find 1 (bit-and code-bits data-bits)))) (let* ((code-bytes-consumed - (* (count 1 code-bits) sb-vm:gencgc-card-bytes)) + (* (count 1 code-bits) sb-vm:gencgc-page-bytes)) (waste (- total-code-size code-bytes-consumed))) ;; This should be true for all platforms. @@ -286,43 +273,10 @@ (assert (not (sb-kernel:immobile-space-addr-p (+ sb-vm:fixedobj-space-start sb-vm:fixedobj-space-size - sb-vm:varyobj-space-size))))) - -;;; After each iteration of FOO there are a few pinned conses. -;;; On alternate GC cycles, those get promoted to generation 1. -;;; When the logic for page-spanning-object zeroing incorrectly decreased -;;; the upper bound on bytes used for partially pinned pages, it caused -;;; an accumulation of pages in generation 1 each with 2 objects' worth -;;; of bytes, and the remainder waste. Because the waste was not accounted -;;; for, it did not trigger GC enough to avoid heap exhaustion. -(with-test (:name :smallobj-auto-gc-trigger) - ;; Ensure that these are compiled functions because the interpreter - ;; would make lots of objects of various sizes which is insufficient - ;; to provoke the bug. - (setf (symbol-function 'foo) - (compile nil '(lambda () (list 1 2)))) - ;; 500 million iterations of this loop seems to be reliable enough - ;; to show that GC happens. - (setf (symbol-function 'callfoo) - (compile nil '(lambda () (loop repeat 500000000 do (foo))))) - (funcall 'callfoo)) - -;;; Pseudo-static large objects should retain the single-object flag -#+gencgc ; PSEUDO-STATIC-GENERATION etc don't exist for cheneygc -(with-test (:name :pseudostatic-large-objects) - (sb-vm:map-allocated-objects - (lambda (obj type size) - (declare (ignore type size)) - (when (>= (sb-vm::primitive-object-size obj) (* 4 sb-vm:gencgc-card-bytes)) - (let* ((addr (sb-kernel:get-lisp-obj-address obj)) - (pte (deref sb-vm:page-table (sb-vm:find-page-index addr)))) - (when (eq (slot pte 'sb-vm::gen) sb-vm:+pseudo-static-generation+) - (let* ((flags (slot pte 'sb-vm::flags)) - (type (ldb (byte 5 (+ #+big-endian 3)) flags))) - (assert (logbitp 4 type))))))) - :all)) - -(with-test (:name :unique-code-serialno) + sb-vm:alien-linkage-table-space-size + sb-vm:text-space-size))))) + +(with-test (:name :unique-code-serialno :skipped-on :interpreter) (let ((a (make-array 100000 :element-type 'bit :initial-element 0))) (sb-vm:map-allocated-objects (lambda (obj type size) @@ -334,32 +288,22 @@ (setf (aref a serial) 1)))) :all))) -(defvar *foo*) -#+gencgc -(with-test (:name (sb-ext:search-roots :simple-fun)) - ;; Tracing a path to a simple fun wasn't working at some point - ;; because of failure to employ fun_code_header in the right place. - (setq *foo* (compile nil '(lambda () 42))) - (let ((wp (sb-ext:make-weak-pointer *foo*))) - (assert (sb-ext:search-roots wp :criterion :oldest :print nil)))) - -#+gencgc -(with-test (:name (sb-ext:search-roots :ignore-immediate)) - (sb-ext:search-roots (make-weak-pointer 48) :gc t :print nil)) - -#+sb-thread -(with-test (:name :concurrently-alloc-code) - (let ((gc-thread - (sb-thread:make-thread - (let ((stop (+ (get-internal-real-time) - internal-time-units-per-second))) - (lambda () - (loop while (<= (get-internal-real-time) stop) - do (gc) (sleep 0))))))) - (loop (compile nil `(lambda () (print 20))) - (unless (sb-thread:thread-alive-p gc-thread) - (return))) - (sb-thread:join-thread gc-thread))) +(defun parse-address-range (line) + ;; I hope nothing preceding the match of "-" could be a false positive. + ;; If there is, I suspect we should parse the legend that contains + ;; "REGION TYPE START - END" to determine the column + ;; with a #\- which appears consistently in the same place on each following line. + (let ((separator (position #\- line))) + (assert separator) + (let* ((start separator)) + (loop (if (digit-char-p (char line (1- start)) 16) (decf start) (return))) + (values (parse-integer line :start start :end separator :radix 16) + (multiple-value-bind (value end) + (parse-integer line :start (1+ separator) :radix 16 :junk-allowed t) + (assert (and (> end (+ separator 3)) + (or (= end (length line)) + (char= (char line end) #\space)))) + value))))) (defun get-shared-library-maps () (let (result) @@ -383,14 +327,11 @@ (assert (search "REGION TYPE" (read-line s))) (loop (let ((line (read-line s))) (when (zerop (length line)) (return)) + ;; Look for lines that look like + ;; "{mumble} 7fff646c8000-7fff646ca000 {mumble}.dylib" (when (search ".dylib" line) - (let ((c (search "00-00" line))) - (assert c) - (let ((start (parse-integer line :start (+ c 2 (- 16)) :radix 16 - :junk-allowed t)) - (end (parse-integer line :start (+ c 3) :radix 16 - :junk-allowed t))) - (push `(,start . ,end) result))))))) + (multiple-value-bind (start end) (parse-address-range line) + (push `(,start . ,end) result)))))) (process-wait p)) result)) @@ -399,7 +340,8 @@ ;;; Verify that it works fine while invoking GC in another thread ;;; despite removal of the mysterious WITHOUT-GCING. #+sb-thread -(with-test (:name :sap-foreign-symbol-no-deadlock) +(with-test (:name :sap-foreign-symbol-no-deadlock + :skipped-on :interpreter) ;; needlessly slow when interpreted (let* ((worker-thread (sb-thread:make-thread (lambda (ranges) @@ -409,6 +351,7 @@ (prevsym "") (nsyms 0)) (loop for addr from start to end by 8 + repeat 100 do (let ((sym (sb-sys:sap-foreign-symbol (sb-sys:int-sap addr)))) (when (and sym (string/= sym prevsym)) (incf nsyms) @@ -419,18 +362,146 @@ (gc-thread (sb-thread:make-thread (lambda () - (loop while working do (gc) (sleep .001)))))) + (loop while working do (gc) (sleep .01)))))) (sb-thread:join-thread worker-thread) (setq working nil) (sb-thread:join-thread gc-thread))) -(with-test (:name :no-conses-on-large-object-pages) - (let* ((fun (checked-compile '(lambda (&rest params) params))) - (list (make-list #+gencgc (/ sb-vm:large-object-size - (sb-vm::primitive-object-size '(1)) - 1/2) - #-gencgc 16384)) - (rest (apply fun list))) - (sb-sys:with-pinned-objects (rest) - (sb-ext:gc :full t) - (assert (and (equal list rest) t))))) +;;; This loop doesn't work for #+use-cons-region (it will run forever) +;;; because you can't hit the end of a page. Also, it's not clear that it should +;;; ever have worked, because the check at the bottom of lisp_alloc() for whether +;;; we're near the end of a page will discard the last few objects in favor of +;;; returning a brand new region. I guess as long as the inline allocator is +;;; always used, it's fine. But the inline code wasn't always used on x86. +;;; So how did that work? +(defun use-up-thread-region () + ;; cons until the thread-local allocation buffer uses up a page + (loop + (let* ((c (cons 1 2)) + (end (+ (sb-kernel:get-lisp-obj-address c) + (- sb-vm:list-pointer-lowtag) + (* 2 sb-vm:n-word-bytes)))) + (when (zerop (logand end (1- sb-vm:gencgc-page-bytes))) + (return))))) +(defglobal *go* nil) + +#+sb-thread +(with-test (:name :c-call-save-p :skipped-on (or :interpreter + :use-cons-region)) + ;; Surely there's a better way to assert that registers get onto the stack + ;; (so they can be seen by GC) than by random hammering on (LIST (LIST ...)). + ;; This should probably be in gc-testlib.c. Or better yet: get rid of #+sb-safepoint + ;; for #+win32, and store the machine context the same as for #-sb-safepoint. + (let* ((fun (compile nil '(lambda (a b c d e f g h i j k l m) + (declare (optimize (sb-c::alien-funcall-saves-fp-and-pc 0))) + (setq *go* t) + #+win32 + (alien-funcall (extern-alien "Sleep" (function void int)) 300) + #-win32 + (alien-funcall (extern-alien "sb_nanosleep" (function void int int)) 0 300000000) + (values a b c d e f g h i j k l m)))) + (thr (sb-thread:make-thread (lambda () + (let ((args #1=(list (LIST 'A) (LIST 'B) (LIST 'C) + (LIST 'D) (LIST 'E) (LIST 'F) (LIST 'G) + (LIST 'H) (LIST 'I) (LIST 'J) (LIST 'K) + (LIST 'L) (LIST 'M)))) + (use-up-thread-region) + (apply fun + args)))))) + (loop (sb-thread:barrier (:read)) + (if *go* (return)) + (sleep .1)) + (gc) + (assert (equal (multiple-value-list (sb-thread:join-thread thr)) #1#)))) + +#+gencgc +(progn +(defun code-iterator (how) + (let ((n 0) (tot-bytes 0)) + (sb-int:dx-flet ((visit (obj type size) + (declare (ignore obj)) + (when (= type sb-vm:code-header-widetag) + (incf n) + (incf tot-bytes size)))) + (ecase how + (:slow (sb-vm:map-allocated-objects #'visit :dynamic)) + (:fast (sb-vm::walk-dynamic-space #'visit #x7f 3 3))) + (values n tot-bytes)))) +(compile 'code-iterator) + +(with-test (:name :code-iteration-fast) + (sb-int:binding* (((slow-n slow-bytes) (code-iterator :slow)) + ((fast-n fast-bytes) (code-iterator :fast))) + ;; Fast should be 20x to 50x faster than slow, but that's kinda sensitive + ;; to the machine and can't be reliably asserted. + (assert (= slow-n fast-n)) + (assert (= slow-bytes fast-bytes))))) + +(defglobal *wp-for-signal-handler-gc-test* nil) +#+(and gencgc unix sb-thread) +(with-test (:name :signal-handler-gc-test) + (sb-thread:join-thread + (sb-thread:make-thread + (lambda () + (let ((foo (make-symbol "hey"))) + (setf *wp-for-signal-handler-gc-test* (make-weak-pointer foo)) + (sb-sys:enable-interrupt + 23 + (lambda (&rest x) (declare (ignore x)) (constantly foo))))))) + (sb-ext:gc :gen 7) + ;; If fullcgc fails to see the closure that is installed as a signal handler + ;; (actually a closure around a closure) then the weak pointer won't survive. + ;; Was broken in https://sourceforge.net/p/sbcl/sbcl/ci/04296434 + (assert (weak-pointer-value *wp-for-signal-handler-gc-test*))) + +;;; We can be certain that the marked status pertains to exactly one +;;; object by ensuring that it can not share pages with other objects. +#+gencgc (defvar *vvv* (make-array + (/ sb-vm:large-object-size sb-vm:n-word-bytes))) +(gc) +#+gencgc +(with-test (:name :page-protected-p :broken-on :x86 + :fails-on (and :big-endian :ppc64)) + (if (= (sb-kernel:generation-of *vvv*) 0) (gc)) + (assert (= (sb-kernel:generation-of *vvv*) 1)) + (assert (sb-kernel:page-protected-p *vvv*)) + (let ((marks (sb-kernel:object-card-marks *vvv*))) + (assert (not (find 1 marks)))) + (setf (svref *vvv* (/ sb-vm:gencgc-card-bytes sb-vm:n-word-bytes)) + (gensym)) + (let ((marks (sb-kernel:object-card-marks *vvv*))) + (assert (eql (bit marks 1) 1))) ; should be marked + (gc) + ;; Depending whether the gensym was promoted (it's now in gen1) + ;; the vector is or isn't marked on one of its cards. + (let ((marks (sb-kernel:object-card-marks *vvv*))) + (ecase (sb-kernel:generation-of + (svref *vvv* (/ sb-vm:gencgc-card-bytes sb-vm:n-word-bytes))) + (0 + (assert (eql (bit marks 1) 1))) ; should be marked + (1 + (assert (eql (bit marks 1) 0))))) ; should not be marked + (setf (svref *vvv* (/ sb-vm:gencgc-card-bytes sb-vm:n-word-bytes)) 0) + (gc) + (let ((marks (sb-kernel:object-card-marks *vvv*))) + (assert (not (find 1 marks))))) + +(with-test (:name :%shrink-vector) + (let ((v (make-array 25 :initial-element 'yikes))) + (sb-sys:with-pinned-objects (v) + ;; Can't call VECTOR-SAP on simple-vector. + ;; (Honestly I don't see what purpose that limitation serves) + (let ((sap (sb-sys:sap+ (sb-sys:int-sap (sb-kernel:get-lisp-obj-address v)) + (- (ash sb-vm:vector-data-offset sb-vm:word-shift) + sb-vm:other-pointer-lowtag)))) + (sb-impl::%shrink-vector v 9) + (loop for i from 10 to 24 + do + (assert (= (sb-sys:sap-ref-word sap (ash i sb-vm:word-shift))))))))) + +(with-test (:name :rospace-strings + :fails-on :darwin-jit) + (let ((err (handler-case (setf (char (opaque-identity (symbol-name '*readtable*)) 0) #\*) + (sb-sys:memory-fault-error (c) + (write-to-string c :escape nil))))) + (assert (search "modify a read-only object" err)))) diff --git a/tests/genheaders.test.sh b/tests/genheaders.test.sh new file mode 100755 index 0000000000..1fb26d689f --- /dev/null +++ b/tests/genheaders.test.sh @@ -0,0 +1,36 @@ +#!/bin/sh + +set -e +export TEST_BASEDIR=${TMPDIR:-/tmp} +. ./subr.sh +create_test_subdirectory + +run_sbcl <<EOF +;; technically this is "skipped" if not fasteval, but we don't have "skipped" +;; as a status code from shell tests. +(unless (and (find-package "SB-INTERPRETER") + ;; host with #+sb-devel hangs, not sure why + (not (member :sb-devel *features*))) + ;; exit normally so that the shell doesn't exit abnormally (as per "set -e") + (exit)) +(setq *evaluator-mode* :interpret) +(defvar *sbcl-local-target-features-file* "../local-target-features.lisp-expr") +(load "../src/cold/shared.lisp") +(load "../src/cold/set-up-cold-packages.lisp") +(load "../tools-for-build/corefile.lisp") +(in-package "SB-COLD") +(defvar *target-sbcl-version* (read-from-file "../version.lisp-expr")) +(in-host-compilation-mode + (lambda (&aux (sb-xc:*features* (cons :c-headers-only sb-xc:*features*))) + (do-stems-and-flags (stem flags 1) + (when (member :c-headers flags) + (handler-bind ((style-warning (function muffle-warning))) + (load (merge-pathnames (stem-remap-target stem) + (make-pathname :directory '(:relative :up) :type "lisp")))))) + (load "../src/compiler/generic/genesis.lisp"))) +(genesis :c-header-dir-name "$TEST_DIRECTORY/" :verbose t) +(assert (probe-file "$TEST_DIRECTORY/gc-tables.h")) +(dolist (pathname (directory "$TEST_DIRECTORY/*.*")) (delete-file pathname)) +EOF + +exit $EXIT_TEST_WIN diff --git a/tests/genmakefile.lisp b/tests/genmakefile.lisp new file mode 100644 index 0000000000..2ccbc57662 --- /dev/null +++ b/tests/genmakefile.lisp @@ -0,0 +1,15 @@ +;;; +;;; invocation: "$SBCL --script genmakefile.lisp >Makefile" +;;; +(let ((files (append (directory "*.test.sh") + (directory "*.*pure*.lisp")))) + (format t "~%all:") + (dolist (file (mapcar 'pathname-name files)) + (format t " \\~% $(LOGDIR)/~a.log" file)) + (terpri) + (terpri) + (dolist (file files) + (let ((in (format nil "~a.~a" (pathname-name file) (pathname-type file))) + (out (format nil "$(LOGDIR)/~a.log" (pathname-name file)))) + (format t "~a: ~a~%~a./run-tests.sh ~a >~a 2>&1~%" + out in #\tab in out)))) diff --git a/tests/gethash-concurrency.impure.lisp b/tests/gethash-concurrency.impure.lisp index 82ef052c0f..68adca249f 100644 --- a/tests/gethash-concurrency.impure.lisp +++ b/tests/gethash-concurrency.impure.lisp @@ -1,6 +1,6 @@ ;;; HASH TABLES -#-sb-thread (sb-ext:exit :code 104) +#-sb-thread (invoke-restart 'run-tests::skip-file) (use-package "SB-THREAD") (use-package "SB-SYS") @@ -71,6 +71,13 @@ (sleep 10) (mapc #'terminate-thread threads)))) + +;;; The new logic for concurrent GETHASH allows multiple threads each to decide to +;;; invoke a GC-provoked rehash, but since we do not want concurrent writers, +;;; only one thread actually rehashes and the other(s) perform linear search. +;;; This is strictly less work than multiple rehashes and should give improved throughput +;;; since no thread waits on rehash. The count of number of linear searches performed +;;; is no longer collected unless explicitly compiled in. (defmacro with-test-setup ((array (table constructor)) &body body) ;; Using fixnums as hash-table keys does not engender a thorough enough test ;; as they will not cause the table to need rehash due to GC. @@ -84,6 +91,7 @@ (let ((v (sb-impl::hash-table-index-vector ,table))) (setf (sb-impl::hash-table-index-vector ,table) (subseq v 0 (/ (length v) 2))))) ,@body + #+hash-table-metrics (format t "~&::: INFO: Rehash count = ~D~%" (sb-impl::hash-table-n-rehash+find ,table)))) @@ -163,6 +171,7 @@ :name "collector")))) (unwind-protect (sleep 2.5) (mapc #'terminate-thread threads)) + #+hash-table-metrics (format t "~&::: INFO: GETHASH count = ~D = ~D, lsearch=~d~%" actions (reduce #'+ actions) diff --git a/tests/hash.impure.lisp b/tests/hash-2.pure.lisp similarity index 93% rename from tests/hash.impure.lisp rename to tests/hash-2.pure.lisp index 12331093e9..45c5c1a3c7 100644 --- a/tests/hash.impure.lisp +++ b/tests/hash-2.pure.lisp @@ -524,4 +524,40 @@ (assert (= empty (psxhash (make-rslotty :cdf #c(0d0 -0d0))))) (assert (= empty (psxhash (make-rslotty :cdf #c(-0d0 0d0))))))) -;;; success +(defun my= (a b) (= a b)) +(defun fixnum-hash (x) (sxhash (the fixnum x))) +(defun fixnum-hash-worse (x) (logand (sxhash (the fixnum x)) 7)) +(define-hash-table-test my= fixnum-hash) + +(with-test (:name :hash-fun-is-function-designator) + ;; Users shouldn't write this baroque expression to make an EQL table. + (assert-error (make-hash-table :hash-function nil)) + ;; nor this + (assert-error (make-hash-table :test #'eql :hash-function nil)) + ;; :TEST, if unknown, does not imply a hash function + ;; even when it looks like it could. + (assert-error (make-hash-table :test #'=)) + ;; and of course this doesn't work either because the preceding doesn't + (assert-error (make-hash-table :test #'= :hash-function nil)) + ;; Try user functions + (let ((h (make-hash-table :test 'my=))) + (assert (eq (sb-impl::hash-table-hash-fun h) #'fixnum-hash))) + (let ((h (make-hash-table :test 'my= :hash-function 'fixnum-hash-worse))) + (assert (eq (sb-impl::hash-table-hash-fun h) #'fixnum-hash-worse))) + (let ((h (make-hash-table :test 'my= :hash-function #'fixnum-hash-worse))) + (assert (eq (sb-impl::hash-table-hash-fun h) #'fixnum-hash-worse))) + (assert-error (make-hash-table :test 'my= :hash-function nil))) ; no good + + +(with-test (:name :psxhash-large-floats) + (flet ((test (integer) + (assert (= (sb-int:psxhash (float integer 1d0)) + (sb-int:psxhash (truncate (float integer 1d0))))) + (assert (= (sb-int:psxhash (float integer)) + (sb-int:psxhash (truncate (float integer))))))) + (loop for i from 80 to 100 by 4 + do (test (expt 2 i)) + (test (1+ (expt 2 i))) + (test (1- (expt 2 i))) + (test (- (expt 2 i) (random (expt 2 i)))) + (test (+ (expt 2 i) (random (expt 2 i))))))) diff --git a/tests/hash-cache.impure.lisp b/tests/hash-cache.pure.lisp similarity index 78% rename from tests/hash-cache.impure.lisp rename to tests/hash-cache.pure.lisp index ec76c150fc..5f956a4e12 100644 --- a/tests/hash-cache.impure.lisp +++ b/tests/hash-cache.pure.lisp @@ -1,6 +1,7 @@ ;;; FIXME: Since timeouts do not work on Windows this would loop ;;; forever. -(with-test (:name (:hash-cache :interrupt) :skipped-on :win32) +(with-test (:name (:hash-cache :interrupt) + :skipped-on (or :win32 :sb-safepoint)) (let* ((type1 (random-type 500)) (type2 (random-type 500)) (wanted (subtypep type1 type2))) @@ -9,7 +10,7 @@ (sb-ext:schedule-timer (sb-ext:make-timer (lambda () (assert (eq wanted (subtypep type1 type2))) - (return-from foo))) + (return-from foo))) 0.05) (loop (assert (eq wanted (subtypep type1 type2)))))))) diff --git a/tests/hash-custom-test.pure.lisp b/tests/hash-custom-test.pure.lisp new file mode 100644 index 0000000000..e4413fe784 --- /dev/null +++ b/tests/hash-custom-test.pure.lisp @@ -0,0 +1,13 @@ +(with-test (:name (:hash-table :custom-hash-function :closure)) + (flet ((equal-p (left right) + (equal left right)) + (hash (item) + (sxhash item))) + (let ((table (make-hash-table :test #'equal-p + :hash-function #'hash))) + (loop for i from 0 to 100 + do (progn + (setf (gethash i table) i) + (assert (= (gethash i table) i)))) + (assert (= (hash-table-count table) 101)) + (assert (eq (hash-table-test table) #'equal-p))))) diff --git a/tests/hash-table.impure.lisp b/tests/hash-table.impure.lisp index 79d9a415c1..3cf66e8a51 100644 --- a/tests/hash-table.impure.lisp +++ b/tests/hash-table.impure.lisp @@ -3,9 +3,37 @@ ;;; Keep moving everything that can move during each GC #+gencgc (setf (generation-number-of-gcs-before-promotion 0) 1000000) +;;; Check for GC invariant loss during weak table creation. +;;; This didn't always fail, but might have, and now shouldn't. +(defglobal *number-of-weak-tables* 0) +(defun make-weak-key-table () (make-hash-table :weakness :key)) +(defun something-useless (x) (list x)) +(defun weak-table-allocation-test () + (let ((thread + (sb-thread:make-thread + (lambda () + (loop + (sleep .0001) + (gc) + (sb-thread:barrier (:read)) + (when (> *number-of-weak-tables* 1000) (return))))))) + (loop repeat 1001 do + (something-useless (make-weak-key-table)) + (incf *number-of-weak-tables*) + (sb-thread:barrier (:write))) + (sb-thread:join-thread thread))) +;;; Interpreted code is probably too slow to be useful in this test +(compile 'weak-table-allocation-test) + +(with-test (:name :weak-table-gc-invariant :skipped-on (not :sb-thread)) + (weak-table-allocation-test)) + +(defun vector-flag-bits (v) + (logand (ash (sb-kernel:get-header-data v) (- sb-vm:array-flags-data-position)) #xFF)) + (defun is-address-sensitive (tbl) - (let ((data (sb-kernel:get-header-data (sb-impl::hash-table-pairs tbl)))) - (logtest data sb-vm:vector-addr-hashing-subtype))) + (logtest (vector-flag-bits (sb-impl::hash-table-pairs tbl)) + sb-vm:vector-addr-hashing-flag)) (with-test (:name (hash-table :eql-hash-symbol-not-eq-based)) ;; If you ask for #'EQ as the test, then everything is address-sensitive, @@ -13,7 +41,8 @@ (let ((ht (make-hash-table :test 'eq))) (setf (gethash (make-symbol "GOO") ht) 1) (assert (is-address-sensitive ht))) - (dolist (test '(eql equal equalp)) + ;; EQUAL tables don't use SYMBOL-HASH + (dolist (test '(eql equalp)) (let ((ht (make-hash-table :test test))) (setf (gethash (make-symbol "GOO") ht) 1) (assert (not (is-address-sensitive ht)))))) @@ -25,7 +54,8 @@ (let ((ht (make-hash-table :test test))) (setf (gethash (make-instance 'ship) ht) 1) (assert (is-address-sensitive ht)))) - (dolist (test '(equal equalp)) + ;; EQUAL tables don't use INSTANCES-SXHASH + (dolist (test '(equalp)) (let ((ht (make-hash-table :test test))) (setf (gethash (make-instance 'ship) ht) 1) (assert (not (is-address-sensitive ht)))))) @@ -52,9 +82,9 @@ (with-test (:name :gc-while-growing-weak-hash-table) (let ((h (make-hash-table :weakness :key))) (setq *gc-after-rehash-me* h) - (dotimes (i 14) (setf (gethash (list (gensym)) h) i)) + (dotimes (i 50) (setf (gethash (list (gensym)) h) i)) (setf (gethash (cons 1 2) h) 'foolz)) - (assert (= *rehash+gc-count* 1))) + (assert (>= *rehash+gc-count* 10))) (defstruct this x) (defstruct that x) @@ -74,3 +104,136 @@ ;; but let's not be too sensitive to the exact bin count in use. ;; It's a heck of a lot better than everything in 1 bin. (assert (> bins-used 40))))) + +(with-test (:name :rehash-no-spurious-address-sensitivity) + (let ((h (make-hash-table :test 'eq))) + (dotimes (i 100) + (setf (gethash i h) (- i))) + (assert (= (vector-flag-bits (sb-impl::hash-table-pairs h)) + sb-vm:vector-hashing-flag)))) + +(defmacro kv-vector-needs-rehash (x) `(svref ,x 1)) +;;; EQL tables no longer get a hash vector, so the GC has to decide +;;; for itself whether key movement forces rehash. +;;; Let's make sure that works. +(with-test (:name :address-insensitive-eql-hash) + (let ((tbl (make-hash-table :size 20))) + (dotimes (i 5) + (let ((key (coerce i 'double-float))) + (setf (gethash key tbl) (sb-kernel:get-lisp-obj-address key))) + (let ((key (coerce i '(complex single-float)))) + (setf (gethash key tbl) (sb-kernel:get-lisp-obj-address key))) + (let ((key (make-symbol (make-string (1+ i) :initial-element #\a)))) + (setf (gethash key tbl) (sb-kernel:get-lisp-obj-address key)))) + (assert (= (vector-flag-bits (sb-impl::hash-table-pairs tbl)) + sb-vm:vector-hashing-flag)) ; noo address-based key + (let ((foo (cons 0 0))) + (setf (gethash foo tbl) foo) + (remhash foo tbl)) + ;; now we've added an address-based key (but removed it) + (assert (= (vector-flag-bits (sb-impl::hash-table-pairs tbl)) + (+ sb-vm:vector-addr-hashing-flag + sb-vm:vector-hashing-flag))) + (gc) + (let ((n-keys-moved 0)) + (maphash (lambda (key value) + (unless (= value (sb-kernel:get-lisp-obj-address key)) + (incf n-keys-moved))) + tbl) + (assert (plusp n-keys-moved)) + ;; keys were moved, the table is marked as address-based, + ;; but no key that moved forced a rehash + (assert (zerop (kv-vector-needs-rehash + (sb-impl::hash-table-pairs tbl))))) + ;; the vector type is unchanged + (assert (= (vector-flag-bits (sb-impl::hash-table-pairs tbl)) + (+ sb-vm:vector-addr-hashing-flag + sb-vm:vector-hashing-flag))) + (setf (gethash (cons 1 2) tbl) 'one) + (setf (gethash (cons 3 4) tbl) 'two) + (setf (gethash (cons 5 6) tbl) 'three) + (gc) + ;; now some key should have moved and forced a rehash + (assert (not (zerop (kv-vector-needs-rehash + (sb-impl::hash-table-pairs tbl))))) + ;; This next thing is impossible to test without some hacks - + ;; we want to see that the addr-hashing flag can be cleared + ;; if, on rehash, there is currently no address-sensitive key + ;; in the table. + ;; This could happen in the real world, but it's actually very + ;; difficult to construct an example because it requires controlling + ;; the addresses of objects. But the 'rehash' bit had to first get + ;; set, and then any key that could cause the bit to get set + ;; has to be removed, which means we had to have successfully found + ;; and removed address-sensitive keys despite having obsolete hashes. + ;; That could only happen by random chance. + ;; However, by stomping on a few keys, we can simulate it. + (let ((pairs (sb-impl::hash-table-pairs tbl))) + (loop for i from 2 below (length pairs) by 2 + when (consp (aref pairs i)) + do (setf (aref pairs i) i))) ; highly illegal! + ;; try to find an address-sensitive key + (assert (not (gethash '(foo) tbl))) + (assert (= (vector-flag-bits (sb-impl::hash-table-pairs tbl)) + ;; Table is no longer address-sensitive + sb-vm:vector-hashing-flag)))) + +(defun actually-address-sensitive-p (ht) + (let* ((hashfun (sb-impl::hash-table-hash-fun ht)) + (some-actually-address-sensitive-key)) + (maphash (lambda (key value) + (declare (ignore value)) + (multiple-value-bind (hash address-sensitive) + (funcall hashfun key) + (declare (ignore hash)) + (when address-sensitive + (setf some-actually-address-sensitive-key t)))) + ht) + some-actually-address-sensitive-key)) + +(with-test (:name :unsynchronized-clrhash-no-lock) + (let ((ht (make-hash-table))) + (setf (gethash 1 ht) 2) + (clrhash ht) + (assert (not (sb-impl::hash-table-%lock ht))))) + +;;; Prove that our completely assinine API with regard to locking works, +;;; which is to say, if the user explicitly locks an implicitly locked table, +;;; there is no "Recursive lock attempt" error. +;;; In general, we can't discern between a lock that preserves table invariants +;;; at the implementation level, or the user level. But I guess with "system" locks +;;; it's sort of OK because reentrance isn't really possible, and internally +;;; the table considers the lock to be a "system" lock. +(with-test (:name :weak-hash-table-with-explicit-lock) + (let ((h (make-hash-table :weakness :key))) + (with-locked-hash-table (h) (setf (gethash 'foo h) 1)))) + +(with-test (:name :hash-table-iterator-no-notes + :fails-on (:or :ppc :ppc64)) + (let ((f + (checked-compile + '(lambda (h) + (declare (optimize speed)) + (let ((n 0)) + (declare (fixnum n)) + ;; Silly test - count items, unrolling by 2 + (with-hash-table-iterator (iter h) + (loop + (let ((a (iter))) + (unless a (return))) + (let ((a (iter))) + (unless a + (incf n) + (return))) + (incf n 2))) + n)) + :allow-notes nil))) + ;; Test F + (maphash (lambda (classoid layout) + (declare (ignore layout)) + (let ((subclasses + (sb-kernel:classoid-subclasses classoid))) + (when (hash-table-p subclasses) + (assert (= (hash-table-count subclasses) + (funcall f subclasses)))))) + (sb-kernel:classoid-subclasses (sb-kernel:find-classoid 't))))) diff --git a/tests/hash.pure.lisp b/tests/hash.pure.lisp index 51caf5a447..4d2ff89213 100644 --- a/tests/hash.pure.lisp +++ b/tests/hash.pure.lisp @@ -31,6 +31,8 @@ (assert (/= (sxhash #*1010) (sxhash #*0101)))) ;;; This test supposes that no un-accounted-for consing occurs. +;;; But now that we have to two regions for allocation, it's not necessarily +;;; the case that any given allocation bumps the mixed-region free pointer. (with-test (:name :address-based-hash-counter :skipped-on :interpreter) ;; It doesn't particularly matter what ADDRESS-BASED-COUNTER-VAL returns, ;; but it's best to verify the assumption that each cons bumps the count @@ -38,8 +40,9 @@ ;; hashes. (let ((win 0) (n-trials 10) (prev (sb-int:address-based-counter-val))) (dotimes (i n-trials) - (declare (notinline cons)) ; it's flushable, but don't flush it - (cons 1 2) + (declare (notinline cons sb-sys:int-sap)) ; it's flushable, but don't flush it + #+use-cons-region (sb-sys:int-sap #xf00fa) ; 2 words in mixed-region + #-use-cons-region (cons 1 2) (let ((ptr (sb-int:address-based-counter-val))) (when (= ptr (1+ prev)) (incf win)) @@ -47,6 +50,58 @@ ;; GC could occur in here. Just check that 9 out of 10 trials succeed. (assert (>= win 9)))) +(with-test (:name (sxhash :bit-vector-sxhash-mask-to-length)) + (let ((bv (make-array 5 :element-type 'bit)) + (unsafely-set-bit + (compile nil + '(lambda (bv i val) + (declare (optimize (sb-c:insert-array-bounds-checks 0))) + (setf (bit bv i) val))))) + (replace bv '(1 0 1 1 1)) + (let ((hash (sxhash bv))) + ;; touch all bits of the first data word as well as the padding word + (loop for i from 5 below (* 2 sb-vm:n-word-bytes) + do (funcall unsafely-set-bit bv i 1) + (assert (eql (sxhash bv) hash)) + (funcall unsafely-set-bit bv i 0))))) + +(defvar *sbv* (make-array 512 :element-type 'bit)) +(defun sxhash-for-bv-test (test-bv) + (let ((underlying *sbv*) + (expected-hash (sxhash test-bv))) + ;; Currently %SXHASH-BIT-VECTOR can only operate on non-simple vectors + ;; if the displacement on bits aligns to a word boundary, + ;; or possibly on a byte boundary for some CPUs. + ;; Otherwise it just copies the non-simple vector as there's no point + ;; to exercising varying values of displaced-index-offet for that. + (loop for index-offset + from 0 by 8 repeat 25 + do (let ((unsimple-bv (make-array 300 + :element-type 'bit + :displaced-to underlying + :displaced-index-offset index-offset + :fill-pointer (length test-bv)))) + (flet ((check-unreplaced-bits (expect) + ;; make sure REPLACE didn't touch bits outside + ;; the expected range. This is a test of REPLACE + ;; more so than SXHASH, but is needed to establish + ;; that SXHASH of the nonsimple vector isn't + ;; looking at bits that it shouldn't. + (loop for i from 0 below index-offset + do (assert (= (bit underlying i) expect))) + (loop for i from (+ index-offset (length test-bv)) + below (length underlying) + do (assert (= (bit underlying i) expect))))) + (fill underlying 0) + (replace unsimple-bv test-bv) + (check-unreplaced-bits 0) + (assert (eql (sxhash unsimple-bv) expected-hash)) + (fill underlying 1) + (replace unsimple-bv test-bv) + (check-unreplaced-bits 1) + (assert (eql (sxhash unsimple-bv) expected-hash))))) + expected-hash)) + ;;; The value of SXHASH on bit-vectors of length a multiple of the word ;;; size didn't depend on the contents of the last word, specifically ;;; making it a constant for bit-vectors of length equal to the word @@ -63,11 +118,11 @@ (map-into v (lambda () (random 2))))) (randomize-v) - (let ((sxhash (sxhash v)) + (let ((sxhash (sxhash-for-bv-test v)) (random-bits-used 0)) (loop (randomize-v) - (when (/= (sxhash v) sxhash) + (when (/= (sxhash-for-bv-test v) sxhash) (return)) (incf random-bits-used length) (when (>= random-bits-used random-bits-to-use) @@ -91,13 +146,13 @@ repeat sb-vm:n-word-bits do (setf (aref v i) (random 2))))) (randomize-v) - (let ((sxhash (sxhash v))) + (let ((sxhash (sxhash-for-bv-test v))) (dotimes (i (ceiling random-bits-to-use sb-vm:n-word-bits) (error "SXHASH on bit-vectors of length ~a ~ does not depend on the final ~a bits." length sb-vm:n-word-bits)) (randomize-v) - (when (/= (sxhash v) sxhash) + (when (/= (sxhash-for-bv-test v) sxhash) (return))))))))) (with-test (:name :maphash-multiple-evaluation) @@ -159,7 +214,7 @@ (setf (gethash #\a tbl) 1) #+64-bit (setf (gethash 1.0f0 tbl) 1) ; single-float is a nonpointer (let ((data (sb-kernel:get-header-data (sb-impl::hash-table-pairs tbl)))) - (assert (not (logtest data sb-vm:vector-addr-hashing-subtype)))))) + (assert (not (logtest data sb-vm:vector-addr-hashing-flag)))))) (with-test (:name (hash-table :small-rehash-size)) (let ((ht (make-hash-table :rehash-size 2))) @@ -171,14 +226,15 @@ (with-test (:name (hash-table :custom-hashfun-with-standard-test)) (flet ((kv-flag-bits (ht) - (sb-kernel:get-header-data (sb-impl::hash-table-pairs ht)))) + (ash (sb-kernel:get-header-data (sb-impl::hash-table-pairs ht)) + (- sb-vm:array-flags-data-position)))) ;; verify that EQ hashing on symbols is address-sensitive (let ((h (make-hash-table :test 'eq))) (setf (gethash 'foo h) 1) - (assert (logtest (kv-flag-bits h) sb-vm:vector-addr-hashing-subtype))) + (assert (logtest (kv-flag-bits h) sb-vm:vector-addr-hashing-flag))) (let ((h (make-hash-table :test 'eq :hash-function 'sb-kernel:symbol-hash))) (setf (gethash 'foo h) 1) - (assert (not (logtest (kv-flag-bits h) sb-vm:vector-addr-hashing-subtype)))) + (assert (not (logtest (kv-flag-bits h) sb-vm:vector-addr-hashing-flag)))) ;; Verify that any standard hash-function on a function is address-sensitive, ;; but a custom hash function makes it not so. @@ -188,19 +244,21 @@ (dolist (test '(eq eql equal equalp)) (let ((h (make-hash-table :test test))) (setf (gethash #'car h) 1) - (assert (logtest (kv-flag-bits h) sb-vm:vector-addr-hashing-subtype))) + (assert (logtest (kv-flag-bits h) sb-vm:vector-addr-hashing-flag))) (let ((h (make-hash-table :test test :hash-function (lambda (x) (sb-kernel:%code-serialno (sb-kernel:fun-code-header x)))))) (setf (gethash #'car h) 1) - (assert (not (logtest (kv-flag-bits h) sb-vm:vector-addr-hashing-subtype))))))) + (assert (not (logtest (kv-flag-bits h) sb-vm:vector-addr-hashing-flag))))))) (defun hash-table-freelist (tbl) (sb-int:named-let chain ((index (sb-impl::hash-table-next-free-kv tbl))) (when (plusp index) (nconc (list index) - (chain (aref (sb-impl::hash-table-next-vector tbl) index)))))) + (if (< index + (sb-impl::kv-vector-high-water-mark (sb-impl::hash-table-pairs tbl))) + (chain (aref (sb-impl::hash-table-next-vector tbl) index))))))) (defvar *tbl* (make-hash-table :weakness :key)) @@ -219,6 +277,7 @@ ;; Ensure the values remain outside of the stack pointer for scrub-control-stack to work (declare (notinline f)) (f)) + (eval nil) (sb-sys:scrub-control-stack) (gc) ;; There were 20 items REMHASHed plus the freelist contains a pointer @@ -290,7 +349,7 @@ ;; and those objects have comparators that descend. ;; However, there are still some things hashed by address: (test-this-object 'equalp (make-weak-pointer "bleep")) - (test-this-object 'equalp (sb-kernel::find-fdefn 'cons)) + (test-this-object 'equalp (sb-int:find-fdefn 'cons)) (test-this-object 'equalp #'car) (test-this-object 'equalp (constantly 5)) (test-this-object 'equal (sb-sys:int-sap 0))) @@ -301,10 +360,160 @@ ;;; This affected the performance of TYPECASE. (with-test (:name :sxhash-on-layout) (dolist (x '(pathname cons array)) - (let ((l (sb-kernel:find-layout x))) - (assert (= (sxhash l) (sb-kernel::layout-clos-hash l)))))) + (let ((l (sb-kernel:wrapper-friend (sb-kernel:find-layout x)))) + (assert (= (sxhash l) (sb-kernel:layout-clos-hash l)))))) (with-test (:name :equalp-table-fixnum-equal-to-float) (let ((table (make-hash-table :test #'equalp))) (assert (eql (setf (gethash 3d0 table) 1) (gethash 3 table))))) + +(with-test (:name :transform-sxhash-string-and-bv) + (let ((f (compile + nil + '(lambda (x y) + (logxor (ash (sxhash (truly-the (or string null) x)) -3) + (sxhash (truly-the (or bit-vector null) y)))))) + (fdefn1 (sb-int:find-fdefn 'sb-kernel:%sxhash-string)) + (fdefn2 (sb-int:find-fdefn 'sb-kernel:%sxhash-bit-vector))) + (every (lambda (x) (member x `(,fdefn1 ,fdefn2))) + (ctu:find-code-constants f)))) + +(with-test (:name :sxhash-on-displaced-string + :fails-on :sbcl) + (let* ((adjustable-string + (make-array 100 :element-type 'character :adjustable t)) + (displaced-string + (make-array 50 :element-type 'character :displaced-to adjustable-string + :displaced-index-offset 19))) + (adjust-array adjustable-string 68) + (assert-error (aref displaced-string 0)) ; should not work + ;; This should fail, but instead it computes the hash of a string of + ;; length 0 which is what we turn displaced-string into after adjustable-string + ;; is changed to be too small to hold displaced-string. + ;; As a possible fix, we could distinguish between safe and unsafe code, + ;; never do the sxhash transforms in safe code, and have the full call to + ;; sxhash always check for "obsolete" strings. + ;; I would guess that all sorts of string transforms are similarly + ;; suspect in this edge case. + ;; On the one hand, this is undefined behavior as per CLHS: + ;; "If A is displaced to B, the consequences are unspecified if B is adjusted + ;; in such a way that it no longer has enough elements to satisfy A." + ;; But on the other, we always try to be maximally helpful, + ;; and it's extremely dubious that we're totally silent here. + ;; Also the same issue exists with bit-vectors. + (assert-error (sxhash displaced-string)))) + +(with-test (:name :array-psxhash-non-consing :skipped-on :interpreter) + (let ((a (make-array 1000 :element-type 'double-float + :initial-element (+ 0d0 #+(or arm64 x86-64) + 1d300)))) + (ctu:assert-no-consing (sb-int:psxhash a)))) + +(with-test (:name :array-psxhash) + (let ((table (make-hash-table :test 'equalp))) + (let ((x (vector 1.0d0 1.0d0)) + (y (make-array 2 :element-type 'double-float :initial-contents '(1.0d0 1.0d0)))) + (setf (gethash x table) t) + (assert (gethash y table))))) + + +#| +;;; Our SXHASH has kinda bad behavior on 64-bit fixnums. +;;; I wonder if we should try to hash fixnum better for users. +;;; Example: +* (dotimes (i 20) + (let ((a (+ sb-vm:dynamic-space-start (* i 32768)))) + (format t "~4d ~x ~b~%" i a (sxhash a)))) + 0 1000000000 1000010010001101110100101010000110101100010111010111001001010 + 1 1000008000 1000010010001101110100101010000110101100000111110111001001010 + 2 1000010000 1000010010001101110100101010000110101100110110010111001001010 + 3 1000018000 1000010010001101110100101010000110101100100110110111001001010 + 4 1000020000 1000010010001101110100101010000110101101010101010111001001010 + 5 1000028000 1000010010001101110100101010000110101101000101110111001001010 + 6 1000030000 1000010010001101110100101010000110101101110100010111001001010 + 7 1000038000 1000010010001101110100101010000110101101100100110111001001010 + 8 1000040000 1000010010001101110100101010000110101110010011010111001001010 + 9 1000048000 1000010010001101110100101010000110101110000011110111001001010 + 10 1000050000 1000010010001101110100101010000110101110110010010111001001010 + 11 1000058000 1000010010001101110100101010000110101110100010110111001001010 + 12 1000060000 1000010010001101110100101010000110101111010001010111001001010 + 13 1000068000 1000010010001101110100101010000110101111000001110111001001010 + 14 1000070000 1000010010001101110100101010000110101111110000010111001001010 + 15 1000078000 1000010010001101110100101010000110101111100000110111001001010 + 16 1000080000 1000010010001101110100101010000110101000011111010111001001010 + ... +|# +(with-test (:name :fixnum-hash-with-more-entropy) + (flet ((try (hasher) + (let (hashes) + (dotimes (i 20) + (let* ((a (+ #+64-bit sb-vm:dynamic-space-start + #-64-bit #xD7C83000 + (* i 32768))) + (hash (funcall hasher a))) + ;; (format t "~4d ~x ~v,'0b~%" i a sb-vm:n-word-bits hash) + (push hash hashes))) + ;; Try some 4-bit subsequences of the hashes + ;; as various positions and make sure that there + ;; are none that match for all inputs. + ;; For 64-bit machines, SXHASH yields complete overlap + ;; of all the test cases at various positions. + ;; 32-bit doesn't seem to suffer from this. + (dotimes (position (- sb-vm:n-fixnum-bits 4)) + (let ((field + (mapcar (lambda (x) (ldb (byte 4 position) x)) + hashes))) + ;; (print `(,position , (length (delete-duplicates field)))) + (when #-64-bit t #+64-bit (not (eq hasher 'sxhash)) + (assert (>= (length (remove-duplicates field)) 8)))))))) + (try 'sxhash) + (try 'sb-int:good-hash-word->fixnum))) + +;;; Ensure that all layout-clos-hash values have a 1 somewhere +;;; such that LOGANDing any number of nonzero hashes is nonzero. +(with-test (:name :layout-hashes-constant-1-bit) + (let ((combined most-positive-fixnum)) + (maphash (lambda (classoid wrapper) + (declare (ignore classoid)) + (let ((hash (sb-kernel:wrapper-clos-hash wrapper))) + (setq combined (logand combined hash)))) + (sb-kernel:classoid-subclasses (sb-kernel:find-classoid 't))) + (assert (/= 0 combined)))) + +(defun c-murmur-fmix (word) + (declare (type sb-vm:word word)) + (alien-funcall (extern-alien #+64-bit "murmur3_fmix64" + #-64-bit "murmur3_fmix32" + (function unsigned unsigned)) + word)) +(compile 'c-murmur-fmix) +;;; Assert that the Lisp translation of the C murmur hash matches. +;;; This is slightly redundant with the :ADDRESS-BASED-SXHASH-GCING test, +;;; though this one is a strictly a unit test of the hashing function, +;;; and the other is a test that GC does the right thing. +;;; So it's not a bad idea to have both. +(defun murmur-compare (random-state n-iter) + (let ((limit (1+ sb-ext:most-positive-word))) + (loop repeat (the fixnum n-iter) + do + (let* ((n (random limit random-state)) + (lisp-hash (sb-impl::murmur-fmix-word n)) + (c-hash (c-murmur-fmix n))) + (assert (= lisp-hash c-hash)))))) +(compile 'murmur-compare) + +(with-test (:name :mumur-hash-compare) + (murmur-compare (make-random-state t) 100000)) + +(with-test (:name :sap-hash) + (assert (/= (sxhash (sb-sys:int-sap #x1000)) + (sxhash (sb-sys:int-sap 0)))) + #-interpreter + (let ((list-of-saps + (loop for i below 1000 collect (sb-sys:int-sap i)))) + (ctu:assert-no-consing + (opaque-identity + (let ((foo 0)) + (dolist (sap list-of-saps foo) + (setq foo (logxor foo (sxhash sap))))))))) diff --git a/tests/heap-reloc/build-test-sbcl b/tests/heap-reloc/build-test-sbcl index 599b82ba71..61e984abfa 100644 --- a/tests/heap-reloc/build-test-sbcl +++ b/tests/heap-reloc/build-test-sbcl @@ -2,7 +2,7 @@ lisp="../../run-sbcl.sh $SBCL_ARGS" m_arg=`$lisp --eval '(progn #+x86 (princ " -m32"))' --quit` -libs=`$lisp --eval '(progn #+sb-core-compression (princ " -lz"))' --quit` +libs=`$lisp --eval '(progn #+sb-core-compression (princ " -lzstd"))' --quit` # Insert CFLAGS in case they contain -fsanitize=memory, for example. # Specify that some symbols are undefined so that the complete diff --git a/tests/heap-reloc/embiggen.lisp b/tests/heap-reloc/embiggen.lisp deleted file mode 100644 index 17995f6ce7..0000000000 --- a/tests/heap-reloc/embiggen.lisp +++ /dev/null @@ -1,56 +0,0 @@ -;;; Arrange so that all layouts have bignums as their bitmap, -;;; for exercising the C instance scavenging code. -;;; -;;; The use of a hashtable here was supposed end up with some layouts -;;; whose bitmap is at a lower address than the layout itself. -;;; This should randomize scavenging such that it sometimes sees -;;; a layout-bitmap that was already forwarded. -;;; However it doesn't work as desired; something else will have -;;; to be done to force that to happen. -;;; -;;; This test can't be run with immobile space enabled -;;; due simply to the assertion that instances in immobile space -;;; (which all happen to be layouts at the moment) -;;; do not have bignum bitmaps, which is true because a LAYOUT -;;; does not have enough slots to warrant a bignum bitmap. -;;; -;;; But the test's entire purpose is to assign noncanonical bignums -;;; (that are equivalent to fixnums) into every layout. -;;; -#-(or immobile-space (and));; FIXME: it's breaking something -(let ((ht (make-hash-table :test 'eql))) - (flet ((bignumify (int) - (or (gethash int ht) - (setf (gethash int ht) - (if (typep int 'fixnum) - (sb-bignum:make-small-bignum int) - int))))) - (sb-vm:map-allocated-objects - (lambda (obj type size) - (declare (ignore type size)) - (when (and (typep obj 'sb-kernel:layout) - (typep (sb-kernel:layout-bitmap obj) 'fixnum)) - (let ((flags (sb-kernel:layout-flags obj))) - (setf (sb-kernel:layout-bitmap obj) - (if (logtest (logior sb-kernel:+condition-layout-flag+ - sb-kernel:+pcl-object-layout-flag+) - flags) - ;; *** this is bogus, since conditions have an arbitrary - ;; number of slots, and need the special case of "all 1s" - ;; But it's ok as a test. - (1- (ash 1 99)) - (bignumify - (let ((bitmap (sb-kernel:layout-bitmap obj))) - (if (/= bitmap -1) - bitmap - (let ((len (sb-kernel:layout-length obj))) - ;; force the 0th bit to 1, for the layout - ;; (Shouldn't LENGTH be right? Doesn't seem to be) - (logior #-compact-instance-header 1 - (1- (ash 1 len))))))))) - (unless (plusp (length (sb-kernel:layout-equalp-tests obj))) - (let ((n (- (sb-kernel:layout-length obj) sb-vm:instance-data-start))) - (when (>= n 0) - (setf (sb-kernel:layout-equalp-tests obj) - (make-array n :initial-element 0)))))))) - :all))) diff --git a/tests/heap-reloc/fake-mman.c b/tests/heap-reloc/fake-mman.c index bfb8fea214..96003c48ed 100644 --- a/tests/heap-reloc/fake-mman.c +++ b/tests/heap-reloc/fake-mman.c @@ -9,80 +9,57 @@ static int verbose=1; /// - partially overlapping ranges for the desired and actual space /// - aligned to OS page but misaligned for GC card -/* Each line of the instruction file contains two addresses, - * a sub-2GB address and a high address. - * - * 64-bit builds use the first address for immobile space - * and the second address for dynamic space. - * If the current build does not support immobile space, - * the first address in the pair is simply ignored. - * - * 32-bit builds use only the first address - */ -void pick_fuzzed_addresses(unsigned long *addr1, - unsigned long *addr2) +void pick_fuzzed_addresses(void** addr1, void** addr2, void** addr3) { char * pathname; FILE * f; char line[100]; - int line_number, i; + int line_number = 1, i; if ((pathname = getenv("SBCL_FAKE_MMAP_INSTRUCTION_FILE")) == NULL) { fprintf(stderr, "WARNING: image built with MOCK_MMAP_FAILURE\n"); fprintf(stderr, " but no mock configuration data found.\n"); exit(1); } - if ((f = fopen(pathname, "r+")) == NULL) { + char *opt = getenv("SBCL_FAKE_MMAP_INSTRUCTION_LINE"); + if (opt) line_number = atoi(opt); + if ((f = fopen(pathname, "r")) == NULL) { // If the file can't be found, don't silently ignore it, // because if the relocator "worked" you don't want to get all happy // that it worked only to find that it didn't actually perform relocation. fprintf(stderr, "Could not read '%s'\n", pathname); exit(1); } - char __attribute__((unused)) *buf = fgets(line, sizeof line, f); - line_number = atoi(line); - for (i = 0 ; i <= line_number ; ++i) { - int ok; - ok = fgets(line, sizeof line, f) != NULL && line[0] != '\n'; - if (i == line_number - 1) { - char *end; - *addr1 = strtoul(line, &end, 16); - *addr2 = strtoul(end, 0, 16); - } - if (!ok) { - // fprintf(stderr, "*** Rewinding fake mmap instructions\n"); - line_number = 0; - break; - } - } - rewind(f); - fprintf(f, "%02d", 1+line_number); + // skip the comment line and read 'line_number' more lines + for (i = 0 ; i <= line_number ; ++i) fgets(line, sizeof line, f); + char *end; + *addr1 = (void*)strtoul(line, &end, 16); + *addr2 = (void*)strtoul(end, &end, 16); + *addr3 = (void*)strtoul(end, &end, 16); + fprintf(stderr, "Trial %d:\n", line_number); fclose(f); } os_vm_address_t -os_validate(int attributes, os_vm_address_t addr, os_vm_size_t len) +os_alloc_gc_space(int space_id, int attributes, os_vm_address_t addr, os_vm_size_t len) { int flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE; void *fuzzed = addr; os_vm_address_t actual; int movable = attributes & MOVABLE; -#ifdef MAP_32BIT - if (attributes & ALLOCATE_LOW) - flags |= MAP_32BIT; -#endif if (addr && movable) { - static unsigned long addr1, addr2; - if (!addr1) - pick_fuzzed_addresses(&addr1, &addr2); -#ifdef LISP_FEATURE_64_BIT - if (!(attributes & ALLOCATE_LOW)) - fuzzed = (void*)addr2; - else -#endif - fuzzed = (void*)addr1; + static void *val1, *val2, *val3; + if (!val1) pick_fuzzed_addresses(&val1, &val2, &val3); + switch (space_id) { + case READ_ONLY_CORE_SPACE_ID: fuzzed = val1; break; + case IMMOBILE_FIXEDOBJ_CORE_SPACE_ID: fuzzed = val2; break; + case DYNAMIC_CORE_SPACE_ID: fuzzed = val3; break; + } } +#ifdef MAP_32BIT + if (attributes & ALLOCATE_LOW) flags |= MAP_32BIT; +#endif actual = mmap(fuzzed, len, OS_VM_PROT_ALL, flags, -1, 0); if (actual == MAP_FAILED) { perror("mmap"); @@ -95,15 +72,8 @@ os_validate(int attributes, os_vm_address_t addr, os_vm_size_t len) } if (verbose && addr != fuzzed) fprintf(stderr, actual == fuzzed ? - "//Fuzzed %12p into %12p successfully\n": - "//Tried fuzzing %p into %p but actually got %p\n", - addr, fuzzed, actual); + "// space %d: Fuzzed %12p into %12p successfully\n": + "// space %d: Tried fuzzing %p into %p but actually got %p\n", + space_id, addr, fuzzed, actual); return actual; } - -void os_invalidate(os_vm_address_t addr, os_vm_size_t len) -{ - if (munmap(addr,len) == -1) { - perror("munmap"); - } -} diff --git a/tests/heap-reloc/fakemap b/tests/heap-reloc/fakemap index babcec4f2d..278977945c 100644 --- a/tests/heap-reloc/fakemap +++ b/tests/heap-reloc/fakemap @@ -1,7 +1,7 @@ -01 -0x40008000 0x3000010000 -0x70000000 0x30000000 # opposite of usual -0x50300000 0x1000010000 -0x50080000 0x1000080000 -0x50040000 0x200000a000 -0x50001000 0x3800008000 +# READONLY n/a DYNAMIC +0xe0000000 0 0x40008000 +0xe0000000 0 0x70000000 +0xe0000000 0 0x50300000 +0xe0000000 0 0x50080000 +0xe0000000 0 0x50040000 +0xe0000000 0 0x50001000 diff --git a/tests/heap-reloc/fakemap_64 b/tests/heap-reloc/fakemap_64 new file mode 100644 index 0000000000..8bbe369e8f --- /dev/null +++ b/tests/heap-reloc/fakemap_64 @@ -0,0 +1,7 @@ +# READONLY FIXEDOBJ DYNAMIC +0x4000010000 0x40008000 0x3000010000 +0x1100000000 0x70000000 0x30000000 +0x1100000000 0x50300000 0x1000010000 +0x1100000000 0x50080000 0x1000080000 +0x1100000000 0x50040000 0x200000a000 +0x1100000000 0x50001000 0x3800008000 diff --git a/tests/heapsort.impure-cload.lisp b/tests/heapsort.pure-cload.lisp similarity index 100% rename from tests/heapsort.impure-cload.lisp rename to tests/heapsort.pure-cload.lisp diff --git a/tests/heapwalk.impure.lisp b/tests/heapwalk.impure.lisp new file mode 100644 index 0000000000..7497cde320 --- /dev/null +++ b/tests/heapwalk.impure.lisp @@ -0,0 +1,48 @@ + +(defun mul (x y) (declare (sb-vm:signed-word x y)) (* x y)) +(compile 'mul) + +(defun manymul (n &aux res) + (dotimes (i n res) + (setq res (mul (floor (- (expt 2 (- sb-vm:n-word-bits 2))) 1000) + (+ i 1000))))) +(compile 'manymul) + +(defun walk () + (let ((v (make-array 1000)) + (ct 0)) + (sb-vm:map-allocated-objects + (lambda (obj type size) + (declare (ignore size)) + (when (and (= type sb-vm:list-pointer-lowtag) + (= (sb-kernel:generation-of obj) 0) + (< ct 1000)) + (setf (aref v ct) obj) + (incf ct))) + :dynamic) + (let ((*print-level* 2) + (*print-length* 4) + (*standard-output* (make-broadcast-stream))) + (dotimes (i ct) + (princ (aref v i)))))) +(compile 'walk) + +;;; As a precondition to asserting that heap walking did not +;;; visit an alleged cons that is a filler object, +;;; assert that there is the telltale pattern (if applicable). +#+(or arm64 x86-64) +(let ((product (manymul 1))) + (sb-sys:with-pinned-objects (product) + (let ((word (sb-sys:sap-ref-word + (sb-sys:int-sap (sb-kernel:get-lisp-obj-address product)) + (- (ash 2 sb-vm:word-shift) sb-vm:other-pointer-lowtag)))) + (assert (= word sb-ext:most-positive-word))))) + +(manymul 100) + +;;; Granted it's not a great idea to assume that anything in the heap +;;; can be printed, but this test was a fairly easy way to get +;;; "Unhandled memory fault at #xFFFFFFFFFFFFFFF0." +;;; The should print approximately one cons (for GC epoch) +(with-test (:name :heapwalk-safety) + (progn (gc :gen 1) (manymul 100) (walk))) diff --git a/tests/hide-packages.test.sh b/tests/hide-packages.test.sh index 4107344a3e..b3c0e6dccd 100644 --- a/tests/hide-packages.test.sh +++ b/tests/hide-packages.test.sh @@ -7,8 +7,33 @@ set -e # +INTERNAL-FEATURES+ is a constant, so use a roundabout way of # clobbering it that avoids a compiler warning and a runtime error. CLOBBER_INTERNAL_FEATURES="(handler-bind ((simple-error #'continue)) + (sb-vm::close-thread-alloc-region) + (alien-funcall (extern-alien \"move_rospace_to_dynamic\" (function void int)) 1) + (when (sb-sys:find-foreign-symbol-address \"test_dirty_all_gc_cards\") + (alien-funcall (extern-alien \"test_dirty_all_gc_cards\" (function void)))) (sb-kernel:set-symbol-global-value (eval ''sb-impl:+internal-features+) nil))" +### Apparently the finalizer thread must be stopped before running these tests or else +### it can crash due to the highly unorthodox use of move_rospace_to_dynamic(). +### Somehow the finalizer thread dereferenced data from the R/O space +### after that space was reduced to 0 size. Amazingly the finalizer hadn't gotten out +### of its new_thread_trampoline nor assigned anything to 'current_thread'. +### parallel-exec was able to elicit about 3 failures in 20 prior to the fix. +### +### Backtrace from gdb: +### ... +### #8 0x000055d729cf8d0a in call_lossage_handler () at interr.c:116 +### #9 0x000055d729cf9127 in corruption_warning_and_maybe_lose ( +### fmt=fmt@entry=0x55d729d2a660 "Received signal %d @ %lx in non-lisp tid %d, resignaling to a lisp thread.") at interr.c:202 +### #10 0x000055d729cf97bc in resignal_to_lisp_thread (signal=signal@entry=11, +### context=context@entry=0x7f9a3e216880) at interrupt.c:218 +### #11 0x000055d729cf9843 in low_level_handle_now_handler (signal=11, info=0x7f9a3e2169b0, +### void_context=0x7f9a3e216880) at interrupt.c:1927 +### #12 <signal handler called> +### #13 new_thread_trampoline (arg=<optimized out>) at src/runtime/runtime.h:160 +### #14 0x00007f9a3ed20d80 in start_thread (arg=0x7f9a3e217640) at pthread_create.c:481 +### #15 0x00007f9a3eaf676f in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:95 + ### Test 1: assert that no package name string has a reference from any ### heap object aside from the package itself. ### Because SAVE-LISP-AND-DIE coalesces strings, this test provides confidence @@ -19,6 +44,7 @@ run_sbcl <<EOF #+cheneygc (exit) ; not much can be done for cheney to make this pass #+sb-devel (exit) ; doesn't pass either +#+sb-thread (sb-impl::finalizer-thread-stop) (defvar *weak-ptrs* nil) (progn ;; Remove features that are also names of packages. @@ -46,8 +72,8 @@ run_sbcl <<EOF (sb-impl::%rebuild-package-names sb-kernel::*package-names*)) (gc :gen 7) -(setq *weak-ptrs* - (remove-if (lambda (x) (not (weak-pointer-value x))) *weak-ptrs*)) +(setq *weak-ptrs* (remove-if-not #'weak-pointer-value *weak-ptrs*)) +(when *weak-ptrs* (search-roots *weak-ptrs* :print :verbose :criterion :static)) (assert (null *weak-ptrs*)) (format t "Package hiding test 1: PASS~%") EOF @@ -60,11 +86,11 @@ run_sbcl <<EOF ;;; That it doesn't pass doesn't mean the packages aren't hidden correctly. ;;; It just means the test is inadequate. #-(or x86 x86-64) (exit) -#-sb-thread (exit) ;; doesn't pass for some reason #+sb-devel (exit) ;;; Does not pass with interpreter (setq sb-ext:*evaluator-mode* :compile) +#+sb-thread (sb-impl::finalizer-thread-stop) ;;; Avoid accidental enlivenment of strings - the forms in this file must ;;; obscure the spellings of package name strings or else they can end up @@ -88,7 +114,8 @@ run_sbcl <<EOF (let ((name (package-name package))) (rename-package name (concatenate 'string "HIDDEN-" name))))) ;; The package hashtable lazily removes keys. Force it do to do so now. - (sb-impl::%rebuild-package-names sb-kernel::*package-names*)) + (sb-impl::%rebuild-package-names sb-kernel::*package-names*) + (sb-sys:scrub-control-stack)) ;;; Place all the strings we want to search for onto the stack. ;;; This little rearrangement here is a hack which causes the last item in diff --git a/tests/icf-smoketest.impure-cload.lisp b/tests/icf-smoketest.impure-cload.lisp new file mode 100644 index 0000000000..ac00a394d9 --- /dev/null +++ b/tests/icf-smoketest.impure-cload.lisp @@ -0,0 +1,7 @@ +(eval '(defun hhh () 92)) +(defvar f #'hhh) +(unintern 'hhh) +(eval '(defun hhh () 92)) +;;; Ensure no crash on (FIND-PACKAGE (SYMBOL-PACKAGE NIL)) if two functions +;;; are identical and one is named by an uninterned symbol. +(fold-identical-code :aggressive t) diff --git a/tests/immobile-space.impure.lisp b/tests/immobile-space.impure.lisp new file mode 100644 index 0000000000..ad9f674db5 --- /dev/null +++ b/tests/immobile-space.impure.lisp @@ -0,0 +1,53 @@ + +#-immobile-space (invoke-restart 'run-tests::skip-file) + +;;; If an instance was allocated but its layout not stored yet +;;; it could crash +(defun alloc-layoutless-instances () + (list (sb-vm::alloc-immobile-fixedobj + 6 (logior (ash 5 sb-vm:instance-length-shift) sb-vm:instance-widetag)))) +(compile 'alloc-layoutless-instances) +;;; the first GC should WP some pages but might not crash +(dotimes (i 1000 (gc)) (alloc-layoutless-instances)) +;;; the second one was more likely to crash +(dotimes (i 1000 (gc)) (alloc-layoutless-instances)) + +(defstruct trythis a) + +;;; Assign a bitmap that is not the special case for "all tagged" +;;; but does correctly indicate 1 tagged slot. +(let* ((l (sb-kernel:wrapper-friend (sb-kernel:find-layout 'trythis))) + (slot (1- (sb-kernel:%instance-length l)))) + (assert (eql (sb-kernel:%raw-instance-ref/signed-word l slot) + sb-kernel:+layout-all-tagged+)) + (sb-kernel:%raw-instance-set/word l slot 1)) + +(defun ll-alloc () + ;; This must be in its own function because the vop preserves no registers + ;; when calling to C. + (sb-vm::alloc-immobile-fixedobj 8 (logior (ash 7 sb-vm:instance-length-shift) + sb-vm:instance-widetag))) +(compile 'll-alloc) ; low level allocator +(defun make () + (let ((inst (ll-alloc))) + (setf (sb-kernel:%instance-wrapper (truly-the trythis inst)) + (sb-kernel:find-layout 'trythis)) + (setf (trythis-a inst) (copy-seq "Hello")) + inst)) + +(setf (extern-alien "verify_gens" char) 0) +(compile 'make) +(defglobal things (loop repeat 5 collect (make))) +;;; promote THINGS to gen 1 so that we can make them +;;; point to something younger. +(gc :gen 1) +(assert (eql (sb-kernel:generation-of (car things)) 1)) +(setf (trythis-a (car things)) "wat") + +;;; This next GC doesn't incur a bug (though that's maybe surprising), +;;; but the final one would if this one leaves a page protection bit +;;; in a wrong state such that an old->young pointer is missed next time. +(gc :gen 2) +(print things) +(setf (trythis-a (car things)) "anewstring") +(gc) diff --git a/tests/impure-runner.lisp b/tests/impure-runner.lisp index 6f250412d2..2c981fa289 100644 --- a/tests/impure-runner.lisp +++ b/tests/impure-runner.lisp @@ -1,5 +1,3 @@ -(setf (extern-alien "gc_allocate_dirty" char) 1) - (with-compilation-unit () (load "test-util") (load "assertoid")) diff --git a/tests/info.before-xc.lisp b/tests/info.before-xc.lisp index a60fc7622e..1b82f0d156 100644 --- a/tests/info.before-xc.lisp +++ b/tests/info.before-xc.lisp @@ -19,34 +19,35 @@ ;;; It's possible in general for a constant to have the value NIL, but ;;; not for vector-data-offset, which must be a number: -(assert (constantp 'sb-vm:vector-data-offset)) +(assert (cl:constantp 'sb-vm:vector-data-offset)) (assert (integerp (symbol-value 'sb-vm:vector-data-offset))) (in-package "SB-IMPL") -(let ((foo-iv (packed-info-insert +nil-packed-infos+ +no-auxilliary-key+ +(let ((foo-iv (packed-info-insert +nil-packed-infos+ +no-auxiliary-key+ 5 "hi 5")) - (bar-iv (packed-info-insert +nil-packed-infos+ +no-auxilliary-key+ + (bar-iv (packed-info-insert +nil-packed-infos+ +no-auxiliary-key+ 6 "hi 6")) (baz-iv (packed-info-insert +nil-packed-infos+ 'mumble 9 :phlebs))) ;; removing nonexistent types returns NIL - (assert (equal nil (packed-info-remove foo-iv +no-auxilliary-key+ + (assert (equal nil (packed-info-remove foo-iv +no-auxiliary-key+ '(4 6 7)))) (assert (equal nil (packed-info-remove baz-iv 'mumble '(4 6 7)))) ;; removing the one info shrinks the vector to nothing ;; and all values of nothing are EQ - (assert (equalp #(0) (packed-info-remove foo-iv +no-auxilliary-key+ '(5)))) - (assert (eq (packed-info-remove foo-iv +no-auxilliary-key+ '(5)) - (packed-info-remove bar-iv +no-auxilliary-key+ '(6)))) - (assert (eq (packed-info-remove foo-iv +no-auxilliary-key+ '(5)) + (assert (equalp (packed-info-remove foo-iv +no-auxiliary-key+ '(5)) + +nil-packed-infos+)) + (assert (eq (packed-info-remove foo-iv +no-auxiliary-key+ '(5)) + (packed-info-remove bar-iv +no-auxiliary-key+ '(6)))) + (assert (eq (packed-info-remove foo-iv +no-auxiliary-key+ '(5)) (packed-info-remove baz-iv 'mumble '(9))))) ;; Test that the packing invariants are maintained: ;; 1. if an FDEFINITION is present in an info group, it is the *first* info -;; 2. if SETF is an auxilliary key, it is the *first* aux key +;; 2. if SETF is an auxiliary key, it is the *first* aux key (let ((vect +nil-packed-infos+) (s 'foo)) (flet ((iv-put (aux-key number val) diff --git a/tests/info.impure.lisp b/tests/info.impure.lisp index 6f04dd4acc..533d5e4d16 100644 --- a/tests/info.impure.lisp +++ b/tests/info.impure.lisp @@ -135,11 +135,11 @@ (info :variable :macro-expansion 'fruitbaskets) (assert (and (not foundp) (not data))))) -;; packed info vector tests +;; packed-info tests (test-util:with-test (:name :globaldb-info-iterate) (let ((s (with-output-to-string (*standard-output*) (show-info '*)))) - (dolist (x '((:function :definition) (:function :type) + (dolist (x '((:function :type) (:function :where-from) (:function :kind) (:function :info) (:function :source-transform) (:type :kind) (:type :builtin) @@ -157,7 +157,6 @@ (flet ((try (x) (assert (eq (find-fdefn x) (info :function :definition x))))) (do-all-symbols (s) - (try s) (try `(setf ,s)) (try `(cas ,s))))) @@ -178,7 +177,7 @@ (let ((val (format nil "value for ~D" num))) (setq iv1 (quick-packed-info-insert iv1 num val) iv2 (%packed-info-insert ; not PACKED-INFO-INSERT - iv2 +no-auxilliary-key+ num val)) + iv2 +no-auxiliary-key+ num val)) (assert (equalp iv1 iv2)))) ;; the first and only info descriptor should be full (assert (not (info-quickly-insertable-p iv1)))))) @@ -189,10 +188,10 @@ ;; The real GET-INFO-VALUE AVERs that INFO-NUMBER is legal. This one doesn't. (defun cheating-get-info-value (sym aux-key info-number) - (let* ((vector (symbol-info-vector sym)) + (let* ((vector (symbol-dbinfo sym)) (index (packed-info-value-index vector aux-key info-number))) (if index - (values (svref vector index) t) + (values (sb-kernel:%info-ref vector index) t) (values nil nil)))) ;; Info vectors may be concurrently updated. If more than one thread writes @@ -203,7 +202,7 @@ #+sb-thread (test-util:with-test (:name :info-vector-concurrency) (let ((s (gensym)) - (a (make-array 1 :element-type 'sb-ext:word))) + (a (make-array 1 :element-type 'sb-ext:word :initial-element 0))) (let* ((aux-keys '(0 a b c d e f g h nil i j k l m n o p setf q r s)) (info-types (loop for i from 1 below 64 collect i)) (work (test-util:shuffle (coerce (crossprod aux-keys info-types) 'vector))) @@ -336,7 +335,8 @@ (let ((tally (make-array n-threads :initial-element 0))) (info-maphash (lambda (key id-list) - (let ((scoreboard (make-array (/ n-threads 2) :element-type 'bit))) + (let ((scoreboard (make-array (/ n-threads 2) :element-type 'bit + :initial-element 0))) (dolist (thread-id id-list) (let ((group-id (floor thread-id 2))) ;; assert no duplicate for a peer group @@ -568,7 +568,7 @@ (flet ((run (names) (declare (simple-vector names)) (let* ((n (length names)) - (counts (make-array n :element-type 'sb-ext:word)) + (counts (make-array n :element-type 'sb-ext:word :initial-element 0)) (threads)) (dotimes (i 15) (push (sb-thread:make-thread @@ -598,8 +598,8 @@ for val = (info :variable :macro-expansion name) do (assert (eql (or val 0) count)))))) ;; Try it when names are symbols or "simple" 2-list names - (run (coerce (loop repeat 50 - for sym = (gensym) + (run (coerce (loop for sym = (gensym) + repeat 50 nconc (list `(setf ,sym) sym)) 'vector)) ;; For hairy names, the tricky piece is in the rehash algorithm, diff --git a/tests/init-hooks.test.sh b/tests/init-hooks.test.sh new file mode 100644 index 0000000000..66e718bf84 --- /dev/null +++ b/tests/init-hooks.test.sh @@ -0,0 +1,33 @@ +#!/bin/sh + +# This software is part of the SBCL system. See the README file for +# more information. +# +# While most of SBCL is derived from the CMU CL system, the test +# files (like this one) were written from scratch after the fork +# from CMU CL. +# +# This software is in the public domain and is provided with +# absolutely no warranty. See the COPYING and CREDITS files for +# more information. + +. ./subr.sh + +use_test_subdirectory + +tmpcore="init-hook-test.core" + +run_sbcl <<EOF + (push 'check-no-threads sb-ext:*init-hooks*) + (defun check-no-threads () + (sb-sys:os-exit (if (sb-thread::thread-p sb-impl::*finalizer-thread*) 1 0))) + (save-lisp-and-die "$tmpcore") +EOF +if [ $? -ne 0 ]; then + echo "failure saving core" + exit 1 +fi +run_sbcl_with_core "$tmpcore" --noinform --disable-debugger +check_status_maybe_lose "init-hooks execution order" $? 0 "(passed)" + +exit $EXIT_TEST_WIN diff --git a/tests/input-manifest.lisp-expr b/tests/input-manifest.lisp-expr index b1c3584d91..f4b50e4ba0 100644 --- a/tests/input-manifest.lisp-expr +++ b/tests/input-manifest.lisp-expr @@ -1,23 +1,28 @@ +;;; This comment might make sourceforge stop thinking that the file +;;; is binary its diff view. +;;; Or not. (("aprof.impure.lisp" "src/code/aprof.lisp" "src/code/shaketree.lisp") + ("avltree.pure.lisp" "tests/bbtree-test-util.lisp") ("bit-vector.impure.lisp" "contrib/sb-posix.fasl") + ("brothertree.impure.lisp" + "src/code/brothertree.lisp") + ("redblack.impure.lisp" + "tests/bbtree-test-util.lisp" + "src/code/redblack.lisp") ("case.pure.lisp" "tests/case-test.lisp") ("chill.test.sh" "src/cold/chill.lisp" - "src/cold/shebang.lisp" "package-data-list.lisp-expr") ("clos.impure.lisp" "contrib/sb-cltl2.fasl" "tests/package-ctor-bug.lisp" "tests/bug-503095.lisp" "tests/bug-503095-2.lisp") - ("compiler.pure.lisp" - "tests/data/wonky1.lisp" - "tests/data/wonky2.lisp" - "tests/data/wonky3.lisp") ("compiler.impure.lisp" "tests/bad-mlf-test.lisp" + "tests/bug-255.lisp" "tests/bug204-test.lisp" "tests/bug-417.lisp" "tests/bug-943953.lisp" @@ -35,8 +40,21 @@ "tests/block-compile-test-4.lisp" "tests/block-compile-test-5.lisp") ("debug.impure.lisp" "tests/bug-414.lisp") + ("block-compile.impure.lisp" + "tests/package-test-1.lisp" + "tests/package-test-2.lisp" + "tests/package-test-3.lisp" + "tests/package-test-4.lisp") ("defstruct.impure-cload.lisp" "tests/block-compile-defstruct-test.lisp") ("elfcore.test.sh" "src/runtime/shrinkwrap-sbcl") + ("exit-hang.impure.lisp" "tests/fcb-threads.so") + ("fcb-threads.impure.lisp" "tests/fcb-threads.so") + ("filecompile.impure.lisp" + "tests/data/wonky1.lisp" + "tests/data/wonky2.lisp" + "tests/data/wonky3.lisp" + "tests/data/wonky4.lisp" + "src/code/primordial-extensions.lisp") ("init.test.sh" "contrib/sb-introspect.fasl" "tests/custom-sysinit.lisp" @@ -46,13 +64,63 @@ "tests/parallel-fasl-load-test.lisp" "tests/data/wonky1.lisp" "tests/data/wonky2.lisp" - "tests/data/wonky3.lisp") + "tests/data/wonky3.lisp" + "tests/data/wonky4.lisp") ("load.pure.lisp" "tests/data/wonky1.lisp") ("octets.pure.lisp" "tests/data/compile-file-pos.lisp" "tests/data/compile-file-pos-utf16be.lisp") + ("packages.impure.lisp" + "contrib/sb-md5.fasl" + "contrib/sb-rotate-byte.fasl" + "tests/package-test-1.lisp" + "tests/package-test-2.lisp" + "tests/package-test-3.lisp" + "tests/package-test-4.lisp") + ("redblack.pure.lisp" "tests/bbtree-test-util.lisp") ("run-program.impure.lisp" "contrib/sb-posix.fasl") + ("sb-aclrepl.impure.lisp" "contrib/sb-aclrepl.fasl" + "../contrib/sb-aclrepl/tests.lisp") + ("sb-bsd-sockets.impure.lisp" "contrib/sb-bsd-sockets.fasl" "contrib/sb-posix.fasl" + "../contrib/sb-bsd-sockets/tests.lisp") + ("sb-cltl2.impure.lisp" "contrib/sb-cltl2.fasl" "../contrib/sb-cltl2/tests.lisp") + ("sb-concurrency.impure.lisp" "contrib/sb-concurrency.fasl" + "../contrib/sb-concurrency/tests/package.lisp" + "../contrib/sb-concurrency/tests/test-utils.lisp" + "../contrib/sb-concurrency/tests/test-frlock.lisp" + "../contrib/sb-concurrency/tests/test-queue.lisp" + "../contrib/sb-concurrency/tests/test-mailbox.lisp" + "../contrib/sb-concurrency/tests/test-gate.lisp") + ("sb-cover.impure.lisp" "contrib/sb-cover.fasl") + ("sb-gmp.impure.lisp" "contrib/sb-gmp.fasl" "../contrib/sb-gmp/tests.lisp") + ("sb-graph.impure.lisp" "contrib/sb-graph.fasl" "contrib/uiop.fasl") + ("sb-introspect.impure.lisp" "contrib/sb-introspect.fasl" + "../contrib/sb-introspect/xref-test-data.lisp" "../contrib/sb-introspect/xref-test.lisp" + "../contrib/sb-introspect/test.lisp" "../contrib/sb-introspect/test-driver.lisp" + "../contrib/sb-introspect/load-test.lisp") + ("sb-md5.impure.lisp" "contrib/sb-md5.fasl" "contrib/sb-rotate-byte.fasl" + "../contrib/sb-md5/md5-tests.lisp") + ("sb-mpfr.impure.lisp" "contrib/sb-gmp.fasl" "contrib/sb-mpfr.fasl" + "../contrib/sb-mpfr/tests.lisp") + ("sb-posix.impure.lisp" "contrib/sb-posix.fasl" + "../contrib/sb-posix/posix-tests.lisp" "../contrib/sb-posix/libc-tests.lisp" + "test-output/write-test.txt") + ("sb-simd.impure.lisp" "contrib/sb-simd.fasl" + "../contrib/sb-simd/test-suite/packages.lisp" + "../contrib/sb-simd/test-suite/numbers.lisp" + "../contrib/sb-simd/test-suite/utilities.lisp" + "../contrib/sb-simd/test-suite/test-suite.lisp" + "../contrib/sb-simd/test-suite/test-arefs.lisp" + "../contrib/sb-simd/test-suite/test-simple-simd-functions.lisp" + "../contrib/sb-simd/test-suite/test-horizontal-functions.lisp" + "../contrib/sb-simd/test-suite/test-hairy-simd-functions.lisp" + "../contrib/sb-simd/test-suite/test-packages.lisp") + ("sb-simple-streams.impure.lisp" "contrib/sb-simple-streams.fasl" "contrib/sb-bsd-sockets.fasl") + ("sb-rotate-byte.impure.lisp" "contrib/sb-rotate-byte.fasl" + "../contrib/sb-rotate-byte/rotate-byte-tests.lisp") + ("sb-sprof.impure.lisp" "contrib/sb-sprof.fasl" + "../contrib/sb-sprof/test.lisp" "../contrib/sb-sprof/graph.lisp") ("signals.impure.lisp" "contrib/sb-posix.fasl") ("stream.impure.lisp" "contrib/sb-posix.fasl") ("threads.impure.lisp" @@ -83,4 +151,6 @@ "tests/data/SentenceBreakProperty.txt") ("undefined-classoid-bug.test.sh" "tests/undefined-classoid-bug-1.lisp" - "tests/undefined-classoid-bug-2.lisp")) + "tests/undefined-classoid-bug-2.lisp") + ("x86-64-codegen.impure.lisp" + "tests/typep-golden-data.txt")) diff --git a/tests/inspect.impure.lisp b/tests/inspect.impure.lisp index 7bbacc4142..6f490ef58a 100644 --- a/tests/inspect.impure.lisp +++ b/tests/inspect.impure.lisp @@ -37,15 +37,15 @@ (assert (search "PROTOTYPE: " (test-inspect class))))) (with-test (:name (inspect array :element-type :lp-1835934)) - (let* ((array (make-array '())) + (let* ((array (make-array '() :initial-element 0)) (result (test-inspect array))) (assert (search "an ARRAY of T" result)) (assert (search "dimensions are ()" result))) - (let ((array (make-array '() :element-type 'fixnum))) + (let ((array (make-array '() :element-type 'fixnum :initial-element 0))) (assert (search "an ARRAY of FIXNUM" (test-inspect array)))) - (let ((array (let ((a (make-array ()))) + (let ((array (let ((a (make-array () :initial-element 0))) (make-array '() :displaced-to a)))) (assert (search "a displaced ARRAY of T" (test-inspect array))))) @@ -66,6 +66,6 @@ (assert (not (search "10." result))))) (with-test (:name (inspect vector fill-pointer)) - (let* ((array (make-array 3 :fill-pointer 2)) + (let* ((array (make-array 3 :fill-pointer 2 :initial-element 0)) (result (test-inspect array))) (assert (search "VECTOR of length 2" result)))) diff --git a/tests/interface.impure.lisp b/tests/interface.impure.lisp index 5edb0f09a7..5b0755e7fd 100644 --- a/tests/interface.impure.lisp +++ b/tests/interface.impure.lisp @@ -527,13 +527,13 @@ (defun testme (a b) (values "nice" (+ a b))) (compile 'testme) (defparameter trace-this-f1 #'testme) -(sb-int:encapsulate-funobj trace-this-f1 (sb-kernel::find-fdefn 'testme)) +(sb-int:encapsulate-funobj trace-this-f1 (sb-int:find-fdefn 'testme)) (defun funky (a b c) (lambda (z) (values "nice" a b (+ (incf a) (decf c) z)))) (compile 'funky) (defparameter trace-this-f2 (funky 10 'wat 19)) (setf (symbol-function 'funky-closure) trace-this-f2) -(sb-int:encapsulate-funobj trace-this-f2 (sb-kernel::find-fdefn 'trace-this-f2)) +(sb-int:encapsulate-funobj trace-this-f2 (sb-int:find-fdefn 'trace-this-f2)) (with-test (:name :trace-funobj-encapsulation) (assert (search "returned \"nice\"" @@ -549,4 +549,15 @@ (with-test (:name :describe-function-not-named-by-designator) (describe (formatter "~&~A~A") (make-broadcast-stream))) ; should not crash +(defun test-intercepted-load (arg) (apply #'load arg (list :foo :bar :allow-other-keys t))) +(compile 'test-intercepted-load) +(sb-int:encapsulate 'load 'interceptor + (compile nil '(lambda (realfun pathname &rest things) + (if (eq pathname :testme) + :yes + (apply realfun pathname things))))) + +(with-test (:name :load-encapsulatable) + (assert (eq (test-intercepted-load :testme) :yes))) + ;;;; success diff --git a/tests/interface.pure.lisp b/tests/interface.pure.lisp index cd2d77825f..2c61b9a69b 100644 --- a/tests/interface.pure.lisp +++ b/tests/interface.pure.lisp @@ -36,6 +36,10 @@ (search "is not" (write-to-string err :escape nil))))))) +;; Regression from R/O space change +(with-test (:name (apropos-list :smoke-test)) + (assert (plusp (length (apropos-list "required-foreign"))))) + ;;; APROPOS should accept a package designator, not just a package, and ;;; furthermore do the right thing when it gets a package designator. ;;; (bug reported and fixed by Alexey Dejneka sbcl-devel 2001-10-17) @@ -53,6 +57,13 @@ (length (apropos-list "" "SB-VM" t)) (length (apropos-list "" "SB-VM"))))) +(with-test (:name :apropos-symbol-values) + (let ((string + (with-output-to-string (*standard-output*) + (apropos "*print-")))) + (assert (search "=" string)) + (assert (search "PPRINT-DISPATCH" string)))) + ;;; TYPEP, SUBTYPEP, UPGRADED-ARRAY-ELEMENT-TYPE and ;;; UPGRADED-COMPLEX-PART-TYPE should be able to deal with NIL as an ;;; environment argument @@ -108,7 +119,8 @@ :timeout))))) ;;; SLEEP should work with large integers as well -(with-test (:name (sleep :pretty-much-forever)) +(with-test (:name (sleep :pretty-much-forever) + :skipped-on (:and (:or :linux :darwin) :sb-safepoint)) ; hangs (assert (eq :timeout (handler-case (sb-ext:with-timeout 1 @@ -203,19 +215,20 @@ ;; if address printing is turned off. Should work on any backend, I think. (with-test (:name (disassemble :without-addresses)) (flet ((disassembly-text (lambda-expr) - (let ((string - (let ((sb-disassem::*disassem-location-column-width* 0) - (*print-pretty* nil)) ; prevent function name wraparound - (with-output-to-string (s) - (disassemble lambda-expr :stream s))))) - ;; Return all except the first two lines. This is subject to change - ;; any time we muck with the layout unfortunately. - (subseq string - (1+ (position #\Newline string - :start (1+ (position #\Newline string)))))))) - (let ((string1 (disassembly-text '(lambda (x) (car x)))) - (string2 (disassembly-text '(lambda (y) (car y))))) - (assert (string= string1 string2))))) + (let ((string + (let ((sb-disassem::*disassem-location-column-width* 0) + (sb-ext:*disassemble-annotate* nil) + (*print-pretty* nil)) ; prevent function name wraparound + (with-output-to-string (s) + (disassemble lambda-expr :stream s))))) + ;; Return all except the first two lines. This is subject to change + ;; any time we muck with the layout unfortunately. + (subseq string + (1+ (position #\Newline string + :start (1+ (position #\Newline string)))))))) + (let ((string1 (disassembly-text '(lambda (x) (car x)))) + (string2 (disassembly-text '(lambda (y) (car y))))) + (assert (string= string1 string2))))) (with-test (:name :disassemble-assembly-routine) (disassemble sb-fasl:*assembler-routines* :stream (make-broadcast-stream))) @@ -280,13 +293,14 @@ (with-test (:name :split-seconds-for-sleep) (assert (< (nth-value 1 (sb-impl::split-seconds-for-sleep 7.2993028420866d7)) 1000000000))) -#+x86-64 + +#+(or x86-64 arm64) (with-test (:name :restart-invalid-arg-counts.1) (handler-bind ((error (lambda (c) (invoke-restart (find-restart 'sb-kernel::replace-function c) 'list)))) (assert (equal (eval '(cons 324)) '(324))))) -#+x86-64 +#+(or x86-64 arm64) (with-test (:name :restart-invalid-arg-counts.2) (handler-bind ((error (lambda (c) (invoke-restart (find-restart 'sb-kernel::call-form c) 123)))) @@ -300,3 +314,8 @@ (multiple-value-list (funcall fun '(1 2 3 4 5 6 7 8 . 10)))) '(1 2 3 4 5 6 7 8))))) + +(with-test (:name :no-v0p-ex1stsp-in-build ; spelled L33t Hax0r style on purpose + :skipped-on (or :sb-devel + :sb-xref-for-internals)) + (assert (null (apropos-list "VOP-EXISTSP")))) diff --git a/tests/interface.test.sh b/tests/interface.test.sh index 2dfb4a9b85..dc79b140a4 100644 --- a/tests/interface.test.sh +++ b/tests/interface.test.sh @@ -28,7 +28,8 @@ tmpscript=$TEST_FILESTEM.lisp-script case "$SBCL_MACHINE_TYPE" in X86-64) cat > $tmpscript <<EOF -(let ((x (make-array (1- (expt 2 32)) :element-type '(unsigned-byte 8)))) +(let ((x (make-array (min (1- array-total-size-limit) (1- (expt 2 32))) + :element-type '(unsigned-byte 8)))) (assert (> (sb-kernel:dynamic-usage) (length x))) ;; prevent compiler from getting too smart... (eval x) diff --git a/tests/interrupt-atomic-incf.impure.lisp b/tests/interrupt-atomic-incf.impure.lisp index 76fa70e5cb..83fe986184 100644 --- a/tests/interrupt-atomic-incf.impure.lisp +++ b/tests/interrupt-atomic-incf.impure.lisp @@ -1,4 +1,4 @@ -#-sb-thread (sb-ext:exit :code 104) +#-sb-thread (invoke-restart 'run-tests::skip-file) (use-package "SB-THREAD") diff --git a/tests/interrupt-consing.impure.lisp b/tests/interrupt-consing.impure.lisp index d47ef337c1..7e4d7ed37a 100644 --- a/tests/interrupt-consing.impure.lisp +++ b/tests/interrupt-consing.impure.lisp @@ -1,4 +1,4 @@ -#-sb-thread (sb-ext:exit :code 104) +#-sb-thread (invoke-restart 'run-tests::skip-file) (use-package "SB-THREAD") diff --git a/tests/interrupted-sleep.impure.lisp b/tests/interrupted-sleep.impure.lisp index 162561ad86..72b4d3176d 100644 --- a/tests/interrupted-sleep.impure.lisp +++ b/tests/interrupted-sleep.impure.lisp @@ -1,4 +1,4 @@ -#-sb-thread (sb-ext:exit :code 104) +#-sb-thread (invoke-restart 'run-tests::skip-file) ;; test that SLEEP actually sleeps for at least the given time, even ;; if interrupted by another thread exiting/a gc/anything diff --git a/tests/join-thread-timeout.impure.lisp b/tests/join-thread-timeout.impure.lisp new file mode 100644 index 0000000000..94a7d9ca0a --- /dev/null +++ b/tests/join-thread-timeout.impure.lisp @@ -0,0 +1,23 @@ +(use-package "SB-THREAD") + +(with-test (:name (:join-thread :timeout) + :broken-on :sb-safepoint + :skipped-on (not :sb-thread)) + (macrolet ((delta-t () '(/ (- (get-internal-real-time) begin) + internal-time-units-per-second))) + (let ((thr (sb-thread:make-thread (lambda () (sleep 10)) :name "thr1")) + (begin (get-internal-real-time))) + (assert-error(join-thread thr :timeout 0.01) join-thread-error) + ;; should not have taken more than 1/10th sec. (and that's being generous) + (assert (< (delta-t) 1/10)) + (sb-thread:terminate-thread thr)) + (let ((cookie (cons t t)) + (thr (sb-thread:make-thread (lambda () (sleep 10)) :name "thr2")) + (begin (get-internal-real-time))) + (assert (eq cookie (join-thread thr :timeout 0.01 :default cookie))) + (assert (< (delta-t) 1/10)) + (sb-thread:terminate-thread thr))) + ;; KLUDGE: JOIN-THREAD would signal an error if the victim threads already indicated + ;; "aborted" status (by failing to store a list of values), so just give them time + ;; to relax and unwind and remove themselves from *ALL-THREADS* + (sleep .25)) diff --git a/tests/join-thread-timeout.pure.lisp b/tests/join-thread-timeout.pure.lisp deleted file mode 100644 index c4c0f0c5ba..0000000000 --- a/tests/join-thread-timeout.pure.lisp +++ /dev/null @@ -1,12 +0,0 @@ -(use-package "SB-THREAD") - -(with-test (:name (:join-thread :timeout) - :skipped-on (not :sb-thread)) - (assert-error - (join-thread (make-join-thread (lambda () (sleep 10))) :timeout 0.01) - join-thread-error) - (let ((cookie (cons t t))) - (assert (eq cookie - (join-thread (make-join-thread (lambda () (sleep 10))) - :timeout 0.01 - :default cookie))))) diff --git a/tests/kill-non-lisp-thread.c b/tests/kill-non-lisp-thread.c index a5cef8c202..63ca1edc76 100644 --- a/tests/kill-non-lisp-thread.c +++ b/tests/kill-non-lisp-thread.c @@ -18,5 +18,5 @@ kill_non_lisp_thread(void) perror("pthread_create"); exit(1); } - pthread_kill(kid, SIGPIPE); + pthread_kill(kid, SIGURG); } diff --git a/tests/kill-non-lisp-thread.impure.lisp b/tests/kill-non-lisp-thread.impure.lisp index 509b0179d0..11fe79eb66 100644 --- a/tests/kill-non-lisp-thread.impure.lisp +++ b/tests/kill-non-lisp-thread.impure.lisp @@ -11,8 +11,7 @@ ;;;; absolutely no warranty. See the COPYING and CREDITS files for ;;;; more information. -#+(or :win32 (not :sb-thread)) -(sb-ext:exit :code 104) +#+(or :win32 (not :sb-thread)) (invoke-restart 'run-tests::skip-file) (use-package :sb-alien) @@ -44,8 +43,8 @@ (push (lambda () (setq receivedp t)) (sb-thread::thread-interruptions sb-thread:*current-thread*)) - #+sb-thruption - ;; On sb-thruption builds, the usual resignalling of SIGPIPE will + #+sb-safepoint + ;; On sb-safepoint builds, the usual resignalling of SIGURG will ;; work without problems, but the signal handler won't ordinarily ;; think that there's anything to be done. Since we're poking at ;; INTERRUPT-THREAD internals anyway, let's help it along. diff --git a/tests/lambda-list.pure.lisp b/tests/lambda-list.pure.lisp index 2dec061d71..63cd0cfeaf 100644 --- a/tests/lambda-list.pure.lisp +++ b/tests/lambda-list.pure.lisp @@ -47,6 +47,15 @@ (error-p (&rest foo &rest bar)) (error-p (&rest foo &optional bar)))) +(with-test (:name :lp1738638) + ;; I really don't like that the name of the keyword to *expect* a failure + ;; is ":allow-failure". It sounds like it's a permission, not a requirement. + (checked-compile '(lambda (&key ((x) 1)) x) :allow-failure t)) + +(with-test (:name :lp1740756) + (checked-compile '(lambda () (declare (special 1))) :allow-failure t) + (checked-compile '(lambda () (declare (special (foo)))) :allow-failure t)) + (with-test (:name (:lambda-list :supplied-p-order 1)) (let ((* 10)) (assert (eql ((lambda (&key (x * *)) () x)) 10)) diff --git a/tests/layouts.pure.lisp b/tests/layouts.pure.lisp new file mode 100644 index 0000000000..dfd3800a80 --- /dev/null +++ b/tests/layouts.pure.lisp @@ -0,0 +1,205 @@ +(with-test (:name :stream-layout-bits) + (loop for wrapper being each hash-value + of (sb-kernel:classoid-subclasses (sb-kernel:find-classoid 't)) + do (flet ((check-bit (bit ancestor-type) + (let ((ancestor (sb-kernel:find-layout ancestor-type))) + (when (or (eq wrapper ancestor) + (find ancestor (sb-kernel:wrapper-inherits wrapper))) + (assert (logtest bit (sb-kernel:wrapper-flags wrapper))))))) + (check-bit sb-kernel:+stream-layout-flag+ 'stream) + (check-bit sb-kernel:+string-stream-layout-flag+ 'string-stream) + (check-bit sb-kernel:+file-stream-layout-flag+ 'file-stream)))) + +(with-test (:name :boxed-layout-bits) + ;; Negative test + (dolist (name '(hash-table sb-thread:thread sb-thread::avlnode)) + (let ((layout (sb-kernel:find-layout name))) + (assert (not (logtest (sb-kernel:wrapper-flags layout) + sb-kernel:+strictly-boxed-flag+))))) + ;; Positive test, just a small sampling + (dolist (name '(condition warning error + pathname logical-pathname + sb-impl::string-output-stream + structure-object sb-c::node + fundamental-stream)) + (let ((layout (sb-kernel:find-layout name))) + (assert (logtest (sb-kernel:wrapper-flags layout) + sb-kernel:+strictly-boxed-flag+))))) + +;;; Test some aspects of bitmaps, and the iterator. + +;;; A layout-bitmap has the same representation as a BIGNUM- +;;; least-significant word first, native endian within the word. +;;; Like a bignum, all but the last word are unsigned, and the last is signed. +;;; This representation allows trailing slots to be either all tagged +;;; or all untagged. + +(defun ld (x) (sb-kernel:layout-depthoid (truly-the sb-vm::layout x))) +(compile 'ld) + +(defstruct d2) +(defstruct (d3 (:include d2))) +(defstruct (d4 (:include d3))) +(defstruct (d5 (:include d4))) +(defstruct (d6 (:include d5))) +(defstruct (d7 (:include d6))) +(defstruct (d8 (:include d7))) +(defstruct (d9 (:include d8))) +(defstruct (d10 (:include d9))) +(defstruct (d11 (:include d10))) +(defstruct (d12 (:include d11))) +(defstruct (d13 (:include d12))) +(defstruct (d14 (:include d13))) +(defstruct (d15 (:include d14))) + +(defparameter *test-layouts* + (coerce (list* (sb-kernel:find-layout 't) + (sb-kernel:find-layout 'structure-object) + (loop for i from 2 to 15 + collect (sb-kernel:find-layout (intern (format nil "D~D" i))))) + 'vector)) + +;;; Assert that BITMAP-NWORDS is insensitive to depthoid +(with-test (:name :bitmap-nwords-1) + (loop for depthoid from 3 to 16 + do + (let ((layout (sb-kernel:make-layout + 1 ; random hash + (sb-kernel:make-undefined-classoid 'blah) + :depthoid depthoid + :bitmap #+64-bit #x6fffffffeeeeff02 ; 1-word bignum + #-64-bit #x70ffe123 + :inherits (subseq *test-layouts* 0 depthoid) + :flags sb-kernel:+structure-layout-flag+))) + (assert (= (sb-kernel:bitmap-nwords layout) 1))))) +(with-test (:name :bitmap-nwords-2) + (loop for depthoid from 3 to 16 + do + (let ((layout (sb-kernel:make-layout + 1 ; random hash + (sb-kernel:make-undefined-classoid 'blah) + :depthoid depthoid + :bitmap #+64-bit #xffffffffeeeeff02 ; 2-word bignum + #-64-bit #x80ffe123 + :inherits (subseq *test-layouts* 0 depthoid) + :flags sb-kernel:+structure-layout-flag+))) + (assert (= (sb-kernel:bitmap-nwords layout) 2))))) + +(defun layout-id-vector-sap (layout) + (sb-sys:sap+ (sb-sys:int-sap (sb-kernel:get-lisp-obj-address layout)) + (- (ash (+ sb-vm:instance-slots-offset + (sb-kernel:get-dsd-index sb-vm:layout sb-kernel::id-word0)) + sb-vm:word-shift) + sb-vm:instance-pointer-lowtag))) + +;;;; Ensure ID uniqueness and that layout ID words match the ID's in the INHERITS vector. +(defparameter *all-wrappers* + (delete-if + ;; temporary layouts (created for parsing DEFSTRUCT) + ;; must be be culled out. + (lambda (x) + (and (typep (sb-kernel:wrapper-classoid x) + 'sb-kernel:structure-classoid) + (eq (sb-kernel:wrapper-equalp-impl x) + #'sb-kernel::equalp-err))) + (sb-vm::list-allocated-objects :all + :type sb-vm:instance-widetag + :test #'sb-kernel::wrapper-p))) + +;;; Assert no overlaps on ID +(with-test (:name :id-uniqueness) + (let ((hash (make-hash-table))) + (dolist (wrapper *all-wrappers*) + (let ((id (sb-kernel:layout-id wrapper))) + (sb-int:awhen (gethash id hash) + (error "ID ~D is ~A and ~A" id sb-int:it wrapper)) + (setf (gethash id hash) wrapper))))) + +;;; Assert that IDs are right +(with-test (:name :id-versus-inherits) + (let ((structure-object (sb-kernel:find-layout 'structure-object))) + (dolist (wrapper *all-wrappers*) + (when (find structure-object (sb-kernel:wrapper-inherits wrapper)) + (let* ((layout (sb-kernel:wrapper-friend wrapper)) + (ids + (sb-sys:with-pinned-objects (layout) + (let ((sap (layout-id-vector-sap layout))) + (loop for depthoid from 2 to (sb-kernel:wrapper-depthoid wrapper) + collect (sb-sys:signed-sap-ref-32 sap (ash (- depthoid 2) 2)))))) + (expected + (map 'list 'sb-kernel:layout-id (sb-kernel:wrapper-inherits wrapper)))) + (unless (equal (list* (sb-kernel:layout-id (sb-kernel:find-layout 't)) + (sb-kernel:layout-id (sb-kernel:find-layout 'structure-object)) + ids) + (append expected (list (sb-kernel:layout-id wrapper)))) + (error "Wrong IDs for ~A: expect ~D actual ~D~%" + wrapper expected ids))))))) + +(makunbound '*all-wrappers*) + +(defun random-bitmap (nwords random-state sign-bit) + (let ((integer 0) + (position 0)) + ;; Deposit N-WORD-BITS bits into INTEGER NWORDS times, + ;; then make sure the sign bit is as requested. + (dotimes (i nwords) + (setf (ldb (byte sb-vm:n-word-bits position) integer) + ;; If the PRNG generates a 0 word, change it to 1. + (max 1 (random (ash 1 sb-vm:n-word-bits) random-state))) + (incf position sb-vm:n-word-bits)) + ;; If INSTANCE-DATA-START is 1, then the 0th bitmap bit must be 0 + ;; because we don't want LAYOUT to be lumped in with tagged slots + ;; (even though it's of course tagged) + (when (and (= sb-vm:instance-data-start 1) (oddp integer)) + (setq integer (logxor integer 1))) + (ecase sign-bit + (:positive + (ldb (byte (1- (* nwords sb-vm:n-word-bits)) 0) integer)) + (:negative + (dpb integer (byte (1- (* nwords sb-vm:n-word-bits)) 0) -1))))) +(compile'random-bitmap) + +;;; Check the random bitmap generator a little. +(with-test (:name :check-random-bitmaps) + (loop for nwords from 2 to 8 + do (dolist (sign '(:positive :negative)) + (dotimes (i 100) + (let ((b (random-bitmap nwords *random-state* sign))) + (assert (= (sb-bignum:%bignum-length b) nwords))))))) + +(defun make-layout-for-test (depthoid bitmap) + (sb-kernel:make-layout 1 ; random hash + (sb-kernel:make-undefined-classoid 'blah) + :depthoid depthoid + :bitmap bitmap + :inherits (subseq *test-layouts* 0 depthoid) + :flags sb-kernel:+structure-layout-flag+)) +(compile 'make-layout-for-test) + +(defun test-bitmap-iterator (layout instance-length reference-bitmap) + (let ((count 0)) + (declare (fixnum count)) + (sb-kernel:do-layout-bitmap (slot-index taggedp layout instance-length) + (incf count) + (sb-int:aver (eq (logbitp slot-index reference-bitmap) taggedp))) + (sb-int:aver (= count (- instance-length sb-vm:instance-data-start))))) +(compile 'test-bitmap-iterator) + +;;; Now randomly test bitmaps of varying length in words +;;; and for both values of the sign bit in the last word. +;;; Test with instances that are longer than the bitmap's significant bit count +;;; so that we can verify infinite sign-extension. +;;; And test with shorter to make sure the loop is properly bounded +;;; by the instance length. +(with-test (:name :random-bitmaps) + (let ((rs (make-random-state t))) + ;; Modulate the depthoid so that BITMAP-START is at different indices. + (loop for depthoid from 6 to 10 + do (loop for n-bitmap-words from 1 to 6 + do + (dolist (sign '(:positive :negative)) + (let* ((bitmap (random-bitmap n-bitmap-words rs sign)) + (layout (make-layout-for-test depthoid bitmap))) + (loop for instance-length from 5 to (* (+ n-bitmap-words 2) + sb-vm:n-word-bits) + do (test-bitmap-iterator layout instance-length bitmap)))))))) diff --git a/tests/load.impure.lisp b/tests/load.impure.lisp index d2dff70d04..b395b8fe5a 100644 --- a/tests/load.impure.lisp +++ b/tests/load.impure.lisp @@ -221,9 +221,11 @@ (with-test-program source nil (load-and-assert partial source source)))) +(when (find-symbol "%LOAD-TRUENAME" "SB-FASL") (push :no-test-load-truename *features*)) + ;; Test loading a source file whose name lacks a type when supplying a ;; partial pathname. -(with-test (:name :load-source-file-default-type) +(with-test (:name :load-source-file-default-type :skipped-on :no-test-load-truename) (let ((source (make-pathname :type :unspecific :defaults *tmp-lisp-filename*)) (partial (make-pathname :defaults *tmp-lisp-filename* @@ -249,7 +251,7 @@ ;; Test loading a fasl whose name lacks a type when supplying a ;; partial pathname. -(with-test (:name :load-fasl-file-defaut-type) +(with-test (:name :load-fasl-file-default-type :skipped-on :no-test-load-truename) (let* ((source *tmp-lisp-filename*) (fasl (make-pathname :type :unspecific :defaults (compile-file-pathname source))) @@ -259,7 +261,7 @@ (load-and-assert partial partial partial)))) ;; Test loading a fasl with a strange type -(with-test (:name :load-fasl-file-strange-type) +(with-test (:name :load-fasl-file-strange-type :skipped-on :no-test-load-truename) (let* ((source *tmp-lisp-filename*) (fasl (make-pathname :defaults (compile-file-pathname source) :type "compiled-lisp"))) @@ -270,7 +272,9 @@ ;; Ensure that loading a fasl specified with a type checks for the ;; header. -(with-test (:name :load-fasl-header-missing-1) +(with-test (:name :load-fasl-header-missing-1 + ;; somehow the header needs to get tested without a pre-test of the file length + :skipped-on :no-test-load-truename) (let* ((source *tmp-lisp-filename*) (fasl (compile-file-pathname source))) (with-test-program source fasl @@ -285,7 +289,9 @@ ;; src/code/target-load.lisp v1.40 and earlier (SBCL version 1.0.12.35 ;; or so). If target-load.lisp is reverted to that state eventually, ;; this test should be removed (or that definition of LOAD altered). -(with-test (:name :load-fasl-header-missing-2) +(with-test (:name :load-fasl-header-missing-2 + ;; this test is probably bad for for the same reason the STRANGE-TYPE test is + :skipped-on :no-test-load-truename) (let* ((source *tmp-lisp-filename*) (fasl (compile-file-pathname source)) (fasl-spec (make-pathname :type nil @@ -434,13 +440,8 @@ (let ((*standard-output* s)) (load output :print t)) (delete-file output) - (assert (string= (get-output-stream-string s) -";; SOME-FANCY-MACRO -;; *SOME-VAR* -;; MY-FAVORITE-TYPE -;; FRED -;; (A)")) - (delete-file *tmp-filename*))) + (assert (not (string= (get-output-stream-string s) ""))) + (delete-file *tmp-filename*))) (with-test (:name :load-reader-error) (unwind-protect diff --git a/tests/lockfree-list.impure.lisp b/tests/lockfree-list.impure.lisp index 2ebe6d1312..77c5474fc5 100644 --- a/tests/lockfree-list.impure.lisp +++ b/tests/lockfree-list.impure.lisp @@ -1,6 +1,13 @@ (in-package "SB-LOCKLESS") -#-gencgc (sb-ext:exit :code 104) +(test-util:with-test (:name :layout-bits) + (dolist (type '(list-node keyed-node)) + (assert (eq (sb-kernel::dd-%element-type + (sb-kernel:find-defstruct-description type)) + '*)) + (assert (not (logtest (sb-kernel:wrapper-flags (find-layout type)) + sb-kernel::+strictly-boxed-flag+))))) + ;;; Make sure no promotions occur so that objects will be movable ;;; throughout these tests. @@ -61,9 +68,10 @@ (gc) (when show (show (list-head *lfl*) #'get-next "del ")))) +;; Enable heap validity tester +#+gencgc (setf (sb-alien:extern-alien "verify_gens" char) 0) + (test-util:with-test (:name :lockfree-list-gc-correctness) - ;; Enable heap validity tester - (setf (sb-alien:extern-alien "verify_gens" char) 0) ;; Create a small list and perform logical deletion of 2 nodes (makelflist 10) (gc)) ; Verify no post-gc crash @@ -182,7 +190,9 @@ (let* ((anode *5*) (next (%node-next anode))) (assert (fixnump next)) - (with-pinned-objects (anode) + ;; maybe this should be a keyword to WITH-PINNED-OBJECTS saying + ;; to explicitly cons onto the list of pins? + (let ((sb-vm::*pinned-objects* (cons anode sb-vm::*pinned-objects*))) (gc) ;; nowhere do we reference node *10* in this test, ;; so there's no reason the GC should want not to move that node @@ -203,3 +213,75 @@ (assert (= (sb-kernel:generation-of *10*) 0)) (assert (not (eql (get-lisp-obj-address *10*) *addr-of-10*)))) + + +(defun scan-pointee-gens (page &optional print) + (unless (zerop (sb-alien:slot (sb-alien:deref sb-vm::page-table page) 'sb-vm::start)) + (warn "Can't properly scan: page start is a lower address")) + (sb-sys:without-gcing + (let* ((where (sb-sys:sap+ (sb-sys:int-sap sb-vm:dynamic-space-start) + (* page sb-vm:gencgc-page-bytes))) + (limit (sb-sys:sap+ where sb-vm:gencgc-page-bytes)) + (gens 0)) + (do ((where where (sb-sys:sap+ where sb-vm:n-word-bytes))) + ((sap>= where limit) gens) + (let* ((word (sb-sys:sap-ref-word where 0)) + (targ-page) + (gen (when (and (sb-vm:is-lisp-pointer word) + (>= (setq targ-page (sb-vm:find-page-index word)) 0)) + (sb-alien:slot (sb-alien:deref sb-vm::page-table targ-page) + 'sb-vm::gen)))) + (when gen (setq gens (logior gens (ash 1 gen)))) + (when print + (sb-alien:alien-funcall + (sb-alien:extern-alien "printf" + (function sb-alien:void system-area-pointer + system-area-pointer + sb-alien:unsigned + sb-alien:unsigned)) + (sb-sys:vector-sap (if gen #.(format nil "%p: %p -> %d~%") #.(format nil "%p: %p~%"))) + where word (or gen 0)))))))) + +;;; Make sure promotions do occur. +(setf (generation-number-of-gcs-before-promotion 0) 1) + +(defstruct foo a b c) +(defparameter *l* nil) +(defun construct (n) + (setq *l* (make-ordered-list :key-type 'fixnum)) + (loop for key from 10 by 10 repeat n do (lfl-insert *l* key (make-foo :a key)))) + +(defun scan-lfl-gens (deletep &aux page-indices) + (do ((node (get-next (list-head *l*)) ; can't delete the dummy node (list head) + (get-next node))) + ((eq node *tail-atom*)) + (when (eql (generation-of node) 1) + (let ((page (sb-vm:find-page-index + (sb-kernel:get-lisp-obj-address node)))) + (pushnew page page-indices))) + (let ((succ (get-next node))) + (when (and (eql (generation-of node) 1) + (eql (generation-of succ) 0) + deletep) + ;; Logically delete NODE, turning its successor pointer untagged. + (format t "~A (deleting) -> ~A~%" node succ) + (with-pinned-objects (succ) + (cas (%node-next node) succ (make-marked-ref succ)))))) + (dolist (page page-indices) + (format t "Page ~d -> ~b~%" page (scan-pointee-gens page)))) + +(defun test-fixnum-as-pointer () + (construct 250) + (gc :gen 1) + (loop for key from 15 by 400 repeat 10 do (lfl-insert *l* key (- key))) + ;; For informational purposes, print the page number on which any node + ;; of *L* is present, and the bitmask of generations to which that page points. + (scan-lfl-gens nil) + ;; Now logically delete any node on a generation 1 page that points + ;; to a generation 0 page. The deletion algorithm first marks the NEXT + ;; pointer on the node being deleted, where "mark" equates to turning + ;; the successor pointer to an untagged pointer. + (scan-lfl-gens t) + (gc)) + +(test-util:with-test (:name :lfl-hidden-pointers) (test-fixnum-as-pointer)) diff --git a/tests/loop.impure.lisp b/tests/loop-2.pure.lisp similarity index 92% rename from tests/loop.impure.lisp rename to tests/loop-2.pure.lisp index f553ac78c9..b95c670b8b 100644 --- a/tests/loop.impure.lisp +++ b/tests/loop-2.pure.lisp @@ -11,12 +11,9 @@ ;;;; absolutely no warranty. See the COPYING and CREDITS files for ;;;; more information. -(in-package "CL-USER") - ;;; Bug 49b, reported by Peter Van Eynde 2000-07-25, was fixed by ;;; Alexey Dejneka's patch on sbcl-devel 2001-09-30. ;;; -;;; (This test is impure because we create a scratch package to work with.) (let ((package (make-package "loop-test-scratch"))) (intern "blah" package) (let ((blah2 (intern "blah2" package))) diff --git a/tests/loop.pure.lisp b/tests/loop.pure.lisp index f353f66a1b..16ecf849ac 100644 --- a/tests/loop.pure.lisp +++ b/tests/loop.pure.lisp @@ -90,7 +90,7 @@ (assert (= (loop for nil being the external-symbols of :cl count t) 978)) (assert (= (loop for x being the external-symbols of :cl count x) 977)) -(let ((*package* (find-package :cl))) +(let ((cl:*package* (find-package :cl))) (assert (= (loop for x being each external-symbol count t) 978))) (assert (eq (loop for a = (return t) return nil) t)) @@ -428,7 +428,7 @@ (assert-no-signal (compile nil '(lambda () (declare (optimize speed)) - (loop repeat (+ 1 5) for baz = 'this then 'that + (loop for baz = 'this then 'that repeat (+ 1 5) do (print baz)))))) (with-test (:name :loop-default-init-type) @@ -454,6 +454,7 @@ for (a b) = (multiple-value-list (floor i 5)) sum (+ a b)))) (ctu:assert-no-consing (f 1000)))) + (with-test (:name :destructuring-m-v-list-with-nil) (assert (equal-mod-gensyms (macroexpand-1 '(sb-loop::loop-desetq (x nil z) (multiple-value-list (foo)))) @@ -461,3 +462,20 @@ (declare (ignore g2)) (sb-loop::loop-desetq x g1) (sb-loop::loop-desetq z g3))))) + +(with-test (:name :collect-list-type) + (assert + (equal (third (sb-kernel:%simple-fun-type + (checked-compile + '(lambda (l) + (loop for x in l + collect x into m + finally (return m)))))) + '(values list &optional))) + (assert + (equal (third (sb-kernel:%simple-fun-type + (checked-compile + '(lambda (l) + (loop for x in l + collect x))))) + '(values list &optional)))) diff --git a/tests/macroexpand.impure.lisp b/tests/macroexpand.impure.lisp index f5f60697f8..ae7b0f8d79 100644 --- a/tests/macroexpand.impure.lisp +++ b/tests/macroexpand.impure.lisp @@ -28,8 +28,6 @@ (assert (equal (let ((glob nil)) (push 'foo glob) glob) '(foo))) (assert (null glob)) - - ;;; CLHS 3.1.2.1.1 specifies that symbol macro expansion must also ;;; go through *MACROEXPAND-HOOK*. (2007-09-22, -TCR.) @@ -40,11 +38,23 @@ ;;; as :compile, but now we support running the test suite with any ;;; *evaluator-mode*, so must explicitly COMPILE the macroexpand hook. ;;; Notice that the lambda expressions being compiled are closures. -;;; This is allowed by sb-interpreter but not sb-eval. +;;; This is allowed by sb-interpreter. sb-eval gets an error +;;; "Unhandled INTERPRETER-ENVIRONMENT-TOO-COMPLEX-ERROR: +;;; Lexical environment of #<INTERPRETED-FUNCTION NIL {1001850EBB}> +;; is too complex to compile." + +;;; Like CHECKED-COMPILE, this disallows unexpected warnings. +;;; But unlike CHECKED-COMPILE, it allows the argument to be a function. +(defun compilefun (fun) + (multiple-value-bind (result warnp errorp) + (compile nil fun) + (assert (not warnp)) + (assert (not errorp)) + result)) (let* ((expanded-p nil) (*macroexpand-hook* - (compile nil #'(lambda (fn form env) + (compilefun #'(lambda (fn form env) (when (eq form '.foo.) (setq expanded-p t)) (funcall fn form env))))) @@ -57,7 +67,7 @@ (let ((sb-ext:*evaluator-mode* :interpret)) (let* ((expanded-p nil) (*macroexpand-hook* - (compile nil #'(lambda (fn form env) + (compilefun #'(lambda (fn form env) (when (eq form '.foo.) (setq expanded-p t)) (funcall fn form env))))) @@ -66,7 +76,7 @@ (let* ((expanded-p nil) (*macroexpand-hook* - (compile nil #'(lambda (fn form env) + (compilefun #'(lambda (fn form env) (when (eq form '/foo/) (setq expanded-p t)) (funcall fn form env))))) @@ -221,12 +231,14 @@ (defmacro capture-env (&environment e &rest r) (declare (ignore r)) e) -(with-test (:name :macroexpand-of-setf-structure-access) - (assert (equal (macroexpand-1 '(setf (foo-a x) 3)) - `(sb-kernel:%instance-set (the foo x) - ,sb-vm:instance-data-start - (sb-kernel:the* (fixnum :context (:struct foo . a)) 3)))) - +(with-test (:name :macroexpand-setf-instance-ref.1) + (assert (equal-mod-gensyms + (macroexpand-1 '(setf (foo-a x) 3)) + `(let ((#1=instance (the foo x)) + (#2=val (sb-kernel:the* (fixnum :context (:struct foo . a)) 3))) + (sb-kernel:%instance-set #1# #.sb-vm:instance-data-start #2#) + #2#)))) +(with-test (:name :macroexpand-setf-instance-ref.2) ;; Lexical definition of (SETF FOO-A) inhibits source-transform. ;; This is not required behavior - SETF of structure slots ;; do not necessarily go through a function named (SETF your-slot), @@ -384,21 +396,8 @@ (assert (equal (funcall f 'o) '(o p))) (assert (eql (funcall f 42) -1)))) -;;; There was a minor glitch in the typecase->case optimizer causing -;;; duplicate layouts to appear, but the correct clause was picked -;;; by good fortune. Assert that there are no duplicates now. -#+#.(cl:if (cl:gethash 'sb-c:multiway-branch-if-eq sb-c::*backend-template-names*) - '(:and) - '(:or)) -(with-test (:name :sealed-struct-typecase-map) - (let (all-layouts) - (sb-int:dovector (bin (subseq (sb-impl::build-sealed-struct-typecase-map - '((sb-kernel:ansi-stream synonym-stream - sb-sys:fd-stream broadcast-stream - two-way-stream concatenated-stream echo-stream) - (broadcast-stream))) - 1)) - (dolist (cell bin) - (let ((layout (car cell))) - (assert (not (member layout all-layouts))) - (push layout all-layouts)))))) +(defmacro macro-with-dotted-list (&rest args) + args) +(with-test (:name :macro-with-dotted-list) + (let ((expansion (macroexpand '(macro-with-dotted-list . 1)))) + (assert (equal expansion 1)))) diff --git a/tests/make-thread.pure.lisp b/tests/make-thread.pure.lisp new file mode 100644 index 0000000000..2db2ed7923 --- /dev/null +++ b/tests/make-thread.pure.lisp @@ -0,0 +1,162 @@ +#+cheneygc (invoke-restart 'run-tests::skip-file) + +(shadow "ASSERT-ERROR") ; conflict between SB-KERNEL:ASSERT-ERROR, ASSERTOID:ASSERT-ERROR +(use-package "SB-KERNEL") +(use-package "SB-THREAD") +(import 'sb-sys::(int-sap sap-int sap+ vector-sap without-gcing)) +(import 'sb-int::(binding* descriptor-sap)) + +;;; Test out-of-memory (or something) that goes wrong in pthread_create +#+sb-thread ; no SB-THREAD::OS-THREAD-CREATE symbol if not +(test-util:with-test (:name :failed-thread-creation) + ;; This test needs to ensure that nothing is in *ALL-THREADS* to begin with. + (sb-thread::%dispose-thread-structs) + (let ((encapsulation + (compile nil + '(lambda (realfun thread stack-base) + (if (sb-thread:thread-ephemeral-p thread) + (funcall realfun thread stack-base) + nil)))) + (success)) + (sb-int:encapsulate 'sb-thread::os-thread-create 'test encapsulation) + (unwind-protect + (handler-case (make-thread #'list :name "thisfails") + (error (e) + (setq success (search "Could not create new OS thread" (write-to-string e))))) + (sb-int:unencapsulate 'sb-thread::os-thread-create 'test)) + (assert success)) + (let ((threads sb-thread::*starting-threads*)) + (when (find-if-not #'thread-ephemeral-p threads) + (error "Should not see new thread in starting list: ~S" threads))) + (let ((threads (remove sb-thread::*initial-thread* + (sb-thread::avltree-list sb-thread::*all-threads*)))) + (when (find-if-not #'thread-ephemeral-p threads) + (error "Should not see new thread in running list: ~S" threads)))) + +(defun actually-get-stack-roots (current-sp + &key allwords (print t) + &aux (current-sp (descriptor-sap current-sp)) + (roots)) + (declare (type (member nil t :everything) allwords)) + (without-gcing + (binding* ((stack-low (get-lisp-obj-address sb-vm:*control-stack-start*)) + (stack-high (get-lisp-obj-address sb-vm:*control-stack-end*)) + ((nwords copy-from direction base) + #+c-stack-is-control-stack ; growth direction is always down + (values (ash (- stack-high (sap-int current-sp)) (- sb-vm:word-shift)) + current-sp #\- "sp") + #-c-stack-is-control-stack ; growth direction is always up + (values (ash (- (sap-int current-sp) stack-low) (- sb-vm:word-shift)) + (int-sap stack-low) #\+ "base")) + (array (make-array nwords :element-type 'sb-ext:word))) + (when print + (format t "SP=~a~dw (range = ~x..~x)~%" direction nwords stack-low stack-high)) + (alien-funcall (extern-alien "memcpy" (function void system-area-pointer + system-area-pointer unsigned)) + (vector-sap array) copy-from (* nwords sb-vm:n-word-bytes)) + (loop for i downfrom (1- nwords) to 0 by 1 do + (let ((word (aref array i))) + (when (or (/= word sb-vm:nil-value) allwords) + (let ((baseptr (alien-funcall (extern-alien "search_all_gc_spaces" (function unsigned unsigned)) + word))) + (cond ((/= baseptr 0) ; an object reference + (let ((obj (sb-vm::reconstitute-object (%make-lisp-obj baseptr)))) + (when (code-component-p obj) + (cond + #+(or c-stack-is-control-stack arm64 riscv) + ((= (logand word sb-vm:lowtag-mask) sb-vm:fun-pointer-lowtag) + (dotimes (i (code-n-entries obj)) + (when (= (get-lisp-obj-address (%code-entry-point obj i)) word) + (return (setq obj (%code-entry-point obj i)))))) + #-(or c-stack-is-control-stack arm64 riscv) ; i.e. does this backend have LRAs + ((= (logand (sb-sys:sap-ref-word (int-sap (logandc2 word sb-vm:lowtag-mask)) 0) + sb-vm:widetag-mask) sb-vm:return-pc-widetag) + (setq obj (%make-lisp-obj word))))) + ;; interior pointers to objects that contain instructions are OK, + ;; otherwise only correctly tagged pointers. + (when (or (typep obj '(or fdefn code-component funcallable-instance)) + (= (get-lisp-obj-address obj) word)) + (push obj roots) + (when print + (format t "~x = ~a[~5d] = ~16x (~A) " + (sap-int (sap+ copy-from (ash i sb-vm:word-shift))) + base i word + (or (generation-of obj) #\S)) ; S is for static + (let ((*print-pretty* nil)) + (cond ((consp obj) (format t "a cons")) + #+sb-fasteval + ((typep obj 'sb-interpreter::sexpr) (format t "a sexpr")) + ((arrayp obj) (format t "a ~s" (type-of obj))) + #+c-stack-is-control-stack + ((and (code-component-p obj) + (>= word (sap-int (code-instructions obj)))) + (format t "PC in ~a" obj)) + (t (format t "~a" obj)))) + (terpri))))) + ((and print + (or (eq allwords :everything) (and allwords (/= word 0)))) + (format t "~x = ~a[~5d] = ~16x~%" + (sap-int (sap+ copy-from (ash i sb-vm:word-shift))) + base i word))))))))) + (if print + (format t "~D roots~%" (length roots)) + roots)) +(compile 'actually-get-stack-roots) +(defun get-stack-roots (&rest rest) + (apply #'actually-get-stack-roots (%make-lisp-obj (sap-int (current-sp))) rest)) + +(defstruct big-structure x) +(defstruct other-big-structure x) +(defun make-a-closure (arg options) + (lambda (&optional (z 0) y) + (declare (ignore y)) + (test-util:opaque-identity + (format nil "Ahoy-hoy! ~d~%" (+ (big-structure-x arg) z))) + (apply #'get-stack-roots options))) +(defun tryit (&rest options) + (let ((thread + (make-thread (make-a-closure (make-big-structure :x 0) options) + :arguments (list 1 (make-other-big-structure))))) + ;; Sometimes the THREAD instance shows up in the list of objects + ;; on the stack, sometimes it doesn't. This is annoying, but work around it. + (remove thread (join-thread thread)))) + +(defun make-a-closure-nontail (arg) + (lambda (&optional (z 0) y) + (declare (ignore y)) + (get-stack-roots) + (test-util:opaque-identity + (format nil "Ahoy-hoy! ~d~%" (+ (big-structure-x arg) z))) + 1)) +(defun tryit-nontail () + (join-thread + (make-thread (make-a-closure-nontail (make-big-structure :x 0)) + :arguments (list 1 (make-other-big-structure))))) + +;;; Test that reusing memory from an exited thread does not point to junk. +;;; In fact, assert something stronger: there are no young objects +;;; between the current SP and end of stack. +(test-util:with-test (:name :expected-gc-roots + :skipped-on (or :interpreter (not :sb-thread))) + (let ((list + (delete-if (lambda (x) + (or (eq x #'actually-get-stack-roots) + (eq x (sb-kernel:fun-code-header #'actually-get-stack-roots)))) + (tryit :print nil)))) + ;; should be not many things pointed to by the stack + (assert (< (length list) #+x86 38 ; more junk, I don't know why + #+x86-64 30 ; less junk, I don't know why + #-(or x86 x86-64) 44)) ; even more junk + ;; Either no objects are in GC generation 0, or all are, depending on + ;; whether CORE_PAGE_GENERATION has been set to 0 for testing. + (let ((n-objects-in-g0 (count 0 list :key #'sb-kernel:generation-of))) + (assert (or (= n-objects-in-g0 0) + (= n-objects-in-g0 (length list))))))) + +;; lp#1595699 +(test-util:with-test (:name :start-thread-in-without-gcing + :skipped-on (not :sb-thread)) + (assert (eq (join-thread + (without-gcing + (make-thread (lambda () 'hi)))) + 'hi))) diff --git a/tests/map-refs.pure.lisp b/tests/map-refs.pure.lisp new file mode 100644 index 0000000000..807a29651b --- /dev/null +++ b/tests/map-refs.pure.lisp @@ -0,0 +1,14 @@ +;;; Make sure MAP-REFERENCING-OBJECTS doesn't spuriously treat raw bits as +;;; potential pointers. Also make sure it sees the SYMBOL-INFO slot. +(defstruct afoo (slot nil :type sb-ext:word)) +(defvar *afoo* (make-afoo :slot (sb-kernel:get-lisp-obj-address '*posix-argv*))) +(with-test (:name :map-referencing-objs) + (sb-vm::map-referencing-objects (lambda (x) (assert (not (typep x 'afoo)))) + :dynamic '*posix-argv*) + (let ((v (sb-kernel:symbol-%info 'satisfies)) referers) + (sb-vm::map-referencing-objects (lambda (referer) (push referer referers)) + #+gencgc :dynamic #-gencgc :static v) + #+immobile-space + (sb-vm::map-referencing-objects (lambda (referer) (push referer referers)) + :immobile v) + (assert (member 'satisfies referers)))) diff --git a/tests/map-tests.impure.lisp b/tests/map-tests.pure.lisp similarity index 98% rename from tests/map-tests.impure.lisp rename to tests/map-tests.pure.lisp index 23cd776cb7..0bb073d4ac 100644 --- a/tests/map-tests.impure.lisp +++ b/tests/map-tests.pure.lisp @@ -223,3 +223,9 @@ (test 'mapcar (list #'list '(1 2 3) '(4 5 6) '(7 8 9)) '((1 4 7) (2 5 8) (3 6 9))) (test 'mapcan (list #'identity '(1)) 1))) + +(with-test (:name (map :initial-element-style-warnin)) + (checked-compile-and-assert + () + `(lambda (x) + (map '(vector hash-table) #'identity x)))) diff --git a/tests/mlf.impure-cload.lisp b/tests/mlf.impure-cload.lisp new file mode 100644 index 0000000000..cbe60c2a93 --- /dev/null +++ b/tests/mlf.impure-cload.lisp @@ -0,0 +1,20 @@ +(eval-when (:compile-toplevel :load-toplevel :execute) + (defstruct fool x)) +(eval-when (:compile-toplevel) + (defmethod make-load-form ((self fool) &optional env) + (declare (ignore env)) + `(make-fool :x ,(fool-x self))) + (defparameter *crashy* t) + (defmethod print-object ((self fool) stream) + (if *crashy* + (progn + (setq *crashy* nil) + (error "Sorry!")) + (call-next-method)))) + +;;; We used to try to "name" everything dumped. +;;; If nothing else, the name should have been written with :READABLY NIL +;;; just in case it was going to signal print-not-readable. +;;; Now we don't print-object at all. +(defvar *foolz* + '#.(list (make-fool :x 1) (make-fool :x 2))) diff --git a/tests/mop-32.impure.lisp b/tests/mop-32.impure.lisp new file mode 100644 index 0000000000..8791731e85 --- /dev/null +++ b/tests/mop-32.impure.lisp @@ -0,0 +1,75 @@ +;;;; Handling errors in UPDATE-INSTANCE-FOR-REDEFINED-CLASS + +;;;; This software is part of the SBCL system. See the README file for +;;;; more information. +;;;; +;;;; While most of SBCL is derived from the CMU CL system, the test +;;;; files (like this one) were written from scratch after the fork +;;;; from CMU CL. +;;;; +;;;; This software is in the public domain and is provided with +;;;; absolutely no warranty. See the COPYING and CREDITS files for +;;;; more information. + +(defclass foo-class (standard-class) ()) + +(defmethod sb-mop:validate-superclass ((c foo-class) (s standard-class)) t) + +(defclass foo-object (standard-object) ()) + +(defmethod shared-initialize :around ((class foo-class) slot-names + &rest rest + &key direct-superclasses) + (apply #'call-next-method + class slot-names + :direct-superclasses + (append (remove (find-class 'standard-object) direct-superclasses) + (list (find-class 'foo-object))) + rest)) + +(defmethod update-instance-for-redefined-class :before + ((instance foo-object) + added-slots discarded-slots + property-list + &rest initargs) + (declare (ignore initargs)) + ;; This U-I-F-R-C is meant to always signal an error. + (error "expected failure")) + +;;; Define FOO. +(defclass foo () () (:metaclass foo-class)) + +;;; Make an instance of FOO. +(defparameter *foo* (make-instance 'foo)) + +;;; Redefine FOO, causing *FOO* to become obsolete. +(defclass foo () + ((slot :initform 42)) + (:metaclass foo-class)) + +;;; This should result in an "expected failure" error, because +;;; the instance is obsolete. +(multiple-value-bind (result error) + (ignore-errors (slot-value *foo* 'slot)) + (assert (null result)) + (assert (string= (princ-to-string error) "expected failure"))) + +;;; This should *also* result in an "expected failure" error, because after +;;; the previous U-I-F-R-C call made a non-local exit, the instance should be +;;; automatically made obsolete once more. +(multiple-value-bind (result error) + (ignore-errors (slot-value *foo* 'slot)) + (assert (null result)) + (assert (string= (princ-to-string error) "expected failure"))) + +;;; Redefine the U-I-F-R-C method to no longer signal an error. +(defmethod update-instance-for-redefined-class :before + ((instance foo-object) + added-slots discarded-slots + property-list + &rest initargs) + (declare (ignore initargs))) + +;;; Instance is now updateable. It should now be possible to access the new slot +;;; and fetch its initform-initialized value. +(assert (= 42 (slot-value *foo* 'slot))) diff --git a/tests/mop-33.impure.lisp b/tests/mop-33.impure.lisp new file mode 100644 index 0000000000..7bb6d728a7 --- /dev/null +++ b/tests/mop-33.impure.lisp @@ -0,0 +1,51 @@ +;;;; Handling errors in UPDATE-INSTANCE-FOR-DIFFERENT-CLASS + +;;;; This software is part of the SBCL system. See the README file for +;;;; more information. +;;;; +;;;; While most of SBCL is derived from the CMU CL system, the test +;;;; files (like this one) were written from scratch after the fork +;;;; from CMU CL. +;;;; +;;;; This software is in the public domain and is provided with +;;;; absolutely no warranty. See the COPYING and CREDITS files for +;;;; more information. + +(defclass foo () ()) + +(defclass bar () ((slot :initform 42))) + +(defmethod update-instance-for-different-class :before + ((foo foo) (bar bar) &rest initargs) + (declare (ignore initargs)) + ;; This U-I-F-D-C is meant to always signal an error. + (error "expected failure")) + +;;; Make an instance of FOO. +(defparameter *foo* (make-instance 'foo)) + +;;; This should result in an "expected failure" error. +(multiple-value-bind (result error) + (ignore-errors (change-class *foo* 'bar)) + (assert (null result)) + (assert (string= (princ-to-string error) "expected failure"))) + +;;; This should *also* result in an "expected failure" error, because after +;;; the previous U-I-F-D-C call made a non-local exit, the instance should be +;;; automatically restored to its previous class. +(multiple-value-bind (result error) + (ignore-errors (change-class *foo* 'bar)) + (assert (null result)) + (assert (string= (princ-to-string error) "expected failure"))) + +;;; Redefine the U-I-F-D-C method to no longer signal an error. +(defmethod update-instance-for-different-class :before + ((foo foo) (bar bar) &rest initargs) + (declare (ignore initargs))) + +;;; It is now possible to change the instance's class. +(change-class *foo* 'bar) + +;;; It should now be possible to access the new slot and fetch its +;;; initform-initialized value. +(assert (= 42 (slot-value *foo* 'slot))) diff --git a/tests/mop.impure.lisp b/tests/mop.impure.lisp index e99085729f..80655acf1c 100644 --- a/tests/mop.impure.lisp +++ b/tests/mop.impure.lisp @@ -20,6 +20,13 @@ (:use "CL" "SB-MOP" "ASSERTOID" "TEST-UTIL")) (in-package "MOP-TEST") + +;;; AMOP says these are the defaults +(with-test (:name :standard-direct-superclasses) + (assert (equal (list (find-class 'standard-object)) + (sb-mop:class-direct-superclasses (make-instance 'standard-class)))) + (assert (equal (list (find-class 'sb-mop:funcallable-standard-object)) + (sb-mop:class-direct-superclasses (make-instance 'sb-mop:funcallable-standard-class))))) ;;; Readers for Class Metaobjects (pp. 212--214 of AMOP) (defclass red-herring (forward-ref) ()) @@ -313,7 +320,7 @@ &rest initargs) (declare (ignore initargs)) (let ((dsd-class-name (gensym))) - (sb-pcl:ensure-class + (sb-mop:ensure-class dsd-class-name :metaclass 'auto-accessors-direct-slot-definition-class :direct-superclasses (list (find-class 'standard-direct-slot-definition)) @@ -420,7 +427,7 @@ ;;; detection of multiple class options in defclass, reported by Bruno Haible (defclass option-class (standard-class) ((option :accessor cl-option :initarg :my-option))) -(defmethod sb-pcl:validate-superclass ((c1 option-class) (c2 standard-class)) +(defmethod sb-mop:validate-superclass ((c1 option-class) (c2 standard-class)) t) (multiple-value-bind (result error) (ignore-errors (eval '(defclass option-class-instance () @@ -695,13 +702,7 @@ (slot-value o 'instance)))))) (defgeneric definitely-a-funcallable-instance (x)) -(with-test (:name (set-funcallable-instance-function :typechecking) - ;; This is a bit of a problem. SET-FUNCALLABLE-INSTANCE-FUNCTION - ;; accepts any funcallable-instance as its first argument, - ;; not just a generic-function. - ;; But an interpreted function *is* a funcallable-instance - ;; See comment in src/pcl/low about possibly tightening this up. - :fails-on :interpreter) +(with-test (:name (set-funcallable-instance-function :typechecking)) (assert-error (set-funcallable-instance-function (lambda (y) (declare (ignore y)) nil) #'definitely-a-funcallable-instance) @@ -749,3 +750,29 @@ 'change-class-test-2))) (assert (eql (slot-value new 'b) 20)) (assert (not (slot-boundp new 'a))))) + +(defclass chgclass-dx-test-1 () ()) +(defclass chgclass-dx-test-2 () ()) +(defclass chgclass-dx-test-fin-1 (funcallable-standard-object) () + (:metaclass funcallable-standard-class)) +(defclass chgclass-dx-test-fin-2 (funcallable-standard-object + chgclass-dx-test-2) + () + (:metaclass funcallable-standard-class)) +(defvar *uifdc-called*) +(defmethod update-instance-for-different-class :before (old (new chgclass-dx-test-2) + &rest initargs) + (declare (ignore initargs)) + (setq *uifdc-called* t) + (assert (sb-ext:stack-allocated-p old)) + (when (functionp new) + (assert (sb-ext:stack-allocated-p (sb-kernel:%funcallable-instance-fun old))))) +(with-test (:name :change-class-temp-on-stack) + (let ((i (make-instance 'chgclass-dx-test-1)) + (*uifdc-called* nil)) + (change-class i 'chgclass-dx-test-2) + (assert *uifdc-called*)) + (let ((i (make-instance 'chgclass-dx-test-fin-1)) + (*uifdc-called* nil)) + (change-class i 'chgclass-dx-test-fin-2) + (assert *uifdc-called*))) diff --git a/tests/mop.pure.lisp b/tests/mop.pure.lisp index 93173fb3fc..f0ba7bb101 100644 --- a/tests/mop.pure.lisp +++ b/tests/mop.pure.lisp @@ -80,17 +80,10 @@ for results = (test-class-slots class) when results do (cerror "continue" "~A" results)))) -;;; AMOP says these are the defaults -(with-test (:name :standard-direct-superclasses) - (assert (equal (list (find-class 'standard-object)) - (sb-mop:class-direct-superclasses (make-instance 'standard-class)))) - (assert (equal (list (find-class 'sb-mop:funcallable-standard-object)) - (sb-mop:class-direct-superclasses (make-instance 'sb-mop:funcallable-standard-class))))) - (with-test (:name :bug-936513) ;; This used to fail as ENSURE-GENERIC-FUNCTION wanted a list specifying ;; the method combination, and didn't accept the actual object - (let ((mc (sb-pcl:find-method-combination #'make-instance 'standard nil))) + (let ((mc (sb-mop:find-method-combination #'make-instance 'standard nil))) (ensure-generic-function 'make-instance :method-combination mc)) ;; Let's make sure the list works too... (ensure-generic-function 'make-instance :method-combination '(standard))) @@ -171,10 +164,10 @@ (find slot-name (sb-mop:class-direct-slots kid) :key 'sb-mop:slot-definition-name) (find slot-name (sb-mop:class-direct-slots par) - :key 'sb-pcl:slot-definition-name) + :key 'sb-mop:slot-definition-name) ;; there is only one effective slot of that name (assert (= 1 (count slot-name (sb-mop:class-slots kid) - :key 'sb-pcl:slot-definition-name)))))) + :key 'sb-mop:slot-definition-name)))))) ;; metaclass = structure-class ;; FUN-TYPE inherits CTYPE (check 'sb-kernel:fun-type 'sb-kernel:ctype 'sb-kernel::%bits) @@ -193,3 +186,11 @@ (dolist (slot-name (mapcar #'sb-mop:slot-definition-name (sb-mop:class-slots class))) (assert (sb-pcl::find-slot-cell layout slot-name)))))))) + +(with-test (:name (typep sb-mop:class-precedence-list)) + (let* ((objs (list (make-hash-table) (make-pathname) (make-condition 'warning) + (find-class 't) #'make-instance))) + (dolist (obj objs) + (let ((cpl (sb-mop:class-precedence-list (class-of obj)))) + (dolist (sc cpl) + (assert (typep obj sc))))))) diff --git a/tests/mutex.impure.lisp b/tests/mutex.impure.lisp index c825b69a4c..917237cfe6 100644 --- a/tests/mutex.impure.lisp +++ b/tests/mutex.impure.lisp @@ -1,4 +1,4 @@ -#-sb-thread (sb-ext:exit :code 104) +#-sb-thread (invoke-restart 'run-tests::skip-file) (use-package "SB-THREAD") @@ -11,8 +11,8 @@ (dotimes (i 100) (with-mutex (mutex) (sleep .03) - (assert (eql (mutex-value mutex) me))) - (assert (not (eql (mutex-value mutex) me)))) + (assert (eql (mutex-owner mutex) me))) + (assert (not (eql (mutex-owner mutex) me)))) (format t "done ~A~%" *current-thread*)))) (let ((kid1 (make-thread #'run)) (kid2 (make-thread #'run))) @@ -27,12 +27,12 @@ (setf child (test-interrupt (lambda () (with-mutex (lock) - (assert (eql (mutex-value lock) *current-thread*))) - (assert (not (eql (mutex-value lock) *current-thread*))) + (assert (eql (mutex-owner lock) *current-thread*))) + (assert (not (eql (mutex-owner lock) *current-thread*))) (sleep 10)))) ;;hold onto lock for long enough that child can't get it immediately (sleep 5) - (interrupt-thread child (lambda () (format t "l ~A~%" (mutex-value lock)))) + (interrupt-thread child (lambda () (format t "l ~A~%" (mutex-owner lock)))) (format t "parent releasing lock~%")) (process-all-interrupts child) (terminate-thread child) diff --git a/tests/octets.pure.lisp b/tests/octets.pure.lisp index 828d61ce81..ac9a119e48 100644 --- a/tests/octets.pure.lisp +++ b/tests/octets.pure.lisp @@ -47,7 +47,7 @@ (ensure-roundtrip-latin :latin9)) (ensure-roundtrip-utf8 () - (let ((string (make-string char-code-limit))) + (let ((string (make-string char-code-limit :initial-element #\nul))) (dotimes (i char-code-limit) (unless (<= #xd800 i #xdfff) (setf (char string i) (code-char i)))) @@ -81,7 +81,7 @@ (ensure-roundtrip-ascii) (ensure-roundtrip-latin1) - #+sb-unicode + #+(and sb-unicode (not unicode-lite)) (progn (ensure-roundtrip-latin9) ;; Latin-9 chars; the previous test checked roundtrip from @@ -243,22 +243,21 @@ ;;; START argument. (assert (equalp #(50) (string-to-octets "42" :start 1 :external-format :utf-8))) -;;; STRING->UTF8 should cope with NIL strings if a null range is required (assert (equalp #() (string-to-octets "" :external-format :utf-8))) -(assert (equalp #() (string-to-octets (make-array 0 :element-type nil) +(assert (equalp #() (string-to-octets (make-string 0) :external-format :utf-8))) -(assert (equalp #() (string-to-octets (make-array 5 :element-type nil) +(assert (equalp #() (string-to-octets (make-string 5) :start 3 :end 3 :external-format :utf-8))) -(assert (equalp #(0) (string-to-octets (make-array 5 :element-type nil) +(assert (equalp #(0) (string-to-octets (make-string 5) :start 3 :end 3 :null-terminate t :external-format :utf-8))) ;;; whoops: the iso-8859-2 format referred to an undefined symbol. -#+sb-unicode +#+(and sb-unicode (not unicode-lite)) (assert (equalp #(251) (string-to-octets (string (code-char 369)) :external-format :latin-2))) -(with-test (:name (:euc-jp :decoding-errors) :skipped-on (not :sb-unicode)) +(with-test (:name (:euc-jp :decoding-errors) :skipped-on (or (not :sb-unicode) :unicode-lite)) (handler-bind ((sb-int:character-decoding-error (lambda (c) (use-value #\? c)))) (assert (string= "?{?" diff --git a/tests/package-locks.impure.lisp b/tests/package-locks.impure.lisp index 18d2f8a16a..641c0a56e7 100644 --- a/tests/package-locks.impure.lisp +++ b/tests/package-locks.impure.lisp @@ -11,6 +11,8 @@ ;;;; absolutely no warranty. See the COPYING and CREDITS files for ;;;; more information. +#+sb-devel (invoke-restart 'run-tests::skip-file) ; packages are not locked for devs + (load "compiler-test-util.lisp") ;;;; Our little labrats and a few utilities @@ -565,18 +567,18 @@ (with-test (:name :compile-time-defun-package-locked) ;; Make sure compile-time side-effects of DEFUN are protected against. - (let ((inline-lambda (function-lambda-expression #'fill-pointer))) + (let ((inline-lambda (function-lambda-expression #'adjustable-array-p))) ;; Make sure it's actually inlined... (assert inline-lambda) (assert (eq :ok (handler-case - (ctu:file-compile `((defun fill-pointer (x) x))) + (ctu:file-compile `((defun adjustable-array-p (x) x))) (sb-ext:symbol-package-locked-error (e) - (when (eq 'fill-pointer + (when (eq 'adjustable-array-p (sb-ext:package-locked-error-symbol e)) :ok))))) (assert (equal inline-lambda - (function-lambda-expression #'fill-pointer))))) + (function-lambda-expression #'adjustable-array-p))))) (with-test (:name :compile-time-defclass-package-locked) ;; Compiling (DEFCLASS FTYPE ...) used to break SBCL, but the package diff --git a/tests/package-test-1.lisp b/tests/package-test-1.lisp new file mode 100644 index 0000000000..e4106ccab0 --- /dev/null +++ b/tests/package-test-1.lisp @@ -0,0 +1,8 @@ +(defpackage "FOO" + (:use "CL")) + +(in-package "FOO") + +(eval-when (:compile-toplevel :load-toplevel :execute) + (defun baz () + :bad)) diff --git a/tests/package-test-2.lisp b/tests/package-test-2.lisp new file mode 100644 index 0000000000..b2dc5b2ee8 --- /dev/null +++ b/tests/package-test-2.lisp @@ -0,0 +1,13 @@ +(eval-when (:compile-toplevel :load-toplevel :execute) + (cond + ((find-package "FOO") + (rename-package "FOO" "BAR" '("FOO"))) + ((not (find-package "BAR")) + (make-package "BAR" :use '("CL") :nicknames '("FOO")) + (export (list (intern "BAZ" "BAR")) "BAR")))) + +(in-package "BAR") + +(eval-when (:compile-toplevel :load-toplevel :execute) + (defun baz () + :good)) diff --git a/tests/package-test-3.lisp b/tests/package-test-3.lisp new file mode 100644 index 0000000000..2b0a2557e1 --- /dev/null +++ b/tests/package-test-3.lisp @@ -0,0 +1,11 @@ +(defpackage "FOO" + (:use "CL") + (:export "BAR" "BAZ")) + +(in-package "FOO") + +(eval-when (:compile-toplevel :load-toplevel :execute) + (defun baz () + 1) + (defmacro bar (&rest args) + `(baz ,@args))) diff --git a/tests/package-test-4.lisp b/tests/package-test-4.lisp new file mode 100644 index 0000000000..75dbb837ab --- /dev/null +++ b/tests/package-test-4.lisp @@ -0,0 +1,13 @@ +(eval-when (:compile-toplevel :load-toplevel :execute) + (cond + ((find-package "FOO") + (rename-package "FOO" "FOO-NEW" '("FOO"))) + ((not (find-package "FOO-NEW")) + (make-package "FOO-NEW" :use '("CL") :nicknames '("FOO")) + (export (list (intern "BAR" "FOO-NEW") (intern "BAZ" "FOO-NEW")) "FOO-NEW")))) + +(in-package "FOO-NEW") + +(eval-when (:compile-toplevel :load-toplevel :execute) + (defmacro bar (&rest args) + `(baz ,@args))) diff --git a/tests/packages.impure.lisp b/tests/packages.impure.lisp index da99113de7..6fe5931191 100644 --- a/tests/packages.impure.lisp +++ b/tests/packages.impure.lisp @@ -11,6 +11,18 @@ ;;;; absolutely no warranty. See the COPYING and CREDITS files for ;;;; more information. +(load "compiler-test-util.lisp") + +(require :sb-md5) +#+64-bit +(progn + (defun spid (x) (sb-impl::symbol-package-id (the symbol x))) ; no stub? + (compile 'spid) + (let ((n 0)) + (do-all-symbols (s) + (when (> (spid s) 100) (incf n))) + (assert (= n 0)))) + (defun set-bad-package (x) (declare (optimize (safety 0))) (setq *package* x)) @@ -36,7 +48,7 @@ (make-package "FOO") (defvar *foo* (find-package (coerce "FOO" 'base-string))) -(rename-package "FOO" (make-array 0 :element-type nil)) +(rename-package "FOO" (make-array 0 :element-type 'character)) (assert (eq *foo* (find-package ""))) (assert (delete-package "")) @@ -924,7 +936,7 @@ if a restart was invoked." ;;; Use array of fixnums because there're no atomic ops on array of word. ;;; This is either 58000 useful bits or 126000 bits depending on word size. -(defglobal *scoreboard* (make-array 2000)) +(defglobal *scoreboard* (make-array 2000 :initial-element 0)) (defglobal *testpkg* (make-package "A-NICE-PACKAGE")) (defun hammer-on-gentemp (package n-iter) @@ -1010,3 +1022,154 @@ if a restart was invoked." (delete-package "PKG-A") (make-package "PKG-B" :nicknames '("PKG-A")) (assert (eq (foo-intern "X") (find-symbol "X" "PKG-B"))))) + +;;; It's extremely unlikely that a user would make >2^16 packages, but test that it works. +(defun grow-id->package-vector () + (let ((table (make-array 65535 :initial-element nil))) ; grow once only. Sorry for cheating + (replace table sb-impl:*id->package*) + (setf sb-impl:*id->package* table))) +(compile 'grow-id->package-vector) + +(with-test (:name :ridiculous-amount-of-packages) + (make-package "WATPACKAGE") + (grow-id->package-vector) ; grow once only. Sorry for cheating + (loop + ;; This loop unfortunately takes 2 seconds, which kind of speaks to + ;; the slowness of package creation. I don't think we need to improve that, + ;; but we _do_ need to test this, so ... it's a minor point of pain. + ;; If I had to guess, resizing the mostly-lockfree hash-table is the issue. + ;; We could grow it all at once to improve the performance. + (let* ((package (make-package "STRANGE")) + (id (sb-impl::package-id package)) + (new-name (format nil "TEST-PKGID-~D" id))) + (unless id (return)) + (rename-package package new-name))) + (let ((p (find-package "STRANGE"))) + (assert (not (sb-impl::package-id p))) + (let ((symbol (intern "WAT123" p))) + (assert (eq (symbol-package symbol) p)) + (delete-package p) + (assert (not (symbol-package symbol))) + (import symbol "WATPACKAGE") + (assert (eq (symbol-package symbol) (find-package "WATPACKAGE"))) + ;; assert that the symbol got a small ID + (assert (not (sb-int:info :symbol :package symbol))))) + (delete-package "WATPACKAGE") + (let ((p (make-package "ANOTHERPACKAGE"))) + (assert (sb-impl::package-id p))) + (let ((p (make-package "YETANOTHERPACKAGE"))) + (assert (not (sb-impl::package-id p)))) + ;; Now for every package named TEST-PKGIDnm, check that a symbol interned + ;; in that package can read the bits back correctly (because vops are confusing) + (let ((n 0)) + (dolist (package (list-all-packages)) + (when (search "TEST-PKGID-" (package-name package)) + (incf n) + (let ((the-symbol (intern "FROBOLA" package))) + (assert (eq (symbol-package the-symbol) package))))) + (assert (> n 65450)))) ; assert that we exercised lots of bit patterns + +;;; The concept behind the intricate storage representation of local nicknames +;;; was that adding a nickname does not create a strong reference to the +;;; nicknamed package, but nonetheless avoids having to do a FIND-PACKAGE +;;; on its actual name. This is efficient, but it is complicated because +;;; it involves weak objects. Here is a test which asserts that. +;;; [It probably would have been fine to penalize DELETE-PACKAGE by forcing +;;; it to scan all other packages for local nicknames of the deleted one, +;;; but I guess I didn't want to do that. But I wonder if it might be possible +;;; to reduce the complexity now that we have package IDs.] +(defvar *the-weak-ptr*) ; to determine that the test worked +(defun prepare-nickname-weakness-test () + (setq *the-weak-ptr* (make-weak-pointer (make-package "SOMEPACKAGE"))) + (make-package "MYPKG" :use '("CL")) + (add-package-local-nickname "SP" "SOMEPACKAGE" "MYPKG") + (intern "ZOOK" "SOMEPACKAGE") + (let ((*package* (find-package "MYPKG"))) + (assert (eq (find-symbol "ZOOK" "SP") + (find-symbol "ZOOK" "SOMEPACKAGE"))))) + +(with-test (:name :local-nicknames-like-weak-pointers) + (prepare-nickname-weakness-test) + ;; Check that SP is a local nickname + (assert (let ((*package* (find-package "MYPKG"))) (find-symbol "ZOOK" "SP"))) + ;;; But not a global name of any package + (assert-error (find-symbol "ZOOK" "SP")) + (delete-package "SOMEPACKAGE") + ;; Assert that the local nickname vector has not yet removed the + ;; deleted package. DELETE-PACKAGE does not scan all packages to adjust + ;; their local nicknames. (There's no "locally nicknamed by" accessor so it + ;; definitely would need to visit all packages which I didn't like. + ;; It wouldn't be the worst thing, but I opted not to store a reverse lookup) + ;; Rather interestingly, this operation overwrites a words of the control stack + ;; that might otherwise randomly contain the very package that got deleted. + (assert (= (length (cdr (sb-impl::package-%local-nicknames + (find-package "MYPKG")))) + 2)) + (sb-sys:scrub-control-stack) + (gc :full t) + (assert (not (weak-pointer-value *the-weak-ptr*))) + (assert-error (let ((*package* (find-package "MYPKG"))) + ;; the nickname magically went away! + (find-symbol "ZOOK" "SP")))) + +;;; This is probably, strictly speaking, non-conforming code according +;;; to ANSI 3.2.4.4 under item 1 for symbol, taking package "same"ness +;;; to mean EQness. +(with-test (:name :defpackage-rename-package-redefpackage) + (ctu:file-compile + `((eval-when (:compile-toplevel :load-toplevel :execute) + (when (find-package "DEFPACKAGE4") + (rename-package "DEFPACKAGE4" "DEFPACKAGE4"))) + (defpackage "DEFPACKAGE4" + (:use :cl)) + (in-package "DEFPACKAGE4") + (eval-when (:compile-toplevel :load-toplevel :execute) + (export '(f)))) + :load t) + (assert (eq (nth-value 1 (find-symbol "F" "DEFPACKAGE4")) + :external))) + +(with-test (:name :defpackage-rename-package) + (delete-package "BAR") + (ctu:file-compile + `((eval-when (:compile-toplevel :load-toplevel :execute) + (cond + ((find-package "FOO") + (rename-package "FOO" + "BAR")) + ((not (find-package "BAR")) + (make-package "BAR" :use '("CL"))))) + + (in-package "BAR") + + (defun stable-union (bar) bar)) + :before-load (lambda () + (delete-package "BAR") + (defpackage foo (:use :cl))) + :load t) + (assert (find-symbol "STABLE-UNION" "BAR")) + (delete-package "BAR")) + +(with-test (:name :defpackage-rename-package-symbol-conflict) + (with-scratch-file (fasl2 "fasl") + (compile-file "package-test-2.lisp" :output-file fasl2) + (delete-package "BAR") + (with-scratch-file (fasl1 "fasl") + (compile-file "package-test-1.lisp" :output-file fasl1) + (load fasl2))) + (assert (eq (symbol-package (find-symbol "BAZ" "BAR")) + (find-package "BAR"))) + (assert (eq (funcall (find-symbol "BAZ" "BAR")) + :good)) + (delete-package "BAR")) + +(with-test (:name :defpackage-rename-package-preserve-externals) + (with-scratch-file (fasl4 "fasl") + (compile-file "package-test-4.lisp" :output-file fasl4) + (delete-package "FOO-NEW") + (with-scratch-file (fasl3 "fasl") + (compile-file "package-test-3.lisp" :output-file fasl3) + (load fasl4))) + (assert (eq (nth-value 1 (find-symbol "BAR" "FOO-NEW")) + :external)) + (delete-package "FOO-NEW")) diff --git a/tests/packed-varints.pure.lisp b/tests/packed-varints.pure.lisp index d61a5ee2c1..b15062d6da 100644 --- a/tests/packed-varints.pure.lisp +++ b/tests/packed-varints.pure.lisp @@ -9,25 +9,6 @@ ;;;; absolutely no warranty. See the COPYING and CREDITS files for ;;;; more information. -(with-test (:name :pack-compiled-debug-info-tlf-num+offset) - (flet ((test (a b) - (let ((cdi - (sb-c::make-compiled-debug-info - :name "test" :fun-map (sb-c::make-compiled-debug-fun :name 'test - :encoded-locs 0 - :allow-other-keys t - :return-pc 0 - :return-pc-pass 0 - :elsewhere-pc 0 - :old-fp 0) - :tlf-num+offset (let ((sb-c::*adjustable-vectors* nil)) - (sb-c::pack-tlf-num+offset a b))))) - (assert (eql a (sb-c::compiled-debug-info-tlf-number cdi))) - (assert (eql b (sb-c::compiled-debug-info-char-offset cdi)))))) - (dolist (i '(nil 0 1 2 313 542)) - (dolist (j '(nil 0 1 2 3 9898989 405344332)) - (test i j))))) - #+(and x86-64 immobile-space sb-unicode (not interpreter)) ; missing symbols otherwise (with-test (:name :bignum-unpacker-no-consing) (flet ((try () diff --git a/tests/parallel-exec.sh b/tests/parallel-exec.sh index 9b43ae9e37..252bf0da68 100755 --- a/tests/parallel-exec.sh +++ b/tests/parallel-exec.sh @@ -2,32 +2,115 @@ logdir=${SBCL_PAREXEC_TMP:-$HOME}/sbcl-test-logs-$$ echo ==== Writing logs to $logdir ==== +# FIXME: junkdir isn't getting removed junkdir=${SBCL_PAREXEC_TMP:-/tmp}/junk mkdir -p $junkdir $logdir +case `uname` in + CYGWIN* | WindowsNT | MINGW* | MSYS*) + if [ $# -ne 1 ] + then + echo $0: Need arg + exit 1 + fi + echo ";; Using -j$1" + echo "LOGDIR=$logdir" >$logdir/Makefile + ../run-sbcl.sh --script genmakefile.lisp >>$logdir/Makefile + exec $GNUMAKE -k -j $1 -f $logdir/Makefile + ;; +esac + +export TEST_DIRECTORY SBCL_HOME TEST_DIRECTORY=$junkdir SBCL_HOME=../obj/sbcl-home exec ../src/runtime/sbcl \ - --noinform --core ../output/sbcl.core --no-userinit --no-sysinit --noprint --disable-debugger << EOF + --noinform --core ../output/sbcl.core \ + --no-userinit --no-sysinit --noprint --disable-debugger $* << EOF +(pop *posix-argv*) (require :sb-posix) +#-sparc (push :test-sprof *features*) +#+test-sprof (require :sb-sprof) (let ((*evaluator-mode* :compile)) (with-compilation-unit () (load"run-tests"))) +#+(and x86-64 linux sb-thread) + (unless (find :gs-seg sb-impl:+internal-features+) + (push :test-aprof *features*)) (in-package run-tests) (import '(sb-alien:alien-funcall sb-alien:extern-alien sb-alien:int sb-alien:c-string sb-alien:unsigned)) (setq *summarize-test-times* t) -(defun parallel-execute-tests (max-jobs) +;;; Ordered approximately in descending order by running time +(defvar *slow-tests* '("threads.impure" + "seq.impure" + "threads.pure" + "compiler.pure" + "timer.impure" + "bug-1180102.impure" + "gethash-concurrency.impure" + "arith-slow.pure")) +(defvar *filter* nil) +(defglobal *delete-logs* nil) +(defun choose-order (tests) + (when *filter* + (let (strings) + (with-open-file (file *filter*) + (loop (let ((line (read-line file nil))) + (if line (push line strings) (return))))) + (setq tests (remove-if (lambda (x) (not (find x strings :test #'string=))) + tests)))) + (sort tests + (lambda (a b) + (let ((posn-a (or (position a *slow-tests* :test #'string=) + most-positive-fixnum)) + (posn-b (or (position b *slow-tests* :test #'string=) + most-positive-fixnum))) + (cond ((< posn-a posn-b) t) + ((> posn-a posn-b) nil) + (t (string< a b))))))) +(defun summarize-gc-times () + (let (observations) + (flet ((parse-triple (string pos) + (sb-int:binding* (((int1 end) (parse-integer string :start (1+ pos) + :junk-allowed t)) + ((int2 end) (parse-integer string :start (1+ end) + :junk-allowed t)) + ((int3) (parse-integer string :start (1+ end) + :junk-allowed t))) + (list int1 int2 int3)))) + (dolist (pn (directory "$logdir/*.*")) + (with-open-file (f pn) + (let ((legend "GC: stw_delay")) + (loop + (let ((line (read-line f nil))) + (unless line (return)) + (when (and (> (length line) (length legend)) + (string= line legend :end1 (length legend))) + (let* ((p1 (position #\= line)) + (p2 (position #\= line :start (1+ p1))) + (stw-dur (parse-triple line p1)) + (gc-dur (parse-triple line p2)) + (count (parse-integer line :start (+ (search "over " line) 5) + :junk-allowed t))) + (let ((name (concatenate 'string (pathname-name pn) "." + (pathname-type pn)))) + (push (list count stw-dur gc-dur name) observations)))))))))) + (let ((fmt " ~5d (~{~10d~^ ~}) (~{~7d~^ ~}) ~a~%")) + (format t "~&Top 15 worst by max time to stop-the-world:~%") + (let ((list (sort (copy-list observations) #'> :key (lambda (x) (third (second x)))))) + (dotimes (i 15) (apply #'format t fmt (pop list)))) + (format t "~&Top 15 worst by avg GC duration (excluding STW delay):~%") + (let ((list (sort (copy-list observations) #'> :key (lambda (x) (second (third x)))))) + (dotimes (i 15) (apply #'format t fmt (pop list)))) + (format t "~&Top 15 worst by max GC duration (excluding STW delay):~%") + (let ((list (sort (copy-list observations) #'> :key (lambda (x) (third (third x)))))) + (dotimes (i 15) (apply #'format t fmt (pop list))))))) +(defun parallel-execute-tests (files max-jobs vop-summary-stats-p) (format t "Using ~D processes~%" max-jobs) ;; Interleave the order in which all tests are launched rather than ;; starting them in the batches that filtering places them in. - (let ((files (sort (mapcar #'pathname-name - (append (pure-load-files) - (pure-cload-files) - (impure-load-files) - (impure-cload-files) - (sh-files))) - #'string<)) - (subprocess-count 0) + (let ((subprocess-count 0) (subprocess-list nil) - (aggregate-vop-usage (make-hash-table)) + (aggregate-vop-usage (make-hash-table :test #'equal)) + ;; Start timing only after all the DIRECTORY calls are done (above) + (start-time (get-internal-real-time)) (missing-usage) (losing)) (labels ((wait () @@ -36,18 +119,28 @@ TEST_DIRECTORY=$junkdir SBCL_HOME=../obj/sbcl-home exec ../src/runtime/sbcl \ #+nil (format t "Runner is waiting on: ~S~%" subprocess-list) (multiple-value-bind (pid status) (sb-posix:wait) (decf subprocess-count) - (let ((process (assoc pid subprocess-list))) + (let ((process (assoc pid subprocess-list)) + (code (ash status -8)) + (et)) + (unless process + (warn "Whoa! Process ~D is an unexpected child" pid) + (return-from wait (wait))) (setq subprocess-list (delete process subprocess-list)) - (let* ((code (ash status -8)) - (filename (cdr process))) - (unless (sum-vop-usage (format nil "$logdir/~a.vop-usage" filename) t) - (when (or (search ".pure" filename) (search ".impure" filename)) - (push filename missing-usage))) + (destructuring-bind ((filename . iteration) start-time) (cdr process) + (setq et (elapsed-time-from start-time)) + (when vop-summary-stats-p + (unless (sum-vop-usage (format nil "$logdir/~a.vop-usage" filename) t) + (when (or (search ".pure" filename) (search ".impure" filename)) + (push filename missing-usage)))) (cond ((eq code 104) - (format t "~A: success~%" filename)) + (format t "~A: success (~d msec)~%" filename et)) (t - (format t "~A: status ~D~%" filename code) - (push filename losing))))))) + (format t "~A~@[[~d]~]: status ~D (~d msec)~%" + filename iteration code et) + (push (list filename iteration pid) losing))))))) + (elapsed-time-from (when) ; return value in milliseconds + (round (- (get-internal-real-time) when) + (/ internal-time-units-per-second 1000))) (sum-vop-usage (input deletep) (with-open-file (f input :if-does-not-exist nil) ;; No vop coverage file from shell script tests or any test @@ -64,53 +157,75 @@ TEST_DIRECTORY=$junkdir SBCL_HOME=../obj/sbcl-home exec ../src/runtime/sbcl \ (wait)) (let ((pid (sb-posix:fork))) (when (zerop pid) - (with-open-file (stream (format nil "$logdir/~a" file) - :direction :output :if-exists :supersede) + (let ((mylog (format nil "$logdir/~a~@[-~d~]" (car file) (cdr file)))) + #+(and linux sb-thread 64-bit) + (sb-alien:alien-funcall (sb-alien:extern-alien "reset_gc_stats" + (function sb-alien:void))) + ;; FILE is (filename . test-iteration) + (with-open-file (stream mylog :direction :output :if-exists :supersede) (alien-funcall (extern-alien "dup2" (function int int int)) (sb-sys:fd-stream-fd stream) 1) (alien-funcall (extern-alien "dup2" (function int int int)) 1 2)) + (setq file (car file)) + #+test-aprof + (unless (search "allocator.pure" file) + (sb-aprof::aprof-start) + (proclaim '(optimize sb-c:instrument-consing))) ;; Send this to the log file, not the terminal (setq *debug-io* (make-two-way-stream (make-concatenated-stream) *error-output*)) (cond ((string= (pathname-type file) "test") - ;; exec /bin/sh with the test and we'll pick up its exit code - (alien-funcall (extern-alien "execl" (function int c-string c-string - c-string unsigned)) - "/bin/sh" "/bin/sh" - (concatenate 'string file ".sh") 0) + (let ((shell (or #+sunos (posix-getenv "SHELL") "/bin/sh"))) + ;; exec the shell with the test and we'll pick up its exit code + (alien-funcall (extern-alien "execl" (function int c-string c-string + &optional c-string unsigned)) + shell shell + (concatenate 'string file ".sh") 0)) ;; if exec fails, just exit with a wrong (not 104) status (alien-funcall (extern-alien "_exit" (function (values) int)) 0)) (t - (setq sb-c::*static-vop-usage-counts* (make-hash-table)) + #+test-sprof (sb-sprof:start-profiling :sample-interval .001) + (setq sb-c::*static-vop-usage-counts* (make-hash-table :synchronized t)) (let ((*features* (cons :parallel-test-runner *features*))) (pure-runner (list (concatenate 'string file ".lisp")) (if (search "-cload" file) 'cload-test 'load-test) (make-broadcast-stream))) - (with-open-file (output (format nil "$logdir/~a.vop-usage" file) - :direction :output) - ;; There's an impure test that screws with the default pprint dispatch - ;; table such that integers don't print normally (and can't be parsed). - (let ((*print-pretty* nil)) - (sb-int:dohash ((name count) sb-c::*static-vop-usage-counts*) - (format output "~7d ~s~%" count name)))) - (exit :code (if (unexpected-failures) 1 104))))) - (format t "~A: pid ~d~%" file pid) + (when vop-summary-stats-p + (with-open-file (output (format nil "$logdir/~a.vop-usage" file) + :direction :output) + ;; There's an impure test that screws with the default pprint dispatch + ;; table such that integers don't print normally (and can't be parsed). + (let ((*print-pretty* nil)) + (sb-int:dohash ((name count) sb-c::*static-vop-usage-counts*) + (format output "~7d \"~s\"~%" count name))))) + #+test-sprof (sb-sprof:stop-profiling) + #+test-aprof (progn (sb-aprof::aprof-stop) (sb-aprof:aprof-show)) + (when (member :allocator-metrics sb-impl:+internal-features+) + (format t "~2&Allocator histogram:~%") + (funcall (intern "PRINT-ALLOCATOR-HISTOGRAM" "SB-THREAD"))) + #+test-sprof (sb-sprof:report :type :flat) + (gc :gen 7) + (when (and (not (unexpected-failures)) *delete-logs*) (delete-file mylog)) + (exit :code (if (unexpected-failures) 1 104)))))) + (format t "~A: pid ~d~@[ (trial ~d)~]~%" (car file) pid (cdr file)) (incf subprocess-count) - (push (cons pid file) subprocess-list))) + (push (list pid file (get-internal-real-time)) subprocess-list))) (loop (if (plusp subprocess-count) (wait) (return))) - (dolist (result '("vop-usage.txt" "vop-usage-combined.txt")) - (let (list) - (sb-int:dohash ((name vop) sb-c::*backend-template-names*) - (declare (ignore vop)) - (push (cons (gethash name aggregate-vop-usage 0) name) list)) - (with-open-file (output (format nil "$logdir/~a" result) - :direction :output - :if-exists :supersede) - (dolist (cell (sort list #'> :key #'car)) - (format output "~7d ~s~%" (car cell) (cdr cell))))) - (sum-vop-usage "../output/warm-vop-usage.txt" nil)) + (when vop-summary-stats-p + (dolist (result '("vop-usage.txt" "vop-usage-combined.txt")) + (let (list) + (sb-int:dohash ((name vop) sb-c::*backend-template-names*) + (declare (ignore vop)) + (push (cons (gethash (prin1-to-string name) aggregate-vop-usage 0) name) list)) + (with-open-file (output (format nil "$logdir/~a" result) + :direction :output + :if-exists :supersede) + (dolist (cell (sort list #'> :key #'car)) + (format output "~7d ~s~%" (car cell) (cdr cell))))) + (sum-vop-usage "../output/warm-vop-usage.txt" nil))) + (format t "~&Total realtime: ~d msec~%" (elapsed-time-from start-time)) (when missing-usage (format t "~&Missing vop-usage:~{ ~a~}~%" missing-usage)) @@ -118,6 +233,51 @@ TEST_DIRECTORY=$junkdir SBCL_HOME=../obj/sbcl-home exec ../src/runtime/sbcl \ (format t "~&Failing files:~%") (dolist (filename losing) (format t "~A~%" filename)) + (format t "==== Logs are in $logdir ====~%") (exit :code 1))))) -(parallel-execute-tests $1) +(when (string= (car *posix-argv*) "--filter") + (setq *filter* (cadr *posix-argv*)) + (setq *posix-argv* (cddr *posix-argv*))) +(if (= (length *posix-argv*) 1) + ;; short form - all files, argument N is the number of parallel tasks + (let ((jobs (parse-integer (car *posix-argv*)))) + (parallel-execute-tests + (mapcar #'list + (choose-order + (mapcar #'pathname-name + (append (pure-load-files) + (pure-cload-files) + (impure-load-files) + (impure-cload-files) + (sh-files))))) + jobs + t) + #+(and linux sb-thread 64-bit) (summarize-gc-times)) + ;; long form + (let ((jobs 4) + (runs-per-test 1) + (argv *posix-argv*)) + (loop (cond ((string= (car argv) "-j") + (setq jobs (parse-integer (cadr argv)) + argv (cddr argv))) + ((string= (car argv) "--runs_per_test") + (setq runs-per-test (parse-integer (cadr argv)) + argv (cddr argv))) + (t + (return)))) + (when (>= runs-per-test 10) + (format t "~&Note: will not keep logs of passing runs~%") + (setq *delete-logs* t)) + (setq argv + (mapcar (lambda (file) + (probe-file file) ; for effect + (pathname-name file)) argv)) + (parallel-execute-tests + (loop for trial-number from 1 to runs-per-test + nconc (mapcar (lambda (file) + (cons file + (when (> runs-per-test 1) trial-number))) + argv)) + jobs + nil))) EOF diff --git a/tests/pathnames.impure.lisp b/tests/pathnames.impure.lisp index 09c62dddbc..0678ebebec 100644 --- a/tests/pathnames.impure.lisp +++ b/tests/pathnames.impure.lisp @@ -17,6 +17,15 @@ ;;;; Pathname accessors +(with-test (:name :pathname-table-clobbered-on-save) + (let ((kvv (sb-impl::hash-table-pairs sb-impl::*pathnames*))) + (sb-int:dovector (element kvv) + (when (and (eq (heap-allocated-p element) :dynamic) + (pathnamep element) + (not (equal element #P""))) + (assert (/= (sb-kernel:generation-of element) + sb-vm:+pseudo-static-generation+)))))) + (with-test (:name (pathname :accessors :stream-not-associated-to-file type-error)) (let ((*stream* (make-string-output-stream))) (declare (special *stream*)) @@ -733,7 +742,8 @@ (defun scratch-dir-truename () (with-scratch-file (name) - (truename (make-pathname :directory (pathname-directory name))))) + (truename (make-pathname :directory (pathname-directory name) + :device (pathname-device name))))) (with-test (:name (delete-file logical-pathname)) (setf (logical-pathname-translations "SB-TEST") @@ -879,3 +889,46 @@ :displaced-to string :displaced-index-offset 1))) (assert (equal (parse-namestring disp) #p"SYS:ABC.LISP")))) + +;;; LOGICAL-PATHAME was missing the specialized pathname comparator +;;; function in SB_KERNEL::LAYOUT-EQUALP-IMPL +(with-test (:name :logical-pathname-equalp-method) + ;; PATHNAME is not a structure-object but uses the instance EQUALP case. + (checked-compile-and-assert + () + `(lambda (x y) + (equalp x y)) + (((make-pathname) (make-pathname :version :newest)) t)) + (let ((s "#p\"sys:contrib/f[1-9].txt\"")) + (let ((a (read-from-string s))) + ;; result shouldn't depend on the pathnames being EQ + (clrhash sb-impl::*pathnames*) + (let ((b (read-from-string s))) + (assert (not (eq a b))) + (equalp a b))))) + +;;; After the change which added address-based hashing to all INSTANCE types, +;;; someone forgot to ensure that address-based hashes were not used on +;;; PATTERN instances which can comprise the subcomponents of a pathname. +;;; So make sure the hash is based on the string contents of the pattern. +;;; Read pathnames from strings to guarantee that some magic effect of reading +;;; pathnames doesn't coalesce them. To be especially certain, clear the +;;; SB-IMPL::*PATHNAMES* table between the read-from-string calls. +(with-test (:name :wild-pathnames-string-based-hash) + (let ((string "#p\"file[0-9].txt\"")) + (let ((a (read-from-string string))) + (clrhash (clrhash sb-impl::*pathnames*)) + (let ((b (read-from-string string))) + (assert (not (eq a b))) + (assert (eql (sxhash a) (sxhash b))))))) + +(with-test (:name :cfp-examples) + (let ((*default-pathname-defaults* #p"")) + (assert (equal (compile-file-pathname "a/b/srcfile.lsp" :output-file "build/bin/") + #P"build/bin/srcfile.fasl")) + (assert (equal (compile-file-pathname "a/b/srcfile.lsp" :output-file "build/bin/f") + #P"build/bin/f.fasl")) + (assert (equal (compile-file-pathname "a/b/srcfile.lsp" :output-file "build/bin/foo.tmp") + #P"build/bin/foo.tmp")) + (assert (equal (compile-file-pathname "a/b/srcfile.lsp") + #P"a/b/srcfile.fasl")))) diff --git a/tests/pprint.impure.lisp b/tests/pprint.impure.lisp index e67b139864..a7ed0c82bc 100644 --- a/tests/pprint.impure.lisp +++ b/tests/pprint.impure.lisp @@ -17,7 +17,7 @@ ;;;; are order-preserving - unless they are of the form (CONS (EQL x)). ;;;; This is not a requirement in general, but is quite reasonable. (with-test (:name :pprint-dispatch-order-preserving) - (let ((tbl (sb-pretty::make-pprint-dispatch-table nil nil nil))) + (let ((tbl (sb-pretty::make-pprint-dispatch-table #() nil nil))) (handler-bind ((warning #'muffle-warning)) ; nonexistent types ;; use EVAL because there are *two* warnings to muffle: first time ;; is when the compiler sees a symbol used as an unknown type-specifier, @@ -29,7 +29,7 @@ (set-pprint-dispatch (eval ''fool) #'pprint-fill 0 tbl) (set-pprint-dispatch (eval ''foo2) #'pprint-fill 5 tbl)) (let ((entries (sb-pretty::pp-dispatch-entries tbl))) - (assert (equal (mapcar #'sb-pretty::pprint-dispatch-entry-type entries) + (assert (equal (map 'list #'sb-pretty::pprint-dispatch-entry-type entries) '(foo1 foo2 fool)))))) ;;;; tests for former BUG 99, where pretty-printing was pretty messed @@ -287,8 +287,7 @@ (*print-pretty* t)) (format nil "~@<~S~:>" (make-instance 'frob)))))) -(with-test (:name :pprint-logical-block-code-deletion-node - :skipped-on (not :stack-allocatable-closures)) +(with-test (:name :pprint-logical-block-code-deletion-node) (handler-case (compile nil `(lambda (words &key a b c) @@ -425,16 +424,19 @@ ;; force MACDADDY to be a closure over X. (let ((x 3)) (defmacro macdaddy (a b &body z) a b z `(who-cares ,x)) (incf x)) +(defun indentation-of (name) + (sb-pretty::macro-indentation (macro-function name))) + (with-test (:name :closure-macro-arglist) ;; assert correct test setup - MACDADDY is a closure if compiling, ;; or a funcallable-instance if not - (assert (eq (sb-kernel:fun-subtype (macro-function 'macdaddy)) + (assert (eq (sb-kernel:%fun-pointer-widetag (macro-function 'macdaddy)) #-interpreter sb-vm:closure-widetag #+interpreter sb-vm:funcallable-instance-widetag)) ;; MACRO-INDENTATION used %simple-fun-arglist instead of %fun-arglist. ;; Depending on your luck it would either not return the right answer, ;; or crash, depending on what lay at 4 words past the function address. - (assert (= (sb-pretty::macro-indentation 'macdaddy) 2))) + (assert (= (indentation-of 'macdaddy) 2))) (defmacro try1 (a b &body fool) `(baz ,a ,b ,fool)) (defmacro try2 (a b &optional &body fool) `(baz ,a ,b ,fool)) @@ -443,12 +445,12 @@ (defmacro try5 (a b &optional . fool) `(baz ,a ,b ,fool)) (defmacro try6 (a b &optional c . fool) `(baz ,a ,b ,c ,fool)) (with-test (:name :macro-indentation) - (assert (= (sb-pretty::macro-indentation 'try1) 2)) - (assert (= (sb-pretty::macro-indentation 'try2) 2)) - (assert (= (sb-pretty::macro-indentation 'try3) 3)) - (assert (= (sb-pretty::macro-indentation 'try4) 2)) - (assert (= (sb-pretty::macro-indentation 'try5) 2)) - (assert (= (sb-pretty::macro-indentation 'try6) 3))) + (assert (= (indentation-of 'try1) 2)) + (assert (= (indentation-of 'try2) 2)) + (assert (= (indentation-of 'try3) 3)) + (assert (= (indentation-of 'try4) 2)) + (assert (= (indentation-of 'try5) 2)) + (assert (= (indentation-of 'try6) 3))) (defclass ship () ()) (let ((ppd (copy-pprint-dispatch))) diff --git a/tests/print.impure.lisp b/tests/print.impure.lisp index c056426cc4..87fa523414 100644 --- a/tests/print.impure.lisp +++ b/tests/print.impure.lisp @@ -156,10 +156,10 @@ '(1 2 0)))) (with-test (:name (print array *print-readably* :element-type)) - (dolist (array (list (make-array '(1 0 1)) + (dolist (array (list (make-array '(1 0 1) :initial-element 0) (make-array 0 :element-type nil) - (make-array 1 :element-type 'base-char) - (make-array 1 :element-type 'character))) + (make-array 1 :element-type 'base-char :initial-element #\nul) + (make-array 1 :element-type 'character :initial-element #\nul))) (assert (multiple-value-bind (result error) (read-from-string (write-to-string array :readably t)) @@ -396,7 +396,7 @@ ;;; CSR inserted a bug into Burger & Dybvig's float printer. Caught ;;; by Raymond Toy (with-test (:name (format :exponential-floating-point-directive :smoke)) - (assert (string= (format nil "~E" 1d23) "1.d+23"))) + (assert (string= (format nil "~E" 1d23) "1.0d+23"))) ;;; Fixed-format bugs from CLISP's test suite (reported by Bruno ;;; Haible, bug 317) @@ -593,7 +593,7 @@ (with-test (:name (format :bug-308961)) (assert (string= (format nil "~4,1F" 0.001) " 0.0")) (assert (string= (format nil "~4,1@F" 0.001) "+0.0")) - (assert (string= (format nil "~E" 0.01) "1.e-2")) + (assert (string= (format nil "~E" 0.01) "1.0e-2")) (assert (string= (format nil "~G" 0.01) "1.00e-2"))) (with-test (:name (:fp-print-read-consistency single-float)) @@ -601,15 +601,15 @@ (oops)) (loop for f = most-positive-single-float then (/ f 2.0) while (> f 0.0) - do (loop repeat 10 - for fr = (random f) + do (loop for fr = (random f) + repeat 10 do (unless (eql fr (read-from-string (prin1-to-string fr))) (push fr oops) (return)))) (loop for f = most-negative-single-float then (/ f 2.0) while (< f -0.0) - do (loop repeat 10 - for fr = (- (random (- f))) + do (loop for fr = (- (random (- f))) + repeat 10 do (unless (eql fr (read-from-string (prin1-to-string fr))) (push fr oops) (return)))) @@ -625,16 +625,16 @@ ;; FIXME skipping denormalized floats due to bug 793774. (loop for f = most-positive-double-float then (/ f 2d0) while (> f 0d0) - do (loop repeat 10 - for fr = (random f) + do (loop for fr = (random f) + repeat 10 do (unless (float-denormalized-p fr) (unless (eql fr (read-from-string (prin1-to-string fr))) (push fr oops) (return))))) (loop for f = most-negative-double-float then (/ f 2d0) while (< f -0d0) - do (loop repeat 10 - for fr = (- (random (- f))) + do (loop for fr = (- (random (- f))) + repeat 10 do (unless (float-denormalized-p fr) (unless (eql fr (read-from-string (prin1-to-string fr))) (push fr oops) @@ -867,4 +867,30 @@ there")))) ;; The unmodified dispatch table never attempts to handle a subtype of INSTANCE. (let ((str (with-standard-io-syntax (write-to-string x :pretty t :readably nil)))) - (assert (search "#<SB-KERNEL:INSTANCE {" str))))) + (assert (search "#<SB-KERNEL:INSTANCE {" str)))) + (let ((x (sb-kernel:%make-funcallable-instance 5))) + (let ((str (write-to-string x :pretty nil))) + (assert (search "#<SB-KERNEL:FUNCALLABLE-INSTANCE {" str))))) + +(with-test (:name :functionless-funcallable-instance) + (let ((x (sb-pcl::%make-standard-funcallable-instance + #() + #-compact-instance-header #xdead))) + (assert (search "#<SB-PCL::STANDARD-FUNCALLABLE-INSTANCE" + (write-to-string x :pretty nil))))) ; should not crash + +(with-test (:name :bug-885320) + (let* ((form `(format nil "~E")) + (fun (compile nil `(lambda (x) (,@form x))))) + (assert (string= (funcall fun 1.0) "1.0e+0")) + (assert (string= (funcall fun 1.0d0) "1.0d+0")) + (assert (string= (apply (car form) (append (cdr form) (list 1.0))) "1.0e+0")) + (assert (string= (apply (car form) (append (cdr form) (list 1.0d0))) "1.0d+0")))) + +(with-test (:name (:bug-885320 :d-k+1)) + (let* ((form `(format nil "~,2,,3E")) + (fun (compile nil `(lambda (x) (,@form x))))) + (assert (string= (funcall fun 1.0) "100.e-2")) + (assert (string= (funcall fun 1.0d0) "100.d-2")) + (assert (string= (apply (car form) (append (cdr form) (list 1.0))) "100.e-2")) + (assert (string= (apply (car form) (append (cdr form) (list 1.0d0))) "100.d-2")))) diff --git a/tests/private-cons.impure.lisp b/tests/private-cons.impure.lisp index 7c801de4e9..2ed61db437 100644 --- a/tests/private-cons.impure.lisp +++ b/tests/private-cons.impure.lisp @@ -32,9 +32,14 @@ list)) #+gencgc +(progn +(defun page-words-used (index) + (ash (slot (deref sb-vm::page-table index) 'sb-vm::words-used*) -1)) +(defun page-need-to-zero (index) + (oddp (slot (deref sb-vm::page-table index) 'sb-vm::words-used*))) (defun test-private-consing () (let ((conses-per-page ; subtract one for the page header cons - (1- (/ sb-vm:gencgc-card-bytes (* 2 sb-vm:n-word-bytes)))) + (1- (/ sb-vm:gencgc-page-bytes (* 2 sb-vm:n-word-bytes)))) (counter 0) (pages) (recycle-me)) @@ -42,17 +47,15 @@ (let* ((cons (private-list (incf counter))) (index (sb-vm::find-page-index cons)) (base-address - (+ sb-vm:dynamic-space-start (* index sb-vm:gencgc-card-bytes))) + (+ sb-vm:dynamic-space-start (* index sb-vm:gencgc-page-bytes))) (final)) (push index pages) (assert (= cons (+ base-address (* 2 sb-vm:n-word-bytes)))) - ;; bytes-used should correspond to 2 conses, - ;; and the dirty flag should be 1. - (assert (= (slot (deref sb-vm::page-table index) 'sb-vm::bytes-used) - (logior (* 4 sb-vm:n-word-bytes) 1))) + ;; words-used should be 4, for 2 conses, + (assert (= (page-words-used index) 4)) (dotimes (i (1- conses-per-page)) (setq final (private-list (incf counter)))) - (assert (= final (+ base-address sb-vm:gencgc-card-bytes + (assert (= final (+ base-address sb-vm:gencgc-page-bytes (* -2 sb-vm:n-word-bytes)))) (push final recycle-me))) (dolist (list recycle-me) @@ -65,9 +68,10 @@ (assert (= (sb-vm::find-page-index (sb-sys:sap-int sap)) (pop pages))))) (alien-funcall (extern-alien "gc_dispose_private_pages" (function void))) - ;; Each of the pages should have zero bytes used and need-to-zero = 1 + ;; Each of the pages should have zero words used and need-to-zero = 1 (dolist (index pages) - (assert (= (slot (deref sb-vm::page-table index) 'sb-vm::bytes-used) 1))))) + (assert (page-need-to-zero index)) + (assert (= (page-words-used index) 0)))))) #-gencgc (defun test-private-consing () diff --git a/tests/profile.impure.lisp b/tests/profile.pure.lisp similarity index 82% rename from tests/profile.impure.lisp rename to tests/profile.pure.lisp index a82dc72873..7186250094 100644 --- a/tests/profile.impure.lisp +++ b/tests/profile.pure.lisp @@ -11,10 +11,7 @@ ;;;; absolutely no warranty. See the COPYING and CREDITS files for ;;;; more information. -(defpackage :profile-test - (:use :cl :sb-thread)) - -(in-package :profile-test) +(use-package "SB-THREAD") (defun miller-rabin-prime-p (n &optional (s 50)) "Miller-Rabin primality test written by R. Matthew Emerson." @@ -57,7 +54,7 @@ (w (make-semaphore)) (workers (loop repeat n-workers - collect (sb-thread:make-thread + collect (make-thread (let ((rs (make-random-state))) (lambda () (block nil @@ -73,16 +70,24 @@ t))))))))) (loop repeat n-workers do (wait-on-semaphore r)) (signal-semaphore w n-workers) - (mapcar #'sb-thread:join-thread workers)))) - -(in-package :cl-user) + (mapcar #'join-thread workers)))) +;;; 9 times out of 10 with #+(and cheneygc ppc) this seems to get: +;;; CORRUPTION WARNING in SBCL pid 61861: +;;; Memory fault at 0x4fc60000 (pc=0xfd7119c) +;;; The integrity of this image is possibly compromised. +;;; Exiting. +;;; 0: [I*]0xdf6a1088 pc=0xfd7119c {0x403f7b8+bd319e4} {code_serialno=343f} +;;; 1: [*] 0xdf6a0fe8 pc=0x40496b8 {0x403f7b8+9f00} (FLET "WITHOUT-GCING-BODY-112" :IN SB-BIGNUM::BIGNUM-TRUNCATE) +;;; and I really don't care why but since this file is allegedly "pure", +;;; its death kills all the remaining tests. (with-test (:name (profile :threads) + :skipped-on :cheneygc :broken-on :win32) - (profile "PROFILE-TEST") + (profile #.(package-name cl:*package*)) ;; This used to signal an error with threads (let* ((n #+sb-thread 5 #-sb-thread 1) - (res (profile-test::waste-cpu-cycles 10 256 n)) + (res (waste-cpu-cycles 10 256 n)) (want (make-list n :initial-element t))) (unless (equal res want) (error "wanted ~S, got ~S" want res))) diff --git a/tests/properties.impure.lisp b/tests/properties.pure.lisp similarity index 90% rename from tests/properties.impure.lisp rename to tests/properties.pure.lisp index 51519d70b1..f1126e0c6f 100644 --- a/tests/properties.impure.lisp +++ b/tests/properties.pure.lisp @@ -11,8 +11,6 @@ ;;;; absolutely no warranty. See the COPYING and CREDITS files for ;;;; more information. -(in-package "CL-USER") - (defun test-symbol (symbol) (setf (symbol-plist symbol) nil) (setf (get symbol 'foo) '(my list)) @@ -22,7 +20,10 @@ (assert (= (length (symbol-plist symbol)) 6)) (remprop symbol 'foo) (assert (not (get symbol 'foo)))) -(mapc #'test-symbol '(foo :keyword || t nil)) +(dolist (s '(foo :keyword || t nil)) + (let ((save (symbol-plist s))) + (unwind-protect (test-symbol s) + (setf (symbol-plist s) save)))) ;;; In early 0.7 versions on non-x86 ports, setting the property list ;;; of 'NIL would trash (CDR NIL), due to a screwup in the low-level ;;; layout of SYMBOL. (There are several low-level punnish tricks used diff --git a/tests/random.pure.lisp b/tests/random.pure.lisp index 83c5eff187..8383705a1e 100644 --- a/tests/random.pure.lisp +++ b/tests/random.pure.lisp @@ -151,3 +151,40 @@ (assert (< max number))))))) (test foo) (test bar)))))) + +;;; RANDOM with a float argument used to produce that argument as a +;;; return value with a probability depending on the magnitude of the +;;; argument. That behavior was wrong since the argument is an +;;; /exclusive/ upper bound for the range of produced values. The +;;; cases below increase the failure possibility as much as possible: +;;; an exclusive upper bound of LEAST-POSITIVE-*-FLOAT means that the +;;; respective 0 is the only valid return value and that the old code +;;; produced a wrong answer with probably 0.5 (assuming proper +;;; distribution of the produced values). +(with-test (:name (random float :upper-bound-exclusive)) + ;; SINGLE-FLOAT, possibly inlined + (let ((values (loop :repeat 10000 + :collect (random least-positive-single-float)))) + (assert (not (find 0.0f0 values :test-not #'=)))) + ;; DOUBLE-FLOAT, possibly inlined + (let ((values (loop :repeat 10000 + :collect (random least-positive-double-float)))) + (assert (not (find 0.0d0 values :test-not #'=)))) + (locally (declare (notinline random)) + ;; SINGLE-FLOAT, not inlined + (let ((values (loop :repeat 10000 + :collect (random least-positive-single-float)))) + (assert (not (find 0.0f0 values :test-not #'=)))) + ;; DOUBLE-FLOAT, not inlined + (let ((values (loop :repeat 10000 + :collect (random least-positive-double-float)))) + (assert (not (find 0.0d0 values :test-not #'=)))))) + +(with-test (:name :float-no-consing + :fails-on (or :mips :ppc) + :skipped-on :interpreter) + (let ((fun (checked-compile `(lambda () + (declare (optimize speed)) + (> (random 40d0) 1d0)) + :allow-notes nil))) + (ctu:assert-no-consing (funcall fun)))) diff --git a/tests/raw-slots-interleaved.impure.lisp b/tests/raw-slots-interleaved.impure.lisp index 09237977fc..a6289e5149 100644 --- a/tests/raw-slots-interleaved.impure.lisp +++ b/tests/raw-slots-interleaved.impure.lisp @@ -26,7 +26,14 @@ 0 :type ,(if (= i 64) 'sb-ext:word t)))))) (defbiggy)) -(assert (typep (sb-kernel:layout-bitmap +(macrolet ((def-100slots () + `(defstruct 100slots + ,@(loop for i from 0 repeat 100 + collect `(,(sb-int:symbolicate "SLOT" (write-to-string i)) + ,(format nil "This is ~D" i)))))) + (def-100slots)) + +(assert (typep (sb-kernel:wrapper-bitmap (sb-kernel::find-layout 'biggy)) 'bignum)) (defvar *x* nil) @@ -53,50 +60,29 @@ ;; Run it twice to make sure things really worked. (let ((*y* (make-biggy)) - (*x* (sb-kernel:layout-bitmap + (*x* (sb-kernel:wrapper-bitmap (sb-kernel::find-layout 'biggy)))) (sb-ext:gc :gen 1)) (princ 'did-pass-1) (terpri) (force-output) (let ((*y* (make-biggy)) - (*x* (sb-kernel:layout-bitmap + (*x* (sb-kernel:wrapper-bitmap (sb-kernel::find-layout 'biggy)))) (sb-ext:gc :gen 1)) (princ 'did-pass-2) (terpri) (force-output) -;; Test the C bignum bit extractor. -;; Surprisingly, there was a bug in it, unrelated to forwarding -;; pointers that remained dormant until the randomized -;; HUGE-MANYRAW test in 'defstruct.impure.lisp' found it. -(defun c-bignum-logbitp (index bignum) - (assert (typep bignum 'bignum)) - (sb-sys:with-pinned-objects (bignum) - (alien-funcall (extern-alien "positive_bignum_logbitp" - (function boolean int system-area-pointer)) - index - (sb-sys:int-sap - (- (sb-kernel:get-lisp-obj-address bignum) - sb-vm:other-pointer-lowtag))))) - -(with-test (:name :c-bignum-logbitp) - ;; walking 1 bit - (dotimes (i 256) - (let ((num (ash 1 i))) - (when (typep num 'bignum) - (dotimes (j 257) - (assert (eq (c-bignum-logbitp j num) - (logbitp j num))))))) - ;; random bits - (let ((max (ash 1 768))) - (dotimes (i 100) - (let ((num (random max))) - (when (typep num 'bignum) - (dotimes (j (* (sb-bignum:%bignum-length num) - sb-vm:n-word-bits)) - (assert (eq (c-bignum-logbitp j num) - (logbitp j num))))))))) +(defun collect-slot-values (struct &aux result) + (sb-kernel:do-instance-tagged-slot (i struct) + (push (sb-kernel:%instance-ref struct i) result)) + (nreverse result)) + +(with-test (:name :sign-extended-bitmap + :fails-on :interpreter) + ;; could have 100 or 101 physical payload slots depending on + ;; presence of a padding word + (assert (>= (length (collect-slot-values (make-100slots))) 100))) ;; for testing the comparator (defstruct foo1 @@ -114,24 +100,26 @@ (c 'cee)) ; 13 9 (defvar *afoo* (make-foo1)) -(assert (= (sb-kernel:layout-length (sb-kernel:layout-of *afoo*)) +(assert (= (sb-kernel:wrapper-length (sb-kernel:wrapper-of *afoo*)) (sb-kernel:%instance-length *afoo*))) -(with-test (:name :tagged-slot-iterator-macro) +(with-test (:name :tagged-slot-iterator-macro + :fails-on :interpreter) ;; on 32-bit, the logical length is 14, which means 15 words (with header), ;; but slot index 14 (word index 15) exists after padding to 16 memory words. + ;; It is allowed to hold a fixnum (or any non-pointer) but naught else. #-64-bit (progn (assert (= (sb-kernel:%instance-length *afoo*) 14)) - (setf (sb-kernel:%instance-ref *afoo* 14) 'magic)) + (setf (sb-kernel:%instance-ref *afoo* 14) #xdead)) ;; on 64-bit, the logical length is 10, which means 11 words (with header), ;; but slot index 10 (word index 11) exists after padding to 12 memory words. #+64-bit (progn (assert (= (sb-kernel:%instance-length *afoo*) 10)) - (setf (sb-kernel:%instance-ref *afoo* 10) 'magic)) + (setf (sb-kernel:%instance-ref *afoo* 10) #xdead)) (let (l) (sb-kernel:do-instance-tagged-slot (i *afoo*) (push `(,i ,(sb-kernel:%instance-ref *afoo* i)) l)) (assert (equalp (nreverse l) - #-64-bit `((3 aaay) (9 bee) (13 cee) (14 magic)) - #+64-bit `((2 aaay) (6 bee) (9 cee) (10 magic)))))) + #-64-bit `((3 aaay) (9 bee) (13 cee)) + #+64-bit `((2 aaay) (6 bee) (9 cee)))))) (defvar *anotherfoo* (make-foo1)) diff --git a/tests/reader.impure.lisp b/tests/reader.impure.lisp index cfcd89d5d8..e9f4456eb6 100644 --- a/tests/reader.impure.lisp +++ b/tests/reader.impure.lisp @@ -242,6 +242,10 @@ #+sb-unicode (with-test (:name :unicode-dispatch-macros) + ;; Smoke test: (set-syntax-from-char unicode-char ordinary-constituent-char) + ;; should not fail + (set-syntax-from-char (code-char 300) #\a) + ;; (let ((*readtable* (copy-readtable))) (make-dispatch-macro-character (code-char #x266F)) ; musical sharp (set-dispatch-macro-character @@ -252,9 +256,12 @@ (let ((x (read-from-string (map 'string #'code-char '(#x266F #x221E))))) (assert (eq x :infinity)) + ;; I don't know what this was testing, and it's "noisy". Can we fix that? + ;; I think we used to treat NIL as *removing* the macro function, which is not + ;; a specified action. But neither could NIL ever be a function designator. (set-dispatch-macro-character (code-char #x266F) (code-char #x221E) nil) (assert (zerop (hash-table-count - (car (sb-impl::%dispatch-macro-char-table + (cdr (sb-impl::%dispatch-macro-char-table (get-macro-character (code-char #x266F))))))))) (let ((*readtable* (copy-readtable))) diff --git a/tests/reader.pure.lisp b/tests/reader.pure.lisp index 74ab507231..78f00e587d 100644 --- a/tests/reader.pure.lisp +++ b/tests/reader.pure.lisp @@ -11,213 +11,219 @@ ;;;; absolutely no warranty. See the COPYING and CREDITS files for ;;;; more information. -(assert (equal (symbol-name '#:|fd\sA|) "fdsA")) - -;;; Prior to sbcl-0.7.2.10, SBCL disobeyed the ANSI requirements on -;;; returning NIL for unset dispatch-macro-character functions. (bug -;;; 151, fixed by Alexey Dejenka sbcl-devel "bug 151" 2002-04-12) -(assert (not (get-dispatch-macro-character #\# #\{))) -(assert (not (get-dispatch-macro-character #\# #\0))) -;;; And we might as well test that we don't have any cross-compilation -;;; shebang residues left... -(assert (not (get-dispatch-macro-character #\# #\!))) -;;; Also test that all the illegal sharp macro characters are -;;; recognized as being illegal. -(loop for char in '(#\Backspace #\Tab #\Newline #\Linefeed - #\Page #\Return #\Space #\) #\<) - do (assert (get-dispatch-macro-character #\# char))) - -(assert (not (ignore-errors (get-dispatch-macro-character #\! #\0) - t))) - -;;; In sbcl-0.7.3, GET-MACRO-CHARACTER and SET-MACRO-CHARACTER didn't -;;; use NIL to represent the no-macro-attached-to-this-character case -;;; as ANSI says they should. (This problem is parallel to the -;;; GET-DISPATCH-MACRO misbehavior fixed in sbcl-0.7.2.10, but -;;; was fixed a little later.) -(dolist (customizable-char - ;; According to ANSI "2.1.4 Character Syntax Types", these - ;; characters are reserved for the programmer. - '(#\? #\! #\[ #\] #\{ #\})) - ;; So they should have no macro-characterness. - (multiple-value-bind (macro-fun non-terminating-p) - (get-macro-character customizable-char) - (assert (null macro-fun)) - ;; Also, in a bit of ANSI weirdness, NON-TERMINATING-P can be - ;; true only when MACRO-FUN is true. (When the character - ;; is not a macro character, it can be embedded in a token, - ;; so it'd be more logical for NON-TERMINATING-P to be T in - ;; this case; but ANSI says it's NIL in this case. - (assert (null non-terminating-p)))) - -;;; rudimentary test of SET-SYNTAX-FROM-CHAR, just to verify that it -;;; wasn't totally broken by the GET-MACRO-CHARACTER/SET-MACRO-CHARACTER -;;; fixes in 0.7.3.16 -(assert (= 123579 (read-from-string "123579"))) -(let ((*readtable* (copy-readtable))) - (set-syntax-from-char #\7 #\;) - (assert (= 1235 (read-from-string "123579")))) +(with-test (:name :random-describe) + (describe sb-impl::*empty-extended-char-table* (make-broadcast-stream))) + +(with-test (:name (:reader symbol :escape)) + (assert (equal (symbol-name '#:|fd\sA|) "fdsA"))) + +(with-test (:name (get-dispatch-macro-character :return-value)) + ;; Prior to sbcl-0.7.2.10, SBCL disobeyed the ANSI requirements on + ;; returning NIL for unset dispatch-macro-character functions. (bug + ;; 151, fixed by Alexey Dejenka sbcl-devel "bug 151" 2002-04-12) + (assert (not (get-dispatch-macro-character #\# #\{))) + (assert (not (get-dispatch-macro-character #\# #\0))) + ;; And we might as well test that we don't have any cross-compilation + ;; shebang residues left... + (assert (not (get-dispatch-macro-character #\# #\!))) + ;; Also test that all the illegal sharp macro characters are + ;; recognized as being illegal. + (loop for char in '(#\Backspace #\Tab #\Newline #\Linefeed + #\Page #\Return #\Space #\) #\<) + do (assert (get-dispatch-macro-character #\# char))) + + (assert-error (get-dispatch-macro-character #\! #\0))) + +(with-test (:name (get-macro-character :return-value)) + ;; In sbcl-0.7.3, GET-MACRO-CHARACTER and SET-MACRO-CHARACTER didn't + ;; use NIL to represent the no-macro-attached-to-this-character case + ;; as ANSI says they should. (This problem is parallel to the + ;; GET-DISPATCH-MACRO misbehavior fixed in sbcl-0.7.2.10, but was + ;; fixed a little later.) + (dolist (customizable-char + ;; According to ANSI "2.1.4 Character Syntax Types", these + ;; characters are reserved for the programmer. + '(#\? #\! #\[ #\] #\{ #\})) + ;; So they should have no macro-characterness. + (multiple-value-bind (macro-fun non-terminating-p) + (get-macro-character customizable-char) + (assert (null macro-fun)) + ;; Also, in a bit of ANSI weirdness, NON-TERMINATING-P can be + ;; true only when MACRO-FUN is true. (When the character is not + ;; a macro character, it can be embedded in a token, so it'd be + ;; more logical for NON-TERMINATING-P to be T in this case; but + ;; ANSI says it's NIL in this case. + (assert (null non-terminating-p))))) + +(with-test (:name (set-syntax-from-char :smoke)) + ;; rudimentary test of SET-SYNTAX-FROM-CHAR, just to verify that it + ;; wasn't totally broken by the GET-MACRO-CHARACTER/SET-MACRO-CHARACTER + ;; fixes in 0.7.3.16 + (assert (= 123579 (read-from-string "123579"))) + (let ((*readtable* (copy-readtable))) + (set-syntax-from-char #\7 #\;) + (assert (= 1235 (read-from-string "123579"))))) ;;; PARSE-INTEGER must signal an error of type PARSE-ERROR if it is ;;; unable to parse an integer and :JUNK-ALLOWED is NIL. -(macrolet ((assert-parse-error (form) - `(multiple-value-bind (val cond) - (ignore-errors ,form) - (assert (null val)) - (assert (typep cond 'parse-error))))) - (assert-parse-error (parse-integer " ")) - (assert-parse-error (parse-integer "12 a")) - (assert-parse-error (parse-integer "12a")) - (assert-parse-error (parse-integer "a")) - (assert (= (parse-integer "12") 12)) - (assert (= (parse-integer " 12 ") 12)) - (assert (= (parse-integer " 12asdb" :junk-allowed t) 12))) +(with-test (:name (parse-integer :smoke)) + (macrolet ((assert-parse-error (form) + `(assert-error ,form parse-error))) + (assert-parse-error (parse-integer " ")) + (assert-parse-error (parse-integer "12 a")) + (assert-parse-error (parse-integer "12a")) + (assert-parse-error (parse-integer "a")) + (assert (= (parse-integer "12") 12)) + (assert (= (parse-integer " 12 ") 12)) + (assert (= (parse-integer " 12asdb" :junk-allowed t) 12)))) ;;; #A notation enforces that once one 0 dimension has been found, all ;;; subsequent ones are also 0. -(assert (equal (array-dimensions (read-from-string "#3A()")) - '(0 0 0))) -(assert (equal (array-dimensions (read-from-string "#3A(())")) - '(1 0 0))) -(assert (equal (array-dimensions (read-from-string "#3A((() ()))")) - '(1 2 0))) +(with-test (:name (:sharpsign-a-reader-macro :initial-elements)) + (assert (equal (array-dimensions (read-from-string "#3A()")) + '(0 0 0))) + (assert (equal (array-dimensions (read-from-string "#3A(())")) + '(1 0 0))) + (assert (equal (array-dimensions (read-from-string "#3A((() ()))")) + '(1 2 0)))) ;;; Bug reported by Nikodemus Siivola on sbcl-devel 2003-07-21: ;;; package misconfiguration -(assert (eq - (handler-case (with-input-from-string (s "cl:") (read s)) - (end-of-file (c) - (declare (ignore c)) - 'good)) - 'good)) +(with-test (:name (with-input-from-string :package-misconfiguration)) + (assert-error (with-input-from-string (s "cl:") (read s)) end-of-file)) ;;; Bugs found by Paul Dietz -(assert (equal (multiple-value-list - (parse-integer " 123 ")) - '(123 12))) - -(let* ((base "xxx 123 yyy") - (intermediate (make-array 8 :element-type (array-element-type base) - :displaced-to base - :displaced-index-offset 2)) - (string (make-array 6 :element-type (array-element-type base) - :displaced-to intermediate - :displaced-index-offset 1))) +(with-test (:name (parse-integer 1)) (assert (equal (multiple-value-list - (parse-integer string)) - '(123 6)))) - -(let ((*read-base* *read-base*)) - (dolist (float-string '(".9" ".9e9" ".9e+9" ".9e-9" - "-.9" "-.9e9" "-.9e+9" "-.9e-9" - "+.9" "+.9e9" "+.9e+9" "+.9e-9" - "0.9" "0.9e9" "0.9e+9" "0.9e-9" - "9.09" "9.09e9" "9.09e+9" "9.09e-9" - #|"9e9" could be integer|# "9e+9" "9e-9")) - (loop for i from 2 to 36 - do (setq *read-base* i) - do (assert (typep (read-from-string float-string) - *read-default-float-format*)) - do (assert (typep - (read-from-string (substitute #\E #\e float-string)) - *read-default-float-format*)) - if (position #\e float-string) - do (assert (typep - (read-from-string (substitute #\s #\e float-string)) - 'short-float)) - and do (assert (typep - (read-from-string (substitute #\S #\e float-string)) - 'short-float)) - and do (assert (typep - (read-from-string (substitute #\f #\e float-string)) - 'single-float)) - and do (assert (typep - (read-from-string (substitute #\F #\e float-string)) - 'single-float)) - and do (assert (typep - (read-from-string (substitute #\d #\e float-string)) - 'double-float)) - and do (assert (typep - (read-from-string (substitute #\D #\e float-string)) - 'double-float)) - and do (assert (typep - (read-from-string (substitute #\l #\e float-string)) - 'long-float)) - and do (assert (typep - (read-from-string (substitute #\L #\e float-string)) - 'long-float))))) - -(let ((*read-base* *read-base*)) - (dolist (integer-string '("1." "2." "3." "4." "5." "6." "7." "8." "9." "0.")) - (loop for i from 2 to 36 - do (setq *read-base* i) - do (assert (typep (read-from-string integer-string) 'integer))))) - -(let ((*read-base* *read-base*)) - (dolist (symbol-string '("A." "a." "Z." "z." - - "+.9eA" "+.9ea" - - "0.A" "0.a" "0.Z" "0.z" - - #|"9eA" "9ea"|# "9e+A" "9e+a" "9e-A" "9e-a" - #|"Ae9" "ae9"|# "Ae+9" "ae+9" "Ae-9" "ae-9" - - "ee+9" "Ee+9" "eE+9" "EE+9" - "ee-9" "Ee-9" "eE-9" "EE-9" - - "A.0" "A.0e10" "a.0" "a.0e10" - - "1e1e+9")) - (loop for i from 2 to 36 - do (setq *read-base* i) - do (assert (typep (read-from-string symbol-string) 'symbol))))) - -(let ((standard-chars " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ + (parse-integer " 123 ")) + '(123 12)))) + +(with-test (:name (parse-integer 2)) + (let* ((base "xxx 123 yyy") + (intermediate (make-array 8 :element-type (array-element-type base) + :displaced-to base + :displaced-index-offset 2)) + (string (make-array 6 :element-type (array-element-type base) + :displaced-to intermediate + :displaced-index-offset 1))) + (assert (equal (multiple-value-list + (parse-integer string)) + '(123 6))))) + +(with-test (:name (*read-base* 1)) + (let ((*read-base* *read-base*)) + (dolist (float-string '(".9" ".9e9" ".9e+9" ".9e-9" + "-.9" "-.9e9" "-.9e+9" "-.9e-9" + "+.9" "+.9e9" "+.9e+9" "+.9e-9" + "0.9" "0.9e9" "0.9e+9" "0.9e-9" + "9.09" "9.09e9" "9.09e+9" "9.09e-9" + #|"9e9" could be integer|# "9e+9" "9e-9")) + (loop for i from 2 to 36 + do (setq *read-base* i) + do (assert (typep (read-from-string float-string) + *read-default-float-format*)) + do (assert (typep + (read-from-string (substitute #\E #\e float-string)) + *read-default-float-format*)) + if (position #\e float-string) + do (assert (typep + (read-from-string (substitute #\s #\e float-string)) + 'short-float)) + and do (assert (typep + (read-from-string (substitute #\S #\e float-string)) + 'short-float)) + and do (assert (typep + (read-from-string (substitute #\f #\e float-string)) + 'single-float)) + and do (assert (typep + (read-from-string (substitute #\F #\e float-string)) + 'single-float)) + and do (assert (typep + (read-from-string (substitute #\d #\e float-string)) + 'double-float)) + and do (assert (typep + (read-from-string (substitute #\D #\e float-string)) + 'double-float)) + and do (assert (typep + (read-from-string (substitute #\l #\e float-string)) + 'long-float)) + and do (assert (typep + (read-from-string (substitute #\L #\e float-string)) + 'long-float)))))) + +(with-test (:name (*read-base* 2)) + (let ((*read-base* *read-base*)) + (dolist (integer-string '("1." "2." "3." "4." "5." "6." "7." "8." "9." "0.")) + (loop for i from 2 to 36 + do (setq *read-base* i) + do (assert (typep (read-from-string integer-string) 'integer)))))) + +(with-test (:name (*read-base* 3)) + (let ((*read-base* *read-base*)) + (dolist (symbol-string '("A." "a." "Z." "z." + + "+.9eA" "+.9ea" + + "0.A" "0.a" "0.Z" "0.z" + + #|"9eA" "9ea"|# "9e+A" "9e+a" "9e-A" "9e-a" + #|"Ae9" "ae9"|# "Ae+9" "ae+9" "Ae-9" "ae-9" + + "ee+9" "Ee+9" "eE+9" "EE+9" + "ee-9" "Ee-9" "eE-9" "EE-9" + + "A.0" "A.0e10" "a.0" "a.0e10" + + "1e1e+9")) + (loop for i from 2 to 36 + do (setq *read-base* i) + do (assert (typep (read-from-string symbol-string) 'symbol)))))) + +(with-test (:name (readtable :specified-macro-characters)) + (let ((standard-chars " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ ") - (standard-terminating-macro-chars "\"'(),;`") - (standard-nonterminating-macro-chars "#")) - (flet ((frob (char) - (multiple-value-bind (fun non-terminating-p) - (get-macro-character char) - (cond - ((find char standard-terminating-macro-chars) - (unless (and fun (not non-terminating-p)) - (list char))) - ((find char standard-nonterminating-macro-chars) - (unless (and fun non-terminating-p) - (list char))) - (t (unless (and (not fun) (not non-terminating-p)) - (list char))))))) - (let ((*readtable* (copy-readtable nil))) - (assert (null (loop for c across standard-chars append (frob c))))))) - -(let ((standard-chars " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ + (standard-terminating-macro-chars "\"'(),;`") + (standard-nonterminating-macro-chars "#")) + (flet ((frob (char) + (multiple-value-bind (fun non-terminating-p) + (get-macro-character char) + (cond ((find char standard-terminating-macro-chars) + (unless (and fun (not non-terminating-p)) + (list char))) + ((find char standard-nonterminating-macro-chars) + (unless (and fun non-terminating-p) + (list char))) + (t (unless (and (not fun) (not non-terminating-p)) + (list char))))))) + (let ((*readtable* (copy-readtable nil))) + (assert (null (loop for c across standard-chars append (frob c)))))))) + +(with-test (:name (readtable :specified-dispatch-macro-characters)) + (let ((standard-chars " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ ") - (undefined-chars "!\"$%&,;>?@[]^_`~{}/dDeEfFgGhHiIjJkKlLmMnNqQtTuUvVwWyYzZ")) - (flet ((frob (char) - (let ((fun (get-dispatch-macro-character #\# char))) - (cond - ((find char undefined-chars) - (when fun (list char))) - ((digit-char-p char 10) - (when fun (list char))) - (t - (unless fun (list char))))))) - (let ((*readtable* (copy-readtable nil))) - (assert (null (loop for c across standard-chars append (frob c))))))) - -(with-test (:name :copy-readtable-with-unicode-macro + (undefined-chars "!\"$%&,;>?@[]^_`~{}/dDeEfFgGhHiIjJkKlLmMnNqQtTuUvVwWyYzZ")) + (flet ((frob (char) + (let ((fun (get-dispatch-macro-character #\# char))) + (cond ((find char undefined-chars) + (when fun (list char))) + ((digit-char-p char 10) + (when fun (list char))) + (t + (unless fun (list char))))))) + (let ((*readtable* (copy-readtable nil))) + (assert (null (loop for c across standard-chars append (frob c)))))))) + +(with-test (:name (copy-readtable :with-unicode-macro) :skipped-on (not :sb-unicode)) (let ((rt (copy-readtable))) (set-macro-character (code-char #x100fa) #'error nil rt) - (assert (plusp (hash-table-count (sb-impl::character-macro-hash-table rt)))) + (assert (plusp (hash-table-count (sb-impl::extended-char-table rt)))) (copy-readtable nil rt) (assert (null (get-macro-character #\UFC rt))))) ;;; All these must return a primary value of NIL when *read-suppress* is T ;;; Reported by Bruno Haible on cmucl-imp 2004-10-25. -(with-test (:name :read-suppress-char-macros) +(with-test (:name (*read-suppress* :char-macros)) (let ((*read-suppress* t)) (assert (null (read-from-string "(1 2 3)"))) (assert (null (with-input-from-string (s "abc xyz)") @@ -235,7 +241,7 @@ ;;; System code that asks whether %READ-PRESERVING-WHITESPACE hit EOF ;;; mistook NIL as an object returned normally for NIL the default eof mark. -(with-test (:name :read-preserving-whitespace-file-position) +(with-test (:name (read-preserving-whitespace file-position)) (multiple-value-bind (obj pos1) (read-from-string "NIL A") (declare (ignore obj)) (multiple-value-bind (obj pos2) (read-from-string "NNN A") @@ -272,23 +278,27 @@ ;;; EOF-ERROR-P defaults to true. Reported by Bruno Haible on ;;; cmucl-imp 2004-10-18. -(multiple-value-bind (res err) (ignore-errors (read-from-string "")) - (assert (not res)) - (assert (typep err 'end-of-file))) +(with-test (:name (read-from-string :eof-error)) + (assert-error (read-from-string "") end-of-file) + (assert (equal '((0 . "A") (1 . "B")) + (coerce (read-from-string "#((0 . \"A\") (1 . \"B\"))") + 'list)))) -(assert (equal '((0 . "A") (1 . "B")) - (coerce (read-from-string "#((0 . \"A\") (1 . \"B\"))") - 'list))) +(with-test (:name (read-delimited-list :non-recursive :circularity)) + (let* ((stream (make-string-input-stream "#1=(nil) #1#)")) + (result (read-delimited-list #\) stream))) + (assert (eq (first result) (second result))))) ;;; parse-integer uses whitespace[1] not whitespace[2] as its ;;; definition of whitespace to skip. -(let ((*readtable* (copy-readtable))) - (set-syntax-from-char #\7 #\Space) - (assert (= 710 (parse-integer "710")))) +(with-test (:name (parse-integer :whitespace-handling)) + (let ((*readtable* (copy-readtable))) + (set-syntax-from-char #\7 #\Space) + (assert (= 710 (parse-integer "710")))) -(let ((*readtable* (copy-readtable))) - (set-syntax-from-char #\7 #\Space) - (assert (string= (format nil "~7D" 1) " 1"))) + (let ((*readtable* (copy-readtable))) + (set-syntax-from-char #\7 #\Space) + (assert (string= (format nil "~7D" 1) " 1")))) (with-test (:name :report-reader-error) ;; Apparently this wants to test the printing of the error string @@ -302,12 +312,13 @@ ;;; The GET-MACRO-CHARACTER in SBCL <= "1.0.34.2" bogusly computed its ;;; second return value relative to *READTABLE* rather than the passed ;;; readtable. -(let* ((*readtable* (copy-readtable nil))) - (set-syntax-from-char #\" #\A) - (multiple-value-bind (reader-fn non-terminating-p) - (get-macro-character #\" (copy-readtable nil)) - (declare (ignore reader-fn)) - (assert (not non-terminating-p)))) +(with-test (:name (get-macro-character :argument)) + (let* ((*readtable* (copy-readtable nil))) + (set-syntax-from-char #\" #\A) + (multiple-value-bind (reader-fn non-terminating-p) + (get-macro-character #\" (copy-readtable nil)) + (declare (ignore reader-fn)) + (assert (not non-terminating-p))))) (with-test (:name :bug-309093) (assert (eq :error @@ -316,7 +327,7 @@ (reader-error () :error))))) -(with-test (:name :set-syntax-from-char-dispatch-macro-char) +(with-test (:name (set-syntax-from-char :dispatch-macro-char)) (let ((rt (copy-readtable))) (make-dispatch-macro-character #\! nil rt) (set-dispatch-macro-character #\! #\! (constantly 'bang^2) rt) @@ -327,7 +338,7 @@ (set-syntax-from-char #\! #\! rt) (assert (eq '!! (maybe-bang)))))) -(with-test (:name :read-in-package-syntax) +(with-test (:name :read-in-package-syntax :skipped-on :sb-devel) (assert (equal '(sb-c::a (sb-kernel::x sb-kernel::y) sb-c::b) (read-from-string "sb-c::(a sb-kernel::(x y) b)"))) (assert (equal '(cl-user::yes-this-is-sbcl) @@ -359,8 +370,7 @@ ;; - calling SUBSEQ for package names ;; - multiple-value-call in WITH-CHAR-MACRO-RESULT ;; - the initial cons cell in READ-LIST -(with-test (:name :read-does-not-cons-per-se - :skipped-on (:or :interpreter (:not :x86-64))) +(with-test (:name :read-does-not-cons-per-se :skipped-on :interpreter) (flet ((test-reading (string) (let ((s (make-string-input-stream string))) (read s) ; once outside the loop, to make A-SYMBOL @@ -389,7 +399,7 @@ ;; impossible to cons 1 byte per run. ;; If this still fails, it might be due to somebody changing the ;; backend-page-bytes to exceed 32KB. Not sure what to do about that. - (test-reading "4.0s0") + #+64-bit (test-reading "4.0s0") (test-reading "COMMON-LISP-USER::A-SYMBOL") (test-reading "()") (test-reading "#\\-") ; should not copy the token buffer @@ -408,9 +418,14 @@ (sb-int:simple-reader-error () :win)) :win))) +(with-test (:name :sharp-star-default-fill :skipped-on :sbcl) + ;; can't assert anything about bits beyond the supplied ones + (let ((bv (opaque-identity #*11))) + (assert (= (sb-kernel:%vector-raw-bits bv 0) 3)))) + ;;; The WITH-FAST-READ-BYTE macro accidentally left the package lock ;;; of FAST-READ-BYTE disabled during its body. -(with-test (:name :fast-read-byte-package-lock) +(with-test (:name :fast-read-byte-package-lock :skipped-on :sb-devel) (let ((fun ;; Suppress the compiler output to avoid noise when running the ;; test. (There are a warning and an error about the package diff --git a/tests/redblack.pure.lisp b/tests/redblack.impure.lisp similarity index 63% rename from tests/redblack.pure.lisp rename to tests/redblack.impure.lisp index 11a979f2b1..362a28b2e6 100644 --- a/tests/redblack.pure.lisp +++ b/tests/redblack.impure.lisp @@ -1,26 +1,39 @@ ;;;; Tests -(add-package-local-nickname "REDBLACK" "SB-RBTREE") +(let ((*evaluator-mode* :compile)) (load "../src/code/redblack.lisp")) + +(add-package-local-nickname "REDBLACK" "SB-RBTREE.MAP") (use-package 'sb-int) -(import 'redblack::(red black redp blackp +(import 'sb-rbtree::(red black)) +(import 'redblack::(redp blackp color-of left right node-key node-value data find= find<=)) +(load "bbtree-test-util.lisp") -(defun verify-invariants (root print) +(defmacro define-verifier (name package + key-decoder sentinel-min sentinel-max) +`(defun ,name (root print) (unless root - (return-from verify-invariants)) + (return-from ,name)) + ;; Pick new names or else: "Lock on package SB-RBTREE.MAP violated when + ;; binding NODE-KEY as a local function while in package TEST.." etc + (flet ((key (x) (,key-decoder (,(intern "NODE-KEY" package) x))) + (*left (x) (,(intern "LEFT" package) x)) + (*right (x) (,(intern "RIGHT" package) x)) + (*redp (x) (,(intern "REDP" package) x)) + (*blackp (x) (,(intern "BLACKP" package) x)) + (*color-of (x) (,(intern "COLOR-OF" package) x))) + (declare (inline node-key left right redp blackp color-of)) ;; Binary search tree invariant - (named-let recurse ((node root) - (min most-negative-fixnum) - (max most-positive-fixnum)) - (assert (< min (node-key node) max)) + (named-let recurse ((node root) (min ,sentinel-min) (max ,sentinel-max)) + (assert (< min (key node) max)) ;; every descendant to the left has a key strictly less than this key - (awhen (left node) (recurse it min (node-key node))) + (awhen (*left node) (recurse it min (key node))) ;; every descendant to the right has a key strictly more than this key - (awhen (right node) (recurse it (node-key node) max))) + (awhen (*right node) (recurse it (key node) max))) ;; Red/black tree invariants - (assert (eq (color-of root) 'black)) + (assert (eq (*color-of root) 'black)) (let ((h (make-hash-table :test #'eq)) (count-red 0) (count-black 0) @@ -29,26 +42,32 @@ (labels ((black-height (node) (or (gethash node h) (setf (gethash node h) - (let ((l (black-height (left node))) - (r (black-height (right node)))) + (let ((l (black-height (*left node))) + (r (black-height (*right node)))) (assert (= l r)) - (if (eq (color-of node) 'black) (1+ l) l)))))) + (if (eq (*color-of node) 'black) (1+ l) l)))))) ;; Child colors and black height (named-let recurse ((node root)) - (ecase (color-of node) + (ecase (*color-of node) (red (incf count-red)) (black (incf count-black))) ;; If a node is red then both its children are black - (when (redp node) - (awhen (left node) (assert (blackp it))) - (awhen (right node) (assert (blackp it)))) - (acond ((left node) (recurse it)) (t (incf count-nil))) - (acond ((right node) (recurse it)) (t (incf count-nil)))) + (when (*redp node) + (awhen (*left node) (assert (*blackp it))) + (awhen (*right node) (assert (*blackp it)))) + (acond ((*left node) (recurse it)) (t (incf count-nil))) + (acond ((*right node) (recurse it)) (t (incf count-nil)))) (when print (format t "red=~3d black=~3d nil=~3d black-height = ~3d~%" count-red count-black count-nil (black-height root)))))) +)) +(define-verifier verify-invariants "SB-RBTREE.MAP" + identity most-negative-fixnum most-positive-fixnum) +(define-verifier verify-invariants-word "SB-RBTREE.WORD" + sb-kernel:get-lisp-obj-address 0 sb-ext:most-positive-word) (compile 'verify-invariants) +(compile 'verify-invariants-word) (defun random-integer-seq (n &aux seq) (let ((a (make-array n :fill-pointer n))) @@ -140,6 +159,44 @@ (tree (buildtree n))) (test-deletion tree 5))) +(defun code-as-fixnum (c) + (sb-kernel:make-lisp-obj + (logandc2 (sb-kernel:get-lisp-obj-address c) sb-vm:lowtag-mask))) +(compile 'code-as-fixnum) + +(with-test (:name :redblack-codeblob-tree) + (let (tree list) + (format t "~&Insertion ...") (force-output) + ;; 32-bit tends to exhaust the heap if performing insertion inside + ;; MAP-CODE-OBJECTS because of disabled GC. So collect first, then insert. + ;; It's the invariant checker that's a memory hog- + ;; this would only cons 8MiB without the checker. + (sb-vm:map-code-objects + (lambda (x) + (when (= (sb-kernel:generation-of x) sb-vm:+pseudo-static-generation+) + (push (code-as-fixnum x) list)))) + (progn ; time + (dolist (x list) + (setq tree (sb-rbtree.word:insert tree x)) + ;; speed up insertion by checking invariants only once in while + (when (zerop (random 6)) (verify-invariants-word tree nil)))) + (format t "~&Deletion ...") (force-output) + (let* ((rs (make-random-state t)) + (tests (let ((*random-state* rs)) (shuffle list))) + (n (length tests))) + (loop + (let ((subseq (subseq tests 0 (min 10 n)))) + (decf n (length subseq)) + ;; assert that all items in subseq are present + (dolist (x subseq) (assert (sb-rbtree.word:find= x tree))) + ;; delete them + (dolist (x subseq) (setq tree (sb-rbtree.word:delete x tree))) + (verify-invariants-word tree nil) + ;; now they're not found + (dolist (x subseq) (assert (not (sb-rbtree.word:find= x tree)))) + (when (null (setq tests (nthcdr (length subseq) tests))) + (return))))))) + (defun test-randomly (&optional (n 10) print &aux (trial 0)) (loop repeat n do (when print @@ -211,3 +268,10 @@ (dotimes (i n-items) (setq tree (redblack:insert tree i i))) tree) + +(defun test-rb-find-inexact (n-nodes n-iterations) + (bbtree-test:test-find-inexact-macro redblack:insert + find<= redblack:find>= node-key)) + +(test-util:with-test (:name :rb-find-inexact) + (bbtree-test:exercise-find-inexact 'test-rb-find-inexact)) diff --git a/tests/relocation.test.sh b/tests/relocation.test.sh index d3fd61458b..48b0d55d6a 100755 --- a/tests/relocation.test.sh +++ b/tests/relocation.test.sh @@ -5,8 +5,9 @@ # The relocation test binary can only be built on linux. # FIXME: This test _should_ work on any architecture, but it doesn't, # so there must have been a regression in the heap relocator. -run_sbcl --eval '(exit :code (or #+linux 0 1))' -if [ $? -eq 1 ] +data=`run_sbcl --eval '(progn #+linux(progn(princ "fakemap") #+64-bit(princ "_64")))' \ + --quit` +if [ -z "$data" ] then # shell tests don't have a way of exiting as "not applicable" exit $EXIT_TEST_WIN @@ -23,15 +24,17 @@ set -e # KLUDGE: assume N = 6 # FIXME: don't assume that N = 6 -export SBCL_FAKE_MMAP_INSTRUCTION_FILE=`pwd`/heap-reloc/fakemap +export SBCL_FAKE_MMAP_INSTRUCTION_FILE=`pwd`/heap-reloc/$data i=1 while [ $i -le 6 ] do - echo Trial $i - i=`expr $i + 1` + export SBCL_FAKE_MMAP_INSTRUCTION_LINE=$i $test_sbcl --lose-on-corruption --disable-ldb --noinform --core ../output/sbcl.core \ --no-sysinit --no-userinit --noprint --disable-debugger \ - --eval '(gc :full t)' --quit + --eval '(gc :full t)' \ + --eval '(defun fib (n) (if (<= n 1) 1 (+ (fib (- n 1)) (fib (- n 2)))))' \ + --eval "(compile 'fib)" -quit + i=`expr $i + 1` done rm -f $test_sbcl diff --git a/tests/run-compiler.sh b/tests/run-compiler.sh index bff44c1109..913e2c8a72 100755 --- a/tests/run-compiler.sh +++ b/tests/run-compiler.sh @@ -2,7 +2,7 @@ platform="${SBCL_SOFTWARE_TYPE}-${SBCL_MACHINE_TYPE}" -if [ -z $CC ]; then +if [ -z "$CC" ]; then if [ -x "`command -v cc`" ]; then CC=cc else diff --git a/tests/run-program.impure.lisp b/tests/run-program.impure.lisp index 0617b1c1d3..0eab8884ca 100644 --- a/tests/run-program.impure.lisp +++ b/tests/run-program.impure.lisp @@ -13,6 +13,21 @@ (cl:in-package :cl-user) +(defun bin-pwd-ignoring-result () + (let ((initially-open-fds (directory "/proc/self/fd/*" :resolve-symlinks nil))) + (sb-ext:run-program "/usr/bin/pwd" nil :input :stream :output :stream :wait nil) + (length initially-open-fds))) + +(with-test (:name (run-program :autoclose-streams) + :broken-on :sbcl ;; not reliable enough + :skipped-on (not :linux)) + (let ((n-initially-open-fds (bin-pwd-ignoring-result))) + (gc) + (sb-sys:scrub-control-stack) ; Make sure we're not referencing the #<process> + (gc) ; now nothing should reference the streams + (assert (= (length (directory "/proc/self/fd/*" :resolve-symlinks nil)) + n-initially-open-fds)))) + ;; In addition to definitions lower down the impurity we're avoiding ;; is the sigchld handler that RUN-PROGRAM sets up, which interfers ;; with the manual unix process control done by the test framework @@ -166,14 +181,13 @@ ;;; agressive about flushing them. So, here's another test using :PTY. #-win32 -(with-test (:name :is-/bin/ed-installed?) - (assert (probe-file "/bin/ed"))) +(unless (probe-file "/bin/ed") (push :no-bin-ed-installed *features*)) #-win32 (progn (defparameter *tmpfile* (scratch-file-name)) - (with-test (:name (run-program :/bin/ed)) + (with-test (:name (run-program :/bin/ed) :skipped-on :no-bin-ed-installed) (with-open-file (f *tmpfile* :direction :output :if-exists :supersede) @@ -221,7 +235,8 @@ ;;; This used to crash on Darwin and trigger recursive lock errors on ;;; every platform. -(with-test (:name (run-program :stress)) +;;; ...and now it triggers recursive lock errors on safepoint + linux. +(with-test (:name (run-program :stress) :skipped-on (:and :sb-safepoint :linux)) ;; Do it a hundred times in batches of 10 so that with a low limit ;; of the number of processes the test can have a chance to pass. ;; @@ -269,7 +284,8 @@ ;; We can't check for the signal itself since run-program.c resets the ;; forked process' signal mask to defaults. But the default is `stop' ;; of which we can be notified asynchronously by providing a status hook. -(with-test (:name (run-program :inherit-stdin) :fails-on :win32) +(with-test (:name (run-program :inherit-stdin) :fails-on :win32 + :skipped-on :no-bin-ed-installed) (let (stopped) (flet ((status-hook (proc) (case (process-status proc) @@ -333,6 +349,10 @@ #-win32 (with-test (:name (run-program :if-input-does-not-exist)) (let ((file (pathname (sb-posix:mktemp "rpXXXXXX")))) + (when (and (boundp 'run-tests::*allowed-inputs*) + ;; If the permitted inputs are :ANY then leave it be + (listp (symbol-value 'run-tests::*allowed-inputs*))) + (push (namestring file) (symbol-value 'run-tests::*allowed-inputs*))) (assert (null (run-program "/bin/cat" '() :input file))) (assert (null (run-program "/bin/cat" '() :output #.(or *compile-file-truename* *load-truename*) @@ -413,25 +433,45 @@ (with-test (:name (run-program :malloc-deadlock) :broken-on :sb-safepoint - :skipped-on (or (not :sb-thread) :win32)) + :skipped-on (or :ubsan (not :sb-thread) :win32)) (let* (stop + (delay-between-gc + (or #+freebsd + (let* ((p (run-program "sysctl" '("hw.model") :search t :output :stream)) + (output (process-output p)) + (result (read-line output))) + (close output) + ;; With the default delay of 0 using FreeBSD on QEMU this test never + ;; finished because the RUN-PROGRAM thread would never get scheduled + ;; after its first entry into the loop. + ;; It wasn't hung, it just wasn't getting CPU time. For me anyway. + (when (search "QEMU" result) + .00000001)) ; 10 nanoseconds + #+(and darwin arm64) + 0.01 + 0)) (threads (list* (sb-thread:make-thread (lambda () - (loop until stop + (loop until (progn (sb-thread:barrier (:read)) + stop) do - (sleep 0) + (sleep delay-between-gc) (gc :full t)))) (loop repeat 3 collect (sb-thread:make-thread (lambda () - (loop until stop + (loop until (progn (sb-thread:barrier (:read)) + stop) do (malloc)))))))) - (loop for time = (get-internal-real-time) - for end = (+ time (* internal-time-units-per-second 4)) then end + (loop with dot = (get-internal-real-time) + with end = (+ dot (* internal-time-units-per-second 4)) + for time = (get-internal-real-time) while (> end time) do - (when (zerop (mod (- time end) (truncate internal-time-units-per-second 10))) + (when (> (- time dot) + (/ internal-time-units-per-second 10)) + (setf dot time) (write-char #\.) (finish-output)) (with-output-to-string (str) @@ -440,4 +480,14 @@ :search t :wait t))) (setf stop t) + (sb-thread:barrier (:write)) (mapc #'sb-thread:join-thread threads))) + +(with-test (:name (run-program :child-fd-leak) + :skipped-on (or :openbsd :win32)) + (when (probe-file "/dev/fd") + (with-open-file (stream "/dev/null") + (let* ((fd (sb-sys:fd-stream-fd stream)) + (process (run-program "test" (list "-e" (format nil "/dev/fd/~a" fd)) + :search t))) + (assert (not (zerop (process-exit-code process)))))))) diff --git a/tests/run-program.test.sh b/tests/run-program.test.sh index 3a08741709..b05b6e2f73 100755 --- a/tests/run-program.test.sh +++ b/tests/run-program.test.sh @@ -22,21 +22,33 @@ export SOMETHING_IN_THE_ENVIRONMENT PATH=/some/path/that/does/not/exist:${PATH} export PATH +# Increase potential soft ulimit on file descriptors for file +# descriptor test case below. +test `ulimit -n` -ge 1050 || ulimit -S -n 1050 + # This should probably be broken up into separate pieces. run_sbcl --eval "(defvar *exit-ok* $EXIT_LISP_WIN)" <<'EOF' +(defmacro our-run-program (name &rest rest) + #+unix `(run-program ,name ,@rest) + #-unix `(run-program ,(subseq name (1+ (position #\/ name :from-end t))) + ,@rest :search t)) + ;; test that $PATH is searched (assert (zerop (sb-ext:process-exit-code (sb-ext:run-program "true" () :search t :wait t)))) (assert (not (zerop (sb-ext:process-exit-code (sb-ext:run-program "false" () :search t :wait t))))) (let ((string (with-output-to-string (stream) - (sb-ext:run-program "/bin/echo" + (our-run-program "/bin/echo" '("foo" "bar") :output stream)))) (assert (string= string "foo bar "))) + (format t ";;; Smoke tests: PASS~%") + ;; Unix environment strings are ordinarily passed with SBCL convention ;; (instead of CMU CL alist-of-keywords convention). + #+unix ; env works differently for msys2 apparently (let ((string (with-output-to-string (stream) (sb-ext:run-program "/usr/bin/env" () :output stream @@ -44,7 +56,14 @@ run_sbcl --eval "(defvar *exit-ok* $EXIT_LISP_WIN)" <<'EOF' (assert (equal string "FEEFIE=foefum "))) +(when (fboundp (find-symbol "UNIX-POLL" "SB-UNIX")) + (let ((f (open "/dev/null"))) + (with-alien ((dup (function int int) :extern)) + (dotimes (i 1025) (alien-funcall dup (sb-impl::fd-stream-fd f))) + (assert (> (alien-funcall dup (sb-impl::fd-stream-fd f)) 1024))))) + ;; Unicode strings + #+unix (flet ((try (sb-impl::*default-external-format* x y) (let* ((process (run-program "/bin/sh" (list "-c" (format nil "echo ~c, $SB_TEST_FOO." x)) @@ -64,6 +83,7 @@ run_sbcl --eval "(defvar *exit-ok* $EXIT_LISP_WIN)" <<'EOF' ;; The default Unix environment for the subprocess is the same as ;; for the parent process. (I.e., we behave like perl and lots of ;; other programs, but not like CMU CL.) + #+unix (let* ((sb-impl::*default-external-format* :latin-1) (sb-alien::*default-c-string-external-format* :latin-1) (string (with-output-to-string (stream) @@ -83,7 +103,7 @@ run_sbcl --eval "(defvar *exit-ok* $EXIT_LISP_WIN)" <<'EOF' ;; make sure that a stream input argument is basically reasonable. (let ((string (let ((i (make-string-input-stream "abcdef"))) (with-output-to-string (stream) - (sb-ext:run-program "/bin/cat" () + (our-run-program "/bin/cat" () :input i :output stream))))) (assert (= (length string) 6)) (assert (string= string "abcdef"))) @@ -94,12 +114,13 @@ run_sbcl --eval "(defvar *exit-ok* $EXIT_LISP_WIN)" <<'EOF' ;; note: this test will be inconclusive if the child's stderr is ;; fully buffered.) (let ((str (with-output-to-string (s) - (run-program "/bin/sh" + (our-run-program "/bin/sh" '("-c" "(echo Foo; sleep 2; echo Bar)>&2") :output s :search t :error :output :wait t)))) (assert (string= str (format nil "Foo~%Bar~%")))) ;; end of file in the middle of a UTF-8 character + ;; (FIXME: asserting failure without knowing why is almost as good as no test at all.) (typep (nth-value 1 (ignore-errors (let ((sb-impl::*default-external-format* :utf-8)) (with-output-to-string (s) diff --git a/tests/run-sbcl.test.sh b/tests/run-sbcl.test.sh new file mode 100644 index 0000000000..086c3efe65 --- /dev/null +++ b/tests/run-sbcl.test.sh @@ -0,0 +1,86 @@ +set -e + +. ./subr.sh + +# run-sbcl.sh's pathname munging turns out always to have been +# insufficient in one way or another. +test_run_sbcl() ( + set -e + args='--noinform --no-userinit --no-sysinit --disable-debugger --quit' + #set -x # uncomment for eyeball debugging + ## There are three ways run-sbcl.sh can fail or set things up badly. + # (1) run-sbcl.sh will refuse to run because there are no build + # artifacts relative to $run_sbcl_path. + "$1" $args + # (2) SBCL will start, but if SBCL_HOME is wrong, will be unable to + # load contribs. (This is what 9d5be5e953 partially addressed.) + "$1" $args --eval '(require :sb-posix)' + # (3) SBCL will start, but if SBCL_HOME is a relative pathname, + # then loading contribs will be sensitive to the dynamic value of + # *DEFAULT-PATHNAME-DEFAULTS*. (There appears not to be consensus + # whether SBCL ought to make SBCL-HOMEDIR-PATHNAME absolute during + # startup, so holding that aside, run-sbcl.sh has to.) + # + # In order to ensure that MODULE-PROVIDE-CONTRIB can't succeed + # when SBCL-HOMEDIR-PATHNAME is relative, we'll construct a + # default directory pathname known not to exist, so that any merge + # with it will also not exist. + "$1" $args --eval '(setq *default-pathname-defaults* + (loop for i upfrom 0 below 1000 + as directory + = (pathname + (format nil "/nosuchdir.~d/" i)) + unless (probe-file directory) + return directory + finally + (error "test setup failure")))' \ + --eval '(require :sb-posix)' +) + +# Sanity check: test the file in our build tree a couple of ways. +echo "testing run-sbcl.sh with an absolute path" +test_run_sbcl "$PWD"/../run-sbcl.sh + +echo "testing run-sbcl.sh with a relative path" +test_run_sbcl ../run-sbcl.sh + +# Next, test a couple ways that run-sbcl.sh could be invoked via a +# symlink. We'll need an absolute path to run-sbcl.sh in our build +# tree in order to construct symlinks that point to it. +if expr "$0" : "^[^/].*" > /dev/null; then + test_file_directory_path="$(cd ./$(dirname "$0") && pwd)" +fi +# Now we can derive an absolute path to run-sbcl.sh relative to this +# file. +run_sbcl_path="$test_file_directory_path/../run-sbcl.sh" + +# Now we're going to frob the file system, so let's do it properly. +use_test_subdirectory + +# 9d5be5e953 (lp#1242643) addressed the possibility that run-sbcl.sh +# was a symlink into the repo. Let's exercise it, 8 years later. +echo "testing run-sbcl.sh when it's a symlink to an absolute path" +ln -s "$run_sbcl_path" ./run-sbcl-absolute-symlink.sh +test_run_sbcl ./run-sbcl-absolute-symlink.sh +rm ./run-sbcl-absolute-symlink.sh + +# Test whether we can run-sbcl.sh through a symlink to a relative +# path. +echo "testing run-sbcl.sh when it's a symlink to a relative path" +ln -s $(pwd | sed 's|^/||; s|[^/][^/]*|..|g')/"$run_sbcl_path" ./run-sbcl-relative-symlink.sh +test_run_sbcl ./run-sbcl-relative-symlink.sh +rm ./run-sbcl-relative-symlink.sh + +# Test whether we can run-sbcl.sh named using a path to the build +# directory that contains a space. +echo "testing run-sbcl.sh named by a path containing spaces" +ln -s `dirname $run_sbcl_path` ./'a b' +# Prior to 4a30189fbc, run-sbcl.sh would start the runtime using the +# core file path ./a b/output/sbcl.core, but unquoted. +# After 4a30189fbc, the path to the core file will be +# ${PWD}/a b/output/sbcl.core, still unquoted. +# 546416b34d changed the core file path handling to ensure +# it's always quoted. +test_run_sbcl "./a b/run-sbcl.sh" + +exit $EXIT_TEST_WIN diff --git a/tests/run-tests.lisp b/tests/run-tests.lisp index 05dc7ed041..4755151051 100644 --- a/tests/run-tests.lisp +++ b/tests/run-tests.lisp @@ -1,4 +1,7 @@ -(setf (extern-alien "gc_allocate_dirty" char) 1) +#+(and linux sb-thread 64-bit) +(sb-alien:alien-funcall (sb-alien:extern-alien + "reset_gc_stats" + (function sb-alien:void))) (load "test-util.lisp") (load "assertoid.lisp") @@ -22,30 +25,32 @@ (defun run-all (&aux (start-time (get-internal-real-time))) (loop :with remainder = (rest *posix-argv*) - :while remainder - :for arg = (pop remainder) - :do (cond - ((string= arg "--evaluator-mode") - (let ((mode (pop remainder))) - (cond - ((string= mode "interpret") - (setf *test-evaluator-mode* :interpret)) - ((string= mode "compile") - (setf *test-evaluator-mode* :compile)) - (t - (error "~@<Invalid evaluator mode: ~A. Must be one ~ + :for arg = (car remainder) + :while remainder + :do + (pop remainder) + (cond + ((string= arg "--evaluator-mode") + (let ((mode (pop remainder))) + (cond + ((string= mode "interpret") + (setf *test-evaluator-mode* :interpret)) + ((string= mode "compile") + (setf *test-evaluator-mode* :compile)) + (t + (error "~@<Invalid evaluator mode: ~A. Must be one ~ of interpret, compile.~@:>" - mode))))) - ((string= arg "--break-on-failure") - (setf *break-on-error* t) - (setf test-util:*break-on-failure* t)) - ((string= arg "--break-on-expected-failure") - (setf test-util:*break-on-expected-failure* t)) - ((string= arg "--report-skipped-tests") - (setf *report-skipped-tests* t)) - ((string= arg "--no-color")) - (t - (push (truename (parse-namestring arg)) *explicit-test-files*)))) + mode))))) + ((string= arg "--break-on-failure") + (setf *break-on-error* t) + (setf test-util:*break-on-failure* t)) + ((string= arg "--break-on-expected-failure") + (setf test-util:*break-on-expected-failure* t)) + ((string= arg "--report-skipped-tests") + (setf *report-skipped-tests* t)) + ((string= arg "--no-color")) + (t + (push (merge-pathnames (parse-namestring arg)) *explicit-test-files*)))) (setf *explicit-test-files* (nreverse *explicit-test-files*)) (with-open-file (log "test.log" :direction :output :if-exists :supersede @@ -54,12 +59,10 @@ (pure-runner (pure-cload-files) 'cload-test log) (impure-runner (impure-load-files) 'load-test log) (impure-runner (impure-cload-files) 'cload-test log) - #-win32 (impure-runner (sh-files) 'sh-test log) + (impure-runner (sh-files) 'sh-test log) (log-file-elapsed-time "GRAND TOTAL" start-time log)) (report) - (sb-ext:exit :code (if (unexpected-failures) - 1 - 104))) + (sb-ext:exit :code (if (unexpected-failures) 1 104))) (defun report () (terpri) @@ -154,19 +157,30 @@ (namestring (make-pathname :name (pathname-name thing) :type (pathname-type thing)))) (stem= (a b) - (string= (stem-of a) (stem-of b)))) + (string= (stem-of a) (stem-of b))) + (starts-with-p (string prefix) + (= (mismatch string prefix) (length prefix))) + (within-directory-p (path directory) + (starts-with-p (namestring (merge-pathnames path)) + (namestring directory)))) (unless (eq (pathname-host filename) sb-impl::*physical-host*) (return-from check-manifest)) (let ((string (namestring filename))) (when (or (find #\* (stem-of filename)) ; wild - (= (mismatch string "/dev/") 5) ; dev/null and dev/random - (= (mismatch string "/tmp/") 5) - (= (mismatch string "/var/tmp/") 9) - (eql (search "/private/var/folders/" string) 0) - (string= string "/proc/self/maps") + (starts-with-p string "/dev/") ; dev/null and dev/random + (starts-with-p string "/proc/self") + ;; Temp files created by test-util's scratch file routine + (starts-with-p (stem-of string) *scratch-file-prefix*) + ;; These have been accepted as okay for a while. Test + ;; files should never explicitly create files in these + ;; directories, but should always use a scratch file. + (starts-with-p string "/tmp/") + (starts-with-p string "/var/tmp/") + (starts-with-p string "/private/var/folders/") + (and (boundp '*test-directory*) + (within-directory-p filename *test-directory*)) (string= string "exists") (member (stem-of filename) '("compiler-test-util.lisp" - "a.txt" "b.lisp" "no-such-file") :test #'string=) (string= (pathname-name filename) "i-am-not") ; any extension @@ -178,6 +192,176 @@ (format *error-output* "~&Assumed valid input file: ~S" filename) (error "Missing input file in manifest: ~S~%" filename)))) +(defparameter *ignore-symbol-value-change* + (flet ((maybe (p s) (and (find-package p) + (find-symbol s p)))) + `(sb-c::*code-serialno* + sb-c::*compile-elapsed-time* + sb-c::*compile-file-elapsed-time* + sb-impl::*package-names-cookie* + sb-impl::*available-buffers* + sb-impl::*token-buf-pool* + sb-impl::*user-hash-table-tests* + sb-impl::**finalizer-store** + sb-vm::*immobile-codeblob-tree* + sb-vm::*dynspace-codeblob-tree* + ,(maybe "SB-KERNEL" "*EVAL-CALLS*") + sb-kernel::*type-cache-nonce* + sb-ext:*gc-run-time* + sb-kernel::*gc-epoch* + sb-int:*n-bytes-freed-or-purified* + ,(maybe "SB-VM" "*BINDING-STACK-POINTER*") + ,(maybe "SB-VM" "*CONTROL-STACK-POINTER*") + ,(maybe "SB-THREAD" "*JOINABLE-THREADS*") + ,(maybe "SB-THREAD" "*STARTING-THREADS*") + ,(maybe "SB-THREAD" "*SPROF-DATA*") + sb-thread::*all-threads* + ,(maybe "SB-VM" "*FREE-TLS-INDEX*") + ,(maybe "SB-VM" "*STORE-BARRIERS-POTENTIALLY-EMITTED*") + ,(maybe "SB-VM" "*STORE-BARRIERS-EMITTED*") + ,(maybe "SB-INTERPRETER" "*LAST-TOPLEVEL-ENV*") + ,(maybe "SB-SYS" "*THRUPTION-PENDING*") + sb-pcl::*dfun-constructors* + #+win32 sb-impl::*waitable-timer-handle* + #+win32 sb-impl::*timer-thread*))) + +(defun collect-symbol-values () + (let (result) + (sb-int:drop-all-hash-caches) + (do-all-symbols (s) + (when (and (not (keywordp s)) + (boundp s) + (not (constantp s)) + (sb-int:system-package-p (symbol-package s)) + (not (member s *ignore-symbol-value-change*))) + (push (cons s (symbol-value s)) result))) + result)) + +(defun compare-symbol-values (expected) + (sb-int:drop-all-hash-caches) + (dolist (item expected) + (let ((val (symbol-value (car item)))) + (unless (eq val (cdr item)) + (error "Symbol value differs: ~S" (car item)))))) + +(defun safe-gf-p (x) + (declare (notinline sb-kernel:%fun-layout)) + (and (sb-kernel:funcallable-instance-p x) + (not (eq (opaque-identity (sb-kernel:%fun-layout x)) 0)) + (sb-pcl::generic-function-p x))) + +(defun summarize-generic-functions () + (loop for gf in (sb-vm:list-allocated-objects :all :test #'safe-gf-p) + collect (cons gf + (when (and (slot-exists-p gf 'sb-pcl::methods) + (slot-boundp gf 'sb-pcl::methods)) + (length (sb-mop:generic-function-methods gf)))))) + + +;;; Because sb-pcl::compile-or-load-defgeneric is disabled in pure tests, +;;; there should be no way to cause this to fail in pure tests except by direct +;;; use of ADD-METHOD or REMOVE-METHOD. +(defun compare-gf-summary (expected) + (dolist (item expected) + (let* ((gf (car item)) + (n-old (cdr item)) + (n-new (when (and (slot-exists-p gf 'sb-pcl::methods) + (slot-boundp gf 'sb-pcl::methods)) + (length (sb-mop:generic-function-methods gf))))) + (assert (eql n-old n-new))))) + +(defun tersely-summarize-globaldb () + (let* ((symbols-with-properties) + (types-ht (make-hash-table)) + (setfs-ht (make-hash-table)) + (structure-classoids + (sb-kernel:classoid-subclasses + (sb-kernel:find-classoid 'structure-object))) + (ignored-stream-classoids + '(sb-gray:fundamental-binary-output-stream + sb-gray:fundamental-binary-input-stream + sb-gray:fundamental-binary-stream + sb-gray:fundamental-character-stream + sb-gray:fundamental-output-stream + sb-gray:fundamental-input-stream)) + (standard-classoids + (sb-kernel:classoid-subclasses + (sb-kernel:find-classoid 'standard-object))) + (condition-classoids + (sb-kernel:classoid-subclasses + (sb-kernel:find-classoid 'condition)))) + (do-all-symbols (s) + (when (symbol-plist s) + (push s symbols-with-properties)) + (when (sb-int:info :type :kind s) + (setf (gethash s types-ht) t)) + (when (sb-int:info :setf :expander s) + (setf (gethash s setfs-ht) t))) + ;; The first two elements of this list are employed to delete new structure + ;; and condition definitions after the test file is executed. + ;; The other elements are used only as a comparison to see that nothing else + ;; was altered in the classoid or type namespace, etc. + (list (loop for key being each hash-key of structure-classoids + collect (sb-kernel:classoid-name key)) + (loop for key being each hash-key of condition-classoids + collect (sb-kernel:classoid-name key)) + (loop for key being each hash-key of standard-classoids + unless (member (sb-kernel:classoid-name key) + ignored-stream-classoids) + collect (sb-kernel:classoid-name key)) + (sort symbols-with-properties #'string<) + (sb-impl::info-env-count sb-int:*info-environment*) + (hash-table-count types-ht) + (hash-table-count setfs-ht)))) + +(defun structureish-classoid-ancestors (classoid) + (map 'list 'sb-kernel:wrapper-classoid + (sb-kernel:wrapper-inherits (sb-kernel:classoid-wrapper classoid)))) + +(defun globaldb-cleanup (initial-packages globaldb-summary) + ;; Package deletion suffices to undo DEFVAR,DEFTYPE,DEFSETF,DEFUN,DEFMACRO + ;; but not DEFSTRUCT or DEFCLASS. + ;; UNDECLARE-STRUCTURE isn't destructive enough for our needs here. + (flet ((delete-classoids (root saved-names) + (let ((worklist + (loop for key being each hash-key + of (sb-kernel:classoid-subclasses (sb-kernel:find-classoid root)) + unless (member (the (and symbol (not null)) + (sb-kernel:classoid-name key)) + saved-names) + collect key))) + (dolist (classoid worklist) + (dolist (ancestor (structureish-classoid-ancestors classoid)) + (sb-kernel::remove-subclassoid classoid ancestor)) + (let ((direct-supers + (mapcar 'sb-kernel:classoid-pcl-class + (sb-kernel:classoid-direct-superclasses classoid))) + (this-class (sb-kernel:classoid-pcl-class classoid))) + (dolist (super direct-supers) + (sb-mop:remove-direct-subclass super this-class))))))) + (delete-classoids 'structure-object (first globaldb-summary)) + (delete-classoids 'condition (second globaldb-summary))) + (let (delete) + (dolist (package (list-all-packages)) + (unless (member package initial-packages) + (push package delete))) + ;; Do all UNUSE-PACKAGE operations first + (dolist (package delete ) + (unuse-package (package-use-list package) package)) + ;; Then all deletions + (mapc 'delete-package delete)) + (loop for x in (cdr globaldb-summary) for y in (cdr (tersely-summarize-globaldb)) + for index from 0 + unless (equal x y) + do (let ((diff (list (set-difference x y) + (set-difference y x)))) + (if (equal diff '((sb-gray:fundamental-character-output-stream + sb-gray:fundamental-character-input-stream) nil)) + (warn "Ignoring mystery change to gray stream classoids") + (let ((*print-pretty* nil)) + (error "Mismatch on element index ~D of globaldb snapshot: diffs=~S" + index diff)))))) + (defun pure-runner (files test-fun log) (unless files (return-from pure-runner)) @@ -196,19 +380,25 @@ (not (or (search ".impure" (namestring file)) (search ".impure-cload" (namestring file))))) (packages-to-use '("ASSERTOID" "TEST-UTIL")) + (initial-packages (list-all-packages)) + (global-symbol-values (when actually-pure + (collect-symbol-values))) + (gf-summary (summarize-generic-functions)) + (globaldb-summary (when actually-pure + (tersely-summarize-globaldb))) (test-package (if actually-pure (make-package (format nil "TEST~36,5,'_R" (random (expt 36 5))) :use (append packages-to-use standard-use-list)) - (find-package "CL-USER"))) - (*allowed-inputs* + (find-package "CL-USER")))) + (setq *allowed-inputs* (if (eq *input-manifest* :ignore) :any (append (cdr (assoc (namestring (make-pathname :name (pathname-name file) :type (pathname-type file))) *input-manifest* :test #'string=)) - (list file))))) + (list file)))) (sb-int:encapsulate 'open 'open-guard (lambda (f filename &rest args &key direction &allow-other-keys) @@ -227,11 +417,20 @@ ;; DEF{constant,fun,macro,parameter,setf,type,var} are generally ok ;; except when DEFfoo defines something too hairy to hang off a symbol. (cond (actually-pure - (shadow '("DEFSTRUCT" "DEFMETHOD" + ;; DEFMACRO and DEFUN are allowed in pure tests because their effect + ;; is undone by deleting the package. We're pretty good now about not + ;; polluting any sort of gobal namespace with compiler metadata + ;; as long as the function is named by just a symbol or (SETF x). + ;; FIXME: probably should shadow DECLAIM, and reject some if not all + ;; possible things that could be declaimed. + ;; Even the impure tests suffer from a DECLAIM leaking into subsequent + ;; tests within the same file, so it's a more general problem. + (shadow '("DEFMETHOD" + "EXIT" ;; Hiding IN-PACKAGE is a good preventative measure. ;; There are other ways to do nasty things of course. ;; Deliberately violating a package lock has got to be impure. - "IN-PACKAGE" "WITHOUT-PACKAGE-LOCKS") + "IN-PACKAGE" "*PACKAGE*" "WITHOUT-PACKAGE-LOCKS") test-package) ;; We have pure tests that exercise the DEFCLASS and DEFGENERIC ;; macros to generate macroexpansion-time errors. That's mostly ok. @@ -246,7 +445,12 @@ (apply f args)))))) (t (use-package packages-to-use test-package))) - (let ((*package* test-package)) + (let ((*package* test-package) + (sb-impl::*gentemp-counter* sb-impl::*gentemp-counter*) + (sb-c::*check-consistency* sb-c::*check-consistency*) + (sb-c:*compile-to-memory-space* sb-c:*compile-to-memory-space*) + (sb-c::*policy-min* sb-c::*policy-min*) + (sb-c::*policy-max* sb-c::*policy-max*)) (restart-case (handler-bind ((error (make-error-handler file))) (let* ((sb-ext:*evaluator-mode* *test-evaluator-mode*) @@ -258,12 +462,18 @@ (funcall test-fun file) (log-file-elapsed-time file start log)))) (skip-file ()))) + (sb-impl::disable-stepping) (sb-int:unencapsulate 'open 'open-guard) (when actually-pure + (setq sb-disassem::*disassem-inst-space* nil + sb-disassem::*assembler-routines-by-addr* nil) + (compare-symbol-values global-symbol-values) + (compare-gf-summary gf-summary) + (globaldb-cleanup initial-packages globaldb-summary) (dolist (symbol '(sb-pcl::compile-or-load-defgeneric sb-kernel::%compiler-defclass)) - (sb-int:unencapsulate symbol 'defblah-guard)) - (delete-package test-package)))) + (sb-int:unencapsulate symbol 'defblah-guard))))) + (makunbound '*allowed-inputs*) ;; after all the files are done (append-failures))) @@ -339,7 +549,12 @@ (loop for file in *explicit-test-files* when (pathname-match-p file wild-mask) collect file) - (directory wild-mask))) + (directory wild-mask + ;; If we're in a tree whose non-directories are + ;; symlinks, the truenames of those symlinks might + ;; not have the same relationships to each other as + ;; we need. + :resolve-symlinks nil))) (defun pure-load-files () (filter-test-files "*.pure.lisp")) @@ -354,4 +569,23 @@ (filter-test-files "*.impure-cload.lisp")) (defun sh-files () - (filter-test-files "*.test.sh")) + (let ((result (filter-test-files "*.test.sh"))) + #+unix result + ;; Rather than hack up the shell scripts which don't pass on #-unix + ;; (which would require at least a few lines of shell script and lisp + ;; to invoke SBCL and exit with some other code), just confine the kludge + ;; to this file. + #-unix + (if *explicit-test-files* + result + (remove-if + (lambda (x) + (member (pathname-name x) + '("filesys.test" ; too many assertions about symlinks to care about just yet + ;; foreign-test-noop-dlclose-test.c:1:10: fatal error: dlfcn.h: No such file or directory + "foreign.test" + ;; No built SBCL here (.../tests/run-sbcl-test-5863): run 'sh make.sh' first! + "run-sbcl.test" + "side-effectful-pathnames.test") ; no idea + :test 'string=)) + result)))) diff --git a/tests/save-deinit.impure.lisp b/tests/save-deinit.impure.lisp deleted file mode 100644 index 16b007372f..0000000000 --- a/tests/save-deinit.impure.lisp +++ /dev/null @@ -1,49 +0,0 @@ - -;;; Bug discovered by users of FriCAS on a single-core virtual machine. -;;; I was able to replicate it exactly as described. -;;; Prior to the fix: -;;; ./sbcl --load save-deinit.impure.lisp -;;; While evaluating the form starting at line 30, column 0 -;;; of #P"/tmp/sbcl-sbcl/tests/save-deinit.impure.lisp": -;;; -;;; debugger invoked on a SB-IMPL::SAVE-WITH-MULTIPLE-THREADS-ERROR in thread -;;; #<THREAD "main thread" RUNNING {1001038523}>: -;;; Cannot save core with multiple threads running. -;;; -;;; Interactive thread (of current session): -;;; #<THREAD "main thread" RUNNING {1001038523}> -;;; -;;; Other thread: -;;; #<THREAD "finalizer" RUNNING {10022A0073}> - -;;; The test below is sufficient to show that it has been fixed. - -#-sb-thread (exit :code 104) - -(sb-int:encapsulate - 'sb-thread::new-lisp-thread-trampoline - 'finalizer-bug - (lambda (f thread semaphore userfun args) - (funcall f thread semaphore - (lambda (&rest args) - (sleep .1) - (apply userfun args)) - args))) - -(finalize (cons 1 'foo) - (lambda () (format t "~&finalizer1~%"))) -(finalize (cons 2 'foo) - (lambda () (format t "~&finalizer2~%"))) - -(setq sb-ext:*save-hooks* (list #'gc)) - -;;; DEINIT will invoke the save hooks which should cause post-GC -;;; to start the finalizer thread. The finalizer thread has a brief -;;; delay purposely induced before its main body. Therefore it won't -;;; have assigned *CURRENT-THREAD* into *FINALIZER-THREAD* until after -;;; FINALIZER-THREAD-STOP has returned. Therefore the test in DEINIT -;;; will see that thread in all threads, and will have to deal with it. -(let (sb-impl::*streams-closed-by-slad*) - (sb-impl::deinit) - (sb-impl::restore-fd-streams) - (sb-impl::reinit)) diff --git a/tests/save.impure.lisp b/tests/save.impure.lisp new file mode 100644 index 0000000000..364451ce63 --- /dev/null +++ b/tests/save.impure.lisp @@ -0,0 +1,29 @@ +;;;; Test errors signaled when saving a core fails early. + +;;;; This software is part of the SBCL system. See the README file for +;;;; more information. +;;;; +;;;; While most of SBCL is derived from the CMU CL system, the test +;;;; files (like this one) were written from scratch after the fork +;;;; from CMU CL. +;;;; +;;;; This software is in the public domain and is provided with +;;;; absolutely no warranty. See the COPYING and CREDITS files for +;;;; more information. + +(with-test (:name (sb-ext:save-lisp-and-die error :multiple-threads) + :skipped-on (:not :sb-thread)) + (let* ((mutex (sb-thread:make-mutex)) + (cvar (sb-thread:make-waitqueue)) + (donep nil) + (thread (sb-thread:make-thread + (lambda () + (sb-thread:with-mutex (mutex) + (loop until donep + do (sb-thread:condition-wait cvar mutex))))))) + (assert-error (save-lisp-and-die "./test") + sb-impl::save-with-multiple-threads-error) + (sb-thread:with-mutex (mutex) + (setf donep t) + (sb-thread:condition-notify cvar)) + (sb-thread:join-thread thread))) diff --git a/tests/save1.test.sh b/tests/save1.test.sh index 917b5cc9c2..bcf632a02f 100644 --- a/tests/save1.test.sh +++ b/tests/save1.test.sh @@ -15,6 +15,7 @@ tmpcore=$TEST_FILESTEM.core # diagnosed and fixed by Dan Barlow in sbcl-0.7.7.29 run_sbcl <<EOF (defun foo (x) (+ x 11)) + (setq *features* (union *features* sb-impl:+internal-features+)) ;; The basic smoke test includes a test that immobile-space defragmentation ;; supports calls to "static" functions - those called without reference ;; to an fdefn, from a caller in dynamic space. @@ -22,6 +23,11 @@ run_sbcl <<EOF ;; but maybe someone changed it :immobile, so bind it to be certain. (let (#+immobile-code (sb-c::*compile-to-memory-space* :dynamic)) (defvar *afun* (compile nil '(lambda (x) (- (length x)))))) + ;; test for lp#1983218 - a VALUE-CELL holding a readonly string could crash + (defun mkcell (x) (sb-sys:%primitive sb-vm::make-value-cell x nil)) + (compile 'mkcell) + (defvar *cell* (mkcell (symbol-name '*print-base*))) + ;; (save-lisp-and-die "$tmpcore") EOF run_sbcl_with_core "$tmpcore" --noinform --no-userinit --no-sysinit --noprint \ @@ -31,4 +37,14 @@ run_sbcl_with_core "$tmpcore" --noinform --no-userinit --no-sysinit --noprint \ EOF check_status_maybe_lose "Basic SAVE-LISP-AND-DIE" $? 21 "(saved core ran)" +run_sbcl <<EOF + (save-lisp-and-die "$tmpcore" :purify nil) +EOF +run_sbcl_with_core "$tmpcore" --noinform --no-userinit --no-sysinit --noprint <<EOF + #-(and darwin arm64) ;; darwin-jit + (unless (zerop (- (sb-sys:sap-int sb-vm:*read-only-space-free-pointer*) sb-vm:read-only-space-start)) + (exit :code 1)) +EOF +check_status_maybe_lose "SAVE-LISP-AND-DIE NOPURIFY" $? 0 "(unpurified core ran)" + exit $EXIT_TEST_WIN diff --git a/tests/save2.test.sh b/tests/save2.test.sh index dfc663eba3..1233d49386 100644 --- a/tests/save2.test.sh +++ b/tests/save2.test.sh @@ -14,4 +14,20 @@ run_sbcl_with_core "$tmpcore" --noinform --no-userinit --no-sysinit \ --eval "(setf sb-ext:*evaluator-mode* :${TEST_SBCL_EVALUATOR_MODE:-compile})" check_status_maybe_lose "SAVE-LISP-AND-DIE :TOPLEVEL" $? 0 "(saved core ran)" +run_sbcl --eval '(save-lisp-and-die "'$tmpcore'" :toplevel (lambda () (format t "Ahoy-hoy.~%")))' +result1=`run_sbcl_with_core "$tmpcore" --noinform --no-userinit --no-sysinit` +result2=`run_sbcl_with_core "$tmpcore" --merge-core-pages --noinform --no-userinit --no-sysinit` +# Both invocations should produce the "Ahoy-hoy." but result2 didn't +# because of busted arg parsing in git rev f0a7f17516 +# result2 has to be string-quoted in case it contains junk (due to not parsing +# --noinform after incorrectly parsing --merge-core-pages) +if [ ${result1} != "Ahoy-hoy." -o "${result2}" != ${result1} ] +then + echo FAIL: merge-core-pages + exit 0 +fi +# Passing doesn't actually mean we utilized madvise, +# just that we didn't choke on the argument. +echo PASS: merge-core-pages + exit $EXIT_TEST_WIN diff --git a/tests/save3.test.sh b/tests/save3.test.sh index 1a0a3a4ef0..95d05b9b25 100644 --- a/tests/save3.test.sh +++ b/tests/save3.test.sh @@ -15,7 +15,7 @@ run_sbcl_with_core "$tmpcore" --noinform --no-userinit --no-sysinit \ check_status_maybe_lose "SAVE-LISP-AND-DIE" $? 0 "(saved core ran)" # Verify that for funcallable instances which were moved into the -# immobile varyobj space by SAVE-LISP-AND-DIE, setting the layout +# immobile text space by SAVE-LISP-AND-DIE, setting the layout # updates the GC card touched bit. # Going through instance-obsolescence stuff makes things mostly work # by accident, because (SETF %FUNCALLABLE-INSTANCE-INFO) touches @@ -34,9 +34,9 @@ run_sbcl <<EOF (:metaclass sb-mop:funcallable-standard-class)) (defclass subgf (standard-generic-function) (a) ; remove a slot (:metaclass sb-mop:funcallable-standard-class)) - (let ((nl (sb-kernel:find-layout 'subgf))) ; new layout + (let ((nl (sb-kernel:wrapper-friend (sb-kernel:find-layout 'subgf)))) ; new layout (assert (not (eq (sb-kernel:%fun-layout #'myfun) nl))) - (setf (sb-kernel:%fun-layout #'myfun) nl) + (sb-kernel:%set-fun-layout #'myfun nl) (gc))) (save-lisp-and-die "$tmpcore" :toplevel #'assign-layout) EOF diff --git a/tests/save4.test.sh b/tests/save4.test.sh index e1890020d1..fa885bd255 100644 --- a/tests/save4.test.sh +++ b/tests/save4.test.sh @@ -1,25 +1,21 @@ export TEST_BASEDIR=${TMPDIR:-/tmp} . ./subr.sh -sourcefile=`pwd -P`/heap-reloc/embiggen.lisp use_test_subdirectory tmpcore=$TEST_FILESTEM.core -# Expose potential failure that could happen in save-lisp-and-die in an image -# that was restarted from one that underwent number coalescing during a -# previous save-lisp-and-die: A bignum as a layout bitmap can be forwarded -# while using that bignum as the bitmap to decide what to scan in that selfsame -# instance. Aside from random failure, this could be detected by enabling -# 'verify_gens' which printed "Ptr sees free page" after GC failed to scavenge -# all pointer slots. I believe that it was a coincidence that my test croaked -# specifically while scanning layout-of-layout. It could have been any -# structure having a slot holding a bignum EQ to its own layout-bitmap. -run_sbcl --load ${sourcefile} <<EOF - #+gencgc (setf (extern-alien "verify_gens" char) 0) - (save-lisp-and-die "$tmpcore") +# test for lp#1983248 - gc_close_region on an unopen region +run_sbcl <<EOF +(defparameter *keepme* (make-array 15500 :fill-pointer 0)) +(let ((s (find-symbol "*COMPILE-TO-MEMORY-SPACE*" "SB-C"))) + (when s + (set s :immobile) + (dotimes (i (array-dimension *keepme* 0)) + (vector-push-extend (compile nil \`(lambda () ,i)) *keepme*)))) +(save-lisp-and-die "$tmpcore") EOF -run_sbcl_with_core "$tmpcore" --noinform --no-userinit --no-sysinit --eval "(exit)" -check_status_maybe_lose "Crash GC" $? 0 "(saved core ran)" + +check_status_maybe_lose "LOTS-OF-CODE" $? 0 "(saved OK)" exit $EXIT_TEST_WIN diff --git a/tests/save5.test.sh b/tests/save5.test.sh index b643a89e9a..67441bf430 100644 --- a/tests/save5.test.sh +++ b/tests/save5.test.sh @@ -10,11 +10,10 @@ run_sbcl <<EOF (defun bar () (format t "~&Callbacks not supported, skipping~%") (exit :code 42)) - #+alien-callbacks - (progn + (when (member :alien-callbacks sb-impl:+internal-features+) (fmakunbound 'bar) - (sb-alien::define-alien-callback foo int () 42) - (defun bar () (exit :code (alien-funcall foo)))) + (sb-alien:define-alien-callable foo int () 42) + (defun bar () (exit :code (alien-funcall (sb-alien:alien-callable-function 'foo))))) (save-lisp-and-die "$tmpcore") EOF run_sbcl_with_core "$tmpcore" --noinform --no-userinit --no-sysinit --noprint \ diff --git a/tests/save6.test.sh b/tests/save6.test.sh index cc497a9766..7182ef4857 100644 --- a/tests/save6.test.sh +++ b/tests/save6.test.sh @@ -7,7 +7,10 @@ fi use_test_subdirectory -tmpcore=$TEST_FILESTEM.core +tmpcore=${TEST_FILESTEM}_a.core +# unix can write a new file to same name as the one we're executing +# but not all OSes can +tmpcore2=${TEST_FILESTEM}_b.core # Regression test for https://bugs.launchpad.net/sbcl/+bug/411925 # saving runtime options _from_ executable cores @@ -16,15 +19,18 @@ run_sbcl <<EOF EOF chmod u+x "$tmpcore" ./"$tmpcore" --no-userinit --no-sysinit --noprint <<EOF - (save-lisp-and-die "$tmpcore" :executable t :save-runtime-options t) + (save-lisp-and-die "$tmpcore2" :executable t :save-runtime-options t) EOF -chmod u+x "$tmpcore" -./"$tmpcore" --no-userinit --no-sysinit --noprint --version --eval '(exit)' <<EOF - (when (equal *posix-argv* '("./$tmpcore" "--version" "--eval" "(exit)")) +chmod u+x "$tmpcore2" +./"$tmpcore2" --no-userinit --no-sysinit --noprint --versions --eval '(exit)' <<EOF + ;; tbh I have no idea how this asserts anything about saving options from executable + ;; cores with saved options + (when #+unix (equal *posix-argv* '("./$tmpcore2" "--versions" "--eval" "(exit)")) + #-unix (equal (cdr *posix-argv*) '("--versions" "--eval" "(exit)")) (exit :code 42)) EOF status=$? -rm "$tmpcore" +rm "$tmpcore" "$tmpcore2" if [ $status -ne 42 ]; then echo "saving runtime options from executable failed" exit 1 diff --git a/tests/save7.test.sh b/tests/save7.test.sh index 1e2afe5862..b01cecc2ba 100644 --- a/tests/save7.test.sh +++ b/tests/save7.test.sh @@ -9,22 +9,52 @@ use_test_subdirectory tmpcore=$TEST_FILESTEM.core +echo "::: Running :SAVE-CORE-MEM-SIZES" # executable core used as "--core" option should not save the memory sizes # that were originally saved, but the sizes in the process doing the save. -run_sbcl_with_args --noinform --control-stack-size 160KB --dynamic-space-size 200MB \ +run_sbcl_with_args --noinform --control-stack-size 320KB --dynamic-space-size 200MB \ --disable-debugger --no-userinit --no-sysinit --noprint <<EOF (save-lisp-and-die "$tmpcore" :executable t :save-runtime-options t) EOF chmod u+x "$tmpcore" +echo "::: INFO: prepared test core" ./"$tmpcore" --no-userinit --no-sysinit --noprint <<EOF - (assert (eql (extern-alien "thread_control_stack_size" unsigned) (* 160 1024))) + (assert (eql (extern-alien "thread_control_stack_size" unsigned) (* 320 1024))) ; allow slight shrinkage if heap relocation has to adjust for alignment (assert (<= 0 (- (* 200 1048576) (dynamic-space-size)) 65536)) EOF -run_sbcl_with_core "$tmpcore" --noinform --control-stack-size 200KB \ +echo "::: Success" + +echo "::: Running :ALWAYS-ACCEPT-MEMORY-SIZES" +# next, check that tmpcore will accept memory size options. +# Use --control-stack-size for the test, since we don't know the valid range +# of dynamic space size for the OS/arch. +# Test that we find the arg in the midst of the command-line args as well. +./"$tmpcore" --no-userinit --control-stack-size 3MB --no-sysinit --noprint <<EOF +(let* ((end (sb-vm::current-thread-offset-sap sb-vm::thread-control-stack-end-slot)) + (start (sb-vm::current-thread-offset-sap sb-vm::thread-control-stack-start-slot)) + (diff (sb-sys:sap- end start))) + (assert (= diff (* 3 1048576)))) +EOF +echo "::: Success" + +echo "::: Running :DASH-DASH-STOP-PARSING" +# Test that we don't parse after a "--" +./"$tmpcore" --no-userinit --no-sysinit --noprint -- --dynamic-space-size 1000GB foo <<EOF +(let* ((end (sb-vm::current-thread-offset-sap sb-vm::thread-control-stack-end-slot)) + (start (sb-vm::current-thread-offset-sap sb-vm::thread-control-stack-start-slot)) + (diff (sb-sys:sap- end start))) + ;; We better not have gotten a terabyte of dynamic space! + (assert (< diff (* 8 1024 1024 1024))) ; assert less than 8GB + (assert (find "--" sb-ext:*posix-argv* :test 'string=))) +EOF +echo "::: Success" + +echo "::: Running :DYNAMIC-SPACE-SIZE-ARG" +run_sbcl_with_core "$tmpcore" --noinform --control-stack-size 640KB \ --tls-limit 5000 \ --dynamic-space-size 250MB --no-userinit --no-sysinit --noprint <<EOF - (assert (eql (extern-alien "thread_control_stack_size" unsigned) (* 200 1024))) + (assert (eql (extern-alien "thread_control_stack_size" unsigned) (* 640 1024))) (assert (eql (extern-alien "dynamic_values_bytes" (unsigned 32)) (* 5000 sb-vm:n-word-bytes))) ; allow slight shrinkage if heap relocation has to adjust for alignment @@ -34,8 +64,9 @@ run_sbcl_with_core "$tmpcore" --noinform --control-stack-size 200KB \ (save-lisp-and-die "${tmpcore}2" :executable t :save-runtime-options t) EOF chmod u+x "${tmpcore}2" +echo "::: INFO: prepared test core" ./"${tmpcore}2" --no-userinit --no-sysinit --noprint <<EOF - (when (and (eql (extern-alien "thread_control_stack_size" unsigned) (* 200 1024)) + (when (and (eql (extern-alien "thread_control_stack_size" unsigned) (* 640 1024)) (eql (extern-alien "dynamic_values_bytes" (unsigned 32)) (* 5000 sb-vm:n-word-bytes)) (dynamic-space-size-good-p)) @@ -47,5 +78,6 @@ if [ $status -ne 42 ]; then echo "re-saved executable used wrong memory size options" exit 1 fi +echo "::: Success" exit $EXIT_TEST_WIN diff --git a/tests/save9.test.sh b/tests/save9.test.sh new file mode 100755 index 0000000000..b194e65487 --- /dev/null +++ b/tests/save9.test.sh @@ -0,0 +1,26 @@ +# Don't try to run sbcl from /tmp on openbsd as it's unlikely to be +# mounted with wxallowed +if [ "$SBCL_SOFTWARE_TYPE" != OpenBSD ]; then + export TEST_BASEDIR=${TMPDIR:-/tmp} +fi +. ./subr.sh + +this_file=`pwd`/save9.test.sh +use_test_subdirectory + +tmpcore=$TEST_FILESTEM.core + +run_sbcl <<EOF + (defvar *s* (open #+unix "$this_file" + #-unix (format nil "~A/run-tests.lisp" + (posix-getenv "SBCL_PWD")))) + (save-lisp-and-die "$tmpcore") +EOF +set -e +answer=`run_sbcl_with_core "$tmpcore" --noinform --disable-ldb --no-userinit --no-sysinit \ +--eval '(print (open-stream-p *s*))' --quit` +rm "$tmpcore" +if [ $answer = NIL ] +then + exit $EXIT_TEST_WIN +fi diff --git a/tests/sb-aclrepl.impure.lisp b/tests/sb-aclrepl.impure.lisp new file mode 100644 index 0000000000..4a890e6592 --- /dev/null +++ b/tests/sb-aclrepl.impure.lisp @@ -0,0 +1,2 @@ +(require :sb-aclrepl) +(load "../contrib/sb-aclrepl/tests.lisp") diff --git a/tests/sb-bsd-sockets.impure.lisp b/tests/sb-bsd-sockets.impure.lisp new file mode 100644 index 0000000000..b653060749 --- /dev/null +++ b/tests/sb-bsd-sockets.impure.lisp @@ -0,0 +1,3 @@ +(require :sb-bsd-sockets) +#-win32 (require :sb-posix) +(load "../contrib/sb-bsd-sockets/tests.lisp") diff --git a/tests/sb-cltl2.impure.lisp b/tests/sb-cltl2.impure.lisp new file mode 100644 index 0000000000..4ef1b9eb03 --- /dev/null +++ b/tests/sb-cltl2.impure.lisp @@ -0,0 +1,2 @@ +(require :sb-cltl2) +(load "../contrib/sb-cltl2/tests.lisp") diff --git a/tests/sb-concurrency.impure.lisp b/tests/sb-concurrency.impure.lisp new file mode 100644 index 0000000000..f92abceae7 --- /dev/null +++ b/tests/sb-concurrency.impure.lisp @@ -0,0 +1,8 @@ +(require :sb-concurrency) +(load "../contrib/sb-concurrency/tests/package.lisp") +(load "../contrib/sb-concurrency/tests/test-utils.lisp") +#-interpreter (load "../contrib/sb-concurrency/tests/test-frlock.lisp") +;; This passes with sb-fasteval but not sb-eval +#-interpreter (load "../contrib/sb-concurrency/tests/test-queue.lisp") +(load "../contrib/sb-concurrency/tests/test-mailbox.lisp") +#-interpreter (load "../contrib/sb-concurrency/tests/test-gate.lisp") diff --git a/tests/sb-cover.impure.lisp b/tests/sb-cover.impure.lisp new file mode 100644 index 0000000000..66187e4f2c --- /dev/null +++ b/tests/sb-cover.impure.lisp @@ -0,0 +1,6 @@ +(setq run-tests::*allowed-inputs* :any) +(require :sb-cover) +(defparameter *source-directory* (truename #P"../contrib/sb-cover/")) +(test-util:with-test-directory (coveragedir) + (defvar cl-user::*coverage-report-directory* coveragedir) + (load (merge-pathnames "tests.lisp" *source-directory*))) diff --git a/tests/sb-gmp.impure.lisp b/tests/sb-gmp.impure.lisp new file mode 100644 index 0000000000..884c69d52e --- /dev/null +++ b/tests/sb-gmp.impure.lisp @@ -0,0 +1,7 @@ +(handler-case (require :sb-gmp) + (warning (c) + (when (search "GMP not loaded" (princ-to-string c)) + (invoke-restart 'run-tests::skip-file)))) +;; FIXME: do we also want to load sb-gmp/tests-stress.lisp? +;; Those tests are wicked slow, taking about 47 seconds on my computer +(load "../contrib/sb-gmp/tests.lisp") diff --git a/tests/sb-graph.impure.lisp b/tests/sb-graph.impure.lisp new file mode 100644 index 0000000000..81648132ba --- /dev/null +++ b/tests/sb-graph.impure.lisp @@ -0,0 +1,148 @@ +(require 'sb-graph) +(require 'sb-posix) +(require 'uiop) + +;;; These are tests for the sb-graph contrib module. Due to the nature +;;; of the features creating a bunch of files, I relocated the tests +;;; to here. + +(defmacro with-graph (&body forms) + `(compile-forms-as-file-with-tracing ',forms)) +(defun compile-forms-as-file-with-tracing (forms) + (declare (type list forms)) + (let* ((sb-c::*compile-trace-targets* (cons :sb-graph sb-c::*compile-trace-targets*)) + (dir (pathname (concatenate 'string (scratch-file-name) "/")))) + (sb-posix:mkdir dir #b111111111) + (let ((lisp (merge-pathnames (pathname-name (pathname (scratch-file-name "lisp"))) + dir)) + (trace (merge-pathnames (pathname-name (pathname (scratch-file-name "trace"))) + dir)) + (fasl (merge-pathnames (pathname-name (pathname (scratch-file-name "fasl"))) + dir))) + (with-open-file (f lisp :direction :output) + (dolist (form forms) + (prin1 form f))) + (let ((res (progn (compile-file lisp :output-file fasl :trace-file trace) t))) + (uiop:delete-directory-tree (pathname dir) :validate t) + res)))) + +(with-test (:name :compile-some-forms-with-graphing + :skipped-on (:not :sb-devel)) + (with-graph + (defpackage :sb-graph-test + (:shadow :stream) + (:use :cl :cl-user) + (:export :hook :disable-hook :enable-hook :unhook :hook-enabled + :make-graph :make-and-dfs :save-graph :graph :render-graph :expand-codename + :interactively-graph :output :expand :dfs-add)) + + (in-package :sb-graph-test) + + (defmacro hook (fun lambda-list &body body) + (let ((ll (gensym)) + (f (gensym)) + (orig (gensym))) + `(let ((,f ',fun)) + (when (nth-value 1 (gethash ',f *hook-enabled*)) + (unhook ,fun)) + (setf (gethash ,f *hook-enabled*) t) + (sb-int::encapsulate ,f 'hook + (lambda (,orig &rest ,ll) + (when (hook-enabled ,fun) + (destructuring-bind ,lambda-list ,ll + (block hook + ,@body))) + (apply ,orig ,ll)))))) + (defmacro disable-hook (fun) + (let ((f (gensym))) + `(let ((,f ',fun)) + (when (nth-value 1 (gethash ,f *hook-enabled*)) + (setf (gethash ',fun *hook-enabled*) nil))))) + (defmacro enable-hook (fun) + (let ((f (gensym))) + `(let ((,f ',fun)) + (when (nth-value 1 (gethash ,f *hook-enabled*)) + (setf (gethash ',fun *hook-enabled*) t))))) + (defmacro unhook (fun) + (let ((f (gensym))) + `(let ((,f ',fun)) + (when (nth-value 1 (gethash ,f *hook-enabled*)) + (sb-int::unencapsulate ,f 'hook) + (remhash ,f *hook-enabled*))))) + (defmacro hook-enabled (fun) + `(gethash ',fun *hook-enabled*)) + (defun make-graph () + (make-instance 'graph + :stream (make-string-output-stream) + :dfs-table (make-hash-table :test 'eq :size 63) + :obj-table (make-hash-table :test 'eq :size 63) + :codename-table (make-hash-table :test 'equal :size 63) + :codename-number 0)) + + (defun make-and-dfs (object distance) + (let ((graph (make-graph))) + (dfs-add graph distance object) + graph)) + + (defun save-graph (str filename) + (with-open-file (s filename :direction :output :if-does-not-exist :create :if-exists :supersede) + (write-string str s))) + + ;; dfs-table: obj -> T + ;; obj-table: obj -> codename + ;; codename-table: codename -> obj + (defclass graph () + ((stream :initarg :stream :accessor stream) + (dfs-table :initarg :dfs-table :reader dfs-table) + (obj-table :initarg :obj-table :reader obj-table) + (codename-table :initarg :codename-table :reader codename-table) + (codename-number :initarg :codename-number :accessor codename-number))) + + (defmethod render-graph (graph) + (get-output-stream-string (stream graph)) + (write-string (format nil "digraph {~%") (stream graph)) + (maphash #'(lambda (k v) (declare (ignore v)) (edges graph k)) (dfs-table graph)) + (write-string "}" (stream graph)) + (get-output-stream-string (stream graph))) + + ;; RENDER-GRAPH goes through all the nodes in DFS-TABLE, so we add the + ;; node corresponding to the given codename to the graph's DFS-TABLE + (defmethod expand-codename (graph codename) + (setf (gethash (gethash codename (codename-table graph)) + (dfs-table graph)) + t)) + + (defun get-node-from-codename (graph codename) + (gethash codename (codename-table graph))) + + ;; creates a new codename, ties it to this object, then returns it. + (defun add-to-code-tables (graph object) + (if (nth-value 1 (gethash object (obj-table graph))) + (gethash object (obj-table graph)) + (let ((new-codename (let ((res (format nil "~X" (codename-number graph)))) + (incf (codename-number graph)) + res))) + (setf (gethash object (obj-table graph)) + new-codename + (gethash new-codename (codename-table graph)) + object) + new-codename))) + + (let ((curr-graph nil) + (curr-file nil)) + (defun interactively-graph (graph &optional (filename nil)) + (setf curr-graph graph) + (setf curr-file filename)) + + (defun output () + (if curr-file + (save-graph (render-graph curr-graph) curr-file) + (render-graph curr-graph))) + + (defun expand (codename) + (expand-codename curr-graph codename) + (when curr-file + (output))) + + (defun get-node (codename) + (get-node-from-codename curr-graph codename))))) diff --git a/tests/sb-introspect.impure.lisp b/tests/sb-introspect.impure.lisp new file mode 100644 index 0000000000..2acc02bc01 --- /dev/null +++ b/tests/sb-introspect.impure.lisp @@ -0,0 +1,15 @@ +(require :sb-introspect) +(test-util:with-scratch-file (f "fasl") + (load (compile-file "../contrib/sb-introspect/xref-test-data.lisp" :output-file f)) + (load "../contrib/sb-introspect/xref-test.lisp") + ;; This test is quite bogus. because it depended on WITH-COMPILATION-UNIT + ;; being wrapped around both the COMPILE-FILE and LOAD which is very weird. + ;; If we take the W-C-U out from the LOAD, then the assertions on CL-USER::FOUR + ;; fails because we don't append property lists. And if we don't COMPILE-FILE, + ;; then we lose information about COMPILE-TIME-TOO-FUN. As written, it's hard to + ;; assert about behaviors that actually occur in each step. + ;; If someone thinks this is an important distinction, that someone can + ;; write better tests. + (with-compilation-unit (:source-plist '(:test-outer "OUT")) + (load (compile-file "../contrib/sb-introspect/test.lisp" :output-file f))) + (load "../contrib/sb-introspect/test-driver.lisp")) diff --git a/tests/sb-md5.impure.lisp b/tests/sb-md5.impure.lisp new file mode 100644 index 0000000000..d1d18eacb8 --- /dev/null +++ b/tests/sb-md5.impure.lisp @@ -0,0 +1,16 @@ +(require :sb-md5) + +(let ((stream (make-string-output-stream))) + (with-package-iterator (iter "SB-MD5" :internal :external) + (loop + (multiple-value-bind (flag symbol) (iter) + (unless flag (return)) + (when (and (fboundp symbol) (not (macro-function symbol))) + (let ((code (sb-kernel:fun-code-header (fdefinition symbol)))) + (disassemble code :stream stream) + (let ((text (get-output-stream-string stream))) + (when (search "ALIEN-FUNCALL" text) + (error "Compiler bug on ~S" code))))))))) + +(setq run-tests::*allowed-inputs* :any) ; makes random pathnames without aid of WITH-SCRATCH-FILE +(load "../contrib/sb-md5/md5-tests.lisp") diff --git a/tests/sb-mpfr.impure.lisp b/tests/sb-mpfr.impure.lisp new file mode 100644 index 0000000000..eb44b7261d --- /dev/null +++ b/tests/sb-mpfr.impure.lisp @@ -0,0 +1,6 @@ +(handler-case (require :sb-mpfr) + (warning (c) + (when (or (search "requires at least MPFR vers" (princ-to-string c)) + (search "not loaded" (princ-to-string c))) + (invoke-restart 'run-tests::skip-file)))) +(load "../contrib/sb-mpfr/tests.lisp") diff --git a/tests/sb-posix.impure.lisp b/tests/sb-posix.impure.lisp new file mode 100644 index 0000000000..93b1c21d0d --- /dev/null +++ b/tests/sb-posix.impure.lisp @@ -0,0 +1,8 @@ +(require :sb-posix) +(let* ((pathname (test-util:generate-test-directory-name)) + (test-util:*test-directory* pathname)) + (ensure-directories-exist pathname) + (format t "~&::: NOTE: using test-directory ~S~%" pathname) + (unwind-protect (load "../contrib/sb-posix/posix-tests.lisp") + (delete-directory pathname :recursive t))) +(load "../contrib/sb-posix/libc-tests.lisp") diff --git a/tests/sb-rotate-byte.impure.lisp b/tests/sb-rotate-byte.impure.lisp new file mode 100644 index 0000000000..109e49a009 --- /dev/null +++ b/tests/sb-rotate-byte.impure.lisp @@ -0,0 +1,2 @@ +(require :sb-rotate-byte) +(load "../contrib/sb-rotate-byte/rotate-byte-tests.lisp") diff --git a/tests/sb-simd.impure.lisp b/tests/sb-simd.impure.lisp new file mode 100644 index 0000000000..07fc2e64f6 --- /dev/null +++ b/tests/sb-simd.impure.lisp @@ -0,0 +1,29 @@ +;;; Under the evaluator +;;; (SB-SIMD-TEST-SUITE::|SB-SIMD-SSE4.1:U32.4-IF|) +;;; failed for me with +;;; RESULT-0 = #<SIMD-PACK 33554433 127 8191 2097153>, +;;; OUTPUT-0 = #<SIMD-PACK 3 8193 2303 1073741823>. +;;; maybe there are other problems but I didn't investigate further. + +#+interpreter (invoke-restart 'run-tests::skip-file) + +(handler-case (require :sb-simd) + (condition (c) + (cond ((search "Don't know how" (princ-to-string c)) + (format t "~&Skipping test of sb-simd~%") + (invoke-restart 'run-tests::skip-file)) + (t + (error "Unexpected error: ~A" c))))) + +(with-compilation-unit () + (dolist (file '("packages.lisp" + "numbers.lisp" + "utilities.lisp" + "test-suite.lisp" + "test-arefs.lisp" + "test-simple-simd-functions.lisp" + "test-horizontal-functions.lisp" + "test-hairy-simd-functions.lisp" + "test-packages.lisp")) + (load (merge-pathnames file #P"../contrib/sb-simd/test-suite/")))) +(sb-simd-test-suite::run-test-suite) diff --git a/tests/sb-simple-streams.impure.lisp b/tests/sb-simple-streams.impure.lisp new file mode 100644 index 0000000000..7ee68fab0d --- /dev/null +++ b/tests/sb-simple-streams.impure.lisp @@ -0,0 +1,3 @@ +(require :sb-simple-streams) +(setq run-tests::*allowed-inputs* :any) +(load "../contrib/sb-simple-streams/simple-stream-tests.lisp") diff --git a/tests/sb-sprof.impure.lisp b/tests/sb-sprof.impure.lisp new file mode 100644 index 0000000000..38c99a561f --- /dev/null +++ b/tests/sb-sprof.impure.lisp @@ -0,0 +1,20 @@ + +;;; This exists outside of the unit test in sb-sprof so that you can execute +;;; it with parallel-exec specifying an arbitrarily huge --runs_per_test. +;;; It is uncharacteristically verbose in its output for my liking, +;;; but I need to try to see it behaving badly (if it does), +;;; and there's really no other way than to watch for bad output. + +#+(or win32 sparc) (invoke-restart 'run-tests::skip-file) + +(require :sb-sprof) +(load "../contrib/sb-sprof/test.lisp") + +(with-test (:name :sprof) + (with-scratch-file (f "fasl") + (setq sb-sprof-test::*compiler-input* "../contrib/sb-sprof/graph.lisp" + sb-sprof-test::*compiler-output* f + ;; It was supposed to be 100 before I decreased it. + ;; surely more samples is better, right? + sb-sprof-test::*sprof-loop-test-max-samples* 100) + (sb-sprof-test:run-tests))) diff --git a/tests/selfbuild-output.pure.lisp b/tests/selfbuild-output.pure.lisp new file mode 100644 index 0000000000..7f9c2f47a2 --- /dev/null +++ b/tests/selfbuild-output.pure.lisp @@ -0,0 +1,21 @@ + +(with-test (:name :make-list-%make-list-not-called + :fails-on (:not :x86-64)) + (assert (not (ctu:find-named-callees #'make-list)))) + +;;; Make sure that we see the literal value of +;;; SB-UNICODE::+CHARACTER-MISC-DATABASE+ +(with-test (:name :alphanumericp-is-inlined + :skipped-on (:not :sb-unicode)) + (let ((code (sb-kernel:fun-code-header #'sb-impl::case-frob-capitalize-out))) + (loop for i from sb-vm:code-constants-offset below (sb-kernel:code-header-words code) + thereis (eq (sb-kernel:code-header-ref code i) + sb-unicode::+character-misc-database+)))) + +(with-test (:name :byte-bash-copier-mixup :skipped-on (or (:not :sb-devel) + :sb-devel-no-errors)) + (let ((a (make-array 20 :element-type '(unsigned-byte 8) + :initial-element 0)) + (b (make-array 5 :element-type '(unsigned-byte 32)))) + ;; Can't mix-and-match array element types. + (assert-error (sb-kernel:ub8-bash-copy a 0 b 0 5)))) diff --git a/tests/seq.impure.lisp b/tests/seq.impure.lisp index 4cba05a1ef..32b5c337d5 100644 --- a/tests/seq.impure.lisp +++ b/tests/seq.impure.lisp @@ -135,93 +135,100 @@ ;;; tests of FIND, POSITION, FIND-IF, and POSITION-IF (and a few for ;;; deprecated FIND-IF-NOT and POSITION-IF-NOT too) -(for-every-seq #() - '((null (find 1 seq)) - (null (find 1 seq :from-end t)) - (null (position 1 seq :key (indiscriminate #'abs))) - (null (position nil seq :test (constantly t))) - (null (position nil seq :test nil)) - (null (position nil seq :test-not nil)) - (null (find-if #'1+ seq :key (indiscriminate #'log))) - (null (position-if #'identity seq :from-end t)) - (null (find-if-not #'packagep seq)) - (null (position-if-not #'packagep seq :key nil)))) -(for-every-seq #(1) - '((null (find 2 seq)) - ;; Get the argument ordering for asymmetric tests like #'> right. - ;; (bug reported and fixed by Alexey Dejneka sbcl-devel 2001-10-17) - (eql 1 (find 2 seq :test #'>)) - (find 2 seq :key #'1+) - (find 1 seq :from-end t) - (null (find 1 seq :from-end t :start 1)) - (null (find 0 seq :from-end t)) - (eql 0 (position 1 seq :key #'abs)) - (null (position nil seq :test 'equal)) - (eql 1 (find-if #'1- seq :key #'log)) - (eql 0 (position-if #'identity seq :from-end t)) - (null (find-if-not #'sin seq)) - (eql 0 (position-if-not #'packagep seq :key 'identity)))) -(for-every-seq #(1 2 3 2 1) - '((find 3 seq) - (find 3 seq :from-end 'yes) - (eql 1 (position 1.5 seq :test #'<)) - (eql 0 (position 0 seq :key '1-)) - (eql 4 (position 0 seq :key '1- :from-end t)) - (eql 2 (position 4 seq :key '1+)) - (eql 2 (position 4 seq :key '1+ :from-end t)) - (eql 1 (position 2 seq)) - (eql 1 (position 2 seq :start 1)) - (null (find 2 seq :start 1 :end 1)) - (eql 3 (position 2 seq :start 2)) - (eql 3 (position 2 seq :key nil :from-end t)) - (eql 2 (position 3 seq :test '=)) - (eql 0 (position 3 seq :test-not 'equalp)) - (eql 2 (position 3 seq :test 'equal :from-end t)) - (null (position 4 seq :test #'eql)) - (null (find-if #'packagep seq)) - (eql 1 (find-if #'plusp seq)) - (eql 3 (position-if #'plusp seq :key #'1- :from-end t)) - (eql 1 (position-if #'evenp seq)) - (eql 3 (position-if #'evenp seq :from-end t)) - (eql 2 (position-if #'plusp seq :from-end nil :key '1- :start 2)) - (eql 3 (position-if #'plusp seq :from-end t :key '1- :start 2)) - (null (position-if #'plusp seq :from-end t :key '1- :start 2 :end 2)) - (null (find-if-not #'plusp seq)) - (eql 0 (position-if-not #'evenp seq)) - (eql 0 (search #(1) seq)) - (eql 1 (search #(4 5) seq :key 'oddp)) - (eql 1 (search #(-2) seq :test (lambda (a b) (= (- a) b)))) - (eql 4 (search #(1) seq :start2 1)) - (null (search #(3) seq :start2 3)) - (eql 2 (search #(3) seq :start2 2)) - (eql 0 (search #(1 2) seq)) - (null (search #(2 1 3) seq)) - (eql 0 (search #(0 1 2 4) seq :start1 1 :end1 3)) - (eql 3 (search #(0 2 1 4) seq :start1 1 :end1 3)) - (eql 4 (search #(1) seq :from-end t)) - (eql 0 (search #(1 2) seq :from-end t)) - (null (search #(1 2) seq :from-end t :start2 1)) - (eql 0 (search #(0 1 2 4) seq :from-end t :start1 1 :end1 3)) - (eql 3 (search #(0 2 1 4) seq :from-end t :start1 1 :end1 3)) - (null (search #(2 1 3) seq :from-end t)))) -(for-every-seq "string test" - '((null (find 0 seq)) - (null (find #\D seq :key #'char-upcase)) - (find #\E seq :key #'char-upcase) - (null (find #\e seq :key #'char-upcase)) - (eql 3 (position #\i seq)) - (eql 0 (position #\s seq :key #'char-downcase)) - (eql 1 (position #\s seq :key #'char-downcase :test #'char/=)) - (eql 9 (position #\s seq :from-end t :test #'char=)) - (eql 10 (position #\s seq :from-end t :test #'char/=)) - (eql 4 (position #\N seq :from-end t :key 'char-upcase :test #'char-equal)) - (eql 5 (position-if (lambda (c) (equal #\g c)) seq)) - (eql 5 (position-if (lambda (c) (equal #\g c)) seq :from-end t)) - (find-if #'characterp seq) - (find-if (lambda (c) (typep c 'base-char)) seq :from-end t) - (null (find-if 'upper-case-p seq)))) - -;;; SUBSEQ + +(with-test (:name :seq.1) + (for-every-seq #() + '((null (find 1 seq)) + (null (find 1 seq :from-end t)) + (null (position 1 seq :key (indiscriminate #'abs))) + (null (position nil seq :test (constantly t))) + (null (position nil seq :test nil)) + (null (position nil seq :test-not nil)) + (null (find-if #'1+ seq :key (indiscriminate #'log))) + (null (position-if #'identity seq :from-end t)) + (null (find-if-not #'packagep seq)) + (null (position-if-not #'packagep seq :key nil))))) + +(with-test (:name :seq.2) + (for-every-seq #(1) + '((null (find 2 seq)) + ;; Get the argument ordering for asymmetric tests like #'> right. + ;; (bug reported and fixed by Alexey Dejneka sbcl-devel 2001-10-17) + (eql 1 (find 2 seq :test #'>)) + (find 2 seq :key #'1+) + (find 1 seq :from-end t) + (null (find 1 seq :from-end t :start 1)) + (null (find 0 seq :from-end t)) + (eql 0 (position 1 seq :key #'abs)) + (null (position nil seq :test 'equal)) + (eql 1 (find-if #'1- seq :key #'log)) + (eql 0 (position-if #'identity seq :from-end t)) + (null (find-if-not #'sin seq)) + (eql 0 (position-if-not #'packagep seq :key 'identity))))) + +(with-test (:name :seq.3) + (for-every-seq #(1 2 3 2 1) + '((find 3 seq) + (find 3 seq :from-end 'yes) + (eql 1 (position 1.5 seq :test #'<)) + (eql 0 (position 0 seq :key '1-)) + (eql 4 (position 0 seq :key '1- :from-end t)) + (eql 2 (position 4 seq :key '1+)) + (eql 2 (position 4 seq :key '1+ :from-end t)) + (eql 1 (position 2 seq)) + (eql 1 (position 2 seq :start 1)) + (null (find 2 seq :start 1 :end 1)) + (eql 3 (position 2 seq :start 2)) + (eql 3 (position 2 seq :key nil :from-end t)) + (eql 2 (position 3 seq :test '=)) + (eql 0 (position 3 seq :test-not 'equalp)) + (eql 2 (position 3 seq :test 'equal :from-end t)) + (null (position 4 seq :test #'eql)) + (null (find-if #'packagep seq)) + (eql 1 (find-if #'plusp seq)) + (eql 3 (position-if #'plusp seq :key #'1- :from-end t)) + (eql 1 (position-if #'evenp seq)) + (eql 3 (position-if #'evenp seq :from-end t)) + (eql 2 (position-if #'plusp seq :from-end nil :key '1- :start 2)) + (eql 3 (position-if #'plusp seq :from-end t :key '1- :start 2)) + (null (position-if #'plusp seq :from-end t :key '1- :start 2 :end 2)) + (null (find-if-not #'plusp seq)) + (eql 0 (position-if-not #'evenp seq)) + (eql 0 (search #(1) seq)) + (eql 1 (search #(4 5) seq :key 'oddp)) + (eql 1 (search #(-2) seq :test (lambda (a b) (= (- a) b)))) + (eql 4 (search #(1) seq :start2 1)) + (null (search #(3) seq :start2 3)) + (eql 2 (search #(3) seq :start2 2)) + (eql 0 (search #(1 2) seq)) + (null (search #(2 1 3) seq)) + (eql 0 (search #(0 1 2 4) seq :start1 1 :end1 3)) + (eql 3 (search #(0 2 1 4) seq :start1 1 :end1 3)) + (eql 4 (search #(1) seq :from-end t)) + (eql 0 (search #(1 2) seq :from-end t)) + (null (search #(1 2) seq :from-end t :start2 1)) + (eql 0 (search #(0 1 2 4) seq :from-end t :start1 1 :end1 3)) + (eql 3 (search #(0 2 1 4) seq :from-end t :start1 1 :end1 3)) + (null (search #(2 1 3) seq :from-end t))))) + +(with-test (:name :seq.4) + (for-every-seq "string test" + '((null (find 0 seq)) + (null (find #\D seq :key #'char-upcase)) + (find #\E seq :key #'char-upcase) + (null (find #\e seq :key #'char-upcase)) + (eql 3 (position #\i seq)) + (eql 0 (position #\s seq :key #'char-downcase)) + (eql 1 (position #\s seq :key #'char-downcase :test #'char/=)) + (eql 9 (position #\s seq :from-end t :test #'char=)) + (eql 10 (position #\s seq :from-end t :test #'char/=)) + (eql 4 (position #\N seq :from-end t :key 'char-upcase :test #'char-equal)) + (eql 5 (position-if (lambda (c) (equal #\g c)) seq)) + (eql 5 (position-if (lambda (c) (equal #\g c)) seq :from-end t)) + (find-if #'characterp seq) + (find-if (lambda (c) (typep c 'base-char)) seq :from-end t) + (null (find-if 'upper-case-p seq))))) + (with-test (:name :subseq) (let ((avec (make-array 10 :fill-pointer 4 @@ -245,14 +252,14 @@ ;; fixed in sbcl-0.7.4.22 by WHN (assert (null (ignore-errors (aref (subseq avec 1 5) 0)))))) -;;; FILL -(defun test-fill-typecheck (x) - (declare (optimize (safety 3) (space 2) (speed 1))) - (fill (make-string 10) x)) - -(assert (string= (test-fill-typecheck #\@) "@@@@@@@@@@")) -;;; BUG 186, fixed in sbcl-0.7.5.5 -(assert (null (ignore-errors (test-fill-typecheck 4097)))) +(with-test (:name :fill-typecheck) + (checked-compile-and-assert + (:optimize :safe) + `(lambda (x) + (fill (make-string 10) x)) + ((#\@) "@@@@@@@@@@" :test #'equal) + ;; BUG 186, fixed in sbcl-0.7.5.5 + ((4097) (condition 'type-error)))) ;;; MAKE-SEQUENCE, COERCE, CONCATENATE, MERGE, MAP and requested ;;; result type (BUGs 46a, 46b, 66) @@ -266,7 +273,6 @@ (vector (signed-byte 32)) (simple-bit-vector))) (declare (optimize safety)) - (format t "~&~S~%" type-stub) ;; MAKE-SEQUENCE (assert (= (length (make-sequence `(,@type-stub) 10)) 10)) (assert (= (length (make-sequence `(,@type-stub 10) 10)) 10)) @@ -351,9 +357,9 @@ ;;; with user-defined types until sbcl-0.7.8.11 (deftype list-typeoid () 'list) (with-test (:name :merge-user-types) - (assert (equal '(1 2 3 4) (merge 'list-typeoid (list 1 3) (list 2 4) '<))) -;;; and also with types that weren't precicely LIST - (assert (equal '(1 2 3 4) (merge 'cons (list 1 3) (list 2 4) '<)))) + (assert (equal '(1 2 3 4) (merge 'list-typeoid (list 1 3) (list 2 4) '<))) + ;; and also with types that weren't precicely LIST + (assert (equal '(1 2 3 4) (merge 'cons (list 1 3) (list 2 4) '<)))) ;;; but wait, there's more! The NULL and CONS types also have implicit ;;; length requirements: @@ -408,19 +414,23 @@ ;;; ELT should signal an error of type TYPE-ERROR if its index ;;; argument isn't a valid sequence index for sequence: -(defun test-elt-signal (x) - (elt x 3)) -(assert-error (test-elt-signal "foo") type-error) -(assert (eql (test-elt-signal "foob") #\b)) -(locally - (declare (optimize (safety 3))) - (assert-error (elt (list 1 2 3) 3) type-error)) +(with-test (:name :elt-signal) + (checked-compile-and-assert + (:optimize :safe) + `(lambda (x) (elt x 3)) + (("foo") (condition 'type-error)) + (("foob") #\b)) + (locally + (declare (optimize (safety 3))) + (assert-error (elt (list 1 2 3) 3) type-error))) ;;; confusion in the refactoring led to this signalling an unbound ;;; variable, not a type error. -(defun svrefalike (x) - (svref x 0)) -(assert-error (svrefalike #*0) type-error) +(with-test (:name :svref-type-error) + (checked-compile-and-assert + (:optimize :safe) + `(lambda (x) (svref x 0)) + ((#*0) (condition 'type-error)))) ;;; checks for uniform bounding index handling. ;;; @@ -439,8 +449,6 @@ :initial-element #\a :element-type 'base-char))) ,(car body) - (format t "... BASE-CHAR") - (finish-output) (flet ((reset () (setf (fill-pointer string) 10) (fill string #\a) @@ -455,8 +463,6 @@ :initial-element #\a :element-type 'character))) ,(car body) - (format t "... CHARACTER") - (finish-output) (flet ((reset () (setf (fill-pointer string) 10) (fill string #\a) @@ -464,320 +470,303 @@ (declare (ignorable #'reset)) ,@(cdr body)))))) -;;; Accessor SUBSEQ -(sequence-bounding-indices-test - (format t "~&/Accessor SUBSEQ") - (assert (string= (subseq string 0 5) "aaaaa")) - (assert-error (subseq string 0 6)) - (assert-error (subseq string (opaque-identity -1) 5)) - (assert-error (subseq string 4 2)) - (assert-error (subseq string 6)) - (assert (string= (setf (subseq string 0 5) "abcde") "abcde")) - (assert (string= (subseq string 0 5) "abcde")) - (reset) - (assert-error (setf (subseq string 0 6) "abcdef")) - (assert-error (setf (subseq string (opaque-identity -1) 5) "abcdef")) - (assert-error (setf (subseq string 4 2) "")) - (assert-error (setf (subseq string 6) "ghij"))) - -;;; Function COUNT, COUNT-IF, COUNT-IF-NOT -(sequence-bounding-indices-test - (format t "~&/Function COUNT, COUNT-IF, COUNT-IF-NOT") - (assert (= (count #\a string :start 0 :end nil) 5)) - (assert (= (count #\a string :start 0 :end 5) 5)) - (assert-error (count #\a string :start 0 :end 6)) - (assert-error (count #\a string :start (opaque-identity -1) :end 5)) - (assert-error (count #\a string :start 4 :end 2)) - (assert-error (count #\a string :start 6 :end 9)) - (assert (= (count-if #'alpha-char-p string :start 0 :end nil) 5)) - (assert (= (count-if #'alpha-char-p string :start 0 :end 5) 5)) - (assert-error - (count-if #'alpha-char-p string :start 0 :end 6)) - (assert-error - (count-if #'alpha-char-p string :start (opaque-identity -1) :end 5)) - (assert-error - (count-if #'alpha-char-p string :start 4 :end 2)) - (assert-error - (count-if #'alpha-char-p string :start 6 :end 9)) - (assert (= (count-if-not #'alpha-char-p string :start 0 :end nil) 0)) - (assert (= (count-if-not #'alpha-char-p string :start 0 :end 5) 0)) - (assert-error - (count-if-not #'alpha-char-p string :start 0 :end 6)) - (assert-error - (count-if-not #'alpha-char-p string :start (opaque-identity -1) :end 5)) - (assert-error - (count-if-not #'alpha-char-p string :start 4 :end 2)) - (assert-error - (count-if-not #'alpha-char-p string :start 6 :end 9))) - -;;; Function FILL -(sequence-bounding-indices-test - (format t "~&/Function FILL") - (assert (string= (fill string #\b :start 0 :end 5) "bbbbb")) - (assert (string= (fill string #\c :start 0 :end nil) "ccccc")) - (assert-error (fill string #\d :start 0 :end 6)) - (assert-error (fill string #\d :start (opaque-identity -1) :end 5)) - (assert-error (fill string #\d :start 4 :end 2)) - (assert-error (fill string #\d :start 6 :end 9))) - -;;; Function FIND, FIND-IF, FIND-IF-NOT -(sequence-bounding-indices-test - (format t "~&/Function FIND, FIND-IF, FIND-IF-NOT") - (assert (char= (find #\a string :start 0 :end nil) #\a)) - (assert (char= (find #\a string :start 0 :end 5) #\a)) - (assert-error (find #\a string :start 0 :end 6)) - (assert-error (find #\a string :start (opaque-identity -1) :end 5)) - (assert-error (find #\a string :start 4 :end 2)) - (assert-error (find #\a string :start 6 :end 9)) - (assert (char= (find-if #'alpha-char-p string :start 0 :end nil) #\a)) - (assert (char= (find-if #'alpha-char-p string :start 0 :end 5) #\a)) - (assert-error - (find-if #'alpha-char-p string :start 0 :end 6)) - (assert-error - (find-if #'alpha-char-p string :start (opaque-identity -1) :end 5)) - (assert-error - (find-if #'alpha-char-p string :start 4 :end 2)) - (assert-error - (find-if #'alpha-char-p string :start 6 :end 9)) - (assert (eq (find-if-not #'alpha-char-p string :start 0 :end nil) nil)) - (assert (eq (find-if-not #'alpha-char-p string :start 0 :end 5) nil)) - (assert-error - (find-if-not #'alpha-char-p string :start 0 :end 6)) - (assert-error - (find-if-not #'alpha-char-p string :start (opaque-identity -1) :end 5)) - (assert-error - (find-if-not #'alpha-char-p string :start 4 :end 2)) - (assert-error - (find-if-not #'alpha-char-p string :start 6 :end 9))) - -;;; Function MISMATCH -(sequence-bounding-indices-test - (format t "~&/Function MISMATCH") - (assert (null (mismatch string "aaaaa" :start1 0 :end1 nil))) - (assert (= (mismatch "aaab" string :start2 0 :end2 4) 3)) - (assert-error (mismatch "aaaaaa" string :start2 0 :end2 6)) - (assert-error (mismatch string "aaaaaa" :start1 (opaque-identity -1) :end1 5)) - (assert-error (mismatch string "" :start1 4 :end1 2)) - (assert-error (mismatch "aaaa" string :start2 6 :end2 9))) - -;;; Function PARSE-INTEGER -(sequence-bounding-indices-test - (format t "~&/Function PARSE-INTEGER") - (setf (fill-pointer string) 10) - (setf (subseq string 0 10) "1234567890") - (setf (fill-pointer string) 5) - (assert (= (parse-integer string :start 0 :end 5) 12345)) - (assert (= (parse-integer string :start 0 :end nil) 12345)) - (assert-error (parse-integer string :start 0 :end 6)) - (assert-error (parse-integer string :start (opaque-identity -1) :end 5)) - (assert-error (parse-integer string :start 4 :end 2)) - (assert-error (parse-integer string :start 6 :end 9))) - -;;; Function PARSE-NAMESTRING -(sequence-bounding-indices-test - (format t "~&/Function PARSE-NAMESTRING") - (setf (fill-pointer string) 10) - (setf (subseq string 0 10) - #-win32 "/dev/ /tmp" - #+win32 "C:/ NUL") - (setf (fill-pointer string) 5) - (assert (truename (parse-namestring string nil *default-pathname-defaults* - :start 0 :end 5))) - (assert (truename (parse-namestring string nil *default-pathname-defaults* - :start 0 :end nil))) - (assert-error (parse-namestring string nil - *default-pathname-defaults* - :start 0 :end 6)) - (assert-error (parse-namestring string nil - *default-pathname-defaults* - :start (opaque-identity -1) :end 5)) - (assert-error (parse-namestring string nil - *default-pathname-defaults* - :start 4 :end 2)) - (assert-error (parse-namestring string nil - *default-pathname-defaults* - :start 6 :end 9))) - -;;; Function POSITION, POSITION-IF, POSITION-IF-NOT -(sequence-bounding-indices-test - (format t "~&/Function POSITION, POSITION-IF, POSITION-IF-NOT") - - (assert (= (position #\a string :start 0 :end nil) 0)) - (assert (= (position #\a string :start 0 :end 5) 0)) - (assert-error (position #\a string :start 0 :end 6)) - (assert-error (position #\a string :start (opaque-identity -1) :end 5)) - (assert-error (position #\a string :start 4 :end 2)) - (assert-error (position #\a string :start 6 :end 9)) - (assert (= (position-if #'alpha-char-p string :start 0 :end nil) 0)) - (assert (= (position-if #'alpha-char-p string :start 0 :end 5) 0)) - (assert-error - (position-if #'alpha-char-p string :start 0 :end 6)) - (assert-error - (position-if #'alpha-char-p string :start (opaque-identity -1) :end 5)) - (assert-error - (position-if #'alpha-char-p string :start 4 :end 2)) - (assert-error - (position-if #'alpha-char-p string :start 6 :end 9)) - (assert (eq (position-if-not #'alpha-char-p string :start 0 :end nil) nil)) - (assert (eq (position-if-not #'alpha-char-p string :start 0 :end 5) nil)) - (assert-error - (position-if-not #'alpha-char-p string :start 0 :end 6)) - (assert-error - (position-if-not #'alpha-char-p string :start (opaque-identity -1) :end 5)) - (assert-error - (position-if-not #'alpha-char-p string :start 4 :end 2)) - (assert-error - (position-if-not #'alpha-char-p string :start 6 :end 9))) - -;;; Function READ-FROM-STRING -(sequence-bounding-indices-test - (format t "~&/Function READ-FROM-STRING") - (setf (subseq string 0 5) "(a b)") - (assert (equal (read-from-string string nil nil :start 0 :end 5) '(a b))) - (assert (equal (read-from-string string nil nil :start 0 :end nil) '(a b))) - (assert-error (read-from-string string nil nil :start 0 :end 6)) - (assert-error (read-from-string string nil nil :start (opaque-identity -1) :end 5)) - (assert-error (read-from-string string nil nil :start 4 :end 2)) - (assert-error (read-from-string string nil nil :start 6 :end 9))) - -;;; Function REDUCE -(sequence-bounding-indices-test - (format t "~&/Function REDUCE") - (setf (subseq string 0 5) "abcde") - (assert (equal (reduce #'list* string :from-end t :start 0 :end nil) - '(#\a #\b #\c #\d . #\e))) - (assert (equal (reduce #'list* string :from-end t :start 0 :end 5) - '(#\a #\b #\c #\d . #\e))) - (assert-error (reduce #'list* string :start 0 :end 6)) - (assert-error (reduce #'list* string :start (opaque-identity -1) :end 5)) - (assert-error (reduce #'list* string :start 4 :end 2)) - (assert-error (reduce #'list* string :start 6 :end 9))) - -;;; Function REMOVE, REMOVE-IF, REMOVE-IF-NOT, DELETE, DELETE-IF, -;;; DELETE-IF-NOT -(sequence-bounding-indices-test - (format t "~&/Function REMOVE, REMOVE-IF, REMOVE-IF-NOT, ...") - (assert (equal (remove #\a string :start 0 :end nil) "")) - (assert (equal (remove #\a string :start 0 :end 5) "")) - (assert-error (remove #\a string :start 0 :end 6)) - (assert-error (remove #\a string :start (opaque-identity -1) :end 5)) - (assert-error (remove #\a string :start 4 :end 2)) - (assert-error (remove #\a string :start 6 :end 9)) - (assert (equal (remove-if #'alpha-char-p string :start 0 :end nil) "")) - (assert (equal (remove-if #'alpha-char-p string :start 0 :end 5) "")) - (assert-error - (remove-if #'alpha-char-p string :start 0 :end 6)) - (assert-error - (remove-if #'alpha-char-p string :start (opaque-identity -1) :end 5)) - (assert-error - (remove-if #'alpha-char-p string :start 4 :end 2)) - (assert-error - (remove-if #'alpha-char-p string :start 6 :end 9)) - (assert (equal (remove-if-not #'alpha-char-p string :start 0 :end nil) - "aaaaa")) - (assert (equal (remove-if-not #'alpha-char-p string :start 0 :end 5) - "aaaaa")) - (assert-error - (remove-if-not #'alpha-char-p string :start 0 :end 6)) - (assert-error - (remove-if-not #'alpha-char-p string :start (opaque-identity -1) :end 5)) - (assert-error - (remove-if-not #'alpha-char-p string :start 4 :end 2)) - (assert-error - (remove-if-not #'alpha-char-p string :start 6 :end 9))) -(sequence-bounding-indices-test - (format t "~&/... DELETE, DELETE-IF, DELETE-IF-NOT") - (assert (equal (delete #\a string :start 0 :end nil) "")) - (reset) - (assert (equal (delete #\a string :start 0 :end 5) "")) - (reset) - (assert-error (delete #\a string :start 0 :end 6)) - (reset) - (assert-error (delete #\a string :start (opaque-identity -1) :end 5)) - (reset) - (assert-error (delete #\a string :start 4 :end 2)) - (reset) - (assert-error (delete #\a string :start 6 :end 9)) - (reset) - (assert (equal (delete-if #'alpha-char-p string :start 0 :end nil) "")) - (reset) - (assert (equal (delete-if #'alpha-char-p string :start 0 :end 5) "")) - (reset) - (assert-error - (delete-if #'alpha-char-p string :start 0 :end 6)) - (reset) - (assert-error - (delete-if #'alpha-char-p string :start (opaque-identity -1) :end 5)) - (reset) - (assert-error - (delete-if #'alpha-char-p string :start 4 :end 2)) - (reset) - (assert-error - (delete-if #'alpha-char-p string :start 6 :end 9)) - (reset) - (assert (equal (delete-if-not #'alpha-char-p string :start 0 :end nil) - "aaaaa")) - (reset) - (assert (equal (delete-if-not #'alpha-char-p string :start 0 :end 5) - "aaaaa")) - (reset) - (assert-error - (delete-if-not #'alpha-char-p string :start 0 :end 6)) - (reset) - (assert-error - (delete-if-not #'alpha-char-p string :start (opaque-identity -1) :end 5)) - (reset) - (assert-error - (delete-if-not #'alpha-char-p string :start 4 :end 2)) - (reset) - (assert-error - (delete-if-not #'alpha-char-p string :start 6 :end 9))) - -;;; Function REMOVE-DUPLICATES, DELETE-DUPLICATES -(sequence-bounding-indices-test - (format t "~&/Function REMOVE-DUPLICATES, DELETE-DUPLICATES") - (assert (string= (remove-duplicates string :start 0 :end 5) "a")) - (assert (string= (remove-duplicates string :start 0 :end nil) "a")) - (assert-error (remove-duplicates string :start 0 :end 6)) - (assert-error (remove-duplicates string :start (opaque-identity -1) :end 5)) - (assert-error (remove-duplicates string :start 4 :end 2)) - (assert-error (remove-duplicates string :start 6 :end 9)) - (assert (string= (delete-duplicates string :start 0 :end 5) "a")) - (reset) - (assert (string= (delete-duplicates string :start 0 :end nil) "a")) - (reset) - (assert-error (delete-duplicates string :start 0 :end 6)) - (reset) - (assert-error (delete-duplicates string :start (opaque-identity -1) :end 5)) - (reset) - (assert-error (delete-duplicates string :start 4 :end 2)) - (reset) - (assert-error (delete-duplicates string :start 6 :end 9))) - -;;; Function REPLACE -(sequence-bounding-indices-test - (format t "~&/Function REPLACE") - (assert (string= (replace string "bbbbb" :start1 0 :end1 5) "bbbbb")) - (assert (string= (replace (copy-seq "ccccc") - string - :start2 0 :end2 nil) "bbbbb")) - (assert-error (replace string "ccccc" :start1 0 :end1 6)) - (assert-error (replace string "ccccc" :start2 (opaque-identity -1) :end2 5)) - (assert-error (replace string "ccccc" :start1 4 :end1 2)) - (assert-error (replace string "ccccc" :start1 6 :end1 9))) - -;;; Function SEARCH -(sequence-bounding-indices-test - (format t "~&/Function SEARCH") - (assert (= (search "aa" string :start2 0 :end2 5) 0)) - (assert (null (search string "aa" :start1 0 :end2 nil))) - (assert-error (search "aa" string :start2 0 :end2 6)) - (assert-error (search "aa" string :start2 (opaque-identity -1) :end2 5)) - (assert-error (search "aa" string :start2 4 :end2 2)) - (assert-error (search "aa" string :start2 6 :end2 9))) - -;;; Function STRING-UPCASE, STRING-DOWNCASE, STRING-CAPITALIZE, -;;; NSTRING-UPCASE, NSTRING-DOWNCASE, NSTRING-CAPITALIZE +(with-test (:name (:bounding-index subseq)) + (sequence-bounding-indices-test + (assert (string= (subseq string 0 5) "aaaaa")) + (assert-error (subseq string 0 6)) + (assert-error (subseq string (opaque-identity -1) 5)) + (assert-error (subseq string 4 2)) + (assert-error (subseq string 6)) + (assert (string= (setf (subseq string 0 5) "abcde") "abcde")) + (assert (string= (subseq string 0 5) "abcde")) + (reset) + (assert-error (setf (subseq string 0 6) "abcdef")) + (assert-error (setf (subseq string (opaque-identity -1) 5) "abcdef")) + (assert-error (setf (subseq string 4 2) "")) + (assert-error (setf (subseq string 6) "ghij")))) + +(with-test (:name (:bounding-index count)) + (sequence-bounding-indices-test + (assert (= (count #\a string :start 0 :end nil) 5)) + (assert (= (count #\a string :start 0 :end 5) 5)) + (assert-error (count #\a string :start 0 :end 6)) + (assert-error (count #\a string :start (opaque-identity -1) :end 5)) + (assert-error (count #\a string :start 4 :end 2)) + (assert-error (count #\a string :start 6 :end 9)) + (assert (= (count-if #'alpha-char-p string :start 0 :end nil) 5)) + (assert (= (count-if #'alpha-char-p string :start 0 :end 5) 5)) + (assert-error + (count-if #'alpha-char-p string :start 0 :end 6)) + (assert-error + (count-if #'alpha-char-p string :start (opaque-identity -1) :end 5)) + (assert-error + (count-if #'alpha-char-p string :start 4 :end 2)) + (assert-error + (count-if #'alpha-char-p string :start 6 :end 9)) + (assert (= (count-if-not #'alpha-char-p string :start 0 :end nil) 0)) + (assert (= (count-if-not #'alpha-char-p string :start 0 :end 5) 0)) + (assert-error + (count-if-not #'alpha-char-p string :start 0 :end 6)) + (assert-error + (count-if-not #'alpha-char-p string :start (opaque-identity -1) :end 5)) + (assert-error + (count-if-not #'alpha-char-p string :start 4 :end 2)) + (assert-error + (count-if-not #'alpha-char-p string :start 6 :end 9)))) + +(with-test (:name (:bounding-index fill)) + (sequence-bounding-indices-test + (assert (string= (fill string #\b :start 0 :end 5) "bbbbb")) + (assert (string= (fill string #\c :start 0 :end nil) "ccccc")) + (assert-error (fill string #\d :start 0 :end 6)) + (assert-error (fill string #\d :start (opaque-identity -1) :end 5)) + (assert-error (fill string #\d :start 4 :end 2)) + (assert-error (fill string #\d :start 6 :end 9)))) + +(with-test (:name (:bounding-index find)) + (sequence-bounding-indices-test + (assert (char= (find #\a string :start 0 :end nil) #\a)) + (assert (char= (find #\a string :start 0 :end 5) #\a)) + (assert-error (find #\a string :start 0 :end 6)) + (assert-error (find #\a string :start (opaque-identity -1) :end 5)) + (assert-error (find #\a string :start 4 :end 2)) + (assert-error (find #\a string :start 6 :end 9)) + (assert (char= (find-if #'alpha-char-p string :start 0 :end nil) #\a)) + (assert (char= (find-if #'alpha-char-p string :start 0 :end 5) #\a)) + (assert-error + (find-if #'alpha-char-p string :start 0 :end 6)) + (assert-error + (find-if #'alpha-char-p string :start (opaque-identity -1) :end 5)) + (assert-error + (find-if #'alpha-char-p string :start 4 :end 2)) + (assert-error + (find-if #'alpha-char-p string :start 6 :end 9)) + (assert (eq (find-if-not #'alpha-char-p string :start 0 :end nil) nil)) + (assert (eq (find-if-not #'alpha-char-p string :start 0 :end 5) nil)) + (assert-error + (find-if-not #'alpha-char-p string :start 0 :end 6)) + (assert-error + (find-if-not #'alpha-char-p string :start (opaque-identity -1) :end 5)) + (assert-error + (find-if-not #'alpha-char-p string :start 4 :end 2)) + (assert-error + (find-if-not #'alpha-char-p string :start 6 :end 9)))) + +(with-test (:name (:bounding-index mismatch)) + (sequence-bounding-indices-test + (assert (null (mismatch string "aaaaa" :start1 0 :end1 nil))) + (assert (= (mismatch "aaab" string :start2 0 :end2 4) 3)) + (assert-error (mismatch "aaaaaa" string :start2 0 :end2 6)) + (assert-error (mismatch string "aaaaaa" :start1 (opaque-identity -1) :end1 5)) + (assert-error (mismatch string "" :start1 4 :end1 2)) + (assert-error (mismatch "aaaa" string :start2 6 :end2 9)))) + +(with-test (:name (:bounding-index parse-integer)) + (sequence-bounding-indices-test + (setf (fill-pointer string) 10) + (setf (subseq string 0 10) "1234567890") + (setf (fill-pointer string) 5) + (assert (= (parse-integer string :start 0 :end 5) 12345)) + (assert (= (parse-integer string :start 0 :end nil) 12345)) + (assert-error (parse-integer string :start 0 :end 6)) + (assert-error (parse-integer string :start (opaque-identity -1) :end 5)) + (assert-error (parse-integer string :start 4 :end 2)) + (assert-error (parse-integer string :start 6 :end 9)))) + +(with-test (:name (:bounding-index parse-namestring)) + (sequence-bounding-indices-test + (setf (fill-pointer string) 10) + (setf (subseq string 0 10) + #-win32 "/dev/ /tmp" + #+win32 "C:/ NUL") + (setf (fill-pointer string) 5) + (assert (truename (parse-namestring string nil *default-pathname-defaults* + :start 0 :end 5))) + (assert (truename (parse-namestring string nil *default-pathname-defaults* + :start 0 :end nil))) + (assert-error (parse-namestring string nil + *default-pathname-defaults* + :start 0 :end 6)) + (assert-error (parse-namestring string nil + *default-pathname-defaults* + :start (opaque-identity -1) :end 5)) + (assert-error (parse-namestring string nil + *default-pathname-defaults* + :start 4 :end 2)) + (assert-error (parse-namestring string nil + *default-pathname-defaults* + :start 6 :end 9)))) + +(with-test (:name (:bounding-index position)) + (sequence-bounding-indices-test + (assert (= (position #\a string :start 0 :end nil) 0)) + (assert (= (position #\a string :start 0 :end 5) 0)) + (assert-error (position #\a string :start 0 :end 6)) + (assert-error (position #\a string :start (opaque-identity -1) :end 5)) + (assert-error (position #\a string :start 4 :end 2)) + (assert-error (position #\a string :start 6 :end 9)) + (assert (= (position-if #'alpha-char-p string :start 0 :end nil) 0)) + (assert (= (position-if #'alpha-char-p string :start 0 :end 5) 0)) + (assert-error + (position-if #'alpha-char-p string :start 0 :end 6)) + (assert-error + (position-if #'alpha-char-p string :start (opaque-identity -1) :end 5)) + (assert-error + (position-if #'alpha-char-p string :start 4 :end 2)) + (assert-error + (position-if #'alpha-char-p string :start 6 :end 9)) + (assert (eq (position-if-not #'alpha-char-p string :start 0 :end nil) nil)) + (assert (eq (position-if-not #'alpha-char-p string :start 0 :end 5) nil)) + (assert-error + (position-if-not #'alpha-char-p string :start 0 :end 6)) + (assert-error + (position-if-not #'alpha-char-p string :start (opaque-identity -1) :end 5)) + (assert-error + (position-if-not #'alpha-char-p string :start 4 :end 2)) + (assert-error + (position-if-not #'alpha-char-p string :start 6 :end 9)))) + +(with-test (:name (:bounding-index read-from-string)) + (sequence-bounding-indices-test + (setf (subseq string 0 5) "(a b)") + (assert (equal (read-from-string string nil nil :start 0 :end 5) '(a b))) + (assert (equal (read-from-string string nil nil :start 0 :end nil) '(a b))) + (assert-error (read-from-string string nil nil :start 0 :end 6)) + (assert-error (read-from-string string nil nil :start (opaque-identity -1) :end 5)) + (assert-error (read-from-string string nil nil :start 4 :end 2)) + (assert-error (read-from-string string nil nil :start 6 :end 9)))) + +(with-test (:name (:bounding-index reduce)) + (sequence-bounding-indices-test + (setf (subseq string 0 5) "abcde") + (assert (equal (reduce #'list* string :from-end t :start 0 :end nil) + '(#\a #\b #\c #\d . #\e))) + (assert (equal (reduce #'list* string :from-end t :start 0 :end 5) + '(#\a #\b #\c #\d . #\e))) + (assert-error (reduce #'list* string :start 0 :end 6)) + (assert-error (reduce #'list* string :start (opaque-identity -1) :end 5)) + (assert-error (reduce #'list* string :start 4 :end 2)) + (assert-error (reduce #'list* string :start 6 :end 9)))) + +(with-test (:name (:bounding-index remove)) + (sequence-bounding-indices-test + (assert (equal (remove #\a string :start 0 :end nil) "")) + (assert (equal (remove #\a string :start 0 :end 5) "")) + (assert-error (remove #\a string :start 0 :end 6)) + (assert-error (remove #\a string :start (opaque-identity -1) :end 5)) + (assert-error (remove #\a string :start 4 :end 2)) + (assert-error (remove #\a string :start 6 :end 9)) + (assert (equal (remove-if #'alpha-char-p string :start 0 :end nil) "")) + (assert (equal (remove-if #'alpha-char-p string :start 0 :end 5) "")) + (assert-error + (remove-if #'alpha-char-p string :start 0 :end 6)) + (assert-error + (remove-if #'alpha-char-p string :start (opaque-identity -1) :end 5)) + (assert-error + (remove-if #'alpha-char-p string :start 4 :end 2)) + (assert-error + (remove-if #'alpha-char-p string :start 6 :end 9)) + (assert (equal (remove-if-not #'alpha-char-p string :start 0 :end nil) + "aaaaa")) + (assert (equal (remove-if-not #'alpha-char-p string :start 0 :end 5) + "aaaaa")) + (assert-error + (remove-if-not #'alpha-char-p string :start 0 :end 6)) + (assert-error + (remove-if-not #'alpha-char-p string :start (opaque-identity -1) :end 5)) + (assert-error + (remove-if-not #'alpha-char-p string :start 4 :end 2)) + (assert-error + (remove-if-not #'alpha-char-p string :start 6 :end 9)))) + +(with-test (:name (:bounding-index delete)) + (sequence-bounding-indices-test + (assert (equal (delete #\a string :start 0 :end nil) "")) + (reset) + (assert (equal (delete #\a string :start 0 :end 5) "")) + (reset) + (assert-error (delete #\a string :start 0 :end 6)) + (reset) + (assert-error (delete #\a string :start (opaque-identity -1) :end 5)) + (reset) + (assert-error (delete #\a string :start 4 :end 2)) + (reset) + (assert-error (delete #\a string :start 6 :end 9)) + (reset) + (assert (equal (delete-if #'alpha-char-p string :start 0 :end nil) "")) + (reset) + (assert (equal (delete-if #'alpha-char-p string :start 0 :end 5) "")) + (reset) + (assert-error + (delete-if #'alpha-char-p string :start 0 :end 6)) + (reset) + (assert-error + (delete-if #'alpha-char-p string :start (opaque-identity -1) :end 5)) + (reset) + (assert-error + (delete-if #'alpha-char-p string :start 4 :end 2)) + (reset) + (assert-error + (delete-if #'alpha-char-p string :start 6 :end 9)) + (reset) + (assert (equal (delete-if-not #'alpha-char-p string :start 0 :end nil) + "aaaaa")) + (reset) + (assert (equal (delete-if-not #'alpha-char-p string :start 0 :end 5) + "aaaaa")) + (reset) + (assert-error + (delete-if-not #'alpha-char-p string :start 0 :end 6)) + (reset) + (assert-error + (delete-if-not #'alpha-char-p string :start (opaque-identity -1) :end 5)) + (reset) + (assert-error + (delete-if-not #'alpha-char-p string :start 4 :end 2)) + (reset) + (assert-error + (delete-if-not #'alpha-char-p string :start 6 :end 9)))) + +(with-test (:name (:bounding-index remove-duplicates)) + (sequence-bounding-indices-test + (assert (string= (remove-duplicates string :start 0 :end 5) "a")) + (assert (string= (remove-duplicates string :start 0 :end nil) "a")) + (assert-error (remove-duplicates string :start 0 :end 6)) + (assert-error (remove-duplicates string :start (opaque-identity -1) :end 5)) + (assert-error (remove-duplicates string :start 4 :end 2)) + (assert-error (remove-duplicates string :start 6 :end 9)) + (assert (string= (delete-duplicates string :start 0 :end 5) "a")) + (reset) + (assert (string= (delete-duplicates string :start 0 :end nil) "a")) + (reset) + (assert-error (delete-duplicates string :start 0 :end 6)) + (reset) + (assert-error (delete-duplicates string :start (opaque-identity -1) :end 5)) + (reset) + (assert-error (delete-duplicates string :start 4 :end 2)) + (reset) + (assert-error (delete-duplicates string :start 6 :end 9)))) + +(with-test (:name (:bounding-index replace)) + (sequence-bounding-indices-test + (assert (string= (replace string "bbbbb" :start1 0 :end1 5) "bbbbb")) + (assert (string= (replace (copy-seq "ccccc") + string + :start2 0 :end2 nil) "bbbbb")) + (assert-error (replace string "ccccc" :start1 0 :end1 6)) + (assert-error (replace string "ccccc" :start2 (opaque-identity -1) :end2 5)) + (assert-error (replace string "ccccc" :start1 4 :end1 2)) + (assert-error (replace string "ccccc" :start1 6 :end1 9)))) + +(with-test (:name (:bounding-index search)) + (sequence-bounding-indices-test + (assert (= (search "aa" string :start2 0 :end2 5) 0)) + (assert (null (search string "aa" :start1 0 :end2 nil))) + (assert-error (search "aa" string :start2 0 :end2 6)) + (assert-error (search "aa" string :start2 (opaque-identity -1) :end2 5)) + (assert-error (search "aa" string :start2 4 :end2 2)) + (assert-error (search "aa" string :start2 6 :end2 9)))) + (defmacro string-case-frob (fn) `(progn (assert-error (,fn string :start 0 :end 6)) @@ -785,19 +774,15 @@ (assert-error (,fn string :start 4 :end 2)) (assert-error (,fn string :start 6 :end 9)))) -(sequence-bounding-indices-test - (format t "~&/Function STRING-UPCASE, STRING-DOWNCASE, STRING-CAPITALIZE, ...") - (string-case-frob string-upcase) - (string-case-frob string-downcase) - (string-case-frob string-capitalize) - (format t "~&/... NSTRING-UPCASE, NSTRING-DOWNCASE, NSTRING-CAPITALIZE") - (string-case-frob nstring-upcase) - (string-case-frob nstring-downcase) - (string-case-frob nstring-capitalize)) - -;;; Function STRING=, STRING/=, STRING<, STRING>, STRING<=, STRING>=, -;;; STRING-EQUAL, STRING-NOT-EQUAL, STRING-LESSP, STRING-GREATERP, -;;; STRING-NOT-GREATERP, STRING-NOT-LESSP +(with-test (:name (:bounding-index :string-case)) + (sequence-bounding-indices-test + (string-case-frob string-upcase) + (string-case-frob string-downcase) + (string-case-frob string-capitalize) + (string-case-frob nstring-upcase) + (string-case-frob nstring-downcase) + (string-case-frob nstring-capitalize))) + (defmacro string-predicate-frob (fn) `(progn (,fn string "abcde" :start1 0 :end1 5) @@ -809,161 +794,161 @@ (assert-error (,fn "uvwxy" string :start1 4 :end1 2)) (assert-error (,fn string "z" :start2 6 :end2 9)))) -(sequence-bounding-indices-test - (format t "~&/Function STRING=, STRING/=, STRING<, STRING>, STRING<=, STRING>=, ...") - (string-predicate-frob string=) - (string-predicate-frob string/=) - (string-predicate-frob string<) - (string-predicate-frob string>) - (string-predicate-frob string<=) - (string-predicate-frob string>=)) -(sequence-bounding-indices-test - (format t "~&/... STRING-EQUAL, STRING-NOT-EQUAL, STRING-LESSP, ...") - (string-predicate-frob string-equal) - (string-predicate-frob string-not-equal) - (string-predicate-frob string-lessp)) -(sequence-bounding-indices-test - (format t "~&/... STRING-GREATERP, STRING-NOT-GREATERP, STRING-NOT-LESSP") - (string-predicate-frob string-greaterp) - (string-predicate-frob string-not-greaterp) - (string-predicate-frob string-not-lessp)) - -;;; Function SUBSTITUTE, SUBSTITUTE-IF, SUBSTITUTE-IF-NOT, -;;; NSUBSTITUTE, NSUBSTITUTE-IF, NSUBSTITUTE-IF-NOT -(sequence-bounding-indices-test - (format t "~&/Function SUBSTITUTE, SUBSTITUTE-IF, SUBSTITUTE-IF-NOT, ...") - (assert (string= (substitute #\b #\a string :start 0 :end 5) "bbbbb")) - (assert (string= (substitute #\c #\a string :start 0 :end nil) - "ccccc")) - (assert-error (substitute #\b #\a string :start 0 :end 6)) - (assert-error (substitute #\b #\a string :start (opaque-identity -1) :end 5)) - (assert-error (substitute #\b #\a string :start 4 :end 2)) - (assert-error (substitute #\b #\a string :start 6 :end 9)) - (assert (string= (substitute-if #\b #'alpha-char-p string - :start 0 :end 5) - "bbbbb")) - (assert (string= (substitute-if #\c #'alpha-char-p string - :start 0 :end nil) - "ccccc")) - (assert-error (substitute-if #\b #'alpha-char-p string - :start 0 :end 6)) - (assert-error (substitute-if #\b #'alpha-char-p string - :start (opaque-identity -1) :end 5)) - (assert-error (substitute-if #\b #'alpha-char-p string - :start 4 :end 2)) - (assert-error (substitute-if #\b #'alpha-char-p string - :start 6 :end 9)) - (assert (string= (substitute-if-not #\b #'alpha-char-p string - :start 0 :end 5) - "aaaaa")) - (assert (string= (substitute-if-not #\c #'alpha-char-p string - :start 0 :end nil) - "aaaaa")) - (assert-error (substitute-if-not #\b #'alpha-char-p string - :start 0 :end 6)) - (assert-error (substitute-if-not #\b #'alpha-char-p string - :start (opaque-identity -1) :end 5)) - (assert-error (substitute-if-not #\b #'alpha-char-p string - :start 4 :end 2)) - (assert-error (substitute-if-not #\b #'alpha-char-p string - :start 6 :end 9))) -(sequence-bounding-indices-test - (format t "~&/... NSUBSTITUTE, NSUBSTITUTE-IF, NSUBSTITUTE-IF-NOT") - (assert (string= (nsubstitute #\b #\a string :start 0 :end 5) "bbbbb")) - (reset) - (assert (string= (nsubstitute #\c #\a string :start 0 :end nil) - "ccccc")) - (reset) - (assert-error (nsubstitute #\b #\a string :start 0 :end 6)) - (reset) - (assert-error (nsubstitute #\b #\a string :start (opaque-identity -1) :end 5)) - (reset) - (assert-error (nsubstitute #\b #\a string :start 4 :end 2)) - (reset) - (assert-error (nsubstitute #\b #\a string :start 6 :end 9)) - (reset) - (assert (string= (nsubstitute-if #\b #'alpha-char-p string - :start 0 :end 5) - "bbbbb")) - (reset) - (assert (string= (nsubstitute-if #\c #'alpha-char-p string - :start 0 :end nil) - "ccccc")) - (reset) - (assert-error (nsubstitute-if #\b #'alpha-char-p string +(with-test (:name (:bounding-index string=)) + (sequence-bounding-indices-test + (string-predicate-frob string=) + (string-predicate-frob string/=) + (string-predicate-frob string<) + (string-predicate-frob string>) + (string-predicate-frob string<=) + (string-predicate-frob string>=))) + +(with-test (:name (:bounding-index string-equal)) + (sequence-bounding-indices-test + (string-predicate-frob string-equal) + (string-predicate-frob string-not-equal) + (string-predicate-frob string-lessp))) + +(with-test (:name (:bounding-index string-greaterp)) + (sequence-bounding-indices-test + (string-predicate-frob string-greaterp) + (string-predicate-frob string-not-greaterp) + (string-predicate-frob string-not-lessp))) + +(with-test (:name (:bounding-index substitute)) + (sequence-bounding-indices-test + (assert (string= (substitute #\b #\a string :start 0 :end 5) "bbbbb")) + (assert (string= (substitute #\c #\a string :start 0 :end nil) + "ccccc")) + (assert-error (substitute #\b #\a string :start 0 :end 6)) + (assert-error (substitute #\b #\a string :start (opaque-identity -1) :end 5)) + (assert-error (substitute #\b #\a string :start 4 :end 2)) + (assert-error (substitute #\b #\a string :start 6 :end 9)) + (assert (string= (substitute-if #\b #'alpha-char-p string + :start 0 :end 5) + "bbbbb")) + (assert (string= (substitute-if #\c #'alpha-char-p string + :start 0 :end nil) + "ccccc")) + (assert-error (substitute-if #\b #'alpha-char-p string + :start 0 :end 6)) + (assert-error (substitute-if #\b #'alpha-char-p string + :start (opaque-identity -1) :end 5)) + (assert-error (substitute-if #\b #'alpha-char-p string + :start 4 :end 2)) + (assert-error (substitute-if #\b #'alpha-char-p string + :start 6 :end 9)) + (assert (string= (substitute-if-not #\b #'alpha-char-p string + :start 0 :end 5) + "aaaaa")) + (assert (string= (substitute-if-not #\c #'alpha-char-p string + :start 0 :end nil) + "aaaaa")) + (assert-error (substitute-if-not #\b #'alpha-char-p string + :start 0 :end 6)) + (assert-error (substitute-if-not #\b #'alpha-char-p string + :start (opaque-identity -1) :end 5)) + (assert-error (substitute-if-not #\b #'alpha-char-p string + :start 4 :end 2)) + (assert-error (substitute-if-not #\b #'alpha-char-p string + :start 6 :end 9)))) + +(with-test (:name (:bounding-index nsubstitute)) + (sequence-bounding-indices-test + (assert (string= (nsubstitute #\b #\a string :start 0 :end 5) "bbbbb")) + (reset) + (assert (string= (nsubstitute #\c #\a string :start 0 :end nil) + "ccccc")) + (reset) + (assert-error (nsubstitute #\b #\a string :start 0 :end 6)) + (reset) + (assert-error (nsubstitute #\b #\a string :start (opaque-identity -1) :end 5)) + (reset) + (assert-error (nsubstitute #\b #\a string :start 4 :end 2)) + (reset) + (assert-error (nsubstitute #\b #\a string :start 6 :end 9)) + (reset) + (assert (string= (nsubstitute-if #\b #'alpha-char-p string + :start 0 :end 5) + "bbbbb")) + (reset) + (assert (string= (nsubstitute-if #\c #'alpha-char-p string + :start 0 :end nil) + "ccccc")) + (reset) + (assert-error (nsubstitute-if #\b #'alpha-char-p string + :start 0 :end 6)) + (reset) + (assert-error (nsubstitute-if #\b #'alpha-char-p string + :start (opaque-identity -1) :end 5)) + (reset) + (assert-error (nsubstitute-if #\b #'alpha-char-p string + :start 4 :end 2)) + (reset) + (assert-error (nsubstitute-if #\b #'alpha-char-p string + :start 6 :end 9)) + (reset) + (assert (string= (nsubstitute-if-not #\b #'alpha-char-p string + :start 0 :end 5) + "aaaaa")) + (reset) + (assert (string= (nsubstitute-if-not #\c #'alpha-char-p string + :start 0 :end nil) + "aaaaa")) + (reset) + (assert-error (nsubstitute-if-not #\b #'alpha-char-p string + :start 0 :end 6)) + (reset) + (assert-error (nsubstitute-if-not #\b #'alpha-char-p string + :start (opaque-identity -1) :end 5)) + (reset) + (assert-error (nsubstitute-if-not #\b #'alpha-char-p string + :start 4 :end 2)) + (reset) + (assert-error (nsubstitute-if-not #\b #'alpha-char-p string + :start 6 :end 9)))) + +(with-test (:name (:bounding-index write-string)) + (sequence-bounding-indices-test + (write-string string *standard-output* :start 0 :end 5) + (write-string string *standard-output* :start 0 :end nil) + (assert-error (write-string string *standard-output* :start 0 :end 6)) - (reset) - (assert-error (nsubstitute-if #\b #'alpha-char-p string + (assert-error (write-string string *standard-output* :start (opaque-identity -1) :end 5)) - (reset) - (assert-error (nsubstitute-if #\b #'alpha-char-p string + (assert-error (write-string string *standard-output* :start 4 :end 2)) - (reset) - (assert-error (nsubstitute-if #\b #'alpha-char-p string + (assert-error (write-string string *standard-output* :start 6 :end 9)) - (reset) - (assert (string= (nsubstitute-if-not #\b #'alpha-char-p string - :start 0 :end 5) - "aaaaa")) - (reset) - (assert (string= (nsubstitute-if-not #\c #'alpha-char-p string - :start 0 :end nil) - "aaaaa")) - (reset) - (assert-error (nsubstitute-if-not #\b #'alpha-char-p string - :start 0 :end 6)) - (reset) - (assert-error (nsubstitute-if-not #\b #'alpha-char-p string - :start (opaque-identity -1) :end 5)) - (reset) - (assert-error (nsubstitute-if-not #\b #'alpha-char-p string - :start 4 :end 2)) - (reset) - (assert-error (nsubstitute-if-not #\b #'alpha-char-p string - :start 6 :end 9))) -;;; Function WRITE-STRING, WRITE-LINE -(sequence-bounding-indices-test - (format t "~&/Function WRITE-STRING, WRITE-LINE") - (write-string string *standard-output* :start 0 :end 5) - (write-string string *standard-output* :start 0 :end nil) - (assert-error (write-string string *standard-output* + (write-line string *standard-output* :start 0 :end 5) + (write-line string *standard-output* :start 0 :end nil) + (assert-error (write-line string *standard-output* :start 0 :end 6)) - (assert-error (write-string string *standard-output* + (assert-error (write-line string *standard-output* :start (opaque-identity -1) :end 5)) - (assert-error (write-string string *standard-output* + (assert-error (write-line string *standard-output* :start 4 :end 2)) - (assert-error (write-string string *standard-output* - :start 6 :end 9)) - (write-line string *standard-output* :start 0 :end 5) - (write-line string *standard-output* :start 0 :end nil) - (assert-error (write-line string *standard-output* - :start 0 :end 6)) - (assert-error (write-line string *standard-output* - :start (opaque-identity -1) :end 5)) - (assert-error (write-line string *standard-output* - :start 4 :end 2)) - (assert-error (write-line string *standard-output* - :start 6 :end 9))) - -;;; Macro WITH-INPUT-FROM-STRING -(sequence-bounding-indices-test - (format t "~&/Macro WITH-INPUT-FROM-STRING") - (with-input-from-string (s string :start 0 :end 5) - (assert (char= (read-char s) #\a))) - (with-input-from-string (s string :start 0 :end nil) - (assert (char= (read-char s) #\a))) - (assert-error - (with-input-from-string (s string :start 0 :end 6) - (read-char s))) - (assert-error - (with-input-from-string (s string :start (opaque-identity -1) :end 5) - (read-char s))) - (assert-error - (with-input-from-string (s string :start 4 :end 2) - (read-char s))) - (assert-error - (with-input-from-string (s string :start 6 :end 9) - (read-char s)))) + (assert-error (write-line string *standard-output* + :start 6 :end 9)))) + +(with-test (:name (:bounding-index with-input-from-string)) + (sequence-bounding-indices-test + (with-input-from-string (s string :start 0 :end 5) + (assert (char= (read-char s) #\a))) + (with-input-from-string (s string :start 0 :end nil) + (assert (char= (read-char s) #\a))) + (assert-error + (with-input-from-string (s string :start 0 :end 6) + (read-char s))) + (assert-error + (with-input-from-string (s string :start (opaque-identity -1) :end 5) + (read-char s))) + (assert-error + (with-input-from-string (s string :start 4 :end 2) + (read-char s))) + (assert-error + (with-input-from-string (s string :start 6 :end 9) + (read-char s))))) ;;; testing bit-bashing according to _The Practice of Programming_ (defun fill-bytes-for-testing (bitsize) @@ -992,7 +977,6 @@ (fill-amounts (collect-fill-amounts n-power)) (bash-function (intern (format nil "UB~A-BASH-FILL" bitsize) (find-package "SB-KERNEL")))) - (format t "~&/Function ~A..." bash-function) (loop for offset from padding-amount below (* 2 padding-amount) do (dolist (c (fill-bytes-for-testing bitsize)) (dolist (n fill-amounts) @@ -1025,7 +1009,6 @@ (fill-amounts (collect-fill-amounts n-power)) (bash-function (intern (format nil "UB~A-BASH-COPY" bitsize) (find-package "SB-KERNEL")))) - (format t "~&/Function ~A..." bash-function) (do ((source-offset padding-amount (1+ source-offset))) ((>= source-offset (* padding-amount 2)) ;; success! @@ -1055,18 +1038,19 @@ bashed-dst) (return-from test-copy-bashing nil)))))))) -;; Too slow for the interpreter -#+#.(cl:if (cl:eq sb-ext:*evaluator-mode* :compile) '(and) '(or)) -(loop for i = 1 then (* i 2) do - ;; the bare '13' here is fairly arbitrary, except that it's been - ;; reduced from '32', which made the tests take aeons; '8' provides - ;; a good range of lengths over which to fill and copy, which - ;; should tease out most errors in the code (if any exist). (It - ;; also makes this part of the test suite finish reasonably - ;; quickly.) - (assert (time (test-fill-bashing i 13 8))) - (assert (time (test-copy-bashing i 13 8))) - until (= i sb-vm:n-word-bits)) +(with-test (:name :bash + ;; Too slow for the interpreter + :skipped-on :interpreter) + (loop for i = 1 then (* i 2) do + ;; the bare '13' here is fairly arbitrary, except that it's been + ;; reduced from '32', which made the tests take aeons; '8' provides + ;; a good range of lengths over which to fill and copy, which + ;; should tease out most errors in the code (if any exist). (It + ;; also makes this part of the test suite finish reasonably + ;; quickly.) + (assert (test-fill-bashing i 13 8)) + (assert (test-copy-bashing i 13 8)) + until (= i sb-vm:n-word-bits))) (defun test-inlined-bashing (bitsize) ;; We have to compile things separately for each bitsize so the @@ -1117,32 +1101,33 @@ (return-from nil nil)))))))) (funcall (checked-compile lambda-form)))) -#+#.(cl:if (cl:eq sb-ext:*evaluator-mode* :compile) '(and) '(or)) -(loop for i = 1 then (* i 2) do - (assert (test-inlined-bashing i)) - until (= i sb-vm:n-word-bits)) +(with-test (:name :inline-bash + :skipped-on :interpreter) + (loop for i = 1 then (* i 2) do + (assert (test-inlined-bashing i)) + until (= i sb-vm:n-word-bits))) ;;; tests from the Sacla test suite via Eric Marsden, 2007-05-07 -(remove-duplicates (vector 1 2 2 1) :test-not (lambda (a b) (not (= a b)))) - -(delete-duplicates (vector #\a #\b #\c #\a) - :test-not (lambda (a b) (not (char-equal a b)))) - -;;; FILL on lists -(let ((l (list 1 2 3))) - (assert (eq l (fill l 0 :start 1 :end 2))) - (assert (equal l '(1 0 3))) - (assert (eq l (fill l 'x :start 2 :end 3))) - (assert (equal l '(1 0 x))) - (assert (eq l (fill l 'y :start 1))) - (assert (equal l '(1 y y))) - (assert (eq l (fill l 'z :end 2))) - (assert (equal l '(z z y))) - (assert (eq l (fill l 1))) - (assert (equal l '(1 1 1))) - (assert-error (fill l 0 :start 4)) - (assert-error (fill l 0 :end 4)) - (assert-error (fill l 0 :start 2 :end 1))) +(with-test (:name :remove-duplicates-test-not) + (remove-duplicates (vector 1 2 2 1) :test-not (lambda (a b) (not (= a b)))) + (delete-duplicates (vector #\a #\b #\c #\a) + :test-not (lambda (a b) (not (char-equal a b))))) + +(with-test (:name :fill-list) + (let ((l (list 1 2 3))) + (assert (eq l (fill l 0 :start 1 :end 2))) + (assert (equal l '(1 0 3))) + (assert (eq l (fill l 'x :start 2 :end 3))) + (assert (equal l '(1 0 x))) + (assert (eq l (fill l 'y :start 1))) + (assert (equal l '(1 y y))) + (assert (eq l (fill l 'z :end 2))) + (assert (equal l '(z z y))) + (assert (eq l (fill l 1))) + (assert (equal l '(1 1 1))) + (assert-error (fill l 0 :start 4)) + (assert-error (fill l 0 :end 4)) + (assert-error (fill l 0 :start 2 :end 1)))) ;;; Both :TEST and :TEST-NOT provided (with-test (:name :test-and-test-not-to-adjoin) @@ -1218,7 +1203,8 @@ (defun random-test-bit-position (n) (loop repeat n - do (let* ((vector (make-array (+ 2 (random 5000)) :element-type 'bit)) + do (let* ((vector (make-array (+ 2 (random 5000)) :element-type 'bit + :initial-element 0)) (offset (random (1- (length vector)))) (size (1+ (random (- (length vector) offset)))) (disp (make-array size :element-type 'bit :displaced-to vector diff --git a/tests/seq.pure.lisp b/tests/seq.pure.lisp index 8b17fb4cca..3f65434e27 100644 --- a/tests/seq.pure.lisp +++ b/tests/seq.pure.lisp @@ -215,7 +215,7 @@ ;;; a proper sequence". (with-test (:name (copy-seq type-error)) (locally (declare (optimize safety)) - (multiple-value-bind (seq err) (ignore-errors (copy-seq '(1 2 3 . 4))) + (multiple-value-bind (seq err) (ignore-errors (copy-seq (opaque-identity '(1 2 3 . 4)))) (assert (not seq)) (assert (typep err 'type-error))))) @@ -299,7 +299,7 @@ (declare (simple-vector x)) (search x #(t t t) :key k)) ((#() nil) 0)) - (checked-compile-and-assert (:optimize :safe) + (checked-compile-and-assert (:optimize :safe :allow-warnings 'warning) `(lambda (x) (declare (simple-vector x)) (search x #(t t t) :start2 1 :end2 0 :end1 0)) @@ -534,3 +534,263 @@ `(lambda (x) (make-array 3 :element-type 'fixnum :initial-element x)) ((1) #(1 1 1) :test #'equalp)))) + + +(with-test (:name (search :type-derivation)) + (checked-compile-and-assert + () + `(lambda (s) + (search '(a) s :end1 nil)) + (('(b a)) 1) + ((#(1)) nil))) + +(with-test (:name :array-equalp-non-consing + :skipped-on :interpreter) + (let ((a (make-array 1000 :element-type 'double-float :initial-element 0d0)) + (b (make-array 1000 :element-type 'double-float :initial-element 0d0))) + (ctu:assert-no-consing (equalp a b)))) + +(with-test (:name (search :array-equalp-numerics)) + ;; This tests something that wasn't broken, but given that the new algorithm + ;; is potentially more complicated, it makes sense to test that various + ;; combinations of numeric arrays compare as equalp when they should. + (let (arrays (testdata '(7 3 1 5))) + (sb-int:dovector + (saetp (remove-if (lambda (x) + (not (typep (sb-vm:saetp-ctype x) 'sb-kernel:numeric-type))) + sb-vm:*specialized-array-element-type-properties*)) + (let ((et (sb-vm::saetp-specifier saetp))) + (unless (or (eq et 'bit) (equal et '(unsigned-byte 2))) + (let ((fancy-array + (make-array 4 :element-type et + :displaced-to (make-array 5 :element-type et) + :displaced-index-offset 1))) + (replace fancy-array + (mapcar (lambda (x) (coerce x et)) testdata)) + (push fancy-array arrays))))) + ;; All pairs should be EQUALP and it should be commutative + ;; and they should be EQUALP to a simple-vector. + (let* ((sv1 (coerce testdata 'simple-vector)) + (sv2 (map 'simple-vector (lambda (x) (coerce x 'single-float)) sv1)) + (sv3 (map 'simple-vector (lambda (x) (coerce x 'double-float)) sv1)) + (sv4 (map 'simple-vector (lambda (x) (coerce x '(complex single-float))) sv1)) + (sv5 (map 'simple-vector (lambda (x) (coerce x '(complex double-float))) sv1)) + (svs (list sv1 sv2 sv3 sv4 sv5))) + (dolist (x arrays) + ;; Try simple vectors containing types that are not EQL to the testdata + (dolist (sv svs) + (assert (equalp x sv)) + (assert (equalp sv x))) + ;; Try all other numeric array types + (dolist (y arrays) + (assert (equalp x y))))))) + +;; lp#1938598 +(with-test (:name :vector-replace-self) + ;; example 1 + (let ((string (make-array 0 :adjustable t :fill-pointer 0 :element-type 'character))) + (declare (notinline replace)) + (vector-push-extend #\_ string) + ;; also test it indirectly + (replace string string :start1 1 :start2 0)) + ;; example 2 + (let ((string (make-array 0 :adjustable t :fill-pointer 0 :element-type 'character))) + (declare (notinline replace)) + (loop for char across "tset" do (vector-push-extend char string)) + (replace string string :start2 1 :start1 2) + (assert (string= string "tsse")))) + +(with-test (:name :sort-vector-length-1 + :skipped-on :interpreter) + (let ((v (vector 5))) + (ctu:assert-no-consing (stable-sort v #'<)))) + +(with-test (:name (replace :empty-constant)) + (checked-compile-and-assert + () + `(lambda (v s) + (replace (the simple-vector v) #() :start1 s)) + ((#(1) 0) #(1) :test #'equalp))) + +(with-test (:name :reduce-type-derive) + (macrolet + ((check (fun expected) + `(assert + (equal (second + (third + (sb-kernel:%simple-fun-type + (checked-compile '(lambda (x) + ,fun))))) + ',expected)))) + (check (reduce '+ x) + t) + (check (reduce '+ x :end 10) + number) + (check (reduce '+ x :initial-value 10) + number) + (check (reduce '+ (the (simple-array t (1)) x)) + t) + (check (reduce '+ (the (simple-array t (2)) x)) + number) + (check (reduce '+ (the (simple-array t (10)) x) :end 1) + t) + (check (reduce '+ (the (simple-array fixnum (*)) x)) + integer) + (check (reduce '+ (the (simple-array (unsigned-byte 8) (*)) x)) + unsigned-byte) + (check (reduce '+ (the (simple-array (unsigned-byte 8) (*)) x) :initial-value -1) + integer) + (check (reduce '+ (the (simple-array double-float (*)) x) :initial-value 1) + (or double-float (integer 1 1))) + (check (reduce '+ (the (simple-array double-float (*)) x) :initial-value 1d0) + double-float) + (check (reduce '+ (the (simple-array double-float (*)) x)) + (or double-float (integer 0 0))) + (check (reduce '+ (the (simple-array double-float (10)) x)) + double-float) + (check (reduce '+ (the (simple-array double-float (1)) x)) + double-float) + (check (reduce '+ x :key #'length) + unsigned-byte) + (check (reduce '+ x :key #'length :initial-value -1) + integer))) + +(with-test (:name :find-type-derive) + (macrolet + ((check (fun expected) + `(assert + (equal (second + (third + (sb-kernel:%simple-fun-type + (checked-compile '(lambda (x y) + (declare (ignorable x y)) + ,fun))))) + ',expected)))) + (check (find x y) t) + (check (find 1 y) (or (integer 1 1) null)) + (check (find x y :key #'car) list) + (check (find x y :test #'=) (or number null)) + (check (find x y :key #'car :test #'=) list) + (check (find x (the vector y) :key #'car) list) + (check (find-if #'evenp y) (or integer null)) + (check (find-if #'evenp (the list y) :key #'car) list) + (check (find x (the (simple-array character (*)) y)) (or character null)) + (check (find x (the string y)) (or character null)))) + +(with-test (:name :position-type-derive) + (macrolet + ((check (fun expected) + `(assert + (ctype= (second + (third + (sb-kernel:%simple-fun-type + (checked-compile '(lambda (x y) + (declare (ignorable x y)) + ,fun))))) + ',expected)))) + (check (position x y) (or (integer 0 (#.(1- array-dimension-limit))) null)) + (check (position x (the (simple-string 10) y)) (or (mod 10) null)) + (check (position x y :end 10) (or (mod 10) null)) + (check (position x (the cons y) :start 5 :end 10) (or (integer 5 9) null)) + (check (position-if x y :end 10) (or (mod 10) null)))) + +(with-test (:name :string-cmp) + (macrolet + ((check (fun expected) + `(assert + (ctype= (second + (third + (sb-kernel:%simple-fun-type + (checked-compile '(lambda (x y) + (declare (ignorable x y)) + ,fun))))) + ',expected)))) + (check (string/= (the simple-string x) (the simple-string y) :end2 0) + (or (integer 0 0) null)))) + +(with-test (:name :reverse-specialized-arrays) + (loop for saetp across sb-vm:*specialized-array-element-type-properties* + for type = (sb-kernel:type-specifier (sb-vm:saetp-ctype saetp)) + when type + do + (let ((value-transformer (cond ((eq type #+sb-unicode 'base-char + #-sb-unicode 'character) + (lambda (x) + (code-char + (if (>= x sb-int:base-char-code-limit) + (random sb-int:base-char-code-limit) + x)))) + #+sb-unicode + ((eq type 'character) + (lambda (x) + (code-char x))) + ((eq type 'bit) + (lambda (x) + x + (random 2))) + ((subtypep type 'integer) + (if (eq type 'fixnum) + #'identity + (let* ((signed (eq (car type) 'signed-byte)) + (width (second type)) + (mod (expt 2 (- width + (if signed + 1 + 0))))) + (if (< mod 1300) + (lambda (x) + (if (>= x mod) + (random mod) + x)) + (lambda (x) + x))))) + (t + (lambda (x) + (coerce x type)))))) + (loop for i to (floor 1300 + (ceiling (sb-vm:saetp-n-bits saetp) sb-vm:n-word-bytes)) + for list = (loop for j from 1 to i + collect (funcall value-transformer j)) + for reverse = (reverse list) + for vector = (make-array i :element-type type + :initial-contents list) + do + (let* ((offset (1+ (random 120))) + (prefix (loop for j from 1 to offset + collect (funcall value-transformer j))) + (suffix (loop for j from 1 to (- 128 offset) + collect (funcall value-transformer j))) + (contents (concatenate 'list prefix list suffix)) + (source (make-array (+ i 128) :element-type type + :initial-contents contents)) + (displaced (make-array i :element-type type + :displaced-to source + :displaced-index-offset offset + :fill-pointer i))) + (assert (equal reverse (coerce (reverse displaced) 'list))) + (assert (equal reverse (coerce (nreverse displaced) 'list))) + (assert (equal prefix (coerce (subseq source 0 offset) 'list))) + (assert (equal suffix (coerce (subseq source (+ offset i)) 'list)))) + (assert (equal reverse (coerce (reverse vector) 'list))) + (assert (equal reverse (coerce (nreverse vector) 'list))))))) + +(with-test (:name :list-derived-type) + (macrolet + ((check (fun expected) + `(assert + (ctype= (second + (third + (sb-kernel:%simple-fun-type + (checked-compile '(lambda (x y) + (declare (ignorable x y)) + ,fun))))) + ',expected)))) + (check (sort (the (cons (eql 0)) x) y) + cons))) + +(with-test (:name :range-error-fill-transform) + (assert + (nth-value 2 (checked-compile `(lambda (x y) + (declare ((simple-base-string 10) x)) + (fill x y :start 12)) + :allow-warnings t)))) diff --git a/tests/session.impure.lisp b/tests/session.impure.lisp index b40152610c..76f8c4b5e8 100644 --- a/tests/session.impure.lisp +++ b/tests/session.impure.lisp @@ -11,7 +11,7 @@ ;;;; absoluely no warranty. See the COPYING and CREDITS files for ;;;; more information. -#-sb-thread (sb-ext:exit :code 104) +#-sb-thread (invoke-restart 'run-tests::skip-file) (setf sb-unix::*on-dangerous-wait* :error) @@ -28,6 +28,23 @@ (with-test (:name (:no-session-deadlock)) (make-join-thread (lambda () (sb-ext:gc)))) +(with-test (:name (:make-thread-while-holding-session-lock)) + (let ((thr1 nil) + (thr2 nil) + (sem1 (sb-thread:make-semaphore)) + (sem2 (sb-thread:make-semaphore))) + (sb-thread::with-session-lock (sb-thread::*session*) + (setq thr1 (sb-thread:make-thread + #'sb-thread:signal-semaphore :arguments sem1) + thr2 (sb-thread:make-thread + #'sb-thread:signal-semaphore :arguments sem2)) + ;; This used to hang right here because threads could not make progress + ;; in their lisp-side trampoline. + (sb-thread:wait-on-semaphore sem1) + (sb-thread:wait-on-semaphore sem2)) + (sb-thread:join-thread thr1) + (sb-thread:join-thread thr2))) + (with-test (:name (:debugger-no-hang-on-session-lock-if-interrupted) :broken-on :win32) (sb-debug::enable-debugger) diff --git a/tests/setf.impure.lisp b/tests/setf.pure.lisp similarity index 99% rename from tests/setf.impure.lisp rename to tests/setf.pure.lisp index 68222a8644..f17908b3fb 100644 --- a/tests/setf.impure.lisp +++ b/tests/setf.pure.lisp @@ -13,8 +13,6 @@ ;;;; absolutely no warranty. See the COPYING and CREDITS files for ;;;; more information. -(load "compiler-test-util.lisp") - (defvar *foo* nil) (defun (setf foo) (bar) (setf *foo* bar)) @@ -453,3 +451,10 @@ (list 'list a b store) b))) (assert (eql (funcall (compile nil `(lambda () (shiftf (shiftf-let*) 21)))) 11))) + +(locally + (declare (optimize (debug 0))) + (defsetf ffff (x) (y) `(list ,x ,y))) + +(with-test (:name :unknown-lambda-var-names) + (checked-compile '(lambda (x) (setf (ffff x) nil)))) diff --git a/tests/side-effectful-pathnames.test.sh b/tests/side-effectful-pathnames.test.sh index 2b1f89ef6e..fa4b659935 100644 --- a/tests/side-effectful-pathnames.test.sh +++ b/tests/side-effectful-pathnames.test.sh @@ -33,13 +33,27 @@ run_sbcl <<EOF (ignore-me (format t "untranslated=~S~%" untranslated)) (translation (namestring (translate-logical-pathname untranslated))) (expected-translation "$testdir/$testfilestem.lisp")) + (declare (ignore ignore-me)) (format t "translation=~S~%" translation) (format t "expected-translation=~S~%" expected-translation) (assert (string= translation expected-translation))) (format t "about to LOAD ~S~%" "TEST:$StudlyCapsStem") (load "TEST:$StudlyCapsStem") (assert (eq *loaded* :yes)) - (let ((compiled-file-name (namestring (compile-file "TEST:$StudlyCapsStem"))) + ;; COMPILE-FILE returns truenames unless SB-C::*MERGE-PATHNAMES* is set it NIL + ;; so that you don't see pathnames returned that are immediately useless + ;; on another machine, in which case we should just explicitly call TRUENAME + ;; to get the expected result for this test, which is of course meaningless, + ;; because my 'pwd' is here: + ;; /google/src/cloud/..somewhere...EA0643B31763702B4088D15FEA8C1700_1/google3/third_party/lisp/sbcl + ;; but it "wants" to see: + ;; /build/work/bb4efcf5cc6f5221b1a246e4fe09dd16eed5/google3/tmp/side-effectful-pathnames-test-4187/load-test.fasl" + ;; even though a different execution's might as well be here (or anywhere): + ;; /build/work/698d0e844a200a4c30cf75e6233b55b215ea/google3/runfiles/google3/third_party/lisp/sbcl/src/tests + ;; So is it better to have a kludged passing test, or a failing test? + ;; And is it better to change the test's expectation, or "force" a valid result? + ;; I don't know the answer to those questions, and I don't care. + (let ((compiled-file-name (namestring (truename (compile-file "TEST:$StudlyCapsStem")))) (expected-file-name "$testdir/$testfilestem.fasl")) (format t "compiled-file-name=~S~%" compiled-file-name) (format t "expected-file-name=~S~%" expected-file-name) diff --git a/tests/signals.impure.lisp b/tests/signals.impure.lisp index 5232538f3f..04ac7cb729 100644 --- a/tests/signals.impure.lisp +++ b/tests/signals.impure.lisp @@ -13,7 +13,9 @@ (use-package :test-util) -(with-test (:name (:async-unwind :specials)) +(sb-ext:finalize (list 1) (lambda ())) +(with-test (:name (:async-unwind :specials) + :skipped-on (:and :sb-safepoint :linux)) ; hangs (let ((*x0* nil) (*x1* nil) (*x2* nil) (*x3* nil) (*x4* nil)) (declare (special *x0* *x1* *x2* *x3* *x4*)) (loop repeat 10 do @@ -45,7 +47,8 @@ ;; (namely SLEEP) to produce known-good arguments, and ;; even if we wanted to check argument validity, ;; integration with `errno' is not to be expected. - :skipped-on :win32) + ;; And this hangs on darwin + safepoint. + :skipped-on (or :win32 (:and :darwin :sb-safepoint))) (let* (saved-errno (returning nil) (timer (make-timer (lambda () @@ -62,17 +65,28 @@ ;; we get EINTR. (loop until returning) (assert (= saved-errno (sb-unix::get-errno))))) + ;; It is desirable to support C-c on Windows, but SIGINT ;; is not the mechanism to use on this platform. -#-win32 +;; This test used to call kill_safely() in the C runtime if using safepoints, +;; and perhaps at some point kill_safely() interacted with the safepoint state +;; for POSIX (i.e. not win32), but it doesn't, at least not now. +;; The special case in kill_safely() for the current thread is pthread_kill() +;; and not a thing more, unless on win32, which skips this test. +;; Note also that RAISE sends a thread-directed signal as per the man page +;; "In a multithreaded program it is equivalent to pthread_kill(pthread_self(), sig);" +;; but thread-directed SIGINT is not the right thing, as it does not accurately +;; model the effect of pressing control-C; hence we should use UNIX-KILL here, +;; which sends a process-directed signal, letting the OS pick a thread. +;; Whether it picks the finalizer thread or main thread, things should work, +;; because we forward to the signal to our foreground thread. +#+unix (with-test (:name :handle-interactive-interrupt) (assert (eq :condition (handler-case (progn - (sb-thread::kill-safely - (sb-thread::thread-os-thread sb-thread::*current-thread*) - sb-unix:sigint) - #+sb-safepoint-strictly + (sb-unix:unix-kill (sb-unix:unix-getpid) sb-unix:sigint) + #+sb-safepoint ;; In this case, the signals handler gets invoked ;; indirectly through an INTERRUPT-THREAD. Give it ;; enough time to hit. @@ -95,3 +109,16 @@ (sb-ext:with-timeout 0.1 (sleep 1) t)))) (sb-ext:timeout () nil)))) + +#+unix +(with-test (:name :ignore-sigpipe) + (multiple-value-bind (read-side write-side) (sb-unix:unix-pipe) + (sb-unix:unix-close read-side) + (sb-sys:enable-interrupt sb-unix:sigpipe :ignore) + (let ((buffer "x")) + (sb-sys:with-pinned-objects (buffer) + (multiple-value-bind (nbytes errno) + (sb-unix:unix-write write-side buffer 0 1) + (assert (and (null nbytes) + (= errno sb-unix:epipe)))))) + (sb-unix:unix-close write-side))) diff --git a/tests/simd-pack-256.impure.lisp b/tests/simd-pack-256.pure.lisp similarity index 59% rename from tests/simd-pack-256.impure.lisp rename to tests/simd-pack-256.pure.lisp index 5fbc4fb46b..ef3794e24f 100644 --- a/tests/simd-pack-256.impure.lisp +++ b/tests/simd-pack-256.pure.lisp @@ -11,10 +11,11 @@ ;;;; absolutely no warranty. See the COPYING and CREDITS files for ;;;; more information. -#-sb-simd-pack-256 (exit :code 104) +#-sb-simd-pack-256 (invoke-restart 'run-tests::skip-file) (when (zerop (sb-alien:extern-alien "avx2_supported" int)) - (exit :code 104)) + (format t "~&INFO: simd-pack-256 not supported") + (invoke-restart 'run-tests::skip-file)) (defun make-constant-packs () (values (sb-ext:%make-simd-pack-256-ub64 1 2 3 4) @@ -89,21 +90,7 @@ (print-not-readable (assert-error (do-it) print-not-readable)) (t - (typecase pack - ((simd-pack-256 single-float) - (if (and *print-readably* - (some #'float-nan-p (multiple-value-list - (%simd-pack-256-singles pack)))) - (assert-error (do-it) print-not-readable) - (do-it))) - ((simd-pack-256 double-float) - (if (and *print-readably* - (some #'float-nan-p (multiple-value-list - (%simd-pack-256-doubles pack)))) - (assert-error (do-it) print-not-readable) - (do-it))) - (t - (do-it))))))))) + (do-it))))))) ;; Default (print-them t) ;; Readably @@ -130,7 +117,7 @@ (setq tmp-fasl (compile-file *tmp-filename*)) (let ((*pack* nil)) (load tmp-fasl) - (assert (typep *pack* '(sb-ext:simd-pack-256 integer))) + (assert (typep *pack* '(sb-ext:simd-pack-256 (unsigned-byte 64)))) (assert (= 2 (sb-kernel:%simd-pack-256-0 *pack*))) (assert (= 4 (sb-kernel:%simd-pack-256-1 *pack*))) (assert (= 8 (sb-kernel:%simd-pack-256-2 *pack*))) @@ -173,3 +160,72 @@ '(1d0 2d0 3d0 4d0))))) (when tmp-fasl (delete-file tmp-fasl)) (delete-file *tmp-filename*)))) + + +(with-test (:name :spilling) + (checked-compile-and-assert + () + `(lambda (x y) + (declare ((sb-ext:simd-pack-256 (unsigned-byte 64)) x)) + (eval y) + (list (sb-kernel:%simd-pack-256-0 x) + (sb-kernel:%simd-pack-256-1 x) + (sb-kernel:%simd-pack-256-2 x) + (sb-kernel:%simd-pack-256-3 x) y)) + (((sb-ext:%make-simd-pack-256-ub64 1 2 3 4) 0) '(1 2 3 4 0) :test #'equal))) + +(with-test (:name (simd-pack-256 subtypep :smoke)) + (assert-tri-eq t t (subtypep '(simd-pack-256 (unsigned-byte 8)) 'simd-pack-256)) + (assert-tri-eq t t (subtypep '(simd-pack-256 (unsigned-byte 16)) 'simd-pack-256)) + (assert-tri-eq t t (subtypep '(simd-pack-256 (unsigned-byte 32)) 'simd-pack-256)) + (assert-tri-eq t t (subtypep '(simd-pack-256 (unsigned-byte 64)) 'simd-pack-256)) + (assert-tri-eq t t (subtypep '(simd-pack-256 (signed-byte 8)) 'simd-pack-256)) + (assert-tri-eq t t (subtypep '(simd-pack-256 (signed-byte 16)) 'simd-pack-256)) + (assert-tri-eq t t (subtypep '(simd-pack-256 (signed-byte 32)) 'simd-pack-256)) + (assert-tri-eq t t (subtypep '(simd-pack-256 (signed-byte 64)) 'simd-pack-256)) + (assert-tri-eq t t (subtypep '(simd-pack-256 single-float) 'simd-pack-256)) + (assert-tri-eq t t (subtypep '(simd-pack-256 double-float) 'simd-pack-256)) + (assert-tri-eq nil t (subtypep 'simd-pack-256 '(simd-pack-256 (unsigned-byte 64)))) + (assert-tri-eq nil t (subtypep 'simd-pack-256 '(simd-pack-256 single-float))) + (assert-tri-eq nil t (subtypep 'simd-pack-256 '(simd-pack-256 double-float))) + (assert-tri-eq t t (subtypep '(simd-pack-256 (unsigned-byte 64)) + '(or (simd-pack-256 (unsigned-byte 64)) (simd-pack-256 single-float)))) + (assert-tri-eq t t (subtypep '(simd-pack-256 (unsigned-byte 64)) + '(or (simd-pack-256 (unsigned-byte 64)) (simd-pack-256 double-float)))) + (assert-tri-eq nil t (subtypep '(simd-pack-256 (unsigned-byte 64)) + '(or (simd-pack-256 single-float) (simd-pack-256 double-float)))) + (assert-tri-eq nil t (subtypep '(or (simd-pack-256 (unsigned-byte 64)) (simd-pack-256 single-float)) + '(simd-pack-256 (unsigned-byte 64)))) + (assert-tri-eq nil t (subtypep '(or (simd-pack-256 (unsigned-byte 64)) (simd-pack-256 double-float)) + '(simd-pack-256 (unsigned-byte 64)))) + (assert-tri-eq nil t (subtypep '(or (simd-pack-256 single-float) (simd-pack-256 double-float)) + '(simd-pack-256 (unsigned-byte 64))))) + +(with-test (:name (simd-pack-256 :ctype-unparse :smoke)) + (flet ((unparsed (s) (sb-kernel:type-specifier (sb-kernel:specifier-type s)))) + (assert (equal (unparsed 'simd-pack-256) 'simd-pack-256)) + (assert (equal (unparsed '(simd-pack-256 (unsigned-byte 8))) '(simd-pack-256 (unsigned-byte 8)))) + (assert (equal (unparsed '(simd-pack-256 (unsigned-byte 16))) '(simd-pack-256 (unsigned-byte 16)))) + (assert (equal (unparsed '(simd-pack-256 (unsigned-byte 32))) '(simd-pack-256 (unsigned-byte 32)))) + (assert (equal (unparsed '(simd-pack-256 (unsigned-byte 64))) '(simd-pack-256 (unsigned-byte 64)))) + (assert (equal (unparsed '(simd-pack-256 (signed-byte 8))) '(simd-pack-256 (signed-byte 8)))) + (assert (equal (unparsed '(simd-pack-256 (signed-byte 16))) '(simd-pack-256 (signed-byte 16)))) + (assert (equal (unparsed '(simd-pack-256 (signed-byte 32))) '(simd-pack-256 (signed-byte 32)))) + (assert (equal (unparsed '(simd-pack-256 (signed-byte 64))) '(simd-pack-256 (signed-byte 64)))) + (assert (equal (unparsed '(simd-pack-256 single-float)) '(simd-pack-256 single-float))) + (assert (equal (unparsed '(simd-pack-256 double-float)) '(simd-pack-256 double-float))) + (assert (equal (unparsed '(or (simd-pack-256 (unsigned-byte 64)) (simd-pack-256 double-float))) + ;; depends on *SIMD-PACK-ELEMENT-TYPES* order + '(or (simd-pack-256 double-float) (simd-pack-256 (unsigned-byte 64))))) + (assert (equal (unparsed '(or + (simd-pack-256 (unsigned-byte 8)) + (simd-pack-256 (unsigned-byte 16)) + (simd-pack-256 (unsigned-byte 32)) + (simd-pack-256 (unsigned-byte 64)) + (simd-pack-256 (signed-byte 8)) + (simd-pack-256 (signed-byte 16)) + (simd-pack-256 (signed-byte 32)) + (simd-pack-256 (signed-byte 64)) + (simd-pack-256 single-float) + (simd-pack-256 double-float))) + 'simd-pack-256)))) diff --git a/tests/simd-pack.impure.lisp b/tests/simd-pack.pure.lisp similarity index 58% rename from tests/simd-pack.impure.lisp rename to tests/simd-pack.pure.lisp index e4b320a95d..f2537899ae 100644 --- a/tests/simd-pack.impure.lisp +++ b/tests/simd-pack.pure.lisp @@ -11,7 +11,7 @@ ;;;; absolutely no warranty. See the COPYING and CREDITS files for ;;;; more information. -#-sb-simd-pack (exit :code 104) +#-sb-simd-pack (invoke-restart 'run-tests::skip-file) (defun make-constant-packs () (values (sb-kernel:%make-simd-pack-ub64 1 2) (sb-kernel:%make-simd-pack-ub32 0 0 0 0) @@ -70,21 +70,7 @@ (print-not-readable (assert-error (do-it) print-not-readable)) (t - (typecase pack - ((simd-pack single-float) - (if (and *print-readably* - (some #'float-nan-p (multiple-value-list - (%simd-pack-singles pack)))) - (assert-error (do-it) print-not-readable) - (do-it))) - ((simd-pack double-float) - (if (and *print-readably* - (some #'float-nan-p (multiple-value-list - (%simd-pack-doubles pack)))) - (assert-error (do-it) print-not-readable) - (do-it))) - (t - (do-it))))))))) + (do-it))))))) ;; Default (print-them t) ;; Readably @@ -111,7 +97,7 @@ (setq tmp-fasl (compile-file *tmp-filename*)) (let ((*pack* nil)) (load tmp-fasl) - (assert (typep *pack* '(sb-kernel:simd-pack integer))) + (assert (typep *pack* '(sb-kernel:simd-pack (unsigned-byte 64)))) (assert (= 2 (sb-kernel:%simd-pack-low *pack*))) (assert (= 4 (sb-kernel:%simd-pack-high *pack*))))) (when tmp-fasl (delete-file tmp-fasl)) @@ -152,3 +138,59 @@ '(1d0 2d0))))) (when tmp-fasl (delete-file tmp-fasl)) (delete-file *tmp-filename*)))) + +(with-test (:name (simd-pack subtypep :smoke)) + (assert-tri-eq t t (subtypep '(simd-pack (unsigned-byte 8)) 'simd-pack)) + (assert-tri-eq t t (subtypep '(simd-pack (unsigned-byte 16)) 'simd-pack)) + (assert-tri-eq t t (subtypep '(simd-pack (unsigned-byte 32)) 'simd-pack)) + (assert-tri-eq t t (subtypep '(simd-pack (unsigned-byte 64)) 'simd-pack)) + (assert-tri-eq t t (subtypep '(simd-pack (signed-byte 8)) 'simd-pack)) + (assert-tri-eq t t (subtypep '(simd-pack (signed-byte 16)) 'simd-pack)) + (assert-tri-eq t t (subtypep '(simd-pack (signed-byte 32)) 'simd-pack)) + (assert-tri-eq t t (subtypep '(simd-pack (signed-byte 64)) 'simd-pack)) + (assert-tri-eq t t (subtypep '(simd-pack single-float) 'simd-pack)) + (assert-tri-eq t t (subtypep '(simd-pack double-float) 'simd-pack)) + (assert-tri-eq nil t (subtypep 'simd-pack '(simd-pack (unsigned-byte 64)))) + (assert-tri-eq nil t (subtypep 'simd-pack '(simd-pack single-float))) + (assert-tri-eq nil t (subtypep 'simd-pack '(simd-pack double-float))) + (assert-tri-eq t t (subtypep '(simd-pack (unsigned-byte 64)) + '(or (simd-pack (unsigned-byte 64)) (simd-pack single-float)))) + (assert-tri-eq t t (subtypep '(simd-pack (unsigned-byte 64)) + '(or (simd-pack (unsigned-byte 64)) (simd-pack double-float)))) + (assert-tri-eq nil t (subtypep '(simd-pack (unsigned-byte 64)) + '(or (simd-pack single-float) (simd-pack double-float)))) + (assert-tri-eq nil t (subtypep '(or (simd-pack (unsigned-byte 64)) (simd-pack single-float)) + '(simd-pack (unsigned-byte 64)))) + (assert-tri-eq nil t (subtypep '(or (simd-pack (unsigned-byte 64)) (simd-pack double-float)) + '(simd-pack (unsigned-byte 64)))) + (assert-tri-eq nil t (subtypep '(or (simd-pack single-float) (simd-pack double-float)) + '(simd-pack (unsigned-byte 64))))) + +(with-test (:name (simd-pack :ctype-unparse :smoke)) + (flet ((unparsed (s) (sb-kernel:type-specifier (sb-kernel:specifier-type s)))) + (assert (equal (unparsed 'simd-pack) 'simd-pack)) + (assert (equal (unparsed '(simd-pack (unsigned-byte 8))) '(simd-pack (unsigned-byte 8)))) + (assert (equal (unparsed '(simd-pack (unsigned-byte 16))) '(simd-pack (unsigned-byte 16)))) + (assert (equal (unparsed '(simd-pack (unsigned-byte 32))) '(simd-pack (unsigned-byte 32)))) + (assert (equal (unparsed '(simd-pack (unsigned-byte 64))) '(simd-pack (unsigned-byte 64)))) + (assert (equal (unparsed '(simd-pack (signed-byte 8))) '(simd-pack (signed-byte 8)))) + (assert (equal (unparsed '(simd-pack (signed-byte 16))) '(simd-pack (signed-byte 16)))) + (assert (equal (unparsed '(simd-pack (signed-byte 32))) '(simd-pack (signed-byte 32)))) + (assert (equal (unparsed '(simd-pack (signed-byte 64))) '(simd-pack (signed-byte 64)))) + (assert (equal (unparsed '(simd-pack single-float)) '(simd-pack single-float))) + (assert (equal (unparsed '(simd-pack double-float)) '(simd-pack double-float))) + (assert (equal (unparsed '(or (simd-pack (unsigned-byte 64)) (simd-pack double-float))) + ;; depends on *SIMD-PACK-ELEMENT-TYPES* order + '(or (simd-pack double-float) (simd-pack (unsigned-byte 64))))) + (assert (equal (unparsed '(or + (simd-pack (unsigned-byte 8)) + (simd-pack (unsigned-byte 16)) + (simd-pack (unsigned-byte 32)) + (simd-pack (unsigned-byte 64)) + (simd-pack (signed-byte 8)) + (simd-pack (signed-byte 16)) + (simd-pack (signed-byte 32)) + (simd-pack (signed-byte 64)) + (simd-pack single-float) + (simd-pack double-float))) + 'simd-pack)))) diff --git a/tests/specializer.impure.lisp b/tests/specializer.impure.lisp index 06d6f91f14..7dde7e4fc9 100644 --- a/tests/specializer.impure.lisp +++ b/tests/specializer.impure.lisp @@ -24,7 +24,7 @@ ;;; Can be parsed but fails to define a method on ;;; SPECIALIZER-TYPE-SPECIFIER. -(defclass custom-2-impl (sb-pcl:specializer) +(defclass custom-2-impl (sb-mop:specializer) ()) (defmethod sb-pcl:parse-specializer-using-class ((generic-function standard-generic-function) @@ -36,7 +36,7 @@ ;;; Can be parsed and has a suitable method on ;;; SPECIALIZER-TYPE-SPECIFIER. -(defclass custom-3-impl (sb-pcl:specializer) +(defclass custom-3-impl (sb-mop:specializer) ()) (defmethod sb-pcl:parse-specializer-using-class ((generic-function standard-generic-function) @@ -51,7 +51,7 @@ ;;; Test (with-test (:name (sb-pcl:parse-specializer-using-class :smoke)) - (let ((proto-gf (sb-pcl:class-prototype + (let ((proto-gf (sb-mop:class-prototype (find-class 'standard-generic-function)))) (flet ((test (specializer-name expected) (flet ((do-it () @@ -106,9 +106,9 @@ (test `(eql t) (sb-mop:intern-eql-specializer t))))) (with-test (:name (sb-pcl:specializer-type-specifier :smoke)) - (let* ((proto-gf (sb-pcl:class-prototype + (let* ((proto-gf (sb-mop:class-prototype (find-class 'standard-generic-function))) - (proto-method (sb-pcl:class-prototype + (proto-method (sb-mop:class-prototype (find-class 'standard-method)))) (flet ((parse (specializer-specifier) (sb-pcl:parse-specializer-using-class diff --git a/tests/static-alloc.impure.lisp b/tests/static-alloc.impure.lisp index a2098ab8bc..f4d03cff1b 100644 --- a/tests/static-alloc.impure.lisp +++ b/tests/static-alloc.impure.lisp @@ -12,3 +12,16 @@ saps (mapcar #'sb-sys:vector-sap vectors))))) +;;; Compute the physical size of some vectors and make sure it's right. +;;; Why, you might ask, can't this simply use SB-VM::PRIMITIVE-OBJECT-SIZE +;;; to compare against the size of a non-static vector? +;;; Because PRIMITIVE-OBJECT-SIZE always gives you the _CORRECT_ answer +;;; for the object, not the amount of space the allocator took, +;;; and this test needs to assert correctness of the allocator. +(dolist (type '(base-char character)) + (loop for i from 1 to 20 + do (let* ((before sb-vm:*static-space-free-pointer*) + (obj (sb-vm::make-static-vector i :element-type type)) + (after sb-vm:*static-space-free-pointer*) + (used (sb-sys:sap- after before))) + (assert (= used (sb-vm::primitive-object-size obj)))))) diff --git a/tests/static-garbage.impure.lisp b/tests/static-garbage.impure.lisp new file mode 100644 index 0000000000..6f11147742 --- /dev/null +++ b/tests/static-garbage.impure.lisp @@ -0,0 +1,10 @@ +;;; Ideally we want to assert that there are no pseudostatic unreachable objects +;;; at all, but that's not simple to do from lisp. +;;; Perform this by itself to remain unaffected by anything else. +#-cheneygc +(with-test (:name :pseudostatic-garbage :skipped-on (:not :sb-thread)) + (flet ((check-not-static (list) + (dolist (x list) + (assert (< (sb-kernel:generation-of x) sb-vm:+pseudo-static-generation+))))) + (check-not-static (sb-vm:list-allocated-objects :all :test #'sb-thread::thread-p)) + (check-not-static (sb-vm:list-allocated-objects :all :test #'sb-thread::semaphore-p)))) diff --git a/tests/static-linker.impure.lisp b/tests/static-linker.impure.lisp new file mode 100644 index 0000000000..3ef5f3a866 --- /dev/null +++ b/tests/static-linker.impure.lisp @@ -0,0 +1,45 @@ +(defun f1 (x) `(invoked-on ,x)) +(compile 'f1) +(setf (symbol-function 'f2) (symbol-function 'f1)) +(defun g (arg) + (case arg + (1 (f1 arg)) + (2 (f2 arg)) + (3 (f1 #'f1)))) +#+immobile-code (sb-vm::statically-link-core) + +(with-test (:name :static-linker-glitch) + (assert (equal (g 3) `(invoked-on ,#'f1)))) + +#+nil ; This fails because ambigous references are not patched any more +(with-test (:name :static-unlinker) + (let ((sb-c::*compile-to-memory-space* :immobile)) + (declare (muffle-conditions style-warning)) + (flet ((disassembly-lines (name) + (split-string + (with-output-to-string (s) + (let ((sb-disassem:*disassem-location-column-width* 0)) + (disassemble name :stream s))) + #\newline)) + (expect (match lines) + (assert (loop for line in lines + thereis (search match line))))) + (compile 'h '(lambda (x) (1+ x))) + (setf (symbol-function 'g) #'h (symbol-function 'f) #'h) + (compile 'c '(lambda (x) (g x))) + (compile 'd '(lambda (x) (f (g x)))) + ;; The FDEFN-FUN of F is same as that of G. + ;; Statically linking D should not patch the fdefn calls into static calls + ;; because it can't unambiguously be undone without storing additional data + ;; about where patches were performed to begin with. + (sb-vm::statically-link-core :callers '(c d)) + (let ((lines (disassembly-lines 'c))) + (expect "#<FUNCTION H>" lines)) + (let ((lines (disassembly-lines 'd))) + (expect "#<FUNCTION H>" lines)) + (setf (symbol-function 'g) #'+) + (let ((lines (disassembly-lines 'c))) + (expect "#<FDEFN G>" lines)) + (let ((lines (disassembly-lines 'd))) + (expect "#<FDEFN G>" lines) + (expect "#<FUNCTION H>" lines))))) diff --git a/tests/step.impure.lisp b/tests/step.pure.lisp similarity index 98% rename from tests/step.impure.lisp rename to tests/step.pure.lisp index c08dbb19b9..bca9917797 100644 --- a/tests/step.impure.lisp +++ b/tests/step.pure.lisp @@ -11,12 +11,8 @@ ;;;; absolutely no warranty. See the COPYING and CREDITS files for ;;;; more information. -(in-package :cl-user) - -#+interpreter (sb-ext:exit :code 104) ;; No stepper support on some platforms. -#-(or x86 x86-64 ppc sparc mips arm arm64) -(sb-ext:exit :code 104) +#+(or interpreter riscv) (invoke-restart 'run-tests::skip-file) ;; These tests should either with code in dynamic space ;; or immobile space, but they only accidentally worked diff --git a/tests/stream.impure.lisp b/tests/stream.impure.lisp index 17ca18201d..2e869e4561 100644 --- a/tests/stream.impure.lisp +++ b/tests/stream.impure.lisp @@ -23,7 +23,7 @@ #P"/tmp/"))) (require :sb-posix) -;;; Believe it or not the x86-64-specific trap routine for UPDATE-OBJECT-LAYOUT-OR-INVALID +;;; Believe it or not the x86-64-specific trap routine for UPDATE-OBJECT-LAYOUT ;;; could fail to return the correct layout after calling from assembly code into lisp, ;;; back to assembly code, back to the vop, and not a single regression test failed. (defclass astream (fundamental-output-stream) ()) @@ -31,16 +31,16 @@ (assert (streamp *str*)) (defclass astream (fundamental-output-stream) (x y)) (with-test (:name :update-stream-layout) - (assert (sb-kernel:layout-invalid (sb-kernel:%instance-layout *str*))) + (assert (sb-kernel:wrapper-invalid (sb-kernel:%instance-wrapper *str*))) (assert (streamp *str*)) - (assert (/= 0 (sb-kernel:layout-clos-hash (sb-kernel:%instance-layout *str*)))) + (assert (/= 0 (sb-kernel:wrapper-clos-hash (sb-kernel:%instance-wrapper *str*)))) (defclass astream () (x y)) - (assert (sb-kernel:layout-invalid (sb-kernel:%instance-layout *str*))) - (assert (= 0 (sb-kernel:layout-clos-hash (sb-kernel:%instance-layout *str*)))) + (assert (sb-kernel:wrapper-invalid (sb-kernel:%instance-wrapper *str*))) + (assert (= 0 (sb-kernel:wrapper-clos-hash (sb-kernel:%instance-wrapper *str*)))) (assert (not (streamp *str*))) - (assert (/= 0 (sb-kernel:layout-clos-hash (sb-kernel:%instance-layout *str*)))) + (assert (/= 0 (sb-kernel:wrapper-clos-hash (sb-kernel:%instance-wrapper *str*)))) (defclass astream (fundamental-output-stream) (x y)) - (assert (sb-kernel:layout-invalid (sb-kernel:%instance-layout *str*))) + (assert (sb-kernel:wrapper-invalid (sb-kernel:%instance-wrapper *str*))) (assert (streamp *str*))) ;;; type errors for inappropriate stream arguments, fixed in @@ -369,7 +369,7 @@ ;;; or slow paths are being taken for each element type. See the ;;; READ-SEQUENCE tests above for more information. ;;; -;;; (trace sb-impl::output-unsigned-byte-full-buffered sb-impl::output-signed-byte-full-buffered sb-impl::output-raw-bytes) +;;; (trace sb-impl::output-unsigned-byte-full-buffered sb-impl::output-signed-byte-full-buffered) (with-test (:name (write-sequence type-error)) (let ((pathname (scratch-file-name)) @@ -670,7 +670,8 @@ (assert (< (- (get-universal-time) time) 2))))) #-win32 -(with-test (:name (open :interrupt) :skipped-on :win32) +(with-test (:name (open :interrupt) + :skipped-on (or :win32 (:and :darwin :sb-safepoint))) (let ((to 0)) (with-scratch-file (fifo) ;; Make a FIFO @@ -853,4 +854,20 @@ (sb-impl::ansi-stream-read-string-from-frc-buffer string s 0 nil))) (assert (= endpos 0))))) -;;; success +(with-test (:name :named-pipe-wait-eof) + (let* ((process (run-program "cat" '() :search t + :wait nil :input nil :output :stream)) + (out (process-output process))) + (sb-sys:wait-until-fd-usable (sb-sys:fd-stream-fd out) :input) + (assert (null (read-byte (process-output process) nil nil))) + (process-close process))) + +(with-test (:name :concatenated-stream-listen) + (let ((file (scratch-file-name))) + (with-open-file (stream file :direction :output :if-exists :supersede) + (write-line "abc" stream)) + (with-open-file (stream file) + (let ((cs (make-concatenated-stream stream))) + (read-char-no-hang cs) + (assert (listen cs)))) + (delete-file file))) diff --git a/tests/stream.pure.lisp b/tests/stream.pure.lisp index 9bfb54282d..02af51d5ba 100644 --- a/tests/stream.pure.lisp +++ b/tests/stream.pure.lisp @@ -136,6 +136,11 @@ ;;; Ideas? #+nil (assert (eq (interactive-stream-p *terminal-io*) t)) +;;; FILE-POSITION should not accept NIL +(with-test (:name :file-position-smoke-test) + (let ((s (make-broadcast-stream))) + (assert-error (file-position s (opaque-identity nil)) type-error))) + ;;; MAKE-STRING-INPUT-STREAM ;;; ;;; * Observe FILE-POSITION :START and :END, and allow setting of @@ -275,38 +280,25 @@ ;;; MAKE-STRING-OUTPUT-STREAM and WITH-OUTPUT-TO-STRING take an ;;; :ELEMENT-TYPE keyword argument (with-test (:name (make-string-output-stream with-output-to-string :element-type)) - (macrolet ((frob (element-type-form) + (macrolet ((frob (element-type-form expect &optional (expect2 expect)) `(progn (let ((s (with-output-to-string (s nil ,@(when element-type-form `(:element-type ,element-type-form)))))) - (assert (typep s '(simple-array ,(if element-type-form - (eval element-type-form) - 'character) - (0))))) - (get-output-stream-string - (make-string-output-stream - ,@(when element-type-form - `(:element-type ,element-type-form))))))) + (assert (typep s '(simple-array ,expect (0))))) + (let ((s (get-output-stream-string + (make-string-output-stream + ,@(when element-type-form + `(:element-type ,element-type-form)))))) + (assert (typep s '(simple-array ,expect2 (0)))))))) ;; If you pass NIL as element-type, note that there seems to be no requirement ;; to produce a stream that can *accept* only characters of that type. - ;; We produce a BASE-STRING-OUTPUT-STREAM if you do something so pointless, - ;; and accept base characters written to that stream. - ;; However, we'll always return a (simple-array nil (0)) from such stream. - ;; For comparison - - ;; CCL: (type-of (get-output-stream-string (make-string-output-stream :element-type nil))) - ;; => (SIMPLE-BASE-STRING 0) - ;; ABCL: - ;; (let ((s (make-string-output-stream :element-type nil))) - ;; (write-string "Hi" s) - ;; (get-output-stream-string s)) => "" - ;; CLISP is more pedantic, refusing to accept characters and returning a NIL vector: - ;; (type-of (get-output-stream-string (make-string-output-stream :element-type nil))) - ;; => (VECTOR NIL 0) - (frob nil) - (frob 'character) - (frob 'base-char) - (frob 'nil))) + ;; We produce a CHARACTER-STRING-OUTPUT-STREAM if you do something so pointless. + (frob nil character) + (frob 'character character) + (frob 'base-char base-char) + ;; I literally do not care why these results differ. + (frob 'nil base-char character))) (with-test (:name (make-string-output-stream :element-type :bogosity)) (assert-error (make-string-output-stream :element-type 'real))) @@ -372,7 +364,7 @@ ;;; immediately be completely filled for normal files, and that the ;;; buffer-fill routine is responsible for figuring out when we've ;;; reached EOF. -(with-test (:name (stream :listen-vs-select) :fails-on :win32) +(with-test (:name (stream :listen-vs-select)) (let ((listen-testfile-name (scratch-file-name)) ;; If non-NIL, size (in bytes) of the file that will exercise ;; the LISTEN problem. @@ -472,7 +464,7 @@ #+sb-unicode (with-test (:name (:default-char-stream-resets)) - (let ((s (sb-impl::%make-default-string-ostream))) + (sb-impl::%with-output-to-string (s) (dotimes (i 2) (write-char (code-char 1000) s) (assert (equal (type-of (get-output-stream-string s)) @@ -482,6 +474,10 @@ (assert (equal (type-of (get-output-stream-string s)) '(simple-base-string 1)))))) +(with-test (:name :with-input-from-string-nowarn) + (checked-compile '(lambda () + (with-input-from-string (s "muffin"))))) + (with-test (:name :with-input-from-string-declarations) (checked-compile-and-assert () @@ -490,3 +486,28 @@ (declare (optimize safety)) (read-char x))) (("a") #\a))) + +(defun input-from-dynamic-extent-stream () + (handler-case (with-input-from-string (stream "#w") (read stream nil nil)) + (error (condition) + (format nil "~A" condition)))) +(compile 'input-from-dynamic-extent-stream) +(with-test (:name :with-input-from-string-signal-stream-error) + (assert (search "unavailable" (input-from-dynamic-extent-stream)))) + +(with-test (:name :closeable-broadcast-stream) + (let ((b (make-broadcast-stream))) + (close b) + (assert (not (open-stream-p b))) + (assert-error (write-string "test" b)))) + +(defvar *some-stream*) +(with-test (:name :closeable-synonym-stream) + (let ((*some-stream* (make-string-input-stream "hola"))) + (let ((syn (make-synonym-stream '*some-stream*))) + (assert (eql (read-char syn) #\h)) + (close syn) + (assert (not (open-stream-p syn))) + (assert-error (read-char syn)) + (close syn) ; no error + (assert (eql (read-char *some-stream*) #\o))))) diff --git a/tests/string.pure.lisp b/tests/string.pure.lisp index 849f3241ac..a0109a0ab7 100644 --- a/tests/string.pure.lisp +++ b/tests/string.pure.lisp @@ -48,34 +48,76 @@ (nstring-capitalize nstring) (assert (string= nstring "Cat")))) -;;; (VECTOR NIL)s are strings. Tests for that and issues uncovered in -;;; the process. +#| +(VECTOR NIL)s are strings only if you believe that the definition involving union +types prevails over the ample amount of exposition in the spec, as well as utility +of the resulting strings, and common sense. + +I tested 9 other implementations, and 7 of them agree that: + (SUBTYPEP '(SIMPLE-ARRAY NIL (*)) 'STRING) => NIL and T + +They have differing behaviors as to effect of make-string and make-array as follows: + +Allegro (10.1 Free Express Edition): + (SIMPLE-ARRAY NIL (*)) exists but does not satisfy STRINGP + (make-string 1 :element-type NIL) returns a (SIMPLE-ARRAY CHARACTER (1)) + +Clasp (built from git rev 6b8047c2 @ 2020-10-22): + (make-array 1 :element-type NIL) signals error + (make-string 1 :element-type NIL) returns a (SIMPLE-ARRAY CHARACTER (1)) + +Clozure (v1.12): + (make-array 1 :element-type NIL) returns (SIMPLE-VECTOR 1) + (make-string 1 :element-type NIL) returns a (SIMPLE-BASE-STRING 1) + +CMUCL (version 20d Unicode): + (make-array 1 :element-type nil) returns (SIMPLE-BASE-STRING 1) + as does MAKE-STRING. + +ECL (version 20.4.24): + (make-array 1 :element-type NIL) says + "ECL does not support arrays with element type NIL" + (make-string 1 :element-type NIL) returns a (SIMPLE-ARRAY BASE-CHAR (1)) + +GCL (version 2.6.12 CLtL1): + (type-of (make-array 1 :element-type nil)) => VECTOR + (array-element-type (make-string 1 :element-type nil)) => STRING-CHAR + +MKCL (version 1.1.11): + (make-array 1 :element-type NIL) returns a (VECTOR NIL 1) + (make-string 1 :element-type NIL) returns a (SIMPLE-BASE-STRING 1) + +Of the dissenters, they return T and T from the subtypep expression above +though their behavioral differences from MAKE-ARRAY to MAKE-STRING +present compelling evidence that at least in their API they disfavor considering +an object a string if it has element type NIL, hence MAKE-STRING upgrades NIL +to a nonempty type. +ABCL (version 1.7.1): + (type-of (make-array 1 :element-type nil)) => (NIL-VECTOR 1) + (type-of (make-string 1 :element-type nil)) => (SIMPLE-BASE-STRING 1) + Also: (make-string 1 :element-type 'ratio) => "^@" ; the type is just ignored +CLISP (version 2.49.92): + (type-of (make-array 1 :element-type nil)) => (SIMPLE-ARRAY NIL (1)) + (type-of (make-string 1 :element-type nil)) => (SIMPLE-BASE-STRING 1) + +And one more Lisp implementation which matches none of the above- +Lispworks personal edition 7.1: + (make-array 1 :element-type nil) signals + ERROR: (ARRAY NIL) is an illegal type specifier. + (make-string 1 :element-type nil) signals + ERROR: (ARRAY NIL) is an illegal type specifier. + (subtypep '(vector nil) 'string) signals + ERROR: (ARRAY NIL (*)) is an illegal type specifier. + +Hence (SIMPLE-ARRAY NIL (*)) is most plausibly not regarded as a string, +the ANSI compliance test suite notwithstanding. +And the range of implementation choices suggest that users can not reasonably +claim that any particular result from these edge cases constitutes a bug. +|# (with-test (:name (vector nil)) - (assert (typep (make-array 1 :element-type nil) 'string)) - (assert (not (typep (make-array 2 :element-type nil) 'base-string))) - (assert (typep (make-string 3 :element-type nil) 'simple-string)) - (assert (not (typep (make-string 4 :element-type nil) 'simple-base-string))) - - (assert (subtypep (class-of (make-array 1 :element-type nil)) - (find-class 'string))) - (assert (subtypep (class-of (make-array 2 :element-type nil :fill-pointer 1)) - (find-class 'string))) - - (assert (string= "" (make-array 0 :element-type nil))) - (assert (string/= "a" (make-array 0 :element-type nil))) - (assert (string= "" (make-array 5 :element-type nil :fill-pointer 0))) - - (assert (= (sxhash "") - (sxhash (make-array 0 :element-type nil)) - (sxhash (make-array 5 :element-type nil :fill-pointer 0)) - (sxhash (make-string 0 :element-type nil)))) - (assert (subtypep (type-of (make-array 2 :element-type nil)) 'simple-string)) - (assert (subtypep (type-of (make-array 4 :element-type nil :fill-pointer t)) - 'string)) - - (assert (eq (intern "") (intern (make-array 0 :element-type nil)))) - (assert (eq (intern "") - (intern (make-array 5 :element-type nil :fill-pointer 0))))) + (assert (not (stringp (make-array 0 :element-type nil)))) + (assert (not (subtypep (class-of (make-array 1 :element-type nil)) + (find-class 'string))))) (with-test (:name (make-string :element-type t type-error)) (multiple-value-bind (fun failure-p warnings) @@ -83,7 +125,11 @@ :allow-failure t :allow-warnings t) (assert failure-p) (assert (= 1 (length warnings))) - (assert-error (funcall fun) type-error))) + ;; It's not clear why this function should be expected to return a TYPE-ERROR. + ;; There is no object created which is of the wrong type, + ;; and the type of the legal value of ELEMENT-TYPE isn't really in question + ;; nor is the best way to describe what you can't pass. + (assert-error (funcall fun) #|type-error|#))) ;; MISC.574 (with-test (:name (string<= base-string :optimized)) @@ -159,8 +205,11 @@ (with-test (:name :nil-vector-access) (let ((nil-vector (make-array 10 :element-type nil))) - (assert-error (write-to-string nil-vector) - sb-kernel:nil-array-accessed-error) + ;; Nowhere is it specified that PRINT-OBJECT on a VECTOR-NIL must + ;; access the contents and signal an error. So WRITE works fine. + (assert (write-to-string nil-vector)) + (let ((*read-eval* nil)) + (assert-error (write-to-string nil-vector :readably t))) (flet ((test (accessor) (assert-error (funcall (checked-compile @@ -172,14 +221,15 @@ nil-vector) sb-kernel:nil-array-accessed-error))) (test 'aref) - (test 'char) - (test 'schar) + ;; (test 'char) ; you'll get a TYPE-ERROR instead. + ;; (test 'schar) ; ditto (test 'row-major-aref)))) (with-test (:name :nil-array-access) (let ((nil-array (make-array '(10 10) :element-type nil))) - (assert-error (write-to-string nil-array) - sb-kernel:nil-array-accessed-error) + (assert (write-to-string nil-array)) + (let ((*read-eval* nil)) + (assert-error (write-to-string nil-array :readably t))) (flet ((test (accessor args) (assert-error (funcall (checked-compile @@ -212,3 +262,60 @@ (let ((result (funcall (checked-compile `(lambda (x) (write-to-string x))) 33d0))) (assert (equal result "33.0d0")) (assert (typep result 'simple-base-string)))) + +(with-test (:name :make-string-fail-early) + ;; This used to get "Heap exhausted" + (assert-error + (funcall (opaque-identity 'make-string) (truncate array-total-size-limit 2) + :element-type '(unsigned-byte 8)))) + +(with-test (:name :make-string-pedantic-initial-element) + ;; This used to be silently accepted (at least in the interpreter) + (assert-error + (funcall (opaque-identity 'make-string) 10 + :element-type '(member #\a #\b #\c) :initial-element nil)) + ;; As was this + (assert-error + (funcall (opaque-identity 'make-string) 10 + :element-type '(member #\a #\b #\c) :initial-element #\x))) + +(with-test (:name :%sp-string-compare-argument-order) + (checked-compile-and-assert + () + `(lambda (x) + (string/= "_" (the simple-string x))) + (("_") nil) + (("a") 0))) + +(with-test (:name :string=-derive-type) + (macrolet + ((check (fun expected) + `(assert + (equal (second + (third + (sb-kernel:%simple-fun-type + (checked-compile '(lambda (x y) + (declare (ignorable x y)) + ,fun))))) + ',expected)))) + (check (string= (the (simple-string 1) x) + (the (simple-string 2) y)) null) + (check (string= (the (simple-base-string 1) x) + (the (simple-base-string 2) y)) null) + (check (string= (the (simple-array character (1)) x) + (the (simple-array character (2)) y)) null))) + +(with-test (:name :string/=-derive-type) + (macrolet + ((check (fun expected) + `(assert + (equal (second + (third + (sb-kernel:%simple-fun-type + (checked-compile '(lambda (x y) + (declare (ignorable x y)) + ,fun))))) + ',expected)))) + (check (string/= (the (simple-string 4) x) + (the (simple-string 1) y) + :start1 1 :end1 * :end2 0) (or (integer 1 1) null)))) diff --git a/tests/style-warnings.impure.lisp b/tests/style-warnings.impure.lisp index 08cc46605c..ea75f83fb2 100644 --- a/tests/style-warnings.impure.lisp +++ b/tests/style-warnings.impure.lisp @@ -17,7 +17,7 @@ ;;;; more information. ;; These tests don't work unless compiling -#+interpreter (sb-ext:exit :code 104) +#+interpreter (invoke-restart 'run-tests::skip-file) (defun f-with-macro (arg) (list arg)) (defun f2-with-macro (a b) (list a b)) diff --git a/tests/subr.sh b/tests/subr.sh index a38e6ecc06..9ee2999d02 100644 --- a/tests/subr.sh +++ b/tests/subr.sh @@ -61,15 +61,15 @@ set +a run_sbcl () ( set -u if [ $# -gt 0 ]; then - "$SBCL_RUNTIME" --core "$SBCL_CORE" $SBCL_ARGS --eval "(setf sb-ext:*evaluator-mode* :${TEST_SBCL_EVALUATOR_MODE:-compile})" "$@" + "$SBCL_RUNTIME" --lose-on-corruption --core "$SBCL_CORE" $SBCL_ARGS --eval "(setf sb-ext:*evaluator-mode* :${TEST_SBCL_EVALUATOR_MODE:-compile})" "$@" else - "$SBCL_RUNTIME" --core "$SBCL_CORE" $SBCL_ARGS --eval "(setf sb-ext:*evaluator-mode* :${TEST_SBCL_EVALUATOR_MODE:-compile})" + "$SBCL_RUNTIME" --lose-on-corruption --core "$SBCL_CORE" $SBCL_ARGS --eval "(setf sb-ext:*evaluator-mode* :${TEST_SBCL_EVALUATOR_MODE:-compile})" fi ) run_sbcl_with_args () ( set -u - "$SBCL_RUNTIME" --core "$SBCL_CORE" "$@" + "$SBCL_RUNTIME" --lose-on-corruption --core "$SBCL_CORE" "$@" ) run_sbcl_with_core () ( @@ -77,9 +77,9 @@ run_sbcl_with_core () ( core="$1" shift if [ $# -gt 0 ]; then - "$SBCL_RUNTIME" --core "$core" "$@" + "$SBCL_RUNTIME" --lose-on-corruption --core "$core" "$@" else - "$SBCL_RUNTIME" --core "$core" $SBCL_ARGS --eval "(setf sb-ext:*evaluator-mode* :${TEST_SBCL_EVALUATOR_MODE:-compile})" + "$SBCL_RUNTIME" --lose-on-corruption --core "$core" $SBCL_ARGS --eval "(setf sb-ext:*evaluator-mode* :${TEST_SBCL_EVALUATOR_MODE:-compile})" fi ) diff --git a/tests/symbol.impure.lisp b/tests/symbol-2.pure.lisp similarity index 96% rename from tests/symbol.impure.lisp rename to tests/symbol-2.pure.lisp index 9d9b67161d..cf42750b15 100644 --- a/tests/symbol.impure.lisp +++ b/tests/symbol-2.pure.lisp @@ -11,13 +11,12 @@ ;;;; absolutely no warranty. See the COPYING and CREDITS files for ;;;; more information. -(in-package "CL-USER") - (declaim (type (simple-array fixnum (*)) *foo*)) (with-test (:name :defvar-type-error) (assert (eq :ok (handler-case - (eval `(defvar *foo* (make-array 10 :element-type '(unsigned-byte 60)))) + (eval `(defvar *foo* (make-array 10 :element-type '(unsigned-byte 60) + :initial-element 0))) (type-error (e) (when (and (typep e 'type-error) (equal '(simple-array fixnum (*)) @@ -62,7 +61,7 @@ *COMPILE-FILE-TRUENAME* 1 *COMPILE-PRINT* 1 *COMPILE-VERBOSE* 1 *DEBUG-IO* 1 *DEBUGGER-HOOK* 1 *DEFAULT-PATHNAME-DEFAULTS* 1 *ERROR-OUTPUT* 1 *FEATURES* 1 *GENSYM-COUNTER* 1 *LOAD-PATHNAME* 1 *LOAD-PRINT* 1 *LOAD-TRUENAME* 1 - *LOAD-VERBOSE* 1 *MACROEXPAND-HOOK* 1 *MODULES* 1 *PACKAGE* 1 *PRINT-ARRAY* 1 + *LOAD-VERBOSE* 1 *MACROEXPAND-HOOK* 1 *MODULES* 1 CL:*PACKAGE* 1 *PRINT-ARRAY* 1 *PRINT-BASE* 1 *PRINT-CASE* 1 *PRINT-CIRCLE* 1 *PRINT-ESCAPE* 1 *PRINT-GENSYM* 1 *PRINT-LENGTH* 1 *PRINT-LEVEL* 1 *PRINT-LINES* 1 *PRINT-MISER-WIDTH* 1 *PRINT-PPRINT-DISPATCH* 1 *PRINT-PRETTY* 1 *PRINT-RADIX* 1 *PRINT-READABLY* 1 @@ -107,7 +106,7 @@ DECODE-FLOAT 2 DECODE-UNIVERSAL-TIME 2 DEFCLASS 2 DEFCONSTANT 2 DEFGENERIC 2 DEFINE-COMPILER-MACRO 2 DEFINE-CONDITION 2 DEFINE-METHOD-COMBINATION 2 DEFINE-MODIFY-MACRO 2 DEFINE-SETF-EXPANDER 2 DEFINE-SYMBOL-MACRO 2 DEFMACRO 2 - DEFMETHOD 2 DEFPACKAGE 2 DEFPARAMETER 2 DEFSETF 2 DEFSTRUCT 2 DEFTYPE 2 DEFUN + CL:DEFMETHOD 2 DEFPACKAGE 2 DEFPARAMETER 2 DEFSETF 2 DEFSTRUCT 2 DEFTYPE 2 DEFUN 2 DEFVAR 2 DELETE 2 DELETE-DUPLICATES 2 DELETE-FILE 2 DELETE-IF 2 DELETE-IF-NOT 2 DELETE-PACKAGE 2 DENOMINATOR 2 DEPOSIT-FIELD 2 DESCRIBE 2 DESCRIBE-OBJECT 2 DESTRUCTURING-BIND 2 DIGIT-CHAR 2 DIGIT-CHAR-P 2 DIRECTORY 2 @@ -137,7 +136,7 @@ HANDLER-CASE 2 HASH-TABLE 8 HASH-TABLE-COUNT 2 HASH-TABLE-P 2 HASH-TABLE-REHASH-SIZE 2 HASH-TABLE-REHASH-THRESHOLD 2 HASH-TABLE-SIZE 2 HASH-TABLE-TEST 2 HOST-NAMESTRING 2 IDENTITY 2 IF 2 IGNORABLE 0 IGNORE 0 - IGNORE-ERRORS 2 IMAGPART 2 IMPORT 2 IN-PACKAGE 2 INCF 2 INITIALIZE-INSTANCE 2 + IGNORE-ERRORS 2 IMAGPART 2 IMPORT 2 CL:IN-PACKAGE 2 INCF 2 INITIALIZE-INSTANCE 2 INLINE 0 INPUT-STREAM-P 2 INSPECT 2 INTEGER 8 INTEGER-DECODE-FLOAT 2 INTEGER-LENGTH 2 INTEGERP 2 INTERACTIVE-STREAM-P 2 INTERN 2 INTERNAL-TIME-UNITS-PER-SECOND 5 INTERSECTION 2 INVALID-METHOD-ERROR 2 @@ -192,6 +191,7 @@ PATHNAME-NAME 10 PATHNAME-TYPE 10 PATHNAME-VERSION 10 PATHNAMEP 2 PEEK-CHAR 2 PHASE 2 PI 5 PLUSP 2 POP 2 POSITION 2 POSITION-IF 2 POSITION-IF-NOT 2 PPRINT 2 PPRINT-DISPATCH 2 PPRINT-EXIT-IF-LIST-EXHAUSTED 2)) +(when (find-symbol "%LOAD-TRUENAME" "SB-FASL") (remf *cl-classification* '*load-truename*)) (defun check-symbols (classification) (loop for (symbol expected) on classification by #'cddr diff --git a/tests/system.impure.lisp b/tests/system.impure.lisp index c3b9437263..e00df4c76e 100644 --- a/tests/system.impure.lisp +++ b/tests/system.impure.lisp @@ -11,7 +11,7 @@ (in-package "SB-VM") -#-(and (or x86 x86-64) (not interpreter)) (sb-ext:exit :code 104) +#-(and (or x86 x86-64) (not interpreter)) (invoke-restart 'run-tests::skip-file) (test-util:with-test (:name :basic-cpuid) (flet ((to-ascii (bits) diff --git a/tests/test-funs.lisp b/tests/test-funs.lisp index a7b8ae6e82..4e802b6b46 100644 --- a/tests/test-funs.lisp +++ b/tests/test-funs.lisp @@ -66,7 +66,12 @@ (start-time (get-internal-real-time))) (with-scratch-file (fasl "fasl") (let ((*features* (append *features* sb-impl:+internal-features+))) - (compile-file file :print nil :output-file fasl)) + (multiple-value-bind (fasl warnings failure) + (compile-file file :print nil :output-file fasl) + (declare (ignorable fasl warnings)) + (when (or #|warnings|# failure) ; FIXME: disallow warnings + (push (list :unexpected-failure file :compile-failed) *failures*) + (return-from cload-test)))) (test-util::record-test-elapsed-time "(compile-file)" start-time) (load fasl) ;; TODO: as above, execute queued tests if within-file concurrency was enabled. @@ -78,7 +83,9 @@ (progn (test-util::setenv "TEST_SBCL_EVALUATOR_MODE" (string-downcase *test-evaluator-mode*)) - (let ((process (sb-ext:run-program "/bin/sh" + ;; Why would it ever be wrong to use (posix-getenv "SHELL") ??? + (let ((process (sb-ext:run-program (or #+(or sunos win32) (posix-getenv "SHELL") + "/bin/sh") (list (native-namestring file)) :output *error-output*))) (let ((*failures* nil)) diff --git a/tests/test-util.lisp b/tests/test-util.lisp index c39ddf36c3..822f3d67aa 100644 --- a/tests/test-util.lisp +++ b/tests/test-util.lisp @@ -32,7 +32,11 @@ #:get-simple-fun-instruction-model #:scratch-file-name + #:*scratch-file-prefix* #:with-scratch-file + #:with-test-directory + #:generate-test-directory-name + #:*test-directory* #:opaque-identity #:runtime #:split-string #:integer-sequence #:shuffle)) @@ -78,13 +82,12 @@ (and (subtypep x y) (subtypep y x))) (defun ctype= (left right) - (let ((a (sb-kernel:specifier-type left))) + (let ((a (sb-kernel:values-specifier-type left))) ;; SPECIFIER-TYPE is a memoized function, and TYPE= is a trivial ;; operation if A and B are EQ. ;; To actually exercise the type operation, remove the memoized parse. (sb-int:drop-all-hash-caches) - (let ((b (sb-kernel:specifier-type right))) - (assert (not (eq a b))) + (let ((b (sb-kernel:values-specifier-type right))) (sb-kernel:type= a b)))) (defmacro assert-tri-eq (expected-result expected-certainp form) @@ -120,7 +123,19 @@ (sb-ext:wait-for (null (sb-thread::thread-interruptions thread)))) (defun test-interrupt (function-to-interrupt &optional quit-p) - (let ((child (make-kill-thread function-to-interrupt))) + ;; Tests of interrupting a newly created thread can fail if the creator runs + ;; so quickly that it bypasses execution of the created thread. So the creator + ;; needs to wait, to have a facsimile of the situation prior to implementation + ;; of the so-called pauseless thread start feature. + ;; Wouldn't you know, it's just reintroducing a startup semaphore. + ;; And interruption tests are even more likely to fail with :sb-safepoint. + ;; Noneless, this tries to be robust enough to pass. + (let* ((sem (sb-thread:make-semaphore)) + (child (make-kill-thread + (lambda () + (sb-thread:signal-semaphore sem) + (funcall function-to-interrupt))))) + (sb-thread:wait-on-semaphore sem) (format t "interrupting child ~A~%" child) (sb-thread:interrupt-thread child (lambda () @@ -154,7 +169,12 @@ (if (expected-failure-p fails-on) (fail-test :expected-failure name error) (fail-test :unexpected-failure name error)) - (return-from run-test)))) + (return-from run-test))) + (timeout (lambda (error) + (if (expected-failure-p fails-on) + (fail-test :expected-failure name error t) + (fail-test :unexpected-failure name error t)) + (return-from run-test)))) ;; Non-pretty is for cases like (with-test (:name (let ...)) ... (log-msg/non-pretty *trace-output* "Running ~S" name) (funcall test-function) @@ -167,10 +187,6 @@ (setf threads (union (union *threads-to-kill* *threads-to-join*) threads)) - #+(and sb-safepoint-strictly (not win32)) - (dolist (thread (sb-thread:list-all-threads)) - (when (typep thread 'sb-thread:signal-handling-thread) - (ignore-errors (sb-thread:join-thread thread)))) (dolist (thread (sb-thread:list-all-threads)) (unless (or (not (sb-thread:thread-alive-p thread)) (eql (the sb-thread:thread thread) @@ -192,7 +208,7 @@ ;;; Like RUN-TEST but do not perform any of the automated thread management. ;;; Since multiple threads are executing tests, there is no reason to kill ;;; unrecognized threads. -(sb-ext:define-load-time-global *output-mutex* (sb-thread:make-mutex)) +(sb-ext:define-load-time-global *output-mutex* (sb-thread:make-mutex :name "run-tests output")) (defun run-test-concurrently (test-spec) (destructuring-bind (test-body . name) test-spec (sb-thread:with-mutex (*output-mutex*) @@ -232,7 +248,7 @@ (eql package (find-package "KEYWORD"))))) (integer t)))) (unless (tree-equal name name :test #'name-ok) - (error "test name must be all-keywords: ~S" name))) + (error "test name must be all-keywords: ~S" name))) ; WHY???? (cond ((broken-p broken-on) `(progn @@ -276,7 +292,7 @@ (enable-debugger) (invoke-debugger condition)))) -(defun fail-test (type test-name condition) +(defun fail-test (type test-name condition &optional backtrace) (if (stringp condition) (log-msg *trace-output* "~@<~A ~S ~:_~A~:>" type test-name condition) @@ -285,7 +301,8 @@ (push (list type *test-file* (or test-name *test-count*)) *failures*) (unless (stringp condition) - ;; (sb-debug:print-backtrace :from :interrupted-frame) + (when backtrace + (sb-debug:print-backtrace :from :interrupted-frame)) (when (or (and *break-on-failure* (not (eq type :expected-failure))) *break-on-expected-failure*) @@ -815,7 +832,8 @@ finally (return (/ min-internal-time-units-per-call (float internal-time-units-per-second))))) -(defmacro runtime (form &key (repetitions 5) (precision 30)) +(defmacro runtime (form &key (repetitions 5) (precision (* 30 + (/ internal-time-units-per-second 1000)))) `(runtime* (lambda () ,form) ,repetitions ,precision)) (declaim (notinline opaque-identity)) @@ -846,21 +864,20 @@ ;;; Return a random file name to avoid writing into the source tree. ;;; We can't use any of the interfaces provided in libc because those are inadequate ;;; for purposes of COMPILE-FILE. This is not trying to be robust against attacks. +(defvar *scratch-file-prefix* "sbcl-scratch") (defun scratch-file-name (&optional extension) (let ((a (make-array 10 :element-type 'character))) (dotimes (i 10) (setf (aref a i) (code-char (+ (char-code #\a) (random 26))))) - ;; not sure where to write files on win32. this is no worse than what it was - #+win32 (format nil "~a~@[.~a~]" a extension) - #-win32 (let ((dir (posix-getenv "TMPDIR")) - (file (format nil "sbcl~d~a~@[.~a~]" - (sb-unix:unix-getpid) a extension))) - (if dir - (namestring - (merge-pathnames - file (truename (parse-native-namestring dir nil *default-pathname-defaults* - :as-directory t)))) - (concatenate 'string "/tmp/" file))))) + (let ((dir (posix-getenv #+win32 "TMP" #+unix "TMPDIR")) + (file (format nil "~a~d~a~@[.~a~]" *scratch-file-prefix* + (sb-unix:unix-getpid) a extension))) + (if dir + (namestring + (merge-pathnames + file (truename (parse-native-namestring dir nil *default-pathname-defaults* + :as-directory t)))) + (concatenate 'string "/tmp/" file))))) (defmacro with-scratch-file ((var &optional extension) &body forms) (sb-int:with-unique-names (tempname) @@ -869,6 +886,35 @@ (let ((,var ,tempname)) ,@forms) ; rebind, as test might asssign into VAR (ignore-errors (delete-file ,tempname)))))) +(defvar *test-directory*) + +(defun generate-test-directory-name () + ;; Why aren't we using TMPDIR??? + (merge-pathnames + (make-pathname :directory `(:relative ,(write-to-string (sb-unix:unix-getpid)))) + (parse-native-namestring (posix-getenv "TEST_DIRECTORY") + nil *default-pathname-defaults* + :as-directory t))) + +(defun call-with-test-directory (fn) + ;; FIXME: this writes into the source directory depending on whether + ;; TEST_DIRECTORY has been made to point elsewhere or not. + (let ((test-directory (generate-test-directory-name))) + (ensure-directories-exist test-directory) + (unwind-protect + ;; WHY REBIND *DEFAULT-PATHNAME-DEFAULTS* ? THIS SUCKS! + ;; (It means we can't use the WITH-TEST-DIRECTORY macro for most things) + (let ((*default-pathname-defaults* test-directory) + (*test-directory* test-directory)) + (funcall fn test-directory)) + (delete-directory test-directory :recursive t)))) + +(defmacro with-test-directory ((&optional (test-directory-var (gensym))) + &body body) + `(call-with-test-directory (lambda (,test-directory-var) + (declare (ignorable ,test-directory-var)) + ,@body))) + ;;; Take a list of lists and assemble them as though they are ;;; instructions inside the body of a vop. There is no need ;;; to use the INST macro in front of each list. @@ -909,3 +955,26 @@ (when (>= (sb-disassem:dstate-cur-offs dstate) (sb-disassem:seg-length segment)) (return))) (result)))) + +;;; If a test file is not very tolerant of the statistical profiler, then +;;; it should call this. There seem to be at least 2 common categories of failure: +;;; * the stack exhaustion test can get a profiling signal when you're already +;;; near exhaustion, and then the profiler exhausts the stack, which isn't +;;; handled very well. Example: +;;; Control stack exhausted, fault: 0xd76b9ff8, PC: 0x806cad2 +;;; 0: fp=0xd76ba008 pc=0x806cad2 Foreign function search_dynamic_space +;;; 1: fp=0xd76ba028 pc=0x80633d1 Foreign function search_all_gc_spaces +;;; 2: fp=0xd76ba048 pc=0x805647e Foreign function component_ptr_from_pc +;;; 3: fp=0xd76baa18 pc=0x8065dfd Foreign function (null) +;;; 4: fp=0xd76baa98 pc=0x806615a Foreign function record_backtrace_from_context +;;; 5: fp=0xd76baab8 pc=0x806625e Foreign function sigprof_handler +;;; * debugger-related tests. I'm not sure why. +(defun disable-profiling () + (when (find-package "SB-SPROF") + (format t "INFO: disabling SB-SPROF~%") + (funcall (intern "STOP-PROFILING" "SB-SPROF")))) + +;;; This unexported symbol emulates SB-RT. Please don't use it in new tests +(defmacro deftest (name form &rest results) ; use SB-RT syntax + `(test-util:with-test (:name ,(sb-int:keywordicate name)) + (assert (equalp (multiple-value-list ,form) ',results)))) diff --git a/tests/threads.impure.lisp b/tests/threads.impure.lisp index aef3cded10..63565f4509 100644 --- a/tests/threads.impure.lisp +++ b/tests/threads.impure.lisp @@ -12,7 +12,7 @@ ;;;; more information. -;;;; WHITE-BOX TESTS +;;;; STRUCTURAL TESTS (shadowing-import 'assertoid:assert-error) (use-package "SB-THREAD") @@ -21,8 +21,6 @@ (setf sb-unix::*on-dangerous-wait* :error) (with-test (:name (:threads :trivia)) - (assert (eql 1 (length (list-all-threads)))) - (assert (eq *current-thread* (find (thread-name *current-thread*) (list-all-threads) :key #'thread-name :test #'equal))) @@ -72,7 +70,7 @@ (process-all-interrupts)) (check-deferrables-unblocked-or-lose 0)) -#-sb-thread (sb-ext:exit :code 104) +#-sb-thread (invoke-restart 'run-tests::skip-file) ;;;; Now the real tests... @@ -140,8 +138,10 @@ (let ((old-threads (list-all-threads)) (thread (make-thread (lambda () + ;; I honestly have no idea what this is testing. + ;; It seems to be nothing more than an implementation change detector test. (assert (sb-thread::avl-find - (sb-kernel:get-lisp-obj-address sb-vm:*control-stack-start*) + (sb-thread::thread-primitive-thread sb-thread:*current-thread*) sb-thread::*all-threads*)) (sleep 2)))) (new-threads (list-all-threads))) @@ -213,23 +213,23 @@ (with-test (:name (:mutex :basics)) (let ((l (make-mutex :name "foo")) (p *current-thread*)) - (assert (eql (mutex-value l) nil) nil "1") + (assert (eql (mutex-owner l) nil) nil "1") (grab-mutex l) - (assert (eql (mutex-value l) p) nil "3") + (assert (eql (mutex-owner l) p) nil "3") (release-mutex l) - (assert (eql (mutex-value l) nil) nil "5"))) + (assert (eql (mutex-owner l) nil) nil "5"))) (with-test (:name (with-recursive-lock :basics)) (labels ((ours-p (value) (eq *current-thread* value))) (let ((l (make-mutex :name "rec"))) - (assert (eql (mutex-value l) nil) nil "1") + (assert (eql (mutex-owner l) nil) nil "1") (with-recursive-lock (l) - (assert (ours-p (mutex-value l)) nil "3") + (assert (ours-p (mutex-owner l)) nil "3") (with-recursive-lock (l) - (assert (ours-p (mutex-value l)) nil "4")) - (assert (ours-p (mutex-value l)) nil "5")) - (assert (eql (mutex-value l) nil) nil "6")))) + (assert (ours-p (mutex-owner l)) nil "4")) + (assert (ours-p (mutex-owner l)) nil "5")) + (assert (eql (mutex-owner l) nil) nil "6")))) (with-test (:name (with-recursive-lock :wait-p)) (let ((m (make-mutex))) @@ -282,19 +282,19 @@ (n 0)) (labels ((in-new-thread () (with-mutex (lock) - (assert (eql (mutex-value lock) *current-thread*)) + (assert (eql (mutex-owner lock) *current-thread*)) (format t "~A got mutex~%" *current-thread*) ;; now drop it and sleep (condition-wait queue lock) ;; after waking we should have the lock again - (assert (eql (mutex-value lock) *current-thread*)) + (assert (eql (mutex-owner lock) *current-thread*)) (assert (eql n 1)) (decf n)))) (make-join-thread #'in-new-thread) (sleep 2) ; give it a chance to start ;; check the lock is free while it's asleep (format t "parent thread ~A~%" *current-thread*) - (assert (eql (mutex-value lock) nil)) + (assert (eql (mutex-owner lock) nil)) (with-mutex (lock) (incf n) (condition-notify queue)) @@ -307,18 +307,18 @@ (eq *current-thread* value)) (in-new-thread () (with-recursive-lock (lock) - (assert (ours-p (mutex-value lock))) - (format t "~A got mutex~%" (mutex-value lock)) + (assert (ours-p (mutex-owner lock))) + (format t "~A got mutex~%" (mutex-owner lock)) ;; now drop it and sleep (condition-wait queue lock) ;; after waking we should have the lock again - (format t "woken, ~A got mutex~%" (mutex-value lock)) - (assert (ours-p (mutex-value lock)))))) + (format t "woken, ~A got mutex~%" (mutex-owner lock)) + (assert (ours-p (mutex-owner lock)))))) (make-join-thread #'in-new-thread) (sleep 2) ; give it a chance to start ;; check the lock is free while it's asleep (format t "parent thread ~A~%" *current-thread*) - (assert (eql (mutex-value lock) nil)) + (assert (eql (mutex-owner lock) nil)) (with-recursive-lock (lock) (condition-notify queue)) (sleep 1)))) @@ -389,7 +389,8 @@ `(handler-case (progn (progn ,@body) nil) (sb-ext:timeout () t))) -(with-test (:name (semaphore :wait-forever)) +(with-test (:name (semaphore :wait-forever) + :skipped-on (:and :sb-safepoint :linux)) ; hangs (let ((sem (make-semaphore :count 0))) (assert (raises-timeout-p (sb-ext:with-timeout 0.1 @@ -568,59 +569,19 @@ (throw 'xxx *runningp*))) (assert (join-thread thread)))) -(with-test (:name (:two-threads-running-gc) - :broken-on :sb-safepoint) - (let (a-done b-done) - (make-join-thread (lambda () - (dotimes (i 100) - (sb-ext:gc) (princ "\\") (force-output)) - (setf a-done t))) - (make-join-thread (lambda () - (dotimes (i 25) - (sb-ext:gc :full t) - (princ "/") (force-output)) - (setf b-done t))) - (loop - (when (and a-done b-done) (return)) - (sleep 1)))) - -(defun waste (&optional (n 100000)) - (loop repeat n do (make-string 16384))) - -(compile 'waste) - -(with-test (:name (:one-thread-runs-gc-while-other-conses) - :broken-on :win32) - (loop for i below 100 do - (princ "!") - (force-output) - (make-join-thread - #'(lambda () - (waste))) - (waste) - (sb-ext:gc))) - -(defparameter *aaa* nil) -(with-test (:name (:one-thread-runs-gc-while-other-conses :again) - :broken-on :win32) - (loop for i below 100 do - (princ "!") - (force-output) - (make-join-thread - #'(lambda () - (let ((*aaa* (waste))) - (waste)))) - (let ((*aaa* (waste))) - (waste)) - (sb-ext:gc))) - (with-test (:name :all-threads-have-abort-restart :broken-on :win32) - (loop repeat 100 do - (let ((thread (make-kill-thread (lambda () (sleep 100000000))))) - (interrupt-thread thread (lambda () - (assert (find-restart 'abort)))) - (process-all-interrupts thread)))) + ;; This test can fail with without the extra semaphore. + ;; See also TEST-INTERRUPT in test-util for further explanation. + (let* ((sem (make-semaphore)) + (thread (make-kill-thread + (lambda () + (signal-semaphore sem) + (sleep 100000000))))) + (wait-on-semaphore sem) + (interrupt-thread thread (lambda () + (assert (find-restart 'abort)))) + (process-all-interrupts thread))) (sb-ext:gc :full t) @@ -710,18 +671,20 @@ (let* ((i (sb-kernel:symbol-tls-index mysym)) (j (+ i sb-vm:n-word-bytes))) (assert (eql (sap-ref-word (sb-thread::current-thread-sap) j) - sb-vm:no-tls-value-marker-widetag)) + sb-vm:no-tls-value-marker)) (setf (sap-ref-lispobj (sb-thread::current-thread-sap) i) fool1 (sap-ref-lispobj (sb-thread::current-thread-sap) j) fool2) ;; assert that my pointer arithmetic worked as expected (assert (eq (symbol-value mysym) fool1)) ;; assert that FOOL1 is found by the TLS scan and that FOOL2 is not. (let ((list (sb-thread::%thread-local-references))) + (assert (not (find sb-vm:no-tls-value-marker list + :key #'sb-kernel:get-lisp-obj-address))) (assert (member fool1 list)) (assert (not (member fool2 list)))) ;; repair the TLS entry that was corrupted by the test (setf (sap-ref-word (sb-thread::current-thread-sap) j) - sb-vm:no-tls-value-marker-widetag))))) + sb-vm:no-tls-value-marker))))) #| ;; a cll post from eric marsden @@ -767,75 +730,6 @@ (mapc #'join-thread threads) (assert (not deadline-handler-run-twice?)))) -(with-test (:name (condition-wait :signal-deadline-with-interrupts-enabled)) - (let ((mutex (make-mutex)) - (waitq (make-waitqueue)) - (A-holds? :unknown) - (B-holds? :unknown) - (A-interrupts-enabled? :unknown) - (B-interrupts-enabled? :unknown) - (A) - (B)) - ;; W.L.O.G., we assume that A is executed first... - (setq A (make-thread - (lambda () - (handler-bind - ((sb-sys:deadline-timeout - (lambda (c) - ;; We came here through the call to DECODE-TIMEOUT - ;; in CONDITION-WAIT; hence both here are supposed - ;; to evaluate to T. - (setq A-holds? (holding-mutex-p mutex)) - (setq A-interrupts-enabled? - sb-sys:*interrupts-enabled*) - (sleep 0.2) - (condition-broadcast waitq) - (sb-sys:defer-deadline 10.0 c)))) - (sb-sys:with-deadline (:seconds 0.1) - (with-mutex (mutex) - (condition-wait waitq mutex))))) - :name "A")) - (setq B (make-thread - (lambda () - (thread-yield) - (handler-bind - ((sb-sys:deadline-timeout - (lambda (c) - ;; We came here through the call to DECODE-TIMEOUT - ;; in CONDITION-WAIT (contended case of - ;; reaquiring the mutex) - so the former will - ;; be NIL, but interrupts should still be enabled. - (setq B-holds? (holding-mutex-p mutex)) - (setq B-interrupts-enabled? - sb-sys:*interrupts-enabled*) - (sleep 0.2) - (condition-broadcast waitq) - (sb-sys:defer-deadline 10.0 c)))) - (sb-sys:with-deadline (:seconds 0.1) - (with-mutex (mutex) - (condition-wait waitq mutex))))) - :name "B")) - (join-thread A) - (join-thread B) - (let ((A-result (list A-holds? A-interrupts-enabled?)) - (B-result (list B-holds? B-interrupts-enabled?))) - ;; We also check some subtle behaviour w.r.t. whether a deadline - ;; handler in CONDITION-WAIT got the mutex, or not. This is most - ;; probably very internal behaviour (so user should not depend - ;; on it) -- I added the testing here just to manifest current - ;; behaviour. - (cond ((equal A-result '(t t)) (assert (equal B-result '(nil t)))) - ((equal B-result '(t t)) (assert (equal A-result '(nil t)))) - (t - (error "Failure: fell through wit A: ~S, B: ~S" - A-result - B-result)))))) - -(with-test (:name (:mutex :finalization)) - (let ((a nil)) - (dotimes (i 500000) - (setf a (make-mutex))))) - ;; You have to shoehorn this arbitrary sexpr into a feature expression ;; to have the test summary show that a test was disabled. #+gencgc @@ -878,7 +772,7 @@ collect (make-thread #'subtypep-hash-cache-test))) (terpri)) -;;;; BLACK BOX TESTS +;;;; FUNCTIONAL TESTS (with-test (:name (:parallel defclass)) (write-line "WARNING, WILL HANG ON FAILURE!") @@ -891,22 +785,23 @@ ;; cheating, and might be hiding the underlying bug that the test is ;; exposing. Let's review this later. (let* ((run t) + (output nil) (d1 (sb-thread:make-thread (lambda () (loop while run do (defclass test-1 () ((a :initform :new-a))) - (write-char #\1) + (when output (write-char #\1)) #-win32 (force-output))) :name "d1")) (d2 (sb-thread:make-thread (lambda () (loop while run do (defclass test-2 () ((b :initform :new-b))) - (write-char #\2) + (when output (write-char #\2)) #-win32 (force-output))) :name "d2")) (d3 (sb-thread:make-thread (lambda () (loop while run do (defclass test-3 (test-1 test-2) ((c :initform :new-c))) - (write-char #\3) + (when output (write-char #\3)) #-win32 (force-output))) :name "d3")) (i (sb-thread:make-thread (lambda () @@ -915,7 +810,7 @@ (assert (member (slot-value i 'a) '(:orig-a :new-a))) (assert (member (slot-value i 'b) '(:orig-b :new-b))) (assert (member (slot-value i 'c) '(:orig-c :new-c)))) - (write-char #\i) + (when output (write-char #\i)) #-win32 (force-output))) :name "i"))) (format t "~%sleeping!~%") @@ -924,45 +819,10 @@ (setf run nil) (mapc (lambda (th) (sb-thread:join-thread th) - (format t "~%joined ~S~%" (sb-thread:thread-name th))) + (format t "~&joined ~S~%" (sb-thread:thread-name th))) (list d1 d2 d3 i)) (force-output))) -(with-test (:name (:deadlock-detection :interrupts) - :broken-on :win32) - (let* ((m1 (sb-thread:make-mutex :name "M1")) - (m2 (sb-thread:make-mutex :name "M2")) - (t1-can-go (sb-thread:make-semaphore :name "T1 can go")) - (t2-can-go (sb-thread:make-semaphore :name "T2 can go")) - (t1 (sb-thread:make-thread - (lambda () - (sb-thread:with-mutex (m1) - (sb-thread:wait-on-semaphore t1-can-go) - :ok1)) - :name "T1")) - (t2 (sb-thread:make-thread - (lambda () - (sb-ext:wait-for (eq t1 (sb-thread:mutex-owner m1))) - (sb-thread:with-mutex (m1 :wait-p t) - (sb-thread:wait-on-semaphore t2-can-go) - :ok2)) - :name "T2"))) - (sb-ext:wait-for (eq m1 (sb-thread::thread-waiting-for t2))) - (sb-thread:interrupt-thread t2 (lambda () - (sb-thread:with-mutex (m2 :wait-p t) - (sb-ext:wait-for - (eq m2 (sb-thread::thread-waiting-for t1))) - (sb-thread:signal-semaphore t2-can-go)))) - (sb-ext:wait-for (eq t2 (sb-thread:mutex-owner m2))) - (sb-thread:interrupt-thread t1 (lambda () - (sb-thread:with-mutex (m2 :wait-p t) - (sb-thread:signal-semaphore t1-can-go)))) - ;; both threads should finish without a deadlock or deadlock - ;; detection error - (let ((res (list (sb-thread:join-thread t1) - (sb-thread:join-thread t2)))) - (assert (equal '(:ok1 :ok2) res))))) - (with-test (:name :spinlock-api) (handler-bind ((warning #'error)) (destructuring-bind (with make get release) diff --git a/tests/threads.pure.lisp b/tests/threads.pure.lisp index b45eeebbad..3a3f50a85f 100644 --- a/tests/threads.pure.lisp +++ b/tests/threads.pure.lisp @@ -13,6 +13,12 @@ (use-package '("SB-EXT" "SB-THREAD")) +(with-test (:name :dont-print-array + :skipped-on (not :sb-thread)) + (let ((thr (sb-thread:make-thread (lambda () (make-array 100))))) + (sb-thread:join-thread thr) + (assert (search "#<(SIMPLE-VECTOR" (write-to-string thr))))) + (with-test (:name atomic-update :skipped-on (not :sb-thread)) (let ((x (cons :count 0)) @@ -29,10 +35,10 @@ ;; Make sure basics are sane on unithreaded ports as well (let ((mutex (make-mutex))) (grab-mutex mutex) - (assert (eq *current-thread* (mutex-value mutex))) + (assert (eq *current-thread* (mutex-owner mutex))) (handler-bind ((warning #'error)) (release-mutex mutex)) - (assert (not (mutex-value mutex))))) + (assert (not (mutex-owner mutex))))) ;;; Terminating a thread that's waiting for the terminal. @@ -48,23 +54,34 @@ (assert (not (thread-alive-p thread))))) ;;; Condition-wait should not be interruptible under WITHOUT-INTERRUPTS +;;; BUT: Such a claim is without much merit. Even if a wait is not "interrupted", +;;; the very definition of spurious wakeup is that return from the wait happens +;;; for ANY reason - users of condition variables must ALWAYS anticipate needing +;;; to loop over a condition-wait. (with-test (:name :without-interrupts+condition-wait :skipped-on (not :sb-thread) :broken-on :win32) (let* ((lock (make-mutex)) (queue (make-waitqueue)) + (actually-wakeup nil) (thread (make-thread (lambda () (sb-sys:without-interrupts (with-mutex (lock) - (condition-wait queue lock))))))) - (sleep 1) + (loop + (condition-wait queue lock) + (if actually-wakeup (return))))))))) + (sleep .25) (assert (thread-alive-p thread)) + ;; this is the supposed "interrupt that doesn't interrupt", + ;; but it _is_ permitted to wake the condition variable. (terminate-thread thread) - (sleep 1) + (sleep .5) (assert (thread-alive-p thread)) + (setq actually-wakeup t) + (sb-thread:barrier (:write)) (condition-notify queue) - (sleep 1) + (sleep .25) (assert (not (thread-alive-p thread))))) ;;; GRAB-MUTEX should not be interruptible under WITHOUT-INTERRUPTS @@ -109,9 +126,10 @@ collect (make-thread (lambda () - (let ((sem semaphore)) - (dotimes (s i) - (wait-on-semaphore sem)))) + (sb-ext:with-timeout 10 + (let ((sem semaphore)) + (dotimes (s i) + (wait-on-semaphore sem))))) :name "reader")) (* n i))) (make-writers (n readers i) @@ -123,9 +141,10 @@ collect (make-thread (lambda () - (let ((sem semaphore)) - (dotimes (s k) - (signal-semaphore sem)))) + (sb-ext:with-timeout 10 + (let ((sem semaphore)) + (dotimes (s k) + (signal-semaphore sem))))) :name "writer")))) (assert (zerop rem)) writers) @@ -142,17 +161,14 @@ (values))))) (assert (eq :ok - (handler-case - (sb-ext:with-timeout 10 - (test 1 1 100) - (test 2 2 10000) - (test 4 2 10000) - (test 4 2 10000) - (test 10 10 10000) - (test 10 1 10000) - :ok) - (sb-ext:timeout () - :timeout))))))) + (sb-ext:with-timeout 20 + (test 1 1 100) + (test 2 2 10000) + (test 4 2 10000) + (test 4 2 10000) + (test 10 10 10000) + (test 10 1 10000) + :ok)))))) ;;;; Printing waitqueues @@ -288,99 +304,6 @@ (sb-thread::symbol-value-in-thread-error-info e))))) (assert error-occurred))) -(with-test (:name :deadlock-detection.1 :skipped-on (not :sb-thread)) - (loop - repeat 1000 - do (flet ((test (ma mb sa sb) - (lambda () - (handler-case - (with-mutex (ma) - (signal-semaphore sa) - (wait-on-semaphore sb) - (with-mutex (mb) - :ok)) - (thread-deadlock (e) - ;; (assert (plusp (length ...))) prevents - ;; flushing. - (assert (plusp (length (princ-to-string e)))) - :deadlock))))) - (let* ((m1 (make-mutex :name "M1")) - (m2 (make-mutex :name "M2")) - (s1 (make-semaphore :name "S1")) - (s2 (make-semaphore :name "S2")) - (t1 (make-thread (test m1 m2 s1 s2) :name "T1")) - (t2 (make-thread (test m2 m1 s2 s1) :name "T2"))) - ;; One will deadlock, and the other will then complete normally. - (let ((res (list (join-thread t1) - (join-thread t2)))) - (assert (or (equal '(:deadlock :ok) res) - (equal '(:ok :deadlock) res)))))))) - -(with-test (:name :deadlock-detection.2 :skipped-on (not :sb-thread)) - (let* ((m1 (make-mutex :name "M1")) - (m2 (make-mutex :name "M2")) - (s1 (make-semaphore :name "S1")) - (s2 (make-semaphore :name "S2")) - (t1 (make-thread - (lambda () - (with-mutex (m1) - (signal-semaphore s1) - (wait-on-semaphore s2) - (with-mutex (m2) - :ok))) - :name "T1"))) - (prog (err) - :retry - (handler-bind ((thread-deadlock - (lambda (e) - (unless err - ;; Make sure we can print the condition - ;; while it's active - (let ((*print-circle* nil)) - (setf err (princ-to-string e))) - (go :retry))))) - (when err - (sleep 1)) - (assert (eq :ok (with-mutex (m2) - (unless err - (signal-semaphore s2) - (wait-on-semaphore s1) - (sleep 1)) - (with-mutex (m1) - :ok))))) - (assert (stringp err))) - (assert (eq :ok (join-thread t1))))) - -(with-test (:name :deadlock-detection.3 :skipped-on (not :sb-thread)) - (let* ((m1 (make-mutex :name "M1")) - (m2 (make-mutex :name "M2")) - (s1 (make-semaphore :name "S1")) - (s2 (make-semaphore :name "S2")) - (t1 (make-thread - (lambda () - (with-mutex (m1) - (signal-semaphore s1) - (wait-on-semaphore s2) - (with-mutex (m2) - :ok))) - :name "T1"))) - ;; Currently we don't consider it a deadlock - ;; if there is a timeout in the chain. - (assert (eq :deadline - (handler-case - (with-mutex (m2) - (signal-semaphore s2) - (wait-on-semaphore s1) - (sleep 1) - (sb-sys:with-deadline (:seconds 0.1) - (with-mutex (m1) - :ok))) - (sb-sys:deadline-timeout () - :deadline) - (thread-deadlock () - :deadlock)))) - (assert (eq :ok (join-thread t1))))) - #+sb-thread (with-test (:name :pass-arguments-to-thread) (assert (= 3 (join-thread (make-thread #'+ :arguments '(1 2)))))) @@ -490,10 +413,7 @@ (with-test (:name (wait-on-semaphore semaphore-notification :lp-1038034) :skipped-on (not :sb-thread) - ;; Maybe because they don't use futexes? - :fails-on (and :sb-thread - (not (or :darwin :openbsd :sunos))) - :broken-on :win32) + :broken-on :sb-safepoint) ;; Test robustness of semaphore acquisition and notification with ;; asynchronous thread termination... Which we know is currently ;; fragile. @@ -531,8 +451,8 @@ :timeout timeout :default :timeout)) (error "Hang in (join-thread ~A) ?" thread)))) - (safe-join-thread t1 :timeout 10) - (safe-join-thread t3 :timeout 10))))) + (safe-join-thread t1 :timeout 60) + (safe-join-thread t3 :timeout 60))))) (when (zerop (mod run 60)) (fresh-line) (write-string "; ")) @@ -577,3 +497,22 @@ (with-test (:name (abort-thread :main-thread)) (assert (main-thread-p)) (assert-error (abort-thread) thread-error)) + +;;; The OSes vary in how pthread_setname works. +;;; According to https://stackoverflow.com/questions/2369738/how-to-set-the-name-of-a-thread-in-linux-pthreads +;;; // NetBSD: name + arg work like printf(name, arg) +;;; int pthread_setname_np(pthread_t thread, const char *name, void *arg); +;;; // FreeBSD & OpenBSD: function name is slightly different, and has no return value +;;; void pthread_set_name_np(pthread_t tid, const char *name); +;;; // Mac OS X: must be set from within the thread (can't specify thread ID) +;;; int pthread_setname_np(const char*); +;;; Only Linux is implemented for now. +(with-test (:name :os-thread-name :skipped-on (:not (and :linux :sb-thread))) + (let ((thr + (make-thread + (lambda () + (with-open-file (stream (format nil "/proc/self/task/~d/comm" + (thread-os-tid *current-thread*))) + (read-line stream))) + :name "testme"))) + (assert (string= (join-thread thr) "testme")))) diff --git a/tests/timer.impure.lisp b/tests/timer.impure.lisp index 8583f6d9bb..04caf6ae2e 100644 --- a/tests/timer.impure.lisp +++ b/tests/timer.impure.lisp @@ -9,7 +9,7 @@ ;;;; absolutely no warranty. See the COPYING and CREDITS files for ;;;; more information. -#+interpreter (sb-ext:exit :code 104) +#+interpreter (invoke-restart 'run-tests::skip-file) (with-test (:name :heap) (let* ((size 1000) @@ -212,22 +212,6 @@ (mapc #'sb-thread:join-thread threads))))) (assert ok)))) -;;; FIXME: Since timeouts do not work on Windows this would loop -;;; forever. -(with-test (:name (:hash-cache :interrupt) :skipped-on :win32) - (let* ((type1 (random-type 500)) - (type2 (random-type 500)) - (wanted (subtypep type1 type2))) - (dotimes (i 100) - (block foo - (sb-ext:schedule-timer (sb-ext:make-timer - (lambda () - (assert (eq wanted (subtypep type1 type2))) - (return-from foo))) - 0.05) - (loop - (assert (eq wanted (subtypep type1 type2)))))))) - ;;; Used to hang occasionally at least on x86. Two bugs caused it: ;;; running out of stack (due to repeating timers being rescheduled ;;; before they ran) and dying threads were open interrupts. @@ -314,7 +298,7 @@ (dolist (thread threads) (sched thread))) (loop for thread in threads - do (sb-thread:join-thread thread :timeout 20)))))) + do (sb-thread:join-thread thread :timeout 40)))))) ;; A timer with a repeat interval can be configured to "catch up" in ;; case of missed calls. diff --git a/tests/trace.impure.lisp b/tests/trace.impure.lisp new file mode 100644 index 0000000000..072017d62f --- /dev/null +++ b/tests/trace.impure.lisp @@ -0,0 +1,42 @@ + +;;; Consider the following definitions in which we assign F2 and F3 +;;; the function binding of F1. +;;; Even if we were to agree that tracing of F2 and F3 should happen +;;; (which I think is wrong in itself), then what about SB-DEBUG::*TRACED-FUNS* ? +;;; It doesn't know that F2 and F3 are traced, which seems like a metadata bug. +;;; So then when we UNTRACE F1, we don't know that we're supposed to UNTRACE +;;; F2 and F3, so they continue to print the tracing output. +;;; And aside from that, when F2 or F3 would get invoked, the tracing output +;;; would suggest that F1 was called by name, which doesn't make a ton of sense, +;;; because first of all tracing is supposed to print the name of what was +;;; actually called - which coincidentally is bound to the same function object +;;; as some other global name - and secondly we just explicitly UNTRACEd the very +;;; name that it said was called. +;;; A reasonable solution to these bugs is to remove the tracing encapsulation +;;; when assigning SYMBOL-FUNCTION or FDEFINITION. Granted there are other +;;; encapsulations (profiling, e.g.) but this entire area is unspecified. + +(defparameter *count* 0) +(defun f1 () (incf *count*)) +(trace f1) +(setf (symbol-function 'f2) #'f1) +(setf (fdefinition 'f3) #'f1) + +(test-util:with-test (:name :strip-encap) + (let ((s (with-output-to-string (*trace-output*) + (f1)))) + (assert (search "F1 returned 1" s))) + (let ((s (with-output-to-string (*trace-output*) + (f2)))) + (assert (= (length s) 0))) + (let ((s (with-output-to-string (*trace-output*) + (f3)))) + (assert (= (length s) 0)))) + +(defvar *foo*) +;; this should keep the tracing encapsulation +(defun f1 () (setq *foo* 'invoked)) +(test-util:with-test (:name :no-strip-encap) + (let ((s (with-output-to-string (*trace-output*) + (f1)))) + (assert (search "F1 returned INVOKED" s)))) diff --git a/tests/traceroot.impure.lisp b/tests/traceroot.impure.lisp index e6edcca132..3ba7624e7f 100644 --- a/tests/traceroot.impure.lisp +++ b/tests/traceroot.impure.lisp @@ -15,7 +15,10 @@ ;;;; and I don't care too much why, since the functionality still works. ;;;; It's just that sometimes we get :PINNED as a root instead of ;;;; the expected reference to the one and only thread. -#-(and gencgc sb-thread (or ppc64 x86-64)) (sb-ext:exit :code 104) +;;;; And also sb-safepoint gets a crash in C. +#-(and gencgc sb-thread (not sb-safepoint) + (or (and arm64 (not darwin)) ppc64 x86-64)) +(invoke-restart 'run-tests::skip-file) (setq sb-ext:*evaluator-mode* :compile) (defvar *fred*) @@ -76,3 +79,55 @@ (with-test (:name (sb-ext:search-roots :stack-direct) :fails-on :sunos) (f0)) + +;;; Employ circumlocution so the file loader doesn't hold on to a string "hi" +(defvar *string-hi* (make-weak-pointer (concatenate 'string "h" "i"))) +(defstruct s1 foo) +(defparameter *top* + `(p q r w x y ,(make-s1 :foo `#((a b c ,(weak-pointer-value *string-hi*) d))) z)) + +;;; Sample output: +;;; Path to "hi": +;;; 6 1000209AB3 [ 1] a package-hashtable +;;; 1 10048F145F [ 29] a (simple-vector 37) +;;; 1 503B403F [ 2] COMMON-LISP-USER::*TOP* +;;; 0 1004B885B7 [ 6] a cons = (P Q R ...) ; = (NTHCDR 6 object) +;;; 0 1004B88617 [ 0] a cons = (# Z) +;;; 0 1004C1AA53 [ 1] a s1 +;;; 0 1004CBB93F [ 2] a (simple-vector 1) +;;; 0 1004D28AE7 [ 3] a cons = (A B C ...) ; = (NTHCDR 3 object) +;;; 0 1004D28B17 [ 0] a cons = ("hi" D) +(with-test (:name :traceroot-collapse-lists) + (let* ((string (with-output-to-string (*standard-output*) + (search-roots *string-hi* :print :verbose))) + (lines (split-string string #\newline))) + (assert + (loop for line in lines + thereis (search "[ 6] a cons = (P Q R ...)" line))) + (assert + (loop for line in lines + thereis (search "[ 3] a cons = (A B C ...)" line))))) + +(defun something () + (let ((a (make-symbol "x"))) + (gc) ; cause the symbol to be pinned + (make-weak-pointer a))) + +(with-test (:name :traceroot-old-pin-no-crash) + (let ((wp (something))) + (search-roots wp) + (something))) + +(defvar *foo*) +#+gencgc +(with-test (:name (sb-ext:search-roots :simple-fun) + :broken-on (and :darwin :arm64)) + ;; Tracing a path to a simple fun wasn't working at some point + ;; because of failure to employ fun_code_header in the right place. + (setq *foo* (compile nil '(lambda () 42))) + (let ((wp (sb-ext:make-weak-pointer *foo*))) + (assert (sb-ext:search-roots wp :criterion :oldest :print nil)))) + +#+gencgc +(with-test (:name (sb-ext:search-roots :ignore-immediate)) + (sb-ext:search-roots (make-weak-pointer 48) :gc t :print nil)) diff --git a/tests/type.before-xc.lisp b/tests/type.before-xc.lisp index 444ff57252..19cfbc5b88 100644 --- a/tests/type.before-xc.lisp +++ b/tests/type.before-xc.lisp @@ -21,6 +21,19 @@ (in-package "BEFORE-XC-TESTS") +;;; Assert that some of the type specifiers which we claim have unique internal +;;; representations do, and that parsing does not rely critically on +;;; memoization performed in SPECIFIER-TYPE, which is only a best effort +;;; to produce the EQ model object given an EQUAL specifier. +(dolist (type sb-kernel::*special-union-types*) + (dolist (constituent-type (union-type-types (specifier-type type))) + (let ((specifier (type-specifier constituent-type))) + (drop-all-hash-caches) + (let ((parse (specifier-type specifier))) + (drop-all-hash-caches) + (let ((reparse (specifier-type specifier))) + (aver (eq parse reparse))))))) + (assert (type= (specifier-type '(and fixnum (satisfies foo))) (specifier-type '(and (satisfies foo) fixnum)))) (assert (type= (specifier-type '(member 1 2 3)) @@ -417,6 +430,79 @@ (assert (= (sb-vm::immediate-constant-sc (complex $0.0d0 $0.0d0)) sb-vm::fp-complex-double-zero-sc-number))) -;;; Unparse a union of (up to) 4 things depending on :sb-unicode as 2 things. -(assert (equal (type-specifier (specifier-type '(or string null))) - '(or string null))) +;;; Unparse a union of (up to) 3 things depending on :sb-unicode as 2 things. +(assert (sb-kernel::brute-force-type-specifier-equalp + (type-specifier (specifier-type '(or string null))) + '(or #+sb-unicode string #-sb-unicode base-string null))) + +(multiple-value-bind (result exactp) + (sb-vm::primitive-type (specifier-type 'list)) + (assert (and (eq result (sb-vm::primitive-type-or-lose 'list)) + exactp))) +(multiple-value-bind (result exactp) + (sb-vm::primitive-type (specifier-type 'cons)) + (assert (and (eq result (sb-vm::primitive-type-or-lose 'list)) + (not exactp)))) + +(let ((bs (specifier-type 'base-string)) + (not-sbs (specifier-type '(not simple-base-string))) + (not-ss (specifier-type '(not simple-string)))) + (let ((intersect (type-intersection bs not-sbs))) + (assert (array-type-p intersect)) + (assert (type= intersect (specifier-type '(and base-string (not simple-array)))))) + ;; should be commutative + (let ((intersect (type-intersection not-sbs bs))) + (assert (array-type-p intersect)) + (assert (type= intersect (specifier-type '(and base-string (not simple-array)))))) + ;; test when the righthand side is a larger negation type + (let ((intersect (type-intersection bs not-ss))) + (assert (array-type-p intersect)) + (assert (type= intersect (specifier-type '(and base-string (not simple-array)))))) + (let ((intersect (type-intersection not-sbs bs))) + (assert (array-type-p intersect)) + (assert (type= intersect (specifier-type '(and base-string (not simple-array))))))) + +#+sb-unicode +(let ((cs (specifier-type 'sb-kernel::character-string)) + (not-scs (specifier-type '(not sb-kernel:simple-character-string))) + (not-ss (specifier-type '(not simple-string)))) + (let ((intersect (type-intersection cs not-scs))) + (assert (array-type-p intersect)) + (assert (type= intersect (specifier-type '(and sb-kernel::character-string (not simple-array)))))) + (let ((intersect (type-intersection not-scs cs))) + (assert (array-type-p intersect)) + (assert (type= intersect (specifier-type '(and sb-kernel::character-string (not simple-array)))))) + ;; test when the righthand side is a larger negation type + (let ((intersect (type-intersection cs not-ss))) + (assert (array-type-p intersect)) + (assert (type= intersect (specifier-type '(and sb-kernel::character-string (not simple-array)))))) + (let ((intersect (type-intersection not-ss cs))) + (assert (array-type-p intersect)) + (assert (type= intersect (specifier-type '(and sb-kernel::character-string (not simple-array))))))) + +#+sb-unicode +(let ((s (specifier-type 'string)) + (not-ss (specifier-type '(not simple-string)))) + (let ((intersect (type-intersection s not-ss))) + (assert (union-type-p intersect)) + (assert (type= intersect (specifier-type '(and string (not simple-array)))))) + (let ((intersect (type-intersection not-ss s))) + (assert (union-type-p intersect)) + (assert (type= intersect (specifier-type '(and string (not simple-array))))))) + +(let ((left (specifier-type '(array bit (2 2)))) + (right (specifier-type '(not (simple-array bit))))) + (let ((intersect (type-intersection left right))) + (assert (array-type-p intersect)) + (assert (type= intersect (specifier-type + '(and (array bit (2 2)) + (not simple-array))))))) + +;;; The instance-typep transform shouldn't need two different lowtag tests +;;; on instance types other than [funcallable-]standard-object. +;;; And for some reason we suppose that STREAM may be either funcallable or not. +(dolist (type '(pathname logical-pathname condition)) + (multiple-value-bind (answer certain) + (csubtypep (find-classoid type) (specifier-type 'funcallable-instance)) + (assert (and (not answer) certain))) + (aver (csubtypep (find-classoid type) (specifier-type 'instance)))) diff --git a/tests/type.impure.lisp b/tests/type.impure.lisp index 5084d170e3..75dddf5ebf 100644 --- a/tests/type.impure.lisp +++ b/tests/type.impure.lisp @@ -299,6 +299,14 @@ (define-condition condition-foo2 (condition-foo1) ()) (define-condition condition-foo3 (condition-foo2) ()) (define-condition condition-foo4 (condition-foo3) ()) +(with-test (:name :add-subclassoid) + (flet ((has-subs (name n) + (= n (length (sb-kernel:classoid-subclasses + (sb-kernel:find-classoid name)))))) + (assert (has-subs 'condition-foo1 3)) ; has foo{2,3,4} + (assert (has-subs 'condition-foo2 2)) ; has foo{3,4} + (assert (has-subs 'condition-foo3 1)) ; has foo4 + (assert (has-subs 'condition-foo4 0)))) ;;; inline type tests (format t "~&/setting up *TESTS-OF-INLINE-TYPE-TESTS*~%") @@ -348,7 +356,7 @@ (assert (subtypep 'simple-error 'error)) (assert (not (subtypep 'condition 'simple-condition))) (assert (not (subtypep 'error 'simple-error))) - (assert (eq (car (sb-pcl:class-direct-superclasses + (assert (eq (car (sb-mop:class-direct-superclasses (find-class 'simple-condition))) (find-class 'condition))) @@ -360,12 +368,12 @@ sb-int:simple-file-error sb-int:simple-style-warning)))) (assert (null (set-difference - (sb-pcl:class-direct-subclasses (find-class + (sb-mop:class-direct-subclasses (find-class 'simple-condition)) subclasses)))) ;; precedence lists - (assert (equal (sb-pcl:class-precedence-list + (assert (equal (sb-mop:class-precedence-list (find-class 'simple-condition)) (mapcar #'find-class '(simple-condition condition @@ -373,24 +381,24 @@ t)))) (sb-mop:finalize-inheritance (find-class 'fundamental-stream)) ;; stream classes - (assert (equal (sb-pcl:class-direct-superclasses (find-class + (assert (equal (sb-mop:class-direct-superclasses (find-class 'fundamental-stream)) (mapcar #'find-class '(standard-object stream)))) (assert (null (set-difference - (sb-pcl:class-direct-subclasses (find-class + (sb-mop:class-direct-subclasses (find-class 'fundamental-stream)) (mapcar #'find-class '(fundamental-binary-stream fundamental-character-stream fundamental-output-stream fundamental-input-stream))))) - (assert (equal (sb-pcl:class-precedence-list (find-class + (assert (equal (sb-mop:class-precedence-list (find-class 'fundamental-stream)) (mapcar #'find-class '(fundamental-stream standard-object sb-pcl::slot-object stream t)))) - (assert (equal (sb-pcl:class-precedence-list (find-class + (assert (equal (sb-mop:class-precedence-list (find-class 'fundamental-stream)) (mapcar #'find-class '(fundamental-stream standard-object @@ -887,8 +895,8 @@ (let ((result (sb-kernel:type-specifier (sb-kernel:specifier-type `(or list ,@(huge-union (lambda (x) `(array ,x (1 1 1))))))))) - (assert (or (equal result '(or cons null (array * (1 1 1)))) - (equal result '(or null cons (array * (1 1 1))))))) + (assert (or (equal result '(or list (array * (1 1 1)))) + (equal result '(or (array * (1 1 1)) list))))) ;; And unions of unions of distinct array types should reduce. (assert @@ -928,7 +936,8 @@ (let* ((hair (sb-kernel:specifier-type '(sb-kernel:unboxed-array 1))) (xform (sb-c::source-transform-union-typep 'myobj hair))) (assert (equal xform - '(or (typep myobj '(and vector (not (array t)))))))) + '(or (typep myobj + '(and vector (not (array t)) (not (array nil)))))))) ;; Exclude one subtype at a time and make sure they all work. (dotimes (i (length sb-vm:*specialized-array-element-type-properties*)) @@ -1002,3 +1011,23 @@ (assert (handler-case (not (sb-kernel:specifier-type class)) (sb-kernel:parse-unknown-type () t))))) + +;;; Try depthoid in excess of sb-kernel::layout-id-vector-fixed-capacity +(defstruct d2) ; depthoid = 2 +(defstruct (d3(:include d2))) ; = 3 +(defstruct (d4(:include d3))) ; and so on +(defstruct (d5(:include d4))) +(defstruct (d6(:include d5))) +(defstruct (d7(:include d6))) +(defstruct (d8(:include d7))) +(compile 'd8-p) +(with-test (:name :deep-structure-is-a) + (assert (d8-p (opaque-identity (make-d8))))) + +(with-test (:name :intersection-complex-=) + (let ((unk (sb-kernel:specifier-type '(and unknown unknown2)))) + (assert-tri-eq nil nil (sb-kernel:type= (sb-kernel:specifier-type t) unk)) + (assert-tri-eq nil nil (sb-kernel:type= (sb-kernel:specifier-type 'integer) unk)) + (assert-tri-eq nil nil (sb-kernel:type= (sb-kernel:specifier-type 'float) unk)) + (assert-tri-eq nil nil (sb-kernel:type= (sb-kernel:specifier-type 'pathname) unk)) + (assert-tri-eq nil nil (sb-kernel:type= (sb-kernel:specifier-type 'sequence) unk)))) diff --git a/tests/type.pure.lisp b/tests/type.pure.lisp index f74a59705c..10051e54ee 100644 --- a/tests/type.pure.lisp +++ b/tests/type.pure.lisp @@ -15,6 +15,16 @@ (flet ((try (f) (assert-error (funcall f 'hash-table 3)))) (mapc #'try '(typexpand-1 typexpand typexpand-all)))) +(with-test (:name :no-*-as-t) ; lp#1860919 + (assert-signal (sb-kernel:specifier-type '(function (*) t)) warning) + (dolist (f '((lambda (x) (the * x)) + (lambda (x) (declare (* x)) x) + (lambda (x) (declare (type * x)) x))) + (multiple-value-bind (f warn err) + (let ((*error-output* (make-broadcast-stream))) (compile nil f)) + (declare (ignore f)) + (assert (and warn err))))) + (with-test (:name (typep sb-kernel:ctypep)) (locally (declare (notinline mapcar)) @@ -157,7 +167,7 @@ (assert-tri-eq t t (subtypep '(function ()) '(function (&rest t)))) (assert-tri-eq nil t (subtypep '(function (&rest t)) '(function ()))) (assert-tri-eq t t (subtypep '(function) - '(function (&optional * &rest t)))) + '(function (&optional t &rest t)))) (assert-tri-eq nil t (subtypep '(function) '(function (t &rest t)))) (assert-tri-eq t t (subtypep 'function '(function))) (assert-tri-eq t t (subtypep '(function) 'function))) @@ -320,6 +330,15 @@ (assert (eq yes cyes)) (assert (eq win cwin))))) +(with-test (:name :intelligent-satisfies) + (assert (sb-kernel:type= (sb-kernel:specifier-type '(satisfies realp)) + (sb-kernel:specifier-type 'real))) + ;; Part of an example in https://bugs.launchpad.net/sbcl/+bug/309455 + (multiple-value-bind (answer certain) + (subtypep 'complex '(and number (satisfies realp))) + (assert (not answer)) + (assert certain))) + ;;; CONS type SUBTYPEP could be too enthusiastic about thinking it was ;;; certain (with-test (:name (subtypep cons satisfies)) @@ -530,7 +549,9 @@ ;; lp#1333731 (with-test (:name (adjust-array :changes type-of)) - (let ((a (make-array 10 :adjustable t))) + ;; I think adjusting an array to enlarge it must read all the old data, + ;; which would be undefined behavior if you hadn't initialized the array. + (let ((a (make-array 10 :adjustable t :initial-element 0))) (assert (equal (type-of a) '(vector t 10))) (adjust-array a 20) (assert (equal (type-of a) '(vector t 20))))) @@ -615,7 +636,7 @@ (values bit &optional *) (values bit &rest *) (values bit &rest *))) - (assert-error (sb-kernel:values-specifier-type x)))) + (assert-signal (sb-kernel:values-specifier-type x) warning))) (with-test (:name :classoids-as-type-specifiers) (dolist (classoid (list (find-classoid 'integer) @@ -649,15 +670,58 @@ (assert (eq (sb-int:info :type :kind s) :primitive)) (assert (eq (sb-int:info :type :kind s) :instance))))))) -(with-test (:name :make-numeric-type) +(with-test (:name (make-numeric-type :smoke)) (assert (eq (make-numeric-type :class 'integer :low '(4) :high '(5)) *empty-type*))) +(with-test (:name (make-numeric-type :union)) + (assert (equal (type-specifier (make-numeric-type :low '(-79106810381456307))) + `(or (rational (-79106810381456307)) + (single-float (-7.910681e16)) + (double-float (-7.91068103814563d16)))))) + +(with-test (:name (make-numeric-type :infinities)) + ;; Without class + (assert (equal (type-specifier + (make-numeric-type :low sb-ext:single-float-negative-infinity + :high sb-ext:single-float-negative-infinity)) + `(or (single-float ,sb-ext:single-float-negative-infinity + ,sb-ext:single-float-negative-infinity) + (double-float ,sb-ext:double-float-negative-infinity + ,sb-ext:double-float-negative-infinity)))) + (assert (equal (type-specifier + (make-numeric-type :low sb-ext:single-float-negative-infinity)) + 'real)) + ;; With FLOAT class + (assert (equal (type-specifier + (make-numeric-type :class 'float + :low sb-ext:single-float-negative-infinity + :high sb-ext:single-float-negative-infinity)) + `(or (single-float ,sb-ext:single-float-negative-infinity + ,sb-ext:single-float-negative-infinity) + (double-float ,sb-ext:double-float-negative-infinity + ,sb-ext:double-float-negative-infinity)))) + (assert (equal (type-specifier + (make-numeric-type :class 'float + :low sb-ext:single-float-negative-infinity)) + `float))) + +(with-test (:name :prettier-union-types :skipped-on (not :sb-unicode)) + ;; (OR STRING BIGNUM) used to unparse as + ;; (OR (VECTOR CHARACTER) BASE-STRING (INTEGER * -4611686018427387905) + ;; (INTEGER 4611686018427387904)) etc + (dolist (other '(float real bignum)) + (let* ((spec `(or string ,other)) + (parse (sb-kernel:specifier-type spec)) + (unparse (sb-kernel:type-specifier parse))) + (assert (or (equal unparse `(or string ,other)) + (equal unparse `(or ,other string))))))) + (with-test (:name :unparse-string) (assert (equal (type-specifier (specifier-type '(string 10))) - '(string 10))) + '(#+sb-unicode string #-sb-unicode base-string 10))) (assert (equal (type-specifier (specifier-type '(simple-string 10))) - '(simple-string 10)))) + '(#+sb-unicode simple-string #-sb-unicode simple-base-string 10)))) (with-test (:name :numeric-types-adjacent) (dolist (x '(-0s0 0s0)) @@ -689,3 +753,67 @@ (with-test (:name :pathnamep-flag-bit) (let ((f (compile nil '(lambda (x) (pathnamep x))))) (assert (not (ctu:find-code-constants f))))) + +(with-test (:name :structure-is-a) + (dolist (what '(sb-int:sset-element sb-c::leaf sb-c::functional + sb-c::optional-dispatch)) + (assert (eval `(sb-c::%structure-is-a ,(sb-kernel:find-layout 'sb-c::optional-dispatch) + ,(sb-kernel:find-layout what)))))) + +(with-test (:name :type-of-empty-instance) + (assert (eq (type-of (eval '(sb-kernel:%make-funcallable-instance 6))) + 'sb-kernel:funcallable-instance)) + (assert (eq (type-of (eval '(sb-kernel:%make-instance 12))) + 'sb-kernel:instance))) + +(with-test (:name (:cons-union :lp1912863)) + (let ((c (cons 2 4))) + (assert (not (typep c '(or (cons (integer 0 8) (integer 5 15)) + (cons (integer 3 15) (integer 4 14)))))))) + +(with-test (:name (:rational-union :equivalent-to-t)) + (let ((type '(or (integer * -1) (rational -1/2 1/2) (integer 1) (not integer)))) + (assert-tri-eq t t (subtypep t type)))) + +(with-test (:name (:rational-union :no-integers-in-rational)) + (let ((type '(or (integer 1 1) (rational 1/2 1/2)))) + (assert-tri-eq t t (subtypep type 'rational)) + (assert-tri-eq nil t (subtypep 'rational type)) + (assert-tri-eq nil t (subtypep type 'integer)) + (assert-tri-eq nil t (subtypep 'integer type)) + (assert (typep 1 type)) + (assert (typep 1/2 type)) + (assert (not (typep 3/4 type))))) + +(with-test (:name (:rational-union :open-bounds-closed)) + (let ((t1 '(rational -1 1)) + (t2 '(or (integer -1 1) (rational (-1) (1))))) + (assert-tri-eq t t (subtypep t1 t2)) + (assert-tri-eq t t (subtypep t2 t1)))) + +(with-test (:name (:rational-union :lp1912863 :bug039)) + (flet ((bug039 () + (let ((t1 'cons) + (t2 '(or (not (cons t (real -1 1))) + (not (cons sequence (eql 2)))))) + (assert-tri-eq t t (subtypep t1 t2)) + (assert-tri-eq t t (subtypep `(not ,t2) `(not ,t1)))))))) + +(with-test (:name (:rational-union :lp1912863 :bug041)) + (flet ((bug041 () + (let ((t1 '(not (cons t integer))) + (t2 '(not (cons (array nil) (eql 0)))) + (t3 '(cons simple-array t))) + (assert-tri-eq t t (subtypep t1 t2)) + (assert-tri-eq t t (subtypep `(not (or ,t2 ,t3)) `(not ,t1))) + (assert-tri-eq t t (subtypep `(and (not ,t2) (not ,t3)) `(not ,t1)))))))) + +(with-test (:name (:lp1916040 :answer)) + (let* ((t1 '(cons sequence short-float)) + (t2 '(or (cons t atom) (cons function t))) + (answer (multiple-value-list (subtypep t1 t2)))) + (assert (member answer '((nil nil) (t t)) :test 'equal)))) + +(with-test (:name (:lp1916233)) + (assert-tri-eq t t (subtypep '(cons (or (simple-array ratio) simple-array) nil) nil)) + (assert-tri-eq t t (subtypep '(or (array ratio) sequence) t))) diff --git a/tests/typep-golden-data.txt b/tests/typep-golden-data.txt new file mode 100644 index 0000000000..8889338c4d --- /dev/null +++ b/tests/typep-golden-data.txt @@ -0,0 +1,723 @@ + 14 (ALIEN SB-UNIX:UNIX-OFFSET) + 39 (AND (NOT SINGLE-FLOAT) (REAL 0 1152921504606)) + 21 (AND (SIGNED-BYTE 8) (NOT (EQL 0))) +! 22 (AND (VECTOR T) (NOT SIMPLE-ARRAY)) + 27 (AND ARRAY (NOT (ARRAY T))) + 26 (AND ARRAY (NOT (VECTOR CHARACTER)) (NOT BASE-STRING) (NOT BIT-VECTOR)) +! 22 (AND CONS (SATISFIES LEGAL-FUN-NAME-P)) + 9 (AND FIXNUM UNSIGNED-BYTE) + 16 (AND FUNCTION (NOT FUNCALLABLE-INSTANCE)) + 32 (AND INTEGER (NOT (SIGNED-BYTE 31))) + 32 (AND INTEGER (NOT (SIGNED-BYTE 32))) + 15 (AND FUNCALLABLE-INSTANCE (NOT INTERPRETED-FUNCTION)) + 21 (AND LAYOUT-ID (NOT (EQL 0))) + 15 (AND STRING (NOT SIMPLE-ARRAY)) + 17 (AND SYMBOL (NOT (EQL T))) + 24 (AND SYMBOL (NOT KEYWORD) (NOT NULL)) + 12 (AND SYMBOL (NOT NULL)) +! 23 (AND SYMBOL (SATISFIES FBOUNDP)) +! 23 (AND SYMBOL (SATISFIES MACRO-FUNCTION)) + 43 (AND VECTOR (NOT (ARRAY T)) (NOT (ARRAY NIL))) + 23 (AND VECTOR (NOT STRING)) +! 29 (AND WARNING (NOT REDEFINITION-WARNING)) + 27 (ARRAY BIT) + 15 (ARRAY CHARACTER (*)) +! 5 (ARRAY NIL (*)) + 27 (ARRAY NIL) + 27 (ARRAY T *) + 27 (ARRAY T) + 12 (COMPLEX DOUBLE-FLOAT) + 12 (COMPLEX RATIONAL) + 12 (COMPLEX SINGLE-FLOAT) + 21 (CONS (MEMBER FUNCTION FUNCTION-DESIGNATOR SB-C::MODIFYING SB-C::INHIBIT-FLUSHING) T) + 37 (CONS (AND SYMBOL (NOT NULL)) (OR NULL (CONS STRING NULL))) + 20 (CONS (CONS (MEMBER LAMBDA) T) NULL) + 38 (CONS (CONS (MEMBER QUOTE) (CONS SYMBOL NULL)) NULL) + 21 (CONS (CONS * (MOD 65536)) NULL) + 17 (CONS (EQL *) NULL) + 20 (CONS (EQL :ABSOLUTE) (CONS (EQL :HOME))) + 12 (CONS (EQL :AFTER-SC-SELECTION)) + 12 (CONS (EQL :BEGIN-FILE)) + 12 (CONS (EQL :CHARACTER-SET)) + 12 (CONS (EQL :CONDITIONAL)) + 12 (CONS (EQL :CONTEXT)) + 29 (CONS (EQL :HOME) (CONS STRING NULL)) + 23 (CONS (EQL :INITIAL-ELEMENT) (CONS T NULL)) + 12 (CONS (EQL :LOAD-TIME-VALUE)) + 12 (CONS (EQL :LOAD-TIME-VALUE-FIXUP)) + 12 (CONS (EQL :STRUCT-READ)) + 23 (CONS (EQL :TEST) (CONS T NULL)) + 64 (CONS (EQL BYTE) (AND (NOT (CONS INTEGER (CONS INTEGER))) (CONS T (CONS T NULL)))) + 23 (CONS (EQL CLASS) (CONS T NULL)) + 23 (CONS (EQL EQL) (CONS T NULL)) + 12 (CONS (EQL EQL)) + 45 (CONS (EQL FIND-CLASS) (CONS (CONS (EQL QUOTE) (CONS SYMBOL NULL)) NULL)) + 27 (CONS (EQL FUNCTION) (CONS (CONS (EQL LAMBDA)) NULL)) + 23 (CONS (EQL FUNCTION) (CONS * NULL)) + 31 (CONS (EQL FUNCTION) (CONS SYMBOL NULL)) + 23 (CONS (EQL FUNCTION) (CONS T NULL)) + 12 (CONS (EQL FUNCTION)) + 24 (CONS (EQL LAMBDA) (CONS LIST)) + 12 (CONS (EQL LAMBDA)) + 12 (CONS (EQL LIST)) + 20 (CONS (EQL LIST*) CONS) + 18 (CONS (EQL LIST*) LIST) + 12 (CONS (EQL LOAD-TIME-VALUE)) + 23 (CONS (EQL MULTIPLE-VALUE-LIST) (CONS T NULL)) + 16 (CONS (EQL NIL)) + 12 (CONS (EQL NOT)) + 12 (CONS (EQL OR)) + 23 (CONS (EQL QUOTE) (CONS T NULL)) + 12 (CONS (EQL QUOTE)) + 23 (CONS (EQL SATISFIES) (CONS T NULL)) + 12 (CONS (EQL SATISFIES)) + 12 (CONS (EQL SB-C::COVERAGE-MAP)) + 23 (CONS (EQL SB-C::LAMBDA-LIST) (CONS T NULL)) + 12 (CONS (EQL SB-C::LOCAL-OPTIMIZE)) + 12 (CONS (EQL SB-C::SOURCE-FORM)) + 12 (CONS (EQL SB-C::VOP-OPTIMIZE)) + 12 (CONS (EQL SB-C:LAMBDA-WITH-LEXENV)) + 12 (CONS (EQL EXPLICIT-CHECK)) + 23 (CONS (EQL QUASIQUOTE) (CONS T NULL)) + 12 (CONS (EQL SB-PCL::.PV.)) + 23 (CONS (EQL SB-PCL::CLASS-EQ) (CONS T NULL)) + 12 (CONS (EQL SB-PCL::FAST-METHOD)) + 23 (CONS (EQL SB-PCL::PROTOTYPE) (CONS T NULL)) + 12 (CONS (EQL SB-PCL::SLOT-ACCESSOR)) + 12 (CONS (EQL MACRO)) + 31 (CONS (EQL SETF) (CONS SYMBOL NULL)) + 20 (CONS (EQL SETF) CONS) + 12 (CONS (EQL SETF)) + 35 (CONS (EQL SETQ) (CONS SYMBOL (CONS T NULL))) + 12 (CONS (EQL TERPRI)) + 27 (CONS (EQL THE) (CONS T (CONS T NULL))) + 28 (CONS (EQL VALUES) (CONS T (CONS (EQL &OPTIONAL) NULL))) + 12 (CONS (EQL VALUES)) + 17 (CONS (MEMBER &OPTIONAL) NULL) + 22 (CONS (MEMBER :CHARACTER-SET) STRING) + 12 (CONS (MEMBER :HOME) T) + 12 (CONS (MEMBER :MULTIPLE) T) + 17 (CONS (MEMBER AND INTERSECTION)) + 26 (CONS (MEMBER AND OR) (CONS T NULL)) + 34 (CONS (MEMBER FUNCTION QUOTE) (CONS SYMBOL NULL)) + 26 (CONS (MEMBER FUNCTION QUOTE) (CONS T NULL)) + 26 (CONS (MEMBER FUNCTION SB-C::GLOBAL-FUNCTION) (CONS T NULL)) +! 35 (CONS (MEMBER FUNCTION) (CONS (SATISFIES LEGAL-FUN-NAME-P) NULL)) + 12 (CONS (MEMBER FUNCTION) T) + 19 (CONS (MEMBER LAMBDA NAMED-LAMBDA SB-C:LAMBDA-WITH-LEXENV)) + 19 (CONS (MEMBER LAMBDA NAMED-LAMBDA SB-IMPL::LAMBDA-WITH-LEXENV)) + 17 (CONS (MEMBER LAMBDA NAMED-LAMBDA) T) + 12 (CONS (MEMBER LAMBDA) T) + 17 (CONS (MEMBER LIST VECTOR)) + 17 (CONS (MEMBER OR UNION)) + 31 (CONS (MEMBER QUOTE) (CONS SYMBOL NULL)) + 17 (CONS (MEMBER SB-C::XEP SB-C::TL-XEP)) + 17 (CONS (MEMBER SB-PCL::SLOW-METHOD SB-PCL::FAST-METHOD)) + 32 (CONS (MEMBER WRITE-STRING WRITE-CHAR) (CONS (OR STRING CHARACTER))) + 28 (CONS (NOT INTEGER) (CONS T NULL)) + 24 (CONS (NOT INTEGER) NULL) + 22 (CONS (OR STRING CHARACTER) T) + 24 (CONS (OR STRING NULL) T) +! 27 (CONS (SATISFIES LEGAL-FUN-NAME-P) NULL) + 25 (CONS ATOM ATOM) + 17 (CONS CONS) + 36 (CONS INTEGER (CONS (NOT INTEGER) NULL)) + 22 (CONS INTEGER NULL) + 19 (CONS INTEGER) + 19 (CONS KEYWORD T) + 19 (CONS KEYWORD) + 25 (CONS LIST (CONS LIST)) + 17 (CONS LIST T) + 24 (CONS REAL NULL) + 21 (CONS SB-ALIEN::CALLING-CONVENTION *) + 23 (CONS SIMPLE-VECTOR SIMPLE-VECTOR) + 34 (CONS STRING (CONS STRING NULL)) + 22 (CONS STRING NULL) + 21 (CONS T (CONS (MEMBER &OPTIONAL) NULL)) + 24 (CONS T (CONS T (CONS T NULL))) + 18 (CONS T (CONS T (EQL DEFINE-COMPILER-MACRO))) + 20 (CONS T (CONS T NULL)) + 14 (CONS T (EQL :DEFAULT)) + 14 (CONS T (MEMBER DEFINE-COMPILER-MACRO)) + 26 (CONS T (OR STRING NULL (SATISFIES UNBOUND-MARKER-P))) + 24 (CONS T (OR STRING NULL)) + 14 (CONS T (UNSIGNED-BYTE 16)) + 17 (CONS T CONS) + 16 (CONS T NULL) + 17 (CONS T SIMPLE-VECTOR) + 19 (CONS T STRING) + 22 (DOUBLE-FLOAT (-1.0d0) (0.0d0)) + 18 (DOUBLE-FLOAT (0.0d0)) + 17 (DOUBLE-FLOAT (1.0d0)) + 21 (DOUBLE-FLOAT -9.007199254740992d15 9.007199254740991d15) + 22 (DOUBLE-FLOAT 0.0d0 1.0d0) + 22 (DOUBLE-FLOAT 0.0d0 1.152921504606d12) + 22 (DOUBLE-FLOAT 0.0d0 4.611686018427388d18) + 18 (DOUBLE-FLOAT 0.0d0) + 9 (EQL 0) + 9 (EQL :AREF) + 9 (EQL :BPT-LRA) + 9 (EQL :FTYPE) + 9 (EQL :GOOD) + 9 (EQL :KNOWN-FUN) + 9 (EQL :LONG-NOP) + 9 (EQL :MULTI-CHAR-WILD) + 9 (EQL :SINGLE-CHAR-WILD) + 9 (EQL :WILD) + 9 (EQL :WILD-INFERIORS) + 9 (EQL T) + 18 (INTEGER (0) *) + 9 (INTEGER (63) 64) + 18 (INTEGER * -1) + 18 (INTEGER * -1000000) + 18 (INTEGER * -1073741825) + 18 (INTEGER * -12) + 18 (INTEGER * -14) + 18 (INTEGER * -17) + 18 (INTEGER * -2) + 18 (INTEGER * -2147483649) + 18 (INTEGER * -4611686018427387901) + 18 (INTEGER * -4611686018427387905) + 18 (INTEGER * -54043195528445951) + 18 (INTEGER * -541073411) + 18 (INTEGER * -6) + 18 (INTEGER * -9) + 18 (INTEGER * -9223372036854775809) + 24 (INTEGER * 0) + 18 (INTEGER * 18446744073709551615) + 18 (INTEGER * 20) + 18 (INTEGER * 2047) + 18 (INTEGER * 2147483647) + 18 (INTEGER * 4611686018427387900) + 18 (INTEGER * 576460752303423487) + 18 (INTEGER * 65535) + 18 (INTEGER -1) + 15 (INTEGER -128 -1) + 15 (INTEGER -128 255) + 15 (INTEGER -2147483648 4294967295) + 15 (INTEGER -536870912 -1) + 22 (INTEGER 0 *) + 9 (INTEGER 0 0) + 12 (INTEGER 0 100000) + 12 (INTEGER 0 2305843009213) + 22 (INTEGER 0) + 12 (INTEGER 1 127) + 12 (INTEGER 1 15) + 12 (INTEGER 1 2) + 14 (INTEGER 1 4611686018427387900) + 12 (INTEGER 1 536870911) + 12 (INTEGER 1 63) + 18 (INTEGER 1) + 18 (INTEGER 1073741824) + 18 (INTEGER 1152921504606846961) + 9 (INTEGER 16 16) + 30 (INTEGER 18446744071562067968 18446744073709551615) + 18 (INTEGER 18446744073709551617) + 18 (INTEGER 18446744073709551621) + 18 (INTEGER 1899) + 18 (INTEGER 2) + 18 (INTEGER 2147483648) + 18 (INTEGER 23058430092136939456) + 18 (INTEGER 2305843009214) + 18 (INTEGER 27670116110564327423) + 18 (INTEGER 36893488147419103231) + 9 (INTEGER 4 4) + 15 (INTEGER 4294967168 4294967295) + 18 (INTEGER 4611686018427387900) + 18 (INTEGER 4611686018427387901) + 18 (INTEGER 4611686018427387902) + 18 (INTEGER 4611686018427387903) + 18 (INTEGER 4611686018427387904) + 15 (INTEGER 5 14) + 18 (INTEGER 63) + 15 (INTEGER 65408 65535) + 9 (INTEGER 8 8) + 9 (MEMBER &OPTIONAL) + 9 (MEMBER *) + 12 (MEMBER 3 4) + 9 (MEMBER :ABSOLUTE) + 9 (MEMBER :AFTER-SC-SELECTION) + 14 (MEMBER :ALWAYS-THREAD-LOCAL T NIL) + 9 (MEMBER :ALWAYS-THREAD-LOCAL) + 9 (MEMBER :BACK) + 9 (MEMBER :BEGIN-FILE) + 9 (MEMBER :BOGUS) + 14 (MEMBER :CDECL :STDCALL NIL) + 9 (MEMBER :CHARACTER-SET) + 9 (MEMBER :CODE) + 9 (MEMBER :CONDITIONAL) + 9 (MEMBER :CONSTRUCTOR) + 9 (MEMBER :CONTEXT) + 12 (MEMBER :DEFAULT :IGNORE) + 9 (MEMBER :DEFAULT) + 9 (MEMBER :GENERIC-FUNCTION) + 9 (MEMBER :HIGH-BYTE) + 9 (MEMBER :HOME) + 9 (MEMBER :INITIAL-ELEMENT) + 12 (MEMBER :INITIALIZING NIL) + 12 (MEMBER :LISP :STREAM) + 12 (MEMBER :LISP NIL) + 9 (MEMBER :LOAD-TIME-VALUE) + 9 (MEMBER :LOAD-TIME-VALUE-FIXUP) + 9 (MEMBER :LONG-NOP) + 12 (MEMBER :MULTI-CHAR-WILD :SINGLE-CHAR-WILD) + 9 (MEMBER :MULTI-CHAR-WILD) + 9 (MEMBER :MULTIPLE) + 12 (MEMBER :NAMED-CALL :FDEFINITION) + 18 (MEMBER :NEWEST :UNC :WILD :UNSPECIFIC NIL) + 9 (MEMBER :NEWEST) + 12 (MEMBER :NONE NIL) + 9 (MEMBER :SINGLE-CHAR-WILD) + 12 (MEMBER :START :END) + 9 (MEMBER :STRUCT-READ) + 9 (MEMBER :TEST) + 16 (MEMBER :TRAP :UNBOUND :SAFE-DEFAULT :UNSAFE-DEFAULT) + 9 (MEMBER :UNC) + 9 (MEMBER :UNKNOWN) + 12 (MEMBER :UNPARSED NIL) + 9 (MEMBER :UNPARSED) + 16 (MEMBER :UNSPECIFIC :WILD :NEWEST NIL) + 9 (MEMBER :UNSPECIFIC) + 14 (MEMBER :UNSPECIFIED NIL T) + 9 (MEMBER :UNSPECIFIED) + 12 (MEMBER :UNTAGGED :TAGGED) + 12 (MEMBER :UP :BACK) + 9 (MEMBER :UP) + 14 (MEMBER :WILD :WILD-INFERIORS :UP) + 12 (MEMBER :WILD :WILD-INFERIORS) + 9 (MEMBER :WILD) + 9 (MEMBER :WILD-INFERIORS) + 12 (MEMBER AND INTERSECTION) + 12 (MEMBER AND OR) + 9 (MEMBER BYTE) + 9 (MEMBER CLASS) + 9 (MEMBER DECLARE) + 9 (MEMBER DEFINE-COMPILER-MACRO) + 9 (MEMBER EQL) + 9 (MEMBER FIND-CLASS) + 12 (MEMBER FUNCTION QUOTE) + 12 (MEMBER FUNCTION SB-C::GLOBAL-FUNCTION) + 16 (MEMBER FUNCTION FUNCTION-DESIGNATOR SB-C::MODIFYING SB-C::INHIBIT-FLUSHING) + 9 (MEMBER FUNCTION) + 14 (MEMBER LAMBDA NAMED-LAMBDA SB-C:LAMBDA-WITH-LEXENV) + 14 (MEMBER LAMBDA NAMED-LAMBDA SB-IMPL::LAMBDA-WITH-LEXENV) + 12 (MEMBER LAMBDA NAMED-LAMBDA) + 9 (MEMBER LAMBDA) + 12 (MEMBER LIST VECTOR) + 9 (MEMBER LIST) + 9 (MEMBER LIST*) + 9 (MEMBER LOAD-TIME-VALUE) + 9 (MEMBER MULTIPLE-VALUE-LIST) + 16 (MEMBER NIL :NEWEST :WILD :UNSPECIFIC) + 14 (MEMBER NIL :START :END) + 12 (MEMBER NIL :START) + 12 (MEMBER NIL :UNPARSED) + 16 (MEMBER NIL :UNSPECIFIC :WILD :UNC) + 14 (MEMBER NIL :UNSPECIFIC :WILD) + 12 (MEMBER NIL :WILD) + 14 (MEMBER NIL T :ALWAYS-THREAD-LOCAL) + 9 (MEMBER NOT) + 12 (MEMBER OR UNION) + 9 (MEMBER OR) + 9 (MEMBER QUOTE) + 9 (MEMBER SATISFIES) + 9 (MEMBER SB-C::COVERAGE-MAP) + 9 (MEMBER SB-C::LAMBDA-LIST) + 9 (MEMBER SB-C::LOCAL-OPTIMIZE) + 9 (MEMBER SB-C::SOURCE-FORM) + 9 (MEMBER SB-C::VOP-OPTIMIZE) + 12 (MEMBER SB-C::XEP SB-C::TL-XEP) + 9 (MEMBER SB-C:LAMBDA-WITH-LEXENV) + 9 (MEMBER EXPLICIT-CHECK) + 9 (MEMBER QUASIQUOTE) + 18 (MEMBER TYPE-SPECIFIER SB-C::PROPER-SEQUENCE SB-C::PROPER-LIST SB-C::PROPER-OR-DOTTED-LIST SB-C::PROPER-OR-CIRCULAR-LIST) + 9 (MEMBER SB-PCL::.PV.) + 9 (MEMBER SB-PCL::CLASS-EQ) + 9 (MEMBER SB-PCL::FAST-METHOD) + 9 (MEMBER SB-PCL::PROTOTYPE) + 9 (MEMBER SB-PCL::SLOT-ACCESSOR) + 12 (MEMBER SB-PCL::SLOW-METHOD SB-PCL::FAST-METHOD) + 9 (MEMBER MACRO) + 9 (MEMBER SETF) + 9 (MEMBER SETQ) + 9 (MEMBER T) + 9 (MEMBER TERPRI) + 9 (MEMBER THE) + 9 (MEMBER VALUES) + 12 (MEMBER WRITE-STRING WRITE-CHAR) + 12 (MOD 100) + 12 (MOD 1114112) + 9 (MOD 128) + 12 (MOD 21) + 12 (MOD 36) + 12 (MOD 4611686018427387900) + 12 (MOD 4611686018427387901) + 27 (NOT (ARRAY NIL)) + 27 (NOT (ARRAY T)) + 9 (NOT (MEMBER T)) + 14 (NOT (SATISFIES KEYWORDP)) +! 16 (NOT (SATISFIES LEGAL-FUN-NAME-P)) + 14 (NOT (VECTOR CHARACTER)) + 14 (NOT BASE-STRING) + 16 (NOT BIT-VECTOR) + 9 (NOT CHARACTER) + 13 (NOT COMPILED-FUNCTION) + 15 (NOT INTEGER) + 10 (NOT LIST) + 9 (NOT NULL) + 17 (NOT NUMBER) +! 15 (NOT EXTENDED-SEQUENCE) + 12 (NOT FUNCALLABLE-INSTANCE) + 10 (NOT INSTANCE) + 13 (NOT INTERPRETED-FUNCTION) +! 16 (NOT REDEFINITION-WARNING) + 14 (NOT SIMPLE-ARRAY) + 12 (NOT SIMPLE-VECTOR) + 14 (NOT STRING) + 14 (NOT SYMBOL) + 14 (NOT VECTOR) + 31 (OR (CONS (MEMBER FUNCTION FUNCTION-DESIGNATOR SB-C::MODIFYING SB-C::INHIBIT-FLUSHING)) (MEMBER TYPE-SPECIFIER SB-C::PROPER-SEQUENCE SB-C::PROPER-LIST SB-C::PROPER-OR-DOTTED-LIST SB-C::PROPER-OR-CIRCULAR-LIST)) + 21 (OR (ALIEN SB-UNIX:UNIX-OFFSET) (MEMBER NIL :START :END)) + 20 (OR (CONS (EQL DECLARE)) STRING) +! 66 (OR (CONS (EQL FUNCTION) (CONS (SATISFIES LEGAL-FUN-NAME-P) NULL)) (CONS (EQL QUOTE) (CONS SYMBOL NULL)) (CONS (EQL LAMBDA))) + 12 (OR (CONS (MEMBER DECLARE) T)) + 31 (OR (CONS (MEMBER FUNCTION) (CONS SYMBOL NULL))) + 22 (OR (CONS (MEMBER LAMBDA NAMED-LAMBDA)) INTERPRETED-FUNCTION) + 57 (OR (CONS (NOT INTEGER) (CONS T NULL)) (CONS INTEGER (CONS (NOT INTEGER) NULL))) + 12 (OR (EQL :ALWAYS-THREAD-LOCAL) FIXNUM) + 15 (OR (EQL :HOME) (CONS (EQL :HOME))) + 15 (OR (EQL :MULTIPLE) (CONS (EQL :MULTIPLE))) + 16 (OR (EQL :WILD) SB-IMPL::PATTERN) + 12 (OR (INTEGER -4611686018427387904 4611686018427387903) CHARACTER) + 18 (OR (INTEGER 1 15) SB-X86-64-ASM::REG) + 9 (OR (MEMBER *)) + 9 (OR (MEMBER :CONDITIONAL)) + 9 (OR (MEMBER :DEFAULT)) + 12 (OR (MEMBER :STANDARD :FIXED)) + 9 (OR (MEMBER :UNKNOWN)) + 12 (OR (MEMBER :UNPARSED :FOO)) + 12 (OR (MEMBER :UNPARSED NIL)) + 9 (OR (MEMBER :UNPARSED)) + 14 (OR (MEMBER :UNSPECIFIC :WILD NIL)) + 12 (OR (MEMBER :UNSPECIFIC :WILD)) + 9 (OR (MEMBER :UNSPECIFIED)) + 16 (OR (MEMBER :WILD) SB-IMPL::PATTERN) + 9 (OR (MEMBER :WILD)) + 9 (OR (MEMBER FUNCTION)) + 14 (OR (MEMBER NIL :UNSPECIFIC :UNC)) + 16 (OR (MEMBER NIL :UNSPECIFIC :WILD :UNC)) + 12 (OR (MEMBER T :UNINITIALIZED)) + 12 (OR (MOD 4611686018427387901) (MEMBER)) + 19 (OR (NOT NUMBER) FIXNUM) + 24 (OR (NOT SYMBOL) (MEMBER T NIL) KEYWORD) + 24 (OR (RATIONAL 0 (32))) + 65 (OR (UNBOXED-ARRAY (*)) NUMBER SYMBOL INSTANCE CHARACTER) + 53 (OR (UNBOXED-ARRAY (*)) NUMBER) + 20 (OR (SIGNED-BYTE 32) SB-C:FIXUP) + 20 (OR (SIGNED-BYTE 32) SB-C:TN) +! 17 (OR (SIMPLE-ARRAY * (*)) EXTENDED-SEQUENCE (MEMBER)) + 15 (OR (SIMPLE-ARRAY CHARACTER (*)) SIMPLE-BASE-STRING) + 15 (OR (UNSIGNED-BYTE 32) SB-C:FIXUP) + 24 (OR (UNSIGNED-BYTE 64)) + 17 (OR (VECTOR CHARACTER) BASE-STRING (MEMBER :WILD)) + 14 (OR (VECTOR CHARACTER) BASE-STRING (MEMBER)) + 22 (OR (VECTOR CHARACTER) BASE-STRING CHARACTER PACKAGE) + 17 (OR (VECTOR CHARACTER) BASE-STRING CHARACTER) + 32 (OR (VECTOR CHARACTER) BASE-STRING NUMBER BIT-VECTOR PATHNAME) + 21 (OR (VECTOR CHARACTER) BASE-STRING PATHNAME) + 23 (OR (VECTOR CHARACTER) BASE-STRING HOST (MEMBER :UNSPECIFIC)) + 35 (OR ARRAY CONS NUMBER CHARACTER STRUCTURE-OBJECT) + 14 (OR BASE-STRING (VECTOR CHARACTER)) + 18 (OR BIGNUM RATIO) + 19 (OR BOOLEAN KEYWORD) + 12 (OR BOOLEAN) + 18 (OR CHARACTER FIXNUM BOOLEAN SINGLE-FLOAT) + 15 (OR CHARACTER PACKAGE) + 21 (OR CHARACTER SYMBOL FIXNUM SINGLE-FLOAT) + 9 (OR CHARACTER) +! 25 (OR CLASS CTYPE) +! 6 (OR CLASS) + 19 (OR COMPLEX SIMD-PACK SIMD-PACK-256) + 37 (OR CONS (AND ARRAY (NOT (OR STRING BIT-VECTOR))) SB-IMPL::COMMA) + 28 (OR CONS NUMBER PATHNAME) + 23 (OR CONS INSTANCE STRING PATHNAME) + 16 (OR CONS INSTANCE) +! 23 (OR ERROR SB-C:COMPILER-ERROR) +! 23 (OR ERROR SB-DI:DEBUG-CONDITION) +! 23 (OR ERROR PARSE-UNKNOWN-TYPE) + 27 (OR FILE-STREAM SYNONYM-STREAM) + 15 (OR FIXNUM BIGNUM RATIO) + 14 (OR FIXNUM CHARACTER SINGLE-FLOAT) + 19 (OR FIXNUM CHARACTER SYMBOL) + 12 (OR FIXNUM CHARACTER) + 15 (OR FIXNUM RATIO) + 15 (OR FIXNUM WRAPPER) + 23 (OR FIXNUM SYMBOL HASH-TABLE) + 30 (OR FLOAT (COMPLEX FLOAT) BIGNUM SIMD-PACK SIMD-PACK-256 SYSTEM-AREA-POINTER) + 17 (OR FLOAT RATIONAL) + 16 (OR FUNCTION (CONS (EQL FUNCTION))) + 13 (OR FUNCTION NULL) + 15 (OR INTEGER (MEMBER)) + 15 (OR INTEGER) + 31 (OR LOGICAL-PATHNAME SYNONYM-STREAM FILE-STREAM) + 34 (OR NULL (CONS (EQL QUOTE) (CONS SYMBOL NULL))) + 25 (OR NULL (CONS (MEMBER :CHARACTER-SET) STRING)) + 27 (OR NULL (CONS REAL NULL)) + 25 (OR NULL (CONS STRING NULL)) + 23 (OR NULL (CONS T (OR STRING NULL))) + 22 (OR NULL (MEMBER :CONC-NAME :CONSTRUCTOR :COPIER :PREDICATE :NAMED)) + 23 (OR NULL (MEMBER :NEWEST :WILD :UNSPECIFIC) INTEGER) + 15 (OR NULL (MEMBER :WILD :UNSPECIFIC) LIST) + 21 (OR NULL (MEMBER :WILD :UNSPECIFIC) STRING) + 12 (OR NULL (SATISFIES UNBOUND-MARKER-P)) + 17 (OR NULL CHARACTER PACKAGE) + 12 (OR NULL CHARACTER) +! 23 (OR NULL FUNCTION CONDITION SB-PCL::CONDITION-CLASS) + 13 (OR NULL FUNCTION) + 40 (OR NULL NUMBER CHARACTER (AND ARRAY (NOT (ARRAY T)))) + 19 (OR NULL NUMBER) + 23 (OR NULL SB-IMPL::PATTERN INTEGER) + 17 (OR NULL STRING) + 9 (OR NULL) + 26 (OR NUMBER CHARACTER SYMBOL) + 19 (OR NUMBER CHARACTER) + 23 (OR NUMBER PATHNAME) + 24 (OR NUMBER SYMBOL) + 36 (OR PACKAGE CODE-COMPONENT PATHNAME HOST HASH-TABLE) + 41 (OR PACKAGE FDEFN CODE-COMPONENT PATHNAME HOST HASH-TABLE) + 22 (OR PATHNAME BIT-VECTOR) + 16 (OR PATHNAME NULL) + 27 (OR PATHNAME STREAM) + 37 (OR PATHNAME SYNONYM-STREAM FILE-STREAM BOOLEAN) + 35 (OR PATHNAME SYNONYM-STREAM FILE-STREAM NULL) + 32 (OR PATHNAME SYNONYM-STREAM FILE-STREAM) + 12 (OR RATIO) + 17 (OR RATIONAL FLOAT) + 17 (OR RATIONAL SINGLE-FLOAT) + 15 (OR RATIONAL) +! 23 (OR READER-ERROR END-OF-FILE) + 23 (OR SB-ASSEM:LABEL SB-X86-64-ASM::LABEL+ADDEND SB-C:FIXUP) + 18 (OR SB-C::CLAMBDA SB-C::LAMBDA-VAR) + 30 (OR SB-C::COMPILER-ERROR-CONTEXT SB-C::NODE SB-C::LVAR-ANNOTATION SB-C::CTRAN (MEMBER)) + 18 (OR SB-C::CRETURN EXIT) + 16 (OR SB-C::CTRAN LIST) + 37 (OR SB-C::DEBUG-INFO SB-C::DEBUG-FUN SB-C::DEBUG-SOURCE SB-C:DEFINITION-SOURCE-LOCATION SB-C::DEBUG-NAME-MARKER) + 20 (OR SB-C::FUNCTIONAL SB-C::GLOBAL-VAR) + 16 (OR SB-C::LEAF (MEMBER :BOGUS)) + 18 (OR SB-C::OPTIONAL-DISPATCH SB-C::CLAMBDA) + 27 (OR SB-C:FIXUP NUMBER SB-X86-64-ASM::REG) + 15 (OR SB-C:TN NULL) + 20 (OR SB-DI::COMPILED-CODE-LOCATION SB-DI::COMPILED-DEBUG-FUN) + 29 (OR SB-DISASSEM::ADDRESS SYSTEM-AREA-POINTER) + 18 (OR SB-IMPL::PATTERN (MEMBER :WILD :WILD-INFERIORS)) + 16 (OR SB-IMPL::PATTERN (MEMBER :WILD)) + 22 (OR SB-IMPL::PATTERN (MEMBER NIL :UNSPECIFIC :WILD :UNC)) + 20 (OR SB-IMPL::PATTERN (MEMBER NIL :UNSPECIFIC :WILD)) +! 23 (OR BROKEN-PIPE END-OF-FILE) + 14 (OR INDEX NULL) +! 18 (OR CLASSOID CLASS) + 19 (OR CONSTANT SB-C::FUNCTIONAL) + 18 (OR CONSTANT SB-C::LAMBDA-VAR) +! 5 (OR EXTENDED-SEQUENCE) + 16 (OR HOST (MEMBER :UNSPECIFIC)) + 16 (OR HOST NULL) + 10 (OR INSTANCE (MEMBER)) + 14 (OR INSTANCE LIST) + 18 (OR SIMPLE-FUN CLOSURE) + 18 (OR SB-PRETTY::NEWLINE SB-PRETTY::BLOCK-START) + 18 (OR SB-X86-64-ASM::REG SB-X86-64-ASM::EA) + 15 (OR SIMPLE-BASE-STRING (SIMPLE-ARRAY CHARACTER (*))) + 23 (OR SIMPLE-STRING SB-IMPL::PATTERN (MEMBER :WILD)) + 15 (OR SINGLE-FLOAT DOUBLE-FLOAT) + 39 (OR STRING (CONS (EQL FUNCTION) (CONS SYMBOL NULL))) + 17 (OR STRING BIT-VECTOR) + 17 (OR STRING CHARACTER) + 40 (OR STRING CONS NUMBER BIT-VECTOR PATHNAME SYMBOL) + 37 (OR STRING CONS NUMBER BIT-VECTOR PATHNAME) + 22 (OR STRING INTEGER) + 31 (OR STRING NULL (CONS T (OR STRING NULL))) + 19 (OR STRING NULL (SATISFIES UNBOUND-MARKER-P)) + 17 (OR STRING NULL) + 21 (OR STRING PATHNAME) + 25 (OR STRING SB-IMPL::PATTERN (MEMBER :WILD :WILD-INFERIORS)) + 21 (OR STRING SB-IMPL::PATTERN) + 34 (OR STRING SYMBOL (CONS (EQL :CHARACTER-SET) STRING)) +! 31 (OR STRUCTURE-OBJECT STANDARD-OBJECT CONDITION) +! 23 (OR STYLE-WARNING COMPILER-NOTE) +! 23 (OR STYLE-WARNING PACKAGE-AT-VARIANCE) + 44 (OR SYMBOL (CONS SYMBOL (CONS SYMBOL NULL))) + 26 (OR SYMBOL CHARACTER NUMBER) +! 19 (OR SYMBOL CLASS) + 16 (OR SYMBOL CONS) + 19 (OR SYMBOL FIXNUM CHARACTER) + 23 (OR SYMBOL FIXNUM CONS WRAPPER) + 17 (OR SYMBOL FIXNUM) + 52 (OR SYMBOL NUMBER CHARACTER (OR UNBOXED-ARRAY (ARRAY NIL)) SYSTEM-AREA-POINTER SIMD-PACK SIMD-PACK-256) + 28 (OR SYMBOL NUMBER STRING) + 20 (OR SYMBOL WRAPPER) + 22 (OR UNSIGNED-BYTE) + 14 (OR VECTOR (MEMBER)) +! 23 (OR WARNING ERROR) + 24 (OR WORD SB-VM:SIGNED-WORD) + 6 (OR) + 18 (RATIONAL (0)) + 24 (RATIONAL -24 24) + 24 (RATIONAL 0 1) + 24 (RATIONAL 0 1152921504606) + 18 (RATIONAL 0) +! 15 (SATISFIES FBOUNDP) + 14 (SATISFIES KEYWORDP) +! 15 (SATISFIES MACRO-FUNCTION) +! 16 (SATISFIES EXTENDED-FUNCTION-DESIGNATOR-P) +! 16 (SATISFIES LEGAL-FUN-NAME-P) + 9 (SATISFIES UNBOUND-MARKER-P) +! 16 (SATISFIES CLASSOID-DEFINITELY-INSTANCEP) + 16 (SATISFIES ARRAY-HEADER-P) + 12 (SATISFIES CLOSUREP) + 12 (SATISFIES SIMPLE-FUN-P) + 15 (SIMPLE-UNBOXED-ARRAY (*)) + 43 (UNBOXED-ARRAY (*)) + 14 (SIGNED-BYTE 32) + 9 (SIGNED-BYTE 63) + 14 (SIGNED-BYTE 64) + 14 (SIGNED-BYTE 8) + 16 (SIMD-PACK DOUBLE-FLOAT) + 16 (SIMD-PACK SINGLE-FLOAT) + 16 (SIMD-PACK-256 DOUBLE-FLOAT) + 16 (SIMD-PACK-256 SINGLE-FLOAT) + 12 (SIMPLE-ARRAY (COMPLEX DOUBLE-FLOAT) (*)) + 12 (SIMPLE-ARRAY (COMPLEX SINGLE-FLOAT) (*)) + 12 (SIMPLE-ARRAY (SIGNED-BYTE 16) (*)) + 12 (SIMPLE-ARRAY (SIGNED-BYTE 32) (*)) + 12 (SIMPLE-ARRAY (SIGNED-BYTE 64) (*)) + 12 (SIMPLE-ARRAY (SIGNED-BYTE 8) (*)) + 12 (SIMPLE-ARRAY (SIGNED-BYTE 8) 1) + 12 (SIMPLE-ARRAY (UNSIGNED-BYTE 15) (*)) + 12 (SIMPLE-ARRAY (UNSIGNED-BYTE 16) (*)) + 12 (SIMPLE-ARRAY (UNSIGNED-BYTE 2) (*)) + 12 (SIMPLE-ARRAY (UNSIGNED-BYTE 31) (*)) + 12 (SIMPLE-ARRAY (UNSIGNED-BYTE 32) (*)) + 12 (SIMPLE-ARRAY (UNSIGNED-BYTE 4) (*)) + 12 (SIMPLE-ARRAY (UNSIGNED-BYTE 62) (*)) + 12 (SIMPLE-ARRAY (UNSIGNED-BYTE 63) (*)) + 12 (SIMPLE-ARRAY (UNSIGNED-BYTE 64) (*)) + 12 (SIMPLE-ARRAY (UNSIGNED-BYTE 7) (*)) + 12 (SIMPLE-ARRAY (UNSIGNED-BYTE 8) (*)) + 16 (SIMPLE-ARRAY (UNSIGNED-BYTE 8) (512)) + 29 (SIMPLE-ARRAY (UNSIGNED-BYTE 8)) + 14 (SIMPLE-ARRAY * (*)) + 23 (SIMPLE-ARRAY * (0)) + 14 (SIMPLE-ARRAY * 1) + 12 (SIMPLE-ARRAY BASE-CHAR (*)) + 12 (SIMPLE-ARRAY CHARACTER (*)) + 16 (SIMPLE-ARRAY CHARACTER (512)) + 12 (SIMPLE-ARRAY DOUBLE-FLOAT (*)) + 12 (SIMPLE-ARRAY FIXNUM (*)) + 12 (SIMPLE-ARRAY NIL (*)) + 12 (SIMPLE-ARRAY SINGLE-FLOAT (*)) + 12 (SIMPLE-ARRAY T (*)) + 29 (SIMPLE-ARRAY T) + 16 (SIMPLE-BIT-VECTOR 64) + 18 (SIMPLE-STRING 1) + 16 (SIMPLE-VECTOR 6) + 16 (SIMPLE-VECTOR 62) + 21 (SINGLE-FLOAT (-1.0) (0.0)) + 16 (SINGLE-FLOAT (0.0)) + 15 (SINGLE-FLOAT (1.0)) + 20 (SINGLE-FLOAT -1.6777216e7 1.6777215e7) + 21 (SINGLE-FLOAT 0.0 1.0) + 21 (SINGLE-FLOAT 0.0 1.1529215e12) + 21 (SINGLE-FLOAT 0.0 4.611686e18) + 16 (SINGLE-FLOAT 0.0) + 27 (STRING 0) + 9 (UNSIGNED-BYTE 12) + 9 (UNSIGNED-BYTE 16) + 9 (UNSIGNED-BYTE 2) + 9 (UNSIGNED-BYTE 27) + 9 (UNSIGNED-BYTE 31) + 9 (UNSIGNED-BYTE 32) + 9 (UNSIGNED-BYTE 4) + 9 (UNSIGNED-BYTE 59) + 9 (UNSIGNED-BYTE 6) + 9 (UNSIGNED-BYTE 62) + 21 (UNSIGNED-BYTE 63) + 24 (UNSIGNED-BYTE 64) + 9 (UNSIGNED-BYTE 7) + 9 (UNSIGNED-BYTE 8) + 22 (UNSIGNED-BYTE) + 27 (VECTOR * 0) + 14 (VECTOR CHARACTER) +! 5 (VECTOR T) + 13 ARRAY + 13 ATOM + 10 BASE-CHAR + 14 BASE-STRING + 12 BIGNUM + 9 BIT + 16 BIT-VECTOR + 12 BOOLEAN + 9 CHARACTER +! 6 CLASS + 13 COMPILED-FUNCTION + 15 COMPLEX + 13 CONS + 12 DOUBLE-FLOAT + 13 EXTENDED-CHAR + 9 FIXNUM + 15 FLOAT +! 6 GENERIC-FUNCTION + 15 INTEGER + 14 KEYWORD + 10 LIST + 12 LONG-FLOAT +! 6 METHOD-COMBINATION + 9 NULL + 17 NUMBER + 12 RATIO + 15 RATIONAL + 17 REAL + 9 SB-C::POLICY-QUALITY + 24 SB-DISASSEM::ADDRESS + 12 SB-IMPL::ABSENT-PATHNAME-COMPONENT + 14 DEPRECATION-STATE + 12 INDEX + 9 INFO-NUMBER + 16 RANDOM-STATE-STATE + 12 CLOSURE + 18 FORMAT-CONTROL + 12 FUNCALLABLE-INSTANCE + 10 INSTANCE + 12 SIMPLE-CHARACTER-STRING + 12 SIMPLE-FUN + 21 STRING-DESIGNATOR +! 26 TYPE-SPECIFIER +! 6 SB-MOP:EQL-SPECIALIZER +! 6 SB-MOP:FORWARD-REFERENCED-CLASS +! 6 SB-MOP:FUNCALLABLE-STANDARD-CLASS +! 6 SB-MOP:SPECIALIZER +! 6 SB-PCL::CLASS-EQ-SPECIALIZER +! 6 SB-PCL::FIND-METHOD-LENGTH-MISMATCH +! 6 SB-PCL:SYSTEM-CLASS + 14 EXIT-CODE + 9 SB-VM:FINITE-SC-OFFSET + 9 SB-VM:SC-OFFSET + 14 SB-VM:SIGNED-WORD +! 5 SEQUENCE + 9 SHORT-FLOAT + 13 SIMD-PACK + 13 SIMD-PACK-256 + 14 SIMPLE-ARRAY + 12 SIMPLE-BASE-STRING + 12 SIMPLE-BIT-VECTOR + 15 SIMPLE-STRING + 12 SIMPLE-VECTOR + 9 SINGLE-FLOAT +! 5 STANDARD-CHAR +! 6 STANDARD-CLASS +! 6 STANDARD-GENERIC-FUNCTION + 14 STRING +! 6 STRUCTURE-CLASS + 6 T + 22 UNSIGNED-BYTE + 14 VECTOR + 24 WORD diff --git a/tests/typep.impure-cload.lisp b/tests/typep.impure-cload.lisp new file mode 100644 index 0000000000..b96bb75c5d --- /dev/null +++ b/tests/typep.impure-cload.lisp @@ -0,0 +1,24 @@ +(declaim (muffle-conditions compiler-note style-warning)) + +(defclass myclass () ()) + +(defun control (x) + (declare (type (or null otherclass) x)) + (funcall 'f2 x)) + +(defun experiment (x) + (declare (type (or null myclass) x)) + (funcall 'f2 x)) + +(defun uses-cached-typep (f) + (let ((c (sb-kernel:fun-code-header f))) + (loop for i from sb-vm:code-constants-offset + below (sb-kernel:code-header-words c) + thereis (let ((const (sb-kernel:code-header-ref c i))) + (and (consp const) + (eq (car const) #'sb-kernel::cached-typep)))))) + +(with-test (:name :typep-of-a-class) + ;; Check that we know how to detect that a function used inefficient TYPEP + (assert (uses-cached-typep #'control)) + (assert (not (uses-cached-typep #'experiment)))) diff --git a/tests/unicode-breaking.pure.lisp b/tests/unicode-breaking.pure.lisp index 8c439422a9..08470cf3d8 100644 --- a/tests/unicode-breaking.pure.lisp +++ b/tests/unicode-breaking.pure.lisp @@ -37,17 +37,21 @@ (remove "" (split-string string #\Space) :test #'string=)))) (if (not (or (cdr list) singleton-list)) (car list) list))) -(defun test-line (fn line) +(defun test-line (fn line n) (let ((relevant-portion (subseq line 0 (position #\# line)))) (when (string/= relevant-portion "") - (let ((string - (coerce (mapcar - #'code-char - (parse-codepoints - (remove +mul+ (remove +div+ relevant-portion)))) - 'string))) - (assert (equalp (funcall fn string) - (line-to-clusters relevant-portion))))))) + (let* ((string + (coerce (mapcar + #'code-char + (parse-codepoints + (remove +mul+ (remove +div+ relevant-portion)))) + 'string)) + (actual (funcall fn string)) + (expected (line-to-clusters relevant-portion))) + (assert (equalp actual expected) + () + "~@<line ~D: ~S - expected: ~S, actual: ~S~@:>" + n line expected actual))))) (defun test-graphemes () (declare (optimize (debug 2))) @@ -55,8 +59,9 @@ :skipped-on (not :sb-unicode)) (with-open-file (s "data/GraphemeBreakTest.txt" :external-format :utf8) (loop for line = (read-line s nil nil) + for n from 0 while line - do (test-line #'graphemes (remove #\Tab line)))))) + do (test-line #'graphemes (remove #\Tab line) n))))) (test-graphemes) @@ -66,8 +71,9 @@ :skipped-on (not :sb-unicode)) (with-open-file (s "data/WordBreakTest.txt" :external-format :utf8) (loop for line = (read-line s nil nil) + for n from 0 while line - do (test-line #'words (remove #\Tab line)))))) + do (test-line #'words (remove #\Tab line) n))))) (test-words) @@ -77,8 +83,9 @@ :skipped-on (not :sb-unicode)) (with-open-file (s "data/SentenceBreakTest.txt" :external-format :utf8) (loop for line = (read-line s nil nil) + for n from 0 while line - do (test-line #'sentences (remove #\Tab line)))))) + do (test-line #'sentences (remove #\Tab line) n))))) (test-sentences) @@ -110,6 +117,7 @@ (setf (gethash s line-break-exceptions) t)) (with-open-file (s "data/LineBreakTest.txt" :external-format :utf8) (loop for line = (read-line s nil nil) + for n from 0 while line do (let ((string (subseq line 0 (max 0 (1- (or (position #\# line) 1)))))) (unless (string= string "") @@ -118,5 +126,11 @@ (string-from-line-break-line string))) (actual (substitute :can :must annotated))) (if (gethash string line-break-exceptions) - (assert (not (equal expected actual))) - (assert (equal expected actual)))))))))) + (assert (not (equal expected actual)) + () + "~@<line ~D: ~S - expected: ~S, actual; ~S~:@>" + n string expected actual) + (assert (equal expected actual) + () + "~@<line ~D: ~S - expected: ~S, actual; ~S~:@>" + n string expected actual))))))))) diff --git a/tests/unicode-properties.pure.lisp b/tests/unicode-properties.pure.lisp index 6b3da6fdae..bb85acb888 100644 --- a/tests/unicode-properties.pure.lisp +++ b/tests/unicode-properties.pure.lisp @@ -139,7 +139,7 @@ Wanted ~S, got ~S." (defun test-bidi-class () (declare (optimize (debug 2))) - (with-open-file (s "data/DerivedBidiClass.txt" :external-format :ascii) + (with-open-file (s "data/DerivedBidiClass.txt" :external-format :utf-8) (with-test (:name (:bidi-class)) (loop for line = (read-line s nil nil) while line @@ -150,7 +150,7 @@ Wanted ~S, got ~S." (defun test-hangul-syllable-type () (declare (optimize (debug 2))) - (with-open-file (s "data/HangulSyllableType.txt" :external-format :ascii) + (with-open-file (s "data/HangulSyllableType.txt" :external-format :utf-8) (with-test (:name (:hangul-syllable-type)) (loop for line = (read-line s nil nil) while line @@ -162,7 +162,7 @@ Wanted ~S, got ~S." (defun test-east-asian-width () (declare (optimize (debug 2))) (with-open-file (s "../tools-for-build/EastAsianWidth.txt" - :external-format :ascii) + :external-format :utf-8) (with-test (:name (:east-asian-width)) (loop for line = (read-line s nil nil) while line @@ -174,7 +174,7 @@ Wanted ~S, got ~S." (defun test-script () (declare (optimize (debug 2))) (with-open-file (s "../tools-for-build/Scripts.txt" - :external-format :ascii) + :external-format :utf-8) (with-test (:name (:script)) (loop for line = (read-line s nil nil) while line @@ -186,7 +186,7 @@ Wanted ~S, got ~S." (defun test-block () (declare (optimize (debug 2))) (with-open-file (s "../tools-for-build/Blocks.txt" - :external-format :ascii) + :external-format :utf-8) (with-test (:name (:block)) (loop for line = (read-line s nil nil) while line @@ -203,7 +203,7 @@ Wanted ~S, got ~S." (defun test-proplist () (declare (optimize (debug 2))) (with-open-file (s "../tools-for-build/PropList.txt" - :external-format :ascii) + :external-format :utf-8) (with-test (:name (:proplist)) (loop for line = (read-line s nil nil) while line @@ -228,7 +228,7 @@ Wanted ~S, got ~S." (defun test-bidi-mirroring-glyph () (declare (optimize (debug 2))) (with-open-file (s "../tools-for-build/BidiMirroring.txt" - :external-format :ascii) + :external-format :utf-8) (with-test (:name (:bidi-mirroring-glyph) :skipped-on (not :sb-unicode)) (loop for line = (read-line s nil nil) @@ -251,7 +251,7 @@ Wanted ~S, got ~S." (defun test-age () (declare (optimize (debug 2))) (with-open-file (s "../tools-for-build/DerivedAge.txt" - :external-format :ascii) + :external-format :utf-8) (with-test (:name (:age)) (loop for line = (read-line s nil nil) while line @@ -275,7 +275,7 @@ Wanted ~S, got ~S." (defun test-grapheme-break-class () (declare (optimize (debug 2))) (with-open-file (s "data/GraphemeBreakProperty.txt" - :external-format :ascii) + :external-format :utf-8) (with-test (:name (:grapheme-break-class)) (loop for line = (read-line s nil nil) while line @@ -289,7 +289,7 @@ Wanted ~S, got ~S." (defun test-word-break-class () (declare (optimize (debug 2))) (with-open-file (s "data/WordBreakProperty.txt" - :external-format :ascii) + :external-format :utf-8) (with-test (:name (:word-break-class)) (loop for line = (read-line s nil nil) while line @@ -302,7 +302,7 @@ Wanted ~S, got ~S." (defun test-sentence-break-class () (declare (optimize (debug 2))) (with-open-file (s "data/SentenceBreakProperty.txt" - :external-format :ascii) + :external-format :utf-8) (with-test (:name (:sentence-break-class)) (loop for line = (read-line s nil nil) while line @@ -314,7 +314,7 @@ Wanted ~S, got ~S." (defun test-line-break-class () (declare (optimize (debug 2))) (with-open-file (s "../tools-for-build/LineBreak.txt" - :external-format :ascii) + :external-format :utf-8) (with-test (:name (:line-break-class)) (loop for line = (read-line s nil nil) while line diff --git a/tests/unintern.impure.lisp b/tests/unintern.impure.lisp new file mode 100644 index 0000000000..fe032cc897 --- /dev/null +++ b/tests/unintern.impure.lisp @@ -0,0 +1,42 @@ +;;; Consider that the CL-USER package (among others) starts out as empty. +;;; So the table-cells are #(0 0 0). Then perform the following operations: +;;; * (intern "X") ; cells => #(0 X 0) +;;; * (intern "Y") ; cells => #(Y X 0) +;;; * (intern "Z") ; cells => #(Z 0 X 0 Y 0 0) +;;; unintern writes a tombstone as required by open-addressing tables +;;; * (unintern 'z) ; cells => #(-1 0 X 0 Y 0 0) +;;; and now you can try to unintern X and Y until you're blue in the face, +;;; but you CAN NOT convince a finalizer attached to either one to execute, +;;; because the initial table holding 2 symbols is in +PSEUDO-STATIC-GENERATION+. +;;; We can't 0-fill symbol vectors because FIND-SYMBOL is lock-free +;;; sans hazard pointers, and we don't want symbols to seem to transiently turn +;;; nonexistent when up-sizing a table. + +;;; But it is so incredibly confusing and unintuitive that playing around +;;; with intern/unintern does not have the effect of letting go of strong references +;;; to symbols in initially empty packages. Granted this is a particular edge case. +;;; The GC limitation is actually far more pervasive, extending to hash-tables +;;; and everything else. But empty packages are excruciatingly and visibly +;;; badly behaved. + +;;; CL-USER's internals aren't empty, merely because of READINg this file. +;;; So use the externals, of which there should be none. +(defun extern (name) + (let ((s (make-symbol name)) + (p *package*)) + (sb-impl::add-symbol (sb-impl::package-external-symbols *package*) s) + (sb-impl::%set-symbol-package s p) + s)) + +(with-test (:name :empty-package-starts-with-readonly-tables) + (extern "X") + (extern "Y") + (extern "Z") + (let ((wps (mapcar (lambda (name) (make-weak-pointer (find-symbol name))) + '("X" "Y" "Z")))) + (unintern (find-symbol "Z")) + (unintern (find-symbol "X")) + (unintern (find-symbol "Y")) + (sb-sys:scrub-control-stack) + (gc) + (assert (< (count-if #'weak-pointer-value wps) 3)))) diff --git a/tests/unwind-to-frame-and-call.impure.lisp b/tests/unwind-to-frame-and-call.impure.lisp index 7e56338980..171c5fb603 100644 --- a/tests/unwind-to-frame-and-call.impure.lisp +++ b/tests/unwind-to-frame-and-call.impure.lisp @@ -14,7 +14,7 @@ ;;; The debugger doesn't have any native knowledge of the interpreter (when (eq sb-ext:*evaluator-mode* :interpret) - (sb-ext:exit :code 104)) + (invoke-restart 'run-tests::skip-file)) (declaim (optimize debug)) @@ -277,12 +277,14 @@ (assert (eql *foo* 'y))) (assert (eql *foo* 'x))))) +(defvar *p* (namestring (if sb-c::*merge-pathnames* *load-truename* *load-pathname*))) + (with-test (:name (:return-from-frame :anonymous :toplevel) :fails-on :win32) - (test-anon *anon-1* 'foo (namestring *load-truename*))) + (test-anon *anon-1* 'foo *p*)) (with-test (:name (:return-from-frame :anonymous :toplevel-special) :fails-on :win32) - (test-anon *anon-2* '*foo* (namestring *load-truename*))) + (test-anon *anon-2* '*foo* *p*)) (with-test (:name (:return-from-frame :anonymous) :fails-on :win32) (test-anon *anon-3* 'foo 'make-anon-3)) diff --git a/tests/vector.impure.lisp b/tests/vector-2.pure.lisp similarity index 98% rename from tests/vector.impure.lisp rename to tests/vector-2.pure.lisp index c3ddfea543..c2d59488a3 100644 --- a/tests/vector.impure.lisp +++ b/tests/vector-2.pure.lisp @@ -9,8 +9,6 @@ ;;;; absolutely no warranty. See the COPYING and CREDITS files for ;;;; more information. -(cl:in-package "CL-USER") - ;;; test case from Utz-Uwe Haus (defstruct some-struct (a 0 :type integer)) @@ -85,6 +83,7 @@ () `(lambda (n) (sb-int:dx-let ((v (make-array (the (mod 200) n) + :initial-element #\null :element-type 'base-char))) (find #\null v :test #'char/=))) ((40) nil))) diff --git a/tests/vector.pure.lisp b/tests/vector.pure.lisp index 94b28bcea5..2770eadcde 100644 --- a/tests/vector.pure.lisp +++ b/tests/vector.pure.lisp @@ -69,3 +69,7 @@ (setf (fill-pointer x) 0))) (make-array 2 :adjustable t)) type-error)) + +(with-test (:name :concatenate-to-vector) + (assert (sb-kernel:%concatenate-to-vector sb-vm:simple-bit-vector-widetag + '(1 1) '(1 0)))) diff --git a/tests/vm.before-xc.lisp b/tests/vm.before-xc.lisp index f7300bc1e3..79bc1f8758 100644 --- a/tests/vm.before-xc.lisp +++ b/tests/vm.before-xc.lisp @@ -16,19 +16,11 @@ (/show "beginning tests/vm.before-xc.lisp") -(flet ((yes (x) - (assert - (eql immediate-sc-number - (immediate-constant-sc x)))) - (no (x) +(flet ((no (x) (assert (not (immediate-constant-sc x))))) - ;; target fixnums can be dealt with as immediates; target bignums - ;; can not. - (yes #.sb-xc:most-positive-fixnum) - (yes #.sb-xc:most-negative-fixnum) - (no #.(1+ sb-xc:most-positive-fixnum)) - (no #.(1- sb-xc:most-negative-fixnum))) + (no #.(1+ most-positive-fixnum)) + (no #.(1- most-negative-fixnum))) ;; Assert that DO-PACKED-TNS has unsurprising behavior if the body RETURNs. ;; This isn't a test in the problem domain of CL - it's of an internal macro, diff --git a/tests/vopcombine.pure.lisp b/tests/vopcombine.pure.lisp new file mode 100644 index 0000000000..c9faf9c2ac --- /dev/null +++ b/tests/vopcombine.pure.lisp @@ -0,0 +1,24 @@ + +;;; MACHINE-VERSION did the wrong thing after rev 1a0c5f225a +;;; but it will cease to be a good test because SB-SYS:*MACHINE-VERSION* +;;; should be a defglobal, but we don't allows defglobals (not thread-locally +;;; bindable) variables to have unbound-marker as their value, so +;;; I don't know what I'll change. But regardless there was another +;;; inefficiency in that SB-SYS:*MACHINE-VERSION* is allowed to be a non-simple +;;; string, while fndb says that #'MACHINE-VERSION returns a SIMPLE-STRING. +;;; After I fix that discrepancy there should be no type-check at all +;;; in the quick case of (MACHINE-VERSION). So this test is a self-contained +;;; replica of what the broken code did, whether or not I change that. +(defvar *some-string*) +(defun compute-the-string () + (format nil "~A a ~A" "here's" "string")) + +(declaim (ftype (function () string) cached-get-a-string)) +(defun cached-get-a-string () + (unless (boundp '*some-string*) + (setf *some-string* (compute-the-string))) + *some-string*) +(compile 'cached-get-a-string) + +(with-test (:name :boundp+symbol-value-labeled-blocks) + (assert (string= (cached-get-a-string) "here's a string"))) diff --git a/tests/walk.impure.lisp b/tests/walk.impure.lisp index c2b9d3bda1..fd74e2b873 100644 --- a/tests/walk.impure.lisp +++ b/tests/walk.impure.lisp @@ -469,7 +469,9 @@ Form: (FOO A) Context: EVAL Form: 'GLOBAL-FOO Context: EVAL \(EVAL-WHEN (:EXECUTE :COMPILE-TOPLEVEL :LOAD-TOPLEVEL) A (FOO A))"))) -(test-util:with-test (:name (:walk multiple-value-bind)) +;; This test doesn't understand that gensyms appear in the expansion +;; (We either need "string=-modulo-tabspace-and-gensyms" or a sexpr-based comparison) +(test-util:with-test (:name (:walk multiple-value-bind) :fails-on :sbcl) (assert (string=-modulo-tabspace (with-output-to-string (*standard-output*) (take-it-out-for-a-test-walk (multiple-value-bind (a b) @@ -482,7 +484,8 @@ Form: A Context: EVAL; lexically bound Form: B Context: EVAL; lexically bound \(MULTIPLE-VALUE-BIND (A B) (FOO A B) (LIST A B))"))) -(test-util:with-test (:name (:walk multiple-value-bind special)) +;; This test doesn't understand that gensyms appear in the expansion +(test-util:with-test (:name (:walk multiple-value-bind special) :fails-on :sbcl) (assert (string=-modulo-tabspace (with-output-to-string (*standard-output*) (take-it-out-for-a-test-walk (multiple-value-bind (a b) @@ -1071,4 +1074,13 @@ Form: C Context: EVAL; lexically bound ;;; Old PCL hung up on this. (defmethod #:foo () (defun #:bar ())) - + +;; lp#1912362 +(defmethod zook (x) (let ((typep x 'vector)) typep)) +(test-util:with-test (:name :let-syntax-error) + (assertoid:assert-error (zook 1))) + +(declaim (inline inlined-fun)) + +(test-util:with-test (:name :inlined-defun) + (eval '(defmethod inlined-defun () (defun inlined-fun ())))) diff --git a/tests/win32-foreign-stack-unwind.impure.lisp b/tests/win32-foreign-stack-unwind.impure.lisp index 6749150740..dfb87d4a60 100644 --- a/tests/win32-foreign-stack-unwind.impure.lisp +++ b/tests/win32-foreign-stack-unwind.impure.lisp @@ -11,8 +11,8 @@ ;;;; absolutely no warranty. See the COPYING and CREDITS files for ;;;; more information. -#-win32 (exit :code 104) ;; This is extremely win32-specific. -#-x86 (exit :code 104) ;; And our AMD64 backend does not aim to support it. +#-win32 (invoke-restart 'run-tests::skip-file) ;; This is extremely win32-specific. +#-x86 (invoke-restart 'run-tests::skip-file) ;; And our AMD64 backend does not aim to support it. (use-package :sb-alien) diff --git a/tests/win32.impure.lisp b/tests/win32.impure.lisp index e3006d6615..1de4ef8d36 100644 --- a/tests/win32.impure.lisp +++ b/tests/win32.impure.lisp @@ -9,7 +9,7 @@ ;;;; absolutely no warranty. See the COPYING and CREDITS files for ;;;; more information. -#-win32 (exit :code 104) +#-win32 (invoke-restart 'run-tests::skip-file) (with-test (:name :dbg-print-exception-c) (handler-case diff --git a/tests/win64-exceptions.c b/tests/win64-exceptions.c new file mode 100644 index 0000000000..9438d0d152 --- /dev/null +++ b/tests/win64-exceptions.c @@ -0,0 +1,301 @@ +/* Compiled and loaded by win64-exceptions.impure.lisp + */ + +/* This software is part of the SBCL system. See the README file for + * more information. + * + * While most of SBCL is derived from the CMU CL system, the test + * files (like this one) were written from scratch after the fork + * from CMU CL. + * + * This software is in the public domain and is provided with + * absolutely no warranty. See the COPYING and CREDITS files for + * more information. + */ + +#include <windows.h> +#include <stdio.h> +#include <stdint.h> + +extern int +unsafe_div(int dividend, int divisor) +{ + return dividend / divisor; +} + +extern void +raise_exception(int code) +{ + RaiseException(code, EXCEPTION_NONCONTINUABLE, 0, NULL); +} + +struct division { + int dividend; + int divisor; + int result; +}; + +static DWORD WINAPI +thread_fn(LPVOID param) +{ + struct division *x = param; + x->result = x->dividend / x->divisor; + return 0; +} + +/* Only used in self-tests, since SBCL can't (and probably shouldn't) handle + * exceptions in foreign threads. */ +extern int +unsafe_div_in_foreign_thread(int dividend, int divisor) +{ + struct division x = { dividend, divisor, -1 }; + DWORD tid; + HANDLE thread = CreateThread(NULL, 0, thread_fn, &x, 0, &tid); + WaitForMultipleObjects(1, &thread, TRUE, INFINITE); + CloseHandle(thread); + return x.result; +} + +typedef struct _UNWIND_INFO { + uint8_t Version : 3; + uint8_t Flags : 5; + uint8_t SizeOfProlog; + uint8_t CountOfCodes; + uint8_t FrameRegister : 4; + uint8_t FrameOffset : 4; + ULONG ExceptionHandler; + ULONG ExceptionData[1]; +} UNWIND_INFO; + +struct fn { + uint8_t code[8]; + uint8_t eh_trampoline[16]; + UNWIND_INFO ui; // needs to be DWORD-aligned + RUNTIME_FUNCTION rt; +}; + +static EXCEPTION_DISPOSITION +div_exception_handler(PEXCEPTION_RECORD ExceptionRecord, + ULONG64 EstablisherFrame, + PCONTEXT ContextRecord, + PDISPATCHER_CONTEXT DispatcherContext) +{ + printf("div_exception_handler() got exception 0x%lx; continuing\n", + ExceptionRecord->ExceptionCode); + fflush(stdout); + ContextRecord->Rip += 2; // skip over DIV instruction + return ExceptionContinueExecution; +} + +static EXCEPTION_DISPOSITION +mov_exception_handler(PEXCEPTION_RECORD ExceptionRecord, + ULONG64 EstablisherFrame, + PCONTEXT ContextRecord, + PDISPATCHER_CONTEXT DispatcherContext) +{ + printf("mov_exception_handler() got exception 0x%lx; continuing\n", + ExceptionRecord->ExceptionCode); + fflush(stdout); + ContextRecord->Rip += 7; // skip over 7-byte MOV instruction + return ExceptionContinueExecution; +} + + +static BOOLEAN +set_up_exception_handler(struct fn *fn, void *handler) +{ + DWORD64 base = (DWORD64) fn; + + uint8_t *tramp = fn->eh_trampoline; + tramp[0] = 0xFF; // jmp qword ptr [rip+2] + tramp[1] = 0x25; + tramp[2] = 0x02; + tramp[3] = 0x00; + tramp[4] = 0x00; + tramp[5] = 0x00; + tramp[6] = 0x66; // 2-byte nop + tramp[7] = 0x90; + *(void **)(tramp+8) = handler; + + UNWIND_INFO *ui = &fn->ui; + ui->Version = 1; + ui->Flags = UNW_FLAG_EHANDLER; + ui->SizeOfProlog = 0; + ui->CountOfCodes = 0; + ui->FrameRegister = 0; + ui->FrameOffset = 0; + ui->ExceptionHandler = (DWORD64) tramp - base; + ui->ExceptionData[0] = 0; + + RUNTIME_FUNCTION *rt = &fn->rt; + rt->BeginAddress = 0; + rt->EndAddress = 8; + rt->UnwindData = (DWORD64) ui - base; + + return RtlAddFunctionTable(rt, 1, base); +} + +/* Sadly, MINGW's __try1/__except don't compile with -shared, so we have to do + * exception handling the hard way, again. */ +extern int +raise_int_divide_by_zero(int handle) +{ + struct fn *fn = VirtualAlloc(NULL, sizeof(struct fn), MEM_COMMIT, + PAGE_EXECUTE_READWRITE); + + uint8_t *code = fn->code; + code[0] = 0x31; // xor ecx, ecx + code[1] = 0xC9; + code[2] = 0xF7; // div ecx + code[3] = 0xF1; + code[4] = 0xC3; // ret + code[5] = code[6] = code[7] = 0x90; // nop + + if (handle && !set_up_exception_handler(fn, div_exception_handler)) + return 0; + + // will raise EXCEPTION_INT_DIVIDE_BY_ZERO + (*((void (*)()) code))(); + + return 1; +} + +extern int * +allocate_readonly_int() +{ + return VirtualAlloc(NULL, sizeof(int), MEM_COMMIT, PAGE_READONLY); +} + +extern int +free_readonly_int(int *n) +{ + return VirtualFree(n, sizeof(int), MEM_RELEASE); +} + +extern int +raise_access_violation(int handle) +{ + struct fn *fn = VirtualAlloc(NULL, sizeof(struct fn), MEM_COMMIT, + PAGE_EXECUTE_READWRITE); + + uint8_t *code = fn->code; + code[0] = 0x48; // mov qword ptr [rcx], 42 + code[1] = 0xC7; + code[2] = 0x01; + code[3] = 0x2A; + code[4] = 0x00; + code[5] = 0x00; + code[6] = 0x00; + code[7] = 0xC3; // ret + + if (handle && !set_up_exception_handler(fn, mov_exception_handler)) + return 0; + + int *n = allocate_readonly_int(); + + // will raise EXCEPTION_ACCESS_VIOLATION + (*((void (*)(int *)) code))(n); + + free_readonly_int(n); + + return 1; +} + +/* + * Self-tests. As of GCC 9.2.0, __try1/__except1 is very finicky. -O1 or higher + * fails to compile, they can only appear once per file (therefore we need to + * enable each test case individually), and there are some restrictions on what + * can happen within the __try1 block (e.g., no returns). + * + * Run with: + * for n in {1..6}; do gcc -DTEST_CASE=$n win64-exceptions.c && ./a.exe; done + */ + +#ifndef TEST_CASE +#define TEST_CASE 0 +#endif + +#if TEST_CASE > 0 +static long CALLBACK +eh(EXCEPTION_POINTERS *ep) +{ + printf("raised exception 0x%lx ", ep->ExceptionRecord->ExceptionCode); + fflush(stdout); + return EXCEPTION_EXECUTE_HANDLER; +} + +int main(void) +{ + printf("\n>>> TEST_CASE=%d\n", TEST_CASE); fflush(stdout); + +# if TEST_CASE == 1 + printf("unsafe_div(12, 4) = %d\n", unsafe_div(12, 4)); fflush(stdout); + + __try1(eh) { + printf("unsafe_div(12, 0) = "); fflush(stdout); + printf("%d (unexpectedly)\n", unsafe_div(12, 0)); fflush(stdout); + } __except1 { + printf("which was handled gracefully\n"); fflush(stdout); + } +# endif + +# if TEST_CASE == 2 + __try1(eh) { + printf("raise_exception(42) ... "); fflush(stdout); + raise_exception(42); + } __except1 { + printf("which was handled gracefully\n"); fflush(stdout); + } +# endif + +# if TEST_CASE == 3 + printf("unsafe_div_in_foreign_thread(12, 4) = %d\n", + unsafe_div_in_foreign_thread(12, 4)); + fflush(stdout); + + printf("unsafe_div_in_foreign_thread(12, 0) ... should kill the process\n"); + fflush(stdout); + printf("unexpectedly, it returned %d\n", + unsafe_div_in_foreign_thread(12, 0)); + fflush(stdout); +# endif + +# if TEST_CASE == 4 + printf("raise_int_divide_by_zero(1) = %d\n", + raise_int_divide_by_zero(1)); fflush(stdout); + + __try1(eh) { + printf("raise_int_divide_by_zero(0) = "); fflush(stdout); + printf("%d (unexpectedly)\n", raise_int_divide_by_zero(0)); + fflush(stdout); + } __except1 { + printf("which was handled gracefully\n"); fflush(stdout); + } +# endif + +# if TEST_CASE == 5 + printf("raise_access_violation(1) = %d\n", + raise_access_violation(1)); fflush(stdout); + + __try1(eh) { + printf("raise_access_violation(0) = "); fflush(stdout); + printf("%d (unexpectedly)\n", raise_access_violation(0)); + fflush(stdout); + } __except1 { + printf("which was handled gracefully\n"); fflush(stdout); + } +# endif + +# if TEST_CASE == 6 + int *n = allocate_readonly_int(); + __try1(eh) { + printf("writing into read-only memory "); fflush(stdout); + printf("yielded %d (unexpectedly)\n", *n = 42); fflush(stdout); + } __except1 { + printf("which was handled gracefully\n"); fflush(stdout); + free_readonly_int(n); + } +# endif + return EXIT_SUCCESS; +} +#endif diff --git a/tests/win64-exceptions.impure.lisp b/tests/win64-exceptions.impure.lisp new file mode 100644 index 0000000000..ab73699620 --- /dev/null +++ b/tests/win64-exceptions.impure.lisp @@ -0,0 +1,75 @@ +;;;; Structured exception handling. Uses win64-exceptions.c. + +;;;; This software is part of the SBCL system. See the README file for +;;;; more information. +;;;; +;;;; While most of SBCL is derived from the CMU CL system, the test +;;;; files (like this one) were written from scratch after the fork +;;;; from CMU CL. +;;;; +;;;; This software is in the public domain and is provided with +;;;; absolutely no warranty. See the COPYING and CREDITS files for +;;;; more information. + +#-(and win32 x86-64) (invoke-restart 'run-tests::skip-file) ;; This is extremely win64-specific. + +(with-scratch-file (dll "dll") + (run-program "gcc" `("-shared" "-o" ,dll "win64-exceptions.c") + :search t) + (load-shared-object dll)) + +(define-alien-routine "unsafe_div" int + (dividend int) + (divisor int)) + +(define-alien-routine "raise_exception" void + (code int)) + +(define-alien-routine "raise_int_divide_by_zero" int + (handle int)) + +(define-alien-routine "raise_access_violation" int + (handle int)) + +(define-alien-routine "allocate_readonly_int" (* int)) + +(define-alien-routine "free_readonly_int" int + (pointer (* int))) + +(with-test (:name :unsafe-div) + (assert (eql 3 (unsafe-div 12 4))) + (multiple-value-bind (result error) + (ignore-errors (unsafe-div 12 0)) + (assert (null result)) + (assert (string= (princ-to-string error) + "EXCEPTION_INT_DIVIDE_BY_ZERO")))) + +(with-test (:name :raise-exception) + (let ((e (nth-value 1 (ignore-errors (raise-exception 42))))) + (assert (typep e 'sb-win32:exception)) + (assert (eql 42 (sb-win32:exception-code e))))) + +(with-test (:name :raise-int-divide-by-zero) + (assert (eql 1 (raise-int-divide-by-zero 1))) + (multiple-value-bind (result error) + (ignore-errors (raise-int-divide-by-zero 0)) + (assert (null result)) + (assert (string= (princ-to-string error) + "EXCEPTION_INT_DIVIDE_BY_ZERO")))) + +(with-test (:name :raise-access-violation) + (assert (eql 1 (raise-access-violation 1))) + (assert-error (raise-access-violation 0) sb-sys:memory-fault-error)) + +(with-test (:name :access-violation-in-lisp) + (let ((p (allocate-readonly-int))) + (assert-error (setf (deref p) 42) sb-sys:memory-fault-error) + (free-readonly-int p))) + +;;; Not a very robust test since neither free() nor HeapFree() document this +;;; exception. The main result we wish for is not having the process abruptly +;;; terminated. +(with-test (:name :heap-corruption) + (let ((bad-pointer (sb-alien:sap-alien (sb-sys:int-sap 42) (* (unsigned 8))))) + (assert-error (sb-alien:free-alien bad-pointer) + sb-sys:foreign-heap-corruption))) diff --git a/tests/x86-64-codegen.impure.lisp b/tests/x86-64-codegen.impure.lisp index 050a2553fa..bcab333a43 100644 --- a/tests/x86-64-codegen.impure.lisp +++ b/tests/x86-64-codegen.impure.lisp @@ -9,28 +9,62 @@ ;;;; absolutely no warranty. See the COPYING and CREDITS files for ;;;; more information. -#-x86-64 (sb-ext:exit :code 104) +#-x86-64 (invoke-restart 'run-tests::skip-file) + +;;; This trivial function failed to compile due to rev 88d078fe +(defun foo (&key k) + (make-list (reduce #'max (mapcar #'length k)))) +(compile 'foo) + +(with-test (:name :lowtag-test-elision) + ;; This tests a certain behavior that while "undefined" should at least not + ;; be fatal. This is important for things like hash-table :TEST where we might + ;; call (EQUAL x y) with X being an unbound marker indicating an empty cell. + ;; After we started using IR1 type derivation to elide lowtag as a guard condition + ;; in some type tests, it became more likely to dereference an unbound marker + ;; which does not fit anywhere in the lisp type space. + (let ((f (compile nil + '(lambda (x) + (typecase x + ((or character number list sb-kernel:instance function) 1) + ;; After eliminating the preceding cases, the compiler knows + ;; that the only remaining pointer type is OTHER-POINTER, + ;; so it just tries to read the widetag. + ;; If X is the unbound marker, this will read a byte preceding + ;; the start of static space, but it holds a zero. + (simple-vector 2)))))) + (assert (not (funcall f (sb-kernel:make-unbound-marker))))) + (assert (not (equalp (sb-kernel:make-unbound-marker) ""))) + (let ((a (- (sb-kernel:get-lisp-obj-address (sb-kernel:make-unbound-marker)) + sb-vm:other-pointer-lowtag))) + (assert (> a sb-vm:static-space-start)))) (load "compiler-test-util.lisp") -(defun disasm (safety expr &optional (remove-epilogue t)) - ;; This lambda has a name because if it doesn't, then the name - ;; is something stupid like (lambda () in ...) which pretty-prints - ;; on a random number of lines. - (let ((fun (compile nil - `(sb-int:named-lambda test () - (declare (optimize (debug 0) (safety ,safety) - (sb-c:verify-arg-count 0))) - ,expr)))) - (sb-int:encapsulate 'sb-disassem::add-debugging-hooks 'test - (lambda (f &rest args) (declare (ignore f args)))) - (let ((lines - (split-string - (with-output-to-string (s) - (let ((sb-disassem:*disassem-location-column-width* 0)) - (disassemble fun :stream s))) - #\newline))) - (sb-int:unencapsulate 'sb-disassem::add-debugging-hooks 'test) - (setq lines (cddr lines)) ; remove "Disassembly for" +(defun disassembly-lines (fun) + ;; FIXME: I don't remember what this override of the hook is for. + (sb-int:encapsulate 'sb-disassem::add-debugging-hooks 'test + (lambda (f &rest args) (declare (ignore f args)))) + (prog1 + (mapcar (lambda (x) (string-left-trim " ;" x)) + (cddr + (split-string + (with-output-to-string (s) + (let ((sb-disassem:*disassem-location-column-width* 0) + (*print-pretty* nil)) + (disassemble fun :stream s))) + #\newline))) + (sb-int:unencapsulate 'sb-disassem::add-debugging-hooks 'test))) + +(sb-vm::define-vop (tryme) + (:generator 1 (sb-assem:inst mov :byte (sb-vm::ea :gs sb-vm::rax-tn) 0))) +(with-test (:name :try-gs-segment) + (assert (loop for line in (disassembly-lines + (compile nil + '(lambda () (sb-sys:%primitive tryme)))) + thereis (search "MOV BYTE PTR GS:[RAX]" line)))) + +(defun strip-assem-junk (fun &optional (remove-epilogue t)) + (let ((lines (disassembly-lines (compile nil fun)))) ;; For human-readability, kill the whitespace (setq lines (mapcar (lambda (x) (string-left-trim " ;" x)) lines)) (when (string= (car (last lines)) "") @@ -45,16 +79,35 @@ '("MOV RSP, RBP" "CLC" "POP RBP" "RET") (subseq lines (- (length lines) 4)))) (butlast lines 4) - lines)))) + lines))) +(defun disasm-load (safety symbol) + ;; This lambda has a name because if it doesn't, then the name + ;; is something stupid like (lambda () in ...) which pretty-prints + ;; on a random number of lines. + (strip-assem-junk `(sb-int:named-lambda test () + (declare (optimize (debug 0) (safety ,safety) + (sb-c:verify-arg-count 0))) + ,symbol))) +(defun disasm-store (sexpr) + (strip-assem-junk `(sb-int:named-lambda test (x) + (declare (ignorable x)) + (declare (optimize (debug 0) + (sb-c:verify-arg-count 0))) + ,sexpr))) (with-test (:name :symeval-known-thread-local :skipped-on (not :sb-thread)) ;; It should take 1 instruction to read a known thread-local var - (assert (= (length (disasm 1 'sb-thread:*current-thread*)) 1)) - (assert (= (length (disasm 1 'sb-sys:*interrupt-pending*)) 1)) - (assert (= (length (disasm 1 'sb-kernel:*gc-inhibit*)) 1)) - (assert (= (length (disasm 1 'sb-kernel:*restart-clusters*)) 1)) - (assert (= (length (disasm 1 'sb-kernel:*handler-clusters*)) 1))) + (assert (= (length (disasm-load 1 'sb-thread:*current-thread*)) 1)) + (assert (= (length (disasm-load 1 'sb-sys:*interrupt-pending*)) 1)) + (assert (= (length (disasm-load 1 'sb-kernel:*gc-inhibit*)) 1)) + (assert (= (length (disasm-load 1 'sb-kernel:*restart-clusters*)) 1)) + (assert (= (length (disasm-load 1 'sb-kernel:*handler-clusters*)) 1))) + +(with-test (:name :set-known-thread-local :skipped-on (or (not :immobile-space) + (not :sb-thread))) + ;; It should take 1 instruction to write a known thread-local var + (assert (= (length (disasm-store '(setq sb-kernel:*gc-inhibit* x))) 1))) ;; Lack of earmuffs on this symbol allocates it in dynamic space (defvar foo) @@ -71,7 +124,7 @@ ;; 83FA61 CMP EDX, 97 ;; 480F44142538F94B20 CMOVEQ RDX, [#x204BF938] ; *PRINT-BASE* ;; (TODO: could use "CMOVEQ RDX, [RIP-n]" in immobile code) - (let ((text (disasm 0 '*print-base*))) + (let ((text (disasm-load 0 '*print-base*))) (assert (= (length text) 3)) ; number of lines ;; two lines should be annotated with *PRINT-BASE* (assert (= (loop for line in text count (search "*PRINT-BASE*" line)) 2))) @@ -81,7 +134,7 @@ ;; 488B059EFFFFFF MOV RAX, [RIP-98] ; 'FOO ;; 83FA61 CMP EDX, 97 ;; 480F4450F9 CMOVEQ RDX, [RAX-7] - (let ((text (disasm 0 'foo))) + (let ((text (disasm-load 0 'foo))) (assert (= (length text) 4)) ;; two lines should be annotated with FOO (assert (= (loop for line in text count (search "FOO" line)) 2)))) @@ -100,7 +153,7 @@ ;; 83FA61 CMP EDX, 97 ;; 480F44142518A24C20 CMOVEQ RDX, [#x204CA218] ; *BLUB* ;; (TODO: could use "CMOVEQ RDX, [RIP-n]" in immobile code) - (let ((text (disasm 0 '*blub*))) + (let ((text (disasm-load 0 '*blub*))) (assert (= (length text) 4)) ;; two lines should be annotated with *BLUB* (assert (= (loop for line in text count (search "*BLUB*" line)) 2))) @@ -111,7 +164,7 @@ ;; 4A8B142A MOV RDX, [RDX+R13] ;; 83FA61 CMP EDX, 97 ;; 480F4450F9 CMOVEQ RDX, [RAX-7] - (assert (= (length (disasm 0 'blub)) 5))) + (assert (= (length (disasm-load 0 'blub)) 5))) (with-test (:name :object-not-type-error-encoding) ;; There should not be a "MOV Rnn, #xSYMBOL" instruction @@ -125,7 +178,9 @@ #\newline)) (index (position "OBJECT-NOT-TYPE-ERROR" lines :test 'search))) - (assert (search "; #<SB-KERNEL:LAYOUT for SB-ASSEM:LABEL" (nth (+ index 2) lines))))) + (let ((line (nth (+ index 2) lines))) + (assert (search "; #<SB-KERNEL:WRAPPER " line)) + (assert (search " SB-ASSEM:LABEL" line))))) #+immobile-code (with-test (:name :reference-assembly-tramp) @@ -160,40 +215,7 @@ (assert (find-line "CALL" "FUNCTION GENSYM")) (assert (find-line "JMP" "FUNCTION PRINT"))))) -#+immobile-code -(with-test (:name :static-unlinker) - (let ((sb-c::*compile-to-memory-space* :immobile)) - (declare (muffle-conditions style-warning)) - (flet ((disassembly-lines (name) - (split-string - (with-output-to-string (s) - (let ((sb-disassem:*disassem-location-column-width* 0)) - (disassemble name :stream s))) - #\newline)) - (expect (match lines) - (assert (loop for line in lines - thereis (search match line))))) - (compile 'h '(lambda (x) (1+ x))) - (setf (symbol-function 'g) #'h (symbol-function 'f) #'h) - (compile 'c '(lambda (x) (g x))) - (compile 'd '(lambda (x) (f (g x)))) - ;; The FDEFN-FUN of F is same as that of G. - ;; Statically linking D should not patch the fdefn calls into static calls - ;; because it can't unambiguously be undone without storing additional data - ;; about where patches were performed to begin with. - (sb-vm::statically-link-core :callers '(c d)) - (let ((lines (disassembly-lines 'c))) - (expect "#<FUNCTION H>" lines)) - (let ((lines (disassembly-lines 'd))) - (expect "#<FUNCTION H>" lines)) - (setf (symbol-function 'g) #'+) - (let ((lines (disassembly-lines 'c))) - (expect "#<FDEFN G>" lines)) - (let ((lines (disassembly-lines 'd))) - (expect "#<FDEFN G>" lines) - (expect "#<FUNCTION H>" lines))))) - -(with-test (:name :c-call) +(with-test (:name :c-call :skipped-on (and :win32 :x86-64)) (let* ((lines (split-string (with-output-to-string (s) (let ((sb-disassem:*disassem-location-column-width* 0)) @@ -317,6 +339,14 @@ (and (search "CMP QWORD PTR [" line) (search ":YUP" line)))))) +(defun thing-ref-thing-ref (arg1 arg2) + (declare (optimize (safety 0))) + (let ((answer (typep (thing-x (thing-x arg1)) 'fixnum))) + (frobify arg1 arg2) + answer)) +(defun frobify (a b) (values a b)) +(compile 'thing-ref-thing-ref) + (with-test (:name :fixnump-thing-ref) (flet ((try (access-form true false) (let* ((f (compile nil `(lambda (obj) (typep ,access-form 'fixnum)))) @@ -335,10 +365,12 @@ (try '(thing-x (truly-the thing obj)) (make-thing :x 1) (make-thing :x "hi")) (try '(car obj) '(1) '("hi")) - (try '(cdr obj) '("hi" . 1) '("hi")))) + (try '(cdr obj) '("hi" . 1) '("hi"))) + ;; fixnump of memref of memref was eliding one memref by accident + (assert (thing-ref-thing-ref (make-thing :x (make-thing :x 3)) 'foo))) (with-test (:name :huge-code :skipped-on (not :immobile-code)) - (sb-vm::allocate-code-object :immobile 0 4 (* 2 1024 1024))) + (sb-vm::allocate-code-object :immobile 4 (* 2 1024 1024))) (defun bbb (x y z) ;; I don't want the number of expected comparisons to depend on whether @@ -581,15 +613,6 @@ ;; n-widetags divided by 4, plus jump table count word. 65))) -sb-vm::(define-vop (cl-user::test) - (:generator 0 - ;; pointless to resize to :qword, but the rule won't try to apply itself - ;; to :dword because zeroing the upper 32 bits is a visible effect. - (inst mov (reg-in-size rax-tn :qword) (reg-in-size rcx-tn :qword)) - (inst mov rax-tn rcx-tn))) -(with-test (:name :mov-mov-elim-ignore-resized-reg) ; just don't crash - (checked-compile '(lambda () (sb-sys:%primitive test) 0))) - (defstruct a) (defstruct (achild (:include a))) (defstruct (agrandchild (:include achild))) @@ -676,16 +699,17 @@ sb-vm::(define-vop (cl-user::test) ;; component. (let ((names (mapcar (lambda (x) - (sb-kernel:classoid-name (sb-kernel:layout-classoid x))) - (ctu:find-code-constants #'sb-kernel:%%typep :type 'sb-kernel:layout)))) + (sb-kernel:classoid-name (sb-kernel:wrapper-classoid x))) + (ctu:find-code-constants #'sb-kernel:%%typep :type 'sb-kernel:wrapper)))) (assert (null (set-difference names '(sb-kernel:ctype sb-kernel:unknown-type sb-kernel:fun-designator-type sb-c::abstract-lexenv sb-kernel::classoid-cell - sb-kernel:layout + sb-kernel:wrapper sb-kernel:classoid + sb-kernel:built-in-classoid #-immobile-space null)))))) ;; lp#1857861 @@ -702,7 +726,7 @@ sb-vm::(define-vop (cl-user::test) (loop for line in (split-string (with-output-to-string (string) (disassemble f :stream string)) #\newline) - thereis (and (search "LAYOUT for" line) + thereis (and (search "WRAPPER for" line) (search "CMP DWORD PTR" line))))) (with-test (:name :thread-local-unbound) @@ -711,10 +735,549 @@ sb-vm::(define-vop (cl-user::test) #+immobile-code (with-test (:name :debug-fun-from-pc-more-robust) - (let ((trampoline - (sb-di::code-header-from-pc - (sb-sys:int-sap (sb-vm::fdefn-raw-addr - (sb-kernel::find-fdefn 'sb-kernel::get-internal-real-time)))))) - (assert (zerop (sb-kernel:code-n-entries trampoline))) - (assert (typep (sb-di::debug-fun-from-pc trampoline 8) - 'sb-di::bogus-debug-fun)))) + ;; This test verifies that debug-fun-from-pc does not croak when the PC points + ;; within a trampoline allocated to wrap a closure in a simple-funifying wrapper + ;; for installation into a global symbol. + (let ((closure (funcall (compile nil '(lambda (x) (lambda () x))) 0)) + (symbol (gensym))) + (assert (sb-kernel:closurep closure)) + (setf (fdefinition symbol) closure) + (let ((trampoline + (sb-di::code-header-from-pc + (sb-sys:int-sap (sb-vm::fdefn-raw-addr + (sb-int:find-fdefn symbol)))))) + (assert (zerop (sb-kernel:code-n-entries trampoline))) + (assert (typep (sb-di::debug-fun-from-pc trampoline 8) + 'sb-di::bogus-debug-fun))))) + +(defstruct foo (s 0 :type (or null string))) +(with-test (:name :reduce-stringp-to-not-null) + (let ((f1 (disassembly-lines + '(lambda (x) (if (null (foo-s (truly-the foo x))) 'not 'is)))) + (f2 (disassembly-lines + '(lambda (x) (if (stringp (foo-s (truly-the foo x))) 'is 'not))))) + ;; the comparison of X to NIL should be a single-byte test + (assert (loop for line in f1 + thereis (and (search (format nil "CMP ") line) ; register is arbitrary + (search (format nil ", ~D" (logand sb-vm:nil-value #xff)) line)))) + ;; the two variations of the test compile to the identical code + (dotimes (i 4) + (assert (string= (nth i f1) (nth i f2)))))) + +(with-test (:name :make-list-ridiculously-huge) + (checked-compile '(lambda () (make-list 3826305079707827596)) + :allow-warnings t)) + +(with-test (:name :with-foo-macro-elides-arg-count-trap) + (let ((lines + (split-string + (with-output-to-string (s) + (sb-c:dis '(lambda (x) (with-standard-io-syntax (eval x))) s)) + #\newline))) + ;; The outer lambda checks its arg count, but the lambda + ;; passed to call-with-mutex does not. + (assert (= (count-if (lambda (line) + (search "Invalid argument count trap" line)) + lines) + 1)))) + +(with-test (:name :known-array-rank) + (flet ((try (type) + (let ((lines + (disassembly-lines + `(lambda (x) + #+sb-safepoint (declare (optimize (sb-c::insert-safepoints 0))) + (array-rank (truly-the ,type x)))))) + ;; (format t "~{~&~A~}" lines) + ;; Naturally this is brittle as heck. I wish we had a better way. + (assert (<= (length lines) 9))))) + (try 'string) + (try '(and vector (not simple-array))) + (try '(or string bit-vector)) ; not an array type, but known rank + (try '(array * (4 5 *))))) + +;;; Match the same set of objects that %OTHER-POINTER-P does. +(deftype other-pointer-object () + '(not (or fixnum single-float function list sb-kernel:instance character))) + +;;; Helper to assert something about how many comparisons it takes to test +;;; for various sets of widetags. +(defun count-cmp-opcodes (type expect function) + (let ((lines (disassembly-lines function))) + (let ((actual + (loop for line in lines + count (or (search "CMP" line) + (search "TEST" line))))) + (unless (eql actual expect) + (format t "~{~&~a~}~%" lines) + (error "typep: needed ~d test ops but expected ~d for ~a" + actual expect type))))) + +(defun check-arrayp-cmp-opcodes (expect type) + ;; Assume the lowtag test passed already. + (count-cmp-opcodes type expect + `(lambda (x) + (declare (optimize (sb-c::verify-arg-count 0) + #+sb-safepoint (sb-c::insert-safepoints 0))) + (typep (truly-the other-pointer-object x) ',type)))) + +(with-test (:name :arrayp-exactly-one-comparison-etc) + (check-arrayp-cmp-opcodes 1 'array) + + (check-arrayp-cmp-opcodes 1 'string) + (check-arrayp-cmp-opcodes 1 'base-string) ; widetags differing in one bit + #+sb-unicode + (check-arrayp-cmp-opcodes 1 'sb-kernel::character-string) ; ditto + (check-arrayp-cmp-opcodes 1 'simple-string) ; 2 adjacent widetags + (check-arrayp-cmp-opcodes 1 '(and string (not simple-array))) + (check-arrayp-cmp-opcodes 1 'simple-base-string) + #+sb-unicode + (check-arrayp-cmp-opcodes 1 'sb-kernel::simple-character-string) + (check-arrayp-cmp-opcodes 1 '(and string (not simple-array))) + (check-arrayp-cmp-opcodes #+sb-unicode 1 + #-sb-unicode 2 + '(and array (not simple-array))) + + ;; some other interesting pairs + ;; This was passing just by random coincidence. + ;; The widetag patterns no longer differ in exactly 1 bit. + ;; Is there any real relevance to this test? + #+nil + (check-arrayp-cmp-opcodes 1 '(or (simple-array (unsigned-byte 8) (*)) + (simple-array (unsigned-byte 16) (*)))) + ;; FIXME: what's up with SIMPLE-UNBOXED-ARRAY requiring 1 SUB, + ;; 3 CMPs, and a MOVZX. Something doesn't feel right. + ;; In general, a lot of the array types are source-transforming to + ;; (AND (SB-KERNEL:%OTHER-POINTER-P #:OBJECT0) + ;; (EQ (SB-KERNEL:%OTHER-POINTER-WIDETAG #:OBJECT0) something)) + ) + +(defun check-integerp-cmp-opcodes (expect type) + (count-cmp-opcodes type expect + `(lambda (x) + (declare (optimize (sb-c::verify-arg-count 0) + #+sb-safepoint (sb-c::insert-safepoints 0))) + (typep x ',type)))) + +(with-test (:name :typep-integer-doubleton) + ;; This was taking 3 comparisons because it was a FIXNUMP test + ;; and some range-based testing rather than just 2 EQ tests. + (check-integerp-cmp-opcodes 2 '(integer 1 2))) + +(defun show-pretty-lines (type lines) + (format t ";;;; Type: ~s~%" type) + (dolist (line lines) + (when (plusp (length line)) + (let* ((label + (if (char= (char line 0) #\L) + (subseq line 0 (1+ (position #\: line))) + "")) + (opcode-bytes + (progn + (setq line (string-left-trim " " (subseq line (length label)))) + (subseq line 0 (position #\Space line))))) + (setq line (string-left-trim " " (subseq line (length opcode-bytes)))) + (format t "; ~4a~20a~a~%" + label opcode-bytes line)))) + (terpri)) + +(defun typep-asm-code-length (type &optional print) + (let* ((lines + (disassembly-lines + (compile nil + `(lambda (x) + (declare (optimize (sb-c::verify-arg-count 0) (debug 0))) + (typep x ',type))))) + (callp + (some (lambda (x) (or (search "#<FUNCTION" x) + (search "#<FDEFN" x))) + lines))) + (when print (show-pretty-lines type lines)) + (values (length lines) callp))) + +;;; Counting instructions of assembly is sort of a very rough guess +;;; as to whether widetags are being tested as efficiently as possible. +;;; This file is for both human and machine consumption. +;;; #\! precedes any line where the type test involves a function call. +;;; It might be just a call. We might consider inlining some of those. +(defun write-golden-typep-data (input-name output-name) + (with-open-file (input input-name) + (with-open-file (output output-name :direction :output + :if-exists :supersede + :if-does-not-exist :create) + (let ((*package* (find-package "SB-KERNEL")) + (*print-pretty* nil)) + (loop (let ((type (read input nil input))) + (when (eq type input) (return)) + (multiple-value-bind (linecount callp) (typep-asm-code-length type) + (format output "~a ~3d ~s~%" + (if callp "!" " ") + linecount type)))))))) + +#+nil +(write-golden-typep-data "../interesting-types.lisp-expr" + "typep-golden-data.txt") + +;;; FIXME: Some time after the MANY-INTERESTING-ARRAY-TYPES test +;;; got disabled, the code size changed either due to a regression, +;;; or more aggressive inlining of ">=" and "<=" +;;; which now causes these warnings. Figure out the new baseline. +;; +;; WARNING: (AND INTEGER (NOT (SIGNED-BYTE 31))) was 32 is 38 +;; WARNING: (AND INTEGER (NOT (SIGNED-BYTE 32))) was 32 is 38 +;; WARNING: (INTEGER (0) *) was 18 is 22 +;; WARNING: (INTEGER * -1) was 18 is 22 +;; WARNING: (INTEGER * -1000000) was 18 is 22 +;; WARNING: (INTEGER * -1073741825) was 18 is 23 +;; WARNING: (INTEGER * -12) was 18 is 22 +;; WARNING: (INTEGER * -14) was 18 is 22 +;; WARNING: (INTEGER * -17) was 18 is 22 +;; WARNING: (INTEGER * -2) was 18 is 22 +;; WARNING: (INTEGER * -2147483649) was 18 is 23 +;; WARNING: (INTEGER * -4611686018427387901) was 18 is 23 +;; WARNING: (INTEGER * -54043195528445951) was 18 is 23 +;; WARNING: (INTEGER * -541073411) was 18 is 22 +;; WARNING: (INTEGER * -6) was 18 is 22 +;; WARNING: (INTEGER * -9) was 18 is 22 +;; WARNING: (INTEGER * 0) was 24 is 22 +;; WARNING: (INTEGER * 20) was 18 is 22 +;; WARNING: (INTEGER * 2047) was 18 is 22 +;; WARNING: (INTEGER * 2147483647) was 18 is 23 +;; WARNING: (INTEGER * 4611686018427387900) was 18 is 23 +;; WARNING: (INTEGER * 576460752303423487) was 18 is 23 +;; WARNING: (INTEGER * 65535) was 18 is 22 +;; WARNING: (INTEGER -1) was 18 is 22 +;; WARNING: (INTEGER 1) was 18 is 22 +;; WARNING: (INTEGER 1073741824) was 18 is 23 +;; WARNING: (INTEGER 1152921504606846961) was 18 is 23 +;; WARNING: (INTEGER 1899) was 18 is 22 +;; WARNING: (INTEGER 2) was 18 is 22 +;; WARNING: (INTEGER 2147483648) was 18 is 23 +;; WARNING: (INTEGER 2305843009214) was 18 is 23 +;; WARNING: (INTEGER 4611686018427387900) was 18 is 23 +;; WARNING: (INTEGER 4611686018427387901) was 18 is 23 +;; WARNING: (INTEGER 4611686018427387902) was 18 is 23 +;; WARNING: (INTEGER 4611686018427387903) was 18 is 23 +;; WARNING: (INTEGER 63) was 18 is 22 +(defun compare-to-golden-typep-data (pathname &optional print) + (with-open-file (input pathname) + (let ((*package* (find-package "SB-KERNEL"))) + (loop (let ((line (read-line input nil input))) + (when (eq line input) (return)) + (with-input-from-string (stream line :start 2) + (let ((expect-n (read stream)) + (type (read stream))) + (multiple-value-bind (linecount callp) + (typep-asm-code-length type print) + (declare (ignore callp)) + (when (/= linecount expect-n) + (warn "~S was ~d is ~d" type expect-n linecount)))))))))) + +(with-test (:name :many-interesting-array-types + :skipped-on (:or (:not :sb-unicode) + (:not :immobile-space))) + (compare-to-golden-typep-data "typep-golden-data.txt")) + +(with-test (:name :integerp->bignump-strength-reduction) + (let ((f1 (compile nil '(lambda (x) + (typecase x (fixnum 'a) (integer 'b) (t 'c))))) + (f2 (compile nil '(lambda (x) + (typecase x (fixnum 'a) (bignum 'b) (t 'c)))))) + (assert (= (length (disassembly-lines f1)) + (length (disassembly-lines f2)))))) + +(with-test (:name :boundp+symbol-value + :skipped-on (not :sb-thread)) + ;; The vop combiner produces exactly one reference to SB-C::*COMPILATION*. + ;; Previously there would have been one from BOUNDP and one from SYMBOL-VALUE. + (let ((lines (disassembly-lines + '(lambda () + (if (boundp 'sb-c::*compilation*) sb-c::*compilation*) '(hi))))) + (dolist (line lines) + (assert (not (search "ERROR" line)))) + (assert (= (loop for line in lines + count (search "*COMPILATION*" line)) + 1))) + ;; Non-constant symbol works too now + (let ((lines (disassembly-lines + '(lambda (x) (if (boundp (truly-the symbol x)) x '(hi)))))) + (dolist (line lines) + (assert (not (search "ERROR" line)))))) + +;;; We were missing the fndb info that fill-pointer-error doesn't return +;;; (not exactly "missing", but in the wrong package) +(with-test (:name :fill-pointer-no-return-multiple) + (let ((lines (disassembly-lines '(lambda (x) (fill-pointer x))))) + (dolist (line lines) + (assert (not (search "RETURN-MULTIPLE" line)))))) + +(with-test (:name :elide-zero-fill) + (let* ((f (compile nil '(lambda () (make-array 100 :initial-element 0)))) + (lines (disassembly-lines f))) + (dolist (line lines) + (assert (not (search "REPE STOSQ" line)))))) + +;;; Word-sized stores (or larger, like double-float on 32-bit) would cons a new lisp object +(with-test (:name :sap-set-does-not-cons) + (loop for (type accessor telltale) in + '((sb-vm:word sb-sys:sap-ref-word "ALLOC-UNSIGNED-BIGNUM") + (double-float sb-sys:sap-ref-double "ALLOC-TRAMP")) + do (let* ((positive-test + (compile nil `(lambda (sap) (,accessor sap 0)))) + (negative-test + (compile nil `(lambda (sap obj) (setf (,accessor sap 0) obj))))) + ;; Positive test ensures we know the right telltale for the type + ;; in case the allocation logic changes + (assert (loop for line in (disassembly-lines positive-test) + thereis (search telltale line))) + (assert (not (loop for line in (disassembly-lines negative-test) + thereis (search telltale line))))))) + +(with-test (:name :bash-copiers-byte-or-larger) + (dolist (f '(sb-kernel::ub8-bash-copy + sb-kernel::ub16-bash-copy + sb-kernel::ub32-bash-copy + sb-kernel::ub64-bash-copy)) + ;; Should not call anything + (assert (not (ctu:find-code-constants (symbol-function f)))))) + +(defstruct bitsy + (fix 0 :type fixnum) + (sw 0 :type sb-vm:signed-word)) + +(defun s62 (x) (logtest (ash 1 62) (bitsy-fix x))) +(compile 's62) +(with-test (:name :lp-1939897) + (assert (not (s62 (make-bitsy :fix (ash 1 61)))))) + +(defmacro try-logbitp-walking-bit-test + (slot-name initarg nbits most-negative-value) + `(let ((functions (make-array ,nbits))) + (flet ((bit-num-to-value (b) + (if (= b ,(1- nbits)) ,most-negative-value (ash 1 b)))) + (loop for bit-index from 0 below ,nbits + do (setf (aref functions bit-index) + (compile nil `(lambda (obj) + (values (logtest ,(bit-num-to-value bit-index) + (,',slot-name obj)) + (logbitp ,bit-index (,',slot-name obj))))))) + (loop for set-bit-index from 0 below ,nbits + do (let ((struct (make-bitsy ,initarg + (bit-num-to-value set-bit-index)))) + (loop for test-bit-index from 0 below ,nbits + do (multiple-value-bind (value1 value2) + (funcall (aref functions test-bit-index) struct) + ;; The expressions should agree at each bit + (assert (eq value1 value2)) + ;; And should give the right answer + (if (= test-bit-index set-bit-index) + (assert value1) + (assert (not value1)))))))))) + +(with-test (:name :logbitp-vs-logtest-exhaustive-test) + (try-logbitp-walking-bit-test bitsy-fix :fix 63 + most-negative-fixnum) + (try-logbitp-walking-bit-test bitsy-sw :sw 64 + (sb-c::mask-signed-field 64 (ash 1 63)))) + +#+allocator-metrics ; missing symbols if absent feature +(with-test (:name :allocator-histogram-bucketing) + (let* ((min 0) (max 5000) + (var-fun (compile nil '(lambda (n) (make-array (the fixnum n)))))) + (loop for n-elements from min to max + do + (let* ((fixed-fun (compile nil `(lambda () (make-array ,n-elements)))) + (h1 (progn + (sb-thread::reset-allocator-histogram) + (funcall fixed-fun) + (first (sb-thread::allocator-histogram)))) + (h2 (progn + (sb-thread::reset-allocator-histogram) + (funcall var-fun n-elements) + (first (sb-thread::allocator-histogram))))) + ;; We have to allow for the possibilty of either or both MAKE-ARRAY calls causing + ;; a GC to occur immediately thereafter, which allocates a cons for the GC epoch. + ;; So if there is an extra element in bin 0, just remove it. + (when (and (> (aref h1 0) 0) + (= (loop for value across h1 sum value) 2)) + (decf (aref h1 0))) + (when (and (> (aref h2 0) 0) (= (loop for value across h2 sum value) 2)) + (decf (aref h2 0))) + (unless (and (= (loop for value across h1 sum value) 1) ; exactly 1 bucket is nonzero + (equalp h1 h2)) + (let ((*print-length* nil)) + (format t "h1=~s~%h2=~s~%" h1 h2) + (error "Error on n-elements = ~d" n-elements))))))) + +(with-test (:name :uniquify-fixups) + (let* ((f (let ((sb-c::*compile-to-memory-space* :dynamic)) + (compile nil + '(lambda (x) + `(,(list 1 2) ,(cons 1 2) ,(list nil x) ,(list '(a) #\x)))))) + (fixups + (sb-c::unpack-code-fixup-locs + (sb-vm::%code-fixups (sb-kernel:fun-code-header f))))) + ;; There are 5 call outs to the fallback allocator, but only 2 (or 3) + ;; fixups to the asm routines, because of uniquification per code component. + ;; 2 of them are are CONS->RNN and CONS->R11 + ;; the other is ENABLE-ALLOC-COUNTER which may or may not be present + (assert (<= (length fixups) 3)))) + +(defstruct submarine x y z) +(defstruct (moreslots (:include submarine)) a b c) +(declaim (ftype (function () double-float) get-dbl)) +(with-test (:name :write-combining-instance-set) + (let* ((f (compile nil '(lambda (s) + (setf (submarine-x (truly-the submarine s)) 0 + (submarine-y s) 0 + (submarine-z s) 0)))) + (lines (disassembly-lines f))) + (assert (= 1 (loop for line in lines count (search "MOVUPD" line)))) + (assert (= 1 (loop for line in lines count (search "MOVSD" line))))) + (let* ((f (compile nil '(lambda (s) + (setf (moreslots-a (truly-the moreslots s)) 0 + (submarine-x s) 0 + (moreslots-c s) 0)))) + (lines (disassembly-lines f))) + (assert (= 3 (loop for line in lines count (search "MOVSD" line))))) + ;; This was crashing in the MOV emitter (luckily) because it received + ;; an XMM register due to omission of a MOVE-FROM-DOUBLE to heap-allocate. + (compile nil + '(lambda (sub a) + (declare (submarine sub)) + (let ((fooval (+ (get-dbl) 23d0))) + (setf (submarine-x sub) a + (submarine-y sub) fooval) + a)))) + +#+immobile-code +(with-test (:name :no-static-linkage-if-notinline) + ;; The normal state of the image has no "static" calls to FIND-PACKAGE + ;; but also has no globally proclaimed NOTINLINE, because that would + ;; suppress the optimization for CACHED-FIND-PACKAGE on a constant string. + (assert (not (sb-vm::fdefn-has-static-callers (sb-int:find-fdefn 'find-package)))) + (assert (not (sb-int:info :function :inlinep 'find-package)))) + +(sb-vm::define-vop (trythis) + (:generator 1 + (sb-vm::inst and sb-vm::rax-tn (sb-c:make-fixup nil :gc-barrier)))) +(defun zook () + (sb-sys:%primitive trythis) + nil) + +;;; Previously INITIALIZE-VECTOR would move every element into +;;; a register, causing each to require a store barrier +;;; and then a register-to-memory move like so: +;;; BB02000000 MOV EBX, 2 +;;; 488D4601 LEA RAX, [RSI+1] +;;; 48C1E80A SHR RAX, 10 +;;; 25FFFF0F00 AND EAX, 1048575 +;;; 41C6040400 MOV BYTE PTR [R12+RAX], 0 +;;; 48895E01 MOV [RSI+1], RBX +;;; The improved code emits 4 consecutive MOV instructions, +;;; one per item. It is still suboptimal in that it can not discern +;;; between initializing and updating, so it always uses a :QWORD move +;;; despite the prezeroed pages. +(with-test (:name :init-vector-mov-to-mem) + (let* ((lines (disassembly-lines + '(lambda () (vector #\x 1 2 3)))) + (magic-value + (write-to-string + (logior (ash (char-code #\x) 8) sb-vm:character-widetag))) + (start + (position-if + (lambda (line) (search magic-value line)) + lines))) + (assert start) + (assert (search ", 2" (nth (+ start 1) lines))) + (assert (search ", 4" (nth (+ start 2) lines))) + (assert (search ", 6" (nth (+ start 3) lines))))) + +(defglobal *myglobalvar* 3) +(with-test (:name :disassemble-symbol-global-value) + (assert (loop for line in (disassembly-lines '(lambda () *myglobalvar*)) + thereis (search "*MYGLOBALVAR*" line)))) + +(defun compiler-trace-output-lines (lexpr) + (let ((string-stream (make-string-output-stream))) + (let ((sb-c::*compiler-trace-output* string-stream) + (sb-c::*compile-trace-targets* '(:vop)) + (*print-pretty* nil)) + (compile nil lexpr)) + (split-string (get-output-stream-string string-stream) + #\newline))) + +(defun assert-has-gc-barrier (match-string lines &optional (skip 0)) + + (let (found) +;; Look for something like this in the trace output: +;; "VOP CLOSURE-INIT t9[RBX(d)] :NORMAL t13[RSI(d)] :NORMAL {0} " +;; " MOV 0, #<TN t14[RAX(u)] :NORMAL>, #<TN t9[RBX(d)] :NORMAL>" +;; " SHR 0, #<TN t14[RAX(u)] :NORMAL>, 10" +;; " AND 6, #<TN t14[RAX(u)] :NORMAL>, #S(FIXUP :NAME NIL :FLAVOR GC-BARRIER :OFFSET 0)" +;; " MOV 4, PTR [R12+RAX+0], 0" +;; " MOV 7, PTR [RBX+5], #<TN t13[RSI(d)] :NORMAL>" + (loop while lines + do + (when (and (search match-string (car lines)) + (minusp (decf skip))) + (setq found t) + (let ((barrier-fixup-line (nth 3 lines))) + (assert (search ":FLAVOR GC-BARRIER" barrier-fixup-line)) + (return))) + (pop lines)) + ;; Fail if we didn't find the sentinel CLOSURE-INIT + (assert found))) + +(with-test (:name :closure-init-gc-barrier) + (let ((lines + (compiler-trace-output-lines + '(lambda (address) + (declare (sb-vm:word address)) + (let ((sap (sb-sys:int-sap address))) + (lambda () sap)))))) + (assert-has-gc-barrier "CLOSURE-INIT" lines))) + +(defstruct (point (:constructor make-point (x))) x (y 0) (z 0)) +(with-test (:name :structure-init-gc-barrier) + (let ((lines + (compiler-trace-output-lines + '(lambda (val) + (declare (double-float val) (inline make-point)) + (let ((neg (- val))) (make-point neg)))))) + (assert-has-gc-barrier "SET-SLOT" lines + #-compact-instance-header 1))) + +(with-test (:name :system-tlabs) + (when (find-symbol "SYS-ALLOC-TRAMP" "SB-VM") + (assert (loop for line in (disassembly-lines 'sb-impl:test-make-packed-info) + thereis (search "SYS-ALLOC-TRAMP" line))) + (assert (loop for line in (disassembly-lines 'sb-impl:test-copy-packed-info) + thereis (search "SYS-ALLOC-TRAMP" line))) + (let ((f (compile nil '(lambda (x) + (declare (sb-c::tlab :system)) + (sb-pcl::%copy-cache x))))) + (assert (loop for line in (disassembly-lines f) + thereis (search "SYS-ALLOC-TRAMP" line)))))) + +(defun find-in-disassembly (string lambda-expression) + (let ((disassembly + (with-output-to-string (s) + (disassemble (compile nil lambda-expression) :stream s)))) + (loop for line in (split-string disassembly #\Newline) + thereis (search string line)))) + +#+immobile-space +(with-test (:name :disassemble-alien-linkage-table-ref + :fails-on (not :sb-thread)) + (dolist (memspace '(:dynamic :immobile)) + (let ((sb-c::*compile-to-memory-space* memspace)) + (assert (find-in-disassembly + (if (eq sb-c::*compile-to-memory-space* :immobile) "lose" "&lose") + '(lambda () + (declare (optimize (sb-c::alien-funcall-saves-fp-and-pc 0))) + (alien-funcall (extern-alien "lose" (function void)))))) + (assert (find-in-disassembly + "&verify_gens" + '(lambda () + (extern-alien "verify_gens" char))))))) diff --git a/tlsf-bsd/.clang-format b/tlsf-bsd/.clang-format new file mode 100644 index 0000000000..2d07d2042f --- /dev/null +++ b/tlsf-bsd/.clang-format @@ -0,0 +1,12 @@ +BasedOnStyle: Chromium +Language: Cpp +MaxEmptyLinesToKeep: 3 +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false +DerivePointerAlignment: false +PointerAlignment: Right +TabWidth: 4 +UseTab: Never +IndentWidth: 4 +BreakBeforeBraces: Linux +AccessModifierOffset: -4 diff --git a/tlsf-bsd/.gitignore b/tlsf-bsd/.gitignore new file mode 100644 index 0000000000..81b995ff0b --- /dev/null +++ b/tlsf-bsd/.gitignore @@ -0,0 +1,17 @@ +*~ +*.o +*.i +*.s +*.P +*.elf +*.bin +*.hex +*.map +*.swp +*.fuse* +*.pyc +*.swo +*.out +build/ +tags +core diff --git a/tlsf-bsd/CHANGES b/tlsf-bsd/CHANGES new file mode 100644 index 0000000000..341b1be6d0 --- /dev/null +++ b/tlsf-bsd/CHANGES @@ -0,0 +1,63 @@ +History +------- +2014/02/08 - v3.0 + * This version is based on improvements from 3DInteractive GmbH + * Interface changed to allow more than one memory pool + * Separated pool handling from control structure (adding, removing, debugging) + * Control structure and pools can still be constructed in the same memory block + * Memory blocks for control structure and pools are checked for alignment + * Added functions to retrieve control structure size, alignment size, min and + max block size, overhead of pool structure, and overhead of a single allocation + * Minimal Pool size is tlsf_block_size_min() + tlsf_pool_overhead() + * Pool must be empty when it is removed, in order to allow O(1) removal + +2011/10/20 - v2.0 + * 64-bit support + * More compiler intrinsics for ffs/fls + * ffs/fls verification during TLSF creation in debug builds + +2008/04/04 - v1.9 + * Add tlsf_heap_check, a heap integrity check + * Support a predefined tlsf_assert macro + * Fix realloc case where block should shrink; if adjacent block is + in use, execution would go down the slow path + +2007/02/08 - v1.8 + * Fix for unnecessary reallocation in tlsf_realloc + +2007/02/03 - v1.7 + * tlsf_heap_walk takes a callback + * tlsf_realloc now returns NULL on failure + * tlsf_memalign optimization for 4-byte alignment + * Usage of size_t where appropriate + +2006/11/21 - v1.6 + * ffs/fls broken out into tlsfbits.h + * tlsf_overhead queries per-pool overhead + +2006/11/07 - v1.5 + * Smart realloc implementation + * Smart memalign implementation + +2006/10/11 - v1.4 + * Add some ffs/fls implementations + * Minor code footprint reduction + +2006/09/14 - v1.3 + * Profiling indicates heavy use of blocks of + size 1-128, so implement small block handling + * Reduce pool overhead by about 1kb + * Reduce minimum block size from 32 to 12 bytes + * Realloc bug fix + +2006/09/09 - v1.2 + * Add tlsf_block_size + * Static assertion mechanism for invariants + * Minor bugfixes + +2006/09/01 - v1.1 + * Add tlsf_realloc + * Add tlsf_walk_heap + +2006/08/25 - v1.0 + * First release diff --git a/tlsf-bsd/LICENSE b/tlsf-bsd/LICENSE new file mode 100644 index 0000000000..85fc74592e --- /dev/null +++ b/tlsf-bsd/LICENSE @@ -0,0 +1,26 @@ +TLSF-BSD is freely redistributable under the two-clause BSD License: + +Copyright (c) 2016 National Cheng Kung University, Taiwan. +Copyright (c) 2006-2008, 2011, 2014 Matthew Conte. +All rights reserved. + +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 THE AUTHOR 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 AUTHOR 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. diff --git a/tlsf-bsd/Makefile b/tlsf-bsd/Makefile new file mode 100644 index 0000000000..2807a1687f --- /dev/null +++ b/tlsf-bsd/Makefile @@ -0,0 +1,43 @@ +OUT = build + +TARGETS = \ + test-bits \ + test-alloc \ + bench-alloc +TARGETS := $(addprefix $(OUT)/,$(TARGETS)) + +all: $(TARGETS) + +CC = gcc +CFLAGS = \ + -std=c99 -Wall -g -I tlsf \ + -D TLSF_CONFIG_ASSERT +LDFLAGS = + +OBJS = tlsf.o +OBJS := $(addprefix $(OUT)/,$(OBJS)) +deps := $(OBJS:%.o=%.o.d) + +$(OUT)/test-%: $(OBJS) tests/test-%.c + $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) +deps += build/test-bits.d + +$(OUT)/bench-%: $(OBJS) tests/bench-%.c + $(CC) $(CFLAGS) -o $@ -MMD -MF $@.d $^ $(LDFLAGS) +# FIXME: avoid hardcode +deps += build/bench-alloc.d + +$(OUT)/%.o: tlsf/%.c + @mkdir -p $(OUT) + $(CC) $(CFLAGS) -c -o $@ -MMD -MF $@.d $< + +CMDSEP = ; echo "Please wait..." ; +check: $(TARGETS) + MALLOC_CHECK_=3 $(foreach prog,$(TARGETS),./$(prog) $(CMDSEP)) + +clean: + $(RM) $(TARGETS) $(OBJS) $(deps) + +.PHONY: all check clean + +-include $(deps) diff --git a/tlsf-bsd/README.md b/tlsf-bsd/README.md new file mode 100644 index 0000000000..38c9a014d2 --- /dev/null +++ b/tlsf-bsd/README.md @@ -0,0 +1,63 @@ +# TLSF-BSD + +Two Level Segregated Fit memory allocator implementation with O(1) +time complexity, distributed under the BSD License. + +## Features + +* O(1) cost for malloc, free, realloc, memalign +* Extremely low overhead per allocation (4 bytes) +* Low overhead per TLSF management of pools (~3kB) +* Low fragmentation +* Compiles to only a few kB of code and data +* Support for adding and removing memory pool regions on the fly + +## API Usage + +You can essentially pass a memory pool for TLSF to manage. +```C +enum { STATIC_POOL_SIZE = 1 << 20 }; +static char s_pool[STATIC_POOL_SIZE]; + +tlsf_t instance = tlsf_create_with_pool(s_pool, STATIC_POOL_SIZE); + +void *data = tlsf_malloc(instance, 64); +tlsf_free(instance, data); +``` + +## Caveats + +* Currently, assumes architecture can make 4-byte aligned accesses +* Not designed to be thread safe; the user must provide this + +## Notes +This code was based on the TLSF 1.4 spec and documentation found at: + http://www.gii.upv.es/tlsf/main/docs + +## Reference + +M. Masmano, I. Ripoll, A. Crespo, and J. Real. +TLSF: a new dynamic memory allocator for real-time systems. +In Proc. ECRTS (2004), IEEE Computer Society, pp. 79-86. + +This implementation was written to the specification of the document, +therefore no GPL restrictions apply. + +It also leverages the TLSF 2.0 improvement to shrink the per-block overhead +from 8 to 4 bytes. + +## Known Issues + +* Due to the internal block structure size and the implementation +details of `tlsf_memalign`, there is worst-case behavior when requesting +small (<16 byte) blocks aligned to 8-byte boundaries. Overuse of memalign +will generally increase fragmentation, but this particular case will leave +lots of unusable "holes" in the pool. The solution would be to internally +align all blocks to 8 bytes, but this will require significantl changes +to the implementation. + +## Licensing + +TLSF-BSD is freely redistributable under the two-clause BSD License. +Use of this source code is governed by a BSD-style license that can be found +in the `LICENSE` file. diff --git a/tlsf-bsd/tests/bench-alloc.c b/tlsf-bsd/tests/bench-alloc.c new file mode 100644 index 0000000000..3d35ca5d42 --- /dev/null +++ b/tlsf-bsd/tests/bench-alloc.c @@ -0,0 +1,227 @@ +/* Copyright (c) 2016 National Cheng Kung University, Taiwan. + * All rights reserved. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef _DEFAULT_SOURCE +#define _DEFAULT_SOURCE +#endif +#define _POSIX_C_SOURCE 199309L + +#include <unistd.h> +#include <assert.h> +#include <errno.h> +#include <sched.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/time.h> +#include <sys/resource.h> +#include <time.h> + +#include "lran2.h" +#include "tlsf.h" + +static tlsf_t *tlsf; + +static void usage(const char *name) +{ + printf("run a malloc benchmark.\n" + "usage: %s [-s blk-size|blk-min:blk-max] [-l loop-count] " + "[-n num-blocks] [-c]\n", + name); + exit(-1); +} + +/* Parse an integer argument. */ +static int parse_int_arg(const char *arg, const char *exe_name) +{ + long int ret; + + errno = 0; + ret = strtol(arg, NULL, 0); + if (errno) + usage(exe_name); + + return (int) ret; +} + +/* Parse a size argument, which is either an integer or two integers + separated by a colon, denoting a range. */ +static void +parse_size_arg(const char *arg, const char *exe_name, + size_t *blk_min, size_t *blk_max) +{ + long int ret; + char *endptr; + + errno = 0; + ret = strtol(arg, &endptr, 0); + + if (errno) + usage(exe_name); + + *blk_min = (int)ret; + + if (endptr && *endptr == ':') { + errno = 0; + ret = strtol(endptr + 1, NULL, 0); + + if (errno) + usage(exe_name); + } + + *blk_max = (int)ret; + + if (blk_min > blk_max) + usage(exe_name); +} + +/* Get a random block size between blk_min and blk_max. */ +static size_t +get_random_block_size(size_t blk_min, size_t blk_max, + struct lran2_st *lran2_state) +{ + size_t blk_size; + + if (blk_max > blk_min) { + blk_size = blk_min + (lran2(lran2_state) % (blk_max - blk_min)); + } else + blk_size = blk_min; + + return blk_size; +} + +static void +run_alloc_benchmark(int loops, size_t blk_min, size_t blk_max, + void **blk_array, size_t num_blks, bool clear, + struct lran2_st *lran2_state) +{ + while (loops--) { + int next_idx = lran2(lran2_state) % num_blks; + size_t blk_size = get_random_block_size(blk_min, blk_max, lran2_state); + + if (blk_array[next_idx]) + tlsf_free(tlsf, blk_array[next_idx]); + + /* Insert the newly alloced block into the array at a random point. */ + blk_array[next_idx] = tlsf_malloc(tlsf, blk_size); + if (clear) + memset(blk_array[next_idx], 0, blk_size); + } + + /* Free up all allocated blocks. */ + for (size_t i = 0; i < num_blks; i++) { + if (blk_array[i]) + tlsf_free(tlsf, blk_array[i]); + } +} + +struct alloc_desc { + /* Generic fields. */ + int loops; + size_t blk_min; + size_t blk_max; + void **blk_array; + size_t num_blks; + bool clear; +}; + +static void start_bench(void *arg) +{ + struct alloc_desc *desc = arg; + struct lran2_st lran2_state; + + lran2_init(&lran2_state, time(NULL) ^ getpid()); + + run_alloc_benchmark(desc->loops, desc->blk_min, desc->blk_max, + desc->blk_array, desc->num_blks, desc->clear, + &lran2_state); +} + +static void stop_bench(void *arg) +{ + struct alloc_desc *desc = arg; + if (!desc) return; + free(desc->blk_array); +} + +int main(int argc, char **argv) +{ + size_t blk_min = 512, blk_max = 512, num_blks = 10000; + int loops = 10000000; + bool clear = false; + int opt; + + while ((opt = getopt(argc, argv, "s:l:r:t:n:b:ch")) > 0) { + switch (opt) { + case 's': + parse_size_arg(optarg, argv[0], &blk_min, &blk_max); + break; + case 'l': + loops = parse_int_arg(optarg, argv[0]); + break; + case 'n': + num_blks = parse_int_arg(optarg, argv[0]); + break; + case 'c': + clear = true; + break; + case 'h': + usage(argv[0]); + break; + default: + usage(argv[0]); + break; + } + } + + const size_t overhead = tlsf_size() + tlsf_pool_overhead() + + tlsf_alloc_overhead(); + char *space = malloc(blk_max * num_blks + overhead); + assert(space); + tlsf = tlsf_create_with_pool(space, blk_max * num_blks + overhead); + + struct alloc_desc desc = { + .loops = loops, + .blk_min = blk_min, + .blk_max = blk_max, + .blk_array = malloc(num_blks * sizeof(unsigned char *)), + .num_blks = num_blks, + .clear = clear, + }; + assert(desc.blk_array != NULL); + memset(desc.blk_array, 0, num_blks * sizeof(unsigned char *)); + + struct timespec start, end; + + int err = clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &start); + assert(err == 0); + start_bench(&desc); + + err = clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &end); + assert(err == 0); + stop_bench(&desc); + + double elapsed = (end.tv_sec - start.tv_sec) + + (end.tv_nsec - start.tv_nsec) * 1e-9; + + struct rusage usage; + err = getrusage(RUSAGE_SELF, &usage); + assert(err == 0); + + tlsf_destroy(tlsf); + free(space); + + /* Dump both machine and human readable versions */ + printf("%u:%u:%u:%u:%u:%.6f: took %.6f s for %u malloc/free\n" + "benchmark loops of %u-%u bytes. ~%.3f us per loop\n", + blk_min, blk_max, loops, + (int)clear, usage.ru_maxrss, elapsed, elapsed, loops, blk_min, + blk_max, (double)(elapsed / loops) * 1e6); + + return 0; +} diff --git a/tlsf-bsd/tests/lran2.h b/tlsf-bsd/tests/lran2.h new file mode 100644 index 0000000000..34acdc8b81 --- /dev/null +++ b/tlsf-bsd/tests/lran2.h @@ -0,0 +1,44 @@ +/* Copyright (c) 1996 Wolfram Gloger. + * A small, portable pseudo-random number generator. + */ + +#ifndef _LRAN2_H +#define _LRAN2_H + +#define LRAN2_MAX 714025l /* constants for portable */ +#define IA 1366l /* random number generator */ +#define IC 150889l /* (see e.g. `Numerical Recipes') */ + +struct lran2_st { + long x, y, v[97]; +}; + +static inline +void lran2_init(struct lran2_st *d, long seed) +{ + long x = (IC - seed) % LRAN2_MAX; + if (x < 0) + x = -x; + for (int j = 0; j < 97; j++) { + x = (IA * x + IC) % LRAN2_MAX; + d->v[j] = x; + } + d->x = (IA * x + IC) % LRAN2_MAX; + d->y = d->x; +} + +static inline +long lran2(struct lran2_st *d) +{ + int j = (d->y % 97); + + d->y = d->v[j]; + d->x = (IA * d->x + IC) % LRAN2_MAX; + d->v[j] = d->x; + return d->y; +} + +#undef IA +#undef IC + +#endif diff --git a/tlsf-bsd/tests/test-alloc.c b/tlsf-bsd/tests/test-alloc.c new file mode 100644 index 0000000000..9d4421a344 --- /dev/null +++ b/tlsf-bsd/tests/test-alloc.c @@ -0,0 +1,106 @@ +#ifndef _DEFAULT_SOURCE +#define _DEFAULT_SOURCE +#endif + +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <time.h> +#include <assert.h> +#include <err.h> + +#include <tlsf.h> + +static void random_test(const size_t spacelen, const size_t cap) +{ + const size_t overhead = tlsf_size() + tlsf_pool_overhead() + + tlsf_alloc_overhead(); + const size_t maxitems = spacelen; + size_t len; + uint8_t *space, *data; + unsigned i = 0; + tlsf_t *tlsf; + void **p; + + space = malloc(spacelen + overhead); + if (space == NULL) { + err(EXIT_FAILURE, "malloc"); + } + + p = malloc(maxitems * sizeof(void *)); + if (p == NULL) { + err(EXIT_FAILURE, "malloc"); + } + + tlsf = tlsf_create_with_pool(space, + spacelen + overhead); + assert(tlsf != NULL); + + /* + * Allocate random sizes up to the cap threshold. + * Track them in an array. + */ + for (;;) { + len = (random() % cap) + 1; + p[i] = tlsf_malloc(tlsf, len); + if (!p[i]) + break; + + /* Fill with magic (only when testing up to 1MB). */ + data = p[i]; + if (spacelen <= 1024 * 1024) { + memset(data, 0, len); + } + data[0] = 0xa5; + + if (i++ == maxitems) + break; + } + + /* + * Randomly deallocate the memory blocks until all of them are freed. + * The free space should match the free space after initialisation. + */ + for (unsigned n = i; n;) { + unsigned target = random() % i; + if (p[target] == NULL) + continue; + data = p[target]; + assert(data[0] == 0xa5); + tlsf_free(tlsf, p[target]); + p[target] = NULL; + n--; + } + + tlsf_destroy(tlsf); + free(space); + free(p); +} + +#define __arraycount(__x) \ + (sizeof(__x) / sizeof(__x[0])) + +static void random_sizes_test(void) +{ + const uint32_t sizes[] = {128, 1024, 1024 * 1024, 128 * 1024 * 1024}; + + for (unsigned i = 0; i < __arraycount(sizes); i++) { + unsigned n = 1024; + + while (n--) { + uint32_t cap = random() % sizes[i] + 1; + printf("sizes = %d, cap = %d\n", sizes[i], cap); + random_test(sizes[i], cap); + } + } +} + +int main(void) +{ + srandom(time(NULL) ^ getpid()); + random_sizes_test(); + puts("OK!"); + return 0; +} diff --git a/tlsf-bsd/tests/test-bits.c b/tlsf-bsd/tests/test-bits.c new file mode 100644 index 0000000000..47dbbc03e8 --- /dev/null +++ b/tlsf-bsd/tests/test-bits.c @@ -0,0 +1,31 @@ +#include <stdio.h> +#include "tlsf_utils.h" + +int test_ffs_fls() +{ + /* Verify ffs/fls work properly. */ + int rv = 0; + rv += (tlsf_ffs(0) == -1) ? 0 : 0x1; + rv += (tlsf_fls(0) == -1) ? 0 : 0x2; + rv += (tlsf_ffs(1) == 0) ? 0 : 0x4; + rv += (tlsf_fls(1) == 0) ? 0 : 0x8; + rv += (tlsf_ffs(0x80000000) == 31) ? 0 : 0x10; + rv += (tlsf_ffs(0x80008000) == 15) ? 0 : 0x20; + rv += (tlsf_fls(0x80000008) == 31) ? 0 : 0x40; + rv += (tlsf_fls(0x7FFFFFFF) == 30) ? 0 : 0x80; + +#if defined(TLSF_64BIT) + rv += (tlsf_fls_sizet(0x80000000) == 31) ? 0 : 0x100; + rv += (tlsf_fls_sizet(0x100000000) == 32) ? 0 : 0x200; + rv += (tlsf_fls_sizet(0xffffffffffffffff) == 63) ? 0 : 0x400; +#endif + + if (rv) + printf("test_ffs_fls: %x ffs/fls tests failed.\n", rv); + return rv; +} + +int main() +{ + return test_ffs_fls(); +} diff --git a/tlsf-bsd/tlsf/tlsf.c b/tlsf-bsd/tlsf/tlsf.c new file mode 100644 index 0000000000..6ea8309912 --- /dev/null +++ b/tlsf-bsd/tlsf/tlsf.c @@ -0,0 +1,1111 @@ +/* Copyright (c) 2016 National Cheng Kung University, Taiwan. + * Copyright (c) 2006-2008, 2011, 2014 Matthew Conte. + * All rights reserved. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include <limits.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "tlsf-bsd/tlsf/tlsf.h" + +#include "tlsf-bsd/tlsf/tlsf_utils.h" + +#if __GNUC__ || __INTEL_COMPILER +#define likely(x) __builtin_expect(!!(x), 1) +#define unlikely(x) __builtin_expect(!!(x), 0) +#else +#define likely(x) (x) +#define unlikely(x) (x) +#endif + +#ifdef TLSF_CONFIG_ASSERT +#include <assert.h> +#define tlsf_assert(expr) assert(expr) +#else +#define tlsf_assert(expr) (void)(0) +#endif + +#include "genesis/config.h" +#include "genesis/constants.h" + +/* Public constants: may be modified. */ +enum tlsf_public { + /* log2 of number of linear subdivisions of block sizes. Larger + * values require more memory in the control structure. Values of + * 4 or 5 are typical. + */ + SL_INDEX_COUNT_LOG2 = 5, +}; + +/* Private constants: do not modify. */ +enum tlsf_private { +#if defined(TLSF_64BIT) + /* All allocation sizes and addresses are aligned to 8 bytes. */ + ALIGN_SIZE_LOG2 = 3, +#else + /* All allocation sizes and addresses are aligned to 4 bytes. */ + ALIGN_SIZE_LOG2 = 2, +#endif + ALIGN_SIZE = (1 << ALIGN_SIZE_LOG2), + +/* + * We support allocations of sizes up to (1 << FL_INDEX_MAX) bits. + * However, because we linearly subdivide the second-level lists, and + * our minimum size granularity is 4 bytes, it doesn't make sense to + * create first-level lists for sizes smaller than SL_INDEX_COUNT * 4, + * or (1 << (SL_INDEX_COUNT_LOG2 + 2)) bytes, as there we will be + * trying to split size ranges into more slots than we have available. + * Instead, we calculate the minimum threshold size, and place all + * blocks below that size into the 0th first-level list. + */ + + FL_INDEX_MAX = 30, + SL_INDEX_COUNT = (1 << SL_INDEX_COUNT_LOG2), + FL_INDEX_SHIFT = (SL_INDEX_COUNT_LOG2 + ALIGN_SIZE_LOG2), + FL_INDEX_COUNT = (FL_INDEX_MAX - FL_INDEX_SHIFT + 1), + + SMALL_BLOCK_SIZE = (1 << FL_INDEX_SHIFT), +}; + +/* + * Cast and min/max macros. + */ +#define tlsf_cast(t, exp) ((t)(exp)) +#define tlsf_min(a, b) ((a) < (b) ? (a) : (b)) +#define tlsf_max(a, b) ((a) > (b) ? (a) : (b)) + +/* + * Static assertion mechanism. + */ +#define _tlsf_glue2(x, y) x##y +#define _tlsf_glue(x, y) _tlsf_glue2(x, y) +#define tlsf_static_assert(exp) \ + typedef char _tlsf_glue(static_assert, __LINE__)[(exp) ? 1 : -1] + +/* This code has been tested on 32- and 64-bit (LP/LLP) architectures. */ +tlsf_static_assert(sizeof(int) * CHAR_BIT == 32); +tlsf_static_assert(sizeof(size_t) * CHAR_BIT >= 32); +tlsf_static_assert(sizeof(size_t) * CHAR_BIT <= 64); + +/* SL_INDEX_COUNT must be <= number of bits in sl_bitmap's storage type. */ +tlsf_static_assert(sizeof(unsigned int) * CHAR_BIT >= SL_INDEX_COUNT); + +/* Ensure we've properly tuned our sizes. */ +tlsf_static_assert(ALIGN_SIZE == SMALL_BLOCK_SIZE / SL_INDEX_COUNT); + +/* + * Data structures and associated constants. + */ + +/* + * Block header structure. + * + * There are several implementation subtleties involved: + * - The prev_phys_block field is only valid if the previous block is free. + * - The prev_phys_block field is actually stored at the end of the + * previous block. It appears at the beginning of this structure only to + * simplify the implementation. + * - The next_free / prev_free fields are only valid if the block is free. + */ +typedef struct block_header_t { + /* Points to the previous physical block. */ + struct block_header_t *prev_phys_block; + +#ifdef LISP_FEATURE_LITTLE_ENDIAN + unsigned char widetag; + unsigned char _flags; // must have at most bits 0, 1, 2 on + unsigned char unused; // must be zero + unsigned char gen; // low 4 must be 0..5 and bit 0x4 can be on + uint32_t _nwords; // including the header +#else + // For this word to read as an object header, the size and widetag + // are flipped relative to little-endian. + // I did not actually test this - I am merely guessing that it's right. + uint32_t _nwords; // including the header + unsigned char gen; // low 4 must be 0..5 and bit 0x4 can be on + unsigned char unused; // must be zero + unsigned char _flags; // must have at most bits 0, 1, 2 on + unsigned char widetag; +#endif + + /* Next and previous free blocks. */ + struct block_header_t *next_free; + struct block_header_t *prev_free; +} block_header_t; + +/* + * - byte 1 bit 0: whether block is busy (0) or free (1) + * - byte 1 bit 1: whether previous block is busy (0) or free (1) + */ +static const unsigned char block_header_free_bit = 1 << 0; +static const unsigned char block_header_prev_free_bit = 1 << 1; + +/* + * The size of the block header exposed to used blocks is the size field. + * The prev_phys_block field is stored *inside* the previous free block. + */ +static const size_t block_header_overhead = sizeof(size_t); + +/* + * The size of the block header that overlaps the previous block, + * namely the size of prev_phys_block field. + */ +static const size_t block_header_overlap = sizeof(block_header_t *); + +/* User data starts directly after the size field in a used block. */ +static const size_t block_start_offset = offsetof(block_header_t, next_free); + +/* + * A free block must be large enough to store its header minus the size of + * the metadata field, and no larger than the number of addressable + * bits for FL_INDEX. + */ +static const size_t block_size_min = + sizeof(block_header_t) - sizeof(size_t); // FIXME: metadata +static const size_t block_size_max = tlsf_cast(size_t, 1) << FL_INDEX_MAX; + +/* The TLSF control structure. */ +typedef struct control_t { + /* Empty lists point at this block to indicate they are free. */ + block_header_t block_null; + + /* Bitmaps for free lists. */ + unsigned int fl_bitmap; + unsigned int sl_bitmap[FL_INDEX_COUNT]; + + /* Head of free lists. */ + block_header_t *blocks[FL_INDEX_COUNT][SL_INDEX_COUNT]; +} control_t; + +/* + * block_header_t member functions. + */ + +static size_t block_size(const block_header_t *block) +{ + return (block->_nwords - 1) << WORD_SHIFT; // nbytes excluding the lispobj header +} + +static void block_set_size(block_header_t *block, size_t size) +{ + // convert to words inclusive of the header, as codeblobs require + block->_nwords = (size >> WORD_SHIFT) + 1; +} + +__attribute__((unused)) static int block_is_last(const block_header_t *block) +{ + return block->_nwords <= 2; +} + +static int block_is_free(const block_header_t *block) +{ + return tlsf_cast(int, block->_flags & block_header_free_bit); +} + +static void block_set_free(block_header_t *block) +{ + tlsf_assert(block->widetag == FILLER_WIDETAG); + block->_flags |= block_header_free_bit; +} + +static void block_set_used(block_header_t *block) +{ + block->_flags &= ~block_header_free_bit; +} + +static int block_is_prev_free(const block_header_t *block) +{ + return tlsf_cast(int, block->_flags & block_header_prev_free_bit); +} + +static void block_set_prev_free(block_header_t *block) +{ + block->_flags |= block_header_prev_free_bit; +} + +static void block_set_prev_used(block_header_t *block) +{ + block->_flags &= ~block_header_prev_free_bit; +} + +static block_header_t *block_from_ptr(const void *ptr) +{ + return tlsf_cast(block_header_t *, + tlsf_cast(unsigned char *, ptr) - block_start_offset); +} + +static void *block_to_ptr(const block_header_t *block) +{ + return tlsf_cast(void *, + tlsf_cast(unsigned char *, block) + block_start_offset); +} + +/* Return location of next block after block of given size. */ +static block_header_t *offset_to_block(const void *ptr, ptrdiff_t size) +{ + return tlsf_cast(block_header_t *, + tlsf_cast(ptrdiff_t, ptr) + size - block_header_overlap); +} + +/* Return location of previous block. */ +static block_header_t *block_prev(const block_header_t *block) +{ + tlsf_assert(block_is_prev_free(block) && "previous block must be free"); + return block->prev_phys_block; +} + +/* Return location of next existing block. */ +static block_header_t *block_next(const block_header_t *block) +{ + block_header_t *next = + offset_to_block(block_to_ptr(block), block_size(block)); + tlsf_assert(!block_is_last(block)); + return next; +} + +/* Link a new block with its physical neighbor, return the neighbor. */ +static block_header_t *block_link_next(block_header_t *block) +{ + block_header_t *next = block_next(block); + next->prev_phys_block = block; + return next; +} + +static void block_mark_as_free(block_header_t *block) +{ + /* Link the block to the next block, first. */ + block_header_t *next = block_link_next(block); + block_set_prev_free(next); + block_set_free(block); +} + +static void block_mark_as_used(block_header_t *block) +{ + block_header_t *next = block_next(block); + block_set_prev_used(next); + block_set_used(block); +} + +static size_t align_up(size_t x, size_t align) +{ + tlsf_assert(0 == (align & (align - 1)) && "must align to a power of two"); + return (x + (align - 1)) & ~(align - 1); +} + +static size_t align_down(size_t x, size_t align) +{ + tlsf_assert(0 == (align & (align - 1)) && "must align to a power of two"); + return x - (x & (align - 1)); +} + +static void *align_ptr(const void *ptr, size_t align) +{ + const ptrdiff_t aligned = + (tlsf_cast(ptrdiff_t, ptr) + (align - 1)) & ~(align - 1); + tlsf_assert(0 == (align & (align - 1)) && "must align to a power of two"); + return tlsf_cast(void *, aligned); +} + +/* + * Adjust an allocation size to be aligned to word size, and no smaller + * than internal minimum. +*/ +static size_t adjust_request_size(size_t size, size_t align) +{ + size_t adjust = 0; + if (size) { + const size_t aligned = align_up(size, align); + + /* aligned sized must not exceed block_size_max */ + if (aligned < block_size_max) { + adjust = tlsf_max(aligned, block_size_min); + } + } + return adjust; +} + +/* + * TLSF utility functions. In most cases, these are direct translations of + * the documentation found in the white paper. +*/ + +static void mapping_insert(size_t size, int *fli, int *sli) +{ + int fl, sl; + if (size < SMALL_BLOCK_SIZE) { + /* Store small blocks in first list. */ + fl = 0; + sl = tlsf_cast(int, size) / (SMALL_BLOCK_SIZE / SL_INDEX_COUNT); + } else { + fl = tlsf_fls_sizet(size); + sl = tlsf_cast(int, size >> (fl - SL_INDEX_COUNT_LOG2)) ^ + (1 << SL_INDEX_COUNT_LOG2); + fl -= (FL_INDEX_SHIFT - 1); + } + *fli = fl; + *sli = sl; +} + +/* This version rounds up to the next block size (for allocations) */ +static void mapping_search(size_t size, int *fli, int *sli) +{ + if (size >= SMALL_BLOCK_SIZE) { + const size_t round = + (1 << (tlsf_fls_sizet(size) - SL_INDEX_COUNT_LOG2)) - 1; + size += round; + } + mapping_insert(size, fli, sli); +} + +static block_header_t *search_suitable_block(control_t *control, + int *fli, + int *sli) +{ + int fl = *fli; + int sl = *sli; + + /* + * First, search for a block in the list associated with the given + * fl/sl index. + */ + unsigned int sl_map = control->sl_bitmap[fl] & (((unsigned int)~0) << sl); + if (!sl_map) { + /* No block exists. Search in the next first-level list. */ + const unsigned int fl_map = + control->fl_bitmap & (((unsigned int)~0) << (fl + 1)); + if (!fl_map) { + /* No free blocks available, memory has been exhausted. */ + return NULL; + } + + fl = tlsf_ffs(fl_map); + *fli = fl; + sl_map = control->sl_bitmap[fl]; + } + tlsf_assert(sl_map && "internal error - second level bitmap is null"); + sl = tlsf_ffs(sl_map); + *sli = sl; + + /* Return the first block in the free list. */ + return control->blocks[fl][sl]; +} + +/* Remove a free block from the free list.*/ +static void remove_free_block(control_t *control, + block_header_t *block, + int fl, + int sl) +{ + block_header_t *prev = block->prev_free; + block_header_t *next = block->next_free; + tlsf_assert(prev && "prev_free field can not be null"); + tlsf_assert(next && "next_free field can not be null"); + next->prev_free = prev; + prev->next_free = next; + + /* If this block is the head of the free list, set new head. */ + if (control->blocks[fl][sl] == block) { + control->blocks[fl][sl] = next; + + /* If the new head is null, clear the bitmap. */ + if (next == &control->block_null) { + control->sl_bitmap[fl] &= ~(1U << sl); + + /* If the second bitmap is now empty, clear the fl bitmap. */ + if (!control->sl_bitmap[fl]) { + control->fl_bitmap &= ~(1U << fl); + } + } + } +} + +/* Insert a free block into the free block list. */ +static void insert_free_block(control_t *control, + block_header_t *block, + int fl, + int sl) +{ + block_header_t *current = control->blocks[fl][sl]; + tlsf_assert(current && "free list cannot have a null entry"); + tlsf_assert(block && "cannot insert a null entry into the free list"); + block->next_free = current; + block->prev_free = &control->block_null; + current->prev_free = block; + + tlsf_assert(block_to_ptr(block) == + align_ptr(block_to_ptr(block), ALIGN_SIZE) && + "block not aligned properly"); + /* + * Insert the new block at the head of the list, and mark the first- + * and second-level bitmaps appropriately. + */ + control->blocks[fl][sl] = block; + control->fl_bitmap |= (1U << fl); + control->sl_bitmap[fl] |= (1U << sl); +} + +/* Remove a given block from the free list. */ +static void block_remove(control_t *control, block_header_t *block) +{ + int fl, sl; + mapping_insert(block_size(block), &fl, &sl); + remove_free_block(control, block, fl, sl); +} + +/* Insert a given block into the free list. */ +static void block_insert(control_t *control, block_header_t *block) +{ + int fl, sl; + mapping_insert(block_size(block), &fl, &sl); + insert_free_block(control, block, fl, sl); +} + +static int block_can_split(block_header_t *block, size_t size) +{ + return block_size(block) >= sizeof(block_header_t) + size; +} + +/* Split a block into two, the second of which is free. */ +static block_header_t *block_split(block_header_t *block, size_t size) +{ + /* Calculate the amount of space left in the remaining block. */ + block_header_t *remaining = offset_to_block(block_to_ptr(block), size); + + const size_t remain_size = + block_size(block) - (size + block_header_overhead); + + tlsf_assert(block_to_ptr(remaining) == + align_ptr(block_to_ptr(remaining), ALIGN_SIZE) && + "remaining block not aligned properly"); + + tlsf_assert(block_size(block) == + remain_size + size + block_header_overhead); + // Clear the block header word to 0 but stuff in a valid widetag. + *(1 + (uintptr_t*)remaining) = FILLER_WIDETAG; + block_set_size(remaining, remain_size); + tlsf_assert(block_size(remaining) >= block_size_min && + "block split with invalid size"); + + block_set_size(block, size); + block_mark_as_free(remaining); + + return remaining; +} + +/* Absorb a free block's storage into an adjacent previous free block. */ +static block_header_t *block_absorb(block_header_t *prev, block_header_t *block) +{ + tlsf_assert(!block_is_last(prev) && "previous block can't be last"); + /* Note: Leaves flags untouched. */ + prev->_nwords += block->_nwords; + block_link_next(prev); + return prev; +} + +/* Merge a just-freed block with an adjacent previous free block. */ +static block_header_t *block_merge_prev(control_t *control, + block_header_t *block) +{ + if (block_is_prev_free(block)) { + block_header_t *prev = block_prev(block); + tlsf_assert(prev && "prev physical block can't be null"); + tlsf_assert(block_is_free(prev) && + "prev block is not free though marked as such"); + block_remove(control, prev); + block = block_absorb(prev, block); + } + + return block; +} + +/* Merge a just-freed block with an adjacent free block. */ +static block_header_t *block_merge_next(control_t *control, + block_header_t *block) +{ + block_header_t *next = block_next(block); + tlsf_assert(next && "next physical block can't be null"); + + if (block_is_free(next)) { + tlsf_assert(!block_is_last(block) && "previous block can't be last"); + block_remove(control, next); + block = block_absorb(block, next); + } + + return block; +} + +/* Trim any trailing block space off the end of a block, return to pool. */ +static void block_trim_free(control_t *control, + block_header_t *block, + size_t size) +{ + tlsf_assert(block_is_free(block) && "block must be free"); + if (block_can_split(block, size)) { + block_header_t *remaining_block = block_split(block, size); + block_link_next(block); + block_set_prev_free(remaining_block); + block_insert(control, remaining_block); + } +} + +/* Trim any trailing block space off the end of a used block, return to pool. */ +static void block_trim_used(control_t *control, + block_header_t *block, + size_t size) +{ + tlsf_assert(!block_is_free(block) && "block must be used"); + if (block_can_split(block, size)) { + /* If the next block is free, we must coalesce. */ + block_header_t *remaining_block = block_split(block, size); + block_set_prev_used(remaining_block); + + remaining_block = block_merge_next(control, remaining_block); + block_insert(control, remaining_block); + } +} + +/* If possible, create a trailing free block after trimming given block by size + */ +static block_header_t *block_trim_free_leading(control_t *control, + block_header_t *block, + size_t size) +{ + block_header_t *remaining_block = block; + if (block_can_split(block, size)) { + /* We want the 2nd block. */ + remaining_block = block_split(block, size - block_header_overhead); + block_set_prev_free(remaining_block); + + block_link_next(block); + block_insert(control, block); + } + + return remaining_block; +} + +static block_header_t *block_locate_free(control_t *control, size_t size) +{ + int fl = 0, sl = 0; + block_header_t *block = NULL; + + if (size) { + mapping_search(size, &fl, &sl); + /* + * mapping_search can futz with the size, so for excessively large + * sizes it can sometimes wind up with indices that are off the end + * of the block array. + * So, we protect against that here, since this is the only callsite of + * mapping_search. + * Note that we don't need to check sl, since it comes from a modulo + * operation that guarantees it's always in range. + */ + if (fl < FL_INDEX_COUNT) { + block = search_suitable_block(control, &fl, &sl); + } + } + + if (block) { + tlsf_assert(block_size(block) >= size); + remove_free_block(control, block, fl, sl); + } + + // Not sure what this is trying to guard against. If there is a block, + // it was just asserted that block->size equals or exceeds 'size', + // and block can be non-NULL only if size was nonzero. + // if (unlikely(block && !block->size) + // block = NULL; + + return block; +} + +static void *block_prepare_used(control_t *control, + block_header_t *block, + size_t size) +{ + void *p = NULL; + if (block) { + tlsf_assert(size && "size must be non-zero"); + block_trim_free(control, block, size); + block_mark_as_used(block); + p = block_to_ptr(block); + } + return p; +} + +/* Clear structure and point all empty lists at the null block. */ +static void control_construct(control_t *control) +{ + int i, j; + + control->block_null.next_free = &control->block_null; + control->block_null.prev_free = &control->block_null; + + control->fl_bitmap = 0; + for (i = 0; i < FL_INDEX_COUNT; ++i) { + control->sl_bitmap[i] = 0; + for (j = 0; j < SL_INDEX_COUNT; ++j) { + control->blocks[i][j] = &control->block_null; + } + } +} + +/* + * Debugging utilities. + */ +#ifdef TLSF_CONFIG_DEBUG + +typedef struct integrity_t { + int prev_status; + int status; +} integrity_t; + +#define tlsf_insist(x) \ + do { \ + tlsf_assert(x); \ + if (!(x)) \ + status--; \ + } while (0) + +static void integrity_walker(void *ptr, size_t size, int used, void *user) +{ + block_header_t *block = block_from_ptr(ptr); + integrity_t *integ = tlsf_cast(integrity_t *, user); + const int this_prev_status = block_is_prev_free(block) ? 1 : 0; + const int this_status = block_is_free(block) ? 1 : 0; + const size_t this_block_size = block_size(block); + + int status = 0; + (void)used; + tlsf_insist(integ->prev_status == this_prev_status && + "prev status incorrect"); + tlsf_insist(size == this_block_size && "block size incorrect"); + + integ->prev_status = this_status; + integ->status += status; +} + +int tlsf_check(tlsf_t tlsf) +{ + int i, j; + + control_t *control = tlsf_cast(control_t *, tlsf); + int status = 0; + + /* Check that the free lists and bitmaps are accurate. */ + for (i = 0; i < FL_INDEX_COUNT; ++i) { + for (j = 0; j < SL_INDEX_COUNT; ++j) { + const int fl_map = control->fl_bitmap & (1 << i); + const int sl_list = control->sl_bitmap[i]; + const int sl_map = sl_list & (1 << j); + const block_header_t *block = control->blocks[i][j]; + + /* Check that first- and second-level lists agree. */ + if (!fl_map) { + tlsf_insist(!sl_map && "second-level map must be null"); + } + + if (!sl_map) { + tlsf_insist(block == &control->block_null && + "block list must be null"); + continue; + } + + /* Check that there is at least one free block. */ + tlsf_insist(sl_list && "no free blocks in second-level map"); + tlsf_insist(block != &control->block_null && + "block should not be null"); + + while (block != &control->block_null) { + int fli, sli; + tlsf_insist(block_is_free(block) && "block should be free"); + tlsf_insist(!block_is_prev_free(block) && + "blocks should have coalesced"); + tlsf_insist(!block_is_free(block_next(block)) && + "blocks should have coalesced"); + tlsf_insist(block_is_prev_free(block_next(block)) && + "block should be free"); + tlsf_insist(block_size(block) >= block_size_min && + "block not minimum size"); + + mapping_insert(block_size(block), &fli, &sli); + tlsf_insist(fli == i && sli == j && + "block size indexed in wrong list"); + block = block->next_free; + } + } + } + + return status; +} + +#undef tlsf_insist + +static void default_walker(void *ptr, size_t size, int used, void *user) +{ + (void)user; + printf("\t%p %s size: %x (%p)\n", ptr, used ? "used" : "free", + (unsigned int)size, block_from_ptr(ptr)); +} + +void tlsf_walk_pool(pool_t pool, tlsf_walker walker, void *user) +{ + tlsf_walker pool_walker = walker ? walker : default_walker; + block_header_t *block = offset_to_block(pool, 0); + + while (block && !block_is_last(block)) { + pool_walker(block_to_ptr(block), block_size(block), + !block_is_free(block), user); + block = block_next(block); + } +} + +size_t tlsf_block_size(void *ptr) +{ + size_t size = 0; + if (ptr) { + const block_header_t *block = block_from_ptr(ptr); + size = block_size(block); + } + return size; +} + +int tlsf_check_pool(pool_t pool) +{ + /* Check that the blocks are physically correct. */ + integrity_t integ = {0, 0}; + tlsf_walk_pool(pool, integrity_walker, &integ); + + return integ.status; +} + +#endif /* TLSF_CONFIG_DEBUG */ + +/* + * Size of the TLSF structures in a given memory block passed to + * tlsf_create, equal to the size of a control_t + */ +size_t tlsf_size(void) +{ + return sizeof(control_t); +} + +size_t tlsf_align_size(void) +{ + return ALIGN_SIZE; +} + +size_t tlsf_block_size_min(void) +{ + return block_size_min; +} + +size_t tlsf_block_size_max(void) +{ + return block_size_max; +} + +/* + * Overhead of the TLSF structures in a given memory block passed to + * tlsf_add_pool, equal to the overhead of a free block and the + * sentinel block. + */ +size_t tlsf_pool_overhead(void) +{ + return 2 * block_header_overhead; +} + +size_t tlsf_alloc_overhead(void) +{ + return block_header_overhead; +} + +pool_t tlsf_add_pool(tlsf_t tlsf, void *mem, size_t bytes) +{ + block_header_t *block; + block_header_t *next; + + const size_t pool_overhead = tlsf_pool_overhead(); + // subtract another word so that the end sentinel consumes 2 words + // (including its header) + const size_t pool_bytes = align_down(bytes - pool_overhead, ALIGN_SIZE) + - N_WORD_BYTES; + + if (((ptrdiff_t)mem % ALIGN_SIZE) != 0) { + printf("tlsf_add_pool: Memory must be aligned by %u bytes.\n", + (unsigned int)ALIGN_SIZE); + return 0; + } + + if (pool_bytes < block_size_min || pool_bytes > block_size_max) { + printf( + "tlsf_add_pool: Memory size must be between %zu and %zu bytes.\n", + pool_overhead + block_size_min, pool_overhead + block_size_max); + return 0; + } + + /* + * Create the main free block. Offset the start of the block slightly + * so that the prev_phys_block field falls outside of the pool - + * it will never be used. + */ + block = offset_to_block(mem, 0); + block->widetag = FILLER_WIDETAG; + block_set_size(block, pool_bytes); + block_set_free(block); + block_set_prev_used(block); + block_insert(tlsf_cast(control_t *, tlsf), block); + + /* Split the block to create a zero-size sentinel block. */ + next = block_link_next(block); + next->widetag = FILLER_WIDETAG; + block_set_size(next, N_WORD_BYTES); + block_set_used(next); + block_set_prev_free(next); + + return mem; +} + +void tlsf_remove_pool(tlsf_t tlsf, pool_t pool) +{ + control_t *control = tlsf_cast(control_t *, tlsf); + block_header_t *block = offset_to_block(pool, 0); + + int fl = 0, sl = 0; + + tlsf_assert(block_is_free(block) && "block should be free"); + tlsf_assert(!block_is_free(block_next(block)) && + "next block should not be free"); + tlsf_assert(block_size(block_next(block)) == 0 && + "next block size should be zero"); + + mapping_insert(block_size(block), &fl, &sl); + remove_free_block(control, block, fl, sl); +} + +/* + * TLSF main interface. + */ + +tlsf_t tlsf_create(void *mem) +{ + if (((ptrdiff_t)mem % ALIGN_SIZE) != 0) { + printf("tlsf_create: Memory must be aligned to %u bytes.\n", + (unsigned int)ALIGN_SIZE); + return NULL; + } + + control_construct(tlsf_cast(control_t *, mem)); + + return tlsf_cast(tlsf_t, mem); +} + +tlsf_t tlsf_create_with_pool(void *mem, size_t bytes) +{ + tlsf_t tlsf = tlsf_create(mem); + tlsf_add_pool(tlsf, (char *)mem + tlsf_size(), bytes - tlsf_size()); + return tlsf; +} + +void tlsf_destroy(tlsf_t tlsf) +{ + /* Nothing to do. */ + (void)tlsf; +} + +pool_t tlsf_get_pool(tlsf_t tlsf) +{ + return tlsf_cast(pool_t, (char *)tlsf + tlsf_size()); +} + +void *tlsf_malloc(tlsf_t tlsf, size_t size) +{ + control_t *control = tlsf_cast(control_t *, tlsf); + const size_t adjust = adjust_request_size(size, ALIGN_SIZE); + block_header_t *block = block_locate_free(control, adjust); + return block_prepare_used(control, block, adjust); +} + +void *tlsf_memalign(tlsf_t tlsf, size_t align, size_t size) +{ + control_t *control = tlsf_cast(control_t *, tlsf); + const size_t adjust = adjust_request_size(size, ALIGN_SIZE); + + /* + * We must allocate an additional minimum block size bytes so that if + * our free block will leave an alignment gap which is smaller, we can + * trim a leading free block and release it back to the pool. We must + * do this because the previous physical block is in use, therefore + * the prev_phys_block field is not valid, and we can't simply adjust + * the size of that block. + */ + const size_t gap_minimum = sizeof(block_header_t); + const size_t size_with_gap = + adjust_request_size(adjust + align + gap_minimum, align); + + /* + * If alignment is less than or equals base alignment, we're done. + * If we requested 0 bytes, return null, as tlsf_malloc(0) does. + */ + const size_t aligned_size = + (adjust && align > ALIGN_SIZE) ? size_with_gap : adjust; + + block_header_t *block = block_locate_free(control, aligned_size); + + /* This can't be a static assert. */ + tlsf_assert(sizeof(block_header_t) == + block_size_min + block_header_overhead); + + if (block) { + void *ptr = block_to_ptr(block); + void *aligned = align_ptr(ptr, align); + size_t gap = tlsf_cast( + size_t, tlsf_cast(ptrdiff_t, aligned) - tlsf_cast(ptrdiff_t, ptr)); + + /* If gap size is too small, offset to next aligned boundary. */ + if (gap && gap < gap_minimum) { + const size_t gap_remain = gap_minimum - gap; + const size_t offset = tlsf_max(gap_remain, align); + const void *next_aligned = + tlsf_cast(void *, tlsf_cast(ptrdiff_t, aligned) + offset); + + aligned = align_ptr(next_aligned, align); + gap = tlsf_cast(size_t, tlsf_cast(ptrdiff_t, aligned) - + tlsf_cast(ptrdiff_t, ptr)); + } + + if (gap) { + tlsf_assert(gap >= gap_minimum && "gap size too small"); + block = block_trim_free_leading(control, block, gap); + } + } + + return block_prepare_used(control, block, adjust); +} + +void tlsf_free(tlsf_t tlsf, void *ptr) +{ + if (unlikely(!ptr)) + return; + + control_t *control = tlsf_cast(control_t *, tlsf); + block_header_t *block = block_from_ptr(ptr); + tlsf_assert(!block_is_free(block) && "block already marked as free"); + block_mark_as_free(block); + block = block_merge_prev(control, block); + block = block_merge_next(control, block); + block_insert(control, block); +} + +/* + * The TLSF block information provides us with enough information to + * provide a reasonably intelligent implementation of realloc, growing or + * shrinking the currently allocated block as required. + * + * This routine handles the somewhat esoteric edge cases of realloc: + * - a non-zero size with a null pointer will behave like malloc + * - a zero size with a non-null pointer will behave like free + * - a request that cannot be satisfied will leave the original buffer + * untouched + * - an extended buffer size will leave the newly-allocated area with + * contents undefined + */ +void *tlsf_realloc(tlsf_t tlsf, void *ptr, size_t size) +{ + control_t *control = tlsf_cast(control_t *, tlsf); + void *p = NULL; + + /* Zero-size requests are treated as free. */ + if (ptr && size == 0) { + tlsf_free(tlsf, ptr); + } + /* Requests with NULL pointers are treated as malloc. */ + else if (!ptr) { + p = tlsf_malloc(tlsf, size); + } else { + block_header_t *block = block_from_ptr(ptr); + block_header_t *next = block_next(block); + + const size_t cursize = block_size(block); + const size_t combined = + cursize + block_size(next) + block_header_overhead; + const size_t adjust = adjust_request_size(size, ALIGN_SIZE); + + tlsf_assert(!block_is_free(block) && "block already marked as free"); + + /* + * If the next block is used, or when combined with the current + * block, does not offer enough space, we must reallocate and copy. + */ + if (adjust > cursize && (!block_is_free(next) || adjust > combined)) { + p = tlsf_malloc(tlsf, size); + if (p) { + const size_t minsize = tlsf_min(cursize, size); + memcpy(p, ptr, minsize); + tlsf_free(tlsf, ptr); + } + } else { + /* Do we need to expand to the next block? */ + if (adjust > cursize) { + block_merge_next(control, block); + block_mark_as_used(block); + } + + /* Trim the resulting block and return the original pointer. */ + block_trim_used(control, block, adjust); + p = ptr; + } + } + + return p; +} + +void tlsf_dump_freelists(tlsf_t tlsf, FILE *f) +{ + control_t *control = tlsf_cast(control_t *, tlsf); + fprintf(f, "Freelists:\n"); + int i,j; + for (i=0; i<FL_INDEX_COUNT; ++i) + for (j=0; j<SL_INDEX_COUNT; ++j) { + block_header_t *l = control->blocks[i][j]; + if (l != &control->block_null) { + fprintf(f, "[%2d,%2d]=", i, j); + do { + fprintf(f, "%p (%x) ", l, l->_nwords); + l = l->next_free; + } while (l != &control->block_null); + putc('\n', f); + } + } +} + +#ifdef LISP_FEATURE_64_BIT +void tlsf_dump_pool(tlsf_t tlsf, pool_t pool, char *pathname) +{ + FILE* f = fopen(pathname, "w"); + if (tlsf) tlsf_dump_freelists(tlsf, f); + fprintf(f, " Free &header header nbytes &prev_header\n"); + fprintf(f, " (incl hdr)\n"); + fprintf(f, " ----- ---------- --------------- ----------- -------------\n"); + block_header_t *block = offset_to_block(pool, 0); + while (block) { + unsigned long* header = (unsigned long*)block + 1, word = *header; + fprintf(f, " %s %12lx %7x:%08x %10lx", + block_is_free(block) ? "free":" ", + (long)header, + (int)(word>>32), (int)(word & 0xFFFFFFFF), + block_size(block)+N_WORD_BYTES); + if (block_is_prev_free(block)) + fprintf(f, " %12lx", (long)block->prev_phys_block+N_WORD_BYTES); + putc('\n', f); + if (block_is_last(block)) break; // include the sentinel in the display + block = block_next(block); + } + fprintf(f, "-- end --\n"); + fclose(f); +} +#endif diff --git a/tlsf-bsd/tlsf/tlsf.h b/tlsf-bsd/tlsf/tlsf.h new file mode 100644 index 0000000000..3f6d96c88b --- /dev/null +++ b/tlsf-bsd/tlsf/tlsf.h @@ -0,0 +1,83 @@ +#ifndef INCLUDED_tlsf +#define INCLUDED_tlsf + +/* + * Two Level Segregated Fit memory allocator. + * + * Copyright (c) 2006-2008, 2011, 2014 Matthew Conte. 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 the copyright holder 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 MATTHEW CONTE 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. + */ + +#include <stddef.h> + +#if defined(__cplusplus) +extern "C" { +#endif + +/* tlsf_t: a TLSF structure. Can contain 1 to N pools. */ +/* pool_t: a block of memory that TLSF can manage. */ +typedef void *tlsf_t; +typedef void *pool_t; + +/* Create/destroy a memory pool. */ +tlsf_t tlsf_create(void *mem); +tlsf_t tlsf_create_with_pool(void *mem, size_t bytes); +void tlsf_destroy(tlsf_t tlsf); +pool_t tlsf_get_pool(tlsf_t tlsf); + +/* Add/remove memory pools. */ +pool_t tlsf_add_pool(tlsf_t tlsf, void *mem, size_t bytes); +void tlsf_remove_pool(tlsf_t tlsf, pool_t pool); + +/* malloc/memalign/realloc/free replacements. */ +void *tlsf_malloc(tlsf_t tlsf, size_t size); +void *tlsf_memalign(tlsf_t tlsf, size_t align, size_t size); +void *tlsf_realloc(tlsf_t tlsf, void *ptr, size_t size); +void tlsf_free(tlsf_t tlsf, void *ptr); + +/* Returns internal block size, not original request size */ +size_t tlsf_block_size(void *ptr); + +/* Overheads/limits of internal structures. */ +size_t tlsf_size(void); +size_t tlsf_align_size(void); +size_t tlsf_block_size_min(void); +size_t tlsf_block_size_max(void); +size_t tlsf_pool_overhead(void); +size_t tlsf_alloc_overhead(void); + +/* Debugging. */ +#ifdef TLSF_CONFIG_DEBUG +typedef void (*tlsf_walker)(void *ptr, size_t size, int used, void *user); +void tlsf_walk_pool(pool_t pool, tlsf_walker walker, void *user); +/* Returns nonzero if any internal consistency check fails. */ +int tlsf_check(tlsf_t tlsf); +int tlsf_check_pool(pool_t pool); +#endif /* TLSF_CONFIG_DEBUG */ + +#if defined(__cplusplus) +}; +#endif + +#endif diff --git a/tlsf-bsd/tlsf/tlsf_utils.h b/tlsf-bsd/tlsf/tlsf_utils.h new file mode 100644 index 0000000000..144e07fece --- /dev/null +++ b/tlsf-bsd/tlsf/tlsf_utils.h @@ -0,0 +1,202 @@ +#ifndef INCLUDED_tlsf_utils +#define INCLUDED_tlsf_utils + +#include <stdint.h> + +/* +** Architecture-specific bit manipulation routines. +** +** TLSF achieves O(1) cost for malloc and free operations by limiting +** the search for a free block to a free list of guaranteed size +** adequate to fulfill the request, combined with efficient free list +** queries using bitmasks and architecture-specific bit-manipulation +** routines. +** +** Most modern processors provide instructions to count leading zeroes +** in a word, find the lowest and highest set bit, etc. These +** specific implementations will be used when available, falling back +** to a reasonably efficient generic implementation. +** +** NOTE: TLSF spec relies on ffs/fls returning value 0..31. +** ffs/fls return 1-32 by default, returning 0 for error. +*/ + +/* +** Detect whether or not we are building for a 32- or 64-bit (LP/LLP) +** architecture. There is no reliable portable method at compile-time. +*/ +#if defined(__alpha__) || defined(__ia64__) || defined(__x86_64__) || \ + defined(_WIN64) || defined(__LP64__) || defined(__LLP64__) || \ + defined(__aarch64__) +#define TLSF_64BIT +#endif + +#if defined(__GNUC__) + +/* count leading zeroes: + * clz(0) == 32, clz(0xf) == 28, clz(1 << 31) == 0 + */ +static inline int clz(uint32_t x) +{ + return x ? __builtin_clz(x) : sizeof(x) * 8; +} + +/* integer binary logarithm (rounding down): + * log2(0) == -1, log2(5) == 2 + */ +static inline int __log2(uint32_t x) +{ + return sizeof(x) * 8 - clz(x) - 1; +} + +/* find first set: + * __ffs(1) == 0, __ffs(0) == -1, __ffs(1<<31) == 31 + */ +static inline int tlsf_ffs(unsigned int word) +{ + return __log2(word & (uint32_t)(-(uint32_t)word)); +} + +static inline int tlsf_fls(unsigned int word) +{ + const int bit = word ? 32 - __builtin_clz(word) : 0; + return bit - 1; +} + +#elif defined(_MSC_VER) && (_MSC_VER >= 1400) && \ + (defined(_M_IX86) || defined(_M_X64)) +/* Microsoft Visual C++ support on x86/X64 architectures. */ + +#include <intrin.h> + +#pragma intrinsic(_BitScanReverse) +#pragma intrinsic(_BitScanForward) + +static inline int tlsf_fls(unsigned int word) +{ + unsigned long index; + return _BitScanReverse(&index, word) ? index : -1; +} + +static inline int tlsf_ffs(unsigned int word) +{ + unsigned long index; + return _BitScanForward(&index, word) ? index : -1; +} + +#elif defined(_MSC_VER) && defined(_M_PPC) +/* Microsoft Visual C++ support on PowerPC architectures. */ + +#include <ppcintrinsics.h> + +static inline int tlsf_fls(unsigned int word) +{ + const int bit = 32 - _CountLeadingZeros(word); + return bit - 1; +} + +static inline int tlsf_ffs(unsigned int word) +{ + const unsigned int reverse = word & (~word + 1); + const int bit = 32 - _CountLeadingZeros(reverse); + return bit - 1; +} + +#elif defined(__ARMCC_VERSION) +/* RealView Compilation Tools for ARM */ + +static inline int tlsf_ffs(unsigned int word) +{ + const unsigned int reverse = word & (~word + 1); + const int bit = 32 - __clz(reverse); + return bit - 1; +} + +static inline int tlsf_fls(unsigned int word) +{ + const int bit = word ? 32 - __clz(word) : 0; + return bit - 1; +} + +#elif defined(__ghs__) +/* Green Hills support for PowerPC */ + +#include <ppc_ghs.h> + +static inline int tlsf_ffs(unsigned int word) +{ + const unsigned int reverse = word & (~word + 1); + const int bit = 32 - __CLZ32(reverse); + return bit - 1; +} + +static inline int tlsf_fls(unsigned int word) +{ + const int bit = word ? 32 - __CLZ32(word) : 0; + return bit - 1; +} + +#else +/* Fall back to generic implementation. */ + +static inline int tlsf_fls_generic(unsigned int word) +{ + int bit = 32; + + if (!word) + bit -= 1; + if (!(word & 0xffff0000)) { + word <<= 16; + bit -= 16; + } + if (!(word & 0xff000000)) { + word <<= 8; + bit -= 8; + } + if (!(word & 0xf0000000)) { + word <<= 4; + bit -= 4; + } + if (!(word & 0xc0000000)) { + word <<= 2; + bit -= 2; + } + if (!(word & 0x80000000)) { + word <<= 1; + bit -= 1; + } + + return bit; +} + +/* Implement ffs in terms of fls. */ +static inline int tlsf_ffs(unsigned int word) +{ + return tlsf_fls_generic(word & (~word + 1)) - 1; +} + +static inline int tlsf_fls(unsigned int word) +{ + return tlsf_fls_generic(word) - 1; +} + +#endif + +/* Possibly 64-bit version of tlsf_fls. */ +#if defined(TLSF_64BIT) +static inline int tlsf_fls_sizet(size_t size) +{ + int high = (int)(size >> 32); + int bits = 0; + if (high) { + bits = 32 + tlsf_fls(high); + } else { + bits = tlsf_fls((int)size & 0xffffffff); + } + return bits; +} +#else +#define tlsf_fls_sizet tlsf_fls +#endif + +#endif /* INCLUDED_tlsf_utils */ diff --git a/tools-for-build/BidiMirroring.txt b/tools-for-build/BidiMirroring.txt index fbc60f1ab6..cbb61c4b57 100644 --- a/tools-for-build/BidiMirroring.txt +++ b/tools-for-build/BidiMirroring.txt @@ -1,32 +1,34 @@ -# BidiMirroring-8.0.0.txt -# Date: 2015-01-20, 18:30:00 GMT [KW, LI] +# BidiMirroring-10.0.0.txt +# Date: 2017-04-12, 17:30:00 GMT [KW, LI] +# © 2017 Unicode®, Inc. +# For terms of use, see http://www.unicode.org/terms_of_use.html +# +# Unicode Character Database +# For documentation, see http://www.unicode.org/reports/tr44/ # # Bidi_Mirroring_Glyph Property -# +# # This file is an informative contributory data file in the # Unicode Character Database. # -# Copyright (c) 1991-2015 Unicode, Inc. -# For terms of use, see http://www.unicode.org/terms_of_use.html -# # This data file lists characters that have the Bidi_Mirrored=Yes property # value, for which there is another Unicode character that typically has a glyph # that is the mirror image of the original character's glyph. # -# The repertoire covered by the file is Unicode 8.0.0. -# +# The repertoire covered by the file is Unicode 10.0.0. +# # The file contains a list of lines with mappings from one code point # to another one for character-based mirroring. # Note that for "real" mirroring, a rendering engine needs to select # appropriate alternative glyphs, and that many Unicode characters do not # have a mirror-image Unicode character. -# +# # Each mapping line contains two fields, separated by a semicolon (';'). # Each of the two fields contains a code point represented as a # variable-length hexadecimal value with 4 to 6 digits. # A comment indicates where the characters are "BEST FIT" mirroring. -# -# Code points for which Bidi_Mirrored=Yes, but for which no appropriate +# +# Code points for which Bidi_Mirrored=Yes, but for which no appropriate # characters exist with mirrored glyphs, are # listed as comments at the end of the file. # @@ -36,14 +38,14 @@ # point has the default value for the Bidi_Mirroring_Glyph property, # that means that no other character exists whose glyph is suitable # for character-based mirroring. -# +# # For information on bidi mirroring, see UAX #9: Unicode Bidirectional Algorithm, # at http://www.unicode.org/unicode/reports/tr9/ -# +# # This file was originally created by Markus Scherer. # Extended for Unicode 3.2, 4.0, 4.1, 5.0, 5.1, 5.2, and 6.0 by Ken Whistler, # and for subsequent versions by Ken Whistler and Laurentiu Iancu. -# +# # ############################################################ # # Property: Bidi_Mirroring_Glyph diff --git a/tools-for-build/Blocks.txt b/tools-for-build/Blocks.txt index 0a4a580763..a4f851b14a 100644 --- a/tools-for-build/Blocks.txt +++ b/tools-for-build/Blocks.txt @@ -1,9 +1,9 @@ -# Blocks-8.0.0.txt -# Date: 2014-11-10, 23:04:00 GMT [KW] +# Blocks-10.0.0.txt +# Date: 2017-04-12, 17:30:00 GMT [KW] +# © 2017 Unicode®, Inc. +# For terms of use, see http://www.unicode.org/terms_of_use.html # # Unicode Character Database -# Copyright (c) 1991-2014 Unicode, Inc. -# For terms of use, see http://www.unicode.org/terms_of_use.html # For documentation, see http://www.unicode.org/reports/tr44/ # # Format: @@ -14,12 +14,12 @@ # Note: When comparing block names, casing, whitespace, hyphens, # and underbars are ignored. # For example, "Latin Extended-A" and "latin extended a" are equivalent. -# For more information on the comparison of property values, +# For more information on the comparison of property values, # see UAX #44: http://www.unicode.org/reports/tr44/ # # All block ranges start with a value where (cp MOD 16) = 0, # and end with a value where (cp MOD 16) = 15. In other words, -# the last hexadecimal digit of the start of range is ...0 +# the last hexadecimal digit of the start of range is ...0 # and the last hexadecimal digit of the end of range is ...F. # This constraint on block ranges guarantees that allocations # are done in terms of whole columns, and that code chart display @@ -51,6 +51,7 @@ 07C0..07FF; NKo 0800..083F; Samaritan 0840..085F; Mandaic +0860..086F; Syriac Supplement 08A0..08FF; Arabic Extended-A 0900..097F; Devanagari 0980..09FF; Bengali @@ -93,6 +94,7 @@ 1BC0..1BFF; Batak 1C00..1C4F; Lepcha 1C50..1C7F; Ol Chiki +1C80..1C8F; Cyrillic Extended-C 1CC0..1CCF; Sundanese Supplement 1CD0..1CFF; Vedic Extensions 1D00..1D7F; Phonetic Extensions @@ -209,6 +211,7 @@ FFF0..FFFF; Specials 10400..1044F; Deseret 10450..1047F; Shavian 10480..104AF; Osmanya +104B0..104FF; Osage 10500..1052F; Elbasan 10530..1056F; Caucasian Albanian 10600..1077F; Linear A @@ -243,13 +246,20 @@ FFF0..FFFF; Specials 11280..112AF; Multani 112B0..112FF; Khudawadi 11300..1137F; Grantha +11400..1147F; Newa 11480..114DF; Tirhuta 11580..115FF; Siddham 11600..1165F; Modi +11660..1167F; Mongolian Supplement 11680..116CF; Takri 11700..1173F; Ahom 118A0..118FF; Warang Citi +11A00..11A4F; Zanabazar Square +11A50..11AAF; Soyombo 11AC0..11AFF; Pau Cin Hau +11C00..11C6F; Bhaiksuki +11C70..11CBF; Marchen +11D00..11D5F; Masaram Gondi 12000..123FF; Cuneiform 12400..1247F; Cuneiform Numbers and Punctuation 12480..1254F; Early Dynastic Cuneiform @@ -260,7 +270,12 @@ FFF0..FFFF; Specials 16AD0..16AFF; Bassa Vah 16B00..16B8F; Pahawh Hmong 16F00..16F9F; Miao +16FE0..16FFF; Ideographic Symbols and Punctuation +17000..187FF; Tangut +18800..18AFF; Tangut Components 1B000..1B0FF; Kana Supplement +1B100..1B12F; Kana Extended-A +1B170..1B2FF; Nushu 1BC00..1BC9F; Duployan 1BCA0..1BCAF; Shorthand Format Controls 1D000..1D0FF; Byzantine Musical Symbols @@ -270,7 +285,9 @@ FFF0..FFFF; Specials 1D360..1D37F; Counting Rod Numerals 1D400..1D7FF; Mathematical Alphanumeric Symbols 1D800..1DAAF; Sutton SignWriting +1E000..1E02F; Glagolitic Supplement 1E800..1E8DF; Mende Kikakui +1E900..1E95F; Adlam 1EE00..1EEFF; Arabic Mathematical Alphabetic Symbols 1F000..1F02F; Mahjong Tiles 1F030..1F09F; Domino Tiles @@ -289,6 +306,7 @@ FFF0..FFFF; Specials 2A700..2B73F; CJK Unified Ideographs Extension C 2B740..2B81F; CJK Unified Ideographs Extension D 2B820..2CEAF; CJK Unified Ideographs Extension E +2CEB0..2EBEF; CJK Unified Ideographs Extension F 2F800..2FA1F; CJK Compatibility Ideographs Supplement E0000..E007F; Tags E0100..E01EF; Variation Selectors Supplement diff --git a/tools-for-build/CaseFolding.txt b/tools-for-build/CaseFolding.txt index 0197a6c40f..efdf18e441 100644 --- a/tools-for-build/CaseFolding.txt +++ b/tools-for-build/CaseFolding.txt @@ -1,10 +1,11 @@ -# CaseFolding-8.0.0.txt -# Date: 2015-01-13, 18:16:36 GMT [MD] +# CaseFolding-10.0.0.txt +# Date: 2017-04-14, 05:40:18 GMT +# © 2017 Unicode®, Inc. +# Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries. +# For terms of use, see http://www.unicode.org/terms_of_use.html # # Unicode Character Database -# Copyright (c) 1991-2015 Unicode, Inc. -# For terms of use, see http://www.unicode.org/terms_of_use.html -# For documentation, see http://www.unicode.org/reports/tr44/ +# For documentation, see http://www.unicode.org/reports/tr44/ # # Case Folding Properties # @@ -23,7 +24,7 @@ # # NOTE: case folding does not preserve normalization formats! # -# For information on case folding, including how to have case folding +# For information on case folding, including how to have case folding # preserve normalization formats, see Section 3.13 Default Case Algorithms in # The Unicode Standard. # @@ -593,6 +594,15 @@ 13FB; C; 13F3; # CHEROKEE SMALL LETTER YU 13FC; C; 13F4; # CHEROKEE SMALL LETTER YV 13FD; C; 13F5; # CHEROKEE SMALL LETTER MV +1C80; C; 0432; # CYRILLIC SMALL LETTER ROUNDED VE +1C81; C; 0434; # CYRILLIC SMALL LETTER LONG-LEGGED DE +1C82; C; 043E; # CYRILLIC SMALL LETTER NARROW O +1C83; C; 0441; # CYRILLIC SMALL LETTER WIDE ES +1C84; C; 0442; # CYRILLIC SMALL LETTER TALL TE +1C85; C; 0442; # CYRILLIC SMALL LETTER THREE-LEGGED TE +1C86; C; 044A; # CYRILLIC SMALL LETTER TALL HARD SIGN +1C87; C; 0463; # CYRILLIC SMALL LETTER TALL YAT +1C88; C; A64B; # CYRILLIC SMALL LETTER UNBLENDED UK 1E00; C; 1E01; # LATIN CAPITAL LETTER A WITH RING BELOW 1E02; C; 1E03; # LATIN CAPITAL LETTER B WITH DOT ABOVE 1E04; C; 1E05; # LATIN CAPITAL LETTER B WITH DOT BELOW @@ -1163,6 +1173,7 @@ A7AA; C; 0266; # LATIN CAPITAL LETTER H WITH HOOK A7AB; C; 025C; # LATIN CAPITAL LETTER REVERSED OPEN E A7AC; C; 0261; # LATIN CAPITAL LETTER SCRIPT G A7AD; C; 026C; # LATIN CAPITAL LETTER L WITH BELT +A7AE; C; 026A; # LATIN CAPITAL LETTER SMALL CAPITAL I A7B0; C; 029E; # LATIN CAPITAL LETTER TURNED K A7B1; C; 0287; # LATIN CAPITAL LETTER TURNED T A7B2; C; 029D; # LATIN CAPITAL LETTER J WITH CROSSED-TAIL @@ -1327,6 +1338,42 @@ FF3A; C; FF5A; # FULLWIDTH LATIN CAPITAL LETTER Z 10425; C; 1044D; # DESERET CAPITAL LETTER ENG 10426; C; 1044E; # DESERET CAPITAL LETTER OI 10427; C; 1044F; # DESERET CAPITAL LETTER EW +104B0; C; 104D8; # OSAGE CAPITAL LETTER A +104B1; C; 104D9; # OSAGE CAPITAL LETTER AI +104B2; C; 104DA; # OSAGE CAPITAL LETTER AIN +104B3; C; 104DB; # OSAGE CAPITAL LETTER AH +104B4; C; 104DC; # OSAGE CAPITAL LETTER BRA +104B5; C; 104DD; # OSAGE CAPITAL LETTER CHA +104B6; C; 104DE; # OSAGE CAPITAL LETTER EHCHA +104B7; C; 104DF; # OSAGE CAPITAL LETTER E +104B8; C; 104E0; # OSAGE CAPITAL LETTER EIN +104B9; C; 104E1; # OSAGE CAPITAL LETTER HA +104BA; C; 104E2; # OSAGE CAPITAL LETTER HYA +104BB; C; 104E3; # OSAGE CAPITAL LETTER I +104BC; C; 104E4; # OSAGE CAPITAL LETTER KA +104BD; C; 104E5; # OSAGE CAPITAL LETTER EHKA +104BE; C; 104E6; # OSAGE CAPITAL LETTER KYA +104BF; C; 104E7; # OSAGE CAPITAL LETTER LA +104C0; C; 104E8; # OSAGE CAPITAL LETTER MA +104C1; C; 104E9; # OSAGE CAPITAL LETTER NA +104C2; C; 104EA; # OSAGE CAPITAL LETTER O +104C3; C; 104EB; # OSAGE CAPITAL LETTER OIN +104C4; C; 104EC; # OSAGE CAPITAL LETTER PA +104C5; C; 104ED; # OSAGE CAPITAL LETTER EHPA +104C6; C; 104EE; # OSAGE CAPITAL LETTER SA +104C7; C; 104EF; # OSAGE CAPITAL LETTER SHA +104C8; C; 104F0; # OSAGE CAPITAL LETTER TA +104C9; C; 104F1; # OSAGE CAPITAL LETTER EHTA +104CA; C; 104F2; # OSAGE CAPITAL LETTER TSA +104CB; C; 104F3; # OSAGE CAPITAL LETTER EHTSA +104CC; C; 104F4; # OSAGE CAPITAL LETTER TSHA +104CD; C; 104F5; # OSAGE CAPITAL LETTER DHA +104CE; C; 104F6; # OSAGE CAPITAL LETTER U +104CF; C; 104F7; # OSAGE CAPITAL LETTER WA +104D0; C; 104F8; # OSAGE CAPITAL LETTER KHA +104D1; C; 104F9; # OSAGE CAPITAL LETTER GHA +104D2; C; 104FA; # OSAGE CAPITAL LETTER ZA +104D3; C; 104FB; # OSAGE CAPITAL LETTER ZHA 10C80; C; 10CC0; # OLD HUNGARIAN CAPITAL LETTER A 10C81; C; 10CC1; # OLD HUNGARIAN CAPITAL LETTER AA 10C82; C; 10CC2; # OLD HUNGARIAN CAPITAL LETTER EB @@ -1410,5 +1457,39 @@ FF3A; C; FF5A; # FULLWIDTH LATIN CAPITAL LETTER Z 118BD; C; 118DD; # WARANG CITI CAPITAL LETTER SSUU 118BE; C; 118DE; # WARANG CITI CAPITAL LETTER SII 118BF; C; 118DF; # WARANG CITI CAPITAL LETTER VIYO +1E900; C; 1E922; # ADLAM CAPITAL LETTER ALIF +1E901; C; 1E923; # ADLAM CAPITAL LETTER DAALI +1E902; C; 1E924; # ADLAM CAPITAL LETTER LAAM +1E903; C; 1E925; # ADLAM CAPITAL LETTER MIIM +1E904; C; 1E926; # ADLAM CAPITAL LETTER BA +1E905; C; 1E927; # ADLAM CAPITAL LETTER SINNYIIYHE +1E906; C; 1E928; # ADLAM CAPITAL LETTER PE +1E907; C; 1E929; # ADLAM CAPITAL LETTER BHE +1E908; C; 1E92A; # ADLAM CAPITAL LETTER RA +1E909; C; 1E92B; # ADLAM CAPITAL LETTER E +1E90A; C; 1E92C; # ADLAM CAPITAL LETTER FA +1E90B; C; 1E92D; # ADLAM CAPITAL LETTER I +1E90C; C; 1E92E; # ADLAM CAPITAL LETTER O +1E90D; C; 1E92F; # ADLAM CAPITAL LETTER DHA +1E90E; C; 1E930; # ADLAM CAPITAL LETTER YHE +1E90F; C; 1E931; # ADLAM CAPITAL LETTER WAW +1E910; C; 1E932; # ADLAM CAPITAL LETTER NUN +1E911; C; 1E933; # ADLAM CAPITAL LETTER KAF +1E912; C; 1E934; # ADLAM CAPITAL LETTER YA +1E913; C; 1E935; # ADLAM CAPITAL LETTER U +1E914; C; 1E936; # ADLAM CAPITAL LETTER JIIM +1E915; C; 1E937; # ADLAM CAPITAL LETTER CHI +1E916; C; 1E938; # ADLAM CAPITAL LETTER HA +1E917; C; 1E939; # ADLAM CAPITAL LETTER QAAF +1E918; C; 1E93A; # ADLAM CAPITAL LETTER GA +1E919; C; 1E93B; # ADLAM CAPITAL LETTER NYA +1E91A; C; 1E93C; # ADLAM CAPITAL LETTER TU +1E91B; C; 1E93D; # ADLAM CAPITAL LETTER NHA +1E91C; C; 1E93E; # ADLAM CAPITAL LETTER VA +1E91D; C; 1E93F; # ADLAM CAPITAL LETTER KHA +1E91E; C; 1E940; # ADLAM CAPITAL LETTER GBE +1E91F; C; 1E941; # ADLAM CAPITAL LETTER ZAL +1E920; C; 1E942; # ADLAM CAPITAL LETTER KPO +1E921; C; 1E943; # ADLAM CAPITAL LETTER SHA # # EOF diff --git a/tools-for-build/CompositionExclusions.txt b/tools-for-build/CompositionExclusions.txt index a4324b8ce8..ff42508686 100644 --- a/tools-for-build/CompositionExclusions.txt +++ b/tools-for-build/CompositionExclusions.txt @@ -1,5 +1,10 @@ -# CompositionExclusions-8.0.0.txt -# Date: 2015-02-19, 00:30:00 GMT [KW, LI] +# CompositionExclusions-10.0.0.txt +# Date: 2017-02-15, 00:00:00 GMT [KW, LI] +# © 2017 Unicode®, Inc. +# For terms of use, see http://www.unicode.org/terms_of_use.html +# +# Unicode Character Database +# For documentation, see http://www.unicode.org/reports/tr44/ # # This file lists the characters for the Composition Exclusion Table # defined in UAX #15, Unicode Normalization Forms. @@ -7,9 +12,6 @@ # This file is a normative contributory data file in the # Unicode Character Database. # -# Copyright (c) 1991-2015 Unicode, Inc. -# For terms of use, see http://www.unicode.org/terms_of_use.html -# # For more information, see # http://www.unicode.org/unicode/reports/tr15/#Primary_Exclusion_List_Table # diff --git a/tools-for-build/DerivedAge.txt b/tools-for-build/DerivedAge.txt index f1b0addb1c..917afd413c 100644 --- a/tools-for-build/DerivedAge.txt +++ b/tools-for-build/DerivedAge.txt @@ -1,10 +1,11 @@ -# DerivedAge-8.0.0.txt -# Date: 2015-02-13, 13:30:18 GMT [MD] +# DerivedAge-10.0.0.txt +# Date: 2017-04-14, 05:40:18 GMT +# © 2017 Unicode®, Inc. +# Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries. +# For terms of use, see http://www.unicode.org/terms_of_use.html # # Unicode Character Database -# Copyright (c) 1991-2015 Unicode, Inc. -# For terms of use, see http://www.unicode.org/terms_of_use.html -# For documentation, see http://www.unicode.org/reports/tr44/ +# For documentation, see http://www.unicode.org/reports/tr44/ # # Unicode Character Database: Derived Property Data # This file shows when various code points were first assigned in Unicode. @@ -12,7 +13,7 @@ # Notes: # # - The term 'assigned' means that a previously reserved code point was assigned -# to be a character (graphic, format, control, or private-use); +# to be a character (graphic, format, control, or private-use); # a noncharacter code point; or a surrogate code point. # For more information, see The Unicode Standard Section 2.4 # @@ -1535,4 +1536,115 @@ FE2E..FE2F ; 8.0 # [2] COMBINING CYRILLIC TITLO LEFT HALF..COMBINING CYRILL # Total code points: 7716 +# ================================================ + +# Age=V9_0 + +# Newly assigned in Unicode 9.0.0 (June, 2016) + +08B6..08BD ; 9.0 # [8] ARABIC LETTER BEH WITH SMALL MEEM ABOVE..ARABIC LETTER AFRICAN NOON +08D4..08E1 ; 9.0 # [14] ARABIC SMALL HIGH WORD AR-RUB..ARABIC SMALL HIGH SIGN SAFHA +08E2 ; 9.0 # ARABIC DISPUTED END OF AYAH +0C80 ; 9.0 # KANNADA SIGN SPACING CANDRABINDU +0D4F ; 9.0 # MALAYALAM SIGN PARA +0D54..0D56 ; 9.0 # [3] MALAYALAM LETTER CHILLU M..MALAYALAM LETTER CHILLU LLL +0D58..0D5E ; 9.0 # [7] MALAYALAM FRACTION ONE ONE-HUNDRED-AND-SIXTIETH..MALAYALAM FRACTION ONE FIFTH +0D76..0D78 ; 9.0 # [3] MALAYALAM FRACTION ONE SIXTEENTH..MALAYALAM FRACTION THREE SIXTEENTHS +1C80..1C88 ; 9.0 # [9] CYRILLIC SMALL LETTER ROUNDED VE..CYRILLIC SMALL LETTER UNBLENDED UK +1DFB ; 9.0 # COMBINING DELETION MARK +23FB..23FE ; 9.0 # [4] POWER SYMBOL..POWER SLEEP SYMBOL +2E43..2E44 ; 9.0 # [2] DASH WITH LEFT UPTURN..DOUBLE SUSPENSION MARK +A7AE ; 9.0 # LATIN CAPITAL LETTER SMALL CAPITAL I +A8C5 ; 9.0 # SAURASHTRA SIGN CANDRABINDU +1018D..1018E ; 9.0 # [2] GREEK INDICTION SIGN..NOMISMA SIGN +104B0..104D3 ; 9.0 # [36] OSAGE CAPITAL LETTER A..OSAGE CAPITAL LETTER ZHA +104D8..104FB ; 9.0 # [36] OSAGE SMALL LETTER A..OSAGE SMALL LETTER ZHA +1123E ; 9.0 # KHOJKI SIGN SUKUN +11400..11459 ; 9.0 # [90] NEWA LETTER A..NEWA DIGIT NINE +1145B ; 9.0 # NEWA PLACEHOLDER MARK +1145D ; 9.0 # NEWA INSERTION SIGN +11660..1166C ; 9.0 # [13] MONGOLIAN BIRGA WITH ORNAMENT..MONGOLIAN TURNED SWIRL BIRGA WITH DOUBLE ORNAMENT +11C00..11C08 ; 9.0 # [9] BHAIKSUKI LETTER A..BHAIKSUKI LETTER VOCALIC L +11C0A..11C36 ; 9.0 # [45] BHAIKSUKI LETTER E..BHAIKSUKI VOWEL SIGN VOCALIC L +11C38..11C45 ; 9.0 # [14] BHAIKSUKI VOWEL SIGN E..BHAIKSUKI GAP FILLER-2 +11C50..11C6C ; 9.0 # [29] BHAIKSUKI DIGIT ZERO..BHAIKSUKI HUNDREDS UNIT MARK +11C70..11C8F ; 9.0 # [32] MARCHEN HEAD MARK..MARCHEN LETTER A +11C92..11CA7 ; 9.0 # [22] MARCHEN SUBJOINED LETTER KA..MARCHEN SUBJOINED LETTER ZA +11CA9..11CB6 ; 9.0 # [14] MARCHEN SUBJOINED LETTER YA..MARCHEN SIGN CANDRABINDU +16FE0 ; 9.0 # TANGUT ITERATION MARK +17000..187EC ; 9.0 # [6125] TANGUT IDEOGRAPH-17000..TANGUT IDEOGRAPH-187EC +18800..18AF2 ; 9.0 # [755] TANGUT COMPONENT-001..TANGUT COMPONENT-755 +1E000..1E006 ; 9.0 # [7] COMBINING GLAGOLITIC LETTER AZU..COMBINING GLAGOLITIC LETTER ZHIVETE +1E008..1E018 ; 9.0 # [17] COMBINING GLAGOLITIC LETTER ZEMLJA..COMBINING GLAGOLITIC LETTER HERU +1E01B..1E021 ; 9.0 # [7] COMBINING GLAGOLITIC LETTER SHTA..COMBINING GLAGOLITIC LETTER YATI +1E023..1E024 ; 9.0 # [2] COMBINING GLAGOLITIC LETTER YU..COMBINING GLAGOLITIC LETTER SMALL YUS +1E026..1E02A ; 9.0 # [5] COMBINING GLAGOLITIC LETTER YO..COMBINING GLAGOLITIC LETTER FITA +1E900..1E94A ; 9.0 # [75] ADLAM CAPITAL LETTER ALIF..ADLAM NUKTA +1E950..1E959 ; 9.0 # [10] ADLAM DIGIT ZERO..ADLAM DIGIT NINE +1E95E..1E95F ; 9.0 # [2] ADLAM INITIAL EXCLAMATION MARK..ADLAM INITIAL QUESTION MARK +1F19B..1F1AC ; 9.0 # [18] SQUARED THREE D..SQUARED VOD +1F23B ; 9.0 # SQUARED CJK UNIFIED IDEOGRAPH-914D +1F57A ; 9.0 # MAN DANCING +1F5A4 ; 9.0 # BLACK HEART +1F6D1..1F6D2 ; 9.0 # [2] OCTAGONAL SIGN..SHOPPING TROLLEY +1F6F4..1F6F6 ; 9.0 # [3] SCOOTER..CANOE +1F919..1F91E ; 9.0 # [6] CALL ME HAND..HAND WITH INDEX AND MIDDLE FINGERS CROSSED +1F920..1F927 ; 9.0 # [8] FACE WITH COWBOY HAT..SNEEZING FACE +1F930 ; 9.0 # PREGNANT WOMAN +1F933..1F93E ; 9.0 # [12] SELFIE..HANDBALL +1F940..1F94B ; 9.0 # [12] WILTED FLOWER..MARTIAL ARTS UNIFORM +1F950..1F95E ; 9.0 # [15] CROISSANT..PANCAKES +1F985..1F991 ; 9.0 # [13] EAGLE..SQUID + +# Total code points: 7500 + +# ================================================ + +# Age=V10_0 + +# Newly assigned in Unicode 10.0.0 (June, 2017) + +0860..086A ; 10.0 # [11] SYRIAC LETTER MALAYALAM NGA..SYRIAC LETTER MALAYALAM SSA +09FC..09FD ; 10.0 # [2] BENGALI LETTER VEDIC ANUSVARA..BENGALI ABBREVIATION SIGN +0AFA..0AFF ; 10.0 # [6] GUJARATI SIGN SUKUN..GUJARATI SIGN TWO-CIRCLE NUKTA ABOVE +0D00 ; 10.0 # MALAYALAM SIGN COMBINING ANUSVARA ABOVE +0D3B..0D3C ; 10.0 # [2] MALAYALAM SIGN VERTICAL BAR VIRAMA..MALAYALAM SIGN CIRCULAR VIRAMA +1CF7 ; 10.0 # VEDIC SIGN ATIKRAMA +1DF6..1DF9 ; 10.0 # [4] COMBINING KAVYKA ABOVE RIGHT..COMBINING WIDE INVERTED BRIDGE BELOW +20BF ; 10.0 # BITCOIN SIGN +23FF ; 10.0 # OBSERVER EYE SYMBOL +2BD2 ; 10.0 # GROUP MARK +2E45..2E49 ; 10.0 # [5] INVERTED LOW KAVYKA..DOUBLE STACKED COMMA +312E ; 10.0 # BOPOMOFO LETTER O WITH DOT ABOVE +9FD6..9FEA ; 10.0 # [21] CJK UNIFIED IDEOGRAPH-9FD6..CJK UNIFIED IDEOGRAPH-9FEA +1032D..1032F ; 10.0 # [3] OLD ITALIC LETTER YE..OLD ITALIC LETTER SOUTHERN TSE +11A00..11A47 ; 10.0 # [72] ZANABAZAR SQUARE LETTER A..ZANABAZAR SQUARE SUBJOINER +11A50..11A83 ; 10.0 # [52] SOYOMBO LETTER A..SOYOMBO LETTER KSSA +11A86..11A9C ; 10.0 # [23] SOYOMBO CLUSTER-INITIAL LETTER RA..SOYOMBO MARK DOUBLE SHAD +11A9E..11AA2 ; 10.0 # [5] SOYOMBO HEAD MARK WITH MOON AND SUN AND TRIPLE FLAME..SOYOMBO TERMINAL MARK-2 +11D00..11D06 ; 10.0 # [7] MASARAM GONDI LETTER A..MASARAM GONDI LETTER E +11D08..11D09 ; 10.0 # [2] MASARAM GONDI LETTER AI..MASARAM GONDI LETTER O +11D0B..11D36 ; 10.0 # [44] MASARAM GONDI LETTER AU..MASARAM GONDI VOWEL SIGN VOCALIC R +11D3A ; 10.0 # MASARAM GONDI VOWEL SIGN E +11D3C..11D3D ; 10.0 # [2] MASARAM GONDI VOWEL SIGN AI..MASARAM GONDI VOWEL SIGN O +11D3F..11D47 ; 10.0 # [9] MASARAM GONDI VOWEL SIGN AU..MASARAM GONDI RA-KARA +11D50..11D59 ; 10.0 # [10] MASARAM GONDI DIGIT ZERO..MASARAM GONDI DIGIT NINE +16FE1 ; 10.0 # NUSHU ITERATION MARK +1B002..1B11E ; 10.0 # [285] HENTAIGANA LETTER A-1..HENTAIGANA LETTER N-MU-MO-2 +1B170..1B2FB ; 10.0 # [396] NUSHU CHARACTER-1B170..NUSHU CHARACTER-1B2FB +1F260..1F265 ; 10.0 # [6] ROUNDED SYMBOL FOR FU..ROUNDED SYMBOL FOR CAI +1F6D3..1F6D4 ; 10.0 # [2] STUPA..PAGODA +1F6F7..1F6F8 ; 10.0 # [2] SLED..FLYING SAUCER +1F900..1F90B ; 10.0 # [12] CIRCLED CROSS FORMEE WITH FOUR DOTS..DOWNWARD FACING NOTCHED HOOK WITH DOT +1F91F ; 10.0 # I LOVE YOU HAND SIGN +1F928..1F92F ; 10.0 # [8] FACE WITH ONE EYEBROW RAISED..SHOCKED FACE WITH EXPLODING HEAD +1F931..1F932 ; 10.0 # [2] BREAST-FEEDING..PALMS UP TOGETHER +1F94C ; 10.0 # CURLING STONE +1F95F..1F96B ; 10.0 # [13] DUMPLING..CANNED FOOD +1F992..1F997 ; 10.0 # [6] GIRAFFE FACE..CRICKET +1F9D0..1F9E6 ; 10.0 # [23] FACE WITH MONOCLE..SOCKS +2CEB0..2EBE0 ; 10.0 # [7473] CJK UNIFIED IDEOGRAPH-2CEB0..CJK UNIFIED IDEOGRAPH-2EBE0 + +# Total code points: 8518 + # EOF diff --git a/tools-for-build/DerivedNormalizationProps.txt b/tools-for-build/DerivedNormalizationProps.txt index 6492493da3..941c310b96 100644 --- a/tools-for-build/DerivedNormalizationProps.txt +++ b/tools-for-build/DerivedNormalizationProps.txt @@ -1,10 +1,11 @@ -# DerivedNormalizationProps-8.0.0.txt -# Date: 2015-02-13, 13:30:23 GMT [MD] +# DerivedNormalizationProps-10.0.0.txt +# Date: 2017-02-14, 04:26:07 GMT +# © 2017 Unicode®, Inc. +# Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries. +# For terms of use, see http://www.unicode.org/terms_of_use.html # # Unicode Character Database -# Copyright (c) 1991-2015 Unicode, Inc. -# For terms of use, see http://www.unicode.org/terms_of_use.html -# For documentation, see http://www.unicode.org/reports/tr44/ +# For documentation, see http://www.unicode.org/reports/tr44/ # ================================================ @@ -1679,12 +1680,12 @@ FFED..FFEE ; NFKD_QC; N # So [2] HALFWIDTH BLACK SQUARE..HALFWIDTH WHITE CI 1F16A..1F16B ; NFKD_QC; N # So [2] RAISED MC SIGN..RAISED MD SIGN 1F190 ; NFKD_QC; N # So SQUARE DJ 1F200..1F202 ; NFKD_QC; N # So [3] SQUARE HIRAGANA HOKA..SQUARED KATAKANA SA -1F210..1F23A ; NFKD_QC; N # So [43] SQUARED CJK UNIFIED IDEOGRAPH-624B..SQUARED CJK UNIFIED IDEOGRAPH-55B6 +1F210..1F23B ; NFKD_QC; N # So [44] SQUARED CJK UNIFIED IDEOGRAPH-624B..SQUARED CJK UNIFIED IDEOGRAPH-914D 1F240..1F248 ; NFKD_QC; N # So [9] TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-672C..TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-6557 1F250..1F251 ; NFKD_QC; N # So [2] CIRCLED IDEOGRAPH ADVANTAGE..CIRCLED IDEOGRAPH ACCEPT 2F800..2FA1D ; NFKD_QC; N # Lo [542] CJK COMPATIBILITY IDEOGRAPH-2F800..CJK COMPATIBILITY IDEOGRAPH-2FA1D -# Total code points: 16893 +# Total code points: 16894 # ================================================ @@ -2082,12 +2083,12 @@ FFED..FFEE ; NFKC_QC; N # So [2] HALFWIDTH BLACK SQUARE..HALFWIDTH WHITE CI 1F16A..1F16B ; NFKC_QC; N # So [2] RAISED MC SIGN..RAISED MD SIGN 1F190 ; NFKC_QC; N # So SQUARE DJ 1F200..1F202 ; NFKC_QC; N # So [3] SQUARE HIRAGANA HOKA..SQUARED KATAKANA SA -1F210..1F23A ; NFKC_QC; N # So [43] SQUARED CJK UNIFIED IDEOGRAPH-624B..SQUARED CJK UNIFIED IDEOGRAPH-55B6 +1F210..1F23B ; NFKC_QC; N # So [44] SQUARED CJK UNIFIED IDEOGRAPH-624B..SQUARED CJK UNIFIED IDEOGRAPH-914D 1F240..1F248 ; NFKC_QC; N # So [9] TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-672C..TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-6557 1F250..1F251 ; NFKC_QC; N # So [2] CIRCLED IDEOGRAPH ADVANTAGE..CIRCLED IDEOGRAPH ACCEPT 2F800..2FA1D ; NFKC_QC; N # Lo [542] CJK COMPATIBILITY IDEOGRAPH-2F800..CJK COMPATIBILITY IDEOGRAPH-2FA1D -# Total code points: 4793 +# Total code points: 4794 # ================================================ @@ -3513,6 +3514,14 @@ FFE3 ; Expands_On_NFKC # Sk FULLWIDTH MACRON 17B4..17B5 ; NFKC_CF; # Mn [2] KHMER VOWEL INHERENT AQ..KHMER VOWEL INHERENT AA 180B..180D ; NFKC_CF; # Mn [3] MONGOLIAN FREE VARIATION SELECTOR ONE..MONGOLIAN FREE VARIATION SELECTOR THREE 180E ; NFKC_CF; # Cf MONGOLIAN VOWEL SEPARATOR +1C80 ; NFKC_CF; 0432 # L& CYRILLIC SMALL LETTER ROUNDED VE +1C81 ; NFKC_CF; 0434 # L& CYRILLIC SMALL LETTER LONG-LEGGED DE +1C82 ; NFKC_CF; 043E # L& CYRILLIC SMALL LETTER NARROW O +1C83 ; NFKC_CF; 0441 # L& CYRILLIC SMALL LETTER WIDE ES +1C84..1C85 ; NFKC_CF; 0442 # L& [2] CYRILLIC SMALL LETTER TALL TE..CYRILLIC SMALL LETTER THREE-LEGGED TE +1C86 ; NFKC_CF; 044A # L& CYRILLIC SMALL LETTER TALL HARD SIGN +1C87 ; NFKC_CF; 0463 # L& CYRILLIC SMALL LETTER TALL YAT +1C88 ; NFKC_CF; A64B # L& CYRILLIC SMALL LETTER UNBLENDED UK 1D2C ; NFKC_CF; 0061 # Lm MODIFIER LETTER CAPITAL A 1D2D ; NFKC_CF; 00E6 # Lm MODIFIER LETTER CAPITAL AE 1D2E ; NFKC_CF; 0062 # Lm MODIFIER LETTER CAPITAL B @@ -5263,6 +5272,7 @@ A7AA ; NFKC_CF; 0266 # L& LATIN CAPITAL LETTER H WITH H A7AB ; NFKC_CF; 025C # L& LATIN CAPITAL LETTER REVERSED OPEN E A7AC ; NFKC_CF; 0261 # L& LATIN CAPITAL LETTER SCRIPT G A7AD ; NFKC_CF; 026C # L& LATIN CAPITAL LETTER L WITH BELT +A7AE ; NFKC_CF; 026A # L& LATIN CAPITAL LETTER SMALL CAPITAL I A7B0 ; NFKC_CF; 029E # L& LATIN CAPITAL LETTER TURNED K A7B1 ; NFKC_CF; 0287 # L& LATIN CAPITAL LETTER TURNED T A7B2 ; NFKC_CF; 029D # L& LATIN CAPITAL LETTER J WITH CROSSED-TAIL @@ -6731,6 +6741,42 @@ FFF0..FFF8 ; NFKC_CF; # Cn [9] <reserved-FFF0>..<reserved-FF 10425 ; NFKC_CF; 1044D # L& DESERET CAPITAL LETTER ENG 10426 ; NFKC_CF; 1044E # L& DESERET CAPITAL LETTER OI 10427 ; NFKC_CF; 1044F # L& DESERET CAPITAL LETTER EW +104B0 ; NFKC_CF; 104D8 # L& OSAGE CAPITAL LETTER A +104B1 ; NFKC_CF; 104D9 # L& OSAGE CAPITAL LETTER AI +104B2 ; NFKC_CF; 104DA # L& OSAGE CAPITAL LETTER AIN +104B3 ; NFKC_CF; 104DB # L& OSAGE CAPITAL LETTER AH +104B4 ; NFKC_CF; 104DC # L& OSAGE CAPITAL LETTER BRA +104B5 ; NFKC_CF; 104DD # L& OSAGE CAPITAL LETTER CHA +104B6 ; NFKC_CF; 104DE # L& OSAGE CAPITAL LETTER EHCHA +104B7 ; NFKC_CF; 104DF # L& OSAGE CAPITAL LETTER E +104B8 ; NFKC_CF; 104E0 # L& OSAGE CAPITAL LETTER EIN +104B9 ; NFKC_CF; 104E1 # L& OSAGE CAPITAL LETTER HA +104BA ; NFKC_CF; 104E2 # L& OSAGE CAPITAL LETTER HYA +104BB ; NFKC_CF; 104E3 # L& OSAGE CAPITAL LETTER I +104BC ; NFKC_CF; 104E4 # L& OSAGE CAPITAL LETTER KA +104BD ; NFKC_CF; 104E5 # L& OSAGE CAPITAL LETTER EHKA +104BE ; NFKC_CF; 104E6 # L& OSAGE CAPITAL LETTER KYA +104BF ; NFKC_CF; 104E7 # L& OSAGE CAPITAL LETTER LA +104C0 ; NFKC_CF; 104E8 # L& OSAGE CAPITAL LETTER MA +104C1 ; NFKC_CF; 104E9 # L& OSAGE CAPITAL LETTER NA +104C2 ; NFKC_CF; 104EA # L& OSAGE CAPITAL LETTER O +104C3 ; NFKC_CF; 104EB # L& OSAGE CAPITAL LETTER OIN +104C4 ; NFKC_CF; 104EC # L& OSAGE CAPITAL LETTER PA +104C5 ; NFKC_CF; 104ED # L& OSAGE CAPITAL LETTER EHPA +104C6 ; NFKC_CF; 104EE # L& OSAGE CAPITAL LETTER SA +104C7 ; NFKC_CF; 104EF # L& OSAGE CAPITAL LETTER SHA +104C8 ; NFKC_CF; 104F0 # L& OSAGE CAPITAL LETTER TA +104C9 ; NFKC_CF; 104F1 # L& OSAGE CAPITAL LETTER EHTA +104CA ; NFKC_CF; 104F2 # L& OSAGE CAPITAL LETTER TSA +104CB ; NFKC_CF; 104F3 # L& OSAGE CAPITAL LETTER EHTSA +104CC ; NFKC_CF; 104F4 # L& OSAGE CAPITAL LETTER TSHA +104CD ; NFKC_CF; 104F5 # L& OSAGE CAPITAL LETTER DHA +104CE ; NFKC_CF; 104F6 # L& OSAGE CAPITAL LETTER U +104CF ; NFKC_CF; 104F7 # L& OSAGE CAPITAL LETTER WA +104D0 ; NFKC_CF; 104F8 # L& OSAGE CAPITAL LETTER KHA +104D1 ; NFKC_CF; 104F9 # L& OSAGE CAPITAL LETTER GHA +104D2 ; NFKC_CF; 104FA # L& OSAGE CAPITAL LETTER ZA +104D3 ; NFKC_CF; 104FB # L& OSAGE CAPITAL LETTER ZHA 10C80 ; NFKC_CF; 10CC0 # L& OLD HUNGARIAN CAPITAL LETTER A 10C81 ; NFKC_CF; 10CC1 # L& OLD HUNGARIAN CAPITAL LETTER AA 10C82 ; NFKC_CF; 10CC2 # L& OLD HUNGARIAN CAPITAL LETTER EB @@ -7819,6 +7865,40 @@ FFF0..FFF8 ; NFKC_CF; # Cn [9] <reserved-FFF0>..<reserved-FF 1D7FD ; NFKC_CF; 0037 # Nd MATHEMATICAL MONOSPACE DIGIT SEVEN 1D7FE ; NFKC_CF; 0038 # Nd MATHEMATICAL MONOSPACE DIGIT EIGHT 1D7FF ; NFKC_CF; 0039 # Nd MATHEMATICAL MONOSPACE DIGIT NINE +1E900 ; NFKC_CF; 1E922 # L& ADLAM CAPITAL LETTER ALIF +1E901 ; NFKC_CF; 1E923 # L& ADLAM CAPITAL LETTER DAALI +1E902 ; NFKC_CF; 1E924 # L& ADLAM CAPITAL LETTER LAAM +1E903 ; NFKC_CF; 1E925 # L& ADLAM CAPITAL LETTER MIIM +1E904 ; NFKC_CF; 1E926 # L& ADLAM CAPITAL LETTER BA +1E905 ; NFKC_CF; 1E927 # L& ADLAM CAPITAL LETTER SINNYIIYHE +1E906 ; NFKC_CF; 1E928 # L& ADLAM CAPITAL LETTER PE +1E907 ; NFKC_CF; 1E929 # L& ADLAM CAPITAL LETTER BHE +1E908 ; NFKC_CF; 1E92A # L& ADLAM CAPITAL LETTER RA +1E909 ; NFKC_CF; 1E92B # L& ADLAM CAPITAL LETTER E +1E90A ; NFKC_CF; 1E92C # L& ADLAM CAPITAL LETTER FA +1E90B ; NFKC_CF; 1E92D # L& ADLAM CAPITAL LETTER I +1E90C ; NFKC_CF; 1E92E # L& ADLAM CAPITAL LETTER O +1E90D ; NFKC_CF; 1E92F # L& ADLAM CAPITAL LETTER DHA +1E90E ; NFKC_CF; 1E930 # L& ADLAM CAPITAL LETTER YHE +1E90F ; NFKC_CF; 1E931 # L& ADLAM CAPITAL LETTER WAW +1E910 ; NFKC_CF; 1E932 # L& ADLAM CAPITAL LETTER NUN +1E911 ; NFKC_CF; 1E933 # L& ADLAM CAPITAL LETTER KAF +1E912 ; NFKC_CF; 1E934 # L& ADLAM CAPITAL LETTER YA +1E913 ; NFKC_CF; 1E935 # L& ADLAM CAPITAL LETTER U +1E914 ; NFKC_CF; 1E936 # L& ADLAM CAPITAL LETTER JIIM +1E915 ; NFKC_CF; 1E937 # L& ADLAM CAPITAL LETTER CHI +1E916 ; NFKC_CF; 1E938 # L& ADLAM CAPITAL LETTER HA +1E917 ; NFKC_CF; 1E939 # L& ADLAM CAPITAL LETTER QAAF +1E918 ; NFKC_CF; 1E93A # L& ADLAM CAPITAL LETTER GA +1E919 ; NFKC_CF; 1E93B # L& ADLAM CAPITAL LETTER NYA +1E91A ; NFKC_CF; 1E93C # L& ADLAM CAPITAL LETTER TU +1E91B ; NFKC_CF; 1E93D # L& ADLAM CAPITAL LETTER NHA +1E91C ; NFKC_CF; 1E93E # L& ADLAM CAPITAL LETTER VA +1E91D ; NFKC_CF; 1E93F # L& ADLAM CAPITAL LETTER KHA +1E91E ; NFKC_CF; 1E940 # L& ADLAM CAPITAL LETTER GBE +1E91F ; NFKC_CF; 1E941 # L& ADLAM CAPITAL LETTER ZAL +1E920 ; NFKC_CF; 1E942 # L& ADLAM CAPITAL LETTER KPO +1E921 ; NFKC_CF; 1E943 # L& ADLAM CAPITAL LETTER SHA 1EE00 ; NFKC_CF; 0627 # Lo ARABIC MATHEMATICAL ALEF 1EE01 ; NFKC_CF; 0628 # Lo ARABIC MATHEMATICAL BEH 1EE02 ; NFKC_CF; 062C # Lo ARABIC MATHEMATICAL JEEM @@ -8083,6 +8163,7 @@ FFF0..FFF8 ; NFKC_CF; # Cn [9] <reserved-FFF0>..<reserved-FF 1F238 ; NFKC_CF; 7533 # So SQUARED CJK UNIFIED IDEOGRAPH-7533 1F239 ; NFKC_CF; 5272 # So SQUARED CJK UNIFIED IDEOGRAPH-5272 1F23A ; NFKC_CF; 55B6 # So SQUARED CJK UNIFIED IDEOGRAPH-55B6 +1F23B ; NFKC_CF; 914D # So SQUARED CJK UNIFIED IDEOGRAPH-914D 1F240 ; NFKC_CF; 3014 672C 3015 # So TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-672C 1F241 ; NFKC_CF; 3014 4E09 3015 # So TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-4E09 1F242 ; NFKC_CF; 3014 4E8C 3015 # So TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-4E8C @@ -8634,7 +8715,7 @@ E0080..E00FF ; NFKC_CF; # Cn [128] <reserved-E0080>..<reserved-E E0100..E01EF ; NFKC_CF; # Mn [240] VARIATION SELECTOR-17..VARIATION SELECTOR-256 E01F0..E0FFF ; NFKC_CF; # Cn [3600] <reserved-E01F0>..<reserved-E0FFF> -# Total code points: 10146 +# Total code points: 10227 # ================================================ @@ -8972,6 +9053,7 @@ E01F0..E0FFF ; NFKC_CF; # Cn [3600] <reserved-E01F0>..<reserved- 17B4..17B5 ; Changes_When_NFKC_Casefolded # Mn [2] KHMER VOWEL INHERENT AQ..KHMER VOWEL INHERENT AA 180B..180D ; Changes_When_NFKC_Casefolded # Mn [3] MONGOLIAN FREE VARIATION SELECTOR ONE..MONGOLIAN FREE VARIATION SELECTOR THREE 180E ; Changes_When_NFKC_Casefolded # Cf MONGOLIAN VOWEL SEPARATOR +1C80..1C88 ; Changes_When_NFKC_Casefolded # L& [9] CYRILLIC SMALL LETTER ROUNDED VE..CYRILLIC SMALL LETTER UNBLENDED UK 1D2C..1D2E ; Changes_When_NFKC_Casefolded # Lm [3] MODIFIER LETTER CAPITAL A..MODIFIER LETTER CAPITAL B 1D30..1D3A ; Changes_When_NFKC_Casefolded # Lm [11] MODIFIER LETTER CAPITAL D..MODIFIER LETTER CAPITAL N 1D3C..1D4D ; Changes_When_NFKC_Casefolded # Lm [18] MODIFIER LETTER CAPITAL O..MODIFIER LETTER SMALL G @@ -9389,7 +9471,7 @@ A7A2 ; Changes_When_NFKC_Casefolded # L& LATIN CAPITAL LETTER K W A7A4 ; Changes_When_NFKC_Casefolded # L& LATIN CAPITAL LETTER N WITH OBLIQUE STROKE A7A6 ; Changes_When_NFKC_Casefolded # L& LATIN CAPITAL LETTER R WITH OBLIQUE STROKE A7A8 ; Changes_When_NFKC_Casefolded # L& LATIN CAPITAL LETTER S WITH OBLIQUE STROKE -A7AA..A7AD ; Changes_When_NFKC_Casefolded # L& [4] LATIN CAPITAL LETTER H WITH HOOK..LATIN CAPITAL LETTER L WITH BELT +A7AA..A7AE ; Changes_When_NFKC_Casefolded # L& [5] LATIN CAPITAL LETTER H WITH HOOK..LATIN CAPITAL LETTER SMALL CAPITAL I A7B0..A7B4 ; Changes_When_NFKC_Casefolded # L& [5] LATIN CAPITAL LETTER TURNED K..LATIN CAPITAL LETTER BETA A7B6 ; Changes_When_NFKC_Casefolded # L& LATIN CAPITAL LETTER OMEGA A7F8..A7F9 ; Changes_When_NFKC_Casefolded # Lm [2] MODIFIER LETTER CAPITAL H WITH STROKE..MODIFIER LETTER SMALL LIGATURE OE @@ -9519,6 +9601,7 @@ FFE9..FFEC ; Changes_When_NFKC_Casefolded # Sm [4] HALFWIDTH LEFTWARDS ARRO FFED..FFEE ; Changes_When_NFKC_Casefolded # So [2] HALFWIDTH BLACK SQUARE..HALFWIDTH WHITE CIRCLE FFF0..FFF8 ; Changes_When_NFKC_Casefolded # Cn [9] <reserved-FFF0>..<reserved-FFF8> 10400..10427 ; Changes_When_NFKC_Casefolded # L& [40] DESERET CAPITAL LETTER LONG I..DESERET CAPITAL LETTER EW +104B0..104D3 ; Changes_When_NFKC_Casefolded # L& [36] OSAGE CAPITAL LETTER A..OSAGE CAPITAL LETTER ZHA 10C80..10CB2 ; Changes_When_NFKC_Casefolded # L& [51] OLD HUNGARIAN CAPITAL LETTER A..OLD HUNGARIAN CAPITAL LETTER US 118A0..118BF ; Changes_When_NFKC_Casefolded # L& [32] WARANG CITI CAPITAL LETTER NGAA..WARANG CITI CAPITAL LETTER VIYO 1BCA0..1BCA3 ; Changes_When_NFKC_Casefolded # Cf [4] SHORTHAND FORMAT LETTER OVERLAP..SHORTHAND FORMAT UP STEP @@ -9566,6 +9649,7 @@ FFF0..FFF8 ; Changes_When_NFKC_Casefolded # Cn [9] <reserved-FFF0>..<reserv 1D7C3 ; Changes_When_NFKC_Casefolded # Sm MATHEMATICAL SANS-SERIF BOLD ITALIC PARTIAL DIFFERENTIAL 1D7C4..1D7CB ; Changes_When_NFKC_Casefolded # L& [8] MATHEMATICAL SANS-SERIF BOLD ITALIC EPSILON SYMBOL..MATHEMATICAL BOLD SMALL DIGAMMA 1D7CE..1D7FF ; Changes_When_NFKC_Casefolded # Nd [50] MATHEMATICAL BOLD DIGIT ZERO..MATHEMATICAL MONOSPACE DIGIT NINE +1E900..1E921 ; Changes_When_NFKC_Casefolded # L& [34] ADLAM CAPITAL LETTER ALIF..ADLAM CAPITAL LETTER SHA 1EE00..1EE03 ; Changes_When_NFKC_Casefolded # Lo [4] ARABIC MATHEMATICAL ALEF..ARABIC MATHEMATICAL DAL 1EE05..1EE1F ; Changes_When_NFKC_Casefolded # Lo [27] ARABIC MATHEMATICAL WAW..ARABIC MATHEMATICAL DOTLESS QAF 1EE21..1EE22 ; Changes_When_NFKC_Casefolded # Lo [2] ARABIC MATHEMATICAL INITIAL BEH..ARABIC MATHEMATICAL INITIAL JEEM @@ -9605,7 +9689,7 @@ FFF0..FFF8 ; Changes_When_NFKC_Casefolded # Cn [9] <reserved-FFF0>..<reserv 1F16A..1F16B ; Changes_When_NFKC_Casefolded # So [2] RAISED MC SIGN..RAISED MD SIGN 1F190 ; Changes_When_NFKC_Casefolded # So SQUARE DJ 1F200..1F202 ; Changes_When_NFKC_Casefolded # So [3] SQUARE HIRAGANA HOKA..SQUARED KATAKANA SA -1F210..1F23A ; Changes_When_NFKC_Casefolded # So [43] SQUARED CJK UNIFIED IDEOGRAPH-624B..SQUARED CJK UNIFIED IDEOGRAPH-55B6 +1F210..1F23B ; Changes_When_NFKC_Casefolded # So [44] SQUARED CJK UNIFIED IDEOGRAPH-624B..SQUARED CJK UNIFIED IDEOGRAPH-914D 1F240..1F248 ; Changes_When_NFKC_Casefolded # So [9] TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-672C..TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-6557 1F250..1F251 ; Changes_When_NFKC_Casefolded # So [2] CIRCLED IDEOGRAPH ADVANTAGE..CIRCLED IDEOGRAPH ACCEPT 2F800..2FA1D ; Changes_When_NFKC_Casefolded # Lo [542] CJK COMPATIBILITY IDEOGRAPH-2F800..CJK COMPATIBILITY IDEOGRAPH-2FA1D @@ -9617,6 +9701,6 @@ E0080..E00FF ; Changes_When_NFKC_Casefolded # Cn [128] <reserved-E0080>..<reser E0100..E01EF ; Changes_When_NFKC_Casefolded # Mn [240] VARIATION SELECTOR-17..VARIATION SELECTOR-256 E01F0..E0FFF ; Changes_When_NFKC_Casefolded # Cn [3600] <reserved-E01F0>..<reserved-E0FFF> -# Total code points: 10146 +# Total code points: 10227 # EOF diff --git a/tools-for-build/Dockerfile.static-executable-example b/tools-for-build/Dockerfile.static-executable-example new file mode 100644 index 0000000000..c33ad829b0 --- /dev/null +++ b/tools-for-build/Dockerfile.static-executable-example @@ -0,0 +1,63 @@ +# Example Dockerfile to build a static executable with SBCL. The example +# executable simply runs the sb-gmp contrib tests. The exeutable has libc, +# libgmp, and libz staticially linked in. It is simple, however it demonstrates +# that a static executable can run on ~any Linux system. + +FROM clfoundation/sbcl:alpine3.14 + +COPY . /usr/local/src/sbcl/ + +WORKDIR /usr/local/src/sbcl + +# Install build prereq and build SBCL with sb-linkable-runtime and +# sb-prelink-linkage-table +RUN set -x \ + # I frequently build arm executables on an arm64 computer. Need to add this + # otherwise SBCL can get confused + && case "$(cat /etc/apk/arch)" in \ + armv7) SBCL_ARCH=arm;; \ + aarch64) SBCL_ARCH=arm64;; \ + x86_64) SBCL_ARCH=x86-64;; \ + *) echo "Unknown arch" >&2; exit 1;; \ + esac \ + && export SBCL_ARCH \ + && apk add --no-cache ca-certificates curl openssl make gcc musl-dev linux-headers gnupg patch zlib-dev zlib-static git \ + # Remove the hardcoding of armv5 as target arch. Use the default provided + # by the base image. Required when building for ARM on Alpine 3.12. + && sed -i -e "s/CFLAGS += -marm -march=armv5/CFLAGS += -marm/" src/runtime/Config.arm-linux \ + && sh make.sh --fancy --with-sb-linkable-runtime --with-sb-prelink-linkage-table \ + && sh install.sh + +# Load sb-gmp into an image, save the foreign symbols it requires, and dump the +# core. +RUN set -x \ + && apk add --no-cache gmp-dev \ + && sbcl --non-interactive \ + --eval '(require :uiop)' \ + --eval '(require :sb-gmp)' \ + --eval '(require :sb-rt)' \ + --eval '(defvar *sb-gmp-tests* (uiop:read-file-string "contrib/sb-gmp/tests.lisp"))' \ + --load tools-for-build/dump-linkage-info.lisp \ + --eval '(sb-dump-linkage-info:dump-to-file "/tmp/linkage-info.sexp")' \ + --eval '(sb-ext:save-lisp-and-die "/tmp/sb-gmp-tester.core")' + +# Build a static runtime, with libgmp linked and the required symbols in the +# linkage table. +RUN set -x \ + && sbcl --script tools-for-build/create-linkage-table-prelink-info-override.lisp \ + /tmp/linkage-info.sexp \ + /tmp/linkage-table-prelink-info-override.c \ + && while read l; do \ + eval "${l%%=*}=\"${l#*=}\""; \ + done < /usr/local/lib/sbcl/sbcl.mk \ + && $CC $CFLAGS -Wno-builtin-declaration-mismatch -o /tmp/linkage-table-prelink-info-override.o -c /tmp/linkage-table-prelink-info-override.c \ + && $CC -no-pie -static $LINKFLAGS -o /tmp/static-sbcl /usr/local/lib/sbcl/$LIBSBCL /tmp/linkage-table-prelink-info-override.o -lgmp $LIBS + +# Use the new static runtime to load the previous core and then dump a +# compressed executable with the toplevel function set to run the sb-gmp test +# suite. +RUN set -x \ + && /tmp/static-sbcl \ + --core /tmp/sb-gmp-tester.core \ + --non-interactive \ + --eval '(sb-ext:save-lisp-and-die "/tmp/sb-gmp-tester" :executable t :toplevel (lambda () (uiop:load-from-string *sb-gmp-tests*) (sb-rt:do-tests) (exit)) :compression t)' diff --git a/tools-for-build/EastAsianWidth.txt b/tools-for-build/EastAsianWidth.txt index b72970e171..0d3129bb0a 100644 --- a/tools-for-build/EastAsianWidth.txt +++ b/tools-for-build/EastAsianWidth.txt @@ -1,35 +1,34 @@ -# EastAsianWidth-8.0.0.txt -# Date: 2015-02-10, 21:00:00 GMT [KW, LI] +# EastAsianWidth-10.0.0.txt +# Date: 2017-03-08, 02:00:00 GMT [KW, LI] +# © 2017 Unicode®, Inc. +# Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries. +# For terms of use, see http://www.unicode.org/terms_of_use.html +# +# Unicode Character Database +# For documentation, see http://www.unicode.org/reports/tr44/ # # East_Asian_Width Property # # This file is an informative contributory data file in the # Unicode Character Database. # -# Copyright (c) 1991-2015 Unicode, Inc. -# For terms of use, see http://www.unicode.org/terms_of_use.html -# # The format is two fields separated by a semicolon. # Field 0: Unicode code point value or range of code point values # Field 1: East_Asian_Width property, consisting of one of the following values: -# "N", "A", "H", "W", "F", "Na" +# "A", "F", "H", "N", "Na", "W" # - All code points, assigned or unassigned, that are not listed -# explicitly are given the value "N". -# The unassigned code points that default to "W" include ranges in the -# following blocks: -# CJK Unified Ideographs Extension A: U+3400..U+4DBF -# CJK Unified Ideographs: U+4E00..U+9FFF -# CJK Compatibility Ideographs: U+F900..U+FAFF -# CJK Unified Ideographs Extension B: U+20000..U+2A6DF -# CJK Unified Ideographs Extension C: U+2A700..U+2B73F -# CJK Unified Ideographs Extension D: U+2B740..U+2B81F -# CJK Unified Ideographs Extension E: U+2B820..U+2CEAF -# CJK Compatibility Ideographs Supplement: U+2F800..U+2FA1F -# and any other reserved code points on -# Planes 2 and 3: U+20000..U+2FFFD -# U+30000..U+3FFFD -# - Character ranges are specified as for other property files in -# the Unicode Character Database. +# explicitly are given the value "N". +# - The unassigned code points in the following blocks default to "W": +# CJK Unified Ideographs Extension A: U+3400..U+4DBF +# CJK Unified Ideographs: U+4E00..U+9FFF +# CJK Compatibility Ideographs: U+F900..U+FAFF +# - All undesignated code points in Planes 2 and 3, whether inside or +# outside of allocated blocks, default to "W": +# Plane 2: U+20000..U+2FFFD +# Plane 3: U+30000..U+3FFFD +# +# Character ranges are specified as for other property files in the +# Unicode Character Database. # # For legacy reasons, there are no spaces before or after the semicolon # which separates the two fields. The comments following the number sign @@ -329,7 +328,11 @@ 0840..0858;N # Lo [25] MANDAIC LETTER HALQA..MANDAIC LETTER AIN 0859..085B;N # Mn [3] MANDAIC AFFRICATION MARK..MANDAIC GEMINATION MARK 085E;N # Po MANDAIC PUNCTUATION +0860..086A;N # Lo [11] SYRIAC LETTER MALAYALAM NGA..SYRIAC LETTER MALAYALAM SSA 08A0..08B4;N # Lo [21] ARABIC LETTER BEH WITH SMALL V BELOW..ARABIC LETTER KAF WITH DOT BELOW +08B6..08BD;N # Lo [8] ARABIC LETTER BEH WITH SMALL MEEM ABOVE..ARABIC LETTER AFRICAN NOON +08D4..08E1;N # Mn [14] ARABIC SMALL HIGH WORD AR-RUB..ARABIC SMALL HIGH SIGN SAFHA +08E2;N # Cf ARABIC DISPUTED END OF AYAH 08E3..08FF;N # Mn [29] ARABIC TURNED DAMMA BELOW..ARABIC MARK SIDEWAYS NOON GHUNNA 0900..0902;N # Mn [3] DEVANAGARI SIGN INVERTED CANDRABINDU..DEVANAGARI SIGN ANUSVARA 0903;N # Mc DEVANAGARI SIGN VISARGA @@ -379,6 +382,8 @@ 09F4..09F9;N # No [6] BENGALI CURRENCY NUMERATOR ONE..BENGALI CURRENCY DENOMINATOR SIXTEEN 09FA;N # So BENGALI ISSHAR 09FB;N # Sc BENGALI GANDA MARK +09FC;N # Lo BENGALI LETTER VEDIC ANUSVARA +09FD;N # Po BENGALI ABBREVIATION SIGN 0A01..0A02;N # Mn [2] GURMUKHI SIGN ADAK BINDI..GURMUKHI SIGN BINDI 0A03;N # Mc GURMUKHI SIGN VISARGA 0A05..0A0A;N # Lo [6] GURMUKHI LETTER A..GURMUKHI LETTER UU @@ -423,6 +428,7 @@ 0AF0;N # Po GUJARATI ABBREVIATION SIGN 0AF1;N # Sc GUJARATI RUPEE SIGN 0AF9;N # Lo GUJARATI LETTER ZHA +0AFA..0AFF;N # Mn [6] GUJARATI SIGN SUKUN..GUJARATI SIGN TWO-CIRCLE NUKTA ABOVE 0B01;N # Mn ORIYA SIGN CANDRABINDU 0B02..0B03;N # Mc [2] ORIYA SIGN ANUSVARA..ORIYA SIGN VISARGA 0B05..0B0C;N # Lo [8] ORIYA LETTER A..ORIYA LETTER VOCALIC L @@ -491,6 +497,7 @@ 0C66..0C6F;N # Nd [10] TELUGU DIGIT ZERO..TELUGU DIGIT NINE 0C78..0C7E;N # No [7] TELUGU FRACTION DIGIT ZERO FOR ODD POWERS OF FOUR..TELUGU FRACTION DIGIT THREE FOR EVEN POWERS OF FOUR 0C7F;N # So TELUGU SIGN TUUMU +0C80;N # Lo KANNADA SIGN SPACING CANDRABINDU 0C81;N # Mn KANNADA SIGN CANDRABINDU 0C82..0C83;N # Mc [2] KANNADA SIGN ANUSVARA..KANNADA SIGN VISARGA 0C85..0C8C;N # Lo [8] KANNADA LETTER A..KANNADA LETTER VOCALIC L @@ -513,11 +520,12 @@ 0CE2..0CE3;N # Mn [2] KANNADA VOWEL SIGN VOCALIC L..KANNADA VOWEL SIGN VOCALIC LL 0CE6..0CEF;N # Nd [10] KANNADA DIGIT ZERO..KANNADA DIGIT NINE 0CF1..0CF2;N # Lo [2] KANNADA SIGN JIHVAMULIYA..KANNADA SIGN UPADHMANIYA -0D01;N # Mn MALAYALAM SIGN CANDRABINDU +0D00..0D01;N # Mn [2] MALAYALAM SIGN COMBINING ANUSVARA ABOVE..MALAYALAM SIGN CANDRABINDU 0D02..0D03;N # Mc [2] MALAYALAM SIGN ANUSVARA..MALAYALAM SIGN VISARGA 0D05..0D0C;N # Lo [8] MALAYALAM LETTER A..MALAYALAM LETTER VOCALIC L 0D0E..0D10;N # Lo [3] MALAYALAM LETTER E..MALAYALAM LETTER AI 0D12..0D3A;N # Lo [41] MALAYALAM LETTER O..MALAYALAM LETTER TTTA +0D3B..0D3C;N # Mn [2] MALAYALAM SIGN VERTICAL BAR VIRAMA..MALAYALAM SIGN CIRCULAR VIRAMA 0D3D;N # Lo MALAYALAM SIGN AVAGRAHA 0D3E..0D40;N # Mc [3] MALAYALAM VOWEL SIGN AA..MALAYALAM VOWEL SIGN II 0D41..0D44;N # Mn [4] MALAYALAM VOWEL SIGN U..MALAYALAM VOWEL SIGN VOCALIC RR @@ -525,11 +533,14 @@ 0D4A..0D4C;N # Mc [3] MALAYALAM VOWEL SIGN O..MALAYALAM VOWEL SIGN AU 0D4D;N # Mn MALAYALAM SIGN VIRAMA 0D4E;N # Lo MALAYALAM LETTER DOT REPH +0D4F;N # So MALAYALAM SIGN PARA +0D54..0D56;N # Lo [3] MALAYALAM LETTER CHILLU M..MALAYALAM LETTER CHILLU LLL 0D57;N # Mc MALAYALAM AU LENGTH MARK +0D58..0D5E;N # No [7] MALAYALAM FRACTION ONE ONE-HUNDRED-AND-SIXTIETH..MALAYALAM FRACTION ONE FIFTH 0D5F..0D61;N # Lo [3] MALAYALAM LETTER ARCHAIC II..MALAYALAM LETTER VOCALIC LL 0D62..0D63;N # Mn [2] MALAYALAM VOWEL SIGN VOCALIC L..MALAYALAM VOWEL SIGN VOCALIC LL 0D66..0D6F;N # Nd [10] MALAYALAM DIGIT ZERO..MALAYALAM DIGIT NINE -0D70..0D75;N # No [6] MALAYALAM NUMBER TEN..MALAYALAM FRACTION THREE QUARTERS +0D70..0D78;N # No [9] MALAYALAM NUMBER TEN..MALAYALAM FRACTION THREE SIXTEENTHS 0D79;N # So MALAYALAM DATE MARK 0D7A..0D7F;N # Lo [6] MALAYALAM LETTER CHILLU NN..MALAYALAM LETTER CHILLU K 0D82..0D83;N # Mc [2] SINHALA SIGN ANUSVARAYA..SINHALA SIGN VISARGAYA @@ -732,7 +743,9 @@ 1820..1842;N # Lo [35] MONGOLIAN LETTER A..MONGOLIAN LETTER CHI 1843;N # Lm MONGOLIAN LETTER TODO LONG VOWEL SIGN 1844..1877;N # Lo [52] MONGOLIAN LETTER TODO E..MONGOLIAN LETTER MANCHU ZHA -1880..18A8;N # Lo [41] MONGOLIAN LETTER ALI GALI ANUSVARA ONE..MONGOLIAN LETTER MANCHU ALI GALI BHA +1880..1884;N # Lo [5] MONGOLIAN LETTER ALI GALI ANUSVARA ONE..MONGOLIAN LETTER ALI GALI INVERTED UBADAMA +1885..1886;N # Mn [2] MONGOLIAN LETTER ALI GALI BALUDA..MONGOLIAN LETTER ALI GALI THREE BALUDA +1887..18A8;N # Lo [34] MONGOLIAN LETTER ALI GALI A..MONGOLIAN LETTER MANCHU ALI GALI BHA 18A9;N # Mn MONGOLIAN LETTER ALI GALI DAGALGA 18AA;N # Lo MONGOLIAN LETTER MANCHU ALI GALI LHA 18B0..18F5;N # Lo [70] CANADIAN SYLLABICS OY..CANADIAN SYLLABICS CARRIER DENTAL S @@ -832,6 +845,7 @@ 1C5A..1C77;N # Lo [30] OL CHIKI LETTER LA..OL CHIKI LETTER OH 1C78..1C7D;N # Lm [6] OL CHIKI MU TTUDDAG..OL CHIKI AHAD 1C7E..1C7F;N # Po [2] OL CHIKI PUNCTUATION MUCAAD..OL CHIKI PUNCTUATION DOUBLE MUCAAD +1C80..1C88;N # Ll [9] CYRILLIC SMALL LETTER ROUNDED VE..CYRILLIC SMALL LETTER UNBLENDED UK 1CC0..1CC7;N # Po [8] SUNDANESE PUNCTUATION BINDU SURYA..SUNDANESE PUNCTUATION BINDU BA SATANGA 1CD0..1CD2;N # Mn [3] VEDIC TONE KARSHANA..VEDIC TONE PRENKHA 1CD3;N # Po VEDIC SIGN NIHSHVASA @@ -844,6 +858,7 @@ 1CF2..1CF3;N # Mc [2] VEDIC SIGN ARDHAVISARGA..VEDIC SIGN ROTATED ARDHAVISARGA 1CF4;N # Mn VEDIC TONE CANDRA ABOVE 1CF5..1CF6;N # Lo [2] VEDIC SIGN JIHVAMULIYA..VEDIC SIGN UPADHMANIYA +1CF7;N # Mc VEDIC SIGN ATIKRAMA 1CF8..1CF9;N # Mn [2] VEDIC TONE RING ABOVE..VEDIC TONE DOUBLE RING ABOVE 1D00..1D2B;N # Ll [44] LATIN LETTER SMALL CAPITAL A..CYRILLIC LETTER SMALL CAPITAL EL 1D2C..1D6A;N # Lm [63] MODIFIER LETTER CAPITAL A..GREEK SUBSCRIPT SMALL LETTER CHI @@ -852,8 +867,8 @@ 1D79..1D7F;N # Ll [7] LATIN SMALL LETTER INSULAR G..LATIN SMALL LETTER UPSILON WITH STROKE 1D80..1D9A;N # Ll [27] LATIN SMALL LETTER B WITH PALATAL HOOK..LATIN SMALL LETTER EZH WITH RETROFLEX HOOK 1D9B..1DBF;N # Lm [37] MODIFIER LETTER SMALL TURNED ALPHA..MODIFIER LETTER SMALL THETA -1DC0..1DF5;N # Mn [54] COMBINING DOTTED GRAVE ACCENT..COMBINING UP TACK ABOVE -1DFC..1DFF;N # Mn [4] COMBINING DOUBLE INVERTED BREVE BELOW..COMBINING RIGHT ARROWHEAD AND DOWN ARROWHEAD BELOW +1DC0..1DF9;N # Mn [58] COMBINING DOTTED GRAVE ACCENT..COMBINING WIDE INVERTED BRIDGE BELOW +1DFB..1DFF;N # Mn [5] COMBINING DELETION MARK..COMBINING RIGHT ARROWHEAD AND DOWN ARROWHEAD BELOW 1E00..1EFF;N # L& [256] LATIN CAPITAL LETTER A WITH RING BELOW..LATIN SMALL LETTER Y WITH LOOP 1F00..1F15;N # L& [22] GREEK SMALL LETTER ALPHA WITH PSILI..GREEK SMALL LETTER EPSILON WITH DASIA AND OXIA 1F18..1F1D;N # Lu [6] GREEK CAPITAL LETTER EPSILON WITH PSILI..GREEK CAPITAL LETTER EPSILON WITH DASIA AND OXIA @@ -945,7 +960,7 @@ 20A9;H # Sc WON SIGN 20AA..20AB;N # Sc [2] NEW SHEQEL SIGN..DONG SIGN 20AC;A # Sc EURO SIGN -20AD..20BE;N # Sc [18] KIP SIGN..LARI SIGN +20AD..20BF;N # Sc [19] KIP SIGN..BITCOIN SIGN 20D0..20DC;N # Mn [13] COMBINING LEFT HARPOON ABOVE..COMBINING FOUR DOTS ABOVE 20DD..20E0;N # Me [4] COMBINING ENCLOSING CIRCLE..COMBINING ENCLOSING CIRCLE BACKSLASH 20E1;N # Mn COMBINING LEFT RIGHT ARROW ABOVE @@ -1092,7 +1107,9 @@ 230B;N # Pe RIGHT FLOOR 230C..2311;N # So [6] BOTTOM RIGHT CROP..SQUARE LOZENGE 2312;A # So ARC -2313..231F;N # So [13] SEGMENT..BOTTOM RIGHT CORNER +2313..2319;N # So [7] SEGMENT..TURNED NOT SIGN +231A..231B;W # So [2] WATCH..HOURGLASS +231C..231F;N # So [4] TOP LEFT CORNER..BOTTOM RIGHT CORNER 2320..2321;N # Sm [2] TOP HALF INTEGRAL..BOTTOM HALF INTEGRAL 2322..2328;N # So [7] FROWN..KEYBOARD 2329;W # Ps LEFT-POINTING ANGLE BRACKET @@ -1103,7 +1120,13 @@ 239B..23B3;N # Sm [25] LEFT PARENTHESIS UPPER HOOK..SUMMATION BOTTOM 23B4..23DB;N # So [40] TOP SQUARE BRACKET..FUSE 23DC..23E1;N # Sm [6] TOP PARENTHESIS..BOTTOM TORTOISE SHELL BRACKET -23E2..23FA;N # So [25] WHITE TRAPEZIUM..BLACK CIRCLE FOR RECORD +23E2..23E8;N # So [7] WHITE TRAPEZIUM..DECIMAL EXPONENT SYMBOL +23E9..23EC;W # So [4] BLACK RIGHT-POINTING DOUBLE TRIANGLE..BLACK DOWN-POINTING DOUBLE TRIANGLE +23ED..23EF;N # So [3] BLACK RIGHT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR..BLACK RIGHT-POINTING TRIANGLE WITH DOUBLE VERTICAL BAR +23F0;W # So ALARM CLOCK +23F1..23F2;N # So [2] STOPWATCH..TIMER CLOCK +23F3;W # So HOURGLASS WITH FLOWING SAND +23F4..23FF;N # So [12] BLACK MEDIUM LEFT-POINTING TRIANGLE..OBSERVER EYE SYMBOL 2400..2426;N # So [39] SYMBOL FOR NULL..SYMBOL FOR SUBSTITUTE FORM TWO 2440..244A;N # So [11] OCR HOOK..OCR DOUBLE BACKSLASH 2460..249B;A # No [60] CIRCLED DIGIT ONE..NUMBER TWENTY FULL STOP @@ -1142,7 +1165,9 @@ 25E6..25EE;N # So [9] WHITE BULLET..UP-POINTING TRIANGLE WITH RIGHT HALF BLACK 25EF;A # So LARGE CIRCLE 25F0..25F7;N # So [8] WHITE SQUARE WITH UPPER LEFT QUADRANT..WHITE CIRCLE WITH UPPER RIGHT QUADRANT -25F8..25FF;N # Sm [8] UPPER LEFT TRIANGLE..LOWER RIGHT TRIANGLE +25F8..25FC;N # Sm [5] UPPER LEFT TRIANGLE..BLACK MEDIUM SQUARE +25FD..25FE;W # Sm [2] WHITE MEDIUM SMALL SQUARE..BLACK MEDIUM SMALL SQUARE +25FF;N # Sm LOWER RIGHT TRIANGLE 2600..2604;N # So [5] BLACK SUN WITH RAYS..COMET 2605..2606;A # So [2] BLACK STAR..WHITE STAR 2607..2608;N # So [2] LIGHTNING..THUNDERSTORM @@ -1150,7 +1175,7 @@ 260A..260D;N # So [4] ASCENDING NODE..OPPOSITION 260E..260F;A # So [2] BLACK TELEPHONE..WHITE TELEPHONE 2610..2613;N # So [4] BALLOT BOX..SALTIRE -2614..2615;A # So [2] UMBRELLA WITH RAIN DROPS..HOT BEVERAGE +2614..2615;W # So [2] UMBRELLA WITH RAIN DROPS..HOT BEVERAGE 2616..261B;N # So [6] WHITE SHOGI PIECE..BLACK RIGHT POINTING INDEX 261C;A # So WHITE LEFT POINTING INDEX 261D;N # So WHITE UP POINTING INDEX @@ -1159,7 +1184,9 @@ 2640;A # So FEMALE SIGN 2641;N # So EARTH 2642;A # So MALE SIGN -2643..265F;N # So [29] JUPITER..BLACK CHESS PAWN +2643..2647;N # So [5] JUPITER..PLUTO +2648..2653;W # So [12] ARIES..PISCES +2654..265F;N # So [12] WHITE CHESS KING..BLACK CHESS PAWN 2660..2661;A # So [2] BLACK SPADE SUIT..WHITE HEART SUIT 2662;N # So WHITE DIAMOND SUIT 2663..2665;A # So [3] BLACK CLUB SUIT..BLACK HEART SUIT @@ -1169,22 +1196,56 @@ 266C..266D;A # So [2] BEAMED SIXTEENTH NOTES..MUSIC FLAT SIGN 266E;N # So MUSIC NATURAL SIGN 266F;A # Sm MUSIC SHARP SIGN -2670..269D;N # So [46] WEST SYRIAC CROSS..OUTLINED WHITE STAR +2670..267E;N # So [15] WEST SYRIAC CROSS..PERMANENT PAPER SIGN +267F;W # So WHEELCHAIR SYMBOL +2680..2692;N # So [19] DIE FACE-1..HAMMER AND PICK +2693;W # So ANCHOR +2694..269D;N # So [10] CROSSED SWORDS..OUTLINED WHITE STAR 269E..269F;A # So [2] THREE LINES CONVERGING RIGHT..THREE LINES CONVERGING LEFT -26A0..26BD;N # So [30] WARNING SIGN..SOCCER BALL -26BE..26BF;A # So [2] BASEBALL..SQUARED KEY +26A0;N # So WARNING SIGN +26A1;W # So HIGH VOLTAGE SIGN +26A2..26A9;N # So [8] DOUBLED FEMALE SIGN..HORIZONTAL MALE WITH STROKE SIGN +26AA..26AB;W # So [2] MEDIUM WHITE CIRCLE..MEDIUM BLACK CIRCLE +26AC..26BC;N # So [17] MEDIUM SMALL WHITE CIRCLE..SESQUIQUADRATE +26BD..26BE;W # So [2] SOCCER BALL..BASEBALL +26BF;A # So SQUARED KEY 26C0..26C3;N # So [4] WHITE DRAUGHTS MAN..BLACK DRAUGHTS KING -26C4..26CD;A # So [10] SNOWMAN WITHOUT SNOW..DISABLED CAR -26CE;N # So OPHIUCHUS -26CF..26E1;A # So [19] PICK..RESTRICTED LEFT ENTRY-2 +26C4..26C5;W # So [2] SNOWMAN WITHOUT SNOW..SUN BEHIND CLOUD +26C6..26CD;A # So [8] RAIN..DISABLED CAR +26CE;W # So OPHIUCHUS +26CF..26D3;A # So [5] PICK..CHAINS +26D4;W # So NO ENTRY +26D5..26E1;A # So [13] ALTERNATE ONE-WAY LEFT WAY TRAFFIC..RESTRICTED LEFT ENTRY-2 26E2;N # So ASTRONOMICAL SYMBOL FOR URANUS 26E3;A # So HEAVY CIRCLE WITH STROKE AND TWO DOTS ABOVE 26E4..26E7;N # So [4] PENTAGRAM..INVERTED PENTAGRAM -26E8..26FF;A # So [24] BLACK CROSS ON SHIELD..WHITE FLAG WITH HORIZONTAL MIDDLE BLACK STRIPE -2700..273C;N # So [61] BLACK SAFETY SCISSORS..OPEN CENTRE TEARDROP-SPOKED ASTERISK +26E8..26E9;A # So [2] BLACK CROSS ON SHIELD..SHINTO SHRINE +26EA;W # So CHURCH +26EB..26F1;A # So [7] CASTLE..UMBRELLA ON GROUND +26F2..26F3;W # So [2] FOUNTAIN..FLAG IN HOLE +26F4;A # So FERRY +26F5;W # So SAILBOAT +26F6..26F9;A # So [4] SQUARE FOUR CORNERS..PERSON WITH BALL +26FA;W # So TENT +26FB..26FC;A # So [2] JAPANESE BANK SYMBOL..HEADSTONE GRAVEYARD SYMBOL +26FD;W # So FUEL PUMP +26FE..26FF;A # So [2] CUP ON BLACK SQUARE..WHITE FLAG WITH HORIZONTAL MIDDLE BLACK STRIPE +2700..2704;N # So [5] BLACK SAFETY SCISSORS..WHITE SCISSORS +2705;W # So WHITE HEAVY CHECK MARK +2706..2709;N # So [4] TELEPHONE LOCATION SIGN..ENVELOPE +270A..270B;W # So [2] RAISED FIST..RAISED HAND +270C..2727;N # So [28] VICTORY HAND..WHITE FOUR POINTED STAR +2728;W # So SPARKLES +2729..273C;N # So [20] STRESS OUTLINED WHITE STAR..OPEN CENTRE TEARDROP-SPOKED ASTERISK 273D;A # So HEAVY TEARDROP-SPOKED ASTERISK -273E..2756;N # So [25] SIX PETALLED BLACK AND WHITE FLORETTE..BLACK DIAMOND MINUS WHITE X -2757;A # So HEAVY EXCLAMATION MARK SYMBOL +273E..274B;N # So [14] SIX PETALLED BLACK AND WHITE FLORETTE..HEAVY EIGHT TEARDROP-SPOKED PROPELLER ASTERISK +274C;W # So CROSS MARK +274D;N # So SHADOWED WHITE CIRCLE +274E;W # So NEGATIVE SQUARED CROSS MARK +274F..2752;N # So [4] LOWER RIGHT DROP-SHADOWED WHITE SQUARE..UPPER RIGHT SHADOWED WHITE SQUARE +2753..2755;W # So [3] BLACK QUESTION MARK ORNAMENT..WHITE EXCLAMATION MARK ORNAMENT +2756;N # So BLACK DIAMOND MINUS WHITE X +2757;W # So HEAVY EXCLAMATION MARK SYMBOL 2758..2767;N # So [16] LIGHT VERTICAL BAR..ROTATED FLORAL HEART BULLET 2768;N # Ps MEDIUM LEFT PARENTHESIS ORNAMENT 2769;N # Pe MEDIUM RIGHT PARENTHESIS ORNAMENT @@ -1202,7 +1263,12 @@ 2775;N # Pe MEDIUM RIGHT CURLY BRACKET ORNAMENT 2776..277F;A # No [10] DINGBAT NEGATIVE CIRCLED DIGIT ONE..DINGBAT NEGATIVE CIRCLED NUMBER TEN 2780..2793;N # No [20] DINGBAT CIRCLED SANS-SERIF DIGIT ONE..DINGBAT NEGATIVE CIRCLED SANS-SERIF NUMBER TEN -2794..27BF;N # So [44] HEAVY WIDE-HEADED RIGHTWARDS ARROW..DOUBLE CURLY LOOP +2794;N # So HEAVY WIDE-HEADED RIGHTWARDS ARROW +2795..2797;W # So [3] HEAVY PLUS SIGN..HEAVY DIVISION SIGN +2798..27AF;N # So [24] HEAVY SOUTH EAST ARROW..NOTCHED LOWER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW +27B0;W # So CURLY LOOP +27B1..27BE;N # So [14] NOTCHED UPPER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW..OPEN-OUTLINED RIGHTWARDS ARROW +27BF;W # So DOUBLE CURLY LOOP 27C0..27C4;N # Sm [5] THREE DIMENSIONAL ANGLE..OPEN SUPERSET 27C5;N # Ps LEFT S-SHAPED BAG DELIMITER 27C6;N # Pe RIGHT S-SHAPED BAG DELIMITER @@ -1253,17 +1319,22 @@ 29FD;N # Pe RIGHT-POINTING CURVED ANGLE BRACKET 29FE..29FF;N # Sm [2] TINY..MINY 2A00..2AFF;N # Sm [256] N-ARY CIRCLED DOT OPERATOR..N-ARY WHITE VERTICAL BAR -2B00..2B2F;N # So [48] NORTH EAST WHITE ARROW..WHITE VERTICAL ELLIPSE +2B00..2B1A;N # So [27] NORTH EAST WHITE ARROW..DOTTED SQUARE +2B1B..2B1C;W # So [2] BLACK LARGE SQUARE..WHITE LARGE SQUARE +2B1D..2B2F;N # So [19] BLACK VERY SMALL SQUARE..WHITE VERTICAL ELLIPSE 2B30..2B44;N # Sm [21] LEFT ARROW WITH SMALL CIRCLE..RIGHTWARDS ARROW THROUGH SUPERSET 2B45..2B46;N # So [2] LEFTWARDS QUADRUPLE ARROW..RIGHTWARDS QUADRUPLE ARROW 2B47..2B4C;N # Sm [6] REVERSE TILDE OPERATOR ABOVE RIGHTWARDS ARROW..RIGHTWARDS ARROW ABOVE REVERSE TILDE OPERATOR -2B4D..2B54;N # So [8] DOWNWARDS TRIANGLE-HEADED ZIGZAG ARROW..WHITE RIGHT-POINTING PENTAGON -2B55..2B59;A # So [5] HEAVY LARGE CIRCLE..HEAVY CIRCLED SALTIRE +2B4D..2B4F;N # So [3] DOWNWARDS TRIANGLE-HEADED ZIGZAG ARROW..SHORT BACKSLANTED SOUTH ARROW +2B50;W # So WHITE MEDIUM STAR +2B51..2B54;N # So [4] BLACK SMALL STAR..WHITE RIGHT-POINTING PENTAGON +2B55;W # So HEAVY LARGE CIRCLE +2B56..2B59;A # So [4] HEAVY OVAL WITH OVAL INSIDE..HEAVY CIRCLED SALTIRE 2B5A..2B73;N # So [26] SLANTED NORTH ARROW WITH HOOKED HEAD..DOWNWARDS TRIANGLE-HEADED ARROW TO BAR 2B76..2B95;N # So [32] NORTH WEST TRIANGLE-HEADED ARROW TO BAR..RIGHTWARDS BLACK ARROW 2B98..2BB9;N # So [34] THREE-D TOP-LIGHTED LEFTWARDS EQUILATERAL ARROWHEAD..UP ARROWHEAD IN A RECTANGLE BOX 2BBD..2BC8;N # So [12] BALLOT BOX WITH LIGHT X..BLACK MEDIUM RIGHT-POINTING TRIANGLE CENTRED -2BCA..2BD1;N # So [8] TOP HALF BLACK CIRCLE..UNCERTAINTY SIGN +2BCA..2BD2;N # So [9] TOP HALF BLACK CIRCLE..GROUP MARK 2BEC..2BEF;N # So [4] LEFTWARDS TWO-HEADED ARROW WITH TRIANGLE ARROWHEADS..DOWNWARDS TWO-HEADED ARROW WITH TRIANGLE ARROWHEADS 2C00..2C2E;N # Lu [47] GLAGOLITIC CAPITAL LETTER AZU..GLAGOLITIC CAPITAL LETTER LATINATE MYSLITE 2C30..2C5E;N # Ll [47] GLAGOLITIC SMALL LETTER AZU..GLAGOLITIC SMALL LETTER LATINATE MYSLITE @@ -1332,6 +1403,7 @@ 2E40;N # Pd DOUBLE HYPHEN 2E41;N # Po REVERSED COMMA 2E42;N # Ps DOUBLE LOW-REVERSED-9 QUOTATION MARK +2E43..2E49;N # Po [7] DASH WITH LEFT UPTURN..DOUBLE STACKED COMMA 2E80..2E99;W # So [26] CJK RADICAL REPEAT..CJK RADICAL RAP 2E9B..2EF3;W # So [89] CJK RADICAL CHOKE..CJK RADICAL C-SIMPLIFIED TURTLE 2F00..2FD5;W # So [214] KANGXI RADICAL ONE..KANGXI RADICAL FLUTE @@ -1387,7 +1459,7 @@ 30FB;W # Po KATAKANA MIDDLE DOT 30FC..30FE;W # Lm [3] KATAKANA-HIRAGANA PROLONGED SOUND MARK..KATAKANA VOICED ITERATION MARK 30FF;W # Lo KATAKANA DIGRAPH KOTO -3105..312D;W # Lo [41] BOPOMOFO LETTER B..BOPOMOFO LETTER IH +3105..312E;W # Lo [42] BOPOMOFO LETTER B..BOPOMOFO LETTER O WITH DOT ABOVE 3131..318E;W # Lo [94] HANGUL LETTER KIYEOK..HANGUL LETTER ARAEAE 3190..3191;W # So [2] IDEOGRAPHIC ANNOTATION LINKING MARK..IDEOGRAPHIC ANNOTATION REVERSE MARK 3192..3195;W # No [4] IDEOGRAPHIC ANNOTATION ONE MARK..IDEOGRAPHIC ANNOTATION FOUR MARK @@ -1410,8 +1482,8 @@ 3400..4DB5;W # Lo [6582] CJK UNIFIED IDEOGRAPH-3400..CJK UNIFIED IDEOGRAPH-4DB5 4DB6..4DBF;W # Cn [10] <reserved-4DB6>..<reserved-4DBF> 4DC0..4DFF;N # So [64] HEXAGRAM FOR THE CREATIVE HEAVEN..HEXAGRAM FOR BEFORE COMPLETION -4E00..9FD5;W # Lo [20950] CJK UNIFIED IDEOGRAPH-4E00..CJK UNIFIED IDEOGRAPH-9FD5 -9FD6..9FFF;W # Cn [42] <reserved-9FD6>..<reserved-9FFF> +4E00..9FEA;W # Lo [20971] CJK UNIFIED IDEOGRAPH-4E00..CJK UNIFIED IDEOGRAPH-9FEA +9FEB..9FFF;W # Cn [21] <reserved-9FEB>..<reserved-9FFF> A000..A014;W # Lo [21] YI SYLLABLE IT..YI SYLLABLE E A015;W # Lm YI SYLLABLE WU A016..A48C;W # Lo [1143] YI SYLLABLE BIT..YI SYLLABLE YYR @@ -1450,7 +1522,7 @@ A788;N # Lm MODIFIER LETTER LOW CIRCUMFLEX ACCENT A789..A78A;N # Sk [2] MODIFIER LETTER COLON..MODIFIER LETTER SHORT EQUALS SIGN A78B..A78E;N # L& [4] LATIN CAPITAL LETTER SALTILLO..LATIN SMALL LETTER L WITH RETROFLEX HOOK AND BELT A78F;N # Lo LATIN LETTER SINOLOGICAL DOT -A790..A7AD;N # L& [30] LATIN CAPITAL LETTER N WITH DESCENDER..LATIN CAPITAL LETTER L WITH BELT +A790..A7AE;N # L& [31] LATIN CAPITAL LETTER N WITH DESCENDER..LATIN CAPITAL LETTER SMALL CAPITAL I A7B0..A7B7;N # L& [8] LATIN CAPITAL LETTER TURNED K..LATIN SMALL LETTER OMEGA A7F7;N # Lo LATIN EPIGRAPHIC LETTER SIDEWAYS I A7F8..A7F9;N # Lm [2] MODIFIER LETTER CAPITAL H WITH STROKE..MODIFIER LETTER SMALL LIGATURE OE @@ -1476,7 +1548,7 @@ A874..A877;N # Po [4] PHAGS-PA SINGLE HEAD MARK..PHAGS-PA MARK DOUBLE SH A880..A881;N # Mc [2] SAURASHTRA SIGN ANUSVARA..SAURASHTRA SIGN VISARGA A882..A8B3;N # Lo [50] SAURASHTRA LETTER A..SAURASHTRA LETTER LLA A8B4..A8C3;N # Mc [16] SAURASHTRA CONSONANT SIGN HAARU..SAURASHTRA VOWEL SIGN AU -A8C4;N # Mn SAURASHTRA SIGN VIRAMA +A8C4..A8C5;N # Mn [2] SAURASHTRA SIGN VIRAMA..SAURASHTRA SIGN CANDRABINDU A8CE..A8CF;N # Po [2] SAURASHTRA DANDA..SAURASHTRA DOUBLE DANDA A8D0..A8D9;N # Nd [10] SAURASHTRA DIGIT ZERO..SAURASHTRA DIGIT NINE A8E0..A8F1;N # Mn [18] COMBINING DEVANAGARI DIGIT ZERO..COMBINING DEVANAGARI SIGN AVAGRAHA @@ -1726,7 +1798,7 @@ FFFD;A # So REPLACEMENT CHARACTER 10175..10178;N # No [4] GREEK ONE HALF SIGN..GREEK THREE QUARTERS SIGN 10179..10189;N # So [17] GREEK YEAR SIGN..GREEK TRYBLION BASE SIGN 1018A..1018B;N # No [2] GREEK ZERO SIGN..GREEK ONE QUARTER SIGN -1018C;N # So GREEK SINUSOID SIGN +1018C..1018E;N # So [3] GREEK SINUSOID SIGN..NOMISMA SIGN 10190..1019B;N # So [12] ROMAN SEXTANS SIGN..ROMAN CENTURIAL SIGN 101A0;N # So GREEK SYMBOL TAU RHO 101D0..101FC;N # So [45] PHAISTOS DISC SIGN PEDESTRIAN..PHAISTOS DISC SIGN WAVY BAND @@ -1737,6 +1809,7 @@ FFFD;A # So REPLACEMENT CHARACTER 102E1..102FB;N # No [27] COPTIC EPACT DIGIT ONE..COPTIC EPACT NUMBER NINE HUNDRED 10300..1031F;N # Lo [32] OLD ITALIC LETTER A..OLD ITALIC LETTER ESS 10320..10323;N # No [4] OLD ITALIC NUMERAL ONE..OLD ITALIC NUMERAL FIFTY +1032D..1032F;N # Lo [3] OLD ITALIC LETTER YE..OLD ITALIC LETTER SOUTHERN TSE 10330..10340;N # Lo [17] GOTHIC LETTER AHSA..GOTHIC LETTER PAIRTHRA 10341;N # Nl GOTHIC LETTER NINETY 10342..10349;N # Lo [8] GOTHIC LETTER RAIDA..GOTHIC LETTER OTHAL @@ -1753,6 +1826,8 @@ FFFD;A # So REPLACEMENT CHARACTER 10450..1047F;N # Lo [48] SHAVIAN LETTER PEEP..SHAVIAN LETTER YEW 10480..1049D;N # Lo [30] OSMANYA LETTER ALEF..OSMANYA LETTER OO 104A0..104A9;N # Nd [10] OSMANYA DIGIT ZERO..OSMANYA DIGIT NINE +104B0..104D3;N # Lu [36] OSAGE CAPITAL LETTER A..OSAGE CAPITAL LETTER ZHA +104D8..104FB;N # Ll [36] OSAGE SMALL LETTER A..OSAGE SMALL LETTER ZHA 10500..10527;N # Lo [40] ELBASAN LETTER A..ELBASAN LETTER KHE 10530..10563;N # Lo [52] CAUCASIAN ALBANIAN LETTER ALT..CAUCASIAN ALBANIAN LETTER KIW 1056F;N # Po CAUCASIAN ALBANIAN CITATION MARK @@ -1880,6 +1955,7 @@ FFFD;A # So REPLACEMENT CHARACTER 11235;N # Mc KHOJKI SIGN VIRAMA 11236..11237;N # Mn [2] KHOJKI SIGN NUKTA..KHOJKI SIGN SHADDA 11238..1123D;N # Po [6] KHOJKI DANDA..KHOJKI ABBREVIATION SIGN +1123E;N # Mn KHOJKI SIGN SUKUN 11280..11286;N # Lo [7] MULTANI LETTER A..MULTANI LETTER GA 11288;N # Lo MULTANI LETTER GHA 1128A..1128D;N # Lo [4] MULTANI LETTER CA..MULTANI LETTER JJA @@ -1912,6 +1988,18 @@ FFFD;A # So REPLACEMENT CHARACTER 11362..11363;N # Mc [2] GRANTHA VOWEL SIGN VOCALIC L..GRANTHA VOWEL SIGN VOCALIC LL 11366..1136C;N # Mn [7] COMBINING GRANTHA DIGIT ZERO..COMBINING GRANTHA DIGIT SIX 11370..11374;N # Mn [5] COMBINING GRANTHA LETTER A..COMBINING GRANTHA LETTER PA +11400..11434;N # Lo [53] NEWA LETTER A..NEWA LETTER HA +11435..11437;N # Mc [3] NEWA VOWEL SIGN AA..NEWA VOWEL SIGN II +11438..1143F;N # Mn [8] NEWA VOWEL SIGN U..NEWA VOWEL SIGN AI +11440..11441;N # Mc [2] NEWA VOWEL SIGN O..NEWA VOWEL SIGN AU +11442..11444;N # Mn [3] NEWA SIGN VIRAMA..NEWA SIGN ANUSVARA +11445;N # Mc NEWA SIGN VISARGA +11446;N # Mn NEWA SIGN NUKTA +11447..1144A;N # Lo [4] NEWA SIGN AVAGRAHA..NEWA SIDDHI +1144B..1144F;N # Po [5] NEWA DANDA..NEWA ABBREVIATION SIGN +11450..11459;N # Nd [10] NEWA DIGIT ZERO..NEWA DIGIT NINE +1145B;N # Po NEWA PLACEHOLDER MARK +1145D;N # Po NEWA INSERTION SIGN 11480..114AF;N # Lo [48] TIRHUTA ANJI..TIRHUTA LETTER HA 114B0..114B2;N # Mc [3] TIRHUTA VOWEL SIGN AA..TIRHUTA VOWEL SIGN II 114B3..114B8;N # Mn [6] TIRHUTA VOWEL SIGN U..TIRHUTA VOWEL SIGN VOCALIC LL @@ -1945,6 +2033,7 @@ FFFD;A # So REPLACEMENT CHARACTER 11641..11643;N # Po [3] MODI DANDA..MODI ABBREVIATION SIGN 11644;N # Lo MODI SIGN HUVA 11650..11659;N # Nd [10] MODI DIGIT ZERO..MODI DIGIT NINE +11660..1166C;N # Po [13] MONGOLIAN BIRGA WITH ORNAMENT..MONGOLIAN TURNED SWIRL BIRGA WITH DOUBLE ORNAMENT 11680..116AA;N # Lo [43] TAKRI LETTER A..TAKRI LETTER RRA 116AB;N # Mn TAKRI SIGN ANUSVARA 116AC;N # Mc TAKRI SIGN VISARGA @@ -1968,7 +2057,59 @@ FFFD;A # So REPLACEMENT CHARACTER 118E0..118E9;N # Nd [10] WARANG CITI DIGIT ZERO..WARANG CITI DIGIT NINE 118EA..118F2;N # No [9] WARANG CITI NUMBER TEN..WARANG CITI NUMBER NINETY 118FF;N # Lo WARANG CITI OM +11A00;N # Lo ZANABAZAR SQUARE LETTER A +11A01..11A06;N # Mn [6] ZANABAZAR SQUARE VOWEL SIGN I..ZANABAZAR SQUARE VOWEL SIGN O +11A07..11A08;N # Mc [2] ZANABAZAR SQUARE VOWEL SIGN AI..ZANABAZAR SQUARE VOWEL SIGN AU +11A09..11A0A;N # Mn [2] ZANABAZAR SQUARE VOWEL SIGN REVERSED I..ZANABAZAR SQUARE VOWEL LENGTH MARK +11A0B..11A32;N # Lo [40] ZANABAZAR SQUARE LETTER KA..ZANABAZAR SQUARE LETTER KSSA +11A33..11A38;N # Mn [6] ZANABAZAR SQUARE FINAL CONSONANT MARK..ZANABAZAR SQUARE SIGN ANUSVARA +11A39;N # Mc ZANABAZAR SQUARE SIGN VISARGA +11A3A;N # Lo ZANABAZAR SQUARE CLUSTER-INITIAL LETTER RA +11A3B..11A3E;N # Mn [4] ZANABAZAR SQUARE CLUSTER-FINAL LETTER YA..ZANABAZAR SQUARE CLUSTER-FINAL LETTER VA +11A3F..11A46;N # Po [8] ZANABAZAR SQUARE INITIAL HEAD MARK..ZANABAZAR SQUARE CLOSING DOUBLE-LINED HEAD MARK +11A47;N # Mn ZANABAZAR SQUARE SUBJOINER +11A50;N # Lo SOYOMBO LETTER A +11A51..11A56;N # Mn [6] SOYOMBO VOWEL SIGN I..SOYOMBO VOWEL SIGN OE +11A57..11A58;N # Mc [2] SOYOMBO VOWEL SIGN AI..SOYOMBO VOWEL SIGN AU +11A59..11A5B;N # Mn [3] SOYOMBO VOWEL SIGN VOCALIC R..SOYOMBO VOWEL LENGTH MARK +11A5C..11A83;N # Lo [40] SOYOMBO LETTER KA..SOYOMBO LETTER KSSA +11A86..11A89;N # Lo [4] SOYOMBO CLUSTER-INITIAL LETTER RA..SOYOMBO CLUSTER-INITIAL LETTER SA +11A8A..11A96;N # Mn [13] SOYOMBO FINAL CONSONANT SIGN G..SOYOMBO SIGN ANUSVARA +11A97;N # Mc SOYOMBO SIGN VISARGA +11A98..11A99;N # Mn [2] SOYOMBO GEMINATION MARK..SOYOMBO SUBJOINER +11A9A..11A9C;N # Po [3] SOYOMBO MARK TSHEG..SOYOMBO MARK DOUBLE SHAD +11A9E..11AA2;N # Po [5] SOYOMBO HEAD MARK WITH MOON AND SUN AND TRIPLE FLAME..SOYOMBO TERMINAL MARK-2 11AC0..11AF8;N # Lo [57] PAU CIN HAU LETTER PA..PAU CIN HAU GLOTTAL STOP FINAL +11C00..11C08;N # Lo [9] BHAIKSUKI LETTER A..BHAIKSUKI LETTER VOCALIC L +11C0A..11C2E;N # Lo [37] BHAIKSUKI LETTER E..BHAIKSUKI LETTER HA +11C2F;N # Mc BHAIKSUKI VOWEL SIGN AA +11C30..11C36;N # Mn [7] BHAIKSUKI VOWEL SIGN I..BHAIKSUKI VOWEL SIGN VOCALIC L +11C38..11C3D;N # Mn [6] BHAIKSUKI VOWEL SIGN E..BHAIKSUKI SIGN ANUSVARA +11C3E;N # Mc BHAIKSUKI SIGN VISARGA +11C3F;N # Mn BHAIKSUKI SIGN VIRAMA +11C40;N # Lo BHAIKSUKI SIGN AVAGRAHA +11C41..11C45;N # Po [5] BHAIKSUKI DANDA..BHAIKSUKI GAP FILLER-2 +11C50..11C59;N # Nd [10] BHAIKSUKI DIGIT ZERO..BHAIKSUKI DIGIT NINE +11C5A..11C6C;N # No [19] BHAIKSUKI NUMBER ONE..BHAIKSUKI HUNDREDS UNIT MARK +11C70..11C71;N # Po [2] MARCHEN HEAD MARK..MARCHEN MARK SHAD +11C72..11C8F;N # Lo [30] MARCHEN LETTER KA..MARCHEN LETTER A +11C92..11CA7;N # Mn [22] MARCHEN SUBJOINED LETTER KA..MARCHEN SUBJOINED LETTER ZA +11CA9;N # Mc MARCHEN SUBJOINED LETTER YA +11CAA..11CB0;N # Mn [7] MARCHEN SUBJOINED LETTER RA..MARCHEN VOWEL SIGN AA +11CB1;N # Mc MARCHEN VOWEL SIGN I +11CB2..11CB3;N # Mn [2] MARCHEN VOWEL SIGN U..MARCHEN VOWEL SIGN E +11CB4;N # Mc MARCHEN VOWEL SIGN O +11CB5..11CB6;N # Mn [2] MARCHEN SIGN ANUSVARA..MARCHEN SIGN CANDRABINDU +11D00..11D06;N # Lo [7] MASARAM GONDI LETTER A..MASARAM GONDI LETTER E +11D08..11D09;N # Lo [2] MASARAM GONDI LETTER AI..MASARAM GONDI LETTER O +11D0B..11D30;N # Lo [38] MASARAM GONDI LETTER AU..MASARAM GONDI LETTER TRA +11D31..11D36;N # Mn [6] MASARAM GONDI VOWEL SIGN AA..MASARAM GONDI VOWEL SIGN VOCALIC R +11D3A;N # Mn MASARAM GONDI VOWEL SIGN E +11D3C..11D3D;N # Mn [2] MASARAM GONDI VOWEL SIGN AI..MASARAM GONDI VOWEL SIGN O +11D3F..11D45;N # Mn [7] MASARAM GONDI VOWEL SIGN AU..MASARAM GONDI VIRAMA +11D46;N # Lo MASARAM GONDI REPHA +11D47;N # Mn MASARAM GONDI RA-KARA +11D50..11D59;N # Nd [10] MASARAM GONDI DIGIT ZERO..MASARAM GONDI DIGIT NINE 12000..12399;N # Lo [922] CUNEIFORM SIGN A..CUNEIFORM SIGN U U 12400..1246E;N # Nl [111] CUNEIFORM NUMERIC SIGN TWO ASH..CUNEIFORM NUMERIC SIGN NINE U VARIANT FORM 12470..12474;N # Po [5] CUNEIFORM PUNCTUATION SIGN OLD ASSYRIAN WORD DIVIDER..CUNEIFORM PUNCTUATION SIGN DIAGONAL QUADCOLON @@ -1998,7 +2139,12 @@ FFFD;A # So REPLACEMENT CHARACTER 16F51..16F7E;N # Mc [46] MIAO SIGN ASPIRATION..MIAO VOWEL SIGN NG 16F8F..16F92;N # Mn [4] MIAO TONE RIGHT..MIAO TONE BELOW 16F93..16F9F;N # Lm [13] MIAO LETTER TONE-2..MIAO LETTER REFORMED TONE-8 -1B000..1B001;W # Lo [2] KATAKANA LETTER ARCHAIC E..HIRAGANA LETTER ARCHAIC YE +16FE0..16FE1;W # Lm [2] TANGUT ITERATION MARK..NUSHU ITERATION MARK +17000..187EC;W # Lo [6125] TANGUT IDEOGRAPH-17000..TANGUT IDEOGRAPH-187EC +18800..18AF2;W # Lo [755] TANGUT COMPONENT-001..TANGUT COMPONENT-755 +1B000..1B0FF;W # Lo [256] KATAKANA LETTER ARCHAIC E..HENTAIGANA LETTER RE-2 +1B100..1B11E;W # Lo [31] HENTAIGANA LETTER RE-3..HENTAIGANA LETTER N-MU-MO-2 +1B170..1B2FB;W # Lo [396] NUSHU CHARACTER-1B170..NUSHU CHARACTER-1B2FB 1BC00..1BC6A;N # Lo [107] DUPLOYAN LETTER H..DUPLOYAN LETTER VOCALIC M 1BC70..1BC7C;N # Lo [13] DUPLOYAN AFFIX LEFT HORIZONTAL SECANT..DUPLOYAN AFFIX ATTACHED TANGENT HOOK 1BC80..1BC88;N # Lo [9] DUPLOYAN AFFIX HIGH ACUTE..DUPLOYAN AFFIX HIGH VERTICAL @@ -2079,9 +2225,18 @@ FFFD;A # So REPLACEMENT CHARACTER 1DA87..1DA8B;N # Po [5] SIGNWRITING COMMA..SIGNWRITING PARENTHESIS 1DA9B..1DA9F;N # Mn [5] SIGNWRITING FILL MODIFIER-2..SIGNWRITING FILL MODIFIER-6 1DAA1..1DAAF;N # Mn [15] SIGNWRITING ROTATION MODIFIER-2..SIGNWRITING ROTATION MODIFIER-16 +1E000..1E006;N # Mn [7] COMBINING GLAGOLITIC LETTER AZU..COMBINING GLAGOLITIC LETTER ZHIVETE +1E008..1E018;N # Mn [17] COMBINING GLAGOLITIC LETTER ZEMLJA..COMBINING GLAGOLITIC LETTER HERU +1E01B..1E021;N # Mn [7] COMBINING GLAGOLITIC LETTER SHTA..COMBINING GLAGOLITIC LETTER YATI +1E023..1E024;N # Mn [2] COMBINING GLAGOLITIC LETTER YU..COMBINING GLAGOLITIC LETTER SMALL YUS +1E026..1E02A;N # Mn [5] COMBINING GLAGOLITIC LETTER YO..COMBINING GLAGOLITIC LETTER FITA 1E800..1E8C4;N # Lo [197] MENDE KIKAKUI SYLLABLE M001 KI..MENDE KIKAKUI SYLLABLE M060 NYON 1E8C7..1E8CF;N # No [9] MENDE KIKAKUI DIGIT ONE..MENDE KIKAKUI DIGIT NINE 1E8D0..1E8D6;N # Mn [7] MENDE KIKAKUI COMBINING NUMBER TEENS..MENDE KIKAKUI COMBINING NUMBER MILLIONS +1E900..1E943;N # L& [68] ADLAM CAPITAL LETTER ALIF..ADLAM SMALL LETTER SHA +1E944..1E94A;N # Mn [7] ADLAM ALIF LENGTHENER..ADLAM NUKTA +1E950..1E959;N # Nd [10] ADLAM DIGIT ZERO..ADLAM DIGIT NINE +1E95E..1E95F;N # Po [2] ADLAM INITIAL EXCLAMATION MARK..ADLAM INITIAL QUESTION MARK 1EE00..1EE03;N # Lo [4] ARABIC MATHEMATICAL ALEF..ARABIC MATHEMATICAL DAL 1EE05..1EE1F;N # Lo [27] ARABIC MATHEMATICAL WAW..ARABIC MATHEMATICAL DOTLESS QAF 1EE21..1EE22;N # Lo [2] ARABIC MATHEMATICAL INITIAL BEH..ARABIC MATHEMATICAL INITIAL JEEM @@ -2116,11 +2271,14 @@ FFFD;A # So REPLACEMENT CHARACTER 1EEA5..1EEA9;N # Lo [5] ARABIC MATHEMATICAL DOUBLE-STRUCK WAW..ARABIC MATHEMATICAL DOUBLE-STRUCK YEH 1EEAB..1EEBB;N # Lo [17] ARABIC MATHEMATICAL DOUBLE-STRUCK LAM..ARABIC MATHEMATICAL DOUBLE-STRUCK GHAIN 1EEF0..1EEF1;N # Sm [2] ARABIC MATHEMATICAL OPERATOR MEEM WITH HAH WITH TATWEEL..ARABIC MATHEMATICAL OPERATOR HAH WITH DAL -1F000..1F02B;N # So [44] MAHJONG TILE EAST WIND..MAHJONG TILE BACK +1F000..1F003;N # So [4] MAHJONG TILE EAST WIND..MAHJONG TILE NORTH WIND +1F004;W # So MAHJONG TILE RED DRAGON +1F005..1F02B;N # So [39] MAHJONG TILE GREEN DRAGON..MAHJONG TILE BACK 1F030..1F093;N # So [100] DOMINO TILE HORIZONTAL BACK..DOMINO TILE VERTICAL-06-06 1F0A0..1F0AE;N # So [15] PLAYING CARD BACK..PLAYING CARD KING OF SPADES 1F0B1..1F0BF;N # So [15] PLAYING CARD ACE OF HEARTS..PLAYING CARD RED JOKER -1F0C1..1F0CF;N # So [15] PLAYING CARD ACE OF DIAMONDS..PLAYING CARD BLACK JOKER +1F0C1..1F0CE;N # So [14] PLAYING CARD ACE OF DIAMONDS..PLAYING CARD KING OF DIAMONDS +1F0CF;W # So PLAYING CARD BLACK JOKER 1F0D1..1F0F5;N # So [37] PLAYING CARD ACE OF CLUBS..PLAYING CARD TRUMP-21 1F100..1F10A;A # No [11] DIGIT ZERO FULL STOP..DIGIT NINE COMMA 1F10B..1F10C;N # No [2] DINGBAT CIRCLED SANS-SERIF DIGIT ZERO..DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT ZERO @@ -2128,22 +2286,66 @@ FFFD;A # So REPLACEMENT CHARACTER 1F12E;N # So CIRCLED WZ 1F130..1F169;A # So [58] SQUARED LATIN CAPITAL LETTER A..NEGATIVE CIRCLED LATIN CAPITAL LETTER Z 1F16A..1F16B;N # So [2] RAISED MC SIGN..RAISED MD SIGN -1F170..1F19A;A # So [43] NEGATIVE SQUARED LATIN CAPITAL LETTER A..SQUARED VS +1F170..1F18D;A # So [30] NEGATIVE SQUARED LATIN CAPITAL LETTER A..NEGATIVE SQUARED SA +1F18E;W # So NEGATIVE SQUARED AB +1F18F..1F190;A # So [2] NEGATIVE SQUARED WC..SQUARE DJ +1F191..1F19A;W # So [10] SQUARED CL..SQUARED VS +1F19B..1F1AC;A # So [18] SQUARED THREE D..SQUARED VOD 1F1E6..1F1FF;N # So [26] REGIONAL INDICATOR SYMBOL LETTER A..REGIONAL INDICATOR SYMBOL LETTER Z 1F200..1F202;W # So [3] SQUARE HIRAGANA HOKA..SQUARED KATAKANA SA -1F210..1F23A;W # So [43] SQUARED CJK UNIFIED IDEOGRAPH-624B..SQUARED CJK UNIFIED IDEOGRAPH-55B6 +1F210..1F23B;W # So [44] SQUARED CJK UNIFIED IDEOGRAPH-624B..SQUARED CJK UNIFIED IDEOGRAPH-914D 1F240..1F248;W # So [9] TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-672C..TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-6557 1F250..1F251;W # So [2] CIRCLED IDEOGRAPH ADVANTAGE..CIRCLED IDEOGRAPH ACCEPT -1F300..1F3FA;N # So [251] CYCLONE..AMPHORA -1F3FB..1F3FF;N # Sk [5] EMOJI MODIFIER FITZPATRICK TYPE-1-2..EMOJI MODIFIER FITZPATRICK TYPE-6 -1F400..1F579;N # So [378] RAT..JOYSTICK -1F57B..1F5A3;N # So [41] LEFT HAND TELEPHONE RECEIVER..BLACK DOWN POINTING BACKHAND INDEX -1F5A5..1F5FF;N # So [91] DESKTOP COMPUTER..MOYAI -1F600..1F64F;N # So [80] GRINNING FACE..PERSON WITH FOLDED HANDS +1F260..1F265;W # So [6] ROUNDED SYMBOL FOR FU..ROUNDED SYMBOL FOR CAI +1F300..1F320;W # So [33] CYCLONE..SHOOTING STAR +1F321..1F32C;N # So [12] THERMOMETER..WIND BLOWING FACE +1F32D..1F335;W # So [9] HOT DOG..CACTUS +1F336;N # So HOT PEPPER +1F337..1F37C;W # So [70] TULIP..BABY BOTTLE +1F37D;N # So FORK AND KNIFE WITH PLATE +1F37E..1F393;W # So [22] BOTTLE WITH POPPING CORK..GRADUATION CAP +1F394..1F39F;N # So [12] HEART WITH TIP ON THE LEFT..ADMISSION TICKETS +1F3A0..1F3CA;W # So [43] CAROUSEL HORSE..SWIMMER +1F3CB..1F3CE;N # So [4] WEIGHT LIFTER..RACING CAR +1F3CF..1F3D3;W # So [5] CRICKET BAT AND BALL..TABLE TENNIS PADDLE AND BALL +1F3D4..1F3DF;N # So [12] SNOW CAPPED MOUNTAIN..STADIUM +1F3E0..1F3F0;W # So [17] HOUSE BUILDING..EUROPEAN CASTLE +1F3F1..1F3F3;N # So [3] WHITE PENNANT..WAVING WHITE FLAG +1F3F4;W # So WAVING BLACK FLAG +1F3F5..1F3F7;N # So [3] ROSETTE..LABEL +1F3F8..1F3FA;W # So [3] BADMINTON RACQUET AND SHUTTLECOCK..AMPHORA +1F3FB..1F3FF;W # Sk [5] EMOJI MODIFIER FITZPATRICK TYPE-1-2..EMOJI MODIFIER FITZPATRICK TYPE-6 +1F400..1F43E;W # So [63] RAT..PAW PRINTS +1F43F;N # So CHIPMUNK +1F440;W # So EYES +1F441;N # So EYE +1F442..1F4FC;W # So [187] EAR..VIDEOCASSETTE +1F4FD..1F4FE;N # So [2] FILM PROJECTOR..PORTABLE STEREO +1F4FF..1F53D;W # So [63] PRAYER BEADS..DOWN-POINTING SMALL RED TRIANGLE +1F53E..1F54A;N # So [13] LOWER RIGHT SHADOWED WHITE CIRCLE..DOVE OF PEACE +1F54B..1F54E;W # So [4] KAABA..MENORAH WITH NINE BRANCHES +1F54F;N # So BOWL OF HYGIEIA +1F550..1F567;W # So [24] CLOCK FACE ONE OCLOCK..CLOCK FACE TWELVE-THIRTY +1F568..1F579;N # So [18] RIGHT SPEAKER..JOYSTICK +1F57A;W # So MAN DANCING +1F57B..1F594;N # So [26] LEFT HAND TELEPHONE RECEIVER..REVERSED VICTORY HAND +1F595..1F596;W # So [2] REVERSED HAND WITH MIDDLE FINGER EXTENDED..RAISED HAND WITH PART BETWEEN MIDDLE AND RING FINGERS +1F597..1F5A3;N # So [13] WHITE DOWN POINTING LEFT HAND INDEX..BLACK DOWN POINTING BACKHAND INDEX +1F5A4;W # So BLACK HEART +1F5A5..1F5FA;N # So [86] DESKTOP COMPUTER..WORLD MAP +1F5FB..1F5FF;W # So [5] MOUNT FUJI..MOYAI +1F600..1F64F;W # So [80] GRINNING FACE..PERSON WITH FOLDED HANDS 1F650..1F67F;N # So [48] NORTH WEST POINTING LEAF..REVERSE CHECKER BOARD -1F680..1F6D0;N # So [81] ROCKET..PLACE OF WORSHIP -1F6E0..1F6EC;N # So [13] HAMMER AND WRENCH..AIRPLANE ARRIVING +1F680..1F6C5;W # So [70] ROCKET..LEFT LUGGAGE +1F6C6..1F6CB;N # So [6] TRIANGLE WITH ROUNDED CORNERS..COUCH AND LAMP +1F6CC;W # So SLEEPING ACCOMMODATION +1F6CD..1F6CF;N # So [3] SHOPPING BAGS..BED +1F6D0..1F6D2;W # So [3] PLACE OF WORSHIP..SHOPPING TROLLEY +1F6D3..1F6D4;N # So [2] STUPA..PAGODA +1F6E0..1F6EA;N # So [11] HAMMER AND WRENCH..NORTHEAST-POINTING AIRPLANE +1F6EB..1F6EC;W # So [2] AIRPLANE DEPARTURE..AIRPLANE ARRIVING 1F6F0..1F6F3;N # So [4] SATELLITE..PASSENGER SHIP +1F6F4..1F6F8;W # So [5] SCOOTER..FLYING SAUCER 1F700..1F773;N # So [116] ALCHEMICAL SYMBOL FOR QUINTESSENCE..ALCHEMICAL SYMBOL FOR HALF OUNCE 1F780..1F7D4;N # So [85] BLACK LEFT-POINTING ISOSCELES RIGHT TRIANGLE..HEAVY TWELVE POINTED PINWHEEL STAR 1F800..1F80B;N # So [12] LEFTWARDS ARROW WITH SMALL TRIANGLE ARROWHEAD..DOWNWARDS ARROW WITH LARGE TRIANGLE ARROWHEAD @@ -2151,9 +2353,13 @@ FFFD;A # So REPLACEMENT CHARACTER 1F850..1F859;N # So [10] LEFTWARDS SANS-SERIF ARROW..UP DOWN SANS-SERIF ARROW 1F860..1F887;N # So [40] WIDE-HEADED LEFTWARDS LIGHT BARB ARROW..WIDE-HEADED SOUTH WEST VERY HEAVY BARB ARROW 1F890..1F8AD;N # So [30] LEFTWARDS TRIANGLE ARROWHEAD..WHITE ARROW SHAFT WIDTH TWO THIRDS -1F910..1F918;N # So [9] ZIPPER-MOUTH FACE..SIGN OF THE HORNS -1F980..1F984;N # So [5] CRAB..UNICORN FACE -1F9C0;N # So CHEESE WEDGE +1F900..1F90B;N # So [12] CIRCLED CROSS FORMEE WITH FOUR DOTS..DOWNWARD FACING NOTCHED HOOK WITH DOT +1F910..1F93E;W # So [47] ZIPPER-MOUTH FACE..HANDBALL +1F940..1F94C;W # So [13] WILTED FLOWER..CURLING STONE +1F950..1F96B;W # So [28] CROISSANT..CANNED FOOD +1F980..1F997;W # So [24] CRAB..CRICKET +1F9C0;W # So CHEESE WEDGE +1F9D0..1F9E6;W # So [23] FACE WITH MONOCLE..SOCKS 20000..2A6D6;W # Lo [42711] CJK UNIFIED IDEOGRAPH-20000..CJK UNIFIED IDEOGRAPH-2A6D6 2A6D7..2A6FF;W # Cn [41] <reserved-2A6D7>..<reserved-2A6FF> 2A700..2B734;W # Lo [4149] CJK UNIFIED IDEOGRAPH-2A700..CJK UNIFIED IDEOGRAPH-2B734 @@ -2161,7 +2367,9 @@ FFFD;A # So REPLACEMENT CHARACTER 2B740..2B81D;W # Lo [222] CJK UNIFIED IDEOGRAPH-2B740..CJK UNIFIED IDEOGRAPH-2B81D 2B81E..2B81F;W # Cn [2] <reserved-2B81E>..<reserved-2B81F> 2B820..2CEA1;W # Lo [5762] CJK UNIFIED IDEOGRAPH-2B820..CJK UNIFIED IDEOGRAPH-2CEA1 -2CEA2..2F7FF;W # Cn [10590] <reserved-2CEA2>..<reserved-2F7FF> +2CEA2..2CEAF;W # Cn [14] <reserved-2CEA2>..<reserved-2CEAF> +2CEB0..2EBE0;W # Lo [7473] CJK UNIFIED IDEOGRAPH-2CEB0..CJK UNIFIED IDEOGRAPH-2EBE0 +2EBE1..2F7FF;W # Cn [3103] <reserved-2EBE1>..<reserved-2F7FF> 2F800..2FA1D;W # Lo [542] CJK COMPATIBILITY IDEOGRAPH-2F800..CJK COMPATIBILITY IDEOGRAPH-2FA1D 2FA1E..2FFFD;W # Cn [1504] <reserved-2FA1E>..<reserved-2FFFD> 30000..3FFFD;W # Cn [65534] <reserved-30000>..<reserved-3FFFD> diff --git a/tools-for-build/GraphemeBreakProperty.txt b/tools-for-build/GraphemeBreakProperty.txt deleted file mode 100644 index fba2ee8793..0000000000 --- a/tools-for-build/GraphemeBreakProperty.txt +++ /dev/null @@ -1,1336 +0,0 @@ -# GraphemeBreakProperty-8.0.0.txt -# Date: 2015-02-13, 13:47:14 GMT [MD] -# -# Unicode Character Database -# Copyright (c) 1991-2015 Unicode, Inc. -# For terms of use, see http://www.unicode.org/terms_of_use.html -# For documentation, see http://www.unicode.org/reports/tr44/ - -# ================================================ - -# Property: Grapheme_Cluster_Break - -# All code points not explicitly listed for Grapheme_Cluster_Break -# have the value Other (XX). - -# @missing: 0000..10FFFF; Other - -# ================================================ - -000D ; CR # Cc <control-000D> - -# Total code points: 1 - -# ================================================ - -000A ; LF # Cc <control-000A> - -# Total code points: 1 - -# ================================================ - -0000..0009 ; Control # Cc [10] <control-0000>..<control-0009> -000B..000C ; Control # Cc [2] <control-000B>..<control-000C> -000E..001F ; Control # Cc [18] <control-000E>..<control-001F> -007F..009F ; Control # Cc [33] <control-007F>..<control-009F> -00AD ; Control # Cf SOFT HYPHEN -0600..0605 ; Control # Cf [6] ARABIC NUMBER SIGN..ARABIC NUMBER MARK ABOVE -061C ; Control # Cf ARABIC LETTER MARK -06DD ; Control # Cf ARABIC END OF AYAH -070F ; Control # Cf SYRIAC ABBREVIATION MARK -180E ; Control # Cf MONGOLIAN VOWEL SEPARATOR -200B ; Control # Cf ZERO WIDTH SPACE -200E..200F ; Control # Cf [2] LEFT-TO-RIGHT MARK..RIGHT-TO-LEFT MARK -2028 ; Control # Zl LINE SEPARATOR -2029 ; Control # Zp PARAGRAPH SEPARATOR -202A..202E ; Control # Cf [5] LEFT-TO-RIGHT EMBEDDING..RIGHT-TO-LEFT OVERRIDE -2060..2064 ; Control # Cf [5] WORD JOINER..INVISIBLE PLUS -2065 ; Control # Cn <reserved-2065> -2066..206F ; Control # Cf [10] LEFT-TO-RIGHT ISOLATE..NOMINAL DIGIT SHAPES -D800..DFFF ; Control # Cs [2048] <surrogate-D800>..<surrogate-DFFF> -FEFF ; Control # Cf ZERO WIDTH NO-BREAK SPACE -FFF0..FFF8 ; Control # Cn [9] <reserved-FFF0>..<reserved-FFF8> -FFF9..FFFB ; Control # Cf [3] INTERLINEAR ANNOTATION ANCHOR..INTERLINEAR ANNOTATION TERMINATOR -110BD ; Control # Cf KAITHI NUMBER SIGN -1BCA0..1BCA3 ; Control # Cf [4] SHORTHAND FORMAT LETTER OVERLAP..SHORTHAND FORMAT UP STEP -1D173..1D17A ; Control # Cf [8] MUSICAL SYMBOL BEGIN BEAM..MUSICAL SYMBOL END PHRASE -E0000 ; Control # Cn <reserved-E0000> -E0001 ; Control # Cf LANGUAGE TAG -E0002..E001F ; Control # Cn [30] <reserved-E0002>..<reserved-E001F> -E0020..E007F ; Control # Cf [96] TAG SPACE..CANCEL TAG -E0080..E00FF ; Control # Cn [128] <reserved-E0080>..<reserved-E00FF> -E01F0..E0FFF ; Control # Cn [3600] <reserved-E01F0>..<reserved-E0FFF> - -# Total code points: 6030 - -# ================================================ - -0300..036F ; Extend # Mn [112] COMBINING GRAVE ACCENT..COMBINING LATIN SMALL LETTER X -0483..0487 ; Extend # Mn [5] COMBINING CYRILLIC TITLO..COMBINING CYRILLIC POKRYTIE -0488..0489 ; Extend # Me [2] COMBINING CYRILLIC HUNDRED THOUSANDS SIGN..COMBINING CYRILLIC MILLIONS SIGN -0591..05BD ; Extend # Mn [45] HEBREW ACCENT ETNAHTA..HEBREW POINT METEG -05BF ; Extend # Mn HEBREW POINT RAFE -05C1..05C2 ; Extend # Mn [2] HEBREW POINT SHIN DOT..HEBREW POINT SIN DOT -05C4..05C5 ; Extend # Mn [2] HEBREW MARK UPPER DOT..HEBREW MARK LOWER DOT -05C7 ; Extend # Mn HEBREW POINT QAMATS QATAN -0610..061A ; Extend # Mn [11] ARABIC SIGN SALLALLAHOU ALAYHE WASSALLAM..ARABIC SMALL KASRA -064B..065F ; Extend # Mn [21] ARABIC FATHATAN..ARABIC WAVY HAMZA BELOW -0670 ; Extend # Mn ARABIC LETTER SUPERSCRIPT ALEF -06D6..06DC ; Extend # Mn [7] ARABIC SMALL HIGH LIGATURE SAD WITH LAM WITH ALEF MAKSURA..ARABIC SMALL HIGH SEEN -06DF..06E4 ; Extend # Mn [6] ARABIC SMALL HIGH ROUNDED ZERO..ARABIC SMALL HIGH MADDA -06E7..06E8 ; Extend # Mn [2] ARABIC SMALL HIGH YEH..ARABIC SMALL HIGH NOON -06EA..06ED ; Extend # Mn [4] ARABIC EMPTY CENTRE LOW STOP..ARABIC SMALL LOW MEEM -0711 ; Extend # Mn SYRIAC LETTER SUPERSCRIPT ALAPH -0730..074A ; Extend # Mn [27] SYRIAC PTHAHA ABOVE..SYRIAC BARREKH -07A6..07B0 ; Extend # Mn [11] THAANA ABAFILI..THAANA SUKUN -07EB..07F3 ; Extend # Mn [9] NKO COMBINING SHORT HIGH TONE..NKO COMBINING DOUBLE DOT ABOVE -0816..0819 ; Extend # Mn [4] SAMARITAN MARK IN..SAMARITAN MARK DAGESH -081B..0823 ; Extend # Mn [9] SAMARITAN MARK EPENTHETIC YUT..SAMARITAN VOWEL SIGN A -0825..0827 ; Extend # Mn [3] SAMARITAN VOWEL SIGN SHORT A..SAMARITAN VOWEL SIGN U -0829..082D ; Extend # Mn [5] SAMARITAN VOWEL SIGN LONG I..SAMARITAN MARK NEQUDAA -0859..085B ; Extend # Mn [3] MANDAIC AFFRICATION MARK..MANDAIC GEMINATION MARK -08E3..0902 ; Extend # Mn [32] ARABIC TURNED DAMMA BELOW..DEVANAGARI SIGN ANUSVARA -093A ; Extend # Mn DEVANAGARI VOWEL SIGN OE -093C ; Extend # Mn DEVANAGARI SIGN NUKTA -0941..0948 ; Extend # Mn [8] DEVANAGARI VOWEL SIGN U..DEVANAGARI VOWEL SIGN AI -094D ; Extend # Mn DEVANAGARI SIGN VIRAMA -0951..0957 ; Extend # Mn [7] DEVANAGARI STRESS SIGN UDATTA..DEVANAGARI VOWEL SIGN UUE -0962..0963 ; Extend # Mn [2] DEVANAGARI VOWEL SIGN VOCALIC L..DEVANAGARI VOWEL SIGN VOCALIC LL -0981 ; Extend # Mn BENGALI SIGN CANDRABINDU -09BC ; Extend # Mn BENGALI SIGN NUKTA -09BE ; Extend # Mc BENGALI VOWEL SIGN AA -09C1..09C4 ; Extend # Mn [4] BENGALI VOWEL SIGN U..BENGALI VOWEL SIGN VOCALIC RR -09CD ; Extend # Mn BENGALI SIGN VIRAMA -09D7 ; Extend # Mc BENGALI AU LENGTH MARK -09E2..09E3 ; Extend # Mn [2] BENGALI VOWEL SIGN VOCALIC L..BENGALI VOWEL SIGN VOCALIC LL -0A01..0A02 ; Extend # Mn [2] GURMUKHI SIGN ADAK BINDI..GURMUKHI SIGN BINDI -0A3C ; Extend # Mn GURMUKHI SIGN NUKTA -0A41..0A42 ; Extend # Mn [2] GURMUKHI VOWEL SIGN U..GURMUKHI VOWEL SIGN UU -0A47..0A48 ; Extend # Mn [2] GURMUKHI VOWEL SIGN EE..GURMUKHI VOWEL SIGN AI -0A4B..0A4D ; Extend # Mn [3] GURMUKHI VOWEL SIGN OO..GURMUKHI SIGN VIRAMA -0A51 ; Extend # Mn GURMUKHI SIGN UDAAT -0A70..0A71 ; Extend # Mn [2] GURMUKHI TIPPI..GURMUKHI ADDAK -0A75 ; Extend # Mn GURMUKHI SIGN YAKASH -0A81..0A82 ; Extend # Mn [2] GUJARATI SIGN CANDRABINDU..GUJARATI SIGN ANUSVARA -0ABC ; Extend # Mn GUJARATI SIGN NUKTA -0AC1..0AC5 ; Extend # Mn [5] GUJARATI VOWEL SIGN U..GUJARATI VOWEL SIGN CANDRA E -0AC7..0AC8 ; Extend # Mn [2] GUJARATI VOWEL SIGN E..GUJARATI VOWEL SIGN AI -0ACD ; Extend # Mn GUJARATI SIGN VIRAMA -0AE2..0AE3 ; Extend # Mn [2] GUJARATI VOWEL SIGN VOCALIC L..GUJARATI VOWEL SIGN VOCALIC LL -0B01 ; Extend # Mn ORIYA SIGN CANDRABINDU -0B3C ; Extend # Mn ORIYA SIGN NUKTA -0B3E ; Extend # Mc ORIYA VOWEL SIGN AA -0B3F ; Extend # Mn ORIYA VOWEL SIGN I -0B41..0B44 ; Extend # Mn [4] ORIYA VOWEL SIGN U..ORIYA VOWEL SIGN VOCALIC RR -0B4D ; Extend # Mn ORIYA SIGN VIRAMA -0B56 ; Extend # Mn ORIYA AI LENGTH MARK -0B57 ; Extend # Mc ORIYA AU LENGTH MARK -0B62..0B63 ; Extend # Mn [2] ORIYA VOWEL SIGN VOCALIC L..ORIYA VOWEL SIGN VOCALIC LL -0B82 ; Extend # Mn TAMIL SIGN ANUSVARA -0BBE ; Extend # Mc TAMIL VOWEL SIGN AA -0BC0 ; Extend # Mn TAMIL VOWEL SIGN II -0BCD ; Extend # Mn TAMIL SIGN VIRAMA -0BD7 ; Extend # Mc TAMIL AU LENGTH MARK -0C00 ; Extend # Mn TELUGU SIGN COMBINING CANDRABINDU ABOVE -0C3E..0C40 ; Extend # Mn [3] TELUGU VOWEL SIGN AA..TELUGU VOWEL SIGN II -0C46..0C48 ; Extend # Mn [3] TELUGU VOWEL SIGN E..TELUGU VOWEL SIGN AI -0C4A..0C4D ; Extend # Mn [4] TELUGU VOWEL SIGN O..TELUGU SIGN VIRAMA -0C55..0C56 ; Extend # Mn [2] TELUGU LENGTH MARK..TELUGU AI LENGTH MARK -0C62..0C63 ; Extend # Mn [2] TELUGU VOWEL SIGN VOCALIC L..TELUGU VOWEL SIGN VOCALIC LL -0C81 ; Extend # Mn KANNADA SIGN CANDRABINDU -0CBC ; Extend # Mn KANNADA SIGN NUKTA -0CBF ; Extend # Mn KANNADA VOWEL SIGN I -0CC2 ; Extend # Mc KANNADA VOWEL SIGN UU -0CC6 ; Extend # Mn KANNADA VOWEL SIGN E -0CCC..0CCD ; Extend # Mn [2] KANNADA VOWEL SIGN AU..KANNADA SIGN VIRAMA -0CD5..0CD6 ; Extend # Mc [2] KANNADA LENGTH MARK..KANNADA AI LENGTH MARK -0CE2..0CE3 ; Extend # Mn [2] KANNADA VOWEL SIGN VOCALIC L..KANNADA VOWEL SIGN VOCALIC LL -0D01 ; Extend # Mn MALAYALAM SIGN CANDRABINDU -0D3E ; Extend # Mc MALAYALAM VOWEL SIGN AA -0D41..0D44 ; Extend # Mn [4] MALAYALAM VOWEL SIGN U..MALAYALAM VOWEL SIGN VOCALIC RR -0D4D ; Extend # Mn MALAYALAM SIGN VIRAMA -0D57 ; Extend # Mc MALAYALAM AU LENGTH MARK -0D62..0D63 ; Extend # Mn [2] MALAYALAM VOWEL SIGN VOCALIC L..MALAYALAM VOWEL SIGN VOCALIC LL -0DCA ; Extend # Mn SINHALA SIGN AL-LAKUNA -0DCF ; Extend # Mc SINHALA VOWEL SIGN AELA-PILLA -0DD2..0DD4 ; Extend # Mn [3] SINHALA VOWEL SIGN KETTI IS-PILLA..SINHALA VOWEL SIGN KETTI PAA-PILLA -0DD6 ; Extend # Mn SINHALA VOWEL SIGN DIGA PAA-PILLA -0DDF ; Extend # Mc SINHALA VOWEL SIGN GAYANUKITTA -0E31 ; Extend # Mn THAI CHARACTER MAI HAN-AKAT -0E34..0E3A ; Extend # Mn [7] THAI CHARACTER SARA I..THAI CHARACTER PHINTHU -0E47..0E4E ; Extend # Mn [8] THAI CHARACTER MAITAIKHU..THAI CHARACTER YAMAKKAN -0EB1 ; Extend # Mn LAO VOWEL SIGN MAI KAN -0EB4..0EB9 ; Extend # Mn [6] LAO VOWEL SIGN I..LAO VOWEL SIGN UU -0EBB..0EBC ; Extend # Mn [2] LAO VOWEL SIGN MAI KON..LAO SEMIVOWEL SIGN LO -0EC8..0ECD ; Extend # Mn [6] LAO TONE MAI EK..LAO NIGGAHITA -0F18..0F19 ; Extend # Mn [2] TIBETAN ASTROLOGICAL SIGN -KHYUD PA..TIBETAN ASTROLOGICAL SIGN SDONG TSHUGS -0F35 ; Extend # Mn TIBETAN MARK NGAS BZUNG NYI ZLA -0F37 ; Extend # Mn TIBETAN MARK NGAS BZUNG SGOR RTAGS -0F39 ; Extend # Mn TIBETAN MARK TSA -PHRU -0F71..0F7E ; Extend # Mn [14] TIBETAN VOWEL SIGN AA..TIBETAN SIGN RJES SU NGA RO -0F80..0F84 ; Extend # Mn [5] TIBETAN VOWEL SIGN REVERSED I..TIBETAN MARK HALANTA -0F86..0F87 ; Extend # Mn [2] TIBETAN SIGN LCI RTAGS..TIBETAN SIGN YANG RTAGS -0F8D..0F97 ; Extend # Mn [11] TIBETAN SUBJOINED SIGN LCE TSA CAN..TIBETAN SUBJOINED LETTER JA -0F99..0FBC ; Extend # Mn [36] TIBETAN SUBJOINED LETTER NYA..TIBETAN SUBJOINED LETTER FIXED-FORM RA -0FC6 ; Extend # Mn TIBETAN SYMBOL PADMA GDAN -102D..1030 ; Extend # Mn [4] MYANMAR VOWEL SIGN I..MYANMAR VOWEL SIGN UU -1032..1037 ; Extend # Mn [6] MYANMAR VOWEL SIGN AI..MYANMAR SIGN DOT BELOW -1039..103A ; Extend # Mn [2] MYANMAR SIGN VIRAMA..MYANMAR SIGN ASAT -103D..103E ; Extend # Mn [2] MYANMAR CONSONANT SIGN MEDIAL WA..MYANMAR CONSONANT SIGN MEDIAL HA -1058..1059 ; Extend # Mn [2] MYANMAR VOWEL SIGN VOCALIC L..MYANMAR VOWEL SIGN VOCALIC LL -105E..1060 ; Extend # Mn [3] MYANMAR CONSONANT SIGN MON MEDIAL NA..MYANMAR CONSONANT SIGN MON MEDIAL LA -1071..1074 ; Extend # Mn [4] MYANMAR VOWEL SIGN GEBA KAREN I..MYANMAR VOWEL SIGN KAYAH EE -1082 ; Extend # Mn MYANMAR CONSONANT SIGN SHAN MEDIAL WA -1085..1086 ; Extend # Mn [2] MYANMAR VOWEL SIGN SHAN E ABOVE..MYANMAR VOWEL SIGN SHAN FINAL Y -108D ; Extend # Mn MYANMAR SIGN SHAN COUNCIL EMPHATIC TONE -109D ; Extend # Mn MYANMAR VOWEL SIGN AITON AI -135D..135F ; Extend # Mn [3] ETHIOPIC COMBINING GEMINATION AND VOWEL LENGTH MARK..ETHIOPIC COMBINING GEMINATION MARK -1712..1714 ; Extend # Mn [3] TAGALOG VOWEL SIGN I..TAGALOG SIGN VIRAMA -1732..1734 ; Extend # Mn [3] HANUNOO VOWEL SIGN I..HANUNOO SIGN PAMUDPOD -1752..1753 ; Extend # Mn [2] BUHID VOWEL SIGN I..BUHID VOWEL SIGN U -1772..1773 ; Extend # Mn [2] TAGBANWA VOWEL SIGN I..TAGBANWA VOWEL SIGN U -17B4..17B5 ; Extend # Mn [2] KHMER VOWEL INHERENT AQ..KHMER VOWEL INHERENT AA -17B7..17BD ; Extend # Mn [7] KHMER VOWEL SIGN I..KHMER VOWEL SIGN UA -17C6 ; Extend # Mn KHMER SIGN NIKAHIT -17C9..17D3 ; Extend # Mn [11] KHMER SIGN MUUSIKATOAN..KHMER SIGN BATHAMASAT -17DD ; Extend # Mn KHMER SIGN ATTHACAN -180B..180D ; Extend # Mn [3] MONGOLIAN FREE VARIATION SELECTOR ONE..MONGOLIAN FREE VARIATION SELECTOR THREE -18A9 ; Extend # Mn MONGOLIAN LETTER ALI GALI DAGALGA -1920..1922 ; Extend # Mn [3] LIMBU VOWEL SIGN A..LIMBU VOWEL SIGN U -1927..1928 ; Extend # Mn [2] LIMBU VOWEL SIGN E..LIMBU VOWEL SIGN O -1932 ; Extend # Mn LIMBU SMALL LETTER ANUSVARA -1939..193B ; Extend # Mn [3] LIMBU SIGN MUKPHRENG..LIMBU SIGN SA-I -1A17..1A18 ; Extend # Mn [2] BUGINESE VOWEL SIGN I..BUGINESE VOWEL SIGN U -1A1B ; Extend # Mn BUGINESE VOWEL SIGN AE -1A56 ; Extend # Mn TAI THAM CONSONANT SIGN MEDIAL LA -1A58..1A5E ; Extend # Mn [7] TAI THAM SIGN MAI KANG LAI..TAI THAM CONSONANT SIGN SA -1A60 ; Extend # Mn TAI THAM SIGN SAKOT -1A62 ; Extend # Mn TAI THAM VOWEL SIGN MAI SAT -1A65..1A6C ; Extend # Mn [8] TAI THAM VOWEL SIGN I..TAI THAM VOWEL SIGN OA BELOW -1A73..1A7C ; Extend # Mn [10] TAI THAM VOWEL SIGN OA ABOVE..TAI THAM SIGN KHUEN-LUE KARAN -1A7F ; Extend # Mn TAI THAM COMBINING CRYPTOGRAMMIC DOT -1AB0..1ABD ; Extend # Mn [14] COMBINING DOUBLED CIRCUMFLEX ACCENT..COMBINING PARENTHESES BELOW -1ABE ; Extend # Me COMBINING PARENTHESES OVERLAY -1B00..1B03 ; Extend # Mn [4] BALINESE SIGN ULU RICEM..BALINESE SIGN SURANG -1B34 ; Extend # Mn BALINESE SIGN REREKAN -1B36..1B3A ; Extend # Mn [5] BALINESE VOWEL SIGN ULU..BALINESE VOWEL SIGN RA REPA -1B3C ; Extend # Mn BALINESE VOWEL SIGN LA LENGA -1B42 ; Extend # Mn BALINESE VOWEL SIGN PEPET -1B6B..1B73 ; Extend # Mn [9] BALINESE MUSICAL SYMBOL COMBINING TEGEH..BALINESE MUSICAL SYMBOL COMBINING GONG -1B80..1B81 ; Extend # Mn [2] SUNDANESE SIGN PANYECEK..SUNDANESE SIGN PANGLAYAR -1BA2..1BA5 ; Extend # Mn [4] SUNDANESE CONSONANT SIGN PANYAKRA..SUNDANESE VOWEL SIGN PANYUKU -1BA8..1BA9 ; Extend # Mn [2] SUNDANESE VOWEL SIGN PAMEPET..SUNDANESE VOWEL SIGN PANEULEUNG -1BAB..1BAD ; Extend # Mn [3] SUNDANESE SIGN VIRAMA..SUNDANESE CONSONANT SIGN PASANGAN WA -1BE6 ; Extend # Mn BATAK SIGN TOMPI -1BE8..1BE9 ; Extend # Mn [2] BATAK VOWEL SIGN PAKPAK E..BATAK VOWEL SIGN EE -1BED ; Extend # Mn BATAK VOWEL SIGN KARO O -1BEF..1BF1 ; Extend # Mn [3] BATAK VOWEL SIGN U FOR SIMALUNGUN SA..BATAK CONSONANT SIGN H -1C2C..1C33 ; Extend # Mn [8] LEPCHA VOWEL SIGN E..LEPCHA CONSONANT SIGN T -1C36..1C37 ; Extend # Mn [2] LEPCHA SIGN RAN..LEPCHA SIGN NUKTA -1CD0..1CD2 ; Extend # Mn [3] VEDIC TONE KARSHANA..VEDIC TONE PRENKHA -1CD4..1CE0 ; Extend # Mn [13] VEDIC SIGN YAJURVEDIC MIDLINE SVARITA..VEDIC TONE RIGVEDIC KASHMIRI INDEPENDENT SVARITA -1CE2..1CE8 ; Extend # Mn [7] VEDIC SIGN VISARGA SVARITA..VEDIC SIGN VISARGA ANUDATTA WITH TAIL -1CED ; Extend # Mn VEDIC SIGN TIRYAK -1CF4 ; Extend # Mn VEDIC TONE CANDRA ABOVE -1CF8..1CF9 ; Extend # Mn [2] VEDIC TONE RING ABOVE..VEDIC TONE DOUBLE RING ABOVE -1DC0..1DF5 ; Extend # Mn [54] COMBINING DOTTED GRAVE ACCENT..COMBINING UP TACK ABOVE -1DFC..1DFF ; Extend # Mn [4] COMBINING DOUBLE INVERTED BREVE BELOW..COMBINING RIGHT ARROWHEAD AND DOWN ARROWHEAD BELOW -200C..200D ; Extend # Cf [2] ZERO WIDTH NON-JOINER..ZERO WIDTH JOINER -20D0..20DC ; Extend # Mn [13] COMBINING LEFT HARPOON ABOVE..COMBINING FOUR DOTS ABOVE -20DD..20E0 ; Extend # Me [4] COMBINING ENCLOSING CIRCLE..COMBINING ENCLOSING CIRCLE BACKSLASH -20E1 ; Extend # Mn COMBINING LEFT RIGHT ARROW ABOVE -20E2..20E4 ; Extend # Me [3] COMBINING ENCLOSING SCREEN..COMBINING ENCLOSING UPWARD POINTING TRIANGLE -20E5..20F0 ; Extend # Mn [12] COMBINING REVERSE SOLIDUS OVERLAY..COMBINING ASTERISK ABOVE -2CEF..2CF1 ; Extend # Mn [3] COPTIC COMBINING NI ABOVE..COPTIC COMBINING SPIRITUS LENIS -2D7F ; Extend # Mn TIFINAGH CONSONANT JOINER -2DE0..2DFF ; Extend # Mn [32] COMBINING CYRILLIC LETTER BE..COMBINING CYRILLIC LETTER IOTIFIED BIG YUS -302A..302D ; Extend # Mn [4] IDEOGRAPHIC LEVEL TONE MARK..IDEOGRAPHIC ENTERING TONE MARK -302E..302F ; Extend # Mc [2] HANGUL SINGLE DOT TONE MARK..HANGUL DOUBLE DOT TONE MARK -3099..309A ; Extend # Mn [2] COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK..COMBINING KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK -A66F ; Extend # Mn COMBINING CYRILLIC VZMET -A670..A672 ; Extend # Me [3] COMBINING CYRILLIC TEN MILLIONS SIGN..COMBINING CYRILLIC THOUSAND MILLIONS SIGN -A674..A67D ; Extend # Mn [10] COMBINING CYRILLIC LETTER UKRAINIAN IE..COMBINING CYRILLIC PAYEROK -A69E..A69F ; Extend # Mn [2] COMBINING CYRILLIC LETTER EF..COMBINING CYRILLIC LETTER IOTIFIED E -A6F0..A6F1 ; Extend # Mn [2] BAMUM COMBINING MARK KOQNDON..BAMUM COMBINING MARK TUKWENTIS -A802 ; Extend # Mn SYLOTI NAGRI SIGN DVISVARA -A806 ; Extend # Mn SYLOTI NAGRI SIGN HASANTA -A80B ; Extend # Mn SYLOTI NAGRI SIGN ANUSVARA -A825..A826 ; Extend # Mn [2] SYLOTI NAGRI VOWEL SIGN U..SYLOTI NAGRI VOWEL SIGN E -A8C4 ; Extend # Mn SAURASHTRA SIGN VIRAMA -A8E0..A8F1 ; Extend # Mn [18] COMBINING DEVANAGARI DIGIT ZERO..COMBINING DEVANAGARI SIGN AVAGRAHA -A926..A92D ; Extend # Mn [8] KAYAH LI VOWEL UE..KAYAH LI TONE CALYA PLOPHU -A947..A951 ; Extend # Mn [11] REJANG VOWEL SIGN I..REJANG CONSONANT SIGN R -A980..A982 ; Extend # Mn [3] JAVANESE SIGN PANYANGGA..JAVANESE SIGN LAYAR -A9B3 ; Extend # Mn JAVANESE SIGN CECAK TELU -A9B6..A9B9 ; Extend # Mn [4] JAVANESE VOWEL SIGN WULU..JAVANESE VOWEL SIGN SUKU MENDUT -A9BC ; Extend # Mn JAVANESE VOWEL SIGN PEPET -A9E5 ; Extend # Mn MYANMAR SIGN SHAN SAW -AA29..AA2E ; Extend # Mn [6] CHAM VOWEL SIGN AA..CHAM VOWEL SIGN OE -AA31..AA32 ; Extend # Mn [2] CHAM VOWEL SIGN AU..CHAM VOWEL SIGN UE -AA35..AA36 ; Extend # Mn [2] CHAM CONSONANT SIGN LA..CHAM CONSONANT SIGN WA -AA43 ; Extend # Mn CHAM CONSONANT SIGN FINAL NG -AA4C ; Extend # Mn CHAM CONSONANT SIGN FINAL M -AA7C ; Extend # Mn MYANMAR SIGN TAI LAING TONE-2 -AAB0 ; Extend # Mn TAI VIET MAI KANG -AAB2..AAB4 ; Extend # Mn [3] TAI VIET VOWEL I..TAI VIET VOWEL U -AAB7..AAB8 ; Extend # Mn [2] TAI VIET MAI KHIT..TAI VIET VOWEL IA -AABE..AABF ; Extend # Mn [2] TAI VIET VOWEL AM..TAI VIET TONE MAI EK -AAC1 ; Extend # Mn TAI VIET TONE MAI THO -AAEC..AAED ; Extend # Mn [2] MEETEI MAYEK VOWEL SIGN UU..MEETEI MAYEK VOWEL SIGN AAI -AAF6 ; Extend # Mn MEETEI MAYEK VIRAMA -ABE5 ; Extend # Mn MEETEI MAYEK VOWEL SIGN ANAP -ABE8 ; Extend # Mn MEETEI MAYEK VOWEL SIGN UNAP -ABED ; Extend # Mn MEETEI MAYEK APUN IYEK -FB1E ; Extend # Mn HEBREW POINT JUDEO-SPANISH VARIKA -FE00..FE0F ; Extend # Mn [16] VARIATION SELECTOR-1..VARIATION SELECTOR-16 -FE20..FE2F ; Extend # Mn [16] COMBINING LIGATURE LEFT HALF..COMBINING CYRILLIC TITLO RIGHT HALF -FF9E..FF9F ; Extend # Lm [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDTH KATAKANA SEMI-VOICED SOUND MARK -101FD ; Extend # Mn PHAISTOS DISC SIGN COMBINING OBLIQUE STROKE -102E0 ; Extend # Mn COPTIC EPACT THOUSANDS MARK -10376..1037A ; Extend # Mn [5] COMBINING OLD PERMIC LETTER AN..COMBINING OLD PERMIC LETTER SII -10A01..10A03 ; Extend # Mn [3] KHAROSHTHI VOWEL SIGN I..KHAROSHTHI VOWEL SIGN VOCALIC R -10A05..10A06 ; Extend # Mn [2] KHAROSHTHI VOWEL SIGN E..KHAROSHTHI VOWEL SIGN O -10A0C..10A0F ; Extend # Mn [4] KHAROSHTHI VOWEL LENGTH MARK..KHAROSHTHI SIGN VISARGA -10A38..10A3A ; Extend # Mn [3] KHAROSHTHI SIGN BAR ABOVE..KHAROSHTHI SIGN DOT BELOW -10A3F ; Extend # Mn KHAROSHTHI VIRAMA -10AE5..10AE6 ; Extend # Mn [2] MANICHAEAN ABBREVIATION MARK ABOVE..MANICHAEAN ABBREVIATION MARK BELOW -11001 ; Extend # Mn BRAHMI SIGN ANUSVARA -11038..11046 ; Extend # Mn [15] BRAHMI VOWEL SIGN AA..BRAHMI VIRAMA -1107F..11081 ; Extend # Mn [3] BRAHMI NUMBER JOINER..KAITHI SIGN ANUSVARA -110B3..110B6 ; Extend # Mn [4] KAITHI VOWEL SIGN U..KAITHI VOWEL SIGN AI -110B9..110BA ; Extend # Mn [2] KAITHI SIGN VIRAMA..KAITHI SIGN NUKTA -11100..11102 ; Extend # Mn [3] CHAKMA SIGN CANDRABINDU..CHAKMA SIGN VISARGA -11127..1112B ; Extend # Mn [5] CHAKMA VOWEL SIGN A..CHAKMA VOWEL SIGN UU -1112D..11134 ; Extend # Mn [8] CHAKMA VOWEL SIGN AI..CHAKMA MAAYYAA -11173 ; Extend # Mn MAHAJANI SIGN NUKTA -11180..11181 ; Extend # Mn [2] SHARADA SIGN CANDRABINDU..SHARADA SIGN ANUSVARA -111B6..111BE ; Extend # Mn [9] SHARADA VOWEL SIGN U..SHARADA VOWEL SIGN O -111CA..111CC ; Extend # Mn [3] SHARADA SIGN NUKTA..SHARADA EXTRA SHORT VOWEL MARK -1122F..11231 ; Extend # Mn [3] KHOJKI VOWEL SIGN U..KHOJKI VOWEL SIGN AI -11234 ; Extend # Mn KHOJKI SIGN ANUSVARA -11236..11237 ; Extend # Mn [2] KHOJKI SIGN NUKTA..KHOJKI SIGN SHADDA -112DF ; Extend # Mn KHUDAWADI SIGN ANUSVARA -112E3..112EA ; Extend # Mn [8] KHUDAWADI VOWEL SIGN U..KHUDAWADI SIGN VIRAMA -11300..11301 ; Extend # Mn [2] GRANTHA SIGN COMBINING ANUSVARA ABOVE..GRANTHA SIGN CANDRABINDU -1133C ; Extend # Mn GRANTHA SIGN NUKTA -1133E ; Extend # Mc GRANTHA VOWEL SIGN AA -11340 ; Extend # Mn GRANTHA VOWEL SIGN II -11357 ; Extend # Mc GRANTHA AU LENGTH MARK -11366..1136C ; Extend # Mn [7] COMBINING GRANTHA DIGIT ZERO..COMBINING GRANTHA DIGIT SIX -11370..11374 ; Extend # Mn [5] COMBINING GRANTHA LETTER A..COMBINING GRANTHA LETTER PA -114B0 ; Extend # Mc TIRHUTA VOWEL SIGN AA -114B3..114B8 ; Extend # Mn [6] TIRHUTA VOWEL SIGN U..TIRHUTA VOWEL SIGN VOCALIC LL -114BA ; Extend # Mn TIRHUTA VOWEL SIGN SHORT E -114BD ; Extend # Mc TIRHUTA VOWEL SIGN SHORT O -114BF..114C0 ; Extend # Mn [2] TIRHUTA SIGN CANDRABINDU..TIRHUTA SIGN ANUSVARA -114C2..114C3 ; Extend # Mn [2] TIRHUTA SIGN VIRAMA..TIRHUTA SIGN NUKTA -115AF ; Extend # Mc SIDDHAM VOWEL SIGN AA -115B2..115B5 ; Extend # Mn [4] SIDDHAM VOWEL SIGN U..SIDDHAM VOWEL SIGN VOCALIC RR -115BC..115BD ; Extend # Mn [2] SIDDHAM SIGN CANDRABINDU..SIDDHAM SIGN ANUSVARA -115BF..115C0 ; Extend # Mn [2] SIDDHAM SIGN VIRAMA..SIDDHAM SIGN NUKTA -115DC..115DD ; Extend # Mn [2] SIDDHAM VOWEL SIGN ALTERNATE U..SIDDHAM VOWEL SIGN ALTERNATE UU -11633..1163A ; Extend # Mn [8] MODI VOWEL SIGN U..MODI VOWEL SIGN AI -1163D ; Extend # Mn MODI SIGN ANUSVARA -1163F..11640 ; Extend # Mn [2] MODI SIGN VIRAMA..MODI SIGN ARDHACANDRA -116AB ; Extend # Mn TAKRI SIGN ANUSVARA -116AD ; Extend # Mn TAKRI VOWEL SIGN AA -116B0..116B5 ; Extend # Mn [6] TAKRI VOWEL SIGN U..TAKRI VOWEL SIGN AU -116B7 ; Extend # Mn TAKRI SIGN NUKTA -1171D..1171F ; Extend # Mn [3] AHOM CONSONANT SIGN MEDIAL LA..AHOM CONSONANT SIGN MEDIAL LIGATING RA -11722..11725 ; Extend # Mn [4] AHOM VOWEL SIGN I..AHOM VOWEL SIGN UU -11727..1172B ; Extend # Mn [5] AHOM VOWEL SIGN AW..AHOM SIGN KILLER -16AF0..16AF4 ; Extend # Mn [5] BASSA VAH COMBINING HIGH TONE..BASSA VAH COMBINING HIGH-LOW TONE -16B30..16B36 ; Extend # Mn [7] PAHAWH HMONG MARK CIM TUB..PAHAWH HMONG MARK CIM TAUM -16F8F..16F92 ; Extend # Mn [4] MIAO TONE RIGHT..MIAO TONE BELOW -1BC9D..1BC9E ; Extend # Mn [2] DUPLOYAN THICK LETTER SELECTOR..DUPLOYAN DOUBLE MARK -1D165 ; Extend # Mc MUSICAL SYMBOL COMBINING STEM -1D167..1D169 ; Extend # Mn [3] MUSICAL SYMBOL COMBINING TREMOLO-1..MUSICAL SYMBOL COMBINING TREMOLO-3 -1D16E..1D172 ; Extend # Mc [5] MUSICAL SYMBOL COMBINING FLAG-1..MUSICAL SYMBOL COMBINING FLAG-5 -1D17B..1D182 ; Extend # Mn [8] MUSICAL SYMBOL COMBINING ACCENT..MUSICAL SYMBOL COMBINING LOURE -1D185..1D18B ; Extend # Mn [7] MUSICAL SYMBOL COMBINING DOIT..MUSICAL SYMBOL COMBINING TRIPLE TONGUE -1D1AA..1D1AD ; Extend # Mn [4] MUSICAL SYMBOL COMBINING DOWN BOW..MUSICAL SYMBOL COMBINING SNAP PIZZICATO -1D242..1D244 ; Extend # Mn [3] COMBINING GREEK MUSICAL TRISEME..COMBINING GREEK MUSICAL PENTASEME -1DA00..1DA36 ; Extend # Mn [55] SIGNWRITING HEAD RIM..SIGNWRITING AIR SUCKING IN -1DA3B..1DA6C ; Extend # Mn [50] SIGNWRITING MOUTH CLOSED NEUTRAL..SIGNWRITING EXCITEMENT -1DA75 ; Extend # Mn SIGNWRITING UPPER BODY TILTING FROM HIP JOINTS -1DA84 ; Extend # Mn SIGNWRITING LOCATION HEAD NECK -1DA9B..1DA9F ; Extend # Mn [5] SIGNWRITING FILL MODIFIER-2..SIGNWRITING FILL MODIFIER-6 -1DAA1..1DAAF ; Extend # Mn [15] SIGNWRITING ROTATION MODIFIER-2..SIGNWRITING ROTATION MODIFIER-16 -1E8D0..1E8D6 ; Extend # Mn [7] MENDE KIKAKUI COMBINING NUMBER TEENS..MENDE KIKAKUI COMBINING NUMBER MILLIONS -E0100..E01EF ; Extend # Mn [240] VARIATION SELECTOR-17..VARIATION SELECTOR-256 - -# Total code points: 1610 - -# ================================================ - -1F1E6..1F1FF ; Regional_Indicator # So [26] REGIONAL INDICATOR SYMBOL LETTER A..REGIONAL INDICATOR SYMBOL LETTER Z - -# Total code points: 26 - -# ================================================ - -0903 ; SpacingMark # Mc DEVANAGARI SIGN VISARGA -093B ; SpacingMark # Mc DEVANAGARI VOWEL SIGN OOE -093E..0940 ; SpacingMark # Mc [3] DEVANAGARI VOWEL SIGN AA..DEVANAGARI VOWEL SIGN II -0949..094C ; SpacingMark # Mc [4] DEVANAGARI VOWEL SIGN CANDRA O..DEVANAGARI VOWEL SIGN AU -094E..094F ; SpacingMark # Mc [2] DEVANAGARI VOWEL SIGN PRISHTHAMATRA E..DEVANAGARI VOWEL SIGN AW -0982..0983 ; SpacingMark # Mc [2] BENGALI SIGN ANUSVARA..BENGALI SIGN VISARGA -09BF..09C0 ; SpacingMark # Mc [2] BENGALI VOWEL SIGN I..BENGALI VOWEL SIGN II -09C7..09C8 ; SpacingMark # Mc [2] BENGALI VOWEL SIGN E..BENGALI VOWEL SIGN AI -09CB..09CC ; SpacingMark # Mc [2] BENGALI VOWEL SIGN O..BENGALI VOWEL SIGN AU -0A03 ; SpacingMark # Mc GURMUKHI SIGN VISARGA -0A3E..0A40 ; SpacingMark # Mc [3] GURMUKHI VOWEL SIGN AA..GURMUKHI VOWEL SIGN II -0A83 ; SpacingMark # Mc GUJARATI SIGN VISARGA -0ABE..0AC0 ; SpacingMark # Mc [3] GUJARATI VOWEL SIGN AA..GUJARATI VOWEL SIGN II -0AC9 ; SpacingMark # Mc GUJARATI VOWEL SIGN CANDRA O -0ACB..0ACC ; SpacingMark # Mc [2] GUJARATI VOWEL SIGN O..GUJARATI VOWEL SIGN AU -0B02..0B03 ; SpacingMark # Mc [2] ORIYA SIGN ANUSVARA..ORIYA SIGN VISARGA -0B40 ; SpacingMark # Mc ORIYA VOWEL SIGN II -0B47..0B48 ; SpacingMark # Mc [2] ORIYA VOWEL SIGN E..ORIYA VOWEL SIGN AI -0B4B..0B4C ; SpacingMark # Mc [2] ORIYA VOWEL SIGN O..ORIYA VOWEL SIGN AU -0BBF ; SpacingMark # Mc TAMIL VOWEL SIGN I -0BC1..0BC2 ; SpacingMark # Mc [2] TAMIL VOWEL SIGN U..TAMIL VOWEL SIGN UU -0BC6..0BC8 ; SpacingMark # Mc [3] TAMIL VOWEL SIGN E..TAMIL VOWEL SIGN AI -0BCA..0BCC ; SpacingMark # Mc [3] TAMIL VOWEL SIGN O..TAMIL VOWEL SIGN AU -0C01..0C03 ; SpacingMark # Mc [3] TELUGU SIGN CANDRABINDU..TELUGU SIGN VISARGA -0C41..0C44 ; SpacingMark # Mc [4] TELUGU VOWEL SIGN U..TELUGU VOWEL SIGN VOCALIC RR -0C82..0C83 ; SpacingMark # Mc [2] KANNADA SIGN ANUSVARA..KANNADA SIGN VISARGA -0CBE ; SpacingMark # Mc KANNADA VOWEL SIGN AA -0CC0..0CC1 ; SpacingMark # Mc [2] KANNADA VOWEL SIGN II..KANNADA VOWEL SIGN U -0CC3..0CC4 ; SpacingMark # Mc [2] KANNADA VOWEL SIGN VOCALIC R..KANNADA VOWEL SIGN VOCALIC RR -0CC7..0CC8 ; SpacingMark # Mc [2] KANNADA VOWEL SIGN EE..KANNADA VOWEL SIGN AI -0CCA..0CCB ; SpacingMark # Mc [2] KANNADA VOWEL SIGN O..KANNADA VOWEL SIGN OO -0D02..0D03 ; SpacingMark # Mc [2] MALAYALAM SIGN ANUSVARA..MALAYALAM SIGN VISARGA -0D3F..0D40 ; SpacingMark # Mc [2] MALAYALAM VOWEL SIGN I..MALAYALAM VOWEL SIGN II -0D46..0D48 ; SpacingMark # Mc [3] MALAYALAM VOWEL SIGN E..MALAYALAM VOWEL SIGN AI -0D4A..0D4C ; SpacingMark # Mc [3] MALAYALAM VOWEL SIGN O..MALAYALAM VOWEL SIGN AU -0D82..0D83 ; SpacingMark # Mc [2] SINHALA SIGN ANUSVARAYA..SINHALA SIGN VISARGAYA -0DD0..0DD1 ; SpacingMark # Mc [2] SINHALA VOWEL SIGN KETTI AEDA-PILLA..SINHALA VOWEL SIGN DIGA AEDA-PILLA -0DD8..0DDE ; SpacingMark # Mc [7] SINHALA VOWEL SIGN GAETTA-PILLA..SINHALA VOWEL SIGN KOMBUVA HAA GAYANUKITTA -0DF2..0DF3 ; SpacingMark # Mc [2] SINHALA VOWEL SIGN DIGA GAETTA-PILLA..SINHALA VOWEL SIGN DIGA GAYANUKITTA -0E33 ; SpacingMark # Lo THAI CHARACTER SARA AM -0EB3 ; SpacingMark # Lo LAO VOWEL SIGN AM -0F3E..0F3F ; SpacingMark # Mc [2] TIBETAN SIGN YAR TSHES..TIBETAN SIGN MAR TSHES -0F7F ; SpacingMark # Mc TIBETAN SIGN RNAM BCAD -1031 ; SpacingMark # Mc MYANMAR VOWEL SIGN E -103B..103C ; SpacingMark # Mc [2] MYANMAR CONSONANT SIGN MEDIAL YA..MYANMAR CONSONANT SIGN MEDIAL RA -1056..1057 ; SpacingMark # Mc [2] MYANMAR VOWEL SIGN VOCALIC R..MYANMAR VOWEL SIGN VOCALIC RR -1084 ; SpacingMark # Mc MYANMAR VOWEL SIGN SHAN E -17B6 ; SpacingMark # Mc KHMER VOWEL SIGN AA -17BE..17C5 ; SpacingMark # Mc [8] KHMER VOWEL SIGN OE..KHMER VOWEL SIGN AU -17C7..17C8 ; SpacingMark # Mc [2] KHMER SIGN REAHMUK..KHMER SIGN YUUKALEAPINTU -1923..1926 ; SpacingMark # Mc [4] LIMBU VOWEL SIGN EE..LIMBU VOWEL SIGN AU -1929..192B ; SpacingMark # Mc [3] LIMBU SUBJOINED LETTER YA..LIMBU SUBJOINED LETTER WA -1930..1931 ; SpacingMark # Mc [2] LIMBU SMALL LETTER KA..LIMBU SMALL LETTER NGA -1933..1938 ; SpacingMark # Mc [6] LIMBU SMALL LETTER TA..LIMBU SMALL LETTER LA -1A19..1A1A ; SpacingMark # Mc [2] BUGINESE VOWEL SIGN E..BUGINESE VOWEL SIGN O -1A55 ; SpacingMark # Mc TAI THAM CONSONANT SIGN MEDIAL RA -1A57 ; SpacingMark # Mc TAI THAM CONSONANT SIGN LA TANG LAI -1A6D..1A72 ; SpacingMark # Mc [6] TAI THAM VOWEL SIGN OY..TAI THAM VOWEL SIGN THAM AI -1B04 ; SpacingMark # Mc BALINESE SIGN BISAH -1B35 ; SpacingMark # Mc BALINESE VOWEL SIGN TEDUNG -1B3B ; SpacingMark # Mc BALINESE VOWEL SIGN RA REPA TEDUNG -1B3D..1B41 ; SpacingMark # Mc [5] BALINESE VOWEL SIGN LA LENGA TEDUNG..BALINESE VOWEL SIGN TALING REPA TEDUNG -1B43..1B44 ; SpacingMark # Mc [2] BALINESE VOWEL SIGN PEPET TEDUNG..BALINESE ADEG ADEG -1B82 ; SpacingMark # Mc SUNDANESE SIGN PANGWISAD -1BA1 ; SpacingMark # Mc SUNDANESE CONSONANT SIGN PAMINGKAL -1BA6..1BA7 ; SpacingMark # Mc [2] SUNDANESE VOWEL SIGN PANAELAENG..SUNDANESE VOWEL SIGN PANOLONG -1BAA ; SpacingMark # Mc SUNDANESE SIGN PAMAAEH -1BE7 ; SpacingMark # Mc BATAK VOWEL SIGN E -1BEA..1BEC ; SpacingMark # Mc [3] BATAK VOWEL SIGN I..BATAK VOWEL SIGN O -1BEE ; SpacingMark # Mc BATAK VOWEL SIGN U -1BF2..1BF3 ; SpacingMark # Mc [2] BATAK PANGOLAT..BATAK PANONGONAN -1C24..1C2B ; SpacingMark # Mc [8] LEPCHA SUBJOINED LETTER YA..LEPCHA VOWEL SIGN UU -1C34..1C35 ; SpacingMark # Mc [2] LEPCHA CONSONANT SIGN NYIN-DO..LEPCHA CONSONANT SIGN KANG -1CE1 ; SpacingMark # Mc VEDIC TONE ATHARVAVEDIC INDEPENDENT SVARITA -1CF2..1CF3 ; SpacingMark # Mc [2] VEDIC SIGN ARDHAVISARGA..VEDIC SIGN ROTATED ARDHAVISARGA -A823..A824 ; SpacingMark # Mc [2] SYLOTI NAGRI VOWEL SIGN A..SYLOTI NAGRI VOWEL SIGN I -A827 ; SpacingMark # Mc SYLOTI NAGRI VOWEL SIGN OO -A880..A881 ; SpacingMark # Mc [2] SAURASHTRA SIGN ANUSVARA..SAURASHTRA SIGN VISARGA -A8B4..A8C3 ; SpacingMark # Mc [16] SAURASHTRA CONSONANT SIGN HAARU..SAURASHTRA VOWEL SIGN AU -A952..A953 ; SpacingMark # Mc [2] REJANG CONSONANT SIGN H..REJANG VIRAMA -A983 ; SpacingMark # Mc JAVANESE SIGN WIGNYAN -A9B4..A9B5 ; SpacingMark # Mc [2] JAVANESE VOWEL SIGN TARUNG..JAVANESE VOWEL SIGN TOLONG -A9BA..A9BB ; SpacingMark # Mc [2] JAVANESE VOWEL SIGN TALING..JAVANESE VOWEL SIGN DIRGA MURE -A9BD..A9C0 ; SpacingMark # Mc [4] JAVANESE CONSONANT SIGN KERET..JAVANESE PANGKON -AA2F..AA30 ; SpacingMark # Mc [2] CHAM VOWEL SIGN O..CHAM VOWEL SIGN AI -AA33..AA34 ; SpacingMark # Mc [2] CHAM CONSONANT SIGN YA..CHAM CONSONANT SIGN RA -AA4D ; SpacingMark # Mc CHAM CONSONANT SIGN FINAL H -AAEB ; SpacingMark # Mc MEETEI MAYEK VOWEL SIGN II -AAEE..AAEF ; SpacingMark # Mc [2] MEETEI MAYEK VOWEL SIGN AU..MEETEI MAYEK VOWEL SIGN AAU -AAF5 ; SpacingMark # Mc MEETEI MAYEK VOWEL SIGN VISARGA -ABE3..ABE4 ; SpacingMark # Mc [2] MEETEI MAYEK VOWEL SIGN ONAP..MEETEI MAYEK VOWEL SIGN INAP -ABE6..ABE7 ; SpacingMark # Mc [2] MEETEI MAYEK VOWEL SIGN YENAP..MEETEI MAYEK VOWEL SIGN SOUNAP -ABE9..ABEA ; SpacingMark # Mc [2] MEETEI MAYEK VOWEL SIGN CHEINAP..MEETEI MAYEK VOWEL SIGN NUNG -ABEC ; SpacingMark # Mc MEETEI MAYEK LUM IYEK -11000 ; SpacingMark # Mc BRAHMI SIGN CANDRABINDU -11002 ; SpacingMark # Mc BRAHMI SIGN VISARGA -11082 ; SpacingMark # Mc KAITHI SIGN VISARGA -110B0..110B2 ; SpacingMark # Mc [3] KAITHI VOWEL SIGN AA..KAITHI VOWEL SIGN II -110B7..110B8 ; SpacingMark # Mc [2] KAITHI VOWEL SIGN O..KAITHI VOWEL SIGN AU -1112C ; SpacingMark # Mc CHAKMA VOWEL SIGN E -11182 ; SpacingMark # Mc SHARADA SIGN VISARGA -111B3..111B5 ; SpacingMark # Mc [3] SHARADA VOWEL SIGN AA..SHARADA VOWEL SIGN II -111BF..111C0 ; SpacingMark # Mc [2] SHARADA VOWEL SIGN AU..SHARADA SIGN VIRAMA -1122C..1122E ; SpacingMark # Mc [3] KHOJKI VOWEL SIGN AA..KHOJKI VOWEL SIGN II -11232..11233 ; SpacingMark # Mc [2] KHOJKI VOWEL SIGN O..KHOJKI VOWEL SIGN AU -11235 ; SpacingMark # Mc KHOJKI SIGN VIRAMA -112E0..112E2 ; SpacingMark # Mc [3] KHUDAWADI VOWEL SIGN AA..KHUDAWADI VOWEL SIGN II -11302..11303 ; SpacingMark # Mc [2] GRANTHA SIGN ANUSVARA..GRANTHA SIGN VISARGA -1133F ; SpacingMark # Mc GRANTHA VOWEL SIGN I -11341..11344 ; SpacingMark # Mc [4] GRANTHA VOWEL SIGN U..GRANTHA VOWEL SIGN VOCALIC RR -11347..11348 ; SpacingMark # Mc [2] GRANTHA VOWEL SIGN EE..GRANTHA VOWEL SIGN AI -1134B..1134D ; SpacingMark # Mc [3] GRANTHA VOWEL SIGN OO..GRANTHA SIGN VIRAMA -11362..11363 ; SpacingMark # Mc [2] GRANTHA VOWEL SIGN VOCALIC L..GRANTHA VOWEL SIGN VOCALIC LL -114B1..114B2 ; SpacingMark # Mc [2] TIRHUTA VOWEL SIGN I..TIRHUTA VOWEL SIGN II -114B9 ; SpacingMark # Mc TIRHUTA VOWEL SIGN E -114BB..114BC ; SpacingMark # Mc [2] TIRHUTA VOWEL SIGN AI..TIRHUTA VOWEL SIGN O -114BE ; SpacingMark # Mc TIRHUTA VOWEL SIGN AU -114C1 ; SpacingMark # Mc TIRHUTA SIGN VISARGA -115B0..115B1 ; SpacingMark # Mc [2] SIDDHAM VOWEL SIGN I..SIDDHAM VOWEL SIGN II -115B8..115BB ; SpacingMark # Mc [4] SIDDHAM VOWEL SIGN E..SIDDHAM VOWEL SIGN AU -115BE ; SpacingMark # Mc SIDDHAM SIGN VISARGA -11630..11632 ; SpacingMark # Mc [3] MODI VOWEL SIGN AA..MODI VOWEL SIGN II -1163B..1163C ; SpacingMark # Mc [2] MODI VOWEL SIGN O..MODI VOWEL SIGN AU -1163E ; SpacingMark # Mc MODI SIGN VISARGA -116AC ; SpacingMark # Mc TAKRI SIGN VISARGA -116AE..116AF ; SpacingMark # Mc [2] TAKRI VOWEL SIGN I..TAKRI VOWEL SIGN II -116B6 ; SpacingMark # Mc TAKRI SIGN VIRAMA -11720..11721 ; SpacingMark # Mc [2] AHOM VOWEL SIGN A..AHOM VOWEL SIGN AA -11726 ; SpacingMark # Mc AHOM VOWEL SIGN E -16F51..16F7E ; SpacingMark # Mc [46] MIAO SIGN ASPIRATION..MIAO VOWEL SIGN NG -1D166 ; SpacingMark # Mc MUSICAL SYMBOL COMBINING SPRECHGESANG STEM -1D16D ; SpacingMark # Mc MUSICAL SYMBOL COMBINING AUGMENTATION DOT - -# Total code points: 330 - -# ================================================ - -1100..115F ; L # Lo [96] HANGUL CHOSEONG KIYEOK..HANGUL CHOSEONG FILLER -A960..A97C ; L # Lo [29] HANGUL CHOSEONG TIKEUT-MIEUM..HANGUL CHOSEONG SSANGYEORINHIEUH - -# Total code points: 125 - -# ================================================ - -1160..11A7 ; V # Lo [72] HANGUL JUNGSEONG FILLER..HANGUL JUNGSEONG O-YAE -D7B0..D7C6 ; V # Lo [23] HANGUL JUNGSEONG O-YEO..HANGUL JUNGSEONG ARAEA-E - -# Total code points: 95 - -# ================================================ - -11A8..11FF ; T # Lo [88] HANGUL JONGSEONG KIYEOK..HANGUL JONGSEONG SSANGNIEUN -D7CB..D7FB ; T # Lo [49] HANGUL JONGSEONG NIEUN-RIEUL..HANGUL JONGSEONG PHIEUPH-THIEUTH - -# Total code points: 137 - -# ================================================ - -AC00 ; LV # Lo HANGUL SYLLABLE GA -AC1C ; LV # Lo HANGUL SYLLABLE GAE -AC38 ; LV # Lo HANGUL SYLLABLE GYA -AC54 ; LV # Lo HANGUL SYLLABLE GYAE -AC70 ; LV # Lo HANGUL SYLLABLE GEO -AC8C ; LV # Lo HANGUL SYLLABLE GE -ACA8 ; LV # Lo HANGUL SYLLABLE GYEO -ACC4 ; LV # Lo HANGUL SYLLABLE GYE -ACE0 ; LV # Lo HANGUL SYLLABLE GO -ACFC ; LV # Lo HANGUL SYLLABLE GWA -AD18 ; LV # Lo HANGUL SYLLABLE GWAE -AD34 ; LV # Lo HANGUL SYLLABLE GOE -AD50 ; LV # Lo HANGUL SYLLABLE GYO -AD6C ; LV # Lo HANGUL SYLLABLE GU -AD88 ; LV # Lo HANGUL SYLLABLE GWEO -ADA4 ; LV # Lo HANGUL SYLLABLE GWE -ADC0 ; LV # Lo HANGUL SYLLABLE GWI -ADDC ; LV # Lo HANGUL SYLLABLE GYU -ADF8 ; LV # Lo HANGUL SYLLABLE GEU -AE14 ; LV # Lo HANGUL SYLLABLE GYI -AE30 ; LV # Lo HANGUL SYLLABLE GI -AE4C ; LV # Lo HANGUL SYLLABLE GGA -AE68 ; LV # Lo HANGUL SYLLABLE GGAE -AE84 ; LV # Lo HANGUL SYLLABLE GGYA -AEA0 ; LV # Lo HANGUL SYLLABLE GGYAE -AEBC ; LV # Lo HANGUL SYLLABLE GGEO -AED8 ; LV # Lo HANGUL SYLLABLE GGE -AEF4 ; LV # Lo HANGUL SYLLABLE GGYEO -AF10 ; LV # Lo HANGUL SYLLABLE GGYE -AF2C ; LV # Lo HANGUL SYLLABLE GGO -AF48 ; LV # Lo HANGUL SYLLABLE GGWA -AF64 ; LV # Lo HANGUL SYLLABLE GGWAE -AF80 ; LV # Lo HANGUL SYLLABLE GGOE -AF9C ; LV # Lo HANGUL SYLLABLE GGYO -AFB8 ; LV # Lo HANGUL SYLLABLE GGU -AFD4 ; LV # Lo HANGUL SYLLABLE GGWEO -AFF0 ; LV # Lo HANGUL SYLLABLE GGWE -B00C ; LV # Lo HANGUL SYLLABLE GGWI -B028 ; LV # Lo HANGUL SYLLABLE GGYU -B044 ; LV # Lo HANGUL SYLLABLE GGEU -B060 ; LV # Lo HANGUL SYLLABLE GGYI -B07C ; LV # Lo HANGUL SYLLABLE GGI -B098 ; LV # Lo HANGUL SYLLABLE NA -B0B4 ; LV # Lo HANGUL SYLLABLE NAE -B0D0 ; LV # Lo HANGUL SYLLABLE NYA -B0EC ; LV # Lo HANGUL SYLLABLE NYAE -B108 ; LV # Lo HANGUL SYLLABLE NEO -B124 ; LV # Lo HANGUL SYLLABLE NE -B140 ; LV # Lo HANGUL SYLLABLE NYEO -B15C ; LV # Lo HANGUL SYLLABLE NYE -B178 ; LV # Lo HANGUL SYLLABLE NO -B194 ; LV # Lo HANGUL SYLLABLE NWA -B1B0 ; LV # Lo HANGUL SYLLABLE NWAE -B1CC ; LV # Lo HANGUL SYLLABLE NOE -B1E8 ; LV # Lo HANGUL SYLLABLE NYO -B204 ; LV # Lo HANGUL SYLLABLE NU -B220 ; LV # Lo HANGUL SYLLABLE NWEO -B23C ; LV # Lo HANGUL SYLLABLE NWE -B258 ; LV # Lo HANGUL SYLLABLE NWI -B274 ; LV # Lo HANGUL SYLLABLE NYU -B290 ; LV # Lo HANGUL SYLLABLE NEU -B2AC ; LV # Lo HANGUL SYLLABLE NYI -B2C8 ; LV # Lo HANGUL SYLLABLE NI -B2E4 ; LV # Lo HANGUL SYLLABLE DA -B300 ; LV # Lo HANGUL SYLLABLE DAE -B31C ; LV # Lo HANGUL SYLLABLE DYA -B338 ; LV # Lo HANGUL SYLLABLE DYAE -B354 ; LV # Lo HANGUL SYLLABLE DEO -B370 ; LV # Lo HANGUL SYLLABLE DE -B38C ; LV # Lo HANGUL SYLLABLE DYEO -B3A8 ; LV # Lo HANGUL SYLLABLE DYE -B3C4 ; LV # Lo HANGUL SYLLABLE DO -B3E0 ; LV # Lo HANGUL SYLLABLE DWA -B3FC ; LV # Lo HANGUL SYLLABLE DWAE -B418 ; LV # Lo HANGUL SYLLABLE DOE -B434 ; LV # Lo HANGUL SYLLABLE DYO -B450 ; LV # Lo HANGUL SYLLABLE DU -B46C ; LV # Lo HANGUL SYLLABLE DWEO -B488 ; LV # Lo HANGUL SYLLABLE DWE -B4A4 ; LV # Lo HANGUL SYLLABLE DWI -B4C0 ; LV # Lo HANGUL SYLLABLE DYU -B4DC ; LV # Lo HANGUL SYLLABLE DEU -B4F8 ; LV # Lo HANGUL SYLLABLE DYI -B514 ; LV # Lo HANGUL SYLLABLE DI -B530 ; LV # Lo HANGUL SYLLABLE DDA -B54C ; LV # Lo HANGUL SYLLABLE DDAE -B568 ; LV # Lo HANGUL SYLLABLE DDYA -B584 ; LV # Lo HANGUL SYLLABLE DDYAE -B5A0 ; LV # Lo HANGUL SYLLABLE DDEO -B5BC ; LV # Lo HANGUL SYLLABLE DDE -B5D8 ; LV # Lo HANGUL SYLLABLE DDYEO -B5F4 ; LV # Lo HANGUL SYLLABLE DDYE -B610 ; LV # Lo HANGUL SYLLABLE DDO -B62C ; LV # Lo HANGUL SYLLABLE DDWA -B648 ; LV # Lo HANGUL SYLLABLE DDWAE -B664 ; LV # Lo HANGUL SYLLABLE DDOE -B680 ; LV # Lo HANGUL SYLLABLE DDYO -B69C ; LV # Lo HANGUL SYLLABLE DDU -B6B8 ; LV # Lo HANGUL SYLLABLE DDWEO -B6D4 ; LV # Lo HANGUL SYLLABLE DDWE -B6F0 ; LV # Lo HANGUL SYLLABLE DDWI -B70C ; LV # Lo HANGUL SYLLABLE DDYU -B728 ; LV # Lo HANGUL SYLLABLE DDEU -B744 ; LV # Lo HANGUL SYLLABLE DDYI -B760 ; LV # Lo HANGUL SYLLABLE DDI -B77C ; LV # Lo HANGUL SYLLABLE RA -B798 ; LV # Lo HANGUL SYLLABLE RAE -B7B4 ; LV # Lo HANGUL SYLLABLE RYA -B7D0 ; LV # Lo HANGUL SYLLABLE RYAE -B7EC ; LV # Lo HANGUL SYLLABLE REO -B808 ; LV # Lo HANGUL SYLLABLE RE -B824 ; LV # Lo HANGUL SYLLABLE RYEO -B840 ; LV # Lo HANGUL SYLLABLE RYE -B85C ; LV # Lo HANGUL SYLLABLE RO -B878 ; LV # Lo HANGUL SYLLABLE RWA -B894 ; LV # Lo HANGUL SYLLABLE RWAE -B8B0 ; LV # Lo HANGUL SYLLABLE ROE -B8CC ; LV # Lo HANGUL SYLLABLE RYO -B8E8 ; LV # Lo HANGUL SYLLABLE RU -B904 ; LV # Lo HANGUL SYLLABLE RWEO -B920 ; LV # Lo HANGUL SYLLABLE RWE -B93C ; LV # Lo HANGUL SYLLABLE RWI -B958 ; LV # Lo HANGUL SYLLABLE RYU -B974 ; LV # Lo HANGUL SYLLABLE REU -B990 ; LV # Lo HANGUL SYLLABLE RYI -B9AC ; LV # Lo HANGUL SYLLABLE RI -B9C8 ; LV # Lo HANGUL SYLLABLE MA -B9E4 ; LV # Lo HANGUL SYLLABLE MAE -BA00 ; LV # Lo HANGUL SYLLABLE MYA -BA1C ; LV # Lo HANGUL SYLLABLE MYAE -BA38 ; LV # Lo HANGUL SYLLABLE MEO -BA54 ; LV # Lo HANGUL SYLLABLE ME -BA70 ; LV # Lo HANGUL SYLLABLE MYEO -BA8C ; LV # Lo HANGUL SYLLABLE MYE -BAA8 ; LV # Lo HANGUL SYLLABLE MO -BAC4 ; LV # Lo HANGUL SYLLABLE MWA -BAE0 ; LV # Lo HANGUL SYLLABLE MWAE -BAFC ; LV # Lo HANGUL SYLLABLE MOE -BB18 ; LV # Lo HANGUL SYLLABLE MYO -BB34 ; LV # Lo HANGUL SYLLABLE MU -BB50 ; LV # Lo HANGUL SYLLABLE MWEO -BB6C ; LV # Lo HANGUL SYLLABLE MWE -BB88 ; LV # Lo HANGUL SYLLABLE MWI -BBA4 ; LV # Lo HANGUL SYLLABLE MYU -BBC0 ; LV # Lo HANGUL SYLLABLE MEU -BBDC ; LV # Lo HANGUL SYLLABLE MYI -BBF8 ; LV # Lo HANGUL SYLLABLE MI -BC14 ; LV # Lo HANGUL SYLLABLE BA -BC30 ; LV # Lo HANGUL SYLLABLE BAE -BC4C ; LV # Lo HANGUL SYLLABLE BYA -BC68 ; LV # Lo HANGUL SYLLABLE BYAE -BC84 ; LV # Lo HANGUL SYLLABLE BEO -BCA0 ; LV # Lo HANGUL SYLLABLE BE -BCBC ; LV # Lo HANGUL SYLLABLE BYEO -BCD8 ; LV # Lo HANGUL SYLLABLE BYE -BCF4 ; LV # Lo HANGUL SYLLABLE BO -BD10 ; LV # Lo HANGUL SYLLABLE BWA -BD2C ; LV # Lo HANGUL SYLLABLE BWAE -BD48 ; LV # Lo HANGUL SYLLABLE BOE -BD64 ; LV # Lo HANGUL SYLLABLE BYO -BD80 ; LV # Lo HANGUL SYLLABLE BU -BD9C ; LV # Lo HANGUL SYLLABLE BWEO -BDB8 ; LV # Lo HANGUL SYLLABLE BWE -BDD4 ; LV # Lo HANGUL SYLLABLE BWI -BDF0 ; LV # Lo HANGUL SYLLABLE BYU -BE0C ; LV # Lo HANGUL SYLLABLE BEU -BE28 ; LV # Lo HANGUL SYLLABLE BYI -BE44 ; LV # Lo HANGUL SYLLABLE BI -BE60 ; LV # Lo HANGUL SYLLABLE BBA -BE7C ; LV # Lo HANGUL SYLLABLE BBAE -BE98 ; LV # Lo HANGUL SYLLABLE BBYA -BEB4 ; LV # Lo HANGUL SYLLABLE BBYAE -BED0 ; LV # Lo HANGUL SYLLABLE BBEO -BEEC ; LV # Lo HANGUL SYLLABLE BBE -BF08 ; LV # Lo HANGUL SYLLABLE BBYEO -BF24 ; LV # Lo HANGUL SYLLABLE BBYE -BF40 ; LV # Lo HANGUL SYLLABLE BBO -BF5C ; LV # Lo HANGUL SYLLABLE BBWA -BF78 ; LV # Lo HANGUL SYLLABLE BBWAE -BF94 ; LV # Lo HANGUL SYLLABLE BBOE -BFB0 ; LV # Lo HANGUL SYLLABLE BBYO -BFCC ; LV # Lo HANGUL SYLLABLE BBU -BFE8 ; LV # Lo HANGUL SYLLABLE BBWEO -C004 ; LV # Lo HANGUL SYLLABLE BBWE -C020 ; LV # Lo HANGUL SYLLABLE BBWI -C03C ; LV # Lo HANGUL SYLLABLE BBYU -C058 ; LV # Lo HANGUL SYLLABLE BBEU -C074 ; LV # Lo HANGUL SYLLABLE BBYI -C090 ; LV # Lo HANGUL SYLLABLE BBI -C0AC ; LV # Lo HANGUL SYLLABLE SA -C0C8 ; LV # Lo HANGUL SYLLABLE SAE -C0E4 ; LV # Lo HANGUL SYLLABLE SYA -C100 ; LV # Lo HANGUL SYLLABLE SYAE -C11C ; LV # Lo HANGUL SYLLABLE SEO -C138 ; LV # Lo HANGUL SYLLABLE SE -C154 ; LV # Lo HANGUL SYLLABLE SYEO -C170 ; LV # Lo HANGUL SYLLABLE SYE -C18C ; LV # Lo HANGUL SYLLABLE SO -C1A8 ; LV # Lo HANGUL SYLLABLE SWA -C1C4 ; LV # Lo HANGUL SYLLABLE SWAE -C1E0 ; LV # Lo HANGUL SYLLABLE SOE -C1FC ; LV # Lo HANGUL SYLLABLE SYO -C218 ; LV # Lo HANGUL SYLLABLE SU -C234 ; LV # Lo HANGUL SYLLABLE SWEO -C250 ; LV # Lo HANGUL SYLLABLE SWE -C26C ; LV # Lo HANGUL SYLLABLE SWI -C288 ; LV # Lo HANGUL SYLLABLE SYU -C2A4 ; LV # Lo HANGUL SYLLABLE SEU -C2C0 ; LV # Lo HANGUL SYLLABLE SYI -C2DC ; LV # Lo HANGUL SYLLABLE SI -C2F8 ; LV # Lo HANGUL SYLLABLE SSA -C314 ; LV # Lo HANGUL SYLLABLE SSAE -C330 ; LV # Lo HANGUL SYLLABLE SSYA -C34C ; LV # Lo HANGUL SYLLABLE SSYAE -C368 ; LV # Lo HANGUL SYLLABLE SSEO -C384 ; LV # Lo HANGUL SYLLABLE SSE -C3A0 ; LV # Lo HANGUL SYLLABLE SSYEO -C3BC ; LV # Lo HANGUL SYLLABLE SSYE -C3D8 ; LV # Lo HANGUL SYLLABLE SSO -C3F4 ; LV # Lo HANGUL SYLLABLE SSWA -C410 ; LV # Lo HANGUL SYLLABLE SSWAE -C42C ; LV # Lo HANGUL SYLLABLE SSOE -C448 ; LV # Lo HANGUL SYLLABLE SSYO -C464 ; LV # Lo HANGUL SYLLABLE SSU -C480 ; LV # Lo HANGUL SYLLABLE SSWEO -C49C ; LV # Lo HANGUL SYLLABLE SSWE -C4B8 ; LV # Lo HANGUL SYLLABLE SSWI -C4D4 ; LV # Lo HANGUL SYLLABLE SSYU -C4F0 ; LV # Lo HANGUL SYLLABLE SSEU -C50C ; LV # Lo HANGUL SYLLABLE SSYI -C528 ; LV # Lo HANGUL SYLLABLE SSI -C544 ; LV # Lo HANGUL SYLLABLE A -C560 ; LV # Lo HANGUL SYLLABLE AE -C57C ; LV # Lo HANGUL SYLLABLE YA -C598 ; LV # Lo HANGUL SYLLABLE YAE -C5B4 ; LV # Lo HANGUL SYLLABLE EO -C5D0 ; LV # Lo HANGUL SYLLABLE E -C5EC ; LV # Lo HANGUL SYLLABLE YEO -C608 ; LV # Lo HANGUL SYLLABLE YE -C624 ; LV # Lo HANGUL SYLLABLE O -C640 ; LV # Lo HANGUL SYLLABLE WA -C65C ; LV # Lo HANGUL SYLLABLE WAE -C678 ; LV # Lo HANGUL SYLLABLE OE -C694 ; LV # Lo HANGUL SYLLABLE YO -C6B0 ; LV # Lo HANGUL SYLLABLE U -C6CC ; LV # Lo HANGUL SYLLABLE WEO -C6E8 ; LV # Lo HANGUL SYLLABLE WE -C704 ; LV # Lo HANGUL SYLLABLE WI -C720 ; LV # Lo HANGUL SYLLABLE YU -C73C ; LV # Lo HANGUL SYLLABLE EU -C758 ; LV # Lo HANGUL SYLLABLE YI -C774 ; LV # Lo HANGUL SYLLABLE I -C790 ; LV # Lo HANGUL SYLLABLE JA -C7AC ; LV # Lo HANGUL SYLLABLE JAE -C7C8 ; LV # Lo HANGUL SYLLABLE JYA -C7E4 ; LV # Lo HANGUL SYLLABLE JYAE -C800 ; LV # Lo HANGUL SYLLABLE JEO -C81C ; LV # Lo HANGUL SYLLABLE JE -C838 ; LV # Lo HANGUL SYLLABLE JYEO -C854 ; LV # Lo HANGUL SYLLABLE JYE -C870 ; LV # Lo HANGUL SYLLABLE JO -C88C ; LV # Lo HANGUL SYLLABLE JWA -C8A8 ; LV # Lo HANGUL SYLLABLE JWAE -C8C4 ; LV # Lo HANGUL SYLLABLE JOE -C8E0 ; LV # Lo HANGUL SYLLABLE JYO -C8FC ; LV # Lo HANGUL SYLLABLE JU -C918 ; LV # Lo HANGUL SYLLABLE JWEO -C934 ; LV # Lo HANGUL SYLLABLE JWE -C950 ; LV # Lo HANGUL SYLLABLE JWI -C96C ; LV # Lo HANGUL SYLLABLE JYU -C988 ; LV # Lo HANGUL SYLLABLE JEU -C9A4 ; LV # Lo HANGUL SYLLABLE JYI -C9C0 ; LV # Lo HANGUL SYLLABLE JI -C9DC ; LV # Lo HANGUL SYLLABLE JJA -C9F8 ; LV # Lo HANGUL SYLLABLE JJAE -CA14 ; LV # Lo HANGUL SYLLABLE JJYA -CA30 ; LV # Lo HANGUL SYLLABLE JJYAE -CA4C ; LV # Lo HANGUL SYLLABLE JJEO -CA68 ; LV # Lo HANGUL SYLLABLE JJE -CA84 ; LV # Lo HANGUL SYLLABLE JJYEO -CAA0 ; LV # Lo HANGUL SYLLABLE JJYE -CABC ; LV # Lo HANGUL SYLLABLE JJO -CAD8 ; LV # Lo HANGUL SYLLABLE JJWA -CAF4 ; LV # Lo HANGUL SYLLABLE JJWAE -CB10 ; LV # Lo HANGUL SYLLABLE JJOE -CB2C ; LV # Lo HANGUL SYLLABLE JJYO -CB48 ; LV # Lo HANGUL SYLLABLE JJU -CB64 ; LV # Lo HANGUL SYLLABLE JJWEO -CB80 ; LV # Lo HANGUL SYLLABLE JJWE -CB9C ; LV # Lo HANGUL SYLLABLE JJWI -CBB8 ; LV # Lo HANGUL SYLLABLE JJYU -CBD4 ; LV # Lo HANGUL SYLLABLE JJEU -CBF0 ; LV # Lo HANGUL SYLLABLE JJYI -CC0C ; LV # Lo HANGUL SYLLABLE JJI -CC28 ; LV # Lo HANGUL SYLLABLE CA -CC44 ; LV # Lo HANGUL SYLLABLE CAE -CC60 ; LV # Lo HANGUL SYLLABLE CYA -CC7C ; LV # Lo HANGUL SYLLABLE CYAE -CC98 ; LV # Lo HANGUL SYLLABLE CEO -CCB4 ; LV # Lo HANGUL SYLLABLE CE -CCD0 ; LV # Lo HANGUL SYLLABLE CYEO -CCEC ; LV # Lo HANGUL SYLLABLE CYE -CD08 ; LV # Lo HANGUL SYLLABLE CO -CD24 ; LV # Lo HANGUL SYLLABLE CWA -CD40 ; LV # Lo HANGUL SYLLABLE CWAE -CD5C ; LV # Lo HANGUL SYLLABLE COE -CD78 ; LV # Lo HANGUL SYLLABLE CYO -CD94 ; LV # Lo HANGUL SYLLABLE CU -CDB0 ; LV # Lo HANGUL SYLLABLE CWEO -CDCC ; LV # Lo HANGUL SYLLABLE CWE -CDE8 ; LV # Lo HANGUL SYLLABLE CWI -CE04 ; LV # Lo HANGUL SYLLABLE CYU -CE20 ; LV # Lo HANGUL SYLLABLE CEU -CE3C ; LV # Lo HANGUL SYLLABLE CYI -CE58 ; LV # Lo HANGUL SYLLABLE CI -CE74 ; LV # Lo HANGUL SYLLABLE KA -CE90 ; LV # Lo HANGUL SYLLABLE KAE -CEAC ; LV # Lo HANGUL SYLLABLE KYA -CEC8 ; LV # Lo HANGUL SYLLABLE KYAE -CEE4 ; LV # Lo HANGUL SYLLABLE KEO -CF00 ; LV # Lo HANGUL SYLLABLE KE -CF1C ; LV # Lo HANGUL SYLLABLE KYEO -CF38 ; LV # Lo HANGUL SYLLABLE KYE -CF54 ; LV # Lo HANGUL SYLLABLE KO -CF70 ; LV # Lo HANGUL SYLLABLE KWA -CF8C ; LV # Lo HANGUL SYLLABLE KWAE -CFA8 ; LV # Lo HANGUL SYLLABLE KOE -CFC4 ; LV # Lo HANGUL SYLLABLE KYO -CFE0 ; LV # Lo HANGUL SYLLABLE KU -CFFC ; LV # Lo HANGUL SYLLABLE KWEO -D018 ; LV # Lo HANGUL SYLLABLE KWE -D034 ; LV # Lo HANGUL SYLLABLE KWI -D050 ; LV # Lo HANGUL SYLLABLE KYU -D06C ; LV # Lo HANGUL SYLLABLE KEU -D088 ; LV # Lo HANGUL SYLLABLE KYI -D0A4 ; LV # Lo HANGUL SYLLABLE KI -D0C0 ; LV # Lo HANGUL SYLLABLE TA -D0DC ; LV # Lo HANGUL SYLLABLE TAE -D0F8 ; LV # Lo HANGUL SYLLABLE TYA -D114 ; LV # Lo HANGUL SYLLABLE TYAE -D130 ; LV # Lo HANGUL SYLLABLE TEO -D14C ; LV # Lo HANGUL SYLLABLE TE -D168 ; LV # Lo HANGUL SYLLABLE TYEO -D184 ; LV # Lo HANGUL SYLLABLE TYE -D1A0 ; LV # Lo HANGUL SYLLABLE TO -D1BC ; LV # Lo HANGUL SYLLABLE TWA -D1D8 ; LV # Lo HANGUL SYLLABLE TWAE -D1F4 ; LV # Lo HANGUL SYLLABLE TOE -D210 ; LV # Lo HANGUL SYLLABLE TYO -D22C ; LV # Lo HANGUL SYLLABLE TU -D248 ; LV # Lo HANGUL SYLLABLE TWEO -D264 ; LV # Lo HANGUL SYLLABLE TWE -D280 ; LV # Lo HANGUL SYLLABLE TWI -D29C ; LV # Lo HANGUL SYLLABLE TYU -D2B8 ; LV # Lo HANGUL SYLLABLE TEU -D2D4 ; LV # Lo HANGUL SYLLABLE TYI -D2F0 ; LV # Lo HANGUL SYLLABLE TI -D30C ; LV # Lo HANGUL SYLLABLE PA -D328 ; LV # Lo HANGUL SYLLABLE PAE -D344 ; LV # Lo HANGUL SYLLABLE PYA -D360 ; LV # Lo HANGUL SYLLABLE PYAE -D37C ; LV # Lo HANGUL SYLLABLE PEO -D398 ; LV # Lo HANGUL SYLLABLE PE -D3B4 ; LV # Lo HANGUL SYLLABLE PYEO -D3D0 ; LV # Lo HANGUL SYLLABLE PYE -D3EC ; LV # Lo HANGUL SYLLABLE PO -D408 ; LV # Lo HANGUL SYLLABLE PWA -D424 ; LV # Lo HANGUL SYLLABLE PWAE -D440 ; LV # Lo HANGUL SYLLABLE POE -D45C ; LV # Lo HANGUL SYLLABLE PYO -D478 ; LV # Lo HANGUL SYLLABLE PU -D494 ; LV # Lo HANGUL SYLLABLE PWEO -D4B0 ; LV # Lo HANGUL SYLLABLE PWE -D4CC ; LV # Lo HANGUL SYLLABLE PWI -D4E8 ; LV # Lo HANGUL SYLLABLE PYU -D504 ; LV # Lo HANGUL SYLLABLE PEU -D520 ; LV # Lo HANGUL SYLLABLE PYI -D53C ; LV # Lo HANGUL SYLLABLE PI -D558 ; LV # Lo HANGUL SYLLABLE HA -D574 ; LV # Lo HANGUL SYLLABLE HAE -D590 ; LV # Lo HANGUL SYLLABLE HYA -D5AC ; LV # Lo HANGUL SYLLABLE HYAE -D5C8 ; LV # Lo HANGUL SYLLABLE HEO -D5E4 ; LV # Lo HANGUL SYLLABLE HE -D600 ; LV # Lo HANGUL SYLLABLE HYEO -D61C ; LV # Lo HANGUL SYLLABLE HYE -D638 ; LV # Lo HANGUL SYLLABLE HO -D654 ; LV # Lo HANGUL SYLLABLE HWA -D670 ; LV # Lo HANGUL SYLLABLE HWAE -D68C ; LV # Lo HANGUL SYLLABLE HOE -D6A8 ; LV # Lo HANGUL SYLLABLE HYO -D6C4 ; LV # Lo HANGUL SYLLABLE HU -D6E0 ; LV # Lo HANGUL SYLLABLE HWEO -D6FC ; LV # Lo HANGUL SYLLABLE HWE -D718 ; LV # Lo HANGUL SYLLABLE HWI -D734 ; LV # Lo HANGUL SYLLABLE HYU -D750 ; LV # Lo HANGUL SYLLABLE HEU -D76C ; LV # Lo HANGUL SYLLABLE HYI -D788 ; LV # Lo HANGUL SYLLABLE HI - -# Total code points: 399 - -# ================================================ - -AC01..AC1B ; LVT # Lo [27] HANGUL SYLLABLE GAG..HANGUL SYLLABLE GAH -AC1D..AC37 ; LVT # Lo [27] HANGUL SYLLABLE GAEG..HANGUL SYLLABLE GAEH -AC39..AC53 ; LVT # Lo [27] HANGUL SYLLABLE GYAG..HANGUL SYLLABLE GYAH -AC55..AC6F ; LVT # Lo [27] HANGUL SYLLABLE GYAEG..HANGUL SYLLABLE GYAEH -AC71..AC8B ; LVT # Lo [27] HANGUL SYLLABLE GEOG..HANGUL SYLLABLE GEOH -AC8D..ACA7 ; LVT # Lo [27] HANGUL SYLLABLE GEG..HANGUL SYLLABLE GEH -ACA9..ACC3 ; LVT # Lo [27] HANGUL SYLLABLE GYEOG..HANGUL SYLLABLE GYEOH -ACC5..ACDF ; LVT # Lo [27] HANGUL SYLLABLE GYEG..HANGUL SYLLABLE GYEH -ACE1..ACFB ; LVT # Lo [27] HANGUL SYLLABLE GOG..HANGUL SYLLABLE GOH -ACFD..AD17 ; LVT # Lo [27] HANGUL SYLLABLE GWAG..HANGUL SYLLABLE GWAH -AD19..AD33 ; LVT # Lo [27] HANGUL SYLLABLE GWAEG..HANGUL SYLLABLE GWAEH -AD35..AD4F ; LVT # Lo [27] HANGUL SYLLABLE GOEG..HANGUL SYLLABLE GOEH -AD51..AD6B ; LVT # Lo [27] HANGUL SYLLABLE GYOG..HANGUL SYLLABLE GYOH -AD6D..AD87 ; LVT # Lo [27] HANGUL SYLLABLE GUG..HANGUL SYLLABLE GUH -AD89..ADA3 ; LVT # Lo [27] HANGUL SYLLABLE GWEOG..HANGUL SYLLABLE GWEOH -ADA5..ADBF ; LVT # Lo [27] HANGUL SYLLABLE GWEG..HANGUL SYLLABLE GWEH -ADC1..ADDB ; LVT # Lo [27] HANGUL SYLLABLE GWIG..HANGUL SYLLABLE GWIH -ADDD..ADF7 ; LVT # Lo [27] HANGUL SYLLABLE GYUG..HANGUL SYLLABLE GYUH -ADF9..AE13 ; LVT # Lo [27] HANGUL SYLLABLE GEUG..HANGUL SYLLABLE GEUH -AE15..AE2F ; LVT # Lo [27] HANGUL SYLLABLE GYIG..HANGUL SYLLABLE GYIH -AE31..AE4B ; LVT # Lo [27] HANGUL SYLLABLE GIG..HANGUL SYLLABLE GIH -AE4D..AE67 ; LVT # Lo [27] HANGUL SYLLABLE GGAG..HANGUL SYLLABLE GGAH -AE69..AE83 ; LVT # Lo [27] HANGUL SYLLABLE GGAEG..HANGUL SYLLABLE GGAEH -AE85..AE9F ; LVT # Lo [27] HANGUL SYLLABLE GGYAG..HANGUL SYLLABLE GGYAH -AEA1..AEBB ; LVT # Lo [27] HANGUL SYLLABLE GGYAEG..HANGUL SYLLABLE GGYAEH -AEBD..AED7 ; LVT # Lo [27] HANGUL SYLLABLE GGEOG..HANGUL SYLLABLE GGEOH -AED9..AEF3 ; LVT # Lo [27] HANGUL SYLLABLE GGEG..HANGUL SYLLABLE GGEH -AEF5..AF0F ; LVT # Lo [27] HANGUL SYLLABLE GGYEOG..HANGUL SYLLABLE GGYEOH -AF11..AF2B ; LVT # Lo [27] HANGUL SYLLABLE GGYEG..HANGUL SYLLABLE GGYEH -AF2D..AF47 ; LVT # Lo [27] HANGUL SYLLABLE GGOG..HANGUL SYLLABLE GGOH -AF49..AF63 ; LVT # Lo [27] HANGUL SYLLABLE GGWAG..HANGUL SYLLABLE GGWAH -AF65..AF7F ; LVT # Lo [27] HANGUL SYLLABLE GGWAEG..HANGUL SYLLABLE GGWAEH -AF81..AF9B ; LVT # Lo [27] HANGUL SYLLABLE GGOEG..HANGUL SYLLABLE GGOEH -AF9D..AFB7 ; LVT # Lo [27] HANGUL SYLLABLE GGYOG..HANGUL SYLLABLE GGYOH -AFB9..AFD3 ; LVT # Lo [27] HANGUL SYLLABLE GGUG..HANGUL SYLLABLE GGUH -AFD5..AFEF ; LVT # Lo [27] HANGUL SYLLABLE GGWEOG..HANGUL SYLLABLE GGWEOH -AFF1..B00B ; LVT # Lo [27] HANGUL SYLLABLE GGWEG..HANGUL SYLLABLE GGWEH -B00D..B027 ; LVT # Lo [27] HANGUL SYLLABLE GGWIG..HANGUL SYLLABLE GGWIH -B029..B043 ; LVT # Lo [27] HANGUL SYLLABLE GGYUG..HANGUL SYLLABLE GGYUH -B045..B05F ; LVT # Lo [27] HANGUL SYLLABLE GGEUG..HANGUL SYLLABLE GGEUH -B061..B07B ; LVT # Lo [27] HANGUL SYLLABLE GGYIG..HANGUL SYLLABLE GGYIH -B07D..B097 ; LVT # Lo [27] HANGUL SYLLABLE GGIG..HANGUL SYLLABLE GGIH -B099..B0B3 ; LVT # Lo [27] HANGUL SYLLABLE NAG..HANGUL SYLLABLE NAH -B0B5..B0CF ; LVT # Lo [27] HANGUL SYLLABLE NAEG..HANGUL SYLLABLE NAEH -B0D1..B0EB ; LVT # Lo [27] HANGUL SYLLABLE NYAG..HANGUL SYLLABLE NYAH -B0ED..B107 ; LVT # Lo [27] HANGUL SYLLABLE NYAEG..HANGUL SYLLABLE NYAEH -B109..B123 ; LVT # Lo [27] HANGUL SYLLABLE NEOG..HANGUL SYLLABLE NEOH -B125..B13F ; LVT # Lo [27] HANGUL SYLLABLE NEG..HANGUL SYLLABLE NEH -B141..B15B ; LVT # Lo [27] HANGUL SYLLABLE NYEOG..HANGUL SYLLABLE NYEOH -B15D..B177 ; LVT # Lo [27] HANGUL SYLLABLE NYEG..HANGUL SYLLABLE NYEH -B179..B193 ; LVT # Lo [27] HANGUL SYLLABLE NOG..HANGUL SYLLABLE NOH -B195..B1AF ; LVT # Lo [27] HANGUL SYLLABLE NWAG..HANGUL SYLLABLE NWAH -B1B1..B1CB ; LVT # Lo [27] HANGUL SYLLABLE NWAEG..HANGUL SYLLABLE NWAEH -B1CD..B1E7 ; LVT # Lo [27] HANGUL SYLLABLE NOEG..HANGUL SYLLABLE NOEH -B1E9..B203 ; LVT # Lo [27] HANGUL SYLLABLE NYOG..HANGUL SYLLABLE NYOH -B205..B21F ; LVT # Lo [27] HANGUL SYLLABLE NUG..HANGUL SYLLABLE NUH -B221..B23B ; LVT # Lo [27] HANGUL SYLLABLE NWEOG..HANGUL SYLLABLE NWEOH -B23D..B257 ; LVT # Lo [27] HANGUL SYLLABLE NWEG..HANGUL SYLLABLE NWEH -B259..B273 ; LVT # Lo [27] HANGUL SYLLABLE NWIG..HANGUL SYLLABLE NWIH -B275..B28F ; LVT # Lo [27] HANGUL SYLLABLE NYUG..HANGUL SYLLABLE NYUH -B291..B2AB ; LVT # Lo [27] HANGUL SYLLABLE NEUG..HANGUL SYLLABLE NEUH -B2AD..B2C7 ; LVT # Lo [27] HANGUL SYLLABLE NYIG..HANGUL SYLLABLE NYIH -B2C9..B2E3 ; LVT # Lo [27] HANGUL SYLLABLE NIG..HANGUL SYLLABLE NIH -B2E5..B2FF ; LVT # Lo [27] HANGUL SYLLABLE DAG..HANGUL SYLLABLE DAH -B301..B31B ; LVT # Lo [27] HANGUL SYLLABLE DAEG..HANGUL SYLLABLE DAEH -B31D..B337 ; LVT # Lo [27] HANGUL SYLLABLE DYAG..HANGUL SYLLABLE DYAH -B339..B353 ; LVT # Lo [27] HANGUL SYLLABLE DYAEG..HANGUL SYLLABLE DYAEH -B355..B36F ; LVT # Lo [27] HANGUL SYLLABLE DEOG..HANGUL SYLLABLE DEOH -B371..B38B ; LVT # Lo [27] HANGUL SYLLABLE DEG..HANGUL SYLLABLE DEH -B38D..B3A7 ; LVT # Lo [27] HANGUL SYLLABLE DYEOG..HANGUL SYLLABLE DYEOH -B3A9..B3C3 ; LVT # Lo [27] HANGUL SYLLABLE DYEG..HANGUL SYLLABLE DYEH -B3C5..B3DF ; LVT # Lo [27] HANGUL SYLLABLE DOG..HANGUL SYLLABLE DOH -B3E1..B3FB ; LVT # Lo [27] HANGUL SYLLABLE DWAG..HANGUL SYLLABLE DWAH -B3FD..B417 ; LVT # Lo [27] HANGUL SYLLABLE DWAEG..HANGUL SYLLABLE DWAEH -B419..B433 ; LVT # Lo [27] HANGUL SYLLABLE DOEG..HANGUL SYLLABLE DOEH -B435..B44F ; LVT # Lo [27] HANGUL SYLLABLE DYOG..HANGUL SYLLABLE DYOH -B451..B46B ; LVT # Lo [27] HANGUL SYLLABLE DUG..HANGUL SYLLABLE DUH -B46D..B487 ; LVT # Lo [27] HANGUL SYLLABLE DWEOG..HANGUL SYLLABLE DWEOH -B489..B4A3 ; LVT # Lo [27] HANGUL SYLLABLE DWEG..HANGUL SYLLABLE DWEH -B4A5..B4BF ; LVT # Lo [27] HANGUL SYLLABLE DWIG..HANGUL SYLLABLE DWIH -B4C1..B4DB ; LVT # Lo [27] HANGUL SYLLABLE DYUG..HANGUL SYLLABLE DYUH -B4DD..B4F7 ; LVT # Lo [27] HANGUL SYLLABLE DEUG..HANGUL SYLLABLE DEUH -B4F9..B513 ; LVT # Lo [27] HANGUL SYLLABLE DYIG..HANGUL SYLLABLE DYIH -B515..B52F ; LVT # Lo [27] HANGUL SYLLABLE DIG..HANGUL SYLLABLE DIH -B531..B54B ; LVT # Lo [27] HANGUL SYLLABLE DDAG..HANGUL SYLLABLE DDAH -B54D..B567 ; LVT # Lo [27] HANGUL SYLLABLE DDAEG..HANGUL SYLLABLE DDAEH -B569..B583 ; LVT # Lo [27] HANGUL SYLLABLE DDYAG..HANGUL SYLLABLE DDYAH -B585..B59F ; LVT # Lo [27] HANGUL SYLLABLE DDYAEG..HANGUL SYLLABLE DDYAEH -B5A1..B5BB ; LVT # Lo [27] HANGUL SYLLABLE DDEOG..HANGUL SYLLABLE DDEOH -B5BD..B5D7 ; LVT # Lo [27] HANGUL SYLLABLE DDEG..HANGUL SYLLABLE DDEH -B5D9..B5F3 ; LVT # Lo [27] HANGUL SYLLABLE DDYEOG..HANGUL SYLLABLE DDYEOH -B5F5..B60F ; LVT # Lo [27] HANGUL SYLLABLE DDYEG..HANGUL SYLLABLE DDYEH -B611..B62B ; LVT # Lo [27] HANGUL SYLLABLE DDOG..HANGUL SYLLABLE DDOH -B62D..B647 ; LVT # Lo [27] HANGUL SYLLABLE DDWAG..HANGUL SYLLABLE DDWAH -B649..B663 ; LVT # Lo [27] HANGUL SYLLABLE DDWAEG..HANGUL SYLLABLE DDWAEH -B665..B67F ; LVT # Lo [27] HANGUL SYLLABLE DDOEG..HANGUL SYLLABLE DDOEH -B681..B69B ; LVT # Lo [27] HANGUL SYLLABLE DDYOG..HANGUL SYLLABLE DDYOH -B69D..B6B7 ; LVT # Lo [27] HANGUL SYLLABLE DDUG..HANGUL SYLLABLE DDUH -B6B9..B6D3 ; LVT # Lo [27] HANGUL SYLLABLE DDWEOG..HANGUL SYLLABLE DDWEOH -B6D5..B6EF ; LVT # Lo [27] HANGUL SYLLABLE DDWEG..HANGUL SYLLABLE DDWEH -B6F1..B70B ; LVT # Lo [27] HANGUL SYLLABLE DDWIG..HANGUL SYLLABLE DDWIH -B70D..B727 ; LVT # Lo [27] HANGUL SYLLABLE DDYUG..HANGUL SYLLABLE DDYUH -B729..B743 ; LVT # Lo [27] HANGUL SYLLABLE DDEUG..HANGUL SYLLABLE DDEUH -B745..B75F ; LVT # Lo [27] HANGUL SYLLABLE DDYIG..HANGUL SYLLABLE DDYIH -B761..B77B ; LVT # Lo [27] HANGUL SYLLABLE DDIG..HANGUL SYLLABLE DDIH -B77D..B797 ; LVT # Lo [27] HANGUL SYLLABLE RAG..HANGUL SYLLABLE RAH -B799..B7B3 ; LVT # Lo [27] HANGUL SYLLABLE RAEG..HANGUL SYLLABLE RAEH -B7B5..B7CF ; LVT # Lo [27] HANGUL SYLLABLE RYAG..HANGUL SYLLABLE RYAH -B7D1..B7EB ; LVT # Lo [27] HANGUL SYLLABLE RYAEG..HANGUL SYLLABLE RYAEH -B7ED..B807 ; LVT # Lo [27] HANGUL SYLLABLE REOG..HANGUL SYLLABLE REOH -B809..B823 ; LVT # Lo [27] HANGUL SYLLABLE REG..HANGUL SYLLABLE REH -B825..B83F ; LVT # Lo [27] HANGUL SYLLABLE RYEOG..HANGUL SYLLABLE RYEOH -B841..B85B ; LVT # Lo [27] HANGUL SYLLABLE RYEG..HANGUL SYLLABLE RYEH -B85D..B877 ; LVT # Lo [27] HANGUL SYLLABLE ROG..HANGUL SYLLABLE ROH -B879..B893 ; LVT # Lo [27] HANGUL SYLLABLE RWAG..HANGUL SYLLABLE RWAH -B895..B8AF ; LVT # Lo [27] HANGUL SYLLABLE RWAEG..HANGUL SYLLABLE RWAEH -B8B1..B8CB ; LVT # Lo [27] HANGUL SYLLABLE ROEG..HANGUL SYLLABLE ROEH -B8CD..B8E7 ; LVT # Lo [27] HANGUL SYLLABLE RYOG..HANGUL SYLLABLE RYOH -B8E9..B903 ; LVT # Lo [27] HANGUL SYLLABLE RUG..HANGUL SYLLABLE RUH -B905..B91F ; LVT # Lo [27] HANGUL SYLLABLE RWEOG..HANGUL SYLLABLE RWEOH -B921..B93B ; LVT # Lo [27] HANGUL SYLLABLE RWEG..HANGUL SYLLABLE RWEH -B93D..B957 ; LVT # Lo [27] HANGUL SYLLABLE RWIG..HANGUL SYLLABLE RWIH -B959..B973 ; LVT # Lo [27] HANGUL SYLLABLE RYUG..HANGUL SYLLABLE RYUH -B975..B98F ; LVT # Lo [27] HANGUL SYLLABLE REUG..HANGUL SYLLABLE REUH -B991..B9AB ; LVT # Lo [27] HANGUL SYLLABLE RYIG..HANGUL SYLLABLE RYIH -B9AD..B9C7 ; LVT # Lo [27] HANGUL SYLLABLE RIG..HANGUL SYLLABLE RIH -B9C9..B9E3 ; LVT # Lo [27] HANGUL SYLLABLE MAG..HANGUL SYLLABLE MAH -B9E5..B9FF ; LVT # Lo [27] HANGUL SYLLABLE MAEG..HANGUL SYLLABLE MAEH -BA01..BA1B ; LVT # Lo [27] HANGUL SYLLABLE MYAG..HANGUL SYLLABLE MYAH -BA1D..BA37 ; LVT # Lo [27] HANGUL SYLLABLE MYAEG..HANGUL SYLLABLE MYAEH -BA39..BA53 ; LVT # Lo [27] HANGUL SYLLABLE MEOG..HANGUL SYLLABLE MEOH -BA55..BA6F ; LVT # Lo [27] HANGUL SYLLABLE MEG..HANGUL SYLLABLE MEH -BA71..BA8B ; LVT # Lo [27] HANGUL SYLLABLE MYEOG..HANGUL SYLLABLE MYEOH -BA8D..BAA7 ; LVT # Lo [27] HANGUL SYLLABLE MYEG..HANGUL SYLLABLE MYEH -BAA9..BAC3 ; LVT # Lo [27] HANGUL SYLLABLE MOG..HANGUL SYLLABLE MOH -BAC5..BADF ; LVT # Lo [27] HANGUL SYLLABLE MWAG..HANGUL SYLLABLE MWAH -BAE1..BAFB ; LVT # Lo [27] HANGUL SYLLABLE MWAEG..HANGUL SYLLABLE MWAEH -BAFD..BB17 ; LVT # Lo [27] HANGUL SYLLABLE MOEG..HANGUL SYLLABLE MOEH -BB19..BB33 ; LVT # Lo [27] HANGUL SYLLABLE MYOG..HANGUL SYLLABLE MYOH -BB35..BB4F ; LVT # Lo [27] HANGUL SYLLABLE MUG..HANGUL SYLLABLE MUH -BB51..BB6B ; LVT # Lo [27] HANGUL SYLLABLE MWEOG..HANGUL SYLLABLE MWEOH -BB6D..BB87 ; LVT # Lo [27] HANGUL SYLLABLE MWEG..HANGUL SYLLABLE MWEH -BB89..BBA3 ; LVT # Lo [27] HANGUL SYLLABLE MWIG..HANGUL SYLLABLE MWIH -BBA5..BBBF ; LVT # Lo [27] HANGUL SYLLABLE MYUG..HANGUL SYLLABLE MYUH -BBC1..BBDB ; LVT # Lo [27] HANGUL SYLLABLE MEUG..HANGUL SYLLABLE MEUH -BBDD..BBF7 ; LVT # Lo [27] HANGUL SYLLABLE MYIG..HANGUL SYLLABLE MYIH -BBF9..BC13 ; LVT # Lo [27] HANGUL SYLLABLE MIG..HANGUL SYLLABLE MIH -BC15..BC2F ; LVT # Lo [27] HANGUL SYLLABLE BAG..HANGUL SYLLABLE BAH -BC31..BC4B ; LVT # Lo [27] HANGUL SYLLABLE BAEG..HANGUL SYLLABLE BAEH -BC4D..BC67 ; LVT # Lo [27] HANGUL SYLLABLE BYAG..HANGUL SYLLABLE BYAH -BC69..BC83 ; LVT # Lo [27] HANGUL SYLLABLE BYAEG..HANGUL SYLLABLE BYAEH -BC85..BC9F ; LVT # Lo [27] HANGUL SYLLABLE BEOG..HANGUL SYLLABLE BEOH -BCA1..BCBB ; LVT # Lo [27] HANGUL SYLLABLE BEG..HANGUL SYLLABLE BEH -BCBD..BCD7 ; LVT # Lo [27] HANGUL SYLLABLE BYEOG..HANGUL SYLLABLE BYEOH -BCD9..BCF3 ; LVT # Lo [27] HANGUL SYLLABLE BYEG..HANGUL SYLLABLE BYEH -BCF5..BD0F ; LVT # Lo [27] HANGUL SYLLABLE BOG..HANGUL SYLLABLE BOH -BD11..BD2B ; LVT # Lo [27] HANGUL SYLLABLE BWAG..HANGUL SYLLABLE BWAH -BD2D..BD47 ; LVT # Lo [27] HANGUL SYLLABLE BWAEG..HANGUL SYLLABLE BWAEH -BD49..BD63 ; LVT # Lo [27] HANGUL SYLLABLE BOEG..HANGUL SYLLABLE BOEH -BD65..BD7F ; LVT # Lo [27] HANGUL SYLLABLE BYOG..HANGUL SYLLABLE BYOH -BD81..BD9B ; LVT # Lo [27] HANGUL SYLLABLE BUG..HANGUL SYLLABLE BUH -BD9D..BDB7 ; LVT # Lo [27] HANGUL SYLLABLE BWEOG..HANGUL SYLLABLE BWEOH -BDB9..BDD3 ; LVT # Lo [27] HANGUL SYLLABLE BWEG..HANGUL SYLLABLE BWEH -BDD5..BDEF ; LVT # Lo [27] HANGUL SYLLABLE BWIG..HANGUL SYLLABLE BWIH -BDF1..BE0B ; LVT # Lo [27] HANGUL SYLLABLE BYUG..HANGUL SYLLABLE BYUH -BE0D..BE27 ; LVT # Lo [27] HANGUL SYLLABLE BEUG..HANGUL SYLLABLE BEUH -BE29..BE43 ; LVT # Lo [27] HANGUL SYLLABLE BYIG..HANGUL SYLLABLE BYIH -BE45..BE5F ; LVT # Lo [27] HANGUL SYLLABLE BIG..HANGUL SYLLABLE BIH -BE61..BE7B ; LVT # Lo [27] HANGUL SYLLABLE BBAG..HANGUL SYLLABLE BBAH -BE7D..BE97 ; LVT # Lo [27] HANGUL SYLLABLE BBAEG..HANGUL SYLLABLE BBAEH -BE99..BEB3 ; LVT # Lo [27] HANGUL SYLLABLE BBYAG..HANGUL SYLLABLE BBYAH -BEB5..BECF ; LVT # Lo [27] HANGUL SYLLABLE BBYAEG..HANGUL SYLLABLE BBYAEH -BED1..BEEB ; LVT # Lo [27] HANGUL SYLLABLE BBEOG..HANGUL SYLLABLE BBEOH -BEED..BF07 ; LVT # Lo [27] HANGUL SYLLABLE BBEG..HANGUL SYLLABLE BBEH -BF09..BF23 ; LVT # Lo [27] HANGUL SYLLABLE BBYEOG..HANGUL SYLLABLE BBYEOH -BF25..BF3F ; LVT # Lo [27] HANGUL SYLLABLE BBYEG..HANGUL SYLLABLE BBYEH -BF41..BF5B ; LVT # Lo [27] HANGUL SYLLABLE BBOG..HANGUL SYLLABLE BBOH -BF5D..BF77 ; LVT # Lo [27] HANGUL SYLLABLE BBWAG..HANGUL SYLLABLE BBWAH -BF79..BF93 ; LVT # Lo [27] HANGUL SYLLABLE BBWAEG..HANGUL SYLLABLE BBWAEH -BF95..BFAF ; LVT # Lo [27] HANGUL SYLLABLE BBOEG..HANGUL SYLLABLE BBOEH -BFB1..BFCB ; LVT # Lo [27] HANGUL SYLLABLE BBYOG..HANGUL SYLLABLE BBYOH -BFCD..BFE7 ; LVT # Lo [27] HANGUL SYLLABLE BBUG..HANGUL SYLLABLE BBUH -BFE9..C003 ; LVT # Lo [27] HANGUL SYLLABLE BBWEOG..HANGUL SYLLABLE BBWEOH -C005..C01F ; LVT # Lo [27] HANGUL SYLLABLE BBWEG..HANGUL SYLLABLE BBWEH -C021..C03B ; LVT # Lo [27] HANGUL SYLLABLE BBWIG..HANGUL SYLLABLE BBWIH -C03D..C057 ; LVT # Lo [27] HANGUL SYLLABLE BBYUG..HANGUL SYLLABLE BBYUH -C059..C073 ; LVT # Lo [27] HANGUL SYLLABLE BBEUG..HANGUL SYLLABLE BBEUH -C075..C08F ; LVT # Lo [27] HANGUL SYLLABLE BBYIG..HANGUL SYLLABLE BBYIH -C091..C0AB ; LVT # Lo [27] HANGUL SYLLABLE BBIG..HANGUL SYLLABLE BBIH -C0AD..C0C7 ; LVT # Lo [27] HANGUL SYLLABLE SAG..HANGUL SYLLABLE SAH -C0C9..C0E3 ; LVT # Lo [27] HANGUL SYLLABLE SAEG..HANGUL SYLLABLE SAEH -C0E5..C0FF ; LVT # Lo [27] HANGUL SYLLABLE SYAG..HANGUL SYLLABLE SYAH -C101..C11B ; LVT # Lo [27] HANGUL SYLLABLE SYAEG..HANGUL SYLLABLE SYAEH -C11D..C137 ; LVT # Lo [27] HANGUL SYLLABLE SEOG..HANGUL SYLLABLE SEOH -C139..C153 ; LVT # Lo [27] HANGUL SYLLABLE SEG..HANGUL SYLLABLE SEH -C155..C16F ; LVT # Lo [27] HANGUL SYLLABLE SYEOG..HANGUL SYLLABLE SYEOH -C171..C18B ; LVT # Lo [27] HANGUL SYLLABLE SYEG..HANGUL SYLLABLE SYEH -C18D..C1A7 ; LVT # Lo [27] HANGUL SYLLABLE SOG..HANGUL SYLLABLE SOH -C1A9..C1C3 ; LVT # Lo [27] HANGUL SYLLABLE SWAG..HANGUL SYLLABLE SWAH -C1C5..C1DF ; LVT # Lo [27] HANGUL SYLLABLE SWAEG..HANGUL SYLLABLE SWAEH -C1E1..C1FB ; LVT # Lo [27] HANGUL SYLLABLE SOEG..HANGUL SYLLABLE SOEH -C1FD..C217 ; LVT # Lo [27] HANGUL SYLLABLE SYOG..HANGUL SYLLABLE SYOH -C219..C233 ; LVT # Lo [27] HANGUL SYLLABLE SUG..HANGUL SYLLABLE SUH -C235..C24F ; LVT # Lo [27] HANGUL SYLLABLE SWEOG..HANGUL SYLLABLE SWEOH -C251..C26B ; LVT # Lo [27] HANGUL SYLLABLE SWEG..HANGUL SYLLABLE SWEH -C26D..C287 ; LVT # Lo [27] HANGUL SYLLABLE SWIG..HANGUL SYLLABLE SWIH -C289..C2A3 ; LVT # Lo [27] HANGUL SYLLABLE SYUG..HANGUL SYLLABLE SYUH -C2A5..C2BF ; LVT # Lo [27] HANGUL SYLLABLE SEUG..HANGUL SYLLABLE SEUH -C2C1..C2DB ; LVT # Lo [27] HANGUL SYLLABLE SYIG..HANGUL SYLLABLE SYIH -C2DD..C2F7 ; LVT # Lo [27] HANGUL SYLLABLE SIG..HANGUL SYLLABLE SIH -C2F9..C313 ; LVT # Lo [27] HANGUL SYLLABLE SSAG..HANGUL SYLLABLE SSAH -C315..C32F ; LVT # Lo [27] HANGUL SYLLABLE SSAEG..HANGUL SYLLABLE SSAEH -C331..C34B ; LVT # Lo [27] HANGUL SYLLABLE SSYAG..HANGUL SYLLABLE SSYAH -C34D..C367 ; LVT # Lo [27] HANGUL SYLLABLE SSYAEG..HANGUL SYLLABLE SSYAEH -C369..C383 ; LVT # Lo [27] HANGUL SYLLABLE SSEOG..HANGUL SYLLABLE SSEOH -C385..C39F ; LVT # Lo [27] HANGUL SYLLABLE SSEG..HANGUL SYLLABLE SSEH -C3A1..C3BB ; LVT # Lo [27] HANGUL SYLLABLE SSYEOG..HANGUL SYLLABLE SSYEOH -C3BD..C3D7 ; LVT # Lo [27] HANGUL SYLLABLE SSYEG..HANGUL SYLLABLE SSYEH -C3D9..C3F3 ; LVT # Lo [27] HANGUL SYLLABLE SSOG..HANGUL SYLLABLE SSOH -C3F5..C40F ; LVT # Lo [27] HANGUL SYLLABLE SSWAG..HANGUL SYLLABLE SSWAH -C411..C42B ; LVT # Lo [27] HANGUL SYLLABLE SSWAEG..HANGUL SYLLABLE SSWAEH -C42D..C447 ; LVT # Lo [27] HANGUL SYLLABLE SSOEG..HANGUL SYLLABLE SSOEH -C449..C463 ; LVT # Lo [27] HANGUL SYLLABLE SSYOG..HANGUL SYLLABLE SSYOH -C465..C47F ; LVT # Lo [27] HANGUL SYLLABLE SSUG..HANGUL SYLLABLE SSUH -C481..C49B ; LVT # Lo [27] HANGUL SYLLABLE SSWEOG..HANGUL SYLLABLE SSWEOH -C49D..C4B7 ; LVT # Lo [27] HANGUL SYLLABLE SSWEG..HANGUL SYLLABLE SSWEH -C4B9..C4D3 ; LVT # Lo [27] HANGUL SYLLABLE SSWIG..HANGUL SYLLABLE SSWIH -C4D5..C4EF ; LVT # Lo [27] HANGUL SYLLABLE SSYUG..HANGUL SYLLABLE SSYUH -C4F1..C50B ; LVT # Lo [27] HANGUL SYLLABLE SSEUG..HANGUL SYLLABLE SSEUH -C50D..C527 ; LVT # Lo [27] HANGUL SYLLABLE SSYIG..HANGUL SYLLABLE SSYIH -C529..C543 ; LVT # Lo [27] HANGUL SYLLABLE SSIG..HANGUL SYLLABLE SSIH -C545..C55F ; LVT # Lo [27] HANGUL SYLLABLE AG..HANGUL SYLLABLE AH -C561..C57B ; LVT # Lo [27] HANGUL SYLLABLE AEG..HANGUL SYLLABLE AEH -C57D..C597 ; LVT # Lo [27] HANGUL SYLLABLE YAG..HANGUL SYLLABLE YAH -C599..C5B3 ; LVT # Lo [27] HANGUL SYLLABLE YAEG..HANGUL SYLLABLE YAEH -C5B5..C5CF ; LVT # Lo [27] HANGUL SYLLABLE EOG..HANGUL SYLLABLE EOH -C5D1..C5EB ; LVT # Lo [27] HANGUL SYLLABLE EG..HANGUL SYLLABLE EH -C5ED..C607 ; LVT # Lo [27] HANGUL SYLLABLE YEOG..HANGUL SYLLABLE YEOH -C609..C623 ; LVT # Lo [27] HANGUL SYLLABLE YEG..HANGUL SYLLABLE YEH -C625..C63F ; LVT # Lo [27] HANGUL SYLLABLE OG..HANGUL SYLLABLE OH -C641..C65B ; LVT # Lo [27] HANGUL SYLLABLE WAG..HANGUL SYLLABLE WAH -C65D..C677 ; LVT # Lo [27] HANGUL SYLLABLE WAEG..HANGUL SYLLABLE WAEH -C679..C693 ; LVT # Lo [27] HANGUL SYLLABLE OEG..HANGUL SYLLABLE OEH -C695..C6AF ; LVT # Lo [27] HANGUL SYLLABLE YOG..HANGUL SYLLABLE YOH -C6B1..C6CB ; LVT # Lo [27] HANGUL SYLLABLE UG..HANGUL SYLLABLE UH -C6CD..C6E7 ; LVT # Lo [27] HANGUL SYLLABLE WEOG..HANGUL SYLLABLE WEOH -C6E9..C703 ; LVT # Lo [27] HANGUL SYLLABLE WEG..HANGUL SYLLABLE WEH -C705..C71F ; LVT # Lo [27] HANGUL SYLLABLE WIG..HANGUL SYLLABLE WIH -C721..C73B ; LVT # Lo [27] HANGUL SYLLABLE YUG..HANGUL SYLLABLE YUH -C73D..C757 ; LVT # Lo [27] HANGUL SYLLABLE EUG..HANGUL SYLLABLE EUH -C759..C773 ; LVT # Lo [27] HANGUL SYLLABLE YIG..HANGUL SYLLABLE YIH -C775..C78F ; LVT # Lo [27] HANGUL SYLLABLE IG..HANGUL SYLLABLE IH -C791..C7AB ; LVT # Lo [27] HANGUL SYLLABLE JAG..HANGUL SYLLABLE JAH -C7AD..C7C7 ; LVT # Lo [27] HANGUL SYLLABLE JAEG..HANGUL SYLLABLE JAEH -C7C9..C7E3 ; LVT # Lo [27] HANGUL SYLLABLE JYAG..HANGUL SYLLABLE JYAH -C7E5..C7FF ; LVT # Lo [27] HANGUL SYLLABLE JYAEG..HANGUL SYLLABLE JYAEH -C801..C81B ; LVT # Lo [27] HANGUL SYLLABLE JEOG..HANGUL SYLLABLE JEOH -C81D..C837 ; LVT # Lo [27] HANGUL SYLLABLE JEG..HANGUL SYLLABLE JEH -C839..C853 ; LVT # Lo [27] HANGUL SYLLABLE JYEOG..HANGUL SYLLABLE JYEOH -C855..C86F ; LVT # Lo [27] HANGUL SYLLABLE JYEG..HANGUL SYLLABLE JYEH -C871..C88B ; LVT # Lo [27] HANGUL SYLLABLE JOG..HANGUL SYLLABLE JOH -C88D..C8A7 ; LVT # Lo [27] HANGUL SYLLABLE JWAG..HANGUL SYLLABLE JWAH -C8A9..C8C3 ; LVT # Lo [27] HANGUL SYLLABLE JWAEG..HANGUL SYLLABLE JWAEH -C8C5..C8DF ; LVT # Lo [27] HANGUL SYLLABLE JOEG..HANGUL SYLLABLE JOEH -C8E1..C8FB ; LVT # Lo [27] HANGUL SYLLABLE JYOG..HANGUL SYLLABLE JYOH -C8FD..C917 ; LVT # Lo [27] HANGUL SYLLABLE JUG..HANGUL SYLLABLE JUH -C919..C933 ; LVT # Lo [27] HANGUL SYLLABLE JWEOG..HANGUL SYLLABLE JWEOH -C935..C94F ; LVT # Lo [27] HANGUL SYLLABLE JWEG..HANGUL SYLLABLE JWEH -C951..C96B ; LVT # Lo [27] HANGUL SYLLABLE JWIG..HANGUL SYLLABLE JWIH -C96D..C987 ; LVT # Lo [27] HANGUL SYLLABLE JYUG..HANGUL SYLLABLE JYUH -C989..C9A3 ; LVT # Lo [27] HANGUL SYLLABLE JEUG..HANGUL SYLLABLE JEUH -C9A5..C9BF ; LVT # Lo [27] HANGUL SYLLABLE JYIG..HANGUL SYLLABLE JYIH -C9C1..C9DB ; LVT # Lo [27] HANGUL SYLLABLE JIG..HANGUL SYLLABLE JIH -C9DD..C9F7 ; LVT # Lo [27] HANGUL SYLLABLE JJAG..HANGUL SYLLABLE JJAH -C9F9..CA13 ; LVT # Lo [27] HANGUL SYLLABLE JJAEG..HANGUL SYLLABLE JJAEH -CA15..CA2F ; LVT # Lo [27] HANGUL SYLLABLE JJYAG..HANGUL SYLLABLE JJYAH -CA31..CA4B ; LVT # Lo [27] HANGUL SYLLABLE JJYAEG..HANGUL SYLLABLE JJYAEH -CA4D..CA67 ; LVT # Lo [27] HANGUL SYLLABLE JJEOG..HANGUL SYLLABLE JJEOH -CA69..CA83 ; LVT # Lo [27] HANGUL SYLLABLE JJEG..HANGUL SYLLABLE JJEH -CA85..CA9F ; LVT # Lo [27] HANGUL SYLLABLE JJYEOG..HANGUL SYLLABLE JJYEOH -CAA1..CABB ; LVT # Lo [27] HANGUL SYLLABLE JJYEG..HANGUL SYLLABLE JJYEH -CABD..CAD7 ; LVT # Lo [27] HANGUL SYLLABLE JJOG..HANGUL SYLLABLE JJOH -CAD9..CAF3 ; LVT # Lo [27] HANGUL SYLLABLE JJWAG..HANGUL SYLLABLE JJWAH -CAF5..CB0F ; LVT # Lo [27] HANGUL SYLLABLE JJWAEG..HANGUL SYLLABLE JJWAEH -CB11..CB2B ; LVT # Lo [27] HANGUL SYLLABLE JJOEG..HANGUL SYLLABLE JJOEH -CB2D..CB47 ; LVT # Lo [27] HANGUL SYLLABLE JJYOG..HANGUL SYLLABLE JJYOH -CB49..CB63 ; LVT # Lo [27] HANGUL SYLLABLE JJUG..HANGUL SYLLABLE JJUH -CB65..CB7F ; LVT # Lo [27] HANGUL SYLLABLE JJWEOG..HANGUL SYLLABLE JJWEOH -CB81..CB9B ; LVT # Lo [27] HANGUL SYLLABLE JJWEG..HANGUL SYLLABLE JJWEH -CB9D..CBB7 ; LVT # Lo [27] HANGUL SYLLABLE JJWIG..HANGUL SYLLABLE JJWIH -CBB9..CBD3 ; LVT # Lo [27] HANGUL SYLLABLE JJYUG..HANGUL SYLLABLE JJYUH -CBD5..CBEF ; LVT # Lo [27] HANGUL SYLLABLE JJEUG..HANGUL SYLLABLE JJEUH -CBF1..CC0B ; LVT # Lo [27] HANGUL SYLLABLE JJYIG..HANGUL SYLLABLE JJYIH -CC0D..CC27 ; LVT # Lo [27] HANGUL SYLLABLE JJIG..HANGUL SYLLABLE JJIH -CC29..CC43 ; LVT # Lo [27] HANGUL SYLLABLE CAG..HANGUL SYLLABLE CAH -CC45..CC5F ; LVT # Lo [27] HANGUL SYLLABLE CAEG..HANGUL SYLLABLE CAEH -CC61..CC7B ; LVT # Lo [27] HANGUL SYLLABLE CYAG..HANGUL SYLLABLE CYAH -CC7D..CC97 ; LVT # Lo [27] HANGUL SYLLABLE CYAEG..HANGUL SYLLABLE CYAEH -CC99..CCB3 ; LVT # Lo [27] HANGUL SYLLABLE CEOG..HANGUL SYLLABLE CEOH -CCB5..CCCF ; LVT # Lo [27] HANGUL SYLLABLE CEG..HANGUL SYLLABLE CEH -CCD1..CCEB ; LVT # Lo [27] HANGUL SYLLABLE CYEOG..HANGUL SYLLABLE CYEOH -CCED..CD07 ; LVT # Lo [27] HANGUL SYLLABLE CYEG..HANGUL SYLLABLE CYEH -CD09..CD23 ; LVT # Lo [27] HANGUL SYLLABLE COG..HANGUL SYLLABLE COH -CD25..CD3F ; LVT # Lo [27] HANGUL SYLLABLE CWAG..HANGUL SYLLABLE CWAH -CD41..CD5B ; LVT # Lo [27] HANGUL SYLLABLE CWAEG..HANGUL SYLLABLE CWAEH -CD5D..CD77 ; LVT # Lo [27] HANGUL SYLLABLE COEG..HANGUL SYLLABLE COEH -CD79..CD93 ; LVT # Lo [27] HANGUL SYLLABLE CYOG..HANGUL SYLLABLE CYOH -CD95..CDAF ; LVT # Lo [27] HANGUL SYLLABLE CUG..HANGUL SYLLABLE CUH -CDB1..CDCB ; LVT # Lo [27] HANGUL SYLLABLE CWEOG..HANGUL SYLLABLE CWEOH -CDCD..CDE7 ; LVT # Lo [27] HANGUL SYLLABLE CWEG..HANGUL SYLLABLE CWEH -CDE9..CE03 ; LVT # Lo [27] HANGUL SYLLABLE CWIG..HANGUL SYLLABLE CWIH -CE05..CE1F ; LVT # Lo [27] HANGUL SYLLABLE CYUG..HANGUL SYLLABLE CYUH -CE21..CE3B ; LVT # Lo [27] HANGUL SYLLABLE CEUG..HANGUL SYLLABLE CEUH -CE3D..CE57 ; LVT # Lo [27] HANGUL SYLLABLE CYIG..HANGUL SYLLABLE CYIH -CE59..CE73 ; LVT # Lo [27] HANGUL SYLLABLE CIG..HANGUL SYLLABLE CIH -CE75..CE8F ; LVT # Lo [27] HANGUL SYLLABLE KAG..HANGUL SYLLABLE KAH -CE91..CEAB ; LVT # Lo [27] HANGUL SYLLABLE KAEG..HANGUL SYLLABLE KAEH -CEAD..CEC7 ; LVT # Lo [27] HANGUL SYLLABLE KYAG..HANGUL SYLLABLE KYAH -CEC9..CEE3 ; LVT # Lo [27] HANGUL SYLLABLE KYAEG..HANGUL SYLLABLE KYAEH -CEE5..CEFF ; LVT # Lo [27] HANGUL SYLLABLE KEOG..HANGUL SYLLABLE KEOH -CF01..CF1B ; LVT # Lo [27] HANGUL SYLLABLE KEG..HANGUL SYLLABLE KEH -CF1D..CF37 ; LVT # Lo [27] HANGUL SYLLABLE KYEOG..HANGUL SYLLABLE KYEOH -CF39..CF53 ; LVT # Lo [27] HANGUL SYLLABLE KYEG..HANGUL SYLLABLE KYEH -CF55..CF6F ; LVT # Lo [27] HANGUL SYLLABLE KOG..HANGUL SYLLABLE KOH -CF71..CF8B ; LVT # Lo [27] HANGUL SYLLABLE KWAG..HANGUL SYLLABLE KWAH -CF8D..CFA7 ; LVT # Lo [27] HANGUL SYLLABLE KWAEG..HANGUL SYLLABLE KWAEH -CFA9..CFC3 ; LVT # Lo [27] HANGUL SYLLABLE KOEG..HANGUL SYLLABLE KOEH -CFC5..CFDF ; LVT # Lo [27] HANGUL SYLLABLE KYOG..HANGUL SYLLABLE KYOH -CFE1..CFFB ; LVT # Lo [27] HANGUL SYLLABLE KUG..HANGUL SYLLABLE KUH -CFFD..D017 ; LVT # Lo [27] HANGUL SYLLABLE KWEOG..HANGUL SYLLABLE KWEOH -D019..D033 ; LVT # Lo [27] HANGUL SYLLABLE KWEG..HANGUL SYLLABLE KWEH -D035..D04F ; LVT # Lo [27] HANGUL SYLLABLE KWIG..HANGUL SYLLABLE KWIH -D051..D06B ; LVT # Lo [27] HANGUL SYLLABLE KYUG..HANGUL SYLLABLE KYUH -D06D..D087 ; LVT # Lo [27] HANGUL SYLLABLE KEUG..HANGUL SYLLABLE KEUH -D089..D0A3 ; LVT # Lo [27] HANGUL SYLLABLE KYIG..HANGUL SYLLABLE KYIH -D0A5..D0BF ; LVT # Lo [27] HANGUL SYLLABLE KIG..HANGUL SYLLABLE KIH -D0C1..D0DB ; LVT # Lo [27] HANGUL SYLLABLE TAG..HANGUL SYLLABLE TAH -D0DD..D0F7 ; LVT # Lo [27] HANGUL SYLLABLE TAEG..HANGUL SYLLABLE TAEH -D0F9..D113 ; LVT # Lo [27] HANGUL SYLLABLE TYAG..HANGUL SYLLABLE TYAH -D115..D12F ; LVT # Lo [27] HANGUL SYLLABLE TYAEG..HANGUL SYLLABLE TYAEH -D131..D14B ; LVT # Lo [27] HANGUL SYLLABLE TEOG..HANGUL SYLLABLE TEOH -D14D..D167 ; LVT # Lo [27] HANGUL SYLLABLE TEG..HANGUL SYLLABLE TEH -D169..D183 ; LVT # Lo [27] HANGUL SYLLABLE TYEOG..HANGUL SYLLABLE TYEOH -D185..D19F ; LVT # Lo [27] HANGUL SYLLABLE TYEG..HANGUL SYLLABLE TYEH -D1A1..D1BB ; LVT # Lo [27] HANGUL SYLLABLE TOG..HANGUL SYLLABLE TOH -D1BD..D1D7 ; LVT # Lo [27] HANGUL SYLLABLE TWAG..HANGUL SYLLABLE TWAH -D1D9..D1F3 ; LVT # Lo [27] HANGUL SYLLABLE TWAEG..HANGUL SYLLABLE TWAEH -D1F5..D20F ; LVT # Lo [27] HANGUL SYLLABLE TOEG..HANGUL SYLLABLE TOEH -D211..D22B ; LVT # Lo [27] HANGUL SYLLABLE TYOG..HANGUL SYLLABLE TYOH -D22D..D247 ; LVT # Lo [27] HANGUL SYLLABLE TUG..HANGUL SYLLABLE TUH -D249..D263 ; LVT # Lo [27] HANGUL SYLLABLE TWEOG..HANGUL SYLLABLE TWEOH -D265..D27F ; LVT # Lo [27] HANGUL SYLLABLE TWEG..HANGUL SYLLABLE TWEH -D281..D29B ; LVT # Lo [27] HANGUL SYLLABLE TWIG..HANGUL SYLLABLE TWIH -D29D..D2B7 ; LVT # Lo [27] HANGUL SYLLABLE TYUG..HANGUL SYLLABLE TYUH -D2B9..D2D3 ; LVT # Lo [27] HANGUL SYLLABLE TEUG..HANGUL SYLLABLE TEUH -D2D5..D2EF ; LVT # Lo [27] HANGUL SYLLABLE TYIG..HANGUL SYLLABLE TYIH -D2F1..D30B ; LVT # Lo [27] HANGUL SYLLABLE TIG..HANGUL SYLLABLE TIH -D30D..D327 ; LVT # Lo [27] HANGUL SYLLABLE PAG..HANGUL SYLLABLE PAH -D329..D343 ; LVT # Lo [27] HANGUL SYLLABLE PAEG..HANGUL SYLLABLE PAEH -D345..D35F ; LVT # Lo [27] HANGUL SYLLABLE PYAG..HANGUL SYLLABLE PYAH -D361..D37B ; LVT # Lo [27] HANGUL SYLLABLE PYAEG..HANGUL SYLLABLE PYAEH -D37D..D397 ; LVT # Lo [27] HANGUL SYLLABLE PEOG..HANGUL SYLLABLE PEOH -D399..D3B3 ; LVT # Lo [27] HANGUL SYLLABLE PEG..HANGUL SYLLABLE PEH -D3B5..D3CF ; LVT # Lo [27] HANGUL SYLLABLE PYEOG..HANGUL SYLLABLE PYEOH -D3D1..D3EB ; LVT # Lo [27] HANGUL SYLLABLE PYEG..HANGUL SYLLABLE PYEH -D3ED..D407 ; LVT # Lo [27] HANGUL SYLLABLE POG..HANGUL SYLLABLE POH -D409..D423 ; LVT # Lo [27] HANGUL SYLLABLE PWAG..HANGUL SYLLABLE PWAH -D425..D43F ; LVT # Lo [27] HANGUL SYLLABLE PWAEG..HANGUL SYLLABLE PWAEH -D441..D45B ; LVT # Lo [27] HANGUL SYLLABLE POEG..HANGUL SYLLABLE POEH -D45D..D477 ; LVT # Lo [27] HANGUL SYLLABLE PYOG..HANGUL SYLLABLE PYOH -D479..D493 ; LVT # Lo [27] HANGUL SYLLABLE PUG..HANGUL SYLLABLE PUH -D495..D4AF ; LVT # Lo [27] HANGUL SYLLABLE PWEOG..HANGUL SYLLABLE PWEOH -D4B1..D4CB ; LVT # Lo [27] HANGUL SYLLABLE PWEG..HANGUL SYLLABLE PWEH -D4CD..D4E7 ; LVT # Lo [27] HANGUL SYLLABLE PWIG..HANGUL SYLLABLE PWIH -D4E9..D503 ; LVT # Lo [27] HANGUL SYLLABLE PYUG..HANGUL SYLLABLE PYUH -D505..D51F ; LVT # Lo [27] HANGUL SYLLABLE PEUG..HANGUL SYLLABLE PEUH -D521..D53B ; LVT # Lo [27] HANGUL SYLLABLE PYIG..HANGUL SYLLABLE PYIH -D53D..D557 ; LVT # Lo [27] HANGUL SYLLABLE PIG..HANGUL SYLLABLE PIH -D559..D573 ; LVT # Lo [27] HANGUL SYLLABLE HAG..HANGUL SYLLABLE HAH -D575..D58F ; LVT # Lo [27] HANGUL SYLLABLE HAEG..HANGUL SYLLABLE HAEH -D591..D5AB ; LVT # Lo [27] HANGUL SYLLABLE HYAG..HANGUL SYLLABLE HYAH -D5AD..D5C7 ; LVT # Lo [27] HANGUL SYLLABLE HYAEG..HANGUL SYLLABLE HYAEH -D5C9..D5E3 ; LVT # Lo [27] HANGUL SYLLABLE HEOG..HANGUL SYLLABLE HEOH -D5E5..D5FF ; LVT # Lo [27] HANGUL SYLLABLE HEG..HANGUL SYLLABLE HEH -D601..D61B ; LVT # Lo [27] HANGUL SYLLABLE HYEOG..HANGUL SYLLABLE HYEOH -D61D..D637 ; LVT # Lo [27] HANGUL SYLLABLE HYEG..HANGUL SYLLABLE HYEH -D639..D653 ; LVT # Lo [27] HANGUL SYLLABLE HOG..HANGUL SYLLABLE HOH -D655..D66F ; LVT # Lo [27] HANGUL SYLLABLE HWAG..HANGUL SYLLABLE HWAH -D671..D68B ; LVT # Lo [27] HANGUL SYLLABLE HWAEG..HANGUL SYLLABLE HWAEH -D68D..D6A7 ; LVT # Lo [27] HANGUL SYLLABLE HOEG..HANGUL SYLLABLE HOEH -D6A9..D6C3 ; LVT # Lo [27] HANGUL SYLLABLE HYOG..HANGUL SYLLABLE HYOH -D6C5..D6DF ; LVT # Lo [27] HANGUL SYLLABLE HUG..HANGUL SYLLABLE HUH -D6E1..D6FB ; LVT # Lo [27] HANGUL SYLLABLE HWEOG..HANGUL SYLLABLE HWEOH -D6FD..D717 ; LVT # Lo [27] HANGUL SYLLABLE HWEG..HANGUL SYLLABLE HWEH -D719..D733 ; LVT # Lo [27] HANGUL SYLLABLE HWIG..HANGUL SYLLABLE HWIH -D735..D74F ; LVT # Lo [27] HANGUL SYLLABLE HYUG..HANGUL SYLLABLE HYUH -D751..D76B ; LVT # Lo [27] HANGUL SYLLABLE HEUG..HANGUL SYLLABLE HEUH -D76D..D787 ; LVT # Lo [27] HANGUL SYLLABLE HYIG..HANGUL SYLLABLE HYIH -D789..D7A3 ; LVT # Lo [27] HANGUL SYLLABLE HIG..HANGUL SYLLABLE HIH - -# Total code points: 10773 - -# EOF diff --git a/tools-for-build/Jamo.txt b/tools-for-build/Jamo.txt index 16101246f3..f2b5ecb5ca 100644 --- a/tools-for-build/Jamo.txt +++ b/tools-for-build/Jamo.txt @@ -1,14 +1,14 @@ -# Jamo-7.0.0.txt -# Date: 2014-01-23, 00:00:00 GMT [KW, LI] +# Jamo-10.0.0.txt +# Date: 2017-02-15, 00:00:00 GMT [KW, LI] +# © 2017 Unicode®, Inc. +# For terms of use, see http://www.unicode.org/terms_of_use.html # # Unicode Character Database -# Copyright (c) 1991-2014 Unicode, Inc. -# For terms of use, see http://www.unicode.org/terms_of_use.html # For documentation, see http://www.unicode.org/reports/tr44/ # # This file defines the Jamo_Short_Name property. # -# See Section 3.12 of The Unicode Standard, Version 7.0 +# See Section 3.12 of The Unicode Standard, Version 10.0 # for more information. # # Each line contains two fields, separated by a semicolon. diff --git a/tools-for-build/LineBreak.txt b/tools-for-build/LineBreak.txt index b627f874d0..d80210bde3 100644 --- a/tools-for-build/LineBreak.txt +++ b/tools-for-build/LineBreak.txt @@ -1,45 +1,45 @@ -# LineBreak-8.0.0.txt -# Date: 2015-02-13, 09:15:00 GMT [KW, LI] +# LineBreak-10.0.0.txt +# Date: 2017-03-08, 02:00:00 GMT [KW, LI] +# © 2017 Unicode®, Inc. +# Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries. +# For terms of use, see http://www.unicode.org/terms_of_use.html +# +# Unicode Character Database +# For documentation, see http://www.unicode.org/reports/tr44/ # # Line_Break Property # # This file is a normative contributory data file in the # Unicode Character Database. -# It contains both normative and informative data. -# -# Copyright (c) 1991-2015 Unicode, Inc. -# For terms of use, see http://www.unicode.org/terms_of_use.html # # The format is two fields separated by a semicolon. # Field 0: Unicode code point value or range of code point values # Field 1: Line_Break property, consisting of one of the following values: -# Normative: -# "BK", "CR", "LF", "CM", "SG", "GL", "CB", "SP", "ZW", -# "NL", "WJ", "JL", "JV", "JT", "H2", "H3" -# Informative: -# "XX", "OP", "CL", "CP", "QU", "NS", "EX", "SY", -# "IS", "PR", "PO", "NU", "AL", "ID", "IN", "HY", -# "BB", "BA", "SA", "AI", "B2", "HL", "CJ", "RI" +# Non-tailorable: +# "BK", "CM", "CR", "GL", "LF", "NL", "SP", "WJ", "ZW", "ZWJ" +# Tailorable: +# "AI", "AL", "B2", "BA", "BB", "CB", "CJ", "CL", "CP", "EB", +# "EM", "EX", "H2", "H3", "HL", "HY", "ID", "IN", "IS", "JL", +# "JT", "JV", "NS", "NU", "OP", "PO", "PR", "QU", "RI", "SA", +# "SG", "SY", "XX" # - All code points, assigned and unassigned, that are not listed -# explicitly are given the value "XX". -# The unassigned code points that default to "ID" include ranges in the -# following blocks: -# CJK Unified Ideographs Extension A: U+3400..U+4DBF -# CJK Unified Ideographs: U+4E00..U+9FFF -# CJK Compatibility Ideographs: U+F900..U+FAFF -# CJK Unified Ideographs Extension B: U+20000..U+2A6DF -# CJK Unified Ideographs Extension C: U+2A700..U+2B73F -# CJK Unified Ideographs Extension D: U+2B740..U+2B81F -# CJK Unified Ideographs Extension E: U+2B820..U+2CEAF -# CJK Compatibility Ideographs Supplement: U+2F800..U+2FA1F -# and any other reserved code points on -# Planes 2 and 3: U+20000..U+2FFFD -# U+30000..U+3FFFD -# The unassigned code points that default to "PR" comprise a range in the -# following block: -# Currency Symbols: U+20A0..U+20CF -# - Character ranges are specified as for other property files in -# the Unicode Character Database. +# explicitly are given the value "XX". +# - The unassigned code points in the following blocks default to "ID": +# CJK Unified Ideographs Extension A: U+3400..U+4DBF +# CJK Unified Ideographs: U+4E00..U+9FFF +# CJK Compatibility Ideographs: U+F900..U+FAFF +# - All undesignated code points in Planes 2 and 3, whether inside or +# outside of allocated blocks, default to "ID": +# Plane 2: U+20000..U+2FFFD +# Plane 3: U+30000..U+3FFFD +# - All unassigned code points in the following Plane 1 range, whether +# inside or outside of allocated blocks, also default to "ID": +# Plane 1 range: U+1F000..U+1FFFD +# - The unassigned code points in the following block default to "PR": +# Currency Symbols: U+20A0..U+20CF +# +# Character ranges are specified as for other property files in the +# Unicode Character Database. # # For legacy reasons, there are no spaces before or after the semicolon # which separates the two fields. The comments following the number sign @@ -273,7 +273,11 @@ 0840..0858;AL # Lo [25] MANDAIC LETTER HALQA..MANDAIC LETTER AIN 0859..085B;CM # Mn [3] MANDAIC AFFRICATION MARK..MANDAIC GEMINATION MARK 085E;AL # Po MANDAIC PUNCTUATION +0860..086A;AL # Lo [11] SYRIAC LETTER MALAYALAM NGA..SYRIAC LETTER MALAYALAM SSA 08A0..08B4;AL # Lo [21] ARABIC LETTER BEH WITH SMALL V BELOW..ARABIC LETTER KAF WITH DOT BELOW +08B6..08BD;AL # Lo [8] ARABIC LETTER BEH WITH SMALL MEEM ABOVE..ARABIC LETTER AFRICAN NOON +08D4..08E1;CM # Mn [14] ARABIC SMALL HIGH WORD AR-RUB..ARABIC SMALL HIGH SIGN SAFHA +08E2;AL # Cf ARABIC DISPUTED END OF AYAH 08E3..08FF;CM # Mn [29] ARABIC TURNED DAMMA BELOW..ARABIC MARK SIDEWAYS NOON GHUNNA 0900..0902;CM # Mn [3] DEVANAGARI SIGN INVERTED CANDRABINDU..DEVANAGARI SIGN ANUSVARA 0903;CM # Mc DEVANAGARI SIGN VISARGA @@ -324,6 +328,8 @@ 09F9;PO # No BENGALI CURRENCY DENOMINATOR SIXTEEN 09FA;AL # So BENGALI ISSHAR 09FB;PR # Sc BENGALI GANDA MARK +09FC;AL # Lo BENGALI LETTER VEDIC ANUSVARA +09FD;AL # Po BENGALI ABBREVIATION SIGN 0A01..0A02;CM # Mn [2] GURMUKHI SIGN ADAK BINDI..GURMUKHI SIGN BINDI 0A03;CM # Mc GURMUKHI SIGN VISARGA 0A05..0A0A;AL # Lo [6] GURMUKHI LETTER A..GURMUKHI LETTER UU @@ -368,6 +374,7 @@ 0AF0;AL # Po GUJARATI ABBREVIATION SIGN 0AF1;PR # Sc GUJARATI RUPEE SIGN 0AF9;AL # Lo GUJARATI LETTER ZHA +0AFA..0AFF;CM # Mn [6] GUJARATI SIGN SUKUN..GUJARATI SIGN TWO-CIRCLE NUKTA ABOVE 0B01;CM # Mn ORIYA SIGN CANDRABINDU 0B02..0B03;CM # Mc [2] ORIYA SIGN ANUSVARA..ORIYA SIGN VISARGA 0B05..0B0C;AL # Lo [8] ORIYA LETTER A..ORIYA LETTER VOCALIC L @@ -436,6 +443,7 @@ 0C66..0C6F;NU # Nd [10] TELUGU DIGIT ZERO..TELUGU DIGIT NINE 0C78..0C7E;AL # No [7] TELUGU FRACTION DIGIT ZERO FOR ODD POWERS OF FOUR..TELUGU FRACTION DIGIT THREE FOR EVEN POWERS OF FOUR 0C7F;AL # So TELUGU SIGN TUUMU +0C80;AL # Lo KANNADA SIGN SPACING CANDRABINDU 0C81;CM # Mn KANNADA SIGN CANDRABINDU 0C82..0C83;CM # Mc [2] KANNADA SIGN ANUSVARA..KANNADA SIGN VISARGA 0C85..0C8C;AL # Lo [8] KANNADA LETTER A..KANNADA LETTER VOCALIC L @@ -458,11 +466,12 @@ 0CE2..0CE3;CM # Mn [2] KANNADA VOWEL SIGN VOCALIC L..KANNADA VOWEL SIGN VOCALIC LL 0CE6..0CEF;NU # Nd [10] KANNADA DIGIT ZERO..KANNADA DIGIT NINE 0CF1..0CF2;AL # Lo [2] KANNADA SIGN JIHVAMULIYA..KANNADA SIGN UPADHMANIYA -0D01;CM # Mn MALAYALAM SIGN CANDRABINDU +0D00..0D01;CM # Mn [2] MALAYALAM SIGN COMBINING ANUSVARA ABOVE..MALAYALAM SIGN CANDRABINDU 0D02..0D03;CM # Mc [2] MALAYALAM SIGN ANUSVARA..MALAYALAM SIGN VISARGA 0D05..0D0C;AL # Lo [8] MALAYALAM LETTER A..MALAYALAM LETTER VOCALIC L 0D0E..0D10;AL # Lo [3] MALAYALAM LETTER E..MALAYALAM LETTER AI 0D12..0D3A;AL # Lo [41] MALAYALAM LETTER O..MALAYALAM LETTER TTTA +0D3B..0D3C;CM # Mn [2] MALAYALAM SIGN VERTICAL BAR VIRAMA..MALAYALAM SIGN CIRCULAR VIRAMA 0D3D;AL # Lo MALAYALAM SIGN AVAGRAHA 0D3E..0D40;CM # Mc [3] MALAYALAM VOWEL SIGN AA..MALAYALAM VOWEL SIGN II 0D41..0D44;CM # Mn [4] MALAYALAM VOWEL SIGN U..MALAYALAM VOWEL SIGN VOCALIC RR @@ -470,11 +479,14 @@ 0D4A..0D4C;CM # Mc [3] MALAYALAM VOWEL SIGN O..MALAYALAM VOWEL SIGN AU 0D4D;CM # Mn MALAYALAM SIGN VIRAMA 0D4E;AL # Lo MALAYALAM LETTER DOT REPH +0D4F;AL # So MALAYALAM SIGN PARA +0D54..0D56;AL # Lo [3] MALAYALAM LETTER CHILLU M..MALAYALAM LETTER CHILLU LLL 0D57;CM # Mc MALAYALAM AU LENGTH MARK +0D58..0D5E;AL # No [7] MALAYALAM FRACTION ONE ONE-HUNDRED-AND-SIXTIETH..MALAYALAM FRACTION ONE FIFTH 0D5F..0D61;AL # Lo [3] MALAYALAM LETTER ARCHAIC II..MALAYALAM LETTER VOCALIC LL 0D62..0D63;CM # Mn [2] MALAYALAM VOWEL SIGN VOCALIC L..MALAYALAM VOWEL SIGN VOCALIC LL 0D66..0D6F;NU # Nd [10] MALAYALAM DIGIT ZERO..MALAYALAM DIGIT NINE -0D70..0D75;AL # No [6] MALAYALAM NUMBER TEN..MALAYALAM FRACTION THREE QUARTERS +0D70..0D78;AL # No [9] MALAYALAM NUMBER TEN..MALAYALAM FRACTION THREE SIXTEENTHS 0D79;PO # So MALAYALAM DATE MARK 0D7A..0D7F;AL # Lo [6] MALAYALAM LETTER CHILLU NN..MALAYALAM LETTER CHILLU K 0D82..0D83;CM # Mc [2] SINHALA SIGN ANUSVARAYA..SINHALA SIGN VISARGAYA @@ -700,7 +712,9 @@ 1820..1842;AL # Lo [35] MONGOLIAN LETTER A..MONGOLIAN LETTER CHI 1843;AL # Lm MONGOLIAN LETTER TODO LONG VOWEL SIGN 1844..1877;AL # Lo [52] MONGOLIAN LETTER TODO E..MONGOLIAN LETTER MANCHU ZHA -1880..18A8;AL # Lo [41] MONGOLIAN LETTER ALI GALI ANUSVARA ONE..MONGOLIAN LETTER MANCHU ALI GALI BHA +1880..1884;AL # Lo [5] MONGOLIAN LETTER ALI GALI ANUSVARA ONE..MONGOLIAN LETTER ALI GALI INVERTED UBADAMA +1885..1886;CM # Mn [2] MONGOLIAN LETTER ALI GALI BALUDA..MONGOLIAN LETTER ALI GALI THREE BALUDA +1887..18A8;AL # Lo [34] MONGOLIAN LETTER ALI GALI A..MONGOLIAN LETTER MANCHU ALI GALI BHA 18A9;CM # Mn MONGOLIAN LETTER ALI GALI DAGALGA 18AA;AL # Lo MONGOLIAN LETTER MANCHU ALI GALI LHA 18B0..18F5;AL # Lo [70] CANADIAN SYLLABICS OY..CANADIAN SYLLABICS CARRIER DENTAL S @@ -802,6 +816,7 @@ 1C5A..1C77;AL # Lo [30] OL CHIKI LETTER LA..OL CHIKI LETTER OH 1C78..1C7D;AL # Lm [6] OL CHIKI MU TTUDDAG..OL CHIKI AHAD 1C7E..1C7F;BA # Po [2] OL CHIKI PUNCTUATION MUCAAD..OL CHIKI PUNCTUATION DOUBLE MUCAAD +1C80..1C88;AL # Ll [9] CYRILLIC SMALL LETTER ROUNDED VE..CYRILLIC SMALL LETTER UNBLENDED UK 1CC0..1CC7;AL # Po [8] SUNDANESE PUNCTUATION BINDU SURYA..SUNDANESE PUNCTUATION BINDU BA SATANGA 1CD0..1CD2;CM # Mn [3] VEDIC TONE KARSHANA..VEDIC TONE PRENKHA 1CD3;AL # Po VEDIC SIGN NIHSHVASA @@ -814,6 +829,7 @@ 1CF2..1CF3;CM # Mc [2] VEDIC SIGN ARDHAVISARGA..VEDIC SIGN ROTATED ARDHAVISARGA 1CF4;CM # Mn VEDIC TONE CANDRA ABOVE 1CF5..1CF6;AL # Lo [2] VEDIC SIGN JIHVAMULIYA..VEDIC SIGN UPADHMANIYA +1CF7;CM # Mc VEDIC SIGN ATIKRAMA 1CF8..1CF9;CM # Mn [2] VEDIC TONE RING ABOVE..VEDIC TONE DOUBLE RING ABOVE 1D00..1D2B;AL # Ll [44] LATIN LETTER SMALL CAPITAL A..CYRILLIC LETTER SMALL CAPITAL EL 1D2C..1D6A;AL # Lm [63] MODIFIER LETTER CAPITAL A..GREEK SUBSCRIPT SMALL LETTER CHI @@ -822,8 +838,8 @@ 1D79..1D7F;AL # Ll [7] LATIN SMALL LETTER INSULAR G..LATIN SMALL LETTER UPSILON WITH STROKE 1D80..1D9A;AL # Ll [27] LATIN SMALL LETTER B WITH PALATAL HOOK..LATIN SMALL LETTER EZH WITH RETROFLEX HOOK 1D9B..1DBF;AL # Lm [37] MODIFIER LETTER SMALL TURNED ALPHA..MODIFIER LETTER SMALL THETA -1DC0..1DF5;CM # Mn [54] COMBINING DOTTED GRAVE ACCENT..COMBINING UP TACK ABOVE -1DFC..1DFF;CM # Mn [4] COMBINING DOUBLE INVERTED BREVE BELOW..COMBINING RIGHT ARROWHEAD AND DOWN ARROWHEAD BELOW +1DC0..1DF9;CM # Mn [58] COMBINING DOTTED GRAVE ACCENT..COMBINING WIDE INVERTED BRIDGE BELOW +1DFB..1DFF;CM # Mn [5] COMBINING DELETION MARK..COMBINING RIGHT ARROWHEAD AND DOWN ARROWHEAD BELOW 1E00..1EFF;AL # L& [256] LATIN CAPITAL LETTER A WITH RING BELOW..LATIN SMALL LETTER Y WITH LOOP 1F00..1F15;AL # L& [22] GREEK SMALL LETTER ALPHA WITH PSILI..GREEK SMALL LETTER EPSILON WITH DASIA AND OXIA 1F18..1F1D;AL # Lu [6] GREEK CAPITAL LETTER EPSILON WITH PSILI..GREEK CAPITAL LETTER EPSILON WITH DASIA AND OXIA @@ -855,7 +871,9 @@ 2007;GL # Zs FIGURE SPACE 2008..200A;BA # Zs [3] PUNCTUATION SPACE..HAIR SPACE 200B;ZW # Cf ZERO WIDTH SPACE -200C..200F;CM # Cf [4] ZERO WIDTH NON-JOINER..RIGHT-TO-LEFT MARK +200C;CM # Cf ZERO WIDTH NON-JOINER +200D;ZWJ # Cf ZERO WIDTH JOINER +200E..200F;CM # Cf [2] LEFT-TO-RIGHT MARK..RIGHT-TO-LEFT MARK 2010;BA # Pd HYPHEN 2011;GL # Pd NON-BREAKING HYPHEN 2012..2013;BA # Pd [2] FIGURE DASH..EN DASH @@ -928,7 +946,8 @@ 20BB;PO # Sc NORDIC MARK SIGN 20BC..20BD;PR # Sc [2] MANAT SIGN..RUBLE SIGN 20BE;PO # Sc LARI SIGN -20BF..20CF;PR # Cn [17] <reserved-20BF>..<reserved-20CF> +20BF;PR # Sc BITCOIN SIGN +20C0..20CF;PR # Cn [16] <reserved-20C0>..<reserved-20CF> 20D0..20DC;CM # Mn [13] COMBINING LEFT HARPOON ABOVE..COMBINING FOUR DOTS ABOVE 20DD..20E0;CM # Me [4] COMBINING ENCLOSING CIRCLE..COMBINING ENCLOSING CIRCLE BACKSLASH 20E1;CM # Mn COMBINING LEFT RIGHT ARROW ABOVE @@ -1091,7 +1110,7 @@ 23DC..23E1;AL # Sm [6] TOP PARENTHESIS..BOTTOM TORTOISE SHELL BRACKET 23E2..23EF;AL # So [14] WHITE TRAPEZIUM..BLACK RIGHT-POINTING TRIANGLE WITH DOUBLE VERTICAL BAR 23F0..23F3;ID # So [4] ALARM CLOCK..HOURGLASS WITH FLOWING SAND -23F4..23FA;AL # So [7] BLACK MEDIUM LEFT-POINTING TRIANGLE..BLACK CIRCLE FOR RECORD +23F4..23FF;AL # So [12] BLACK MEDIUM LEFT-POINTING TRIANGLE..OBSERVER EYE SYMBOL 2400..2426;AL # So [39] SYMBOL FOR NULL..SYMBOL FOR SUBSTITUTE FORM TWO 2440..244A;AL # So [11] OCR HOOK..OCR DOUBLE BACKSLASH 2460..249B;AI # No [60] CIRCLED DIGIT ONE..NUMBER TWENTY FULL STOP @@ -1143,7 +1162,9 @@ 2616..2617;AI # So [2] WHITE SHOGI PIECE..BLACK SHOGI PIECE 2618;ID # So SHAMROCK 2619;AL # So REVERSED ROTATED FLORAL HEART BULLET -261A..261F;ID # So [6] BLACK LEFT POINTING INDEX..WHITE DOWN POINTING INDEX +261A..261C;ID # So [3] BLACK LEFT POINTING INDEX..WHITE LEFT POINTING INDEX +261D;EB # So WHITE UP POINTING INDEX +261E..261F;ID # So [2] WHITE RIGHT POINTING INDEX..WHITE DOWN POINTING INDEX 2620..2638;AL # So [25] SKULL AND CROSSBONES..WHEEL OF DHARMA 2639..263B;ID # So [3] WHITE FROWNING FACE..BLACK SMILING FACE 263C..263F;AL # So [4] WHITE SUN WITH RAYS..MERCURY @@ -1188,19 +1209,23 @@ 26EB..26F0;AI # So [6] CASTLE..MOUNTAIN 26F1..26F5;ID # So [5] UMBRELLA ON GROUND..SAILBOAT 26F6;AI # So SQUARE FOUR CORNERS -26F7..26FA;ID # So [4] SKIER..TENT +26F7..26F8;ID # So [2] SKIER..ICE SKATE +26F9;EB # So PERSON WITH BALL +26FA;ID # So TENT 26FB..26FC;AI # So [2] JAPANESE BANK SYMBOL..HEADSTONE GRAVEYARD SYMBOL 26FD..26FF;ID # So [3] FUEL PUMP..WHITE FLAG WITH HORIZONTAL MIDDLE BLACK STRIPE 2700..2704;ID # So [5] BLACK SAFETY SCISSORS..WHITE SCISSORS 2705..2707;AL # So [3] WHITE HEAVY CHECK MARK..TAPE DRIVE -2708..270D;ID # So [6] AIRPLANE..WRITING HAND +2708..2709;ID # So [2] AIRPLANE..ENVELOPE +270A..270D;EB # So [4] RAISED FIST..WRITING HAND 270E..2756;AL # So [73] LOWER RIGHT PENCIL..BLACK DIAMOND MINUS WHITE X 2757;AI # So HEAVY EXCLAMATION MARK SYMBOL 2758..275A;AL # So [3] LIGHT VERTICAL BAR..HEAVY VERTICAL BAR 275B..2760;QU # So [6] HEAVY SINGLE TURNED COMMA QUOTATION MARK ORNAMENT..HEAVY LOW DOUBLE COMMA QUOTATION MARK ORNAMENT 2761;AL # So CURVED STEM PARAGRAPH SIGN ORNAMENT 2762..2763;EX # So [2] HEAVY EXCLAMATION MARK ORNAMENT..HEAVY HEART EXCLAMATION MARK ORNAMENT -2764..2767;AL # So [4] HEAVY BLACK HEART..ROTATED FLORAL HEART BULLET +2764;ID # So HEAVY BLACK HEART +2765..2767;AL # So [3] ROTATED HEAVY BLACK HEART BULLET..ROTATED FLORAL HEART BULLET 2768;OP # Ps MEDIUM LEFT PARENTHESIS ORNAMENT 2769;CL # Pe MEDIUM RIGHT PARENTHESIS ORNAMENT 276A;OP # Ps MEDIUM FLATTENED LEFT PARENTHESIS ORNAMENT @@ -1277,7 +1302,7 @@ 2B76..2B95;AL # So [32] NORTH WEST TRIANGLE-HEADED ARROW TO BAR..RIGHTWARDS BLACK ARROW 2B98..2BB9;AL # So [34] THREE-D TOP-LIGHTED LEFTWARDS EQUILATERAL ARROWHEAD..UP ARROWHEAD IN A RECTANGLE BOX 2BBD..2BC8;AL # So [12] BALLOT BOX WITH LIGHT X..BLACK MEDIUM RIGHT-POINTING TRIANGLE CENTRED -2BCA..2BD1;AL # So [8] TOP HALF BLACK CIRCLE..UNCERTAINTY SIGN +2BCA..2BD2;AL # So [9] TOP HALF BLACK CIRCLE..GROUP MARK 2BEC..2BEF;AL # So [4] LEFTWARDS TWO-HEADED ARROW WITH TRIANGLE ARROWHEADS..DOWNWARDS TWO-HEADED ARROW WITH TRIANGLE ARROWHEADS 2C00..2C2E;AL # Lu [47] GLAGOLITIC CAPITAL LETTER AZU..GLAGOLITIC CAPITAL LETTER LATINATE MYSLITE 2C30..2C5E;AL # Ll [47] GLAGOLITIC SMALL LETTER AZU..GLAGOLITIC SMALL LETTER LATINATE MYSLITE @@ -1355,6 +1380,7 @@ 2E40;BA # Pd DOUBLE HYPHEN 2E41;BA # Po REVERSED COMMA 2E42;OP # Ps DOUBLE LOW-REVERSED-9 QUOTATION MARK +2E43..2E49;BA # Po [7] DASH WITH LEFT UPTURN..DOUBLE STACKED COMMA 2E80..2E99;ID # So [26] CJK RADICAL REPEAT..CJK RADICAL RAP 2E9B..2EF3;ID # So [89] CJK RADICAL CHOKE..CJK RADICAL C-SIMPLIFIED TURTLE 2F00..2FD5;ID # So [214] KANGXI RADICAL ONE..KANGXI RADICAL FLUTE @@ -1453,7 +1479,7 @@ 30FC;CJ # Lm KATAKANA-HIRAGANA PROLONGED SOUND MARK 30FD..30FE;NS # Lm [2] KATAKANA ITERATION MARK..KATAKANA VOICED ITERATION MARK 30FF;ID # Lo KATAKANA DIGRAPH KOTO -3105..312D;ID # Lo [41] BOPOMOFO LETTER B..BOPOMOFO LETTER IH +3105..312E;ID # Lo [42] BOPOMOFO LETTER B..BOPOMOFO LETTER O WITH DOT ABOVE 3131..318E;ID # Lo [94] HANGUL LETTER KIYEOK..HANGUL LETTER ARAEAE 3190..3191;ID # So [2] IDEOGRAPHIC ANNOTATION LINKING MARK..IDEOGRAPHIC ANNOTATION REVERSE MARK 3192..3195;ID # No [4] IDEOGRAPHIC ANNOTATION ONE MARK..IDEOGRAPHIC ANNOTATION FOUR MARK @@ -1476,8 +1502,8 @@ 3400..4DB5;ID # Lo [6582] CJK UNIFIED IDEOGRAPH-3400..CJK UNIFIED IDEOGRAPH-4DB5 4DB6..4DBF;ID # Cn [10] <reserved-4DB6>..<reserved-4DBF> 4DC0..4DFF;AL # So [64] HEXAGRAM FOR THE CREATIVE HEAVEN..HEXAGRAM FOR BEFORE COMPLETION -4E00..9FD5;ID # Lo [20950] CJK UNIFIED IDEOGRAPH-4E00..CJK UNIFIED IDEOGRAPH-9FD5 -9FD6..9FFF;ID # Cn [42] <reserved-9FD6>..<reserved-9FFF> +4E00..9FEA;ID # Lo [20971] CJK UNIFIED IDEOGRAPH-4E00..CJK UNIFIED IDEOGRAPH-9FEA +9FEB..9FFF;ID # Cn [21] <reserved-9FEB>..<reserved-9FFF> A000..A014;ID # Lo [21] YI SYLLABLE IT..YI SYLLABLE E A015;NS # Lm YI SYLLABLE WU A016..A48C;ID # Lo [1143] YI SYLLABLE BIT..YI SYLLABLE YYR @@ -1519,7 +1545,7 @@ A788;AL # Lm MODIFIER LETTER LOW CIRCUMFLEX ACCENT A789..A78A;AL # Sk [2] MODIFIER LETTER COLON..MODIFIER LETTER SHORT EQUALS SIGN A78B..A78E;AL # L& [4] LATIN CAPITAL LETTER SALTILLO..LATIN SMALL LETTER L WITH RETROFLEX HOOK AND BELT A78F;AL # Lo LATIN LETTER SINOLOGICAL DOT -A790..A7AD;AL # L& [30] LATIN CAPITAL LETTER N WITH DESCENDER..LATIN CAPITAL LETTER L WITH BELT +A790..A7AE;AL # L& [31] LATIN CAPITAL LETTER N WITH DESCENDER..LATIN CAPITAL LETTER SMALL CAPITAL I A7B0..A7B7;AL # L& [8] LATIN CAPITAL LETTER TURNED K..LATIN SMALL LETTER OMEGA A7F7;AL # Lo LATIN EPIGRAPHIC LETTER SIDEWAYS I A7F8..A7F9;AL # Lm [2] MODIFIER LETTER CAPITAL H WITH STROKE..MODIFIER LETTER SMALL LIGATURE OE @@ -1546,7 +1572,7 @@ A876..A877;EX # Po [2] PHAGS-PA MARK SHAD..PHAGS-PA MARK DOUBLE SHAD A880..A881;CM # Mc [2] SAURASHTRA SIGN ANUSVARA..SAURASHTRA SIGN VISARGA A882..A8B3;AL # Lo [50] SAURASHTRA LETTER A..SAURASHTRA LETTER LLA A8B4..A8C3;CM # Mc [16] SAURASHTRA CONSONANT SIGN HAARU..SAURASHTRA VOWEL SIGN AU -A8C4;CM # Mn SAURASHTRA SIGN VIRAMA +A8C4..A8C5;CM # Mn [2] SAURASHTRA SIGN VIRAMA..SAURASHTRA SIGN CANDRABINDU A8CE..A8CF;BA # Po [2] SAURASHTRA DANDA..SAURASHTRA DOUBLE DANDA A8D0..A8D9;NU # Nd [10] SAURASHTRA DIGIT ZERO..SAURASHTRA DIGIT NINE A8E0..A8F1;CM # Mn [18] COMBINING DEVANAGARI DIGIT ZERO..COMBINING DEVANAGARI SIGN AVAGRAHA @@ -2574,16 +2600,16 @@ FF62;OP # Ps HALFWIDTH LEFT CORNER BRACKET FF63;CL # Pe HALFWIDTH RIGHT CORNER BRACKET FF64;CL # Po HALFWIDTH IDEOGRAPHIC COMMA FF65;NS # Po HALFWIDTH KATAKANA MIDDLE DOT -FF66;AL # Lo HALFWIDTH KATAKANA LETTER WO +FF66;ID # Lo HALFWIDTH KATAKANA LETTER WO FF67..FF6F;CJ # Lo [9] HALFWIDTH KATAKANA LETTER SMALL A..HALFWIDTH KATAKANA LETTER SMALL TU FF70;CJ # Lm HALFWIDTH KATAKANA-HIRAGANA PROLONGED SOUND MARK -FF71..FF9D;AL # Lo [45] HALFWIDTH KATAKANA LETTER A..HALFWIDTH KATAKANA LETTER N +FF71..FF9D;ID # Lo [45] HALFWIDTH KATAKANA LETTER A..HALFWIDTH KATAKANA LETTER N FF9E..FF9F;NS # Lm [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDTH KATAKANA SEMI-VOICED SOUND MARK -FFA0..FFBE;AL # Lo [31] HALFWIDTH HANGUL FILLER..HALFWIDTH HANGUL LETTER HIEUH -FFC2..FFC7;AL # Lo [6] HALFWIDTH HANGUL LETTER A..HALFWIDTH HANGUL LETTER E -FFCA..FFCF;AL # Lo [6] HALFWIDTH HANGUL LETTER YEO..HALFWIDTH HANGUL LETTER OE -FFD2..FFD7;AL # Lo [6] HALFWIDTH HANGUL LETTER YO..HALFWIDTH HANGUL LETTER YU -FFDA..FFDC;AL # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGUL LETTER I +FFA0..FFBE;ID # Lo [31] HALFWIDTH HANGUL FILLER..HALFWIDTH HANGUL LETTER HIEUH +FFC2..FFC7;ID # Lo [6] HALFWIDTH HANGUL LETTER A..HALFWIDTH HANGUL LETTER E +FFCA..FFCF;ID # Lo [6] HALFWIDTH HANGUL LETTER YEO..HALFWIDTH HANGUL LETTER OE +FFD2..FFD7;ID # Lo [6] HALFWIDTH HANGUL LETTER YO..HALFWIDTH HANGUL LETTER YU +FFDA..FFDC;ID # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGUL LETTER I FFE0;PO # Sc FULLWIDTH CENT SIGN FFE1;PR # Sc FULLWIDTH POUND SIGN FFE2;ID # Sm FULLWIDTH NOT SIGN @@ -2610,7 +2636,7 @@ FFFD;AI # So REPLACEMENT CHARACTER 10175..10178;AL # No [4] GREEK ONE HALF SIGN..GREEK THREE QUARTERS SIGN 10179..10189;AL # So [17] GREEK YEAR SIGN..GREEK TRYBLION BASE SIGN 1018A..1018B;AL # No [2] GREEK ZERO SIGN..GREEK ONE QUARTER SIGN -1018C;AL # So GREEK SINUSOID SIGN +1018C..1018E;AL # So [3] GREEK SINUSOID SIGN..NOMISMA SIGN 10190..1019B;AL # So [12] ROMAN SEXTANS SIGN..ROMAN CENTURIAL SIGN 101A0;AL # So GREEK SYMBOL TAU RHO 101D0..101FC;AL # So [45] PHAISTOS DISC SIGN PEDESTRIAN..PHAISTOS DISC SIGN WAVY BAND @@ -2621,6 +2647,7 @@ FFFD;AI # So REPLACEMENT CHARACTER 102E1..102FB;AL # No [27] COPTIC EPACT DIGIT ONE..COPTIC EPACT NUMBER NINE HUNDRED 10300..1031F;AL # Lo [32] OLD ITALIC LETTER A..OLD ITALIC LETTER ESS 10320..10323;AL # No [4] OLD ITALIC NUMERAL ONE..OLD ITALIC NUMERAL FIFTY +1032D..1032F;AL # Lo [3] OLD ITALIC LETTER YE..OLD ITALIC LETTER SOUTHERN TSE 10330..10340;AL # Lo [17] GOTHIC LETTER AHSA..GOTHIC LETTER PAIRTHRA 10341;AL # Nl GOTHIC LETTER NINETY 10342..10349;AL # Lo [8] GOTHIC LETTER RAIDA..GOTHIC LETTER OTHAL @@ -2637,6 +2664,8 @@ FFFD;AI # So REPLACEMENT CHARACTER 10450..1047F;AL # Lo [48] SHAVIAN LETTER PEEP..SHAVIAN LETTER YEW 10480..1049D;AL # Lo [30] OSMANYA LETTER ALEF..OSMANYA LETTER OO 104A0..104A9;NU # Nd [10] OSMANYA DIGIT ZERO..OSMANYA DIGIT NINE +104B0..104D3;AL # Lu [36] OSAGE CAPITAL LETTER A..OSAGE CAPITAL LETTER ZHA +104D8..104FB;AL # Ll [36] OSAGE SMALL LETTER A..OSAGE SMALL LETTER ZHA 10500..10527;AL # Lo [40] ELBASAN LETTER A..ELBASAN LETTER KHE 10530..10563;AL # Lo [52] CAUCASIAN ALBANIAN LETTER ALT..CAUCASIAN ALBANIAN LETTER KIW 1056F;AL # Po CAUCASIAN ALBANIAN CITATION MARK @@ -2774,6 +2803,7 @@ FFFD;AI # So REPLACEMENT CHARACTER 1123A;AL # Po KHOJKI WORD SEPARATOR 1123B..1123C;BA # Po [2] KHOJKI SECTION MARK..KHOJKI DOUBLE SECTION MARK 1123D;AL # Po KHOJKI ABBREVIATION SIGN +1123E;CM # Mn KHOJKI SIGN SUKUN 11280..11286;AL # Lo [7] MULTANI LETTER A..MULTANI LETTER GA 11288;AL # Lo MULTANI LETTER GHA 1128A..1128D;AL # Lo [4] MULTANI LETTER CA..MULTANI LETTER JJA @@ -2806,6 +2836,19 @@ FFFD;AI # So REPLACEMENT CHARACTER 11362..11363;CM # Mc [2] GRANTHA VOWEL SIGN VOCALIC L..GRANTHA VOWEL SIGN VOCALIC LL 11366..1136C;CM # Mn [7] COMBINING GRANTHA DIGIT ZERO..COMBINING GRANTHA DIGIT SIX 11370..11374;CM # Mn [5] COMBINING GRANTHA LETTER A..COMBINING GRANTHA LETTER PA +11400..11434;AL # Lo [53] NEWA LETTER A..NEWA LETTER HA +11435..11437;CM # Mc [3] NEWA VOWEL SIGN AA..NEWA VOWEL SIGN II +11438..1143F;CM # Mn [8] NEWA VOWEL SIGN U..NEWA VOWEL SIGN AI +11440..11441;CM # Mc [2] NEWA VOWEL SIGN O..NEWA VOWEL SIGN AU +11442..11444;CM # Mn [3] NEWA SIGN VIRAMA..NEWA SIGN ANUSVARA +11445;CM # Mc NEWA SIGN VISARGA +11446;CM # Mn NEWA SIGN NUKTA +11447..1144A;AL # Lo [4] NEWA SIGN AVAGRAHA..NEWA SIDDHI +1144B..1144E;BA # Po [4] NEWA DANDA..NEWA GAP FILLER +1144F;AL # Po NEWA ABBREVIATION SIGN +11450..11459;NU # Nd [10] NEWA DIGIT ZERO..NEWA DIGIT NINE +1145B;BA # Po NEWA PLACEHOLDER MARK +1145D;AL # Po NEWA INSERTION SIGN 11480..114AF;AL # Lo [48] TIRHUTA ANJI..TIRHUTA LETTER HA 114B0..114B2;CM # Mc [3] TIRHUTA VOWEL SIGN AA..TIRHUTA VOWEL SIGN II 114B3..114B8;CM # Mn [6] TIRHUTA VOWEL SIGN U..TIRHUTA VOWEL SIGN VOCALIC LL @@ -2844,6 +2887,7 @@ FFFD;AI # So REPLACEMENT CHARACTER 11643;AL # Po MODI ABBREVIATION SIGN 11644;AL # Lo MODI SIGN HUVA 11650..11659;NU # Nd [10] MODI DIGIT ZERO..MODI DIGIT NINE +11660..1166C;BB # Po [13] MONGOLIAN BIRGA WITH ORNAMENT..MONGOLIAN TURNED SWIRL BIRGA WITH DOUBLE ORNAMENT 11680..116AA;AL # Lo [43] TAKRI LETTER A..TAKRI LETTER RRA 116AB;CM # Mn TAKRI SIGN ANUSVARA 116AC;CM # Mc TAKRI SIGN VISARGA @@ -2867,7 +2911,65 @@ FFFD;AI # So REPLACEMENT CHARACTER 118E0..118E9;NU # Nd [10] WARANG CITI DIGIT ZERO..WARANG CITI DIGIT NINE 118EA..118F2;AL # No [9] WARANG CITI NUMBER TEN..WARANG CITI NUMBER NINETY 118FF;AL # Lo WARANG CITI OM +11A00;AL # Lo ZANABAZAR SQUARE LETTER A +11A01..11A06;CM # Mn [6] ZANABAZAR SQUARE VOWEL SIGN I..ZANABAZAR SQUARE VOWEL SIGN O +11A07..11A08;CM # Mc [2] ZANABAZAR SQUARE VOWEL SIGN AI..ZANABAZAR SQUARE VOWEL SIGN AU +11A09..11A0A;CM # Mn [2] ZANABAZAR SQUARE VOWEL SIGN REVERSED I..ZANABAZAR SQUARE VOWEL LENGTH MARK +11A0B..11A32;AL # Lo [40] ZANABAZAR SQUARE LETTER KA..ZANABAZAR SQUARE LETTER KSSA +11A33..11A38;CM # Mn [6] ZANABAZAR SQUARE FINAL CONSONANT MARK..ZANABAZAR SQUARE SIGN ANUSVARA +11A39;CM # Mc ZANABAZAR SQUARE SIGN VISARGA +11A3A;AL # Lo ZANABAZAR SQUARE CLUSTER-INITIAL LETTER RA +11A3B..11A3E;CM # Mn [4] ZANABAZAR SQUARE CLUSTER-FINAL LETTER YA..ZANABAZAR SQUARE CLUSTER-FINAL LETTER VA +11A3F;BB # Po ZANABAZAR SQUARE INITIAL HEAD MARK +11A40;AL # Po ZANABAZAR SQUARE CLOSING HEAD MARK +11A41..11A44;BA # Po [4] ZANABAZAR SQUARE MARK TSHEG..ZANABAZAR SQUARE MARK LONG TSHEG +11A45;BB # Po ZANABAZAR SQUARE INITIAL DOUBLE-LINED HEAD MARK +11A46;AL # Po ZANABAZAR SQUARE CLOSING DOUBLE-LINED HEAD MARK +11A47;CM # Mn ZANABAZAR SQUARE SUBJOINER +11A50;AL # Lo SOYOMBO LETTER A +11A51..11A56;CM # Mn [6] SOYOMBO VOWEL SIGN I..SOYOMBO VOWEL SIGN OE +11A57..11A58;CM # Mc [2] SOYOMBO VOWEL SIGN AI..SOYOMBO VOWEL SIGN AU +11A59..11A5B;CM # Mn [3] SOYOMBO VOWEL SIGN VOCALIC R..SOYOMBO VOWEL LENGTH MARK +11A5C..11A83;AL # Lo [40] SOYOMBO LETTER KA..SOYOMBO LETTER KSSA +11A86..11A89;AL # Lo [4] SOYOMBO CLUSTER-INITIAL LETTER RA..SOYOMBO CLUSTER-INITIAL LETTER SA +11A8A..11A96;CM # Mn [13] SOYOMBO FINAL CONSONANT SIGN G..SOYOMBO SIGN ANUSVARA +11A97;CM # Mc SOYOMBO SIGN VISARGA +11A98..11A99;CM # Mn [2] SOYOMBO GEMINATION MARK..SOYOMBO SUBJOINER +11A9A..11A9C;BA # Po [3] SOYOMBO MARK TSHEG..SOYOMBO MARK DOUBLE SHAD +11A9E..11AA0;BB # Po [3] SOYOMBO HEAD MARK WITH MOON AND SUN AND TRIPLE FLAME..SOYOMBO HEAD MARK WITH MOON AND SUN +11AA1..11AA2;BA # Po [2] SOYOMBO TERMINAL MARK-1..SOYOMBO TERMINAL MARK-2 11AC0..11AF8;AL # Lo [57] PAU CIN HAU LETTER PA..PAU CIN HAU GLOTTAL STOP FINAL +11C00..11C08;AL # Lo [9] BHAIKSUKI LETTER A..BHAIKSUKI LETTER VOCALIC L +11C0A..11C2E;AL # Lo [37] BHAIKSUKI LETTER E..BHAIKSUKI LETTER HA +11C2F;CM # Mc BHAIKSUKI VOWEL SIGN AA +11C30..11C36;CM # Mn [7] BHAIKSUKI VOWEL SIGN I..BHAIKSUKI VOWEL SIGN VOCALIC L +11C38..11C3D;CM # Mn [6] BHAIKSUKI VOWEL SIGN E..BHAIKSUKI SIGN ANUSVARA +11C3E;CM # Mc BHAIKSUKI SIGN VISARGA +11C3F;CM # Mn BHAIKSUKI SIGN VIRAMA +11C40;AL # Lo BHAIKSUKI SIGN AVAGRAHA +11C41..11C45;BA # Po [5] BHAIKSUKI DANDA..BHAIKSUKI GAP FILLER-2 +11C50..11C59;NU # Nd [10] BHAIKSUKI DIGIT ZERO..BHAIKSUKI DIGIT NINE +11C5A..11C6C;AL # No [19] BHAIKSUKI NUMBER ONE..BHAIKSUKI HUNDREDS UNIT MARK +11C70;BB # Po MARCHEN HEAD MARK +11C71;EX # Po MARCHEN MARK SHAD +11C72..11C8F;AL # Lo [30] MARCHEN LETTER KA..MARCHEN LETTER A +11C92..11CA7;CM # Mn [22] MARCHEN SUBJOINED LETTER KA..MARCHEN SUBJOINED LETTER ZA +11CA9;CM # Mc MARCHEN SUBJOINED LETTER YA +11CAA..11CB0;CM # Mn [7] MARCHEN SUBJOINED LETTER RA..MARCHEN VOWEL SIGN AA +11CB1;CM # Mc MARCHEN VOWEL SIGN I +11CB2..11CB3;CM # Mn [2] MARCHEN VOWEL SIGN U..MARCHEN VOWEL SIGN E +11CB4;CM # Mc MARCHEN VOWEL SIGN O +11CB5..11CB6;CM # Mn [2] MARCHEN SIGN ANUSVARA..MARCHEN SIGN CANDRABINDU +11D00..11D06;AL # Lo [7] MASARAM GONDI LETTER A..MASARAM GONDI LETTER E +11D08..11D09;AL # Lo [2] MASARAM GONDI LETTER AI..MASARAM GONDI LETTER O +11D0B..11D30;AL # Lo [38] MASARAM GONDI LETTER AU..MASARAM GONDI LETTER TRA +11D31..11D36;CM # Mn [6] MASARAM GONDI VOWEL SIGN AA..MASARAM GONDI VOWEL SIGN VOCALIC R +11D3A;CM # Mn MASARAM GONDI VOWEL SIGN E +11D3C..11D3D;CM # Mn [2] MASARAM GONDI VOWEL SIGN AI..MASARAM GONDI VOWEL SIGN O +11D3F..11D45;CM # Mn [7] MASARAM GONDI VOWEL SIGN AU..MASARAM GONDI VIRAMA +11D46;AL # Lo MASARAM GONDI REPHA +11D47;CM # Mn MASARAM GONDI RA-KARA +11D50..11D59;NU # Nd [10] MASARAM GONDI DIGIT ZERO..MASARAM GONDI DIGIT NINE 12000..12399;AL # Lo [922] CUNEIFORM SIGN A..CUNEIFORM SIGN U U 12400..1246E;AL # Nl [111] CUNEIFORM NUMERIC SIGN TWO ASH..CUNEIFORM NUMERIC SIGN NINE U VARIANT FORM 12470..12474;BA # Po [5] CUNEIFORM PUNCTUATION SIGN OLD ASSYRIAN WORD DIVIDER..CUNEIFORM PUNCTUATION SIGN DIAGONAL QUADCOLON @@ -2914,7 +3016,12 @@ FFFD;AI # So REPLACEMENT CHARACTER 16F51..16F7E;CM # Mc [46] MIAO SIGN ASPIRATION..MIAO VOWEL SIGN NG 16F8F..16F92;CM # Mn [4] MIAO TONE RIGHT..MIAO TONE BELOW 16F93..16F9F;AL # Lm [13] MIAO LETTER TONE-2..MIAO LETTER REFORMED TONE-8 -1B000..1B001;ID # Lo [2] KATAKANA LETTER ARCHAIC E..HIRAGANA LETTER ARCHAIC YE +16FE0..16FE1;NS # Lm [2] TANGUT ITERATION MARK..NUSHU ITERATION MARK +17000..187EC;ID # Lo [6125] TANGUT IDEOGRAPH-17000..TANGUT IDEOGRAPH-187EC +18800..18AF2;ID # Lo [755] TANGUT COMPONENT-001..TANGUT COMPONENT-755 +1B000..1B0FF;ID # Lo [256] KATAKANA LETTER ARCHAIC E..HENTAIGANA LETTER RE-2 +1B100..1B11E;ID # Lo [31] HENTAIGANA LETTER RE-3..HENTAIGANA LETTER N-MU-MO-2 +1B170..1B2FB;ID # Lo [396] NUSHU CHARACTER-1B170..NUSHU CHARACTER-1B2FB 1BC00..1BC6A;AL # Lo [107] DUPLOYAN LETTER H..DUPLOYAN LETTER VOCALIC M 1BC70..1BC7C;AL # Lo [13] DUPLOYAN AFFIX LEFT HORIZONTAL SECANT..DUPLOYAN AFFIX ATTACHED TANGENT HOOK 1BC80..1BC88;AL # Lo [9] DUPLOYAN AFFIX HIGH ACUTE..DUPLOYAN AFFIX HIGH VERTICAL @@ -2996,9 +3103,18 @@ FFFD;AI # So REPLACEMENT CHARACTER 1DA8B;AL # Po SIGNWRITING PARENTHESIS 1DA9B..1DA9F;CM # Mn [5] SIGNWRITING FILL MODIFIER-2..SIGNWRITING FILL MODIFIER-6 1DAA1..1DAAF;CM # Mn [15] SIGNWRITING ROTATION MODIFIER-2..SIGNWRITING ROTATION MODIFIER-16 +1E000..1E006;CM # Mn [7] COMBINING GLAGOLITIC LETTER AZU..COMBINING GLAGOLITIC LETTER ZHIVETE +1E008..1E018;CM # Mn [17] COMBINING GLAGOLITIC LETTER ZEMLJA..COMBINING GLAGOLITIC LETTER HERU +1E01B..1E021;CM # Mn [7] COMBINING GLAGOLITIC LETTER SHTA..COMBINING GLAGOLITIC LETTER YATI +1E023..1E024;CM # Mn [2] COMBINING GLAGOLITIC LETTER YU..COMBINING GLAGOLITIC LETTER SMALL YUS +1E026..1E02A;CM # Mn [5] COMBINING GLAGOLITIC LETTER YO..COMBINING GLAGOLITIC LETTER FITA 1E800..1E8C4;AL # Lo [197] MENDE KIKAKUI SYLLABLE M001 KI..MENDE KIKAKUI SYLLABLE M060 NYON 1E8C7..1E8CF;AL # No [9] MENDE KIKAKUI DIGIT ONE..MENDE KIKAKUI DIGIT NINE 1E8D0..1E8D6;CM # Mn [7] MENDE KIKAKUI COMBINING NUMBER TEENS..MENDE KIKAKUI COMBINING NUMBER MILLIONS +1E900..1E943;AL # L& [68] ADLAM CAPITAL LETTER ALIF..ADLAM SMALL LETTER SHA +1E944..1E94A;CM # Mn [7] ADLAM ALIF LENGTHENER..ADLAM NUKTA +1E950..1E959;NU # Nd [10] ADLAM DIGIT ZERO..ADLAM DIGIT NINE +1E95E..1E95F;OP # Po [2] ADLAM INITIAL EXCLAMATION MARK..ADLAM INITIAL QUESTION MARK 1EE00..1EE03;AL # Lo [4] ARABIC MATHEMATICAL ALEF..ARABIC MATHEMATICAL DAL 1EE05..1EE1F;AL # Lo [27] ARABIC MATHEMATICAL WAW..ARABIC MATHEMATICAL DOTLESS QAF 1EE21..1EE22;AL # Lo [2] ARABIC MATHEMATICAL INITIAL BEH..ARABIC MATHEMATICAL INITIAL JEEM @@ -3034,37 +3150,79 @@ FFFD;AI # So REPLACEMENT CHARACTER 1EEAB..1EEBB;AL # Lo [17] ARABIC MATHEMATICAL DOUBLE-STRUCK LAM..ARABIC MATHEMATICAL DOUBLE-STRUCK GHAIN 1EEF0..1EEF1;AL # Sm [2] ARABIC MATHEMATICAL OPERATOR MEEM WITH HAH WITH TATWEEL..ARABIC MATHEMATICAL OPERATOR HAH WITH DAL 1F000..1F02B;ID # So [44] MAHJONG TILE EAST WIND..MAHJONG TILE BACK +1F02C..1F02F;ID # Cn [4] <reserved-1F02C>..<reserved-1F02F> 1F030..1F093;ID # So [100] DOMINO TILE HORIZONTAL BACK..DOMINO TILE VERTICAL-06-06 +1F094..1F09F;ID # Cn [12] <reserved-1F094>..<reserved-1F09F> 1F0A0..1F0AE;ID # So [15] PLAYING CARD BACK..PLAYING CARD KING OF SPADES +1F0AF..1F0B0;ID # Cn [2] <reserved-1F0AF>..<reserved-1F0B0> 1F0B1..1F0BF;ID # So [15] PLAYING CARD ACE OF HEARTS..PLAYING CARD RED JOKER +1F0C0;ID # Cn <reserved-1F0C0> 1F0C1..1F0CF;ID # So [15] PLAYING CARD ACE OF DIAMONDS..PLAYING CARD BLACK JOKER +1F0D0;ID # Cn <reserved-1F0D0> 1F0D1..1F0F5;ID # So [37] PLAYING CARD ACE OF CLUBS..PLAYING CARD TRUMP-21 +1F0F6..1F0FF;ID # Cn [10] <reserved-1F0F6>..<reserved-1F0FF> 1F100..1F10C;AI # No [13] DIGIT ZERO FULL STOP..DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT ZERO +1F10D..1F10F;ID # Cn [3] <reserved-1F10D>..<reserved-1F10F> 1F110..1F12D;AI # So [30] PARENTHESIZED LATIN CAPITAL LETTER A..CIRCLED CD 1F12E;AL # So CIRCLED WZ +1F12F;ID # Cn <reserved-1F12F> 1F130..1F169;AI # So [58] SQUARED LATIN CAPITAL LETTER A..NEGATIVE CIRCLED LATIN CAPITAL LETTER Z 1F16A..1F16B;AL # So [2] RAISED MC SIGN..RAISED MD SIGN -1F170..1F19A;AI # So [43] NEGATIVE SQUARED LATIN CAPITAL LETTER A..SQUARED VS +1F16C..1F16F;ID # Cn [4] <reserved-1F16C>..<reserved-1F16F> +1F170..1F1AC;AI # So [61] NEGATIVE SQUARED LATIN CAPITAL LETTER A..SQUARED VOD +1F1AD..1F1E5;ID # Cn [57] <reserved-1F1AD>..<reserved-1F1E5> 1F1E6..1F1FF;RI # So [26] REGIONAL INDICATOR SYMBOL LETTER A..REGIONAL INDICATOR SYMBOL LETTER Z 1F200..1F202;ID # So [3] SQUARE HIRAGANA HOKA..SQUARED KATAKANA SA -1F210..1F23A;ID # So [43] SQUARED CJK UNIFIED IDEOGRAPH-624B..SQUARED CJK UNIFIED IDEOGRAPH-55B6 +1F203..1F20F;ID # Cn [13] <reserved-1F203>..<reserved-1F20F> +1F210..1F23B;ID # So [44] SQUARED CJK UNIFIED IDEOGRAPH-624B..SQUARED CJK UNIFIED IDEOGRAPH-914D +1F23C..1F23F;ID # Cn [4] <reserved-1F23C>..<reserved-1F23F> 1F240..1F248;ID # So [9] TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-672C..TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-6557 +1F249..1F24F;ID # Cn [7] <reserved-1F249>..<reserved-1F24F> 1F250..1F251;ID # So [2] CIRCLED IDEOGRAPH ADVANTAGE..CIRCLED IDEOGRAPH ACCEPT -1F300..1F39B;ID # So [156] CYCLONE..CONTROL KNOBS +1F252..1F25F;ID # Cn [14] <reserved-1F252>..<reserved-1F25F> +1F260..1F265;ID # So [6] ROUNDED SYMBOL FOR FU..ROUNDED SYMBOL FOR CAI +1F266..1F2FF;ID # Cn [154] <reserved-1F266>..<reserved-1F2FF> +1F300..1F384;ID # So [133] CYCLONE..CHRISTMAS TREE +1F385;EB # So FATHER CHRISTMAS +1F386..1F39B;ID # So [22] FIREWORKS..CONTROL KNOBS 1F39C..1F39D;AL # So [2] BEAMED ASCENDING MUSICAL NOTES..BEAMED DESCENDING MUSICAL NOTES 1F39E..1F3B4;ID # So [23] FILM FRAMES..FLOWER PLAYING CARDS 1F3B5..1F3B6;AL # So [2] MUSICAL NOTE..MULTIPLE MUSICAL NOTES 1F3B7..1F3BB;ID # So [5] SAXOPHONE..VIOLIN 1F3BC;AL # So MUSICAL SCORE -1F3BD..1F3FA;ID # So [62] RUNNING SHIRT WITH SASH..AMPHORA -1F3FB..1F3FF;AL # Sk [5] EMOJI MODIFIER FITZPATRICK TYPE-1-2..EMOJI MODIFIER FITZPATRICK TYPE-6 -1F400..1F49F;ID # So [160] RAT..HEART DECORATION +1F3BD..1F3C1;ID # So [5] RUNNING SHIRT WITH SASH..CHEQUERED FLAG +1F3C2..1F3C4;EB # So [3] SNOWBOARDER..SURFER +1F3C5..1F3C6;ID # So [2] SPORTS MEDAL..TROPHY +1F3C7;EB # So HORSE RACING +1F3C8..1F3C9;ID # So [2] AMERICAN FOOTBALL..RUGBY FOOTBALL +1F3CA..1F3CC;EB # So [3] SWIMMER..GOLFER +1F3CD..1F3FA;ID # So [46] RACING MOTORCYCLE..AMPHORA +1F3FB..1F3FF;EM # Sk [5] EMOJI MODIFIER FITZPATRICK TYPE-1-2..EMOJI MODIFIER FITZPATRICK TYPE-6 +1F400..1F441;ID # So [66] RAT..EYE +1F442..1F443;EB # So [2] EAR..NOSE +1F444..1F445;ID # So [2] MOUTH..TONGUE +1F446..1F450;EB # So [11] WHITE UP POINTING BACKHAND INDEX..OPEN HANDS SIGN +1F451..1F465;ID # So [21] CROWN..BUSTS IN SILHOUETTE +1F466..1F469;EB # So [4] BOY..WOMAN +1F46A..1F46D;ID # So [4] FAMILY..TWO WOMEN HOLDING HANDS +1F46E;EB # So POLICE OFFICER +1F46F;ID # So WOMAN WITH BUNNY EARS +1F470..1F478;EB # So [9] BRIDE WITH VEIL..PRINCESS +1F479..1F47B;ID # So [3] JAPANESE OGRE..GHOST +1F47C;EB # So BABY ANGEL +1F47D..1F480;ID # So [4] EXTRATERRESTRIAL ALIEN..SKULL +1F481..1F483;EB # So [3] INFORMATION DESK PERSON..DANCER +1F484;ID # So LIPSTICK +1F485..1F487;EB # So [3] NAIL POLISH..HAIRCUT +1F488..1F49F;ID # So [24] BARBER POLE..HEART DECORATION 1F4A0;AL # So DIAMOND SHAPE WITH A DOT INSIDE 1F4A1;ID # So ELECTRIC LIGHT BULB 1F4A2;AL # So ANGER SYMBOL 1F4A3;ID # So BOMB 1F4A4;AL # So SLEEPING SYMBOL -1F4A5..1F4AE;ID # So [10] COLLISION SYMBOL..WHITE FLOWER +1F4A5..1F4A9;ID # So [5] COLLISION SYMBOL..PILE OF POO +1F4AA;EB # So FLEXED BICEPS +1F4AB..1F4AE;ID # So [4] DIZZY SYMBOL..WHITE FLOWER 1F4AF;AL # So HUNDRED POINTS SYMBOL 1F4B0;ID # So MONEY BAG 1F4B1..1F4B2;AL # So [2] CURRENCY EXCHANGE..HEAVY DOLLAR SIGN @@ -3074,31 +3232,80 @@ FFFD;AI # So REPLACEMENT CHARACTER 1F517..1F524;AL # So [14] LINK SYMBOL..INPUT SYMBOL FOR LATIN LETTERS 1F525..1F531;ID # So [13] FIRE..TRIDENT EMBLEM 1F532..1F549;AL # So [24] BLACK SQUARE BUTTON..OM SYMBOL -1F54A..1F579;ID # So [48] DOVE OF PEACE..JOYSTICK -1F57B..1F5A3;ID # So [41] LEFT HAND TELEPHONE RECEIVER..BLACK DOWN POINTING BACKHAND INDEX -1F5A5..1F5D3;ID # So [47] DESKTOP COMPUTER..SPIRAL CALENDAR PAD +1F54A..1F573;ID # So [42] DOVE OF PEACE..HOLE +1F574..1F575;EB # So [2] MAN IN BUSINESS SUIT LEVITATING..SLEUTH OR SPY +1F576..1F579;ID # So [4] DARK SUNGLASSES..JOYSTICK +1F57A;EB # So MAN DANCING +1F57B..1F58F;ID # So [21] LEFT HAND TELEPHONE RECEIVER..TURNED OK HAND SIGN +1F590;EB # So RAISED HAND WITH FINGERS SPLAYED +1F591..1F594;ID # So [4] REVERSED RAISED HAND WITH FINGERS SPLAYED..REVERSED VICTORY HAND +1F595..1F596;EB # So [2] REVERSED HAND WITH MIDDLE FINGER EXTENDED..RAISED HAND WITH PART BETWEEN MIDDLE AND RING FINGERS +1F597..1F5D3;ID # So [61] WHITE DOWN POINTING LEFT HAND INDEX..SPIRAL CALENDAR PAD 1F5D4..1F5DB;AL # So [8] DESKTOP WINDOW..DECREASE FONT SIZE SYMBOL 1F5DC..1F5F3;ID # So [24] COMPRESSION..BALLOT BOX WITH BALLOT 1F5F4..1F5F9;AL # So [6] BALLOT SCRIPT X..BALLOT BOX WITH BOLD CHECK 1F5FA..1F5FF;ID # So [6] WORLD MAP..MOYAI -1F600..1F64F;ID # So [80] GRINNING FACE..PERSON WITH FOLDED HANDS +1F600..1F644;ID # So [69] GRINNING FACE..FACE WITH ROLLING EYES +1F645..1F647;EB # So [3] FACE WITH NO GOOD GESTURE..PERSON BOWING DEEPLY +1F648..1F64A;ID # So [3] SEE-NO-EVIL MONKEY..SPEAK-NO-EVIL MONKEY +1F64B..1F64F;EB # So [5] HAPPY PERSON RAISING ONE HAND..PERSON WITH FOLDED HANDS 1F650..1F675;AL # So [38] NORTH WEST POINTING LEAF..SWASH AMPERSAND ORNAMENT 1F676..1F678;QU # So [3] SANS-SERIF HEAVY DOUBLE TURNED COMMA QUOTATION MARK ORNAMENT..SANS-SERIF HEAVY LOW DOUBLE COMMA QUOTATION MARK ORNAMENT 1F679..1F67B;NS # So [3] HEAVY INTERROBANG ORNAMENT..HEAVY SANS-SERIF INTERROBANG ORNAMENT 1F67C..1F67F;AL # So [4] VERY HEAVY SOLIDUS..REVERSE CHECKER BOARD -1F680..1F6D0;ID # So [81] ROCKET..PLACE OF WORSHIP +1F680..1F6A2;ID # So [35] ROCKET..SHIP +1F6A3;EB # So ROWBOAT +1F6A4..1F6B3;ID # So [16] SPEEDBOAT..NO BICYCLES +1F6B4..1F6B6;EB # So [3] BICYCLIST..PEDESTRIAN +1F6B7..1F6BF;ID # So [9] NO PEDESTRIANS..SHOWER +1F6C0;EB # So BATH +1F6C1..1F6CB;ID # So [11] BATHTUB..COUCH AND LAMP +1F6CC;EB # So SLEEPING ACCOMMODATION +1F6CD..1F6D4;ID # So [8] SHOPPING BAGS..PAGODA +1F6D5..1F6DF;ID # Cn [11] <reserved-1F6D5>..<reserved-1F6DF> 1F6E0..1F6EC;ID # So [13] HAMMER AND WRENCH..AIRPLANE ARRIVING -1F6F0..1F6F3;ID # So [4] SATELLITE..PASSENGER SHIP +1F6ED..1F6EF;ID # Cn [3] <reserved-1F6ED>..<reserved-1F6EF> +1F6F0..1F6F8;ID # So [9] SATELLITE..FLYING SAUCER +1F6F9..1F6FF;ID # Cn [7] <reserved-1F6F9>..<reserved-1F6FF> 1F700..1F773;AL # So [116] ALCHEMICAL SYMBOL FOR QUINTESSENCE..ALCHEMICAL SYMBOL FOR HALF OUNCE +1F774..1F77F;ID # Cn [12] <reserved-1F774>..<reserved-1F77F> 1F780..1F7D4;AL # So [85] BLACK LEFT-POINTING ISOSCELES RIGHT TRIANGLE..HEAVY TWELVE POINTED PINWHEEL STAR +1F7D5..1F7FF;ID # Cn [43] <reserved-1F7D5>..<reserved-1F7FF> 1F800..1F80B;AL # So [12] LEFTWARDS ARROW WITH SMALL TRIANGLE ARROWHEAD..DOWNWARDS ARROW WITH LARGE TRIANGLE ARROWHEAD +1F80C..1F80F;ID # Cn [4] <reserved-1F80C>..<reserved-1F80F> 1F810..1F847;AL # So [56] LEFTWARDS ARROW WITH SMALL EQUILATERAL ARROWHEAD..DOWNWARDS HEAVY ARROW +1F848..1F84F;ID # Cn [8] <reserved-1F848>..<reserved-1F84F> 1F850..1F859;AL # So [10] LEFTWARDS SANS-SERIF ARROW..UP DOWN SANS-SERIF ARROW +1F85A..1F85F;ID # Cn [6] <reserved-1F85A>..<reserved-1F85F> 1F860..1F887;AL # So [40] WIDE-HEADED LEFTWARDS LIGHT BARB ARROW..WIDE-HEADED SOUTH WEST VERY HEAVY BARB ARROW +1F888..1F88F;ID # Cn [8] <reserved-1F888>..<reserved-1F88F> 1F890..1F8AD;AL # So [30] LEFTWARDS TRIANGLE ARROWHEAD..WHITE ARROW SHAFT WIDTH TWO THIRDS -1F910..1F918;ID # So [9] ZIPPER-MOUTH FACE..SIGN OF THE HORNS -1F980..1F984;ID # So [5] CRAB..UNICORN FACE +1F8AE..1F8FF;ID # Cn [82] <reserved-1F8AE>..<reserved-1F8FF> +1F900..1F90B;AL # So [12] CIRCLED CROSS FORMEE WITH FOUR DOTS..DOWNWARD FACING NOTCHED HOOK WITH DOT +1F90C..1F90F;ID # Cn [4] <reserved-1F90C>..<reserved-1F90F> +1F910..1F917;ID # So [8] ZIPPER-MOUTH FACE..HUGGING FACE +1F918..1F91C;EB # So [5] SIGN OF THE HORNS..RIGHT-FACING FIST +1F91D;ID # So HANDSHAKE +1F91E..1F91F;EB # So [2] HAND WITH INDEX AND MIDDLE FINGERS CROSSED..I LOVE YOU HAND SIGN +1F920..1F925;ID # So [6] FACE WITH COWBOY HAT..LYING FACE +1F926;EB # So FACE PALM +1F927..1F92F;ID # So [9] SNEEZING FACE..SHOCKED FACE WITH EXPLODING HEAD +1F930..1F939;EB # So [10] PREGNANT WOMAN..JUGGLING +1F93A..1F93C;ID # So [3] FENCER..WRESTLERS +1F93D..1F93E;EB # So [2] WATER POLO..HANDBALL +1F93F;ID # Cn <reserved-1F93F> +1F940..1F94C;ID # So [13] WILTED FLOWER..CURLING STONE +1F94D..1F94F;ID # Cn [3] <reserved-1F94D>..<reserved-1F94F> +1F950..1F96B;ID # So [28] CROISSANT..CANNED FOOD +1F96C..1F97F;ID # Cn [20] <reserved-1F96C>..<reserved-1F97F> +1F980..1F997;ID # So [24] CRAB..CRICKET +1F998..1F9BF;ID # Cn [40] <reserved-1F998>..<reserved-1F9BF> 1F9C0;ID # So CHEESE WEDGE +1F9C1..1F9CF;ID # Cn [15] <reserved-1F9C1>..<reserved-1F9CF> +1F9D0;ID # So FACE WITH MONOCLE +1F9D1..1F9DD;EB # So [13] ADULT..ELF +1F9DE..1F9E6;ID # So [9] GENIE..SOCKS +1F9E7..1FFFD;ID # Cn [1559] <reserved-1F9E7>..<reserved-1FFFD> 20000..2A6D6;ID # Lo [42711] CJK UNIFIED IDEOGRAPH-20000..CJK UNIFIED IDEOGRAPH-2A6D6 2A6D7..2A6FF;ID # Cn [41] <reserved-2A6D7>..<reserved-2A6FF> 2A700..2B734;ID # Lo [4149] CJK UNIFIED IDEOGRAPH-2A700..CJK UNIFIED IDEOGRAPH-2B734 @@ -3106,7 +3313,9 @@ FFFD;AI # So REPLACEMENT CHARACTER 2B740..2B81D;ID # Lo [222] CJK UNIFIED IDEOGRAPH-2B740..CJK UNIFIED IDEOGRAPH-2B81D 2B81E..2B81F;ID # Cn [2] <reserved-2B81E>..<reserved-2B81F> 2B820..2CEA1;ID # Lo [5762] CJK UNIFIED IDEOGRAPH-2B820..CJK UNIFIED IDEOGRAPH-2CEA1 -2CEA2..2F7FF;ID # Cn [10590] <reserved-2CEA2>..<reserved-2F7FF> +2CEA2..2CEAF;ID # Cn [14] <reserved-2CEA2>..<reserved-2CEAF> +2CEB0..2EBE0;ID # Lo [7473] CJK UNIFIED IDEOGRAPH-2CEB0..CJK UNIFIED IDEOGRAPH-2EBE0 +2EBE1..2F7FF;ID # Cn [3103] <reserved-2EBE1>..<reserved-2F7FF> 2F800..2FA1D;ID # Lo [542] CJK COMPATIBILITY IDEOGRAPH-2F800..CJK COMPATIBILITY IDEOGRAPH-2FA1D 2FA1E..2FFFD;ID # Cn [1504] <reserved-2FA1E>..<reserved-2FFFD> 30000..3FFFD;ID # Cn [65534] <reserved-30000>..<reserved-3FFFD> diff --git a/tools-for-build/Makefile b/tools-for-build/Makefile index 1be91e9df1..b5a123603f 100644 --- a/tools-for-build/Makefile +++ b/tools-for-build/Makefile @@ -7,10 +7,11 @@ # provided with absolutely no warranty. See the COPYING and CREDITS # files for more information. --include genesis/Makefile.features +-include genesis/Makefile.features # for grovel-headers -include Config -CPPFLAGS+=-I../src/runtime +# Do not append to CFLAGS otherwise -I can override the -I below. +CFLAGS:=-I../src/runtime $(CFLAGS) LDFLAGS:=$(LDFLAGS) LDLIBS:=$(OS_LIBS) diff --git a/tools-for-build/NormalizationCorrections.txt b/tools-for-build/NormalizationCorrections.txt index 04fc10d11c..f7fc35e52c 100644 --- a/tools-for-build/NormalizationCorrections.txt +++ b/tools-for-build/NormalizationCorrections.txt @@ -1,12 +1,14 @@ -# NormalizationCorrections-8.0.0.txt -# Date: 2015-03-07, 01:30:00 GMT [KW, LI] +# NormalizationCorrections-10.0.0.txt +# Date: 2017-04-13, 01:00:00 GMT [KW, LI] +# © 2017 Unicode®, Inc. +# For terms of use, see http://www.unicode.org/terms_of_use.html +# +# Unicode Character Database +# For documentation, see http://www.unicode.org/reports/tr44/ # # This file is a normative contributory data file in the # Unicode Character Database. # -# Copyright (c) 1991-2015 Unicode, Inc. -# For terms of use, see http://www.unicode.org/terms_of_use.html -# # The normalization stability policy of the Unicode Consortium # ordinarily precludes any change to the decomposition # for any character, once established in a relevant version @@ -25,7 +27,7 @@ # # Currently this list has exactly six entries in it, one for the # typo found and corrected in Corrigendum #3, and five for -# the typos and misidentifications found and corrected in +# the typos and misidentifications found and corrected in # Corrigendum #4. All efforts # will be made to keep the entries limited to just those fixes. # @@ -35,7 +37,7 @@ # Field 2: Corrected decomposition # Field 3: Version of Unicode for which the correction was # entered into UnicodeData.txt, in n.n.n format. -# Comment: Indicates the Unicode Corrigendum which documents +# Comment: Indicates the Unicode Corrigendum which documents # the correction # # For more information, see UAX #15, Unicode Normalization Forms. diff --git a/tools-for-build/PropList.txt b/tools-for-build/PropList.txt index 2eb2926e07..9a2d0e4b1c 100644 --- a/tools-for-build/PropList.txt +++ b/tools-for-build/PropList.txt @@ -1,10 +1,11 @@ -# PropList-8.0.0.txt -# Date: 2015-05-16, 17:50:38 GMT [MD] +# PropList-10.0.0.txt +# Date: 2017-03-10, 08:25:30 GMT +# © 2017 Unicode®, Inc. +# Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries. +# For terms of use, see http://www.unicode.org/terms_of_use.html # # Unicode Character Database -# Copyright (c) 1991-2015 Unicode, Inc. -# For terms of use, see http://www.unicode.org/terms_of_use.html -# For documentation, see http://www.unicode.org/reports/tr44/ +# For documentation, see http://www.unicode.org/reports/tr44/ # ================================================ @@ -192,10 +193,17 @@ FF64 ; Terminal_Punctuation # Po HALFWIDTH IDEOGRAPHIC COMMA 111DE..111DF ; Terminal_Punctuation # Po [2] SHARADA SECTION MARK-1..SHARADA SECTION MARK-2 11238..1123C ; Terminal_Punctuation # Po [5] KHOJKI DANDA..KHOJKI DOUBLE SECTION MARK 112A9 ; Terminal_Punctuation # Po MULTANI SECTION MARK +1144B..1144D ; Terminal_Punctuation # Po [3] NEWA DANDA..NEWA COMMA +1145B ; Terminal_Punctuation # Po NEWA PLACEHOLDER MARK 115C2..115C5 ; Terminal_Punctuation # Po [4] SIDDHAM DANDA..SIDDHAM SEPARATOR BAR 115C9..115D7 ; Terminal_Punctuation # Po [15] SIDDHAM END OF TEXT MARK..SIDDHAM SECTION MARK WITH CIRCLES AND FOUR ENCLOSURES 11641..11642 ; Terminal_Punctuation # Po [2] MODI DANDA..MODI DOUBLE DANDA 1173C..1173E ; Terminal_Punctuation # Po [3] AHOM SIGN SMALL SECTION..AHOM SIGN RULAI +11A42..11A43 ; Terminal_Punctuation # Po [2] ZANABAZAR SQUARE MARK SHAD..ZANABAZAR SQUARE MARK DOUBLE SHAD +11A9B..11A9C ; Terminal_Punctuation # Po [2] SOYOMBO MARK SHAD..SOYOMBO MARK DOUBLE SHAD +11AA1..11AA2 ; Terminal_Punctuation # Po [2] SOYOMBO TERMINAL MARK-1..SOYOMBO TERMINAL MARK-2 +11C41..11C43 ; Terminal_Punctuation # Po [3] BHAIKSUKI DANDA..BHAIKSUKI WORD SEPARATOR +11C71 ; Terminal_Punctuation # Po MARCHEN MARK SHAD 12470..12474 ; Terminal_Punctuation # Po [5] CUNEIFORM PUNCTUATION SIGN OLD ASSYRIAN WORD DIVIDER..CUNEIFORM PUNCTUATION SIGN DIAGONAL QUADCOLON 16A6E..16A6F ; Terminal_Punctuation # Po [2] MRO DANDA..MRO DOUBLE DANDA 16AF5 ; Terminal_Punctuation # Po BASSA VAH FULL STOP @@ -204,7 +212,7 @@ FF64 ; Terminal_Punctuation # Po HALFWIDTH IDEOGRAPHIC COMMA 1BC9F ; Terminal_Punctuation # Po DUPLOYAN PUNCTUATION CHINOOK FULL STOP 1DA87..1DA8A ; Terminal_Punctuation # Po [4] SIGNWRITING COMMA..SIGNWRITING COLON -# Total code points: 238 +# Total code points: 252 # ================================================ @@ -429,6 +437,7 @@ FF41..FF46 ; Hex_Digit # L& [6] FULLWIDTH LATIN SMALL LETTER A..FULLWIDTH L 081B..0823 ; Other_Alphabetic # Mn [9] SAMARITAN MARK EPENTHETIC YUT..SAMARITAN VOWEL SIGN A 0825..0827 ; Other_Alphabetic # Mn [3] SAMARITAN VOWEL SIGN SHORT A..SAMARITAN VOWEL SIGN U 0829..082C ; Other_Alphabetic # Mn [4] SAMARITAN VOWEL SIGN LONG I..SAMARITAN VOWEL SIGN SUKUN +08D4..08DF ; Other_Alphabetic # Mn [12] ARABIC SMALL HIGH WORD AR-RUB..ARABIC SMALL HIGH WORD WAQFA 08E3..08E9 ; Other_Alphabetic # Mn [7] ARABIC TURNED DAMMA BELOW..ARABIC CURLY KASRATAN 08F0..0902 ; Other_Alphabetic # Mn [19] ARABIC OPEN FATHATAN..DEVANAGARI SIGN ANUSVARA 0903 ; Other_Alphabetic # Mc DEVANAGARI SIGN VISARGA @@ -465,6 +474,7 @@ FF41..FF46 ; Hex_Digit # L& [6] FULLWIDTH LATIN SMALL LETTER A..FULLWIDTH L 0AC9 ; Other_Alphabetic # Mc GUJARATI VOWEL SIGN CANDRA O 0ACB..0ACC ; Other_Alphabetic # Mc [2] GUJARATI VOWEL SIGN O..GUJARATI VOWEL SIGN AU 0AE2..0AE3 ; Other_Alphabetic # Mn [2] GUJARATI VOWEL SIGN VOCALIC L..GUJARATI VOWEL SIGN VOCALIC LL +0AFA..0AFC ; Other_Alphabetic # Mn [3] GUJARATI SIGN SUKUN..GUJARATI SIGN MADDAH 0B01 ; Other_Alphabetic # Mn ORIYA SIGN CANDRABINDU 0B02..0B03 ; Other_Alphabetic # Mc [2] ORIYA SIGN ANUSVARA..ORIYA SIGN VISARGA 0B3E ; Other_Alphabetic # Mc ORIYA VOWEL SIGN AA @@ -502,7 +512,7 @@ FF41..FF46 ; Hex_Digit # L& [6] FULLWIDTH LATIN SMALL LETTER A..FULLWIDTH L 0CCC ; Other_Alphabetic # Mn KANNADA VOWEL SIGN AU 0CD5..0CD6 ; Other_Alphabetic # Mc [2] KANNADA LENGTH MARK..KANNADA AI LENGTH MARK 0CE2..0CE3 ; Other_Alphabetic # Mn [2] KANNADA VOWEL SIGN VOCALIC L..KANNADA VOWEL SIGN VOCALIC LL -0D01 ; Other_Alphabetic # Mn MALAYALAM SIGN CANDRABINDU +0D00..0D01 ; Other_Alphabetic # Mn [2] MALAYALAM SIGN COMBINING ANUSVARA ABOVE..MALAYALAM SIGN CANDRABINDU 0D02..0D03 ; Other_Alphabetic # Mc [2] MALAYALAM SIGN ANUSVARA..MALAYALAM SIGN VISARGA 0D3E..0D40 ; Other_Alphabetic # Mc [3] MALAYALAM VOWEL SIGN AA..MALAYALAM VOWEL SIGN II 0D41..0D44 ; Other_Alphabetic # Mn [4] MALAYALAM VOWEL SIGN U..MALAYALAM VOWEL SIGN VOCALIC RR @@ -556,6 +566,7 @@ FF41..FF46 ; Hex_Digit # L& [6] FULLWIDTH LATIN SMALL LETTER A..FULLWIDTH L 17BE..17C5 ; Other_Alphabetic # Mc [8] KHMER VOWEL SIGN OE..KHMER VOWEL SIGN AU 17C6 ; Other_Alphabetic # Mn KHMER SIGN NIKAHIT 17C7..17C8 ; Other_Alphabetic # Mc [2] KHMER SIGN REAHMUK..KHMER SIGN YUUKALEAPINTU +1885..1886 ; Other_Alphabetic # Mn [2] MONGOLIAN LETTER ALI GALI BALUDA..MONGOLIAN LETTER ALI GALI THREE BALUDA 18A9 ; Other_Alphabetic # Mn MONGOLIAN LETTER ALI GALI DAGALGA 1920..1922 ; Other_Alphabetic # Mn [3] LIMBU VOWEL SIGN A..LIMBU VOWEL SIGN U 1923..1926 ; Other_Alphabetic # Mc [4] LIMBU VOWEL SIGN EE..LIMBU VOWEL SIGN AU @@ -613,6 +624,7 @@ A825..A826 ; Other_Alphabetic # Mn [2] SYLOTI NAGRI VOWEL SIGN U..SYLOTI NA A827 ; Other_Alphabetic # Mc SYLOTI NAGRI VOWEL SIGN OO A880..A881 ; Other_Alphabetic # Mc [2] SAURASHTRA SIGN ANUSVARA..SAURASHTRA SIGN VISARGA A8B4..A8C3 ; Other_Alphabetic # Mc [16] SAURASHTRA CONSONANT SIGN HAARU..SAURASHTRA VOWEL SIGN AU +A8C5 ; Other_Alphabetic # Mn SAURASHTRA SIGN CANDRABINDU A926..A92A ; Other_Alphabetic # Mn [5] KAYAH LI VOWEL UE..KAYAH LI VOWEL O A947..A951 ; Other_Alphabetic # Mn [11] REJANG VOWEL SIGN I..REJANG CONSONANT SIGN R A952 ; Other_Alphabetic # Mc REJANG CONSONANT SIGN H @@ -671,6 +683,7 @@ FB1E ; Other_Alphabetic # Mn HEBREW POINT JUDEO-SPANISH VARIKA 11232..11233 ; Other_Alphabetic # Mc [2] KHOJKI VOWEL SIGN O..KHOJKI VOWEL SIGN AU 11234 ; Other_Alphabetic # Mn KHOJKI SIGN ANUSVARA 11237 ; Other_Alphabetic # Mn KHOJKI SIGN SHADDA +1123E ; Other_Alphabetic # Mn KHOJKI SIGN SUKUN 112DF ; Other_Alphabetic # Mn KHUDAWADI SIGN ANUSVARA 112E0..112E2 ; Other_Alphabetic # Mc [3] KHUDAWADI VOWEL SIGN AA..KHUDAWADI VOWEL SIGN II 112E3..112E8 ; Other_Alphabetic # Mn [6] KHUDAWADI VOWEL SIGN U..KHUDAWADI VOWEL SIGN AU @@ -683,6 +696,11 @@ FB1E ; Other_Alphabetic # Mn HEBREW POINT JUDEO-SPANISH VARIKA 1134B..1134C ; Other_Alphabetic # Mc [2] GRANTHA VOWEL SIGN OO..GRANTHA VOWEL SIGN AU 11357 ; Other_Alphabetic # Mc GRANTHA AU LENGTH MARK 11362..11363 ; Other_Alphabetic # Mc [2] GRANTHA VOWEL SIGN VOCALIC L..GRANTHA VOWEL SIGN VOCALIC LL +11435..11437 ; Other_Alphabetic # Mc [3] NEWA VOWEL SIGN AA..NEWA VOWEL SIGN II +11438..1143F ; Other_Alphabetic # Mn [8] NEWA VOWEL SIGN U..NEWA VOWEL SIGN AI +11440..11441 ; Other_Alphabetic # Mc [2] NEWA VOWEL SIGN O..NEWA VOWEL SIGN AU +11443..11444 ; Other_Alphabetic # Mn [2] NEWA SIGN CANDRABINDU..NEWA SIGN ANUSVARA +11445 ; Other_Alphabetic # Mc NEWA SIGN VISARGA 114B0..114B2 ; Other_Alphabetic # Mc [3] TIRHUTA VOWEL SIGN AA..TIRHUTA VOWEL SIGN II 114B3..114B8 ; Other_Alphabetic # Mn [6] TIRHUTA VOWEL SIGN U..TIRHUTA VOWEL SIGN VOCALIC LL 114B9 ; Other_Alphabetic # Mc TIRHUTA VOWEL SIGN E @@ -712,14 +730,48 @@ FB1E ; Other_Alphabetic # Mn HEBREW POINT JUDEO-SPANISH VARIKA 11722..11725 ; Other_Alphabetic # Mn [4] AHOM VOWEL SIGN I..AHOM VOWEL SIGN UU 11726 ; Other_Alphabetic # Mc AHOM VOWEL SIGN E 11727..1172A ; Other_Alphabetic # Mn [4] AHOM VOWEL SIGN AW..AHOM VOWEL SIGN AM +11A01..11A06 ; Other_Alphabetic # Mn [6] ZANABAZAR SQUARE VOWEL SIGN I..ZANABAZAR SQUARE VOWEL SIGN O +11A07..11A08 ; Other_Alphabetic # Mc [2] ZANABAZAR SQUARE VOWEL SIGN AI..ZANABAZAR SQUARE VOWEL SIGN AU +11A09..11A0A ; Other_Alphabetic # Mn [2] ZANABAZAR SQUARE VOWEL SIGN REVERSED I..ZANABAZAR SQUARE VOWEL LENGTH MARK +11A35..11A38 ; Other_Alphabetic # Mn [4] ZANABAZAR SQUARE SIGN CANDRABINDU..ZANABAZAR SQUARE SIGN ANUSVARA +11A39 ; Other_Alphabetic # Mc ZANABAZAR SQUARE SIGN VISARGA +11A3B..11A3E ; Other_Alphabetic # Mn [4] ZANABAZAR SQUARE CLUSTER-FINAL LETTER YA..ZANABAZAR SQUARE CLUSTER-FINAL LETTER VA +11A51..11A56 ; Other_Alphabetic # Mn [6] SOYOMBO VOWEL SIGN I..SOYOMBO VOWEL SIGN OE +11A57..11A58 ; Other_Alphabetic # Mc [2] SOYOMBO VOWEL SIGN AI..SOYOMBO VOWEL SIGN AU +11A59..11A5B ; Other_Alphabetic # Mn [3] SOYOMBO VOWEL SIGN VOCALIC R..SOYOMBO VOWEL LENGTH MARK +11A8A..11A96 ; Other_Alphabetic # Mn [13] SOYOMBO FINAL CONSONANT SIGN G..SOYOMBO SIGN ANUSVARA +11A97 ; Other_Alphabetic # Mc SOYOMBO SIGN VISARGA +11C2F ; Other_Alphabetic # Mc BHAIKSUKI VOWEL SIGN AA +11C30..11C36 ; Other_Alphabetic # Mn [7] BHAIKSUKI VOWEL SIGN I..BHAIKSUKI VOWEL SIGN VOCALIC L +11C38..11C3D ; Other_Alphabetic # Mn [6] BHAIKSUKI VOWEL SIGN E..BHAIKSUKI SIGN ANUSVARA +11C3E ; Other_Alphabetic # Mc BHAIKSUKI SIGN VISARGA +11C92..11CA7 ; Other_Alphabetic # Mn [22] MARCHEN SUBJOINED LETTER KA..MARCHEN SUBJOINED LETTER ZA +11CA9 ; Other_Alphabetic # Mc MARCHEN SUBJOINED LETTER YA +11CAA..11CB0 ; Other_Alphabetic # Mn [7] MARCHEN SUBJOINED LETTER RA..MARCHEN VOWEL SIGN AA +11CB1 ; Other_Alphabetic # Mc MARCHEN VOWEL SIGN I +11CB2..11CB3 ; Other_Alphabetic # Mn [2] MARCHEN VOWEL SIGN U..MARCHEN VOWEL SIGN E +11CB4 ; Other_Alphabetic # Mc MARCHEN VOWEL SIGN O +11CB5..11CB6 ; Other_Alphabetic # Mn [2] MARCHEN SIGN ANUSVARA..MARCHEN SIGN CANDRABINDU +11D31..11D36 ; Other_Alphabetic # Mn [6] MASARAM GONDI VOWEL SIGN AA..MASARAM GONDI VOWEL SIGN VOCALIC R +11D3A ; Other_Alphabetic # Mn MASARAM GONDI VOWEL SIGN E +11D3C..11D3D ; Other_Alphabetic # Mn [2] MASARAM GONDI VOWEL SIGN AI..MASARAM GONDI VOWEL SIGN O +11D3F..11D41 ; Other_Alphabetic # Mn [3] MASARAM GONDI VOWEL SIGN AU..MASARAM GONDI SIGN VISARGA +11D43 ; Other_Alphabetic # Mn MASARAM GONDI SIGN CANDRA +11D47 ; Other_Alphabetic # Mn MASARAM GONDI RA-KARA 16B30..16B36 ; Other_Alphabetic # Mn [7] PAHAWH HMONG MARK CIM TUB..PAHAWH HMONG MARK CIM TAUM 16F51..16F7E ; Other_Alphabetic # Mc [46] MIAO SIGN ASPIRATION..MIAO VOWEL SIGN NG 1BC9E ; Other_Alphabetic # Mn DUPLOYAN DOUBLE MARK +1E000..1E006 ; Other_Alphabetic # Mn [7] COMBINING GLAGOLITIC LETTER AZU..COMBINING GLAGOLITIC LETTER ZHIVETE +1E008..1E018 ; Other_Alphabetic # Mn [17] COMBINING GLAGOLITIC LETTER ZEMLJA..COMBINING GLAGOLITIC LETTER HERU +1E01B..1E021 ; Other_Alphabetic # Mn [7] COMBINING GLAGOLITIC LETTER SHTA..COMBINING GLAGOLITIC LETTER YATI +1E023..1E024 ; Other_Alphabetic # Mn [2] COMBINING GLAGOLITIC LETTER YU..COMBINING GLAGOLITIC LETTER SMALL YUS +1E026..1E02A ; Other_Alphabetic # Mn [5] COMBINING GLAGOLITIC LETTER YO..COMBINING GLAGOLITIC LETTER FITA +1E947 ; Other_Alphabetic # Mn ADLAM HAMZA 1F130..1F149 ; Other_Alphabetic # So [26] SQUARED LATIN CAPITAL LETTER A..SQUARED LATIN CAPITAL LETTER Z 1F150..1F169 ; Other_Alphabetic # So [26] NEGATIVE CIRCLED LATIN CAPITAL LETTER A..NEGATIVE CIRCLED LATIN CAPITAL LETTER Z 1F170..1F189 ; Other_Alphabetic # So [26] NEGATIVE SQUARED LATIN CAPITAL LETTER A..NEGATIVE SQUARED LATIN CAPITAL LETTER Z -# Total code points: 1116 +# Total code points: 1300 # ================================================ @@ -728,16 +780,20 @@ FB1E ; Other_Alphabetic # Mn HEBREW POINT JUDEO-SPANISH VARIKA 3021..3029 ; Ideographic # Nl [9] HANGZHOU NUMERAL ONE..HANGZHOU NUMERAL NINE 3038..303A ; Ideographic # Nl [3] HANGZHOU NUMERAL TEN..HANGZHOU NUMERAL THIRTY 3400..4DB5 ; Ideographic # Lo [6582] CJK UNIFIED IDEOGRAPH-3400..CJK UNIFIED IDEOGRAPH-4DB5 -4E00..9FD5 ; Ideographic # Lo [20950] CJK UNIFIED IDEOGRAPH-4E00..CJK UNIFIED IDEOGRAPH-9FD5 +4E00..9FEA ; Ideographic # Lo [20971] CJK UNIFIED IDEOGRAPH-4E00..CJK UNIFIED IDEOGRAPH-9FEA F900..FA6D ; Ideographic # Lo [366] CJK COMPATIBILITY IDEOGRAPH-F900..CJK COMPATIBILITY IDEOGRAPH-FA6D FA70..FAD9 ; Ideographic # Lo [106] CJK COMPATIBILITY IDEOGRAPH-FA70..CJK COMPATIBILITY IDEOGRAPH-FAD9 +17000..187EC ; Ideographic # Lo [6125] TANGUT IDEOGRAPH-17000..TANGUT IDEOGRAPH-187EC +18800..18AF2 ; Ideographic # Lo [755] TANGUT COMPONENT-001..TANGUT COMPONENT-755 +1B170..1B2FB ; Ideographic # Lo [396] NUSHU CHARACTER-1B170..NUSHU CHARACTER-1B2FB 20000..2A6D6 ; Ideographic # Lo [42711] CJK UNIFIED IDEOGRAPH-20000..CJK UNIFIED IDEOGRAPH-2A6D6 2A700..2B734 ; Ideographic # Lo [4149] CJK UNIFIED IDEOGRAPH-2A700..CJK UNIFIED IDEOGRAPH-2B734 2B740..2B81D ; Ideographic # Lo [222] CJK UNIFIED IDEOGRAPH-2B740..CJK UNIFIED IDEOGRAPH-2B81D 2B820..2CEA1 ; Ideographic # Lo [5762] CJK UNIFIED IDEOGRAPH-2B820..CJK UNIFIED IDEOGRAPH-2CEA1 +2CEB0..2EBE0 ; Ideographic # Lo [7473] CJK UNIFIED IDEOGRAPH-2CEB0..CJK UNIFIED IDEOGRAPH-2EBE0 2F800..2FA1D ; Ideographic # Lo [542] CJK COMPATIBILITY IDEOGRAPH-2F800..CJK COMPATIBILITY IDEOGRAPH-2FA1D -# Total code points: 81404 +# Total code points: 96174 # ================================================ @@ -793,12 +849,14 @@ FA70..FAD9 ; Ideographic # Lo [106] CJK COMPATIBILITY IDEOGRAPH-FA70..CJK COM 0A4D ; Diacritic # Mn GURMUKHI SIGN VIRAMA 0ABC ; Diacritic # Mn GUJARATI SIGN NUKTA 0ACD ; Diacritic # Mn GUJARATI SIGN VIRAMA +0AFD..0AFF ; Diacritic # Mn [3] GUJARATI SIGN THREE-DOT NUKTA ABOVE..GUJARATI SIGN TWO-CIRCLE NUKTA ABOVE 0B3C ; Diacritic # Mn ORIYA SIGN NUKTA 0B4D ; Diacritic # Mn ORIYA SIGN VIRAMA 0BCD ; Diacritic # Mn TAMIL SIGN VIRAMA 0C4D ; Diacritic # Mn TELUGU SIGN VIRAMA 0CBC ; Diacritic # Mn KANNADA SIGN NUKTA 0CCD ; Diacritic # Mn KANNADA SIGN VIRAMA +0D3B..0D3C ; Diacritic # Mn [2] MALAYALAM SIGN VERTICAL BAR VIRAMA..MALAYALAM SIGN CIRCULAR VIRAMA 0D4D ; Diacritic # Mn MALAYALAM SIGN VIRAMA 0DCA ; Diacritic # Mn SINHALA SIGN AL-LAKUNA 0E47..0E4C ; Diacritic # Mn [6] THAI CHARACTER MAITAIKHU..THAI CHARACTER THANTHAKHAT @@ -838,10 +896,11 @@ FA70..FAD9 ; Ideographic # Lo [106] CJK COMPATIBILITY IDEOGRAPH-FA70..CJK COM 1CE2..1CE8 ; Diacritic # Mn [7] VEDIC SIGN VISARGA SVARITA..VEDIC SIGN VISARGA ANUDATTA WITH TAIL 1CED ; Diacritic # Mn VEDIC SIGN TIRYAK 1CF4 ; Diacritic # Mn VEDIC TONE CANDRA ABOVE +1CF7 ; Diacritic # Mc VEDIC SIGN ATIKRAMA 1CF8..1CF9 ; Diacritic # Mn [2] VEDIC TONE RING ABOVE..VEDIC TONE DOUBLE RING ABOVE 1D2C..1D6A ; Diacritic # Lm [63] MODIFIER LETTER CAPITAL A..GREEK SUBSCRIPT SMALL LETTER CHI 1DC4..1DCF ; Diacritic # Mn [12] COMBINING MACRON-ACUTE..COMBINING ZIGZAG BELOW -1DF5 ; Diacritic # Mn COMBINING UP TACK ABOVE +1DF5..1DF9 ; Diacritic # Mn [5] COMBINING UP TACK ABOVE..COMBINING WIDE INVERTED BRIDGE BELOW 1DFD..1DFF ; Diacritic # Mn [3] COMBINING ALMOST EQUAL TO BELOW..COMBINING RIGHT ARROWHEAD AND DOWN ARROWHEAD BELOW 1FBD ; Diacritic # Sk GREEK KORONIS 1FBF..1FC1 ; Diacritic # Sk [3] GREEK PSILI..GREEK DIALYTIKA AND PERISPOMENI @@ -906,12 +965,20 @@ FFE3 ; Diacritic # Sk FULLWIDTH MACRON 1134D ; Diacritic # Mc GRANTHA SIGN VIRAMA 11366..1136C ; Diacritic # Mn [7] COMBINING GRANTHA DIGIT ZERO..COMBINING GRANTHA DIGIT SIX 11370..11374 ; Diacritic # Mn [5] COMBINING GRANTHA LETTER A..COMBINING GRANTHA LETTER PA +11442 ; Diacritic # Mn NEWA SIGN VIRAMA +11446 ; Diacritic # Mn NEWA SIGN NUKTA 114C2..114C3 ; Diacritic # Mn [2] TIRHUTA SIGN VIRAMA..TIRHUTA SIGN NUKTA 115BF..115C0 ; Diacritic # Mn [2] SIDDHAM SIGN VIRAMA..SIDDHAM SIGN NUKTA 1163F ; Diacritic # Mn MODI SIGN VIRAMA 116B6 ; Diacritic # Mc TAKRI SIGN VIRAMA 116B7 ; Diacritic # Mn TAKRI SIGN NUKTA 1172B ; Diacritic # Mn AHOM SIGN KILLER +11A34 ; Diacritic # Mn ZANABAZAR SQUARE SIGN VIRAMA +11A47 ; Diacritic # Mn ZANABAZAR SQUARE SUBJOINER +11A99 ; Diacritic # Mn SOYOMBO SUBJOINER +11C3F ; Diacritic # Mn BHAIKSUKI SIGN VIRAMA +11D42 ; Diacritic # Mn MASARAM GONDI SIGN NUKTA +11D44..11D45 ; Diacritic # Mn [2] MASARAM GONDI SIGN HALANTA..MASARAM GONDI VIRAMA 16AF0..16AF4 ; Diacritic # Mn [5] BASSA VAH COMBINING HIGH TONE..BASSA VAH COMBINING HIGH-LOW TONE 16F8F..16F92 ; Diacritic # Mn [4] MIAO TONE RIGHT..MIAO TONE BELOW 16F93..16F9F ; Diacritic # Lm [13] MIAO LETTER TONE-2..MIAO LETTER REFORMED TONE-8 @@ -921,8 +988,10 @@ FFE3 ; Diacritic # Sk FULLWIDTH MACRON 1D185..1D18B ; Diacritic # Mn [7] MUSICAL SYMBOL COMBINING DOIT..MUSICAL SYMBOL COMBINING TRIPLE TONGUE 1D1AA..1D1AD ; Diacritic # Mn [4] MUSICAL SYMBOL COMBINING DOWN BOW..MUSICAL SYMBOL COMBINING SNAP PIZZICATO 1E8D0..1E8D6 ; Diacritic # Mn [7] MENDE KIKAKUI COMBINING NUMBER TEENS..MENDE KIKAKUI COMBINING NUMBER MILLIONS +1E944..1E946 ; Diacritic # Mn [3] ADLAM ALIF LENGTHENER..ADLAM GEMINATION MARK +1E948..1E94A ; Diacritic # Mn [3] ADLAM CONSONANT MODIFIER..ADLAM NUKTA -# Total code points: 773 +# Total code points: 798 # ================================================ @@ -951,9 +1020,12 @@ AAF3..AAF4 ; Extender # Lm [2] MEETEI MAYEK SYLLABLE REPETITION MARK..MEETE FF70 ; Extender # Lm HALFWIDTH KATAKANA-HIRAGANA PROLONGED SOUND MARK 1135D ; Extender # Lo GRANTHA SIGN PLUTA 115C6..115C8 ; Extender # Po [3] SIDDHAM REPETITION MARK-1..SIDDHAM REPETITION MARK-3 +11A98 ; Extender # Mn SOYOMBO GEMINATION MARK 16B42..16B43 ; Extender # Lm [2] PAHAWH HMONG SIGN VOS NRUA..PAHAWH HMONG SIGN IB YAM +16FE0..16FE1 ; Extender # Lm [2] TANGUT ITERATION MARK..NUSHU ITERATION MARK +1E944..1E946 ; Extender # Mn [3] ADLAM ALIF LENGTHENER..ADLAM GEMINATION MARK -# Total code points: 38 +# Total code points: 44 # ================================================ @@ -1027,7 +1099,7 @@ FFFFE..FFFFF ; Noncharacter_Code_Point # Cn [2] <noncharacter-FFFFE>..<noncha 0D57 ; Other_Grapheme_Extend # Mc MALAYALAM AU LENGTH MARK 0DCF ; Other_Grapheme_Extend # Mc SINHALA VOWEL SIGN AELA-PILLA 0DDF ; Other_Grapheme_Extend # Mc SINHALA VOWEL SIGN GAYANUKITTA -200C..200D ; Other_Grapheme_Extend # Cf [2] ZERO WIDTH NON-JOINER..ZERO WIDTH JOINER +200C ; Other_Grapheme_Extend # Cf ZERO WIDTH NON-JOINER 302E..302F ; Other_Grapheme_Extend # Mc [2] HANGUL SINGLE DOT TONE MARK..HANGUL DOUBLE DOT TONE MARK FF9E..FF9F ; Other_Grapheme_Extend # Lm [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDTH KATAKANA SEMI-VOICED SOUND MARK 1133E ; Other_Grapheme_Extend # Mc GRANTHA VOWEL SIGN AA @@ -1037,8 +1109,9 @@ FF9E..FF9F ; Other_Grapheme_Extend # Lm [2] HALFWIDTH KATAKANA VOICED SOUND 115AF ; Other_Grapheme_Extend # Mc SIDDHAM VOWEL SIGN AA 1D165 ; Other_Grapheme_Extend # Mc MUSICAL SYMBOL COMBINING STEM 1D16E..1D172 ; Other_Grapheme_Extend # Mc [5] MUSICAL SYMBOL COMBINING FLAG-1..MUSICAL SYMBOL COMBINING FLAG-5 +E0020..E007F ; Other_Grapheme_Extend # Cf [96] TAG SPACE..CANCEL TAG -# Total code points: 30 +# Total code points: 125 # ================================================ @@ -1064,7 +1137,7 @@ FF9E..FF9F ; Other_Grapheme_Extend # Lm [2] HALFWIDTH KATAKANA VOICED SOUND # ================================================ 3400..4DB5 ; Unified_Ideograph # Lo [6582] CJK UNIFIED IDEOGRAPH-3400..CJK UNIFIED IDEOGRAPH-4DB5 -4E00..9FD5 ; Unified_Ideograph # Lo [20950] CJK UNIFIED IDEOGRAPH-4E00..CJK UNIFIED IDEOGRAPH-9FD5 +4E00..9FEA ; Unified_Ideograph # Lo [20971] CJK UNIFIED IDEOGRAPH-4E00..CJK UNIFIED IDEOGRAPH-9FEA FA0E..FA0F ; Unified_Ideograph # Lo [2] CJK COMPATIBILITY IDEOGRAPH-FA0E..CJK COMPATIBILITY IDEOGRAPH-FA0F FA11 ; Unified_Ideograph # Lo CJK COMPATIBILITY IDEOGRAPH-FA11 FA13..FA14 ; Unified_Ideograph # Lo [2] CJK COMPATIBILITY IDEOGRAPH-FA13..CJK COMPATIBILITY IDEOGRAPH-FA14 @@ -1076,8 +1149,9 @@ FA27..FA29 ; Unified_Ideograph # Lo [3] CJK COMPATIBILITY IDEOGRAPH-FA27..C 2A700..2B734 ; Unified_Ideograph # Lo [4149] CJK UNIFIED IDEOGRAPH-2A700..CJK UNIFIED IDEOGRAPH-2B734 2B740..2B81D ; Unified_Ideograph # Lo [222] CJK UNIFIED IDEOGRAPH-2B740..CJK UNIFIED IDEOGRAPH-2B81D 2B820..2CEA1 ; Unified_Ideograph # Lo [5762] CJK UNIFIED IDEOGRAPH-2B820..CJK UNIFIED IDEOGRAPH-2CEA1 +2CEB0..2EBE0 ; Unified_Ideograph # Lo [7473] CJK UNIFIED IDEOGRAPH-2CEB0..CJK UNIFIED IDEOGRAPH-2EBE0 -# Total code points: 80388 +# Total code points: 87882 # ================================================ @@ -1106,9 +1180,8 @@ E01F0..E0FFF ; Other_Default_Ignorable_Code_Point # Cn [3600] <reserved-E01F0>. 2329 ; Deprecated # Ps LEFT-POINTING ANGLE BRACKET 232A ; Deprecated # Pe RIGHT-POINTING ANGLE BRACKET E0001 ; Deprecated # Cf LANGUAGE TAG -E007F ; Deprecated # Cf CANCEL TAG -# Total code points: 16 +# Total code points: 15 # ================================================ @@ -1160,11 +1233,12 @@ AABB..AABC ; Logical_Order_Exception # Lo [2] TAI VIET VOWEL AUE..TAI VIET # ================================================ +1885..1886 ; Other_ID_Start # Mn [2] MONGOLIAN LETTER ALI GALI BALUDA..MONGOLIAN LETTER ALI GALI THREE BALUDA 2118 ; Other_ID_Start # Sm SCRIPT CAPITAL P 212E ; Other_ID_Start # So ESTIMATED SYMBOL 309B..309C ; Other_ID_Start # Sk [2] KATAKANA-HIRAGANA VOICED SOUND MARK..KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK -# Total code points: 4 +# Total code points: 6 # ================================================ @@ -1177,72 +1251,76 @@ AABB..AABC ; Logical_Order_Exception # Lo [2] TAI VIET VOWEL AUE..TAI VIET # ================================================ -0021 ; STerm # Po EXCLAMATION MARK -002E ; STerm # Po FULL STOP -003F ; STerm # Po QUESTION MARK -0589 ; STerm # Po ARMENIAN FULL STOP -061F ; STerm # Po ARABIC QUESTION MARK -06D4 ; STerm # Po ARABIC FULL STOP -0700..0702 ; STerm # Po [3] SYRIAC END OF PARAGRAPH..SYRIAC SUBLINEAR FULL STOP -07F9 ; STerm # Po NKO EXCLAMATION MARK -0964..0965 ; STerm # Po [2] DEVANAGARI DANDA..DEVANAGARI DOUBLE DANDA -104A..104B ; STerm # Po [2] MYANMAR SIGN LITTLE SECTION..MYANMAR SIGN SECTION -1362 ; STerm # Po ETHIOPIC FULL STOP -1367..1368 ; STerm # Po [2] ETHIOPIC QUESTION MARK..ETHIOPIC PARAGRAPH SEPARATOR -166E ; STerm # Po CANADIAN SYLLABICS FULL STOP -1735..1736 ; STerm # Po [2] PHILIPPINE SINGLE PUNCTUATION..PHILIPPINE DOUBLE PUNCTUATION -1803 ; STerm # Po MONGOLIAN FULL STOP -1809 ; STerm # Po MONGOLIAN MANCHU FULL STOP -1944..1945 ; STerm # Po [2] LIMBU EXCLAMATION MARK..LIMBU QUESTION MARK -1AA8..1AAB ; STerm # Po [4] TAI THAM SIGN KAAN..TAI THAM SIGN SATKAANKUU -1B5A..1B5B ; STerm # Po [2] BALINESE PANTI..BALINESE PAMADA -1B5E..1B5F ; STerm # Po [2] BALINESE CARIK SIKI..BALINESE CARIK PAREREN -1C3B..1C3C ; STerm # Po [2] LEPCHA PUNCTUATION TA-ROL..LEPCHA PUNCTUATION NYET THYOOM TA-ROL -1C7E..1C7F ; STerm # Po [2] OL CHIKI PUNCTUATION MUCAAD..OL CHIKI PUNCTUATION DOUBLE MUCAAD -203C..203D ; STerm # Po [2] DOUBLE EXCLAMATION MARK..INTERROBANG -2047..2049 ; STerm # Po [3] DOUBLE QUESTION MARK..EXCLAMATION QUESTION MARK -2E2E ; STerm # Po REVERSED QUESTION MARK -2E3C ; STerm # Po STENOGRAPHIC FULL STOP -3002 ; STerm # Po IDEOGRAPHIC FULL STOP -A4FF ; STerm # Po LISU PUNCTUATION FULL STOP -A60E..A60F ; STerm # Po [2] VAI FULL STOP..VAI QUESTION MARK -A6F3 ; STerm # Po BAMUM FULL STOP -A6F7 ; STerm # Po BAMUM QUESTION MARK -A876..A877 ; STerm # Po [2] PHAGS-PA MARK SHAD..PHAGS-PA MARK DOUBLE SHAD -A8CE..A8CF ; STerm # Po [2] SAURASHTRA DANDA..SAURASHTRA DOUBLE DANDA -A92F ; STerm # Po KAYAH LI SIGN SHYA -A9C8..A9C9 ; STerm # Po [2] JAVANESE PADA LINGSA..JAVANESE PADA LUNGSI -AA5D..AA5F ; STerm # Po [3] CHAM PUNCTUATION DANDA..CHAM PUNCTUATION TRIPLE DANDA -AAF0..AAF1 ; STerm # Po [2] MEETEI MAYEK CHEIKHAN..MEETEI MAYEK AHANG KHUDAM -ABEB ; STerm # Po MEETEI MAYEK CHEIKHEI -FE52 ; STerm # Po SMALL FULL STOP -FE56..FE57 ; STerm # Po [2] SMALL QUESTION MARK..SMALL EXCLAMATION MARK -FF01 ; STerm # Po FULLWIDTH EXCLAMATION MARK -FF0E ; STerm # Po FULLWIDTH FULL STOP -FF1F ; STerm # Po FULLWIDTH QUESTION MARK -FF61 ; STerm # Po HALFWIDTH IDEOGRAPHIC FULL STOP -10A56..10A57 ; STerm # Po [2] KHAROSHTHI PUNCTUATION DANDA..KHAROSHTHI PUNCTUATION DOUBLE DANDA -11047..11048 ; STerm # Po [2] BRAHMI DANDA..BRAHMI DOUBLE DANDA -110BE..110C1 ; STerm # Po [4] KAITHI SECTION MARK..KAITHI DOUBLE DANDA -11141..11143 ; STerm # Po [3] CHAKMA DANDA..CHAKMA QUESTION MARK -111C5..111C6 ; STerm # Po [2] SHARADA DANDA..SHARADA DOUBLE DANDA -111CD ; STerm # Po SHARADA SUTRA MARK -111DE..111DF ; STerm # Po [2] SHARADA SECTION MARK-1..SHARADA SECTION MARK-2 -11238..11239 ; STerm # Po [2] KHOJKI DANDA..KHOJKI DOUBLE DANDA -1123B..1123C ; STerm # Po [2] KHOJKI SECTION MARK..KHOJKI DOUBLE SECTION MARK -112A9 ; STerm # Po MULTANI SECTION MARK -115C2..115C3 ; STerm # Po [2] SIDDHAM DANDA..SIDDHAM DOUBLE DANDA -115C9..115D7 ; STerm # Po [15] SIDDHAM END OF TEXT MARK..SIDDHAM SECTION MARK WITH CIRCLES AND FOUR ENCLOSURES -11641..11642 ; STerm # Po [2] MODI DANDA..MODI DOUBLE DANDA -1173C..1173E ; STerm # Po [3] AHOM SIGN SMALL SECTION..AHOM SIGN RULAI -16A6E..16A6F ; STerm # Po [2] MRO DANDA..MRO DOUBLE DANDA -16AF5 ; STerm # Po BASSA VAH FULL STOP -16B37..16B38 ; STerm # Po [2] PAHAWH HMONG SIGN VOS THOM..PAHAWH HMONG SIGN VOS TSHAB CEEB -16B44 ; STerm # Po PAHAWH HMONG SIGN XAUS -1BC9F ; STerm # Po DUPLOYAN PUNCTUATION CHINOOK FULL STOP -1DA88 ; STerm # Po SIGNWRITING FULL STOP - -# Total code points: 120 +0021 ; Sentence_Terminal # Po EXCLAMATION MARK +002E ; Sentence_Terminal # Po FULL STOP +003F ; Sentence_Terminal # Po QUESTION MARK +0589 ; Sentence_Terminal # Po ARMENIAN FULL STOP +061F ; Sentence_Terminal # Po ARABIC QUESTION MARK +06D4 ; Sentence_Terminal # Po ARABIC FULL STOP +0700..0702 ; Sentence_Terminal # Po [3] SYRIAC END OF PARAGRAPH..SYRIAC SUBLINEAR FULL STOP +07F9 ; Sentence_Terminal # Po NKO EXCLAMATION MARK +0964..0965 ; Sentence_Terminal # Po [2] DEVANAGARI DANDA..DEVANAGARI DOUBLE DANDA +104A..104B ; Sentence_Terminal # Po [2] MYANMAR SIGN LITTLE SECTION..MYANMAR SIGN SECTION +1362 ; Sentence_Terminal # Po ETHIOPIC FULL STOP +1367..1368 ; Sentence_Terminal # Po [2] ETHIOPIC QUESTION MARK..ETHIOPIC PARAGRAPH SEPARATOR +166E ; Sentence_Terminal # Po CANADIAN SYLLABICS FULL STOP +1735..1736 ; Sentence_Terminal # Po [2] PHILIPPINE SINGLE PUNCTUATION..PHILIPPINE DOUBLE PUNCTUATION +1803 ; Sentence_Terminal # Po MONGOLIAN FULL STOP +1809 ; Sentence_Terminal # Po MONGOLIAN MANCHU FULL STOP +1944..1945 ; Sentence_Terminal # Po [2] LIMBU EXCLAMATION MARK..LIMBU QUESTION MARK +1AA8..1AAB ; Sentence_Terminal # Po [4] TAI THAM SIGN KAAN..TAI THAM SIGN SATKAANKUU +1B5A..1B5B ; Sentence_Terminal # Po [2] BALINESE PANTI..BALINESE PAMADA +1B5E..1B5F ; Sentence_Terminal # Po [2] BALINESE CARIK SIKI..BALINESE CARIK PAREREN +1C3B..1C3C ; Sentence_Terminal # Po [2] LEPCHA PUNCTUATION TA-ROL..LEPCHA PUNCTUATION NYET THYOOM TA-ROL +1C7E..1C7F ; Sentence_Terminal # Po [2] OL CHIKI PUNCTUATION MUCAAD..OL CHIKI PUNCTUATION DOUBLE MUCAAD +203C..203D ; Sentence_Terminal # Po [2] DOUBLE EXCLAMATION MARK..INTERROBANG +2047..2049 ; Sentence_Terminal # Po [3] DOUBLE QUESTION MARK..EXCLAMATION QUESTION MARK +2E2E ; Sentence_Terminal # Po REVERSED QUESTION MARK +2E3C ; Sentence_Terminal # Po STENOGRAPHIC FULL STOP +3002 ; Sentence_Terminal # Po IDEOGRAPHIC FULL STOP +A4FF ; Sentence_Terminal # Po LISU PUNCTUATION FULL STOP +A60E..A60F ; Sentence_Terminal # Po [2] VAI FULL STOP..VAI QUESTION MARK +A6F3 ; Sentence_Terminal # Po BAMUM FULL STOP +A6F7 ; Sentence_Terminal # Po BAMUM QUESTION MARK +A876..A877 ; Sentence_Terminal # Po [2] PHAGS-PA MARK SHAD..PHAGS-PA MARK DOUBLE SHAD +A8CE..A8CF ; Sentence_Terminal # Po [2] SAURASHTRA DANDA..SAURASHTRA DOUBLE DANDA +A92F ; Sentence_Terminal # Po KAYAH LI SIGN SHYA +A9C8..A9C9 ; Sentence_Terminal # Po [2] JAVANESE PADA LINGSA..JAVANESE PADA LUNGSI +AA5D..AA5F ; Sentence_Terminal # Po [3] CHAM PUNCTUATION DANDA..CHAM PUNCTUATION TRIPLE DANDA +AAF0..AAF1 ; Sentence_Terminal # Po [2] MEETEI MAYEK CHEIKHAN..MEETEI MAYEK AHANG KHUDAM +ABEB ; Sentence_Terminal # Po MEETEI MAYEK CHEIKHEI +FE52 ; Sentence_Terminal # Po SMALL FULL STOP +FE56..FE57 ; Sentence_Terminal # Po [2] SMALL QUESTION MARK..SMALL EXCLAMATION MARK +FF01 ; Sentence_Terminal # Po FULLWIDTH EXCLAMATION MARK +FF0E ; Sentence_Terminal # Po FULLWIDTH FULL STOP +FF1F ; Sentence_Terminal # Po FULLWIDTH QUESTION MARK +FF61 ; Sentence_Terminal # Po HALFWIDTH IDEOGRAPHIC FULL STOP +10A56..10A57 ; Sentence_Terminal # Po [2] KHAROSHTHI PUNCTUATION DANDA..KHAROSHTHI PUNCTUATION DOUBLE DANDA +11047..11048 ; Sentence_Terminal # Po [2] BRAHMI DANDA..BRAHMI DOUBLE DANDA +110BE..110C1 ; Sentence_Terminal # Po [4] KAITHI SECTION MARK..KAITHI DOUBLE DANDA +11141..11143 ; Sentence_Terminal # Po [3] CHAKMA DANDA..CHAKMA QUESTION MARK +111C5..111C6 ; Sentence_Terminal # Po [2] SHARADA DANDA..SHARADA DOUBLE DANDA +111CD ; Sentence_Terminal # Po SHARADA SUTRA MARK +111DE..111DF ; Sentence_Terminal # Po [2] SHARADA SECTION MARK-1..SHARADA SECTION MARK-2 +11238..11239 ; Sentence_Terminal # Po [2] KHOJKI DANDA..KHOJKI DOUBLE DANDA +1123B..1123C ; Sentence_Terminal # Po [2] KHOJKI SECTION MARK..KHOJKI DOUBLE SECTION MARK +112A9 ; Sentence_Terminal # Po MULTANI SECTION MARK +1144B..1144C ; Sentence_Terminal # Po [2] NEWA DANDA..NEWA DOUBLE DANDA +115C2..115C3 ; Sentence_Terminal # Po [2] SIDDHAM DANDA..SIDDHAM DOUBLE DANDA +115C9..115D7 ; Sentence_Terminal # Po [15] SIDDHAM END OF TEXT MARK..SIDDHAM SECTION MARK WITH CIRCLES AND FOUR ENCLOSURES +11641..11642 ; Sentence_Terminal # Po [2] MODI DANDA..MODI DOUBLE DANDA +1173C..1173E ; Sentence_Terminal # Po [3] AHOM SIGN SMALL SECTION..AHOM SIGN RULAI +11A42..11A43 ; Sentence_Terminal # Po [2] ZANABAZAR SQUARE MARK SHAD..ZANABAZAR SQUARE MARK DOUBLE SHAD +11A9B..11A9C ; Sentence_Terminal # Po [2] SOYOMBO MARK SHAD..SOYOMBO MARK DOUBLE SHAD +11C41..11C42 ; Sentence_Terminal # Po [2] BHAIKSUKI DANDA..BHAIKSUKI DOUBLE DANDA +16A6E..16A6F ; Sentence_Terminal # Po [2] MRO DANDA..MRO DOUBLE DANDA +16AF5 ; Sentence_Terminal # Po BASSA VAH FULL STOP +16B37..16B38 ; Sentence_Terminal # Po [2] PAHAWH HMONG SIGN VOS THOM..PAHAWH HMONG SIGN VOS TSHAB CEEB +16B44 ; Sentence_Terminal # Po PAHAWH HMONG SIGN XAUS +1BC9F ; Sentence_Terminal # Po DUPLOYAN PUNCTUATION CHINOOK FULL STOP +1DA88 ; Sentence_Terminal # Po SIGNWRITING FULL STOP + +# Total code points: 128 # ================================================ @@ -1359,9 +1437,7 @@ E0100..E01EF ; Variation_Selector # Mn [240] VARIATION SELECTOR-17..VARIATION S 239B..23B3 ; Pattern_Syntax # Sm [25] LEFT PARENTHESIS UPPER HOOK..SUMMATION BOTTOM 23B4..23DB ; Pattern_Syntax # So [40] TOP SQUARE BRACKET..FUSE 23DC..23E1 ; Pattern_Syntax # Sm [6] TOP PARENTHESIS..BOTTOM TORTOISE SHELL BRACKET -23E2..23FA ; Pattern_Syntax # So [25] WHITE TRAPEZIUM..BLACK CIRCLE FOR RECORD -23FB..23FF ; Pattern_Syntax # Cn [5] <reserved-23FB>..<reserved-23FF> -2400..2426 ; Pattern_Syntax # So [39] SYMBOL FOR NULL..SYMBOL FOR SUBSTITUTE FORM TWO +23E2..2426 ; Pattern_Syntax # So [69] WHITE TRAPEZIUM..SYMBOL FOR SUBSTITUTE FORM TWO 2427..243F ; Pattern_Syntax # Cn [25] <reserved-2427>..<reserved-243F> 2440..244A ; Pattern_Syntax # So [11] OCR HOOK..OCR DOUBLE BACKSLASH 244B..245F ; Pattern_Syntax # Cn [21] <reserved-244B>..<reserved-245F> @@ -1449,8 +1525,8 @@ E0100..E01EF ; Variation_Selector # Mn [240] VARIATION SELECTOR-17..VARIATION S 2BBA..2BBC ; Pattern_Syntax # Cn [3] <reserved-2BBA>..<reserved-2BBC> 2BBD..2BC8 ; Pattern_Syntax # So [12] BALLOT BOX WITH LIGHT X..BLACK MEDIUM RIGHT-POINTING TRIANGLE CENTRED 2BC9 ; Pattern_Syntax # Cn <reserved-2BC9> -2BCA..2BD1 ; Pattern_Syntax # So [8] TOP HALF BLACK CIRCLE..UNCERTAINTY SIGN -2BD2..2BEB ; Pattern_Syntax # Cn [26] <reserved-2BD2>..<reserved-2BEB> +2BCA..2BD2 ; Pattern_Syntax # So [9] TOP HALF BLACK CIRCLE..GROUP MARK +2BD3..2BEB ; Pattern_Syntax # Cn [25] <reserved-2BD3>..<reserved-2BEB> 2BEC..2BEF ; Pattern_Syntax # So [4] LEFTWARDS TWO-HEADED ARROW WITH TRIANGLE ARROWHEADS..DOWNWARDS TWO-HEADED ARROW WITH TRIANGLE ARROWHEADS 2BF0..2BFF ; Pattern_Syntax # Cn [16] <reserved-2BF0>..<reserved-2BFF> 2E00..2E01 ; Pattern_Syntax # Po [2] RIGHT ANGLE SUBSTITUTION MARKER..RIGHT ANGLE DOTTED SUBSTITUTION MARKER @@ -1490,7 +1566,8 @@ E0100..E01EF ; Variation_Selector # Mn [240] VARIATION SELECTOR-17..VARIATION S 2E40 ; Pattern_Syntax # Pd DOUBLE HYPHEN 2E41 ; Pattern_Syntax # Po REVERSED COMMA 2E42 ; Pattern_Syntax # Ps DOUBLE LOW-REVERSED-9 QUOTATION MARK -2E43..2E7F ; Pattern_Syntax # Cn [61] <reserved-2E43>..<reserved-2E7F> +2E43..2E49 ; Pattern_Syntax # Po [7] DASH WITH LEFT UPTURN..DOUBLE STACKED COMMA +2E4A..2E7F ; Pattern_Syntax # Cn [54] <reserved-2E4A>..<reserved-2E7F> 3001..3003 ; Pattern_Syntax # Po [3] IDEOGRAPHIC COMMA..DITTO MARK 3008 ; Pattern_Syntax # Ps LEFT ANGLE BRACKET 3009 ; Pattern_Syntax # Pe RIGHT ANGLE BRACKET @@ -1522,4 +1599,20 @@ FE45..FE46 ; Pattern_Syntax # Po [2] SESAME DOT..WHITE SESAME DOT # Total code points: 2760 +# ================================================ + +0600..0605 ; Prepended_Concatenation_Mark # Cf [6] ARABIC NUMBER SIGN..ARABIC NUMBER MARK ABOVE +06DD ; Prepended_Concatenation_Mark # Cf ARABIC END OF AYAH +070F ; Prepended_Concatenation_Mark # Cf SYRIAC ABBREVIATION MARK +08E2 ; Prepended_Concatenation_Mark # Cf ARABIC DISPUTED END OF AYAH +110BD ; Prepended_Concatenation_Mark # Cf KAITHI NUMBER SIGN + +# Total code points: 10 + +# ================================================ + +1F1E6..1F1FF ; Regional_Indicator # So [26] REGIONAL INDICATOR SYMBOL LETTER A..REGIONAL INDICATOR SYMBOL LETTER Z + +# Total code points: 26 + # EOF diff --git a/tools-for-build/Scripts.txt b/tools-for-build/Scripts.txt index 7e42740407..72319448e9 100644 --- a/tools-for-build/Scripts.txt +++ b/tools-for-build/Scripts.txt @@ -1,10 +1,11 @@ -# Scripts-8.0.0.txt -# Date: 2015-03-11, 22:29:42 GMT [MD] +# Scripts-10.0.0.txt +# Date: 2017-03-11, 06:40:37 GMT +# © 2017 Unicode®, Inc. +# Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries. +# For terms of use, see http://www.unicode.org/terms_of_use.html # # Unicode Character Database -# Copyright (c) 1991-2015 Unicode, Inc. -# For terms of use, see http://www.unicode.org/terms_of_use.html -# For documentation, see http://www.unicode.org/reports/tr44/ +# For documentation, see http://www.unicode.org/reports/tr44/ # For more information, see: # UAX #24, Unicode Script Property: http://www.unicode.org/reports/tr24/ # Especially the sections: @@ -92,10 +93,10 @@ 0605 ; Common # Cf ARABIC NUMBER MARK ABOVE 060C ; Common # Po ARABIC COMMA 061B ; Common # Po ARABIC SEMICOLON -061C ; Common # Cf ARABIC LETTER MARK 061F ; Common # Po ARABIC QUESTION MARK 0640 ; Common # Lm ARABIC TATWEEL 06DD ; Common # Cf ARABIC END OF AYAH +08E2 ; Common # Cf ARABIC DISPUTED END OF AYAH 0964..0965 ; Common # Po [2] DEVANAGARI DANDA..DEVANAGARI DOUBLE DANDA 0E3F ; Common # Sc THAI CURRENCY SYMBOL BAHT 0FD5..0FD8 ; Common # So [4] RIGHT-FACING SVASTI SIGN..LEFT-FACING SVASTI SIGN WITH DOTS @@ -110,6 +111,7 @@ 1CEE..1CF1 ; Common # Lo [4] VEDIC SIGN HEXIFORM LONG ANUSVARA..VEDIC SIGN ANUSVARA UBHAYATO MUKHA 1CF2..1CF3 ; Common # Mc [2] VEDIC SIGN ARDHAVISARGA..VEDIC SIGN ROTATED ARDHAVISARGA 1CF5..1CF6 ; Common # Lo [2] VEDIC SIGN JIHVAMULIYA..VEDIC SIGN UPADHMANIYA +1CF7 ; Common # Mc VEDIC SIGN ATIKRAMA 2000..200A ; Common # Zs [11] EN QUAD..HAIR SPACE 200B ; Common # Cf ZERO WIDTH SPACE 200E..200F ; Common # Cf [2] LEFT-TO-RIGHT MARK..RIGHT-TO-LEFT MARK @@ -153,7 +155,7 @@ 208A..208C ; Common # Sm [3] SUBSCRIPT PLUS SIGN..SUBSCRIPT EQUALS SIGN 208D ; Common # Ps SUBSCRIPT LEFT PARENTHESIS 208E ; Common # Pe SUBSCRIPT RIGHT PARENTHESIS -20A0..20BE ; Common # Sc [31] EURO-CURRENCY SIGN..LARI SIGN +20A0..20BF ; Common # Sc [32] EURO-CURRENCY SIGN..BITCOIN SIGN 2100..2101 ; Common # So [2] ACCOUNT OF..ADDRESSED TO THE SUBJECT 2102 ; Common # L& DOUBLE-STRUCK CAPITAL C 2103..2106 ; Common # So [4] DEGREE CELSIUS..CADA UNA @@ -223,8 +225,7 @@ 239B..23B3 ; Common # Sm [25] LEFT PARENTHESIS UPPER HOOK..SUMMATION BOTTOM 23B4..23DB ; Common # So [40] TOP SQUARE BRACKET..FUSE 23DC..23E1 ; Common # Sm [6] TOP PARENTHESIS..BOTTOM TORTOISE SHELL BRACKET -23E2..23FA ; Common # So [25] WHITE TRAPEZIUM..BLACK CIRCLE FOR RECORD -2400..2426 ; Common # So [39] SYMBOL FOR NULL..SYMBOL FOR SUBSTITUTE FORM TWO +23E2..2426 ; Common # So [69] WHITE TRAPEZIUM..SYMBOL FOR SUBSTITUTE FORM TWO 2440..244A ; Common # So [11] OCR HOOK..OCR DOUBLE BACKSLASH 2460..249B ; Common # No [60] CIRCLED DIGIT ONE..NUMBER TWENTY FULL STOP 249C..24E9 ; Common # So [78] PARENTHESIZED LATIN SMALL LETTER A..CIRCLED LATIN SMALL LETTER Z @@ -309,7 +310,7 @@ 2B76..2B95 ; Common # So [32] NORTH WEST TRIANGLE-HEADED ARROW TO BAR..RIGHTWARDS BLACK ARROW 2B98..2BB9 ; Common # So [34] THREE-D TOP-LIGHTED LEFTWARDS EQUILATERAL ARROWHEAD..UP ARROWHEAD IN A RECTANGLE BOX 2BBD..2BC8 ; Common # So [12] BALLOT BOX WITH LIGHT X..BLACK MEDIUM RIGHT-POINTING TRIANGLE CENTRED -2BCA..2BD1 ; Common # So [8] TOP HALF BLACK CIRCLE..UNCERTAINTY SIGN +2BCA..2BD2 ; Common # So [9] TOP HALF BLACK CIRCLE..GROUP MARK 2BEC..2BEF ; Common # So [4] LEFTWARDS TWO-HEADED ARROW WITH TRIANGLE ARROWHEADS..DOWNWARDS TWO-HEADED ARROW WITH TRIANGLE ARROWHEADS 2E00..2E01 ; Common # Po [2] RIGHT ANGLE SUBSTITUTION MARKER..RIGHT ANGLE DOTTED SUBSTITUTION MARKER 2E02 ; Common # Pi LEFT SUBSTITUTION BRACKET @@ -348,6 +349,7 @@ 2E40 ; Common # Pd DOUBLE HYPHEN 2E41 ; Common # Po REVERSED COMMA 2E42 ; Common # Ps DOUBLE LOW-REVERSED-9 QUOTATION MARK +2E43..2E49 ; Common # Po [7] DASH WITH LEFT UPTURN..DOUBLE STACKED COMMA 2FF0..2FFB ; Common # So [12] IDEOGRAPHIC DESCRIPTION CHARACTER LEFT TO RIGHT..IDEOGRAPHIC DESCRIPTION CHARACTER OVERLAID 3000 ; Common # Zs IDEOGRAPHIC SPACE 3001..3003 ; Common # Po [3] IDEOGRAPHIC COMMA..DITTO MARK @@ -572,19 +574,18 @@ FFFC..FFFD ; Common # So [2] OBJECT REPLACEMENT CHARACTER..REPLACEMENT CHAR 1F100..1F10C ; Common # No [13] DIGIT ZERO FULL STOP..DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT ZERO 1F110..1F12E ; Common # So [31] PARENTHESIZED LATIN CAPITAL LETTER A..CIRCLED WZ 1F130..1F16B ; Common # So [60] SQUARED LATIN CAPITAL LETTER A..RAISED MD SIGN -1F170..1F19A ; Common # So [43] NEGATIVE SQUARED LATIN CAPITAL LETTER A..SQUARED VS +1F170..1F1AC ; Common # So [61] NEGATIVE SQUARED LATIN CAPITAL LETTER A..SQUARED VOD 1F1E6..1F1FF ; Common # So [26] REGIONAL INDICATOR SYMBOL LETTER A..REGIONAL INDICATOR SYMBOL LETTER Z 1F201..1F202 ; Common # So [2] SQUARED KATAKANA KOKO..SQUARED KATAKANA SA -1F210..1F23A ; Common # So [43] SQUARED CJK UNIFIED IDEOGRAPH-624B..SQUARED CJK UNIFIED IDEOGRAPH-55B6 +1F210..1F23B ; Common # So [44] SQUARED CJK UNIFIED IDEOGRAPH-624B..SQUARED CJK UNIFIED IDEOGRAPH-914D 1F240..1F248 ; Common # So [9] TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-672C..TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-6557 1F250..1F251 ; Common # So [2] CIRCLED IDEOGRAPH ADVANTAGE..CIRCLED IDEOGRAPH ACCEPT +1F260..1F265 ; Common # So [6] ROUNDED SYMBOL FOR FU..ROUNDED SYMBOL FOR CAI 1F300..1F3FA ; Common # So [251] CYCLONE..AMPHORA 1F3FB..1F3FF ; Common # Sk [5] EMOJI MODIFIER FITZPATRICK TYPE-1-2..EMOJI MODIFIER FITZPATRICK TYPE-6 -1F400..1F579 ; Common # So [378] RAT..JOYSTICK -1F57B..1F5A3 ; Common # So [41] LEFT HAND TELEPHONE RECEIVER..BLACK DOWN POINTING BACKHAND INDEX -1F5A5..1F6D0 ; Common # So [300] DESKTOP COMPUTER..PLACE OF WORSHIP +1F400..1F6D4 ; Common # So [725] RAT..PAGODA 1F6E0..1F6EC ; Common # So [13] HAMMER AND WRENCH..AIRPLANE ARRIVING -1F6F0..1F6F3 ; Common # So [4] SATELLITE..PASSENGER SHIP +1F6F0..1F6F8 ; Common # So [9] SATELLITE..FLYING SAUCER 1F700..1F773 ; Common # So [116] ALCHEMICAL SYMBOL FOR QUINTESSENCE..ALCHEMICAL SYMBOL FOR HALF OUNCE 1F780..1F7D4 ; Common # So [85] BLACK LEFT-POINTING ISOSCELES RIGHT TRIANGLE..HEAVY TWELVE POINTED PINWHEEL STAR 1F800..1F80B ; Common # So [12] LEFTWARDS ARROW WITH SMALL TRIANGLE ARROWHEAD..DOWNWARDS ARROW WITH LARGE TRIANGLE ARROWHEAD @@ -592,13 +593,17 @@ FFFC..FFFD ; Common # So [2] OBJECT REPLACEMENT CHARACTER..REPLACEMENT CHAR 1F850..1F859 ; Common # So [10] LEFTWARDS SANS-SERIF ARROW..UP DOWN SANS-SERIF ARROW 1F860..1F887 ; Common # So [40] WIDE-HEADED LEFTWARDS LIGHT BARB ARROW..WIDE-HEADED SOUTH WEST VERY HEAVY BARB ARROW 1F890..1F8AD ; Common # So [30] LEFTWARDS TRIANGLE ARROWHEAD..WHITE ARROW SHAFT WIDTH TWO THIRDS -1F910..1F918 ; Common # So [9] ZIPPER-MOUTH FACE..SIGN OF THE HORNS -1F980..1F984 ; Common # So [5] CRAB..UNICORN FACE +1F900..1F90B ; Common # So [12] CIRCLED CROSS FORMEE WITH FOUR DOTS..DOWNWARD FACING NOTCHED HOOK WITH DOT +1F910..1F93E ; Common # So [47] ZIPPER-MOUTH FACE..HANDBALL +1F940..1F94C ; Common # So [13] WILTED FLOWER..CURLING STONE +1F950..1F96B ; Common # So [28] CROISSANT..CANNED FOOD +1F980..1F997 ; Common # So [24] CRAB..CRICKET 1F9C0 ; Common # So CHEESE WEDGE +1F9D0..1F9E6 ; Common # So [23] FACE WITH MONOCLE..SOCKS E0001 ; Common # Cf LANGUAGE TAG E0020..E007F ; Common # Cf [96] TAG SPACE..CANCEL TAG -# Total code points: 7179 +# Total code points: 7363 # ================================================ @@ -641,7 +646,7 @@ A770 ; Latin # Lm MODIFIER LETTER US A771..A787 ; Latin # L& [23] LATIN SMALL LETTER DUM..LATIN SMALL LETTER INSULAR T A78B..A78E ; Latin # L& [4] LATIN CAPITAL LETTER SALTILLO..LATIN SMALL LETTER L WITH RETROFLEX HOOK AND BELT A78F ; Latin # Lo LATIN LETTER SINOLOGICAL DOT -A790..A7AD ; Latin # L& [30] LATIN CAPITAL LETTER N WITH DESCENDER..LATIN CAPITAL LETTER L WITH BELT +A790..A7AE ; Latin # L& [31] LATIN CAPITAL LETTER N WITH DESCENDER..LATIN CAPITAL LETTER SMALL CAPITAL I A7B0..A7B7 ; Latin # L& [8] LATIN CAPITAL LETTER TURNED K..LATIN SMALL LETTER OMEGA A7F7 ; Latin # Lo LATIN EPIGRAPHIC LETTER SIDEWAYS I A7F8..A7F9 ; Latin # Lm [2] MODIFIER LETTER CAPITAL H WITH STROKE..MODIFIER LETTER SMALL LIGATURE OE @@ -654,7 +659,7 @@ FB00..FB06 ; Latin # L& [7] LATIN SMALL LIGATURE FF..LATIN SMALL LIGATURE S FF21..FF3A ; Latin # L& [26] FULLWIDTH LATIN CAPITAL LETTER A..FULLWIDTH LATIN CAPITAL LETTER Z FF41..FF5A ; Latin # L& [26] FULLWIDTH LATIN SMALL LETTER A..FULLWIDTH LATIN SMALL LETTER Z -# Total code points: 1349 +# Total code points: 1350 # ================================================ @@ -708,13 +713,13 @@ AB65 ; Greek # L& GREEK LETTER SMALL CAPITAL OMEGA 10175..10178 ; Greek # No [4] GREEK ONE HALF SIGN..GREEK THREE QUARTERS SIGN 10179..10189 ; Greek # So [17] GREEK YEAR SIGN..GREEK TRYBLION BASE SIGN 1018A..1018B ; Greek # No [2] GREEK ZERO SIGN..GREEK ONE QUARTER SIGN -1018C ; Greek # So GREEK SINUSOID SIGN +1018C..1018E ; Greek # So [3] GREEK SINUSOID SIGN..NOMISMA SIGN 101A0 ; Greek # So GREEK SYMBOL TAU RHO 1D200..1D241 ; Greek # So [66] GREEK VOCAL NOTATION SYMBOL-1..GREEK INSTRUMENTAL NOTATION SYMBOL-54 1D242..1D244 ; Greek # Mn [3] COMBINING GREEK MUSICAL TRISEME..COMBINING GREEK MUSICAL PENTASEME 1D245 ; Greek # So GREEK MUSICAL LEIMMA -# Total code points: 516 +# Total code points: 518 # ================================================ @@ -724,6 +729,7 @@ AB65 ; Greek # L& GREEK LETTER SMALL CAPITAL OMEGA 0487 ; Cyrillic # Mn COMBINING CYRILLIC POKRYTIE 0488..0489 ; Cyrillic # Me [2] COMBINING CYRILLIC HUNDRED THOUSANDS SIGN..COMBINING CYRILLIC MILLIONS SIGN 048A..052F ; Cyrillic # L& [166] CYRILLIC CAPITAL LETTER SHORT I WITH TAIL..CYRILLIC SMALL LETTER EL WITH DESCENDER +1C80..1C88 ; Cyrillic # L& [9] CYRILLIC SMALL LETTER ROUNDED VE..CYRILLIC SMALL LETTER UNBLENDED UK 1D2B ; Cyrillic # L& CYRILLIC LETTER SMALL CAPITAL EL 1D78 ; Cyrillic # Lm MODIFIER LETTER CYRILLIC EN 2DE0..2DFF ; Cyrillic # Mn [32] COMBINING CYRILLIC LETTER BE..COMBINING CYRILLIC LETTER IOTIFIED BIG YUS @@ -740,7 +746,7 @@ A69C..A69D ; Cyrillic # Lm [2] MODIFIER LETTER CYRILLIC HARD SIGN..MODIFIER A69E..A69F ; Cyrillic # Mn [2] COMBINING CYRILLIC LETTER EF..COMBINING CYRILLIC LETTER IOTIFIED E FE2E..FE2F ; Cyrillic # Mn [2] COMBINING CYRILLIC TITLO LEFT HALF..COMBINING CYRILLIC TITLO RIGHT HALF -# Total code points: 434 +# Total code points: 443 # ================================================ @@ -791,6 +797,7 @@ FB46..FB4F ; Hebrew # Lo [10] HEBREW LETTER TSADI WITH DAGESH..HEBREW LIGATU 060D ; Arabic # Po ARABIC DATE SEPARATOR 060E..060F ; Arabic # So [2] ARABIC POETIC VERSE SIGN..ARABIC SIGN MISRA 0610..061A ; Arabic # Mn [11] ARABIC SIGN SALLALLAHOU ALAYHE WASSALLAM..ARABIC SMALL KASRA +061C ; Arabic # Cf ARABIC LETTER MARK 061E ; Arabic # Po ARABIC TRIPLE DOT PUNCTUATION MARK 0620..063F ; Arabic # Lo [32] ARABIC LETTER KASHMIRI YEH..ARABIC LETTER FARSI YEH WITH THREE DOTS ABOVE 0641..064A ; Arabic # Lo [10] ARABIC LETTER FEH..ARABIC LETTER YEH @@ -815,6 +822,8 @@ FB46..FB4F ; Hebrew # Lo [10] HEBREW LETTER TSADI WITH DAGESH..HEBREW LIGATU 06FF ; Arabic # Lo ARABIC LETTER HEH WITH INVERTED V 0750..077F ; Arabic # Lo [48] ARABIC LETTER BEH WITH THREE DOTS HORIZONTALLY BELOW..ARABIC LETTER KAF WITH TWO DOTS ABOVE 08A0..08B4 ; Arabic # Lo [21] ARABIC LETTER BEH WITH SMALL V BELOW..ARABIC LETTER KAF WITH DOT BELOW +08B6..08BD ; Arabic # Lo [8] ARABIC LETTER BEH WITH SMALL MEEM ABOVE..ARABIC LETTER AFRICAN NOON +08D4..08E1 ; Arabic # Mn [14] ARABIC SMALL HIGH WORD AR-RUB..ARABIC SMALL HIGH SIGN SAFHA 08E3..08FF ; Arabic # Mn [29] ARABIC TURNED DAMMA BELOW..ARABIC MARK SIDEWAYS NOON GHUNNA FB50..FBB1 ; Arabic # Lo [98] ARABIC LETTER ALEF WASLA ISOLATED FORM..ARABIC LETTER YEH BARREE WITH HAMZA ABOVE FINAL FORM FBB2..FBC1 ; Arabic # Sk [16] ARABIC SYMBOL DOT ABOVE..ARABIC SYMBOL SMALL TAH BELOW @@ -862,7 +871,7 @@ FE76..FEFC ; Arabic # Lo [135] ARABIC FATHA ISOLATED FORM..ARABIC LIGATURE LA 1EEAB..1EEBB ; Arabic # Lo [17] ARABIC MATHEMATICAL DOUBLE-STRUCK LAM..ARABIC MATHEMATICAL DOUBLE-STRUCK GHAIN 1EEF0..1EEF1 ; Arabic # Sm [2] ARABIC MATHEMATICAL OPERATOR MEEM WITH HAH WITH TATWEEL..ARABIC MATHEMATICAL OPERATOR HAH WITH DAL -# Total code points: 1257 +# Total code points: 1280 # ================================================ @@ -873,8 +882,9 @@ FE76..FEFC ; Arabic # Lo [135] ARABIC FATHA ISOLATED FORM..ARABIC LIGATURE LA 0712..072F ; Syriac # Lo [30] SYRIAC LETTER BETH..SYRIAC LETTER PERSIAN DHALATH 0730..074A ; Syriac # Mn [27] SYRIAC PTHAHA ABOVE..SYRIAC BARREKH 074D..074F ; Syriac # Lo [3] SYRIAC LETTER SOGDIAN ZHAIN..SYRIAC LETTER SOGDIAN FE +0860..086A ; Syriac # Lo [11] SYRIAC LETTER MALAYALAM NGA..SYRIAC LETTER MALAYALAM SSA -# Total code points: 77 +# Total code points: 88 # ================================================ @@ -944,8 +954,10 @@ A8FD ; Devanagari # Lo DEVANAGARI JAIN OM 09F4..09F9 ; Bengali # No [6] BENGALI CURRENCY NUMERATOR ONE..BENGALI CURRENCY DENOMINATOR SIXTEEN 09FA ; Bengali # So BENGALI ISSHAR 09FB ; Bengali # Sc BENGALI GANDA MARK +09FC ; Bengali # Lo BENGALI LETTER VEDIC ANUSVARA +09FD ; Bengali # Po BENGALI ABBREVIATION SIGN -# Total code points: 93 +# Total code points: 95 # ================================================ @@ -998,8 +1010,9 @@ A8FD ; Devanagari # Lo DEVANAGARI JAIN OM 0AF0 ; Gujarati # Po GUJARATI ABBREVIATION SIGN 0AF1 ; Gujarati # Sc GUJARATI RUPEE SIGN 0AF9 ; Gujarati # Lo GUJARATI LETTER ZHA +0AFA..0AFF ; Gujarati # Mn [6] GUJARATI SIGN SUKUN..GUJARATI SIGN TWO-CIRCLE NUKTA ABOVE -# Total code points: 85 +# Total code points: 91 # ================================================ @@ -1086,6 +1099,7 @@ A8FD ; Devanagari # Lo DEVANAGARI JAIN OM # ================================================ +0C80 ; Kannada # Lo KANNADA SIGN SPACING CANDRABINDU 0C81 ; Kannada # Mn KANNADA SIGN CANDRABINDU 0C82..0C83 ; Kannada # Mc [2] KANNADA SIGN ANUSVARA..KANNADA SIGN VISARGA 0C85..0C8C ; Kannada # Lo [8] KANNADA LETTER A..KANNADA LETTER VOCALIC L @@ -1109,15 +1123,16 @@ A8FD ; Devanagari # Lo DEVANAGARI JAIN OM 0CE6..0CEF ; Kannada # Nd [10] KANNADA DIGIT ZERO..KANNADA DIGIT NINE 0CF1..0CF2 ; Kannada # Lo [2] KANNADA SIGN JIHVAMULIYA..KANNADA SIGN UPADHMANIYA -# Total code points: 87 +# Total code points: 88 # ================================================ -0D01 ; Malayalam # Mn MALAYALAM SIGN CANDRABINDU +0D00..0D01 ; Malayalam # Mn [2] MALAYALAM SIGN COMBINING ANUSVARA ABOVE..MALAYALAM SIGN CANDRABINDU 0D02..0D03 ; Malayalam # Mc [2] MALAYALAM SIGN ANUSVARA..MALAYALAM SIGN VISARGA 0D05..0D0C ; Malayalam # Lo [8] MALAYALAM LETTER A..MALAYALAM LETTER VOCALIC L 0D0E..0D10 ; Malayalam # Lo [3] MALAYALAM LETTER E..MALAYALAM LETTER AI 0D12..0D3A ; Malayalam # Lo [41] MALAYALAM LETTER O..MALAYALAM LETTER TTTA +0D3B..0D3C ; Malayalam # Mn [2] MALAYALAM SIGN VERTICAL BAR VIRAMA..MALAYALAM SIGN CIRCULAR VIRAMA 0D3D ; Malayalam # Lo MALAYALAM SIGN AVAGRAHA 0D3E..0D40 ; Malayalam # Mc [3] MALAYALAM VOWEL SIGN AA..MALAYALAM VOWEL SIGN II 0D41..0D44 ; Malayalam # Mn [4] MALAYALAM VOWEL SIGN U..MALAYALAM VOWEL SIGN VOCALIC RR @@ -1125,15 +1140,18 @@ A8FD ; Devanagari # Lo DEVANAGARI JAIN OM 0D4A..0D4C ; Malayalam # Mc [3] MALAYALAM VOWEL SIGN O..MALAYALAM VOWEL SIGN AU 0D4D ; Malayalam # Mn MALAYALAM SIGN VIRAMA 0D4E ; Malayalam # Lo MALAYALAM LETTER DOT REPH +0D4F ; Malayalam # So MALAYALAM SIGN PARA +0D54..0D56 ; Malayalam # Lo [3] MALAYALAM LETTER CHILLU M..MALAYALAM LETTER CHILLU LLL 0D57 ; Malayalam # Mc MALAYALAM AU LENGTH MARK +0D58..0D5E ; Malayalam # No [7] MALAYALAM FRACTION ONE ONE-HUNDRED-AND-SIXTIETH..MALAYALAM FRACTION ONE FIFTH 0D5F..0D61 ; Malayalam # Lo [3] MALAYALAM LETTER ARCHAIC II..MALAYALAM LETTER VOCALIC LL 0D62..0D63 ; Malayalam # Mn [2] MALAYALAM VOWEL SIGN VOCALIC L..MALAYALAM VOWEL SIGN VOCALIC LL 0D66..0D6F ; Malayalam # Nd [10] MALAYALAM DIGIT ZERO..MALAYALAM DIGIT NINE -0D70..0D75 ; Malayalam # No [6] MALAYALAM NUMBER TEN..MALAYALAM FRACTION THREE QUARTERS +0D70..0D78 ; Malayalam # No [9] MALAYALAM NUMBER TEN..MALAYALAM FRACTION THREE SIXTEENTHS 0D79 ; Malayalam # So MALAYALAM DATE MARK 0D7A..0D7F ; Malayalam # Lo [6] MALAYALAM LETTER CHILLU NN..MALAYALAM LETTER CHILLU K -# Total code points: 100 +# Total code points: 117 # ================================================ @@ -1436,21 +1454,24 @@ AB70..ABBF ; Cherokee # L& [80] CHEROKEE SMALL LETTER A..CHEROKEE SMALL LETT 1820..1842 ; Mongolian # Lo [35] MONGOLIAN LETTER A..MONGOLIAN LETTER CHI 1843 ; Mongolian # Lm MONGOLIAN LETTER TODO LONG VOWEL SIGN 1844..1877 ; Mongolian # Lo [52] MONGOLIAN LETTER TODO E..MONGOLIAN LETTER MANCHU ZHA -1880..18A8 ; Mongolian # Lo [41] MONGOLIAN LETTER ALI GALI ANUSVARA ONE..MONGOLIAN LETTER MANCHU ALI GALI BHA +1880..1884 ; Mongolian # Lo [5] MONGOLIAN LETTER ALI GALI ANUSVARA ONE..MONGOLIAN LETTER ALI GALI INVERTED UBADAMA +1885..1886 ; Mongolian # Mn [2] MONGOLIAN LETTER ALI GALI BALUDA..MONGOLIAN LETTER ALI GALI THREE BALUDA +1887..18A8 ; Mongolian # Lo [34] MONGOLIAN LETTER ALI GALI A..MONGOLIAN LETTER MANCHU ALI GALI BHA 18A9 ; Mongolian # Mn MONGOLIAN LETTER ALI GALI DAGALGA 18AA ; Mongolian # Lo MONGOLIAN LETTER MANCHU ALI GALI LHA +11660..1166C ; Mongolian # Po [13] MONGOLIAN BIRGA WITH ORNAMENT..MONGOLIAN TURNED SWIRL BIRGA WITH DOUBLE ORNAMENT -# Total code points: 153 +# Total code points: 166 # ================================================ 3041..3096 ; Hiragana # Lo [86] HIRAGANA LETTER SMALL A..HIRAGANA LETTER SMALL KE 309D..309E ; Hiragana # Lm [2] HIRAGANA ITERATION MARK..HIRAGANA VOICED ITERATION MARK 309F ; Hiragana # Lo HIRAGANA DIGRAPH YORI -1B001 ; Hiragana # Lo HIRAGANA LETTER ARCHAIC YE +1B001..1B11E ; Hiragana # Lo [286] HIRAGANA LETTER ARCHAIC YE..HENTAIGANA LETTER N-MU-MO-2 1F200 ; Hiragana # So SQUARE HIRAGANA HOKA -# Total code points: 91 +# Total code points: 376 # ================================================ @@ -1469,10 +1490,10 @@ FF71..FF9D ; Katakana # Lo [45] HALFWIDTH KATAKANA LETTER A..HALFWIDTH KATAK # ================================================ 02EA..02EB ; Bopomofo # Sk [2] MODIFIER LETTER YIN DEPARTING TONE MARK..MODIFIER LETTER YANG DEPARTING TONE MARK -3105..312D ; Bopomofo # Lo [41] BOPOMOFO LETTER B..BOPOMOFO LETTER IH +3105..312E ; Bopomofo # Lo [42] BOPOMOFO LETTER B..BOPOMOFO LETTER O WITH DOT ABOVE 31A0..31BA ; Bopomofo # Lo [27] BOPOMOFO LETTER BU..BOPOMOFO LETTER ZY -# Total code points: 70 +# Total code points: 71 # ================================================ @@ -1485,16 +1506,17 @@ FF71..FF9D ; Katakana # Lo [45] HALFWIDTH KATAKANA LETTER A..HALFWIDTH KATAK 3038..303A ; Han # Nl [3] HANGZHOU NUMERAL TEN..HANGZHOU NUMERAL THIRTY 303B ; Han # Lm VERTICAL IDEOGRAPHIC ITERATION MARK 3400..4DB5 ; Han # Lo [6582] CJK UNIFIED IDEOGRAPH-3400..CJK UNIFIED IDEOGRAPH-4DB5 -4E00..9FD5 ; Han # Lo [20950] CJK UNIFIED IDEOGRAPH-4E00..CJK UNIFIED IDEOGRAPH-9FD5 +4E00..9FEA ; Han # Lo [20971] CJK UNIFIED IDEOGRAPH-4E00..CJK UNIFIED IDEOGRAPH-9FEA F900..FA6D ; Han # Lo [366] CJK COMPATIBILITY IDEOGRAPH-F900..CJK COMPATIBILITY IDEOGRAPH-FA6D FA70..FAD9 ; Han # Lo [106] CJK COMPATIBILITY IDEOGRAPH-FA70..CJK COMPATIBILITY IDEOGRAPH-FAD9 20000..2A6D6 ; Han # Lo [42711] CJK UNIFIED IDEOGRAPH-20000..CJK UNIFIED IDEOGRAPH-2A6D6 2A700..2B734 ; Han # Lo [4149] CJK UNIFIED IDEOGRAPH-2A700..CJK UNIFIED IDEOGRAPH-2B734 2B740..2B81D ; Han # Lo [222] CJK UNIFIED IDEOGRAPH-2B740..CJK UNIFIED IDEOGRAPH-2B81D 2B820..2CEA1 ; Han # Lo [5762] CJK UNIFIED IDEOGRAPH-2B820..CJK UNIFIED IDEOGRAPH-2CEA1 +2CEB0..2EBE0 ; Han # Lo [7473] CJK UNIFIED IDEOGRAPH-2CEB0..CJK UNIFIED IDEOGRAPH-2EBE0 2F800..2FA1D ; Han # Lo [542] CJK COMPATIBILITY IDEOGRAPH-2F800..CJK COMPATIBILITY IDEOGRAPH-2FA1D -# Total code points: 81734 +# Total code points: 89228 # ================================================ @@ -1509,8 +1531,9 @@ A490..A4C6 ; Yi # So [55] YI RADICAL QOT..YI RADICAL KE 10300..1031F ; Old_Italic # Lo [32] OLD ITALIC LETTER A..OLD ITALIC LETTER ESS 10320..10323 ; Old_Italic # No [4] OLD ITALIC NUMERAL ONE..OLD ITALIC NUMERAL FIFTY +1032D..1032F ; Old_Italic # Lo [3] OLD ITALIC LETTER YE..OLD ITALIC LETTER SOUTHERN TSE -# Total code points: 36 +# Total code points: 39 # ================================================ @@ -1542,8 +1565,8 @@ A490..A4C6 ; Yi # So [55] YI RADICAL QOT..YI RADICAL KE 1CED ; Inherited # Mn VEDIC SIGN TIRYAK 1CF4 ; Inherited # Mn VEDIC TONE CANDRA ABOVE 1CF8..1CF9 ; Inherited # Mn [2] VEDIC TONE RING ABOVE..VEDIC TONE DOUBLE RING ABOVE -1DC0..1DF5 ; Inherited # Mn [54] COMBINING DOTTED GRAVE ACCENT..COMBINING UP TACK ABOVE -1DFC..1DFF ; Inherited # Mn [4] COMBINING DOUBLE INVERTED BREVE BELOW..COMBINING RIGHT ARROWHEAD AND DOWN ARROWHEAD BELOW +1DC0..1DF9 ; Inherited # Mn [58] COMBINING DOTTED GRAVE ACCENT..COMBINING WIDE INVERTED BRIDGE BELOW +1DFB..1DFF ; Inherited # Mn [5] COMBINING DELETION MARK..COMBINING RIGHT ARROWHEAD AND DOWN ARROWHEAD BELOW 200C..200D ; Inherited # Cf [2] ZERO WIDTH NON-JOINER..ZERO WIDTH JOINER 20D0..20DC ; Inherited # Mn [13] COMBINING LEFT HARPOON ABOVE..COMBINING FOUR DOTS ABOVE 20DD..20E0 ; Inherited # Me [4] COMBINING ENCLOSING CIRCLE..COMBINING ENCLOSING CIRCLE BACKSLASH @@ -1562,7 +1585,7 @@ FE20..FE2D ; Inherited # Mn [14] COMBINING LIGATURE LEFT HALF..COMBINING CON 1D1AA..1D1AD ; Inherited # Mn [4] MUSICAL SYMBOL COMBINING DOWN BOW..MUSICAL SYMBOL COMBINING SNAP PIZZICATO E0100..E01EF ; Inherited # Mn [240] VARIATION SELECTOR-17..VARIATION SELECTOR-256 -# Total code points: 563 +# Total code points: 568 # ================================================ @@ -1705,8 +1728,13 @@ E0100..E01EF ; Inherited # Mn [240] VARIATION SELECTOR-17..VARIATION SELECTOR-2 2C00..2C2E ; Glagolitic # L& [47] GLAGOLITIC CAPITAL LETTER AZU..GLAGOLITIC CAPITAL LETTER LATINATE MYSLITE 2C30..2C5E ; Glagolitic # L& [47] GLAGOLITIC SMALL LETTER AZU..GLAGOLITIC SMALL LETTER LATINATE MYSLITE +1E000..1E006 ; Glagolitic # Mn [7] COMBINING GLAGOLITIC LETTER AZU..COMBINING GLAGOLITIC LETTER ZHIVETE +1E008..1E018 ; Glagolitic # Mn [17] COMBINING GLAGOLITIC LETTER ZEMLJA..COMBINING GLAGOLITIC LETTER HERU +1E01B..1E021 ; Glagolitic # Mn [7] COMBINING GLAGOLITIC LETTER SHTA..COMBINING GLAGOLITIC LETTER YATI +1E023..1E024 ; Glagolitic # Mn [2] COMBINING GLAGOLITIC LETTER YU..COMBINING GLAGOLITIC LETTER SMALL YUS +1E026..1E02A ; Glagolitic # Mn [5] COMBINING GLAGOLITIC LETTER YO..COMBINING GLAGOLITIC LETTER FITA -# Total code points: 94 +# Total code points: 132 # ================================================ @@ -1872,11 +1900,11 @@ A62A..A62B ; Vai # Lo [2] VAI SYLLABLE NDOLE MA..VAI SYLLABLE NDOLE DO A880..A881 ; Saurashtra # Mc [2] SAURASHTRA SIGN ANUSVARA..SAURASHTRA SIGN VISARGA A882..A8B3 ; Saurashtra # Lo [50] SAURASHTRA LETTER A..SAURASHTRA LETTER LLA A8B4..A8C3 ; Saurashtra # Mc [16] SAURASHTRA CONSONANT SIGN HAARU..SAURASHTRA VOWEL SIGN AU -A8C4 ; Saurashtra # Mn SAURASHTRA SIGN VIRAMA +A8C4..A8C5 ; Saurashtra # Mn [2] SAURASHTRA SIGN VIRAMA..SAURASHTRA SIGN CANDRABINDU A8CE..A8CF ; Saurashtra # Po [2] SAURASHTRA DANDA..SAURASHTRA DOUBLE DANDA A8D0..A8D9 ; Saurashtra # Nd [10] SAURASHTRA DIGIT ZERO..SAURASHTRA DIGIT NINE -# Total code points: 81 +# Total code points: 82 # ================================================ @@ -2314,8 +2342,9 @@ ABF0..ABF9 ; Meetei_Mayek # Nd [10] MEETEI MAYEK DIGIT ZERO..MEETEI MAYEK DI 11235 ; Khojki # Mc KHOJKI SIGN VIRAMA 11236..11237 ; Khojki # Mn [2] KHOJKI SIGN NUKTA..KHOJKI SIGN SHADDA 11238..1123D ; Khojki # Po [6] KHOJKI DANDA..KHOJKI ABBREVIATION SIGN +1123E ; Khojki # Mn KHOJKI SIGN SUKUN -# Total code points: 61 +# Total code points: 62 # ================================================ @@ -2536,4 +2565,129 @@ ABF0..ABF9 ; Meetei_Mayek # Nd [10] MEETEI MAYEK DIGIT ZERO..MEETEI MAYEK DI # Total code points: 672 +# ================================================ + +1E900..1E943 ; Adlam # L& [68] ADLAM CAPITAL LETTER ALIF..ADLAM SMALL LETTER SHA +1E944..1E94A ; Adlam # Mn [7] ADLAM ALIF LENGTHENER..ADLAM NUKTA +1E950..1E959 ; Adlam # Nd [10] ADLAM DIGIT ZERO..ADLAM DIGIT NINE +1E95E..1E95F ; Adlam # Po [2] ADLAM INITIAL EXCLAMATION MARK..ADLAM INITIAL QUESTION MARK + +# Total code points: 87 + +# ================================================ + +11C00..11C08 ; Bhaiksuki # Lo [9] BHAIKSUKI LETTER A..BHAIKSUKI LETTER VOCALIC L +11C0A..11C2E ; Bhaiksuki # Lo [37] BHAIKSUKI LETTER E..BHAIKSUKI LETTER HA +11C2F ; Bhaiksuki # Mc BHAIKSUKI VOWEL SIGN AA +11C30..11C36 ; Bhaiksuki # Mn [7] BHAIKSUKI VOWEL SIGN I..BHAIKSUKI VOWEL SIGN VOCALIC L +11C38..11C3D ; Bhaiksuki # Mn [6] BHAIKSUKI VOWEL SIGN E..BHAIKSUKI SIGN ANUSVARA +11C3E ; Bhaiksuki # Mc BHAIKSUKI SIGN VISARGA +11C3F ; Bhaiksuki # Mn BHAIKSUKI SIGN VIRAMA +11C40 ; Bhaiksuki # Lo BHAIKSUKI SIGN AVAGRAHA +11C41..11C45 ; Bhaiksuki # Po [5] BHAIKSUKI DANDA..BHAIKSUKI GAP FILLER-2 +11C50..11C59 ; Bhaiksuki # Nd [10] BHAIKSUKI DIGIT ZERO..BHAIKSUKI DIGIT NINE +11C5A..11C6C ; Bhaiksuki # No [19] BHAIKSUKI NUMBER ONE..BHAIKSUKI HUNDREDS UNIT MARK + +# Total code points: 97 + +# ================================================ + +11C70..11C71 ; Marchen # Po [2] MARCHEN HEAD MARK..MARCHEN MARK SHAD +11C72..11C8F ; Marchen # Lo [30] MARCHEN LETTER KA..MARCHEN LETTER A +11C92..11CA7 ; Marchen # Mn [22] MARCHEN SUBJOINED LETTER KA..MARCHEN SUBJOINED LETTER ZA +11CA9 ; Marchen # Mc MARCHEN SUBJOINED LETTER YA +11CAA..11CB0 ; Marchen # Mn [7] MARCHEN SUBJOINED LETTER RA..MARCHEN VOWEL SIGN AA +11CB1 ; Marchen # Mc MARCHEN VOWEL SIGN I +11CB2..11CB3 ; Marchen # Mn [2] MARCHEN VOWEL SIGN U..MARCHEN VOWEL SIGN E +11CB4 ; Marchen # Mc MARCHEN VOWEL SIGN O +11CB5..11CB6 ; Marchen # Mn [2] MARCHEN SIGN ANUSVARA..MARCHEN SIGN CANDRABINDU + +# Total code points: 68 + +# ================================================ + +11400..11434 ; Newa # Lo [53] NEWA LETTER A..NEWA LETTER HA +11435..11437 ; Newa # Mc [3] NEWA VOWEL SIGN AA..NEWA VOWEL SIGN II +11438..1143F ; Newa # Mn [8] NEWA VOWEL SIGN U..NEWA VOWEL SIGN AI +11440..11441 ; Newa # Mc [2] NEWA VOWEL SIGN O..NEWA VOWEL SIGN AU +11442..11444 ; Newa # Mn [3] NEWA SIGN VIRAMA..NEWA SIGN ANUSVARA +11445 ; Newa # Mc NEWA SIGN VISARGA +11446 ; Newa # Mn NEWA SIGN NUKTA +11447..1144A ; Newa # Lo [4] NEWA SIGN AVAGRAHA..NEWA SIDDHI +1144B..1144F ; Newa # Po [5] NEWA DANDA..NEWA ABBREVIATION SIGN +11450..11459 ; Newa # Nd [10] NEWA DIGIT ZERO..NEWA DIGIT NINE +1145B ; Newa # Po NEWA PLACEHOLDER MARK +1145D ; Newa # Po NEWA INSERTION SIGN + +# Total code points: 92 + +# ================================================ + +104B0..104D3 ; Osage # L& [36] OSAGE CAPITAL LETTER A..OSAGE CAPITAL LETTER ZHA +104D8..104FB ; Osage # L& [36] OSAGE SMALL LETTER A..OSAGE SMALL LETTER ZHA + +# Total code points: 72 + +# ================================================ + +16FE0 ; Tangut # Lm TANGUT ITERATION MARK +17000..187EC ; Tangut # Lo [6125] TANGUT IDEOGRAPH-17000..TANGUT IDEOGRAPH-187EC +18800..18AF2 ; Tangut # Lo [755] TANGUT COMPONENT-001..TANGUT COMPONENT-755 + +# Total code points: 6881 + +# ================================================ + +11D00..11D06 ; Masaram_Gondi # Lo [7] MASARAM GONDI LETTER A..MASARAM GONDI LETTER E +11D08..11D09 ; Masaram_Gondi # Lo [2] MASARAM GONDI LETTER AI..MASARAM GONDI LETTER O +11D0B..11D30 ; Masaram_Gondi # Lo [38] MASARAM GONDI LETTER AU..MASARAM GONDI LETTER TRA +11D31..11D36 ; Masaram_Gondi # Mn [6] MASARAM GONDI VOWEL SIGN AA..MASARAM GONDI VOWEL SIGN VOCALIC R +11D3A ; Masaram_Gondi # Mn MASARAM GONDI VOWEL SIGN E +11D3C..11D3D ; Masaram_Gondi # Mn [2] MASARAM GONDI VOWEL SIGN AI..MASARAM GONDI VOWEL SIGN O +11D3F..11D45 ; Masaram_Gondi # Mn [7] MASARAM GONDI VOWEL SIGN AU..MASARAM GONDI VIRAMA +11D46 ; Masaram_Gondi # Lo MASARAM GONDI REPHA +11D47 ; Masaram_Gondi # Mn MASARAM GONDI RA-KARA +11D50..11D59 ; Masaram_Gondi # Nd [10] MASARAM GONDI DIGIT ZERO..MASARAM GONDI DIGIT NINE + +# Total code points: 75 + +# ================================================ + +16FE1 ; Nushu # Lm NUSHU ITERATION MARK +1B170..1B2FB ; Nushu # Lo [396] NUSHU CHARACTER-1B170..NUSHU CHARACTER-1B2FB + +# Total code points: 397 + +# ================================================ + +11A50 ; Soyombo # Lo SOYOMBO LETTER A +11A51..11A56 ; Soyombo # Mn [6] SOYOMBO VOWEL SIGN I..SOYOMBO VOWEL SIGN OE +11A57..11A58 ; Soyombo # Mc [2] SOYOMBO VOWEL SIGN AI..SOYOMBO VOWEL SIGN AU +11A59..11A5B ; Soyombo # Mn [3] SOYOMBO VOWEL SIGN VOCALIC R..SOYOMBO VOWEL LENGTH MARK +11A5C..11A83 ; Soyombo # Lo [40] SOYOMBO LETTER KA..SOYOMBO LETTER KSSA +11A86..11A89 ; Soyombo # Lo [4] SOYOMBO CLUSTER-INITIAL LETTER RA..SOYOMBO CLUSTER-INITIAL LETTER SA +11A8A..11A96 ; Soyombo # Mn [13] SOYOMBO FINAL CONSONANT SIGN G..SOYOMBO SIGN ANUSVARA +11A97 ; Soyombo # Mc SOYOMBO SIGN VISARGA +11A98..11A99 ; Soyombo # Mn [2] SOYOMBO GEMINATION MARK..SOYOMBO SUBJOINER +11A9A..11A9C ; Soyombo # Po [3] SOYOMBO MARK TSHEG..SOYOMBO MARK DOUBLE SHAD +11A9E..11AA2 ; Soyombo # Po [5] SOYOMBO HEAD MARK WITH MOON AND SUN AND TRIPLE FLAME..SOYOMBO TERMINAL MARK-2 + +# Total code points: 80 + +# ================================================ + +11A00 ; Zanabazar_Square # Lo ZANABAZAR SQUARE LETTER A +11A01..11A06 ; Zanabazar_Square # Mn [6] ZANABAZAR SQUARE VOWEL SIGN I..ZANABAZAR SQUARE VOWEL SIGN O +11A07..11A08 ; Zanabazar_Square # Mc [2] ZANABAZAR SQUARE VOWEL SIGN AI..ZANABAZAR SQUARE VOWEL SIGN AU +11A09..11A0A ; Zanabazar_Square # Mn [2] ZANABAZAR SQUARE VOWEL SIGN REVERSED I..ZANABAZAR SQUARE VOWEL LENGTH MARK +11A0B..11A32 ; Zanabazar_Square # Lo [40] ZANABAZAR SQUARE LETTER KA..ZANABAZAR SQUARE LETTER KSSA +11A33..11A38 ; Zanabazar_Square # Mn [6] ZANABAZAR SQUARE FINAL CONSONANT MARK..ZANABAZAR SQUARE SIGN ANUSVARA +11A39 ; Zanabazar_Square # Mc ZANABAZAR SQUARE SIGN VISARGA +11A3A ; Zanabazar_Square # Lo ZANABAZAR SQUARE CLUSTER-INITIAL LETTER RA +11A3B..11A3E ; Zanabazar_Square # Mn [4] ZANABAZAR SQUARE CLUSTER-FINAL LETTER YA..ZANABAZAR SQUARE CLUSTER-FINAL LETTER VA +11A3F..11A46 ; Zanabazar_Square # Po [8] ZANABAZAR SQUARE INITIAL HEAD MARK..ZANABAZAR SQUARE CLOSING DOUBLE-LINED HEAD MARK +11A47 ; Zanabazar_Square # Mn ZANABAZAR SQUARE SUBJOINER + +# Total code points: 72 + # EOF diff --git a/tools-for-build/SpecialCasing.txt b/tools-for-build/SpecialCasing.txt index 8de6462f18..b9ba0d81c1 100644 --- a/tools-for-build/SpecialCasing.txt +++ b/tools-for-build/SpecialCasing.txt @@ -1,10 +1,11 @@ -# SpecialCasing-8.0.0.txt -# Date: 2014-12-16, 23:08:04 GMT [MD] +# SpecialCasing-10.0.0.txt +# Date: 2017-04-14, 05:40:43 GMT +# © 2017 Unicode®, Inc. +# Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries. +# For terms of use, see http://www.unicode.org/terms_of_use.html # # Unicode Character Database -# Copyright (c) 1991-2014 Unicode, Inc. -# For terms of use, see http://www.unicode.org/terms_of_use.html -# For documentation, see http://www.unicode.org/reports/tr44/ +# For documentation, see http://www.unicode.org/reports/tr44/ # # Special Casing # @@ -196,7 +197,7 @@ FB17; FB17; 0544 056D; 0544 053D; # ARMENIAN SMALL LIGATURE MEN XEH # ================================================================================ # Conditional Mappings -# The remainder of this file provides conditional casing data used to produce +# The remainder of this file provides conditional casing data used to produce # full case mappings. # ================================================================================ # Language-Insensitive Mappings diff --git a/tools-for-build/UnicodeData.txt b/tools-for-build/UnicodeData.txt index aa0e914f84..d89c64f526 100644 --- a/tools-for-build/UnicodeData.txt +++ b/tools-for-build/UnicodeData.txt @@ -616,7 +616,7 @@ 0267;LATIN SMALL LETTER HENG WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER HENG HOOK;;;; 0268;LATIN SMALL LETTER I WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER BARRED I;;0197;;0197 0269;LATIN SMALL LETTER IOTA;Ll;0;L;;;;;N;;;0196;;0196 -026A;LATIN LETTER SMALL CAPITAL I;Ll;0;L;;;;;N;;;;; +026A;LATIN LETTER SMALL CAPITAL I;Ll;0;L;;;;;N;;;A7AE;;A7AE 026B;LATIN SMALL LETTER L WITH MIDDLE TILDE;Ll;0;L;;;;;N;;;2C62;;2C62 026C;LATIN SMALL LETTER L WITH BELT;Ll;0;L;;;;;N;LATIN SMALL LETTER L BELT;;A7AD;;A7AD 026D;LATIN SMALL LETTER L WITH RETROFLEX HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER L RETROFLEX HOOK;;;; @@ -2072,6 +2072,17 @@ 085A;MANDAIC VOCALIZATION MARK;Mn;220;NSM;;;;;N;;;;; 085B;MANDAIC GEMINATION MARK;Mn;220;NSM;;;;;N;;;;; 085E;MANDAIC PUNCTUATION;Po;0;R;;;;;N;;;;; +0860;SYRIAC LETTER MALAYALAM NGA;Lo;0;AL;;;;;N;;;;; +0861;SYRIAC LETTER MALAYALAM JA;Lo;0;AL;;;;;N;;;;; +0862;SYRIAC LETTER MALAYALAM NYA;Lo;0;AL;;;;;N;;;;; +0863;SYRIAC LETTER MALAYALAM TTA;Lo;0;AL;;;;;N;;;;; +0864;SYRIAC LETTER MALAYALAM NNA;Lo;0;AL;;;;;N;;;;; +0865;SYRIAC LETTER MALAYALAM NNNA;Lo;0;AL;;;;;N;;;;; +0866;SYRIAC LETTER MALAYALAM BHA;Lo;0;AL;;;;;N;;;;; +0867;SYRIAC LETTER MALAYALAM RA;Lo;0;AL;;;;;N;;;;; +0868;SYRIAC LETTER MALAYALAM LLA;Lo;0;AL;;;;;N;;;;; +0869;SYRIAC LETTER MALAYALAM LLLA;Lo;0;AL;;;;;N;;;;; +086A;SYRIAC LETTER MALAYALAM SSA;Lo;0;AL;;;;;N;;;;; 08A0;ARABIC LETTER BEH WITH SMALL V BELOW;Lo;0;AL;;;;;N;;;;; 08A1;ARABIC LETTER BEH WITH HAMZA ABOVE;Lo;0;AL;;;;;N;;;;; 08A2;ARABIC LETTER JEEM WITH TWO DOTS ABOVE;Lo;0;AL;;;;;N;;;;; @@ -2093,6 +2104,29 @@ 08B2;ARABIC LETTER ZAIN WITH INVERTED V ABOVE;Lo;0;AL;;;;;N;;;;; 08B3;ARABIC LETTER AIN WITH THREE DOTS BELOW;Lo;0;AL;;;;;N;;;;; 08B4;ARABIC LETTER KAF WITH DOT BELOW;Lo;0;AL;;;;;N;;;;; +08B6;ARABIC LETTER BEH WITH SMALL MEEM ABOVE;Lo;0;AL;;;;;N;;;;; +08B7;ARABIC LETTER PEH WITH SMALL MEEM ABOVE;Lo;0;AL;;;;;N;;;;; +08B8;ARABIC LETTER TEH WITH SMALL TEH ABOVE;Lo;0;AL;;;;;N;;;;; +08B9;ARABIC LETTER REH WITH SMALL NOON ABOVE;Lo;0;AL;;;;;N;;;;; +08BA;ARABIC LETTER YEH WITH TWO DOTS BELOW AND SMALL NOON ABOVE;Lo;0;AL;;;;;N;;;;; +08BB;ARABIC LETTER AFRICAN FEH;Lo;0;AL;;;;;N;;;;; +08BC;ARABIC LETTER AFRICAN QAF;Lo;0;AL;;;;;N;;;;; +08BD;ARABIC LETTER AFRICAN NOON;Lo;0;AL;;;;;N;;;;; +08D4;ARABIC SMALL HIGH WORD AR-RUB;Mn;230;NSM;;;;;N;;;;; +08D5;ARABIC SMALL HIGH SAD;Mn;230;NSM;;;;;N;;;;; +08D6;ARABIC SMALL HIGH AIN;Mn;230;NSM;;;;;N;;;;; +08D7;ARABIC SMALL HIGH QAF;Mn;230;NSM;;;;;N;;;;; +08D8;ARABIC SMALL HIGH NOON WITH KASRA;Mn;230;NSM;;;;;N;;;;; +08D9;ARABIC SMALL LOW NOON WITH KASRA;Mn;230;NSM;;;;;N;;;;; +08DA;ARABIC SMALL HIGH WORD ATH-THALATHA;Mn;230;NSM;;;;;N;;;;; +08DB;ARABIC SMALL HIGH WORD AS-SAJDA;Mn;230;NSM;;;;;N;;;;; +08DC;ARABIC SMALL HIGH WORD AN-NISF;Mn;230;NSM;;;;;N;;;;; +08DD;ARABIC SMALL HIGH WORD SAKTA;Mn;230;NSM;;;;;N;;;;; +08DE;ARABIC SMALL HIGH WORD QIF;Mn;230;NSM;;;;;N;;;;; +08DF;ARABIC SMALL HIGH WORD WAQFA;Mn;230;NSM;;;;;N;;;;; +08E0;ARABIC SMALL HIGH FOOTNOTE MARKER;Mn;230;NSM;;;;;N;;;;; +08E1;ARABIC SMALL HIGH SIGN SAFHA;Mn;230;NSM;;;;;N;;;;; +08E2;ARABIC DISPUTED END OF AYAH;Cf;0;AN;;;;;N;;;;; 08E3;ARABIC TURNED DAMMA BELOW;Mn;220;NSM;;;;;N;;;;; 08E4;ARABIC CURLY FATHA;Mn;230;NSM;;;;;N;;;;; 08E5;ARABIC CURLY DAMMA;Mn;230;NSM;;;;;N;;;;; @@ -2343,6 +2377,8 @@ 09F9;BENGALI CURRENCY DENOMINATOR SIXTEEN;No;0;L;;;;16;N;;;;; 09FA;BENGALI ISSHAR;So;0;L;;;;;N;;;;; 09FB;BENGALI GANDA MARK;Sc;0;ET;;;;;N;;;;; +09FC;BENGALI LETTER VEDIC ANUSVARA;Lo;0;L;;;;;N;;;;; +09FD;BENGALI ABBREVIATION SIGN;Po;0;L;;;;;N;;;;; 0A01;GURMUKHI SIGN ADAK BINDI;Mn;0;NSM;;;;;N;;;;; 0A02;GURMUKHI SIGN BINDI;Mn;0;NSM;;;;;N;;;;; 0A03;GURMUKHI SIGN VISARGA;Mc;0;L;;;;;N;;;;; @@ -2507,6 +2543,12 @@ 0AF0;GUJARATI ABBREVIATION SIGN;Po;0;L;;;;;N;;;;; 0AF1;GUJARATI RUPEE SIGN;Sc;0;ET;;;;;N;;;;; 0AF9;GUJARATI LETTER ZHA;Lo;0;L;;;;;N;;;;; +0AFA;GUJARATI SIGN SUKUN;Mn;0;NSM;;;;;N;;;;; +0AFB;GUJARATI SIGN SHADDA;Mn;0;NSM;;;;;N;;;;; +0AFC;GUJARATI SIGN MADDAH;Mn;0;NSM;;;;;N;;;;; +0AFD;GUJARATI SIGN THREE-DOT NUKTA ABOVE;Mn;0;NSM;;;;;N;;;;; +0AFE;GUJARATI SIGN CIRCLE NUKTA ABOVE;Mn;0;NSM;;;;;N;;;;; +0AFF;GUJARATI SIGN TWO-CIRCLE NUKTA ABOVE;Mn;0;NSM;;;;;N;;;;; 0B01;ORIYA SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;; 0B02;ORIYA SIGN ANUSVARA;Mc;0;L;;;;;N;;;;; 0B03;ORIYA SIGN VISARGA;Mc;0;L;;;;;N;;;;; @@ -2765,6 +2807,7 @@ 0C7D;TELUGU FRACTION DIGIT TWO FOR EVEN POWERS OF FOUR;No;0;ON;;;;2;N;;;;; 0C7E;TELUGU FRACTION DIGIT THREE FOR EVEN POWERS OF FOUR;No;0;ON;;;;3;N;;;;; 0C7F;TELUGU SIGN TUUMU;So;0;L;;;;;N;;;;; +0C80;KANNADA SIGN SPACING CANDRABINDU;Lo;0;L;;;;;N;;;;; 0C81;KANNADA SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;; 0C82;KANNADA SIGN ANUSVARA;Mc;0;L;;;;;N;;;;; 0C83;KANNADA SIGN VISARGA;Mc;0;L;;;;;N;;;;; @@ -2852,6 +2895,7 @@ 0CEF;KANNADA DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; 0CF1;KANNADA SIGN JIHVAMULIYA;Lo;0;L;;;;;N;;;;; 0CF2;KANNADA SIGN UPADHMANIYA;Lo;0;L;;;;;N;;;;; +0D00;MALAYALAM SIGN COMBINING ANUSVARA ABOVE;Mn;0;NSM;;;;;N;;;;; 0D01;MALAYALAM SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;; 0D02;MALAYALAM SIGN ANUSVARA;Mc;0;L;;;;;N;;;;; 0D03;MALAYALAM SIGN VISARGA;Mc;0;L;;;;;N;;;;; @@ -2907,6 +2951,8 @@ 0D38;MALAYALAM LETTER SA;Lo;0;L;;;;;N;;;;; 0D39;MALAYALAM LETTER HA;Lo;0;L;;;;;N;;;;; 0D3A;MALAYALAM LETTER TTTA;Lo;0;L;;;;;N;;;;; +0D3B;MALAYALAM SIGN VERTICAL BAR VIRAMA;Mn;9;NSM;;;;;N;;;;; +0D3C;MALAYALAM SIGN CIRCULAR VIRAMA;Mn;9;NSM;;;;;N;;;;; 0D3D;MALAYALAM SIGN AVAGRAHA;Lo;0;L;;;;;N;;;;; 0D3E;MALAYALAM VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; 0D3F;MALAYALAM VOWEL SIGN I;Mc;0;L;;;;;N;;;;; @@ -2923,7 +2969,18 @@ 0D4C;MALAYALAM VOWEL SIGN AU;Mc;0;L;0D46 0D57;;;;N;;;;; 0D4D;MALAYALAM SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; 0D4E;MALAYALAM LETTER DOT REPH;Lo;0;L;;;;;N;;;;; +0D4F;MALAYALAM SIGN PARA;So;0;L;;;;;N;;;;; +0D54;MALAYALAM LETTER CHILLU M;Lo;0;L;;;;;N;;;;; +0D55;MALAYALAM LETTER CHILLU Y;Lo;0;L;;;;;N;;;;; +0D56;MALAYALAM LETTER CHILLU LLL;Lo;0;L;;;;;N;;;;; 0D57;MALAYALAM AU LENGTH MARK;Mc;0;L;;;;;N;;;;; +0D58;MALAYALAM FRACTION ONE ONE-HUNDRED-AND-SIXTIETH;No;0;L;;;;1/160;N;;;;; +0D59;MALAYALAM FRACTION ONE FORTIETH;No;0;L;;;;1/40;N;;;;; +0D5A;MALAYALAM FRACTION THREE EIGHTIETHS;No;0;L;;;;3/80;N;;;;; +0D5B;MALAYALAM FRACTION ONE TWENTIETH;No;0;L;;;;1/20;N;;;;; +0D5C;MALAYALAM FRACTION ONE TENTH;No;0;L;;;;1/10;N;;;;; +0D5D;MALAYALAM FRACTION THREE TWENTIETHS;No;0;L;;;;3/20;N;;;;; +0D5E;MALAYALAM FRACTION ONE FIFTH;No;0;L;;;;1/5;N;;;;; 0D5F;MALAYALAM LETTER ARCHAIC II;Lo;0;L;;;;;N;;;;; 0D60;MALAYALAM LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;; 0D61;MALAYALAM LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;; @@ -2945,6 +3002,9 @@ 0D73;MALAYALAM FRACTION ONE QUARTER;No;0;L;;;;1/4;N;;;;; 0D74;MALAYALAM FRACTION ONE HALF;No;0;L;;;;1/2;N;;;;; 0D75;MALAYALAM FRACTION THREE QUARTERS;No;0;L;;;;3/4;N;;;;; +0D76;MALAYALAM FRACTION ONE SIXTEENTH;No;0;L;;;;1/16;N;;;;; +0D77;MALAYALAM FRACTION ONE EIGHTH;No;0;L;;;;1/8;N;;;;; +0D78;MALAYALAM FRACTION THREE SIXTEENTHS;No;0;L;;;;3/16;N;;;;; 0D79;MALAYALAM DATE MARK;So;0;L;;;;;N;;;;; 0D7A;MALAYALAM LETTER CHILLU NN;Lo;0;L;;;;;N;;;;; 0D7B;MALAYALAM LETTER CHILLU N;Lo;0;L;;;;;N;;;;; @@ -5458,8 +5518,8 @@ 1882;MONGOLIAN LETTER ALI GALI DAMARU;Lo;0;L;;;;;N;;;;; 1883;MONGOLIAN LETTER ALI GALI UBADAMA;Lo;0;L;;;;;N;;;;; 1884;MONGOLIAN LETTER ALI GALI INVERTED UBADAMA;Lo;0;L;;;;;N;;;;; -1885;MONGOLIAN LETTER ALI GALI BALUDA;Lo;0;L;;;;;N;;;;; -1886;MONGOLIAN LETTER ALI GALI THREE BALUDA;Lo;0;L;;;;;N;;;;; +1885;MONGOLIAN LETTER ALI GALI BALUDA;Mn;0;NSM;;;;;N;;;;; +1886;MONGOLIAN LETTER ALI GALI THREE BALUDA;Mn;0;NSM;;;;;N;;;;; 1887;MONGOLIAN LETTER ALI GALI A;Lo;0;L;;;;;N;;;;; 1888;MONGOLIAN LETTER ALI GALI I;Lo;0;L;;;;;N;;;;; 1889;MONGOLIAN LETTER ALI GALI KA;Lo;0;L;;;;;N;;;;; @@ -6319,6 +6379,15 @@ 1C7D;OL CHIKI AHAD;Lm;0;L;;;;;N;;;;; 1C7E;OL CHIKI PUNCTUATION MUCAAD;Po;0;L;;;;;N;;;;; 1C7F;OL CHIKI PUNCTUATION DOUBLE MUCAAD;Po;0;L;;;;;N;;;;; +1C80;CYRILLIC SMALL LETTER ROUNDED VE;Ll;0;L;;;;;N;;;0412;;0412 +1C81;CYRILLIC SMALL LETTER LONG-LEGGED DE;Ll;0;L;;;;;N;;;0414;;0414 +1C82;CYRILLIC SMALL LETTER NARROW O;Ll;0;L;;;;;N;;;041E;;041E +1C83;CYRILLIC SMALL LETTER WIDE ES;Ll;0;L;;;;;N;;;0421;;0421 +1C84;CYRILLIC SMALL LETTER TALL TE;Ll;0;L;;;;;N;;;0422;;0422 +1C85;CYRILLIC SMALL LETTER THREE-LEGGED TE;Ll;0;L;;;;;N;;;0422;;0422 +1C86;CYRILLIC SMALL LETTER TALL HARD SIGN;Ll;0;L;;;;;N;;;042A;;042A +1C87;CYRILLIC SMALL LETTER TALL YAT;Ll;0;L;;;;;N;;;0462;;0462 +1C88;CYRILLIC SMALL LETTER UNBLENDED UK;Ll;0;L;;;;;N;;;A64A;;A64A 1CC0;SUNDANESE PUNCTUATION BINDU SURYA;Po;0;L;;;;;N;;;;; 1CC1;SUNDANESE PUNCTUATION BINDU PANGLONG;Po;0;L;;;;;N;;;;; 1CC2;SUNDANESE PUNCTUATION BINDU PURNAMA;Po;0;L;;;;;N;;;;; @@ -6366,6 +6435,7 @@ 1CF4;VEDIC TONE CANDRA ABOVE;Mn;230;NSM;;;;;N;;;;; 1CF5;VEDIC SIGN JIHVAMULIYA;Lo;0;L;;;;;N;;;;; 1CF6;VEDIC SIGN UPADHMANIYA;Lo;0;L;;;;;N;;;;; +1CF7;VEDIC SIGN ATIKRAMA;Mc;0;L;;;;;N;;;;; 1CF8;VEDIC TONE RING ABOVE;Mn;230;NSM;;;;;N;;;;; 1CF9;VEDIC TONE DOUBLE RING ABOVE;Mn;230;NSM;;;;;N;;;;; 1D00;LATIN LETTER SMALL CAPITAL A;Ll;0;L;;;;;N;;;;; @@ -6614,6 +6684,11 @@ 1DF3;COMBINING LATIN SMALL LETTER O WITH DIAERESIS;Mn;230;NSM;;;;;N;;;;; 1DF4;COMBINING LATIN SMALL LETTER U WITH DIAERESIS;Mn;230;NSM;;;;;N;;;;; 1DF5;COMBINING UP TACK ABOVE;Mn;230;NSM;;;;;N;;;;; +1DF6;COMBINING KAVYKA ABOVE RIGHT;Mn;232;NSM;;;;;N;;;;; +1DF7;COMBINING KAVYKA ABOVE LEFT;Mn;228;NSM;;;;;N;;;;; +1DF8;COMBINING DOT ABOVE LEFT;Mn;228;NSM;;;;;N;;;;; +1DF9;COMBINING WIDE INVERTED BRIDGE BELOW;Mn;220;NSM;;;;;N;;;;; +1DFB;COMBINING DELETION MARK;Mn;230;NSM;;;;;N;;;;; 1DFC;COMBINING DOUBLE INVERTED BREVE BELOW;Mn;233;NSM;;;;;N;;;;; 1DFD;COMBINING ALMOST EQUAL TO BELOW;Mn;220;NSM;;;;;N;;;;; 1DFE;COMBINING LEFT ARROWHEAD ABOVE;Mn;230;NSM;;;;;N;;;;; @@ -7291,6 +7366,7 @@ 20BC;MANAT SIGN;Sc;0;ET;;;;;N;;;;; 20BD;RUBLE SIGN;Sc;0;ET;;;;;N;;;;; 20BE;LARI SIGN;Sc;0;ET;;;;;N;;;;; +20BF;BITCOIN SIGN;Sc;0;ET;;;;;N;;;;; 20D0;COMBINING LEFT HARPOON ABOVE;Mn;230;NSM;;;;;N;NON-SPACING LEFT HARPOON ABOVE;;;; 20D1;COMBINING RIGHT HARPOON ABOVE;Mn;230;NSM;;;;;N;NON-SPACING RIGHT HARPOON ABOVE;;;; 20D2;COMBINING LONG VERTICAL LINE OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING LONG VERTICAL BAR OVERLAY;;;; @@ -8083,6 +8159,11 @@ 23F8;DOUBLE VERTICAL BAR;So;0;ON;;;;;N;;;;; 23F9;BLACK SQUARE FOR STOP;So;0;ON;;;;;N;;;;; 23FA;BLACK CIRCLE FOR RECORD;So;0;ON;;;;;N;;;;; +23FB;POWER SYMBOL;So;0;ON;;;;;N;;;;; +23FC;POWER ON-OFF SYMBOL;So;0;ON;;;;;N;;;;; +23FD;POWER ON SYMBOL;So;0;ON;;;;;N;;;;; +23FE;POWER SLEEP SYMBOL;So;0;ON;;;;;N;;;;; +23FF;OBSERVER EYE SYMBOL;So;0;ON;;;;;N;;;;; 2400;SYMBOL FOR NULL;So;0;ON;;;;;N;GRAPHIC FOR NULL;;;; 2401;SYMBOL FOR START OF HEADING;So;0;ON;;;;;N;GRAPHIC FOR START OF HEADING;;;; 2402;SYMBOL FOR START OF TEXT;So;0;ON;;;;;N;GRAPHIC FOR START OF TEXT;;;; @@ -10031,6 +10112,7 @@ 2BCF;ROTATED WHITE FOUR POINTED CUSP;So;0;ON;;;;;N;;;;; 2BD0;SQUARE POSITION INDICATOR;So;0;ON;;;;;N;;;;; 2BD1;UNCERTAINTY SIGN;So;0;ON;;;;;N;;;;; +2BD2;GROUP MARK;So;0;ON;;;;;N;;;;; 2BEC;LEFTWARDS TWO-HEADED ARROW WITH TRIANGLE ARROWHEADS;So;0;ON;;;;;N;;;;; 2BED;UPWARDS TWO-HEADED ARROW WITH TRIANGLE ARROWHEADS;So;0;ON;;;;;N;;;;; 2BEE;RIGHTWARDS TWO-HEADED ARROW WITH TRIANGLE ARROWHEADS;So;0;ON;;;;;N;;;;; @@ -10561,6 +10643,13 @@ 2E40;DOUBLE HYPHEN;Pd;0;ON;;;;;N;;;;; 2E41;REVERSED COMMA;Po;0;ON;;;;;N;;;;; 2E42;DOUBLE LOW-REVERSED-9 QUOTATION MARK;Ps;0;ON;;;;;N;;;;; +2E43;DASH WITH LEFT UPTURN;Po;0;ON;;;;;N;;;;; +2E44;DOUBLE SUSPENSION MARK;Po;0;ON;;;;;N;;;;; +2E45;INVERTED LOW KAVYKA;Po;0;ON;;;;;N;;;;; +2E46;INVERTED LOW KAVYKA WITH KAVYKA ABOVE;Po;0;ON;;;;;N;;;;; +2E47;LOW KAVYKA;Po;0;ON;;;;;N;;;;; +2E48;LOW KAVYKA WITH DOT;Po;0;ON;;;;;N;;;;; +2E49;DOUBLE STACKED COMMA;Po;0;ON;;;;;N;;;;; 2E80;CJK RADICAL REPEAT;So;0;ON;;;;;N;;;;; 2E81;CJK RADICAL CLIFF;So;0;ON;;;;;N;;;;; 2E82;CJK RADICAL SECOND ONE;So;0;ON;;;;;N;;;;; @@ -11196,6 +11285,7 @@ 312B;BOPOMOFO LETTER NG;Lo;0;L;;;;;N;;;;; 312C;BOPOMOFO LETTER GN;Lo;0;L;;;;;N;;;;; 312D;BOPOMOFO LETTER IH;Lo;0;L;;;;;N;;;;; +312E;BOPOMOFO LETTER O WITH DOT ABOVE;Lo;0;L;;;;;N;;;;; 3131;HANGUL LETTER KIYEOK;Lo;0;L;<compat> 1100;;;;N;HANGUL LETTER GIYEOG;;;; 3132;HANGUL LETTER SSANGKIYEOK;Lo;0;L;<compat> 1101;;;;N;HANGUL LETTER SSANG GIYEOG;;;; 3133;HANGUL LETTER KIYEOK-SIOS;Lo;0;L;<compat> 11AA;;;;N;HANGUL LETTER GIYEOG SIOS;;;; @@ -11962,7 +12052,7 @@ 4DFE;HEXAGRAM FOR AFTER COMPLETION;So;0;ON;;;;;N;;;;; 4DFF;HEXAGRAM FOR BEFORE COMPLETION;So;0;ON;;;;;N;;;;; 4E00;<CJK Ideograph, First>;Lo;0;L;;;;;N;;;;; -9FD5;<CJK Ideograph, Last>;Lo;0;L;;;;;N;;;;; +9FEA;<CJK Ideograph, Last>;Lo;0;L;;;;;N;;;;; A000;YI SYLLABLE IT;Lo;0;L;;;;;N;;;;; A001;YI SYLLABLE IX;Lo;0;L;;;;;N;;;;; A002;YI SYLLABLE I;Lo;0;L;;;;;N;;;;; @@ -13889,6 +13979,7 @@ A7AA;LATIN CAPITAL LETTER H WITH HOOK;Lu;0;L;;;;;N;;;;0266; A7AB;LATIN CAPITAL LETTER REVERSED OPEN E;Lu;0;L;;;;;N;;;;025C; A7AC;LATIN CAPITAL LETTER SCRIPT G;Lu;0;L;;;;;N;;;;0261; A7AD;LATIN CAPITAL LETTER L WITH BELT;Lu;0;L;;;;;N;;;;026C; +A7AE;LATIN CAPITAL LETTER SMALL CAPITAL I;Lu;0;L;;;;;N;;;;026A; A7B0;LATIN CAPITAL LETTER TURNED K;Lu;0;L;;;;;N;;;;029E; A7B1;LATIN CAPITAL LETTER TURNED T;Lu;0;L;;;;;N;;;;0287; A7B2;LATIN CAPITAL LETTER J WITH CROSSED-TAIL;Lu;0;L;;;;;N;;;;029D; @@ -14085,6 +14176,7 @@ A8C1;SAURASHTRA VOWEL SIGN O;Mc;0;L;;;;;N;;;;; A8C2;SAURASHTRA VOWEL SIGN OO;Mc;0;L;;;;;N;;;;; A8C3;SAURASHTRA VOWEL SIGN AU;Mc;0;L;;;;;N;;;;; A8C4;SAURASHTRA SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; +A8C5;SAURASHTRA SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;; A8CE;SAURASHTRA DANDA;Po;0;L;;;;;N;;;;; A8CF;SAURASHTRA DOUBLE DANDA;Po;0;L;;;;;N;;;;; A8D0;SAURASHTRA DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; @@ -16834,6 +16926,8 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1018A;GREEK ZERO SIGN;No;0;ON;;;;0;N;;;;; 1018B;GREEK ONE QUARTER SIGN;No;0;ON;;;;1/4;N;;;;; 1018C;GREEK SINUSOID SIGN;So;0;ON;;;;;N;;;;; +1018D;GREEK INDICTION SIGN;So;0;L;;;;;N;;;;; +1018E;NOMISMA SIGN;So;0;L;;;;;N;;;;; 10190;ROMAN SEXTANS SIGN;So;0;ON;;;;;N;;;;; 10191;ROMAN UNCIA SIGN;So;0;ON;;;;;N;;;;; 10192;ROMAN SEMUNCIA SIGN;So;0;ON;;;;;N;;;;; @@ -17035,6 +17129,9 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 10321;OLD ITALIC NUMERAL FIVE;No;0;L;;;;5;N;;;;; 10322;OLD ITALIC NUMERAL TEN;No;0;L;;;;10;N;;;;; 10323;OLD ITALIC NUMERAL FIFTY;No;0;L;;;;50;N;;;;; +1032D;OLD ITALIC LETTER YE;Lo;0;L;;;;;N;;;;; +1032E;OLD ITALIC LETTER NORTHERN TSE;Lo;0;L;;;;;N;;;;; +1032F;OLD ITALIC LETTER SOUTHERN TSE;Lo;0;L;;;;;N;;;;; 10330;GOTHIC LETTER AHSA;Lo;0;L;;;;;N;;;;; 10331;GOTHIC LETTER BAIRKAN;Lo;0;L;;;;;N;;;;; 10332;GOTHIC LETTER GIBA;Lo;0;L;;;;;N;;;;; @@ -17354,6 +17451,78 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 104A7;OSMANYA DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; 104A8;OSMANYA DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; 104A9;OSMANYA DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +104B0;OSAGE CAPITAL LETTER A;Lu;0;L;;;;;N;;;;104D8; +104B1;OSAGE CAPITAL LETTER AI;Lu;0;L;;;;;N;;;;104D9; +104B2;OSAGE CAPITAL LETTER AIN;Lu;0;L;;;;;N;;;;104DA; +104B3;OSAGE CAPITAL LETTER AH;Lu;0;L;;;;;N;;;;104DB; +104B4;OSAGE CAPITAL LETTER BRA;Lu;0;L;;;;;N;;;;104DC; +104B5;OSAGE CAPITAL LETTER CHA;Lu;0;L;;;;;N;;;;104DD; +104B6;OSAGE CAPITAL LETTER EHCHA;Lu;0;L;;;;;N;;;;104DE; +104B7;OSAGE CAPITAL LETTER E;Lu;0;L;;;;;N;;;;104DF; +104B8;OSAGE CAPITAL LETTER EIN;Lu;0;L;;;;;N;;;;104E0; +104B9;OSAGE CAPITAL LETTER HA;Lu;0;L;;;;;N;;;;104E1; +104BA;OSAGE CAPITAL LETTER HYA;Lu;0;L;;;;;N;;;;104E2; +104BB;OSAGE CAPITAL LETTER I;Lu;0;L;;;;;N;;;;104E3; +104BC;OSAGE CAPITAL LETTER KA;Lu;0;L;;;;;N;;;;104E4; +104BD;OSAGE CAPITAL LETTER EHKA;Lu;0;L;;;;;N;;;;104E5; +104BE;OSAGE CAPITAL LETTER KYA;Lu;0;L;;;;;N;;;;104E6; +104BF;OSAGE CAPITAL LETTER LA;Lu;0;L;;;;;N;;;;104E7; +104C0;OSAGE CAPITAL LETTER MA;Lu;0;L;;;;;N;;;;104E8; +104C1;OSAGE CAPITAL LETTER NA;Lu;0;L;;;;;N;;;;104E9; +104C2;OSAGE CAPITAL LETTER O;Lu;0;L;;;;;N;;;;104EA; +104C3;OSAGE CAPITAL LETTER OIN;Lu;0;L;;;;;N;;;;104EB; +104C4;OSAGE CAPITAL LETTER PA;Lu;0;L;;;;;N;;;;104EC; +104C5;OSAGE CAPITAL LETTER EHPA;Lu;0;L;;;;;N;;;;104ED; +104C6;OSAGE CAPITAL LETTER SA;Lu;0;L;;;;;N;;;;104EE; +104C7;OSAGE CAPITAL LETTER SHA;Lu;0;L;;;;;N;;;;104EF; +104C8;OSAGE CAPITAL LETTER TA;Lu;0;L;;;;;N;;;;104F0; +104C9;OSAGE CAPITAL LETTER EHTA;Lu;0;L;;;;;N;;;;104F1; +104CA;OSAGE CAPITAL LETTER TSA;Lu;0;L;;;;;N;;;;104F2; +104CB;OSAGE CAPITAL LETTER EHTSA;Lu;0;L;;;;;N;;;;104F3; +104CC;OSAGE CAPITAL LETTER TSHA;Lu;0;L;;;;;N;;;;104F4; +104CD;OSAGE CAPITAL LETTER DHA;Lu;0;L;;;;;N;;;;104F5; +104CE;OSAGE CAPITAL LETTER U;Lu;0;L;;;;;N;;;;104F6; +104CF;OSAGE CAPITAL LETTER WA;Lu;0;L;;;;;N;;;;104F7; +104D0;OSAGE CAPITAL LETTER KHA;Lu;0;L;;;;;N;;;;104F8; +104D1;OSAGE CAPITAL LETTER GHA;Lu;0;L;;;;;N;;;;104F9; +104D2;OSAGE CAPITAL LETTER ZA;Lu;0;L;;;;;N;;;;104FA; +104D3;OSAGE CAPITAL LETTER ZHA;Lu;0;L;;;;;N;;;;104FB; +104D8;OSAGE SMALL LETTER A;Ll;0;L;;;;;N;;;104B0;;104B0 +104D9;OSAGE SMALL LETTER AI;Ll;0;L;;;;;N;;;104B1;;104B1 +104DA;OSAGE SMALL LETTER AIN;Ll;0;L;;;;;N;;;104B2;;104B2 +104DB;OSAGE SMALL LETTER AH;Ll;0;L;;;;;N;;;104B3;;104B3 +104DC;OSAGE SMALL LETTER BRA;Ll;0;L;;;;;N;;;104B4;;104B4 +104DD;OSAGE SMALL LETTER CHA;Ll;0;L;;;;;N;;;104B5;;104B5 +104DE;OSAGE SMALL LETTER EHCHA;Ll;0;L;;;;;N;;;104B6;;104B6 +104DF;OSAGE SMALL LETTER E;Ll;0;L;;;;;N;;;104B7;;104B7 +104E0;OSAGE SMALL LETTER EIN;Ll;0;L;;;;;N;;;104B8;;104B8 +104E1;OSAGE SMALL LETTER HA;Ll;0;L;;;;;N;;;104B9;;104B9 +104E2;OSAGE SMALL LETTER HYA;Ll;0;L;;;;;N;;;104BA;;104BA +104E3;OSAGE SMALL LETTER I;Ll;0;L;;;;;N;;;104BB;;104BB +104E4;OSAGE SMALL LETTER KA;Ll;0;L;;;;;N;;;104BC;;104BC +104E5;OSAGE SMALL LETTER EHKA;Ll;0;L;;;;;N;;;104BD;;104BD +104E6;OSAGE SMALL LETTER KYA;Ll;0;L;;;;;N;;;104BE;;104BE +104E7;OSAGE SMALL LETTER LA;Ll;0;L;;;;;N;;;104BF;;104BF +104E8;OSAGE SMALL LETTER MA;Ll;0;L;;;;;N;;;104C0;;104C0 +104E9;OSAGE SMALL LETTER NA;Ll;0;L;;;;;N;;;104C1;;104C1 +104EA;OSAGE SMALL LETTER O;Ll;0;L;;;;;N;;;104C2;;104C2 +104EB;OSAGE SMALL LETTER OIN;Ll;0;L;;;;;N;;;104C3;;104C3 +104EC;OSAGE SMALL LETTER PA;Ll;0;L;;;;;N;;;104C4;;104C4 +104ED;OSAGE SMALL LETTER EHPA;Ll;0;L;;;;;N;;;104C5;;104C5 +104EE;OSAGE SMALL LETTER SA;Ll;0;L;;;;;N;;;104C6;;104C6 +104EF;OSAGE SMALL LETTER SHA;Ll;0;L;;;;;N;;;104C7;;104C7 +104F0;OSAGE SMALL LETTER TA;Ll;0;L;;;;;N;;;104C8;;104C8 +104F1;OSAGE SMALL LETTER EHTA;Ll;0;L;;;;;N;;;104C9;;104C9 +104F2;OSAGE SMALL LETTER TSA;Ll;0;L;;;;;N;;;104CA;;104CA +104F3;OSAGE SMALL LETTER EHTSA;Ll;0;L;;;;;N;;;104CB;;104CB +104F4;OSAGE SMALL LETTER TSHA;Ll;0;L;;;;;N;;;104CC;;104CC +104F5;OSAGE SMALL LETTER DHA;Ll;0;L;;;;;N;;;104CD;;104CD +104F6;OSAGE SMALL LETTER U;Ll;0;L;;;;;N;;;104CE;;104CE +104F7;OSAGE SMALL LETTER WA;Ll;0;L;;;;;N;;;104CF;;104CF +104F8;OSAGE SMALL LETTER KHA;Ll;0;L;;;;;N;;;104D0;;104D0 +104F9;OSAGE SMALL LETTER GHA;Ll;0;L;;;;;N;;;104D1;;104D1 +104FA;OSAGE SMALL LETTER ZA;Ll;0;L;;;;;N;;;104D2;;104D2 +104FB;OSAGE SMALL LETTER ZHA;Ll;0;L;;;;;N;;;104D3;;104D3 10500;ELBASAN LETTER A;Lo;0;L;;;;;N;;;;; 10501;ELBASAN LETTER BE;Lo;0;L;;;;;N;;;;; 10502;ELBASAN LETTER CE;Lo;0;L;;;;;N;;;;; @@ -19180,6 +19349,7 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1123B;KHOJKI SECTION MARK;Po;0;L;;;;;N;;;;; 1123C;KHOJKI DOUBLE SECTION MARK;Po;0;L;;;;;N;;;;; 1123D;KHOJKI ABBREVIATION SIGN;Po;0;L;;;;;N;;;;; +1123E;KHOJKI SIGN SUKUN;Mn;0;NSM;;;;;N;;;;; 11280;MULTANI LETTER A;Lo;0;L;;;;;N;;;;; 11281;MULTANI LETTER I;Lo;0;L;;;;;N;;;;; 11282;MULTANI LETTER U;Lo;0;L;;;;;N;;;;; @@ -19372,6 +19542,98 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 11372;COMBINING GRANTHA LETTER NA;Mn;230;NSM;;;;;N;;;;; 11373;COMBINING GRANTHA LETTER VI;Mn;230;NSM;;;;;N;;;;; 11374;COMBINING GRANTHA LETTER PA;Mn;230;NSM;;;;;N;;;;; +11400;NEWA LETTER A;Lo;0;L;;;;;N;;;;; +11401;NEWA LETTER AA;Lo;0;L;;;;;N;;;;; +11402;NEWA LETTER I;Lo;0;L;;;;;N;;;;; +11403;NEWA LETTER II;Lo;0;L;;;;;N;;;;; +11404;NEWA LETTER U;Lo;0;L;;;;;N;;;;; +11405;NEWA LETTER UU;Lo;0;L;;;;;N;;;;; +11406;NEWA LETTER VOCALIC R;Lo;0;L;;;;;N;;;;; +11407;NEWA LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;; +11408;NEWA LETTER VOCALIC L;Lo;0;L;;;;;N;;;;; +11409;NEWA LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;; +1140A;NEWA LETTER E;Lo;0;L;;;;;N;;;;; +1140B;NEWA LETTER AI;Lo;0;L;;;;;N;;;;; +1140C;NEWA LETTER O;Lo;0;L;;;;;N;;;;; +1140D;NEWA LETTER AU;Lo;0;L;;;;;N;;;;; +1140E;NEWA LETTER KA;Lo;0;L;;;;;N;;;;; +1140F;NEWA LETTER KHA;Lo;0;L;;;;;N;;;;; +11410;NEWA LETTER GA;Lo;0;L;;;;;N;;;;; +11411;NEWA LETTER GHA;Lo;0;L;;;;;N;;;;; +11412;NEWA LETTER NGA;Lo;0;L;;;;;N;;;;; +11413;NEWA LETTER NGHA;Lo;0;L;;;;;N;;;;; +11414;NEWA LETTER CA;Lo;0;L;;;;;N;;;;; +11415;NEWA LETTER CHA;Lo;0;L;;;;;N;;;;; +11416;NEWA LETTER JA;Lo;0;L;;;;;N;;;;; +11417;NEWA LETTER JHA;Lo;0;L;;;;;N;;;;; +11418;NEWA LETTER NYA;Lo;0;L;;;;;N;;;;; +11419;NEWA LETTER NYHA;Lo;0;L;;;;;N;;;;; +1141A;NEWA LETTER TTA;Lo;0;L;;;;;N;;;;; +1141B;NEWA LETTER TTHA;Lo;0;L;;;;;N;;;;; +1141C;NEWA LETTER DDA;Lo;0;L;;;;;N;;;;; +1141D;NEWA LETTER DDHA;Lo;0;L;;;;;N;;;;; +1141E;NEWA LETTER NNA;Lo;0;L;;;;;N;;;;; +1141F;NEWA LETTER TA;Lo;0;L;;;;;N;;;;; +11420;NEWA LETTER THA;Lo;0;L;;;;;N;;;;; +11421;NEWA LETTER DA;Lo;0;L;;;;;N;;;;; +11422;NEWA LETTER DHA;Lo;0;L;;;;;N;;;;; +11423;NEWA LETTER NA;Lo;0;L;;;;;N;;;;; +11424;NEWA LETTER NHA;Lo;0;L;;;;;N;;;;; +11425;NEWA LETTER PA;Lo;0;L;;;;;N;;;;; +11426;NEWA LETTER PHA;Lo;0;L;;;;;N;;;;; +11427;NEWA LETTER BA;Lo;0;L;;;;;N;;;;; +11428;NEWA LETTER BHA;Lo;0;L;;;;;N;;;;; +11429;NEWA LETTER MA;Lo;0;L;;;;;N;;;;; +1142A;NEWA LETTER MHA;Lo;0;L;;;;;N;;;;; +1142B;NEWA LETTER YA;Lo;0;L;;;;;N;;;;; +1142C;NEWA LETTER RA;Lo;0;L;;;;;N;;;;; +1142D;NEWA LETTER RHA;Lo;0;L;;;;;N;;;;; +1142E;NEWA LETTER LA;Lo;0;L;;;;;N;;;;; +1142F;NEWA LETTER LHA;Lo;0;L;;;;;N;;;;; +11430;NEWA LETTER WA;Lo;0;L;;;;;N;;;;; +11431;NEWA LETTER SHA;Lo;0;L;;;;;N;;;;; +11432;NEWA LETTER SSA;Lo;0;L;;;;;N;;;;; +11433;NEWA LETTER SA;Lo;0;L;;;;;N;;;;; +11434;NEWA LETTER HA;Lo;0;L;;;;;N;;;;; +11435;NEWA VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; +11436;NEWA VOWEL SIGN I;Mc;0;L;;;;;N;;;;; +11437;NEWA VOWEL SIGN II;Mc;0;L;;;;;N;;;;; +11438;NEWA VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; +11439;NEWA VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;; +1143A;NEWA VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;; +1143B;NEWA VOWEL SIGN VOCALIC RR;Mn;0;NSM;;;;;N;;;;; +1143C;NEWA VOWEL SIGN VOCALIC L;Mn;0;NSM;;;;;N;;;;; +1143D;NEWA VOWEL SIGN VOCALIC LL;Mn;0;NSM;;;;;N;;;;; +1143E;NEWA VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;; +1143F;NEWA VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;; +11440;NEWA VOWEL SIGN O;Mc;0;L;;;;;N;;;;; +11441;NEWA VOWEL SIGN AU;Mc;0;L;;;;;N;;;;; +11442;NEWA SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; +11443;NEWA SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;; +11444;NEWA SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;; +11445;NEWA SIGN VISARGA;Mc;0;L;;;;;N;;;;; +11446;NEWA SIGN NUKTA;Mn;7;NSM;;;;;N;;;;; +11447;NEWA SIGN AVAGRAHA;Lo;0;L;;;;;N;;;;; +11448;NEWA SIGN FINAL ANUSVARA;Lo;0;L;;;;;N;;;;; +11449;NEWA OM;Lo;0;L;;;;;N;;;;; +1144A;NEWA SIDDHI;Lo;0;L;;;;;N;;;;; +1144B;NEWA DANDA;Po;0;L;;;;;N;;;;; +1144C;NEWA DOUBLE DANDA;Po;0;L;;;;;N;;;;; +1144D;NEWA COMMA;Po;0;L;;;;;N;;;;; +1144E;NEWA GAP FILLER;Po;0;L;;;;;N;;;;; +1144F;NEWA ABBREVIATION SIGN;Po;0;L;;;;;N;;;;; +11450;NEWA DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +11451;NEWA DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +11452;NEWA DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +11453;NEWA DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +11454;NEWA DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +11455;NEWA DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +11456;NEWA DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +11457;NEWA DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +11458;NEWA DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +11459;NEWA DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +1145B;NEWA PLACEHOLDER MARK;Po;0;L;;;;;N;;;;; +1145D;NEWA INSERTION SIGN;Po;0;L;;;;;N;;;;; 11480;TIRHUTA ANJI;Lo;0;L;;;;;N;;;;; 11481;TIRHUTA LETTER A;Lo;0;L;;;;;N;;;;; 11482;TIRHUTA LETTER AA;Lo;0;L;;;;;N;;;;; @@ -19625,6 +19887,19 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 11657;MODI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; 11658;MODI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; 11659;MODI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +11660;MONGOLIAN BIRGA WITH ORNAMENT;Po;0;ON;;;;;N;;;;; +11661;MONGOLIAN ROTATED BIRGA;Po;0;ON;;;;;N;;;;; +11662;MONGOLIAN DOUBLE BIRGA WITH ORNAMENT;Po;0;ON;;;;;N;;;;; +11663;MONGOLIAN TRIPLE BIRGA WITH ORNAMENT;Po;0;ON;;;;;N;;;;; +11664;MONGOLIAN BIRGA WITH DOUBLE ORNAMENT;Po;0;ON;;;;;N;;;;; +11665;MONGOLIAN ROTATED BIRGA WITH ORNAMENT;Po;0;ON;;;;;N;;;;; +11666;MONGOLIAN ROTATED BIRGA WITH DOUBLE ORNAMENT;Po;0;ON;;;;;N;;;;; +11667;MONGOLIAN INVERTED BIRGA;Po;0;ON;;;;;N;;;;; +11668;MONGOLIAN INVERTED BIRGA WITH DOUBLE ORNAMENT;Po;0;ON;;;;;N;;;;; +11669;MONGOLIAN SWIRL BIRGA;Po;0;ON;;;;;N;;;;; +1166A;MONGOLIAN SWIRL BIRGA WITH ORNAMENT;Po;0;ON;;;;;N;;;;; +1166B;MONGOLIAN SWIRL BIRGA WITH DOUBLE ORNAMENT;Po;0;ON;;;;;N;;;;; +1166C;MONGOLIAN TURNED SWIRL BIRGA WITH DOUBLE ORNAMENT;Po;0;ON;;;;;N;;;;; 11680;TAKRI LETTER A;Lo;0;L;;;;;N;;;;; 11681;TAKRI LETTER AA;Lo;0;L;;;;;N;;;;; 11682;TAKRI LETTER I;Lo;0;L;;;;;N;;;;; @@ -19832,6 +20107,158 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 118F1;WARANG CITI NUMBER EIGHTY;No;0;L;;;;80;N;;;;; 118F2;WARANG CITI NUMBER NINETY;No;0;L;;;;90;N;;;;; 118FF;WARANG CITI OM;Lo;0;L;;;;;N;;;;; +11A00;ZANABAZAR SQUARE LETTER A;Lo;0;L;;;;;N;;;;; +11A01;ZANABAZAR SQUARE VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;; +11A02;ZANABAZAR SQUARE VOWEL SIGN UE;Mn;0;NSM;;;;;N;;;;; +11A03;ZANABAZAR SQUARE VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; +11A04;ZANABAZAR SQUARE VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;; +11A05;ZANABAZAR SQUARE VOWEL SIGN OE;Mn;0;NSM;;;;;N;;;;; +11A06;ZANABAZAR SQUARE VOWEL SIGN O;Mn;0;NSM;;;;;N;;;;; +11A07;ZANABAZAR SQUARE VOWEL SIGN AI;Mc;0;L;;;;;N;;;;; +11A08;ZANABAZAR SQUARE VOWEL SIGN AU;Mc;0;L;;;;;N;;;;; +11A09;ZANABAZAR SQUARE VOWEL SIGN REVERSED I;Mn;0;NSM;;;;;N;;;;; +11A0A;ZANABAZAR SQUARE VOWEL LENGTH MARK;Mn;0;NSM;;;;;N;;;;; +11A0B;ZANABAZAR SQUARE LETTER KA;Lo;0;L;;;;;N;;;;; +11A0C;ZANABAZAR SQUARE LETTER KHA;Lo;0;L;;;;;N;;;;; +11A0D;ZANABAZAR SQUARE LETTER GA;Lo;0;L;;;;;N;;;;; +11A0E;ZANABAZAR SQUARE LETTER GHA;Lo;0;L;;;;;N;;;;; +11A0F;ZANABAZAR SQUARE LETTER NGA;Lo;0;L;;;;;N;;;;; +11A10;ZANABAZAR SQUARE LETTER CA;Lo;0;L;;;;;N;;;;; +11A11;ZANABAZAR SQUARE LETTER CHA;Lo;0;L;;;;;N;;;;; +11A12;ZANABAZAR SQUARE LETTER JA;Lo;0;L;;;;;N;;;;; +11A13;ZANABAZAR SQUARE LETTER NYA;Lo;0;L;;;;;N;;;;; +11A14;ZANABAZAR SQUARE LETTER TTA;Lo;0;L;;;;;N;;;;; +11A15;ZANABAZAR SQUARE LETTER TTHA;Lo;0;L;;;;;N;;;;; +11A16;ZANABAZAR SQUARE LETTER DDA;Lo;0;L;;;;;N;;;;; +11A17;ZANABAZAR SQUARE LETTER DDHA;Lo;0;L;;;;;N;;;;; +11A18;ZANABAZAR SQUARE LETTER NNA;Lo;0;L;;;;;N;;;;; +11A19;ZANABAZAR SQUARE LETTER TA;Lo;0;L;;;;;N;;;;; +11A1A;ZANABAZAR SQUARE LETTER THA;Lo;0;L;;;;;N;;;;; +11A1B;ZANABAZAR SQUARE LETTER DA;Lo;0;L;;;;;N;;;;; +11A1C;ZANABAZAR SQUARE LETTER DHA;Lo;0;L;;;;;N;;;;; +11A1D;ZANABAZAR SQUARE LETTER NA;Lo;0;L;;;;;N;;;;; +11A1E;ZANABAZAR SQUARE LETTER PA;Lo;0;L;;;;;N;;;;; +11A1F;ZANABAZAR SQUARE LETTER PHA;Lo;0;L;;;;;N;;;;; +11A20;ZANABAZAR SQUARE LETTER BA;Lo;0;L;;;;;N;;;;; +11A21;ZANABAZAR SQUARE LETTER BHA;Lo;0;L;;;;;N;;;;; +11A22;ZANABAZAR SQUARE LETTER MA;Lo;0;L;;;;;N;;;;; +11A23;ZANABAZAR SQUARE LETTER TSA;Lo;0;L;;;;;N;;;;; +11A24;ZANABAZAR SQUARE LETTER TSHA;Lo;0;L;;;;;N;;;;; +11A25;ZANABAZAR SQUARE LETTER DZA;Lo;0;L;;;;;N;;;;; +11A26;ZANABAZAR SQUARE LETTER DZHA;Lo;0;L;;;;;N;;;;; +11A27;ZANABAZAR SQUARE LETTER ZHA;Lo;0;L;;;;;N;;;;; +11A28;ZANABAZAR SQUARE LETTER ZA;Lo;0;L;;;;;N;;;;; +11A29;ZANABAZAR SQUARE LETTER -A;Lo;0;L;;;;;N;;;;; +11A2A;ZANABAZAR SQUARE LETTER YA;Lo;0;L;;;;;N;;;;; +11A2B;ZANABAZAR SQUARE LETTER RA;Lo;0;L;;;;;N;;;;; +11A2C;ZANABAZAR SQUARE LETTER LA;Lo;0;L;;;;;N;;;;; +11A2D;ZANABAZAR SQUARE LETTER VA;Lo;0;L;;;;;N;;;;; +11A2E;ZANABAZAR SQUARE LETTER SHA;Lo;0;L;;;;;N;;;;; +11A2F;ZANABAZAR SQUARE LETTER SSA;Lo;0;L;;;;;N;;;;; +11A30;ZANABAZAR SQUARE LETTER SA;Lo;0;L;;;;;N;;;;; +11A31;ZANABAZAR SQUARE LETTER HA;Lo;0;L;;;;;N;;;;; +11A32;ZANABAZAR SQUARE LETTER KSSA;Lo;0;L;;;;;N;;;;; +11A33;ZANABAZAR SQUARE FINAL CONSONANT MARK;Mn;0;NSM;;;;;N;;;;; +11A34;ZANABAZAR SQUARE SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;; +11A35;ZANABAZAR SQUARE SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;; +11A36;ZANABAZAR SQUARE SIGN CANDRABINDU WITH ORNAMENT;Mn;0;NSM;;;;;N;;;;; +11A37;ZANABAZAR SQUARE SIGN CANDRA WITH ORNAMENT;Mn;0;NSM;;;;;N;;;;; +11A38;ZANABAZAR SQUARE SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;; +11A39;ZANABAZAR SQUARE SIGN VISARGA;Mc;0;L;;;;;N;;;;; +11A3A;ZANABAZAR SQUARE CLUSTER-INITIAL LETTER RA;Lo;0;L;;;;;N;;;;; +11A3B;ZANABAZAR SQUARE CLUSTER-FINAL LETTER YA;Mn;0;NSM;;;;;N;;;;; +11A3C;ZANABAZAR SQUARE CLUSTER-FINAL LETTER RA;Mn;0;NSM;;;;;N;;;;; +11A3D;ZANABAZAR SQUARE CLUSTER-FINAL LETTER LA;Mn;0;NSM;;;;;N;;;;; +11A3E;ZANABAZAR SQUARE CLUSTER-FINAL LETTER VA;Mn;0;NSM;;;;;N;;;;; +11A3F;ZANABAZAR SQUARE INITIAL HEAD MARK;Po;0;L;;;;;N;;;;; +11A40;ZANABAZAR SQUARE CLOSING HEAD MARK;Po;0;L;;;;;N;;;;; +11A41;ZANABAZAR SQUARE MARK TSHEG;Po;0;L;;;;;N;;;;; +11A42;ZANABAZAR SQUARE MARK SHAD;Po;0;L;;;;;N;;;;; +11A43;ZANABAZAR SQUARE MARK DOUBLE SHAD;Po;0;L;;;;;N;;;;; +11A44;ZANABAZAR SQUARE MARK LONG TSHEG;Po;0;L;;;;;N;;;;; +11A45;ZANABAZAR SQUARE INITIAL DOUBLE-LINED HEAD MARK;Po;0;L;;;;;N;;;;; +11A46;ZANABAZAR SQUARE CLOSING DOUBLE-LINED HEAD MARK;Po;0;L;;;;;N;;;;; +11A47;ZANABAZAR SQUARE SUBJOINER;Mn;9;NSM;;;;;N;;;;; +11A50;SOYOMBO LETTER A;Lo;0;L;;;;;N;;;;; +11A51;SOYOMBO VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;; +11A52;SOYOMBO VOWEL SIGN UE;Mn;0;NSM;;;;;N;;;;; +11A53;SOYOMBO VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; +11A54;SOYOMBO VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;; +11A55;SOYOMBO VOWEL SIGN O;Mn;0;NSM;;;;;N;;;;; +11A56;SOYOMBO VOWEL SIGN OE;Mn;0;NSM;;;;;N;;;;; +11A57;SOYOMBO VOWEL SIGN AI;Mc;0;L;;;;;N;;;;; +11A58;SOYOMBO VOWEL SIGN AU;Mc;0;L;;;;;N;;;;; +11A59;SOYOMBO VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;; +11A5A;SOYOMBO VOWEL SIGN VOCALIC L;Mn;0;NSM;;;;;N;;;;; +11A5B;SOYOMBO VOWEL LENGTH MARK;Mn;0;NSM;;;;;N;;;;; +11A5C;SOYOMBO LETTER KA;Lo;0;L;;;;;N;;;;; +11A5D;SOYOMBO LETTER KHA;Lo;0;L;;;;;N;;;;; +11A5E;SOYOMBO LETTER GA;Lo;0;L;;;;;N;;;;; +11A5F;SOYOMBO LETTER GHA;Lo;0;L;;;;;N;;;;; +11A60;SOYOMBO LETTER NGA;Lo;0;L;;;;;N;;;;; +11A61;SOYOMBO LETTER CA;Lo;0;L;;;;;N;;;;; +11A62;SOYOMBO LETTER CHA;Lo;0;L;;;;;N;;;;; +11A63;SOYOMBO LETTER JA;Lo;0;L;;;;;N;;;;; +11A64;SOYOMBO LETTER JHA;Lo;0;L;;;;;N;;;;; +11A65;SOYOMBO LETTER NYA;Lo;0;L;;;;;N;;;;; +11A66;SOYOMBO LETTER TTA;Lo;0;L;;;;;N;;;;; +11A67;SOYOMBO LETTER TTHA;Lo;0;L;;;;;N;;;;; +11A68;SOYOMBO LETTER DDA;Lo;0;L;;;;;N;;;;; +11A69;SOYOMBO LETTER DDHA;Lo;0;L;;;;;N;;;;; +11A6A;SOYOMBO LETTER NNA;Lo;0;L;;;;;N;;;;; +11A6B;SOYOMBO LETTER TA;Lo;0;L;;;;;N;;;;; +11A6C;SOYOMBO LETTER THA;Lo;0;L;;;;;N;;;;; +11A6D;SOYOMBO LETTER DA;Lo;0;L;;;;;N;;;;; +11A6E;SOYOMBO LETTER DHA;Lo;0;L;;;;;N;;;;; +11A6F;SOYOMBO LETTER NA;Lo;0;L;;;;;N;;;;; +11A70;SOYOMBO LETTER PA;Lo;0;L;;;;;N;;;;; +11A71;SOYOMBO LETTER PHA;Lo;0;L;;;;;N;;;;; +11A72;SOYOMBO LETTER BA;Lo;0;L;;;;;N;;;;; +11A73;SOYOMBO LETTER BHA;Lo;0;L;;;;;N;;;;; +11A74;SOYOMBO LETTER MA;Lo;0;L;;;;;N;;;;; +11A75;SOYOMBO LETTER TSA;Lo;0;L;;;;;N;;;;; +11A76;SOYOMBO LETTER TSHA;Lo;0;L;;;;;N;;;;; +11A77;SOYOMBO LETTER DZA;Lo;0;L;;;;;N;;;;; +11A78;SOYOMBO LETTER ZHA;Lo;0;L;;;;;N;;;;; +11A79;SOYOMBO LETTER ZA;Lo;0;L;;;;;N;;;;; +11A7A;SOYOMBO LETTER -A;Lo;0;L;;;;;N;;;;; +11A7B;SOYOMBO LETTER YA;Lo;0;L;;;;;N;;;;; +11A7C;SOYOMBO LETTER RA;Lo;0;L;;;;;N;;;;; +11A7D;SOYOMBO LETTER LA;Lo;0;L;;;;;N;;;;; +11A7E;SOYOMBO LETTER VA;Lo;0;L;;;;;N;;;;; +11A7F;SOYOMBO LETTER SHA;Lo;0;L;;;;;N;;;;; +11A80;SOYOMBO LETTER SSA;Lo;0;L;;;;;N;;;;; +11A81;SOYOMBO LETTER SA;Lo;0;L;;;;;N;;;;; +11A82;SOYOMBO LETTER HA;Lo;0;L;;;;;N;;;;; +11A83;SOYOMBO LETTER KSSA;Lo;0;L;;;;;N;;;;; +11A86;SOYOMBO CLUSTER-INITIAL LETTER RA;Lo;0;L;;;;;N;;;;; +11A87;SOYOMBO CLUSTER-INITIAL LETTER LA;Lo;0;L;;;;;N;;;;; +11A88;SOYOMBO CLUSTER-INITIAL LETTER SHA;Lo;0;L;;;;;N;;;;; +11A89;SOYOMBO CLUSTER-INITIAL LETTER SA;Lo;0;L;;;;;N;;;;; +11A8A;SOYOMBO FINAL CONSONANT SIGN G;Mn;0;NSM;;;;;N;;;;; +11A8B;SOYOMBO FINAL CONSONANT SIGN K;Mn;0;NSM;;;;;N;;;;; +11A8C;SOYOMBO FINAL CONSONANT SIGN NG;Mn;0;NSM;;;;;N;;;;; +11A8D;SOYOMBO FINAL CONSONANT SIGN D;Mn;0;NSM;;;;;N;;;;; +11A8E;SOYOMBO FINAL CONSONANT SIGN N;Mn;0;NSM;;;;;N;;;;; +11A8F;SOYOMBO FINAL CONSONANT SIGN B;Mn;0;NSM;;;;;N;;;;; +11A90;SOYOMBO FINAL CONSONANT SIGN M;Mn;0;NSM;;;;;N;;;;; +11A91;SOYOMBO FINAL CONSONANT SIGN R;Mn;0;NSM;;;;;N;;;;; +11A92;SOYOMBO FINAL CONSONANT SIGN L;Mn;0;NSM;;;;;N;;;;; +11A93;SOYOMBO FINAL CONSONANT SIGN SH;Mn;0;NSM;;;;;N;;;;; +11A94;SOYOMBO FINAL CONSONANT SIGN S;Mn;0;NSM;;;;;N;;;;; +11A95;SOYOMBO FINAL CONSONANT SIGN -A;Mn;0;NSM;;;;;N;;;;; +11A96;SOYOMBO SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;; +11A97;SOYOMBO SIGN VISARGA;Mc;0;L;;;;;N;;;;; +11A98;SOYOMBO GEMINATION MARK;Mn;0;NSM;;;;;N;;;;; +11A99;SOYOMBO SUBJOINER;Mn;9;NSM;;;;;N;;;;; +11A9A;SOYOMBO MARK TSHEG;Po;0;L;;;;;N;;;;; +11A9B;SOYOMBO MARK SHAD;Po;0;L;;;;;N;;;;; +11A9C;SOYOMBO MARK DOUBLE SHAD;Po;0;L;;;;;N;;;;; +11A9E;SOYOMBO HEAD MARK WITH MOON AND SUN AND TRIPLE FLAME;Po;0;L;;;;;N;;;;; +11A9F;SOYOMBO HEAD MARK WITH MOON AND SUN AND FLAME;Po;0;L;;;;;N;;;;; +11AA0;SOYOMBO HEAD MARK WITH MOON AND SUN;Po;0;L;;;;;N;;;;; +11AA1;SOYOMBO TERMINAL MARK-1;Po;0;L;;;;;N;;;;; +11AA2;SOYOMBO TERMINAL MARK-2;Po;0;L;;;;;N;;;;; 11AC0;PAU CIN HAU LETTER PA;Lo;0;L;;;;;N;;;;; 11AC1;PAU CIN HAU LETTER KA;Lo;0;L;;;;;N;;;;; 11AC2;PAU CIN HAU LETTER LA;Lo;0;L;;;;;N;;;;; @@ -19889,6 +20316,246 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 11AF6;PAU CIN HAU LOW-FALLING TONE LONG FINAL;Lo;0;L;;;;;N;;;;; 11AF7;PAU CIN HAU LOW-FALLING TONE FINAL;Lo;0;L;;;;;N;;;;; 11AF8;PAU CIN HAU GLOTTAL STOP FINAL;Lo;0;L;;;;;N;;;;; +11C00;BHAIKSUKI LETTER A;Lo;0;L;;;;;N;;;;; +11C01;BHAIKSUKI LETTER AA;Lo;0;L;;;;;N;;;;; +11C02;BHAIKSUKI LETTER I;Lo;0;L;;;;;N;;;;; +11C03;BHAIKSUKI LETTER II;Lo;0;L;;;;;N;;;;; +11C04;BHAIKSUKI LETTER U;Lo;0;L;;;;;N;;;;; +11C05;BHAIKSUKI LETTER UU;Lo;0;L;;;;;N;;;;; +11C06;BHAIKSUKI LETTER VOCALIC R;Lo;0;L;;;;;N;;;;; +11C07;BHAIKSUKI LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;; +11C08;BHAIKSUKI LETTER VOCALIC L;Lo;0;L;;;;;N;;;;; +11C0A;BHAIKSUKI LETTER E;Lo;0;L;;;;;N;;;;; +11C0B;BHAIKSUKI LETTER AI;Lo;0;L;;;;;N;;;;; +11C0C;BHAIKSUKI LETTER O;Lo;0;L;;;;;N;;;;; +11C0D;BHAIKSUKI LETTER AU;Lo;0;L;;;;;N;;;;; +11C0E;BHAIKSUKI LETTER KA;Lo;0;L;;;;;N;;;;; +11C0F;BHAIKSUKI LETTER KHA;Lo;0;L;;;;;N;;;;; +11C10;BHAIKSUKI LETTER GA;Lo;0;L;;;;;N;;;;; +11C11;BHAIKSUKI LETTER GHA;Lo;0;L;;;;;N;;;;; +11C12;BHAIKSUKI LETTER NGA;Lo;0;L;;;;;N;;;;; +11C13;BHAIKSUKI LETTER CA;Lo;0;L;;;;;N;;;;; +11C14;BHAIKSUKI LETTER CHA;Lo;0;L;;;;;N;;;;; +11C15;BHAIKSUKI LETTER JA;Lo;0;L;;;;;N;;;;; +11C16;BHAIKSUKI LETTER JHA;Lo;0;L;;;;;N;;;;; +11C17;BHAIKSUKI LETTER NYA;Lo;0;L;;;;;N;;;;; +11C18;BHAIKSUKI LETTER TTA;Lo;0;L;;;;;N;;;;; +11C19;BHAIKSUKI LETTER TTHA;Lo;0;L;;;;;N;;;;; +11C1A;BHAIKSUKI LETTER DDA;Lo;0;L;;;;;N;;;;; +11C1B;BHAIKSUKI LETTER DDHA;Lo;0;L;;;;;N;;;;; +11C1C;BHAIKSUKI LETTER NNA;Lo;0;L;;;;;N;;;;; +11C1D;BHAIKSUKI LETTER TA;Lo;0;L;;;;;N;;;;; +11C1E;BHAIKSUKI LETTER THA;Lo;0;L;;;;;N;;;;; +11C1F;BHAIKSUKI LETTER DA;Lo;0;L;;;;;N;;;;; +11C20;BHAIKSUKI LETTER DHA;Lo;0;L;;;;;N;;;;; +11C21;BHAIKSUKI LETTER NA;Lo;0;L;;;;;N;;;;; +11C22;BHAIKSUKI LETTER PA;Lo;0;L;;;;;N;;;;; +11C23;BHAIKSUKI LETTER PHA;Lo;0;L;;;;;N;;;;; +11C24;BHAIKSUKI LETTER BA;Lo;0;L;;;;;N;;;;; +11C25;BHAIKSUKI LETTER BHA;Lo;0;L;;;;;N;;;;; +11C26;BHAIKSUKI LETTER MA;Lo;0;L;;;;;N;;;;; +11C27;BHAIKSUKI LETTER YA;Lo;0;L;;;;;N;;;;; +11C28;BHAIKSUKI LETTER RA;Lo;0;L;;;;;N;;;;; +11C29;BHAIKSUKI LETTER LA;Lo;0;L;;;;;N;;;;; +11C2A;BHAIKSUKI LETTER VA;Lo;0;L;;;;;N;;;;; +11C2B;BHAIKSUKI LETTER SHA;Lo;0;L;;;;;N;;;;; +11C2C;BHAIKSUKI LETTER SSA;Lo;0;L;;;;;N;;;;; +11C2D;BHAIKSUKI LETTER SA;Lo;0;L;;;;;N;;;;; +11C2E;BHAIKSUKI LETTER HA;Lo;0;L;;;;;N;;;;; +11C2F;BHAIKSUKI VOWEL SIGN AA;Mc;0;L;;;;;N;;;;; +11C30;BHAIKSUKI VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;; +11C31;BHAIKSUKI VOWEL SIGN II;Mn;0;NSM;;;;;N;;;;; +11C32;BHAIKSUKI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; +11C33;BHAIKSUKI VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;; +11C34;BHAIKSUKI VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;; +11C35;BHAIKSUKI VOWEL SIGN VOCALIC RR;Mn;0;NSM;;;;;N;;;;; +11C36;BHAIKSUKI VOWEL SIGN VOCALIC L;Mn;0;NSM;;;;;N;;;;; +11C38;BHAIKSUKI VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;; +11C39;BHAIKSUKI VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;; +11C3A;BHAIKSUKI VOWEL SIGN O;Mn;0;NSM;;;;;N;;;;; +11C3B;BHAIKSUKI VOWEL SIGN AU;Mn;0;NSM;;;;;N;;;;; +11C3C;BHAIKSUKI SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;; +11C3D;BHAIKSUKI SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;; +11C3E;BHAIKSUKI SIGN VISARGA;Mc;0;L;;;;;N;;;;; +11C3F;BHAIKSUKI SIGN VIRAMA;Mn;9;L;;;;;N;;;;; +11C40;BHAIKSUKI SIGN AVAGRAHA;Lo;0;L;;;;;N;;;;; +11C41;BHAIKSUKI DANDA;Po;0;L;;;;;N;;;;; +11C42;BHAIKSUKI DOUBLE DANDA;Po;0;L;;;;;N;;;;; +11C43;BHAIKSUKI WORD SEPARATOR;Po;0;L;;;;;N;;;;; +11C44;BHAIKSUKI GAP FILLER-1;Po;0;L;;;;;N;;;;; +11C45;BHAIKSUKI GAP FILLER-2;Po;0;L;;;;;N;;;;; +11C50;BHAIKSUKI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +11C51;BHAIKSUKI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +11C52;BHAIKSUKI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +11C53;BHAIKSUKI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +11C54;BHAIKSUKI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +11C55;BHAIKSUKI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +11C56;BHAIKSUKI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +11C57;BHAIKSUKI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +11C58;BHAIKSUKI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +11C59;BHAIKSUKI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; +11C5A;BHAIKSUKI NUMBER ONE;No;0;L;;;;1;N;;;;; +11C5B;BHAIKSUKI NUMBER TWO;No;0;L;;;;2;N;;;;; +11C5C;BHAIKSUKI NUMBER THREE;No;0;L;;;;3;N;;;;; +11C5D;BHAIKSUKI NUMBER FOUR;No;0;L;;;;4;N;;;;; +11C5E;BHAIKSUKI NUMBER FIVE;No;0;L;;;;5;N;;;;; +11C5F;BHAIKSUKI NUMBER SIX;No;0;L;;;;6;N;;;;; +11C60;BHAIKSUKI NUMBER SEVEN;No;0;L;;;;7;N;;;;; +11C61;BHAIKSUKI NUMBER EIGHT;No;0;L;;;;8;N;;;;; +11C62;BHAIKSUKI NUMBER NINE;No;0;L;;;;9;N;;;;; +11C63;BHAIKSUKI NUMBER TEN;No;0;L;;;;10;N;;;;; +11C64;BHAIKSUKI NUMBER TWENTY;No;0;L;;;;20;N;;;;; +11C65;BHAIKSUKI NUMBER THIRTY;No;0;L;;;;30;N;;;;; +11C66;BHAIKSUKI NUMBER FORTY;No;0;L;;;;40;N;;;;; +11C67;BHAIKSUKI NUMBER FIFTY;No;0;L;;;;50;N;;;;; +11C68;BHAIKSUKI NUMBER SIXTY;No;0;L;;;;60;N;;;;; +11C69;BHAIKSUKI NUMBER SEVENTY;No;0;L;;;;70;N;;;;; +11C6A;BHAIKSUKI NUMBER EIGHTY;No;0;L;;;;80;N;;;;; +11C6B;BHAIKSUKI NUMBER NINETY;No;0;L;;;;90;N;;;;; +11C6C;BHAIKSUKI HUNDREDS UNIT MARK;No;0;L;;;;100;N;;;;; +11C70;MARCHEN HEAD MARK;Po;0;L;;;;;N;;;;; +11C71;MARCHEN MARK SHAD;Po;0;L;;;;;N;;;;; +11C72;MARCHEN LETTER KA;Lo;0;L;;;;;N;;;;; +11C73;MARCHEN LETTER KHA;Lo;0;L;;;;;N;;;;; +11C74;MARCHEN LETTER GA;Lo;0;L;;;;;N;;;;; +11C75;MARCHEN LETTER NGA;Lo;0;L;;;;;N;;;;; +11C76;MARCHEN LETTER CA;Lo;0;L;;;;;N;;;;; +11C77;MARCHEN LETTER CHA;Lo;0;L;;;;;N;;;;; +11C78;MARCHEN LETTER JA;Lo;0;L;;;;;N;;;;; +11C79;MARCHEN LETTER NYA;Lo;0;L;;;;;N;;;;; +11C7A;MARCHEN LETTER TA;Lo;0;L;;;;;N;;;;; +11C7B;MARCHEN LETTER THA;Lo;0;L;;;;;N;;;;; +11C7C;MARCHEN LETTER DA;Lo;0;L;;;;;N;;;;; +11C7D;MARCHEN LETTER NA;Lo;0;L;;;;;N;;;;; +11C7E;MARCHEN LETTER PA;Lo;0;L;;;;;N;;;;; +11C7F;MARCHEN LETTER PHA;Lo;0;L;;;;;N;;;;; +11C80;MARCHEN LETTER BA;Lo;0;L;;;;;N;;;;; +11C81;MARCHEN LETTER MA;Lo;0;L;;;;;N;;;;; +11C82;MARCHEN LETTER TSA;Lo;0;L;;;;;N;;;;; +11C83;MARCHEN LETTER TSHA;Lo;0;L;;;;;N;;;;; +11C84;MARCHEN LETTER DZA;Lo;0;L;;;;;N;;;;; +11C85;MARCHEN LETTER WA;Lo;0;L;;;;;N;;;;; +11C86;MARCHEN LETTER ZHA;Lo;0;L;;;;;N;;;;; +11C87;MARCHEN LETTER ZA;Lo;0;L;;;;;N;;;;; +11C88;MARCHEN LETTER -A;Lo;0;L;;;;;N;;;;; +11C89;MARCHEN LETTER YA;Lo;0;L;;;;;N;;;;; +11C8A;MARCHEN LETTER RA;Lo;0;L;;;;;N;;;;; +11C8B;MARCHEN LETTER LA;Lo;0;L;;;;;N;;;;; +11C8C;MARCHEN LETTER SHA;Lo;0;L;;;;;N;;;;; +11C8D;MARCHEN LETTER SA;Lo;0;L;;;;;N;;;;; +11C8E;MARCHEN LETTER HA;Lo;0;L;;;;;N;;;;; +11C8F;MARCHEN LETTER A;Lo;0;L;;;;;N;;;;; +11C92;MARCHEN SUBJOINED LETTER KA;Mn;0;NSM;;;;;N;;;;; +11C93;MARCHEN SUBJOINED LETTER KHA;Mn;0;NSM;;;;;N;;;;; +11C94;MARCHEN SUBJOINED LETTER GA;Mn;0;NSM;;;;;N;;;;; +11C95;MARCHEN SUBJOINED LETTER NGA;Mn;0;NSM;;;;;N;;;;; +11C96;MARCHEN SUBJOINED LETTER CA;Mn;0;NSM;;;;;N;;;;; +11C97;MARCHEN SUBJOINED LETTER CHA;Mn;0;NSM;;;;;N;;;;; +11C98;MARCHEN SUBJOINED LETTER JA;Mn;0;NSM;;;;;N;;;;; +11C99;MARCHEN SUBJOINED LETTER NYA;Mn;0;NSM;;;;;N;;;;; +11C9A;MARCHEN SUBJOINED LETTER TA;Mn;0;NSM;;;;;N;;;;; +11C9B;MARCHEN SUBJOINED LETTER THA;Mn;0;NSM;;;;;N;;;;; +11C9C;MARCHEN SUBJOINED LETTER DA;Mn;0;NSM;;;;;N;;;;; +11C9D;MARCHEN SUBJOINED LETTER NA;Mn;0;NSM;;;;;N;;;;; +11C9E;MARCHEN SUBJOINED LETTER PA;Mn;0;NSM;;;;;N;;;;; +11C9F;MARCHEN SUBJOINED LETTER PHA;Mn;0;NSM;;;;;N;;;;; +11CA0;MARCHEN SUBJOINED LETTER BA;Mn;0;NSM;;;;;N;;;;; +11CA1;MARCHEN SUBJOINED LETTER MA;Mn;0;NSM;;;;;N;;;;; +11CA2;MARCHEN SUBJOINED LETTER TSA;Mn;0;NSM;;;;;N;;;;; +11CA3;MARCHEN SUBJOINED LETTER TSHA;Mn;0;NSM;;;;;N;;;;; +11CA4;MARCHEN SUBJOINED LETTER DZA;Mn;0;NSM;;;;;N;;;;; +11CA5;MARCHEN SUBJOINED LETTER WA;Mn;0;NSM;;;;;N;;;;; +11CA6;MARCHEN SUBJOINED LETTER ZHA;Mn;0;NSM;;;;;N;;;;; +11CA7;MARCHEN SUBJOINED LETTER ZA;Mn;0;NSM;;;;;N;;;;; +11CA9;MARCHEN SUBJOINED LETTER YA;Mc;0;L;;;;;N;;;;; +11CAA;MARCHEN SUBJOINED LETTER RA;Mn;0;NSM;;;;;N;;;;; +11CAB;MARCHEN SUBJOINED LETTER LA;Mn;0;NSM;;;;;N;;;;; +11CAC;MARCHEN SUBJOINED LETTER SHA;Mn;0;NSM;;;;;N;;;;; +11CAD;MARCHEN SUBJOINED LETTER SA;Mn;0;NSM;;;;;N;;;;; +11CAE;MARCHEN SUBJOINED LETTER HA;Mn;0;NSM;;;;;N;;;;; +11CAF;MARCHEN SUBJOINED LETTER A;Mn;0;NSM;;;;;N;;;;; +11CB0;MARCHEN VOWEL SIGN AA;Mn;0;NSM;;;;;N;;;;; +11CB1;MARCHEN VOWEL SIGN I;Mc;0;L;;;;;N;;;;; +11CB2;MARCHEN VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; +11CB3;MARCHEN VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;; +11CB4;MARCHEN VOWEL SIGN O;Mc;0;L;;;;;N;;;;; +11CB5;MARCHEN SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;; +11CB6;MARCHEN SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;; +11D00;MASARAM GONDI LETTER A;Lo;0;L;;;;;N;;;;; +11D01;MASARAM GONDI LETTER AA;Lo;0;L;;;;;N;;;;; +11D02;MASARAM GONDI LETTER I;Lo;0;L;;;;;N;;;;; +11D03;MASARAM GONDI LETTER II;Lo;0;L;;;;;N;;;;; +11D04;MASARAM GONDI LETTER U;Lo;0;L;;;;;N;;;;; +11D05;MASARAM GONDI LETTER UU;Lo;0;L;;;;;N;;;;; +11D06;MASARAM GONDI LETTER E;Lo;0;L;;;;;N;;;;; +11D08;MASARAM GONDI LETTER AI;Lo;0;L;;;;;N;;;;; +11D09;MASARAM GONDI LETTER O;Lo;0;L;;;;;N;;;;; +11D0B;MASARAM GONDI LETTER AU;Lo;0;L;;;;;N;;;;; +11D0C;MASARAM GONDI LETTER KA;Lo;0;L;;;;;N;;;;; +11D0D;MASARAM GONDI LETTER KHA;Lo;0;L;;;;;N;;;;; +11D0E;MASARAM GONDI LETTER GA;Lo;0;L;;;;;N;;;;; +11D0F;MASARAM GONDI LETTER GHA;Lo;0;L;;;;;N;;;;; +11D10;MASARAM GONDI LETTER NGA;Lo;0;L;;;;;N;;;;; +11D11;MASARAM GONDI LETTER CA;Lo;0;L;;;;;N;;;;; +11D12;MASARAM GONDI LETTER CHA;Lo;0;L;;;;;N;;;;; +11D13;MASARAM GONDI LETTER JA;Lo;0;L;;;;;N;;;;; +11D14;MASARAM GONDI LETTER JHA;Lo;0;L;;;;;N;;;;; +11D15;MASARAM GONDI LETTER NYA;Lo;0;L;;;;;N;;;;; +11D16;MASARAM GONDI LETTER TTA;Lo;0;L;;;;;N;;;;; +11D17;MASARAM GONDI LETTER TTHA;Lo;0;L;;;;;N;;;;; +11D18;MASARAM GONDI LETTER DDA;Lo;0;L;;;;;N;;;;; +11D19;MASARAM GONDI LETTER DDHA;Lo;0;L;;;;;N;;;;; +11D1A;MASARAM GONDI LETTER NNA;Lo;0;L;;;;;N;;;;; +11D1B;MASARAM GONDI LETTER TA;Lo;0;L;;;;;N;;;;; +11D1C;MASARAM GONDI LETTER THA;Lo;0;L;;;;;N;;;;; +11D1D;MASARAM GONDI LETTER DA;Lo;0;L;;;;;N;;;;; +11D1E;MASARAM GONDI LETTER DHA;Lo;0;L;;;;;N;;;;; +11D1F;MASARAM GONDI LETTER NA;Lo;0;L;;;;;N;;;;; +11D20;MASARAM GONDI LETTER PA;Lo;0;L;;;;;N;;;;; +11D21;MASARAM GONDI LETTER PHA;Lo;0;L;;;;;N;;;;; +11D22;MASARAM GONDI LETTER BA;Lo;0;L;;;;;N;;;;; +11D23;MASARAM GONDI LETTER BHA;Lo;0;L;;;;;N;;;;; +11D24;MASARAM GONDI LETTER MA;Lo;0;L;;;;;N;;;;; +11D25;MASARAM GONDI LETTER YA;Lo;0;L;;;;;N;;;;; +11D26;MASARAM GONDI LETTER RA;Lo;0;L;;;;;N;;;;; +11D27;MASARAM GONDI LETTER LA;Lo;0;L;;;;;N;;;;; +11D28;MASARAM GONDI LETTER VA;Lo;0;L;;;;;N;;;;; +11D29;MASARAM GONDI LETTER SHA;Lo;0;L;;;;;N;;;;; +11D2A;MASARAM GONDI LETTER SSA;Lo;0;L;;;;;N;;;;; +11D2B;MASARAM GONDI LETTER SA;Lo;0;L;;;;;N;;;;; +11D2C;MASARAM GONDI LETTER HA;Lo;0;L;;;;;N;;;;; +11D2D;MASARAM GONDI LETTER LLA;Lo;0;L;;;;;N;;;;; +11D2E;MASARAM GONDI LETTER KSSA;Lo;0;L;;;;;N;;;;; +11D2F;MASARAM GONDI LETTER JNYA;Lo;0;L;;;;;N;;;;; +11D30;MASARAM GONDI LETTER TRA;Lo;0;L;;;;;N;;;;; +11D31;MASARAM GONDI VOWEL SIGN AA;Mn;0;NSM;;;;;N;;;;; +11D32;MASARAM GONDI VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;; +11D33;MASARAM GONDI VOWEL SIGN II;Mn;0;NSM;;;;;N;;;;; +11D34;MASARAM GONDI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;; +11D35;MASARAM GONDI VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;; +11D36;MASARAM GONDI VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;; +11D3A;MASARAM GONDI VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;; +11D3C;MASARAM GONDI VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;; +11D3D;MASARAM GONDI VOWEL SIGN O;Mn;0;NSM;;;;;N;;;;; +11D3F;MASARAM GONDI VOWEL SIGN AU;Mn;0;NSM;;;;;N;;;;; +11D40;MASARAM GONDI SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;; +11D41;MASARAM GONDI SIGN VISARGA;Mn;0;NSM;;;;;N;;;;; +11D42;MASARAM GONDI SIGN NUKTA;Mn;7;NSM;;;;;N;;;;; +11D43;MASARAM GONDI SIGN CANDRA;Mn;0;NSM;;;;;N;;;;; +11D44;MASARAM GONDI SIGN HALANTA;Mn;9;NSM;;;;;N;;;;; +11D45;MASARAM GONDI VIRAMA;Mn;9;NSM;;;;;N;;;;; +11D46;MASARAM GONDI REPHA;Lo;0;L;;;;;N;;;;; +11D47;MASARAM GONDI RA-KARA;Mn;0;NSM;;;;;N;;;;; +11D50;MASARAM GONDI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; +11D51;MASARAM GONDI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; +11D52;MASARAM GONDI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; +11D53;MASARAM GONDI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; +11D54;MASARAM GONDI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; +11D55;MASARAM GONDI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; +11D56;MASARAM GONDI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; +11D57;MASARAM GONDI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; +11D58;MASARAM GONDI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; +11D59;MASARAM GONDI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; 12000;CUNEIFORM SIGN A;Lo;0;L;;;;;N;;;;; 12001;CUNEIFORM SIGN A TIMES A;Lo;0;L;;;;;N;;;;; 12002;CUNEIFORM SIGN A TIMES BAD;Lo;0;L;;;;;N;;;;; @@ -23685,8 +24352,1448 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 16F9D;MIAO LETTER REFORMED TONE-5;Lm;0;L;;;;;N;;;;; 16F9E;MIAO LETTER REFORMED TONE-6;Lm;0;L;;;;;N;;;;; 16F9F;MIAO LETTER REFORMED TONE-8;Lm;0;L;;;;;N;;;;; +16FE0;TANGUT ITERATION MARK;Lm;0;L;;;;;N;;;;; +16FE1;NUSHU ITERATION MARK;Lm;0;L;;;;;N;;;;; +17000;<Tangut Ideograph, First>;Lo;0;L;;;;;N;;;;; +187EC;<Tangut Ideograph, Last>;Lo;0;L;;;;;N;;;;; +18800;TANGUT COMPONENT-001;Lo;0;L;;;;;N;;;;; +18801;TANGUT COMPONENT-002;Lo;0;L;;;;;N;;;;; +18802;TANGUT COMPONENT-003;Lo;0;L;;;;;N;;;;; +18803;TANGUT COMPONENT-004;Lo;0;L;;;;;N;;;;; +18804;TANGUT COMPONENT-005;Lo;0;L;;;;;N;;;;; +18805;TANGUT COMPONENT-006;Lo;0;L;;;;;N;;;;; +18806;TANGUT COMPONENT-007;Lo;0;L;;;;;N;;;;; +18807;TANGUT COMPONENT-008;Lo;0;L;;;;;N;;;;; +18808;TANGUT COMPONENT-009;Lo;0;L;;;;;N;;;;; +18809;TANGUT COMPONENT-010;Lo;0;L;;;;;N;;;;; +1880A;TANGUT COMPONENT-011;Lo;0;L;;;;;N;;;;; +1880B;TANGUT COMPONENT-012;Lo;0;L;;;;;N;;;;; +1880C;TANGUT COMPONENT-013;Lo;0;L;;;;;N;;;;; +1880D;TANGUT COMPONENT-014;Lo;0;L;;;;;N;;;;; +1880E;TANGUT COMPONENT-015;Lo;0;L;;;;;N;;;;; +1880F;TANGUT COMPONENT-016;Lo;0;L;;;;;N;;;;; +18810;TANGUT COMPONENT-017;Lo;0;L;;;;;N;;;;; +18811;TANGUT COMPONENT-018;Lo;0;L;;;;;N;;;;; +18812;TANGUT COMPONENT-019;Lo;0;L;;;;;N;;;;; +18813;TANGUT COMPONENT-020;Lo;0;L;;;;;N;;;;; +18814;TANGUT COMPONENT-021;Lo;0;L;;;;;N;;;;; +18815;TANGUT COMPONENT-022;Lo;0;L;;;;;N;;;;; +18816;TANGUT COMPONENT-023;Lo;0;L;;;;;N;;;;; +18817;TANGUT COMPONENT-024;Lo;0;L;;;;;N;;;;; +18818;TANGUT COMPONENT-025;Lo;0;L;;;;;N;;;;; +18819;TANGUT COMPONENT-026;Lo;0;L;;;;;N;;;;; +1881A;TANGUT COMPONENT-027;Lo;0;L;;;;;N;;;;; +1881B;TANGUT COMPONENT-028;Lo;0;L;;;;;N;;;;; +1881C;TANGUT COMPONENT-029;Lo;0;L;;;;;N;;;;; +1881D;TANGUT COMPONENT-030;Lo;0;L;;;;;N;;;;; +1881E;TANGUT COMPONENT-031;Lo;0;L;;;;;N;;;;; +1881F;TANGUT COMPONENT-032;Lo;0;L;;;;;N;;;;; +18820;TANGUT COMPONENT-033;Lo;0;L;;;;;N;;;;; +18821;TANGUT COMPONENT-034;Lo;0;L;;;;;N;;;;; +18822;TANGUT COMPONENT-035;Lo;0;L;;;;;N;;;;; +18823;TANGUT COMPONENT-036;Lo;0;L;;;;;N;;;;; +18824;TANGUT COMPONENT-037;Lo;0;L;;;;;N;;;;; +18825;TANGUT COMPONENT-038;Lo;0;L;;;;;N;;;;; +18826;TANGUT COMPONENT-039;Lo;0;L;;;;;N;;;;; +18827;TANGUT COMPONENT-040;Lo;0;L;;;;;N;;;;; +18828;TANGUT COMPONENT-041;Lo;0;L;;;;;N;;;;; +18829;TANGUT COMPONENT-042;Lo;0;L;;;;;N;;;;; +1882A;TANGUT COMPONENT-043;Lo;0;L;;;;;N;;;;; +1882B;TANGUT COMPONENT-044;Lo;0;L;;;;;N;;;;; +1882C;TANGUT COMPONENT-045;Lo;0;L;;;;;N;;;;; +1882D;TANGUT COMPONENT-046;Lo;0;L;;;;;N;;;;; +1882E;TANGUT COMPONENT-047;Lo;0;L;;;;;N;;;;; +1882F;TANGUT COMPONENT-048;Lo;0;L;;;;;N;;;;; +18830;TANGUT COMPONENT-049;Lo;0;L;;;;;N;;;;; +18831;TANGUT COMPONENT-050;Lo;0;L;;;;;N;;;;; +18832;TANGUT COMPONENT-051;Lo;0;L;;;;;N;;;;; +18833;TANGUT COMPONENT-052;Lo;0;L;;;;;N;;;;; +18834;TANGUT COMPONENT-053;Lo;0;L;;;;;N;;;;; +18835;TANGUT COMPONENT-054;Lo;0;L;;;;;N;;;;; +18836;TANGUT COMPONENT-055;Lo;0;L;;;;;N;;;;; +18837;TANGUT COMPONENT-056;Lo;0;L;;;;;N;;;;; +18838;TANGUT COMPONENT-057;Lo;0;L;;;;;N;;;;; +18839;TANGUT COMPONENT-058;Lo;0;L;;;;;N;;;;; +1883A;TANGUT COMPONENT-059;Lo;0;L;;;;;N;;;;; +1883B;TANGUT COMPONENT-060;Lo;0;L;;;;;N;;;;; +1883C;TANGUT COMPONENT-061;Lo;0;L;;;;;N;;;;; +1883D;TANGUT COMPONENT-062;Lo;0;L;;;;;N;;;;; +1883E;TANGUT COMPONENT-063;Lo;0;L;;;;;N;;;;; +1883F;TANGUT COMPONENT-064;Lo;0;L;;;;;N;;;;; +18840;TANGUT COMPONENT-065;Lo;0;L;;;;;N;;;;; +18841;TANGUT COMPONENT-066;Lo;0;L;;;;;N;;;;; +18842;TANGUT COMPONENT-067;Lo;0;L;;;;;N;;;;; +18843;TANGUT COMPONENT-068;Lo;0;L;;;;;N;;;;; +18844;TANGUT COMPONENT-069;Lo;0;L;;;;;N;;;;; +18845;TANGUT COMPONENT-070;Lo;0;L;;;;;N;;;;; +18846;TANGUT COMPONENT-071;Lo;0;L;;;;;N;;;;; +18847;TANGUT COMPONENT-072;Lo;0;L;;;;;N;;;;; +18848;TANGUT COMPONENT-073;Lo;0;L;;;;;N;;;;; +18849;TANGUT COMPONENT-074;Lo;0;L;;;;;N;;;;; +1884A;TANGUT COMPONENT-075;Lo;0;L;;;;;N;;;;; +1884B;TANGUT COMPONENT-076;Lo;0;L;;;;;N;;;;; +1884C;TANGUT COMPONENT-077;Lo;0;L;;;;;N;;;;; +1884D;TANGUT COMPONENT-078;Lo;0;L;;;;;N;;;;; +1884E;TANGUT COMPONENT-079;Lo;0;L;;;;;N;;;;; +1884F;TANGUT COMPONENT-080;Lo;0;L;;;;;N;;;;; +18850;TANGUT COMPONENT-081;Lo;0;L;;;;;N;;;;; +18851;TANGUT COMPONENT-082;Lo;0;L;;;;;N;;;;; +18852;TANGUT COMPONENT-083;Lo;0;L;;;;;N;;;;; +18853;TANGUT COMPONENT-084;Lo;0;L;;;;;N;;;;; +18854;TANGUT COMPONENT-085;Lo;0;L;;;;;N;;;;; +18855;TANGUT COMPONENT-086;Lo;0;L;;;;;N;;;;; +18856;TANGUT COMPONENT-087;Lo;0;L;;;;;N;;;;; +18857;TANGUT COMPONENT-088;Lo;0;L;;;;;N;;;;; +18858;TANGUT COMPONENT-089;Lo;0;L;;;;;N;;;;; +18859;TANGUT COMPONENT-090;Lo;0;L;;;;;N;;;;; +1885A;TANGUT COMPONENT-091;Lo;0;L;;;;;N;;;;; +1885B;TANGUT COMPONENT-092;Lo;0;L;;;;;N;;;;; +1885C;TANGUT COMPONENT-093;Lo;0;L;;;;;N;;;;; +1885D;TANGUT COMPONENT-094;Lo;0;L;;;;;N;;;;; +1885E;TANGUT COMPONENT-095;Lo;0;L;;;;;N;;;;; +1885F;TANGUT COMPONENT-096;Lo;0;L;;;;;N;;;;; +18860;TANGUT COMPONENT-097;Lo;0;L;;;;;N;;;;; +18861;TANGUT COMPONENT-098;Lo;0;L;;;;;N;;;;; +18862;TANGUT COMPONENT-099;Lo;0;L;;;;;N;;;;; +18863;TANGUT COMPONENT-100;Lo;0;L;;;;;N;;;;; +18864;TANGUT COMPONENT-101;Lo;0;L;;;;;N;;;;; +18865;TANGUT COMPONENT-102;Lo;0;L;;;;;N;;;;; +18866;TANGUT COMPONENT-103;Lo;0;L;;;;;N;;;;; +18867;TANGUT COMPONENT-104;Lo;0;L;;;;;N;;;;; +18868;TANGUT COMPONENT-105;Lo;0;L;;;;;N;;;;; +18869;TANGUT COMPONENT-106;Lo;0;L;;;;;N;;;;; +1886A;TANGUT COMPONENT-107;Lo;0;L;;;;;N;;;;; +1886B;TANGUT COMPONENT-108;Lo;0;L;;;;;N;;;;; +1886C;TANGUT COMPONENT-109;Lo;0;L;;;;;N;;;;; +1886D;TANGUT COMPONENT-110;Lo;0;L;;;;;N;;;;; +1886E;TANGUT COMPONENT-111;Lo;0;L;;;;;N;;;;; +1886F;TANGUT COMPONENT-112;Lo;0;L;;;;;N;;;;; +18870;TANGUT COMPONENT-113;Lo;0;L;;;;;N;;;;; +18871;TANGUT COMPONENT-114;Lo;0;L;;;;;N;;;;; +18872;TANGUT COMPONENT-115;Lo;0;L;;;;;N;;;;; +18873;TANGUT COMPONENT-116;Lo;0;L;;;;;N;;;;; +18874;TANGUT COMPONENT-117;Lo;0;L;;;;;N;;;;; +18875;TANGUT COMPONENT-118;Lo;0;L;;;;;N;;;;; +18876;TANGUT COMPONENT-119;Lo;0;L;;;;;N;;;;; +18877;TANGUT COMPONENT-120;Lo;0;L;;;;;N;;;;; +18878;TANGUT COMPONENT-121;Lo;0;L;;;;;N;;;;; +18879;TANGUT COMPONENT-122;Lo;0;L;;;;;N;;;;; +1887A;TANGUT COMPONENT-123;Lo;0;L;;;;;N;;;;; +1887B;TANGUT COMPONENT-124;Lo;0;L;;;;;N;;;;; +1887C;TANGUT COMPONENT-125;Lo;0;L;;;;;N;;;;; +1887D;TANGUT COMPONENT-126;Lo;0;L;;;;;N;;;;; +1887E;TANGUT COMPONENT-127;Lo;0;L;;;;;N;;;;; +1887F;TANGUT COMPONENT-128;Lo;0;L;;;;;N;;;;; +18880;TANGUT COMPONENT-129;Lo;0;L;;;;;N;;;;; +18881;TANGUT COMPONENT-130;Lo;0;L;;;;;N;;;;; +18882;TANGUT COMPONENT-131;Lo;0;L;;;;;N;;;;; +18883;TANGUT COMPONENT-132;Lo;0;L;;;;;N;;;;; +18884;TANGUT COMPONENT-133;Lo;0;L;;;;;N;;;;; +18885;TANGUT COMPONENT-134;Lo;0;L;;;;;N;;;;; +18886;TANGUT COMPONENT-135;Lo;0;L;;;;;N;;;;; +18887;TANGUT COMPONENT-136;Lo;0;L;;;;;N;;;;; +18888;TANGUT COMPONENT-137;Lo;0;L;;;;;N;;;;; +18889;TANGUT COMPONENT-138;Lo;0;L;;;;;N;;;;; +1888A;TANGUT COMPONENT-139;Lo;0;L;;;;;N;;;;; +1888B;TANGUT COMPONENT-140;Lo;0;L;;;;;N;;;;; +1888C;TANGUT COMPONENT-141;Lo;0;L;;;;;N;;;;; +1888D;TANGUT COMPONENT-142;Lo;0;L;;;;;N;;;;; +1888E;TANGUT COMPONENT-143;Lo;0;L;;;;;N;;;;; +1888F;TANGUT COMPONENT-144;Lo;0;L;;;;;N;;;;; +18890;TANGUT COMPONENT-145;Lo;0;L;;;;;N;;;;; +18891;TANGUT COMPONENT-146;Lo;0;L;;;;;N;;;;; +18892;TANGUT COMPONENT-147;Lo;0;L;;;;;N;;;;; +18893;TANGUT COMPONENT-148;Lo;0;L;;;;;N;;;;; +18894;TANGUT COMPONENT-149;Lo;0;L;;;;;N;;;;; +18895;TANGUT COMPONENT-150;Lo;0;L;;;;;N;;;;; +18896;TANGUT COMPONENT-151;Lo;0;L;;;;;N;;;;; +18897;TANGUT COMPONENT-152;Lo;0;L;;;;;N;;;;; +18898;TANGUT COMPONENT-153;Lo;0;L;;;;;N;;;;; +18899;TANGUT COMPONENT-154;Lo;0;L;;;;;N;;;;; +1889A;TANGUT COMPONENT-155;Lo;0;L;;;;;N;;;;; +1889B;TANGUT COMPONENT-156;Lo;0;L;;;;;N;;;;; +1889C;TANGUT COMPONENT-157;Lo;0;L;;;;;N;;;;; +1889D;TANGUT COMPONENT-158;Lo;0;L;;;;;N;;;;; +1889E;TANGUT COMPONENT-159;Lo;0;L;;;;;N;;;;; +1889F;TANGUT COMPONENT-160;Lo;0;L;;;;;N;;;;; +188A0;TANGUT COMPONENT-161;Lo;0;L;;;;;N;;;;; +188A1;TANGUT COMPONENT-162;Lo;0;L;;;;;N;;;;; +188A2;TANGUT COMPONENT-163;Lo;0;L;;;;;N;;;;; +188A3;TANGUT COMPONENT-164;Lo;0;L;;;;;N;;;;; +188A4;TANGUT COMPONENT-165;Lo;0;L;;;;;N;;;;; +188A5;TANGUT COMPONENT-166;Lo;0;L;;;;;N;;;;; +188A6;TANGUT COMPONENT-167;Lo;0;L;;;;;N;;;;; +188A7;TANGUT COMPONENT-168;Lo;0;L;;;;;N;;;;; +188A8;TANGUT COMPONENT-169;Lo;0;L;;;;;N;;;;; +188A9;TANGUT COMPONENT-170;Lo;0;L;;;;;N;;;;; +188AA;TANGUT COMPONENT-171;Lo;0;L;;;;;N;;;;; +188AB;TANGUT COMPONENT-172;Lo;0;L;;;;;N;;;;; +188AC;TANGUT COMPONENT-173;Lo;0;L;;;;;N;;;;; +188AD;TANGUT COMPONENT-174;Lo;0;L;;;;;N;;;;; +188AE;TANGUT COMPONENT-175;Lo;0;L;;;;;N;;;;; +188AF;TANGUT COMPONENT-176;Lo;0;L;;;;;N;;;;; +188B0;TANGUT COMPONENT-177;Lo;0;L;;;;;N;;;;; +188B1;TANGUT COMPONENT-178;Lo;0;L;;;;;N;;;;; +188B2;TANGUT COMPONENT-179;Lo;0;L;;;;;N;;;;; +188B3;TANGUT COMPONENT-180;Lo;0;L;;;;;N;;;;; +188B4;TANGUT COMPONENT-181;Lo;0;L;;;;;N;;;;; +188B5;TANGUT COMPONENT-182;Lo;0;L;;;;;N;;;;; +188B6;TANGUT COMPONENT-183;Lo;0;L;;;;;N;;;;; +188B7;TANGUT COMPONENT-184;Lo;0;L;;;;;N;;;;; +188B8;TANGUT COMPONENT-185;Lo;0;L;;;;;N;;;;; +188B9;TANGUT COMPONENT-186;Lo;0;L;;;;;N;;;;; +188BA;TANGUT COMPONENT-187;Lo;0;L;;;;;N;;;;; +188BB;TANGUT COMPONENT-188;Lo;0;L;;;;;N;;;;; +188BC;TANGUT COMPONENT-189;Lo;0;L;;;;;N;;;;; +188BD;TANGUT COMPONENT-190;Lo;0;L;;;;;N;;;;; +188BE;TANGUT COMPONENT-191;Lo;0;L;;;;;N;;;;; +188BF;TANGUT COMPONENT-192;Lo;0;L;;;;;N;;;;; +188C0;TANGUT COMPONENT-193;Lo;0;L;;;;;N;;;;; +188C1;TANGUT COMPONENT-194;Lo;0;L;;;;;N;;;;; +188C2;TANGUT COMPONENT-195;Lo;0;L;;;;;N;;;;; +188C3;TANGUT COMPONENT-196;Lo;0;L;;;;;N;;;;; +188C4;TANGUT COMPONENT-197;Lo;0;L;;;;;N;;;;; +188C5;TANGUT COMPONENT-198;Lo;0;L;;;;;N;;;;; +188C6;TANGUT COMPONENT-199;Lo;0;L;;;;;N;;;;; +188C7;TANGUT COMPONENT-200;Lo;0;L;;;;;N;;;;; +188C8;TANGUT COMPONENT-201;Lo;0;L;;;;;N;;;;; +188C9;TANGUT COMPONENT-202;Lo;0;L;;;;;N;;;;; +188CA;TANGUT COMPONENT-203;Lo;0;L;;;;;N;;;;; +188CB;TANGUT COMPONENT-204;Lo;0;L;;;;;N;;;;; +188CC;TANGUT COMPONENT-205;Lo;0;L;;;;;N;;;;; +188CD;TANGUT COMPONENT-206;Lo;0;L;;;;;N;;;;; +188CE;TANGUT COMPONENT-207;Lo;0;L;;;;;N;;;;; +188CF;TANGUT COMPONENT-208;Lo;0;L;;;;;N;;;;; +188D0;TANGUT COMPONENT-209;Lo;0;L;;;;;N;;;;; +188D1;TANGUT COMPONENT-210;Lo;0;L;;;;;N;;;;; +188D2;TANGUT COMPONENT-211;Lo;0;L;;;;;N;;;;; +188D3;TANGUT COMPONENT-212;Lo;0;L;;;;;N;;;;; +188D4;TANGUT COMPONENT-213;Lo;0;L;;;;;N;;;;; +188D5;TANGUT COMPONENT-214;Lo;0;L;;;;;N;;;;; +188D6;TANGUT COMPONENT-215;Lo;0;L;;;;;N;;;;; +188D7;TANGUT COMPONENT-216;Lo;0;L;;;;;N;;;;; +188D8;TANGUT COMPONENT-217;Lo;0;L;;;;;N;;;;; +188D9;TANGUT COMPONENT-218;Lo;0;L;;;;;N;;;;; +188DA;TANGUT COMPONENT-219;Lo;0;L;;;;;N;;;;; +188DB;TANGUT COMPONENT-220;Lo;0;L;;;;;N;;;;; +188DC;TANGUT COMPONENT-221;Lo;0;L;;;;;N;;;;; +188DD;TANGUT COMPONENT-222;Lo;0;L;;;;;N;;;;; +188DE;TANGUT COMPONENT-223;Lo;0;L;;;;;N;;;;; +188DF;TANGUT COMPONENT-224;Lo;0;L;;;;;N;;;;; +188E0;TANGUT COMPONENT-225;Lo;0;L;;;;;N;;;;; +188E1;TANGUT COMPONENT-226;Lo;0;L;;;;;N;;;;; +188E2;TANGUT COMPONENT-227;Lo;0;L;;;;;N;;;;; +188E3;TANGUT COMPONENT-228;Lo;0;L;;;;;N;;;;; +188E4;TANGUT COMPONENT-229;Lo;0;L;;;;;N;;;;; +188E5;TANGUT COMPONENT-230;Lo;0;L;;;;;N;;;;; +188E6;TANGUT COMPONENT-231;Lo;0;L;;;;;N;;;;; +188E7;TANGUT COMPONENT-232;Lo;0;L;;;;;N;;;;; +188E8;TANGUT COMPONENT-233;Lo;0;L;;;;;N;;;;; +188E9;TANGUT COMPONENT-234;Lo;0;L;;;;;N;;;;; +188EA;TANGUT COMPONENT-235;Lo;0;L;;;;;N;;;;; +188EB;TANGUT COMPONENT-236;Lo;0;L;;;;;N;;;;; +188EC;TANGUT COMPONENT-237;Lo;0;L;;;;;N;;;;; +188ED;TANGUT COMPONENT-238;Lo;0;L;;;;;N;;;;; +188EE;TANGUT COMPONENT-239;Lo;0;L;;;;;N;;;;; +188EF;TANGUT COMPONENT-240;Lo;0;L;;;;;N;;;;; +188F0;TANGUT COMPONENT-241;Lo;0;L;;;;;N;;;;; +188F1;TANGUT COMPONENT-242;Lo;0;L;;;;;N;;;;; +188F2;TANGUT COMPONENT-243;Lo;0;L;;;;;N;;;;; +188F3;TANGUT COMPONENT-244;Lo;0;L;;;;;N;;;;; +188F4;TANGUT COMPONENT-245;Lo;0;L;;;;;N;;;;; +188F5;TANGUT COMPONENT-246;Lo;0;L;;;;;N;;;;; +188F6;TANGUT COMPONENT-247;Lo;0;L;;;;;N;;;;; +188F7;TANGUT COMPONENT-248;Lo;0;L;;;;;N;;;;; +188F8;TANGUT COMPONENT-249;Lo;0;L;;;;;N;;;;; +188F9;TANGUT COMPONENT-250;Lo;0;L;;;;;N;;;;; +188FA;TANGUT COMPONENT-251;Lo;0;L;;;;;N;;;;; +188FB;TANGUT COMPONENT-252;Lo;0;L;;;;;N;;;;; +188FC;TANGUT COMPONENT-253;Lo;0;L;;;;;N;;;;; +188FD;TANGUT COMPONENT-254;Lo;0;L;;;;;N;;;;; +188FE;TANGUT COMPONENT-255;Lo;0;L;;;;;N;;;;; +188FF;TANGUT COMPONENT-256;Lo;0;L;;;;;N;;;;; +18900;TANGUT COMPONENT-257;Lo;0;L;;;;;N;;;;; +18901;TANGUT COMPONENT-258;Lo;0;L;;;;;N;;;;; +18902;TANGUT COMPONENT-259;Lo;0;L;;;;;N;;;;; +18903;TANGUT COMPONENT-260;Lo;0;L;;;;;N;;;;; +18904;TANGUT COMPONENT-261;Lo;0;L;;;;;N;;;;; +18905;TANGUT COMPONENT-262;Lo;0;L;;;;;N;;;;; +18906;TANGUT COMPONENT-263;Lo;0;L;;;;;N;;;;; +18907;TANGUT COMPONENT-264;Lo;0;L;;;;;N;;;;; +18908;TANGUT COMPONENT-265;Lo;0;L;;;;;N;;;;; +18909;TANGUT COMPONENT-266;Lo;0;L;;;;;N;;;;; +1890A;TANGUT COMPONENT-267;Lo;0;L;;;;;N;;;;; +1890B;TANGUT COMPONENT-268;Lo;0;L;;;;;N;;;;; +1890C;TANGUT COMPONENT-269;Lo;0;L;;;;;N;;;;; +1890D;TANGUT COMPONENT-270;Lo;0;L;;;;;N;;;;; +1890E;TANGUT COMPONENT-271;Lo;0;L;;;;;N;;;;; +1890F;TANGUT COMPONENT-272;Lo;0;L;;;;;N;;;;; +18910;TANGUT COMPONENT-273;Lo;0;L;;;;;N;;;;; +18911;TANGUT COMPONENT-274;Lo;0;L;;;;;N;;;;; +18912;TANGUT COMPONENT-275;Lo;0;L;;;;;N;;;;; +18913;TANGUT COMPONENT-276;Lo;0;L;;;;;N;;;;; +18914;TANGUT COMPONENT-277;Lo;0;L;;;;;N;;;;; +18915;TANGUT COMPONENT-278;Lo;0;L;;;;;N;;;;; +18916;TANGUT COMPONENT-279;Lo;0;L;;;;;N;;;;; +18917;TANGUT COMPONENT-280;Lo;0;L;;;;;N;;;;; +18918;TANGUT COMPONENT-281;Lo;0;L;;;;;N;;;;; +18919;TANGUT COMPONENT-282;Lo;0;L;;;;;N;;;;; +1891A;TANGUT COMPONENT-283;Lo;0;L;;;;;N;;;;; +1891B;TANGUT COMPONENT-284;Lo;0;L;;;;;N;;;;; +1891C;TANGUT COMPONENT-285;Lo;0;L;;;;;N;;;;; +1891D;TANGUT COMPONENT-286;Lo;0;L;;;;;N;;;;; +1891E;TANGUT COMPONENT-287;Lo;0;L;;;;;N;;;;; +1891F;TANGUT COMPONENT-288;Lo;0;L;;;;;N;;;;; +18920;TANGUT COMPONENT-289;Lo;0;L;;;;;N;;;;; +18921;TANGUT COMPONENT-290;Lo;0;L;;;;;N;;;;; +18922;TANGUT COMPONENT-291;Lo;0;L;;;;;N;;;;; +18923;TANGUT COMPONENT-292;Lo;0;L;;;;;N;;;;; +18924;TANGUT COMPONENT-293;Lo;0;L;;;;;N;;;;; +18925;TANGUT COMPONENT-294;Lo;0;L;;;;;N;;;;; +18926;TANGUT COMPONENT-295;Lo;0;L;;;;;N;;;;; +18927;TANGUT COMPONENT-296;Lo;0;L;;;;;N;;;;; +18928;TANGUT COMPONENT-297;Lo;0;L;;;;;N;;;;; +18929;TANGUT COMPONENT-298;Lo;0;L;;;;;N;;;;; +1892A;TANGUT COMPONENT-299;Lo;0;L;;;;;N;;;;; +1892B;TANGUT COMPONENT-300;Lo;0;L;;;;;N;;;;; +1892C;TANGUT COMPONENT-301;Lo;0;L;;;;;N;;;;; +1892D;TANGUT COMPONENT-302;Lo;0;L;;;;;N;;;;; +1892E;TANGUT COMPONENT-303;Lo;0;L;;;;;N;;;;; +1892F;TANGUT COMPONENT-304;Lo;0;L;;;;;N;;;;; +18930;TANGUT COMPONENT-305;Lo;0;L;;;;;N;;;;; +18931;TANGUT COMPONENT-306;Lo;0;L;;;;;N;;;;; +18932;TANGUT COMPONENT-307;Lo;0;L;;;;;N;;;;; +18933;TANGUT COMPONENT-308;Lo;0;L;;;;;N;;;;; +18934;TANGUT COMPONENT-309;Lo;0;L;;;;;N;;;;; +18935;TANGUT COMPONENT-310;Lo;0;L;;;;;N;;;;; +18936;TANGUT COMPONENT-311;Lo;0;L;;;;;N;;;;; +18937;TANGUT COMPONENT-312;Lo;0;L;;;;;N;;;;; +18938;TANGUT COMPONENT-313;Lo;0;L;;;;;N;;;;; +18939;TANGUT COMPONENT-314;Lo;0;L;;;;;N;;;;; +1893A;TANGUT COMPONENT-315;Lo;0;L;;;;;N;;;;; +1893B;TANGUT COMPONENT-316;Lo;0;L;;;;;N;;;;; +1893C;TANGUT COMPONENT-317;Lo;0;L;;;;;N;;;;; +1893D;TANGUT COMPONENT-318;Lo;0;L;;;;;N;;;;; +1893E;TANGUT COMPONENT-319;Lo;0;L;;;;;N;;;;; +1893F;TANGUT COMPONENT-320;Lo;0;L;;;;;N;;;;; +18940;TANGUT COMPONENT-321;Lo;0;L;;;;;N;;;;; +18941;TANGUT COMPONENT-322;Lo;0;L;;;;;N;;;;; +18942;TANGUT COMPONENT-323;Lo;0;L;;;;;N;;;;; +18943;TANGUT COMPONENT-324;Lo;0;L;;;;;N;;;;; +18944;TANGUT COMPONENT-325;Lo;0;L;;;;;N;;;;; +18945;TANGUT COMPONENT-326;Lo;0;L;;;;;N;;;;; +18946;TANGUT COMPONENT-327;Lo;0;L;;;;;N;;;;; +18947;TANGUT COMPONENT-328;Lo;0;L;;;;;N;;;;; +18948;TANGUT COMPONENT-329;Lo;0;L;;;;;N;;;;; +18949;TANGUT COMPONENT-330;Lo;0;L;;;;;N;;;;; +1894A;TANGUT COMPONENT-331;Lo;0;L;;;;;N;;;;; +1894B;TANGUT COMPONENT-332;Lo;0;L;;;;;N;;;;; +1894C;TANGUT COMPONENT-333;Lo;0;L;;;;;N;;;;; +1894D;TANGUT COMPONENT-334;Lo;0;L;;;;;N;;;;; +1894E;TANGUT COMPONENT-335;Lo;0;L;;;;;N;;;;; +1894F;TANGUT COMPONENT-336;Lo;0;L;;;;;N;;;;; +18950;TANGUT COMPONENT-337;Lo;0;L;;;;;N;;;;; +18951;TANGUT COMPONENT-338;Lo;0;L;;;;;N;;;;; +18952;TANGUT COMPONENT-339;Lo;0;L;;;;;N;;;;; +18953;TANGUT COMPONENT-340;Lo;0;L;;;;;N;;;;; +18954;TANGUT COMPONENT-341;Lo;0;L;;;;;N;;;;; +18955;TANGUT COMPONENT-342;Lo;0;L;;;;;N;;;;; +18956;TANGUT COMPONENT-343;Lo;0;L;;;;;N;;;;; +18957;TANGUT COMPONENT-344;Lo;0;L;;;;;N;;;;; +18958;TANGUT COMPONENT-345;Lo;0;L;;;;;N;;;;; +18959;TANGUT COMPONENT-346;Lo;0;L;;;;;N;;;;; +1895A;TANGUT COMPONENT-347;Lo;0;L;;;;;N;;;;; +1895B;TANGUT COMPONENT-348;Lo;0;L;;;;;N;;;;; +1895C;TANGUT COMPONENT-349;Lo;0;L;;;;;N;;;;; +1895D;TANGUT COMPONENT-350;Lo;0;L;;;;;N;;;;; +1895E;TANGUT COMPONENT-351;Lo;0;L;;;;;N;;;;; +1895F;TANGUT COMPONENT-352;Lo;0;L;;;;;N;;;;; +18960;TANGUT COMPONENT-353;Lo;0;L;;;;;N;;;;; +18961;TANGUT COMPONENT-354;Lo;0;L;;;;;N;;;;; +18962;TANGUT COMPONENT-355;Lo;0;L;;;;;N;;;;; +18963;TANGUT COMPONENT-356;Lo;0;L;;;;;N;;;;; +18964;TANGUT COMPONENT-357;Lo;0;L;;;;;N;;;;; +18965;TANGUT COMPONENT-358;Lo;0;L;;;;;N;;;;; +18966;TANGUT COMPONENT-359;Lo;0;L;;;;;N;;;;; +18967;TANGUT COMPONENT-360;Lo;0;L;;;;;N;;;;; +18968;TANGUT COMPONENT-361;Lo;0;L;;;;;N;;;;; +18969;TANGUT COMPONENT-362;Lo;0;L;;;;;N;;;;; +1896A;TANGUT COMPONENT-363;Lo;0;L;;;;;N;;;;; +1896B;TANGUT COMPONENT-364;Lo;0;L;;;;;N;;;;; +1896C;TANGUT COMPONENT-365;Lo;0;L;;;;;N;;;;; +1896D;TANGUT COMPONENT-366;Lo;0;L;;;;;N;;;;; +1896E;TANGUT COMPONENT-367;Lo;0;L;;;;;N;;;;; +1896F;TANGUT COMPONENT-368;Lo;0;L;;;;;N;;;;; +18970;TANGUT COMPONENT-369;Lo;0;L;;;;;N;;;;; +18971;TANGUT COMPONENT-370;Lo;0;L;;;;;N;;;;; +18972;TANGUT COMPONENT-371;Lo;0;L;;;;;N;;;;; +18973;TANGUT COMPONENT-372;Lo;0;L;;;;;N;;;;; +18974;TANGUT COMPONENT-373;Lo;0;L;;;;;N;;;;; +18975;TANGUT COMPONENT-374;Lo;0;L;;;;;N;;;;; +18976;TANGUT COMPONENT-375;Lo;0;L;;;;;N;;;;; +18977;TANGUT COMPONENT-376;Lo;0;L;;;;;N;;;;; +18978;TANGUT COMPONENT-377;Lo;0;L;;;;;N;;;;; +18979;TANGUT COMPONENT-378;Lo;0;L;;;;;N;;;;; +1897A;TANGUT COMPONENT-379;Lo;0;L;;;;;N;;;;; +1897B;TANGUT COMPONENT-380;Lo;0;L;;;;;N;;;;; +1897C;TANGUT COMPONENT-381;Lo;0;L;;;;;N;;;;; +1897D;TANGUT COMPONENT-382;Lo;0;L;;;;;N;;;;; +1897E;TANGUT COMPONENT-383;Lo;0;L;;;;;N;;;;; +1897F;TANGUT COMPONENT-384;Lo;0;L;;;;;N;;;;; +18980;TANGUT COMPONENT-385;Lo;0;L;;;;;N;;;;; +18981;TANGUT COMPONENT-386;Lo;0;L;;;;;N;;;;; +18982;TANGUT COMPONENT-387;Lo;0;L;;;;;N;;;;; +18983;TANGUT COMPONENT-388;Lo;0;L;;;;;N;;;;; +18984;TANGUT COMPONENT-389;Lo;0;L;;;;;N;;;;; +18985;TANGUT COMPONENT-390;Lo;0;L;;;;;N;;;;; +18986;TANGUT COMPONENT-391;Lo;0;L;;;;;N;;;;; +18987;TANGUT COMPONENT-392;Lo;0;L;;;;;N;;;;; +18988;TANGUT COMPONENT-393;Lo;0;L;;;;;N;;;;; +18989;TANGUT COMPONENT-394;Lo;0;L;;;;;N;;;;; +1898A;TANGUT COMPONENT-395;Lo;0;L;;;;;N;;;;; +1898B;TANGUT COMPONENT-396;Lo;0;L;;;;;N;;;;; +1898C;TANGUT COMPONENT-397;Lo;0;L;;;;;N;;;;; +1898D;TANGUT COMPONENT-398;Lo;0;L;;;;;N;;;;; +1898E;TANGUT COMPONENT-399;Lo;0;L;;;;;N;;;;; +1898F;TANGUT COMPONENT-400;Lo;0;L;;;;;N;;;;; +18990;TANGUT COMPONENT-401;Lo;0;L;;;;;N;;;;; +18991;TANGUT COMPONENT-402;Lo;0;L;;;;;N;;;;; +18992;TANGUT COMPONENT-403;Lo;0;L;;;;;N;;;;; +18993;TANGUT COMPONENT-404;Lo;0;L;;;;;N;;;;; +18994;TANGUT COMPONENT-405;Lo;0;L;;;;;N;;;;; +18995;TANGUT COMPONENT-406;Lo;0;L;;;;;N;;;;; +18996;TANGUT COMPONENT-407;Lo;0;L;;;;;N;;;;; +18997;TANGUT COMPONENT-408;Lo;0;L;;;;;N;;;;; +18998;TANGUT COMPONENT-409;Lo;0;L;;;;;N;;;;; +18999;TANGUT COMPONENT-410;Lo;0;L;;;;;N;;;;; +1899A;TANGUT COMPONENT-411;Lo;0;L;;;;;N;;;;; +1899B;TANGUT COMPONENT-412;Lo;0;L;;;;;N;;;;; +1899C;TANGUT COMPONENT-413;Lo;0;L;;;;;N;;;;; +1899D;TANGUT COMPONENT-414;Lo;0;L;;;;;N;;;;; +1899E;TANGUT COMPONENT-415;Lo;0;L;;;;;N;;;;; +1899F;TANGUT COMPONENT-416;Lo;0;L;;;;;N;;;;; +189A0;TANGUT COMPONENT-417;Lo;0;L;;;;;N;;;;; +189A1;TANGUT COMPONENT-418;Lo;0;L;;;;;N;;;;; +189A2;TANGUT COMPONENT-419;Lo;0;L;;;;;N;;;;; +189A3;TANGUT COMPONENT-420;Lo;0;L;;;;;N;;;;; +189A4;TANGUT COMPONENT-421;Lo;0;L;;;;;N;;;;; +189A5;TANGUT COMPONENT-422;Lo;0;L;;;;;N;;;;; +189A6;TANGUT COMPONENT-423;Lo;0;L;;;;;N;;;;; +189A7;TANGUT COMPONENT-424;Lo;0;L;;;;;N;;;;; +189A8;TANGUT COMPONENT-425;Lo;0;L;;;;;N;;;;; +189A9;TANGUT COMPONENT-426;Lo;0;L;;;;;N;;;;; +189AA;TANGUT COMPONENT-427;Lo;0;L;;;;;N;;;;; +189AB;TANGUT COMPONENT-428;Lo;0;L;;;;;N;;;;; +189AC;TANGUT COMPONENT-429;Lo;0;L;;;;;N;;;;; +189AD;TANGUT COMPONENT-430;Lo;0;L;;;;;N;;;;; +189AE;TANGUT COMPONENT-431;Lo;0;L;;;;;N;;;;; +189AF;TANGUT COMPONENT-432;Lo;0;L;;;;;N;;;;; +189B0;TANGUT COMPONENT-433;Lo;0;L;;;;;N;;;;; +189B1;TANGUT COMPONENT-434;Lo;0;L;;;;;N;;;;; +189B2;TANGUT COMPONENT-435;Lo;0;L;;;;;N;;;;; +189B3;TANGUT COMPONENT-436;Lo;0;L;;;;;N;;;;; +189B4;TANGUT COMPONENT-437;Lo;0;L;;;;;N;;;;; +189B5;TANGUT COMPONENT-438;Lo;0;L;;;;;N;;;;; +189B6;TANGUT COMPONENT-439;Lo;0;L;;;;;N;;;;; +189B7;TANGUT COMPONENT-440;Lo;0;L;;;;;N;;;;; +189B8;TANGUT COMPONENT-441;Lo;0;L;;;;;N;;;;; +189B9;TANGUT COMPONENT-442;Lo;0;L;;;;;N;;;;; +189BA;TANGUT COMPONENT-443;Lo;0;L;;;;;N;;;;; +189BB;TANGUT COMPONENT-444;Lo;0;L;;;;;N;;;;; +189BC;TANGUT COMPONENT-445;Lo;0;L;;;;;N;;;;; +189BD;TANGUT COMPONENT-446;Lo;0;L;;;;;N;;;;; +189BE;TANGUT COMPONENT-447;Lo;0;L;;;;;N;;;;; +189BF;TANGUT COMPONENT-448;Lo;0;L;;;;;N;;;;; +189C0;TANGUT COMPONENT-449;Lo;0;L;;;;;N;;;;; +189C1;TANGUT COMPONENT-450;Lo;0;L;;;;;N;;;;; +189C2;TANGUT COMPONENT-451;Lo;0;L;;;;;N;;;;; +189C3;TANGUT COMPONENT-452;Lo;0;L;;;;;N;;;;; +189C4;TANGUT COMPONENT-453;Lo;0;L;;;;;N;;;;; +189C5;TANGUT COMPONENT-454;Lo;0;L;;;;;N;;;;; +189C6;TANGUT COMPONENT-455;Lo;0;L;;;;;N;;;;; +189C7;TANGUT COMPONENT-456;Lo;0;L;;;;;N;;;;; +189C8;TANGUT COMPONENT-457;Lo;0;L;;;;;N;;;;; +189C9;TANGUT COMPONENT-458;Lo;0;L;;;;;N;;;;; +189CA;TANGUT COMPONENT-459;Lo;0;L;;;;;N;;;;; +189CB;TANGUT COMPONENT-460;Lo;0;L;;;;;N;;;;; +189CC;TANGUT COMPONENT-461;Lo;0;L;;;;;N;;;;; +189CD;TANGUT COMPONENT-462;Lo;0;L;;;;;N;;;;; +189CE;TANGUT COMPONENT-463;Lo;0;L;;;;;N;;;;; +189CF;TANGUT COMPONENT-464;Lo;0;L;;;;;N;;;;; +189D0;TANGUT COMPONENT-465;Lo;0;L;;;;;N;;;;; +189D1;TANGUT COMPONENT-466;Lo;0;L;;;;;N;;;;; +189D2;TANGUT COMPONENT-467;Lo;0;L;;;;;N;;;;; +189D3;TANGUT COMPONENT-468;Lo;0;L;;;;;N;;;;; +189D4;TANGUT COMPONENT-469;Lo;0;L;;;;;N;;;;; +189D5;TANGUT COMPONENT-470;Lo;0;L;;;;;N;;;;; +189D6;TANGUT COMPONENT-471;Lo;0;L;;;;;N;;;;; +189D7;TANGUT COMPONENT-472;Lo;0;L;;;;;N;;;;; +189D8;TANGUT COMPONENT-473;Lo;0;L;;;;;N;;;;; +189D9;TANGUT COMPONENT-474;Lo;0;L;;;;;N;;;;; +189DA;TANGUT COMPONENT-475;Lo;0;L;;;;;N;;;;; +189DB;TANGUT COMPONENT-476;Lo;0;L;;;;;N;;;;; +189DC;TANGUT COMPONENT-477;Lo;0;L;;;;;N;;;;; +189DD;TANGUT COMPONENT-478;Lo;0;L;;;;;N;;;;; +189DE;TANGUT COMPONENT-479;Lo;0;L;;;;;N;;;;; +189DF;TANGUT COMPONENT-480;Lo;0;L;;;;;N;;;;; +189E0;TANGUT COMPONENT-481;Lo;0;L;;;;;N;;;;; +189E1;TANGUT COMPONENT-482;Lo;0;L;;;;;N;;;;; +189E2;TANGUT COMPONENT-483;Lo;0;L;;;;;N;;;;; +189E3;TANGUT COMPONENT-484;Lo;0;L;;;;;N;;;;; +189E4;TANGUT COMPONENT-485;Lo;0;L;;;;;N;;;;; +189E5;TANGUT COMPONENT-486;Lo;0;L;;;;;N;;;;; +189E6;TANGUT COMPONENT-487;Lo;0;L;;;;;N;;;;; +189E7;TANGUT COMPONENT-488;Lo;0;L;;;;;N;;;;; +189E8;TANGUT COMPONENT-489;Lo;0;L;;;;;N;;;;; +189E9;TANGUT COMPONENT-490;Lo;0;L;;;;;N;;;;; +189EA;TANGUT COMPONENT-491;Lo;0;L;;;;;N;;;;; +189EB;TANGUT COMPONENT-492;Lo;0;L;;;;;N;;;;; +189EC;TANGUT COMPONENT-493;Lo;0;L;;;;;N;;;;; +189ED;TANGUT COMPONENT-494;Lo;0;L;;;;;N;;;;; +189EE;TANGUT COMPONENT-495;Lo;0;L;;;;;N;;;;; +189EF;TANGUT COMPONENT-496;Lo;0;L;;;;;N;;;;; +189F0;TANGUT COMPONENT-497;Lo;0;L;;;;;N;;;;; +189F1;TANGUT COMPONENT-498;Lo;0;L;;;;;N;;;;; +189F2;TANGUT COMPONENT-499;Lo;0;L;;;;;N;;;;; +189F3;TANGUT COMPONENT-500;Lo;0;L;;;;;N;;;;; +189F4;TANGUT COMPONENT-501;Lo;0;L;;;;;N;;;;; +189F5;TANGUT COMPONENT-502;Lo;0;L;;;;;N;;;;; +189F6;TANGUT COMPONENT-503;Lo;0;L;;;;;N;;;;; +189F7;TANGUT COMPONENT-504;Lo;0;L;;;;;N;;;;; +189F8;TANGUT COMPONENT-505;Lo;0;L;;;;;N;;;;; +189F9;TANGUT COMPONENT-506;Lo;0;L;;;;;N;;;;; +189FA;TANGUT COMPONENT-507;Lo;0;L;;;;;N;;;;; +189FB;TANGUT COMPONENT-508;Lo;0;L;;;;;N;;;;; +189FC;TANGUT COMPONENT-509;Lo;0;L;;;;;N;;;;; +189FD;TANGUT COMPONENT-510;Lo;0;L;;;;;N;;;;; +189FE;TANGUT COMPONENT-511;Lo;0;L;;;;;N;;;;; +189FF;TANGUT COMPONENT-512;Lo;0;L;;;;;N;;;;; +18A00;TANGUT COMPONENT-513;Lo;0;L;;;;;N;;;;; +18A01;TANGUT COMPONENT-514;Lo;0;L;;;;;N;;;;; +18A02;TANGUT COMPONENT-515;Lo;0;L;;;;;N;;;;; +18A03;TANGUT COMPONENT-516;Lo;0;L;;;;;N;;;;; +18A04;TANGUT COMPONENT-517;Lo;0;L;;;;;N;;;;; +18A05;TANGUT COMPONENT-518;Lo;0;L;;;;;N;;;;; +18A06;TANGUT COMPONENT-519;Lo;0;L;;;;;N;;;;; +18A07;TANGUT COMPONENT-520;Lo;0;L;;;;;N;;;;; +18A08;TANGUT COMPONENT-521;Lo;0;L;;;;;N;;;;; +18A09;TANGUT COMPONENT-522;Lo;0;L;;;;;N;;;;; +18A0A;TANGUT COMPONENT-523;Lo;0;L;;;;;N;;;;; +18A0B;TANGUT COMPONENT-524;Lo;0;L;;;;;N;;;;; +18A0C;TANGUT COMPONENT-525;Lo;0;L;;;;;N;;;;; +18A0D;TANGUT COMPONENT-526;Lo;0;L;;;;;N;;;;; +18A0E;TANGUT COMPONENT-527;Lo;0;L;;;;;N;;;;; +18A0F;TANGUT COMPONENT-528;Lo;0;L;;;;;N;;;;; +18A10;TANGUT COMPONENT-529;Lo;0;L;;;;;N;;;;; +18A11;TANGUT COMPONENT-530;Lo;0;L;;;;;N;;;;; +18A12;TANGUT COMPONENT-531;Lo;0;L;;;;;N;;;;; +18A13;TANGUT COMPONENT-532;Lo;0;L;;;;;N;;;;; +18A14;TANGUT COMPONENT-533;Lo;0;L;;;;;N;;;;; +18A15;TANGUT COMPONENT-534;Lo;0;L;;;;;N;;;;; +18A16;TANGUT COMPONENT-535;Lo;0;L;;;;;N;;;;; +18A17;TANGUT COMPONENT-536;Lo;0;L;;;;;N;;;;; +18A18;TANGUT COMPONENT-537;Lo;0;L;;;;;N;;;;; +18A19;TANGUT COMPONENT-538;Lo;0;L;;;;;N;;;;; +18A1A;TANGUT COMPONENT-539;Lo;0;L;;;;;N;;;;; +18A1B;TANGUT COMPONENT-540;Lo;0;L;;;;;N;;;;; +18A1C;TANGUT COMPONENT-541;Lo;0;L;;;;;N;;;;; +18A1D;TANGUT COMPONENT-542;Lo;0;L;;;;;N;;;;; +18A1E;TANGUT COMPONENT-543;Lo;0;L;;;;;N;;;;; +18A1F;TANGUT COMPONENT-544;Lo;0;L;;;;;N;;;;; +18A20;TANGUT COMPONENT-545;Lo;0;L;;;;;N;;;;; +18A21;TANGUT COMPONENT-546;Lo;0;L;;;;;N;;;;; +18A22;TANGUT COMPONENT-547;Lo;0;L;;;;;N;;;;; +18A23;TANGUT COMPONENT-548;Lo;0;L;;;;;N;;;;; +18A24;TANGUT COMPONENT-549;Lo;0;L;;;;;N;;;;; +18A25;TANGUT COMPONENT-550;Lo;0;L;;;;;N;;;;; +18A26;TANGUT COMPONENT-551;Lo;0;L;;;;;N;;;;; +18A27;TANGUT COMPONENT-552;Lo;0;L;;;;;N;;;;; +18A28;TANGUT COMPONENT-553;Lo;0;L;;;;;N;;;;; +18A29;TANGUT COMPONENT-554;Lo;0;L;;;;;N;;;;; +18A2A;TANGUT COMPONENT-555;Lo;0;L;;;;;N;;;;; +18A2B;TANGUT COMPONENT-556;Lo;0;L;;;;;N;;;;; +18A2C;TANGUT COMPONENT-557;Lo;0;L;;;;;N;;;;; +18A2D;TANGUT COMPONENT-558;Lo;0;L;;;;;N;;;;; +18A2E;TANGUT COMPONENT-559;Lo;0;L;;;;;N;;;;; +18A2F;TANGUT COMPONENT-560;Lo;0;L;;;;;N;;;;; +18A30;TANGUT COMPONENT-561;Lo;0;L;;;;;N;;;;; +18A31;TANGUT COMPONENT-562;Lo;0;L;;;;;N;;;;; +18A32;TANGUT COMPONENT-563;Lo;0;L;;;;;N;;;;; +18A33;TANGUT COMPONENT-564;Lo;0;L;;;;;N;;;;; +18A34;TANGUT COMPONENT-565;Lo;0;L;;;;;N;;;;; +18A35;TANGUT COMPONENT-566;Lo;0;L;;;;;N;;;;; +18A36;TANGUT COMPONENT-567;Lo;0;L;;;;;N;;;;; +18A37;TANGUT COMPONENT-568;Lo;0;L;;;;;N;;;;; +18A38;TANGUT COMPONENT-569;Lo;0;L;;;;;N;;;;; +18A39;TANGUT COMPONENT-570;Lo;0;L;;;;;N;;;;; +18A3A;TANGUT COMPONENT-571;Lo;0;L;;;;;N;;;;; +18A3B;TANGUT COMPONENT-572;Lo;0;L;;;;;N;;;;; +18A3C;TANGUT COMPONENT-573;Lo;0;L;;;;;N;;;;; +18A3D;TANGUT COMPONENT-574;Lo;0;L;;;;;N;;;;; +18A3E;TANGUT COMPONENT-575;Lo;0;L;;;;;N;;;;; +18A3F;TANGUT COMPONENT-576;Lo;0;L;;;;;N;;;;; +18A40;TANGUT COMPONENT-577;Lo;0;L;;;;;N;;;;; +18A41;TANGUT COMPONENT-578;Lo;0;L;;;;;N;;;;; +18A42;TANGUT COMPONENT-579;Lo;0;L;;;;;N;;;;; +18A43;TANGUT COMPONENT-580;Lo;0;L;;;;;N;;;;; +18A44;TANGUT COMPONENT-581;Lo;0;L;;;;;N;;;;; +18A45;TANGUT COMPONENT-582;Lo;0;L;;;;;N;;;;; +18A46;TANGUT COMPONENT-583;Lo;0;L;;;;;N;;;;; +18A47;TANGUT COMPONENT-584;Lo;0;L;;;;;N;;;;; +18A48;TANGUT COMPONENT-585;Lo;0;L;;;;;N;;;;; +18A49;TANGUT COMPONENT-586;Lo;0;L;;;;;N;;;;; +18A4A;TANGUT COMPONENT-587;Lo;0;L;;;;;N;;;;; +18A4B;TANGUT COMPONENT-588;Lo;0;L;;;;;N;;;;; +18A4C;TANGUT COMPONENT-589;Lo;0;L;;;;;N;;;;; +18A4D;TANGUT COMPONENT-590;Lo;0;L;;;;;N;;;;; +18A4E;TANGUT COMPONENT-591;Lo;0;L;;;;;N;;;;; +18A4F;TANGUT COMPONENT-592;Lo;0;L;;;;;N;;;;; +18A50;TANGUT COMPONENT-593;Lo;0;L;;;;;N;;;;; +18A51;TANGUT COMPONENT-594;Lo;0;L;;;;;N;;;;; +18A52;TANGUT COMPONENT-595;Lo;0;L;;;;;N;;;;; +18A53;TANGUT COMPONENT-596;Lo;0;L;;;;;N;;;;; +18A54;TANGUT COMPONENT-597;Lo;0;L;;;;;N;;;;; +18A55;TANGUT COMPONENT-598;Lo;0;L;;;;;N;;;;; +18A56;TANGUT COMPONENT-599;Lo;0;L;;;;;N;;;;; +18A57;TANGUT COMPONENT-600;Lo;0;L;;;;;N;;;;; +18A58;TANGUT COMPONENT-601;Lo;0;L;;;;;N;;;;; +18A59;TANGUT COMPONENT-602;Lo;0;L;;;;;N;;;;; +18A5A;TANGUT COMPONENT-603;Lo;0;L;;;;;N;;;;; +18A5B;TANGUT COMPONENT-604;Lo;0;L;;;;;N;;;;; +18A5C;TANGUT COMPONENT-605;Lo;0;L;;;;;N;;;;; +18A5D;TANGUT COMPONENT-606;Lo;0;L;;;;;N;;;;; +18A5E;TANGUT COMPONENT-607;Lo;0;L;;;;;N;;;;; +18A5F;TANGUT COMPONENT-608;Lo;0;L;;;;;N;;;;; +18A60;TANGUT COMPONENT-609;Lo;0;L;;;;;N;;;;; +18A61;TANGUT COMPONENT-610;Lo;0;L;;;;;N;;;;; +18A62;TANGUT COMPONENT-611;Lo;0;L;;;;;N;;;;; +18A63;TANGUT COMPONENT-612;Lo;0;L;;;;;N;;;;; +18A64;TANGUT COMPONENT-613;Lo;0;L;;;;;N;;;;; +18A65;TANGUT COMPONENT-614;Lo;0;L;;;;;N;;;;; +18A66;TANGUT COMPONENT-615;Lo;0;L;;;;;N;;;;; +18A67;TANGUT COMPONENT-616;Lo;0;L;;;;;N;;;;; +18A68;TANGUT COMPONENT-617;Lo;0;L;;;;;N;;;;; +18A69;TANGUT COMPONENT-618;Lo;0;L;;;;;N;;;;; +18A6A;TANGUT COMPONENT-619;Lo;0;L;;;;;N;;;;; +18A6B;TANGUT COMPONENT-620;Lo;0;L;;;;;N;;;;; +18A6C;TANGUT COMPONENT-621;Lo;0;L;;;;;N;;;;; +18A6D;TANGUT COMPONENT-622;Lo;0;L;;;;;N;;;;; +18A6E;TANGUT COMPONENT-623;Lo;0;L;;;;;N;;;;; +18A6F;TANGUT COMPONENT-624;Lo;0;L;;;;;N;;;;; +18A70;TANGUT COMPONENT-625;Lo;0;L;;;;;N;;;;; +18A71;TANGUT COMPONENT-626;Lo;0;L;;;;;N;;;;; +18A72;TANGUT COMPONENT-627;Lo;0;L;;;;;N;;;;; +18A73;TANGUT COMPONENT-628;Lo;0;L;;;;;N;;;;; +18A74;TANGUT COMPONENT-629;Lo;0;L;;;;;N;;;;; +18A75;TANGUT COMPONENT-630;Lo;0;L;;;;;N;;;;; +18A76;TANGUT COMPONENT-631;Lo;0;L;;;;;N;;;;; +18A77;TANGUT COMPONENT-632;Lo;0;L;;;;;N;;;;; +18A78;TANGUT COMPONENT-633;Lo;0;L;;;;;N;;;;; +18A79;TANGUT COMPONENT-634;Lo;0;L;;;;;N;;;;; +18A7A;TANGUT COMPONENT-635;Lo;0;L;;;;;N;;;;; +18A7B;TANGUT COMPONENT-636;Lo;0;L;;;;;N;;;;; +18A7C;TANGUT COMPONENT-637;Lo;0;L;;;;;N;;;;; +18A7D;TANGUT COMPONENT-638;Lo;0;L;;;;;N;;;;; +18A7E;TANGUT COMPONENT-639;Lo;0;L;;;;;N;;;;; +18A7F;TANGUT COMPONENT-640;Lo;0;L;;;;;N;;;;; +18A80;TANGUT COMPONENT-641;Lo;0;L;;;;;N;;;;; +18A81;TANGUT COMPONENT-642;Lo;0;L;;;;;N;;;;; +18A82;TANGUT COMPONENT-643;Lo;0;L;;;;;N;;;;; +18A83;TANGUT COMPONENT-644;Lo;0;L;;;;;N;;;;; +18A84;TANGUT COMPONENT-645;Lo;0;L;;;;;N;;;;; +18A85;TANGUT COMPONENT-646;Lo;0;L;;;;;N;;;;; +18A86;TANGUT COMPONENT-647;Lo;0;L;;;;;N;;;;; +18A87;TANGUT COMPONENT-648;Lo;0;L;;;;;N;;;;; +18A88;TANGUT COMPONENT-649;Lo;0;L;;;;;N;;;;; +18A89;TANGUT COMPONENT-650;Lo;0;L;;;;;N;;;;; +18A8A;TANGUT COMPONENT-651;Lo;0;L;;;;;N;;;;; +18A8B;TANGUT COMPONENT-652;Lo;0;L;;;;;N;;;;; +18A8C;TANGUT COMPONENT-653;Lo;0;L;;;;;N;;;;; +18A8D;TANGUT COMPONENT-654;Lo;0;L;;;;;N;;;;; +18A8E;TANGUT COMPONENT-655;Lo;0;L;;;;;N;;;;; +18A8F;TANGUT COMPONENT-656;Lo;0;L;;;;;N;;;;; +18A90;TANGUT COMPONENT-657;Lo;0;L;;;;;N;;;;; +18A91;TANGUT COMPONENT-658;Lo;0;L;;;;;N;;;;; +18A92;TANGUT COMPONENT-659;Lo;0;L;;;;;N;;;;; +18A93;TANGUT COMPONENT-660;Lo;0;L;;;;;N;;;;; +18A94;TANGUT COMPONENT-661;Lo;0;L;;;;;N;;;;; +18A95;TANGUT COMPONENT-662;Lo;0;L;;;;;N;;;;; +18A96;TANGUT COMPONENT-663;Lo;0;L;;;;;N;;;;; +18A97;TANGUT COMPONENT-664;Lo;0;L;;;;;N;;;;; +18A98;TANGUT COMPONENT-665;Lo;0;L;;;;;N;;;;; +18A99;TANGUT COMPONENT-666;Lo;0;L;;;;;N;;;;; +18A9A;TANGUT COMPONENT-667;Lo;0;L;;;;;N;;;;; +18A9B;TANGUT COMPONENT-668;Lo;0;L;;;;;N;;;;; +18A9C;TANGUT COMPONENT-669;Lo;0;L;;;;;N;;;;; +18A9D;TANGUT COMPONENT-670;Lo;0;L;;;;;N;;;;; +18A9E;TANGUT COMPONENT-671;Lo;0;L;;;;;N;;;;; +18A9F;TANGUT COMPONENT-672;Lo;0;L;;;;;N;;;;; +18AA0;TANGUT COMPONENT-673;Lo;0;L;;;;;N;;;;; +18AA1;TANGUT COMPONENT-674;Lo;0;L;;;;;N;;;;; +18AA2;TANGUT COMPONENT-675;Lo;0;L;;;;;N;;;;; +18AA3;TANGUT COMPONENT-676;Lo;0;L;;;;;N;;;;; +18AA4;TANGUT COMPONENT-677;Lo;0;L;;;;;N;;;;; +18AA5;TANGUT COMPONENT-678;Lo;0;L;;;;;N;;;;; +18AA6;TANGUT COMPONENT-679;Lo;0;L;;;;;N;;;;; +18AA7;TANGUT COMPONENT-680;Lo;0;L;;;;;N;;;;; +18AA8;TANGUT COMPONENT-681;Lo;0;L;;;;;N;;;;; +18AA9;TANGUT COMPONENT-682;Lo;0;L;;;;;N;;;;; +18AAA;TANGUT COMPONENT-683;Lo;0;L;;;;;N;;;;; +18AAB;TANGUT COMPONENT-684;Lo;0;L;;;;;N;;;;; +18AAC;TANGUT COMPONENT-685;Lo;0;L;;;;;N;;;;; +18AAD;TANGUT COMPONENT-686;Lo;0;L;;;;;N;;;;; +18AAE;TANGUT COMPONENT-687;Lo;0;L;;;;;N;;;;; +18AAF;TANGUT COMPONENT-688;Lo;0;L;;;;;N;;;;; +18AB0;TANGUT COMPONENT-689;Lo;0;L;;;;;N;;;;; +18AB1;TANGUT COMPONENT-690;Lo;0;L;;;;;N;;;;; +18AB2;TANGUT COMPONENT-691;Lo;0;L;;;;;N;;;;; +18AB3;TANGUT COMPONENT-692;Lo;0;L;;;;;N;;;;; +18AB4;TANGUT COMPONENT-693;Lo;0;L;;;;;N;;;;; +18AB5;TANGUT COMPONENT-694;Lo;0;L;;;;;N;;;;; +18AB6;TANGUT COMPONENT-695;Lo;0;L;;;;;N;;;;; +18AB7;TANGUT COMPONENT-696;Lo;0;L;;;;;N;;;;; +18AB8;TANGUT COMPONENT-697;Lo;0;L;;;;;N;;;;; +18AB9;TANGUT COMPONENT-698;Lo;0;L;;;;;N;;;;; +18ABA;TANGUT COMPONENT-699;Lo;0;L;;;;;N;;;;; +18ABB;TANGUT COMPONENT-700;Lo;0;L;;;;;N;;;;; +18ABC;TANGUT COMPONENT-701;Lo;0;L;;;;;N;;;;; +18ABD;TANGUT COMPONENT-702;Lo;0;L;;;;;N;;;;; +18ABE;TANGUT COMPONENT-703;Lo;0;L;;;;;N;;;;; +18ABF;TANGUT COMPONENT-704;Lo;0;L;;;;;N;;;;; +18AC0;TANGUT COMPONENT-705;Lo;0;L;;;;;N;;;;; +18AC1;TANGUT COMPONENT-706;Lo;0;L;;;;;N;;;;; +18AC2;TANGUT COMPONENT-707;Lo;0;L;;;;;N;;;;; +18AC3;TANGUT COMPONENT-708;Lo;0;L;;;;;N;;;;; +18AC4;TANGUT COMPONENT-709;Lo;0;L;;;;;N;;;;; +18AC5;TANGUT COMPONENT-710;Lo;0;L;;;;;N;;;;; +18AC6;TANGUT COMPONENT-711;Lo;0;L;;;;;N;;;;; +18AC7;TANGUT COMPONENT-712;Lo;0;L;;;;;N;;;;; +18AC8;TANGUT COMPONENT-713;Lo;0;L;;;;;N;;;;; +18AC9;TANGUT COMPONENT-714;Lo;0;L;;;;;N;;;;; +18ACA;TANGUT COMPONENT-715;Lo;0;L;;;;;N;;;;; +18ACB;TANGUT COMPONENT-716;Lo;0;L;;;;;N;;;;; +18ACC;TANGUT COMPONENT-717;Lo;0;L;;;;;N;;;;; +18ACD;TANGUT COMPONENT-718;Lo;0;L;;;;;N;;;;; +18ACE;TANGUT COMPONENT-719;Lo;0;L;;;;;N;;;;; +18ACF;TANGUT COMPONENT-720;Lo;0;L;;;;;N;;;;; +18AD0;TANGUT COMPONENT-721;Lo;0;L;;;;;N;;;;; +18AD1;TANGUT COMPONENT-722;Lo;0;L;;;;;N;;;;; +18AD2;TANGUT COMPONENT-723;Lo;0;L;;;;;N;;;;; +18AD3;TANGUT COMPONENT-724;Lo;0;L;;;;;N;;;;; +18AD4;TANGUT COMPONENT-725;Lo;0;L;;;;;N;;;;; +18AD5;TANGUT COMPONENT-726;Lo;0;L;;;;;N;;;;; +18AD6;TANGUT COMPONENT-727;Lo;0;L;;;;;N;;;;; +18AD7;TANGUT COMPONENT-728;Lo;0;L;;;;;N;;;;; +18AD8;TANGUT COMPONENT-729;Lo;0;L;;;;;N;;;;; +18AD9;TANGUT COMPONENT-730;Lo;0;L;;;;;N;;;;; +18ADA;TANGUT COMPONENT-731;Lo;0;L;;;;;N;;;;; +18ADB;TANGUT COMPONENT-732;Lo;0;L;;;;;N;;;;; +18ADC;TANGUT COMPONENT-733;Lo;0;L;;;;;N;;;;; +18ADD;TANGUT COMPONENT-734;Lo;0;L;;;;;N;;;;; +18ADE;TANGUT COMPONENT-735;Lo;0;L;;;;;N;;;;; +18ADF;TANGUT COMPONENT-736;Lo;0;L;;;;;N;;;;; +18AE0;TANGUT COMPONENT-737;Lo;0;L;;;;;N;;;;; +18AE1;TANGUT COMPONENT-738;Lo;0;L;;;;;N;;;;; +18AE2;TANGUT COMPONENT-739;Lo;0;L;;;;;N;;;;; +18AE3;TANGUT COMPONENT-740;Lo;0;L;;;;;N;;;;; +18AE4;TANGUT COMPONENT-741;Lo;0;L;;;;;N;;;;; +18AE5;TANGUT COMPONENT-742;Lo;0;L;;;;;N;;;;; +18AE6;TANGUT COMPONENT-743;Lo;0;L;;;;;N;;;;; +18AE7;TANGUT COMPONENT-744;Lo;0;L;;;;;N;;;;; +18AE8;TANGUT COMPONENT-745;Lo;0;L;;;;;N;;;;; +18AE9;TANGUT COMPONENT-746;Lo;0;L;;;;;N;;;;; +18AEA;TANGUT COMPONENT-747;Lo;0;L;;;;;N;;;;; +18AEB;TANGUT COMPONENT-748;Lo;0;L;;;;;N;;;;; +18AEC;TANGUT COMPONENT-749;Lo;0;L;;;;;N;;;;; +18AED;TANGUT COMPONENT-750;Lo;0;L;;;;;N;;;;; +18AEE;TANGUT COMPONENT-751;Lo;0;L;;;;;N;;;;; +18AEF;TANGUT COMPONENT-752;Lo;0;L;;;;;N;;;;; +18AF0;TANGUT COMPONENT-753;Lo;0;L;;;;;N;;;;; +18AF1;TANGUT COMPONENT-754;Lo;0;L;;;;;N;;;;; +18AF2;TANGUT COMPONENT-755;Lo;0;L;;;;;N;;;;; 1B000;KATAKANA LETTER ARCHAIC E;Lo;0;L;;;;;N;;;;; 1B001;HIRAGANA LETTER ARCHAIC YE;Lo;0;L;;;;;N;;;;; +1B002;HENTAIGANA LETTER A-1;Lo;0;L;;;;;N;;;;; +1B003;HENTAIGANA LETTER A-2;Lo;0;L;;;;;N;;;;; +1B004;HENTAIGANA LETTER A-3;Lo;0;L;;;;;N;;;;; +1B005;HENTAIGANA LETTER A-WO;Lo;0;L;;;;;N;;;;; +1B006;HENTAIGANA LETTER I-1;Lo;0;L;;;;;N;;;;; +1B007;HENTAIGANA LETTER I-2;Lo;0;L;;;;;N;;;;; +1B008;HENTAIGANA LETTER I-3;Lo;0;L;;;;;N;;;;; +1B009;HENTAIGANA LETTER I-4;Lo;0;L;;;;;N;;;;; +1B00A;HENTAIGANA LETTER U-1;Lo;0;L;;;;;N;;;;; +1B00B;HENTAIGANA LETTER U-2;Lo;0;L;;;;;N;;;;; +1B00C;HENTAIGANA LETTER U-3;Lo;0;L;;;;;N;;;;; +1B00D;HENTAIGANA LETTER U-4;Lo;0;L;;;;;N;;;;; +1B00E;HENTAIGANA LETTER U-5;Lo;0;L;;;;;N;;;;; +1B00F;HENTAIGANA LETTER E-2;Lo;0;L;;;;;N;;;;; +1B010;HENTAIGANA LETTER E-3;Lo;0;L;;;;;N;;;;; +1B011;HENTAIGANA LETTER E-4;Lo;0;L;;;;;N;;;;; +1B012;HENTAIGANA LETTER E-5;Lo;0;L;;;;;N;;;;; +1B013;HENTAIGANA LETTER E-6;Lo;0;L;;;;;N;;;;; +1B014;HENTAIGANA LETTER O-1;Lo;0;L;;;;;N;;;;; +1B015;HENTAIGANA LETTER O-2;Lo;0;L;;;;;N;;;;; +1B016;HENTAIGANA LETTER O-3;Lo;0;L;;;;;N;;;;; +1B017;HENTAIGANA LETTER KA-1;Lo;0;L;;;;;N;;;;; +1B018;HENTAIGANA LETTER KA-2;Lo;0;L;;;;;N;;;;; +1B019;HENTAIGANA LETTER KA-3;Lo;0;L;;;;;N;;;;; +1B01A;HENTAIGANA LETTER KA-4;Lo;0;L;;;;;N;;;;; +1B01B;HENTAIGANA LETTER KA-5;Lo;0;L;;;;;N;;;;; +1B01C;HENTAIGANA LETTER KA-6;Lo;0;L;;;;;N;;;;; +1B01D;HENTAIGANA LETTER KA-7;Lo;0;L;;;;;N;;;;; +1B01E;HENTAIGANA LETTER KA-8;Lo;0;L;;;;;N;;;;; +1B01F;HENTAIGANA LETTER KA-9;Lo;0;L;;;;;N;;;;; +1B020;HENTAIGANA LETTER KA-10;Lo;0;L;;;;;N;;;;; +1B021;HENTAIGANA LETTER KA-11;Lo;0;L;;;;;N;;;;; +1B022;HENTAIGANA LETTER KA-KE;Lo;0;L;;;;;N;;;;; +1B023;HENTAIGANA LETTER KI-1;Lo;0;L;;;;;N;;;;; +1B024;HENTAIGANA LETTER KI-2;Lo;0;L;;;;;N;;;;; +1B025;HENTAIGANA LETTER KI-3;Lo;0;L;;;;;N;;;;; +1B026;HENTAIGANA LETTER KI-4;Lo;0;L;;;;;N;;;;; +1B027;HENTAIGANA LETTER KI-5;Lo;0;L;;;;;N;;;;; +1B028;HENTAIGANA LETTER KI-6;Lo;0;L;;;;;N;;;;; +1B029;HENTAIGANA LETTER KI-7;Lo;0;L;;;;;N;;;;; +1B02A;HENTAIGANA LETTER KI-8;Lo;0;L;;;;;N;;;;; +1B02B;HENTAIGANA LETTER KU-1;Lo;0;L;;;;;N;;;;; +1B02C;HENTAIGANA LETTER KU-2;Lo;0;L;;;;;N;;;;; +1B02D;HENTAIGANA LETTER KU-3;Lo;0;L;;;;;N;;;;; +1B02E;HENTAIGANA LETTER KU-4;Lo;0;L;;;;;N;;;;; +1B02F;HENTAIGANA LETTER KU-5;Lo;0;L;;;;;N;;;;; +1B030;HENTAIGANA LETTER KU-6;Lo;0;L;;;;;N;;;;; +1B031;HENTAIGANA LETTER KU-7;Lo;0;L;;;;;N;;;;; +1B032;HENTAIGANA LETTER KE-1;Lo;0;L;;;;;N;;;;; +1B033;HENTAIGANA LETTER KE-2;Lo;0;L;;;;;N;;;;; +1B034;HENTAIGANA LETTER KE-3;Lo;0;L;;;;;N;;;;; +1B035;HENTAIGANA LETTER KE-4;Lo;0;L;;;;;N;;;;; +1B036;HENTAIGANA LETTER KE-5;Lo;0;L;;;;;N;;;;; +1B037;HENTAIGANA LETTER KE-6;Lo;0;L;;;;;N;;;;; +1B038;HENTAIGANA LETTER KO-1;Lo;0;L;;;;;N;;;;; +1B039;HENTAIGANA LETTER KO-2;Lo;0;L;;;;;N;;;;; +1B03A;HENTAIGANA LETTER KO-3;Lo;0;L;;;;;N;;;;; +1B03B;HENTAIGANA LETTER KO-KI;Lo;0;L;;;;;N;;;;; +1B03C;HENTAIGANA LETTER SA-1;Lo;0;L;;;;;N;;;;; +1B03D;HENTAIGANA LETTER SA-2;Lo;0;L;;;;;N;;;;; +1B03E;HENTAIGANA LETTER SA-3;Lo;0;L;;;;;N;;;;; +1B03F;HENTAIGANA LETTER SA-4;Lo;0;L;;;;;N;;;;; +1B040;HENTAIGANA LETTER SA-5;Lo;0;L;;;;;N;;;;; +1B041;HENTAIGANA LETTER SA-6;Lo;0;L;;;;;N;;;;; +1B042;HENTAIGANA LETTER SA-7;Lo;0;L;;;;;N;;;;; +1B043;HENTAIGANA LETTER SA-8;Lo;0;L;;;;;N;;;;; +1B044;HENTAIGANA LETTER SI-1;Lo;0;L;;;;;N;;;;; +1B045;HENTAIGANA LETTER SI-2;Lo;0;L;;;;;N;;;;; +1B046;HENTAIGANA LETTER SI-3;Lo;0;L;;;;;N;;;;; +1B047;HENTAIGANA LETTER SI-4;Lo;0;L;;;;;N;;;;; +1B048;HENTAIGANA LETTER SI-5;Lo;0;L;;;;;N;;;;; +1B049;HENTAIGANA LETTER SI-6;Lo;0;L;;;;;N;;;;; +1B04A;HENTAIGANA LETTER SU-1;Lo;0;L;;;;;N;;;;; +1B04B;HENTAIGANA LETTER SU-2;Lo;0;L;;;;;N;;;;; +1B04C;HENTAIGANA LETTER SU-3;Lo;0;L;;;;;N;;;;; +1B04D;HENTAIGANA LETTER SU-4;Lo;0;L;;;;;N;;;;; +1B04E;HENTAIGANA LETTER SU-5;Lo;0;L;;;;;N;;;;; +1B04F;HENTAIGANA LETTER SU-6;Lo;0;L;;;;;N;;;;; +1B050;HENTAIGANA LETTER SU-7;Lo;0;L;;;;;N;;;;; +1B051;HENTAIGANA LETTER SU-8;Lo;0;L;;;;;N;;;;; +1B052;HENTAIGANA LETTER SE-1;Lo;0;L;;;;;N;;;;; +1B053;HENTAIGANA LETTER SE-2;Lo;0;L;;;;;N;;;;; +1B054;HENTAIGANA LETTER SE-3;Lo;0;L;;;;;N;;;;; +1B055;HENTAIGANA LETTER SE-4;Lo;0;L;;;;;N;;;;; +1B056;HENTAIGANA LETTER SE-5;Lo;0;L;;;;;N;;;;; +1B057;HENTAIGANA LETTER SO-1;Lo;0;L;;;;;N;;;;; +1B058;HENTAIGANA LETTER SO-2;Lo;0;L;;;;;N;;;;; +1B059;HENTAIGANA LETTER SO-3;Lo;0;L;;;;;N;;;;; +1B05A;HENTAIGANA LETTER SO-4;Lo;0;L;;;;;N;;;;; +1B05B;HENTAIGANA LETTER SO-5;Lo;0;L;;;;;N;;;;; +1B05C;HENTAIGANA LETTER SO-6;Lo;0;L;;;;;N;;;;; +1B05D;HENTAIGANA LETTER SO-7;Lo;0;L;;;;;N;;;;; +1B05E;HENTAIGANA LETTER TA-1;Lo;0;L;;;;;N;;;;; +1B05F;HENTAIGANA LETTER TA-2;Lo;0;L;;;;;N;;;;; +1B060;HENTAIGANA LETTER TA-3;Lo;0;L;;;;;N;;;;; +1B061;HENTAIGANA LETTER TA-4;Lo;0;L;;;;;N;;;;; +1B062;HENTAIGANA LETTER TI-1;Lo;0;L;;;;;N;;;;; +1B063;HENTAIGANA LETTER TI-2;Lo;0;L;;;;;N;;;;; +1B064;HENTAIGANA LETTER TI-3;Lo;0;L;;;;;N;;;;; +1B065;HENTAIGANA LETTER TI-4;Lo;0;L;;;;;N;;;;; +1B066;HENTAIGANA LETTER TI-5;Lo;0;L;;;;;N;;;;; +1B067;HENTAIGANA LETTER TI-6;Lo;0;L;;;;;N;;;;; +1B068;HENTAIGANA LETTER TI-7;Lo;0;L;;;;;N;;;;; +1B069;HENTAIGANA LETTER TU-1;Lo;0;L;;;;;N;;;;; +1B06A;HENTAIGANA LETTER TU-2;Lo;0;L;;;;;N;;;;; +1B06B;HENTAIGANA LETTER TU-3;Lo;0;L;;;;;N;;;;; +1B06C;HENTAIGANA LETTER TU-4;Lo;0;L;;;;;N;;;;; +1B06D;HENTAIGANA LETTER TU-TO;Lo;0;L;;;;;N;;;;; +1B06E;HENTAIGANA LETTER TE-1;Lo;0;L;;;;;N;;;;; +1B06F;HENTAIGANA LETTER TE-2;Lo;0;L;;;;;N;;;;; +1B070;HENTAIGANA LETTER TE-3;Lo;0;L;;;;;N;;;;; +1B071;HENTAIGANA LETTER TE-4;Lo;0;L;;;;;N;;;;; +1B072;HENTAIGANA LETTER TE-5;Lo;0;L;;;;;N;;;;; +1B073;HENTAIGANA LETTER TE-6;Lo;0;L;;;;;N;;;;; +1B074;HENTAIGANA LETTER TE-7;Lo;0;L;;;;;N;;;;; +1B075;HENTAIGANA LETTER TE-8;Lo;0;L;;;;;N;;;;; +1B076;HENTAIGANA LETTER TE-9;Lo;0;L;;;;;N;;;;; +1B077;HENTAIGANA LETTER TO-1;Lo;0;L;;;;;N;;;;; +1B078;HENTAIGANA LETTER TO-2;Lo;0;L;;;;;N;;;;; +1B079;HENTAIGANA LETTER TO-3;Lo;0;L;;;;;N;;;;; +1B07A;HENTAIGANA LETTER TO-4;Lo;0;L;;;;;N;;;;; +1B07B;HENTAIGANA LETTER TO-5;Lo;0;L;;;;;N;;;;; +1B07C;HENTAIGANA LETTER TO-6;Lo;0;L;;;;;N;;;;; +1B07D;HENTAIGANA LETTER TO-RA;Lo;0;L;;;;;N;;;;; +1B07E;HENTAIGANA LETTER NA-1;Lo;0;L;;;;;N;;;;; +1B07F;HENTAIGANA LETTER NA-2;Lo;0;L;;;;;N;;;;; +1B080;HENTAIGANA LETTER NA-3;Lo;0;L;;;;;N;;;;; +1B081;HENTAIGANA LETTER NA-4;Lo;0;L;;;;;N;;;;; +1B082;HENTAIGANA LETTER NA-5;Lo;0;L;;;;;N;;;;; +1B083;HENTAIGANA LETTER NA-6;Lo;0;L;;;;;N;;;;; +1B084;HENTAIGANA LETTER NA-7;Lo;0;L;;;;;N;;;;; +1B085;HENTAIGANA LETTER NA-8;Lo;0;L;;;;;N;;;;; +1B086;HENTAIGANA LETTER NA-9;Lo;0;L;;;;;N;;;;; +1B087;HENTAIGANA LETTER NI-1;Lo;0;L;;;;;N;;;;; +1B088;HENTAIGANA LETTER NI-2;Lo;0;L;;;;;N;;;;; +1B089;HENTAIGANA LETTER NI-3;Lo;0;L;;;;;N;;;;; +1B08A;HENTAIGANA LETTER NI-4;Lo;0;L;;;;;N;;;;; +1B08B;HENTAIGANA LETTER NI-5;Lo;0;L;;;;;N;;;;; +1B08C;HENTAIGANA LETTER NI-6;Lo;0;L;;;;;N;;;;; +1B08D;HENTAIGANA LETTER NI-7;Lo;0;L;;;;;N;;;;; +1B08E;HENTAIGANA LETTER NI-TE;Lo;0;L;;;;;N;;;;; +1B08F;HENTAIGANA LETTER NU-1;Lo;0;L;;;;;N;;;;; +1B090;HENTAIGANA LETTER NU-2;Lo;0;L;;;;;N;;;;; +1B091;HENTAIGANA LETTER NU-3;Lo;0;L;;;;;N;;;;; +1B092;HENTAIGANA LETTER NE-1;Lo;0;L;;;;;N;;;;; +1B093;HENTAIGANA LETTER NE-2;Lo;0;L;;;;;N;;;;; +1B094;HENTAIGANA LETTER NE-3;Lo;0;L;;;;;N;;;;; +1B095;HENTAIGANA LETTER NE-4;Lo;0;L;;;;;N;;;;; +1B096;HENTAIGANA LETTER NE-5;Lo;0;L;;;;;N;;;;; +1B097;HENTAIGANA LETTER NE-6;Lo;0;L;;;;;N;;;;; +1B098;HENTAIGANA LETTER NE-KO;Lo;0;L;;;;;N;;;;; +1B099;HENTAIGANA LETTER NO-1;Lo;0;L;;;;;N;;;;; +1B09A;HENTAIGANA LETTER NO-2;Lo;0;L;;;;;N;;;;; +1B09B;HENTAIGANA LETTER NO-3;Lo;0;L;;;;;N;;;;; +1B09C;HENTAIGANA LETTER NO-4;Lo;0;L;;;;;N;;;;; +1B09D;HENTAIGANA LETTER NO-5;Lo;0;L;;;;;N;;;;; +1B09E;HENTAIGANA LETTER HA-1;Lo;0;L;;;;;N;;;;; +1B09F;HENTAIGANA LETTER HA-2;Lo;0;L;;;;;N;;;;; +1B0A0;HENTAIGANA LETTER HA-3;Lo;0;L;;;;;N;;;;; +1B0A1;HENTAIGANA LETTER HA-4;Lo;0;L;;;;;N;;;;; +1B0A2;HENTAIGANA LETTER HA-5;Lo;0;L;;;;;N;;;;; +1B0A3;HENTAIGANA LETTER HA-6;Lo;0;L;;;;;N;;;;; +1B0A4;HENTAIGANA LETTER HA-7;Lo;0;L;;;;;N;;;;; +1B0A5;HENTAIGANA LETTER HA-8;Lo;0;L;;;;;N;;;;; +1B0A6;HENTAIGANA LETTER HA-9;Lo;0;L;;;;;N;;;;; +1B0A7;HENTAIGANA LETTER HA-10;Lo;0;L;;;;;N;;;;; +1B0A8;HENTAIGANA LETTER HA-11;Lo;0;L;;;;;N;;;;; +1B0A9;HENTAIGANA LETTER HI-1;Lo;0;L;;;;;N;;;;; +1B0AA;HENTAIGANA LETTER HI-2;Lo;0;L;;;;;N;;;;; +1B0AB;HENTAIGANA LETTER HI-3;Lo;0;L;;;;;N;;;;; +1B0AC;HENTAIGANA LETTER HI-4;Lo;0;L;;;;;N;;;;; +1B0AD;HENTAIGANA LETTER HI-5;Lo;0;L;;;;;N;;;;; +1B0AE;HENTAIGANA LETTER HI-6;Lo;0;L;;;;;N;;;;; +1B0AF;HENTAIGANA LETTER HI-7;Lo;0;L;;;;;N;;;;; +1B0B0;HENTAIGANA LETTER HU-1;Lo;0;L;;;;;N;;;;; +1B0B1;HENTAIGANA LETTER HU-2;Lo;0;L;;;;;N;;;;; +1B0B2;HENTAIGANA LETTER HU-3;Lo;0;L;;;;;N;;;;; +1B0B3;HENTAIGANA LETTER HE-1;Lo;0;L;;;;;N;;;;; +1B0B4;HENTAIGANA LETTER HE-2;Lo;0;L;;;;;N;;;;; +1B0B5;HENTAIGANA LETTER HE-3;Lo;0;L;;;;;N;;;;; +1B0B6;HENTAIGANA LETTER HE-4;Lo;0;L;;;;;N;;;;; +1B0B7;HENTAIGANA LETTER HE-5;Lo;0;L;;;;;N;;;;; +1B0B8;HENTAIGANA LETTER HE-6;Lo;0;L;;;;;N;;;;; +1B0B9;HENTAIGANA LETTER HE-7;Lo;0;L;;;;;N;;;;; +1B0BA;HENTAIGANA LETTER HO-1;Lo;0;L;;;;;N;;;;; +1B0BB;HENTAIGANA LETTER HO-2;Lo;0;L;;;;;N;;;;; +1B0BC;HENTAIGANA LETTER HO-3;Lo;0;L;;;;;N;;;;; +1B0BD;HENTAIGANA LETTER HO-4;Lo;0;L;;;;;N;;;;; +1B0BE;HENTAIGANA LETTER HO-5;Lo;0;L;;;;;N;;;;; +1B0BF;HENTAIGANA LETTER HO-6;Lo;0;L;;;;;N;;;;; +1B0C0;HENTAIGANA LETTER HO-7;Lo;0;L;;;;;N;;;;; +1B0C1;HENTAIGANA LETTER HO-8;Lo;0;L;;;;;N;;;;; +1B0C2;HENTAIGANA LETTER MA-1;Lo;0;L;;;;;N;;;;; +1B0C3;HENTAIGANA LETTER MA-2;Lo;0;L;;;;;N;;;;; +1B0C4;HENTAIGANA LETTER MA-3;Lo;0;L;;;;;N;;;;; +1B0C5;HENTAIGANA LETTER MA-4;Lo;0;L;;;;;N;;;;; +1B0C6;HENTAIGANA LETTER MA-5;Lo;0;L;;;;;N;;;;; +1B0C7;HENTAIGANA LETTER MA-6;Lo;0;L;;;;;N;;;;; +1B0C8;HENTAIGANA LETTER MA-7;Lo;0;L;;;;;N;;;;; +1B0C9;HENTAIGANA LETTER MI-1;Lo;0;L;;;;;N;;;;; +1B0CA;HENTAIGANA LETTER MI-2;Lo;0;L;;;;;N;;;;; +1B0CB;HENTAIGANA LETTER MI-3;Lo;0;L;;;;;N;;;;; +1B0CC;HENTAIGANA LETTER MI-4;Lo;0;L;;;;;N;;;;; +1B0CD;HENTAIGANA LETTER MI-5;Lo;0;L;;;;;N;;;;; +1B0CE;HENTAIGANA LETTER MI-6;Lo;0;L;;;;;N;;;;; +1B0CF;HENTAIGANA LETTER MI-7;Lo;0;L;;;;;N;;;;; +1B0D0;HENTAIGANA LETTER MU-1;Lo;0;L;;;;;N;;;;; +1B0D1;HENTAIGANA LETTER MU-2;Lo;0;L;;;;;N;;;;; +1B0D2;HENTAIGANA LETTER MU-3;Lo;0;L;;;;;N;;;;; +1B0D3;HENTAIGANA LETTER MU-4;Lo;0;L;;;;;N;;;;; +1B0D4;HENTAIGANA LETTER ME-1;Lo;0;L;;;;;N;;;;; +1B0D5;HENTAIGANA LETTER ME-2;Lo;0;L;;;;;N;;;;; +1B0D6;HENTAIGANA LETTER ME-MA;Lo;0;L;;;;;N;;;;; +1B0D7;HENTAIGANA LETTER MO-1;Lo;0;L;;;;;N;;;;; +1B0D8;HENTAIGANA LETTER MO-2;Lo;0;L;;;;;N;;;;; +1B0D9;HENTAIGANA LETTER MO-3;Lo;0;L;;;;;N;;;;; +1B0DA;HENTAIGANA LETTER MO-4;Lo;0;L;;;;;N;;;;; +1B0DB;HENTAIGANA LETTER MO-5;Lo;0;L;;;;;N;;;;; +1B0DC;HENTAIGANA LETTER MO-6;Lo;0;L;;;;;N;;;;; +1B0DD;HENTAIGANA LETTER YA-1;Lo;0;L;;;;;N;;;;; +1B0DE;HENTAIGANA LETTER YA-2;Lo;0;L;;;;;N;;;;; +1B0DF;HENTAIGANA LETTER YA-3;Lo;0;L;;;;;N;;;;; +1B0E0;HENTAIGANA LETTER YA-4;Lo;0;L;;;;;N;;;;; +1B0E1;HENTAIGANA LETTER YA-5;Lo;0;L;;;;;N;;;;; +1B0E2;HENTAIGANA LETTER YA-YO;Lo;0;L;;;;;N;;;;; +1B0E3;HENTAIGANA LETTER YU-1;Lo;0;L;;;;;N;;;;; +1B0E4;HENTAIGANA LETTER YU-2;Lo;0;L;;;;;N;;;;; +1B0E5;HENTAIGANA LETTER YU-3;Lo;0;L;;;;;N;;;;; +1B0E6;HENTAIGANA LETTER YU-4;Lo;0;L;;;;;N;;;;; +1B0E7;HENTAIGANA LETTER YO-1;Lo;0;L;;;;;N;;;;; +1B0E8;HENTAIGANA LETTER YO-2;Lo;0;L;;;;;N;;;;; +1B0E9;HENTAIGANA LETTER YO-3;Lo;0;L;;;;;N;;;;; +1B0EA;HENTAIGANA LETTER YO-4;Lo;0;L;;;;;N;;;;; +1B0EB;HENTAIGANA LETTER YO-5;Lo;0;L;;;;;N;;;;; +1B0EC;HENTAIGANA LETTER YO-6;Lo;0;L;;;;;N;;;;; +1B0ED;HENTAIGANA LETTER RA-1;Lo;0;L;;;;;N;;;;; +1B0EE;HENTAIGANA LETTER RA-2;Lo;0;L;;;;;N;;;;; +1B0EF;HENTAIGANA LETTER RA-3;Lo;0;L;;;;;N;;;;; +1B0F0;HENTAIGANA LETTER RA-4;Lo;0;L;;;;;N;;;;; +1B0F1;HENTAIGANA LETTER RI-1;Lo;0;L;;;;;N;;;;; +1B0F2;HENTAIGANA LETTER RI-2;Lo;0;L;;;;;N;;;;; +1B0F3;HENTAIGANA LETTER RI-3;Lo;0;L;;;;;N;;;;; +1B0F4;HENTAIGANA LETTER RI-4;Lo;0;L;;;;;N;;;;; +1B0F5;HENTAIGANA LETTER RI-5;Lo;0;L;;;;;N;;;;; +1B0F6;HENTAIGANA LETTER RI-6;Lo;0;L;;;;;N;;;;; +1B0F7;HENTAIGANA LETTER RI-7;Lo;0;L;;;;;N;;;;; +1B0F8;HENTAIGANA LETTER RU-1;Lo;0;L;;;;;N;;;;; +1B0F9;HENTAIGANA LETTER RU-2;Lo;0;L;;;;;N;;;;; +1B0FA;HENTAIGANA LETTER RU-3;Lo;0;L;;;;;N;;;;; +1B0FB;HENTAIGANA LETTER RU-4;Lo;0;L;;;;;N;;;;; +1B0FC;HENTAIGANA LETTER RU-5;Lo;0;L;;;;;N;;;;; +1B0FD;HENTAIGANA LETTER RU-6;Lo;0;L;;;;;N;;;;; +1B0FE;HENTAIGANA LETTER RE-1;Lo;0;L;;;;;N;;;;; +1B0FF;HENTAIGANA LETTER RE-2;Lo;0;L;;;;;N;;;;; +1B100;HENTAIGANA LETTER RE-3;Lo;0;L;;;;;N;;;;; +1B101;HENTAIGANA LETTER RE-4;Lo;0;L;;;;;N;;;;; +1B102;HENTAIGANA LETTER RO-1;Lo;0;L;;;;;N;;;;; +1B103;HENTAIGANA LETTER RO-2;Lo;0;L;;;;;N;;;;; +1B104;HENTAIGANA LETTER RO-3;Lo;0;L;;;;;N;;;;; +1B105;HENTAIGANA LETTER RO-4;Lo;0;L;;;;;N;;;;; +1B106;HENTAIGANA LETTER RO-5;Lo;0;L;;;;;N;;;;; +1B107;HENTAIGANA LETTER RO-6;Lo;0;L;;;;;N;;;;; +1B108;HENTAIGANA LETTER WA-1;Lo;0;L;;;;;N;;;;; +1B109;HENTAIGANA LETTER WA-2;Lo;0;L;;;;;N;;;;; +1B10A;HENTAIGANA LETTER WA-3;Lo;0;L;;;;;N;;;;; +1B10B;HENTAIGANA LETTER WA-4;Lo;0;L;;;;;N;;;;; +1B10C;HENTAIGANA LETTER WA-5;Lo;0;L;;;;;N;;;;; +1B10D;HENTAIGANA LETTER WI-1;Lo;0;L;;;;;N;;;;; +1B10E;HENTAIGANA LETTER WI-2;Lo;0;L;;;;;N;;;;; +1B10F;HENTAIGANA LETTER WI-3;Lo;0;L;;;;;N;;;;; +1B110;HENTAIGANA LETTER WI-4;Lo;0;L;;;;;N;;;;; +1B111;HENTAIGANA LETTER WI-5;Lo;0;L;;;;;N;;;;; +1B112;HENTAIGANA LETTER WE-1;Lo;0;L;;;;;N;;;;; +1B113;HENTAIGANA LETTER WE-2;Lo;0;L;;;;;N;;;;; +1B114;HENTAIGANA LETTER WE-3;Lo;0;L;;;;;N;;;;; +1B115;HENTAIGANA LETTER WE-4;Lo;0;L;;;;;N;;;;; +1B116;HENTAIGANA LETTER WO-1;Lo;0;L;;;;;N;;;;; +1B117;HENTAIGANA LETTER WO-2;Lo;0;L;;;;;N;;;;; +1B118;HENTAIGANA LETTER WO-3;Lo;0;L;;;;;N;;;;; +1B119;HENTAIGANA LETTER WO-4;Lo;0;L;;;;;N;;;;; +1B11A;HENTAIGANA LETTER WO-5;Lo;0;L;;;;;N;;;;; +1B11B;HENTAIGANA LETTER WO-6;Lo;0;L;;;;;N;;;;; +1B11C;HENTAIGANA LETTER WO-7;Lo;0;L;;;;;N;;;;; +1B11D;HENTAIGANA LETTER N-MU-MO-1;Lo;0;L;;;;;N;;;;; +1B11E;HENTAIGANA LETTER N-MU-MO-2;Lo;0;L;;;;;N;;;;; +1B170;NUSHU CHARACTER-1B170;Lo;0;L;;;;;N;;;;; +1B171;NUSHU CHARACTER-1B171;Lo;0;L;;;;;N;;;;; +1B172;NUSHU CHARACTER-1B172;Lo;0;L;;;;;N;;;;; +1B173;NUSHU CHARACTER-1B173;Lo;0;L;;;;;N;;;;; +1B174;NUSHU CHARACTER-1B174;Lo;0;L;;;;;N;;;;; +1B175;NUSHU CHARACTER-1B175;Lo;0;L;;;;;N;;;;; +1B176;NUSHU CHARACTER-1B176;Lo;0;L;;;;;N;;;;; +1B177;NUSHU CHARACTER-1B177;Lo;0;L;;;;;N;;;;; +1B178;NUSHU CHARACTER-1B178;Lo;0;L;;;;;N;;;;; +1B179;NUSHU CHARACTER-1B179;Lo;0;L;;;;;N;;;;; +1B17A;NUSHU CHARACTER-1B17A;Lo;0;L;;;;;N;;;;; +1B17B;NUSHU CHARACTER-1B17B;Lo;0;L;;;;;N;;;;; +1B17C;NUSHU CHARACTER-1B17C;Lo;0;L;;;;;N;;;;; +1B17D;NUSHU CHARACTER-1B17D;Lo;0;L;;;;;N;;;;; +1B17E;NUSHU CHARACTER-1B17E;Lo;0;L;;;;;N;;;;; +1B17F;NUSHU CHARACTER-1B17F;Lo;0;L;;;;;N;;;;; +1B180;NUSHU CHARACTER-1B180;Lo;0;L;;;;;N;;;;; +1B181;NUSHU CHARACTER-1B181;Lo;0;L;;;;;N;;;;; +1B182;NUSHU CHARACTER-1B182;Lo;0;L;;;;;N;;;;; +1B183;NUSHU CHARACTER-1B183;Lo;0;L;;;;;N;;;;; +1B184;NUSHU CHARACTER-1B184;Lo;0;L;;;;;N;;;;; +1B185;NUSHU CHARACTER-1B185;Lo;0;L;;;;;N;;;;; +1B186;NUSHU CHARACTER-1B186;Lo;0;L;;;;;N;;;;; +1B187;NUSHU CHARACTER-1B187;Lo;0;L;;;;;N;;;;; +1B188;NUSHU CHARACTER-1B188;Lo;0;L;;;;;N;;;;; +1B189;NUSHU CHARACTER-1B189;Lo;0;L;;;;;N;;;;; +1B18A;NUSHU CHARACTER-1B18A;Lo;0;L;;;;;N;;;;; +1B18B;NUSHU CHARACTER-1B18B;Lo;0;L;;;;;N;;;;; +1B18C;NUSHU CHARACTER-1B18C;Lo;0;L;;;;;N;;;;; +1B18D;NUSHU CHARACTER-1B18D;Lo;0;L;;;;;N;;;;; +1B18E;NUSHU CHARACTER-1B18E;Lo;0;L;;;;;N;;;;; +1B18F;NUSHU CHARACTER-1B18F;Lo;0;L;;;;;N;;;;; +1B190;NUSHU CHARACTER-1B190;Lo;0;L;;;;;N;;;;; +1B191;NUSHU CHARACTER-1B191;Lo;0;L;;;;;N;;;;; +1B192;NUSHU CHARACTER-1B192;Lo;0;L;;;;;N;;;;; +1B193;NUSHU CHARACTER-1B193;Lo;0;L;;;;;N;;;;; +1B194;NUSHU CHARACTER-1B194;Lo;0;L;;;;;N;;;;; +1B195;NUSHU CHARACTER-1B195;Lo;0;L;;;;;N;;;;; +1B196;NUSHU CHARACTER-1B196;Lo;0;L;;;;;N;;;;; +1B197;NUSHU CHARACTER-1B197;Lo;0;L;;;;;N;;;;; +1B198;NUSHU CHARACTER-1B198;Lo;0;L;;;;;N;;;;; +1B199;NUSHU CHARACTER-1B199;Lo;0;L;;;;;N;;;;; +1B19A;NUSHU CHARACTER-1B19A;Lo;0;L;;;;;N;;;;; +1B19B;NUSHU CHARACTER-1B19B;Lo;0;L;;;;;N;;;;; +1B19C;NUSHU CHARACTER-1B19C;Lo;0;L;;;;;N;;;;; +1B19D;NUSHU CHARACTER-1B19D;Lo;0;L;;;;;N;;;;; +1B19E;NUSHU CHARACTER-1B19E;Lo;0;L;;;;;N;;;;; +1B19F;NUSHU CHARACTER-1B19F;Lo;0;L;;;;;N;;;;; +1B1A0;NUSHU CHARACTER-1B1A0;Lo;0;L;;;;;N;;;;; +1B1A1;NUSHU CHARACTER-1B1A1;Lo;0;L;;;;;N;;;;; +1B1A2;NUSHU CHARACTER-1B1A2;Lo;0;L;;;;;N;;;;; +1B1A3;NUSHU CHARACTER-1B1A3;Lo;0;L;;;;;N;;;;; +1B1A4;NUSHU CHARACTER-1B1A4;Lo;0;L;;;;;N;;;;; +1B1A5;NUSHU CHARACTER-1B1A5;Lo;0;L;;;;;N;;;;; +1B1A6;NUSHU CHARACTER-1B1A6;Lo;0;L;;;;;N;;;;; +1B1A7;NUSHU CHARACTER-1B1A7;Lo;0;L;;;;;N;;;;; +1B1A8;NUSHU CHARACTER-1B1A8;Lo;0;L;;;;;N;;;;; +1B1A9;NUSHU CHARACTER-1B1A9;Lo;0;L;;;;;N;;;;; +1B1AA;NUSHU CHARACTER-1B1AA;Lo;0;L;;;;;N;;;;; +1B1AB;NUSHU CHARACTER-1B1AB;Lo;0;L;;;;;N;;;;; +1B1AC;NUSHU CHARACTER-1B1AC;Lo;0;L;;;;;N;;;;; +1B1AD;NUSHU CHARACTER-1B1AD;Lo;0;L;;;;;N;;;;; +1B1AE;NUSHU CHARACTER-1B1AE;Lo;0;L;;;;;N;;;;; +1B1AF;NUSHU CHARACTER-1B1AF;Lo;0;L;;;;;N;;;;; +1B1B0;NUSHU CHARACTER-1B1B0;Lo;0;L;;;;;N;;;;; +1B1B1;NUSHU CHARACTER-1B1B1;Lo;0;L;;;;;N;;;;; +1B1B2;NUSHU CHARACTER-1B1B2;Lo;0;L;;;;;N;;;;; +1B1B3;NUSHU CHARACTER-1B1B3;Lo;0;L;;;;;N;;;;; +1B1B4;NUSHU CHARACTER-1B1B4;Lo;0;L;;;;;N;;;;; +1B1B5;NUSHU CHARACTER-1B1B5;Lo;0;L;;;;;N;;;;; +1B1B6;NUSHU CHARACTER-1B1B6;Lo;0;L;;;;;N;;;;; +1B1B7;NUSHU CHARACTER-1B1B7;Lo;0;L;;;;;N;;;;; +1B1B8;NUSHU CHARACTER-1B1B8;Lo;0;L;;;;;N;;;;; +1B1B9;NUSHU CHARACTER-1B1B9;Lo;0;L;;;;;N;;;;; +1B1BA;NUSHU CHARACTER-1B1BA;Lo;0;L;;;;;N;;;;; +1B1BB;NUSHU CHARACTER-1B1BB;Lo;0;L;;;;;N;;;;; +1B1BC;NUSHU CHARACTER-1B1BC;Lo;0;L;;;;;N;;;;; +1B1BD;NUSHU CHARACTER-1B1BD;Lo;0;L;;;;;N;;;;; +1B1BE;NUSHU CHARACTER-1B1BE;Lo;0;L;;;;;N;;;;; +1B1BF;NUSHU CHARACTER-1B1BF;Lo;0;L;;;;;N;;;;; +1B1C0;NUSHU CHARACTER-1B1C0;Lo;0;L;;;;;N;;;;; +1B1C1;NUSHU CHARACTER-1B1C1;Lo;0;L;;;;;N;;;;; +1B1C2;NUSHU CHARACTER-1B1C2;Lo;0;L;;;;;N;;;;; +1B1C3;NUSHU CHARACTER-1B1C3;Lo;0;L;;;;;N;;;;; +1B1C4;NUSHU CHARACTER-1B1C4;Lo;0;L;;;;;N;;;;; +1B1C5;NUSHU CHARACTER-1B1C5;Lo;0;L;;;;;N;;;;; +1B1C6;NUSHU CHARACTER-1B1C6;Lo;0;L;;;;;N;;;;; +1B1C7;NUSHU CHARACTER-1B1C7;Lo;0;L;;;;;N;;;;; +1B1C8;NUSHU CHARACTER-1B1C8;Lo;0;L;;;;;N;;;;; +1B1C9;NUSHU CHARACTER-1B1C9;Lo;0;L;;;;;N;;;;; +1B1CA;NUSHU CHARACTER-1B1CA;Lo;0;L;;;;;N;;;;; +1B1CB;NUSHU CHARACTER-1B1CB;Lo;0;L;;;;;N;;;;; +1B1CC;NUSHU CHARACTER-1B1CC;Lo;0;L;;;;;N;;;;; +1B1CD;NUSHU CHARACTER-1B1CD;Lo;0;L;;;;;N;;;;; +1B1CE;NUSHU CHARACTER-1B1CE;Lo;0;L;;;;;N;;;;; +1B1CF;NUSHU CHARACTER-1B1CF;Lo;0;L;;;;;N;;;;; +1B1D0;NUSHU CHARACTER-1B1D0;Lo;0;L;;;;;N;;;;; +1B1D1;NUSHU CHARACTER-1B1D1;Lo;0;L;;;;;N;;;;; +1B1D2;NUSHU CHARACTER-1B1D2;Lo;0;L;;;;;N;;;;; +1B1D3;NUSHU CHARACTER-1B1D3;Lo;0;L;;;;;N;;;;; +1B1D4;NUSHU CHARACTER-1B1D4;Lo;0;L;;;;;N;;;;; +1B1D5;NUSHU CHARACTER-1B1D5;Lo;0;L;;;;;N;;;;; +1B1D6;NUSHU CHARACTER-1B1D6;Lo;0;L;;;;;N;;;;; +1B1D7;NUSHU CHARACTER-1B1D7;Lo;0;L;;;;;N;;;;; +1B1D8;NUSHU CHARACTER-1B1D8;Lo;0;L;;;;;N;;;;; +1B1D9;NUSHU CHARACTER-1B1D9;Lo;0;L;;;;;N;;;;; +1B1DA;NUSHU CHARACTER-1B1DA;Lo;0;L;;;;;N;;;;; +1B1DB;NUSHU CHARACTER-1B1DB;Lo;0;L;;;;;N;;;;; +1B1DC;NUSHU CHARACTER-1B1DC;Lo;0;L;;;;;N;;;;; +1B1DD;NUSHU CHARACTER-1B1DD;Lo;0;L;;;;;N;;;;; +1B1DE;NUSHU CHARACTER-1B1DE;Lo;0;L;;;;;N;;;;; +1B1DF;NUSHU CHARACTER-1B1DF;Lo;0;L;;;;;N;;;;; +1B1E0;NUSHU CHARACTER-1B1E0;Lo;0;L;;;;;N;;;;; +1B1E1;NUSHU CHARACTER-1B1E1;Lo;0;L;;;;;N;;;;; +1B1E2;NUSHU CHARACTER-1B1E2;Lo;0;L;;;;;N;;;;; +1B1E3;NUSHU CHARACTER-1B1E3;Lo;0;L;;;;;N;;;;; +1B1E4;NUSHU CHARACTER-1B1E4;Lo;0;L;;;;;N;;;;; +1B1E5;NUSHU CHARACTER-1B1E5;Lo;0;L;;;;;N;;;;; +1B1E6;NUSHU CHARACTER-1B1E6;Lo;0;L;;;;;N;;;;; +1B1E7;NUSHU CHARACTER-1B1E7;Lo;0;L;;;;;N;;;;; +1B1E8;NUSHU CHARACTER-1B1E8;Lo;0;L;;;;;N;;;;; +1B1E9;NUSHU CHARACTER-1B1E9;Lo;0;L;;;;;N;;;;; +1B1EA;NUSHU CHARACTER-1B1EA;Lo;0;L;;;;;N;;;;; +1B1EB;NUSHU CHARACTER-1B1EB;Lo;0;L;;;;;N;;;;; +1B1EC;NUSHU CHARACTER-1B1EC;Lo;0;L;;;;;N;;;;; +1B1ED;NUSHU CHARACTER-1B1ED;Lo;0;L;;;;;N;;;;; +1B1EE;NUSHU CHARACTER-1B1EE;Lo;0;L;;;;;N;;;;; +1B1EF;NUSHU CHARACTER-1B1EF;Lo;0;L;;;;;N;;;;; +1B1F0;NUSHU CHARACTER-1B1F0;Lo;0;L;;;;;N;;;;; +1B1F1;NUSHU CHARACTER-1B1F1;Lo;0;L;;;;;N;;;;; +1B1F2;NUSHU CHARACTER-1B1F2;Lo;0;L;;;;;N;;;;; +1B1F3;NUSHU CHARACTER-1B1F3;Lo;0;L;;;;;N;;;;; +1B1F4;NUSHU CHARACTER-1B1F4;Lo;0;L;;;;;N;;;;; +1B1F5;NUSHU CHARACTER-1B1F5;Lo;0;L;;;;;N;;;;; +1B1F6;NUSHU CHARACTER-1B1F6;Lo;0;L;;;;;N;;;;; +1B1F7;NUSHU CHARACTER-1B1F7;Lo;0;L;;;;;N;;;;; +1B1F8;NUSHU CHARACTER-1B1F8;Lo;0;L;;;;;N;;;;; +1B1F9;NUSHU CHARACTER-1B1F9;Lo;0;L;;;;;N;;;;; +1B1FA;NUSHU CHARACTER-1B1FA;Lo;0;L;;;;;N;;;;; +1B1FB;NUSHU CHARACTER-1B1FB;Lo;0;L;;;;;N;;;;; +1B1FC;NUSHU CHARACTER-1B1FC;Lo;0;L;;;;;N;;;;; +1B1FD;NUSHU CHARACTER-1B1FD;Lo;0;L;;;;;N;;;;; +1B1FE;NUSHU CHARACTER-1B1FE;Lo;0;L;;;;;N;;;;; +1B1FF;NUSHU CHARACTER-1B1FF;Lo;0;L;;;;;N;;;;; +1B200;NUSHU CHARACTER-1B200;Lo;0;L;;;;;N;;;;; +1B201;NUSHU CHARACTER-1B201;Lo;0;L;;;;;N;;;;; +1B202;NUSHU CHARACTER-1B202;Lo;0;L;;;;;N;;;;; +1B203;NUSHU CHARACTER-1B203;Lo;0;L;;;;;N;;;;; +1B204;NUSHU CHARACTER-1B204;Lo;0;L;;;;;N;;;;; +1B205;NUSHU CHARACTER-1B205;Lo;0;L;;;;;N;;;;; +1B206;NUSHU CHARACTER-1B206;Lo;0;L;;;;;N;;;;; +1B207;NUSHU CHARACTER-1B207;Lo;0;L;;;;;N;;;;; +1B208;NUSHU CHARACTER-1B208;Lo;0;L;;;;;N;;;;; +1B209;NUSHU CHARACTER-1B209;Lo;0;L;;;;;N;;;;; +1B20A;NUSHU CHARACTER-1B20A;Lo;0;L;;;;;N;;;;; +1B20B;NUSHU CHARACTER-1B20B;Lo;0;L;;;;;N;;;;; +1B20C;NUSHU CHARACTER-1B20C;Lo;0;L;;;;;N;;;;; +1B20D;NUSHU CHARACTER-1B20D;Lo;0;L;;;;;N;;;;; +1B20E;NUSHU CHARACTER-1B20E;Lo;0;L;;;;;N;;;;; +1B20F;NUSHU CHARACTER-1B20F;Lo;0;L;;;;;N;;;;; +1B210;NUSHU CHARACTER-1B210;Lo;0;L;;;;;N;;;;; +1B211;NUSHU CHARACTER-1B211;Lo;0;L;;;;;N;;;;; +1B212;NUSHU CHARACTER-1B212;Lo;0;L;;;;;N;;;;; +1B213;NUSHU CHARACTER-1B213;Lo;0;L;;;;;N;;;;; +1B214;NUSHU CHARACTER-1B214;Lo;0;L;;;;;N;;;;; +1B215;NUSHU CHARACTER-1B215;Lo;0;L;;;;;N;;;;; +1B216;NUSHU CHARACTER-1B216;Lo;0;L;;;;;N;;;;; +1B217;NUSHU CHARACTER-1B217;Lo;0;L;;;;;N;;;;; +1B218;NUSHU CHARACTER-1B218;Lo;0;L;;;;;N;;;;; +1B219;NUSHU CHARACTER-1B219;Lo;0;L;;;;;N;;;;; +1B21A;NUSHU CHARACTER-1B21A;Lo;0;L;;;;;N;;;;; +1B21B;NUSHU CHARACTER-1B21B;Lo;0;L;;;;;N;;;;; +1B21C;NUSHU CHARACTER-1B21C;Lo;0;L;;;;;N;;;;; +1B21D;NUSHU CHARACTER-1B21D;Lo;0;L;;;;;N;;;;; +1B21E;NUSHU CHARACTER-1B21E;Lo;0;L;;;;;N;;;;; +1B21F;NUSHU CHARACTER-1B21F;Lo;0;L;;;;;N;;;;; +1B220;NUSHU CHARACTER-1B220;Lo;0;L;;;;;N;;;;; +1B221;NUSHU CHARACTER-1B221;Lo;0;L;;;;;N;;;;; +1B222;NUSHU CHARACTER-1B222;Lo;0;L;;;;;N;;;;; +1B223;NUSHU CHARACTER-1B223;Lo;0;L;;;;;N;;;;; +1B224;NUSHU CHARACTER-1B224;Lo;0;L;;;;;N;;;;; +1B225;NUSHU CHARACTER-1B225;Lo;0;L;;;;;N;;;;; +1B226;NUSHU CHARACTER-1B226;Lo;0;L;;;;;N;;;;; +1B227;NUSHU CHARACTER-1B227;Lo;0;L;;;;;N;;;;; +1B228;NUSHU CHARACTER-1B228;Lo;0;L;;;;;N;;;;; +1B229;NUSHU CHARACTER-1B229;Lo;0;L;;;;;N;;;;; +1B22A;NUSHU CHARACTER-1B22A;Lo;0;L;;;;;N;;;;; +1B22B;NUSHU CHARACTER-1B22B;Lo;0;L;;;;;N;;;;; +1B22C;NUSHU CHARACTER-1B22C;Lo;0;L;;;;;N;;;;; +1B22D;NUSHU CHARACTER-1B22D;Lo;0;L;;;;;N;;;;; +1B22E;NUSHU CHARACTER-1B22E;Lo;0;L;;;;;N;;;;; +1B22F;NUSHU CHARACTER-1B22F;Lo;0;L;;;;;N;;;;; +1B230;NUSHU CHARACTER-1B230;Lo;0;L;;;;;N;;;;; +1B231;NUSHU CHARACTER-1B231;Lo;0;L;;;;;N;;;;; +1B232;NUSHU CHARACTER-1B232;Lo;0;L;;;;;N;;;;; +1B233;NUSHU CHARACTER-1B233;Lo;0;L;;;;;N;;;;; +1B234;NUSHU CHARACTER-1B234;Lo;0;L;;;;;N;;;;; +1B235;NUSHU CHARACTER-1B235;Lo;0;L;;;;;N;;;;; +1B236;NUSHU CHARACTER-1B236;Lo;0;L;;;;;N;;;;; +1B237;NUSHU CHARACTER-1B237;Lo;0;L;;;;;N;;;;; +1B238;NUSHU CHARACTER-1B238;Lo;0;L;;;;;N;;;;; +1B239;NUSHU CHARACTER-1B239;Lo;0;L;;;;;N;;;;; +1B23A;NUSHU CHARACTER-1B23A;Lo;0;L;;;;;N;;;;; +1B23B;NUSHU CHARACTER-1B23B;Lo;0;L;;;;;N;;;;; +1B23C;NUSHU CHARACTER-1B23C;Lo;0;L;;;;;N;;;;; +1B23D;NUSHU CHARACTER-1B23D;Lo;0;L;;;;;N;;;;; +1B23E;NUSHU CHARACTER-1B23E;Lo;0;L;;;;;N;;;;; +1B23F;NUSHU CHARACTER-1B23F;Lo;0;L;;;;;N;;;;; +1B240;NUSHU CHARACTER-1B240;Lo;0;L;;;;;N;;;;; +1B241;NUSHU CHARACTER-1B241;Lo;0;L;;;;;N;;;;; +1B242;NUSHU CHARACTER-1B242;Lo;0;L;;;;;N;;;;; +1B243;NUSHU CHARACTER-1B243;Lo;0;L;;;;;N;;;;; +1B244;NUSHU CHARACTER-1B244;Lo;0;L;;;;;N;;;;; +1B245;NUSHU CHARACTER-1B245;Lo;0;L;;;;;N;;;;; +1B246;NUSHU CHARACTER-1B246;Lo;0;L;;;;;N;;;;; +1B247;NUSHU CHARACTER-1B247;Lo;0;L;;;;;N;;;;; +1B248;NUSHU CHARACTER-1B248;Lo;0;L;;;;;N;;;;; +1B249;NUSHU CHARACTER-1B249;Lo;0;L;;;;;N;;;;; +1B24A;NUSHU CHARACTER-1B24A;Lo;0;L;;;;;N;;;;; +1B24B;NUSHU CHARACTER-1B24B;Lo;0;L;;;;;N;;;;; +1B24C;NUSHU CHARACTER-1B24C;Lo;0;L;;;;;N;;;;; +1B24D;NUSHU CHARACTER-1B24D;Lo;0;L;;;;;N;;;;; +1B24E;NUSHU CHARACTER-1B24E;Lo;0;L;;;;;N;;;;; +1B24F;NUSHU CHARACTER-1B24F;Lo;0;L;;;;;N;;;;; +1B250;NUSHU CHARACTER-1B250;Lo;0;L;;;;;N;;;;; +1B251;NUSHU CHARACTER-1B251;Lo;0;L;;;;;N;;;;; +1B252;NUSHU CHARACTER-1B252;Lo;0;L;;;;;N;;;;; +1B253;NUSHU CHARACTER-1B253;Lo;0;L;;;;;N;;;;; +1B254;NUSHU CHARACTER-1B254;Lo;0;L;;;;;N;;;;; +1B255;NUSHU CHARACTER-1B255;Lo;0;L;;;;;N;;;;; +1B256;NUSHU CHARACTER-1B256;Lo;0;L;;;;;N;;;;; +1B257;NUSHU CHARACTER-1B257;Lo;0;L;;;;;N;;;;; +1B258;NUSHU CHARACTER-1B258;Lo;0;L;;;;;N;;;;; +1B259;NUSHU CHARACTER-1B259;Lo;0;L;;;;;N;;;;; +1B25A;NUSHU CHARACTER-1B25A;Lo;0;L;;;;;N;;;;; +1B25B;NUSHU CHARACTER-1B25B;Lo;0;L;;;;;N;;;;; +1B25C;NUSHU CHARACTER-1B25C;Lo;0;L;;;;;N;;;;; +1B25D;NUSHU CHARACTER-1B25D;Lo;0;L;;;;;N;;;;; +1B25E;NUSHU CHARACTER-1B25E;Lo;0;L;;;;;N;;;;; +1B25F;NUSHU CHARACTER-1B25F;Lo;0;L;;;;;N;;;;; +1B260;NUSHU CHARACTER-1B260;Lo;0;L;;;;;N;;;;; +1B261;NUSHU CHARACTER-1B261;Lo;0;L;;;;;N;;;;; +1B262;NUSHU CHARACTER-1B262;Lo;0;L;;;;;N;;;;; +1B263;NUSHU CHARACTER-1B263;Lo;0;L;;;;;N;;;;; +1B264;NUSHU CHARACTER-1B264;Lo;0;L;;;;;N;;;;; +1B265;NUSHU CHARACTER-1B265;Lo;0;L;;;;;N;;;;; +1B266;NUSHU CHARACTER-1B266;Lo;0;L;;;;;N;;;;; +1B267;NUSHU CHARACTER-1B267;Lo;0;L;;;;;N;;;;; +1B268;NUSHU CHARACTER-1B268;Lo;0;L;;;;;N;;;;; +1B269;NUSHU CHARACTER-1B269;Lo;0;L;;;;;N;;;;; +1B26A;NUSHU CHARACTER-1B26A;Lo;0;L;;;;;N;;;;; +1B26B;NUSHU CHARACTER-1B26B;Lo;0;L;;;;;N;;;;; +1B26C;NUSHU CHARACTER-1B26C;Lo;0;L;;;;;N;;;;; +1B26D;NUSHU CHARACTER-1B26D;Lo;0;L;;;;;N;;;;; +1B26E;NUSHU CHARACTER-1B26E;Lo;0;L;;;;;N;;;;; +1B26F;NUSHU CHARACTER-1B26F;Lo;0;L;;;;;N;;;;; +1B270;NUSHU CHARACTER-1B270;Lo;0;L;;;;;N;;;;; +1B271;NUSHU CHARACTER-1B271;Lo;0;L;;;;;N;;;;; +1B272;NUSHU CHARACTER-1B272;Lo;0;L;;;;;N;;;;; +1B273;NUSHU CHARACTER-1B273;Lo;0;L;;;;;N;;;;; +1B274;NUSHU CHARACTER-1B274;Lo;0;L;;;;;N;;;;; +1B275;NUSHU CHARACTER-1B275;Lo;0;L;;;;;N;;;;; +1B276;NUSHU CHARACTER-1B276;Lo;0;L;;;;;N;;;;; +1B277;NUSHU CHARACTER-1B277;Lo;0;L;;;;;N;;;;; +1B278;NUSHU CHARACTER-1B278;Lo;0;L;;;;;N;;;;; +1B279;NUSHU CHARACTER-1B279;Lo;0;L;;;;;N;;;;; +1B27A;NUSHU CHARACTER-1B27A;Lo;0;L;;;;;N;;;;; +1B27B;NUSHU CHARACTER-1B27B;Lo;0;L;;;;;N;;;;; +1B27C;NUSHU CHARACTER-1B27C;Lo;0;L;;;;;N;;;;; +1B27D;NUSHU CHARACTER-1B27D;Lo;0;L;;;;;N;;;;; +1B27E;NUSHU CHARACTER-1B27E;Lo;0;L;;;;;N;;;;; +1B27F;NUSHU CHARACTER-1B27F;Lo;0;L;;;;;N;;;;; +1B280;NUSHU CHARACTER-1B280;Lo;0;L;;;;;N;;;;; +1B281;NUSHU CHARACTER-1B281;Lo;0;L;;;;;N;;;;; +1B282;NUSHU CHARACTER-1B282;Lo;0;L;;;;;N;;;;; +1B283;NUSHU CHARACTER-1B283;Lo;0;L;;;;;N;;;;; +1B284;NUSHU CHARACTER-1B284;Lo;0;L;;;;;N;;;;; +1B285;NUSHU CHARACTER-1B285;Lo;0;L;;;;;N;;;;; +1B286;NUSHU CHARACTER-1B286;Lo;0;L;;;;;N;;;;; +1B287;NUSHU CHARACTER-1B287;Lo;0;L;;;;;N;;;;; +1B288;NUSHU CHARACTER-1B288;Lo;0;L;;;;;N;;;;; +1B289;NUSHU CHARACTER-1B289;Lo;0;L;;;;;N;;;;; +1B28A;NUSHU CHARACTER-1B28A;Lo;0;L;;;;;N;;;;; +1B28B;NUSHU CHARACTER-1B28B;Lo;0;L;;;;;N;;;;; +1B28C;NUSHU CHARACTER-1B28C;Lo;0;L;;;;;N;;;;; +1B28D;NUSHU CHARACTER-1B28D;Lo;0;L;;;;;N;;;;; +1B28E;NUSHU CHARACTER-1B28E;Lo;0;L;;;;;N;;;;; +1B28F;NUSHU CHARACTER-1B28F;Lo;0;L;;;;;N;;;;; +1B290;NUSHU CHARACTER-1B290;Lo;0;L;;;;;N;;;;; +1B291;NUSHU CHARACTER-1B291;Lo;0;L;;;;;N;;;;; +1B292;NUSHU CHARACTER-1B292;Lo;0;L;;;;;N;;;;; +1B293;NUSHU CHARACTER-1B293;Lo;0;L;;;;;N;;;;; +1B294;NUSHU CHARACTER-1B294;Lo;0;L;;;;;N;;;;; +1B295;NUSHU CHARACTER-1B295;Lo;0;L;;;;;N;;;;; +1B296;NUSHU CHARACTER-1B296;Lo;0;L;;;;;N;;;;; +1B297;NUSHU CHARACTER-1B297;Lo;0;L;;;;;N;;;;; +1B298;NUSHU CHARACTER-1B298;Lo;0;L;;;;;N;;;;; +1B299;NUSHU CHARACTER-1B299;Lo;0;L;;;;;N;;;;; +1B29A;NUSHU CHARACTER-1B29A;Lo;0;L;;;;;N;;;;; +1B29B;NUSHU CHARACTER-1B29B;Lo;0;L;;;;;N;;;;; +1B29C;NUSHU CHARACTER-1B29C;Lo;0;L;;;;;N;;;;; +1B29D;NUSHU CHARACTER-1B29D;Lo;0;L;;;;;N;;;;; +1B29E;NUSHU CHARACTER-1B29E;Lo;0;L;;;;;N;;;;; +1B29F;NUSHU CHARACTER-1B29F;Lo;0;L;;;;;N;;;;; +1B2A0;NUSHU CHARACTER-1B2A0;Lo;0;L;;;;;N;;;;; +1B2A1;NUSHU CHARACTER-1B2A1;Lo;0;L;;;;;N;;;;; +1B2A2;NUSHU CHARACTER-1B2A2;Lo;0;L;;;;;N;;;;; +1B2A3;NUSHU CHARACTER-1B2A3;Lo;0;L;;;;;N;;;;; +1B2A4;NUSHU CHARACTER-1B2A4;Lo;0;L;;;;;N;;;;; +1B2A5;NUSHU CHARACTER-1B2A5;Lo;0;L;;;;;N;;;;; +1B2A6;NUSHU CHARACTER-1B2A6;Lo;0;L;;;;;N;;;;; +1B2A7;NUSHU CHARACTER-1B2A7;Lo;0;L;;;;;N;;;;; +1B2A8;NUSHU CHARACTER-1B2A8;Lo;0;L;;;;;N;;;;; +1B2A9;NUSHU CHARACTER-1B2A9;Lo;0;L;;;;;N;;;;; +1B2AA;NUSHU CHARACTER-1B2AA;Lo;0;L;;;;;N;;;;; +1B2AB;NUSHU CHARACTER-1B2AB;Lo;0;L;;;;;N;;;;; +1B2AC;NUSHU CHARACTER-1B2AC;Lo;0;L;;;;;N;;;;; +1B2AD;NUSHU CHARACTER-1B2AD;Lo;0;L;;;;;N;;;;; +1B2AE;NUSHU CHARACTER-1B2AE;Lo;0;L;;;;;N;;;;; +1B2AF;NUSHU CHARACTER-1B2AF;Lo;0;L;;;;;N;;;;; +1B2B0;NUSHU CHARACTER-1B2B0;Lo;0;L;;;;;N;;;;; +1B2B1;NUSHU CHARACTER-1B2B1;Lo;0;L;;;;;N;;;;; +1B2B2;NUSHU CHARACTER-1B2B2;Lo;0;L;;;;;N;;;;; +1B2B3;NUSHU CHARACTER-1B2B3;Lo;0;L;;;;;N;;;;; +1B2B4;NUSHU CHARACTER-1B2B4;Lo;0;L;;;;;N;;;;; +1B2B5;NUSHU CHARACTER-1B2B5;Lo;0;L;;;;;N;;;;; +1B2B6;NUSHU CHARACTER-1B2B6;Lo;0;L;;;;;N;;;;; +1B2B7;NUSHU CHARACTER-1B2B7;Lo;0;L;;;;;N;;;;; +1B2B8;NUSHU CHARACTER-1B2B8;Lo;0;L;;;;;N;;;;; +1B2B9;NUSHU CHARACTER-1B2B9;Lo;0;L;;;;;N;;;;; +1B2BA;NUSHU CHARACTER-1B2BA;Lo;0;L;;;;;N;;;;; +1B2BB;NUSHU CHARACTER-1B2BB;Lo;0;L;;;;;N;;;;; +1B2BC;NUSHU CHARACTER-1B2BC;Lo;0;L;;;;;N;;;;; +1B2BD;NUSHU CHARACTER-1B2BD;Lo;0;L;;;;;N;;;;; +1B2BE;NUSHU CHARACTER-1B2BE;Lo;0;L;;;;;N;;;;; +1B2BF;NUSHU CHARACTER-1B2BF;Lo;0;L;;;;;N;;;;; +1B2C0;NUSHU CHARACTER-1B2C0;Lo;0;L;;;;;N;;;;; +1B2C1;NUSHU CHARACTER-1B2C1;Lo;0;L;;;;;N;;;;; +1B2C2;NUSHU CHARACTER-1B2C2;Lo;0;L;;;;;N;;;;; +1B2C3;NUSHU CHARACTER-1B2C3;Lo;0;L;;;;;N;;;;; +1B2C4;NUSHU CHARACTER-1B2C4;Lo;0;L;;;;;N;;;;; +1B2C5;NUSHU CHARACTER-1B2C5;Lo;0;L;;;;;N;;;;; +1B2C6;NUSHU CHARACTER-1B2C6;Lo;0;L;;;;;N;;;;; +1B2C7;NUSHU CHARACTER-1B2C7;Lo;0;L;;;;;N;;;;; +1B2C8;NUSHU CHARACTER-1B2C8;Lo;0;L;;;;;N;;;;; +1B2C9;NUSHU CHARACTER-1B2C9;Lo;0;L;;;;;N;;;;; +1B2CA;NUSHU CHARACTER-1B2CA;Lo;0;L;;;;;N;;;;; +1B2CB;NUSHU CHARACTER-1B2CB;Lo;0;L;;;;;N;;;;; +1B2CC;NUSHU CHARACTER-1B2CC;Lo;0;L;;;;;N;;;;; +1B2CD;NUSHU CHARACTER-1B2CD;Lo;0;L;;;;;N;;;;; +1B2CE;NUSHU CHARACTER-1B2CE;Lo;0;L;;;;;N;;;;; +1B2CF;NUSHU CHARACTER-1B2CF;Lo;0;L;;;;;N;;;;; +1B2D0;NUSHU CHARACTER-1B2D0;Lo;0;L;;;;;N;;;;; +1B2D1;NUSHU CHARACTER-1B2D1;Lo;0;L;;;;;N;;;;; +1B2D2;NUSHU CHARACTER-1B2D2;Lo;0;L;;;;;N;;;;; +1B2D3;NUSHU CHARACTER-1B2D3;Lo;0;L;;;;;N;;;;; +1B2D4;NUSHU CHARACTER-1B2D4;Lo;0;L;;;;;N;;;;; +1B2D5;NUSHU CHARACTER-1B2D5;Lo;0;L;;;;;N;;;;; +1B2D6;NUSHU CHARACTER-1B2D6;Lo;0;L;;;;;N;;;;; +1B2D7;NUSHU CHARACTER-1B2D7;Lo;0;L;;;;;N;;;;; +1B2D8;NUSHU CHARACTER-1B2D8;Lo;0;L;;;;;N;;;;; +1B2D9;NUSHU CHARACTER-1B2D9;Lo;0;L;;;;;N;;;;; +1B2DA;NUSHU CHARACTER-1B2DA;Lo;0;L;;;;;N;;;;; +1B2DB;NUSHU CHARACTER-1B2DB;Lo;0;L;;;;;N;;;;; +1B2DC;NUSHU CHARACTER-1B2DC;Lo;0;L;;;;;N;;;;; +1B2DD;NUSHU CHARACTER-1B2DD;Lo;0;L;;;;;N;;;;; +1B2DE;NUSHU CHARACTER-1B2DE;Lo;0;L;;;;;N;;;;; +1B2DF;NUSHU CHARACTER-1B2DF;Lo;0;L;;;;;N;;;;; +1B2E0;NUSHU CHARACTER-1B2E0;Lo;0;L;;;;;N;;;;; +1B2E1;NUSHU CHARACTER-1B2E1;Lo;0;L;;;;;N;;;;; +1B2E2;NUSHU CHARACTER-1B2E2;Lo;0;L;;;;;N;;;;; +1B2E3;NUSHU CHARACTER-1B2E3;Lo;0;L;;;;;N;;;;; +1B2E4;NUSHU CHARACTER-1B2E4;Lo;0;L;;;;;N;;;;; +1B2E5;NUSHU CHARACTER-1B2E5;Lo;0;L;;;;;N;;;;; +1B2E6;NUSHU CHARACTER-1B2E6;Lo;0;L;;;;;N;;;;; +1B2E7;NUSHU CHARACTER-1B2E7;Lo;0;L;;;;;N;;;;; +1B2E8;NUSHU CHARACTER-1B2E8;Lo;0;L;;;;;N;;;;; +1B2E9;NUSHU CHARACTER-1B2E9;Lo;0;L;;;;;N;;;;; +1B2EA;NUSHU CHARACTER-1B2EA;Lo;0;L;;;;;N;;;;; +1B2EB;NUSHU CHARACTER-1B2EB;Lo;0;L;;;;;N;;;;; +1B2EC;NUSHU CHARACTER-1B2EC;Lo;0;L;;;;;N;;;;; +1B2ED;NUSHU CHARACTER-1B2ED;Lo;0;L;;;;;N;;;;; +1B2EE;NUSHU CHARACTER-1B2EE;Lo;0;L;;;;;N;;;;; +1B2EF;NUSHU CHARACTER-1B2EF;Lo;0;L;;;;;N;;;;; +1B2F0;NUSHU CHARACTER-1B2F0;Lo;0;L;;;;;N;;;;; +1B2F1;NUSHU CHARACTER-1B2F1;Lo;0;L;;;;;N;;;;; +1B2F2;NUSHU CHARACTER-1B2F2;Lo;0;L;;;;;N;;;;; +1B2F3;NUSHU CHARACTER-1B2F3;Lo;0;L;;;;;N;;;;; +1B2F4;NUSHU CHARACTER-1B2F4;Lo;0;L;;;;;N;;;;; +1B2F5;NUSHU CHARACTER-1B2F5;Lo;0;L;;;;;N;;;;; +1B2F6;NUSHU CHARACTER-1B2F6;Lo;0;L;;;;;N;;;;; +1B2F7;NUSHU CHARACTER-1B2F7;Lo;0;L;;;;;N;;;;; +1B2F8;NUSHU CHARACTER-1B2F8;Lo;0;L;;;;;N;;;;; +1B2F9;NUSHU CHARACTER-1B2F9;Lo;0;L;;;;;N;;;;; +1B2FA;NUSHU CHARACTER-1B2FA;Lo;0;L;;;;;N;;;;; +1B2FB;NUSHU CHARACTER-1B2FB;Lo;0;L;;;;;N;;;;; 1BC00;DUPLOYAN LETTER H;Lo;0;L;;;;;N;;;;; 1BC01;DUPLOYAN LETTER X;Lo;0;L;;;;;N;;;;; 1BC02;DUPLOYAN LETTER P;Lo;0;L;;;;;N;;;;; @@ -26154,6 +28261,44 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1DAAD;SIGNWRITING ROTATION MODIFIER-14;Mn;0;NSM;;;;;N;;;;; 1DAAE;SIGNWRITING ROTATION MODIFIER-15;Mn;0;NSM;;;;;N;;;;; 1DAAF;SIGNWRITING ROTATION MODIFIER-16;Mn;0;NSM;;;;;N;;;;; +1E000;COMBINING GLAGOLITIC LETTER AZU;Mn;230;NSM;;;;;N;;;;; +1E001;COMBINING GLAGOLITIC LETTER BUKY;Mn;230;NSM;;;;;N;;;;; +1E002;COMBINING GLAGOLITIC LETTER VEDE;Mn;230;NSM;;;;;N;;;;; +1E003;COMBINING GLAGOLITIC LETTER GLAGOLI;Mn;230;NSM;;;;;N;;;;; +1E004;COMBINING GLAGOLITIC LETTER DOBRO;Mn;230;NSM;;;;;N;;;;; +1E005;COMBINING GLAGOLITIC LETTER YESTU;Mn;230;NSM;;;;;N;;;;; +1E006;COMBINING GLAGOLITIC LETTER ZHIVETE;Mn;230;NSM;;;;;N;;;;; +1E008;COMBINING GLAGOLITIC LETTER ZEMLJA;Mn;230;NSM;;;;;N;;;;; +1E009;COMBINING GLAGOLITIC LETTER IZHE;Mn;230;NSM;;;;;N;;;;; +1E00A;COMBINING GLAGOLITIC LETTER INITIAL IZHE;Mn;230;NSM;;;;;N;;;;; +1E00B;COMBINING GLAGOLITIC LETTER I;Mn;230;NSM;;;;;N;;;;; +1E00C;COMBINING GLAGOLITIC LETTER DJERVI;Mn;230;NSM;;;;;N;;;;; +1E00D;COMBINING GLAGOLITIC LETTER KAKO;Mn;230;NSM;;;;;N;;;;; +1E00E;COMBINING GLAGOLITIC LETTER LJUDIJE;Mn;230;NSM;;;;;N;;;;; +1E00F;COMBINING GLAGOLITIC LETTER MYSLITE;Mn;230;NSM;;;;;N;;;;; +1E010;COMBINING GLAGOLITIC LETTER NASHI;Mn;230;NSM;;;;;N;;;;; +1E011;COMBINING GLAGOLITIC LETTER ONU;Mn;230;NSM;;;;;N;;;;; +1E012;COMBINING GLAGOLITIC LETTER POKOJI;Mn;230;NSM;;;;;N;;;;; +1E013;COMBINING GLAGOLITIC LETTER RITSI;Mn;230;NSM;;;;;N;;;;; +1E014;COMBINING GLAGOLITIC LETTER SLOVO;Mn;230;NSM;;;;;N;;;;; +1E015;COMBINING GLAGOLITIC LETTER TVRIDO;Mn;230;NSM;;;;;N;;;;; +1E016;COMBINING GLAGOLITIC LETTER UKU;Mn;230;NSM;;;;;N;;;;; +1E017;COMBINING GLAGOLITIC LETTER FRITU;Mn;230;NSM;;;;;N;;;;; +1E018;COMBINING GLAGOLITIC LETTER HERU;Mn;230;NSM;;;;;N;;;;; +1E01B;COMBINING GLAGOLITIC LETTER SHTA;Mn;230;NSM;;;;;N;;;;; +1E01C;COMBINING GLAGOLITIC LETTER TSI;Mn;230;NSM;;;;;N;;;;; +1E01D;COMBINING GLAGOLITIC LETTER CHRIVI;Mn;230;NSM;;;;;N;;;;; +1E01E;COMBINING GLAGOLITIC LETTER SHA;Mn;230;NSM;;;;;N;;;;; +1E01F;COMBINING GLAGOLITIC LETTER YERU;Mn;230;NSM;;;;;N;;;;; +1E020;COMBINING GLAGOLITIC LETTER YERI;Mn;230;NSM;;;;;N;;;;; +1E021;COMBINING GLAGOLITIC LETTER YATI;Mn;230;NSM;;;;;N;;;;; +1E023;COMBINING GLAGOLITIC LETTER YU;Mn;230;NSM;;;;;N;;;;; +1E024;COMBINING GLAGOLITIC LETTER SMALL YUS;Mn;230;NSM;;;;;N;;;;; +1E026;COMBINING GLAGOLITIC LETTER YO;Mn;230;NSM;;;;;N;;;;; +1E027;COMBINING GLAGOLITIC LETTER IOTATED SMALL YUS;Mn;230;NSM;;;;;N;;;;; +1E028;COMBINING GLAGOLITIC LETTER BIG YUS;Mn;230;NSM;;;;;N;;;;; +1E029;COMBINING GLAGOLITIC LETTER IOTATED BIG YUS;Mn;230;NSM;;;;;N;;;;; +1E02A;COMBINING GLAGOLITIC LETTER FITA;Mn;230;NSM;;;;;N;;;;; 1E800;MENDE KIKAKUI SYLLABLE M001 KI;Lo;0;R;;;;;N;;;;; 1E801;MENDE KIKAKUI SYLLABLE M002 KA;Lo;0;R;;;;;N;;;;; 1E802;MENDE KIKAKUI SYLLABLE M003 KU;Lo;0;R;;;;;N;;;;; @@ -26367,6 +28512,93 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1E8D4;MENDE KIKAKUI COMBINING NUMBER TEN THOUSANDS;Mn;220;NSM;;;;;N;;;;; 1E8D5;MENDE KIKAKUI COMBINING NUMBER HUNDRED THOUSANDS;Mn;220;NSM;;;;;N;;;;; 1E8D6;MENDE KIKAKUI COMBINING NUMBER MILLIONS;Mn;220;NSM;;;;;N;;;;; +1E900;ADLAM CAPITAL LETTER ALIF;Lu;0;R;;;;;N;;;;1E922; +1E901;ADLAM CAPITAL LETTER DAALI;Lu;0;R;;;;;N;;;;1E923; +1E902;ADLAM CAPITAL LETTER LAAM;Lu;0;R;;;;;N;;;;1E924; +1E903;ADLAM CAPITAL LETTER MIIM;Lu;0;R;;;;;N;;;;1E925; +1E904;ADLAM CAPITAL LETTER BA;Lu;0;R;;;;;N;;;;1E926; +1E905;ADLAM CAPITAL LETTER SINNYIIYHE;Lu;0;R;;;;;N;;;;1E927; +1E906;ADLAM CAPITAL LETTER PE;Lu;0;R;;;;;N;;;;1E928; +1E907;ADLAM CAPITAL LETTER BHE;Lu;0;R;;;;;N;;;;1E929; +1E908;ADLAM CAPITAL LETTER RA;Lu;0;R;;;;;N;;;;1E92A; +1E909;ADLAM CAPITAL LETTER E;Lu;0;R;;;;;N;;;;1E92B; +1E90A;ADLAM CAPITAL LETTER FA;Lu;0;R;;;;;N;;;;1E92C; +1E90B;ADLAM CAPITAL LETTER I;Lu;0;R;;;;;N;;;;1E92D; +1E90C;ADLAM CAPITAL LETTER O;Lu;0;R;;;;;N;;;;1E92E; +1E90D;ADLAM CAPITAL LETTER DHA;Lu;0;R;;;;;N;;;;1E92F; +1E90E;ADLAM CAPITAL LETTER YHE;Lu;0;R;;;;;N;;;;1E930; +1E90F;ADLAM CAPITAL LETTER WAW;Lu;0;R;;;;;N;;;;1E931; +1E910;ADLAM CAPITAL LETTER NUN;Lu;0;R;;;;;N;;;;1E932; +1E911;ADLAM CAPITAL LETTER KAF;Lu;0;R;;;;;N;;;;1E933; +1E912;ADLAM CAPITAL LETTER YA;Lu;0;R;;;;;N;;;;1E934; +1E913;ADLAM CAPITAL LETTER U;Lu;0;R;;;;;N;;;;1E935; +1E914;ADLAM CAPITAL LETTER JIIM;Lu;0;R;;;;;N;;;;1E936; +1E915;ADLAM CAPITAL LETTER CHI;Lu;0;R;;;;;N;;;;1E937; +1E916;ADLAM CAPITAL LETTER HA;Lu;0;R;;;;;N;;;;1E938; +1E917;ADLAM CAPITAL LETTER QAAF;Lu;0;R;;;;;N;;;;1E939; +1E918;ADLAM CAPITAL LETTER GA;Lu;0;R;;;;;N;;;;1E93A; +1E919;ADLAM CAPITAL LETTER NYA;Lu;0;R;;;;;N;;;;1E93B; +1E91A;ADLAM CAPITAL LETTER TU;Lu;0;R;;;;;N;;;;1E93C; +1E91B;ADLAM CAPITAL LETTER NHA;Lu;0;R;;;;;N;;;;1E93D; +1E91C;ADLAM CAPITAL LETTER VA;Lu;0;R;;;;;N;;;;1E93E; +1E91D;ADLAM CAPITAL LETTER KHA;Lu;0;R;;;;;N;;;;1E93F; +1E91E;ADLAM CAPITAL LETTER GBE;Lu;0;R;;;;;N;;;;1E940; +1E91F;ADLAM CAPITAL LETTER ZAL;Lu;0;R;;;;;N;;;;1E941; +1E920;ADLAM CAPITAL LETTER KPO;Lu;0;R;;;;;N;;;;1E942; +1E921;ADLAM CAPITAL LETTER SHA;Lu;0;R;;;;;N;;;;1E943; +1E922;ADLAM SMALL LETTER ALIF;Ll;0;R;;;;;N;;;1E900;;1E900 +1E923;ADLAM SMALL LETTER DAALI;Ll;0;R;;;;;N;;;1E901;;1E901 +1E924;ADLAM SMALL LETTER LAAM;Ll;0;R;;;;;N;;;1E902;;1E902 +1E925;ADLAM SMALL LETTER MIIM;Ll;0;R;;;;;N;;;1E903;;1E903 +1E926;ADLAM SMALL LETTER BA;Ll;0;R;;;;;N;;;1E904;;1E904 +1E927;ADLAM SMALL LETTER SINNYIIYHE;Ll;0;R;;;;;N;;;1E905;;1E905 +1E928;ADLAM SMALL LETTER PE;Ll;0;R;;;;;N;;;1E906;;1E906 +1E929;ADLAM SMALL LETTER BHE;Ll;0;R;;;;;N;;;1E907;;1E907 +1E92A;ADLAM SMALL LETTER RA;Ll;0;R;;;;;N;;;1E908;;1E908 +1E92B;ADLAM SMALL LETTER E;Ll;0;R;;;;;N;;;1E909;;1E909 +1E92C;ADLAM SMALL LETTER FA;Ll;0;R;;;;;N;;;1E90A;;1E90A +1E92D;ADLAM SMALL LETTER I;Ll;0;R;;;;;N;;;1E90B;;1E90B +1E92E;ADLAM SMALL LETTER O;Ll;0;R;;;;;N;;;1E90C;;1E90C +1E92F;ADLAM SMALL LETTER DHA;Ll;0;R;;;;;N;;;1E90D;;1E90D +1E930;ADLAM SMALL LETTER YHE;Ll;0;R;;;;;N;;;1E90E;;1E90E +1E931;ADLAM SMALL LETTER WAW;Ll;0;R;;;;;N;;;1E90F;;1E90F +1E932;ADLAM SMALL LETTER NUN;Ll;0;R;;;;;N;;;1E910;;1E910 +1E933;ADLAM SMALL LETTER KAF;Ll;0;R;;;;;N;;;1E911;;1E911 +1E934;ADLAM SMALL LETTER YA;Ll;0;R;;;;;N;;;1E912;;1E912 +1E935;ADLAM SMALL LETTER U;Ll;0;R;;;;;N;;;1E913;;1E913 +1E936;ADLAM SMALL LETTER JIIM;Ll;0;R;;;;;N;;;1E914;;1E914 +1E937;ADLAM SMALL LETTER CHI;Ll;0;R;;;;;N;;;1E915;;1E915 +1E938;ADLAM SMALL LETTER HA;Ll;0;R;;;;;N;;;1E916;;1E916 +1E939;ADLAM SMALL LETTER QAAF;Ll;0;R;;;;;N;;;1E917;;1E917 +1E93A;ADLAM SMALL LETTER GA;Ll;0;R;;;;;N;;;1E918;;1E918 +1E93B;ADLAM SMALL LETTER NYA;Ll;0;R;;;;;N;;;1E919;;1E919 +1E93C;ADLAM SMALL LETTER TU;Ll;0;R;;;;;N;;;1E91A;;1E91A +1E93D;ADLAM SMALL LETTER NHA;Ll;0;R;;;;;N;;;1E91B;;1E91B +1E93E;ADLAM SMALL LETTER VA;Ll;0;R;;;;;N;;;1E91C;;1E91C +1E93F;ADLAM SMALL LETTER KHA;Ll;0;R;;;;;N;;;1E91D;;1E91D +1E940;ADLAM SMALL LETTER GBE;Ll;0;R;;;;;N;;;1E91E;;1E91E +1E941;ADLAM SMALL LETTER ZAL;Ll;0;R;;;;;N;;;1E91F;;1E91F +1E942;ADLAM SMALL LETTER KPO;Ll;0;R;;;;;N;;;1E920;;1E920 +1E943;ADLAM SMALL LETTER SHA;Ll;0;R;;;;;N;;;1E921;;1E921 +1E944;ADLAM ALIF LENGTHENER;Mn;230;NSM;;;;;N;;;;; +1E945;ADLAM VOWEL LENGTHENER;Mn;230;NSM;;;;;N;;;;; +1E946;ADLAM GEMINATION MARK;Mn;230;NSM;;;;;N;;;;; +1E947;ADLAM HAMZA;Mn;230;NSM;;;;;N;;;;; +1E948;ADLAM CONSONANT MODIFIER;Mn;230;NSM;;;;;N;;;;; +1E949;ADLAM GEMINATE CONSONANT MODIFIER;Mn;230;NSM;;;;;N;;;;; +1E94A;ADLAM NUKTA;Mn;7;NSM;;;;;N;;;;; +1E950;ADLAM DIGIT ZERO;Nd;0;R;;0;0;0;N;;;;; +1E951;ADLAM DIGIT ONE;Nd;0;R;;1;1;1;N;;;;; +1E952;ADLAM DIGIT TWO;Nd;0;R;;2;2;2;N;;;;; +1E953;ADLAM DIGIT THREE;Nd;0;R;;3;3;3;N;;;;; +1E954;ADLAM DIGIT FOUR;Nd;0;R;;4;4;4;N;;;;; +1E955;ADLAM DIGIT FIVE;Nd;0;R;;5;5;5;N;;;;; +1E956;ADLAM DIGIT SIX;Nd;0;R;;6;6;6;N;;;;; +1E957;ADLAM DIGIT SEVEN;Nd;0;R;;7;7;7;N;;;;; +1E958;ADLAM DIGIT EIGHT;Nd;0;R;;8;8;8;N;;;;; +1E959;ADLAM DIGIT NINE;Nd;0;R;;9;9;9;N;;;;; +1E95E;ADLAM INITIAL EXCLAMATION MARK;Po;0;R;;;;;N;;;;; +1E95F;ADLAM INITIAL QUESTION MARK;Po;0;R;;;;;N;;;;; 1EE00;ARABIC MATHEMATICAL ALEF;Lo;0;AL;<font> 0627;;;;N;;;;; 1EE01;ARABIC MATHEMATICAL BEH;Lo;0;AL;<font> 0628;;;;N;;;;; 1EE02;ARABIC MATHEMATICAL JEEM;Lo;0;AL;<font> 062C;;;;N;;;;; @@ -26883,6 +29115,24 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1F198;SQUARED SOS;So;0;L;;;;;N;;;;; 1F199;SQUARED UP WITH EXCLAMATION MARK;So;0;L;;;;;N;;;;; 1F19A;SQUARED VS;So;0;L;;;;;N;;;;; +1F19B;SQUARED THREE D;So;0;L;;;;;N;;;;; +1F19C;SQUARED SECOND SCREEN;So;0;L;;;;;N;;;;; +1F19D;SQUARED TWO K;So;0;L;;;;;N;;;;; +1F19E;SQUARED FOUR K;So;0;L;;;;;N;;;;; +1F19F;SQUARED EIGHT K;So;0;L;;;;;N;;;;; +1F1A0;SQUARED FIVE POINT ONE;So;0;L;;;;;N;;;;; +1F1A1;SQUARED SEVEN POINT ONE;So;0;L;;;;;N;;;;; +1F1A2;SQUARED TWENTY-TWO POINT TWO;So;0;L;;;;;N;;;;; +1F1A3;SQUARED SIXTY P;So;0;L;;;;;N;;;;; +1F1A4;SQUARED ONE HUNDRED TWENTY P;So;0;L;;;;;N;;;;; +1F1A5;SQUARED LATIN SMALL LETTER D;So;0;L;;;;;N;;;;; +1F1A6;SQUARED HC;So;0;L;;;;;N;;;;; +1F1A7;SQUARED HDR;So;0;L;;;;;N;;;;; +1F1A8;SQUARED HI-RES;So;0;L;;;;;N;;;;; +1F1A9;SQUARED LOSSLESS;So;0;L;;;;;N;;;;; +1F1AA;SQUARED SHV;So;0;L;;;;;N;;;;; +1F1AB;SQUARED UHD;So;0;L;;;;;N;;;;; +1F1AC;SQUARED VOD;So;0;L;;;;;N;;;;; 1F1E6;REGIONAL INDICATOR SYMBOL LETTER A;So;0;L;;;;;N;;;;; 1F1E7;REGIONAL INDICATOR SYMBOL LETTER B;So;0;L;;;;;N;;;;; 1F1E8;REGIONAL INDICATOR SYMBOL LETTER C;So;0;L;;;;;N;;;;; @@ -26955,6 +29205,7 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1F238;SQUARED CJK UNIFIED IDEOGRAPH-7533;So;0;L;<square> 7533;;;;N;;;;; 1F239;SQUARED CJK UNIFIED IDEOGRAPH-5272;So;0;L;<square> 5272;;;;N;;;;; 1F23A;SQUARED CJK UNIFIED IDEOGRAPH-55B6;So;0;L;<square> 55B6;;;;N;;;;; +1F23B;SQUARED CJK UNIFIED IDEOGRAPH-914D;So;0;L;<square> 914D;;;;N;;;;; 1F240;TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-672C;So;0;L;<compat> 3014 672C 3015;;;;N;;;;; 1F241;TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-4E09;So;0;L;<compat> 3014 4E09 3015;;;;N;;;;; 1F242;TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-4E8C;So;0;L;<compat> 3014 4E8C 3015;;;;N;;;;; @@ -26966,6 +29217,12 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1F248;TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-6557;So;0;L;<compat> 3014 6557 3015;;;;N;;;;; 1F250;CIRCLED IDEOGRAPH ADVANTAGE;So;0;L;<circle> 5F97;;;;N;;;;; 1F251;CIRCLED IDEOGRAPH ACCEPT;So;0;L;<circle> 53EF;;;;N;;;;; +1F260;ROUNDED SYMBOL FOR FU;So;0;ON;;;;;N;;;;; +1F261;ROUNDED SYMBOL FOR LU;So;0;ON;;;;;N;;;;; +1F262;ROUNDED SYMBOL FOR SHOU;So;0;ON;;;;;N;;;;; +1F263;ROUNDED SYMBOL FOR XI;So;0;ON;;;;;N;;;;; +1F264;ROUNDED SYMBOL FOR SHUANGXI;So;0;ON;;;;;N;;;;; +1F265;ROUNDED SYMBOL FOR CAI;So;0;ON;;;;;N;;;;; 1F300;CYCLONE;So;0;ON;;;;;N;;;;; 1F301;FOGGY;So;0;ON;;;;;N;;;;; 1F302;CLOSED UMBRELLA;So;0;ON;;;;;N;;;;; @@ -27600,6 +29857,7 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1F577;SPIDER;So;0;ON;;;;;N;;;;; 1F578;SPIDER WEB;So;0;ON;;;;;N;;;;; 1F579;JOYSTICK;So;0;ON;;;;;N;;;;; +1F57A;MAN DANCING;So;0;ON;;;;;N;;;;; 1F57B;LEFT HAND TELEPHONE RECEIVER;So;0;ON;;;;;N;;;;; 1F57C;TELEPHONE RECEIVER WITH PAGE;So;0;ON;;;;;N;;;;; 1F57D;RIGHT HAND TELEPHONE RECEIVER;So;0;ON;;;;;N;;;;; @@ -27641,6 +29899,7 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1F5A1;SIDEWAYS BLACK DOWN POINTING INDEX;So;0;ON;;;;;N;;;;; 1F5A2;BLACK UP POINTING BACKHAND INDEX;So;0;ON;;;;;N;;;;; 1F5A3;BLACK DOWN POINTING BACKHAND INDEX;So;0;ON;;;;;N;;;;; +1F5A4;BLACK HEART;So;0;ON;;;;;N;;;;; 1F5A5;DESKTOP COMPUTER;So;0;ON;;;;;N;;;;; 1F5A6;KEYBOARD AND MOUSE;So;0;ON;;;;;N;;;;; 1F5A7;THREE NETWORKED COMPUTERS;So;0;ON;;;;;N;;;;; @@ -27941,6 +30200,10 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1F6CE;BELLHOP BELL;So;0;ON;;;;;N;;;;; 1F6CF;BED;So;0;ON;;;;;N;;;;; 1F6D0;PLACE OF WORSHIP;So;0;ON;;;;;N;;;;; +1F6D1;OCTAGONAL SIGN;So;0;ON;;;;;N;;;;; +1F6D2;SHOPPING TROLLEY;So;0;ON;;;;;N;;;;; +1F6D3;STUPA;So;0;ON;;;;;N;;;;; +1F6D4;PAGODA;So;0;ON;;;;;N;;;;; 1F6E0;HAMMER AND WRENCH;So;0;ON;;;;;N;;;;; 1F6E1;SHIELD;So;0;ON;;;;;N;;;;; 1F6E2;OIL DRUM;So;0;ON;;;;;N;;;;; @@ -27958,6 +30221,11 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1F6F1;ONCOMING FIRE ENGINE;So;0;ON;;;;;N;;;;; 1F6F2;DIESEL LOCOMOTIVE;So;0;ON;;;;;N;;;;; 1F6F3;PASSENGER SHIP;So;0;ON;;;;;N;;;;; +1F6F4;SCOOTER;So;0;ON;;;;;N;;;;; +1F6F5;MOTOR SCOOTER;So;0;ON;;;;;N;;;;; +1F6F6;CANOE;So;0;ON;;;;;N;;;;; +1F6F7;SLED;So;0;ON;;;;;N;;;;; +1F6F8;FLYING SAUCER;So;0;ON;;;;;N;;;;; 1F700;ALCHEMICAL SYMBOL FOR QUINTESSENCE;So;0;ON;;;;;N;;;;; 1F701;ALCHEMICAL SYMBOL FOR AIR;So;0;ON;;;;;N;;;;; 1F702;ALCHEMICAL SYMBOL FOR FIRE;So;0;ON;;;;;N;;;;; @@ -28307,6 +30575,18 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1F8AB;RIGHTWARDS FRONT-TILTED SHADOWED WHITE ARROW;So;0;ON;;;;;N;;;;; 1F8AC;WHITE ARROW SHAFT WIDTH ONE;So;0;ON;;;;;N;;;;; 1F8AD;WHITE ARROW SHAFT WIDTH TWO THIRDS;So;0;ON;;;;;N;;;;; +1F900;CIRCLED CROSS FORMEE WITH FOUR DOTS;So;0;ON;;;;;N;;;;; +1F901;CIRCLED CROSS FORMEE WITH TWO DOTS;So;0;ON;;;;;N;;;;; +1F902;CIRCLED CROSS FORMEE;So;0;ON;;;;;N;;;;; +1F903;LEFT HALF CIRCLE WITH FOUR DOTS;So;0;ON;;;;;N;;;;; +1F904;LEFT HALF CIRCLE WITH THREE DOTS;So;0;ON;;;;;N;;;;; +1F905;LEFT HALF CIRCLE WITH TWO DOTS;So;0;ON;;;;;N;;;;; +1F906;LEFT HALF CIRCLE WITH DOT;So;0;ON;;;;;N;;;;; +1F907;LEFT HALF CIRCLE;So;0;ON;;;;;N;;;;; +1F908;DOWNWARD FACING HOOK;So;0;ON;;;;;N;;;;; +1F909;DOWNWARD FACING NOTCHED HOOK;So;0;ON;;;;;N;;;;; +1F90A;DOWNWARD FACING HOOK WITH DOT;So;0;ON;;;;;N;;;;; +1F90B;DOWNWARD FACING NOTCHED HOOK WITH DOT;So;0;ON;;;;;N;;;;; 1F910;ZIPPER-MOUTH FACE;So;0;ON;;;;;N;;;;; 1F911;MONEY-MOUTH FACE;So;0;ON;;;;;N;;;;; 1F912;FACE WITH THERMOMETER;So;0;ON;;;;;N;;;;; @@ -28316,12 +30596,133 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 1F916;ROBOT FACE;So;0;ON;;;;;N;;;;; 1F917;HUGGING FACE;So;0;ON;;;;;N;;;;; 1F918;SIGN OF THE HORNS;So;0;ON;;;;;N;;;;; +1F919;CALL ME HAND;So;0;ON;;;;;N;;;;; +1F91A;RAISED BACK OF HAND;So;0;ON;;;;;N;;;;; +1F91B;LEFT-FACING FIST;So;0;ON;;;;;N;;;;; +1F91C;RIGHT-FACING FIST;So;0;ON;;;;;N;;;;; +1F91D;HANDSHAKE;So;0;ON;;;;;N;;;;; +1F91E;HAND WITH INDEX AND MIDDLE FINGERS CROSSED;So;0;ON;;;;;N;;;;; +1F91F;I LOVE YOU HAND SIGN;So;0;ON;;;;;N;;;;; +1F920;FACE WITH COWBOY HAT;So;0;ON;;;;;N;;;;; +1F921;CLOWN FACE;So;0;ON;;;;;N;;;;; +1F922;NAUSEATED FACE;So;0;ON;;;;;N;;;;; +1F923;ROLLING ON THE FLOOR LAUGHING;So;0;ON;;;;;N;;;;; +1F924;DROOLING FACE;So;0;ON;;;;;N;;;;; +1F925;LYING FACE;So;0;ON;;;;;N;;;;; +1F926;FACE PALM;So;0;ON;;;;;N;;;;; +1F927;SNEEZING FACE;So;0;ON;;;;;N;;;;; +1F928;FACE WITH ONE EYEBROW RAISED;So;0;ON;;;;;N;;;;; +1F929;GRINNING FACE WITH STAR EYES;So;0;ON;;;;;N;;;;; +1F92A;GRINNING FACE WITH ONE LARGE AND ONE SMALL EYE;So;0;ON;;;;;N;;;;; +1F92B;FACE WITH FINGER COVERING CLOSED LIPS;So;0;ON;;;;;N;;;;; +1F92C;SERIOUS FACE WITH SYMBOLS COVERING MOUTH;So;0;ON;;;;;N;;;;; +1F92D;SMILING FACE WITH SMILING EYES AND HAND COVERING MOUTH;So;0;ON;;;;;N;;;;; +1F92E;FACE WITH OPEN MOUTH VOMITING;So;0;ON;;;;;N;;;;; +1F92F;SHOCKED FACE WITH EXPLODING HEAD;So;0;ON;;;;;N;;;;; +1F930;PREGNANT WOMAN;So;0;ON;;;;;N;;;;; +1F931;BREAST-FEEDING;So;0;ON;;;;;N;;;;; +1F932;PALMS UP TOGETHER;So;0;ON;;;;;N;;;;; +1F933;SELFIE;So;0;ON;;;;;N;;;;; +1F934;PRINCE;So;0;ON;;;;;N;;;;; +1F935;MAN IN TUXEDO;So;0;ON;;;;;N;;;;; +1F936;MOTHER CHRISTMAS;So;0;ON;;;;;N;;;;; +1F937;SHRUG;So;0;ON;;;;;N;;;;; +1F938;PERSON DOING CARTWHEEL;So;0;ON;;;;;N;;;;; +1F939;JUGGLING;So;0;ON;;;;;N;;;;; +1F93A;FENCER;So;0;ON;;;;;N;;;;; +1F93B;MODERN PENTATHLON;So;0;ON;;;;;N;;;;; +1F93C;WRESTLERS;So;0;ON;;;;;N;;;;; +1F93D;WATER POLO;So;0;ON;;;;;N;;;;; +1F93E;HANDBALL;So;0;ON;;;;;N;;;;; +1F940;WILTED FLOWER;So;0;ON;;;;;N;;;;; +1F941;DRUM WITH DRUMSTICKS;So;0;ON;;;;;N;;;;; +1F942;CLINKING GLASSES;So;0;ON;;;;;N;;;;; +1F943;TUMBLER GLASS;So;0;ON;;;;;N;;;;; +1F944;SPOON;So;0;ON;;;;;N;;;;; +1F945;GOAL NET;So;0;ON;;;;;N;;;;; +1F946;RIFLE;So;0;ON;;;;;N;;;;; +1F947;FIRST PLACE MEDAL;So;0;ON;;;;;N;;;;; +1F948;SECOND PLACE MEDAL;So;0;ON;;;;;N;;;;; +1F949;THIRD PLACE MEDAL;So;0;ON;;;;;N;;;;; +1F94A;BOXING GLOVE;So;0;ON;;;;;N;;;;; +1F94B;MARTIAL ARTS UNIFORM;So;0;ON;;;;;N;;;;; +1F94C;CURLING STONE;So;0;ON;;;;;N;;;;; +1F950;CROISSANT;So;0;ON;;;;;N;;;;; +1F951;AVOCADO;So;0;ON;;;;;N;;;;; +1F952;CUCUMBER;So;0;ON;;;;;N;;;;; +1F953;BACON;So;0;ON;;;;;N;;;;; +1F954;POTATO;So;0;ON;;;;;N;;;;; +1F955;CARROT;So;0;ON;;;;;N;;;;; +1F956;BAGUETTE BREAD;So;0;ON;;;;;N;;;;; +1F957;GREEN SALAD;So;0;ON;;;;;N;;;;; +1F958;SHALLOW PAN OF FOOD;So;0;ON;;;;;N;;;;; +1F959;STUFFED FLATBREAD;So;0;ON;;;;;N;;;;; +1F95A;EGG;So;0;ON;;;;;N;;;;; +1F95B;GLASS OF MILK;So;0;ON;;;;;N;;;;; +1F95C;PEANUTS;So;0;ON;;;;;N;;;;; +1F95D;KIWIFRUIT;So;0;ON;;;;;N;;;;; +1F95E;PANCAKES;So;0;ON;;;;;N;;;;; +1F95F;DUMPLING;So;0;ON;;;;;N;;;;; +1F960;FORTUNE COOKIE;So;0;ON;;;;;N;;;;; +1F961;TAKEOUT BOX;So;0;ON;;;;;N;;;;; +1F962;CHOPSTICKS;So;0;ON;;;;;N;;;;; +1F963;BOWL WITH SPOON;So;0;ON;;;;;N;;;;; +1F964;CUP WITH STRAW;So;0;ON;;;;;N;;;;; +1F965;COCONUT;So;0;ON;;;;;N;;;;; +1F966;BROCCOLI;So;0;ON;;;;;N;;;;; +1F967;PIE;So;0;ON;;;;;N;;;;; +1F968;PRETZEL;So;0;ON;;;;;N;;;;; +1F969;CUT OF MEAT;So;0;ON;;;;;N;;;;; +1F96A;SANDWICH;So;0;ON;;;;;N;;;;; +1F96B;CANNED FOOD;So;0;ON;;;;;N;;;;; 1F980;CRAB;So;0;ON;;;;;N;;;;; 1F981;LION FACE;So;0;ON;;;;;N;;;;; 1F982;SCORPION;So;0;ON;;;;;N;;;;; 1F983;TURKEY;So;0;ON;;;;;N;;;;; 1F984;UNICORN FACE;So;0;ON;;;;;N;;;;; +1F985;EAGLE;So;0;ON;;;;;N;;;;; +1F986;DUCK;So;0;ON;;;;;N;;;;; +1F987;BAT;So;0;ON;;;;;N;;;;; +1F988;SHARK;So;0;ON;;;;;N;;;;; +1F989;OWL;So;0;ON;;;;;N;;;;; +1F98A;FOX FACE;So;0;ON;;;;;N;;;;; +1F98B;BUTTERFLY;So;0;ON;;;;;N;;;;; +1F98C;DEER;So;0;ON;;;;;N;;;;; +1F98D;GORILLA;So;0;ON;;;;;N;;;;; +1F98E;LIZARD;So;0;ON;;;;;N;;;;; +1F98F;RHINOCEROS;So;0;ON;;;;;N;;;;; +1F990;SHRIMP;So;0;ON;;;;;N;;;;; +1F991;SQUID;So;0;ON;;;;;N;;;;; +1F992;GIRAFFE FACE;So;0;ON;;;;;N;;;;; +1F993;ZEBRA FACE;So;0;ON;;;;;N;;;;; +1F994;HEDGEHOG;So;0;ON;;;;;N;;;;; +1F995;SAUROPOD;So;0;ON;;;;;N;;;;; +1F996;T-REX;So;0;ON;;;;;N;;;;; +1F997;CRICKET;So;0;ON;;;;;N;;;;; 1F9C0;CHEESE WEDGE;So;0;ON;;;;;N;;;;; +1F9D0;FACE WITH MONOCLE;So;0;ON;;;;;N;;;;; +1F9D1;ADULT;So;0;ON;;;;;N;;;;; +1F9D2;CHILD;So;0;ON;;;;;N;;;;; +1F9D3;OLDER ADULT;So;0;ON;;;;;N;;;;; +1F9D4;BEARDED PERSON;So;0;ON;;;;;N;;;;; +1F9D5;PERSON WITH HEADSCARF;So;0;ON;;;;;N;;;;; +1F9D6;PERSON IN STEAMY ROOM;So;0;ON;;;;;N;;;;; +1F9D7;PERSON CLIMBING;So;0;ON;;;;;N;;;;; +1F9D8;PERSON IN LOTUS POSITION;So;0;ON;;;;;N;;;;; +1F9D9;MAGE;So;0;ON;;;;;N;;;;; +1F9DA;FAIRY;So;0;ON;;;;;N;;;;; +1F9DB;VAMPIRE;So;0;ON;;;;;N;;;;; +1F9DC;MERPERSON;So;0;ON;;;;;N;;;;; +1F9DD;ELF;So;0;ON;;;;;N;;;;; +1F9DE;GENIE;So;0;ON;;;;;N;;;;; +1F9DF;ZOMBIE;So;0;ON;;;;;N;;;;; +1F9E0;BRAIN;So;0;ON;;;;;N;;;;; +1F9E1;ORANGE HEART;So;0;ON;;;;;N;;;;; +1F9E2;BILLED CAP;So;0;ON;;;;;N;;;;; +1F9E3;SCARF;So;0;ON;;;;;N;;;;; +1F9E4;GLOVES;So;0;ON;;;;;N;;;;; +1F9E5;COAT;So;0;ON;;;;;N;;;;; +1F9E6;SOCKS;So;0;ON;;;;;N;;;;; 20000;<CJK Ideograph Extension B, First>;Lo;0;L;;;;;N;;;;; 2A6D6;<CJK Ideograph Extension B, Last>;Lo;0;L;;;;;N;;;;; 2A700;<CJK Ideograph Extension C, First>;Lo;0;L;;;;;N;;;;; @@ -28330,6 +30731,8 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;; 2B81D;<CJK Ideograph Extension D, Last>;Lo;0;L;;;;;N;;;;; 2B820;<CJK Ideograph Extension E, First>;Lo;0;L;;;;;N;;;;; 2CEA1;<CJK Ideograph Extension E, Last>;Lo;0;L;;;;;N;;;;; +2CEB0;<CJK Ideograph Extension F, First>;Lo;0;L;;;;;N;;;;; +2EBE0;<CJK Ideograph Extension F, Last>;Lo;0;L;;;;;N;;;;; 2F800;CJK COMPATIBILITY IDEOGRAPH-2F800;Lo;0;L;4E3D;;;;N;;;;; 2F801;CJK COMPATIBILITY IDEOGRAPH-2F801;Lo;0;L;4E38;;;;N;;;;; 2F802;CJK COMPATIBILITY IDEOGRAPH-2F802;Lo;0;L;4E41;;;;N;;;;; diff --git a/tools-for-build/allkeys.txt b/tools-for-build/allkeys.txt index a0892568c5..7cc05743c1 100644 --- a/tools-for-build/allkeys.txt +++ b/tools-for-build/allkeys.txt @@ -1,30058 +1,31329 @@ -# allkeys.txt from Unicode 8.0.0 (comments removed) -0000 ; [.0000.0000.0000] -0001 ; [.0000.0000.0000] -0002 ; [.0000.0000.0000] -0003 ; [.0000.0000.0000] -0004 ; [.0000.0000.0000] -0005 ; [.0000.0000.0000] -0006 ; [.0000.0000.0000] -0007 ; [.0000.0000.0000] -0008 ; [.0000.0000.0000] -000E ; [.0000.0000.0000] -000F ; [.0000.0000.0000] -0010 ; [.0000.0000.0000] -0011 ; [.0000.0000.0000] -0012 ; [.0000.0000.0000] -0013 ; [.0000.0000.0000] -0014 ; [.0000.0000.0000] -0015 ; [.0000.0000.0000] -0016 ; [.0000.0000.0000] -0017 ; [.0000.0000.0000] -0018 ; [.0000.0000.0000] -0019 ; [.0000.0000.0000] -001A ; [.0000.0000.0000] -001B ; [.0000.0000.0000] -001C ; [.0000.0000.0000] -001D ; [.0000.0000.0000] -001E ; [.0000.0000.0000] -001F ; [.0000.0000.0000] -007F ; [.0000.0000.0000] -0080 ; [.0000.0000.0000] -0081 ; [.0000.0000.0000] -0082 ; [.0000.0000.0000] -0083 ; [.0000.0000.0000] -0084 ; [.0000.0000.0000] -0086 ; [.0000.0000.0000] -0087 ; [.0000.0000.0000] -0088 ; [.0000.0000.0000] -0089 ; [.0000.0000.0000] -008A ; [.0000.0000.0000] -008B ; [.0000.0000.0000] -008C ; [.0000.0000.0000] -008D ; [.0000.0000.0000] -008E ; [.0000.0000.0000] -008F ; [.0000.0000.0000] -0090 ; [.0000.0000.0000] -0091 ; [.0000.0000.0000] -0092 ; [.0000.0000.0000] -0093 ; [.0000.0000.0000] -0094 ; [.0000.0000.0000] -0095 ; [.0000.0000.0000] -0096 ; [.0000.0000.0000] -0097 ; [.0000.0000.0000] -0098 ; [.0000.0000.0000] -0099 ; [.0000.0000.0000] -009A ; [.0000.0000.0000] -009B ; [.0000.0000.0000] -009C ; [.0000.0000.0000] -009D ; [.0000.0000.0000] -009E ; [.0000.0000.0000] -009F ; [.0000.0000.0000] -00AD ; [.0000.0000.0000] -061C ; [.0000.0000.0000] -070F ; [.0000.0000.0000] -180B ; [.0000.0000.0000] -180C ; [.0000.0000.0000] -180D ; [.0000.0000.0000] -180E ; [.0000.0000.0000] -200B ; [.0000.0000.0000] -200C ; [.0000.0000.0000] -200D ; [.0000.0000.0000] -200E ; [.0000.0000.0000] -200F ; [.0000.0000.0000] -202A ; [.0000.0000.0000] -202B ; [.0000.0000.0000] -202C ; [.0000.0000.0000] -202D ; [.0000.0000.0000] -202E ; [.0000.0000.0000] -2060 ; [.0000.0000.0000] -2066 ; [.0000.0000.0000] -2067 ; [.0000.0000.0000] -2068 ; [.0000.0000.0000] -2069 ; [.0000.0000.0000] -206A ; [.0000.0000.0000] -206B ; [.0000.0000.0000] -206C ; [.0000.0000.0000] -206D ; [.0000.0000.0000] -206E ; [.0000.0000.0000] -206F ; [.0000.0000.0000] -FE00 ; [.0000.0000.0000] -FE01 ; [.0000.0000.0000] -FE02 ; [.0000.0000.0000] -FE03 ; [.0000.0000.0000] -FE04 ; [.0000.0000.0000] -FE05 ; [.0000.0000.0000] -FE06 ; [.0000.0000.0000] -FE07 ; [.0000.0000.0000] -FE08 ; [.0000.0000.0000] -FE09 ; [.0000.0000.0000] -FE0A ; [.0000.0000.0000] -FE0B ; [.0000.0000.0000] -FE0C ; [.0000.0000.0000] -FE0D ; [.0000.0000.0000] -FE0E ; [.0000.0000.0000] -FE0F ; [.0000.0000.0000] -FEFF ; [.0000.0000.0000] -FFF9 ; [.0000.0000.0000] -FFFA ; [.0000.0000.0000] -FFFB ; [.0000.0000.0000] -1BCA0 ; [.0000.0000.0000] -1BCA1 ; [.0000.0000.0000] -1BCA2 ; [.0000.0000.0000] -1BCA3 ; [.0000.0000.0000] -1D173 ; [.0000.0000.0000] -1D174 ; [.0000.0000.0000] -1D175 ; [.0000.0000.0000] -1D176 ; [.0000.0000.0000] -1D177 ; [.0000.0000.0000] -1D178 ; [.0000.0000.0000] -1D179 ; [.0000.0000.0000] -1D17A ; [.0000.0000.0000] -E0001 ; [.0000.0000.0000] -E0020 ; [.0000.0000.0000] -E0021 ; [.0000.0000.0000] -E0022 ; [.0000.0000.0000] -E0023 ; [.0000.0000.0000] -E0024 ; [.0000.0000.0000] -E0025 ; [.0000.0000.0000] -E0026 ; [.0000.0000.0000] -E0027 ; [.0000.0000.0000] -E0028 ; [.0000.0000.0000] -E0029 ; [.0000.0000.0000] -E002A ; [.0000.0000.0000] -E002B ; [.0000.0000.0000] -E002C ; [.0000.0000.0000] -E002D ; [.0000.0000.0000] -E002E ; [.0000.0000.0000] -E002F ; [.0000.0000.0000] -E0030 ; [.0000.0000.0000] -E0031 ; [.0000.0000.0000] -E0032 ; [.0000.0000.0000] -E0033 ; [.0000.0000.0000] -E0034 ; [.0000.0000.0000] -E0035 ; [.0000.0000.0000] -E0036 ; [.0000.0000.0000] -E0037 ; [.0000.0000.0000] -E0038 ; [.0000.0000.0000] -E0039 ; [.0000.0000.0000] -E003A ; [.0000.0000.0000] -E003B ; [.0000.0000.0000] -E003C ; [.0000.0000.0000] -E003D ; [.0000.0000.0000] -E003E ; [.0000.0000.0000] -E003F ; [.0000.0000.0000] -E0040 ; [.0000.0000.0000] -E0041 ; [.0000.0000.0000] -E0042 ; [.0000.0000.0000] -E0043 ; [.0000.0000.0000] -E0044 ; [.0000.0000.0000] -E0045 ; [.0000.0000.0000] -E0046 ; [.0000.0000.0000] -E0047 ; [.0000.0000.0000] -E0048 ; [.0000.0000.0000] -E0049 ; [.0000.0000.0000] -E004A ; [.0000.0000.0000] -E004B ; [.0000.0000.0000] -E004C ; [.0000.0000.0000] -E004D ; [.0000.0000.0000] -E004E ; [.0000.0000.0000] -E004F ; [.0000.0000.0000] -E0050 ; [.0000.0000.0000] -E0051 ; [.0000.0000.0000] -E0052 ; [.0000.0000.0000] -E0053 ; [.0000.0000.0000] -E0054 ; [.0000.0000.0000] -E0055 ; [.0000.0000.0000] -E0056 ; [.0000.0000.0000] -E0057 ; [.0000.0000.0000] -E0058 ; [.0000.0000.0000] -E0059 ; [.0000.0000.0000] -E005A ; [.0000.0000.0000] -E005B ; [.0000.0000.0000] -E005C ; [.0000.0000.0000] -E005D ; [.0000.0000.0000] -E005E ; [.0000.0000.0000] -E005F ; [.0000.0000.0000] -E0060 ; [.0000.0000.0000] -E0061 ; [.0000.0000.0000] -E0062 ; [.0000.0000.0000] -E0063 ; [.0000.0000.0000] -E0064 ; [.0000.0000.0000] -E0065 ; [.0000.0000.0000] -E0066 ; [.0000.0000.0000] -E0067 ; [.0000.0000.0000] -E0068 ; [.0000.0000.0000] -E0069 ; [.0000.0000.0000] -E006A ; [.0000.0000.0000] -E006B ; [.0000.0000.0000] -E006C ; [.0000.0000.0000] -E006D ; [.0000.0000.0000] -E006E ; [.0000.0000.0000] -E006F ; [.0000.0000.0000] -E0070 ; [.0000.0000.0000] -E0071 ; [.0000.0000.0000] -E0072 ; [.0000.0000.0000] -E0073 ; [.0000.0000.0000] -E0074 ; [.0000.0000.0000] -E0075 ; [.0000.0000.0000] -E0076 ; [.0000.0000.0000] -E0077 ; [.0000.0000.0000] -E0078 ; [.0000.0000.0000] -E0079 ; [.0000.0000.0000] -E007A ; [.0000.0000.0000] -E007B ; [.0000.0000.0000] -E007C ; [.0000.0000.0000] -E007D ; [.0000.0000.0000] -E007E ; [.0000.0000.0000] -E007F ; [.0000.0000.0000] -E0100 ; [.0000.0000.0000] -E0101 ; [.0000.0000.0000] -E0102 ; [.0000.0000.0000] -E0103 ; [.0000.0000.0000] -E0104 ; [.0000.0000.0000] -E0105 ; [.0000.0000.0000] -E0106 ; [.0000.0000.0000] -E0107 ; [.0000.0000.0000] -E0108 ; [.0000.0000.0000] -E0109 ; [.0000.0000.0000] -E010A ; [.0000.0000.0000] -E010B ; [.0000.0000.0000] -E010C ; [.0000.0000.0000] -E010D ; [.0000.0000.0000] -E010E ; [.0000.0000.0000] -E010F ; [.0000.0000.0000] -E0110 ; [.0000.0000.0000] -E0111 ; [.0000.0000.0000] -E0112 ; [.0000.0000.0000] -E0113 ; [.0000.0000.0000] -E0114 ; [.0000.0000.0000] -E0115 ; [.0000.0000.0000] -E0116 ; [.0000.0000.0000] -E0117 ; [.0000.0000.0000] -E0118 ; [.0000.0000.0000] -E0119 ; [.0000.0000.0000] -E011A ; [.0000.0000.0000] -E011B ; [.0000.0000.0000] -E011C ; [.0000.0000.0000] -E011D ; [.0000.0000.0000] -E011E ; [.0000.0000.0000] -E011F ; [.0000.0000.0000] -E0120 ; [.0000.0000.0000] -E0121 ; [.0000.0000.0000] -E0122 ; [.0000.0000.0000] -E0123 ; [.0000.0000.0000] -E0124 ; [.0000.0000.0000] -E0125 ; [.0000.0000.0000] -E0126 ; [.0000.0000.0000] -E0127 ; [.0000.0000.0000] -E0128 ; [.0000.0000.0000] -E0129 ; [.0000.0000.0000] -E012A ; [.0000.0000.0000] -E012B ; [.0000.0000.0000] -E012C ; [.0000.0000.0000] -E012D ; [.0000.0000.0000] -E012E ; [.0000.0000.0000] -E012F ; [.0000.0000.0000] -E0130 ; [.0000.0000.0000] -E0131 ; [.0000.0000.0000] -E0132 ; [.0000.0000.0000] -E0133 ; [.0000.0000.0000] -E0134 ; [.0000.0000.0000] -E0135 ; [.0000.0000.0000] -E0136 ; [.0000.0000.0000] -E0137 ; [.0000.0000.0000] -E0138 ; [.0000.0000.0000] -E0139 ; [.0000.0000.0000] -E013A ; [.0000.0000.0000] -E013B ; [.0000.0000.0000] -E013C ; [.0000.0000.0000] -E013D ; [.0000.0000.0000] -E013E ; [.0000.0000.0000] -E013F ; [.0000.0000.0000] -E0140 ; [.0000.0000.0000] -E0141 ; [.0000.0000.0000] -E0142 ; [.0000.0000.0000] -E0143 ; [.0000.0000.0000] -E0144 ; [.0000.0000.0000] -E0145 ; [.0000.0000.0000] -E0146 ; [.0000.0000.0000] -E0147 ; [.0000.0000.0000] -E0148 ; [.0000.0000.0000] -E0149 ; [.0000.0000.0000] -E014A ; [.0000.0000.0000] -E014B ; [.0000.0000.0000] -E014C ; [.0000.0000.0000] -E014D ; [.0000.0000.0000] -E014E ; [.0000.0000.0000] -E014F ; [.0000.0000.0000] -E0150 ; [.0000.0000.0000] -E0151 ; [.0000.0000.0000] -E0152 ; [.0000.0000.0000] -E0153 ; [.0000.0000.0000] -E0154 ; [.0000.0000.0000] -E0155 ; [.0000.0000.0000] -E0156 ; [.0000.0000.0000] -E0157 ; [.0000.0000.0000] -E0158 ; [.0000.0000.0000] -E0159 ; [.0000.0000.0000] -E015A ; [.0000.0000.0000] -E015B ; [.0000.0000.0000] -E015C ; [.0000.0000.0000] -E015D ; [.0000.0000.0000] -E015E ; [.0000.0000.0000] -E015F ; [.0000.0000.0000] -E0160 ; [.0000.0000.0000] -E0161 ; [.0000.0000.0000] -E0162 ; [.0000.0000.0000] -E0163 ; [.0000.0000.0000] -E0164 ; [.0000.0000.0000] -E0165 ; [.0000.0000.0000] -E0166 ; [.0000.0000.0000] -E0167 ; [.0000.0000.0000] -E0168 ; [.0000.0000.0000] -E0169 ; [.0000.0000.0000] -E016A ; [.0000.0000.0000] -E016B ; [.0000.0000.0000] -E016C ; [.0000.0000.0000] -E016D ; [.0000.0000.0000] -E016E ; [.0000.0000.0000] -E016F ; [.0000.0000.0000] -E0170 ; [.0000.0000.0000] -E0171 ; [.0000.0000.0000] -E0172 ; [.0000.0000.0000] -E0173 ; [.0000.0000.0000] -E0174 ; [.0000.0000.0000] -E0175 ; [.0000.0000.0000] -E0176 ; [.0000.0000.0000] -E0177 ; [.0000.0000.0000] -E0178 ; [.0000.0000.0000] -E0179 ; [.0000.0000.0000] -E017A ; [.0000.0000.0000] -E017B ; [.0000.0000.0000] -E017C ; [.0000.0000.0000] -E017D ; [.0000.0000.0000] -E017E ; [.0000.0000.0000] -E017F ; [.0000.0000.0000] -E0180 ; [.0000.0000.0000] -E0181 ; [.0000.0000.0000] -E0182 ; [.0000.0000.0000] -E0183 ; [.0000.0000.0000] -E0184 ; [.0000.0000.0000] -E0185 ; [.0000.0000.0000] -E0186 ; [.0000.0000.0000] -E0187 ; [.0000.0000.0000] -E0188 ; [.0000.0000.0000] -E0189 ; [.0000.0000.0000] -E018A ; [.0000.0000.0000] -E018B ; [.0000.0000.0000] -E018C ; [.0000.0000.0000] -E018D ; [.0000.0000.0000] -E018E ; [.0000.0000.0000] -E018F ; [.0000.0000.0000] -E0190 ; [.0000.0000.0000] -E0191 ; [.0000.0000.0000] -E0192 ; [.0000.0000.0000] -E0193 ; [.0000.0000.0000] -E0194 ; [.0000.0000.0000] -E0195 ; [.0000.0000.0000] -E0196 ; [.0000.0000.0000] -E0197 ; [.0000.0000.0000] -E0198 ; [.0000.0000.0000] -E0199 ; [.0000.0000.0000] -E019A ; [.0000.0000.0000] -E019B ; [.0000.0000.0000] -E019C ; [.0000.0000.0000] -E019D ; [.0000.0000.0000] -E019E ; [.0000.0000.0000] -E019F ; [.0000.0000.0000] -E01A0 ; [.0000.0000.0000] -E01A1 ; [.0000.0000.0000] -E01A2 ; [.0000.0000.0000] -E01A3 ; [.0000.0000.0000] -E01A4 ; [.0000.0000.0000] -E01A5 ; [.0000.0000.0000] -E01A6 ; [.0000.0000.0000] -E01A7 ; [.0000.0000.0000] -E01A8 ; [.0000.0000.0000] -E01A9 ; [.0000.0000.0000] -E01AA ; [.0000.0000.0000] -E01AB ; [.0000.0000.0000] -E01AC ; [.0000.0000.0000] -E01AD ; [.0000.0000.0000] -E01AE ; [.0000.0000.0000] -E01AF ; [.0000.0000.0000] -E01B0 ; [.0000.0000.0000] -E01B1 ; [.0000.0000.0000] -E01B2 ; [.0000.0000.0000] -E01B3 ; [.0000.0000.0000] -E01B4 ; [.0000.0000.0000] -E01B5 ; [.0000.0000.0000] -E01B6 ; [.0000.0000.0000] -E01B7 ; [.0000.0000.0000] -E01B8 ; [.0000.0000.0000] -E01B9 ; [.0000.0000.0000] -E01BA ; [.0000.0000.0000] -E01BB ; [.0000.0000.0000] -E01BC ; [.0000.0000.0000] -E01BD ; [.0000.0000.0000] -E01BE ; [.0000.0000.0000] -E01BF ; [.0000.0000.0000] -E01C0 ; [.0000.0000.0000] -E01C1 ; [.0000.0000.0000] -E01C2 ; [.0000.0000.0000] -E01C3 ; [.0000.0000.0000] -E01C4 ; [.0000.0000.0000] -E01C5 ; [.0000.0000.0000] -E01C6 ; [.0000.0000.0000] -E01C7 ; [.0000.0000.0000] -E01C8 ; [.0000.0000.0000] -E01C9 ; [.0000.0000.0000] -E01CA ; [.0000.0000.0000] -E01CB ; [.0000.0000.0000] -E01CC ; [.0000.0000.0000] -E01CD ; [.0000.0000.0000] -E01CE ; [.0000.0000.0000] -E01CF ; [.0000.0000.0000] -E01D0 ; [.0000.0000.0000] -E01D1 ; [.0000.0000.0000] -E01D2 ; [.0000.0000.0000] -E01D3 ; [.0000.0000.0000] -E01D4 ; [.0000.0000.0000] -E01D5 ; [.0000.0000.0000] -E01D6 ; [.0000.0000.0000] -E01D7 ; [.0000.0000.0000] -E01D8 ; [.0000.0000.0000] -E01D9 ; [.0000.0000.0000] -E01DA ; [.0000.0000.0000] -E01DB ; [.0000.0000.0000] -E01DC ; [.0000.0000.0000] -E01DD ; [.0000.0000.0000] -E01DE ; [.0000.0000.0000] -E01DF ; [.0000.0000.0000] -E01E0 ; [.0000.0000.0000] -E01E1 ; [.0000.0000.0000] -E01E2 ; [.0000.0000.0000] -E01E3 ; [.0000.0000.0000] -E01E4 ; [.0000.0000.0000] -E01E5 ; [.0000.0000.0000] -E01E6 ; [.0000.0000.0000] -E01E7 ; [.0000.0000.0000] -E01E8 ; [.0000.0000.0000] -E01E9 ; [.0000.0000.0000] -E01EA ; [.0000.0000.0000] -E01EB ; [.0000.0000.0000] -E01EC ; [.0000.0000.0000] -E01ED ; [.0000.0000.0000] -E01EE ; [.0000.0000.0000] -E01EF ; [.0000.0000.0000] -0009 ; [*0201.0020.0002] -000A ; [*0202.0020.0002] -000B ; [*0203.0020.0002] -000C ; [*0204.0020.0002] -000D ; [*0205.0020.0002] -0020 ; [*0209.0020.0002] -0021 ; [*025F.0020.0002] -0022 ; [*0305.0020.0002] -0023 ; [*0391.0020.0002] -0025 ; [*0392.0020.0002] -0026 ; [*038F.0020.0002] -0027 ; [*02FE.0020.0002] -0028 ; [*0310.0020.0002] -0029 ; [*0311.0020.0002] -002A ; [*0388.0020.0002] -002B ; [*05F6.0020.0002] -002C ; [*0221.0020.0002] -002D ; [*020D.0020.0002] -002E ; [*0274.0020.0002] -002F ; [*038D.0020.0002] -003A ; [*0238.0020.0002] -003B ; [*0233.0020.0002] -003C ; [*05FA.0020.0002] -003D ; [*05FB.0020.0002] -003E ; [*05FC.0020.0002] -003F ; [*0264.0020.0002] -0040 ; [*0387.0020.0002] -005B ; [*0312.0020.0002] -005C ; [*038E.0020.0002] -005D ; [*0313.0020.0002] -005E ; [*0466.0020.0002] -005F ; [*020B.0020.0002] -0060 ; [*0463.0020.0002] -007B ; [*0314.0020.0002] -007C ; [*05FE.0020.0002] -007D ; [*0315.0020.0002] -007E ; [*0600.0020.0002] -0085 ; [*0206.0020.0002] -00A0 ; [*0209.0020.001B] -00A1 ; [*0260.0020.0002] -00A6 ; [*05FF.0020.0002] -00A7 ; [*0382.0020.0002] -00A8 ; [*046A.0020.0002] -00A9 ; [*0564.0020.0002] -00AB ; [*030E.0020.0002] -00AC ; [*05FD.0020.0002] -00AE ; [*0565.0020.0002] -00AF ; [*0467.0020.0002] -00B0 ; [*04D7.0020.0002] -00B1 ; [*05F7.0020.0002] -00B4 ; [*0464.0020.0002] -00B6 ; [*0384.0020.0002] -00B7 ; [*0288.0020.0002] -00B8 ; [*046D.0020.0002] -00BB ; [*030F.0020.0002] -00BF ; [*0265.0020.0002] -00D7 ; [*05F9.0020.0002] -00F7 ; [*05F8.0020.0002] -02B9 ; [*0474.0020.0002] -02BA ; [*0476.0020.0002] -02C2 ; [*0477.0020.0002] -02C3 ; [*0478.0020.0002] -02C4 ; [*0479.0020.0002] -02C5 ; [*047A.0020.0002] -02C6 ; [*047B.0020.0002] -02C7 ; [*047C.0020.0002] -02C8 ; [*047D.0020.0002] -02C9 ; [*047E.0020.0002] -02CA ; [*047F.0020.0002] -02CB ; [*0480.0020.0002] -02CC ; [*0481.0020.0002] -02CD ; [*0482.0020.0002] -02CE ; [*0483.0020.0002] -02CF ; [*0484.0020.0002] -02D2 ; [*0485.0020.0002] -02D3 ; [*0486.0020.0002] -02D4 ; [*0487.0020.0002] -02D5 ; [*0488.0020.0002] -02D6 ; [*0489.0020.0002] -02D7 ; [*048A.0020.0002] -02D8 ; [*0468.0020.0002] -02D9 ; [*0469.0020.0002] -02DA ; [*046B.0020.0002] -02DB ; [*046E.0020.0002] -02DC ; [*0465.0020.0002] -02DD ; [*046C.0020.0002] -02DE ; [*048B.0020.0002] -02DF ; [*048C.0020.0002] -02E5 ; [*048D.0020.0002] -02E6 ; [*048E.0020.0002] -02E7 ; [*048F.0020.0002] -02E8 ; [*0490.0020.0002] -02E9 ; [*0491.0020.0002] -02EA ; [*0492.0020.0002] -02EB ; [*0493.0020.0002] -02EC ; [*0494.0020.0002] -02ED ; [*0495.0020.0002] -02EF ; [*0496.0020.0002] -02F0 ; [*0497.0020.0002] -02F1 ; [*0498.0020.0002] -02F2 ; [*0499.0020.0002] -02F3 ; [*049A.0020.0002] -02F4 ; [*049B.0020.0002] -02F5 ; [*049C.0020.0002] -02F6 ; [*049D.0020.0002] -02F7 ; [*049E.0020.0002] -02F8 ; [*049F.0020.0002] -02F9 ; [*04A0.0020.0002] -02FA ; [*04A1.0020.0002] -02FB ; [*04A2.0020.0002] -02FC ; [*04A3.0020.0002] -02FD ; [*04A4.0020.0002] -02FE ; [*04A5.0020.0002] -02FF ; [*04A6.0020.0002] -034F ; [.0000.0000.0000] -0374 ; [*0474.0020.0002] -0375 ; [*0475.0020.0002] -037E ; [*0233.0020.0002] -0384 ; [*0464.0020.0002] -0385 ; [*046A.0020.0002][.0000.0024.0002] -0387 ; [*0288.0020.0002] -03F6 ; [*05F1.0020.0002] -0482 ; [*04D8.0020.0002] -0488 ; [.0000.0000.0000] -0489 ; [.0000.0000.0000] -055A ; [*03C3.0020.0002] -055B ; [*03C4.0020.0002] -055C ; [*0261.0020.0002] -055D ; [*0225.0020.0002] -055E ; [*0267.0020.0002] -055F ; [*03C5.0020.0002] -0589 ; [*0239.0020.0002] -058A ; [*020E.0020.0002] -058D ; [*04D9.0020.0002] -058E ; [*04DA.0020.0002] -0591 ; [.0000.0000.0000] -0592 ; [.0000.0000.0000] -0593 ; [.0000.0000.0000] -0594 ; [.0000.0000.0000] -0595 ; [.0000.0000.0000] -0596 ; [.0000.0000.0000] -0597 ; [.0000.0000.0000] -0598 ; [.0000.0000.0000] -0599 ; [.0000.0000.0000] -059A ; [.0000.0000.0000] -059B ; [.0000.0000.0000] -059C ; [.0000.0000.0000] -059D ; [.0000.0000.0000] -059E ; [.0000.0000.0000] -059F ; [.0000.0000.0000] -05A0 ; [.0000.0000.0000] -05A1 ; [.0000.0000.0000] -05A2 ; [.0000.0000.0000] -05A3 ; [.0000.0000.0000] -05A4 ; [.0000.0000.0000] -05A5 ; [.0000.0000.0000] -05A6 ; [.0000.0000.0000] -05A7 ; [.0000.0000.0000] -05A8 ; [.0000.0000.0000] -05A9 ; [.0000.0000.0000] -05AA ; [.0000.0000.0000] -05AB ; [.0000.0000.0000] -05AC ; [.0000.0000.0000] -05AD ; [.0000.0000.0000] -05AE ; [.0000.0000.0000] -05AF ; [.0000.0000.0000] -05BD ; [.0000.0000.0000] -05BE ; [*03C6.0020.0002] -05C0 ; [*03C7.0020.0002] -05C3 ; [*03C8.0020.0002] -05C4 ; [.0000.0000.0000] -05C5 ; [.0000.0000.0000] -05C6 ; [*03C9.0020.0002] -05F3 ; [*03CA.0020.0002] -05F4 ; [*03CB.0020.0002] -0600 ; [.0000.0000.0000] -0601 ; [.0000.0000.0000] -0602 ; [.0000.0000.0000] -0603 ; [.0000.0000.0000] -0604 ; [.0000.0000.0000] -0605 ; [.0000.0000.0000] -0606 ; [*060D.0020.0002] -0607 ; [*060F.0020.0002] -0608 ; [*04DB.0020.0002] -0609 ; [*0395.0020.0002] -060A ; [*0397.0020.0002] -060C ; [*0226.0020.0002] -060D ; [*0227.0020.0002] -060E ; [*04DE.0020.0002] -060F ; [*04DF.0020.0002] -0610 ; [.0000.0000.0000] -0611 ; [.0000.0000.0000] -0612 ; [.0000.0000.0000] -0613 ; [.0000.0000.0000] -0614 ; [.0000.0000.0000] -0615 ; [.0000.0000.0000] -0616 ; [.0000.0000.0000] -0617 ; [.0000.0000.0000] -0618 ; [.0000.0000.0000] -0619 ; [.0000.0000.0000] -061A ; [.0000.0000.0000] -061B ; [*0234.0020.0002] -061E ; [*023A.0020.0002] -061F ; [*0268.0020.0002] -0640 ; [.0000.0000.0000] -066A ; [*0393.0020.0002] -066B ; [*0228.0020.0002] -066C ; [*0229.0020.0002] -066D ; [*038B.0020.0002] -06D4 ; [*0276.0020.0002] -06D6 ; [.0000.0000.0000] -06D7 ; [.0000.0000.0000] -06D8 ; [.0000.0000.0000] -06D9 ; [.0000.0000.0000] -06DA ; [.0000.0000.0000] -06DB ; [.0000.0000.0000] -06DC ; [.0000.0000.0000] -06DD ; [.0000.0000.0000] -06DE ; [*04E0.0020.0002] -06DF ; [.0000.0000.0000] -06E0 ; [.0000.0000.0000] -06E1 ; [.0000.0000.0000] -06E2 ; [.0000.0000.0000] -06E3 ; [.0000.0000.0000] -06E4 ; [.0000.0000.0000] -06E7 ; [.0000.0000.0000] -06E8 ; [.0000.0000.0000] -06E9 ; [*04E1.0020.0002] -06EA ; [.0000.0000.0000] -06EB ; [.0000.0000.0000] -06EC ; [.0000.0000.0000] -06ED ; [.0000.0000.0000] -0700 ; [*02BD.0020.0002] -0701 ; [*0277.0020.0002] -0702 ; [*0278.0020.0002] -0703 ; [*023B.0020.0002] -0704 ; [*023C.0020.0002] -0705 ; [*023D.0020.0002] -0706 ; [*023E.0020.0002] -0707 ; [*023F.0020.0002] -0708 ; [*0240.0020.0002] -0709 ; [*0269.0020.0002] -070A ; [*03CC.0020.0002] -070B ; [*03CD.0020.0002] -070C ; [*03CE.0020.0002] -070D ; [*03CF.0020.0002] -0740 ; [.0000.0000.0000] -0743 ; [.0000.0000.0000] -0744 ; [.0000.0000.0000] -0747 ; [.0000.0000.0000] -0748 ; [.0000.0000.0000] -0749 ; [.0000.0000.0000] -074A ; [.0000.0000.0000] -07F6 ; [*04F3.0020.0002] -07F7 ; [*02BE.0020.0002] -07F8 ; [*022A.0020.0002] -07F9 ; [*0262.0020.0002] -07FA ; [.0000.0000.0000] -0830 ; [*0241.0020.0002] -0831 ; [*0242.0020.0002] -0832 ; [*0243.0020.0002] -0833 ; [*0244.0020.0002] -0834 ; [*0245.0020.0002] -0835 ; [*0246.0020.0002] -0836 ; [*0247.0020.0002] -0837 ; [*0248.0020.0002] -0838 ; [*0249.0020.0002] -0839 ; [*024A.0020.0002] -083A ; [*024B.0020.0002] -083B ; [*024C.0020.0002] -083C ; [*024D.0020.0002] -083D ; [*024E.0020.0002] -083E ; [*024F.0020.0002] -085E ; [*03D0.0020.0002] -08EA ; [.0000.0000.0000] -08EB ; [.0000.0000.0000] -08EC ; [.0000.0000.0000] -08ED ; [.0000.0000.0000] -08EE ; [.0000.0000.0000] -08EF ; [.0000.0000.0000] -08F3 ; [.0000.0000.0000] -0951 ; [.0000.0000.0000] -0952 ; [.0000.0000.0000] -0964 ; [*028B.0020.0002] -0965 ; [*028C.0020.0002] -0970 ; [*03D2.0020.0002] -09F4 ; [*1A26.0020.0002] -09F5 ; [*1A27.0020.0002] -09F6 ; [*1A28.0020.0002] -09F7 ; [*1A29.0020.0002] -09F8 ; [*1A2A.0020.0002] -09F9 ; [*1A2B.0020.0002] -09FA ; [*04F4.0020.0002] -0AF0 ; [*03D7.0020.0002] -0B70 ; [*04F5.0020.0002] -0B72 ; [*1A2C.0020.0002] -0B73 ; [*1A2D.0020.0002] -0B74 ; [*1A2E.0020.0002] -0B75 ; [*1A2F.0020.0002] -0B76 ; [*1A30.0020.0002] -0B77 ; [*1A31.0020.0002] -0BF0 ; [*1A38.0020.0002] -0BF1 ; [*1A39.0020.0002] -0BF2 ; [*1A3A.0020.0002] -0BF3 ; [*04F6.0020.0002] -0BF4 ; [*04F7.0020.0002] -0BF5 ; [*04F8.0020.0002] -0BF6 ; [*04F9.0020.0002] -0BF7 ; [*04FA.0020.0002] -0BF8 ; [*04FB.0020.0002] -0BFA ; [*04FC.0020.0002] -0C7F ; [*04FD.0020.0002] -0D70 ; [*1A3B.0020.0002] -0D71 ; [*1A3C.0020.0002] -0D72 ; [*1A3D.0020.0002] -0D73 ; [*1A3E.0020.0002] -0D74 ; [*1A3F.0020.0002] -0D75 ; [*1A40.0020.0002] -0D79 ; [*04FE.0020.0002] -0DF4 ; [*03D8.0020.0002] -0E4F ; [*03D9.0020.0002] -0E5A ; [*03DA.0020.0002] -0E5B ; [*03DB.0020.0002] -0F01 ; [*0506.0020.0002] -0F02 ; [*0507.0020.0002] -0F03 ; [*0508.0020.0002] -0F04 ; [*03DE.0020.0002] -0F05 ; [*03DF.0020.0002] -0F06 ; [*03E0.0020.0002] -0F07 ; [*03E1.0020.0002] -0F08 ; [*03E2.0020.0002] -0F09 ; [*03E3.0020.0002] -0F0A ; [*03E4.0020.0002] -0F0B ; [*03E7.0020.0002] -0F0C ; [*03E7.0020.001B] -0F0D ; [*03E8.0020.0002] -0F0E ; [*03E9.0020.0002] -0F0F ; [*03EA.0020.0002] -0F10 ; [*03EB.0020.0002] -0F11 ; [*03EC.0020.0002] -0F12 ; [*03ED.0020.0002] -0F13 ; [*0509.0020.0002] -0F14 ; [*0257.0020.0002] -0F15 ; [*050A.0020.0002] -0F16 ; [*050B.0020.0002] -0F17 ; [*050C.0020.0002] -0F18 ; [.0000.0000.0000] -0F19 ; [.0000.0000.0000] -0F1A ; [*050D.0020.0002] -0F1B ; [*050E.0020.0002] -0F1C ; [*050F.0020.0002] -0F1D ; [*0510.0020.0002] -0F1E ; [*0511.0020.0002] -0F1F ; [*0512.0020.0002] -0F34 ; [*0513.0020.0002] -0F35 ; [.0000.0000.0000] -0F36 ; [*0514.0020.0002] -0F37 ; [.0000.0000.0000] -0F38 ; [*0515.0020.0002] -0F3A ; [*0316.0020.0002] -0F3B ; [*0317.0020.0002] -0F3C ; [*0318.0020.0002] -0F3D ; [*0319.0020.0002] -0F3E ; [.0000.0000.0000] -0F3F ; [.0000.0000.0000] -0F82 ; [.0000.0000.0000] -0F83 ; [.0000.0000.0000] -0F85 ; [*03EE.0020.0002] -0F86 ; [.0000.0000.0000] -0F87 ; [.0000.0000.0000] -0FBE ; [*0516.0020.0002] -0FBF ; [*0517.0020.0002] -0FC0 ; [*0518.0020.0002] -0FC1 ; [*0519.0020.0002] -0FC2 ; [*051A.0020.0002] -0FC3 ; [*051B.0020.0002] -0FC4 ; [*051C.0020.0002] -0FC5 ; [*051D.0020.0002] -0FC6 ; [.0000.0000.0000] -0FC7 ; [*051E.0020.0002] -0FC8 ; [*051F.0020.0002] -0FC9 ; [*0520.0020.0002] -0FCA ; [*0521.0020.0002] -0FCB ; [*0522.0020.0002] -0FCC ; [*0523.0020.0002] -0FCE ; [*0524.0020.0002] -0FCF ; [*0525.0020.0002] -0FD0 ; [*03E5.0020.0002] -0FD1 ; [*03E6.0020.0002] -0FD2 ; [*03EF.0020.0002] -0FD3 ; [*03F0.0020.0002] -0FD4 ; [*03F1.0020.0002] -0FD5 ; [*0526.0020.0002] -0FD6 ; [*0527.0020.0002] -0FD7 ; [*0528.0020.0002] -0FD8 ; [*0529.0020.0002] -0FD9 ; [*03F2.0020.0002] -0FDA ; [*03F3.0020.0002] -104A ; [*0296.0020.0002] -104B ; [*0297.0020.0002] -104C ; [*03F7.0020.0002] -104D ; [*03F8.0020.0002] -104E ; [*03F9.0020.0002] -104F ; [*03FA.0020.0002] -109E ; [*052B.0020.0002] -109F ; [*052C.0020.0002] -10FB ; [*02BF.0020.0002] -1360 ; [*02C0.0020.0002] -1361 ; [*0250.0020.0002] -1362 ; [*0279.0020.0002] -1363 ; [*0251.0020.0002] -1364 ; [*0252.0020.0002] -1365 ; [*0253.0020.0002] -1366 ; [*0254.0020.0002] -1367 ; [*026A.0020.0002] -1368 ; [*02C1.0020.0002] -1372 ; [*1A41.0020.0002] -1373 ; [*1A42.0020.0002] -1374 ; [*1A43.0020.0002] -1375 ; [*1A44.0020.0002] -1376 ; [*1A45.0020.0002] -1377 ; [*1A46.0020.0002] -1378 ; [*1A47.0020.0002] -1379 ; [*1A48.0020.0002] -137A ; [*1A49.0020.0002] -137B ; [*1A4A.0020.0002] -137C ; [*1A4B.0020.0002] -1390 ; [*04A7.0020.0002] -1391 ; [*04A8.0020.0002] -1392 ; [*04A9.0020.0002] -1393 ; [*04AA.0020.0002] -1394 ; [*04AB.0020.0002] -1395 ; [*04AC.0020.0002] -1396 ; [*04AD.0020.0002] -1397 ; [*04AE.0020.0002] -1398 ; [*04AF.0020.0002] -1399 ; [*04B0.0020.0002] -1400 ; [*020F.0020.0002] -166D ; [*0407.0020.0002] -166E ; [*027C.0020.0002] -1680 ; [*0209.0020.0004] -169B ; [*031A.0020.0002] -169C ; [*031B.0020.0002] -16EB ; [*025B.0020.0002] -16EC ; [*025C.0020.0002] -16ED ; [*025D.0020.0002] -1735 ; [*0293.0020.0002] -1736 ; [*0294.0020.0002] -17B4 ; [.0000.0000.0000] -17B5 ; [.0000.0000.0000] -17D3 ; [.0000.0000.0000] -17D4 ; [*0298.0020.0002] -17D5 ; [*0299.0020.0002] -17D6 ; [*0258.0020.0002] -17D8 ; [*03FB.0020.0002] -17D9 ; [*03FC.0020.0002] -17DA ; [*03FD.0020.0002] -1800 ; [*03D1.0020.0002] -1801 ; [*0275.0020.0002] -1802 ; [*022B.0020.0002] -1803 ; [*027A.0020.0002] -1804 ; [*0255.0020.0002] -1805 ; [*0256.0020.0002] -1806 ; [*0211.0020.0002] -1807 ; [*0212.0020.0002] -1808 ; [*022C.0020.0002] -1809 ; [*027B.0020.0002] -180A ; [.0000.0000.0000] -1940 ; [*052A.0020.0002] -1944 ; [*0263.0020.0002] -1945 ; [*026B.0020.0002] -19E0 ; [*0531.0020.0002] -19E1 ; [*0532.0020.0002] -19E2 ; [*0533.0020.0002] -19E3 ; [*0534.0020.0002] -19E4 ; [*0535.0020.0002] -19E5 ; [*0536.0020.0002] -19E6 ; [*0537.0020.0002] -19E7 ; [*0538.0020.0002] -19E8 ; [*0539.0020.0002] -19E9 ; [*053A.0020.0002] -19EA ; [*053B.0020.0002] -19EB ; [*053C.0020.0002] -19EC ; [*053D.0020.0002] -19ED ; [*053E.0020.0002] -19EE ; [*053F.0020.0002] -19EF ; [*0540.0020.0002] -19F0 ; [*0541.0020.0002] -19F1 ; [*0542.0020.0002] -19F2 ; [*0543.0020.0002] -19F3 ; [*0544.0020.0002] -19F4 ; [*0545.0020.0002] -19F5 ; [*0546.0020.0002] -19F6 ; [*0547.0020.0002] -19F7 ; [*0548.0020.0002] -19F8 ; [*0549.0020.0002] -19F9 ; [*054A.0020.0002] -19FA ; [*054B.0020.0002] -19FB ; [*054C.0020.0002] -19FC ; [*054D.0020.0002] -19FD ; [*054E.0020.0002] -19FE ; [*054F.0020.0002] -19FF ; [*0550.0020.0002] -1A1E ; [*02C2.0020.0002] -1A1F ; [*02C3.0020.0002] -1A7F ; [.0000.0000.0000] -1AA0 ; [*03FE.0020.0002] -1AA1 ; [*03FF.0020.0002] -1AA2 ; [*0400.0020.0002] -1AA3 ; [*0401.0020.0002] -1AA4 ; [*0402.0020.0002] -1AA5 ; [*0403.0020.0002] -1AA6 ; [*0404.0020.0002] -1AA8 ; [*029A.0020.0002] -1AA9 ; [*029B.0020.0002] -1AAA ; [*029C.0020.0002] -1AAB ; [*029D.0020.0002] -1AAC ; [*0405.0020.0002] -1AAD ; [*0406.0020.0002] -1B5A ; [*02C4.0020.0002] -1B5B ; [*02C5.0020.0002] -1B5C ; [*027D.0020.0002] -1B5D ; [*0259.0020.0002] -1B5E ; [*029E.0020.0002] -1B5F ; [*029F.0020.0002] -1B60 ; [*0210.0020.0002] -1B61 ; [*0551.0020.0002] -1B62 ; [*0552.0020.0002] -1B63 ; [*0553.0020.0002] -1B64 ; [*0554.0020.0002] -1B65 ; [*0555.0020.0002] -1B66 ; [*0556.0020.0002] -1B67 ; [*0557.0020.0002] -1B68 ; [*0558.0020.0002] -1B69 ; [*0559.0020.0002] -1B6A ; [*055A.0020.0002] -1B6B ; [.0000.0000.0000] -1B6C ; [.0000.0000.0000] -1B6D ; [.0000.0000.0000] -1B6E ; [.0000.0000.0000] -1B6F ; [.0000.0000.0000] -1B70 ; [.0000.0000.0000] -1B71 ; [.0000.0000.0000] -1B72 ; [.0000.0000.0000] -1B73 ; [.0000.0000.0000] -1B74 ; [*055B.0020.0002] -1B75 ; [*055C.0020.0002] -1B76 ; [*055D.0020.0002] -1B77 ; [*055E.0020.0002] -1B78 ; [*055F.0020.0002] -1B79 ; [*0560.0020.0002] -1B7A ; [*0561.0020.0002] -1B7B ; [*0562.0020.0002] -1B7C ; [*0563.0020.0002] -1BFC ; [*0413.0020.0002] -1BFD ; [*0414.0020.0002] -1BFE ; [*0415.0020.0002] -1BFF ; [*0416.0020.0002] -1C3B ; [*028F.0020.0002] -1C3C ; [*0290.0020.0002] -1C3D ; [*03F4.0020.0002] -1C3E ; [*03F5.0020.0002] -1C3F ; [*03F6.0020.0002] -1C7E ; [*02BB.0020.0002] -1C7F ; [*02BC.0020.0002] -1CC0 ; [*0408.0020.0002] -1CC1 ; [*0409.0020.0002] -1CC2 ; [*040A.0020.0002] -1CC3 ; [*040B.0020.0002] -1CC4 ; [*040C.0020.0002] -1CC5 ; [*040D.0020.0002] -1CC6 ; [*040E.0020.0002] -1CC7 ; [*040F.0020.0002] -1CD0 ; [.0000.0000.0000] -1CD1 ; [.0000.0000.0000] -1CD2 ; [.0000.0000.0000] -1CD3 ; [.0000.0000.0000] -1CD4 ; [.0000.0000.0000] -1CD5 ; [.0000.0000.0000] -1CD6 ; [.0000.0000.0000] -1CD7 ; [.0000.0000.0000] -1CD8 ; [.0000.0000.0000] -1CD9 ; [.0000.0000.0000] -1CDA ; [.0000.0000.0000] -1CDB ; [.0000.0000.0000] -1CDC ; [.0000.0000.0000] -1CDD ; [.0000.0000.0000] -1CDE ; [.0000.0000.0000] -1CDF ; [.0000.0000.0000] -1CE0 ; [.0000.0000.0000] -1CE1 ; [.0000.0000.0000] -1CE2 ; [.0000.0000.0000] -1CE3 ; [.0000.0000.0000] -1CE4 ; [.0000.0000.0000] -1CE5 ; [.0000.0000.0000] -1CE6 ; [.0000.0000.0000] -1CE7 ; [.0000.0000.0000] -1CE8 ; [.0000.0000.0000] -1CF4 ; [.0000.0000.0000] -1CF8 ; [.0000.0000.0000] -1CF9 ; [.0000.0000.0000] -1FBD ; [*046F.0020.0002] -1FBF ; [*046F.0020.0002] -1FC0 ; [*0471.0020.0002] -1FC1 ; [*046A.0020.0002][.0000.002A.0002] -1FCD ; [*046F.0020.0002][.0000.0025.0002] -1FCE ; [*046F.0020.0002][.0000.0024.0002] -1FCF ; [*046F.0020.0002][.0000.002A.0002] -1FDD ; [*0470.0020.0002][.0000.0025.0002] -1FDE ; [*0470.0020.0002][.0000.0024.0002] -1FDF ; [*0470.0020.0002][.0000.002A.0002] -1FED ; [*046A.0020.0002][.0000.0025.0002] -1FEE ; [*046A.0020.0002][.0000.0024.0002] -1FEF ; [*0463.0020.0002] -1FFD ; [*0464.0020.0002] -1FFE ; [*0470.0020.0002] -2000 ; [*0209.0020.0004] -2001 ; [*0209.0020.0004] -2002 ; [*0209.0020.0004] -2003 ; [*0209.0020.0004] -2004 ; [*0209.0020.0004] -2005 ; [*0209.0020.0004] -2006 ; [*0209.0020.0004] -2007 ; [*0209.0020.001B] -2008 ; [*0209.0020.0004] -2009 ; [*0209.0020.0004] -200A ; [*0209.0020.0004] -2010 ; [*0213.0020.0002] -2011 ; [*0213.0020.001B] -2012 ; [*0214.0020.0002] -2013 ; [*0215.0020.0002] -2014 ; [*0216.0020.0002] -2015 ; [*0217.0020.0002] -2016 ; [*037C.0020.0002] -2017 ; [*020C.0020.0002] -2018 ; [*02FF.0020.0002] -2019 ; [*0300.0020.0002] -201A ; [*0301.0020.0002] -201B ; [*0302.0020.0002] -201C ; [*0306.0020.0002] -201D ; [*0307.0020.0002] -201E ; [*0308.0020.0002] -201F ; [*0309.0020.0002] -2020 ; [*0398.0020.0002] -2021 ; [*0399.0020.0002] -2022 ; [*039D.0020.0002] -2023 ; [*039E.0020.0002] -2024 ; [*0274.0020.0004] -2025 ; [*0274.0020.0004][*0274.0020.0004] -2026 ; [*0274.0020.0004][*0274.0020.0004][*0274.0020.0004] -2027 ; [*039F.0020.0002] -2028 ; [*0207.0020.0002] -2029 ; [*0208.0020.0002] -202F ; [*0209.0020.001B] -2030 ; [*0394.0020.0002] -2031 ; [*0396.0020.0002] -2032 ; [*03A3.0020.0002] -2033 ; [*03A3.0020.0004][*03A3.0020.0004] -2034 ; [*03A3.0020.0004][*03A3.0020.0004][*03A3.0020.0004] -2035 ; [*03A4.0020.0002] -2036 ; [*03A4.0020.0004][*03A4.0020.0004] -2037 ; [*03A4.0020.0004][*03A4.0020.0004][*03A4.0020.0004] -2038 ; [*03A7.0020.0002] -2039 ; [*0303.0020.0002] -203A ; [*0304.0020.0002] -203B ; [*03A8.0020.0002] -203C ; [*025F.0020.0004][*025F.0020.0004] -203D ; [*0272.0020.0002] -203E ; [*020A.0020.0002] -203F ; [*03A9.0020.0002] -2040 ; [*03AB.0020.0002] -2041 ; [*03AD.0020.0002] -2042 ; [*03AE.0020.0002] -2043 ; [*03A0.0020.0002] -2044 ; [*0606.0020.0002] -2045 ; [*031C.0020.0002] -2046 ; [*031D.0020.0002] -2047 ; [*0264.0020.0004][*0264.0020.0004] -2048 ; [*0264.0020.0004][*025F.0020.0004] -2049 ; [*025F.0020.0004][*0264.0020.0004] -204A ; [*0390.0020.0002] -204B ; [*0385.0020.0002] -204C ; [*03A1.0020.0002] -204D ; [*03A2.0020.0002] -204E ; [*0389.0020.0002] -204F ; [*0235.0020.0002] -2050 ; [*03AC.0020.0002] -2051 ; [*038A.0020.0002] -2052 ; [*0602.0020.0002] -2053 ; [*021A.0020.0002] -2054 ; [*03AA.0020.0002] -2055 ; [*02E1.0020.0002] -2056 ; [*02E2.0020.0002] -2057 ; [*03A3.0020.0004][*03A3.0020.0004][*03A3.0020.0004][*03A3.0020.0004] -2058 ; [*02E3.0020.0002] -2059 ; [*02E4.0020.0002] -205A ; [*02E5.0020.0002] -205B ; [*02E6.0020.0002] -205C ; [*02E7.0020.0002] -205D ; [*02E8.0020.0002] -205E ; [*02E9.0020.0002] -205F ; [*0209.0020.0004] -2061 ; [.0000.0000.0000] -2062 ; [.0000.0000.0000] -2063 ; [.0000.0000.0000] -2064 ; [.0000.0000.0000] -207A ; [*05F6.0020.0014] -207B ; [*0601.0020.0014] -207C ; [*05FB.0020.0014] -207D ; [*0310.0020.0014] -207E ; [*0311.0020.0014] -208A ; [*05F6.0020.0015] -208B ; [*0601.0020.0015] -208C ; [*05FB.0020.0015] -208D ; [*0310.0020.0015] -208E ; [*0311.0020.0015] -2104 ; [*0566.0020.0002] -2108 ; [*0567.0020.0002] -2114 ; [*0568.0020.0002] -2117 ; [*0569.0020.0002] -2118 ; [*056A.0020.0002] -211E ; [*056B.0020.0002] -211F ; [*056C.0020.0002] -2123 ; [*056D.0020.0002] -2125 ; [*056E.0020.0002] -2127 ; [*056F.0020.0002] -2129 ; [*0570.0020.0002] -212E ; [*0571.0020.0002] -213A ; [*0572.0020.0002] -2140 ; [*05F5.0020.0005] -2141 ; [*0573.0020.0002] -2142 ; [*0574.0020.0002] -2143 ; [*0575.0020.0002] -2144 ; [*0576.0020.0002] -214A ; [*0577.0020.0002] -214B ; [*0691.0020.0002] -214C ; [*0578.0020.0002] -214F ; [*0579.0020.0002] -2180 ; [*1A4C.0020.0002] -2181 ; [*1A4D.0020.0002] -2182 ; [*1A4E.0020.0002] -2186 ; [*1A4F.0020.0002] -2187 ; [*1A50.0020.0002] -2188 ; [*1A51.0020.0002] -218A ; [*057A.0020.0002] -218B ; [*057B.0020.0002] -2190 ; [*057C.0020.0002] -2191 ; [*057E.0020.0002] -2192 ; [*057D.0020.0002] -2193 ; [*057F.0020.0002] -2194 ; [*0580.0020.0002] -2195 ; [*0581.0020.0002] -2196 ; [*0582.0020.0002] -2197 ; [*0583.0020.0002] -2198 ; [*0584.0020.0002] -2199 ; [*0585.0020.0002] -219A ; [*057C.0020.0002][.0000.002F.0002] -219B ; [*057D.0020.0002][.0000.002F.0002] -219C ; [*0586.0020.0002] -219D ; [*0587.0020.0002] -219E ; [*0588.0020.0002] -219F ; [*0589.0020.0002] -21A0 ; [*058A.0020.0002] -21A1 ; [*058B.0020.0002] -21A2 ; [*058C.0020.0002] -21A3 ; [*058D.0020.0002] -21A4 ; [*058E.0020.0002] -21A5 ; [*058F.0020.0002] -21A6 ; [*0590.0020.0002] -21A7 ; [*0591.0020.0002] -21A8 ; [*0592.0020.0002] -21A9 ; [*0593.0020.0002] -21AA ; [*0594.0020.0002] -21AB ; [*0595.0020.0002] -21AC ; [*0596.0020.0002] -21AD ; [*0597.0020.0002] -21AE ; [*0580.0020.0002][.0000.002F.0002] -21AF ; [*0598.0020.0002] -21B0 ; [*0599.0020.0002] -21B1 ; [*059A.0020.0002] -21B2 ; [*059B.0020.0002] -21B3 ; [*059C.0020.0002] -21B4 ; [*059D.0020.0002] -21B5 ; [*059E.0020.0002] -21B6 ; [*059F.0020.0002] -21B7 ; [*05A0.0020.0002] -21B8 ; [*05A1.0020.0002] -21B9 ; [*05A2.0020.0002] -21BA ; [*05A3.0020.0002] -21BB ; [*05A4.0020.0002] -21BC ; [*05A5.0020.0002] -21BD ; [*05A6.0020.0002] -21BE ; [*05A7.0020.0002] -21BF ; [*05A8.0020.0002] -21C0 ; [*05A9.0020.0002] -21C1 ; [*05AA.0020.0002] -21C2 ; [*05AB.0020.0002] -21C3 ; [*05AC.0020.0002] -21C4 ; [*05AD.0020.0002] -21C5 ; [*05AE.0020.0002] -21C6 ; [*05AF.0020.0002] -21C7 ; [*05B0.0020.0002] -21C8 ; [*05B1.0020.0002] -21C9 ; [*05B2.0020.0002] -21CA ; [*05B3.0020.0002] -21CB ; [*05B4.0020.0002] -21CC ; [*05B5.0020.0002] -21CD ; [*05B6.0020.0002][.0000.002F.0002] -21CE ; [*05BA.0020.0002][.0000.002F.0002] -21CF ; [*05B8.0020.0002][.0000.002F.0002] -21D0 ; [*05B6.0020.0002] -21D1 ; [*05B7.0020.0002] -21D2 ; [*05B8.0020.0002] -21D3 ; [*05B9.0020.0002] -21D4 ; [*05BA.0020.0002] -21D5 ; [*05BB.0020.0002] -21D6 ; [*05BC.0020.0002] -21D7 ; [*05BD.0020.0002] -21D8 ; [*05BE.0020.0002] -21D9 ; [*05BF.0020.0002] -21DA ; [*05C0.0020.0002] -21DB ; [*05C1.0020.0002] -21DC ; [*05C2.0020.0002] -21DD ; [*05C3.0020.0002] -21DE ; [*05C4.0020.0002] -21DF ; [*05C5.0020.0002] -21E0 ; [*05C6.0020.0002] -21E1 ; [*05C7.0020.0002] -21E2 ; [*05C8.0020.0002] -21E3 ; [*05C9.0020.0002] -21E4 ; [*05CA.0020.0002] -21E5 ; [*05CB.0020.0002] -21E6 ; [*05CC.0020.0002] -21E7 ; [*05CD.0020.0002] -21E8 ; [*05CE.0020.0002] -21E9 ; [*05CF.0020.0002] -21EA ; [*05D0.0020.0002] -21EB ; [*05D1.0020.0002] -21EC ; [*05D2.0020.0002] -21ED ; [*05D3.0020.0002] -21EE ; [*05D4.0020.0002] -21EF ; [*05D5.0020.0002] -21F0 ; [*05D6.0020.0002] -21F1 ; [*05D7.0020.0002] -21F2 ; [*05D8.0020.0002] -21F3 ; [*05D9.0020.0002] -21F4 ; [*05DA.0020.0002] -21F5 ; [*05DB.0020.0002] -21F6 ; [*05DC.0020.0002] -21F7 ; [*05DD.0020.0002] -21F8 ; [*05DE.0020.0002] -21F9 ; [*05DF.0020.0002] -21FA ; [*05E0.0020.0002] -21FB ; [*05E1.0020.0002] -21FC ; [*05E2.0020.0002] -21FD ; [*05E3.0020.0002] -21FE ; [*05E4.0020.0002] -21FF ; [*05E5.0020.0002] -2200 ; [*05E6.0020.0002] -2201 ; [*05E7.0020.0002] -2202 ; [*05E8.0020.0002] -2203 ; [*05E9.0020.0002] -2204 ; [*05E9.0020.0002][.0000.002F.0002] -2205 ; [*05EA.0020.0002] -2206 ; [*05EB.0020.0002] -2207 ; [*05EC.0020.0002] -2208 ; [*05ED.0020.0002] -2209 ; [*05ED.0020.0002][.0000.002F.0002] -220A ; [*05EE.0020.0002] -220B ; [*05EF.0020.0002] -220C ; [*05EF.0020.0002][.0000.002F.0002] -220D ; [*05F0.0020.0002] -220E ; [*05F2.0020.0002] -220F ; [*05F3.0020.0002] -2210 ; [*05F4.0020.0002] -2211 ; [*05F5.0020.0002] -2212 ; [*0601.0020.0002] -2213 ; [*0603.0020.0002] -2214 ; [*0604.0020.0002] -2215 ; [*0605.0020.0002] -2216 ; [*0607.0020.0002] -2217 ; [*0608.0020.0002] -2218 ; [*0609.0020.0002] -2219 ; [*060A.0020.0002] -221A ; [*060B.0020.0002] -221B ; [*060C.0020.0002] -221C ; [*060E.0020.0002] -221D ; [*0610.0020.0002] -221E ; [*0611.0020.0002] -221F ; [*0612.0020.0002] -2220 ; [*0613.0020.0002] -2221 ; [*0614.0020.0002] -2222 ; [*0615.0020.0002] -2223 ; [*0616.0020.0002] -2224 ; [*0616.0020.0002][.0000.002F.0002] -2225 ; [*0617.0020.0002] -2226 ; [*0617.0020.0002][.0000.002F.0002] -2227 ; [*0618.0020.0002] -2228 ; [*0619.0020.0002] -2229 ; [*061A.0020.0002] -222A ; [*061B.0020.0002] -222B ; [*061C.0020.0002] -222C ; [*061C.0020.0004][*061C.0020.0004] -222D ; [*061C.0020.0004][*061C.0020.0004][*061C.0020.0004] -222E ; [*061D.0020.0002] -222F ; [*061D.0020.0004][*061D.0020.0004] -2230 ; [*061D.0020.0004][*061D.0020.0004][*061D.0020.0004] -2231 ; [*061E.0020.0002] -2232 ; [*061F.0020.0002] -2233 ; [*0620.0020.0002] -2234 ; [*0621.0020.0002] -2235 ; [*0622.0020.0002] -2236 ; [*0623.0020.0002] -2237 ; [*0624.0020.0002] -2238 ; [*0625.0020.0002] -2239 ; [*0626.0020.0002] -223A ; [*0627.0020.0002] -223B ; [*0628.0020.0002] -223C ; [*0629.0020.0002] -223D ; [*062A.0020.0002] -223E ; [*062B.0020.0002] -223F ; [*062C.0020.0002] -2240 ; [*062D.0020.0002] -2241 ; [*0629.0020.0002][.0000.002F.0002] -2242 ; [*062E.0020.0002] -2243 ; [*062F.0020.0002] -2244 ; [*062F.0020.0002][.0000.002F.0002] -2245 ; [*0630.0020.0002] -2246 ; [*0631.0020.0002] -2247 ; [*0630.0020.0002][.0000.002F.0002] -2248 ; [*0632.0020.0002] -2249 ; [*0632.0020.0002][.0000.002F.0002] -224A ; [*0633.0020.0002] -224B ; [*0634.0020.0002] -224C ; [*0635.0020.0002] -224D ; [*0636.0020.0002] -224E ; [*0637.0020.0002] -224F ; [*0638.0020.0002] -2250 ; [*0639.0020.0002] -2251 ; [*063A.0020.0002] -2252 ; [*063B.0020.0002] -2253 ; [*063C.0020.0002] -2254 ; [*063D.0020.0002] -2255 ; [*063E.0020.0002] -2256 ; [*063F.0020.0002] -2257 ; [*0640.0020.0002] -2258 ; [*0641.0020.0002] -2259 ; [*0642.0020.0002] -225A ; [*0643.0020.0002] -225B ; [*0644.0020.0002] -225C ; [*0645.0020.0002] -225D ; [*0646.0020.0002] -225E ; [*0647.0020.0002] -225F ; [*0648.0020.0002] -2260 ; [*05FB.0020.0002][.0000.002F.0002] -2261 ; [*0649.0020.0002] -2262 ; [*0649.0020.0002][.0000.002F.0002] -2263 ; [*064A.0020.0002] -2264 ; [*064B.0020.0002] -2265 ; [*064C.0020.0002] -2266 ; [*064D.0020.0002] -2267 ; [*064E.0020.0002] -2268 ; [*064F.0020.0002] -2269 ; [*0650.0020.0002] -226A ; [*0651.0020.0002] -226B ; [*0652.0020.0002] -226C ; [*0653.0020.0002] -226D ; [*0636.0020.0002][.0000.002F.0002] -226E ; [*05FA.0020.0002][.0000.002F.0002] -226F ; [*05FC.0020.0002][.0000.002F.0002] -2270 ; [*064B.0020.0002][.0000.002F.0002] -2271 ; [*064C.0020.0002][.0000.002F.0002] -2272 ; [*0654.0020.0002] -2273 ; [*0655.0020.0002] -2274 ; [*0654.0020.0002][.0000.002F.0002] -2275 ; [*0655.0020.0002][.0000.002F.0002] -2276 ; [*0656.0020.0002] -2277 ; [*0657.0020.0002] -2278 ; [*0656.0020.0002][.0000.002F.0002] -2279 ; [*0657.0020.0002][.0000.002F.0002] -227A ; [*0658.0020.0002] -227B ; [*0659.0020.0002] -227C ; [*065A.0020.0002] -227D ; [*065B.0020.0002] -227E ; [*065C.0020.0002] -227F ; [*065D.0020.0002] -2280 ; [*0658.0020.0002][.0000.002F.0002] -2281 ; [*0659.0020.0002][.0000.002F.0002] -2282 ; [*065E.0020.0002] -2283 ; [*065F.0020.0002] -2284 ; [*065E.0020.0002][.0000.002F.0002] -2285 ; [*065F.0020.0002][.0000.002F.0002] -2286 ; [*0660.0020.0002] -2287 ; [*0661.0020.0002] -2288 ; [*0660.0020.0002][.0000.002F.0002] -2289 ; [*0661.0020.0002][.0000.002F.0002] -228A ; [*0662.0020.0002] -228B ; [*0663.0020.0002] -228C ; [*0664.0020.0002] -228D ; [*0665.0020.0002] -228E ; [*0666.0020.0002] -228F ; [*0667.0020.0002] -2290 ; [*0668.0020.0002] -2291 ; [*0669.0020.0002] -2292 ; [*066A.0020.0002] -2293 ; [*066B.0020.0002] -2294 ; [*066C.0020.0002] -2295 ; [*066D.0020.0002] -2296 ; [*066E.0020.0002] -2297 ; [*066F.0020.0002] -2298 ; [*0670.0020.0002] -2299 ; [*0671.0020.0002] -229A ; [*0672.0020.0002] -229B ; [*0673.0020.0002] -229C ; [*0674.0020.0002] -229D ; [*0675.0020.0002] -229E ; [*0676.0020.0002] -229F ; [*0677.0020.0002] -22A0 ; [*0678.0020.0002] -22A1 ; [*0679.0020.0002] -22A2 ; [*067A.0020.0002] -22A3 ; [*067B.0020.0002] -22A4 ; [*067C.0020.0002] -22A5 ; [*067D.0020.0002] -22A6 ; [*067E.0020.0002] -22A7 ; [*067F.0020.0002] -22A8 ; [*0680.0020.0002] -22A9 ; [*0681.0020.0002] -22AA ; [*0682.0020.0002] -22AB ; [*0683.0020.0002] -22AC ; [*067A.0020.0002][.0000.002F.0002] -22AD ; [*0680.0020.0002][.0000.002F.0002] -22AE ; [*0681.0020.0002][.0000.002F.0002] -22AF ; [*0683.0020.0002][.0000.002F.0002] -22B0 ; [*0684.0020.0002] -22B1 ; [*0685.0020.0002] -22B2 ; [*0686.0020.0002] -22B3 ; [*0687.0020.0002] -22B4 ; [*0688.0020.0002] -22B5 ; [*0689.0020.0002] -22B6 ; [*068A.0020.0002] -22B7 ; [*068B.0020.0002] -22B8 ; [*068C.0020.0002] -22B9 ; [*068D.0020.0002] -22BA ; [*068E.0020.0002] -22BB ; [*068F.0020.0002] -22BC ; [*0690.0020.0002] -22BD ; [*0692.0020.0002] -22BE ; [*0693.0020.0002] -22BF ; [*0694.0020.0002] -22C0 ; [*0695.0020.0002] -22C1 ; [*0696.0020.0002] -22C2 ; [*0697.0020.0002] -22C3 ; [*0698.0020.0002] -22C4 ; [*0699.0020.0002] -22C5 ; [*069A.0020.0002] -22C6 ; [*069B.0020.0002] -22C7 ; [*069C.0020.0002] -22C8 ; [*069D.0020.0002] -22C9 ; [*069E.0020.0002] -22CA ; [*069F.0020.0002] -22CB ; [*06A0.0020.0002] -22CC ; [*06A1.0020.0002] -22CD ; [*06A2.0020.0002] -22CE ; [*06A3.0020.0002] -22CF ; [*06A4.0020.0002] -22D0 ; [*06A5.0020.0002] -22D1 ; [*06A6.0020.0002] -22D2 ; [*06A7.0020.0002] -22D3 ; [*06A8.0020.0002] -22D4 ; [*06A9.0020.0002] -22D5 ; [*06AA.0020.0002] -22D6 ; [*06AB.0020.0002] -22D7 ; [*06AC.0020.0002] -22D8 ; [*06AD.0020.0002] -22D9 ; [*06AE.0020.0002] -22DA ; [*06AF.0020.0002] -22DB ; [*06B0.0020.0002] -22DC ; [*06B1.0020.0002] -22DD ; [*06B2.0020.0002] -22DE ; [*06B3.0020.0002] -22DF ; [*06B4.0020.0002] -22E0 ; [*065A.0020.0002][.0000.002F.0002] -22E1 ; [*065B.0020.0002][.0000.002F.0002] -22E2 ; [*0669.0020.0002][.0000.002F.0002] -22E3 ; [*066A.0020.0002][.0000.002F.0002] -22E4 ; [*06B5.0020.0002] -22E5 ; [*06B6.0020.0002] -22E6 ; [*06B7.0020.0002] -22E7 ; [*06B8.0020.0002] -22E8 ; [*06B9.0020.0002] -22E9 ; [*06BA.0020.0002] -22EA ; [*0686.0020.0002][.0000.002F.0002] -22EB ; [*0687.0020.0002][.0000.002F.0002] -22EC ; [*0688.0020.0002][.0000.002F.0002] -22ED ; [*0689.0020.0002][.0000.002F.0002] -22EE ; [*06BB.0020.0002] -22EF ; [*06BC.0020.0002] -22F0 ; [*06BD.0020.0002] -22F1 ; [*06BE.0020.0002] -22F2 ; [*06BF.0020.0002] -22F3 ; [*06C0.0020.0002] -22F4 ; [*06C1.0020.0002] -22F5 ; [*06C2.0020.0002] -22F6 ; [*06C3.0020.0002] -22F7 ; [*06C4.0020.0002] -22F8 ; [*06C5.0020.0002] -22F9 ; [*06C6.0020.0002] -22FA ; [*06C7.0020.0002] -22FB ; [*06C8.0020.0002] -22FC ; [*06C9.0020.0002] -22FD ; [*06CA.0020.0002] -22FE ; [*06CB.0020.0002] -22FF ; [*06CC.0020.0002] -2300 ; [*06CD.0020.0002] -2301 ; [*06CE.0020.0002] -2302 ; [*06CF.0020.0002] -2303 ; [*06D0.0020.0002] -2304 ; [*06D1.0020.0002] -2305 ; [*06D2.0020.0002] -2306 ; [*06D3.0020.0002] -2307 ; [*06D4.0020.0002] -2308 ; [*031E.0020.0002] -2309 ; [*031F.0020.0002] -230A ; [*0320.0020.0002] -230B ; [*0321.0020.0002] -230C ; [*06D5.0020.0002] -230D ; [*06D6.0020.0002] -230E ; [*06D7.0020.0002] -230F ; [*06D8.0020.0002] -2310 ; [*06D9.0020.0002] -2311 ; [*06DA.0020.0002] -2312 ; [*06DB.0020.0002] -2313 ; [*06DC.0020.0002] -2314 ; [*06DD.0020.0002] -2315 ; [*06DE.0020.0002] -2316 ; [*06DF.0020.0002] -2317 ; [*06E0.0020.0002] -2318 ; [*06E1.0020.0002] -2319 ; [*06E2.0020.0002] -231A ; [*06E3.0020.0002] -231B ; [*06E4.0020.0002] -231C ; [*06E5.0020.0002] -231D ; [*06E6.0020.0002] -231E ; [*06E7.0020.0002] -231F ; [*06E8.0020.0002] -2320 ; [*06E9.0020.0002] -2321 ; [*06EA.0020.0002] -2322 ; [*06EB.0020.0002] -2323 ; [*06EC.0020.0002] -2324 ; [*06ED.0020.0002] -2325 ; [*06EE.0020.0002] -2326 ; [*06EF.0020.0002] -2327 ; [*06F0.0020.0002] -2328 ; [*06F1.0020.0002] -2329 ; [*0368.0020.0002] -232A ; [*0369.0020.0002] -232B ; [*06F2.0020.0002] -232C ; [*06F3.0020.0002] -232D ; [*06F4.0020.0002] -232E ; [*06F5.0020.0002] -232F ; [*06F6.0020.0002] -2330 ; [*06F7.0020.0002] -2331 ; [*06F8.0020.0002] -2332 ; [*06F9.0020.0002] -2333 ; [*06FA.0020.0002] -2334 ; [*06FB.0020.0002] -2335 ; [*06FC.0020.0002] -2336 ; [*06FD.0020.0002] -2337 ; [*06FE.0020.0002] -2338 ; [*06FF.0020.0002] -2339 ; [*0700.0020.0002] -233A ; [*0701.0020.0002] -233B ; [*0702.0020.0002] -233C ; [*0703.0020.0002] -233D ; [*0704.0020.0002] -233E ; [*0705.0020.0002] -233F ; [*0706.0020.0002] -2340 ; [*0707.0020.0002] -2341 ; [*0708.0020.0002] -2342 ; [*0709.0020.0002] -2343 ; [*070A.0020.0002] -2344 ; [*070B.0020.0002] -2345 ; [*070C.0020.0002] -2346 ; [*070D.0020.0002] -2347 ; [*070E.0020.0002] -2348 ; [*070F.0020.0002] -2349 ; [*0710.0020.0002] -234A ; [*0711.0020.0002] -234B ; [*0712.0020.0002] -234C ; [*0713.0020.0002] -234D ; [*0714.0020.0002] -234E ; [*0715.0020.0002] -234F ; [*0716.0020.0002] -2350 ; [*0717.0020.0002] -2351 ; [*0718.0020.0002] -2352 ; [*0719.0020.0002] -2353 ; [*071A.0020.0002] -2354 ; [*071B.0020.0002] -2355 ; [*071C.0020.0002] -2356 ; [*071D.0020.0002] -2357 ; [*071E.0020.0002] -2358 ; [*071F.0020.0002] -2359 ; [*0720.0020.0002] -235A ; [*0721.0020.0002] -235B ; [*0722.0020.0002] -235C ; [*0723.0020.0002] -235D ; [*0724.0020.0002] -235E ; [*0725.0020.0002] -235F ; [*0726.0020.0002] -2360 ; [*0727.0020.0002] -2361 ; [*0728.0020.0002] -2362 ; [*0729.0020.0002] -2363 ; [*072A.0020.0002] -2364 ; [*072B.0020.0002] -2365 ; [*072C.0020.0002] -2366 ; [*072D.0020.0002] -2367 ; [*072E.0020.0002] -2368 ; [*072F.0020.0002] -2369 ; [*0730.0020.0002] -236A ; [*0731.0020.0002] -236B ; [*0732.0020.0002] -236C ; [*0733.0020.0002] -236D ; [*0734.0020.0002] -236E ; [*0735.0020.0002] -236F ; [*0736.0020.0002] -2370 ; [*0737.0020.0002] -2371 ; [*0738.0020.0002] -2372 ; [*0739.0020.0002] -2373 ; [*073A.0020.0002] -2374 ; [*073B.0020.0002] -2375 ; [*073C.0020.0002] -2376 ; [*073D.0020.0002] -2377 ; [*073E.0020.0002] -2378 ; [*073F.0020.0002] -2379 ; [*0740.0020.0002] -237A ; [*0741.0020.0002] -237B ; [*0742.0020.0002] -237C ; [*0743.0020.0002] -237D ; [*0744.0020.0002] -237E ; [*0745.0020.0002] -237F ; [*0746.0020.0002] -2380 ; [*0747.0020.0002] -2381 ; [*0748.0020.0002] -2382 ; [*0749.0020.0002] -2383 ; [*074A.0020.0002] -2384 ; [*074B.0020.0002] -2385 ; [*074C.0020.0002] -2386 ; [*074D.0020.0002] -2387 ; [*074E.0020.0002] -2388 ; [*074F.0020.0002] -2389 ; [*0750.0020.0002] -238A ; [*0751.0020.0002] -238B ; [*0752.0020.0002] -238C ; [*0753.0020.0002] -238D ; [*0754.0020.0002] -238E ; [*0755.0020.0002] -238F ; [*0756.0020.0002] -2390 ; [*0757.0020.0002] -2391 ; [*0758.0020.0002] -2392 ; [*0759.0020.0002] -2393 ; [*075A.0020.0002] -2394 ; [*075B.0020.0002] -2395 ; [*075C.0020.0002] -2396 ; [*075D.0020.0002] -2397 ; [*075E.0020.0002] -2398 ; [*075F.0020.0002] -2399 ; [*0760.0020.0002] -239A ; [*0761.0020.0002] -239B ; [*0762.0020.0002] -239C ; [*0763.0020.0002] -239D ; [*0764.0020.0002] -239E ; [*0765.0020.0002] -239F ; [*0766.0020.0002] -23A0 ; [*0767.0020.0002] -23A1 ; [*0768.0020.0002] -23A2 ; [*0769.0020.0002] -23A3 ; [*076A.0020.0002] -23A4 ; [*076B.0020.0002] -23A5 ; [*076C.0020.0002] -23A6 ; [*076D.0020.0002] -23A7 ; [*076E.0020.0002] -23A8 ; [*076F.0020.0002] -23A9 ; [*0770.0020.0002] -23AA ; [*0771.0020.0002] -23AB ; [*0772.0020.0002] -23AC ; [*0773.0020.0002] -23AD ; [*0774.0020.0002] -23AE ; [*0775.0020.0002] -23AF ; [*0776.0020.0002] -23B0 ; [*0777.0020.0002] -23B1 ; [*0778.0020.0002] -23B2 ; [*0779.0020.0002] -23B3 ; [*077A.0020.0002] -23B4 ; [*077B.0020.0002] -23B5 ; [*077C.0020.0002] -23B6 ; [*077D.0020.0002] -23B7 ; [*077E.0020.0002] -23B8 ; [*077F.0020.0002] -23B9 ; [*0780.0020.0002] -23BA ; [*0781.0020.0002] -23BB ; [*0782.0020.0002] -23BC ; [*0783.0020.0002] -23BD ; [*0784.0020.0002] -23BE ; [*0785.0020.0002] -23BF ; [*0786.0020.0002] -23C0 ; [*0787.0020.0002] -23C1 ; [*0788.0020.0002] -23C2 ; [*0789.0020.0002] -23C3 ; [*078A.0020.0002] -23C4 ; [*078B.0020.0002] -23C5 ; [*078C.0020.0002] -23C6 ; [*078D.0020.0002] -23C7 ; [*078E.0020.0002] -23C8 ; [*078F.0020.0002] -23C9 ; [*0790.0020.0002] -23CA ; [*0791.0020.0002] -23CB ; [*0792.0020.0002] -23CC ; [*0793.0020.0002] -23CD ; [*0794.0020.0002] -23CE ; [*0795.0020.0002] -23CF ; [*0796.0020.0002] -23D0 ; [*0797.0020.0002] -23D1 ; [*0798.0020.0002] -23D2 ; [*0799.0020.0002] -23D3 ; [*079A.0020.0002] -23D4 ; [*079B.0020.0002] -23D5 ; [*079C.0020.0002] -23D6 ; [*079D.0020.0002] -23D7 ; [*079E.0020.0002] -23D8 ; [*079F.0020.0002] -23D9 ; [*07A0.0020.0002] -23DA ; [*07A1.0020.0002] -23DB ; [*07A2.0020.0002] -23DC ; [*07A3.0020.0002] -23DD ; [*07A4.0020.0002] -23DE ; [*07A5.0020.0002] -23DF ; [*07A6.0020.0002] -23E0 ; [*07A7.0020.0002] -23E1 ; [*07A8.0020.0002] -23E2 ; [*07A9.0020.0002] -23E3 ; [*07AA.0020.0002] -23E4 ; [*07AB.0020.0002] -23E5 ; [*07AC.0020.0002] -23E6 ; [*07AD.0020.0002] -23E7 ; [*07AE.0020.0002] -23E8 ; [*07AF.0020.0002] -23E9 ; [*07B0.0020.0002] -23EA ; [*07B1.0020.0002] -23EB ; [*07B2.0020.0002] -23EC ; [*07B3.0020.0002] -23ED ; [*07B4.0020.0002] -23EE ; [*07B5.0020.0002] -23EF ; [*07B6.0020.0002] -23F0 ; [*07B7.0020.0002] -23F1 ; [*07B8.0020.0002] -23F2 ; [*07B9.0020.0002] -23F3 ; [*07BA.0020.0002] -23F4 ; [*07BB.0020.0002] -23F5 ; [*07BC.0020.0002] -23F6 ; [*07BD.0020.0002] -23F7 ; [*07BE.0020.0002] -23F8 ; [*07BF.0020.0002] -23F9 ; [*07C0.0020.0002] -23FA ; [*07C1.0020.0002] -2400 ; [*07C2.0020.0002] -2401 ; [*07C3.0020.0002] -2402 ; [*07C4.0020.0002] -2403 ; [*07C5.0020.0002] -2404 ; [*07C6.0020.0002] -2405 ; [*07C7.0020.0002] -2406 ; [*07C8.0020.0002] -2407 ; [*07C9.0020.0002] -2408 ; [*07CA.0020.0002] -2409 ; [*07CB.0020.0002] -240A ; [*07CC.0020.0002] -240B ; [*07CD.0020.0002] -240C ; [*07CE.0020.0002] -240D ; [*07CF.0020.0002] -240E ; [*07D0.0020.0002] -240F ; [*07D1.0020.0002] -2410 ; [*07D2.0020.0002] -2411 ; [*07D3.0020.0002] -2412 ; [*07D4.0020.0002] -2413 ; [*07D5.0020.0002] -2414 ; [*07D6.0020.0002] -2415 ; [*07D7.0020.0002] -2416 ; [*07D8.0020.0002] -2417 ; [*07D9.0020.0002] -2418 ; [*07DA.0020.0002] -2419 ; [*07DB.0020.0002] -241A ; [*07DC.0020.0002] -241B ; [*07DD.0020.0002] -241C ; [*07DE.0020.0002] -241D ; [*07DF.0020.0002] -241E ; [*07E0.0020.0002] -241F ; [*07E1.0020.0002] -2420 ; [*07E2.0020.0002] -2421 ; [*07E3.0020.0002] -2422 ; [*07E4.0020.0002] -2423 ; [*07E5.0020.0002] -2424 ; [*07E6.0020.0002] -2425 ; [*07E7.0020.0002] -2426 ; [*07E8.0020.0002] -2440 ; [*07E9.0020.0002] -2441 ; [*07EA.0020.0002] -2442 ; [*07EB.0020.0002] -2443 ; [*07EC.0020.0002] -2444 ; [*07ED.0020.0002] -2445 ; [*07EE.0020.0002] -2446 ; [*07EF.0020.0002] -2447 ; [*07F0.0020.0002] -2448 ; [*07F1.0020.0002] -2449 ; [*07F2.0020.0002] -244A ; [*07F3.0020.0002] -2500 ; [*07F4.0020.0002] -2501 ; [*07F5.0020.0002] -2502 ; [*07F6.0020.0002] -2503 ; [*07F7.0020.0002] -2504 ; [*07F8.0020.0002] -2505 ; [*07F9.0020.0002] -2506 ; [*07FA.0020.0002] -2507 ; [*07FB.0020.0002] -2508 ; [*07FC.0020.0002] -2509 ; [*07FD.0020.0002] -250A ; [*07FE.0020.0002] -250B ; [*07FF.0020.0002] -250C ; [*0800.0020.0002] -250D ; [*0801.0020.0002] -250E ; [*0802.0020.0002] -250F ; [*0803.0020.0002] -2510 ; [*0804.0020.0002] -2511 ; [*0805.0020.0002] -2512 ; [*0806.0020.0002] -2513 ; [*0807.0020.0002] -2514 ; [*0808.0020.0002] -2515 ; [*0809.0020.0002] -2516 ; [*080A.0020.0002] -2517 ; [*080B.0020.0002] -2518 ; [*080C.0020.0002] -2519 ; [*080D.0020.0002] -251A ; [*080E.0020.0002] -251B ; [*080F.0020.0002] -251C ; [*0810.0020.0002] -251D ; [*0811.0020.0002] -251E ; [*0812.0020.0002] -251F ; [*0813.0020.0002] -2520 ; [*0814.0020.0002] -2521 ; [*0815.0020.0002] -2522 ; [*0816.0020.0002] -2523 ; [*0817.0020.0002] -2524 ; [*0818.0020.0002] -2525 ; [*0819.0020.0002] -2526 ; [*081A.0020.0002] -2527 ; [*081B.0020.0002] -2528 ; [*081C.0020.0002] -2529 ; [*081D.0020.0002] -252A ; [*081E.0020.0002] -252B ; [*081F.0020.0002] -252C ; [*0820.0020.0002] -252D ; [*0821.0020.0002] -252E ; [*0822.0020.0002] -252F ; [*0823.0020.0002] -2530 ; [*0824.0020.0002] -2531 ; [*0825.0020.0002] -2532 ; [*0826.0020.0002] -2533 ; [*0827.0020.0002] -2534 ; [*0828.0020.0002] -2535 ; [*0829.0020.0002] -2536 ; [*082A.0020.0002] -2537 ; [*082B.0020.0002] -2538 ; [*082C.0020.0002] -2539 ; [*082D.0020.0002] -253A ; [*082E.0020.0002] -253B ; [*082F.0020.0002] -253C ; [*0830.0020.0002] -253D ; [*0831.0020.0002] -253E ; [*0832.0020.0002] -253F ; [*0833.0020.0002] -2540 ; [*0834.0020.0002] -2541 ; [*0835.0020.0002] -2542 ; [*0836.0020.0002] -2543 ; [*0837.0020.0002] -2544 ; [*0838.0020.0002] -2545 ; [*0839.0020.0002] -2546 ; [*083A.0020.0002] -2547 ; [*083B.0020.0002] -2548 ; [*083C.0020.0002] -2549 ; [*083D.0020.0002] -254A ; [*083E.0020.0002] -254B ; [*083F.0020.0002] -254C ; [*0840.0020.0002] -254D ; [*0841.0020.0002] -254E ; [*0842.0020.0002] -254F ; [*0843.0020.0002] -2550 ; [*0844.0020.0002] -2551 ; [*0845.0020.0002] -2552 ; [*0846.0020.0002] -2553 ; [*0847.0020.0002] -2554 ; [*0848.0020.0002] -2555 ; [*0849.0020.0002] -2556 ; [*084A.0020.0002] -2557 ; [*084B.0020.0002] -2558 ; [*084C.0020.0002] -2559 ; [*084D.0020.0002] -255A ; [*084E.0020.0002] -255B ; [*084F.0020.0002] -255C ; [*0850.0020.0002] -255D ; [*0851.0020.0002] -255E ; [*0852.0020.0002] -255F ; [*0853.0020.0002] -2560 ; [*0854.0020.0002] -2561 ; [*0855.0020.0002] -2562 ; [*0856.0020.0002] -2563 ; [*0857.0020.0002] -2564 ; [*0858.0020.0002] -2565 ; [*0859.0020.0002] -2566 ; [*085A.0020.0002] -2567 ; [*085B.0020.0002] -2568 ; [*085C.0020.0002] -2569 ; [*085D.0020.0002] -256A ; [*085E.0020.0002] -256B ; [*085F.0020.0002] -256C ; [*0860.0020.0002] -256D ; [*0861.0020.0002] -256E ; [*0862.0020.0002] -256F ; [*0863.0020.0002] -2570 ; [*0864.0020.0002] -2571 ; [*0865.0020.0002] -2572 ; [*0866.0020.0002] -2573 ; [*0867.0020.0002] -2574 ; [*0868.0020.0002] -2575 ; [*0869.0020.0002] -2576 ; [*086A.0020.0002] -2577 ; [*086B.0020.0002] -2578 ; [*086C.0020.0002] -2579 ; [*086D.0020.0002] -257A ; [*086E.0020.0002] -257B ; [*086F.0020.0002] -257C ; [*0870.0020.0002] -257D ; [*0871.0020.0002] -257E ; [*0872.0020.0002] -257F ; [*0873.0020.0002] -2580 ; [*0874.0020.0002] -2581 ; [*0875.0020.0002] -2582 ; [*0876.0020.0002] -2583 ; [*0877.0020.0002] -2584 ; [*0878.0020.0002] -2585 ; [*0879.0020.0002] -2586 ; [*087A.0020.0002] -2587 ; [*087B.0020.0002] -2588 ; [*087C.0020.0002] -2589 ; [*087D.0020.0002] -258A ; [*087E.0020.0002] -258B ; [*087F.0020.0002] -258C ; [*0880.0020.0002] -258D ; [*0881.0020.0002] -258E ; [*0882.0020.0002] -258F ; [*0883.0020.0002] -2590 ; [*0884.0020.0002] -2591 ; [*0885.0020.0002] -2592 ; [*0886.0020.0002] -2593 ; [*0887.0020.0002] -2594 ; [*0888.0020.0002] -2595 ; [*0889.0020.0002] -2596 ; [*088A.0020.0002] -2597 ; [*088B.0020.0002] -2598 ; [*088C.0020.0002] -2599 ; [*088D.0020.0002] -259A ; [*088E.0020.0002] -259B ; [*088F.0020.0002] -259C ; [*0890.0020.0002] -259D ; [*0891.0020.0002] -259E ; [*0892.0020.0002] -259F ; [*0893.0020.0002] -25A0 ; [*0894.0020.0002] -25A1 ; [*0895.0020.0002] -25A2 ; [*0896.0020.0002] -25A3 ; [*0897.0020.0002] -25A4 ; [*0898.0020.0002] -25A5 ; [*0899.0020.0002] -25A6 ; [*089A.0020.0002] -25A7 ; [*089B.0020.0002] -25A8 ; [*089C.0020.0002] -25A9 ; [*089D.0020.0002] -25AA ; [*089E.0020.0002] -25AB ; [*089F.0020.0002] -25AC ; [*08A0.0020.0002] -25AD ; [*08A1.0020.0002] -25AE ; [*08A2.0020.0002] -25AF ; [*08A3.0020.0002] -25B0 ; [*08A4.0020.0002] -25B1 ; [*08A5.0020.0002] -25B2 ; [*08A6.0020.0002] -25B3 ; [*08A7.0020.0002] -25B4 ; [*08A8.0020.0002] -25B5 ; [*08A9.0020.0002] -25B6 ; [*08AA.0020.0002] -25B7 ; [*08AB.0020.0002] -25B8 ; [*08AC.0020.0002] -25B9 ; [*08AD.0020.0002] -25BA ; [*08AE.0020.0002] -25BB ; [*08AF.0020.0002] -25BC ; [*08B0.0020.0002] -25BD ; [*08B1.0020.0002] -25BE ; [*08B2.0020.0002] -25BF ; [*08B3.0020.0002] -25C0 ; [*08B4.0020.0002] -25C1 ; [*08B5.0020.0002] -25C2 ; [*08B6.0020.0002] -25C3 ; [*08B7.0020.0002] -25C4 ; [*08B8.0020.0002] -25C5 ; [*08B9.0020.0002] -25C6 ; [*08BA.0020.0002] -25C7 ; [*08BB.0020.0002] -25C8 ; [*08BC.0020.0002] -25C9 ; [*08BD.0020.0002] -25CA ; [*08BE.0020.0002] -25CB ; [*08BF.0020.0002] -25CC ; [*08C0.0020.0002] -25CD ; [*08C1.0020.0002] -25CE ; [*08C2.0020.0002] -25CF ; [*08C3.0020.0002] -25D0 ; [*08C4.0020.0002] -25D1 ; [*08C5.0020.0002] -25D2 ; [*08C6.0020.0002] -25D3 ; [*08C7.0020.0002] -25D4 ; [*08C8.0020.0002] -25D5 ; [*08C9.0020.0002] -25D6 ; [*08CA.0020.0002] -25D7 ; [*08CB.0020.0002] -25D8 ; [*08CC.0020.0002] -25D9 ; [*08CD.0020.0002] -25DA ; [*08CE.0020.0002] -25DB ; [*08CF.0020.0002] -25DC ; [*08D0.0020.0002] -25DD ; [*08D1.0020.0002] -25DE ; [*08D2.0020.0002] -25DF ; [*08D3.0020.0002] -25E0 ; [*08D4.0020.0002] -25E1 ; [*08D5.0020.0002] -25E2 ; [*08D6.0020.0002] -25E3 ; [*08D7.0020.0002] -25E4 ; [*08D8.0020.0002] -25E5 ; [*08D9.0020.0002] -25E6 ; [*08DA.0020.0002] -25E7 ; [*08DB.0020.0002] -25E8 ; [*08DC.0020.0002] -25E9 ; [*08DD.0020.0002] -25EA ; [*08DE.0020.0002] -25EB ; [*08DF.0020.0002] -25EC ; [*08E0.0020.0002] -25ED ; [*08E1.0020.0002] -25EE ; [*08E2.0020.0002] -25EF ; [*08E3.0020.0002] -25F0 ; [*08E4.0020.0002] -25F1 ; [*08E5.0020.0002] -25F2 ; [*08E6.0020.0002] -25F3 ; [*08E7.0020.0002] -25F4 ; [*08E8.0020.0002] -25F5 ; [*08E9.0020.0002] -25F6 ; [*08EA.0020.0002] -25F7 ; [*08EB.0020.0002] -25F8 ; [*08EC.0020.0002] -25F9 ; [*08ED.0020.0002] -25FA ; [*08EE.0020.0002] -25FB ; [*08EF.0020.0002] -25FC ; [*08F0.0020.0002] -25FD ; [*08F1.0020.0002] -25FE ; [*08F2.0020.0002] -25FF ; [*08F3.0020.0002] -2600 ; [*08F4.0020.0002] -2601 ; [*08F5.0020.0002] -2602 ; [*08F6.0020.0002] -2603 ; [*08F7.0020.0002] -2604 ; [*08F8.0020.0002] -2605 ; [*08F9.0020.0002] -2606 ; [*08FA.0020.0002] -2607 ; [*08FB.0020.0002] -2608 ; [*08FC.0020.0002] -2609 ; [*08FD.0020.0002] -260A ; [*08FE.0020.0002] -260B ; [*08FF.0020.0002] -260C ; [*0900.0020.0002] -260D ; [*0901.0020.0002] -260E ; [*0902.0020.0002] -260F ; [*0903.0020.0002] -2610 ; [*0904.0020.0002] -2611 ; [*0905.0020.0002] -2612 ; [*0906.0020.0002] -2613 ; [*0907.0020.0002] -2614 ; [*0908.0020.0002] -2615 ; [*0909.0020.0002] -2616 ; [*090A.0020.0002] -2617 ; [*090B.0020.0002] -2618 ; [*090C.0020.0002] -2619 ; [*090D.0020.0002] -261A ; [*090E.0020.0002] -261B ; [*090F.0020.0002] -261C ; [*0910.0020.0002] -261D ; [*0911.0020.0002] -261E ; [*0912.0020.0002] -261F ; [*0913.0020.0002] -2620 ; [*0914.0020.0002] -2621 ; [*0915.0020.0002] -2622 ; [*0916.0020.0002] -2623 ; [*0917.0020.0002] -2624 ; [*0918.0020.0002] -2625 ; [*0919.0020.0002] -2626 ; [*091A.0020.0002] -2627 ; [*091B.0020.0002] -2628 ; [*091C.0020.0002] -2629 ; [*091D.0020.0002] -262A ; [*091E.0020.0002] -262B ; [*091F.0020.0002] -262C ; [*0920.0020.0002] -262D ; [*0921.0020.0002] -262E ; [*0922.0020.0002] -262F ; [*0923.0020.0002] -2630 ; [*0E7E.0020.0002] -2631 ; [*0E7F.0020.0002] -2632 ; [*0E80.0020.0002] -2633 ; [*0E81.0020.0002] -2634 ; [*0E82.0020.0002] -2635 ; [*0E83.0020.0002] -2636 ; [*0E84.0020.0002] -2637 ; [*0E85.0020.0002] -2638 ; [*0924.0020.0002] -2639 ; [*0925.0020.0002] -263A ; [*0926.0020.0002] -263B ; [*0927.0020.0002] -263C ; [*0928.0020.0002] -263D ; [*0929.0020.0002] -263E ; [*092A.0020.0002] -263F ; [*092B.0020.0002] -2640 ; [*092C.0020.0002] -2641 ; [*092D.0020.0002] -2642 ; [*092E.0020.0002] -2643 ; [*092F.0020.0002] -2644 ; [*0930.0020.0002] -2645 ; [*0931.0020.0002] -2646 ; [*0932.0020.0002] -2647 ; [*0933.0020.0002] -2648 ; [*0934.0020.0002] -2649 ; [*0935.0020.0002] -264A ; [*0936.0020.0002] -264B ; [*0937.0020.0002] -264C ; [*0938.0020.0002] -264D ; [*0939.0020.0002] -264E ; [*093A.0020.0002] -264F ; [*093B.0020.0002] -2650 ; [*093C.0020.0002] -2651 ; [*093D.0020.0002] -2652 ; [*093E.0020.0002] -2653 ; [*093F.0020.0002] -2654 ; [*0940.0020.0002] -2655 ; [*0941.0020.0002] -2656 ; [*0942.0020.0002] -2657 ; [*0943.0020.0002] -2658 ; [*0944.0020.0002] -2659 ; [*0945.0020.0002] -265A ; [*0946.0020.0002] -265B ; [*0947.0020.0002] -265C ; [*0948.0020.0002] -265D ; [*0949.0020.0002] -265E ; [*094A.0020.0002] -265F ; [*094B.0020.0002] -2660 ; [*094C.0020.0002] -2661 ; [*094D.0020.0002] -2662 ; [*094E.0020.0002] -2663 ; [*094F.0020.0002] -2664 ; [*0950.0020.0002] -2665 ; [*0951.0020.0002] -2666 ; [*0952.0020.0002] -2667 ; [*0953.0020.0002] -2668 ; [*0954.0020.0002] -2669 ; [*0955.0020.0002] -266A ; [*0956.0020.0002] -266B ; [*0957.0020.0002] -266C ; [*0958.0020.0002] -266D ; [*10CD.0020.0002] -266E ; [*10CE.0020.0002] -266F ; [*10CF.0020.0002] -2670 ; [*0959.0020.0002] -2671 ; [*095A.0020.0002] -2672 ; [*095B.0020.0002] -2673 ; [*095C.0020.0002] -2674 ; [*095D.0020.0002] -2675 ; [*095E.0020.0002] -2676 ; [*095F.0020.0002] -2677 ; [*0960.0020.0002] -2678 ; [*0961.0020.0002] -2679 ; [*0962.0020.0002] -267A ; [*0963.0020.0002] -267B ; [*0964.0020.0002] -267C ; [*0965.0020.0002] -267D ; [*0966.0020.0002] -267E ; [*0967.0020.0002] -267F ; [*0968.0020.0002] -2680 ; [*0969.0020.0002] -2681 ; [*096A.0020.0002] -2682 ; [*096B.0020.0002] -2683 ; [*096C.0020.0002] -2684 ; [*096D.0020.0002] -2685 ; [*096E.0020.0002] -2686 ; [*096F.0020.0002] -2687 ; [*0970.0020.0002] -2688 ; [*0971.0020.0002] -2689 ; [*0972.0020.0002] -268A ; [*0E78.0020.0002] -268B ; [*0E79.0020.0002] -268C ; [*0E7A.0020.0002] -268D ; [*0E7B.0020.0002] -268E ; [*0E7C.0020.0002] -268F ; [*0E7D.0020.0002] -2690 ; [*0973.0020.0002] -2691 ; [*0974.0020.0002] -2692 ; [*0975.0020.0002] -2693 ; [*0976.0020.0002] -2694 ; [*0977.0020.0002] -2695 ; [*0978.0020.0002] -2696 ; [*0979.0020.0002] -2697 ; [*097A.0020.0002] -2698 ; [*097B.0020.0002] -2699 ; [*097C.0020.0002] -269A ; [*097D.0020.0002] -269B ; [*097E.0020.0002] -269C ; [*097F.0020.0002] -269D ; [*0980.0020.0002] -269E ; [*0981.0020.0002] -269F ; [*0982.0020.0002] -26A0 ; [*0983.0020.0002] -26A1 ; [*0984.0020.0002] -26A2 ; [*0985.0020.0002] -26A3 ; [*0986.0020.0002] -26A4 ; [*0987.0020.0002] -26A5 ; [*0988.0020.0002] -26A6 ; [*0989.0020.0002] -26A7 ; [*098A.0020.0002] -26A8 ; [*098B.0020.0002] -26A9 ; [*098C.0020.0002] -26AA ; [*098D.0020.0002] -26AB ; [*098E.0020.0002] -26AC ; [*098F.0020.0002] -26AD ; [*0990.0020.0002] -26AE ; [*0991.0020.0002] -26AF ; [*0992.0020.0002] -26B0 ; [*0993.0020.0002] -26B1 ; [*0994.0020.0002] -26B2 ; [*0995.0020.0002] -26B3 ; [*0996.0020.0002] -26B4 ; [*0997.0020.0002] -26B5 ; [*0998.0020.0002] -26B6 ; [*0999.0020.0002] -26B7 ; [*099A.0020.0002] -26B8 ; [*099B.0020.0002] -26B9 ; [*099C.0020.0002] -26BA ; [*099D.0020.0002] -26BB ; [*099E.0020.0002] -26BC ; [*099F.0020.0002] -26BD ; [*09A0.0020.0002] -26BE ; [*09A1.0020.0002] -26BF ; [*09A2.0020.0002] -26C0 ; [*09A3.0020.0002] -26C1 ; [*09A4.0020.0002] -26C2 ; [*09A5.0020.0002] -26C3 ; [*09A6.0020.0002] -26C4 ; [*09A7.0020.0002] -26C5 ; [*09A8.0020.0002] -26C6 ; [*09A9.0020.0002] -26C7 ; [*09AA.0020.0002] -26C8 ; [*09AB.0020.0002] -26C9 ; [*09AC.0020.0002] -26CA ; [*09AD.0020.0002] -26CB ; [*09AE.0020.0002] -26CC ; [*09AF.0020.0002] -26CD ; [*09B0.0020.0002] -26CE ; [*09B1.0020.0002] -26CF ; [*09B2.0020.0002] -26D0 ; [*09B3.0020.0002] -26D1 ; [*09B4.0020.0002] -26D2 ; [*09B5.0020.0002] -26D3 ; [*09B6.0020.0002] -26D4 ; [*09B7.0020.0002] -26D5 ; [*09B8.0020.0002] -26D6 ; [*09B9.0020.0002] -26D7 ; [*09BA.0020.0002] -26D8 ; [*09BB.0020.0002] -26D9 ; [*09BC.0020.0002] -26DA ; [*09BD.0020.0002] -26DB ; [*09BE.0020.0002] -26DC ; [*09BF.0020.0002] -26DD ; [*09C0.0020.0002] -26DE ; [*09C1.0020.0002] -26DF ; [*09C2.0020.0002] -26E0 ; [*09C3.0020.0002] -26E1 ; [*09C4.0020.0002] -26E2 ; [*09C5.0020.0002] -26E3 ; [*09C6.0020.0002] -26E4 ; [*09C7.0020.0002] -26E5 ; [*09C8.0020.0002] -26E6 ; [*09C9.0020.0002] -26E7 ; [*09CA.0020.0002] -26E8 ; [*09CB.0020.0002] -26E9 ; [*09CC.0020.0002] -26EA ; [*09CD.0020.0002] -26EB ; [*09CE.0020.0002] -26EC ; [*09CF.0020.0002] -26ED ; [*09D0.0020.0002] -26EE ; [*09D1.0020.0002] -26EF ; [*09D2.0020.0002] -26F0 ; [*09D3.0020.0002] -26F1 ; [*09D4.0020.0002] -26F2 ; [*09D5.0020.0002] -26F3 ; [*09D6.0020.0002] -26F4 ; [*09D7.0020.0002] -26F5 ; [*09D8.0020.0002] -26F6 ; [*09D9.0020.0002] -26F7 ; [*09DA.0020.0002] -26F8 ; [*09DB.0020.0002] -26F9 ; [*09DC.0020.0002] -26FA ; [*09DD.0020.0002] -26FB ; [*09DE.0020.0002] -26FC ; [*09DF.0020.0002] -26FD ; [*09E0.0020.0002] -26FE ; [*09E1.0020.0002] -26FF ; [*09E2.0020.0002] -2700 ; [*09FD.0020.0002] -2701 ; [*09FE.0020.0002] -2702 ; [*09FF.0020.0002] -2703 ; [*0A00.0020.0002] -2704 ; [*0A01.0020.0002] -2705 ; [*0A02.0020.0002] -2706 ; [*0A03.0020.0002] -2707 ; [*0A04.0020.0002] -2708 ; [*0A05.0020.0002] -2709 ; [*0A06.0020.0002] -270A ; [*0A07.0020.0002] -270B ; [*0A08.0020.0002] -270C ; [*0A09.0020.0002] -270D ; [*0A0A.0020.0002] -270E ; [*0A0B.0020.0002] -270F ; [*0A0C.0020.0002] -2710 ; [*0A0D.0020.0002] -2711 ; [*0A0E.0020.0002] -2712 ; [*0A0F.0020.0002] -2713 ; [*0A10.0020.0002] -2714 ; [*0A11.0020.0002] -2715 ; [*0A12.0020.0002] -2716 ; [*0A13.0020.0002] -2717 ; [*0A14.0020.0002] -2718 ; [*0A15.0020.0002] -2719 ; [*0A16.0020.0002] -271A ; [*0A17.0020.0002] -271B ; [*0A18.0020.0002] -271C ; [*0A19.0020.0002] -271D ; [*0A1A.0020.0002] -271E ; [*0A1B.0020.0002] -271F ; [*0A1C.0020.0002] -2720 ; [*0A1D.0020.0002] -2721 ; [*0A1E.0020.0002] -2722 ; [*0A1F.0020.0002] -2723 ; [*0A20.0020.0002] -2724 ; [*0A21.0020.0002] -2725 ; [*0A22.0020.0002] -2726 ; [*0A23.0020.0002] -2727 ; [*0A24.0020.0002] -2728 ; [*0A25.0020.0002] -2729 ; [*0A26.0020.0002] -272A ; [*0A27.0020.0002] -272B ; [*0A28.0020.0002] -272C ; [*0A29.0020.0002] -272D ; [*0A2A.0020.0002] -272E ; [*0A2B.0020.0002] -272F ; [*0A2C.0020.0002] -2730 ; [*0A2D.0020.0002] -2731 ; [*0A2E.0020.0002] -2732 ; [*0A2F.0020.0002] -2733 ; [*0A30.0020.0002] -2734 ; [*0A31.0020.0002] -2735 ; [*0A32.0020.0002] -2736 ; [*0A33.0020.0002] -2737 ; [*0A34.0020.0002] -2738 ; [*0A35.0020.0002] -2739 ; [*0A36.0020.0002] -273A ; [*0A37.0020.0002] -273B ; [*0A38.0020.0002] -273C ; [*0A39.0020.0002] -273D ; [*0A3A.0020.0002] -273E ; [*0A3B.0020.0002] -273F ; [*0A3C.0020.0002] -2740 ; [*0A3D.0020.0002] -2741 ; [*0A3E.0020.0002] -2742 ; [*0A3F.0020.0002] -2743 ; [*0A40.0020.0002] -2744 ; [*0A41.0020.0002] -2745 ; [*0A42.0020.0002] -2746 ; [*0A43.0020.0002] -2747 ; [*0A44.0020.0002] -2748 ; [*0A45.0020.0002] -2749 ; [*0A46.0020.0002] -274A ; [*0A47.0020.0002] -274B ; [*0A48.0020.0002] -274C ; [*0A49.0020.0002] -274D ; [*0A4A.0020.0002] -274E ; [*0A4B.0020.0002] -274F ; [*0A4C.0020.0002] -2750 ; [*0A4D.0020.0002] -2751 ; [*0A4E.0020.0002] -2752 ; [*0A4F.0020.0002] -2753 ; [*0A50.0020.0002] -2754 ; [*0A51.0020.0002] -2755 ; [*0A52.0020.0002] -2756 ; [*0A53.0020.0002] -2757 ; [*0A54.0020.0002] -2758 ; [*0A55.0020.0002] -2759 ; [*0A56.0020.0002] -275A ; [*0A57.0020.0002] -275B ; [*0A58.0020.0002] -275C ; [*0A59.0020.0002] -275D ; [*0A5A.0020.0002] -275E ; [*0A5B.0020.0002] -275F ; [*0A5C.0020.0002] -2760 ; [*0A5D.0020.0002] -2761 ; [*0A5E.0020.0002] -2762 ; [*0A5F.0020.0002] -2763 ; [*0A60.0020.0002] -2764 ; [*0A61.0020.0002] -2765 ; [*0A62.0020.0002] -2766 ; [*0A63.0020.0002] -2767 ; [*0A64.0020.0002] -2768 ; [*0346.0020.0002] -2769 ; [*0347.0020.0002] -276A ; [*0348.0020.0002] -276B ; [*0349.0020.0002] -276C ; [*034A.0020.0002] -276D ; [*034B.0020.0002] -276E ; [*034C.0020.0002] -276F ; [*034D.0020.0002] -2770 ; [*034E.0020.0002] -2771 ; [*034F.0020.0002] -2772 ; [*0350.0020.0002] -2773 ; [*0351.0020.0002] -2774 ; [*0352.0020.0002] -2775 ; [*0353.0020.0002] -2794 ; [*0A65.0020.0002] -2795 ; [*0A66.0020.0002] -2796 ; [*0A67.0020.0002] -2797 ; [*0A68.0020.0002] -2798 ; [*0A69.0020.0002] -2799 ; [*0A6A.0020.0002] -279A ; [*0A6B.0020.0002] -279B ; [*0A6C.0020.0002] -279C ; [*0A6D.0020.0002] -279D ; [*0A6E.0020.0002] -279E ; [*0A6F.0020.0002] -279F ; [*0A70.0020.0002] -27A0 ; [*0A71.0020.0002] -27A1 ; [*0A72.0020.0002] -27A2 ; [*0A73.0020.0002] -27A3 ; [*0A74.0020.0002] -27A4 ; [*0A75.0020.0002] -27A5 ; [*0A76.0020.0002] -27A6 ; [*0A77.0020.0002] -27A7 ; [*0A78.0020.0002] -27A8 ; [*0A79.0020.0002] -27A9 ; [*0A7A.0020.0002] -27AA ; [*0A7B.0020.0002] -27AB ; [*0A7C.0020.0002] -27AC ; [*0A7D.0020.0002] -27AD ; [*0A7E.0020.0002] -27AE ; [*0A7F.0020.0002] -27AF ; [*0A80.0020.0002] -27B0 ; [*0A81.0020.0002] -27B1 ; [*0A82.0020.0002] -27B2 ; [*0A83.0020.0002] -27B3 ; [*0A84.0020.0002] -27B4 ; [*0A85.0020.0002] -27B5 ; [*0A86.0020.0002] -27B6 ; [*0A87.0020.0002] -27B7 ; [*0A88.0020.0002] -27B8 ; [*0A89.0020.0002] -27B9 ; [*0A8A.0020.0002] -27BA ; [*0A8B.0020.0002] -27BB ; [*0A8C.0020.0002] -27BC ; [*0A8D.0020.0002] -27BD ; [*0A8E.0020.0002] -27BE ; [*0A8F.0020.0002] -27BF ; [*0A90.0020.0002] -27C0 ; [*0A91.0020.0002] -27C1 ; [*0A92.0020.0002] -27C2 ; [*0A93.0020.0002] -27C3 ; [*0A94.0020.0002] -27C4 ; [*0A95.0020.0002] -27C5 ; [*033A.0020.0002] -27C6 ; [*033B.0020.0002] -27C7 ; [*0A96.0020.0002] -27C8 ; [*0A97.0020.0002] -27C9 ; [*0A98.0020.0002] -27CA ; [*0A99.0020.0002] -27CB ; [*0A9A.0020.0002] -27CC ; [*0A9B.0020.0002] -27CD ; [*0A9C.0020.0002] -27CE ; [*0A9D.0020.0002] -27CF ; [*0A9E.0020.0002] -27D0 ; [*0A9F.0020.0002] -27D1 ; [*0AA0.0020.0002] -27D2 ; [*0AA1.0020.0002] -27D3 ; [*0AA2.0020.0002] -27D4 ; [*0AA3.0020.0002] -27D5 ; [*0AA4.0020.0002] -27D6 ; [*0AA5.0020.0002] -27D7 ; [*0AA6.0020.0002] -27D8 ; [*0AA7.0020.0002] -27D9 ; [*0AA8.0020.0002] -27DA ; [*0AA9.0020.0002] -27DB ; [*0AAA.0020.0002] -27DC ; [*0AAB.0020.0002] -27DD ; [*0AAC.0020.0002] -27DE ; [*0AAD.0020.0002] -27DF ; [*0AAE.0020.0002] -27E0 ; [*0AAF.0020.0002] -27E1 ; [*0AB0.0020.0002] -27E2 ; [*0AB1.0020.0002] -27E3 ; [*0AB2.0020.0002] -27E4 ; [*0AB3.0020.0002] -27E5 ; [*0AB4.0020.0002] -27E6 ; [*033C.0020.0002] -27E7 ; [*033D.0020.0002] -27E8 ; [*033E.0020.0002] -27E9 ; [*033F.0020.0002] -27EA ; [*0340.0020.0002] -27EB ; [*0341.0020.0002] -27EC ; [*0342.0020.0002] -27ED ; [*0343.0020.0002] -27EE ; [*0344.0020.0002] -27EF ; [*0345.0020.0002] -27F0 ; [*0AB5.0020.0002] -27F1 ; [*0AB6.0020.0002] -27F2 ; [*0AB7.0020.0002] -27F3 ; [*0AB8.0020.0002] -27F4 ; [*0AB9.0020.0002] -27F5 ; [*0ABA.0020.0002] -27F6 ; [*0ABB.0020.0002] -27F7 ; [*0ABC.0020.0002] -27F8 ; [*0ABD.0020.0002] -27F9 ; [*0ABE.0020.0002] -27FA ; [*0ABF.0020.0002] -27FB ; [*0AC0.0020.0002] -27FC ; [*0AC1.0020.0002] -27FD ; [*0AC2.0020.0002] -27FE ; [*0AC3.0020.0002] -27FF ; [*0AC4.0020.0002] -2800 ; [*0D78.0020.0002] -2801 ; [*0D79.0020.0002] -2802 ; [*0D7A.0020.0002] -2803 ; [*0D7B.0020.0002] -2804 ; [*0D7C.0020.0002] -2805 ; [*0D7D.0020.0002] -2806 ; [*0D7E.0020.0002] -2807 ; [*0D7F.0020.0002] -2808 ; [*0D80.0020.0002] -2809 ; [*0D81.0020.0002] -280A ; [*0D82.0020.0002] -280B ; [*0D83.0020.0002] -280C ; [*0D84.0020.0002] -280D ; [*0D85.0020.0002] -280E ; [*0D86.0020.0002] -280F ; [*0D87.0020.0002] -2810 ; [*0D88.0020.0002] -2811 ; [*0D89.0020.0002] -2812 ; [*0D8A.0020.0002] -2813 ; [*0D8B.0020.0002] -2814 ; [*0D8C.0020.0002] -2815 ; [*0D8D.0020.0002] -2816 ; [*0D8E.0020.0002] -2817 ; [*0D8F.0020.0002] -2818 ; [*0D90.0020.0002] -2819 ; [*0D91.0020.0002] -281A ; [*0D92.0020.0002] -281B ; [*0D93.0020.0002] -281C ; [*0D94.0020.0002] -281D ; [*0D95.0020.0002] -281E ; [*0D96.0020.0002] -281F ; [*0D97.0020.0002] -2820 ; [*0D98.0020.0002] -2821 ; [*0D99.0020.0002] -2822 ; [*0D9A.0020.0002] -2823 ; [*0D9B.0020.0002] -2824 ; [*0D9C.0020.0002] -2825 ; [*0D9D.0020.0002] -2826 ; [*0D9E.0020.0002] -2827 ; [*0D9F.0020.0002] -2828 ; [*0DA0.0020.0002] -2829 ; [*0DA1.0020.0002] -282A ; [*0DA2.0020.0002] -282B ; [*0DA3.0020.0002] -282C ; [*0DA4.0020.0002] -282D ; [*0DA5.0020.0002] -282E ; [*0DA6.0020.0002] -282F ; [*0DA7.0020.0002] -2830 ; [*0DA8.0020.0002] -2831 ; [*0DA9.0020.0002] -2832 ; [*0DAA.0020.0002] -2833 ; [*0DAB.0020.0002] -2834 ; [*0DAC.0020.0002] -2835 ; [*0DAD.0020.0002] -2836 ; [*0DAE.0020.0002] -2837 ; [*0DAF.0020.0002] -2838 ; [*0DB0.0020.0002] -2839 ; [*0DB1.0020.0002] -283A ; [*0DB2.0020.0002] -283B ; [*0DB3.0020.0002] -283C ; [*0DB4.0020.0002] -283D ; [*0DB5.0020.0002] -283E ; [*0DB6.0020.0002] -283F ; [*0DB7.0020.0002] -2840 ; [*0DB8.0020.0002] -2841 ; [*0DB9.0020.0002] -2842 ; [*0DBA.0020.0002] -2843 ; [*0DBB.0020.0002] -2844 ; [*0DBC.0020.0002] -2845 ; [*0DBD.0020.0002] -2846 ; [*0DBE.0020.0002] -2847 ; [*0DBF.0020.0002] -2848 ; [*0DC0.0020.0002] -2849 ; [*0DC1.0020.0002] -284A ; [*0DC2.0020.0002] -284B ; [*0DC3.0020.0002] -284C ; [*0DC4.0020.0002] -284D ; [*0DC5.0020.0002] -284E ; [*0DC6.0020.0002] -284F ; [*0DC7.0020.0002] -2850 ; [*0DC8.0020.0002] -2851 ; [*0DC9.0020.0002] -2852 ; [*0DCA.0020.0002] -2853 ; [*0DCB.0020.0002] -2854 ; [*0DCC.0020.0002] -2855 ; [*0DCD.0020.0002] -2856 ; [*0DCE.0020.0002] -2857 ; [*0DCF.0020.0002] -2858 ; [*0DD0.0020.0002] -2859 ; [*0DD1.0020.0002] -285A ; [*0DD2.0020.0002] -285B ; [*0DD3.0020.0002] -285C ; [*0DD4.0020.0002] -285D ; [*0DD5.0020.0002] -285E ; [*0DD6.0020.0002] -285F ; [*0DD7.0020.0002] -2860 ; [*0DD8.0020.0002] -2861 ; [*0DD9.0020.0002] -2862 ; [*0DDA.0020.0002] -2863 ; [*0DDB.0020.0002] -2864 ; [*0DDC.0020.0002] -2865 ; [*0DDD.0020.0002] -2866 ; [*0DDE.0020.0002] -2867 ; [*0DDF.0020.0002] -2868 ; [*0DE0.0020.0002] -2869 ; [*0DE1.0020.0002] -286A ; [*0DE2.0020.0002] -286B ; [*0DE3.0020.0002] -286C ; [*0DE4.0020.0002] -286D ; [*0DE5.0020.0002] -286E ; [*0DE6.0020.0002] -286F ; [*0DE7.0020.0002] -2870 ; [*0DE8.0020.0002] -2871 ; [*0DE9.0020.0002] -2872 ; [*0DEA.0020.0002] -2873 ; [*0DEB.0020.0002] -2874 ; [*0DEC.0020.0002] -2875 ; [*0DED.0020.0002] -2876 ; [*0DEE.0020.0002] -2877 ; [*0DEF.0020.0002] -2878 ; [*0DF0.0020.0002] -2879 ; [*0DF1.0020.0002] -287A ; [*0DF2.0020.0002] -287B ; [*0DF3.0020.0002] -287C ; [*0DF4.0020.0002] -287D ; [*0DF5.0020.0002] -287E ; [*0DF6.0020.0002] -287F ; [*0DF7.0020.0002] -2880 ; [*0DF8.0020.0002] -2881 ; [*0DF9.0020.0002] -2882 ; [*0DFA.0020.0002] -2883 ; [*0DFB.0020.0002] -2884 ; [*0DFC.0020.0002] -2885 ; [*0DFD.0020.0002] -2886 ; [*0DFE.0020.0002] -2887 ; [*0DFF.0020.0002] -2888 ; [*0E00.0020.0002] -2889 ; [*0E01.0020.0002] -288A ; [*0E02.0020.0002] -288B ; [*0E03.0020.0002] -288C ; [*0E04.0020.0002] -288D ; [*0E05.0020.0002] -288E ; [*0E06.0020.0002] -288F ; [*0E07.0020.0002] -2890 ; [*0E08.0020.0002] -2891 ; [*0E09.0020.0002] -2892 ; [*0E0A.0020.0002] -2893 ; [*0E0B.0020.0002] -2894 ; [*0E0C.0020.0002] -2895 ; [*0E0D.0020.0002] -2896 ; [*0E0E.0020.0002] -2897 ; [*0E0F.0020.0002] -2898 ; [*0E10.0020.0002] -2899 ; [*0E11.0020.0002] -289A ; [*0E12.0020.0002] -289B ; [*0E13.0020.0002] -289C ; [*0E14.0020.0002] -289D ; [*0E15.0020.0002] -289E ; [*0E16.0020.0002] -289F ; [*0E17.0020.0002] -28A0 ; [*0E18.0020.0002] -28A1 ; [*0E19.0020.0002] -28A2 ; [*0E1A.0020.0002] -28A3 ; [*0E1B.0020.0002] -28A4 ; [*0E1C.0020.0002] -28A5 ; [*0E1D.0020.0002] -28A6 ; [*0E1E.0020.0002] -28A7 ; [*0E1F.0020.0002] -28A8 ; [*0E20.0020.0002] -28A9 ; [*0E21.0020.0002] -28AA ; [*0E22.0020.0002] -28AB ; [*0E23.0020.0002] -28AC ; [*0E24.0020.0002] -28AD ; [*0E25.0020.0002] -28AE ; [*0E26.0020.0002] -28AF ; [*0E27.0020.0002] -28B0 ; [*0E28.0020.0002] -28B1 ; [*0E29.0020.0002] -28B2 ; [*0E2A.0020.0002] -28B3 ; [*0E2B.0020.0002] -28B4 ; [*0E2C.0020.0002] -28B5 ; [*0E2D.0020.0002] -28B6 ; [*0E2E.0020.0002] -28B7 ; [*0E2F.0020.0002] -28B8 ; [*0E30.0020.0002] -28B9 ; [*0E31.0020.0002] -28BA ; [*0E32.0020.0002] -28BB ; [*0E33.0020.0002] -28BC ; [*0E34.0020.0002] -28BD ; [*0E35.0020.0002] -28BE ; [*0E36.0020.0002] -28BF ; [*0E37.0020.0002] -28C0 ; [*0E38.0020.0002] -28C1 ; [*0E39.0020.0002] -28C2 ; [*0E3A.0020.0002] -28C3 ; [*0E3B.0020.0002] -28C4 ; [*0E3C.0020.0002] -28C5 ; [*0E3D.0020.0002] -28C6 ; [*0E3E.0020.0002] -28C7 ; [*0E3F.0020.0002] -28C8 ; [*0E40.0020.0002] -28C9 ; [*0E41.0020.0002] -28CA ; [*0E42.0020.0002] -28CB ; [*0E43.0020.0002] -28CC ; [*0E44.0020.0002] -28CD ; [*0E45.0020.0002] -28CE ; [*0E46.0020.0002] -28CF ; [*0E47.0020.0002] -28D0 ; [*0E48.0020.0002] -28D1 ; [*0E49.0020.0002] -28D2 ; [*0E4A.0020.0002] -28D3 ; [*0E4B.0020.0002] -28D4 ; [*0E4C.0020.0002] -28D5 ; [*0E4D.0020.0002] -28D6 ; [*0E4E.0020.0002] -28D7 ; [*0E4F.0020.0002] -28D8 ; [*0E50.0020.0002] -28D9 ; [*0E51.0020.0002] -28DA ; [*0E52.0020.0002] -28DB ; [*0E53.0020.0002] -28DC ; [*0E54.0020.0002] -28DD ; [*0E55.0020.0002] -28DE ; [*0E56.0020.0002] -28DF ; [*0E57.0020.0002] -28E0 ; [*0E58.0020.0002] -28E1 ; [*0E59.0020.0002] -28E2 ; [*0E5A.0020.0002] -28E3 ; [*0E5B.0020.0002] -28E4 ; [*0E5C.0020.0002] -28E5 ; [*0E5D.0020.0002] -28E6 ; [*0E5E.0020.0002] -28E7 ; [*0E5F.0020.0002] -28E8 ; [*0E60.0020.0002] -28E9 ; [*0E61.0020.0002] -28EA ; [*0E62.0020.0002] -28EB ; [*0E63.0020.0002] -28EC ; [*0E64.0020.0002] -28ED ; [*0E65.0020.0002] -28EE ; [*0E66.0020.0002] -28EF ; [*0E67.0020.0002] -28F0 ; [*0E68.0020.0002] -28F1 ; [*0E69.0020.0002] -28F2 ; [*0E6A.0020.0002] -28F3 ; [*0E6B.0020.0002] -28F4 ; [*0E6C.0020.0002] -28F5 ; [*0E6D.0020.0002] -28F6 ; [*0E6E.0020.0002] -28F7 ; [*0E6F.0020.0002] -28F8 ; [*0E70.0020.0002] -28F9 ; [*0E71.0020.0002] -28FA ; [*0E72.0020.0002] -28FB ; [*0E73.0020.0002] -28FC ; [*0E74.0020.0002] -28FD ; [*0E75.0020.0002] -28FE ; [*0E76.0020.0002] -28FF ; [*0E77.0020.0002] -2900 ; [*0AC5.0020.0002] -2901 ; [*0AC6.0020.0002] -2902 ; [*0AC7.0020.0002] -2903 ; [*0AC8.0020.0002] -2904 ; [*0AC9.0020.0002] -2905 ; [*0ACA.0020.0002] -2906 ; [*0ACB.0020.0002] -2907 ; [*0ACC.0020.0002] -2908 ; [*0ACD.0020.0002] -2909 ; [*0ACE.0020.0002] -290A ; [*0ACF.0020.0002] -290B ; [*0AD0.0020.0002] -290C ; [*0AD1.0020.0002] -290D ; [*0AD2.0020.0002] -290E ; [*0AD3.0020.0002] -290F ; [*0AD4.0020.0002] -2910 ; [*0AD5.0020.0002] -2911 ; [*0AD6.0020.0002] -2912 ; [*0AD7.0020.0002] -2913 ; [*0AD8.0020.0002] -2914 ; [*0AD9.0020.0002] -2915 ; [*0ADA.0020.0002] -2916 ; [*0ADB.0020.0002] -2917 ; [*0ADC.0020.0002] -2918 ; [*0ADD.0020.0002] -2919 ; [*0ADE.0020.0002] -291A ; [*0ADF.0020.0002] -291B ; [*0AE0.0020.0002] -291C ; [*0AE1.0020.0002] -291D ; [*0AE2.0020.0002] -291E ; [*0AE3.0020.0002] -291F ; [*0AE4.0020.0002] -2920 ; [*0AE5.0020.0002] -2921 ; [*0AE6.0020.0002] -2922 ; [*0AE7.0020.0002] -2923 ; [*0AE8.0020.0002] -2924 ; [*0AE9.0020.0002] -2925 ; [*0AEA.0020.0002] -2926 ; [*0AEB.0020.0002] -2927 ; [*0AEC.0020.0002] -2928 ; [*0AED.0020.0002] -2929 ; [*0AEE.0020.0002] -292A ; [*0AEF.0020.0002] -292B ; [*0AF0.0020.0002] -292C ; [*0AF1.0020.0002] -292D ; [*0AF2.0020.0002] -292E ; [*0AF3.0020.0002] -292F ; [*0AF4.0020.0002] -2930 ; [*0AF5.0020.0002] -2931 ; [*0AF6.0020.0002] -2932 ; [*0AF7.0020.0002] -2933 ; [*0AF8.0020.0002] -2934 ; [*0AF9.0020.0002] -2935 ; [*0AFA.0020.0002] -2936 ; [*0AFB.0020.0002] -2937 ; [*0AFC.0020.0002] -2938 ; [*0AFD.0020.0002] -2939 ; [*0AFE.0020.0002] -293A ; [*0AFF.0020.0002] -293B ; [*0B00.0020.0002] -293C ; [*0B01.0020.0002] -293D ; [*0B02.0020.0002] -293E ; [*0B03.0020.0002] -293F ; [*0B04.0020.0002] -2940 ; [*0B05.0020.0002] -2941 ; [*0B06.0020.0002] -2942 ; [*0B07.0020.0002] -2943 ; [*0B08.0020.0002] -2944 ; [*0B09.0020.0002] -2945 ; [*0B0A.0020.0002] -2946 ; [*0B0B.0020.0002] -2947 ; [*0B0C.0020.0002] -2948 ; [*0B0D.0020.0002] -2949 ; [*0B0E.0020.0002] -294A ; [*0B0F.0020.0002] -294B ; [*0B10.0020.0002] -294C ; [*0B11.0020.0002] -294D ; [*0B12.0020.0002] -294E ; [*0B13.0020.0002] -294F ; [*0B14.0020.0002] -2950 ; [*0B15.0020.0002] -2951 ; [*0B16.0020.0002] -2952 ; [*0B17.0020.0002] -2953 ; [*0B18.0020.0002] -2954 ; [*0B19.0020.0002] -2955 ; [*0B1A.0020.0002] -2956 ; [*0B1B.0020.0002] -2957 ; [*0B1C.0020.0002] -2958 ; [*0B1D.0020.0002] -2959 ; [*0B1E.0020.0002] -295A ; [*0B1F.0020.0002] -295B ; [*0B20.0020.0002] -295C ; [*0B21.0020.0002] -295D ; [*0B22.0020.0002] -295E ; [*0B23.0020.0002] -295F ; [*0B24.0020.0002] -2960 ; [*0B25.0020.0002] -2961 ; [*0B26.0020.0002] -2962 ; [*0B27.0020.0002] -2963 ; [*0B28.0020.0002] -2964 ; [*0B29.0020.0002] -2965 ; [*0B2A.0020.0002] -2966 ; [*0B2B.0020.0002] -2967 ; [*0B2C.0020.0002] -2968 ; [*0B2D.0020.0002] -2969 ; [*0B2E.0020.0002] -296A ; [*0B2F.0020.0002] -296B ; [*0B30.0020.0002] -296C ; [*0B31.0020.0002] -296D ; [*0B32.0020.0002] -296E ; [*0B33.0020.0002] -296F ; [*0B34.0020.0002] -2970 ; [*0B35.0020.0002] -2971 ; [*0B36.0020.0002] -2972 ; [*0B37.0020.0002] -2973 ; [*0B38.0020.0002] -2974 ; [*0B39.0020.0002] -2975 ; [*0B3A.0020.0002] -2976 ; [*0B3B.0020.0002] -2977 ; [*0B3C.0020.0002] -2978 ; [*0B3D.0020.0002] -2979 ; [*0B3E.0020.0002] -297A ; [*0B3F.0020.0002] -297B ; [*0B40.0020.0002] -297C ; [*0B41.0020.0002] -297D ; [*0B42.0020.0002] -297E ; [*0B43.0020.0002] -297F ; [*0B44.0020.0002] -2980 ; [*0B45.0020.0002] -2981 ; [*0B46.0020.0002] -2982 ; [*0B47.0020.0002] -2983 ; [*0324.0020.0002] -2984 ; [*0325.0020.0002] -2985 ; [*0326.0020.0002] -2986 ; [*0327.0020.0002] -2987 ; [*0328.0020.0002] -2988 ; [*0329.0020.0002] -2989 ; [*032A.0020.0002] -298A ; [*032B.0020.0002] -298B ; [*032C.0020.0002] -298C ; [*032D.0020.0002] -298D ; [*032E.0020.0002] -298E ; [*032F.0020.0002] -298F ; [*0330.0020.0002] -2990 ; [*0331.0020.0002] -2991 ; [*0332.0020.0002] -2992 ; [*0333.0020.0002] -2993 ; [*0334.0020.0002] -2994 ; [*0335.0020.0002] -2995 ; [*0336.0020.0002] -2996 ; [*0337.0020.0002] -2997 ; [*0338.0020.0002] -2998 ; [*0339.0020.0002] -2999 ; [*0B48.0020.0002] -299A ; [*0B49.0020.0002] -299B ; [*0B4A.0020.0002] -299C ; [*0B4B.0020.0002] -299D ; [*0B4C.0020.0002] -299E ; [*0B4D.0020.0002] -299F ; [*0B4E.0020.0002] -29A0 ; [*0B4F.0020.0002] -29A1 ; [*0B50.0020.0002] -29A2 ; [*0B51.0020.0002] -29A3 ; [*0B52.0020.0002] -29A4 ; [*0B53.0020.0002] -29A5 ; [*0B54.0020.0002] -29A6 ; [*0B55.0020.0002] -29A7 ; [*0B56.0020.0002] -29A8 ; [*0B57.0020.0002] -29A9 ; [*0B58.0020.0002] -29AA ; [*0B59.0020.0002] -29AB ; [*0B5A.0020.0002] -29AC ; [*0B5B.0020.0002] -29AD ; [*0B5C.0020.0002] -29AE ; [*0B5D.0020.0002] -29AF ; [*0B5E.0020.0002] -29B0 ; [*0B5F.0020.0002] -29B1 ; [*0B60.0020.0002] -29B2 ; [*0B61.0020.0002] -29B3 ; [*0B62.0020.0002] -29B4 ; [*0B63.0020.0002] -29B5 ; [*0B64.0020.0002] -29B6 ; [*0B65.0020.0002] -29B7 ; [*0B66.0020.0002] -29B8 ; [*0B67.0020.0002] -29B9 ; [*0B68.0020.0002] -29BA ; [*0B69.0020.0002] -29BB ; [*0B6A.0020.0002] -29BC ; [*0B6B.0020.0002] -29BD ; [*0B6C.0020.0002] -29BE ; [*0B6D.0020.0002] -29BF ; [*0B6E.0020.0002] -29C0 ; [*0B6F.0020.0002] -29C1 ; [*0B70.0020.0002] -29C2 ; [*0B71.0020.0002] -29C3 ; [*0B72.0020.0002] -29C4 ; [*0B73.0020.0002] -29C5 ; [*0B74.0020.0002] -29C6 ; [*0B75.0020.0002] -29C7 ; [*0B76.0020.0002] -29C8 ; [*0B77.0020.0002] -29C9 ; [*0B78.0020.0002] -29CA ; [*0B79.0020.0002] -29CB ; [*0B7A.0020.0002] -29CC ; [*0B7B.0020.0002] -29CD ; [*0B7C.0020.0002] -29CE ; [*0B7D.0020.0002] -29CF ; [*0B7E.0020.0002] -29D0 ; [*0B7F.0020.0002] -29D1 ; [*0B80.0020.0002] -29D2 ; [*0B81.0020.0002] -29D3 ; [*0B82.0020.0002] -29D4 ; [*0B83.0020.0002] -29D5 ; [*0B84.0020.0002] -29D6 ; [*0B85.0020.0002] -29D7 ; [*0B86.0020.0002] -29D8 ; [*037E.0020.0002] -29D9 ; [*037F.0020.0002] -29DA ; [*0380.0020.0002] -29DB ; [*0381.0020.0002] -29DC ; [*0B87.0020.0002] -29DD ; [*0B88.0020.0002] -29DE ; [*0B89.0020.0002] -29DF ; [*0B8A.0020.0002] -29E0 ; [*0B8B.0020.0002] -29E1 ; [*0B8C.0020.0002] -29E2 ; [*0B8D.0020.0002] -29E3 ; [*0B8E.0020.0002] -29E4 ; [*0B8F.0020.0002] -29E5 ; [*0B90.0020.0002] -29E6 ; [*0B91.0020.0002] -29E7 ; [*0B92.0020.0002] -29E8 ; [*0B93.0020.0002] -29E9 ; [*0B94.0020.0002] -29EA ; [*0B95.0020.0002] -29EB ; [*0B96.0020.0002] -29EC ; [*0B97.0020.0002] -29ED ; [*0B98.0020.0002] -29EE ; [*0B99.0020.0002] -29EF ; [*0B9A.0020.0002] -29F0 ; [*0B9B.0020.0002] -29F1 ; [*0B9C.0020.0002] -29F2 ; [*0B9D.0020.0002] -29F3 ; [*0B9E.0020.0002] -29F4 ; [*0B9F.0020.0002] -29F5 ; [*0BA0.0020.0002] -29F6 ; [*0BA1.0020.0002] -29F7 ; [*0BA2.0020.0002] -29F8 ; [*0BA3.0020.0002] -29F9 ; [*0BA4.0020.0002] -29FA ; [*0BA5.0020.0002] -29FB ; [*0BA6.0020.0002] -29FC ; [*0322.0020.0002] -29FD ; [*0323.0020.0002] -29FE ; [*0BA7.0020.0002] -29FF ; [*0BA8.0020.0002] -2A00 ; [*0BA9.0020.0002] -2A01 ; [*0BAA.0020.0002] -2A02 ; [*0BAB.0020.0002] -2A03 ; [*0BAC.0020.0002] -2A04 ; [*0BAD.0020.0002] -2A05 ; [*0BAE.0020.0002] -2A06 ; [*0BAF.0020.0002] -2A07 ; [*0BB0.0020.0002] -2A08 ; [*0BB1.0020.0002] -2A09 ; [*0BB2.0020.0002] -2A0A ; [*0BB3.0020.0002] -2A0B ; [*0BB4.0020.0002] -2A0C ; [*061C.0020.0004][*061C.0020.0004][*061C.0020.0004][*061C.0020.0004] -2A0D ; [*0BB5.0020.0002] -2A0E ; [*0BB6.0020.0002] -2A0F ; [*0BB7.0020.0002] -2A10 ; [*0BB8.0020.0002] -2A11 ; [*0BB9.0020.0002] -2A12 ; [*0BBA.0020.0002] -2A13 ; [*0BBB.0020.0002] -2A14 ; [*0BBC.0020.0002] -2A15 ; [*0BBD.0020.0002] -2A16 ; [*0BBE.0020.0002] -2A17 ; [*0BBF.0020.0002] -2A18 ; [*0BC0.0020.0002] -2A19 ; [*0BC1.0020.0002] -2A1A ; [*0BC2.0020.0002] -2A1B ; [*0BC3.0020.0002] -2A1C ; [*0BC4.0020.0002] -2A1D ; [*0BC5.0020.0002] -2A1E ; [*0BC6.0020.0002] -2A1F ; [*0BC7.0020.0002] -2A20 ; [*0BC8.0020.0002] -2A21 ; [*0BC9.0020.0002] -2A22 ; [*0BCA.0020.0002] -2A23 ; [*0BCB.0020.0002] -2A24 ; [*0BCC.0020.0002] -2A25 ; [*0BCD.0020.0002] -2A26 ; [*0BCE.0020.0002] -2A27 ; [*0BCF.0020.0002] -2A28 ; [*0BD0.0020.0002] -2A29 ; [*0BD1.0020.0002] -2A2A ; [*0BD2.0020.0002] -2A2B ; [*0BD3.0020.0002] -2A2C ; [*0BD4.0020.0002] -2A2D ; [*0BD5.0020.0002] -2A2E ; [*0BD6.0020.0002] -2A2F ; [*0BD7.0020.0002] -2A30 ; [*0BD8.0020.0002] -2A31 ; [*0BD9.0020.0002] -2A32 ; [*0BDA.0020.0002] -2A33 ; [*0BDB.0020.0002] -2A34 ; [*0BDC.0020.0002] -2A35 ; [*0BDD.0020.0002] -2A36 ; [*0BDE.0020.0002] -2A37 ; [*0BDF.0020.0002] -2A38 ; [*0BE0.0020.0002] -2A39 ; [*0BE1.0020.0002] -2A3A ; [*0BE2.0020.0002] -2A3B ; [*0BE3.0020.0002] -2A3C ; [*0BE4.0020.0002] -2A3D ; [*0BE5.0020.0002] -2A3E ; [*0BE6.0020.0002] -2A3F ; [*0BE7.0020.0002] -2A40 ; [*0BE8.0020.0002] -2A41 ; [*0BE9.0020.0002] -2A42 ; [*0BEA.0020.0002] -2A43 ; [*0BEB.0020.0002] -2A44 ; [*0BEC.0020.0002] -2A45 ; [*0BED.0020.0002] -2A46 ; [*0BEE.0020.0002] -2A47 ; [*0BEF.0020.0002] -2A48 ; [*0BF0.0020.0002] -2A49 ; [*0BF1.0020.0002] -2A4A ; [*0BF2.0020.0002] -2A4B ; [*0BF3.0020.0002] -2A4C ; [*0BF4.0020.0002] -2A4D ; [*0BF5.0020.0002] -2A4E ; [*0BF6.0020.0002] -2A4F ; [*0BF7.0020.0002] -2A50 ; [*0BF8.0020.0002] -2A51 ; [*0BF9.0020.0002] -2A52 ; [*0BFA.0020.0002] -2A53 ; [*0BFB.0020.0002] -2A54 ; [*0BFC.0020.0002] -2A55 ; [*0BFD.0020.0002] -2A56 ; [*0BFE.0020.0002] -2A57 ; [*0BFF.0020.0002] -2A58 ; [*0C00.0020.0002] -2A59 ; [*0C01.0020.0002] -2A5A ; [*0C02.0020.0002] -2A5B ; [*0C03.0020.0002] -2A5C ; [*0C04.0020.0002] -2A5D ; [*0C05.0020.0002] -2A5E ; [*0C06.0020.0002] -2A5F ; [*0C07.0020.0002] -2A60 ; [*0C08.0020.0002] -2A61 ; [*0C09.0020.0002] -2A62 ; [*0C0A.0020.0002] -2A63 ; [*0C0B.0020.0002] -2A64 ; [*0C0C.0020.0002] -2A65 ; [*0C0D.0020.0002] -2A66 ; [*0C0E.0020.0002] -2A67 ; [*0C0F.0020.0002] -2A68 ; [*0C10.0020.0002] -2A69 ; [*0C11.0020.0002] -2A6A ; [*0C12.0020.0002] -2A6B ; [*0C13.0020.0002] -2A6C ; [*0C14.0020.0002] -2A6D ; [*0C15.0020.0002] -2A6E ; [*0C16.0020.0002] -2A6F ; [*0C17.0020.0002] -2A70 ; [*0C18.0020.0002] -2A71 ; [*0C19.0020.0002] -2A72 ; [*0C1A.0020.0002] -2A73 ; [*0C1B.0020.0002] -2A74 ; [*0238.0020.0004][*0238.0020.0004][*05FB.0020.0004] -2A75 ; [*05FB.0020.0004][*05FB.0020.0004] -2A76 ; [*05FB.0020.0004][*05FB.0020.0004][*05FB.0020.0004] -2A77 ; [*0C1C.0020.0002] -2A78 ; [*0C1D.0020.0002] -2A79 ; [*0C1E.0020.0002] -2A7A ; [*0C1F.0020.0002] -2A7B ; [*0C20.0020.0002] -2A7C ; [*0C21.0020.0002] -2A7D ; [*0C22.0020.0002] -2A7E ; [*0C23.0020.0002] -2A7F ; [*0C24.0020.0002] -2A80 ; [*0C25.0020.0002] -2A81 ; [*0C26.0020.0002] -2A82 ; [*0C27.0020.0002] -2A83 ; [*0C28.0020.0002] -2A84 ; [*0C29.0020.0002] -2A85 ; [*0C2A.0020.0002] -2A86 ; [*0C2B.0020.0002] -2A87 ; [*0C2C.0020.0002] -2A88 ; [*0C2D.0020.0002] -2A89 ; [*0C2E.0020.0002] -2A8A ; [*0C2F.0020.0002] -2A8B ; [*0C30.0020.0002] -2A8C ; [*0C31.0020.0002] -2A8D ; [*0C32.0020.0002] -2A8E ; [*0C33.0020.0002] -2A8F ; [*0C34.0020.0002] -2A90 ; [*0C35.0020.0002] -2A91 ; [*0C36.0020.0002] -2A92 ; [*0C37.0020.0002] -2A93 ; [*0C38.0020.0002] -2A94 ; [*0C39.0020.0002] -2A95 ; [*0C3A.0020.0002] -2A96 ; [*0C3B.0020.0002] -2A97 ; [*0C3C.0020.0002] -2A98 ; [*0C3D.0020.0002] -2A99 ; [*0C3E.0020.0002] -2A9A ; [*0C3F.0020.0002] -2A9B ; [*0C40.0020.0002] -2A9C ; [*0C41.0020.0002] -2A9D ; [*0C42.0020.0002] -2A9E ; [*0C43.0020.0002] -2A9F ; [*0C44.0020.0002] -2AA0 ; [*0C45.0020.0002] -2AA1 ; [*0C46.0020.0002] -2AA2 ; [*0C47.0020.0002] -2AA3 ; [*0C48.0020.0002] -2AA4 ; [*0C49.0020.0002] -2AA5 ; [*0C4A.0020.0002] -2AA6 ; [*0C4B.0020.0002] -2AA7 ; [*0C4C.0020.0002] -2AA8 ; [*0C4D.0020.0002] -2AA9 ; [*0C4E.0020.0002] -2AAA ; [*0C4F.0020.0002] -2AAB ; [*0C50.0020.0002] -2AAC ; [*0C51.0020.0002] -2AAD ; [*0C52.0020.0002] -2AAE ; [*0C53.0020.0002] -2AAF ; [*0C54.0020.0002] -2AB0 ; [*0C55.0020.0002] -2AB1 ; [*0C56.0020.0002] -2AB2 ; [*0C57.0020.0002] -2AB3 ; [*0C58.0020.0002] -2AB4 ; [*0C59.0020.0002] -2AB5 ; [*0C5A.0020.0002] -2AB6 ; [*0C5B.0020.0002] -2AB7 ; [*0C5C.0020.0002] -2AB8 ; [*0C5D.0020.0002] -2AB9 ; [*0C5E.0020.0002] -2ABA ; [*0C5F.0020.0002] -2ABB ; [*0C60.0020.0002] -2ABC ; [*0C61.0020.0002] -2ABD ; [*0C62.0020.0002] -2ABE ; [*0C63.0020.0002] -2ABF ; [*0C64.0020.0002] -2AC0 ; [*0C65.0020.0002] -2AC1 ; [*0C66.0020.0002] -2AC2 ; [*0C67.0020.0002] -2AC3 ; [*0C68.0020.0002] -2AC4 ; [*0C69.0020.0002] -2AC5 ; [*0C6A.0020.0002] -2AC6 ; [*0C6B.0020.0002] -2AC7 ; [*0C6C.0020.0002] -2AC8 ; [*0C6D.0020.0002] -2AC9 ; [*0C6E.0020.0002] -2ACA ; [*0C6F.0020.0002] -2ACB ; [*0C70.0020.0002] -2ACC ; [*0C71.0020.0002] -2ACD ; [*0C72.0020.0002] -2ACE ; [*0C73.0020.0002] -2ACF ; [*0C74.0020.0002] -2AD0 ; [*0C75.0020.0002] -2AD1 ; [*0C76.0020.0002] -2AD2 ; [*0C77.0020.0002] -2AD3 ; [*0C78.0020.0002] -2AD4 ; [*0C79.0020.0002] -2AD5 ; [*0C7A.0020.0002] -2AD6 ; [*0C7B.0020.0002] -2AD7 ; [*0C7C.0020.0002] -2AD8 ; [*0C7D.0020.0002] -2AD9 ; [*0C7E.0020.0002] -2ADA ; [*0C7F.0020.0002] -2ADB ; [*0C80.0020.0002] -2ADC ; [*0C81.0020.0002][.0000.002F.0002] -2ADD ; [*0C81.0020.0002] -2ADE ; [*0C82.0020.0002] -2ADF ; [*0C83.0020.0002] -2AE0 ; [*0C84.0020.0002] -2AE1 ; [*0C85.0020.0002] -2AE2 ; [*0C86.0020.0002] -2AE3 ; [*0C87.0020.0002] -2AE4 ; [*0C88.0020.0002] -2AE5 ; [*0C89.0020.0002] -2AE6 ; [*0C8A.0020.0002] -2AE7 ; [*0C8B.0020.0002] -2AE8 ; [*0C8C.0020.0002] -2AE9 ; [*0C8D.0020.0002] -2AEA ; [*0C8E.0020.0002] -2AEB ; [*0C8F.0020.0002] -2AEC ; [*0C90.0020.0002] -2AED ; [*0C91.0020.0002] -2AEE ; [*0C92.0020.0002] -2AEF ; [*0C93.0020.0002] -2AF0 ; [*0C94.0020.0002] -2AF1 ; [*0C95.0020.0002] -2AF2 ; [*0C96.0020.0002] -2AF3 ; [*0C97.0020.0002] -2AF4 ; [*0C98.0020.0002] -2AF5 ; [*0C99.0020.0002] -2AF6 ; [*0C9A.0020.0002] -2AF7 ; [*0C9B.0020.0002] -2AF8 ; [*0C9C.0020.0002] -2AF9 ; [*0C9D.0020.0002] -2AFA ; [*0C9E.0020.0002] -2AFB ; [*0C9F.0020.0002] -2AFC ; [*0CA0.0020.0002] -2AFD ; [*0CA1.0020.0002] -2AFE ; [*0CA2.0020.0002] -2AFF ; [*0CA3.0020.0002] -2B00 ; [*0CA4.0020.0002] -2B01 ; [*0CA5.0020.0002] -2B02 ; [*0CA6.0020.0002] -2B03 ; [*0CA7.0020.0002] -2B04 ; [*0CA8.0020.0002] -2B05 ; [*0CA9.0020.0002] -2B06 ; [*0CAA.0020.0002] -2B07 ; [*0CAB.0020.0002] -2B08 ; [*0CAC.0020.0002] -2B09 ; [*0CAD.0020.0002] -2B0A ; [*0CAE.0020.0002] -2B0B ; [*0CAF.0020.0002] -2B0C ; [*0CB0.0020.0002] -2B0D ; [*0CB1.0020.0002] -2B0E ; [*0CB2.0020.0002] -2B0F ; [*0CB3.0020.0002] -2B10 ; [*0CB4.0020.0002] -2B11 ; [*0CB5.0020.0002] -2B12 ; [*0CB6.0020.0002] -2B13 ; [*0CB7.0020.0002] -2B14 ; [*0CB8.0020.0002] -2B15 ; [*0CB9.0020.0002] -2B16 ; [*0CBA.0020.0002] -2B17 ; [*0CBB.0020.0002] -2B18 ; [*0CBC.0020.0002] -2B19 ; [*0CBD.0020.0002] -2B1A ; [*0CBE.0020.0002] -2B1B ; [*0CBF.0020.0002] -2B1C ; [*0CC0.0020.0002] -2B1D ; [*0CC1.0020.0002] -2B1E ; [*0CC2.0020.0002] -2B1F ; [*0CC3.0020.0002] -2B20 ; [*0CC4.0020.0002] -2B21 ; [*0CC5.0020.0002] -2B22 ; [*0CC6.0020.0002] -2B23 ; [*0CC7.0020.0002] -2B24 ; [*0CC8.0020.0002] -2B25 ; [*0CC9.0020.0002] -2B26 ; [*0CCA.0020.0002] -2B27 ; [*0CCB.0020.0002] -2B28 ; [*0CCC.0020.0002] -2B29 ; [*0CCD.0020.0002] -2B2A ; [*0CCE.0020.0002] -2B2B ; [*0CCF.0020.0002] -2B2C ; [*0CD0.0020.0002] -2B2D ; [*0CD1.0020.0002] -2B2E ; [*0CD2.0020.0002] -2B2F ; [*0CD3.0020.0002] -2B30 ; [*0CD4.0020.0002] -2B31 ; [*0CD5.0020.0002] -2B32 ; [*0CD6.0020.0002] -2B33 ; [*0CD7.0020.0002] -2B34 ; [*0CD8.0020.0002] -2B35 ; [*0CD9.0020.0002] -2B36 ; [*0CDA.0020.0002] -2B37 ; [*0CDB.0020.0002] -2B38 ; [*0CDC.0020.0002] -2B39 ; [*0CDD.0020.0002] -2B3A ; [*0CDE.0020.0002] -2B3B ; [*0CDF.0020.0002] -2B3C ; [*0CE0.0020.0002] -2B3D ; [*0CE1.0020.0002] -2B3E ; [*0CE2.0020.0002] -2B3F ; [*0CE3.0020.0002] -2B40 ; [*0CE4.0020.0002] -2B41 ; [*0CE5.0020.0002] -2B42 ; [*0CE6.0020.0002] -2B43 ; [*0CE7.0020.0002] -2B44 ; [*0CE8.0020.0002] -2B45 ; [*0CE9.0020.0002] -2B46 ; [*0CEA.0020.0002] -2B47 ; [*0CEB.0020.0002] -2B48 ; [*0CEC.0020.0002] -2B49 ; [*0CED.0020.0002] -2B4A ; [*0CEE.0020.0002] -2B4B ; [*0CEF.0020.0002] -2B4C ; [*0CF0.0020.0002] -2B4D ; [*0CF1.0020.0002] -2B4E ; [*0CF2.0020.0002] -2B4F ; [*0CF3.0020.0002] -2B50 ; [*0CF4.0020.0002] -2B51 ; [*0CF5.0020.0002] -2B52 ; [*0CF6.0020.0002] -2B53 ; [*0CF7.0020.0002] -2B54 ; [*0CF8.0020.0002] -2B55 ; [*0CF9.0020.0002] -2B56 ; [*0CFA.0020.0002] -2B57 ; [*0CFB.0020.0002] -2B58 ; [*0CFC.0020.0002] -2B59 ; [*0CFD.0020.0002] -2B5A ; [*0CFE.0020.0002] -2B5B ; [*0CFF.0020.0002] -2B5C ; [*0D00.0020.0002] -2B5D ; [*0D01.0020.0002] -2B5E ; [*0D02.0020.0002] -2B5F ; [*0D03.0020.0002] -2B60 ; [*0D04.0020.0002] -2B61 ; [*0D05.0020.0002] -2B62 ; [*0D06.0020.0002] -2B63 ; [*0D07.0020.0002] -2B64 ; [*0D08.0020.0002] -2B65 ; [*0D09.0020.0002] -2B66 ; [*0D0A.0020.0002] -2B67 ; [*0D0B.0020.0002] -2B68 ; [*0D0C.0020.0002] -2B69 ; [*0D0D.0020.0002] -2B6A ; [*0D0E.0020.0002] -2B6B ; [*0D0F.0020.0002] -2B6C ; [*0D10.0020.0002] -2B6D ; [*0D11.0020.0002] -2B6E ; [*0D12.0020.0002] -2B6F ; [*0D13.0020.0002] -2B70 ; [*0D14.0020.0002] -2B71 ; [*0D15.0020.0002] -2B72 ; [*0D16.0020.0002] -2B73 ; [*0D17.0020.0002] -2B76 ; [*0D18.0020.0002] -2B77 ; [*0D19.0020.0002] -2B78 ; [*0D1A.0020.0002] -2B79 ; [*0D1B.0020.0002] -2B7A ; [*0D1C.0020.0002] -2B7B ; [*0D1D.0020.0002] -2B7C ; [*0D1E.0020.0002] -2B7D ; [*0D1F.0020.0002] -2B7E ; [*0D20.0020.0002] -2B7F ; [*0D21.0020.0002] -2B80 ; [*0D22.0020.0002] -2B81 ; [*0D23.0020.0002] -2B82 ; [*0D24.0020.0002] -2B83 ; [*0D25.0020.0002] -2B84 ; [*0D26.0020.0002] -2B85 ; [*0D27.0020.0002] -2B86 ; [*0D28.0020.0002] -2B87 ; [*0D29.0020.0002] -2B88 ; [*0D2A.0020.0002] -2B89 ; [*0D2B.0020.0002] -2B8A ; [*0D2C.0020.0002] -2B8B ; [*0D2D.0020.0002] -2B8C ; [*0D2E.0020.0002] -2B8D ; [*0D2F.0020.0002] -2B8E ; [*0D30.0020.0002] -2B8F ; [*0D31.0020.0002] -2B90 ; [*0D32.0020.0002] -2B91 ; [*0D33.0020.0002] -2B92 ; [*0D34.0020.0002] -2B93 ; [*0D35.0020.0002] -2B94 ; [*0D36.0020.0002] -2B95 ; [*0D37.0020.0002] -2B98 ; [*0D38.0020.0002] -2B99 ; [*0D39.0020.0002] -2B9A ; [*0D3A.0020.0002] -2B9B ; [*0D3B.0020.0002] -2B9C ; [*0D3C.0020.0002] -2B9D ; [*0D3D.0020.0002] -2B9E ; [*0D3E.0020.0002] -2B9F ; [*0D3F.0020.0002] -2BA0 ; [*0D40.0020.0002] -2BA1 ; [*0D41.0020.0002] -2BA2 ; [*0D42.0020.0002] -2BA3 ; [*0D43.0020.0002] -2BA4 ; [*0D44.0020.0002] -2BA5 ; [*0D45.0020.0002] -2BA6 ; [*0D46.0020.0002] -2BA7 ; [*0D47.0020.0002] -2BA8 ; [*0D48.0020.0002] -2BA9 ; [*0D49.0020.0002] -2BAA ; [*0D4A.0020.0002] -2BAB ; [*0D4B.0020.0002] -2BAC ; [*0D4C.0020.0002] -2BAD ; [*0D4D.0020.0002] -2BAE ; [*0D4E.0020.0002] -2BAF ; [*0D4F.0020.0002] -2BB0 ; [*0D50.0020.0002] -2BB1 ; [*0D51.0020.0002] -2BB2 ; [*0D52.0020.0002] -2BB3 ; [*0D53.0020.0002] -2BB4 ; [*0D54.0020.0002] -2BB5 ; [*0D55.0020.0002] -2BB6 ; [*0D56.0020.0002] -2BB7 ; [*0D57.0020.0002] -2BB8 ; [*0D58.0020.0002] -2BB9 ; [*0D59.0020.0002] -2BBD ; [*0D5A.0020.0002] -2BBE ; [*0D5B.0020.0002] -2BBF ; [*0D5C.0020.0002] -2BC0 ; [*0D5D.0020.0002] -2BC1 ; [*0D5E.0020.0002] -2BC2 ; [*0D5F.0020.0002] -2BC3 ; [*0D60.0020.0002] -2BC4 ; [*0D61.0020.0002] -2BC5 ; [*0D62.0020.0002] -2BC6 ; [*0D63.0020.0002] -2BC7 ; [*0D64.0020.0002] -2BC8 ; [*0D65.0020.0002] -2BCA ; [*0D66.0020.0002] -2BCB ; [*0D67.0020.0002] -2BCC ; [*0D68.0020.0002] -2BCD ; [*0D69.0020.0002] -2BCE ; [*0D6A.0020.0002] -2BCF ; [*0D6B.0020.0002] -2BD0 ; [*0D6C.0020.0002] -2BD1 ; [*0D6D.0020.0002] -2BEC ; [*0D6E.0020.0002] -2BED ; [*0D6F.0020.0002] -2BEE ; [*0D70.0020.0002] -2BEF ; [*0D71.0020.0002] -2CE5 ; [*0D72.0020.0002] -2CE6 ; [*0D73.0020.0002] -2CE7 ; [*0D74.0020.0002] -2CE8 ; [*0D75.0020.0002] -2CE9 ; [*0D76.0020.0002] -2CEA ; [*0D77.0020.0002] -2CF9 ; [*027E.0020.0002] -2CFA ; [*026C.0020.0002] -2CFB ; [*026D.0020.0002] -2CFC ; [*02EF.0020.0002] -2CFD ; [*1A68.0020.0002] -2CFE ; [*027F.0020.0002] -2CFF ; [*02F0.0020.0002] -2D70 ; [*0410.0020.0002] -2D7F ; [.0000.0000.0000] -2E00 ; [*03AF.0020.0002] -2E01 ; [*03B0.0020.0002] -2E02 ; [*0354.0020.0002] -2E03 ; [*0355.0020.0002] -2E04 ; [*0356.0020.0002] -2E05 ; [*0357.0020.0002] -2E06 ; [*03B1.0020.0002] -2E07 ; [*03B2.0020.0002] -2E08 ; [*03B3.0020.0002] -2E09 ; [*0358.0020.0002] -2E0A ; [*0359.0020.0002] -2E0B ; [*03B4.0020.0002] -2E0C ; [*035A.0020.0002] -2E0D ; [*035B.0020.0002] -2E0E ; [*03B5.0020.0002] -2E0F ; [*03B6.0020.0002] -2E10 ; [*03B7.0020.0002] -2E11 ; [*03B8.0020.0002] -2E12 ; [*03B9.0020.0002] -2E13 ; [*03BA.0020.0002] -2E14 ; [*03BB.0020.0002] -2E15 ; [*03BC.0020.0002] -2E16 ; [*03BD.0020.0002] -2E17 ; [*021B.0020.0002] -2E18 ; [*0273.0020.0002] -2E19 ; [*02F1.0020.0002] -2E1A ; [*03BE.0020.0002] -2E1B ; [*03BF.0020.0002] -2E1C ; [*035C.0020.0002] -2E1D ; [*035D.0020.0002] -2E1E ; [*03C0.0020.0002] -2E1F ; [*03C1.0020.0002] -2E20 ; [*035E.0020.0002] -2E21 ; [*035F.0020.0002] -2E22 ; [*0360.0020.0002] -2E23 ; [*0361.0020.0002] -2E24 ; [*0362.0020.0002] -2E25 ; [*0363.0020.0002] -2E26 ; [*0364.0020.0002] -2E27 ; [*0365.0020.0002] -2E28 ; [*0366.0020.0002] -2E29 ; [*0367.0020.0002] -2E2A ; [*02EA.0020.0002] -2E2B ; [*02EB.0020.0002] -2E2C ; [*02EC.0020.0002] -2E2D ; [*02ED.0020.0002] -2E2E ; [*0266.0020.0002] -2E30 ; [*0280.0020.0002] -2E31 ; [*0289.0020.0002] -2E32 ; [*0223.0020.0002] -2E33 ; [*028A.0020.0002] -2E34 ; [*0222.0020.0002] -2E35 ; [*0236.0020.0002] -2E36 ; [*039A.0020.0002] -2E37 ; [*039B.0020.0002] -2E38 ; [*039C.0020.0002] -2E39 ; [*0383.0020.0002] -2E3A ; [*0218.0020.0002] -2E3B ; [*0219.0020.0002] -2E3C ; [*0281.0020.0002] -2E3D ; [*02EE.0020.0002] -2E3E ; [*037D.0020.0002] -2E3F ; [*0386.0020.0002] -2E40 ; [*021C.0020.0002] -2E41 ; [*0224.0020.0002] -2E42 ; [*030A.0020.0002] -2FF0 ; [*19EB.0020.0002] -2FF1 ; [*19EC.0020.0002] -2FF2 ; [*19ED.0020.0002] -2FF3 ; [*19EE.0020.0002] -2FF4 ; [*19EF.0020.0002] -2FF5 ; [*19F0.0020.0002] -2FF6 ; [*19F1.0020.0002] -2FF7 ; [*19F2.0020.0002] -2FF8 ; [*19F3.0020.0002] -2FF9 ; [*19F4.0020.0002] -2FFA ; [*19F5.0020.0002] -2FFB ; [*19F6.0020.0002] -3000 ; [*0209.0020.0003] -3001 ; [*0230.0020.0002] -3002 ; [*0287.0020.0002] -3003 ; [*03A5.0020.0002] -3004 ; [*1A1B.0020.0002] -3008 ; [*0368.0020.0002] -3009 ; [*0369.0020.0002] -300A ; [*036A.0020.0002] -300B ; [*036B.0020.0002] -300C ; [*036C.0020.0002] -300D ; [*036D.0020.0002] -300E ; [*036E.0020.0002] -300F ; [*036F.0020.0002] -3010 ; [*0370.0020.0002] -3011 ; [*0371.0020.0002] -3012 ; [*1A1C.0020.0002] -3013 ; [*1A1D.0020.0002] -3014 ; [*0372.0020.0002] -3015 ; [*0373.0020.0002] -3016 ; [*0374.0020.0002] -3017 ; [*0375.0020.0002] -3018 ; [*0376.0020.0002] -3019 ; [*0377.0020.0002] -301A ; [*0378.0020.0002] -301B ; [*0379.0020.0002] -301C ; [*021D.0020.0002] -301D ; [*030B.0020.0002] -301E ; [*030C.0020.0002] -301F ; [*030D.0020.0002] -3020 ; [*1A1E.0020.0002] -3030 ; [*021E.0020.0002] -3036 ; [*1A1C.0020.0004] -3037 ; [*1A1F.0020.0002] -303D ; [*03A6.0020.0002] -303E ; [*1A20.0020.0002] -303F ; [*1A21.0020.0002] -309B ; [*0472.0020.0002] -309C ; [*0473.0020.0002] -30A0 ; [*021F.0020.0002] -30FB ; [*0220.0020.0002] -3190 ; [*1A22.0020.0002] -3191 ; [*1A23.0020.0002] -31C0 ; [*19F7.0020.0002] -31C1 ; [*19F8.0020.0002] -31C2 ; [*19F9.0020.0002] -31C3 ; [*19FA.0020.0002] -31C4 ; [*19FB.0020.0002] -31C5 ; [*19FC.0020.0002] -31C6 ; [*19FD.0020.0002] -31C7 ; [*19FE.0020.0002] -31C8 ; [*19FF.0020.0002] -31C9 ; [*1A00.0020.0002] -31CA ; [*1A01.0020.0002] -31CB ; [*1A02.0020.0002] -31CC ; [*1A03.0020.0002] -31CD ; [*1A04.0020.0002] -31CE ; [*1A05.0020.0002] -31CF ; [*1A06.0020.0002] -31D0 ; [*1A07.0020.0002] -31D1 ; [*1A08.0020.0002] -31D2 ; [*1A09.0020.0002] -31D3 ; [*1A0A.0020.0002] -31D4 ; [*1A0B.0020.0002] -31D5 ; [*1A0C.0020.0002] -31D6 ; [*1A0D.0020.0002] -31D7 ; [*1A0E.0020.0002] -31D8 ; [*1A0F.0020.0002] -31D9 ; [*1A10.0020.0002] -31DA ; [*1A11.0020.0002] -31DB ; [*1A12.0020.0002] -31DC ; [*1A13.0020.0002] -31DD ; [*1A14.0020.0002] -31DE ; [*1A15.0020.0002] -31DF ; [*1A16.0020.0002] -31E0 ; [*1A17.0020.0002] -31E1 ; [*1A18.0020.0002] -31E2 ; [*1A19.0020.0002] -31E3 ; [*1A1A.0020.0002] -327F ; [*1A24.0020.0002] -4DC0 ; [*0E86.0020.0002] -4DC1 ; [*0E87.0020.0002] -4DC2 ; [*0E88.0020.0002] -4DC3 ; [*0E89.0020.0002] -4DC4 ; [*0E8A.0020.0002] -4DC5 ; [*0E8B.0020.0002] -4DC6 ; [*0E8C.0020.0002] -4DC7 ; [*0E8D.0020.0002] -4DC8 ; [*0E8E.0020.0002] -4DC9 ; [*0E8F.0020.0002] -4DCA ; [*0E90.0020.0002] -4DCB ; [*0E91.0020.0002] -4DCC ; [*0E92.0020.0002] -4DCD ; [*0E93.0020.0002] -4DCE ; [*0E94.0020.0002] -4DCF ; [*0E95.0020.0002] -4DD0 ; [*0E96.0020.0002] -4DD1 ; [*0E97.0020.0002] -4DD2 ; [*0E98.0020.0002] -4DD3 ; [*0E99.0020.0002] -4DD4 ; [*0E9A.0020.0002] -4DD5 ; [*0E9B.0020.0002] -4DD6 ; [*0E9C.0020.0002] -4DD7 ; [*0E9D.0020.0002] -4DD8 ; [*0E9E.0020.0002] -4DD9 ; [*0E9F.0020.0002] -4DDA ; [*0EA0.0020.0002] -4DDB ; [*0EA1.0020.0002] -4DDC ; [*0EA2.0020.0002] -4DDD ; [*0EA3.0020.0002] -4DDE ; [*0EA4.0020.0002] -4DDF ; [*0EA5.0020.0002] -4DE0 ; [*0EA6.0020.0002] -4DE1 ; [*0EA7.0020.0002] -4DE2 ; [*0EA8.0020.0002] -4DE3 ; [*0EA9.0020.0002] -4DE4 ; [*0EAA.0020.0002] -4DE5 ; [*0EAB.0020.0002] -4DE6 ; [*0EAC.0020.0002] -4DE7 ; [*0EAD.0020.0002] -4DE8 ; [*0EAE.0020.0002] -4DE9 ; [*0EAF.0020.0002] -4DEA ; [*0EB0.0020.0002] -4DEB ; [*0EB1.0020.0002] -4DEC ; [*0EB2.0020.0002] -4DED ; [*0EB3.0020.0002] -4DEE ; [*0EB4.0020.0002] -4DEF ; [*0EB5.0020.0002] -4DF0 ; [*0EB6.0020.0002] -4DF1 ; [*0EB7.0020.0002] -4DF2 ; [*0EB8.0020.0002] -4DF3 ; [*0EB9.0020.0002] -4DF4 ; [*0EBA.0020.0002] -4DF5 ; [*0EBB.0020.0002] -4DF6 ; [*0EBC.0020.0002] -4DF7 ; [*0EBD.0020.0002] -4DF8 ; [*0EBE.0020.0002] -4DF9 ; [*0EBF.0020.0002] -4DFA ; [*0EC0.0020.0002] -4DFB ; [*0EC1.0020.0002] -4DFC ; [*0EC2.0020.0002] -4DFD ; [*0EC3.0020.0002] -4DFE ; [*0EC4.0020.0002] -4DFF ; [*0EC5.0020.0002] -A490 ; [*0F1D.0020.0002] -A491 ; [*0F1E.0020.0002] -A492 ; [*0F1F.0020.0002] -A493 ; [*0F20.0020.0002] -A494 ; [*0F21.0020.0002] -A495 ; [*0F22.0020.0002] -A496 ; [*0F23.0020.0002] -A497 ; [*0F24.0020.0002] -A498 ; [*0F25.0020.0002] -A499 ; [*0F26.0020.0002] -A49A ; [*0F27.0020.0002] -A49B ; [*0F28.0020.0002] -A49C ; [*0F29.0020.0002] -A49D ; [*0F2A.0020.0002] -A49E ; [*0F2B.0020.0002] -A49F ; [*0F2C.0020.0002] -A4A0 ; [*0F2D.0020.0002] -A4A1 ; [*0F2E.0020.0002] -A4A2 ; [*0F2F.0020.0002] -A4A3 ; [*0F30.0020.0002] -A4A4 ; [*0F31.0020.0002] -A4A5 ; [*0F32.0020.0002] -A4A6 ; [*0F33.0020.0002] -A4A7 ; [*0F34.0020.0002] -A4A8 ; [*0F35.0020.0002] -A4A9 ; [*0F36.0020.0002] -A4AA ; [*0F37.0020.0002] -A4AB ; [*0F38.0020.0002] -A4AC ; [*0F39.0020.0002] -A4AD ; [*0F3A.0020.0002] -A4AE ; [*0F3B.0020.0002] -A4AF ; [*0F3C.0020.0002] -A4B0 ; [*0F3D.0020.0002] -A4B1 ; [*0F3E.0020.0002] -A4B2 ; [*0F3F.0020.0002] -A4B3 ; [*0F40.0020.0002] -A4B4 ; [*0F41.0020.0002] -A4B5 ; [*0F42.0020.0002] -A4B6 ; [*0F43.0020.0002] -A4B7 ; [*0F44.0020.0002] -A4B8 ; [*0F45.0020.0002] -A4B9 ; [*0F46.0020.0002] -A4BA ; [*0F47.0020.0002] -A4BB ; [*0F48.0020.0002] -A4BC ; [*0F49.0020.0002] -A4BD ; [*0F4A.0020.0002] -A4BE ; [*0F4B.0020.0002] -A4BF ; [*0F4C.0020.0002] -A4C0 ; [*0F4D.0020.0002] -A4C1 ; [*0F4E.0020.0002] -A4C2 ; [*0F4F.0020.0002] -A4C3 ; [*0F50.0020.0002] -A4C4 ; [*0F51.0020.0002] -A4C5 ; [*0F52.0020.0002] -A4C6 ; [*0F53.0020.0002] -A4FE ; [*022D.0020.0002] -A4FF ; [*0282.0020.0002] -A60D ; [*022E.0020.0002] -A60E ; [*0283.0020.0002] -A60F ; [*026E.0020.0002] -A670 ; [.0000.0000.0000] -A671 ; [.0000.0000.0000] -A672 ; [.0000.0000.0000] -A673 ; [*038C.0020.0002] -A67E ; [*03C2.0020.0002] -A6F2 ; [*02D0.0020.0002] -A6F3 ; [*0284.0020.0002] -A6F4 ; [*025E.0020.0002] -A6F5 ; [*022F.0020.0002] -A6F6 ; [*0237.0020.0002] -A6F7 ; [*026F.0020.0002] -A700 ; [*04B1.0020.0002] -A701 ; [*04B2.0020.0002] -A702 ; [*04B3.0020.0002] -A703 ; [*04B4.0020.0002] -A704 ; [*04B5.0020.0002] -A705 ; [*04B6.0020.0002] -A706 ; [*04B7.0020.0002] -A707 ; [*04B8.0020.0002] -A708 ; [*04B9.0020.0002] -A709 ; [*04BA.0020.0002] -A70A ; [*04BB.0020.0002] -A70B ; [*04BC.0020.0002] -A70C ; [*04BD.0020.0002] -A70D ; [*04BE.0020.0002] -A70E ; [*04BF.0020.0002] -A70F ; [*04C0.0020.0002] -A710 ; [*04C1.0020.0002] -A711 ; [*04C2.0020.0002] -A712 ; [*04C3.0020.0002] -A713 ; [*04C4.0020.0002] -A714 ; [*04C5.0020.0002] -A715 ; [*04C6.0020.0002] -A716 ; [*04C7.0020.0002] -A717 ; [*04C8.0020.0002] -A718 ; [*04C9.0020.0002] -A719 ; [*04CA.0020.0002] -A71A ; [*04CB.0020.0002] -A71B ; [*04CC.0020.0002] -A71C ; [*04CD.0020.0002] -A71D ; [*04CE.0020.0002] -A71E ; [*04CF.0020.0002] -A71F ; [*04D0.0020.0002] -A720 ; [*04D1.0020.0002] -A721 ; [*04D2.0020.0002] -A788 ; [*04D3.0020.0002] -A789 ; [*04D4.0020.0002] -A78A ; [*04D5.0020.0002] -A828 ; [*04FF.0020.0002] -A829 ; [*0500.0020.0002] -A82A ; [*0501.0020.0002] -A82B ; [*0502.0020.0002] -A830 ; [*1A32.0020.0002] -A831 ; [*1A33.0020.0002] -A832 ; [*1A34.0020.0002] -A833 ; [*1A35.0020.0002] -A834 ; [*1A36.0020.0002] -A835 ; [*1A37.0020.0002] -A836 ; [*0503.0020.0002] -A837 ; [*0504.0020.0002] -A839 ; [*0505.0020.0002] -A874 ; [*0411.0020.0002] -A875 ; [*0412.0020.0002] -A876 ; [*0291.0020.0002] -A877 ; [*0292.0020.0002] -A8CE ; [*028D.0020.0002] -A8CF ; [*028E.0020.0002] -A8E0 ; [.0000.0000.0000] -A8E1 ; [.0000.0000.0000] -A8E2 ; [.0000.0000.0000] -A8E3 ; [.0000.0000.0000] -A8E4 ; [.0000.0000.0000] -A8E5 ; [.0000.0000.0000] -A8E6 ; [.0000.0000.0000] -A8E7 ; [.0000.0000.0000] -A8E8 ; [.0000.0000.0000] -A8E9 ; [.0000.0000.0000] -A8EA ; [.0000.0000.0000] -A8EB ; [.0000.0000.0000] -A8EC ; [.0000.0000.0000] -A8ED ; [.0000.0000.0000] -A8EE ; [.0000.0000.0000] -A8EF ; [.0000.0000.0000] -A8F0 ; [.0000.0000.0000] -A8F1 ; [.0000.0000.0000] -A8F8 ; [*03D3.0020.0002] -A8F9 ; [*03D4.0020.0002] -A8FA ; [*03D5.0020.0002] -A8FC ; [*03D6.0020.0002] -A92E ; [*0417.0020.0002] -A92F ; [*0295.0020.0002] -A95F ; [*02D1.0020.0002] -A9C1 ; [*02C6.0020.0002] -A9C2 ; [*02C7.0020.0002] -A9C3 ; [*02C8.0020.0002] -A9C4 ; [*02C9.0020.0002] -A9C5 ; [*02CA.0020.0002] -A9C6 ; [*02CB.0020.0002] -A9C7 ; [*025A.0020.0002] -A9C8 ; [*02A0.0020.0002] -A9C9 ; [*02A1.0020.0002] -A9CA ; [*02CC.0020.0002] -A9CB ; [*02CD.0020.0002] -A9CC ; [*02CE.0020.0002] -A9CD ; [*02CF.0020.0002] -A9DE ; [*0418.0020.0002] -A9DF ; [*0419.0020.0002] -AA5C ; [*041A.0020.0002] -AA5D ; [*02A2.0020.0002] -AA5E ; [*02A3.0020.0002] -AA5F ; [*02A4.0020.0002] -AA77 ; [*052D.0020.0002] -AA78 ; [*052E.0020.0002] -AA79 ; [*052F.0020.0002] -AADE ; [*03DC.0020.0002] -AADF ; [*03DD.0020.0002] -AAF0 ; [*02A5.0020.0002] -AAF1 ; [*0270.0020.0002] -AB5B ; [*04D6.0020.0002] -ABEB ; [*02A6.0020.0002] -FB29 ; [*05F6.0020.0005] -FBB2 ; [*04E3.0020.0002] -FBB3 ; [*04E4.0020.0002] -FBB4 ; [*04E5.0020.0002] -FBB5 ; [*04E6.0020.0002] -FBB6 ; [*04E7.0020.0002] -FBB7 ; [*04E8.0020.0002] -FBB8 ; [*04E9.0020.0002] -FBB9 ; [*04EA.0020.0002] -FBBA ; [*04EB.0020.0002] -FBBB ; [*04EC.0020.0002] -FBBC ; [*04ED.0020.0002] -FBBD ; [*04EE.0020.0002] -FBBE ; [*04EF.0020.0002] -FBBF ; [*04F0.0020.0002] -FBC0 ; [*04F1.0020.0002] -FBC1 ; [*04F2.0020.0002] -FD3E ; [*037A.0020.0002] -FD3F ; [*037B.0020.0002] -FDFD ; [*04E2.0020.0002] -FE10 ; [*0221.0020.0016] -FE11 ; [*0230.0020.0016] -FE12 ; [*0287.0020.0016] -FE13 ; [*0238.0020.0016] -FE14 ; [*0233.0020.0016] -FE15 ; [*025F.0020.0016] -FE16 ; [*0264.0020.0016] -FE17 ; [*0374.0020.0016] -FE18 ; [*0375.0020.0016] -FE19 ; [*0274.0020.0016][*0274.0020.0016][*0274.0020.0016] -FE21 ; [.0000.0000.0000] -FE23 ; [.0000.0000.0000] -FE24 ; [.0000.0000.0000] -FE25 ; [.0000.0000.0000] -FE26 ; [.0000.0000.0000] -FE28 ; [.0000.0000.0000] -FE2A ; [.0000.0000.0000] -FE2B ; [.0000.0000.0000] -FE2C ; [.0000.0000.0000] -FE2D ; [.0000.0000.0000] -FE2F ; [.0000.0000.0000] -FE30 ; [*0274.0020.0016][*0274.0020.0016] -FE31 ; [*0216.0020.0016] -FE32 ; [*0215.0020.0016] -FE33 ; [*020B.0020.0016] -FE34 ; [*020B.0020.0016] -FE35 ; [*0310.0020.0016] -FE36 ; [*0311.0020.0016] -FE37 ; [*0314.0020.0016] -FE38 ; [*0315.0020.0016] -FE39 ; [*0372.0020.0016] -FE3A ; [*0373.0020.0016] -FE3B ; [*0370.0020.0016] -FE3C ; [*0371.0020.0016] -FE3D ; [*036A.0020.0016] -FE3E ; [*036B.0020.0016] -FE3F ; [*0368.0020.0016] -FE40 ; [*0369.0020.0016] -FE41 ; [*036C.0020.0016] -FE42 ; [*036D.0020.0016] -FE43 ; [*036E.0020.0016] -FE44 ; [*036F.0020.0016] -FE45 ; [*0231.0020.0002] -FE46 ; [*0232.0020.0002] -FE47 ; [*0312.0020.0016] -FE48 ; [*0313.0020.0016] -FE49 ; [*020A.0020.0004] -FE4A ; [*020A.0020.0004] -FE4B ; [*020A.0020.0004] -FE4C ; [*020A.0020.0004] -FE4D ; [*020B.0020.0004] -FE4E ; [*020B.0020.0004] -FE4F ; [*020B.0020.0004] -FE50 ; [*0221.0020.000F] -FE51 ; [*0230.0020.000F] -FE52 ; [*0274.0020.000F] -FE54 ; [*0233.0020.000F] -FE55 ; [*0238.0020.000F] -FE56 ; [*0264.0020.000F] -FE57 ; [*025F.0020.000F] -FE58 ; [*0216.0020.000F] -FE59 ; [*0310.0020.000F] -FE5A ; [*0311.0020.000F] -FE5B ; [*0314.0020.000F] -FE5C ; [*0315.0020.000F] -FE5D ; [*0372.0020.000F] -FE5E ; [*0373.0020.000F] -FE5F ; [*0391.0020.000F] -FE60 ; [*038F.0020.000F] -FE61 ; [*0388.0020.000F] -FE62 ; [*05F6.0020.000F] -FE63 ; [*020D.0020.000F] -FE64 ; [*05FA.0020.000F] -FE65 ; [*05FC.0020.000F] -FE66 ; [*05FB.0020.000F] -FE68 ; [*038E.0020.000F] -FE6A ; [*0392.0020.000F] -FE6B ; [*0387.0020.000F] -FE73 ; [.0000.0000.0000] -FF01 ; [*025F.0020.0003] -FF02 ; [*0305.0020.0003] -FF03 ; [*0391.0020.0003] -FF05 ; [*0392.0020.0003] -FF06 ; [*038F.0020.0003] -FF07 ; [*02FE.0020.0003] -FF08 ; [*0310.0020.0003] -FF09 ; [*0311.0020.0003] -FF0A ; [*0388.0020.0003] -FF0B ; [*05F6.0020.0003] -FF0C ; [*0221.0020.0003] -FF0D ; [*020D.0020.0003] -FF0E ; [*0274.0020.0003] -FF0F ; [*038D.0020.0003] -FF1A ; [*0238.0020.0003] -FF1B ; [*0233.0020.0003] -FF1C ; [*05FA.0020.0003] -FF1D ; [*05FB.0020.0003] -FF1E ; [*05FC.0020.0003] -FF1F ; [*0264.0020.0003] -FF20 ; [*0387.0020.0003] -FF3B ; [*0312.0020.0003] -FF3C ; [*038E.0020.0003] -FF3D ; [*0313.0020.0003] -FF3E ; [*0466.0020.0003] -FF3F ; [*020B.0020.0003] -FF40 ; [*0463.0020.0003] -FF5B ; [*0314.0020.0003] -FF5C ; [*05FE.0020.0003] -FF5D ; [*0315.0020.0003] -FF5E ; [*0600.0020.0003] -FF5F ; [*0326.0020.0003] -FF60 ; [*0327.0020.0003] -FF61 ; [*0287.0020.0012] -FF62 ; [*036C.0020.0012] -FF63 ; [*036D.0020.0012] -FF64 ; [*0230.0020.0012] -FF65 ; [*0220.0020.0012] -FFE2 ; [*05FD.0020.0003] -FFE3 ; [*0467.0020.0003] -FFE4 ; [*05FF.0020.0003] -FFE8 ; [*07F6.0020.0012] -FFE9 ; [*057C.0020.0012] -FFEA ; [*057E.0020.0012] -FFEB ; [*057D.0020.0012] -FFEC ; [*057F.0020.0012] -FFED ; [*0894.0020.0012] -FFEE ; [*08BF.0020.0012] -FFFC ; [*1A25.0020.0002] -10100 ; [*02F3.0020.0002] -10101 ; [*02F4.0020.0002] -10102 ; [*02F5.0020.0002] -10110 ; [*1A6F.0020.0002] -10111 ; [*1A70.0020.0002] -10112 ; [*1A71.0020.0002] -10113 ; [*1A72.0020.0002] -10114 ; [*1A73.0020.0002] -10115 ; [*1A74.0020.0002] -10116 ; [*1A75.0020.0002] -10117 ; [*1A76.0020.0002] -10118 ; [*1A77.0020.0002] -10119 ; [*1A78.0020.0002] -1011A ; [*1A79.0020.0002] -1011B ; [*1A7A.0020.0002] -1011C ; [*1A7B.0020.0002] -1011D ; [*1A7C.0020.0002] -1011E ; [*1A7D.0020.0002] -1011F ; [*1A7E.0020.0002] -10120 ; [*1A7F.0020.0002] -10121 ; [*1A80.0020.0002] -10122 ; [*1A81.0020.0002] -10123 ; [*1A82.0020.0002] -10124 ; [*1A83.0020.0002] -10125 ; [*1A84.0020.0002] -10126 ; [*1A85.0020.0002] -10127 ; [*1A86.0020.0002] -10128 ; [*1A87.0020.0002] -10129 ; [*1A88.0020.0002] -1012A ; [*1A89.0020.0002] -1012B ; [*1A8A.0020.0002] -1012C ; [*1A8B.0020.0002] -1012D ; [*1A8C.0020.0002] -1012E ; [*1A8D.0020.0002] -1012F ; [*1A8E.0020.0002] -10130 ; [*1A8F.0020.0002] -10131 ; [*1A90.0020.0002] -10132 ; [*1A91.0020.0002] -10133 ; [*1A92.0020.0002] -10137 ; [*0F54.0020.0002] -10138 ; [*0F55.0020.0002] -10139 ; [*0F56.0020.0002] -1013A ; [*0F57.0020.0002] -1013B ; [*0F58.0020.0002] -1013C ; [*0F59.0020.0002] -1013D ; [*0F5A.0020.0002] -1013E ; [*0F5B.0020.0002] -1013F ; [*0F5C.0020.0002] -10140 ; [*1A93.0020.0002] -10141 ; [*1A94.0020.0002] -10144 ; [*1A95.0020.0002] -10145 ; [*1A96.0020.0002] -10146 ; [*1A97.0020.0002] -10147 ; [*1A98.0020.0002] -10149 ; [*1A99.0020.0002] -1014A ; [*1A9A.0020.0002] -1014B ; [*1A9B.0020.0002] -1014C ; [*1A9C.0020.0002] -1014D ; [*1A9D.0020.0002] -1014E ; [*1A9E.0020.0002] -10150 ; [*1A9F.0020.0002] -10151 ; [*1AA0.0020.0002] -10152 ; [*1AA1.0020.0002] -10153 ; [*1AA2.0020.0002] -10154 ; [*1AA3.0020.0002] -10155 ; [*1AA4.0020.0002] -10156 ; [*1AA5.0020.0002] -10157 ; [*1AA6.0020.0002] -10160 ; [*1AA7.0020.0002] -10161 ; [*1AA8.0020.0002] -10162 ; [*1AA9.0020.0002] -10163 ; [*1AAA.0020.0002] -10164 ; [*1AAB.0020.0002] -10165 ; [*1AAC.0020.0002] -10166 ; [*1AAD.0020.0002] -10167 ; [*1AAE.0020.0002] -10168 ; [*1AAF.0020.0002] -10169 ; [*1AB0.0020.0002] -1016A ; [*1AB1.0020.0002] -1016B ; [*1AB2.0020.0002] -1016C ; [*1AB3.0020.0002] -1016D ; [*1AB4.0020.0002] -1016E ; [*1AB5.0020.0002] -1016F ; [*1AB6.0020.0002] -10170 ; [*1AB7.0020.0002] -10171 ; [*1AB8.0020.0002] -10172 ; [*1AB9.0020.0002] -10174 ; [*1ABA.0020.0002] -10175 ; [*1ABB.0020.0002] -10176 ; [*1ABC.0020.0002] -10177 ; [*1ABD.0020.0002] -10178 ; [*1ABE.0020.0002] -10179 ; [*0F5D.0020.0002] -1017A ; [*0F5E.0020.0002] -1017B ; [*0F5F.0020.0002] -1017C ; [*0F60.0020.0002] -1017D ; [*0F61.0020.0002] -1017E ; [*0F62.0020.0002] -1017F ; [*0F63.0020.0002] -10180 ; [*0F64.0020.0002] -10181 ; [*0F65.0020.0002] -10182 ; [*0F66.0020.0002] -10183 ; [*0F67.0020.0002] -10184 ; [*0F68.0020.0002] -10185 ; [*0F69.0020.0002] -10186 ; [*0F6A.0020.0002] -10187 ; [*0F6B.0020.0002] -10188 ; [*0F6C.0020.0002] -10189 ; [*0F6D.0020.0002] -1018B ; [*1ABF.0020.0002] -1018C ; [*0F6E.0020.0002] -10190 ; [*0F6F.0020.0002] -10191 ; [*0F70.0020.0002] -10192 ; [*0F71.0020.0002] -10193 ; [*0F72.0020.0002] -10194 ; [*0F73.0020.0002] -10195 ; [*0F74.0020.0002] -10196 ; [*0F75.0020.0002] -10197 ; [*0F76.0020.0002] -10198 ; [*0F77.0020.0002] -10199 ; [*0F78.0020.0002] -1019A ; [*0F79.0020.0002] -1019B ; [*0F7A.0020.0002] -101A0 ; [*0F7B.0020.0002] -101D0 ; [*0F7C.0020.0002] -101D1 ; [*0F7D.0020.0002] -101D2 ; [*0F7E.0020.0002] -101D3 ; [*0F7F.0020.0002] -101D4 ; [*0F80.0020.0002] -101D5 ; [*0F81.0020.0002] -101D6 ; [*0F82.0020.0002] -101D7 ; [*0F83.0020.0002] -101D8 ; [*0F84.0020.0002] -101D9 ; [*0F85.0020.0002] -101DA ; [*0F86.0020.0002] -101DB ; [*0F87.0020.0002] -101DC ; [*0F88.0020.0002] -101DD ; [*0F89.0020.0002] -101DE ; [*0F8A.0020.0002] -101DF ; [*0F8B.0020.0002] -101E0 ; [*0F8C.0020.0002] -101E1 ; [*0F8D.0020.0002] -101E2 ; [*0F8E.0020.0002] -101E3 ; [*0F8F.0020.0002] -101E4 ; [*0F90.0020.0002] -101E5 ; [*0F91.0020.0002] -101E6 ; [*0F92.0020.0002] -101E7 ; [*0F93.0020.0002] -101E8 ; [*0F94.0020.0002] -101E9 ; [*0F95.0020.0002] -101EA ; [*0F96.0020.0002] -101EB ; [*0F97.0020.0002] -101EC ; [*0F98.0020.0002] -101ED ; [*0F99.0020.0002] -101EE ; [*0F9A.0020.0002] -101EF ; [*0F9B.0020.0002] -101F0 ; [*0F9C.0020.0002] -101F1 ; [*0F9D.0020.0002] -101F2 ; [*0F9E.0020.0002] -101F3 ; [*0F9F.0020.0002] -101F4 ; [*0FA0.0020.0002] -101F5 ; [*0FA1.0020.0002] -101F6 ; [*0FA2.0020.0002] -101F7 ; [*0FA3.0020.0002] -101F8 ; [*0FA4.0020.0002] -101F9 ; [*0FA5.0020.0002] -101FA ; [*0FA6.0020.0002] -101FB ; [*0FA7.0020.0002] -101FC ; [*0FA8.0020.0002] -102E0 ; [.0000.0000.0000] -102EA ; [*1AC0.0020.0002] -102EB ; [*1AC1.0020.0002] -102EC ; [*1AC2.0020.0002] -102ED ; [*1AC3.0020.0002] -102EE ; [*1AC4.0020.0002] -102EF ; [*1AC5.0020.0002] -102F0 ; [*1AC6.0020.0002] -102F1 ; [*1AC7.0020.0002] -102F2 ; [*1AC8.0020.0002] -102F3 ; [*1AC9.0020.0002] -102F4 ; [*1ACA.0020.0002] -102F5 ; [*1ACB.0020.0002] -102F6 ; [*1ACC.0020.0002] -102F7 ; [*1ACD.0020.0002] -102F8 ; [*1ACE.0020.0002] -102F9 ; [*1ACF.0020.0002] -102FA ; [*1AD0.0020.0002] -102FB ; [*1AD1.0020.0002] -10322 ; [*1A69.0020.0002] -10323 ; [*1A6A.0020.0002] -1039F ; [*02F6.0020.0002] -103D0 ; [*02F7.0020.0002] -103D3 ; [*1AD2.0020.0002] -103D4 ; [*1AD3.0020.0002] -103D5 ; [*1AD4.0020.0002] -1056F ; [*041B.0020.0002] -10857 ; [*02D2.0020.0002] -1085B ; [*1AE4.0020.0002] -1085C ; [*1AE5.0020.0002] -1085D ; [*1AE6.0020.0002] -1085E ; [*1AE7.0020.0002] -1085F ; [*1AE8.0020.0002] -10877 ; [*0FA9.0020.0002] -10878 ; [*0FAA.0020.0002] -1087E ; [*1AD5.0020.0002] -1087F ; [*1AD6.0020.0002] -108AD ; [*1AD7.0020.0002] -108AE ; [*1AD8.0020.0002] -108AF ; [*1AD9.0020.0002] -108FD ; [*1ADA.0020.0002] -108FE ; [*1ADB.0020.0002] -108FF ; [*1ADC.0020.0002] -10917 ; [*1AE1.0020.0002] -10918 ; [*1AE2.0020.0002] -10919 ; [*1AE3.0020.0002] -1091F ; [*02F8.0020.0002] -1093F ; [*02F2.0020.0002] -109BC ; [*1B59.0020.0002] -109BD ; [*1B4E.0020.0002] -109C9 ; [*1B23.0020.0002] -109CA ; [*1B24.0020.0002] -109CB ; [*1B25.0020.0002] -109CC ; [*1B26.0020.0002] -109CD ; [*1B27.0020.0002] -109CE ; [*1B28.0020.0002] -109CF ; [*1B29.0020.0002] -109D2 ; [*1B2A.0020.0002] -109D3 ; [*1B2B.0020.0002] -109D4 ; [*1B2C.0020.0002] -109D5 ; [*1B2D.0020.0002] -109D6 ; [*1B2E.0020.0002] -109D7 ; [*1B2F.0020.0002] -109D8 ; [*1B30.0020.0002] -109D9 ; [*1B31.0020.0002] -109DA ; [*1B32.0020.0002] -109DB ; [*1B33.0020.0002] -109DC ; [*1B34.0020.0002] -109DD ; [*1B35.0020.0002] -109DE ; [*1B36.0020.0002] -109DF ; [*1B37.0020.0002] -109E0 ; [*1B38.0020.0002] -109E1 ; [*1B39.0020.0002] -109E2 ; [*1B3A.0020.0002] -109E3 ; [*1B3B.0020.0002] -109E4 ; [*1B3C.0020.0002] -109E5 ; [*1B3D.0020.0002] -109E6 ; [*1B3E.0020.0002] -109E7 ; [*1B3F.0020.0002] -109E8 ; [*1B40.0020.0002] -109E9 ; [*1B41.0020.0002] -109EA ; [*1B42.0020.0002] -109EB ; [*1B43.0020.0002] -109EC ; [*1B44.0020.0002] -109ED ; [*1B45.0020.0002] -109EE ; [*1B46.0020.0002] -109EF ; [*1B47.0020.0002] -109F0 ; [*1B48.0020.0002] -109F1 ; [*1B49.0020.0002] -109F2 ; [*1B4A.0020.0002] -109F3 ; [*1B4B.0020.0002] -109F4 ; [*1B4C.0020.0002] -109F5 ; [*1B4D.0020.0002] -109F6 ; [*1B4F.0020.0002] -109F7 ; [*1B50.0020.0002] -109F8 ; [*1B51.0020.0002] -109F9 ; [*1B52.0020.0002] -109FA ; [*1B53.0020.0002] -109FB ; [*1B54.0020.0002] -109FC ; [*1B55.0020.0002] -109FD ; [*1B56.0020.0002] -109FE ; [*1B57.0020.0002] -109FF ; [*1B58.0020.0002] -10A44 ; [*1B04.0020.0002] -10A45 ; [*1B05.0020.0002] -10A46 ; [*1B06.0020.0002] -10A47 ; [*1B07.0020.0002] -10A50 ; [*0421.0020.0002] -10A51 ; [*0422.0020.0002] -10A52 ; [*0423.0020.0002] -10A53 ; [*0424.0020.0002] -10A54 ; [*0425.0020.0002] -10A55 ; [*0426.0020.0002] -10A56 ; [*02A7.0020.0002] -10A57 ; [*02A8.0020.0002] -10A58 ; [*0427.0020.0002] -10A7E ; [*1ADD.0020.0002] -10A7F ; [*1ADE.0020.0002] -10A9E ; [*1ADF.0020.0002] -10A9F ; [*1AE0.0020.0002] -10AED ; [*1AE9.0020.0002] -10AEE ; [*1AEA.0020.0002] -10AEF ; [*1AEB.0020.0002] -10AF0 ; [*0429.0020.0002] -10AF1 ; [*042A.0020.0002] -10AF2 ; [*042B.0020.0002] -10AF3 ; [*042C.0020.0002] -10AF4 ; [*042D.0020.0002] -10AF5 ; [*042E.0020.0002] -10AF6 ; [*042F.0020.0002] -10B39 ; [*0428.0020.0002] -10B3A ; [*02D3.0020.0002] -10B3B ; [*02D4.0020.0002] -10B3C ; [*02D5.0020.0002] -10B3D ; [*02D6.0020.0002] -10B3E ; [*02D7.0020.0002] -10B3F ; [*02D8.0020.0002] -10B5C ; [*1AEC.0020.0002] -10B5D ; [*1AED.0020.0002] -10B5E ; [*1AEE.0020.0002] -10B5F ; [*1AEF.0020.0002] -10B7C ; [*1AF0.0020.0002] -10B7D ; [*1AF1.0020.0002] -10B7E ; [*1AF2.0020.0002] -10B7F ; [*1AF3.0020.0002] -10B99 ; [*0430.0020.0002] -10B9A ; [*0431.0020.0002] -10B9B ; [*0432.0020.0002] -10B9C ; [*0433.0020.0002] -10BAD ; [*1AF4.0020.0002] -10BAE ; [*1AF5.0020.0002] -10BAF ; [*1AF6.0020.0002] -10CFC ; [*1A6B.0020.0002] -10CFD ; [*1A6C.0020.0002] -10CFE ; [*1A6D.0020.0002] -10CFF ; [*1A6E.0020.0002] -10E69 ; [*1A52.0020.0002] -10E6A ; [*1A53.0020.0002] -10E6B ; [*1A54.0020.0002] -10E6C ; [*1A55.0020.0002] -10E6D ; [*1A56.0020.0002] -10E6E ; [*1A57.0020.0002] -10E6F ; [*1A58.0020.0002] -10E70 ; [*1A59.0020.0002] -10E71 ; [*1A5A.0020.0002] -10E72 ; [*1A5B.0020.0002] -10E73 ; [*1A5C.0020.0002] -10E74 ; [*1A5D.0020.0002] -10E75 ; [*1A5E.0020.0002] -10E76 ; [*1A5F.0020.0002] -10E77 ; [*1A60.0020.0002] -10E78 ; [*1A61.0020.0002] -10E79 ; [*1A62.0020.0002] -10E7A ; [*1A63.0020.0002] -10E7B ; [*1A64.0020.0002] -10E7C ; [*1A65.0020.0002] -10E7D ; [*1A66.0020.0002] -10E7E ; [*1A67.0020.0002] -11047 ; [*02A9.0020.0002] -11048 ; [*02AA.0020.0002] -11049 ; [*041C.0020.0002] -1104A ; [*041D.0020.0002] -1104B ; [*041E.0020.0002] -1104C ; [*041F.0020.0002] -1104D ; [*0420.0020.0002] -1105B ; [*1AF9.0020.0002] -1105C ; [*1AFA.0020.0002] -1105D ; [*1AFB.0020.0002] -1105E ; [*1AFC.0020.0002] -1105F ; [*1AFD.0020.0002] -11060 ; [*1AFE.0020.0002] -11061 ; [*1AFF.0020.0002] -11062 ; [*1B00.0020.0002] -11063 ; [*1B01.0020.0002] -11064 ; [*1B02.0020.0002] -11065 ; [*1B03.0020.0002] -110BB ; [*0434.0020.0002] -110BC ; [*0435.0020.0002] -110BD ; [.0000.0000.0000] -110BE ; [*02D9.0020.0002] -110BF ; [*02DA.0020.0002] -110C0 ; [*02AB.0020.0002] -110C1 ; [*02AC.0020.0002] -11140 ; [*02DB.0020.0002] -11141 ; [*02AD.0020.0002] -11142 ; [*02AE.0020.0002] -11143 ; [*0271.0020.0002] -11174 ; [*0436.0020.0002] -11175 ; [*0437.0020.0002] -111C5 ; [*02AF.0020.0002] -111C6 ; [*02B0.0020.0002] -111C7 ; [*0439.0020.0002] -111C8 ; [*02DC.0020.0002] -111C9 ; [*043A.0020.0002] -111CD ; [*0438.0020.0002] -111DB ; [*043B.0020.0002] -111DD ; [*043C.0020.0002] -111DE ; [*02DD.0020.0002] -111DF ; [*02DE.0020.0002] -111EA ; [*1B08.0020.0002] -111EB ; [*1B09.0020.0002] -111EC ; [*1B0A.0020.0002] -111ED ; [*1B0B.0020.0002] -111EE ; [*1B0C.0020.0002] -111EF ; [*1B0D.0020.0002] -111F0 ; [*1B0E.0020.0002] -111F1 ; [*1B0F.0020.0002] -111F2 ; [*1B10.0020.0002] -111F3 ; [*1B11.0020.0002] -111F4 ; [*1B12.0020.0002] -11238 ; [*02B1.0020.0002] -11239 ; [*02B2.0020.0002] -1123A ; [*043D.0020.0002] -1123B ; [*043E.0020.0002] -1123C ; [*043F.0020.0002] -1123D ; [*0440.0020.0002] -112A9 ; [*02DF.0020.0002] -11366 ; [.0000.0000.0000] -11367 ; [.0000.0000.0000] -11368 ; [.0000.0000.0000] -11369 ; [.0000.0000.0000] -1136A ; [.0000.0000.0000] -1136B ; [.0000.0000.0000] -1136C ; [.0000.0000.0000] -11370 ; [.0000.0000.0000] -11371 ; [.0000.0000.0000] -11372 ; [.0000.0000.0000] -11373 ; [.0000.0000.0000] -11374 ; [.0000.0000.0000] -114C6 ; [*0441.0020.0002] -115C1 ; [*0442.0020.0002] -115C2 ; [*02B3.0020.0002] -115C3 ; [*02B4.0020.0002] -115C4 ; [*0443.0020.0002] -115C5 ; [*0444.0020.0002] -115C6 ; [*0445.0020.0002] -115C7 ; [*0446.0020.0002] -115C8 ; [*0447.0020.0002] -115C9 ; [*0448.0020.0002] -115CA ; [*0449.0020.0002] -115CB ; [*044A.0020.0002] -115CC ; [*044B.0020.0002] -115CD ; [*044C.0020.0002] -115CE ; [*044D.0020.0002] -115CF ; [*044E.0020.0002] -115D0 ; [*044F.0020.0002] -115D1 ; [*0450.0020.0002] -115D2 ; [*0451.0020.0002] -115D3 ; [*0452.0020.0002] -115D4 ; [*0453.0020.0002] -115D5 ; [*0454.0020.0002] -115D6 ; [*0455.0020.0002] -115D7 ; [*0456.0020.0002] -11641 ; [*02B5.0020.0002] -11642 ; [*02B6.0020.0002] -11643 ; [*0457.0020.0002] -1173A ; [*1AF7.0020.0002] -1173B ; [*1AF8.0020.0002] -1173C ; [*02B7.0020.0002] -1173D ; [*02B8.0020.0002] -1173E ; [*02E0.0020.0002] -1173F ; [*0530.0020.0002] -118EA ; [*1B13.0020.0002] -118EB ; [*1B14.0020.0002] -118EC ; [*1B15.0020.0002] -118ED ; [*1B16.0020.0002] -118EE ; [*1B17.0020.0002] -118EF ; [*1B18.0020.0002] -118F0 ; [*1B19.0020.0002] -118F1 ; [*1B1A.0020.0002] -118F2 ; [*1B1B.0020.0002] -12432 ; [*1B5A.0020.0002] -12433 ; [*1B5B.0020.0002] -1245A ; [*1B5C.0020.0002] -1245B ; [*1B5D.0020.0002] -1245C ; [*1B5E.0020.0002] -1245D ; [*1B5F.0020.0002] -1245E ; [*1B60.0020.0002] -1245F ; [*1B61.0020.0002] -12460 ; [*1B62.0020.0002] -12461 ; [*1B63.0020.0002] -12462 ; [*1B64.0020.0002] -12463 ; [*1B65.0020.0002] -12464 ; [*1B66.0020.0002] -12465 ; [*1B67.0020.0002] -12466 ; [*1B68.0020.0002] -12467 ; [*1B69.0020.0002] -12468 ; [*1B6A.0020.0002] -12470 ; [*02F9.0020.0002] -12471 ; [*02FA.0020.0002] -12472 ; [*02FB.0020.0002] -12473 ; [*02FC.0020.0002] -12474 ; [*02FD.0020.0002] -16A6E ; [*02B9.0020.0002] -16A6F ; [*02BA.0020.0002] -16AF5 ; [*0285.0020.0002] -16B37 ; [*0458.0020.0002] -16B38 ; [*0459.0020.0002] -16B39 ; [*045A.0020.0002] -16B3A ; [*045B.0020.0002] -16B3B ; [*045C.0020.0002] -16B3C ; [*0FAB.0020.0002] -16B3D ; [*0FAC.0020.0002] -16B3E ; [*0FAD.0020.0002] -16B3F ; [*0FAE.0020.0002] -16B44 ; [*045D.0020.0002] -16B45 ; [*0FAF.0020.0002] -16B5B ; [*1B1C.0020.0002] -16B5C ; [*1B1D.0020.0002] -16B5D ; [*1B1E.0020.0002] -16B5E ; [*1B1F.0020.0002] -16B5F ; [*1B20.0020.0002] -16B60 ; [*1B21.0020.0002] -16B61 ; [*1B22.0020.0002] -1BC9C ; [*11A0.0020.0002] -1BC9F ; [*0286.0020.0002] -1D000 ; [*0FB0.0020.0002] -1D001 ; [*0FB1.0020.0002] -1D002 ; [*0FB2.0020.0002] -1D003 ; [*0FB3.0020.0002] -1D004 ; [*0FB4.0020.0002] -1D005 ; [*0FB5.0020.0002] -1D006 ; [*0FB6.0020.0002] -1D007 ; [*0FB7.0020.0002] -1D008 ; [*0FB8.0020.0002] -1D009 ; [*0FB9.0020.0002] -1D00A ; [*0FBA.0020.0002] -1D00B ; [*0FBB.0020.0002] -1D00C ; [*0FBC.0020.0002] -1D00D ; [*0FBD.0020.0002] -1D00E ; [*0FBE.0020.0002] -1D00F ; [*0FBF.0020.0002] -1D010 ; [*0FC0.0020.0002] -1D011 ; [*0FC1.0020.0002] -1D012 ; [*0FC2.0020.0002] -1D013 ; [*0FC3.0020.0002] -1D014 ; [*0FC4.0020.0002] -1D015 ; [*0FC5.0020.0002] -1D016 ; [*0FC6.0020.0002] -1D017 ; [*0FC7.0020.0002] -1D018 ; [*0FC8.0020.0002] -1D019 ; [*0FC9.0020.0002] -1D01A ; [*0FCA.0020.0002] -1D01B ; [*0FCB.0020.0002] -1D01C ; [*0FCC.0020.0002] -1D01D ; [*0FCD.0020.0002] -1D01E ; [*0FCE.0020.0002] -1D01F ; [*0FCF.0020.0002] -1D020 ; [*0FD0.0020.0002] -1D021 ; [*0FD1.0020.0002] -1D022 ; [*0FD2.0020.0002] -1D023 ; [*0FD3.0020.0002] -1D024 ; [*0FD4.0020.0002] -1D025 ; [*0FD5.0020.0002] -1D026 ; [*0FD6.0020.0002] -1D027 ; [*0FD7.0020.0002] -1D028 ; [*0FD8.0020.0002] -1D029 ; [*0FD9.0020.0002] -1D02A ; [*0FDA.0020.0002] -1D02B ; [*0FDB.0020.0002] -1D02C ; [*0FDC.0020.0002] -1D02D ; [*0FDD.0020.0002] -1D02E ; [*0FDE.0020.0002] -1D02F ; [*0FDF.0020.0002] -1D030 ; [*0FE0.0020.0002] -1D031 ; [*0FE1.0020.0002] -1D032 ; [*0FE2.0020.0002] -1D033 ; [*0FE3.0020.0002] -1D034 ; [*0FE4.0020.0002] -1D035 ; [*0FE5.0020.0002] -1D036 ; [*0FE6.0020.0002] -1D037 ; [*0FE7.0020.0002] -1D038 ; [*0FE8.0020.0002] -1D039 ; [*0FE9.0020.0002] -1D03A ; [*0FEA.0020.0002] -1D03B ; [*0FEB.0020.0002] -1D03C ; [*0FEC.0020.0002] -1D03D ; [*0FED.0020.0002] -1D03E ; [*0FEE.0020.0002] -1D03F ; [*0FEF.0020.0002] -1D040 ; [*0FF0.0020.0002] -1D041 ; [*0FF1.0020.0002] -1D042 ; [*0FF2.0020.0002] -1D043 ; [*0FF3.0020.0002] -1D044 ; [*0FF4.0020.0002] -1D045 ; [*0FF5.0020.0002] -1D046 ; [*0FF6.0020.0002] -1D047 ; [*0FF7.0020.0002] -1D048 ; [*0FF8.0020.0002] -1D049 ; [*0FF9.0020.0002] -1D04A ; [*0FFA.0020.0002] -1D04B ; [*0FFB.0020.0002] -1D04C ; [*0FFC.0020.0002] -1D04D ; [*0FFD.0020.0002] -1D04E ; [*0FFE.0020.0002] -1D04F ; [*0FFF.0020.0002] -1D050 ; [*1000.0020.0002] -1D051 ; [*1001.0020.0002] -1D052 ; [*1002.0020.0002] -1D053 ; [*1003.0020.0002] -1D054 ; [*1004.0020.0002] -1D055 ; [*1005.0020.0002] -1D056 ; [*1006.0020.0002] -1D057 ; [*1007.0020.0002] -1D058 ; [*1008.0020.0002] -1D059 ; [*1009.0020.0002] -1D05A ; [*100A.0020.0002] -1D05B ; [*100B.0020.0002] -1D05C ; [*100C.0020.0002] -1D05D ; [*100D.0020.0002] -1D05E ; [*100E.0020.0002] -1D05F ; [*100F.0020.0002] -1D060 ; [*1010.0020.0002] -1D061 ; [*1011.0020.0002] -1D062 ; [*1012.0020.0002] -1D063 ; [*1013.0020.0002] -1D064 ; [*1014.0020.0002] -1D065 ; [*1015.0020.0002] -1D066 ; [*1016.0020.0002] -1D067 ; [*1017.0020.0002] -1D068 ; [*1018.0020.0002] -1D069 ; [*1019.0020.0002] -1D06A ; [*101A.0020.0002] -1D06B ; [*101B.0020.0002] -1D06C ; [*101C.0020.0002] -1D06D ; [*101D.0020.0002] -1D06E ; [*101E.0020.0002] -1D06F ; [*101F.0020.0002] -1D070 ; [*1020.0020.0002] -1D071 ; [*1021.0020.0002] -1D072 ; [*1022.0020.0002] -1D073 ; [*1023.0020.0002] -1D074 ; [*1024.0020.0002] -1D075 ; [*1025.0020.0002] -1D076 ; [*1026.0020.0002] -1D077 ; [*1027.0020.0002] -1D078 ; [*1028.0020.0002] -1D079 ; [*1029.0020.0002] -1D07A ; [*102A.0020.0002] -1D07B ; [*102B.0020.0002] -1D07C ; [*102C.0020.0002] -1D07D ; [*102D.0020.0002] -1D07E ; [*102E.0020.0002] -1D07F ; [*102F.0020.0002] -1D080 ; [*1030.0020.0002] -1D081 ; [*1031.0020.0002] -1D082 ; [*1032.0020.0002] -1D083 ; [*1033.0020.0002] -1D084 ; [*1034.0020.0002] -1D085 ; [*1035.0020.0002] -1D086 ; [*1036.0020.0002] -1D087 ; [*1037.0020.0002] -1D088 ; [*1038.0020.0002] -1D089 ; [*1039.0020.0002] -1D08A ; [*103A.0020.0002] -1D08B ; [*103B.0020.0002] -1D08C ; [*103C.0020.0002] -1D08D ; [*103D.0020.0002] -1D08E ; [*103E.0020.0002] -1D08F ; [*103F.0020.0002] -1D090 ; [*1040.0020.0002] -1D091 ; [*1041.0020.0002] -1D092 ; [*1042.0020.0002] -1D093 ; [*1043.0020.0002] -1D094 ; [*1044.0020.0002] -1D095 ; [*1045.0020.0002] -1D096 ; [*1046.0020.0002] -1D097 ; [*1047.0020.0002] -1D098 ; [*1048.0020.0002] -1D099 ; [*1049.0020.0002] -1D09A ; [*104A.0020.0002] -1D09B ; [*104B.0020.0002] -1D09C ; [*104C.0020.0002] -1D09D ; [*104D.0020.0002] -1D09E ; [*104E.0020.0002] -1D09F ; [*104F.0020.0002] -1D0A0 ; [*1050.0020.0002] -1D0A1 ; [*1051.0020.0002] -1D0A2 ; [*1052.0020.0002] -1D0A3 ; [*1053.0020.0002] -1D0A4 ; [*1054.0020.0002] -1D0A5 ; [*1055.0020.0002] -1D0A6 ; [*1056.0020.0002] -1D0A7 ; [*1057.0020.0002] -1D0A8 ; [*1058.0020.0002] -1D0A9 ; [*1059.0020.0002] -1D0AA ; [*105A.0020.0002] -1D0AB ; [*105B.0020.0002] -1D0AC ; [*105C.0020.0002] -1D0AD ; [*105D.0020.0002] -1D0AE ; [*105E.0020.0002] -1D0AF ; [*105F.0020.0002] -1D0B0 ; [*1060.0020.0002] -1D0B1 ; [*1061.0020.0002] -1D0B2 ; [*1062.0020.0002] -1D0B3 ; [*1063.0020.0002] -1D0B4 ; [*1064.0020.0002] -1D0B5 ; [*1065.0020.0002] -1D0B6 ; [*1066.0020.0002] -1D0B7 ; [*1067.0020.0002] -1D0B8 ; [*1068.0020.0002] -1D0B9 ; [*1069.0020.0002] -1D0BA ; [*106A.0020.0002] -1D0BB ; [*106B.0020.0002] -1D0BC ; [*106C.0020.0002] -1D0BD ; [*106D.0020.0002] -1D0BE ; [*106E.0020.0002] -1D0BF ; [*106F.0020.0002] -1D0C0 ; [*1070.0020.0002] -1D0C1 ; [*1071.0020.0002] -1D0C2 ; [*1072.0020.0002] -1D0C3 ; [*1073.0020.0002] -1D0C4 ; [*1074.0020.0002] -1D0C5 ; [*1075.0020.0002] -1D0C6 ; [*1076.0020.0002] -1D0C7 ; [*1077.0020.0002] -1D0C8 ; [*1078.0020.0002] -1D0C9 ; [*1079.0020.0002] -1D0CA ; [*107A.0020.0002] -1D0CB ; [*107B.0020.0002] -1D0CC ; [*107C.0020.0002] -1D0CD ; [*107D.0020.0002] -1D0CE ; [*107E.0020.0002] -1D0CF ; [*107F.0020.0002] -1D0D0 ; [*1080.0020.0002] -1D0D1 ; [*1081.0020.0002] -1D0D2 ; [*1082.0020.0002] -1D0D3 ; [*1083.0020.0002] -1D0D4 ; [*1084.0020.0002] -1D0D5 ; [*1085.0020.0002] -1D0D6 ; [*1086.0020.0002] -1D0D7 ; [*1087.0020.0002] -1D0D8 ; [*1088.0020.0002] -1D0D9 ; [*1089.0020.0002] -1D0DA ; [*108A.0020.0002] -1D0DB ; [*108B.0020.0002] -1D0DC ; [*108C.0020.0002] -1D0DD ; [*108D.0020.0002] -1D0DE ; [*108E.0020.0002] -1D0DF ; [*108F.0020.0002] -1D0E0 ; [*1090.0020.0002] -1D0E1 ; [*1091.0020.0002] -1D0E2 ; [*1092.0020.0002] -1D0E3 ; [*1093.0020.0002] -1D0E4 ; [*1094.0020.0002] -1D0E5 ; [*1095.0020.0002] -1D0E6 ; [*1096.0020.0002] -1D0E7 ; [*1097.0020.0002] -1D0E8 ; [*1098.0020.0002] -1D0E9 ; [*1099.0020.0002] -1D0EA ; [*109A.0020.0002] -1D0EB ; [*109B.0020.0002] -1D0EC ; [*109C.0020.0002] -1D0ED ; [*109D.0020.0002] -1D0EE ; [*109E.0020.0002] -1D0EF ; [*109F.0020.0002] -1D0F0 ; [*10A0.0020.0002] -1D0F1 ; [*10A1.0020.0002] -1D0F2 ; [*10A2.0020.0002] -1D0F3 ; [*10A3.0020.0002] -1D0F4 ; [*10A4.0020.0002] -1D0F5 ; [*10A5.0020.0002] -1D100 ; [*10A6.0020.0002] -1D101 ; [*10A7.0020.0002] -1D102 ; [*10A8.0020.0002] -1D103 ; [*10A9.0020.0002] -1D104 ; [*10AA.0020.0002] -1D105 ; [*10AB.0020.0002] -1D106 ; [*10AC.0020.0002] -1D107 ; [*10AD.0020.0002] -1D108 ; [*10AE.0020.0002] -1D109 ; [*10AF.0020.0002] -1D10A ; [*10B0.0020.0002] -1D10B ; [*10B1.0020.0002] -1D10C ; [*10B2.0020.0002] -1D10D ; [*10B3.0020.0002] -1D10E ; [*10B4.0020.0002] -1D10F ; [*10B5.0020.0002] -1D110 ; [*10B6.0020.0002] -1D111 ; [*10B7.0020.0002] -1D112 ; [*10B8.0020.0002] -1D113 ; [*10B9.0020.0002] -1D114 ; [*10BA.0020.0002] -1D115 ; [*10BB.0020.0002] -1D116 ; [*10BC.0020.0002] -1D117 ; [*10BD.0020.0002] -1D118 ; [*10BE.0020.0002] -1D119 ; [*10BF.0020.0002] -1D11A ; [*10C0.0020.0002] -1D11B ; [*10C1.0020.0002] -1D11C ; [*10C2.0020.0002] -1D11D ; [*10C3.0020.0002] -1D11E ; [*10C4.0020.0002] -1D11F ; [*10C5.0020.0002] -1D120 ; [*10C6.0020.0002] -1D121 ; [*10C7.0020.0002] -1D122 ; [*10C8.0020.0002] -1D123 ; [*10C9.0020.0002] -1D124 ; [*10CA.0020.0002] -1D125 ; [*10CB.0020.0002] -1D126 ; [*10CC.0020.0002] -1D129 ; [*10E0.0020.0002] -1D12A ; [*10D0.0020.0002] -1D12B ; [*10D1.0020.0002] -1D12C ; [*10D2.0020.0002] -1D12D ; [*10D3.0020.0002] -1D12E ; [*10D4.0020.0002] -1D12F ; [*10D5.0020.0002] -1D130 ; [*10D6.0020.0002] -1D131 ; [*10D7.0020.0002] -1D132 ; [*10D8.0020.0002] -1D133 ; [*10D9.0020.0002] -1D134 ; [*10DA.0020.0002] -1D135 ; [*10DB.0020.0002] -1D136 ; [*10DC.0020.0002] -1D137 ; [*10DD.0020.0002] -1D138 ; [*10DE.0020.0002] -1D139 ; [*10DF.0020.0002] -1D13A ; [*10E1.0020.0002] -1D13B ; [*10E2.0020.0002] -1D13C ; [*10E3.0020.0002] -1D13D ; [*10E4.0020.0002] -1D13E ; [*10E5.0020.0002] -1D13F ; [*10E6.0020.0002] -1D140 ; [*10E7.0020.0002] -1D141 ; [*10E8.0020.0002] -1D142 ; [*10E9.0020.0002] -1D143 ; [*10EA.0020.0002] -1D144 ; [*10EB.0020.0002] -1D145 ; [*10EC.0020.0002] -1D146 ; [*10ED.0020.0002] -1D147 ; [*10EE.0020.0002] -1D148 ; [*10EF.0020.0002] -1D149 ; [*10F0.0020.0002] -1D14A ; [*10F1.0020.0002] -1D14B ; [*10F2.0020.0002] -1D14C ; [*10F3.0020.0002] -1D14D ; [*10F4.0020.0002] -1D14E ; [*10F5.0020.0002] -1D14F ; [*10F6.0020.0002] -1D150 ; [*10F7.0020.0002] -1D151 ; [*10F8.0020.0002] -1D152 ; [*10F9.0020.0002] -1D153 ; [*10FA.0020.0002] -1D154 ; [*10FB.0020.0002] -1D155 ; [*10FC.0020.0002] -1D156 ; [*10FD.0020.0002] -1D157 ; [*10FE.0020.0002] -1D158 ; [*10FF.0020.0002] -1D159 ; [*1100.0020.0002] -1D15A ; [*1101.0020.0002] -1D15B ; [*1102.0020.0002] -1D15C ; [*1103.0020.0002] -1D15D ; [*1104.0020.0002] -1D15E ; [*10FE.0020.0002][.0000.0000.0000] -1D15F ; [*10FF.0020.0002][.0000.0000.0000] -1D160 ; [*10FF.0020.0002][.0000.0000.0000][.0000.0000.0000] -1D161 ; [*10FF.0020.0002][.0000.0000.0000][.0000.0000.0000] -1D162 ; [*10FF.0020.0002][.0000.0000.0000][.0000.0000.0000] -1D163 ; [*10FF.0020.0002][.0000.0000.0000][.0000.0000.0000] -1D164 ; [*10FF.0020.0002][.0000.0000.0000][.0000.0000.0000] -1D165 ; [.0000.0000.0000] -1D166 ; [.0000.0000.0000] -1D167 ; [.0000.0000.0000] -1D168 ; [.0000.0000.0000] -1D169 ; [.0000.0000.0000] -1D16A ; [*1105.0020.0002] -1D16B ; [*1106.0020.0002] -1D16C ; [*1107.0020.0002] -1D16D ; [.0000.0000.0000] -1D16E ; [.0000.0000.0000] -1D16F ; [.0000.0000.0000] -1D170 ; [.0000.0000.0000] -1D171 ; [.0000.0000.0000] -1D172 ; [.0000.0000.0000] -1D17B ; [.0000.0000.0000] -1D17C ; [.0000.0000.0000] -1D17D ; [.0000.0000.0000] -1D17E ; [.0000.0000.0000] -1D17F ; [.0000.0000.0000] -1D180 ; [.0000.0000.0000] -1D181 ; [.0000.0000.0000] -1D182 ; [.0000.0000.0000] -1D183 ; [*1108.0020.0002] -1D184 ; [*1109.0020.0002] -1D185 ; [.0000.0000.0000] -1D186 ; [.0000.0000.0000] -1D187 ; [.0000.0000.0000] -1D188 ; [.0000.0000.0000] -1D189 ; [.0000.0000.0000] -1D18A ; [.0000.0000.0000] -1D18B ; [.0000.0000.0000] -1D18C ; [*110A.0020.0002] -1D18D ; [*110B.0020.0002] -1D18E ; [*110C.0020.0002] -1D18F ; [*110D.0020.0002] -1D190 ; [*110E.0020.0002] -1D191 ; [*110F.0020.0002] -1D192 ; [*1110.0020.0002] -1D193 ; [*1111.0020.0002] -1D194 ; [*1112.0020.0002] -1D195 ; [*1113.0020.0002] -1D196 ; [*1114.0020.0002] -1D197 ; [*1115.0020.0002] -1D198 ; [*1116.0020.0002] -1D199 ; [*1117.0020.0002] -1D19A ; [*1118.0020.0002] -1D19B ; [*1119.0020.0002] -1D19C ; [*111A.0020.0002] -1D19D ; [*111B.0020.0002] -1D19E ; [*111C.0020.0002] -1D19F ; [*111D.0020.0002] -1D1A0 ; [*111E.0020.0002] -1D1A1 ; [*111F.0020.0002] -1D1A2 ; [*1120.0020.0002] -1D1A3 ; [*1121.0020.0002] -1D1A4 ; [*1122.0020.0002] -1D1A5 ; [*1123.0020.0002] -1D1A6 ; [*1124.0020.0002] -1D1A7 ; [*1125.0020.0002] -1D1A8 ; [*1126.0020.0002] -1D1A9 ; [*1127.0020.0002] -1D1AA ; [.0000.0000.0000] -1D1AB ; [.0000.0000.0000] -1D1AC ; [.0000.0000.0000] -1D1AD ; [.0000.0000.0000] -1D1AE ; [*1128.0020.0002] -1D1AF ; [*1129.0020.0002] -1D1B0 ; [*112A.0020.0002] -1D1B1 ; [*112B.0020.0002] -1D1B2 ; [*112C.0020.0002] -1D1B3 ; [*112D.0020.0002] -1D1B4 ; [*112E.0020.0002] -1D1B5 ; [*112F.0020.0002] -1D1B6 ; [*1130.0020.0002] -1D1B7 ; [*1131.0020.0002] -1D1B8 ; [*1132.0020.0002] -1D1B9 ; [*1133.0020.0002] -1D1BA ; [*1134.0020.0002] -1D1BB ; [*1133.0020.0002][.0000.0000.0000] -1D1BC ; [*1134.0020.0002][.0000.0000.0000] -1D1BD ; [*1133.0020.0002][.0000.0000.0000][.0000.0000.0000] -1D1BE ; [*1134.0020.0002][.0000.0000.0000][.0000.0000.0000] -1D1BF ; [*1133.0020.0002][.0000.0000.0000][.0000.0000.0000] -1D1C0 ; [*1134.0020.0002][.0000.0000.0000][.0000.0000.0000] -1D1C1 ; [*1135.0020.0002] -1D1C2 ; [*1136.0020.0002] -1D1C3 ; [*1137.0020.0002] -1D1C4 ; [*1138.0020.0002] -1D1C5 ; [*1139.0020.0002] -1D1C6 ; [*113A.0020.0002] -1D1C7 ; [*113B.0020.0002] -1D1C8 ; [*113C.0020.0002] -1D1C9 ; [*113D.0020.0002] -1D1CA ; [*113E.0020.0002] -1D1CB ; [*113F.0020.0002] -1D1CC ; [*1140.0020.0002] -1D1CD ; [*1141.0020.0002] -1D1CE ; [*1142.0020.0002] -1D1CF ; [*1143.0020.0002] -1D1D0 ; [*1144.0020.0002] -1D1D1 ; [*1145.0020.0002] -1D1D2 ; [*1146.0020.0002] -1D1D3 ; [*1147.0020.0002] -1D1D4 ; [*1148.0020.0002] -1D1D5 ; [*1149.0020.0002] -1D1D6 ; [*114A.0020.0002] -1D1D7 ; [*114B.0020.0002] -1D1D8 ; [*114C.0020.0002] -1D1D9 ; [*114D.0020.0002] -1D1DA ; [*114E.0020.0002] -1D1DB ; [*114F.0020.0002] -1D1DC ; [*1150.0020.0002] -1D1DD ; [*1151.0020.0002] -1D1DE ; [*1152.0020.0002] -1D1DF ; [*1153.0020.0002] -1D1E0 ; [*1154.0020.0002] -1D1E1 ; [*1155.0020.0002] -1D1E2 ; [*1156.0020.0002] -1D1E3 ; [*1157.0020.0002] -1D1E4 ; [*1158.0020.0002] -1D1E5 ; [*1159.0020.0002] -1D1E6 ; [*115A.0020.0002] -1D1E7 ; [*115B.0020.0002] -1D1E8 ; [*115C.0020.0002] -1D200 ; [*115D.0020.0002] -1D201 ; [*115E.0020.0002] -1D202 ; [*115F.0020.0002] -1D203 ; [*1160.0020.0002] -1D204 ; [*1161.0020.0002] -1D205 ; [*1162.0020.0002] -1D206 ; [*1163.0020.0002] -1D207 ; [*1164.0020.0002] -1D208 ; [*1165.0020.0002] -1D209 ; [*1166.0020.0002] -1D20A ; [*1167.0020.0002] -1D20B ; [*1168.0020.0002] -1D20C ; [*1169.0020.0002] -1D20D ; [*116A.0020.0002] -1D20E ; [*116B.0020.0002] -1D20F ; [*116C.0020.0002] -1D210 ; [*116D.0020.0002] -1D211 ; [*116E.0020.0002] -1D212 ; [*116F.0020.0002] -1D213 ; [*1170.0020.0002] -1D214 ; [*1171.0020.0002] -1D215 ; [*1172.0020.0002] -1D216 ; [*1173.0020.0002] -1D217 ; [*1174.0020.0002] -1D218 ; [*1175.0020.0002] -1D219 ; [*1176.0020.0002] -1D21A ; [*1177.0020.0002] -1D21B ; [*1178.0020.0002] -1D21C ; [*1179.0020.0002] -1D21D ; [*117A.0020.0002] -1D21E ; [*117B.0020.0002] -1D21F ; [*117C.0020.0002] -1D220 ; [*117D.0020.0002] -1D221 ; [*117E.0020.0002] -1D222 ; [*117F.0020.0002] -1D223 ; [*1180.0020.0002] -1D224 ; [*1181.0020.0002] -1D225 ; [*1182.0020.0002] -1D226 ; [*1183.0020.0002] -1D227 ; [*1184.0020.0002] -1D228 ; [*1185.0020.0002] -1D229 ; [*1186.0020.0002] -1D22A ; [*1187.0020.0002] -1D22B ; [*1188.0020.0002] -1D22C ; [*1189.0020.0002] -1D22D ; [*118A.0020.0002] -1D22E ; [*118B.0020.0002] -1D22F ; [*118C.0020.0002] -1D230 ; [*118D.0020.0002] -1D231 ; [*118E.0020.0002] -1D232 ; [*118F.0020.0002] -1D233 ; [*1190.0020.0002] -1D234 ; [*1191.0020.0002] -1D235 ; [*1192.0020.0002] -1D236 ; [*1193.0020.0002] -1D237 ; [*1194.0020.0002] -1D238 ; [*1195.0020.0002] -1D239 ; [*1196.0020.0002] -1D23A ; [*1197.0020.0002] -1D23B ; [*1198.0020.0002] -1D23C ; [*1199.0020.0002] -1D23D ; [*119A.0020.0002] -1D23E ; [*119B.0020.0002] -1D23F ; [*119C.0020.0002] -1D240 ; [*119D.0020.0002] -1D241 ; [*119E.0020.0002] -1D242 ; [.0000.0000.0000] -1D243 ; [.0000.0000.0000] -1D244 ; [.0000.0000.0000] -1D245 ; [*119F.0020.0002] -1D300 ; [*0EC6.0020.0002] -1D301 ; [*0EC7.0020.0002] -1D302 ; [*0EC8.0020.0002] -1D303 ; [*0EC9.0020.0002] -1D304 ; [*0ECA.0020.0002] -1D305 ; [*0ECB.0020.0002] -1D306 ; [*0ECC.0020.0002] -1D307 ; [*0ECD.0020.0002] -1D308 ; [*0ECE.0020.0002] -1D309 ; [*0ECF.0020.0002] -1D30A ; [*0ED0.0020.0002] -1D30B ; [*0ED1.0020.0002] -1D30C ; [*0ED2.0020.0002] -1D30D ; [*0ED3.0020.0002] -1D30E ; [*0ED4.0020.0002] -1D30F ; [*0ED5.0020.0002] -1D310 ; [*0ED6.0020.0002] -1D311 ; [*0ED7.0020.0002] -1D312 ; [*0ED8.0020.0002] -1D313 ; [*0ED9.0020.0002] -1D314 ; [*0EDA.0020.0002] -1D315 ; [*0EDB.0020.0002] -1D316 ; [*0EDC.0020.0002] -1D317 ; [*0EDD.0020.0002] -1D318 ; [*0EDE.0020.0002] -1D319 ; [*0EDF.0020.0002] -1D31A ; [*0EE0.0020.0002] -1D31B ; [*0EE1.0020.0002] -1D31C ; [*0EE2.0020.0002] -1D31D ; [*0EE3.0020.0002] -1D31E ; [*0EE4.0020.0002] -1D31F ; [*0EE5.0020.0002] -1D320 ; [*0EE6.0020.0002] -1D321 ; [*0EE7.0020.0002] -1D322 ; [*0EE8.0020.0002] -1D323 ; [*0EE9.0020.0002] -1D324 ; [*0EEA.0020.0002] -1D325 ; [*0EEB.0020.0002] -1D326 ; [*0EEC.0020.0002] -1D327 ; [*0EED.0020.0002] -1D328 ; [*0EEE.0020.0002] -1D329 ; [*0EEF.0020.0002] -1D32A ; [*0EF0.0020.0002] -1D32B ; [*0EF1.0020.0002] -1D32C ; [*0EF2.0020.0002] -1D32D ; [*0EF3.0020.0002] -1D32E ; [*0EF4.0020.0002] -1D32F ; [*0EF5.0020.0002] -1D330 ; [*0EF6.0020.0002] -1D331 ; [*0EF7.0020.0002] -1D332 ; [*0EF8.0020.0002] -1D333 ; [*0EF9.0020.0002] -1D334 ; [*0EFA.0020.0002] -1D335 ; [*0EFB.0020.0002] -1D336 ; [*0EFC.0020.0002] -1D337 ; [*0EFD.0020.0002] -1D338 ; [*0EFE.0020.0002] -1D339 ; [*0EFF.0020.0002] -1D33A ; [*0F00.0020.0002] -1D33B ; [*0F01.0020.0002] -1D33C ; [*0F02.0020.0002] -1D33D ; [*0F03.0020.0002] -1D33E ; [*0F04.0020.0002] -1D33F ; [*0F05.0020.0002] -1D340 ; [*0F06.0020.0002] -1D341 ; [*0F07.0020.0002] -1D342 ; [*0F08.0020.0002] -1D343 ; [*0F09.0020.0002] -1D344 ; [*0F0A.0020.0002] -1D345 ; [*0F0B.0020.0002] -1D346 ; [*0F0C.0020.0002] -1D347 ; [*0F0D.0020.0002] -1D348 ; [*0F0E.0020.0002] -1D349 ; [*0F0F.0020.0002] -1D34A ; [*0F10.0020.0002] -1D34B ; [*0F11.0020.0002] -1D34C ; [*0F12.0020.0002] -1D34D ; [*0F13.0020.0002] -1D34E ; [*0F14.0020.0002] -1D34F ; [*0F15.0020.0002] -1D350 ; [*0F16.0020.0002] -1D351 ; [*0F17.0020.0002] -1D352 ; [*0F18.0020.0002] -1D353 ; [*0F19.0020.0002] -1D354 ; [*0F1A.0020.0002] -1D355 ; [*0F1B.0020.0002] -1D356 ; [*0F1C.0020.0002] -1D369 ; [*1B6B.0020.0002] -1D36A ; [*1B6C.0020.0002] -1D36B ; [*1B6D.0020.0002] -1D36C ; [*1B6E.0020.0002] -1D36D ; [*1B6F.0020.0002] -1D36E ; [*1B70.0020.0002] -1D36F ; [*1B71.0020.0002] -1D370 ; [*1B72.0020.0002] -1D371 ; [*1B73.0020.0002] -1D6C1 ; [*05EC.0020.0005] -1D6DB ; [*05E8.0020.0005] -1D6FB ; [*05EC.0020.0005] -1D715 ; [*05E8.0020.0005] -1D735 ; [*05EC.0020.0005] -1D74F ; [*05E8.0020.0005] -1D76F ; [*05EC.0020.0005] -1D789 ; [*05E8.0020.0005] -1D7A9 ; [*05EC.0020.0005] -1D7C3 ; [*05E8.0020.0005] -1D800 ; [*17CF.0020.0002] -1D801 ; [*17D0.0020.0002] -1D802 ; [*17D1.0020.0002] -1D803 ; [*17D2.0020.0002] -1D804 ; [*17D3.0020.0002] -1D805 ; [*17D4.0020.0002] -1D806 ; [*17D5.0020.0002] -1D807 ; [*17D6.0020.0002] -1D808 ; [*17D7.0020.0002] -1D809 ; [*17D8.0020.0002] -1D80A ; [*17D9.0020.0002] -1D80B ; [*17DA.0020.0002] -1D80C ; [*17DB.0020.0002] -1D80D ; [*17DC.0020.0002] -1D80E ; [*17DD.0020.0002] -1D80F ; [*17DE.0020.0002] -1D810 ; [*17DF.0020.0002] -1D811 ; [*17E0.0020.0002] -1D812 ; [*17E1.0020.0002] -1D813 ; [*17E2.0020.0002] -1D814 ; [*17E3.0020.0002] -1D815 ; [*17E4.0020.0002] -1D816 ; [*17E5.0020.0002] -1D817 ; [*17E6.0020.0002] -1D818 ; [*17E7.0020.0002] -1D819 ; [*17E8.0020.0002] -1D81A ; [*17E9.0020.0002] -1D81B ; [*17EA.0020.0002] -1D81C ; [*17EB.0020.0002] -1D81D ; [*17EC.0020.0002] -1D81E ; [*17ED.0020.0002] -1D81F ; [*17EE.0020.0002] -1D820 ; [*17EF.0020.0002] -1D821 ; [*17F0.0020.0002] -1D822 ; [*17F1.0020.0002] -1D823 ; [*17F2.0020.0002] -1D824 ; [*17F3.0020.0002] -1D825 ; [*17F4.0020.0002] -1D826 ; [*17F5.0020.0002] -1D827 ; [*17F6.0020.0002] -1D828 ; [*17F7.0020.0002] -1D829 ; [*17F8.0020.0002] -1D82A ; [*17F9.0020.0002] -1D82B ; [*17FA.0020.0002] -1D82C ; [*17FB.0020.0002] -1D82D ; [*17FC.0020.0002] -1D82E ; [*17FD.0020.0002] -1D82F ; [*17FE.0020.0002] -1D830 ; [*17FF.0020.0002] -1D831 ; [*1800.0020.0002] -1D832 ; [*1801.0020.0002] -1D833 ; [*1802.0020.0002] -1D834 ; [*1803.0020.0002] -1D835 ; [*1804.0020.0002] -1D836 ; [*1805.0020.0002] -1D837 ; [*1806.0020.0002] -1D838 ; [*1807.0020.0002] -1D839 ; [*1808.0020.0002] -1D83A ; [*1809.0020.0002] -1D83B ; [*180A.0020.0002] -1D83C ; [*180B.0020.0002] -1D83D ; [*180C.0020.0002] -1D83E ; [*180D.0020.0002] -1D83F ; [*180E.0020.0002] -1D840 ; [*180F.0020.0002] -1D841 ; [*1810.0020.0002] -1D842 ; [*1811.0020.0002] -1D843 ; [*1812.0020.0002] -1D844 ; [*1813.0020.0002] -1D845 ; [*1814.0020.0002] -1D846 ; [*1815.0020.0002] -1D847 ; [*1816.0020.0002] -1D848 ; [*1817.0020.0002] -1D849 ; [*1818.0020.0002] -1D84A ; [*1819.0020.0002] -1D84B ; [*181A.0020.0002] -1D84C ; [*181B.0020.0002] -1D84D ; [*181C.0020.0002] -1D84E ; [*181D.0020.0002] -1D84F ; [*181E.0020.0002] -1D850 ; [*181F.0020.0002] -1D851 ; [*1820.0020.0002] -1D852 ; [*1821.0020.0002] -1D853 ; [*1822.0020.0002] -1D854 ; [*1823.0020.0002] -1D855 ; [*1824.0020.0002] -1D856 ; [*1825.0020.0002] -1D857 ; [*1826.0020.0002] -1D858 ; [*1827.0020.0002] -1D859 ; [*1828.0020.0002] -1D85A ; [*1829.0020.0002] -1D85B ; [*182A.0020.0002] -1D85C ; [*182B.0020.0002] -1D85D ; [*182C.0020.0002] -1D85E ; [*182D.0020.0002] -1D85F ; [*182E.0020.0002] -1D860 ; [*182F.0020.0002] -1D861 ; [*1830.0020.0002] -1D862 ; [*1831.0020.0002] -1D863 ; [*1832.0020.0002] -1D864 ; [*1833.0020.0002] -1D865 ; [*1834.0020.0002] -1D866 ; [*1835.0020.0002] -1D867 ; [*1836.0020.0002] -1D868 ; [*1837.0020.0002] -1D869 ; [*1838.0020.0002] -1D86A ; [*1839.0020.0002] -1D86B ; [*183A.0020.0002] -1D86C ; [*183B.0020.0002] -1D86D ; [*183C.0020.0002] -1D86E ; [*183D.0020.0002] -1D86F ; [*183E.0020.0002] -1D870 ; [*183F.0020.0002] -1D871 ; [*1840.0020.0002] -1D872 ; [*1841.0020.0002] -1D873 ; [*1842.0020.0002] -1D874 ; [*1843.0020.0002] -1D875 ; [*1844.0020.0002] -1D876 ; [*1845.0020.0002] -1D877 ; [*1846.0020.0002] -1D878 ; [*1847.0020.0002] -1D879 ; [*1848.0020.0002] -1D87A ; [*1849.0020.0002] -1D87B ; [*184A.0020.0002] -1D87C ; [*184B.0020.0002] -1D87D ; [*184C.0020.0002] -1D87E ; [*184D.0020.0002] -1D87F ; [*184E.0020.0002] -1D880 ; [*184F.0020.0002] -1D881 ; [*1850.0020.0002] -1D882 ; [*1851.0020.0002] -1D883 ; [*1852.0020.0002] -1D884 ; [*1853.0020.0002] -1D885 ; [*1854.0020.0002] -1D886 ; [*1855.0020.0002] -1D887 ; [*1856.0020.0002] -1D888 ; [*1857.0020.0002] -1D889 ; [*1858.0020.0002] -1D88A ; [*1859.0020.0002] -1D88B ; [*185A.0020.0002] -1D88C ; [*185B.0020.0002] -1D88D ; [*185C.0020.0002] -1D88E ; [*185D.0020.0002] -1D88F ; [*185E.0020.0002] -1D890 ; [*185F.0020.0002] -1D891 ; [*1860.0020.0002] -1D892 ; [*1861.0020.0002] -1D893 ; [*1862.0020.0002] -1D894 ; [*1863.0020.0002] -1D895 ; [*1864.0020.0002] -1D896 ; [*1865.0020.0002] -1D897 ; [*1866.0020.0002] -1D898 ; [*1867.0020.0002] -1D899 ; [*1868.0020.0002] -1D89A ; [*1869.0020.0002] -1D89B ; [*186A.0020.0002] -1D89C ; [*186B.0020.0002] -1D89D ; [*186C.0020.0002] -1D89E ; [*186D.0020.0002] -1D89F ; [*186E.0020.0002] -1D8A0 ; [*186F.0020.0002] -1D8A1 ; [*1870.0020.0002] -1D8A2 ; [*1871.0020.0002] -1D8A3 ; [*1872.0020.0002] -1D8A4 ; [*1873.0020.0002] -1D8A5 ; [*1874.0020.0002] -1D8A6 ; [*1875.0020.0002] -1D8A7 ; [*1876.0020.0002] -1D8A8 ; [*1877.0020.0002] -1D8A9 ; [*1878.0020.0002] -1D8AA ; [*1879.0020.0002] -1D8AB ; [*187A.0020.0002] -1D8AC ; [*187B.0020.0002] -1D8AD ; [*187C.0020.0002] -1D8AE ; [*187D.0020.0002] -1D8AF ; [*187E.0020.0002] -1D8B0 ; [*187F.0020.0002] -1D8B1 ; [*1880.0020.0002] -1D8B2 ; [*1881.0020.0002] -1D8B3 ; [*1882.0020.0002] -1D8B4 ; [*1883.0020.0002] -1D8B5 ; [*1884.0020.0002] -1D8B6 ; [*1885.0020.0002] -1D8B7 ; [*1886.0020.0002] -1D8B8 ; [*1887.0020.0002] -1D8B9 ; [*1888.0020.0002] -1D8BA ; [*1889.0020.0002] -1D8BB ; [*188A.0020.0002] -1D8BC ; [*188B.0020.0002] -1D8BD ; [*188C.0020.0002] -1D8BE ; [*188D.0020.0002] -1D8BF ; [*188E.0020.0002] -1D8C0 ; [*188F.0020.0002] -1D8C1 ; [*1890.0020.0002] -1D8C2 ; [*1891.0020.0002] -1D8C3 ; [*1892.0020.0002] -1D8C4 ; [*1893.0020.0002] -1D8C5 ; [*1894.0020.0002] -1D8C6 ; [*1895.0020.0002] -1D8C7 ; [*1896.0020.0002] -1D8C8 ; [*1897.0020.0002] -1D8C9 ; [*1898.0020.0002] -1D8CA ; [*1899.0020.0002] -1D8CB ; [*189A.0020.0002] -1D8CC ; [*189B.0020.0002] -1D8CD ; [*189C.0020.0002] -1D8CE ; [*189D.0020.0002] -1D8CF ; [*189E.0020.0002] -1D8D0 ; [*189F.0020.0002] -1D8D1 ; [*18A0.0020.0002] -1D8D2 ; [*18A1.0020.0002] -1D8D3 ; [*18A2.0020.0002] -1D8D4 ; [*18A3.0020.0002] -1D8D5 ; [*18A4.0020.0002] -1D8D6 ; [*18A5.0020.0002] -1D8D7 ; [*18A6.0020.0002] -1D8D8 ; [*18A7.0020.0002] -1D8D9 ; [*18A8.0020.0002] -1D8DA ; [*18A9.0020.0002] -1D8DB ; [*18AA.0020.0002] -1D8DC ; [*18AB.0020.0002] -1D8DD ; [*18AC.0020.0002] -1D8DE ; [*18AD.0020.0002] -1D8DF ; [*18AE.0020.0002] -1D8E0 ; [*18AF.0020.0002] -1D8E1 ; [*18B0.0020.0002] -1D8E2 ; [*18B1.0020.0002] -1D8E3 ; [*18B2.0020.0002] -1D8E4 ; [*18B3.0020.0002] -1D8E5 ; [*18B4.0020.0002] -1D8E6 ; [*18B5.0020.0002] -1D8E7 ; [*18B6.0020.0002] -1D8E8 ; [*18B7.0020.0002] -1D8E9 ; [*18B8.0020.0002] -1D8EA ; [*18B9.0020.0002] -1D8EB ; [*18BA.0020.0002] -1D8EC ; [*18BB.0020.0002] -1D8ED ; [*18BC.0020.0002] -1D8EE ; [*18BD.0020.0002] -1D8EF ; [*18BE.0020.0002] -1D8F0 ; [*18BF.0020.0002] -1D8F1 ; [*18C0.0020.0002] -1D8F2 ; [*18C1.0020.0002] -1D8F3 ; [*18C2.0020.0002] -1D8F4 ; [*18C3.0020.0002] -1D8F5 ; [*18C4.0020.0002] -1D8F6 ; [*18C5.0020.0002] -1D8F7 ; [*18C6.0020.0002] -1D8F8 ; [*18C7.0020.0002] -1D8F9 ; [*18C8.0020.0002] -1D8FA ; [*18C9.0020.0002] -1D8FB ; [*18CA.0020.0002] -1D8FC ; [*18CB.0020.0002] -1D8FD ; [*18CC.0020.0002] -1D8FE ; [*18CD.0020.0002] -1D8FF ; [*18CE.0020.0002] -1D900 ; [*18CF.0020.0002] -1D901 ; [*18D0.0020.0002] -1D902 ; [*18D1.0020.0002] -1D903 ; [*18D2.0020.0002] -1D904 ; [*18D3.0020.0002] -1D905 ; [*18D4.0020.0002] -1D906 ; [*18D5.0020.0002] -1D907 ; [*18D6.0020.0002] -1D908 ; [*18D7.0020.0002] -1D909 ; [*18D8.0020.0002] -1D90A ; [*18D9.0020.0002] -1D90B ; [*18DA.0020.0002] -1D90C ; [*18DB.0020.0002] -1D90D ; [*18DC.0020.0002] -1D90E ; [*18DD.0020.0002] -1D90F ; [*18DE.0020.0002] -1D910 ; [*18DF.0020.0002] -1D911 ; [*18E0.0020.0002] -1D912 ; [*18E1.0020.0002] -1D913 ; [*18E2.0020.0002] -1D914 ; [*18E3.0020.0002] -1D915 ; [*18E4.0020.0002] -1D916 ; [*18E5.0020.0002] -1D917 ; [*18E6.0020.0002] -1D918 ; [*18E7.0020.0002] -1D919 ; [*18E8.0020.0002] -1D91A ; [*18E9.0020.0002] -1D91B ; [*18EA.0020.0002] -1D91C ; [*18EB.0020.0002] -1D91D ; [*18EC.0020.0002] -1D91E ; [*18ED.0020.0002] -1D91F ; [*18EE.0020.0002] -1D920 ; [*18EF.0020.0002] -1D921 ; [*18F0.0020.0002] -1D922 ; [*18F1.0020.0002] -1D923 ; [*18F2.0020.0002] -1D924 ; [*18F3.0020.0002] -1D925 ; [*18F4.0020.0002] -1D926 ; [*18F5.0020.0002] -1D927 ; [*18F6.0020.0002] -1D928 ; [*18F7.0020.0002] -1D929 ; [*18F8.0020.0002] -1D92A ; [*18F9.0020.0002] -1D92B ; [*18FA.0020.0002] -1D92C ; [*18FB.0020.0002] -1D92D ; [*18FC.0020.0002] -1D92E ; [*18FD.0020.0002] -1D92F ; [*18FE.0020.0002] -1D930 ; [*18FF.0020.0002] -1D931 ; [*1900.0020.0002] -1D932 ; [*1901.0020.0002] -1D933 ; [*1902.0020.0002] -1D934 ; [*1903.0020.0002] -1D935 ; [*1904.0020.0002] -1D936 ; [*1905.0020.0002] -1D937 ; [*1906.0020.0002] -1D938 ; [*1907.0020.0002] -1D939 ; [*1908.0020.0002] -1D93A ; [*1909.0020.0002] -1D93B ; [*190A.0020.0002] -1D93C ; [*190B.0020.0002] -1D93D ; [*190C.0020.0002] -1D93E ; [*190D.0020.0002] -1D93F ; [*190E.0020.0002] -1D940 ; [*190F.0020.0002] -1D941 ; [*1910.0020.0002] -1D942 ; [*1911.0020.0002] -1D943 ; [*1912.0020.0002] -1D944 ; [*1913.0020.0002] -1D945 ; [*1914.0020.0002] -1D946 ; [*1915.0020.0002] -1D947 ; [*1916.0020.0002] -1D948 ; [*1917.0020.0002] -1D949 ; [*1918.0020.0002] -1D94A ; [*1919.0020.0002] -1D94B ; [*191A.0020.0002] -1D94C ; [*191B.0020.0002] -1D94D ; [*191C.0020.0002] -1D94E ; [*191D.0020.0002] -1D94F ; [*191E.0020.0002] -1D950 ; [*191F.0020.0002] -1D951 ; [*1920.0020.0002] -1D952 ; [*1921.0020.0002] -1D953 ; [*1922.0020.0002] -1D954 ; [*1923.0020.0002] -1D955 ; [*1924.0020.0002] -1D956 ; [*1925.0020.0002] -1D957 ; [*1926.0020.0002] -1D958 ; [*1927.0020.0002] -1D959 ; [*1928.0020.0002] -1D95A ; [*1929.0020.0002] -1D95B ; [*192A.0020.0002] -1D95C ; [*192B.0020.0002] -1D95D ; [*192C.0020.0002] -1D95E ; [*192D.0020.0002] -1D95F ; [*192E.0020.0002] -1D960 ; [*192F.0020.0002] -1D961 ; [*1930.0020.0002] -1D962 ; [*1931.0020.0002] -1D963 ; [*1932.0020.0002] -1D964 ; [*1933.0020.0002] -1D965 ; [*1934.0020.0002] -1D966 ; [*1935.0020.0002] -1D967 ; [*1936.0020.0002] -1D968 ; [*1937.0020.0002] -1D969 ; [*1938.0020.0002] -1D96A ; [*1939.0020.0002] -1D96B ; [*193A.0020.0002] -1D96C ; [*193B.0020.0002] -1D96D ; [*193C.0020.0002] -1D96E ; [*193D.0020.0002] -1D96F ; [*193E.0020.0002] -1D970 ; [*193F.0020.0002] -1D971 ; [*1940.0020.0002] -1D972 ; [*1941.0020.0002] -1D973 ; [*1942.0020.0002] -1D974 ; [*1943.0020.0002] -1D975 ; [*1944.0020.0002] -1D976 ; [*1945.0020.0002] -1D977 ; [*1946.0020.0002] -1D978 ; [*1947.0020.0002] -1D979 ; [*1948.0020.0002] -1D97A ; [*1949.0020.0002] -1D97B ; [*194A.0020.0002] -1D97C ; [*194B.0020.0002] -1D97D ; [*194C.0020.0002] -1D97E ; [*194D.0020.0002] -1D97F ; [*194E.0020.0002] -1D980 ; [*194F.0020.0002] -1D981 ; [*1950.0020.0002] -1D982 ; [*1951.0020.0002] -1D983 ; [*1952.0020.0002] -1D984 ; [*1953.0020.0002] -1D985 ; [*1954.0020.0002] -1D986 ; [*1955.0020.0002] -1D987 ; [*1956.0020.0002] -1D988 ; [*1957.0020.0002] -1D989 ; [*1958.0020.0002] -1D98A ; [*1959.0020.0002] -1D98B ; [*195A.0020.0002] -1D98C ; [*195B.0020.0002] -1D98D ; [*195C.0020.0002] -1D98E ; [*195D.0020.0002] -1D98F ; [*195E.0020.0002] -1D990 ; [*195F.0020.0002] -1D991 ; [*1960.0020.0002] -1D992 ; [*1961.0020.0002] -1D993 ; [*1962.0020.0002] -1D994 ; [*1963.0020.0002] -1D995 ; [*1964.0020.0002] -1D996 ; [*1965.0020.0002] -1D997 ; [*1966.0020.0002] -1D998 ; [*1967.0020.0002] -1D999 ; [*1968.0020.0002] -1D99A ; [*1969.0020.0002] -1D99B ; [*196A.0020.0002] -1D99C ; [*196B.0020.0002] -1D99D ; [*196C.0020.0002] -1D99E ; [*196D.0020.0002] -1D99F ; [*196E.0020.0002] -1D9A0 ; [*196F.0020.0002] -1D9A1 ; [*1970.0020.0002] -1D9A2 ; [*1971.0020.0002] -1D9A3 ; [*1972.0020.0002] -1D9A4 ; [*1973.0020.0002] -1D9A5 ; [*1974.0020.0002] -1D9A6 ; [*1975.0020.0002] -1D9A7 ; [*1976.0020.0002] -1D9A8 ; [*1977.0020.0002] -1D9A9 ; [*1978.0020.0002] -1D9AA ; [*1979.0020.0002] -1D9AB ; [*197A.0020.0002] -1D9AC ; [*197B.0020.0002] -1D9AD ; [*197C.0020.0002] -1D9AE ; [*197D.0020.0002] -1D9AF ; [*197E.0020.0002] -1D9B0 ; [*197F.0020.0002] -1D9B1 ; [*1980.0020.0002] -1D9B2 ; [*1981.0020.0002] -1D9B3 ; [*1982.0020.0002] -1D9B4 ; [*1983.0020.0002] -1D9B5 ; [*1984.0020.0002] -1D9B6 ; [*1985.0020.0002] -1D9B7 ; [*1986.0020.0002] -1D9B8 ; [*1987.0020.0002] -1D9B9 ; [*1988.0020.0002] -1D9BA ; [*1989.0020.0002] -1D9BB ; [*198A.0020.0002] -1D9BC ; [*198B.0020.0002] -1D9BD ; [*198C.0020.0002] -1D9BE ; [*198D.0020.0002] -1D9BF ; [*198E.0020.0002] -1D9C0 ; [*198F.0020.0002] -1D9C1 ; [*1990.0020.0002] -1D9C2 ; [*1991.0020.0002] -1D9C3 ; [*1992.0020.0002] -1D9C4 ; [*1993.0020.0002] -1D9C5 ; [*1994.0020.0002] -1D9C6 ; [*1995.0020.0002] -1D9C7 ; [*1996.0020.0002] -1D9C8 ; [*1997.0020.0002] -1D9C9 ; [*1998.0020.0002] -1D9CA ; [*1999.0020.0002] -1D9CB ; [*199A.0020.0002] -1D9CC ; [*199B.0020.0002] -1D9CD ; [*199C.0020.0002] -1D9CE ; [*199D.0020.0002] -1D9CF ; [*199E.0020.0002] -1D9D0 ; [*199F.0020.0002] -1D9D1 ; [*19A0.0020.0002] -1D9D2 ; [*19A1.0020.0002] -1D9D3 ; [*19A2.0020.0002] -1D9D4 ; [*19A3.0020.0002] -1D9D5 ; [*19A4.0020.0002] -1D9D6 ; [*19A5.0020.0002] -1D9D7 ; [*19A6.0020.0002] -1D9D8 ; [*19A7.0020.0002] -1D9D9 ; [*19A8.0020.0002] -1D9DA ; [*19A9.0020.0002] -1D9DB ; [*19AA.0020.0002] -1D9DC ; [*19AB.0020.0002] -1D9DD ; [*19AC.0020.0002] -1D9DE ; [*19AD.0020.0002] -1D9DF ; [*19AE.0020.0002] -1D9E0 ; [*19AF.0020.0002] -1D9E1 ; [*19B0.0020.0002] -1D9E2 ; [*19B1.0020.0002] -1D9E3 ; [*19B2.0020.0002] -1D9E4 ; [*19B3.0020.0002] -1D9E5 ; [*19B4.0020.0002] -1D9E6 ; [*19B5.0020.0002] -1D9E7 ; [*19B6.0020.0002] -1D9E8 ; [*19B7.0020.0002] -1D9E9 ; [*19B8.0020.0002] -1D9EA ; [*19B9.0020.0002] -1D9EB ; [*19BA.0020.0002] -1D9EC ; [*19BB.0020.0002] -1D9ED ; [*19BC.0020.0002] -1D9EE ; [*19BD.0020.0002] -1D9EF ; [*19BE.0020.0002] -1D9F0 ; [*19BF.0020.0002] -1D9F1 ; [*19C0.0020.0002] -1D9F2 ; [*19C1.0020.0002] -1D9F3 ; [*19C2.0020.0002] -1D9F4 ; [*19C3.0020.0002] -1D9F5 ; [*19C4.0020.0002] -1D9F6 ; [*19C5.0020.0002] -1D9F7 ; [*19C6.0020.0002] -1D9F8 ; [*19C7.0020.0002] -1D9F9 ; [*19C8.0020.0002] -1D9FA ; [*19C9.0020.0002] -1D9FB ; [*19CA.0020.0002] -1D9FC ; [*19CB.0020.0002] -1D9FD ; [*19CC.0020.0002] -1D9FE ; [*19CD.0020.0002] -1D9FF ; [*19CE.0020.0002] -1DA00 ; [.0000.0000.0000] -1DA01 ; [.0000.0000.0000] -1DA02 ; [.0000.0000.0000] -1DA03 ; [.0000.0000.0000] -1DA04 ; [.0000.0000.0000] -1DA05 ; [.0000.0000.0000] -1DA06 ; [.0000.0000.0000] -1DA07 ; [.0000.0000.0000] -1DA08 ; [.0000.0000.0000] -1DA09 ; [.0000.0000.0000] -1DA0A ; [.0000.0000.0000] -1DA0B ; [.0000.0000.0000] -1DA0C ; [.0000.0000.0000] -1DA0D ; [.0000.0000.0000] -1DA0E ; [.0000.0000.0000] -1DA0F ; [.0000.0000.0000] -1DA10 ; [.0000.0000.0000] -1DA11 ; [.0000.0000.0000] -1DA12 ; [.0000.0000.0000] -1DA13 ; [.0000.0000.0000] -1DA14 ; [.0000.0000.0000] -1DA15 ; [.0000.0000.0000] -1DA16 ; [.0000.0000.0000] -1DA17 ; [.0000.0000.0000] -1DA18 ; [.0000.0000.0000] -1DA19 ; [.0000.0000.0000] -1DA1A ; [.0000.0000.0000] -1DA1B ; [.0000.0000.0000] -1DA1C ; [.0000.0000.0000] -1DA1D ; [.0000.0000.0000] -1DA1E ; [.0000.0000.0000] -1DA1F ; [.0000.0000.0000] -1DA20 ; [.0000.0000.0000] -1DA21 ; [.0000.0000.0000] -1DA22 ; [.0000.0000.0000] -1DA23 ; [.0000.0000.0000] -1DA24 ; [.0000.0000.0000] -1DA25 ; [.0000.0000.0000] -1DA26 ; [.0000.0000.0000] -1DA27 ; [.0000.0000.0000] -1DA28 ; [.0000.0000.0000] -1DA29 ; [.0000.0000.0000] -1DA2A ; [.0000.0000.0000] -1DA2B ; [.0000.0000.0000] -1DA2C ; [.0000.0000.0000] -1DA2D ; [.0000.0000.0000] -1DA2E ; [.0000.0000.0000] -1DA2F ; [.0000.0000.0000] -1DA30 ; [.0000.0000.0000] -1DA31 ; [.0000.0000.0000] -1DA32 ; [.0000.0000.0000] -1DA33 ; [.0000.0000.0000] -1DA34 ; [.0000.0000.0000] -1DA35 ; [.0000.0000.0000] -1DA36 ; [.0000.0000.0000] -1DA37 ; [*19CF.0020.0002] -1DA38 ; [*19D0.0020.0002] -1DA39 ; [*19D1.0020.0002] -1DA3A ; [*19D2.0020.0002] -1DA3B ; [.0000.0000.0000] -1DA3C ; [.0000.0000.0000] -1DA3D ; [.0000.0000.0000] -1DA3E ; [.0000.0000.0000] -1DA3F ; [.0000.0000.0000] -1DA40 ; [.0000.0000.0000] -1DA41 ; [.0000.0000.0000] -1DA42 ; [.0000.0000.0000] -1DA43 ; [.0000.0000.0000] -1DA44 ; [.0000.0000.0000] -1DA45 ; [.0000.0000.0000] -1DA46 ; [.0000.0000.0000] -1DA47 ; [.0000.0000.0000] -1DA48 ; [.0000.0000.0000] -1DA49 ; [.0000.0000.0000] -1DA4A ; [.0000.0000.0000] -1DA4B ; [.0000.0000.0000] -1DA4C ; [.0000.0000.0000] -1DA4D ; [.0000.0000.0000] -1DA4E ; [.0000.0000.0000] -1DA4F ; [.0000.0000.0000] -1DA50 ; [.0000.0000.0000] -1DA51 ; [.0000.0000.0000] -1DA52 ; [.0000.0000.0000] -1DA53 ; [.0000.0000.0000] -1DA54 ; [.0000.0000.0000] -1DA55 ; [.0000.0000.0000] -1DA56 ; [.0000.0000.0000] -1DA57 ; [.0000.0000.0000] -1DA58 ; [.0000.0000.0000] -1DA59 ; [.0000.0000.0000] -1DA5A ; [.0000.0000.0000] -1DA5B ; [.0000.0000.0000] -1DA5C ; [.0000.0000.0000] -1DA5D ; [.0000.0000.0000] -1DA5E ; [.0000.0000.0000] -1DA5F ; [.0000.0000.0000] -1DA60 ; [.0000.0000.0000] -1DA61 ; [.0000.0000.0000] -1DA62 ; [.0000.0000.0000] -1DA63 ; [.0000.0000.0000] -1DA64 ; [.0000.0000.0000] -1DA65 ; [.0000.0000.0000] -1DA66 ; [.0000.0000.0000] -1DA67 ; [.0000.0000.0000] -1DA68 ; [.0000.0000.0000] -1DA69 ; [.0000.0000.0000] -1DA6A ; [.0000.0000.0000] -1DA6B ; [.0000.0000.0000] -1DA6C ; [.0000.0000.0000] -1DA6D ; [*19D3.0020.0002] -1DA6E ; [*19D4.0020.0002] -1DA6F ; [*19D5.0020.0002] -1DA70 ; [*19D6.0020.0002] -1DA71 ; [*19D7.0020.0002] -1DA72 ; [*19D8.0020.0002] -1DA73 ; [*19D9.0020.0002] -1DA74 ; [*19DA.0020.0002] -1DA75 ; [.0000.0000.0000] -1DA76 ; [*19DB.0020.0002] -1DA77 ; [*19DC.0020.0002] -1DA78 ; [*19DD.0020.0002] -1DA79 ; [*19DE.0020.0002] -1DA7A ; [*19DF.0020.0002] -1DA7B ; [*19E0.0020.0002] -1DA7C ; [*19E1.0020.0002] -1DA7D ; [*19E2.0020.0002] -1DA7E ; [*19E3.0020.0002] -1DA7F ; [*19E4.0020.0002] -1DA80 ; [*19E5.0020.0002] -1DA81 ; [*19E6.0020.0002] -1DA82 ; [*19E7.0020.0002] -1DA83 ; [*19E8.0020.0002] -1DA84 ; [.0000.0000.0000] -1DA85 ; [*19E9.0020.0002] -1DA86 ; [*19EA.0020.0002] -1DA87 ; [*045E.0020.0002] -1DA88 ; [*045F.0020.0002] -1DA89 ; [*0460.0020.0002] -1DA8A ; [*0461.0020.0002] -1DA8B ; [*0462.0020.0002] -1DA9B ; [.0000.0000.0000] -1DA9C ; [.0000.0000.0000] -1DA9D ; [.0000.0000.0000] -1DA9E ; [.0000.0000.0000] -1DA9F ; [.0000.0000.0000] -1DAA1 ; [.0000.0000.0000] -1DAA2 ; [.0000.0000.0000] -1DAA3 ; [.0000.0000.0000] -1DAA4 ; [.0000.0000.0000] -1DAA5 ; [.0000.0000.0000] -1DAA6 ; [.0000.0000.0000] -1DAA7 ; [.0000.0000.0000] -1DAA8 ; [.0000.0000.0000] -1DAA9 ; [.0000.0000.0000] -1DAAA ; [.0000.0000.0000] -1DAAB ; [.0000.0000.0000] -1DAAC ; [.0000.0000.0000] -1DAAD ; [.0000.0000.0000] -1DAAE ; [.0000.0000.0000] -1DAAF ; [.0000.0000.0000] -1E8D0 ; [.0000.0000.0000] -1E8D1 ; [.0000.0000.0000] -1E8D2 ; [.0000.0000.0000] -1E8D3 ; [.0000.0000.0000] -1E8D4 ; [.0000.0000.0000] -1E8D5 ; [.0000.0000.0000] -1E8D6 ; [.0000.0000.0000] -1EEF0 ; [*04DC.0020.0002] -1EEF1 ; [*04DD.0020.0002] -1F000 ; [*11A1.0020.0002] -1F001 ; [*11A2.0020.0002] -1F002 ; [*11A3.0020.0002] -1F003 ; [*11A4.0020.0002] -1F004 ; [*11A5.0020.0002] -1F005 ; [*11A6.0020.0002] -1F006 ; [*11A7.0020.0002] -1F007 ; [*11A8.0020.0002] -1F008 ; [*11A9.0020.0002] -1F009 ; [*11AA.0020.0002] -1F00A ; [*11AB.0020.0002] -1F00B ; [*11AC.0020.0002] -1F00C ; [*11AD.0020.0002] -1F00D ; [*11AE.0020.0002] -1F00E ; [*11AF.0020.0002] -1F00F ; [*11B0.0020.0002] -1F010 ; [*11B1.0020.0002] -1F011 ; [*11B2.0020.0002] -1F012 ; [*11B3.0020.0002] -1F013 ; [*11B4.0020.0002] -1F014 ; [*11B5.0020.0002] -1F015 ; [*11B6.0020.0002] -1F016 ; [*11B7.0020.0002] -1F017 ; [*11B8.0020.0002] -1F018 ; [*11B9.0020.0002] -1F019 ; [*11BA.0020.0002] -1F01A ; [*11BB.0020.0002] -1F01B ; [*11BC.0020.0002] -1F01C ; [*11BD.0020.0002] -1F01D ; [*11BE.0020.0002] -1F01E ; [*11BF.0020.0002] -1F01F ; [*11C0.0020.0002] -1F020 ; [*11C1.0020.0002] -1F021 ; [*11C2.0020.0002] -1F022 ; [*11C3.0020.0002] -1F023 ; [*11C4.0020.0002] -1F024 ; [*11C5.0020.0002] -1F025 ; [*11C6.0020.0002] -1F026 ; [*11C7.0020.0002] -1F027 ; [*11C8.0020.0002] -1F028 ; [*11C9.0020.0002] -1F029 ; [*11CA.0020.0002] -1F02A ; [*11CB.0020.0002] -1F02B ; [*11CC.0020.0002] -1F030 ; [*11CD.0020.0002] -1F031 ; [*11CE.0020.0002] -1F032 ; [*11CF.0020.0002] -1F033 ; [*11D0.0020.0002] -1F034 ; [*11D1.0020.0002] -1F035 ; [*11D2.0020.0002] -1F036 ; [*11D3.0020.0002] -1F037 ; [*11D4.0020.0002] -1F038 ; [*11D5.0020.0002] -1F039 ; [*11D6.0020.0002] -1F03A ; [*11D7.0020.0002] -1F03B ; [*11D8.0020.0002] -1F03C ; [*11D9.0020.0002] -1F03D ; [*11DA.0020.0002] -1F03E ; [*11DB.0020.0002] -1F03F ; [*11DC.0020.0002] -1F040 ; [*11DD.0020.0002] -1F041 ; [*11DE.0020.0002] -1F042 ; [*11DF.0020.0002] -1F043 ; [*11E0.0020.0002] -1F044 ; [*11E1.0020.0002] -1F045 ; [*11E2.0020.0002] -1F046 ; [*11E3.0020.0002] -1F047 ; [*11E4.0020.0002] -1F048 ; [*11E5.0020.0002] -1F049 ; [*11E6.0020.0002] -1F04A ; [*11E7.0020.0002] -1F04B ; [*11E8.0020.0002] -1F04C ; [*11E9.0020.0002] -1F04D ; [*11EA.0020.0002] -1F04E ; [*11EB.0020.0002] -1F04F ; [*11EC.0020.0002] -1F050 ; [*11ED.0020.0002] -1F051 ; [*11EE.0020.0002] -1F052 ; [*11EF.0020.0002] -1F053 ; [*11F0.0020.0002] -1F054 ; [*11F1.0020.0002] -1F055 ; [*11F2.0020.0002] -1F056 ; [*11F3.0020.0002] -1F057 ; [*11F4.0020.0002] -1F058 ; [*11F5.0020.0002] -1F059 ; [*11F6.0020.0002] -1F05A ; [*11F7.0020.0002] -1F05B ; [*11F8.0020.0002] -1F05C ; [*11F9.0020.0002] -1F05D ; [*11FA.0020.0002] -1F05E ; [*11FB.0020.0002] -1F05F ; [*11FC.0020.0002] -1F060 ; [*11FD.0020.0002] -1F061 ; [*11FE.0020.0002] -1F062 ; [*11FF.0020.0002] -1F063 ; [*1200.0020.0002] -1F064 ; [*1201.0020.0002] -1F065 ; [*1202.0020.0002] -1F066 ; [*1203.0020.0002] -1F067 ; [*1204.0020.0002] -1F068 ; [*1205.0020.0002] -1F069 ; [*1206.0020.0002] -1F06A ; [*1207.0020.0002] -1F06B ; [*1208.0020.0002] -1F06C ; [*1209.0020.0002] -1F06D ; [*120A.0020.0002] -1F06E ; [*120B.0020.0002] -1F06F ; [*120C.0020.0002] -1F070 ; [*120D.0020.0002] -1F071 ; [*120E.0020.0002] -1F072 ; [*120F.0020.0002] -1F073 ; [*1210.0020.0002] -1F074 ; [*1211.0020.0002] -1F075 ; [*1212.0020.0002] -1F076 ; [*1213.0020.0002] -1F077 ; [*1214.0020.0002] -1F078 ; [*1215.0020.0002] -1F079 ; [*1216.0020.0002] -1F07A ; [*1217.0020.0002] -1F07B ; [*1218.0020.0002] -1F07C ; [*1219.0020.0002] -1F07D ; [*121A.0020.0002] -1F07E ; [*121B.0020.0002] -1F07F ; [*121C.0020.0002] -1F080 ; [*121D.0020.0002] -1F081 ; [*121E.0020.0002] -1F082 ; [*121F.0020.0002] -1F083 ; [*1220.0020.0002] -1F084 ; [*1221.0020.0002] -1F085 ; [*1222.0020.0002] -1F086 ; [*1223.0020.0002] -1F087 ; [*1224.0020.0002] -1F088 ; [*1225.0020.0002] -1F089 ; [*1226.0020.0002] -1F08A ; [*1227.0020.0002] -1F08B ; [*1228.0020.0002] -1F08C ; [*1229.0020.0002] -1F08D ; [*122A.0020.0002] -1F08E ; [*122B.0020.0002] -1F08F ; [*122C.0020.0002] -1F090 ; [*122D.0020.0002] -1F091 ; [*122E.0020.0002] -1F092 ; [*122F.0020.0002] -1F093 ; [*1230.0020.0002] -1F0A0 ; [*1231.0020.0002] -1F0A1 ; [*1232.0020.0002] -1F0A2 ; [*1233.0020.0002] -1F0A3 ; [*1234.0020.0002] -1F0A4 ; [*1235.0020.0002] -1F0A5 ; [*1236.0020.0002] -1F0A6 ; [*1237.0020.0002] -1F0A7 ; [*1238.0020.0002] -1F0A8 ; [*1239.0020.0002] -1F0A9 ; [*123A.0020.0002] -1F0AA ; [*123B.0020.0002] -1F0AB ; [*123C.0020.0002] -1F0AC ; [*123D.0020.0002] -1F0AD ; [*123E.0020.0002] -1F0AE ; [*123F.0020.0002] -1F0B1 ; [*1240.0020.0002] -1F0B2 ; [*1241.0020.0002] -1F0B3 ; [*1242.0020.0002] -1F0B4 ; [*1243.0020.0002] -1F0B5 ; [*1244.0020.0002] -1F0B6 ; [*1245.0020.0002] -1F0B7 ; [*1246.0020.0002] -1F0B8 ; [*1247.0020.0002] -1F0B9 ; [*1248.0020.0002] -1F0BA ; [*1249.0020.0002] -1F0BB ; [*124A.0020.0002] -1F0BC ; [*124B.0020.0002] -1F0BD ; [*124C.0020.0002] -1F0BE ; [*124D.0020.0002] -1F0BF ; [*124E.0020.0002] -1F0C1 ; [*124F.0020.0002] -1F0C2 ; [*1250.0020.0002] -1F0C3 ; [*1251.0020.0002] -1F0C4 ; [*1252.0020.0002] -1F0C5 ; [*1253.0020.0002] -1F0C6 ; [*1254.0020.0002] -1F0C7 ; [*1255.0020.0002] -1F0C8 ; [*1256.0020.0002] -1F0C9 ; [*1257.0020.0002] -1F0CA ; [*1258.0020.0002] -1F0CB ; [*1259.0020.0002] -1F0CC ; [*125A.0020.0002] -1F0CD ; [*125B.0020.0002] -1F0CE ; [*125C.0020.0002] -1F0CF ; [*125D.0020.0002] -1F0D1 ; [*125E.0020.0002] -1F0D2 ; [*125F.0020.0002] -1F0D3 ; [*1260.0020.0002] -1F0D4 ; [*1261.0020.0002] -1F0D5 ; [*1262.0020.0002] -1F0D6 ; [*1263.0020.0002] -1F0D7 ; [*1264.0020.0002] -1F0D8 ; [*1265.0020.0002] -1F0D9 ; [*1266.0020.0002] -1F0DA ; [*1267.0020.0002] -1F0DB ; [*1268.0020.0002] -1F0DC ; [*1269.0020.0002] -1F0DD ; [*126A.0020.0002] -1F0DE ; [*126B.0020.0002] -1F0DF ; [*126C.0020.0002] -1F0E0 ; [*126D.0020.0002] -1F0E1 ; [*126E.0020.0002] -1F0E2 ; [*126F.0020.0002] -1F0E3 ; [*1270.0020.0002] -1F0E4 ; [*1271.0020.0002] -1F0E5 ; [*1272.0020.0002] -1F0E6 ; [*1273.0020.0002] -1F0E7 ; [*1274.0020.0002] -1F0E8 ; [*1275.0020.0002] -1F0E9 ; [*1276.0020.0002] -1F0EA ; [*1277.0020.0002] -1F0EB ; [*1278.0020.0002] -1F0EC ; [*1279.0020.0002] -1F0ED ; [*127A.0020.0002] -1F0EE ; [*127B.0020.0002] -1F0EF ; [*127C.0020.0002] -1F0F0 ; [*127D.0020.0002] -1F0F1 ; [*127E.0020.0002] -1F0F2 ; [*127F.0020.0002] -1F0F3 ; [*1280.0020.0002] -1F0F4 ; [*1281.0020.0002] -1F0F5 ; [*1282.0020.0002] -1F1E6 ; [*09E3.0020.0002] -1F1E7 ; [*09E4.0020.0002] -1F1E8 ; [*09E5.0020.0002] -1F1E9 ; [*09E6.0020.0002] -1F1EA ; [*09E7.0020.0002] -1F1EB ; [*09E8.0020.0002] -1F1EC ; [*09E9.0020.0002] -1F1ED ; [*09EA.0020.0002] -1F1EE ; [*09EB.0020.0002] -1F1EF ; [*09EC.0020.0002] -1F1F0 ; [*09ED.0020.0002] -1F1F1 ; [*09EE.0020.0002] -1F1F2 ; [*09EF.0020.0002] -1F1F3 ; [*09F0.0020.0002] -1F1F4 ; [*09F1.0020.0002] -1F1F5 ; [*09F2.0020.0002] -1F1F6 ; [*09F3.0020.0002] -1F1F7 ; [*09F4.0020.0002] -1F1F8 ; [*09F5.0020.0002] -1F1F9 ; [*09F6.0020.0002] -1F1FA ; [*09F7.0020.0002] -1F1FB ; [*09F8.0020.0002] -1F1FC ; [*09F9.0020.0002] -1F1FD ; [*09FA.0020.0002] -1F1FE ; [*09FB.0020.0002] -1F1FF ; [*09FC.0020.0002] -1F300 ; [*1283.0020.0002] -1F301 ; [*1284.0020.0002] -1F302 ; [*1285.0020.0002] -1F303 ; [*1286.0020.0002] -1F304 ; [*1287.0020.0002] -1F305 ; [*1288.0020.0002] -1F306 ; [*1289.0020.0002] -1F307 ; [*128A.0020.0002] -1F308 ; [*128B.0020.0002] -1F309 ; [*128C.0020.0002] -1F30A ; [*128D.0020.0002] -1F30B ; [*128E.0020.0002] -1F30C ; [*128F.0020.0002] -1F30D ; [*1290.0020.0002] -1F30E ; [*1291.0020.0002] -1F30F ; [*1292.0020.0002] -1F310 ; [*1293.0020.0002] -1F311 ; [*1294.0020.0002] -1F312 ; [*1295.0020.0002] -1F313 ; [*1296.0020.0002] -1F314 ; [*1297.0020.0002] -1F315 ; [*1298.0020.0002] -1F316 ; [*1299.0020.0002] -1F317 ; [*129A.0020.0002] -1F318 ; [*129B.0020.0002] -1F319 ; [*129C.0020.0002] -1F31A ; [*129D.0020.0002] -1F31B ; [*129E.0020.0002] -1F31C ; [*129F.0020.0002] -1F31D ; [*12A0.0020.0002] -1F31E ; [*12A1.0020.0002] -1F31F ; [*12A2.0020.0002] -1F320 ; [*12A3.0020.0002] -1F321 ; [*12A4.0020.0002] -1F322 ; [*12A5.0020.0002] -1F323 ; [*12A6.0020.0002] -1F324 ; [*12A7.0020.0002] -1F325 ; [*12A8.0020.0002] -1F326 ; [*12A9.0020.0002] -1F327 ; [*12AA.0020.0002] -1F328 ; [*12AB.0020.0002] -1F329 ; [*12AC.0020.0002] -1F32A ; [*12AD.0020.0002] -1F32B ; [*12AE.0020.0002] -1F32C ; [*12AF.0020.0002] -1F32D ; [*12B0.0020.0002] -1F32E ; [*12B1.0020.0002] -1F32F ; [*12B2.0020.0002] -1F330 ; [*12B3.0020.0002] -1F331 ; [*12B4.0020.0002] -1F332 ; [*12B5.0020.0002] -1F333 ; [*12B6.0020.0002] -1F334 ; [*12B7.0020.0002] -1F335 ; [*12B8.0020.0002] -1F336 ; [*12B9.0020.0002] -1F337 ; [*12BA.0020.0002] -1F338 ; [*12BB.0020.0002] -1F339 ; [*12BC.0020.0002] -1F33A ; [*12BD.0020.0002] -1F33B ; [*12BE.0020.0002] -1F33C ; [*12BF.0020.0002] -1F33D ; [*12C0.0020.0002] -1F33E ; [*12C1.0020.0002] -1F33F ; [*12C2.0020.0002] -1F340 ; [*12C3.0020.0002] -1F341 ; [*12C4.0020.0002] -1F342 ; [*12C5.0020.0002] -1F343 ; [*12C6.0020.0002] -1F344 ; [*12C7.0020.0002] -1F345 ; [*12C8.0020.0002] -1F346 ; [*12C9.0020.0002] -1F347 ; [*12CA.0020.0002] -1F348 ; [*12CB.0020.0002] -1F349 ; [*12CC.0020.0002] -1F34A ; [*12CD.0020.0002] -1F34B ; [*12CE.0020.0002] -1F34C ; [*12CF.0020.0002] -1F34D ; [*12D0.0020.0002] -1F34E ; [*12D1.0020.0002] -1F34F ; [*12D2.0020.0002] -1F350 ; [*12D3.0020.0002] -1F351 ; [*12D4.0020.0002] -1F352 ; [*12D5.0020.0002] -1F353 ; [*12D6.0020.0002] -1F354 ; [*12D7.0020.0002] -1F355 ; [*12D8.0020.0002] -1F356 ; [*12D9.0020.0002] -1F357 ; [*12DA.0020.0002] -1F358 ; [*12DB.0020.0002] -1F359 ; [*12DC.0020.0002] -1F35A ; [*12DD.0020.0002] -1F35B ; [*12DE.0020.0002] -1F35C ; [*12DF.0020.0002] -1F35D ; [*12E0.0020.0002] -1F35E ; [*12E1.0020.0002] -1F35F ; [*12E2.0020.0002] -1F360 ; [*12E3.0020.0002] -1F361 ; [*12E4.0020.0002] -1F362 ; [*12E5.0020.0002] -1F363 ; [*12E6.0020.0002] -1F364 ; [*12E7.0020.0002] -1F365 ; [*12E8.0020.0002] -1F366 ; [*12E9.0020.0002] -1F367 ; [*12EA.0020.0002] -1F368 ; [*12EB.0020.0002] -1F369 ; [*12EC.0020.0002] -1F36A ; [*12ED.0020.0002] -1F36B ; [*12EE.0020.0002] -1F36C ; [*12EF.0020.0002] -1F36D ; [*12F0.0020.0002] -1F36E ; [*12F1.0020.0002] -1F36F ; [*12F2.0020.0002] -1F370 ; [*12F3.0020.0002] -1F371 ; [*12F4.0020.0002] -1F372 ; [*12F5.0020.0002] -1F373 ; [*12F6.0020.0002] -1F374 ; [*12F7.0020.0002] -1F375 ; [*12F8.0020.0002] -1F376 ; [*12F9.0020.0002] -1F377 ; [*12FA.0020.0002] -1F378 ; [*12FB.0020.0002] -1F379 ; [*12FC.0020.0002] -1F37A ; [*12FD.0020.0002] -1F37B ; [*12FE.0020.0002] -1F37C ; [*12FF.0020.0002] -1F37D ; [*1300.0020.0002] -1F37E ; [*1301.0020.0002] -1F37F ; [*1302.0020.0002] -1F380 ; [*1303.0020.0002] -1F381 ; [*1304.0020.0002] -1F382 ; [*1305.0020.0002] -1F383 ; [*1306.0020.0002] -1F384 ; [*1307.0020.0002] -1F385 ; [*1308.0020.0002] -1F386 ; [*1309.0020.0002] -1F387 ; [*130A.0020.0002] -1F388 ; [*130B.0020.0002] -1F389 ; [*130C.0020.0002] -1F38A ; [*130D.0020.0002] -1F38B ; [*130E.0020.0002] -1F38C ; [*130F.0020.0002] -1F38D ; [*1310.0020.0002] -1F38E ; [*1311.0020.0002] -1F38F ; [*1312.0020.0002] -1F390 ; [*1313.0020.0002] -1F391 ; [*1314.0020.0002] -1F392 ; [*1315.0020.0002] -1F393 ; [*1316.0020.0002] -1F394 ; [*1317.0020.0002] -1F395 ; [*1318.0020.0002] -1F396 ; [*1319.0020.0002] -1F397 ; [*131A.0020.0002] -1F398 ; [*131B.0020.0002] -1F399 ; [*131C.0020.0002] -1F39A ; [*131D.0020.0002] -1F39B ; [*131E.0020.0002] -1F39C ; [*131F.0020.0002] -1F39D ; [*1320.0020.0002] -1F39E ; [*1321.0020.0002] -1F39F ; [*1322.0020.0002] -1F3A0 ; [*1323.0020.0002] -1F3A1 ; [*1324.0020.0002] -1F3A2 ; [*1325.0020.0002] -1F3A3 ; [*1326.0020.0002] -1F3A4 ; [*1327.0020.0002] -1F3A5 ; [*1328.0020.0002] -1F3A6 ; [*1329.0020.0002] -1F3A7 ; [*132A.0020.0002] -1F3A8 ; [*132B.0020.0002] -1F3A9 ; [*132C.0020.0002] -1F3AA ; [*132D.0020.0002] -1F3AB ; [*132E.0020.0002] -1F3AC ; [*132F.0020.0002] -1F3AD ; [*1330.0020.0002] -1F3AE ; [*1331.0020.0002] -1F3AF ; [*1332.0020.0002] -1F3B0 ; [*1333.0020.0002] -1F3B1 ; [*1334.0020.0002] -1F3B2 ; [*1335.0020.0002] -1F3B3 ; [*1336.0020.0002] -1F3B4 ; [*1337.0020.0002] -1F3B5 ; [*1338.0020.0002] -1F3B6 ; [*1339.0020.0002] -1F3B7 ; [*133A.0020.0002] -1F3B8 ; [*133B.0020.0002] -1F3B9 ; [*133C.0020.0002] -1F3BA ; [*133D.0020.0002] -1F3BB ; [*133E.0020.0002] -1F3BC ; [*133F.0020.0002] -1F3BD ; [*1340.0020.0002] -1F3BE ; [*1341.0020.0002] -1F3BF ; [*1342.0020.0002] -1F3C0 ; [*1343.0020.0002] -1F3C1 ; [*1344.0020.0002] -1F3C2 ; [*1345.0020.0002] -1F3C3 ; [*1346.0020.0002] -1F3C4 ; [*1347.0020.0002] -1F3C5 ; [*1348.0020.0002] -1F3C6 ; [*1349.0020.0002] -1F3C7 ; [*134A.0020.0002] -1F3C8 ; [*134B.0020.0002] -1F3C9 ; [*134C.0020.0002] -1F3CA ; [*134D.0020.0002] -1F3CB ; [*134E.0020.0002] -1F3CC ; [*134F.0020.0002] -1F3CD ; [*1350.0020.0002] -1F3CE ; [*1351.0020.0002] -1F3CF ; [*1352.0020.0002] -1F3D0 ; [*1353.0020.0002] -1F3D1 ; [*1354.0020.0002] -1F3D2 ; [*1355.0020.0002] -1F3D3 ; [*1356.0020.0002] -1F3D4 ; [*1357.0020.0002] -1F3D5 ; [*1358.0020.0002] -1F3D6 ; [*1359.0020.0002] -1F3D7 ; [*135A.0020.0002] -1F3D8 ; [*135B.0020.0002] -1F3D9 ; [*135C.0020.0002] -1F3DA ; [*135D.0020.0002] -1F3DB ; [*135E.0020.0002] -1F3DC ; [*135F.0020.0002] -1F3DD ; [*1360.0020.0002] -1F3DE ; [*1361.0020.0002] -1F3DF ; [*1362.0020.0002] -1F3E0 ; [*1363.0020.0002] -1F3E1 ; [*1364.0020.0002] -1F3E2 ; [*1365.0020.0002] -1F3E3 ; [*1366.0020.0002] -1F3E4 ; [*1367.0020.0002] -1F3E5 ; [*1368.0020.0002] -1F3E6 ; [*1369.0020.0002] -1F3E7 ; [*136A.0020.0002] -1F3E8 ; [*136B.0020.0002] -1F3E9 ; [*136C.0020.0002] -1F3EA ; [*136D.0020.0002] -1F3EB ; [*136E.0020.0002] -1F3EC ; [*136F.0020.0002] -1F3ED ; [*1370.0020.0002] -1F3EE ; [*1371.0020.0002] -1F3EF ; [*1372.0020.0002] -1F3F0 ; [*1373.0020.0002] -1F3F1 ; [*1374.0020.0002] -1F3F2 ; [*1375.0020.0002] -1F3F3 ; [*1376.0020.0002] -1F3F4 ; [*1377.0020.0002] -1F3F5 ; [*1378.0020.0002] -1F3F6 ; [*1379.0020.0002] -1F3F7 ; [*137A.0020.0002] -1F3F8 ; [*137B.0020.0002] -1F3F9 ; [*137C.0020.0002] -1F3FA ; [*137D.0020.0002] -1F3FB ; [*137E.0020.0002] -1F3FC ; [*137F.0020.0002] -1F3FD ; [*1380.0020.0002] -1F3FE ; [*1381.0020.0002] -1F3FF ; [*1382.0020.0002] -1F400 ; [*1383.0020.0002] -1F401 ; [*1384.0020.0002] -1F402 ; [*1385.0020.0002] -1F403 ; [*1386.0020.0002] -1F404 ; [*1387.0020.0002] -1F405 ; [*1388.0020.0002] -1F406 ; [*1389.0020.0002] -1F407 ; [*138A.0020.0002] -1F408 ; [*138B.0020.0002] -1F409 ; [*138C.0020.0002] -1F40A ; [*138D.0020.0002] -1F40B ; [*138E.0020.0002] -1F40C ; [*138F.0020.0002] -1F40D ; [*1390.0020.0002] -1F40E ; [*1391.0020.0002] -1F40F ; [*1392.0020.0002] -1F410 ; [*1393.0020.0002] -1F411 ; [*1394.0020.0002] -1F412 ; [*1395.0020.0002] -1F413 ; [*1396.0020.0002] -1F414 ; [*1397.0020.0002] -1F415 ; [*1398.0020.0002] -1F416 ; [*1399.0020.0002] -1F417 ; [*139A.0020.0002] -1F418 ; [*139B.0020.0002] -1F419 ; [*139C.0020.0002] -1F41A ; [*139D.0020.0002] -1F41B ; [*139E.0020.0002] -1F41C ; [*139F.0020.0002] -1F41D ; [*13A0.0020.0002] -1F41E ; [*13A1.0020.0002] -1F41F ; [*13A2.0020.0002] -1F420 ; [*13A3.0020.0002] -1F421 ; [*13A4.0020.0002] -1F422 ; [*13A5.0020.0002] -1F423 ; [*13A6.0020.0002] -1F424 ; [*13A7.0020.0002] -1F425 ; [*13A8.0020.0002] -1F426 ; [*13A9.0020.0002] -1F427 ; [*13AA.0020.0002] -1F428 ; [*13AB.0020.0002] -1F429 ; [*13AC.0020.0002] -1F42A ; [*13AD.0020.0002] -1F42B ; [*13AE.0020.0002] -1F42C ; [*13AF.0020.0002] -1F42D ; [*13B0.0020.0002] -1F42E ; [*13B1.0020.0002] -1F42F ; [*13B2.0020.0002] -1F430 ; [*13B3.0020.0002] -1F431 ; [*13B4.0020.0002] -1F432 ; [*13B5.0020.0002] -1F433 ; [*13B6.0020.0002] -1F434 ; [*13B7.0020.0002] -1F435 ; [*13B8.0020.0002] -1F436 ; [*13B9.0020.0002] -1F437 ; [*13BA.0020.0002] -1F438 ; [*13BB.0020.0002] -1F439 ; [*13BC.0020.0002] -1F43A ; [*13BD.0020.0002] -1F43B ; [*13BE.0020.0002] -1F43C ; [*13BF.0020.0002] -1F43D ; [*13C0.0020.0002] -1F43E ; [*13C1.0020.0002] -1F43F ; [*13C2.0020.0002] -1F440 ; [*13C3.0020.0002] -1F441 ; [*13C4.0020.0002] -1F442 ; [*13C5.0020.0002] -1F443 ; [*13C6.0020.0002] -1F444 ; [*13C7.0020.0002] -1F445 ; [*13C8.0020.0002] -1F446 ; [*13C9.0020.0002] -1F447 ; [*13CA.0020.0002] -1F448 ; [*13CB.0020.0002] -1F449 ; [*13CC.0020.0002] -1F44A ; [*13CD.0020.0002] -1F44B ; [*13CE.0020.0002] -1F44C ; [*13CF.0020.0002] -1F44D ; [*13D0.0020.0002] -1F44E ; [*13D1.0020.0002] -1F44F ; [*13D2.0020.0002] -1F450 ; [*13D3.0020.0002] -1F451 ; [*13D4.0020.0002] -1F452 ; [*13D5.0020.0002] -1F453 ; [*13D6.0020.0002] -1F454 ; [*13D7.0020.0002] -1F455 ; [*13D8.0020.0002] -1F456 ; [*13D9.0020.0002] -1F457 ; [*13DA.0020.0002] -1F458 ; [*13DB.0020.0002] -1F459 ; [*13DC.0020.0002] -1F45A ; [*13DD.0020.0002] -1F45B ; [*13DE.0020.0002] -1F45C ; [*13DF.0020.0002] -1F45D ; [*13E0.0020.0002] -1F45E ; [*13E1.0020.0002] -1F45F ; [*13E2.0020.0002] -1F460 ; [*13E3.0020.0002] -1F461 ; [*13E4.0020.0002] -1F462 ; [*13E5.0020.0002] -1F463 ; [*13E6.0020.0002] -1F464 ; [*13E7.0020.0002] -1F465 ; [*13E8.0020.0002] -1F466 ; [*13E9.0020.0002] -1F467 ; [*13EA.0020.0002] -1F468 ; [*13EB.0020.0002] -1F469 ; [*13EC.0020.0002] -1F46A ; [*13ED.0020.0002] -1F46B ; [*13EE.0020.0002] -1F46C ; [*13EF.0020.0002] -1F46D ; [*13F0.0020.0002] -1F46E ; [*13F1.0020.0002] -1F46F ; [*13F2.0020.0002] -1F470 ; [*13F3.0020.0002] -1F471 ; [*13F4.0020.0002] -1F472 ; [*13F5.0020.0002] -1F473 ; [*13F6.0020.0002] -1F474 ; [*13F7.0020.0002] -1F475 ; [*13F8.0020.0002] -1F476 ; [*13F9.0020.0002] -1F477 ; [*13FA.0020.0002] -1F478 ; [*13FB.0020.0002] -1F479 ; [*13FC.0020.0002] -1F47A ; [*13FD.0020.0002] -1F47B ; [*13FE.0020.0002] -1F47C ; [*13FF.0020.0002] -1F47D ; [*1400.0020.0002] -1F47E ; [*1401.0020.0002] -1F47F ; [*1402.0020.0002] -1F480 ; [*1403.0020.0002] -1F481 ; [*1404.0020.0002] -1F482 ; [*1405.0020.0002] -1F483 ; [*1406.0020.0002] -1F484 ; [*1407.0020.0002] -1F485 ; [*1408.0020.0002] -1F486 ; [*1409.0020.0002] -1F487 ; [*140A.0020.0002] -1F488 ; [*140B.0020.0002] -1F489 ; [*140C.0020.0002] -1F48A ; [*140D.0020.0002] -1F48B ; [*140E.0020.0002] -1F48C ; [*140F.0020.0002] -1F48D ; [*1410.0020.0002] -1F48E ; [*1411.0020.0002] -1F48F ; [*1412.0020.0002] -1F490 ; [*1413.0020.0002] -1F491 ; [*1414.0020.0002] -1F492 ; [*1415.0020.0002] -1F493 ; [*1416.0020.0002] -1F494 ; [*1417.0020.0002] -1F495 ; [*1418.0020.0002] -1F496 ; [*1419.0020.0002] -1F497 ; [*141A.0020.0002] -1F498 ; [*141B.0020.0002] -1F499 ; [*141C.0020.0002] -1F49A ; [*141D.0020.0002] -1F49B ; [*141E.0020.0002] -1F49C ; [*141F.0020.0002] -1F49D ; [*1420.0020.0002] -1F49E ; [*1421.0020.0002] -1F49F ; [*1422.0020.0002] -1F4A0 ; [*1423.0020.0002] -1F4A1 ; [*1424.0020.0002] -1F4A2 ; [*1425.0020.0002] -1F4A3 ; [*1426.0020.0002] -1F4A4 ; [*1427.0020.0002] -1F4A5 ; [*1428.0020.0002] -1F4A6 ; [*1429.0020.0002] -1F4A7 ; [*142A.0020.0002] -1F4A8 ; [*142B.0020.0002] -1F4A9 ; [*142C.0020.0002] -1F4AA ; [*142D.0020.0002] -1F4AB ; [*142E.0020.0002] -1F4AC ; [*142F.0020.0002] -1F4AD ; [*1430.0020.0002] -1F4AE ; [*1431.0020.0002] -1F4AF ; [*1432.0020.0002] -1F4B0 ; [*1433.0020.0002] -1F4B1 ; [*1434.0020.0002] -1F4B2 ; [*1435.0020.0002] -1F4B3 ; [*1436.0020.0002] -1F4B4 ; [*1437.0020.0002] -1F4B5 ; [*1438.0020.0002] -1F4B6 ; [*1439.0020.0002] -1F4B7 ; [*143A.0020.0002] -1F4B8 ; [*143B.0020.0002] -1F4B9 ; [*143C.0020.0002] -1F4BA ; [*143D.0020.0002] -1F4BB ; [*143E.0020.0002] -1F4BC ; [*143F.0020.0002] -1F4BD ; [*1440.0020.0002] -1F4BE ; [*1441.0020.0002] -1F4BF ; [*1442.0020.0002] -1F4C0 ; [*1443.0020.0002] -1F4C1 ; [*1444.0020.0002] -1F4C2 ; [*1445.0020.0002] -1F4C3 ; [*1446.0020.0002] -1F4C4 ; [*1447.0020.0002] -1F4C5 ; [*1448.0020.0002] -1F4C6 ; [*1449.0020.0002] -1F4C7 ; [*144A.0020.0002] -1F4C8 ; [*144B.0020.0002] -1F4C9 ; [*144C.0020.0002] -1F4CA ; [*144D.0020.0002] -1F4CB ; [*144E.0020.0002] -1F4CC ; [*144F.0020.0002] -1F4CD ; [*1450.0020.0002] -1F4CE ; [*1451.0020.0002] -1F4CF ; [*1452.0020.0002] -1F4D0 ; [*1453.0020.0002] -1F4D1 ; [*1454.0020.0002] -1F4D2 ; [*1455.0020.0002] -1F4D3 ; [*1456.0020.0002] -1F4D4 ; [*1457.0020.0002] -1F4D5 ; [*1458.0020.0002] -1F4D6 ; [*1459.0020.0002] -1F4D7 ; [*145A.0020.0002] -1F4D8 ; [*145B.0020.0002] -1F4D9 ; [*145C.0020.0002] -1F4DA ; [*145D.0020.0002] -1F4DB ; [*145E.0020.0002] -1F4DC ; [*145F.0020.0002] -1F4DD ; [*1460.0020.0002] -1F4DE ; [*1461.0020.0002] -1F4DF ; [*1462.0020.0002] -1F4E0 ; [*1463.0020.0002] -1F4E1 ; [*1464.0020.0002] -1F4E2 ; [*1465.0020.0002] -1F4E3 ; [*1466.0020.0002] -1F4E4 ; [*1467.0020.0002] -1F4E5 ; [*1468.0020.0002] -1F4E6 ; [*1469.0020.0002] -1F4E7 ; [*146A.0020.0002] -1F4E8 ; [*146B.0020.0002] -1F4E9 ; [*146C.0020.0002] -1F4EA ; [*146D.0020.0002] -1F4EB ; [*146E.0020.0002] -1F4EC ; [*146F.0020.0002] -1F4ED ; [*1470.0020.0002] -1F4EE ; [*1471.0020.0002] -1F4EF ; [*1472.0020.0002] -1F4F0 ; [*1473.0020.0002] -1F4F1 ; [*1474.0020.0002] -1F4F2 ; [*1475.0020.0002] -1F4F3 ; [*1476.0020.0002] -1F4F4 ; [*1477.0020.0002] -1F4F5 ; [*1478.0020.0002] -1F4F6 ; [*1479.0020.0002] -1F4F7 ; [*147A.0020.0002] -1F4F8 ; [*147B.0020.0002] -1F4F9 ; [*147C.0020.0002] -1F4FA ; [*147D.0020.0002] -1F4FB ; [*147E.0020.0002] -1F4FC ; [*147F.0020.0002] -1F4FD ; [*1480.0020.0002] -1F4FE ; [*1481.0020.0002] -1F4FF ; [*1482.0020.0002] -1F500 ; [*1483.0020.0002] -1F501 ; [*1484.0020.0002] -1F502 ; [*1485.0020.0002] -1F503 ; [*1486.0020.0002] -1F504 ; [*1487.0020.0002] -1F505 ; [*1488.0020.0002] -1F506 ; [*1489.0020.0002] -1F507 ; [*148A.0020.0002] -1F508 ; [*148B.0020.0002] -1F509 ; [*148C.0020.0002] -1F50A ; [*148D.0020.0002] -1F50B ; [*148E.0020.0002] -1F50C ; [*148F.0020.0002] -1F50D ; [*1490.0020.0002] -1F50E ; [*1491.0020.0002] -1F50F ; [*1492.0020.0002] -1F510 ; [*1493.0020.0002] -1F511 ; [*1494.0020.0002] -1F512 ; [*1495.0020.0002] -1F513 ; [*1496.0020.0002] -1F514 ; [*1497.0020.0002] -1F515 ; [*1498.0020.0002] -1F516 ; [*1499.0020.0002] -1F517 ; [*149A.0020.0002] -1F518 ; [*149B.0020.0002] -1F519 ; [*149C.0020.0002] -1F51A ; [*149D.0020.0002] -1F51B ; [*149E.0020.0002] -1F51C ; [*149F.0020.0002] -1F51D ; [*14A0.0020.0002] -1F51E ; [*14A1.0020.0002] -1F51F ; [*14A2.0020.0002] -1F520 ; [*14A3.0020.0002] -1F521 ; [*14A4.0020.0002] -1F522 ; [*14A5.0020.0002] -1F523 ; [*14A6.0020.0002] -1F524 ; [*14A7.0020.0002] -1F525 ; [*14A8.0020.0002] -1F526 ; [*14A9.0020.0002] -1F527 ; [*14AA.0020.0002] -1F528 ; [*14AB.0020.0002] -1F529 ; [*14AC.0020.0002] -1F52A ; [*14AD.0020.0002] -1F52B ; [*14AE.0020.0002] -1F52C ; [*14AF.0020.0002] -1F52D ; [*14B0.0020.0002] -1F52E ; [*14B1.0020.0002] -1F52F ; [*14B2.0020.0002] -1F530 ; [*14B3.0020.0002] -1F531 ; [*14B4.0020.0002] -1F532 ; [*14B5.0020.0002] -1F533 ; [*14B6.0020.0002] -1F534 ; [*14B7.0020.0002] -1F535 ; [*14B8.0020.0002] -1F536 ; [*14B9.0020.0002] -1F537 ; [*14BA.0020.0002] -1F538 ; [*14BB.0020.0002] -1F539 ; [*14BC.0020.0002] -1F53A ; [*14BD.0020.0002] -1F53B ; [*14BE.0020.0002] -1F53C ; [*14BF.0020.0002] -1F53D ; [*14C0.0020.0002] -1F53E ; [*14C1.0020.0002] -1F53F ; [*14C2.0020.0002] -1F540 ; [*14C3.0020.0002] -1F541 ; [*14C4.0020.0002] -1F542 ; [*14C5.0020.0002] -1F543 ; [*14C6.0020.0002] -1F544 ; [*14C7.0020.0002] -1F545 ; [*14C8.0020.0002] -1F546 ; [*14C9.0020.0002] -1F547 ; [*14CA.0020.0002] -1F548 ; [*14CB.0020.0002] -1F549 ; [*14CC.0020.0002] -1F54A ; [*14CD.0020.0002] -1F54B ; [*14CE.0020.0002] -1F54C ; [*14CF.0020.0002] -1F54D ; [*14D0.0020.0002] -1F54E ; [*14D1.0020.0002] -1F54F ; [*14D2.0020.0002] -1F550 ; [*14D3.0020.0002] -1F551 ; [*14D4.0020.0002] -1F552 ; [*14D5.0020.0002] -1F553 ; [*14D6.0020.0002] -1F554 ; [*14D7.0020.0002] -1F555 ; [*14D8.0020.0002] -1F556 ; [*14D9.0020.0002] -1F557 ; [*14DA.0020.0002] -1F558 ; [*14DB.0020.0002] -1F559 ; [*14DC.0020.0002] -1F55A ; [*14DD.0020.0002] -1F55B ; [*14DE.0020.0002] -1F55C ; [*14DF.0020.0002] -1F55D ; [*14E0.0020.0002] -1F55E ; [*14E1.0020.0002] -1F55F ; [*14E2.0020.0002] -1F560 ; [*14E3.0020.0002] -1F561 ; [*14E4.0020.0002] -1F562 ; [*14E5.0020.0002] -1F563 ; [*14E6.0020.0002] -1F564 ; [*14E7.0020.0002] -1F565 ; [*14E8.0020.0002] -1F566 ; [*14E9.0020.0002] -1F567 ; [*14EA.0020.0002] -1F568 ; [*14EB.0020.0002] -1F569 ; [*14EC.0020.0002] -1F56A ; [*14ED.0020.0002] -1F56B ; [*14EE.0020.0002] -1F56C ; [*14EF.0020.0002] -1F56D ; [*14F0.0020.0002] -1F56E ; [*14F1.0020.0002] -1F56F ; [*14F2.0020.0002] -1F570 ; [*14F3.0020.0002] -1F571 ; [*14F4.0020.0002] -1F572 ; [*14F5.0020.0002] -1F573 ; [*14F6.0020.0002] -1F574 ; [*14F7.0020.0002] -1F575 ; [*14F8.0020.0002] -1F576 ; [*14F9.0020.0002] -1F577 ; [*14FA.0020.0002] -1F578 ; [*14FB.0020.0002] -1F579 ; [*14FC.0020.0002] -1F57B ; [*14FD.0020.0002] -1F57C ; [*14FE.0020.0002] -1F57D ; [*14FF.0020.0002] -1F57E ; [*1500.0020.0002] -1F57F ; [*1501.0020.0002] -1F580 ; [*1502.0020.0002] -1F581 ; [*1503.0020.0002] -1F582 ; [*1504.0020.0002] -1F583 ; [*1505.0020.0002] -1F584 ; [*1506.0020.0002] -1F585 ; [*1507.0020.0002] -1F586 ; [*1508.0020.0002] -1F587 ; [*1509.0020.0002] -1F588 ; [*150A.0020.0002] -1F589 ; [*150B.0020.0002] -1F58A ; [*150C.0020.0002] -1F58B ; [*150D.0020.0002] -1F58C ; [*150E.0020.0002] -1F58D ; [*150F.0020.0002] -1F58E ; [*1510.0020.0002] -1F58F ; [*1511.0020.0002] -1F590 ; [*1512.0020.0002] -1F591 ; [*1513.0020.0002] -1F592 ; [*1514.0020.0002] -1F593 ; [*1515.0020.0002] -1F594 ; [*1516.0020.0002] -1F595 ; [*1517.0020.0002] -1F596 ; [*1518.0020.0002] -1F597 ; [*1519.0020.0002] -1F598 ; [*151A.0020.0002] -1F599 ; [*151B.0020.0002] -1F59A ; [*151C.0020.0002] -1F59B ; [*151D.0020.0002] -1F59C ; [*151E.0020.0002] -1F59D ; [*151F.0020.0002] -1F59E ; [*1520.0020.0002] -1F59F ; [*1521.0020.0002] -1F5A0 ; [*1522.0020.0002] -1F5A1 ; [*1523.0020.0002] -1F5A2 ; [*1524.0020.0002] -1F5A3 ; [*1525.0020.0002] -1F5A5 ; [*1526.0020.0002] -1F5A6 ; [*1527.0020.0002] -1F5A7 ; [*1528.0020.0002] -1F5A8 ; [*1529.0020.0002] -1F5A9 ; [*152A.0020.0002] -1F5AA ; [*152B.0020.0002] -1F5AB ; [*152C.0020.0002] -1F5AC ; [*152D.0020.0002] -1F5AD ; [*152E.0020.0002] -1F5AE ; [*152F.0020.0002] -1F5AF ; [*1530.0020.0002] -1F5B0 ; [*1531.0020.0002] -1F5B1 ; [*1532.0020.0002] -1F5B2 ; [*1533.0020.0002] -1F5B3 ; [*1534.0020.0002] -1F5B4 ; [*1535.0020.0002] -1F5B5 ; [*1536.0020.0002] -1F5B6 ; [*1537.0020.0002] -1F5B7 ; [*1538.0020.0002] -1F5B8 ; [*1539.0020.0002] -1F5B9 ; [*153A.0020.0002] -1F5BA ; [*153B.0020.0002] -1F5BB ; [*153C.0020.0002] -1F5BC ; [*153D.0020.0002] -1F5BD ; [*153E.0020.0002] -1F5BE ; [*153F.0020.0002] -1F5BF ; [*1540.0020.0002] -1F5C0 ; [*1541.0020.0002] -1F5C1 ; [*1542.0020.0002] -1F5C2 ; [*1543.0020.0002] -1F5C3 ; [*1544.0020.0002] -1F5C4 ; [*1545.0020.0002] -1F5C5 ; [*1546.0020.0002] -1F5C6 ; [*1547.0020.0002] -1F5C7 ; [*1548.0020.0002] -1F5C8 ; [*1549.0020.0002] -1F5C9 ; [*154A.0020.0002] -1F5CA ; [*154B.0020.0002] -1F5CB ; [*154C.0020.0002] -1F5CC ; [*154D.0020.0002] -1F5CD ; [*154E.0020.0002] -1F5CE ; [*154F.0020.0002] -1F5CF ; [*1550.0020.0002] -1F5D0 ; [*1551.0020.0002] -1F5D1 ; [*1552.0020.0002] -1F5D2 ; [*1553.0020.0002] -1F5D3 ; [*1554.0020.0002] -1F5D4 ; [*1555.0020.0002] -1F5D5 ; [*1556.0020.0002] -1F5D6 ; [*1557.0020.0002] -1F5D7 ; [*1558.0020.0002] -1F5D8 ; [*1559.0020.0002] -1F5D9 ; [*155A.0020.0002] -1F5DA ; [*155B.0020.0002] -1F5DB ; [*155C.0020.0002] -1F5DC ; [*155D.0020.0002] -1F5DD ; [*155E.0020.0002] -1F5DE ; [*155F.0020.0002] -1F5DF ; [*1560.0020.0002] -1F5E0 ; [*1561.0020.0002] -1F5E1 ; [*1562.0020.0002] -1F5E2 ; [*1563.0020.0002] -1F5E3 ; [*1564.0020.0002] -1F5E4 ; [*1565.0020.0002] -1F5E5 ; [*1566.0020.0002] -1F5E6 ; [*1567.0020.0002] -1F5E7 ; [*1568.0020.0002] -1F5E8 ; [*1569.0020.0002] -1F5E9 ; [*156A.0020.0002] -1F5EA ; [*156B.0020.0002] -1F5EB ; [*156C.0020.0002] -1F5EC ; [*156D.0020.0002] -1F5ED ; [*156E.0020.0002] -1F5EE ; [*156F.0020.0002] -1F5EF ; [*1570.0020.0002] -1F5F0 ; [*1571.0020.0002] -1F5F1 ; [*1572.0020.0002] -1F5F2 ; [*1573.0020.0002] -1F5F3 ; [*1574.0020.0002] -1F5F4 ; [*1575.0020.0002] -1F5F5 ; [*1576.0020.0002] -1F5F6 ; [*1577.0020.0002] -1F5F7 ; [*1578.0020.0002] -1F5F8 ; [*1579.0020.0002] -1F5F9 ; [*157A.0020.0002] -1F5FA ; [*157B.0020.0002] -1F5FB ; [*157C.0020.0002] -1F5FC ; [*157D.0020.0002] -1F5FD ; [*157E.0020.0002] -1F5FE ; [*157F.0020.0002] -1F5FF ; [*1580.0020.0002] -1F600 ; [*1590.0020.0002] -1F601 ; [*1591.0020.0002] -1F602 ; [*1592.0020.0002] -1F603 ; [*1593.0020.0002] -1F604 ; [*1594.0020.0002] -1F605 ; [*1595.0020.0002] -1F606 ; [*1596.0020.0002] -1F607 ; [*1597.0020.0002] -1F608 ; [*1598.0020.0002] -1F609 ; [*1599.0020.0002] -1F60A ; [*159A.0020.0002] -1F60B ; [*159B.0020.0002] -1F60C ; [*159C.0020.0002] -1F60D ; [*159D.0020.0002] -1F60E ; [*159E.0020.0002] -1F60F ; [*159F.0020.0002] -1F610 ; [*15A0.0020.0002] -1F611 ; [*15A1.0020.0002] -1F612 ; [*15A2.0020.0002] -1F613 ; [*15A3.0020.0002] -1F614 ; [*15A4.0020.0002] -1F615 ; [*15A5.0020.0002] -1F616 ; [*15A6.0020.0002] -1F617 ; [*15A7.0020.0002] -1F618 ; [*15A8.0020.0002] -1F619 ; [*15A9.0020.0002] -1F61A ; [*15AA.0020.0002] -1F61B ; [*15AB.0020.0002] -1F61C ; [*15AC.0020.0002] -1F61D ; [*15AD.0020.0002] -1F61E ; [*15AE.0020.0002] -1F61F ; [*15AF.0020.0002] -1F620 ; [*15B0.0020.0002] -1F621 ; [*15B1.0020.0002] -1F622 ; [*15B2.0020.0002] -1F623 ; [*15B3.0020.0002] -1F624 ; [*15B4.0020.0002] -1F625 ; [*15B5.0020.0002] -1F626 ; [*15B6.0020.0002] -1F627 ; [*15B7.0020.0002] -1F628 ; [*15B8.0020.0002] -1F629 ; [*15B9.0020.0002] -1F62A ; [*15BA.0020.0002] -1F62B ; [*15BB.0020.0002] -1F62C ; [*15BC.0020.0002] -1F62D ; [*15BD.0020.0002] -1F62E ; [*15BE.0020.0002] -1F62F ; [*15BF.0020.0002] -1F630 ; [*15C0.0020.0002] -1F631 ; [*15C1.0020.0002] -1F632 ; [*15C2.0020.0002] -1F633 ; [*15C3.0020.0002] -1F634 ; [*15C4.0020.0002] -1F635 ; [*15C5.0020.0002] -1F636 ; [*15C6.0020.0002] -1F637 ; [*15C7.0020.0002] -1F638 ; [*15C8.0020.0002] -1F639 ; [*15C9.0020.0002] -1F63A ; [*15CA.0020.0002] -1F63B ; [*15CB.0020.0002] -1F63C ; [*15CC.0020.0002] -1F63D ; [*15CD.0020.0002] -1F63E ; [*15CE.0020.0002] -1F63F ; [*15CF.0020.0002] -1F640 ; [*15D0.0020.0002] -1F641 ; [*15D1.0020.0002] -1F642 ; [*15D2.0020.0002] -1F643 ; [*15D3.0020.0002] -1F644 ; [*15D4.0020.0002] -1F645 ; [*15D5.0020.0002] -1F646 ; [*15D6.0020.0002] -1F647 ; [*15D7.0020.0002] -1F648 ; [*15D8.0020.0002] -1F649 ; [*15D9.0020.0002] -1F64A ; [*15DA.0020.0002] -1F64B ; [*15DB.0020.0002] -1F64C ; [*15DC.0020.0002] -1F64D ; [*15DD.0020.0002] -1F64E ; [*15DE.0020.0002] -1F64F ; [*15DF.0020.0002] -1F650 ; [*15E0.0020.0002] -1F651 ; [*15E1.0020.0002] -1F652 ; [*15E2.0020.0002] -1F653 ; [*15E3.0020.0002] -1F654 ; [*15E4.0020.0002] -1F655 ; [*15E5.0020.0002] -1F656 ; [*15E6.0020.0002] -1F657 ; [*15E7.0020.0002] -1F658 ; [*15E8.0020.0002] -1F659 ; [*15E9.0020.0002] -1F65A ; [*15EA.0020.0002] -1F65B ; [*15EB.0020.0002] -1F65C ; [*15EC.0020.0002] -1F65D ; [*15ED.0020.0002] -1F65E ; [*15EE.0020.0002] -1F65F ; [*15EF.0020.0002] -1F660 ; [*15F0.0020.0002] -1F661 ; [*15F1.0020.0002] -1F662 ; [*15F2.0020.0002] -1F663 ; [*15F3.0020.0002] -1F664 ; [*15F4.0020.0002] -1F665 ; [*15F5.0020.0002] -1F666 ; [*15F6.0020.0002] -1F667 ; [*15F7.0020.0002] -1F668 ; [*15F8.0020.0002] -1F669 ; [*15F9.0020.0002] -1F66A ; [*15FA.0020.0002] -1F66B ; [*15FB.0020.0002] -1F66C ; [*15FC.0020.0002] -1F66D ; [*15FD.0020.0002] -1F66E ; [*15FE.0020.0002] -1F66F ; [*15FF.0020.0002] -1F670 ; [*1600.0020.0002] -1F671 ; [*1601.0020.0002] -1F672 ; [*1602.0020.0002] -1F673 ; [*1603.0020.0002] -1F674 ; [*1604.0020.0002] -1F675 ; [*1605.0020.0002] -1F676 ; [*1606.0020.0002] -1F677 ; [*1607.0020.0002] -1F678 ; [*1608.0020.0002] -1F679 ; [*1609.0020.0002] -1F67A ; [*160A.0020.0002] -1F67B ; [*160B.0020.0002] -1F67C ; [*160C.0020.0002] -1F67D ; [*160D.0020.0002] -1F67E ; [*160E.0020.0002] -1F67F ; [*160F.0020.0002] -1F680 ; [*1610.0020.0002] -1F681 ; [*1611.0020.0002] -1F682 ; [*1612.0020.0002] -1F683 ; [*1613.0020.0002] -1F684 ; [*1614.0020.0002] -1F685 ; [*1615.0020.0002] -1F686 ; [*1616.0020.0002] -1F687 ; [*1617.0020.0002] -1F688 ; [*1618.0020.0002] -1F689 ; [*1619.0020.0002] -1F68A ; [*161A.0020.0002] -1F68B ; [*161B.0020.0002] -1F68C ; [*161C.0020.0002] -1F68D ; [*161D.0020.0002] -1F68E ; [*161E.0020.0002] -1F68F ; [*161F.0020.0002] -1F690 ; [*1620.0020.0002] -1F691 ; [*1621.0020.0002] -1F692 ; [*1622.0020.0002] -1F693 ; [*1623.0020.0002] -1F694 ; [*1624.0020.0002] -1F695 ; [*1625.0020.0002] -1F696 ; [*1626.0020.0002] -1F697 ; [*1627.0020.0002] -1F698 ; [*1628.0020.0002] -1F699 ; [*1629.0020.0002] -1F69A ; [*162A.0020.0002] -1F69B ; [*162B.0020.0002] -1F69C ; [*162C.0020.0002] -1F69D ; [*162D.0020.0002] -1F69E ; [*162E.0020.0002] -1F69F ; [*162F.0020.0002] -1F6A0 ; [*1630.0020.0002] -1F6A1 ; [*1631.0020.0002] -1F6A2 ; [*1632.0020.0002] -1F6A3 ; [*1633.0020.0002] -1F6A4 ; [*1634.0020.0002] -1F6A5 ; [*1635.0020.0002] -1F6A6 ; [*1636.0020.0002] -1F6A7 ; [*1637.0020.0002] -1F6A8 ; [*1638.0020.0002] -1F6A9 ; [*1639.0020.0002] -1F6AA ; [*163A.0020.0002] -1F6AB ; [*163B.0020.0002] -1F6AC ; [*163C.0020.0002] -1F6AD ; [*163D.0020.0002] -1F6AE ; [*163E.0020.0002] -1F6AF ; [*163F.0020.0002] -1F6B0 ; [*1640.0020.0002] -1F6B1 ; [*1641.0020.0002] -1F6B2 ; [*1642.0020.0002] -1F6B3 ; [*1643.0020.0002] -1F6B4 ; [*1644.0020.0002] -1F6B5 ; [*1645.0020.0002] -1F6B6 ; [*1646.0020.0002] -1F6B7 ; [*1647.0020.0002] -1F6B8 ; [*1648.0020.0002] -1F6B9 ; [*1649.0020.0002] -1F6BA ; [*164A.0020.0002] -1F6BB ; [*164B.0020.0002] -1F6BC ; [*164C.0020.0002] -1F6BD ; [*164D.0020.0002] -1F6BE ; [*164E.0020.0002] -1F6BF ; [*164F.0020.0002] -1F6C0 ; [*1650.0020.0002] -1F6C1 ; [*1651.0020.0002] -1F6C2 ; [*1652.0020.0002] -1F6C3 ; [*1653.0020.0002] -1F6C4 ; [*1654.0020.0002] -1F6C5 ; [*1655.0020.0002] -1F6C6 ; [*1656.0020.0002] -1F6C7 ; [*1657.0020.0002] -1F6C8 ; [*1658.0020.0002] -1F6C9 ; [*1659.0020.0002] -1F6CA ; [*165A.0020.0002] -1F6CB ; [*165B.0020.0002] -1F6CC ; [*165C.0020.0002] -1F6CD ; [*165D.0020.0002] -1F6CE ; [*165E.0020.0002] -1F6CF ; [*165F.0020.0002] -1F6D0 ; [*1660.0020.0002] -1F6E0 ; [*1661.0020.0002] -1F6E1 ; [*1662.0020.0002] -1F6E2 ; [*1663.0020.0002] -1F6E3 ; [*1664.0020.0002] -1F6E4 ; [*1665.0020.0002] -1F6E5 ; [*1666.0020.0002] -1F6E6 ; [*1667.0020.0002] -1F6E7 ; [*1668.0020.0002] -1F6E8 ; [*1669.0020.0002] -1F6E9 ; [*166A.0020.0002] -1F6EA ; [*166B.0020.0002] -1F6EB ; [*166C.0020.0002] -1F6EC ; [*166D.0020.0002] -1F6F0 ; [*166E.0020.0002] -1F6F1 ; [*166F.0020.0002] -1F6F2 ; [*1670.0020.0002] -1F6F3 ; [*1671.0020.0002] -1F700 ; [*1672.0020.0002] -1F701 ; [*1673.0020.0002] -1F702 ; [*1674.0020.0002] -1F703 ; [*1675.0020.0002] -1F704 ; [*1676.0020.0002] -1F705 ; [*1677.0020.0002] -1F706 ; [*1678.0020.0002] -1F707 ; [*1679.0020.0002] -1F708 ; [*167A.0020.0002] -1F709 ; [*167B.0020.0002] -1F70A ; [*167C.0020.0002] -1F70B ; [*167D.0020.0002] -1F70C ; [*167E.0020.0002] -1F70D ; [*167F.0020.0002] -1F70E ; [*1680.0020.0002] -1F70F ; [*1681.0020.0002] -1F710 ; [*1682.0020.0002] -1F711 ; [*1683.0020.0002] -1F712 ; [*1684.0020.0002] -1F713 ; [*1685.0020.0002] -1F714 ; [*1686.0020.0002] -1F715 ; [*1687.0020.0002] -1F716 ; [*1688.0020.0002] -1F717 ; [*1689.0020.0002] -1F718 ; [*168A.0020.0002] -1F719 ; [*168B.0020.0002] -1F71A ; [*168C.0020.0002] -1F71B ; [*168D.0020.0002] -1F71C ; [*168E.0020.0002] -1F71D ; [*168F.0020.0002] -1F71E ; [*1690.0020.0002] -1F71F ; [*1691.0020.0002] -1F720 ; [*1692.0020.0002] -1F721 ; [*1693.0020.0002] -1F722 ; [*1694.0020.0002] -1F723 ; [*1695.0020.0002] -1F724 ; [*1696.0020.0002] -1F725 ; [*1697.0020.0002] -1F726 ; [*1698.0020.0002] -1F727 ; [*1699.0020.0002] -1F728 ; [*169A.0020.0002] -1F729 ; [*169B.0020.0002] -1F72A ; [*169C.0020.0002] -1F72B ; [*169D.0020.0002] -1F72C ; [*169E.0020.0002] -1F72D ; [*169F.0020.0002] -1F72E ; [*16A0.0020.0002] -1F72F ; [*16A1.0020.0002] -1F730 ; [*16A2.0020.0002] -1F731 ; [*16A3.0020.0002] -1F732 ; [*16A4.0020.0002] -1F733 ; [*16A5.0020.0002] -1F734 ; [*16A6.0020.0002] -1F735 ; [*16A7.0020.0002] -1F736 ; [*16A8.0020.0002] -1F737 ; [*16A9.0020.0002] -1F738 ; [*16AA.0020.0002] -1F739 ; [*16AB.0020.0002] -1F73A ; [*16AC.0020.0002] -1F73B ; [*16AD.0020.0002] -1F73C ; [*16AE.0020.0002] -1F73D ; [*16AF.0020.0002] -1F73E ; [*16B0.0020.0002] -1F73F ; [*16B1.0020.0002] -1F740 ; [*16B2.0020.0002] -1F741 ; [*16B3.0020.0002] -1F742 ; [*16B4.0020.0002] -1F743 ; [*16B5.0020.0002] -1F744 ; [*16B6.0020.0002] -1F745 ; [*16B7.0020.0002] -1F746 ; [*16B8.0020.0002] -1F747 ; [*16B9.0020.0002] -1F748 ; [*16BA.0020.0002] -1F749 ; [*16BB.0020.0002] -1F74A ; [*16BC.0020.0002] -1F74B ; [*16BD.0020.0002] -1F74C ; [*16BE.0020.0002] -1F74D ; [*16BF.0020.0002] -1F74E ; [*16C0.0020.0002] -1F74F ; [*16C1.0020.0002] -1F750 ; [*16C2.0020.0002] -1F751 ; [*16C3.0020.0002] -1F752 ; [*16C4.0020.0002] -1F753 ; [*16C5.0020.0002] -1F754 ; [*16C6.0020.0002] -1F755 ; [*16C7.0020.0002] -1F756 ; [*16C8.0020.0002] -1F757 ; [*16C9.0020.0002] -1F758 ; [*16CA.0020.0002] -1F759 ; [*16CB.0020.0002] -1F75A ; [*16CC.0020.0002] -1F75B ; [*16CD.0020.0002] -1F75C ; [*16CE.0020.0002] -1F75D ; [*16CF.0020.0002] -1F75E ; [*16D0.0020.0002] -1F75F ; [*16D1.0020.0002] -1F760 ; [*16D2.0020.0002] -1F761 ; [*16D3.0020.0002] -1F762 ; [*16D4.0020.0002] -1F763 ; [*16D5.0020.0002] -1F764 ; [*16D6.0020.0002] -1F765 ; [*16D7.0020.0002] -1F766 ; [*16D8.0020.0002] -1F767 ; [*16D9.0020.0002] -1F768 ; [*16DA.0020.0002] -1F769 ; [*16DB.0020.0002] -1F76A ; [*16DC.0020.0002] -1F76B ; [*16DD.0020.0002] -1F76C ; [*16DE.0020.0002] -1F76D ; [*16DF.0020.0002] -1F76E ; [*16E0.0020.0002] -1F76F ; [*16E1.0020.0002] -1F770 ; [*16E2.0020.0002] -1F771 ; [*16E3.0020.0002] -1F772 ; [*16E4.0020.0002] -1F773 ; [*16E5.0020.0002] -1F780 ; [*16E6.0020.0002] -1F781 ; [*16E7.0020.0002] -1F782 ; [*16E8.0020.0002] -1F783 ; [*16E9.0020.0002] -1F784 ; [*16EA.0020.0002] -1F785 ; [*16EB.0020.0002] -1F786 ; [*16EC.0020.0002] -1F787 ; [*16ED.0020.0002] -1F788 ; [*16EE.0020.0002] -1F789 ; [*16EF.0020.0002] -1F78A ; [*16F0.0020.0002] -1F78B ; [*16F1.0020.0002] -1F78C ; [*16F2.0020.0002] -1F78D ; [*16F3.0020.0002] -1F78E ; [*16F4.0020.0002] -1F78F ; [*16F5.0020.0002] -1F790 ; [*16F6.0020.0002] -1F791 ; [*16F7.0020.0002] -1F792 ; [*16F8.0020.0002] -1F793 ; [*16F9.0020.0002] -1F794 ; [*16FA.0020.0002] -1F795 ; [*16FB.0020.0002] -1F796 ; [*16FC.0020.0002] -1F797 ; [*16FD.0020.0002] -1F798 ; [*16FE.0020.0002] -1F799 ; [*16FF.0020.0002] -1F79A ; [*1700.0020.0002] -1F79B ; [*1701.0020.0002] -1F79C ; [*1702.0020.0002] -1F79D ; [*1703.0020.0002] -1F79E ; [*1704.0020.0002] -1F79F ; [*1705.0020.0002] -1F7A0 ; [*1706.0020.0002] -1F7A1 ; [*1707.0020.0002] -1F7A2 ; [*1708.0020.0002] -1F7A3 ; [*1709.0020.0002] -1F7A4 ; [*170A.0020.0002] -1F7A5 ; [*170B.0020.0002] -1F7A6 ; [*170C.0020.0002] -1F7A7 ; [*170D.0020.0002] -1F7A8 ; [*170E.0020.0002] -1F7A9 ; [*170F.0020.0002] -1F7AA ; [*1710.0020.0002] -1F7AB ; [*1711.0020.0002] -1F7AC ; [*1712.0020.0002] -1F7AD ; [*1713.0020.0002] -1F7AE ; [*1714.0020.0002] -1F7AF ; [*1715.0020.0002] -1F7B0 ; [*1716.0020.0002] -1F7B1 ; [*1717.0020.0002] -1F7B2 ; [*1718.0020.0002] -1F7B3 ; [*1719.0020.0002] -1F7B4 ; [*171A.0020.0002] -1F7B5 ; [*171B.0020.0002] -1F7B6 ; [*171C.0020.0002] -1F7B7 ; [*171D.0020.0002] -1F7B8 ; [*171E.0020.0002] -1F7B9 ; [*171F.0020.0002] -1F7BA ; [*1720.0020.0002] -1F7BB ; [*1721.0020.0002] -1F7BC ; [*1722.0020.0002] -1F7BD ; [*1723.0020.0002] -1F7BE ; [*1724.0020.0002] -1F7BF ; [*1725.0020.0002] -1F7C0 ; [*1726.0020.0002] -1F7C1 ; [*1727.0020.0002] -1F7C2 ; [*1728.0020.0002] -1F7C3 ; [*1729.0020.0002] -1F7C4 ; [*172A.0020.0002] -1F7C5 ; [*172B.0020.0002] -1F7C6 ; [*172C.0020.0002] -1F7C7 ; [*172D.0020.0002] -1F7C8 ; [*172E.0020.0002] -1F7C9 ; [*172F.0020.0002] -1F7CA ; [*1730.0020.0002] -1F7CB ; [*1731.0020.0002] -1F7CC ; [*1732.0020.0002] -1F7CD ; [*1733.0020.0002] -1F7CE ; [*1734.0020.0002] -1F7CF ; [*1735.0020.0002] -1F7D0 ; [*1736.0020.0002] -1F7D1 ; [*1737.0020.0002] -1F7D2 ; [*1738.0020.0002] -1F7D3 ; [*1739.0020.0002] -1F7D4 ; [*173A.0020.0002] -1F800 ; [*173B.0020.0002] -1F801 ; [*173C.0020.0002] -1F802 ; [*173D.0020.0002] -1F803 ; [*173E.0020.0002] -1F804 ; [*173F.0020.0002] -1F805 ; [*1740.0020.0002] -1F806 ; [*1741.0020.0002] -1F807 ; [*1742.0020.0002] -1F808 ; [*1743.0020.0002] -1F809 ; [*1744.0020.0002] -1F80A ; [*1745.0020.0002] -1F80B ; [*1746.0020.0002] -1F810 ; [*1747.0020.0002] -1F811 ; [*1748.0020.0002] -1F812 ; [*1749.0020.0002] -1F813 ; [*174A.0020.0002] -1F814 ; [*174B.0020.0002] -1F815 ; [*174C.0020.0002] -1F816 ; [*174D.0020.0002] -1F817 ; [*174E.0020.0002] -1F818 ; [*174F.0020.0002] -1F819 ; [*1750.0020.0002] -1F81A ; [*1751.0020.0002] -1F81B ; [*1752.0020.0002] -1F81C ; [*1753.0020.0002] -1F81D ; [*1754.0020.0002] -1F81E ; [*1755.0020.0002] -1F81F ; [*1756.0020.0002] -1F820 ; [*1757.0020.0002] -1F821 ; [*1758.0020.0002] -1F822 ; [*1759.0020.0002] -1F823 ; [*175A.0020.0002] -1F824 ; [*175B.0020.0002] -1F825 ; [*175C.0020.0002] -1F826 ; [*175D.0020.0002] -1F827 ; [*175E.0020.0002] -1F828 ; [*175F.0020.0002] -1F829 ; [*1760.0020.0002] -1F82A ; [*1761.0020.0002] -1F82B ; [*1762.0020.0002] -1F82C ; [*1763.0020.0002] -1F82D ; [*1764.0020.0002] -1F82E ; [*1765.0020.0002] -1F82F ; [*1766.0020.0002] -1F830 ; [*1767.0020.0002] -1F831 ; [*1768.0020.0002] -1F832 ; [*1769.0020.0002] -1F833 ; [*176A.0020.0002] -1F834 ; [*176B.0020.0002] -1F835 ; [*176C.0020.0002] -1F836 ; [*176D.0020.0002] -1F837 ; [*176E.0020.0002] -1F838 ; [*176F.0020.0002] -1F839 ; [*1770.0020.0002] -1F83A ; [*1771.0020.0002] -1F83B ; [*1772.0020.0002] -1F83C ; [*1773.0020.0002] -1F83D ; [*1774.0020.0002] -1F83E ; [*1775.0020.0002] -1F83F ; [*1776.0020.0002] -1F840 ; [*1777.0020.0002] -1F841 ; [*1778.0020.0002] -1F842 ; [*1779.0020.0002] -1F843 ; [*177A.0020.0002] -1F844 ; [*177B.0020.0002] -1F845 ; [*177C.0020.0002] -1F846 ; [*177D.0020.0002] -1F847 ; [*177E.0020.0002] -1F850 ; [*177F.0020.0002] -1F851 ; [*1780.0020.0002] -1F852 ; [*1781.0020.0002] -1F853 ; [*1782.0020.0002] -1F854 ; [*1783.0020.0002] -1F855 ; [*1784.0020.0002] -1F856 ; [*1785.0020.0002] -1F857 ; [*1786.0020.0002] -1F858 ; [*1787.0020.0002] -1F859 ; [*1788.0020.0002] -1F860 ; [*1789.0020.0002] -1F861 ; [*178A.0020.0002] -1F862 ; [*178B.0020.0002] -1F863 ; [*178C.0020.0002] -1F864 ; [*178D.0020.0002] -1F865 ; [*178E.0020.0002] -1F866 ; [*178F.0020.0002] -1F867 ; [*1790.0020.0002] -1F868 ; [*1791.0020.0002] -1F869 ; [*1792.0020.0002] -1F86A ; [*1793.0020.0002] -1F86B ; [*1794.0020.0002] -1F86C ; [*1795.0020.0002] -1F86D ; [*1796.0020.0002] -1F86E ; [*1797.0020.0002] -1F86F ; [*1798.0020.0002] -1F870 ; [*1799.0020.0002] -1F871 ; [*179A.0020.0002] -1F872 ; [*179B.0020.0002] -1F873 ; [*179C.0020.0002] -1F874 ; [*179D.0020.0002] -1F875 ; [*179E.0020.0002] -1F876 ; [*179F.0020.0002] -1F877 ; [*17A0.0020.0002] -1F878 ; [*17A1.0020.0002] -1F879 ; [*17A2.0020.0002] -1F87A ; [*17A3.0020.0002] -1F87B ; [*17A4.0020.0002] -1F87C ; [*17A5.0020.0002] -1F87D ; [*17A6.0020.0002] -1F87E ; [*17A7.0020.0002] -1F87F ; [*17A8.0020.0002] -1F880 ; [*17A9.0020.0002] -1F881 ; [*17AA.0020.0002] -1F882 ; [*17AB.0020.0002] -1F883 ; [*17AC.0020.0002] -1F884 ; [*17AD.0020.0002] -1F885 ; [*17AE.0020.0002] -1F886 ; [*17AF.0020.0002] -1F887 ; [*17B0.0020.0002] -1F890 ; [*17B1.0020.0002] -1F891 ; [*17B2.0020.0002] -1F892 ; [*17B3.0020.0002] -1F893 ; [*17B4.0020.0002] -1F894 ; [*17B5.0020.0002] -1F895 ; [*17B6.0020.0002] -1F896 ; [*17B7.0020.0002] -1F897 ; [*17B8.0020.0002] -1F898 ; [*17B9.0020.0002] -1F899 ; [*17BA.0020.0002] -1F89A ; [*17BB.0020.0002] -1F89B ; [*17BC.0020.0002] -1F89C ; [*17BD.0020.0002] -1F89D ; [*17BE.0020.0002] -1F89E ; [*17BF.0020.0002] -1F89F ; [*17C0.0020.0002] -1F8A0 ; [*17C1.0020.0002] -1F8A1 ; [*17C2.0020.0002] -1F8A2 ; [*17C3.0020.0002] -1F8A3 ; [*17C4.0020.0002] -1F8A4 ; [*17C5.0020.0002] -1F8A5 ; [*17C6.0020.0002] -1F8A6 ; [*17C7.0020.0002] -1F8A7 ; [*17C8.0020.0002] -1F8A8 ; [*17C9.0020.0002] -1F8A9 ; [*17CA.0020.0002] -1F8AA ; [*17CB.0020.0002] -1F8AB ; [*17CC.0020.0002] -1F8AC ; [*17CD.0020.0002] -1F8AD ; [*17CE.0020.0002] -1F910 ; [*1581.0020.0002] -1F911 ; [*1582.0020.0002] -1F912 ; [*1583.0020.0002] -1F913 ; [*1584.0020.0002] -1F914 ; [*1585.0020.0002] -1F915 ; [*1586.0020.0002] -1F916 ; [*1587.0020.0002] -1F917 ; [*1588.0020.0002] -1F918 ; [*1589.0020.0002] -1F980 ; [*158A.0020.0002] -1F981 ; [*158B.0020.0002] -1F982 ; [*158C.0020.0002] -1F983 ; [*158D.0020.0002] -1F984 ; [*158E.0020.0002] -1F9C0 ; [*158F.0020.0002] -0332 ; [.0000.0021.0002] -0313 ; [.0000.0022.0002] -0343 ; [.0000.0022.0002] -0486 ; [.0000.0022.0002] -2CF1 ; [.0000.0022.0002] -0314 ; [.0000.0023.0002] -0485 ; [.0000.0023.0002] -2CF0 ; [.0000.0023.0002] -0301 ; [.0000.0024.0002] -0341 ; [.0000.0024.0002] -0954 ; [.0000.0024.0002] -0300 ; [.0000.0025.0002] -0340 ; [.0000.0025.0002] -0953 ; [.0000.0025.0002] -0306 ; [.0000.0026.0002] -0302 ; [.0000.0027.0002] -030C ; [.0000.0028.0002] -030A ; [.0000.0029.0002] -0342 ; [.0000.002A.0002] -0308 ; [.0000.002B.0002] -0344 ; [.0000.002B.0002][.0000.0024.0002] -030B ; [.0000.002C.0002] -0303 ; [.0000.002D.0002] -0307 ; [.0000.002E.0002] -0338 ; [.0000.002F.0002] -0327 ; [.0000.0030.0002] -0328 ; [.0000.0031.0002] -0304 ; [.0000.0032.0002] -030D ; [.0000.0033.0002] -030E ; [.0000.0033.0002] -0312 ; [.0000.0033.0002] -0315 ; [.0000.0033.0002] -031A ; [.0000.0033.0002] -033D ; [.0000.0033.0002] -033E ; [.0000.0033.0002] -033F ; [.0000.0033.0002] -0346 ; [.0000.0033.0002] -034A ; [.0000.0033.0002] -034B ; [.0000.0033.0002] -034C ; [.0000.0033.0002] -0350 ; [.0000.0033.0002] -0351 ; [.0000.0033.0002] -0352 ; [.0000.0033.0002] -0357 ; [.0000.0033.0002] -035B ; [.0000.0033.0002] -035D ; [.0000.0033.0002] -035E ; [.0000.0033.0002] -0484 ; [.0000.0033.0002] -0487 ; [.0000.0033.0002] -0741 ; [.0000.0033.0002] -0745 ; [.0000.0033.0002] -17CB ; [.0000.0033.0002] -17CC ; [.0000.0033.0002] -17CD ; [.0000.0033.0002] -17CE ; [.0000.0033.0002] -17CF ; [.0000.0033.0002] -17D0 ; [.0000.0033.0002] -17D1 ; [.0000.0033.0002] -17DD ; [.0000.0033.0002] -1AB0 ; [.0000.0033.0002] -1AB1 ; [.0000.0033.0002] -1AB2 ; [.0000.0033.0002] -1AB3 ; [.0000.0033.0002] -1AB4 ; [.0000.0033.0002] -1ABB ; [.0000.0033.0002] -1ABC ; [.0000.0033.0002] -1DC0 ; [.0000.0033.0002] -1DC1 ; [.0000.0033.0002] -1DC3 ; [.0000.0033.0002] -1DC4 ; [.0000.0033.0002] -1DC5 ; [.0000.0033.0002] -1DC6 ; [.0000.0033.0002] -1DC7 ; [.0000.0033.0002] -1DC8 ; [.0000.0033.0002] -1DC9 ; [.0000.0033.0002] -1DCB ; [.0000.0033.0002] -1DCC ; [.0000.0033.0002] -1DCD ; [.0000.0033.0002] -1DCE ; [.0000.0033.0002] -1DD1 ; [.0000.0033.0002] -1DF5 ; [.0000.0033.0002] -1DFE ; [.0000.0033.0002] -20F0 ; [.0000.0033.0002] -2CEF ; [.0000.0033.0002] -A67C ; [.0000.0033.0002] -A67D ; [.0000.0033.0002] -10AE5 ; [.0000.0033.0002] -1BC9D ; [.0000.0033.0002] -0316 ; [.0000.0034.0002] -0317 ; [.0000.0034.0002] -0318 ; [.0000.0034.0002] -0319 ; [.0000.0034.0002] -031C ; [.0000.0034.0002] -031D ; [.0000.0034.0002] -031E ; [.0000.0034.0002] -031F ; [.0000.0034.0002] -0320 ; [.0000.0034.0002] -0329 ; [.0000.0034.0002] -032A ; [.0000.0034.0002] -032B ; [.0000.0034.0002] -032C ; [.0000.0034.0002] -032F ; [.0000.0034.0002] -0333 ; [.0000.0034.0002] -033A ; [.0000.0034.0002] -033B ; [.0000.0034.0002] -033C ; [.0000.0034.0002] -0347 ; [.0000.0034.0002] -0348 ; [.0000.0034.0002] -0349 ; [.0000.0034.0002] -034D ; [.0000.0034.0002] -034E ; [.0000.0034.0002] -0353 ; [.0000.0034.0002] -0354 ; [.0000.0034.0002] -0355 ; [.0000.0034.0002] -0356 ; [.0000.0034.0002] -0359 ; [.0000.0034.0002] -035A ; [.0000.0034.0002] -035C ; [.0000.0034.0002] -035F ; [.0000.0034.0002] -0362 ; [.0000.0034.0002] -0742 ; [.0000.0034.0002] -0746 ; [.0000.0034.0002] -0859 ; [.0000.0034.0002] -085A ; [.0000.0034.0002] -085B ; [.0000.0034.0002] -1AB5 ; [.0000.0034.0002] -1AB6 ; [.0000.0034.0002] -1AB7 ; [.0000.0034.0002] -1AB8 ; [.0000.0034.0002] -1AB9 ; [.0000.0034.0002] -1ABA ; [.0000.0034.0002] -1ABD ; [.0000.0034.0002] -1DC2 ; [.0000.0034.0002] -1DCF ; [.0000.0034.0002] -1DD0 ; [.0000.0034.0002] -1DFC ; [.0000.0034.0002] -1DFD ; [.0000.0034.0002] -1DFF ; [.0000.0034.0002] -20EC ; [.0000.0034.0002] -20ED ; [.0000.0034.0002] -20EE ; [.0000.0034.0002] -20EF ; [.0000.0034.0002] -FE27 ; [.0000.0034.0002] -10A0D ; [.0000.0034.0002] -10AE6 ; [.0000.0034.0002] -0336 ; [.0000.0035.0002] -0337 ; [.0000.0035.0002] -20D8 ; [.0000.0035.0002] -20D9 ; [.0000.0035.0002] -20DA ; [.0000.0035.0002] -20E5 ; [.0000.0035.0002] -20EA ; [.0000.0035.0002] -20EB ; [.0000.0035.0002] -1BC9E ; [.0000.0035.0002] -1ABE ; [.0000.0036.0002] -20DD ; [.0000.0036.0002] -20DE ; [.0000.0036.0002] -20DF ; [.0000.0036.0002] -20E0 ; [.0000.0036.0002] -20E2 ; [.0000.0036.0002] -20E3 ; [.0000.0036.0002] -20E4 ; [.0000.0036.0002] -3099 ; [.0000.0037.0002] -FF9E ; [.0000.0037.0012] -309A ; [.0000.0038.0002] -FF9F ; [.0000.0038.0012] -0335 ; [.0000.0039.0002] -0305 ; [.0000.003A.0002] -0309 ; [.0000.003B.0002] -030F ; [.0000.003C.0002] -0310 ; [.0000.003D.0002] -0311 ; [.0000.003E.0002] -031B ; [.0000.003F.0002] -0321 ; [.0000.0040.0002] -0322 ; [.0000.0041.0002] -0323 ; [.0000.0042.0002] -0324 ; [.0000.0043.0002] -0325 ; [.0000.0044.0002] -0326 ; [.0000.0045.0002] -032D ; [.0000.0046.0002] -032E ; [.0000.0047.0002] -0330 ; [.0000.0048.0002] -0331 ; [.0000.0049.0002] -0334 ; [.0000.004A.0002] -0339 ; [.0000.004B.0002] -0345 ; [.0000.004C.0002] -0358 ; [.0000.004D.0002] -0360 ; [.0000.004E.0002] -FE22 ; [.0000.004E.0002] -FE29 ; [.0000.004E.0002] -0361 ; [.0000.004F.0002] -FE20 ; [.0000.004F.0002] -0483 ; [.0000.0050.0002] -FE2E ; [.0000.0050.0002] -A66F ; [.0000.0051.0002] -05B0 ; [.0000.0052.0002] -05B1 ; [.0000.0053.0002] -05B2 ; [.0000.0054.0002] -05B3 ; [.0000.0055.0002] -05B4 ; [.0000.0056.0002] -05B5 ; [.0000.0057.0002] -05B6 ; [.0000.0058.0002] -05B7 ; [.0000.0059.0002] -05B8 ; [.0000.005A.0002] -05C7 ; [.0000.005A.0002] -05B9 ; [.0000.005B.0002] -05BA ; [.0000.005B.0002] -05BB ; [.0000.005C.0002] -05C2 ; [.0000.005D.0002] -05C1 ; [.0000.005E.0002] -05BC ; [.0000.005F.0002] -05BF ; [.0000.0060.0002] -FB1E ; [.0000.0061.0002] -081C ; [.0000.0062.0002] -081D ; [.0000.0062.0002] -081E ; [.0000.0063.0002] -081F ; [.0000.0063.0002] -0820 ; [.0000.0063.0002] -0821 ; [.0000.0064.0002] -0822 ; [.0000.0064.0002] -0823 ; [.0000.0064.0002] -0824 ; [.0000.0065.0002] -0825 ; [.0000.0065.0002] -0826 ; [.0000.0066.0002] -0827 ; [.0000.0066.0002] -0828 ; [.0000.0067.0002] -0829 ; [.0000.0067.0002] -082A ; [.0000.0067.0002] -082B ; [.0000.0068.0002] -082C ; [.0000.0069.0002] -0818 ; [.0000.006A.0002] -0819 ; [.0000.006B.0002] -082D ; [.0000.006C.0002] -064B ; [.0000.006D.0002] -FE71 ; [.0000.006D.0018] -FE70 ; [.0000.006D.001A] -08F0 ; [.0000.006E.0002] -08E7 ; [.0000.006F.0002] -064C ; [.0000.0070.0002] -FE72 ; [.0000.0070.001A] -FC5E ; [.0000.0070.001A][.0000.0080.001A] -08F1 ; [.0000.0071.0002] -08E8 ; [.0000.0072.0002] -064D ; [.0000.0073.0002] -FE74 ; [.0000.0073.001A] -FC5F ; [.0000.0073.001A][.0000.0080.001A] -08F2 ; [.0000.0074.0002] -08E9 ; [.0000.0075.0002] -064E ; [.0000.0076.0002] -FE77 ; [.0000.0076.0018] -FE76 ; [.0000.0076.001A] -FCF2 ; [.0000.0076.0018][.0000.0080.0018] -FC60 ; [.0000.0076.001A][.0000.0080.001A] -08E4 ; [.0000.0077.0002] -08F4 ; [.0000.0078.0002] -08F5 ; [.0000.0079.0002] -064F ; [.0000.007A.0002] -FE79 ; [.0000.007A.0018] -FE78 ; [.0000.007A.001A] -FCF3 ; [.0000.007A.0018][.0000.0080.0018] -FC61 ; [.0000.007A.001A][.0000.0080.001A] -08E5 ; [.0000.007B.0002] -08FE ; [.0000.007C.0002] -0650 ; [.0000.007D.0002] -FE7B ; [.0000.007D.0018] -FE7A ; [.0000.007D.001A] -FCF4 ; [.0000.007D.0018][.0000.0080.0018] -FC62 ; [.0000.007D.001A][.0000.0080.001A] -08E6 ; [.0000.007E.0002] -08F6 ; [.0000.007F.0002] -0651 ; [.0000.0080.0002] -11237 ; [.0000.0080.0002] -FE7D ; [.0000.0080.0018] -FE7C ; [.0000.0080.001A] -FC63 ; [.0000.0080.001A][.0000.0098.001A] -0652 ; [.0000.0081.0002] -FE7F ; [.0000.0081.0018] -FE7E ; [.0000.0081.001A] -0653 ; [.0000.0082.0002] -0654 ; [.0000.0083.0002] -0655 ; [.0000.0084.0002] -065F ; [.0000.0085.0002] -0656 ; [.0000.0086.0002] -0657 ; [.0000.0087.0002] -0658 ; [.0000.0088.0002] -08FF ; [.0000.0089.0002] -0659 ; [.0000.008A.0002] -065A ; [.0000.008B.0002] -065B ; [.0000.008C.0002] -065C ; [.0000.008D.0002] -065D ; [.0000.008E.0002] -065E ; [.0000.008F.0002] -08E3 ; [.0000.0090.0002] -08F7 ; [.0000.0091.0002] -08F8 ; [.0000.0092.0002] -08FD ; [.0000.0093.0002] -08FB ; [.0000.0094.0002] -08FC ; [.0000.0095.0002] -08F9 ; [.0000.0096.0002] -08FA ; [.0000.0097.0002] -0670 ; [.0000.0098.0002] -0711 ; [.0000.0099.0002] -0730 ; [.0000.009A.0002] -0731 ; [.0000.009B.0002] -0732 ; [.0000.009C.0002] -0733 ; [.0000.009D.0002] -0734 ; [.0000.009E.0002] -0735 ; [.0000.009F.0002] -0736 ; [.0000.00A0.0002] -0737 ; [.0000.00A1.0002] -0738 ; [.0000.00A2.0002] -0739 ; [.0000.00A3.0002] -073A ; [.0000.00A4.0002] -073B ; [.0000.00A5.0002] -073C ; [.0000.00A6.0002] -073D ; [.0000.00A7.0002] -073E ; [.0000.00A8.0002] -073F ; [.0000.00A9.0002] -07EB ; [.0000.00AA.0002] -07EC ; [.0000.00AB.0002] -07ED ; [.0000.00AC.0002] -07EE ; [.0000.00AD.0002] -07EF ; [.0000.00AE.0002] -07F0 ; [.0000.00AF.0002] -07F1 ; [.0000.00B0.0002] -07F2 ; [.0000.00B1.0002] -07F3 ; [.0000.00B2.0002] -135F ; [.0000.00B3.0002] -135E ; [.0000.00B4.0002] -135D ; [.0000.00B5.0002] -A6F0 ; [.0000.00B6.0002] -A6F1 ; [.0000.00B7.0002] -16AF0 ; [.0000.00B8.0002] -16AF1 ; [.0000.00B9.0002] -16AF2 ; [.0000.00BA.0002] -16AF3 ; [.0000.00BB.0002] -16AF4 ; [.0000.00BC.0002] -093C ; [.0000.00BD.0002] -09BC ; [.0000.00BD.0002] -0A3C ; [.0000.00BD.0002] -0ABC ; [.0000.00BD.0002] -0B3C ; [.0000.00BD.0002] -0CBC ; [.0000.00BD.0002] -1B34 ; [.0000.00BD.0002] -1BE6 ; [.0000.00BD.0002] -1C37 ; [.0000.00BD.0002] -A9B3 ; [.0000.00BD.0002] -110BA ; [.0000.00BD.0002] -11173 ; [.0000.00BD.0002] -111CA ; [.0000.00BD.0002] -11236 ; [.0000.00BD.0002] -112E9 ; [.0000.00BD.0002] -1133C ; [.0000.00BD.0002] -114C3 ; [.0000.00BD.0002] -115C0 ; [.0000.00BD.0002] -116B7 ; [.0000.00BD.0002] -0900 ; [.0000.00BE.0002] -0901 ; [.0000.00BE.0002] -0981 ; [.0000.00BE.0002] -0A01 ; [.0000.00BE.0002] -0A81 ; [.0000.00BE.0002] -0B01 ; [.0000.00BE.0002] -0C00 ; [.0000.00BE.0002] -0C01 ; [.0000.00BE.0002] -0C81 ; [.0000.00BE.0002] -0D01 ; [.0000.00BE.0002] -1B00 ; [.0000.00BE.0002] -1B01 ; [.0000.00BE.0002] -A980 ; [.0000.00BE.0002] -11000 ; [.0000.00BE.0002] -11080 ; [.0000.00BE.0002] -11100 ; [.0000.00BE.0002] -11180 ; [.0000.00BE.0002] -11301 ; [.0000.00BE.0002] -114BF ; [.0000.00BE.0002] -115BC ; [.0000.00BE.0002] -11640 ; [.0000.00BE.0002] -0902 ; [.0000.00BF.0002] -0982 ; [.0000.00BF.0002] -0A02 ; [.0000.00BF.0002] -0A82 ; [.0000.00BF.0002] -0B02 ; [.0000.00BF.0002] -0B82 ; [.0000.00BF.0002] -0C02 ; [.0000.00BF.0002] -0C82 ; [.0000.00BF.0002] -0D02 ; [.0000.00BF.0002] -0D82 ; [.0000.00BF.0002] -0F7E ; [.0000.00BF.0002] -1036 ; [.0000.00BF.0002] -17C6 ; [.0000.00BF.0002] -1A74 ; [.0000.00BF.0002] -1B02 ; [.0000.00BF.0002] -1B80 ; [.0000.00BF.0002] -1CED ; [.0000.00BF.0002] -A80B ; [.0000.00BF.0002] -A880 ; [.0000.00BF.0002] -A981 ; [.0000.00BF.0002] -10A0E ; [.0000.00BF.0002] -11001 ; [.0000.00BF.0002] -11081 ; [.0000.00BF.0002] -11101 ; [.0000.00BF.0002] -11181 ; [.0000.00BF.0002] -11234 ; [.0000.00BF.0002] -112DF ; [.0000.00BF.0002] -11300 ; [.0000.00BF.0002] -11302 ; [.0000.00BF.0002] -114C0 ; [.0000.00BF.0002] -115BD ; [.0000.00BF.0002] -1163D ; [.0000.00BF.0002] -116AB ; [.0000.00BF.0002] -0903 ; [.0000.00C0.0002] -0983 ; [.0000.00C0.0002] -0A03 ; [.0000.00C0.0002] -0A83 ; [.0000.00C0.0002] -0B03 ; [.0000.00C0.0002] -0C03 ; [.0000.00C0.0002] -0C83 ; [.0000.00C0.0002] -0D03 ; [.0000.00C0.0002] -0D83 ; [.0000.00C0.0002] -0F7F ; [.0000.00C0.0002] -1038 ; [.0000.00C0.0002] -17C7 ; [.0000.00C0.0002] -1B04 ; [.0000.00C0.0002] -1B82 ; [.0000.00C0.0002] -1CF2 ; [.0000.00C0.0002] -1CF3 ; [.0000.00C0.0002] -A881 ; [.0000.00C0.0002] -A983 ; [.0000.00C0.0002] -10A0F ; [.0000.00C0.0002] -11002 ; [.0000.00C0.0002] -11082 ; [.0000.00C0.0002] -11102 ; [.0000.00C0.0002] -11182 ; [.0000.00C0.0002] -11303 ; [.0000.00C0.0002] -114C1 ; [.0000.00C0.0002] -115BE ; [.0000.00C0.0002] -1163E ; [.0000.00C0.0002] -116AC ; [.0000.00C0.0002] -0A70 ; [.0000.00C1.0002] -0A71 ; [.0000.00C2.0002] -1B03 ; [.0000.00C3.0002] -A982 ; [.0000.00C4.0002] -1B81 ; [.0000.00C5.0002] -ABEC ; [.0000.00C6.0002] -10A38 ; [.0000.00C7.0002] -10A39 ; [.0000.00C8.0002] -10A3A ; [.0000.00C9.0002] -111CB ; [.0000.00CA.0002] -111CC ; [.0000.00CB.0002] -0E4E ; [.0000.00CC.0002] -0E47 ; [.0000.00CD.0002] -0E48 ; [.0000.00CE.0002] -0E49 ; [.0000.00CF.0002] -0E4A ; [.0000.00D0.0002] -0E4B ; [.0000.00D1.0002] -0E4C ; [.0000.00D2.0002] -0E4D ; [.0000.00D3.0002] -0EC8 ; [.0000.00D4.0002] -0EC9 ; [.0000.00D5.0002] -0ECA ; [.0000.00D6.0002] -0ECB ; [.0000.00D7.0002] -0ECC ; [.0000.00D8.0002] -0ECD ; [.0000.00D9.0002] -AABF ; [.0000.00DA.0002] -AAC1 ; [.0000.00DB.0002] -0F39 ; [.0000.00DC.0002] -A92B ; [.0000.00DD.0002] -A92C ; [.0000.00DE.0002] -A92D ; [.0000.00DF.0002] -1037 ; [.0000.00E0.0002] -17C8 ; [.0000.00E1.0002] -17C9 ; [.0000.00E2.0002] -17CA ; [.0000.00E3.0002] -1A75 ; [.0000.00E4.0002] -1A76 ; [.0000.00E5.0002] -1A77 ; [.0000.00E6.0002] -1A78 ; [.0000.00E7.0002] -1A79 ; [.0000.00E8.0002] -1A7A ; [.0000.00E9.0002] -1A7B ; [.0000.00EA.0002] -1A7C ; [.0000.00EB.0002] -1939 ; [.0000.00EC.0002] -193A ; [.0000.00ED.0002] -193B ; [.0000.00EE.0002] -16B30 ; [.0000.00EF.0002] -16B31 ; [.0000.00F0.0002] -16B32 ; [.0000.00F1.0002] -16B33 ; [.0000.00F2.0002] -16B34 ; [.0000.00F3.0002] -16B35 ; [.0000.00F4.0002] -16B36 ; [.0000.00F5.0002] -302A ; [.0000.00F6.0002] -302B ; [.0000.00F7.0002] -302C ; [.0000.00F8.0002] -302D ; [.0000.00F9.0002] -302E ; [.0000.00FA.0002] -302F ; [.0000.00FB.0002] -20D0 ; [.0000.00FC.0002] -20D1 ; [.0000.00FD.0002] -20D2 ; [.0000.00FE.0002] -20D3 ; [.0000.00FE.0002] -20D4 ; [.0000.00FF.0002] -20D5 ; [.0000.0100.0002] -20D6 ; [.0000.0101.0002] -20D7 ; [.0000.0102.0002] -20DB ; [.0000.0103.0002] -20DC ; [.0000.0104.0002] -20E1 ; [.0000.0105.0002] -20E6 ; [.0000.0106.0002] -20E7 ; [.0000.0107.0002] -20E8 ; [.0000.0108.0002] -20E9 ; [.0000.0109.0002] -101FD ; [.0000.010A.0002] -02D0 ; [.1B74.0020.0002] -02D1 ; [.1B75.0020.0002] -0971 ; [.1B76.0020.0002] -0E46 ; [.1B77.0020.0002] -0EC6 ; [.1B78.0020.0002] -17D7 ; [.1B79.0020.0002] -1AA7 ; [.1B7A.0020.0002] -A9CF ; [.1B7B.0020.0002] -A9E6 ; [.1B7C.0020.0002] -AA70 ; [.1B7D.0020.0002] -AADD ; [.1B7E.0020.0002] -AAF3 ; [.1B7F.0020.0002] -AAF4 ; [.1B80.0020.0002] -16B42 ; [.1B81.0020.0002] -16B43 ; [.1B82.0020.0002] -3005 ; [.1B83.0020.0002] -303B ; [.1B84.0020.0002] -3031 ; [.1B85.0020.0002] -3032 ; [.1B85.0020.0002][.0000.0037.0002] -3033 ; [.1B86.0020.0002] -3034 ; [.1B86.0020.0002][.0000.0037.0002] -3035 ; [.1B87.0020.0002] -309D ; [.1B88.0020.0002] -309E ; [.1B88.0020.0002][.0000.0037.0002] -30FC ; [.1B89.0020.0002] -FF70 ; [.1B89.0020.0012] -30FD ; [.1B8A.0020.0002] -30FE ; [.1B8A.0020.0002][.0000.0037.0002] -00A4 ; [.1B8B.0020.0002] -00A2 ; [.1B8C.0020.0002] -FFE0 ; [.1B8C.0020.0003] -0024 ; [.1B8D.0020.0002] -FF04 ; [.1B8D.0020.0003] -FE69 ; [.1B8D.0020.000F] -00A3 ; [.1B8E.0020.0002] -FFE1 ; [.1B8E.0020.0003] -00A5 ; [.1B8F.0020.0002] -FFE5 ; [.1B8F.0020.0003] -058F ; [.1B90.0020.0002] -060B ; [.1B91.0020.0002] -09F2 ; [.1B92.0020.0002] -09F3 ; [.1B93.0020.0002] -09FB ; [.1B94.0020.0002] -0AF1 ; [.1B95.0020.0002] -A838 ; [.1B96.0020.0002] -0BF9 ; [.1B97.0020.0002] -0E3F ; [.1B98.0020.0002] -17DB ; [.1B99.0020.0002] -20A0 ; [.1B9A.0020.0002] -20A1 ; [.1B9B.0020.0002] -20A2 ; [.1B9C.0020.0002] -20A3 ; [.1B9D.0020.0002] -20A4 ; [.1B9E.0020.0002] -20A5 ; [.1B9F.0020.0002] -20A6 ; [.1BA0.0020.0002] -20A7 ; [.1BA1.0020.0002] -20A9 ; [.1BA2.0020.0002] -FFE6 ; [.1BA2.0020.0003] -20AA ; [.1BA3.0020.0002] -20AB ; [.1BA4.0020.0002] -20AC ; [.1BA5.0020.0002] -20AD ; [.1BA6.0020.0002] -20AE ; [.1BA7.0020.0002] -20AF ; [.1BA8.0020.0002] -20B0 ; [.1BA9.0020.0002] -20B1 ; [.1BAA.0020.0002] -20B2 ; [.1BAB.0020.0002] -20B3 ; [.1BAC.0020.0002] -20B4 ; [.1BAD.0020.0002] -20B5 ; [.1BAE.0020.0002] -20B6 ; [.1BAF.0020.0002] -20B7 ; [.1BB0.0020.0002] -20B8 ; [.1BB1.0020.0002] -20B9 ; [.1BB2.0020.0002] -20BA ; [.1BB3.0020.0002] -20BB ; [.1BB4.0020.0002] -20BC ; [.1BB5.0020.0002] -20BD ; [.1BB6.0020.0002] -20BE ; [.1BB7.0020.0002] -0030 ; [.1BB8.0020.0002] -0660 ; [.1BB8.0020.0002] -06F0 ; [.1BB8.0020.0002] -07C0 ; [.1BB8.0020.0002] -0966 ; [.1BB8.0020.0002] -09E6 ; [.1BB8.0020.0002] -0A66 ; [.1BB8.0020.0002] -0AE6 ; [.1BB8.0020.0002] -0B66 ; [.1BB8.0020.0002] -0BE6 ; [.1BB8.0020.0002] -0C66 ; [.1BB8.0020.0002] -0C78 ; [.1BB8.0020.0002] -0CE6 ; [.1BB8.0020.0002] -0D66 ; [.1BB8.0020.0002] -0DE6 ; [.1BB8.0020.0002] -0E50 ; [.1BB8.0020.0002] -0ED0 ; [.1BB8.0020.0002] -0F20 ; [.1BB8.0020.0002] -1040 ; [.1BB8.0020.0002] -1090 ; [.1BB8.0020.0002] -17E0 ; [.1BB8.0020.0002] -17F0 ; [.1BB8.0020.0002] -1810 ; [.1BB8.0020.0002] -1946 ; [.1BB8.0020.0002] -19D0 ; [.1BB8.0020.0002] -1A80 ; [.1BB8.0020.0002] -1A90 ; [.1BB8.0020.0002] -1B50 ; [.1BB8.0020.0002] -1BB0 ; [.1BB8.0020.0002] -1C40 ; [.1BB8.0020.0002] -1C50 ; [.1BB8.0020.0002] -3007 ; [.1BB8.0020.0002] -A620 ; [.1BB8.0020.0002] -A8D0 ; [.1BB8.0020.0002] -A900 ; [.1BB8.0020.0002] -A9D0 ; [.1BB8.0020.0002] -A9F0 ; [.1BB8.0020.0002] -AA50 ; [.1BB8.0020.0002] -ABF0 ; [.1BB8.0020.0002] -1018A ; [.1BB8.0020.0002] -104A0 ; [.1BB8.0020.0002] -11066 ; [.1BB8.0020.0002] -110F0 ; [.1BB8.0020.0002] -11136 ; [.1BB8.0020.0002] -111D0 ; [.1BB8.0020.0002] -112F0 ; [.1BB8.0020.0002] -114D0 ; [.1BB8.0020.0002] -11650 ; [.1BB8.0020.0002] -116C0 ; [.1BB8.0020.0002] -11730 ; [.1BB8.0020.0002] -118E0 ; [.1BB8.0020.0002] -16A60 ; [.1BB8.0020.0002] -16B50 ; [.1BB8.0020.0002] -FF10 ; [.1BB8.0020.0003] -0F33 ; [.1BB8.0020.0004] -1F100 ; [.1BB8.0020.0004][*0274.0020.0004] -1F101 ; [.1BB8.0020.0004][*0221.0020.0004] -1D7CE ; [.1BB8.0020.0005] -1D7D8 ; [.1BB8.0020.0005] -1D7E2 ; [.1BB8.0020.0005] -1D7EC ; [.1BB8.0020.0005] -1D7F6 ; [.1BB8.0020.0005] -24EA ; [.1BB8.0020.0006] -24FF ; [.1BB8.0020.0006] -1F10B ; [.1BB8.0020.0006] -1F10C ; [.1BB8.0020.0006] -2070 ; [.1BB8.0020.0014] -2080 ; [.1BB8.0020.0015] -2189 ; [.1BB8.0020.001E][*0606.0020.001E][.1BBB.0020.001E] -3358 ; [.1BB8.0020.0004][.FB40.0020.0004][.F0B9.0000.0000] -0031 ; [.1BB9.0020.0002] -0661 ; [.1BB9.0020.0002] -06F1 ; [.1BB9.0020.0002] -07C1 ; [.1BB9.0020.0002] -0967 ; [.1BB9.0020.0002] -09E7 ; [.1BB9.0020.0002] -0A67 ; [.1BB9.0020.0002] -0AE7 ; [.1BB9.0020.0002] -0B67 ; [.1BB9.0020.0002] -0BE7 ; [.1BB9.0020.0002] -0C67 ; [.1BB9.0020.0002] -0C79 ; [.1BB9.0020.0002] -0C7C ; [.1BB9.0020.0002] -0CE7 ; [.1BB9.0020.0002] -0D67 ; [.1BB9.0020.0002] -0DE7 ; [.1BB9.0020.0002] -0E51 ; [.1BB9.0020.0002] -0ED1 ; [.1BB9.0020.0002] -0F21 ; [.1BB9.0020.0002] -1041 ; [.1BB9.0020.0002] -1091 ; [.1BB9.0020.0002] -1369 ; [.1BB9.0020.0002] -17E1 ; [.1BB9.0020.0002] -17F1 ; [.1BB9.0020.0002] -1811 ; [.1BB9.0020.0002] -1947 ; [.1BB9.0020.0002] -19D1 ; [.1BB9.0020.0002] -19DA ; [.1BB9.0020.0002] -1A81 ; [.1BB9.0020.0002] -1A91 ; [.1BB9.0020.0002] -1B51 ; [.1BB9.0020.0002] -1BB1 ; [.1BB9.0020.0002] -1C41 ; [.1BB9.0020.0002] -1C51 ; [.1BB9.0020.0002] -3021 ; [.1BB9.0020.0002] -A621 ; [.1BB9.0020.0002] -A8D1 ; [.1BB9.0020.0002] -A901 ; [.1BB9.0020.0002] -A9D1 ; [.1BB9.0020.0002] -A9F1 ; [.1BB9.0020.0002] -AA51 ; [.1BB9.0020.0002] -ABF1 ; [.1BB9.0020.0002] -10107 ; [.1BB9.0020.0002] -10142 ; [.1BB9.0020.0002] -10158 ; [.1BB9.0020.0002] -10159 ; [.1BB9.0020.0002] -1015A ; [.1BB9.0020.0002] -102E1 ; [.1BB9.0020.0002] -10320 ; [.1BB9.0020.0002] -103D1 ; [.1BB9.0020.0002] -104A1 ; [.1BB9.0020.0002] -10858 ; [.1BB9.0020.0002] -10879 ; [.1BB9.0020.0002] -108A7 ; [.1BB9.0020.0002] -108FB ; [.1BB9.0020.0002] -10916 ; [.1BB9.0020.0002] -109C0 ; [.1BB9.0020.0002] -10A40 ; [.1BB9.0020.0002] -10A7D ; [.1BB9.0020.0002] -10A9D ; [.1BB9.0020.0002] -10AEB ; [.1BB9.0020.0002] -10B58 ; [.1BB9.0020.0002] -10B78 ; [.1BB9.0020.0002] -10BA9 ; [.1BB9.0020.0002] -10CFA ; [.1BB9.0020.0002] -10E60 ; [.1BB9.0020.0002] -11052 ; [.1BB9.0020.0002] -11067 ; [.1BB9.0020.0002] -110F1 ; [.1BB9.0020.0002] -11137 ; [.1BB9.0020.0002] -111D1 ; [.1BB9.0020.0002] -111E1 ; [.1BB9.0020.0002] -112F1 ; [.1BB9.0020.0002] -114D1 ; [.1BB9.0020.0002] -11651 ; [.1BB9.0020.0002] -116C1 ; [.1BB9.0020.0002] -11731 ; [.1BB9.0020.0002] -118E1 ; [.1BB9.0020.0002] -12415 ; [.1BB9.0020.0002] -1241E ; [.1BB9.0020.0002] -1242C ; [.1BB9.0020.0002] -12434 ; [.1BB9.0020.0002] -1244F ; [.1BB9.0020.0002] -12458 ; [.1BB9.0020.0002] -16A61 ; [.1BB9.0020.0002] -16B51 ; [.1BB9.0020.0002] -1D360 ; [.1BB9.0020.0002] -1E8C7 ; [.1BB9.0020.0002] -FF11 ; [.1BB9.0020.0003] -0F2A ; [.1BB9.0020.0004] -2474 ; [*0310.0020.0004][.1BB9.0020.0004][*0311.0020.0004] -2488 ; [.1BB9.0020.0004][*0274.0020.0004] -1F102 ; [.1BB9.0020.0004][*0221.0020.0004] -1D7CF ; [.1BB9.0020.0005] -1D7D9 ; [.1BB9.0020.0005] -1D7E3 ; [.1BB9.0020.0005] -1D7ED ; [.1BB9.0020.0005] -1D7F7 ; [.1BB9.0020.0005] -2460 ; [.1BB9.0020.0006] -24F5 ; [.1BB9.0020.0006] -2776 ; [.1BB9.0020.0006] -2780 ; [.1BB9.0020.0006] -278A ; [.1BB9.0020.0006] -00B9 ; [.1BB9.0020.0014] -2081 ; [.1BB9.0020.0015] -215F ; [.1BB9.0020.001E][*0606.0020.001E] -247D ; [*0310.0020.0004][.1BB9.0020.0004][.1BB8.0020.0004][*0311.0020.0004] -2491 ; [.1BB9.0020.0004][.1BB8.0020.0004][*0274.0020.0004] -2469 ; [.1BB9.0020.0006][.1BB8.0020.0006] -24FE ; [.1BB9.0020.0006][.1BB8.0020.0006] -277F ; [.1BB9.0020.0006][.1BB8.0020.0006] -2789 ; [.1BB9.0020.0006][.1BB8.0020.0006] -2793 ; [.1BB9.0020.0006][.1BB8.0020.0006] -3248 ; [.1BB9.0020.0006][.1BB8.0020.0006] -33E9 ; [.1BB9.0020.0004][.1BB8.0020.0004][.FB40.0020.0004][.E5E5.0000.0000] -32C9 ; [.1BB9.0020.0004][.1BB8.0020.0004][.FB40.0020.0004][.E708.0000.0000] -3362 ; [.1BB9.0020.0004][.1BB8.0020.0004][.FB40.0020.0004][.F0B9.0000.0000] -247E ; [*0310.0020.0004][.1BB9.0020.0004][.1BB9.0020.0004][*0311.0020.0004] -2492 ; [.1BB9.0020.0004][.1BB9.0020.0004][*0274.0020.0004] -246A ; [.1BB9.0020.0006][.1BB9.0020.0006] -24EB ; [.1BB9.0020.0006][.1BB9.0020.0006] -2152 ; [.1BB9.0020.001E][*0606.0020.001E][.1BB9.0020.001E][.1BB8.0020.001E] -33EA ; [.1BB9.0020.0004][.1BB9.0020.0004][.FB40.0020.0004][.E5E5.0000.0000] -32CA ; [.1BB9.0020.0004][.1BB9.0020.0004][.FB40.0020.0004][.E708.0000.0000] -3363 ; [.1BB9.0020.0004][.1BB9.0020.0004][.FB40.0020.0004][.F0B9.0000.0000] -247F ; [*0310.0020.0004][.1BB9.0020.0004][.1BBA.0020.0004][*0311.0020.0004] -2493 ; [.1BB9.0020.0004][.1BBA.0020.0004][*0274.0020.0004] -246B ; [.1BB9.0020.0006][.1BBA.0020.0006] -24EC ; [.1BB9.0020.0006][.1BBA.0020.0006] -00BD ; [.1BB9.0020.001E][*0606.0020.001E][.1BBA.0020.001E] -33EB ; [.1BB9.0020.0004][.1BBA.0020.0004][.FB40.0020.0004][.E5E5.0000.0000] -32CB ; [.1BB9.0020.0004][.1BBA.0020.0004][.FB40.0020.0004][.E708.0000.0000] -3364 ; [.1BB9.0020.0004][.1BBA.0020.0004][.FB40.0020.0004][.F0B9.0000.0000] -2480 ; [*0310.0020.0004][.1BB9.0020.0004][.1BBB.0020.0004][*0311.0020.0004] -2494 ; [.1BB9.0020.0004][.1BBB.0020.0004][*0274.0020.0004] -246C ; [.1BB9.0020.0006][.1BBB.0020.0006] -24ED ; [.1BB9.0020.0006][.1BBB.0020.0006] -2153 ; [.1BB9.0020.001E][*0606.0020.001E][.1BBB.0020.001E] -33EC ; [.1BB9.0020.0004][.1BBB.0020.0004][.FB40.0020.0004][.E5E5.0000.0000] -3365 ; [.1BB9.0020.0004][.1BBB.0020.0004][.FB40.0020.0004][.F0B9.0000.0000] -2481 ; [*0310.0020.0004][.1BB9.0020.0004][.1BBC.0020.0004][*0311.0020.0004] -2495 ; [.1BB9.0020.0004][.1BBC.0020.0004][*0274.0020.0004] -246D ; [.1BB9.0020.0006][.1BBC.0020.0006] -24EE ; [.1BB9.0020.0006][.1BBC.0020.0006] -00BC ; [.1BB9.0020.001E][*0606.0020.001E][.1BBC.0020.001E] -33ED ; [.1BB9.0020.0004][.1BBC.0020.0004][.FB40.0020.0004][.E5E5.0000.0000] -3366 ; [.1BB9.0020.0004][.1BBC.0020.0004][.FB40.0020.0004][.F0B9.0000.0000] -2482 ; [*0310.0020.0004][.1BB9.0020.0004][.1BBD.0020.0004][*0311.0020.0004] -2496 ; [.1BB9.0020.0004][.1BBD.0020.0004][*0274.0020.0004] -246E ; [.1BB9.0020.0006][.1BBD.0020.0006] -24EF ; [.1BB9.0020.0006][.1BBD.0020.0006] -2155 ; [.1BB9.0020.001E][*0606.0020.001E][.1BBD.0020.001E] -33EE ; [.1BB9.0020.0004][.1BBD.0020.0004][.FB40.0020.0004][.E5E5.0000.0000] -3367 ; [.1BB9.0020.0004][.1BBD.0020.0004][.FB40.0020.0004][.F0B9.0000.0000] -2483 ; [*0310.0020.0004][.1BB9.0020.0004][.1BBE.0020.0004][*0311.0020.0004] -2497 ; [.1BB9.0020.0004][.1BBE.0020.0004][*0274.0020.0004] -246F ; [.1BB9.0020.0006][.1BBE.0020.0006] -24F0 ; [.1BB9.0020.0006][.1BBE.0020.0006] -2159 ; [.1BB9.0020.001E][*0606.0020.001E][.1BBE.0020.001E] -33EF ; [.1BB9.0020.0004][.1BBE.0020.0004][.FB40.0020.0004][.E5E5.0000.0000] -3368 ; [.1BB9.0020.0004][.1BBE.0020.0004][.FB40.0020.0004][.F0B9.0000.0000] -2484 ; [*0310.0020.0004][.1BB9.0020.0004][.1BBF.0020.0004][*0311.0020.0004] -2498 ; [.1BB9.0020.0004][.1BBF.0020.0004][*0274.0020.0004] -2470 ; [.1BB9.0020.0006][.1BBF.0020.0006] -24F1 ; [.1BB9.0020.0006][.1BBF.0020.0006] -2150 ; [.1BB9.0020.001E][*0606.0020.001E][.1BBF.0020.001E] -33F0 ; [.1BB9.0020.0004][.1BBF.0020.0004][.FB40.0020.0004][.E5E5.0000.0000] -3369 ; [.1BB9.0020.0004][.1BBF.0020.0004][.FB40.0020.0004][.F0B9.0000.0000] -2485 ; [*0310.0020.0004][.1BB9.0020.0004][.1BC0.0020.0004][*0311.0020.0004] -2499 ; [.1BB9.0020.0004][.1BC0.0020.0004][*0274.0020.0004] -2471 ; [.1BB9.0020.0006][.1BC0.0020.0006] -24F2 ; [.1BB9.0020.0006][.1BC0.0020.0006] -215B ; [.1BB9.0020.001E][*0606.0020.001E][.1BC0.0020.001E] -33F1 ; [.1BB9.0020.0004][.1BC0.0020.0004][.FB40.0020.0004][.E5E5.0000.0000] -336A ; [.1BB9.0020.0004][.1BC0.0020.0004][.FB40.0020.0004][.F0B9.0000.0000] -2486 ; [*0310.0020.0004][.1BB9.0020.0004][.1BC1.0020.0004][*0311.0020.0004] -249A ; [.1BB9.0020.0004][.1BC1.0020.0004][*0274.0020.0004] -2472 ; [.1BB9.0020.0006][.1BC1.0020.0006] -24F3 ; [.1BB9.0020.0006][.1BC1.0020.0006] -2151 ; [.1BB9.0020.001E][*0606.0020.001E][.1BC1.0020.001E] -33F2 ; [.1BB9.0020.0004][.1BC1.0020.0004][.FB40.0020.0004][.E5E5.0000.0000] -336B ; [.1BB9.0020.0004][.1BC1.0020.0004][.FB40.0020.0004][.F0B9.0000.0000] -33E0 ; [.1BB9.0020.0004][.FB40.0020.0004][.E5E5.0000.0000] -32C0 ; [.1BB9.0020.0004][.FB40.0020.0004][.E708.0000.0000] -3359 ; [.1BB9.0020.0004][.FB40.0020.0004][.F0B9.0000.0000] -0032 ; [.1BBA.0020.0002] -0662 ; [.1BBA.0020.0002] -06F2 ; [.1BBA.0020.0002] -07C2 ; [.1BBA.0020.0002] -0968 ; [.1BBA.0020.0002] -09E8 ; [.1BBA.0020.0002] -0A68 ; [.1BBA.0020.0002] -0AE8 ; [.1BBA.0020.0002] -0B68 ; [.1BBA.0020.0002] -0BE8 ; [.1BBA.0020.0002] -0C68 ; [.1BBA.0020.0002] -0C7A ; [.1BBA.0020.0002] -0C7D ; [.1BBA.0020.0002] -0CE8 ; [.1BBA.0020.0002] -0D68 ; [.1BBA.0020.0002] -0DE8 ; [.1BBA.0020.0002] -0E52 ; [.1BBA.0020.0002] -0ED2 ; [.1BBA.0020.0002] -0F22 ; [.1BBA.0020.0002] -1042 ; [.1BBA.0020.0002] -1092 ; [.1BBA.0020.0002] -136A ; [.1BBA.0020.0002] -17E2 ; [.1BBA.0020.0002] -17F2 ; [.1BBA.0020.0002] -1812 ; [.1BBA.0020.0002] -1948 ; [.1BBA.0020.0002] -19D2 ; [.1BBA.0020.0002] -1A82 ; [.1BBA.0020.0002] -1A92 ; [.1BBA.0020.0002] -1B52 ; [.1BBA.0020.0002] -1BB2 ; [.1BBA.0020.0002] -1C42 ; [.1BBA.0020.0002] -1C52 ; [.1BBA.0020.0002] -3022 ; [.1BBA.0020.0002] -A622 ; [.1BBA.0020.0002] -A8D2 ; [.1BBA.0020.0002] -A902 ; [.1BBA.0020.0002] -A9D2 ; [.1BBA.0020.0002] -A9F2 ; [.1BBA.0020.0002] -AA52 ; [.1BBA.0020.0002] -ABF2 ; [.1BBA.0020.0002] -10108 ; [.1BBA.0020.0002] -1015B ; [.1BBA.0020.0002] -1015C ; [.1BBA.0020.0002] -1015D ; [.1BBA.0020.0002] -1015E ; [.1BBA.0020.0002] -102E2 ; [.1BBA.0020.0002] -103D2 ; [.1BBA.0020.0002] -104A2 ; [.1BBA.0020.0002] -10859 ; [.1BBA.0020.0002] -1087A ; [.1BBA.0020.0002] -108A8 ; [.1BBA.0020.0002] -1091A ; [.1BBA.0020.0002] -109C1 ; [.1BBA.0020.0002] -10A41 ; [.1BBA.0020.0002] -10B59 ; [.1BBA.0020.0002] -10B79 ; [.1BBA.0020.0002] -10BAA ; [.1BBA.0020.0002] -10E61 ; [.1BBA.0020.0002] -11053 ; [.1BBA.0020.0002] -11068 ; [.1BBA.0020.0002] -110F2 ; [.1BBA.0020.0002] -11138 ; [.1BBA.0020.0002] -111D2 ; [.1BBA.0020.0002] -111E2 ; [.1BBA.0020.0002] -112F2 ; [.1BBA.0020.0002] -114D2 ; [.1BBA.0020.0002] -11652 ; [.1BBA.0020.0002] -116C2 ; [.1BBA.0020.0002] -11732 ; [.1BBA.0020.0002] -118E2 ; [.1BBA.0020.0002] -12400 ; [.1BBA.0020.0002] -12416 ; [.1BBA.0020.0002] -1241F ; [.1BBA.0020.0002] -12423 ; [.1BBA.0020.0002] -1242D ; [.1BBA.0020.0002] -12435 ; [.1BBA.0020.0002] -1244A ; [.1BBA.0020.0002] -12450 ; [.1BBA.0020.0002] -12456 ; [.1BBA.0020.0002] -12459 ; [.1BBA.0020.0002] -16A62 ; [.1BBA.0020.0002] -16B52 ; [.1BBA.0020.0002] -1D361 ; [.1BBA.0020.0002] -1E8C8 ; [.1BBA.0020.0002] -FF12 ; [.1BBA.0020.0003] -0F2B ; [.1BBA.0020.0004] -2475 ; [*0310.0020.0004][.1BBA.0020.0004][*0311.0020.0004] -2489 ; [.1BBA.0020.0004][*0274.0020.0004] -1F103 ; [.1BBA.0020.0004][*0221.0020.0004] -1D7D0 ; [.1BBA.0020.0005] -1D7DA ; [.1BBA.0020.0005] -1D7E4 ; [.1BBA.0020.0005] -1D7EE ; [.1BBA.0020.0005] -1D7F8 ; [.1BBA.0020.0005] -2461 ; [.1BBA.0020.0006] -24F6 ; [.1BBA.0020.0006] -2777 ; [.1BBA.0020.0006] -2781 ; [.1BBA.0020.0006] -278B ; [.1BBA.0020.0006] -00B2 ; [.1BBA.0020.0014] -2082 ; [.1BBA.0020.0015] -2487 ; [*0310.0020.0004][.1BBA.0020.0004][.1BB8.0020.0004][*0311.0020.0004] -249B ; [.1BBA.0020.0004][.1BB8.0020.0004][*0274.0020.0004] -2473 ; [.1BBA.0020.0006][.1BB8.0020.0006] -24F4 ; [.1BBA.0020.0006][.1BB8.0020.0006] -3249 ; [.1BBA.0020.0006][.1BB8.0020.0006] -33F3 ; [.1BBA.0020.0004][.1BB8.0020.0004][.FB40.0020.0004][.E5E5.0000.0000] -336C ; [.1BBA.0020.0004][.1BB8.0020.0004][.FB40.0020.0004][.F0B9.0000.0000] -3251 ; [.1BBA.0020.0006][.1BB9.0020.0006] -33F4 ; [.1BBA.0020.0004][.1BB9.0020.0004][.FB40.0020.0004][.E5E5.0000.0000] -336D ; [.1BBA.0020.0004][.1BB9.0020.0004][.FB40.0020.0004][.F0B9.0000.0000] -3252 ; [.1BBA.0020.0006][.1BBA.0020.0006] -33F5 ; [.1BBA.0020.0004][.1BBA.0020.0004][.FB40.0020.0004][.E5E5.0000.0000] -336E ; [.1BBA.0020.0004][.1BBA.0020.0004][.FB40.0020.0004][.F0B9.0000.0000] -3253 ; [.1BBA.0020.0006][.1BBB.0020.0006] -2154 ; [.1BBA.0020.001E][*0606.0020.001E][.1BBB.0020.001E] -33F6 ; [.1BBA.0020.0004][.1BBB.0020.0004][.FB40.0020.0004][.E5E5.0000.0000] -336F ; [.1BBA.0020.0004][.1BBB.0020.0004][.FB40.0020.0004][.F0B9.0000.0000] -3254 ; [.1BBA.0020.0006][.1BBC.0020.0006] -33F7 ; [.1BBA.0020.0004][.1BBC.0020.0004][.FB40.0020.0004][.E5E5.0000.0000] -3370 ; [.1BBA.0020.0004][.1BBC.0020.0004][.FB40.0020.0004][.F0B9.0000.0000] -3255 ; [.1BBA.0020.0006][.1BBD.0020.0006] -2156 ; [.1BBA.0020.001E][*0606.0020.001E][.1BBD.0020.001E] -33F8 ; [.1BBA.0020.0004][.1BBD.0020.0004][.FB40.0020.0004][.E5E5.0000.0000] -3256 ; [.1BBA.0020.0006][.1BBE.0020.0006] -33F9 ; [.1BBA.0020.0004][.1BBE.0020.0004][.FB40.0020.0004][.E5E5.0000.0000] -3257 ; [.1BBA.0020.0006][.1BBF.0020.0006] -33FA ; [.1BBA.0020.0004][.1BBF.0020.0004][.FB40.0020.0004][.E5E5.0000.0000] -3258 ; [.1BBA.0020.0006][.1BC0.0020.0006] -33FB ; [.1BBA.0020.0004][.1BC0.0020.0004][.FB40.0020.0004][.E5E5.0000.0000] -3259 ; [.1BBA.0020.0006][.1BC1.0020.0006] -33FC ; [.1BBA.0020.0004][.1BC1.0020.0004][.FB40.0020.0004][.E5E5.0000.0000] -33E1 ; [.1BBA.0020.0004][.FB40.0020.0004][.E5E5.0000.0000] -32C1 ; [.1BBA.0020.0004][.FB40.0020.0004][.E708.0000.0000] -335A ; [.1BBA.0020.0004][.FB40.0020.0004][.F0B9.0000.0000] -0033 ; [.1BBB.0020.0002] -0663 ; [.1BBB.0020.0002] -06F3 ; [.1BBB.0020.0002] -07C3 ; [.1BBB.0020.0002] -0969 ; [.1BBB.0020.0002] -09E9 ; [.1BBB.0020.0002] -0A69 ; [.1BBB.0020.0002] -0AE9 ; [.1BBB.0020.0002] -0B69 ; [.1BBB.0020.0002] -0BE9 ; [.1BBB.0020.0002] -0C69 ; [.1BBB.0020.0002] -0C7B ; [.1BBB.0020.0002] -0C7E ; [.1BBB.0020.0002] -0CE9 ; [.1BBB.0020.0002] -0D69 ; [.1BBB.0020.0002] -0DE9 ; [.1BBB.0020.0002] -0E53 ; [.1BBB.0020.0002] -0ED3 ; [.1BBB.0020.0002] -0F23 ; [.1BBB.0020.0002] -1043 ; [.1BBB.0020.0002] -1093 ; [.1BBB.0020.0002] -136B ; [.1BBB.0020.0002] -17E3 ; [.1BBB.0020.0002] -17F3 ; [.1BBB.0020.0002] -1813 ; [.1BBB.0020.0002] -1949 ; [.1BBB.0020.0002] -19D3 ; [.1BBB.0020.0002] -1A83 ; [.1BBB.0020.0002] -1A93 ; [.1BBB.0020.0002] -1B53 ; [.1BBB.0020.0002] -1BB3 ; [.1BBB.0020.0002] -1C43 ; [.1BBB.0020.0002] -1C53 ; [.1BBB.0020.0002] -3023 ; [.1BBB.0020.0002] -A623 ; [.1BBB.0020.0002] -A8D3 ; [.1BBB.0020.0002] -A903 ; [.1BBB.0020.0002] -A9D3 ; [.1BBB.0020.0002] -A9F3 ; [.1BBB.0020.0002] -AA53 ; [.1BBB.0020.0002] -ABF3 ; [.1BBB.0020.0002] -10109 ; [.1BBB.0020.0002] -102E3 ; [.1BBB.0020.0002] -104A3 ; [.1BBB.0020.0002] -1085A ; [.1BBB.0020.0002] -1087B ; [.1BBB.0020.0002] -108A9 ; [.1BBB.0020.0002] -1091B ; [.1BBB.0020.0002] -109C2 ; [.1BBB.0020.0002] -10A42 ; [.1BBB.0020.0002] -10B5A ; [.1BBB.0020.0002] -10B7A ; [.1BBB.0020.0002] -10BAB ; [.1BBB.0020.0002] -10E62 ; [.1BBB.0020.0002] -11054 ; [.1BBB.0020.0002] -11069 ; [.1BBB.0020.0002] -110F3 ; [.1BBB.0020.0002] -11139 ; [.1BBB.0020.0002] -111D3 ; [.1BBB.0020.0002] -111E3 ; [.1BBB.0020.0002] -112F3 ; [.1BBB.0020.0002] -114D3 ; [.1BBB.0020.0002] -11653 ; [.1BBB.0020.0002] -116C3 ; [.1BBB.0020.0002] -11733 ; [.1BBB.0020.0002] -118E3 ; [.1BBB.0020.0002] -12401 ; [.1BBB.0020.0002] -12408 ; [.1BBB.0020.0002] -12417 ; [.1BBB.0020.0002] -12420 ; [.1BBB.0020.0002] -12424 ; [.1BBB.0020.0002] -12425 ; [.1BBB.0020.0002] -1242E ; [.1BBB.0020.0002] -1242F ; [.1BBB.0020.0002] -12436 ; [.1BBB.0020.0002] -12437 ; [.1BBB.0020.0002] -1243A ; [.1BBB.0020.0002] -1243B ; [.1BBB.0020.0002] -1244B ; [.1BBB.0020.0002] -12451 ; [.1BBB.0020.0002] -12457 ; [.1BBB.0020.0002] -16A63 ; [.1BBB.0020.0002] -16B53 ; [.1BBB.0020.0002] -1D362 ; [.1BBB.0020.0002] -1E8C9 ; [.1BBB.0020.0002] -FF13 ; [.1BBB.0020.0003] -0F2C ; [.1BBB.0020.0004] -2476 ; [*0310.0020.0004][.1BBB.0020.0004][*0311.0020.0004] -248A ; [.1BBB.0020.0004][*0274.0020.0004] -1F104 ; [.1BBB.0020.0004][*0221.0020.0004] -1D7D1 ; [.1BBB.0020.0005] -1D7DB ; [.1BBB.0020.0005] -1D7E5 ; [.1BBB.0020.0005] -1D7EF ; [.1BBB.0020.0005] -1D7F9 ; [.1BBB.0020.0005] -2462 ; [.1BBB.0020.0006] -24F7 ; [.1BBB.0020.0006] -2778 ; [.1BBB.0020.0006] -2782 ; [.1BBB.0020.0006] -278C ; [.1BBB.0020.0006] -00B3 ; [.1BBB.0020.0014] -2083 ; [.1BBB.0020.0015] -324A ; [.1BBB.0020.0006][.1BB8.0020.0006] -325A ; [.1BBB.0020.0006][.1BB8.0020.0006] -33FD ; [.1BBB.0020.0004][.1BB8.0020.0004][.FB40.0020.0004][.E5E5.0000.0000] -325B ; [.1BBB.0020.0006][.1BB9.0020.0006] -33FE ; [.1BBB.0020.0004][.1BB9.0020.0004][.FB40.0020.0004][.E5E5.0000.0000] -325C ; [.1BBB.0020.0006][.1BBA.0020.0006] -325D ; [.1BBB.0020.0006][.1BBB.0020.0006] -325E ; [.1BBB.0020.0006][.1BBC.0020.0006] -00BE ; [.1BBB.0020.001E][*0606.0020.001E][.1BBC.0020.001E] -325F ; [.1BBB.0020.0006][.1BBD.0020.0006] -2157 ; [.1BBB.0020.001E][*0606.0020.001E][.1BBD.0020.001E] -32B1 ; [.1BBB.0020.0006][.1BBE.0020.0006] -32B2 ; [.1BBB.0020.0006][.1BBF.0020.0006] -32B3 ; [.1BBB.0020.0006][.1BC0.0020.0006] -215C ; [.1BBB.0020.001E][*0606.0020.001E][.1BC0.0020.001E] -32B4 ; [.1BBB.0020.0006][.1BC1.0020.0006] -33E2 ; [.1BBB.0020.0004][.FB40.0020.0004][.E5E5.0000.0000] -32C2 ; [.1BBB.0020.0004][.FB40.0020.0004][.E708.0000.0000] -335B ; [.1BBB.0020.0004][.FB40.0020.0004][.F0B9.0000.0000] -0034 ; [.1BBC.0020.0002] -0664 ; [.1BBC.0020.0002] -06F4 ; [.1BBC.0020.0002] -07C4 ; [.1BBC.0020.0002] -096A ; [.1BBC.0020.0002] -09EA ; [.1BBC.0020.0002] -0A6A ; [.1BBC.0020.0002] -0AEA ; [.1BBC.0020.0002] -0B6A ; [.1BBC.0020.0002] -0BEA ; [.1BBC.0020.0002] -0C6A ; [.1BBC.0020.0002] -0CEA ; [.1BBC.0020.0002] -0D6A ; [.1BBC.0020.0002] -0DEA ; [.1BBC.0020.0002] -0E54 ; [.1BBC.0020.0002] -0ED4 ; [.1BBC.0020.0002] -0F24 ; [.1BBC.0020.0002] -1044 ; [.1BBC.0020.0002] -1094 ; [.1BBC.0020.0002] -136C ; [.1BBC.0020.0002] -17E4 ; [.1BBC.0020.0002] -17F4 ; [.1BBC.0020.0002] -1814 ; [.1BBC.0020.0002] -194A ; [.1BBC.0020.0002] -19D4 ; [.1BBC.0020.0002] -1A84 ; [.1BBC.0020.0002] -1A94 ; [.1BBC.0020.0002] -1B54 ; [.1BBC.0020.0002] -1BB4 ; [.1BBC.0020.0002] -1C44 ; [.1BBC.0020.0002] -1C54 ; [.1BBC.0020.0002] -3024 ; [.1BBC.0020.0002] -A624 ; [.1BBC.0020.0002] -A8D4 ; [.1BBC.0020.0002] -A904 ; [.1BBC.0020.0002] -A9D4 ; [.1BBC.0020.0002] -A9F4 ; [.1BBC.0020.0002] -AA54 ; [.1BBC.0020.0002] -ABF4 ; [.1BBC.0020.0002] -1010A ; [.1BBC.0020.0002] -102E4 ; [.1BBC.0020.0002] -104A4 ; [.1BBC.0020.0002] -1087C ; [.1BBC.0020.0002] -108AA ; [.1BBC.0020.0002] -108AB ; [.1BBC.0020.0002] -109C3 ; [.1BBC.0020.0002] -10A43 ; [.1BBC.0020.0002] -10B5B ; [.1BBC.0020.0002] -10B7B ; [.1BBC.0020.0002] -10BAC ; [.1BBC.0020.0002] -10E63 ; [.1BBC.0020.0002] -11055 ; [.1BBC.0020.0002] -1106A ; [.1BBC.0020.0002] -110F4 ; [.1BBC.0020.0002] -1113A ; [.1BBC.0020.0002] -111D4 ; [.1BBC.0020.0002] -111E4 ; [.1BBC.0020.0002] -112F4 ; [.1BBC.0020.0002] -114D4 ; [.1BBC.0020.0002] -11654 ; [.1BBC.0020.0002] -116C4 ; [.1BBC.0020.0002] -11734 ; [.1BBC.0020.0002] -118E4 ; [.1BBC.0020.0002] -12402 ; [.1BBC.0020.0002] -12409 ; [.1BBC.0020.0002] -1240F ; [.1BBC.0020.0002] -12418 ; [.1BBC.0020.0002] -12421 ; [.1BBC.0020.0002] -12426 ; [.1BBC.0020.0002] -12430 ; [.1BBC.0020.0002] -12438 ; [.1BBC.0020.0002] -1243C ; [.1BBC.0020.0002] -1243D ; [.1BBC.0020.0002] -1243E ; [.1BBC.0020.0002] -1243F ; [.1BBC.0020.0002] -1244C ; [.1BBC.0020.0002] -12452 ; [.1BBC.0020.0002] -12453 ; [.1BBC.0020.0002] -12469 ; [.1BBC.0020.0002] -16A64 ; [.1BBC.0020.0002] -16B54 ; [.1BBC.0020.0002] -1D363 ; [.1BBC.0020.0002] -1E8CA ; [.1BBC.0020.0002] -FF14 ; [.1BBC.0020.0003] -0F2D ; [.1BBC.0020.0004] -2477 ; [*0310.0020.0004][.1BBC.0020.0004][*0311.0020.0004] -248B ; [.1BBC.0020.0004][*0274.0020.0004] -1F105 ; [.1BBC.0020.0004][*0221.0020.0004] -1D7D2 ; [.1BBC.0020.0005] -1D7DC ; [.1BBC.0020.0005] -1D7E6 ; [.1BBC.0020.0005] -1D7F0 ; [.1BBC.0020.0005] -1D7FA ; [.1BBC.0020.0005] -2463 ; [.1BBC.0020.0006] -24F8 ; [.1BBC.0020.0006] -2779 ; [.1BBC.0020.0006] -2783 ; [.1BBC.0020.0006] -278D ; [.1BBC.0020.0006] -2074 ; [.1BBC.0020.0014] -2084 ; [.1BBC.0020.0015] -324B ; [.1BBC.0020.0006][.1BB8.0020.0006] -32B5 ; [.1BBC.0020.0006][.1BB8.0020.0006] -32B6 ; [.1BBC.0020.0006][.1BB9.0020.0006] -32B7 ; [.1BBC.0020.0006][.1BBA.0020.0006] -32B8 ; [.1BBC.0020.0006][.1BBB.0020.0006] -32B9 ; [.1BBC.0020.0006][.1BBC.0020.0006] -32BA ; [.1BBC.0020.0006][.1BBD.0020.0006] -2158 ; [.1BBC.0020.001E][*0606.0020.001E][.1BBD.0020.001E] -32BB ; [.1BBC.0020.0006][.1BBE.0020.0006] -32BC ; [.1BBC.0020.0006][.1BBF.0020.0006] -32BD ; [.1BBC.0020.0006][.1BC0.0020.0006] -32BE ; [.1BBC.0020.0006][.1BC1.0020.0006] -33E3 ; [.1BBC.0020.0004][.FB40.0020.0004][.E5E5.0000.0000] -32C3 ; [.1BBC.0020.0004][.FB40.0020.0004][.E708.0000.0000] -335C ; [.1BBC.0020.0004][.FB40.0020.0004][.F0B9.0000.0000] -0035 ; [.1BBD.0020.0002] -0665 ; [.1BBD.0020.0002] -06F5 ; [.1BBD.0020.0002] -07C5 ; [.1BBD.0020.0002] -096B ; [.1BBD.0020.0002] -09EB ; [.1BBD.0020.0002] -0A6B ; [.1BBD.0020.0002] -0AEB ; [.1BBD.0020.0002] -0B6B ; [.1BBD.0020.0002] -0BEB ; [.1BBD.0020.0002] -0C6B ; [.1BBD.0020.0002] -0CEB ; [.1BBD.0020.0002] -0D6B ; [.1BBD.0020.0002] -0DEB ; [.1BBD.0020.0002] -0E55 ; [.1BBD.0020.0002] -0ED5 ; [.1BBD.0020.0002] -0F25 ; [.1BBD.0020.0002] -1045 ; [.1BBD.0020.0002] -1095 ; [.1BBD.0020.0002] -136D ; [.1BBD.0020.0002] -17E5 ; [.1BBD.0020.0002] -17F5 ; [.1BBD.0020.0002] -1815 ; [.1BBD.0020.0002] -194B ; [.1BBD.0020.0002] -19D5 ; [.1BBD.0020.0002] -1A85 ; [.1BBD.0020.0002] -1A95 ; [.1BBD.0020.0002] -1B55 ; [.1BBD.0020.0002] -1BB5 ; [.1BBD.0020.0002] -1C45 ; [.1BBD.0020.0002] -1C55 ; [.1BBD.0020.0002] -3025 ; [.1BBD.0020.0002] -A625 ; [.1BBD.0020.0002] -A8D5 ; [.1BBD.0020.0002] -A905 ; [.1BBD.0020.0002] -A9D5 ; [.1BBD.0020.0002] -A9F5 ; [.1BBD.0020.0002] -AA55 ; [.1BBD.0020.0002] -ABF5 ; [.1BBD.0020.0002] -1010B ; [.1BBD.0020.0002] -10143 ; [.1BBD.0020.0002] -10148 ; [.1BBD.0020.0002] -1014F ; [.1BBD.0020.0002] -1015F ; [.1BBD.0020.0002] -10173 ; [.1BBD.0020.0002] -102E5 ; [.1BBD.0020.0002] -10321 ; [.1BBD.0020.0002] -104A5 ; [.1BBD.0020.0002] -1087D ; [.1BBD.0020.0002] -108AC ; [.1BBD.0020.0002] -108FC ; [.1BBD.0020.0002] -109C4 ; [.1BBD.0020.0002] -10AEC ; [.1BBD.0020.0002] -10CFB ; [.1BBD.0020.0002] -10E64 ; [.1BBD.0020.0002] -11056 ; [.1BBD.0020.0002] -1106B ; [.1BBD.0020.0002] -110F5 ; [.1BBD.0020.0002] -1113B ; [.1BBD.0020.0002] -111D5 ; [.1BBD.0020.0002] -111E5 ; [.1BBD.0020.0002] -112F5 ; [.1BBD.0020.0002] -114D5 ; [.1BBD.0020.0002] -11655 ; [.1BBD.0020.0002] -116C5 ; [.1BBD.0020.0002] -11735 ; [.1BBD.0020.0002] -118E5 ; [.1BBD.0020.0002] -12403 ; [.1BBD.0020.0002] -1240A ; [.1BBD.0020.0002] -12410 ; [.1BBD.0020.0002] -12419 ; [.1BBD.0020.0002] -12422 ; [.1BBD.0020.0002] -12427 ; [.1BBD.0020.0002] -12431 ; [.1BBD.0020.0002] -12439 ; [.1BBD.0020.0002] -1244D ; [.1BBD.0020.0002] -12454 ; [.1BBD.0020.0002] -12455 ; [.1BBD.0020.0002] -1246A ; [.1BBD.0020.0002] -16A65 ; [.1BBD.0020.0002] -16B55 ; [.1BBD.0020.0002] -1D364 ; [.1BBD.0020.0002] -1E8CB ; [.1BBD.0020.0002] -FF15 ; [.1BBD.0020.0003] -0F2E ; [.1BBD.0020.0004] -2478 ; [*0310.0020.0004][.1BBD.0020.0004][*0311.0020.0004] -248C ; [.1BBD.0020.0004][*0274.0020.0004] -1F106 ; [.1BBD.0020.0004][*0221.0020.0004] -1D7D3 ; [.1BBD.0020.0005] -1D7DD ; [.1BBD.0020.0005] -1D7E7 ; [.1BBD.0020.0005] -1D7F1 ; [.1BBD.0020.0005] -1D7FB ; [.1BBD.0020.0005] -2464 ; [.1BBD.0020.0006] -24F9 ; [.1BBD.0020.0006] -277A ; [.1BBD.0020.0006] -2784 ; [.1BBD.0020.0006] -278E ; [.1BBD.0020.0006] -2075 ; [.1BBD.0020.0014] -2085 ; [.1BBD.0020.0015] -324C ; [.1BBD.0020.0006][.1BB8.0020.0006] -32BF ; [.1BBD.0020.0006][.1BB8.0020.0006] -215A ; [.1BBD.0020.001E][*0606.0020.001E][.1BBE.0020.001E] -215D ; [.1BBD.0020.001E][*0606.0020.001E][.1BC0.0020.001E] -33E4 ; [.1BBD.0020.0004][.FB40.0020.0004][.E5E5.0000.0000] -32C4 ; [.1BBD.0020.0004][.FB40.0020.0004][.E708.0000.0000] -335D ; [.1BBD.0020.0004][.FB40.0020.0004][.F0B9.0000.0000] -0036 ; [.1BBE.0020.0002] -0666 ; [.1BBE.0020.0002] -06F6 ; [.1BBE.0020.0002] -07C6 ; [.1BBE.0020.0002] -096C ; [.1BBE.0020.0002] -09EC ; [.1BBE.0020.0002] -0A6C ; [.1BBE.0020.0002] -0AEC ; [.1BBE.0020.0002] -0B6C ; [.1BBE.0020.0002] -0BEC ; [.1BBE.0020.0002] -0C6C ; [.1BBE.0020.0002] -0CEC ; [.1BBE.0020.0002] -0D6C ; [.1BBE.0020.0002] -0DEC ; [.1BBE.0020.0002] -0E56 ; [.1BBE.0020.0002] -0ED6 ; [.1BBE.0020.0002] -0F26 ; [.1BBE.0020.0002] -1046 ; [.1BBE.0020.0002] -1096 ; [.1BBE.0020.0002] -136E ; [.1BBE.0020.0002] -17E6 ; [.1BBE.0020.0002] -17F6 ; [.1BBE.0020.0002] -1816 ; [.1BBE.0020.0002] -194C ; [.1BBE.0020.0002] -19D6 ; [.1BBE.0020.0002] -1A86 ; [.1BBE.0020.0002] -1A96 ; [.1BBE.0020.0002] -1B56 ; [.1BBE.0020.0002] -1BB6 ; [.1BBE.0020.0002] -1C46 ; [.1BBE.0020.0002] -1C56 ; [.1BBE.0020.0002] -2185 ; [.1BBE.0020.0002] -3026 ; [.1BBE.0020.0002] -A626 ; [.1BBE.0020.0002] -A8D6 ; [.1BBE.0020.0002] -A906 ; [.1BBE.0020.0002] -A9D6 ; [.1BBE.0020.0002] -A9F6 ; [.1BBE.0020.0002] -AA56 ; [.1BBE.0020.0002] -ABF6 ; [.1BBE.0020.0002] -1010C ; [.1BBE.0020.0002] -102E6 ; [.1BBE.0020.0002] -104A6 ; [.1BBE.0020.0002] -109C5 ; [.1BBE.0020.0002] -10E65 ; [.1BBE.0020.0002] -11057 ; [.1BBE.0020.0002] -1106C ; [.1BBE.0020.0002] -110F6 ; [.1BBE.0020.0002] -1113C ; [.1BBE.0020.0002] -111D6 ; [.1BBE.0020.0002] -111E6 ; [.1BBE.0020.0002] -112F6 ; [.1BBE.0020.0002] -114D6 ; [.1BBE.0020.0002] -11656 ; [.1BBE.0020.0002] -116C6 ; [.1BBE.0020.0002] -11736 ; [.1BBE.0020.0002] -118E6 ; [.1BBE.0020.0002] -12404 ; [.1BBE.0020.0002] -1240B ; [.1BBE.0020.0002] -12411 ; [.1BBE.0020.0002] -1241A ; [.1BBE.0020.0002] -12428 ; [.1BBE.0020.0002] -12440 ; [.1BBE.0020.0002] -1244E ; [.1BBE.0020.0002] -1246B ; [.1BBE.0020.0002] -16A66 ; [.1BBE.0020.0002] -16B56 ; [.1BBE.0020.0002] -1D365 ; [.1BBE.0020.0002] -1E8CC ; [.1BBE.0020.0002] -FF16 ; [.1BBE.0020.0003] -0F2F ; [.1BBE.0020.0004] -2479 ; [*0310.0020.0004][.1BBE.0020.0004][*0311.0020.0004] -248D ; [.1BBE.0020.0004][*0274.0020.0004] -1F107 ; [.1BBE.0020.0004][*0221.0020.0004] -1D7D4 ; [.1BBE.0020.0005] -1D7DE ; [.1BBE.0020.0005] -1D7E8 ; [.1BBE.0020.0005] -1D7F2 ; [.1BBE.0020.0005] -1D7FC ; [.1BBE.0020.0005] -2465 ; [.1BBE.0020.0006] -24FA ; [.1BBE.0020.0006] -277B ; [.1BBE.0020.0006] -2785 ; [.1BBE.0020.0006] -278F ; [.1BBE.0020.0006] -2076 ; [.1BBE.0020.0014] -2086 ; [.1BBE.0020.0015] -324D ; [.1BBE.0020.0006][.1BB8.0020.0006] -33E5 ; [.1BBE.0020.0004][.FB40.0020.0004][.E5E5.0000.0000] -32C5 ; [.1BBE.0020.0004][.FB40.0020.0004][.E708.0000.0000] -335E ; [.1BBE.0020.0004][.FB40.0020.0004][.F0B9.0000.0000] -0037 ; [.1BBF.0020.0002] -0667 ; [.1BBF.0020.0002] -06F7 ; [.1BBF.0020.0002] -07C7 ; [.1BBF.0020.0002] -096D ; [.1BBF.0020.0002] -09ED ; [.1BBF.0020.0002] -0A6D ; [.1BBF.0020.0002] -0AED ; [.1BBF.0020.0002] -0B6D ; [.1BBF.0020.0002] -0BED ; [.1BBF.0020.0002] -0C6D ; [.1BBF.0020.0002] -0CED ; [.1BBF.0020.0002] -0D6D ; [.1BBF.0020.0002] -0DED ; [.1BBF.0020.0002] -0E57 ; [.1BBF.0020.0002] -0ED7 ; [.1BBF.0020.0002] -0F27 ; [.1BBF.0020.0002] -1047 ; [.1BBF.0020.0002] -1097 ; [.1BBF.0020.0002] -136F ; [.1BBF.0020.0002] -17E7 ; [.1BBF.0020.0002] -17F7 ; [.1BBF.0020.0002] -1817 ; [.1BBF.0020.0002] -194D ; [.1BBF.0020.0002] -19D7 ; [.1BBF.0020.0002] -1A87 ; [.1BBF.0020.0002] -1A97 ; [.1BBF.0020.0002] -1B57 ; [.1BBF.0020.0002] -1BB7 ; [.1BBF.0020.0002] -1C47 ; [.1BBF.0020.0002] -1C57 ; [.1BBF.0020.0002] -3027 ; [.1BBF.0020.0002] -A627 ; [.1BBF.0020.0002] -A8D7 ; [.1BBF.0020.0002] -A907 ; [.1BBF.0020.0002] -A9D7 ; [.1BBF.0020.0002] -A9F7 ; [.1BBF.0020.0002] -AA57 ; [.1BBF.0020.0002] -ABF7 ; [.1BBF.0020.0002] -1010D ; [.1BBF.0020.0002] -102E7 ; [.1BBF.0020.0002] -104A7 ; [.1BBF.0020.0002] -109C6 ; [.1BBF.0020.0002] -10E66 ; [.1BBF.0020.0002] -11058 ; [.1BBF.0020.0002] -1106D ; [.1BBF.0020.0002] -110F7 ; [.1BBF.0020.0002] -1113D ; [.1BBF.0020.0002] -111D7 ; [.1BBF.0020.0002] -111E7 ; [.1BBF.0020.0002] -112F7 ; [.1BBF.0020.0002] -114D7 ; [.1BBF.0020.0002] -11657 ; [.1BBF.0020.0002] -116C7 ; [.1BBF.0020.0002] -11737 ; [.1BBF.0020.0002] -118E7 ; [.1BBF.0020.0002] -12405 ; [.1BBF.0020.0002] -1240C ; [.1BBF.0020.0002] -12412 ; [.1BBF.0020.0002] -1241B ; [.1BBF.0020.0002] -12429 ; [.1BBF.0020.0002] -12441 ; [.1BBF.0020.0002] -12442 ; [.1BBF.0020.0002] -12443 ; [.1BBF.0020.0002] -1246C ; [.1BBF.0020.0002] -16A67 ; [.1BBF.0020.0002] -16B57 ; [.1BBF.0020.0002] -1D366 ; [.1BBF.0020.0002] -1E8CD ; [.1BBF.0020.0002] -FF17 ; [.1BBF.0020.0003] -0F30 ; [.1BBF.0020.0004] -247A ; [*0310.0020.0004][.1BBF.0020.0004][*0311.0020.0004] -248E ; [.1BBF.0020.0004][*0274.0020.0004] -1F108 ; [.1BBF.0020.0004][*0221.0020.0004] -1D7D5 ; [.1BBF.0020.0005] -1D7DF ; [.1BBF.0020.0005] -1D7E9 ; [.1BBF.0020.0005] -1D7F3 ; [.1BBF.0020.0005] -1D7FD ; [.1BBF.0020.0005] -2466 ; [.1BBF.0020.0006] -24FB ; [.1BBF.0020.0006] -277C ; [.1BBF.0020.0006] -2786 ; [.1BBF.0020.0006] -2790 ; [.1BBF.0020.0006] -2077 ; [.1BBF.0020.0014] -2087 ; [.1BBF.0020.0015] -324E ; [.1BBF.0020.0006][.1BB8.0020.0006] -215E ; [.1BBF.0020.001E][*0606.0020.001E][.1BC0.0020.001E] -33E6 ; [.1BBF.0020.0004][.FB40.0020.0004][.E5E5.0000.0000] -32C6 ; [.1BBF.0020.0004][.FB40.0020.0004][.E708.0000.0000] -335F ; [.1BBF.0020.0004][.FB40.0020.0004][.F0B9.0000.0000] -0038 ; [.1BC0.0020.0002] -0668 ; [.1BC0.0020.0002] -06F8 ; [.1BC0.0020.0002] -07C8 ; [.1BC0.0020.0002] -096E ; [.1BC0.0020.0002] -09EE ; [.1BC0.0020.0002] -0A6E ; [.1BC0.0020.0002] -0AEE ; [.1BC0.0020.0002] -0B6E ; [.1BC0.0020.0002] -0BEE ; [.1BC0.0020.0002] -0C6E ; [.1BC0.0020.0002] -0CEE ; [.1BC0.0020.0002] -0D6E ; [.1BC0.0020.0002] -0DEE ; [.1BC0.0020.0002] -0E58 ; [.1BC0.0020.0002] -0ED8 ; [.1BC0.0020.0002] -0F28 ; [.1BC0.0020.0002] -1048 ; [.1BC0.0020.0002] -1098 ; [.1BC0.0020.0002] -1370 ; [.1BC0.0020.0002] -17E8 ; [.1BC0.0020.0002] -17F8 ; [.1BC0.0020.0002] -1818 ; [.1BC0.0020.0002] -194E ; [.1BC0.0020.0002] -19D8 ; [.1BC0.0020.0002] -1A88 ; [.1BC0.0020.0002] -1A98 ; [.1BC0.0020.0002] -1B58 ; [.1BC0.0020.0002] -1BB8 ; [.1BC0.0020.0002] -1C48 ; [.1BC0.0020.0002] -1C58 ; [.1BC0.0020.0002] -3028 ; [.1BC0.0020.0002] -A628 ; [.1BC0.0020.0002] -A8D8 ; [.1BC0.0020.0002] -A908 ; [.1BC0.0020.0002] -A9D8 ; [.1BC0.0020.0002] -A9F8 ; [.1BC0.0020.0002] -AA58 ; [.1BC0.0020.0002] -ABF8 ; [.1BC0.0020.0002] -1010E ; [.1BC0.0020.0002] -102E8 ; [.1BC0.0020.0002] -104A8 ; [.1BC0.0020.0002] -109C7 ; [.1BC0.0020.0002] -10E67 ; [.1BC0.0020.0002] -11059 ; [.1BC0.0020.0002] -1106E ; [.1BC0.0020.0002] -110F8 ; [.1BC0.0020.0002] -1113E ; [.1BC0.0020.0002] -111D8 ; [.1BC0.0020.0002] -111E8 ; [.1BC0.0020.0002] -112F8 ; [.1BC0.0020.0002] -114D8 ; [.1BC0.0020.0002] -11658 ; [.1BC0.0020.0002] -116C8 ; [.1BC0.0020.0002] -11738 ; [.1BC0.0020.0002] -118E8 ; [.1BC0.0020.0002] -12406 ; [.1BC0.0020.0002] -1240D ; [.1BC0.0020.0002] -12413 ; [.1BC0.0020.0002] -1241C ; [.1BC0.0020.0002] -1242A ; [.1BC0.0020.0002] -12444 ; [.1BC0.0020.0002] -12445 ; [.1BC0.0020.0002] -1246D ; [.1BC0.0020.0002] -16A68 ; [.1BC0.0020.0002] -16B58 ; [.1BC0.0020.0002] -1D367 ; [.1BC0.0020.0002] -1E8CE ; [.1BC0.0020.0002] -FF18 ; [.1BC0.0020.0003] -0F31 ; [.1BC0.0020.0004] -247B ; [*0310.0020.0004][.1BC0.0020.0004][*0311.0020.0004] -248F ; [.1BC0.0020.0004][*0274.0020.0004] -1F109 ; [.1BC0.0020.0004][*0221.0020.0004] -1D7D6 ; [.1BC0.0020.0005] -1D7E0 ; [.1BC0.0020.0005] -1D7EA ; [.1BC0.0020.0005] -1D7F4 ; [.1BC0.0020.0005] -1D7FE ; [.1BC0.0020.0005] -2467 ; [.1BC0.0020.0006] -24FC ; [.1BC0.0020.0006] -277D ; [.1BC0.0020.0006] -2787 ; [.1BC0.0020.0006] -2791 ; [.1BC0.0020.0006] -2078 ; [.1BC0.0020.0014] -2088 ; [.1BC0.0020.0015] -324F ; [.1BC0.0020.0006][.1BB8.0020.0006] -33E7 ; [.1BC0.0020.0004][.FB40.0020.0004][.E5E5.0000.0000] -32C7 ; [.1BC0.0020.0004][.FB40.0020.0004][.E708.0000.0000] -3360 ; [.1BC0.0020.0004][.FB40.0020.0004][.F0B9.0000.0000] -0039 ; [.1BC1.0020.0002] -0669 ; [.1BC1.0020.0002] -06F9 ; [.1BC1.0020.0002] -07C9 ; [.1BC1.0020.0002] -096F ; [.1BC1.0020.0002] -09EF ; [.1BC1.0020.0002] -0A6F ; [.1BC1.0020.0002] -0AEF ; [.1BC1.0020.0002] -0B6F ; [.1BC1.0020.0002] -0BEF ; [.1BC1.0020.0002] -0C6F ; [.1BC1.0020.0002] -0CEF ; [.1BC1.0020.0002] -0D6F ; [.1BC1.0020.0002] -0DEF ; [.1BC1.0020.0002] -0E59 ; [.1BC1.0020.0002] -0ED9 ; [.1BC1.0020.0002] -0F29 ; [.1BC1.0020.0002] -1049 ; [.1BC1.0020.0002] -1099 ; [.1BC1.0020.0002] -1371 ; [.1BC1.0020.0002] -17E9 ; [.1BC1.0020.0002] -17F9 ; [.1BC1.0020.0002] -1819 ; [.1BC1.0020.0002] -194F ; [.1BC1.0020.0002] -19D9 ; [.1BC1.0020.0002] -1A89 ; [.1BC1.0020.0002] -1A99 ; [.1BC1.0020.0002] -1B59 ; [.1BC1.0020.0002] -1BB9 ; [.1BC1.0020.0002] -1C49 ; [.1BC1.0020.0002] -1C59 ; [.1BC1.0020.0002] -3029 ; [.1BC1.0020.0002] -A629 ; [.1BC1.0020.0002] -A8D9 ; [.1BC1.0020.0002] -A909 ; [.1BC1.0020.0002] -A9D9 ; [.1BC1.0020.0002] -A9F9 ; [.1BC1.0020.0002] -AA59 ; [.1BC1.0020.0002] -ABF9 ; [.1BC1.0020.0002] -1010F ; [.1BC1.0020.0002] -102E9 ; [.1BC1.0020.0002] -104A9 ; [.1BC1.0020.0002] -109C8 ; [.1BC1.0020.0002] -10E68 ; [.1BC1.0020.0002] -1105A ; [.1BC1.0020.0002] -1106F ; [.1BC1.0020.0002] -110F9 ; [.1BC1.0020.0002] -1113F ; [.1BC1.0020.0002] -111D9 ; [.1BC1.0020.0002] -111E9 ; [.1BC1.0020.0002] -112F9 ; [.1BC1.0020.0002] -114D9 ; [.1BC1.0020.0002] -11659 ; [.1BC1.0020.0002] -116C9 ; [.1BC1.0020.0002] -11739 ; [.1BC1.0020.0002] -118E9 ; [.1BC1.0020.0002] -12407 ; [.1BC1.0020.0002] -1240E ; [.1BC1.0020.0002] -12414 ; [.1BC1.0020.0002] -1241D ; [.1BC1.0020.0002] -1242B ; [.1BC1.0020.0002] -12446 ; [.1BC1.0020.0002] -12447 ; [.1BC1.0020.0002] -12448 ; [.1BC1.0020.0002] -12449 ; [.1BC1.0020.0002] -1246E ; [.1BC1.0020.0002] -16A69 ; [.1BC1.0020.0002] -16B59 ; [.1BC1.0020.0002] -1D368 ; [.1BC1.0020.0002] -1E8CF ; [.1BC1.0020.0002] -FF19 ; [.1BC1.0020.0003] -0F32 ; [.1BC1.0020.0004] -247C ; [*0310.0020.0004][.1BC1.0020.0004][*0311.0020.0004] -2490 ; [.1BC1.0020.0004][*0274.0020.0004] -1F10A ; [.1BC1.0020.0004][*0221.0020.0004] -1D7D7 ; [.1BC1.0020.0005] -1D7E1 ; [.1BC1.0020.0005] -1D7EB ; [.1BC1.0020.0005] -1D7F5 ; [.1BC1.0020.0005] -1D7FF ; [.1BC1.0020.0005] -2468 ; [.1BC1.0020.0006] -24FD ; [.1BC1.0020.0006] -277E ; [.1BC1.0020.0006] -2788 ; [.1BC1.0020.0006] -2792 ; [.1BC1.0020.0006] -2079 ; [.1BC1.0020.0014] -2089 ; [.1BC1.0020.0015] -33E8 ; [.1BC1.0020.0004][.FB40.0020.0004][.E5E5.0000.0000] -32C8 ; [.1BC1.0020.0004][.FB40.0020.0004][.E708.0000.0000] -3361 ; [.1BC1.0020.0004][.FB40.0020.0004][.F0B9.0000.0000] -0061 ; [.1BC2.0020.0002] -FF41 ; [.1BC2.0020.0003] -0363 ; [.1BC2.0020.0004] -249C ; [*0310.0020.0004][.1BC2.0020.0004][*0311.0020.0004] -1D41A ; [.1BC2.0020.0005] -1D44E ; [.1BC2.0020.0005] -1D482 ; [.1BC2.0020.0005] -1D4B6 ; [.1BC2.0020.0005] -1D4EA ; [.1BC2.0020.0005] -1D51E ; [.1BC2.0020.0005] -1D552 ; [.1BC2.0020.0005] -1D586 ; [.1BC2.0020.0005] -1D5BA ; [.1BC2.0020.0005] -1D5EE ; [.1BC2.0020.0005] -1D622 ; [.1BC2.0020.0005] -1D656 ; [.1BC2.0020.0005] -1D68A ; [.1BC2.0020.0005] -24D0 ; [.1BC2.0020.0006] -0041 ; [.1BC2.0020.0008] -FF21 ; [.1BC2.0020.0009] -1F110 ; [*0310.0020.0004][.1BC2.0020.000A][*0311.0020.0004] -1D400 ; [.1BC2.0020.000B] -1D434 ; [.1BC2.0020.000B] -1D468 ; [.1BC2.0020.000B] -1D49C ; [.1BC2.0020.000B] -1D4D0 ; [.1BC2.0020.000B] -1D504 ; [.1BC2.0020.000B] -1D538 ; [.1BC2.0020.000B] -1D56C ; [.1BC2.0020.000B] -1D5A0 ; [.1BC2.0020.000B] -1D5D4 ; [.1BC2.0020.000B] -1D608 ; [.1BC2.0020.000B] -1D63C ; [.1BC2.0020.000B] -1D670 ; [.1BC2.0020.000B] -24B6 ; [.1BC2.0020.000C] -1F150 ; [.1BC2.0020.000C] -00AA ; [.1BC2.0020.0014] -1D43 ; [.1BC2.0020.0014] -2090 ; [.1BC2.0020.0015] -1D2C ; [.1BC2.0020.001D] -1F130 ; [.1BC2.0020.001D] -1F170 ; [.1BC2.0020.001D] -00E1 ; [.1BC2.0020.0002][.0000.0024.0002] -00C1 ; [.1BC2.0020.0008][.0000.0024.0002] -00E0 ; [.1BC2.0020.0002][.0000.0025.0002] -00C0 ; [.1BC2.0020.0008][.0000.0025.0002] -0103 ; [.1BC2.0020.0002][.0000.0026.0002] -0102 ; [.1BC2.0020.0008][.0000.0026.0002] -1EAF ; [.1BC2.0020.0002][.0000.0026.0002][.0000.0024.0002] -1EAE ; [.1BC2.0020.0008][.0000.0026.0002][.0000.0024.0002] -1EB1 ; [.1BC2.0020.0002][.0000.0026.0002][.0000.0025.0002] -1EB0 ; [.1BC2.0020.0008][.0000.0026.0002][.0000.0025.0002] -1EB5 ; [.1BC2.0020.0002][.0000.0026.0002][.0000.002D.0002] -1EB4 ; [.1BC2.0020.0008][.0000.0026.0002][.0000.002D.0002] -1EB3 ; [.1BC2.0020.0002][.0000.0026.0002][.0000.003B.0002] -1EB2 ; [.1BC2.0020.0008][.0000.0026.0002][.0000.003B.0002] -00E2 ; [.1BC2.0020.0002][.0000.0027.0002] -00C2 ; [.1BC2.0020.0008][.0000.0027.0002] -1EA5 ; [.1BC2.0020.0002][.0000.0027.0002][.0000.0024.0002] -1EA4 ; [.1BC2.0020.0008][.0000.0027.0002][.0000.0024.0002] -1EA7 ; [.1BC2.0020.0002][.0000.0027.0002][.0000.0025.0002] -1EA6 ; [.1BC2.0020.0008][.0000.0027.0002][.0000.0025.0002] -1EAB ; [.1BC2.0020.0002][.0000.0027.0002][.0000.002D.0002] -1EAA ; [.1BC2.0020.0008][.0000.0027.0002][.0000.002D.0002] -1EA9 ; [.1BC2.0020.0002][.0000.0027.0002][.0000.003B.0002] -1EA8 ; [.1BC2.0020.0008][.0000.0027.0002][.0000.003B.0002] -01CE ; [.1BC2.0020.0002][.0000.0028.0002] -01CD ; [.1BC2.0020.0008][.0000.0028.0002] -00E5 ; [.1BC2.0020.0002][.0000.0029.0002] -00C5 ; [.1BC2.0020.0008][.0000.0029.0002] -212B ; [.1BC2.0020.0008][.0000.0029.0002] -01FB ; [.1BC2.0020.0002][.0000.0029.0002][.0000.0024.0002] -01FA ; [.1BC2.0020.0008][.0000.0029.0002][.0000.0024.0002] -00E4 ; [.1BC2.0020.0002][.0000.002B.0002] -1DF2 ; [.1BC2.0020.0004][.0000.002B.0004] -A79B ; [.1BC2.0020.0004][.0000.002B.0004] -00C4 ; [.1BC2.0020.0008][.0000.002B.0002] -A79A ; [.1BC2.0020.000A][.0000.002B.0004] -01DF ; [.1BC2.0020.0002][.0000.002B.0002][.0000.0032.0002] -01DE ; [.1BC2.0020.0008][.0000.002B.0002][.0000.0032.0002] -00E3 ; [.1BC2.0020.0002][.0000.002D.0002] -00C3 ; [.1BC2.0020.0008][.0000.002D.0002] -0227 ; [.1BC2.0020.0002][.0000.002E.0002] -0226 ; [.1BC2.0020.0008][.0000.002E.0002] -01E1 ; [.1BC2.0020.0002][.0000.002E.0002][.0000.0032.0002] -01E0 ; [.1BC2.0020.0008][.0000.002E.0002][.0000.0032.0002] -0105 ; [.1BC2.0020.0002][.0000.0031.0002] -0104 ; [.1BC2.0020.0008][.0000.0031.0002] -0101 ; [.1BC2.0020.0002][.0000.0032.0002] -0100 ; [.1BC2.0020.0008][.0000.0032.0002] -1EA3 ; [.1BC2.0020.0002][.0000.003B.0002] -1EA2 ; [.1BC2.0020.0008][.0000.003B.0002] -0201 ; [.1BC2.0020.0002][.0000.003C.0002] -0200 ; [.1BC2.0020.0008][.0000.003C.0002] -0203 ; [.1BC2.0020.0002][.0000.003E.0002] -0202 ; [.1BC2.0020.0008][.0000.003E.0002] -1EA1 ; [.1BC2.0020.0002][.0000.0042.0002] -1EA0 ; [.1BC2.0020.0008][.0000.0042.0002] -1EB7 ; [.1BC2.0020.0002][.0000.0042.0002][.0000.0026.0002] -1EB6 ; [.1BC2.0020.0008][.0000.0042.0002][.0000.0026.0002] -1EAD ; [.1BC2.0020.0002][.0000.0042.0002][.0000.0027.0002] -1EAC ; [.1BC2.0020.0008][.0000.0042.0002][.0000.0027.0002] -1E01 ; [.1BC2.0020.0002][.0000.0044.0002] -1E00 ; [.1BC2.0020.0008][.0000.0044.0002] -1DD3 ; [.1BC2.0020.0004][.0000.010B.0004] -A733 ; [.1BC2.0020.0004][.1BC2.0020.0004] -A732 ; [.1BC2.0020.000A][.1BC2.0020.000A] -1F18E ; [.1BC2.0020.001D][.1BDB.0020.001D] -2100 ; [.1BC2.0020.0004][*038D.0020.0004][.1BF5.0020.0004] -00E6 ; [.1BC2.0020.0004][.0000.010B.0004][.1C25.0020.0004] -1DD4 ; [.1BC2.0020.0004][.0000.010B.0004][.1C25.0020.0004] -00C6 ; [.1BC2.0020.000A][.0000.010B.0004][.1C25.0020.000A] -1D2D ; [.1BC2.0020.0014][.0000.010B.0014][.1C25.0020.0014] -01FD ; [.1BC2.0020.0004][.0000.010B.0004][.1C25.0020.0004][.0000.0024.0002] -01FC ; [.1BC2.0020.000A][.0000.010B.0004][.1C25.0020.000A][.0000.0024.0002] -01E3 ; [.1BC2.0020.0004][.0000.010B.0004][.1C25.0020.0004][.0000.0032.0002] -01E2 ; [.1BC2.0020.000A][.0000.010B.0004][.1C25.0020.000A][.0000.0032.0002] -33C2 ; [.1BC2.0020.001C][*0274.0020.001C][.1D25.0020.001C][*0274.0020.001C] -33DF ; [.1BC2.0020.001D][*0605.0020.001C][.1D25.0020.001C] -1DD5 ; [.1BC2.0020.0004][.1D58.0020.0004] -A735 ; [.1BC2.0020.0004][.1D58.0020.0004] -A734 ; [.1BC2.0020.000A][.1D58.0020.000A] -2101 ; [.1BC2.0020.0004][*038D.0020.0004][.1DEC.0020.0004] -214D ; [.1BC2.0020.000A][*038D.0020.0004][.1DEC.0020.000A] -A737 ; [.1BC2.0020.0004][.1E30.0020.0004] -A736 ; [.1BC2.0020.000A][.1E30.0020.000A] -3373 ; [.1BC2.0020.001D][.1E30.0020.001D] -1DD6 ; [.1BC2.0020.0004][.1E5E.0020.0004] -A739 ; [.1BC2.0020.0004][.1E5E.0020.0004] -A738 ; [.1BC2.0020.000A][.1E5E.0020.000A] -A73B ; [.1BC2.0020.0004][.0000.010B.0004][.1E5E.0020.0004] -A73A ; [.1BC2.0020.000A][.0000.010B.0004][.1E5E.0020.000A] -A73D ; [.1BC2.0020.0004][.1E86.0020.0004] -A73C ; [.1BC2.0020.000A][.1E86.0020.000A] -1E9A ; [.1BC2.0020.0004][.1EFB.0020.0004] -1D00 ; [.1BC6.0020.0002] -2C65 ; [.1BC7.0020.0002] -023A ; [.1BC7.0020.0008] -1D8F ; [.1BC8.0020.0002] -1D01 ; [.1BC9.0020.0002] -1D02 ; [.1BCA.0020.0002] -1D46 ; [.1BCA.0020.0014] -AB31 ; [.1BCB.0020.0002] -0250 ; [.1BCC.0020.0002] -2C6F ; [.1BCC.0020.0008] -1D44 ; [.1BCC.0020.0014] -0251 ; [.1BD0.0020.0002] -1DE7 ; [.1BD0.0020.0004] -2C6D ; [.1BD0.0020.0008] -1D45 ; [.1BD0.0020.0014] -AB30 ; [.1BD4.0020.0002] -1D90 ; [.1BD5.0020.0002] -0252 ; [.1BD6.0020.0002] -2C70 ; [.1BD6.0020.0008] -1D9B ; [.1BD6.0020.0014] -AB64 ; [.1BDA.0020.0002] -0062 ; [.1BDB.0020.0002] -FF42 ; [.1BDB.0020.0003] -1DE8 ; [.1BDB.0020.0004] -249D ; [*0310.0020.0004][.1BDB.0020.0004][*0311.0020.0004] -1D41B ; [.1BDB.0020.0005] -1D44F ; [.1BDB.0020.0005] -1D483 ; [.1BDB.0020.0005] -1D4B7 ; [.1BDB.0020.0005] -1D4EB ; [.1BDB.0020.0005] -1D51F ; [.1BDB.0020.0005] -1D553 ; [.1BDB.0020.0005] -1D587 ; [.1BDB.0020.0005] -1D5BB ; [.1BDB.0020.0005] -1D5EF ; [.1BDB.0020.0005] -1D623 ; [.1BDB.0020.0005] -1D657 ; [.1BDB.0020.0005] -1D68B ; [.1BDB.0020.0005] -24D1 ; [.1BDB.0020.0006] -0042 ; [.1BDB.0020.0008] -FF22 ; [.1BDB.0020.0009] -1F111 ; [*0310.0020.0004][.1BDB.0020.000A][*0311.0020.0004] -212C ; [.1BDB.0020.000B] -1D401 ; [.1BDB.0020.000B] -1D435 ; [.1BDB.0020.000B] -1D469 ; [.1BDB.0020.000B] -1D4D1 ; [.1BDB.0020.000B] -1D505 ; [.1BDB.0020.000B] -1D539 ; [.1BDB.0020.000B] -1D56D ; [.1BDB.0020.000B] -1D5A1 ; [.1BDB.0020.000B] -1D5D5 ; [.1BDB.0020.000B] -1D609 ; [.1BDB.0020.000B] -1D63D ; [.1BDB.0020.000B] -1D671 ; [.1BDB.0020.000B] -24B7 ; [.1BDB.0020.000C] -1F151 ; [.1BDB.0020.000C] -1D47 ; [.1BDB.0020.0014] -1D2E ; [.1BDB.0020.001D] -1F131 ; [.1BDB.0020.001D] -1F171 ; [.1BDB.0020.001D] -1E03 ; [.1BDB.0020.0002][.0000.002E.0002] -1E02 ; [.1BDB.0020.0008][.0000.002E.0002] -1E05 ; [.1BDB.0020.0002][.0000.0042.0002] -1E04 ; [.1BDB.0020.0008][.0000.0042.0002] -1E07 ; [.1BDB.0020.0002][.0000.0049.0002] -1E06 ; [.1BDB.0020.0008][.0000.0049.0002] -3374 ; [.1BDB.0020.001C][.1BC2.0020.001C][.1DAE.0020.001C] -33C3 ; [.1BDB.0020.001D][.1D9C.0020.001C] -0299 ; [.1BDF.0020.0002] -0180 ; [.1BE3.0020.0002] -0243 ; [.1BE3.0020.0008] -1D2F ; [.1BE7.0020.0002] -1D03 ; [.1BE8.0020.0002] -1D6C ; [.1BE9.0020.0002] -A797 ; [.1BEA.0020.0002] -A796 ; [.1BEA.0020.0008] -1D80 ; [.1BEB.0020.0002] -0253 ; [.1BEC.0020.0002] -0181 ; [.1BEC.0020.0008] -0183 ; [.1BF0.0020.0002] -0182 ; [.1BF0.0020.0008] -A7B5 ; [.1BF4.0020.0002] -1DE9 ; [.1BF4.0020.0004] -A7B4 ; [.1BF4.0020.0008] -0063 ; [.1BF5.0020.0002] -FF43 ; [.1BF5.0020.0003] -0368 ; [.1BF5.0020.0004] -217D ; [.1BF5.0020.0004] -249E ; [*0310.0020.0004][.1BF5.0020.0004][*0311.0020.0004] -1D41C ; [.1BF5.0020.0005] -1D450 ; [.1BF5.0020.0005] -1D484 ; [.1BF5.0020.0005] -1D4B8 ; [.1BF5.0020.0005] -1D4EC ; [.1BF5.0020.0005] -1D520 ; [.1BF5.0020.0005] -1D554 ; [.1BF5.0020.0005] -1D588 ; [.1BF5.0020.0005] -1D5BC ; [.1BF5.0020.0005] -1D5F0 ; [.1BF5.0020.0005] -1D624 ; [.1BF5.0020.0005] -1D658 ; [.1BF5.0020.0005] -1D68C ; [.1BF5.0020.0005] -24D2 ; [.1BF5.0020.0006] -0043 ; [.1BF5.0020.0008] -FF23 ; [.1BF5.0020.0009] -2103 ; [*04D7.0020.0004][.1BF5.0020.000A] -216D ; [.1BF5.0020.000A] -1F112 ; [*0310.0020.0004][.1BF5.0020.000A][*0311.0020.0004] -2102 ; [.1BF5.0020.000B] -212D ; [.1BF5.0020.000B] -1D402 ; [.1BF5.0020.000B] -1D436 ; [.1BF5.0020.000B] -1D46A ; [.1BF5.0020.000B] -1D49E ; [.1BF5.0020.000B] -1D4D2 ; [.1BF5.0020.000B] -1D56E ; [.1BF5.0020.000B] -1D5A2 ; [.1BF5.0020.000B] -1D5D6 ; [.1BF5.0020.000B] -1D60A ; [.1BF5.0020.000B] -1D63E ; [.1BF5.0020.000B] -1D672 ; [.1BF5.0020.000B] -24B8 ; [.1BF5.0020.000C] -1F12B ; [.1BF5.0020.000C] -1F152 ; [.1BF5.0020.000C] -1D9C ; [.1BF5.0020.0014] -1F132 ; [.1BF5.0020.001D] -1F172 ; [.1BF5.0020.001D] -0107 ; [.1BF5.0020.0002][.0000.0024.0002] -0106 ; [.1BF5.0020.0008][.0000.0024.0002] -0109 ; [.1BF5.0020.0002][.0000.0027.0002] -0108 ; [.1BF5.0020.0008][.0000.0027.0002] -010D ; [.1BF5.0020.0002][.0000.0028.0002] -010C ; [.1BF5.0020.0008][.0000.0028.0002] -010B ; [.1BF5.0020.0002][.0000.002E.0002] -010A ; [.1BF5.0020.0008][.0000.002E.0002] -00E7 ; [.1BF5.0020.0002][.0000.0030.0002] -1DD7 ; [.1BF5.0020.0004][.0000.0030.0004] -00C7 ; [.1BF5.0020.0008][.0000.0030.0002] -1E09 ; [.1BF5.0020.0002][.0000.0030.0002][.0000.0024.0002] -1E08 ; [.1BF5.0020.0008][.0000.0030.0002][.0000.0024.0002] -3388 ; [.1BF5.0020.001C][.1BC2.0020.001C][.1CF2.0020.001C] -33C4 ; [.1BF5.0020.001C][.1BF5.0020.001C] -1F12D ; [.1BF5.0020.000C][.1C0A.0020.000C] -33C5 ; [.1BF5.0020.001C][.1C0A.0020.001C] -33C6 ; [.1BF5.0020.001D][*0605.0020.001C][.1CE0.0020.001C][.1C6F.0020.001C] -1F191 ; [.1BF5.0020.001D][.1CF2.0020.001D] -339D ; [.1BF5.0020.001C][.1D25.0020.001C] -33A0 ; [.1BF5.0020.001C][.1D25.0020.001C][.1BBA.0020.001C] -33A4 ; [.1BF5.0020.001C][.1D25.0020.001C][.1BBB.0020.001C] -2105 ; [.1BF5.0020.0004][*038D.0020.0004][.1D58.0020.0004] -33C7 ; [.1BF5.0020.001D][.1D58.0020.001C][*0274.0020.001C] -1F192 ; [.1BF5.0020.001D][.1D58.0020.001D][.1D58.0020.001D][.1CF2.0020.001D] -2106 ; [.1BF5.0020.0004][*038D.0020.0004][.1E30.0020.0004] -1D04 ; [.1BF9.0020.0002] -023C ; [.1BFA.0020.0002] -023B ; [.1BFA.0020.0008] -A793 ; [.1BFE.0020.0002] -A792 ; [.1BFE.0020.0008] -A794 ; [.1BFF.0020.0002] -0188 ; [.1C00.0020.0002] -0187 ; [.1C00.0020.0008] -0255 ; [.1C04.0020.0002] -1D9D ; [.1C04.0020.0014] -2184 ; [.1C08.0020.0002] -2183 ; [.1C08.0020.0008] -A73F ; [.1C09.0020.0002] -A73E ; [.1C09.0020.0008] -0064 ; [.1C0A.0020.0002] -FF44 ; [.1C0A.0020.0003] -0369 ; [.1C0A.0020.0004] -217E ; [.1C0A.0020.0004] -249F ; [*0310.0020.0004][.1C0A.0020.0004][*0311.0020.0004] -2146 ; [.1C0A.0020.0005] -1D41D ; [.1C0A.0020.0005] -1D451 ; [.1C0A.0020.0005] -1D485 ; [.1C0A.0020.0005] -1D4B9 ; [.1C0A.0020.0005] -1D4ED ; [.1C0A.0020.0005] -1D521 ; [.1C0A.0020.0005] -1D555 ; [.1C0A.0020.0005] -1D589 ; [.1C0A.0020.0005] -1D5BD ; [.1C0A.0020.0005] -1D5F1 ; [.1C0A.0020.0005] -1D625 ; [.1C0A.0020.0005] -1D659 ; [.1C0A.0020.0005] -1D68D ; [.1C0A.0020.0005] -24D3 ; [.1C0A.0020.0006] -0044 ; [.1C0A.0020.0008] -FF24 ; [.1C0A.0020.0009] -216E ; [.1C0A.0020.000A] -1F113 ; [*0310.0020.0004][.1C0A.0020.000A][*0311.0020.0004] -2145 ; [.1C0A.0020.000B] -1D403 ; [.1C0A.0020.000B] -1D437 ; [.1C0A.0020.000B] -1D46B ; [.1C0A.0020.000B] -1D49F ; [.1C0A.0020.000B] -1D4D3 ; [.1C0A.0020.000B] -1D507 ; [.1C0A.0020.000B] -1D53B ; [.1C0A.0020.000B] -1D56F ; [.1C0A.0020.000B] -1D5A3 ; [.1C0A.0020.000B] -1D5D7 ; [.1C0A.0020.000B] -1D60B ; [.1C0A.0020.000B] -1D63F ; [.1C0A.0020.000B] -1D673 ; [.1C0A.0020.000B] -24B9 ; [.1C0A.0020.000C] -1F153 ; [.1C0A.0020.000C] -1D48 ; [.1C0A.0020.0014] -1D30 ; [.1C0A.0020.001D] -1F133 ; [.1C0A.0020.001D] -1F173 ; [.1C0A.0020.001D] -010F ; [.1C0A.0020.0002][.0000.0028.0002] -010E ; [.1C0A.0020.0008][.0000.0028.0002] -1E0B ; [.1C0A.0020.0002][.0000.002E.0002] -1E0A ; [.1C0A.0020.0008][.0000.002E.0002] -1E11 ; [.1C0A.0020.0002][.0000.0030.0002] -1E10 ; [.1C0A.0020.0008][.0000.0030.0002] -0111 ; [.1C0A.0020.0002][.0000.0039.0002] -0110 ; [.1C0A.0020.0008][.0000.0039.0002] -1E0D ; [.1C0A.0020.0002][.0000.0042.0002] -1E0C ; [.1C0A.0020.0008][.0000.0042.0002] -1E13 ; [.1C0A.0020.0002][.0000.0046.0002] -1E12 ; [.1C0A.0020.0008][.0000.0046.0002] -1E0F ; [.1C0A.0020.0002][.0000.0049.0002] -1E0E ; [.1C0A.0020.0008][.0000.0049.0002] -00F0 ; [.1C0A.0020.0004][.0000.010B.0004] -1DD9 ; [.1C0A.0020.0004][.0000.010B.0004] -00D0 ; [.1C0A.0020.000A][.0000.010B.0004] -1D9E ; [.1C0A.0020.0014][.0000.010B.0014] -1DD8 ; [.1C0A.0020.0004][.0000.010C.0004] -A77A ; [.1C0A.0020.0004][.0000.010C.0004] -A779 ; [.1C0A.0020.000A][.0000.010C.0004] -3372 ; [.1C0A.0020.001C][.1BC2.0020.001C] -0238 ; [.1C0A.0020.0004][.1BDB.0020.0004] -33C8 ; [.1C0A.0020.001C][.1BDB.0020.001D] -1F190 ; [.1C0A.0020.001D][.1CC7.0020.001D] -3397 ; [.1C0A.0020.001C][.1CF2.0020.001C] -3377 ; [.1C0A.0020.001C][.1D25.0020.001C] -3378 ; [.1C0A.0020.001C][.1D25.0020.001C][.1BBA.0020.001C] -3379 ; [.1C0A.0020.001C][.1D25.0020.001C][.1BBB.0020.001C] -01F3 ; [.1C0A.0020.0004][.1E9C.0020.0004] -02A3 ; [.1C0A.0020.0004][.1E9C.0020.0004] -01F2 ; [.1C0A.0020.000A][.1E9C.0020.0004] -01F1 ; [.1C0A.0020.000A][.1E9C.0020.000A] -01C6 ; [.1C0A.0020.0004][.1E9C.0020.0004][.0000.0028.0004] -01C5 ; [.1C0A.0020.000A][.1E9C.0020.0004][.0000.0028.0004] -01C4 ; [.1C0A.0020.000A][.1E9C.0020.000A][.0000.0028.0004] -02A5 ; [.1C0A.0020.0004][.1EAF.0020.0004] -02A4 ; [.1C0A.0020.0004][.1EB9.0020.0004] -1D05 ; [.1C0E.0020.0002] -1D06 ; [.1C0F.0020.0002] -1D6D ; [.1C10.0020.0002] -1D81 ; [.1C11.0020.0002] -0256 ; [.1C12.0020.0002] -0189 ; [.1C12.0020.0008] -0257 ; [.1C16.0020.0002] -018A ; [.1C16.0020.0008] -1D91 ; [.1C1A.0020.0002] -018C ; [.1C1B.0020.0002] -018B ; [.1C1B.0020.0008] -0221 ; [.1C1F.0020.0002] -A771 ; [.1C23.0020.0002] -1E9F ; [.1C24.0020.0002] -0065 ; [.1C25.0020.0002] -FF45 ; [.1C25.0020.0003] -0364 ; [.1C25.0020.0004] -24A0 ; [*0310.0020.0004][.1C25.0020.0004][*0311.0020.0004] -212F ; [.1C25.0020.0005] -2147 ; [.1C25.0020.0005] -1D41E ; [.1C25.0020.0005] -1D452 ; [.1C25.0020.0005] -1D486 ; [.1C25.0020.0005] -1D4EE ; [.1C25.0020.0005] -1D522 ; [.1C25.0020.0005] -1D556 ; [.1C25.0020.0005] -1D58A ; [.1C25.0020.0005] -1D5BE ; [.1C25.0020.0005] -1D5F2 ; [.1C25.0020.0005] -1D626 ; [.1C25.0020.0005] -1D65A ; [.1C25.0020.0005] -1D68E ; [.1C25.0020.0005] -24D4 ; [.1C25.0020.0006] -0045 ; [.1C25.0020.0008] -FF25 ; [.1C25.0020.0009] -1F114 ; [*0310.0020.0004][.1C25.0020.000A][*0311.0020.0004] -2130 ; [.1C25.0020.000B] -1D404 ; [.1C25.0020.000B] -1D438 ; [.1C25.0020.000B] -1D46C ; [.1C25.0020.000B] -1D4D4 ; [.1C25.0020.000B] -1D508 ; [.1C25.0020.000B] -1D53C ; [.1C25.0020.000B] -1D570 ; [.1C25.0020.000B] -1D5A4 ; [.1C25.0020.000B] -1D5D8 ; [.1C25.0020.000B] -1D60C ; [.1C25.0020.000B] -1D640 ; [.1C25.0020.000B] -1D674 ; [.1C25.0020.000B] -24BA ; [.1C25.0020.000C] -1F154 ; [.1C25.0020.000C] -1D49 ; [.1C25.0020.0014] -2091 ; [.1C25.0020.0015] -1D31 ; [.1C25.0020.001D] -1F134 ; [.1C25.0020.001D] -1F174 ; [.1C25.0020.001D] -00E9 ; [.1C25.0020.0002][.0000.0024.0002] -00C9 ; [.1C25.0020.0008][.0000.0024.0002] -00E8 ; [.1C25.0020.0002][.0000.0025.0002] -00C8 ; [.1C25.0020.0008][.0000.0025.0002] -0115 ; [.1C25.0020.0002][.0000.0026.0002] -0114 ; [.1C25.0020.0008][.0000.0026.0002] -00EA ; [.1C25.0020.0002][.0000.0027.0002] -00CA ; [.1C25.0020.0008][.0000.0027.0002] -1EBF ; [.1C25.0020.0002][.0000.0027.0002][.0000.0024.0002] -1EBE ; [.1C25.0020.0008][.0000.0027.0002][.0000.0024.0002] -1EC1 ; [.1C25.0020.0002][.0000.0027.0002][.0000.0025.0002] -1EC0 ; [.1C25.0020.0008][.0000.0027.0002][.0000.0025.0002] -1EC5 ; [.1C25.0020.0002][.0000.0027.0002][.0000.002D.0002] -1EC4 ; [.1C25.0020.0008][.0000.0027.0002][.0000.002D.0002] -1EC3 ; [.1C25.0020.0002][.0000.0027.0002][.0000.003B.0002] -1EC2 ; [.1C25.0020.0008][.0000.0027.0002][.0000.003B.0002] -011B ; [.1C25.0020.0002][.0000.0028.0002] -011A ; [.1C25.0020.0008][.0000.0028.0002] -00EB ; [.1C25.0020.0002][.0000.002B.0002] -00CB ; [.1C25.0020.0008][.0000.002B.0002] -1EBD ; [.1C25.0020.0002][.0000.002D.0002] -1EBC ; [.1C25.0020.0008][.0000.002D.0002] -0117 ; [.1C25.0020.0002][.0000.002E.0002] -0116 ; [.1C25.0020.0008][.0000.002E.0002] -0229 ; [.1C25.0020.0002][.0000.0030.0002] -0228 ; [.1C25.0020.0008][.0000.0030.0002] -1E1D ; [.1C25.0020.0002][.0000.0030.0002][.0000.0026.0002] -1E1C ; [.1C25.0020.0008][.0000.0030.0002][.0000.0026.0002] -0119 ; [.1C25.0020.0002][.0000.0031.0002] -0118 ; [.1C25.0020.0008][.0000.0031.0002] -0113 ; [.1C25.0020.0002][.0000.0032.0002] -0112 ; [.1C25.0020.0008][.0000.0032.0002] -1E17 ; [.1C25.0020.0002][.0000.0032.0002][.0000.0024.0002] -1E16 ; [.1C25.0020.0008][.0000.0032.0002][.0000.0024.0002] -1E15 ; [.1C25.0020.0002][.0000.0032.0002][.0000.0025.0002] -1E14 ; [.1C25.0020.0008][.0000.0032.0002][.0000.0025.0002] -1EBB ; [.1C25.0020.0002][.0000.003B.0002] -1EBA ; [.1C25.0020.0008][.0000.003B.0002] -0205 ; [.1C25.0020.0002][.0000.003C.0002] -0204 ; [.1C25.0020.0008][.0000.003C.0002] -0207 ; [.1C25.0020.0002][.0000.003E.0002] -0206 ; [.1C25.0020.0008][.0000.003E.0002] -1EB9 ; [.1C25.0020.0002][.0000.0042.0002] -1EB8 ; [.1C25.0020.0008][.0000.0042.0002] -1EC7 ; [.1C25.0020.0002][.0000.0042.0002][.0000.0027.0002] -1EC6 ; [.1C25.0020.0008][.0000.0042.0002][.0000.0027.0002] -1E19 ; [.1C25.0020.0002][.0000.0046.0002] -1E18 ; [.1C25.0020.0008][.0000.0046.0002] -1E1B ; [.1C25.0020.0002][.0000.0048.0002] -1E1A ; [.1C25.0020.0008][.0000.0048.0002] -32CD ; [.1C25.0020.001C][.1DAE.0020.001C][.1C6F.0020.001C] -32CE ; [.1C25.0020.001C][.1E5E.0020.001D] -1D07 ; [.1C29.0020.0002] -AB32 ; [.1C2A.0020.0002] -AB33 ; [.1C2B.0020.0002] -0247 ; [.1C2C.0020.0002] -0246 ; [.1C2C.0020.0008] -1D92 ; [.1C30.0020.0002] -AB34 ; [.1C31.0020.0002] -2C78 ; [.1C32.0020.0002] -01DD ; [.1C33.0020.0002] -018E ; [.1C33.0020.0008] -1D32 ; [.1C33.0020.001D] -2C7B ; [.1C37.0020.0002] -0259 ; [.1C38.0020.0002] -1DEA ; [.1C38.0020.0004] -018F ; [.1C38.0020.0008] -1D4A ; [.1C38.0020.0014] -2094 ; [.1C38.0020.0015] -1D95 ; [.1C3C.0020.0002] -025B ; [.1C3D.0020.0002] -0190 ; [.1C3D.0020.0008] -2107 ; [.1C3D.0020.000A] -1D4B ; [.1C3D.0020.0014] -1D93 ; [.1C41.0020.0002] -0258 ; [.1C42.0020.0002] -025A ; [.1C46.0020.0002] -025C ; [.1C4A.0020.0002] -A7AB ; [.1C4A.0020.0008] -1D9F ; [.1C4A.0020.0014] -1D94 ; [.1C4E.0020.0002] -1D08 ; [.1C4F.0020.0002] -1D4C ; [.1C4F.0020.0014] -025D ; [.1C50.0020.0002] -025E ; [.1C54.0020.0002] -029A ; [.1C58.0020.0002] -0264 ; [.1C5C.0020.0002] -0066 ; [.1C60.0020.0002] -FF46 ; [.1C60.0020.0003] -1DEB ; [.1C60.0020.0004] -24A1 ; [*0310.0020.0004][.1C60.0020.0004][*0311.0020.0004] -1D41F ; [.1C60.0020.0005] -1D453 ; [.1C60.0020.0005] -1D487 ; [.1C60.0020.0005] -1D4BB ; [.1C60.0020.0005] -1D4EF ; [.1C60.0020.0005] -1D523 ; [.1C60.0020.0005] -1D557 ; [.1C60.0020.0005] -1D58B ; [.1C60.0020.0005] -1D5BF ; [.1C60.0020.0005] -1D5F3 ; [.1C60.0020.0005] -1D627 ; [.1C60.0020.0005] -1D65B ; [.1C60.0020.0005] -1D68F ; [.1C60.0020.0005] -24D5 ; [.1C60.0020.0006] -0046 ; [.1C60.0020.0008] -FF26 ; [.1C60.0020.0009] -2109 ; [*04D7.0020.0004][.1C60.0020.000A] -1F115 ; [*0310.0020.0004][.1C60.0020.000A][*0311.0020.0004] -2131 ; [.1C60.0020.000B] -1D405 ; [.1C60.0020.000B] -1D439 ; [.1C60.0020.000B] -1D46D ; [.1C60.0020.000B] -1D4D5 ; [.1C60.0020.000B] -1D509 ; [.1C60.0020.000B] -1D53D ; [.1C60.0020.000B] -1D571 ; [.1C60.0020.000B] -1D5A5 ; [.1C60.0020.000B] -1D5D9 ; [.1C60.0020.000B] -1D60D ; [.1C60.0020.000B] -1D641 ; [.1C60.0020.000B] -1D675 ; [.1C60.0020.000B] -24BB ; [.1C60.0020.000C] -1F155 ; [.1C60.0020.000C] -1DA0 ; [.1C60.0020.0014] -1F135 ; [.1C60.0020.001D] -1F175 ; [.1C60.0020.001D] -1E1F ; [.1C60.0020.0002][.0000.002E.0002] -1E1E ; [.1C60.0020.0008][.0000.002E.0002] -A77C ; [.1C60.0020.0004][.0000.010C.0004] -A77B ; [.1C60.0020.000A][.0000.010C.0004] -213B ; [.1C60.0020.000A][.1BC2.0020.000A][.1E7A.0020.000A] -FB00 ; [.1C60.0020.0004][.1C60.0020.0004] -FB03 ; [.1C60.0020.0004][.1C60.0020.0004][.1CAD.0020.0004] -FB04 ; [.1C60.0020.0004][.1C60.0020.0004][.1CF2.0020.0004] -FB01 ; [.1C60.0020.0004][.1CAD.0020.0004] -FB02 ; [.1C60.0020.0004][.1CF2.0020.0004] -3399 ; [.1C60.0020.001C][.1D25.0020.001C] -02A9 ; [.1C60.0020.0004][.1D53.0020.0004] -1F193 ; [.1C60.0020.001D][.1DAE.0020.001D][.1C25.0020.001D][.1C25.0020.001D] -A730 ; [.1C64.0020.0002] -AB35 ; [.1C65.0020.0002] -A799 ; [.1C66.0020.0002] -A798 ; [.1C66.0020.0008] -1D6E ; [.1C67.0020.0002] -1D82 ; [.1C68.0020.0002] -0192 ; [.1C69.0020.0002] -0191 ; [.1C69.0020.0008] -214E ; [.1C6D.0020.0002] -2132 ; [.1C6D.0020.0008] -A7FB ; [.1C6E.0020.0002] -0067 ; [.1C6F.0020.0002] -FF47 ; [.1C6F.0020.0003] -1DDA ; [.1C6F.0020.0004] -24A2 ; [*0310.0020.0004][.1C6F.0020.0004][*0311.0020.0004] -210A ; [.1C6F.0020.0005] -1D420 ; [.1C6F.0020.0005] -1D454 ; [.1C6F.0020.0005] -1D488 ; [.1C6F.0020.0005] -1D4F0 ; [.1C6F.0020.0005] -1D524 ; [.1C6F.0020.0005] -1D558 ; [.1C6F.0020.0005] -1D58C ; [.1C6F.0020.0005] -1D5C0 ; [.1C6F.0020.0005] -1D5F4 ; [.1C6F.0020.0005] -1D628 ; [.1C6F.0020.0005] -1D65C ; [.1C6F.0020.0005] -1D690 ; [.1C6F.0020.0005] -24D6 ; [.1C6F.0020.0006] -0047 ; [.1C6F.0020.0008] -FF27 ; [.1C6F.0020.0009] -1F116 ; [*0310.0020.0004][.1C6F.0020.000A][*0311.0020.0004] -1D406 ; [.1C6F.0020.000B] -1D43A ; [.1C6F.0020.000B] -1D46E ; [.1C6F.0020.000B] -1D4A2 ; [.1C6F.0020.000B] -1D4D6 ; [.1C6F.0020.000B] -1D50A ; [.1C6F.0020.000B] -1D53E ; [.1C6F.0020.000B] -1D572 ; [.1C6F.0020.000B] -1D5A6 ; [.1C6F.0020.000B] -1D5DA ; [.1C6F.0020.000B] -1D60E ; [.1C6F.0020.000B] -1D642 ; [.1C6F.0020.000B] -1D676 ; [.1C6F.0020.000B] -24BC ; [.1C6F.0020.000C] -1F156 ; [.1C6F.0020.000C] -1D4D ; [.1C6F.0020.0014] -1D33 ; [.1C6F.0020.001D] -1F136 ; [.1C6F.0020.001D] -1F176 ; [.1C6F.0020.001D] -01F5 ; [.1C6F.0020.0002][.0000.0024.0002] -01F4 ; [.1C6F.0020.0008][.0000.0024.0002] -011F ; [.1C6F.0020.0002][.0000.0026.0002] -011E ; [.1C6F.0020.0008][.0000.0026.0002] -011D ; [.1C6F.0020.0002][.0000.0027.0002] -011C ; [.1C6F.0020.0008][.0000.0027.0002] -01E7 ; [.1C6F.0020.0002][.0000.0028.0002] -01E6 ; [.1C6F.0020.0008][.0000.0028.0002] -0121 ; [.1C6F.0020.0002][.0000.002E.0002] -0120 ; [.1C6F.0020.0008][.0000.002E.0002] -0123 ; [.1C6F.0020.0002][.0000.0030.0002] -0122 ; [.1C6F.0020.0008][.0000.0030.0002] -1E21 ; [.1C6F.0020.0002][.0000.0032.0002] -1E20 ; [.1C6F.0020.0008][.0000.0032.0002] -A7A1 ; [.1C6F.0020.0004][.0000.0035.0004] -A7A0 ; [.1C6F.0020.000A][.0000.0035.0004] -1D79 ; [.1C6F.0020.0004][.0000.010C.0004] -A77D ; [.1C6F.0020.000A][.0000.010C.0004] -33FF ; [.1C6F.0020.001C][.1BC2.0020.001C][.1CF2.0020.001C] -3387 ; [.1C6F.0020.001D][.1BDB.0020.001D] -3393 ; [.1C6F.0020.001D][.1C93.0020.001D][.1E9C.0020.001C] -33AC ; [.1C6F.0020.001D][.1D87.0020.001D][.1BC2.0020.001C] -33C9 ; [.1C6F.0020.001D][.1E86.0020.001C] -0261 ; [.1C73.0020.0002] -A7AC ; [.1C73.0020.0008] -1DA2 ; [.1C73.0020.0014] -AB36 ; [.1C77.0020.0002] -0262 ; [.1C78.0020.0002] -1DDB ; [.1C78.0020.0004] -01E5 ; [.1C7C.0020.0002] -01E4 ; [.1C7C.0020.0008] -1D83 ; [.1C80.0020.0002] -0260 ; [.1C81.0020.0002] -0193 ; [.1C81.0020.0008] -029B ; [.1C85.0020.0002] -1D77 ; [.1C89.0020.0002] -A77F ; [.1C8A.0020.0002] -A77E ; [.1C8A.0020.0008] -0263 ; [.1C8B.0020.0002] -0194 ; [.1C8B.0020.0008] -02E0 ; [.1C8B.0020.0014] -01A3 ; [.1C8F.0020.0002] -01A2 ; [.1C8F.0020.0008] -0068 ; [.1C93.0020.0002] -FF48 ; [.1C93.0020.0003] -036A ; [.1C93.0020.0004] -24A3 ; [*0310.0020.0004][.1C93.0020.0004][*0311.0020.0004] -210E ; [.1C93.0020.0005] -1D421 ; [.1C93.0020.0005] -1D489 ; [.1C93.0020.0005] -1D4BD ; [.1C93.0020.0005] -1D4F1 ; [.1C93.0020.0005] -1D525 ; [.1C93.0020.0005] -1D559 ; [.1C93.0020.0005] -1D58D ; [.1C93.0020.0005] -1D5C1 ; [.1C93.0020.0005] -1D5F5 ; [.1C93.0020.0005] -1D629 ; [.1C93.0020.0005] -1D65D ; [.1C93.0020.0005] -1D691 ; [.1C93.0020.0005] -24D7 ; [.1C93.0020.0006] -0048 ; [.1C93.0020.0008] -FF28 ; [.1C93.0020.0009] -1F117 ; [*0310.0020.0004][.1C93.0020.000A][*0311.0020.0004] -210B ; [.1C93.0020.000B] -210C ; [.1C93.0020.000B] -210D ; [.1C93.0020.000B] -1D407 ; [.1C93.0020.000B] -1D43B ; [.1C93.0020.000B] -1D46F ; [.1C93.0020.000B] -1D4D7 ; [.1C93.0020.000B] -1D573 ; [.1C93.0020.000B] -1D5A7 ; [.1C93.0020.000B] -1D5DB ; [.1C93.0020.000B] -1D60F ; [.1C93.0020.000B] -1D643 ; [.1C93.0020.000B] -1D677 ; [.1C93.0020.000B] -24BD ; [.1C93.0020.000C] -1F157 ; [.1C93.0020.000C] -02B0 ; [.1C93.0020.0014] -2095 ; [.1C93.0020.0015] -1D34 ; [.1C93.0020.001D] -1F137 ; [.1C93.0020.001D] -1F177 ; [.1C93.0020.001D] -0125 ; [.1C93.0020.0002][.0000.0027.0002] -0124 ; [.1C93.0020.0008][.0000.0027.0002] -021F ; [.1C93.0020.0002][.0000.0028.0002] -021E ; [.1C93.0020.0008][.0000.0028.0002] -1E27 ; [.1C93.0020.0002][.0000.002B.0002] -1E26 ; [.1C93.0020.0008][.0000.002B.0002] -1E23 ; [.1C93.0020.0002][.0000.002E.0002] -1E22 ; [.1C93.0020.0008][.0000.002E.0002] -1E29 ; [.1C93.0020.0002][.0000.0030.0002] -1E28 ; [.1C93.0020.0008][.0000.0030.0002] -0127 ; [.1C93.0020.0002][.0000.0039.0002] -210F ; [.1C93.0020.0002][.0000.0039.0002] -0126 ; [.1C93.0020.0008][.0000.0039.0002] -A7F8 ; [.1C93.0020.0014][.0000.0039.0014] -1E25 ; [.1C93.0020.0002][.0000.0042.0002] -1E24 ; [.1C93.0020.0008][.0000.0042.0002] -1E2B ; [.1C93.0020.0002][.0000.0047.0002] -1E2A ; [.1C93.0020.0008][.0000.0047.0002] -1E96 ; [.1C93.0020.0002][.0000.0049.0002] -33CA ; [.1C93.0020.001C][.1BC2.0020.001C] -32CC ; [.1C93.0020.001D][.1C6F.0020.001C] -33CB ; [.1C93.0020.001D][.1D87.0020.001D] -3371 ; [.1C93.0020.001C][.1D87.0020.001D][.1BC2.0020.001C] -1F14A ; [.1C93.0020.001D][.1E5E.0020.001D] -3390 ; [.1C93.0020.001D][.1E9C.0020.001C] -029C ; [.1C97.0020.0002] -0195 ; [.1C9B.0020.0002] -01F6 ; [.1C9B.0020.0008] -A795 ; [.1C9F.0020.0002] -0266 ; [.1CA0.0020.0002] -A7AA ; [.1CA0.0020.0008] -02B1 ; [.1CA0.0020.0014] -2C68 ; [.1CA4.0020.0002] -2C67 ; [.1CA4.0020.0008] -2C76 ; [.1CA5.0020.0002] -2C75 ; [.1CA5.0020.0008] -A727 ; [.1CA6.0020.0002] -A726 ; [.1CA6.0020.0008] -AB5C ; [.1CA6.0020.0014] -0267 ; [.1CA7.0020.0002] -02BB ; [.1CAB.0020.0002] -02BD ; [.1CAC.0020.0002] -0069 ; [.1CAD.0020.0002] -FF49 ; [.1CAD.0020.0003] -0365 ; [.1CAD.0020.0004] -2170 ; [.1CAD.0020.0004] -24A4 ; [*0310.0020.0004][.1CAD.0020.0004][*0311.0020.0004] -2139 ; [.1CAD.0020.0005] -2148 ; [.1CAD.0020.0005] -1D422 ; [.1CAD.0020.0005] -1D456 ; [.1CAD.0020.0005] -1D48A ; [.1CAD.0020.0005] -1D4BE ; [.1CAD.0020.0005] -1D4F2 ; [.1CAD.0020.0005] -1D526 ; [.1CAD.0020.0005] -1D55A ; [.1CAD.0020.0005] -1D58E ; [.1CAD.0020.0005] -1D5C2 ; [.1CAD.0020.0005] -1D5F6 ; [.1CAD.0020.0005] -1D62A ; [.1CAD.0020.0005] -1D65E ; [.1CAD.0020.0005] -1D692 ; [.1CAD.0020.0005] -24D8 ; [.1CAD.0020.0006] -0049 ; [.1CAD.0020.0008] -FF29 ; [.1CAD.0020.0009] -2160 ; [.1CAD.0020.000A] -1F118 ; [*0310.0020.0004][.1CAD.0020.000A][*0311.0020.0004] -2110 ; [.1CAD.0020.000B] -2111 ; [.1CAD.0020.000B] -1D408 ; [.1CAD.0020.000B] -1D43C ; [.1CAD.0020.000B] -1D470 ; [.1CAD.0020.000B] -1D4D8 ; [.1CAD.0020.000B] -1D540 ; [.1CAD.0020.000B] -1D574 ; [.1CAD.0020.000B] -1D5A8 ; [.1CAD.0020.000B] -1D5DC ; [.1CAD.0020.000B] -1D610 ; [.1CAD.0020.000B] -1D644 ; [.1CAD.0020.000B] -1D678 ; [.1CAD.0020.000B] -24BE ; [.1CAD.0020.000C] -1F158 ; [.1CAD.0020.000C] -2071 ; [.1CAD.0020.0014] -1D62 ; [.1CAD.0020.0015] -1D35 ; [.1CAD.0020.001D] -1F138 ; [.1CAD.0020.001D] -1F178 ; [.1CAD.0020.001D] -00ED ; [.1CAD.0020.0002][.0000.0024.0002] -00CD ; [.1CAD.0020.0008][.0000.0024.0002] -00EC ; [.1CAD.0020.0002][.0000.0025.0002] -00CC ; [.1CAD.0020.0008][.0000.0025.0002] -012D ; [.1CAD.0020.0002][.0000.0026.0002] -012C ; [.1CAD.0020.0008][.0000.0026.0002] -00EE ; [.1CAD.0020.0002][.0000.0027.0002] -00CE ; [.1CAD.0020.0008][.0000.0027.0002] -01D0 ; [.1CAD.0020.0002][.0000.0028.0002] -01CF ; [.1CAD.0020.0008][.0000.0028.0002] -00EF ; [.1CAD.0020.0002][.0000.002B.0002] -00CF ; [.1CAD.0020.0008][.0000.002B.0002] -1E2F ; [.1CAD.0020.0002][.0000.002B.0002][.0000.0024.0002] -1E2E ; [.1CAD.0020.0008][.0000.002B.0002][.0000.0024.0002] -0129 ; [.1CAD.0020.0002][.0000.002D.0002] -0128 ; [.1CAD.0020.0008][.0000.002D.0002] -0130 ; [.1CAD.0020.0008][.0000.002E.0002] -012F ; [.1CAD.0020.0002][.0000.0031.0002] -012E ; [.1CAD.0020.0008][.0000.0031.0002] -012B ; [.1CAD.0020.0002][.0000.0032.0002] -012A ; [.1CAD.0020.0008][.0000.0032.0002] -1EC9 ; [.1CAD.0020.0002][.0000.003B.0002] -1EC8 ; [.1CAD.0020.0008][.0000.003B.0002] -0209 ; [.1CAD.0020.0002][.0000.003C.0002] -0208 ; [.1CAD.0020.0008][.0000.003C.0002] -020B ; [.1CAD.0020.0002][.0000.003E.0002] -020A ; [.1CAD.0020.0008][.0000.003E.0002] -1ECB ; [.1CAD.0020.0002][.0000.0042.0002] -1ECA ; [.1CAD.0020.0008][.0000.0042.0002] -1E2D ; [.1CAD.0020.0002][.0000.0048.0002] -1E2C ; [.1CAD.0020.0008][.0000.0048.0002] -1F18B ; [.1CAD.0020.001D][.1BF5.0020.001D] -1F194 ; [.1CAD.0020.001D][.1C0A.0020.001D] -2171 ; [.1CAD.0020.0004][.1CAD.0020.0004] -2161 ; [.1CAD.0020.000A][.1CAD.0020.000A] -2172 ; [.1CAD.0020.0004][.1CAD.0020.0004][.1CAD.0020.0004] -2162 ; [.1CAD.0020.000A][.1CAD.0020.000A][.1CAD.0020.000A] -0133 ; [.1CAD.0020.0004][.1CC7.0020.0004] -0132 ; [.1CAD.0020.000A][.1CC7.0020.000A] -33CC ; [.1CAD.0020.001C][.1D34.0020.001C] -337A ; [.1CAD.0020.001D][.1E30.0020.001D] -2173 ; [.1CAD.0020.0004][.1E5E.0020.0004] -2163 ; [.1CAD.0020.000A][.1E5E.0020.000A] -2178 ; [.1CAD.0020.0004][.1E7A.0020.0004] -2168 ; [.1CAD.0020.000A][.1E7A.0020.000A] -0131 ; [.1CB1.0020.0002] -1D6A4 ; [.1CB1.0020.0005] -026A ; [.1CB5.0020.0002] -1DA6 ; [.1CB5.0020.0014] -A7FE ; [.1CB9.0020.0002] -A7F7 ; [.1CBA.0020.0002] -1D09 ; [.1CBB.0020.0002] -1D4E ; [.1CBB.0020.0014] -0268 ; [.1CBC.0020.0002] -0197 ; [.1CBC.0020.0008] -1DA4 ; [.1CBC.0020.0014] -1D7B ; [.1CC0.0020.0002] -1DA7 ; [.1CC0.0020.0014] -1D96 ; [.1CC1.0020.0002] -0269 ; [.1CC2.0020.0002] -0196 ; [.1CC2.0020.0008] -1DA5 ; [.1CC2.0020.0014] -1D7C ; [.1CC6.0020.0002] -006A ; [.1CC7.0020.0002] -FF4A ; [.1CC7.0020.0003] -24A5 ; [*0310.0020.0004][.1CC7.0020.0004][*0311.0020.0004] -2149 ; [.1CC7.0020.0005] -1D423 ; [.1CC7.0020.0005] -1D457 ; [.1CC7.0020.0005] -1D48B ; [.1CC7.0020.0005] -1D4BF ; [.1CC7.0020.0005] -1D4F3 ; [.1CC7.0020.0005] -1D527 ; [.1CC7.0020.0005] -1D55B ; [.1CC7.0020.0005] -1D58F ; [.1CC7.0020.0005] -1D5C3 ; [.1CC7.0020.0005] -1D5F7 ; [.1CC7.0020.0005] -1D62B ; [.1CC7.0020.0005] -1D65F ; [.1CC7.0020.0005] -1D693 ; [.1CC7.0020.0005] -24D9 ; [.1CC7.0020.0006] -004A ; [.1CC7.0020.0008] -FF2A ; [.1CC7.0020.0009] -1F119 ; [*0310.0020.0004][.1CC7.0020.000A][*0311.0020.0004] -1D409 ; [.1CC7.0020.000B] -1D43D ; [.1CC7.0020.000B] -1D471 ; [.1CC7.0020.000B] -1D4A5 ; [.1CC7.0020.000B] -1D4D9 ; [.1CC7.0020.000B] -1D50D ; [.1CC7.0020.000B] -1D541 ; [.1CC7.0020.000B] -1D575 ; [.1CC7.0020.000B] -1D5A9 ; [.1CC7.0020.000B] -1D5DD ; [.1CC7.0020.000B] -1D611 ; [.1CC7.0020.000B] -1D645 ; [.1CC7.0020.000B] -1D679 ; [.1CC7.0020.000B] -24BF ; [.1CC7.0020.000C] -1F159 ; [.1CC7.0020.000C] -02B2 ; [.1CC7.0020.0014] -2C7C ; [.1CC7.0020.0015] -1D36 ; [.1CC7.0020.001D] -1F139 ; [.1CC7.0020.001D] -1F179 ; [.1CC7.0020.001D] -0135 ; [.1CC7.0020.0002][.0000.0027.0002] -0134 ; [.1CC7.0020.0008][.0000.0027.0002] -01F0 ; [.1CC7.0020.0002][.0000.0028.0002] -0237 ; [.1CCB.0020.0002] -1D6A5 ; [.1CCB.0020.0005] -1D0A ; [.1CCF.0020.0002] -0249 ; [.1CD0.0020.0002] -0248 ; [.1CD0.0020.0008] -029D ; [.1CD4.0020.0002] -A7B2 ; [.1CD4.0020.0008] -1DA8 ; [.1CD4.0020.0014] -025F ; [.1CD8.0020.0002] -1DA1 ; [.1CD8.0020.0014] -0284 ; [.1CDC.0020.0002] -006B ; [.1CE0.0020.0002] -FF4B ; [.1CE0.0020.0003] -1DDC ; [.1CE0.0020.0004] -24A6 ; [*0310.0020.0004][.1CE0.0020.0004][*0311.0020.0004] -1D424 ; [.1CE0.0020.0005] -1D458 ; [.1CE0.0020.0005] -1D48C ; [.1CE0.0020.0005] -1D4C0 ; [.1CE0.0020.0005] -1D4F4 ; [.1CE0.0020.0005] -1D528 ; [.1CE0.0020.0005] -1D55C ; [.1CE0.0020.0005] -1D590 ; [.1CE0.0020.0005] -1D5C4 ; [.1CE0.0020.0005] -1D5F8 ; [.1CE0.0020.0005] -1D62C ; [.1CE0.0020.0005] -1D660 ; [.1CE0.0020.0005] -1D694 ; [.1CE0.0020.0005] -24DA ; [.1CE0.0020.0006] -004B ; [.1CE0.0020.0008] -212A ; [.1CE0.0020.0008] -FF2B ; [.1CE0.0020.0009] -1F11A ; [*0310.0020.0004][.1CE0.0020.000A][*0311.0020.0004] -1D40A ; [.1CE0.0020.000B] -1D43E ; [.1CE0.0020.000B] -1D472 ; [.1CE0.0020.000B] -1D4A6 ; [.1CE0.0020.000B] -1D4DA ; [.1CE0.0020.000B] -1D50E ; [.1CE0.0020.000B] -1D542 ; [.1CE0.0020.000B] -1D576 ; [.1CE0.0020.000B] -1D5AA ; [.1CE0.0020.000B] -1D5DE ; [.1CE0.0020.000B] -1D612 ; [.1CE0.0020.000B] -1D646 ; [.1CE0.0020.000B] -1D67A ; [.1CE0.0020.000B] -24C0 ; [.1CE0.0020.000C] -1F15A ; [.1CE0.0020.000C] -1D4F ; [.1CE0.0020.0014] -2096 ; [.1CE0.0020.0015] -1D37 ; [.1CE0.0020.001D] -1F13A ; [.1CE0.0020.001D] -1F17A ; [.1CE0.0020.001D] -1E31 ; [.1CE0.0020.0002][.0000.0024.0002] -1E30 ; [.1CE0.0020.0008][.0000.0024.0002] -01E9 ; [.1CE0.0020.0002][.0000.0028.0002] -01E8 ; [.1CE0.0020.0008][.0000.0028.0002] -0137 ; [.1CE0.0020.0002][.0000.0030.0002] -0136 ; [.1CE0.0020.0008][.0000.0030.0002] -A7A3 ; [.1CE0.0020.0004][.0000.0035.0004] -A7A2 ; [.1CE0.0020.000A][.0000.0035.0004] -1E33 ; [.1CE0.0020.0002][.0000.0042.0002] -1E32 ; [.1CE0.0020.0008][.0000.0042.0002] -1E35 ; [.1CE0.0020.0002][.0000.0049.0002] -1E34 ; [.1CE0.0020.0008][.0000.0049.0002] -3384 ; [.1CE0.0020.001C][.1BC2.0020.001D] -3385 ; [.1CE0.0020.001D][.1BDB.0020.001D] -3389 ; [.1CE0.0020.001C][.1BF5.0020.001C][.1BC2.0020.001C][.1CF2.0020.001C] -338F ; [.1CE0.0020.001C][.1C6F.0020.001C] -3391 ; [.1CE0.0020.001C][.1C93.0020.001D][.1E9C.0020.001C] -33CD ; [.1CE0.0020.001D][.1CE0.0020.001D] -3398 ; [.1CE0.0020.001C][.1CF2.0020.001C] -339E ; [.1CE0.0020.001C][.1D25.0020.001C] -33CE ; [.1CE0.0020.001D][.1D25.0020.001D] -33A2 ; [.1CE0.0020.001C][.1D25.0020.001C][.1BBA.0020.001C] -33A6 ; [.1CE0.0020.001C][.1D25.0020.001C][.1BBB.0020.001C] -33AA ; [.1CE0.0020.001C][.1D87.0020.001D][.1BC2.0020.001C] -33CF ; [.1CE0.0020.001C][.1E10.0020.001C] -33B8 ; [.1CE0.0020.001C][.1E5E.0020.001D] -33BE ; [.1CE0.0020.001C][.1E70.0020.001D] -33C0 ; [.1CE0.0020.001C][.1F5C.0020.001D] -1D0B ; [.1CE4.0020.0002] -1D84 ; [.1CE5.0020.0002] -0199 ; [.1CE6.0020.0002] -0198 ; [.1CE6.0020.0008] -2C6A ; [.1CEA.0020.0002] -2C69 ; [.1CEA.0020.0008] -A741 ; [.1CEB.0020.0002] -A740 ; [.1CEB.0020.0008] -A743 ; [.1CEC.0020.0002] -A742 ; [.1CEC.0020.0008] -A745 ; [.1CED.0020.0002] -A744 ; [.1CED.0020.0008] -029E ; [.1CEE.0020.0002] -A7B0 ; [.1CEE.0020.0008] -006C ; [.1CF2.0020.0002] -FF4C ; [.1CF2.0020.0003] -1DDD ; [.1CF2.0020.0004] -217C ; [.1CF2.0020.0004] -24A7 ; [*0310.0020.0004][.1CF2.0020.0004][*0311.0020.0004] -2113 ; [.1CF2.0020.0005] -1D425 ; [.1CF2.0020.0005] -1D459 ; [.1CF2.0020.0005] -1D48D ; [.1CF2.0020.0005] -1D4C1 ; [.1CF2.0020.0005] -1D4F5 ; [.1CF2.0020.0005] -1D529 ; [.1CF2.0020.0005] -1D55D ; [.1CF2.0020.0005] -1D591 ; [.1CF2.0020.0005] -1D5C5 ; [.1CF2.0020.0005] -1D5F9 ; [.1CF2.0020.0005] -1D62D ; [.1CF2.0020.0005] -1D661 ; [.1CF2.0020.0005] -1D695 ; [.1CF2.0020.0005] -24DB ; [.1CF2.0020.0006] -004C ; [.1CF2.0020.0008] -FF2C ; [.1CF2.0020.0009] -216C ; [.1CF2.0020.000A] -1F11B ; [*0310.0020.0004][.1CF2.0020.000A][*0311.0020.0004] -2112 ; [.1CF2.0020.000B] -1D40B ; [.1CF2.0020.000B] -1D43F ; [.1CF2.0020.000B] -1D473 ; [.1CF2.0020.000B] -1D4DB ; [.1CF2.0020.000B] -1D50F ; [.1CF2.0020.000B] -1D543 ; [.1CF2.0020.000B] -1D577 ; [.1CF2.0020.000B] -1D5AB ; [.1CF2.0020.000B] -1D5DF ; [.1CF2.0020.000B] -1D613 ; [.1CF2.0020.000B] -1D647 ; [.1CF2.0020.000B] -1D67B ; [.1CF2.0020.000B] -24C1 ; [.1CF2.0020.000C] -1F15B ; [.1CF2.0020.000C] -02E1 ; [.1CF2.0020.0014] -2097 ; [.1CF2.0020.0015] -1D38 ; [.1CF2.0020.001D] -1F13B ; [.1CF2.0020.001D] -1F17B ; [.1CF2.0020.001D] -013A ; [.1CF2.0020.0002][.0000.0024.0002] -0139 ; [.1CF2.0020.0008][.0000.0024.0002] -013E ; [.1CF2.0020.0002][.0000.0028.0002] -013D ; [.1CF2.0020.0008][.0000.0028.0002] -013C ; [.1CF2.0020.0002][.0000.0030.0002] -013B ; [.1CF2.0020.0008][.0000.0030.0002] -0142 ; [.1CF2.0020.0002][.0000.0039.0002] -0141 ; [.1CF2.0020.0008][.0000.0039.0002] -1E37 ; [.1CF2.0020.0002][.0000.0042.0002] -1E36 ; [.1CF2.0020.0008][.0000.0042.0002] -1E39 ; [.1CF2.0020.0002][.0000.0042.0002][.0000.0032.0002] -1E38 ; [.1CF2.0020.0008][.0000.0042.0002][.0000.0032.0002] -1E3D ; [.1CF2.0020.0002][.0000.0046.0002] -1E3C ; [.1CF2.0020.0008][.0000.0046.0002] -1E3B ; [.1CF2.0020.0002][.0000.0049.0002] -1E3A ; [.1CF2.0020.0008][.0000.0049.0002] -0140 ; [.1CF2.0020.0002][.0000.010B.0002] -006C 00B7 ; [.1CF2.0020.0002][.0000.010B.0002] -006C 0387 ; [.1CF2.0020.0002][.0000.010B.0002] -013F ; [.1CF2.0020.0008][.0000.010B.0002] -004C 00B7 ; [.1CF2.0020.0008][.0000.010B.0002] -004C 0387 ; [.1CF2.0020.0008][.0000.010B.0002] -01C9 ; [.1CF2.0020.0004][.1CC7.0020.0004] -01C8 ; [.1CF2.0020.000A][.1CC7.0020.0004] -01C7 ; [.1CF2.0020.000A][.1CC7.0020.000A] -1EFB ; [.1CF2.0020.0004][.1CF2.0020.0004] -1EFA ; [.1CF2.0020.000A][.1CF2.0020.000A] -33D0 ; [.1CF2.0020.001C][.1D25.0020.001C] -33D1 ; [.1CF2.0020.001C][.1D34.0020.001C] -33D2 ; [.1CF2.0020.001C][.1D58.0020.001C][.1C6F.0020.001C] -02AA ; [.1CF2.0020.0004][.1DEC.0020.0004] -32CF ; [.1CF2.0020.001D][.1E10.0020.001D][.1C0A.0020.001D] -33D3 ; [.1CF2.0020.001C][.1E7A.0020.001C] -02AB ; [.1CF2.0020.0004][.1E9C.0020.0004] -029F ; [.1CF6.0020.0002] -1DDE ; [.1CF6.0020.0004] -1DAB ; [.1CF6.0020.0014] -A747 ; [.1CFA.0020.0002] -A746 ; [.1CFA.0020.0008] -1D0C ; [.1CFB.0020.0002] -A749 ; [.1CFC.0020.0002] -A748 ; [.1CFC.0020.0008] -019A ; [.1CFD.0020.0002] -023D ; [.1CFD.0020.0008] -2C61 ; [.1D01.0020.0002] -2C60 ; [.1D01.0020.0008] -026B ; [.1D02.0020.0002] -2C62 ; [.1D02.0020.0008] -AB5E ; [.1D02.0020.0014] -AB38 ; [.1D06.0020.0002] -1DEC ; [.1D06.0020.0004] -AB39 ; [.1D07.0020.0002] -026C ; [.1D08.0020.0002] -A7AD ; [.1D08.0020.0008] -AB37 ; [.1D0C.0020.0002] -AB5D ; [.1D0C.0020.0014] -1D85 ; [.1D0D.0020.0002] -1DAA ; [.1D0D.0020.0014] -026D ; [.1D0E.0020.0002] -1DA9 ; [.1D0E.0020.0014] -A78E ; [.1D12.0020.0002] -0234 ; [.1D13.0020.0002] -A772 ; [.1D17.0020.0002] -026E ; [.1D18.0020.0002] -A781 ; [.1D1C.0020.0002] -A780 ; [.1D1C.0020.0008] -019B ; [.1D1D.0020.0002] -028E ; [.1D21.0020.0002] -006D ; [.1D25.0020.0002] -FF4D ; [.1D25.0020.0003] -036B ; [.1D25.0020.0004] -217F ; [.1D25.0020.0004] -24A8 ; [*0310.0020.0004][.1D25.0020.0004][*0311.0020.0004] -1D426 ; [.1D25.0020.0005] -1D45A ; [.1D25.0020.0005] -1D48E ; [.1D25.0020.0005] -1D4C2 ; [.1D25.0020.0005] -1D4F6 ; [.1D25.0020.0005] -1D52A ; [.1D25.0020.0005] -1D55E ; [.1D25.0020.0005] -1D592 ; [.1D25.0020.0005] -1D5C6 ; [.1D25.0020.0005] -1D5FA ; [.1D25.0020.0005] -1D62E ; [.1D25.0020.0005] -1D662 ; [.1D25.0020.0005] -1D696 ; [.1D25.0020.0005] -24DC ; [.1D25.0020.0006] -004D ; [.1D25.0020.0008] -FF2D ; [.1D25.0020.0009] -216F ; [.1D25.0020.000A] -1F11C ; [*0310.0020.0004][.1D25.0020.000A][*0311.0020.0004] -2133 ; [.1D25.0020.000B] -1D40C ; [.1D25.0020.000B] -1D440 ; [.1D25.0020.000B] -1D474 ; [.1D25.0020.000B] -1D4DC ; [.1D25.0020.000B] -1D510 ; [.1D25.0020.000B] -1D544 ; [.1D25.0020.000B] -1D578 ; [.1D25.0020.000B] -1D5AC ; [.1D25.0020.000B] -1D5E0 ; [.1D25.0020.000B] -1D614 ; [.1D25.0020.000B] -1D648 ; [.1D25.0020.000B] -1D67C ; [.1D25.0020.000B] -24C2 ; [.1D25.0020.000C] -1F15C ; [.1D25.0020.000C] -1D50 ; [.1D25.0020.0014] -2098 ; [.1D25.0020.0015] -1D39 ; [.1D25.0020.001D] -1F13C ; [.1D25.0020.001D] -1F17C ; [.1D25.0020.001D] -1E3F ; [.1D25.0020.0002][.0000.0024.0002] -1E3E ; [.1D25.0020.0008][.0000.0024.0002] -1E41 ; [.1D25.0020.0002][.0000.002E.0002] -1E40 ; [.1D25.0020.0008][.0000.002E.0002] -1E43 ; [.1D25.0020.0002][.0000.0042.0002] -1E42 ; [.1D25.0020.0008][.0000.0042.0002] -33A1 ; [.1D25.0020.001C][.1BBA.0020.001C] -33A5 ; [.1D25.0020.001C][.1BBB.0020.001C] -3383 ; [.1D25.0020.001C][.1BC2.0020.001D] -33D4 ; [.1D25.0020.001C][.1BDB.0020.001C] -3386 ; [.1D25.0020.001D][.1BDB.0020.001D] -1F16A ; [.1D25.0020.0014][.1BF5.0020.0014] -1F16B ; [.1D25.0020.0014][.1C0A.0020.0014] -338E ; [.1D25.0020.001C][.1C6F.0020.001C] -3392 ; [.1D25.0020.001D][.1C93.0020.001D][.1E9C.0020.001C] -33D5 ; [.1D25.0020.001C][.1CAD.0020.001C][.1CF2.0020.001C] -3396 ; [.1D25.0020.001C][.1CF2.0020.001C] -339C ; [.1D25.0020.001C][.1D25.0020.001C] -339F ; [.1D25.0020.001C][.1D25.0020.001C][.1BBA.0020.001C] -33A3 ; [.1D25.0020.001C][.1D25.0020.001C][.1BBB.0020.001C] -33D6 ; [.1D25.0020.001C][.1D58.0020.001C][.1CF2.0020.001C] -33AB ; [.1D25.0020.001D][.1D87.0020.001D][.1BC2.0020.001C] -33A7 ; [.1D25.0020.001C][*0605.0020.001C][.1DEC.0020.001C] -33B3 ; [.1D25.0020.001C][.1DEC.0020.001C] -33A8 ; [.1D25.0020.001C][*0605.0020.001C][.1DEC.0020.001C][.1BBA.0020.001C] -33B7 ; [.1D25.0020.001C][.1E5E.0020.001D] -33B9 ; [.1D25.0020.001D][.1E5E.0020.001D] -1F14B ; [.1D25.0020.001D][.1E5E.0020.001D] -33BD ; [.1D25.0020.001C][.1E70.0020.001D] -33BF ; [.1D25.0020.001D][.1E70.0020.001D] -33C1 ; [.1D25.0020.001D][.1F5C.0020.001D] -1D0D ; [.1D29.0020.0002] -1DDF ; [.1D29.0020.0004] -1D6F ; [.1D2A.0020.0002] -1D86 ; [.1D2B.0020.0002] -0271 ; [.1D2C.0020.0002] -2C6E ; [.1D2C.0020.0008] -1DAC ; [.1D2C.0020.0014] -AB3A ; [.1D30.0020.0002] -A7FD ; [.1D31.0020.0002] -A7FF ; [.1D32.0020.0002] -A773 ; [.1D33.0020.0002] -006E ; [.1D34.0020.0002] -FF4E ; [.1D34.0020.0003] -1DE0 ; [.1D34.0020.0004] -24A9 ; [*0310.0020.0004][.1D34.0020.0004][*0311.0020.0004] -1D427 ; [.1D34.0020.0005] -1D45B ; [.1D34.0020.0005] -1D48F ; [.1D34.0020.0005] -1D4C3 ; [.1D34.0020.0005] -1D4F7 ; [.1D34.0020.0005] -1D52B ; [.1D34.0020.0005] -1D55F ; [.1D34.0020.0005] -1D593 ; [.1D34.0020.0005] -1D5C7 ; [.1D34.0020.0005] -1D5FB ; [.1D34.0020.0005] -1D62F ; [.1D34.0020.0005] -1D663 ; [.1D34.0020.0005] -1D697 ; [.1D34.0020.0005] -24DD ; [.1D34.0020.0006] -004E ; [.1D34.0020.0008] -FF2E ; [.1D34.0020.0009] -1F11D ; [*0310.0020.0004][.1D34.0020.000A][*0311.0020.0004] -2115 ; [.1D34.0020.000B] -1D40D ; [.1D34.0020.000B] -1D441 ; [.1D34.0020.000B] -1D475 ; [.1D34.0020.000B] -1D4A9 ; [.1D34.0020.000B] -1D4DD ; [.1D34.0020.000B] -1D511 ; [.1D34.0020.000B] -1D579 ; [.1D34.0020.000B] -1D5AD ; [.1D34.0020.000B] -1D5E1 ; [.1D34.0020.000B] -1D615 ; [.1D34.0020.000B] -1D649 ; [.1D34.0020.000B] -1D67D ; [.1D34.0020.000B] -24C3 ; [.1D34.0020.000C] -1F15D ; [.1D34.0020.000C] -207F ; [.1D34.0020.0014] -2099 ; [.1D34.0020.0015] -1D3A ; [.1D34.0020.001D] -1F13D ; [.1D34.0020.001D] -1F17D ; [.1D34.0020.001D] -0144 ; [.1D34.0020.0002][.0000.0024.0002] -0143 ; [.1D34.0020.0008][.0000.0024.0002] -01F9 ; [.1D34.0020.0002][.0000.0025.0002] -01F8 ; [.1D34.0020.0008][.0000.0025.0002] -0148 ; [.1D34.0020.0002][.0000.0028.0002] -0147 ; [.1D34.0020.0008][.0000.0028.0002] -00F1 ; [.1D34.0020.0002][.0000.002D.0002] -00D1 ; [.1D34.0020.0008][.0000.002D.0002] -1E45 ; [.1D34.0020.0002][.0000.002E.0002] -1E44 ; [.1D34.0020.0008][.0000.002E.0002] -0146 ; [.1D34.0020.0002][.0000.0030.0002] -0145 ; [.1D34.0020.0008][.0000.0030.0002] -A7A5 ; [.1D34.0020.0004][.0000.0035.0004] -A7A4 ; [.1D34.0020.000A][.0000.0035.0004] -1E47 ; [.1D34.0020.0002][.0000.0042.0002] -1E46 ; [.1D34.0020.0008][.0000.0042.0002] -1E4B ; [.1D34.0020.0002][.0000.0046.0002] -1E4A ; [.1D34.0020.0008][.0000.0046.0002] -1E49 ; [.1D34.0020.0002][.0000.0049.0002] -1E48 ; [.1D34.0020.0008][.0000.0049.0002] -3381 ; [.1D34.0020.001C][.1BC2.0020.001D] -1F195 ; [.1D34.0020.001D][.1C25.0020.001D][.1E70.0020.001D] -338B ; [.1D34.0020.001C][.1C60.0020.001D] -1F196 ; [.1D34.0020.001D][.1C6F.0020.001D] -01CC ; [.1D34.0020.0004][.1CC7.0020.0004] -01CB ; [.1D34.0020.000A][.1CC7.0020.0004] -01CA ; [.1D34.0020.000A][.1CC7.0020.000A] -339A ; [.1D34.0020.001C][.1D25.0020.001C] -2116 ; [.1D34.0020.000A][.1D58.0020.0004] -33B1 ; [.1D34.0020.001C][.1DEC.0020.001C] -33B5 ; [.1D34.0020.001C][.1E5E.0020.001D] -33BB ; [.1D34.0020.001C][.1E70.0020.001D] -0274 ; [.1D38.0020.0002] -1DE1 ; [.1D38.0020.0004] -1DB0 ; [.1D38.0020.0014] -1D3B ; [.1D3C.0020.0002] -1D0E ; [.1D3D.0020.0002] -1D70 ; [.1D3E.0020.0002] -0272 ; [.1D3F.0020.0002] -019D ; [.1D3F.0020.0008] -1DAE ; [.1D3F.0020.0014] -019E ; [.1D43.0020.0002] -0220 ; [.1D43.0020.0008] -A791 ; [.1D47.0020.0002] -A790 ; [.1D47.0020.0008] -1D87 ; [.1D48.0020.0002] -0273 ; [.1D49.0020.0002] -1DAF ; [.1D49.0020.0014] -0235 ; [.1D4D.0020.0002] -AB3B ; [.1D51.0020.0002] -A774 ; [.1D52.0020.0002] -014B ; [.1D53.0020.0002] -014A ; [.1D53.0020.0008] -1D51 ; [.1D53.0020.0014] -AB3C ; [.1D57.0020.0002] -006F ; [.1D58.0020.0002] -FF4F ; [.1D58.0020.0003] -0366 ; [.1D58.0020.0004] -24AA ; [*0310.0020.0004][.1D58.0020.0004][*0311.0020.0004] -2134 ; [.1D58.0020.0005] -1D428 ; [.1D58.0020.0005] -1D45C ; [.1D58.0020.0005] -1D490 ; [.1D58.0020.0005] -1D4F8 ; [.1D58.0020.0005] -1D52C ; [.1D58.0020.0005] -1D560 ; [.1D58.0020.0005] -1D594 ; [.1D58.0020.0005] -1D5C8 ; [.1D58.0020.0005] -1D5FC ; [.1D58.0020.0005] -1D630 ; [.1D58.0020.0005] -1D664 ; [.1D58.0020.0005] -1D698 ; [.1D58.0020.0005] -24DE ; [.1D58.0020.0006] -004F ; [.1D58.0020.0008] -FF2F ; [.1D58.0020.0009] -1F11E ; [*0310.0020.0004][.1D58.0020.000A][*0311.0020.0004] -1D40E ; [.1D58.0020.000B] -1D442 ; [.1D58.0020.000B] -1D476 ; [.1D58.0020.000B] -1D4AA ; [.1D58.0020.000B] -1D4DE ; [.1D58.0020.000B] -1D512 ; [.1D58.0020.000B] -1D546 ; [.1D58.0020.000B] -1D57A ; [.1D58.0020.000B] -1D5AE ; [.1D58.0020.000B] -1D5E2 ; [.1D58.0020.000B] -1D616 ; [.1D58.0020.000B] -1D64A ; [.1D58.0020.000B] -1D67E ; [.1D58.0020.000B] -24C4 ; [.1D58.0020.000C] -1F15E ; [.1D58.0020.000C] -00BA ; [.1D58.0020.0014] -1D52 ; [.1D58.0020.0014] -2092 ; [.1D58.0020.0015] -1D3C ; [.1D58.0020.001D] -1F13E ; [.1D58.0020.001D] -1F17E ; [.1D58.0020.001D] -00F3 ; [.1D58.0020.0002][.0000.0024.0002] -00D3 ; [.1D58.0020.0008][.0000.0024.0002] -00F2 ; [.1D58.0020.0002][.0000.0025.0002] -00D2 ; [.1D58.0020.0008][.0000.0025.0002] -014F ; [.1D58.0020.0002][.0000.0026.0002] -014E ; [.1D58.0020.0008][.0000.0026.0002] -00F4 ; [.1D58.0020.0002][.0000.0027.0002] -00D4 ; [.1D58.0020.0008][.0000.0027.0002] -1ED1 ; [.1D58.0020.0002][.0000.0027.0002][.0000.0024.0002] -1ED0 ; [.1D58.0020.0008][.0000.0027.0002][.0000.0024.0002] -1ED3 ; [.1D58.0020.0002][.0000.0027.0002][.0000.0025.0002] -1ED2 ; [.1D58.0020.0008][.0000.0027.0002][.0000.0025.0002] -1ED7 ; [.1D58.0020.0002][.0000.0027.0002][.0000.002D.0002] -1ED6 ; [.1D58.0020.0008][.0000.0027.0002][.0000.002D.0002] -1ED5 ; [.1D58.0020.0002][.0000.0027.0002][.0000.003B.0002] -1ED4 ; [.1D58.0020.0008][.0000.0027.0002][.0000.003B.0002] -01D2 ; [.1D58.0020.0002][.0000.0028.0002] -01D1 ; [.1D58.0020.0008][.0000.0028.0002] -00F6 ; [.1D58.0020.0002][.0000.002B.0002] -1DF3 ; [.1D58.0020.0004][.0000.002B.0004] -A79D ; [.1D58.0020.0004][.0000.002B.0004] -00D6 ; [.1D58.0020.0008][.0000.002B.0002] -A79C ; [.1D58.0020.000A][.0000.002B.0004] -022B ; [.1D58.0020.0002][.0000.002B.0002][.0000.0032.0002] -022A ; [.1D58.0020.0008][.0000.002B.0002][.0000.0032.0002] -0151 ; [.1D58.0020.0002][.0000.002C.0002] -0150 ; [.1D58.0020.0008][.0000.002C.0002] -00F5 ; [.1D58.0020.0002][.0000.002D.0002] -00D5 ; [.1D58.0020.0008][.0000.002D.0002] -1E4D ; [.1D58.0020.0002][.0000.002D.0002][.0000.0024.0002] -1E4C ; [.1D58.0020.0008][.0000.002D.0002][.0000.0024.0002] -1E4F ; [.1D58.0020.0002][.0000.002D.0002][.0000.002B.0002] -1E4E ; [.1D58.0020.0008][.0000.002D.0002][.0000.002B.0002] -022D ; [.1D58.0020.0002][.0000.002D.0002][.0000.0032.0002] -022C ; [.1D58.0020.0008][.0000.002D.0002][.0000.0032.0002] -022F ; [.1D58.0020.0002][.0000.002E.0002] -022E ; [.1D58.0020.0008][.0000.002E.0002] -0231 ; [.1D58.0020.0002][.0000.002E.0002][.0000.0032.0002] -0230 ; [.1D58.0020.0008][.0000.002E.0002][.0000.0032.0002] -00F8 ; [.1D58.0020.0002][.0000.002F.0002] -00D8 ; [.1D58.0020.0008][.0000.002F.0002] -01FF ; [.1D58.0020.0002][.0000.002F.0002][.0000.0024.0002] -01FE ; [.1D58.0020.0008][.0000.002F.0002][.0000.0024.0002] -01EB ; [.1D58.0020.0002][.0000.0031.0002] -01EA ; [.1D58.0020.0008][.0000.0031.0002] -01ED ; [.1D58.0020.0002][.0000.0031.0002][.0000.0032.0002] -01EC ; [.1D58.0020.0008][.0000.0031.0002][.0000.0032.0002] -014D ; [.1D58.0020.0002][.0000.0032.0002] -014C ; [.1D58.0020.0008][.0000.0032.0002] -1E53 ; [.1D58.0020.0002][.0000.0032.0002][.0000.0024.0002] -1E52 ; [.1D58.0020.0008][.0000.0032.0002][.0000.0024.0002] -1E51 ; [.1D58.0020.0002][.0000.0032.0002][.0000.0025.0002] -1E50 ; [.1D58.0020.0008][.0000.0032.0002][.0000.0025.0002] -1DED ; [.1D58.0020.0004][.0000.0034.0004] -1ECF ; [.1D58.0020.0002][.0000.003B.0002] -1ECE ; [.1D58.0020.0008][.0000.003B.0002] -020D ; [.1D58.0020.0002][.0000.003C.0002] -020C ; [.1D58.0020.0008][.0000.003C.0002] -020F ; [.1D58.0020.0002][.0000.003E.0002] -020E ; [.1D58.0020.0008][.0000.003E.0002] -01A1 ; [.1D58.0020.0002][.0000.003F.0002] -01A0 ; [.1D58.0020.0008][.0000.003F.0002] -1EDB ; [.1D58.0020.0002][.0000.003F.0002][.0000.0024.0002] -1EDA ; [.1D58.0020.0008][.0000.003F.0002][.0000.0024.0002] -1EDD ; [.1D58.0020.0002][.0000.003F.0002][.0000.0025.0002] -1EDC ; [.1D58.0020.0008][.0000.003F.0002][.0000.0025.0002] -1EE1 ; [.1D58.0020.0002][.0000.003F.0002][.0000.002D.0002] -1EE0 ; [.1D58.0020.0008][.0000.003F.0002][.0000.002D.0002] -1EDF ; [.1D58.0020.0002][.0000.003F.0002][.0000.003B.0002] -1EDE ; [.1D58.0020.0008][.0000.003F.0002][.0000.003B.0002] -1EE3 ; [.1D58.0020.0002][.0000.003F.0002][.0000.0042.0002] -1EE2 ; [.1D58.0020.0008][.0000.003F.0002][.0000.0042.0002] -1ECD ; [.1D58.0020.0002][.0000.0042.0002] -1ECC ; [.1D58.0020.0008][.0000.0042.0002] -1ED9 ; [.1D58.0020.0002][.0000.0042.0002][.0000.0027.0002] -1ED8 ; [.1D58.0020.0008][.0000.0042.0002][.0000.0027.0002] -0153 ; [.1D58.0020.0004][.0000.010B.0004][.1C25.0020.0004] -0152 ; [.1D58.0020.000A][.0000.010B.0004][.1C25.0020.000A] -A7F9 ; [.1D58.0020.0014][.0000.010B.0014][.1C25.0020.0014] -1F197 ; [.1D58.0020.001D][.1CE0.0020.001D] -A74F ; [.1D58.0020.0004][.1D58.0020.0004] -A74E ; [.1D58.0020.000A][.1D58.0020.000A] -3375 ; [.1D58.0020.001C][.1E5E.0020.001D] -1D0F ; [.1D5C.0020.0002] -1D11 ; [.1D5D.0020.0002] -AB3D ; [.1D5E.0020.0002] -0276 ; [.1D5F.0020.0002] -1D14 ; [.1D63.0020.0002] -AB41 ; [.1D64.0020.0002] -AB42 ; [.1D65.0020.0002] -AB40 ; [.1D66.0020.0002] -AB43 ; [.1D67.0020.0002] -AB44 ; [.1D68.0020.0002] -1D13 ; [.1D69.0020.0002] -AB3E ; [.1D6A.0020.0002] -0254 ; [.1D6B.0020.0002] -0186 ; [.1D6B.0020.0008] -1D53 ; [.1D6B.0020.0014] -1D10 ; [.1D6F.0020.0002] -1D12 ; [.1D70.0020.0002] -AB3F ; [.1D71.0020.0002] -1D97 ; [.1D72.0020.0002] -AB62 ; [.1D73.0020.0002] -A74D ; [.1D74.0020.0002] -A74C ; [.1D74.0020.0008] -1D16 ; [.1D75.0020.0002] -1D54 ; [.1D75.0020.0014] -1D17 ; [.1D76.0020.0002] -1D55 ; [.1D76.0020.0014] -2C7A ; [.1D77.0020.0002] -0275 ; [.1D78.0020.0002] -019F ; [.1D78.0020.0008] -1DB1 ; [.1D78.0020.0014] -A74B ; [.1D7C.0020.0002] -A74A ; [.1D7C.0020.0008] -0277 ; [.1D7D.0020.0002] -A7B7 ; [.1D81.0020.0002] -A7B6 ; [.1D81.0020.0008] -0223 ; [.1D82.0020.0002] -0222 ; [.1D82.0020.0008] -1D3D ; [.1D82.0020.001D] -1D15 ; [.1D86.0020.0002] -0070 ; [.1D87.0020.0002] -FF50 ; [.1D87.0020.0003] -1DEE ; [.1D87.0020.0004] -24AB ; [*0310.0020.0004][.1D87.0020.0004][*0311.0020.0004] -1D429 ; [.1D87.0020.0005] -1D45D ; [.1D87.0020.0005] -1D491 ; [.1D87.0020.0005] -1D4C5 ; [.1D87.0020.0005] -1D4F9 ; [.1D87.0020.0005] -1D52D ; [.1D87.0020.0005] -1D561 ; [.1D87.0020.0005] -1D595 ; [.1D87.0020.0005] -1D5C9 ; [.1D87.0020.0005] -1D5FD ; [.1D87.0020.0005] -1D631 ; [.1D87.0020.0005] -1D665 ; [.1D87.0020.0005] -1D699 ; [.1D87.0020.0005] -24DF ; [.1D87.0020.0006] -0050 ; [.1D87.0020.0008] -FF30 ; [.1D87.0020.0009] -1F11F ; [*0310.0020.0004][.1D87.0020.000A][*0311.0020.0004] -2119 ; [.1D87.0020.000B] -1D40F ; [.1D87.0020.000B] -1D443 ; [.1D87.0020.000B] -1D477 ; [.1D87.0020.000B] -1D4AB ; [.1D87.0020.000B] -1D4DF ; [.1D87.0020.000B] -1D513 ; [.1D87.0020.000B] -1D57B ; [.1D87.0020.000B] -1D5AF ; [.1D87.0020.000B] -1D5E3 ; [.1D87.0020.000B] -1D617 ; [.1D87.0020.000B] -1D64B ; [.1D87.0020.000B] -1D67F ; [.1D87.0020.000B] -24C5 ; [.1D87.0020.000C] -1F15F ; [.1D87.0020.000C] -1D56 ; [.1D87.0020.0014] -209A ; [.1D87.0020.0015] -1D3E ; [.1D87.0020.001D] -1F13F ; [.1D87.0020.001D] -1F17F ; [.1D87.0020.001D] -1F18A ; [.1D87.0020.001D] -1E55 ; [.1D87.0020.0002][.0000.0024.0002] -1E54 ; [.1D87.0020.0008][.0000.0024.0002] -1E57 ; [.1D87.0020.0002][.0000.002E.0002] -1E56 ; [.1D87.0020.0008][.0000.002E.0002] -3380 ; [.1D87.0020.001C][.1BC2.0020.001D] -33A9 ; [.1D87.0020.001D][.1BC2.0020.001C] -1F18C ; [.1D87.0020.001D][.1BC2.0020.001D] -3376 ; [.1D87.0020.001C][.1BF5.0020.001C] -338A ; [.1D87.0020.001C][.1C60.0020.001D] -33D7 ; [.1D87.0020.001D][.1C93.0020.001D] -33D8 ; [.1D87.0020.001C][*0274.0020.001C][.1D25.0020.001C][*0274.0020.001C] -33D9 ; [.1D87.0020.001D][.1D87.0020.001D][.1D25.0020.001D] -1F14E ; [.1D87.0020.001D][.1D87.0020.001D][.1E5E.0020.001D] -33DA ; [.1D87.0020.001D][.1DAE.0020.001D] -33B0 ; [.1D87.0020.001C][.1DEC.0020.001C] -3250 ; [.1D87.0020.001D][.1E10.0020.001D][.1C25.0020.001D] -33B4 ; [.1D87.0020.001C][.1E5E.0020.001D] -33BA ; [.1D87.0020.001C][.1E70.0020.001D] -1D18 ; [.1D8B.0020.0002] -1D7D ; [.1D8C.0020.0002] -2C63 ; [.1D8C.0020.0008] -A751 ; [.1D8D.0020.0002] -A750 ; [.1D8D.0020.0008] -1D71 ; [.1D8E.0020.0002] -1D88 ; [.1D8F.0020.0002] -01A5 ; [.1D90.0020.0002] -01A4 ; [.1D90.0020.0008] -A753 ; [.1D94.0020.0002] -A752 ; [.1D94.0020.0008] -A755 ; [.1D95.0020.0002] -A754 ; [.1D95.0020.0008] -A7FC ; [.1D96.0020.0002] -0278 ; [.1D97.0020.0002] -1DB2 ; [.1D97.0020.0014] -2C77 ; [.1D9B.0020.0002] -0071 ; [.1D9C.0020.0002] -FF51 ; [.1D9C.0020.0003] -24AC ; [*0310.0020.0004][.1D9C.0020.0004][*0311.0020.0004] -1D42A ; [.1D9C.0020.0005] -1D45E ; [.1D9C.0020.0005] -1D492 ; [.1D9C.0020.0005] -1D4C6 ; [.1D9C.0020.0005] -1D4FA ; [.1D9C.0020.0005] -1D52E ; [.1D9C.0020.0005] -1D562 ; [.1D9C.0020.0005] -1D596 ; [.1D9C.0020.0005] -1D5CA ; [.1D9C.0020.0005] -1D5FE ; [.1D9C.0020.0005] -1D632 ; [.1D9C.0020.0005] -1D666 ; [.1D9C.0020.0005] -1D69A ; [.1D9C.0020.0005] -24E0 ; [.1D9C.0020.0006] -0051 ; [.1D9C.0020.0008] -FF31 ; [.1D9C.0020.0009] -1F120 ; [*0310.0020.0004][.1D9C.0020.000A][*0311.0020.0004] -211A ; [.1D9C.0020.000B] -1D410 ; [.1D9C.0020.000B] -1D444 ; [.1D9C.0020.000B] -1D478 ; [.1D9C.0020.000B] -1D4AC ; [.1D9C.0020.000B] -1D4E0 ; [.1D9C.0020.000B] -1D514 ; [.1D9C.0020.000B] -1D57C ; [.1D9C.0020.000B] -1D5B0 ; [.1D9C.0020.000B] -1D5E4 ; [.1D9C.0020.000B] -1D618 ; [.1D9C.0020.000B] -1D64C ; [.1D9C.0020.000B] -1D680 ; [.1D9C.0020.000B] -24C6 ; [.1D9C.0020.000C] -1F160 ; [.1D9C.0020.000C] -1F140 ; [.1D9C.0020.001D] -1F180 ; [.1D9C.0020.001D] -0239 ; [.1D9C.0020.0004][.1D87.0020.0004] -A757 ; [.1DA0.0020.0002] -A756 ; [.1DA0.0020.0008] -A759 ; [.1DA1.0020.0002] -A758 ; [.1DA1.0020.0008] -02A0 ; [.1DA2.0020.0002] -024B ; [.1DA6.0020.0002] -024A ; [.1DA6.0020.0008] -0138 ; [.1DAA.0020.0002] -0072 ; [.1DAE.0020.0002] -FF52 ; [.1DAE.0020.0003] -036C ; [.1DAE.0020.0004] -1DCA ; [.1DAE.0020.0004] -24AD ; [*0310.0020.0004][.1DAE.0020.0004][*0311.0020.0004] -1D42B ; [.1DAE.0020.0005] -1D45F ; [.1DAE.0020.0005] -1D493 ; [.1DAE.0020.0005] -1D4C7 ; [.1DAE.0020.0005] -1D4FB ; [.1DAE.0020.0005] -1D52F ; [.1DAE.0020.0005] -1D563 ; [.1DAE.0020.0005] -1D597 ; [.1DAE.0020.0005] -1D5CB ; [.1DAE.0020.0005] -1D5FF ; [.1DAE.0020.0005] -1D633 ; [.1DAE.0020.0005] -1D667 ; [.1DAE.0020.0005] -1D69B ; [.1DAE.0020.0005] -24E1 ; [.1DAE.0020.0006] -0052 ; [.1DAE.0020.0008] -FF32 ; [.1DAE.0020.0009] -1F121 ; [*0310.0020.0004][.1DAE.0020.000A][*0311.0020.0004] -211B ; [.1DAE.0020.000B] -211C ; [.1DAE.0020.000B] -211D ; [.1DAE.0020.000B] -1D411 ; [.1DAE.0020.000B] -1D445 ; [.1DAE.0020.000B] -1D479 ; [.1DAE.0020.000B] -1D4E1 ; [.1DAE.0020.000B] -1D57D ; [.1DAE.0020.000B] -1D5B1 ; [.1DAE.0020.000B] -1D5E5 ; [.1DAE.0020.000B] -1D619 ; [.1DAE.0020.000B] -1D64D ; [.1DAE.0020.000B] -1D681 ; [.1DAE.0020.000B] -24C7 ; [.1DAE.0020.000C] -1F12C ; [.1DAE.0020.000C] -1F161 ; [.1DAE.0020.000C] -02B3 ; [.1DAE.0020.0014] -1D63 ; [.1DAE.0020.0015] -1D3F ; [.1DAE.0020.001D] -1F141 ; [.1DAE.0020.001D] -1F181 ; [.1DAE.0020.001D] -0155 ; [.1DAE.0020.0002][.0000.0024.0002] -0154 ; [.1DAE.0020.0008][.0000.0024.0002] -0159 ; [.1DAE.0020.0002][.0000.0028.0002] -0158 ; [.1DAE.0020.0008][.0000.0028.0002] -1E59 ; [.1DAE.0020.0002][.0000.002E.0002] -1E58 ; [.1DAE.0020.0008][.0000.002E.0002] -0157 ; [.1DAE.0020.0002][.0000.0030.0002] -0156 ; [.1DAE.0020.0008][.0000.0030.0002] -A7A7 ; [.1DAE.0020.0004][.0000.0035.0004] -A7A6 ; [.1DAE.0020.000A][.0000.0035.0004] -0211 ; [.1DAE.0020.0002][.0000.003C.0002] -0210 ; [.1DAE.0020.0008][.0000.003C.0002] -0213 ; [.1DAE.0020.0002][.0000.003E.0002] -0212 ; [.1DAE.0020.0008][.0000.003E.0002] -1E5B ; [.1DAE.0020.0002][.0000.0042.0002] -1E5A ; [.1DAE.0020.0008][.0000.0042.0002] -1E5D ; [.1DAE.0020.0002][.0000.0042.0002][.0000.0032.0002] -1E5C ; [.1DAE.0020.0008][.0000.0042.0002][.0000.0032.0002] -1E5F ; [.1DAE.0020.0002][.0000.0049.0002] -1E5E ; [.1DAE.0020.0008][.0000.0049.0002] -A783 ; [.1DAE.0020.0004][.0000.010C.0004] -A782 ; [.1DAE.0020.000A][.0000.010C.0004] -33AD ; [.1DAE.0020.001C][.1BC2.0020.001C][.1C0A.0020.001C] -33AE ; [.1DAE.0020.001C][.1BC2.0020.001C][.1C0A.0020.001C][*0605.0020.001C][.1DEC.0020.001C] -33AF ; [.1DAE.0020.001C][.1BC2.0020.001C][.1C0A.0020.001C][*0605.0020.001C][.1DEC.0020.001C][.1BBA.0020.001C] -20A8 ; [.1DAE.0020.000A][.1DEC.0020.0004] -AB45 ; [.1DB2.0020.0002] -0280 ; [.1DB3.0020.0002] -1DE2 ; [.1DB3.0020.0004] -01A6 ; [.1DB3.0020.0008] -AB46 ; [.1DB7.0020.0002] -A75B ; [.1DB8.0020.0002] -1DE3 ; [.1DB8.0020.0004] -A75A ; [.1DB8.0020.0008] -1D19 ; [.1DB9.0020.0002] -024D ; [.1DBA.0020.0002] -024C ; [.1DBA.0020.0008] -1D72 ; [.1DBE.0020.0002] -0279 ; [.1DBF.0020.0002] -02B4 ; [.1DBF.0020.0014] -1D1A ; [.1DC3.0020.0002] -027A ; [.1DC4.0020.0002] -1D89 ; [.1DC8.0020.0002] -027B ; [.1DC9.0020.0002] -02B5 ; [.1DC9.0020.0014] -2C79 ; [.1DCD.0020.0002] -027C ; [.1DCE.0020.0002] -027D ; [.1DD2.0020.0002] -2C64 ; [.1DD2.0020.0008] -AB49 ; [.1DD6.0020.0002] -027E ; [.1DD7.0020.0002] -1D73 ; [.1DDB.0020.0002] -027F ; [.1DDC.0020.0002] -AB47 ; [.1DE0.0020.0002] -AB48 ; [.1DE1.0020.0002] -AB4A ; [.1DE2.0020.0002] -AB4B ; [.1DE3.0020.0002] -AB4C ; [.1DE4.0020.0002] -0281 ; [.1DE5.0020.0002] -02B6 ; [.1DE5.0020.0014] -A775 ; [.1DE9.0020.0002] -A776 ; [.1DEA.0020.0002] -A75D ; [.1DEB.0020.0002] -A75C ; [.1DEB.0020.0008] -0073 ; [.1DEC.0020.0002] -FF53 ; [.1DEC.0020.0003] -1DE4 ; [.1DEC.0020.0004] -24AE ; [*0310.0020.0004][.1DEC.0020.0004][*0311.0020.0004] -1D42C ; [.1DEC.0020.0005] -1D460 ; [.1DEC.0020.0005] -1D494 ; [.1DEC.0020.0005] -1D4C8 ; [.1DEC.0020.0005] -1D4FC ; [.1DEC.0020.0005] -1D530 ; [.1DEC.0020.0005] -1D564 ; [.1DEC.0020.0005] -1D598 ; [.1DEC.0020.0005] -1D5CC ; [.1DEC.0020.0005] -1D600 ; [.1DEC.0020.0005] -1D634 ; [.1DEC.0020.0005] -1D668 ; [.1DEC.0020.0005] -1D69C ; [.1DEC.0020.0005] -24E2 ; [.1DEC.0020.0006] -0053 ; [.1DEC.0020.0008] -FF33 ; [.1DEC.0020.0009] -1F122 ; [*0310.0020.0004][.1DEC.0020.000A][*0311.0020.0004] -1F12A ; [*0372.0020.0004][.1DEC.0020.000A][*0373.0020.0004] -1D412 ; [.1DEC.0020.000B] -1D446 ; [.1DEC.0020.000B] -1D47A ; [.1DEC.0020.000B] -1D4AE ; [.1DEC.0020.000B] -1D4E2 ; [.1DEC.0020.000B] -1D516 ; [.1DEC.0020.000B] -1D54A ; [.1DEC.0020.000B] -1D57E ; [.1DEC.0020.000B] -1D5B2 ; [.1DEC.0020.000B] -1D5E6 ; [.1DEC.0020.000B] -1D61A ; [.1DEC.0020.000B] -1D64E ; [.1DEC.0020.000B] -1D682 ; [.1DEC.0020.000B] -24C8 ; [.1DEC.0020.000C] -1F162 ; [.1DEC.0020.000C] -02E2 ; [.1DEC.0020.0014] -209B ; [.1DEC.0020.0015] -1F142 ; [.1DEC.0020.001D] -1F182 ; [.1DEC.0020.001D] -015B ; [.1DEC.0020.0002][.0000.0024.0002] -015A ; [.1DEC.0020.0008][.0000.0024.0002] -1E65 ; [.1DEC.0020.0002][.0000.0024.0002][.0000.002E.0002] -1E64 ; [.1DEC.0020.0008][.0000.0024.0002][.0000.002E.0002] -015D ; [.1DEC.0020.0002][.0000.0027.0002] -015C ; [.1DEC.0020.0008][.0000.0027.0002] -0161 ; [.1DEC.0020.0002][.0000.0028.0002] -0160 ; [.1DEC.0020.0008][.0000.0028.0002] -1E67 ; [.1DEC.0020.0002][.0000.0028.0002][.0000.002E.0002] -1E66 ; [.1DEC.0020.0008][.0000.0028.0002][.0000.002E.0002] -1E61 ; [.1DEC.0020.0002][.0000.002E.0002] -1E60 ; [.1DEC.0020.0008][.0000.002E.0002] -015F ; [.1DEC.0020.0002][.0000.0030.0002] -015E ; [.1DEC.0020.0008][.0000.0030.0002] -A7A9 ; [.1DEC.0020.0004][.0000.0035.0004] -A7A8 ; [.1DEC.0020.000A][.0000.0035.0004] -1E63 ; [.1DEC.0020.0002][.0000.0042.0002] -1E62 ; [.1DEC.0020.0008][.0000.0042.0002] -1E69 ; [.1DEC.0020.0002][.0000.0042.0002][.0000.002E.0002] -1E68 ; [.1DEC.0020.0008][.0000.0042.0002][.0000.002E.0002] -0219 ; [.1DEC.0020.0002][.0000.0045.0002] -0218 ; [.1DEC.0020.0008][.0000.0045.0002] -017F ; [.1DEC.0020.0004][.0000.010C.0004] -1DE5 ; [.1DEC.0020.0004][.0000.010C.0004] -A785 ; [.1DEC.0020.0004][.0000.010C.0004] -A784 ; [.1DEC.0020.000A][.0000.010C.0004] -1E9B ; [.1DEC.0020.0004][.0000.010C.0004][.0000.002E.0002] -1F18D ; [.1DEC.0020.001D][.1BC2.0020.001D] -1F14C ; [.1DEC.0020.001D][.1C0A.0020.001D] -2120 ; [.1DEC.0020.0014][.1D25.0020.0014] -1F198 ; [.1DEC.0020.001D][.1D58.0020.001D][.1DEC.0020.001D] -33DB ; [.1DEC.0020.001C][.1DAE.0020.001C] -1F14D ; [.1DEC.0020.001D][.1DEC.0020.001D] -00DF ; [.1DEC.0020.0004][.0000.010B.0004][.1DEC.0020.0004] -1E9E ; [.1DEC.0020.000A][.0000.010B.0004][.1DEC.0020.000A] -FB06 ; [.1DEC.0020.0004][.1E10.0020.0004] -FB05 ; [.1DEC.0020.0004][.0000.010C.0004][.1E10.0020.0004] -33DC ; [.1DEC.0020.001D][.1E5E.0020.001C] -A731 ; [.1DF0.0020.0002] -1D74 ; [.1DF1.0020.0002] -1D8A ; [.1DF2.0020.0002] -0282 ; [.1DF3.0020.0002] -1DB3 ; [.1DF3.0020.0014] -023F ; [.1DF7.0020.0002] -2C7E ; [.1DF7.0020.0008] -1E9C ; [.1DFB.0020.0002] -1E9D ; [.1DFC.0020.0002] -0283 ; [.1DFD.0020.0002] -1DEF ; [.1DFD.0020.0004] -01A9 ; [.1DFD.0020.0008] -1DB4 ; [.1DFD.0020.0014] -AB4D ; [.1E01.0020.0002] -1D8B ; [.1E02.0020.0002] -01AA ; [.1E03.0020.0002] -0285 ; [.1E07.0020.0002] -1D98 ; [.1E0B.0020.0002] -0286 ; [.1E0C.0020.0002] -0074 ; [.1E10.0020.0002] -FF54 ; [.1E10.0020.0003] -036D ; [.1E10.0020.0004] -24AF ; [*0310.0020.0004][.1E10.0020.0004][*0311.0020.0004] -1D42D ; [.1E10.0020.0005] -1D461 ; [.1E10.0020.0005] -1D495 ; [.1E10.0020.0005] -1D4C9 ; [.1E10.0020.0005] -1D4FD ; [.1E10.0020.0005] -1D531 ; [.1E10.0020.0005] -1D565 ; [.1E10.0020.0005] -1D599 ; [.1E10.0020.0005] -1D5CD ; [.1E10.0020.0005] -1D601 ; [.1E10.0020.0005] -1D635 ; [.1E10.0020.0005] -1D669 ; [.1E10.0020.0005] -1D69D ; [.1E10.0020.0005] -24E3 ; [.1E10.0020.0006] -0054 ; [.1E10.0020.0008] -FF34 ; [.1E10.0020.0009] -1F123 ; [*0310.0020.0004][.1E10.0020.000A][*0311.0020.0004] -1D413 ; [.1E10.0020.000B] -1D447 ; [.1E10.0020.000B] -1D47B ; [.1E10.0020.000B] -1D4AF ; [.1E10.0020.000B] -1D4E3 ; [.1E10.0020.000B] -1D517 ; [.1E10.0020.000B] -1D54B ; [.1E10.0020.000B] -1D57F ; [.1E10.0020.000B] -1D5B3 ; [.1E10.0020.000B] -1D5E7 ; [.1E10.0020.000B] -1D61B ; [.1E10.0020.000B] -1D64F ; [.1E10.0020.000B] -1D683 ; [.1E10.0020.000B] -24C9 ; [.1E10.0020.000C] -1F163 ; [.1E10.0020.000C] -1D57 ; [.1E10.0020.0014] -209C ; [.1E10.0020.0015] -1D40 ; [.1E10.0020.001D] -1F143 ; [.1E10.0020.001D] -1F183 ; [.1E10.0020.001D] -0165 ; [.1E10.0020.0002][.0000.0028.0002] -0164 ; [.1E10.0020.0008][.0000.0028.0002] -1E97 ; [.1E10.0020.0002][.0000.002B.0002] -1E6B ; [.1E10.0020.0002][.0000.002E.0002] -1E6A ; [.1E10.0020.0008][.0000.002E.0002] -0163 ; [.1E10.0020.0002][.0000.0030.0002] -0162 ; [.1E10.0020.0008][.0000.0030.0002] -1E6D ; [.1E10.0020.0002][.0000.0042.0002] -1E6C ; [.1E10.0020.0008][.0000.0042.0002] -021B ; [.1E10.0020.0002][.0000.0045.0002] -021A ; [.1E10.0020.0008][.0000.0045.0002] -1E71 ; [.1E10.0020.0002][.0000.0046.0002] -1E70 ; [.1E10.0020.0008][.0000.0046.0002] -1E6F ; [.1E10.0020.0002][.0000.0049.0002] -1E6E ; [.1E10.0020.0008][.0000.0049.0002] -A787 ; [.1E10.0020.0004][.0000.010C.0004] -A786 ; [.1E10.0020.000A][.0000.010C.0004] -02A8 ; [.1E10.0020.0004][.1C04.0020.0004] -2121 ; [.1E10.0020.000A][.1C25.0020.000A][.1CF2.0020.000A] -1D7A ; [.1E10.0020.0004][.0000.010B.0004][.1C93.0020.0004] -3394 ; [.1E10.0020.001D][.1C93.0020.001D][.1E9C.0020.001C] -2122 ; [.1E10.0020.0014][.1D25.0020.0014] -01BE ; [.1E10.0020.0004][.1DEC.0020.0004] -02A6 ; [.1E10.0020.0004][.1DEC.0020.0004] -02A7 ; [.1E10.0020.0004][.1DFD.0020.0004] -A729 ; [.1E10.0020.0004][.1E9C.0020.0004] -A728 ; [.1E10.0020.000A][.1E9C.0020.0004] -1D1B ; [.1E14.0020.0002] -0167 ; [.1E15.0020.0002] -0166 ; [.1E15.0020.0008] -2C66 ; [.1E19.0020.0002] -023E ; [.1E19.0020.0008] -1D75 ; [.1E1A.0020.0002] -01AB ; [.1E1B.0020.0002] -1DB5 ; [.1E1B.0020.0014] -01AD ; [.1E1F.0020.0002] -01AC ; [.1E1F.0020.0008] -0288 ; [.1E23.0020.0002] -01AE ; [.1E23.0020.0008] -0236 ; [.1E27.0020.0002] -A777 ; [.1E2B.0020.0002] -0287 ; [.1E2C.0020.0002] -A7B1 ; [.1E2C.0020.0008] -0075 ; [.1E30.0020.0002] -FF55 ; [.1E30.0020.0003] -0367 ; [.1E30.0020.0004] -24B0 ; [*0310.0020.0004][.1E30.0020.0004][*0311.0020.0004] -1D42E ; [.1E30.0020.0005] -1D462 ; [.1E30.0020.0005] -1D496 ; [.1E30.0020.0005] -1D4CA ; [.1E30.0020.0005] -1D4FE ; [.1E30.0020.0005] -1D532 ; [.1E30.0020.0005] -1D566 ; [.1E30.0020.0005] -1D59A ; [.1E30.0020.0005] -1D5CE ; [.1E30.0020.0005] -1D602 ; [.1E30.0020.0005] -1D636 ; [.1E30.0020.0005] -1D66A ; [.1E30.0020.0005] -1D69E ; [.1E30.0020.0005] -24E4 ; [.1E30.0020.0006] -0055 ; [.1E30.0020.0008] -FF35 ; [.1E30.0020.0009] -1F124 ; [*0310.0020.0004][.1E30.0020.000A][*0311.0020.0004] -1D414 ; [.1E30.0020.000B] -1D448 ; [.1E30.0020.000B] -1D47C ; [.1E30.0020.000B] -1D4B0 ; [.1E30.0020.000B] -1D4E4 ; [.1E30.0020.000B] -1D518 ; [.1E30.0020.000B] -1D54C ; [.1E30.0020.000B] -1D580 ; [.1E30.0020.000B] -1D5B4 ; [.1E30.0020.000B] -1D5E8 ; [.1E30.0020.000B] -1D61C ; [.1E30.0020.000B] -1D650 ; [.1E30.0020.000B] -1D684 ; [.1E30.0020.000B] -24CA ; [.1E30.0020.000C] -1F164 ; [.1E30.0020.000C] -1D58 ; [.1E30.0020.0014] -1D64 ; [.1E30.0020.0015] -1D41 ; [.1E30.0020.001D] -1F144 ; [.1E30.0020.001D] -1F184 ; [.1E30.0020.001D] -00FA ; [.1E30.0020.0002][.0000.0024.0002] -00DA ; [.1E30.0020.0008][.0000.0024.0002] -00F9 ; [.1E30.0020.0002][.0000.0025.0002] -00D9 ; [.1E30.0020.0008][.0000.0025.0002] -016D ; [.1E30.0020.0002][.0000.0026.0002] -016C ; [.1E30.0020.0008][.0000.0026.0002] -00FB ; [.1E30.0020.0002][.0000.0027.0002] -00DB ; [.1E30.0020.0008][.0000.0027.0002] -01D4 ; [.1E30.0020.0002][.0000.0028.0002] -01D3 ; [.1E30.0020.0008][.0000.0028.0002] -016F ; [.1E30.0020.0002][.0000.0029.0002] -016E ; [.1E30.0020.0008][.0000.0029.0002] -00FC ; [.1E30.0020.0002][.0000.002B.0002] -1DF4 ; [.1E30.0020.0004][.0000.002B.0004] -A79F ; [.1E30.0020.0004][.0000.002B.0004] -00DC ; [.1E30.0020.0008][.0000.002B.0002] -A79E ; [.1E30.0020.000A][.0000.002B.0004] -01D8 ; [.1E30.0020.0002][.0000.002B.0002][.0000.0024.0002] -01D7 ; [.1E30.0020.0008][.0000.002B.0002][.0000.0024.0002] -01DC ; [.1E30.0020.0002][.0000.002B.0002][.0000.0025.0002] -01DB ; [.1E30.0020.0008][.0000.002B.0002][.0000.0025.0002] -01DA ; [.1E30.0020.0002][.0000.002B.0002][.0000.0028.0002] -01D9 ; [.1E30.0020.0008][.0000.002B.0002][.0000.0028.0002] -01D6 ; [.1E30.0020.0002][.0000.002B.0002][.0000.0032.0002] -01D5 ; [.1E30.0020.0008][.0000.002B.0002][.0000.0032.0002] -0171 ; [.1E30.0020.0002][.0000.002C.0002] -0170 ; [.1E30.0020.0008][.0000.002C.0002] -0169 ; [.1E30.0020.0002][.0000.002D.0002] -0168 ; [.1E30.0020.0008][.0000.002D.0002] -1E79 ; [.1E30.0020.0002][.0000.002D.0002][.0000.0024.0002] -1E78 ; [.1E30.0020.0008][.0000.002D.0002][.0000.0024.0002] -0173 ; [.1E30.0020.0002][.0000.0031.0002] -0172 ; [.1E30.0020.0008][.0000.0031.0002] -016B ; [.1E30.0020.0002][.0000.0032.0002] -016A ; [.1E30.0020.0008][.0000.0032.0002] -1E7B ; [.1E30.0020.0002][.0000.0032.0002][.0000.002B.0002] -1E7A ; [.1E30.0020.0008][.0000.0032.0002][.0000.002B.0002] -1DF0 ; [.1E30.0020.0004][.0000.0034.0004] -1EE7 ; [.1E30.0020.0002][.0000.003B.0002] -1EE6 ; [.1E30.0020.0008][.0000.003B.0002] -0215 ; [.1E30.0020.0002][.0000.003C.0002] -0214 ; [.1E30.0020.0008][.0000.003C.0002] -0217 ; [.1E30.0020.0002][.0000.003E.0002] -0216 ; [.1E30.0020.0008][.0000.003E.0002] -01B0 ; [.1E30.0020.0002][.0000.003F.0002] -01AF ; [.1E30.0020.0008][.0000.003F.0002] -1EE9 ; [.1E30.0020.0002][.0000.003F.0002][.0000.0024.0002] -1EE8 ; [.1E30.0020.0008][.0000.003F.0002][.0000.0024.0002] -1EEB ; [.1E30.0020.0002][.0000.003F.0002][.0000.0025.0002] -1EEA ; [.1E30.0020.0008][.0000.003F.0002][.0000.0025.0002] -1EEF ; [.1E30.0020.0002][.0000.003F.0002][.0000.002D.0002] -1EEE ; [.1E30.0020.0008][.0000.003F.0002][.0000.002D.0002] -1EED ; [.1E30.0020.0002][.0000.003F.0002][.0000.003B.0002] -1EEC ; [.1E30.0020.0008][.0000.003F.0002][.0000.003B.0002] -1EF1 ; [.1E30.0020.0002][.0000.003F.0002][.0000.0042.0002] -1EF0 ; [.1E30.0020.0008][.0000.003F.0002][.0000.0042.0002] -1EE5 ; [.1E30.0020.0002][.0000.0042.0002] -1EE4 ; [.1E30.0020.0008][.0000.0042.0002] -1E73 ; [.1E30.0020.0002][.0000.0043.0002] -1E72 ; [.1E30.0020.0008][.0000.0043.0002] -1E77 ; [.1E30.0020.0002][.0000.0046.0002] -1E76 ; [.1E30.0020.0008][.0000.0046.0002] -1E75 ; [.1E30.0020.0002][.0000.0048.0002] -1E74 ; [.1E30.0020.0008][.0000.0048.0002] -1F199 ; [.1E30.0020.001D][.1D87.0020.001D][*025F.0020.001C] -1D1C ; [.1E34.0020.0002] -1DB8 ; [.1E34.0020.0014] -AB4E ; [.1E35.0020.0002] -1D1D ; [.1E36.0020.0002] -1D59 ; [.1E36.0020.0014] -1D1E ; [.1E37.0020.0002] -1D6B ; [.1E38.0020.0002] -AB50 ; [.1E39.0020.0002] -AB51 ; [.1E3A.0020.0002] -0289 ; [.1E3B.0020.0002] -0244 ; [.1E3B.0020.0008] -1DB6 ; [.1E3B.0020.0014] -AB4F ; [.1E3F.0020.0002] -1D7E ; [.1E40.0020.0002] -1D99 ; [.1E41.0020.0002] -AB52 ; [.1E42.0020.0002] -AB5F ; [.1E42.0020.0014] -0265 ; [.1E43.0020.0002] -A78D ; [.1E43.0020.0008] -1DA3 ; [.1E43.0020.0014] -02AE ; [.1E47.0020.0002] -02AF ; [.1E4B.0020.0002] -026F ; [.1E4F.0020.0002] -019C ; [.1E4F.0020.0008] -1D5A ; [.1E4F.0020.0014] -A7FA ; [.1E53.0020.0002] -1D1F ; [.1E54.0020.0002] -0270 ; [.1E55.0020.0002] -1DAD ; [.1E55.0020.0014] -028A ; [.1E59.0020.0002] -01B1 ; [.1E59.0020.0008] -1DB7 ; [.1E59.0020.0014] -1D7F ; [.1E5D.0020.0002] -0076 ; [.1E5E.0020.0002] -FF56 ; [.1E5E.0020.0003] -036E ; [.1E5E.0020.0004] -2174 ; [.1E5E.0020.0004] -24B1 ; [*0310.0020.0004][.1E5E.0020.0004][*0311.0020.0004] -1D42F ; [.1E5E.0020.0005] -1D463 ; [.1E5E.0020.0005] -1D497 ; [.1E5E.0020.0005] -1D4CB ; [.1E5E.0020.0005] -1D4FF ; [.1E5E.0020.0005] -1D533 ; [.1E5E.0020.0005] -1D567 ; [.1E5E.0020.0005] -1D59B ; [.1E5E.0020.0005] -1D5CF ; [.1E5E.0020.0005] -1D603 ; [.1E5E.0020.0005] -1D637 ; [.1E5E.0020.0005] -1D66B ; [.1E5E.0020.0005] -1D69F ; [.1E5E.0020.0005] -24E5 ; [.1E5E.0020.0006] -0056 ; [.1E5E.0020.0008] -FF36 ; [.1E5E.0020.0009] -2164 ; [.1E5E.0020.000A] -1F125 ; [*0310.0020.0004][.1E5E.0020.000A][*0311.0020.0004] -1D415 ; [.1E5E.0020.000B] -1D449 ; [.1E5E.0020.000B] -1D47D ; [.1E5E.0020.000B] -1D4B1 ; [.1E5E.0020.000B] -1D4E5 ; [.1E5E.0020.000B] -1D519 ; [.1E5E.0020.000B] -1D54D ; [.1E5E.0020.000B] -1D581 ; [.1E5E.0020.000B] -1D5B5 ; [.1E5E.0020.000B] -1D5E9 ; [.1E5E.0020.000B] -1D61D ; [.1E5E.0020.000B] -1D651 ; [.1E5E.0020.000B] -1D685 ; [.1E5E.0020.000B] -24CB ; [.1E5E.0020.000C] -1F165 ; [.1E5E.0020.000C] -1D5B ; [.1E5E.0020.0014] -1D65 ; [.1E5E.0020.0015] -2C7D ; [.1E5E.0020.001D] -1F145 ; [.1E5E.0020.001D] -1F185 ; [.1E5E.0020.001D] -1E7D ; [.1E5E.0020.0002][.0000.002D.0002] -1E7C ; [.1E5E.0020.0008][.0000.002D.0002] -1E7F ; [.1E5E.0020.0002][.0000.0042.0002] -1E7E ; [.1E5E.0020.0008][.0000.0042.0002] -2175 ; [.1E5E.0020.0004][.1CAD.0020.0004] -2165 ; [.1E5E.0020.000A][.1CAD.0020.000A] -2176 ; [.1E5E.0020.0004][.1CAD.0020.0004][.1CAD.0020.0004] -2166 ; [.1E5E.0020.000A][.1CAD.0020.000A][.1CAD.0020.000A] -2177 ; [.1E5E.0020.0004][.1CAD.0020.0004][.1CAD.0020.0004][.1CAD.0020.0004] -2167 ; [.1E5E.0020.000A][.1CAD.0020.000A][.1CAD.0020.000A][.1CAD.0020.000A] -33DE ; [.1E5E.0020.001D][*0605.0020.001C][.1D25.0020.001C] -1F19A ; [.1E5E.0020.001D][.1DEC.0020.001D] -A761 ; [.1E5E.0020.0004][.1E86.0020.0004] -A760 ; [.1E5E.0020.000A][.1E86.0020.000A] -1D20 ; [.1E62.0020.0002] -A75F ; [.1E63.0020.0002] -A75E ; [.1E63.0020.0008] -1D8C ; [.1E64.0020.0002] -028B ; [.1E65.0020.0002] -01B2 ; [.1E65.0020.0008] -1DB9 ; [.1E65.0020.0014] -2C71 ; [.1E69.0020.0002] -2C74 ; [.1E6A.0020.0002] -1EFD ; [.1E6B.0020.0002] -1EFC ; [.1E6B.0020.0008] -028C ; [.1E6C.0020.0002] -0245 ; [.1E6C.0020.0008] -1DBA ; [.1E6C.0020.0014] -0077 ; [.1E70.0020.0002] -FF57 ; [.1E70.0020.0003] -1DF1 ; [.1E70.0020.0004] -24B2 ; [*0310.0020.0004][.1E70.0020.0004][*0311.0020.0004] -1D430 ; [.1E70.0020.0005] -1D464 ; [.1E70.0020.0005] -1D498 ; [.1E70.0020.0005] -1D4CC ; [.1E70.0020.0005] -1D500 ; [.1E70.0020.0005] -1D534 ; [.1E70.0020.0005] -1D568 ; [.1E70.0020.0005] -1D59C ; [.1E70.0020.0005] -1D5D0 ; [.1E70.0020.0005] -1D604 ; [.1E70.0020.0005] -1D638 ; [.1E70.0020.0005] -1D66C ; [.1E70.0020.0005] -1D6A0 ; [.1E70.0020.0005] -24E6 ; [.1E70.0020.0006] -0057 ; [.1E70.0020.0008] -FF37 ; [.1E70.0020.0009] -1F126 ; [*0310.0020.0004][.1E70.0020.000A][*0311.0020.0004] -1D416 ; [.1E70.0020.000B] -1D44A ; [.1E70.0020.000B] -1D47E ; [.1E70.0020.000B] -1D4B2 ; [.1E70.0020.000B] -1D4E6 ; [.1E70.0020.000B] -1D51A ; [.1E70.0020.000B] -1D54E ; [.1E70.0020.000B] -1D582 ; [.1E70.0020.000B] -1D5B6 ; [.1E70.0020.000B] -1D5EA ; [.1E70.0020.000B] -1D61E ; [.1E70.0020.000B] -1D652 ; [.1E70.0020.000B] -1D686 ; [.1E70.0020.000B] -24CC ; [.1E70.0020.000C] -1F166 ; [.1E70.0020.000C] -02B7 ; [.1E70.0020.0014] -1D42 ; [.1E70.0020.001D] -1F146 ; [.1E70.0020.001D] -1F186 ; [.1E70.0020.001D] -1E83 ; [.1E70.0020.0002][.0000.0024.0002] -1E82 ; [.1E70.0020.0008][.0000.0024.0002] -1E81 ; [.1E70.0020.0002][.0000.0025.0002] -1E80 ; [.1E70.0020.0008][.0000.0025.0002] -0175 ; [.1E70.0020.0002][.0000.0027.0002] -0174 ; [.1E70.0020.0008][.0000.0027.0002] -1E98 ; [.1E70.0020.0002][.0000.0029.0002] -1E85 ; [.1E70.0020.0002][.0000.002B.0002] -1E84 ; [.1E70.0020.0008][.0000.002B.0002] -1E87 ; [.1E70.0020.0002][.0000.002E.0002] -1E86 ; [.1E70.0020.0008][.0000.002E.0002] -1E89 ; [.1E70.0020.0002][.0000.0042.0002] -1E88 ; [.1E70.0020.0008][.0000.0042.0002] -33DD ; [.1E70.0020.001D][.1BDB.0020.001C] -1F14F ; [.1E70.0020.001D][.1BF5.0020.001D] -1F18F ; [.1E70.0020.001D][.1BF5.0020.001D] -1F12E ; [.1E70.0020.000C][.1E9C.0020.000C] -1D21 ; [.1E74.0020.0002] -2C73 ; [.1E75.0020.0002] -2C72 ; [.1E75.0020.0008] -028D ; [.1E76.0020.0002] -0078 ; [.1E7A.0020.0002] -FF58 ; [.1E7A.0020.0003] -036F ; [.1E7A.0020.0004] -2179 ; [.1E7A.0020.0004] -24B3 ; [*0310.0020.0004][.1E7A.0020.0004][*0311.0020.0004] -1D431 ; [.1E7A.0020.0005] -1D465 ; [.1E7A.0020.0005] -1D499 ; [.1E7A.0020.0005] -1D4CD ; [.1E7A.0020.0005] -1D501 ; [.1E7A.0020.0005] -1D535 ; [.1E7A.0020.0005] -1D569 ; [.1E7A.0020.0005] -1D59D ; [.1E7A.0020.0005] -1D5D1 ; [.1E7A.0020.0005] -1D605 ; [.1E7A.0020.0005] -1D639 ; [.1E7A.0020.0005] -1D66D ; [.1E7A.0020.0005] -1D6A1 ; [.1E7A.0020.0005] -24E7 ; [.1E7A.0020.0006] -0058 ; [.1E7A.0020.0008] -FF38 ; [.1E7A.0020.0009] -2169 ; [.1E7A.0020.000A] -1F127 ; [*0310.0020.0004][.1E7A.0020.000A][*0311.0020.0004] -1D417 ; [.1E7A.0020.000B] -1D44B ; [.1E7A.0020.000B] -1D47F ; [.1E7A.0020.000B] -1D4B3 ; [.1E7A.0020.000B] -1D4E7 ; [.1E7A.0020.000B] -1D51B ; [.1E7A.0020.000B] -1D54F ; [.1E7A.0020.000B] -1D583 ; [.1E7A.0020.000B] -1D5B7 ; [.1E7A.0020.000B] -1D5EB ; [.1E7A.0020.000B] -1D61F ; [.1E7A.0020.000B] -1D653 ; [.1E7A.0020.000B] -1D687 ; [.1E7A.0020.000B] -24CD ; [.1E7A.0020.000C] -1F167 ; [.1E7A.0020.000C] -02E3 ; [.1E7A.0020.0014] -2093 ; [.1E7A.0020.0015] -1F147 ; [.1E7A.0020.001D] -1F187 ; [.1E7A.0020.001D] -1E8D ; [.1E7A.0020.0002][.0000.002B.0002] -1E8C ; [.1E7A.0020.0008][.0000.002B.0002] -1E8B ; [.1E7A.0020.0002][.0000.002E.0002] -1E8A ; [.1E7A.0020.0008][.0000.002E.0002] -217A ; [.1E7A.0020.0004][.1CAD.0020.0004] -216A ; [.1E7A.0020.000A][.1CAD.0020.000A] -217B ; [.1E7A.0020.0004][.1CAD.0020.0004][.1CAD.0020.0004] -216B ; [.1E7A.0020.000A][.1CAD.0020.000A][.1CAD.0020.000A] -1D8D ; [.1E7E.0020.0002] -AB56 ; [.1E7F.0020.0002] -AB57 ; [.1E80.0020.0002] -AB58 ; [.1E81.0020.0002] -AB59 ; [.1E82.0020.0002] -AB53 ; [.1E83.0020.0002] -A7B3 ; [.1E83.0020.0008] -AB54 ; [.1E84.0020.0002] -AB55 ; [.1E85.0020.0002] -0079 ; [.1E86.0020.0002] -FF59 ; [.1E86.0020.0003] -24B4 ; [*0310.0020.0004][.1E86.0020.0004][*0311.0020.0004] -1D432 ; [.1E86.0020.0005] -1D466 ; [.1E86.0020.0005] -1D49A ; [.1E86.0020.0005] -1D4CE ; [.1E86.0020.0005] -1D502 ; [.1E86.0020.0005] -1D536 ; [.1E86.0020.0005] -1D56A ; [.1E86.0020.0005] -1D59E ; [.1E86.0020.0005] -1D5D2 ; [.1E86.0020.0005] -1D606 ; [.1E86.0020.0005] -1D63A ; [.1E86.0020.0005] -1D66E ; [.1E86.0020.0005] -1D6A2 ; [.1E86.0020.0005] -24E8 ; [.1E86.0020.0006] -0059 ; [.1E86.0020.0008] -FF39 ; [.1E86.0020.0009] -1F128 ; [*0310.0020.0004][.1E86.0020.000A][*0311.0020.0004] -1D418 ; [.1E86.0020.000B] -1D44C ; [.1E86.0020.000B] -1D480 ; [.1E86.0020.000B] -1D4B4 ; [.1E86.0020.000B] -1D4E8 ; [.1E86.0020.000B] -1D51C ; [.1E86.0020.000B] -1D550 ; [.1E86.0020.000B] -1D584 ; [.1E86.0020.000B] -1D5B8 ; [.1E86.0020.000B] -1D5EC ; [.1E86.0020.000B] -1D620 ; [.1E86.0020.000B] -1D654 ; [.1E86.0020.000B] -1D688 ; [.1E86.0020.000B] -24CE ; [.1E86.0020.000C] -1F168 ; [.1E86.0020.000C] -02B8 ; [.1E86.0020.0014] -1F148 ; [.1E86.0020.001D] -1F188 ; [.1E86.0020.001D] -00FD ; [.1E86.0020.0002][.0000.0024.0002] -00DD ; [.1E86.0020.0008][.0000.0024.0002] -1EF3 ; [.1E86.0020.0002][.0000.0025.0002] -1EF2 ; [.1E86.0020.0008][.0000.0025.0002] -0177 ; [.1E86.0020.0002][.0000.0027.0002] -0176 ; [.1E86.0020.0008][.0000.0027.0002] -1E99 ; [.1E86.0020.0002][.0000.0029.0002] -00FF ; [.1E86.0020.0002][.0000.002B.0002] -0178 ; [.1E86.0020.0008][.0000.002B.0002] -1EF9 ; [.1E86.0020.0002][.0000.002D.0002] -1EF8 ; [.1E86.0020.0008][.0000.002D.0002] -1E8F ; [.1E86.0020.0002][.0000.002E.0002] -1E8E ; [.1E86.0020.0008][.0000.002E.0002] -0233 ; [.1E86.0020.0002][.0000.0032.0002] -0232 ; [.1E86.0020.0008][.0000.0032.0002] -1EF7 ; [.1E86.0020.0002][.0000.003B.0002] -1EF6 ; [.1E86.0020.0008][.0000.003B.0002] -1EF5 ; [.1E86.0020.0002][.0000.0042.0002] -1EF4 ; [.1E86.0020.0008][.0000.0042.0002] -028F ; [.1E8A.0020.0002] -024F ; [.1E8E.0020.0002] -024E ; [.1E8E.0020.0008] -01B4 ; [.1E92.0020.0002] -01B3 ; [.1E92.0020.0008] -1EFF ; [.1E96.0020.0002] -1EFE ; [.1E96.0020.0008] -AB5A ; [.1E97.0020.0002] -021D ; [.1E98.0020.0002] -021C ; [.1E98.0020.0008] -007A ; [.1E9C.0020.0002] -FF5A ; [.1E9C.0020.0003] -1DE6 ; [.1E9C.0020.0004] -24B5 ; [*0310.0020.0004][.1E9C.0020.0004][*0311.0020.0004] -1D433 ; [.1E9C.0020.0005] -1D467 ; [.1E9C.0020.0005] -1D49B ; [.1E9C.0020.0005] -1D4CF ; [.1E9C.0020.0005] -1D503 ; [.1E9C.0020.0005] -1D537 ; [.1E9C.0020.0005] -1D56B ; [.1E9C.0020.0005] -1D59F ; [.1E9C.0020.0005] -1D5D3 ; [.1E9C.0020.0005] -1D607 ; [.1E9C.0020.0005] -1D63B ; [.1E9C.0020.0005] -1D66F ; [.1E9C.0020.0005] -1D6A3 ; [.1E9C.0020.0005] -24E9 ; [.1E9C.0020.0006] -005A ; [.1E9C.0020.0008] -FF3A ; [.1E9C.0020.0009] -1F129 ; [*0310.0020.0004][.1E9C.0020.000A][*0311.0020.0004] -2124 ; [.1E9C.0020.000B] -2128 ; [.1E9C.0020.000B] -1D419 ; [.1E9C.0020.000B] -1D44D ; [.1E9C.0020.000B] -1D481 ; [.1E9C.0020.000B] -1D4B5 ; [.1E9C.0020.000B] -1D4E9 ; [.1E9C.0020.000B] -1D585 ; [.1E9C.0020.000B] -1D5B9 ; [.1E9C.0020.000B] -1D5ED ; [.1E9C.0020.000B] -1D621 ; [.1E9C.0020.000B] -1D655 ; [.1E9C.0020.000B] -1D689 ; [.1E9C.0020.000B] -24CF ; [.1E9C.0020.000C] -1F169 ; [.1E9C.0020.000C] -1DBB ; [.1E9C.0020.0014] -1F149 ; [.1E9C.0020.001D] -1F189 ; [.1E9C.0020.001D] -017A ; [.1E9C.0020.0002][.0000.0024.0002] -0179 ; [.1E9C.0020.0008][.0000.0024.0002] -1E91 ; [.1E9C.0020.0002][.0000.0027.0002] -1E90 ; [.1E9C.0020.0008][.0000.0027.0002] -017E ; [.1E9C.0020.0002][.0000.0028.0002] -017D ; [.1E9C.0020.0008][.0000.0028.0002] -017C ; [.1E9C.0020.0002][.0000.002E.0002] -017B ; [.1E9C.0020.0008][.0000.002E.0002] -1E93 ; [.1E9C.0020.0002][.0000.0042.0002] -1E92 ; [.1E9C.0020.0008][.0000.0042.0002] -1E95 ; [.1E9C.0020.0002][.0000.0049.0002] -1E94 ; [.1E9C.0020.0008][.0000.0049.0002] -018D ; [.1E9C.0020.0004][.1E70.0020.0004] -1D22 ; [.1EA0.0020.0002] -01B6 ; [.1EA1.0020.0002] -01B5 ; [.1EA1.0020.0008] -1D76 ; [.1EA5.0020.0002] -1D8E ; [.1EA6.0020.0002] -0225 ; [.1EA7.0020.0002] -0224 ; [.1EA7.0020.0008] -0290 ; [.1EAB.0020.0002] -1DBC ; [.1EAB.0020.0014] -0291 ; [.1EAF.0020.0002] -1DBD ; [.1EAF.0020.0014] -0240 ; [.1EB3.0020.0002] -2C7F ; [.1EB3.0020.0008] -2C6C ; [.1EB7.0020.0002] -2C6B ; [.1EB7.0020.0008] -A763 ; [.1EB8.0020.0002] -A762 ; [.1EB8.0020.0008] -0292 ; [.1EB9.0020.0002] -01B7 ; [.1EB9.0020.0008] -1DBE ; [.1EB9.0020.0014] -01EF ; [.1EB9.0020.0002][.0000.0028.0002] -01EE ; [.1EB9.0020.0008][.0000.0028.0002] -1D23 ; [.1EBD.0020.0002] -01B9 ; [.1EBE.0020.0002] -01B8 ; [.1EBE.0020.0008] -1D9A ; [.1EC2.0020.0002] -01BA ; [.1EC3.0020.0002] -0293 ; [.1EC7.0020.0002] -00FE ; [.1ECB.0020.0002] -00DE ; [.1ECB.0020.0008] -A765 ; [.1ECF.0020.0002] -A764 ; [.1ECF.0020.0008] -A767 ; [.1ED0.0020.0002] -A766 ; [.1ED0.0020.0008] -01BF ; [.1ED1.0020.0002] -01F7 ; [.1ED1.0020.0008] -A769 ; [.1ED5.0020.0002] -A768 ; [.1ED5.0020.0008] -AB60 ; [.1ED6.0020.0002] -AB61 ; [.1ED7.0020.0002] -AB63 ; [.1ED8.0020.0002] -A76B ; [.1ED9.0020.0002] -A76A ; [.1ED9.0020.0008] -A76D ; [.1EDA.0020.0002] -A76C ; [.1EDA.0020.0008] -A76F ; [.1EDB.0020.0002] -1DD2 ; [.1EDB.0020.0004] -A76E ; [.1EDB.0020.0008] -A770 ; [.1EDB.0020.0014] -A778 ; [.1EDC.0020.0002] -01BB ; [.1EDD.0020.0002] -A72B ; [.1EE1.0020.0002] -A72A ; [.1EE1.0020.0008] -A72D ; [.1EE2.0020.0002] -A72C ; [.1EE2.0020.0008] -A72F ; [.1EE3.0020.0002] -A72E ; [.1EE3.0020.0008] -01A8 ; [.1EE4.0020.0002] -01A7 ; [.1EE4.0020.0008] -01BD ; [.1EE8.0020.0002] -01BC ; [.1EE8.0020.0008] -0185 ; [.1EEC.0020.0002] -0184 ; [.1EEC.0020.0008] -0294 ; [.1EF0.0020.0002] -0242 ; [.1EF4.0020.0002] -0241 ; [.1EF4.0020.0008] -02C0 ; [.1EF8.0020.0002] -02BC ; [.1EF9.0020.0002] -0149 ; [.1EF9.0020.0004][.1D34.0020.0004] -02EE ; [.1EFA.0020.0002] -02BE ; [.1EFB.0020.0002] -A723 ; [.1EFC.0020.0002] -A722 ; [.1EFC.0020.0008] -A78C ; [.1EFD.0020.0002] -A78B ; [.1EFD.0020.0008] -A78F ; [.1EFE.0020.0002] -0295 ; [.1EFF.0020.0002] -02E4 ; [.1EFF.0020.0014] -02BF ; [.1F03.0020.0002] -02C1 ; [.1F04.0020.0002] -1D24 ; [.1F05.0020.0002] -1D25 ; [.1F06.0020.0002] -1D5C ; [.1F06.0020.0014] -A725 ; [.1F07.0020.0002] -A724 ; [.1F07.0020.0008] -02A1 ; [.1F08.0020.0002] -02A2 ; [.1F0C.0020.0002] -0296 ; [.1F10.0020.0002] -01C0 ; [.1F14.0020.0002] -01C1 ; [.1F18.0020.0002] -01C2 ; [.1F1C.0020.0002] -01C3 ; [.1F20.0020.0002] -0297 ; [.1F24.0020.0002] -0298 ; [.1F28.0020.0002] -02AC ; [.1F2C.0020.0002] -02AD ; [.1F30.0020.0002] -03B1 ; [.1F34.0020.0002] -1D6C2 ; [.1F34.0020.0005] -1D6FC ; [.1F34.0020.0005] -1D736 ; [.1F34.0020.0005] -1D770 ; [.1F34.0020.0005] -1D7AA ; [.1F34.0020.0005] -0391 ; [.1F34.0020.0008] -1D6A8 ; [.1F34.0020.000B] -1D6E2 ; [.1F34.0020.000B] -1D71C ; [.1F34.0020.000B] -1D756 ; [.1F34.0020.000B] -1D790 ; [.1F34.0020.000B] -1F00 ; [.1F34.0020.0002][.0000.0022.0002] -1F08 ; [.1F34.0020.0008][.0000.0022.0002] -1F04 ; [.1F34.0020.0002][.0000.0022.0002][.0000.0024.0002] -1F0C ; [.1F34.0020.0008][.0000.0022.0002][.0000.0024.0002] -1F84 ; [.1F34.0020.0002][.0000.0022.0002][.0000.0024.0002][.0000.004C.0002] -1F8C ; [.1F34.0020.0008][.0000.0022.0002][.0000.0024.0002][.0000.004C.0002] -1F02 ; [.1F34.0020.0002][.0000.0022.0002][.0000.0025.0002] -1F0A ; [.1F34.0020.0008][.0000.0022.0002][.0000.0025.0002] -1F82 ; [.1F34.0020.0002][.0000.0022.0002][.0000.0025.0002][.0000.004C.0002] -1F8A ; [.1F34.0020.0008][.0000.0022.0002][.0000.0025.0002][.0000.004C.0002] -1F06 ; [.1F34.0020.0002][.0000.0022.0002][.0000.002A.0002] -1F0E ; [.1F34.0020.0008][.0000.0022.0002][.0000.002A.0002] -1F86 ; [.1F34.0020.0002][.0000.0022.0002][.0000.002A.0002][.0000.004C.0002] -1F8E ; [.1F34.0020.0008][.0000.0022.0002][.0000.002A.0002][.0000.004C.0002] -1F80 ; [.1F34.0020.0002][.0000.0022.0002][.0000.004C.0002] -1F88 ; [.1F34.0020.0008][.0000.0022.0002][.0000.004C.0002] -1F01 ; [.1F34.0020.0002][.0000.0023.0002] -1F09 ; [.1F34.0020.0008][.0000.0023.0002] -1F05 ; [.1F34.0020.0002][.0000.0023.0002][.0000.0024.0002] -1F0D ; [.1F34.0020.0008][.0000.0023.0002][.0000.0024.0002] -1F85 ; [.1F34.0020.0002][.0000.0023.0002][.0000.0024.0002][.0000.004C.0002] -1F8D ; [.1F34.0020.0008][.0000.0023.0002][.0000.0024.0002][.0000.004C.0002] -1F03 ; [.1F34.0020.0002][.0000.0023.0002][.0000.0025.0002] -1F0B ; [.1F34.0020.0008][.0000.0023.0002][.0000.0025.0002] -1F83 ; [.1F34.0020.0002][.0000.0023.0002][.0000.0025.0002][.0000.004C.0002] -1F8B ; [.1F34.0020.0008][.0000.0023.0002][.0000.0025.0002][.0000.004C.0002] -1F07 ; [.1F34.0020.0002][.0000.0023.0002][.0000.002A.0002] -1F0F ; [.1F34.0020.0008][.0000.0023.0002][.0000.002A.0002] -1F87 ; [.1F34.0020.0002][.0000.0023.0002][.0000.002A.0002][.0000.004C.0002] -1F8F ; [.1F34.0020.0008][.0000.0023.0002][.0000.002A.0002][.0000.004C.0002] -1F81 ; [.1F34.0020.0002][.0000.0023.0002][.0000.004C.0002] -1F89 ; [.1F34.0020.0008][.0000.0023.0002][.0000.004C.0002] -03AC ; [.1F34.0020.0002][.0000.0024.0002] -1F71 ; [.1F34.0020.0002][.0000.0024.0002] -0386 ; [.1F34.0020.0008][.0000.0024.0002] -1FBB ; [.1F34.0020.0008][.0000.0024.0002] -1FB4 ; [.1F34.0020.0002][.0000.0024.0002][.0000.004C.0002] -1F70 ; [.1F34.0020.0002][.0000.0025.0002] -1FBA ; [.1F34.0020.0008][.0000.0025.0002] -1FB2 ; [.1F34.0020.0002][.0000.0025.0002][.0000.004C.0002] -1FB0 ; [.1F34.0020.0002][.0000.0026.0002] -1FB8 ; [.1F34.0020.0008][.0000.0026.0002] -1FB6 ; [.1F34.0020.0002][.0000.002A.0002] -1FB7 ; [.1F34.0020.0002][.0000.002A.0002][.0000.004C.0002] -1FB1 ; [.1F34.0020.0002][.0000.0032.0002] -1FB9 ; [.1F34.0020.0008][.0000.0032.0002] -1FB3 ; [.1F34.0020.0002][.0000.004C.0002] -1FBC ; [.1F34.0020.0008][.0000.004C.0002] -03B2 ; [.1F35.0020.0002] -03D0 ; [.1F35.0020.0004] -1D6C3 ; [.1F35.0020.0005] -1D6FD ; [.1F35.0020.0005] -1D737 ; [.1F35.0020.0005] -1D771 ; [.1F35.0020.0005] -1D7AB ; [.1F35.0020.0005] -0392 ; [.1F35.0020.0008] -1D6A9 ; [.1F35.0020.000B] -1D6E3 ; [.1F35.0020.000B] -1D71D ; [.1F35.0020.000B] -1D757 ; [.1F35.0020.000B] -1D791 ; [.1F35.0020.000B] -1D5D ; [.1F35.0020.0014] -1D66 ; [.1F35.0020.0015] -03B3 ; [.1F36.0020.0002] -213D ; [.1F36.0020.0005] -1D6C4 ; [.1F36.0020.0005] -1D6FE ; [.1F36.0020.0005] -1D738 ; [.1F36.0020.0005] -1D772 ; [.1F36.0020.0005] -1D7AC ; [.1F36.0020.0005] -0393 ; [.1F36.0020.0008] -213E ; [.1F36.0020.000B] -1D6AA ; [.1F36.0020.000B] -1D6E4 ; [.1F36.0020.000B] -1D71E ; [.1F36.0020.000B] -1D758 ; [.1F36.0020.000B] -1D792 ; [.1F36.0020.000B] -1D5E ; [.1F36.0020.0014] -1D67 ; [.1F36.0020.0015] -1D26 ; [.1F37.0020.0002] -03B4 ; [.1F38.0020.0002] -1D6C5 ; [.1F38.0020.0005] -1D6FF ; [.1F38.0020.0005] -1D739 ; [.1F38.0020.0005] -1D773 ; [.1F38.0020.0005] -1D7AD ; [.1F38.0020.0005] -0394 ; [.1F38.0020.0008] -1D6AB ; [.1F38.0020.000B] -1D6E5 ; [.1F38.0020.000B] -1D71F ; [.1F38.0020.000B] -1D759 ; [.1F38.0020.000B] -1D793 ; [.1F38.0020.000B] -1D5F ; [.1F38.0020.0014] -03B5 ; [.1F39.0020.0002] -03F5 ; [.1F39.0020.0004] -1D6C6 ; [.1F39.0020.0005] -1D6DC ; [.1F39.0020.0005] -1D700 ; [.1F39.0020.0005] -1D716 ; [.1F39.0020.0005] -1D73A ; [.1F39.0020.0005] -1D750 ; [.1F39.0020.0005] -1D774 ; [.1F39.0020.0005] -1D78A ; [.1F39.0020.0005] -1D7AE ; [.1F39.0020.0005] -1D7C4 ; [.1F39.0020.0005] -0395 ; [.1F39.0020.0008] -1D6AC ; [.1F39.0020.000B] -1D6E6 ; [.1F39.0020.000B] -1D720 ; [.1F39.0020.000B] -1D75A ; [.1F39.0020.000B] -1D794 ; [.1F39.0020.000B] -1F10 ; [.1F39.0020.0002][.0000.0022.0002] -1F18 ; [.1F39.0020.0008][.0000.0022.0002] -1F14 ; [.1F39.0020.0002][.0000.0022.0002][.0000.0024.0002] -1F1C ; [.1F39.0020.0008][.0000.0022.0002][.0000.0024.0002] -1F12 ; [.1F39.0020.0002][.0000.0022.0002][.0000.0025.0002] -1F1A ; [.1F39.0020.0008][.0000.0022.0002][.0000.0025.0002] -1F11 ; [.1F39.0020.0002][.0000.0023.0002] -1F19 ; [.1F39.0020.0008][.0000.0023.0002] -1F15 ; [.1F39.0020.0002][.0000.0023.0002][.0000.0024.0002] -1F1D ; [.1F39.0020.0008][.0000.0023.0002][.0000.0024.0002] -1F13 ; [.1F39.0020.0002][.0000.0023.0002][.0000.0025.0002] -1F1B ; [.1F39.0020.0008][.0000.0023.0002][.0000.0025.0002] -03AD ; [.1F39.0020.0002][.0000.0024.0002] -1F73 ; [.1F39.0020.0002][.0000.0024.0002] -0388 ; [.1F39.0020.0008][.0000.0024.0002] -1FC9 ; [.1F39.0020.0008][.0000.0024.0002] -1F72 ; [.1F39.0020.0002][.0000.0025.0002] -1FC8 ; [.1F39.0020.0008][.0000.0025.0002] -03DD ; [.1F3A.0020.0002] -1D7CB ; [.1F3A.0020.0005] -03DC ; [.1F3A.0020.0008] -1D7CA ; [.1F3A.0020.000B] -0377 ; [.1F3B.0020.0002] -0376 ; [.1F3B.0020.0008] -03DB ; [.1F3C.0020.0002] -03DA ; [.1F3C.0020.0008] -03B6 ; [.1F3D.0020.0002] -1D6C7 ; [.1F3D.0020.0005] -1D701 ; [.1F3D.0020.0005] -1D73B ; [.1F3D.0020.0005] -1D775 ; [.1F3D.0020.0005] -1D7AF ; [.1F3D.0020.0005] -0396 ; [.1F3D.0020.0008] -1D6AD ; [.1F3D.0020.000B] -1D6E7 ; [.1F3D.0020.000B] -1D721 ; [.1F3D.0020.000B] -1D75B ; [.1F3D.0020.000B] -1D795 ; [.1F3D.0020.000B] -0371 ; [.1F3E.0020.0002] -0370 ; [.1F3E.0020.0008] -03B7 ; [.1F3F.0020.0002] -1D6C8 ; [.1F3F.0020.0005] -1D702 ; [.1F3F.0020.0005] -1D73C ; [.1F3F.0020.0005] -1D776 ; [.1F3F.0020.0005] -1D7B0 ; [.1F3F.0020.0005] -0397 ; [.1F3F.0020.0008] -1D6AE ; [.1F3F.0020.000B] -1D6E8 ; [.1F3F.0020.000B] -1D722 ; [.1F3F.0020.000B] -1D75C ; [.1F3F.0020.000B] -1D796 ; [.1F3F.0020.000B] -1F20 ; [.1F3F.0020.0002][.0000.0022.0002] -1F28 ; [.1F3F.0020.0008][.0000.0022.0002] -1F24 ; [.1F3F.0020.0002][.0000.0022.0002][.0000.0024.0002] -1F2C ; [.1F3F.0020.0008][.0000.0022.0002][.0000.0024.0002] -1F94 ; [.1F3F.0020.0002][.0000.0022.0002][.0000.0024.0002][.0000.004C.0002] -1F9C ; [.1F3F.0020.0008][.0000.0022.0002][.0000.0024.0002][.0000.004C.0002] -1F22 ; [.1F3F.0020.0002][.0000.0022.0002][.0000.0025.0002] -1F2A ; [.1F3F.0020.0008][.0000.0022.0002][.0000.0025.0002] -1F92 ; [.1F3F.0020.0002][.0000.0022.0002][.0000.0025.0002][.0000.004C.0002] -1F9A ; [.1F3F.0020.0008][.0000.0022.0002][.0000.0025.0002][.0000.004C.0002] -1F26 ; [.1F3F.0020.0002][.0000.0022.0002][.0000.002A.0002] -1F2E ; [.1F3F.0020.0008][.0000.0022.0002][.0000.002A.0002] -1F96 ; [.1F3F.0020.0002][.0000.0022.0002][.0000.002A.0002][.0000.004C.0002] -1F9E ; [.1F3F.0020.0008][.0000.0022.0002][.0000.002A.0002][.0000.004C.0002] -1F90 ; [.1F3F.0020.0002][.0000.0022.0002][.0000.004C.0002] -1F98 ; [.1F3F.0020.0008][.0000.0022.0002][.0000.004C.0002] -1F21 ; [.1F3F.0020.0002][.0000.0023.0002] -1F29 ; [.1F3F.0020.0008][.0000.0023.0002] -1F25 ; [.1F3F.0020.0002][.0000.0023.0002][.0000.0024.0002] -1F2D ; [.1F3F.0020.0008][.0000.0023.0002][.0000.0024.0002] -1F95 ; [.1F3F.0020.0002][.0000.0023.0002][.0000.0024.0002][.0000.004C.0002] -1F9D ; [.1F3F.0020.0008][.0000.0023.0002][.0000.0024.0002][.0000.004C.0002] -1F23 ; [.1F3F.0020.0002][.0000.0023.0002][.0000.0025.0002] -1F2B ; [.1F3F.0020.0008][.0000.0023.0002][.0000.0025.0002] -1F93 ; [.1F3F.0020.0002][.0000.0023.0002][.0000.0025.0002][.0000.004C.0002] -1F9B ; [.1F3F.0020.0008][.0000.0023.0002][.0000.0025.0002][.0000.004C.0002] -1F27 ; [.1F3F.0020.0002][.0000.0023.0002][.0000.002A.0002] -1F2F ; [.1F3F.0020.0008][.0000.0023.0002][.0000.002A.0002] -1F97 ; [.1F3F.0020.0002][.0000.0023.0002][.0000.002A.0002][.0000.004C.0002] -1F9F ; [.1F3F.0020.0008][.0000.0023.0002][.0000.002A.0002][.0000.004C.0002] -1F91 ; [.1F3F.0020.0002][.0000.0023.0002][.0000.004C.0002] -1F99 ; [.1F3F.0020.0008][.0000.0023.0002][.0000.004C.0002] -03AE ; [.1F3F.0020.0002][.0000.0024.0002] -1F75 ; [.1F3F.0020.0002][.0000.0024.0002] -0389 ; [.1F3F.0020.0008][.0000.0024.0002] -1FCB ; [.1F3F.0020.0008][.0000.0024.0002] -1FC4 ; [.1F3F.0020.0002][.0000.0024.0002][.0000.004C.0002] -1F74 ; [.1F3F.0020.0002][.0000.0025.0002] -1FCA ; [.1F3F.0020.0008][.0000.0025.0002] -1FC2 ; [.1F3F.0020.0002][.0000.0025.0002][.0000.004C.0002] -1FC6 ; [.1F3F.0020.0002][.0000.002A.0002] -1FC7 ; [.1F3F.0020.0002][.0000.002A.0002][.0000.004C.0002] -1FC3 ; [.1F3F.0020.0002][.0000.004C.0002] -1FCC ; [.1F3F.0020.0008][.0000.004C.0002] -03B8 ; [.1F40.0020.0002] -03D1 ; [.1F40.0020.0004] -1D6C9 ; [.1F40.0020.0005] -1D6DD ; [.1F40.0020.0005] -1D703 ; [.1F40.0020.0005] -1D717 ; [.1F40.0020.0005] -1D73D ; [.1F40.0020.0005] -1D751 ; [.1F40.0020.0005] -1D777 ; [.1F40.0020.0005] -1D78B ; [.1F40.0020.0005] -1D7B1 ; [.1F40.0020.0005] -1D7C5 ; [.1F40.0020.0005] -0398 ; [.1F40.0020.0008] -03F4 ; [.1F40.0020.000A] -1D6AF ; [.1F40.0020.000B] -1D6B9 ; [.1F40.0020.000B] -1D6E9 ; [.1F40.0020.000B] -1D6F3 ; [.1F40.0020.000B] -1D723 ; [.1F40.0020.000B] -1D72D ; [.1F40.0020.000B] -1D75D ; [.1F40.0020.000B] -1D767 ; [.1F40.0020.000B] -1D797 ; [.1F40.0020.000B] -1D7A1 ; [.1F40.0020.000B] -1DBF ; [.1F40.0020.0014] -03B9 ; [.1F41.0020.0002] -1FBE ; [.1F41.0020.0002] -037A ; [.1F41.0020.0004] -1D6CA ; [.1F41.0020.0005] -1D704 ; [.1F41.0020.0005] -1D73E ; [.1F41.0020.0005] -1D778 ; [.1F41.0020.0005] -1D7B2 ; [.1F41.0020.0005] -0399 ; [.1F41.0020.0008] -1D6B0 ; [.1F41.0020.000B] -1D6EA ; [.1F41.0020.000B] -1D724 ; [.1F41.0020.000B] -1D75E ; [.1F41.0020.000B] -1D798 ; [.1F41.0020.000B] -1F30 ; [.1F41.0020.0002][.0000.0022.0002] -1F38 ; [.1F41.0020.0008][.0000.0022.0002] -1F34 ; [.1F41.0020.0002][.0000.0022.0002][.0000.0024.0002] -1F3C ; [.1F41.0020.0008][.0000.0022.0002][.0000.0024.0002] -1F32 ; [.1F41.0020.0002][.0000.0022.0002][.0000.0025.0002] -1F3A ; [.1F41.0020.0008][.0000.0022.0002][.0000.0025.0002] -1F36 ; [.1F41.0020.0002][.0000.0022.0002][.0000.002A.0002] -1F3E ; [.1F41.0020.0008][.0000.0022.0002][.0000.002A.0002] -1F31 ; [.1F41.0020.0002][.0000.0023.0002] -1F39 ; [.1F41.0020.0008][.0000.0023.0002] -1F35 ; [.1F41.0020.0002][.0000.0023.0002][.0000.0024.0002] -1F3D ; [.1F41.0020.0008][.0000.0023.0002][.0000.0024.0002] -1F33 ; [.1F41.0020.0002][.0000.0023.0002][.0000.0025.0002] -1F3B ; [.1F41.0020.0008][.0000.0023.0002][.0000.0025.0002] -1F37 ; [.1F41.0020.0002][.0000.0023.0002][.0000.002A.0002] -1F3F ; [.1F41.0020.0008][.0000.0023.0002][.0000.002A.0002] -03AF ; [.1F41.0020.0002][.0000.0024.0002] -1F77 ; [.1F41.0020.0002][.0000.0024.0002] -038A ; [.1F41.0020.0008][.0000.0024.0002] -1FDB ; [.1F41.0020.0008][.0000.0024.0002] -1F76 ; [.1F41.0020.0002][.0000.0025.0002] -1FDA ; [.1F41.0020.0008][.0000.0025.0002] -1FD0 ; [.1F41.0020.0002][.0000.0026.0002] -1FD8 ; [.1F41.0020.0008][.0000.0026.0002] -1FD6 ; [.1F41.0020.0002][.0000.002A.0002] -03CA ; [.1F41.0020.0002][.0000.002B.0002] -03AA ; [.1F41.0020.0008][.0000.002B.0002] -0390 ; [.1F41.0020.0002][.0000.002B.0002][.0000.0024.0002] -1FD3 ; [.1F41.0020.0002][.0000.002B.0002][.0000.0024.0002] -1FD2 ; [.1F41.0020.0002][.0000.002B.0002][.0000.0025.0002] -1FD7 ; [.1F41.0020.0002][.0000.002B.0002][.0000.002A.0002] -1FD1 ; [.1F41.0020.0002][.0000.0032.0002] -1FD9 ; [.1F41.0020.0008][.0000.0032.0002] -03F3 ; [.1F42.0020.0002] -037F ; [.1F42.0020.0008] -03BA ; [.1F43.0020.0002] -03F0 ; [.1F43.0020.0004] -1D6CB ; [.1F43.0020.0005] -1D6DE ; [.1F43.0020.0005] -1D705 ; [.1F43.0020.0005] -1D718 ; [.1F43.0020.0005] -1D73F ; [.1F43.0020.0005] -1D752 ; [.1F43.0020.0005] -1D779 ; [.1F43.0020.0005] -1D78C ; [.1F43.0020.0005] -1D7B3 ; [.1F43.0020.0005] -1D7C6 ; [.1F43.0020.0005] -039A ; [.1F43.0020.0008] -1D6B1 ; [.1F43.0020.000B] -1D6EB ; [.1F43.0020.000B] -1D725 ; [.1F43.0020.000B] -1D75F ; [.1F43.0020.000B] -1D799 ; [.1F43.0020.000B] -03D7 ; [.1F43.0020.0004][.1F34.0020.0004][.1F41.0020.0004] -03CF ; [.1F43.0020.000A][.1F34.0020.0004][.1F41.0020.0004] -03BB ; [.1F44.0020.0002] -1D6CC ; [.1F44.0020.0005] -1D706 ; [.1F44.0020.0005] -1D740 ; [.1F44.0020.0005] -1D77A ; [.1F44.0020.0005] -1D7B4 ; [.1F44.0020.0005] -039B ; [.1F44.0020.0008] -1D6B2 ; [.1F44.0020.000B] -1D6EC ; [.1F44.0020.000B] -1D726 ; [.1F44.0020.000B] -1D760 ; [.1F44.0020.000B] -1D79A ; [.1F44.0020.000B] -1D27 ; [.1F45.0020.0002] -03BC ; [.1F46.0020.0002] -00B5 ; [.1F46.0020.0004] -1D6CD ; [.1F46.0020.0005] -1D707 ; [.1F46.0020.0005] -1D741 ; [.1F46.0020.0005] -1D77B ; [.1F46.0020.0005] -1D7B5 ; [.1F46.0020.0005] -039C ; [.1F46.0020.0008] -1D6B3 ; [.1F46.0020.000B] -1D6ED ; [.1F46.0020.000B] -1D727 ; [.1F46.0020.000B] -1D761 ; [.1F46.0020.000B] -1D79B ; [.1F46.0020.000B] -3382 ; [.1F46.0020.001C][.1BC2.0020.001D] -338C ; [.1F46.0020.001C][.1C60.0020.001D] -338D ; [.1F46.0020.001C][.1C6F.0020.001C] -3395 ; [.1F46.0020.001C][.1CF2.0020.001C] -339B ; [.1F46.0020.001C][.1D25.0020.001C] -33B2 ; [.1F46.0020.001C][.1DEC.0020.001C] -33B6 ; [.1F46.0020.001C][.1E5E.0020.001D] -33BC ; [.1F46.0020.001C][.1E70.0020.001D] -03BD ; [.1F47.0020.0002] -1D6CE ; [.1F47.0020.0005] -1D708 ; [.1F47.0020.0005] -1D742 ; [.1F47.0020.0005] -1D77C ; [.1F47.0020.0005] -1D7B6 ; [.1F47.0020.0005] -039D ; [.1F47.0020.0008] -1D6B4 ; [.1F47.0020.000B] -1D6EE ; [.1F47.0020.000B] -1D728 ; [.1F47.0020.000B] -1D762 ; [.1F47.0020.000B] -1D79C ; [.1F47.0020.000B] -03BE ; [.1F48.0020.0002] -1D6CF ; [.1F48.0020.0005] -1D709 ; [.1F48.0020.0005] -1D743 ; [.1F48.0020.0005] -1D77D ; [.1F48.0020.0005] -1D7B7 ; [.1F48.0020.0005] -039E ; [.1F48.0020.0008] -1D6B5 ; [.1F48.0020.000B] -1D6EF ; [.1F48.0020.000B] -1D729 ; [.1F48.0020.000B] -1D763 ; [.1F48.0020.000B] -1D79D ; [.1F48.0020.000B] -03BF ; [.1F49.0020.0002] -1D6D0 ; [.1F49.0020.0005] -1D70A ; [.1F49.0020.0005] -1D744 ; [.1F49.0020.0005] -1D77E ; [.1F49.0020.0005] -1D7B8 ; [.1F49.0020.0005] -039F ; [.1F49.0020.0008] -1D6B6 ; [.1F49.0020.000B] -1D6F0 ; [.1F49.0020.000B] -1D72A ; [.1F49.0020.000B] -1D764 ; [.1F49.0020.000B] -1D79E ; [.1F49.0020.000B] -1F40 ; [.1F49.0020.0002][.0000.0022.0002] -1F48 ; [.1F49.0020.0008][.0000.0022.0002] -1F44 ; [.1F49.0020.0002][.0000.0022.0002][.0000.0024.0002] -1F4C ; [.1F49.0020.0008][.0000.0022.0002][.0000.0024.0002] -1F42 ; [.1F49.0020.0002][.0000.0022.0002][.0000.0025.0002] -1F4A ; [.1F49.0020.0008][.0000.0022.0002][.0000.0025.0002] -1F41 ; [.1F49.0020.0002][.0000.0023.0002] -1F49 ; [.1F49.0020.0008][.0000.0023.0002] -1F45 ; [.1F49.0020.0002][.0000.0023.0002][.0000.0024.0002] -1F4D ; [.1F49.0020.0008][.0000.0023.0002][.0000.0024.0002] -1F43 ; [.1F49.0020.0002][.0000.0023.0002][.0000.0025.0002] -1F4B ; [.1F49.0020.0008][.0000.0023.0002][.0000.0025.0002] -03CC ; [.1F49.0020.0002][.0000.0024.0002] -1F79 ; [.1F49.0020.0002][.0000.0024.0002] -038C ; [.1F49.0020.0008][.0000.0024.0002] -1FF9 ; [.1F49.0020.0008][.0000.0024.0002] -1F78 ; [.1F49.0020.0002][.0000.0025.0002] -1FF8 ; [.1F49.0020.0008][.0000.0025.0002] -03C0 ; [.1F4A.0020.0002] -03D6 ; [.1F4A.0020.0004] -213C ; [.1F4A.0020.0005] -1D6D1 ; [.1F4A.0020.0005] -1D6E1 ; [.1F4A.0020.0005] -1D70B ; [.1F4A.0020.0005] -1D71B ; [.1F4A.0020.0005] -1D745 ; [.1F4A.0020.0005] -1D755 ; [.1F4A.0020.0005] -1D77F ; [.1F4A.0020.0005] -1D78F ; [.1F4A.0020.0005] -1D7B9 ; [.1F4A.0020.0005] -1D7C9 ; [.1F4A.0020.0005] -03A0 ; [.1F4A.0020.0008] -213F ; [.1F4A.0020.000B] -1D6B7 ; [.1F4A.0020.000B] -1D6F1 ; [.1F4A.0020.000B] -1D72B ; [.1F4A.0020.000B] -1D765 ; [.1F4A.0020.000B] -1D79F ; [.1F4A.0020.000B] -1D28 ; [.1F4B.0020.0002] -03FB ; [.1F4C.0020.0002] -03FA ; [.1F4C.0020.0008] -03DF ; [.1F4D.0020.0002] -03DE ; [.1F4D.0020.0008] -03D9 ; [.1F4E.0020.0002] -03D8 ; [.1F4E.0020.0008] -03C1 ; [.1F4F.0020.0002] -03F1 ; [.1F4F.0020.0004] -1D6D2 ; [.1F4F.0020.0005] -1D6E0 ; [.1F4F.0020.0005] -1D70C ; [.1F4F.0020.0005] -1D71A ; [.1F4F.0020.0005] -1D746 ; [.1F4F.0020.0005] -1D754 ; [.1F4F.0020.0005] -1D780 ; [.1F4F.0020.0005] -1D78E ; [.1F4F.0020.0005] -1D7BA ; [.1F4F.0020.0005] -1D7C8 ; [.1F4F.0020.0005] -03A1 ; [.1F4F.0020.0008] -1D6B8 ; [.1F4F.0020.000B] -1D6F2 ; [.1F4F.0020.000B] -1D72C ; [.1F4F.0020.000B] -1D766 ; [.1F4F.0020.000B] -1D7A0 ; [.1F4F.0020.000B] -1D68 ; [.1F4F.0020.0015] -1FE4 ; [.1F4F.0020.0002][.0000.0022.0002] -1FE5 ; [.1F4F.0020.0002][.0000.0023.0002] -1FEC ; [.1F4F.0020.0008][.0000.0023.0002] -1D29 ; [.1F50.0020.0002] -03FC ; [.1F51.0020.0002] -03C3 ; [.1F52.0020.0002] -03F2 ; [.1F52.0020.0004] -1D6D3 ; [.1F52.0020.0005] -1D6D4 ; [.1F52.0020.0005] -1D70D ; [.1F52.0020.0005] -1D70E ; [.1F52.0020.0005] -1D747 ; [.1F52.0020.0005] -1D748 ; [.1F52.0020.0005] -1D781 ; [.1F52.0020.0005] -1D782 ; [.1F52.0020.0005] -1D7BB ; [.1F52.0020.0005] -1D7BC ; [.1F52.0020.0005] -03A3 ; [.1F52.0020.0008] -03F9 ; [.1F52.0020.000A] -1D6BA ; [.1F52.0020.000B] -1D6F4 ; [.1F52.0020.000B] -1D72E ; [.1F52.0020.000B] -1D768 ; [.1F52.0020.000B] -1D7A2 ; [.1F52.0020.000B] -03C2 ; [.1F52.0020.0019] -037C ; [.1F53.0020.0002] -03FE ; [.1F53.0020.0008] -037B ; [.1F54.0020.0002] -03FD ; [.1F54.0020.0008] -037D ; [.1F55.0020.0002] -03FF ; [.1F55.0020.0008] -03C4 ; [.1F56.0020.0002] -1D6D5 ; [.1F56.0020.0005] -1D70F ; [.1F56.0020.0005] -1D749 ; [.1F56.0020.0005] -1D783 ; [.1F56.0020.0005] -1D7BD ; [.1F56.0020.0005] -03A4 ; [.1F56.0020.0008] -1D6BB ; [.1F56.0020.000B] -1D6F5 ; [.1F56.0020.000B] -1D72F ; [.1F56.0020.000B] -1D769 ; [.1F56.0020.000B] -1D7A3 ; [.1F56.0020.000B] -03C5 ; [.1F57.0020.0002] -1D6D6 ; [.1F57.0020.0005] -1D710 ; [.1F57.0020.0005] -1D74A ; [.1F57.0020.0005] -1D784 ; [.1F57.0020.0005] -1D7BE ; [.1F57.0020.0005] -03A5 ; [.1F57.0020.0008] -03D2 ; [.1F57.0020.000A] -1D6BC ; [.1F57.0020.000B] -1D6F6 ; [.1F57.0020.000B] -1D730 ; [.1F57.0020.000B] -1D76A ; [.1F57.0020.000B] -1D7A4 ; [.1F57.0020.000B] -1F50 ; [.1F57.0020.0002][.0000.0022.0002] -1F54 ; [.1F57.0020.0002][.0000.0022.0002][.0000.0024.0002] -1F52 ; [.1F57.0020.0002][.0000.0022.0002][.0000.0025.0002] -1F56 ; [.1F57.0020.0002][.0000.0022.0002][.0000.002A.0002] -1F51 ; [.1F57.0020.0002][.0000.0023.0002] -1F59 ; [.1F57.0020.0008][.0000.0023.0002] -1F55 ; [.1F57.0020.0002][.0000.0023.0002][.0000.0024.0002] -1F5D ; [.1F57.0020.0008][.0000.0023.0002][.0000.0024.0002] -1F53 ; [.1F57.0020.0002][.0000.0023.0002][.0000.0025.0002] -1F5B ; [.1F57.0020.0008][.0000.0023.0002][.0000.0025.0002] -1F57 ; [.1F57.0020.0002][.0000.0023.0002][.0000.002A.0002] -1F5F ; [.1F57.0020.0008][.0000.0023.0002][.0000.002A.0002] -03CD ; [.1F57.0020.0002][.0000.0024.0002] -1F7B ; [.1F57.0020.0002][.0000.0024.0002] -038E ; [.1F57.0020.0008][.0000.0024.0002] -1FEB ; [.1F57.0020.0008][.0000.0024.0002] -03D3 ; [.1F57.0020.000A][.0000.0024.0002] -1F7A ; [.1F57.0020.0002][.0000.0025.0002] -1FEA ; [.1F57.0020.0008][.0000.0025.0002] -1FE0 ; [.1F57.0020.0002][.0000.0026.0002] -1FE8 ; [.1F57.0020.0008][.0000.0026.0002] -1FE6 ; [.1F57.0020.0002][.0000.002A.0002] -03CB ; [.1F57.0020.0002][.0000.002B.0002] -03AB ; [.1F57.0020.0008][.0000.002B.0002] -03D4 ; [.1F57.0020.000A][.0000.002B.0002] -03B0 ; [.1F57.0020.0002][.0000.002B.0002][.0000.0024.0002] -1FE3 ; [.1F57.0020.0002][.0000.002B.0002][.0000.0024.0002] -1FE2 ; [.1F57.0020.0002][.0000.002B.0002][.0000.0025.0002] -1FE7 ; [.1F57.0020.0002][.0000.002B.0002][.0000.002A.0002] -1FE1 ; [.1F57.0020.0002][.0000.0032.0002] -1FE9 ; [.1F57.0020.0008][.0000.0032.0002] -03C6 ; [.1F58.0020.0002] -03D5 ; [.1F58.0020.0004] -1D6D7 ; [.1F58.0020.0005] -1D6DF ; [.1F58.0020.0005] -1D711 ; [.1F58.0020.0005] -1D719 ; [.1F58.0020.0005] -1D74B ; [.1F58.0020.0005] -1D753 ; [.1F58.0020.0005] -1D785 ; [.1F58.0020.0005] -1D78D ; [.1F58.0020.0005] -1D7BF ; [.1F58.0020.0005] -1D7C7 ; [.1F58.0020.0005] -03A6 ; [.1F58.0020.0008] -1D6BD ; [.1F58.0020.000B] -1D6F7 ; [.1F58.0020.000B] -1D731 ; [.1F58.0020.000B] -1D76B ; [.1F58.0020.000B] -1D7A5 ; [.1F58.0020.000B] -1D60 ; [.1F58.0020.0014] -1D69 ; [.1F58.0020.0015] -03C7 ; [.1F59.0020.0002] -1D6D8 ; [.1F59.0020.0005] -1D712 ; [.1F59.0020.0005] -1D74C ; [.1F59.0020.0005] -1D786 ; [.1F59.0020.0005] -1D7C0 ; [.1F59.0020.0005] -03A7 ; [.1F59.0020.0008] -1D6BE ; [.1F59.0020.000B] -1D6F8 ; [.1F59.0020.000B] -1D732 ; [.1F59.0020.000B] -1D76C ; [.1F59.0020.000B] -1D7A6 ; [.1F59.0020.000B] -1D61 ; [.1F59.0020.0014] -1D6A ; [.1F59.0020.0015] -03C8 ; [.1F5A.0020.0002] -1D6D9 ; [.1F5A.0020.0005] -1D713 ; [.1F5A.0020.0005] -1D74D ; [.1F5A.0020.0005] -1D787 ; [.1F5A.0020.0005] -1D7C1 ; [.1F5A.0020.0005] -03A8 ; [.1F5A.0020.0008] -1D6BF ; [.1F5A.0020.000B] -1D6F9 ; [.1F5A.0020.000B] -1D733 ; [.1F5A.0020.000B] -1D76D ; [.1F5A.0020.000B] -1D7A7 ; [.1F5A.0020.000B] -1D2A ; [.1F5B.0020.0002] -03C9 ; [.1F5C.0020.0002] -1D6DA ; [.1F5C.0020.0005] -1D714 ; [.1F5C.0020.0005] -1D74E ; [.1F5C.0020.0005] -1D788 ; [.1F5C.0020.0005] -1D7C2 ; [.1F5C.0020.0005] -03A9 ; [.1F5C.0020.0008] -2126 ; [.1F5C.0020.0008] -1D6C0 ; [.1F5C.0020.000B] -1D6FA ; [.1F5C.0020.000B] -1D734 ; [.1F5C.0020.000B] -1D76E ; [.1F5C.0020.000B] -1D7A8 ; [.1F5C.0020.000B] -1F60 ; [.1F5C.0020.0002][.0000.0022.0002] -1F68 ; [.1F5C.0020.0008][.0000.0022.0002] -1F64 ; [.1F5C.0020.0002][.0000.0022.0002][.0000.0024.0002] -1F6C ; [.1F5C.0020.0008][.0000.0022.0002][.0000.0024.0002] -1FA4 ; [.1F5C.0020.0002][.0000.0022.0002][.0000.0024.0002][.0000.004C.0002] -1FAC ; [.1F5C.0020.0008][.0000.0022.0002][.0000.0024.0002][.0000.004C.0002] -1F62 ; [.1F5C.0020.0002][.0000.0022.0002][.0000.0025.0002] -1F6A ; [.1F5C.0020.0008][.0000.0022.0002][.0000.0025.0002] -1FA2 ; [.1F5C.0020.0002][.0000.0022.0002][.0000.0025.0002][.0000.004C.0002] -1FAA ; [.1F5C.0020.0008][.0000.0022.0002][.0000.0025.0002][.0000.004C.0002] -1F66 ; [.1F5C.0020.0002][.0000.0022.0002][.0000.002A.0002] -1F6E ; [.1F5C.0020.0008][.0000.0022.0002][.0000.002A.0002] -1FA6 ; [.1F5C.0020.0002][.0000.0022.0002][.0000.002A.0002][.0000.004C.0002] -1FAE ; [.1F5C.0020.0008][.0000.0022.0002][.0000.002A.0002][.0000.004C.0002] -1FA0 ; [.1F5C.0020.0002][.0000.0022.0002][.0000.004C.0002] -1FA8 ; [.1F5C.0020.0008][.0000.0022.0002][.0000.004C.0002] -1F61 ; [.1F5C.0020.0002][.0000.0023.0002] -1F69 ; [.1F5C.0020.0008][.0000.0023.0002] -1F65 ; [.1F5C.0020.0002][.0000.0023.0002][.0000.0024.0002] -1F6D ; [.1F5C.0020.0008][.0000.0023.0002][.0000.0024.0002] -1FA5 ; [.1F5C.0020.0002][.0000.0023.0002][.0000.0024.0002][.0000.004C.0002] -1FAD ; [.1F5C.0020.0008][.0000.0023.0002][.0000.0024.0002][.0000.004C.0002] -1F63 ; [.1F5C.0020.0002][.0000.0023.0002][.0000.0025.0002] -1F6B ; [.1F5C.0020.0008][.0000.0023.0002][.0000.0025.0002] -1FA3 ; [.1F5C.0020.0002][.0000.0023.0002][.0000.0025.0002][.0000.004C.0002] -1FAB ; [.1F5C.0020.0008][.0000.0023.0002][.0000.0025.0002][.0000.004C.0002] -1F67 ; [.1F5C.0020.0002][.0000.0023.0002][.0000.002A.0002] -1F6F ; [.1F5C.0020.0008][.0000.0023.0002][.0000.002A.0002] -1FA7 ; [.1F5C.0020.0002][.0000.0023.0002][.0000.002A.0002][.0000.004C.0002] -1FAF ; [.1F5C.0020.0008][.0000.0023.0002][.0000.002A.0002][.0000.004C.0002] -1FA1 ; [.1F5C.0020.0002][.0000.0023.0002][.0000.004C.0002] -1FA9 ; [.1F5C.0020.0008][.0000.0023.0002][.0000.004C.0002] -03CE ; [.1F5C.0020.0002][.0000.0024.0002] -1F7D ; [.1F5C.0020.0002][.0000.0024.0002] -038F ; [.1F5C.0020.0008][.0000.0024.0002] -1FFB ; [.1F5C.0020.0008][.0000.0024.0002] -1FF4 ; [.1F5C.0020.0002][.0000.0024.0002][.0000.004C.0002] -1F7C ; [.1F5C.0020.0002][.0000.0025.0002] -1FFA ; [.1F5C.0020.0008][.0000.0025.0002] -1FF2 ; [.1F5C.0020.0002][.0000.0025.0002][.0000.004C.0002] -1FF6 ; [.1F5C.0020.0002][.0000.002A.0002] -1FF7 ; [.1F5C.0020.0002][.0000.002A.0002][.0000.004C.0002] -1FF3 ; [.1F5C.0020.0002][.0000.004C.0002] -1FFC ; [.1F5C.0020.0008][.0000.004C.0002] -AB65 ; [.1F5D.0020.0002] -03E1 ; [.1F5E.0020.0002] -03E0 ; [.1F5E.0020.0008] -0373 ; [.1F5F.0020.0002] -0372 ; [.1F5F.0020.0008] -03F8 ; [.1F60.0020.0002] -03F7 ; [.1F60.0020.0008] -2C81 ; [.1F61.0020.0002] -2C80 ; [.1F61.0020.0008] -2C83 ; [.1F62.0020.0002] -2C82 ; [.1F62.0020.0008] -2C85 ; [.1F63.0020.0002] -2C84 ; [.1F63.0020.0008] -2C87 ; [.1F64.0020.0002] -2C86 ; [.1F64.0020.0008] -2C89 ; [.1F65.0020.0002] -2C88 ; [.1F65.0020.0008] -2CB7 ; [.1F66.0020.0002] -2CB6 ; [.1F66.0020.0008] -2C8B ; [.1F67.0020.0002] -2C8A ; [.1F67.0020.0008] -2C8D ; [.1F68.0020.0002] -2C8C ; [.1F68.0020.0008] -2C8F ; [.1F69.0020.0002] -2C8E ; [.1F69.0020.0008] -2C91 ; [.1F6A.0020.0002] -2C90 ; [.1F6A.0020.0008] -2C93 ; [.1F6B.0020.0002] -2C92 ; [.1F6B.0020.0008] -2C95 ; [.1F6C.0020.0002] -2C94 ; [.1F6C.0020.0008] -2CE4 ; [.1F6C.0020.0004][.1F61.0020.0004][.1F6B.0020.0004] -2CB9 ; [.1F6D.0020.0002] -2CB8 ; [.1F6D.0020.0008] -2C97 ; [.1F6E.0020.0002] -2C96 ; [.1F6E.0020.0008] -2C99 ; [.1F6F.0020.0002] -2C98 ; [.1F6F.0020.0008] -2C9B ; [.1F70.0020.0002] -2C9A ; [.1F70.0020.0008] -2CBB ; [.1F71.0020.0002] -2CBA ; [.1F71.0020.0008] -2CBD ; [.1F72.0020.0002] -2CBC ; [.1F72.0020.0008] -2C9D ; [.1F73.0020.0002] -2C9C ; [.1F73.0020.0008] -2C9F ; [.1F74.0020.0002] -2C9E ; [.1F74.0020.0008] -2CA1 ; [.1F75.0020.0002] -2CA0 ; [.1F75.0020.0008] -2CA3 ; [.1F76.0020.0002] -2CA2 ; [.1F76.0020.0008] -2CA5 ; [.1F77.0020.0002] -2CA4 ; [.1F77.0020.0008] -2CA7 ; [.1F78.0020.0002] -2CA6 ; [.1F78.0020.0008] -2CA9 ; [.1F79.0020.0002] -2CA8 ; [.1F79.0020.0008] -2CAB ; [.1F7A.0020.0002] -2CAA ; [.1F7A.0020.0008] -2CAD ; [.1F7B.0020.0002] -2CAC ; [.1F7B.0020.0008] -2CAF ; [.1F7C.0020.0002] -2CAE ; [.1F7C.0020.0008] -2CB1 ; [.1F7D.0020.0002] -2CB0 ; [.1F7D.0020.0008] -2CBF ; [.1F7E.0020.0002] -2CBE ; [.1F7E.0020.0008] -2CC1 ; [.1F7F.0020.0002] -2CC0 ; [.1F7F.0020.0008] -03E3 ; [.1F80.0020.0002] -03E2 ; [.1F80.0020.0008] -2CEC ; [.1F81.0020.0002] -2CEB ; [.1F81.0020.0008] -2CC3 ; [.1F82.0020.0002] -2CC2 ; [.1F82.0020.0008] -2CC5 ; [.1F83.0020.0002] -2CC4 ; [.1F83.0020.0008] -2CC7 ; [.1F84.0020.0002] -2CC6 ; [.1F84.0020.0008] -03E5 ; [.1F85.0020.0002] -03E4 ; [.1F85.0020.0008] -03E7 ; [.1F86.0020.0002] -03E6 ; [.1F86.0020.0008] -2CF3 ; [.1F87.0020.0002] -2CF2 ; [.1F87.0020.0008] -2CC9 ; [.1F88.0020.0002] -2CC8 ; [.1F88.0020.0008] -03E9 ; [.1F89.0020.0002] -03E8 ; [.1F89.0020.0008] -2CCB ; [.1F8A.0020.0002] -2CCA ; [.1F8A.0020.0008] -2CCD ; [.1F8B.0020.0002] -2CCC ; [.1F8B.0020.0008] -2CCF ; [.1F8C.0020.0002] -2CCE ; [.1F8C.0020.0008] -2CD1 ; [.1F8D.0020.0002] -2CD0 ; [.1F8D.0020.0008] -2CD3 ; [.1F8E.0020.0002] -2CD2 ; [.1F8E.0020.0008] -2CD5 ; [.1F8F.0020.0002] -2CD4 ; [.1F8F.0020.0008] -03EB ; [.1F90.0020.0002] -03EA ; [.1F90.0020.0008] -2CEE ; [.1F91.0020.0002] -2CED ; [.1F91.0020.0008] -2CD7 ; [.1F92.0020.0002] -2CD6 ; [.1F92.0020.0008] -03ED ; [.1F93.0020.0002] -03EC ; [.1F93.0020.0008] -2CD9 ; [.1F94.0020.0002] -2CD8 ; [.1F94.0020.0008] -2CDB ; [.1F95.0020.0002] -2CDA ; [.1F95.0020.0008] -2CDD ; [.1F96.0020.0002] -2CDC ; [.1F96.0020.0008] -03EF ; [.1F97.0020.0002] -03EE ; [.1F97.0020.0008] -2CB3 ; [.1F98.0020.0002] -2CB2 ; [.1F98.0020.0008] -2CB5 ; [.1F99.0020.0002] -2CB4 ; [.1F99.0020.0008] -2CDF ; [.1F9A.0020.0002] -2CDE ; [.1F9A.0020.0008] -2CE1 ; [.1F9B.0020.0002] -2CE0 ; [.1F9B.0020.0008] -2CE3 ; [.1F9C.0020.0002] -2CE2 ; [.1F9C.0020.0008] -0430 ; [.1F9D.0020.0002] -2DF6 ; [.1F9D.0020.0004] -0410 ; [.1F9D.0020.0008] -04D1 ; [.1F9D.0020.0002][.0000.0026.0002] -04D0 ; [.1F9D.0020.0008][.0000.0026.0002] -04D3 ; [.1F9D.0020.0002][.0000.002B.0002] -04D2 ; [.1F9D.0020.0008][.0000.002B.0002] -04D9 ; [.1FA1.0020.0002] -04D8 ; [.1FA1.0020.0008] -04DB ; [.1FA1.0020.0002][.0000.002B.0002] -04DA ; [.1FA1.0020.0008][.0000.002B.0002] -04D5 ; [.1FA5.0020.0002] -04D4 ; [.1FA5.0020.0008] -0431 ; [.1FA9.0020.0002] -2DE0 ; [.1FA9.0020.0004] -0411 ; [.1FA9.0020.0008] -0432 ; [.1FAD.0020.0002] -2DE1 ; [.1FAD.0020.0004] -0412 ; [.1FAD.0020.0008] -0433 ; [.1FB1.0020.0002] -2DE2 ; [.1FB1.0020.0004] -0413 ; [.1FB1.0020.0008] -0453 ; [.1FB1.0020.0002][.0000.0024.0002] -0403 ; [.1FB1.0020.0008][.0000.0024.0002] -0491 ; [.1FB1.0020.0004][.0000.010C.0004] -0490 ; [.1FB1.0020.000A][.0000.010C.0004] -0493 ; [.1FB5.0020.0002] -0492 ; [.1FB5.0020.0008] -04FB ; [.1FB9.0020.0002] -04FA ; [.1FB9.0020.0008] -0495 ; [.1FBD.0020.0002] -0494 ; [.1FBD.0020.0008] -04F7 ; [.1FC1.0020.0002] -04F6 ; [.1FC1.0020.0008] -0434 ; [.1FC5.0020.0002] -2DE3 ; [.1FC5.0020.0004] -0414 ; [.1FC5.0020.0008] -0501 ; [.1FC9.0020.0002] -0500 ; [.1FC9.0020.0008] -A681 ; [.1FCA.0020.0002] -A680 ; [.1FCA.0020.0008] -0452 ; [.1FCB.0020.0002] -0402 ; [.1FCB.0020.0008] -A663 ; [.1FCF.0020.0002] -A662 ; [.1FCF.0020.0008] -0503 ; [.1FD0.0020.0002] -0502 ; [.1FD0.0020.0008] -0499 ; [.1FD1.0020.0002] -0498 ; [.1FD1.0020.0008] -0435 ; [.1FD5.0020.0002] -2DF7 ; [.1FD5.0020.0004] -0415 ; [.1FD5.0020.0008] -0450 ; [.1FD5.0020.0002][.0000.0025.0002] -0400 ; [.1FD5.0020.0008][.0000.0025.0002] -04D7 ; [.1FD5.0020.0002][.0000.0026.0002] -04D6 ; [.1FD5.0020.0008][.0000.0026.0002] -0451 ; [.1FD5.0020.0002][.0000.002B.0002] -0401 ; [.1FD5.0020.0008][.0000.002B.0002] -0454 ; [.1FD9.0020.0002] -A674 ; [.1FD9.0020.0004] -0404 ; [.1FD9.0020.0008] -0436 ; [.1FDD.0020.0002] -2DE4 ; [.1FDD.0020.0004] -0416 ; [.1FDD.0020.0008] -04C2 ; [.1FDD.0020.0002][.0000.0026.0002] -04C1 ; [.1FDD.0020.0008][.0000.0026.0002] -04DD ; [.1FDD.0020.0002][.0000.002B.0002] -04DC ; [.1FDD.0020.0008][.0000.002B.0002] -052B ; [.1FE1.0020.0002] -052A ; [.1FE1.0020.0008] -A685 ; [.1FE2.0020.0002] -A684 ; [.1FE2.0020.0008] -0497 ; [.1FE3.0020.0002] -0496 ; [.1FE3.0020.0008] -0437 ; [.1FE7.0020.0002] -2DE5 ; [.1FE7.0020.0004] -0417 ; [.1FE7.0020.0008] -04DF ; [.1FE7.0020.0002][.0000.002B.0002] -04DE ; [.1FE7.0020.0008][.0000.002B.0002] -A641 ; [.1FEB.0020.0002] -A640 ; [.1FEB.0020.0008] -0505 ; [.1FEC.0020.0002] -0504 ; [.1FEC.0020.0008] -0511 ; [.1FED.0020.0002] -0510 ; [.1FED.0020.0008] -A643 ; [.1FEE.0020.0002] -A642 ; [.1FEE.0020.0008] -0455 ; [.1FEF.0020.0002] -0405 ; [.1FEF.0020.0008] -A645 ; [.1FF3.0020.0002] -A644 ; [.1FF3.0020.0008] -04E1 ; [.1FF4.0020.0002] -04E0 ; [.1FF4.0020.0008] -A689 ; [.1FF8.0020.0002] -A688 ; [.1FF8.0020.0008] -0507 ; [.1FF9.0020.0002] -0506 ; [.1FF9.0020.0008] -A683 ; [.1FFA.0020.0002] -A682 ; [.1FFA.0020.0008] -0438 ; [.1FFB.0020.0002] -A675 ; [.1FFB.0020.0004] -0418 ; [.1FFB.0020.0008] -045D ; [.1FFB.0020.0002][.0000.0025.0002] -040D ; [.1FFB.0020.0008][.0000.0025.0002] -04E5 ; [.1FFB.0020.0002][.0000.002B.0002] -04E4 ; [.1FFB.0020.0008][.0000.002B.0002] -04E3 ; [.1FFB.0020.0002][.0000.0032.0002] -04E2 ; [.1FFB.0020.0008][.0000.0032.0002] -048B ; [.1FFF.0020.0002] -048A ; [.1FFF.0020.0008] -0456 ; [.2003.0020.0002] -0406 ; [.2003.0020.0008] -0457 ; [.2003.0020.0002][.0000.002B.0002] -A676 ; [.2003.0020.0004][.0000.002B.0004] -0407 ; [.2003.0020.0008][.0000.002B.0002] -A647 ; [.2007.0020.0002] -A646 ; [.2007.0020.0008] -0439 ; [.2008.0020.0002] -0438 0306 ; [.2008.0020.0002] -0419 ; [.2008.0020.0008] -0418 0306 ; [.2008.0020.0008] -0458 ; [.200C.0020.0002] -0408 ; [.200C.0020.0008] -A649 ; [.2010.0020.0002] -2DF8 ; [.2010.0020.0004] -A648 ; [.2010.0020.0008] -043A ; [.2011.0020.0002] -2DE6 ; [.2011.0020.0004] -041A ; [.2011.0020.0008] -045C ; [.2011.0020.0002][.0000.0024.0002] -040C ; [.2011.0020.0008][.0000.0024.0002] -049B ; [.2015.0020.0002] -049A ; [.2015.0020.0008] -04C4 ; [.2019.0020.0002] -04C3 ; [.2019.0020.0008] -04A1 ; [.201D.0020.0002] -04A0 ; [.201D.0020.0008] -049F ; [.2021.0020.0002] -049E ; [.2021.0020.0008] -049D ; [.2025.0020.0002] -049C ; [.2025.0020.0008] -051F ; [.2029.0020.0002] -051E ; [.2029.0020.0008] -051B ; [.202A.0020.0002] -051A ; [.202A.0020.0008] -043B ; [.202B.0020.0002] -2DE7 ; [.202B.0020.0004] -041B ; [.202B.0020.0008] -1D2B ; [.202F.0020.0002] -04C6 ; [.2030.0020.0002] -04C5 ; [.2030.0020.0008] -052F ; [.2034.0020.0002] -052E ; [.2034.0020.0008] -0513 ; [.2035.0020.0002] -0512 ; [.2035.0020.0008] -0521 ; [.2036.0020.0002] -0520 ; [.2036.0020.0008] -0459 ; [.2037.0020.0002] -0409 ; [.2037.0020.0008] -A665 ; [.203B.0020.0002] -A664 ; [.203B.0020.0008] -0509 ; [.203C.0020.0002] -0508 ; [.203C.0020.0008] -0515 ; [.203D.0020.0002] -0514 ; [.203D.0020.0008] -043C ; [.203E.0020.0002] -2DE8 ; [.203E.0020.0004] -041C ; [.203E.0020.0008] -04CE ; [.2042.0020.0002] -04CD ; [.2042.0020.0008] -A667 ; [.2046.0020.0002] -A666 ; [.2046.0020.0008] -043D ; [.2047.0020.0002] -2DE9 ; [.2047.0020.0004] -041D ; [.2047.0020.0008] -1D78 ; [.2047.0020.0014] -0529 ; [.204B.0020.0002] -0528 ; [.204B.0020.0008] -04CA ; [.204C.0020.0002] -04C9 ; [.204C.0020.0008] -04A3 ; [.2050.0020.0002] -04A2 ; [.2050.0020.0008] -04C8 ; [.2054.0020.0002] -04C7 ; [.2054.0020.0008] -0523 ; [.2058.0020.0002] -0522 ; [.2058.0020.0008] -04A5 ; [.2059.0020.0002] -04A4 ; [.2059.0020.0008] -045A ; [.205D.0020.0002] -040A ; [.205D.0020.0008] -050B ; [.2061.0020.0002] -050A ; [.2061.0020.0008] -043E ; [.2062.0020.0002] -2DEA ; [.2062.0020.0004] -A669 ; [.2062.0020.0004] -A66B ; [.2062.0020.0004] -A66D ; [.2062.0020.0004] -A66E ; [.2062.0020.0004] -A699 ; [.2062.0020.0004] -A69B ; [.2062.0020.0004] -041E ; [.2062.0020.0008] -A668 ; [.2062.0020.000A] -A66A ; [.2062.0020.000A] -A66C ; [.2062.0020.000A] -A698 ; [.2062.0020.000A] -A69A ; [.2062.0020.000A] -04E7 ; [.2062.0020.0002][.0000.002B.0002] -04E6 ; [.2062.0020.0008][.0000.002B.0002] -04E9 ; [.2066.0020.0002] -04E8 ; [.2066.0020.0008] -04EB ; [.2066.0020.0002][.0000.002B.0002] -04EA ; [.2066.0020.0008][.0000.002B.0002] -043F ; [.206A.0020.0002] -2DEB ; [.206A.0020.0004] -041F ; [.206A.0020.0008] -0525 ; [.206E.0020.0002] -0524 ; [.206E.0020.0008] -04A7 ; [.206F.0020.0002] -04A6 ; [.206F.0020.0008] -0481 ; [.2073.0020.0002] -0480 ; [.2073.0020.0008] -0440 ; [.2077.0020.0002] -2DEC ; [.2077.0020.0004] -0420 ; [.2077.0020.0008] -048F ; [.207B.0020.0002] -048E ; [.207B.0020.0008] -0517 ; [.207F.0020.0002] -0516 ; [.207F.0020.0008] -0441 ; [.2080.0020.0002] -2DED ; [.2080.0020.0004] -0421 ; [.2080.0020.0008] -2DF5 ; [.2080.0020.0004][.2089.0020.0004] -050D ; [.2084.0020.0002] -050C ; [.2084.0020.0008] -04AB ; [.2085.0020.0002] -04AA ; [.2085.0020.0008] -0442 ; [.2089.0020.0002] -2DEE ; [.2089.0020.0004] -0422 ; [.2089.0020.0008] -A68D ; [.208D.0020.0002] -A68C ; [.208D.0020.0008] -050F ; [.208E.0020.0002] -050E ; [.208E.0020.0008] -04AD ; [.208F.0020.0002] -04AC ; [.208F.0020.0008] -A68B ; [.2093.0020.0002] -A68A ; [.2093.0020.0008] -045B ; [.2094.0020.0002] -040B ; [.2094.0020.0008] -0443 ; [.2098.0020.0002] -A677 ; [.2098.0020.0004] -0423 ; [.2098.0020.0008] -045E ; [.2098.0020.0002][.0000.0026.0002] -040E ; [.2098.0020.0008][.0000.0026.0002] -04F1 ; [.2098.0020.0002][.0000.002B.0002] -04F0 ; [.2098.0020.0008][.0000.002B.0002] -04F3 ; [.2098.0020.0002][.0000.002C.0002] -04F2 ; [.2098.0020.0008][.0000.002C.0002] -04EF ; [.2098.0020.0002][.0000.0032.0002] -04EE ; [.2098.0020.0008][.0000.0032.0002] -04AF ; [.209C.0020.0002] -04AE ; [.209C.0020.0008] -04B1 ; [.20A0.0020.0002] -04B0 ; [.20A0.0020.0008] -A64B ; [.20A4.0020.0002] -2DF9 ; [.20A4.0020.0004] -A64A ; [.20A4.0020.0008] -0479 ; [.20A5.0020.0002] -0478 ; [.20A5.0020.0008] -0444 ; [.20A9.0020.0002] -A69E ; [.20A9.0020.0004] -0424 ; [.20A9.0020.0008] -0445 ; [.20AD.0020.0002] -2DEF ; [.20AD.0020.0004] -0425 ; [.20AD.0020.0008] -04FD ; [.20B1.0020.0002] -04FC ; [.20B1.0020.0008] -04FF ; [.20B5.0020.0002] -04FE ; [.20B5.0020.0008] -04B3 ; [.20B9.0020.0002] -04B2 ; [.20B9.0020.0008] -04BB ; [.20BD.0020.0002] -04BA ; [.20BD.0020.0008] -0527 ; [.20C1.0020.0002] -0526 ; [.20C1.0020.0008] -A695 ; [.20C2.0020.0002] -A694 ; [.20C2.0020.0008] -0461 ; [.20C3.0020.0002] -A67B ; [.20C3.0020.0004] -0460 ; [.20C3.0020.0008] -047F ; [.20C7.0020.0002] -047E ; [.20C7.0020.0008] -A64D ; [.20CB.0020.0002] -A64C ; [.20CB.0020.0008] -047D ; [.20CC.0020.0002] -047C ; [.20CC.0020.0008] -047B ; [.20D0.0020.0002] -047A ; [.20D0.0020.0008] -0446 ; [.20D4.0020.0002] -2DF0 ; [.20D4.0020.0004] -0426 ; [.20D4.0020.0008] -A661 ; [.20D8.0020.0002] -A660 ; [.20D8.0020.0008] -A68F ; [.20D9.0020.0002] -A68E ; [.20D9.0020.0008] -04B5 ; [.20DA.0020.0002] -04B4 ; [.20DA.0020.0008] -A691 ; [.20DE.0020.0002] -A690 ; [.20DE.0020.0008] -0447 ; [.20DF.0020.0002] -2DF1 ; [.20DF.0020.0004] -0427 ; [.20DF.0020.0008] -04F5 ; [.20DF.0020.0002][.0000.002B.0002] -04F4 ; [.20DF.0020.0008][.0000.002B.0002] -052D ; [.20E3.0020.0002] -052C ; [.20E3.0020.0008] -A693 ; [.20E4.0020.0002] -A692 ; [.20E4.0020.0008] -04B7 ; [.20E5.0020.0002] -04B6 ; [.20E5.0020.0008] -04CC ; [.20E9.0020.0002] -04CB ; [.20E9.0020.0008] -04B9 ; [.20ED.0020.0002] -04B8 ; [.20ED.0020.0008] -A687 ; [.20F1.0020.0002] -A686 ; [.20F1.0020.0008] -04BD ; [.20F2.0020.0002] -04BC ; [.20F2.0020.0008] -04BF ; [.20F6.0020.0002] -04BE ; [.20F6.0020.0008] -045F ; [.20FA.0020.0002] -040F ; [.20FA.0020.0008] -0448 ; [.20FE.0020.0002] -2DF2 ; [.20FE.0020.0004] -0428 ; [.20FE.0020.0008] -A697 ; [.2102.0020.0002] -A696 ; [.2102.0020.0008] -0449 ; [.2103.0020.0002] -2DF3 ; [.2103.0020.0004] -0429 ; [.2103.0020.0008] -A64F ; [.2107.0020.0002] -A64E ; [.2107.0020.0008] -2E2F ; [.2108.0020.0002] -A67F ; [.2109.0020.0002] -044A ; [.210A.0020.0002] -A678 ; [.210A.0020.0004] -042A ; [.210A.0020.0008] -A69C ; [.210A.0020.0014] -A651 ; [.210E.0020.0002] -A650 ; [.210E.0020.0008] -044B ; [.210F.0020.0002] -A679 ; [.210F.0020.0004] -042B ; [.210F.0020.0008] -04F9 ; [.210F.0020.0002][.0000.002B.0002] -04F8 ; [.210F.0020.0008][.0000.002B.0002] -044C ; [.2113.0020.0002] -A67A ; [.2113.0020.0004] -042C ; [.2113.0020.0008] -A69D ; [.2113.0020.0014] -048D ; [.2117.0020.0002] -048C ; [.2117.0020.0008] -0463 ; [.211B.0020.0002] -2DFA ; [.211B.0020.0004] -0462 ; [.211B.0020.0008] -A653 ; [.211F.0020.0002] -A652 ; [.211F.0020.0008] -044D ; [.2120.0020.0002] -042D ; [.2120.0020.0008] -04ED ; [.2120.0020.0002][.0000.002B.0002] -04EC ; [.2120.0020.0008][.0000.002B.0002] -044E ; [.2124.0020.0002] -2DFB ; [.2124.0020.0004] -042E ; [.2124.0020.0008] -A655 ; [.2128.0020.0002] -A654 ; [.2128.0020.0008] -A657 ; [.2129.0020.0002] -2DFC ; [.2129.0020.0004] -A656 ; [.2129.0020.0008] -044F ; [.212A.0020.0002] -042F ; [.212A.0020.0008] -0519 ; [.212E.0020.0002] -0518 ; [.212E.0020.0008] -0465 ; [.212F.0020.0002] -A69F ; [.212F.0020.0004] -0464 ; [.212F.0020.0008] -0467 ; [.2133.0020.0002] -2DFD ; [.2133.0020.0004] -0466 ; [.2133.0020.0008] -A659 ; [.2137.0020.0002] -A658 ; [.2137.0020.0008] -046B ; [.2138.0020.0002] -2DFE ; [.2138.0020.0004] -046A ; [.2138.0020.0008] -A65B ; [.213C.0020.0002] -A65A ; [.213C.0020.0008] -0469 ; [.213D.0020.0002] -0468 ; [.213D.0020.0008] -A65D ; [.2141.0020.0002] -A65C ; [.2141.0020.0008] -046D ; [.2142.0020.0002] -2DFF ; [.2142.0020.0004] -046C ; [.2142.0020.0008] -046F ; [.2146.0020.0002] -046E ; [.2146.0020.0008] -0471 ; [.214A.0020.0002] -0470 ; [.214A.0020.0008] -0473 ; [.214E.0020.0002] -2DF4 ; [.214E.0020.0004] -0472 ; [.214E.0020.0008] -0475 ; [.2152.0020.0002] -0474 ; [.2152.0020.0008] -0477 ; [.2152.0020.0002][.0000.003C.0002] -0476 ; [.2152.0020.0008][.0000.003C.0002] -A65F ; [.2156.0020.0002] -A65E ; [.2156.0020.0008] -04A9 ; [.2157.0020.0002] -04A8 ; [.2157.0020.0008] -051D ; [.215B.0020.0002] -051C ; [.215B.0020.0008] -04CF ; [.215C.0020.0002] -04C0 ; [.215C.0020.0008] -2C30 ; [.2160.0020.0002] -2C00 ; [.2160.0020.0008] -2C31 ; [.2161.0020.0002] -2C01 ; [.2161.0020.0008] -2C32 ; [.2162.0020.0002] -2C02 ; [.2162.0020.0008] -2C33 ; [.2163.0020.0002] -2C03 ; [.2163.0020.0008] -2C34 ; [.2164.0020.0002] -2C04 ; [.2164.0020.0008] -2C35 ; [.2165.0020.0002] -2C05 ; [.2165.0020.0008] -2C36 ; [.2166.0020.0002] -2C06 ; [.2166.0020.0008] -2C37 ; [.2167.0020.0002] -2C07 ; [.2167.0020.0008] -2C38 ; [.2168.0020.0002] -2C08 ; [.2168.0020.0008] -2C39 ; [.2169.0020.0002] -2C09 ; [.2169.0020.0008] -2C3A ; [.216A.0020.0002] -2C0A ; [.216A.0020.0008] -2C3B ; [.216B.0020.0002] -2C0B ; [.216B.0020.0008] -2C3C ; [.216C.0020.0002] -2C0C ; [.216C.0020.0008] -2C3D ; [.216D.0020.0002] -2C0D ; [.216D.0020.0008] -2C3E ; [.216E.0020.0002] -2C0E ; [.216E.0020.0008] -2C3F ; [.216F.0020.0002] -2C0F ; [.216F.0020.0008] -2C40 ; [.2170.0020.0002] -2C10 ; [.2170.0020.0008] -2C41 ; [.2171.0020.0002] -2C11 ; [.2171.0020.0008] -2C42 ; [.2172.0020.0002] -2C12 ; [.2172.0020.0008] -2C43 ; [.2173.0020.0002] -2C13 ; [.2173.0020.0008] -2C44 ; [.2174.0020.0002] -2C14 ; [.2174.0020.0008] -2C45 ; [.2175.0020.0002] -2C15 ; [.2175.0020.0008] -2C46 ; [.2176.0020.0002] -2C16 ; [.2176.0020.0008] -2C47 ; [.2177.0020.0002] -2C17 ; [.2177.0020.0008] -2C48 ; [.2178.0020.0002] -2C18 ; [.2178.0020.0008] -2C49 ; [.2179.0020.0002] -2C19 ; [.2179.0020.0008] -2C4A ; [.217A.0020.0002] -2C1A ; [.217A.0020.0008] -2C4B ; [.217B.0020.0002] -2C1B ; [.217B.0020.0008] -2C4C ; [.217C.0020.0002] -2C1C ; [.217C.0020.0008] -2C4D ; [.217D.0020.0002] -2C1D ; [.217D.0020.0008] -2C4E ; [.217E.0020.0002] -2C1E ; [.217E.0020.0008] -2C4F ; [.217F.0020.0002] -2C1F ; [.217F.0020.0008] -2C50 ; [.2180.0020.0002] -2C20 ; [.2180.0020.0008] -2C51 ; [.2181.0020.0002] -2C21 ; [.2181.0020.0008] -2C52 ; [.2182.0020.0002] -2C22 ; [.2182.0020.0008] -2C53 ; [.2183.0020.0002] -2C23 ; [.2183.0020.0008] -2C54 ; [.2184.0020.0002] -2C24 ; [.2184.0020.0008] -2C55 ; [.2185.0020.0002] -2C25 ; [.2185.0020.0008] -2C56 ; [.2186.0020.0002] -2C26 ; [.2186.0020.0008] -2C57 ; [.2187.0020.0002] -2C27 ; [.2187.0020.0008] -2C58 ; [.2188.0020.0002] -2C28 ; [.2188.0020.0008] -2C59 ; [.2189.0020.0002] -2C29 ; [.2189.0020.0008] -2C5A ; [.218A.0020.0002] -2C2A ; [.218A.0020.0008] -2C5B ; [.218B.0020.0002] -2C2B ; [.218B.0020.0008] -2C5C ; [.218C.0020.0002] -2C2C ; [.218C.0020.0008] -2C5D ; [.218D.0020.0002] -2C2D ; [.218D.0020.0008] -2C5E ; [.218E.0020.0002] -2C2E ; [.218E.0020.0008] -10350 ; [.218F.0020.0002] -10376 ; [.218F.0020.0004] -10351 ; [.2190.0020.0002] -10352 ; [.2191.0020.0002] -10353 ; [.2192.0020.0002] -10377 ; [.2192.0020.0004] -10354 ; [.2193.0020.0002] -10355 ; [.2194.0020.0002] -10356 ; [.2195.0020.0002] -10357 ; [.2196.0020.0002] -10378 ; [.2196.0020.0004] -10358 ; [.2197.0020.0002] -10359 ; [.2198.0020.0002] -1035A ; [.2199.0020.0002] -1035B ; [.219A.0020.0002] -1035C ; [.219B.0020.0002] -1035D ; [.219C.0020.0002] -10379 ; [.219C.0020.0004] -1035E ; [.219D.0020.0002] -1035F ; [.219E.0020.0002] -10360 ; [.219F.0020.0002] -10361 ; [.21A0.0020.0002] -1037A ; [.21A0.0020.0004] -10362 ; [.21A1.0020.0002] -10363 ; [.21A2.0020.0002] -10364 ; [.21A3.0020.0002] -10365 ; [.21A4.0020.0002] -10366 ; [.21A5.0020.0002] -10367 ; [.21A6.0020.0002] -10368 ; [.21A7.0020.0002] -10369 ; [.21A8.0020.0002] -1036A ; [.21A9.0020.0002] -1036B ; [.21AA.0020.0002] -1036C ; [.21AB.0020.0002] -1036D ; [.21AC.0020.0002] -1036E ; [.21AD.0020.0002] -1036F ; [.21AE.0020.0002] -10370 ; [.21AF.0020.0002] -10371 ; [.21B0.0020.0002] -10372 ; [.21B1.0020.0002] -10373 ; [.21B2.0020.0002] -10374 ; [.21B3.0020.0002] -10375 ; [.21B4.0020.0002] -10D0 ; [.21B5.0020.0002] -2D00 ; [.21B6.0020.0002] -10A0 ; [.21B6.0020.0008] -10D1 ; [.21B7.0020.0002] -2D01 ; [.21B8.0020.0002] -10A1 ; [.21B8.0020.0008] -10D2 ; [.21B9.0020.0002] -2D02 ; [.21BA.0020.0002] -10A2 ; [.21BA.0020.0008] -10D3 ; [.21BB.0020.0002] -2D03 ; [.21BC.0020.0002] -10A3 ; [.21BC.0020.0008] -10D4 ; [.21BD.0020.0002] -2D04 ; [.21BE.0020.0002] -10A4 ; [.21BE.0020.0008] -10D5 ; [.21BF.0020.0002] -2D05 ; [.21C0.0020.0002] -10A5 ; [.21C0.0020.0008] -10D6 ; [.21C1.0020.0002] -2D06 ; [.21C2.0020.0002] -10A6 ; [.21C2.0020.0008] -10F1 ; [.21C3.0020.0002] -2D21 ; [.21C4.0020.0002] -10C1 ; [.21C4.0020.0008] -10D7 ; [.21C5.0020.0002] -2D07 ; [.21C6.0020.0002] -10A7 ; [.21C6.0020.0008] -10D8 ; [.21C7.0020.0002] -2D08 ; [.21C8.0020.0002] -10A8 ; [.21C8.0020.0008] -10D9 ; [.21C9.0020.0002] -2D09 ; [.21CA.0020.0002] -10A9 ; [.21CA.0020.0008] -10DA ; [.21CB.0020.0002] -2D0A ; [.21CC.0020.0002] -10AA ; [.21CC.0020.0008] -10DB ; [.21CD.0020.0002] -2D0B ; [.21CE.0020.0002] -10AB ; [.21CE.0020.0008] -10DC ; [.21CF.0020.0002] -10FC ; [.21CF.0020.0014] -2D0C ; [.21D0.0020.0002] -10AC ; [.21D0.0020.0008] -10F2 ; [.21D1.0020.0002] -2D22 ; [.21D2.0020.0002] -10C2 ; [.21D2.0020.0008] -10DD ; [.21D3.0020.0002] -2D0D ; [.21D4.0020.0002] -10AD ; [.21D4.0020.0008] -10DE ; [.21D5.0020.0002] -2D0E ; [.21D6.0020.0002] -10AE ; [.21D6.0020.0008] -10DF ; [.21D7.0020.0002] -2D0F ; [.21D8.0020.0002] -10AF ; [.21D8.0020.0008] -10E0 ; [.21D9.0020.0002] -2D10 ; [.21DA.0020.0002] -10B0 ; [.21DA.0020.0008] -10E1 ; [.21DB.0020.0002] -2D11 ; [.21DC.0020.0002] -10B1 ; [.21DC.0020.0008] -10E2 ; [.21DD.0020.0002] -2D12 ; [.21DE.0020.0002] -10B2 ; [.21DE.0020.0008] -10F3 ; [.21DF.0020.0002] -2D23 ; [.21E0.0020.0002] -10C3 ; [.21E0.0020.0008] -10E3 ; [.21E1.0020.0002] -2D13 ; [.21E2.0020.0002] -10B3 ; [.21E2.0020.0008] -10E4 ; [.21E3.0020.0002] -2D14 ; [.21E4.0020.0002] -10B4 ; [.21E4.0020.0008] -10E5 ; [.21E5.0020.0002] -2D15 ; [.21E6.0020.0002] -10B5 ; [.21E6.0020.0008] -10E6 ; [.21E7.0020.0002] -2D16 ; [.21E8.0020.0002] -10B6 ; [.21E8.0020.0008] -10E7 ; [.21E9.0020.0002] -2D17 ; [.21EA.0020.0002] -10B7 ; [.21EA.0020.0008] -10E8 ; [.21EB.0020.0002] -2D18 ; [.21EC.0020.0002] -10B8 ; [.21EC.0020.0008] -10E9 ; [.21ED.0020.0002] -2D19 ; [.21EE.0020.0002] -10B9 ; [.21EE.0020.0008] -10EA ; [.21EF.0020.0002] -2D1A ; [.21F0.0020.0002] -10BA ; [.21F0.0020.0008] -10EB ; [.21F1.0020.0002] -2D1B ; [.21F2.0020.0002] -10BB ; [.21F2.0020.0008] -10EC ; [.21F3.0020.0002] -2D1C ; [.21F4.0020.0002] -10BC ; [.21F4.0020.0008] -10ED ; [.21F5.0020.0002] -2D1D ; [.21F6.0020.0002] -10BD ; [.21F6.0020.0008] -10EE ; [.21F7.0020.0002] -2D1E ; [.21F8.0020.0002] -10BE ; [.21F8.0020.0008] -10F4 ; [.21F9.0020.0002] -2D24 ; [.21FA.0020.0002] -10C4 ; [.21FA.0020.0008] -10EF ; [.21FB.0020.0002] -2D1F ; [.21FC.0020.0002] -10BF ; [.21FC.0020.0008] -10F0 ; [.21FD.0020.0002] -2D20 ; [.21FE.0020.0002] -10C0 ; [.21FE.0020.0008] -10F5 ; [.21FF.0020.0002] -2D25 ; [.2200.0020.0002] -10C5 ; [.2200.0020.0008] -10F6 ; [.2201.0020.0002] -10F7 ; [.2202.0020.0002] -2D27 ; [.2203.0020.0002] -10C7 ; [.2203.0020.0008] -10F8 ; [.2204.0020.0002] -10F9 ; [.2205.0020.0002] -10FA ; [.2206.0020.0002] -10FD ; [.2207.0020.0002] -2D2D ; [.2208.0020.0002] -10CD ; [.2208.0020.0008] -10FE ; [.2209.0020.0002] -10FF ; [.220A.0020.0002] -0561 ; [.220B.0020.0002] -0531 ; [.220B.0020.0008] -0562 ; [.220C.0020.0002] -0532 ; [.220C.0020.0008] -0563 ; [.220D.0020.0002] -0533 ; [.220D.0020.0008] -0564 ; [.220E.0020.0002] -0534 ; [.220E.0020.0008] -0565 ; [.220F.0020.0002] -0535 ; [.220F.0020.0008] -0587 ; [.220F.0020.0004][.222C.0020.0004] -0566 ; [.2210.0020.0002] -0536 ; [.2210.0020.0008] -0567 ; [.2211.0020.0002] -0537 ; [.2211.0020.0008] -0568 ; [.2212.0020.0002] -0538 ; [.2212.0020.0008] -0569 ; [.2213.0020.0002] -0539 ; [.2213.0020.0008] -056A ; [.2214.0020.0002] -053A ; [.2214.0020.0008] -056B ; [.2215.0020.0002] -053B ; [.2215.0020.0008] -056C ; [.2216.0020.0002] -053C ; [.2216.0020.0008] -056D ; [.2217.0020.0002] -053D ; [.2217.0020.0008] -056E ; [.2218.0020.0002] -053E ; [.2218.0020.0008] -056F ; [.2219.0020.0002] -053F ; [.2219.0020.0008] -0570 ; [.221A.0020.0002] -0540 ; [.221A.0020.0008] -0571 ; [.221B.0020.0002] -0541 ; [.221B.0020.0008] -0572 ; [.221C.0020.0002] -0542 ; [.221C.0020.0008] -0573 ; [.221D.0020.0002] -0543 ; [.221D.0020.0008] -0574 ; [.221E.0020.0002] -0544 ; [.221E.0020.0008] -FB14 ; [.221E.0020.0004][.220F.0020.0004] -FB15 ; [.221E.0020.0004][.2215.0020.0004] -FB17 ; [.221E.0020.0004][.2217.0020.0004] -FB13 ; [.221E.0020.0004][.2220.0020.0004] -0575 ; [.221F.0020.0002] -0545 ; [.221F.0020.0008] -0576 ; [.2220.0020.0002] -0546 ; [.2220.0020.0008] -0577 ; [.2221.0020.0002] -0547 ; [.2221.0020.0008] -0578 ; [.2222.0020.0002] -0548 ; [.2222.0020.0008] -0579 ; [.2223.0020.0002] -0549 ; [.2223.0020.0008] -057A ; [.2224.0020.0002] -054A ; [.2224.0020.0008] -057B ; [.2225.0020.0002] -054B ; [.2225.0020.0008] -057C ; [.2226.0020.0002] -054C ; [.2226.0020.0008] -057D ; [.2227.0020.0002] -054D ; [.2227.0020.0008] -057E ; [.2228.0020.0002] -054E ; [.2228.0020.0008] -FB16 ; [.2228.0020.0004][.2220.0020.0004] -057F ; [.2229.0020.0002] -054F ; [.2229.0020.0008] -0580 ; [.222A.0020.0002] -0550 ; [.222A.0020.0008] -0581 ; [.222B.0020.0002] -0551 ; [.222B.0020.0008] -0582 ; [.222C.0020.0002] -0552 ; [.222C.0020.0008] -0583 ; [.222D.0020.0002] -0553 ; [.222D.0020.0008] -0584 ; [.222E.0020.0002] -0554 ; [.222E.0020.0008] -0585 ; [.222F.0020.0002] -0555 ; [.222F.0020.0008] -0586 ; [.2230.0020.0002] -0556 ; [.2230.0020.0008] -0559 ; [.2231.0020.0002] -05D0 ; [.2232.0020.0002] -2135 ; [.2232.0020.0004] -FB21 ; [.2232.0020.0005] -FB2E ; [.2232.0020.0002][.0000.0059.0002] -FB2F ; [.2232.0020.0002][.0000.005A.0002] -FB30 ; [.2232.0020.0002][.0000.005F.0002] -FB4F ; [.2232.0020.0004][.223D.0020.0004] -05D1 ; [.2233.0020.0002] -2136 ; [.2233.0020.0004] -FB31 ; [.2233.0020.0002][.0000.005F.0002] -FB4C ; [.2233.0020.0002][.0000.0060.0002] -05D2 ; [.2234.0020.0002] -2137 ; [.2234.0020.0004] -FB32 ; [.2234.0020.0002][.0000.005F.0002] -05D3 ; [.2235.0020.0002] -2138 ; [.2235.0020.0004] -FB22 ; [.2235.0020.0005] -FB33 ; [.2235.0020.0002][.0000.005F.0002] -05D4 ; [.2236.0020.0002] -FB23 ; [.2236.0020.0005] -FB34 ; [.2236.0020.0002][.0000.005F.0002] -05D5 ; [.2237.0020.0002] -FB4B ; [.2237.0020.0002][.0000.005B.0002] -FB35 ; [.2237.0020.0002][.0000.005F.0002] -05F0 ; [.2237.0020.0004][.2237.0020.0004] -05F1 ; [.2237.0020.0004][.223B.0020.0004] -05D6 ; [.2238.0020.0002] -FB36 ; [.2238.0020.0002][.0000.005F.0002] -05D7 ; [.2239.0020.0002] -05D8 ; [.223A.0020.0002] -FB38 ; [.223A.0020.0002][.0000.005F.0002] -05D9 ; [.223B.0020.0002] -FB1D ; [.223B.0020.0002][.0000.0056.0002] -FB39 ; [.223B.0020.0002][.0000.005F.0002] -05F2 ; [.223B.0020.0004][.223B.0020.0004] -FB1F ; [.223B.0020.0004][.223B.0020.0004][.0000.0059.0002] -05DB ; [.223C.0020.0002] -FB24 ; [.223C.0020.0005] -05DA ; [.223C.0020.0019] -FB3B ; [.223C.0020.0002][.0000.005F.0002] -FB3A ; [.223C.0020.0019][.0000.005F.0002] -FB4D ; [.223C.0020.0002][.0000.0060.0002] -05DC ; [.223D.0020.0002] -FB25 ; [.223D.0020.0005] -FB3C ; [.223D.0020.0002][.0000.005F.0002] -05DE ; [.223E.0020.0002] -FB26 ; [.223E.0020.0005] -05DD ; [.223E.0020.0019] -FB3E ; [.223E.0020.0002][.0000.005F.0002] -05E0 ; [.223F.0020.0002] -05DF ; [.223F.0020.0019] -FB40 ; [.223F.0020.0002][.0000.005F.0002] -05E1 ; [.2240.0020.0002] -FB41 ; [.2240.0020.0002][.0000.005F.0002] -05E2 ; [.2241.0020.0002] -FB20 ; [.2241.0020.0005] -05E4 ; [.2242.0020.0002] -05E3 ; [.2242.0020.0019] -FB44 ; [.2242.0020.0002][.0000.005F.0002] -FB43 ; [.2242.0020.0019][.0000.005F.0002] -FB4E ; [.2242.0020.0002][.0000.0060.0002] -05E6 ; [.2243.0020.0002] -05E5 ; [.2243.0020.0019] -FB46 ; [.2243.0020.0002][.0000.005F.0002] -05E7 ; [.2244.0020.0002] -FB47 ; [.2244.0020.0002][.0000.005F.0002] -05E8 ; [.2245.0020.0002] -FB27 ; [.2245.0020.0005] -FB48 ; [.2245.0020.0002][.0000.005F.0002] -05E9 ; [.2246.0020.0002] -FB2B ; [.2246.0020.0002][.0000.005D.0002] -FB2A ; [.2246.0020.0002][.0000.005E.0002] -FB49 ; [.2246.0020.0002][.0000.005F.0002] -FB2D ; [.2246.0020.0002][.0000.005F.0002][.0000.005D.0002] -FB2C ; [.2246.0020.0002][.0000.005F.0002][.0000.005E.0002] -05EA ; [.2247.0020.0002] -FB28 ; [.2247.0020.0005] -FB4A ; [.2247.0020.0002][.0000.005F.0002] -10900 ; [.2248.0020.0002] -10901 ; [.2249.0020.0002] -10902 ; [.224A.0020.0002] -10903 ; [.224B.0020.0002] -10904 ; [.224C.0020.0002] -10905 ; [.224D.0020.0002] -10906 ; [.224E.0020.0002] -10907 ; [.224F.0020.0002] -10908 ; [.2250.0020.0002] -10909 ; [.2251.0020.0002] -1090A ; [.2252.0020.0002] -1090B ; [.2253.0020.0002] -1090C ; [.2254.0020.0002] -1090D ; [.2255.0020.0002] -1090E ; [.2256.0020.0002] -1090F ; [.2257.0020.0002] -10910 ; [.2258.0020.0002] -10911 ; [.2259.0020.0002] -10912 ; [.225A.0020.0002] -10913 ; [.225B.0020.0002] -10914 ; [.225C.0020.0002] -10915 ; [.225D.0020.0002] -0800 ; [.225E.0020.0002] -0801 ; [.225F.0020.0002] -0802 ; [.2260.0020.0002] -0803 ; [.2261.0020.0002] -0804 ; [.2262.0020.0002] -0805 ; [.2263.0020.0002] -0806 ; [.2264.0020.0002] -0807 ; [.2265.0020.0002] -0808 ; [.2266.0020.0002] -0809 ; [.2267.0020.0002] -080A ; [.2268.0020.0002] -080B ; [.2269.0020.0002] -080C ; [.226A.0020.0002] -080D ; [.226B.0020.0002] -080E ; [.226C.0020.0002] -080F ; [.226D.0020.0002] -0810 ; [.226E.0020.0002] -0811 ; [.226F.0020.0002] -0812 ; [.2270.0020.0002] -0813 ; [.2271.0020.0002] -0814 ; [.2272.0020.0002] -0815 ; [.2273.0020.0002] -0816 ; [.2274.0020.0002] -0817 ; [.2275.0020.0002] -081A ; [.2276.0020.0002] -081B ; [.2277.0020.0002] -0621 ; [.2278.0020.0002] -0674 ; [.2278.0020.0004] -FE80 ; [.2278.0020.001A] -06FD ; [.2278.0020.0004][.0000.010C.0004] -0622 ; [.2279.0020.0002] -0627 0653 ; [.2279.0020.0002] -FE82 ; [.2279.0020.0019] -FE81 ; [.2279.0020.001A] -0623 ; [.227A.0020.0002] -0627 0654 ; [.227A.0020.0002] -FE84 ; [.227A.0020.0019] -FE83 ; [.227A.0020.001A] -0672 ; [.227B.0020.0002] -0671 ; [.227C.0020.0002] -FB51 ; [.227C.0020.0019] -FB50 ; [.227C.0020.001A] -0624 ; [.227D.0020.0002] -0648 0654 ; [.227D.0020.0002] -FE86 ; [.227D.0020.0019] -FE85 ; [.227D.0020.001A] -0625 ; [.227E.0020.0002] -0627 0655 ; [.227E.0020.0002] -FE88 ; [.227E.0020.0019] -FE87 ; [.227E.0020.001A] -0673 ; [.227F.0020.0002] -0773 ; [.2280.0020.0002] -0774 ; [.2281.0020.0002] -0626 ; [.2282.0020.0002] -064A 0654 ; [.2282.0020.0002] -FE8B ; [.2282.0020.0017] -FE8C ; [.2282.0020.0018] -FE8A ; [.2282.0020.0019] -FE89 ; [.2282.0020.001A] -FBEB ; [.2282.0020.0019][.2286.0020.0019] -FBEA ; [.2282.0020.001A][.2286.0020.001A] -FC97 ; [.2282.0020.0017][.229D.0020.0017] -FC00 ; [.2282.0020.001A][.229D.0020.001A] -FC98 ; [.2282.0020.0017][.22A4.0020.0017] -FC01 ; [.2282.0020.001A][.22A4.0020.001A] -FC99 ; [.2282.0020.0017][.22A5.0020.0017] -FC64 ; [.2282.0020.0019][.22BE.0020.0019] -FC65 ; [.2282.0020.0019][.22BF.0020.0019] -FC9A ; [.2282.0020.0017][.2318.0020.0017] -FCDF ; [.2282.0020.0018][.2318.0020.0018] -FC66 ; [.2282.0020.0019][.2318.0020.0019] -FC02 ; [.2282.0020.001A][.2318.0020.001A] -FC67 ; [.2282.0020.0019][.231C.0020.0019] -FC9B ; [.2282.0020.0017][.2325.0020.0017] -FCE0 ; [.2282.0020.0018][.2325.0020.0018] -FBED ; [.2282.0020.0019][.232A.0020.0019] -FBEC ; [.2282.0020.001A][.232A.0020.001A] -FBEF ; [.2282.0020.0019][.232B.0020.0019] -FBEE ; [.2282.0020.001A][.232B.0020.001A] -FBF3 ; [.2282.0020.0019][.232E.0020.0019] -FBF2 ; [.2282.0020.001A][.232E.0020.001A] -FBF1 ; [.2282.0020.0019][.232F.0020.0019] -FBF0 ; [.2282.0020.001A][.232F.0020.001A] -FBF5 ; [.2282.0020.0019][.2330.0020.0019] -FBF4 ; [.2282.0020.001A][.2330.0020.001A] -FBFB ; [.2282.0020.0017][.2339.0020.0017] -FBFA ; [.2282.0020.0019][.2339.0020.0019] -FC68 ; [.2282.0020.0019][.2339.0020.0019] -FBF9 ; [.2282.0020.001A][.2339.0020.001A] -FC03 ; [.2282.0020.001A][.2339.0020.001A] -FC69 ; [.2282.0020.0019][.233A.0020.0019] -FC04 ; [.2282.0020.001A][.233A.0020.001A] -FBF8 ; [.2282.0020.0017][.233E.0020.0017] -FBF7 ; [.2282.0020.0019][.233E.0020.0019] -FBF6 ; [.2282.0020.001A][.233E.0020.001A] -08A8 ; [.2283.0020.0002] -08A9 ; [.2284.0020.0002] -08AC ; [.2285.0020.0002] -0627 ; [.2286.0020.0002] -08AD ; [.2286.0020.0004] -1EE00 ; [.2286.0020.0005] -1EE80 ; [.2286.0020.0005] -FE8E ; [.2286.0020.0019] -FE8D ; [.2286.0020.001A] -FD3C ; [.2286.0020.0019][.0000.006D.0019] -FD3D ; [.2286.0020.001A][.0000.006D.001A] -0675 ; [.2286.0020.0004][.2278.0020.0004] -FDF3 ; [.2286.0020.001A][.22FC.0020.001A][.2288.0020.001A][.22BE.0020.001A] -FDF2 ; [.2286.0020.001A][.2311.0020.001A][.2311.0020.001A][.2325.0020.001A] -066E ; [.2287.0020.0002] -1EE1C ; [.2287.0020.0005] -1EE7C ; [.2287.0020.0005] -0628 ; [.2288.0020.0002] -1EE01 ; [.2288.0020.0005] -1EE21 ; [.2288.0020.0005] -1EE61 ; [.2288.0020.0005] -1EE81 ; [.2288.0020.0005] -1EEA1 ; [.2288.0020.0005] -FE91 ; [.2288.0020.0017] -FE92 ; [.2288.0020.0018] -FE90 ; [.2288.0020.0019] -FE8F ; [.2288.0020.001A] -FC9C ; [.2288.0020.0017][.229D.0020.0017] -FC05 ; [.2288.0020.001A][.229D.0020.001A] -FC9D ; [.2288.0020.0017][.22A4.0020.0017] -FC06 ; [.2288.0020.001A][.22A4.0020.001A] -FDC2 ; [.2288.0020.0019][.22A4.0020.0019][.233A.0020.0019] -FC9E ; [.2288.0020.0017][.22A5.0020.0017] -FC07 ; [.2288.0020.001A][.22A5.0020.001A] -FD9E ; [.2288.0020.0019][.22A5.0020.0019][.233A.0020.0019] -FC6A ; [.2288.0020.0019][.22BE.0020.0019] -FC6B ; [.2288.0020.0019][.22BF.0020.0019] -FC9F ; [.2288.0020.0017][.2318.0020.0017] -FCE1 ; [.2288.0020.0018][.2318.0020.0018] -FC6C ; [.2288.0020.0019][.2318.0020.0019] -FC08 ; [.2288.0020.001A][.2318.0020.001A] -FC6D ; [.2288.0020.0019][.231C.0020.0019] -FCA0 ; [.2288.0020.0017][.2325.0020.0017] -FCE2 ; [.2288.0020.0018][.2325.0020.0018] -FC6E ; [.2288.0020.0019][.2339.0020.0019] -FC09 ; [.2288.0020.001A][.2339.0020.001A] -FC6F ; [.2288.0020.0019][.233A.0020.0019] -FC0A ; [.2288.0020.001A][.233A.0020.001A] -067B ; [.2289.0020.0002] -FB54 ; [.2289.0020.0017] -FB55 ; [.2289.0020.0018] -FB53 ; [.2289.0020.0019] -FB52 ; [.2289.0020.001A] -067E ; [.228A.0020.0002] -FB58 ; [.228A.0020.0017] -FB59 ; [.228A.0020.0018] -FB57 ; [.228A.0020.0019] -FB56 ; [.228A.0020.001A] -0680 ; [.228B.0020.0002] -FB5C ; [.228B.0020.0017] -FB5D ; [.228B.0020.0018] -FB5B ; [.228B.0020.0019] -FB5A ; [.228B.0020.001A] -0750 ; [.228C.0020.0002] -0751 ; [.228D.0020.0002] -0752 ; [.228E.0020.0002] -0753 ; [.228F.0020.0002] -0754 ; [.2290.0020.0002] -0755 ; [.2291.0020.0002] -08A0 ; [.2292.0020.0002] -0756 ; [.2293.0020.0002] -08A1 ; [.2294.0020.0002] -0629 ; [.2295.0020.0002] -FE94 ; [.2295.0020.0019] -FE93 ; [.2295.0020.001A] -062A ; [.2296.0020.0002] -1EE15 ; [.2296.0020.0005] -1EE35 ; [.2296.0020.0005] -1EE75 ; [.2296.0020.0005] -1EE95 ; [.2296.0020.0005] -1EEB5 ; [.2296.0020.0005] -FE97 ; [.2296.0020.0017] -FE98 ; [.2296.0020.0018] -FE96 ; [.2296.0020.0019] -FE95 ; [.2296.0020.001A] -FCA1 ; [.2296.0020.0017][.229D.0020.0017] -FC0B ; [.2296.0020.001A][.229D.0020.001A] -FD50 ; [.2296.0020.0017][.229D.0020.0017][.2318.0020.0017] -FDA0 ; [.2296.0020.0019][.229D.0020.0019][.2339.0020.0019] -FD9F ; [.2296.0020.0019][.229D.0020.0019][.233A.0020.0019] -FCA2 ; [.2296.0020.0017][.22A4.0020.0017] -FC0C ; [.2296.0020.001A][.22A4.0020.001A] -FD52 ; [.2296.0020.0017][.22A4.0020.0017][.229D.0020.0017] -FD51 ; [.2296.0020.0019][.22A4.0020.0019][.229D.0020.0019] -FD53 ; [.2296.0020.0017][.22A4.0020.0017][.2318.0020.0017] -FCA3 ; [.2296.0020.0017][.22A5.0020.0017] -FC0D ; [.2296.0020.001A][.22A5.0020.001A] -FD54 ; [.2296.0020.0017][.22A5.0020.0017][.2318.0020.0017] -FDA2 ; [.2296.0020.0019][.22A5.0020.0019][.2339.0020.0019] -FDA1 ; [.2296.0020.0019][.22A5.0020.0019][.233A.0020.0019] -FC70 ; [.2296.0020.0019][.22BE.0020.0019] -FC71 ; [.2296.0020.0019][.22BF.0020.0019] -FCA4 ; [.2296.0020.0017][.2318.0020.0017] -FCE3 ; [.2296.0020.0018][.2318.0020.0018] -FC72 ; [.2296.0020.0019][.2318.0020.0019] -FC0E ; [.2296.0020.001A][.2318.0020.001A] -FD55 ; [.2296.0020.0017][.2318.0020.0017][.229D.0020.0017] -FD56 ; [.2296.0020.0017][.2318.0020.0017][.22A4.0020.0017] -FD57 ; [.2296.0020.0017][.2318.0020.0017][.22A5.0020.0017] -FDA4 ; [.2296.0020.0019][.2318.0020.0019][.2339.0020.0019] -FDA3 ; [.2296.0020.0019][.2318.0020.0019][.233A.0020.0019] -FC73 ; [.2296.0020.0019][.231C.0020.0019] -FCA5 ; [.2296.0020.0017][.2325.0020.0017] -FCE4 ; [.2296.0020.0018][.2325.0020.0018] -FC74 ; [.2296.0020.0019][.2339.0020.0019] -FC0F ; [.2296.0020.001A][.2339.0020.001A] -FC75 ; [.2296.0020.0019][.233A.0020.0019] -FC10 ; [.2296.0020.001A][.233A.0020.001A] -062B ; [.2297.0020.0002] -1EE16 ; [.2297.0020.0005] -1EE36 ; [.2297.0020.0005] -1EE76 ; [.2297.0020.0005] -1EE96 ; [.2297.0020.0005] -1EEB6 ; [.2297.0020.0005] -FE9B ; [.2297.0020.0017] -FE9C ; [.2297.0020.0018] -FE9A ; [.2297.0020.0019] -FE99 ; [.2297.0020.001A] -FC11 ; [.2297.0020.001A][.229D.0020.001A] -FC76 ; [.2297.0020.0019][.22BE.0020.0019] -FC77 ; [.2297.0020.0019][.22BF.0020.0019] -FCA6 ; [.2297.0020.0017][.2318.0020.0017] -FCE5 ; [.2297.0020.0018][.2318.0020.0018] -FC78 ; [.2297.0020.0019][.2318.0020.0019] -FC12 ; [.2297.0020.001A][.2318.0020.001A] -FC79 ; [.2297.0020.0019][.231C.0020.0019] -FCE6 ; [.2297.0020.0018][.2325.0020.0018] -FC7A ; [.2297.0020.0019][.2339.0020.0019] -FC13 ; [.2297.0020.001A][.2339.0020.001A] -FC7B ; [.2297.0020.0019][.233A.0020.0019] -FC14 ; [.2297.0020.001A][.233A.0020.001A] -0679 ; [.2298.0020.0002] -FB68 ; [.2298.0020.0017] -FB69 ; [.2298.0020.0018] -FB67 ; [.2298.0020.0019] -FB66 ; [.2298.0020.001A] -067A ; [.2299.0020.0002] -FB60 ; [.2299.0020.0017] -FB61 ; [.2299.0020.0018] -FB5F ; [.2299.0020.0019] -FB5E ; [.2299.0020.001A] -067C ; [.229A.0020.0002] -067D ; [.229B.0020.0002] -067F ; [.229C.0020.0002] -FB64 ; [.229C.0020.0017] -FB65 ; [.229C.0020.0018] -FB63 ; [.229C.0020.0019] -FB62 ; [.229C.0020.001A] -062C ; [.229D.0020.0002] -1EE02 ; [.229D.0020.0005] -1EE22 ; [.229D.0020.0005] -1EE42 ; [.229D.0020.0005] -1EE62 ; [.229D.0020.0005] -1EE82 ; [.229D.0020.0005] -1EEA2 ; [.229D.0020.0005] -FE9F ; [.229D.0020.0017] -FEA0 ; [.229D.0020.0018] -FE9E ; [.229D.0020.0019] -FE9D ; [.229D.0020.001A] -FCA7 ; [.229D.0020.0017][.22A4.0020.0017] -FC15 ; [.229D.0020.001A][.22A4.0020.001A] -FDA6 ; [.229D.0020.0019][.22A4.0020.0019][.2339.0020.0019] -FDBE ; [.229D.0020.0019][.22A4.0020.0019][.233A.0020.0019] -FDFB ; [.229D.0020.001A][.2311.0020.001A][*0209.0020.001A][.229D.0020.001A][.2311.0020.001A][.2286.0020.001A][.2311.0020.001A][.2325.0020.001A] -FCA8 ; [.229D.0020.0017][.2318.0020.0017] -FC16 ; [.229D.0020.001A][.2318.0020.001A] -FD59 ; [.229D.0020.0017][.2318.0020.0017][.22A4.0020.0017] -FD58 ; [.229D.0020.0019][.2318.0020.0019][.22A4.0020.0019] -FDA7 ; [.229D.0020.0019][.2318.0020.0019][.2339.0020.0019] -FDA5 ; [.229D.0020.0019][.2318.0020.0019][.233A.0020.0019] -FD1D ; [.229D.0020.0019][.2339.0020.0019] -FD01 ; [.229D.0020.001A][.2339.0020.001A] -FD1E ; [.229D.0020.0019][.233A.0020.0019] -FD02 ; [.229D.0020.001A][.233A.0020.001A] -0683 ; [.229E.0020.0002] -FB78 ; [.229E.0020.0017] -FB79 ; [.229E.0020.0018] -FB77 ; [.229E.0020.0019] -FB76 ; [.229E.0020.001A] -0684 ; [.229F.0020.0002] -FB74 ; [.229F.0020.0017] -FB75 ; [.229F.0020.0018] -FB73 ; [.229F.0020.0019] -FB72 ; [.229F.0020.001A] -0686 ; [.22A0.0020.0002] -FB7C ; [.22A0.0020.0017] -FB7D ; [.22A0.0020.0018] -FB7B ; [.22A0.0020.0019] -FB7A ; [.22A0.0020.001A] -06BF ; [.22A1.0020.0002] -0687 ; [.22A2.0020.0002] -FB80 ; [.22A2.0020.0017] -FB81 ; [.22A2.0020.0018] -FB7F ; [.22A2.0020.0019] -FB7E ; [.22A2.0020.001A] -08A2 ; [.22A3.0020.0002] -062D ; [.22A4.0020.0002] -1EE07 ; [.22A4.0020.0005] -1EE27 ; [.22A4.0020.0005] -1EE47 ; [.22A4.0020.0005] -1EE67 ; [.22A4.0020.0005] -1EE87 ; [.22A4.0020.0005] -1EEA7 ; [.22A4.0020.0005] -FEA3 ; [.22A4.0020.0017] -FEA4 ; [.22A4.0020.0018] -FEA2 ; [.22A4.0020.0019] -FEA1 ; [.22A4.0020.001A] -FCA9 ; [.22A4.0020.0017][.229D.0020.0017] -FC17 ; [.22A4.0020.001A][.229D.0020.001A] -FDBF ; [.22A4.0020.0019][.229D.0020.0019][.233A.0020.0019] -FCAA ; [.22A4.0020.0017][.2318.0020.0017] -FC18 ; [.22A4.0020.001A][.2318.0020.001A] -FD5B ; [.22A4.0020.0019][.2318.0020.0019][.2339.0020.0019] -FD5A ; [.22A4.0020.0019][.2318.0020.0019][.233A.0020.0019] -FD1B ; [.22A4.0020.0019][.2339.0020.0019] -FCFF ; [.22A4.0020.001A][.2339.0020.001A] -FD1C ; [.22A4.0020.0019][.233A.0020.0019] -FD00 ; [.22A4.0020.001A][.233A.0020.001A] -062E ; [.22A5.0020.0002] -1EE17 ; [.22A5.0020.0005] -1EE37 ; [.22A5.0020.0005] -1EE57 ; [.22A5.0020.0005] -1EE77 ; [.22A5.0020.0005] -1EE97 ; [.22A5.0020.0005] -1EEB7 ; [.22A5.0020.0005] -FEA7 ; [.22A5.0020.0017] -FEA8 ; [.22A5.0020.0018] -FEA6 ; [.22A5.0020.0019] -FEA5 ; [.22A5.0020.001A] -FCAB ; [.22A5.0020.0017][.229D.0020.0017] -FC19 ; [.22A5.0020.001A][.229D.0020.001A] -FC1A ; [.22A5.0020.001A][.22A4.0020.001A] -FCAC ; [.22A5.0020.0017][.2318.0020.0017] -FC1B ; [.22A5.0020.001A][.2318.0020.001A] -FD1F ; [.22A5.0020.0019][.2339.0020.0019] -FD03 ; [.22A5.0020.001A][.2339.0020.001A] -FD20 ; [.22A5.0020.0019][.233A.0020.0019] -FD04 ; [.22A5.0020.001A][.233A.0020.001A] -0681 ; [.22A6.0020.0002] -0682 ; [.22A7.0020.0002] -0685 ; [.22A8.0020.0002] -0757 ; [.22A9.0020.0002] -0758 ; [.22AA.0020.0002] -076E ; [.22AB.0020.0002] -076F ; [.22AC.0020.0002] -0772 ; [.22AD.0020.0002] -077C ; [.22AE.0020.0002] -062F ; [.22AF.0020.0002] -1EE03 ; [.22AF.0020.0005] -1EE83 ; [.22AF.0020.0005] -1EEA3 ; [.22AF.0020.0005] -FEAA ; [.22AF.0020.0019] -FEA9 ; [.22AF.0020.001A] -0630 ; [.22B0.0020.0002] -1EE18 ; [.22B0.0020.0005] -1EE98 ; [.22B0.0020.0005] -1EEB8 ; [.22B0.0020.0005] -FEAC ; [.22B0.0020.0019] -FEAB ; [.22B0.0020.001A] -FC5B ; [.22B0.0020.001A][.0000.0098.001A] -0688 ; [.22B1.0020.0002] -FB89 ; [.22B1.0020.0019] -FB88 ; [.22B1.0020.001A] -0689 ; [.22B2.0020.0002] -068A ; [.22B3.0020.0002] -068B ; [.22B4.0020.0002] -068C ; [.22B5.0020.0002] -FB85 ; [.22B5.0020.0019] -FB84 ; [.22B5.0020.001A] -068D ; [.22B6.0020.0002] -FB83 ; [.22B6.0020.0019] -FB82 ; [.22B6.0020.001A] -08AE ; [.22B7.0020.0002] -068E ; [.22B8.0020.0002] -FB87 ; [.22B8.0020.0019] -FB86 ; [.22B8.0020.001A] -068F ; [.22B9.0020.0002] -0690 ; [.22BA.0020.0002] -06EE ; [.22BB.0020.0002] -0759 ; [.22BC.0020.0002] -075A ; [.22BD.0020.0002] -0631 ; [.22BE.0020.0002] -1EE13 ; [.22BE.0020.0005] -1EE93 ; [.22BE.0020.0005] -1EEB3 ; [.22BE.0020.0005] -FEAE ; [.22BE.0020.0019] -FEAD ; [.22BE.0020.001A] -FC5C ; [.22BE.0020.001A][.0000.0098.001A] -FDF6 ; [.22BE.0020.001A][.22D0.0020.001A][.232B.0020.001A][.2311.0020.001A] -FDFC ; [.22BE.0020.001A][.233B.0020.001A][.2286.0020.001A][.2311.0020.001A] -0632 ; [.22BF.0020.0002] -1EE06 ; [.22BF.0020.0005] -1EE86 ; [.22BF.0020.0005] -1EEA6 ; [.22BF.0020.0005] -FEB0 ; [.22BF.0020.0019] -FEAF ; [.22BF.0020.001A] -0691 ; [.22C0.0020.0002] -FB8D ; [.22C0.0020.0019] -FB8C ; [.22C0.0020.001A] -0692 ; [.22C1.0020.0002] -0693 ; [.22C2.0020.0002] -0694 ; [.22C3.0020.0002] -0695 ; [.22C4.0020.0002] -0696 ; [.22C5.0020.0002] -0697 ; [.22C6.0020.0002] -0698 ; [.22C7.0020.0002] -FB8B ; [.22C7.0020.0019] -FB8A ; [.22C7.0020.001A] -0699 ; [.22C8.0020.0002] -06EF ; [.22C9.0020.0002] -075B ; [.22CA.0020.0002] -076B ; [.22CB.0020.0002] -076C ; [.22CC.0020.0002] -0771 ; [.22CD.0020.0002] -08AA ; [.22CE.0020.0002] -08B2 ; [.22CF.0020.0002] -0633 ; [.22D0.0020.0002] -1EE0E ; [.22D0.0020.0005] -1EE2E ; [.22D0.0020.0005] -1EE4E ; [.22D0.0020.0005] -1EE6E ; [.22D0.0020.0005] -1EE8E ; [.22D0.0020.0005] -1EEAE ; [.22D0.0020.0005] -FEB3 ; [.22D0.0020.0017] -FEB4 ; [.22D0.0020.0018] -FEB2 ; [.22D0.0020.0019] -FEB1 ; [.22D0.0020.001A] -FCAD ; [.22D0.0020.0017][.229D.0020.0017] -FD34 ; [.22D0.0020.0018][.229D.0020.0018] -FC1C ; [.22D0.0020.001A][.229D.0020.001A] -FD5D ; [.22D0.0020.0017][.229D.0020.0017][.22A4.0020.0017] -FD5E ; [.22D0.0020.0019][.229D.0020.0019][.2339.0020.0019] -FCAE ; [.22D0.0020.0017][.22A4.0020.0017] -FD35 ; [.22D0.0020.0018][.22A4.0020.0018] -FC1D ; [.22D0.0020.001A][.22A4.0020.001A] -FD5C ; [.22D0.0020.0017][.22A4.0020.0017][.229D.0020.0017] -FCAF ; [.22D0.0020.0017][.22A5.0020.0017] -FD36 ; [.22D0.0020.0018][.22A5.0020.0018] -FC1E ; [.22D0.0020.001A][.22A5.0020.001A] -FDA8 ; [.22D0.0020.0019][.22A5.0020.0019][.2339.0020.0019] -FDC6 ; [.22D0.0020.0019][.22A5.0020.0019][.233A.0020.0019] -FD2A ; [.22D0.0020.0019][.22BE.0020.0019] -FD0E ; [.22D0.0020.001A][.22BE.0020.001A] -FCB0 ; [.22D0.0020.0017][.2318.0020.0017] -FCE7 ; [.22D0.0020.0018][.2318.0020.0018] -FC1F ; [.22D0.0020.001A][.2318.0020.001A] -FD61 ; [.22D0.0020.0017][.2318.0020.0017][.229D.0020.0017] -FD60 ; [.22D0.0020.0017][.2318.0020.0017][.22A4.0020.0017] -FD5F ; [.22D0.0020.0019][.2318.0020.0019][.22A4.0020.0019] -FD63 ; [.22D0.0020.0017][.2318.0020.0017][.2318.0020.0017] -FD62 ; [.22D0.0020.0019][.2318.0020.0019][.2318.0020.0019] -FD31 ; [.22D0.0020.0017][.2325.0020.0017] -FCE8 ; [.22D0.0020.0018][.2325.0020.0018] -FD17 ; [.22D0.0020.0019][.2339.0020.0019] -FCFB ; [.22D0.0020.001A][.2339.0020.001A] -FD18 ; [.22D0.0020.0019][.233A.0020.0019] -FCFC ; [.22D0.0020.001A][.233A.0020.001A] -0634 ; [.22D1.0020.0002] -1EE14 ; [.22D1.0020.0005] -1EE34 ; [.22D1.0020.0005] -1EE54 ; [.22D1.0020.0005] -1EE74 ; [.22D1.0020.0005] -1EE94 ; [.22D1.0020.0005] -1EEB4 ; [.22D1.0020.0005] -FEB7 ; [.22D1.0020.0017] -FEB8 ; [.22D1.0020.0018] -FEB6 ; [.22D1.0020.0019] -FEB5 ; [.22D1.0020.001A] -FD2D ; [.22D1.0020.0017][.229D.0020.0017] -FD37 ; [.22D1.0020.0018][.229D.0020.0018] -FD25 ; [.22D1.0020.0019][.229D.0020.0019] -FD09 ; [.22D1.0020.001A][.229D.0020.001A] -FD69 ; [.22D1.0020.0019][.229D.0020.0019][.233A.0020.0019] -FD2E ; [.22D1.0020.0017][.22A4.0020.0017] -FD38 ; [.22D1.0020.0018][.22A4.0020.0018] -FD26 ; [.22D1.0020.0019][.22A4.0020.0019] -FD0A ; [.22D1.0020.001A][.22A4.0020.001A] -FD68 ; [.22D1.0020.0017][.22A4.0020.0017][.2318.0020.0017] -FD67 ; [.22D1.0020.0019][.22A4.0020.0019][.2318.0020.0019] -FDAA ; [.22D1.0020.0019][.22A4.0020.0019][.233A.0020.0019] -FD2F ; [.22D1.0020.0017][.22A5.0020.0017] -FD39 ; [.22D1.0020.0018][.22A5.0020.0018] -FD27 ; [.22D1.0020.0019][.22A5.0020.0019] -FD0B ; [.22D1.0020.001A][.22A5.0020.001A] -FD29 ; [.22D1.0020.0019][.22BE.0020.0019] -FD0D ; [.22D1.0020.001A][.22BE.0020.001A] -FD30 ; [.22D1.0020.0017][.2318.0020.0017] -FCE9 ; [.22D1.0020.0018][.2318.0020.0018] -FD28 ; [.22D1.0020.0019][.2318.0020.0019] -FD0C ; [.22D1.0020.001A][.2318.0020.001A] -FD6B ; [.22D1.0020.0017][.2318.0020.0017][.22A5.0020.0017] -FD6A ; [.22D1.0020.0019][.2318.0020.0019][.22A5.0020.0019] -FD6D ; [.22D1.0020.0017][.2318.0020.0017][.2318.0020.0017] -FD6C ; [.22D1.0020.0019][.2318.0020.0019][.2318.0020.0019] -FD32 ; [.22D1.0020.0017][.2325.0020.0017] -FCEA ; [.22D1.0020.0018][.2325.0020.0018] -FD19 ; [.22D1.0020.0019][.2339.0020.0019] -FCFD ; [.22D1.0020.001A][.2339.0020.001A] -FD1A ; [.22D1.0020.0019][.233A.0020.0019] -FCFE ; [.22D1.0020.001A][.233A.0020.001A] -069A ; [.22D2.0020.0002] -069B ; [.22D3.0020.0002] -069C ; [.22D4.0020.0002] -06FA ; [.22D5.0020.0002] -075C ; [.22D6.0020.0002] -076D ; [.22D7.0020.0002] -0770 ; [.22D8.0020.0002] -077D ; [.22D9.0020.0002] -077E ; [.22DA.0020.0002] -0635 ; [.22DB.0020.0002] -1EE11 ; [.22DB.0020.0005] -1EE31 ; [.22DB.0020.0005] -1EE51 ; [.22DB.0020.0005] -1EE71 ; [.22DB.0020.0005] -1EE91 ; [.22DB.0020.0005] -1EEB1 ; [.22DB.0020.0005] -FEBB ; [.22DB.0020.0017] -FEBC ; [.22DB.0020.0018] -FEBA ; [.22DB.0020.0019] -FEB9 ; [.22DB.0020.001A] -FCB1 ; [.22DB.0020.0017][.22A4.0020.0017] -FC20 ; [.22DB.0020.001A][.22A4.0020.001A] -FD65 ; [.22DB.0020.0017][.22A4.0020.0017][.22A4.0020.0017] -FD64 ; [.22DB.0020.0019][.22A4.0020.0019][.22A4.0020.0019] -FDA9 ; [.22DB.0020.0019][.22A4.0020.0019][.233A.0020.0019] -FCB2 ; [.22DB.0020.0017][.22A5.0020.0017] -FD2B ; [.22DB.0020.0019][.22BE.0020.0019] -FD0F ; [.22DB.0020.001A][.22BE.0020.001A] -FDF5 ; [.22DB.0020.001A][.2311.0020.001A][.22E5.0020.001A][.2318.0020.001A] -FDF9 ; [.22DB.0020.001A][.2311.0020.001A][.2339.0020.001A] -FDFA ; [.22DB.0020.001A][.2311.0020.001A][.2339.0020.001A][*0209.0020.001A][.2286.0020.001A][.2311.0020.001A][.2311.0020.001A][.2325.0020.001A][*0209.0020.001A][.22E5.0020.001A][.2311.0020.001A][.233A.0020.001A][.2325.0020.001A][*0209.0020.001A][.232B.0020.001A][.22D0.0020.001A][.2311.0020.001A][.2318.0020.001A] -FDF0 ; [.22DB.0020.001A][.2311.0020.001A][.2347.0020.001A] -FCB3 ; [.22DB.0020.0017][.2318.0020.0017] -FC21 ; [.22DB.0020.001A][.2318.0020.001A] -FDC5 ; [.22DB.0020.0017][.2318.0020.0017][.2318.0020.0017] -FD66 ; [.22DB.0020.0019][.2318.0020.0019][.2318.0020.0019] -FD21 ; [.22DB.0020.0019][.2339.0020.0019] -FD05 ; [.22DB.0020.001A][.2339.0020.001A] -FD22 ; [.22DB.0020.0019][.233A.0020.0019] -FD06 ; [.22DB.0020.001A][.233A.0020.001A] -0636 ; [.22DC.0020.0002] -1EE19 ; [.22DC.0020.0005] -1EE39 ; [.22DC.0020.0005] -1EE59 ; [.22DC.0020.0005] -1EE79 ; [.22DC.0020.0005] -1EE99 ; [.22DC.0020.0005] -1EEB9 ; [.22DC.0020.0005] -FEBF ; [.22DC.0020.0017] -FEC0 ; [.22DC.0020.0018] -FEBE ; [.22DC.0020.0019] -FEBD ; [.22DC.0020.001A] -FCB4 ; [.22DC.0020.0017][.229D.0020.0017] -FC22 ; [.22DC.0020.001A][.229D.0020.001A] -FCB5 ; [.22DC.0020.0017][.22A4.0020.0017] -FC23 ; [.22DC.0020.001A][.22A4.0020.001A] -FD6E ; [.22DC.0020.0019][.22A4.0020.0019][.2339.0020.0019] -FDAB ; [.22DC.0020.0019][.22A4.0020.0019][.233A.0020.0019] -FCB6 ; [.22DC.0020.0017][.22A5.0020.0017] -FC24 ; [.22DC.0020.001A][.22A5.0020.001A] -FD70 ; [.22DC.0020.0017][.22A5.0020.0017][.2318.0020.0017] -FD6F ; [.22DC.0020.0019][.22A5.0020.0019][.2318.0020.0019] -FD2C ; [.22DC.0020.0019][.22BE.0020.0019] -FD10 ; [.22DC.0020.001A][.22BE.0020.001A] -FCB7 ; [.22DC.0020.0017][.2318.0020.0017] -FC25 ; [.22DC.0020.001A][.2318.0020.001A] -FD23 ; [.22DC.0020.0019][.2339.0020.0019] -FD07 ; [.22DC.0020.001A][.2339.0020.001A] -FD24 ; [.22DC.0020.0019][.233A.0020.0019] -FD08 ; [.22DC.0020.001A][.233A.0020.001A] -069D ; [.22DD.0020.0002] -08AF ; [.22DE.0020.0002] -069E ; [.22DF.0020.0002] -06FB ; [.22E0.0020.0002] -0637 ; [.22E1.0020.0002] -1EE08 ; [.22E1.0020.0005] -1EE68 ; [.22E1.0020.0005] -1EE88 ; [.22E1.0020.0005] -1EEA8 ; [.22E1.0020.0005] -FEC3 ; [.22E1.0020.0017] -FEC4 ; [.22E1.0020.0018] -FEC2 ; [.22E1.0020.0019] -FEC1 ; [.22E1.0020.001A] -FCB8 ; [.22E1.0020.0017][.22A4.0020.0017] -FC26 ; [.22E1.0020.001A][.22A4.0020.001A] -FD33 ; [.22E1.0020.0017][.2318.0020.0017] -FD3A ; [.22E1.0020.0018][.2318.0020.0018] -FC27 ; [.22E1.0020.001A][.2318.0020.001A] -FD72 ; [.22E1.0020.0017][.2318.0020.0017][.22A4.0020.0017] -FD71 ; [.22E1.0020.0019][.2318.0020.0019][.22A4.0020.0019] -FD73 ; [.22E1.0020.0017][.2318.0020.0017][.2318.0020.0017] -FD74 ; [.22E1.0020.0019][.2318.0020.0019][.233A.0020.0019] -FD11 ; [.22E1.0020.0019][.2339.0020.0019] -FCF5 ; [.22E1.0020.001A][.2339.0020.001A] -FD12 ; [.22E1.0020.0019][.233A.0020.0019] -FCF6 ; [.22E1.0020.001A][.233A.0020.001A] -0638 ; [.22E2.0020.0002] -1EE1A ; [.22E2.0020.0005] -1EE7A ; [.22E2.0020.0005] -1EE9A ; [.22E2.0020.0005] -1EEBA ; [.22E2.0020.0005] -FEC7 ; [.22E2.0020.0017] -FEC8 ; [.22E2.0020.0018] -FEC6 ; [.22E2.0020.0019] -FEC5 ; [.22E2.0020.001A] -FCB9 ; [.22E2.0020.0017][.2318.0020.0017] -FD3B ; [.22E2.0020.0018][.2318.0020.0018] -FC28 ; [.22E2.0020.001A][.2318.0020.001A] -069F ; [.22E3.0020.0002] -08A3 ; [.22E4.0020.0002] -0639 ; [.22E5.0020.0002] -1EE0F ; [.22E5.0020.0005] -1EE2F ; [.22E5.0020.0005] -1EE4F ; [.22E5.0020.0005] -1EE6F ; [.22E5.0020.0005] -1EE8F ; [.22E5.0020.0005] -1EEAF ; [.22E5.0020.0005] -FECB ; [.22E5.0020.0017] -FECC ; [.22E5.0020.0018] -FECA ; [.22E5.0020.0019] -FEC9 ; [.22E5.0020.001A] -FCBA ; [.22E5.0020.0017][.229D.0020.0017] -FC29 ; [.22E5.0020.001A][.229D.0020.001A] -FDC4 ; [.22E5.0020.0017][.229D.0020.0017][.2318.0020.0017] -FD75 ; [.22E5.0020.0019][.229D.0020.0019][.2318.0020.0019] -FDF7 ; [.22E5.0020.001A][.2311.0020.001A][.233A.0020.001A][.2325.0020.001A] -FCBB ; [.22E5.0020.0017][.2318.0020.0017] -FC2A ; [.22E5.0020.001A][.2318.0020.001A] -FD77 ; [.22E5.0020.0017][.2318.0020.0017][.2318.0020.0017] -FD76 ; [.22E5.0020.0019][.2318.0020.0019][.2318.0020.0019] -FD78 ; [.22E5.0020.0019][.2318.0020.0019][.2339.0020.0019] -FDB6 ; [.22E5.0020.0019][.2318.0020.0019][.233A.0020.0019] -FD13 ; [.22E5.0020.0019][.2339.0020.0019] -FCF7 ; [.22E5.0020.001A][.2339.0020.001A] -FD14 ; [.22E5.0020.0019][.233A.0020.0019] -FCF8 ; [.22E5.0020.001A][.233A.0020.001A] -063A ; [.22E6.0020.0002] -1EE1B ; [.22E6.0020.0005] -1EE3B ; [.22E6.0020.0005] -1EE5B ; [.22E6.0020.0005] -1EE7B ; [.22E6.0020.0005] -1EE9B ; [.22E6.0020.0005] -1EEBB ; [.22E6.0020.0005] -FECF ; [.22E6.0020.0017] -FED0 ; [.22E6.0020.0018] -FECE ; [.22E6.0020.0019] -FECD ; [.22E6.0020.001A] -FCBC ; [.22E6.0020.0017][.229D.0020.0017] -FC2B ; [.22E6.0020.001A][.229D.0020.001A] -FCBD ; [.22E6.0020.0017][.2318.0020.0017] -FC2C ; [.22E6.0020.001A][.2318.0020.001A] -FD79 ; [.22E6.0020.0019][.2318.0020.0019][.2318.0020.0019] -FD7B ; [.22E6.0020.0019][.2318.0020.0019][.2339.0020.0019] -FD7A ; [.22E6.0020.0019][.2318.0020.0019][.233A.0020.0019] -FD15 ; [.22E6.0020.0019][.2339.0020.0019] -FCF9 ; [.22E6.0020.001A][.2339.0020.001A] -FD16 ; [.22E6.0020.0019][.233A.0020.0019] -FCFA ; [.22E6.0020.001A][.233A.0020.001A] -06A0 ; [.22E7.0020.0002] -06FC ; [.22E8.0020.0002] -075D ; [.22E9.0020.0002] -075E ; [.22EA.0020.0002] -075F ; [.22EB.0020.0002] -08B3 ; [.22EC.0020.0002] -0641 ; [.22ED.0020.0002] -1EE10 ; [.22ED.0020.0005] -1EE30 ; [.22ED.0020.0005] -1EE70 ; [.22ED.0020.0005] -1EE90 ; [.22ED.0020.0005] -1EEB0 ; [.22ED.0020.0005] -FED3 ; [.22ED.0020.0017] -FED4 ; [.22ED.0020.0018] -FED2 ; [.22ED.0020.0019] -FED1 ; [.22ED.0020.001A] -FCBE ; [.22ED.0020.0017][.229D.0020.0017] -FC2D ; [.22ED.0020.001A][.229D.0020.001A] -FCBF ; [.22ED.0020.0017][.22A4.0020.0017] -FC2E ; [.22ED.0020.001A][.22A4.0020.001A] -FCC0 ; [.22ED.0020.0017][.22A5.0020.0017] -FC2F ; [.22ED.0020.001A][.22A5.0020.001A] -FD7D ; [.22ED.0020.0017][.22A5.0020.0017][.2318.0020.0017] -FD7C ; [.22ED.0020.0019][.22A5.0020.0019][.2318.0020.0019] -FCC1 ; [.22ED.0020.0017][.2318.0020.0017] -FC30 ; [.22ED.0020.001A][.2318.0020.001A] -FDC1 ; [.22ED.0020.0019][.2318.0020.0019][.233A.0020.0019] -FC7C ; [.22ED.0020.0019][.2339.0020.0019] -FC31 ; [.22ED.0020.001A][.2339.0020.001A] -FC7D ; [.22ED.0020.0019][.233A.0020.0019] -FC32 ; [.22ED.0020.001A][.233A.0020.001A] -06A1 ; [.22EE.0020.0002] -1EE1E ; [.22EE.0020.0005] -1EE7E ; [.22EE.0020.0005] -06A2 ; [.22EF.0020.0002] -06A3 ; [.22F0.0020.0002] -06A4 ; [.22F1.0020.0002] -FB6C ; [.22F1.0020.0017] -FB6D ; [.22F1.0020.0018] -FB6B ; [.22F1.0020.0019] -FB6A ; [.22F1.0020.001A] -08A4 ; [.22F2.0020.0002] -06A5 ; [.22F3.0020.0002] -06A6 ; [.22F4.0020.0002] -FB70 ; [.22F4.0020.0017] -FB71 ; [.22F4.0020.0018] -FB6F ; [.22F4.0020.0019] -FB6E ; [.22F4.0020.001A] -0760 ; [.22F5.0020.0002] -0761 ; [.22F6.0020.0002] -066F ; [.22F7.0020.0002] -1EE1F ; [.22F7.0020.0005] -1EE5F ; [.22F7.0020.0005] -0642 ; [.22F8.0020.0002] -1EE12 ; [.22F8.0020.0005] -1EE32 ; [.22F8.0020.0005] -1EE52 ; [.22F8.0020.0005] -1EE72 ; [.22F8.0020.0005] -1EE92 ; [.22F8.0020.0005] -1EEB2 ; [.22F8.0020.0005] -FED7 ; [.22F8.0020.0017] -FED8 ; [.22F8.0020.0018] -FED6 ; [.22F8.0020.0019] -FED5 ; [.22F8.0020.001A] -FCC2 ; [.22F8.0020.0017][.22A4.0020.0017] -FC33 ; [.22F8.0020.001A][.22A4.0020.001A] -FDF1 ; [.22F8.0020.001A][.2311.0020.001A][.2347.0020.001A] -FCC3 ; [.22F8.0020.0017][.2318.0020.0017] -FC34 ; [.22F8.0020.001A][.2318.0020.001A] -FDB4 ; [.22F8.0020.0017][.2318.0020.0017][.22A4.0020.0017] -FD7E ; [.22F8.0020.0019][.2318.0020.0019][.22A4.0020.0019] -FD7F ; [.22F8.0020.0019][.2318.0020.0019][.2318.0020.0019] -FDB2 ; [.22F8.0020.0019][.2318.0020.0019][.233A.0020.0019] -FC7E ; [.22F8.0020.0019][.2339.0020.0019] -FC35 ; [.22F8.0020.001A][.2339.0020.001A] -FC7F ; [.22F8.0020.0019][.233A.0020.0019] -FC36 ; [.22F8.0020.001A][.233A.0020.001A] -06A7 ; [.22F9.0020.0002] -06A8 ; [.22FA.0020.0002] -08A5 ; [.22FB.0020.0002] -0643 ; [.22FC.0020.0002] -1EE0A ; [.22FC.0020.0005] -1EE2A ; [.22FC.0020.0005] -1EE6A ; [.22FC.0020.0005] -FEDB ; [.22FC.0020.0017] -FEDC ; [.22FC.0020.0018] -FEDA ; [.22FC.0020.0019] -FED9 ; [.22FC.0020.001A] -FC80 ; [.22FC.0020.0019][.2286.0020.0019] -FC37 ; [.22FC.0020.001A][.2286.0020.001A] -FCC4 ; [.22FC.0020.0017][.229D.0020.0017] -FC38 ; [.22FC.0020.001A][.229D.0020.001A] -FCC5 ; [.22FC.0020.0017][.22A4.0020.0017] -FC39 ; [.22FC.0020.001A][.22A4.0020.001A] -FCC6 ; [.22FC.0020.0017][.22A5.0020.0017] -FC3A ; [.22FC.0020.001A][.22A5.0020.001A] -FCC7 ; [.22FC.0020.0017][.2311.0020.0017] -FCEB ; [.22FC.0020.0018][.2311.0020.0018] -FC81 ; [.22FC.0020.0019][.2311.0020.0019] -FC3B ; [.22FC.0020.001A][.2311.0020.001A] -FCC8 ; [.22FC.0020.0017][.2318.0020.0017] -FCEC ; [.22FC.0020.0018][.2318.0020.0018] -FC82 ; [.22FC.0020.0019][.2318.0020.0019] -FC3C ; [.22FC.0020.001A][.2318.0020.001A] -FDC3 ; [.22FC.0020.0017][.2318.0020.0017][.2318.0020.0017] -FDBB ; [.22FC.0020.0019][.2318.0020.0019][.2318.0020.0019] -FDB7 ; [.22FC.0020.0019][.2318.0020.0019][.233A.0020.0019] -FC83 ; [.22FC.0020.0019][.2339.0020.0019] -FC3D ; [.22FC.0020.001A][.2339.0020.001A] -FC84 ; [.22FC.0020.0019][.233A.0020.0019] -FC3E ; [.22FC.0020.001A][.233A.0020.001A] -06A9 ; [.22FD.0020.0002] -FB90 ; [.22FD.0020.0017] -FB91 ; [.22FD.0020.0018] -FB8F ; [.22FD.0020.0019] -FB8E ; [.22FD.0020.001A] -06AA ; [.22FE.0020.0002] -06AB ; [.22FF.0020.0002] -06AC ; [.2300.0020.0002] -077F ; [.2301.0020.0002] -06AD ; [.2302.0020.0002] -FBD5 ; [.2302.0020.0017] -FBD6 ; [.2302.0020.0018] -FBD4 ; [.2302.0020.0019] -FBD3 ; [.2302.0020.001A] -06AE ; [.2303.0020.0002] -08B4 ; [.2304.0020.0002] -06AF ; [.2305.0020.0002] -FB94 ; [.2305.0020.0017] -FB95 ; [.2305.0020.0018] -FB93 ; [.2305.0020.0019] -FB92 ; [.2305.0020.001A] -08B0 ; [.2306.0020.0002] -06B0 ; [.2307.0020.0002] -06B1 ; [.2308.0020.0002] -FB9C ; [.2308.0020.0017] -FB9D ; [.2308.0020.0018] -FB9B ; [.2308.0020.0019] -FB9A ; [.2308.0020.001A] -06B2 ; [.2309.0020.0002] -06B3 ; [.230A.0020.0002] -FB98 ; [.230A.0020.0017] -FB99 ; [.230A.0020.0018] -FB97 ; [.230A.0020.0019] -FB96 ; [.230A.0020.001A] -06B4 ; [.230B.0020.0002] -0762 ; [.230C.0020.0002] -063B ; [.230D.0020.0002] -063C ; [.230E.0020.0002] -0763 ; [.230F.0020.0002] -0764 ; [.2310.0020.0002] -0644 ; [.2311.0020.0002] -1EE0B ; [.2311.0020.0005] -1EE2B ; [.2311.0020.0005] -1EE4B ; [.2311.0020.0005] -1EE8B ; [.2311.0020.0005] -1EEAB ; [.2311.0020.0005] -FEDF ; [.2311.0020.0017] -FEE0 ; [.2311.0020.0018] -FEDE ; [.2311.0020.0019] -FEDD ; [.2311.0020.001A] -FEF6 ; [.2311.0020.0019][.2279.0020.0019] -FEF5 ; [.2311.0020.001A][.2279.0020.001A] -FEF8 ; [.2311.0020.0019][.227A.0020.0019] -FEF7 ; [.2311.0020.001A][.227A.0020.001A] -FEFA ; [.2311.0020.0019][.227E.0020.0019] -FEF9 ; [.2311.0020.001A][.227E.0020.001A] -FEFC ; [.2311.0020.0019][.2286.0020.0019] -FEFB ; [.2311.0020.001A][.2286.0020.001A] -FCC9 ; [.2311.0020.0017][.229D.0020.0017] -FC3F ; [.2311.0020.001A][.229D.0020.001A] -FD83 ; [.2311.0020.0017][.229D.0020.0017][.229D.0020.0017] -FD84 ; [.2311.0020.0019][.229D.0020.0019][.229D.0020.0019] -FDBA ; [.2311.0020.0017][.229D.0020.0017][.2318.0020.0017] -FDBC ; [.2311.0020.0019][.229D.0020.0019][.2318.0020.0019] -FDAC ; [.2311.0020.0019][.229D.0020.0019][.233A.0020.0019] -FCCA ; [.2311.0020.0017][.22A4.0020.0017] -FC40 ; [.2311.0020.001A][.22A4.0020.001A] -FDB5 ; [.2311.0020.0017][.22A4.0020.0017][.2318.0020.0017] -FD80 ; [.2311.0020.0019][.22A4.0020.0019][.2318.0020.0019] -FD82 ; [.2311.0020.0019][.22A4.0020.0019][.2339.0020.0019] -FD81 ; [.2311.0020.0019][.22A4.0020.0019][.233A.0020.0019] -FCCB ; [.2311.0020.0017][.22A5.0020.0017] -FC41 ; [.2311.0020.001A][.22A5.0020.001A] -FD86 ; [.2311.0020.0017][.22A5.0020.0017][.2318.0020.0017] -FD85 ; [.2311.0020.0019][.22A5.0020.0019][.2318.0020.0019] -FCCC ; [.2311.0020.0017][.2318.0020.0017] -FCED ; [.2311.0020.0018][.2318.0020.0018] -FC85 ; [.2311.0020.0019][.2318.0020.0019] -FC42 ; [.2311.0020.001A][.2318.0020.001A] -FD88 ; [.2311.0020.0017][.2318.0020.0017][.22A4.0020.0017] -FD87 ; [.2311.0020.0019][.2318.0020.0019][.22A4.0020.0019] -FDAD ; [.2311.0020.0019][.2318.0020.0019][.233A.0020.0019] -FCCD ; [.2311.0020.0017][.2325.0020.0017] -FC86 ; [.2311.0020.0019][.2339.0020.0019] -FC43 ; [.2311.0020.001A][.2339.0020.001A] -FC87 ; [.2311.0020.0019][.233A.0020.0019] -FC44 ; [.2311.0020.001A][.233A.0020.001A] -06B5 ; [.2312.0020.0002] -06B6 ; [.2313.0020.0002] -06B7 ; [.2314.0020.0002] -06B8 ; [.2315.0020.0002] -076A ; [.2316.0020.0002] -08A6 ; [.2317.0020.0002] -0645 ; [.2318.0020.0002] -1EE0C ; [.2318.0020.0005] -1EE2C ; [.2318.0020.0005] -1EE6C ; [.2318.0020.0005] -1EE8C ; [.2318.0020.0005] -1EEAC ; [.2318.0020.0005] -FEE3 ; [.2318.0020.0017] -FEE4 ; [.2318.0020.0018] -FEE2 ; [.2318.0020.0019] -FEE1 ; [.2318.0020.001A] -06FE ; [.2318.0020.0004][.0000.010C.0004] -FC88 ; [.2318.0020.0019][.2286.0020.0019] -FCCE ; [.2318.0020.0017][.229D.0020.0017] -FC45 ; [.2318.0020.001A][.229D.0020.001A] -FD8C ; [.2318.0020.0017][.229D.0020.0017][.22A4.0020.0017] -FD92 ; [.2318.0020.0017][.229D.0020.0017][.22A5.0020.0017] -FD8D ; [.2318.0020.0017][.229D.0020.0017][.2318.0020.0017] -FDC0 ; [.2318.0020.0019][.229D.0020.0019][.233A.0020.0019] -FCCF ; [.2318.0020.0017][.22A4.0020.0017] -FC46 ; [.2318.0020.001A][.22A4.0020.001A] -FD89 ; [.2318.0020.0017][.22A4.0020.0017][.229D.0020.0017] -FD8A ; [.2318.0020.0017][.22A4.0020.0017][.2318.0020.0017] -FDF4 ; [.2318.0020.001A][.22A4.0020.001A][.2318.0020.001A][.22AF.0020.001A] -FD8B ; [.2318.0020.0019][.22A4.0020.0019][.233A.0020.0019] -FCD0 ; [.2318.0020.0017][.22A5.0020.0017] -FC47 ; [.2318.0020.001A][.22A5.0020.001A] -FD8E ; [.2318.0020.0017][.22A5.0020.0017][.229D.0020.0017] -FD8F ; [.2318.0020.0017][.22A5.0020.0017][.2318.0020.0017] -FDB9 ; [.2318.0020.0019][.22A5.0020.0019][.233A.0020.0019] -FCD1 ; [.2318.0020.0017][.2318.0020.0017] -FC89 ; [.2318.0020.0019][.2318.0020.0019] -FC48 ; [.2318.0020.001A][.2318.0020.001A] -FDB1 ; [.2318.0020.0019][.2318.0020.0019][.233A.0020.0019] -FC49 ; [.2318.0020.001A][.2339.0020.001A] -FC4A ; [.2318.0020.001A][.233A.0020.001A] -0765 ; [.2319.0020.0002] -0766 ; [.231A.0020.0002] -08A7 ; [.231B.0020.0002] -0646 ; [.231C.0020.0002] -1EE0D ; [.231C.0020.0005] -1EE2D ; [.231C.0020.0005] -1EE4D ; [.231C.0020.0005] -1EE6D ; [.231C.0020.0005] -1EE8D ; [.231C.0020.0005] -1EEAD ; [.231C.0020.0005] -FEE7 ; [.231C.0020.0017] -FEE8 ; [.231C.0020.0018] -FEE6 ; [.231C.0020.0019] -FEE5 ; [.231C.0020.001A] -FCD2 ; [.231C.0020.0017][.229D.0020.0017] -FC4B ; [.231C.0020.001A][.229D.0020.001A] -FDB8 ; [.231C.0020.0017][.229D.0020.0017][.22A4.0020.0017] -FDBD ; [.231C.0020.0019][.229D.0020.0019][.22A4.0020.0019] -FD98 ; [.231C.0020.0017][.229D.0020.0017][.2318.0020.0017] -FD97 ; [.231C.0020.0019][.229D.0020.0019][.2318.0020.0019] -FD99 ; [.231C.0020.0019][.229D.0020.0019][.2339.0020.0019] -FDC7 ; [.231C.0020.0019][.229D.0020.0019][.233A.0020.0019] -FCD3 ; [.231C.0020.0017][.22A4.0020.0017] -FC4C ; [.231C.0020.001A][.22A4.0020.001A] -FD95 ; [.231C.0020.0017][.22A4.0020.0017][.2318.0020.0017] -FD96 ; [.231C.0020.0019][.22A4.0020.0019][.2339.0020.0019] -FDB3 ; [.231C.0020.0019][.22A4.0020.0019][.233A.0020.0019] -FCD4 ; [.231C.0020.0017][.22A5.0020.0017] -FC4D ; [.231C.0020.001A][.22A5.0020.001A] -FC8A ; [.231C.0020.0019][.22BE.0020.0019] -FC8B ; [.231C.0020.0019][.22BF.0020.0019] -FCD5 ; [.231C.0020.0017][.2318.0020.0017] -FCEE ; [.231C.0020.0018][.2318.0020.0018] -FC8C ; [.231C.0020.0019][.2318.0020.0019] -FC4E ; [.231C.0020.001A][.2318.0020.001A] -FD9B ; [.231C.0020.0019][.2318.0020.0019][.2339.0020.0019] -FD9A ; [.231C.0020.0019][.2318.0020.0019][.233A.0020.0019] -FC8D ; [.231C.0020.0019][.231C.0020.0019] -FCD6 ; [.231C.0020.0017][.2325.0020.0017] -FCEF ; [.231C.0020.0018][.2325.0020.0018] -FC8E ; [.231C.0020.0019][.2339.0020.0019] -FC4F ; [.231C.0020.001A][.2339.0020.001A] -FC8F ; [.231C.0020.0019][.233A.0020.0019] -FC50 ; [.231C.0020.001A][.233A.0020.001A] -06BA ; [.231D.0020.0002] -1EE1D ; [.231D.0020.0005] -1EE5D ; [.231D.0020.0005] -FB9F ; [.231D.0020.0019] -FB9E ; [.231D.0020.001A] -06BB ; [.231E.0020.0002] -FBA2 ; [.231E.0020.0017] -FBA3 ; [.231E.0020.0018] -FBA1 ; [.231E.0020.0019] -FBA0 ; [.231E.0020.001A] -06BC ; [.231F.0020.0002] -06BD ; [.2320.0020.0002] -06B9 ; [.2321.0020.0002] -0767 ; [.2322.0020.0002] -0768 ; [.2323.0020.0002] -0769 ; [.2324.0020.0002] -0647 ; [.2325.0020.0002] -1EE24 ; [.2325.0020.0005] -1EE64 ; [.2325.0020.0005] -1EE84 ; [.2325.0020.0005] -FEEB ; [.2325.0020.0017] -FEEC ; [.2325.0020.0018] -FEEA ; [.2325.0020.0019] -FEE9 ; [.2325.0020.001A] -FCD9 ; [.2325.0020.0017][.0000.0098.0017] -FCD7 ; [.2325.0020.0017][.229D.0020.0017] -FC51 ; [.2325.0020.001A][.229D.0020.001A] -FCD8 ; [.2325.0020.0017][.2318.0020.0017] -FC52 ; [.2325.0020.001A][.2318.0020.001A] -FD93 ; [.2325.0020.0017][.2318.0020.0017][.229D.0020.0017] -FD94 ; [.2325.0020.0017][.2318.0020.0017][.2318.0020.0017] -FC53 ; [.2325.0020.001A][.2339.0020.001A] -FC54 ; [.2325.0020.001A][.233A.0020.001A] -06BE ; [.2326.0020.0002] -FBAC ; [.2326.0020.0017] -FBAD ; [.2326.0020.0018] -FBAB ; [.2326.0020.0019] -FBAA ; [.2326.0020.001A] -06C1 ; [.2327.0020.0002] -FBA8 ; [.2327.0020.0017] -FBA9 ; [.2327.0020.0018] -FBA7 ; [.2327.0020.0019] -FBA6 ; [.2327.0020.001A] -06C2 ; [.2327.0020.0002][.0000.0083.0002] -06C3 ; [.2328.0020.0002] -06FF ; [.2329.0020.0002] -06D5 ; [.232A.0020.0002] -06C0 ; [.232A.0020.0002][.0000.0083.0002] -FBA5 ; [.232A.0020.0019][.0000.0083.0019] -FBA4 ; [.232A.0020.001A][.0000.0083.001A] -0648 ; [.232B.0020.0002] -06E5 ; [.232B.0020.0004] -1EE05 ; [.232B.0020.0005] -1EE85 ; [.232B.0020.0005] -1EEA5 ; [.232B.0020.0005] -FEEE ; [.232B.0020.0019] -FEED ; [.232B.0020.001A] -0676 ; [.232B.0020.0004][.2278.0020.0004] -FDF8 ; [.232B.0020.001A][.22D0.0020.001A][.2311.0020.001A][.2318.0020.001A] -06C4 ; [.232C.0020.0002] -06C5 ; [.232D.0020.0002] -FBE1 ; [.232D.0020.0019] -FBE0 ; [.232D.0020.001A] -06C6 ; [.232E.0020.0002] -FBDA ; [.232E.0020.0019] -FBD9 ; [.232E.0020.001A] -06C7 ; [.232F.0020.0002] -FBD8 ; [.232F.0020.0019] -FBD7 ; [.232F.0020.001A] -0677 ; [.232F.0020.0004][.2278.0020.0004] -FBDD ; [.232F.0020.001A][.2278.0020.001A] -06C8 ; [.2330.0020.0002] -FBDC ; [.2330.0020.0019] -FBDB ; [.2330.0020.001A] -06C9 ; [.2331.0020.0002] -FBE3 ; [.2331.0020.0019] -FBE2 ; [.2331.0020.001A] -06CA ; [.2332.0020.0002] -06CB ; [.2333.0020.0002] -FBDF ; [.2333.0020.0019] -FBDE ; [.2333.0020.001A] -08B1 ; [.2334.0020.0002] -06CF ; [.2335.0020.0002] -0778 ; [.2336.0020.0002] -0779 ; [.2337.0020.0002] -08AB ; [.2338.0020.0002] -0649 ; [.2339.0020.0002] -FBE8 ; [.2339.0020.0017] -FBE9 ; [.2339.0020.0018] -FEF0 ; [.2339.0020.0019] -FEEF ; [.2339.0020.001A] -FC90 ; [.2339.0020.0019][.0000.0098.0019] -FC5D ; [.2339.0020.001A][.0000.0098.001A] -064A ; [.233A.0020.0002] -06E6 ; [.233A.0020.0004] -1EE09 ; [.233A.0020.0005] -1EE29 ; [.233A.0020.0005] -1EE49 ; [.233A.0020.0005] -1EE69 ; [.233A.0020.0005] -1EE89 ; [.233A.0020.0005] -1EEA9 ; [.233A.0020.0005] -FEF3 ; [.233A.0020.0017] -FEF4 ; [.233A.0020.0018] -FEF2 ; [.233A.0020.0019] -FEF1 ; [.233A.0020.001A] -0678 ; [.233A.0020.0004][.2278.0020.0004] -FCDA ; [.233A.0020.0017][.229D.0020.0017] -FC55 ; [.233A.0020.001A][.229D.0020.001A] -FDAF ; [.233A.0020.0019][.229D.0020.0019][.233A.0020.0019] -FCDB ; [.233A.0020.0017][.22A4.0020.0017] -FC56 ; [.233A.0020.001A][.22A4.0020.001A] -FDAE ; [.233A.0020.0019][.22A4.0020.0019][.233A.0020.0019] -FCDC ; [.233A.0020.0017][.22A5.0020.0017] -FC57 ; [.233A.0020.001A][.22A5.0020.001A] -FC91 ; [.233A.0020.0019][.22BE.0020.0019] -FC92 ; [.233A.0020.0019][.22BF.0020.0019] -FCDD ; [.233A.0020.0017][.2318.0020.0017] -FCF0 ; [.233A.0020.0018][.2318.0020.0018] -FC93 ; [.233A.0020.0019][.2318.0020.0019] -FC58 ; [.233A.0020.001A][.2318.0020.001A] -FD9D ; [.233A.0020.0017][.2318.0020.0017][.2318.0020.0017] -FD9C ; [.233A.0020.0019][.2318.0020.0019][.2318.0020.0019] -FDB0 ; [.233A.0020.0019][.2318.0020.0019][.233A.0020.0019] -FC94 ; [.233A.0020.0019][.231C.0020.0019] -FCDE ; [.233A.0020.0017][.2325.0020.0017] -FCF1 ; [.233A.0020.0018][.2325.0020.0018] -FC95 ; [.233A.0020.0019][.2339.0020.0019] -FC59 ; [.233A.0020.001A][.2339.0020.001A] -FC96 ; [.233A.0020.0019][.233A.0020.0019] -FC5A ; [.233A.0020.001A][.233A.0020.001A] -06CC ; [.233B.0020.0002] -FBFE ; [.233B.0020.0017] -FBFF ; [.233B.0020.0018] -FBFD ; [.233B.0020.0019] -FBFC ; [.233B.0020.001A] -06CD ; [.233C.0020.0002] -06CE ; [.233D.0020.0002] -06D0 ; [.233E.0020.0002] -FBE6 ; [.233E.0020.0017] -FBE7 ; [.233E.0020.0018] -FBE5 ; [.233E.0020.0019] -FBE4 ; [.233E.0020.001A] -06D1 ; [.233F.0020.0002] -063D ; [.2340.0020.0002] -063E ; [.2341.0020.0002] -063F ; [.2342.0020.0002] -0620 ; [.2343.0020.0002] -0775 ; [.2344.0020.0002] -0776 ; [.2345.0020.0002] -0777 ; [.2346.0020.0002] -06D2 ; [.2347.0020.0002] -FBAF ; [.2347.0020.0019] -FBAE ; [.2347.0020.001A] -06D3 ; [.2347.0020.0002][.0000.0083.0002] -FBB1 ; [.2347.0020.0019][.0000.0083.0019] -FBB0 ; [.2347.0020.001A][.0000.0083.001A] -077A ; [.2348.0020.0002] -077B ; [.2349.0020.0002] -0710 ; [.234A.0020.0002] -0712 ; [.234B.0020.0002] -072D ; [.234B.0020.0004][.0000.010D.0004] -0713 ; [.234C.0020.0002] -0714 ; [.234C.0020.0004][.0000.010C.0004] -072E ; [.234C.0020.0004][.0000.010D.0004] -0716 ; [.234D.0020.0002] -0715 ; [.234E.0020.0002] -072F ; [.234E.0020.0004][.0000.010D.0004] -0717 ; [.234F.0020.0002] -0718 ; [.2350.0020.0002] -0719 ; [.2351.0020.0002] -074D ; [.2352.0020.0002] -071A ; [.2353.0020.0002] -071B ; [.2354.0020.0002] -071C ; [.2354.0020.0004][.0000.010C.0004] -071D ; [.2355.0020.0002] -071E ; [.2356.0020.0002] -071F ; [.2357.0020.0002] -074E ; [.2358.0020.0002] -0720 ; [.2359.0020.0002] -0721 ; [.235A.0020.0002] -0722 ; [.235B.0020.0002] -0723 ; [.235C.0020.0002] -0724 ; [.235C.0020.0019] -0725 ; [.235D.0020.0002] -0726 ; [.235E.0020.0002] -0727 ; [.235E.0020.0004][.0000.010C.0004] -074F ; [.235F.0020.0002] -0728 ; [.2360.0020.0002] -0729 ; [.2361.0020.0002] -072A ; [.2362.0020.0002] -072B ; [.2363.0020.0002] -072C ; [.2364.0020.0002] -0840 ; [.2365.0020.0002] -0841 ; [.2366.0020.0002] -0842 ; [.2367.0020.0002] -0843 ; [.2368.0020.0002] -0844 ; [.2369.0020.0002] -0845 ; [.236A.0020.0002] -0846 ; [.236B.0020.0002] -0847 ; [.236C.0020.0002] -0848 ; [.236D.0020.0002] -0849 ; [.236E.0020.0002] -084A ; [.236F.0020.0002] -084B ; [.2370.0020.0002] -084C ; [.2371.0020.0002] -084D ; [.2372.0020.0002] -084E ; [.2373.0020.0002] -084F ; [.2374.0020.0002] -0850 ; [.2375.0020.0002] -0851 ; [.2376.0020.0002] -0852 ; [.2377.0020.0002] -0853 ; [.2378.0020.0002] -0854 ; [.2379.0020.0002] -0855 ; [.237A.0020.0002] -0856 ; [.237B.0020.0002] -0857 ; [.237C.0020.0002] -0858 ; [.237D.0020.0002] -0780 ; [.237E.0020.0002] -0799 ; [.237F.0020.0002] -079A ; [.2380.0020.0002] -0781 ; [.2381.0020.0002] -0782 ; [.2382.0020.0002] -0783 ; [.2383.0020.0002] -079C ; [.2384.0020.0002] -0784 ; [.2385.0020.0002] -0785 ; [.2386.0020.0002] -0786 ; [.2387.0020.0002] -0787 ; [.2388.0020.0002] -07A2 ; [.2389.0020.0002] -07A3 ; [.238A.0020.0002] -0788 ; [.238B.0020.0002] -07A5 ; [.238C.0020.0002] -0789 ; [.238D.0020.0002] -078A ; [.238E.0020.0002] -078B ; [.238F.0020.0002] -079B ; [.2390.0020.0002] -078C ; [.2391.0020.0002] -0798 ; [.2392.0020.0002] -07A0 ; [.2393.0020.0002] -07A1 ; [.2394.0020.0002] -078D ; [.2395.0020.0002] -078E ; [.2396.0020.0002] -07A4 ; [.2397.0020.0002] -078F ; [.2398.0020.0002] -0790 ; [.2399.0020.0002] -079D ; [.239A.0020.0002] -079E ; [.239B.0020.0002] -079F ; [.239C.0020.0002] -0791 ; [.239D.0020.0002] -0792 ; [.239E.0020.0002] -0793 ; [.239F.0020.0002] -0794 ; [.23A0.0020.0002] -0795 ; [.23A1.0020.0002] -0796 ; [.23A2.0020.0002] -0797 ; [.23A3.0020.0002] -07B1 ; [.23A4.0020.0002] -07A6 ; [.23A5.0020.0002] -07A7 ; [.23A6.0020.0002] -07A8 ; [.23A7.0020.0002] -07A9 ; [.23A8.0020.0002] -07AA ; [.23A9.0020.0002] -07AB ; [.23AA.0020.0002] -07AC ; [.23AB.0020.0002] -07AD ; [.23AC.0020.0002] -07AE ; [.23AD.0020.0002] -07AF ; [.23AE.0020.0002] -07B0 ; [.23AF.0020.0002] -07CA ; [.23B0.0020.0002] -07CB ; [.23B1.0020.0002] -07CC ; [.23B2.0020.0002] -07CD ; [.23B3.0020.0002] -07CE ; [.23B4.0020.0002] -07CF ; [.23B5.0020.0002] -07D0 ; [.23B6.0020.0002] -07D1 ; [.23B7.0020.0002] -07D2 ; [.23B8.0020.0002] -07D3 ; [.23B9.0020.0002] -07D4 ; [.23BA.0020.0002] -07D5 ; [.23BB.0020.0002] -07D6 ; [.23BC.0020.0002] -07E8 ; [.23BC.0020.0004][.0000.010B.0004] -07D7 ; [.23BD.0020.0002] -07E9 ; [.23BD.0020.0004][.0000.010B.0004] -07D8 ; [.23BE.0020.0002] -07D9 ; [.23BF.0020.0002] -07EA ; [.23BF.0020.0004][.0000.010B.0004] -07DA ; [.23C0.0020.0002] -07DB ; [.23C1.0020.0002] -07DC ; [.23C2.0020.0002] -07DD ; [.23C3.0020.0002] -07DE ; [.23C4.0020.0002] -07DF ; [.23C5.0020.0002] -07E0 ; [.23C6.0020.0002] -07E1 ; [.23C7.0020.0002] -07E2 ; [.23C8.0020.0002] -07E3 ; [.23C9.0020.0002] -07E4 ; [.23CA.0020.0002] -07E5 ; [.23CB.0020.0002] -07E6 ; [.23CC.0020.0002] -07E7 ; [.23CD.0020.0002] -07F4 ; [.23CE.0020.0002] -07F5 ; [.23CF.0020.0002] -2D30 ; [.23D0.0020.0002] -2D31 ; [.23D1.0020.0002] -2D32 ; [.23D2.0020.0002] -2D33 ; [.23D3.0020.0002] -2D34 ; [.23D4.0020.0002] -2D35 ; [.23D5.0020.0002] -2D36 ; [.23D6.0020.0002] -2D37 ; [.23D7.0020.0002] -2D38 ; [.23D8.0020.0002] -2D39 ; [.23D9.0020.0002] -2D3A ; [.23DA.0020.0002] -2D3B ; [.23DB.0020.0002] -2D66 ; [.23DC.0020.0002] -2D3C ; [.23DD.0020.0002] -2D3D ; [.23DE.0020.0002] -2D3E ; [.23DF.0020.0002] -2D3F ; [.23E0.0020.0002] -2D40 ; [.23E1.0020.0002] -2D41 ; [.23E2.0020.0002] -2D42 ; [.23E3.0020.0002] -2D43 ; [.23E4.0020.0002] -2D44 ; [.23E5.0020.0002] -2D45 ; [.23E6.0020.0002] -2D46 ; [.23E7.0020.0002] -2D47 ; [.23E8.0020.0002] -2D48 ; [.23E9.0020.0002] -2D49 ; [.23EA.0020.0002] -2D4A ; [.23EB.0020.0002] -2D4B ; [.23EC.0020.0002] -2D4C ; [.23ED.0020.0002] -2D4D ; [.23EE.0020.0002] -2D4E ; [.23EF.0020.0002] -2D4F ; [.23F0.0020.0002] -2D50 ; [.23F1.0020.0002] -2D51 ; [.23F2.0020.0002] -2D52 ; [.23F3.0020.0002] -2D53 ; [.23F4.0020.0002] -2D67 ; [.23F5.0020.0002] -2D54 ; [.23F6.0020.0002] -2D55 ; [.23F7.0020.0002] -2D56 ; [.23F8.0020.0002] -2D57 ; [.23F9.0020.0002] -2D58 ; [.23FA.0020.0002] -2D59 ; [.23FB.0020.0002] -2D5A ; [.23FC.0020.0002] -2D5B ; [.23FD.0020.0002] -2D5C ; [.23FE.0020.0002] -2D5D ; [.23FF.0020.0002] -2D5E ; [.2400.0020.0002] -2D5F ; [.2401.0020.0002] -2D60 ; [.2402.0020.0002] -2D61 ; [.2403.0020.0002] -2D62 ; [.2404.0020.0002] -2D63 ; [.2405.0020.0002] -2D64 ; [.2406.0020.0002] -2D65 ; [.2407.0020.0002] -2D6F ; [.2408.0020.0002] -1200 ; [.2409.0020.0002] -1201 ; [.240A.0020.0002] -1202 ; [.240B.0020.0002] -1203 ; [.240C.0020.0002] -1204 ; [.240D.0020.0002] -1205 ; [.240E.0020.0002] -1206 ; [.240F.0020.0002] -1207 ; [.2410.0020.0002] -1208 ; [.2411.0020.0002] -1209 ; [.2412.0020.0002] -120A ; [.2413.0020.0002] -120B ; [.2414.0020.0002] -120C ; [.2415.0020.0002] -120D ; [.2416.0020.0002] -120E ; [.2417.0020.0002] -120F ; [.2418.0020.0002] -2D80 ; [.2419.0020.0002] -1210 ; [.241A.0020.0002] -1211 ; [.241B.0020.0002] -1212 ; [.241C.0020.0002] -1213 ; [.241D.0020.0002] -1214 ; [.241E.0020.0002] -1215 ; [.241F.0020.0002] -1216 ; [.2420.0020.0002] -1217 ; [.2421.0020.0002] -1218 ; [.2422.0020.0002] -1219 ; [.2423.0020.0002] -121A ; [.2424.0020.0002] -121B ; [.2425.0020.0002] -121C ; [.2426.0020.0002] -121D ; [.2427.0020.0002] -121E ; [.2428.0020.0002] -121F ; [.2429.0020.0002] -1380 ; [.242A.0020.0002] -1381 ; [.242B.0020.0002] -1382 ; [.242C.0020.0002] -1383 ; [.242D.0020.0002] -2D81 ; [.242E.0020.0002] -1220 ; [.242F.0020.0002] -1221 ; [.2430.0020.0002] -1222 ; [.2431.0020.0002] -1223 ; [.2432.0020.0002] -1224 ; [.2433.0020.0002] -1225 ; [.2434.0020.0002] -1226 ; [.2435.0020.0002] -1227 ; [.2436.0020.0002] -1228 ; [.2437.0020.0002] -1229 ; [.2438.0020.0002] -122A ; [.2439.0020.0002] -122B ; [.243A.0020.0002] -122C ; [.243B.0020.0002] -122D ; [.243C.0020.0002] -122E ; [.243D.0020.0002] -122F ; [.243E.0020.0002] -2D82 ; [.243F.0020.0002] -1230 ; [.2440.0020.0002] -1231 ; [.2441.0020.0002] -1232 ; [.2442.0020.0002] -1233 ; [.2443.0020.0002] -1234 ; [.2444.0020.0002] -1235 ; [.2445.0020.0002] -1236 ; [.2446.0020.0002] -1237 ; [.2447.0020.0002] -2D83 ; [.2448.0020.0002] -AB01 ; [.2449.0020.0002] -AB02 ; [.244A.0020.0002] -AB03 ; [.244B.0020.0002] -AB04 ; [.244C.0020.0002] -AB05 ; [.244D.0020.0002] -AB06 ; [.244E.0020.0002] -1238 ; [.244F.0020.0002] -1239 ; [.2450.0020.0002] -123A ; [.2451.0020.0002] -123B ; [.2452.0020.0002] -123C ; [.2453.0020.0002] -123D ; [.2454.0020.0002] -123E ; [.2455.0020.0002] -123F ; [.2456.0020.0002] -2D84 ; [.2457.0020.0002] -1240 ; [.2458.0020.0002] -1241 ; [.2459.0020.0002] -1242 ; [.245A.0020.0002] -1243 ; [.245B.0020.0002] -1244 ; [.245C.0020.0002] -1245 ; [.245D.0020.0002] -1246 ; [.245E.0020.0002] -1247 ; [.245F.0020.0002] -1248 ; [.2460.0020.0002] -124A ; [.2461.0020.0002] -124B ; [.2462.0020.0002] -124C ; [.2463.0020.0002] -124D ; [.2464.0020.0002] -1250 ; [.2465.0020.0002] -1251 ; [.2466.0020.0002] -1252 ; [.2467.0020.0002] -1253 ; [.2468.0020.0002] -1254 ; [.2469.0020.0002] -1255 ; [.246A.0020.0002] -1256 ; [.246B.0020.0002] -1258 ; [.246C.0020.0002] -125A ; [.246D.0020.0002] -125B ; [.246E.0020.0002] -125C ; [.246F.0020.0002] -125D ; [.2470.0020.0002] -1260 ; [.2471.0020.0002] -1261 ; [.2472.0020.0002] -1262 ; [.2473.0020.0002] -1263 ; [.2474.0020.0002] -1264 ; [.2475.0020.0002] -1265 ; [.2476.0020.0002] -1266 ; [.2477.0020.0002] -1267 ; [.2478.0020.0002] -1384 ; [.2479.0020.0002] -1385 ; [.247A.0020.0002] -1386 ; [.247B.0020.0002] -1387 ; [.247C.0020.0002] -2D85 ; [.247D.0020.0002] -1268 ; [.247E.0020.0002] -1269 ; [.247F.0020.0002] -126A ; [.2480.0020.0002] -126B ; [.2481.0020.0002] -126C ; [.2482.0020.0002] -126D ; [.2483.0020.0002] -126E ; [.2484.0020.0002] -126F ; [.2485.0020.0002] -1270 ; [.2486.0020.0002] -1271 ; [.2487.0020.0002] -1272 ; [.2488.0020.0002] -1273 ; [.2489.0020.0002] -1274 ; [.248A.0020.0002] -1275 ; [.248B.0020.0002] -1276 ; [.248C.0020.0002] -1277 ; [.248D.0020.0002] -2D86 ; [.248E.0020.0002] -1278 ; [.248F.0020.0002] -1279 ; [.2490.0020.0002] -127A ; [.2491.0020.0002] -127B ; [.2492.0020.0002] -127C ; [.2493.0020.0002] -127D ; [.2494.0020.0002] -127E ; [.2495.0020.0002] -127F ; [.2496.0020.0002] -2D87 ; [.2497.0020.0002] -1280 ; [.2498.0020.0002] -1281 ; [.2499.0020.0002] -1282 ; [.249A.0020.0002] -1283 ; [.249B.0020.0002] -1284 ; [.249C.0020.0002] -1285 ; [.249D.0020.0002] -1286 ; [.249E.0020.0002] -1287 ; [.249F.0020.0002] -1288 ; [.24A0.0020.0002] -128A ; [.24A1.0020.0002] -128B ; [.24A2.0020.0002] -128C ; [.24A3.0020.0002] -128D ; [.24A4.0020.0002] -1290 ; [.24A5.0020.0002] -1291 ; [.24A6.0020.0002] -1292 ; [.24A7.0020.0002] -1293 ; [.24A8.0020.0002] -1294 ; [.24A9.0020.0002] -1295 ; [.24AA.0020.0002] -1296 ; [.24AB.0020.0002] -1297 ; [.24AC.0020.0002] -2D88 ; [.24AD.0020.0002] -1298 ; [.24AE.0020.0002] -1299 ; [.24AF.0020.0002] -129A ; [.24B0.0020.0002] -129B ; [.24B1.0020.0002] -129C ; [.24B2.0020.0002] -129D ; [.24B3.0020.0002] -129E ; [.24B4.0020.0002] -129F ; [.24B5.0020.0002] -2D89 ; [.24B6.0020.0002] -12A0 ; [.24B7.0020.0002] -12A1 ; [.24B8.0020.0002] -12A2 ; [.24B9.0020.0002] -12A3 ; [.24BA.0020.0002] -12A4 ; [.24BB.0020.0002] -12A5 ; [.24BC.0020.0002] -12A6 ; [.24BD.0020.0002] -12A7 ; [.24BE.0020.0002] -2D8A ; [.24BF.0020.0002] -12A8 ; [.24C0.0020.0002] -12A9 ; [.24C1.0020.0002] -12AA ; [.24C2.0020.0002] -12AB ; [.24C3.0020.0002] -12AC ; [.24C4.0020.0002] -12AD ; [.24C5.0020.0002] -12AE ; [.24C6.0020.0002] -12AF ; [.24C7.0020.0002] -12B0 ; [.24C8.0020.0002] -12B2 ; [.24C9.0020.0002] -12B3 ; [.24CA.0020.0002] -12B4 ; [.24CB.0020.0002] -12B5 ; [.24CC.0020.0002] -12B8 ; [.24CD.0020.0002] -12B9 ; [.24CE.0020.0002] -12BA ; [.24CF.0020.0002] -12BB ; [.24D0.0020.0002] -12BC ; [.24D1.0020.0002] -12BD ; [.24D2.0020.0002] -12BE ; [.24D3.0020.0002] -12C0 ; [.24D4.0020.0002] -12C2 ; [.24D5.0020.0002] -12C3 ; [.24D6.0020.0002] -12C4 ; [.24D7.0020.0002] -12C5 ; [.24D8.0020.0002] -12C8 ; [.24D9.0020.0002] -12C9 ; [.24DA.0020.0002] -12CA ; [.24DB.0020.0002] -12CB ; [.24DC.0020.0002] -12CC ; [.24DD.0020.0002] -12CD ; [.24DE.0020.0002] -12CE ; [.24DF.0020.0002] -12CF ; [.24E0.0020.0002] -12D0 ; [.24E1.0020.0002] -12D1 ; [.24E2.0020.0002] -12D2 ; [.24E3.0020.0002] -12D3 ; [.24E4.0020.0002] -12D4 ; [.24E5.0020.0002] -12D5 ; [.24E6.0020.0002] -12D6 ; [.24E7.0020.0002] -12D8 ; [.24E8.0020.0002] -12D9 ; [.24E9.0020.0002] -12DA ; [.24EA.0020.0002] -12DB ; [.24EB.0020.0002] -12DC ; [.24EC.0020.0002] -12DD ; [.24ED.0020.0002] -12DE ; [.24EE.0020.0002] -12DF ; [.24EF.0020.0002] -2D8B ; [.24F0.0020.0002] -AB11 ; [.24F1.0020.0002] -AB12 ; [.24F2.0020.0002] -AB13 ; [.24F3.0020.0002] -AB14 ; [.24F4.0020.0002] -AB15 ; [.24F5.0020.0002] -AB16 ; [.24F6.0020.0002] -12E0 ; [.24F7.0020.0002] -12E1 ; [.24F8.0020.0002] -12E2 ; [.24F9.0020.0002] -12E3 ; [.24FA.0020.0002] -12E4 ; [.24FB.0020.0002] -12E5 ; [.24FC.0020.0002] -12E6 ; [.24FD.0020.0002] -12E7 ; [.24FE.0020.0002] -12E8 ; [.24FF.0020.0002] -12E9 ; [.2500.0020.0002] -12EA ; [.2501.0020.0002] -12EB ; [.2502.0020.0002] -12EC ; [.2503.0020.0002] -12ED ; [.2504.0020.0002] -12EE ; [.2505.0020.0002] -12EF ; [.2506.0020.0002] -12F0 ; [.2507.0020.0002] -12F1 ; [.2508.0020.0002] -12F2 ; [.2509.0020.0002] -12F3 ; [.250A.0020.0002] -12F4 ; [.250B.0020.0002] -12F5 ; [.250C.0020.0002] -12F6 ; [.250D.0020.0002] -12F7 ; [.250E.0020.0002] -2D8C ; [.250F.0020.0002] -AB09 ; [.2510.0020.0002] -AB0A ; [.2511.0020.0002] -AB0B ; [.2512.0020.0002] -AB0C ; [.2513.0020.0002] -AB0D ; [.2514.0020.0002] -AB0E ; [.2515.0020.0002] -12F8 ; [.2516.0020.0002] -12F9 ; [.2517.0020.0002] -12FA ; [.2518.0020.0002] -12FB ; [.2519.0020.0002] -12FC ; [.251A.0020.0002] -12FD ; [.251B.0020.0002] -12FE ; [.251C.0020.0002] -12FF ; [.251D.0020.0002] -2D8D ; [.251E.0020.0002] -1300 ; [.251F.0020.0002] -1301 ; [.2520.0020.0002] -1302 ; [.2521.0020.0002] -1303 ; [.2522.0020.0002] -1304 ; [.2523.0020.0002] -1305 ; [.2524.0020.0002] -1306 ; [.2525.0020.0002] -1307 ; [.2526.0020.0002] -2D8E ; [.2527.0020.0002] -1308 ; [.2528.0020.0002] -1309 ; [.2529.0020.0002] -130A ; [.252A.0020.0002] -130B ; [.252B.0020.0002] -130C ; [.252C.0020.0002] -130D ; [.252D.0020.0002] -130E ; [.252E.0020.0002] -130F ; [.252F.0020.0002] -1310 ; [.2530.0020.0002] -1312 ; [.2531.0020.0002] -1313 ; [.2532.0020.0002] -1314 ; [.2533.0020.0002] -1315 ; [.2534.0020.0002] -1318 ; [.2535.0020.0002] -1319 ; [.2536.0020.0002] -131A ; [.2537.0020.0002] -131B ; [.2538.0020.0002] -131C ; [.2539.0020.0002] -131D ; [.253A.0020.0002] -131E ; [.253B.0020.0002] -131F ; [.253C.0020.0002] -2D93 ; [.253D.0020.0002] -2D94 ; [.253E.0020.0002] -2D95 ; [.253F.0020.0002] -2D96 ; [.2540.0020.0002] -1320 ; [.2541.0020.0002] -1321 ; [.2542.0020.0002] -1322 ; [.2543.0020.0002] -1323 ; [.2544.0020.0002] -1324 ; [.2545.0020.0002] -1325 ; [.2546.0020.0002] -1326 ; [.2547.0020.0002] -1327 ; [.2548.0020.0002] -2D8F ; [.2549.0020.0002] -1328 ; [.254A.0020.0002] -1329 ; [.254B.0020.0002] -132A ; [.254C.0020.0002] -132B ; [.254D.0020.0002] -132C ; [.254E.0020.0002] -132D ; [.254F.0020.0002] -132E ; [.2550.0020.0002] -132F ; [.2551.0020.0002] -2D90 ; [.2552.0020.0002] -AB20 ; [.2553.0020.0002] -AB21 ; [.2554.0020.0002] -AB22 ; [.2555.0020.0002] -AB23 ; [.2556.0020.0002] -AB24 ; [.2557.0020.0002] -AB25 ; [.2558.0020.0002] -AB26 ; [.2559.0020.0002] -1330 ; [.255A.0020.0002] -1331 ; [.255B.0020.0002] -1332 ; [.255C.0020.0002] -1333 ; [.255D.0020.0002] -1334 ; [.255E.0020.0002] -1335 ; [.255F.0020.0002] -1336 ; [.2560.0020.0002] -1337 ; [.2561.0020.0002] -2D91 ; [.2562.0020.0002] -1338 ; [.2563.0020.0002] -1339 ; [.2564.0020.0002] -133A ; [.2565.0020.0002] -133B ; [.2566.0020.0002] -133C ; [.2567.0020.0002] -133D ; [.2568.0020.0002] -133E ; [.2569.0020.0002] -133F ; [.256A.0020.0002] -AB28 ; [.256B.0020.0002] -AB29 ; [.256C.0020.0002] -AB2A ; [.256D.0020.0002] -AB2B ; [.256E.0020.0002] -AB2C ; [.256F.0020.0002] -AB2D ; [.2570.0020.0002] -AB2E ; [.2571.0020.0002] -1340 ; [.2572.0020.0002] -1341 ; [.2573.0020.0002] -1342 ; [.2574.0020.0002] -1343 ; [.2575.0020.0002] -1344 ; [.2576.0020.0002] -1345 ; [.2577.0020.0002] -1346 ; [.2578.0020.0002] -1347 ; [.2579.0020.0002] -1348 ; [.257A.0020.0002] -1349 ; [.257B.0020.0002] -134A ; [.257C.0020.0002] -134B ; [.257D.0020.0002] -134C ; [.257E.0020.0002] -134D ; [.257F.0020.0002] -134E ; [.2580.0020.0002] -134F ; [.2581.0020.0002] -1388 ; [.2582.0020.0002] -1389 ; [.2583.0020.0002] -138A ; [.2584.0020.0002] -138B ; [.2585.0020.0002] -1350 ; [.2586.0020.0002] -1351 ; [.2587.0020.0002] -1352 ; [.2588.0020.0002] -1353 ; [.2589.0020.0002] -1354 ; [.258A.0020.0002] -1355 ; [.258B.0020.0002] -1356 ; [.258C.0020.0002] -1357 ; [.258D.0020.0002] -138C ; [.258E.0020.0002] -138D ; [.258F.0020.0002] -138E ; [.2590.0020.0002] -138F ; [.2591.0020.0002] -2D92 ; [.2592.0020.0002] -1358 ; [.2593.0020.0002] -1359 ; [.2594.0020.0002] -135A ; [.2595.0020.0002] -2DA0 ; [.2596.0020.0002] -2DA1 ; [.2597.0020.0002] -2DA2 ; [.2598.0020.0002] -2DA3 ; [.2599.0020.0002] -2DA4 ; [.259A.0020.0002] -2DA5 ; [.259B.0020.0002] -2DA6 ; [.259C.0020.0002] -2DA8 ; [.259D.0020.0002] -2DA9 ; [.259E.0020.0002] -2DAA ; [.259F.0020.0002] -2DAB ; [.25A0.0020.0002] -2DAC ; [.25A1.0020.0002] -2DAD ; [.25A2.0020.0002] -2DAE ; [.25A3.0020.0002] -2DB0 ; [.25A4.0020.0002] -2DB1 ; [.25A5.0020.0002] -2DB2 ; [.25A6.0020.0002] -2DB3 ; [.25A7.0020.0002] -2DB4 ; [.25A8.0020.0002] -2DB5 ; [.25A9.0020.0002] -2DB6 ; [.25AA.0020.0002] -2DB8 ; [.25AB.0020.0002] -2DB9 ; [.25AC.0020.0002] -2DBA ; [.25AD.0020.0002] -2DBB ; [.25AE.0020.0002] -2DBC ; [.25AF.0020.0002] -2DBD ; [.25B0.0020.0002] -2DBE ; [.25B1.0020.0002] -2DC0 ; [.25B2.0020.0002] -2DC1 ; [.25B3.0020.0002] -2DC2 ; [.25B4.0020.0002] -2DC3 ; [.25B5.0020.0002] -2DC4 ; [.25B6.0020.0002] -2DC5 ; [.25B7.0020.0002] -2DC6 ; [.25B8.0020.0002] -2DC8 ; [.25B9.0020.0002] -2DC9 ; [.25BA.0020.0002] -2DCA ; [.25BB.0020.0002] -2DCB ; [.25BC.0020.0002] -2DCC ; [.25BD.0020.0002] -2DCD ; [.25BE.0020.0002] -2DCE ; [.25BF.0020.0002] -2DD0 ; [.25C0.0020.0002] -2DD1 ; [.25C1.0020.0002] -2DD2 ; [.25C2.0020.0002] -2DD3 ; [.25C3.0020.0002] -2DD4 ; [.25C4.0020.0002] -2DD5 ; [.25C5.0020.0002] -2DD6 ; [.25C6.0020.0002] -2DD8 ; [.25C7.0020.0002] -2DD9 ; [.25C8.0020.0002] -2DDA ; [.25C9.0020.0002] -2DDB ; [.25CA.0020.0002] -2DDC ; [.25CB.0020.0002] -2DDD ; [.25CC.0020.0002] -2DDE ; [.25CD.0020.0002] -0950 ; [.25CE.0020.0002] -A8FD ; [.25CF.0020.0002] -0972 ; [.25D0.0020.0002] -0904 ; [.25D1.0020.0002] -0905 ; [.25D2.0020.0002] -0906 ; [.25D3.0020.0002] -0973 ; [.25D4.0020.0002] -0974 ; [.25D5.0020.0002] -0975 ; [.25D6.0020.0002] -0976 ; [.25D7.0020.0002] -0977 ; [.25D8.0020.0002] -0907 ; [.25D9.0020.0002] -0908 ; [.25DA.0020.0002] -0909 ; [.25DB.0020.0002] -090A ; [.25DC.0020.0002] -090B ; [.25DD.0020.0002] -0960 ; [.25DE.0020.0002] -090C ; [.25DF.0020.0002] -0961 ; [.25E0.0020.0002] -090D ; [.25E1.0020.0002] -090E ; [.25E2.0020.0002] -090F ; [.25E3.0020.0002] -0910 ; [.25E4.0020.0002] -0911 ; [.25E5.0020.0002] -0912 ; [.25E6.0020.0002] -0913 ; [.25E7.0020.0002] -0914 ; [.25E8.0020.0002] -0915 ; [.25E9.0020.0002] -0958 ; [.25E9.0020.0002][.0000.00BD.0002] -0916 ; [.25EA.0020.0002] -0959 ; [.25EA.0020.0002][.0000.00BD.0002] -0917 ; [.25EB.0020.0002] -095A ; [.25EB.0020.0002][.0000.00BD.0002] -097B ; [.25EC.0020.0002] -0918 ; [.25ED.0020.0002] -0919 ; [.25EE.0020.0002] -091A ; [.25EF.0020.0002] -091B ; [.25F0.0020.0002] -091C ; [.25F1.0020.0002] -095B ; [.25F1.0020.0002][.0000.00BD.0002] -0979 ; [.25F2.0020.0002] -097C ; [.25F3.0020.0002] -091D ; [.25F4.0020.0002] -091E ; [.25F5.0020.0002] -091F ; [.25F6.0020.0002] -0920 ; [.25F7.0020.0002] -0978 ; [.25F8.0020.0002] -0921 ; [.25F9.0020.0002] -095C ; [.25F9.0020.0002][.0000.00BD.0002] -097E ; [.25FA.0020.0002] -0922 ; [.25FB.0020.0002] -095D ; [.25FB.0020.0002][.0000.00BD.0002] -0923 ; [.25FC.0020.0002] -0924 ; [.25FD.0020.0002] -0925 ; [.25FE.0020.0002] -0926 ; [.25FF.0020.0002] -0927 ; [.2600.0020.0002] -0928 ; [.2601.0020.0002] -0929 ; [.2601.0020.0002][.0000.00BD.0002] -092A ; [.2602.0020.0002] -092B ; [.2603.0020.0002] -095E ; [.2603.0020.0002][.0000.00BD.0002] -092C ; [.2604.0020.0002] -097F ; [.2605.0020.0002] -092D ; [.2606.0020.0002] -092E ; [.2607.0020.0002] -092F ; [.2608.0020.0002] -095F ; [.2608.0020.0002][.0000.00BD.0002] -097A ; [.2609.0020.0002] -0930 ; [.260A.0020.0002] -0931 ; [.260A.0020.0002][.0000.00BD.0002] -0932 ; [.260B.0020.0002] -0933 ; [.260C.0020.0002] -0934 ; [.260C.0020.0002][.0000.00BD.0002] -0935 ; [.260D.0020.0002] -0936 ; [.260E.0020.0002] -0937 ; [.260F.0020.0002] -0938 ; [.2610.0020.0002] -0939 ; [.2611.0020.0002] -093D ; [.2612.0020.0002] -097D ; [.2613.0020.0002] -1CE9 ; [.2614.0020.0002] -1CEA ; [.2614.0020.0004] -1CEB ; [.2614.0020.0004] -1CEC ; [.2614.0020.0004] -1CEE ; [.2614.0020.0004] -1CEF ; [.2614.0020.0004] -1CF0 ; [.2614.0020.0004] -1CF1 ; [.2614.0020.0004] -1CF5 ; [.2615.0020.0002] -1CF6 ; [.2616.0020.0002] -A8F2 ; [.2617.0020.0002] -A8F3 ; [.2617.0020.0004] -A8F4 ; [.2617.0020.0004] -A8F5 ; [.2617.0020.0004] -A8F6 ; [.2617.0020.0004] -A8F7 ; [.2617.0020.0004] -A8FB ; [.2618.0020.0002] -093E ; [.2619.0020.0002] -093A ; [.261A.0020.0002] -093B ; [.261B.0020.0002] -094F ; [.261C.0020.0002] -0956 ; [.261D.0020.0002] -0957 ; [.261E.0020.0002] -093F ; [.261F.0020.0002] -0940 ; [.2620.0020.0002] -0941 ; [.2621.0020.0002] -0942 ; [.2622.0020.0002] -0943 ; [.2623.0020.0002] -0944 ; [.2624.0020.0002] -0962 ; [.2625.0020.0002] -0963 ; [.2626.0020.0002] -0945 ; [.2627.0020.0002] -0955 ; [.2628.0020.0002] -0946 ; [.2629.0020.0002] -0947 ; [.262A.0020.0002] -094E ; [.262B.0020.0002] -0948 ; [.262C.0020.0002] -0949 ; [.262D.0020.0002] -094A ; [.262E.0020.0002] -094B ; [.262F.0020.0002] -094C ; [.2630.0020.0002] -094D ; [.2631.0020.0002] -0980 ; [.2632.0020.0002] -0985 ; [.2633.0020.0002] -0986 ; [.2634.0020.0002] -0987 ; [.2635.0020.0002] -0988 ; [.2636.0020.0002] -0989 ; [.2637.0020.0002] -098A ; [.2638.0020.0002] -098B ; [.2639.0020.0002] -09E0 ; [.263A.0020.0002] -098C ; [.263B.0020.0002] -09E1 ; [.263C.0020.0002] -098F ; [.263D.0020.0002] -0990 ; [.263E.0020.0002] -0993 ; [.263F.0020.0002] -0994 ; [.2640.0020.0002] -0995 ; [.2641.0020.0002] -0996 ; [.2642.0020.0002] -0997 ; [.2643.0020.0002] -0998 ; [.2644.0020.0002] -0999 ; [.2645.0020.0002] -099A ; [.2646.0020.0002] -099B ; [.2647.0020.0002] -099C ; [.2648.0020.0002] -099D ; [.2649.0020.0002] -099E ; [.264A.0020.0002] -099F ; [.264B.0020.0002] -09A0 ; [.264C.0020.0002] -09A1 ; [.264D.0020.0002] -09DC ; [.264D.0020.0002][.0000.00BD.0002] -09A2 ; [.264E.0020.0002] -09DD ; [.264E.0020.0002][.0000.00BD.0002] -09A3 ; [.264F.0020.0002] -09A4 ; [.2650.0020.0002] -09CE ; [.2650.0020.0004][.2671.0020.0004] -09A5 ; [.2651.0020.0002] -09A6 ; [.2652.0020.0002] -09A7 ; [.2653.0020.0002] -09A8 ; [.2654.0020.0002] -09AA ; [.2655.0020.0002] -09AB ; [.2656.0020.0002] -09AC ; [.2657.0020.0002] -09AD ; [.2658.0020.0002] -09AE ; [.2659.0020.0002] -09AF ; [.265A.0020.0002] -09DF ; [.265A.0020.0002][.0000.00BD.0002] -09B0 ; [.265B.0020.0002] -09F0 ; [.265C.0020.0002] -09B2 ; [.265D.0020.0002] -09F1 ; [.265E.0020.0002] -09B6 ; [.265F.0020.0002] -09B7 ; [.2660.0020.0002] -09B8 ; [.2661.0020.0002] -09B9 ; [.2662.0020.0002] -09BD ; [.2663.0020.0002] -09BE ; [.2664.0020.0002] -09BF ; [.2665.0020.0002] -09C0 ; [.2666.0020.0002] -09C1 ; [.2667.0020.0002] -09C2 ; [.2668.0020.0002] -09C3 ; [.2669.0020.0002] -09C4 ; [.266A.0020.0002] -09E2 ; [.266B.0020.0002] -09E3 ; [.266C.0020.0002] -09C7 ; [.266D.0020.0002] -09C8 ; [.266E.0020.0002] -09CB ; [.266F.0020.0002] -09C7 09BE ; [.266F.0020.0002] -09CC ; [.2670.0020.0002] -09C7 09D7 ; [.2670.0020.0002] -09CD ; [.2671.0020.0002] -09D7 ; [.2672.0020.0002] -0A74 ; [.2673.0020.0002] -0A73 ; [.2674.0020.0002] -0A09 ; [.2675.0020.0002] -0A0A ; [.2676.0020.0002] -0A13 ; [.2677.0020.0002] -0A05 ; [.2678.0020.0002] -0A06 ; [.2679.0020.0002] -0A10 ; [.267A.0020.0002] -0A14 ; [.267B.0020.0002] -0A72 ; [.267C.0020.0002] -0A07 ; [.267D.0020.0002] -0A08 ; [.267E.0020.0002] -0A0F ; [.267F.0020.0002] -0A38 ; [.2680.0020.0002] -0A36 ; [.2680.0020.0002][.0000.00BD.0002] -0A39 ; [.2681.0020.0002] -0A51 ; [.2682.0020.0002] -0A15 ; [.2683.0020.0002] -0A16 ; [.2684.0020.0002] -0A59 ; [.2684.0020.0002][.0000.00BD.0002] -0A17 ; [.2685.0020.0002] -0A5A ; [.2685.0020.0002][.0000.00BD.0002] -0A18 ; [.2686.0020.0002] -0A19 ; [.2687.0020.0002] -0A1A ; [.2688.0020.0002] -0A1B ; [.2689.0020.0002] -0A1C ; [.268A.0020.0002] -0A5B ; [.268A.0020.0002][.0000.00BD.0002] -0A1D ; [.268B.0020.0002] -0A1E ; [.268C.0020.0002] -0A1F ; [.268D.0020.0002] -0A20 ; [.268E.0020.0002] -0A21 ; [.268F.0020.0002] -0A22 ; [.2690.0020.0002] -0A23 ; [.2691.0020.0002] -0A24 ; [.2692.0020.0002] -0A25 ; [.2693.0020.0002] -0A26 ; [.2694.0020.0002] -0A27 ; [.2695.0020.0002] -0A28 ; [.2696.0020.0002] -0A2A ; [.2697.0020.0002] -0A2B ; [.2698.0020.0002] -0A5E ; [.2698.0020.0002][.0000.00BD.0002] -0A2C ; [.2699.0020.0002] -0A2D ; [.269A.0020.0002] -0A2E ; [.269B.0020.0002] -0A2F ; [.269C.0020.0002] -0A75 ; [.269D.0020.0002] -0A30 ; [.269E.0020.0002] -0A32 ; [.269F.0020.0002] -0A33 ; [.269F.0020.0002][.0000.00BD.0002] -0A35 ; [.26A0.0020.0002] -0A5C ; [.26A1.0020.0002] -0A3E ; [.26A2.0020.0002] -0A3F ; [.26A3.0020.0002] -0A40 ; [.26A4.0020.0002] -0A41 ; [.26A5.0020.0002] -0A42 ; [.26A6.0020.0002] -0A47 ; [.26A7.0020.0002] -0A48 ; [.26A8.0020.0002] -0A4B ; [.26A9.0020.0002] -0A4C ; [.26AA.0020.0002] -0A4D ; [.26AB.0020.0002] -0AD0 ; [.26AC.0020.0002] -0A85 ; [.26AD.0020.0002] -0A86 ; [.26AE.0020.0002] -0A87 ; [.26AF.0020.0002] -0A88 ; [.26B0.0020.0002] -0A89 ; [.26B1.0020.0002] -0A8A ; [.26B2.0020.0002] -0A8B ; [.26B3.0020.0002] -0AE0 ; [.26B4.0020.0002] -0A8C ; [.26B5.0020.0002] -0AE1 ; [.26B6.0020.0002] -0A8D ; [.26B7.0020.0002] -0A8F ; [.26B8.0020.0002] -0A90 ; [.26B9.0020.0002] -0A91 ; [.26BA.0020.0002] -0A93 ; [.26BB.0020.0002] -0A94 ; [.26BC.0020.0002] -0A95 ; [.26BD.0020.0002] -0A96 ; [.26BE.0020.0002] -0A97 ; [.26BF.0020.0002] -0A98 ; [.26C0.0020.0002] -0A99 ; [.26C1.0020.0002] -0A9A ; [.26C2.0020.0002] -0A9B ; [.26C3.0020.0002] -0A9C ; [.26C4.0020.0002] -0AF9 ; [.26C5.0020.0002] -0A9D ; [.26C6.0020.0002] -0A9E ; [.26C7.0020.0002] -0A9F ; [.26C8.0020.0002] -0AA0 ; [.26C9.0020.0002] -0AA1 ; [.26CA.0020.0002] -0AA2 ; [.26CB.0020.0002] -0AA3 ; [.26CC.0020.0002] -0AA4 ; [.26CD.0020.0002] -0AA5 ; [.26CE.0020.0002] -0AA6 ; [.26CF.0020.0002] -0AA7 ; [.26D0.0020.0002] -0AA8 ; [.26D1.0020.0002] -0AAA ; [.26D2.0020.0002] -0AAB ; [.26D3.0020.0002] -0AAC ; [.26D4.0020.0002] -0AAD ; [.26D5.0020.0002] -0AAE ; [.26D6.0020.0002] -0AAF ; [.26D7.0020.0002] -0AB0 ; [.26D8.0020.0002] -0AB2 ; [.26D9.0020.0002] -0AB5 ; [.26DA.0020.0002] -0AB6 ; [.26DB.0020.0002] -0AB7 ; [.26DC.0020.0002] -0AB8 ; [.26DD.0020.0002] -0AB9 ; [.26DE.0020.0002] -0AB3 ; [.26DF.0020.0002] -0ABD ; [.26E0.0020.0002] -0ABE ; [.26E1.0020.0002] -0ABF ; [.26E2.0020.0002] -0AC0 ; [.26E3.0020.0002] -0AC1 ; [.26E4.0020.0002] -0AC2 ; [.26E5.0020.0002] -0AC3 ; [.26E6.0020.0002] -0AC4 ; [.26E7.0020.0002] -0AE2 ; [.26E8.0020.0002] -0AE3 ; [.26E9.0020.0002] -0AC5 ; [.26EA.0020.0002] -0AC7 ; [.26EB.0020.0002] -0AC8 ; [.26EC.0020.0002] -0AC9 ; [.26ED.0020.0002] -0ACB ; [.26EE.0020.0002] -0ACC ; [.26EF.0020.0002] -0ACD ; [.26F0.0020.0002] -0B05 ; [.26F1.0020.0002] -0B06 ; [.26F2.0020.0002] -0B07 ; [.26F3.0020.0002] -0B08 ; [.26F4.0020.0002] -0B09 ; [.26F5.0020.0002] -0B0A ; [.26F6.0020.0002] -0B0B ; [.26F7.0020.0002] -0B60 ; [.26F8.0020.0002] -0B0C ; [.26F9.0020.0002] -0B61 ; [.26FA.0020.0002] -0B0F ; [.26FB.0020.0002] -0B10 ; [.26FC.0020.0002] -0B13 ; [.26FD.0020.0002] -0B14 ; [.26FE.0020.0002] -0B15 ; [.26FF.0020.0002] -0B16 ; [.2700.0020.0002] -0B17 ; [.2701.0020.0002] -0B18 ; [.2702.0020.0002] -0B19 ; [.2703.0020.0002] -0B1A ; [.2704.0020.0002] -0B1B ; [.2705.0020.0002] -0B1C ; [.2706.0020.0002] -0B1D ; [.2707.0020.0002] -0B1E ; [.2708.0020.0002] -0B1F ; [.2709.0020.0002] -0B20 ; [.270A.0020.0002] -0B21 ; [.270B.0020.0002] -0B5C ; [.270B.0020.0002][.0000.00BD.0002] -0B22 ; [.270C.0020.0002] -0B5D ; [.270C.0020.0002][.0000.00BD.0002] -0B23 ; [.270D.0020.0002] -0B24 ; [.270E.0020.0002] -0B25 ; [.270F.0020.0002] -0B26 ; [.2710.0020.0002] -0B27 ; [.2711.0020.0002] -0B28 ; [.2712.0020.0002] -0B2A ; [.2713.0020.0002] -0B2B ; [.2714.0020.0002] -0B2C ; [.2715.0020.0002] -0B2D ; [.2716.0020.0002] -0B2E ; [.2717.0020.0002] -0B2F ; [.2718.0020.0002] -0B5F ; [.2719.0020.0002] -0B30 ; [.271A.0020.0002] -0B32 ; [.271B.0020.0002] -0B33 ; [.271C.0020.0002] -0B35 ; [.271D.0020.0002] -0B71 ; [.271E.0020.0002] -0B36 ; [.271F.0020.0002] -0B37 ; [.2720.0020.0002] -0B38 ; [.2721.0020.0002] -0B39 ; [.2722.0020.0002] -0B3D ; [.2723.0020.0002] -0B3E ; [.2724.0020.0002] -0B3F ; [.2725.0020.0002] -0B40 ; [.2726.0020.0002] -0B41 ; [.2727.0020.0002] -0B42 ; [.2728.0020.0002] -0B43 ; [.2729.0020.0002] -0B44 ; [.272A.0020.0002] -0B62 ; [.272B.0020.0002] -0B63 ; [.272C.0020.0002] -0B47 ; [.272D.0020.0002] -0B48 ; [.272E.0020.0002] -0B47 0B56 ; [.272E.0020.0002] -0B4B ; [.272F.0020.0002] -0B47 0B3E ; [.272F.0020.0002] -0B4C ; [.2730.0020.0002] -0B47 0B57 ; [.2730.0020.0002] -0B4D ; [.2731.0020.0002] -0B56 ; [.2732.0020.0002] -0B57 ; [.2733.0020.0002] -0BD0 ; [.2734.0020.0002] -0B85 ; [.2735.0020.0002] -0B86 ; [.2736.0020.0002] -0B87 ; [.2737.0020.0002] -0B88 ; [.2738.0020.0002] -0B89 ; [.2739.0020.0002] -0B8A ; [.273A.0020.0002] -0B8E ; [.273B.0020.0002] -0B8F ; [.273C.0020.0002] -0B90 ; [.273D.0020.0002] -0B92 ; [.273E.0020.0002] -0B93 ; [.273F.0020.0002] -0B94 ; [.2740.0020.0002] -0B92 0BD7 ; [.2740.0020.0002] -0B83 ; [.2741.0020.0002] -0B95 ; [.2742.0020.0002] -0B99 ; [.2743.0020.0002] -0B9A ; [.2744.0020.0002] -0B9E ; [.2745.0020.0002] -0B9F ; [.2746.0020.0002] -0BA3 ; [.2747.0020.0002] -0BA4 ; [.2748.0020.0002] -0BA8 ; [.2749.0020.0002] -0BAA ; [.274A.0020.0002] -0BAE ; [.274B.0020.0002] -0BAF ; [.274C.0020.0002] -0BB0 ; [.274D.0020.0002] -0BB2 ; [.274E.0020.0002] -0BB5 ; [.274F.0020.0002] -0BB4 ; [.2750.0020.0002] -0BB3 ; [.2751.0020.0002] -0BB1 ; [.2752.0020.0002] -0BA9 ; [.2753.0020.0002] -0B9C ; [.2754.0020.0002] -0BB6 ; [.2755.0020.0002] -0BB7 ; [.2756.0020.0002] -0BB8 ; [.2757.0020.0002] -0BB9 ; [.2758.0020.0002] -0BBE ; [.2759.0020.0002] -0BBF ; [.275A.0020.0002] -0BC0 ; [.275B.0020.0002] -0BC1 ; [.275C.0020.0002] -0BC2 ; [.275D.0020.0002] -0BC6 ; [.275E.0020.0002] -0BC7 ; [.275F.0020.0002] -0BC8 ; [.2760.0020.0002] -0BCA ; [.2761.0020.0002] -0BC6 0BBE ; [.2761.0020.0002] -0BCB ; [.2762.0020.0002] -0BC7 0BBE ; [.2762.0020.0002] -0BCC ; [.2763.0020.0002] -0BC6 0BD7 ; [.2763.0020.0002] -0BCD ; [.2764.0020.0002] -0BD7 ; [.2765.0020.0002] -0C05 ; [.2766.0020.0002] -0C06 ; [.2767.0020.0002] -0C07 ; [.2768.0020.0002] -0C08 ; [.2769.0020.0002] -0C09 ; [.276A.0020.0002] -0C0A ; [.276B.0020.0002] -0C0B ; [.276C.0020.0002] -0C60 ; [.276D.0020.0002] -0C0C ; [.276E.0020.0002] -0C61 ; [.276F.0020.0002] -0C0E ; [.2770.0020.0002] -0C0F ; [.2771.0020.0002] -0C10 ; [.2772.0020.0002] -0C12 ; [.2773.0020.0002] -0C13 ; [.2774.0020.0002] -0C14 ; [.2775.0020.0002] -0C15 ; [.2776.0020.0002] -0C16 ; [.2777.0020.0002] -0C17 ; [.2778.0020.0002] -0C18 ; [.2779.0020.0002] -0C19 ; [.277A.0020.0002] -0C1A ; [.277B.0020.0002] -0C58 ; [.277C.0020.0002] -0C1B ; [.277D.0020.0002] -0C1C ; [.277E.0020.0002] -0C59 ; [.277F.0020.0002] -0C1D ; [.2780.0020.0002] -0C1E ; [.2781.0020.0002] -0C1F ; [.2782.0020.0002] -0C20 ; [.2783.0020.0002] -0C21 ; [.2784.0020.0002] -0C22 ; [.2785.0020.0002] -0C23 ; [.2786.0020.0002] -0C24 ; [.2787.0020.0002] -0C25 ; [.2788.0020.0002] -0C26 ; [.2789.0020.0002] -0C27 ; [.278A.0020.0002] -0C28 ; [.278B.0020.0002] -0C2A ; [.278C.0020.0002] -0C2B ; [.278D.0020.0002] -0C2C ; [.278E.0020.0002] -0C2D ; [.278F.0020.0002] -0C2E ; [.2790.0020.0002] -0C2F ; [.2791.0020.0002] -0C30 ; [.2792.0020.0002] -0C31 ; [.2793.0020.0002] -0C32 ; [.2794.0020.0002] -0C35 ; [.2795.0020.0002] -0C36 ; [.2796.0020.0002] -0C37 ; [.2797.0020.0002] -0C38 ; [.2798.0020.0002] -0C39 ; [.2799.0020.0002] -0C33 ; [.279A.0020.0002] -0C34 ; [.279B.0020.0002] -0C5A ; [.279C.0020.0002] -0C3D ; [.279D.0020.0002] -0C3E ; [.279E.0020.0002] -0C3F ; [.279F.0020.0002] -0C40 ; [.27A0.0020.0002] -0C41 ; [.27A1.0020.0002] -0C42 ; [.27A2.0020.0002] -0C43 ; [.27A3.0020.0002] -0C44 ; [.27A4.0020.0002] -0C62 ; [.27A5.0020.0002] -0C63 ; [.27A6.0020.0002] -0C46 ; [.27A7.0020.0002] -0C47 ; [.27A8.0020.0002] -0C48 ; [.27A9.0020.0002] -0C46 0C56 ; [.27A9.0020.0002] -0C4A ; [.27AA.0020.0002] -0C4B ; [.27AB.0020.0002] -0C4C ; [.27AC.0020.0002] -0C4D ; [.27AD.0020.0002] -0C55 ; [.27AE.0020.0002] -0C56 ; [.27AF.0020.0002] -0C85 ; [.27B0.0020.0002] -0C86 ; [.27B1.0020.0002] -0C87 ; [.27B2.0020.0002] -0C88 ; [.27B3.0020.0002] -0C89 ; [.27B4.0020.0002] -0C8A ; [.27B5.0020.0002] -0C8B ; [.27B6.0020.0002] -0CE0 ; [.27B7.0020.0002] -0C8C ; [.27B8.0020.0002] -0CE1 ; [.27B9.0020.0002] -0C8E ; [.27BA.0020.0002] -0C8F ; [.27BB.0020.0002] -0C90 ; [.27BC.0020.0002] -0C92 ; [.27BD.0020.0002] -0C93 ; [.27BE.0020.0002] -0C94 ; [.27BF.0020.0002] -0C95 ; [.27C0.0020.0002] -0C96 ; [.27C1.0020.0002] -0C97 ; [.27C2.0020.0002] -0C98 ; [.27C3.0020.0002] -0C99 ; [.27C4.0020.0002] -0C9A ; [.27C5.0020.0002] -0C9B ; [.27C6.0020.0002] -0C9C ; [.27C7.0020.0002] -0C9D ; [.27C8.0020.0002] -0C9E ; [.27C9.0020.0002] -0C9F ; [.27CA.0020.0002] -0CA0 ; [.27CB.0020.0002] -0CA1 ; [.27CC.0020.0002] -0CA2 ; [.27CD.0020.0002] -0CA3 ; [.27CE.0020.0002] -0CA4 ; [.27CF.0020.0002] -0CA5 ; [.27D0.0020.0002] -0CA6 ; [.27D1.0020.0002] -0CA7 ; [.27D2.0020.0002] -0CA8 ; [.27D3.0020.0002] -0CAA ; [.27D4.0020.0002] -0CAB ; [.27D5.0020.0002] -0CAC ; [.27D6.0020.0002] -0CAD ; [.27D7.0020.0002] -0CAE ; [.27D8.0020.0002] -0CAF ; [.27D9.0020.0002] -0CB0 ; [.27DA.0020.0002] -0CB1 ; [.27DB.0020.0002] -0CB2 ; [.27DC.0020.0002] -0CB5 ; [.27DD.0020.0002] -0CB6 ; [.27DE.0020.0002] -0CB7 ; [.27DF.0020.0002] -0CB8 ; [.27E0.0020.0002] -0CB9 ; [.27E1.0020.0002] -0CB3 ; [.27E2.0020.0002] -0CDE ; [.27E3.0020.0002] -0CBD ; [.27E4.0020.0002] -0CF1 ; [.27E5.0020.0002] -0CF2 ; [.27E6.0020.0002] -0CBE ; [.27E7.0020.0002] -0CBF ; [.27E8.0020.0002] -0CC0 ; [.27E9.0020.0002] -0CBF 0CD5 ; [.27E9.0020.0002] -0CC1 ; [.27EA.0020.0002] -0CC2 ; [.27EB.0020.0002] -0CC3 ; [.27EC.0020.0002] -0CC4 ; [.27ED.0020.0002] -0CE2 ; [.27EE.0020.0002] -0CE3 ; [.27EF.0020.0002] -0CC6 ; [.27F0.0020.0002] -0CC7 ; [.27F1.0020.0002] -0CC6 0CD5 ; [.27F1.0020.0002] -0CC8 ; [.27F2.0020.0002] -0CC6 0CD6 ; [.27F2.0020.0002] -0CCA ; [.27F3.0020.0002] -0CC6 0CC2 ; [.27F3.0020.0002] -0CCB ; [.27F4.0020.0002] -0CC6 0CC2 0CD5 ; [.27F4.0020.0002] -0CCA 0CD5 ; [.27F4.0020.0002] -0CCC ; [.27F5.0020.0002] -0CCD ; [.27F6.0020.0002] -0CD5 ; [.27F7.0020.0002] -0CD6 ; [.27F8.0020.0002] -0D05 ; [.27F9.0020.0002] -0D06 ; [.27FA.0020.0002] -0D07 ; [.27FB.0020.0002] -0D08 ; [.27FC.0020.0002] -0D5F ; [.27FD.0020.0002] -0D09 ; [.27FE.0020.0002] -0D0A ; [.27FF.0020.0002] -0D0B ; [.2800.0020.0002] -0D60 ; [.2801.0020.0002] -0D0C ; [.2802.0020.0002] -0D61 ; [.2803.0020.0002] -0D0E ; [.2804.0020.0002] -0D0F ; [.2805.0020.0002] -0D10 ; [.2806.0020.0002] -0D12 ; [.2807.0020.0002] -0D13 ; [.2808.0020.0002] -0D14 ; [.2809.0020.0002] -0D15 ; [.280A.0020.0002] -0D7F ; [.280A.0020.0004][.2841.0020.0004] -0D16 ; [.280B.0020.0002] -0D17 ; [.280C.0020.0002] -0D18 ; [.280D.0020.0002] -0D19 ; [.280E.0020.0002] -0D1A ; [.280F.0020.0002] -0D1B ; [.2810.0020.0002] -0D1C ; [.2811.0020.0002] -0D1D ; [.2812.0020.0002] -0D1E ; [.2813.0020.0002] -0D1F ; [.2814.0020.0002] -0D20 ; [.2815.0020.0002] -0D21 ; [.2816.0020.0002] -0D22 ; [.2817.0020.0002] -0D23 ; [.2818.0020.0002] -0D7A ; [.2818.0020.0004][.2841.0020.0004] -0D24 ; [.2819.0020.0002] -0D25 ; [.281A.0020.0002] -0D26 ; [.281B.0020.0002] -0D27 ; [.281C.0020.0002] -0D28 ; [.281D.0020.0002] -0D7B ; [.281D.0020.0004][.2841.0020.0004] -0D29 ; [.281E.0020.0002] -0D2A ; [.281F.0020.0002] -0D2B ; [.2820.0020.0002] -0D2C ; [.2821.0020.0002] -0D2D ; [.2822.0020.0002] -0D2E ; [.2823.0020.0002] -0D2F ; [.2824.0020.0002] -0D30 ; [.2825.0020.0002] -0D4E ; [.2825.0020.0004][.2841.0020.0004] -0D7C ; [.2825.0020.0004][.2841.0020.0004] -0D32 ; [.2826.0020.0002] -0D7D ; [.2826.0020.0004][.2841.0020.0004] -0D35 ; [.2827.0020.0002] -0D36 ; [.2828.0020.0002] -0D37 ; [.2829.0020.0002] -0D38 ; [.282A.0020.0002] -0D39 ; [.282B.0020.0002] -0D33 ; [.282C.0020.0002] -0D7E ; [.282C.0020.0004][.2841.0020.0004] -0D34 ; [.282D.0020.0002] -0D31 ; [.282E.0020.0002] -0D3A ; [.282F.0020.0002] -0D3D ; [.2830.0020.0002] -0D3E ; [.2831.0020.0002] -0D3F ; [.2832.0020.0002] -0D40 ; [.2833.0020.0002] -0D41 ; [.2834.0020.0002] -0D42 ; [.2835.0020.0002] -0D43 ; [.2836.0020.0002] -0D44 ; [.2837.0020.0002] -0D62 ; [.2838.0020.0002] -0D63 ; [.2839.0020.0002] -0D46 ; [.283A.0020.0002] -0D47 ; [.283B.0020.0002] -0D48 ; [.283C.0020.0002] -0D4A ; [.283D.0020.0002] -0D46 0D3E ; [.283D.0020.0002] -0D4B ; [.283E.0020.0002] -0D47 0D3E ; [.283E.0020.0002] -0D4C ; [.283F.0020.0002] -0D46 0D57 ; [.283F.0020.0002] -0D57 ; [.2840.0020.0002] -0D4D ; [.2841.0020.0002] -0D85 ; [.2842.0020.0002] -0D86 ; [.2843.0020.0002] -0D87 ; [.2844.0020.0002] -0D88 ; [.2845.0020.0002] -0D89 ; [.2846.0020.0002] -0D8A ; [.2847.0020.0002] -0D8B ; [.2848.0020.0002] -0D8C ; [.2849.0020.0002] -0D8D ; [.284A.0020.0002] -0D8E ; [.284B.0020.0002] -0D8F ; [.284C.0020.0002] -0D90 ; [.284D.0020.0002] -0D91 ; [.284E.0020.0002] -0D92 ; [.284F.0020.0002] -0D93 ; [.2850.0020.0002] -0D94 ; [.2851.0020.0002] -0D95 ; [.2852.0020.0002] -0D96 ; [.2853.0020.0002] -0D9A ; [.2854.0020.0002] -0D9B ; [.2855.0020.0002] -0D9C ; [.2856.0020.0002] -0D9D ; [.2857.0020.0002] -0D9E ; [.2858.0020.0002] -0D9F ; [.2859.0020.0002] -0DA0 ; [.285A.0020.0002] -0DA1 ; [.285B.0020.0002] -0DA2 ; [.285C.0020.0002] -0DA3 ; [.285D.0020.0002] -0DA4 ; [.285E.0020.0002] -0DA5 ; [.285F.0020.0002] -0DA6 ; [.2860.0020.0002] -0DA7 ; [.2861.0020.0002] -0DA8 ; [.2862.0020.0002] -0DA9 ; [.2863.0020.0002] -0DAA ; [.2864.0020.0002] -0DAB ; [.2865.0020.0002] -0DAC ; [.2866.0020.0002] -0DAD ; [.2867.0020.0002] -0DAE ; [.2868.0020.0002] -0DAF ; [.2869.0020.0002] -0DB0 ; [.286A.0020.0002] -0DB1 ; [.286B.0020.0002] -0DB3 ; [.286C.0020.0002] -0DB4 ; [.286D.0020.0002] -0DB5 ; [.286E.0020.0002] -0DB6 ; [.286F.0020.0002] -0DB7 ; [.2870.0020.0002] -0DB8 ; [.2871.0020.0002] -0DB9 ; [.2872.0020.0002] -0DBA ; [.2873.0020.0002] -0DBB ; [.2874.0020.0002] -0DBD ; [.2875.0020.0002] -0DC0 ; [.2876.0020.0002] -0DC1 ; [.2877.0020.0002] -0DC2 ; [.2878.0020.0002] -0DC3 ; [.2879.0020.0002] -0DC4 ; [.287A.0020.0002] -0DC5 ; [.287B.0020.0002] -0DC6 ; [.287C.0020.0002] -0DCF ; [.287D.0020.0002] -0DD0 ; [.287E.0020.0002] -0DD1 ; [.287F.0020.0002] -0DD2 ; [.2880.0020.0002] -0DD3 ; [.2881.0020.0002] -0DD4 ; [.2882.0020.0002] -0DD6 ; [.2883.0020.0002] -0DD8 ; [.2884.0020.0002] -0DF2 ; [.2885.0020.0002] -0DDF ; [.2886.0020.0002] -0DF3 ; [.2887.0020.0002] -0DD9 ; [.2888.0020.0002] -0DDA ; [.2889.0020.0002] -0DD9 0DCA ; [.2889.0020.0002] -0DDB ; [.288A.0020.0002] -0DDC ; [.288B.0020.0002] -0DD9 0DCF ; [.288B.0020.0002] -0DDD ; [.288C.0020.0002] -0DD9 0DCF 0DCA ; [.288C.0020.0002] -0DDC 0DCA ; [.288C.0020.0002] -0DDE ; [.288D.0020.0002] -0DD9 0DDF ; [.288D.0020.0002] -0DCA ; [.288E.0020.0002] -AAF2 ; [.288F.0020.0002] -ABC0 ; [.2890.0020.0002] -ABC1 ; [.2891.0020.0002] -ABC2 ; [.2892.0020.0002] -ABC3 ; [.2893.0020.0002] -ABC4 ; [.2894.0020.0002] -ABC5 ; [.2895.0020.0002] -ABC6 ; [.2896.0020.0002] -ABC7 ; [.2897.0020.0002] -ABC8 ; [.2898.0020.0002] -ABC9 ; [.2899.0020.0002] -ABCA ; [.289A.0020.0002] -ABCB ; [.289B.0020.0002] -ABCC ; [.289C.0020.0002] -ABCD ; [.289D.0020.0002] -ABCE ; [.289E.0020.0002] -ABCF ; [.289F.0020.0002] -ABD0 ; [.28A0.0020.0002] -ABD1 ; [.28A1.0020.0002] -ABD2 ; [.28A2.0020.0002] -ABD3 ; [.28A3.0020.0002] -ABD4 ; [.28A4.0020.0002] -ABD5 ; [.28A5.0020.0002] -ABD6 ; [.28A6.0020.0002] -ABD7 ; [.28A7.0020.0002] -ABD8 ; [.28A8.0020.0002] -ABD9 ; [.28A9.0020.0002] -ABDA ; [.28AA.0020.0002] -AAE0 ; [.28AB.0020.0002] -AAE1 ; [.28AC.0020.0002] -AAE2 ; [.28AD.0020.0002] -AAE3 ; [.28AE.0020.0002] -AAE4 ; [.28AF.0020.0002] -AAE5 ; [.28B0.0020.0002] -AAE6 ; [.28B1.0020.0002] -AAE7 ; [.28B2.0020.0002] -AAE8 ; [.28B3.0020.0002] -AAE9 ; [.28B4.0020.0002] -AAEA ; [.28B5.0020.0002] -ABE3 ; [.28B6.0020.0002] -ABE4 ; [.28B7.0020.0002] -ABE5 ; [.28B8.0020.0002] -ABE6 ; [.28B9.0020.0002] -ABE7 ; [.28BA.0020.0002] -ABE8 ; [.28BB.0020.0002] -ABE9 ; [.28BC.0020.0002] -ABEA ; [.28BD.0020.0002] -AAEB ; [.28BE.0020.0002] -AAEC ; [.28BF.0020.0002] -AAED ; [.28C0.0020.0002] -AAEE ; [.28C1.0020.0002] -AAEF ; [.28C2.0020.0002] -AAF5 ; [.28C3.0020.0002] -ABDB ; [.28C4.0020.0002] -ABDC ; [.28C5.0020.0002] -ABDD ; [.28C6.0020.0002] -ABDE ; [.28C7.0020.0002] -ABDF ; [.28C8.0020.0002] -ABE0 ; [.28C9.0020.0002] -ABE1 ; [.28CA.0020.0002] -ABE2 ; [.28CB.0020.0002] -ABED ; [.28CC.0020.0002] -AAF6 ; [.28CD.0020.0002] -A800 ; [.28CE.0020.0002] -A801 ; [.28CF.0020.0002] -A802 ; [.28D0.0020.0002] -A803 ; [.28D1.0020.0002] -A804 ; [.28D2.0020.0002] -A805 ; [.28D3.0020.0002] -A806 ; [.28D4.0020.0002] -A807 ; [.28D5.0020.0002] -A808 ; [.28D6.0020.0002] -A809 ; [.28D7.0020.0002] -A80A ; [.28D8.0020.0002] -A80C ; [.28D9.0020.0002] -A80D ; [.28DA.0020.0002] -A80E ; [.28DB.0020.0002] -A80F ; [.28DC.0020.0002] -A810 ; [.28DD.0020.0002] -A811 ; [.28DE.0020.0002] -A812 ; [.28DF.0020.0002] -A813 ; [.28E0.0020.0002] -A814 ; [.28E1.0020.0002] -A815 ; [.28E2.0020.0002] -A816 ; [.28E3.0020.0002] -A817 ; [.28E4.0020.0002] -A818 ; [.28E5.0020.0002] -A819 ; [.28E6.0020.0002] -A81A ; [.28E7.0020.0002] -A81B ; [.28E8.0020.0002] -A81C ; [.28E9.0020.0002] -A81D ; [.28EA.0020.0002] -A81E ; [.28EB.0020.0002] -A81F ; [.28EC.0020.0002] -A820 ; [.28ED.0020.0002] -A821 ; [.28EE.0020.0002] -A822 ; [.28EF.0020.0002] -A823 ; [.28F0.0020.0002] -A824 ; [.28F1.0020.0002] -A825 ; [.28F2.0020.0002] -A826 ; [.28F3.0020.0002] -A827 ; [.28F4.0020.0002] -A882 ; [.28F5.0020.0002] -A883 ; [.28F6.0020.0002] -A884 ; [.28F7.0020.0002] -A885 ; [.28F8.0020.0002] -A886 ; [.28F9.0020.0002] -A887 ; [.28FA.0020.0002] -A888 ; [.28FB.0020.0002] -A889 ; [.28FC.0020.0002] -A88A ; [.28FD.0020.0002] -A88B ; [.28FE.0020.0002] -A88C ; [.28FF.0020.0002] -A88D ; [.2900.0020.0002] -A88E ; [.2901.0020.0002] -A88F ; [.2902.0020.0002] -A890 ; [.2903.0020.0002] -A891 ; [.2904.0020.0002] -A892 ; [.2905.0020.0002] -A893 ; [.2906.0020.0002] -A894 ; [.2907.0020.0002] -A895 ; [.2908.0020.0002] -A896 ; [.2909.0020.0002] -A897 ; [.290A.0020.0002] -A898 ; [.290B.0020.0002] -A899 ; [.290C.0020.0002] -A89A ; [.290D.0020.0002] -A89B ; [.290E.0020.0002] -A89C ; [.290F.0020.0002] -A89D ; [.2910.0020.0002] -A89E ; [.2911.0020.0002] -A89F ; [.2912.0020.0002] -A8A0 ; [.2913.0020.0002] -A8A1 ; [.2914.0020.0002] -A8A2 ; [.2915.0020.0002] -A8A3 ; [.2916.0020.0002] -A8A4 ; [.2917.0020.0002] -A8A5 ; [.2918.0020.0002] -A8A6 ; [.2919.0020.0002] -A8A7 ; [.291A.0020.0002] -A8A8 ; [.291B.0020.0002] -A8A9 ; [.291C.0020.0002] -A8AA ; [.291D.0020.0002] -A8AB ; [.291E.0020.0002] -A8AC ; [.291F.0020.0002] -A8AD ; [.2920.0020.0002] -A8AE ; [.2921.0020.0002] -A8AF ; [.2922.0020.0002] -A8B0 ; [.2923.0020.0002] -A8B1 ; [.2924.0020.0002] -A8B2 ; [.2925.0020.0002] -A8B3 ; [.2926.0020.0002] -A8B4 ; [.2927.0020.0002] -A8B5 ; [.2928.0020.0002] -A8B6 ; [.2929.0020.0002] -A8B7 ; [.292A.0020.0002] -A8B8 ; [.292B.0020.0002] -A8B9 ; [.292C.0020.0002] -A8BA ; [.292D.0020.0002] -A8BB ; [.292E.0020.0002] -A8BC ; [.292F.0020.0002] -A8BD ; [.2930.0020.0002] -A8BE ; [.2931.0020.0002] -A8BF ; [.2932.0020.0002] -A8C0 ; [.2933.0020.0002] -A8C1 ; [.2934.0020.0002] -A8C2 ; [.2935.0020.0002] -A8C3 ; [.2936.0020.0002] -A8C4 ; [.2937.0020.0002] -11083 ; [.2938.0020.0002] -11084 ; [.2939.0020.0002] -11085 ; [.293A.0020.0002] -11086 ; [.293B.0020.0002] -11087 ; [.293C.0020.0002] -11088 ; [.293D.0020.0002] -11089 ; [.293E.0020.0002] -1108A ; [.293F.0020.0002] -1108B ; [.2940.0020.0002] -1108C ; [.2941.0020.0002] -1108D ; [.2942.0020.0002] -1108E ; [.2943.0020.0002] -1108F ; [.2944.0020.0002] -11090 ; [.2945.0020.0002] -11091 ; [.2946.0020.0002] -11092 ; [.2947.0020.0002] -11093 ; [.2948.0020.0002] -11094 ; [.2949.0020.0002] -11095 ; [.294A.0020.0002] -11096 ; [.294B.0020.0002] -11097 ; [.294C.0020.0002] -11098 ; [.294D.0020.0002] -11099 ; [.294E.0020.0002] -1109A ; [.294E.0020.0002][.0000.00BD.0002] -1109B ; [.294F.0020.0002] -1109C ; [.294F.0020.0002][.0000.00BD.0002] -1109D ; [.2950.0020.0002] -1109E ; [.2951.0020.0002] -1109F ; [.2952.0020.0002] -110A0 ; [.2953.0020.0002] -110A1 ; [.2954.0020.0002] -110A2 ; [.2955.0020.0002] -110A3 ; [.2956.0020.0002] -110A4 ; [.2957.0020.0002] -110A5 ; [.2958.0020.0002] -110AB ; [.2958.0020.0002][.0000.00BD.0002] -110A6 ; [.2959.0020.0002] -110A7 ; [.295A.0020.0002] -110A8 ; [.295B.0020.0002] -110A9 ; [.295C.0020.0002] -110AA ; [.295D.0020.0002] -110AC ; [.295E.0020.0002] -110AD ; [.295F.0020.0002] -110AE ; [.2960.0020.0002] -110AF ; [.2961.0020.0002] -110B0 ; [.2962.0020.0002] -110B1 ; [.2963.0020.0002] -110B2 ; [.2964.0020.0002] -110B3 ; [.2965.0020.0002] -110B4 ; [.2966.0020.0002] -110B5 ; [.2967.0020.0002] -110B6 ; [.2968.0020.0002] -110B7 ; [.2969.0020.0002] -110B8 ; [.296A.0020.0002] -110B9 ; [.296B.0020.0002] -11150 ; [.296C.0020.0002] -11151 ; [.296D.0020.0002] -11152 ; [.296E.0020.0002] -11153 ; [.296F.0020.0002] -11154 ; [.2970.0020.0002] -11155 ; [.2971.0020.0002] -11156 ; [.2972.0020.0002] -11157 ; [.2973.0020.0002] -11158 ; [.2974.0020.0002] -11159 ; [.2975.0020.0002] -1115A ; [.2976.0020.0002] -1115B ; [.2977.0020.0002] -1115C ; [.2978.0020.0002] -1115D ; [.2979.0020.0002] -1115E ; [.297A.0020.0002] -1115F ; [.297B.0020.0002] -11160 ; [.297C.0020.0002] -11161 ; [.297D.0020.0002] -11162 ; [.297E.0020.0002] -11163 ; [.297F.0020.0002] -11164 ; [.2980.0020.0002] -11165 ; [.2981.0020.0002] -11166 ; [.2982.0020.0002] -11167 ; [.2983.0020.0002] -11168 ; [.2984.0020.0002] -11169 ; [.2985.0020.0002] -1116A ; [.2986.0020.0002] -1116B ; [.2987.0020.0002] -1116C ; [.2988.0020.0002] -1116D ; [.2989.0020.0002] -1116E ; [.298A.0020.0002] -1116F ; [.298B.0020.0002] -11176 ; [.298C.0020.0002] -11170 ; [.298D.0020.0002] -11171 ; [.298E.0020.0002] -11172 ; [.298F.0020.0002] -111C4 ; [.2990.0020.0002] -111DA ; [.2991.0020.0002] -11183 ; [.2992.0020.0002] -11184 ; [.2993.0020.0002] -11185 ; [.2994.0020.0002] -11186 ; [.2995.0020.0002] -11187 ; [.2996.0020.0002] -11188 ; [.2997.0020.0002] -11189 ; [.2998.0020.0002] -1118A ; [.2999.0020.0002] -1118B ; [.299A.0020.0002] -1118C ; [.299B.0020.0002] -1118D ; [.299C.0020.0002] -1118E ; [.299D.0020.0002] -1118F ; [.299E.0020.0002] -11190 ; [.299F.0020.0002] -11191 ; [.29A0.0020.0002] -11192 ; [.29A1.0020.0002] -11193 ; [.29A2.0020.0002] -11194 ; [.29A3.0020.0002] -11195 ; [.29A4.0020.0002] -11196 ; [.29A5.0020.0002] -11197 ; [.29A6.0020.0002] -11198 ; [.29A7.0020.0002] -11199 ; [.29A8.0020.0002] -1119A ; [.29A9.0020.0002] -1119B ; [.29AA.0020.0002] -1119C ; [.29AB.0020.0002] -1119D ; [.29AC.0020.0002] -1119E ; [.29AD.0020.0002] -1119F ; [.29AE.0020.0002] -111A0 ; [.29AF.0020.0002] -111A1 ; [.29B0.0020.0002] -111A2 ; [.29B1.0020.0002] -111A3 ; [.29B2.0020.0002] -111A4 ; [.29B3.0020.0002] -111A5 ; [.29B4.0020.0002] -111A6 ; [.29B5.0020.0002] -111A7 ; [.29B6.0020.0002] -111A8 ; [.29B7.0020.0002] -111A9 ; [.29B8.0020.0002] -111AA ; [.29B9.0020.0002] -111AB ; [.29BA.0020.0002] -111AC ; [.29BB.0020.0002] -111AD ; [.29BC.0020.0002] -111AE ; [.29BD.0020.0002] -111AF ; [.29BE.0020.0002] -111B0 ; [.29BF.0020.0002] -111B1 ; [.29C0.0020.0002] -111B2 ; [.29C1.0020.0002] -111C1 ; [.29C2.0020.0002] -111C2 ; [.29C3.0020.0002] -111C3 ; [.29C4.0020.0002] -111DC ; [.29C5.0020.0002] -111B3 ; [.29C6.0020.0002] -111B4 ; [.29C7.0020.0002] -111B5 ; [.29C8.0020.0002] -111B6 ; [.29C9.0020.0002] -111B7 ; [.29CA.0020.0002] -111B8 ; [.29CB.0020.0002] -111B9 ; [.29CC.0020.0002] -111BA ; [.29CD.0020.0002] -111BB ; [.29CE.0020.0002] -111BC ; [.29CF.0020.0002] -111BD ; [.29D0.0020.0002] -111BE ; [.29D1.0020.0002] -111BF ; [.29D2.0020.0002] -111C0 ; [.29D3.0020.0002] -11200 ; [.29D4.0020.0002] -11201 ; [.29D5.0020.0002] -11202 ; [.29D6.0020.0002] -11203 ; [.29D7.0020.0002] -11204 ; [.29D8.0020.0002] -11205 ; [.29D9.0020.0002] -11206 ; [.29DA.0020.0002] -11207 ; [.29DB.0020.0002] -11208 ; [.29DC.0020.0002] -11209 ; [.29DD.0020.0002] -1120A ; [.29DE.0020.0002] -1120B ; [.29DF.0020.0002] -1120C ; [.29E0.0020.0002] -1120D ; [.29E1.0020.0002] -1120E ; [.29E2.0020.0002] -1120F ; [.29E3.0020.0002] -11210 ; [.29E4.0020.0002] -11211 ; [.29E5.0020.0002] -11213 ; [.29E6.0020.0002] -11214 ; [.29E7.0020.0002] -11215 ; [.29E8.0020.0002] -11216 ; [.29E9.0020.0002] -11217 ; [.29EA.0020.0002] -11218 ; [.29EB.0020.0002] -11219 ; [.29EC.0020.0002] -1121A ; [.29ED.0020.0002] -1121B ; [.29EE.0020.0002] -1121C ; [.29EF.0020.0002] -1121D ; [.29F0.0020.0002] -1121E ; [.29F1.0020.0002] -1121F ; [.29F2.0020.0002] -11220 ; [.29F3.0020.0002] -11221 ; [.29F4.0020.0002] -11222 ; [.29F5.0020.0002] -11223 ; [.29F6.0020.0002] -11224 ; [.29F7.0020.0002] -11225 ; [.29F8.0020.0002] -11226 ; [.29F9.0020.0002] -11227 ; [.29FA.0020.0002] -11228 ; [.29FB.0020.0002] -11229 ; [.29FC.0020.0002] -1122A ; [.29FD.0020.0002] -1122B ; [.29FE.0020.0002] -1122C ; [.29FF.0020.0002] -1122D ; [.2A00.0020.0002] -1122E ; [.2A01.0020.0002] -1122F ; [.2A02.0020.0002] -11230 ; [.2A03.0020.0002] -11231 ; [.2A04.0020.0002] -11232 ; [.2A05.0020.0002] -11233 ; [.2A06.0020.0002] -11235 ; [.2A07.0020.0002] -112B0 ; [.2A08.0020.0002] -112B1 ; [.2A09.0020.0002] -112B2 ; [.2A0A.0020.0002] -112B3 ; [.2A0B.0020.0002] -112B4 ; [.2A0C.0020.0002] -112B5 ; [.2A0D.0020.0002] -112B6 ; [.2A0E.0020.0002] -112B7 ; [.2A0F.0020.0002] -112B8 ; [.2A10.0020.0002] -112B9 ; [.2A11.0020.0002] -112BA ; [.2A12.0020.0002] -112BB ; [.2A13.0020.0002] -112BC ; [.2A14.0020.0002] -112BD ; [.2A15.0020.0002] -112BE ; [.2A16.0020.0002] -112BF ; [.2A17.0020.0002] -112C0 ; [.2A18.0020.0002] -112C1 ; [.2A19.0020.0002] -112C2 ; [.2A1A.0020.0002] -112C3 ; [.2A1B.0020.0002] -112C4 ; [.2A1C.0020.0002] -112C5 ; [.2A1D.0020.0002] -112C6 ; [.2A1E.0020.0002] -112C7 ; [.2A1F.0020.0002] -112C8 ; [.2A20.0020.0002] -112C9 ; [.2A21.0020.0002] -112CA ; [.2A22.0020.0002] -112CB ; [.2A23.0020.0002] -112CC ; [.2A24.0020.0002] -112CD ; [.2A25.0020.0002] -112CE ; [.2A26.0020.0002] -112CF ; [.2A27.0020.0002] -112D0 ; [.2A28.0020.0002] -112D1 ; [.2A29.0020.0002] -112D2 ; [.2A2A.0020.0002] -112D3 ; [.2A2B.0020.0002] -112D4 ; [.2A2C.0020.0002] -112D5 ; [.2A2D.0020.0002] -112D6 ; [.2A2E.0020.0002] -112D7 ; [.2A2F.0020.0002] -112D8 ; [.2A30.0020.0002] -112D9 ; [.2A31.0020.0002] -112DA ; [.2A32.0020.0002] -112DB ; [.2A33.0020.0002] -112DC ; [.2A34.0020.0002] -112DD ; [.2A35.0020.0002] -112DE ; [.2A36.0020.0002] -112E0 ; [.2A37.0020.0002] -112E1 ; [.2A38.0020.0002] -112E2 ; [.2A39.0020.0002] -112E3 ; [.2A3A.0020.0002] -112E4 ; [.2A3B.0020.0002] -112E5 ; [.2A3C.0020.0002] -112E6 ; [.2A3D.0020.0002] -112E7 ; [.2A3E.0020.0002] -112E8 ; [.2A3F.0020.0002] -112EA ; [.2A40.0020.0002] -11280 ; [.2A41.0020.0002] -11281 ; [.2A42.0020.0002] -11282 ; [.2A43.0020.0002] -11283 ; [.2A44.0020.0002] -112A5 ; [.2A45.0020.0002] -112A6 ; [.2A46.0020.0002] -11284 ; [.2A47.0020.0002] -11285 ; [.2A48.0020.0002] -11286 ; [.2A49.0020.0002] -11288 ; [.2A4A.0020.0002] -1128A ; [.2A4B.0020.0002] -1128B ; [.2A4C.0020.0002] -1128C ; [.2A4D.0020.0002] -1128D ; [.2A4E.0020.0002] -1128F ; [.2A4F.0020.0002] -11290 ; [.2A50.0020.0002] -11291 ; [.2A51.0020.0002] -11292 ; [.2A52.0020.0002] -11293 ; [.2A53.0020.0002] -11294 ; [.2A54.0020.0002] -11295 ; [.2A55.0020.0002] -11296 ; [.2A56.0020.0002] -11297 ; [.2A57.0020.0002] -11298 ; [.2A58.0020.0002] -11299 ; [.2A59.0020.0002] -1129A ; [.2A5A.0020.0002] -1129B ; [.2A5B.0020.0002] -1129C ; [.2A5C.0020.0002] -1129D ; [.2A5D.0020.0002] -1129F ; [.2A5E.0020.0002] -112A0 ; [.2A5F.0020.0002] -112A1 ; [.2A60.0020.0002] -112A2 ; [.2A61.0020.0002] -112A3 ; [.2A62.0020.0002] -112A4 ; [.2A63.0020.0002] -112A7 ; [.2A64.0020.0002] -112A8 ; [.2A65.0020.0002] -11350 ; [.2A66.0020.0002] -11305 ; [.2A67.0020.0002] -11306 ; [.2A68.0020.0002] -11307 ; [.2A69.0020.0002] -11308 ; [.2A6A.0020.0002] -11309 ; [.2A6B.0020.0002] -1130A ; [.2A6C.0020.0002] -1130B ; [.2A6D.0020.0002] -11360 ; [.2A6E.0020.0002] -1130C ; [.2A6F.0020.0002] -11361 ; [.2A70.0020.0002] -1130F ; [.2A71.0020.0002] -11310 ; [.2A72.0020.0002] -11313 ; [.2A73.0020.0002] -11314 ; [.2A74.0020.0002] -11315 ; [.2A75.0020.0002] -11316 ; [.2A76.0020.0002] -11317 ; [.2A77.0020.0002] -11318 ; [.2A78.0020.0002] -11319 ; [.2A79.0020.0002] -1131A ; [.2A7A.0020.0002] -1131B ; [.2A7B.0020.0002] -1131C ; [.2A7C.0020.0002] -1131D ; [.2A7D.0020.0002] -1131E ; [.2A7E.0020.0002] -1131F ; [.2A7F.0020.0002] -11320 ; [.2A80.0020.0002] -11321 ; [.2A81.0020.0002] -11322 ; [.2A82.0020.0002] -11323 ; [.2A83.0020.0002] -11324 ; [.2A84.0020.0002] -11325 ; [.2A85.0020.0002] -11326 ; [.2A86.0020.0002] -11327 ; [.2A87.0020.0002] -11328 ; [.2A88.0020.0002] -1132A ; [.2A89.0020.0002] -1132B ; [.2A8A.0020.0002] -1132C ; [.2A8B.0020.0002] -1132D ; [.2A8C.0020.0002] -1132E ; [.2A8D.0020.0002] -1132F ; [.2A8E.0020.0002] -11330 ; [.2A8F.0020.0002] -11332 ; [.2A90.0020.0002] -11333 ; [.2A91.0020.0002] -11335 ; [.2A92.0020.0002] -11336 ; [.2A93.0020.0002] -11337 ; [.2A94.0020.0002] -11338 ; [.2A95.0020.0002] -11339 ; [.2A96.0020.0002] -1133D ; [.2A97.0020.0002] -1135E ; [.2A98.0020.0002] -1135F ; [.2A99.0020.0002] -1133E ; [.2A9A.0020.0002] -1133F ; [.2A9B.0020.0002] -11340 ; [.2A9C.0020.0002] -11341 ; [.2A9D.0020.0002] -11342 ; [.2A9E.0020.0002] -11343 ; [.2A9F.0020.0002] -11344 ; [.2AA0.0020.0002] -11362 ; [.2AA1.0020.0002] -11363 ; [.2AA2.0020.0002] -11347 ; [.2AA3.0020.0002] -11348 ; [.2AA4.0020.0002] -1134B ; [.2AA5.0020.0002] -11347 1133E ; [.2AA5.0020.0002] -1134C ; [.2AA6.0020.0002] -11347 11357 ; [.2AA6.0020.0002] -1134D ; [.2AA7.0020.0002] -11357 ; [.2AA8.0020.0002] -1135D ; [.2AA9.0020.0002] -114C7 ; [.2AAA.0020.0002] -11480 ; [.2AAB.0020.0002] -11481 ; [.2AAC.0020.0002] -11482 ; [.2AAD.0020.0002] -11483 ; [.2AAE.0020.0002] -11484 ; [.2AAF.0020.0002] -11485 ; [.2AB0.0020.0002] -11486 ; [.2AB1.0020.0002] -11487 ; [.2AB2.0020.0002] -11488 ; [.2AB3.0020.0002] -11489 ; [.2AB4.0020.0002] -1148A ; [.2AB5.0020.0002] -1148B ; [.2AB6.0020.0002] -1148C ; [.2AB7.0020.0002] -1148D ; [.2AB8.0020.0002] -1148E ; [.2AB9.0020.0002] -1148F ; [.2ABA.0020.0002] -11490 ; [.2ABB.0020.0002] -11491 ; [.2ABC.0020.0002] -11492 ; [.2ABD.0020.0002] -11493 ; [.2ABE.0020.0002] -11494 ; [.2ABF.0020.0002] -11495 ; [.2AC0.0020.0002] -11496 ; [.2AC1.0020.0002] -11497 ; [.2AC2.0020.0002] -11498 ; [.2AC3.0020.0002] -11499 ; [.2AC4.0020.0002] -1149A ; [.2AC5.0020.0002] -1149B ; [.2AC6.0020.0002] -1149C ; [.2AC7.0020.0002] -1149D ; [.2AC8.0020.0002] -1149E ; [.2AC9.0020.0002] -1149F ; [.2ACA.0020.0002] -114A0 ; [.2ACB.0020.0002] -114A1 ; [.2ACC.0020.0002] -114A2 ; [.2ACD.0020.0002] -114A3 ; [.2ACE.0020.0002] -114A4 ; [.2ACF.0020.0002] -114A5 ; [.2AD0.0020.0002] -114A6 ; [.2AD1.0020.0002] -114A7 ; [.2AD2.0020.0002] -114A8 ; [.2AD3.0020.0002] -114A9 ; [.2AD4.0020.0002] -114AA ; [.2AD5.0020.0002] -114AB ; [.2AD6.0020.0002] -114AC ; [.2AD7.0020.0002] -114AD ; [.2AD8.0020.0002] -114AE ; [.2AD9.0020.0002] -114AF ; [.2ADA.0020.0002] -114C4 ; [.2ADB.0020.0002] -114C5 ; [.2ADC.0020.0002] -114B0 ; [.2ADD.0020.0002] -114B1 ; [.2ADE.0020.0002] -114B2 ; [.2ADF.0020.0002] -114B3 ; [.2AE0.0020.0002] -114B4 ; [.2AE1.0020.0002] -114B5 ; [.2AE2.0020.0002] -114B6 ; [.2AE3.0020.0002] -114B7 ; [.2AE4.0020.0002] -114B8 ; [.2AE5.0020.0002] -114B9 ; [.2AE6.0020.0002] -114BA ; [.2AE7.0020.0002] -114BB ; [.2AE8.0020.0002] -114B9 114BA ; [.2AE8.0020.0002] -114BC ; [.2AE9.0020.0002] -114B9 114B0 ; [.2AE9.0020.0002] -114BD ; [.2AEA.0020.0002] -114BE ; [.2AEB.0020.0002] -114B9 114BD ; [.2AEB.0020.0002] -114C2 ; [.2AEC.0020.0002] -11580 ; [.2AED.0020.0002] -11581 ; [.2AEE.0020.0002] -11582 ; [.2AEF.0020.0002] -115D8 ; [.2AEF.0020.0004][.0000.010B.0004] -115D9 ; [.2AEF.0020.0004][.0000.010C.0004] -11583 ; [.2AF0.0020.0002] -115DA ; [.2AF0.0020.0004][.0000.010B.0004] -11584 ; [.2AF1.0020.0002] -115DB ; [.2AF1.0020.0004][.0000.010B.0004] -11585 ; [.2AF2.0020.0002] -11586 ; [.2AF3.0020.0002] -11587 ; [.2AF4.0020.0002] -11588 ; [.2AF5.0020.0002] -11589 ; [.2AF6.0020.0002] -1158A ; [.2AF7.0020.0002] -1158B ; [.2AF8.0020.0002] -1158C ; [.2AF9.0020.0002] -1158D ; [.2AFA.0020.0002] -1158E ; [.2AFB.0020.0002] -1158F ; [.2AFC.0020.0002] -11590 ; [.2AFD.0020.0002] -11591 ; [.2AFE.0020.0002] -11592 ; [.2AFF.0020.0002] -11593 ; [.2B00.0020.0002] -11594 ; [.2B01.0020.0002] -11595 ; [.2B02.0020.0002] -11596 ; [.2B03.0020.0002] -11597 ; [.2B04.0020.0002] -11598 ; [.2B05.0020.0002] -11599 ; [.2B06.0020.0002] -1159A ; [.2B07.0020.0002] -1159B ; [.2B08.0020.0002] -1159C ; [.2B09.0020.0002] -1159D ; [.2B0A.0020.0002] -1159E ; [.2B0B.0020.0002] -1159F ; [.2B0C.0020.0002] -115A0 ; [.2B0D.0020.0002] -115A1 ; [.2B0E.0020.0002] -115A2 ; [.2B0F.0020.0002] -115A3 ; [.2B10.0020.0002] -115A4 ; [.2B11.0020.0002] -115A5 ; [.2B12.0020.0002] -115A6 ; [.2B13.0020.0002] -115A7 ; [.2B14.0020.0002] -115A8 ; [.2B15.0020.0002] -115A9 ; [.2B16.0020.0002] -115AA ; [.2B17.0020.0002] -115AB ; [.2B18.0020.0002] -115AC ; [.2B19.0020.0002] -115AD ; [.2B1A.0020.0002] -115AE ; [.2B1B.0020.0002] -115AF ; [.2B1C.0020.0002] -115B0 ; [.2B1D.0020.0002] -115B1 ; [.2B1E.0020.0002] -115B2 ; [.2B1F.0020.0002] -115DC ; [.2B1F.0020.0004][.0000.010B.0004] -115B3 ; [.2B20.0020.0002] -115DD ; [.2B20.0020.0004][.0000.010B.0004] -115B4 ; [.2B21.0020.0002] -115B5 ; [.2B22.0020.0002] -115B8 ; [.2B23.0020.0002] -115B9 ; [.2B24.0020.0002] -115BA ; [.2B25.0020.0002] -115B8 115AF ; [.2B25.0020.0002] -115BB ; [.2B26.0020.0002] -115B9 115AF ; [.2B26.0020.0002] -115BF ; [.2B27.0020.0002] -11600 ; [.2B28.0020.0002] -11601 ; [.2B29.0020.0002] -11602 ; [.2B2A.0020.0002] -11603 ; [.2B2B.0020.0002] -11604 ; [.2B2C.0020.0002] -11605 ; [.2B2D.0020.0002] -11606 ; [.2B2E.0020.0002] -11607 ; [.2B2F.0020.0002] -11608 ; [.2B30.0020.0002] -11609 ; [.2B31.0020.0002] -1160A ; [.2B32.0020.0002] -1160B ; [.2B33.0020.0002] -1160C ; [.2B34.0020.0002] -1160D ; [.2B35.0020.0002] -1160E ; [.2B36.0020.0002] -1160F ; [.2B37.0020.0002] -11610 ; [.2B38.0020.0002] -11611 ; [.2B39.0020.0002] -11612 ; [.2B3A.0020.0002] -11613 ; [.2B3B.0020.0002] -11614 ; [.2B3C.0020.0002] -11615 ; [.2B3D.0020.0002] -11616 ; [.2B3E.0020.0002] -11617 ; [.2B3F.0020.0002] -11618 ; [.2B40.0020.0002] -11619 ; [.2B41.0020.0002] -1161A ; [.2B42.0020.0002] -1161B ; [.2B43.0020.0002] -1161C ; [.2B44.0020.0002] -1161D ; [.2B45.0020.0002] -1161E ; [.2B46.0020.0002] -1161F ; [.2B47.0020.0002] -11620 ; [.2B48.0020.0002] -11621 ; [.2B49.0020.0002] -11622 ; [.2B4A.0020.0002] -11623 ; [.2B4B.0020.0002] -11624 ; [.2B4C.0020.0002] -11625 ; [.2B4D.0020.0002] -11626 ; [.2B4E.0020.0002] -11627 ; [.2B4F.0020.0002] -11628 ; [.2B50.0020.0002] -11629 ; [.2B51.0020.0002] -1162A ; [.2B52.0020.0002] -1162B ; [.2B53.0020.0002] -1162C ; [.2B54.0020.0002] -1162D ; [.2B55.0020.0002] -1162E ; [.2B56.0020.0002] -1162F ; [.2B57.0020.0002] -11630 ; [.2B58.0020.0002] -11631 ; [.2B59.0020.0002] -11632 ; [.2B5A.0020.0002] -11633 ; [.2B5B.0020.0002] -11634 ; [.2B5C.0020.0002] -11635 ; [.2B5D.0020.0002] -11636 ; [.2B5E.0020.0002] -11637 ; [.2B5F.0020.0002] -11638 ; [.2B60.0020.0002] -11639 ; [.2B61.0020.0002] -1163A ; [.2B62.0020.0002] -1163B ; [.2B63.0020.0002] -1163C ; [.2B64.0020.0002] -1163F ; [.2B65.0020.0002] -11644 ; [.2B66.0020.0002] -11680 ; [.2B67.0020.0002] -11681 ; [.2B68.0020.0002] -11682 ; [.2B69.0020.0002] -11683 ; [.2B6A.0020.0002] -11684 ; [.2B6B.0020.0002] -11685 ; [.2B6C.0020.0002] -11686 ; [.2B6D.0020.0002] -11687 ; [.2B6E.0020.0002] -11688 ; [.2B6F.0020.0002] -11689 ; [.2B70.0020.0002] -116A8 ; [.2B71.0020.0002] -116A7 ; [.2B72.0020.0002] -116A9 ; [.2B73.0020.0002] -1168A ; [.2B74.0020.0002] -1168B ; [.2B75.0020.0002] -1168C ; [.2B76.0020.0002] -1168D ; [.2B77.0020.0002] -1168E ; [.2B78.0020.0002] -1168F ; [.2B79.0020.0002] -11690 ; [.2B7A.0020.0002] -11691 ; [.2B7B.0020.0002] -11692 ; [.2B7C.0020.0002] -11693 ; [.2B7D.0020.0002] -11694 ; [.2B7E.0020.0002] -11695 ; [.2B7F.0020.0002] -11696 ; [.2B80.0020.0002] -11697 ; [.2B81.0020.0002] -11698 ; [.2B82.0020.0002] -11699 ; [.2B83.0020.0002] -1169A ; [.2B84.0020.0002] -1169B ; [.2B85.0020.0002] -1169C ; [.2B86.0020.0002] -1169D ; [.2B87.0020.0002] -1169E ; [.2B88.0020.0002] -1169F ; [.2B89.0020.0002] -116A0 ; [.2B8A.0020.0002] -116A1 ; [.2B8B.0020.0002] -116A2 ; [.2B8C.0020.0002] -116A3 ; [.2B8D.0020.0002] -116A4 ; [.2B8E.0020.0002] -116A5 ; [.2B8F.0020.0002] -116A6 ; [.2B90.0020.0002] -116AA ; [.2B91.0020.0002] -116AD ; [.2B92.0020.0002] -116AE ; [.2B93.0020.0002] -116AF ; [.2B94.0020.0002] -116B0 ; [.2B95.0020.0002] -116B1 ; [.2B96.0020.0002] -116B2 ; [.2B97.0020.0002] -116B3 ; [.2B98.0020.0002] -116B4 ; [.2B99.0020.0002] -116B5 ; [.2B9A.0020.0002] -116B6 ; [.2B9B.0020.0002] -11700 ; [.2B9C.0020.0002] -11701 ; [.2B9D.0020.0002] -11702 ; [.2B9E.0020.0002] -11703 ; [.2B9F.0020.0002] -11704 ; [.2BA0.0020.0002] -11705 ; [.2BA0.0020.0004][.0000.010B.0004] -11706 ; [.2BA1.0020.0002] -11707 ; [.2BA2.0020.0002] -11708 ; [.2BA3.0020.0002] -11709 ; [.2BA4.0020.0002] -1170A ; [.2BA5.0020.0002] -1170B ; [.2BA6.0020.0002] -1170C ; [.2BA7.0020.0002] -1170D ; [.2BA8.0020.0002] -1170E ; [.2BA9.0020.0002] -1170F ; [.2BAA.0020.0002] -11710 ; [.2BAB.0020.0002] -11711 ; [.2BAC.0020.0002] -11712 ; [.2BAD.0020.0002] -11713 ; [.2BAE.0020.0002] -11714 ; [.2BAF.0020.0002] -11715 ; [.2BB0.0020.0002] -11716 ; [.2BB0.0020.0004][.0000.010B.0004] -11717 ; [.2BB1.0020.0002] -11718 ; [.2BB2.0020.0002] -11719 ; [.2BB3.0020.0002] -11720 ; [.2BB4.0020.0002] -11721 ; [.2BB5.0020.0002] -11722 ; [.2BB6.0020.0002] -11723 ; [.2BB7.0020.0002] -11724 ; [.2BB8.0020.0002] -11725 ; [.2BB9.0020.0002] -11726 ; [.2BBA.0020.0002] -11727 ; [.2BBB.0020.0002] -11728 ; [.2BBC.0020.0002] -11729 ; [.2BBD.0020.0002] -1172A ; [.2BBE.0020.0002] -1172B ; [.2BBF.0020.0002] -1171D ; [.2BC0.0020.0002] -1171E ; [.2BC1.0020.0002] -1171F ; [.2BC2.0020.0002] -1B83 ; [.2BC3.0020.0002] -1BBA ; [.2BC3.0020.0004] -1B84 ; [.2BC4.0020.0002] -1B85 ; [.2BC5.0020.0002] -1B86 ; [.2BC6.0020.0002] -1B87 ; [.2BC7.0020.0002] -1B88 ; [.2BC8.0020.0002] -1B89 ; [.2BC9.0020.0002] -1B8A ; [.2BCA.0020.0002] -1BBE ; [.2BCA.0020.0019] -1BAE ; [.2BCB.0020.0002] -1B8B ; [.2BCC.0020.0002] -1B8C ; [.2BCD.0020.0002] -1B8D ; [.2BCE.0020.0002] -1B8E ; [.2BCF.0020.0002] -1B8F ; [.2BD0.0020.0002] -1B90 ; [.2BD1.0020.0002] -1B91 ; [.2BD2.0020.0002] -1B92 ; [.2BD3.0020.0002] -1B93 ; [.2BD4.0020.0002] -1B94 ; [.2BD5.0020.0002] -1B95 ; [.2BD6.0020.0002] -1B96 ; [.2BD7.0020.0002] -1B97 ; [.2BD8.0020.0002] -1B98 ; [.2BD9.0020.0002] -1BBD ; [.2BDA.0020.0002] -1B99 ; [.2BDB.0020.0002] -1BBF ; [.2BDB.0020.0019] -1BAC ; [.2BDC.0020.0002] -1B9A ; [.2BDD.0020.0002] -1BA1 ; [.2BDE.0020.0002] -1B9B ; [.2BDF.0020.0002] -1BA2 ; [.2BE0.0020.0002] -1BBB ; [.2BE1.0020.0002] -1B9C ; [.2BE2.0020.0002] -1BA3 ; [.2BE3.0020.0002] -1BBC ; [.2BE4.0020.0002] -1B9D ; [.2BE5.0020.0002] -1BAD ; [.2BE6.0020.0002] -1B9E ; [.2BE7.0020.0002] -1B9F ; [.2BE8.0020.0002] -1BAF ; [.2BE9.0020.0002] -1BA0 ; [.2BEA.0020.0002] -1BA4 ; [.2BEB.0020.0002] -1BA5 ; [.2BEC.0020.0002] -1BA6 ; [.2BED.0020.0002] -1BA7 ; [.2BEE.0020.0002] -1BA8 ; [.2BEF.0020.0002] -1BA9 ; [.2BF0.0020.0002] -1BAA ; [.2BF1.0020.0002] -1BAB ; [.2BF2.0020.0002] -11005 ; [.2BF3.0020.0002] -11006 ; [.2BF4.0020.0002] -11007 ; [.2BF5.0020.0002] -11008 ; [.2BF6.0020.0002] -11009 ; [.2BF7.0020.0002] -1100A ; [.2BF8.0020.0002] -1100B ; [.2BF9.0020.0002] -1100C ; [.2BFA.0020.0002] -1100D ; [.2BFB.0020.0002] -1100E ; [.2BFC.0020.0002] -1100F ; [.2BFD.0020.0002] -11010 ; [.2BFE.0020.0002] -11011 ; [.2BFF.0020.0002] -11012 ; [.2C00.0020.0002] -11013 ; [.2C01.0020.0002] -11014 ; [.2C02.0020.0002] -11015 ; [.2C03.0020.0002] -11016 ; [.2C04.0020.0002] -11017 ; [.2C05.0020.0002] -11018 ; [.2C06.0020.0002] -11019 ; [.2C07.0020.0002] -1101A ; [.2C08.0020.0002] -1101B ; [.2C09.0020.0002] -1101C ; [.2C0A.0020.0002] -1101D ; [.2C0B.0020.0002] -1101E ; [.2C0C.0020.0002] -1101F ; [.2C0D.0020.0002] -11020 ; [.2C0E.0020.0002] -11021 ; [.2C0F.0020.0002] -11022 ; [.2C10.0020.0002] -11023 ; [.2C11.0020.0002] -11024 ; [.2C12.0020.0002] -11025 ; [.2C13.0020.0002] -11026 ; [.2C14.0020.0002] -11027 ; [.2C15.0020.0002] -11028 ; [.2C16.0020.0002] -11029 ; [.2C17.0020.0002] -1102A ; [.2C18.0020.0002] -1102B ; [.2C19.0020.0002] -1102C ; [.2C1A.0020.0002] -1102D ; [.2C1B.0020.0002] -1102E ; [.2C1C.0020.0002] -1102F ; [.2C1D.0020.0002] -11030 ; [.2C1E.0020.0002] -11031 ; [.2C1F.0020.0002] -11032 ; [.2C20.0020.0002] -11033 ; [.2C21.0020.0002] -11003 ; [.2C22.0020.0002] -11004 ; [.2C23.0020.0002] -11034 ; [.2C24.0020.0002] -11035 ; [.2C25.0020.0002] -11036 ; [.2C26.0020.0002] -11037 ; [.2C27.0020.0002] -11038 ; [.2C28.0020.0002] -11039 ; [.2C29.0020.0002] -1103A ; [.2C2A.0020.0002] -1103B ; [.2C2B.0020.0002] -1103C ; [.2C2C.0020.0002] -1103D ; [.2C2D.0020.0002] -1103E ; [.2C2E.0020.0002] -1103F ; [.2C2F.0020.0002] -11040 ; [.2C30.0020.0002] -11041 ; [.2C31.0020.0002] -11042 ; [.2C32.0020.0002] -11043 ; [.2C33.0020.0002] -11044 ; [.2C34.0020.0002] -11045 ; [.2C35.0020.0002] -11046 ; [.2C36.0020.0002] -1107F ; [.2C37.0020.0002] -10A00 ; [.2C38.0020.0002] -10A01 ; [.2C39.0020.0002] -10A02 ; [.2C3A.0020.0002] -10A03 ; [.2C3B.0020.0002] -10A05 ; [.2C3C.0020.0002] -10A06 ; [.2C3D.0020.0002] -10A0C ; [.2C3E.0020.0002] -10A10 ; [.2C3F.0020.0002] -10A11 ; [.2C40.0020.0002] -10A12 ; [.2C41.0020.0002] -10A13 ; [.2C42.0020.0002] -10A15 ; [.2C43.0020.0002] -10A16 ; [.2C44.0020.0002] -10A17 ; [.2C45.0020.0002] -10A19 ; [.2C46.0020.0002] -10A1A ; [.2C47.0020.0002] -10A1B ; [.2C48.0020.0002] -10A1C ; [.2C49.0020.0002] -10A1D ; [.2C4A.0020.0002] -10A1E ; [.2C4B.0020.0002] -10A1F ; [.2C4C.0020.0002] -10A20 ; [.2C4D.0020.0002] -10A21 ; [.2C4E.0020.0002] -10A22 ; [.2C4F.0020.0002] -10A23 ; [.2C50.0020.0002] -10A24 ; [.2C51.0020.0002] -10A25 ; [.2C52.0020.0002] -10A26 ; [.2C53.0020.0002] -10A27 ; [.2C54.0020.0002] -10A28 ; [.2C55.0020.0002] -10A29 ; [.2C56.0020.0002] -10A2A ; [.2C57.0020.0002] -10A2B ; [.2C58.0020.0002] -10A2C ; [.2C59.0020.0002] -10A2D ; [.2C5A.0020.0002] -10A2E ; [.2C5B.0020.0002] -10A2F ; [.2C5C.0020.0002] -10A30 ; [.2C5D.0020.0002] -10A31 ; [.2C5E.0020.0002] -10A32 ; [.2C5F.0020.0002] -10A33 ; [.2C60.0020.0002] -10A3F ; [.2C61.0020.0002] -0E01 ; [.2C62.0020.0002] -0E40 0E01 ; [.2C62.0020.0002][.2C9C.0020.0002] -0E41 0E01 ; [.2C62.0020.0002][.2C9D.0020.0002] -0E42 0E01 ; [.2C62.0020.0002][.2C9E.0020.0002] -0E43 0E01 ; [.2C62.0020.0002][.2C9F.0020.0002] -0E44 0E01 ; [.2C62.0020.0002][.2CA0.0020.0002] -0E02 ; [.2C63.0020.0002] -0E40 0E02 ; [.2C63.0020.0002][.2C9C.0020.0002] -0E41 0E02 ; [.2C63.0020.0002][.2C9D.0020.0002] -0E42 0E02 ; [.2C63.0020.0002][.2C9E.0020.0002] -0E43 0E02 ; [.2C63.0020.0002][.2C9F.0020.0002] -0E44 0E02 ; [.2C63.0020.0002][.2CA0.0020.0002] -0E03 ; [.2C64.0020.0002] -0E40 0E03 ; [.2C64.0020.0002][.2C9C.0020.0002] -0E41 0E03 ; [.2C64.0020.0002][.2C9D.0020.0002] -0E42 0E03 ; [.2C64.0020.0002][.2C9E.0020.0002] -0E43 0E03 ; [.2C64.0020.0002][.2C9F.0020.0002] -0E44 0E03 ; [.2C64.0020.0002][.2CA0.0020.0002] -0E04 ; [.2C65.0020.0002] -0E40 0E04 ; [.2C65.0020.0002][.2C9C.0020.0002] -0E41 0E04 ; [.2C65.0020.0002][.2C9D.0020.0002] -0E42 0E04 ; [.2C65.0020.0002][.2C9E.0020.0002] -0E43 0E04 ; [.2C65.0020.0002][.2C9F.0020.0002] -0E44 0E04 ; [.2C65.0020.0002][.2CA0.0020.0002] -0E05 ; [.2C66.0020.0002] -0E40 0E05 ; [.2C66.0020.0002][.2C9C.0020.0002] -0E41 0E05 ; [.2C66.0020.0002][.2C9D.0020.0002] -0E42 0E05 ; [.2C66.0020.0002][.2C9E.0020.0002] -0E43 0E05 ; [.2C66.0020.0002][.2C9F.0020.0002] -0E44 0E05 ; [.2C66.0020.0002][.2CA0.0020.0002] -0E06 ; [.2C67.0020.0002] -0E40 0E06 ; [.2C67.0020.0002][.2C9C.0020.0002] -0E41 0E06 ; [.2C67.0020.0002][.2C9D.0020.0002] -0E42 0E06 ; [.2C67.0020.0002][.2C9E.0020.0002] -0E43 0E06 ; [.2C67.0020.0002][.2C9F.0020.0002] -0E44 0E06 ; [.2C67.0020.0002][.2CA0.0020.0002] -0E07 ; [.2C68.0020.0002] -0E40 0E07 ; [.2C68.0020.0002][.2C9C.0020.0002] -0E41 0E07 ; [.2C68.0020.0002][.2C9D.0020.0002] -0E42 0E07 ; [.2C68.0020.0002][.2C9E.0020.0002] -0E43 0E07 ; [.2C68.0020.0002][.2C9F.0020.0002] -0E44 0E07 ; [.2C68.0020.0002][.2CA0.0020.0002] -0E08 ; [.2C69.0020.0002] -0E40 0E08 ; [.2C69.0020.0002][.2C9C.0020.0002] -0E41 0E08 ; [.2C69.0020.0002][.2C9D.0020.0002] -0E42 0E08 ; [.2C69.0020.0002][.2C9E.0020.0002] -0E43 0E08 ; [.2C69.0020.0002][.2C9F.0020.0002] -0E44 0E08 ; [.2C69.0020.0002][.2CA0.0020.0002] -0E09 ; [.2C6A.0020.0002] -0E40 0E09 ; [.2C6A.0020.0002][.2C9C.0020.0002] -0E41 0E09 ; [.2C6A.0020.0002][.2C9D.0020.0002] -0E42 0E09 ; [.2C6A.0020.0002][.2C9E.0020.0002] -0E43 0E09 ; [.2C6A.0020.0002][.2C9F.0020.0002] -0E44 0E09 ; [.2C6A.0020.0002][.2CA0.0020.0002] -0E0A ; [.2C6B.0020.0002] -0E40 0E0A ; [.2C6B.0020.0002][.2C9C.0020.0002] -0E41 0E0A ; [.2C6B.0020.0002][.2C9D.0020.0002] -0E42 0E0A ; [.2C6B.0020.0002][.2C9E.0020.0002] -0E43 0E0A ; [.2C6B.0020.0002][.2C9F.0020.0002] -0E44 0E0A ; [.2C6B.0020.0002][.2CA0.0020.0002] -0E0B ; [.2C6C.0020.0002] -0E40 0E0B ; [.2C6C.0020.0002][.2C9C.0020.0002] -0E41 0E0B ; [.2C6C.0020.0002][.2C9D.0020.0002] -0E42 0E0B ; [.2C6C.0020.0002][.2C9E.0020.0002] -0E43 0E0B ; [.2C6C.0020.0002][.2C9F.0020.0002] -0E44 0E0B ; [.2C6C.0020.0002][.2CA0.0020.0002] -0E0C ; [.2C6D.0020.0002] -0E40 0E0C ; [.2C6D.0020.0002][.2C9C.0020.0002] -0E41 0E0C ; [.2C6D.0020.0002][.2C9D.0020.0002] -0E42 0E0C ; [.2C6D.0020.0002][.2C9E.0020.0002] -0E43 0E0C ; [.2C6D.0020.0002][.2C9F.0020.0002] -0E44 0E0C ; [.2C6D.0020.0002][.2CA0.0020.0002] -0E0D ; [.2C6E.0020.0002] -0E40 0E0D ; [.2C6E.0020.0002][.2C9C.0020.0002] -0E41 0E0D ; [.2C6E.0020.0002][.2C9D.0020.0002] -0E42 0E0D ; [.2C6E.0020.0002][.2C9E.0020.0002] -0E43 0E0D ; [.2C6E.0020.0002][.2C9F.0020.0002] -0E44 0E0D ; [.2C6E.0020.0002][.2CA0.0020.0002] -0E0E ; [.2C6F.0020.0002] -0E40 0E0E ; [.2C6F.0020.0002][.2C9C.0020.0002] -0E41 0E0E ; [.2C6F.0020.0002][.2C9D.0020.0002] -0E42 0E0E ; [.2C6F.0020.0002][.2C9E.0020.0002] -0E43 0E0E ; [.2C6F.0020.0002][.2C9F.0020.0002] -0E44 0E0E ; [.2C6F.0020.0002][.2CA0.0020.0002] -0E0F ; [.2C70.0020.0002] -0E40 0E0F ; [.2C70.0020.0002][.2C9C.0020.0002] -0E41 0E0F ; [.2C70.0020.0002][.2C9D.0020.0002] -0E42 0E0F ; [.2C70.0020.0002][.2C9E.0020.0002] -0E43 0E0F ; [.2C70.0020.0002][.2C9F.0020.0002] -0E44 0E0F ; [.2C70.0020.0002][.2CA0.0020.0002] -0E10 ; [.2C71.0020.0002] -0E40 0E10 ; [.2C71.0020.0002][.2C9C.0020.0002] -0E41 0E10 ; [.2C71.0020.0002][.2C9D.0020.0002] -0E42 0E10 ; [.2C71.0020.0002][.2C9E.0020.0002] -0E43 0E10 ; [.2C71.0020.0002][.2C9F.0020.0002] -0E44 0E10 ; [.2C71.0020.0002][.2CA0.0020.0002] -0E11 ; [.2C72.0020.0002] -0E40 0E11 ; [.2C72.0020.0002][.2C9C.0020.0002] -0E41 0E11 ; [.2C72.0020.0002][.2C9D.0020.0002] -0E42 0E11 ; [.2C72.0020.0002][.2C9E.0020.0002] -0E43 0E11 ; [.2C72.0020.0002][.2C9F.0020.0002] -0E44 0E11 ; [.2C72.0020.0002][.2CA0.0020.0002] -0E12 ; [.2C73.0020.0002] -0E40 0E12 ; [.2C73.0020.0002][.2C9C.0020.0002] -0E41 0E12 ; [.2C73.0020.0002][.2C9D.0020.0002] -0E42 0E12 ; [.2C73.0020.0002][.2C9E.0020.0002] -0E43 0E12 ; [.2C73.0020.0002][.2C9F.0020.0002] -0E44 0E12 ; [.2C73.0020.0002][.2CA0.0020.0002] -0E13 ; [.2C74.0020.0002] -0E40 0E13 ; [.2C74.0020.0002][.2C9C.0020.0002] -0E41 0E13 ; [.2C74.0020.0002][.2C9D.0020.0002] -0E42 0E13 ; [.2C74.0020.0002][.2C9E.0020.0002] -0E43 0E13 ; [.2C74.0020.0002][.2C9F.0020.0002] -0E44 0E13 ; [.2C74.0020.0002][.2CA0.0020.0002] -0E14 ; [.2C75.0020.0002] -0E40 0E14 ; [.2C75.0020.0002][.2C9C.0020.0002] -0E41 0E14 ; [.2C75.0020.0002][.2C9D.0020.0002] -0E42 0E14 ; [.2C75.0020.0002][.2C9E.0020.0002] -0E43 0E14 ; [.2C75.0020.0002][.2C9F.0020.0002] -0E44 0E14 ; [.2C75.0020.0002][.2CA0.0020.0002] -0E15 ; [.2C76.0020.0002] -0E40 0E15 ; [.2C76.0020.0002][.2C9C.0020.0002] -0E41 0E15 ; [.2C76.0020.0002][.2C9D.0020.0002] -0E42 0E15 ; [.2C76.0020.0002][.2C9E.0020.0002] -0E43 0E15 ; [.2C76.0020.0002][.2C9F.0020.0002] -0E44 0E15 ; [.2C76.0020.0002][.2CA0.0020.0002] -0E16 ; [.2C77.0020.0002] -0E40 0E16 ; [.2C77.0020.0002][.2C9C.0020.0002] -0E41 0E16 ; [.2C77.0020.0002][.2C9D.0020.0002] -0E42 0E16 ; [.2C77.0020.0002][.2C9E.0020.0002] -0E43 0E16 ; [.2C77.0020.0002][.2C9F.0020.0002] -0E44 0E16 ; [.2C77.0020.0002][.2CA0.0020.0002] -0E17 ; [.2C78.0020.0002] -0E40 0E17 ; [.2C78.0020.0002][.2C9C.0020.0002] -0E41 0E17 ; [.2C78.0020.0002][.2C9D.0020.0002] -0E42 0E17 ; [.2C78.0020.0002][.2C9E.0020.0002] -0E43 0E17 ; [.2C78.0020.0002][.2C9F.0020.0002] -0E44 0E17 ; [.2C78.0020.0002][.2CA0.0020.0002] -0E18 ; [.2C79.0020.0002] -0E40 0E18 ; [.2C79.0020.0002][.2C9C.0020.0002] -0E41 0E18 ; [.2C79.0020.0002][.2C9D.0020.0002] -0E42 0E18 ; [.2C79.0020.0002][.2C9E.0020.0002] -0E43 0E18 ; [.2C79.0020.0002][.2C9F.0020.0002] -0E44 0E18 ; [.2C79.0020.0002][.2CA0.0020.0002] -0E19 ; [.2C7A.0020.0002] -0E40 0E19 ; [.2C7A.0020.0002][.2C9C.0020.0002] -0E41 0E19 ; [.2C7A.0020.0002][.2C9D.0020.0002] -0E42 0E19 ; [.2C7A.0020.0002][.2C9E.0020.0002] -0E43 0E19 ; [.2C7A.0020.0002][.2C9F.0020.0002] -0E44 0E19 ; [.2C7A.0020.0002][.2CA0.0020.0002] -0E1A ; [.2C7B.0020.0002] -0E40 0E1A ; [.2C7B.0020.0002][.2C9C.0020.0002] -0E41 0E1A ; [.2C7B.0020.0002][.2C9D.0020.0002] -0E42 0E1A ; [.2C7B.0020.0002][.2C9E.0020.0002] -0E43 0E1A ; [.2C7B.0020.0002][.2C9F.0020.0002] -0E44 0E1A ; [.2C7B.0020.0002][.2CA0.0020.0002] -0E1B ; [.2C7C.0020.0002] -0E40 0E1B ; [.2C7C.0020.0002][.2C9C.0020.0002] -0E41 0E1B ; [.2C7C.0020.0002][.2C9D.0020.0002] -0E42 0E1B ; [.2C7C.0020.0002][.2C9E.0020.0002] -0E43 0E1B ; [.2C7C.0020.0002][.2C9F.0020.0002] -0E44 0E1B ; [.2C7C.0020.0002][.2CA0.0020.0002] -0E1C ; [.2C7D.0020.0002] -0E40 0E1C ; [.2C7D.0020.0002][.2C9C.0020.0002] -0E41 0E1C ; [.2C7D.0020.0002][.2C9D.0020.0002] -0E42 0E1C ; [.2C7D.0020.0002][.2C9E.0020.0002] -0E43 0E1C ; [.2C7D.0020.0002][.2C9F.0020.0002] -0E44 0E1C ; [.2C7D.0020.0002][.2CA0.0020.0002] -0E1D ; [.2C7E.0020.0002] -0E40 0E1D ; [.2C7E.0020.0002][.2C9C.0020.0002] -0E41 0E1D ; [.2C7E.0020.0002][.2C9D.0020.0002] -0E42 0E1D ; [.2C7E.0020.0002][.2C9E.0020.0002] -0E43 0E1D ; [.2C7E.0020.0002][.2C9F.0020.0002] -0E44 0E1D ; [.2C7E.0020.0002][.2CA0.0020.0002] -0E1E ; [.2C7F.0020.0002] -0E40 0E1E ; [.2C7F.0020.0002][.2C9C.0020.0002] -0E41 0E1E ; [.2C7F.0020.0002][.2C9D.0020.0002] -0E42 0E1E ; [.2C7F.0020.0002][.2C9E.0020.0002] -0E43 0E1E ; [.2C7F.0020.0002][.2C9F.0020.0002] -0E44 0E1E ; [.2C7F.0020.0002][.2CA0.0020.0002] -0E1F ; [.2C80.0020.0002] -0E40 0E1F ; [.2C80.0020.0002][.2C9C.0020.0002] -0E41 0E1F ; [.2C80.0020.0002][.2C9D.0020.0002] -0E42 0E1F ; [.2C80.0020.0002][.2C9E.0020.0002] -0E43 0E1F ; [.2C80.0020.0002][.2C9F.0020.0002] -0E44 0E1F ; [.2C80.0020.0002][.2CA0.0020.0002] -0E20 ; [.2C81.0020.0002] -0E40 0E20 ; [.2C81.0020.0002][.2C9C.0020.0002] -0E41 0E20 ; [.2C81.0020.0002][.2C9D.0020.0002] -0E42 0E20 ; [.2C81.0020.0002][.2C9E.0020.0002] -0E43 0E20 ; [.2C81.0020.0002][.2C9F.0020.0002] -0E44 0E20 ; [.2C81.0020.0002][.2CA0.0020.0002] -0E21 ; [.2C82.0020.0002] -0E40 0E21 ; [.2C82.0020.0002][.2C9C.0020.0002] -0E41 0E21 ; [.2C82.0020.0002][.2C9D.0020.0002] -0E42 0E21 ; [.2C82.0020.0002][.2C9E.0020.0002] -0E43 0E21 ; [.2C82.0020.0002][.2C9F.0020.0002] -0E44 0E21 ; [.2C82.0020.0002][.2CA0.0020.0002] -0E22 ; [.2C83.0020.0002] -0E40 0E22 ; [.2C83.0020.0002][.2C9C.0020.0002] -0E41 0E22 ; [.2C83.0020.0002][.2C9D.0020.0002] -0E42 0E22 ; [.2C83.0020.0002][.2C9E.0020.0002] -0E43 0E22 ; [.2C83.0020.0002][.2C9F.0020.0002] -0E44 0E22 ; [.2C83.0020.0002][.2CA0.0020.0002] -0E23 ; [.2C84.0020.0002] -0E40 0E23 ; [.2C84.0020.0002][.2C9C.0020.0002] -0E41 0E23 ; [.2C84.0020.0002][.2C9D.0020.0002] -0E42 0E23 ; [.2C84.0020.0002][.2C9E.0020.0002] -0E43 0E23 ; [.2C84.0020.0002][.2C9F.0020.0002] -0E44 0E23 ; [.2C84.0020.0002][.2CA0.0020.0002] -0E24 ; [.2C85.0020.0002] -0E40 0E24 ; [.2C85.0020.0002][.2C9C.0020.0002] -0E41 0E24 ; [.2C85.0020.0002][.2C9D.0020.0002] -0E42 0E24 ; [.2C85.0020.0002][.2C9E.0020.0002] -0E43 0E24 ; [.2C85.0020.0002][.2C9F.0020.0002] -0E44 0E24 ; [.2C85.0020.0002][.2CA0.0020.0002] -0E25 ; [.2C86.0020.0002] -0E40 0E25 ; [.2C86.0020.0002][.2C9C.0020.0002] -0E41 0E25 ; [.2C86.0020.0002][.2C9D.0020.0002] -0E42 0E25 ; [.2C86.0020.0002][.2C9E.0020.0002] -0E43 0E25 ; [.2C86.0020.0002][.2C9F.0020.0002] -0E44 0E25 ; [.2C86.0020.0002][.2CA0.0020.0002] -0E26 ; [.2C87.0020.0002] -0E40 0E26 ; [.2C87.0020.0002][.2C9C.0020.0002] -0E41 0E26 ; [.2C87.0020.0002][.2C9D.0020.0002] -0E42 0E26 ; [.2C87.0020.0002][.2C9E.0020.0002] -0E43 0E26 ; [.2C87.0020.0002][.2C9F.0020.0002] -0E44 0E26 ; [.2C87.0020.0002][.2CA0.0020.0002] -0E27 ; [.2C88.0020.0002] -0E40 0E27 ; [.2C88.0020.0002][.2C9C.0020.0002] -0E41 0E27 ; [.2C88.0020.0002][.2C9D.0020.0002] -0E42 0E27 ; [.2C88.0020.0002][.2C9E.0020.0002] -0E43 0E27 ; [.2C88.0020.0002][.2C9F.0020.0002] -0E44 0E27 ; [.2C88.0020.0002][.2CA0.0020.0002] -0E28 ; [.2C89.0020.0002] -0E40 0E28 ; [.2C89.0020.0002][.2C9C.0020.0002] -0E41 0E28 ; [.2C89.0020.0002][.2C9D.0020.0002] -0E42 0E28 ; [.2C89.0020.0002][.2C9E.0020.0002] -0E43 0E28 ; [.2C89.0020.0002][.2C9F.0020.0002] -0E44 0E28 ; [.2C89.0020.0002][.2CA0.0020.0002] -0E29 ; [.2C8A.0020.0002] -0E40 0E29 ; [.2C8A.0020.0002][.2C9C.0020.0002] -0E41 0E29 ; [.2C8A.0020.0002][.2C9D.0020.0002] -0E42 0E29 ; [.2C8A.0020.0002][.2C9E.0020.0002] -0E43 0E29 ; [.2C8A.0020.0002][.2C9F.0020.0002] -0E44 0E29 ; [.2C8A.0020.0002][.2CA0.0020.0002] -0E2A ; [.2C8B.0020.0002] -0E40 0E2A ; [.2C8B.0020.0002][.2C9C.0020.0002] -0E41 0E2A ; [.2C8B.0020.0002][.2C9D.0020.0002] -0E42 0E2A ; [.2C8B.0020.0002][.2C9E.0020.0002] -0E43 0E2A ; [.2C8B.0020.0002][.2C9F.0020.0002] -0E44 0E2A ; [.2C8B.0020.0002][.2CA0.0020.0002] -0E2B ; [.2C8C.0020.0002] -0E40 0E2B ; [.2C8C.0020.0002][.2C9C.0020.0002] -0E41 0E2B ; [.2C8C.0020.0002][.2C9D.0020.0002] -0E42 0E2B ; [.2C8C.0020.0002][.2C9E.0020.0002] -0E43 0E2B ; [.2C8C.0020.0002][.2C9F.0020.0002] -0E44 0E2B ; [.2C8C.0020.0002][.2CA0.0020.0002] -0E2C ; [.2C8D.0020.0002] -0E40 0E2C ; [.2C8D.0020.0002][.2C9C.0020.0002] -0E41 0E2C ; [.2C8D.0020.0002][.2C9D.0020.0002] -0E42 0E2C ; [.2C8D.0020.0002][.2C9E.0020.0002] -0E43 0E2C ; [.2C8D.0020.0002][.2C9F.0020.0002] -0E44 0E2C ; [.2C8D.0020.0002][.2CA0.0020.0002] -0E2D ; [.2C8E.0020.0002] -0E40 0E2D ; [.2C8E.0020.0002][.2C9C.0020.0002] -0E41 0E2D ; [.2C8E.0020.0002][.2C9D.0020.0002] -0E42 0E2D ; [.2C8E.0020.0002][.2C9E.0020.0002] -0E43 0E2D ; [.2C8E.0020.0002][.2C9F.0020.0002] -0E44 0E2D ; [.2C8E.0020.0002][.2CA0.0020.0002] -0E2E ; [.2C8F.0020.0002] -0E40 0E2E ; [.2C8F.0020.0002][.2C9C.0020.0002] -0E41 0E2E ; [.2C8F.0020.0002][.2C9D.0020.0002] -0E42 0E2E ; [.2C8F.0020.0002][.2C9E.0020.0002] -0E43 0E2E ; [.2C8F.0020.0002][.2C9F.0020.0002] -0E44 0E2E ; [.2C8F.0020.0002][.2CA0.0020.0002] -0E2F ; [.2C90.0020.0002] -0E30 ; [.2C91.0020.0002] -0E31 ; [.2C92.0020.0002] -0E32 ; [.2C93.0020.0002] -0E33 ; [.2C94.0020.0002] -0E4D 0E32 ; [.2C94.0020.0002] -0E34 ; [.2C95.0020.0002] -0E35 ; [.2C96.0020.0002] -0E36 ; [.2C97.0020.0002] -0E37 ; [.2C98.0020.0002] -0E38 ; [.2C99.0020.0002] -0E39 ; [.2C9A.0020.0002] -0E3A ; [.2C9B.0020.0002] -0E40 ; [.2C9C.0020.0002] -0E41 ; [.2C9D.0020.0002] -0E42 ; [.2C9E.0020.0002] -0E43 ; [.2C9F.0020.0002] -0E44 ; [.2CA0.0020.0002] -0E45 ; [.2CA1.0020.0002] -0EDE ; [.2CA2.0020.0002] -0EC0 0EDE ; [.2CA2.0020.0002][.2CCD.0020.0002] -0EC1 0EDE ; [.2CA2.0020.0002][.2CCE.0020.0002] -0EC2 0EDE ; [.2CA2.0020.0002][.2CCF.0020.0002] -0EC3 0EDE ; [.2CA2.0020.0002][.2CD0.0020.0002] -0EC4 0EDE ; [.2CA2.0020.0002][.2CD1.0020.0002] -0E81 ; [.2CA3.0020.0002] -0EC0 0E81 ; [.2CA3.0020.0002][.2CCD.0020.0002] -0EC1 0E81 ; [.2CA3.0020.0002][.2CCE.0020.0002] -0EC2 0E81 ; [.2CA3.0020.0002][.2CCF.0020.0002] -0EC3 0E81 ; [.2CA3.0020.0002][.2CD0.0020.0002] -0EC4 0E81 ; [.2CA3.0020.0002][.2CD1.0020.0002] -0E82 ; [.2CA4.0020.0002] -0EC0 0E82 ; [.2CA4.0020.0002][.2CCD.0020.0002] -0EC1 0E82 ; [.2CA4.0020.0002][.2CCE.0020.0002] -0EC2 0E82 ; [.2CA4.0020.0002][.2CCF.0020.0002] -0EC3 0E82 ; [.2CA4.0020.0002][.2CD0.0020.0002] -0EC4 0E82 ; [.2CA4.0020.0002][.2CD1.0020.0002] -0E84 ; [.2CA5.0020.0002] -0EC0 0E84 ; [.2CA5.0020.0002][.2CCD.0020.0002] -0EC1 0E84 ; [.2CA5.0020.0002][.2CCE.0020.0002] -0EC2 0E84 ; [.2CA5.0020.0002][.2CCF.0020.0002] -0EC3 0E84 ; [.2CA5.0020.0002][.2CD0.0020.0002] -0EC4 0E84 ; [.2CA5.0020.0002][.2CD1.0020.0002] -0E87 ; [.2CA6.0020.0002] -0EC0 0E87 ; [.2CA6.0020.0002][.2CCD.0020.0002] -0EC1 0E87 ; [.2CA6.0020.0002][.2CCE.0020.0002] -0EC2 0E87 ; [.2CA6.0020.0002][.2CCF.0020.0002] -0EC3 0E87 ; [.2CA6.0020.0002][.2CD0.0020.0002] -0EC4 0E87 ; [.2CA6.0020.0002][.2CD1.0020.0002] -0E88 ; [.2CA7.0020.0002] -0EC0 0E88 ; [.2CA7.0020.0002][.2CCD.0020.0002] -0EC1 0E88 ; [.2CA7.0020.0002][.2CCE.0020.0002] -0EC2 0E88 ; [.2CA7.0020.0002][.2CCF.0020.0002] -0EC3 0E88 ; [.2CA7.0020.0002][.2CD0.0020.0002] -0EC4 0E88 ; [.2CA7.0020.0002][.2CD1.0020.0002] -0EAA ; [.2CA8.0020.0002] -0EC0 0EAA ; [.2CA8.0020.0002][.2CCD.0020.0002] -0EC1 0EAA ; [.2CA8.0020.0002][.2CCE.0020.0002] -0EC2 0EAA ; [.2CA8.0020.0002][.2CCF.0020.0002] -0EC3 0EAA ; [.2CA8.0020.0002][.2CD0.0020.0002] -0EC4 0EAA ; [.2CA8.0020.0002][.2CD1.0020.0002] -0E8A ; [.2CA9.0020.0002] -0EC0 0E8A ; [.2CA9.0020.0002][.2CCD.0020.0002] -0EC1 0E8A ; [.2CA9.0020.0002][.2CCE.0020.0002] -0EC2 0E8A ; [.2CA9.0020.0002][.2CCF.0020.0002] -0EC3 0E8A ; [.2CA9.0020.0002][.2CD0.0020.0002] -0EC4 0E8A ; [.2CA9.0020.0002][.2CD1.0020.0002] -0EDF ; [.2CAA.0020.0002] -0EC0 0EDF ; [.2CAA.0020.0002][.2CCD.0020.0002] -0EC1 0EDF ; [.2CAA.0020.0002][.2CCE.0020.0002] -0EC2 0EDF ; [.2CAA.0020.0002][.2CCF.0020.0002] -0EC3 0EDF ; [.2CAA.0020.0002][.2CD0.0020.0002] -0EC4 0EDF ; [.2CAA.0020.0002][.2CD1.0020.0002] -0E8D ; [.2CAB.0020.0002] -0EC0 0E8D ; [.2CAB.0020.0002][.2CCD.0020.0002] -0EC1 0E8D ; [.2CAB.0020.0002][.2CCE.0020.0002] -0EC2 0E8D ; [.2CAB.0020.0002][.2CCF.0020.0002] -0EC3 0E8D ; [.2CAB.0020.0002][.2CD0.0020.0002] -0EC4 0E8D ; [.2CAB.0020.0002][.2CD1.0020.0002] -0E94 ; [.2CAC.0020.0002] -0EC0 0E94 ; [.2CAC.0020.0002][.2CCD.0020.0002] -0EC1 0E94 ; [.2CAC.0020.0002][.2CCE.0020.0002] -0EC2 0E94 ; [.2CAC.0020.0002][.2CCF.0020.0002] -0EC3 0E94 ; [.2CAC.0020.0002][.2CD0.0020.0002] -0EC4 0E94 ; [.2CAC.0020.0002][.2CD1.0020.0002] -0E95 ; [.2CAD.0020.0002] -0EC0 0E95 ; [.2CAD.0020.0002][.2CCD.0020.0002] -0EC1 0E95 ; [.2CAD.0020.0002][.2CCE.0020.0002] -0EC2 0E95 ; [.2CAD.0020.0002][.2CCF.0020.0002] -0EC3 0E95 ; [.2CAD.0020.0002][.2CD0.0020.0002] -0EC4 0E95 ; [.2CAD.0020.0002][.2CD1.0020.0002] -0E96 ; [.2CAE.0020.0002] -0EC0 0E96 ; [.2CAE.0020.0002][.2CCD.0020.0002] -0EC1 0E96 ; [.2CAE.0020.0002][.2CCE.0020.0002] -0EC2 0E96 ; [.2CAE.0020.0002][.2CCF.0020.0002] -0EC3 0E96 ; [.2CAE.0020.0002][.2CD0.0020.0002] -0EC4 0E96 ; [.2CAE.0020.0002][.2CD1.0020.0002] -0E97 ; [.2CAF.0020.0002] -0EC0 0E97 ; [.2CAF.0020.0002][.2CCD.0020.0002] -0EC1 0E97 ; [.2CAF.0020.0002][.2CCE.0020.0002] -0EC2 0E97 ; [.2CAF.0020.0002][.2CCF.0020.0002] -0EC3 0E97 ; [.2CAF.0020.0002][.2CD0.0020.0002] -0EC4 0E97 ; [.2CAF.0020.0002][.2CD1.0020.0002] -0E99 ; [.2CB0.0020.0002] -0EC0 0E99 ; [.2CB0.0020.0002][.2CCD.0020.0002] -0EC1 0E99 ; [.2CB0.0020.0002][.2CCE.0020.0002] -0EC2 0E99 ; [.2CB0.0020.0002][.2CCF.0020.0002] -0EC3 0E99 ; [.2CB0.0020.0002][.2CD0.0020.0002] -0EC4 0E99 ; [.2CB0.0020.0002][.2CD1.0020.0002] -0E9A ; [.2CB1.0020.0002] -0EC0 0E9A ; [.2CB1.0020.0002][.2CCD.0020.0002] -0EC1 0E9A ; [.2CB1.0020.0002][.2CCE.0020.0002] -0EC2 0E9A ; [.2CB1.0020.0002][.2CCF.0020.0002] -0EC3 0E9A ; [.2CB1.0020.0002][.2CD0.0020.0002] -0EC4 0E9A ; [.2CB1.0020.0002][.2CD1.0020.0002] -0E9B ; [.2CB2.0020.0002] -0EC0 0E9B ; [.2CB2.0020.0002][.2CCD.0020.0002] -0EC1 0E9B ; [.2CB2.0020.0002][.2CCE.0020.0002] -0EC2 0E9B ; [.2CB2.0020.0002][.2CCF.0020.0002] -0EC3 0E9B ; [.2CB2.0020.0002][.2CD0.0020.0002] -0EC4 0E9B ; [.2CB2.0020.0002][.2CD1.0020.0002] -0E9C ; [.2CB3.0020.0002] -0EC0 0E9C ; [.2CB3.0020.0002][.2CCD.0020.0002] -0EC1 0E9C ; [.2CB3.0020.0002][.2CCE.0020.0002] -0EC2 0E9C ; [.2CB3.0020.0002][.2CCF.0020.0002] -0EC3 0E9C ; [.2CB3.0020.0002][.2CD0.0020.0002] -0EC4 0E9C ; [.2CB3.0020.0002][.2CD1.0020.0002] -0E9D ; [.2CB4.0020.0002] -0EC0 0E9D ; [.2CB4.0020.0002][.2CCD.0020.0002] -0EC1 0E9D ; [.2CB4.0020.0002][.2CCE.0020.0002] -0EC2 0E9D ; [.2CB4.0020.0002][.2CCF.0020.0002] -0EC3 0E9D ; [.2CB4.0020.0002][.2CD0.0020.0002] -0EC4 0E9D ; [.2CB4.0020.0002][.2CD1.0020.0002] -0E9E ; [.2CB5.0020.0002] -0EC0 0E9E ; [.2CB5.0020.0002][.2CCD.0020.0002] -0EC1 0E9E ; [.2CB5.0020.0002][.2CCE.0020.0002] -0EC2 0E9E ; [.2CB5.0020.0002][.2CCF.0020.0002] -0EC3 0E9E ; [.2CB5.0020.0002][.2CD0.0020.0002] -0EC4 0E9E ; [.2CB5.0020.0002][.2CD1.0020.0002] -0E9F ; [.2CB6.0020.0002] -0EC0 0E9F ; [.2CB6.0020.0002][.2CCD.0020.0002] -0EC1 0E9F ; [.2CB6.0020.0002][.2CCE.0020.0002] -0EC2 0E9F ; [.2CB6.0020.0002][.2CCF.0020.0002] -0EC3 0E9F ; [.2CB6.0020.0002][.2CD0.0020.0002] -0EC4 0E9F ; [.2CB6.0020.0002][.2CD1.0020.0002] -0EA1 ; [.2CB7.0020.0002] -0EC0 0EA1 ; [.2CB7.0020.0002][.2CCD.0020.0002] -0EC1 0EA1 ; [.2CB7.0020.0002][.2CCE.0020.0002] -0EC2 0EA1 ; [.2CB7.0020.0002][.2CCF.0020.0002] -0EC3 0EA1 ; [.2CB7.0020.0002][.2CD0.0020.0002] -0EC4 0EA1 ; [.2CB7.0020.0002][.2CD1.0020.0002] -0EA2 ; [.2CB8.0020.0002] -0EC0 0EA2 ; [.2CB8.0020.0002][.2CCD.0020.0002] -0EC1 0EA2 ; [.2CB8.0020.0002][.2CCE.0020.0002] -0EC2 0EA2 ; [.2CB8.0020.0002][.2CCF.0020.0002] -0EC3 0EA2 ; [.2CB8.0020.0002][.2CD0.0020.0002] -0EC4 0EA2 ; [.2CB8.0020.0002][.2CD1.0020.0002] -0EA3 ; [.2CB9.0020.0002] -0EC0 0EA3 ; [.2CB9.0020.0002][.2CCD.0020.0002] -0EC1 0EA3 ; [.2CB9.0020.0002][.2CCE.0020.0002] -0EC2 0EA3 ; [.2CB9.0020.0002][.2CCF.0020.0002] -0EC3 0EA3 ; [.2CB9.0020.0002][.2CD0.0020.0002] -0EC4 0EA3 ; [.2CB9.0020.0002][.2CD1.0020.0002] -0EA5 ; [.2CBA.0020.0002] -0EC0 0EA5 ; [.2CBA.0020.0002][.2CCD.0020.0002] -0EC1 0EA5 ; [.2CBA.0020.0002][.2CCE.0020.0002] -0EC2 0EA5 ; [.2CBA.0020.0002][.2CCF.0020.0002] -0EC3 0EA5 ; [.2CBA.0020.0002][.2CD0.0020.0002] -0EC4 0EA5 ; [.2CBA.0020.0002][.2CD1.0020.0002] -0EA7 ; [.2CBB.0020.0002] -0EC0 0EA7 ; [.2CBB.0020.0002][.2CCD.0020.0002] -0EC1 0EA7 ; [.2CBB.0020.0002][.2CCE.0020.0002] -0EC2 0EA7 ; [.2CBB.0020.0002][.2CCF.0020.0002] -0EC3 0EA7 ; [.2CBB.0020.0002][.2CD0.0020.0002] -0EC4 0EA7 ; [.2CBB.0020.0002][.2CD1.0020.0002] -0EAB ; [.2CBC.0020.0002] -0EDC ; [.2CBC.0020.0004][.2CB0.0020.0004] -0EC0 0EDC ; [.2CBC.0020.0004][.2CB0.0020.0004][.2CCD.0020.0002] -0EC1 0EDC ; [.2CBC.0020.0004][.2CB0.0020.0004][.2CCE.0020.0002] -0EC2 0EDC ; [.2CBC.0020.0004][.2CB0.0020.0004][.2CCF.0020.0002] -0EC3 0EDC ; [.2CBC.0020.0004][.2CB0.0020.0004][.2CD0.0020.0002] -0EC4 0EDC ; [.2CBC.0020.0004][.2CB0.0020.0004][.2CD1.0020.0002] -0EDD ; [.2CBC.0020.0004][.2CB7.0020.0004] -0EC0 0EDD ; [.2CBC.0020.0004][.2CB7.0020.0004][.2CCD.0020.0002] -0EC1 0EDD ; [.2CBC.0020.0004][.2CB7.0020.0004][.2CCE.0020.0002] -0EC2 0EDD ; [.2CBC.0020.0004][.2CB7.0020.0004][.2CCF.0020.0002] -0EC3 0EDD ; [.2CBC.0020.0004][.2CB7.0020.0004][.2CD0.0020.0002] -0EC4 0EDD ; [.2CBC.0020.0004][.2CB7.0020.0004][.2CD1.0020.0002] -0EC0 0EAB ; [.2CBC.0020.0002][.2CCD.0020.0002] -0EC1 0EAB ; [.2CBC.0020.0002][.2CCE.0020.0002] -0EC2 0EAB ; [.2CBC.0020.0002][.2CCF.0020.0002] -0EC3 0EAB ; [.2CBC.0020.0002][.2CD0.0020.0002] -0EC4 0EAB ; [.2CBC.0020.0002][.2CD1.0020.0002] -0EAD ; [.2CBD.0020.0002] -0EC0 0EAD ; [.2CBD.0020.0002][.2CCD.0020.0002] -0EC1 0EAD ; [.2CBD.0020.0002][.2CCE.0020.0002] -0EC2 0EAD ; [.2CBD.0020.0002][.2CCF.0020.0002] -0EC3 0EAD ; [.2CBD.0020.0002][.2CD0.0020.0002] -0EC4 0EAD ; [.2CBD.0020.0002][.2CD1.0020.0002] -0EAE ; [.2CBE.0020.0002] -0EC0 0EAE ; [.2CBE.0020.0002][.2CCD.0020.0002] -0EC1 0EAE ; [.2CBE.0020.0002][.2CCE.0020.0002] -0EC2 0EAE ; [.2CBE.0020.0002][.2CCF.0020.0002] -0EC3 0EAE ; [.2CBE.0020.0002][.2CD0.0020.0002] -0EC4 0EAE ; [.2CBE.0020.0002][.2CD1.0020.0002] -0EAF ; [.2CBF.0020.0002] -0EB0 ; [.2CC0.0020.0002] -0EB1 ; [.2CC1.0020.0002] -0EB2 ; [.2CC2.0020.0002] -0EB3 ; [.2CC3.0020.0002] -0ECD 0EB2 ; [.2CC3.0020.0002] -0EB4 ; [.2CC4.0020.0002] -0EB5 ; [.2CC5.0020.0002] -0EB6 ; [.2CC6.0020.0002] -0EB7 ; [.2CC7.0020.0002] -0EB8 ; [.2CC8.0020.0002] -0EB9 ; [.2CC9.0020.0002] -0EBB ; [.2CCA.0020.0002] -0EBC ; [.2CCB.0020.0002] -0EBD ; [.2CCC.0020.0002] -0EC0 ; [.2CCD.0020.0002] -0EC1 ; [.2CCE.0020.0002] -0EC2 ; [.2CCF.0020.0002] -0EC3 ; [.2CD0.0020.0002] -0EC4 ; [.2CD1.0020.0002] -AA80 ; [.2CD2.0020.0002] -AAB5 AA80 ; [.2CD2.0020.0002][.2D07.0020.0002] -AAB6 AA80 ; [.2CD2.0020.0002][.2D08.0020.0002] -AAB9 AA80 ; [.2CD2.0020.0002][.2D0B.0020.0002] -AABB AA80 ; [.2CD2.0020.0002][.2D0D.0020.0002] -AABC AA80 ; [.2CD2.0020.0002][.2D0E.0020.0002] -AA81 ; [.2CD3.0020.0002] -AAB5 AA81 ; [.2CD3.0020.0002][.2D07.0020.0002] -AAB6 AA81 ; [.2CD3.0020.0002][.2D08.0020.0002] -AAB9 AA81 ; [.2CD3.0020.0002][.2D0B.0020.0002] -AABB AA81 ; [.2CD3.0020.0002][.2D0D.0020.0002] -AABC AA81 ; [.2CD3.0020.0002][.2D0E.0020.0002] -AA82 ; [.2CD4.0020.0002] -AAB5 AA82 ; [.2CD4.0020.0002][.2D07.0020.0002] -AAB6 AA82 ; [.2CD4.0020.0002][.2D08.0020.0002] -AAB9 AA82 ; [.2CD4.0020.0002][.2D0B.0020.0002] -AABB AA82 ; [.2CD4.0020.0002][.2D0D.0020.0002] -AABC AA82 ; [.2CD4.0020.0002][.2D0E.0020.0002] -AA83 ; [.2CD5.0020.0002] -AAB5 AA83 ; [.2CD5.0020.0002][.2D07.0020.0002] -AAB6 AA83 ; [.2CD5.0020.0002][.2D08.0020.0002] -AAB9 AA83 ; [.2CD5.0020.0002][.2D0B.0020.0002] -AABB AA83 ; [.2CD5.0020.0002][.2D0D.0020.0002] -AABC AA83 ; [.2CD5.0020.0002][.2D0E.0020.0002] -AA84 ; [.2CD6.0020.0002] -AAB5 AA84 ; [.2CD6.0020.0002][.2D07.0020.0002] -AAB6 AA84 ; [.2CD6.0020.0002][.2D08.0020.0002] -AAB9 AA84 ; [.2CD6.0020.0002][.2D0B.0020.0002] -AABB AA84 ; [.2CD6.0020.0002][.2D0D.0020.0002] -AABC AA84 ; [.2CD6.0020.0002][.2D0E.0020.0002] -AA85 ; [.2CD7.0020.0002] -AAB5 AA85 ; [.2CD7.0020.0002][.2D07.0020.0002] -AAB6 AA85 ; [.2CD7.0020.0002][.2D08.0020.0002] -AAB9 AA85 ; [.2CD7.0020.0002][.2D0B.0020.0002] -AABB AA85 ; [.2CD7.0020.0002][.2D0D.0020.0002] -AABC AA85 ; [.2CD7.0020.0002][.2D0E.0020.0002] -AA86 ; [.2CD8.0020.0002] -AAB5 AA86 ; [.2CD8.0020.0002][.2D07.0020.0002] -AAB6 AA86 ; [.2CD8.0020.0002][.2D08.0020.0002] -AAB9 AA86 ; [.2CD8.0020.0002][.2D0B.0020.0002] -AABB AA86 ; [.2CD8.0020.0002][.2D0D.0020.0002] -AABC AA86 ; [.2CD8.0020.0002][.2D0E.0020.0002] -AA87 ; [.2CD9.0020.0002] -AAB5 AA87 ; [.2CD9.0020.0002][.2D07.0020.0002] -AAB6 AA87 ; [.2CD9.0020.0002][.2D08.0020.0002] -AAB9 AA87 ; [.2CD9.0020.0002][.2D0B.0020.0002] -AABB AA87 ; [.2CD9.0020.0002][.2D0D.0020.0002] -AABC AA87 ; [.2CD9.0020.0002][.2D0E.0020.0002] -AA88 ; [.2CDA.0020.0002] -AAB5 AA88 ; [.2CDA.0020.0002][.2D07.0020.0002] -AAB6 AA88 ; [.2CDA.0020.0002][.2D08.0020.0002] -AAB9 AA88 ; [.2CDA.0020.0002][.2D0B.0020.0002] -AABB AA88 ; [.2CDA.0020.0002][.2D0D.0020.0002] -AABC AA88 ; [.2CDA.0020.0002][.2D0E.0020.0002] -AA89 ; [.2CDB.0020.0002] -AAB5 AA89 ; [.2CDB.0020.0002][.2D07.0020.0002] -AAB6 AA89 ; [.2CDB.0020.0002][.2D08.0020.0002] -AAB9 AA89 ; [.2CDB.0020.0002][.2D0B.0020.0002] -AABB AA89 ; [.2CDB.0020.0002][.2D0D.0020.0002] -AABC AA89 ; [.2CDB.0020.0002][.2D0E.0020.0002] -AA8A ; [.2CDC.0020.0002] -AAB5 AA8A ; [.2CDC.0020.0002][.2D07.0020.0002] -AAB6 AA8A ; [.2CDC.0020.0002][.2D08.0020.0002] -AAB9 AA8A ; [.2CDC.0020.0002][.2D0B.0020.0002] -AABB AA8A ; [.2CDC.0020.0002][.2D0D.0020.0002] -AABC AA8A ; [.2CDC.0020.0002][.2D0E.0020.0002] -AA8B ; [.2CDD.0020.0002] -AAB5 AA8B ; [.2CDD.0020.0002][.2D07.0020.0002] -AAB6 AA8B ; [.2CDD.0020.0002][.2D08.0020.0002] -AAB9 AA8B ; [.2CDD.0020.0002][.2D0B.0020.0002] -AABB AA8B ; [.2CDD.0020.0002][.2D0D.0020.0002] -AABC AA8B ; [.2CDD.0020.0002][.2D0E.0020.0002] -AA8C ; [.2CDE.0020.0002] -AAB5 AA8C ; [.2CDE.0020.0002][.2D07.0020.0002] -AAB6 AA8C ; [.2CDE.0020.0002][.2D08.0020.0002] -AAB9 AA8C ; [.2CDE.0020.0002][.2D0B.0020.0002] -AABB AA8C ; [.2CDE.0020.0002][.2D0D.0020.0002] -AABC AA8C ; [.2CDE.0020.0002][.2D0E.0020.0002] -AA8D ; [.2CDF.0020.0002] -AAB5 AA8D ; [.2CDF.0020.0002][.2D07.0020.0002] -AAB6 AA8D ; [.2CDF.0020.0002][.2D08.0020.0002] -AAB9 AA8D ; [.2CDF.0020.0002][.2D0B.0020.0002] -AABB AA8D ; [.2CDF.0020.0002][.2D0D.0020.0002] -AABC AA8D ; [.2CDF.0020.0002][.2D0E.0020.0002] -AA8E ; [.2CE0.0020.0002] -AAB5 AA8E ; [.2CE0.0020.0002][.2D07.0020.0002] -AAB6 AA8E ; [.2CE0.0020.0002][.2D08.0020.0002] -AAB9 AA8E ; [.2CE0.0020.0002][.2D0B.0020.0002] -AABB AA8E ; [.2CE0.0020.0002][.2D0D.0020.0002] -AABC AA8E ; [.2CE0.0020.0002][.2D0E.0020.0002] -AA8F ; [.2CE1.0020.0002] -AAB5 AA8F ; [.2CE1.0020.0002][.2D07.0020.0002] -AAB6 AA8F ; [.2CE1.0020.0002][.2D08.0020.0002] -AAB9 AA8F ; [.2CE1.0020.0002][.2D0B.0020.0002] -AABB AA8F ; [.2CE1.0020.0002][.2D0D.0020.0002] -AABC AA8F ; [.2CE1.0020.0002][.2D0E.0020.0002] -AA90 ; [.2CE2.0020.0002] -AAB5 AA90 ; [.2CE2.0020.0002][.2D07.0020.0002] -AAB6 AA90 ; [.2CE2.0020.0002][.2D08.0020.0002] -AAB9 AA90 ; [.2CE2.0020.0002][.2D0B.0020.0002] -AABB AA90 ; [.2CE2.0020.0002][.2D0D.0020.0002] -AABC AA90 ; [.2CE2.0020.0002][.2D0E.0020.0002] -AA91 ; [.2CE3.0020.0002] -AAB5 AA91 ; [.2CE3.0020.0002][.2D07.0020.0002] -AAB6 AA91 ; [.2CE3.0020.0002][.2D08.0020.0002] -AAB9 AA91 ; [.2CE3.0020.0002][.2D0B.0020.0002] -AABB AA91 ; [.2CE3.0020.0002][.2D0D.0020.0002] -AABC AA91 ; [.2CE3.0020.0002][.2D0E.0020.0002] -AA92 ; [.2CE4.0020.0002] -AAB5 AA92 ; [.2CE4.0020.0002][.2D07.0020.0002] -AAB6 AA92 ; [.2CE4.0020.0002][.2D08.0020.0002] -AAB9 AA92 ; [.2CE4.0020.0002][.2D0B.0020.0002] -AABB AA92 ; [.2CE4.0020.0002][.2D0D.0020.0002] -AABC AA92 ; [.2CE4.0020.0002][.2D0E.0020.0002] -AA93 ; [.2CE5.0020.0002] -AAB5 AA93 ; [.2CE5.0020.0002][.2D07.0020.0002] -AAB6 AA93 ; [.2CE5.0020.0002][.2D08.0020.0002] -AAB9 AA93 ; [.2CE5.0020.0002][.2D0B.0020.0002] -AABB AA93 ; [.2CE5.0020.0002][.2D0D.0020.0002] -AABC AA93 ; [.2CE5.0020.0002][.2D0E.0020.0002] -AA94 ; [.2CE6.0020.0002] -AAB5 AA94 ; [.2CE6.0020.0002][.2D07.0020.0002] -AAB6 AA94 ; [.2CE6.0020.0002][.2D08.0020.0002] -AAB9 AA94 ; [.2CE6.0020.0002][.2D0B.0020.0002] -AABB AA94 ; [.2CE6.0020.0002][.2D0D.0020.0002] -AABC AA94 ; [.2CE6.0020.0002][.2D0E.0020.0002] -AA95 ; [.2CE7.0020.0002] -AAB5 AA95 ; [.2CE7.0020.0002][.2D07.0020.0002] -AAB6 AA95 ; [.2CE7.0020.0002][.2D08.0020.0002] -AAB9 AA95 ; [.2CE7.0020.0002][.2D0B.0020.0002] -AABB AA95 ; [.2CE7.0020.0002][.2D0D.0020.0002] -AABC AA95 ; [.2CE7.0020.0002][.2D0E.0020.0002] -AA96 ; [.2CE8.0020.0002] -AAB5 AA96 ; [.2CE8.0020.0002][.2D07.0020.0002] -AAB6 AA96 ; [.2CE8.0020.0002][.2D08.0020.0002] -AAB9 AA96 ; [.2CE8.0020.0002][.2D0B.0020.0002] -AABB AA96 ; [.2CE8.0020.0002][.2D0D.0020.0002] -AABC AA96 ; [.2CE8.0020.0002][.2D0E.0020.0002] -AA97 ; [.2CE9.0020.0002] -AAB5 AA97 ; [.2CE9.0020.0002][.2D07.0020.0002] -AAB6 AA97 ; [.2CE9.0020.0002][.2D08.0020.0002] -AAB9 AA97 ; [.2CE9.0020.0002][.2D0B.0020.0002] -AABB AA97 ; [.2CE9.0020.0002][.2D0D.0020.0002] -AABC AA97 ; [.2CE9.0020.0002][.2D0E.0020.0002] -AA98 ; [.2CEA.0020.0002] -AAB5 AA98 ; [.2CEA.0020.0002][.2D07.0020.0002] -AAB6 AA98 ; [.2CEA.0020.0002][.2D08.0020.0002] -AAB9 AA98 ; [.2CEA.0020.0002][.2D0B.0020.0002] -AABB AA98 ; [.2CEA.0020.0002][.2D0D.0020.0002] -AABC AA98 ; [.2CEA.0020.0002][.2D0E.0020.0002] -AA99 ; [.2CEB.0020.0002] -AAB5 AA99 ; [.2CEB.0020.0002][.2D07.0020.0002] -AAB6 AA99 ; [.2CEB.0020.0002][.2D08.0020.0002] -AAB9 AA99 ; [.2CEB.0020.0002][.2D0B.0020.0002] -AABB AA99 ; [.2CEB.0020.0002][.2D0D.0020.0002] -AABC AA99 ; [.2CEB.0020.0002][.2D0E.0020.0002] -AA9A ; [.2CEC.0020.0002] -AAB5 AA9A ; [.2CEC.0020.0002][.2D07.0020.0002] -AAB6 AA9A ; [.2CEC.0020.0002][.2D08.0020.0002] -AAB9 AA9A ; [.2CEC.0020.0002][.2D0B.0020.0002] -AABB AA9A ; [.2CEC.0020.0002][.2D0D.0020.0002] -AABC AA9A ; [.2CEC.0020.0002][.2D0E.0020.0002] -AA9B ; [.2CED.0020.0002] -AAB5 AA9B ; [.2CED.0020.0002][.2D07.0020.0002] -AAB6 AA9B ; [.2CED.0020.0002][.2D08.0020.0002] -AAB9 AA9B ; [.2CED.0020.0002][.2D0B.0020.0002] -AABB AA9B ; [.2CED.0020.0002][.2D0D.0020.0002] -AABC AA9B ; [.2CED.0020.0002][.2D0E.0020.0002] -AA9C ; [.2CEE.0020.0002] -AAB5 AA9C ; [.2CEE.0020.0002][.2D07.0020.0002] -AAB6 AA9C ; [.2CEE.0020.0002][.2D08.0020.0002] -AAB9 AA9C ; [.2CEE.0020.0002][.2D0B.0020.0002] -AABB AA9C ; [.2CEE.0020.0002][.2D0D.0020.0002] -AABC AA9C ; [.2CEE.0020.0002][.2D0E.0020.0002] -AA9D ; [.2CEF.0020.0002] -AAB5 AA9D ; [.2CEF.0020.0002][.2D07.0020.0002] -AAB6 AA9D ; [.2CEF.0020.0002][.2D08.0020.0002] -AAB9 AA9D ; [.2CEF.0020.0002][.2D0B.0020.0002] -AABB AA9D ; [.2CEF.0020.0002][.2D0D.0020.0002] -AABC AA9D ; [.2CEF.0020.0002][.2D0E.0020.0002] -AA9E ; [.2CF0.0020.0002] -AAB5 AA9E ; [.2CF0.0020.0002][.2D07.0020.0002] -AAB6 AA9E ; [.2CF0.0020.0002][.2D08.0020.0002] -AAB9 AA9E ; [.2CF0.0020.0002][.2D0B.0020.0002] -AABB AA9E ; [.2CF0.0020.0002][.2D0D.0020.0002] -AABC AA9E ; [.2CF0.0020.0002][.2D0E.0020.0002] -AA9F ; [.2CF1.0020.0002] -AAB5 AA9F ; [.2CF1.0020.0002][.2D07.0020.0002] -AAB6 AA9F ; [.2CF1.0020.0002][.2D08.0020.0002] -AAB9 AA9F ; [.2CF1.0020.0002][.2D0B.0020.0002] -AABB AA9F ; [.2CF1.0020.0002][.2D0D.0020.0002] -AABC AA9F ; [.2CF1.0020.0002][.2D0E.0020.0002] -AAA0 ; [.2CF2.0020.0002] -AAB5 AAA0 ; [.2CF2.0020.0002][.2D07.0020.0002] -AAB6 AAA0 ; [.2CF2.0020.0002][.2D08.0020.0002] -AAB9 AAA0 ; [.2CF2.0020.0002][.2D0B.0020.0002] -AABB AAA0 ; [.2CF2.0020.0002][.2D0D.0020.0002] -AABC AAA0 ; [.2CF2.0020.0002][.2D0E.0020.0002] -AAA1 ; [.2CF3.0020.0002] -AAB5 AAA1 ; [.2CF3.0020.0002][.2D07.0020.0002] -AAB6 AAA1 ; [.2CF3.0020.0002][.2D08.0020.0002] -AAB9 AAA1 ; [.2CF3.0020.0002][.2D0B.0020.0002] -AABB AAA1 ; [.2CF3.0020.0002][.2D0D.0020.0002] -AABC AAA1 ; [.2CF3.0020.0002][.2D0E.0020.0002] -AAA2 ; [.2CF4.0020.0002] -AAB5 AAA2 ; [.2CF4.0020.0002][.2D07.0020.0002] -AAB6 AAA2 ; [.2CF4.0020.0002][.2D08.0020.0002] -AAB9 AAA2 ; [.2CF4.0020.0002][.2D0B.0020.0002] -AABB AAA2 ; [.2CF4.0020.0002][.2D0D.0020.0002] -AABC AAA2 ; [.2CF4.0020.0002][.2D0E.0020.0002] -AAA3 ; [.2CF5.0020.0002] -AAB5 AAA3 ; [.2CF5.0020.0002][.2D07.0020.0002] -AAB6 AAA3 ; [.2CF5.0020.0002][.2D08.0020.0002] -AAB9 AAA3 ; [.2CF5.0020.0002][.2D0B.0020.0002] -AABB AAA3 ; [.2CF5.0020.0002][.2D0D.0020.0002] -AABC AAA3 ; [.2CF5.0020.0002][.2D0E.0020.0002] -AAA4 ; [.2CF6.0020.0002] -AAB5 AAA4 ; [.2CF6.0020.0002][.2D07.0020.0002] -AAB6 AAA4 ; [.2CF6.0020.0002][.2D08.0020.0002] -AAB9 AAA4 ; [.2CF6.0020.0002][.2D0B.0020.0002] -AABB AAA4 ; [.2CF6.0020.0002][.2D0D.0020.0002] -AABC AAA4 ; [.2CF6.0020.0002][.2D0E.0020.0002] -AAA5 ; [.2CF7.0020.0002] -AAB5 AAA5 ; [.2CF7.0020.0002][.2D07.0020.0002] -AAB6 AAA5 ; [.2CF7.0020.0002][.2D08.0020.0002] -AAB9 AAA5 ; [.2CF7.0020.0002][.2D0B.0020.0002] -AABB AAA5 ; [.2CF7.0020.0002][.2D0D.0020.0002] -AABC AAA5 ; [.2CF7.0020.0002][.2D0E.0020.0002] -AAA6 ; [.2CF8.0020.0002] -AAB5 AAA6 ; [.2CF8.0020.0002][.2D07.0020.0002] -AAB6 AAA6 ; [.2CF8.0020.0002][.2D08.0020.0002] -AAB9 AAA6 ; [.2CF8.0020.0002][.2D0B.0020.0002] -AABB AAA6 ; [.2CF8.0020.0002][.2D0D.0020.0002] -AABC AAA6 ; [.2CF8.0020.0002][.2D0E.0020.0002] -AAA7 ; [.2CF9.0020.0002] -AAB5 AAA7 ; [.2CF9.0020.0002][.2D07.0020.0002] -AAB6 AAA7 ; [.2CF9.0020.0002][.2D08.0020.0002] -AAB9 AAA7 ; [.2CF9.0020.0002][.2D0B.0020.0002] -AABB AAA7 ; [.2CF9.0020.0002][.2D0D.0020.0002] -AABC AAA7 ; [.2CF9.0020.0002][.2D0E.0020.0002] -AAA8 ; [.2CFA.0020.0002] -AAB5 AAA8 ; [.2CFA.0020.0002][.2D07.0020.0002] -AAB6 AAA8 ; [.2CFA.0020.0002][.2D08.0020.0002] -AAB9 AAA8 ; [.2CFA.0020.0002][.2D0B.0020.0002] -AABB AAA8 ; [.2CFA.0020.0002][.2D0D.0020.0002] -AABC AAA8 ; [.2CFA.0020.0002][.2D0E.0020.0002] -AAA9 ; [.2CFB.0020.0002] -AAB5 AAA9 ; [.2CFB.0020.0002][.2D07.0020.0002] -AAB6 AAA9 ; [.2CFB.0020.0002][.2D08.0020.0002] -AAB9 AAA9 ; [.2CFB.0020.0002][.2D0B.0020.0002] -AABB AAA9 ; [.2CFB.0020.0002][.2D0D.0020.0002] -AABC AAA9 ; [.2CFB.0020.0002][.2D0E.0020.0002] -AAAA ; [.2CFC.0020.0002] -AAB5 AAAA ; [.2CFC.0020.0002][.2D07.0020.0002] -AAB6 AAAA ; [.2CFC.0020.0002][.2D08.0020.0002] -AAB9 AAAA ; [.2CFC.0020.0002][.2D0B.0020.0002] -AABB AAAA ; [.2CFC.0020.0002][.2D0D.0020.0002] -AABC AAAA ; [.2CFC.0020.0002][.2D0E.0020.0002] -AAAB ; [.2CFD.0020.0002] -AAB5 AAAB ; [.2CFD.0020.0002][.2D07.0020.0002] -AAB6 AAAB ; [.2CFD.0020.0002][.2D08.0020.0002] -AAB9 AAAB ; [.2CFD.0020.0002][.2D0B.0020.0002] -AABB AAAB ; [.2CFD.0020.0002][.2D0D.0020.0002] -AABC AAAB ; [.2CFD.0020.0002][.2D0E.0020.0002] -AAAC ; [.2CFE.0020.0002] -AAB5 AAAC ; [.2CFE.0020.0002][.2D07.0020.0002] -AAB6 AAAC ; [.2CFE.0020.0002][.2D08.0020.0002] -AAB9 AAAC ; [.2CFE.0020.0002][.2D0B.0020.0002] -AABB AAAC ; [.2CFE.0020.0002][.2D0D.0020.0002] -AABC AAAC ; [.2CFE.0020.0002][.2D0E.0020.0002] -AAAD ; [.2CFF.0020.0002] -AAB5 AAAD ; [.2CFF.0020.0002][.2D07.0020.0002] -AAB6 AAAD ; [.2CFF.0020.0002][.2D08.0020.0002] -AAB9 AAAD ; [.2CFF.0020.0002][.2D0B.0020.0002] -AABB AAAD ; [.2CFF.0020.0002][.2D0D.0020.0002] -AABC AAAD ; [.2CFF.0020.0002][.2D0E.0020.0002] -AAAE ; [.2D00.0020.0002] -AAB5 AAAE ; [.2D00.0020.0002][.2D07.0020.0002] -AAB6 AAAE ; [.2D00.0020.0002][.2D08.0020.0002] -AAB9 AAAE ; [.2D00.0020.0002][.2D0B.0020.0002] -AABB AAAE ; [.2D00.0020.0002][.2D0D.0020.0002] -AABC AAAE ; [.2D00.0020.0002][.2D0E.0020.0002] -AAAF ; [.2D01.0020.0002] -AAB5 AAAF ; [.2D01.0020.0002][.2D07.0020.0002] -AAB6 AAAF ; [.2D01.0020.0002][.2D08.0020.0002] -AAB9 AAAF ; [.2D01.0020.0002][.2D0B.0020.0002] -AABB AAAF ; [.2D01.0020.0002][.2D0D.0020.0002] -AABC AAAF ; [.2D01.0020.0002][.2D0E.0020.0002] -AAB0 ; [.2D02.0020.0002] -AAB1 ; [.2D03.0020.0002] -AAB2 ; [.2D04.0020.0002] -AAB3 ; [.2D05.0020.0002] -AAB4 ; [.2D06.0020.0002] -AAB5 ; [.2D07.0020.0002] -AAB6 ; [.2D08.0020.0002] -AAB7 ; [.2D09.0020.0002] -AAB8 ; [.2D0A.0020.0002] -AAB9 ; [.2D0B.0020.0002] -AABA ; [.2D0C.0020.0002] -AABB ; [.2D0D.0020.0002] -AABC ; [.2D0E.0020.0002] -AABD ; [.2D0F.0020.0002] -AABE ; [.2D10.0020.0002] -AAC0 ; [.2D11.0020.0002] -AAC2 ; [.2D12.0020.0002] -AADB ; [.2D13.0020.0002] -AADC ; [.2D14.0020.0002] -0F40 ; [.2D15.0020.0002] -0F69 ; [.2D15.0020.0002][.2D56.0020.0002] -0F90 ; [.2D16.0020.0002] -0FB9 ; [.2D16.0020.0002][.2D56.0020.0002] -0F6B ; [.2D17.0020.0002] -0F41 ; [.2D18.0020.0002] -0F91 ; [.2D19.0020.0002] -0F42 ; [.2D1A.0020.0002] -0F43 ; [.2D1A.0020.0002][.2D5A.0020.0002] -0F92 ; [.2D1B.0020.0002] -0F93 ; [.2D1B.0020.0002][.2D5A.0020.0002] -0F44 ; [.2D1C.0020.0002] -0F94 ; [.2D1D.0020.0002] -0F45 ; [.2D1E.0020.0002] -0F95 ; [.2D1F.0020.0002] -0F46 ; [.2D20.0020.0002] -0F96 ; [.2D21.0020.0002] -0F47 ; [.2D22.0020.0002] -0F97 ; [.2D23.0020.0002] -0F49 ; [.2D24.0020.0002] -0F99 ; [.2D25.0020.0002] -0F4A ; [.2D26.0020.0002] -0F9A ; [.2D27.0020.0002] -0F4B ; [.2D28.0020.0002] -0F9B ; [.2D29.0020.0002] -0F4C ; [.2D2A.0020.0002] -0F4D ; [.2D2A.0020.0002][.2D5A.0020.0002] -0F9C ; [.2D2B.0020.0002] -0F9D ; [.2D2B.0020.0002][.2D5A.0020.0002] -0F4E ; [.2D2C.0020.0002] -0F9E ; [.2D2D.0020.0002] -0F4F ; [.2D2E.0020.0002] -0F9F ; [.2D2F.0020.0002] -0F50 ; [.2D30.0020.0002] -0FA0 ; [.2D31.0020.0002] -0F51 ; [.2D32.0020.0002] -0F52 ; [.2D32.0020.0002][.2D5A.0020.0002] -0FA1 ; [.2D33.0020.0002] -0FA2 ; [.2D33.0020.0002][.2D5A.0020.0002] -0F53 ; [.2D34.0020.0002] -0FA3 ; [.2D35.0020.0002] -0F54 ; [.2D36.0020.0002] -0FA4 ; [.2D37.0020.0002] -0F55 ; [.2D38.0020.0002] -0FA5 ; [.2D39.0020.0002] -0F56 ; [.2D3A.0020.0002] -0F57 ; [.2D3A.0020.0002][.2D5A.0020.0002] -0FA6 ; [.2D3B.0020.0002] -0FA7 ; [.2D3B.0020.0002][.2D5A.0020.0002] -0F58 ; [.2D3C.0020.0002] -0FA8 ; [.2D3D.0020.0002] -0F59 ; [.2D3E.0020.0002] -0FA9 ; [.2D3F.0020.0002] -0F5A ; [.2D40.0020.0002] -0FAA ; [.2D41.0020.0002] -0F5B ; [.2D42.0020.0002] -0F5C ; [.2D42.0020.0002][.2D5A.0020.0002] -0FAB ; [.2D43.0020.0002] -0FAC ; [.2D43.0020.0002][.2D5A.0020.0002] -0F5D ; [.2D44.0020.0002] -0FAD ; [.2D45.0020.0002] -0FBA ; [.2D45.0020.0004][.0000.010C.0004] -0F5E ; [.2D46.0020.0002] -0FAE ; [.2D47.0020.0002] -0F5F ; [.2D48.0020.0002] -0FAF ; [.2D49.0020.0002] -0F60 ; [.2D4A.0020.0002] -0FB0 ; [.2D4B.0020.0002] -0F61 ; [.2D4C.0020.0002] -0FB1 ; [.2D4D.0020.0002] -0FBB ; [.2D4D.0020.0004][.0000.010C.0004] -0F62 ; [.2D4E.0020.0002] -0F6A ; [.2D4E.0020.0004][.0000.010C.0004] -0FB2 ; [.2D4F.0020.0002] -0FBC ; [.2D4F.0020.0004][.0000.010C.0004] -0F6C ; [.2D50.0020.0002] -0F63 ; [.2D51.0020.0002] -0FB3 ; [.2D52.0020.0002] -0F64 ; [.2D53.0020.0002] -0FB4 ; [.2D54.0020.0002] -0F65 ; [.2D55.0020.0002] -0FB5 ; [.2D56.0020.0002] -0F66 ; [.2D57.0020.0002] -0FB6 ; [.2D58.0020.0002] -0F67 ; [.2D59.0020.0002] -0FB7 ; [.2D5A.0020.0002] -0F68 ; [.2D5B.0020.0002] -0F00 ; [.2D5B.0020.0004][.2D72.0020.0004][.0000.00BF.0004] -0FB8 ; [.2D5C.0020.0002] -0F88 ; [.2D5D.0020.0002] -0F8D ; [.2D5E.0020.0002] -0F89 ; [.2D5F.0020.0002] -0F8E ; [.2D60.0020.0002] -0F8C ; [.2D61.0020.0002] -0F8F ; [.2D62.0020.0002] -0F8A ; [.2D63.0020.0002] -0F8B ; [.2D64.0020.0002] -0F71 ; [.2D65.0020.0002] -0F72 ; [.2D66.0020.0002] -0F73 ; [.2D67.0020.0002] -0F71 0F72 ; [.2D67.0020.0002] -0F80 ; [.2D68.0020.0002] -0F81 ; [.2D69.0020.0002] -0F71 0F80 ; [.2D69.0020.0002] -0F74 ; [.2D6A.0020.0002] -0F75 ; [.2D6B.0020.0002] -0F71 0F74 ; [.2D6B.0020.0002] -0F76 ; [.2D6C.0020.0002] -0FB2 0F80 ; [.2D6C.0020.0002] -0F77 ; [.2D6D.0020.0002] -0FB2 0F71 0F80 ; [.2D6D.0020.0002] -0FB2 0F81 ; [.2D6D.0020.0002] -0F78 ; [.2D6E.0020.0002] -0FB3 0F80 ; [.2D6E.0020.0002] -0F79 ; [.2D6F.0020.0002] -0FB3 0F71 0F80 ; [.2D6F.0020.0002] -0FB3 0F81 ; [.2D6F.0020.0002] -0F7A ; [.2D70.0020.0002] -0F7B ; [.2D71.0020.0002] -0F7C ; [.2D72.0020.0002] -0F7D ; [.2D73.0020.0002] -0F84 ; [.2D74.0020.0002] -1C00 ; [.2D75.0020.0002] -1C01 ; [.2D76.0020.0002] -1C02 ; [.2D77.0020.0002] -1C03 ; [.2D78.0020.0002] -1C04 ; [.2D79.0020.0002] -1C05 ; [.2D7A.0020.0002] -1C06 ; [.2D7B.0020.0002] -1C07 ; [.2D7C.0020.0002] -1C08 ; [.2D7D.0020.0002] -1C09 ; [.2D7E.0020.0002] -1C4D ; [.2D7F.0020.0002] -1C4E ; [.2D80.0020.0002] -1C4F ; [.2D81.0020.0002] -1C0A ; [.2D82.0020.0002] -1C0B ; [.2D83.0020.0002] -1C0C ; [.2D84.0020.0002] -1C0D ; [.2D85.0020.0002] -1C0E ; [.2D86.0020.0002] -1C0F ; [.2D87.0020.0002] -1C10 ; [.2D88.0020.0002] -1C11 ; [.2D89.0020.0002] -1C12 ; [.2D8A.0020.0002] -1C13 ; [.2D8B.0020.0002] -1C14 ; [.2D8C.0020.0002] -1C15 ; [.2D8D.0020.0002] -1C16 ; [.2D8E.0020.0002] -1C17 ; [.2D8F.0020.0002] -1C18 ; [.2D90.0020.0002] -1C19 ; [.2D91.0020.0002] -1C1A ; [.2D92.0020.0002] -1C24 ; [.2D93.0020.0002] -1C1B ; [.2D94.0020.0002] -1C25 ; [.2D95.0020.0002] -1C1C ; [.2D96.0020.0002] -1C1D ; [.2D97.0020.0002] -1C1E ; [.2D98.0020.0002] -1C1F ; [.2D99.0020.0002] -1C20 ; [.2D9A.0020.0002] -1C21 ; [.2D9B.0020.0002] -1C22 ; [.2D9C.0020.0002] -1C23 ; [.2D9D.0020.0002] -1C36 ; [.2D9E.0020.0002] -1C26 ; [.2D9F.0020.0002] -1C27 ; [.2DA0.0020.0002] -1C28 ; [.2DA1.0020.0002] -1C29 ; [.2DA2.0020.0002] -1C2A ; [.2DA3.0020.0002] -1C2B ; [.2DA4.0020.0002] -1C2C ; [.2DA5.0020.0002] -1C2D ; [.2DA6.0020.0002] -1C2E ; [.2DA7.0020.0002] -1C2F ; [.2DA8.0020.0002] -1C30 ; [.2DA9.0020.0002] -1C31 ; [.2DAA.0020.0002] -1C32 ; [.2DAB.0020.0002] -1C33 ; [.2DAC.0020.0002] -1C34 ; [.2DAD.0020.0002] -1C35 ; [.2DAE.0020.0002] -A840 ; [.2DAF.0020.0002] -A841 ; [.2DB0.0020.0002] -A842 ; [.2DB1.0020.0002] -A843 ; [.2DB2.0020.0002] -A844 ; [.2DB3.0020.0002] -A845 ; [.2DB4.0020.0002] -A846 ; [.2DB5.0020.0002] -A847 ; [.2DB6.0020.0002] -A869 ; [.2DB7.0020.0002] -A86A ; [.2DB8.0020.0002] -A86B ; [.2DB9.0020.0002] -A86C ; [.2DBA.0020.0002] -A848 ; [.2DBB.0020.0002] -A849 ; [.2DBC.0020.0002] -A84A ; [.2DBD.0020.0002] -A84B ; [.2DBE.0020.0002] -A84C ; [.2DBF.0020.0002] -A84D ; [.2DC0.0020.0002] -A84E ; [.2DC1.0020.0002] -A84F ; [.2DC2.0020.0002] -A850 ; [.2DC3.0020.0002] -A851 ; [.2DC4.0020.0002] -A852 ; [.2DC5.0020.0002] -A853 ; [.2DC6.0020.0002] -A867 ; [.2DC7.0020.0002] -A854 ; [.2DC8.0020.0002] -A855 ; [.2DC9.0020.0002] -A856 ; [.2DCA.0020.0002] -A857 ; [.2DCB.0020.0002] -A868 ; [.2DCC.0020.0002] -A86D ; [.2DCD.0020.0002] -A858 ; [.2DCE.0020.0002] -A871 ; [.2DCF.0020.0002] -A872 ; [.2DD0.0020.0002] -A859 ; [.2DD1.0020.0002] -A85A ; [.2DD2.0020.0002] -A86E ; [.2DD3.0020.0002] -A85B ; [.2DD4.0020.0002] -A85C ; [.2DD5.0020.0002] -A86F ; [.2DD6.0020.0002] -A870 ; [.2DD7.0020.0002] -A85D ; [.2DD8.0020.0002] -A862 ; [.2DD9.0020.0002] -A863 ; [.2DDA.0020.0002] -A864 ; [.2DDB.0020.0002] -A865 ; [.2DDC.0020.0002] -A85E ; [.2DDD.0020.0002] -A85F ; [.2DDE.0020.0002] -A860 ; [.2DDF.0020.0002] -A861 ; [.2DE0.0020.0002] -A866 ; [.2DE1.0020.0002] -A873 ; [.2DE2.0020.0002] -1900 ; [.2DE3.0020.0002] -1901 ; [.2DE4.0020.0002] -1902 ; [.2DE5.0020.0002] -1903 ; [.2DE6.0020.0002] -1904 ; [.2DE7.0020.0002] -1905 ; [.2DE8.0020.0002] -1906 ; [.2DE9.0020.0002] -1907 ; [.2DEA.0020.0002] -1908 ; [.2DEB.0020.0002] -191D ; [.2DEB.0020.0004][.2E09.0020.0004] -1909 ; [.2DEC.0020.0002] -190A ; [.2DED.0020.0002] -190B ; [.2DEE.0020.0002] -191E ; [.2DEE.0020.0004][.2E0A.0020.0004] -190C ; [.2DEF.0020.0002] -190D ; [.2DF0.0020.0002] -190E ; [.2DF1.0020.0002] -190F ; [.2DF2.0020.0002] -1910 ; [.2DF3.0020.0002] -1911 ; [.2DF4.0020.0002] -1912 ; [.2DF5.0020.0002] -1913 ; [.2DF6.0020.0002] -1914 ; [.2DF7.0020.0002] -1915 ; [.2DF8.0020.0002] -1916 ; [.2DF9.0020.0002] -1917 ; [.2DFA.0020.0002] -1918 ; [.2DFB.0020.0002] -1919 ; [.2DFC.0020.0002] -191A ; [.2DFD.0020.0002] -191B ; [.2DFE.0020.0002] -191C ; [.2DFF.0020.0002] -1920 ; [.2E00.0020.0002] -1921 ; [.2E01.0020.0002] -1922 ; [.2E02.0020.0002] -1923 ; [.2E03.0020.0002] -1924 ; [.2E04.0020.0002] -1925 ; [.2E05.0020.0002] -1926 ; [.2E06.0020.0002] -1927 ; [.2E07.0020.0002] -1928 ; [.2E08.0020.0002] -1929 ; [.2E09.0020.0002] -192A ; [.2E0A.0020.0002] -192B ; [.2E0B.0020.0002] -1930 ; [.2E0C.0020.0002] -1931 ; [.2E0D.0020.0002] -1932 ; [.2E0E.0020.0002] -1933 ; [.2E0F.0020.0002] -1934 ; [.2E10.0020.0002] -1935 ; [.2E11.0020.0002] -1936 ; [.2E12.0020.0002] -1937 ; [.2E13.0020.0002] -1938 ; [.2E14.0020.0002] -1700 ; [.2E15.0020.0002] -1701 ; [.2E16.0020.0002] -1702 ; [.2E17.0020.0002] -1703 ; [.2E18.0020.0002] -1704 ; [.2E19.0020.0002] -1705 ; [.2E1A.0020.0002] -1706 ; [.2E1B.0020.0002] -1707 ; [.2E1C.0020.0002] -1708 ; [.2E1D.0020.0002] -1709 ; [.2E1E.0020.0002] -170A ; [.2E1F.0020.0002] -170B ; [.2E20.0020.0002] -170C ; [.2E21.0020.0002] -170E ; [.2E22.0020.0002] -170F ; [.2E23.0020.0002] -1710 ; [.2E24.0020.0002] -1711 ; [.2E25.0020.0002] -1712 ; [.2E26.0020.0002] -1713 ; [.2E27.0020.0002] -1714 ; [.2E28.0020.0002] -1720 ; [.2E29.0020.0002] -1721 ; [.2E2A.0020.0002] -1722 ; [.2E2B.0020.0002] -1723 ; [.2E2C.0020.0002] -1724 ; [.2E2D.0020.0002] -1725 ; [.2E2E.0020.0002] -1726 ; [.2E2F.0020.0002] -1727 ; [.2E30.0020.0002] -1728 ; [.2E31.0020.0002] -1729 ; [.2E32.0020.0002] -172A ; [.2E33.0020.0002] -172B ; [.2E34.0020.0002] -172C ; [.2E35.0020.0002] -172D ; [.2E36.0020.0002] -172E ; [.2E37.0020.0002] -172F ; [.2E38.0020.0002] -1730 ; [.2E39.0020.0002] -1731 ; [.2E3A.0020.0002] -1732 ; [.2E3B.0020.0002] -1733 ; [.2E3C.0020.0002] -1734 ; [.2E3D.0020.0002] -1740 ; [.2E3E.0020.0002] -1741 ; [.2E3F.0020.0002] -1742 ; [.2E40.0020.0002] -1743 ; [.2E41.0020.0002] -1744 ; [.2E42.0020.0002] -1745 ; [.2E43.0020.0002] -1746 ; [.2E44.0020.0002] -1747 ; [.2E45.0020.0002] -1748 ; [.2E46.0020.0002] -1749 ; [.2E47.0020.0002] -174A ; [.2E48.0020.0002] -174B ; [.2E49.0020.0002] -174C ; [.2E4A.0020.0002] -174D ; [.2E4B.0020.0002] -174E ; [.2E4C.0020.0002] -174F ; [.2E4D.0020.0002] -1750 ; [.2E4E.0020.0002] -1751 ; [.2E4F.0020.0002] -1752 ; [.2E50.0020.0002] -1753 ; [.2E51.0020.0002] -1760 ; [.2E52.0020.0002] -1761 ; [.2E53.0020.0002] -1762 ; [.2E54.0020.0002] -1763 ; [.2E55.0020.0002] -1764 ; [.2E56.0020.0002] -1765 ; [.2E57.0020.0002] -1766 ; [.2E58.0020.0002] -1767 ; [.2E59.0020.0002] -1768 ; [.2E5A.0020.0002] -1769 ; [.2E5B.0020.0002] -176A ; [.2E5C.0020.0002] -176B ; [.2E5D.0020.0002] -176C ; [.2E5E.0020.0002] -176E ; [.2E5F.0020.0002] -176F ; [.2E60.0020.0002] -1770 ; [.2E61.0020.0002] -1772 ; [.2E62.0020.0002] -1773 ; [.2E63.0020.0002] -1A00 ; [.2E64.0020.0002] -1A01 ; [.2E65.0020.0002] -1A02 ; [.2E66.0020.0002] -1A03 ; [.2E67.0020.0002] -1A04 ; [.2E68.0020.0002] -1A05 ; [.2E69.0020.0002] -1A06 ; [.2E6A.0020.0002] -1A07 ; [.2E6B.0020.0002] -1A08 ; [.2E6C.0020.0002] -1A09 ; [.2E6D.0020.0002] -1A0A ; [.2E6E.0020.0002] -1A0B ; [.2E6F.0020.0002] -1A0C ; [.2E70.0020.0002] -1A0D ; [.2E71.0020.0002] -1A0E ; [.2E72.0020.0002] -1A0F ; [.2E73.0020.0002] -1A10 ; [.2E74.0020.0002] -1A11 ; [.2E75.0020.0002] -1A12 ; [.2E76.0020.0002] -1A13 ; [.2E77.0020.0002] -1A14 ; [.2E78.0020.0002] -1A15 ; [.2E79.0020.0002] -1A16 ; [.2E7A.0020.0002] -1A17 ; [.2E7B.0020.0002] -1A18 ; [.2E7C.0020.0002] -1A19 ; [.2E7D.0020.0002] -1A1A ; [.2E7E.0020.0002] -1A1B ; [.2E7F.0020.0002] -1BC0 ; [.2E80.0020.0002] -1BC1 ; [.2E80.0020.0004] -1BC2 ; [.2E81.0020.0002] -1BC3 ; [.2E81.0020.0004] -1BC4 ; [.2E81.0020.0004] -1BC5 ; [.2E82.0020.0002] -1BC6 ; [.2E82.0020.0004] -1BC7 ; [.2E83.0020.0002] -1BC8 ; [.2E83.0020.0004] -1BC9 ; [.2E84.0020.0002] -1BCA ; [.2E84.0020.0004] -1BCB ; [.2E85.0020.0002] -1BCC ; [.2E85.0020.0004] -1BCD ; [.2E85.0020.0004] -1BCE ; [.2E86.0020.0002] -1BCF ; [.2E86.0020.0004] -1BD0 ; [.2E87.0020.0002] -1BD1 ; [.2E88.0020.0002] -1BD2 ; [.2E89.0020.0002] -1BD3 ; [.2E89.0020.0004] -1BD4 ; [.2E8A.0020.0002] -1BD5 ; [.2E8A.0020.0004] -1BD6 ; [.2E8B.0020.0002] -1BD7 ; [.2E8B.0020.0004] -1BD8 ; [.2E8C.0020.0002] -1BD9 ; [.2E8C.0020.0004] -1BDA ; [.2E8C.0020.0004] -1BDB ; [.2E8D.0020.0002] -1BDC ; [.2E8D.0020.0004] -1BDD ; [.2E8E.0020.0002] -1BDE ; [.2E8F.0020.0002] -1BDF ; [.2E8F.0020.0004] -1BE0 ; [.2E90.0020.0002] -1BE1 ; [.2E91.0020.0002] -1BE2 ; [.2E92.0020.0002] -1BE3 ; [.2E93.0020.0002] -1BE4 ; [.2E94.0020.0002] -1BE5 ; [.2E95.0020.0002] -1BE7 ; [.2E96.0020.0002] -1BE8 ; [.2E96.0020.0004] -1BE9 ; [.2E97.0020.0002] -1BEA ; [.2E98.0020.0002] -1BEB ; [.2E98.0020.0004] -1BEC ; [.2E99.0020.0002] -1BED ; [.2E99.0020.0004] -1BEE ; [.2E9A.0020.0002] -1BEF ; [.2E9A.0020.0004] -1BF0 ; [.2E9B.0020.0002] -1BF1 ; [.2E9C.0020.0002] -1BF2 ; [.2E9D.0020.0002] -1BF3 ; [.2E9E.0020.0002] -A930 ; [.2E9F.0020.0002] -A931 ; [.2EA0.0020.0002] -A932 ; [.2EA1.0020.0002] -A933 ; [.2EA2.0020.0002] -A934 ; [.2EA3.0020.0002] -A935 ; [.2EA4.0020.0002] -A936 ; [.2EA5.0020.0002] -A937 ; [.2EA6.0020.0002] -A938 ; [.2EA7.0020.0002] -A939 ; [.2EA8.0020.0002] -A93A ; [.2EA9.0020.0002] -A93B ; [.2EAA.0020.0002] -A93C ; [.2EAB.0020.0002] -A93D ; [.2EAC.0020.0002] -A93E ; [.2EAD.0020.0002] -A93F ; [.2EAE.0020.0002] -A940 ; [.2EAF.0020.0002] -A941 ; [.2EB0.0020.0002] -A942 ; [.2EB1.0020.0002] -A943 ; [.2EB2.0020.0002] -A944 ; [.2EB3.0020.0002] -A945 ; [.2EB4.0020.0002] -A946 ; [.2EB5.0020.0002] -A947 ; [.2EB6.0020.0002] -A948 ; [.2EB7.0020.0002] -A949 ; [.2EB8.0020.0002] -A94A ; [.2EB9.0020.0002] -A94B ; [.2EBA.0020.0002] -A94C ; [.2EBB.0020.0002] -A94D ; [.2EBC.0020.0002] -A94E ; [.2EBD.0020.0002] -A94F ; [.2EBE.0020.0002] -A950 ; [.2EBF.0020.0002] -A951 ; [.2EC0.0020.0002] -A952 ; [.2EC1.0020.0002] -A953 ; [.2EC2.0020.0002] -A90A ; [.2EC3.0020.0002] -A90B ; [.2EC4.0020.0002] -A90C ; [.2EC5.0020.0002] -A90D ; [.2EC6.0020.0002] -A90E ; [.2EC7.0020.0002] -A90F ; [.2EC8.0020.0002] -A910 ; [.2EC9.0020.0002] -A911 ; [.2ECA.0020.0002] -A912 ; [.2ECB.0020.0002] -A913 ; [.2ECC.0020.0002] -A914 ; [.2ECD.0020.0002] -A915 ; [.2ECE.0020.0002] -A916 ; [.2ECF.0020.0002] -A917 ; [.2ED0.0020.0002] -A918 ; [.2ED1.0020.0002] -A919 ; [.2ED2.0020.0002] -A91A ; [.2ED3.0020.0002] -A91B ; [.2ED4.0020.0002] -A91C ; [.2ED5.0020.0002] -A91D ; [.2ED6.0020.0002] -A91E ; [.2ED7.0020.0002] -A91F ; [.2ED8.0020.0002] -A920 ; [.2ED9.0020.0002] -A921 ; [.2EDA.0020.0002] -A922 ; [.2EDB.0020.0002] -A923 ; [.2EDC.0020.0002] -A924 ; [.2EDD.0020.0002] -A925 ; [.2EDE.0020.0002] -A926 ; [.2EDF.0020.0002] -A927 ; [.2EE0.0020.0002] -A928 ; [.2EE1.0020.0002] -A929 ; [.2EE2.0020.0002] -A92A ; [.2EE3.0020.0002] -1000 ; [.2EE4.0020.0002] -1075 ; [.2EE5.0020.0002] -1001 ; [.2EE6.0020.0002] -1076 ; [.2EE7.0020.0002] -1002 ; [.2EE8.0020.0002] -1077 ; [.2EE9.0020.0002] -AA60 ; [.2EEA.0020.0002] -A9E9 ; [.2EEB.0020.0002] -1003 ; [.2EEC.0020.0002] -A9E0 ; [.2EED.0020.0002] -A9EA ; [.2EEE.0020.0002] -1004 ; [.2EEF.0020.0002] -105A ; [.2EF0.0020.0002] -1005 ; [.2EF1.0020.0002] -1078 ; [.2EF2.0020.0002] -AA61 ; [.2EF3.0020.0002] -1006 ; [.2EF4.0020.0002] -A9E1 ; [.2EF5.0020.0002] -AA62 ; [.2EF6.0020.0002] -AA7E ; [.2EF7.0020.0002] -1007 ; [.2EF8.0020.0002] -AA63 ; [.2EF9.0020.0002] -A9EB ; [.2EFA.0020.0002] -1079 ; [.2EFB.0020.0002] -AA72 ; [.2EFC.0020.0002] -1008 ; [.2EFD.0020.0002] -105B ; [.2EFE.0020.0002] -A9E2 ; [.2EFF.0020.0002] -AA64 ; [.2F00.0020.0002] -A9EC ; [.2F01.0020.0002] -1061 ; [.2F02.0020.0002] -AA7F ; [.2F03.0020.0002] -1009 ; [.2F04.0020.0002] -107A ; [.2F05.0020.0002] -AA65 ; [.2F06.0020.0002] -A9E7 ; [.2F07.0020.0002] -100A ; [.2F08.0020.0002] -100B ; [.2F09.0020.0002] -AA66 ; [.2F0A.0020.0002] -100C ; [.2F0B.0020.0002] -AA67 ; [.2F0C.0020.0002] -100D ; [.2F0D.0020.0002] -AA68 ; [.2F0E.0020.0002] -A9ED ; [.2F0F.0020.0002] -100E ; [.2F10.0020.0002] -AA69 ; [.2F11.0020.0002] -A9EE ; [.2F12.0020.0002] -100F ; [.2F13.0020.0002] -106E ; [.2F14.0020.0002] -A9E3 ; [.2F15.0020.0002] -A9EF ; [.2F16.0020.0002] -1010 ; [.2F17.0020.0002] -1011 ; [.2F18.0020.0002] -1012 ; [.2F19.0020.0002] -107B ; [.2F1A.0020.0002] -A9FB ; [.2F1B.0020.0002] -1013 ; [.2F1C.0020.0002] -AA6A ; [.2F1D.0020.0002] -A9FC ; [.2F1E.0020.0002] -1014 ; [.2F1F.0020.0002] -107C ; [.2F20.0020.0002] -AA6B ; [.2F21.0020.0002] -105E ; [.2F22.0020.0002] -1015 ; [.2F23.0020.0002] -1016 ; [.2F24.0020.0002] -107D ; [.2F25.0020.0002] -107E ; [.2F26.0020.0002] -AA6F ; [.2F27.0020.0002] -108E ; [.2F28.0020.0002] -A9E8 ; [.2F29.0020.0002] -1017 ; [.2F2A.0020.0002] -107F ; [.2F2B.0020.0002] -A9FD ; [.2F2C.0020.0002] -1018 ; [.2F2D.0020.0002] -A9E4 ; [.2F2E.0020.0002] -A9FE ; [.2F2F.0020.0002] -1019 ; [.2F30.0020.0002] -105F ; [.2F31.0020.0002] -101A ; [.2F32.0020.0002] -103B ; [.2F33.0020.0002] -101B ; [.2F34.0020.0002] -AA73 ; [.2F35.0020.0002] -AA7A ; [.2F36.0020.0002] -103C ; [.2F37.0020.0002] -101C ; [.2F38.0020.0002] -1060 ; [.2F39.0020.0002] -101D ; [.2F3A.0020.0002] -103D ; [.2F3B.0020.0002] -1082 ; [.2F3C.0020.0002] -1080 ; [.2F3D.0020.0002] -1050 ; [.2F3E.0020.0002] -1051 ; [.2F3F.0020.0002] -1065 ; [.2F40.0020.0002] -101E ; [.2F41.0020.0002] -103F ; [.2F41.0020.0004][.2F7A.0020.0004][.2F41.0020.0004] -AA6C ; [.2F42.0020.0002] -101F ; [.2F43.0020.0002] -1081 ; [.2F44.0020.0002] -AA6D ; [.2F45.0020.0002] -103E ; [.2F46.0020.0002] -AA6E ; [.2F47.0020.0002] -AA71 ; [.2F48.0020.0002] -1020 ; [.2F49.0020.0002] -A9FA ; [.2F4A.0020.0002] -105C ; [.2F4B.0020.0002] -105D ; [.2F4C.0020.0002] -106F ; [.2F4D.0020.0002] -1070 ; [.2F4E.0020.0002] -1066 ; [.2F4F.0020.0002] -1021 ; [.2F50.0020.0002] -1022 ; [.2F51.0020.0002] -1023 ; [.2F52.0020.0002] -1024 ; [.2F53.0020.0002] -1025 ; [.2F54.0020.0002] -1026 ; [.2F55.0020.0002] -1025 102E ; [.2F55.0020.0002] -1052 ; [.2F56.0020.0002] -1053 ; [.2F57.0020.0002] -1054 ; [.2F58.0020.0002] -1055 ; [.2F59.0020.0002] -1027 ; [.2F5A.0020.0002] -1028 ; [.2F5B.0020.0002] -1029 ; [.2F5C.0020.0002] -102A ; [.2F5D.0020.0002] -102C ; [.2F5E.0020.0002] -102B ; [.2F5E.0020.0004] -1083 ; [.2F5F.0020.0002] -1072 ; [.2F60.0020.0002] -109C ; [.2F61.0020.0002] -102D ; [.2F62.0020.0002] -1071 ; [.2F63.0020.0002] -102E ; [.2F64.0020.0002] -1033 ; [.2F65.0020.0002] -102F ; [.2F66.0020.0002] -1073 ; [.2F67.0020.0002] -1074 ; [.2F68.0020.0002] -1030 ; [.2F69.0020.0002] -1056 ; [.2F6A.0020.0002] -1057 ; [.2F6B.0020.0002] -1058 ; [.2F6C.0020.0002] -1059 ; [.2F6D.0020.0002] -1031 ; [.2F6E.0020.0002] -1084 ; [.2F6F.0020.0002] -1035 ; [.2F70.0020.0002] -1085 ; [.2F71.0020.0002] -1032 ; [.2F72.0020.0002] -109D ; [.2F73.0020.0002] -1034 ; [.2F74.0020.0002] -1062 ; [.2F75.0020.0002] -1067 ; [.2F76.0020.0002] -1068 ; [.2F77.0020.0002] -A9E5 ; [.2F78.0020.0002] -1086 ; [.2F79.0020.0002] -1039 ; [.2F7A.0020.0002] -103A ; [.2F7B.0020.0002] -1063 ; [.2F7C.0020.0002] -1064 ; [.2F7D.0020.0002] -1069 ; [.2F7E.0020.0002] -106A ; [.2F7F.0020.0002] -106B ; [.2F80.0020.0002] -106C ; [.2F81.0020.0002] -106D ; [.2F82.0020.0002] -1087 ; [.2F83.0020.0002] -108B ; [.2F84.0020.0002] -1088 ; [.2F85.0020.0002] -108C ; [.2F86.0020.0002] -108D ; [.2F87.0020.0002] -1089 ; [.2F88.0020.0002] -108A ; [.2F89.0020.0002] -108F ; [.2F8A.0020.0002] -109A ; [.2F8B.0020.0002] -109B ; [.2F8C.0020.0002] -AA7B ; [.2F8D.0020.0002] -AA7C ; [.2F8E.0020.0002] -AA7D ; [.2F8F.0020.0002] -AA74 ; [.2F90.0020.0002] -AA75 ; [.2F91.0020.0002] -AA76 ; [.2F92.0020.0002] -11103 ; [.2F93.0020.0002] -11104 ; [.2F94.0020.0002] -11105 ; [.2F95.0020.0002] -11106 ; [.2F96.0020.0002] -11107 ; [.2F97.0020.0002] -11108 ; [.2F98.0020.0002] -11109 ; [.2F99.0020.0002] -1110A ; [.2F9A.0020.0002] -1110B ; [.2F9B.0020.0002] -1110C ; [.2F9C.0020.0002] -1110D ; [.2F9D.0020.0002] -1110E ; [.2F9E.0020.0002] -1110F ; [.2F9F.0020.0002] -11110 ; [.2FA0.0020.0002] -11111 ; [.2FA1.0020.0002] -11112 ; [.2FA2.0020.0002] -11113 ; [.2FA3.0020.0002] -11114 ; [.2FA4.0020.0002] -11115 ; [.2FA5.0020.0002] -11116 ; [.2FA6.0020.0002] -11117 ; [.2FA7.0020.0002] -11118 ; [.2FA8.0020.0002] -11119 ; [.2FA9.0020.0002] -1111A ; [.2FAA.0020.0002] -1111B ; [.2FAB.0020.0002] -1111C ; [.2FAC.0020.0002] -1111D ; [.2FAD.0020.0002] -1111E ; [.2FAE.0020.0002] -1111F ; [.2FAF.0020.0002] -11120 ; [.2FB0.0020.0002] -11121 ; [.2FB1.0020.0002] -11122 ; [.2FB2.0020.0002] -11123 ; [.2FB3.0020.0002] -11124 ; [.2FB4.0020.0002] -11125 ; [.2FB5.0020.0002] -11126 ; [.2FB6.0020.0002] -11127 ; [.2FB7.0020.0002] -11128 ; [.2FB8.0020.0002] -11129 ; [.2FB9.0020.0002] -1112A ; [.2FBA.0020.0002] -1112B ; [.2FBB.0020.0002] -1112C ; [.2FBC.0020.0002] -1112D ; [.2FBD.0020.0002] -1112E ; [.2FBE.0020.0002] -11131 11127 ; [.2FBE.0020.0002] -1112F ; [.2FBF.0020.0002] -11132 11127 ; [.2FBF.0020.0002] -11130 ; [.2FC0.0020.0002] -11131 ; [.2FC1.0020.0002] -11132 ; [.2FC2.0020.0002] -11133 ; [.2FC3.0020.0002] -11134 ; [.2FC4.0020.0002] -1780 ; [.2FC5.0020.0002] -1781 ; [.2FC6.0020.0002] -1782 ; [.2FC7.0020.0002] -1783 ; [.2FC8.0020.0002] -1784 ; [.2FC9.0020.0002] -1785 ; [.2FCA.0020.0002] -1786 ; [.2FCB.0020.0002] -1787 ; [.2FCC.0020.0002] -1788 ; [.2FCD.0020.0002] -1789 ; [.2FCE.0020.0002] -178A ; [.2FCF.0020.0002] -178B ; [.2FD0.0020.0002] -178C ; [.2FD1.0020.0002] -178D ; [.2FD2.0020.0002] -178E ; [.2FD3.0020.0002] -178F ; [.2FD4.0020.0002] -1790 ; [.2FD5.0020.0002] -1791 ; [.2FD6.0020.0002] -1792 ; [.2FD7.0020.0002] -1793 ; [.2FD8.0020.0002] -1794 ; [.2FD9.0020.0002] -1795 ; [.2FDA.0020.0002] -1796 ; [.2FDB.0020.0002] -1797 ; [.2FDC.0020.0002] -1798 ; [.2FDD.0020.0002] -1799 ; [.2FDE.0020.0002] -179A ; [.2FDF.0020.0002] -179B ; [.2FE0.0020.0002] -179C ; [.2FE1.0020.0002] -179D ; [.2FE2.0020.0002] -179E ; [.2FE3.0020.0002] -179F ; [.2FE4.0020.0002] -17A0 ; [.2FE5.0020.0002] -17A1 ; [.2FE6.0020.0002] -17A2 ; [.2FE7.0020.0002] -17DC ; [.2FE8.0020.0002] -17A3 ; [.2FE9.0020.0002] -17A4 ; [.2FEA.0020.0002] -17A5 ; [.2FEB.0020.0002] -17A6 ; [.2FEC.0020.0002] -17A7 ; [.2FED.0020.0002] -17A8 ; [.2FEE.0020.0002] -17A9 ; [.2FEF.0020.0002] -17AA ; [.2FF0.0020.0002] -17AB ; [.2FF1.0020.0002] -17AC ; [.2FF2.0020.0002] -17AD ; [.2FF3.0020.0002] -17AE ; [.2FF4.0020.0002] -17AF ; [.2FF5.0020.0002] -17B0 ; [.2FF6.0020.0002] -17B1 ; [.2FF7.0020.0002] -17B2 ; [.2FF8.0020.0002] -17B3 ; [.2FF9.0020.0002] -17B6 ; [.2FFA.0020.0002] -17B7 ; [.2FFB.0020.0002] -17B8 ; [.2FFC.0020.0002] -17B9 ; [.2FFD.0020.0002] -17BA ; [.2FFE.0020.0002] -17BB ; [.2FFF.0020.0002] -17BC ; [.3000.0020.0002] -17BD ; [.3001.0020.0002] -17BE ; [.3002.0020.0002] -17BF ; [.3003.0020.0002] -17C0 ; [.3004.0020.0002] -17C1 ; [.3005.0020.0002] -17C2 ; [.3006.0020.0002] -17C3 ; [.3007.0020.0002] -17C4 ; [.3008.0020.0002] -17C5 ; [.3009.0020.0002] -17D2 ; [.300A.0020.0002] -1950 ; [.300B.0020.0002] -1951 ; [.300C.0020.0002] -1952 ; [.300D.0020.0002] -1953 ; [.300E.0020.0002] -1954 ; [.300F.0020.0002] -1955 ; [.3010.0020.0002] -1956 ; [.3011.0020.0002] -1957 ; [.3012.0020.0002] -1958 ; [.3013.0020.0002] -1959 ; [.3014.0020.0002] -195A ; [.3015.0020.0002] -195B ; [.3016.0020.0002] -195C ; [.3017.0020.0002] -195D ; [.3018.0020.0002] -195E ; [.3019.0020.0002] -195F ; [.301A.0020.0002] -1960 ; [.301B.0020.0002] -1961 ; [.301C.0020.0002] -1962 ; [.301D.0020.0002] -1963 ; [.301E.0020.0002] -1964 ; [.301F.0020.0002] -1965 ; [.3020.0020.0002] -1966 ; [.3021.0020.0002] -1967 ; [.3022.0020.0002] -1968 ; [.3023.0020.0002] -1969 ; [.3024.0020.0002] -196A ; [.3025.0020.0002] -196B ; [.3026.0020.0002] -196C ; [.3027.0020.0002] -196D ; [.3028.0020.0002] -1970 ; [.3029.0020.0002] -1971 ; [.302A.0020.0002] -1972 ; [.302B.0020.0002] -1973 ; [.302C.0020.0002] -1974 ; [.302D.0020.0002] -1980 ; [.302E.0020.0002] -19B5 1980 ; [.302E.0020.0002][.305F.0020.0002] -19B6 1980 ; [.302E.0020.0002][.3060.0020.0002] -19B7 1980 ; [.302E.0020.0002][.3061.0020.0002] -19BA 1980 ; [.302E.0020.0002][.3064.0020.0002] -1981 ; [.302F.0020.0002] -19B5 1981 ; [.302F.0020.0002][.305F.0020.0002] -19B6 1981 ; [.302F.0020.0002][.3060.0020.0002] -19B7 1981 ; [.302F.0020.0002][.3061.0020.0002] -19BA 1981 ; [.302F.0020.0002][.3064.0020.0002] -1982 ; [.3030.0020.0002] -19B5 1982 ; [.3030.0020.0002][.305F.0020.0002] -19B6 1982 ; [.3030.0020.0002][.3060.0020.0002] -19B7 1982 ; [.3030.0020.0002][.3061.0020.0002] -19BA 1982 ; [.3030.0020.0002][.3064.0020.0002] -1983 ; [.3031.0020.0002] -19B5 1983 ; [.3031.0020.0002][.305F.0020.0002] -19B6 1983 ; [.3031.0020.0002][.3060.0020.0002] -19B7 1983 ; [.3031.0020.0002][.3061.0020.0002] -19BA 1983 ; [.3031.0020.0002][.3064.0020.0002] -1984 ; [.3032.0020.0002] -19B5 1984 ; [.3032.0020.0002][.305F.0020.0002] -19B6 1984 ; [.3032.0020.0002][.3060.0020.0002] -19B7 1984 ; [.3032.0020.0002][.3061.0020.0002] -19BA 1984 ; [.3032.0020.0002][.3064.0020.0002] -1985 ; [.3033.0020.0002] -19B5 1985 ; [.3033.0020.0002][.305F.0020.0002] -19B6 1985 ; [.3033.0020.0002][.3060.0020.0002] -19B7 1985 ; [.3033.0020.0002][.3061.0020.0002] -19BA 1985 ; [.3033.0020.0002][.3064.0020.0002] -1986 ; [.3034.0020.0002] -19B5 1986 ; [.3034.0020.0002][.305F.0020.0002] -19B6 1986 ; [.3034.0020.0002][.3060.0020.0002] -19B7 1986 ; [.3034.0020.0002][.3061.0020.0002] -19BA 1986 ; [.3034.0020.0002][.3064.0020.0002] -1987 ; [.3035.0020.0002] -19B5 1987 ; [.3035.0020.0002][.305F.0020.0002] -19B6 1987 ; [.3035.0020.0002][.3060.0020.0002] -19B7 1987 ; [.3035.0020.0002][.3061.0020.0002] -19BA 1987 ; [.3035.0020.0002][.3064.0020.0002] -1988 ; [.3036.0020.0002] -19B5 1988 ; [.3036.0020.0002][.305F.0020.0002] -19B6 1988 ; [.3036.0020.0002][.3060.0020.0002] -19B7 1988 ; [.3036.0020.0002][.3061.0020.0002] -19BA 1988 ; [.3036.0020.0002][.3064.0020.0002] -1989 ; [.3037.0020.0002] -19B5 1989 ; [.3037.0020.0002][.305F.0020.0002] -19B6 1989 ; [.3037.0020.0002][.3060.0020.0002] -19B7 1989 ; [.3037.0020.0002][.3061.0020.0002] -19BA 1989 ; [.3037.0020.0002][.3064.0020.0002] -198A ; [.3038.0020.0002] -19B5 198A ; [.3038.0020.0002][.305F.0020.0002] -19B6 198A ; [.3038.0020.0002][.3060.0020.0002] -19B7 198A ; [.3038.0020.0002][.3061.0020.0002] -19BA 198A ; [.3038.0020.0002][.3064.0020.0002] -198B ; [.3039.0020.0002] -19B5 198B ; [.3039.0020.0002][.305F.0020.0002] -19B6 198B ; [.3039.0020.0002][.3060.0020.0002] -19B7 198B ; [.3039.0020.0002][.3061.0020.0002] -19BA 198B ; [.3039.0020.0002][.3064.0020.0002] -198C ; [.303A.0020.0002] -19B5 198C ; [.303A.0020.0002][.305F.0020.0002] -19B6 198C ; [.303A.0020.0002][.3060.0020.0002] -19B7 198C ; [.303A.0020.0002][.3061.0020.0002] -19BA 198C ; [.303A.0020.0002][.3064.0020.0002] -198D ; [.303B.0020.0002] -19B5 198D ; [.303B.0020.0002][.305F.0020.0002] -19B6 198D ; [.303B.0020.0002][.3060.0020.0002] -19B7 198D ; [.303B.0020.0002][.3061.0020.0002] -19BA 198D ; [.303B.0020.0002][.3064.0020.0002] -198E ; [.303C.0020.0002] -19B5 198E ; [.303C.0020.0002][.305F.0020.0002] -19B6 198E ; [.303C.0020.0002][.3060.0020.0002] -19B7 198E ; [.303C.0020.0002][.3061.0020.0002] -19BA 198E ; [.303C.0020.0002][.3064.0020.0002] -198F ; [.303D.0020.0002] -19B5 198F ; [.303D.0020.0002][.305F.0020.0002] -19B6 198F ; [.303D.0020.0002][.3060.0020.0002] -19B7 198F ; [.303D.0020.0002][.3061.0020.0002] -19BA 198F ; [.303D.0020.0002][.3064.0020.0002] -1990 ; [.303E.0020.0002] -19B5 1990 ; [.303E.0020.0002][.305F.0020.0002] -19B6 1990 ; [.303E.0020.0002][.3060.0020.0002] -19B7 1990 ; [.303E.0020.0002][.3061.0020.0002] -19BA 1990 ; [.303E.0020.0002][.3064.0020.0002] -1991 ; [.303F.0020.0002] -19B5 1991 ; [.303F.0020.0002][.305F.0020.0002] -19B6 1991 ; [.303F.0020.0002][.3060.0020.0002] -19B7 1991 ; [.303F.0020.0002][.3061.0020.0002] -19BA 1991 ; [.303F.0020.0002][.3064.0020.0002] -1992 ; [.3040.0020.0002] -19B5 1992 ; [.3040.0020.0002][.305F.0020.0002] -19B6 1992 ; [.3040.0020.0002][.3060.0020.0002] -19B7 1992 ; [.3040.0020.0002][.3061.0020.0002] -19BA 1992 ; [.3040.0020.0002][.3064.0020.0002] -1993 ; [.3041.0020.0002] -19B5 1993 ; [.3041.0020.0002][.305F.0020.0002] -19B6 1993 ; [.3041.0020.0002][.3060.0020.0002] -19B7 1993 ; [.3041.0020.0002][.3061.0020.0002] -19BA 1993 ; [.3041.0020.0002][.3064.0020.0002] -1994 ; [.3042.0020.0002] -19B5 1994 ; [.3042.0020.0002][.305F.0020.0002] -19B6 1994 ; [.3042.0020.0002][.3060.0020.0002] -19B7 1994 ; [.3042.0020.0002][.3061.0020.0002] -19BA 1994 ; [.3042.0020.0002][.3064.0020.0002] -1995 ; [.3043.0020.0002] -19B5 1995 ; [.3043.0020.0002][.305F.0020.0002] -19B6 1995 ; [.3043.0020.0002][.3060.0020.0002] -19B7 1995 ; [.3043.0020.0002][.3061.0020.0002] -19BA 1995 ; [.3043.0020.0002][.3064.0020.0002] -1996 ; [.3044.0020.0002] -19B5 1996 ; [.3044.0020.0002][.305F.0020.0002] -19B6 1996 ; [.3044.0020.0002][.3060.0020.0002] -19B7 1996 ; [.3044.0020.0002][.3061.0020.0002] -19BA 1996 ; [.3044.0020.0002][.3064.0020.0002] -1997 ; [.3045.0020.0002] -19B5 1997 ; [.3045.0020.0002][.305F.0020.0002] -19B6 1997 ; [.3045.0020.0002][.3060.0020.0002] -19B7 1997 ; [.3045.0020.0002][.3061.0020.0002] -19BA 1997 ; [.3045.0020.0002][.3064.0020.0002] -1998 ; [.3046.0020.0002] -19B5 1998 ; [.3046.0020.0002][.305F.0020.0002] -19B6 1998 ; [.3046.0020.0002][.3060.0020.0002] -19B7 1998 ; [.3046.0020.0002][.3061.0020.0002] -19BA 1998 ; [.3046.0020.0002][.3064.0020.0002] -1999 ; [.3047.0020.0002] -19B5 1999 ; [.3047.0020.0002][.305F.0020.0002] -19B6 1999 ; [.3047.0020.0002][.3060.0020.0002] -19B7 1999 ; [.3047.0020.0002][.3061.0020.0002] -19BA 1999 ; [.3047.0020.0002][.3064.0020.0002] -199A ; [.3048.0020.0002] -19B5 199A ; [.3048.0020.0002][.305F.0020.0002] -19B6 199A ; [.3048.0020.0002][.3060.0020.0002] -19B7 199A ; [.3048.0020.0002][.3061.0020.0002] -19BA 199A ; [.3048.0020.0002][.3064.0020.0002] -199B ; [.3049.0020.0002] -19B5 199B ; [.3049.0020.0002][.305F.0020.0002] -19B6 199B ; [.3049.0020.0002][.3060.0020.0002] -19B7 199B ; [.3049.0020.0002][.3061.0020.0002] -19BA 199B ; [.3049.0020.0002][.3064.0020.0002] -199C ; [.304A.0020.0002] -19B5 199C ; [.304A.0020.0002][.305F.0020.0002] -19B6 199C ; [.304A.0020.0002][.3060.0020.0002] -19DE ; [.304A.0020.0004][.3060.0020.0004] -19DF ; [.304A.0020.0004][.3060.0020.0004][.306B.0020.0004] -19B7 199C ; [.304A.0020.0002][.3061.0020.0002] -19BA 199C ; [.304A.0020.0002][.3064.0020.0002] -199D ; [.304B.0020.0002] -19B5 199D ; [.304B.0020.0002][.305F.0020.0002] -19B6 199D ; [.304B.0020.0002][.3060.0020.0002] -19B7 199D ; [.304B.0020.0002][.3061.0020.0002] -19BA 199D ; [.304B.0020.0002][.3064.0020.0002] -199E ; [.304C.0020.0002] -19B5 199E ; [.304C.0020.0002][.305F.0020.0002] -19B6 199E ; [.304C.0020.0002][.3060.0020.0002] -19B7 199E ; [.304C.0020.0002][.3061.0020.0002] -19BA 199E ; [.304C.0020.0002][.3064.0020.0002] -199F ; [.304D.0020.0002] -19B5 199F ; [.304D.0020.0002][.305F.0020.0002] -19B6 199F ; [.304D.0020.0002][.3060.0020.0002] -19B7 199F ; [.304D.0020.0002][.3061.0020.0002] -19BA 199F ; [.304D.0020.0002][.3064.0020.0002] -19A0 ; [.304E.0020.0002] -19B5 19A0 ; [.304E.0020.0002][.305F.0020.0002] -19B6 19A0 ; [.304E.0020.0002][.3060.0020.0002] -19B7 19A0 ; [.304E.0020.0002][.3061.0020.0002] -19BA 19A0 ; [.304E.0020.0002][.3064.0020.0002] -19A1 ; [.304F.0020.0002] -19B5 19A1 ; [.304F.0020.0002][.305F.0020.0002] -19B6 19A1 ; [.304F.0020.0002][.3060.0020.0002] -19B7 19A1 ; [.304F.0020.0002][.3061.0020.0002] -19BA 19A1 ; [.304F.0020.0002][.3064.0020.0002] -19A2 ; [.3050.0020.0002] -19B5 19A2 ; [.3050.0020.0002][.305F.0020.0002] -19B6 19A2 ; [.3050.0020.0002][.3060.0020.0002] -19B7 19A2 ; [.3050.0020.0002][.3061.0020.0002] -19BA 19A2 ; [.3050.0020.0002][.3064.0020.0002] -19A3 ; [.3051.0020.0002] -19B5 19A3 ; [.3051.0020.0002][.305F.0020.0002] -19B6 19A3 ; [.3051.0020.0002][.3060.0020.0002] -19B7 19A3 ; [.3051.0020.0002][.3061.0020.0002] -19BA 19A3 ; [.3051.0020.0002][.3064.0020.0002] -19A4 ; [.3052.0020.0002] -19B5 19A4 ; [.3052.0020.0002][.305F.0020.0002] -19B6 19A4 ; [.3052.0020.0002][.3060.0020.0002] -19B7 19A4 ; [.3052.0020.0002][.3061.0020.0002] -19BA 19A4 ; [.3052.0020.0002][.3064.0020.0002] -19A5 ; [.3053.0020.0002] -19B5 19A5 ; [.3053.0020.0002][.305F.0020.0002] -19B6 19A5 ; [.3053.0020.0002][.3060.0020.0002] -19B7 19A5 ; [.3053.0020.0002][.3061.0020.0002] -19BA 19A5 ; [.3053.0020.0002][.3064.0020.0002] -19A6 ; [.3054.0020.0002] -19B5 19A6 ; [.3054.0020.0002][.305F.0020.0002] -19B6 19A6 ; [.3054.0020.0002][.3060.0020.0002] -19B7 19A6 ; [.3054.0020.0002][.3061.0020.0002] -19BA 19A6 ; [.3054.0020.0002][.3064.0020.0002] -19A7 ; [.3055.0020.0002] -19B5 19A7 ; [.3055.0020.0002][.305F.0020.0002] -19B6 19A7 ; [.3055.0020.0002][.3060.0020.0002] -19B7 19A7 ; [.3055.0020.0002][.3061.0020.0002] -19BA 19A7 ; [.3055.0020.0002][.3064.0020.0002] -19A8 ; [.3056.0020.0002] -19B5 19A8 ; [.3056.0020.0002][.305F.0020.0002] -19B6 19A8 ; [.3056.0020.0002][.3060.0020.0002] -19B7 19A8 ; [.3056.0020.0002][.3061.0020.0002] -19BA 19A8 ; [.3056.0020.0002][.3064.0020.0002] -19A9 ; [.3057.0020.0002] -19B5 19A9 ; [.3057.0020.0002][.305F.0020.0002] -19B6 19A9 ; [.3057.0020.0002][.3060.0020.0002] -19B7 19A9 ; [.3057.0020.0002][.3061.0020.0002] -19BA 19A9 ; [.3057.0020.0002][.3064.0020.0002] -19AA ; [.3058.0020.0002] -19B5 19AA ; [.3058.0020.0002][.305F.0020.0002] -19B6 19AA ; [.3058.0020.0002][.3060.0020.0002] -19B7 19AA ; [.3058.0020.0002][.3061.0020.0002] -19BA 19AA ; [.3058.0020.0002][.3064.0020.0002] -19AB ; [.3059.0020.0002] -19B5 19AB ; [.3059.0020.0002][.305F.0020.0002] -19B6 19AB ; [.3059.0020.0002][.3060.0020.0002] -19B7 19AB ; [.3059.0020.0002][.3061.0020.0002] -19BA 19AB ; [.3059.0020.0002][.3064.0020.0002] -19B0 ; [.305A.0020.0002] -19B1 ; [.305B.0020.0002] -19B2 ; [.305C.0020.0002] -19B3 ; [.305D.0020.0002] -19B4 ; [.305E.0020.0002] -19B5 ; [.305F.0020.0002] -19B6 ; [.3060.0020.0002] -19B7 ; [.3061.0020.0002] -19B8 ; [.3062.0020.0002] -19B9 ; [.3063.0020.0002] -19BA ; [.3064.0020.0002] -19BB ; [.3065.0020.0002] -19BC ; [.3066.0020.0002] -19BD ; [.3067.0020.0002] -19BE ; [.3068.0020.0002] -19BF ; [.3069.0020.0002] -19C0 ; [.306A.0020.0002] -19C1 ; [.306B.0020.0002] -19C2 ; [.306C.0020.0002] -19C3 ; [.306D.0020.0002] -19C4 ; [.306E.0020.0002] -19C5 ; [.306F.0020.0002] -19C6 ; [.3070.0020.0002] -19C7 ; [.3071.0020.0002] -19C8 ; [.3072.0020.0002] -19C9 ; [.3073.0020.0002] -1A20 ; [.3074.0020.0002] -1A21 ; [.3075.0020.0002] -1A22 ; [.3076.0020.0002] -1A23 ; [.3077.0020.0002] -1A24 ; [.3078.0020.0002] -1A25 ; [.3079.0020.0002] -1A26 ; [.307A.0020.0002] -1A58 ; [.307A.0020.0004] -1A59 ; [.307A.0020.0004] -1A27 ; [.307B.0020.0002] -1A28 ; [.307C.0020.0002] -1A29 ; [.307D.0020.0002] -1A2A ; [.307E.0020.0002] -1A2B ; [.307F.0020.0002] -1A2C ; [.3080.0020.0002] -1A2D ; [.3081.0020.0002] -1A2E ; [.3082.0020.0002] -1A2F ; [.3083.0020.0002] -1A30 ; [.3084.0020.0002] -1A31 ; [.3085.0020.0002] -1A32 ; [.3086.0020.0002] -1A33 ; [.3087.0020.0002] -1A34 ; [.3088.0020.0002] -1A35 ; [.3089.0020.0002] -1A36 ; [.308A.0020.0002] -1A37 ; [.308B.0020.0002] -1A38 ; [.308C.0020.0002] -1A39 ; [.308D.0020.0002] -1A3A ; [.308E.0020.0002] -1A3B ; [.308F.0020.0002] -1A5A ; [.308F.0020.0004] -1A5B ; [.308F.0020.0004] -1A3C ; [.3090.0020.0002] -1A3D ; [.3091.0020.0002] -1A3E ; [.3092.0020.0002] -1A3F ; [.3093.0020.0002] -1A40 ; [.3094.0020.0002] -1A41 ; [.3095.0020.0002] -1A42 ; [.3096.0020.0002] -1A43 ; [.3097.0020.0002] -1A44 ; [.3098.0020.0002] -1A45 ; [.3099.0020.0002] -1A46 ; [.309A.0020.0002] -1A54 ; [.309A.0020.0004][.30C0.0020.0004][.309A.0020.0004] -1A47 ; [.309B.0020.0002] -1A48 ; [.309C.0020.0002] -1A49 ; [.309D.0020.0002] -1A4A ; [.309E.0020.0002] -1A4B ; [.309F.0020.0002] -1A4C ; [.30A0.0020.0002] -1A53 ; [.30A1.0020.0002] -1A6B ; [.30A2.0020.0002] -1A55 ; [.30A3.0020.0002] -1A56 ; [.30A4.0020.0002] -1A57 ; [.30A5.0020.0002] -1A5C ; [.30A6.0020.0002] -1A5D ; [.30A7.0020.0002] -1A5E ; [.30A8.0020.0002] -1A4D ; [.30A9.0020.0002] -1A4E ; [.30AA.0020.0002] -1A4F ; [.30AB.0020.0002] -1A50 ; [.30AC.0020.0002] -1A51 ; [.30AD.0020.0002] -1A52 ; [.30AE.0020.0002] -1A61 ; [.30AF.0020.0002] -1A6C ; [.30B0.0020.0002] -1A62 ; [.30B1.0020.0002] -1A63 ; [.30B2.0020.0002] -1A64 ; [.30B2.0020.0004] -1A65 ; [.30B3.0020.0002] -1A66 ; [.30B4.0020.0002] -1A67 ; [.30B5.0020.0002] -1A68 ; [.30B6.0020.0002] -1A69 ; [.30B7.0020.0002] -1A6A ; [.30B8.0020.0002] -1A6E ; [.30B9.0020.0002] -1A6F ; [.30BA.0020.0002] -1A73 ; [.30BB.0020.0002] -1A70 ; [.30BC.0020.0002] -1A71 ; [.30BD.0020.0002] -1A72 ; [.30BE.0020.0002] -1A6D ; [.30BF.0020.0002] -1A60 ; [.30C0.0020.0002] -AA00 ; [.30C1.0020.0002] -AA01 ; [.30C2.0020.0002] -AA02 ; [.30C3.0020.0002] -AA03 ; [.30C4.0020.0002] -AA04 ; [.30C5.0020.0002] -AA05 ; [.30C6.0020.0002] -AA06 ; [.30C7.0020.0002] -AA07 ; [.30C8.0020.0002] -AA08 ; [.30C9.0020.0002] -AA09 ; [.30CA.0020.0002] -AA0A ; [.30CB.0020.0002] -AA0B ; [.30CC.0020.0002] -AA0C ; [.30CD.0020.0002] -AA0D ; [.30CE.0020.0002] -AA0E ; [.30CF.0020.0002] -AA0F ; [.30D0.0020.0002] -AA10 ; [.30D1.0020.0002] -AA11 ; [.30D2.0020.0002] -AA12 ; [.30D3.0020.0002] -AA13 ; [.30D4.0020.0002] -AA14 ; [.30D5.0020.0002] -AA15 ; [.30D6.0020.0002] -AA16 ; [.30D7.0020.0002] -AA17 ; [.30D8.0020.0002] -AA18 ; [.30D9.0020.0002] -AA19 ; [.30DA.0020.0002] -AA1A ; [.30DB.0020.0002] -AA1B ; [.30DC.0020.0002] -AA1C ; [.30DD.0020.0002] -AA1D ; [.30DE.0020.0002] -AA1E ; [.30DF.0020.0002] -AA1F ; [.30E0.0020.0002] -AA20 ; [.30E1.0020.0002] -AA21 ; [.30E2.0020.0002] -AA22 ; [.30E3.0020.0002] -AA23 ; [.30E4.0020.0002] -AA24 ; [.30E5.0020.0002] -AA25 ; [.30E6.0020.0002] -AA26 ; [.30E7.0020.0002] -AA27 ; [.30E8.0020.0002] -AA28 ; [.30E9.0020.0002] -AA33 ; [.30EA.0020.0002] -AA34 ; [.30EB.0020.0002] -AA35 ; [.30EC.0020.0002] -AA36 ; [.30ED.0020.0002] -AA29 ; [.30EE.0020.0002] -AA2A ; [.30EF.0020.0002] -AA2B ; [.30F0.0020.0002] -AA2C ; [.30F1.0020.0002] -AA2D ; [.30F2.0020.0002] -AA2E ; [.30F3.0020.0002] -AA2F ; [.30F4.0020.0002] -AA30 ; [.30F5.0020.0002] -AA31 ; [.30F6.0020.0002] -AA32 ; [.30F7.0020.0002] -AA40 ; [.30F8.0020.0002] -AA41 ; [.30F9.0020.0002] -AA42 ; [.30FA.0020.0002] -AA43 ; [.30FB.0020.0002] -AA44 ; [.30FC.0020.0002] -AA45 ; [.30FD.0020.0002] -AA46 ; [.30FE.0020.0002] -AA47 ; [.30FF.0020.0002] -AA48 ; [.3100.0020.0002] -AA49 ; [.3101.0020.0002] -AA4A ; [.3102.0020.0002] -AA4B ; [.3103.0020.0002] -AA4C ; [.3104.0020.0002] -AA4D ; [.3105.0020.0002] -1B05 ; [.3106.0020.0002] -1B06 ; [.3107.0020.0002] -1B05 1B35 ; [.3107.0020.0002] -1B07 ; [.3108.0020.0002] -1B08 ; [.3109.0020.0002] -1B07 1B35 ; [.3109.0020.0002] -1B09 ; [.310A.0020.0002] -1B0A ; [.310B.0020.0002] -1B09 1B35 ; [.310B.0020.0002] -1B0B ; [.310C.0020.0002] -1B0C ; [.310D.0020.0002] -1B0B 1B35 ; [.310D.0020.0002] -1B0D ; [.310E.0020.0002] -1B0E ; [.310F.0020.0002] -1B0D 1B35 ; [.310F.0020.0002] -1B0F ; [.3110.0020.0002] -1B10 ; [.3111.0020.0002] -1B11 ; [.3112.0020.0002] -1B12 ; [.3113.0020.0002] -1B11 1B35 ; [.3113.0020.0002] -1B13 ; [.3114.0020.0002] -1B45 ; [.3115.0020.0002] -1B46 ; [.3116.0020.0002] -1B14 ; [.3117.0020.0002] -1B15 ; [.3118.0020.0002] -1B16 ; [.3119.0020.0002] -1B17 ; [.311A.0020.0002] -1B18 ; [.311B.0020.0002] -1B19 ; [.311C.0020.0002] -1B1A ; [.311D.0020.0002] -1B1B ; [.311E.0020.0002] -1B1C ; [.311F.0020.0002] -1B1D ; [.3120.0020.0002] -1B1E ; [.3121.0020.0002] -1B1F ; [.3122.0020.0002] -1B20 ; [.3123.0020.0002] -1B21 ; [.3124.0020.0002] -1B22 ; [.3125.0020.0002] -1B47 ; [.3126.0020.0002] -1B23 ; [.3127.0020.0002] -1B24 ; [.3128.0020.0002] -1B25 ; [.3129.0020.0002] -1B26 ; [.312A.0020.0002] -1B27 ; [.312B.0020.0002] -1B48 ; [.312C.0020.0002] -1B28 ; [.312D.0020.0002] -1B29 ; [.312E.0020.0002] -1B2A ; [.312F.0020.0002] -1B2B ; [.3130.0020.0002] -1B2C ; [.3131.0020.0002] -1B2D ; [.3132.0020.0002] -1B2E ; [.3133.0020.0002] -1B2F ; [.3134.0020.0002] -1B49 ; [.3135.0020.0002] -1B30 ; [.3136.0020.0002] -1B31 ; [.3137.0020.0002] -1B32 ; [.3138.0020.0002] -1B4A ; [.3139.0020.0002] -1B4B ; [.313A.0020.0002] -1B33 ; [.313B.0020.0002] -1B35 ; [.313C.0020.0002] -1B36 ; [.313D.0020.0002] -1B37 ; [.313E.0020.0002] -1B38 ; [.313F.0020.0002] -1B39 ; [.3140.0020.0002] -1B3A ; [.3141.0020.0002] -1B3B ; [.3142.0020.0002] -1B3A 1B35 ; [.3142.0020.0002] -1B3C ; [.3143.0020.0002] -1B3D ; [.3144.0020.0002] -1B3C 1B35 ; [.3144.0020.0002] -1B3E ; [.3145.0020.0002] -1B3F ; [.3146.0020.0002] -1B40 ; [.3147.0020.0002] -1B3E 1B35 ; [.3147.0020.0002] -1B41 ; [.3148.0020.0002] -1B3F 1B35 ; [.3148.0020.0002] -1B42 ; [.3149.0020.0002] -1B43 ; [.314A.0020.0002] -1B42 1B35 ; [.314A.0020.0002] -1B44 ; [.314B.0020.0002] -A984 ; [.314C.0020.0002] -A985 ; [.314D.0020.0002] -A986 ; [.314E.0020.0002] -A987 ; [.314F.0020.0002] -A988 ; [.3150.0020.0002] -A989 ; [.3151.0020.0002] -A98A ; [.3152.0020.0002] -A98B ; [.3153.0020.0002] -A98C ; [.3154.0020.0002] -A98D ; [.3155.0020.0002] -A98E ; [.3156.0020.0002] -A98F ; [.3157.0020.0002] -A990 ; [.3158.0020.0002] -A991 ; [.3159.0020.0002] -A992 ; [.315A.0020.0002] -A993 ; [.315B.0020.0002] -A994 ; [.315C.0020.0002] -A995 ; [.315D.0020.0002] -A996 ; [.315E.0020.0002] -A997 ; [.315F.0020.0002] -A998 ; [.3160.0020.0002] -A999 ; [.3161.0020.0002] -A99A ; [.3162.0020.0002] -A99B ; [.3163.0020.0002] -A99C ; [.3164.0020.0002] -A99D ; [.3165.0020.0002] -A99E ; [.3166.0020.0002] -A99F ; [.3167.0020.0002] -A9A0 ; [.3168.0020.0002] -A9A1 ; [.3169.0020.0002] -A9A2 ; [.316A.0020.0002] -A9A3 ; [.316B.0020.0002] -A9A4 ; [.316C.0020.0002] -A9A5 ; [.316D.0020.0002] -A9A6 ; [.316E.0020.0002] -A9A7 ; [.316F.0020.0002] -A9A8 ; [.3170.0020.0002] -A9A9 ; [.3171.0020.0002] -A9AA ; [.3172.0020.0002] -A9BE ; [.3173.0020.0002] -A9AB ; [.3174.0020.0002] -A9AC ; [.3174.0020.0004] -A9BF ; [.3175.0020.0002] -A9AD ; [.3176.0020.0002] -A9AE ; [.3177.0020.0002] -A9AF ; [.3178.0020.0002] -A9B0 ; [.3179.0020.0002] -A9B1 ; [.317A.0020.0002] -A9B2 ; [.317B.0020.0002] -A9B4 ; [.317C.0020.0002] -A9BC ; [.317D.0020.0002] -A9B6 ; [.317E.0020.0002] -A9B7 ; [.317F.0020.0002] -A9B8 ; [.3180.0020.0002] -A9B9 ; [.3181.0020.0002] -A9BD ; [.3182.0020.0002] -A9BA ; [.3183.0020.0002] -A9BB ; [.3184.0020.0002] -A9B5 ; [.3185.0020.0002] -A9C0 ; [.3186.0020.0002] -1880 ; [.3187.0020.0002] -1881 ; [.3188.0020.0002] -1882 ; [.3189.0020.0002] -1883 ; [.318A.0020.0002] -1884 ; [.318B.0020.0002] -1885 ; [.318C.0020.0002] -1886 ; [.318D.0020.0002] -1843 ; [.318E.0020.0002] -1820 ; [.318F.0020.0002] -1887 ; [.3190.0020.0002] -1821 ; [.3191.0020.0002] -1844 ; [.3192.0020.0002] -185D ; [.3193.0020.0002] -1822 ; [.3194.0020.0002] -1845 ; [.3195.0020.0002] -185E ; [.3196.0020.0002] -1873 ; [.3197.0020.0002] -1888 ; [.3198.0020.0002] -185F ; [.3199.0020.0002] -1823 ; [.319A.0020.0002] -1846 ; [.319B.0020.0002] -1824 ; [.319C.0020.0002] -1847 ; [.319D.0020.0002] -1861 ; [.319E.0020.0002] -1825 ; [.319F.0020.0002] -1848 ; [.31A0.0020.0002] -1826 ; [.31A1.0020.0002] -1849 ; [.31A2.0020.0002] -1860 ; [.31A3.0020.0002] -1827 ; [.31A4.0020.0002] -1828 ; [.31A5.0020.0002] -1829 ; [.31A6.0020.0002] -184A ; [.31A7.0020.0002] -1862 ; [.31A8.0020.0002] -188A ; [.31A9.0020.0002] -189B ; [.31AA.0020.0002] -182A ; [.31AB.0020.0002] -184B ; [.31AC.0020.0002] -182B ; [.31AD.0020.0002] -184C ; [.31AE.0020.0002] -1866 ; [.31AF.0020.0002] -182C ; [.31B0.0020.0002] -184D ; [.31B1.0020.0002] -182D ; [.31B2.0020.0002] -184E ; [.31B3.0020.0002] -1864 ; [.31B4.0020.0002] -189A ; [.31B5.0020.0002] -1865 ; [.31B6.0020.0002] -182E ; [.31B7.0020.0002] -184F ; [.31B8.0020.0002] -182F ; [.31B9.0020.0002] -1830 ; [.31BA.0020.0002] -1831 ; [.31BB.0020.0002] -1867 ; [.31BC.0020.0002] -189C ; [.31BD.0020.0002] -189D ; [.31BE.0020.0002] -18A2 ; [.31BF.0020.0002] -18A4 ; [.31C0.0020.0002] -18A5 ; [.31C1.0020.0002] -1832 ; [.31C2.0020.0002] -1850 ; [.31C3.0020.0002] -1868 ; [.31C4.0020.0002] -1833 ; [.31C5.0020.0002] -1851 ; [.31C6.0020.0002] -1869 ; [.31C7.0020.0002] -1834 ; [.31C8.0020.0002] -1852 ; [.31C9.0020.0002] -1871 ; [.31CA.0020.0002] -185C ; [.31CB.0020.0002] -188B ; [.31CC.0020.0002] -1835 ; [.31CD.0020.0002] -1853 ; [.31CE.0020.0002] -186A ; [.31CF.0020.0002] -1877 ; [.31D0.0020.0002] -1836 ; [.31D1.0020.0002] -1855 ; [.31D2.0020.0002] -1872 ; [.31D3.0020.0002] -1837 ; [.31D4.0020.0002] -1875 ; [.31D5.0020.0002] -1838 ; [.31D6.0020.0002] -1856 ; [.31D7.0020.0002] -1839 ; [.31D8.0020.0002] -186B ; [.31D9.0020.0002] -1876 ; [.31DA.0020.0002] -183A ; [.31DB.0020.0002] -1857 ; [.31DC.0020.0002] -1863 ; [.31DD.0020.0002] -1874 ; [.31DE.0020.0002] -1889 ; [.31DF.0020.0002] -183B ; [.31E0.0020.0002] -183C ; [.31E1.0020.0002] -1854 ; [.31E2.0020.0002] -186E ; [.31E3.0020.0002] -183D ; [.31E4.0020.0002] -186F ; [.31E5.0020.0002] -1858 ; [.31E6.0020.0002] -186C ; [.31E7.0020.0002] -183E ; [.31E8.0020.0002] -1859 ; [.31E9.0020.0002] -186D ; [.31EA.0020.0002] -183F ; [.31EB.0020.0002] -1840 ; [.31EC.0020.0002] -1841 ; [.31ED.0020.0002] -1842 ; [.31EE.0020.0002] -185A ; [.31EF.0020.0002] -185B ; [.31F0.0020.0002] -1870 ; [.31F1.0020.0002] -188C ; [.31F2.0020.0002] -189E ; [.31F3.0020.0002] -188D ; [.31F4.0020.0002] -188E ; [.31F5.0020.0002] -189F ; [.31F6.0020.0002] -188F ; [.31F7.0020.0002] -1890 ; [.31F8.0020.0002] -1898 ; [.31F9.0020.0002] -18A0 ; [.31FA.0020.0002] -1891 ; [.31FB.0020.0002] -18A1 ; [.31FC.0020.0002] -1892 ; [.31FD.0020.0002] -1893 ; [.31FE.0020.0002] -18A8 ; [.31FF.0020.0002] -1894 ; [.3200.0020.0002] -18A3 ; [.3201.0020.0002] -1895 ; [.3202.0020.0002] -1899 ; [.3203.0020.0002] -1896 ; [.3204.0020.0002] -1897 ; [.3205.0020.0002] -18A6 ; [.3206.0020.0002] -18A7 ; [.3207.0020.0002] -18AA ; [.3208.0020.0002] -18A9 ; [.3209.0020.0002] -1C5A ; [.320A.0020.0002] -1C5B ; [.320B.0020.0002] -1C5C ; [.320C.0020.0002] -1C5D ; [.320D.0020.0002] -1C5E ; [.320E.0020.0002] -1C5F ; [.320F.0020.0002] -1C60 ; [.3210.0020.0002] -1C61 ; [.3211.0020.0002] -1C62 ; [.3212.0020.0002] -1C63 ; [.3213.0020.0002] -1C64 ; [.3214.0020.0002] -1C65 ; [.3215.0020.0002] -1C66 ; [.3216.0020.0002] -1C67 ; [.3217.0020.0002] -1C68 ; [.3218.0020.0002] -1C69 ; [.3219.0020.0002] -1C6A ; [.321A.0020.0002] -1C6B ; [.321B.0020.0002] -1C6C ; [.321C.0020.0002] -1C6D ; [.321D.0020.0002] -1C6E ; [.321E.0020.0002] -1C6F ; [.321F.0020.0002] -1C70 ; [.3220.0020.0002] -1C71 ; [.3221.0020.0002] -1C72 ; [.3222.0020.0002] -1C73 ; [.3223.0020.0002] -1C74 ; [.3224.0020.0002] -1C75 ; [.3225.0020.0002] -1C76 ; [.3226.0020.0002] -1C77 ; [.3227.0020.0002] -1C78 ; [.3228.0020.0002] -1C79 ; [.3229.0020.0002] -1C7A ; [.322A.0020.0002] -1C7B ; [.322B.0020.0002] -1C7C ; [.322C.0020.0002] -1C7D ; [.322D.0020.0002] -AB70 ; [.322E.0020.0002] -13A0 ; [.322E.0020.0008] -AB71 ; [.322F.0020.0002] -13A1 ; [.322F.0020.0008] -AB72 ; [.3230.0020.0002] -13A2 ; [.3230.0020.0008] -AB73 ; [.3231.0020.0002] -13A3 ; [.3231.0020.0008] -AB74 ; [.3232.0020.0002] -13A4 ; [.3232.0020.0008] -AB75 ; [.3233.0020.0002] -13A5 ; [.3233.0020.0008] -AB76 ; [.3234.0020.0002] -13A6 ; [.3234.0020.0008] -AB77 ; [.3235.0020.0002] -13A7 ; [.3235.0020.0008] -AB78 ; [.3236.0020.0002] -13A8 ; [.3236.0020.0008] -AB79 ; [.3237.0020.0002] -13A9 ; [.3237.0020.0008] -AB7A ; [.3238.0020.0002] -13AA ; [.3238.0020.0008] -AB7B ; [.3239.0020.0002] -13AB ; [.3239.0020.0008] -AB7C ; [.323A.0020.0002] -13AC ; [.323A.0020.0008] -AB7D ; [.323B.0020.0002] -13AD ; [.323B.0020.0008] -AB7E ; [.323C.0020.0002] -13AE ; [.323C.0020.0008] -AB7F ; [.323D.0020.0002] -13AF ; [.323D.0020.0008] -AB80 ; [.323E.0020.0002] -13B0 ; [.323E.0020.0008] -AB81 ; [.323F.0020.0002] -13B1 ; [.323F.0020.0008] -AB82 ; [.3240.0020.0002] -13B2 ; [.3240.0020.0008] -AB83 ; [.3241.0020.0002] -13B3 ; [.3241.0020.0008] -AB84 ; [.3242.0020.0002] -13B4 ; [.3242.0020.0008] -AB85 ; [.3243.0020.0002] -13B5 ; [.3243.0020.0008] -AB86 ; [.3244.0020.0002] -13B6 ; [.3244.0020.0008] -AB87 ; [.3245.0020.0002] -13B7 ; [.3245.0020.0008] -AB88 ; [.3246.0020.0002] -13B8 ; [.3246.0020.0008] -AB89 ; [.3247.0020.0002] -13B9 ; [.3247.0020.0008] -AB8A ; [.3248.0020.0002] -13BA ; [.3248.0020.0008] -AB8B ; [.3249.0020.0002] -13BB ; [.3249.0020.0008] -AB8C ; [.324A.0020.0002] -13BC ; [.324A.0020.0008] -AB8D ; [.324B.0020.0002] -13BD ; [.324B.0020.0008] -AB8E ; [.324C.0020.0002] -13BE ; [.324C.0020.0008] -AB8F ; [.324D.0020.0002] -13BF ; [.324D.0020.0008] -AB90 ; [.324E.0020.0002] -13C0 ; [.324E.0020.0008] -AB91 ; [.324F.0020.0002] -13C1 ; [.324F.0020.0008] -AB92 ; [.3250.0020.0002] -13C2 ; [.3250.0020.0008] -AB93 ; [.3251.0020.0002] -13C3 ; [.3251.0020.0008] -AB94 ; [.3252.0020.0002] -13C4 ; [.3252.0020.0008] -AB95 ; [.3253.0020.0002] -13C5 ; [.3253.0020.0008] -AB96 ; [.3254.0020.0002] -13C6 ; [.3254.0020.0008] -AB97 ; [.3255.0020.0002] -13C7 ; [.3255.0020.0008] -AB98 ; [.3256.0020.0002] -13C8 ; [.3256.0020.0008] -AB99 ; [.3257.0020.0002] -13C9 ; [.3257.0020.0008] -AB9A ; [.3258.0020.0002] -13CA ; [.3258.0020.0008] -AB9B ; [.3259.0020.0002] -13CB ; [.3259.0020.0008] -AB9C ; [.325A.0020.0002] -13CC ; [.325A.0020.0008] -AB9D ; [.325B.0020.0002] -13CD ; [.325B.0020.0008] -AB9E ; [.325C.0020.0002] -13CE ; [.325C.0020.0008] -AB9F ; [.325D.0020.0002] -13CF ; [.325D.0020.0008] -ABA0 ; [.325E.0020.0002] -13D0 ; [.325E.0020.0008] -ABA1 ; [.325F.0020.0002] -13D1 ; [.325F.0020.0008] -ABA2 ; [.3260.0020.0002] -13D2 ; [.3260.0020.0008] -ABA3 ; [.3261.0020.0002] -13D3 ; [.3261.0020.0008] -ABA4 ; [.3262.0020.0002] -13D4 ; [.3262.0020.0008] -ABA5 ; [.3263.0020.0002] -13D5 ; [.3263.0020.0008] -ABA6 ; [.3264.0020.0002] -13D6 ; [.3264.0020.0008] -ABA7 ; [.3265.0020.0002] -13D7 ; [.3265.0020.0008] -ABA8 ; [.3266.0020.0002] -13D8 ; [.3266.0020.0008] -ABA9 ; [.3267.0020.0002] -13D9 ; [.3267.0020.0008] -ABAA ; [.3268.0020.0002] -13DA ; [.3268.0020.0008] -ABAB ; [.3269.0020.0002] -13DB ; [.3269.0020.0008] -ABAC ; [.326A.0020.0002] -13DC ; [.326A.0020.0008] -ABAD ; [.326B.0020.0002] -13DD ; [.326B.0020.0008] -ABAE ; [.326C.0020.0002] -13DE ; [.326C.0020.0008] -ABAF ; [.326D.0020.0002] -13DF ; [.326D.0020.0008] -ABB0 ; [.326E.0020.0002] -13E0 ; [.326E.0020.0008] -ABB1 ; [.326F.0020.0002] -13E1 ; [.326F.0020.0008] -ABB2 ; [.3270.0020.0002] -13E2 ; [.3270.0020.0008] -ABB3 ; [.3271.0020.0002] -13E3 ; [.3271.0020.0008] -ABB4 ; [.3272.0020.0002] -13E4 ; [.3272.0020.0008] -ABB5 ; [.3273.0020.0002] -13E5 ; [.3273.0020.0008] -ABB6 ; [.3274.0020.0002] -13E6 ; [.3274.0020.0008] -ABB7 ; [.3275.0020.0002] -13E7 ; [.3275.0020.0008] -ABB8 ; [.3276.0020.0002] -13E8 ; [.3276.0020.0008] -ABB9 ; [.3277.0020.0002] -13E9 ; [.3277.0020.0008] -ABBA ; [.3278.0020.0002] -13EA ; [.3278.0020.0008] -ABBB ; [.3279.0020.0002] -13EB ; [.3279.0020.0008] -ABBC ; [.327A.0020.0002] -13EC ; [.327A.0020.0008] -ABBD ; [.327B.0020.0002] -13ED ; [.327B.0020.0008] -ABBE ; [.327C.0020.0002] -13EE ; [.327C.0020.0008] -ABBF ; [.327D.0020.0002] -13EF ; [.327D.0020.0008] -13F8 ; [.327E.0020.0002] -13F0 ; [.327E.0020.0008] -13F9 ; [.327F.0020.0002] -13F1 ; [.327F.0020.0008] -13FA ; [.3280.0020.0002] -13F2 ; [.3280.0020.0008] -13FB ; [.3281.0020.0002] -13F3 ; [.3281.0020.0008] -13FC ; [.3282.0020.0002] -13F4 ; [.3282.0020.0008] -13FD ; [.3283.0020.0002] -13F5 ; [.3283.0020.0008] -1401 ; [.3284.0020.0002] -1402 ; [.3285.0020.0002] -1403 ; [.3286.0020.0002] -1404 ; [.3287.0020.0002] -1405 ; [.3288.0020.0002] -1406 ; [.3289.0020.0002] -1407 ; [.328A.0020.0002] -1408 ; [.328B.0020.0002] -1409 ; [.328C.0020.0002] -140A ; [.328D.0020.0002] -140B ; [.328E.0020.0002] -140C ; [.328F.0020.0002] -140D ; [.3290.0020.0002] -140E ; [.3291.0020.0002] -140F ; [.3292.0020.0002] -1410 ; [.3293.0020.0002] -1411 ; [.3294.0020.0002] -1412 ; [.3295.0020.0002] -1413 ; [.3296.0020.0002] -1414 ; [.3297.0020.0002] -1415 ; [.3298.0020.0002] -1416 ; [.3299.0020.0002] -1417 ; [.329A.0020.0002] -1418 ; [.329B.0020.0002] -1419 ; [.329C.0020.0002] -141A ; [.329D.0020.0002] -141B ; [.329E.0020.0002] -141C ; [.329F.0020.0002] -141D ; [.32A0.0020.0002] -141E ; [.32A1.0020.0002] -141F ; [.32A2.0020.0002] -1420 ; [.32A3.0020.0002] -1421 ; [.32A4.0020.0002] -1422 ; [.32A5.0020.0002] -1423 ; [.32A6.0020.0002] -1424 ; [.32A7.0020.0002] -1425 ; [.32A8.0020.0002] -1426 ; [.32A9.0020.0002] -1427 ; [.32AA.0020.0002] -1428 ; [.32AB.0020.0002] -1429 ; [.32AC.0020.0002] -142A ; [.32AD.0020.0002] -142B ; [.32AE.0020.0002] -142C ; [.32AF.0020.0002] -142D ; [.32B0.0020.0002] -142E ; [.32B1.0020.0002] -142F ; [.32B2.0020.0002] -1430 ; [.32B3.0020.0002] -1431 ; [.32B4.0020.0002] -1432 ; [.32B5.0020.0002] -1433 ; [.32B6.0020.0002] -1434 ; [.32B7.0020.0002] -1435 ; [.32B8.0020.0002] -1436 ; [.32B9.0020.0002] -1437 ; [.32BA.0020.0002] -1438 ; [.32BB.0020.0002] -1439 ; [.32BC.0020.0002] -143A ; [.32BD.0020.0002] -143B ; [.32BE.0020.0002] -143C ; [.32BF.0020.0002] -143D ; [.32C0.0020.0002] -143E ; [.32C1.0020.0002] -143F ; [.32C2.0020.0002] -1440 ; [.32C3.0020.0002] -1441 ; [.32C4.0020.0002] -1442 ; [.32C5.0020.0002] -1443 ; [.32C6.0020.0002] -1444 ; [.32C7.0020.0002] -1445 ; [.32C8.0020.0002] -1446 ; [.32C9.0020.0002] -1447 ; [.32CA.0020.0002] -1448 ; [.32CB.0020.0002] -1449 ; [.32CC.0020.0002] -144A ; [.32CD.0020.0002] -144B ; [.32CE.0020.0002] -144C ; [.32CF.0020.0002] -144D ; [.32D0.0020.0002] -144E ; [.32D1.0020.0002] -144F ; [.32D2.0020.0002] -1450 ; [.32D3.0020.0002] -1451 ; [.32D4.0020.0002] -1452 ; [.32D5.0020.0002] -1453 ; [.32D6.0020.0002] -1454 ; [.32D7.0020.0002] -1455 ; [.32D8.0020.0002] -1456 ; [.32D9.0020.0002] -1457 ; [.32DA.0020.0002] -1458 ; [.32DB.0020.0002] -1459 ; [.32DC.0020.0002] -145A ; [.32DD.0020.0002] -145B ; [.32DE.0020.0002] -145C ; [.32DF.0020.0002] -145D ; [.32E0.0020.0002] -145E ; [.32E1.0020.0002] -145F ; [.32E2.0020.0002] -1460 ; [.32E3.0020.0002] -1461 ; [.32E4.0020.0002] -1462 ; [.32E5.0020.0002] -1463 ; [.32E6.0020.0002] -1464 ; [.32E7.0020.0002] -1465 ; [.32E8.0020.0002] -1466 ; [.32E9.0020.0002] -1467 ; [.32EA.0020.0002] -1468 ; [.32EB.0020.0002] -1469 ; [.32EC.0020.0002] -146A ; [.32ED.0020.0002] -146B ; [.32EE.0020.0002] -146C ; [.32EF.0020.0002] -146D ; [.32F0.0020.0002] -146E ; [.32F1.0020.0002] -146F ; [.32F2.0020.0002] -1470 ; [.32F3.0020.0002] -1471 ; [.32F4.0020.0002] -1472 ; [.32F5.0020.0002] -1473 ; [.32F6.0020.0002] -1474 ; [.32F7.0020.0002] -1475 ; [.32F8.0020.0002] -1476 ; [.32F9.0020.0002] -1477 ; [.32FA.0020.0002] -1478 ; [.32FB.0020.0002] -1479 ; [.32FC.0020.0002] -147A ; [.32FD.0020.0002] -147B ; [.32FE.0020.0002] -147C ; [.32FF.0020.0002] -147D ; [.3300.0020.0002] -147E ; [.3301.0020.0002] -147F ; [.3302.0020.0002] -1480 ; [.3303.0020.0002] -1481 ; [.3304.0020.0002] -1482 ; [.3305.0020.0002] -1483 ; [.3306.0020.0002] -1484 ; [.3307.0020.0002] -1485 ; [.3308.0020.0002] -1486 ; [.3309.0020.0002] -1487 ; [.330A.0020.0002] -1488 ; [.330B.0020.0002] -1489 ; [.330C.0020.0002] -148A ; [.330D.0020.0002] -148B ; [.330E.0020.0002] -148C ; [.330F.0020.0002] -148D ; [.3310.0020.0002] -148E ; [.3311.0020.0002] -148F ; [.3312.0020.0002] -1490 ; [.3313.0020.0002] -1491 ; [.3314.0020.0002] -1492 ; [.3315.0020.0002] -1493 ; [.3316.0020.0002] -1494 ; [.3317.0020.0002] -1495 ; [.3318.0020.0002] -1496 ; [.3319.0020.0002] -1497 ; [.331A.0020.0002] -1498 ; [.331B.0020.0002] -1499 ; [.331C.0020.0002] -149A ; [.331D.0020.0002] -149B ; [.331E.0020.0002] -149C ; [.331F.0020.0002] -149D ; [.3320.0020.0002] -149E ; [.3321.0020.0002] -149F ; [.3322.0020.0002] -14A0 ; [.3323.0020.0002] -14A1 ; [.3324.0020.0002] -14A2 ; [.3325.0020.0002] -14A3 ; [.3326.0020.0002] -14A4 ; [.3327.0020.0002] -14A5 ; [.3328.0020.0002] -14A6 ; [.3329.0020.0002] -14A7 ; [.332A.0020.0002] -14A8 ; [.332B.0020.0002] -14A9 ; [.332C.0020.0002] -14AA ; [.332D.0020.0002] -14AB ; [.332E.0020.0002] -14AC ; [.332F.0020.0002] -14AD ; [.3330.0020.0002] -14AE ; [.3331.0020.0002] -14AF ; [.3332.0020.0002] -14B0 ; [.3333.0020.0002] -14B1 ; [.3334.0020.0002] -14B2 ; [.3335.0020.0002] -14B3 ; [.3336.0020.0002] -14B4 ; [.3337.0020.0002] -14B5 ; [.3338.0020.0002] -14B6 ; [.3339.0020.0002] -14B7 ; [.333A.0020.0002] -14B8 ; [.333B.0020.0002] -14B9 ; [.333C.0020.0002] -14BA ; [.333D.0020.0002] -14BB ; [.333E.0020.0002] -14BC ; [.333F.0020.0002] -14BD ; [.3340.0020.0002] -14BE ; [.3341.0020.0002] -14BF ; [.3342.0020.0002] -14C0 ; [.3343.0020.0002] -14C1 ; [.3344.0020.0002] -14C2 ; [.3345.0020.0002] -14C3 ; [.3346.0020.0002] -14C4 ; [.3347.0020.0002] -14C5 ; [.3348.0020.0002] -14C6 ; [.3349.0020.0002] -14C7 ; [.334A.0020.0002] -14C8 ; [.334B.0020.0002] -14C9 ; [.334C.0020.0002] -14CA ; [.334D.0020.0002] -14CB ; [.334E.0020.0002] -14CC ; [.334F.0020.0002] -14CD ; [.3350.0020.0002] -14CE ; [.3351.0020.0002] -14CF ; [.3352.0020.0002] -14D0 ; [.3353.0020.0002] -14D1 ; [.3354.0020.0002] -14D2 ; [.3355.0020.0002] -14D3 ; [.3356.0020.0002] -14D4 ; [.3357.0020.0002] -14D5 ; [.3358.0020.0002] -14D6 ; [.3359.0020.0002] -14D7 ; [.335A.0020.0002] -14D8 ; [.335B.0020.0002] -14D9 ; [.335C.0020.0002] -14DA ; [.335D.0020.0002] -14DB ; [.335E.0020.0002] -14DC ; [.335F.0020.0002] -14DD ; [.3360.0020.0002] -14DE ; [.3361.0020.0002] -14DF ; [.3362.0020.0002] -14E0 ; [.3363.0020.0002] -14E1 ; [.3364.0020.0002] -14E2 ; [.3365.0020.0002] -14E3 ; [.3366.0020.0002] -14E4 ; [.3367.0020.0002] -14E5 ; [.3368.0020.0002] -14E6 ; [.3369.0020.0002] -14E7 ; [.336A.0020.0002] -14E8 ; [.336B.0020.0002] -14E9 ; [.336C.0020.0002] -14EA ; [.336D.0020.0002] -14EB ; [.336E.0020.0002] -14EC ; [.336F.0020.0002] -14ED ; [.3370.0020.0002] -14EE ; [.3371.0020.0002] -14EF ; [.3372.0020.0002] -14F0 ; [.3373.0020.0002] -14F1 ; [.3374.0020.0002] -14F2 ; [.3375.0020.0002] -14F3 ; [.3376.0020.0002] -14F4 ; [.3377.0020.0002] -14F5 ; [.3378.0020.0002] -14F6 ; [.3379.0020.0002] -14F7 ; [.337A.0020.0002] -14F8 ; [.337B.0020.0002] -14F9 ; [.337C.0020.0002] -14FA ; [.337D.0020.0002] -14FB ; [.337E.0020.0002] -14FC ; [.337F.0020.0002] -14FD ; [.3380.0020.0002] -14FE ; [.3381.0020.0002] -14FF ; [.3382.0020.0002] -1500 ; [.3383.0020.0002] -1501 ; [.3384.0020.0002] -1502 ; [.3385.0020.0002] -1503 ; [.3386.0020.0002] -1504 ; [.3387.0020.0002] -1505 ; [.3388.0020.0002] -1506 ; [.3389.0020.0002] -1507 ; [.338A.0020.0002] -1508 ; [.338B.0020.0002] -1509 ; [.338C.0020.0002] -150A ; [.338D.0020.0002] -150B ; [.338E.0020.0002] -150C ; [.338F.0020.0002] -150D ; [.3390.0020.0002] -150E ; [.3391.0020.0002] -150F ; [.3392.0020.0002] -1510 ; [.3393.0020.0002] -1511 ; [.3394.0020.0002] -1512 ; [.3395.0020.0002] -1513 ; [.3396.0020.0002] -1514 ; [.3397.0020.0002] -1515 ; [.3398.0020.0002] -1516 ; [.3399.0020.0002] -1517 ; [.339A.0020.0002] -1518 ; [.339B.0020.0002] -1519 ; [.339C.0020.0002] -151A ; [.339D.0020.0002] -151B ; [.339E.0020.0002] -151C ; [.339F.0020.0002] -151D ; [.33A0.0020.0002] -151E ; [.33A1.0020.0002] -151F ; [.33A2.0020.0002] -1520 ; [.33A3.0020.0002] -1521 ; [.33A4.0020.0002] -1522 ; [.33A5.0020.0002] -1523 ; [.33A6.0020.0002] -1524 ; [.33A7.0020.0002] -1525 ; [.33A8.0020.0002] -1526 ; [.33A9.0020.0002] -1527 ; [.33AA.0020.0002] -1528 ; [.33AB.0020.0002] -1529 ; [.33AC.0020.0002] -152A ; [.33AD.0020.0002] -152B ; [.33AE.0020.0002] -152C ; [.33AF.0020.0002] -152D ; [.33B0.0020.0002] -152E ; [.33B1.0020.0002] -152F ; [.33B2.0020.0002] -1530 ; [.33B3.0020.0002] -1531 ; [.33B4.0020.0002] -1532 ; [.33B5.0020.0002] -1533 ; [.33B6.0020.0002] -1534 ; [.33B7.0020.0002] -1535 ; [.33B8.0020.0002] -1536 ; [.33B9.0020.0002] -1537 ; [.33BA.0020.0002] -1538 ; [.33BB.0020.0002] -1539 ; [.33BC.0020.0002] -153A ; [.33BD.0020.0002] -153B ; [.33BE.0020.0002] -153C ; [.33BF.0020.0002] -153D ; [.33C0.0020.0002] -153E ; [.33C1.0020.0002] -153F ; [.33C2.0020.0002] -1540 ; [.33C3.0020.0002] -1541 ; [.33C4.0020.0002] -1542 ; [.33C5.0020.0002] -1543 ; [.33C6.0020.0002] -1544 ; [.33C7.0020.0002] -1545 ; [.33C8.0020.0002] -1546 ; [.33C9.0020.0002] -1547 ; [.33CA.0020.0002] -1548 ; [.33CB.0020.0002] -1549 ; [.33CC.0020.0002] -154A ; [.33CD.0020.0002] -154B ; [.33CE.0020.0002] -154C ; [.33CF.0020.0002] -154D ; [.33D0.0020.0002] -154E ; [.33D1.0020.0002] -154F ; [.33D2.0020.0002] -1550 ; [.33D3.0020.0002] -1551 ; [.33D4.0020.0002] -1552 ; [.33D5.0020.0002] -1553 ; [.33D6.0020.0002] -1554 ; [.33D7.0020.0002] -1555 ; [.33D8.0020.0002] -1556 ; [.33D9.0020.0002] -1557 ; [.33DA.0020.0002] -1558 ; [.33DB.0020.0002] -1559 ; [.33DC.0020.0002] -155A ; [.33DD.0020.0002] -155B ; [.33DE.0020.0002] -155C ; [.33DF.0020.0002] -155D ; [.33E0.0020.0002] -155E ; [.33E1.0020.0002] -155F ; [.33E2.0020.0002] -1560 ; [.33E3.0020.0002] -1561 ; [.33E4.0020.0002] -1562 ; [.33E5.0020.0002] -1563 ; [.33E6.0020.0002] -1564 ; [.33E7.0020.0002] -1565 ; [.33E8.0020.0002] -1566 ; [.33E9.0020.0002] -1567 ; [.33EA.0020.0002] -1568 ; [.33EB.0020.0002] -1569 ; [.33EC.0020.0002] -156A ; [.33ED.0020.0002] -156B ; [.33EE.0020.0002] -156C ; [.33EF.0020.0002] -156D ; [.33F0.0020.0002] -156E ; [.33F1.0020.0002] -156F ; [.33F2.0020.0002] -1570 ; [.33F3.0020.0002] -1571 ; [.33F4.0020.0002] -1572 ; [.33F5.0020.0002] -1573 ; [.33F6.0020.0002] -1574 ; [.33F7.0020.0002] -1575 ; [.33F8.0020.0002] -1576 ; [.33F9.0020.0002] -1577 ; [.33FA.0020.0002] -1578 ; [.33FB.0020.0002] -1579 ; [.33FC.0020.0002] -157A ; [.33FD.0020.0002] -157B ; [.33FE.0020.0002] -157D ; [.33FF.0020.0002] -166F ; [.3400.0020.0002] -157E ; [.3401.0020.0002] -157F ; [.3402.0020.0002] -1580 ; [.3403.0020.0002] -1581 ; [.3404.0020.0002] -1582 ; [.3405.0020.0002] -1583 ; [.3406.0020.0002] -1584 ; [.3407.0020.0002] -1585 ; [.3408.0020.0002] -1586 ; [.3409.0020.0002] -1587 ; [.340A.0020.0002] -1588 ; [.340B.0020.0002] -1589 ; [.340C.0020.0002] -158A ; [.340D.0020.0002] -158B ; [.340E.0020.0002] -158C ; [.340F.0020.0002] -158D ; [.3410.0020.0002] -1670 ; [.3411.0020.0002] -158E ; [.3412.0020.0002] -158F ; [.3413.0020.0002] -1590 ; [.3414.0020.0002] -1591 ; [.3415.0020.0002] -1592 ; [.3416.0020.0002] -1593 ; [.3417.0020.0002] -1594 ; [.3418.0020.0002] -1595 ; [.3419.0020.0002] -1671 ; [.341A.0020.0002] -1672 ; [.341B.0020.0002] -1673 ; [.341C.0020.0002] -1674 ; [.341D.0020.0002] -1675 ; [.341E.0020.0002] -1676 ; [.341F.0020.0002] -1596 ; [.3420.0020.0002] -1597 ; [.3421.0020.0002] -1598 ; [.3422.0020.0002] -1599 ; [.3423.0020.0002] -159A ; [.3424.0020.0002] -159B ; [.3425.0020.0002] -159C ; [.3426.0020.0002] -159D ; [.3427.0020.0002] -159E ; [.3428.0020.0002] -159F ; [.3429.0020.0002] -15A0 ; [.342A.0020.0002] -15A1 ; [.342B.0020.0002] -15A2 ; [.342C.0020.0002] -15A3 ; [.342D.0020.0002] -15A4 ; [.342E.0020.0002] -15A5 ; [.342F.0020.0002] -15A6 ; [.3430.0020.0002] -157C ; [.3431.0020.0002] -15A7 ; [.3432.0020.0002] -15A8 ; [.3433.0020.0002] -15A9 ; [.3434.0020.0002] -15AA ; [.3435.0020.0002] -15AB ; [.3436.0020.0002] -15AC ; [.3437.0020.0002] -15AD ; [.3438.0020.0002] -15AE ; [.3439.0020.0002] -15AF ; [.343A.0020.0002] -15B0 ; [.343B.0020.0002] -15B1 ; [.343C.0020.0002] -15B2 ; [.343D.0020.0002] -15B3 ; [.343E.0020.0002] -15B4 ; [.343F.0020.0002] -15B5 ; [.3440.0020.0002] -15B6 ; [.3441.0020.0002] -15B7 ; [.3442.0020.0002] -15B8 ; [.3443.0020.0002] -15B9 ; [.3444.0020.0002] -15BA ; [.3445.0020.0002] -15BB ; [.3446.0020.0002] -15BC ; [.3447.0020.0002] -15BD ; [.3448.0020.0002] -15BE ; [.3449.0020.0002] -15BF ; [.344A.0020.0002] -15C0 ; [.344B.0020.0002] -15C1 ; [.344C.0020.0002] -15C2 ; [.344D.0020.0002] -15C3 ; [.344E.0020.0002] -15C4 ; [.344F.0020.0002] -15C5 ; [.3450.0020.0002] -15C6 ; [.3451.0020.0002] -15C7 ; [.3452.0020.0002] -15C8 ; [.3453.0020.0002] -15C9 ; [.3454.0020.0002] -15CA ; [.3455.0020.0002] -15CB ; [.3456.0020.0002] -15CC ; [.3457.0020.0002] -15CD ; [.3458.0020.0002] -15CE ; [.3459.0020.0002] -15CF ; [.345A.0020.0002] -15D0 ; [.345B.0020.0002] -15D1 ; [.345C.0020.0002] -15D2 ; [.345D.0020.0002] -15D3 ; [.345E.0020.0002] -15D4 ; [.345F.0020.0002] -15D5 ; [.3460.0020.0002] -15D6 ; [.3461.0020.0002] -15D7 ; [.3462.0020.0002] -15D8 ; [.3463.0020.0002] -15D9 ; [.3464.0020.0002] -15DA ; [.3465.0020.0002] -15DB ; [.3466.0020.0002] -15DC ; [.3467.0020.0002] -15DD ; [.3468.0020.0002] -15DE ; [.3469.0020.0002] -15DF ; [.346A.0020.0002] -15E0 ; [.346B.0020.0002] -15E1 ; [.346C.0020.0002] -15E2 ; [.346D.0020.0002] -15E3 ; [.346E.0020.0002] -15E4 ; [.346F.0020.0002] -15E5 ; [.3470.0020.0002] -15E6 ; [.3471.0020.0002] -15E7 ; [.3472.0020.0002] -15E8 ; [.3473.0020.0002] -15E9 ; [.3474.0020.0002] -15EA ; [.3475.0020.0002] -15EB ; [.3476.0020.0002] -15EC ; [.3477.0020.0002] -15ED ; [.3478.0020.0002] -15EE ; [.3479.0020.0002] -15EF ; [.347A.0020.0002] -15F0 ; [.347B.0020.0002] -15F1 ; [.347C.0020.0002] -15F2 ; [.347D.0020.0002] -15F3 ; [.347E.0020.0002] -15F4 ; [.347F.0020.0002] -15F5 ; [.3480.0020.0002] -15F6 ; [.3481.0020.0002] -15F7 ; [.3482.0020.0002] -15F8 ; [.3483.0020.0002] -15F9 ; [.3484.0020.0002] -15FA ; [.3485.0020.0002] -15FB ; [.3486.0020.0002] -15FC ; [.3487.0020.0002] -15FD ; [.3488.0020.0002] -15FE ; [.3489.0020.0002] -15FF ; [.348A.0020.0002] -1600 ; [.348B.0020.0002] -1601 ; [.348C.0020.0002] -1602 ; [.348D.0020.0002] -1603 ; [.348E.0020.0002] -1604 ; [.348F.0020.0002] -1605 ; [.3490.0020.0002] -1606 ; [.3491.0020.0002] -1607 ; [.3492.0020.0002] -1608 ; [.3493.0020.0002] -1609 ; [.3494.0020.0002] -160A ; [.3495.0020.0002] -160B ; [.3496.0020.0002] -160C ; [.3497.0020.0002] -160D ; [.3498.0020.0002] -160E ; [.3499.0020.0002] -160F ; [.349A.0020.0002] -1610 ; [.349B.0020.0002] -1611 ; [.349C.0020.0002] -1612 ; [.349D.0020.0002] -1613 ; [.349E.0020.0002] -1614 ; [.349F.0020.0002] -1615 ; [.34A0.0020.0002] -1616 ; [.34A1.0020.0002] -1617 ; [.34A2.0020.0002] -1618 ; [.34A3.0020.0002] -1619 ; [.34A4.0020.0002] -161A ; [.34A5.0020.0002] -161B ; [.34A6.0020.0002] -161C ; [.34A7.0020.0002] -161D ; [.34A8.0020.0002] -161E ; [.34A9.0020.0002] -161F ; [.34AA.0020.0002] -1620 ; [.34AB.0020.0002] -1621 ; [.34AC.0020.0002] -1622 ; [.34AD.0020.0002] -1623 ; [.34AE.0020.0002] -1624 ; [.34AF.0020.0002] -1625 ; [.34B0.0020.0002] -1626 ; [.34B1.0020.0002] -1627 ; [.34B2.0020.0002] -1628 ; [.34B3.0020.0002] -1629 ; [.34B4.0020.0002] -162A ; [.34B5.0020.0002] -162B ; [.34B6.0020.0002] -162C ; [.34B7.0020.0002] -162D ; [.34B8.0020.0002] -162E ; [.34B9.0020.0002] -162F ; [.34BA.0020.0002] -1630 ; [.34BB.0020.0002] -1631 ; [.34BC.0020.0002] -1632 ; [.34BD.0020.0002] -1633 ; [.34BE.0020.0002] -1634 ; [.34BF.0020.0002] -1635 ; [.34C0.0020.0002] -1636 ; [.34C1.0020.0002] -1637 ; [.34C2.0020.0002] -1638 ; [.34C3.0020.0002] -1639 ; [.34C4.0020.0002] -163A ; [.34C5.0020.0002] -163B ; [.34C6.0020.0002] -163C ; [.34C7.0020.0002] -163D ; [.34C8.0020.0002] -163E ; [.34C9.0020.0002] -163F ; [.34CA.0020.0002] -1640 ; [.34CB.0020.0002] -1641 ; [.34CC.0020.0002] -1642 ; [.34CD.0020.0002] -1643 ; [.34CE.0020.0002] -1644 ; [.34CF.0020.0002] -1645 ; [.34D0.0020.0002] -1646 ; [.34D1.0020.0002] -1647 ; [.34D2.0020.0002] -1648 ; [.34D3.0020.0002] -1649 ; [.34D4.0020.0002] -164A ; [.34D5.0020.0002] -164B ; [.34D6.0020.0002] -164C ; [.34D7.0020.0002] -164D ; [.34D8.0020.0002] -164E ; [.34D9.0020.0002] -164F ; [.34DA.0020.0002] -1650 ; [.34DB.0020.0002] -1651 ; [.34DC.0020.0002] -1652 ; [.34DD.0020.0002] -1653 ; [.34DE.0020.0002] -1654 ; [.34DF.0020.0002] -1655 ; [.34E0.0020.0002] -1656 ; [.34E1.0020.0002] -1657 ; [.34E2.0020.0002] -1658 ; [.34E3.0020.0002] -1659 ; [.34E4.0020.0002] -165A ; [.34E5.0020.0002] -165B ; [.34E6.0020.0002] -165C ; [.34E7.0020.0002] -165D ; [.34E8.0020.0002] -165E ; [.34E9.0020.0002] -165F ; [.34EA.0020.0002] -1660 ; [.34EB.0020.0002] -1661 ; [.34EC.0020.0002] -1662 ; [.34ED.0020.0002] -1663 ; [.34EE.0020.0002] -1664 ; [.34EF.0020.0002] -1665 ; [.34F0.0020.0002] -1666 ; [.34F1.0020.0002] -1667 ; [.34F2.0020.0002] -1668 ; [.34F3.0020.0002] -1669 ; [.34F4.0020.0002] -166A ; [.34F5.0020.0002] -166B ; [.34F6.0020.0002] -166C ; [.34F7.0020.0002] -1677 ; [.34F8.0020.0002] -1678 ; [.34F9.0020.0002] -1679 ; [.34FA.0020.0002] -167A ; [.34FB.0020.0002] -167B ; [.34FC.0020.0002] -167C ; [.34FD.0020.0002] -167D ; [.34FE.0020.0002] -167E ; [.34FF.0020.0002] -167F ; [.3500.0020.0002] -18B0 ; [.3501.0020.0002] -18B1 ; [.3502.0020.0002] -18B2 ; [.3503.0020.0002] -18B3 ; [.3504.0020.0002] -18B4 ; [.3505.0020.0002] -18B5 ; [.3506.0020.0002] -18B6 ; [.3507.0020.0002] -18B7 ; [.3508.0020.0002] -18B8 ; [.3509.0020.0002] -18B9 ; [.350A.0020.0002] -18BA ; [.350B.0020.0002] -18BB ; [.350C.0020.0002] -18BC ; [.350D.0020.0002] -18BD ; [.350E.0020.0002] -18BE ; [.350F.0020.0002] -18BF ; [.3510.0020.0002] -18C0 ; [.3511.0020.0002] -18C1 ; [.3512.0020.0002] -18C2 ; [.3513.0020.0002] -18C3 ; [.3514.0020.0002] -18C4 ; [.3515.0020.0002] -18C5 ; [.3516.0020.0002] -18C6 ; [.3517.0020.0002] -18C7 ; [.3518.0020.0002] -18C8 ; [.3519.0020.0002] -18C9 ; [.351A.0020.0002] -18CA ; [.351B.0020.0002] -18CB ; [.351C.0020.0002] -18CC ; [.351D.0020.0002] -18CD ; [.351E.0020.0002] -18CE ; [.351F.0020.0002] -18CF ; [.3520.0020.0002] -18D0 ; [.3521.0020.0002] -18D1 ; [.3522.0020.0002] -18D2 ; [.3523.0020.0002] -18D3 ; [.3524.0020.0002] -18D4 ; [.3525.0020.0002] -18D5 ; [.3526.0020.0002] -18D6 ; [.3527.0020.0002] -18D7 ; [.3528.0020.0002] -18D8 ; [.3529.0020.0002] -18D9 ; [.352A.0020.0002] -18DA ; [.352B.0020.0002] -18DB ; [.352C.0020.0002] -18DC ; [.352D.0020.0002] -18DD ; [.352E.0020.0002] -18DE ; [.352F.0020.0002] -18DF ; [.3530.0020.0002] -18E0 ; [.3531.0020.0002] -18E1 ; [.3532.0020.0002] -18E2 ; [.3533.0020.0002] -18E3 ; [.3534.0020.0002] -18E4 ; [.3535.0020.0002] -18E5 ; [.3536.0020.0002] -18E6 ; [.3537.0020.0002] -18E7 ; [.3538.0020.0002] -18E8 ; [.3539.0020.0002] -18E9 ; [.353A.0020.0002] -18EA ; [.353B.0020.0002] -18EB ; [.353C.0020.0002] -18EC ; [.353D.0020.0002] -18ED ; [.353E.0020.0002] -18EE ; [.353F.0020.0002] -18EF ; [.3540.0020.0002] -18F0 ; [.3541.0020.0002] -18F1 ; [.3542.0020.0002] -18F2 ; [.3543.0020.0002] -18F3 ; [.3544.0020.0002] -18F4 ; [.3545.0020.0002] -18F5 ; [.3546.0020.0002] -1681 ; [.3547.0020.0002] -1682 ; [.3548.0020.0002] -1683 ; [.3549.0020.0002] -1684 ; [.354A.0020.0002] -1685 ; [.354B.0020.0002] -1686 ; [.354C.0020.0002] -1687 ; [.354D.0020.0002] -1688 ; [.354E.0020.0002] -1689 ; [.354F.0020.0002] -168A ; [.3550.0020.0002] -168B ; [.3551.0020.0002] -168C ; [.3552.0020.0002] -168D ; [.3553.0020.0002] -168E ; [.3554.0020.0002] -168F ; [.3555.0020.0002] -1690 ; [.3556.0020.0002] -1691 ; [.3557.0020.0002] -1692 ; [.3558.0020.0002] -1693 ; [.3559.0020.0002] -1694 ; [.355A.0020.0002] -1695 ; [.355B.0020.0002] -1696 ; [.355C.0020.0002] -1697 ; [.355D.0020.0002] -1698 ; [.355E.0020.0002] -1699 ; [.355F.0020.0002] -169A ; [.3560.0020.0002] -16A0 ; [.3561.0020.0002] -16A1 ; [.3561.0020.0004][.0000.010B.0004] -16A2 ; [.3562.0020.0002] -16A4 ; [.3562.0020.0004][.0000.010B.0004] -16A5 ; [.3562.0020.0004][.0000.010C.0004] -16A6 ; [.3563.0020.0002] -16A7 ; [.3563.0020.0004][.0000.010B.0004] -16F0 ; [.3563.0020.0004][.3563.0020.0004] -16A8 ; [.3564.0020.0002] -16A9 ; [.3564.0020.0004][.0000.010B.0004] -16AC ; [.3564.0020.0004][.0000.010C.0004] -16AD ; [.3564.0020.0004][.0000.010D.0004] -16AE ; [.3564.0020.0004][.0000.010E.0004] -16F4 ; [.3565.0020.0002] -16AF ; [.3566.0020.0002] -16B0 ; [.3567.0020.0002] -16B1 ; [.3568.0020.0002] -16B2 ; [.3569.0020.0002] -16B3 ; [.3569.0020.0004][.0000.010B.0004] -16B4 ; [.3569.0020.0004][.0000.010C.0004] -16B5 ; [.3569.0020.0004][.0000.010D.0004] -16B6 ; [.3569.0020.0004][.0000.010E.0004] -16F1 ; [.356A.0020.0002] -16B7 ; [.356B.0020.0002] -16B9 ; [.356C.0020.0002] -16E9 ; [.356C.0020.0004][.0000.010B.0004] -16BA ; [.356D.0020.0002] -16BB ; [.356D.0020.0004][.0000.010B.0004] -16BC ; [.356D.0020.0004][.0000.010C.0004] -16BD ; [.356D.0020.0004][.0000.010D.0004] -16BE ; [.356E.0020.0002] -16BF ; [.356E.0020.0004][.0000.010B.0004] -16C0 ; [.356E.0020.0004][.0000.010C.0004] -16C1 ; [.356F.0020.0002] -16C2 ; [.356F.0020.0004][.0000.010B.0004] -16F5 ; [.3570.0020.0002] -16C3 ; [.3571.0020.0002] -16C4 ; [.3571.0020.0004][.0000.010B.0004] -16C5 ; [.3572.0020.0002] -16C6 ; [.3572.0020.0004][.0000.010B.0004] -16EE ; [.3572.0020.0004][.357D.0020.0004] -16C7 ; [.3573.0020.0002] -16C8 ; [.3574.0020.0002] -16D5 ; [.3574.0020.0004][.0000.010B.0004] -16C9 ; [.3575.0020.0002] -16CA ; [.3576.0020.0002] -16CB ; [.3576.0020.0004][.0000.010B.0004] -16EA ; [.3576.0020.0004][.0000.010C.0004] -16CC ; [.3576.0020.0004][.0000.010D.0004] -16CD ; [.3576.0020.0004][.0000.010E.0004] -16CE ; [.3576.0020.0004][.0000.010F.0004] -16F2 ; [.3577.0020.0002] -16CF ; [.3578.0020.0002] -16D0 ; [.3578.0020.0004][.0000.010B.0004] -16D1 ; [.3578.0020.0004][.0000.010C.0004] -16D2 ; [.3579.0020.0002] -16D3 ; [.3579.0020.0004][.0000.010B.0004] -16D4 ; [.3579.0020.0004][.0000.010C.0004] -16D6 ; [.357A.0020.0002] -16F6 ; [.357B.0020.0002] -16D7 ; [.357C.0020.0002] -16D8 ; [.357C.0020.0004][.0000.010B.0004] -16D9 ; [.357C.0020.0004][.0000.010C.0004] -16EF ; [.357C.0020.0004][.0000.010B.0004][.357C.0020.0004][.0000.010B.0004] -16DA ; [.357D.0020.0002] -16DB ; [.357D.0020.0004][.0000.010B.0004] -16DC ; [.357E.0020.0002] -16DD ; [.357E.0020.0004][.0000.010B.0004] -16DE ; [.357F.0020.0002] -16DF ; [.3580.0020.0002] -16F3 ; [.3581.0020.0002] -16AA ; [.3582.0020.0002] -16F7 ; [.3583.0020.0002] -16AB ; [.3584.0020.0002] -16F8 ; [.3585.0020.0002] -16A3 ; [.3586.0020.0002] -16E0 ; [.3587.0020.0002] -16E3 ; [.3588.0020.0002] -16B8 ; [.3589.0020.0002] -16E4 ; [.358A.0020.0002] -16E1 ; [.358B.0020.0002] -16E2 ; [.358C.0020.0002] -16E5 ; [.358D.0020.0002] -16E6 ; [.358E.0020.0002] -16E7 ; [.358E.0020.0004][.0000.010B.0004] -16E8 ; [.358E.0020.0004][.0000.010C.0004] -10CC0 ; [.358F.0020.0002] -10C80 ; [.358F.0020.0008] -10CC1 ; [.358F.0020.0004][.0000.010B.0004] -10C81 ; [.358F.0020.000A][.0000.010B.0004] -10CC2 ; [.3590.0020.0002] -10C82 ; [.3590.0020.0008] -10CC3 ; [.3591.0020.0002] -10C83 ; [.3591.0020.0008] -10CC4 ; [.3592.0020.0002] -10C84 ; [.3592.0020.0008] -10CC5 ; [.3593.0020.0002] -10C85 ; [.3593.0020.0008] -10CC6 ; [.3594.0020.0002] -10C86 ; [.3594.0020.0008] -10CC7 ; [.3595.0020.0002] -10C87 ; [.3595.0020.0008] -10CC8 ; [.3596.0020.0002] -10C88 ; [.3596.0020.0008] -10CC9 ; [.3597.0020.0002] -10C89 ; [.3597.0020.0008] -10CCA ; [.3597.0020.0004][.0000.010B.0004] -10C8A ; [.3597.0020.000A][.0000.010B.0004] -10CCB ; [.3597.0020.0004][.0000.010C.0004] -10C8B ; [.3597.0020.000A][.0000.010C.0004] -10CCC ; [.3598.0020.0002] -10C8C ; [.3598.0020.0008] -10CCD ; [.3599.0020.0002] -10C8D ; [.3599.0020.0008] -10CCE ; [.359A.0020.0002] -10C8E ; [.359A.0020.0008] -10CCF ; [.359B.0020.0002] -10C8F ; [.359B.0020.0008] -10CD0 ; [.359C.0020.0002] -10C90 ; [.359C.0020.0008] -10CD1 ; [.359C.0020.0004][.0000.010B.0004] -10C91 ; [.359C.0020.000A][.0000.010B.0004] -10CD2 ; [.359D.0020.0002] -10C92 ; [.359D.0020.0008] -10CD3 ; [.359E.0020.0002] -10C93 ; [.359E.0020.0008] -10CD4 ; [.359F.0020.0002] -10C94 ; [.359F.0020.0008] -10CD5 ; [.35A0.0020.0002] -10C95 ; [.35A0.0020.0008] -10CD6 ; [.35A1.0020.0002] -10C96 ; [.35A1.0020.0008] -10CD7 ; [.35A2.0020.0002] -10C97 ; [.35A2.0020.0008] -10CD8 ; [.35A3.0020.0002] -10C98 ; [.35A3.0020.0008] -10CD9 ; [.35A4.0020.0002] -10C99 ; [.35A4.0020.0008] -10CDA ; [.35A5.0020.0002] -10C9A ; [.35A5.0020.0008] -10CDB ; [.35A6.0020.0002] -10C9B ; [.35A6.0020.0008] -10CDC ; [.35A6.0020.0004][.0000.010B.0004] -10C9C ; [.35A6.0020.000A][.0000.010B.0004] -10CDD ; [.35A7.0020.0002] -10C9D ; [.35A7.0020.0008] -10CDE ; [.35A7.0020.0004][.0000.010B.0004] -10C9E ; [.35A7.0020.000A][.0000.010B.0004] -10CDF ; [.35A7.0020.0004][.0000.010C.0004] -10C9F ; [.35A7.0020.000A][.0000.010C.0004] -10CE0 ; [.35A8.0020.0002] -10CA0 ; [.35A8.0020.0008] -10CE1 ; [.35A9.0020.0002] -10CA1 ; [.35A9.0020.0008] -10CE2 ; [.35AA.0020.0002] -10CA2 ; [.35AA.0020.0008] -10CE3 ; [.35AA.0020.0004][.0000.010B.0004] -10CA3 ; [.35AA.0020.000A][.0000.010B.0004] -10CE4 ; [.35AB.0020.0002] -10CA4 ; [.35AB.0020.0008] -10CE5 ; [.35AC.0020.0002] -10CA5 ; [.35AC.0020.0008] -10CE6 ; [.35AD.0020.0002] -10CA6 ; [.35AD.0020.0008] -10CE7 ; [.35AE.0020.0002] -10CA7 ; [.35AE.0020.0008] -10CE8 ; [.35AF.0020.0002] -10CA8 ; [.35AF.0020.0008] -10CE9 ; [.35B0.0020.0002] -10CA9 ; [.35B0.0020.0008] -10CEA ; [.35B1.0020.0002] -10CAA ; [.35B1.0020.0008] -10CEB ; [.35B1.0020.0004][.0000.010B.0004] -10CAB ; [.35B1.0020.000A][.0000.010B.0004] -10CEC ; [.35B2.0020.0002] -10CAC ; [.35B2.0020.0008] -10CED ; [.35B2.0020.0004][.0000.010B.0004] -10CAD ; [.35B2.0020.000A][.0000.010B.0004] -10CEE ; [.35B3.0020.0002] -10CAE ; [.35B3.0020.0008] -10CEF ; [.35B4.0020.0002] -10CAF ; [.35B4.0020.0008] -10CF0 ; [.35B5.0020.0002] -10CB0 ; [.35B5.0020.0008] -10CF1 ; [.35B6.0020.0002] -10CB1 ; [.35B6.0020.0008] -10CF2 ; [.35B7.0020.0002] -10CB2 ; [.35B7.0020.0008] -10C00 ; [.35B8.0020.0002] -10C01 ; [.35B8.0020.0004][.0000.010B.0004] -10C02 ; [.35B9.0020.0002] -10C03 ; [.35BA.0020.0002] -10C04 ; [.35BA.0020.0004][.0000.010B.0004] -10C05 ; [.35BB.0020.0002] -10C06 ; [.35BC.0020.0002] -10C07 ; [.35BD.0020.0002] -10C08 ; [.35BD.0020.0004][.0000.010B.0004] -10C09 ; [.35BE.0020.0002] -10C0A ; [.35BE.0020.0004][.0000.010B.0004] -10C0B ; [.35BF.0020.0002] -10C0C ; [.35BF.0020.0004][.0000.010B.0004] -10C0D ; [.35C0.0020.0002] -10C0E ; [.35C0.0020.0004][.0000.010B.0004] -10C0F ; [.35C1.0020.0002] -10C10 ; [.35C1.0020.0004][.0000.010B.0004] -10C11 ; [.35C2.0020.0002] -10C12 ; [.35C2.0020.0004][.0000.010B.0004] -10C13 ; [.35C3.0020.0002] -10C14 ; [.35C4.0020.0002] -10C15 ; [.35C4.0020.0004][.0000.010B.0004] -10C16 ; [.35C5.0020.0002] -10C17 ; [.35C5.0020.0004][.0000.010B.0004] -10C18 ; [.35C6.0020.0002] -10C19 ; [.35C6.0020.0004][.0000.010B.0004] -10C1A ; [.35C7.0020.0002] -10C1B ; [.35C7.0020.0004][.0000.010B.0004] -10C1C ; [.35C8.0020.0002] -10C1D ; [.35C8.0020.0004][.0000.010B.0004] -10C1E ; [.35C9.0020.0002] -10C1F ; [.35C9.0020.0004][.0000.010B.0004] -10C20 ; [.35CA.0020.0002] -10C21 ; [.35CB.0020.0002] -10C22 ; [.35CC.0020.0002] -10C23 ; [.35CD.0020.0002] -10C24 ; [.35CE.0020.0002] -10C25 ; [.35CE.0020.0004][.0000.010B.0004] -10C26 ; [.35CF.0020.0002] -10C27 ; [.35CF.0020.0004][.0000.010B.0004] -10C28 ; [.35D0.0020.0002] -10C29 ; [.35D0.0020.0004][.0000.010B.0004] -10C2A ; [.35D1.0020.0002] -10C2B ; [.35D1.0020.0004][.0000.010B.0004] -10C2C ; [.35D2.0020.0002] -10C2D ; [.35D3.0020.0002] -10C2E ; [.35D3.0020.0004][.0000.010B.0004] -10C2F ; [.35D4.0020.0002] -10C30 ; [.35D5.0020.0002] -10C31 ; [.35D6.0020.0002] -10C32 ; [.35D7.0020.0002] -10C33 ; [.35D7.0020.0004][.0000.010B.0004] -10C34 ; [.35D8.0020.0002] -10C35 ; [.35D8.0020.0004][.0000.010B.0004] -10C36 ; [.35D9.0020.0002] -10C37 ; [.35D9.0020.0004][.0000.010B.0004] -10C38 ; [.35DA.0020.0002] -10C39 ; [.35DA.0020.0004][.0000.010B.0004] -10C3A ; [.35DB.0020.0002] -10C3B ; [.35DB.0020.0004][.0000.010B.0004] -10C3C ; [.35DC.0020.0002] -10C3D ; [.35DD.0020.0002] -10C3E ; [.35DE.0020.0002] -10C3F ; [.35DF.0020.0002] -10C40 ; [.35DF.0020.0004][.0000.010B.0004] -10C41 ; [.35E0.0020.0002] -10C42 ; [.35E0.0020.0004][.0000.010B.0004] -10C43 ; [.35E1.0020.0002] -10C44 ; [.35E1.0020.0004][.0000.010B.0004] -10C45 ; [.35E2.0020.0002] -10C46 ; [.35E2.0020.0004][.0000.010B.0004] -10C47 ; [.35E3.0020.0002] -10C48 ; [.35E4.0020.0002] -A500 ; [.35E5.0020.0002] -A501 ; [.35E6.0020.0002] -A502 ; [.35E7.0020.0002] -A503 ; [.35E8.0020.0002] -A504 ; [.35E9.0020.0002] -A505 ; [.35EA.0020.0002] -A506 ; [.35EB.0020.0002] -A507 ; [.35EC.0020.0002] -A508 ; [.35ED.0020.0002] -A509 ; [.35EE.0020.0002] -A50A ; [.35EF.0020.0002] -A50B ; [.35F0.0020.0002] -A50C ; [.35F1.0020.0002] -A613 ; [.35F1.0020.0004][.36F0.0020.0004] -A50D ; [.35F2.0020.0002] -A50E ; [.35F3.0020.0002] -A50F ; [.35F4.0020.0002] -A510 ; [.35F5.0020.0002] -A511 ; [.35F6.0020.0002] -A512 ; [.35F7.0020.0002] -A513 ; [.35F8.0020.0002] -A514 ; [.35F9.0020.0002] -A515 ; [.35FA.0020.0002] -A516 ; [.35FB.0020.0002] -A517 ; [.35FC.0020.0002] -A518 ; [.35FD.0020.0002] -A519 ; [.35FE.0020.0002] -A51A ; [.35FF.0020.0002] -A51B ; [.3600.0020.0002] -A51C ; [.3601.0020.0002] -A51D ; [.3602.0020.0002] -A51E ; [.3603.0020.0002] -A614 ; [.3603.0020.0004][.36F0.0020.0004] -A51F ; [.3604.0020.0002] -A520 ; [.3605.0020.0002] -A521 ; [.3606.0020.0002] -A522 ; [.3607.0020.0002] -A523 ; [.3608.0020.0002] -A524 ; [.3609.0020.0002] -A525 ; [.360A.0020.0002] -A526 ; [.360B.0020.0002] -A527 ; [.360C.0020.0002] -A528 ; [.360D.0020.0002] -A529 ; [.360E.0020.0002] -A52A ; [.360F.0020.0002] -A52B ; [.3610.0020.0002] -A52C ; [.3611.0020.0002] -A52D ; [.3612.0020.0002] -A52E ; [.3613.0020.0002] -A52F ; [.3614.0020.0002] -A530 ; [.3615.0020.0002] -A531 ; [.3616.0020.0002] -A532 ; [.3617.0020.0002] -A533 ; [.3618.0020.0002] -A615 ; [.3618.0020.0004][.36F0.0020.0004] -A534 ; [.3619.0020.0002] -A535 ; [.361A.0020.0002] -A536 ; [.361B.0020.0002] -A537 ; [.361C.0020.0002] -A538 ; [.361D.0020.0002] -A539 ; [.361E.0020.0002] -A53A ; [.361F.0020.0002] -A53B ; [.3620.0020.0002] -A53C ; [.3621.0020.0002] -A53D ; [.3622.0020.0002] -A53E ; [.3623.0020.0002] -A53F ; [.3624.0020.0002] -A540 ; [.3625.0020.0002] -A541 ; [.3626.0020.0002] -A542 ; [.3627.0020.0002] -A543 ; [.3628.0020.0002] -A544 ; [.3629.0020.0002] -A545 ; [.362A.0020.0002] -A546 ; [.362B.0020.0002] -A547 ; [.362C.0020.0002] -A616 ; [.362C.0020.0004][.36F1.0020.0004] -A548 ; [.362D.0020.0002] -A549 ; [.362E.0020.0002] -A54A ; [.362F.0020.0002] -A54B ; [.3630.0020.0002] -A54C ; [.3631.0020.0002] -A54D ; [.3632.0020.0002] -A54E ; [.3633.0020.0002] -A54F ; [.3634.0020.0002] -A550 ; [.3635.0020.0002] -A551 ; [.3636.0020.0002] -A552 ; [.3637.0020.0002] -A617 ; [.3637.0020.0004][.36F0.0020.0004] -A553 ; [.3638.0020.0002] -A554 ; [.3639.0020.0002] -A555 ; [.363A.0020.0002] -A556 ; [.363B.0020.0002] -A557 ; [.363C.0020.0002] -A558 ; [.363D.0020.0002] -A610 ; [.363D.0020.0004] -A618 ; [.363D.0020.0004][.36F1.0020.0004] -A559 ; [.363E.0020.0002] -A55A ; [.363F.0020.0002] -A619 ; [.363F.0020.0004][.36F1.0020.0004] -A55B ; [.3640.0020.0002] -A55C ; [.3641.0020.0002] -A55D ; [.3642.0020.0002] -A55E ; [.3643.0020.0002] -A55F ; [.3644.0020.0002] -A560 ; [.3645.0020.0002] -A61A ; [.3645.0020.0004][.36F0.0020.0004] -A561 ; [.3646.0020.0002] -A562 ; [.3647.0020.0002] -A563 ; [.3648.0020.0002] -A564 ; [.3649.0020.0002] -A565 ; [.364A.0020.0002] -A566 ; [.364B.0020.0002] -A567 ; [.364C.0020.0002] -A568 ; [.364D.0020.0002] -A569 ; [.364E.0020.0002] -A56A ; [.364F.0020.0002] -A611 ; [.364F.0020.0004] -A56B ; [.3650.0020.0002] -A56C ; [.3651.0020.0002] -A56D ; [.3652.0020.0002] -A56E ; [.3653.0020.0002] -A62A ; [.3653.0020.0004] -A56F ; [.3654.0020.0002] -A570 ; [.3655.0020.0002] -A571 ; [.3656.0020.0002] -A572 ; [.3657.0020.0002] -A573 ; [.3658.0020.0002] -A574 ; [.3659.0020.0002] -A575 ; [.365A.0020.0002] -A576 ; [.365B.0020.0002] -A577 ; [.365C.0020.0002] -A578 ; [.365D.0020.0002] -A579 ; [.365E.0020.0002] -A57A ; [.365F.0020.0002] -A57B ; [.3660.0020.0002] -A57C ; [.3661.0020.0002] -A57D ; [.3662.0020.0002] -A57E ; [.3663.0020.0002] -A57F ; [.3664.0020.0002] -A580 ; [.3665.0020.0002] -A581 ; [.3666.0020.0002] -A582 ; [.3667.0020.0002] -A583 ; [.3668.0020.0002] -A584 ; [.3669.0020.0002] -A585 ; [.366A.0020.0002] -A61B ; [.366A.0020.0004][.36F0.0020.0004] -A586 ; [.366B.0020.0002] -A587 ; [.366C.0020.0002] -A612 ; [.366C.0020.0004] -A588 ; [.366D.0020.0002] -A589 ; [.366E.0020.0002] -A58A ; [.366F.0020.0002] -A58B ; [.3670.0020.0002] -A58C ; [.3671.0020.0002] -A58D ; [.3672.0020.0002] -A58E ; [.3673.0020.0002] -A58F ; [.3674.0020.0002] -A590 ; [.3675.0020.0002] -A591 ; [.3676.0020.0002] -A592 ; [.3677.0020.0002] -A593 ; [.3678.0020.0002] -A594 ; [.3679.0020.0002] -A595 ; [.367A.0020.0002] -A596 ; [.367B.0020.0002] -A597 ; [.367C.0020.0002] -A598 ; [.367D.0020.0002] -A599 ; [.367E.0020.0002] -A59A ; [.367F.0020.0002] -A59B ; [.3680.0020.0002] -A59C ; [.3681.0020.0002] -A59D ; [.3682.0020.0002] -A59E ; [.3683.0020.0002] -A59F ; [.3684.0020.0002] -A5A0 ; [.3685.0020.0002] -A5A1 ; [.3686.0020.0002] -A5A2 ; [.3687.0020.0002] -A5A3 ; [.3688.0020.0002] -A5A4 ; [.3689.0020.0002] -A5A5 ; [.368A.0020.0002] -A5A6 ; [.368B.0020.0002] -A5A7 ; [.368C.0020.0002] -A5A8 ; [.368D.0020.0002] -A5A9 ; [.368E.0020.0002] -A5AA ; [.368F.0020.0002] -A5AB ; [.3690.0020.0002] -A5AC ; [.3691.0020.0002] -A5AD ; [.3692.0020.0002] -A5AE ; [.3693.0020.0002] -A5AF ; [.3694.0020.0002] -A5B0 ; [.3695.0020.0002] -A5B1 ; [.3696.0020.0002] -A5B2 ; [.3697.0020.0002] -A5B3 ; [.3698.0020.0002] -A5B4 ; [.3699.0020.0002] -A61C ; [.3699.0020.0004][.36F0.0020.0004] -A5B5 ; [.369A.0020.0002] -A5B6 ; [.369B.0020.0002] -A5B7 ; [.369C.0020.0002] -A5B8 ; [.369D.0020.0002] -A5B9 ; [.369E.0020.0002] -A5BA ; [.369F.0020.0002] -A5BB ; [.36A0.0020.0002] -A5BC ; [.36A1.0020.0002] -A5BD ; [.36A2.0020.0002] -A5BE ; [.36A3.0020.0002] -A5BF ; [.36A4.0020.0002] -A5C0 ; [.36A5.0020.0002] -A5C1 ; [.36A6.0020.0002] -A5C2 ; [.36A7.0020.0002] -A5C3 ; [.36A8.0020.0002] -A5C4 ; [.36A9.0020.0002] -A5C5 ; [.36AA.0020.0002] -A5C6 ; [.36AB.0020.0002] -A5C7 ; [.36AC.0020.0002] -A5C8 ; [.36AD.0020.0002] -A5C9 ; [.36AE.0020.0002] -A5CA ; [.36AF.0020.0002] -A5CB ; [.36B0.0020.0002] -A61D ; [.36B0.0020.0004][.36F0.0020.0004] -A5CC ; [.36B1.0020.0002] -A5CD ; [.36B2.0020.0002] -A5CE ; [.36B3.0020.0002] -A5CF ; [.36B4.0020.0002] -A5D0 ; [.36B5.0020.0002] -A5D1 ; [.36B6.0020.0002] -A62B ; [.36B6.0020.0004] -A61E ; [.36B6.0020.0004][.36F1.0020.0004] -A5D2 ; [.36B7.0020.0002] -A5D3 ; [.36B8.0020.0002] -A5D4 ; [.36B9.0020.0002] -A5D5 ; [.36BA.0020.0002] -A5D6 ; [.36BB.0020.0002] -A5D7 ; [.36BC.0020.0002] -A5D8 ; [.36BD.0020.0002] -A61F ; [.36BD.0020.0004][.36F0.0020.0004] -A5D9 ; [.36BE.0020.0002] -A5DA ; [.36BF.0020.0002] -A5DB ; [.36C0.0020.0002] -A5DC ; [.36C1.0020.0002] -A5DD ; [.36C2.0020.0002] -A5DE ; [.36C3.0020.0002] -A5DF ; [.36C4.0020.0002] -A5E0 ; [.36C5.0020.0002] -A5E1 ; [.36C6.0020.0002] -A5E2 ; [.36C7.0020.0002] -A5E3 ; [.36C8.0020.0002] -A5E4 ; [.36C9.0020.0002] -A5E5 ; [.36CA.0020.0002] -A5E6 ; [.36CB.0020.0002] -A5E7 ; [.36CC.0020.0002] -A5E8 ; [.36CD.0020.0002] -A5E9 ; [.36CE.0020.0002] -A5EA ; [.36CF.0020.0002] -A5EB ; [.36D0.0020.0002] -A5EC ; [.36D1.0020.0002] -A5ED ; [.36D2.0020.0002] -A5EE ; [.36D3.0020.0002] -A5EF ; [.36D4.0020.0002] -A5F0 ; [.36D5.0020.0002] -A5F1 ; [.36D6.0020.0002] -A5F2 ; [.36D7.0020.0002] -A5F3 ; [.36D8.0020.0002] -A5F4 ; [.36D9.0020.0002] -A5F5 ; [.36DA.0020.0002] -A5F6 ; [.36DB.0020.0002] -A5F7 ; [.36DC.0020.0002] -A5F8 ; [.36DD.0020.0002] -A5F9 ; [.36DE.0020.0002] -A5FA ; [.36DF.0020.0002] -A5FB ; [.36E0.0020.0002] -A5FC ; [.36E1.0020.0002] -A5FD ; [.36E2.0020.0002] -A5FE ; [.36E3.0020.0002] -A5FF ; [.36E4.0020.0002] -A600 ; [.36E5.0020.0002] -A601 ; [.36E6.0020.0002] -A602 ; [.36E7.0020.0002] -A603 ; [.36E8.0020.0002] -A604 ; [.36E9.0020.0002] -A605 ; [.36EA.0020.0002] -A606 ; [.36EB.0020.0002] -A607 ; [.36EC.0020.0002] -A608 ; [.36ED.0020.0002] -A609 ; [.36EE.0020.0002] -A60A ; [.36EF.0020.0002] -A60B ; [.36F0.0020.0002] -A60C ; [.36F1.0020.0002] -A6A0 ; [.36F2.0020.0002] -A6A1 ; [.36F3.0020.0002] -A6A2 ; [.36F4.0020.0002] -A6A3 ; [.36F5.0020.0002] -A6A4 ; [.36F6.0020.0002] -A6A5 ; [.36F7.0020.0002] -A6A6 ; [.36F8.0020.0002] -A6A7 ; [.36F9.0020.0002] -A6A8 ; [.36FA.0020.0002] -A6A9 ; [.36FB.0020.0002] -A6AA ; [.36FC.0020.0002] -A6AB ; [.36FD.0020.0002] -A6AC ; [.36FE.0020.0002] -A6AD ; [.36FF.0020.0002] -A6AE ; [.3700.0020.0002] -A6AF ; [.3701.0020.0002] -A6B0 ; [.3702.0020.0002] -A6B1 ; [.3703.0020.0002] -A6B2 ; [.3704.0020.0002] -A6B3 ; [.3705.0020.0002] -A6B4 ; [.3706.0020.0002] -A6B5 ; [.3707.0020.0002] -A6B6 ; [.3708.0020.0002] -A6B7 ; [.3709.0020.0002] -A6B8 ; [.370A.0020.0002] -A6B9 ; [.370B.0020.0002] -A6BA ; [.370C.0020.0002] -A6BB ; [.370D.0020.0002] -A6BC ; [.370E.0020.0002] -A6BD ; [.370F.0020.0002] -A6BE ; [.3710.0020.0002] -A6BF ; [.3711.0020.0002] -A6C0 ; [.3712.0020.0002] -A6C1 ; [.3713.0020.0002] -A6C2 ; [.3714.0020.0002] -A6C3 ; [.3715.0020.0002] -A6C4 ; [.3716.0020.0002] -A6C5 ; [.3717.0020.0002] -A6C6 ; [.3718.0020.0002] -A6C7 ; [.3719.0020.0002] -A6C8 ; [.371A.0020.0002] -A6C9 ; [.371B.0020.0002] -A6CA ; [.371C.0020.0002] -A6CB ; [.371D.0020.0002] -A6CC ; [.371E.0020.0002] -A6CD ; [.371F.0020.0002] -A6CE ; [.3720.0020.0002] -A6CF ; [.3721.0020.0002] -A6D0 ; [.3722.0020.0002] -A6D1 ; [.3723.0020.0002] -A6D2 ; [.3724.0020.0002] -A6D3 ; [.3725.0020.0002] -A6D4 ; [.3726.0020.0002] -A6D5 ; [.3727.0020.0002] -A6D6 ; [.3728.0020.0002] -A6D7 ; [.3729.0020.0002] -A6D8 ; [.372A.0020.0002] -A6D9 ; [.372B.0020.0002] -A6DA ; [.372C.0020.0002] -A6DB ; [.372D.0020.0002] -A6DC ; [.372E.0020.0002] -A6DD ; [.372F.0020.0002] -A6DE ; [.3730.0020.0002] -A6DF ; [.3731.0020.0002] -A6E0 ; [.3732.0020.0002] -A6E1 ; [.3733.0020.0002] -A6E2 ; [.3734.0020.0002] -A6E3 ; [.3735.0020.0002] -A6E4 ; [.3736.0020.0002] -A6E5 ; [.3737.0020.0002] -A6E6 ; [.3738.0020.0002] -A6E7 ; [.3739.0020.0002] -A6E8 ; [.373A.0020.0002] -A6E9 ; [.373B.0020.0002] -A6EA ; [.373C.0020.0002] -A6EB ; [.373D.0020.0002] -A6EC ; [.373E.0020.0002] -A6ED ; [.373F.0020.0002] -A6EE ; [.3740.0020.0002] -A6EF ; [.3741.0020.0002] -16800 ; [.3742.0020.0002] -16801 ; [.3743.0020.0002] -16802 ; [.3744.0020.0002] -16803 ; [.3745.0020.0002] -16804 ; [.3746.0020.0002] -16805 ; [.3747.0020.0002] -16806 ; [.3748.0020.0002] -16807 ; [.3749.0020.0002] -16808 ; [.374A.0020.0002] -16809 ; [.374B.0020.0002] -1680A ; [.374C.0020.0002] -1680B ; [.374D.0020.0002] -1680C ; [.374E.0020.0002] -1680D ; [.374F.0020.0002] -1680E ; [.3750.0020.0002] -1680F ; [.3751.0020.0002] -16810 ; [.3752.0020.0002] -16811 ; [.3753.0020.0002] -16812 ; [.3754.0020.0002] -16813 ; [.3755.0020.0002] -16814 ; [.3756.0020.0002] -16815 ; [.3757.0020.0002] -16816 ; [.3758.0020.0002] -16817 ; [.3759.0020.0002] -16818 ; [.375A.0020.0002] -16819 ; [.375B.0020.0002] -1681A ; [.375C.0020.0002] -1681B ; [.375D.0020.0002] -1681C ; [.375E.0020.0002] -1681D ; [.375F.0020.0002] -1681E ; [.3760.0020.0002] -1681F ; [.3761.0020.0002] -16820 ; [.3762.0020.0002] -16821 ; [.3763.0020.0002] -16822 ; [.3764.0020.0002] -16823 ; [.3765.0020.0002] -16824 ; [.3766.0020.0002] -16825 ; [.3767.0020.0002] -16826 ; [.3768.0020.0002] -16827 ; [.3769.0020.0002] -16828 ; [.376A.0020.0002] -16829 ; [.376B.0020.0002] -1682A ; [.376C.0020.0002] -1682B ; [.376D.0020.0002] -1682C ; [.376E.0020.0002] -1682D ; [.376F.0020.0002] -1682E ; [.3770.0020.0002] -1682F ; [.3771.0020.0002] -16830 ; [.3772.0020.0002] -16831 ; [.3773.0020.0002] -16832 ; [.3774.0020.0002] -16833 ; [.3775.0020.0002] -16834 ; [.3776.0020.0002] -16835 ; [.3777.0020.0002] -16836 ; [.3778.0020.0002] -16837 ; [.3779.0020.0002] -16838 ; [.377A.0020.0002] -16839 ; [.377B.0020.0002] -1683A ; [.377C.0020.0002] -1683B ; [.377D.0020.0002] -1683C ; [.377E.0020.0002] -1683D ; [.377F.0020.0002] -1683E ; [.3780.0020.0002] -1683F ; [.3781.0020.0002] -16840 ; [.3782.0020.0002] -16841 ; [.3783.0020.0002] -16842 ; [.3784.0020.0002] -16843 ; [.3785.0020.0002] -16844 ; [.3786.0020.0002] -16845 ; [.3787.0020.0002] -16846 ; [.3788.0020.0002] -16847 ; [.3789.0020.0002] -16848 ; [.378A.0020.0002] -16849 ; [.378B.0020.0002] -1684A ; [.378C.0020.0002] -1684B ; [.378D.0020.0002] -1684C ; [.378E.0020.0002] -1684D ; [.378F.0020.0002] -1684E ; [.3790.0020.0002] -1684F ; [.3791.0020.0002] -16850 ; [.3792.0020.0002] -16851 ; [.3793.0020.0002] -16852 ; [.3794.0020.0002] -16853 ; [.3795.0020.0002] -16854 ; [.3796.0020.0002] -16855 ; [.3797.0020.0002] -16856 ; [.3798.0020.0002] -16857 ; [.3799.0020.0002] -16858 ; [.379A.0020.0002] -16859 ; [.379B.0020.0002] -1685A ; [.379C.0020.0002] -1685B ; [.379D.0020.0002] -1685C ; [.379E.0020.0002] -1685D ; [.379F.0020.0002] -1685E ; [.37A0.0020.0002] -1685F ; [.37A1.0020.0002] -16860 ; [.37A2.0020.0002] -16861 ; [.37A3.0020.0002] -16862 ; [.37A4.0020.0002] -16863 ; [.37A5.0020.0002] -16864 ; [.37A6.0020.0002] -16865 ; [.37A7.0020.0002] -16866 ; [.37A8.0020.0002] -16867 ; [.37A9.0020.0002] -16868 ; [.37AA.0020.0002] -16869 ; [.37AB.0020.0002] -1686A ; [.37AC.0020.0002] -1686B ; [.37AD.0020.0002] -1686C ; [.37AE.0020.0002] -1686D ; [.37AF.0020.0002] -1686E ; [.37B0.0020.0002] -1686F ; [.37B1.0020.0002] -16870 ; [.37B2.0020.0002] -16871 ; [.37B3.0020.0002] -16872 ; [.37B4.0020.0002] -16873 ; [.37B5.0020.0002] -16874 ; [.37B6.0020.0002] -16875 ; [.37B7.0020.0002] -16876 ; [.37B8.0020.0002] -16877 ; [.37B9.0020.0002] -16878 ; [.37BA.0020.0002] -16879 ; [.37BB.0020.0002] -1687A ; [.37BC.0020.0002] -1687B ; [.37BD.0020.0002] -1687C ; [.37BE.0020.0002] -1687D ; [.37BF.0020.0002] -1687E ; [.37C0.0020.0002] -1687F ; [.37C1.0020.0002] -16880 ; [.37C2.0020.0002] -16881 ; [.37C3.0020.0002] -16882 ; [.37C4.0020.0002] -16883 ; [.37C5.0020.0002] -16884 ; [.37C6.0020.0002] -16885 ; [.37C7.0020.0002] -16886 ; [.37C8.0020.0002] -16887 ; [.37C9.0020.0002] -16888 ; [.37CA.0020.0002] -16889 ; [.37CB.0020.0002] -1688A ; [.37CC.0020.0002] -1688B ; [.37CD.0020.0002] -1688C ; [.37CE.0020.0002] -1688D ; [.37CF.0020.0002] -1688E ; [.37D0.0020.0002] -1688F ; [.37D1.0020.0002] -16890 ; [.37D2.0020.0002] -16891 ; [.37D3.0020.0002] -16892 ; [.37D4.0020.0002] -16893 ; [.37D5.0020.0002] -16894 ; [.37D6.0020.0002] -16895 ; [.37D7.0020.0002] -16896 ; [.37D8.0020.0002] -16897 ; [.37D9.0020.0002] -16898 ; [.37DA.0020.0002] -16899 ; [.37DB.0020.0002] -1689A ; [.37DC.0020.0002] -1689B ; [.37DD.0020.0002] -1689C ; [.37DE.0020.0002] -1689D ; [.37DF.0020.0002] -1689E ; [.37E0.0020.0002] -1689F ; [.37E1.0020.0002] -168A0 ; [.37E2.0020.0002] -168A1 ; [.37E3.0020.0002] -168A2 ; [.37E4.0020.0002] -168A3 ; [.37E5.0020.0002] -168A4 ; [.37E6.0020.0002] -168A5 ; [.37E7.0020.0002] -168A6 ; [.37E8.0020.0002] -168A7 ; [.37E9.0020.0002] -168A8 ; [.37EA.0020.0002] -168A9 ; [.37EB.0020.0002] -168AA ; [.37EC.0020.0002] -168AB ; [.37ED.0020.0002] -168AC ; [.37EE.0020.0002] -168AD ; [.37EF.0020.0002] -168AE ; [.37F0.0020.0002] -168AF ; [.37F1.0020.0002] -168B0 ; [.37F2.0020.0002] -168B1 ; [.37F3.0020.0002] -168B2 ; [.37F4.0020.0002] -168B3 ; [.37F5.0020.0002] -168B4 ; [.37F6.0020.0002] -168B5 ; [.37F7.0020.0002] -168B6 ; [.37F8.0020.0002] -168B7 ; [.37F9.0020.0002] -168B8 ; [.37FA.0020.0002] -168B9 ; [.37FB.0020.0002] -168BA ; [.37FC.0020.0002] -168BB ; [.37FD.0020.0002] -168BC ; [.37FE.0020.0002] -168BD ; [.37FF.0020.0002] -168BE ; [.3800.0020.0002] -168BF ; [.3801.0020.0002] -168C0 ; [.3802.0020.0002] -168C1 ; [.3803.0020.0002] -168C2 ; [.3804.0020.0002] -168C3 ; [.3805.0020.0002] -168C4 ; [.3806.0020.0002] -168C5 ; [.3807.0020.0002] -168C6 ; [.3808.0020.0002] -168C7 ; [.3809.0020.0002] -168C8 ; [.380A.0020.0002] -168C9 ; [.380B.0020.0002] -168CA ; [.380C.0020.0002] -168CB ; [.380D.0020.0002] -168CC ; [.380E.0020.0002] -168CD ; [.380F.0020.0002] -168CE ; [.3810.0020.0002] -168CF ; [.3811.0020.0002] -168D0 ; [.3812.0020.0002] -168D1 ; [.3813.0020.0002] -168D2 ; [.3814.0020.0002] -168D3 ; [.3815.0020.0002] -168D4 ; [.3816.0020.0002] -168D5 ; [.3817.0020.0002] -168D6 ; [.3818.0020.0002] -168D7 ; [.3819.0020.0002] -168D8 ; [.381A.0020.0002] -168D9 ; [.381B.0020.0002] -168DA ; [.381C.0020.0002] -168DB ; [.381D.0020.0002] -168DC ; [.381E.0020.0002] -168DD ; [.381F.0020.0002] -168DE ; [.3820.0020.0002] -168DF ; [.3821.0020.0002] -168E0 ; [.3822.0020.0002] -168E1 ; [.3823.0020.0002] -168E2 ; [.3824.0020.0002] -168E3 ; [.3825.0020.0002] -168E4 ; [.3826.0020.0002] -168E5 ; [.3827.0020.0002] -168E6 ; [.3828.0020.0002] -168E7 ; [.3829.0020.0002] -168E8 ; [.382A.0020.0002] -168E9 ; [.382B.0020.0002] -168EA ; [.382C.0020.0002] -168EB ; [.382D.0020.0002] -168EC ; [.382E.0020.0002] -168ED ; [.382F.0020.0002] -168EE ; [.3830.0020.0002] -168EF ; [.3831.0020.0002] -168F0 ; [.3832.0020.0002] -168F1 ; [.3833.0020.0002] -168F2 ; [.3834.0020.0002] -168F3 ; [.3835.0020.0002] -168F4 ; [.3836.0020.0002] -168F5 ; [.3837.0020.0002] -168F6 ; [.3838.0020.0002] -168F7 ; [.3839.0020.0002] -168F8 ; [.383A.0020.0002] -168F9 ; [.383B.0020.0002] -168FA ; [.383C.0020.0002] -168FB ; [.383D.0020.0002] -168FC ; [.383E.0020.0002] -168FD ; [.383F.0020.0002] -168FE ; [.3840.0020.0002] -168FF ; [.3841.0020.0002] -16900 ; [.3842.0020.0002] -16901 ; [.3843.0020.0002] -16902 ; [.3844.0020.0002] -16903 ; [.3845.0020.0002] -16904 ; [.3846.0020.0002] -16905 ; [.3847.0020.0002] -16906 ; [.3848.0020.0002] -16907 ; [.3849.0020.0002] -16908 ; [.384A.0020.0002] -16909 ; [.384B.0020.0002] -1690A ; [.384C.0020.0002] -1690B ; [.384D.0020.0002] -1690C ; [.384E.0020.0002] -1690D ; [.384F.0020.0002] -1690E ; [.3850.0020.0002] -1690F ; [.3851.0020.0002] -16910 ; [.3852.0020.0002] -16911 ; [.3853.0020.0002] -16912 ; [.3854.0020.0002] -16913 ; [.3855.0020.0002] -16914 ; [.3856.0020.0002] -16915 ; [.3857.0020.0002] -16916 ; [.3858.0020.0002] -16917 ; [.3859.0020.0002] -16918 ; [.385A.0020.0002] -16919 ; [.385B.0020.0002] -1691A ; [.385C.0020.0002] -1691B ; [.385D.0020.0002] -1691C ; [.385E.0020.0002] -1691D ; [.385F.0020.0002] -1691E ; [.3860.0020.0002] -1691F ; [.3861.0020.0002] -16920 ; [.3862.0020.0002] -16921 ; [.3863.0020.0002] -16922 ; [.3864.0020.0002] -16923 ; [.3865.0020.0002] -16924 ; [.3866.0020.0002] -16925 ; [.3867.0020.0002] -16926 ; [.3868.0020.0002] -16927 ; [.3869.0020.0002] -16928 ; [.386A.0020.0002] -16929 ; [.386B.0020.0002] -1692A ; [.386C.0020.0002] -1692B ; [.386D.0020.0002] -1692C ; [.386E.0020.0002] -1692D ; [.386F.0020.0002] -1692E ; [.3870.0020.0002] -1692F ; [.3871.0020.0002] -16930 ; [.3872.0020.0002] -16931 ; [.3873.0020.0002] -16932 ; [.3874.0020.0002] -16933 ; [.3875.0020.0002] -16934 ; [.3876.0020.0002] -16935 ; [.3877.0020.0002] -16936 ; [.3878.0020.0002] -16937 ; [.3879.0020.0002] -16938 ; [.387A.0020.0002] -16939 ; [.387B.0020.0002] -1693A ; [.387C.0020.0002] -1693B ; [.387D.0020.0002] -1693C ; [.387E.0020.0002] -1693D ; [.387F.0020.0002] -1693E ; [.3880.0020.0002] -1693F ; [.3881.0020.0002] -16940 ; [.3882.0020.0002] -16941 ; [.3883.0020.0002] -16942 ; [.3884.0020.0002] -16943 ; [.3885.0020.0002] -16944 ; [.3886.0020.0002] -16945 ; [.3887.0020.0002] -16946 ; [.3888.0020.0002] -16947 ; [.3889.0020.0002] -16948 ; [.388A.0020.0002] -16949 ; [.388B.0020.0002] -1694A ; [.388C.0020.0002] -1694B ; [.388D.0020.0002] -1694C ; [.388E.0020.0002] -1694D ; [.388F.0020.0002] -1694E ; [.3890.0020.0002] -1694F ; [.3891.0020.0002] -16950 ; [.3892.0020.0002] -16951 ; [.3893.0020.0002] -16952 ; [.3894.0020.0002] -16953 ; [.3895.0020.0002] -16954 ; [.3896.0020.0002] -16955 ; [.3897.0020.0002] -16956 ; [.3898.0020.0002] -16957 ; [.3899.0020.0002] -16958 ; [.389A.0020.0002] -16959 ; [.389B.0020.0002] -1695A ; [.389C.0020.0002] -1695B ; [.389D.0020.0002] -1695C ; [.389E.0020.0002] -1695D ; [.389F.0020.0002] -1695E ; [.38A0.0020.0002] -1695F ; [.38A1.0020.0002] -16960 ; [.38A2.0020.0002] -16961 ; [.38A3.0020.0002] -16962 ; [.38A4.0020.0002] -16963 ; [.38A5.0020.0002] -16964 ; [.38A6.0020.0002] -16965 ; [.38A7.0020.0002] -16966 ; [.38A8.0020.0002] -16967 ; [.38A9.0020.0002] -16968 ; [.38AA.0020.0002] -16969 ; [.38AB.0020.0002] -1696A ; [.38AC.0020.0002] -1696B ; [.38AD.0020.0002] -1696C ; [.38AE.0020.0002] -1696D ; [.38AF.0020.0002] -1696E ; [.38B0.0020.0002] -1696F ; [.38B1.0020.0002] -16970 ; [.38B2.0020.0002] -16971 ; [.38B3.0020.0002] -16972 ; [.38B4.0020.0002] -16973 ; [.38B5.0020.0002] -16974 ; [.38B6.0020.0002] -16975 ; [.38B7.0020.0002] -16976 ; [.38B8.0020.0002] -16977 ; [.38B9.0020.0002] -16978 ; [.38BA.0020.0002] -16979 ; [.38BB.0020.0002] -1697A ; [.38BC.0020.0002] -1697B ; [.38BD.0020.0002] -1697C ; [.38BE.0020.0002] -1697D ; [.38BF.0020.0002] -1697E ; [.38C0.0020.0002] -1697F ; [.38C1.0020.0002] -16980 ; [.38C2.0020.0002] -16981 ; [.38C3.0020.0002] -16982 ; [.38C4.0020.0002] -16983 ; [.38C5.0020.0002] -16984 ; [.38C6.0020.0002] -16985 ; [.38C7.0020.0002] -16986 ; [.38C8.0020.0002] -16987 ; [.38C9.0020.0002] -16988 ; [.38CA.0020.0002] -16989 ; [.38CB.0020.0002] -1698A ; [.38CC.0020.0002] -1698B ; [.38CD.0020.0002] -1698C ; [.38CE.0020.0002] -1698D ; [.38CF.0020.0002] -1698E ; [.38D0.0020.0002] -1698F ; [.38D1.0020.0002] -16990 ; [.38D2.0020.0002] -16991 ; [.38D3.0020.0002] -16992 ; [.38D4.0020.0002] -16993 ; [.38D5.0020.0002] -16994 ; [.38D6.0020.0002] -16995 ; [.38D7.0020.0002] -16996 ; [.38D8.0020.0002] -16997 ; [.38D9.0020.0002] -16998 ; [.38DA.0020.0002] -16999 ; [.38DB.0020.0002] -1699A ; [.38DC.0020.0002] -1699B ; [.38DD.0020.0002] -1699C ; [.38DE.0020.0002] -1699D ; [.38DF.0020.0002] -1699E ; [.38E0.0020.0002] -1699F ; [.38E1.0020.0002] -169A0 ; [.38E2.0020.0002] -169A1 ; [.38E3.0020.0002] -169A2 ; [.38E4.0020.0002] -169A3 ; [.38E5.0020.0002] -169A4 ; [.38E6.0020.0002] -169A5 ; [.38E7.0020.0002] -169A6 ; [.38E8.0020.0002] -169A7 ; [.38E9.0020.0002] -169A8 ; [.38EA.0020.0002] -169A9 ; [.38EB.0020.0002] -169AA ; [.38EC.0020.0002] -169AB ; [.38ED.0020.0002] -169AC ; [.38EE.0020.0002] -169AD ; [.38EF.0020.0002] -169AE ; [.38F0.0020.0002] -169AF ; [.38F1.0020.0002] -169B0 ; [.38F2.0020.0002] -169B1 ; [.38F3.0020.0002] -169B2 ; [.38F4.0020.0002] -169B3 ; [.38F5.0020.0002] -169B4 ; [.38F6.0020.0002] -169B5 ; [.38F7.0020.0002] -169B6 ; [.38F8.0020.0002] -169B7 ; [.38F9.0020.0002] -169B8 ; [.38FA.0020.0002] -169B9 ; [.38FB.0020.0002] -169BA ; [.38FC.0020.0002] -169BB ; [.38FD.0020.0002] -169BC ; [.38FE.0020.0002] -169BD ; [.38FF.0020.0002] -169BE ; [.3900.0020.0002] -169BF ; [.3901.0020.0002] -169C0 ; [.3902.0020.0002] -169C1 ; [.3903.0020.0002] -169C2 ; [.3904.0020.0002] -169C3 ; [.3905.0020.0002] -169C4 ; [.3906.0020.0002] -169C5 ; [.3907.0020.0002] -169C6 ; [.3908.0020.0002] -169C7 ; [.3909.0020.0002] -169C8 ; [.390A.0020.0002] -169C9 ; [.390B.0020.0002] -169CA ; [.390C.0020.0002] -169CB ; [.390D.0020.0002] -169CC ; [.390E.0020.0002] -169CD ; [.390F.0020.0002] -169CE ; [.3910.0020.0002] -169CF ; [.3911.0020.0002] -169D0 ; [.3912.0020.0002] -169D1 ; [.3913.0020.0002] -169D2 ; [.3914.0020.0002] -169D3 ; [.3915.0020.0002] -169D4 ; [.3916.0020.0002] -169D5 ; [.3917.0020.0002] -169D6 ; [.3918.0020.0002] -169D7 ; [.3919.0020.0002] -169D8 ; [.391A.0020.0002] -169D9 ; [.391B.0020.0002] -169DA ; [.391C.0020.0002] -169DB ; [.391D.0020.0002] -169DC ; [.391E.0020.0002] -169DD ; [.391F.0020.0002] -169DE ; [.3920.0020.0002] -169DF ; [.3921.0020.0002] -169E0 ; [.3922.0020.0002] -169E1 ; [.3923.0020.0002] -169E2 ; [.3924.0020.0002] -169E3 ; [.3925.0020.0002] -169E4 ; [.3926.0020.0002] -169E5 ; [.3927.0020.0002] -169E6 ; [.3928.0020.0002] -169E7 ; [.3929.0020.0002] -169E8 ; [.392A.0020.0002] -169E9 ; [.392B.0020.0002] -169EA ; [.392C.0020.0002] -169EB ; [.392D.0020.0002] -169EC ; [.392E.0020.0002] -169ED ; [.392F.0020.0002] -169EE ; [.3930.0020.0002] -169EF ; [.3931.0020.0002] -169F0 ; [.3932.0020.0002] -169F1 ; [.3933.0020.0002] -169F2 ; [.3934.0020.0002] -169F3 ; [.3935.0020.0002] -169F4 ; [.3936.0020.0002] -169F5 ; [.3937.0020.0002] -169F6 ; [.3938.0020.0002] -169F7 ; [.3939.0020.0002] -169F8 ; [.393A.0020.0002] -169F9 ; [.393B.0020.0002] -169FA ; [.393C.0020.0002] -169FB ; [.393D.0020.0002] -169FC ; [.393E.0020.0002] -169FD ; [.393F.0020.0002] -169FE ; [.3940.0020.0002] -169FF ; [.3941.0020.0002] -16A00 ; [.3942.0020.0002] -16A01 ; [.3943.0020.0002] -16A02 ; [.3944.0020.0002] -16A03 ; [.3945.0020.0002] -16A04 ; [.3946.0020.0002] -16A05 ; [.3947.0020.0002] -16A06 ; [.3948.0020.0002] -16A07 ; [.3949.0020.0002] -16A08 ; [.394A.0020.0002] -16A09 ; [.394B.0020.0002] -16A0A ; [.394C.0020.0002] -16A0B ; [.394D.0020.0002] -16A0C ; [.394E.0020.0002] -16A0D ; [.394F.0020.0002] -16A0E ; [.3950.0020.0002] -16A0F ; [.3951.0020.0002] -16A10 ; [.3952.0020.0002] -16A11 ; [.3953.0020.0002] -16A12 ; [.3954.0020.0002] -16A13 ; [.3955.0020.0002] -16A14 ; [.3956.0020.0002] -16A15 ; [.3957.0020.0002] -16A16 ; [.3958.0020.0002] -16A17 ; [.3959.0020.0002] -16A18 ; [.395A.0020.0002] -16A19 ; [.395B.0020.0002] -16A1A ; [.395C.0020.0002] -16A1B ; [.395D.0020.0002] -16A1C ; [.395E.0020.0002] -16A1D ; [.395F.0020.0002] -16A1E ; [.3960.0020.0002] -16A1F ; [.3961.0020.0002] -16A20 ; [.3962.0020.0002] -16A21 ; [.3963.0020.0002] -16A22 ; [.3964.0020.0002] -16A23 ; [.3965.0020.0002] -16A24 ; [.3966.0020.0002] -16A25 ; [.3967.0020.0002] -16A26 ; [.3968.0020.0002] -16A27 ; [.3969.0020.0002] -16A28 ; [.396A.0020.0002] -16A29 ; [.396B.0020.0002] -16A2A ; [.396C.0020.0002] -16A2B ; [.396D.0020.0002] -16A2C ; [.396E.0020.0002] -16A2D ; [.396F.0020.0002] -16A2E ; [.3970.0020.0002] -16A2F ; [.3971.0020.0002] -16A30 ; [.3972.0020.0002] -16A31 ; [.3973.0020.0002] -16A32 ; [.3974.0020.0002] -16A33 ; [.3975.0020.0002] -16A34 ; [.3976.0020.0002] -16A35 ; [.3977.0020.0002] -16A36 ; [.3978.0020.0002] -16A37 ; [.3979.0020.0002] -16A38 ; [.397A.0020.0002] -16AD0 ; [.397B.0020.0002] -16AD1 ; [.397C.0020.0002] -16AD2 ; [.397D.0020.0002] -16AD3 ; [.397E.0020.0002] -16AD4 ; [.397F.0020.0002] -16AD5 ; [.3980.0020.0002] -16AD6 ; [.3981.0020.0002] -16AD7 ; [.3982.0020.0002] -16AD8 ; [.3983.0020.0002] -16AD9 ; [.3984.0020.0002] -16ADA ; [.3985.0020.0002] -16ADB ; [.3986.0020.0002] -16ADC ; [.3987.0020.0002] -16ADD ; [.3988.0020.0002] -16ADE ; [.3989.0020.0002] -16ADF ; [.398A.0020.0002] -16AE0 ; [.398B.0020.0002] -16AE1 ; [.398C.0020.0002] -16AE2 ; [.398D.0020.0002] -16AE3 ; [.398E.0020.0002] -16AE4 ; [.398F.0020.0002] -16AE5 ; [.3990.0020.0002] -16AE6 ; [.3991.0020.0002] -16AE7 ; [.3992.0020.0002] -16AE8 ; [.3993.0020.0002] -16AE9 ; [.3994.0020.0002] -16AEA ; [.3995.0020.0002] -16AEB ; [.3996.0020.0002] -16AEC ; [.3997.0020.0002] -16AED ; [.3998.0020.0002] -1E800 ; [.3999.0020.0002] -1E801 ; [.399A.0020.0002] -1E802 ; [.399B.0020.0002] -1E803 ; [.399C.0020.0002] -1E804 ; [.399D.0020.0002] -1E805 ; [.399E.0020.0002] -1E806 ; [.399F.0020.0002] -1E807 ; [.39A0.0020.0002] -1E808 ; [.39A1.0020.0002] -1E809 ; [.39A2.0020.0002] -1E80A ; [.39A3.0020.0002] -1E80B ; [.39A4.0020.0002] -1E80C ; [.39A5.0020.0002] -1E80D ; [.39A6.0020.0002] -1E80E ; [.39A7.0020.0002] -1E80F ; [.39A8.0020.0002] -1E810 ; [.39A9.0020.0002] -1E811 ; [.39AA.0020.0002] -1E812 ; [.39AB.0020.0002] -1E813 ; [.39AC.0020.0002] -1E814 ; [.39AD.0020.0002] -1E815 ; [.39AE.0020.0002] -1E816 ; [.39AF.0020.0002] -1E817 ; [.39B0.0020.0002] -1E818 ; [.39B1.0020.0002] -1E819 ; [.39B2.0020.0002] -1E81A ; [.39B3.0020.0002] -1E81B ; [.39B4.0020.0002] -1E81C ; [.39B5.0020.0002] -1E81D ; [.39B6.0020.0002] -1E81E ; [.39B7.0020.0002] -1E81F ; [.39B8.0020.0002] -1E820 ; [.39B9.0020.0002] -1E821 ; [.39BA.0020.0002] -1E822 ; [.39BB.0020.0002] -1E823 ; [.39BC.0020.0002] -1E824 ; [.39BD.0020.0002] -1E825 ; [.39BE.0020.0002] -1E826 ; [.39BF.0020.0002] -1E827 ; [.39C0.0020.0002] -1E828 ; [.39C1.0020.0002] -1E829 ; [.39C2.0020.0002] -1E82A ; [.39C3.0020.0002] -1E82B ; [.39C4.0020.0002] -1E82C ; [.39C5.0020.0002] -1E82D ; [.39C6.0020.0002] -1E82E ; [.39C7.0020.0002] -1E82F ; [.39C8.0020.0002] -1E830 ; [.39C9.0020.0002] -1E831 ; [.39CA.0020.0002] -1E832 ; [.39CB.0020.0002] -1E833 ; [.39CC.0020.0002] -1E834 ; [.39CD.0020.0002] -1E835 ; [.39CE.0020.0002] -1E836 ; [.39CF.0020.0002] -1E837 ; [.39D0.0020.0002] -1E838 ; [.39D1.0020.0002] -1E839 ; [.39D2.0020.0002] -1E83A ; [.39D3.0020.0002] -1E83B ; [.39D4.0020.0002] -1E83C ; [.39D5.0020.0002] -1E83D ; [.39D6.0020.0002] -1E83E ; [.39D7.0020.0002] -1E83F ; [.39D8.0020.0002] -1E840 ; [.39D9.0020.0002] -1E841 ; [.39DA.0020.0002] -1E842 ; [.39DB.0020.0002] -1E843 ; [.39DC.0020.0002] -1E844 ; [.39DD.0020.0002] -1E845 ; [.39DE.0020.0002] -1E846 ; [.39DF.0020.0002] -1E847 ; [.39E0.0020.0002] -1E848 ; [.39E1.0020.0002] -1E849 ; [.39E2.0020.0002] -1E84A ; [.39E3.0020.0002] -1E84B ; [.39E4.0020.0002] -1E84C ; [.39E5.0020.0002] -1E84D ; [.39E6.0020.0002] -1E84E ; [.39E7.0020.0002] -1E84F ; [.39E8.0020.0002] -1E850 ; [.39E9.0020.0002] -1E851 ; [.39EA.0020.0002] -1E852 ; [.39EB.0020.0002] -1E853 ; [.39EC.0020.0002] -1E854 ; [.39ED.0020.0002] -1E855 ; [.39EE.0020.0002] -1E856 ; [.39EF.0020.0002] -1E857 ; [.39F0.0020.0002] -1E858 ; [.39F1.0020.0002] -1E859 ; [.39F2.0020.0002] -1E85A ; [.39F3.0020.0002] -1E85B ; [.39F4.0020.0002] -1E85C ; [.39F5.0020.0002] -1E85D ; [.39F6.0020.0002] -1E85E ; [.39F7.0020.0002] -1E85F ; [.39F8.0020.0002] -1E860 ; [.39F9.0020.0002] -1E861 ; [.39FA.0020.0002] -1E862 ; [.39FB.0020.0002] -1E863 ; [.39FC.0020.0002] -1E864 ; [.39FD.0020.0002] -1E865 ; [.39FE.0020.0002] -1E866 ; [.39FF.0020.0002] -1E867 ; [.3A00.0020.0002] -1E868 ; [.3A01.0020.0002] -1E869 ; [.3A02.0020.0002] -1E86A ; [.3A03.0020.0002] -1E86B ; [.3A04.0020.0002] -1E86C ; [.3A05.0020.0002] -1E86D ; [.3A06.0020.0002] -1E86E ; [.3A07.0020.0002] -1E86F ; [.3A08.0020.0002] -1E870 ; [.3A09.0020.0002] -1E871 ; [.3A0A.0020.0002] -1E872 ; [.3A0B.0020.0002] -1E873 ; [.3A0C.0020.0002] -1E874 ; [.3A0D.0020.0002] -1E875 ; [.3A0E.0020.0002] -1E876 ; [.3A0F.0020.0002] -1E877 ; [.3A10.0020.0002] -1E878 ; [.3A11.0020.0002] -1E879 ; [.3A12.0020.0002] -1E87A ; [.3A13.0020.0002] -1E87B ; [.3A14.0020.0002] -1E87C ; [.3A15.0020.0002] -1E87D ; [.3A16.0020.0002] -1E87E ; [.3A17.0020.0002] -1E87F ; [.3A18.0020.0002] -1E880 ; [.3A19.0020.0002] -1E881 ; [.3A1A.0020.0002] -1E882 ; [.3A1B.0020.0002] -1E883 ; [.3A1C.0020.0002] -1E884 ; [.3A1D.0020.0002] -1E885 ; [.3A1E.0020.0002] -1E886 ; [.3A1F.0020.0002] -1E887 ; [.3A20.0020.0002] -1E888 ; [.3A21.0020.0002] -1E889 ; [.3A22.0020.0002] -1E88A ; [.3A23.0020.0002] -1E88B ; [.3A24.0020.0002] -1E88C ; [.3A25.0020.0002] -1E88D ; [.3A26.0020.0002] -1E88E ; [.3A27.0020.0002] -1E88F ; [.3A28.0020.0002] -1E890 ; [.3A29.0020.0002] -1E891 ; [.3A2A.0020.0002] -1E892 ; [.3A2B.0020.0002] -1E893 ; [.3A2C.0020.0002] -1E894 ; [.3A2D.0020.0002] -1E895 ; [.3A2E.0020.0002] -1E896 ; [.3A2F.0020.0002] -1E897 ; [.3A30.0020.0002] -1E898 ; [.3A31.0020.0002] -1E899 ; [.3A32.0020.0002] -1E89A ; [.3A33.0020.0002] -1E89B ; [.3A34.0020.0002] -1E89C ; [.3A35.0020.0002] -1E89D ; [.3A36.0020.0002] -1E89E ; [.3A37.0020.0002] -1E89F ; [.3A38.0020.0002] -1E8A0 ; [.3A39.0020.0002] -1E8A1 ; [.3A3A.0020.0002] -1E8A2 ; [.3A3B.0020.0002] -1E8A3 ; [.3A3C.0020.0002] -1E8A4 ; [.3A3D.0020.0002] -1E8A5 ; [.3A3E.0020.0002] -1E8A6 ; [.3A3F.0020.0002] -1E8A7 ; [.3A40.0020.0002] -1E8A8 ; [.3A41.0020.0002] -1E8A9 ; [.3A42.0020.0002] -1E8AA ; [.3A43.0020.0002] -1E8AB ; [.3A44.0020.0002] -1E8AC ; [.3A45.0020.0002] -1E8AD ; [.3A46.0020.0002] -1E8AE ; [.3A47.0020.0002] -1E8AF ; [.3A48.0020.0002] -1E8B0 ; [.3A49.0020.0002] -1E8B1 ; [.3A4A.0020.0002] -1E8B2 ; [.3A4B.0020.0002] -1E8B3 ; [.3A4C.0020.0002] -1E8B4 ; [.3A4D.0020.0002] -1E8B5 ; [.3A4E.0020.0002] -1E8B6 ; [.3A4F.0020.0002] -1E8B7 ; [.3A50.0020.0002] -1E8B8 ; [.3A51.0020.0002] -1E8B9 ; [.3A52.0020.0002] -1E8BA ; [.3A53.0020.0002] -1E8BB ; [.3A54.0020.0002] -1E8BC ; [.3A55.0020.0002] -1E8BD ; [.3A56.0020.0002] -1E8BE ; [.3A57.0020.0002] -1E8BF ; [.3A58.0020.0002] -1E8C0 ; [.3A59.0020.0002] -1E8C1 ; [.3A5A.0020.0002] -1E8C2 ; [.3A5B.0020.0002] -1E8C3 ; [.3A5C.0020.0002] -1E8C4 ; [.3A5D.0020.0002] -1100 ; [.3A5E.0020.0002] -3131 ; [.3A5E.0020.0004] -3200 ; [*0310.0020.0004][.3A5E.0020.0004][*0311.0020.0004] -3260 ; [.3A5E.0020.0006] -FFA1 ; [.3A5E.0020.0012] -320E ; [*0310.0020.0004][.3A5E.0020.0004][.3ADC.0020.0004][*0311.0020.0004] -326E ; [.3A5E.0020.0006][.3ADC.0020.0006] -1101 ; [.3A5F.0020.0002] -3132 ; [.3A5F.0020.0004] -FFA2 ; [.3A5F.0020.0012] -1102 ; [.3A60.0020.0002] -3134 ; [.3A60.0020.0004] -3201 ; [*0310.0020.0004][.3A60.0020.0004][*0311.0020.0004] -3261 ; [.3A60.0020.0006] -FFA4 ; [.3A60.0020.0012] -320F ; [*0310.0020.0004][.3A60.0020.0004][.3ADC.0020.0004][*0311.0020.0004] -326F ; [.3A60.0020.0006][.3ADC.0020.0006] -1103 ; [.3A61.0020.0002] -3137 ; [.3A61.0020.0004] -3202 ; [*0310.0020.0004][.3A61.0020.0004][*0311.0020.0004] -3262 ; [.3A61.0020.0006] -FFA7 ; [.3A61.0020.0012] -3210 ; [*0310.0020.0004][.3A61.0020.0004][.3ADC.0020.0004][*0311.0020.0004] -3270 ; [.3A61.0020.0006][.3ADC.0020.0006] -1104 ; [.3A62.0020.0002] -3138 ; [.3A62.0020.0004] -FFA8 ; [.3A62.0020.0012] -1105 ; [.3A63.0020.0002] -3139 ; [.3A63.0020.0004] -3203 ; [*0310.0020.0004][.3A63.0020.0004][*0311.0020.0004] -3263 ; [.3A63.0020.0006] -FFA9 ; [.3A63.0020.0012] -3211 ; [*0310.0020.0004][.3A63.0020.0004][.3ADC.0020.0004][*0311.0020.0004] -3271 ; [.3A63.0020.0006][.3ADC.0020.0006] -1106 ; [.3A64.0020.0002] -3141 ; [.3A64.0020.0004] -3204 ; [*0310.0020.0004][.3A64.0020.0004][*0311.0020.0004] -3264 ; [.3A64.0020.0006] -FFB1 ; [.3A64.0020.0012] -3212 ; [*0310.0020.0004][.3A64.0020.0004][.3ADC.0020.0004][*0311.0020.0004] -3272 ; [.3A64.0020.0006][.3ADC.0020.0006] -1107 ; [.3A65.0020.0002] -3142 ; [.3A65.0020.0004] -3205 ; [*0310.0020.0004][.3A65.0020.0004][*0311.0020.0004] -3265 ; [.3A65.0020.0006] -FFB2 ; [.3A65.0020.0012] -3213 ; [*0310.0020.0004][.3A65.0020.0004][.3ADC.0020.0004][*0311.0020.0004] -3273 ; [.3A65.0020.0006][.3ADC.0020.0006] -1108 ; [.3A66.0020.0002] -3143 ; [.3A66.0020.0004] -FFB3 ; [.3A66.0020.0012] -1109 ; [.3A67.0020.0002] -3145 ; [.3A67.0020.0004] -3206 ; [*0310.0020.0004][.3A67.0020.0004][*0311.0020.0004] -3266 ; [.3A67.0020.0006] -FFB5 ; [.3A67.0020.0012] -3214 ; [*0310.0020.0004][.3A67.0020.0004][.3ADC.0020.0004][*0311.0020.0004] -3274 ; [.3A67.0020.0006][.3ADC.0020.0006] -110A ; [.3A68.0020.0002] -3146 ; [.3A68.0020.0004] -FFB6 ; [.3A68.0020.0012] -110B ; [.3A69.0020.0002] -3147 ; [.3A69.0020.0004] -3207 ; [*0310.0020.0004][.3A69.0020.0004][*0311.0020.0004] -3267 ; [.3A69.0020.0006] -FFB7 ; [.3A69.0020.0012] -3215 ; [*0310.0020.0004][.3A69.0020.0004][.3ADC.0020.0004][*0311.0020.0004] -3275 ; [.3A69.0020.0006][.3ADC.0020.0006] -321D ; [*0310.0020.0004][.3A69.0020.0004][.3AE4.0020.0004][.3A6A.0020.0004][.3AE0.0020.0004][.3B3D.0020.0004][*0311.0020.0004] -321E ; [*0310.0020.0004][.3A69.0020.0004][.3AE4.0020.0004][.3A70.0020.0004][.3AE9.0020.0004][*0311.0020.0004] -327E ; [.3A69.0020.0006][.3AE9.0020.0006] -110C ; [.3A6A.0020.0002] -3148 ; [.3A6A.0020.0004] -3208 ; [*0310.0020.0004][.3A6A.0020.0004][*0311.0020.0004] -3268 ; [.3A6A.0020.0006] -FFB8 ; [.3A6A.0020.0012] -3216 ; [*0310.0020.0004][.3A6A.0020.0004][.3ADC.0020.0004][*0311.0020.0004] -3276 ; [.3A6A.0020.0006][.3ADC.0020.0006] -321C ; [*0310.0020.0004][.3A6A.0020.0004][.3AE9.0020.0004][*0311.0020.0004] -327D ; [.3A6A.0020.0006][.3AE9.0020.0006][.3A69.0020.0006][.3AEF.0020.0006] -110D ; [.3A6B.0020.0002] -3149 ; [.3A6B.0020.0004] -FFB9 ; [.3A6B.0020.0012] -110E ; [.3A6C.0020.0002] -314A ; [.3A6C.0020.0004] -3209 ; [*0310.0020.0004][.3A6C.0020.0004][*0311.0020.0004] -3269 ; [.3A6C.0020.0006] -FFBA ; [.3A6C.0020.0012] -3217 ; [*0310.0020.0004][.3A6C.0020.0004][.3ADC.0020.0004][*0311.0020.0004] -3277 ; [.3A6C.0020.0006][.3ADC.0020.0006] -327C ; [.3A6C.0020.0006][.3ADC.0020.0006][.3B49.0020.0006][.3A5E.0020.0006][.3AE4.0020.0006] -110F ; [.3A6D.0020.0002] -314B ; [.3A6D.0020.0004] -320A ; [*0310.0020.0004][.3A6D.0020.0004][*0311.0020.0004] -326A ; [.3A6D.0020.0006] -FFBB ; [.3A6D.0020.0012] -3218 ; [*0310.0020.0004][.3A6D.0020.0004][.3ADC.0020.0004][*0311.0020.0004] -3278 ; [.3A6D.0020.0006][.3ADC.0020.0006] -1110 ; [.3A6E.0020.0002] -314C ; [.3A6E.0020.0004] -320B ; [*0310.0020.0004][.3A6E.0020.0004][*0311.0020.0004] -326B ; [.3A6E.0020.0006] -FFBC ; [.3A6E.0020.0012] -3219 ; [*0310.0020.0004][.3A6E.0020.0004][.3ADC.0020.0004][*0311.0020.0004] -3279 ; [.3A6E.0020.0006][.3ADC.0020.0006] -1111 ; [.3A6F.0020.0002] -314D ; [.3A6F.0020.0004] -320C ; [*0310.0020.0004][.3A6F.0020.0004][*0311.0020.0004] -326C ; [.3A6F.0020.0006] -FFBD ; [.3A6F.0020.0012] -321A ; [*0310.0020.0004][.3A6F.0020.0004][.3ADC.0020.0004][*0311.0020.0004] -327A ; [.3A6F.0020.0006][.3ADC.0020.0006] -1112 ; [.3A70.0020.0002] -314E ; [.3A70.0020.0004] -320D ; [*0310.0020.0004][.3A70.0020.0004][*0311.0020.0004] -326D ; [.3A70.0020.0006] -FFBE ; [.3A70.0020.0012] -321B ; [*0310.0020.0004][.3A70.0020.0004][.3ADC.0020.0004][*0311.0020.0004] -327B ; [.3A70.0020.0006][.3ADC.0020.0006] -1113 ; [.3A71.0020.0002] -1114 ; [.3A72.0020.0002] -3165 ; [.3A72.0020.0004] -1115 ; [.3A73.0020.0002] -3166 ; [.3A73.0020.0004] -1116 ; [.3A74.0020.0002] -1117 ; [.3A75.0020.0002] -1118 ; [.3A76.0020.0002] -1119 ; [.3A77.0020.0002] -111A ; [.3A78.0020.0002] -3140 ; [.3A78.0020.0004] -FFB0 ; [.3A78.0020.0012] -111B ; [.3A79.0020.0002] -111C ; [.3A7A.0020.0002] -316E ; [.3A7A.0020.0004] -111D ; [.3A7B.0020.0002] -3171 ; [.3A7B.0020.0004] -111E ; [.3A7C.0020.0002] -3172 ; [.3A7C.0020.0004] -111F ; [.3A7D.0020.0002] -1120 ; [.3A7E.0020.0002] -3173 ; [.3A7E.0020.0004] -1121 ; [.3A7F.0020.0002] -3144 ; [.3A7F.0020.0004] -FFB4 ; [.3A7F.0020.0012] -1122 ; [.3A80.0020.0002] -3174 ; [.3A80.0020.0004] -1123 ; [.3A81.0020.0002] -3175 ; [.3A81.0020.0004] -1124 ; [.3A82.0020.0002] -1125 ; [.3A83.0020.0002] -1126 ; [.3A84.0020.0002] -1127 ; [.3A85.0020.0002] -3176 ; [.3A85.0020.0004] -1128 ; [.3A86.0020.0002] -1129 ; [.3A87.0020.0002] -3177 ; [.3A87.0020.0004] -112A ; [.3A88.0020.0002] -112B ; [.3A89.0020.0002] -3178 ; [.3A89.0020.0004] -112C ; [.3A8A.0020.0002] -3179 ; [.3A8A.0020.0004] -112D ; [.3A8B.0020.0002] -317A ; [.3A8B.0020.0004] -112E ; [.3A8C.0020.0002] -317B ; [.3A8C.0020.0004] -112F ; [.3A8D.0020.0002] -317C ; [.3A8D.0020.0004] -1130 ; [.3A8E.0020.0002] -1131 ; [.3A8F.0020.0002] -1132 ; [.3A90.0020.0002] -317D ; [.3A90.0020.0004] -1133 ; [.3A91.0020.0002] -1134 ; [.3A92.0020.0002] -1135 ; [.3A93.0020.0002] -1136 ; [.3A94.0020.0002] -317E ; [.3A94.0020.0004] -1137 ; [.3A95.0020.0002] -1138 ; [.3A96.0020.0002] -1139 ; [.3A97.0020.0002] -113A ; [.3A98.0020.0002] -113B ; [.3A99.0020.0002] -113C ; [.3A9A.0020.0002] -113D ; [.3A9B.0020.0002] -113E ; [.3A9C.0020.0002] -113F ; [.3A9D.0020.0002] -1140 ; [.3A9E.0020.0002] -317F ; [.3A9E.0020.0004] -1141 ; [.3A9F.0020.0002] -1142 ; [.3AA0.0020.0002] -1143 ; [.3AA1.0020.0002] -1144 ; [.3AA2.0020.0002] -1145 ; [.3AA3.0020.0002] -1146 ; [.3AA4.0020.0002] -1147 ; [.3AA5.0020.0002] -3180 ; [.3AA5.0020.0004] -1148 ; [.3AA6.0020.0002] -1149 ; [.3AA7.0020.0002] -114A ; [.3AA8.0020.0002] -114B ; [.3AA9.0020.0002] -114C ; [.3AAA.0020.0002] -3181 ; [.3AAA.0020.0004] -114D ; [.3AAB.0020.0002] -114E ; [.3AAC.0020.0002] -114F ; [.3AAD.0020.0002] -1150 ; [.3AAE.0020.0002] -1151 ; [.3AAF.0020.0002] -1152 ; [.3AB0.0020.0002] -1153 ; [.3AB1.0020.0002] -1154 ; [.3AB2.0020.0002] -1155 ; [.3AB3.0020.0002] -1156 ; [.3AB4.0020.0002] -1157 ; [.3AB5.0020.0002] -3184 ; [.3AB5.0020.0004] -1158 ; [.3AB6.0020.0002] -3185 ; [.3AB6.0020.0004] -1159 ; [.3AB7.0020.0002] -3186 ; [.3AB7.0020.0004] -115A ; [.3AB8.0020.0002] -115B ; [.3AB9.0020.0002] -115C ; [.3ABA.0020.0002] -115D ; [.3ABB.0020.0002] -115E ; [.3ABC.0020.0002] -A960 ; [.3ABD.0020.0002] -A961 ; [.3ABE.0020.0002] -A962 ; [.3ABF.0020.0002] -A963 ; [.3AC0.0020.0002] -A964 ; [.3AC1.0020.0002] -A965 ; [.3AC2.0020.0002] -A966 ; [.3AC3.0020.0002] -A967 ; [.3AC4.0020.0002] -A968 ; [.3AC5.0020.0002] -A969 ; [.3AC6.0020.0002] -A96A ; [.3AC7.0020.0002] -A96B ; [.3AC8.0020.0002] -A96C ; [.3AC9.0020.0002] -A96D ; [.3ACA.0020.0002] -A96E ; [.3ACB.0020.0002] -A96F ; [.3ACC.0020.0002] -A970 ; [.3ACD.0020.0002] -A971 ; [.3ACE.0020.0002] -A972 ; [.3ACF.0020.0002] -A973 ; [.3AD0.0020.0002] -A974 ; [.3AD1.0020.0002] -A975 ; [.3AD2.0020.0002] -A976 ; [.3AD3.0020.0002] -A977 ; [.3AD4.0020.0002] -A978 ; [.3AD5.0020.0002] -A979 ; [.3AD6.0020.0002] -A97A ; [.3AD7.0020.0002] -A97B ; [.3AD8.0020.0002] -A97C ; [.3AD9.0020.0002] -115F ; [.3ADA.0020.0002] -1160 ; [.3ADB.0020.0002] -3164 ; [.3ADB.0020.0004] -FFA0 ; [.3ADB.0020.0012] -1161 ; [.3ADC.0020.0002] -314F ; [.3ADC.0020.0004] -FFC2 ; [.3ADC.0020.0012] -1162 ; [.3ADD.0020.0002] -3150 ; [.3ADD.0020.0004] -FFC3 ; [.3ADD.0020.0012] -1163 ; [.3ADE.0020.0002] -3151 ; [.3ADE.0020.0004] -FFC4 ; [.3ADE.0020.0012] -1164 ; [.3ADF.0020.0002] -3152 ; [.3ADF.0020.0004] -FFC5 ; [.3ADF.0020.0012] -1165 ; [.3AE0.0020.0002] -3153 ; [.3AE0.0020.0004] -FFC6 ; [.3AE0.0020.0012] -1166 ; [.3AE1.0020.0002] -3154 ; [.3AE1.0020.0004] -FFC7 ; [.3AE1.0020.0012] -1167 ; [.3AE2.0020.0002] -3155 ; [.3AE2.0020.0004] -FFCA ; [.3AE2.0020.0012] -1168 ; [.3AE3.0020.0002] -3156 ; [.3AE3.0020.0004] -FFCB ; [.3AE3.0020.0012] -1169 ; [.3AE4.0020.0002] -3157 ; [.3AE4.0020.0004] -FFCC ; [.3AE4.0020.0012] -116A ; [.3AE5.0020.0002] -3158 ; [.3AE5.0020.0004] -FFCD ; [.3AE5.0020.0012] -116B ; [.3AE6.0020.0002] -3159 ; [.3AE6.0020.0004] -FFCE ; [.3AE6.0020.0012] -116C ; [.3AE7.0020.0002] -315A ; [.3AE7.0020.0004] -FFCF ; [.3AE7.0020.0012] -116D ; [.3AE8.0020.0002] -315B ; [.3AE8.0020.0004] -FFD2 ; [.3AE8.0020.0012] -116E ; [.3AE9.0020.0002] -315C ; [.3AE9.0020.0004] -FFD3 ; [.3AE9.0020.0012] -116F ; [.3AEA.0020.0002] -315D ; [.3AEA.0020.0004] -FFD4 ; [.3AEA.0020.0012] -1170 ; [.3AEB.0020.0002] -315E ; [.3AEB.0020.0004] -FFD5 ; [.3AEB.0020.0012] -1171 ; [.3AEC.0020.0002] -315F ; [.3AEC.0020.0004] -FFD6 ; [.3AEC.0020.0012] -1172 ; [.3AED.0020.0002] -3160 ; [.3AED.0020.0004] -FFD7 ; [.3AED.0020.0012] -1173 ; [.3AEE.0020.0002] -3161 ; [.3AEE.0020.0004] -FFDA ; [.3AEE.0020.0012] -1174 ; [.3AEF.0020.0002] -3162 ; [.3AEF.0020.0004] -FFDB ; [.3AEF.0020.0012] -1175 ; [.3AF0.0020.0002] -3163 ; [.3AF0.0020.0004] -FFDC ; [.3AF0.0020.0012] -1176 ; [.3AF1.0020.0002] -1177 ; [.3AF2.0020.0002] -1178 ; [.3AF3.0020.0002] -1179 ; [.3AF4.0020.0002] -117A ; [.3AF5.0020.0002] -117B ; [.3AF6.0020.0002] -117C ; [.3AF7.0020.0002] -117D ; [.3AF8.0020.0002] -117E ; [.3AF9.0020.0002] -117F ; [.3AFA.0020.0002] -1180 ; [.3AFB.0020.0002] -1181 ; [.3AFC.0020.0002] -1182 ; [.3AFD.0020.0002] -1183 ; [.3AFE.0020.0002] -1184 ; [.3AFF.0020.0002] -3187 ; [.3AFF.0020.0004] -1185 ; [.3B00.0020.0002] -3188 ; [.3B00.0020.0004] -1186 ; [.3B01.0020.0002] -1187 ; [.3B02.0020.0002] -1188 ; [.3B03.0020.0002] -3189 ; [.3B03.0020.0004] -1189 ; [.3B04.0020.0002] -118A ; [.3B05.0020.0002] -118B ; [.3B06.0020.0002] -118C ; [.3B07.0020.0002] -118D ; [.3B08.0020.0002] -118E ; [.3B09.0020.0002] -118F ; [.3B0A.0020.0002] -1190 ; [.3B0B.0020.0002] -1191 ; [.3B0C.0020.0002] -318A ; [.3B0C.0020.0004] -1192 ; [.3B0D.0020.0002] -318B ; [.3B0D.0020.0004] -1193 ; [.3B0E.0020.0002] -1194 ; [.3B0F.0020.0002] -318C ; [.3B0F.0020.0004] -1195 ; [.3B10.0020.0002] -1196 ; [.3B11.0020.0002] -1197 ; [.3B12.0020.0002] -1198 ; [.3B13.0020.0002] -1199 ; [.3B14.0020.0002] -119A ; [.3B15.0020.0002] -119B ; [.3B16.0020.0002] -119C ; [.3B17.0020.0002] -119D ; [.3B18.0020.0002] -119E ; [.3B19.0020.0002] -318D ; [.3B19.0020.0004] -119F ; [.3B1A.0020.0002] -11A0 ; [.3B1B.0020.0002] -11A1 ; [.3B1C.0020.0002] -318E ; [.3B1C.0020.0004] -11A2 ; [.3B1D.0020.0002] -11A3 ; [.3B1E.0020.0002] -11A4 ; [.3B1F.0020.0002] -11A5 ; [.3B20.0020.0002] -11A6 ; [.3B21.0020.0002] -11A7 ; [.3B22.0020.0002] -D7B0 ; [.3B23.0020.0002] -D7B1 ; [.3B24.0020.0002] -D7B2 ; [.3B25.0020.0002] -D7B3 ; [.3B26.0020.0002] -D7B4 ; [.3B27.0020.0002] -D7B5 ; [.3B28.0020.0002] -D7B6 ; [.3B29.0020.0002] -D7B7 ; [.3B2A.0020.0002] -D7B8 ; [.3B2B.0020.0002] -D7B9 ; [.3B2C.0020.0002] -D7BA ; [.3B2D.0020.0002] -D7BB ; [.3B2E.0020.0002] -D7BC ; [.3B2F.0020.0002] -D7BD ; [.3B30.0020.0002] -D7BE ; [.3B31.0020.0002] -D7BF ; [.3B32.0020.0002] -D7C0 ; [.3B33.0020.0002] -D7C1 ; [.3B34.0020.0002] -D7C2 ; [.3B35.0020.0002] -D7C3 ; [.3B36.0020.0002] -D7C4 ; [.3B37.0020.0002] -D7C5 ; [.3B38.0020.0002] -D7C6 ; [.3B39.0020.0002] -11A8 ; [.3B3A.0020.0002] -11A9 ; [.3B3B.0020.0002] -11AA ; [.3B3C.0020.0002] -3133 ; [.3B3C.0020.0004] -FFA3 ; [.3B3C.0020.0012] -11AB ; [.3B3D.0020.0002] -11AC ; [.3B3E.0020.0002] -3135 ; [.3B3E.0020.0004] -FFA5 ; [.3B3E.0020.0012] -11AD ; [.3B3F.0020.0002] -3136 ; [.3B3F.0020.0004] -FFA6 ; [.3B3F.0020.0012] -11AE ; [.3B40.0020.0002] -11AF ; [.3B41.0020.0002] -11B0 ; [.3B42.0020.0002] -313A ; [.3B42.0020.0004] -FFAA ; [.3B42.0020.0012] -11B1 ; [.3B43.0020.0002] -313B ; [.3B43.0020.0004] -FFAB ; [.3B43.0020.0012] -11B2 ; [.3B44.0020.0002] -313C ; [.3B44.0020.0004] -FFAC ; [.3B44.0020.0012] -11B3 ; [.3B45.0020.0002] -313D ; [.3B45.0020.0004] -FFAD ; [.3B45.0020.0012] -11B4 ; [.3B46.0020.0002] -313E ; [.3B46.0020.0004] -FFAE ; [.3B46.0020.0012] -11B5 ; [.3B47.0020.0002] -313F ; [.3B47.0020.0004] -FFAF ; [.3B47.0020.0012] -11B6 ; [.3B48.0020.0002] -11B7 ; [.3B49.0020.0002] -11B8 ; [.3B4A.0020.0002] -11B9 ; [.3B4B.0020.0002] -11BA ; [.3B4C.0020.0002] -11BB ; [.3B4D.0020.0002] -11BC ; [.3B4E.0020.0002] -11BD ; [.3B4F.0020.0002] -11BE ; [.3B50.0020.0002] -11BF ; [.3B51.0020.0002] -11C0 ; [.3B52.0020.0002] -11C1 ; [.3B53.0020.0002] -11C2 ; [.3B54.0020.0002] -11C3 ; [.3B55.0020.0002] -11C4 ; [.3B56.0020.0002] -11C5 ; [.3B57.0020.0002] -11C6 ; [.3B58.0020.0002] -11C7 ; [.3B59.0020.0002] -3167 ; [.3B59.0020.0004] -11C8 ; [.3B5A.0020.0002] -3168 ; [.3B5A.0020.0004] -11C9 ; [.3B5B.0020.0002] -11CA ; [.3B5C.0020.0002] -11CB ; [.3B5D.0020.0002] -11CC ; [.3B5E.0020.0002] -3169 ; [.3B5E.0020.0004] -11CD ; [.3B5F.0020.0002] -11CE ; [.3B60.0020.0002] -316A ; [.3B60.0020.0004] -11CF ; [.3B61.0020.0002] -11D0 ; [.3B62.0020.0002] -11D1 ; [.3B63.0020.0002] -11D2 ; [.3B64.0020.0002] -11D3 ; [.3B65.0020.0002] -316B ; [.3B65.0020.0004] -11D4 ; [.3B66.0020.0002] -11D5 ; [.3B67.0020.0002] -11D6 ; [.3B68.0020.0002] -11D7 ; [.3B69.0020.0002] -316C ; [.3B69.0020.0004] -11D8 ; [.3B6A.0020.0002] -11D9 ; [.3B6B.0020.0002] -316D ; [.3B6B.0020.0004] -11DA ; [.3B6C.0020.0002] -11DB ; [.3B6D.0020.0002] -11DC ; [.3B6E.0020.0002] -11DD ; [.3B6F.0020.0002] -316F ; [.3B6F.0020.0004] -11DE ; [.3B70.0020.0002] -11DF ; [.3B71.0020.0002] -3170 ; [.3B71.0020.0004] -11E0 ; [.3B72.0020.0002] -11E1 ; [.3B73.0020.0002] -11E2 ; [.3B74.0020.0002] -11E3 ; [.3B75.0020.0002] -11E4 ; [.3B76.0020.0002] -11E5 ; [.3B77.0020.0002] -11E6 ; [.3B78.0020.0002] -11E7 ; [.3B79.0020.0002] -11E8 ; [.3B7A.0020.0002] -11E9 ; [.3B7B.0020.0002] -11EA ; [.3B7C.0020.0002] -11EB ; [.3B7D.0020.0002] -11EC ; [.3B7E.0020.0002] -11ED ; [.3B7F.0020.0002] -11EE ; [.3B80.0020.0002] -11EF ; [.3B81.0020.0002] -11F0 ; [.3B82.0020.0002] -11F1 ; [.3B83.0020.0002] -3182 ; [.3B83.0020.0004] -11F2 ; [.3B84.0020.0002] -3183 ; [.3B84.0020.0004] -11F3 ; [.3B85.0020.0002] -11F4 ; [.3B86.0020.0002] -11F5 ; [.3B87.0020.0002] -11F6 ; [.3B88.0020.0002] -11F7 ; [.3B89.0020.0002] -11F8 ; [.3B8A.0020.0002] -11F9 ; [.3B8B.0020.0002] -11FA ; [.3B8C.0020.0002] -11FB ; [.3B8D.0020.0002] -11FC ; [.3B8E.0020.0002] -11FD ; [.3B8F.0020.0002] -11FE ; [.3B90.0020.0002] -11FF ; [.3B91.0020.0002] -D7CB ; [.3B92.0020.0002] -D7CC ; [.3B93.0020.0002] -D7CD ; [.3B94.0020.0002] -D7CE ; [.3B95.0020.0002] -D7CF ; [.3B96.0020.0002] -D7D0 ; [.3B97.0020.0002] -D7D1 ; [.3B98.0020.0002] -D7D2 ; [.3B99.0020.0002] -D7D3 ; [.3B9A.0020.0002] -D7D4 ; [.3B9B.0020.0002] -D7D5 ; [.3B9C.0020.0002] -D7D6 ; [.3B9D.0020.0002] -D7D7 ; [.3B9E.0020.0002] -D7D8 ; [.3B9F.0020.0002] -D7D9 ; [.3BA0.0020.0002] -D7DA ; [.3BA1.0020.0002] -D7DB ; [.3BA2.0020.0002] -D7DC ; [.3BA3.0020.0002] -D7DD ; [.3BA4.0020.0002] -D7DE ; [.3BA5.0020.0002] -D7DF ; [.3BA6.0020.0002] -D7E0 ; [.3BA7.0020.0002] -D7E1 ; [.3BA8.0020.0002] -D7E2 ; [.3BA9.0020.0002] -D7E3 ; [.3BAA.0020.0002] -D7E4 ; [.3BAB.0020.0002] -D7E5 ; [.3BAC.0020.0002] -D7E6 ; [.3BAD.0020.0002] -D7E7 ; [.3BAE.0020.0002] -D7E8 ; [.3BAF.0020.0002] -D7E9 ; [.3BB0.0020.0002] -D7EA ; [.3BB1.0020.0002] -D7EB ; [.3BB2.0020.0002] -D7EC ; [.3BB3.0020.0002] -D7ED ; [.3BB4.0020.0002] -D7EE ; [.3BB5.0020.0002] -D7EF ; [.3BB6.0020.0002] -D7F0 ; [.3BB7.0020.0002] -D7F1 ; [.3BB8.0020.0002] -D7F2 ; [.3BB9.0020.0002] -D7F3 ; [.3BBA.0020.0002] -D7F4 ; [.3BBB.0020.0002] -D7F5 ; [.3BBC.0020.0002] -D7F6 ; [.3BBD.0020.0002] -D7F7 ; [.3BBE.0020.0002] -D7F8 ; [.3BBF.0020.0002] -D7F9 ; [.3BC0.0020.0002] -D7FA ; [.3BC1.0020.0002] -D7FB ; [.3BC2.0020.0002] -3041 ; [.3BC3.0020.000D] -3042 ; [.3BC3.0020.000E] -30A1 ; [.3BC3.0020.000F] -FF67 ; [.3BC3.0020.0010] -30A2 ; [.3BC3.0020.0011] -FF71 ; [.3BC3.0020.0012] -32D0 ; [.3BC3.0020.0013] -3303 ; [.3BC3.0020.001C][.1B89.0020.001C][.3BED.0020.001C] -3300 ; [.3BC3.0020.001C][.3BDD.0020.001C][.0000.0038.001C][.1B89.0020.001C][.3BD7.0020.001C] -3301 ; [.3BC3.0020.001C][.3BED.0020.001C][.3BDF.0020.001C][.3BC3.0020.001C] -3302 ; [.3BC3.0020.001C][.3BF4.0020.001C][.3BE0.0020.001C][.0000.0038.001C][.3BC3.0020.001C] -3043 ; [.3BC4.0020.000D] -3044 ; [.3BC4.0020.000E] -30A3 ; [.3BC4.0020.000F] -FF68 ; [.3BC4.0020.0010] -30A4 ; [.3BC4.0020.0011] -FF72 ; [.3BC4.0020.0012] -32D1 ; [.3BC4.0020.0013] -3304 ; [.3BC4.0020.001C][.3BD9.0020.001C][.3BF4.0020.001C][.3BCB.0020.001C][.0000.0037.001C] -3305 ; [.3BC4.0020.001C][.3BF4.0020.001C][.3BD4.0020.001C] -3045 ; [.3BC5.0020.000D] -3046 ; [.3BC5.0020.000E] -30A5 ; [.3BC5.0020.000F] -FF69 ; [.3BC5.0020.0010] -30A6 ; [.3BC5.0020.0011] -FF73 ; [.3BC5.0020.0012] -32D2 ; [.3BC5.0020.0013] -3094 ; [.3BC5.0020.000E][.0000.0037.0002] -30F4 ; [.3BC5.0020.0011][.0000.0037.0002] -3306 ; [.3BC5.0020.001C][.3BC8.0020.001C][.3BF4.0020.001C] -1B000 ; [.3BC6.0020.0011] -3047 ; [.3BC7.0020.000D] -3048 ; [.3BC7.0020.000E] -30A7 ; [.3BC7.0020.000F] -FF6A ; [.3BC7.0020.0010] -30A8 ; [.3BC7.0020.0011] -FF74 ; [.3BC7.0020.0012] -32D3 ; [.3BC7.0020.0013] -3308 ; [.3BC7.0020.001C][.1B89.0020.001C][.3BC9.0020.001C][.1B89.0020.001C] -3307 ; [.3BC7.0020.001C][.3BD0.0020.001C][.3BCB.0020.001C][.1B89.0020.001C][.3BD7.0020.001C][.0000.0037.001C] -3049 ; [.3BC8.0020.000D] -304A ; [.3BC8.0020.000E] -30A9 ; [.3BC8.0020.000F] -FF6B ; [.3BC8.0020.0010] -30AA ; [.3BC8.0020.0011] -FF75 ; [.3BC8.0020.0012] -32D4 ; [.3BC8.0020.0013] -330A ; [.3BC8.0020.001C][.1B89.0020.001C][.3BE4.0020.001C] -3309 ; [.3BC8.0020.001C][.3BF4.0020.001C][.3BD0.0020.001C] -3095 ; [.3BC9.0020.000D] -304B ; [.3BC9.0020.000E] -30F5 ; [.3BC9.0020.000F] -30AB ; [.3BC9.0020.0011] -FF76 ; [.3BC9.0020.0012] -32D5 ; [.3BC9.0020.0013] -304C ; [.3BC9.0020.000E][.0000.0037.0002] -30AC ; [.3BC9.0020.0011][.0000.0037.0002] -330B ; [.3BC9.0020.001C][.3BC4.0020.001C][.3BEC.0020.001C] -330C ; [.3BC9.0020.001C][.3BEB.0020.001C][.3BD5.0020.001C][.3BD7.0020.001C] -330D ; [.3BC9.0020.001C][.3BEF.0020.001C][.3BEC.0020.001C][.1B89.0020.001C] -330E ; [.3BC9.0020.001C][.0000.0037.001C][.3BEF.0020.001C][.3BF4.0020.001C] -330F ; [.3BC9.0020.001C][.0000.0037.001C][.3BF4.0020.001C][.3BE2.0020.001C] -304D ; [.3BCA.0020.000E] -30AD ; [.3BCA.0020.0011] -FF77 ; [.3BCA.0020.0012] -32D6 ; [.3BCA.0020.0013] -304E ; [.3BCA.0020.000E][.0000.0037.0002] -30AE ; [.3BCA.0020.0011][.0000.0037.0002] -3310 ; [.3BCA.0020.001C][.0000.0037.001C][.3BC9.0020.001C][.0000.0037.001C] -3311 ; [.3BCA.0020.001C][.0000.0037.001C][.3BD9.0020.001C][.1B89.0020.001C] -3312 ; [.3BCA.0020.001C][.3BE8.0020.001C][.3BEC.0020.001C][.1B89.0020.001C] -3313 ; [.3BCA.0020.001C][.0000.0037.001C][.3BED.0020.001C][.3BD3.0020.001C][.0000.0037.001C][.1B89.0020.001C] -3314 ; [.3BCA.0020.001C][.3BEF.0020.001C] -3315 ; [.3BCA.0020.001C][.3BEF.0020.001C][.3BCB.0020.001C][.0000.0037.001C][.3BEB.0020.001C][.3BE4.0020.001C] -3316 ; [.3BCA.0020.001C][.3BEF.0020.001C][.3BE5.0020.001C][.1B89.0020.001C][.3BD7.0020.001C][.3BED.0020.001C] -3317 ; [.3BCA.0020.001C][.3BEF.0020.001C][.3BF0.0020.001C][.3BD5.0020.001C][.3BD7.0020.001C] -304F ; [.3BCB.0020.000E] -31F0 ; [.3BCB.0020.000F] -30AF ; [.3BCB.0020.0011] -FF78 ; [.3BCB.0020.0012] -32D7 ; [.3BCB.0020.0013] -3050 ; [.3BCB.0020.000E][.0000.0037.0002] -30B0 ; [.3BCB.0020.0011][.0000.0037.0002] -3318 ; [.3BCB.0020.001C][.0000.0037.001C][.3BEB.0020.001C][.3BE4.0020.001C] -3319 ; [.3BCB.0020.001C][.0000.0037.001C][.3BEB.0020.001C][.3BE4.0020.001C][.3BD7.0020.001C][.3BF4.0020.001C] -331A ; [.3BCB.0020.001C][.3BED.0020.001C][.3BD1.0020.001C][.0000.0037.001C][.3BC4.0020.001C][.3BEF.0020.001C] -331B ; [.3BCB.0020.001C][.3BEF.0020.001C][.1B89.0020.001C][.3BDB.0020.001C] -3096 ; [.3BCC.0020.000D] -3051 ; [.3BCC.0020.000E] -30F6 ; [.3BCC.0020.000F] -30B1 ; [.3BCC.0020.0011] -FF79 ; [.3BCC.0020.0012] -32D8 ; [.3BCC.0020.0013] -3052 ; [.3BCC.0020.000E][.0000.0037.0002] -30B2 ; [.3BCC.0020.0011][.0000.0037.0002] -331C ; [.3BCC.0020.001C][.1B89.0020.001C][.3BD0.0020.001C] -3053 ; [.3BCD.0020.000E] -30B3 ; [.3BCD.0020.0011] -FF7A ; [.3BCD.0020.0012] -32D9 ; [.3BCD.0020.0013] -3054 ; [.3BCD.0020.000E][.0000.0037.0002] -30B4 ; [.3BCD.0020.0011][.0000.0037.0002] -331E ; [.3BCD.0020.001C][.1B89.0020.001C][.3BE1.0020.001C][.0000.0038.001C] -1F201 ; [.3BCD.0020.001C][.3BCD.0020.001C] -30FF ; [.3BCD.0020.0016][.3BD7.0020.0016] -331D ; [.3BCD.0020.001C][.3BED.0020.001C][.3BD8.0020.001C] -3055 ; [.3BCE.0020.000E] -30B5 ; [.3BCE.0020.0011] -FF7B ; [.3BCE.0020.0012] -32DA ; [.3BCE.0020.0013] -1F202 ; [.3BCE.0020.001C] -3056 ; [.3BCE.0020.000E][.0000.0037.0002] -30B6 ; [.3BCE.0020.0011][.0000.0037.0002] -331F ; [.3BCE.0020.001C][.3BC4.0020.001C][.3BCB.0020.001C][.3BED.0020.001C] -3320 ; [.3BCE.0020.001C][.3BF4.0020.001C][.3BD4.0020.001C][.1B89.0020.001C][.3BE4.0020.001C] -3057 ; [.3BCF.0020.000E] -31F1 ; [.3BCF.0020.000F] -30B7 ; [.3BCF.0020.0011] -FF7C ; [.3BCF.0020.0012] -32DB ; [.3BCF.0020.0013] -3058 ; [.3BCF.0020.000E][.0000.0037.0002] -30B8 ; [.3BCF.0020.0011][.0000.0037.0002] -3006 ; [.3BCF.0020.0004][.3BE5.0020.0004] -3321 ; [.3BCF.0020.001C][.3BEC.0020.001C][.3BF4.0020.001C][.3BCB.0020.001C][.0000.0037.001C] -3059 ; [.3BD0.0020.000E] -31F2 ; [.3BD0.0020.000F] -30B9 ; [.3BD0.0020.0011] -FF7D ; [.3BD0.0020.0012] -32DC ; [.3BD0.0020.0013] -305A ; [.3BD0.0020.000E][.0000.0037.0002] -30BA ; [.3BD0.0020.0011][.0000.0037.0002] -305B ; [.3BD1.0020.000E] -30BB ; [.3BD1.0020.0011] -FF7E ; [.3BD1.0020.0012] -32DD ; [.3BD1.0020.0013] -305C ; [.3BD1.0020.000E][.0000.0037.0002] -30BC ; [.3BD1.0020.0011][.0000.0037.0002] -3322 ; [.3BD1.0020.001C][.3BF4.0020.001C][.3BD4.0020.001C] -3323 ; [.3BD1.0020.001C][.3BF4.0020.001C][.3BD7.0020.001C] -305D ; [.3BD2.0020.000E] -30BD ; [.3BD2.0020.0011] -FF7F ; [.3BD2.0020.0012] -32DE ; [.3BD2.0020.0013] -305E ; [.3BD2.0020.000E][.0000.0037.0002] -30BE ; [.3BD2.0020.0011][.0000.0037.0002] -305F ; [.3BD3.0020.000E] -30BF ; [.3BD3.0020.0011] -FF80 ; [.3BD3.0020.0012] -32DF ; [.3BD3.0020.0013] -3060 ; [.3BD3.0020.000E][.0000.0037.0002] -30C0 ; [.3BD3.0020.0011][.0000.0037.0002] -3324 ; [.3BD3.0020.001C][.0000.0037.001C][.1B89.0020.001C][.3BD0.0020.001C] -3061 ; [.3BD4.0020.000E] -30C1 ; [.3BD4.0020.0011] -FF81 ; [.3BD4.0020.0012] -32E0 ; [.3BD4.0020.0013] -3062 ; [.3BD4.0020.000E][.0000.0037.0002] -30C2 ; [.3BD4.0020.0011][.0000.0037.0002] -3063 ; [.3BD5.0020.000D] -3064 ; [.3BD5.0020.000E] -30C3 ; [.3BD5.0020.000F] -FF6F ; [.3BD5.0020.0010] -30C4 ; [.3BD5.0020.0011] -FF82 ; [.3BD5.0020.0012] -32E1 ; [.3BD5.0020.0013] -3065 ; [.3BD5.0020.000E][.0000.0037.0002] -30C5 ; [.3BD5.0020.0011][.0000.0037.0002] -3066 ; [.3BD6.0020.000E] -30C6 ; [.3BD6.0020.0011] -FF83 ; [.3BD6.0020.0012] -32E2 ; [.3BD6.0020.0013] -3067 ; [.3BD6.0020.000E][.0000.0037.0002] -30C7 ; [.3BD6.0020.0011][.0000.0037.0002] -1F213 ; [.3BD6.0020.001C][.0000.0037.001C] -3325 ; [.3BD6.0020.001C][.0000.0037.001C][.3BCF.0020.001C] -3068 ; [.3BD7.0020.000E] -31F3 ; [.3BD7.0020.000F] -30C8 ; [.3BD7.0020.0011] -FF84 ; [.3BD7.0020.0012] -32E3 ; [.3BD7.0020.0013] -3069 ; [.3BD7.0020.000E][.0000.0037.0002] -30C9 ; [.3BD7.0020.0011][.0000.0037.0002] -3326 ; [.3BD7.0020.001C][.0000.0037.001C][.3BED.0020.001C] -3327 ; [.3BD7.0020.001C][.3BF4.0020.001C] -306A ; [.3BD8.0020.000E] -30CA ; [.3BD8.0020.0011] -FF85 ; [.3BD8.0020.0012] -32E4 ; [.3BD8.0020.0013] -3328 ; [.3BD8.0020.001C][.3BDC.0020.001C] -306B ; [.3BD9.0020.000E] -30CB ; [.3BD9.0020.0011] -FF86 ; [.3BD9.0020.0012] -32E5 ; [.3BD9.0020.0013] -306C ; [.3BDA.0020.000E] -31F4 ; [.3BDA.0020.000F] -30CC ; [.3BDA.0020.0011] -FF87 ; [.3BDA.0020.0012] -32E6 ; [.3BDA.0020.0013] -306D ; [.3BDB.0020.000E] -30CD ; [.3BDB.0020.0011] -FF88 ; [.3BDB.0020.0012] -32E7 ; [.3BDB.0020.0013] -306E ; [.3BDC.0020.000E] -30CE ; [.3BDC.0020.0011] -FF89 ; [.3BDC.0020.0012] -32E8 ; [.3BDC.0020.0013] -3329 ; [.3BDC.0020.001C][.3BD5.0020.001C][.3BD7.0020.001C] -306F ; [.3BDD.0020.000E] -31F5 ; [.3BDD.0020.000F] -30CF ; [.3BDD.0020.0011] -FF8A ; [.3BDD.0020.0012] -32E9 ; [.3BDD.0020.0013] -3070 ; [.3BDD.0020.000E][.0000.0037.0002] -30D0 ; [.3BDD.0020.0011][.0000.0037.0002] -3071 ; [.3BDD.0020.000E][.0000.0038.0002] -30D1 ; [.3BDD.0020.0011][.0000.0038.0002] -332B ; [.3BDD.0020.001C][.0000.0038.001C][.1B89.0020.001C][.3BD1.0020.001C][.3BF4.0020.001C][.3BD7.0020.001C] -332C ; [.3BDD.0020.001C][.0000.0038.001C][.1B89.0020.001C][.3BD5.0020.001C] -332D ; [.3BDD.0020.001C][.0000.0037.001C][.1B89.0020.001C][.3BEE.0020.001C][.3BED.0020.001C] -332A ; [.3BDD.0020.001C][.3BC4.0020.001C][.3BD5.0020.001C] -3072 ; [.3BDE.0020.000E] -31F6 ; [.3BDE.0020.000F] -30D2 ; [.3BDE.0020.0011] -FF8B ; [.3BDE.0020.0012] -32EA ; [.3BDE.0020.0013] -3073 ; [.3BDE.0020.000E][.0000.0037.0002] -30D3 ; [.3BDE.0020.0011][.0000.0037.0002] -3074 ; [.3BDE.0020.000E][.0000.0038.0002] -30D4 ; [.3BDE.0020.0011][.0000.0038.0002] -332E ; [.3BDE.0020.001C][.0000.0038.001C][.3BC3.0020.001C][.3BD0.0020.001C][.3BD7.0020.001C][.3BED.0020.001C] -332F ; [.3BDE.0020.001C][.0000.0038.001C][.3BCB.0020.001C][.3BED.0020.001C] -3330 ; [.3BDE.0020.001C][.0000.0038.001C][.3BCD.0020.001C] -3331 ; [.3BDE.0020.001C][.0000.0037.001C][.3BED.0020.001C] -3075 ; [.3BDF.0020.000E] -31F7 ; [.3BDF.0020.000F] -30D5 ; [.3BDF.0020.0011] -FF8C ; [.3BDF.0020.0012] -32EB ; [.3BDF.0020.0013] -3076 ; [.3BDF.0020.000E][.0000.0037.0002] -30D6 ; [.3BDF.0020.0011][.0000.0037.0002] -3077 ; [.3BDF.0020.000E][.0000.0038.0002] -30D7 ; [.3BDF.0020.0011][.0000.0038.0002] -3332 ; [.3BDF.0020.001C][.3BC3.0020.001C][.3BEB.0020.001C][.3BD5.0020.001C][.3BD7.0020.001C][.0000.0037.001C] -3333 ; [.3BDF.0020.001C][.3BC4.0020.001C][.1B89.0020.001C][.3BD7.0020.001C] -3334 ; [.3BDF.0020.001C][.0000.0037.001C][.3BD5.0020.001C][.3BCF.0020.001C][.3BC7.0020.001C][.3BED.0020.001C] -3335 ; [.3BDF.0020.001C][.3BEB.0020.001C][.3BF4.0020.001C] -3078 ; [.3BE0.0020.000E] -31F8 ; [.3BE0.0020.000F] -30D8 ; [.3BE0.0020.0011] -FF8D ; [.3BE0.0020.0012] -32EC ; [.3BE0.0020.0013] -3079 ; [.3BE0.0020.000E][.0000.0037.0002] -30D9 ; [.3BE0.0020.0011][.0000.0037.0002] -307A ; [.3BE0.0020.000E][.0000.0038.0002] -30DA ; [.3BE0.0020.0011][.0000.0038.0002] -333B ; [.3BE0.0020.001C][.0000.0038.001C][.1B89.0020.001C][.3BCF.0020.001C][.0000.0037.001C] -333C ; [.3BE0.0020.001C][.0000.0037.001C][.1B89.0020.001C][.3BD3.0020.001C] -3336 ; [.3BE0.0020.001C][.3BCB.0020.001C][.3BD3.0020.001C][.1B89.0020.001C][.3BED.0020.001C] -3337 ; [.3BE0.0020.001C][.0000.0038.001C][.3BD2.0020.001C] -3338 ; [.3BE0.0020.001C][.0000.0038.001C][.3BD9.0020.001C][.3BDE.0020.001C] -3339 ; [.3BE0.0020.001C][.3BED.0020.001C][.3BD5.0020.001C] -333A ; [.3BE0.0020.001C][.0000.0038.001C][.3BF4.0020.001C][.3BD0.0020.001C] -307B ; [.3BE1.0020.000E] -31F9 ; [.3BE1.0020.000F] -30DB ; [.3BE1.0020.0011] -FF8E ; [.3BE1.0020.0012] -32ED ; [.3BE1.0020.0013] -307C ; [.3BE1.0020.000E][.0000.0037.0002] -30DC ; [.3BE1.0020.0011][.0000.0037.0002] -307D ; [.3BE1.0020.000E][.0000.0038.0002] -30DD ; [.3BE1.0020.0011][.0000.0038.0002] -3341 ; [.3BE1.0020.001C][.1B89.0020.001C][.3BED.0020.001C] -3342 ; [.3BE1.0020.001C][.1B89.0020.001C][.3BF4.0020.001C] -333D ; [.3BE1.0020.001C][.0000.0038.001C][.3BC4.0020.001C][.3BF4.0020.001C][.3BD7.0020.001C] -1F200 ; [.3BE1.0020.001C][.3BC9.0020.001C] -333E ; [.3BE1.0020.001C][.0000.0037.001C][.3BED.0020.001C][.3BD7.0020.001C] -333F ; [.3BE1.0020.001C][.3BF4.0020.001C] -3340 ; [.3BE1.0020.001C][.0000.0038.001C][.3BF4.0020.001C][.3BD7.0020.001C][.0000.0037.001C] -307E ; [.3BE2.0020.000E] -30DE ; [.3BE2.0020.0011] -FF8F ; [.3BE2.0020.0012] -32EE ; [.3BE2.0020.0013] -3343 ; [.3BE2.0020.001C][.3BC4.0020.001C][.3BCB.0020.001C][.3BEF.0020.001C] -3344 ; [.3BE2.0020.001C][.3BC4.0020.001C][.3BED.0020.001C] -303C ; [.3BE2.0020.0004][.3BD0.0020.0004] -3345 ; [.3BE2.0020.001C][.3BD5.0020.001C][.3BDD.0020.001C] -3346 ; [.3BE2.0020.001C][.3BED.0020.001C][.3BCB.0020.001C] -3347 ; [.3BE2.0020.001C][.3BF4.0020.001C][.3BCF.0020.001C][.3BEA.0020.001C][.3BF4.0020.001C] -307F ; [.3BE3.0020.000E] -30DF ; [.3BE3.0020.0011] -FF90 ; [.3BE3.0020.0012] -32EF ; [.3BE3.0020.0013] -3348 ; [.3BE3.0020.001C][.3BCB.0020.001C][.3BEF.0020.001C][.3BF4.0020.001C] -3349 ; [.3BE3.0020.001C][.3BEC.0020.001C] -334A ; [.3BE3.0020.001C][.3BEC.0020.001C][.3BDD.0020.001C][.0000.0037.001C][.1B89.0020.001C][.3BED.0020.001C] -3080 ; [.3BE4.0020.000E] -31FA ; [.3BE4.0020.000F] -30E0 ; [.3BE4.0020.0011] -FF91 ; [.3BE4.0020.0012] -32F0 ; [.3BE4.0020.0013] -3081 ; [.3BE5.0020.000E] -30E1 ; [.3BE5.0020.0011] -FF92 ; [.3BE5.0020.0012] -32F1 ; [.3BE5.0020.0013] -334D ; [.3BE5.0020.001C][.1B89.0020.001C][.3BD7.0020.001C][.3BED.0020.001C] -334B ; [.3BE5.0020.001C][.3BC9.0020.001C][.0000.0037.001C] -334C ; [.3BE5.0020.001C][.3BC9.0020.001C][.0000.0037.001C][.3BD7.0020.001C][.3BF4.0020.001C] -3082 ; [.3BE6.0020.000E] -30E2 ; [.3BE6.0020.0011] -FF93 ; [.3BE6.0020.0012] -32F2 ; [.3BE6.0020.0013] -3083 ; [.3BE7.0020.000D] -3084 ; [.3BE7.0020.000E] -30E3 ; [.3BE7.0020.000F] -FF6C ; [.3BE7.0020.0010] -30E4 ; [.3BE7.0020.0011] -FF94 ; [.3BE7.0020.0012] -32F3 ; [.3BE7.0020.0013] -334E ; [.3BE7.0020.001C][.1B89.0020.001C][.3BD7.0020.001C][.0000.0037.001C] -334F ; [.3BE7.0020.001C][.1B89.0020.001C][.3BED.0020.001C] -3085 ; [.3BE8.0020.000D] -3086 ; [.3BE8.0020.000E] -30E5 ; [.3BE8.0020.000F] -FF6D ; [.3BE8.0020.0010] -30E6 ; [.3BE8.0020.0011] -FF95 ; [.3BE8.0020.0012] -32F4 ; [.3BE8.0020.0013] -3350 ; [.3BE8.0020.001C][.3BC3.0020.001C][.3BF4.0020.001C] -1B001 ; [.3BE9.0020.000E] -3087 ; [.3BEA.0020.000D] -3088 ; [.3BEA.0020.000E] -30E7 ; [.3BEA.0020.000F] -FF6E ; [.3BEA.0020.0010] -30E8 ; [.3BEA.0020.0011] -FF96 ; [.3BEA.0020.0012] -32F5 ; [.3BEA.0020.0013] -309F ; [.3BEA.0020.0016][.3BEC.0020.0016] -3089 ; [.3BEB.0020.000E] -31FB ; [.3BEB.0020.000F] -30E9 ; [.3BEB.0020.0011] -FF97 ; [.3BEB.0020.0012] -32F6 ; [.3BEB.0020.0013] -308A ; [.3BEC.0020.000E] -31FC ; [.3BEC.0020.000F] -30EA ; [.3BEC.0020.0011] -FF98 ; [.3BEC.0020.0012] -32F7 ; [.3BEC.0020.0013] -3351 ; [.3BEC.0020.001C][.3BD5.0020.001C][.3BD7.0020.001C][.3BED.0020.001C] -3352 ; [.3BEC.0020.001C][.3BEB.0020.001C] -308B ; [.3BED.0020.000E] -31FD ; [.3BED.0020.000F] -30EB ; [.3BED.0020.0011] -FF99 ; [.3BED.0020.0012] -32F8 ; [.3BED.0020.0013] -3354 ; [.3BED.0020.001C][.1B89.0020.001C][.3BDF.0020.001C][.0000.0037.001C][.3BED.0020.001C] -3353 ; [.3BED.0020.001C][.3BDE.0020.001C][.0000.0038.001C][.1B89.0020.001C] -308C ; [.3BEE.0020.000E] -31FE ; [.3BEE.0020.000F] -30EC ; [.3BEE.0020.0011] -FF9A ; [.3BEE.0020.0012] -32F9 ; [.3BEE.0020.0013] -3355 ; [.3BEE.0020.001C][.3BE4.0020.001C] -3356 ; [.3BEE.0020.001C][.3BF4.0020.001C][.3BD7.0020.001C][.3BCC.0020.001C][.0000.0037.001C][.3BF4.0020.001C] -308D ; [.3BEF.0020.000E] -31FF ; [.3BEF.0020.000F] -30ED ; [.3BEF.0020.0011] -FF9B ; [.3BEF.0020.0012] -32FA ; [.3BEF.0020.0013] -308E ; [.3BF0.0020.000D] -308F ; [.3BF0.0020.000E] -30EE ; [.3BF0.0020.000F] -30EF ; [.3BF0.0020.0011] -FF9C ; [.3BF0.0020.0012] -32FB ; [.3BF0.0020.0013] -30F7 ; [.3BF0.0020.0011][.0000.0037.0002] -3357 ; [.3BF0.0020.001C][.3BD5.0020.001C][.3BD7.0020.001C] -3090 ; [.3BF1.0020.000E] -30F0 ; [.3BF1.0020.0011] -32FC ; [.3BF1.0020.0013] -30F8 ; [.3BF1.0020.0011][.0000.0037.0002] -3091 ; [.3BF2.0020.000E] -30F1 ; [.3BF2.0020.0011] -32FD ; [.3BF2.0020.0013] -30F9 ; [.3BF2.0020.0011][.0000.0037.0002] -3092 ; [.3BF3.0020.000E] -30F2 ; [.3BF3.0020.0011] -FF66 ; [.3BF3.0020.0012] -32FE ; [.3BF3.0020.0013] -30FA ; [.3BF3.0020.0011][.0000.0037.0002] -3093 ; [.3BF4.0020.000E] -30F3 ; [.3BF4.0020.0011] -FF9D ; [.3BF4.0020.0012] -3105 ; [.3BF5.0020.0002] -31A0 ; [.3BF5.0020.0004][.0000.010C.0004] -3106 ; [.3BF6.0020.0002] -31B4 ; [.3BF6.0020.0019] -3107 ; [.3BF7.0020.0002] -3108 ; [.3BF8.0020.0002] -312A ; [.3BF9.0020.0002] -3109 ; [.3BFA.0020.0002] -310A ; [.3BFB.0020.0002] -31B5 ; [.3BFB.0020.0019] -310B ; [.3BFC.0020.0002] -310C ; [.3BFD.0020.0002] -310D ; [.3BFE.0020.0002] -31A3 ; [.3BFE.0020.0004][.0000.010C.0004] -310E ; [.3BFF.0020.0002] -31B6 ; [.3BFF.0020.0019] -312B ; [.3C00.0020.0002] -31AD ; [.3C01.0020.0002] -310F ; [.3C02.0020.0002] -31B7 ; [.3C02.0020.0019] -3110 ; [.3C03.0020.0002] -31A2 ; [.3C03.0020.0004][.0000.010C.0004] -3111 ; [.3C04.0020.0002] -3112 ; [.3C05.0020.0002] -312C ; [.3C06.0020.0002] -3113 ; [.3C07.0020.0002] -3114 ; [.3C08.0020.0002] -3115 ; [.3C09.0020.0002] -3116 ; [.3C0A.0020.0002] -3117 ; [.3C0B.0020.0002] -31A1 ; [.3C0B.0020.0004][.0000.010C.0004] -3118 ; [.3C0C.0020.0002] -3119 ; [.3C0D.0020.0002] -31B8 ; [.3C0E.0020.0002] -31B9 ; [.3C0F.0020.0002] -31BA ; [.3C10.0020.0002] -311A ; [.3C11.0020.0002] -31A9 ; [.3C11.0020.0004][.0000.010C.0004] -311B ; [.3C12.0020.0002] -31A7 ; [.3C12.0020.0004][.0000.010C.0004] -31A6 ; [.3C13.0020.0002] -311C ; [.3C14.0020.0002] -311D ; [.3C15.0020.0002] -31A4 ; [.3C16.0020.0002] -31A5 ; [.3C16.0020.0004][.0000.010C.0004] -311E ; [.3C17.0020.0002] -31AE ; [.3C17.0020.0004][.0000.010C.0004] -311F ; [.3C18.0020.0002] -3120 ; [.3C19.0020.0002] -31AF ; [.3C19.0020.0004][.0000.010C.0004] -3121 ; [.3C1A.0020.0002] -3122 ; [.3C1B.0020.0002] -3123 ; [.3C1C.0020.0002] -3124 ; [.3C1D.0020.0002] -31B2 ; [.3C1E.0020.0002] -3125 ; [.3C1F.0020.0002] -31B0 ; [.3C20.0020.0002] -31B1 ; [.3C21.0020.0002] -31AC ; [.3C22.0020.0002] -3126 ; [.3C23.0020.0002] -3127 ; [.3C24.0020.0002] -31AA ; [.3C24.0020.0004][.0000.010C.0004] -31B3 ; [.3C24.0020.0016][.0000.010C.0016] -3128 ; [.3C25.0020.0002] -31AB ; [.3C25.0020.0004][.0000.010C.0004] -31A8 ; [.3C25.0020.0004][.0000.010D.0004] -3129 ; [.3C26.0020.0002] -312D ; [.3C27.0020.0002] -A000 ; [.3C28.0020.0002] -A001 ; [.3C29.0020.0002] -A002 ; [.3C2A.0020.0002] -A003 ; [.3C2B.0020.0002] -A004 ; [.3C2C.0020.0002] -A005 ; [.3C2D.0020.0002] -A006 ; [.3C2E.0020.0002] -A007 ; [.3C2F.0020.0002] -A008 ; [.3C30.0020.0002] -A009 ; [.3C31.0020.0002] -A00A ; [.3C32.0020.0002] -A00B ; [.3C33.0020.0002] -A00C ; [.3C34.0020.0002] -A00D ; [.3C35.0020.0002] -A00E ; [.3C36.0020.0002] -A00F ; [.3C37.0020.0002] -A010 ; [.3C38.0020.0002] -A011 ; [.3C39.0020.0002] -A012 ; [.3C3A.0020.0002] -A013 ; [.3C3B.0020.0002] -A014 ; [.3C3C.0020.0002] -A015 ; [.3C3D.0020.0002] -A016 ; [.3C3E.0020.0002] -A017 ; [.3C3F.0020.0002] -A018 ; [.3C40.0020.0002] -A019 ; [.3C41.0020.0002] -A01A ; [.3C42.0020.0002] -A01B ; [.3C43.0020.0002] -A01C ; [.3C44.0020.0002] -A01D ; [.3C45.0020.0002] -A01E ; [.3C46.0020.0002] -A01F ; [.3C47.0020.0002] -A020 ; [.3C48.0020.0002] -A021 ; [.3C49.0020.0002] -A022 ; [.3C4A.0020.0002] -A023 ; [.3C4B.0020.0002] -A024 ; [.3C4C.0020.0002] -A025 ; [.3C4D.0020.0002] -A026 ; [.3C4E.0020.0002] -A027 ; [.3C4F.0020.0002] -A028 ; [.3C50.0020.0002] -A029 ; [.3C51.0020.0002] -A02A ; [.3C52.0020.0002] -A02B ; [.3C53.0020.0002] -A02C ; [.3C54.0020.0002] -A02D ; [.3C55.0020.0002] -A02E ; [.3C56.0020.0002] -A02F ; [.3C57.0020.0002] -A030 ; [.3C58.0020.0002] -A031 ; [.3C59.0020.0002] -A032 ; [.3C5A.0020.0002] -A033 ; [.3C5B.0020.0002] -A034 ; [.3C5C.0020.0002] -A035 ; [.3C5D.0020.0002] -A036 ; [.3C5E.0020.0002] -A037 ; [.3C5F.0020.0002] -A038 ; [.3C60.0020.0002] -A039 ; [.3C61.0020.0002] -A03A ; [.3C62.0020.0002] -A03B ; [.3C63.0020.0002] -A03C ; [.3C64.0020.0002] -A03D ; [.3C65.0020.0002] -A03E ; [.3C66.0020.0002] -A03F ; [.3C67.0020.0002] -A040 ; [.3C68.0020.0002] -A041 ; [.3C69.0020.0002] -A042 ; [.3C6A.0020.0002] -A043 ; [.3C6B.0020.0002] -A044 ; [.3C6C.0020.0002] -A045 ; [.3C6D.0020.0002] -A046 ; [.3C6E.0020.0002] -A047 ; [.3C6F.0020.0002] -A048 ; [.3C70.0020.0002] -A049 ; [.3C71.0020.0002] -A04A ; [.3C72.0020.0002] -A04B ; [.3C73.0020.0002] -A04C ; [.3C74.0020.0002] -A04D ; [.3C75.0020.0002] -A04E ; [.3C76.0020.0002] -A04F ; [.3C77.0020.0002] -A050 ; [.3C78.0020.0002] -A051 ; [.3C79.0020.0002] -A052 ; [.3C7A.0020.0002] -A053 ; [.3C7B.0020.0002] -A054 ; [.3C7C.0020.0002] -A055 ; [.3C7D.0020.0002] -A056 ; [.3C7E.0020.0002] -A057 ; [.3C7F.0020.0002] -A058 ; [.3C80.0020.0002] -A059 ; [.3C81.0020.0002] -A05A ; [.3C82.0020.0002] -A05B ; [.3C83.0020.0002] -A05C ; [.3C84.0020.0002] -A05D ; [.3C85.0020.0002] -A05E ; [.3C86.0020.0002] -A05F ; [.3C87.0020.0002] -A060 ; [.3C88.0020.0002] -A061 ; [.3C89.0020.0002] -A062 ; [.3C8A.0020.0002] -A063 ; [.3C8B.0020.0002] -A064 ; [.3C8C.0020.0002] -A065 ; [.3C8D.0020.0002] -A066 ; [.3C8E.0020.0002] -A067 ; [.3C8F.0020.0002] -A068 ; [.3C90.0020.0002] -A069 ; [.3C91.0020.0002] -A06A ; [.3C92.0020.0002] -A06B ; [.3C93.0020.0002] -A06C ; [.3C94.0020.0002] -A06D ; [.3C95.0020.0002] -A06E ; [.3C96.0020.0002] -A06F ; [.3C97.0020.0002] -A070 ; [.3C98.0020.0002] -A071 ; [.3C99.0020.0002] -A072 ; [.3C9A.0020.0002] -A073 ; [.3C9B.0020.0002] -A074 ; [.3C9C.0020.0002] -A075 ; [.3C9D.0020.0002] -A076 ; [.3C9E.0020.0002] -A077 ; [.3C9F.0020.0002] -A078 ; [.3CA0.0020.0002] -A079 ; [.3CA1.0020.0002] -A07A ; [.3CA2.0020.0002] -A07B ; [.3CA3.0020.0002] -A07C ; [.3CA4.0020.0002] -A07D ; [.3CA5.0020.0002] -A07E ; [.3CA6.0020.0002] -A07F ; [.3CA7.0020.0002] -A080 ; [.3CA8.0020.0002] -A081 ; [.3CA9.0020.0002] -A082 ; [.3CAA.0020.0002] -A083 ; [.3CAB.0020.0002] -A084 ; [.3CAC.0020.0002] -A085 ; [.3CAD.0020.0002] -A086 ; [.3CAE.0020.0002] -A087 ; [.3CAF.0020.0002] -A088 ; [.3CB0.0020.0002] -A089 ; [.3CB1.0020.0002] -A08A ; [.3CB2.0020.0002] -A08B ; [.3CB3.0020.0002] -A08C ; [.3CB4.0020.0002] -A08D ; [.3CB5.0020.0002] -A08E ; [.3CB6.0020.0002] -A08F ; [.3CB7.0020.0002] -A090 ; [.3CB8.0020.0002] -A091 ; [.3CB9.0020.0002] -A092 ; [.3CBA.0020.0002] -A093 ; [.3CBB.0020.0002] -A094 ; [.3CBC.0020.0002] -A095 ; [.3CBD.0020.0002] -A096 ; [.3CBE.0020.0002] -A097 ; [.3CBF.0020.0002] -A098 ; [.3CC0.0020.0002] -A099 ; [.3CC1.0020.0002] -A09A ; [.3CC2.0020.0002] -A09B ; [.3CC3.0020.0002] -A09C ; [.3CC4.0020.0002] -A09D ; [.3CC5.0020.0002] -A09E ; [.3CC6.0020.0002] -A09F ; [.3CC7.0020.0002] -A0A0 ; [.3CC8.0020.0002] -A0A1 ; [.3CC9.0020.0002] -A0A2 ; [.3CCA.0020.0002] -A0A3 ; [.3CCB.0020.0002] -A0A4 ; [.3CCC.0020.0002] -A0A5 ; [.3CCD.0020.0002] -A0A6 ; [.3CCE.0020.0002] -A0A7 ; [.3CCF.0020.0002] -A0A8 ; [.3CD0.0020.0002] -A0A9 ; [.3CD1.0020.0002] -A0AA ; [.3CD2.0020.0002] -A0AB ; [.3CD3.0020.0002] -A0AC ; [.3CD4.0020.0002] -A0AD ; [.3CD5.0020.0002] -A0AE ; [.3CD6.0020.0002] -A0AF ; [.3CD7.0020.0002] -A0B0 ; [.3CD8.0020.0002] -A0B1 ; [.3CD9.0020.0002] -A0B2 ; [.3CDA.0020.0002] -A0B3 ; [.3CDB.0020.0002] -A0B4 ; [.3CDC.0020.0002] -A0B5 ; [.3CDD.0020.0002] -A0B6 ; [.3CDE.0020.0002] -A0B7 ; [.3CDF.0020.0002] -A0B8 ; [.3CE0.0020.0002] -A0B9 ; [.3CE1.0020.0002] -A0BA ; [.3CE2.0020.0002] -A0BB ; [.3CE3.0020.0002] -A0BC ; [.3CE4.0020.0002] -A0BD ; [.3CE5.0020.0002] -A0BE ; [.3CE6.0020.0002] -A0BF ; [.3CE7.0020.0002] -A0C0 ; [.3CE8.0020.0002] -A0C1 ; [.3CE9.0020.0002] -A0C2 ; [.3CEA.0020.0002] -A0C3 ; [.3CEB.0020.0002] -A0C4 ; [.3CEC.0020.0002] -A0C5 ; [.3CED.0020.0002] -A0C6 ; [.3CEE.0020.0002] -A0C7 ; [.3CEF.0020.0002] -A0C8 ; [.3CF0.0020.0002] -A0C9 ; [.3CF1.0020.0002] -A0CA ; [.3CF2.0020.0002] -A0CB ; [.3CF3.0020.0002] -A0CC ; [.3CF4.0020.0002] -A0CD ; [.3CF5.0020.0002] -A0CE ; [.3CF6.0020.0002] -A0CF ; [.3CF7.0020.0002] -A0D0 ; [.3CF8.0020.0002] -A0D1 ; [.3CF9.0020.0002] -A0D2 ; [.3CFA.0020.0002] -A0D3 ; [.3CFB.0020.0002] -A0D4 ; [.3CFC.0020.0002] -A0D5 ; [.3CFD.0020.0002] -A0D6 ; [.3CFE.0020.0002] -A0D7 ; [.3CFF.0020.0002] -A0D8 ; [.3D00.0020.0002] -A0D9 ; [.3D01.0020.0002] -A0DA ; [.3D02.0020.0002] -A0DB ; [.3D03.0020.0002] -A0DC ; [.3D04.0020.0002] -A0DD ; [.3D05.0020.0002] -A0DE ; [.3D06.0020.0002] -A0DF ; [.3D07.0020.0002] -A0E0 ; [.3D08.0020.0002] -A0E1 ; [.3D09.0020.0002] -A0E2 ; [.3D0A.0020.0002] -A0E3 ; [.3D0B.0020.0002] -A0E4 ; [.3D0C.0020.0002] -A0E5 ; [.3D0D.0020.0002] -A0E6 ; [.3D0E.0020.0002] -A0E7 ; [.3D0F.0020.0002] -A0E8 ; [.3D10.0020.0002] -A0E9 ; [.3D11.0020.0002] -A0EA ; [.3D12.0020.0002] -A0EB ; [.3D13.0020.0002] -A0EC ; [.3D14.0020.0002] -A0ED ; [.3D15.0020.0002] -A0EE ; [.3D16.0020.0002] -A0EF ; [.3D17.0020.0002] -A0F0 ; [.3D18.0020.0002] -A0F1 ; [.3D19.0020.0002] -A0F2 ; [.3D1A.0020.0002] -A0F3 ; [.3D1B.0020.0002] -A0F4 ; [.3D1C.0020.0002] -A0F5 ; [.3D1D.0020.0002] -A0F6 ; [.3D1E.0020.0002] -A0F7 ; [.3D1F.0020.0002] -A0F8 ; [.3D20.0020.0002] -A0F9 ; [.3D21.0020.0002] -A0FA ; [.3D22.0020.0002] -A0FB ; [.3D23.0020.0002] -A0FC ; [.3D24.0020.0002] -A0FD ; [.3D25.0020.0002] -A0FE ; [.3D26.0020.0002] -A0FF ; [.3D27.0020.0002] -A100 ; [.3D28.0020.0002] -A101 ; [.3D29.0020.0002] -A102 ; [.3D2A.0020.0002] -A103 ; [.3D2B.0020.0002] -A104 ; [.3D2C.0020.0002] -A105 ; [.3D2D.0020.0002] -A106 ; [.3D2E.0020.0002] -A107 ; [.3D2F.0020.0002] -A108 ; [.3D30.0020.0002] -A109 ; [.3D31.0020.0002] -A10A ; [.3D32.0020.0002] -A10B ; [.3D33.0020.0002] -A10C ; [.3D34.0020.0002] -A10D ; [.3D35.0020.0002] -A10E ; [.3D36.0020.0002] -A10F ; [.3D37.0020.0002] -A110 ; [.3D38.0020.0002] -A111 ; [.3D39.0020.0002] -A112 ; [.3D3A.0020.0002] -A113 ; [.3D3B.0020.0002] -A114 ; [.3D3C.0020.0002] -A115 ; [.3D3D.0020.0002] -A116 ; [.3D3E.0020.0002] -A117 ; [.3D3F.0020.0002] -A118 ; [.3D40.0020.0002] -A119 ; [.3D41.0020.0002] -A11A ; [.3D42.0020.0002] -A11B ; [.3D43.0020.0002] -A11C ; [.3D44.0020.0002] -A11D ; [.3D45.0020.0002] -A11E ; [.3D46.0020.0002] -A11F ; [.3D47.0020.0002] -A120 ; [.3D48.0020.0002] -A121 ; [.3D49.0020.0002] -A122 ; [.3D4A.0020.0002] -A123 ; [.3D4B.0020.0002] -A124 ; [.3D4C.0020.0002] -A125 ; [.3D4D.0020.0002] -A126 ; [.3D4E.0020.0002] -A127 ; [.3D4F.0020.0002] -A128 ; [.3D50.0020.0002] -A129 ; [.3D51.0020.0002] -A12A ; [.3D52.0020.0002] -A12B ; [.3D53.0020.0002] -A12C ; [.3D54.0020.0002] -A12D ; [.3D55.0020.0002] -A12E ; [.3D56.0020.0002] -A12F ; [.3D57.0020.0002] -A130 ; [.3D58.0020.0002] -A131 ; [.3D59.0020.0002] -A132 ; [.3D5A.0020.0002] -A133 ; [.3D5B.0020.0002] -A134 ; [.3D5C.0020.0002] -A135 ; [.3D5D.0020.0002] -A136 ; [.3D5E.0020.0002] -A137 ; [.3D5F.0020.0002] -A138 ; [.3D60.0020.0002] -A139 ; [.3D61.0020.0002] -A13A ; [.3D62.0020.0002] -A13B ; [.3D63.0020.0002] -A13C ; [.3D64.0020.0002] -A13D ; [.3D65.0020.0002] -A13E ; [.3D66.0020.0002] -A13F ; [.3D67.0020.0002] -A140 ; [.3D68.0020.0002] -A141 ; [.3D69.0020.0002] -A142 ; [.3D6A.0020.0002] -A143 ; [.3D6B.0020.0002] -A144 ; [.3D6C.0020.0002] -A145 ; [.3D6D.0020.0002] -A146 ; [.3D6E.0020.0002] -A147 ; [.3D6F.0020.0002] -A148 ; [.3D70.0020.0002] -A149 ; [.3D71.0020.0002] -A14A ; [.3D72.0020.0002] -A14B ; [.3D73.0020.0002] -A14C ; [.3D74.0020.0002] -A14D ; [.3D75.0020.0002] -A14E ; [.3D76.0020.0002] -A14F ; [.3D77.0020.0002] -A150 ; [.3D78.0020.0002] -A151 ; [.3D79.0020.0002] -A152 ; [.3D7A.0020.0002] -A153 ; [.3D7B.0020.0002] -A154 ; [.3D7C.0020.0002] -A155 ; [.3D7D.0020.0002] -A156 ; [.3D7E.0020.0002] -A157 ; [.3D7F.0020.0002] -A158 ; [.3D80.0020.0002] -A159 ; [.3D81.0020.0002] -A15A ; [.3D82.0020.0002] -A15B ; [.3D83.0020.0002] -A15C ; [.3D84.0020.0002] -A15D ; [.3D85.0020.0002] -A15E ; [.3D86.0020.0002] -A15F ; [.3D87.0020.0002] -A160 ; [.3D88.0020.0002] -A161 ; [.3D89.0020.0002] -A162 ; [.3D8A.0020.0002] -A163 ; [.3D8B.0020.0002] -A164 ; [.3D8C.0020.0002] -A165 ; [.3D8D.0020.0002] -A166 ; [.3D8E.0020.0002] -A167 ; [.3D8F.0020.0002] -A168 ; [.3D90.0020.0002] -A169 ; [.3D91.0020.0002] -A16A ; [.3D92.0020.0002] -A16B ; [.3D93.0020.0002] -A16C ; [.3D94.0020.0002] -A16D ; [.3D95.0020.0002] -A16E ; [.3D96.0020.0002] -A16F ; [.3D97.0020.0002] -A170 ; [.3D98.0020.0002] -A171 ; [.3D99.0020.0002] -A172 ; [.3D9A.0020.0002] -A173 ; [.3D9B.0020.0002] -A174 ; [.3D9C.0020.0002] -A175 ; [.3D9D.0020.0002] -A176 ; [.3D9E.0020.0002] -A177 ; [.3D9F.0020.0002] -A178 ; [.3DA0.0020.0002] -A179 ; [.3DA1.0020.0002] -A17A ; [.3DA2.0020.0002] -A17B ; [.3DA3.0020.0002] -A17C ; [.3DA4.0020.0002] -A17D ; [.3DA5.0020.0002] -A17E ; [.3DA6.0020.0002] -A17F ; [.3DA7.0020.0002] -A180 ; [.3DA8.0020.0002] -A181 ; [.3DA9.0020.0002] -A182 ; [.3DAA.0020.0002] -A183 ; [.3DAB.0020.0002] -A184 ; [.3DAC.0020.0002] -A185 ; [.3DAD.0020.0002] -A186 ; [.3DAE.0020.0002] -A187 ; [.3DAF.0020.0002] -A188 ; [.3DB0.0020.0002] -A189 ; [.3DB1.0020.0002] -A18A ; [.3DB2.0020.0002] -A18B ; [.3DB3.0020.0002] -A18C ; [.3DB4.0020.0002] -A18D ; [.3DB5.0020.0002] -A18E ; [.3DB6.0020.0002] -A18F ; [.3DB7.0020.0002] -A190 ; [.3DB8.0020.0002] -A191 ; [.3DB9.0020.0002] -A192 ; [.3DBA.0020.0002] -A193 ; [.3DBB.0020.0002] -A194 ; [.3DBC.0020.0002] -A195 ; [.3DBD.0020.0002] -A196 ; [.3DBE.0020.0002] -A197 ; [.3DBF.0020.0002] -A198 ; [.3DC0.0020.0002] -A199 ; [.3DC1.0020.0002] -A19A ; [.3DC2.0020.0002] -A19B ; [.3DC3.0020.0002] -A19C ; [.3DC4.0020.0002] -A19D ; [.3DC5.0020.0002] -A19E ; [.3DC6.0020.0002] -A19F ; [.3DC7.0020.0002] -A1A0 ; [.3DC8.0020.0002] -A1A1 ; [.3DC9.0020.0002] -A1A2 ; [.3DCA.0020.0002] -A1A3 ; [.3DCB.0020.0002] -A1A4 ; [.3DCC.0020.0002] -A1A5 ; [.3DCD.0020.0002] -A1A6 ; [.3DCE.0020.0002] -A1A7 ; [.3DCF.0020.0002] -A1A8 ; [.3DD0.0020.0002] -A1A9 ; [.3DD1.0020.0002] -A1AA ; [.3DD2.0020.0002] -A1AB ; [.3DD3.0020.0002] -A1AC ; [.3DD4.0020.0002] -A1AD ; [.3DD5.0020.0002] -A1AE ; [.3DD6.0020.0002] -A1AF ; [.3DD7.0020.0002] -A1B0 ; [.3DD8.0020.0002] -A1B1 ; [.3DD9.0020.0002] -A1B2 ; [.3DDA.0020.0002] -A1B3 ; [.3DDB.0020.0002] -A1B4 ; [.3DDC.0020.0002] -A1B5 ; [.3DDD.0020.0002] -A1B6 ; [.3DDE.0020.0002] -A1B7 ; [.3DDF.0020.0002] -A1B8 ; [.3DE0.0020.0002] -A1B9 ; [.3DE1.0020.0002] -A1BA ; [.3DE2.0020.0002] -A1BB ; [.3DE3.0020.0002] -A1BC ; [.3DE4.0020.0002] -A1BD ; [.3DE5.0020.0002] -A1BE ; [.3DE6.0020.0002] -A1BF ; [.3DE7.0020.0002] -A1C0 ; [.3DE8.0020.0002] -A1C1 ; [.3DE9.0020.0002] -A1C2 ; [.3DEA.0020.0002] -A1C3 ; [.3DEB.0020.0002] -A1C4 ; [.3DEC.0020.0002] -A1C5 ; [.3DED.0020.0002] -A1C6 ; [.3DEE.0020.0002] -A1C7 ; [.3DEF.0020.0002] -A1C8 ; [.3DF0.0020.0002] -A1C9 ; [.3DF1.0020.0002] -A1CA ; [.3DF2.0020.0002] -A1CB ; [.3DF3.0020.0002] -A1CC ; [.3DF4.0020.0002] -A1CD ; [.3DF5.0020.0002] -A1CE ; [.3DF6.0020.0002] -A1CF ; [.3DF7.0020.0002] -A1D0 ; [.3DF8.0020.0002] -A1D1 ; [.3DF9.0020.0002] -A1D2 ; [.3DFA.0020.0002] -A1D3 ; [.3DFB.0020.0002] -A1D4 ; [.3DFC.0020.0002] -A1D5 ; [.3DFD.0020.0002] -A1D6 ; [.3DFE.0020.0002] -A1D7 ; [.3DFF.0020.0002] -A1D8 ; [.3E00.0020.0002] -A1D9 ; [.3E01.0020.0002] -A1DA ; [.3E02.0020.0002] -A1DB ; [.3E03.0020.0002] -A1DC ; [.3E04.0020.0002] -A1DD ; [.3E05.0020.0002] -A1DE ; [.3E06.0020.0002] -A1DF ; [.3E07.0020.0002] -A1E0 ; [.3E08.0020.0002] -A1E1 ; [.3E09.0020.0002] -A1E2 ; [.3E0A.0020.0002] -A1E3 ; [.3E0B.0020.0002] -A1E4 ; [.3E0C.0020.0002] -A1E5 ; [.3E0D.0020.0002] -A1E6 ; [.3E0E.0020.0002] -A1E7 ; [.3E0F.0020.0002] -A1E8 ; [.3E10.0020.0002] -A1E9 ; [.3E11.0020.0002] -A1EA ; [.3E12.0020.0002] -A1EB ; [.3E13.0020.0002] -A1EC ; [.3E14.0020.0002] -A1ED ; [.3E15.0020.0002] -A1EE ; [.3E16.0020.0002] -A1EF ; [.3E17.0020.0002] -A1F0 ; [.3E18.0020.0002] -A1F1 ; [.3E19.0020.0002] -A1F2 ; [.3E1A.0020.0002] -A1F3 ; [.3E1B.0020.0002] -A1F4 ; [.3E1C.0020.0002] -A1F5 ; [.3E1D.0020.0002] -A1F6 ; [.3E1E.0020.0002] -A1F7 ; [.3E1F.0020.0002] -A1F8 ; [.3E20.0020.0002] -A1F9 ; [.3E21.0020.0002] -A1FA ; [.3E22.0020.0002] -A1FB ; [.3E23.0020.0002] -A1FC ; [.3E24.0020.0002] -A1FD ; [.3E25.0020.0002] -A1FE ; [.3E26.0020.0002] -A1FF ; [.3E27.0020.0002] -A200 ; [.3E28.0020.0002] -A201 ; [.3E29.0020.0002] -A202 ; [.3E2A.0020.0002] -A203 ; [.3E2B.0020.0002] -A204 ; [.3E2C.0020.0002] -A205 ; [.3E2D.0020.0002] -A206 ; [.3E2E.0020.0002] -A207 ; [.3E2F.0020.0002] -A208 ; [.3E30.0020.0002] -A209 ; [.3E31.0020.0002] -A20A ; [.3E32.0020.0002] -A20B ; [.3E33.0020.0002] -A20C ; [.3E34.0020.0002] -A20D ; [.3E35.0020.0002] -A20E ; [.3E36.0020.0002] -A20F ; [.3E37.0020.0002] -A210 ; [.3E38.0020.0002] -A211 ; [.3E39.0020.0002] -A212 ; [.3E3A.0020.0002] -A213 ; [.3E3B.0020.0002] -A214 ; [.3E3C.0020.0002] -A215 ; [.3E3D.0020.0002] -A216 ; [.3E3E.0020.0002] -A217 ; [.3E3F.0020.0002] -A218 ; [.3E40.0020.0002] -A219 ; [.3E41.0020.0002] -A21A ; [.3E42.0020.0002] -A21B ; [.3E43.0020.0002] -A21C ; [.3E44.0020.0002] -A21D ; [.3E45.0020.0002] -A21E ; [.3E46.0020.0002] -A21F ; [.3E47.0020.0002] -A220 ; [.3E48.0020.0002] -A221 ; [.3E49.0020.0002] -A222 ; [.3E4A.0020.0002] -A223 ; [.3E4B.0020.0002] -A224 ; [.3E4C.0020.0002] -A225 ; [.3E4D.0020.0002] -A226 ; [.3E4E.0020.0002] -A227 ; [.3E4F.0020.0002] -A228 ; [.3E50.0020.0002] -A229 ; [.3E51.0020.0002] -A22A ; [.3E52.0020.0002] -A22B ; [.3E53.0020.0002] -A22C ; [.3E54.0020.0002] -A22D ; [.3E55.0020.0002] -A22E ; [.3E56.0020.0002] -A22F ; [.3E57.0020.0002] -A230 ; [.3E58.0020.0002] -A231 ; [.3E59.0020.0002] -A232 ; [.3E5A.0020.0002] -A233 ; [.3E5B.0020.0002] -A234 ; [.3E5C.0020.0002] -A235 ; [.3E5D.0020.0002] -A236 ; [.3E5E.0020.0002] -A237 ; [.3E5F.0020.0002] -A238 ; [.3E60.0020.0002] -A239 ; [.3E61.0020.0002] -A23A ; [.3E62.0020.0002] -A23B ; [.3E63.0020.0002] -A23C ; [.3E64.0020.0002] -A23D ; [.3E65.0020.0002] -A23E ; [.3E66.0020.0002] -A23F ; [.3E67.0020.0002] -A240 ; [.3E68.0020.0002] -A241 ; [.3E69.0020.0002] -A242 ; [.3E6A.0020.0002] -A243 ; [.3E6B.0020.0002] -A244 ; [.3E6C.0020.0002] -A245 ; [.3E6D.0020.0002] -A246 ; [.3E6E.0020.0002] -A247 ; [.3E6F.0020.0002] -A248 ; [.3E70.0020.0002] -A249 ; [.3E71.0020.0002] -A24A ; [.3E72.0020.0002] -A24B ; [.3E73.0020.0002] -A24C ; [.3E74.0020.0002] -A24D ; [.3E75.0020.0002] -A24E ; [.3E76.0020.0002] -A24F ; [.3E77.0020.0002] -A250 ; [.3E78.0020.0002] -A251 ; [.3E79.0020.0002] -A252 ; [.3E7A.0020.0002] -A253 ; [.3E7B.0020.0002] -A254 ; [.3E7C.0020.0002] -A255 ; [.3E7D.0020.0002] -A256 ; [.3E7E.0020.0002] -A257 ; [.3E7F.0020.0002] -A258 ; [.3E80.0020.0002] -A259 ; [.3E81.0020.0002] -A25A ; [.3E82.0020.0002] -A25B ; [.3E83.0020.0002] -A25C ; [.3E84.0020.0002] -A25D ; [.3E85.0020.0002] -A25E ; [.3E86.0020.0002] -A25F ; [.3E87.0020.0002] -A260 ; [.3E88.0020.0002] -A261 ; [.3E89.0020.0002] -A262 ; [.3E8A.0020.0002] -A263 ; [.3E8B.0020.0002] -A264 ; [.3E8C.0020.0002] -A265 ; [.3E8D.0020.0002] -A266 ; [.3E8E.0020.0002] -A267 ; [.3E8F.0020.0002] -A268 ; [.3E90.0020.0002] -A269 ; [.3E91.0020.0002] -A26A ; [.3E92.0020.0002] -A26B ; [.3E93.0020.0002] -A26C ; [.3E94.0020.0002] -A26D ; [.3E95.0020.0002] -A26E ; [.3E96.0020.0002] -A26F ; [.3E97.0020.0002] -A270 ; [.3E98.0020.0002] -A271 ; [.3E99.0020.0002] -A272 ; [.3E9A.0020.0002] -A273 ; [.3E9B.0020.0002] -A274 ; [.3E9C.0020.0002] -A275 ; [.3E9D.0020.0002] -A276 ; [.3E9E.0020.0002] -A277 ; [.3E9F.0020.0002] -A278 ; [.3EA0.0020.0002] -A279 ; [.3EA1.0020.0002] -A27A ; [.3EA2.0020.0002] -A27B ; [.3EA3.0020.0002] -A27C ; [.3EA4.0020.0002] -A27D ; [.3EA5.0020.0002] -A27E ; [.3EA6.0020.0002] -A27F ; [.3EA7.0020.0002] -A280 ; [.3EA8.0020.0002] -A281 ; [.3EA9.0020.0002] -A282 ; [.3EAA.0020.0002] -A283 ; [.3EAB.0020.0002] -A284 ; [.3EAC.0020.0002] -A285 ; [.3EAD.0020.0002] -A286 ; [.3EAE.0020.0002] -A287 ; [.3EAF.0020.0002] -A288 ; [.3EB0.0020.0002] -A289 ; [.3EB1.0020.0002] -A28A ; [.3EB2.0020.0002] -A28B ; [.3EB3.0020.0002] -A28C ; [.3EB4.0020.0002] -A28D ; [.3EB5.0020.0002] -A28E ; [.3EB6.0020.0002] -A28F ; [.3EB7.0020.0002] -A290 ; [.3EB8.0020.0002] -A291 ; [.3EB9.0020.0002] -A292 ; [.3EBA.0020.0002] -A293 ; [.3EBB.0020.0002] -A294 ; [.3EBC.0020.0002] -A295 ; [.3EBD.0020.0002] -A296 ; [.3EBE.0020.0002] -A297 ; [.3EBF.0020.0002] -A298 ; [.3EC0.0020.0002] -A299 ; [.3EC1.0020.0002] -A29A ; [.3EC2.0020.0002] -A29B ; [.3EC3.0020.0002] -A29C ; [.3EC4.0020.0002] -A29D ; [.3EC5.0020.0002] -A29E ; [.3EC6.0020.0002] -A29F ; [.3EC7.0020.0002] -A2A0 ; [.3EC8.0020.0002] -A2A1 ; [.3EC9.0020.0002] -A2A2 ; [.3ECA.0020.0002] -A2A3 ; [.3ECB.0020.0002] -A2A4 ; [.3ECC.0020.0002] -A2A5 ; [.3ECD.0020.0002] -A2A6 ; [.3ECE.0020.0002] -A2A7 ; [.3ECF.0020.0002] -A2A8 ; [.3ED0.0020.0002] -A2A9 ; [.3ED1.0020.0002] -A2AA ; [.3ED2.0020.0002] -A2AB ; [.3ED3.0020.0002] -A2AC ; [.3ED4.0020.0002] -A2AD ; [.3ED5.0020.0002] -A2AE ; [.3ED6.0020.0002] -A2AF ; [.3ED7.0020.0002] -A2B0 ; [.3ED8.0020.0002] -A2B1 ; [.3ED9.0020.0002] -A2B2 ; [.3EDA.0020.0002] -A2B3 ; [.3EDB.0020.0002] -A2B4 ; [.3EDC.0020.0002] -A2B5 ; [.3EDD.0020.0002] -A2B6 ; [.3EDE.0020.0002] -A2B7 ; [.3EDF.0020.0002] -A2B8 ; [.3EE0.0020.0002] -A2B9 ; [.3EE1.0020.0002] -A2BA ; [.3EE2.0020.0002] -A2BB ; [.3EE3.0020.0002] -A2BC ; [.3EE4.0020.0002] -A2BD ; [.3EE5.0020.0002] -A2BE ; [.3EE6.0020.0002] -A2BF ; [.3EE7.0020.0002] -A2C0 ; [.3EE8.0020.0002] -A2C1 ; [.3EE9.0020.0002] -A2C2 ; [.3EEA.0020.0002] -A2C3 ; [.3EEB.0020.0002] -A2C4 ; [.3EEC.0020.0002] -A2C5 ; [.3EED.0020.0002] -A2C6 ; [.3EEE.0020.0002] -A2C7 ; [.3EEF.0020.0002] -A2C8 ; [.3EF0.0020.0002] -A2C9 ; [.3EF1.0020.0002] -A2CA ; [.3EF2.0020.0002] -A2CB ; [.3EF3.0020.0002] -A2CC ; [.3EF4.0020.0002] -A2CD ; [.3EF5.0020.0002] -A2CE ; [.3EF6.0020.0002] -A2CF ; [.3EF7.0020.0002] -A2D0 ; [.3EF8.0020.0002] -A2D1 ; [.3EF9.0020.0002] -A2D2 ; [.3EFA.0020.0002] -A2D3 ; [.3EFB.0020.0002] -A2D4 ; [.3EFC.0020.0002] -A2D5 ; [.3EFD.0020.0002] -A2D6 ; [.3EFE.0020.0002] -A2D7 ; [.3EFF.0020.0002] -A2D8 ; [.3F00.0020.0002] -A2D9 ; [.3F01.0020.0002] -A2DA ; [.3F02.0020.0002] -A2DB ; [.3F03.0020.0002] -A2DC ; [.3F04.0020.0002] -A2DD ; [.3F05.0020.0002] -A2DE ; [.3F06.0020.0002] -A2DF ; [.3F07.0020.0002] -A2E0 ; [.3F08.0020.0002] -A2E1 ; [.3F09.0020.0002] -A2E2 ; [.3F0A.0020.0002] -A2E3 ; [.3F0B.0020.0002] -A2E4 ; [.3F0C.0020.0002] -A2E5 ; [.3F0D.0020.0002] -A2E6 ; [.3F0E.0020.0002] -A2E7 ; [.3F0F.0020.0002] -A2E8 ; [.3F10.0020.0002] -A2E9 ; [.3F11.0020.0002] -A2EA ; [.3F12.0020.0002] -A2EB ; [.3F13.0020.0002] -A2EC ; [.3F14.0020.0002] -A2ED ; [.3F15.0020.0002] -A2EE ; [.3F16.0020.0002] -A2EF ; [.3F17.0020.0002] -A2F0 ; [.3F18.0020.0002] -A2F1 ; [.3F19.0020.0002] -A2F2 ; [.3F1A.0020.0002] -A2F3 ; [.3F1B.0020.0002] -A2F4 ; [.3F1C.0020.0002] -A2F5 ; [.3F1D.0020.0002] -A2F6 ; [.3F1E.0020.0002] -A2F7 ; [.3F1F.0020.0002] -A2F8 ; [.3F20.0020.0002] -A2F9 ; [.3F21.0020.0002] -A2FA ; [.3F22.0020.0002] -A2FB ; [.3F23.0020.0002] -A2FC ; [.3F24.0020.0002] -A2FD ; [.3F25.0020.0002] -A2FE ; [.3F26.0020.0002] -A2FF ; [.3F27.0020.0002] -A300 ; [.3F28.0020.0002] -A301 ; [.3F29.0020.0002] -A302 ; [.3F2A.0020.0002] -A303 ; [.3F2B.0020.0002] -A304 ; [.3F2C.0020.0002] -A305 ; [.3F2D.0020.0002] -A306 ; [.3F2E.0020.0002] -A307 ; [.3F2F.0020.0002] -A308 ; [.3F30.0020.0002] -A309 ; [.3F31.0020.0002] -A30A ; [.3F32.0020.0002] -A30B ; [.3F33.0020.0002] -A30C ; [.3F34.0020.0002] -A30D ; [.3F35.0020.0002] -A30E ; [.3F36.0020.0002] -A30F ; [.3F37.0020.0002] -A310 ; [.3F38.0020.0002] -A311 ; [.3F39.0020.0002] -A312 ; [.3F3A.0020.0002] -A313 ; [.3F3B.0020.0002] -A314 ; [.3F3C.0020.0002] -A315 ; [.3F3D.0020.0002] -A316 ; [.3F3E.0020.0002] -A317 ; [.3F3F.0020.0002] -A318 ; [.3F40.0020.0002] -A319 ; [.3F41.0020.0002] -A31A ; [.3F42.0020.0002] -A31B ; [.3F43.0020.0002] -A31C ; [.3F44.0020.0002] -A31D ; [.3F45.0020.0002] -A31E ; [.3F46.0020.0002] -A31F ; [.3F47.0020.0002] -A320 ; [.3F48.0020.0002] -A321 ; [.3F49.0020.0002] -A322 ; [.3F4A.0020.0002] -A323 ; [.3F4B.0020.0002] -A324 ; [.3F4C.0020.0002] -A325 ; [.3F4D.0020.0002] -A326 ; [.3F4E.0020.0002] -A327 ; [.3F4F.0020.0002] -A328 ; [.3F50.0020.0002] -A329 ; [.3F51.0020.0002] -A32A ; [.3F52.0020.0002] -A32B ; [.3F53.0020.0002] -A32C ; [.3F54.0020.0002] -A32D ; [.3F55.0020.0002] -A32E ; [.3F56.0020.0002] -A32F ; [.3F57.0020.0002] -A330 ; [.3F58.0020.0002] -A331 ; [.3F59.0020.0002] -A332 ; [.3F5A.0020.0002] -A333 ; [.3F5B.0020.0002] -A334 ; [.3F5C.0020.0002] -A335 ; [.3F5D.0020.0002] -A336 ; [.3F5E.0020.0002] -A337 ; [.3F5F.0020.0002] -A338 ; [.3F60.0020.0002] -A339 ; [.3F61.0020.0002] -A33A ; [.3F62.0020.0002] -A33B ; [.3F63.0020.0002] -A33C ; [.3F64.0020.0002] -A33D ; [.3F65.0020.0002] -A33E ; [.3F66.0020.0002] -A33F ; [.3F67.0020.0002] -A340 ; [.3F68.0020.0002] -A341 ; [.3F69.0020.0002] -A342 ; [.3F6A.0020.0002] -A343 ; [.3F6B.0020.0002] -A344 ; [.3F6C.0020.0002] -A345 ; [.3F6D.0020.0002] -A346 ; [.3F6E.0020.0002] -A347 ; [.3F6F.0020.0002] -A348 ; [.3F70.0020.0002] -A349 ; [.3F71.0020.0002] -A34A ; [.3F72.0020.0002] -A34B ; [.3F73.0020.0002] -A34C ; [.3F74.0020.0002] -A34D ; [.3F75.0020.0002] -A34E ; [.3F76.0020.0002] -A34F ; [.3F77.0020.0002] -A350 ; [.3F78.0020.0002] -A351 ; [.3F79.0020.0002] -A352 ; [.3F7A.0020.0002] -A353 ; [.3F7B.0020.0002] -A354 ; [.3F7C.0020.0002] -A355 ; [.3F7D.0020.0002] -A356 ; [.3F7E.0020.0002] -A357 ; [.3F7F.0020.0002] -A358 ; [.3F80.0020.0002] -A359 ; [.3F81.0020.0002] -A35A ; [.3F82.0020.0002] -A35B ; [.3F83.0020.0002] -A35C ; [.3F84.0020.0002] -A35D ; [.3F85.0020.0002] -A35E ; [.3F86.0020.0002] -A35F ; [.3F87.0020.0002] -A360 ; [.3F88.0020.0002] -A361 ; [.3F89.0020.0002] -A362 ; [.3F8A.0020.0002] -A363 ; [.3F8B.0020.0002] -A364 ; [.3F8C.0020.0002] -A365 ; [.3F8D.0020.0002] -A366 ; [.3F8E.0020.0002] -A367 ; [.3F8F.0020.0002] -A368 ; [.3F90.0020.0002] -A369 ; [.3F91.0020.0002] -A36A ; [.3F92.0020.0002] -A36B ; [.3F93.0020.0002] -A36C ; [.3F94.0020.0002] -A36D ; [.3F95.0020.0002] -A36E ; [.3F96.0020.0002] -A36F ; [.3F97.0020.0002] -A370 ; [.3F98.0020.0002] -A371 ; [.3F99.0020.0002] -A372 ; [.3F9A.0020.0002] -A373 ; [.3F9B.0020.0002] -A374 ; [.3F9C.0020.0002] -A375 ; [.3F9D.0020.0002] -A376 ; [.3F9E.0020.0002] -A377 ; [.3F9F.0020.0002] -A378 ; [.3FA0.0020.0002] -A379 ; [.3FA1.0020.0002] -A37A ; [.3FA2.0020.0002] -A37B ; [.3FA3.0020.0002] -A37C ; [.3FA4.0020.0002] -A37D ; [.3FA5.0020.0002] -A37E ; [.3FA6.0020.0002] -A37F ; [.3FA7.0020.0002] -A380 ; [.3FA8.0020.0002] -A381 ; [.3FA9.0020.0002] -A382 ; [.3FAA.0020.0002] -A383 ; [.3FAB.0020.0002] -A384 ; [.3FAC.0020.0002] -A385 ; [.3FAD.0020.0002] -A386 ; [.3FAE.0020.0002] -A387 ; [.3FAF.0020.0002] -A388 ; [.3FB0.0020.0002] -A389 ; [.3FB1.0020.0002] -A38A ; [.3FB2.0020.0002] -A38B ; [.3FB3.0020.0002] -A38C ; [.3FB4.0020.0002] -A38D ; [.3FB5.0020.0002] -A38E ; [.3FB6.0020.0002] -A38F ; [.3FB7.0020.0002] -A390 ; [.3FB8.0020.0002] -A391 ; [.3FB9.0020.0002] -A392 ; [.3FBA.0020.0002] -A393 ; [.3FBB.0020.0002] -A394 ; [.3FBC.0020.0002] -A395 ; [.3FBD.0020.0002] -A396 ; [.3FBE.0020.0002] -A397 ; [.3FBF.0020.0002] -A398 ; [.3FC0.0020.0002] -A399 ; [.3FC1.0020.0002] -A39A ; [.3FC2.0020.0002] -A39B ; [.3FC3.0020.0002] -A39C ; [.3FC4.0020.0002] -A39D ; [.3FC5.0020.0002] -A39E ; [.3FC6.0020.0002] -A39F ; [.3FC7.0020.0002] -A3A0 ; [.3FC8.0020.0002] -A3A1 ; [.3FC9.0020.0002] -A3A2 ; [.3FCA.0020.0002] -A3A3 ; [.3FCB.0020.0002] -A3A4 ; [.3FCC.0020.0002] -A3A5 ; [.3FCD.0020.0002] -A3A6 ; [.3FCE.0020.0002] -A3A7 ; [.3FCF.0020.0002] -A3A8 ; [.3FD0.0020.0002] -A3A9 ; [.3FD1.0020.0002] -A3AA ; [.3FD2.0020.0002] -A3AB ; [.3FD3.0020.0002] -A3AC ; [.3FD4.0020.0002] -A3AD ; [.3FD5.0020.0002] -A3AE ; [.3FD6.0020.0002] -A3AF ; [.3FD7.0020.0002] -A3B0 ; [.3FD8.0020.0002] -A3B1 ; [.3FD9.0020.0002] -A3B2 ; [.3FDA.0020.0002] -A3B3 ; [.3FDB.0020.0002] -A3B4 ; [.3FDC.0020.0002] -A3B5 ; [.3FDD.0020.0002] -A3B6 ; [.3FDE.0020.0002] -A3B7 ; [.3FDF.0020.0002] -A3B8 ; [.3FE0.0020.0002] -A3B9 ; [.3FE1.0020.0002] -A3BA ; [.3FE2.0020.0002] -A3BB ; [.3FE3.0020.0002] -A3BC ; [.3FE4.0020.0002] -A3BD ; [.3FE5.0020.0002] -A3BE ; [.3FE6.0020.0002] -A3BF ; [.3FE7.0020.0002] -A3C0 ; [.3FE8.0020.0002] -A3C1 ; [.3FE9.0020.0002] -A3C2 ; [.3FEA.0020.0002] -A3C3 ; [.3FEB.0020.0002] -A3C4 ; [.3FEC.0020.0002] -A3C5 ; [.3FED.0020.0002] -A3C6 ; [.3FEE.0020.0002] -A3C7 ; [.3FEF.0020.0002] -A3C8 ; [.3FF0.0020.0002] -A3C9 ; [.3FF1.0020.0002] -A3CA ; [.3FF2.0020.0002] -A3CB ; [.3FF3.0020.0002] -A3CC ; [.3FF4.0020.0002] -A3CD ; [.3FF5.0020.0002] -A3CE ; [.3FF6.0020.0002] -A3CF ; [.3FF7.0020.0002] -A3D0 ; [.3FF8.0020.0002] -A3D1 ; [.3FF9.0020.0002] -A3D2 ; [.3FFA.0020.0002] -A3D3 ; [.3FFB.0020.0002] -A3D4 ; [.3FFC.0020.0002] -A3D5 ; [.3FFD.0020.0002] -A3D6 ; [.3FFE.0020.0002] -A3D7 ; [.3FFF.0020.0002] -A3D8 ; [.4000.0020.0002] -A3D9 ; [.4001.0020.0002] -A3DA ; [.4002.0020.0002] -A3DB ; [.4003.0020.0002] -A3DC ; [.4004.0020.0002] -A3DD ; [.4005.0020.0002] -A3DE ; [.4006.0020.0002] -A3DF ; [.4007.0020.0002] -A3E0 ; [.4008.0020.0002] -A3E1 ; [.4009.0020.0002] -A3E2 ; [.400A.0020.0002] -A3E3 ; [.400B.0020.0002] -A3E4 ; [.400C.0020.0002] -A3E5 ; [.400D.0020.0002] -A3E6 ; [.400E.0020.0002] -A3E7 ; [.400F.0020.0002] -A3E8 ; [.4010.0020.0002] -A3E9 ; [.4011.0020.0002] -A3EA ; [.4012.0020.0002] -A3EB ; [.4013.0020.0002] -A3EC ; [.4014.0020.0002] -A3ED ; [.4015.0020.0002] -A3EE ; [.4016.0020.0002] -A3EF ; [.4017.0020.0002] -A3F0 ; [.4018.0020.0002] -A3F1 ; [.4019.0020.0002] -A3F2 ; [.401A.0020.0002] -A3F3 ; [.401B.0020.0002] -A3F4 ; [.401C.0020.0002] -A3F5 ; [.401D.0020.0002] -A3F6 ; [.401E.0020.0002] -A3F7 ; [.401F.0020.0002] -A3F8 ; [.4020.0020.0002] -A3F9 ; [.4021.0020.0002] -A3FA ; [.4022.0020.0002] -A3FB ; [.4023.0020.0002] -A3FC ; [.4024.0020.0002] -A3FD ; [.4025.0020.0002] -A3FE ; [.4026.0020.0002] -A3FF ; [.4027.0020.0002] -A400 ; [.4028.0020.0002] -A401 ; [.4029.0020.0002] -A402 ; [.402A.0020.0002] -A403 ; [.402B.0020.0002] -A404 ; [.402C.0020.0002] -A405 ; [.402D.0020.0002] -A406 ; [.402E.0020.0002] -A407 ; [.402F.0020.0002] -A408 ; [.4030.0020.0002] -A409 ; [.4031.0020.0002] -A40A ; [.4032.0020.0002] -A40B ; [.4033.0020.0002] -A40C ; [.4034.0020.0002] -A40D ; [.4035.0020.0002] -A40E ; [.4036.0020.0002] -A40F ; [.4037.0020.0002] -A410 ; [.4038.0020.0002] -A411 ; [.4039.0020.0002] -A412 ; [.403A.0020.0002] -A413 ; [.403B.0020.0002] -A414 ; [.403C.0020.0002] -A415 ; [.403D.0020.0002] -A416 ; [.403E.0020.0002] -A417 ; [.403F.0020.0002] -A418 ; [.4040.0020.0002] -A419 ; [.4041.0020.0002] -A41A ; [.4042.0020.0002] -A41B ; [.4043.0020.0002] -A41C ; [.4044.0020.0002] -A41D ; [.4045.0020.0002] -A41E ; [.4046.0020.0002] -A41F ; [.4047.0020.0002] -A420 ; [.4048.0020.0002] -A421 ; [.4049.0020.0002] -A422 ; [.404A.0020.0002] -A423 ; [.404B.0020.0002] -A424 ; [.404C.0020.0002] -A425 ; [.404D.0020.0002] -A426 ; [.404E.0020.0002] -A427 ; [.404F.0020.0002] -A428 ; [.4050.0020.0002] -A429 ; [.4051.0020.0002] -A42A ; [.4052.0020.0002] -A42B ; [.4053.0020.0002] -A42C ; [.4054.0020.0002] -A42D ; [.4055.0020.0002] -A42E ; [.4056.0020.0002] -A42F ; [.4057.0020.0002] -A430 ; [.4058.0020.0002] -A431 ; [.4059.0020.0002] -A432 ; [.405A.0020.0002] -A433 ; [.405B.0020.0002] -A434 ; [.405C.0020.0002] -A435 ; [.405D.0020.0002] -A436 ; [.405E.0020.0002] -A437 ; [.405F.0020.0002] -A438 ; [.4060.0020.0002] -A439 ; [.4061.0020.0002] -A43A ; [.4062.0020.0002] -A43B ; [.4063.0020.0002] -A43C ; [.4064.0020.0002] -A43D ; [.4065.0020.0002] -A43E ; [.4066.0020.0002] -A43F ; [.4067.0020.0002] -A440 ; [.4068.0020.0002] -A441 ; [.4069.0020.0002] -A442 ; [.406A.0020.0002] -A443 ; [.406B.0020.0002] -A444 ; [.406C.0020.0002] -A445 ; [.406D.0020.0002] -A446 ; [.406E.0020.0002] -A447 ; [.406F.0020.0002] -A448 ; [.4070.0020.0002] -A449 ; [.4071.0020.0002] -A44A ; [.4072.0020.0002] -A44B ; [.4073.0020.0002] -A44C ; [.4074.0020.0002] -A44D ; [.4075.0020.0002] -A44E ; [.4076.0020.0002] -A44F ; [.4077.0020.0002] -A450 ; [.4078.0020.0002] -A451 ; [.4079.0020.0002] -A452 ; [.407A.0020.0002] -A453 ; [.407B.0020.0002] -A454 ; [.407C.0020.0002] -A455 ; [.407D.0020.0002] -A456 ; [.407E.0020.0002] -A457 ; [.407F.0020.0002] -A458 ; [.4080.0020.0002] -A459 ; [.4081.0020.0002] -A45A ; [.4082.0020.0002] -A45B ; [.4083.0020.0002] -A45C ; [.4084.0020.0002] -A45D ; [.4085.0020.0002] -A45E ; [.4086.0020.0002] -A45F ; [.4087.0020.0002] -A460 ; [.4088.0020.0002] -A461 ; [.4089.0020.0002] -A462 ; [.408A.0020.0002] -A463 ; [.408B.0020.0002] -A464 ; [.408C.0020.0002] -A465 ; [.408D.0020.0002] -A466 ; [.408E.0020.0002] -A467 ; [.408F.0020.0002] -A468 ; [.4090.0020.0002] -A469 ; [.4091.0020.0002] -A46A ; [.4092.0020.0002] -A46B ; [.4093.0020.0002] -A46C ; [.4094.0020.0002] -A46D ; [.4095.0020.0002] -A46E ; [.4096.0020.0002] -A46F ; [.4097.0020.0002] -A470 ; [.4098.0020.0002] -A471 ; [.4099.0020.0002] -A472 ; [.409A.0020.0002] -A473 ; [.409B.0020.0002] -A474 ; [.409C.0020.0002] -A475 ; [.409D.0020.0002] -A476 ; [.409E.0020.0002] -A477 ; [.409F.0020.0002] -A478 ; [.40A0.0020.0002] -A479 ; [.40A1.0020.0002] -A47A ; [.40A2.0020.0002] -A47B ; [.40A3.0020.0002] -A47C ; [.40A4.0020.0002] -A47D ; [.40A5.0020.0002] -A47E ; [.40A6.0020.0002] -A47F ; [.40A7.0020.0002] -A480 ; [.40A8.0020.0002] -A481 ; [.40A9.0020.0002] -A482 ; [.40AA.0020.0002] -A483 ; [.40AB.0020.0002] -A484 ; [.40AC.0020.0002] -A485 ; [.40AD.0020.0002] -A486 ; [.40AE.0020.0002] -A487 ; [.40AF.0020.0002] -A488 ; [.40B0.0020.0002] -A489 ; [.40B1.0020.0002] -A48A ; [.40B2.0020.0002] -A48B ; [.40B3.0020.0002] -A48C ; [.40B4.0020.0002] -A4F8 ; [.40B5.0020.0002] -A4F9 ; [.40B6.0020.0002] -A4FA ; [.40B7.0020.0002] -A4FB ; [.40B8.0020.0002] -A4FD ; [.40B9.0020.0002] -A4FC ; [.40BA.0020.0002] -A4D0 ; [.40BB.0020.0002] -A4D1 ; [.40BC.0020.0002] -A4D2 ; [.40BD.0020.0002] -A4D3 ; [.40BE.0020.0002] -A4D4 ; [.40BF.0020.0002] -A4D5 ; [.40C0.0020.0002] -A4D6 ; [.40C1.0020.0002] -A4D7 ; [.40C2.0020.0002] -A4D8 ; [.40C3.0020.0002] -A4D9 ; [.40C4.0020.0002] -A4DA ; [.40C5.0020.0002] -A4DB ; [.40C6.0020.0002] -A4DC ; [.40C7.0020.0002] -A4DD ; [.40C8.0020.0002] -A4DE ; [.40C9.0020.0002] -A4DF ; [.40CA.0020.0002] -A4E0 ; [.40CB.0020.0002] -A4E1 ; [.40CC.0020.0002] -A4E2 ; [.40CD.0020.0002] -A4E3 ; [.40CE.0020.0002] -A4E4 ; [.40CF.0020.0002] -A4E5 ; [.40D0.0020.0002] -A4E6 ; [.40D1.0020.0002] -A4E7 ; [.40D2.0020.0002] -A4E8 ; [.40D3.0020.0002] -A4E9 ; [.40D4.0020.0002] -A4EB ; [.40D5.0020.0002] -A4ED ; [.40D6.0020.0002] -A4EA ; [.40D7.0020.0002] -A4EC ; [.40D8.0020.0002] -A4EE ; [.40D9.0020.0002] -A4EF ; [.40DA.0020.0002] -A4F0 ; [.40DB.0020.0002] -A4F1 ; [.40DC.0020.0002] -A4F2 ; [.40DD.0020.0002] -A4F3 ; [.40DE.0020.0002] -A4F4 ; [.40DF.0020.0002] -A4F5 ; [.40E0.0020.0002] -A4F6 ; [.40E1.0020.0002] -A4F7 ; [.40E2.0020.0002] -16F00 ; [.40E3.0020.0002] -16F01 ; [.40E4.0020.0002] -16F02 ; [.40E5.0020.0002] -16F03 ; [.40E6.0020.0002] -16F04 ; [.40E7.0020.0002] -16F06 ; [.40E7.0020.0004] -16F05 ; [.40E8.0020.0002] -16F07 ; [.40E9.0020.0002] -16F08 ; [.40EA.0020.0002] -16F09 ; [.40EB.0020.0002] -16F0A ; [.40EC.0020.0002] -16F0B ; [.40ED.0020.0002] -16F0C ; [.40EE.0020.0002] -16F0D ; [.40EF.0020.0002] -16F0E ; [.40F0.0020.0002] -16F0F ; [.40F1.0020.0002] -16F10 ; [.40F2.0020.0002] -16F13 ; [.40F2.0020.0004] -16F11 ; [.40F3.0020.0002] -16F12 ; [.40F4.0020.0002] -16F14 ; [.40F5.0020.0002] -16F15 ; [.40F6.0020.0002] -16F16 ; [.40F7.0020.0002] -16F17 ; [.40F8.0020.0002] -16F18 ; [.40F9.0020.0002] -16F19 ; [.40FA.0020.0002] -16F1A ; [.40FB.0020.0002] -16F1B ; [.40FC.0020.0002] -16F1C ; [.40FD.0020.0002] -16F1D ; [.40FE.0020.0002] -16F1E ; [.40FF.0020.0002] -16F1F ; [.4100.0020.0002] -16F20 ; [.4101.0020.0002] -16F21 ; [.4102.0020.0002] -16F22 ; [.4103.0020.0002] -16F23 ; [.4104.0020.0002] -16F25 ; [.4104.0020.0004] -16F24 ; [.4105.0020.0002] -16F26 ; [.4106.0020.0002] -16F27 ; [.4107.0020.0002] -16F28 ; [.4108.0020.0002] -16F29 ; [.4109.0020.0002] -16F2A ; [.410A.0020.0002] -16F2B ; [.410B.0020.0002] -16F2C ; [.410C.0020.0002] -16F2D ; [.410D.0020.0002] -16F2E ; [.410E.0020.0002] -16F2F ; [.410F.0020.0002] -16F30 ; [.4110.0020.0002] -16F31 ; [.4111.0020.0002] -16F32 ; [.4112.0020.0002] -16F33 ; [.4113.0020.0002] -16F34 ; [.4114.0020.0002] -16F35 ; [.4115.0020.0002] -16F36 ; [.4116.0020.0002] -16F37 ; [.4117.0020.0002] -16F38 ; [.4118.0020.0002] -16F39 ; [.4119.0020.0002] -16F3A ; [.411A.0020.0002] -16F3B ; [.411B.0020.0002] -16F3C ; [.411C.0020.0002] -16F3D ; [.411D.0020.0002] -16F3F ; [.411D.0020.0004] -16F3E ; [.411E.0020.0002] -16F40 ; [.411F.0020.0002] -16F41 ; [.4120.0020.0002] -16F42 ; [.4121.0020.0002] -16F43 ; [.4122.0020.0002] -16F44 ; [.4123.0020.0002] -16F50 ; [.4124.0020.0002] -16F51 ; [.4125.0020.0002] -16F52 ; [.4126.0020.0002] -16F53 ; [.4127.0020.0002] -16F54 ; [.4128.0020.0002] -16F55 ; [.4129.0020.0002] -16F56 ; [.412A.0020.0002] -16F57 ; [.412B.0020.0002] -16F58 ; [.412C.0020.0002] -16F59 ; [.412D.0020.0002] -16F5A ; [.412E.0020.0002] -16F5B ; [.412F.0020.0002] -16F5C ; [.4130.0020.0002] -16F5D ; [.4131.0020.0002] -16F5E ; [.4132.0020.0002] -16F5F ; [.4133.0020.0002] -16F60 ; [.4134.0020.0002] -16F61 ; [.4135.0020.0002] -16F62 ; [.4136.0020.0002] -16F63 ; [.4137.0020.0002] -16F64 ; [.4138.0020.0002] -16F65 ; [.4139.0020.0002] -16F66 ; [.413A.0020.0002] -16F67 ; [.413B.0020.0002] -16F68 ; [.413C.0020.0002] -16F69 ; [.413D.0020.0002] -16F6A ; [.413E.0020.0002] -16F6B ; [.413F.0020.0002] -16F6C ; [.4140.0020.0002] -16F6D ; [.4141.0020.0002] -16F6E ; [.4142.0020.0002] -16F6F ; [.4143.0020.0002] -16F70 ; [.4144.0020.0002] -16F71 ; [.4145.0020.0002] -16F72 ; [.4146.0020.0002] -16F73 ; [.4147.0020.0002] -16F74 ; [.4148.0020.0002] -16F75 ; [.4149.0020.0002] -16F76 ; [.414A.0020.0002] -16F77 ; [.414B.0020.0002] -16F78 ; [.414C.0020.0002] -16F79 ; [.414D.0020.0002] -16F7A ; [.414E.0020.0002] -16F7B ; [.414F.0020.0002] -16F7C ; [.4150.0020.0002] -16F7D ; [.4151.0020.0002] -16F7E ; [.4152.0020.0002] -16F8F ; [.4153.0020.0002] -16F90 ; [.4154.0020.0002] -16F91 ; [.4155.0020.0002] -16F92 ; [.4156.0020.0002] -16F93 ; [.4157.0020.0002] -16F94 ; [.4158.0020.0002] -16F95 ; [.4159.0020.0002] -16F96 ; [.415A.0020.0002] -16F97 ; [.415B.0020.0002] -16F98 ; [.415C.0020.0002] -16F99 ; [.415D.0020.0002] -16F9A ; [.415E.0020.0002] -16F9B ; [.415F.0020.0002] -16F9C ; [.4160.0020.0002] -16F9D ; [.4161.0020.0002] -16F9E ; [.4162.0020.0002] -16F9F ; [.4163.0020.0002] -118FF ; [.4164.0020.0002] -118C0 ; [.4165.0020.0002] -118A0 ; [.4165.0020.0008] -118C1 ; [.4166.0020.0002] -118A1 ; [.4166.0020.0008] -118C2 ; [.4167.0020.0002] -118A2 ; [.4167.0020.0008] -118C3 ; [.4168.0020.0002] -118A3 ; [.4168.0020.0008] -118C4 ; [.4169.0020.0002] -118A4 ; [.4169.0020.0008] -118C5 ; [.416A.0020.0002] -118A5 ; [.416A.0020.0008] -118C6 ; [.416B.0020.0002] -118A6 ; [.416B.0020.0008] -118C7 ; [.416C.0020.0002] -118A7 ; [.416C.0020.0008] -118C8 ; [.416D.0020.0002] -118A8 ; [.416D.0020.0008] -118C9 ; [.416E.0020.0002] -118A9 ; [.416E.0020.0008] -118CA ; [.416F.0020.0002] -118AA ; [.416F.0020.0008] -118CB ; [.4170.0020.0002] -118AB ; [.4170.0020.0008] -118CC ; [.4171.0020.0002] -118AC ; [.4171.0020.0008] -118CD ; [.4172.0020.0002] -118AD ; [.4172.0020.0008] -118CE ; [.4173.0020.0002] -118AE ; [.4173.0020.0008] -118CF ; [.4174.0020.0002] -118AF ; [.4174.0020.0008] -118D0 ; [.4175.0020.0002] -118B0 ; [.4175.0020.0008] -118D1 ; [.4176.0020.0002] -118B1 ; [.4176.0020.0008] -118D2 ; [.4177.0020.0002] -118B2 ; [.4177.0020.0008] -118D3 ; [.4178.0020.0002] -118B3 ; [.4178.0020.0008] -118D4 ; [.4179.0020.0002] -118B4 ; [.4179.0020.0008] -118D5 ; [.417A.0020.0002] -118B5 ; [.417A.0020.0008] -118D6 ; [.417B.0020.0002] -118B6 ; [.417B.0020.0008] -118D7 ; [.417C.0020.0002] -118B7 ; [.417C.0020.0008] -118D8 ; [.417D.0020.0002] -118B8 ; [.417D.0020.0008] -118D9 ; [.417E.0020.0002] -118B9 ; [.417E.0020.0008] -118DA ; [.417F.0020.0002] -118BA ; [.417F.0020.0008] -118DB ; [.4180.0020.0002] -118BB ; [.4180.0020.0008] -118DC ; [.4181.0020.0002] -118BC ; [.4181.0020.0008] -118DD ; [.4182.0020.0002] -118BD ; [.4182.0020.0008] -118DE ; [.4183.0020.0002] -118BE ; [.4183.0020.0008] -118DF ; [.4184.0020.0002] -118BF ; [.4184.0020.0008] -11AD5 ; [.4185.0020.0002] -11AD6 ; [.4186.0020.0002] -11AD7 ; [.4187.0020.0002] -11AD8 ; [.4188.0020.0002] -11AD9 ; [.4189.0020.0002] -11ADA ; [.418A.0020.0002] -11ADB ; [.418B.0020.0002] -11AC0 ; [.418C.0020.0002] -11AC1 ; [.418D.0020.0002] -11AC2 ; [.418E.0020.0002] -11AC3 ; [.418F.0020.0002] -11AC4 ; [.4190.0020.0002] -11AC5 ; [.4191.0020.0002] -11AC6 ; [.4192.0020.0002] -11AC7 ; [.4193.0020.0002] -11AC8 ; [.4194.0020.0002] -11AC9 ; [.4195.0020.0002] -11ACA ; [.4196.0020.0002] -11ACB ; [.4197.0020.0002] -11ACC ; [.4198.0020.0002] -11ACD ; [.4199.0020.0002] -11ACE ; [.419A.0020.0002] -11ACF ; [.419B.0020.0002] -11AD0 ; [.419C.0020.0002] -11AD1 ; [.419D.0020.0002] -11AD2 ; [.419E.0020.0002] -11AD3 ; [.419F.0020.0002] -11AD4 ; [.41A0.0020.0002] -11ADC ; [.41A1.0020.0002] -11ADD ; [.41A2.0020.0002] -11ADF ; [.41A3.0020.0002] -11AE0 ; [.41A4.0020.0002] -11AE1 ; [.41A5.0020.0002] -11AE2 ; [.41A6.0020.0002] -11AE3 ; [.41A7.0020.0002] -11ADE ; [.41A8.0020.0002] -11AE4 ; [.41A9.0020.0002] -11AEF ; [.41AA.0020.0002] -11AF2 ; [.41AB.0020.0002] -11AF1 ; [.41AC.0020.0002] -11AE6 ; [.41AD.0020.0002] -11AE9 ; [.41AE.0020.0002] -11AE5 ; [.41AF.0020.0002] -11AE8 ; [.41B0.0020.0002] -11AF4 ; [.41B1.0020.0002] -11AF7 ; [.41B2.0020.0002] -11AF3 ; [.41B3.0020.0002] -11AF6 ; [.41B4.0020.0002] -11AEC ; [.41B5.0020.0002] -11AEE ; [.41B6.0020.0002] -11AEB ; [.41B7.0020.0002] -11AED ; [.41B8.0020.0002] -11AF5 ; [.41B9.0020.0002] -11AF8 ; [.41BA.0020.0002] -11AE7 ; [.41BB.0020.0002] -11AEA ; [.41BC.0020.0002] -11AF0 ; [.41BD.0020.0002] -16B00 ; [.41BE.0020.0002] -16B01 ; [.41BF.0020.0002] -16B02 ; [.41C0.0020.0002] -16B03 ; [.41C1.0020.0002] -16B04 ; [.41C2.0020.0002] -16B05 ; [.41C3.0020.0002] -16B06 ; [.41C4.0020.0002] -16B07 ; [.41C5.0020.0002] -16B08 ; [.41C6.0020.0002] -16B09 ; [.41C7.0020.0002] -16B0A ; [.41C8.0020.0002] -16B0B ; [.41C9.0020.0002] -16B0C ; [.41CA.0020.0002] -16B0D ; [.41CB.0020.0002] -16B0E ; [.41CC.0020.0002] -16B0F ; [.41CD.0020.0002] -16B10 ; [.41CE.0020.0002] -16B11 ; [.41CF.0020.0002] -16B12 ; [.41D0.0020.0002] -16B13 ; [.41D1.0020.0002] -16B14 ; [.41D2.0020.0002] -16B15 ; [.41D3.0020.0002] -16B16 ; [.41D4.0020.0002] -16B17 ; [.41D5.0020.0002] -16B18 ; [.41D6.0020.0002] -16B19 ; [.41D7.0020.0002] -16B1A ; [.41D8.0020.0002] -16B1B ; [.41D9.0020.0002] -16B1C ; [.41DA.0020.0002] -16B1D ; [.41DB.0020.0002] -16B1E ; [.41DC.0020.0002] -16B1F ; [.41DD.0020.0002] -16B20 ; [.41DE.0020.0002] -16B21 ; [.41DF.0020.0002] -16B22 ; [.41E0.0020.0002] -16B23 ; [.41E1.0020.0002] -16B24 ; [.41E2.0020.0002] -16B25 ; [.41E3.0020.0002] -16B26 ; [.41E4.0020.0002] -16B27 ; [.41E5.0020.0002] -16B28 ; [.41E6.0020.0002] -16B29 ; [.41E7.0020.0002] -16B2A ; [.41E8.0020.0002] -16B2B ; [.41E9.0020.0002] -16B2C ; [.41EA.0020.0002] -16B2D ; [.41EB.0020.0002] -16B2E ; [.41EC.0020.0002] -16B2F ; [.41ED.0020.0002] -16B40 ; [.41EE.0020.0002] -16B41 ; [.41EF.0020.0002] -16B63 ; [.41F0.0020.0002] -16B64 ; [.41F1.0020.0002] -16B65 ; [.41F2.0020.0002] -16B66 ; [.41F3.0020.0002] -16B67 ; [.41F4.0020.0002] -16B68 ; [.41F5.0020.0002] -16B69 ; [.41F6.0020.0002] -16B6A ; [.41F7.0020.0002] -16B6B ; [.41F8.0020.0002] -16B6C ; [.41F9.0020.0002] -16B6D ; [.41FA.0020.0002] -16B6E ; [.41FB.0020.0002] -16B6F ; [.41FC.0020.0002] -16B70 ; [.41FD.0020.0002] -16B71 ; [.41FE.0020.0002] -16B72 ; [.41FF.0020.0002] -16B73 ; [.4200.0020.0002] -16B74 ; [.4201.0020.0002] -16B75 ; [.4202.0020.0002] -16B76 ; [.4203.0020.0002] -16B77 ; [.4204.0020.0002] -16B7D ; [.4205.0020.0002] -16B7E ; [.4206.0020.0002] -16B7F ; [.4207.0020.0002] -16B80 ; [.4208.0020.0002] -16B81 ; [.4209.0020.0002] -16B82 ; [.420A.0020.0002] -16B83 ; [.420B.0020.0002] -16B84 ; [.420C.0020.0002] -16B85 ; [.420D.0020.0002] -16B86 ; [.420E.0020.0002] -16B87 ; [.420F.0020.0002] -16B88 ; [.4210.0020.0002] -16B89 ; [.4211.0020.0002] -16B8A ; [.4212.0020.0002] -16B8B ; [.4213.0020.0002] -16B8C ; [.4214.0020.0002] -16B8D ; [.4215.0020.0002] -16B8E ; [.4216.0020.0002] -16B8F ; [.4217.0020.0002] -10280 ; [.4218.0020.0002] -10281 ; [.4219.0020.0002] -10282 ; [.421A.0020.0002] -10283 ; [.421B.0020.0002] -10284 ; [.421C.0020.0002] -10285 ; [.421D.0020.0002] -10286 ; [.421E.0020.0002] -10287 ; [.421F.0020.0002] -10288 ; [.4220.0020.0002] -10289 ; [.4221.0020.0002] -1028A ; [.4222.0020.0002] -1028B ; [.4223.0020.0002] -1028C ; [.4224.0020.0002] -1028D ; [.4225.0020.0002] -1028E ; [.4226.0020.0002] -1028F ; [.4227.0020.0002] -10290 ; [.4228.0020.0002] -10291 ; [.4229.0020.0002] -10292 ; [.422A.0020.0002] -10293 ; [.422B.0020.0002] -10294 ; [.422C.0020.0002] -10295 ; [.422D.0020.0002] -10296 ; [.422E.0020.0002] -10297 ; [.422F.0020.0002] -10298 ; [.4230.0020.0002] -10299 ; [.4231.0020.0002] -1029A ; [.4232.0020.0002] -1029B ; [.4233.0020.0002] -1029C ; [.4234.0020.0002] -102A0 ; [.4235.0020.0002] -102A1 ; [.4236.0020.0002] -102A2 ; [.4237.0020.0002] -102A3 ; [.4238.0020.0002] -102A4 ; [.4239.0020.0002] -102A5 ; [.423A.0020.0002] -102A6 ; [.423B.0020.0002] -102A7 ; [.423C.0020.0002] -102A8 ; [.423D.0020.0002] -102A9 ; [.423E.0020.0002] -102AA ; [.423F.0020.0002] -102AB ; [.4240.0020.0002] -102AC ; [.4241.0020.0002] -102AD ; [.4242.0020.0002] -102AE ; [.4243.0020.0002] -102AF ; [.4244.0020.0002] -102B0 ; [.4245.0020.0002] -102B1 ; [.4246.0020.0002] -102B2 ; [.4247.0020.0002] -102B3 ; [.4248.0020.0002] -102B4 ; [.4249.0020.0002] -102B5 ; [.424A.0020.0002] -102B6 ; [.424B.0020.0002] -102B7 ; [.424C.0020.0002] -102B8 ; [.424D.0020.0002] -102B9 ; [.424E.0020.0002] -102BA ; [.424F.0020.0002] -102BB ; [.4250.0020.0002] -102BC ; [.4251.0020.0002] -102BD ; [.4252.0020.0002] -102BE ; [.4253.0020.0002] -102BF ; [.4254.0020.0002] -102C0 ; [.4255.0020.0002] -102C1 ; [.4256.0020.0002] -102C2 ; [.4257.0020.0002] -102C3 ; [.4258.0020.0002] -102C4 ; [.4259.0020.0002] -102C5 ; [.425A.0020.0002] -102C6 ; [.425B.0020.0002] -102C7 ; [.425C.0020.0002] -102C8 ; [.425D.0020.0002] -102C9 ; [.425E.0020.0002] -102CA ; [.425F.0020.0002] -102CB ; [.4260.0020.0002] -102CC ; [.4261.0020.0002] -102CD ; [.4262.0020.0002] -102CE ; [.4263.0020.0002] -102CF ; [.4264.0020.0002] -102D0 ; [.4265.0020.0002] -10920 ; [.4266.0020.0002] -10921 ; [.4267.0020.0002] -10922 ; [.4268.0020.0002] -10923 ; [.4269.0020.0002] -10924 ; [.426A.0020.0002] -10925 ; [.426B.0020.0002] -10926 ; [.426C.0020.0002] -10927 ; [.426D.0020.0002] -10928 ; [.426E.0020.0002] -10929 ; [.426F.0020.0002] -1092A ; [.4270.0020.0002] -1092B ; [.4271.0020.0002] -1092C ; [.4272.0020.0002] -1092D ; [.4273.0020.0002] -1092E ; [.4274.0020.0002] -1092F ; [.4275.0020.0002] -10930 ; [.4276.0020.0002] -10931 ; [.4277.0020.0002] -10932 ; [.4278.0020.0002] -10933 ; [.4279.0020.0002] -10934 ; [.427A.0020.0002] -10935 ; [.427B.0020.0002] -10936 ; [.427C.0020.0002] -10937 ; [.427D.0020.0002] -10938 ; [.427E.0020.0002] -10939 ; [.427F.0020.0002] -10300 ; [.4280.0020.0002] -10301 ; [.4281.0020.0002] -10302 ; [.4282.0020.0002] -10303 ; [.4283.0020.0002] -10304 ; [.4284.0020.0002] -10305 ; [.4285.0020.0002] -10306 ; [.4286.0020.0002] -10307 ; [.4287.0020.0002] -10308 ; [.4288.0020.0002] -10309 ; [.4289.0020.0002] -1030A ; [.428A.0020.0002] -1030B ; [.428B.0020.0002] -1030C ; [.428C.0020.0002] -1030D ; [.428D.0020.0002] -1030E ; [.428E.0020.0002] -1031F ; [.428F.0020.0002] -1030F ; [.4290.0020.0002] -10310 ; [.4291.0020.0002] -10311 ; [.4292.0020.0002] -10312 ; [.4293.0020.0002] -10313 ; [.4294.0020.0002] -10314 ; [.4295.0020.0002] -10315 ; [.4296.0020.0002] -10316 ; [.4297.0020.0002] -10317 ; [.4298.0020.0002] -10318 ; [.4299.0020.0002] -10319 ; [.429A.0020.0002] -1031A ; [.429B.0020.0002] -1031B ; [.429C.0020.0002] -1031C ; [.429D.0020.0002] -1031D ; [.429E.0020.0002] -1031E ; [.429F.0020.0002] -10330 ; [.42A0.0020.0002] -10331 ; [.42A1.0020.0002] -10332 ; [.42A2.0020.0002] -10333 ; [.42A3.0020.0002] -10334 ; [.42A4.0020.0002] -10335 ; [.42A5.0020.0002] -10336 ; [.42A6.0020.0002] -10337 ; [.42A7.0020.0002] -10338 ; [.42A8.0020.0002] -10339 ; [.42A9.0020.0002] -1033A ; [.42AA.0020.0002] -1033B ; [.42AB.0020.0002] -1033C ; [.42AC.0020.0002] -1033D ; [.42AD.0020.0002] -1033E ; [.42AE.0020.0002] -1033F ; [.42AF.0020.0002] -10340 ; [.42B0.0020.0002] -10341 ; [.42B1.0020.0002] -10342 ; [.42B2.0020.0002] -10343 ; [.42B3.0020.0002] -10344 ; [.42B4.0020.0002] -10345 ; [.42B5.0020.0002] -10346 ; [.42B6.0020.0002] -10347 ; [.42B7.0020.0002] -10348 ; [.42B8.0020.0002] -10349 ; [.42B9.0020.0002] -1034A ; [.42BA.0020.0002] -10428 ; [.42BB.0020.0002] -10400 ; [.42BB.0020.0008] -10429 ; [.42BC.0020.0002] -10401 ; [.42BC.0020.0008] -1042A ; [.42BD.0020.0002] -10402 ; [.42BD.0020.0008] -1042B ; [.42BE.0020.0002] -10403 ; [.42BE.0020.0008] -1042C ; [.42BF.0020.0002] -10404 ; [.42BF.0020.0008] -1042D ; [.42C0.0020.0002] -10405 ; [.42C0.0020.0008] -1042E ; [.42C1.0020.0002] -10406 ; [.42C1.0020.0008] -1042F ; [.42C2.0020.0002] -10407 ; [.42C2.0020.0008] -10430 ; [.42C3.0020.0002] -10408 ; [.42C3.0020.0008] -10431 ; [.42C4.0020.0002] -10409 ; [.42C4.0020.0008] -10432 ; [.42C5.0020.0002] -1040A ; [.42C5.0020.0008] -10433 ; [.42C6.0020.0002] -1040B ; [.42C6.0020.0008] -10434 ; [.42C7.0020.0002] -1040C ; [.42C7.0020.0008] -10435 ; [.42C8.0020.0002] -1040D ; [.42C8.0020.0008] -10436 ; [.42C9.0020.0002] -1040E ; [.42C9.0020.0008] -10437 ; [.42CA.0020.0002] -1040F ; [.42CA.0020.0008] -10438 ; [.42CB.0020.0002] -10410 ; [.42CB.0020.0008] -10439 ; [.42CC.0020.0002] -10411 ; [.42CC.0020.0008] -1043A ; [.42CD.0020.0002] -10412 ; [.42CD.0020.0008] -1043B ; [.42CE.0020.0002] -10413 ; [.42CE.0020.0008] -1043C ; [.42CF.0020.0002] -10414 ; [.42CF.0020.0008] -1043D ; [.42D0.0020.0002] -10415 ; [.42D0.0020.0008] -1043E ; [.42D1.0020.0002] -10416 ; [.42D1.0020.0008] -1043F ; [.42D2.0020.0002] -10417 ; [.42D2.0020.0008] -10440 ; [.42D3.0020.0002] -10418 ; [.42D3.0020.0008] -10441 ; [.42D4.0020.0002] -10419 ; [.42D4.0020.0008] -10442 ; [.42D5.0020.0002] -1041A ; [.42D5.0020.0008] -10443 ; [.42D6.0020.0002] -1041B ; [.42D6.0020.0008] -10444 ; [.42D7.0020.0002] -1041C ; [.42D7.0020.0008] -10445 ; [.42D8.0020.0002] -1041D ; [.42D8.0020.0008] -10446 ; [.42D9.0020.0002] -1041E ; [.42D9.0020.0008] -10447 ; [.42DA.0020.0002] -1041F ; [.42DA.0020.0008] -10448 ; [.42DB.0020.0002] -10420 ; [.42DB.0020.0008] -10449 ; [.42DC.0020.0002] -10421 ; [.42DC.0020.0008] -1044A ; [.42DD.0020.0002] -10422 ; [.42DD.0020.0008] -1044B ; [.42DE.0020.0002] -10423 ; [.42DE.0020.0008] -1044C ; [.42DF.0020.0002] -10424 ; [.42DF.0020.0008] -1044D ; [.42E0.0020.0002] -10425 ; [.42E0.0020.0008] -1044E ; [.42E1.0020.0002] -10426 ; [.42E1.0020.0008] -1044F ; [.42E2.0020.0002] -10427 ; [.42E2.0020.0008] -10450 ; [.42E3.0020.0002] -10451 ; [.42E4.0020.0002] -10452 ; [.42E5.0020.0002] -10453 ; [.42E6.0020.0002] -10454 ; [.42E7.0020.0002] -10455 ; [.42E8.0020.0002] -10456 ; [.42E9.0020.0002] -10457 ; [.42EA.0020.0002] -10458 ; [.42EB.0020.0002] -10459 ; [.42EC.0020.0002] -1045A ; [.42ED.0020.0002] -1045B ; [.42EE.0020.0002] -1045C ; [.42EF.0020.0002] -1045D ; [.42F0.0020.0002] -1045E ; [.42F1.0020.0002] -1045F ; [.42F2.0020.0002] -10460 ; [.42F3.0020.0002] -10461 ; [.42F4.0020.0002] -10462 ; [.42F5.0020.0002] -10463 ; [.42F6.0020.0002] -10464 ; [.42F7.0020.0002] -10465 ; [.42F8.0020.0002] -10466 ; [.42F9.0020.0002] -10467 ; [.42FA.0020.0002] -10468 ; [.42FB.0020.0002] -10469 ; [.42FC.0020.0002] -1046A ; [.42FD.0020.0002] -1046B ; [.42FE.0020.0002] -1046C ; [.42FF.0020.0002] -1046D ; [.4300.0020.0002] -1046E ; [.4301.0020.0002] -1046F ; [.4302.0020.0002] -10470 ; [.4303.0020.0002] -10471 ; [.4304.0020.0002] -10472 ; [.4305.0020.0002] -10473 ; [.4306.0020.0002] -10474 ; [.4307.0020.0002] -10475 ; [.4308.0020.0002] -10476 ; [.4309.0020.0002] -10477 ; [.430A.0020.0002] -10478 ; [.430B.0020.0002] -10479 ; [.430C.0020.0002] -1047A ; [.430D.0020.0002] -1047B ; [.430E.0020.0002] -1047C ; [.430F.0020.0002] -1047D ; [.4310.0020.0002] -1047E ; [.4311.0020.0002] -1047F ; [.4312.0020.0002] -1BC00 ; [.4313.0020.0002] -1BC01 ; [.4314.0020.0002] -1BC02 ; [.4315.0020.0002] -1BC03 ; [.4316.0020.0002] -1BC04 ; [.4317.0020.0002] -1BC05 ; [.4318.0020.0002] -1BC06 ; [.4319.0020.0002] -1BC07 ; [.431A.0020.0002] -1BC08 ; [.431B.0020.0002] -1BC09 ; [.431C.0020.0002] -1BC0A ; [.431D.0020.0002] -1BC0B ; [.431E.0020.0002] -1BC0C ; [.431F.0020.0002] -1BC0D ; [.4320.0020.0002] -1BC0E ; [.4321.0020.0002] -1BC0F ; [.4322.0020.0002] -1BC10 ; [.4323.0020.0002] -1BC11 ; [.4324.0020.0002] -1BC12 ; [.4325.0020.0002] -1BC13 ; [.4326.0020.0002] -1BC14 ; [.4327.0020.0002] -1BC15 ; [.4328.0020.0002] -1BC16 ; [.4329.0020.0002] -1BC17 ; [.432A.0020.0002] -1BC18 ; [.432B.0020.0002] -1BC19 ; [.432C.0020.0002] -1BC1A ; [.432D.0020.0002] -1BC1B ; [.432E.0020.0002] -1BC1C ; [.432F.0020.0002] -1BC1D ; [.4330.0020.0002] -1BC1E ; [.4331.0020.0002] -1BC1F ; [.4332.0020.0002] -1BC20 ; [.4333.0020.0002] -1BC21 ; [.4334.0020.0002] -1BC22 ; [.4335.0020.0002] -1BC23 ; [.4336.0020.0002] -1BC24 ; [.4337.0020.0002] -1BC25 ; [.4338.0020.0002] -1BC26 ; [.4339.0020.0002] -1BC27 ; [.433A.0020.0002] -1BC28 ; [.433B.0020.0002] -1BC29 ; [.433C.0020.0002] -1BC2A ; [.433D.0020.0002] -1BC2B ; [.433E.0020.0002] -1BC2C ; [.433F.0020.0002] -1BC2D ; [.4340.0020.0002] -1BC2E ; [.4341.0020.0002] -1BC2F ; [.4342.0020.0002] -1BC30 ; [.4343.0020.0002] -1BC31 ; [.4344.0020.0002] -1BC32 ; [.4345.0020.0002] -1BC33 ; [.4346.0020.0002] -1BC34 ; [.4347.0020.0002] -1BC35 ; [.4348.0020.0002] -1BC36 ; [.4349.0020.0002] -1BC37 ; [.434A.0020.0002] -1BC38 ; [.434B.0020.0002] -1BC39 ; [.434C.0020.0002] -1BC3A ; [.434D.0020.0002] -1BC3B ; [.434E.0020.0002] -1BC3C ; [.434F.0020.0002] -1BC3D ; [.4350.0020.0002] -1BC3E ; [.4351.0020.0002] -1BC3F ; [.4352.0020.0002] -1BC40 ; [.4353.0020.0002] -1BC41 ; [.4354.0020.0002] -1BC42 ; [.4355.0020.0002] -1BC43 ; [.4356.0020.0002] -1BC44 ; [.4357.0020.0002] -1BC45 ; [.4358.0020.0002] -1BC46 ; [.4359.0020.0002] -1BC47 ; [.435A.0020.0002] -1BC48 ; [.435B.0020.0002] -1BC49 ; [.435C.0020.0002] -1BC4A ; [.435D.0020.0002] -1BC4B ; [.435E.0020.0002] -1BC4C ; [.435F.0020.0002] -1BC4D ; [.4360.0020.0002] -1BC4E ; [.4361.0020.0002] -1BC4F ; [.4362.0020.0002] -1BC50 ; [.4363.0020.0002] -1BC51 ; [.4364.0020.0002] -1BC52 ; [.4365.0020.0002] -1BC53 ; [.4366.0020.0002] -1BC54 ; [.4367.0020.0002] -1BC55 ; [.4368.0020.0002] -1BC56 ; [.4369.0020.0002] -1BC57 ; [.436A.0020.0002] -1BC58 ; [.436B.0020.0002] -1BC59 ; [.436C.0020.0002] -1BC5A ; [.436D.0020.0002] -1BC5B ; [.436E.0020.0002] -1BC5C ; [.436F.0020.0002] -1BC5D ; [.4370.0020.0002] -1BC5E ; [.4371.0020.0002] -1BC5F ; [.4372.0020.0002] -1BC60 ; [.4373.0020.0002] -1BC61 ; [.4374.0020.0002] -1BC62 ; [.4375.0020.0002] -1BC63 ; [.4376.0020.0002] -1BC64 ; [.4377.0020.0002] -1BC65 ; [.4378.0020.0002] -1BC66 ; [.4379.0020.0002] -1BC67 ; [.437A.0020.0002] -1BC68 ; [.437B.0020.0002] -1BC69 ; [.437C.0020.0002] -1BC6A ; [.437D.0020.0002] -1BC70 ; [.437E.0020.0002] -1BC71 ; [.437F.0020.0002] -1BC72 ; [.4380.0020.0002] -1BC73 ; [.4381.0020.0002] -1BC74 ; [.4382.0020.0002] -1BC75 ; [.4383.0020.0002] -1BC76 ; [.4384.0020.0002] -1BC77 ; [.4385.0020.0002] -1BC78 ; [.4386.0020.0002] -1BC79 ; [.4387.0020.0002] -1BC7A ; [.4388.0020.0002] -1BC7B ; [.4389.0020.0002] -1BC7C ; [.438A.0020.0002] -1BC80 ; [.438B.0020.0002] -1BC81 ; [.438C.0020.0002] -1BC82 ; [.438D.0020.0002] -1BC83 ; [.438E.0020.0002] -1BC84 ; [.438F.0020.0002] -1BC85 ; [.4390.0020.0002] -1BC86 ; [.4391.0020.0002] -1BC87 ; [.4392.0020.0002] -1BC88 ; [.4393.0020.0002] -1BC90 ; [.4394.0020.0002] -1BC91 ; [.4395.0020.0002] -1BC92 ; [.4396.0020.0002] -1BC93 ; [.4397.0020.0002] -1BC94 ; [.4398.0020.0002] -1BC95 ; [.4399.0020.0002] -1BC96 ; [.439A.0020.0002] -1BC97 ; [.439B.0020.0002] -1BC98 ; [.439C.0020.0002] -1BC99 ; [.439D.0020.0002] -10480 ; [.439E.0020.0002] -10481 ; [.439F.0020.0002] -10482 ; [.43A0.0020.0002] -10483 ; [.43A1.0020.0002] -10484 ; [.43A2.0020.0002] -10485 ; [.43A3.0020.0002] -10486 ; [.43A4.0020.0002] -10487 ; [.43A5.0020.0002] -10488 ; [.43A6.0020.0002] -10489 ; [.43A7.0020.0002] -1048A ; [.43A8.0020.0002] -1048B ; [.43A9.0020.0002] -1048C ; [.43AA.0020.0002] -1048D ; [.43AB.0020.0002] -1048E ; [.43AC.0020.0002] -1048F ; [.43AD.0020.0002] -10490 ; [.43AE.0020.0002] -10491 ; [.43AF.0020.0002] -10492 ; [.43B0.0020.0002] -10493 ; [.43B1.0020.0002] -10494 ; [.43B2.0020.0002] -10495 ; [.43B3.0020.0002] -10496 ; [.43B4.0020.0002] -10497 ; [.43B5.0020.0002] -10498 ; [.43B6.0020.0002] -10499 ; [.43B7.0020.0002] -1049A ; [.43B8.0020.0002] -1049B ; [.43B9.0020.0002] -1049C ; [.43BA.0020.0002] -1049D ; [.43BB.0020.0002] -10500 ; [.43BC.0020.0002] -10501 ; [.43BD.0020.0002] -10502 ; [.43BE.0020.0002] -10503 ; [.43BF.0020.0002] -10504 ; [.43C0.0020.0002] -10505 ; [.43C1.0020.0002] -10506 ; [.43C2.0020.0002] -10507 ; [.43C3.0020.0002] -10508 ; [.43C4.0020.0002] -10509 ; [.43C5.0020.0002] -1050A ; [.43C6.0020.0002] -1050B ; [.43C7.0020.0002] -1050C ; [.43C8.0020.0002] -1050D ; [.43C9.0020.0002] -1050E ; [.43CA.0020.0002] -1050F ; [.43CB.0020.0002] -10510 ; [.43CC.0020.0002] -10511 ; [.43CD.0020.0002] -10512 ; [.43CE.0020.0002] -10513 ; [.43CF.0020.0002] -10514 ; [.43D0.0020.0002] -10515 ; [.43D1.0020.0002] -10516 ; [.43D2.0020.0002] -10517 ; [.43D3.0020.0002] -10518 ; [.43D4.0020.0002] -10519 ; [.43D5.0020.0002] -1051A ; [.43D6.0020.0002] -1051B ; [.43D7.0020.0002] -1051C ; [.43D8.0020.0002] -1051D ; [.43D9.0020.0002] -1051E ; [.43DA.0020.0002] -1051F ; [.43DB.0020.0002] -10520 ; [.43DC.0020.0002] -10521 ; [.43DD.0020.0002] -10522 ; [.43DE.0020.0002] -10523 ; [.43DF.0020.0002] -10524 ; [.43E0.0020.0002] -10525 ; [.43E1.0020.0002] -10526 ; [.43E2.0020.0002] -10527 ; [.43E3.0020.0002] -10530 ; [.43E4.0020.0002] -10531 ; [.43E5.0020.0002] -10532 ; [.43E6.0020.0002] -10533 ; [.43E7.0020.0002] -10534 ; [.43E8.0020.0002] -10535 ; [.43E9.0020.0002] -10536 ; [.43EA.0020.0002] -10537 ; [.43EB.0020.0002] -10538 ; [.43EC.0020.0002] -10539 ; [.43ED.0020.0002] -1053A ; [.43EE.0020.0002] -1053B ; [.43EF.0020.0002] -1053C ; [.43F0.0020.0002] -1053D ; [.43F1.0020.0002] -1053E ; [.43F2.0020.0002] -1053F ; [.43F3.0020.0002] -10540 ; [.43F4.0020.0002] -10541 ; [.43F5.0020.0002] -10542 ; [.43F6.0020.0002] -10543 ; [.43F7.0020.0002] -10544 ; [.43F8.0020.0002] -10545 ; [.43F9.0020.0002] -10546 ; [.43FA.0020.0002] -10547 ; [.43FB.0020.0002] -10548 ; [.43FC.0020.0002] -10549 ; [.43FD.0020.0002] -1054A ; [.43FE.0020.0002] -1054B ; [.43FF.0020.0002] -1054C ; [.4400.0020.0002] -1054D ; [.4401.0020.0002] -1054E ; [.4402.0020.0002] -1054F ; [.4403.0020.0002] -10550 ; [.4404.0020.0002] -10551 ; [.4405.0020.0002] -10552 ; [.4406.0020.0002] -10553 ; [.4407.0020.0002] -10554 ; [.4408.0020.0002] -10555 ; [.4409.0020.0002] -10556 ; [.440A.0020.0002] -10557 ; [.440B.0020.0002] -10558 ; [.440C.0020.0002] -10559 ; [.440D.0020.0002] -1055A ; [.440E.0020.0002] -1055B ; [.440F.0020.0002] -1055C ; [.4410.0020.0002] -1055D ; [.4411.0020.0002] -1055E ; [.4412.0020.0002] -1055F ; [.4413.0020.0002] -10560 ; [.4414.0020.0002] -10561 ; [.4415.0020.0002] -10562 ; [.4416.0020.0002] -10563 ; [.4417.0020.0002] -110D0 ; [.4418.0020.0002] -110D1 ; [.4419.0020.0002] -110D2 ; [.441A.0020.0002] -110D3 ; [.441B.0020.0002] -110D4 ; [.441C.0020.0002] -110D5 ; [.441D.0020.0002] -110D6 ; [.441E.0020.0002] -110D7 ; [.441F.0020.0002] -110D8 ; [.4420.0020.0002] -110D9 ; [.4421.0020.0002] -110DA ; [.4422.0020.0002] -110DB ; [.4423.0020.0002] -110DC ; [.4424.0020.0002] -110DD ; [.4425.0020.0002] -110DE ; [.4426.0020.0002] -110DF ; [.4427.0020.0002] -110E0 ; [.4428.0020.0002] -110E1 ; [.4429.0020.0002] -110E2 ; [.442A.0020.0002] -110E3 ; [.442B.0020.0002] -110E4 ; [.442C.0020.0002] -110E5 ; [.442D.0020.0002] -110E6 ; [.442E.0020.0002] -110E7 ; [.442F.0020.0002] -110E8 ; [.4430.0020.0002] -16A40 ; [.4431.0020.0002] -16A41 ; [.4432.0020.0002] -16A42 ; [.4433.0020.0002] -16A43 ; [.4434.0020.0002] -16A44 ; [.4435.0020.0002] -16A45 ; [.4436.0020.0002] -16A46 ; [.4437.0020.0002] -16A47 ; [.4438.0020.0002] -16A48 ; [.4439.0020.0002] -16A49 ; [.443A.0020.0002] -16A4A ; [.443B.0020.0002] -16A4B ; [.443C.0020.0002] -16A4C ; [.443D.0020.0002] -16A4D ; [.443E.0020.0002] -16A4E ; [.443F.0020.0002] -16A4F ; [.4440.0020.0002] -16A50 ; [.4441.0020.0002] -16A51 ; [.4442.0020.0002] -16A52 ; [.4443.0020.0002] -16A53 ; [.4444.0020.0002] -16A54 ; [.4445.0020.0002] -16A55 ; [.4446.0020.0002] -16A56 ; [.4447.0020.0002] -16A57 ; [.4448.0020.0002] -16A58 ; [.4449.0020.0002] -16A59 ; [.444A.0020.0002] -16A5A ; [.444B.0020.0002] -16A5B ; [.444C.0020.0002] -16A5C ; [.444D.0020.0002] -16A5D ; [.444E.0020.0002] -16A5E ; [.444F.0020.0002] -10000 ; [.4450.0020.0002] -10001 ; [.4451.0020.0002] -10002 ; [.4452.0020.0002] -10003 ; [.4453.0020.0002] -10004 ; [.4454.0020.0002] -10005 ; [.4455.0020.0002] -10006 ; [.4456.0020.0002] -10007 ; [.4457.0020.0002] -10008 ; [.4458.0020.0002] -10009 ; [.4459.0020.0002] -1000A ; [.445A.0020.0002] -1000B ; [.445B.0020.0002] -1000D ; [.445C.0020.0002] -1000E ; [.445D.0020.0002] -1000F ; [.445E.0020.0002] -10010 ; [.445F.0020.0002] -10011 ; [.4460.0020.0002] -10012 ; [.4461.0020.0002] -10013 ; [.4462.0020.0002] -10014 ; [.4463.0020.0002] -10015 ; [.4464.0020.0002] -10016 ; [.4465.0020.0002] -10017 ; [.4466.0020.0002] -10018 ; [.4467.0020.0002] -10019 ; [.4468.0020.0002] -1001A ; [.4469.0020.0002] -1001B ; [.446A.0020.0002] -1001C ; [.446B.0020.0002] -1001D ; [.446C.0020.0002] -1001E ; [.446D.0020.0002] -1001F ; [.446E.0020.0002] -10020 ; [.446F.0020.0002] -10021 ; [.4470.0020.0002] -10022 ; [.4471.0020.0002] -10023 ; [.4472.0020.0002] -10024 ; [.4473.0020.0002] -10025 ; [.4474.0020.0002] -10026 ; [.4475.0020.0002] -10028 ; [.4476.0020.0002] -10029 ; [.4477.0020.0002] -1002A ; [.4478.0020.0002] -1002B ; [.4479.0020.0002] -1002C ; [.447A.0020.0002] -1002D ; [.447B.0020.0002] -1002E ; [.447C.0020.0002] -1002F ; [.447D.0020.0002] -10030 ; [.447E.0020.0002] -10031 ; [.447F.0020.0002] -10032 ; [.4480.0020.0002] -10033 ; [.4481.0020.0002] -10034 ; [.4482.0020.0002] -10035 ; [.4483.0020.0002] -10036 ; [.4484.0020.0002] -10037 ; [.4485.0020.0002] -10038 ; [.4486.0020.0002] -10039 ; [.4487.0020.0002] -1003A ; [.4488.0020.0002] -1003C ; [.4489.0020.0002] -1003D ; [.448A.0020.0002] -1003F ; [.448B.0020.0002] -10040 ; [.448C.0020.0002] -10041 ; [.448D.0020.0002] -10042 ; [.448E.0020.0002] -10043 ; [.448F.0020.0002] -10044 ; [.4490.0020.0002] -10045 ; [.4491.0020.0002] -10046 ; [.4492.0020.0002] -10047 ; [.4493.0020.0002] -10048 ; [.4494.0020.0002] -10049 ; [.4495.0020.0002] -1004A ; [.4496.0020.0002] -1004B ; [.4497.0020.0002] -1004C ; [.4498.0020.0002] -1004D ; [.4499.0020.0002] -10050 ; [.449A.0020.0002] -10051 ; [.449B.0020.0002] -10052 ; [.449C.0020.0002] -10053 ; [.449D.0020.0002] -10054 ; [.449E.0020.0002] -10055 ; [.449F.0020.0002] -10056 ; [.44A0.0020.0002] -10057 ; [.44A1.0020.0002] -10058 ; [.44A2.0020.0002] -10059 ; [.44A3.0020.0002] -1005A ; [.44A4.0020.0002] -1005B ; [.44A5.0020.0002] -1005C ; [.44A6.0020.0002] -1005D ; [.44A7.0020.0002] -10080 ; [.44A8.0020.0002] -10081 ; [.44A9.0020.0002] -10082 ; [.44AA.0020.0002] -10083 ; [.44AB.0020.0002] -10084 ; [.44AC.0020.0002] -10085 ; [.44AD.0020.0002] -10086 ; [.44AE.0020.0002] -10087 ; [.44AF.0020.0002] -10088 ; [.44B0.0020.0002] -10089 ; [.44B1.0020.0002] -1008A ; [.44B2.0020.0002] -1008B ; [.44B3.0020.0002] -1008C ; [.44B4.0020.0002] -1008D ; [.44B5.0020.0002] -1008E ; [.44B6.0020.0002] -1008F ; [.44B7.0020.0002] -10090 ; [.44B8.0020.0002] -10091 ; [.44B9.0020.0002] -10092 ; [.44BA.0020.0002] -10093 ; [.44BB.0020.0002] -10094 ; [.44BC.0020.0002] -10095 ; [.44BD.0020.0002] -10096 ; [.44BE.0020.0002] -10097 ; [.44BF.0020.0002] -10098 ; [.44C0.0020.0002] -10099 ; [.44C1.0020.0002] -1009A ; [.44C2.0020.0002] -1009B ; [.44C3.0020.0002] -1009C ; [.44C4.0020.0002] -1009D ; [.44C5.0020.0002] -1009E ; [.44C6.0020.0002] -1009F ; [.44C7.0020.0002] -100A0 ; [.44C8.0020.0002] -100A1 ; [.44C9.0020.0002] -100A2 ; [.44CA.0020.0002] -100A3 ; [.44CB.0020.0002] -100A4 ; [.44CC.0020.0002] -100A5 ; [.44CD.0020.0002] -100A6 ; [.44CE.0020.0002] -100A7 ; [.44CF.0020.0002] -100A8 ; [.44D0.0020.0002] -100A9 ; [.44D1.0020.0002] -100AA ; [.44D2.0020.0002] -100AB ; [.44D3.0020.0002] -100AC ; [.44D4.0020.0002] -100AD ; [.44D5.0020.0002] -100AE ; [.44D6.0020.0002] -100AF ; [.44D7.0020.0002] -100B0 ; [.44D8.0020.0002] -100B1 ; [.44D9.0020.0002] -100B2 ; [.44DA.0020.0002] -100B3 ; [.44DB.0020.0002] -100B4 ; [.44DC.0020.0002] -100B5 ; [.44DD.0020.0002] -100B6 ; [.44DE.0020.0002] -100B7 ; [.44DF.0020.0002] -100B8 ; [.44E0.0020.0002] -100B9 ; [.44E1.0020.0002] -100BA ; [.44E2.0020.0002] -100BB ; [.44E3.0020.0002] -100BC ; [.44E4.0020.0002] -100BD ; [.44E5.0020.0002] -100BE ; [.44E6.0020.0002] -100BF ; [.44E7.0020.0002] -100C0 ; [.44E8.0020.0002] -100C1 ; [.44E9.0020.0002] -100C2 ; [.44EA.0020.0002] -100C3 ; [.44EB.0020.0002] -100C4 ; [.44EC.0020.0002] -100C5 ; [.44ED.0020.0002] -100C6 ; [.44EE.0020.0002] -100C7 ; [.44EF.0020.0002] -100C8 ; [.44F0.0020.0002] -100C9 ; [.44F1.0020.0002] -100CA ; [.44F2.0020.0002] -100CB ; [.44F3.0020.0002] -100CC ; [.44F4.0020.0002] -100CD ; [.44F5.0020.0002] -100CE ; [.44F6.0020.0002] -100CF ; [.44F7.0020.0002] -100D0 ; [.44F8.0020.0002] -100D1 ; [.44F9.0020.0002] -100D2 ; [.44FA.0020.0002] -100D3 ; [.44FB.0020.0002] -100D4 ; [.44FC.0020.0002] -100D5 ; [.44FD.0020.0002] -100D6 ; [.44FE.0020.0002] -100D7 ; [.44FF.0020.0002] -100D8 ; [.4500.0020.0002] -100D9 ; [.4501.0020.0002] -100DA ; [.4502.0020.0002] -100DB ; [.4503.0020.0002] -100DC ; [.4504.0020.0002] -100DD ; [.4505.0020.0002] -100DE ; [.4506.0020.0002] -100DF ; [.4507.0020.0002] -100E0 ; [.4508.0020.0002] -100E1 ; [.4509.0020.0002] -100E2 ; [.450A.0020.0002] -100E3 ; [.450B.0020.0002] -100E4 ; [.450C.0020.0002] -100E5 ; [.450D.0020.0002] -100E6 ; [.450E.0020.0002] -100E7 ; [.450F.0020.0002] -100E8 ; [.4510.0020.0002] -100E9 ; [.4511.0020.0002] -100EA ; [.4512.0020.0002] -100EB ; [.4513.0020.0002] -100EC ; [.4514.0020.0002] -100ED ; [.4515.0020.0002] -100EE ; [.4516.0020.0002] -100EF ; [.4517.0020.0002] -100F0 ; [.4518.0020.0002] -100F1 ; [.4519.0020.0002] -100F2 ; [.451A.0020.0002] -100F3 ; [.451B.0020.0002] -100F4 ; [.451C.0020.0002] -100F5 ; [.451D.0020.0002] -100F6 ; [.451E.0020.0002] -100F7 ; [.451F.0020.0002] -100F8 ; [.4520.0020.0002] -100F9 ; [.4521.0020.0002] -100FA ; [.4522.0020.0002] -10600 ; [.4523.0020.0002] -10601 ; [.4524.0020.0002] -10602 ; [.4525.0020.0002] -10603 ; [.4526.0020.0002] -10604 ; [.4527.0020.0002] -10605 ; [.4528.0020.0002] -10606 ; [.4529.0020.0002] -10607 ; [.452A.0020.0002] -10608 ; [.452B.0020.0002] -10609 ; [.452C.0020.0002] -1060A ; [.452D.0020.0002] -1060B ; [.452E.0020.0002] -1060C ; [.452F.0020.0002] -1060D ; [.4530.0020.0002] -1060E ; [.4531.0020.0002] -1060F ; [.4532.0020.0002] -10610 ; [.4533.0020.0002] -10611 ; [.4534.0020.0002] -10612 ; [.4535.0020.0002] -10613 ; [.4536.0020.0002] -10614 ; [.4537.0020.0002] -10615 ; [.4538.0020.0002] -10616 ; [.4539.0020.0002] -10617 ; [.453A.0020.0002] -10618 ; [.453B.0020.0002] -10619 ; [.453C.0020.0002] -1061A ; [.453D.0020.0002] -1061B ; [.453E.0020.0002] -1061C ; [.453F.0020.0002] -1061D ; [.4540.0020.0002] -1061E ; [.4541.0020.0002] -1061F ; [.4542.0020.0002] -10620 ; [.4543.0020.0002] -10621 ; [.4544.0020.0002] -10622 ; [.4545.0020.0002] -10623 ; [.4546.0020.0002] -10624 ; [.4547.0020.0002] -10625 ; [.4548.0020.0002] -10626 ; [.4549.0020.0002] -10627 ; [.454A.0020.0002] -10628 ; [.454B.0020.0002] -10629 ; [.454C.0020.0002] -1062A ; [.454D.0020.0002] -1062B ; [.454E.0020.0002] -1062C ; [.454F.0020.0002] -1062D ; [.4550.0020.0002] -1062E ; [.4551.0020.0002] -1062F ; [.4552.0020.0002] -10630 ; [.4553.0020.0002] -10631 ; [.4554.0020.0002] -10632 ; [.4555.0020.0002] -10633 ; [.4556.0020.0002] -10634 ; [.4557.0020.0002] -10635 ; [.4558.0020.0002] -10636 ; [.4559.0020.0002] -10637 ; [.455A.0020.0002] -10638 ; [.455B.0020.0002] -10639 ; [.455C.0020.0002] -1063A ; [.455D.0020.0002] -1063B ; [.455E.0020.0002] -1063C ; [.455F.0020.0002] -1063D ; [.4560.0020.0002] -1063E ; [.4561.0020.0002] -1063F ; [.4562.0020.0002] -10640 ; [.4563.0020.0002] -10641 ; [.4564.0020.0002] -10642 ; [.4565.0020.0002] -10643 ; [.4566.0020.0002] -10644 ; [.4567.0020.0002] -10645 ; [.4568.0020.0002] -10646 ; [.4569.0020.0002] -10647 ; [.456A.0020.0002] -10648 ; [.456B.0020.0002] -10649 ; [.456C.0020.0002] -1064A ; [.456D.0020.0002] -1064B ; [.456E.0020.0002] -1064C ; [.456F.0020.0002] -1064D ; [.4570.0020.0002] -1064E ; [.4571.0020.0002] -1064F ; [.4572.0020.0002] -10650 ; [.4573.0020.0002] -10651 ; [.4574.0020.0002] -10652 ; [.4575.0020.0002] -10653 ; [.4576.0020.0002] -10654 ; [.4577.0020.0002] -10655 ; [.4578.0020.0002] -10656 ; [.4579.0020.0002] -10657 ; [.457A.0020.0002] -10658 ; [.457B.0020.0002] -10659 ; [.457C.0020.0002] -1065A ; [.457D.0020.0002] -1065B ; [.457E.0020.0002] -1065C ; [.457F.0020.0002] -1065D ; [.4580.0020.0002] -1065E ; [.4581.0020.0002] -1065F ; [.4582.0020.0002] -10660 ; [.4583.0020.0002] -10661 ; [.4584.0020.0002] -10662 ; [.4585.0020.0002] -10663 ; [.4586.0020.0002] -10664 ; [.4587.0020.0002] -10665 ; [.4588.0020.0002] -10666 ; [.4589.0020.0002] -10667 ; [.458A.0020.0002] -10668 ; [.458B.0020.0002] -10669 ; [.458C.0020.0002] -1066A ; [.458D.0020.0002] -1066B ; [.458E.0020.0002] -1066C ; [.458F.0020.0002] -1066D ; [.4590.0020.0002] -1066E ; [.4591.0020.0002] -1066F ; [.4592.0020.0002] -10670 ; [.4593.0020.0002] -10671 ; [.4594.0020.0002] -10672 ; [.4595.0020.0002] -10673 ; [.4596.0020.0002] -10674 ; [.4597.0020.0002] -10675 ; [.4598.0020.0002] -10676 ; [.4599.0020.0002] -10677 ; [.459A.0020.0002] -10678 ; [.459B.0020.0002] -10679 ; [.459C.0020.0002] -1067A ; [.459D.0020.0002] -1067B ; [.459E.0020.0002] -1067C ; [.459F.0020.0002] -1067D ; [.45A0.0020.0002] -1067E ; [.45A1.0020.0002] -1067F ; [.45A2.0020.0002] -10680 ; [.45A3.0020.0002] -10681 ; [.45A4.0020.0002] -10682 ; [.45A5.0020.0002] -10683 ; [.45A6.0020.0002] -10684 ; [.45A7.0020.0002] -10685 ; [.45A8.0020.0002] -10686 ; [.45A9.0020.0002] -10687 ; [.45AA.0020.0002] -10688 ; [.45AB.0020.0002] -10689 ; [.45AC.0020.0002] -1068A ; [.45AD.0020.0002] -1068B ; [.45AE.0020.0002] -1068C ; [.45AF.0020.0002] -1068D ; [.45B0.0020.0002] -1068E ; [.45B1.0020.0002] -1068F ; [.45B2.0020.0002] -10690 ; [.45B3.0020.0002] -10691 ; [.45B4.0020.0002] -10692 ; [.45B5.0020.0002] -10693 ; [.45B6.0020.0002] -10694 ; [.45B7.0020.0002] -10695 ; [.45B8.0020.0002] -10696 ; [.45B9.0020.0002] -10697 ; [.45BA.0020.0002] -10698 ; [.45BB.0020.0002] -10699 ; [.45BC.0020.0002] -1069A ; [.45BD.0020.0002] -1069B ; [.45BE.0020.0002] -1069C ; [.45BF.0020.0002] -1069D ; [.45C0.0020.0002] -1069E ; [.45C1.0020.0002] -1069F ; [.45C2.0020.0002] -106A0 ; [.45C3.0020.0002] -106A1 ; [.45C4.0020.0002] -106A2 ; [.45C5.0020.0002] -106A3 ; [.45C6.0020.0002] -106A4 ; [.45C7.0020.0002] -106A5 ; [.45C8.0020.0002] -106A6 ; [.45C9.0020.0002] -106A7 ; [.45CA.0020.0002] -106A8 ; [.45CB.0020.0002] -106A9 ; [.45CC.0020.0002] -106AA ; [.45CD.0020.0002] -106AB ; [.45CE.0020.0002] -106AC ; [.45CF.0020.0002] -106AD ; [.45D0.0020.0002] -106AE ; [.45D1.0020.0002] -106AF ; [.45D2.0020.0002] -106B0 ; [.45D3.0020.0002] -106B1 ; [.45D4.0020.0002] -106B2 ; [.45D5.0020.0002] -106B3 ; [.45D6.0020.0002] -106B4 ; [.45D7.0020.0002] -106B5 ; [.45D8.0020.0002] -106B6 ; [.45D9.0020.0002] -106B7 ; [.45DA.0020.0002] -106B8 ; [.45DB.0020.0002] -106B9 ; [.45DC.0020.0002] -106BA ; [.45DD.0020.0002] -106BB ; [.45DE.0020.0002] -106BC ; [.45DF.0020.0002] -106BD ; [.45E0.0020.0002] -106BE ; [.45E1.0020.0002] -106BF ; [.45E2.0020.0002] -106C0 ; [.45E3.0020.0002] -106C1 ; [.45E4.0020.0002] -106C2 ; [.45E5.0020.0002] -106C3 ; [.45E6.0020.0002] -106C4 ; [.45E7.0020.0002] -106C5 ; [.45E8.0020.0002] -106C6 ; [.45E9.0020.0002] -106C7 ; [.45EA.0020.0002] -106C8 ; [.45EB.0020.0002] -106C9 ; [.45EC.0020.0002] -106CA ; [.45ED.0020.0002] -106CB ; [.45EE.0020.0002] -106CC ; [.45EF.0020.0002] -106CD ; [.45F0.0020.0002] -106CE ; [.45F1.0020.0002] -106CF ; [.45F2.0020.0002] -106D0 ; [.45F3.0020.0002] -106D1 ; [.45F4.0020.0002] -106D2 ; [.45F5.0020.0002] -106D3 ; [.45F6.0020.0002] -106D4 ; [.45F7.0020.0002] -106D5 ; [.45F8.0020.0002] -106D6 ; [.45F9.0020.0002] -106D7 ; [.45FA.0020.0002] -106D8 ; [.45FB.0020.0002] -106D9 ; [.45FC.0020.0002] -106DA ; [.45FD.0020.0002] -106DB ; [.45FE.0020.0002] -106DC ; [.45FF.0020.0002] -106DD ; [.4600.0020.0002] -106DE ; [.4601.0020.0002] -106DF ; [.4602.0020.0002] -106E0 ; [.4603.0020.0002] -106E1 ; [.4604.0020.0002] -106E2 ; [.4605.0020.0002] -106E3 ; [.4606.0020.0002] -106E4 ; [.4607.0020.0002] -106E5 ; [.4608.0020.0002] -106E6 ; [.4609.0020.0002] -106E7 ; [.460A.0020.0002] -106E8 ; [.460B.0020.0002] -106E9 ; [.460C.0020.0002] -106EA ; [.460D.0020.0002] -106EB ; [.460E.0020.0002] -106EC ; [.460F.0020.0002] -106ED ; [.4610.0020.0002] -106EE ; [.4611.0020.0002] -106EF ; [.4612.0020.0002] -106F0 ; [.4613.0020.0002] -106F1 ; [.4614.0020.0002] -106F2 ; [.4615.0020.0002] -106F3 ; [.4616.0020.0002] -106F4 ; [.4617.0020.0002] -106F5 ; [.4618.0020.0002] -106F6 ; [.4619.0020.0002] -106F7 ; [.461A.0020.0002] -106F8 ; [.461B.0020.0002] -106F9 ; [.461C.0020.0002] -106FA ; [.461D.0020.0002] -106FB ; [.461E.0020.0002] -106FC ; [.461F.0020.0002] -106FD ; [.4620.0020.0002] -106FE ; [.4621.0020.0002] -106FF ; [.4622.0020.0002] -10700 ; [.4623.0020.0002] -10701 ; [.4624.0020.0002] -10702 ; [.4625.0020.0002] -10703 ; [.4626.0020.0002] -10704 ; [.4627.0020.0002] -10705 ; [.4628.0020.0002] -10706 ; [.4629.0020.0002] -10707 ; [.462A.0020.0002] -10708 ; [.462B.0020.0002] -10709 ; [.462C.0020.0002] -1070A ; [.462D.0020.0002] -1070B ; [.462E.0020.0002] -1070C ; [.462F.0020.0002] -1070D ; [.4630.0020.0002] -1070E ; [.4631.0020.0002] -1070F ; [.4632.0020.0002] -10710 ; [.4633.0020.0002] -10711 ; [.4634.0020.0002] -10712 ; [.4635.0020.0002] -10713 ; [.4636.0020.0002] -10714 ; [.4637.0020.0002] -10715 ; [.4638.0020.0002] -10716 ; [.4639.0020.0002] -10717 ; [.463A.0020.0002] -10718 ; [.463B.0020.0002] -10719 ; [.463C.0020.0002] -1071A ; [.463D.0020.0002] -1071B ; [.463E.0020.0002] -1071C ; [.463F.0020.0002] -1071D ; [.4640.0020.0002] -1071E ; [.4641.0020.0002] -1071F ; [.4642.0020.0002] -10720 ; [.4643.0020.0002] -10721 ; [.4644.0020.0002] -10722 ; [.4645.0020.0002] -10723 ; [.4646.0020.0002] -10724 ; [.4647.0020.0002] -10725 ; [.4648.0020.0002] -10726 ; [.4649.0020.0002] -10727 ; [.464A.0020.0002] -10728 ; [.464B.0020.0002] -10729 ; [.464C.0020.0002] -1072A ; [.464D.0020.0002] -1072B ; [.464E.0020.0002] -1072C ; [.464F.0020.0002] -1072D ; [.4650.0020.0002] -1072E ; [.4651.0020.0002] -1072F ; [.4652.0020.0002] -10730 ; [.4653.0020.0002] -10731 ; [.4654.0020.0002] -10732 ; [.4655.0020.0002] -10733 ; [.4656.0020.0002] -10734 ; [.4657.0020.0002] -10735 ; [.4658.0020.0002] -10736 ; [.4659.0020.0002] -10740 ; [.465A.0020.0002] -10741 ; [.465B.0020.0002] -10742 ; [.465C.0020.0002] -10743 ; [.465D.0020.0002] -10744 ; [.465E.0020.0002] -10745 ; [.465F.0020.0002] -10746 ; [.4660.0020.0002] -10747 ; [.4661.0020.0002] -10748 ; [.4662.0020.0002] -10749 ; [.4663.0020.0002] -1074A ; [.4664.0020.0002] -1074B ; [.4665.0020.0002] -1074C ; [.4666.0020.0002] -1074D ; [.4667.0020.0002] -1074E ; [.4668.0020.0002] -1074F ; [.4669.0020.0002] -10750 ; [.466A.0020.0002] -10751 ; [.466B.0020.0002] -10752 ; [.466C.0020.0002] -10753 ; [.466D.0020.0002] -10754 ; [.466E.0020.0002] -10755 ; [.466F.0020.0002] -10760 ; [.4670.0020.0002] -10761 ; [.4671.0020.0002] -10762 ; [.4672.0020.0002] -10763 ; [.4673.0020.0002] -10764 ; [.4674.0020.0002] -10765 ; [.4675.0020.0002] -10766 ; [.4676.0020.0002] -10767 ; [.4677.0020.0002] -10800 ; [.4678.0020.0002] -10801 ; [.4679.0020.0002] -10802 ; [.467A.0020.0002] -10803 ; [.467B.0020.0002] -10804 ; [.467C.0020.0002] -10805 ; [.467D.0020.0002] -10808 ; [.467E.0020.0002] -1080A ; [.467F.0020.0002] -1080B ; [.4680.0020.0002] -1080C ; [.4681.0020.0002] -1080D ; [.4682.0020.0002] -1080E ; [.4683.0020.0002] -1080F ; [.4684.0020.0002] -10810 ; [.4685.0020.0002] -10811 ; [.4686.0020.0002] -10812 ; [.4687.0020.0002] -10813 ; [.4688.0020.0002] -10814 ; [.4689.0020.0002] -10815 ; [.468A.0020.0002] -10816 ; [.468B.0020.0002] -10817 ; [.468C.0020.0002] -10818 ; [.468D.0020.0002] -10819 ; [.468E.0020.0002] -1081A ; [.468F.0020.0002] -1081B ; [.4690.0020.0002] -1081C ; [.4691.0020.0002] -1081D ; [.4692.0020.0002] -1081E ; [.4693.0020.0002] -1081F ; [.4694.0020.0002] -10820 ; [.4695.0020.0002] -10821 ; [.4696.0020.0002] -10822 ; [.4697.0020.0002] -10823 ; [.4698.0020.0002] -10824 ; [.4699.0020.0002] -10825 ; [.469A.0020.0002] -10826 ; [.469B.0020.0002] -10827 ; [.469C.0020.0002] -10828 ; [.469D.0020.0002] -10829 ; [.469E.0020.0002] -1082A ; [.469F.0020.0002] -1082B ; [.46A0.0020.0002] -1082C ; [.46A1.0020.0002] -1082D ; [.46A2.0020.0002] -1082E ; [.46A3.0020.0002] -1082F ; [.46A4.0020.0002] -10830 ; [.46A5.0020.0002] -10831 ; [.46A6.0020.0002] -10832 ; [.46A7.0020.0002] -10833 ; [.46A8.0020.0002] -10834 ; [.46A9.0020.0002] -10835 ; [.46AA.0020.0002] -10837 ; [.46AB.0020.0002] -10838 ; [.46AC.0020.0002] -1083C ; [.46AD.0020.0002] -1083F ; [.46AE.0020.0002] -10A60 ; [.46AF.0020.0002] -10A61 ; [.46B0.0020.0002] -10A62 ; [.46B1.0020.0002] -10A63 ; [.46B2.0020.0002] -10A64 ; [.46B3.0020.0002] -10A65 ; [.46B4.0020.0002] -10A66 ; [.46B5.0020.0002] -10A67 ; [.46B6.0020.0002] -10A68 ; [.46B7.0020.0002] -10A69 ; [.46B8.0020.0002] -10A6A ; [.46B9.0020.0002] -10A6B ; [.46BA.0020.0002] -10A6C ; [.46BB.0020.0002] -10A6D ; [.46BC.0020.0002] -10A6E ; [.46BD.0020.0002] -10A6F ; [.46BE.0020.0002] -10A70 ; [.46BF.0020.0002] -10A71 ; [.46C0.0020.0002] -10A72 ; [.46C1.0020.0002] -10A73 ; [.46C2.0020.0002] -10A74 ; [.46C3.0020.0002] -10A75 ; [.46C4.0020.0002] -10A76 ; [.46C5.0020.0002] -10A77 ; [.46C6.0020.0002] -10A78 ; [.46C7.0020.0002] -10A79 ; [.46C8.0020.0002] -10A7A ; [.46C9.0020.0002] -10A7B ; [.46CA.0020.0002] -10A7C ; [.46CB.0020.0002] -10A80 ; [.46CC.0020.0002] -10A81 ; [.46CD.0020.0002] -10A82 ; [.46CE.0020.0002] -10A83 ; [.46CF.0020.0002] -10A84 ; [.46D0.0020.0002] -10A85 ; [.46D1.0020.0002] -10A86 ; [.46D2.0020.0002] -10A87 ; [.46D3.0020.0002] -10A88 ; [.46D4.0020.0002] -10A89 ; [.46D5.0020.0002] -10A8A ; [.46D6.0020.0002] -10A8B ; [.46D7.0020.0002] -10A8C ; [.46D8.0020.0002] -10A8D ; [.46D9.0020.0002] -10A8E ; [.46DA.0020.0002] -10A8F ; [.46DB.0020.0002] -10A90 ; [.46DC.0020.0002] -10A91 ; [.46DD.0020.0002] -10A92 ; [.46DE.0020.0002] -10A93 ; [.46DF.0020.0002] -10A94 ; [.46E0.0020.0002] -10A95 ; [.46E1.0020.0002] -10A96 ; [.46E2.0020.0002] -10A97 ; [.46E3.0020.0002] -10A98 ; [.46E4.0020.0002] -10A99 ; [.46E5.0020.0002] -10A9A ; [.46E6.0020.0002] -10A9B ; [.46E7.0020.0002] -10A9C ; [.46E8.0020.0002] -10B00 ; [.46E9.0020.0002] -10B01 ; [.46EA.0020.0002] -10B02 ; [.46EB.0020.0002] -10B03 ; [.46EC.0020.0002] -10B04 ; [.46ED.0020.0002] -10B05 ; [.46EE.0020.0002] -10B06 ; [.46EF.0020.0002] -10B07 ; [.46F0.0020.0002] -10B08 ; [.46F1.0020.0002] -10B09 ; [.46F2.0020.0002] -10B0A ; [.46F3.0020.0002] -10B0B ; [.46F4.0020.0002] -10B0C ; [.46F5.0020.0002] -10B0D ; [.46F6.0020.0002] -10B0E ; [.46F7.0020.0002] -10B0F ; [.46F8.0020.0002] -10B10 ; [.46F9.0020.0002] -10B11 ; [.46FA.0020.0002] -10B12 ; [.46FB.0020.0002] -10B13 ; [.46FC.0020.0002] -10B14 ; [.46FD.0020.0002] -10B15 ; [.46FE.0020.0002] -10B16 ; [.46FF.0020.0002] -10B17 ; [.4700.0020.0002] -10B18 ; [.4701.0020.0002] -10B19 ; [.4702.0020.0002] -10B1A ; [.4703.0020.0002] -10B1B ; [.4704.0020.0002] -10B1C ; [.4705.0020.0002] -10B1D ; [.4706.0020.0002] -10B1E ; [.4707.0020.0002] -10B1F ; [.4708.0020.0002] -10B20 ; [.4709.0020.0002] -10B21 ; [.470A.0020.0002] -10B22 ; [.470B.0020.0002] -10B23 ; [.470C.0020.0002] -10B24 ; [.470D.0020.0002] -10B25 ; [.470E.0020.0002] -10B26 ; [.470F.0020.0002] -10B27 ; [.4710.0020.0002] -10B28 ; [.4711.0020.0002] -10B29 ; [.4712.0020.0002] -10B2A ; [.4713.0020.0002] -10B2B ; [.4714.0020.0002] -10B2C ; [.4715.0020.0002] -10B2D ; [.4716.0020.0002] -10B2E ; [.4716.0020.0004][.0000.010B.0004] -10B2F ; [.4717.0020.0002] -10B30 ; [.4718.0020.0002] -10B31 ; [.4719.0020.0002] -10B32 ; [.471A.0020.0002] -10B33 ; [.471B.0020.0002] -10B34 ; [.471C.0020.0002] -10B35 ; [.471D.0020.0002] -10860 ; [.471E.0020.0002] -10861 ; [.471F.0020.0002] -10862 ; [.4720.0020.0002] -10863 ; [.4721.0020.0002] -10864 ; [.4722.0020.0002] -10865 ; [.4723.0020.0002] -10866 ; [.4724.0020.0002] -10867 ; [.4725.0020.0002] -10868 ; [.4726.0020.0002] -10869 ; [.4727.0020.0002] -1086A ; [.4728.0020.0002] -1086B ; [.4729.0020.0002] -1086C ; [.472A.0020.0002] -1086E ; [.472B.0020.0002] -1086D ; [.472B.0020.0019] -1086F ; [.472C.0020.0002] -10870 ; [.472D.0020.0002] -10871 ; [.472E.0020.0002] -10872 ; [.472F.0020.0002] -10873 ; [.4730.0020.0002] -10874 ; [.4731.0020.0002] -10875 ; [.4732.0020.0002] -10876 ; [.4733.0020.0002] -10881 ; [.4734.0020.0002] -10880 ; [.4734.0020.0019] -10883 ; [.4735.0020.0002] -10882 ; [.4735.0020.0019] -10884 ; [.4736.0020.0002] -10885 ; [.4737.0020.0002] -10887 ; [.4738.0020.0002] -10886 ; [.4738.0020.0019] -10888 ; [.4739.0020.0002] -10889 ; [.473A.0020.0002] -1088A ; [.473B.0020.0002] -1088B ; [.473C.0020.0002] -1088D ; [.473D.0020.0002] -1088C ; [.473D.0020.0019] -1088F ; [.473E.0020.0002] -1088E ; [.473E.0020.0019] -10891 ; [.473F.0020.0002] -10890 ; [.473F.0020.0019] -10893 ; [.4740.0020.0002] -10892 ; [.4740.0020.0019] -10895 ; [.4741.0020.0002] -10894 ; [.4741.0020.0019] -10896 ; [.4742.0020.0002] -10897 ; [.4743.0020.0002] -10898 ; [.4744.0020.0002] -10899 ; [.4745.0020.0002] -1089A ; [.4746.0020.0002] -1089B ; [.4747.0020.0002] -1089D ; [.4748.0020.0002] -1089C ; [.4748.0020.0019] -1089E ; [.4749.0020.0002] -108E0 ; [.474A.0020.0002] -108E1 ; [.474B.0020.0002] -108E2 ; [.474C.0020.0002] -108E3 ; [.474D.0020.0002] -108E4 ; [.474E.0020.0002] -108E5 ; [.474F.0020.0002] -108E6 ; [.4750.0020.0002] -108E7 ; [.4751.0020.0002] -108E8 ; [.4752.0020.0002] -108E9 ; [.4753.0020.0002] -108EA ; [.4754.0020.0002] -108EB ; [.4755.0020.0002] -108EC ; [.4756.0020.0002] -108ED ; [.4757.0020.0002] -108EE ; [.4758.0020.0002] -108EF ; [.4759.0020.0002] -108F0 ; [.475A.0020.0002] -108F1 ; [.475B.0020.0002] -108F2 ; [.475C.0020.0002] -108F4 ; [.475D.0020.0002] -108F5 ; [.475E.0020.0002] -10840 ; [.475F.0020.0002] -10841 ; [.4760.0020.0002] -10842 ; [.4761.0020.0002] -10843 ; [.4762.0020.0002] -10844 ; [.4763.0020.0002] -10845 ; [.4764.0020.0002] -10846 ; [.4765.0020.0002] -10847 ; [.4766.0020.0002] -10848 ; [.4767.0020.0002] -10849 ; [.4768.0020.0002] -1084A ; [.4769.0020.0002] -1084B ; [.476A.0020.0002] -1084C ; [.476B.0020.0002] -1084D ; [.476C.0020.0002] -1084E ; [.476D.0020.0002] -1084F ; [.476E.0020.0002] -10850 ; [.476F.0020.0002] -10851 ; [.4770.0020.0002] -10852 ; [.4771.0020.0002] -10853 ; [.4772.0020.0002] -10854 ; [.4773.0020.0002] -10855 ; [.4774.0020.0002] -10B40 ; [.4775.0020.0002] -10B41 ; [.4776.0020.0002] -10B42 ; [.4777.0020.0002] -10B43 ; [.4778.0020.0002] -10B44 ; [.4779.0020.0002] -10B45 ; [.477A.0020.0002] -10B46 ; [.477B.0020.0002] -10B47 ; [.477C.0020.0002] -10B48 ; [.477D.0020.0002] -10B49 ; [.477E.0020.0002] -10B4A ; [.477F.0020.0002] -10B4B ; [.4780.0020.0002] -10B4C ; [.4781.0020.0002] -10B4D ; [.4782.0020.0002] -10B4E ; [.4783.0020.0002] -10B4F ; [.4784.0020.0002] -10B50 ; [.4785.0020.0002] -10B51 ; [.4786.0020.0002] -10B52 ; [.4787.0020.0002] -10B53 ; [.4788.0020.0002] -10B54 ; [.4789.0020.0002] -10B55 ; [.478A.0020.0002] -10B60 ; [.478B.0020.0002] -10B61 ; [.478C.0020.0002] -10B62 ; [.478D.0020.0002] -10B63 ; [.478E.0020.0002] -10B64 ; [.478F.0020.0002] -10B65 ; [.4790.0020.0002] -10B66 ; [.4791.0020.0002] -10B67 ; [.4792.0020.0002] -10B68 ; [.4793.0020.0002] -10B69 ; [.4794.0020.0002] -10B6A ; [.4795.0020.0002] -10B6B ; [.4796.0020.0002] -10B6C ; [.4797.0020.0002] -10B6D ; [.4798.0020.0002] -10B6E ; [.4799.0020.0002] -10B6F ; [.479A.0020.0002] -10B70 ; [.479B.0020.0002] -10B71 ; [.479C.0020.0002] -10B72 ; [.479D.0020.0002] -10B80 ; [.479E.0020.0002] -10B81 ; [.479F.0020.0002] -10B82 ; [.47A0.0020.0002] -10B83 ; [.47A1.0020.0002] -10B84 ; [.47A2.0020.0002] -10B85 ; [.47A3.0020.0002] -10B86 ; [.47A4.0020.0002] -10B87 ; [.47A5.0020.0002] -10B88 ; [.47A6.0020.0002] -10B89 ; [.47A7.0020.0002] -10B8A ; [.47A8.0020.0002] -10B8B ; [.47A9.0020.0002] -10B8C ; [.47AA.0020.0002] -10B8D ; [.47AB.0020.0002] -10B8E ; [.47AC.0020.0002] -10B8F ; [.47AD.0020.0002] -10B90 ; [.47AE.0020.0002] -10B91 ; [.47AF.0020.0002] -10AC0 ; [.47B0.0020.0002] -10AC1 ; [.47B1.0020.0002] -10AC2 ; [.47B2.0020.0002] -10AC3 ; [.47B3.0020.0002] -10AC4 ; [.47B4.0020.0002] -10AC5 ; [.47B5.0020.0002] -10AC6 ; [.47B6.0020.0002] -10AC7 ; [.47B7.0020.0002] -10AC8 ; [.47B7.0020.0004][.0000.010C.0004] -10AC9 ; [.47B8.0020.0002] -10ACA ; [.47B9.0020.0002] -10ACB ; [.47BA.0020.0002] -10ACC ; [.47BB.0020.0002] -10ACD ; [.47BC.0020.0002] -10ACE ; [.47BD.0020.0002] -10ACF ; [.47BE.0020.0002] -10AD0 ; [.47BF.0020.0002] -10AD1 ; [.47C0.0020.0002] -10AD2 ; [.47C1.0020.0002] -10AD3 ; [.47C2.0020.0002] -10AD4 ; [.47C3.0020.0002] -10AD5 ; [.47C4.0020.0002] -10AD6 ; [.47C5.0020.0002] -10AD7 ; [.47C6.0020.0002] -10AD8 ; [.47C7.0020.0002] -10AD9 ; [.47C8.0020.0002] -10ADA ; [.47C9.0020.0002] -10ADB ; [.47CA.0020.0002] -10ADC ; [.47CB.0020.0002] -10ADD ; [.47CC.0020.0002] -10ADE ; [.47CD.0020.0002] -10ADF ; [.47CE.0020.0002] -10AE0 ; [.47CF.0020.0002] -10AE1 ; [.47D0.0020.0002] -10AE2 ; [.47D1.0020.0002] -10AE3 ; [.47D2.0020.0002] -10AE4 ; [.47D3.0020.0002] -10380 ; [.47D4.0020.0002] -10381 ; [.47D5.0020.0002] -10382 ; [.47D6.0020.0002] -10383 ; [.47D7.0020.0002] -10384 ; [.47D8.0020.0002] -10385 ; [.47D9.0020.0002] -10386 ; [.47DA.0020.0002] -10387 ; [.47DB.0020.0002] -10388 ; [.47DC.0020.0002] -10389 ; [.47DD.0020.0002] -1038A ; [.47DE.0020.0002] -1038B ; [.47DF.0020.0002] -1038C ; [.47E0.0020.0002] -1038D ; [.47E1.0020.0002] -1038E ; [.47E2.0020.0002] -1038F ; [.47E3.0020.0002] -10390 ; [.47E4.0020.0002] -10391 ; [.47E5.0020.0002] -10392 ; [.47E6.0020.0002] -10393 ; [.47E7.0020.0002] -10394 ; [.47E8.0020.0002] -10395 ; [.47E9.0020.0002] -10396 ; [.47EA.0020.0002] -10397 ; [.47EB.0020.0002] -10398 ; [.47EC.0020.0002] -10399 ; [.47ED.0020.0002] -1039A ; [.47EE.0020.0002] -1039B ; [.47EF.0020.0002] -1039C ; [.47F0.0020.0002] -1039D ; [.47F1.0020.0002] -103A0 ; [.47F2.0020.0002] -103A1 ; [.47F3.0020.0002] -103A2 ; [.47F4.0020.0002] -103A3 ; [.47F5.0020.0002] -103A4 ; [.47F6.0020.0002] -103A5 ; [.47F7.0020.0002] -103A6 ; [.47F8.0020.0002] -103A7 ; [.47F9.0020.0002] -103A8 ; [.47FA.0020.0002] -103A9 ; [.47FB.0020.0002] -103AA ; [.47FC.0020.0002] -103AB ; [.47FD.0020.0002] -103AC ; [.47FE.0020.0002] -103AD ; [.47FF.0020.0002] -103AE ; [.4800.0020.0002] -103AF ; [.4801.0020.0002] -103B0 ; [.4802.0020.0002] -103B1 ; [.4803.0020.0002] -103B2 ; [.4804.0020.0002] -103B3 ; [.4805.0020.0002] -103B4 ; [.4806.0020.0002] -103B5 ; [.4807.0020.0002] -103B6 ; [.4808.0020.0002] -103B7 ; [.4809.0020.0002] -103B8 ; [.480A.0020.0002] -103B9 ; [.480B.0020.0002] -103BA ; [.480C.0020.0002] -103BB ; [.480D.0020.0002] -103BC ; [.480E.0020.0002] -103BD ; [.480F.0020.0002] -103BE ; [.4810.0020.0002] -103BF ; [.4811.0020.0002] -103C0 ; [.4812.0020.0002] -103C1 ; [.4813.0020.0002] -103C2 ; [.4814.0020.0002] -103C3 ; [.4815.0020.0002] -103C8 ; [.4816.0020.0002] -103C9 ; [.4817.0020.0002] -103CA ; [.4818.0020.0002] -103CB ; [.4819.0020.0002] -103CC ; [.481A.0020.0002] -103CD ; [.481B.0020.0002] -103CE ; [.481C.0020.0002] -103CF ; [.481D.0020.0002] -12000 ; [.481E.0020.0002] -12001 ; [.481F.0020.0002] -12002 ; [.4820.0020.0002] -12003 ; [.4821.0020.0002] -12004 ; [.4822.0020.0002] -12005 ; [.4823.0020.0002] -12006 ; [.4824.0020.0002] -12007 ; [.4825.0020.0002] -12008 ; [.4826.0020.0002] -12009 ; [.4827.0020.0002] -1200A ; [.4828.0020.0002] -1200B ; [.4829.0020.0002] -1200C ; [.482A.0020.0002] -1200D ; [.482B.0020.0002] -1200E ; [.482C.0020.0002] -1200F ; [.482D.0020.0002] -12010 ; [.482E.0020.0002] -12011 ; [.482F.0020.0002] -12012 ; [.4830.0020.0002] -12013 ; [.4831.0020.0002] -12014 ; [.4832.0020.0002] -12015 ; [.4833.0020.0002] -12016 ; [.4834.0020.0002] -12017 ; [.4835.0020.0002] -12018 ; [.4836.0020.0002] -12019 ; [.4837.0020.0002] -1201A ; [.4838.0020.0002] -1201B ; [.4839.0020.0002] -1201C ; [.483A.0020.0002] -1201D ; [.483B.0020.0002] -1201E ; [.483C.0020.0002] -1201F ; [.483D.0020.0002] -12020 ; [.483E.0020.0002] -12021 ; [.483F.0020.0002] -12022 ; [.4840.0020.0002] -12023 ; [.4841.0020.0002] -12024 ; [.4842.0020.0002] -12025 ; [.4843.0020.0002] -12026 ; [.4844.0020.0002] -12027 ; [.4845.0020.0002] -12028 ; [.4846.0020.0002] -12029 ; [.4847.0020.0002] -1202A ; [.4848.0020.0002] -1202B ; [.4849.0020.0002] -1202C ; [.484A.0020.0002] -1202D ; [.484B.0020.0002] -1202E ; [.484C.0020.0002] -1202F ; [.484D.0020.0002] -12030 ; [.484E.0020.0002] -12031 ; [.484F.0020.0002] -12032 ; [.4850.0020.0002] -12033 ; [.4851.0020.0002] -12034 ; [.4852.0020.0002] -12035 ; [.4853.0020.0002] -12036 ; [.4854.0020.0002] -12037 ; [.4855.0020.0002] -12038 ; [.4856.0020.0002] -12039 ; [.4857.0020.0002] -1203A ; [.4858.0020.0002] -1203B ; [.4859.0020.0002] -1203C ; [.485A.0020.0002] -1203D ; [.485B.0020.0002] -1203E ; [.485C.0020.0002] -1203F ; [.485D.0020.0002] -12040 ; [.485E.0020.0002] -12041 ; [.485F.0020.0002] -12042 ; [.4860.0020.0002] -12043 ; [.4861.0020.0002] -12044 ; [.4862.0020.0002] -12045 ; [.4863.0020.0002] -12046 ; [.4864.0020.0002] -12047 ; [.4865.0020.0002] -12048 ; [.4866.0020.0002] -12049 ; [.4867.0020.0002] -1204A ; [.4868.0020.0002] -1204B ; [.4869.0020.0002] -1204C ; [.486A.0020.0002] -1204D ; [.486B.0020.0002] -1204E ; [.486C.0020.0002] -1204F ; [.486D.0020.0002] -12050 ; [.486E.0020.0002] -12051 ; [.486F.0020.0002] -12052 ; [.4870.0020.0002] -12053 ; [.4871.0020.0002] -12054 ; [.4872.0020.0002] -12055 ; [.4873.0020.0002] -12056 ; [.4874.0020.0002] -12057 ; [.4875.0020.0002] -12058 ; [.4876.0020.0002] -12059 ; [.4877.0020.0002] -1205A ; [.4878.0020.0002] -1205B ; [.4879.0020.0002] -1205C ; [.487A.0020.0002] -1205D ; [.487B.0020.0002] -1205E ; [.487C.0020.0002] -1205F ; [.487D.0020.0002] -12060 ; [.487E.0020.0002] -12061 ; [.487F.0020.0002] -12062 ; [.4880.0020.0002] -12063 ; [.4881.0020.0002] -12064 ; [.4882.0020.0002] -12065 ; [.4883.0020.0002] -12066 ; [.4884.0020.0002] -12067 ; [.4885.0020.0002] -12068 ; [.4886.0020.0002] -12069 ; [.4887.0020.0002] -1206A ; [.4888.0020.0002] -1206B ; [.4889.0020.0002] -1206C ; [.488A.0020.0002] -1206D ; [.488B.0020.0002] -1206E ; [.488C.0020.0002] -1206F ; [.488D.0020.0002] -12070 ; [.488E.0020.0002] -12071 ; [.488F.0020.0002] -12072 ; [.4890.0020.0002] -12073 ; [.4891.0020.0002] -12074 ; [.4892.0020.0002] -12075 ; [.4893.0020.0002] -12076 ; [.4894.0020.0002] -12077 ; [.4895.0020.0002] -12078 ; [.4896.0020.0002] -12079 ; [.4897.0020.0002] -1207A ; [.4898.0020.0002] -1207B ; [.4899.0020.0002] -1207C ; [.489A.0020.0002] -1207D ; [.489B.0020.0002] -1207E ; [.489C.0020.0002] -1207F ; [.489D.0020.0002] -12080 ; [.489E.0020.0002] -12081 ; [.489F.0020.0002] -12082 ; [.48A0.0020.0002] -12083 ; [.48A1.0020.0002] -12084 ; [.48A2.0020.0002] -12085 ; [.48A3.0020.0002] -12086 ; [.48A4.0020.0002] -12087 ; [.48A5.0020.0002] -12088 ; [.48A6.0020.0002] -12089 ; [.48A7.0020.0002] -1208A ; [.48A8.0020.0002] -1208B ; [.48A9.0020.0002] -1208C ; [.48AA.0020.0002] -1208D ; [.48AB.0020.0002] -1208E ; [.48AC.0020.0002] -1208F ; [.48AD.0020.0002] -12090 ; [.48AE.0020.0002] -12091 ; [.48AF.0020.0002] -12092 ; [.48B0.0020.0002] -12093 ; [.48B1.0020.0002] -12094 ; [.48B2.0020.0002] -12095 ; [.48B3.0020.0002] -12096 ; [.48B4.0020.0002] -12097 ; [.48B5.0020.0002] -12098 ; [.48B6.0020.0002] -12099 ; [.48B7.0020.0002] -1209A ; [.48B8.0020.0002] -1209B ; [.48B9.0020.0002] -1209C ; [.48BA.0020.0002] -1209D ; [.48BB.0020.0002] -1209E ; [.48BC.0020.0002] -1209F ; [.48BD.0020.0002] -120A0 ; [.48BE.0020.0002] -120A1 ; [.48BF.0020.0002] -120A2 ; [.48C0.0020.0002] -120A3 ; [.48C1.0020.0002] -120A4 ; [.48C2.0020.0002] -120A5 ; [.48C3.0020.0002] -120A6 ; [.48C4.0020.0002] -120A7 ; [.48C5.0020.0002] -120A8 ; [.48C6.0020.0002] -120A9 ; [.48C7.0020.0002] -120AA ; [.48C8.0020.0002] -120AB ; [.48C9.0020.0002] -120AC ; [.48CA.0020.0002] -120AD ; [.48CB.0020.0002] -120AE ; [.48CC.0020.0002] -120AF ; [.48CD.0020.0002] -120B0 ; [.48CE.0020.0002] -120B1 ; [.48CF.0020.0002] -120B2 ; [.48D0.0020.0002] -120B3 ; [.48D1.0020.0002] -120B4 ; [.48D2.0020.0002] -120B5 ; [.48D3.0020.0002] -120B6 ; [.48D4.0020.0002] -120B7 ; [.48D5.0020.0002] -120B8 ; [.48D6.0020.0002] -120B9 ; [.48D7.0020.0002] -120BA ; [.48D8.0020.0002] -120BB ; [.48D9.0020.0002] -120BC ; [.48DA.0020.0002] -120BD ; [.48DB.0020.0002] -120BE ; [.48DC.0020.0002] -120BF ; [.48DD.0020.0002] -120C0 ; [.48DE.0020.0002] -120C1 ; [.48DF.0020.0002] -120C2 ; [.48E0.0020.0002] -120C3 ; [.48E1.0020.0002] -120C4 ; [.48E2.0020.0002] -120C5 ; [.48E3.0020.0002] -120C6 ; [.48E4.0020.0002] -120C7 ; [.48E5.0020.0002] -120C8 ; [.48E6.0020.0002] -120C9 ; [.48E7.0020.0002] -120CA ; [.48E8.0020.0002] -120CB ; [.48E9.0020.0002] -120CC ; [.48EA.0020.0002] -120CD ; [.48EB.0020.0002] -120CE ; [.48EC.0020.0002] -120CF ; [.48ED.0020.0002] -120D0 ; [.48EE.0020.0002] -120D1 ; [.48EF.0020.0002] -120D2 ; [.48F0.0020.0002] -120D3 ; [.48F1.0020.0002] -120D4 ; [.48F2.0020.0002] -120D5 ; [.48F3.0020.0002] -120D6 ; [.48F4.0020.0002] -120D7 ; [.48F5.0020.0002] -120D8 ; [.48F6.0020.0002] -120D9 ; [.48F7.0020.0002] -120DA ; [.48F8.0020.0002] -120DB ; [.48F9.0020.0002] -120DC ; [.48FA.0020.0002] -120DD ; [.48FB.0020.0002] -120DE ; [.48FC.0020.0002] -120DF ; [.48FD.0020.0002] -120E0 ; [.48FE.0020.0002] -120E1 ; [.48FF.0020.0002] -120E2 ; [.4900.0020.0002] -120E3 ; [.4901.0020.0002] -120E4 ; [.4902.0020.0002] -120E5 ; [.4903.0020.0002] -120E6 ; [.4904.0020.0002] -120E7 ; [.4905.0020.0002] -120E8 ; [.4906.0020.0002] -120E9 ; [.4907.0020.0002] -120EA ; [.4908.0020.0002] -120EB ; [.4909.0020.0002] -120EC ; [.490A.0020.0002] -120ED ; [.490B.0020.0002] -120EE ; [.490C.0020.0002] -120EF ; [.490D.0020.0002] -120F0 ; [.490E.0020.0002] -120F1 ; [.490F.0020.0002] -120F2 ; [.4910.0020.0002] -120F3 ; [.4911.0020.0002] -120F4 ; [.4912.0020.0002] -120F5 ; [.4913.0020.0002] -120F6 ; [.4914.0020.0002] -120F7 ; [.4915.0020.0002] -120F8 ; [.4916.0020.0002] -120F9 ; [.4917.0020.0002] -120FA ; [.4918.0020.0002] -120FB ; [.4919.0020.0002] -120FC ; [.491A.0020.0002] -120FD ; [.491B.0020.0002] -120FE ; [.491C.0020.0002] -120FF ; [.491D.0020.0002] -12100 ; [.491E.0020.0002] -12101 ; [.491F.0020.0002] -12102 ; [.4920.0020.0002] -12103 ; [.4921.0020.0002] -12104 ; [.4922.0020.0002] -12105 ; [.4923.0020.0002] -12106 ; [.4924.0020.0002] -12107 ; [.4925.0020.0002] -12108 ; [.4926.0020.0002] -12109 ; [.4927.0020.0002] -1210A ; [.4928.0020.0002] -1210B ; [.4929.0020.0002] -1210C ; [.492A.0020.0002] -1210D ; [.492B.0020.0002] -1210E ; [.492C.0020.0002] -1210F ; [.492D.0020.0002] -12110 ; [.492E.0020.0002] -12111 ; [.492F.0020.0002] -12112 ; [.4930.0020.0002] -12113 ; [.4931.0020.0002] -12114 ; [.4932.0020.0002] -12115 ; [.4933.0020.0002] -12116 ; [.4934.0020.0002] -12117 ; [.4935.0020.0002] -12118 ; [.4936.0020.0002] -12119 ; [.4937.0020.0002] -1211A ; [.4938.0020.0002] -1211B ; [.4939.0020.0002] -1211C ; [.493A.0020.0002] -1211D ; [.493B.0020.0002] -1211E ; [.493C.0020.0002] -1211F ; [.493D.0020.0002] -12120 ; [.493E.0020.0002] -12121 ; [.493F.0020.0002] -12122 ; [.4940.0020.0002] -12123 ; [.4941.0020.0002] -12124 ; [.4942.0020.0002] -12125 ; [.4943.0020.0002] -12126 ; [.4944.0020.0002] -12127 ; [.4945.0020.0002] -12128 ; [.4946.0020.0002] -12129 ; [.4947.0020.0002] -1212A ; [.4948.0020.0002] -1212B ; [.4949.0020.0002] -1212C ; [.494A.0020.0002] -1212D ; [.494B.0020.0002] -1212E ; [.494C.0020.0002] -1212F ; [.494D.0020.0002] -12130 ; [.494E.0020.0002] -12131 ; [.494F.0020.0002] -12132 ; [.4950.0020.0002] -12133 ; [.4951.0020.0002] -12134 ; [.4952.0020.0002] -12135 ; [.4953.0020.0002] -12136 ; [.4954.0020.0002] -12137 ; [.4955.0020.0002] -12138 ; [.4956.0020.0002] -12139 ; [.4957.0020.0002] -1213A ; [.4958.0020.0002] -1213B ; [.4959.0020.0002] -1213C ; [.495A.0020.0002] -1213D ; [.495B.0020.0002] -1213E ; [.495C.0020.0002] -1213F ; [.495D.0020.0002] -12140 ; [.495E.0020.0002] -12141 ; [.495F.0020.0002] -12142 ; [.4960.0020.0002] -12143 ; [.4961.0020.0002] -12144 ; [.4962.0020.0002] -12145 ; [.4963.0020.0002] -12146 ; [.4964.0020.0002] -12147 ; [.4965.0020.0002] -12148 ; [.4966.0020.0002] -12149 ; [.4967.0020.0002] -1214A ; [.4968.0020.0002] -1214B ; [.4969.0020.0002] -1214C ; [.496A.0020.0002] -1214D ; [.496B.0020.0002] -1214E ; [.496C.0020.0002] -1214F ; [.496D.0020.0002] -12150 ; [.496E.0020.0002] -12151 ; [.496F.0020.0002] -12152 ; [.4970.0020.0002] -12153 ; [.4971.0020.0002] -12154 ; [.4972.0020.0002] -12155 ; [.4973.0020.0002] -12156 ; [.4974.0020.0002] -12157 ; [.4975.0020.0002] -12158 ; [.4976.0020.0002] -12159 ; [.4977.0020.0002] -1215A ; [.4978.0020.0002] -1215B ; [.4979.0020.0002] -1215C ; [.497A.0020.0002] -1215D ; [.497B.0020.0002] -1215E ; [.497C.0020.0002] -1215F ; [.497D.0020.0002] -12160 ; [.497E.0020.0002] -12161 ; [.497F.0020.0002] -12162 ; [.4980.0020.0002] -12163 ; [.4981.0020.0002] -12164 ; [.4982.0020.0002] -12165 ; [.4983.0020.0002] -12166 ; [.4984.0020.0002] -12167 ; [.4985.0020.0002] -12168 ; [.4986.0020.0002] -12169 ; [.4987.0020.0002] -1216A ; [.4988.0020.0002] -1216B ; [.4989.0020.0002] -1216C ; [.498A.0020.0002] -1216D ; [.498B.0020.0002] -1216E ; [.498C.0020.0002] -1216F ; [.498D.0020.0002] -12170 ; [.498E.0020.0002] -12171 ; [.498F.0020.0002] -12172 ; [.4990.0020.0002] -12173 ; [.4991.0020.0002] -12174 ; [.4992.0020.0002] -12175 ; [.4993.0020.0002] -12176 ; [.4994.0020.0002] -12177 ; [.4995.0020.0002] -12178 ; [.4996.0020.0002] -12179 ; [.4997.0020.0002] -1217A ; [.4998.0020.0002] -1217B ; [.4999.0020.0002] -1217C ; [.499A.0020.0002] -1217D ; [.499B.0020.0002] -1217E ; [.499C.0020.0002] -1217F ; [.499D.0020.0002] -12180 ; [.499E.0020.0002] -12181 ; [.499F.0020.0002] -12182 ; [.49A0.0020.0002] -12183 ; [.49A1.0020.0002] -12184 ; [.49A2.0020.0002] -12185 ; [.49A3.0020.0002] -12186 ; [.49A4.0020.0002] -12187 ; [.49A5.0020.0002] -12188 ; [.49A6.0020.0002] -12189 ; [.49A7.0020.0002] -1218A ; [.49A8.0020.0002] -1218B ; [.49A9.0020.0002] -1218C ; [.49AA.0020.0002] -1218D ; [.49AB.0020.0002] -1218E ; [.49AC.0020.0002] -1218F ; [.49AD.0020.0002] -12190 ; [.49AE.0020.0002] -12191 ; [.49AF.0020.0002] -12192 ; [.49B0.0020.0002] -12193 ; [.49B1.0020.0002] -12194 ; [.49B2.0020.0002] -12195 ; [.49B3.0020.0002] -12196 ; [.49B4.0020.0002] -12197 ; [.49B5.0020.0002] -12198 ; [.49B6.0020.0002] -12199 ; [.49B7.0020.0002] -1219A ; [.49B8.0020.0002] -1219B ; [.49B9.0020.0002] -1219C ; [.49BA.0020.0002] -1219D ; [.49BB.0020.0002] -1219E ; [.49BC.0020.0002] -1219F ; [.49BD.0020.0002] -121A0 ; [.49BE.0020.0002] -121A1 ; [.49BF.0020.0002] -121A2 ; [.49C0.0020.0002] -121A3 ; [.49C1.0020.0002] -121A4 ; [.49C2.0020.0002] -121A5 ; [.49C3.0020.0002] -121A6 ; [.49C4.0020.0002] -121A7 ; [.49C5.0020.0002] -121A8 ; [.49C6.0020.0002] -121A9 ; [.49C7.0020.0002] -121AA ; [.49C8.0020.0002] -121AB ; [.49C9.0020.0002] -121AC ; [.49CA.0020.0002] -121AD ; [.49CB.0020.0002] -121AE ; [.49CC.0020.0002] -121AF ; [.49CD.0020.0002] -121B0 ; [.49CE.0020.0002] -121B1 ; [.49CF.0020.0002] -121B2 ; [.49D0.0020.0002] -121B3 ; [.49D1.0020.0002] -121B4 ; [.49D2.0020.0002] -121B5 ; [.49D3.0020.0002] -121B6 ; [.49D4.0020.0002] -121B7 ; [.49D5.0020.0002] -121B8 ; [.49D6.0020.0002] -121B9 ; [.49D7.0020.0002] -121BA ; [.49D8.0020.0002] -121BB ; [.49D9.0020.0002] -121BC ; [.49DA.0020.0002] -121BD ; [.49DB.0020.0002] -121BE ; [.49DC.0020.0002] -121BF ; [.49DD.0020.0002] -121C0 ; [.49DE.0020.0002] -121C1 ; [.49DF.0020.0002] -121C2 ; [.49E0.0020.0002] -121C3 ; [.49E1.0020.0002] -121C4 ; [.49E2.0020.0002] -121C5 ; [.49E3.0020.0002] -121C6 ; [.49E4.0020.0002] -121C7 ; [.49E5.0020.0002] -121C8 ; [.49E6.0020.0002] -121C9 ; [.49E7.0020.0002] -121CA ; [.49E8.0020.0002] -121CB ; [.49E9.0020.0002] -121CC ; [.49EA.0020.0002] -121CD ; [.49EB.0020.0002] -121CE ; [.49EC.0020.0002] -121CF ; [.49ED.0020.0002] -121D0 ; [.49EE.0020.0002] -121D1 ; [.49EF.0020.0002] -121D2 ; [.49F0.0020.0002] -121D3 ; [.49F1.0020.0002] -121D4 ; [.49F2.0020.0002] -121D5 ; [.49F3.0020.0002] -121D6 ; [.49F4.0020.0002] -121D7 ; [.49F5.0020.0002] -121D8 ; [.49F6.0020.0002] -121D9 ; [.49F7.0020.0002] -121DA ; [.49F8.0020.0002] -121DB ; [.49F9.0020.0002] -121DC ; [.49FA.0020.0002] -121DD ; [.49FB.0020.0002] -121DE ; [.49FC.0020.0002] -121DF ; [.49FD.0020.0002] -121E0 ; [.49FE.0020.0002] -121E1 ; [.49FF.0020.0002] -121E2 ; [.4A00.0020.0002] -121E3 ; [.4A01.0020.0002] -121E4 ; [.4A02.0020.0002] -121E5 ; [.4A03.0020.0002] -121E6 ; [.4A04.0020.0002] -121E7 ; [.4A05.0020.0002] -121E8 ; [.4A06.0020.0002] -121E9 ; [.4A07.0020.0002] -121EA ; [.4A08.0020.0002] -121EB ; [.4A09.0020.0002] -121EC ; [.4A0A.0020.0002] -121ED ; [.4A0B.0020.0002] -121EE ; [.4A0C.0020.0002] -121EF ; [.4A0D.0020.0002] -121F0 ; [.4A0E.0020.0002] -121F1 ; [.4A0F.0020.0002] -121F2 ; [.4A10.0020.0002] -121F3 ; [.4A11.0020.0002] -121F4 ; [.4A12.0020.0002] -121F5 ; [.4A13.0020.0002] -121F6 ; [.4A14.0020.0002] -121F7 ; [.4A15.0020.0002] -121F8 ; [.4A16.0020.0002] -121F9 ; [.4A17.0020.0002] -121FA ; [.4A18.0020.0002] -121FB ; [.4A19.0020.0002] -121FC ; [.4A1A.0020.0002] -121FD ; [.4A1B.0020.0002] -121FE ; [.4A1C.0020.0002] -121FF ; [.4A1D.0020.0002] -12200 ; [.4A1E.0020.0002] -12201 ; [.4A1F.0020.0002] -12202 ; [.4A20.0020.0002] -12203 ; [.4A21.0020.0002] -12204 ; [.4A22.0020.0002] -12205 ; [.4A23.0020.0002] -12206 ; [.4A24.0020.0002] -12207 ; [.4A25.0020.0002] -12208 ; [.4A26.0020.0002] -12209 ; [.4A27.0020.0002] -1220A ; [.4A28.0020.0002] -1220B ; [.4A29.0020.0002] -1220C ; [.4A2A.0020.0002] -1220D ; [.4A2B.0020.0002] -1220E ; [.4A2C.0020.0002] -1220F ; [.4A2D.0020.0002] -12210 ; [.4A2E.0020.0002] -12211 ; [.4A2F.0020.0002] -12212 ; [.4A30.0020.0002] -12213 ; [.4A31.0020.0002] -12214 ; [.4A32.0020.0002] -12215 ; [.4A33.0020.0002] -12216 ; [.4A34.0020.0002] -12217 ; [.4A35.0020.0002] -12218 ; [.4A36.0020.0002] -12219 ; [.4A37.0020.0002] -1221A ; [.4A38.0020.0002] -1221B ; [.4A39.0020.0002] -1221C ; [.4A3A.0020.0002] -1221D ; [.4A3B.0020.0002] -1221E ; [.4A3C.0020.0002] -1221F ; [.4A3D.0020.0002] -12220 ; [.4A3E.0020.0002] -12221 ; [.4A3F.0020.0002] -12222 ; [.4A40.0020.0002] -12223 ; [.4A41.0020.0002] -12224 ; [.4A42.0020.0002] -12225 ; [.4A43.0020.0002] -12226 ; [.4A44.0020.0002] -12227 ; [.4A45.0020.0002] -12228 ; [.4A46.0020.0002] -12229 ; [.4A47.0020.0002] -1222A ; [.4A48.0020.0002] -1222B ; [.4A49.0020.0002] -1222C ; [.4A4A.0020.0002] -1222D ; [.4A4B.0020.0002] -1222E ; [.4A4C.0020.0002] -1222F ; [.4A4D.0020.0002] -12230 ; [.4A4E.0020.0002] -12231 ; [.4A4F.0020.0002] -12232 ; [.4A50.0020.0002] -12233 ; [.4A51.0020.0002] -12234 ; [.4A52.0020.0002] -12235 ; [.4A53.0020.0002] -12236 ; [.4A54.0020.0002] -12237 ; [.4A55.0020.0002] -12238 ; [.4A56.0020.0002] -12239 ; [.4A57.0020.0002] -1223A ; [.4A58.0020.0002] -1223B ; [.4A59.0020.0002] -1223C ; [.4A5A.0020.0002] -1223D ; [.4A5B.0020.0002] -1223E ; [.4A5C.0020.0002] -1223F ; [.4A5D.0020.0002] -12240 ; [.4A5E.0020.0002] -12241 ; [.4A5F.0020.0002] -12242 ; [.4A60.0020.0002] -12243 ; [.4A61.0020.0002] -12244 ; [.4A62.0020.0002] -12245 ; [.4A63.0020.0002] -12246 ; [.4A64.0020.0002] -12247 ; [.4A65.0020.0002] -12248 ; [.4A66.0020.0002] -12249 ; [.4A67.0020.0002] -1224A ; [.4A68.0020.0002] -1224B ; [.4A69.0020.0002] -1224C ; [.4A6A.0020.0002] -1224D ; [.4A6B.0020.0002] -1224E ; [.4A6C.0020.0002] -1224F ; [.4A6D.0020.0002] -12250 ; [.4A6E.0020.0002] -12251 ; [.4A6F.0020.0002] -12252 ; [.4A70.0020.0002] -12253 ; [.4A71.0020.0002] -12254 ; [.4A72.0020.0002] -12255 ; [.4A73.0020.0002] -12256 ; [.4A74.0020.0002] -12257 ; [.4A75.0020.0002] -12258 ; [.4A76.0020.0002] -12259 ; [.4A77.0020.0002] -1225A ; [.4A78.0020.0002] -1225B ; [.4A79.0020.0002] -1225C ; [.4A7A.0020.0002] -1225D ; [.4A7B.0020.0002] -1225E ; [.4A7C.0020.0002] -1225F ; [.4A7D.0020.0002] -12260 ; [.4A7E.0020.0002] -12261 ; [.4A7F.0020.0002] -12262 ; [.4A80.0020.0002] -122D4 ; [.4A81.0020.0002] -122D5 ; [.4A82.0020.0002] -12263 ; [.4A83.0020.0002] -12264 ; [.4A84.0020.0002] -12265 ; [.4A85.0020.0002] -12266 ; [.4A86.0020.0002] -12267 ; [.4A87.0020.0002] -12268 ; [.4A88.0020.0002] -12269 ; [.4A89.0020.0002] -1226A ; [.4A8A.0020.0002] -1226B ; [.4A8B.0020.0002] -1226C ; [.4A8C.0020.0002] -1226D ; [.4A8D.0020.0002] -1226E ; [.4A8E.0020.0002] -1226F ; [.4A8F.0020.0002] -12270 ; [.4A90.0020.0002] -12271 ; [.4A91.0020.0002] -12272 ; [.4A92.0020.0002] -12273 ; [.4A93.0020.0002] -12274 ; [.4A94.0020.0002] -12275 ; [.4A95.0020.0002] -12276 ; [.4A96.0020.0002] -12277 ; [.4A97.0020.0002] -12278 ; [.4A98.0020.0002] -12279 ; [.4A99.0020.0002] -1227A ; [.4A9A.0020.0002] -1227B ; [.4A9B.0020.0002] -1227C ; [.4A9C.0020.0002] -1227D ; [.4A9D.0020.0002] -1227E ; [.4A9E.0020.0002] -1227F ; [.4A9F.0020.0002] -12280 ; [.4AA0.0020.0002] -12281 ; [.4AA1.0020.0002] -12282 ; [.4AA2.0020.0002] -12283 ; [.4AA3.0020.0002] -12284 ; [.4AA4.0020.0002] -12285 ; [.4AA5.0020.0002] -12286 ; [.4AA6.0020.0002] -12287 ; [.4AA7.0020.0002] -12288 ; [.4AA8.0020.0002] -12289 ; [.4AA9.0020.0002] -1228A ; [.4AAA.0020.0002] -1228B ; [.4AAB.0020.0002] -1228C ; [.4AAC.0020.0002] -1228D ; [.4AAD.0020.0002] -1228E ; [.4AAE.0020.0002] -1228F ; [.4AAF.0020.0002] -12290 ; [.4AB0.0020.0002] -12291 ; [.4AB1.0020.0002] -12292 ; [.4AB2.0020.0002] -12293 ; [.4AB3.0020.0002] -12294 ; [.4AB4.0020.0002] -12295 ; [.4AB5.0020.0002] -12296 ; [.4AB6.0020.0002] -12297 ; [.4AB7.0020.0002] -12298 ; [.4AB8.0020.0002] -12299 ; [.4AB9.0020.0002] -1229A ; [.4ABA.0020.0002] -1229B ; [.4ABB.0020.0002] -1229C ; [.4ABC.0020.0002] -1229D ; [.4ABD.0020.0002] -1229E ; [.4ABE.0020.0002] -1229F ; [.4ABF.0020.0002] -122A0 ; [.4AC0.0020.0002] -122A1 ; [.4AC1.0020.0002] -122A2 ; [.4AC2.0020.0002] -122A3 ; [.4AC3.0020.0002] -122A4 ; [.4AC4.0020.0002] -122A5 ; [.4AC5.0020.0002] -122A6 ; [.4AC6.0020.0002] -122A7 ; [.4AC7.0020.0002] -122A8 ; [.4AC8.0020.0002] -122A9 ; [.4AC9.0020.0002] -122AA ; [.4ACA.0020.0002] -122AB ; [.4ACB.0020.0002] -122AC ; [.4ACC.0020.0002] -122AD ; [.4ACD.0020.0002] -122AE ; [.4ACE.0020.0002] -122AF ; [.4ACF.0020.0002] -122B0 ; [.4AD0.0020.0002] -122B1 ; [.4AD1.0020.0002] -122B2 ; [.4AD2.0020.0002] -122B3 ; [.4AD3.0020.0002] -122B4 ; [.4AD4.0020.0002] -122B5 ; [.4AD5.0020.0002] -122B6 ; [.4AD6.0020.0002] -122B7 ; [.4AD7.0020.0002] -122B8 ; [.4AD8.0020.0002] -122B9 ; [.4AD9.0020.0002] -122BA ; [.4ADA.0020.0002] -122BB ; [.4ADB.0020.0002] -122BC ; [.4ADC.0020.0002] -122BD ; [.4ADD.0020.0002] -122BE ; [.4ADE.0020.0002] -122BF ; [.4ADF.0020.0002] -122C0 ; [.4AE0.0020.0002] -122C1 ; [.4AE1.0020.0002] -122C2 ; [.4AE2.0020.0002] -122C3 ; [.4AE3.0020.0002] -122C4 ; [.4AE4.0020.0002] -122C5 ; [.4AE5.0020.0002] -122C6 ; [.4AE6.0020.0002] -122C7 ; [.4AE7.0020.0002] -122C8 ; [.4AE8.0020.0002] -122C9 ; [.4AE9.0020.0002] -122CA ; [.4AEA.0020.0002] -122CB ; [.4AEB.0020.0002] -122CC ; [.4AEC.0020.0002] -122CD ; [.4AED.0020.0002] -122CE ; [.4AEE.0020.0002] -122CF ; [.4AEF.0020.0002] -122D0 ; [.4AF0.0020.0002] -122D1 ; [.4AF1.0020.0002] -122D2 ; [.4AF2.0020.0002] -122D3 ; [.4AF3.0020.0002] -122D6 ; [.4AF4.0020.0002] -122D7 ; [.4AF5.0020.0002] -122D8 ; [.4AF6.0020.0002] -122D9 ; [.4AF7.0020.0002] -122DA ; [.4AF8.0020.0002] -122DB ; [.4AF9.0020.0002] -122DC ; [.4AFA.0020.0002] -122DD ; [.4AFB.0020.0002] -122DE ; [.4AFC.0020.0002] -122DF ; [.4AFD.0020.0002] -122E0 ; [.4AFE.0020.0002] -122E1 ; [.4AFF.0020.0002] -122E2 ; [.4B00.0020.0002] -122E3 ; [.4B01.0020.0002] -122E4 ; [.4B02.0020.0002] -122E5 ; [.4B03.0020.0002] -122E6 ; [.4B04.0020.0002] -122E7 ; [.4B05.0020.0002] -122E8 ; [.4B06.0020.0002] -122E9 ; [.4B07.0020.0002] -122EA ; [.4B08.0020.0002] -122EB ; [.4B09.0020.0002] -122EC ; [.4B0A.0020.0002] -122ED ; [.4B0B.0020.0002] -122EE ; [.4B0C.0020.0002] -122EF ; [.4B0D.0020.0002] -122F0 ; [.4B0E.0020.0002] -122F1 ; [.4B0F.0020.0002] -122F2 ; [.4B10.0020.0002] -122F3 ; [.4B11.0020.0002] -122F4 ; [.4B12.0020.0002] -122F5 ; [.4B13.0020.0002] -122F6 ; [.4B14.0020.0002] -122F7 ; [.4B15.0020.0002] -122F8 ; [.4B16.0020.0002] -122F9 ; [.4B17.0020.0002] -122FA ; [.4B18.0020.0002] -122FB ; [.4B19.0020.0002] -122FC ; [.4B1A.0020.0002] -122FD ; [.4B1B.0020.0002] -122FE ; [.4B1C.0020.0002] -122FF ; [.4B1D.0020.0002] -12300 ; [.4B1E.0020.0002] -12301 ; [.4B1F.0020.0002] -12302 ; [.4B20.0020.0002] -12303 ; [.4B21.0020.0002] -12304 ; [.4B22.0020.0002] -12305 ; [.4B23.0020.0002] -12306 ; [.4B24.0020.0002] -12307 ; [.4B25.0020.0002] -12308 ; [.4B26.0020.0002] -12309 ; [.4B27.0020.0002] -1230A ; [.4B28.0020.0002] -1230B ; [.4B29.0020.0002] -1230C ; [.4B2A.0020.0002] -1230D ; [.4B2B.0020.0002] -1230E ; [.4B2C.0020.0002] -1230F ; [.4B2D.0020.0002] -12310 ; [.4B2E.0020.0002] -12311 ; [.4B2F.0020.0002] -12312 ; [.4B30.0020.0002] -12313 ; [.4B31.0020.0002] -12314 ; [.4B32.0020.0002] -12315 ; [.4B33.0020.0002] -12316 ; [.4B34.0020.0002] -12317 ; [.4B35.0020.0002] -12318 ; [.4B36.0020.0002] -12319 ; [.4B37.0020.0002] -1231A ; [.4B38.0020.0002] -1231B ; [.4B39.0020.0002] -1231C ; [.4B3A.0020.0002] -1231D ; [.4B3B.0020.0002] -1231E ; [.4B3C.0020.0002] -1231F ; [.4B3D.0020.0002] -12320 ; [.4B3E.0020.0002] -12321 ; [.4B3F.0020.0002] -12322 ; [.4B40.0020.0002] -12323 ; [.4B41.0020.0002] -12324 ; [.4B42.0020.0002] -12325 ; [.4B43.0020.0002] -12326 ; [.4B44.0020.0002] -12327 ; [.4B45.0020.0002] -12328 ; [.4B46.0020.0002] -12329 ; [.4B47.0020.0002] -1232A ; [.4B48.0020.0002] -1232B ; [.4B49.0020.0002] -1232C ; [.4B4A.0020.0002] -1232D ; [.4B4B.0020.0002] -1232E ; [.4B4C.0020.0002] -1232F ; [.4B4D.0020.0002] -12330 ; [.4B4E.0020.0002] -12331 ; [.4B4F.0020.0002] -12332 ; [.4B50.0020.0002] -12333 ; [.4B51.0020.0002] -12334 ; [.4B52.0020.0002] -12335 ; [.4B53.0020.0002] -12336 ; [.4B54.0020.0002] -12337 ; [.4B55.0020.0002] -12338 ; [.4B56.0020.0002] -12339 ; [.4B57.0020.0002] -1233A ; [.4B58.0020.0002] -1233B ; [.4B59.0020.0002] -1233C ; [.4B5A.0020.0002] -1233D ; [.4B5B.0020.0002] -1233E ; [.4B5C.0020.0002] -1233F ; [.4B5D.0020.0002] -12340 ; [.4B5E.0020.0002] -12341 ; [.4B5F.0020.0002] -12342 ; [.4B60.0020.0002] -12343 ; [.4B61.0020.0002] -12344 ; [.4B62.0020.0002] -12345 ; [.4B63.0020.0002] -12346 ; [.4B64.0020.0002] -12347 ; [.4B65.0020.0002] -12348 ; [.4B66.0020.0002] -12349 ; [.4B67.0020.0002] -1234A ; [.4B68.0020.0002] -1234B ; [.4B69.0020.0002] -1234C ; [.4B6A.0020.0002] -1234D ; [.4B6B.0020.0002] -1234E ; [.4B6C.0020.0002] -1234F ; [.4B6D.0020.0002] -12350 ; [.4B6E.0020.0002] -12351 ; [.4B6F.0020.0002] -12352 ; [.4B70.0020.0002] -12353 ; [.4B71.0020.0002] -12354 ; [.4B72.0020.0002] -12355 ; [.4B73.0020.0002] -12356 ; [.4B74.0020.0002] -12357 ; [.4B75.0020.0002] -12358 ; [.4B76.0020.0002] -12359 ; [.4B77.0020.0002] -1235A ; [.4B78.0020.0002] -1235B ; [.4B79.0020.0002] -1235C ; [.4B7A.0020.0002] -1235D ; [.4B7B.0020.0002] -1235E ; [.4B7C.0020.0002] -1235F ; [.4B7D.0020.0002] -12360 ; [.4B7E.0020.0002] -12361 ; [.4B7F.0020.0002] -12362 ; [.4B80.0020.0002] -12363 ; [.4B81.0020.0002] -12364 ; [.4B82.0020.0002] -12365 ; [.4B83.0020.0002] -12366 ; [.4B84.0020.0002] -12367 ; [.4B85.0020.0002] -12368 ; [.4B86.0020.0002] -12369 ; [.4B87.0020.0002] -1236A ; [.4B88.0020.0002] -1236B ; [.4B89.0020.0002] -1236C ; [.4B8A.0020.0002] -1236D ; [.4B8B.0020.0002] -1236E ; [.4B8C.0020.0002] -1236F ; [.4B8D.0020.0002] -12370 ; [.4B8E.0020.0002] -12371 ; [.4B8F.0020.0002] -12372 ; [.4B90.0020.0002] -12373 ; [.4B91.0020.0002] -12374 ; [.4B92.0020.0002] -12375 ; [.4B93.0020.0002] -12376 ; [.4B94.0020.0002] -12377 ; [.4B95.0020.0002] -12378 ; [.4B96.0020.0002] -12379 ; [.4B97.0020.0002] -1237A ; [.4B98.0020.0002] -1237B ; [.4B99.0020.0002] -1237C ; [.4B9A.0020.0002] -1237D ; [.4B9B.0020.0002] -1237E ; [.4B9C.0020.0002] -1237F ; [.4B9D.0020.0002] -12380 ; [.4B9E.0020.0002] -12381 ; [.4B9F.0020.0002] -12382 ; [.4BA0.0020.0002] -12383 ; [.4BA1.0020.0002] -12384 ; [.4BA2.0020.0002] -12385 ; [.4BA3.0020.0002] -12386 ; [.4BA4.0020.0002] -12387 ; [.4BA5.0020.0002] -12388 ; [.4BA6.0020.0002] -12389 ; [.4BA7.0020.0002] -1238A ; [.4BA8.0020.0002] -1238B ; [.4BA9.0020.0002] -1238C ; [.4BAA.0020.0002] -1238D ; [.4BAB.0020.0002] -1238E ; [.4BAC.0020.0002] -1238F ; [.4BAD.0020.0002] -12390 ; [.4BAE.0020.0002] -12391 ; [.4BAF.0020.0002] -12392 ; [.4BB0.0020.0002] -12393 ; [.4BB1.0020.0002] -12394 ; [.4BB2.0020.0002] -12395 ; [.4BB3.0020.0002] -12396 ; [.4BB4.0020.0002] -12397 ; [.4BB5.0020.0002] -12398 ; [.4BB6.0020.0002] -12399 ; [.4BB7.0020.0002] -12480 ; [.4BB8.0020.0002] -12481 ; [.4BB9.0020.0002] -12482 ; [.4BBA.0020.0002] -12483 ; [.4BBB.0020.0002] -12484 ; [.4BBC.0020.0002] -12485 ; [.4BBD.0020.0002] -12486 ; [.4BBE.0020.0002] -12487 ; [.4BBF.0020.0002] -12488 ; [.4BC0.0020.0002] -12489 ; [.4BC1.0020.0002] -1248A ; [.4BC2.0020.0002] -1248B ; [.4BC3.0020.0002] -1248C ; [.4BC4.0020.0002] -1248D ; [.4BC5.0020.0002] -1248E ; [.4BC6.0020.0002] -1248F ; [.4BC7.0020.0002] -12490 ; [.4BC8.0020.0002] -12491 ; [.4BC9.0020.0002] -12492 ; [.4BCA.0020.0002] -12493 ; [.4BCB.0020.0002] -12494 ; [.4BCC.0020.0002] -12495 ; [.4BCD.0020.0002] -12496 ; [.4BCE.0020.0002] -12497 ; [.4BCF.0020.0002] -12498 ; [.4BD0.0020.0002] -12499 ; [.4BD1.0020.0002] -1249A ; [.4BD2.0020.0002] -1249B ; [.4BD3.0020.0002] -1249C ; [.4BD4.0020.0002] -1249D ; [.4BD5.0020.0002] -1249E ; [.4BD6.0020.0002] -1249F ; [.4BD7.0020.0002] -124A0 ; [.4BD8.0020.0002] -124A1 ; [.4BD9.0020.0002] -124A2 ; [.4BDA.0020.0002] -124A3 ; [.4BDB.0020.0002] -124A4 ; [.4BDC.0020.0002] -124A5 ; [.4BDD.0020.0002] -124A6 ; [.4BDE.0020.0002] -124A7 ; [.4BDF.0020.0002] -124A8 ; [.4BE0.0020.0002] -124A9 ; [.4BE1.0020.0002] -124AA ; [.4BE2.0020.0002] -124AB ; [.4BE3.0020.0002] -124AC ; [.4BE4.0020.0002] -124AD ; [.4BE5.0020.0002] -124AE ; [.4BE6.0020.0002] -124AF ; [.4BE7.0020.0002] -124B0 ; [.4BE8.0020.0002] -124B1 ; [.4BE9.0020.0002] -124B2 ; [.4BEA.0020.0002] -124B3 ; [.4BEB.0020.0002] -124B4 ; [.4BEC.0020.0002] -124B5 ; [.4BED.0020.0002] -124B6 ; [.4BEE.0020.0002] -124B7 ; [.4BEF.0020.0002] -124B8 ; [.4BF0.0020.0002] -124B9 ; [.4BF1.0020.0002] -124BA ; [.4BF2.0020.0002] -124BB ; [.4BF3.0020.0002] -124BC ; [.4BF4.0020.0002] -124BD ; [.4BF5.0020.0002] -124BE ; [.4BF6.0020.0002] -124BF ; [.4BF7.0020.0002] -124C0 ; [.4BF8.0020.0002] -124C1 ; [.4BF9.0020.0002] -124C2 ; [.4BFA.0020.0002] -124C3 ; [.4BFB.0020.0002] -124C4 ; [.4BFC.0020.0002] -124C5 ; [.4BFD.0020.0002] -124C6 ; [.4BFE.0020.0002] -124C7 ; [.4BFF.0020.0002] -124C8 ; [.4C00.0020.0002] -124C9 ; [.4C01.0020.0002] -124CA ; [.4C02.0020.0002] -124CB ; [.4C03.0020.0002] -124CC ; [.4C04.0020.0002] -124CD ; [.4C05.0020.0002] -124CE ; [.4C06.0020.0002] -124CF ; [.4C07.0020.0002] -124D0 ; [.4C08.0020.0002] -124D1 ; [.4C09.0020.0002] -124D2 ; [.4C0A.0020.0002] -124D3 ; [.4C0B.0020.0002] -124D4 ; [.4C0C.0020.0002] -124D5 ; [.4C0D.0020.0002] -124D6 ; [.4C0E.0020.0002] -124D7 ; [.4C0F.0020.0002] -124D8 ; [.4C10.0020.0002] -124D9 ; [.4C11.0020.0002] -124DA ; [.4C12.0020.0002] -124DB ; [.4C13.0020.0002] -124DC ; [.4C14.0020.0002] -124DD ; [.4C15.0020.0002] -124DE ; [.4C16.0020.0002] -124DF ; [.4C17.0020.0002] -124E0 ; [.4C18.0020.0002] -124E1 ; [.4C19.0020.0002] -124E2 ; [.4C1A.0020.0002] -124E3 ; [.4C1B.0020.0002] -124E4 ; [.4C1C.0020.0002] -124E5 ; [.4C1D.0020.0002] -124E6 ; [.4C1E.0020.0002] -124E7 ; [.4C1F.0020.0002] -124E8 ; [.4C20.0020.0002] -124E9 ; [.4C21.0020.0002] -124EA ; [.4C22.0020.0002] -124EB ; [.4C23.0020.0002] -124EC ; [.4C24.0020.0002] -124ED ; [.4C25.0020.0002] -124EE ; [.4C26.0020.0002] -124EF ; [.4C27.0020.0002] -124F0 ; [.4C28.0020.0002] -124F1 ; [.4C29.0020.0002] -124F2 ; [.4C2A.0020.0002] -124F3 ; [.4C2B.0020.0002] -124F4 ; [.4C2C.0020.0002] -124F5 ; [.4C2D.0020.0002] -124F6 ; [.4C2E.0020.0002] -124F7 ; [.4C2F.0020.0002] -124F8 ; [.4C30.0020.0002] -124F9 ; [.4C31.0020.0002] -124FA ; [.4C32.0020.0002] -124FB ; [.4C33.0020.0002] -124FC ; [.4C34.0020.0002] -124FD ; [.4C35.0020.0002] -124FE ; [.4C36.0020.0002] -124FF ; [.4C37.0020.0002] -12500 ; [.4C38.0020.0002] -12501 ; [.4C39.0020.0002] -12502 ; [.4C3A.0020.0002] -12503 ; [.4C3B.0020.0002] -12504 ; [.4C3C.0020.0002] -12505 ; [.4C3D.0020.0002] -12506 ; [.4C3E.0020.0002] -12507 ; [.4C3F.0020.0002] -12508 ; [.4C40.0020.0002] -12509 ; [.4C41.0020.0002] -1250A ; [.4C42.0020.0002] -1250B ; [.4C43.0020.0002] -1250C ; [.4C44.0020.0002] -1250D ; [.4C45.0020.0002] -1250E ; [.4C46.0020.0002] -1250F ; [.4C47.0020.0002] -12510 ; [.4C48.0020.0002] -12511 ; [.4C49.0020.0002] -12512 ; [.4C4A.0020.0002] -12513 ; [.4C4B.0020.0002] -12514 ; [.4C4C.0020.0002] -12515 ; [.4C4D.0020.0002] -12516 ; [.4C4E.0020.0002] -12517 ; [.4C4F.0020.0002] -12518 ; [.4C50.0020.0002] -12519 ; [.4C51.0020.0002] -1251A ; [.4C52.0020.0002] -1251B ; [.4C53.0020.0002] -1251C ; [.4C54.0020.0002] -1251D ; [.4C55.0020.0002] -1251E ; [.4C56.0020.0002] -1251F ; [.4C57.0020.0002] -12520 ; [.4C58.0020.0002] -12521 ; [.4C59.0020.0002] -12522 ; [.4C5A.0020.0002] -12523 ; [.4C5B.0020.0002] -12524 ; [.4C5C.0020.0002] -12525 ; [.4C5D.0020.0002] -12526 ; [.4C5E.0020.0002] -12527 ; [.4C5F.0020.0002] -12528 ; [.4C60.0020.0002] -12529 ; [.4C61.0020.0002] -1252A ; [.4C62.0020.0002] -1252B ; [.4C63.0020.0002] -1252C ; [.4C64.0020.0002] -1252D ; [.4C65.0020.0002] -1252E ; [.4C66.0020.0002] -1252F ; [.4C67.0020.0002] -12530 ; [.4C68.0020.0002] -12531 ; [.4C69.0020.0002] -12532 ; [.4C6A.0020.0002] -12533 ; [.4C6B.0020.0002] -12534 ; [.4C6C.0020.0002] -12535 ; [.4C6D.0020.0002] -12536 ; [.4C6E.0020.0002] -12537 ; [.4C6F.0020.0002] -12538 ; [.4C70.0020.0002] -12539 ; [.4C71.0020.0002] -1253A ; [.4C72.0020.0002] -1253B ; [.4C73.0020.0002] -1253C ; [.4C74.0020.0002] -1253D ; [.4C75.0020.0002] -1253E ; [.4C76.0020.0002] -1253F ; [.4C77.0020.0002] -12540 ; [.4C78.0020.0002] -12541 ; [.4C79.0020.0002] -12542 ; [.4C7A.0020.0002] -12543 ; [.4C7B.0020.0002] -13000 ; [.4C7C.0020.0002] -13001 ; [.4C7D.0020.0002] -13002 ; [.4C7E.0020.0002] -13003 ; [.4C7F.0020.0002] -13004 ; [.4C80.0020.0002] -13005 ; [.4C81.0020.0002] -13006 ; [.4C82.0020.0002] -13007 ; [.4C83.0020.0002] -13008 ; [.4C84.0020.0002] -13009 ; [.4C85.0020.0002] -1300A ; [.4C86.0020.0002] -1300B ; [.4C87.0020.0002] -1300C ; [.4C88.0020.0002] -1300D ; [.4C89.0020.0002] -1300E ; [.4C8A.0020.0002] -1300F ; [.4C8B.0020.0002] -13010 ; [.4C8C.0020.0002] -13011 ; [.4C8D.0020.0002] -13012 ; [.4C8E.0020.0002] -13013 ; [.4C8F.0020.0002] -13014 ; [.4C90.0020.0002] -13015 ; [.4C91.0020.0002] -13016 ; [.4C92.0020.0002] -13017 ; [.4C93.0020.0002] -13018 ; [.4C94.0020.0002] -13019 ; [.4C95.0020.0002] -1301A ; [.4C96.0020.0002] -1301B ; [.4C97.0020.0002] -1301C ; [.4C98.0020.0002] -1301D ; [.4C99.0020.0002] -1301E ; [.4C9A.0020.0002] -1301F ; [.4C9B.0020.0002] -13020 ; [.4C9C.0020.0002] -13021 ; [.4C9D.0020.0002] -13022 ; [.4C9E.0020.0002] -13023 ; [.4C9F.0020.0002] -13024 ; [.4CA0.0020.0002] -13025 ; [.4CA1.0020.0002] -13026 ; [.4CA2.0020.0002] -13027 ; [.4CA3.0020.0002] -13028 ; [.4CA4.0020.0002] -13029 ; [.4CA5.0020.0002] -1302A ; [.4CA6.0020.0002] -1302B ; [.4CA7.0020.0002] -1302C ; [.4CA8.0020.0002] -1302D ; [.4CA9.0020.0002] -1302E ; [.4CAA.0020.0002] -1302F ; [.4CAB.0020.0002] -13030 ; [.4CAC.0020.0002] -13031 ; [.4CAD.0020.0002] -13032 ; [.4CAE.0020.0002] -13033 ; [.4CAF.0020.0002] -13034 ; [.4CB0.0020.0002] -13035 ; [.4CB1.0020.0002] -13036 ; [.4CB2.0020.0002] -13037 ; [.4CB3.0020.0002] -13038 ; [.4CB4.0020.0002] -13039 ; [.4CB5.0020.0002] -1303A ; [.4CB6.0020.0002] -1303B ; [.4CB7.0020.0002] -1303C ; [.4CB8.0020.0002] -1303D ; [.4CB9.0020.0002] -1303E ; [.4CBA.0020.0002] -1303F ; [.4CBB.0020.0002] -13040 ; [.4CBC.0020.0002] -13041 ; [.4CBD.0020.0002] -13042 ; [.4CBE.0020.0002] -13043 ; [.4CBF.0020.0002] -13044 ; [.4CC0.0020.0002] -13045 ; [.4CC1.0020.0002] -13046 ; [.4CC2.0020.0002] -13047 ; [.4CC3.0020.0002] -13048 ; [.4CC4.0020.0002] -13049 ; [.4CC5.0020.0002] -1304A ; [.4CC6.0020.0002] -1304B ; [.4CC7.0020.0002] -1304C ; [.4CC8.0020.0002] -1304D ; [.4CC9.0020.0002] -1304E ; [.4CCA.0020.0002] -1304F ; [.4CCB.0020.0002] -13050 ; [.4CCC.0020.0002] -13051 ; [.4CCD.0020.0002] -13052 ; [.4CCE.0020.0002] -13053 ; [.4CCF.0020.0002] -13054 ; [.4CD0.0020.0002] -13055 ; [.4CD1.0020.0002] -13056 ; [.4CD2.0020.0002] -13057 ; [.4CD3.0020.0002] -13058 ; [.4CD4.0020.0002] -13059 ; [.4CD5.0020.0002] -1305A ; [.4CD6.0020.0002] -1305B ; [.4CD7.0020.0002] -1305C ; [.4CD8.0020.0002] -1305D ; [.4CD9.0020.0002] -1305E ; [.4CDA.0020.0002] -1305F ; [.4CDB.0020.0002] -13060 ; [.4CDC.0020.0002] -13061 ; [.4CDD.0020.0002] -13062 ; [.4CDE.0020.0002] -13063 ; [.4CDF.0020.0002] -13064 ; [.4CE0.0020.0002] -13065 ; [.4CE1.0020.0002] -13066 ; [.4CE2.0020.0002] -13067 ; [.4CE3.0020.0002] -13068 ; [.4CE4.0020.0002] -13069 ; [.4CE5.0020.0002] -1306A ; [.4CE6.0020.0002] -1306B ; [.4CE7.0020.0002] -1306C ; [.4CE8.0020.0002] -1306D ; [.4CE9.0020.0002] -1306E ; [.4CEA.0020.0002] -1306F ; [.4CEB.0020.0002] -13070 ; [.4CEC.0020.0002] -13071 ; [.4CED.0020.0002] -13072 ; [.4CEE.0020.0002] -13073 ; [.4CEF.0020.0002] -13074 ; [.4CF0.0020.0002] -13075 ; [.4CF1.0020.0002] -13076 ; [.4CF2.0020.0002] -13077 ; [.4CF3.0020.0002] -13078 ; [.4CF4.0020.0002] -13079 ; [.4CF5.0020.0002] -1307A ; [.4CF6.0020.0002] -1307B ; [.4CF7.0020.0002] -1307C ; [.4CF8.0020.0002] -1307D ; [.4CF9.0020.0002] -1307E ; [.4CFA.0020.0002] -1307F ; [.4CFB.0020.0002] -13080 ; [.4CFC.0020.0002] -13081 ; [.4CFD.0020.0002] -13082 ; [.4CFE.0020.0002] -13083 ; [.4CFF.0020.0002] -13084 ; [.4D00.0020.0002] -13085 ; [.4D01.0020.0002] -13086 ; [.4D02.0020.0002] -13087 ; [.4D03.0020.0002] -13088 ; [.4D04.0020.0002] -13089 ; [.4D05.0020.0002] -1308A ; [.4D06.0020.0002] -1308B ; [.4D07.0020.0002] -1308C ; [.4D08.0020.0002] -1308D ; [.4D09.0020.0002] -1308E ; [.4D0A.0020.0002] -1308F ; [.4D0B.0020.0002] -13090 ; [.4D0C.0020.0002] -13091 ; [.4D0D.0020.0002] -13092 ; [.4D0E.0020.0002] -13093 ; [.4D0F.0020.0002] -13094 ; [.4D10.0020.0002] -13095 ; [.4D11.0020.0002] -13096 ; [.4D12.0020.0002] -13097 ; [.4D13.0020.0002] -13098 ; [.4D14.0020.0002] -13099 ; [.4D15.0020.0002] -1309A ; [.4D16.0020.0002] -1309B ; [.4D17.0020.0002] -1309C ; [.4D18.0020.0002] -1309D ; [.4D19.0020.0002] -1309E ; [.4D1A.0020.0002] -1309F ; [.4D1B.0020.0002] -130A0 ; [.4D1C.0020.0002] -130A1 ; [.4D1D.0020.0002] -130A2 ; [.4D1E.0020.0002] -130A3 ; [.4D1F.0020.0002] -130A4 ; [.4D20.0020.0002] -130A5 ; [.4D21.0020.0002] -130A6 ; [.4D22.0020.0002] -130A7 ; [.4D23.0020.0002] -130A8 ; [.4D24.0020.0002] -130A9 ; [.4D25.0020.0002] -130AA ; [.4D26.0020.0002] -130AB ; [.4D27.0020.0002] -130AC ; [.4D28.0020.0002] -130AD ; [.4D29.0020.0002] -130AE ; [.4D2A.0020.0002] -130AF ; [.4D2B.0020.0002] -130B0 ; [.4D2C.0020.0002] -130B1 ; [.4D2D.0020.0002] -130B2 ; [.4D2E.0020.0002] -130B3 ; [.4D2F.0020.0002] -130B4 ; [.4D30.0020.0002] -130B5 ; [.4D31.0020.0002] -130B6 ; [.4D32.0020.0002] -130B7 ; [.4D33.0020.0002] -130B8 ; [.4D34.0020.0002] -130B9 ; [.4D35.0020.0002] -130BA ; [.4D36.0020.0002] -130BB ; [.4D37.0020.0002] -130BC ; [.4D38.0020.0002] -130BD ; [.4D39.0020.0002] -130BE ; [.4D3A.0020.0002] -130BF ; [.4D3B.0020.0002] -130C0 ; [.4D3C.0020.0002] -130C1 ; [.4D3D.0020.0002] -130C2 ; [.4D3E.0020.0002] -130C3 ; [.4D3F.0020.0002] -130C4 ; [.4D40.0020.0002] -130C5 ; [.4D41.0020.0002] -130C6 ; [.4D42.0020.0002] -130C7 ; [.4D43.0020.0002] -130C8 ; [.4D44.0020.0002] -130C9 ; [.4D45.0020.0002] -130CA ; [.4D46.0020.0002] -130CB ; [.4D47.0020.0002] -130CC ; [.4D48.0020.0002] -130CD ; [.4D49.0020.0002] -130CE ; [.4D4A.0020.0002] -130CF ; [.4D4B.0020.0002] -130D0 ; [.4D4C.0020.0002] -130D1 ; [.4D4D.0020.0002] -130D2 ; [.4D4E.0020.0002] -130D3 ; [.4D4F.0020.0002] -130D4 ; [.4D50.0020.0002] -130D5 ; [.4D51.0020.0002] -130D6 ; [.4D52.0020.0002] -130D7 ; [.4D53.0020.0002] -130D8 ; [.4D54.0020.0002] -130D9 ; [.4D55.0020.0002] -130DA ; [.4D56.0020.0002] -130DB ; [.4D57.0020.0002] -130DC ; [.4D58.0020.0002] -130DD ; [.4D59.0020.0002] -130DE ; [.4D5A.0020.0002] -130DF ; [.4D5B.0020.0002] -130E0 ; [.4D5C.0020.0002] -130E1 ; [.4D5D.0020.0002] -130E2 ; [.4D5E.0020.0002] -130E3 ; [.4D5F.0020.0002] -130E4 ; [.4D60.0020.0002] -130E5 ; [.4D61.0020.0002] -130E6 ; [.4D62.0020.0002] -130E7 ; [.4D63.0020.0002] -130E8 ; [.4D64.0020.0002] -130E9 ; [.4D65.0020.0002] -130EA ; [.4D66.0020.0002] -130EB ; [.4D67.0020.0002] -130EC ; [.4D68.0020.0002] -130ED ; [.4D69.0020.0002] -130EE ; [.4D6A.0020.0002] -130EF ; [.4D6B.0020.0002] -130F0 ; [.4D6C.0020.0002] -130F1 ; [.4D6D.0020.0002] -130F2 ; [.4D6E.0020.0002] -130F3 ; [.4D6F.0020.0002] -130F4 ; [.4D70.0020.0002] -130F5 ; [.4D71.0020.0002] -130F6 ; [.4D72.0020.0002] -130F7 ; [.4D73.0020.0002] -130F8 ; [.4D74.0020.0002] -130F9 ; [.4D75.0020.0002] -130FA ; [.4D76.0020.0002] -130FB ; [.4D77.0020.0002] -130FC ; [.4D78.0020.0002] -130FD ; [.4D79.0020.0002] -130FE ; [.4D7A.0020.0002] -130FF ; [.4D7B.0020.0002] -13100 ; [.4D7C.0020.0002] -13101 ; [.4D7D.0020.0002] -13102 ; [.4D7E.0020.0002] -13103 ; [.4D7F.0020.0002] -13104 ; [.4D80.0020.0002] -13105 ; [.4D81.0020.0002] -13106 ; [.4D82.0020.0002] -13107 ; [.4D83.0020.0002] -13108 ; [.4D84.0020.0002] -13109 ; [.4D85.0020.0002] -1310A ; [.4D86.0020.0002] -1310B ; [.4D87.0020.0002] -1310C ; [.4D88.0020.0002] -1310D ; [.4D89.0020.0002] -1310E ; [.4D8A.0020.0002] -1310F ; [.4D8B.0020.0002] -13110 ; [.4D8C.0020.0002] -13111 ; [.4D8D.0020.0002] -13112 ; [.4D8E.0020.0002] -13113 ; [.4D8F.0020.0002] -13114 ; [.4D90.0020.0002] -13115 ; [.4D91.0020.0002] -13116 ; [.4D92.0020.0002] -13117 ; [.4D93.0020.0002] -13118 ; [.4D94.0020.0002] -13119 ; [.4D95.0020.0002] -1311A ; [.4D96.0020.0002] -1311B ; [.4D97.0020.0002] -1311C ; [.4D98.0020.0002] -1311D ; [.4D99.0020.0002] -1311E ; [.4D9A.0020.0002] -1311F ; [.4D9B.0020.0002] -13120 ; [.4D9C.0020.0002] -13121 ; [.4D9D.0020.0002] -13122 ; [.4D9E.0020.0002] -13123 ; [.4D9F.0020.0002] -13124 ; [.4DA0.0020.0002] -13125 ; [.4DA1.0020.0002] -13126 ; [.4DA2.0020.0002] -13127 ; [.4DA3.0020.0002] -13128 ; [.4DA4.0020.0002] -13129 ; [.4DA5.0020.0002] -1312A ; [.4DA6.0020.0002] -1312B ; [.4DA7.0020.0002] -1312C ; [.4DA8.0020.0002] -1312D ; [.4DA9.0020.0002] -1312E ; [.4DAA.0020.0002] -1312F ; [.4DAB.0020.0002] -13130 ; [.4DAC.0020.0002] -13131 ; [.4DAD.0020.0002] -13132 ; [.4DAE.0020.0002] -13133 ; [.4DAF.0020.0002] -13134 ; [.4DB0.0020.0002] -13135 ; [.4DB1.0020.0002] -13136 ; [.4DB2.0020.0002] -13137 ; [.4DB3.0020.0002] -13138 ; [.4DB4.0020.0002] -13139 ; [.4DB5.0020.0002] -1313A ; [.4DB6.0020.0002] -1313B ; [.4DB7.0020.0002] -1313C ; [.4DB8.0020.0002] -1313D ; [.4DB9.0020.0002] -1313E ; [.4DBA.0020.0002] -1313F ; [.4DBB.0020.0002] -13140 ; [.4DBC.0020.0002] -13141 ; [.4DBD.0020.0002] -13142 ; [.4DBE.0020.0002] -13143 ; [.4DBF.0020.0002] -13144 ; [.4DC0.0020.0002] -13145 ; [.4DC1.0020.0002] -13146 ; [.4DC2.0020.0002] -13147 ; [.4DC3.0020.0002] -13148 ; [.4DC4.0020.0002] -13149 ; [.4DC5.0020.0002] -1314A ; [.4DC6.0020.0002] -1314B ; [.4DC7.0020.0002] -1314C ; [.4DC8.0020.0002] -1314D ; [.4DC9.0020.0002] -1314E ; [.4DCA.0020.0002] -1314F ; [.4DCB.0020.0002] -13150 ; [.4DCC.0020.0002] -13151 ; [.4DCD.0020.0002] -13152 ; [.4DCE.0020.0002] -13153 ; [.4DCF.0020.0002] -13154 ; [.4DD0.0020.0002] -13155 ; [.4DD1.0020.0002] -13156 ; [.4DD2.0020.0002] -13157 ; [.4DD3.0020.0002] -13158 ; [.4DD4.0020.0002] -13159 ; [.4DD5.0020.0002] -1315A ; [.4DD6.0020.0002] -1315B ; [.4DD7.0020.0002] -1315C ; [.4DD8.0020.0002] -1315D ; [.4DD9.0020.0002] -1315E ; [.4DDA.0020.0002] -1315F ; [.4DDB.0020.0002] -13160 ; [.4DDC.0020.0002] -13161 ; [.4DDD.0020.0002] -13162 ; [.4DDE.0020.0002] -13163 ; [.4DDF.0020.0002] -13164 ; [.4DE0.0020.0002] -13165 ; [.4DE1.0020.0002] -13166 ; [.4DE2.0020.0002] -13167 ; [.4DE3.0020.0002] -13168 ; [.4DE4.0020.0002] -13169 ; [.4DE5.0020.0002] -1316A ; [.4DE6.0020.0002] -1316B ; [.4DE7.0020.0002] -1316C ; [.4DE8.0020.0002] -1316D ; [.4DE9.0020.0002] -1316E ; [.4DEA.0020.0002] -1316F ; [.4DEB.0020.0002] -13170 ; [.4DEC.0020.0002] -13171 ; [.4DED.0020.0002] -13172 ; [.4DEE.0020.0002] -13173 ; [.4DEF.0020.0002] -13174 ; [.4DF0.0020.0002] -13175 ; [.4DF1.0020.0002] -13176 ; [.4DF2.0020.0002] -13177 ; [.4DF3.0020.0002] -13178 ; [.4DF4.0020.0002] -13179 ; [.4DF5.0020.0002] -1317A ; [.4DF6.0020.0002] -1317B ; [.4DF7.0020.0002] -1317C ; [.4DF8.0020.0002] -1317D ; [.4DF9.0020.0002] -1317E ; [.4DFA.0020.0002] -1317F ; [.4DFB.0020.0002] -13180 ; [.4DFC.0020.0002] -13181 ; [.4DFD.0020.0002] -13182 ; [.4DFE.0020.0002] -13183 ; [.4DFF.0020.0002] -13184 ; [.4E00.0020.0002] -13185 ; [.4E01.0020.0002] -13186 ; [.4E02.0020.0002] -13187 ; [.4E03.0020.0002] -13188 ; [.4E04.0020.0002] -13189 ; [.4E05.0020.0002] -1318A ; [.4E06.0020.0002] -1318B ; [.4E07.0020.0002] -1318C ; [.4E08.0020.0002] -1318D ; [.4E09.0020.0002] -1318E ; [.4E0A.0020.0002] -1318F ; [.4E0B.0020.0002] -13190 ; [.4E0C.0020.0002] -13191 ; [.4E0D.0020.0002] -13192 ; [.4E0E.0020.0002] -13193 ; [.4E0F.0020.0002] -13194 ; [.4E10.0020.0002] -13195 ; [.4E11.0020.0002] -13196 ; [.4E12.0020.0002] -13197 ; [.4E13.0020.0002] -13198 ; [.4E14.0020.0002] -13199 ; [.4E15.0020.0002] -1319A ; [.4E16.0020.0002] -1319B ; [.4E17.0020.0002] -1319C ; [.4E18.0020.0002] -1319D ; [.4E19.0020.0002] -1319E ; [.4E1A.0020.0002] -1319F ; [.4E1B.0020.0002] -131A0 ; [.4E1C.0020.0002] -131A1 ; [.4E1D.0020.0002] -131A2 ; [.4E1E.0020.0002] -131A3 ; [.4E1F.0020.0002] -131A4 ; [.4E20.0020.0002] -131A5 ; [.4E21.0020.0002] -131A6 ; [.4E22.0020.0002] -131A7 ; [.4E23.0020.0002] -131A8 ; [.4E24.0020.0002] -131A9 ; [.4E25.0020.0002] -131AA ; [.4E26.0020.0002] -131AB ; [.4E27.0020.0002] -131AC ; [.4E28.0020.0002] -131AD ; [.4E29.0020.0002] -131AE ; [.4E2A.0020.0002] -131AF ; [.4E2B.0020.0002] -131B0 ; [.4E2C.0020.0002] -131B1 ; [.4E2D.0020.0002] -131B2 ; [.4E2E.0020.0002] -131B3 ; [.4E2F.0020.0002] -131B4 ; [.4E30.0020.0002] -131B5 ; [.4E31.0020.0002] -131B6 ; [.4E32.0020.0002] -131B7 ; [.4E33.0020.0002] -131B8 ; [.4E34.0020.0002] -131B9 ; [.4E35.0020.0002] -131BA ; [.4E36.0020.0002] -131BB ; [.4E37.0020.0002] -131BC ; [.4E38.0020.0002] -131BD ; [.4E39.0020.0002] -131BE ; [.4E3A.0020.0002] -131BF ; [.4E3B.0020.0002] -131C0 ; [.4E3C.0020.0002] -131C1 ; [.4E3D.0020.0002] -131C2 ; [.4E3E.0020.0002] -131C3 ; [.4E3F.0020.0002] -131C4 ; [.4E40.0020.0002] -131C5 ; [.4E41.0020.0002] -131C6 ; [.4E42.0020.0002] -131C7 ; [.4E43.0020.0002] -131C8 ; [.4E44.0020.0002] -131C9 ; [.4E45.0020.0002] -131CA ; [.4E46.0020.0002] -131CB ; [.4E47.0020.0002] -131CC ; [.4E48.0020.0002] -131CD ; [.4E49.0020.0002] -131CE ; [.4E4A.0020.0002] -131CF ; [.4E4B.0020.0002] -131D0 ; [.4E4C.0020.0002] -131D1 ; [.4E4D.0020.0002] -131D2 ; [.4E4E.0020.0002] -131D3 ; [.4E4F.0020.0002] -131D4 ; [.4E50.0020.0002] -131D5 ; [.4E51.0020.0002] -131D6 ; [.4E52.0020.0002] -131D7 ; [.4E53.0020.0002] -131D8 ; [.4E54.0020.0002] -131D9 ; [.4E55.0020.0002] -131DA ; [.4E56.0020.0002] -131DB ; [.4E57.0020.0002] -131DC ; [.4E58.0020.0002] -131DD ; [.4E59.0020.0002] -131DE ; [.4E5A.0020.0002] -131DF ; [.4E5B.0020.0002] -131E0 ; [.4E5C.0020.0002] -131E1 ; [.4E5D.0020.0002] -131E2 ; [.4E5E.0020.0002] -131E3 ; [.4E5F.0020.0002] -131E4 ; [.4E60.0020.0002] -131E5 ; [.4E61.0020.0002] -131E6 ; [.4E62.0020.0002] -131E7 ; [.4E63.0020.0002] -131E8 ; [.4E64.0020.0002] -131E9 ; [.4E65.0020.0002] -131EA ; [.4E66.0020.0002] -131EB ; [.4E67.0020.0002] -131EC ; [.4E68.0020.0002] -131ED ; [.4E69.0020.0002] -131EE ; [.4E6A.0020.0002] -131EF ; [.4E6B.0020.0002] -131F0 ; [.4E6C.0020.0002] -131F1 ; [.4E6D.0020.0002] -131F2 ; [.4E6E.0020.0002] -131F3 ; [.4E6F.0020.0002] -131F4 ; [.4E70.0020.0002] -131F5 ; [.4E71.0020.0002] -131F6 ; [.4E72.0020.0002] -131F7 ; [.4E73.0020.0002] -131F8 ; [.4E74.0020.0002] -131F9 ; [.4E75.0020.0002] -131FA ; [.4E76.0020.0002] -131FB ; [.4E77.0020.0002] -131FC ; [.4E78.0020.0002] -131FD ; [.4E79.0020.0002] -131FE ; [.4E7A.0020.0002] -131FF ; [.4E7B.0020.0002] -13200 ; [.4E7C.0020.0002] -13201 ; [.4E7D.0020.0002] -13202 ; [.4E7E.0020.0002] -13203 ; [.4E7F.0020.0002] -13204 ; [.4E80.0020.0002] -13205 ; [.4E81.0020.0002] -13206 ; [.4E82.0020.0002] -13207 ; [.4E83.0020.0002] -13208 ; [.4E84.0020.0002] -13209 ; [.4E85.0020.0002] -1320A ; [.4E86.0020.0002] -1320B ; [.4E87.0020.0002] -1320C ; [.4E88.0020.0002] -1320D ; [.4E89.0020.0002] -1320E ; [.4E8A.0020.0002] -1320F ; [.4E8B.0020.0002] -13210 ; [.4E8C.0020.0002] -13211 ; [.4E8D.0020.0002] -13212 ; [.4E8E.0020.0002] -13213 ; [.4E8F.0020.0002] -13214 ; [.4E90.0020.0002] -13215 ; [.4E91.0020.0002] -13216 ; [.4E92.0020.0002] -13217 ; [.4E93.0020.0002] -13218 ; [.4E94.0020.0002] -13219 ; [.4E95.0020.0002] -1321A ; [.4E96.0020.0002] -1321B ; [.4E97.0020.0002] -1321C ; [.4E98.0020.0002] -1321D ; [.4E99.0020.0002] -1321E ; [.4E9A.0020.0002] -1321F ; [.4E9B.0020.0002] -13220 ; [.4E9C.0020.0002] -13221 ; [.4E9D.0020.0002] -13222 ; [.4E9E.0020.0002] -13223 ; [.4E9F.0020.0002] -13224 ; [.4EA0.0020.0002] -13225 ; [.4EA1.0020.0002] -13226 ; [.4EA2.0020.0002] -13227 ; [.4EA3.0020.0002] -13228 ; [.4EA4.0020.0002] -13229 ; [.4EA5.0020.0002] -1322A ; [.4EA6.0020.0002] -1322B ; [.4EA7.0020.0002] -1322C ; [.4EA8.0020.0002] -1322D ; [.4EA9.0020.0002] -1322E ; [.4EAA.0020.0002] -1322F ; [.4EAB.0020.0002] -13230 ; [.4EAC.0020.0002] -13231 ; [.4EAD.0020.0002] -13232 ; [.4EAE.0020.0002] -13233 ; [.4EAF.0020.0002] -13234 ; [.4EB0.0020.0002] -13235 ; [.4EB1.0020.0002] -13236 ; [.4EB2.0020.0002] -13237 ; [.4EB3.0020.0002] -13238 ; [.4EB4.0020.0002] -13239 ; [.4EB5.0020.0002] -1323A ; [.4EB6.0020.0002] -1323B ; [.4EB7.0020.0002] -1323C ; [.4EB8.0020.0002] -1323D ; [.4EB9.0020.0002] -1323E ; [.4EBA.0020.0002] -1323F ; [.4EBB.0020.0002] -13240 ; [.4EBC.0020.0002] -13241 ; [.4EBD.0020.0002] -13242 ; [.4EBE.0020.0002] -13243 ; [.4EBF.0020.0002] -13244 ; [.4EC0.0020.0002] -13245 ; [.4EC1.0020.0002] -13246 ; [.4EC2.0020.0002] -13247 ; [.4EC3.0020.0002] -13248 ; [.4EC4.0020.0002] -13249 ; [.4EC5.0020.0002] -1324A ; [.4EC6.0020.0002] -1324B ; [.4EC7.0020.0002] -1324C ; [.4EC8.0020.0002] -1324D ; [.4EC9.0020.0002] -1324E ; [.4ECA.0020.0002] -1324F ; [.4ECB.0020.0002] -13250 ; [.4ECC.0020.0002] -13251 ; [.4ECD.0020.0002] -13252 ; [.4ECE.0020.0002] -13253 ; [.4ECF.0020.0002] -13254 ; [.4ED0.0020.0002] -13255 ; [.4ED1.0020.0002] -13256 ; [.4ED2.0020.0002] -13257 ; [.4ED3.0020.0002] -13258 ; [.4ED4.0020.0002] -13259 ; [.4ED5.0020.0002] -1325A ; [.4ED6.0020.0002] -1325B ; [.4ED7.0020.0002] -1325C ; [.4ED8.0020.0002] -1325D ; [.4ED9.0020.0002] -1325E ; [.4EDA.0020.0002] -1325F ; [.4EDB.0020.0002] -13260 ; [.4EDC.0020.0002] -13261 ; [.4EDD.0020.0002] -13262 ; [.4EDE.0020.0002] -13263 ; [.4EDF.0020.0002] -13264 ; [.4EE0.0020.0002] -13265 ; [.4EE1.0020.0002] -13266 ; [.4EE2.0020.0002] -13267 ; [.4EE3.0020.0002] -13268 ; [.4EE4.0020.0002] -13269 ; [.4EE5.0020.0002] -1326A ; [.4EE6.0020.0002] -1326B ; [.4EE7.0020.0002] -1326C ; [.4EE8.0020.0002] -1326D ; [.4EE9.0020.0002] -1326E ; [.4EEA.0020.0002] -1326F ; [.4EEB.0020.0002] -13270 ; [.4EEC.0020.0002] -13271 ; [.4EED.0020.0002] -13272 ; [.4EEE.0020.0002] -13273 ; [.4EEF.0020.0002] -13274 ; [.4EF0.0020.0002] -13275 ; [.4EF1.0020.0002] -13276 ; [.4EF2.0020.0002] -13277 ; [.4EF3.0020.0002] -13278 ; [.4EF4.0020.0002] -13279 ; [.4EF5.0020.0002] -1327A ; [.4EF6.0020.0002] -1327B ; [.4EF7.0020.0002] -1327C ; [.4EF8.0020.0002] -1327D ; [.4EF9.0020.0002] -1327E ; [.4EFA.0020.0002] -1327F ; [.4EFB.0020.0002] -13280 ; [.4EFC.0020.0002] -13281 ; [.4EFD.0020.0002] -13282 ; [.4EFE.0020.0002] -13283 ; [.4EFF.0020.0002] -13284 ; [.4F00.0020.0002] -13285 ; [.4F01.0020.0002] -13286 ; [.4F02.0020.0002] -13287 ; [.4F03.0020.0002] -13288 ; [.4F04.0020.0002] -13289 ; [.4F05.0020.0002] -1328A ; [.4F06.0020.0002] -1328B ; [.4F07.0020.0002] -1328C ; [.4F08.0020.0002] -1328D ; [.4F09.0020.0002] -1328E ; [.4F0A.0020.0002] -1328F ; [.4F0B.0020.0002] -13290 ; [.4F0C.0020.0002] -13291 ; [.4F0D.0020.0002] -13292 ; [.4F0E.0020.0002] -13293 ; [.4F0F.0020.0002] -13294 ; [.4F10.0020.0002] -13295 ; [.4F11.0020.0002] -13296 ; [.4F12.0020.0002] -13297 ; [.4F13.0020.0002] -13298 ; [.4F14.0020.0002] -13299 ; [.4F15.0020.0002] -1329A ; [.4F16.0020.0002] -1329B ; [.4F17.0020.0002] -1329C ; [.4F18.0020.0002] -1329D ; [.4F19.0020.0002] -1329E ; [.4F1A.0020.0002] -1329F ; [.4F1B.0020.0002] -132A0 ; [.4F1C.0020.0002] -132A1 ; [.4F1D.0020.0002] -132A2 ; [.4F1E.0020.0002] -132A3 ; [.4F1F.0020.0002] -132A4 ; [.4F20.0020.0002] -132A5 ; [.4F21.0020.0002] -132A6 ; [.4F22.0020.0002] -132A7 ; [.4F23.0020.0002] -132A8 ; [.4F24.0020.0002] -132A9 ; [.4F25.0020.0002] -132AA ; [.4F26.0020.0002] -132AB ; [.4F27.0020.0002] -132AC ; [.4F28.0020.0002] -132AD ; [.4F29.0020.0002] -132AE ; [.4F2A.0020.0002] -132AF ; [.4F2B.0020.0002] -132B0 ; [.4F2C.0020.0002] -132B1 ; [.4F2D.0020.0002] -132B2 ; [.4F2E.0020.0002] -132B3 ; [.4F2F.0020.0002] -132B4 ; [.4F30.0020.0002] -132B5 ; [.4F31.0020.0002] -132B6 ; [.4F32.0020.0002] -132B7 ; [.4F33.0020.0002] -132B8 ; [.4F34.0020.0002] -132B9 ; [.4F35.0020.0002] -132BA ; [.4F36.0020.0002] -132BB ; [.4F37.0020.0002] -132BC ; [.4F38.0020.0002] -132BD ; [.4F39.0020.0002] -132BE ; [.4F3A.0020.0002] -132BF ; [.4F3B.0020.0002] -132C0 ; [.4F3C.0020.0002] -132C1 ; [.4F3D.0020.0002] -132C2 ; [.4F3E.0020.0002] -132C3 ; [.4F3F.0020.0002] -132C4 ; [.4F40.0020.0002] -132C5 ; [.4F41.0020.0002] -132C6 ; [.4F42.0020.0002] -132C7 ; [.4F43.0020.0002] -132C8 ; [.4F44.0020.0002] -132C9 ; [.4F45.0020.0002] -132CA ; [.4F46.0020.0002] -132CB ; [.4F47.0020.0002] -132CC ; [.4F48.0020.0002] -132CD ; [.4F49.0020.0002] -132CE ; [.4F4A.0020.0002] -132CF ; [.4F4B.0020.0002] -132D0 ; [.4F4C.0020.0002] -132D1 ; [.4F4D.0020.0002] -132D2 ; [.4F4E.0020.0002] -132D3 ; [.4F4F.0020.0002] -132D4 ; [.4F50.0020.0002] -132D5 ; [.4F51.0020.0002] -132D6 ; [.4F52.0020.0002] -132D7 ; [.4F53.0020.0002] -132D8 ; [.4F54.0020.0002] -132D9 ; [.4F55.0020.0002] -132DA ; [.4F56.0020.0002] -132DB ; [.4F57.0020.0002] -132DC ; [.4F58.0020.0002] -132DD ; [.4F59.0020.0002] -132DE ; [.4F5A.0020.0002] -132DF ; [.4F5B.0020.0002] -132E0 ; [.4F5C.0020.0002] -132E1 ; [.4F5D.0020.0002] -132E2 ; [.4F5E.0020.0002] -132E3 ; [.4F5F.0020.0002] -132E4 ; [.4F60.0020.0002] -132E5 ; [.4F61.0020.0002] -132E6 ; [.4F62.0020.0002] -132E7 ; [.4F63.0020.0002] -132E8 ; [.4F64.0020.0002] -132E9 ; [.4F65.0020.0002] -132EA ; [.4F66.0020.0002] -132EB ; [.4F67.0020.0002] -132EC ; [.4F68.0020.0002] -132ED ; [.4F69.0020.0002] -132EE ; [.4F6A.0020.0002] -132EF ; [.4F6B.0020.0002] -132F0 ; [.4F6C.0020.0002] -132F1 ; [.4F6D.0020.0002] -132F2 ; [.4F6E.0020.0002] -132F3 ; [.4F6F.0020.0002] -132F4 ; [.4F70.0020.0002] -132F5 ; [.4F71.0020.0002] -132F6 ; [.4F72.0020.0002] -132F7 ; [.4F73.0020.0002] -132F8 ; [.4F74.0020.0002] -132F9 ; [.4F75.0020.0002] -132FA ; [.4F76.0020.0002] -132FB ; [.4F77.0020.0002] -132FC ; [.4F78.0020.0002] -132FD ; [.4F79.0020.0002] -132FE ; [.4F7A.0020.0002] -132FF ; [.4F7B.0020.0002] -13300 ; [.4F7C.0020.0002] -13301 ; [.4F7D.0020.0002] -13302 ; [.4F7E.0020.0002] -13303 ; [.4F7F.0020.0002] -13304 ; [.4F80.0020.0002] -13305 ; [.4F81.0020.0002] -13306 ; [.4F82.0020.0002] -13307 ; [.4F83.0020.0002] -13308 ; [.4F84.0020.0002] -13309 ; [.4F85.0020.0002] -1330A ; [.4F86.0020.0002] -1330B ; [.4F87.0020.0002] -1330C ; [.4F88.0020.0002] -1330D ; [.4F89.0020.0002] -1330E ; [.4F8A.0020.0002] -1330F ; [.4F8B.0020.0002] -13310 ; [.4F8C.0020.0002] -13311 ; [.4F8D.0020.0002] -13312 ; [.4F8E.0020.0002] -13313 ; [.4F8F.0020.0002] -13314 ; [.4F90.0020.0002] -13315 ; [.4F91.0020.0002] -13316 ; [.4F92.0020.0002] -13317 ; [.4F93.0020.0002] -13318 ; [.4F94.0020.0002] -13319 ; [.4F95.0020.0002] -1331A ; [.4F96.0020.0002] -1331B ; [.4F97.0020.0002] -1331C ; [.4F98.0020.0002] -1331D ; [.4F99.0020.0002] -1331E ; [.4F9A.0020.0002] -1331F ; [.4F9B.0020.0002] -13320 ; [.4F9C.0020.0002] -13321 ; [.4F9D.0020.0002] -13322 ; [.4F9E.0020.0002] -13323 ; [.4F9F.0020.0002] -13324 ; [.4FA0.0020.0002] -13325 ; [.4FA1.0020.0002] -13326 ; [.4FA2.0020.0002] -13327 ; [.4FA3.0020.0002] -13328 ; [.4FA4.0020.0002] -13329 ; [.4FA5.0020.0002] -1332A ; [.4FA6.0020.0002] -1332B ; [.4FA7.0020.0002] -1332C ; [.4FA8.0020.0002] -1332D ; [.4FA9.0020.0002] -1332E ; [.4FAA.0020.0002] -1332F ; [.4FAB.0020.0002] -13330 ; [.4FAC.0020.0002] -13331 ; [.4FAD.0020.0002] -13332 ; [.4FAE.0020.0002] -13333 ; [.4FAF.0020.0002] -13334 ; [.4FB0.0020.0002] -13335 ; [.4FB1.0020.0002] -13336 ; [.4FB2.0020.0002] -13337 ; [.4FB3.0020.0002] -13338 ; [.4FB4.0020.0002] -13339 ; [.4FB5.0020.0002] -1333A ; [.4FB6.0020.0002] -1333B ; [.4FB7.0020.0002] -1333C ; [.4FB8.0020.0002] -1333D ; [.4FB9.0020.0002] -1333E ; [.4FBA.0020.0002] -1333F ; [.4FBB.0020.0002] -13340 ; [.4FBC.0020.0002] -13341 ; [.4FBD.0020.0002] -13342 ; [.4FBE.0020.0002] -13343 ; [.4FBF.0020.0002] -13344 ; [.4FC0.0020.0002] -13345 ; [.4FC1.0020.0002] -13346 ; [.4FC2.0020.0002] -13347 ; [.4FC3.0020.0002] -13348 ; [.4FC4.0020.0002] -13349 ; [.4FC5.0020.0002] -1334A ; [.4FC6.0020.0002] -1334B ; [.4FC7.0020.0002] -1334C ; [.4FC8.0020.0002] -1334D ; [.4FC9.0020.0002] -1334E ; [.4FCA.0020.0002] -1334F ; [.4FCB.0020.0002] -13350 ; [.4FCC.0020.0002] -13351 ; [.4FCD.0020.0002] -13352 ; [.4FCE.0020.0002] -13353 ; [.4FCF.0020.0002] -13354 ; [.4FD0.0020.0002] -13355 ; [.4FD1.0020.0002] -13356 ; [.4FD2.0020.0002] -13357 ; [.4FD3.0020.0002] -13358 ; [.4FD4.0020.0002] -13359 ; [.4FD5.0020.0002] -1335A ; [.4FD6.0020.0002] -1335B ; [.4FD7.0020.0002] -1335C ; [.4FD8.0020.0002] -1335D ; [.4FD9.0020.0002] -1335E ; [.4FDA.0020.0002] -1335F ; [.4FDB.0020.0002] -13360 ; [.4FDC.0020.0002] -13361 ; [.4FDD.0020.0002] -13362 ; [.4FDE.0020.0002] -13363 ; [.4FDF.0020.0002] -13364 ; [.4FE0.0020.0002] -13365 ; [.4FE1.0020.0002] -13366 ; [.4FE2.0020.0002] -13367 ; [.4FE3.0020.0002] -13368 ; [.4FE4.0020.0002] -13369 ; [.4FE5.0020.0002] -1336A ; [.4FE6.0020.0002] -1336B ; [.4FE7.0020.0002] -1336C ; [.4FE8.0020.0002] -1336D ; [.4FE9.0020.0002] -1336E ; [.4FEA.0020.0002] -1336F ; [.4FEB.0020.0002] -13370 ; [.4FEC.0020.0002] -13371 ; [.4FED.0020.0002] -13372 ; [.4FEE.0020.0002] -13373 ; [.4FEF.0020.0002] -13374 ; [.4FF0.0020.0002] -13375 ; [.4FF1.0020.0002] -13376 ; [.4FF2.0020.0002] -13377 ; [.4FF3.0020.0002] -13378 ; [.4FF4.0020.0002] -13379 ; [.4FF5.0020.0002] -1337A ; [.4FF6.0020.0002] -1337B ; [.4FF7.0020.0002] -1337C ; [.4FF8.0020.0002] -1337D ; [.4FF9.0020.0002] -1337E ; [.4FFA.0020.0002] -1337F ; [.4FFB.0020.0002] -13380 ; [.4FFC.0020.0002] -13381 ; [.4FFD.0020.0002] -13382 ; [.4FFE.0020.0002] -13383 ; [.4FFF.0020.0002] -13384 ; [.5000.0020.0002] -13385 ; [.5001.0020.0002] -13386 ; [.5002.0020.0002] -13387 ; [.5003.0020.0002] -13388 ; [.5004.0020.0002] -13389 ; [.5005.0020.0002] -1338A ; [.5006.0020.0002] -1338B ; [.5007.0020.0002] -1338C ; [.5008.0020.0002] -1338D ; [.5009.0020.0002] -1338E ; [.500A.0020.0002] -1338F ; [.500B.0020.0002] -13390 ; [.500C.0020.0002] -13391 ; [.500D.0020.0002] -13392 ; [.500E.0020.0002] -13393 ; [.500F.0020.0002] -13394 ; [.5010.0020.0002] -13395 ; [.5011.0020.0002] -13396 ; [.5012.0020.0002] -13397 ; [.5013.0020.0002] -13398 ; [.5014.0020.0002] -13399 ; [.5015.0020.0002] -1339A ; [.5016.0020.0002] -1339B ; [.5017.0020.0002] -1339C ; [.5018.0020.0002] -1339D ; [.5019.0020.0002] -1339E ; [.501A.0020.0002] -1339F ; [.501B.0020.0002] -133A0 ; [.501C.0020.0002] -133A1 ; [.501D.0020.0002] -133A2 ; [.501E.0020.0002] -133A3 ; [.501F.0020.0002] -133A4 ; [.5020.0020.0002] -133A5 ; [.5021.0020.0002] -133A6 ; [.5022.0020.0002] -133A7 ; [.5023.0020.0002] -133A8 ; [.5024.0020.0002] -133A9 ; [.5025.0020.0002] -133AA ; [.5026.0020.0002] -133AB ; [.5027.0020.0002] -133AC ; [.5028.0020.0002] -133AD ; [.5029.0020.0002] -133AE ; [.502A.0020.0002] -133AF ; [.502B.0020.0002] -133B0 ; [.502C.0020.0002] -133B1 ; [.502D.0020.0002] -133B2 ; [.502E.0020.0002] -133B3 ; [.502F.0020.0002] -133B4 ; [.5030.0020.0002] -133B5 ; [.5031.0020.0002] -133B6 ; [.5032.0020.0002] -133B7 ; [.5033.0020.0002] -133B8 ; [.5034.0020.0002] -133B9 ; [.5035.0020.0002] -133BA ; [.5036.0020.0002] -133BB ; [.5037.0020.0002] -133BC ; [.5038.0020.0002] -133BD ; [.5039.0020.0002] -133BE ; [.503A.0020.0002] -133BF ; [.503B.0020.0002] -133C0 ; [.503C.0020.0002] -133C1 ; [.503D.0020.0002] -133C2 ; [.503E.0020.0002] -133C3 ; [.503F.0020.0002] -133C4 ; [.5040.0020.0002] -133C5 ; [.5041.0020.0002] -133C6 ; [.5042.0020.0002] -133C7 ; [.5043.0020.0002] -133C8 ; [.5044.0020.0002] -133C9 ; [.5045.0020.0002] -133CA ; [.5046.0020.0002] -133CB ; [.5047.0020.0002] -133CC ; [.5048.0020.0002] -133CD ; [.5049.0020.0002] -133CE ; [.504A.0020.0002] -133CF ; [.504B.0020.0002] -133D0 ; [.504C.0020.0002] -133D1 ; [.504D.0020.0002] -133D2 ; [.504E.0020.0002] -133D3 ; [.504F.0020.0002] -133D4 ; [.5050.0020.0002] -133D5 ; [.5051.0020.0002] -133D6 ; [.5052.0020.0002] -133D7 ; [.5053.0020.0002] -133D8 ; [.5054.0020.0002] -133D9 ; [.5055.0020.0002] -133DA ; [.5056.0020.0002] -133DB ; [.5057.0020.0002] -133DC ; [.5058.0020.0002] -133DD ; [.5059.0020.0002] -133DE ; [.505A.0020.0002] -133DF ; [.505B.0020.0002] -133E0 ; [.505C.0020.0002] -133E1 ; [.505D.0020.0002] -133E2 ; [.505E.0020.0002] -133E3 ; [.505F.0020.0002] -133E4 ; [.5060.0020.0002] -133E5 ; [.5061.0020.0002] -133E6 ; [.5062.0020.0002] -133E7 ; [.5063.0020.0002] -133E8 ; [.5064.0020.0002] -133E9 ; [.5065.0020.0002] -133EA ; [.5066.0020.0002] -133EB ; [.5067.0020.0002] -133EC ; [.5068.0020.0002] -133ED ; [.5069.0020.0002] -133EE ; [.506A.0020.0002] -133EF ; [.506B.0020.0002] -133F0 ; [.506C.0020.0002] -133F1 ; [.506D.0020.0002] -133F2 ; [.506E.0020.0002] -133F3 ; [.506F.0020.0002] -133F4 ; [.5070.0020.0002] -133F5 ; [.5071.0020.0002] -133F6 ; [.5072.0020.0002] -133F7 ; [.5073.0020.0002] -133F8 ; [.5074.0020.0002] -133F9 ; [.5075.0020.0002] -133FA ; [.5076.0020.0002] -133FB ; [.5077.0020.0002] -133FC ; [.5078.0020.0002] -133FD ; [.5079.0020.0002] -133FE ; [.507A.0020.0002] -133FF ; [.507B.0020.0002] -13400 ; [.507C.0020.0002] -13401 ; [.507D.0020.0002] -13402 ; [.507E.0020.0002] -13403 ; [.507F.0020.0002] -13404 ; [.5080.0020.0002] -13405 ; [.5081.0020.0002] -13406 ; [.5082.0020.0002] -13407 ; [.5083.0020.0002] -13408 ; [.5084.0020.0002] -13409 ; [.5085.0020.0002] -1340A ; [.5086.0020.0002] -1340B ; [.5087.0020.0002] -1340C ; [.5088.0020.0002] -1340D ; [.5089.0020.0002] -1340E ; [.508A.0020.0002] -1340F ; [.508B.0020.0002] -13410 ; [.508C.0020.0002] -13411 ; [.508D.0020.0002] -13412 ; [.508E.0020.0002] -13413 ; [.508F.0020.0002] -13414 ; [.5090.0020.0002] -13415 ; [.5091.0020.0002] -13416 ; [.5092.0020.0002] -13417 ; [.5093.0020.0002] -13418 ; [.5094.0020.0002] -13419 ; [.5095.0020.0002] -1341A ; [.5096.0020.0002] -1341B ; [.5097.0020.0002] -1341C ; [.5098.0020.0002] -1341D ; [.5099.0020.0002] -1341E ; [.509A.0020.0002] -1341F ; [.509B.0020.0002] -13420 ; [.509C.0020.0002] -13421 ; [.509D.0020.0002] -13422 ; [.509E.0020.0002] -13423 ; [.509F.0020.0002] -13424 ; [.50A0.0020.0002] -13425 ; [.50A1.0020.0002] -13426 ; [.50A2.0020.0002] -13427 ; [.50A3.0020.0002] -13428 ; [.50A4.0020.0002] -13429 ; [.50A5.0020.0002] -1342A ; [.50A6.0020.0002] -1342B ; [.50A7.0020.0002] -1342C ; [.50A8.0020.0002] -1342D ; [.50A9.0020.0002] -1342E ; [.50AA.0020.0002] -109A0 ; [.50AB.0020.0002] -10980 ; [.50AB.0020.0004][.0000.010B.0004] -109A1 ; [.50AC.0020.0002] -10981 ; [.50AC.0020.0004][.0000.010B.0004] -109A2 ; [.50AD.0020.0002] -10982 ; [.50AD.0020.0004][.0000.010B.0004] -109A3 ; [.50AE.0020.0002] -10983 ; [.50AE.0020.0004][.0000.010B.0004] -109A4 ; [.50AF.0020.0002] -10984 ; [.50AF.0020.0004][.0000.010B.0004] -109A5 ; [.50B0.0020.0002] -10985 ; [.50B0.0020.0004][.0000.010B.0004] -109A6 ; [.50B1.0020.0002] -10986 ; [.50B1.0020.0004][.0000.010B.0004] -10987 ; [.50B1.0020.0004][.0000.010C.0004] -109A7 ; [.50B2.0020.0002] -10988 ; [.50B2.0020.0004][.0000.010B.0004] -109A8 ; [.50B3.0020.0002] -10989 ; [.50B3.0020.0004][.0000.010B.0004] -109A9 ; [.50B4.0020.0002] -1098A ; [.50B4.0020.0004][.0000.010B.0004] -1098B ; [.50B4.0020.0004][.0000.010C.0004] -109AA ; [.50B5.0020.0002] -1098C ; [.50B5.0020.0004][.0000.010B.0004] -1098D ; [.50B5.0020.0004][.0000.010C.0004] -109AB ; [.50B6.0020.0002] -1098E ; [.50B6.0020.0004][.0000.010B.0004] -1098F ; [.50B6.0020.0004][.0000.010C.0004] -109AC ; [.50B7.0020.0002] -10990 ; [.50B7.0020.0004][.0000.010B.0004] -109AD ; [.50B8.0020.0002] -10991 ; [.50B8.0020.0004][.0000.010B.0004] -109AE ; [.50B9.0020.0002] -10992 ; [.50B9.0020.0004][.0000.010B.0004] -109AF ; [.50BA.0020.0002] -109B0 ; [.50BA.0020.0004][.0000.010B.0004] -10993 ; [.50BA.0020.0004][.0000.010C.0004] -10994 ; [.50BA.0020.0004][.0000.010D.0004] -109B1 ; [.50BB.0020.0002] -10995 ; [.50BB.0020.0004][.0000.010B.0004] -109B2 ; [.50BC.0020.0002] -10996 ; [.50BC.0020.0004][.0000.010B.0004] -109B3 ; [.50BD.0020.0002] -10997 ; [.50BD.0020.0004][.0000.010B.0004] -109B4 ; [.50BE.0020.0002] -10998 ; [.50BE.0020.0004][.0000.010B.0004] -10999 ; [.50BE.0020.0004][.0000.010C.0004] -109B5 ; [.50BF.0020.0002] -1099A ; [.50BF.0020.0004][.0000.010B.0004] -1099B ; [.50BF.0020.0004][.0000.010C.0004] -109B6 ; [.50C0.0020.0002] -1099C ; [.50C0.0020.0004][.0000.010B.0004] -109B7 ; [.50C1.0020.0002] -1099D ; [.50C1.0020.0004][.0000.010B.0004] -109BE ; [.50C2.0020.0002] -109BF ; [.50C3.0020.0002] -1099E ; [.50C4.0020.0002] -1099F ; [.50C5.0020.0002] -14400 ; [.50C6.0020.0002] -14401 ; [.50C7.0020.0002] -14402 ; [.50C8.0020.0002] -14403 ; [.50C9.0020.0002] -14404 ; [.50CA.0020.0002] -14405 ; [.50CB.0020.0002] -14406 ; [.50CC.0020.0002] -14407 ; [.50CD.0020.0002] -14408 ; [.50CE.0020.0002] -14409 ; [.50CF.0020.0002] -1440A ; [.50D0.0020.0002] -1440B ; [.50D1.0020.0002] -1440C ; [.50D2.0020.0002] -1440D ; [.50D3.0020.0002] -1440E ; [.50D4.0020.0002] -1440F ; [.50D5.0020.0002] -14410 ; [.50D6.0020.0002] -14411 ; [.50D7.0020.0002] -14412 ; [.50D8.0020.0002] -14413 ; [.50D9.0020.0002] -14414 ; [.50DA.0020.0002] -14415 ; [.50DB.0020.0002] -14416 ; [.50DC.0020.0002] -14417 ; [.50DD.0020.0002] -14418 ; [.50DE.0020.0002] -14419 ; [.50DF.0020.0002] -1441A ; [.50E0.0020.0002] -1441B ; [.50E1.0020.0002] -1441C ; [.50E2.0020.0002] -1441D ; [.50E3.0020.0002] -1441E ; [.50E4.0020.0002] -1441F ; [.50E5.0020.0002] -14420 ; [.50E6.0020.0002] -14421 ; [.50E7.0020.0002] -14422 ; [.50E8.0020.0002] -14423 ; [.50E9.0020.0002] -14424 ; [.50EA.0020.0002] -14425 ; [.50EB.0020.0002] -14426 ; [.50EC.0020.0002] -14427 ; [.50ED.0020.0002] -14428 ; [.50EE.0020.0002] -14429 ; [.50EF.0020.0002] -1442A ; [.50F0.0020.0002] -1442B ; [.50F1.0020.0002] -1442C ; [.50F2.0020.0002] -1442D ; [.50F3.0020.0002] -1442E ; [.50F4.0020.0002] -1442F ; [.50F5.0020.0002] -14430 ; [.50F6.0020.0002] -14431 ; [.50F7.0020.0002] -14432 ; [.50F8.0020.0002] -14433 ; [.50F9.0020.0002] -14434 ; [.50FA.0020.0002] -14435 ; [.50FB.0020.0002] -14436 ; [.50FC.0020.0002] -14437 ; [.50FD.0020.0002] -14438 ; [.50FE.0020.0002] -14439 ; [.50FF.0020.0002] -1443A ; [.5100.0020.0002] -1443B ; [.5101.0020.0002] -1443C ; [.5102.0020.0002] -1443D ; [.5103.0020.0002] -1443E ; [.5104.0020.0002] -1443F ; [.5105.0020.0002] -14440 ; [.5106.0020.0002] -14441 ; [.5107.0020.0002] -14442 ; [.5108.0020.0002] -14443 ; [.5109.0020.0002] -14444 ; [.510A.0020.0002] -14445 ; [.510B.0020.0002] -14446 ; [.510C.0020.0002] -14447 ; [.510D.0020.0002] -14448 ; [.510E.0020.0002] -14449 ; [.510F.0020.0002] -1444A ; [.5110.0020.0002] -1444B ; [.5111.0020.0002] -1444C ; [.5112.0020.0002] -1444D ; [.5113.0020.0002] -1444E ; [.5114.0020.0002] -1444F ; [.5115.0020.0002] -14450 ; [.5116.0020.0002] -14451 ; [.5117.0020.0002] -14452 ; [.5118.0020.0002] -14453 ; [.5119.0020.0002] -14454 ; [.511A.0020.0002] -14455 ; [.511B.0020.0002] -14456 ; [.511C.0020.0002] -14457 ; [.511D.0020.0002] -14458 ; [.511E.0020.0002] -14459 ; [.511F.0020.0002] -1445A ; [.5120.0020.0002] -1445B ; [.5121.0020.0002] -1445C ; [.5122.0020.0002] -1445D ; [.5123.0020.0002] -1445E ; [.5124.0020.0002] -1445F ; [.5125.0020.0002] -14460 ; [.5126.0020.0002] -14461 ; [.5127.0020.0002] -14462 ; [.5128.0020.0002] -14463 ; [.5129.0020.0002] -14464 ; [.512A.0020.0002] -14465 ; [.512B.0020.0002] -14466 ; [.512C.0020.0002] -14467 ; [.512D.0020.0002] -14468 ; [.512E.0020.0002] -14469 ; [.512F.0020.0002] -1446A ; [.5130.0020.0002] -1446B ; [.5131.0020.0002] -1446C ; [.5132.0020.0002] -1446D ; [.5133.0020.0002] -1446E ; [.5134.0020.0002] -1446F ; [.5135.0020.0002] -14470 ; [.5136.0020.0002] -14471 ; [.5137.0020.0002] -14472 ; [.5138.0020.0002] -14473 ; [.5139.0020.0002] -14474 ; [.513A.0020.0002] -14475 ; [.513B.0020.0002] -14476 ; [.513C.0020.0002] -14477 ; [.513D.0020.0002] -14478 ; [.513E.0020.0002] -14479 ; [.513F.0020.0002] -1447A ; [.5140.0020.0002] -1447B ; [.5141.0020.0002] -1447C ; [.5142.0020.0002] -1447D ; [.5143.0020.0002] -1447E ; [.5144.0020.0002] -1447F ; [.5145.0020.0002] -14480 ; [.5146.0020.0002] -14481 ; [.5147.0020.0002] -14482 ; [.5148.0020.0002] -14483 ; [.5149.0020.0002] -14484 ; [.514A.0020.0002] -14485 ; [.514B.0020.0002] -14486 ; [.514C.0020.0002] -14487 ; [.514D.0020.0002] -14488 ; [.514E.0020.0002] -14489 ; [.514F.0020.0002] -1448A ; [.5150.0020.0002] -1448B ; [.5151.0020.0002] -1448C ; [.5152.0020.0002] -1448D ; [.5153.0020.0002] -1448E ; [.5154.0020.0002] -1448F ; [.5155.0020.0002] -14490 ; [.5156.0020.0002] -14491 ; [.5157.0020.0002] -14492 ; [.5158.0020.0002] -14493 ; [.5159.0020.0002] -14494 ; [.515A.0020.0002] -14495 ; [.515B.0020.0002] -14496 ; [.515C.0020.0002] -14497 ; [.515D.0020.0002] -14498 ; [.515E.0020.0002] -14499 ; [.515F.0020.0002] -1449A ; [.5160.0020.0002] -1449B ; [.5161.0020.0002] -1449C ; [.5162.0020.0002] -1449D ; [.5163.0020.0002] -1449E ; [.5164.0020.0002] -1449F ; [.5165.0020.0002] -144A0 ; [.5166.0020.0002] -144A1 ; [.5167.0020.0002] -144A2 ; [.5168.0020.0002] -144A3 ; [.5169.0020.0002] -144A4 ; [.516A.0020.0002] -144A5 ; [.516B.0020.0002] -144A6 ; [.516C.0020.0002] -144A7 ; [.516D.0020.0002] -144A8 ; [.516E.0020.0002] -144A9 ; [.516F.0020.0002] -144AA ; [.5170.0020.0002] -144AB ; [.5171.0020.0002] -144AC ; [.5172.0020.0002] -144AD ; [.5173.0020.0002] -144AE ; [.5174.0020.0002] -144AF ; [.5175.0020.0002] -144B0 ; [.5176.0020.0002] -144B1 ; [.5177.0020.0002] -144B2 ; [.5178.0020.0002] -144B3 ; [.5179.0020.0002] -144B4 ; [.517A.0020.0002] -144B5 ; [.517B.0020.0002] -144B6 ; [.517C.0020.0002] -144B7 ; [.517D.0020.0002] -144B8 ; [.517E.0020.0002] -144B9 ; [.517F.0020.0002] -144BA ; [.5180.0020.0002] -144BB ; [.5181.0020.0002] -144BC ; [.5182.0020.0002] -144BD ; [.5183.0020.0002] -144BE ; [.5184.0020.0002] -144BF ; [.5185.0020.0002] -144C0 ; [.5186.0020.0002] -144C1 ; [.5187.0020.0002] -144C2 ; [.5188.0020.0002] -144C3 ; [.5189.0020.0002] -144C4 ; [.518A.0020.0002] -144C5 ; [.518B.0020.0002] -144C6 ; [.518C.0020.0002] -144C7 ; [.518D.0020.0002] -144C8 ; [.518E.0020.0002] -144C9 ; [.518F.0020.0002] -144CA ; [.5190.0020.0002] -144CB ; [.5191.0020.0002] -144CC ; [.5192.0020.0002] -144CD ; [.5193.0020.0002] -144CE ; [.5194.0020.0002] -144CF ; [.5195.0020.0002] -144D0 ; [.5196.0020.0002] -144D1 ; [.5197.0020.0002] -144D2 ; [.5198.0020.0002] -144D3 ; [.5199.0020.0002] -144D4 ; [.519A.0020.0002] -144D5 ; [.519B.0020.0002] -144D6 ; [.519C.0020.0002] -144D7 ; [.519D.0020.0002] -144D8 ; [.519E.0020.0002] -144D9 ; [.519F.0020.0002] -144DA ; [.51A0.0020.0002] -144DB ; [.51A1.0020.0002] -144DC ; [.51A2.0020.0002] -144DD ; [.51A3.0020.0002] -144DE ; [.51A4.0020.0002] -144DF ; [.51A5.0020.0002] -144E0 ; [.51A6.0020.0002] -144E1 ; [.51A7.0020.0002] -144E2 ; [.51A8.0020.0002] -144E3 ; [.51A9.0020.0002] -144E4 ; [.51AA.0020.0002] -144E5 ; [.51AB.0020.0002] -144E6 ; [.51AC.0020.0002] -144E7 ; [.51AD.0020.0002] -144E8 ; [.51AE.0020.0002] -144E9 ; [.51AF.0020.0002] -144EA ; [.51B0.0020.0002] -144EB ; [.51B1.0020.0002] -144EC ; [.51B2.0020.0002] -144ED ; [.51B3.0020.0002] -144EE ; [.51B4.0020.0002] -144EF ; [.51B5.0020.0002] -144F0 ; [.51B6.0020.0002] -144F1 ; [.51B7.0020.0002] -144F2 ; [.51B8.0020.0002] -144F3 ; [.51B9.0020.0002] -144F4 ; [.51BA.0020.0002] -144F5 ; [.51BB.0020.0002] -144F6 ; [.51BC.0020.0002] -144F7 ; [.51BD.0020.0002] -144F8 ; [.51BE.0020.0002] -144F9 ; [.51BF.0020.0002] -144FA ; [.51C0.0020.0002] -144FB ; [.51C1.0020.0002] -144FC ; [.51C2.0020.0002] -144FD ; [.51C3.0020.0002] -144FE ; [.51C4.0020.0002] -144FF ; [.51C5.0020.0002] -14500 ; [.51C6.0020.0002] -14501 ; [.51C7.0020.0002] -14502 ; [.51C8.0020.0002] -14503 ; [.51C9.0020.0002] -14504 ; [.51CA.0020.0002] -14505 ; [.51CB.0020.0002] -14506 ; [.51CC.0020.0002] -14507 ; [.51CD.0020.0002] -14508 ; [.51CE.0020.0002] -14509 ; [.51CF.0020.0002] -1450A ; [.51D0.0020.0002] -1450B ; [.51D1.0020.0002] -1450C ; [.51D2.0020.0002] -1450D ; [.51D3.0020.0002] -1450E ; [.51D4.0020.0002] -1450F ; [.51D5.0020.0002] -14510 ; [.51D6.0020.0002] -14511 ; [.51D7.0020.0002] -14512 ; [.51D8.0020.0002] -14513 ; [.51D9.0020.0002] -14514 ; [.51DA.0020.0002] -14515 ; [.51DB.0020.0002] -14516 ; [.51DC.0020.0002] -14517 ; [.51DD.0020.0002] -14518 ; [.51DE.0020.0002] -14519 ; [.51DF.0020.0002] -1451A ; [.51E0.0020.0002] -1451B ; [.51E1.0020.0002] -1451C ; [.51E2.0020.0002] -1451D ; [.51E3.0020.0002] -1451E ; [.51E4.0020.0002] -1451F ; [.51E5.0020.0002] -14520 ; [.51E6.0020.0002] -14521 ; [.51E7.0020.0002] -14522 ; [.51E8.0020.0002] -14523 ; [.51E9.0020.0002] -14524 ; [.51EA.0020.0002] -14525 ; [.51EB.0020.0002] -14526 ; [.51EC.0020.0002] -14527 ; [.51ED.0020.0002] -14528 ; [.51EE.0020.0002] -14529 ; [.51EF.0020.0002] -1452A ; [.51F0.0020.0002] -1452B ; [.51F1.0020.0002] -1452C ; [.51F2.0020.0002] -1452D ; [.51F3.0020.0002] -1452E ; [.51F4.0020.0002] -1452F ; [.51F5.0020.0002] -14530 ; [.51F6.0020.0002] -14531 ; [.51F7.0020.0002] -14532 ; [.51F8.0020.0002] -14533 ; [.51F9.0020.0002] -14534 ; [.51FA.0020.0002] -14535 ; [.51FB.0020.0002] -14536 ; [.51FC.0020.0002] -14537 ; [.51FD.0020.0002] -14538 ; [.51FE.0020.0002] -14539 ; [.51FF.0020.0002] -1453A ; [.5200.0020.0002] -1453B ; [.5201.0020.0002] -1453C ; [.5202.0020.0002] -1453D ; [.5203.0020.0002] -1453E ; [.5204.0020.0002] -1453F ; [.5205.0020.0002] -14540 ; [.5206.0020.0002] -14541 ; [.5207.0020.0002] -14542 ; [.5208.0020.0002] -14543 ; [.5209.0020.0002] -14544 ; [.520A.0020.0002] -14545 ; [.520B.0020.0002] -14546 ; [.520C.0020.0002] -14547 ; [.520D.0020.0002] -14548 ; [.520E.0020.0002] -14549 ; [.520F.0020.0002] -1454A ; [.5210.0020.0002] -1454B ; [.5211.0020.0002] -1454C ; [.5212.0020.0002] -1454D ; [.5213.0020.0002] -1454E ; [.5214.0020.0002] -1454F ; [.5215.0020.0002] -14550 ; [.5216.0020.0002] -14551 ; [.5217.0020.0002] -14552 ; [.5218.0020.0002] -14553 ; [.5219.0020.0002] -14554 ; [.521A.0020.0002] -14555 ; [.521B.0020.0002] -14556 ; [.521C.0020.0002] -14557 ; [.521D.0020.0002] -14558 ; [.521E.0020.0002] -14559 ; [.521F.0020.0002] -1455A ; [.5220.0020.0002] -1455B ; [.5221.0020.0002] -1455C ; [.5222.0020.0002] -1455D ; [.5223.0020.0002] -1455E ; [.5224.0020.0002] -1455F ; [.5225.0020.0002] -14560 ; [.5226.0020.0002] -14561 ; [.5227.0020.0002] -14562 ; [.5228.0020.0002] -14563 ; [.5229.0020.0002] -14564 ; [.522A.0020.0002] -14565 ; [.522B.0020.0002] -14566 ; [.522C.0020.0002] -14567 ; [.522D.0020.0002] -14568 ; [.522E.0020.0002] -14569 ; [.522F.0020.0002] -1456A ; [.5230.0020.0002] -1456B ; [.5231.0020.0002] -1456C ; [.5232.0020.0002] -1456D ; [.5233.0020.0002] -1456E ; [.5234.0020.0002] -1456F ; [.5235.0020.0002] -14570 ; [.5236.0020.0002] -14571 ; [.5237.0020.0002] -14572 ; [.5238.0020.0002] -14573 ; [.5239.0020.0002] -14574 ; [.523A.0020.0002] -14575 ; [.523B.0020.0002] -14576 ; [.523C.0020.0002] -14577 ; [.523D.0020.0002] -14578 ; [.523E.0020.0002] -14579 ; [.523F.0020.0002] -1457A ; [.5240.0020.0002] -1457B ; [.5241.0020.0002] -1457C ; [.5242.0020.0002] -1457D ; [.5243.0020.0002] -1457E ; [.5244.0020.0002] -1457F ; [.5245.0020.0002] -14580 ; [.5246.0020.0002] -14581 ; [.5247.0020.0002] -14582 ; [.5248.0020.0002] -14583 ; [.5249.0020.0002] -14584 ; [.524A.0020.0002] -14585 ; [.524B.0020.0002] -14586 ; [.524C.0020.0002] -14587 ; [.524D.0020.0002] -14588 ; [.524E.0020.0002] -14589 ; [.524F.0020.0002] -1458A ; [.5250.0020.0002] -1458B ; [.5251.0020.0002] -1458C ; [.5252.0020.0002] -1458D ; [.5253.0020.0002] -1458E ; [.5254.0020.0002] -1458F ; [.5255.0020.0002] -14590 ; [.5256.0020.0002] -14591 ; [.5257.0020.0002] -14592 ; [.5258.0020.0002] -14593 ; [.5259.0020.0002] -14594 ; [.525A.0020.0002] -14595 ; [.525B.0020.0002] -14596 ; [.525C.0020.0002] -14597 ; [.525D.0020.0002] -14598 ; [.525E.0020.0002] -14599 ; [.525F.0020.0002] -1459A ; [.5260.0020.0002] -1459B ; [.5261.0020.0002] -1459C ; [.5262.0020.0002] -1459D ; [.5263.0020.0002] -1459E ; [.5264.0020.0002] -1459F ; [.5265.0020.0002] -145A0 ; [.5266.0020.0002] -145A1 ; [.5267.0020.0002] -145A2 ; [.5268.0020.0002] -145A3 ; [.5269.0020.0002] -145A4 ; [.526A.0020.0002] -145A5 ; [.526B.0020.0002] -145A6 ; [.526C.0020.0002] -145A7 ; [.526D.0020.0002] -145A8 ; [.526E.0020.0002] -145A9 ; [.526F.0020.0002] -145AA ; [.5270.0020.0002] -145AB ; [.5271.0020.0002] -145AC ; [.5272.0020.0002] -145AD ; [.5273.0020.0002] -145AE ; [.5274.0020.0002] -145AF ; [.5275.0020.0002] -145B0 ; [.5276.0020.0002] -145B1 ; [.5277.0020.0002] -145B2 ; [.5278.0020.0002] -145B3 ; [.5279.0020.0002] -145B4 ; [.527A.0020.0002] -145B5 ; [.527B.0020.0002] -145B6 ; [.527C.0020.0002] -145B7 ; [.527D.0020.0002] -145B8 ; [.527E.0020.0002] -145B9 ; [.527F.0020.0002] -145BA ; [.5280.0020.0002] -145BB ; [.5281.0020.0002] -145BC ; [.5282.0020.0002] -145BD ; [.5283.0020.0002] -145BE ; [.5284.0020.0002] -145BF ; [.5285.0020.0002] -145C0 ; [.5286.0020.0002] -145C1 ; [.5287.0020.0002] -145C2 ; [.5288.0020.0002] -145C3 ; [.5289.0020.0002] -145C4 ; [.528A.0020.0002] -145C5 ; [.528B.0020.0002] -145C6 ; [.528C.0020.0002] -145C7 ; [.528D.0020.0002] -145C8 ; [.528E.0020.0002] -145C9 ; [.528F.0020.0002] -145CA ; [.5290.0020.0002] -145CB ; [.5291.0020.0002] -145CC ; [.5292.0020.0002] -145CD ; [.5293.0020.0002] -145CE ; [.5294.0020.0002] -145CF ; [.5295.0020.0002] -145D0 ; [.5296.0020.0002] -145D1 ; [.5297.0020.0002] -145D2 ; [.5298.0020.0002] -145D3 ; [.5299.0020.0002] -145D4 ; [.529A.0020.0002] -145D5 ; [.529B.0020.0002] -145D6 ; [.529C.0020.0002] -145D7 ; [.529D.0020.0002] -145D8 ; [.529E.0020.0002] -145D9 ; [.529F.0020.0002] -145DA ; [.52A0.0020.0002] -145DB ; [.52A1.0020.0002] -145DC ; [.52A2.0020.0002] -145DD ; [.52A3.0020.0002] -145DE ; [.52A4.0020.0002] -145DF ; [.52A5.0020.0002] -145E0 ; [.52A6.0020.0002] -145E1 ; [.52A7.0020.0002] -145E2 ; [.52A8.0020.0002] -145E3 ; [.52A9.0020.0002] -145E4 ; [.52AA.0020.0002] -145E5 ; [.52AB.0020.0002] -145E6 ; [.52AC.0020.0002] -145E7 ; [.52AD.0020.0002] -145E8 ; [.52AE.0020.0002] -145E9 ; [.52AF.0020.0002] -145EA ; [.52B0.0020.0002] -145EB ; [.52B1.0020.0002] -145EC ; [.52B2.0020.0002] -145ED ; [.52B3.0020.0002] -145EE ; [.52B4.0020.0002] -145EF ; [.52B5.0020.0002] -145F0 ; [.52B6.0020.0002] -145F1 ; [.52B7.0020.0002] -145F2 ; [.52B8.0020.0002] -145F3 ; [.52B9.0020.0002] -145F4 ; [.52BA.0020.0002] -145F5 ; [.52BB.0020.0002] -145F6 ; [.52BC.0020.0002] -145F7 ; [.52BD.0020.0002] -145F8 ; [.52BE.0020.0002] -145F9 ; [.52BF.0020.0002] -145FA ; [.52C0.0020.0002] -145FB ; [.52C1.0020.0002] -145FC ; [.52C2.0020.0002] -145FD ; [.52C3.0020.0002] -145FE ; [.52C4.0020.0002] -145FF ; [.52C5.0020.0002] -14600 ; [.52C6.0020.0002] -14601 ; [.52C7.0020.0002] -14602 ; [.52C8.0020.0002] -14603 ; [.52C9.0020.0002] -14604 ; [.52CA.0020.0002] -14605 ; [.52CB.0020.0002] -14606 ; [.52CC.0020.0002] -14607 ; [.52CD.0020.0002] -14608 ; [.52CE.0020.0002] -14609 ; [.52CF.0020.0002] -1460A ; [.52D0.0020.0002] -1460B ; [.52D1.0020.0002] -1460C ; [.52D2.0020.0002] -1460D ; [.52D3.0020.0002] -1460E ; [.52D4.0020.0002] -1460F ; [.52D5.0020.0002] -14610 ; [.52D6.0020.0002] -14611 ; [.52D7.0020.0002] -14612 ; [.52D8.0020.0002] -14613 ; [.52D9.0020.0002] -14614 ; [.52DA.0020.0002] -14615 ; [.52DB.0020.0002] -14616 ; [.52DC.0020.0002] -14617 ; [.52DD.0020.0002] -14618 ; [.52DE.0020.0002] -14619 ; [.52DF.0020.0002] -1461A ; [.52E0.0020.0002] -1461B ; [.52E1.0020.0002] -1461C ; [.52E2.0020.0002] -1461D ; [.52E3.0020.0002] -1461E ; [.52E4.0020.0002] -1461F ; [.52E5.0020.0002] -14620 ; [.52E6.0020.0002] -14621 ; [.52E7.0020.0002] -14622 ; [.52E8.0020.0002] -14623 ; [.52E9.0020.0002] -14624 ; [.52EA.0020.0002] -14625 ; [.52EB.0020.0002] -14626 ; [.52EC.0020.0002] -14627 ; [.52ED.0020.0002] -14628 ; [.52EE.0020.0002] -14629 ; [.52EF.0020.0002] -1462A ; [.52F0.0020.0002] -1462B ; [.52F1.0020.0002] -1462C ; [.52F2.0020.0002] -1462D ; [.52F3.0020.0002] -1462E ; [.52F4.0020.0002] -1462F ; [.52F5.0020.0002] -14630 ; [.52F6.0020.0002] -14631 ; [.52F7.0020.0002] -14632 ; [.52F8.0020.0002] -14633 ; [.52F9.0020.0002] -14634 ; [.52FA.0020.0002] -14635 ; [.52FB.0020.0002] -14636 ; [.52FC.0020.0002] -14637 ; [.52FD.0020.0002] -14638 ; [.52FE.0020.0002] -14639 ; [.52FF.0020.0002] -1463A ; [.5300.0020.0002] -1463B ; [.5301.0020.0002] -1463C ; [.5302.0020.0002] -1463D ; [.5303.0020.0002] -1463E ; [.5304.0020.0002] -1463F ; [.5305.0020.0002] -14640 ; [.5306.0020.0002] -14641 ; [.5307.0020.0002] -14642 ; [.5308.0020.0002] -14643 ; [.5309.0020.0002] -14644 ; [.530A.0020.0002] -14645 ; [.530B.0020.0002] -14646 ; [.530C.0020.0002] -2F00 ; [.FB40.0020.0004][.CE00.0000.0000] -3220 ; [*0310.0020.0004][.FB40.0020.0004][.CE00.0000.0000][*0311.0020.0004] -3280 ; [.FB40.0020.0006][.CE00.0000.0000] -3192 ; [.FB40.0020.0014][.CE00.0000.0000] -1F229 ; [.FB40.0020.001C][.CE00.0000.0000] -319C ; [.FB40.0020.0014][.CE01.0000.0000] -3226 ; [*0310.0020.0004][.FB40.0020.0004][.CE03.0000.0000][*0311.0020.0004] -3286 ; [.FB40.0020.0006][.CE03.0000.0000] -3222 ; [*0310.0020.0004][.FB40.0020.0004][.CE09.0000.0000][*0311.0020.0004] -1F241 ; [*0372.0020.0004][.FB40.0020.0004][.CE09.0000.0000][*0373.0020.0004] -3282 ; [.FB40.0020.0006][.CE09.0000.0000] -3194 ; [.FB40.0020.0014][.CE09.0000.0000] -1F22A ; [.FB40.0020.001C][.CE09.0000.0000] -32A4 ; [.FB40.0020.0006][.CE0A.0000.0000] -3196 ; [.FB40.0020.0014][.CE0A.0000.0000] -32A6 ; [.FB40.0020.0006][.CE0B.0000.0000] -3198 ; [.FB40.0020.0014][.CE0B.0000.0000] -F967 ; [.FB40.0020.0002][.CE0D.0000.0000] -319B ; [.FB40.0020.0014][.CE19.0000.0000] -FA70 ; [.FB40.0020.0002][.CE26.0000.0000] -2F01 ; [.FB40.0020.0004][.CE28.0000.0000] -2EA6 ; [.FB40.0020.0004][.CE2C.0000.0000] -32A5 ; [.FB40.0020.0006][.CE2D.0000.0000] -3197 ; [.FB40.0020.0014][.CE2D.0000.0000] -1F22D ; [.FB40.0020.001C][.CE2D.0000.0000] -F905 ; [.FB40.0020.0002][.CE32.0000.0000] -2F02 ; [.FB40.0020.0004][.CE36.0000.0000] -2E80 ; [.FB40.0020.0004][.CE36.0000.0000][.0000.010B.0004] -2F801 ; [.FB40.0020.0002][.CE38.0000.0000] -F95E ; [.FB40.0020.0002][.CE39.0000.0000] -2F800 ; [.FB40.0020.0002][.CE3D.0000.0000] -2F03 ; [.FB40.0020.0004][.CE3F.0000.0000] -2F802 ; [.FB40.0020.0002][.CE41.0000.0000] -2F04 ; [.FB40.0020.0004][.CE59.0000.0000] -319A ; [.FB40.0020.0014][.CE59.0000.0000] -2E84 ; [.FB40.0020.0004][.CE59.0000.0000][.0000.010B.0004] -2E83 ; [.FB40.0020.0004][.CE5A.0000.0000] -2E82 ; [.FB40.0020.0004][.CE5B.0000.0000] -3228 ; [*0310.0020.0004][.FB40.0020.0004][.CE5D.0000.0000][*0311.0020.0004] -3288 ; [.FB40.0020.0006][.CE5D.0000.0000] -F91B ; [.FB40.0020.0002][.CE82.0000.0000] -2F05 ; [.FB40.0020.0004][.CE85.0000.0000] -F9BA ; [.FB40.0020.0002][.CE86.0000.0000] -2F06 ; [.FB40.0020.0004][.CE8C.0000.0000] -3221 ; [*0310.0020.0004][.FB40.0020.0004][.CE8C.0000.0000][*0311.0020.0004] -1F242 ; [*0372.0020.0004][.FB40.0020.0004][.CE8C.0000.0000][*0373.0020.0004] -3281 ; [.FB40.0020.0006][.CE8C.0000.0000] -3193 ; [.FB40.0020.0014][.CE8C.0000.0000] -1F214 ; [.FB40.0020.001C][.CE8C.0000.0000] -3224 ; [*0310.0020.0004][.FB40.0020.0004][.CE94.0000.0000][*0311.0020.0004] -3284 ; [.FB40.0020.0006][.CE94.0000.0000] -2F07 ; [.FB40.0020.0004][.CEA0.0000.0000] -1F218 ; [.FB40.0020.001C][.CEA4.0000.0000] -F977 ; [.FB40.0020.0002][.CEAE.0000.0000] -2F08 ; [.FB40.0020.0004][.CEBA.0000.0000] -319F ; [.FB40.0020.0014][.CEBA.0000.0000] -2E85 ; [.FB40.0020.0004][.CEBB.0000.0000] -F9FD ; [.FB40.0020.0002][.CEC0.0000.0000] -2F819 ; [.FB40.0020.0002][.CECC.0000.0000] -3239 ; [*0310.0020.0004][.FB40.0020.0004][.CEE3.0000.0000][*0311.0020.0004] -F9A8 ; [.FB40.0020.0002][.CEE4.0000.0000] -323D ; [*0310.0020.0004][.FB40.0020.0004][.CF01.0000.0000][*0311.0020.0004] -32AD ; [.FB40.0020.0006][.CF01.0000.0000] -3241 ; [*0310.0020.0004][.FB40.0020.0004][.CF11.0000.0000][*0311.0020.0004] -32A1 ; [.FB40.0020.0006][.CF11.0000.0000] -2F804 ; [.FB40.0020.0002][.CF60.0000.0000] -FA73 ; [.FB40.0020.0002][.CF80.0000.0000] -F92D ; [.FB40.0020.0002][.CF86.0000.0000] -F9B5 ; [.FB40.0020.0002][.CF8B.0000.0000] -FA30 ; [.FB40.0020.0002][.CFAE.0000.0000] -2F805 ; [.FB40.0020.0002][.CFAE.0000.0000] -2F806 ; [.FB40.0020.0002][.CFBB.0000.0000] -F965 ; [.FB40.0020.0002][.CFBF.0000.0000] -2F807 ; [.FB40.0020.0002][.D002.0000.0000] -F9D4 ; [.FB40.0020.0002][.D02B.0000.0000] -2F808 ; [.FB40.0020.0002][.D07A.0000.0000] -2F809 ; [.FB40.0020.0002][.D099.0000.0000] -2F80B ; [.FB40.0020.0002][.D0CF.0000.0000] -F9BB ; [.FB40.0020.0002][.D0DA.0000.0000] -FA31 ; [.FB40.0020.0002][.D0E7.0000.0000] -2F80A ; [.FB40.0020.0002][.D0E7.0000.0000] -329D ; [.FB40.0020.0006][.D12A.0000.0000] -2F09 ; [.FB40.0020.0004][.D13F.0000.0000] -FA0C ; [.FB40.0020.0002][.D140.0000.0000] -FA74 ; [.FB40.0020.0002][.D145.0000.0000] -FA32 ; [.FB40.0020.0002][.D14D.0000.0000] -2F80E ; [.FB40.0020.0002][.D14D.0000.0000] -2F80F ; [.FB40.0020.0002][.D154.0000.0000] -2F810 ; [.FB40.0020.0002][.D164.0000.0000] -2F0A ; [.FB40.0020.0004][.D165.0000.0000] -2F814 ; [.FB40.0020.0002][.D167.0000.0000] -FA72 ; [.FB40.0020.0002][.D168.0000.0000] -F978 ; [.FB40.0020.0002][.D169.0000.0000] -2F0B ; [.FB40.0020.0004][.D16B.0000.0000] -3227 ; [*0310.0020.0004][.FB40.0020.0004][.D16B.0000.0000][*0311.0020.0004] -3287 ; [.FB40.0020.0006][.D16B.0000.0000] -F9D1 ; [.FB40.0020.0002][.D16D.0000.0000] -3225 ; [*0310.0020.0004][.FB40.0020.0004][.D16D.0000.0000][*0311.0020.0004] -3285 ; [.FB40.0020.0006][.D16D.0000.0000] -2F811 ; [.FB40.0020.0002][.D177.0000.0000] -FA75 ; [.FB40.0020.0002][.D180.0000.0000] -2F0C ; [.FB40.0020.0004][.D182.0000.0000] -2E86 ; [.FB40.0020.0004][.D182.0000.0000][.0000.010B.0004] -2F815 ; [.FB40.0020.0002][.D18D.0000.0000] -1F21E ; [.FB40.0020.001C][.D18D.0000.0000] -2F8D2 ; [.FB40.0020.0002][.D192.0000.0000] -2F8D3 ; [.FB40.0020.0002][.D195.0000.0000] -2F0D ; [.FB40.0020.0004][.D196.0000.0000] -2F817 ; [.FB40.0020.0002][.D197.0000.0000] -32A2 ; [.FB40.0020.0006][.D199.0000.0000] -2F818 ; [.FB40.0020.0002][.D1A4.0000.0000] -2F0E ; [.FB40.0020.0004][.D1AB.0000.0000] -2F81A ; [.FB40.0020.0002][.D1AC.0000.0000] -FA71 ; [.FB40.0020.0002][.D1B5.0000.0000] -2F81B ; [.FB40.0020.0002][.D1B5.0000.0000] -F92E ; [.FB40.0020.0002][.D1B7.0000.0000] -F979 ; [.FB40.0020.0002][.D1C9.0000.0000] -F955 ; [.FB40.0020.0002][.D1CC.0000.0000] -F954 ; [.FB40.0020.0002][.D1DC.0000.0000] -FA15 ; [.FB40.0020.0002][.D1DE.0000.0000] -2F0F ; [.FB40.0020.0004][.D1E0.0000.0000] -2E87 ; [.FB40.0020.0004][.D1E0.0000.0000][.0000.010B.0004] -2F81D ; [.FB40.0020.0002][.D1F5.0000.0000] -2F10 ; [.FB40.0020.0004][.D1F5.0000.0000] -2F11 ; [.FB40.0020.0004][.D200.0000.0000] -2E88 ; [.FB40.0020.0004][.D200.0000.0000][.0000.010B.0004] -2E89 ; [.FB40.0020.0004][.D202.0000.0000] -2F81E ; [.FB40.0020.0002][.D203.0000.0000] -FA00 ; [.FB40.0020.0002][.D207.0000.0000] -2F850 ; [.FB40.0020.0002][.D207.0000.0000] -F99C ; [.FB40.0020.0002][.D217.0000.0000] -1F220 ; [.FB40.0020.001C][.D21D.0000.0000] -F9DD ; [.FB40.0020.0002][.D229.0000.0000] -F9FF ; [.FB40.0020.0002][.D23A.0000.0000] -2F820 ; [.FB40.0020.0002][.D23B.0000.0000] -2F821 ; [.FB40.0020.0002][.D246.0000.0000] -1F21C ; [.FB40.0020.001C][.D24D.0000.0000] -2F822 ; [.FB40.0020.0002][.D272.0000.0000] -1F239 ; [.FB40.0020.001C][.D272.0000.0000] -2F823 ; [.FB40.0020.0002][.D277.0000.0000] -F9C7 ; [.FB40.0020.0002][.D289.0000.0000] -F98A ; [.FB40.0020.0002][.D29B.0000.0000] -2F12 ; [.FB40.0020.0004][.D29B.0000.0000] -F99D ; [.FB40.0020.0002][.D2A3.0000.0000] -2F992 ; [.FB40.0020.0002][.D2B3.0000.0000] -3238 ; [*0310.0020.0004][.FB40.0020.0004][.D2B4.0000.0000][*0311.0020.0004] -3298 ; [.FB40.0020.0006][.D2B4.0000.0000] -FA76 ; [.FB40.0020.0002][.D2C7.0000.0000] -2F825 ; [.FB40.0020.0002][.D2C7.0000.0000] -FA33 ; [.FB40.0020.0002][.D2C9.0000.0000] -2F826 ; [.FB40.0020.0002][.D2C9.0000.0000] -F952 ; [.FB40.0020.0002][.D2D2.0000.0000] -1F247 ; [*0372.0020.0004][.FB40.0020.0004][.D2DD.0000.0000][*0373.0020.0004] -F92F ; [.FB40.0020.0002][.D2DE.0000.0000] -FA34 ; [.FB40.0020.0002][.D2E4.0000.0000] -2F827 ; [.FB40.0020.0002][.D2E4.0000.0000] -F97F ; [.FB40.0020.0002][.D2F5.0000.0000] -2F13 ; [.FB40.0020.0004][.D2F9.0000.0000] -FA77 ; [.FB40.0020.0002][.D2FA.0000.0000] -2F828 ; [.FB40.0020.0002][.D2FA.0000.0000] -2F829 ; [.FB40.0020.0002][.D305.0000.0000] -2F82A ; [.FB40.0020.0002][.D306.0000.0000] -2F14 ; [.FB40.0020.0004][.D315.0000.0000] -F963 ; [.FB40.0020.0002][.D317.0000.0000] -2F82B ; [.FB40.0020.0002][.D317.0000.0000] -2F15 ; [.FB40.0020.0004][.D31A.0000.0000] -2F16 ; [.FB40.0020.0004][.D338.0000.0000] -32A9 ; [.FB40.0020.0006][.D33B.0000.0000] -F9EB ; [.FB40.0020.0002][.D33F.0000.0000] -2F17 ; [.FB40.0020.0004][.D341.0000.0000] -3038 ; [.FB40.0020.0004][.D341.0000.0000] -3229 ; [*0310.0020.0004][.FB40.0020.0004][.D341.0000.0000][*0311.0020.0004] -3289 ; [.FB40.0020.0006][.D341.0000.0000] -3039 ; [.FB40.0020.0004][.D344.0000.0000] -303A ; [.FB40.0020.0004][.D345.0000.0000] -2F82C ; [.FB40.0020.0002][.D349.0000.0000] -FA35 ; [.FB40.0020.0002][.D351.0000.0000] -2F82D ; [.FB40.0020.0002][.D351.0000.0000] -323F ; [*0310.0020.0004][.FB40.0020.0004][.D354.0000.0000][*0311.0020.0004] -32AF ; [.FB40.0020.0006][.D354.0000.0000] -2F82E ; [.FB40.0020.0002][.D35A.0000.0000] -2F18 ; [.FB40.0020.0004][.D35C.0000.0000] -2E8A ; [.FB40.0020.0004][.D35C.0000.0000][.0000.010B.0004] -2F19 ; [.FB40.0020.0004][.D369.0000.0000] -2E8B ; [.FB40.0020.0004][.D369.0000.0000][.0000.010B.0004] -329E ; [.FB40.0020.0006][.D370.0000.0000] -2F82F ; [.FB40.0020.0002][.D373.0000.0000] -F91C ; [.FB40.0020.0002][.D375.0000.0000] -2F830 ; [.FB40.0020.0002][.D37D.0000.0000] -2F831 ; [.FB40.0020.0002][.D37F.0000.0000] -2F832 ; [.FB40.0020.0002][.D37F.0000.0000] -2F833 ; [.FB40.0020.0002][.D37F.0000.0000] -2F1A ; [.FB40.0020.0004][.D382.0000.0000] -2E81 ; [.FB40.0020.0004][.D382.0000.0000][.0000.010B.0004] -2F1B ; [.FB40.0020.0004][.D3B6.0000.0000] -F96B ; [.FB40.0020.0002][.D3C3.0000.0000] -2F1C ; [.FB40.0020.0004][.D3C8.0000.0000] -2F836 ; [.FB40.0020.0002][.D3CA.0000.0000] -1F212 ; [.FB40.0020.001C][.D3CC.0000.0000] -2F837 ; [.FB40.0020.0002][.D3DF.0000.0000] -2F1D ; [.FB40.0020.0004][.D3E3.0000.0000] -F906 ; [.FB40.0020.0002][.D3E5.0000.0000] -2F839 ; [.FB40.0020.0002][.D3EB.0000.0000] -1F251 ; [.FB40.0020.0006][.D3EF.0000.0000] -2F83A ; [.FB40.0020.0002][.D3F1.0000.0000] -32A8 ; [.FB40.0020.0006][.D3F3.0000.0000] -1F22E ; [.FB40.0020.001C][.D3F3.0000.0000] -2F83B ; [.FB40.0020.0002][.D406.0000.0000] -1F234 ; [.FB40.0020.001C][.D408.0000.0000] -3234 ; [*0310.0020.0004][.FB40.0020.0004][.D40D.0000.0000][*0311.0020.0004] -3294 ; [.FB40.0020.0006][.D40D.0000.0000] -F9DE ; [.FB40.0020.0002][.D40F.0000.0000] -F9ED ; [.FB40.0020.0002][.D41D.0000.0000] -2F83D ; [.FB40.0020.0002][.D438.0000.0000] -1F225 ; [.FB40.0020.001C][.D439.0000.0000] -F980 ; [.FB40.0020.0002][.D442.0000.0000] -2F83E ; [.FB40.0020.0002][.D448.0000.0000] -2F83F ; [.FB40.0020.0002][.D468.0000.0000] -323A ; [*0310.0020.0004][.FB40.0020.0004][.D47C.0000.0000][*0311.0020.0004] -2F83C ; [.FB40.0020.0002][.D49E.0000.0000] -2F840 ; [.FB40.0020.0002][.D4A2.0000.0000] -F99E ; [.FB40.0020.0002][.D4BD.0000.0000] -2F841 ; [.FB40.0020.0002][.D4F6.0000.0000] -2F842 ; [.FB40.0020.0002][.D510.0000.0000] -3244 ; [.FB40.0020.0006][.D54F.0000.0000] -2F843 ; [.FB40.0020.0002][.D553.0000.0000] -FA79 ; [.FB40.0020.0002][.D555.0000.0000] -2F844 ; [.FB40.0020.0002][.D563.0000.0000] -2F845 ; [.FB40.0020.0002][.D584.0000.0000] -2F846 ; [.FB40.0020.0002][.D584.0000.0000] -F90B ; [.FB40.0020.0002][.D587.0000.0000] -FA7A ; [.FB40.0020.0002][.D599.0000.0000] -2F847 ; [.FB40.0020.0002][.D599.0000.0000] -FA36 ; [.FB40.0020.0002][.D59D.0000.0000] -FA78 ; [.FB40.0020.0002][.D59D.0000.0000] -2F848 ; [.FB40.0020.0002][.D5AB.0000.0000] -2F849 ; [.FB40.0020.0002][.D5B3.0000.0000] -1F23A ; [.FB40.0020.001C][.D5B6.0000.0000] -FA0D ; [.FB40.0020.0002][.D5C0.0000.0000] -2F84A ; [.FB40.0020.0002][.D5C2.0000.0000] -FA7B ; [.FB40.0020.0002][.D5E2.0000.0000] -FA37 ; [.FB40.0020.0002][.D606.0000.0000] -2F84C ; [.FB40.0020.0002][.D606.0000.0000] -2F84E ; [.FB40.0020.0002][.D651.0000.0000] -FA38 ; [.FB40.0020.0002][.D668.0000.0000] -2F84F ; [.FB40.0020.0002][.D674.0000.0000] -2F1E ; [.FB40.0020.0004][.D6D7.0000.0000] -3223 ; [*0310.0020.0004][.FB40.0020.0004][.D6DB.0000.0000][*0311.0020.0004] -3283 ; [.FB40.0020.0006][.D6DB.0000.0000] -3195 ; [.FB40.0020.0014][.D6DB.0000.0000] -F9A9 ; [.FB40.0020.0002][.D6F9.0000.0000] -2F84B ; [.FB40.0020.0002][.D716.0000.0000] -2F84D ; [.FB40.0020.0002][.D717.0000.0000] -2F1F ; [.FB40.0020.0004][.D71F.0000.0000] -322F ; [*0310.0020.0004][.FB40.0020.0004][.D71F.0000.0000][*0311.0020.0004] -328F ; [.FB40.0020.0006][.D71F.0000.0000] -319E ; [.FB40.0020.0014][.D730.0000.0000] -2F855 ; [.FB40.0020.0002][.D78B.0000.0000] -2F852 ; [.FB40.0020.0002][.D7CE.0000.0000] -2F853 ; [.FB40.0020.0002][.D7F4.0000.0000] -2F854 ; [.FB40.0020.0002][.D80D.0000.0000] -2F857 ; [.FB40.0020.0002][.D831.0000.0000] -2F856 ; [.FB40.0020.0002][.D832.0000.0000] -FA39 ; [.FB40.0020.0002][.D840.0000.0000] -FA10 ; [.FB40.0020.0002][.D85A.0000.0000] -FA7C ; [.FB40.0020.0002][.D85A.0000.0000] -F96C ; [.FB40.0020.0002][.D85E.0000.0000] -FA3A ; [.FB40.0020.0002][.D8A8.0000.0000] -2F858 ; [.FB40.0020.0002][.D8AC.0000.0000] -FA7D ; [.FB40.0020.0002][.D8B3.0000.0000] -F94A ; [.FB40.0020.0002][.D8D8.0000.0000] -F942 ; [.FB40.0020.0002][.D8DF.0000.0000] -2F20 ; [.FB40.0020.0004][.D8EB.0000.0000] -2F851 ; [.FB40.0020.0002][.D8EE.0000.0000] -1F224 ; [.FB40.0020.001C][.D8F0.0000.0000] -2F85A ; [.FB40.0020.0002][.D8F2.0000.0000] -2F85B ; [.FB40.0020.0002][.D8F7.0000.0000] -2F21 ; [.FB40.0020.0004][.D902.0000.0000] -2F85C ; [.FB40.0020.0002][.D906.0000.0000] -2F22 ; [.FB40.0020.0004][.D90A.0000.0000] -2F23 ; [.FB40.0020.0004][.D915.0000.0000] -2F85D ; [.FB40.0020.0002][.D91A.0000.0000] -1F215 ; [.FB40.0020.001C][.D91A.0000.0000] -32B0 ; [.FB40.0020.0006][.D91C.0000.0000] -2F85E ; [.FB40.0020.0002][.D922.0000.0000] -2F24 ; [.FB40.0020.0004][.D927.0000.0000] -337D ; [.FB40.0020.001C][.D927.0000.0000][.FB40.0020.001C][.EB63.0000.0000] -319D ; [.FB40.0020.0014][.D929.0000.0000] -1F217 ; [.FB40.0020.001C][.D929.0000.0000] -FA7E ; [.FB40.0020.0002][.D944.0000.0000] -F90C ; [.FB40.0020.0002][.D948.0000.0000] -F909 ; [.FB40.0020.0002][.D951.0000.0000] -FA7F ; [.FB40.0020.0002][.D954.0000.0000] -2F85F ; [.FB40.0020.0002][.D962.0000.0000] -F981 ; [.FB40.0020.0002][.D973.0000.0000] -2F25 ; [.FB40.0020.0004][.D973.0000.0000] -329B ; [.FB40.0020.0006][.D973.0000.0000] -2F865 ; [.FB40.0020.0002][.D9D8.0000.0000] -2F862 ; [.FB40.0020.0002][.D9EC.0000.0000] -2F863 ; [.FB40.0020.0002][.DA1B.0000.0000] -2F864 ; [.FB40.0020.0002][.DA27.0000.0000] -FA80 ; [.FB40.0020.0002][.DA62.0000.0000] -2F866 ; [.FB40.0020.0002][.DA66.0000.0000] -2F986 ; [.FB40.0020.0002][.DAB5.0000.0000] -2F869 ; [.FB40.0020.0002][.DB08.0000.0000] -FA81 ; [.FB40.0020.0002][.DB28.0000.0000] -2F86A ; [.FB40.0020.0002][.DB3E.0000.0000] -2F86B ; [.FB40.0020.0002][.DB3E.0000.0000] -2F26 ; [.FB40.0020.0004][.DB50.0000.0000] -1F211 ; [.FB40.0020.001C][.DB57.0000.0000] -323B ; [*0310.0020.0004][.FB40.0020.0004][.DB66.0000.0000][*0311.0020.0004] -32AB ; [.FB40.0020.0006][.DB66.0000.0000] -2F27 ; [.FB40.0020.0004][.DB80.0000.0000] -FA04 ; [.FB40.0020.0002][.DB85.0000.0000] -1F243 ; [*0372.0020.0004][.FB40.0020.0004][.DB89.0000.0000][*0373.0020.0004] -32AA ; [.FB40.0020.0006][.DB97.0000.0000] -2F86D ; [.FB40.0020.0002][.DBC3.0000.0000] -2F86E ; [.FB40.0020.0002][.DBD8.0000.0000] -F95F ; [.FB40.0020.0002][.DBE7.0000.0000] -F9AA ; [.FB40.0020.0002][.DBE7.0000.0000] -2F86F ; [.FB40.0020.0002][.DBE7.0000.0000] -F9BC ; [.FB40.0020.0002][.DBEE.0000.0000] -2F870 ; [.FB40.0020.0002][.DBF3.0000.0000] -2F28 ; [.FB40.0020.0004][.DBF8.0000.0000] -2F872 ; [.FB40.0020.0002][.DBFF.0000.0000] -2F873 ; [.FB40.0020.0002][.DC06.0000.0000] -2F29 ; [.FB40.0020.0004][.DC0F.0000.0000] -2E8C ; [.FB40.0020.0004][.DC0F.0000.0000][.0000.010B.0004] -2E8D ; [.FB40.0020.0004][.DC0F.0000.0000][.0000.010C.0004] -2F875 ; [.FB40.0020.0002][.DC22.0000.0000] -2E90 ; [.FB40.0020.0004][.DC22.0000.0000] -2F2A ; [.FB40.0020.0004][.DC22.0000.0000] -2E8E ; [.FB40.0020.0004][.DC22.0000.0000][.0000.010B.0004] -2E8F ; [.FB40.0020.0004][.DC23.0000.0000] -2E91 ; [.FB40.0020.0004][.DC23.0000.0000][.0000.010B.0004] -2F2B ; [.FB40.0020.0004][.DC38.0000.0000] -F9BD ; [.FB40.0020.0002][.DC3F.0000.0000] -2F877 ; [.FB40.0020.0002][.DC60.0000.0000] -F94B ; [.FB40.0020.0002][.DC62.0000.0000] -FA3B ; [.FB40.0020.0002][.DC64.0000.0000] -F9DF ; [.FB40.0020.0002][.DC65.0000.0000] -FA3C ; [.FB40.0020.0002][.DC6E.0000.0000] -2F878 ; [.FB40.0020.0002][.DC6E.0000.0000] -2F2C ; [.FB40.0020.0004][.DC6E.0000.0000] -2F2D ; [.FB40.0020.0004][.DC71.0000.0000] -2F87A ; [.FB40.0020.0002][.DC8D.0000.0000] -2F879 ; [.FB40.0020.0002][.DCC0.0000.0000] -F9D5 ; [.FB40.0020.0002][.DD19.0000.0000] -2F87C ; [.FB40.0020.0002][.DD43.0000.0000] -F921 ; [.FB40.0020.0002][.DD50.0000.0000] -2F87F ; [.FB40.0020.0002][.DD6B.0000.0000] -2F87E ; [.FB40.0020.0002][.DD6E.0000.0000] -2F880 ; [.FB40.0020.0002][.DD7C.0000.0000] -2F9F4 ; [.FB40.0020.0002][.DDB2.0000.0000] -F9AB ; [.FB40.0020.0002][.DDBA.0000.0000] -2F2E ; [.FB40.0020.0004][.DDDB.0000.0000] -2F881 ; [.FB40.0020.0002][.DDE1.0000.0000] -2F882 ; [.FB40.0020.0002][.DDE2.0000.0000] -2F2F ; [.FB40.0020.0004][.DDE5.0000.0000] -32A7 ; [.FB40.0020.0006][.DDE6.0000.0000] -1F22C ; [.FB40.0020.001C][.DDE6.0000.0000] -2F30 ; [.FB40.0020.0004][.DDF1.0000.0000] -2E92 ; [.FB40.0020.0004][.DDF3.0000.0000] -2F884 ; [.FB40.0020.0002][.DDFD.0000.0000] -2F31 ; [.FB40.0020.0004][.DDFE.0000.0000] -2F885 ; [.FB40.0020.0002][.DE28.0000.0000] -2F886 ; [.FB40.0020.0002][.DE3D.0000.0000] -2F887 ; [.FB40.0020.0002][.DE69.0000.0000] -2F32 ; [.FB40.0020.0004][.DE72.0000.0000] -337B ; [.FB40.0020.001C][.DE73.0000.0000][.FB40.0020.001C][.E210.0000.0000] -F98E ; [.FB40.0020.0002][.DE74.0000.0000] -2E93 ; [.FB40.0020.0004][.DE7A.0000.0000] -2F33 ; [.FB40.0020.0004][.DE7A.0000.0000] -3245 ; [.FB40.0020.0006][.DE7C.0000.0000] -2F34 ; [.FB40.0020.0004][.DE7F.0000.0000] -FA01 ; [.FB40.0020.0002][.DEA6.0000.0000] -2F88B ; [.FB40.0020.0002][.DEB0.0000.0000] -2F88C ; [.FB40.0020.0002][.DEB3.0000.0000] -2F88D ; [.FB40.0020.0002][.DEB6.0000.0000] -F9A2 ; [.FB40.0020.0002][.DEC9.0000.0000] -F928 ; [.FB40.0020.0002][.DECA.0000.0000] -2F88E ; [.FB40.0020.0002][.DECA.0000.0000] -FA82 ; [.FB40.0020.0002][.DED2.0000.0000] -FA0B ; [.FB40.0020.0002][.DED3.0000.0000] -FA83 ; [.FB40.0020.0002][.DED9.0000.0000] -F982 ; [.FB40.0020.0002][.DEEC.0000.0000] -2F35 ; [.FB40.0020.0004][.DEF4.0000.0000] -2F890 ; [.FB40.0020.0002][.DEFE.0000.0000] -2F36 ; [.FB40.0020.0004][.DEFE.0000.0000] -F943 ; [.FB40.0020.0002][.DF04.0000.0000] -2F37 ; [.FB40.0020.0004][.DF0B.0000.0000] -2F38 ; [.FB40.0020.0004][.DF13.0000.0000] -2F894 ; [.FB40.0020.0002][.DF22.0000.0000] -2F895 ; [.FB40.0020.0002][.DF22.0000.0000] -2F39 ; [.FB40.0020.0004][.DF50.0000.0000] -2E95 ; [.FB40.0020.0004][.DF50.0000.0000][.0000.010B.0004] -2E94 ; [.FB40.0020.0004][.DF51.0000.0000] -2F874 ; [.FB40.0020.0002][.DF53.0000.0000] -2F3A ; [.FB40.0020.0004][.DF61.0000.0000] -2F899 ; [.FB40.0020.0002][.DF62.0000.0000] -FA84 ; [.FB40.0020.0002][.DF69.0000.0000] -2F89A ; [.FB40.0020.0002][.DF6B.0000.0000] -2F3B ; [.FB40.0020.0004][.DF73.0000.0000] -F9D8 ; [.FB40.0020.0002][.DF8B.0000.0000] -1F21D ; [.FB40.0020.001C][.DF8C.0000.0000] -1F250 ; [.FB40.0020.0006][.DF97.0000.0000] -2F89C ; [.FB40.0020.0002][.DF9A.0000.0000] -F966 ; [.FB40.0020.0002][.DFA9.0000.0000] -FA85 ; [.FB40.0020.0002][.DFAD.0000.0000] -2F3C ; [.FB40.0020.0004][.DFC3.0000.0000] -2E97 ; [.FB40.0020.0004][.DFC3.0000.0000][.0000.010B.0004] -2E96 ; [.FB40.0020.0004][.DFC4.0000.0000] -2F89D ; [.FB40.0020.0002][.DFCD.0000.0000] -2F89E ; [.FB40.0020.0002][.DFD7.0000.0000] -F9A3 ; [.FB40.0020.0002][.DFF5.0000.0000] -2F89F ; [.FB40.0020.0002][.DFF9.0000.0000] -F960 ; [.FB40.0020.0002][.E012.0000.0000] -F9AC ; [.FB40.0020.0002][.E01C.0000.0000] -FA6B ; [.FB40.0020.0002][.E075.0000.0000] -2F8A0 ; [.FB40.0020.0002][.E081.0000.0000] -FA3D ; [.FB40.0020.0002][.E094.0000.0000] -2F8A3 ; [.FB40.0020.0002][.E094.0000.0000] -2F8A5 ; [.FB40.0020.0002][.E0C7.0000.0000] -FA86 ; [.FB40.0020.0002][.E0D8.0000.0000] -F9B9 ; [.FB40.0020.0002][.E0E1.0000.0000] -FA88 ; [.FB40.0020.0002][.E108.0000.0000] -F9D9 ; [.FB40.0020.0002][.E144.0000.0000] -2F8A6 ; [.FB40.0020.0002][.E148.0000.0000] -2F8A7 ; [.FB40.0020.0002][.E14C.0000.0000] -2F8A9 ; [.FB40.0020.0002][.E14C.0000.0000] -FA87 ; [.FB40.0020.0002][.E14E.0000.0000] -2F8A8 ; [.FB40.0020.0002][.E14E.0000.0000] -FA8A ; [.FB40.0020.0002][.E160.0000.0000] -FA3E ; [.FB40.0020.0002][.E168.0000.0000] -2F8AA ; [.FB40.0020.0002][.E17A.0000.0000] -FA3F ; [.FB40.0020.0002][.E18E.0000.0000] -FA89 ; [.FB40.0020.0002][.E18E.0000.0000] -2F8AB ; [.FB40.0020.0002][.E18E.0000.0000] -F98F ; [.FB40.0020.0002][.E190.0000.0000] -2F8AD ; [.FB40.0020.0002][.E1A4.0000.0000] -2F8AE ; [.FB40.0020.0002][.E1AF.0000.0000] -2F8AC ; [.FB40.0020.0002][.E1B2.0000.0000] -2F8AF ; [.FB40.0020.0002][.E1DE.0000.0000] -FA40 ; [.FB40.0020.0002][.E1F2.0000.0000] -FA8B ; [.FB40.0020.0002][.E1F2.0000.0000] -2F8B0 ; [.FB40.0020.0002][.E1F2.0000.0000] -F90D ; [.FB40.0020.0002][.E1F6.0000.0000] -2F8B1 ; [.FB40.0020.0002][.E1F6.0000.0000] -F990 ; [.FB40.0020.0002][.E200.0000.0000] -2F3D ; [.FB40.0020.0004][.E208.0000.0000] -2F8B2 ; [.FB40.0020.0002][.E210.0000.0000] -2F8B3 ; [.FB40.0020.0002][.E21B.0000.0000] -F9D2 ; [.FB40.0020.0002][.E22E.0000.0000] -FA8C ; [.FB40.0020.0002][.E234.0000.0000] -2F3E ; [.FB40.0020.0004][.E236.0000.0000] -2F3F ; [.FB40.0020.0004][.E24B.0000.0000] -1F210 ; [.FB40.0020.001C][.E24B.0000.0000] -2E98 ; [.FB40.0020.0004][.E24C.0000.0000] -1F245 ; [*0372.0020.0004][.FB40.0020.0004][.E253.0000.0000][*0373.0020.0004] -1F231 ; [.FB40.0020.001C][.E253.0000.0000] -2F8B4 ; [.FB40.0020.0002][.E25D.0000.0000] -1F227 ; [.FB40.0020.001C][.E295.0000.0000] -2F8B5 ; [.FB40.0020.0002][.E2B1.0000.0000] -F925 ; [.FB40.0020.0002][.E2C9.0000.0000] -F95B ; [.FB40.0020.0002][.E2CF.0000.0000] -FA02 ; [.FB40.0020.0002][.E2D3.0000.0000] -2F8B6 ; [.FB40.0020.0002][.E2D4.0000.0000] -2F8BA ; [.FB40.0020.0002][.E2FC.0000.0000] -F973 ; [.FB40.0020.0002][.E2FE.0000.0000] -1F22F ; [.FB40.0020.001C][.E307.0000.0000] -2F8B9 ; [.FB40.0020.0002][.E33D.0000.0000] -2F8B7 ; [.FB40.0020.0002][.E350.0000.0000] -1F228 ; [.FB40.0020.001C][.E355.0000.0000] -2F8BB ; [.FB40.0020.0002][.E368.0000.0000] -F9A4 ; [.FB40.0020.0002][.E37B.0000.0000] -2F8BC ; [.FB40.0020.0002][.E383.0000.0000] -F975 ; [.FB40.0020.0002][.E3A0.0000.0000] -2F8C1 ; [.FB40.0020.0002][.E3A9.0000.0000] -FA8D ; [.FB40.0020.0002][.E3C4.0000.0000] -2F8C0 ; [.FB40.0020.0002][.E3C5.0000.0000] -2F8BD ; [.FB40.0020.0002][.E3E4.0000.0000] -FA8E ; [.FB40.0020.0002][.E41C.0000.0000] -2F8BF ; [.FB40.0020.0002][.E422.0000.0000] -FA8F ; [.FB40.0020.0002][.E452.0000.0000] -2F8C3 ; [.FB40.0020.0002][.E469.0000.0000] -2F8C6 ; [.FB40.0020.0002][.E477.0000.0000] -2F8C4 ; [.FB40.0020.0002][.E47E.0000.0000] -F991 ; [.FB40.0020.0002][.E49A.0000.0000] -2F8C5 ; [.FB40.0020.0002][.E49D.0000.0000] -F930 ; [.FB40.0020.0002][.E4C4.0000.0000] -2F40 ; [.FB40.0020.0004][.E52F.0000.0000] -2F41 ; [.FB40.0020.0004][.E534.0000.0000] -2E99 ; [.FB40.0020.0004][.E535.0000.0000] -FA41 ; [.FB40.0020.0002][.E54F.0000.0000] -2F8C8 ; [.FB40.0020.0002][.E54F.0000.0000] -FA90 ; [.FB40.0020.0002][.E556.0000.0000] -1F248 ; [*0372.0020.0004][.FB40.0020.0004][.E557.0000.0000][*0373.0020.0004] -2F8C9 ; [.FB40.0020.0002][.E56C.0000.0000] -F969 ; [.FB40.0020.0002][.E578.0000.0000] -2F42 ; [.FB40.0020.0004][.E587.0000.0000] -3246 ; [.FB40.0020.0006][.E587.0000.0000] -2F43 ; [.FB40.0020.0004][.E597.0000.0000] -F9BE ; [.FB40.0020.0002][.E599.0000.0000] -1F21B ; [.FB40.0020.001C][.E599.0000.0000] -2F44 ; [.FB40.0020.0004][.E5A4.0000.0000] -1F21F ; [.FB40.0020.001C][.E5B0.0000.0000] -2F45 ; [.FB40.0020.0004][.E5B9.0000.0000] -F983 ; [.FB40.0020.0002][.E5C5.0000.0000] -2F46 ; [.FB40.0020.0004][.E5E0.0000.0000] -2E9B ; [.FB40.0020.0004][.E5E1.0000.0000] -FA42 ; [.FB40.0020.0002][.E5E2.0000.0000] -2F8CB ; [.FB40.0020.0002][.E5E3.0000.0000] -2F47 ; [.FB40.0020.0004][.E5E5.0000.0000] -3230 ; [*0310.0020.0004][.FB40.0020.0004][.E5E5.0000.0000][*0311.0020.0004] -3290 ; [.FB40.0020.0006][.E5E5.0000.0000] -2E9C ; [.FB40.0020.0004][.E5E5.0000.0000][.0000.010B.0004] -337E ; [.FB40.0020.001C][.E60E.0000.0000][.FB40.0020.001C][.ECBB.0000.0000] -F9E0 ; [.FB40.0020.0002][.E613.0000.0000] -1F219 ; [.FB40.0020.001C][.E620.0000.0000] -337C ; [.FB40.0020.001C][.E62D.0000.0000][.FB40.0020.001C][.D48C.0000.0000] -2F8CD ; [.FB40.0020.0002][.E649.0000.0000] -FA12 ; [.FB40.0020.0002][.E674.0000.0000] -FA91 ; [.FB40.0020.0002][.E674.0000.0000] -F9C5 ; [.FB40.0020.0002][.E688.0000.0000] -FA43 ; [.FB40.0020.0002][.E691.0000.0000] -2F8CF ; [.FB40.0020.0002][.E691.0000.0000] -2F8D5 ; [.FB40.0020.0002][.E69C.0000.0000] -FA06 ; [.FB40.0020.0002][.E6B4.0000.0000] -F98B ; [.FB40.0020.0002][.E6C6.0000.0000] -2F48 ; [.FB40.0020.0004][.E6F0.0000.0000] -F901 ; [.FB40.0020.0002][.E6F4.0000.0000] -2F8CC ; [.FB40.0020.0002][.E6F8.0000.0000] -2F8D4 ; [.FB40.0020.0002][.E700.0000.0000] -2F49 ; [.FB40.0020.0004][.E708.0000.0000] -322A ; [*0310.0020.0004][.FB40.0020.0004][.E708.0000.0000][*0311.0020.0004] -328A ; [.FB40.0020.0006][.E708.0000.0000] -1F237 ; [.FB40.0020.001C][.E708.0000.0000] -2E9D ; [.FB40.0020.0004][.E708.0000.0000][.0000.010B.0004] -3232 ; [*0310.0020.0004][.FB40.0020.0004][.E709.0000.0000][*0311.0020.0004] -3292 ; [.FB40.0020.0006][.E709.0000.0000] -1F236 ; [.FB40.0020.001C][.E709.0000.0000] -F929 ; [.FB40.0020.0002][.E717.0000.0000] -FA92 ; [.FB40.0020.0002][.E717.0000.0000] -2F8D8 ; [.FB40.0020.0002][.E717.0000.0000] -FA93 ; [.FB40.0020.0002][.E71B.0000.0000] -2F8D9 ; [.FB40.0020.0002][.E71B.0000.0000] -2F8DA ; [.FB40.0020.0002][.E721.0000.0000] -2F4A ; [.FB40.0020.0004][.E728.0000.0000] -322D ; [*0310.0020.0004][.FB40.0020.0004][.E728.0000.0000][*0311.0020.0004] -328D ; [.FB40.0020.0006][.E728.0000.0000] -1F240 ; [*0372.0020.0004][.FB40.0020.0004][.E72C.0000.0000][*0373.0020.0004] -F9E1 ; [.FB40.0020.0002][.E74E.0000.0000] -2F8DC ; [.FB40.0020.0002][.E753.0000.0000] -FA94 ; [.FB40.0020.0002][.E756.0000.0000] -2F8DB ; [.FB40.0020.0002][.E75E.0000.0000] -F9C8 ; [.FB40.0020.0002][.E77B.0000.0000] -2F8E0 ; [.FB40.0020.0002][.E785.0000.0000] -F9F4 ; [.FB40.0020.0002][.E797.0000.0000] -F9C9 ; [.FB40.0020.0002][.E7F3.0000.0000] -2F8DF ; [.FB40.0020.0002][.E7FA.0000.0000] -F9DA ; [.FB40.0020.0002][.E817.0000.0000] -2F8E5 ; [.FB40.0020.0002][.E81F.0000.0000] -3231 ; [*0310.0020.0004][.FB40.0020.0004][.E82A.0000.0000][*0311.0020.0004] -3291 ; [.FB40.0020.0006][.E82A.0000.0000] -337F ; [.FB40.0020.001C][.E82A.0000.0000][.FB40.0020.001C][.DF0F.0000.0000][.FB40.0020.001C][.CF1A.0000.0000][.FB40.0020.001C][.F93E.0000.0000] -2F8E1 ; [.FB40.0020.0002][.E852.0000.0000] -F97A ; [.FB40.0020.0002][.E881.0000.0000] -FA44 ; [.FB40.0020.0002][.E885.0000.0000] -2F8E2 ; [.FB40.0020.0002][.E885.0000.0000] -2F8E4 ; [.FB40.0020.0002][.E88E.0000.0000] -F9E2 ; [.FB40.0020.0002][.E8A8.0000.0000] -2F8E6 ; [.FB40.0020.0002][.E914.0000.0000] -2F8E8 ; [.FB40.0020.0002][.E942.0000.0000] -2F8E9 ; [.FB40.0020.0002][.E9A3.0000.0000] -2F8EA ; [.FB40.0020.0002][.E9EA.0000.0000] -F914 ; [.FB40.0020.0002][.EA02.0000.0000] -F95C ; [.FB40.0020.0002][.EA02.0000.0000] -F9BF ; [.FB40.0020.0002][.EA02.0000.0000] -F94C ; [.FB40.0020.0002][.EA13.0000.0000] -2F8EB ; [.FB40.0020.0002][.EAA8.0000.0000] -F931 ; [.FB40.0020.0002][.EAD3.0000.0000] -2F8ED ; [.FB40.0020.0002][.EADB.0000.0000] -F91D ; [.FB40.0020.0002][.EB04.0000.0000] -2F4B ; [.FB40.0020.0004][.EB20.0000.0000] -2F8EF ; [.FB40.0020.0002][.EB21.0000.0000] -2F8F1 ; [.FB40.0020.0002][.EB54.0000.0000] -2F4C ; [.FB40.0020.0004][.EB62.0000.0000] -32A3 ; [.FB40.0020.0006][.EB63.0000.0000] -2F8F3 ; [.FB40.0020.0002][.EB72.0000.0000] -F98C ; [.FB40.0020.0002][.EB77.0000.0000] -FA95 ; [.FB40.0020.0002][.EB79.0000.0000] -2F4D ; [.FB40.0020.0004][.EB79.0000.0000] -2E9E ; [.FB40.0020.0004][.EB7A.0000.0000][.0000.010B.0004] -2F8F4 ; [.FB40.0020.0002][.EB9F.0000.0000] -F9A5 ; [.FB40.0020.0002][.EBAE.0000.0000] -2F4E ; [.FB40.0020.0004][.EBB3.0000.0000] -F970 ; [.FB40.0020.0002][.EBBA.0000.0000] -FA96 ; [.FB40.0020.0002][.EBBA.0000.0000] -2F8F5 ; [.FB40.0020.0002][.EBBA.0000.0000] -2F8F6 ; [.FB40.0020.0002][.EBBB.0000.0000] -2F4F ; [.FB40.0020.0004][.EBCB.0000.0000] -2E9F ; [.FB40.0020.0004][.EBCD.0000.0000] -2F50 ; [.FB40.0020.0004][.EBD4.0000.0000] -2F51 ; [.FB40.0020.0004][.EBDB.0000.0000] -2F52 ; [.FB40.0020.0004][.EC0F.0000.0000] -2EA0 ; [.FB40.0020.0004][.EC11.0000.0000] -2F53 ; [.FB40.0020.0004][.EC14.0000.0000] -2F54 ; [.FB40.0020.0004][.EC34.0000.0000] -322C ; [*0310.0020.0004][.FB40.0020.0004][.EC34.0000.0000][*0311.0020.0004] -328C ; [.FB40.0020.0006][.EC34.0000.0000] -2EA1 ; [.FB40.0020.0004][.EC35.0000.0000] -2EA2 ; [.FB40.0020.0004][.EC3A.0000.0000] -2F8FA ; [.FB40.0020.0002][.EC4E.0000.0000] -2F8FE ; [.FB40.0020.0002][.EC67.0000.0000] -F972 ; [.FB40.0020.0002][.EC88.0000.0000] -2F8FC ; [.FB40.0020.0002][.ECBF.0000.0000] -F968 ; [.FB40.0020.0002][.ECCC.0000.0000] -2F8FD ; [.FB40.0020.0002][.ECCD.0000.0000] -F9E3 ; [.FB40.0020.0002][.ECE5.0000.0000] -329F ; [.FB40.0020.0006][.ECE8.0000.0000] -2F8FF ; [.FB40.0020.0002][.ED16.0000.0000] -F915 ; [.FB40.0020.0002][.ED1B.0000.0000] -FA05 ; [.FB40.0020.0002][.ED1E.0000.0000] -2F907 ; [.FB40.0020.0002][.ED34.0000.0000] -2F900 ; [.FB40.0020.0002][.ED3E.0000.0000] -F9CA ; [.FB40.0020.0002][.ED41.0000.0000] -FA97 ; [.FB40.0020.0002][.ED41.0000.0000] -2F902 ; [.FB40.0020.0002][.ED41.0000.0000] -2F903 ; [.FB40.0020.0002][.ED69.0000.0000] -F92A ; [.FB40.0020.0002][.ED6A.0000.0000] -FA45 ; [.FB40.0020.0002][.ED77.0000.0000] -2F901 ; [.FB40.0020.0002][.ED77.0000.0000] -2F904 ; [.FB40.0020.0002][.ED78.0000.0000] -2F905 ; [.FB40.0020.0002][.ED85.0000.0000] -F9F5 ; [.FB40.0020.0002][.EDCB.0000.0000] -F94D ; [.FB40.0020.0002][.EDDA.0000.0000] -F9D6 ; [.FB40.0020.0002][.EDEA.0000.0000] -2F90E ; [.FB40.0020.0002][.EDF9.0000.0000] -FA46 ; [.FB40.0020.0002][.EE1A.0000.0000] -2F908 ; [.FB40.0020.0002][.EE2F.0000.0000] -2F909 ; [.FB40.0020.0002][.EE6E.0000.0000] -1F235 ; [.FB40.0020.001C][.EE80.0000.0000] -F9CB ; [.FB40.0020.0002][.EE9C.0000.0000] -F9EC ; [.FB40.0020.0002][.EEBA.0000.0000] -2F90C ; [.FB40.0020.0002][.EEC7.0000.0000] -FA99 ; [.FB40.0020.0002][.EECB.0000.0000] -2F90B ; [.FB40.0020.0002][.EECB.0000.0000] -F904 ; [.FB40.0020.0002][.EED1.0000.0000] -FA98 ; [.FB40.0020.0002][.EEDB.0000.0000] -F94E ; [.FB40.0020.0002][.EF0F.0000.0000] -1F226 ; [.FB40.0020.001C][.EF14.0000.0000] -FA47 ; [.FB40.0020.0002][.EF22.0000.0000] -FA9A ; [.FB40.0020.0002][.EF22.0000.0000] -F992 ; [.FB40.0020.0002][.EF23.0000.0000] -2F90F ; [.FB40.0020.0002][.EF6E.0000.0000] -2F912 ; [.FB40.0020.0002][.EFC6.0000.0000] -F922 ; [.FB40.0020.0002][.EFEB.0000.0000] -F984 ; [.FB40.0020.0002][.EFFE.0000.0000] -2F915 ; [.FB40.0020.0002][.F01B.0000.0000] -FA9B ; [.FB40.0020.0002][.F01E.0000.0000] -2F914 ; [.FB40.0020.0002][.F01E.0000.0000] -2F913 ; [.FB40.0020.0002][.F039.0000.0000] -2F917 ; [.FB40.0020.0002][.F04A.0000.0000] -2F55 ; [.FB40.0020.0004][.F06B.0000.0000] -322B ; [*0310.0020.0004][.FB40.0020.0004][.F06B.0000.0000][*0311.0020.0004] -328B ; [.FB40.0020.0006][.F06B.0000.0000] -2EA3 ; [.FB40.0020.0004][.F06C.0000.0000] -2F835 ; [.FB40.0020.0002][.F070.0000.0000] -2F919 ; [.FB40.0020.0002][.F077.0000.0000] -2F918 ; [.FB40.0020.0002][.F07D.0000.0000] -F9FB ; [.FB40.0020.0002][.F099.0000.0000] -2F91A ; [.FB40.0020.0002][.F0AD.0000.0000] -1F244 ; [*0372.0020.0004][.FB40.0020.0004][.F0B9.0000.0000][*0373.0020.0004] -F99F ; [.FB40.0020.0002][.F0C8.0000.0000] -F916 ; [.FB40.0020.0002][.F0D9.0000.0000] -1F21A ; [.FB40.0020.001C][.F121.0000.0000] -2F91C ; [.FB40.0020.0002][.F145.0000.0000] -F993 ; [.FB40.0020.0002][.F149.0000.0000] -FA48 ; [.FB40.0020.0002][.F16E.0000.0000] -FA9C ; [.FB40.0020.0002][.F16E.0000.0000] -2F91E ; [.FB40.0020.0002][.F19C.0000.0000] -F9C0 ; [.FB40.0020.0002][.F1CE.0000.0000] -F9EE ; [.FB40.0020.0002][.F1D0.0000.0000] -F932 ; [.FB40.0020.0002][.F210.0000.0000] -F91E ; [.FB40.0020.0002][.F21B.0000.0000] -2F920 ; [.FB40.0020.0002][.F228.0000.0000] -2F56 ; [.FB40.0020.0004][.F22A.0000.0000] -FA49 ; [.FB40.0020.0002][.F22B.0000.0000] -2EA4 ; [.FB40.0020.0004][.F22B.0000.0000] -2EA5 ; [.FB40.0020.0004][.F22B.0000.0000][.0000.010B.0004] -FA9E ; [.FB40.0020.0002][.F235.0000.0000] -2F921 ; [.FB40.0020.0002][.F235.0000.0000] -2F57 ; [.FB40.0020.0004][.F236.0000.0000] -2F58 ; [.FB40.0020.0004][.F23B.0000.0000] -2F59 ; [.FB40.0020.0004][.F23F.0000.0000] -2F5A ; [.FB40.0020.0004][.F247.0000.0000] -2F922 ; [.FB40.0020.0002][.F250.0000.0000] -2F5B ; [.FB40.0020.0004][.F259.0000.0000] -2F5C ; [.FB40.0020.0004][.F25B.0000.0000] -2EA7 ; [.FB40.0020.0004][.F25B.0000.0000][.0000.010B.0004] -F946 ; [.FB40.0020.0002][.F262.0000.0000] -3235 ; [*0310.0020.0004][.FB40.0020.0004][.F279.0000.0000][*0311.0020.0004] -3295 ; [.FB40.0020.0006][.F279.0000.0000] -2F924 ; [.FB40.0020.0002][.F280.0000.0000] -2F925 ; [.FB40.0020.0002][.F295.0000.0000] -2F5D ; [.FB40.0020.0004][.F2AC.0000.0000] -2EA8 ; [.FB40.0020.0004][.F2AD.0000.0000] -FA9F ; [.FB40.0020.0002][.F2AF.0000.0000] -F9FA ; [.FB40.0020.0002][.F2C0.0000.0000] -F92B ; [.FB40.0020.0002][.F2FC.0000.0000] -FA16 ; [.FB40.0020.0002][.F32A.0000.0000] -FAA0 ; [.FB40.0020.0002][.F32A.0000.0000] -F9A7 ; [.FB40.0020.0002][.F375.0000.0000] -2F928 ; [.FB40.0020.0002][.F37A.0000.0000] -2F5E ; [.FB40.0020.0004][.F384.0000.0000] -F961 ; [.FB40.0020.0002][.F387.0000.0000] -F9DB ; [.FB40.0020.0002][.F387.0000.0000] -2F5F ; [.FB40.0020.0004][.F389.0000.0000] -2F929 ; [.FB40.0020.0002][.F38B.0000.0000] -2EA9 ; [.FB40.0020.0004][.F38B.0000.0000][.0000.010B.0004] -2F92B ; [.FB40.0020.0002][.F3A5.0000.0000] -F9AD ; [.FB40.0020.0002][.F3B2.0000.0000] -F917 ; [.FB40.0020.0002][.F3DE.0000.0000] -F9E4 ; [.FB40.0020.0002][.F406.0000.0000] -F9CC ; [.FB40.0020.0002][.F409.0000.0000] -FA4A ; [.FB40.0020.0002][.F422.0000.0000] -2F92E ; [.FB40.0020.0002][.F447.0000.0000] -2F92F ; [.FB40.0020.0002][.F45C.0000.0000] -F9AE ; [.FB40.0020.0002][.F469.0000.0000] -FAA1 ; [.FB40.0020.0002][.F471.0000.0000] -2F930 ; [.FB40.0020.0002][.F471.0000.0000] -2F931 ; [.FB40.0020.0002][.F485.0000.0000] -F994 ; [.FB40.0020.0002][.F489.0000.0000] -F9EF ; [.FB40.0020.0002][.F498.0000.0000] -2F932 ; [.FB40.0020.0002][.F4CA.0000.0000] -2F60 ; [.FB40.0020.0004][.F4DC.0000.0000] -2F61 ; [.FB40.0020.0004][.F4E6.0000.0000] -FAA2 ; [.FB40.0020.0002][.F506.0000.0000] -2F62 ; [.FB40.0020.0004][.F518.0000.0000] -2F63 ; [.FB40.0020.0004][.F51F.0000.0000] -1F222 ; [.FB40.0020.001C][.F51F.0000.0000] -2F934 ; [.FB40.0020.0002][.F524.0000.0000] -2F64 ; [.FB40.0020.0004][.F528.0000.0000] -2F65 ; [.FB40.0020.0004][.F530.0000.0000] -3199 ; [.FB40.0020.0014][.F532.0000.0000] -1F238 ; [.FB40.0020.001C][.F533.0000.0000] -329A ; [.FB40.0020.0006][.F537.0000.0000] -FAA3 ; [.FB40.0020.0002][.F53B.0000.0000] -2F936 ; [.FB40.0020.0002][.F53E.0000.0000] -F9CD ; [.FB40.0020.0002][.F559.0000.0000] -F976 ; [.FB40.0020.0002][.F565.0000.0000] -F962 ; [.FB40.0020.0002][.F570.0000.0000] -2F938 ; [.FB40.0020.0002][.F570.0000.0000] -2F66 ; [.FB40.0020.0004][.F58B.0000.0000] -2EAA ; [.FB40.0020.0004][.F58B.0000.0000][.0000.010B.0004] -2F67 ; [.FB40.0020.0004][.F592.0000.0000] -F9E5 ; [.FB40.0020.0002][.F5E2.0000.0000] -2F93A ; [.FB40.0020.0002][.F610.0000.0000] -FAA4 ; [.FB40.0020.0002][.F61D.0000.0000] -FAA5 ; [.FB40.0020.0002][.F61F.0000.0000] -F9C1 ; [.FB40.0020.0002][.F642.0000.0000] -F90E ; [.FB40.0020.0002][.F669.0000.0000] -2F68 ; [.FB40.0020.0004][.F676.0000.0000] -2F69 ; [.FB40.0020.0004][.F67D.0000.0000] -2F6A ; [.FB40.0020.0004][.F6AE.0000.0000] -2F6B ; [.FB40.0020.0004][.F6BF.0000.0000] -FA17 ; [.FB40.0020.0002][.F6CA.0000.0000] -FAA6 ; [.FB40.0020.0002][.F6CA.0000.0000] -1F246 ; [*0372.0020.0004][.FB40.0020.0004][.F6D7.0000.0000][*0373.0020.0004] -FAA7 ; [.FB40.0020.0002][.F6DB.0000.0000] -323C ; [*0310.0020.0004][.FB40.0020.0004][.F6E3.0000.0000][*0311.0020.0004] -32AC ; [.FB40.0020.0006][.F6E3.0000.0000] -F933 ; [.FB40.0020.0002][.F6E7.0000.0000] -2F6C ; [.FB40.0020.0004][.F6EE.0000.0000] -2EAB ; [.FB40.0020.0004][.F6EE.0000.0000][.0000.010B.0004] -FAA8 ; [.FB40.0020.0002][.F6F4.0000.0000] -2F940 ; [.FB40.0020.0002][.F6F4.0000.0000] -F96D ; [.FB40.0020.0002][.F701.0000.0000] -2F945 ; [.FB40.0020.0002][.F71E.0000.0000] -2F946 ; [.FB40.0020.0002][.F71F.0000.0000] -2F947 ; [.FB40.0020.0002][.F71F.0000.0000] -FAAA ; [.FB40.0020.0002][.F740.0000.0000] -FAA9 ; [.FB40.0020.0002][.F74A.0000.0000] -2F948 ; [.FB40.0020.0002][.F74A.0000.0000] -2F94A ; [.FB40.0020.0002][.F78B.0000.0000] -FA9D ; [.FB40.0020.0002][.F7A7.0000.0000] -2F6D ; [.FB40.0020.0004][.F7DB.0000.0000] -2F6E ; [.FB40.0020.0004][.F7E2.0000.0000] -2F6F ; [.FB40.0020.0004][.F7F3.0000.0000] -2F94E ; [.FB40.0020.0002][.F84E.0000.0000] -F9CE ; [.FB40.0020.0002][.F86B.0000.0000] -F93B ; [.FB40.0020.0002][.F88C.0000.0000] -2F94F ; [.FB40.0020.0002][.F88C.0000.0000] -FA4B ; [.FB40.0020.0002][.F891.0000.0000] -F947 ; [.FB40.0020.0002][.F8CA.0000.0000] -FAAB ; [.FB40.0020.0002][.F8CC.0000.0000] -2F950 ; [.FB40.0020.0002][.F8CC.0000.0000] -F964 ; [.FB40.0020.0002][.F8FB.0000.0000] -F985 ; [.FB40.0020.0002][.F92A.0000.0000] -2F70 ; [.FB40.0020.0004][.F93A.0000.0000] -2EAC ; [.FB40.0020.0004][.F93A.0000.0000][.0000.010B.0004] -2EAD ; [.FB40.0020.0004][.F93B.0000.0000] -FA18 ; [.FB40.0020.0002][.F93C.0000.0000] -FA4C ; [.FB40.0020.0002][.F93E.0000.0000] -3233 ; [*0310.0020.0004][.FB40.0020.0004][.F93E.0000.0000][*0311.0020.0004] -3293 ; [.FB40.0020.0006][.F93E.0000.0000] -FA4E ; [.FB40.0020.0002][.F948.0000.0000] -FA4D ; [.FB40.0020.0002][.F949.0000.0000] -FA4F ; [.FB40.0020.0002][.F950.0000.0000] -FA50 ; [.FB40.0020.0002][.F956.0000.0000] -2F953 ; [.FB40.0020.0002][.F956.0000.0000] -FA51 ; [.FB40.0020.0002][.F95D.0000.0000] -3237 ; [*0310.0020.0004][.FB40.0020.0004][.F95D.0000.0000][*0311.0020.0004] -3297 ; [.FB40.0020.0006][.F95D.0000.0000] -FA19 ; [.FB40.0020.0002][.F95E.0000.0000] -FA1A ; [.FB40.0020.0002][.F965.0000.0000] -3240 ; [*0310.0020.0004][.FB40.0020.0004][.F96D.0000.0000][*0311.0020.0004] -F93C ; [.FB40.0020.0002][.F97F.0000.0000] -1F232 ; [.FB40.0020.001C][.F981.0000.0000] -FA52 ; [.FB40.0020.0002][.F98D.0000.0000] -FA53 ; [.FB40.0020.0002][.F98E.0000.0000] -FA1B ; [.FB40.0020.0002][.F98F.0000.0000] -2F956 ; [.FB40.0020.0002][.F98F.0000.0000] -F9B6 ; [.FB40.0020.0002][.F9AE.0000.0000] -2F71 ; [.FB40.0020.0004][.F9B8.0000.0000] -2F72 ; [.FB40.0020.0004][.F9BE.0000.0000] -F995 ; [.FB40.0020.0002][.F9CA.0000.0000] -3299 ; [.FB40.0020.0006][.F9D8.0000.0000] -2F957 ; [.FB40.0020.0002][.F9EB.0000.0000] -F956 ; [.FB40.0020.0002][.FA1C.0000.0000] -FA54 ; [.FB40.0020.0002][.FA40.0000.0000] -2F959 ; [.FB40.0020.0002][.FA40.0000.0000] -2F95A ; [.FB40.0020.0002][.FA4A.0000.0000] -2F95B ; [.FB40.0020.0002][.FA4F.0000.0000] -2F73 ; [.FB40.0020.0004][.FA74.0000.0000] -1F233 ; [.FB40.0020.001C][.FA7A.0000.0000] -FA55 ; [.FB40.0020.0002][.FA81.0000.0000] -FAAC ; [.FB40.0020.0002][.FAB1.0000.0000] -F9F7 ; [.FB40.0020.0002][.FACB.0000.0000] -2F74 ; [.FB40.0020.0004][.FACB.0000.0000] -2F95F ; [.FB40.0020.0002][.FAEE.0000.0000] -2F75 ; [.FB40.0020.0004][.FAF9.0000.0000] -2EAE ; [.FB40.0020.0004][.FAF9.0000.0000][.0000.010B.0004] -F9F8 ; [.FB40.0020.0002][.FB20.0000.0000] -3247 ; [.FB40.0020.0006][.FB8F.0000.0000] -FA56 ; [.FB40.0020.0002][.FBC0.0000.0000] -FAAD ; [.FB40.0020.0002][.FBC0.0000.0000] -2F962 ; [.FB40.0020.0002][.FBC6.0000.0000] -2F963 ; [.FB40.0020.0002][.FBC9.0000.0000] -F9A6 ; [.FB40.0020.0002][.FC3E.0000.0000] -F944 ; [.FB40.0020.0002][.FC60.0000.0000] -2F76 ; [.FB40.0020.0004][.FC73.0000.0000] -FAAE ; [.FB40.0020.0002][.FC7B.0000.0000] -F9F9 ; [.FB40.0020.0002][.FC92.0000.0000] -FA1D ; [.FB40.0020.0002][.FCBE.0000.0000] -2F966 ; [.FB40.0020.0002][.FCD2.0000.0000] -FA03 ; [.FB40.0020.0002][.FCD6.0000.0000] -2F969 ; [.FB40.0020.0002][.FCE3.0000.0000] -F97B ; [.FB40.0020.0002][.FCE7.0000.0000] -2F968 ; [.FB40.0020.0002][.FCE8.0000.0000] -2F77 ; [.FB40.0020.0004][.FCF8.0000.0000] -2EAF ; [.FB40.0020.0004][.FCF9.0000.0000] -2F96A ; [.FB40.0020.0002][.FD00.0000.0000] -F9CF ; [.FB40.0020.0002][.FD10.0000.0000] -F96A ; [.FB40.0020.0002][.FD22.0000.0000] -F94F ; [.FB40.0020.0002][.FD2F.0000.0000] -1F221 ; [.FB40.0020.001C][.FD42.0000.0000] -FAAF ; [.FB40.0020.0002][.FD5B.0000.0000] -2F96C ; [.FB40.0020.0002][.FD63.0000.0000] -F93D ; [.FB40.0020.0002][.FDA0.0000.0000] -F957 ; [.FB40.0020.0002][.FDBE.0000.0000] -2F96E ; [.FB40.0020.0002][.FDC7.0000.0000] -F996 ; [.FB40.0020.0002][.FDF4.0000.0000] -FA57 ; [.FB40.0020.0002][.FDF4.0000.0000] -FAB0 ; [.FB40.0020.0002][.FDF4.0000.0000] -2F96F ; [.FB40.0020.0002][.FE02.0000.0000] -FA58 ; [.FB40.0020.0002][.FE09.0000.0000] -F950 ; [.FB40.0020.0002][.FE37.0000.0000] -FA59 ; [.FB40.0020.0002][.FE41.0000.0000] -2F970 ; [.FB40.0020.0002][.FE45.0000.0000] -2EB0 ; [.FB40.0020.0004][.FE9F.0000.0000] -2F78 ; [.FB40.0020.0004][.FF36.0000.0000] -FAB1 ; [.FB40.0020.0002][.FF3E.0000.0000] -2F79 ; [.FB40.0020.0004][.FF51.0000.0000] -2EB2 ; [.FB40.0020.0004][.FF52.0000.0000] -2EB5 ; [.FB40.0020.0004][.FF52.0000.0000][.0000.010B.0004] -2EB1 ; [.FB40.0020.0004][.FF53.0000.0000] -2EB3 ; [.FB40.0020.0004][.FF53.0000.0000][.0000.010B.0004] -2EB4 ; [.FB40.0020.0004][.FF53.0000.0000][.0000.010C.0004] -FA5A ; [.FB40.0020.0002][.FF72.0000.0000] -F9E6 ; [.FB40.0020.0002][.FF79.0000.0000] -2F976 ; [.FB40.0020.0002][.FF7A.0000.0000] -F90F ; [.FB40.0020.0002][.FF85.0000.0000] -2F7A ; [.FB40.0020.0004][.FF8A.0000.0000] -2EB6 ; [.FB40.0020.0004][.FF8A.0000.0000][.0000.010B.0004] -2EB7 ; [.FB40.0020.0004][.FF8A.0000.0000][.0000.010C.0004] -2EB8 ; [.FB40.0020.0004][.FF8B.0000.0000] -2F978 ; [.FB40.0020.0002][.FF95.0000.0000] -F9AF ; [.FB40.0020.0002][.FF9A.0000.0000] -FA1E ; [.FB40.0020.0002][.FFBD.0000.0000] -2F7B ; [.FB40.0020.0004][.FFBD.0000.0000] -2F979 ; [.FB40.0020.0002][.FFFA.0000.0000] -F934 ; [.FB41.0020.0002][.8001.0000.0000] -2F7C ; [.FB41.0020.0004][.8001.0000.0000] -2EB9 ; [.FB41.0020.0004][.8002.0000.0000] -FA5B ; [.FB41.0020.0002][.8005.0000.0000] -FAB2 ; [.FB41.0020.0002][.8005.0000.0000] -2F97A ; [.FB41.0020.0002][.8005.0000.0000] -2F7D ; [.FB41.0020.0004][.800C.0000.0000] -2F7E ; [.FB41.0020.0004][.8012.0000.0000] -2F7F ; [.FB41.0020.0004][.8033.0000.0000] -F9B0 ; [.FB41.0020.0002][.8046.0000.0000] -2F97D ; [.FB41.0020.0002][.8060.0000.0000] -F997 ; [.FB41.0020.0002][.806F.0000.0000] -2F97F ; [.FB41.0020.0002][.8070.0000.0000] -F945 ; [.FB41.0020.0002][.807E.0000.0000] -2F80 ; [.FB41.0020.0004][.807F.0000.0000] -2EBB ; [.FB41.0020.0004][.807F.0000.0000][.0000.010B.0004] -2EBA ; [.FB41.0020.0004][.8080.0000.0000] -2F81 ; [.FB41.0020.0004][.8089.0000.0000] -2EBC ; [.FB41.0020.0004][.8089.0000.0000][.0000.010B.0004] -F953 ; [.FB41.0020.0002][.808B.0000.0000] -2F8D6 ; [.FB41.0020.0002][.80AD.0000.0000] -2F982 ; [.FB41.0020.0002][.80B2.0000.0000] -2F983 ; [.FB41.0020.0002][.8103.0000.0000] -2F985 ; [.FB41.0020.0002][.813E.0000.0000] -F926 ; [.FB41.0020.0002][.81D8.0000.0000] -2F82 ; [.FB41.0020.0004][.81E3.0000.0000] -F9F6 ; [.FB41.0020.0002][.81E8.0000.0000] -2F83 ; [.FB41.0020.0004][.81EA.0000.0000] -3242 ; [*0310.0020.0004][.FB41.0020.0004][.81EA.0000.0000][*0311.0020.0004] -FA5C ; [.FB41.0020.0002][.81ED.0000.0000] -2F84 ; [.FB41.0020.0004][.81F3.0000.0000] -3243 ; [*0310.0020.0004][.FB41.0020.0004][.81F3.0000.0000][*0311.0020.0004] -2F85 ; [.FB41.0020.0004][.81FC.0000.0000] -2EBD ; [.FB41.0020.0004][.81FC.0000.0000][.0000.010B.0004] -2F893 ; [.FB41.0020.0002][.8201.0000.0000] -2F98B ; [.FB41.0020.0002][.8201.0000.0000] -2F98C ; [.FB41.0020.0002][.8204.0000.0000] -2F86 ; [.FB41.0020.0004][.820C.0000.0000] -FA6D ; [.FB41.0020.0002][.8218.0000.0000] -2F87 ; [.FB41.0020.0004][.821B.0000.0000] -2F88 ; [.FB41.0020.0004][.821F.0000.0000] -2F89 ; [.FB41.0020.0004][.826E.0000.0000] -F97C ; [.FB41.0020.0002][.826F.0000.0000] -2F8A ; [.FB41.0020.0004][.8272.0000.0000] -2F8B ; [.FB41.0020.0004][.8278.0000.0000] -FA5D ; [.FB41.0020.0002][.8279.0000.0000] -FA5E ; [.FB41.0020.0002][.8279.0000.0000] -2EBE ; [.FB41.0020.0004][.8279.0000.0000] -2EBF ; [.FB41.0020.0004][.8279.0000.0000][.0000.010B.0004] -2EC0 ; [.FB41.0020.0004][.8279.0000.0000][.0000.010C.0004] -2F990 ; [.FB41.0020.0002][.828B.0000.0000] -2F98F ; [.FB41.0020.0002][.8291.0000.0000] -2F991 ; [.FB41.0020.0002][.829D.0000.0000] -2F993 ; [.FB41.0020.0002][.82B1.0000.0000] -2F994 ; [.FB41.0020.0002][.82B3.0000.0000] -2F995 ; [.FB41.0020.0002][.82BD.0000.0000] -F974 ; [.FB41.0020.0002][.82E5.0000.0000] -2F998 ; [.FB41.0020.0002][.82E5.0000.0000] -2F996 ; [.FB41.0020.0002][.82E6.0000.0000] -2F999 ; [.FB41.0020.0002][.831D.0000.0000] -2F99C ; [.FB41.0020.0002][.8323.0000.0000] -F9FE ; [.FB41.0020.0002][.8336.0000.0000] -FAB3 ; [.FB41.0020.0002][.8352.0000.0000] -2F9A0 ; [.FB41.0020.0002][.8353.0000.0000] -2F99A ; [.FB41.0020.0002][.8363.0000.0000] -2F99B ; [.FB41.0020.0002][.83AD.0000.0000] -2F99D ; [.FB41.0020.0002][.83BD.0000.0000] -F93E ; [.FB41.0020.0002][.83C9.0000.0000] -2F9A1 ; [.FB41.0020.0002][.83CA.0000.0000] -2F9A2 ; [.FB41.0020.0002][.83CC.0000.0000] -2F9A3 ; [.FB41.0020.0002][.83DC.0000.0000] -2F99E ; [.FB41.0020.0002][.83E7.0000.0000] -FAB4 ; [.FB41.0020.0002][.83EF.0000.0000] -F958 ; [.FB41.0020.0002][.83F1.0000.0000] -F918 ; [.FB41.0020.0002][.843D.0000.0000] -F96E ; [.FB41.0020.0002][.8449.0000.0000] -FA5F ; [.FB41.0020.0002][.8457.0000.0000] -2F99F ; [.FB41.0020.0002][.8457.0000.0000] -F999 ; [.FB41.0020.0002][.84EE.0000.0000] -2F9A8 ; [.FB41.0020.0002][.84F1.0000.0000] -2F9A9 ; [.FB41.0020.0002][.84F3.0000.0000] -F9C2 ; [.FB41.0020.0002][.84FC.0000.0000] -2F9AA ; [.FB41.0020.0002][.8516.0000.0000] -2F9AC ; [.FB41.0020.0002][.8564.0000.0000] -F923 ; [.FB41.0020.0002][.85CD.0000.0000] -F9F0 ; [.FB41.0020.0002][.85FA.0000.0000] -F935 ; [.FB41.0020.0002][.8606.0000.0000] -FA20 ; [.FB41.0020.0002][.8612.0000.0000] -F91F ; [.FB41.0020.0002][.862D.0000.0000] -F910 ; [.FB41.0020.0002][.863F.0000.0000] -2F8C ; [.FB41.0020.0004][.864D.0000.0000] -2EC1 ; [.FB41.0020.0004][.864E.0000.0000] -2F9B3 ; [.FB41.0020.0002][.8650.0000.0000] -F936 ; [.FB41.0020.0002][.865C.0000.0000] -2F9B4 ; [.FB41.0020.0002][.865C.0000.0000] -2F9B5 ; [.FB41.0020.0002][.8667.0000.0000] -2F9B6 ; [.FB41.0020.0002][.8669.0000.0000] -2F8D ; [.FB41.0020.0004][.866B.0000.0000] -2F9B8 ; [.FB41.0020.0002][.8688.0000.0000] -2F9B7 ; [.FB41.0020.0002][.86A9.0000.0000] -2F9BA ; [.FB41.0020.0002][.86E2.0000.0000] -2F9B9 ; [.FB41.0020.0002][.870E.0000.0000] -2F9BC ; [.FB41.0020.0002][.8728.0000.0000] -2F9BD ; [.FB41.0020.0002][.876B.0000.0000] -FAB5 ; [.FB41.0020.0002][.8779.0000.0000] -2F9BB ; [.FB41.0020.0002][.8779.0000.0000] -2F9BE ; [.FB41.0020.0002][.8786.0000.0000] -F911 ; [.FB41.0020.0002][.87BA.0000.0000] -2F9C0 ; [.FB41.0020.0002][.87E1.0000.0000] -2F9C1 ; [.FB41.0020.0002][.8801.0000.0000] -F927 ; [.FB41.0020.0002][.881F.0000.0000] -2F8E ; [.FB41.0020.0004][.8840.0000.0000] -FA08 ; [.FB41.0020.0002][.884C.0000.0000] -2F8F ; [.FB41.0020.0004][.884C.0000.0000] -2F9C3 ; [.FB41.0020.0002][.8860.0000.0000] -2F9C4 ; [.FB41.0020.0002][.8863.0000.0000] -2F90 ; [.FB41.0020.0004][.8863.0000.0000] -2EC2 ; [.FB41.0020.0004][.8864.0000.0000] -F9A0 ; [.FB41.0020.0002][.88C2.0000.0000] -F9E7 ; [.FB41.0020.0002][.88CF.0000.0000] -2F9C6 ; [.FB41.0020.0002][.88D7.0000.0000] -2F9C7 ; [.FB41.0020.0002][.88DE.0000.0000] -F9E8 ; [.FB41.0020.0002][.88E1.0000.0000] -F912 ; [.FB41.0020.0002][.88F8.0000.0000] -2F9C9 ; [.FB41.0020.0002][.88FA.0000.0000] -FA60 ; [.FB41.0020.0002][.8910.0000.0000] -FAB6 ; [.FB41.0020.0002][.8941.0000.0000] -F924 ; [.FB41.0020.0002][.8964.0000.0000] -2F91 ; [.FB41.0020.0004][.897E.0000.0000] -2EC4 ; [.FB41.0020.0004][.897F.0000.0000] -2EC3 ; [.FB41.0020.0004][.8980.0000.0000] -FAB7 ; [.FB41.0020.0002][.8986.0000.0000] -FA0A ; [.FB41.0020.0002][.898B.0000.0000] -2F92 ; [.FB41.0020.0004][.898B.0000.0000] -FA61 ; [.FB41.0020.0002][.8996.0000.0000] -FAB8 ; [.FB41.0020.0002][.8996.0000.0000] -2EC5 ; [.FB41.0020.0004][.89C1.0000.0000] -2EC6 ; [.FB41.0020.0004][.89D2.0000.0000] -2F93 ; [.FB41.0020.0004][.89D2.0000.0000] -2EC7 ; [.FB41.0020.0004][.89D2.0000.0000][.0000.010B.0004] -1F216 ; [.FB41.0020.001C][.89E3.0000.0000] -2F94 ; [.FB41.0020.0004][.8A00.0000.0000] -2F9CF ; [.FB41.0020.0002][.8AA0.0000.0000] -F96F ; [.FB41.0020.0002][.8AAA.0000.0000] -F9A1 ; [.FB41.0020.0002][.8AAA.0000.0000] -FAB9 ; [.FB41.0020.0002][.8ABF.0000.0000] -FABB ; [.FB41.0020.0002][.8ACB.0000.0000] -F97D ; [.FB41.0020.0002][.8AD2.0000.0000] -F941 ; [.FB41.0020.0002][.8AD6.0000.0000] -FABE ; [.FB41.0020.0002][.8AED.0000.0000] -2F9D0 ; [.FB41.0020.0002][.8AED.0000.0000] -FA22 ; [.FB41.0020.0002][.8AF8.0000.0000] -FABA ; [.FB41.0020.0002][.8AF8.0000.0000] -F95D ; [.FB41.0020.0002][.8AFE.0000.0000] -FABD ; [.FB41.0020.0002][.8AFE.0000.0000] -FA62 ; [.FB41.0020.0002][.8B01.0000.0000] -FABC ; [.FB41.0020.0002][.8B01.0000.0000] -FA63 ; [.FB41.0020.0002][.8B39.0000.0000] -FABF ; [.FB41.0020.0002][.8B39.0000.0000] -F9FC ; [.FB41.0020.0002][.8B58.0000.0000] -F95A ; [.FB41.0020.0002][.8B80.0000.0000] -FAC0 ; [.FB41.0020.0002][.8B8A.0000.0000] -2F9D1 ; [.FB41.0020.0002][.8B8A.0000.0000] -2EC8 ; [.FB41.0020.0004][.8BA0.0000.0000] -2F95 ; [.FB41.0020.0004][.8C37.0000.0000] -2F96 ; [.FB41.0020.0004][.8C46.0000.0000] -F900 ; [.FB41.0020.0002][.8C48.0000.0000] -2F9D2 ; [.FB41.0020.0002][.8C55.0000.0000] -2F97 ; [.FB41.0020.0004][.8C55.0000.0000] -2F98 ; [.FB41.0020.0004][.8C78.0000.0000] -2F99 ; [.FB41.0020.0004][.8C9D.0000.0000] -3236 ; [*0310.0020.0004][.FB41.0020.0004][.8CA1.0000.0000][*0311.0020.0004] -3296 ; [.FB41.0020.0006][.8CA1.0000.0000] -1F223 ; [.FB41.0020.001C][.8CA9.0000.0000] -2F9D4 ; [.FB41.0020.0002][.8CAB.0000.0000] -2F9D5 ; [.FB41.0020.0002][.8CC1.0000.0000] -F948 ; [.FB41.0020.0002][.8CC2.0000.0000] -323E ; [*0310.0020.0004][.FB41.0020.0004][.8CC7.0000.0000][*0311.0020.0004] -32AE ; [.FB41.0020.0006][.8CC7.0000.0000] -F903 ; [.FB41.0020.0002][.8CC8.0000.0000] -FA64 ; [.FB41.0020.0002][.8CD3.0000.0000] -FA65 ; [.FB41.0020.0002][.8D08.0000.0000] -FAC1 ; [.FB41.0020.0002][.8D08.0000.0000] -2F9D6 ; [.FB41.0020.0002][.8D1B.0000.0000] -2EC9 ; [.FB41.0020.0004][.8D1D.0000.0000] -2F9A ; [.FB41.0020.0004][.8D64.0000.0000] -2F9B ; [.FB41.0020.0004][.8D70.0000.0000] -1F230 ; [.FB41.0020.001C][.8D70.0000.0000] -2F9D7 ; [.FB41.0020.0002][.8D77.0000.0000] -2F9C ; [.FB41.0020.0004][.8DB3.0000.0000] -2ECA ; [.FB41.0020.0004][.8DB3.0000.0000][.0000.010B.0004] -2F9DB ; [.FB41.0020.0002][.8DBC.0000.0000] -2F9DA ; [.FB41.0020.0002][.8DCB.0000.0000] -F937 ; [.FB41.0020.0002][.8DEF.0000.0000] -2F9DC ; [.FB41.0020.0002][.8DF0.0000.0000] -2F9D ; [.FB41.0020.0004][.8EAB.0000.0000] -F902 ; [.FB41.0020.0002][.8ECA.0000.0000] -2F9E ; [.FB41.0020.0004][.8ECA.0000.0000] -2F9DE ; [.FB41.0020.0002][.8ED4.0000.0000] -F998 ; [.FB41.0020.0002][.8F26.0000.0000] -F9D7 ; [.FB41.0020.0002][.8F2A.0000.0000] -FAC2 ; [.FB41.0020.0002][.8F38.0000.0000] -2F9DF ; [.FB41.0020.0002][.8F38.0000.0000] -FA07 ; [.FB41.0020.0002][.8F3B.0000.0000] -F98D ; [.FB41.0020.0002][.8F62.0000.0000] -2ECB ; [.FB41.0020.0004][.8F66.0000.0000] -2F9F ; [.FB41.0020.0004][.8F9B.0000.0000] -2F98D ; [.FB41.0020.0002][.8F9E.0000.0000] -F971 ; [.FB41.0020.0002][.8FB0.0000.0000] -2FA0 ; [.FB41.0020.0004][.8FB0.0000.0000] -2FA1 ; [.FB41.0020.0004][.8FB5.0000.0000] -FA66 ; [.FB41.0020.0002][.8FB6.0000.0000] -2ECC ; [.FB41.0020.0004][.8FB6.0000.0000] -2ECD ; [.FB41.0020.0004][.8FB6.0000.0000][.0000.010B.0004] -2ECE ; [.FB41.0020.0004][.8FB6.0000.0000][.0000.010C.0004] -F99A ; [.FB41.0020.0002][.9023.0000.0000] -FA25 ; [.FB41.0020.0002][.9038.0000.0000] -FA67 ; [.FB41.0020.0002][.9038.0000.0000] -1F22B ; [.FB41.0020.001C][.904A.0000.0000] -329C ; [.FB41.0020.0006][.9069.0000.0000] -FAC3 ; [.FB41.0020.0002][.9072.0000.0000] -F9C3 ; [.FB41.0020.0002][.907C.0000.0000] -F913 ; [.FB41.0020.0002][.908F.0000.0000] -2FA2 ; [.FB41.0020.0004][.9091.0000.0000] -2ECF ; [.FB41.0020.0004][.9091.0000.0000][.0000.010B.0004] -2F9E2 ; [.FB41.0020.0002][.9094.0000.0000] -F92C ; [.FB41.0020.0002][.90CE.0000.0000] -FA2E ; [.FB41.0020.0002][.90DE.0000.0000] -2F9E3 ; [.FB41.0020.0002][.90F1.0000.0000] -FA26 ; [.FB41.0020.0002][.90FD.0000.0000] -2F9E4 ; [.FB41.0020.0002][.9111.0000.0000] -2F9E6 ; [.FB41.0020.0002][.911B.0000.0000] -2FA3 ; [.FB41.0020.0004][.9149.0000.0000] -F919 ; [.FB41.0020.0002][.916A.0000.0000] -FAC4 ; [.FB41.0020.0002][.9199.0000.0000] -F9B7 ; [.FB41.0020.0002][.91B4.0000.0000] -2FA4 ; [.FB41.0020.0004][.91C6.0000.0000] -F9E9 ; [.FB41.0020.0002][.91CC.0000.0000] -2FA5 ; [.FB41.0020.0004][.91CC.0000.0000] -F97E ; [.FB41.0020.0002][.91CF.0000.0000] -F90A ; [.FB41.0020.0002][.91D1.0000.0000] -2FA6 ; [.FB41.0020.0004][.91D1.0000.0000] -322E ; [*0310.0020.0004][.FB41.0020.0004][.91D1.0000.0000][*0311.0020.0004] -328E ; [.FB41.0020.0006][.91D1.0000.0000] -F9B1 ; [.FB41.0020.0002][.9234.0000.0000] -2F9E7 ; [.FB41.0020.0002][.9238.0000.0000] -FAC5 ; [.FB41.0020.0002][.9276.0000.0000] -2F9EA ; [.FB41.0020.0002][.927C.0000.0000] -2F9E8 ; [.FB41.0020.0002][.92D7.0000.0000] -2F9E9 ; [.FB41.0020.0002][.92D8.0000.0000] -F93F ; [.FB41.0020.0002][.9304.0000.0000] -F99B ; [.FB41.0020.0002][.934A.0000.0000] -2F9EB ; [.FB41.0020.0002][.93F9.0000.0000] -2F9EC ; [.FB41.0020.0002][.9415.0000.0000] -2ED0 ; [.FB41.0020.0004][.9485.0000.0000] -2ED1 ; [.FB41.0020.0004][.9577.0000.0000] -2FA7 ; [.FB41.0020.0004][.9577.0000.0000] -2ED2 ; [.FB41.0020.0004][.9578.0000.0000] -2ED3 ; [.FB41.0020.0004][.957F.0000.0000] -2FA8 ; [.FB41.0020.0004][.9580.0000.0000] -2F9EE ; [.FB41.0020.0002][.958B.0000.0000] -F986 ; [.FB41.0020.0002][.95AD.0000.0000] -2F9F0 ; [.FB41.0020.0002][.95B7.0000.0000] -2ED4 ; [.FB41.0020.0004][.95E8.0000.0000] -2FA9 ; [.FB41.0020.0004][.961C.0000.0000] -2ED5 ; [.FB41.0020.0004][.961C.0000.0000][.0000.010B.0004] -2ED6 ; [.FB41.0020.0004][.961D.0000.0000] -F9C6 ; [.FB41.0020.0002][.962E.0000.0000] -F951 ; [.FB41.0020.0002][.964B.0000.0000] -FA09 ; [.FB41.0020.0002][.964D.0000.0000] -F959 ; [.FB41.0020.0002][.9675.0000.0000] -F9D3 ; [.FB41.0020.0002][.9678.0000.0000] -FAC6 ; [.FB41.0020.0002][.967C.0000.0000] -F9DC ; [.FB41.0020.0002][.9686.0000.0000] -F9F1 ; [.FB41.0020.0002][.96A3.0000.0000] -2FAA ; [.FB41.0020.0004][.96B6.0000.0000] -FA2F ; [.FB41.0020.0002][.96B7.0000.0000] -F9B8 ; [.FB41.0020.0002][.96B8.0000.0000] -2FAB ; [.FB41.0020.0004][.96B9.0000.0000] -2F9F3 ; [.FB41.0020.0002][.96C3.0000.0000] -F9EA ; [.FB41.0020.0002][.96E2.0000.0000] -FA68 ; [.FB41.0020.0002][.96E3.0000.0000] -FAC7 ; [.FB41.0020.0002][.96E3.0000.0000] -2FAC ; [.FB41.0020.0004][.96E8.0000.0000] -2ED7 ; [.FB41.0020.0004][.96E8.0000.0000][.0000.010B.0004] -F9B2 ; [.FB41.0020.0002][.96F6.0000.0000] -F949 ; [.FB41.0020.0002][.96F7.0000.0000] -2F9F5 ; [.FB41.0020.0002][.9723.0000.0000] -F938 ; [.FB41.0020.0002][.9732.0000.0000] -F9B3 ; [.FB41.0020.0002][.9748.0000.0000] -2FAD ; [.FB41.0020.0004][.9751.0000.0000] -2ED8 ; [.FB41.0020.0004][.9752.0000.0000] -FA1C ; [.FB41.0020.0002][.9756.0000.0000] -FAC8 ; [.FB41.0020.0002][.9756.0000.0000] -2FAE ; [.FB41.0020.0004][.975E.0000.0000] -2FAF ; [.FB41.0020.0004][.9762.0000.0000] -2FB0 ; [.FB41.0020.0004][.9769.0000.0000] -2FB1 ; [.FB41.0020.0004][.97CB.0000.0000] -FAC9 ; [.FB41.0020.0002][.97DB.0000.0000] -2F9FA ; [.FB41.0020.0002][.97E0.0000.0000] -2ED9 ; [.FB41.0020.0004][.97E6.0000.0000] -2FB2 ; [.FB41.0020.0004][.97ED.0000.0000] -2FB3 ; [.FB41.0020.0004][.97F3.0000.0000] -FA69 ; [.FB41.0020.0002][.97FF.0000.0000] -FACA ; [.FB41.0020.0002][.97FF.0000.0000] -2FB4 ; [.FB41.0020.0004][.9801.0000.0000] -32A0 ; [.FB41.0020.0006][.9805.0000.0000] -FACB ; [.FB41.0020.0002][.980B.0000.0000] -2F9FE ; [.FB41.0020.0002][.980B.0000.0000] -2F9FF ; [.FB41.0020.0002][.980B.0000.0000] -F9B4 ; [.FB41.0020.0002][.9818.0000.0000] -2FA00 ; [.FB41.0020.0002][.9829.0000.0000] -FA6A ; [.FB41.0020.0002][.983B.0000.0000] -FACC ; [.FB41.0020.0002][.983B.0000.0000] -F9D0 ; [.FB41.0020.0002][.985E.0000.0000] -2EDA ; [.FB41.0020.0004][.9875.0000.0000] -2FB5 ; [.FB41.0020.0004][.98A8.0000.0000] -2EDB ; [.FB41.0020.0004][.98CE.0000.0000] -2FB6 ; [.FB41.0020.0004][.98DB.0000.0000] -2EDC ; [.FB41.0020.0004][.98DE.0000.0000] -2EDD ; [.FB41.0020.0004][.98DF.0000.0000] -2FB7 ; [.FB41.0020.0004][.98DF.0000.0000] -2EDF ; [.FB41.0020.0004][.98E0.0000.0000] -2EDE ; [.FB41.0020.0004][.98E0.0000.0000][.0000.010B.0004] -2FA02 ; [.FB41.0020.0002][.98E2.0000.0000] -FA2A ; [.FB41.0020.0002][.98EF.0000.0000] -FA2B ; [.FB41.0020.0002][.98FC.0000.0000] -FA2C ; [.FB41.0020.0002][.9928.0000.0000] -2FA04 ; [.FB41.0020.0002][.9929.0000.0000] -2EE0 ; [.FB41.0020.0004][.9963.0000.0000] -2FB8 ; [.FB41.0020.0004][.9996.0000.0000] -2EE1 ; [.FB41.0020.0004][.9996.0000.0000][.0000.010B.0004] -2FB9 ; [.FB41.0020.0004][.9999.0000.0000] -2FA05 ; [.FB41.0020.0002][.99A7.0000.0000] -2FBA ; [.FB41.0020.0004][.99AC.0000.0000] -2FA06 ; [.FB41.0020.0002][.99C2.0000.0000] -F91A ; [.FB41.0020.0002][.99F1.0000.0000] -2FA07 ; [.FB41.0020.0002][.99FE.0000.0000] -F987 ; [.FB41.0020.0002][.9A6A.0000.0000] -2EE2 ; [.FB41.0020.0004][.9A6C.0000.0000] -2FBB ; [.FB41.0020.0004][.9AA8.0000.0000] -2EE3 ; [.FB41.0020.0004][.9AA8.0000.0000][.0000.010B.0004] -2FBC ; [.FB41.0020.0004][.9AD8.0000.0000] -2FBD ; [.FB41.0020.0004][.9ADF.0000.0000] -FACD ; [.FB41.0020.0002][.9B12.0000.0000] -2FA0A ; [.FB41.0020.0002][.9B12.0000.0000] -2FBE ; [.FB41.0020.0004][.9B25.0000.0000] -2FBF ; [.FB41.0020.0004][.9B2F.0000.0000] -2FC0 ; [.FB41.0020.0004][.9B32.0000.0000] -2FC1 ; [.FB41.0020.0004][.9B3C.0000.0000] -2EE4 ; [.FB41.0020.0004][.9B3C.0000.0000][.0000.010B.0004] -2FC2 ; [.FB41.0020.0004][.9B5A.0000.0000] -F939 ; [.FB41.0020.0002][.9B6F.0000.0000] -2FA0B ; [.FB41.0020.0002][.9C40.0000.0000] -F9F2 ; [.FB41.0020.0002][.9C57.0000.0000] -2EE5 ; [.FB41.0020.0004][.9C7C.0000.0000] -2FC3 ; [.FB41.0020.0004][.9CE5.0000.0000] -2FA0C ; [.FB41.0020.0002][.9CFD.0000.0000] -2FA0F ; [.FB41.0020.0002][.9D67.0000.0000] -FA2D ; [.FB41.0020.0002][.9DB4.0000.0000] -F93A ; [.FB41.0020.0002][.9DFA.0000.0000] -F920 ; [.FB41.0020.0002][.9E1E.0000.0000] -2EE6 ; [.FB41.0020.0004][.9E1F.0000.0000] -2FC4 ; [.FB41.0020.0004][.9E75.0000.0000] -2EE7 ; [.FB41.0020.0004][.9E75.0000.0000][.0000.010B.0004] -F940 ; [.FB41.0020.0002][.9E7F.0000.0000] -2FC5 ; [.FB41.0020.0004][.9E7F.0000.0000] -F988 ; [.FB41.0020.0002][.9E97.0000.0000] -F9F3 ; [.FB41.0020.0002][.9E9F.0000.0000] -2FC6 ; [.FB41.0020.0004][.9EA5.0000.0000] -2EE8 ; [.FB41.0020.0004][.9EA6.0000.0000] -2FA15 ; [.FB41.0020.0002][.9EBB.0000.0000] -2FC7 ; [.FB41.0020.0004][.9EBB.0000.0000] -2FC8 ; [.FB41.0020.0004][.9EC3.0000.0000] -2EE9 ; [.FB41.0020.0004][.9EC4.0000.0000] -2FC9 ; [.FB41.0020.0004][.9ECD.0000.0000] -F989 ; [.FB41.0020.0002][.9ECE.0000.0000] -2FCA ; [.FB41.0020.0004][.9ED1.0000.0000] -2FA17 ; [.FB41.0020.0002][.9EF9.0000.0000] -2FCB ; [.FB41.0020.0004][.9EF9.0000.0000] -2FCC ; [.FB41.0020.0004][.9EFD.0000.0000] -2FA18 ; [.FB41.0020.0002][.9EFE.0000.0000] -2EEA ; [.FB41.0020.0004][.9EFE.0000.0000] -2FA19 ; [.FB41.0020.0002][.9F05.0000.0000] -2FCD ; [.FB41.0020.0004][.9F0E.0000.0000] -2FA1A ; [.FB41.0020.0002][.9F0F.0000.0000] -2FCE ; [.FB41.0020.0004][.9F13.0000.0000] -2FA1B ; [.FB41.0020.0002][.9F16.0000.0000] -2FCF ; [.FB41.0020.0004][.9F20.0000.0000] -2FA1C ; [.FB41.0020.0002][.9F3B.0000.0000] -2FD0 ; [.FB41.0020.0004][.9F3B.0000.0000] -FAD8 ; [.FB41.0020.0002][.9F43.0000.0000] -2FD1 ; [.FB41.0020.0004][.9F4A.0000.0000] -2EEB ; [.FB41.0020.0004][.9F4A.0000.0000][.0000.010B.0004] -2EEC ; [.FB41.0020.0004][.9F50.0000.0000] -2FD2 ; [.FB41.0020.0004][.9F52.0000.0000] -2EED ; [.FB41.0020.0004][.9F52.0000.0000][.0000.010B.0004] -2EEE ; [.FB41.0020.0004][.9F7F.0000.0000] -F9C4 ; [.FB41.0020.0002][.9F8D.0000.0000] -2FD3 ; [.FB41.0020.0004][.9F8D.0000.0000] -2EEF ; [.FB41.0020.0004][.9F8D.0000.0000][.0000.010B.0004] -FAD9 ; [.FB41.0020.0002][.9F8E.0000.0000] -2EF0 ; [.FB41.0020.0004][.9F99.0000.0000] -F907 ; [.FB41.0020.0002][.9F9C.0000.0000] -F908 ; [.FB41.0020.0002][.9F9C.0000.0000] -FACE ; [.FB41.0020.0002][.9F9C.0000.0000] -2FD4 ; [.FB41.0020.0004][.9F9C.0000.0000] -2EF1 ; [.FB41.0020.0004][.9F9C.0000.0000][.0000.010B.0004] -2EF2 ; [.FB41.0020.0004][.9F9C.0000.0000][.0000.010C.0004] -2EF3 ; [.FB41.0020.0004][.9F9F.0000.0000] -2FD5 ; [.FB41.0020.0004][.9FA0.0000.0000] -FA0E ; [.FB41.0020.0002][.FA0E.0000.0000] -FA0F ; [.FB41.0020.0002][.FA0F.0000.0000] -FA11 ; [.FB41.0020.0002][.FA11.0000.0000] -FA13 ; [.FB41.0020.0002][.FA13.0000.0000] -FA14 ; [.FB41.0020.0002][.FA14.0000.0000] -FA1F ; [.FB41.0020.0002][.FA1F.0000.0000] -FA21 ; [.FB41.0020.0002][.FA21.0000.0000] -FA23 ; [.FB41.0020.0002][.FA23.0000.0000] -FA24 ; [.FB41.0020.0002][.FA24.0000.0000] -FA27 ; [.FB41.0020.0002][.FA27.0000.0000] -FA28 ; [.FB41.0020.0002][.FA28.0000.0000] -FA29 ; [.FB41.0020.0002][.FA29.0000.0000] -2F80C ; [.FB80.0020.0002][.B49E.0000.0000] -2F813 ; [.FB80.0020.0002][.B4B9.0000.0000] -2F9CA ; [.FB80.0020.0002][.B4BB.0000.0000] -2F81F ; [.FB80.0020.0002][.B4DF.0000.0000] -2F824 ; [.FB80.0020.0002][.B515.0000.0000] -2F867 ; [.FB80.0020.0002][.B6EE.0000.0000] -2F868 ; [.FB80.0020.0002][.B6FC.0000.0000] -2F876 ; [.FB80.0020.0002][.B781.0000.0000] -2F883 ; [.FB80.0020.0002][.B82F.0000.0000] -2F888 ; [.FB80.0020.0002][.B862.0000.0000] -2F88A ; [.FB80.0020.0002][.B87C.0000.0000] -2F896 ; [.FB80.0020.0002][.B8C7.0000.0000] -2F89B ; [.FB80.0020.0002][.B8E3.0000.0000] -2F8A2 ; [.FB80.0020.0002][.B91C.0000.0000] -2F8A1 ; [.FB80.0020.0002][.B93A.0000.0000] -2F8C2 ; [.FB80.0020.0002][.BA2E.0000.0000] -2F8C7 ; [.FB80.0020.0002][.BA6C.0000.0000] -2F8D1 ; [.FB80.0020.0002][.BAE4.0000.0000] -2F8D0 ; [.FB80.0020.0002][.BB08.0000.0000] -2F8CE ; [.FB80.0020.0002][.BB19.0000.0000] -2F8DE ; [.FB80.0020.0002][.BB49.0000.0000] -FAD2 ; [.FB80.0020.0002][.BB9D.0000.0000] -2F8E7 ; [.FB80.0020.0002][.BB9D.0000.0000] -2F8EE ; [.FB80.0020.0002][.BC18.0000.0000] -2F8F2 ; [.FB80.0020.0002][.BC4E.0000.0000] -2F90A ; [.FB80.0020.0002][.BD33.0000.0000] -2F916 ; [.FB80.0020.0002][.BD96.0000.0000] -2F92A ; [.FB80.0020.0002][.BEAC.0000.0000] -2F92C ; [.FB80.0020.0002][.BEB8.0000.0000] -2F92D ; [.FB80.0020.0002][.BEB8.0000.0000] -2F933 ; [.FB80.0020.0002][.BF1B.0000.0000] -2F93E ; [.FB80.0020.0002][.BFFC.0000.0000] -2F93F ; [.FB80.0020.0002][.C008.0000.0000] -FAD3 ; [.FB80.0020.0002][.C018.0000.0000] -FAD4 ; [.FB80.0020.0002][.C039.0000.0000] -2F949 ; [.FB80.0020.0002][.C039.0000.0000] -2F94B ; [.FB80.0020.0002][.C046.0000.0000] -2F94C ; [.FB80.0020.0002][.C096.0000.0000] -2F951 ; [.FB80.0020.0002][.C0E3.0000.0000] -2F958 ; [.FB80.0020.0002][.C12F.0000.0000] -2F960 ; [.FB80.0020.0002][.C202.0000.0000] -2F964 ; [.FB80.0020.0002][.C227.0000.0000] -2F967 ; [.FB80.0020.0002][.C2A0.0000.0000] -2F96D ; [.FB80.0020.0002][.C301.0000.0000] -2F971 ; [.FB80.0020.0002][.C334.0000.0000] -2F974 ; [.FB80.0020.0002][.C359.0000.0000] -2F981 ; [.FB80.0020.0002][.C3D5.0000.0000] -2F8D7 ; [.FB80.0020.0002][.C3D9.0000.0000] -2F984 ; [.FB80.0020.0002][.C40B.0000.0000] -2F98E ; [.FB80.0020.0002][.C46B.0000.0000] -2F9A7 ; [.FB80.0020.0002][.C52B.0000.0000] -2F9AE ; [.FB80.0020.0002][.C55D.0000.0000] -2F9AF ; [.FB80.0020.0002][.C561.0000.0000] -2F9B2 ; [.FB80.0020.0002][.C56B.0000.0000] -2F9BF ; [.FB80.0020.0002][.C5D7.0000.0000] -2F9C2 ; [.FB80.0020.0002][.C5F9.0000.0000] -2F9C8 ; [.FB80.0020.0002][.C635.0000.0000] -2F9CD ; [.FB80.0020.0002][.C6BE.0000.0000] -2F9CE ; [.FB80.0020.0002][.C6C7.0000.0000] -2F9EF ; [.FB80.0020.0002][.C995.0000.0000] -2F9F2 ; [.FB80.0020.0002][.C9E6.0000.0000] -2F9F8 ; [.FB80.0020.0002][.CA6E.0000.0000] -2F9F9 ; [.FB80.0020.0002][.CA76.0000.0000] -2F9FC ; [.FB80.0020.0002][.CAB2.0000.0000] -2FA03 ; [.FB80.0020.0002][.CB33.0000.0000] -2FA08 ; [.FB80.0020.0002][.CBCE.0000.0000] -2FA0D ; [.FB80.0020.0002][.CCCE.0000.0000] -2FA0E ; [.FB80.0020.0002][.CCED.0000.0000] -2FA11 ; [.FB80.0020.0002][.CCF8.0000.0000] -2FA16 ; [.FB80.0020.0002][.CD56.0000.0000] -2F803 ; [.FB84.0020.0002][.8122.0000.0000] -2F812 ; [.FB84.0020.0002][.851C.0000.0000] -2F91B ; [.FB84.0020.0002][.8525.0000.0000] -2F816 ; [.FB84.0020.0002][.854B.0000.0000] -2F80D ; [.FB84.0020.0002][.863A.0000.0000] -2F9D9 ; [.FB84.0020.0002][.8804.0000.0000] -2F9DD ; [.FB84.0020.0002][.88DE.0000.0000] -2F834 ; [.FB84.0020.0002][.8A2C.0000.0000] -2F838 ; [.FB84.0020.0002][.8B63.0000.0000] -2F859 ; [.FB84.0020.0002][.94E4.0000.0000] -2F860 ; [.FB84.0020.0002][.96A8.0000.0000] -2F861 ; [.FB84.0020.0002][.96EA.0000.0000] -2F86C ; [.FB84.0020.0002][.99C8.0000.0000] -2F871 ; [.FB84.0020.0002][.9B18.0000.0000] -2F8F8 ; [.FB84.0020.0002][.9D0B.0000.0000] -2F87B ; [.FB84.0020.0002][.9DE4.0000.0000] -2F87D ; [.FB84.0020.0002][.9DE6.0000.0000] -2F889 ; [.FB84.0020.0002][.A183.0000.0000] -2F939 ; [.FB84.0020.0002][.A19F.0000.0000] -2F891 ; [.FB84.0020.0002][.A331.0000.0000] -2F892 ; [.FB84.0020.0002][.A331.0000.0000] -2F8A4 ; [.FB84.0020.0002][.A6D4.0000.0000] -FAD0 ; [.FB84.0020.0002][.A844.0000.0000] -FACF ; [.FB84.0020.0002][.A84A.0000.0000] -2F8B8 ; [.FB84.0020.0002][.AB0C.0000.0000] -2F8BE ; [.FB84.0020.0002][.ABF1.0000.0000] -2F8CA ; [.FB84.0020.0002][.B00A.0000.0000] -2F897 ; [.FB84.0020.0002][.B2B8.0000.0000] -2F980 ; [.FB84.0020.0002][.B35F.0000.0000] -2F989 ; [.FB84.0020.0002][.B393.0000.0000] -2F98A ; [.FB84.0020.0002][.B39C.0000.0000] -2F8DD ; [.FB84.0020.0002][.B3C3.0000.0000] -FAD1 ; [.FB84.0020.0002][.B3D5.0000.0000] -2F8E3 ; [.FB84.0020.0002][.B46D.0000.0000] -2F8EC ; [.FB84.0020.0002][.B6A3.0000.0000] -2F8F0 ; [.FB84.0020.0002][.B8A7.0000.0000] -2F8F7 ; [.FB84.0020.0002][.BA8D.0000.0000] -2F8F9 ; [.FB84.0020.0002][.BAFA.0000.0000] -2F8FB ; [.FB84.0020.0002][.BCBC.0000.0000] -2F906 ; [.FB84.0020.0002][.BD1E.0000.0000] -2F90D ; [.FB84.0020.0002][.BED1.0000.0000] -2F910 ; [.FB84.0020.0002][.BF5E.0000.0000] -2F911 ; [.FB84.0020.0002][.BF8E.0000.0000] -2F91D ; [.FB84.0020.0002][.C263.0000.0000] -FA6C ; [.FB84.0020.0002][.C2EE.0000.0000] -2F91F ; [.FB84.0020.0002][.C3AB.0000.0000] -2F923 ; [.FB84.0020.0002][.C608.0000.0000] -2F926 ; [.FB84.0020.0002][.C735.0000.0000] -2F927 ; [.FB84.0020.0002][.C814.0000.0000] -2F935 ; [.FB84.0020.0002][.CC36.0000.0000] -2F937 ; [.FB84.0020.0002][.CC92.0000.0000] -2F93B ; [.FB84.0020.0002][.CFA1.0000.0000] -2F93C ; [.FB84.0020.0002][.CFB8.0000.0000] -2F93D ; [.FB84.0020.0002][.D044.0000.0000] -2F942 ; [.FB84.0020.0002][.D0F2.0000.0000] -2F941 ; [.FB84.0020.0002][.D0F3.0000.0000] -2F943 ; [.FB84.0020.0002][.D119.0000.0000] -2F944 ; [.FB84.0020.0002][.D133.0000.0000] -FAD5 ; [.FB84.0020.0002][.D249.0000.0000] -2F94D ; [.FB84.0020.0002][.D41D.0000.0000] -2F952 ; [.FB84.0020.0002][.D626.0000.0000] -2F954 ; [.FB84.0020.0002][.D69A.0000.0000] -2F955 ; [.FB84.0020.0002][.D6C5.0000.0000] -2F95C ; [.FB84.0020.0002][.D97C.0000.0000] -2F95D ; [.FB84.0020.0002][.DAA7.0000.0000] -2F95E ; [.FB84.0020.0002][.DAA7.0000.0000] -2F961 ; [.FB84.0020.0002][.DBAB.0000.0000] -2F965 ; [.FB84.0020.0002][.DC80.0000.0000] -FAD6 ; [.FB84.0020.0002][.DCD0.0000.0000] -2F96B ; [.FB84.0020.0002][.DF86.0000.0000] -2F898 ; [.FB84.0020.0002][.E1DA.0000.0000] -2F972 ; [.FB84.0020.0002][.E228.0000.0000] -2F973 ; [.FB84.0020.0002][.E247.0000.0000] -2F975 ; [.FB84.0020.0002][.E2D9.0000.0000] -2F977 ; [.FB84.0020.0002][.E33E.0000.0000] -2F97B ; [.FB84.0020.0002][.E4DA.0000.0000] -2F97C ; [.FB84.0020.0002][.E523.0000.0000] -2F97E ; [.FB84.0020.0002][.E5A8.0000.0000] -2F987 ; [.FB84.0020.0002][.E7A7.0000.0000] -2F988 ; [.FB84.0020.0002][.E7B5.0000.0000] -2F997 ; [.FB84.0020.0002][.EB3C.0000.0000] -2F9A4 ; [.FB84.0020.0002][.EC36.0000.0000] -2F9A6 ; [.FB84.0020.0002][.ECD5.0000.0000] -2F9A5 ; [.FB84.0020.0002][.ED6B.0000.0000] -2F9AD ; [.FB84.0020.0002][.EF2C.0000.0000] -2F9B0 ; [.FB84.0020.0002][.EFB1.0000.0000] -2F9B1 ; [.FB84.0020.0002][.F0D2.0000.0000] -2F9AB ; [.FB84.0020.0002][.F3CA.0000.0000] -2F9C5 ; [.FB84.0020.0002][.F667.0000.0000] -2F9CB ; [.FB84.0020.0002][.F8AE.0000.0000] -2F9CC ; [.FB84.0020.0002][.F966.0000.0000] -2F9D3 ; [.FB84.0020.0002][.FCA8.0000.0000] -FAD7 ; [.FB84.0020.0002][.FED3.0000.0000] -2F9D8 ; [.FB84.0020.0002][.FF2F.0000.0000] -2F9E0 ; [.FB85.0020.0002][.85D2.0000.0000] -2F9E1 ; [.FB85.0020.0002][.85ED.0000.0000] -2F9E5 ; [.FB85.0020.0002][.872E.0000.0000] -2F9ED ; [.FB85.0020.0002][.8BFA.0000.0000] -2F9F1 ; [.FB85.0020.0002][.8D77.0000.0000] -2F9F6 ; [.FB85.0020.0002][.9145.0000.0000] -2F81C ; [.FB85.0020.0002][.91DF.0000.0000] -2F9F7 ; [.FB85.0020.0002][.921A.0000.0000] -2F9FB ; [.FB85.0020.0002][.940A.0000.0000] -2F9FD ; [.FB85.0020.0002][.9496.0000.0000] -2FA01 ; [.FB85.0020.0002][.95B6.0000.0000] -2FA09 ; [.FB85.0020.0002][.9B30.0000.0000] -2FA10 ; [.FB85.0020.0002][.A0CE.0000.0000] -2FA12 ; [.FB85.0020.0002][.A105.0000.0000] -2FA13 ; [.FB85.0020.0002][.A20E.0000.0000] -2FA14 ; [.FB85.0020.0002][.A291.0000.0000] -2F88F ; [.FB85.0020.0002][.A392.0000.0000] -2FA1D ; [.FB85.0020.0002][.A600.0000.0000] -FFFD ; [.FFFD.0020.0002] +# allkeys-10.0.0.txt +# Date: 2017-04-26, 11:47:03 GMT [KW] +# Copyright 2017 Unicode, Inc. +# For terms of use, see http://www.unicode.org/terms_of_use.html +# +# This file defines the Default Unicode Collation Element Table +# (DUCET) for the Unicode Collation Algorithm +# +# See UTS #10, Unicode Collation Algorithm, for more information. +# +# Diagnostic weight ranges +# Primary weight range: 0200..56DA (21723) +# Secondary weight range: 0020..0115 (246) +# Variant secondaries: 0111..0115 (5) +# Tertiary weight range: 0002..001F (30) +# +@version 10.0.0 + +@implicitweights 17000..18AFF; FB00 # Tangut and Tangut Components + +@implicitweights 1B170..1B2FF; FB01 # Nushu + +0000 ; [.0000.0000.0000] # NULL (in ISO 6429) +0001 ; [.0000.0000.0000] # START OF HEADING (in ISO 6429) +0002 ; [.0000.0000.0000] # START OF TEXT (in ISO 6429) +0003 ; [.0000.0000.0000] # END OF TEXT (in ISO 6429) +0004 ; [.0000.0000.0000] # END OF TRANSMISSION (in ISO 6429) +0005 ; [.0000.0000.0000] # ENQUIRY (in ISO 6429) +0006 ; [.0000.0000.0000] # ACKNOWLEDGE (in ISO 6429) +0007 ; [.0000.0000.0000] # BELL (in ISO 6429) +0008 ; [.0000.0000.0000] # BACKSPACE (in ISO 6429) +000E ; [.0000.0000.0000] # SHIFT OUT (in ISO 6429) +000F ; [.0000.0000.0000] # SHIFT IN (in ISO 6429) +0010 ; [.0000.0000.0000] # DATA LINK ESCAPE (in ISO 6429) +0011 ; [.0000.0000.0000] # DEVICE CONTROL ONE (in ISO 6429) +0012 ; [.0000.0000.0000] # DEVICE CONTROL TWO (in ISO 6429) +0013 ; [.0000.0000.0000] # DEVICE CONTROL THREE (in ISO 6429) +0014 ; [.0000.0000.0000] # DEVICE CONTROL FOUR (in ISO 6429) +0015 ; [.0000.0000.0000] # NEGATIVE ACKNOWLEDGE (in ISO 6429) +0016 ; [.0000.0000.0000] # SYNCHRONOUS IDLE (in ISO 6429) +0017 ; [.0000.0000.0000] # END OF TRANSMISSION BLOCK (in ISO 6429) +0018 ; [.0000.0000.0000] # CANCEL (in ISO 6429) +0019 ; [.0000.0000.0000] # END OF MEDIUM (in ISO 6429) +001A ; [.0000.0000.0000] # SUBSTITUTE (in ISO 6429) +001B ; [.0000.0000.0000] # ESCAPE (in ISO 6429) +001C ; [.0000.0000.0000] # FILE SEPARATOR (in ISO 6429) +001D ; [.0000.0000.0000] # GROUP SEPARATOR (in ISO 6429) +001E ; [.0000.0000.0000] # RECORD SEPARATOR (in ISO 6429) +001F ; [.0000.0000.0000] # UNIT SEPARATOR (in ISO 6429) +007F ; [.0000.0000.0000] # DELETE (in ISO 6429) +0080 ; [.0000.0000.0000] # <control> +0081 ; [.0000.0000.0000] # <control> +0082 ; [.0000.0000.0000] # BREAK PERMITTED HERE (in ISO 6429) +0083 ; [.0000.0000.0000] # NO BREAK HERE (in ISO 6429) +0084 ; [.0000.0000.0000] # <control> +0086 ; [.0000.0000.0000] # START OF SELECTED AREA (in ISO 6429) +0087 ; [.0000.0000.0000] # END OF SELECTED AREA (in ISO 6429) +0088 ; [.0000.0000.0000] # CHARACTER TABULATION SET (in ISO 6429) +0089 ; [.0000.0000.0000] # CHARACTER TABULATION WITH JUSTIFICATION (in ISO 6429) +008A ; [.0000.0000.0000] # LINE TABULATION SET (in ISO 6429) +008B ; [.0000.0000.0000] # PARTIAL LINE FORWARD (in ISO 6429) +008C ; [.0000.0000.0000] # PARTIAL LINE BACKWARD (in ISO 6429) +008D ; [.0000.0000.0000] # PARTIAL LINE FEED (in ISO 6429) +008E ; [.0000.0000.0000] # SINGLE SHIFT TWO (in ISO 6429) +008F ; [.0000.0000.0000] # SINGLE SHIFT THREE (in ISO 6429) +0090 ; [.0000.0000.0000] # DEVICE CONTROL STRING (in ISO 6429) +0091 ; [.0000.0000.0000] # PRIVATE USE ONE (in ISO 6429) +0092 ; [.0000.0000.0000] # PRIVATE USE TWO (in ISO 6429) +0093 ; [.0000.0000.0000] # SET TRANSMIT STATE (in ISO 6429) +0094 ; [.0000.0000.0000] # CANCEL CHARACTER (in ISO 6429) +0095 ; [.0000.0000.0000] # MESSAGE WAITING (in ISO 6429) +0096 ; [.0000.0000.0000] # START OF GUARDED AREA (in ISO 6429) +0097 ; [.0000.0000.0000] # END OF GUARDED AREA (in ISO 6429) +0098 ; [.0000.0000.0000] # START OF STRING (in ISO 6429) +0099 ; [.0000.0000.0000] # <control> +009A ; [.0000.0000.0000] # SINGLE CHARACTER INTRODUCER (in ISO 6429) +009B ; [.0000.0000.0000] # CONTROL SEQUENCE INTRODUCER (in ISO 6429) +009C ; [.0000.0000.0000] # STRING TERMINATOR (in ISO 6429) +009D ; [.0000.0000.0000] # OPERATING SYSTEM COMMAND (in ISO 6429) +009E ; [.0000.0000.0000] # PRIVACY MESSAGE (in ISO 6429) +009F ; [.0000.0000.0000] # APPLICATION PROGRAM COMMAND (in ISO 6429) +00AD ; [.0000.0000.0000] # SOFT HYPHEN +061C ; [.0000.0000.0000] # ARABIC LETTER MARK +070F ; [.0000.0000.0000] # SYRIAC ABBREVIATION MARK +08E2 ; [.0000.0000.0000] # ARABIC DISPUTED END OF AYAH +180B ; [.0000.0000.0000] # MONGOLIAN FREE VARIATION SELECTOR ONE +180C ; [.0000.0000.0000] # MONGOLIAN FREE VARIATION SELECTOR TWO +180D ; [.0000.0000.0000] # MONGOLIAN FREE VARIATION SELECTOR THREE +180E ; [.0000.0000.0000] # MONGOLIAN VOWEL SEPARATOR +200B ; [.0000.0000.0000] # ZERO WIDTH SPACE +200C ; [.0000.0000.0000] # ZERO WIDTH NON-JOINER +200D ; [.0000.0000.0000] # ZERO WIDTH JOINER +200E ; [.0000.0000.0000] # LEFT-TO-RIGHT MARK +200F ; [.0000.0000.0000] # RIGHT-TO-LEFT MARK +202A ; [.0000.0000.0000] # LEFT-TO-RIGHT EMBEDDING +202B ; [.0000.0000.0000] # RIGHT-TO-LEFT EMBEDDING +202C ; [.0000.0000.0000] # POP DIRECTIONAL FORMATTING +202D ; [.0000.0000.0000] # LEFT-TO-RIGHT OVERRIDE +202E ; [.0000.0000.0000] # RIGHT-TO-LEFT OVERRIDE +2060 ; [.0000.0000.0000] # WORD JOINER +2066 ; [.0000.0000.0000] # LEFT-TO-RIGHT ISOLATE +2067 ; [.0000.0000.0000] # RIGHT-TO-LEFT ISOLATE +2068 ; [.0000.0000.0000] # FIRST STRONG ISOLATE +2069 ; [.0000.0000.0000] # POP DIRECTIONAL ISOLATE +206A ; [.0000.0000.0000] # INHIBIT SYMMETRIC SWAPPING +206B ; [.0000.0000.0000] # ACTIVATE SYMMETRIC SWAPPING +206C ; [.0000.0000.0000] # INHIBIT ARABIC FORM SHAPING +206D ; [.0000.0000.0000] # ACTIVATE ARABIC FORM SHAPING +206E ; [.0000.0000.0000] # NATIONAL DIGIT SHAPES +206F ; [.0000.0000.0000] # NOMINAL DIGIT SHAPES +FE00 ; [.0000.0000.0000] # VARIATION SELECTOR-1 +FE01 ; [.0000.0000.0000] # VARIATION SELECTOR-2 +FE02 ; [.0000.0000.0000] # VARIATION SELECTOR-3 +FE03 ; [.0000.0000.0000] # VARIATION SELECTOR-4 +FE04 ; [.0000.0000.0000] # VARIATION SELECTOR-5 +FE05 ; [.0000.0000.0000] # VARIATION SELECTOR-6 +FE06 ; [.0000.0000.0000] # VARIATION SELECTOR-7 +FE07 ; [.0000.0000.0000] # VARIATION SELECTOR-8 +FE08 ; [.0000.0000.0000] # VARIATION SELECTOR-9 +FE09 ; [.0000.0000.0000] # VARIATION SELECTOR-10 +FE0A ; [.0000.0000.0000] # VARIATION SELECTOR-11 +FE0B ; [.0000.0000.0000] # VARIATION SELECTOR-12 +FE0C ; [.0000.0000.0000] # VARIATION SELECTOR-13 +FE0D ; [.0000.0000.0000] # VARIATION SELECTOR-14 +FE0E ; [.0000.0000.0000] # VARIATION SELECTOR-15 +FE0F ; [.0000.0000.0000] # VARIATION SELECTOR-16 +FEFF ; [.0000.0000.0000] # ZERO WIDTH NO-BREAK SPACE +FFF9 ; [.0000.0000.0000] # INTERLINEAR ANNOTATION ANCHOR +FFFA ; [.0000.0000.0000] # INTERLINEAR ANNOTATION SEPARATOR +FFFB ; [.0000.0000.0000] # INTERLINEAR ANNOTATION TERMINATOR +1BCA0 ; [.0000.0000.0000] # SHORTHAND FORMAT LETTER OVERLAP +1BCA1 ; [.0000.0000.0000] # SHORTHAND FORMAT CONTINUING OVERLAP +1BCA2 ; [.0000.0000.0000] # SHORTHAND FORMAT DOWN STEP +1BCA3 ; [.0000.0000.0000] # SHORTHAND FORMAT UP STEP +1D173 ; [.0000.0000.0000] # MUSICAL SYMBOL BEGIN BEAM +1D174 ; [.0000.0000.0000] # MUSICAL SYMBOL END BEAM +1D175 ; [.0000.0000.0000] # MUSICAL SYMBOL BEGIN TIE +1D176 ; [.0000.0000.0000] # MUSICAL SYMBOL END TIE +1D177 ; [.0000.0000.0000] # MUSICAL SYMBOL BEGIN SLUR +1D178 ; [.0000.0000.0000] # MUSICAL SYMBOL END SLUR +1D179 ; [.0000.0000.0000] # MUSICAL SYMBOL BEGIN PHRASE +1D17A ; [.0000.0000.0000] # MUSICAL SYMBOL END PHRASE +E0001 ; [.0000.0000.0000] # LANGUAGE TAG +E0020 ; [.0000.0000.0000] # TAG SPACE +E0021 ; [.0000.0000.0000] # TAG EXCLAMATION MARK +E0022 ; [.0000.0000.0000] # TAG QUOTATION MARK +E0023 ; [.0000.0000.0000] # TAG NUMBER SIGN +E0024 ; [.0000.0000.0000] # TAG DOLLAR SIGN +E0025 ; [.0000.0000.0000] # TAG PERCENT SIGN +E0026 ; [.0000.0000.0000] # TAG AMPERSAND +E0027 ; [.0000.0000.0000] # TAG APOSTROPHE +E0028 ; [.0000.0000.0000] # TAG LEFT PARENTHESIS +E0029 ; [.0000.0000.0000] # TAG RIGHT PARENTHESIS +E002A ; [.0000.0000.0000] # TAG ASTERISK +E002B ; [.0000.0000.0000] # TAG PLUS SIGN +E002C ; [.0000.0000.0000] # TAG COMMA +E002D ; [.0000.0000.0000] # TAG HYPHEN-MINUS +E002E ; [.0000.0000.0000] # TAG FULL STOP +E002F ; [.0000.0000.0000] # TAG SOLIDUS +E0030 ; [.0000.0000.0000] # TAG DIGIT ZERO +E0031 ; [.0000.0000.0000] # TAG DIGIT ONE +E0032 ; [.0000.0000.0000] # TAG DIGIT TWO +E0033 ; [.0000.0000.0000] # TAG DIGIT THREE +E0034 ; [.0000.0000.0000] # TAG DIGIT FOUR +E0035 ; [.0000.0000.0000] # TAG DIGIT FIVE +E0036 ; [.0000.0000.0000] # TAG DIGIT SIX +E0037 ; [.0000.0000.0000] # TAG DIGIT SEVEN +E0038 ; [.0000.0000.0000] # TAG DIGIT EIGHT +E0039 ; [.0000.0000.0000] # TAG DIGIT NINE +E003A ; [.0000.0000.0000] # TAG COLON +E003B ; [.0000.0000.0000] # TAG SEMICOLON +E003C ; [.0000.0000.0000] # TAG LESS-THAN SIGN +E003D ; [.0000.0000.0000] # TAG EQUALS SIGN +E003E ; [.0000.0000.0000] # TAG GREATER-THAN SIGN +E003F ; [.0000.0000.0000] # TAG QUESTION MARK +E0040 ; [.0000.0000.0000] # TAG COMMERCIAL AT +E0041 ; [.0000.0000.0000] # TAG LATIN CAPITAL LETTER A +E0042 ; [.0000.0000.0000] # TAG LATIN CAPITAL LETTER B +E0043 ; [.0000.0000.0000] # TAG LATIN CAPITAL LETTER C +E0044 ; [.0000.0000.0000] # TAG LATIN CAPITAL LETTER D +E0045 ; [.0000.0000.0000] # TAG LATIN CAPITAL LETTER E +E0046 ; [.0000.0000.0000] # TAG LATIN CAPITAL LETTER F +E0047 ; [.0000.0000.0000] # TAG LATIN CAPITAL LETTER G +E0048 ; [.0000.0000.0000] # TAG LATIN CAPITAL LETTER H +E0049 ; [.0000.0000.0000] # TAG LATIN CAPITAL LETTER I +E004A ; [.0000.0000.0000] # TAG LATIN CAPITAL LETTER J +E004B ; [.0000.0000.0000] # TAG LATIN CAPITAL LETTER K +E004C ; [.0000.0000.0000] # TAG LATIN CAPITAL LETTER L +E004D ; [.0000.0000.0000] # TAG LATIN CAPITAL LETTER M +E004E ; [.0000.0000.0000] # TAG LATIN CAPITAL LETTER N +E004F ; [.0000.0000.0000] # TAG LATIN CAPITAL LETTER O +E0050 ; [.0000.0000.0000] # TAG LATIN CAPITAL LETTER P +E0051 ; [.0000.0000.0000] # TAG LATIN CAPITAL LETTER Q +E0052 ; [.0000.0000.0000] # TAG LATIN CAPITAL LETTER R +E0053 ; [.0000.0000.0000] # TAG LATIN CAPITAL LETTER S +E0054 ; [.0000.0000.0000] # TAG LATIN CAPITAL LETTER T +E0055 ; [.0000.0000.0000] # TAG LATIN CAPITAL LETTER U +E0056 ; [.0000.0000.0000] # TAG LATIN CAPITAL LETTER V +E0057 ; [.0000.0000.0000] # TAG LATIN CAPITAL LETTER W +E0058 ; [.0000.0000.0000] # TAG LATIN CAPITAL LETTER X +E0059 ; [.0000.0000.0000] # TAG LATIN CAPITAL LETTER Y +E005A ; [.0000.0000.0000] # TAG LATIN CAPITAL LETTER Z +E005B ; [.0000.0000.0000] # TAG LEFT SQUARE BRACKET +E005C ; [.0000.0000.0000] # TAG REVERSE SOLIDUS +E005D ; [.0000.0000.0000] # TAG RIGHT SQUARE BRACKET +E005E ; [.0000.0000.0000] # TAG CIRCUMFLEX ACCENT +E005F ; [.0000.0000.0000] # TAG LOW LINE +E0060 ; [.0000.0000.0000] # TAG GRAVE ACCENT +E0061 ; [.0000.0000.0000] # TAG LATIN SMALL LETTER A +E0062 ; [.0000.0000.0000] # TAG LATIN SMALL LETTER B +E0063 ; [.0000.0000.0000] # TAG LATIN SMALL LETTER C +E0064 ; [.0000.0000.0000] # TAG LATIN SMALL LETTER D +E0065 ; [.0000.0000.0000] # TAG LATIN SMALL LETTER E +E0066 ; [.0000.0000.0000] # TAG LATIN SMALL LETTER F +E0067 ; [.0000.0000.0000] # TAG LATIN SMALL LETTER G +E0068 ; [.0000.0000.0000] # TAG LATIN SMALL LETTER H +E0069 ; [.0000.0000.0000] # TAG LATIN SMALL LETTER I +E006A ; [.0000.0000.0000] # TAG LATIN SMALL LETTER J +E006B ; [.0000.0000.0000] # TAG LATIN SMALL LETTER K +E006C ; [.0000.0000.0000] # TAG LATIN SMALL LETTER L +E006D ; [.0000.0000.0000] # TAG LATIN SMALL LETTER M +E006E ; [.0000.0000.0000] # TAG LATIN SMALL LETTER N +E006F ; [.0000.0000.0000] # TAG LATIN SMALL LETTER O +E0070 ; [.0000.0000.0000] # TAG LATIN SMALL LETTER P +E0071 ; [.0000.0000.0000] # TAG LATIN SMALL LETTER Q +E0072 ; [.0000.0000.0000] # TAG LATIN SMALL LETTER R +E0073 ; [.0000.0000.0000] # TAG LATIN SMALL LETTER S +E0074 ; [.0000.0000.0000] # TAG LATIN SMALL LETTER T +E0075 ; [.0000.0000.0000] # TAG LATIN SMALL LETTER U +E0076 ; [.0000.0000.0000] # TAG LATIN SMALL LETTER V +E0077 ; [.0000.0000.0000] # TAG LATIN SMALL LETTER W +E0078 ; [.0000.0000.0000] # TAG LATIN SMALL LETTER X +E0079 ; [.0000.0000.0000] # TAG LATIN SMALL LETTER Y +E007A ; [.0000.0000.0000] # TAG LATIN SMALL LETTER Z +E007B ; [.0000.0000.0000] # TAG LEFT CURLY BRACKET +E007C ; [.0000.0000.0000] # TAG VERTICAL LINE +E007D ; [.0000.0000.0000] # TAG RIGHT CURLY BRACKET +E007E ; [.0000.0000.0000] # TAG TILDE +E007F ; [.0000.0000.0000] # CANCEL TAG +E0100 ; [.0000.0000.0000] # VARIATION SELECTOR-17 +E0101 ; [.0000.0000.0000] # VARIATION SELECTOR-18 +E0102 ; [.0000.0000.0000] # VARIATION SELECTOR-19 +E0103 ; [.0000.0000.0000] # VARIATION SELECTOR-20 +E0104 ; [.0000.0000.0000] # VARIATION SELECTOR-21 +E0105 ; [.0000.0000.0000] # VARIATION SELECTOR-22 +E0106 ; [.0000.0000.0000] # VARIATION SELECTOR-23 +E0107 ; [.0000.0000.0000] # VARIATION SELECTOR-24 +E0108 ; [.0000.0000.0000] # VARIATION SELECTOR-25 +E0109 ; [.0000.0000.0000] # VARIATION SELECTOR-26 +E010A ; [.0000.0000.0000] # VARIATION SELECTOR-27 +E010B ; [.0000.0000.0000] # VARIATION SELECTOR-28 +E010C ; [.0000.0000.0000] # VARIATION SELECTOR-29 +E010D ; [.0000.0000.0000] # VARIATION SELECTOR-30 +E010E ; [.0000.0000.0000] # VARIATION SELECTOR-31 +E010F ; [.0000.0000.0000] # VARIATION SELECTOR-32 +E0110 ; [.0000.0000.0000] # VARIATION SELECTOR-33 +E0111 ; [.0000.0000.0000] # VARIATION SELECTOR-34 +E0112 ; [.0000.0000.0000] # VARIATION SELECTOR-35 +E0113 ; [.0000.0000.0000] # VARIATION SELECTOR-36 +E0114 ; [.0000.0000.0000] # VARIATION SELECTOR-37 +E0115 ; [.0000.0000.0000] # VARIATION SELECTOR-38 +E0116 ; [.0000.0000.0000] # VARIATION SELECTOR-39 +E0117 ; [.0000.0000.0000] # VARIATION SELECTOR-40 +E0118 ; [.0000.0000.0000] # VARIATION SELECTOR-41 +E0119 ; [.0000.0000.0000] # VARIATION SELECTOR-42 +E011A ; [.0000.0000.0000] # VARIATION SELECTOR-43 +E011B ; [.0000.0000.0000] # VARIATION SELECTOR-44 +E011C ; [.0000.0000.0000] # VARIATION SELECTOR-45 +E011D ; [.0000.0000.0000] # VARIATION SELECTOR-46 +E011E ; [.0000.0000.0000] # VARIATION SELECTOR-47 +E011F ; [.0000.0000.0000] # VARIATION SELECTOR-48 +E0120 ; [.0000.0000.0000] # VARIATION SELECTOR-49 +E0121 ; [.0000.0000.0000] # VARIATION SELECTOR-50 +E0122 ; [.0000.0000.0000] # VARIATION SELECTOR-51 +E0123 ; [.0000.0000.0000] # VARIATION SELECTOR-52 +E0124 ; [.0000.0000.0000] # VARIATION SELECTOR-53 +E0125 ; [.0000.0000.0000] # VARIATION SELECTOR-54 +E0126 ; [.0000.0000.0000] # VARIATION SELECTOR-55 +E0127 ; [.0000.0000.0000] # VARIATION SELECTOR-56 +E0128 ; [.0000.0000.0000] # VARIATION SELECTOR-57 +E0129 ; [.0000.0000.0000] # VARIATION SELECTOR-58 +E012A ; [.0000.0000.0000] # VARIATION SELECTOR-59 +E012B ; [.0000.0000.0000] # VARIATION SELECTOR-60 +E012C ; [.0000.0000.0000] # VARIATION SELECTOR-61 +E012D ; [.0000.0000.0000] # VARIATION SELECTOR-62 +E012E ; [.0000.0000.0000] # VARIATION SELECTOR-63 +E012F ; [.0000.0000.0000] # VARIATION SELECTOR-64 +E0130 ; [.0000.0000.0000] # VARIATION SELECTOR-65 +E0131 ; [.0000.0000.0000] # VARIATION SELECTOR-66 +E0132 ; [.0000.0000.0000] # VARIATION SELECTOR-67 +E0133 ; [.0000.0000.0000] # VARIATION SELECTOR-68 +E0134 ; [.0000.0000.0000] # VARIATION SELECTOR-69 +E0135 ; [.0000.0000.0000] # VARIATION SELECTOR-70 +E0136 ; [.0000.0000.0000] # VARIATION SELECTOR-71 +E0137 ; [.0000.0000.0000] # VARIATION SELECTOR-72 +E0138 ; [.0000.0000.0000] # VARIATION SELECTOR-73 +E0139 ; [.0000.0000.0000] # VARIATION SELECTOR-74 +E013A ; [.0000.0000.0000] # VARIATION SELECTOR-75 +E013B ; [.0000.0000.0000] # VARIATION SELECTOR-76 +E013C ; [.0000.0000.0000] # VARIATION SELECTOR-77 +E013D ; [.0000.0000.0000] # VARIATION SELECTOR-78 +E013E ; [.0000.0000.0000] # VARIATION SELECTOR-79 +E013F ; [.0000.0000.0000] # VARIATION SELECTOR-80 +E0140 ; [.0000.0000.0000] # VARIATION SELECTOR-81 +E0141 ; [.0000.0000.0000] # VARIATION SELECTOR-82 +E0142 ; [.0000.0000.0000] # VARIATION SELECTOR-83 +E0143 ; [.0000.0000.0000] # VARIATION SELECTOR-84 +E0144 ; [.0000.0000.0000] # VARIATION SELECTOR-85 +E0145 ; [.0000.0000.0000] # VARIATION SELECTOR-86 +E0146 ; [.0000.0000.0000] # VARIATION SELECTOR-87 +E0147 ; [.0000.0000.0000] # VARIATION SELECTOR-88 +E0148 ; [.0000.0000.0000] # VARIATION SELECTOR-89 +E0149 ; [.0000.0000.0000] # VARIATION SELECTOR-90 +E014A ; [.0000.0000.0000] # VARIATION SELECTOR-91 +E014B ; [.0000.0000.0000] # VARIATION SELECTOR-92 +E014C ; [.0000.0000.0000] # VARIATION SELECTOR-93 +E014D ; [.0000.0000.0000] # VARIATION SELECTOR-94 +E014E ; [.0000.0000.0000] # VARIATION SELECTOR-95 +E014F ; [.0000.0000.0000] # VARIATION SELECTOR-96 +E0150 ; [.0000.0000.0000] # VARIATION SELECTOR-97 +E0151 ; [.0000.0000.0000] # VARIATION SELECTOR-98 +E0152 ; [.0000.0000.0000] # VARIATION SELECTOR-99 +E0153 ; [.0000.0000.0000] # VARIATION SELECTOR-100 +E0154 ; [.0000.0000.0000] # VARIATION SELECTOR-101 +E0155 ; [.0000.0000.0000] # VARIATION SELECTOR-102 +E0156 ; [.0000.0000.0000] # VARIATION SELECTOR-103 +E0157 ; [.0000.0000.0000] # VARIATION SELECTOR-104 +E0158 ; [.0000.0000.0000] # VARIATION SELECTOR-105 +E0159 ; [.0000.0000.0000] # VARIATION SELECTOR-106 +E015A ; [.0000.0000.0000] # VARIATION SELECTOR-107 +E015B ; [.0000.0000.0000] # VARIATION SELECTOR-108 +E015C ; [.0000.0000.0000] # VARIATION SELECTOR-109 +E015D ; [.0000.0000.0000] # VARIATION SELECTOR-110 +E015E ; [.0000.0000.0000] # VARIATION SELECTOR-111 +E015F ; [.0000.0000.0000] # VARIATION SELECTOR-112 +E0160 ; [.0000.0000.0000] # VARIATION SELECTOR-113 +E0161 ; [.0000.0000.0000] # VARIATION SELECTOR-114 +E0162 ; [.0000.0000.0000] # VARIATION SELECTOR-115 +E0163 ; [.0000.0000.0000] # VARIATION SELECTOR-116 +E0164 ; [.0000.0000.0000] # VARIATION SELECTOR-117 +E0165 ; [.0000.0000.0000] # VARIATION SELECTOR-118 +E0166 ; [.0000.0000.0000] # VARIATION SELECTOR-119 +E0167 ; [.0000.0000.0000] # VARIATION SELECTOR-120 +E0168 ; [.0000.0000.0000] # VARIATION SELECTOR-121 +E0169 ; [.0000.0000.0000] # VARIATION SELECTOR-122 +E016A ; [.0000.0000.0000] # VARIATION SELECTOR-123 +E016B ; [.0000.0000.0000] # VARIATION SELECTOR-124 +E016C ; [.0000.0000.0000] # VARIATION SELECTOR-125 +E016D ; [.0000.0000.0000] # VARIATION SELECTOR-126 +E016E ; [.0000.0000.0000] # VARIATION SELECTOR-127 +E016F ; [.0000.0000.0000] # VARIATION SELECTOR-128 +E0170 ; [.0000.0000.0000] # VARIATION SELECTOR-129 +E0171 ; [.0000.0000.0000] # VARIATION SELECTOR-130 +E0172 ; [.0000.0000.0000] # VARIATION SELECTOR-131 +E0173 ; [.0000.0000.0000] # VARIATION SELECTOR-132 +E0174 ; [.0000.0000.0000] # VARIATION SELECTOR-133 +E0175 ; [.0000.0000.0000] # VARIATION SELECTOR-134 +E0176 ; [.0000.0000.0000] # VARIATION SELECTOR-135 +E0177 ; [.0000.0000.0000] # VARIATION SELECTOR-136 +E0178 ; [.0000.0000.0000] # VARIATION SELECTOR-137 +E0179 ; [.0000.0000.0000] # VARIATION SELECTOR-138 +E017A ; [.0000.0000.0000] # VARIATION SELECTOR-139 +E017B ; [.0000.0000.0000] # VARIATION SELECTOR-140 +E017C ; [.0000.0000.0000] # VARIATION SELECTOR-141 +E017D ; [.0000.0000.0000] # VARIATION SELECTOR-142 +E017E ; [.0000.0000.0000] # VARIATION SELECTOR-143 +E017F ; [.0000.0000.0000] # VARIATION SELECTOR-144 +E0180 ; [.0000.0000.0000] # VARIATION SELECTOR-145 +E0181 ; [.0000.0000.0000] # VARIATION SELECTOR-146 +E0182 ; [.0000.0000.0000] # VARIATION SELECTOR-147 +E0183 ; [.0000.0000.0000] # VARIATION SELECTOR-148 +E0184 ; [.0000.0000.0000] # VARIATION SELECTOR-149 +E0185 ; [.0000.0000.0000] # VARIATION SELECTOR-150 +E0186 ; [.0000.0000.0000] # VARIATION SELECTOR-151 +E0187 ; [.0000.0000.0000] # VARIATION SELECTOR-152 +E0188 ; [.0000.0000.0000] # VARIATION SELECTOR-153 +E0189 ; [.0000.0000.0000] # VARIATION SELECTOR-154 +E018A ; [.0000.0000.0000] # VARIATION SELECTOR-155 +E018B ; [.0000.0000.0000] # VARIATION SELECTOR-156 +E018C ; [.0000.0000.0000] # VARIATION SELECTOR-157 +E018D ; [.0000.0000.0000] # VARIATION SELECTOR-158 +E018E ; [.0000.0000.0000] # VARIATION SELECTOR-159 +E018F ; [.0000.0000.0000] # VARIATION SELECTOR-160 +E0190 ; [.0000.0000.0000] # VARIATION SELECTOR-161 +E0191 ; [.0000.0000.0000] # VARIATION SELECTOR-162 +E0192 ; [.0000.0000.0000] # VARIATION SELECTOR-163 +E0193 ; [.0000.0000.0000] # VARIATION SELECTOR-164 +E0194 ; [.0000.0000.0000] # VARIATION SELECTOR-165 +E0195 ; [.0000.0000.0000] # VARIATION SELECTOR-166 +E0196 ; [.0000.0000.0000] # VARIATION SELECTOR-167 +E0197 ; [.0000.0000.0000] # VARIATION SELECTOR-168 +E0198 ; [.0000.0000.0000] # VARIATION SELECTOR-169 +E0199 ; [.0000.0000.0000] # VARIATION SELECTOR-170 +E019A ; [.0000.0000.0000] # VARIATION SELECTOR-171 +E019B ; [.0000.0000.0000] # VARIATION SELECTOR-172 +E019C ; [.0000.0000.0000] # VARIATION SELECTOR-173 +E019D ; [.0000.0000.0000] # VARIATION SELECTOR-174 +E019E ; [.0000.0000.0000] # VARIATION SELECTOR-175 +E019F ; [.0000.0000.0000] # VARIATION SELECTOR-176 +E01A0 ; [.0000.0000.0000] # VARIATION SELECTOR-177 +E01A1 ; [.0000.0000.0000] # VARIATION SELECTOR-178 +E01A2 ; [.0000.0000.0000] # VARIATION SELECTOR-179 +E01A3 ; [.0000.0000.0000] # VARIATION SELECTOR-180 +E01A4 ; [.0000.0000.0000] # VARIATION SELECTOR-181 +E01A5 ; [.0000.0000.0000] # VARIATION SELECTOR-182 +E01A6 ; [.0000.0000.0000] # VARIATION SELECTOR-183 +E01A7 ; [.0000.0000.0000] # VARIATION SELECTOR-184 +E01A8 ; [.0000.0000.0000] # VARIATION SELECTOR-185 +E01A9 ; [.0000.0000.0000] # VARIATION SELECTOR-186 +E01AA ; [.0000.0000.0000] # VARIATION SELECTOR-187 +E01AB ; [.0000.0000.0000] # VARIATION SELECTOR-188 +E01AC ; [.0000.0000.0000] # VARIATION SELECTOR-189 +E01AD ; [.0000.0000.0000] # VARIATION SELECTOR-190 +E01AE ; [.0000.0000.0000] # VARIATION SELECTOR-191 +E01AF ; [.0000.0000.0000] # VARIATION SELECTOR-192 +E01B0 ; [.0000.0000.0000] # VARIATION SELECTOR-193 +E01B1 ; [.0000.0000.0000] # VARIATION SELECTOR-194 +E01B2 ; [.0000.0000.0000] # VARIATION SELECTOR-195 +E01B3 ; [.0000.0000.0000] # VARIATION SELECTOR-196 +E01B4 ; [.0000.0000.0000] # VARIATION SELECTOR-197 +E01B5 ; [.0000.0000.0000] # VARIATION SELECTOR-198 +E01B6 ; [.0000.0000.0000] # VARIATION SELECTOR-199 +E01B7 ; [.0000.0000.0000] # VARIATION SELECTOR-200 +E01B8 ; [.0000.0000.0000] # VARIATION SELECTOR-201 +E01B9 ; [.0000.0000.0000] # VARIATION SELECTOR-202 +E01BA ; [.0000.0000.0000] # VARIATION SELECTOR-203 +E01BB ; [.0000.0000.0000] # VARIATION SELECTOR-204 +E01BC ; [.0000.0000.0000] # VARIATION SELECTOR-205 +E01BD ; [.0000.0000.0000] # VARIATION SELECTOR-206 +E01BE ; [.0000.0000.0000] # VARIATION SELECTOR-207 +E01BF ; [.0000.0000.0000] # VARIATION SELECTOR-208 +E01C0 ; [.0000.0000.0000] # VARIATION SELECTOR-209 +E01C1 ; [.0000.0000.0000] # VARIATION SELECTOR-210 +E01C2 ; [.0000.0000.0000] # VARIATION SELECTOR-211 +E01C3 ; [.0000.0000.0000] # VARIATION SELECTOR-212 +E01C4 ; [.0000.0000.0000] # VARIATION SELECTOR-213 +E01C5 ; [.0000.0000.0000] # VARIATION SELECTOR-214 +E01C6 ; [.0000.0000.0000] # VARIATION SELECTOR-215 +E01C7 ; [.0000.0000.0000] # VARIATION SELECTOR-216 +E01C8 ; [.0000.0000.0000] # VARIATION SELECTOR-217 +E01C9 ; [.0000.0000.0000] # VARIATION SELECTOR-218 +E01CA ; [.0000.0000.0000] # VARIATION SELECTOR-219 +E01CB ; [.0000.0000.0000] # VARIATION SELECTOR-220 +E01CC ; [.0000.0000.0000] # VARIATION SELECTOR-221 +E01CD ; [.0000.0000.0000] # VARIATION SELECTOR-222 +E01CE ; [.0000.0000.0000] # VARIATION SELECTOR-223 +E01CF ; [.0000.0000.0000] # VARIATION SELECTOR-224 +E01D0 ; [.0000.0000.0000] # VARIATION SELECTOR-225 +E01D1 ; [.0000.0000.0000] # VARIATION SELECTOR-226 +E01D2 ; [.0000.0000.0000] # VARIATION SELECTOR-227 +E01D3 ; [.0000.0000.0000] # VARIATION SELECTOR-228 +E01D4 ; [.0000.0000.0000] # VARIATION SELECTOR-229 +E01D5 ; [.0000.0000.0000] # VARIATION SELECTOR-230 +E01D6 ; [.0000.0000.0000] # VARIATION SELECTOR-231 +E01D7 ; [.0000.0000.0000] # VARIATION SELECTOR-232 +E01D8 ; [.0000.0000.0000] # VARIATION SELECTOR-233 +E01D9 ; [.0000.0000.0000] # VARIATION SELECTOR-234 +E01DA ; [.0000.0000.0000] # VARIATION SELECTOR-235 +E01DB ; [.0000.0000.0000] # VARIATION SELECTOR-236 +E01DC ; [.0000.0000.0000] # VARIATION SELECTOR-237 +E01DD ; [.0000.0000.0000] # VARIATION SELECTOR-238 +E01DE ; [.0000.0000.0000] # VARIATION SELECTOR-239 +E01DF ; [.0000.0000.0000] # VARIATION SELECTOR-240 +E01E0 ; [.0000.0000.0000] # VARIATION SELECTOR-241 +E01E1 ; [.0000.0000.0000] # VARIATION SELECTOR-242 +E01E2 ; [.0000.0000.0000] # VARIATION SELECTOR-243 +E01E3 ; [.0000.0000.0000] # VARIATION SELECTOR-244 +E01E4 ; [.0000.0000.0000] # VARIATION SELECTOR-245 +E01E5 ; [.0000.0000.0000] # VARIATION SELECTOR-246 +E01E6 ; [.0000.0000.0000] # VARIATION SELECTOR-247 +E01E7 ; [.0000.0000.0000] # VARIATION SELECTOR-248 +E01E8 ; [.0000.0000.0000] # VARIATION SELECTOR-249 +E01E9 ; [.0000.0000.0000] # VARIATION SELECTOR-250 +E01EA ; [.0000.0000.0000] # VARIATION SELECTOR-251 +E01EB ; [.0000.0000.0000] # VARIATION SELECTOR-252 +E01EC ; [.0000.0000.0000] # VARIATION SELECTOR-253 +E01ED ; [.0000.0000.0000] # VARIATION SELECTOR-254 +E01EE ; [.0000.0000.0000] # VARIATION SELECTOR-255 +E01EF ; [.0000.0000.0000] # VARIATION SELECTOR-256 +0009 ; [*0201.0020.0002] # HORIZONTAL TABULATION (in ISO 6429) +000A ; [*0202.0020.0002] # LINE FEED (in ISO 6429) +000B ; [*0203.0020.0002] # VERTICAL TABULATION (in ISO 6429) +000C ; [*0204.0020.0002] # FORM FEED (in ISO 6429) +000D ; [*0205.0020.0002] # CARRIAGE RETURN (in ISO 6429) +0020 ; [*0209.0020.0002] # SPACE +0021 ; [*0261.0020.0002] # EXCLAMATION MARK +0022 ; [*030D.0020.0002] # QUOTATION MARK +0023 ; [*0399.0020.0002] # NUMBER SIGN +0025 ; [*039A.0020.0002] # PERCENT SIGN +0026 ; [*0397.0020.0002] # AMPERSAND +0027 ; [*0306.0020.0002] # APOSTROPHE +0028 ; [*0318.0020.0002] # LEFT PARENTHESIS +0029 ; [*0319.0020.0002] # RIGHT PARENTHESIS +002A ; [*0390.0020.0002] # ASTERISK +002B ; [*062C.0020.0002] # PLUS SIGN +002C ; [*0222.0020.0002] # COMMA +002D ; [*020D.0020.0002] # HYPHEN-MINUS +002E ; [*0278.0020.0002] # FULL STOP +002F ; [*0395.0020.0002] # SOLIDUS +003A ; [*023A.0020.0002] # COLON +003B ; [*0234.0020.0002] # SEMICOLON +003C ; [*0630.0020.0002] # LESS-THAN SIGN +003D ; [*0631.0020.0002] # EQUALS SIGN +003E ; [*0632.0020.0002] # GREATER-THAN SIGN +003F ; [*0267.0020.0002] # QUESTION MARK +0040 ; [*038F.0020.0002] # COMMERCIAL AT +005B ; [*031A.0020.0002] # LEFT SQUARE BRACKET +005C ; [*0396.0020.0002] # REVERSE SOLIDUS +005D ; [*031B.0020.0002] # RIGHT SQUARE BRACKET +005E ; [*049B.0020.0002] # CIRCUMFLEX ACCENT +005F ; [*020B.0020.0002] # LOW LINE +0060 ; [*0498.0020.0002] # GRAVE ACCENT +007B ; [*031C.0020.0002] # LEFT CURLY BRACKET +007C ; [*0634.0020.0002] # VERTICAL LINE +007D ; [*031D.0020.0002] # RIGHT CURLY BRACKET +007E ; [*0636.0020.0002] # TILDE +0085 ; [*0206.0020.0002] # NEXT LINE (in ISO 6429) +00A0 ; [*0209.0020.001B] # NO-BREAK SPACE +00A1 ; [*0262.0020.0002] # INVERTED EXCLAMATION MARK +00A6 ; [*0635.0020.0002] # BROKEN BAR +00A7 ; [*038A.0020.0002] # SECTION SIGN +00A8 ; [*049F.0020.0002] # DIAERESIS +00A9 ; [*059A.0020.0002] # COPYRIGHT SIGN +00AB ; [*0316.0020.0002] # LEFT-POINTING DOUBLE ANGLE QUOTATION MARK +00AC ; [*0633.0020.0002] # NOT SIGN +00AE ; [*059B.0020.0002] # REGISTERED SIGN +00AF ; [*049C.0020.0002] # MACRON +00B0 ; [*050C.0020.0002] # DEGREE SIGN +00B1 ; [*062D.0020.0002] # PLUS-MINUS SIGN +00B4 ; [*0499.0020.0002] # ACUTE ACCENT +00B6 ; [*038C.0020.0002] # PILCROW SIGN +00B7 ; [*028C.0020.0002] # MIDDLE DOT +00B8 ; [*04A2.0020.0002] # CEDILLA +00BB ; [*0317.0020.0002] # RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK +00BF ; [*0268.0020.0002] # INVERTED QUESTION MARK +00D7 ; [*062F.0020.0002] # MULTIPLICATION SIGN +00F7 ; [*062E.0020.0002] # DIVISION SIGN +02B9 ; [*04A9.0020.0002] # MODIFIER LETTER PRIME +02BA ; [*04AB.0020.0002] # MODIFIER LETTER DOUBLE PRIME +02C2 ; [*04AC.0020.0002] # MODIFIER LETTER LEFT ARROWHEAD +02C3 ; [*04AD.0020.0002] # MODIFIER LETTER RIGHT ARROWHEAD +02C4 ; [*04AE.0020.0002] # MODIFIER LETTER UP ARROWHEAD +02C5 ; [*04AF.0020.0002] # MODIFIER LETTER DOWN ARROWHEAD +02C6 ; [*04B0.0020.0002] # MODIFIER LETTER CIRCUMFLEX ACCENT +02C7 ; [*04B1.0020.0002] # CARON +02C8 ; [*04B2.0020.0002] # MODIFIER LETTER VERTICAL LINE +02C9 ; [*04B3.0020.0002] # MODIFIER LETTER MACRON +02CA ; [*04B4.0020.0002] # MODIFIER LETTER ACUTE ACCENT +02CB ; [*04B5.0020.0002] # MODIFIER LETTER GRAVE ACCENT +02CC ; [*04B6.0020.0002] # MODIFIER LETTER LOW VERTICAL LINE +02CD ; [*04B7.0020.0002] # MODIFIER LETTER LOW MACRON +02CE ; [*04B8.0020.0002] # MODIFIER LETTER LOW GRAVE ACCENT +02CF ; [*04B9.0020.0002] # MODIFIER LETTER LOW ACUTE ACCENT +02D2 ; [*04BA.0020.0002] # MODIFIER LETTER CENTRED RIGHT HALF RING +02D3 ; [*04BB.0020.0002] # MODIFIER LETTER CENTRED LEFT HALF RING +02D4 ; [*04BC.0020.0002] # MODIFIER LETTER UP TACK +02D5 ; [*04BD.0020.0002] # MODIFIER LETTER DOWN TACK +02D6 ; [*04BE.0020.0002] # MODIFIER LETTER PLUS SIGN +02D7 ; [*04BF.0020.0002] # MODIFIER LETTER MINUS SIGN +02D8 ; [*049D.0020.0002] # BREVE +02D9 ; [*049E.0020.0002] # DOT ABOVE +02DA ; [*04A0.0020.0002] # RING ABOVE +02DB ; [*04A3.0020.0002] # OGONEK +02DC ; [*049A.0020.0002] # SMALL TILDE +02DD ; [*04A1.0020.0002] # DOUBLE ACUTE ACCENT +02DE ; [*04C0.0020.0002] # MODIFIER LETTER RHOTIC HOOK +02DF ; [*04C1.0020.0002] # MODIFIER LETTER CROSS ACCENT +02E5 ; [*04C2.0020.0002] # MODIFIER LETTER EXTRA-HIGH TONE BAR +02E6 ; [*04C3.0020.0002] # MODIFIER LETTER HIGH TONE BAR +02E7 ; [*04C4.0020.0002] # MODIFIER LETTER MID TONE BAR +02E8 ; [*04C5.0020.0002] # MODIFIER LETTER LOW TONE BAR +02E9 ; [*04C6.0020.0002] # MODIFIER LETTER EXTRA-LOW TONE BAR +02EA ; [*04C7.0020.0002] # MODIFIER LETTER YIN DEPARTING TONE MARK +02EB ; [*04C8.0020.0002] # MODIFIER LETTER YANG DEPARTING TONE MARK +02EC ; [*04C9.0020.0002] # MODIFIER LETTER VOICING +02ED ; [*04CA.0020.0002] # MODIFIER LETTER UNASPIRATED +02EF ; [*04CB.0020.0002] # MODIFIER LETTER LOW DOWN ARROWHEAD +02F0 ; [*04CC.0020.0002] # MODIFIER LETTER LOW UP ARROWHEAD +02F1 ; [*04CD.0020.0002] # MODIFIER LETTER LOW LEFT ARROWHEAD +02F2 ; [*04CE.0020.0002] # MODIFIER LETTER LOW RIGHT ARROWHEAD +02F3 ; [*04CF.0020.0002] # MODIFIER LETTER LOW RING +02F4 ; [*04D0.0020.0002] # MODIFIER LETTER MIDDLE GRAVE ACCENT +02F5 ; [*04D1.0020.0002] # MODIFIER LETTER MIDDLE DOUBLE GRAVE ACCENT +02F6 ; [*04D2.0020.0002] # MODIFIER LETTER MIDDLE DOUBLE ACUTE ACCENT +02F7 ; [*04D3.0020.0002] # MODIFIER LETTER LOW TILDE +02F8 ; [*04D4.0020.0002] # MODIFIER LETTER RAISED COLON +02F9 ; [*04D5.0020.0002] # MODIFIER LETTER BEGIN HIGH TONE +02FA ; [*04D6.0020.0002] # MODIFIER LETTER END HIGH TONE +02FB ; [*04D7.0020.0002] # MODIFIER LETTER BEGIN LOW TONE +02FC ; [*04D8.0020.0002] # MODIFIER LETTER END LOW TONE +02FD ; [*04D9.0020.0002] # MODIFIER LETTER SHELF +02FE ; [*04DA.0020.0002] # MODIFIER LETTER OPEN SHELF +02FF ; [*04DB.0020.0002] # MODIFIER LETTER LOW LEFT ARROW +034F ; [.0000.0000.0000] # COMBINING GRAPHEME JOINER +0374 ; [*04A9.0020.0002] # GREEK NUMERAL SIGN +0375 ; [*04AA.0020.0002] # GREEK LOWER NUMERAL SIGN +037E ; [*0234.0020.0002] # GREEK QUESTION MARK +0384 ; [*0499.0020.0002] # GREEK TONOS +0385 ; [*049F.0020.0002][.0000.0024.0002] # GREEK DIALYTIKA TONOS +0387 ; [*028C.0020.0002] # GREEK ANO TELEIA +03F6 ; [*0627.0020.0002] # GREEK REVERSED LUNATE EPSILON SYMBOL +0482 ; [*050D.0020.0002] # CYRILLIC THOUSANDS SIGN +0488 ; [.0000.0000.0000] # COMBINING CYRILLIC HUNDRED THOUSANDS SIGN +0489 ; [.0000.0000.0000] # COMBINING CYRILLIC MILLIONS SIGN +055A ; [*03D0.0020.0002] # ARMENIAN APOSTROPHE +055B ; [*03D1.0020.0002] # ARMENIAN EMPHASIS MARK +055C ; [*0263.0020.0002] # ARMENIAN EXCLAMATION MARK +055D ; [*0226.0020.0002] # ARMENIAN COMMA +055E ; [*026A.0020.0002] # ARMENIAN QUESTION MARK +055F ; [*03D2.0020.0002] # ARMENIAN ABBREVIATION MARK +0589 ; [*023B.0020.0002] # ARMENIAN FULL STOP +058A ; [*020E.0020.0002] # ARMENIAN HYPHEN +058D ; [*050E.0020.0002] # RIGHT-FACING ARMENIAN ETERNITY SIGN +058E ; [*050F.0020.0002] # LEFT-FACING ARMENIAN ETERNITY SIGN +0591 ; [.0000.0000.0000] # HEBREW ACCENT ETNAHTA +0592 ; [.0000.0000.0000] # HEBREW ACCENT SEGOL +0593 ; [.0000.0000.0000] # HEBREW ACCENT SHALSHELET +0594 ; [.0000.0000.0000] # HEBREW ACCENT ZAQEF QATAN +0595 ; [.0000.0000.0000] # HEBREW ACCENT ZAQEF GADOL +0596 ; [.0000.0000.0000] # HEBREW ACCENT TIPEHA +0597 ; [.0000.0000.0000] # HEBREW ACCENT REVIA +0598 ; [.0000.0000.0000] # HEBREW ACCENT ZARQA +0599 ; [.0000.0000.0000] # HEBREW ACCENT PASHTA +059A ; [.0000.0000.0000] # HEBREW ACCENT YETIV +059B ; [.0000.0000.0000] # HEBREW ACCENT TEVIR +059C ; [.0000.0000.0000] # HEBREW ACCENT GERESH +059D ; [.0000.0000.0000] # HEBREW ACCENT GERESH MUQDAM +059E ; [.0000.0000.0000] # HEBREW ACCENT GERSHAYIM +059F ; [.0000.0000.0000] # HEBREW ACCENT QARNEY PARA +05A0 ; [.0000.0000.0000] # HEBREW ACCENT TELISHA GEDOLA +05A1 ; [.0000.0000.0000] # HEBREW ACCENT PAZER +05A2 ; [.0000.0000.0000] # HEBREW ACCENT ATNAH HAFUKH +05A3 ; [.0000.0000.0000] # HEBREW ACCENT MUNAH +05A4 ; [.0000.0000.0000] # HEBREW ACCENT MAHAPAKH +05A5 ; [.0000.0000.0000] # HEBREW ACCENT MERKHA +05A6 ; [.0000.0000.0000] # HEBREW ACCENT MERKHA KEFULA +05A7 ; [.0000.0000.0000] # HEBREW ACCENT DARGA +05A8 ; [.0000.0000.0000] # HEBREW ACCENT QADMA +05A9 ; [.0000.0000.0000] # HEBREW ACCENT TELISHA QETANA +05AA ; [.0000.0000.0000] # HEBREW ACCENT YERAH BEN YOMO +05AB ; [.0000.0000.0000] # HEBREW ACCENT OLE +05AC ; [.0000.0000.0000] # HEBREW ACCENT ILUY +05AD ; [.0000.0000.0000] # HEBREW ACCENT DEHI +05AE ; [.0000.0000.0000] # HEBREW ACCENT ZINOR +05AF ; [.0000.0000.0000] # HEBREW MARK MASORA CIRCLE +05BD ; [.0000.0000.0000] # HEBREW POINT METEG +05BE ; [*03D3.0020.0002] # HEBREW PUNCTUATION MAQAF +05C0 ; [*03D4.0020.0002] # HEBREW PUNCTUATION PASEQ +05C3 ; [*03D5.0020.0002] # HEBREW PUNCTUATION SOF PASUQ +05C4 ; [.0000.0000.0000] # HEBREW MARK UPPER DOT +05C5 ; [.0000.0000.0000] # HEBREW MARK LOWER DOT +05C6 ; [*03D6.0020.0002] # HEBREW PUNCTUATION NUN HAFUKHA +05F3 ; [*03D7.0020.0002] # HEBREW PUNCTUATION GERESH +05F4 ; [*03D8.0020.0002] # HEBREW PUNCTUATION GERSHAYIM +0600 ; [.0000.0000.0000] # ARABIC NUMBER SIGN +0601 ; [.0000.0000.0000] # ARABIC SIGN SANAH +0602 ; [.0000.0000.0000] # ARABIC FOOTNOTE MARKER +0603 ; [.0000.0000.0000] # ARABIC SIGN SAFHA +0604 ; [.0000.0000.0000] # ARABIC SIGN SAMVAT +0605 ; [.0000.0000.0000] # ARABIC NUMBER MARK ABOVE +0606 ; [*0643.0020.0002] # ARABIC-INDIC CUBE ROOT +0607 ; [*0645.0020.0002] # ARABIC-INDIC FOURTH ROOT +0608 ; [*0510.0020.0002] # ARABIC RAY +0609 ; [*039D.0020.0002] # ARABIC-INDIC PER MILLE SIGN +060A ; [*039F.0020.0002] # ARABIC-INDIC PER TEN THOUSAND SIGN +060C ; [*0227.0020.0002] # ARABIC COMMA +060D ; [*0228.0020.0002] # ARABIC DATE SEPARATOR +060E ; [*0513.0020.0002] # ARABIC POETIC VERSE SIGN +060F ; [*0514.0020.0002] # ARABIC SIGN MISRA +0610 ; [.0000.0000.0000] # ARABIC SIGN SALLALLAHOU ALAYHE WASSALLAM +0611 ; [.0000.0000.0000] # ARABIC SIGN ALAYHE ASSALLAM +0612 ; [.0000.0000.0000] # ARABIC SIGN RAHMATULLAH ALAYHE +0613 ; [.0000.0000.0000] # ARABIC SIGN RADI ALLAHOU ANHU +0614 ; [.0000.0000.0000] # ARABIC SIGN TAKHALLUS +0615 ; [.0000.0000.0000] # ARABIC SMALL HIGH TAH +0616 ; [.0000.0000.0000] # ARABIC SMALL HIGH LIGATURE ALEF WITH LAM WITH YEH +0617 ; [.0000.0000.0000] # ARABIC SMALL HIGH ZAIN +0618 ; [.0000.0000.0000] # ARABIC SMALL FATHA +0619 ; [.0000.0000.0000] # ARABIC SMALL DAMMA +061A ; [.0000.0000.0000] # ARABIC SMALL KASRA +061B ; [*0235.0020.0002] # ARABIC SEMICOLON +061E ; [*023C.0020.0002] # ARABIC TRIPLE DOT PUNCTUATION MARK +061F ; [*026B.0020.0002] # ARABIC QUESTION MARK +0640 ; [.0000.0000.0000] # ARABIC TATWEEL +066A ; [*039B.0020.0002] # ARABIC PERCENT SIGN +066B ; [*0229.0020.0002] # ARABIC DECIMAL SEPARATOR +066C ; [*022A.0020.0002] # ARABIC THOUSANDS SEPARATOR +066D ; [*0393.0020.0002] # ARABIC FIVE POINTED STAR +06D4 ; [*027A.0020.0002] # ARABIC FULL STOP +06D6 ; [.0000.0000.0000] # ARABIC SMALL HIGH LIGATURE SAD WITH LAM WITH ALEF MAKSURA +06D7 ; [.0000.0000.0000] # ARABIC SMALL HIGH LIGATURE QAF WITH LAM WITH ALEF MAKSURA +06D8 ; [.0000.0000.0000] # ARABIC SMALL HIGH MEEM INITIAL FORM +06D9 ; [.0000.0000.0000] # ARABIC SMALL HIGH LAM ALEF +06DA ; [.0000.0000.0000] # ARABIC SMALL HIGH JEEM +06DB ; [.0000.0000.0000] # ARABIC SMALL HIGH THREE DOTS +06DC ; [.0000.0000.0000] # ARABIC SMALL HIGH SEEN +06DD ; [.0000.0000.0000] # ARABIC END OF AYAH +06DE ; [*0515.0020.0002] # ARABIC START OF RUB EL HIZB +06DF ; [.0000.0000.0000] # ARABIC SMALL HIGH ROUNDED ZERO +06E0 ; [.0000.0000.0000] # ARABIC SMALL HIGH UPRIGHT RECTANGULAR ZERO +06E1 ; [.0000.0000.0000] # ARABIC SMALL HIGH DOTLESS HEAD OF KHAH +06E2 ; [.0000.0000.0000] # ARABIC SMALL HIGH MEEM ISOLATED FORM +06E3 ; [.0000.0000.0000] # ARABIC SMALL LOW SEEN +06E4 ; [.0000.0000.0000] # ARABIC SMALL HIGH MADDA +06E7 ; [.0000.0000.0000] # ARABIC SMALL HIGH YEH +06E8 ; [.0000.0000.0000] # ARABIC SMALL HIGH NOON +06E9 ; [*0516.0020.0002] # ARABIC PLACE OF SAJDAH +06EA ; [.0000.0000.0000] # ARABIC EMPTY CENTRE LOW STOP +06EB ; [.0000.0000.0000] # ARABIC EMPTY CENTRE HIGH STOP +06EC ; [.0000.0000.0000] # ARABIC ROUNDED HIGH STOP WITH FILLED CENTRE +06ED ; [.0000.0000.0000] # ARABIC SMALL LOW MEEM +0700 ; [*02C5.0020.0002] # SYRIAC END OF PARAGRAPH +0701 ; [*027B.0020.0002] # SYRIAC SUPRALINEAR FULL STOP +0702 ; [*027C.0020.0002] # SYRIAC SUBLINEAR FULL STOP +0703 ; [*023D.0020.0002] # SYRIAC SUPRALINEAR COLON +0704 ; [*023E.0020.0002] # SYRIAC SUBLINEAR COLON +0705 ; [*023F.0020.0002] # SYRIAC HORIZONTAL COLON +0706 ; [*0240.0020.0002] # SYRIAC COLON SKEWED LEFT +0707 ; [*0241.0020.0002] # SYRIAC COLON SKEWED RIGHT +0708 ; [*0242.0020.0002] # SYRIAC SUPRALINEAR COLON SKEWED LEFT +0709 ; [*026C.0020.0002] # SYRIAC SUBLINEAR COLON SKEWED RIGHT +070A ; [*03D9.0020.0002] # SYRIAC CONTRACTION +070B ; [*03DA.0020.0002] # SYRIAC HARKLEAN OBELUS +070C ; [*03DB.0020.0002] # SYRIAC HARKLEAN METOBELUS +070D ; [*03DC.0020.0002] # SYRIAC HARKLEAN ASTERISCUS +0740 ; [.0000.0000.0000] # SYRIAC FEMININE DOT +0743 ; [.0000.0000.0000] # SYRIAC TWO VERTICAL DOTS ABOVE +0744 ; [.0000.0000.0000] # SYRIAC TWO VERTICAL DOTS BELOW +0747 ; [.0000.0000.0000] # SYRIAC OBLIQUE LINE ABOVE +0748 ; [.0000.0000.0000] # SYRIAC OBLIQUE LINE BELOW +0749 ; [.0000.0000.0000] # SYRIAC MUSIC +074A ; [.0000.0000.0000] # SYRIAC BARREKH +07F6 ; [*0528.0020.0002] # NKO SYMBOL OO DENNEN +07F7 ; [*02C6.0020.0002] # NKO SYMBOL GBAKURUNEN +07F8 ; [*022B.0020.0002] # NKO COMMA +07F9 ; [*0264.0020.0002] # NKO EXCLAMATION MARK +07FA ; [.0000.0000.0000] # NKO LAJANYALAN +0830 ; [*0243.0020.0002] # SAMARITAN PUNCTUATION NEQUDAA +0831 ; [*0244.0020.0002] # SAMARITAN PUNCTUATION AFSAAQ +0832 ; [*0245.0020.0002] # SAMARITAN PUNCTUATION ANGED +0833 ; [*0246.0020.0002] # SAMARITAN PUNCTUATION BAU +0834 ; [*0247.0020.0002] # SAMARITAN PUNCTUATION ATMAAU +0835 ; [*0248.0020.0002] # SAMARITAN PUNCTUATION SHIYYAALAA +0836 ; [*0249.0020.0002] # SAMARITAN ABBREVIATION MARK +0837 ; [*024A.0020.0002] # SAMARITAN PUNCTUATION MELODIC QITSA +0838 ; [*024B.0020.0002] # SAMARITAN PUNCTUATION ZIQAA +0839 ; [*024C.0020.0002] # SAMARITAN PUNCTUATION QITSA +083A ; [*024D.0020.0002] # SAMARITAN PUNCTUATION ZAEF +083B ; [*024E.0020.0002] # SAMARITAN PUNCTUATION TURU +083C ; [*024F.0020.0002] # SAMARITAN PUNCTUATION ARKAANU +083D ; [*0250.0020.0002] # SAMARITAN PUNCTUATION SOF MASHFAAT +083E ; [*0251.0020.0002] # SAMARITAN PUNCTUATION ANNAAU +085E ; [*03DD.0020.0002] # MANDAIC PUNCTUATION +08D4 ; [.0000.0000.0000] # ARABIC SMALL HIGH WORD AR-RUB +08D5 ; [.0000.0000.0000] # ARABIC SMALL HIGH SAD +08D6 ; [.0000.0000.0000] # ARABIC SMALL HIGH AIN +08D7 ; [.0000.0000.0000] # ARABIC SMALL HIGH QAF +08D8 ; [.0000.0000.0000] # ARABIC SMALL HIGH NOON WITH KASRA +08D9 ; [.0000.0000.0000] # ARABIC SMALL LOW NOON WITH KASRA +08DA ; [.0000.0000.0000] # ARABIC SMALL HIGH WORD ATH-THALATHA +08DB ; [.0000.0000.0000] # ARABIC SMALL HIGH WORD AS-SAJDA +08DC ; [.0000.0000.0000] # ARABIC SMALL HIGH WORD AN-NISF +08DD ; [.0000.0000.0000] # ARABIC SMALL HIGH WORD SAKTA +08DE ; [.0000.0000.0000] # ARABIC SMALL HIGH WORD QIF +08DF ; [.0000.0000.0000] # ARABIC SMALL HIGH WORD WAQFA +08E0 ; [.0000.0000.0000] # ARABIC SMALL HIGH FOOTNOTE MARKER +08E1 ; [.0000.0000.0000] # ARABIC SMALL HIGH SIGN SAFHA +08EA ; [.0000.0000.0000] # ARABIC TONE ONE DOT ABOVE +08EB ; [.0000.0000.0000] # ARABIC TONE TWO DOTS ABOVE +08EC ; [.0000.0000.0000] # ARABIC TONE LOOP ABOVE +08ED ; [.0000.0000.0000] # ARABIC TONE ONE DOT BELOW +08EE ; [.0000.0000.0000] # ARABIC TONE TWO DOTS BELOW +08EF ; [.0000.0000.0000] # ARABIC TONE LOOP BELOW +08F3 ; [.0000.0000.0000] # ARABIC SMALL HIGH WAW +0951 ; [.0000.0000.0000] # DEVANAGARI STRESS SIGN UDATTA +0952 ; [.0000.0000.0000] # DEVANAGARI STRESS SIGN ANUDATTA +0964 ; [*028F.0020.0002] # DEVANAGARI DANDA +0965 ; [*0290.0020.0002] # DEVANAGARI DOUBLE DANDA +0970 ; [*03EC.0020.0002] # DEVANAGARI ABBREVIATION SIGN +09F4 ; [*1AFA.0020.0002] # BENGALI CURRENCY NUMERATOR ONE +09F5 ; [*1AFB.0020.0002] # BENGALI CURRENCY NUMERATOR TWO +09F6 ; [*1AFC.0020.0002] # BENGALI CURRENCY NUMERATOR THREE +09F7 ; [*1AFD.0020.0002] # BENGALI CURRENCY NUMERATOR FOUR +09F8 ; [*1AFE.0020.0002] # BENGALI CURRENCY NUMERATOR ONE LESS THAN THE DENOMINATOR +09F9 ; [*1AFF.0020.0002] # BENGALI CURRENCY DENOMINATOR SIXTEEN +09FA ; [*0529.0020.0002] # BENGALI ISSHAR +09FD ; [*03F1.0020.0002] # BENGALI ABBREVIATION SIGN +0AF0 ; [*03F2.0020.0002] # GUJARATI ABBREVIATION SIGN +0B70 ; [*052A.0020.0002] # ORIYA ISSHAR +0B72 ; [*1B00.0020.0002] # ORIYA FRACTION ONE QUARTER +0B73 ; [*1B01.0020.0002] # ORIYA FRACTION ONE HALF +0B74 ; [*1B02.0020.0002] # ORIYA FRACTION THREE QUARTERS +0B75 ; [*1B03.0020.0002] # ORIYA FRACTION ONE SIXTEENTH +0B76 ; [*1B04.0020.0002] # ORIYA FRACTION ONE EIGHTH +0B77 ; [*1B05.0020.0002] # ORIYA FRACTION THREE SIXTEENTHS +0BF0 ; [*1B0C.0020.0002] # TAMIL NUMBER TEN +0BF1 ; [*1B0D.0020.0002] # TAMIL NUMBER ONE HUNDRED +0BF2 ; [*1B0E.0020.0002] # TAMIL NUMBER ONE THOUSAND +0BF3 ; [*052B.0020.0002] # TAMIL DAY SIGN +0BF4 ; [*052C.0020.0002] # TAMIL MONTH SIGN +0BF5 ; [*052D.0020.0002] # TAMIL YEAR SIGN +0BF6 ; [*052E.0020.0002] # TAMIL DEBIT SIGN +0BF7 ; [*052F.0020.0002] # TAMIL CREDIT SIGN +0BF8 ; [*0530.0020.0002] # TAMIL AS ABOVE SIGN +0BFA ; [*0531.0020.0002] # TAMIL NUMBER SIGN +0C7F ; [*0532.0020.0002] # TELUGU SIGN TUUMU +0D4F ; [*0533.0020.0002] # MALAYALAM SIGN PARA +0D58 ; [*1B0F.0020.0002] # MALAYALAM FRACTION ONE ONE-HUNDRED-AND-SIXTIETH +0D59 ; [*1B10.0020.0002] # MALAYALAM FRACTION ONE FORTIETH +0D5A ; [*1B11.0020.0002] # MALAYALAM FRACTION THREE EIGHTIETHS +0D5B ; [*1B12.0020.0002] # MALAYALAM FRACTION ONE TWENTIETH +0D5C ; [*1B13.0020.0002] # MALAYALAM FRACTION ONE TENTH +0D5D ; [*1B14.0020.0002] # MALAYALAM FRACTION THREE TWENTIETHS +0D5E ; [*1B15.0020.0002] # MALAYALAM FRACTION ONE FIFTH +0D70 ; [*1B16.0020.0002] # MALAYALAM NUMBER TEN +0D71 ; [*1B17.0020.0002] # MALAYALAM NUMBER ONE HUNDRED +0D72 ; [*1B18.0020.0002] # MALAYALAM NUMBER ONE THOUSAND +0D73 ; [*1B19.0020.0002] # MALAYALAM FRACTION ONE QUARTER +0D74 ; [*1B1A.0020.0002] # MALAYALAM FRACTION ONE HALF +0D75 ; [*1B1B.0020.0002] # MALAYALAM FRACTION THREE QUARTERS +0D76 ; [*1B1C.0020.0002] # MALAYALAM FRACTION ONE SIXTEENTH +0D77 ; [*1B1D.0020.0002] # MALAYALAM FRACTION ONE EIGHTH +0D78 ; [*1B1E.0020.0002] # MALAYALAM FRACTION THREE SIXTEENTHS +0D79 ; [*0534.0020.0002] # MALAYALAM DATE MARK +0DF4 ; [*03F3.0020.0002] # SINHALA PUNCTUATION KUNDDALIYA +0E4F ; [*03F4.0020.0002] # THAI CHARACTER FONGMAN +0E5A ; [*03F5.0020.0002] # THAI CHARACTER ANGKHANKHU +0E5B ; [*03F6.0020.0002] # THAI CHARACTER KHOMUT +0F01 ; [*053C.0020.0002] # TIBETAN MARK GTER YIG MGO TRUNCATED A +0F02 ; [*053D.0020.0002] # TIBETAN MARK GTER YIG MGO -UM RNAM BCAD MA +0F03 ; [*053E.0020.0002] # TIBETAN MARK GTER YIG MGO -UM GTER TSHEG MA +0F04 ; [*03F9.0020.0002] # TIBETAN MARK INITIAL YIG MGO MDUN MA +0F05 ; [*03FA.0020.0002] # TIBETAN MARK CLOSING YIG MGO SGAB MA +0F06 ; [*03FB.0020.0002] # TIBETAN MARK CARET YIG MGO PHUR SHAD MA +0F07 ; [*03FC.0020.0002] # TIBETAN MARK YIG MGO TSHEG SHAD MA +0F08 ; [*03FD.0020.0002] # TIBETAN MARK SBRUL SHAD +0F09 ; [*03FE.0020.0002] # TIBETAN MARK BSKUR YIG MGO +0F0A ; [*03FF.0020.0002] # TIBETAN MARK BKA- SHOG YIG MGO +0F0B ; [*0402.0020.0002] # TIBETAN MARK INTERSYLLABIC TSHEG +0F0C ; [*0402.0020.001B] # TIBETAN MARK DELIMITER TSHEG BSTAR +0F0D ; [*0403.0020.0002] # TIBETAN MARK SHAD +0F0E ; [*0404.0020.0002] # TIBETAN MARK NYIS SHAD +0F0F ; [*0405.0020.0002] # TIBETAN MARK TSHEG SHAD +0F10 ; [*0406.0020.0002] # TIBETAN MARK NYIS TSHEG SHAD +0F11 ; [*0407.0020.0002] # TIBETAN MARK RIN CHEN SPUNGS SHAD +0F12 ; [*0408.0020.0002] # TIBETAN MARK RGYA GRAM SHAD +0F13 ; [*053F.0020.0002] # TIBETAN MARK CARET -DZUD RTAGS ME LONG CAN +0F14 ; [*0259.0020.0002] # TIBETAN MARK GTER TSHEG +0F15 ; [*0540.0020.0002] # TIBETAN LOGOTYPE SIGN CHAD RTAGS +0F16 ; [*0541.0020.0002] # TIBETAN LOGOTYPE SIGN LHAG RTAGS +0F17 ; [*0542.0020.0002] # TIBETAN ASTROLOGICAL SIGN SGRA GCAN -CHAR RTAGS +0F18 ; [.0000.0000.0000] # TIBETAN ASTROLOGICAL SIGN -KHYUD PA +0F19 ; [.0000.0000.0000] # TIBETAN ASTROLOGICAL SIGN SDONG TSHUGS +0F1A ; [*0543.0020.0002] # TIBETAN SIGN RDEL DKAR GCIG +0F1B ; [*0544.0020.0002] # TIBETAN SIGN RDEL DKAR GNYIS +0F1C ; [*0545.0020.0002] # TIBETAN SIGN RDEL DKAR GSUM +0F1D ; [*0546.0020.0002] # TIBETAN SIGN RDEL NAG GCIG +0F1E ; [*0547.0020.0002] # TIBETAN SIGN RDEL NAG GNYIS +0F1F ; [*0548.0020.0002] # TIBETAN SIGN RDEL DKAR RDEL NAG +0F34 ; [*0549.0020.0002] # TIBETAN MARK BSDUS RTAGS +0F35 ; [.0000.0000.0000] # TIBETAN MARK NGAS BZUNG NYI ZLA +0F36 ; [*054A.0020.0002] # TIBETAN MARK CARET -DZUD RTAGS BZHI MIG CAN +0F37 ; [.0000.0000.0000] # TIBETAN MARK NGAS BZUNG SGOR RTAGS +0F38 ; [*054B.0020.0002] # TIBETAN MARK CHE MGO +0F3A ; [*031E.0020.0002] # TIBETAN MARK GUG RTAGS GYON +0F3B ; [*031F.0020.0002] # TIBETAN MARK GUG RTAGS GYAS +0F3C ; [*0320.0020.0002] # TIBETAN MARK ANG KHANG GYON +0F3D ; [*0321.0020.0002] # TIBETAN MARK ANG KHANG GYAS +0F3E ; [.0000.0000.0000] # TIBETAN SIGN YAR TSHES +0F3F ; [.0000.0000.0000] # TIBETAN SIGN MAR TSHES +0F82 ; [.0000.0000.0000] # TIBETAN SIGN NYI ZLA NAA DA +0F83 ; [.0000.0000.0000] # TIBETAN SIGN SNA LDAN +0F85 ; [*0409.0020.0002] # TIBETAN MARK PALUTA +0F86 ; [.0000.0000.0000] # TIBETAN SIGN LCI RTAGS +0F87 ; [.0000.0000.0000] # TIBETAN SIGN YANG RTAGS +0FBE ; [*054C.0020.0002] # TIBETAN KU RU KHA +0FBF ; [*054D.0020.0002] # TIBETAN KU RU KHA BZHI MIG CAN +0FC0 ; [*054E.0020.0002] # TIBETAN CANTILLATION SIGN HEAVY BEAT +0FC1 ; [*054F.0020.0002] # TIBETAN CANTILLATION SIGN LIGHT BEAT +0FC2 ; [*0550.0020.0002] # TIBETAN CANTILLATION SIGN CANG TE-U +0FC3 ; [*0551.0020.0002] # TIBETAN CANTILLATION SIGN SBUB -CHAL +0FC4 ; [*0552.0020.0002] # TIBETAN SYMBOL DRIL BU +0FC5 ; [*0553.0020.0002] # TIBETAN SYMBOL RDO RJE +0FC6 ; [.0000.0000.0000] # TIBETAN SYMBOL PADMA GDAN +0FC7 ; [*0554.0020.0002] # TIBETAN SYMBOL RDO RJE RGYA GRAM +0FC8 ; [*0555.0020.0002] # TIBETAN SYMBOL PHUR PA +0FC9 ; [*0556.0020.0002] # TIBETAN SYMBOL NOR BU +0FCA ; [*0557.0020.0002] # TIBETAN SYMBOL NOR BU NYIS -KHYIL +0FCB ; [*0558.0020.0002] # TIBETAN SYMBOL NOR BU GSUM -KHYIL +0FCC ; [*0559.0020.0002] # TIBETAN SYMBOL NOR BU BZHI -KHYIL +0FCE ; [*055A.0020.0002] # TIBETAN SIGN RDEL NAG RDEL DKAR +0FCF ; [*055B.0020.0002] # TIBETAN SIGN RDEL NAG GSUM +0FD0 ; [*0400.0020.0002] # TIBETAN MARK BSKA- SHOG GI MGO RGYAN +0FD1 ; [*0401.0020.0002] # TIBETAN MARK MNYAM YIG GI MGO RGYAN +0FD2 ; [*040A.0020.0002] # TIBETAN MARK NYIS TSHEG +0FD3 ; [*040B.0020.0002] # TIBETAN MARK INITIAL BRDA RNYING YIG MGO MDUN MA +0FD4 ; [*040C.0020.0002] # TIBETAN MARK CLOSING BRDA RNYING YIG MGO SGAB MA +0FD5 ; [*055C.0020.0002] # RIGHT-FACING SVASTI SIGN +0FD6 ; [*055D.0020.0002] # LEFT-FACING SVASTI SIGN +0FD7 ; [*055E.0020.0002] # RIGHT-FACING SVASTI SIGN WITH DOTS +0FD8 ; [*055F.0020.0002] # LEFT-FACING SVASTI SIGN WITH DOTS +0FD9 ; [*040D.0020.0002] # TIBETAN MARK LEADING MCHAN RTAGS +0FDA ; [*040E.0020.0002] # TIBETAN MARK TRAILING MCHAN RTAGS +104A ; [*029A.0020.0002] # MYANMAR SIGN LITTLE SECTION +104B ; [*029B.0020.0002] # MYANMAR SIGN SECTION +104C ; [*0424.0020.0002] # MYANMAR SYMBOL LOCATIVE +104D ; [*0425.0020.0002] # MYANMAR SYMBOL COMPLETED +104E ; [*0426.0020.0002] # MYANMAR SYMBOL AFOREMENTIONED +104F ; [*0427.0020.0002] # MYANMAR SYMBOL GENITIVE +109E ; [*0561.0020.0002] # MYANMAR SYMBOL SHAN ONE +109F ; [*0562.0020.0002] # MYANMAR SYMBOL SHAN EXCLAMATION +10FB ; [*02C7.0020.0002] # GEORGIAN PARAGRAPH SEPARATOR +1360 ; [*02C8.0020.0002] # ETHIOPIC SECTION MARK +1361 ; [*0252.0020.0002] # ETHIOPIC WORDSPACE +1362 ; [*027D.0020.0002] # ETHIOPIC FULL STOP +1363 ; [*0253.0020.0002] # ETHIOPIC COMMA +1364 ; [*0254.0020.0002] # ETHIOPIC SEMICOLON +1365 ; [*0255.0020.0002] # ETHIOPIC COLON +1366 ; [*0256.0020.0002] # ETHIOPIC PREFACE COLON +1367 ; [*026D.0020.0002] # ETHIOPIC QUESTION MARK +1368 ; [*02C9.0020.0002] # ETHIOPIC PARAGRAPH SEPARATOR +1372 ; [*1B1F.0020.0002] # ETHIOPIC NUMBER TEN +1373 ; [*1B20.0020.0002] # ETHIOPIC NUMBER TWENTY +1374 ; [*1B21.0020.0002] # ETHIOPIC NUMBER THIRTY +1375 ; [*1B22.0020.0002] # ETHIOPIC NUMBER FORTY +1376 ; [*1B23.0020.0002] # ETHIOPIC NUMBER FIFTY +1377 ; [*1B24.0020.0002] # ETHIOPIC NUMBER SIXTY +1378 ; [*1B25.0020.0002] # ETHIOPIC NUMBER SEVENTY +1379 ; [*1B26.0020.0002] # ETHIOPIC NUMBER EIGHTY +137A ; [*1B27.0020.0002] # ETHIOPIC NUMBER NINETY +137B ; [*1B28.0020.0002] # ETHIOPIC NUMBER HUNDRED +137C ; [*1B29.0020.0002] # ETHIOPIC NUMBER TEN THOUSAND +1390 ; [*04DC.0020.0002] # ETHIOPIC TONAL MARK YIZET +1391 ; [*04DD.0020.0002] # ETHIOPIC TONAL MARK DERET +1392 ; [*04DE.0020.0002] # ETHIOPIC TONAL MARK RIKRIK +1393 ; [*04DF.0020.0002] # ETHIOPIC TONAL MARK SHORT RIKRIK +1394 ; [*04E0.0020.0002] # ETHIOPIC TONAL MARK DIFAT +1395 ; [*04E1.0020.0002] # ETHIOPIC TONAL MARK KENAT +1396 ; [*04E2.0020.0002] # ETHIOPIC TONAL MARK CHIRET +1397 ; [*04E3.0020.0002] # ETHIOPIC TONAL MARK HIDET +1398 ; [*04E4.0020.0002] # ETHIOPIC TONAL MARK DERET-HIDET +1399 ; [*04E5.0020.0002] # ETHIOPIC TONAL MARK KURT +1400 ; [*020F.0020.0002] # CANADIAN SYLLABICS HYPHEN +166D ; [*0434.0020.0002] # CANADIAN SYLLABICS CHI SIGN +166E ; [*0280.0020.0002] # CANADIAN SYLLABICS FULL STOP +1680 ; [*0209.0020.0004] # OGHAM SPACE MARK +169B ; [*0322.0020.0002] # OGHAM FEATHER MARK +169C ; [*0323.0020.0002] # OGHAM REVERSED FEATHER MARK +16EB ; [*025D.0020.0002] # RUNIC SINGLE PUNCTUATION +16EC ; [*025E.0020.0002] # RUNIC MULTIPLE PUNCTUATION +16ED ; [*025F.0020.0002] # RUNIC CROSS PUNCTUATION +1735 ; [*0297.0020.0002] # PHILIPPINE SINGLE PUNCTUATION +1736 ; [*0298.0020.0002] # PHILIPPINE DOUBLE PUNCTUATION +17B4 ; [.0000.0000.0000] # KHMER VOWEL INHERENT AQ +17B5 ; [.0000.0000.0000] # KHMER VOWEL INHERENT AA +17D3 ; [.0000.0000.0000] # KHMER SIGN BATHAMASAT +17D4 ; [*029C.0020.0002] # KHMER SIGN KHAN +17D5 ; [*029D.0020.0002] # KHMER SIGN BARIYOOSAN +17D6 ; [*025A.0020.0002] # KHMER SIGN CAMNUC PII KUUH +17D8 ; [*0428.0020.0002] # KHMER SIGN BEYYAL +17D9 ; [*0429.0020.0002] # KHMER SIGN PHNAEK MUAN +17DA ; [*042A.0020.0002] # KHMER SIGN KOOMUUT +1800 ; [*03DE.0020.0002] # MONGOLIAN BIRGA +1801 ; [*0279.0020.0002] # MONGOLIAN ELLIPSIS +1802 ; [*022C.0020.0002] # MONGOLIAN COMMA +1803 ; [*027E.0020.0002] # MONGOLIAN FULL STOP +1804 ; [*0257.0020.0002] # MONGOLIAN COLON +1805 ; [*0258.0020.0002] # MONGOLIAN FOUR DOTS +1806 ; [*0211.0020.0002] # MONGOLIAN TODO SOFT HYPHEN +1807 ; [*0212.0020.0002] # MONGOLIAN SIBE SYLLABLE BOUNDARY MARKER +1808 ; [*022D.0020.0002] # MONGOLIAN MANCHU COMMA +1809 ; [*027F.0020.0002] # MONGOLIAN MANCHU FULL STOP +180A ; [.0000.0000.0000] # MONGOLIAN NIRUGU +1940 ; [*0560.0020.0002] # LIMBU SIGN LOO +1944 ; [*0265.0020.0002] # LIMBU EXCLAMATION MARK +1945 ; [*026E.0020.0002] # LIMBU QUESTION MARK +19E0 ; [*0567.0020.0002] # KHMER SYMBOL PATHAMASAT +19E1 ; [*0568.0020.0002] # KHMER SYMBOL MUOY KOET +19E2 ; [*0569.0020.0002] # KHMER SYMBOL PII KOET +19E3 ; [*056A.0020.0002] # KHMER SYMBOL BEI KOET +19E4 ; [*056B.0020.0002] # KHMER SYMBOL BUON KOET +19E5 ; [*056C.0020.0002] # KHMER SYMBOL PRAM KOET +19E6 ; [*056D.0020.0002] # KHMER SYMBOL PRAM-MUOY KOET +19E7 ; [*056E.0020.0002] # KHMER SYMBOL PRAM-PII KOET +19E8 ; [*056F.0020.0002] # KHMER SYMBOL PRAM-BEI KOET +19E9 ; [*0570.0020.0002] # KHMER SYMBOL PRAM-BUON KOET +19EA ; [*0571.0020.0002] # KHMER SYMBOL DAP KOET +19EB ; [*0572.0020.0002] # KHMER SYMBOL DAP-MUOY KOET +19EC ; [*0573.0020.0002] # KHMER SYMBOL DAP-PII KOET +19ED ; [*0574.0020.0002] # KHMER SYMBOL DAP-BEI KOET +19EE ; [*0575.0020.0002] # KHMER SYMBOL DAP-BUON KOET +19EF ; [*0576.0020.0002] # KHMER SYMBOL DAP-PRAM KOET +19F0 ; [*0577.0020.0002] # KHMER SYMBOL TUTEYASAT +19F1 ; [*0578.0020.0002] # KHMER SYMBOL MUOY ROC +19F2 ; [*0579.0020.0002] # KHMER SYMBOL PII ROC +19F3 ; [*057A.0020.0002] # KHMER SYMBOL BEI ROC +19F4 ; [*057B.0020.0002] # KHMER SYMBOL BUON ROC +19F5 ; [*057C.0020.0002] # KHMER SYMBOL PRAM ROC +19F6 ; [*057D.0020.0002] # KHMER SYMBOL PRAM-MUOY ROC +19F7 ; [*057E.0020.0002] # KHMER SYMBOL PRAM-PII ROC +19F8 ; [*057F.0020.0002] # KHMER SYMBOL PRAM-BEI ROC +19F9 ; [*0580.0020.0002] # KHMER SYMBOL PRAM-BUON ROC +19FA ; [*0581.0020.0002] # KHMER SYMBOL DAP ROC +19FB ; [*0582.0020.0002] # KHMER SYMBOL DAP-MUOY ROC +19FC ; [*0583.0020.0002] # KHMER SYMBOL DAP-PII ROC +19FD ; [*0584.0020.0002] # KHMER SYMBOL DAP-BEI ROC +19FE ; [*0585.0020.0002] # KHMER SYMBOL DAP-BUON ROC +19FF ; [*0586.0020.0002] # KHMER SYMBOL DAP-PRAM ROC +1A1E ; [*02CA.0020.0002] # BUGINESE PALLAWA +1A1F ; [*02CB.0020.0002] # BUGINESE END OF SECTION +1A7F ; [.0000.0000.0000] # TAI THAM COMBINING CRYPTOGRAMMIC DOT +1AA0 ; [*042B.0020.0002] # TAI THAM SIGN WIANG +1AA1 ; [*042C.0020.0002] # TAI THAM SIGN WIANGWAAK +1AA2 ; [*042D.0020.0002] # TAI THAM SIGN SAWAN +1AA3 ; [*042E.0020.0002] # TAI THAM SIGN KEOW +1AA4 ; [*042F.0020.0002] # TAI THAM SIGN HOY +1AA5 ; [*0430.0020.0002] # TAI THAM SIGN DOKMAI +1AA6 ; [*0431.0020.0002] # TAI THAM SIGN REVERSED ROTATED RANA +1AA8 ; [*029E.0020.0002] # TAI THAM SIGN KAAN +1AA9 ; [*029F.0020.0002] # TAI THAM SIGN KAANKUU +1AAA ; [*02A0.0020.0002] # TAI THAM SIGN SATKAAN +1AAB ; [*02A1.0020.0002] # TAI THAM SIGN SATKAANKUU +1AAC ; [*0432.0020.0002] # TAI THAM SIGN HANG +1AAD ; [*0433.0020.0002] # TAI THAM SIGN CAANG +1B5A ; [*02CC.0020.0002] # BALINESE PANTI +1B5B ; [*02CD.0020.0002] # BALINESE PAMADA +1B5C ; [*0281.0020.0002] # BALINESE WINDU +1B5D ; [*025B.0020.0002] # BALINESE CARIK PAMUNGKAH +1B5E ; [*02A2.0020.0002] # BALINESE CARIK SIKI +1B5F ; [*02A3.0020.0002] # BALINESE CARIK PAREREN +1B60 ; [*0210.0020.0002] # BALINESE PAMENENG +1B61 ; [*0587.0020.0002] # BALINESE MUSICAL SYMBOL DONG +1B62 ; [*0588.0020.0002] # BALINESE MUSICAL SYMBOL DENG +1B63 ; [*0589.0020.0002] # BALINESE MUSICAL SYMBOL DUNG +1B64 ; [*058A.0020.0002] # BALINESE MUSICAL SYMBOL DANG +1B65 ; [*058B.0020.0002] # BALINESE MUSICAL SYMBOL DANG SURANG +1B66 ; [*058C.0020.0002] # BALINESE MUSICAL SYMBOL DING +1B67 ; [*058D.0020.0002] # BALINESE MUSICAL SYMBOL DAENG +1B68 ; [*058E.0020.0002] # BALINESE MUSICAL SYMBOL DEUNG +1B69 ; [*058F.0020.0002] # BALINESE MUSICAL SYMBOL DAING +1B6A ; [*0590.0020.0002] # BALINESE MUSICAL SYMBOL DANG GEDE +1B6B ; [.0000.0000.0000] # BALINESE MUSICAL SYMBOL COMBINING TEGEH +1B6C ; [.0000.0000.0000] # BALINESE MUSICAL SYMBOL COMBINING ENDEP +1B6D ; [.0000.0000.0000] # BALINESE MUSICAL SYMBOL COMBINING KEMPUL +1B6E ; [.0000.0000.0000] # BALINESE MUSICAL SYMBOL COMBINING KEMPLI +1B6F ; [.0000.0000.0000] # BALINESE MUSICAL SYMBOL COMBINING JEGOGAN +1B70 ; [.0000.0000.0000] # BALINESE MUSICAL SYMBOL COMBINING KEMPUL WITH JEGOGAN +1B71 ; [.0000.0000.0000] # BALINESE MUSICAL SYMBOL COMBINING KEMPLI WITH JEGOGAN +1B72 ; [.0000.0000.0000] # BALINESE MUSICAL SYMBOL COMBINING BENDE +1B73 ; [.0000.0000.0000] # BALINESE MUSICAL SYMBOL COMBINING GONG +1B74 ; [*0591.0020.0002] # BALINESE MUSICAL SYMBOL RIGHT-HAND OPEN DUG +1B75 ; [*0592.0020.0002] # BALINESE MUSICAL SYMBOL RIGHT-HAND OPEN DAG +1B76 ; [*0593.0020.0002] # BALINESE MUSICAL SYMBOL RIGHT-HAND CLOSED TUK +1B77 ; [*0594.0020.0002] # BALINESE MUSICAL SYMBOL RIGHT-HAND CLOSED TAK +1B78 ; [*0595.0020.0002] # BALINESE MUSICAL SYMBOL LEFT-HAND OPEN PANG +1B79 ; [*0596.0020.0002] # BALINESE MUSICAL SYMBOL LEFT-HAND OPEN PUNG +1B7A ; [*0597.0020.0002] # BALINESE MUSICAL SYMBOL LEFT-HAND CLOSED PLAK +1B7B ; [*0598.0020.0002] # BALINESE MUSICAL SYMBOL LEFT-HAND CLOSED PLUK +1B7C ; [*0599.0020.0002] # BALINESE MUSICAL SYMBOL LEFT-HAND OPEN PING +1BFC ; [*0440.0020.0002] # BATAK SYMBOL BINDU NA METEK +1BFD ; [*0441.0020.0002] # BATAK SYMBOL BINDU PINARBORAS +1BFE ; [*0442.0020.0002] # BATAK SYMBOL BINDU JUDUL +1BFF ; [*0443.0020.0002] # BATAK SYMBOL BINDU PANGOLAT +1C3B ; [*0293.0020.0002] # LEPCHA PUNCTUATION TA-ROL +1C3C ; [*0294.0020.0002] # LEPCHA PUNCTUATION NYET THYOOM TA-ROL +1C3D ; [*0421.0020.0002] # LEPCHA PUNCTUATION CER-WA +1C3E ; [*0422.0020.0002] # LEPCHA PUNCTUATION TSHOOK CER-WA +1C3F ; [*0423.0020.0002] # LEPCHA PUNCTUATION TSHOOK +1C7E ; [*02C3.0020.0002] # OL CHIKI PUNCTUATION MUCAAD +1C7F ; [*02C4.0020.0002] # OL CHIKI PUNCTUATION DOUBLE MUCAAD +1CC0 ; [*0435.0020.0002] # SUNDANESE PUNCTUATION BINDU SURYA +1CC1 ; [*0436.0020.0002] # SUNDANESE PUNCTUATION BINDU PANGLONG +1CC2 ; [*0437.0020.0002] # SUNDANESE PUNCTUATION BINDU PURNAMA +1CC3 ; [*0438.0020.0002] # SUNDANESE PUNCTUATION BINDU CAKRA +1CC4 ; [*0439.0020.0002] # SUNDANESE PUNCTUATION BINDU LEU SATANGA +1CC5 ; [*043A.0020.0002] # SUNDANESE PUNCTUATION BINDU KA SATANGA +1CC6 ; [*043B.0020.0002] # SUNDANESE PUNCTUATION BINDU DA SATANGA +1CC7 ; [*043C.0020.0002] # SUNDANESE PUNCTUATION BINDU BA SATANGA +1CD0 ; [.0000.0000.0000] # VEDIC TONE KARSHANA +1CD1 ; [.0000.0000.0000] # VEDIC TONE SHARA +1CD2 ; [.0000.0000.0000] # VEDIC TONE PRENKHA +1CD3 ; [.0000.0000.0000] # VEDIC SIGN NIHSHVASA +1CD4 ; [.0000.0000.0000] # VEDIC SIGN YAJURVEDIC MIDLINE SVARITA +1CD5 ; [.0000.0000.0000] # VEDIC TONE YAJURVEDIC AGGRAVATED INDEPENDENT SVARITA +1CD6 ; [.0000.0000.0000] # VEDIC TONE YAJURVEDIC INDEPENDENT SVARITA +1CD7 ; [.0000.0000.0000] # VEDIC TONE YAJURVEDIC KATHAKA INDEPENDENT SVARITA +1CD8 ; [.0000.0000.0000] # VEDIC TONE CANDRA BELOW +1CD9 ; [.0000.0000.0000] # VEDIC TONE YAJURVEDIC KATHAKA INDEPENDENT SVARITA SCHROEDER +1CDA ; [.0000.0000.0000] # VEDIC TONE DOUBLE SVARITA +1CDB ; [.0000.0000.0000] # VEDIC TONE TRIPLE SVARITA +1CDC ; [.0000.0000.0000] # VEDIC TONE KATHAKA ANUDATTA +1CDD ; [.0000.0000.0000] # VEDIC TONE DOT BELOW +1CDE ; [.0000.0000.0000] # VEDIC TONE TWO DOTS BELOW +1CDF ; [.0000.0000.0000] # VEDIC TONE THREE DOTS BELOW +1CE0 ; [.0000.0000.0000] # VEDIC TONE RIGVEDIC KASHMIRI INDEPENDENT SVARITA +1CE1 ; [.0000.0000.0000] # VEDIC TONE ATHARVAVEDIC INDEPENDENT SVARITA +1CE2 ; [.0000.0000.0000] # VEDIC SIGN VISARGA SVARITA +1CE3 ; [.0000.0000.0000] # VEDIC SIGN VISARGA UDATTA +1CE4 ; [.0000.0000.0000] # VEDIC SIGN REVERSED VISARGA UDATTA +1CE5 ; [.0000.0000.0000] # VEDIC SIGN VISARGA ANUDATTA +1CE6 ; [.0000.0000.0000] # VEDIC SIGN REVERSED VISARGA ANUDATTA +1CE7 ; [.0000.0000.0000] # VEDIC SIGN VISARGA UDATTA WITH TAIL +1CE8 ; [.0000.0000.0000] # VEDIC SIGN VISARGA ANUDATTA WITH TAIL +1CF4 ; [.0000.0000.0000] # VEDIC TONE CANDRA ABOVE +1CF7 ; [.0000.0000.0000] # VEDIC SIGN ATIKRAMA +1CF8 ; [.0000.0000.0000] # VEDIC TONE RING ABOVE +1CF9 ; [.0000.0000.0000] # VEDIC TONE DOUBLE RING ABOVE +1FBD ; [*04A4.0020.0002] # GREEK KORONIS +1FBF ; [*04A4.0020.0002] # GREEK PSILI +1FC0 ; [*04A6.0020.0002] # GREEK PERISPOMENI +1FC1 ; [*049F.0020.0002][.0000.002A.0002] # GREEK DIALYTIKA AND PERISPOMENI +1FCD ; [*04A4.0020.0002][.0000.0025.0002] # GREEK PSILI AND VARIA +1FCE ; [*04A4.0020.0002][.0000.0024.0002] # GREEK PSILI AND OXIA +1FCF ; [*04A4.0020.0002][.0000.002A.0002] # GREEK PSILI AND PERISPOMENI +1FDD ; [*04A5.0020.0002][.0000.0025.0002] # GREEK DASIA AND VARIA +1FDE ; [*04A5.0020.0002][.0000.0024.0002] # GREEK DASIA AND OXIA +1FDF ; [*04A5.0020.0002][.0000.002A.0002] # GREEK DASIA AND PERISPOMENI +1FED ; [*049F.0020.0002][.0000.0025.0002] # GREEK DIALYTIKA AND VARIA +1FEE ; [*049F.0020.0002][.0000.0024.0002] # GREEK DIALYTIKA AND OXIA +1FEF ; [*0498.0020.0002] # GREEK VARIA +1FFD ; [*0499.0020.0002] # GREEK OXIA +1FFE ; [*04A5.0020.0002] # GREEK DASIA +2000 ; [*0209.0020.0004] # EN QUAD +2001 ; [*0209.0020.0004] # EM QUAD +2002 ; [*0209.0020.0004] # EN SPACE +2003 ; [*0209.0020.0004] # EM SPACE +2004 ; [*0209.0020.0004] # THREE-PER-EM SPACE +2005 ; [*0209.0020.0004] # FOUR-PER-EM SPACE +2006 ; [*0209.0020.0004] # SIX-PER-EM SPACE +2007 ; [*0209.0020.001B] # FIGURE SPACE +2008 ; [*0209.0020.0004] # PUNCTUATION SPACE +2009 ; [*0209.0020.0004] # THIN SPACE +200A ; [*0209.0020.0004] # HAIR SPACE +2010 ; [*0213.0020.0002] # HYPHEN +2011 ; [*0213.0020.001B] # NON-BREAKING HYPHEN +2012 ; [*0214.0020.0002] # FIGURE DASH +2013 ; [*0215.0020.0002] # EN DASH +2014 ; [*0216.0020.0002] # EM DASH +2015 ; [*0217.0020.0002] # HORIZONTAL BAR +2016 ; [*0384.0020.0002] # DOUBLE VERTICAL LINE +2017 ; [*020C.0020.0002] # DOUBLE LOW LINE +2018 ; [*0307.0020.0002] # LEFT SINGLE QUOTATION MARK +2019 ; [*0308.0020.0002] # RIGHT SINGLE QUOTATION MARK +201A ; [*0309.0020.0002] # SINGLE LOW-9 QUOTATION MARK +201B ; [*030A.0020.0002] # SINGLE HIGH-REVERSED-9 QUOTATION MARK +201C ; [*030E.0020.0002] # LEFT DOUBLE QUOTATION MARK +201D ; [*030F.0020.0002] # RIGHT DOUBLE QUOTATION MARK +201E ; [*0310.0020.0002] # DOUBLE LOW-9 QUOTATION MARK +201F ; [*0311.0020.0002] # DOUBLE HIGH-REVERSED-9 QUOTATION MARK +2020 ; [*03A0.0020.0002] # DAGGER +2021 ; [*03A1.0020.0002] # DOUBLE DAGGER +2022 ; [*03A5.0020.0002] # BULLET +2023 ; [*03A6.0020.0002] # TRIANGULAR BULLET +2024 ; [*0278.0020.0004] # ONE DOT LEADER +2025 ; [*0278.0020.0004][*0278.0020.0004] # TWO DOT LEADER +2026 ; [*0278.0020.0004][*0278.0020.0004][*0278.0020.0004] # HORIZONTAL ELLIPSIS +2027 ; [*03A7.0020.0002] # HYPHENATION POINT +2028 ; [*0207.0020.0002] # LINE SEPARATOR +2029 ; [*0208.0020.0002] # PARAGRAPH SEPARATOR +202F ; [*0209.0020.001B] # NARROW NO-BREAK SPACE +2030 ; [*039C.0020.0002] # PER MILLE SIGN +2031 ; [*039E.0020.0002] # PER TEN THOUSAND SIGN +2032 ; [*03AB.0020.0002] # PRIME +2033 ; [*03AB.0020.0004][*03AB.0020.0004] # DOUBLE PRIME +2034 ; [*03AB.0020.0004][*03AB.0020.0004][*03AB.0020.0004] # TRIPLE PRIME +2035 ; [*03AC.0020.0002] # REVERSED PRIME +2036 ; [*03AC.0020.0004][*03AC.0020.0004] # REVERSED DOUBLE PRIME +2037 ; [*03AC.0020.0004][*03AC.0020.0004][*03AC.0020.0004] # REVERSED TRIPLE PRIME +2038 ; [*03AF.0020.0002] # CARET +2039 ; [*030B.0020.0002] # SINGLE LEFT-POINTING ANGLE QUOTATION MARK +203A ; [*030C.0020.0002] # SINGLE RIGHT-POINTING ANGLE QUOTATION MARK +203B ; [*03B0.0020.0002] # REFERENCE MARK +203C ; [*0261.0020.0004][*0261.0020.0004] # DOUBLE EXCLAMATION MARK +203D ; [*0276.0020.0002] # INTERROBANG +203E ; [*020A.0020.0002] # OVERLINE +203F ; [*03B1.0020.0002] # UNDERTIE +2040 ; [*03B3.0020.0002] # CHARACTER TIE +2041 ; [*03B5.0020.0002] # CARET INSERTION POINT +2042 ; [*03B6.0020.0002] # ASTERISM +2043 ; [*03A8.0020.0002] # HYPHEN BULLET +2044 ; [*063C.0020.0002] # FRACTION SLASH +2045 ; [*0324.0020.0002] # LEFT SQUARE BRACKET WITH QUILL +2046 ; [*0325.0020.0002] # RIGHT SQUARE BRACKET WITH QUILL +2047 ; [*0267.0020.0004][*0267.0020.0004] # DOUBLE QUESTION MARK +2048 ; [*0267.0020.0004][*0261.0020.0004] # QUESTION EXCLAMATION MARK +2049 ; [*0261.0020.0004][*0267.0020.0004] # EXCLAMATION QUESTION MARK +204A ; [*0398.0020.0002] # TIRONIAN SIGN ET +204B ; [*038D.0020.0002] # REVERSED PILCROW SIGN +204C ; [*03A9.0020.0002] # BLACK LEFTWARDS BULLET +204D ; [*03AA.0020.0002] # BLACK RIGHTWARDS BULLET +204E ; [*0391.0020.0002] # LOW ASTERISK +204F ; [*0236.0020.0002] # REVERSED SEMICOLON +2050 ; [*03B4.0020.0002] # CLOSE UP +2051 ; [*0392.0020.0002] # TWO ASTERISKS ALIGNED VERTICALLY +2052 ; [*0638.0020.0002] # COMMERCIAL MINUS SIGN +2053 ; [*021A.0020.0002] # SWUNG DASH +2054 ; [*03B2.0020.0002] # INVERTED UNDERTIE +2055 ; [*02E9.0020.0002] # FLOWER PUNCTUATION MARK +2056 ; [*02EA.0020.0002] # THREE DOT PUNCTUATION +2057 ; [*03AB.0020.0004][*03AB.0020.0004][*03AB.0020.0004][*03AB.0020.0004] # QUADRUPLE PRIME +2058 ; [*02EB.0020.0002] # FOUR DOT PUNCTUATION +2059 ; [*02EC.0020.0002] # FIVE DOT PUNCTUATION +205A ; [*02ED.0020.0002] # TWO DOT PUNCTUATION +205B ; [*02EE.0020.0002] # FOUR DOT MARK +205C ; [*02EF.0020.0002] # DOTTED CROSS +205D ; [*02F0.0020.0002] # TRICOLON +205E ; [*02F1.0020.0002] # VERTICAL FOUR DOTS +205F ; [*0209.0020.0004] # MEDIUM MATHEMATICAL SPACE +2061 ; [.0000.0000.0000] # FUNCTION APPLICATION +2062 ; [.0000.0000.0000] # INVISIBLE TIMES +2063 ; [.0000.0000.0000] # INVISIBLE SEPARATOR +2064 ; [.0000.0000.0000] # INVISIBLE PLUS +207A ; [*062C.0020.0014] # SUPERSCRIPT PLUS SIGN +207B ; [*0637.0020.0014] # SUPERSCRIPT MINUS +207C ; [*0631.0020.0014] # SUPERSCRIPT EQUALS SIGN +207D ; [*0318.0020.0014] # SUPERSCRIPT LEFT PARENTHESIS +207E ; [*0319.0020.0014] # SUPERSCRIPT RIGHT PARENTHESIS +208A ; [*062C.0020.0015] # SUBSCRIPT PLUS SIGN +208B ; [*0637.0020.0015] # SUBSCRIPT MINUS +208C ; [*0631.0020.0015] # SUBSCRIPT EQUALS SIGN +208D ; [*0318.0020.0015] # SUBSCRIPT LEFT PARENTHESIS +208E ; [*0319.0020.0015] # SUBSCRIPT RIGHT PARENTHESIS +2104 ; [*059C.0020.0002] # CENTRE LINE SYMBOL +2108 ; [*059D.0020.0002] # SCRUPLE +2114 ; [*059E.0020.0002] # L B BAR SYMBOL +2117 ; [*059F.0020.0002] # SOUND RECORDING COPYRIGHT +2118 ; [*05A0.0020.0002] # SCRIPT CAPITAL P +211E ; [*05A1.0020.0002] # PRESCRIPTION TAKE +211F ; [*05A2.0020.0002] # RESPONSE +2123 ; [*05A3.0020.0002] # VERSICLE +2125 ; [*05A4.0020.0002] # OUNCE SIGN +2127 ; [*05A5.0020.0002] # INVERTED OHM SIGN +2129 ; [*05A6.0020.0002] # TURNED GREEK SMALL LETTER IOTA +212E ; [*05A7.0020.0002] # ESTIMATED SYMBOL +213A ; [*05A8.0020.0002] # ROTATED CAPITAL Q +2140 ; [*062B.0020.0005] # DOUBLE-STRUCK N-ARY SUMMATION +2141 ; [*05A9.0020.0002] # TURNED SANS-SERIF CAPITAL G +2142 ; [*05AA.0020.0002] # TURNED SANS-SERIF CAPITAL L +2143 ; [*05AB.0020.0002] # REVERSED SANS-SERIF CAPITAL L +2144 ; [*05AC.0020.0002] # TURNED SANS-SERIF CAPITAL Y +214A ; [*05AD.0020.0002] # PROPERTY LINE +214B ; [*06C7.0020.0002] # TURNED AMPERSAND +214C ; [*05AE.0020.0002] # PER SIGN +214F ; [*05AF.0020.0002] # SYMBOL FOR SAMARITAN SOURCE +2180 ; [*1B2A.0020.0002] # ROMAN NUMERAL ONE THOUSAND C D +2181 ; [*1B2B.0020.0002] # ROMAN NUMERAL FIVE THOUSAND +2182 ; [*1B2C.0020.0002] # ROMAN NUMERAL TEN THOUSAND +2186 ; [*1B2D.0020.0002] # ROMAN NUMERAL FIFTY EARLY FORM +2187 ; [*1B2E.0020.0002] # ROMAN NUMERAL FIFTY THOUSAND +2188 ; [*1B2F.0020.0002] # ROMAN NUMERAL ONE HUNDRED THOUSAND +218A ; [*05B0.0020.0002] # TURNED DIGIT TWO +218B ; [*05B1.0020.0002] # TURNED DIGIT THREE +2190 ; [*05B2.0020.0002] # LEFTWARDS ARROW +2191 ; [*05B4.0020.0002] # UPWARDS ARROW +2192 ; [*05B3.0020.0002] # RIGHTWARDS ARROW +2193 ; [*05B5.0020.0002] # DOWNWARDS ARROW +2194 ; [*05B6.0020.0002] # LEFT RIGHT ARROW +2195 ; [*05B7.0020.0002] # UP DOWN ARROW +2196 ; [*05B8.0020.0002] # NORTH WEST ARROW +2197 ; [*05B9.0020.0002] # NORTH EAST ARROW +2198 ; [*05BA.0020.0002] # SOUTH EAST ARROW +2199 ; [*05BB.0020.0002] # SOUTH WEST ARROW +219A ; [*05B2.0020.0002][.0000.002F.0002] # LEFTWARDS ARROW WITH STROKE +219B ; [*05B3.0020.0002][.0000.002F.0002] # RIGHTWARDS ARROW WITH STROKE +219C ; [*05BC.0020.0002] # LEFTWARDS WAVE ARROW +219D ; [*05BD.0020.0002] # RIGHTWARDS WAVE ARROW +219E ; [*05BE.0020.0002] # LEFTWARDS TWO HEADED ARROW +219F ; [*05BF.0020.0002] # UPWARDS TWO HEADED ARROW +21A0 ; [*05C0.0020.0002] # RIGHTWARDS TWO HEADED ARROW +21A1 ; [*05C1.0020.0002] # DOWNWARDS TWO HEADED ARROW +21A2 ; [*05C2.0020.0002] # LEFTWARDS ARROW WITH TAIL +21A3 ; [*05C3.0020.0002] # RIGHTWARDS ARROW WITH TAIL +21A4 ; [*05C4.0020.0002] # LEFTWARDS ARROW FROM BAR +21A5 ; [*05C5.0020.0002] # UPWARDS ARROW FROM BAR +21A6 ; [*05C6.0020.0002] # RIGHTWARDS ARROW FROM BAR +21A7 ; [*05C7.0020.0002] # DOWNWARDS ARROW FROM BAR +21A8 ; [*05C8.0020.0002] # UP DOWN ARROW WITH BASE +21A9 ; [*05C9.0020.0002] # LEFTWARDS ARROW WITH HOOK +21AA ; [*05CA.0020.0002] # RIGHTWARDS ARROW WITH HOOK +21AB ; [*05CB.0020.0002] # LEFTWARDS ARROW WITH LOOP +21AC ; [*05CC.0020.0002] # RIGHTWARDS ARROW WITH LOOP +21AD ; [*05CD.0020.0002] # LEFT RIGHT WAVE ARROW +21AE ; [*05B6.0020.0002][.0000.002F.0002] # LEFT RIGHT ARROW WITH STROKE +21AF ; [*05CE.0020.0002] # DOWNWARDS ZIGZAG ARROW +21B0 ; [*05CF.0020.0002] # UPWARDS ARROW WITH TIP LEFTWARDS +21B1 ; [*05D0.0020.0002] # UPWARDS ARROW WITH TIP RIGHTWARDS +21B2 ; [*05D1.0020.0002] # DOWNWARDS ARROW WITH TIP LEFTWARDS +21B3 ; [*05D2.0020.0002] # DOWNWARDS ARROW WITH TIP RIGHTWARDS +21B4 ; [*05D3.0020.0002] # RIGHTWARDS ARROW WITH CORNER DOWNWARDS +21B5 ; [*05D4.0020.0002] # DOWNWARDS ARROW WITH CORNER LEFTWARDS +21B6 ; [*05D5.0020.0002] # ANTICLOCKWISE TOP SEMICIRCLE ARROW +21B7 ; [*05D6.0020.0002] # CLOCKWISE TOP SEMICIRCLE ARROW +21B8 ; [*05D7.0020.0002] # NORTH WEST ARROW TO LONG BAR +21B9 ; [*05D8.0020.0002] # LEFTWARDS ARROW TO BAR OVER RIGHTWARDS ARROW TO BAR +21BA ; [*05D9.0020.0002] # ANTICLOCKWISE OPEN CIRCLE ARROW +21BB ; [*05DA.0020.0002] # CLOCKWISE OPEN CIRCLE ARROW +21BC ; [*05DB.0020.0002] # LEFTWARDS HARPOON WITH BARB UPWARDS +21BD ; [*05DC.0020.0002] # LEFTWARDS HARPOON WITH BARB DOWNWARDS +21BE ; [*05DD.0020.0002] # UPWARDS HARPOON WITH BARB RIGHTWARDS +21BF ; [*05DE.0020.0002] # UPWARDS HARPOON WITH BARB LEFTWARDS +21C0 ; [*05DF.0020.0002] # RIGHTWARDS HARPOON WITH BARB UPWARDS +21C1 ; [*05E0.0020.0002] # RIGHTWARDS HARPOON WITH BARB DOWNWARDS +21C2 ; [*05E1.0020.0002] # DOWNWARDS HARPOON WITH BARB RIGHTWARDS +21C3 ; [*05E2.0020.0002] # DOWNWARDS HARPOON WITH BARB LEFTWARDS +21C4 ; [*05E3.0020.0002] # RIGHTWARDS ARROW OVER LEFTWARDS ARROW +21C5 ; [*05E4.0020.0002] # UPWARDS ARROW LEFTWARDS OF DOWNWARDS ARROW +21C6 ; [*05E5.0020.0002] # LEFTWARDS ARROW OVER RIGHTWARDS ARROW +21C7 ; [*05E6.0020.0002] # LEFTWARDS PAIRED ARROWS +21C8 ; [*05E7.0020.0002] # UPWARDS PAIRED ARROWS +21C9 ; [*05E8.0020.0002] # RIGHTWARDS PAIRED ARROWS +21CA ; [*05E9.0020.0002] # DOWNWARDS PAIRED ARROWS +21CB ; [*05EA.0020.0002] # LEFTWARDS HARPOON OVER RIGHTWARDS HARPOON +21CC ; [*05EB.0020.0002] # RIGHTWARDS HARPOON OVER LEFTWARDS HARPOON +21CD ; [*05EC.0020.0002][.0000.002F.0002] # LEFTWARDS DOUBLE ARROW WITH STROKE +21CE ; [*05F0.0020.0002][.0000.002F.0002] # LEFT RIGHT DOUBLE ARROW WITH STROKE +21CF ; [*05EE.0020.0002][.0000.002F.0002] # RIGHTWARDS DOUBLE ARROW WITH STROKE +21D0 ; [*05EC.0020.0002] # LEFTWARDS DOUBLE ARROW +21D1 ; [*05ED.0020.0002] # UPWARDS DOUBLE ARROW +21D2 ; [*05EE.0020.0002] # RIGHTWARDS DOUBLE ARROW +21D3 ; [*05EF.0020.0002] # DOWNWARDS DOUBLE ARROW +21D4 ; [*05F0.0020.0002] # LEFT RIGHT DOUBLE ARROW +21D5 ; [*05F1.0020.0002] # UP DOWN DOUBLE ARROW +21D6 ; [*05F2.0020.0002] # NORTH WEST DOUBLE ARROW +21D7 ; [*05F3.0020.0002] # NORTH EAST DOUBLE ARROW +21D8 ; [*05F4.0020.0002] # SOUTH EAST DOUBLE ARROW +21D9 ; [*05F5.0020.0002] # SOUTH WEST DOUBLE ARROW +21DA ; [*05F6.0020.0002] # LEFTWARDS TRIPLE ARROW +21DB ; [*05F7.0020.0002] # RIGHTWARDS TRIPLE ARROW +21DC ; [*05F8.0020.0002] # LEFTWARDS SQUIGGLE ARROW +21DD ; [*05F9.0020.0002] # RIGHTWARDS SQUIGGLE ARROW +21DE ; [*05FA.0020.0002] # UPWARDS ARROW WITH DOUBLE STROKE +21DF ; [*05FB.0020.0002] # DOWNWARDS ARROW WITH DOUBLE STROKE +21E0 ; [*05FC.0020.0002] # LEFTWARDS DASHED ARROW +21E1 ; [*05FD.0020.0002] # UPWARDS DASHED ARROW +21E2 ; [*05FE.0020.0002] # RIGHTWARDS DASHED ARROW +21E3 ; [*05FF.0020.0002] # DOWNWARDS DASHED ARROW +21E4 ; [*0600.0020.0002] # LEFTWARDS ARROW TO BAR +21E5 ; [*0601.0020.0002] # RIGHTWARDS ARROW TO BAR +21E6 ; [*0602.0020.0002] # LEFTWARDS WHITE ARROW +21E7 ; [*0603.0020.0002] # UPWARDS WHITE ARROW +21E8 ; [*0604.0020.0002] # RIGHTWARDS WHITE ARROW +21E9 ; [*0605.0020.0002] # DOWNWARDS WHITE ARROW +21EA ; [*0606.0020.0002] # UPWARDS WHITE ARROW FROM BAR +21EB ; [*0607.0020.0002] # UPWARDS WHITE ARROW ON PEDESTAL +21EC ; [*0608.0020.0002] # UPWARDS WHITE ARROW ON PEDESTAL WITH HORIZONTAL BAR +21ED ; [*0609.0020.0002] # UPWARDS WHITE ARROW ON PEDESTAL WITH VERTICAL BAR +21EE ; [*060A.0020.0002] # UPWARDS WHITE DOUBLE ARROW +21EF ; [*060B.0020.0002] # UPWARDS WHITE DOUBLE ARROW ON PEDESTAL +21F0 ; [*060C.0020.0002] # RIGHTWARDS WHITE ARROW FROM WALL +21F1 ; [*060D.0020.0002] # NORTH WEST ARROW TO CORNER +21F2 ; [*060E.0020.0002] # SOUTH EAST ARROW TO CORNER +21F3 ; [*060F.0020.0002] # UP DOWN WHITE ARROW +21F4 ; [*0610.0020.0002] # RIGHT ARROW WITH SMALL CIRCLE +21F5 ; [*0611.0020.0002] # DOWNWARDS ARROW LEFTWARDS OF UPWARDS ARROW +21F6 ; [*0612.0020.0002] # THREE RIGHTWARDS ARROWS +21F7 ; [*0613.0020.0002] # LEFTWARDS ARROW WITH VERTICAL STROKE +21F8 ; [*0614.0020.0002] # RIGHTWARDS ARROW WITH VERTICAL STROKE +21F9 ; [*0615.0020.0002] # LEFT RIGHT ARROW WITH VERTICAL STROKE +21FA ; [*0616.0020.0002] # LEFTWARDS ARROW WITH DOUBLE VERTICAL STROKE +21FB ; [*0617.0020.0002] # RIGHTWARDS ARROW WITH DOUBLE VERTICAL STROKE +21FC ; [*0618.0020.0002] # LEFT RIGHT ARROW WITH DOUBLE VERTICAL STROKE +21FD ; [*0619.0020.0002] # LEFTWARDS OPEN-HEADED ARROW +21FE ; [*061A.0020.0002] # RIGHTWARDS OPEN-HEADED ARROW +21FF ; [*061B.0020.0002] # LEFT RIGHT OPEN-HEADED ARROW +2200 ; [*061C.0020.0002] # FOR ALL +2201 ; [*061D.0020.0002] # COMPLEMENT +2202 ; [*061E.0020.0002] # PARTIAL DIFFERENTIAL +2203 ; [*061F.0020.0002] # THERE EXISTS +2204 ; [*061F.0020.0002][.0000.002F.0002] # THERE DOES NOT EXIST +2205 ; [*0620.0020.0002] # EMPTY SET +2206 ; [*0621.0020.0002] # INCREMENT +2207 ; [*0622.0020.0002] # NABLA +2208 ; [*0623.0020.0002] # ELEMENT OF +2209 ; [*0623.0020.0002][.0000.002F.0002] # NOT AN ELEMENT OF +220A ; [*0624.0020.0002] # SMALL ELEMENT OF +220B ; [*0625.0020.0002] # CONTAINS AS MEMBER +220C ; [*0625.0020.0002][.0000.002F.0002] # DOES NOT CONTAIN AS MEMBER +220D ; [*0626.0020.0002] # SMALL CONTAINS AS MEMBER +220E ; [*0628.0020.0002] # END OF PROOF +220F ; [*0629.0020.0002] # N-ARY PRODUCT +2210 ; [*062A.0020.0002] # N-ARY COPRODUCT +2211 ; [*062B.0020.0002] # N-ARY SUMMATION +2212 ; [*0637.0020.0002] # MINUS SIGN +2213 ; [*0639.0020.0002] # MINUS-OR-PLUS SIGN +2214 ; [*063A.0020.0002] # DOT PLUS +2215 ; [*063B.0020.0002] # DIVISION SLASH +2216 ; [*063D.0020.0002] # SET MINUS +2217 ; [*063E.0020.0002] # ASTERISK OPERATOR +2218 ; [*063F.0020.0002] # RING OPERATOR +2219 ; [*0640.0020.0002] # BULLET OPERATOR +221A ; [*0641.0020.0002] # SQUARE ROOT +221B ; [*0642.0020.0002] # CUBE ROOT +221C ; [*0644.0020.0002] # FOURTH ROOT +221D ; [*0646.0020.0002] # PROPORTIONAL TO +221E ; [*0647.0020.0002] # INFINITY +221F ; [*0648.0020.0002] # RIGHT ANGLE +2220 ; [*0649.0020.0002] # ANGLE +2221 ; [*064A.0020.0002] # MEASURED ANGLE +2222 ; [*064B.0020.0002] # SPHERICAL ANGLE +2223 ; [*064C.0020.0002] # DIVIDES +2224 ; [*064C.0020.0002][.0000.002F.0002] # DOES NOT DIVIDE +2225 ; [*064D.0020.0002] # PARALLEL TO +2226 ; [*064D.0020.0002][.0000.002F.0002] # NOT PARALLEL TO +2227 ; [*064E.0020.0002] # LOGICAL AND +2228 ; [*064F.0020.0002] # LOGICAL OR +2229 ; [*0650.0020.0002] # INTERSECTION +222A ; [*0651.0020.0002] # UNION +222B ; [*0652.0020.0002] # INTEGRAL +222C ; [*0652.0020.0004][*0652.0020.0004] # DOUBLE INTEGRAL +222D ; [*0652.0020.0004][*0652.0020.0004][*0652.0020.0004] # TRIPLE INTEGRAL +222E ; [*0653.0020.0002] # CONTOUR INTEGRAL +222F ; [*0653.0020.0004][*0653.0020.0004] # SURFACE INTEGRAL +2230 ; [*0653.0020.0004][*0653.0020.0004][*0653.0020.0004] # VOLUME INTEGRAL +2231 ; [*0654.0020.0002] # CLOCKWISE INTEGRAL +2232 ; [*0655.0020.0002] # CLOCKWISE CONTOUR INTEGRAL +2233 ; [*0656.0020.0002] # ANTICLOCKWISE CONTOUR INTEGRAL +2234 ; [*0657.0020.0002] # THEREFORE +2235 ; [*0658.0020.0002] # BECAUSE +2236 ; [*0659.0020.0002] # RATIO +2237 ; [*065A.0020.0002] # PROPORTION +2238 ; [*065B.0020.0002] # DOT MINUS +2239 ; [*065C.0020.0002] # EXCESS +223A ; [*065D.0020.0002] # GEOMETRIC PROPORTION +223B ; [*065E.0020.0002] # HOMOTHETIC +223C ; [*065F.0020.0002] # TILDE OPERATOR +223D ; [*0660.0020.0002] # REVERSED TILDE +223E ; [*0661.0020.0002] # INVERTED LAZY S +223F ; [*0662.0020.0002] # SINE WAVE +2240 ; [*0663.0020.0002] # WREATH PRODUCT +2241 ; [*065F.0020.0002][.0000.002F.0002] # NOT TILDE +2242 ; [*0664.0020.0002] # MINUS TILDE +2243 ; [*0665.0020.0002] # ASYMPTOTICALLY EQUAL TO +2244 ; [*0665.0020.0002][.0000.002F.0002] # NOT ASYMPTOTICALLY EQUAL TO +2245 ; [*0666.0020.0002] # APPROXIMATELY EQUAL TO +2246 ; [*0667.0020.0002] # APPROXIMATELY BUT NOT ACTUALLY EQUAL TO +2247 ; [*0666.0020.0002][.0000.002F.0002] # NEITHER APPROXIMATELY NOR ACTUALLY EQUAL TO +2248 ; [*0668.0020.0002] # ALMOST EQUAL TO +2249 ; [*0668.0020.0002][.0000.002F.0002] # NOT ALMOST EQUAL TO +224A ; [*0669.0020.0002] # ALMOST EQUAL OR EQUAL TO +224B ; [*066A.0020.0002] # TRIPLE TILDE +224C ; [*066B.0020.0002] # ALL EQUAL TO +224D ; [*066C.0020.0002] # EQUIVALENT TO +224E ; [*066D.0020.0002] # GEOMETRICALLY EQUIVALENT TO +224F ; [*066E.0020.0002] # DIFFERENCE BETWEEN +2250 ; [*066F.0020.0002] # APPROACHES THE LIMIT +2251 ; [*0670.0020.0002] # GEOMETRICALLY EQUAL TO +2252 ; [*0671.0020.0002] # APPROXIMATELY EQUAL TO OR THE IMAGE OF +2253 ; [*0672.0020.0002] # IMAGE OF OR APPROXIMATELY EQUAL TO +2254 ; [*0673.0020.0002] # COLON EQUALS +2255 ; [*0674.0020.0002] # EQUALS COLON +2256 ; [*0675.0020.0002] # RING IN EQUAL TO +2257 ; [*0676.0020.0002] # RING EQUAL TO +2258 ; [*0677.0020.0002] # CORRESPONDS TO +2259 ; [*0678.0020.0002] # ESTIMATES +225A ; [*0679.0020.0002] # EQUIANGULAR TO +225B ; [*067A.0020.0002] # STAR EQUALS +225C ; [*067B.0020.0002] # DELTA EQUAL TO +225D ; [*067C.0020.0002] # EQUAL TO BY DEFINITION +225E ; [*067D.0020.0002] # MEASURED BY +225F ; [*067E.0020.0002] # QUESTIONED EQUAL TO +2260 ; [*0631.0020.0002][.0000.002F.0002] # NOT EQUAL TO +2261 ; [*067F.0020.0002] # IDENTICAL TO +2262 ; [*067F.0020.0002][.0000.002F.0002] # NOT IDENTICAL TO +2263 ; [*0680.0020.0002] # STRICTLY EQUIVALENT TO +2264 ; [*0681.0020.0002] # LESS-THAN OR EQUAL TO +2265 ; [*0682.0020.0002] # GREATER-THAN OR EQUAL TO +2266 ; [*0683.0020.0002] # LESS-THAN OVER EQUAL TO +2267 ; [*0684.0020.0002] # GREATER-THAN OVER EQUAL TO +2268 ; [*0685.0020.0002] # LESS-THAN BUT NOT EQUAL TO +2269 ; [*0686.0020.0002] # GREATER-THAN BUT NOT EQUAL TO +226A ; [*0687.0020.0002] # MUCH LESS-THAN +226B ; [*0688.0020.0002] # MUCH GREATER-THAN +226C ; [*0689.0020.0002] # BETWEEN +226D ; [*066C.0020.0002][.0000.002F.0002] # NOT EQUIVALENT TO +226E ; [*0630.0020.0002][.0000.002F.0002] # NOT LESS-THAN +226F ; [*0632.0020.0002][.0000.002F.0002] # NOT GREATER-THAN +2270 ; [*0681.0020.0002][.0000.002F.0002] # NEITHER LESS-THAN NOR EQUAL TO +2271 ; [*0682.0020.0002][.0000.002F.0002] # NEITHER GREATER-THAN NOR EQUAL TO +2272 ; [*068A.0020.0002] # LESS-THAN OR EQUIVALENT TO +2273 ; [*068B.0020.0002] # GREATER-THAN OR EQUIVALENT TO +2274 ; [*068A.0020.0002][.0000.002F.0002] # NEITHER LESS-THAN NOR EQUIVALENT TO +2275 ; [*068B.0020.0002][.0000.002F.0002] # NEITHER GREATER-THAN NOR EQUIVALENT TO +2276 ; [*068C.0020.0002] # LESS-THAN OR GREATER-THAN +2277 ; [*068D.0020.0002] # GREATER-THAN OR LESS-THAN +2278 ; [*068C.0020.0002][.0000.002F.0002] # NEITHER LESS-THAN NOR GREATER-THAN +2279 ; [*068D.0020.0002][.0000.002F.0002] # NEITHER GREATER-THAN NOR LESS-THAN +227A ; [*068E.0020.0002] # PRECEDES +227B ; [*068F.0020.0002] # SUCCEEDS +227C ; [*0690.0020.0002] # PRECEDES OR EQUAL TO +227D ; [*0691.0020.0002] # SUCCEEDS OR EQUAL TO +227E ; [*0692.0020.0002] # PRECEDES OR EQUIVALENT TO +227F ; [*0693.0020.0002] # SUCCEEDS OR EQUIVALENT TO +2280 ; [*068E.0020.0002][.0000.002F.0002] # DOES NOT PRECEDE +2281 ; [*068F.0020.0002][.0000.002F.0002] # DOES NOT SUCCEED +2282 ; [*0694.0020.0002] # SUBSET OF +2283 ; [*0695.0020.0002] # SUPERSET OF +2284 ; [*0694.0020.0002][.0000.002F.0002] # NOT A SUBSET OF +2285 ; [*0695.0020.0002][.0000.002F.0002] # NOT A SUPERSET OF +2286 ; [*0696.0020.0002] # SUBSET OF OR EQUAL TO +2287 ; [*0697.0020.0002] # SUPERSET OF OR EQUAL TO +2288 ; [*0696.0020.0002][.0000.002F.0002] # NEITHER A SUBSET OF NOR EQUAL TO +2289 ; [*0697.0020.0002][.0000.002F.0002] # NEITHER A SUPERSET OF NOR EQUAL TO +228A ; [*0698.0020.0002] # SUBSET OF WITH NOT EQUAL TO +228B ; [*0699.0020.0002] # SUPERSET OF WITH NOT EQUAL TO +228C ; [*069A.0020.0002] # MULTISET +228D ; [*069B.0020.0002] # MULTISET MULTIPLICATION +228E ; [*069C.0020.0002] # MULTISET UNION +228F ; [*069D.0020.0002] # SQUARE IMAGE OF +2290 ; [*069E.0020.0002] # SQUARE ORIGINAL OF +2291 ; [*069F.0020.0002] # SQUARE IMAGE OF OR EQUAL TO +2292 ; [*06A0.0020.0002] # SQUARE ORIGINAL OF OR EQUAL TO +2293 ; [*06A1.0020.0002] # SQUARE CAP +2294 ; [*06A2.0020.0002] # SQUARE CUP +2295 ; [*06A3.0020.0002] # CIRCLED PLUS +2296 ; [*06A4.0020.0002] # CIRCLED MINUS +2297 ; [*06A5.0020.0002] # CIRCLED TIMES +2298 ; [*06A6.0020.0002] # CIRCLED DIVISION SLASH +2299 ; [*06A7.0020.0002] # CIRCLED DOT OPERATOR +229A ; [*06A8.0020.0002] # CIRCLED RING OPERATOR +229B ; [*06A9.0020.0002] # CIRCLED ASTERISK OPERATOR +229C ; [*06AA.0020.0002] # CIRCLED EQUALS +229D ; [*06AB.0020.0002] # CIRCLED DASH +229E ; [*06AC.0020.0002] # SQUARED PLUS +229F ; [*06AD.0020.0002] # SQUARED MINUS +22A0 ; [*06AE.0020.0002] # SQUARED TIMES +22A1 ; [*06AF.0020.0002] # SQUARED DOT OPERATOR +22A2 ; [*06B0.0020.0002] # RIGHT TACK +22A3 ; [*06B1.0020.0002] # LEFT TACK +22A4 ; [*06B2.0020.0002] # DOWN TACK +22A5 ; [*06B3.0020.0002] # UP TACK +22A6 ; [*06B4.0020.0002] # ASSERTION +22A7 ; [*06B5.0020.0002] # MODELS +22A8 ; [*06B6.0020.0002] # TRUE +22A9 ; [*06B7.0020.0002] # FORCES +22AA ; [*06B8.0020.0002] # TRIPLE VERTICAL BAR RIGHT TURNSTILE +22AB ; [*06B9.0020.0002] # DOUBLE VERTICAL BAR DOUBLE RIGHT TURNSTILE +22AC ; [*06B0.0020.0002][.0000.002F.0002] # DOES NOT PROVE +22AD ; [*06B6.0020.0002][.0000.002F.0002] # NOT TRUE +22AE ; [*06B7.0020.0002][.0000.002F.0002] # DOES NOT FORCE +22AF ; [*06B9.0020.0002][.0000.002F.0002] # NEGATED DOUBLE VERTICAL BAR DOUBLE RIGHT TURNSTILE +22B0 ; [*06BA.0020.0002] # PRECEDES UNDER RELATION +22B1 ; [*06BB.0020.0002] # SUCCEEDS UNDER RELATION +22B2 ; [*06BC.0020.0002] # NORMAL SUBGROUP OF +22B3 ; [*06BD.0020.0002] # CONTAINS AS NORMAL SUBGROUP +22B4 ; [*06BE.0020.0002] # NORMAL SUBGROUP OF OR EQUAL TO +22B5 ; [*06BF.0020.0002] # CONTAINS AS NORMAL SUBGROUP OR EQUAL TO +22B6 ; [*06C0.0020.0002] # ORIGINAL OF +22B7 ; [*06C1.0020.0002] # IMAGE OF +22B8 ; [*06C2.0020.0002] # MULTIMAP +22B9 ; [*06C3.0020.0002] # HERMITIAN CONJUGATE MATRIX +22BA ; [*06C4.0020.0002] # INTERCALATE +22BB ; [*06C5.0020.0002] # XOR +22BC ; [*06C6.0020.0002] # NAND +22BD ; [*06C8.0020.0002] # NOR +22BE ; [*06C9.0020.0002] # RIGHT ANGLE WITH ARC +22BF ; [*06CA.0020.0002] # RIGHT TRIANGLE +22C0 ; [*06CB.0020.0002] # N-ARY LOGICAL AND +22C1 ; [*06CC.0020.0002] # N-ARY LOGICAL OR +22C2 ; [*06CD.0020.0002] # N-ARY INTERSECTION +22C3 ; [*06CE.0020.0002] # N-ARY UNION +22C4 ; [*06CF.0020.0002] # DIAMOND OPERATOR +22C5 ; [*06D0.0020.0002] # DOT OPERATOR +22C6 ; [*06D1.0020.0002] # STAR OPERATOR +22C7 ; [*06D2.0020.0002] # DIVISION TIMES +22C8 ; [*06D3.0020.0002] # BOWTIE +22C9 ; [*06D4.0020.0002] # LEFT NORMAL FACTOR SEMIDIRECT PRODUCT +22CA ; [*06D5.0020.0002] # RIGHT NORMAL FACTOR SEMIDIRECT PRODUCT +22CB ; [*06D6.0020.0002] # LEFT SEMIDIRECT PRODUCT +22CC ; [*06D7.0020.0002] # RIGHT SEMIDIRECT PRODUCT +22CD ; [*06D8.0020.0002] # REVERSED TILDE EQUALS +22CE ; [*06D9.0020.0002] # CURLY LOGICAL OR +22CF ; [*06DA.0020.0002] # CURLY LOGICAL AND +22D0 ; [*06DB.0020.0002] # DOUBLE SUBSET +22D1 ; [*06DC.0020.0002] # DOUBLE SUPERSET +22D2 ; [*06DD.0020.0002] # DOUBLE INTERSECTION +22D3 ; [*06DE.0020.0002] # DOUBLE UNION +22D4 ; [*06DF.0020.0002] # PITCHFORK +22D5 ; [*06E0.0020.0002] # EQUAL AND PARALLEL TO +22D6 ; [*06E1.0020.0002] # LESS-THAN WITH DOT +22D7 ; [*06E2.0020.0002] # GREATER-THAN WITH DOT +22D8 ; [*06E3.0020.0002] # VERY MUCH LESS-THAN +22D9 ; [*06E4.0020.0002] # VERY MUCH GREATER-THAN +22DA ; [*06E5.0020.0002] # LESS-THAN EQUAL TO OR GREATER-THAN +22DB ; [*06E6.0020.0002] # GREATER-THAN EQUAL TO OR LESS-THAN +22DC ; [*06E7.0020.0002] # EQUAL TO OR LESS-THAN +22DD ; [*06E8.0020.0002] # EQUAL TO OR GREATER-THAN +22DE ; [*06E9.0020.0002] # EQUAL TO OR PRECEDES +22DF ; [*06EA.0020.0002] # EQUAL TO OR SUCCEEDS +22E0 ; [*0690.0020.0002][.0000.002F.0002] # DOES NOT PRECEDE OR EQUAL +22E1 ; [*0691.0020.0002][.0000.002F.0002] # DOES NOT SUCCEED OR EQUAL +22E2 ; [*069F.0020.0002][.0000.002F.0002] # NOT SQUARE IMAGE OF OR EQUAL TO +22E3 ; [*06A0.0020.0002][.0000.002F.0002] # NOT SQUARE ORIGINAL OF OR EQUAL TO +22E4 ; [*06EB.0020.0002] # SQUARE IMAGE OF OR NOT EQUAL TO +22E5 ; [*06EC.0020.0002] # SQUARE ORIGINAL OF OR NOT EQUAL TO +22E6 ; [*06ED.0020.0002] # LESS-THAN BUT NOT EQUIVALENT TO +22E7 ; [*06EE.0020.0002] # GREATER-THAN BUT NOT EQUIVALENT TO +22E8 ; [*06EF.0020.0002] # PRECEDES BUT NOT EQUIVALENT TO +22E9 ; [*06F0.0020.0002] # SUCCEEDS BUT NOT EQUIVALENT TO +22EA ; [*06BC.0020.0002][.0000.002F.0002] # NOT NORMAL SUBGROUP OF +22EB ; [*06BD.0020.0002][.0000.002F.0002] # DOES NOT CONTAIN AS NORMAL SUBGROUP +22EC ; [*06BE.0020.0002][.0000.002F.0002] # NOT NORMAL SUBGROUP OF OR EQUAL TO +22ED ; [*06BF.0020.0002][.0000.002F.0002] # DOES NOT CONTAIN AS NORMAL SUBGROUP OR EQUAL +22EE ; [*06F1.0020.0002] # VERTICAL ELLIPSIS +22EF ; [*06F2.0020.0002] # MIDLINE HORIZONTAL ELLIPSIS +22F0 ; [*06F3.0020.0002] # UP RIGHT DIAGONAL ELLIPSIS +22F1 ; [*06F4.0020.0002] # DOWN RIGHT DIAGONAL ELLIPSIS +22F2 ; [*06F5.0020.0002] # ELEMENT OF WITH LONG HORIZONTAL STROKE +22F3 ; [*06F6.0020.0002] # ELEMENT OF WITH VERTICAL BAR AT END OF HORIZONTAL STROKE +22F4 ; [*06F7.0020.0002] # SMALL ELEMENT OF WITH VERTICAL BAR AT END OF HORIZONTAL STROKE +22F5 ; [*06F8.0020.0002] # ELEMENT OF WITH DOT ABOVE +22F6 ; [*06F9.0020.0002] # ELEMENT OF WITH OVERBAR +22F7 ; [*06FA.0020.0002] # SMALL ELEMENT OF WITH OVERBAR +22F8 ; [*06FB.0020.0002] # ELEMENT OF WITH UNDERBAR +22F9 ; [*06FC.0020.0002] # ELEMENT OF WITH TWO HORIZONTAL STROKES +22FA ; [*06FD.0020.0002] # CONTAINS WITH LONG HORIZONTAL STROKE +22FB ; [*06FE.0020.0002] # CONTAINS WITH VERTICAL BAR AT END OF HORIZONTAL STROKE +22FC ; [*06FF.0020.0002] # SMALL CONTAINS WITH VERTICAL BAR AT END OF HORIZONTAL STROKE +22FD ; [*0700.0020.0002] # CONTAINS WITH OVERBAR +22FE ; [*0701.0020.0002] # SMALL CONTAINS WITH OVERBAR +22FF ; [*0702.0020.0002] # Z NOTATION BAG MEMBERSHIP +2300 ; [*0703.0020.0002] # DIAMETER SIGN +2301 ; [*0704.0020.0002] # ELECTRIC ARROW +2302 ; [*0705.0020.0002] # HOUSE +2303 ; [*0706.0020.0002] # UP ARROWHEAD +2304 ; [*0707.0020.0002] # DOWN ARROWHEAD +2305 ; [*0708.0020.0002] # PROJECTIVE +2306 ; [*0709.0020.0002] # PERSPECTIVE +2307 ; [*070A.0020.0002] # WAVY LINE +2308 ; [*0326.0020.0002] # LEFT CEILING +2309 ; [*0327.0020.0002] # RIGHT CEILING +230A ; [*0328.0020.0002] # LEFT FLOOR +230B ; [*0329.0020.0002] # RIGHT FLOOR +230C ; [*070B.0020.0002] # BOTTOM RIGHT CROP +230D ; [*070C.0020.0002] # BOTTOM LEFT CROP +230E ; [*070D.0020.0002] # TOP RIGHT CROP +230F ; [*070E.0020.0002] # TOP LEFT CROP +2310 ; [*070F.0020.0002] # REVERSED NOT SIGN +2311 ; [*0710.0020.0002] # SQUARE LOZENGE +2312 ; [*0711.0020.0002] # ARC +2313 ; [*0712.0020.0002] # SEGMENT +2314 ; [*0713.0020.0002] # SECTOR +2315 ; [*0714.0020.0002] # TELEPHONE RECORDER +2316 ; [*0715.0020.0002] # POSITION INDICATOR +2317 ; [*0716.0020.0002] # VIEWDATA SQUARE +2318 ; [*0717.0020.0002] # PLACE OF INTEREST SIGN +2319 ; [*0718.0020.0002] # TURNED NOT SIGN +231A ; [*0719.0020.0002] # WATCH +231B ; [*071A.0020.0002] # HOURGLASS +231C ; [*071B.0020.0002] # TOP LEFT CORNER +231D ; [*071C.0020.0002] # TOP RIGHT CORNER +231E ; [*071D.0020.0002] # BOTTOM LEFT CORNER +231F ; [*071E.0020.0002] # BOTTOM RIGHT CORNER +2320 ; [*071F.0020.0002] # TOP HALF INTEGRAL +2321 ; [*0720.0020.0002] # BOTTOM HALF INTEGRAL +2322 ; [*0721.0020.0002] # FROWN +2323 ; [*0722.0020.0002] # SMILE +2324 ; [*0723.0020.0002] # UP ARROWHEAD BETWEEN TWO HORIZONTAL BARS +2325 ; [*0724.0020.0002] # OPTION KEY +2326 ; [*0725.0020.0002] # ERASE TO THE RIGHT +2327 ; [*0726.0020.0002] # X IN A RECTANGLE BOX +2328 ; [*0727.0020.0002] # KEYBOARD +2329 ; [*0370.0020.0002] # LEFT-POINTING ANGLE BRACKET +232A ; [*0371.0020.0002] # RIGHT-POINTING ANGLE BRACKET +232B ; [*0728.0020.0002] # ERASE TO THE LEFT +232C ; [*0729.0020.0002] # BENZENE RING +232D ; [*072A.0020.0002] # CYLINDRICITY +232E ; [*072B.0020.0002] # ALL AROUND-PROFILE +232F ; [*072C.0020.0002] # SYMMETRY +2330 ; [*072D.0020.0002] # TOTAL RUNOUT +2331 ; [*072E.0020.0002] # DIMENSION ORIGIN +2332 ; [*072F.0020.0002] # CONICAL TAPER +2333 ; [*0730.0020.0002] # SLOPE +2334 ; [*0731.0020.0002] # COUNTERBORE +2335 ; [*0732.0020.0002] # COUNTERSINK +2336 ; [*0733.0020.0002] # APL FUNCTIONAL SYMBOL I-BEAM +2337 ; [*0734.0020.0002] # APL FUNCTIONAL SYMBOL SQUISH QUAD +2338 ; [*0735.0020.0002] # APL FUNCTIONAL SYMBOL QUAD EQUAL +2339 ; [*0736.0020.0002] # APL FUNCTIONAL SYMBOL QUAD DIVIDE +233A ; [*0737.0020.0002] # APL FUNCTIONAL SYMBOL QUAD DIAMOND +233B ; [*0738.0020.0002] # APL FUNCTIONAL SYMBOL QUAD JOT +233C ; [*0739.0020.0002] # APL FUNCTIONAL SYMBOL QUAD CIRCLE +233D ; [*073A.0020.0002] # APL FUNCTIONAL SYMBOL CIRCLE STILE +233E ; [*073B.0020.0002] # APL FUNCTIONAL SYMBOL CIRCLE JOT +233F ; [*073C.0020.0002] # APL FUNCTIONAL SYMBOL SLASH BAR +2340 ; [*073D.0020.0002] # APL FUNCTIONAL SYMBOL BACKSLASH BAR +2341 ; [*073E.0020.0002] # APL FUNCTIONAL SYMBOL QUAD SLASH +2342 ; [*073F.0020.0002] # APL FUNCTIONAL SYMBOL QUAD BACKSLASH +2343 ; [*0740.0020.0002] # APL FUNCTIONAL SYMBOL QUAD LESS-THAN +2344 ; [*0741.0020.0002] # APL FUNCTIONAL SYMBOL QUAD GREATER-THAN +2345 ; [*0742.0020.0002] # APL FUNCTIONAL SYMBOL LEFTWARDS VANE +2346 ; [*0743.0020.0002] # APL FUNCTIONAL SYMBOL RIGHTWARDS VANE +2347 ; [*0744.0020.0002] # APL FUNCTIONAL SYMBOL QUAD LEFTWARDS ARROW +2348 ; [*0745.0020.0002] # APL FUNCTIONAL SYMBOL QUAD RIGHTWARDS ARROW +2349 ; [*0746.0020.0002] # APL FUNCTIONAL SYMBOL CIRCLE BACKSLASH +234A ; [*0747.0020.0002] # APL FUNCTIONAL SYMBOL DOWN TACK UNDERBAR +234B ; [*0748.0020.0002] # APL FUNCTIONAL SYMBOL DELTA STILE +234C ; [*0749.0020.0002] # APL FUNCTIONAL SYMBOL QUAD DOWN CARET +234D ; [*074A.0020.0002] # APL FUNCTIONAL SYMBOL QUAD DELTA +234E ; [*074B.0020.0002] # APL FUNCTIONAL SYMBOL DOWN TACK JOT +234F ; [*074C.0020.0002] # APL FUNCTIONAL SYMBOL UPWARDS VANE +2350 ; [*074D.0020.0002] # APL FUNCTIONAL SYMBOL QUAD UPWARDS ARROW +2351 ; [*074E.0020.0002] # APL FUNCTIONAL SYMBOL UP TACK OVERBAR +2352 ; [*074F.0020.0002] # APL FUNCTIONAL SYMBOL DEL STILE +2353 ; [*0750.0020.0002] # APL FUNCTIONAL SYMBOL QUAD UP CARET +2354 ; [*0751.0020.0002] # APL FUNCTIONAL SYMBOL QUAD DEL +2355 ; [*0752.0020.0002] # APL FUNCTIONAL SYMBOL UP TACK JOT +2356 ; [*0753.0020.0002] # APL FUNCTIONAL SYMBOL DOWNWARDS VANE +2357 ; [*0754.0020.0002] # APL FUNCTIONAL SYMBOL QUAD DOWNWARDS ARROW +2358 ; [*0755.0020.0002] # APL FUNCTIONAL SYMBOL QUOTE UNDERBAR +2359 ; [*0756.0020.0002] # APL FUNCTIONAL SYMBOL DELTA UNDERBAR +235A ; [*0757.0020.0002] # APL FUNCTIONAL SYMBOL DIAMOND UNDERBAR +235B ; [*0758.0020.0002] # APL FUNCTIONAL SYMBOL JOT UNDERBAR +235C ; [*0759.0020.0002] # APL FUNCTIONAL SYMBOL CIRCLE UNDERBAR +235D ; [*075A.0020.0002] # APL FUNCTIONAL SYMBOL UP SHOE JOT +235E ; [*075B.0020.0002] # APL FUNCTIONAL SYMBOL QUOTE QUAD +235F ; [*075C.0020.0002] # APL FUNCTIONAL SYMBOL CIRCLE STAR +2360 ; [*075D.0020.0002] # APL FUNCTIONAL SYMBOL QUAD COLON +2361 ; [*075E.0020.0002] # APL FUNCTIONAL SYMBOL UP TACK DIAERESIS +2362 ; [*075F.0020.0002] # APL FUNCTIONAL SYMBOL DEL DIAERESIS +2363 ; [*0760.0020.0002] # APL FUNCTIONAL SYMBOL STAR DIAERESIS +2364 ; [*0761.0020.0002] # APL FUNCTIONAL SYMBOL JOT DIAERESIS +2365 ; [*0762.0020.0002] # APL FUNCTIONAL SYMBOL CIRCLE DIAERESIS +2366 ; [*0763.0020.0002] # APL FUNCTIONAL SYMBOL DOWN SHOE STILE +2367 ; [*0764.0020.0002] # APL FUNCTIONAL SYMBOL LEFT SHOE STILE +2368 ; [*0765.0020.0002] # APL FUNCTIONAL SYMBOL TILDE DIAERESIS +2369 ; [*0766.0020.0002] # APL FUNCTIONAL SYMBOL GREATER-THAN DIAERESIS +236A ; [*0767.0020.0002] # APL FUNCTIONAL SYMBOL COMMA BAR +236B ; [*0768.0020.0002] # APL FUNCTIONAL SYMBOL DEL TILDE +236C ; [*0769.0020.0002] # APL FUNCTIONAL SYMBOL ZILDE +236D ; [*076A.0020.0002] # APL FUNCTIONAL SYMBOL STILE TILDE +236E ; [*076B.0020.0002] # APL FUNCTIONAL SYMBOL SEMICOLON UNDERBAR +236F ; [*076C.0020.0002] # APL FUNCTIONAL SYMBOL QUAD NOT EQUAL +2370 ; [*076D.0020.0002] # APL FUNCTIONAL SYMBOL QUAD QUESTION +2371 ; [*076E.0020.0002] # APL FUNCTIONAL SYMBOL DOWN CARET TILDE +2372 ; [*076F.0020.0002] # APL FUNCTIONAL SYMBOL UP CARET TILDE +2373 ; [*0770.0020.0002] # APL FUNCTIONAL SYMBOL IOTA +2374 ; [*0771.0020.0002] # APL FUNCTIONAL SYMBOL RHO +2375 ; [*0772.0020.0002] # APL FUNCTIONAL SYMBOL OMEGA +2376 ; [*0773.0020.0002] # APL FUNCTIONAL SYMBOL ALPHA UNDERBAR +2377 ; [*0774.0020.0002] # APL FUNCTIONAL SYMBOL EPSILON UNDERBAR +2378 ; [*0775.0020.0002] # APL FUNCTIONAL SYMBOL IOTA UNDERBAR +2379 ; [*0776.0020.0002] # APL FUNCTIONAL SYMBOL OMEGA UNDERBAR +237A ; [*0777.0020.0002] # APL FUNCTIONAL SYMBOL ALPHA +237B ; [*0778.0020.0002] # NOT CHECK MARK +237C ; [*0779.0020.0002] # RIGHT ANGLE WITH DOWNWARDS ZIGZAG ARROW +237D ; [*077A.0020.0002] # SHOULDERED OPEN BOX +237E ; [*077B.0020.0002] # BELL SYMBOL +237F ; [*077C.0020.0002] # VERTICAL LINE WITH MIDDLE DOT +2380 ; [*077D.0020.0002] # INSERTION SYMBOL +2381 ; [*077E.0020.0002] # CONTINUOUS UNDERLINE SYMBOL +2382 ; [*077F.0020.0002] # DISCONTINUOUS UNDERLINE SYMBOL +2383 ; [*0780.0020.0002] # EMPHASIS SYMBOL +2384 ; [*0781.0020.0002] # COMPOSITION SYMBOL +2385 ; [*0782.0020.0002] # WHITE SQUARE WITH CENTRE VERTICAL LINE +2386 ; [*0783.0020.0002] # ENTER SYMBOL +2387 ; [*0784.0020.0002] # ALTERNATIVE KEY SYMBOL +2388 ; [*0785.0020.0002] # HELM SYMBOL +2389 ; [*0786.0020.0002] # CIRCLED HORIZONTAL BAR WITH NOTCH +238A ; [*0787.0020.0002] # CIRCLED TRIANGLE DOWN +238B ; [*0788.0020.0002] # BROKEN CIRCLE WITH NORTHWEST ARROW +238C ; [*0789.0020.0002] # UNDO SYMBOL +238D ; [*078A.0020.0002] # MONOSTABLE SYMBOL +238E ; [*078B.0020.0002] # HYSTERESIS SYMBOL +238F ; [*078C.0020.0002] # OPEN-CIRCUIT-OUTPUT H-TYPE SYMBOL +2390 ; [*078D.0020.0002] # OPEN-CIRCUIT-OUTPUT L-TYPE SYMBOL +2391 ; [*078E.0020.0002] # PASSIVE-PULL-DOWN-OUTPUT SYMBOL +2392 ; [*078F.0020.0002] # PASSIVE-PULL-UP-OUTPUT SYMBOL +2393 ; [*0790.0020.0002] # DIRECT CURRENT SYMBOL FORM TWO +2394 ; [*0791.0020.0002] # SOFTWARE-FUNCTION SYMBOL +2395 ; [*0792.0020.0002] # APL FUNCTIONAL SYMBOL QUAD +2396 ; [*0793.0020.0002] # DECIMAL SEPARATOR KEY SYMBOL +2397 ; [*0794.0020.0002] # PREVIOUS PAGE +2398 ; [*0795.0020.0002] # NEXT PAGE +2399 ; [*0796.0020.0002] # PRINT SCREEN SYMBOL +239A ; [*0797.0020.0002] # CLEAR SCREEN SYMBOL +239B ; [*0798.0020.0002] # LEFT PARENTHESIS UPPER HOOK +239C ; [*0799.0020.0002] # LEFT PARENTHESIS EXTENSION +239D ; [*079A.0020.0002] # LEFT PARENTHESIS LOWER HOOK +239E ; [*079B.0020.0002] # RIGHT PARENTHESIS UPPER HOOK +239F ; [*079C.0020.0002] # RIGHT PARENTHESIS EXTENSION +23A0 ; [*079D.0020.0002] # RIGHT PARENTHESIS LOWER HOOK +23A1 ; [*079E.0020.0002] # LEFT SQUARE BRACKET UPPER CORNER +23A2 ; [*079F.0020.0002] # LEFT SQUARE BRACKET EXTENSION +23A3 ; [*07A0.0020.0002] # LEFT SQUARE BRACKET LOWER CORNER +23A4 ; [*07A1.0020.0002] # RIGHT SQUARE BRACKET UPPER CORNER +23A5 ; [*07A2.0020.0002] # RIGHT SQUARE BRACKET EXTENSION +23A6 ; [*07A3.0020.0002] # RIGHT SQUARE BRACKET LOWER CORNER +23A7 ; [*07A4.0020.0002] # LEFT CURLY BRACKET UPPER HOOK +23A8 ; [*07A5.0020.0002] # LEFT CURLY BRACKET MIDDLE PIECE +23A9 ; [*07A6.0020.0002] # LEFT CURLY BRACKET LOWER HOOK +23AA ; [*07A7.0020.0002] # CURLY BRACKET EXTENSION +23AB ; [*07A8.0020.0002] # RIGHT CURLY BRACKET UPPER HOOK +23AC ; [*07A9.0020.0002] # RIGHT CURLY BRACKET MIDDLE PIECE +23AD ; [*07AA.0020.0002] # RIGHT CURLY BRACKET LOWER HOOK +23AE ; [*07AB.0020.0002] # INTEGRAL EXTENSION +23AF ; [*07AC.0020.0002] # HORIZONTAL LINE EXTENSION +23B0 ; [*07AD.0020.0002] # UPPER LEFT OR LOWER RIGHT CURLY BRACKET SECTION +23B1 ; [*07AE.0020.0002] # UPPER RIGHT OR LOWER LEFT CURLY BRACKET SECTION +23B2 ; [*07AF.0020.0002] # SUMMATION TOP +23B3 ; [*07B0.0020.0002] # SUMMATION BOTTOM +23B4 ; [*07B1.0020.0002] # TOP SQUARE BRACKET +23B5 ; [*07B2.0020.0002] # BOTTOM SQUARE BRACKET +23B6 ; [*07B3.0020.0002] # BOTTOM SQUARE BRACKET OVER TOP SQUARE BRACKET +23B7 ; [*07B4.0020.0002] # RADICAL SYMBOL BOTTOM +23B8 ; [*07B5.0020.0002] # LEFT VERTICAL BOX LINE +23B9 ; [*07B6.0020.0002] # RIGHT VERTICAL BOX LINE +23BA ; [*07B7.0020.0002] # HORIZONTAL SCAN LINE-1 +23BB ; [*07B8.0020.0002] # HORIZONTAL SCAN LINE-3 +23BC ; [*07B9.0020.0002] # HORIZONTAL SCAN LINE-7 +23BD ; [*07BA.0020.0002] # HORIZONTAL SCAN LINE-9 +23BE ; [*07BB.0020.0002] # DENTISTRY SYMBOL LIGHT VERTICAL AND TOP RIGHT +23BF ; [*07BC.0020.0002] # DENTISTRY SYMBOL LIGHT VERTICAL AND BOTTOM RIGHT +23C0 ; [*07BD.0020.0002] # DENTISTRY SYMBOL LIGHT VERTICAL WITH CIRCLE +23C1 ; [*07BE.0020.0002] # DENTISTRY SYMBOL LIGHT DOWN AND HORIZONTAL WITH CIRCLE +23C2 ; [*07BF.0020.0002] # DENTISTRY SYMBOL LIGHT UP AND HORIZONTAL WITH CIRCLE +23C3 ; [*07C0.0020.0002] # DENTISTRY SYMBOL LIGHT VERTICAL WITH TRIANGLE +23C4 ; [*07C1.0020.0002] # DENTISTRY SYMBOL LIGHT DOWN AND HORIZONTAL WITH TRIANGLE +23C5 ; [*07C2.0020.0002] # DENTISTRY SYMBOL LIGHT UP AND HORIZONTAL WITH TRIANGLE +23C6 ; [*07C3.0020.0002] # DENTISTRY SYMBOL LIGHT VERTICAL AND WAVE +23C7 ; [*07C4.0020.0002] # DENTISTRY SYMBOL LIGHT DOWN AND HORIZONTAL WITH WAVE +23C8 ; [*07C5.0020.0002] # DENTISTRY SYMBOL LIGHT UP AND HORIZONTAL WITH WAVE +23C9 ; [*07C6.0020.0002] # DENTISTRY SYMBOL LIGHT DOWN AND HORIZONTAL +23CA ; [*07C7.0020.0002] # DENTISTRY SYMBOL LIGHT UP AND HORIZONTAL +23CB ; [*07C8.0020.0002] # DENTISTRY SYMBOL LIGHT VERTICAL AND TOP LEFT +23CC ; [*07C9.0020.0002] # DENTISTRY SYMBOL LIGHT VERTICAL AND BOTTOM LEFT +23CD ; [*07CA.0020.0002] # SQUARE FOOT +23CE ; [*07CB.0020.0002] # RETURN SYMBOL +23CF ; [*07CC.0020.0002] # EJECT SYMBOL +23D0 ; [*07CD.0020.0002] # VERTICAL LINE EXTENSION +23D1 ; [*07CE.0020.0002] # METRICAL BREVE +23D2 ; [*07CF.0020.0002] # METRICAL LONG OVER SHORT +23D3 ; [*07D0.0020.0002] # METRICAL SHORT OVER LONG +23D4 ; [*07D1.0020.0002] # METRICAL LONG OVER TWO SHORTS +23D5 ; [*07D2.0020.0002] # METRICAL TWO SHORTS OVER LONG +23D6 ; [*07D3.0020.0002] # METRICAL TWO SHORTS JOINED +23D7 ; [*07D4.0020.0002] # METRICAL TRISEME +23D8 ; [*07D5.0020.0002] # METRICAL TETRASEME +23D9 ; [*07D6.0020.0002] # METRICAL PENTASEME +23DA ; [*07D7.0020.0002] # EARTH GROUND +23DB ; [*07D8.0020.0002] # FUSE +23DC ; [*07D9.0020.0002] # TOP PARENTHESIS +23DD ; [*07DA.0020.0002] # BOTTOM PARENTHESIS +23DE ; [*07DB.0020.0002] # TOP CURLY BRACKET +23DF ; [*07DC.0020.0002] # BOTTOM CURLY BRACKET +23E0 ; [*07DD.0020.0002] # TOP TORTOISE SHELL BRACKET +23E1 ; [*07DE.0020.0002] # BOTTOM TORTOISE SHELL BRACKET +23E2 ; [*07DF.0020.0002] # WHITE TRAPEZIUM +23E3 ; [*07E0.0020.0002] # BENZENE RING WITH CIRCLE +23E4 ; [*07E1.0020.0002] # STRAIGHTNESS +23E5 ; [*07E2.0020.0002] # FLATNESS +23E6 ; [*07E3.0020.0002] # AC CURRENT +23E7 ; [*07E4.0020.0002] # ELECTRICAL INTERSECTION +23E8 ; [*07E5.0020.0002] # DECIMAL EXPONENT SYMBOL +23E9 ; [*07E6.0020.0002] # BLACK RIGHT-POINTING DOUBLE TRIANGLE +23EA ; [*07E7.0020.0002] # BLACK LEFT-POINTING DOUBLE TRIANGLE +23EB ; [*07E8.0020.0002] # BLACK UP-POINTING DOUBLE TRIANGLE +23EC ; [*07E9.0020.0002] # BLACK DOWN-POINTING DOUBLE TRIANGLE +23ED ; [*07EA.0020.0002] # BLACK RIGHT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR +23EE ; [*07EB.0020.0002] # BLACK LEFT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR +23EF ; [*07EC.0020.0002] # BLACK RIGHT-POINTING TRIANGLE WITH DOUBLE VERTICAL BAR +23F0 ; [*07ED.0020.0002] # ALARM CLOCK +23F1 ; [*07EE.0020.0002] # STOPWATCH +23F2 ; [*07EF.0020.0002] # TIMER CLOCK +23F3 ; [*07F0.0020.0002] # HOURGLASS WITH FLOWING SAND +23F4 ; [*07F1.0020.0002] # BLACK MEDIUM LEFT-POINTING TRIANGLE +23F5 ; [*07F2.0020.0002] # BLACK MEDIUM RIGHT-POINTING TRIANGLE +23F6 ; [*07F3.0020.0002] # BLACK MEDIUM UP-POINTING TRIANGLE +23F7 ; [*07F4.0020.0002] # BLACK MEDIUM DOWN-POINTING TRIANGLE +23F8 ; [*07F5.0020.0002] # DOUBLE VERTICAL BAR +23F9 ; [*07F6.0020.0002] # BLACK SQUARE FOR STOP +23FA ; [*07F7.0020.0002] # BLACK CIRCLE FOR RECORD +23FB ; [*07F8.0020.0002] # POWER SYMBOL +23FC ; [*07F9.0020.0002] # POWER ON-OFF SYMBOL +23FD ; [*07FA.0020.0002] # POWER ON SYMBOL +23FE ; [*07FB.0020.0002] # POWER SLEEP SYMBOL +23FF ; [*07FC.0020.0002] # OBSERVER EYE SYMBOL +2400 ; [*07FD.0020.0002] # SYMBOL FOR NULL +2401 ; [*07FE.0020.0002] # SYMBOL FOR START OF HEADING +2402 ; [*07FF.0020.0002] # SYMBOL FOR START OF TEXT +2403 ; [*0800.0020.0002] # SYMBOL FOR END OF TEXT +2404 ; [*0801.0020.0002] # SYMBOL FOR END OF TRANSMISSION +2405 ; [*0802.0020.0002] # SYMBOL FOR ENQUIRY +2406 ; [*0803.0020.0002] # SYMBOL FOR ACKNOWLEDGE +2407 ; [*0804.0020.0002] # SYMBOL FOR BELL +2408 ; [*0805.0020.0002] # SYMBOL FOR BACKSPACE +2409 ; [*0806.0020.0002] # SYMBOL FOR HORIZONTAL TABULATION +240A ; [*0807.0020.0002] # SYMBOL FOR LINE FEED +240B ; [*0808.0020.0002] # SYMBOL FOR VERTICAL TABULATION +240C ; [*0809.0020.0002] # SYMBOL FOR FORM FEED +240D ; [*080A.0020.0002] # SYMBOL FOR CARRIAGE RETURN +240E ; [*080B.0020.0002] # SYMBOL FOR SHIFT OUT +240F ; [*080C.0020.0002] # SYMBOL FOR SHIFT IN +2410 ; [*080D.0020.0002] # SYMBOL FOR DATA LINK ESCAPE +2411 ; [*080E.0020.0002] # SYMBOL FOR DEVICE CONTROL ONE +2412 ; [*080F.0020.0002] # SYMBOL FOR DEVICE CONTROL TWO +2413 ; [*0810.0020.0002] # SYMBOL FOR DEVICE CONTROL THREE +2414 ; [*0811.0020.0002] # SYMBOL FOR DEVICE CONTROL FOUR +2415 ; [*0812.0020.0002] # SYMBOL FOR NEGATIVE ACKNOWLEDGE +2416 ; [*0813.0020.0002] # SYMBOL FOR SYNCHRONOUS IDLE +2417 ; [*0814.0020.0002] # SYMBOL FOR END OF TRANSMISSION BLOCK +2418 ; [*0815.0020.0002] # SYMBOL FOR CANCEL +2419 ; [*0816.0020.0002] # SYMBOL FOR END OF MEDIUM +241A ; [*0817.0020.0002] # SYMBOL FOR SUBSTITUTE +241B ; [*0818.0020.0002] # SYMBOL FOR ESCAPE +241C ; [*0819.0020.0002] # SYMBOL FOR FILE SEPARATOR +241D ; [*081A.0020.0002] # SYMBOL FOR GROUP SEPARATOR +241E ; [*081B.0020.0002] # SYMBOL FOR RECORD SEPARATOR +241F ; [*081C.0020.0002] # SYMBOL FOR UNIT SEPARATOR +2420 ; [*081D.0020.0002] # SYMBOL FOR SPACE +2421 ; [*081E.0020.0002] # SYMBOL FOR DELETE +2422 ; [*081F.0020.0002] # BLANK SYMBOL +2423 ; [*0820.0020.0002] # OPEN BOX +2424 ; [*0821.0020.0002] # SYMBOL FOR NEWLINE +2425 ; [*0822.0020.0002] # SYMBOL FOR DELETE FORM TWO +2426 ; [*0823.0020.0002] # SYMBOL FOR SUBSTITUTE FORM TWO +2440 ; [*0824.0020.0002] # OCR HOOK +2441 ; [*0825.0020.0002] # OCR CHAIR +2442 ; [*0826.0020.0002] # OCR FORK +2443 ; [*0827.0020.0002] # OCR INVERTED FORK +2444 ; [*0828.0020.0002] # OCR BELT BUCKLE +2445 ; [*0829.0020.0002] # OCR BOW TIE +2446 ; [*082A.0020.0002] # OCR BRANCH BANK IDENTIFICATION +2447 ; [*082B.0020.0002] # OCR AMOUNT OF CHECK +2448 ; [*082C.0020.0002] # OCR DASH +2449 ; [*082D.0020.0002] # OCR CUSTOMER ACCOUNT NUMBER +244A ; [*082E.0020.0002] # OCR DOUBLE BACKSLASH +2500 ; [*082F.0020.0002] # BOX DRAWINGS LIGHT HORIZONTAL +2501 ; [*0830.0020.0002] # BOX DRAWINGS HEAVY HORIZONTAL +2502 ; [*0831.0020.0002] # BOX DRAWINGS LIGHT VERTICAL +2503 ; [*0832.0020.0002] # BOX DRAWINGS HEAVY VERTICAL +2504 ; [*0833.0020.0002] # BOX DRAWINGS LIGHT TRIPLE DASH HORIZONTAL +2505 ; [*0834.0020.0002] # BOX DRAWINGS HEAVY TRIPLE DASH HORIZONTAL +2506 ; [*0835.0020.0002] # BOX DRAWINGS LIGHT TRIPLE DASH VERTICAL +2507 ; [*0836.0020.0002] # BOX DRAWINGS HEAVY TRIPLE DASH VERTICAL +2508 ; [*0837.0020.0002] # BOX DRAWINGS LIGHT QUADRUPLE DASH HORIZONTAL +2509 ; [*0838.0020.0002] # BOX DRAWINGS HEAVY QUADRUPLE DASH HORIZONTAL +250A ; [*0839.0020.0002] # BOX DRAWINGS LIGHT QUADRUPLE DASH VERTICAL +250B ; [*083A.0020.0002] # BOX DRAWINGS HEAVY QUADRUPLE DASH VERTICAL +250C ; [*083B.0020.0002] # BOX DRAWINGS LIGHT DOWN AND RIGHT +250D ; [*083C.0020.0002] # BOX DRAWINGS DOWN LIGHT AND RIGHT HEAVY +250E ; [*083D.0020.0002] # BOX DRAWINGS DOWN HEAVY AND RIGHT LIGHT +250F ; [*083E.0020.0002] # BOX DRAWINGS HEAVY DOWN AND RIGHT +2510 ; [*083F.0020.0002] # BOX DRAWINGS LIGHT DOWN AND LEFT +2511 ; [*0840.0020.0002] # BOX DRAWINGS DOWN LIGHT AND LEFT HEAVY +2512 ; [*0841.0020.0002] # BOX DRAWINGS DOWN HEAVY AND LEFT LIGHT +2513 ; [*0842.0020.0002] # BOX DRAWINGS HEAVY DOWN AND LEFT +2514 ; [*0843.0020.0002] # BOX DRAWINGS LIGHT UP AND RIGHT +2515 ; [*0844.0020.0002] # BOX DRAWINGS UP LIGHT AND RIGHT HEAVY +2516 ; [*0845.0020.0002] # BOX DRAWINGS UP HEAVY AND RIGHT LIGHT +2517 ; [*0846.0020.0002] # BOX DRAWINGS HEAVY UP AND RIGHT +2518 ; [*0847.0020.0002] # BOX DRAWINGS LIGHT UP AND LEFT +2519 ; [*0848.0020.0002] # BOX DRAWINGS UP LIGHT AND LEFT HEAVY +251A ; [*0849.0020.0002] # BOX DRAWINGS UP HEAVY AND LEFT LIGHT +251B ; [*084A.0020.0002] # BOX DRAWINGS HEAVY UP AND LEFT +251C ; [*084B.0020.0002] # BOX DRAWINGS LIGHT VERTICAL AND RIGHT +251D ; [*084C.0020.0002] # BOX DRAWINGS VERTICAL LIGHT AND RIGHT HEAVY +251E ; [*084D.0020.0002] # BOX DRAWINGS UP HEAVY AND RIGHT DOWN LIGHT +251F ; [*084E.0020.0002] # BOX DRAWINGS DOWN HEAVY AND RIGHT UP LIGHT +2520 ; [*084F.0020.0002] # BOX DRAWINGS VERTICAL HEAVY AND RIGHT LIGHT +2521 ; [*0850.0020.0002] # BOX DRAWINGS DOWN LIGHT AND RIGHT UP HEAVY +2522 ; [*0851.0020.0002] # BOX DRAWINGS UP LIGHT AND RIGHT DOWN HEAVY +2523 ; [*0852.0020.0002] # BOX DRAWINGS HEAVY VERTICAL AND RIGHT +2524 ; [*0853.0020.0002] # BOX DRAWINGS LIGHT VERTICAL AND LEFT +2525 ; [*0854.0020.0002] # BOX DRAWINGS VERTICAL LIGHT AND LEFT HEAVY +2526 ; [*0855.0020.0002] # BOX DRAWINGS UP HEAVY AND LEFT DOWN LIGHT +2527 ; [*0856.0020.0002] # BOX DRAWINGS DOWN HEAVY AND LEFT UP LIGHT +2528 ; [*0857.0020.0002] # BOX DRAWINGS VERTICAL HEAVY AND LEFT LIGHT +2529 ; [*0858.0020.0002] # BOX DRAWINGS DOWN LIGHT AND LEFT UP HEAVY +252A ; [*0859.0020.0002] # BOX DRAWINGS UP LIGHT AND LEFT DOWN HEAVY +252B ; [*085A.0020.0002] # BOX DRAWINGS HEAVY VERTICAL AND LEFT +252C ; [*085B.0020.0002] # BOX DRAWINGS LIGHT DOWN AND HORIZONTAL +252D ; [*085C.0020.0002] # BOX DRAWINGS LEFT HEAVY AND RIGHT DOWN LIGHT +252E ; [*085D.0020.0002] # BOX DRAWINGS RIGHT HEAVY AND LEFT DOWN LIGHT +252F ; [*085E.0020.0002] # BOX DRAWINGS DOWN LIGHT AND HORIZONTAL HEAVY +2530 ; [*085F.0020.0002] # BOX DRAWINGS DOWN HEAVY AND HORIZONTAL LIGHT +2531 ; [*0860.0020.0002] # BOX DRAWINGS RIGHT LIGHT AND LEFT DOWN HEAVY +2532 ; [*0861.0020.0002] # BOX DRAWINGS LEFT LIGHT AND RIGHT DOWN HEAVY +2533 ; [*0862.0020.0002] # BOX DRAWINGS HEAVY DOWN AND HORIZONTAL +2534 ; [*0863.0020.0002] # BOX DRAWINGS LIGHT UP AND HORIZONTAL +2535 ; [*0864.0020.0002] # BOX DRAWINGS LEFT HEAVY AND RIGHT UP LIGHT +2536 ; [*0865.0020.0002] # BOX DRAWINGS RIGHT HEAVY AND LEFT UP LIGHT +2537 ; [*0866.0020.0002] # BOX DRAWINGS UP LIGHT AND HORIZONTAL HEAVY +2538 ; [*0867.0020.0002] # BOX DRAWINGS UP HEAVY AND HORIZONTAL LIGHT +2539 ; [*0868.0020.0002] # BOX DRAWINGS RIGHT LIGHT AND LEFT UP HEAVY +253A ; [*0869.0020.0002] # BOX DRAWINGS LEFT LIGHT AND RIGHT UP HEAVY +253B ; [*086A.0020.0002] # BOX DRAWINGS HEAVY UP AND HORIZONTAL +253C ; [*086B.0020.0002] # BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL +253D ; [*086C.0020.0002] # BOX DRAWINGS LEFT HEAVY AND RIGHT VERTICAL LIGHT +253E ; [*086D.0020.0002] # BOX DRAWINGS RIGHT HEAVY AND LEFT VERTICAL LIGHT +253F ; [*086E.0020.0002] # BOX DRAWINGS VERTICAL LIGHT AND HORIZONTAL HEAVY +2540 ; [*086F.0020.0002] # BOX DRAWINGS UP HEAVY AND DOWN HORIZONTAL LIGHT +2541 ; [*0870.0020.0002] # BOX DRAWINGS DOWN HEAVY AND UP HORIZONTAL LIGHT +2542 ; [*0871.0020.0002] # BOX DRAWINGS VERTICAL HEAVY AND HORIZONTAL LIGHT +2543 ; [*0872.0020.0002] # BOX DRAWINGS LEFT UP HEAVY AND RIGHT DOWN LIGHT +2544 ; [*0873.0020.0002] # BOX DRAWINGS RIGHT UP HEAVY AND LEFT DOWN LIGHT +2545 ; [*0874.0020.0002] # BOX DRAWINGS LEFT DOWN HEAVY AND RIGHT UP LIGHT +2546 ; [*0875.0020.0002] # BOX DRAWINGS RIGHT DOWN HEAVY AND LEFT UP LIGHT +2547 ; [*0876.0020.0002] # BOX DRAWINGS DOWN LIGHT AND UP HORIZONTAL HEAVY +2548 ; [*0877.0020.0002] # BOX DRAWINGS UP LIGHT AND DOWN HORIZONTAL HEAVY +2549 ; [*0878.0020.0002] # BOX DRAWINGS RIGHT LIGHT AND LEFT VERTICAL HEAVY +254A ; [*0879.0020.0002] # BOX DRAWINGS LEFT LIGHT AND RIGHT VERTICAL HEAVY +254B ; [*087A.0020.0002] # BOX DRAWINGS HEAVY VERTICAL AND HORIZONTAL +254C ; [*087B.0020.0002] # BOX DRAWINGS LIGHT DOUBLE DASH HORIZONTAL +254D ; [*087C.0020.0002] # BOX DRAWINGS HEAVY DOUBLE DASH HORIZONTAL +254E ; [*087D.0020.0002] # BOX DRAWINGS LIGHT DOUBLE DASH VERTICAL +254F ; [*087E.0020.0002] # BOX DRAWINGS HEAVY DOUBLE DASH VERTICAL +2550 ; [*087F.0020.0002] # BOX DRAWINGS DOUBLE HORIZONTAL +2551 ; [*0880.0020.0002] # BOX DRAWINGS DOUBLE VERTICAL +2552 ; [*0881.0020.0002] # BOX DRAWINGS DOWN SINGLE AND RIGHT DOUBLE +2553 ; [*0882.0020.0002] # BOX DRAWINGS DOWN DOUBLE AND RIGHT SINGLE +2554 ; [*0883.0020.0002] # BOX DRAWINGS DOUBLE DOWN AND RIGHT +2555 ; [*0884.0020.0002] # BOX DRAWINGS DOWN SINGLE AND LEFT DOUBLE +2556 ; [*0885.0020.0002] # BOX DRAWINGS DOWN DOUBLE AND LEFT SINGLE +2557 ; [*0886.0020.0002] # BOX DRAWINGS DOUBLE DOWN AND LEFT +2558 ; [*0887.0020.0002] # BOX DRAWINGS UP SINGLE AND RIGHT DOUBLE +2559 ; [*0888.0020.0002] # BOX DRAWINGS UP DOUBLE AND RIGHT SINGLE +255A ; [*0889.0020.0002] # BOX DRAWINGS DOUBLE UP AND RIGHT +255B ; [*088A.0020.0002] # BOX DRAWINGS UP SINGLE AND LEFT DOUBLE +255C ; [*088B.0020.0002] # BOX DRAWINGS UP DOUBLE AND LEFT SINGLE +255D ; [*088C.0020.0002] # BOX DRAWINGS DOUBLE UP AND LEFT +255E ; [*088D.0020.0002] # BOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLE +255F ; [*088E.0020.0002] # BOX DRAWINGS VERTICAL DOUBLE AND RIGHT SINGLE +2560 ; [*088F.0020.0002] # BOX DRAWINGS DOUBLE VERTICAL AND RIGHT +2561 ; [*0890.0020.0002] # BOX DRAWINGS VERTICAL SINGLE AND LEFT DOUBLE +2562 ; [*0891.0020.0002] # BOX DRAWINGS VERTICAL DOUBLE AND LEFT SINGLE +2563 ; [*0892.0020.0002] # BOX DRAWINGS DOUBLE VERTICAL AND LEFT +2564 ; [*0893.0020.0002] # BOX DRAWINGS DOWN SINGLE AND HORIZONTAL DOUBLE +2565 ; [*0894.0020.0002] # BOX DRAWINGS DOWN DOUBLE AND HORIZONTAL SINGLE +2566 ; [*0895.0020.0002] # BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL +2567 ; [*0896.0020.0002] # BOX DRAWINGS UP SINGLE AND HORIZONTAL DOUBLE +2568 ; [*0897.0020.0002] # BOX DRAWINGS UP DOUBLE AND HORIZONTAL SINGLE +2569 ; [*0898.0020.0002] # BOX DRAWINGS DOUBLE UP AND HORIZONTAL +256A ; [*0899.0020.0002] # BOX DRAWINGS VERTICAL SINGLE AND HORIZONTAL DOUBLE +256B ; [*089A.0020.0002] # BOX DRAWINGS VERTICAL DOUBLE AND HORIZONTAL SINGLE +256C ; [*089B.0020.0002] # BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL +256D ; [*089C.0020.0002] # BOX DRAWINGS LIGHT ARC DOWN AND RIGHT +256E ; [*089D.0020.0002] # BOX DRAWINGS LIGHT ARC DOWN AND LEFT +256F ; [*089E.0020.0002] # BOX DRAWINGS LIGHT ARC UP AND LEFT +2570 ; [*089F.0020.0002] # BOX DRAWINGS LIGHT ARC UP AND RIGHT +2571 ; [*08A0.0020.0002] # BOX DRAWINGS LIGHT DIAGONAL UPPER RIGHT TO LOWER LEFT +2572 ; [*08A1.0020.0002] # BOX DRAWINGS LIGHT DIAGONAL UPPER LEFT TO LOWER RIGHT +2573 ; [*08A2.0020.0002] # BOX DRAWINGS LIGHT DIAGONAL CROSS +2574 ; [*08A3.0020.0002] # BOX DRAWINGS LIGHT LEFT +2575 ; [*08A4.0020.0002] # BOX DRAWINGS LIGHT UP +2576 ; [*08A5.0020.0002] # BOX DRAWINGS LIGHT RIGHT +2577 ; [*08A6.0020.0002] # BOX DRAWINGS LIGHT DOWN +2578 ; [*08A7.0020.0002] # BOX DRAWINGS HEAVY LEFT +2579 ; [*08A8.0020.0002] # BOX DRAWINGS HEAVY UP +257A ; [*08A9.0020.0002] # BOX DRAWINGS HEAVY RIGHT +257B ; [*08AA.0020.0002] # BOX DRAWINGS HEAVY DOWN +257C ; [*08AB.0020.0002] # BOX DRAWINGS LIGHT LEFT AND HEAVY RIGHT +257D ; [*08AC.0020.0002] # BOX DRAWINGS LIGHT UP AND HEAVY DOWN +257E ; [*08AD.0020.0002] # BOX DRAWINGS HEAVY LEFT AND LIGHT RIGHT +257F ; [*08AE.0020.0002] # BOX DRAWINGS HEAVY UP AND LIGHT DOWN +2580 ; [*08AF.0020.0002] # UPPER HALF BLOCK +2581 ; [*08B0.0020.0002] # LOWER ONE EIGHTH BLOCK +2582 ; [*08B1.0020.0002] # LOWER ONE QUARTER BLOCK +2583 ; [*08B2.0020.0002] # LOWER THREE EIGHTHS BLOCK +2584 ; [*08B3.0020.0002] # LOWER HALF BLOCK +2585 ; [*08B4.0020.0002] # LOWER FIVE EIGHTHS BLOCK +2586 ; [*08B5.0020.0002] # LOWER THREE QUARTERS BLOCK +2587 ; [*08B6.0020.0002] # LOWER SEVEN EIGHTHS BLOCK +2588 ; [*08B7.0020.0002] # FULL BLOCK +2589 ; [*08B8.0020.0002] # LEFT SEVEN EIGHTHS BLOCK +258A ; [*08B9.0020.0002] # LEFT THREE QUARTERS BLOCK +258B ; [*08BA.0020.0002] # LEFT FIVE EIGHTHS BLOCK +258C ; [*08BB.0020.0002] # LEFT HALF BLOCK +258D ; [*08BC.0020.0002] # LEFT THREE EIGHTHS BLOCK +258E ; [*08BD.0020.0002] # LEFT ONE QUARTER BLOCK +258F ; [*08BE.0020.0002] # LEFT ONE EIGHTH BLOCK +2590 ; [*08BF.0020.0002] # RIGHT HALF BLOCK +2591 ; [*08C0.0020.0002] # LIGHT SHADE +2592 ; [*08C1.0020.0002] # MEDIUM SHADE +2593 ; [*08C2.0020.0002] # DARK SHADE +2594 ; [*08C3.0020.0002] # UPPER ONE EIGHTH BLOCK +2595 ; [*08C4.0020.0002] # RIGHT ONE EIGHTH BLOCK +2596 ; [*08C5.0020.0002] # QUADRANT LOWER LEFT +2597 ; [*08C6.0020.0002] # QUADRANT LOWER RIGHT +2598 ; [*08C7.0020.0002] # QUADRANT UPPER LEFT +2599 ; [*08C8.0020.0002] # QUADRANT UPPER LEFT AND LOWER LEFT AND LOWER RIGHT +259A ; [*08C9.0020.0002] # QUADRANT UPPER LEFT AND LOWER RIGHT +259B ; [*08CA.0020.0002] # QUADRANT UPPER LEFT AND UPPER RIGHT AND LOWER LEFT +259C ; [*08CB.0020.0002] # QUADRANT UPPER LEFT AND UPPER RIGHT AND LOWER RIGHT +259D ; [*08CC.0020.0002] # QUADRANT UPPER RIGHT +259E ; [*08CD.0020.0002] # QUADRANT UPPER RIGHT AND LOWER LEFT +259F ; [*08CE.0020.0002] # QUADRANT UPPER RIGHT AND LOWER LEFT AND LOWER RIGHT +25A0 ; [*08CF.0020.0002] # BLACK SQUARE +25A1 ; [*08D0.0020.0002] # WHITE SQUARE +25A2 ; [*08D1.0020.0002] # WHITE SQUARE WITH ROUNDED CORNERS +25A3 ; [*08D2.0020.0002] # WHITE SQUARE CONTAINING BLACK SMALL SQUARE +25A4 ; [*08D3.0020.0002] # SQUARE WITH HORIZONTAL FILL +25A5 ; [*08D4.0020.0002] # SQUARE WITH VERTICAL FILL +25A6 ; [*08D5.0020.0002] # SQUARE WITH ORTHOGONAL CROSSHATCH FILL +25A7 ; [*08D6.0020.0002] # SQUARE WITH UPPER LEFT TO LOWER RIGHT FILL +25A8 ; [*08D7.0020.0002] # SQUARE WITH UPPER RIGHT TO LOWER LEFT FILL +25A9 ; [*08D8.0020.0002] # SQUARE WITH DIAGONAL CROSSHATCH FILL +25AA ; [*08D9.0020.0002] # BLACK SMALL SQUARE +25AB ; [*08DA.0020.0002] # WHITE SMALL SQUARE +25AC ; [*08DB.0020.0002] # BLACK RECTANGLE +25AD ; [*08DC.0020.0002] # WHITE RECTANGLE +25AE ; [*08DD.0020.0002] # BLACK VERTICAL RECTANGLE +25AF ; [*08DE.0020.0002] # WHITE VERTICAL RECTANGLE +25B0 ; [*08DF.0020.0002] # BLACK PARALLELOGRAM +25B1 ; [*08E0.0020.0002] # WHITE PARALLELOGRAM +25B2 ; [*08E1.0020.0002] # BLACK UP-POINTING TRIANGLE +25B3 ; [*08E2.0020.0002] # WHITE UP-POINTING TRIANGLE +25B4 ; [*08E3.0020.0002] # BLACK UP-POINTING SMALL TRIANGLE +25B5 ; [*08E4.0020.0002] # WHITE UP-POINTING SMALL TRIANGLE +25B6 ; [*08E5.0020.0002] # BLACK RIGHT-POINTING TRIANGLE +25B7 ; [*08E6.0020.0002] # WHITE RIGHT-POINTING TRIANGLE +25B8 ; [*08E7.0020.0002] # BLACK RIGHT-POINTING SMALL TRIANGLE +25B9 ; [*08E8.0020.0002] # WHITE RIGHT-POINTING SMALL TRIANGLE +25BA ; [*08E9.0020.0002] # BLACK RIGHT-POINTING POINTER +25BB ; [*08EA.0020.0002] # WHITE RIGHT-POINTING POINTER +25BC ; [*08EB.0020.0002] # BLACK DOWN-POINTING TRIANGLE +25BD ; [*08EC.0020.0002] # WHITE DOWN-POINTING TRIANGLE +25BE ; [*08ED.0020.0002] # BLACK DOWN-POINTING SMALL TRIANGLE +25BF ; [*08EE.0020.0002] # WHITE DOWN-POINTING SMALL TRIANGLE +25C0 ; [*08EF.0020.0002] # BLACK LEFT-POINTING TRIANGLE +25C1 ; [*08F0.0020.0002] # WHITE LEFT-POINTING TRIANGLE +25C2 ; [*08F1.0020.0002] # BLACK LEFT-POINTING SMALL TRIANGLE +25C3 ; [*08F2.0020.0002] # WHITE LEFT-POINTING SMALL TRIANGLE +25C4 ; [*08F3.0020.0002] # BLACK LEFT-POINTING POINTER +25C5 ; [*08F4.0020.0002] # WHITE LEFT-POINTING POINTER +25C6 ; [*08F5.0020.0002] # BLACK DIAMOND +25C7 ; [*08F6.0020.0002] # WHITE DIAMOND +25C8 ; [*08F7.0020.0002] # WHITE DIAMOND CONTAINING BLACK SMALL DIAMOND +25C9 ; [*08F8.0020.0002] # FISHEYE +25CA ; [*08F9.0020.0002] # LOZENGE +25CB ; [*08FA.0020.0002] # WHITE CIRCLE +25CC ; [*08FB.0020.0002] # DOTTED CIRCLE +25CD ; [*08FC.0020.0002] # CIRCLE WITH VERTICAL FILL +25CE ; [*08FD.0020.0002] # BULLSEYE +25CF ; [*08FE.0020.0002] # BLACK CIRCLE +25D0 ; [*08FF.0020.0002] # CIRCLE WITH LEFT HALF BLACK +25D1 ; [*0900.0020.0002] # CIRCLE WITH RIGHT HALF BLACK +25D2 ; [*0901.0020.0002] # CIRCLE WITH LOWER HALF BLACK +25D3 ; [*0902.0020.0002] # CIRCLE WITH UPPER HALF BLACK +25D4 ; [*0903.0020.0002] # CIRCLE WITH UPPER RIGHT QUADRANT BLACK +25D5 ; [*0904.0020.0002] # CIRCLE WITH ALL BUT UPPER LEFT QUADRANT BLACK +25D6 ; [*0905.0020.0002] # LEFT HALF BLACK CIRCLE +25D7 ; [*0906.0020.0002] # RIGHT HALF BLACK CIRCLE +25D8 ; [*0907.0020.0002] # INVERSE BULLET +25D9 ; [*0908.0020.0002] # INVERSE WHITE CIRCLE +25DA ; [*0909.0020.0002] # UPPER HALF INVERSE WHITE CIRCLE +25DB ; [*090A.0020.0002] # LOWER HALF INVERSE WHITE CIRCLE +25DC ; [*090B.0020.0002] # UPPER LEFT QUADRANT CIRCULAR ARC +25DD ; [*090C.0020.0002] # UPPER RIGHT QUADRANT CIRCULAR ARC +25DE ; [*090D.0020.0002] # LOWER RIGHT QUADRANT CIRCULAR ARC +25DF ; [*090E.0020.0002] # LOWER LEFT QUADRANT CIRCULAR ARC +25E0 ; [*090F.0020.0002] # UPPER HALF CIRCLE +25E1 ; [*0910.0020.0002] # LOWER HALF CIRCLE +25E2 ; [*0911.0020.0002] # BLACK LOWER RIGHT TRIANGLE +25E3 ; [*0912.0020.0002] # BLACK LOWER LEFT TRIANGLE +25E4 ; [*0913.0020.0002] # BLACK UPPER LEFT TRIANGLE +25E5 ; [*0914.0020.0002] # BLACK UPPER RIGHT TRIANGLE +25E6 ; [*0915.0020.0002] # WHITE BULLET +25E7 ; [*0916.0020.0002] # SQUARE WITH LEFT HALF BLACK +25E8 ; [*0917.0020.0002] # SQUARE WITH RIGHT HALF BLACK +25E9 ; [*0918.0020.0002] # SQUARE WITH UPPER LEFT DIAGONAL HALF BLACK +25EA ; [*0919.0020.0002] # SQUARE WITH LOWER RIGHT DIAGONAL HALF BLACK +25EB ; [*091A.0020.0002] # WHITE SQUARE WITH VERTICAL BISECTING LINE +25EC ; [*091B.0020.0002] # WHITE UP-POINTING TRIANGLE WITH DOT +25ED ; [*091C.0020.0002] # UP-POINTING TRIANGLE WITH LEFT HALF BLACK +25EE ; [*091D.0020.0002] # UP-POINTING TRIANGLE WITH RIGHT HALF BLACK +25EF ; [*091E.0020.0002] # LARGE CIRCLE +25F0 ; [*091F.0020.0002] # WHITE SQUARE WITH UPPER LEFT QUADRANT +25F1 ; [*0920.0020.0002] # WHITE SQUARE WITH LOWER LEFT QUADRANT +25F2 ; [*0921.0020.0002] # WHITE SQUARE WITH LOWER RIGHT QUADRANT +25F3 ; [*0922.0020.0002] # WHITE SQUARE WITH UPPER RIGHT QUADRANT +25F4 ; [*0923.0020.0002] # WHITE CIRCLE WITH UPPER LEFT QUADRANT +25F5 ; [*0924.0020.0002] # WHITE CIRCLE WITH LOWER LEFT QUADRANT +25F6 ; [*0925.0020.0002] # WHITE CIRCLE WITH LOWER RIGHT QUADRANT +25F7 ; [*0926.0020.0002] # WHITE CIRCLE WITH UPPER RIGHT QUADRANT +25F8 ; [*0927.0020.0002] # UPPER LEFT TRIANGLE +25F9 ; [*0928.0020.0002] # UPPER RIGHT TRIANGLE +25FA ; [*0929.0020.0002] # LOWER LEFT TRIANGLE +25FB ; [*092A.0020.0002] # WHITE MEDIUM SQUARE +25FC ; [*092B.0020.0002] # BLACK MEDIUM SQUARE +25FD ; [*092C.0020.0002] # WHITE MEDIUM SMALL SQUARE +25FE ; [*092D.0020.0002] # BLACK MEDIUM SMALL SQUARE +25FF ; [*092E.0020.0002] # LOWER RIGHT TRIANGLE +2600 ; [*092F.0020.0002] # BLACK SUN WITH RAYS +2601 ; [*0930.0020.0002] # CLOUD +2602 ; [*0931.0020.0002] # UMBRELLA +2603 ; [*0932.0020.0002] # SNOWMAN +2604 ; [*0933.0020.0002] # COMET +2605 ; [*0934.0020.0002] # BLACK STAR +2606 ; [*0935.0020.0002] # WHITE STAR +2607 ; [*0936.0020.0002] # LIGHTNING +2608 ; [*0937.0020.0002] # THUNDERSTORM +2609 ; [*0938.0020.0002] # SUN +260A ; [*0939.0020.0002] # ASCENDING NODE +260B ; [*093A.0020.0002] # DESCENDING NODE +260C ; [*093B.0020.0002] # CONJUNCTION +260D ; [*093C.0020.0002] # OPPOSITION +260E ; [*093D.0020.0002] # BLACK TELEPHONE +260F ; [*093E.0020.0002] # WHITE TELEPHONE +2610 ; [*093F.0020.0002] # BALLOT BOX +2611 ; [*0940.0020.0002] # BALLOT BOX WITH CHECK +2612 ; [*0941.0020.0002] # BALLOT BOX WITH X +2613 ; [*0942.0020.0002] # SALTIRE +2614 ; [*0943.0020.0002] # UMBRELLA WITH RAIN DROPS +2615 ; [*0944.0020.0002] # HOT BEVERAGE +2616 ; [*0945.0020.0002] # WHITE SHOGI PIECE +2617 ; [*0946.0020.0002] # BLACK SHOGI PIECE +2618 ; [*0947.0020.0002] # SHAMROCK +2619 ; [*0948.0020.0002] # REVERSED ROTATED FLORAL HEART BULLET +261A ; [*0949.0020.0002] # BLACK LEFT POINTING INDEX +261B ; [*094A.0020.0002] # BLACK RIGHT POINTING INDEX +261C ; [*094B.0020.0002] # WHITE LEFT POINTING INDEX +261D ; [*094C.0020.0002] # WHITE UP POINTING INDEX +261E ; [*094D.0020.0002] # WHITE RIGHT POINTING INDEX +261F ; [*094E.0020.0002] # WHITE DOWN POINTING INDEX +2620 ; [*094F.0020.0002] # SKULL AND CROSSBONES +2621 ; [*0950.0020.0002] # CAUTION SIGN +2622 ; [*0951.0020.0002] # RADIOACTIVE SIGN +2623 ; [*0952.0020.0002] # BIOHAZARD SIGN +2624 ; [*0953.0020.0002] # CADUCEUS +2625 ; [*0954.0020.0002] # ANKH +2626 ; [*0955.0020.0002] # ORTHODOX CROSS +2627 ; [*0956.0020.0002] # CHI RHO +2628 ; [*0957.0020.0002] # CROSS OF LORRAINE +2629 ; [*0958.0020.0002] # CROSS OF JERUSALEM +262A ; [*0959.0020.0002] # STAR AND CRESCENT +262B ; [*095A.0020.0002] # FARSI SYMBOL +262C ; [*095B.0020.0002] # ADI SHAKTI +262D ; [*095C.0020.0002] # HAMMER AND SICKLE +262E ; [*095D.0020.0002] # PEACE SYMBOL +262F ; [*095E.0020.0002] # YIN YANG +2630 ; [*0EBA.0020.0002] # TRIGRAM FOR HEAVEN +2631 ; [*0EBB.0020.0002] # TRIGRAM FOR LAKE +2632 ; [*0EBC.0020.0002] # TRIGRAM FOR FIRE +2633 ; [*0EBD.0020.0002] # TRIGRAM FOR THUNDER +2634 ; [*0EBE.0020.0002] # TRIGRAM FOR WIND +2635 ; [*0EBF.0020.0002] # TRIGRAM FOR WATER +2636 ; [*0EC0.0020.0002] # TRIGRAM FOR MOUNTAIN +2637 ; [*0EC1.0020.0002] # TRIGRAM FOR EARTH +2638 ; [*095F.0020.0002] # WHEEL OF DHARMA +2639 ; [*0960.0020.0002] # WHITE FROWNING FACE +263A ; [*0961.0020.0002] # WHITE SMILING FACE +263B ; [*0962.0020.0002] # BLACK SMILING FACE +263C ; [*0963.0020.0002] # WHITE SUN WITH RAYS +263D ; [*0964.0020.0002] # FIRST QUARTER MOON +263E ; [*0965.0020.0002] # LAST QUARTER MOON +263F ; [*0966.0020.0002] # MERCURY +2640 ; [*0967.0020.0002] # FEMALE SIGN +2641 ; [*0968.0020.0002] # EARTH +2642 ; [*0969.0020.0002] # MALE SIGN +2643 ; [*096A.0020.0002] # JUPITER +2644 ; [*096B.0020.0002] # SATURN +2645 ; [*096C.0020.0002] # URANUS +2646 ; [*096D.0020.0002] # NEPTUNE +2647 ; [*096E.0020.0002] # PLUTO +2648 ; [*096F.0020.0002] # ARIES +2649 ; [*0970.0020.0002] # TAURUS +264A ; [*0971.0020.0002] # GEMINI +264B ; [*0972.0020.0002] # CANCER +264C ; [*0973.0020.0002] # LEO +264D ; [*0974.0020.0002] # VIRGO +264E ; [*0975.0020.0002] # LIBRA +264F ; [*0976.0020.0002] # SCORPIUS +2650 ; [*0977.0020.0002] # SAGITTARIUS +2651 ; [*0978.0020.0002] # CAPRICORN +2652 ; [*0979.0020.0002] # AQUARIUS +2653 ; [*097A.0020.0002] # PISCES +2654 ; [*097B.0020.0002] # WHITE CHESS KING +2655 ; [*097C.0020.0002] # WHITE CHESS QUEEN +2656 ; [*097D.0020.0002] # WHITE CHESS ROOK +2657 ; [*097E.0020.0002] # WHITE CHESS BISHOP +2658 ; [*097F.0020.0002] # WHITE CHESS KNIGHT +2659 ; [*0980.0020.0002] # WHITE CHESS PAWN +265A ; [*0981.0020.0002] # BLACK CHESS KING +265B ; [*0982.0020.0002] # BLACK CHESS QUEEN +265C ; [*0983.0020.0002] # BLACK CHESS ROOK +265D ; [*0984.0020.0002] # BLACK CHESS BISHOP +265E ; [*0985.0020.0002] # BLACK CHESS KNIGHT +265F ; [*0986.0020.0002] # BLACK CHESS PAWN +2660 ; [*0987.0020.0002] # BLACK SPADE SUIT +2661 ; [*0988.0020.0002] # WHITE HEART SUIT +2662 ; [*0989.0020.0002] # WHITE DIAMOND SUIT +2663 ; [*098A.0020.0002] # BLACK CLUB SUIT +2664 ; [*098B.0020.0002] # WHITE SPADE SUIT +2665 ; [*098C.0020.0002] # BLACK HEART SUIT +2666 ; [*098D.0020.0002] # BLACK DIAMOND SUIT +2667 ; [*098E.0020.0002] # WHITE CLUB SUIT +2668 ; [*098F.0020.0002] # HOT SPRINGS +2669 ; [*0990.0020.0002] # QUARTER NOTE +266A ; [*0991.0020.0002] # EIGHTH NOTE +266B ; [*0992.0020.0002] # BEAMED EIGHTH NOTES +266C ; [*0993.0020.0002] # BEAMED SIXTEENTH NOTES +266D ; [*110B.0020.0002] # MUSIC FLAT SIGN +266E ; [*110C.0020.0002] # MUSIC NATURAL SIGN +266F ; [*110D.0020.0002] # MUSIC SHARP SIGN +2670 ; [*0994.0020.0002] # WEST SYRIAC CROSS +2671 ; [*0995.0020.0002] # EAST SYRIAC CROSS +2672 ; [*0996.0020.0002] # UNIVERSAL RECYCLING SYMBOL +2673 ; [*0997.0020.0002] # RECYCLING SYMBOL FOR TYPE-1 PLASTICS +2674 ; [*0998.0020.0002] # RECYCLING SYMBOL FOR TYPE-2 PLASTICS +2675 ; [*0999.0020.0002] # RECYCLING SYMBOL FOR TYPE-3 PLASTICS +2676 ; [*099A.0020.0002] # RECYCLING SYMBOL FOR TYPE-4 PLASTICS +2677 ; [*099B.0020.0002] # RECYCLING SYMBOL FOR TYPE-5 PLASTICS +2678 ; [*099C.0020.0002] # RECYCLING SYMBOL FOR TYPE-6 PLASTICS +2679 ; [*099D.0020.0002] # RECYCLING SYMBOL FOR TYPE-7 PLASTICS +267A ; [*099E.0020.0002] # RECYCLING SYMBOL FOR GENERIC MATERIALS +267B ; [*099F.0020.0002] # BLACK UNIVERSAL RECYCLING SYMBOL +267C ; [*09A0.0020.0002] # RECYCLED PAPER SYMBOL +267D ; [*09A1.0020.0002] # PARTIALLY-RECYCLED PAPER SYMBOL +267E ; [*09A2.0020.0002] # PERMANENT PAPER SIGN +267F ; [*09A3.0020.0002] # WHEELCHAIR SYMBOL +2680 ; [*09A4.0020.0002] # DIE FACE-1 +2681 ; [*09A5.0020.0002] # DIE FACE-2 +2682 ; [*09A6.0020.0002] # DIE FACE-3 +2683 ; [*09A7.0020.0002] # DIE FACE-4 +2684 ; [*09A8.0020.0002] # DIE FACE-5 +2685 ; [*09A9.0020.0002] # DIE FACE-6 +2686 ; [*09AA.0020.0002] # WHITE CIRCLE WITH DOT RIGHT +2687 ; [*09AB.0020.0002] # WHITE CIRCLE WITH TWO DOTS +2688 ; [*09AC.0020.0002] # BLACK CIRCLE WITH WHITE DOT RIGHT +2689 ; [*09AD.0020.0002] # BLACK CIRCLE WITH TWO WHITE DOTS +268A ; [*0EB4.0020.0002] # MONOGRAM FOR YANG +268B ; [*0EB5.0020.0002] # MONOGRAM FOR YIN +268C ; [*0EB6.0020.0002] # DIGRAM FOR GREATER YANG +268D ; [*0EB7.0020.0002] # DIGRAM FOR LESSER YIN +268E ; [*0EB8.0020.0002] # DIGRAM FOR LESSER YANG +268F ; [*0EB9.0020.0002] # DIGRAM FOR GREATER YIN +2690 ; [*09AE.0020.0002] # WHITE FLAG +2691 ; [*09AF.0020.0002] # BLACK FLAG +2692 ; [*09B0.0020.0002] # HAMMER AND PICK +2693 ; [*09B1.0020.0002] # ANCHOR +2694 ; [*09B2.0020.0002] # CROSSED SWORDS +2695 ; [*09B3.0020.0002] # STAFF OF AESCULAPIUS +2696 ; [*09B4.0020.0002] # SCALES +2697 ; [*09B5.0020.0002] # ALEMBIC +2698 ; [*09B6.0020.0002] # FLOWER +2699 ; [*09B7.0020.0002] # GEAR +269A ; [*09B8.0020.0002] # STAFF OF HERMES +269B ; [*09B9.0020.0002] # ATOM SYMBOL +269C ; [*09BA.0020.0002] # FLEUR-DE-LIS +269D ; [*09BB.0020.0002] # OUTLINED WHITE STAR +269E ; [*09BC.0020.0002] # THREE LINES CONVERGING RIGHT +269F ; [*09BD.0020.0002] # THREE LINES CONVERGING LEFT +26A0 ; [*09BE.0020.0002] # WARNING SIGN +26A1 ; [*09BF.0020.0002] # HIGH VOLTAGE SIGN +26A2 ; [*09C0.0020.0002] # DOUBLED FEMALE SIGN +26A3 ; [*09C1.0020.0002] # DOUBLED MALE SIGN +26A4 ; [*09C2.0020.0002] # INTERLOCKED FEMALE AND MALE SIGN +26A5 ; [*09C3.0020.0002] # MALE AND FEMALE SIGN +26A6 ; [*09C4.0020.0002] # MALE WITH STROKE SIGN +26A7 ; [*09C5.0020.0002] # MALE WITH STROKE AND MALE AND FEMALE SIGN +26A8 ; [*09C6.0020.0002] # VERTICAL MALE WITH STROKE SIGN +26A9 ; [*09C7.0020.0002] # HORIZONTAL MALE WITH STROKE SIGN +26AA ; [*09C8.0020.0002] # MEDIUM WHITE CIRCLE +26AB ; [*09C9.0020.0002] # MEDIUM BLACK CIRCLE +26AC ; [*09CA.0020.0002] # MEDIUM SMALL WHITE CIRCLE +26AD ; [*09CB.0020.0002] # MARRIAGE SYMBOL +26AE ; [*09CC.0020.0002] # DIVORCE SYMBOL +26AF ; [*09CD.0020.0002] # UNMARRIED PARTNERSHIP SYMBOL +26B0 ; [*09CE.0020.0002] # COFFIN +26B1 ; [*09CF.0020.0002] # FUNERAL URN +26B2 ; [*09D0.0020.0002] # NEUTER +26B3 ; [*09D1.0020.0002] # CERES +26B4 ; [*09D2.0020.0002] # PALLAS +26B5 ; [*09D3.0020.0002] # JUNO +26B6 ; [*09D4.0020.0002] # VESTA +26B7 ; [*09D5.0020.0002] # CHIRON +26B8 ; [*09D6.0020.0002] # BLACK MOON LILITH +26B9 ; [*09D7.0020.0002] # SEXTILE +26BA ; [*09D8.0020.0002] # SEMISEXTILE +26BB ; [*09D9.0020.0002] # QUINCUNX +26BC ; [*09DA.0020.0002] # SESQUIQUADRATE +26BD ; [*09DB.0020.0002] # SOCCER BALL +26BE ; [*09DC.0020.0002] # BASEBALL +26BF ; [*09DD.0020.0002] # SQUARED KEY +26C0 ; [*09DE.0020.0002] # WHITE DRAUGHTS MAN +26C1 ; [*09DF.0020.0002] # WHITE DRAUGHTS KING +26C2 ; [*09E0.0020.0002] # BLACK DRAUGHTS MAN +26C3 ; [*09E1.0020.0002] # BLACK DRAUGHTS KING +26C4 ; [*09E2.0020.0002] # SNOWMAN WITHOUT SNOW +26C5 ; [*09E3.0020.0002] # SUN BEHIND CLOUD +26C6 ; [*09E4.0020.0002] # RAIN +26C7 ; [*09E5.0020.0002] # BLACK SNOWMAN +26C8 ; [*09E6.0020.0002] # THUNDER CLOUD AND RAIN +26C9 ; [*09E7.0020.0002] # TURNED WHITE SHOGI PIECE +26CA ; [*09E8.0020.0002] # TURNED BLACK SHOGI PIECE +26CB ; [*09E9.0020.0002] # WHITE DIAMOND IN SQUARE +26CC ; [*09EA.0020.0002] # CROSSING LANES +26CD ; [*09EB.0020.0002] # DISABLED CAR +26CE ; [*09EC.0020.0002] # OPHIUCHUS +26CF ; [*09ED.0020.0002] # PICK +26D0 ; [*09EE.0020.0002] # CAR SLIDING +26D1 ; [*09EF.0020.0002] # HELMET WITH WHITE CROSS +26D2 ; [*09F0.0020.0002] # CIRCLED CROSSING LANES +26D3 ; [*09F1.0020.0002] # CHAINS +26D4 ; [*09F2.0020.0002] # NO ENTRY +26D5 ; [*09F3.0020.0002] # ALTERNATE ONE-WAY LEFT WAY TRAFFIC +26D6 ; [*09F4.0020.0002] # BLACK TWO-WAY LEFT WAY TRAFFIC +26D7 ; [*09F5.0020.0002] # WHITE TWO-WAY LEFT WAY TRAFFIC +26D8 ; [*09F6.0020.0002] # BLACK LEFT LANE MERGE +26D9 ; [*09F7.0020.0002] # WHITE LEFT LANE MERGE +26DA ; [*09F8.0020.0002] # DRIVE SLOW SIGN +26DB ; [*09F9.0020.0002] # HEAVY WHITE DOWN-POINTING TRIANGLE +26DC ; [*09FA.0020.0002] # LEFT CLOSED ENTRY +26DD ; [*09FB.0020.0002] # SQUARED SALTIRE +26DE ; [*09FC.0020.0002] # FALLING DIAGONAL IN WHITE CIRCLE IN BLACK SQUARE +26DF ; [*09FD.0020.0002] # BLACK TRUCK +26E0 ; [*09FE.0020.0002] # RESTRICTED LEFT ENTRY-1 +26E1 ; [*09FF.0020.0002] # RESTRICTED LEFT ENTRY-2 +26E2 ; [*0A00.0020.0002] # ASTRONOMICAL SYMBOL FOR URANUS +26E3 ; [*0A01.0020.0002] # HEAVY CIRCLE WITH STROKE AND TWO DOTS ABOVE +26E4 ; [*0A02.0020.0002] # PENTAGRAM +26E5 ; [*0A03.0020.0002] # RIGHT-HANDED INTERLACED PENTAGRAM +26E6 ; [*0A04.0020.0002] # LEFT-HANDED INTERLACED PENTAGRAM +26E7 ; [*0A05.0020.0002] # INVERTED PENTAGRAM +26E8 ; [*0A06.0020.0002] # BLACK CROSS ON SHIELD +26E9 ; [*0A07.0020.0002] # SHINTO SHRINE +26EA ; [*0A08.0020.0002] # CHURCH +26EB ; [*0A09.0020.0002] # CASTLE +26EC ; [*0A0A.0020.0002] # HISTORIC SITE +26ED ; [*0A0B.0020.0002] # GEAR WITHOUT HUB +26EE ; [*0A0C.0020.0002] # GEAR WITH HANDLES +26EF ; [*0A0D.0020.0002] # MAP SYMBOL FOR LIGHTHOUSE +26F0 ; [*0A0E.0020.0002] # MOUNTAIN +26F1 ; [*0A0F.0020.0002] # UMBRELLA ON GROUND +26F2 ; [*0A10.0020.0002] # FOUNTAIN +26F3 ; [*0A11.0020.0002] # FLAG IN HOLE +26F4 ; [*0A12.0020.0002] # FERRY +26F5 ; [*0A13.0020.0002] # SAILBOAT +26F6 ; [*0A14.0020.0002] # SQUARE FOUR CORNERS +26F7 ; [*0A15.0020.0002] # SKIER +26F8 ; [*0A16.0020.0002] # ICE SKATE +26F9 ; [*0A17.0020.0002] # PERSON WITH BALL +26FA ; [*0A18.0020.0002] # TENT +26FB ; [*0A19.0020.0002] # JAPANESE BANK SYMBOL +26FC ; [*0A1A.0020.0002] # HEADSTONE GRAVEYARD SYMBOL +26FD ; [*0A1B.0020.0002] # FUEL PUMP +26FE ; [*0A1C.0020.0002] # CUP ON BLACK SQUARE +26FF ; [*0A1D.0020.0002] # WHITE FLAG WITH HORIZONTAL MIDDLE BLACK STRIPE +2700 ; [*0A38.0020.0002] # BLACK SAFETY SCISSORS +2701 ; [*0A39.0020.0002] # UPPER BLADE SCISSORS +2702 ; [*0A3A.0020.0002] # BLACK SCISSORS +2703 ; [*0A3B.0020.0002] # LOWER BLADE SCISSORS +2704 ; [*0A3C.0020.0002] # WHITE SCISSORS +2705 ; [*0A3D.0020.0002] # WHITE HEAVY CHECK MARK +2706 ; [*0A3E.0020.0002] # TELEPHONE LOCATION SIGN +2707 ; [*0A3F.0020.0002] # TAPE DRIVE +2708 ; [*0A40.0020.0002] # AIRPLANE +2709 ; [*0A41.0020.0002] # ENVELOPE +270A ; [*0A42.0020.0002] # RAISED FIST +270B ; [*0A43.0020.0002] # RAISED HAND +270C ; [*0A44.0020.0002] # VICTORY HAND +270D ; [*0A45.0020.0002] # WRITING HAND +270E ; [*0A46.0020.0002] # LOWER RIGHT PENCIL +270F ; [*0A47.0020.0002] # PENCIL +2710 ; [*0A48.0020.0002] # UPPER RIGHT PENCIL +2711 ; [*0A49.0020.0002] # WHITE NIB +2712 ; [*0A4A.0020.0002] # BLACK NIB +2713 ; [*0A4B.0020.0002] # CHECK MARK +2714 ; [*0A4C.0020.0002] # HEAVY CHECK MARK +2715 ; [*0A4D.0020.0002] # MULTIPLICATION X +2716 ; [*0A4E.0020.0002] # HEAVY MULTIPLICATION X +2717 ; [*0A4F.0020.0002] # BALLOT X +2718 ; [*0A50.0020.0002] # HEAVY BALLOT X +2719 ; [*0A51.0020.0002] # OUTLINED GREEK CROSS +271A ; [*0A52.0020.0002] # HEAVY GREEK CROSS +271B ; [*0A53.0020.0002] # OPEN CENTRE CROSS +271C ; [*0A54.0020.0002] # HEAVY OPEN CENTRE CROSS +271D ; [*0A55.0020.0002] # LATIN CROSS +271E ; [*0A56.0020.0002] # SHADOWED WHITE LATIN CROSS +271F ; [*0A57.0020.0002] # OUTLINED LATIN CROSS +2720 ; [*0A58.0020.0002] # MALTESE CROSS +2721 ; [*0A59.0020.0002] # STAR OF DAVID +2722 ; [*0A5A.0020.0002] # FOUR TEARDROP-SPOKED ASTERISK +2723 ; [*0A5B.0020.0002] # FOUR BALLOON-SPOKED ASTERISK +2724 ; [*0A5C.0020.0002] # HEAVY FOUR BALLOON-SPOKED ASTERISK +2725 ; [*0A5D.0020.0002] # FOUR CLUB-SPOKED ASTERISK +2726 ; [*0A5E.0020.0002] # BLACK FOUR POINTED STAR +2727 ; [*0A5F.0020.0002] # WHITE FOUR POINTED STAR +2728 ; [*0A60.0020.0002] # SPARKLES +2729 ; [*0A61.0020.0002] # STRESS OUTLINED WHITE STAR +272A ; [*0A62.0020.0002] # CIRCLED WHITE STAR +272B ; [*0A63.0020.0002] # OPEN CENTRE BLACK STAR +272C ; [*0A64.0020.0002] # BLACK CENTRE WHITE STAR +272D ; [*0A65.0020.0002] # OUTLINED BLACK STAR +272E ; [*0A66.0020.0002] # HEAVY OUTLINED BLACK STAR +272F ; [*0A67.0020.0002] # PINWHEEL STAR +2730 ; [*0A68.0020.0002] # SHADOWED WHITE STAR +2731 ; [*0A69.0020.0002] # HEAVY ASTERISK +2732 ; [*0A6A.0020.0002] # OPEN CENTRE ASTERISK +2733 ; [*0A6B.0020.0002] # EIGHT SPOKED ASTERISK +2734 ; [*0A6C.0020.0002] # EIGHT POINTED BLACK STAR +2735 ; [*0A6D.0020.0002] # EIGHT POINTED PINWHEEL STAR +2736 ; [*0A6E.0020.0002] # SIX POINTED BLACK STAR +2737 ; [*0A6F.0020.0002] # EIGHT POINTED RECTILINEAR BLACK STAR +2738 ; [*0A70.0020.0002] # HEAVY EIGHT POINTED RECTILINEAR BLACK STAR +2739 ; [*0A71.0020.0002] # TWELVE POINTED BLACK STAR +273A ; [*0A72.0020.0002] # SIXTEEN POINTED ASTERISK +273B ; [*0A73.0020.0002] # TEARDROP-SPOKED ASTERISK +273C ; [*0A74.0020.0002] # OPEN CENTRE TEARDROP-SPOKED ASTERISK +273D ; [*0A75.0020.0002] # HEAVY TEARDROP-SPOKED ASTERISK +273E ; [*0A76.0020.0002] # SIX PETALLED BLACK AND WHITE FLORETTE +273F ; [*0A77.0020.0002] # BLACK FLORETTE +2740 ; [*0A78.0020.0002] # WHITE FLORETTE +2741 ; [*0A79.0020.0002] # EIGHT PETALLED OUTLINED BLACK FLORETTE +2742 ; [*0A7A.0020.0002] # CIRCLED OPEN CENTRE EIGHT POINTED STAR +2743 ; [*0A7B.0020.0002] # HEAVY TEARDROP-SPOKED PINWHEEL ASTERISK +2744 ; [*0A7C.0020.0002] # SNOWFLAKE +2745 ; [*0A7D.0020.0002] # TIGHT TRIFOLIATE SNOWFLAKE +2746 ; [*0A7E.0020.0002] # HEAVY CHEVRON SNOWFLAKE +2747 ; [*0A7F.0020.0002] # SPARKLE +2748 ; [*0A80.0020.0002] # HEAVY SPARKLE +2749 ; [*0A81.0020.0002] # BALLOON-SPOKED ASTERISK +274A ; [*0A82.0020.0002] # EIGHT TEARDROP-SPOKED PROPELLER ASTERISK +274B ; [*0A83.0020.0002] # HEAVY EIGHT TEARDROP-SPOKED PROPELLER ASTERISK +274C ; [*0A84.0020.0002] # CROSS MARK +274D ; [*0A85.0020.0002] # SHADOWED WHITE CIRCLE +274E ; [*0A86.0020.0002] # NEGATIVE SQUARED CROSS MARK +274F ; [*0A87.0020.0002] # LOWER RIGHT DROP-SHADOWED WHITE SQUARE +2750 ; [*0A88.0020.0002] # UPPER RIGHT DROP-SHADOWED WHITE SQUARE +2751 ; [*0A89.0020.0002] # LOWER RIGHT SHADOWED WHITE SQUARE +2752 ; [*0A8A.0020.0002] # UPPER RIGHT SHADOWED WHITE SQUARE +2753 ; [*0A8B.0020.0002] # BLACK QUESTION MARK ORNAMENT +2754 ; [*0A8C.0020.0002] # WHITE QUESTION MARK ORNAMENT +2755 ; [*0A8D.0020.0002] # WHITE EXCLAMATION MARK ORNAMENT +2756 ; [*0A8E.0020.0002] # BLACK DIAMOND MINUS WHITE X +2757 ; [*0A8F.0020.0002] # HEAVY EXCLAMATION MARK SYMBOL +2758 ; [*0A90.0020.0002] # LIGHT VERTICAL BAR +2759 ; [*0A91.0020.0002] # MEDIUM VERTICAL BAR +275A ; [*0A92.0020.0002] # HEAVY VERTICAL BAR +275B ; [*0A93.0020.0002] # HEAVY SINGLE TURNED COMMA QUOTATION MARK ORNAMENT +275C ; [*0A94.0020.0002] # HEAVY SINGLE COMMA QUOTATION MARK ORNAMENT +275D ; [*0A95.0020.0002] # HEAVY DOUBLE TURNED COMMA QUOTATION MARK ORNAMENT +275E ; [*0A96.0020.0002] # HEAVY DOUBLE COMMA QUOTATION MARK ORNAMENT +275F ; [*0A97.0020.0002] # HEAVY LOW SINGLE COMMA QUOTATION MARK ORNAMENT +2760 ; [*0A98.0020.0002] # HEAVY LOW DOUBLE COMMA QUOTATION MARK ORNAMENT +2761 ; [*0A99.0020.0002] # CURVED STEM PARAGRAPH SIGN ORNAMENT +2762 ; [*0A9A.0020.0002] # HEAVY EXCLAMATION MARK ORNAMENT +2763 ; [*0A9B.0020.0002] # HEAVY HEART EXCLAMATION MARK ORNAMENT +2764 ; [*0A9C.0020.0002] # HEAVY BLACK HEART +2765 ; [*0A9D.0020.0002] # ROTATED HEAVY BLACK HEART BULLET +2766 ; [*0A9E.0020.0002] # FLORAL HEART +2767 ; [*0A9F.0020.0002] # ROTATED FLORAL HEART BULLET +2768 ; [*034E.0020.0002] # MEDIUM LEFT PARENTHESIS ORNAMENT +2769 ; [*034F.0020.0002] # MEDIUM RIGHT PARENTHESIS ORNAMENT +276A ; [*0350.0020.0002] # MEDIUM FLATTENED LEFT PARENTHESIS ORNAMENT +276B ; [*0351.0020.0002] # MEDIUM FLATTENED RIGHT PARENTHESIS ORNAMENT +276C ; [*0352.0020.0002] # MEDIUM LEFT-POINTING ANGLE BRACKET ORNAMENT +276D ; [*0353.0020.0002] # MEDIUM RIGHT-POINTING ANGLE BRACKET ORNAMENT +276E ; [*0354.0020.0002] # HEAVY LEFT-POINTING ANGLE QUOTATION MARK ORNAMENT +276F ; [*0355.0020.0002] # HEAVY RIGHT-POINTING ANGLE QUOTATION MARK ORNAMENT +2770 ; [*0356.0020.0002] # HEAVY LEFT-POINTING ANGLE BRACKET ORNAMENT +2771 ; [*0357.0020.0002] # HEAVY RIGHT-POINTING ANGLE BRACKET ORNAMENT +2772 ; [*0358.0020.0002] # LIGHT LEFT TORTOISE SHELL BRACKET ORNAMENT +2773 ; [*0359.0020.0002] # LIGHT RIGHT TORTOISE SHELL BRACKET ORNAMENT +2774 ; [*035A.0020.0002] # MEDIUM LEFT CURLY BRACKET ORNAMENT +2775 ; [*035B.0020.0002] # MEDIUM RIGHT CURLY BRACKET ORNAMENT +2794 ; [*0AA0.0020.0002] # HEAVY WIDE-HEADED RIGHTWARDS ARROW +2795 ; [*0AA1.0020.0002] # HEAVY PLUS SIGN +2796 ; [*0AA2.0020.0002] # HEAVY MINUS SIGN +2797 ; [*0AA3.0020.0002] # HEAVY DIVISION SIGN +2798 ; [*0AA4.0020.0002] # HEAVY SOUTH EAST ARROW +2799 ; [*0AA5.0020.0002] # HEAVY RIGHTWARDS ARROW +279A ; [*0AA6.0020.0002] # HEAVY NORTH EAST ARROW +279B ; [*0AA7.0020.0002] # DRAFTING POINT RIGHTWARDS ARROW +279C ; [*0AA8.0020.0002] # HEAVY ROUND-TIPPED RIGHTWARDS ARROW +279D ; [*0AA9.0020.0002] # TRIANGLE-HEADED RIGHTWARDS ARROW +279E ; [*0AAA.0020.0002] # HEAVY TRIANGLE-HEADED RIGHTWARDS ARROW +279F ; [*0AAB.0020.0002] # DASHED TRIANGLE-HEADED RIGHTWARDS ARROW +27A0 ; [*0AAC.0020.0002] # HEAVY DASHED TRIANGLE-HEADED RIGHTWARDS ARROW +27A1 ; [*0AAD.0020.0002] # BLACK RIGHTWARDS ARROW +27A2 ; [*0AAE.0020.0002] # THREE-D TOP-LIGHTED RIGHTWARDS ARROWHEAD +27A3 ; [*0AAF.0020.0002] # THREE-D BOTTOM-LIGHTED RIGHTWARDS ARROWHEAD +27A4 ; [*0AB0.0020.0002] # BLACK RIGHTWARDS ARROWHEAD +27A5 ; [*0AB1.0020.0002] # HEAVY BLACK CURVED DOWNWARDS AND RIGHTWARDS ARROW +27A6 ; [*0AB2.0020.0002] # HEAVY BLACK CURVED UPWARDS AND RIGHTWARDS ARROW +27A7 ; [*0AB3.0020.0002] # SQUAT BLACK RIGHTWARDS ARROW +27A8 ; [*0AB4.0020.0002] # HEAVY CONCAVE-POINTED BLACK RIGHTWARDS ARROW +27A9 ; [*0AB5.0020.0002] # RIGHT-SHADED WHITE RIGHTWARDS ARROW +27AA ; [*0AB6.0020.0002] # LEFT-SHADED WHITE RIGHTWARDS ARROW +27AB ; [*0AB7.0020.0002] # BACK-TILTED SHADOWED WHITE RIGHTWARDS ARROW +27AC ; [*0AB8.0020.0002] # FRONT-TILTED SHADOWED WHITE RIGHTWARDS ARROW +27AD ; [*0AB9.0020.0002] # HEAVY LOWER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW +27AE ; [*0ABA.0020.0002] # HEAVY UPPER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW +27AF ; [*0ABB.0020.0002] # NOTCHED LOWER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW +27B0 ; [*0ABC.0020.0002] # CURLY LOOP +27B1 ; [*0ABD.0020.0002] # NOTCHED UPPER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW +27B2 ; [*0ABE.0020.0002] # CIRCLED HEAVY WHITE RIGHTWARDS ARROW +27B3 ; [*0ABF.0020.0002] # WHITE-FEATHERED RIGHTWARDS ARROW +27B4 ; [*0AC0.0020.0002] # BLACK-FEATHERED SOUTH EAST ARROW +27B5 ; [*0AC1.0020.0002] # BLACK-FEATHERED RIGHTWARDS ARROW +27B6 ; [*0AC2.0020.0002] # BLACK-FEATHERED NORTH EAST ARROW +27B7 ; [*0AC3.0020.0002] # HEAVY BLACK-FEATHERED SOUTH EAST ARROW +27B8 ; [*0AC4.0020.0002] # HEAVY BLACK-FEATHERED RIGHTWARDS ARROW +27B9 ; [*0AC5.0020.0002] # HEAVY BLACK-FEATHERED NORTH EAST ARROW +27BA ; [*0AC6.0020.0002] # TEARDROP-BARBED RIGHTWARDS ARROW +27BB ; [*0AC7.0020.0002] # HEAVY TEARDROP-SHANKED RIGHTWARDS ARROW +27BC ; [*0AC8.0020.0002] # WEDGE-TAILED RIGHTWARDS ARROW +27BD ; [*0AC9.0020.0002] # HEAVY WEDGE-TAILED RIGHTWARDS ARROW +27BE ; [*0ACA.0020.0002] # OPEN-OUTLINED RIGHTWARDS ARROW +27BF ; [*0ACB.0020.0002] # DOUBLE CURLY LOOP +27C0 ; [*0ACC.0020.0002] # THREE DIMENSIONAL ANGLE +27C1 ; [*0ACD.0020.0002] # WHITE TRIANGLE CONTAINING SMALL WHITE TRIANGLE +27C2 ; [*0ACE.0020.0002] # PERPENDICULAR +27C3 ; [*0ACF.0020.0002] # OPEN SUBSET +27C4 ; [*0AD0.0020.0002] # OPEN SUPERSET +27C5 ; [*0342.0020.0002] # LEFT S-SHAPED BAG DELIMITER +27C6 ; [*0343.0020.0002] # RIGHT S-SHAPED BAG DELIMITER +27C7 ; [*0AD1.0020.0002] # OR WITH DOT INSIDE +27C8 ; [*0AD2.0020.0002] # REVERSE SOLIDUS PRECEDING SUBSET +27C9 ; [*0AD3.0020.0002] # SUPERSET PRECEDING SOLIDUS +27CA ; [*0AD4.0020.0002] # VERTICAL BAR WITH HORIZONTAL STROKE +27CB ; [*0AD5.0020.0002] # MATHEMATICAL RISING DIAGONAL +27CC ; [*0AD6.0020.0002] # LONG DIVISION +27CD ; [*0AD7.0020.0002] # MATHEMATICAL FALLING DIAGONAL +27CE ; [*0AD8.0020.0002] # SQUARED LOGICAL AND +27CF ; [*0AD9.0020.0002] # SQUARED LOGICAL OR +27D0 ; [*0ADA.0020.0002] # WHITE DIAMOND WITH CENTRED DOT +27D1 ; [*0ADB.0020.0002] # AND WITH DOT +27D2 ; [*0ADC.0020.0002] # ELEMENT OF OPENING UPWARDS +27D3 ; [*0ADD.0020.0002] # LOWER RIGHT CORNER WITH DOT +27D4 ; [*0ADE.0020.0002] # UPPER LEFT CORNER WITH DOT +27D5 ; [*0ADF.0020.0002] # LEFT OUTER JOIN +27D6 ; [*0AE0.0020.0002] # RIGHT OUTER JOIN +27D7 ; [*0AE1.0020.0002] # FULL OUTER JOIN +27D8 ; [*0AE2.0020.0002] # LARGE UP TACK +27D9 ; [*0AE3.0020.0002] # LARGE DOWN TACK +27DA ; [*0AE4.0020.0002] # LEFT AND RIGHT DOUBLE TURNSTILE +27DB ; [*0AE5.0020.0002] # LEFT AND RIGHT TACK +27DC ; [*0AE6.0020.0002] # LEFT MULTIMAP +27DD ; [*0AE7.0020.0002] # LONG RIGHT TACK +27DE ; [*0AE8.0020.0002] # LONG LEFT TACK +27DF ; [*0AE9.0020.0002] # UP TACK WITH CIRCLE ABOVE +27E0 ; [*0AEA.0020.0002] # LOZENGE DIVIDED BY HORIZONTAL RULE +27E1 ; [*0AEB.0020.0002] # WHITE CONCAVE-SIDED DIAMOND +27E2 ; [*0AEC.0020.0002] # WHITE CONCAVE-SIDED DIAMOND WITH LEFTWARDS TICK +27E3 ; [*0AED.0020.0002] # WHITE CONCAVE-SIDED DIAMOND WITH RIGHTWARDS TICK +27E4 ; [*0AEE.0020.0002] # WHITE SQUARE WITH LEFTWARDS TICK +27E5 ; [*0AEF.0020.0002] # WHITE SQUARE WITH RIGHTWARDS TICK +27E6 ; [*0344.0020.0002] # MATHEMATICAL LEFT WHITE SQUARE BRACKET +27E7 ; [*0345.0020.0002] # MATHEMATICAL RIGHT WHITE SQUARE BRACKET +27E8 ; [*0346.0020.0002] # MATHEMATICAL LEFT ANGLE BRACKET +27E9 ; [*0347.0020.0002] # MATHEMATICAL RIGHT ANGLE BRACKET +27EA ; [*0348.0020.0002] # MATHEMATICAL LEFT DOUBLE ANGLE BRACKET +27EB ; [*0349.0020.0002] # MATHEMATICAL RIGHT DOUBLE ANGLE BRACKET +27EC ; [*034A.0020.0002] # MATHEMATICAL LEFT WHITE TORTOISE SHELL BRACKET +27ED ; [*034B.0020.0002] # MATHEMATICAL RIGHT WHITE TORTOISE SHELL BRACKET +27EE ; [*034C.0020.0002] # MATHEMATICAL LEFT FLATTENED PARENTHESIS +27EF ; [*034D.0020.0002] # MATHEMATICAL RIGHT FLATTENED PARENTHESIS +27F0 ; [*0AF0.0020.0002] # UPWARDS QUADRUPLE ARROW +27F1 ; [*0AF1.0020.0002] # DOWNWARDS QUADRUPLE ARROW +27F2 ; [*0AF2.0020.0002] # ANTICLOCKWISE GAPPED CIRCLE ARROW +27F3 ; [*0AF3.0020.0002] # CLOCKWISE GAPPED CIRCLE ARROW +27F4 ; [*0AF4.0020.0002] # RIGHT ARROW WITH CIRCLED PLUS +27F5 ; [*0AF5.0020.0002] # LONG LEFTWARDS ARROW +27F6 ; [*0AF6.0020.0002] # LONG RIGHTWARDS ARROW +27F7 ; [*0AF7.0020.0002] # LONG LEFT RIGHT ARROW +27F8 ; [*0AF8.0020.0002] # LONG LEFTWARDS DOUBLE ARROW +27F9 ; [*0AF9.0020.0002] # LONG RIGHTWARDS DOUBLE ARROW +27FA ; [*0AFA.0020.0002] # LONG LEFT RIGHT DOUBLE ARROW +27FB ; [*0AFB.0020.0002] # LONG LEFTWARDS ARROW FROM BAR +27FC ; [*0AFC.0020.0002] # LONG RIGHTWARDS ARROW FROM BAR +27FD ; [*0AFD.0020.0002] # LONG LEFTWARDS DOUBLE ARROW FROM BAR +27FE ; [*0AFE.0020.0002] # LONG RIGHTWARDS DOUBLE ARROW FROM BAR +27FF ; [*0AFF.0020.0002] # LONG RIGHTWARDS SQUIGGLE ARROW +2800 ; [*0DB4.0020.0002] # BRAILLE PATTERN BLANK +2801 ; [*0DB5.0020.0002] # BRAILLE PATTERN DOTS-1 +2802 ; [*0DB6.0020.0002] # BRAILLE PATTERN DOTS-2 +2803 ; [*0DB7.0020.0002] # BRAILLE PATTERN DOTS-12 +2804 ; [*0DB8.0020.0002] # BRAILLE PATTERN DOTS-3 +2805 ; [*0DB9.0020.0002] # BRAILLE PATTERN DOTS-13 +2806 ; [*0DBA.0020.0002] # BRAILLE PATTERN DOTS-23 +2807 ; [*0DBB.0020.0002] # BRAILLE PATTERN DOTS-123 +2808 ; [*0DBC.0020.0002] # BRAILLE PATTERN DOTS-4 +2809 ; [*0DBD.0020.0002] # BRAILLE PATTERN DOTS-14 +280A ; [*0DBE.0020.0002] # BRAILLE PATTERN DOTS-24 +280B ; [*0DBF.0020.0002] # BRAILLE PATTERN DOTS-124 +280C ; [*0DC0.0020.0002] # BRAILLE PATTERN DOTS-34 +280D ; [*0DC1.0020.0002] # BRAILLE PATTERN DOTS-134 +280E ; [*0DC2.0020.0002] # BRAILLE PATTERN DOTS-234 +280F ; [*0DC3.0020.0002] # BRAILLE PATTERN DOTS-1234 +2810 ; [*0DC4.0020.0002] # BRAILLE PATTERN DOTS-5 +2811 ; [*0DC5.0020.0002] # BRAILLE PATTERN DOTS-15 +2812 ; [*0DC6.0020.0002] # BRAILLE PATTERN DOTS-25 +2813 ; [*0DC7.0020.0002] # BRAILLE PATTERN DOTS-125 +2814 ; [*0DC8.0020.0002] # BRAILLE PATTERN DOTS-35 +2815 ; [*0DC9.0020.0002] # BRAILLE PATTERN DOTS-135 +2816 ; [*0DCA.0020.0002] # BRAILLE PATTERN DOTS-235 +2817 ; [*0DCB.0020.0002] # BRAILLE PATTERN DOTS-1235 +2818 ; [*0DCC.0020.0002] # BRAILLE PATTERN DOTS-45 +2819 ; [*0DCD.0020.0002] # BRAILLE PATTERN DOTS-145 +281A ; [*0DCE.0020.0002] # BRAILLE PATTERN DOTS-245 +281B ; [*0DCF.0020.0002] # BRAILLE PATTERN DOTS-1245 +281C ; [*0DD0.0020.0002] # BRAILLE PATTERN DOTS-345 +281D ; [*0DD1.0020.0002] # BRAILLE PATTERN DOTS-1345 +281E ; [*0DD2.0020.0002] # BRAILLE PATTERN DOTS-2345 +281F ; [*0DD3.0020.0002] # BRAILLE PATTERN DOTS-12345 +2820 ; [*0DD4.0020.0002] # BRAILLE PATTERN DOTS-6 +2821 ; [*0DD5.0020.0002] # BRAILLE PATTERN DOTS-16 +2822 ; [*0DD6.0020.0002] # BRAILLE PATTERN DOTS-26 +2823 ; [*0DD7.0020.0002] # BRAILLE PATTERN DOTS-126 +2824 ; [*0DD8.0020.0002] # BRAILLE PATTERN DOTS-36 +2825 ; [*0DD9.0020.0002] # BRAILLE PATTERN DOTS-136 +2826 ; [*0DDA.0020.0002] # BRAILLE PATTERN DOTS-236 +2827 ; [*0DDB.0020.0002] # BRAILLE PATTERN DOTS-1236 +2828 ; [*0DDC.0020.0002] # BRAILLE PATTERN DOTS-46 +2829 ; [*0DDD.0020.0002] # BRAILLE PATTERN DOTS-146 +282A ; [*0DDE.0020.0002] # BRAILLE PATTERN DOTS-246 +282B ; [*0DDF.0020.0002] # BRAILLE PATTERN DOTS-1246 +282C ; [*0DE0.0020.0002] # BRAILLE PATTERN DOTS-346 +282D ; [*0DE1.0020.0002] # BRAILLE PATTERN DOTS-1346 +282E ; [*0DE2.0020.0002] # BRAILLE PATTERN DOTS-2346 +282F ; [*0DE3.0020.0002] # BRAILLE PATTERN DOTS-12346 +2830 ; [*0DE4.0020.0002] # BRAILLE PATTERN DOTS-56 +2831 ; [*0DE5.0020.0002] # BRAILLE PATTERN DOTS-156 +2832 ; [*0DE6.0020.0002] # BRAILLE PATTERN DOTS-256 +2833 ; [*0DE7.0020.0002] # BRAILLE PATTERN DOTS-1256 +2834 ; [*0DE8.0020.0002] # BRAILLE PATTERN DOTS-356 +2835 ; [*0DE9.0020.0002] # BRAILLE PATTERN DOTS-1356 +2836 ; [*0DEA.0020.0002] # BRAILLE PATTERN DOTS-2356 +2837 ; [*0DEB.0020.0002] # BRAILLE PATTERN DOTS-12356 +2838 ; [*0DEC.0020.0002] # BRAILLE PATTERN DOTS-456 +2839 ; [*0DED.0020.0002] # BRAILLE PATTERN DOTS-1456 +283A ; [*0DEE.0020.0002] # BRAILLE PATTERN DOTS-2456 +283B ; [*0DEF.0020.0002] # BRAILLE PATTERN DOTS-12456 +283C ; [*0DF0.0020.0002] # BRAILLE PATTERN DOTS-3456 +283D ; [*0DF1.0020.0002] # BRAILLE PATTERN DOTS-13456 +283E ; [*0DF2.0020.0002] # BRAILLE PATTERN DOTS-23456 +283F ; [*0DF3.0020.0002] # BRAILLE PATTERN DOTS-123456 +2840 ; [*0DF4.0020.0002] # BRAILLE PATTERN DOTS-7 +2841 ; [*0DF5.0020.0002] # BRAILLE PATTERN DOTS-17 +2842 ; [*0DF6.0020.0002] # BRAILLE PATTERN DOTS-27 +2843 ; [*0DF7.0020.0002] # BRAILLE PATTERN DOTS-127 +2844 ; [*0DF8.0020.0002] # BRAILLE PATTERN DOTS-37 +2845 ; [*0DF9.0020.0002] # BRAILLE PATTERN DOTS-137 +2846 ; [*0DFA.0020.0002] # BRAILLE PATTERN DOTS-237 +2847 ; [*0DFB.0020.0002] # BRAILLE PATTERN DOTS-1237 +2848 ; [*0DFC.0020.0002] # BRAILLE PATTERN DOTS-47 +2849 ; [*0DFD.0020.0002] # BRAILLE PATTERN DOTS-147 +284A ; [*0DFE.0020.0002] # BRAILLE PATTERN DOTS-247 +284B ; [*0DFF.0020.0002] # BRAILLE PATTERN DOTS-1247 +284C ; [*0E00.0020.0002] # BRAILLE PATTERN DOTS-347 +284D ; [*0E01.0020.0002] # BRAILLE PATTERN DOTS-1347 +284E ; [*0E02.0020.0002] # BRAILLE PATTERN DOTS-2347 +284F ; [*0E03.0020.0002] # BRAILLE PATTERN DOTS-12347 +2850 ; [*0E04.0020.0002] # BRAILLE PATTERN DOTS-57 +2851 ; [*0E05.0020.0002] # BRAILLE PATTERN DOTS-157 +2852 ; [*0E06.0020.0002] # BRAILLE PATTERN DOTS-257 +2853 ; [*0E07.0020.0002] # BRAILLE PATTERN DOTS-1257 +2854 ; [*0E08.0020.0002] # BRAILLE PATTERN DOTS-357 +2855 ; [*0E09.0020.0002] # BRAILLE PATTERN DOTS-1357 +2856 ; [*0E0A.0020.0002] # BRAILLE PATTERN DOTS-2357 +2857 ; [*0E0B.0020.0002] # BRAILLE PATTERN DOTS-12357 +2858 ; [*0E0C.0020.0002] # BRAILLE PATTERN DOTS-457 +2859 ; [*0E0D.0020.0002] # BRAILLE PATTERN DOTS-1457 +285A ; [*0E0E.0020.0002] # BRAILLE PATTERN DOTS-2457 +285B ; [*0E0F.0020.0002] # BRAILLE PATTERN DOTS-12457 +285C ; [*0E10.0020.0002] # BRAILLE PATTERN DOTS-3457 +285D ; [*0E11.0020.0002] # BRAILLE PATTERN DOTS-13457 +285E ; [*0E12.0020.0002] # BRAILLE PATTERN DOTS-23457 +285F ; [*0E13.0020.0002] # BRAILLE PATTERN DOTS-123457 +2860 ; [*0E14.0020.0002] # BRAILLE PATTERN DOTS-67 +2861 ; [*0E15.0020.0002] # BRAILLE PATTERN DOTS-167 +2862 ; [*0E16.0020.0002] # BRAILLE PATTERN DOTS-267 +2863 ; [*0E17.0020.0002] # BRAILLE PATTERN DOTS-1267 +2864 ; [*0E18.0020.0002] # BRAILLE PATTERN DOTS-367 +2865 ; [*0E19.0020.0002] # BRAILLE PATTERN DOTS-1367 +2866 ; [*0E1A.0020.0002] # BRAILLE PATTERN DOTS-2367 +2867 ; [*0E1B.0020.0002] # BRAILLE PATTERN DOTS-12367 +2868 ; [*0E1C.0020.0002] # BRAILLE PATTERN DOTS-467 +2869 ; [*0E1D.0020.0002] # BRAILLE PATTERN DOTS-1467 +286A ; [*0E1E.0020.0002] # BRAILLE PATTERN DOTS-2467 +286B ; [*0E1F.0020.0002] # BRAILLE PATTERN DOTS-12467 +286C ; [*0E20.0020.0002] # BRAILLE PATTERN DOTS-3467 +286D ; [*0E21.0020.0002] # BRAILLE PATTERN DOTS-13467 +286E ; [*0E22.0020.0002] # BRAILLE PATTERN DOTS-23467 +286F ; [*0E23.0020.0002] # BRAILLE PATTERN DOTS-123467 +2870 ; [*0E24.0020.0002] # BRAILLE PATTERN DOTS-567 +2871 ; [*0E25.0020.0002] # BRAILLE PATTERN DOTS-1567 +2872 ; [*0E26.0020.0002] # BRAILLE PATTERN DOTS-2567 +2873 ; [*0E27.0020.0002] # BRAILLE PATTERN DOTS-12567 +2874 ; [*0E28.0020.0002] # BRAILLE PATTERN DOTS-3567 +2875 ; [*0E29.0020.0002] # BRAILLE PATTERN DOTS-13567 +2876 ; [*0E2A.0020.0002] # BRAILLE PATTERN DOTS-23567 +2877 ; [*0E2B.0020.0002] # BRAILLE PATTERN DOTS-123567 +2878 ; [*0E2C.0020.0002] # BRAILLE PATTERN DOTS-4567 +2879 ; [*0E2D.0020.0002] # BRAILLE PATTERN DOTS-14567 +287A ; [*0E2E.0020.0002] # BRAILLE PATTERN DOTS-24567 +287B ; [*0E2F.0020.0002] # BRAILLE PATTERN DOTS-124567 +287C ; [*0E30.0020.0002] # BRAILLE PATTERN DOTS-34567 +287D ; [*0E31.0020.0002] # BRAILLE PATTERN DOTS-134567 +287E ; [*0E32.0020.0002] # BRAILLE PATTERN DOTS-234567 +287F ; [*0E33.0020.0002] # BRAILLE PATTERN DOTS-1234567 +2880 ; [*0E34.0020.0002] # BRAILLE PATTERN DOTS-8 +2881 ; [*0E35.0020.0002] # BRAILLE PATTERN DOTS-18 +2882 ; [*0E36.0020.0002] # BRAILLE PATTERN DOTS-28 +2883 ; [*0E37.0020.0002] # BRAILLE PATTERN DOTS-128 +2884 ; [*0E38.0020.0002] # BRAILLE PATTERN DOTS-38 +2885 ; [*0E39.0020.0002] # BRAILLE PATTERN DOTS-138 +2886 ; [*0E3A.0020.0002] # BRAILLE PATTERN DOTS-238 +2887 ; [*0E3B.0020.0002] # BRAILLE PATTERN DOTS-1238 +2888 ; [*0E3C.0020.0002] # BRAILLE PATTERN DOTS-48 +2889 ; [*0E3D.0020.0002] # BRAILLE PATTERN DOTS-148 +288A ; [*0E3E.0020.0002] # BRAILLE PATTERN DOTS-248 +288B ; [*0E3F.0020.0002] # BRAILLE PATTERN DOTS-1248 +288C ; [*0E40.0020.0002] # BRAILLE PATTERN DOTS-348 +288D ; [*0E41.0020.0002] # BRAILLE PATTERN DOTS-1348 +288E ; [*0E42.0020.0002] # BRAILLE PATTERN DOTS-2348 +288F ; [*0E43.0020.0002] # BRAILLE PATTERN DOTS-12348 +2890 ; [*0E44.0020.0002] # BRAILLE PATTERN DOTS-58 +2891 ; [*0E45.0020.0002] # BRAILLE PATTERN DOTS-158 +2892 ; [*0E46.0020.0002] # BRAILLE PATTERN DOTS-258 +2893 ; [*0E47.0020.0002] # BRAILLE PATTERN DOTS-1258 +2894 ; [*0E48.0020.0002] # BRAILLE PATTERN DOTS-358 +2895 ; [*0E49.0020.0002] # BRAILLE PATTERN DOTS-1358 +2896 ; [*0E4A.0020.0002] # BRAILLE PATTERN DOTS-2358 +2897 ; [*0E4B.0020.0002] # BRAILLE PATTERN DOTS-12358 +2898 ; [*0E4C.0020.0002] # BRAILLE PATTERN DOTS-458 +2899 ; [*0E4D.0020.0002] # BRAILLE PATTERN DOTS-1458 +289A ; [*0E4E.0020.0002] # BRAILLE PATTERN DOTS-2458 +289B ; [*0E4F.0020.0002] # BRAILLE PATTERN DOTS-12458 +289C ; [*0E50.0020.0002] # BRAILLE PATTERN DOTS-3458 +289D ; [*0E51.0020.0002] # BRAILLE PATTERN DOTS-13458 +289E ; [*0E52.0020.0002] # BRAILLE PATTERN DOTS-23458 +289F ; [*0E53.0020.0002] # BRAILLE PATTERN DOTS-123458 +28A0 ; [*0E54.0020.0002] # BRAILLE PATTERN DOTS-68 +28A1 ; [*0E55.0020.0002] # BRAILLE PATTERN DOTS-168 +28A2 ; [*0E56.0020.0002] # BRAILLE PATTERN DOTS-268 +28A3 ; [*0E57.0020.0002] # BRAILLE PATTERN DOTS-1268 +28A4 ; [*0E58.0020.0002] # BRAILLE PATTERN DOTS-368 +28A5 ; [*0E59.0020.0002] # BRAILLE PATTERN DOTS-1368 +28A6 ; [*0E5A.0020.0002] # BRAILLE PATTERN DOTS-2368 +28A7 ; [*0E5B.0020.0002] # BRAILLE PATTERN DOTS-12368 +28A8 ; [*0E5C.0020.0002] # BRAILLE PATTERN DOTS-468 +28A9 ; [*0E5D.0020.0002] # BRAILLE PATTERN DOTS-1468 +28AA ; [*0E5E.0020.0002] # BRAILLE PATTERN DOTS-2468 +28AB ; [*0E5F.0020.0002] # BRAILLE PATTERN DOTS-12468 +28AC ; [*0E60.0020.0002] # BRAILLE PATTERN DOTS-3468 +28AD ; [*0E61.0020.0002] # BRAILLE PATTERN DOTS-13468 +28AE ; [*0E62.0020.0002] # BRAILLE PATTERN DOTS-23468 +28AF ; [*0E63.0020.0002] # BRAILLE PATTERN DOTS-123468 +28B0 ; [*0E64.0020.0002] # BRAILLE PATTERN DOTS-568 +28B1 ; [*0E65.0020.0002] # BRAILLE PATTERN DOTS-1568 +28B2 ; [*0E66.0020.0002] # BRAILLE PATTERN DOTS-2568 +28B3 ; [*0E67.0020.0002] # BRAILLE PATTERN DOTS-12568 +28B4 ; [*0E68.0020.0002] # BRAILLE PATTERN DOTS-3568 +28B5 ; [*0E69.0020.0002] # BRAILLE PATTERN DOTS-13568 +28B6 ; [*0E6A.0020.0002] # BRAILLE PATTERN DOTS-23568 +28B7 ; [*0E6B.0020.0002] # BRAILLE PATTERN DOTS-123568 +28B8 ; [*0E6C.0020.0002] # BRAILLE PATTERN DOTS-4568 +28B9 ; [*0E6D.0020.0002] # BRAILLE PATTERN DOTS-14568 +28BA ; [*0E6E.0020.0002] # BRAILLE PATTERN DOTS-24568 +28BB ; [*0E6F.0020.0002] # BRAILLE PATTERN DOTS-124568 +28BC ; [*0E70.0020.0002] # BRAILLE PATTERN DOTS-34568 +28BD ; [*0E71.0020.0002] # BRAILLE PATTERN DOTS-134568 +28BE ; [*0E72.0020.0002] # BRAILLE PATTERN DOTS-234568 +28BF ; [*0E73.0020.0002] # BRAILLE PATTERN DOTS-1234568 +28C0 ; [*0E74.0020.0002] # BRAILLE PATTERN DOTS-78 +28C1 ; [*0E75.0020.0002] # BRAILLE PATTERN DOTS-178 +28C2 ; [*0E76.0020.0002] # BRAILLE PATTERN DOTS-278 +28C3 ; [*0E77.0020.0002] # BRAILLE PATTERN DOTS-1278 +28C4 ; [*0E78.0020.0002] # BRAILLE PATTERN DOTS-378 +28C5 ; [*0E79.0020.0002] # BRAILLE PATTERN DOTS-1378 +28C6 ; [*0E7A.0020.0002] # BRAILLE PATTERN DOTS-2378 +28C7 ; [*0E7B.0020.0002] # BRAILLE PATTERN DOTS-12378 +28C8 ; [*0E7C.0020.0002] # BRAILLE PATTERN DOTS-478 +28C9 ; [*0E7D.0020.0002] # BRAILLE PATTERN DOTS-1478 +28CA ; [*0E7E.0020.0002] # BRAILLE PATTERN DOTS-2478 +28CB ; [*0E7F.0020.0002] # BRAILLE PATTERN DOTS-12478 +28CC ; [*0E80.0020.0002] # BRAILLE PATTERN DOTS-3478 +28CD ; [*0E81.0020.0002] # BRAILLE PATTERN DOTS-13478 +28CE ; [*0E82.0020.0002] # BRAILLE PATTERN DOTS-23478 +28CF ; [*0E83.0020.0002] # BRAILLE PATTERN DOTS-123478 +28D0 ; [*0E84.0020.0002] # BRAILLE PATTERN DOTS-578 +28D1 ; [*0E85.0020.0002] # BRAILLE PATTERN DOTS-1578 +28D2 ; [*0E86.0020.0002] # BRAILLE PATTERN DOTS-2578 +28D3 ; [*0E87.0020.0002] # BRAILLE PATTERN DOTS-12578 +28D4 ; [*0E88.0020.0002] # BRAILLE PATTERN DOTS-3578 +28D5 ; [*0E89.0020.0002] # BRAILLE PATTERN DOTS-13578 +28D6 ; [*0E8A.0020.0002] # BRAILLE PATTERN DOTS-23578 +28D7 ; [*0E8B.0020.0002] # BRAILLE PATTERN DOTS-123578 +28D8 ; [*0E8C.0020.0002] # BRAILLE PATTERN DOTS-4578 +28D9 ; [*0E8D.0020.0002] # BRAILLE PATTERN DOTS-14578 +28DA ; [*0E8E.0020.0002] # BRAILLE PATTERN DOTS-24578 +28DB ; [*0E8F.0020.0002] # BRAILLE PATTERN DOTS-124578 +28DC ; [*0E90.0020.0002] # BRAILLE PATTERN DOTS-34578 +28DD ; [*0E91.0020.0002] # BRAILLE PATTERN DOTS-134578 +28DE ; [*0E92.0020.0002] # BRAILLE PATTERN DOTS-234578 +28DF ; [*0E93.0020.0002] # BRAILLE PATTERN DOTS-1234578 +28E0 ; [*0E94.0020.0002] # BRAILLE PATTERN DOTS-678 +28E1 ; [*0E95.0020.0002] # BRAILLE PATTERN DOTS-1678 +28E2 ; [*0E96.0020.0002] # BRAILLE PATTERN DOTS-2678 +28E3 ; [*0E97.0020.0002] # BRAILLE PATTERN DOTS-12678 +28E4 ; [*0E98.0020.0002] # BRAILLE PATTERN DOTS-3678 +28E5 ; [*0E99.0020.0002] # BRAILLE PATTERN DOTS-13678 +28E6 ; [*0E9A.0020.0002] # BRAILLE PATTERN DOTS-23678 +28E7 ; [*0E9B.0020.0002] # BRAILLE PATTERN DOTS-123678 +28E8 ; [*0E9C.0020.0002] # BRAILLE PATTERN DOTS-4678 +28E9 ; [*0E9D.0020.0002] # BRAILLE PATTERN DOTS-14678 +28EA ; [*0E9E.0020.0002] # BRAILLE PATTERN DOTS-24678 +28EB ; [*0E9F.0020.0002] # BRAILLE PATTERN DOTS-124678 +28EC ; [*0EA0.0020.0002] # BRAILLE PATTERN DOTS-34678 +28ED ; [*0EA1.0020.0002] # BRAILLE PATTERN DOTS-134678 +28EE ; [*0EA2.0020.0002] # BRAILLE PATTERN DOTS-234678 +28EF ; [*0EA3.0020.0002] # BRAILLE PATTERN DOTS-1234678 +28F0 ; [*0EA4.0020.0002] # BRAILLE PATTERN DOTS-5678 +28F1 ; [*0EA5.0020.0002] # BRAILLE PATTERN DOTS-15678 +28F2 ; [*0EA6.0020.0002] # BRAILLE PATTERN DOTS-25678 +28F3 ; [*0EA7.0020.0002] # BRAILLE PATTERN DOTS-125678 +28F4 ; [*0EA8.0020.0002] # BRAILLE PATTERN DOTS-35678 +28F5 ; [*0EA9.0020.0002] # BRAILLE PATTERN DOTS-135678 +28F6 ; [*0EAA.0020.0002] # BRAILLE PATTERN DOTS-235678 +28F7 ; [*0EAB.0020.0002] # BRAILLE PATTERN DOTS-1235678 +28F8 ; [*0EAC.0020.0002] # BRAILLE PATTERN DOTS-45678 +28F9 ; [*0EAD.0020.0002] # BRAILLE PATTERN DOTS-145678 +28FA ; [*0EAE.0020.0002] # BRAILLE PATTERN DOTS-245678 +28FB ; [*0EAF.0020.0002] # BRAILLE PATTERN DOTS-1245678 +28FC ; [*0EB0.0020.0002] # BRAILLE PATTERN DOTS-345678 +28FD ; [*0EB1.0020.0002] # BRAILLE PATTERN DOTS-1345678 +28FE ; [*0EB2.0020.0002] # BRAILLE PATTERN DOTS-2345678 +28FF ; [*0EB3.0020.0002] # BRAILLE PATTERN DOTS-12345678 +2900 ; [*0B00.0020.0002] # RIGHTWARDS TWO-HEADED ARROW WITH VERTICAL STROKE +2901 ; [*0B01.0020.0002] # RIGHTWARDS TWO-HEADED ARROW WITH DOUBLE VERTICAL STROKE +2902 ; [*0B02.0020.0002] # LEFTWARDS DOUBLE ARROW WITH VERTICAL STROKE +2903 ; [*0B03.0020.0002] # RIGHTWARDS DOUBLE ARROW WITH VERTICAL STROKE +2904 ; [*0B04.0020.0002] # LEFT RIGHT DOUBLE ARROW WITH VERTICAL STROKE +2905 ; [*0B05.0020.0002] # RIGHTWARDS TWO-HEADED ARROW FROM BAR +2906 ; [*0B06.0020.0002] # LEFTWARDS DOUBLE ARROW FROM BAR +2907 ; [*0B07.0020.0002] # RIGHTWARDS DOUBLE ARROW FROM BAR +2908 ; [*0B08.0020.0002] # DOWNWARDS ARROW WITH HORIZONTAL STROKE +2909 ; [*0B09.0020.0002] # UPWARDS ARROW WITH HORIZONTAL STROKE +290A ; [*0B0A.0020.0002] # UPWARDS TRIPLE ARROW +290B ; [*0B0B.0020.0002] # DOWNWARDS TRIPLE ARROW +290C ; [*0B0C.0020.0002] # LEFTWARDS DOUBLE DASH ARROW +290D ; [*0B0D.0020.0002] # RIGHTWARDS DOUBLE DASH ARROW +290E ; [*0B0E.0020.0002] # LEFTWARDS TRIPLE DASH ARROW +290F ; [*0B0F.0020.0002] # RIGHTWARDS TRIPLE DASH ARROW +2910 ; [*0B10.0020.0002] # RIGHTWARDS TWO-HEADED TRIPLE DASH ARROW +2911 ; [*0B11.0020.0002] # RIGHTWARDS ARROW WITH DOTTED STEM +2912 ; [*0B12.0020.0002] # UPWARDS ARROW TO BAR +2913 ; [*0B13.0020.0002] # DOWNWARDS ARROW TO BAR +2914 ; [*0B14.0020.0002] # RIGHTWARDS ARROW WITH TAIL WITH VERTICAL STROKE +2915 ; [*0B15.0020.0002] # RIGHTWARDS ARROW WITH TAIL WITH DOUBLE VERTICAL STROKE +2916 ; [*0B16.0020.0002] # RIGHTWARDS TWO-HEADED ARROW WITH TAIL +2917 ; [*0B17.0020.0002] # RIGHTWARDS TWO-HEADED ARROW WITH TAIL WITH VERTICAL STROKE +2918 ; [*0B18.0020.0002] # RIGHTWARDS TWO-HEADED ARROW WITH TAIL WITH DOUBLE VERTICAL STROKE +2919 ; [*0B19.0020.0002] # LEFTWARDS ARROW-TAIL +291A ; [*0B1A.0020.0002] # RIGHTWARDS ARROW-TAIL +291B ; [*0B1B.0020.0002] # LEFTWARDS DOUBLE ARROW-TAIL +291C ; [*0B1C.0020.0002] # RIGHTWARDS DOUBLE ARROW-TAIL +291D ; [*0B1D.0020.0002] # LEFTWARDS ARROW TO BLACK DIAMOND +291E ; [*0B1E.0020.0002] # RIGHTWARDS ARROW TO BLACK DIAMOND +291F ; [*0B1F.0020.0002] # LEFTWARDS ARROW FROM BAR TO BLACK DIAMOND +2920 ; [*0B20.0020.0002] # RIGHTWARDS ARROW FROM BAR TO BLACK DIAMOND +2921 ; [*0B21.0020.0002] # NORTH WEST AND SOUTH EAST ARROW +2922 ; [*0B22.0020.0002] # NORTH EAST AND SOUTH WEST ARROW +2923 ; [*0B23.0020.0002] # NORTH WEST ARROW WITH HOOK +2924 ; [*0B24.0020.0002] # NORTH EAST ARROW WITH HOOK +2925 ; [*0B25.0020.0002] # SOUTH EAST ARROW WITH HOOK +2926 ; [*0B26.0020.0002] # SOUTH WEST ARROW WITH HOOK +2927 ; [*0B27.0020.0002] # NORTH WEST ARROW AND NORTH EAST ARROW +2928 ; [*0B28.0020.0002] # NORTH EAST ARROW AND SOUTH EAST ARROW +2929 ; [*0B29.0020.0002] # SOUTH EAST ARROW AND SOUTH WEST ARROW +292A ; [*0B2A.0020.0002] # SOUTH WEST ARROW AND NORTH WEST ARROW +292B ; [*0B2B.0020.0002] # RISING DIAGONAL CROSSING FALLING DIAGONAL +292C ; [*0B2C.0020.0002] # FALLING DIAGONAL CROSSING RISING DIAGONAL +292D ; [*0B2D.0020.0002] # SOUTH EAST ARROW CROSSING NORTH EAST ARROW +292E ; [*0B2E.0020.0002] # NORTH EAST ARROW CROSSING SOUTH EAST ARROW +292F ; [*0B2F.0020.0002] # FALLING DIAGONAL CROSSING NORTH EAST ARROW +2930 ; [*0B30.0020.0002] # RISING DIAGONAL CROSSING SOUTH EAST ARROW +2931 ; [*0B31.0020.0002] # NORTH EAST ARROW CROSSING NORTH WEST ARROW +2932 ; [*0B32.0020.0002] # NORTH WEST ARROW CROSSING NORTH EAST ARROW +2933 ; [*0B33.0020.0002] # WAVE ARROW POINTING DIRECTLY RIGHT +2934 ; [*0B34.0020.0002] # ARROW POINTING RIGHTWARDS THEN CURVING UPWARDS +2935 ; [*0B35.0020.0002] # ARROW POINTING RIGHTWARDS THEN CURVING DOWNWARDS +2936 ; [*0B36.0020.0002] # ARROW POINTING DOWNWARDS THEN CURVING LEFTWARDS +2937 ; [*0B37.0020.0002] # ARROW POINTING DOWNWARDS THEN CURVING RIGHTWARDS +2938 ; [*0B38.0020.0002] # RIGHT-SIDE ARC CLOCKWISE ARROW +2939 ; [*0B39.0020.0002] # LEFT-SIDE ARC ANTICLOCKWISE ARROW +293A ; [*0B3A.0020.0002] # TOP ARC ANTICLOCKWISE ARROW +293B ; [*0B3B.0020.0002] # BOTTOM ARC ANTICLOCKWISE ARROW +293C ; [*0B3C.0020.0002] # TOP ARC CLOCKWISE ARROW WITH MINUS +293D ; [*0B3D.0020.0002] # TOP ARC ANTICLOCKWISE ARROW WITH PLUS +293E ; [*0B3E.0020.0002] # LOWER RIGHT SEMICIRCULAR CLOCKWISE ARROW +293F ; [*0B3F.0020.0002] # LOWER LEFT SEMICIRCULAR ANTICLOCKWISE ARROW +2940 ; [*0B40.0020.0002] # ANTICLOCKWISE CLOSED CIRCLE ARROW +2941 ; [*0B41.0020.0002] # CLOCKWISE CLOSED CIRCLE ARROW +2942 ; [*0B42.0020.0002] # RIGHTWARDS ARROW ABOVE SHORT LEFTWARDS ARROW +2943 ; [*0B43.0020.0002] # LEFTWARDS ARROW ABOVE SHORT RIGHTWARDS ARROW +2944 ; [*0B44.0020.0002] # SHORT RIGHTWARDS ARROW ABOVE LEFTWARDS ARROW +2945 ; [*0B45.0020.0002] # RIGHTWARDS ARROW WITH PLUS BELOW +2946 ; [*0B46.0020.0002] # LEFTWARDS ARROW WITH PLUS BELOW +2947 ; [*0B47.0020.0002] # RIGHTWARDS ARROW THROUGH X +2948 ; [*0B48.0020.0002] # LEFT RIGHT ARROW THROUGH SMALL CIRCLE +2949 ; [*0B49.0020.0002] # UPWARDS TWO-HEADED ARROW FROM SMALL CIRCLE +294A ; [*0B4A.0020.0002] # LEFT BARB UP RIGHT BARB DOWN HARPOON +294B ; [*0B4B.0020.0002] # LEFT BARB DOWN RIGHT BARB UP HARPOON +294C ; [*0B4C.0020.0002] # UP BARB RIGHT DOWN BARB LEFT HARPOON +294D ; [*0B4D.0020.0002] # UP BARB LEFT DOWN BARB RIGHT HARPOON +294E ; [*0B4E.0020.0002] # LEFT BARB UP RIGHT BARB UP HARPOON +294F ; [*0B4F.0020.0002] # UP BARB RIGHT DOWN BARB RIGHT HARPOON +2950 ; [*0B50.0020.0002] # LEFT BARB DOWN RIGHT BARB DOWN HARPOON +2951 ; [*0B51.0020.0002] # UP BARB LEFT DOWN BARB LEFT HARPOON +2952 ; [*0B52.0020.0002] # LEFTWARDS HARPOON WITH BARB UP TO BAR +2953 ; [*0B53.0020.0002] # RIGHTWARDS HARPOON WITH BARB UP TO BAR +2954 ; [*0B54.0020.0002] # UPWARDS HARPOON WITH BARB RIGHT TO BAR +2955 ; [*0B55.0020.0002] # DOWNWARDS HARPOON WITH BARB RIGHT TO BAR +2956 ; [*0B56.0020.0002] # LEFTWARDS HARPOON WITH BARB DOWN TO BAR +2957 ; [*0B57.0020.0002] # RIGHTWARDS HARPOON WITH BARB DOWN TO BAR +2958 ; [*0B58.0020.0002] # UPWARDS HARPOON WITH BARB LEFT TO BAR +2959 ; [*0B59.0020.0002] # DOWNWARDS HARPOON WITH BARB LEFT TO BAR +295A ; [*0B5A.0020.0002] # LEFTWARDS HARPOON WITH BARB UP FROM BAR +295B ; [*0B5B.0020.0002] # RIGHTWARDS HARPOON WITH BARB UP FROM BAR +295C ; [*0B5C.0020.0002] # UPWARDS HARPOON WITH BARB RIGHT FROM BAR +295D ; [*0B5D.0020.0002] # DOWNWARDS HARPOON WITH BARB RIGHT FROM BAR +295E ; [*0B5E.0020.0002] # LEFTWARDS HARPOON WITH BARB DOWN FROM BAR +295F ; [*0B5F.0020.0002] # RIGHTWARDS HARPOON WITH BARB DOWN FROM BAR +2960 ; [*0B60.0020.0002] # UPWARDS HARPOON WITH BARB LEFT FROM BAR +2961 ; [*0B61.0020.0002] # DOWNWARDS HARPOON WITH BARB LEFT FROM BAR +2962 ; [*0B62.0020.0002] # LEFTWARDS HARPOON WITH BARB UP ABOVE LEFTWARDS HARPOON WITH BARB DOWN +2963 ; [*0B63.0020.0002] # UPWARDS HARPOON WITH BARB LEFT BESIDE UPWARDS HARPOON WITH BARB RIGHT +2964 ; [*0B64.0020.0002] # RIGHTWARDS HARPOON WITH BARB UP ABOVE RIGHTWARDS HARPOON WITH BARB DOWN +2965 ; [*0B65.0020.0002] # DOWNWARDS HARPOON WITH BARB LEFT BESIDE DOWNWARDS HARPOON WITH BARB RIGHT +2966 ; [*0B66.0020.0002] # LEFTWARDS HARPOON WITH BARB UP ABOVE RIGHTWARDS HARPOON WITH BARB UP +2967 ; [*0B67.0020.0002] # LEFTWARDS HARPOON WITH BARB DOWN ABOVE RIGHTWARDS HARPOON WITH BARB DOWN +2968 ; [*0B68.0020.0002] # RIGHTWARDS HARPOON WITH BARB UP ABOVE LEFTWARDS HARPOON WITH BARB UP +2969 ; [*0B69.0020.0002] # RIGHTWARDS HARPOON WITH BARB DOWN ABOVE LEFTWARDS HARPOON WITH BARB DOWN +296A ; [*0B6A.0020.0002] # LEFTWARDS HARPOON WITH BARB UP ABOVE LONG DASH +296B ; [*0B6B.0020.0002] # LEFTWARDS HARPOON WITH BARB DOWN BELOW LONG DASH +296C ; [*0B6C.0020.0002] # RIGHTWARDS HARPOON WITH BARB UP ABOVE LONG DASH +296D ; [*0B6D.0020.0002] # RIGHTWARDS HARPOON WITH BARB DOWN BELOW LONG DASH +296E ; [*0B6E.0020.0002] # UPWARDS HARPOON WITH BARB LEFT BESIDE DOWNWARDS HARPOON WITH BARB RIGHT +296F ; [*0B6F.0020.0002] # DOWNWARDS HARPOON WITH BARB LEFT BESIDE UPWARDS HARPOON WITH BARB RIGHT +2970 ; [*0B70.0020.0002] # RIGHT DOUBLE ARROW WITH ROUNDED HEAD +2971 ; [*0B71.0020.0002] # EQUALS SIGN ABOVE RIGHTWARDS ARROW +2972 ; [*0B72.0020.0002] # TILDE OPERATOR ABOVE RIGHTWARDS ARROW +2973 ; [*0B73.0020.0002] # LEFTWARDS ARROW ABOVE TILDE OPERATOR +2974 ; [*0B74.0020.0002] # RIGHTWARDS ARROW ABOVE TILDE OPERATOR +2975 ; [*0B75.0020.0002] # RIGHTWARDS ARROW ABOVE ALMOST EQUAL TO +2976 ; [*0B76.0020.0002] # LESS-THAN ABOVE LEFTWARDS ARROW +2977 ; [*0B77.0020.0002] # LEFTWARDS ARROW THROUGH LESS-THAN +2978 ; [*0B78.0020.0002] # GREATER-THAN ABOVE RIGHTWARDS ARROW +2979 ; [*0B79.0020.0002] # SUBSET ABOVE RIGHTWARDS ARROW +297A ; [*0B7A.0020.0002] # LEFTWARDS ARROW THROUGH SUBSET +297B ; [*0B7B.0020.0002] # SUPERSET ABOVE LEFTWARDS ARROW +297C ; [*0B7C.0020.0002] # LEFT FISH TAIL +297D ; [*0B7D.0020.0002] # RIGHT FISH TAIL +297E ; [*0B7E.0020.0002] # UP FISH TAIL +297F ; [*0B7F.0020.0002] # DOWN FISH TAIL +2980 ; [*0B80.0020.0002] # TRIPLE VERTICAL BAR DELIMITER +2981 ; [*0B81.0020.0002] # Z NOTATION SPOT +2982 ; [*0B82.0020.0002] # Z NOTATION TYPE COLON +2983 ; [*032C.0020.0002] # LEFT WHITE CURLY BRACKET +2984 ; [*032D.0020.0002] # RIGHT WHITE CURLY BRACKET +2985 ; [*032E.0020.0002] # LEFT WHITE PARENTHESIS +2986 ; [*032F.0020.0002] # RIGHT WHITE PARENTHESIS +2987 ; [*0330.0020.0002] # Z NOTATION LEFT IMAGE BRACKET +2988 ; [*0331.0020.0002] # Z NOTATION RIGHT IMAGE BRACKET +2989 ; [*0332.0020.0002] # Z NOTATION LEFT BINDING BRACKET +298A ; [*0333.0020.0002] # Z NOTATION RIGHT BINDING BRACKET +298B ; [*0334.0020.0002] # LEFT SQUARE BRACKET WITH UNDERBAR +298C ; [*0335.0020.0002] # RIGHT SQUARE BRACKET WITH UNDERBAR +298D ; [*0336.0020.0002] # LEFT SQUARE BRACKET WITH TICK IN TOP CORNER +298E ; [*0337.0020.0002] # RIGHT SQUARE BRACKET WITH TICK IN BOTTOM CORNER +298F ; [*0338.0020.0002] # LEFT SQUARE BRACKET WITH TICK IN BOTTOM CORNER +2990 ; [*0339.0020.0002] # RIGHT SQUARE BRACKET WITH TICK IN TOP CORNER +2991 ; [*033A.0020.0002] # LEFT ANGLE BRACKET WITH DOT +2992 ; [*033B.0020.0002] # RIGHT ANGLE BRACKET WITH DOT +2993 ; [*033C.0020.0002] # LEFT ARC LESS-THAN BRACKET +2994 ; [*033D.0020.0002] # RIGHT ARC GREATER-THAN BRACKET +2995 ; [*033E.0020.0002] # DOUBLE LEFT ARC GREATER-THAN BRACKET +2996 ; [*033F.0020.0002] # DOUBLE RIGHT ARC LESS-THAN BRACKET +2997 ; [*0340.0020.0002] # LEFT BLACK TORTOISE SHELL BRACKET +2998 ; [*0341.0020.0002] # RIGHT BLACK TORTOISE SHELL BRACKET +2999 ; [*0B83.0020.0002] # DOTTED FENCE +299A ; [*0B84.0020.0002] # VERTICAL ZIGZAG LINE +299B ; [*0B85.0020.0002] # MEASURED ANGLE OPENING LEFT +299C ; [*0B86.0020.0002] # RIGHT ANGLE VARIANT WITH SQUARE +299D ; [*0B87.0020.0002] # MEASURED RIGHT ANGLE WITH DOT +299E ; [*0B88.0020.0002] # ANGLE WITH S INSIDE +299F ; [*0B89.0020.0002] # ACUTE ANGLE +29A0 ; [*0B8A.0020.0002] # SPHERICAL ANGLE OPENING LEFT +29A1 ; [*0B8B.0020.0002] # SPHERICAL ANGLE OPENING UP +29A2 ; [*0B8C.0020.0002] # TURNED ANGLE +29A3 ; [*0B8D.0020.0002] # REVERSED ANGLE +29A4 ; [*0B8E.0020.0002] # ANGLE WITH UNDERBAR +29A5 ; [*0B8F.0020.0002] # REVERSED ANGLE WITH UNDERBAR +29A6 ; [*0B90.0020.0002] # OBLIQUE ANGLE OPENING UP +29A7 ; [*0B91.0020.0002] # OBLIQUE ANGLE OPENING DOWN +29A8 ; [*0B92.0020.0002] # MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING UP AND RIGHT +29A9 ; [*0B93.0020.0002] # MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING UP AND LEFT +29AA ; [*0B94.0020.0002] # MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING DOWN AND RIGHT +29AB ; [*0B95.0020.0002] # MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING DOWN AND LEFT +29AC ; [*0B96.0020.0002] # MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING RIGHT AND UP +29AD ; [*0B97.0020.0002] # MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING LEFT AND UP +29AE ; [*0B98.0020.0002] # MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING RIGHT AND DOWN +29AF ; [*0B99.0020.0002] # MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING LEFT AND DOWN +29B0 ; [*0B9A.0020.0002] # REVERSED EMPTY SET +29B1 ; [*0B9B.0020.0002] # EMPTY SET WITH OVERBAR +29B2 ; [*0B9C.0020.0002] # EMPTY SET WITH SMALL CIRCLE ABOVE +29B3 ; [*0B9D.0020.0002] # EMPTY SET WITH RIGHT ARROW ABOVE +29B4 ; [*0B9E.0020.0002] # EMPTY SET WITH LEFT ARROW ABOVE +29B5 ; [*0B9F.0020.0002] # CIRCLE WITH HORIZONTAL BAR +29B6 ; [*0BA0.0020.0002] # CIRCLED VERTICAL BAR +29B7 ; [*0BA1.0020.0002] # CIRCLED PARALLEL +29B8 ; [*0BA2.0020.0002] # CIRCLED REVERSE SOLIDUS +29B9 ; [*0BA3.0020.0002] # CIRCLED PERPENDICULAR +29BA ; [*0BA4.0020.0002] # CIRCLE DIVIDED BY HORIZONTAL BAR AND TOP HALF DIVIDED BY VERTICAL BAR +29BB ; [*0BA5.0020.0002] # CIRCLE WITH SUPERIMPOSED X +29BC ; [*0BA6.0020.0002] # CIRCLED ANTICLOCKWISE-ROTATED DIVISION SIGN +29BD ; [*0BA7.0020.0002] # UP ARROW THROUGH CIRCLE +29BE ; [*0BA8.0020.0002] # CIRCLED WHITE BULLET +29BF ; [*0BA9.0020.0002] # CIRCLED BULLET +29C0 ; [*0BAA.0020.0002] # CIRCLED LESS-THAN +29C1 ; [*0BAB.0020.0002] # CIRCLED GREATER-THAN +29C2 ; [*0BAC.0020.0002] # CIRCLE WITH SMALL CIRCLE TO THE RIGHT +29C3 ; [*0BAD.0020.0002] # CIRCLE WITH TWO HORIZONTAL STROKES TO THE RIGHT +29C4 ; [*0BAE.0020.0002] # SQUARED RISING DIAGONAL SLASH +29C5 ; [*0BAF.0020.0002] # SQUARED FALLING DIAGONAL SLASH +29C6 ; [*0BB0.0020.0002] # SQUARED ASTERISK +29C7 ; [*0BB1.0020.0002] # SQUARED SMALL CIRCLE +29C8 ; [*0BB2.0020.0002] # SQUARED SQUARE +29C9 ; [*0BB3.0020.0002] # TWO JOINED SQUARES +29CA ; [*0BB4.0020.0002] # TRIANGLE WITH DOT ABOVE +29CB ; [*0BB5.0020.0002] # TRIANGLE WITH UNDERBAR +29CC ; [*0BB6.0020.0002] # S IN TRIANGLE +29CD ; [*0BB7.0020.0002] # TRIANGLE WITH SERIFS AT BOTTOM +29CE ; [*0BB8.0020.0002] # RIGHT TRIANGLE ABOVE LEFT TRIANGLE +29CF ; [*0BB9.0020.0002] # LEFT TRIANGLE BESIDE VERTICAL BAR +29D0 ; [*0BBA.0020.0002] # VERTICAL BAR BESIDE RIGHT TRIANGLE +29D1 ; [*0BBB.0020.0002] # BOWTIE WITH LEFT HALF BLACK +29D2 ; [*0BBC.0020.0002] # BOWTIE WITH RIGHT HALF BLACK +29D3 ; [*0BBD.0020.0002] # BLACK BOWTIE +29D4 ; [*0BBE.0020.0002] # TIMES WITH LEFT HALF BLACK +29D5 ; [*0BBF.0020.0002] # TIMES WITH RIGHT HALF BLACK +29D6 ; [*0BC0.0020.0002] # WHITE HOURGLASS +29D7 ; [*0BC1.0020.0002] # BLACK HOURGLASS +29D8 ; [*0386.0020.0002] # LEFT WIGGLY FENCE +29D9 ; [*0387.0020.0002] # RIGHT WIGGLY FENCE +29DA ; [*0388.0020.0002] # LEFT DOUBLE WIGGLY FENCE +29DB ; [*0389.0020.0002] # RIGHT DOUBLE WIGGLY FENCE +29DC ; [*0BC2.0020.0002] # INCOMPLETE INFINITY +29DD ; [*0BC3.0020.0002] # TIE OVER INFINITY +29DE ; [*0BC4.0020.0002] # INFINITY NEGATED WITH VERTICAL BAR +29DF ; [*0BC5.0020.0002] # DOUBLE-ENDED MULTIMAP +29E0 ; [*0BC6.0020.0002] # SQUARE WITH CONTOURED OUTLINE +29E1 ; [*0BC7.0020.0002] # INCREASES AS +29E2 ; [*0BC8.0020.0002] # SHUFFLE PRODUCT +29E3 ; [*0BC9.0020.0002] # EQUALS SIGN AND SLANTED PARALLEL +29E4 ; [*0BCA.0020.0002] # EQUALS SIGN AND SLANTED PARALLEL WITH TILDE ABOVE +29E5 ; [*0BCB.0020.0002] # IDENTICAL TO AND SLANTED PARALLEL +29E6 ; [*0BCC.0020.0002] # GLEICH STARK +29E7 ; [*0BCD.0020.0002] # THERMODYNAMIC +29E8 ; [*0BCE.0020.0002] # DOWN-POINTING TRIANGLE WITH LEFT HALF BLACK +29E9 ; [*0BCF.0020.0002] # DOWN-POINTING TRIANGLE WITH RIGHT HALF BLACK +29EA ; [*0BD0.0020.0002] # BLACK DIAMOND WITH DOWN ARROW +29EB ; [*0BD1.0020.0002] # BLACK LOZENGE +29EC ; [*0BD2.0020.0002] # WHITE CIRCLE WITH DOWN ARROW +29ED ; [*0BD3.0020.0002] # BLACK CIRCLE WITH DOWN ARROW +29EE ; [*0BD4.0020.0002] # ERROR-BARRED WHITE SQUARE +29EF ; [*0BD5.0020.0002] # ERROR-BARRED BLACK SQUARE +29F0 ; [*0BD6.0020.0002] # ERROR-BARRED WHITE DIAMOND +29F1 ; [*0BD7.0020.0002] # ERROR-BARRED BLACK DIAMOND +29F2 ; [*0BD8.0020.0002] # ERROR-BARRED WHITE CIRCLE +29F3 ; [*0BD9.0020.0002] # ERROR-BARRED BLACK CIRCLE +29F4 ; [*0BDA.0020.0002] # RULE-DELAYED +29F5 ; [*0BDB.0020.0002] # REVERSE SOLIDUS OPERATOR +29F6 ; [*0BDC.0020.0002] # SOLIDUS WITH OVERBAR +29F7 ; [*0BDD.0020.0002] # REVERSE SOLIDUS WITH HORIZONTAL STROKE +29F8 ; [*0BDE.0020.0002] # BIG SOLIDUS +29F9 ; [*0BDF.0020.0002] # BIG REVERSE SOLIDUS +29FA ; [*0BE0.0020.0002] # DOUBLE PLUS +29FB ; [*0BE1.0020.0002] # TRIPLE PLUS +29FC ; [*032A.0020.0002] # LEFT-POINTING CURVED ANGLE BRACKET +29FD ; [*032B.0020.0002] # RIGHT-POINTING CURVED ANGLE BRACKET +29FE ; [*0BE2.0020.0002] # TINY +29FF ; [*0BE3.0020.0002] # MINY +2A00 ; [*0BE4.0020.0002] # N-ARY CIRCLED DOT OPERATOR +2A01 ; [*0BE5.0020.0002] # N-ARY CIRCLED PLUS OPERATOR +2A02 ; [*0BE6.0020.0002] # N-ARY CIRCLED TIMES OPERATOR +2A03 ; [*0BE7.0020.0002] # N-ARY UNION OPERATOR WITH DOT +2A04 ; [*0BE8.0020.0002] # N-ARY UNION OPERATOR WITH PLUS +2A05 ; [*0BE9.0020.0002] # N-ARY SQUARE INTERSECTION OPERATOR +2A06 ; [*0BEA.0020.0002] # N-ARY SQUARE UNION OPERATOR +2A07 ; [*0BEB.0020.0002] # TWO LOGICAL AND OPERATOR +2A08 ; [*0BEC.0020.0002] # TWO LOGICAL OR OPERATOR +2A09 ; [*0BED.0020.0002] # N-ARY TIMES OPERATOR +2A0A ; [*0BEE.0020.0002] # MODULO TWO SUM +2A0B ; [*0BEF.0020.0002] # SUMMATION WITH INTEGRAL +2A0C ; [*0652.0020.0004][*0652.0020.0004][*0652.0020.0004][*0652.0020.0004] # QUADRUPLE INTEGRAL OPERATOR +2A0D ; [*0BF0.0020.0002] # FINITE PART INTEGRAL +2A0E ; [*0BF1.0020.0002] # INTEGRAL WITH DOUBLE STROKE +2A0F ; [*0BF2.0020.0002] # INTEGRAL AVERAGE WITH SLASH +2A10 ; [*0BF3.0020.0002] # CIRCULATION FUNCTION +2A11 ; [*0BF4.0020.0002] # ANTICLOCKWISE INTEGRATION +2A12 ; [*0BF5.0020.0002] # LINE INTEGRATION WITH RECTANGULAR PATH AROUND POLE +2A13 ; [*0BF6.0020.0002] # LINE INTEGRATION WITH SEMICIRCULAR PATH AROUND POLE +2A14 ; [*0BF7.0020.0002] # LINE INTEGRATION NOT INCLUDING THE POLE +2A15 ; [*0BF8.0020.0002] # INTEGRAL AROUND A POINT OPERATOR +2A16 ; [*0BF9.0020.0002] # QUATERNION INTEGRAL OPERATOR +2A17 ; [*0BFA.0020.0002] # INTEGRAL WITH LEFTWARDS ARROW WITH HOOK +2A18 ; [*0BFB.0020.0002] # INTEGRAL WITH TIMES SIGN +2A19 ; [*0BFC.0020.0002] # INTEGRAL WITH INTERSECTION +2A1A ; [*0BFD.0020.0002] # INTEGRAL WITH UNION +2A1B ; [*0BFE.0020.0002] # INTEGRAL WITH OVERBAR +2A1C ; [*0BFF.0020.0002] # INTEGRAL WITH UNDERBAR +2A1D ; [*0C00.0020.0002] # JOIN +2A1E ; [*0C01.0020.0002] # LARGE LEFT TRIANGLE OPERATOR +2A1F ; [*0C02.0020.0002] # Z NOTATION SCHEMA COMPOSITION +2A20 ; [*0C03.0020.0002] # Z NOTATION SCHEMA PIPING +2A21 ; [*0C04.0020.0002] # Z NOTATION SCHEMA PROJECTION +2A22 ; [*0C05.0020.0002] # PLUS SIGN WITH SMALL CIRCLE ABOVE +2A23 ; [*0C06.0020.0002] # PLUS SIGN WITH CIRCUMFLEX ACCENT ABOVE +2A24 ; [*0C07.0020.0002] # PLUS SIGN WITH TILDE ABOVE +2A25 ; [*0C08.0020.0002] # PLUS SIGN WITH DOT BELOW +2A26 ; [*0C09.0020.0002] # PLUS SIGN WITH TILDE BELOW +2A27 ; [*0C0A.0020.0002] # PLUS SIGN WITH SUBSCRIPT TWO +2A28 ; [*0C0B.0020.0002] # PLUS SIGN WITH BLACK TRIANGLE +2A29 ; [*0C0C.0020.0002] # MINUS SIGN WITH COMMA ABOVE +2A2A ; [*0C0D.0020.0002] # MINUS SIGN WITH DOT BELOW +2A2B ; [*0C0E.0020.0002] # MINUS SIGN WITH FALLING DOTS +2A2C ; [*0C0F.0020.0002] # MINUS SIGN WITH RISING DOTS +2A2D ; [*0C10.0020.0002] # PLUS SIGN IN LEFT HALF CIRCLE +2A2E ; [*0C11.0020.0002] # PLUS SIGN IN RIGHT HALF CIRCLE +2A2F ; [*0C12.0020.0002] # VECTOR OR CROSS PRODUCT +2A30 ; [*0C13.0020.0002] # MULTIPLICATION SIGN WITH DOT ABOVE +2A31 ; [*0C14.0020.0002] # MULTIPLICATION SIGN WITH UNDERBAR +2A32 ; [*0C15.0020.0002] # SEMIDIRECT PRODUCT WITH BOTTOM CLOSED +2A33 ; [*0C16.0020.0002] # SMASH PRODUCT +2A34 ; [*0C17.0020.0002] # MULTIPLICATION SIGN IN LEFT HALF CIRCLE +2A35 ; [*0C18.0020.0002] # MULTIPLICATION SIGN IN RIGHT HALF CIRCLE +2A36 ; [*0C19.0020.0002] # CIRCLED MULTIPLICATION SIGN WITH CIRCUMFLEX ACCENT +2A37 ; [*0C1A.0020.0002] # MULTIPLICATION SIGN IN DOUBLE CIRCLE +2A38 ; [*0C1B.0020.0002] # CIRCLED DIVISION SIGN +2A39 ; [*0C1C.0020.0002] # PLUS SIGN IN TRIANGLE +2A3A ; [*0C1D.0020.0002] # MINUS SIGN IN TRIANGLE +2A3B ; [*0C1E.0020.0002] # MULTIPLICATION SIGN IN TRIANGLE +2A3C ; [*0C1F.0020.0002] # INTERIOR PRODUCT +2A3D ; [*0C20.0020.0002] # RIGHTHAND INTERIOR PRODUCT +2A3E ; [*0C21.0020.0002] # Z NOTATION RELATIONAL COMPOSITION +2A3F ; [*0C22.0020.0002] # AMALGAMATION OR COPRODUCT +2A40 ; [*0C23.0020.0002] # INTERSECTION WITH DOT +2A41 ; [*0C24.0020.0002] # UNION WITH MINUS SIGN +2A42 ; [*0C25.0020.0002] # UNION WITH OVERBAR +2A43 ; [*0C26.0020.0002] # INTERSECTION WITH OVERBAR +2A44 ; [*0C27.0020.0002] # INTERSECTION WITH LOGICAL AND +2A45 ; [*0C28.0020.0002] # UNION WITH LOGICAL OR +2A46 ; [*0C29.0020.0002] # UNION ABOVE INTERSECTION +2A47 ; [*0C2A.0020.0002] # INTERSECTION ABOVE UNION +2A48 ; [*0C2B.0020.0002] # UNION ABOVE BAR ABOVE INTERSECTION +2A49 ; [*0C2C.0020.0002] # INTERSECTION ABOVE BAR ABOVE UNION +2A4A ; [*0C2D.0020.0002] # UNION BESIDE AND JOINED WITH UNION +2A4B ; [*0C2E.0020.0002] # INTERSECTION BESIDE AND JOINED WITH INTERSECTION +2A4C ; [*0C2F.0020.0002] # CLOSED UNION WITH SERIFS +2A4D ; [*0C30.0020.0002] # CLOSED INTERSECTION WITH SERIFS +2A4E ; [*0C31.0020.0002] # DOUBLE SQUARE INTERSECTION +2A4F ; [*0C32.0020.0002] # DOUBLE SQUARE UNION +2A50 ; [*0C33.0020.0002] # CLOSED UNION WITH SERIFS AND SMASH PRODUCT +2A51 ; [*0C34.0020.0002] # LOGICAL AND WITH DOT ABOVE +2A52 ; [*0C35.0020.0002] # LOGICAL OR WITH DOT ABOVE +2A53 ; [*0C36.0020.0002] # DOUBLE LOGICAL AND +2A54 ; [*0C37.0020.0002] # DOUBLE LOGICAL OR +2A55 ; [*0C38.0020.0002] # TWO INTERSECTING LOGICAL AND +2A56 ; [*0C39.0020.0002] # TWO INTERSECTING LOGICAL OR +2A57 ; [*0C3A.0020.0002] # SLOPING LARGE OR +2A58 ; [*0C3B.0020.0002] # SLOPING LARGE AND +2A59 ; [*0C3C.0020.0002] # LOGICAL OR OVERLAPPING LOGICAL AND +2A5A ; [*0C3D.0020.0002] # LOGICAL AND WITH MIDDLE STEM +2A5B ; [*0C3E.0020.0002] # LOGICAL OR WITH MIDDLE STEM +2A5C ; [*0C3F.0020.0002] # LOGICAL AND WITH HORIZONTAL DASH +2A5D ; [*0C40.0020.0002] # LOGICAL OR WITH HORIZONTAL DASH +2A5E ; [*0C41.0020.0002] # LOGICAL AND WITH DOUBLE OVERBAR +2A5F ; [*0C42.0020.0002] # LOGICAL AND WITH UNDERBAR +2A60 ; [*0C43.0020.0002] # LOGICAL AND WITH DOUBLE UNDERBAR +2A61 ; [*0C44.0020.0002] # SMALL VEE WITH UNDERBAR +2A62 ; [*0C45.0020.0002] # LOGICAL OR WITH DOUBLE OVERBAR +2A63 ; [*0C46.0020.0002] # LOGICAL OR WITH DOUBLE UNDERBAR +2A64 ; [*0C47.0020.0002] # Z NOTATION DOMAIN ANTIRESTRICTION +2A65 ; [*0C48.0020.0002] # Z NOTATION RANGE ANTIRESTRICTION +2A66 ; [*0C49.0020.0002] # EQUALS SIGN WITH DOT BELOW +2A67 ; [*0C4A.0020.0002] # IDENTICAL WITH DOT ABOVE +2A68 ; [*0C4B.0020.0002] # TRIPLE HORIZONTAL BAR WITH DOUBLE VERTICAL STROKE +2A69 ; [*0C4C.0020.0002] # TRIPLE HORIZONTAL BAR WITH TRIPLE VERTICAL STROKE +2A6A ; [*0C4D.0020.0002] # TILDE OPERATOR WITH DOT ABOVE +2A6B ; [*0C4E.0020.0002] # TILDE OPERATOR WITH RISING DOTS +2A6C ; [*0C4F.0020.0002] # SIMILAR MINUS SIMILAR +2A6D ; [*0C50.0020.0002] # CONGRUENT WITH DOT ABOVE +2A6E ; [*0C51.0020.0002] # EQUALS WITH ASTERISK +2A6F ; [*0C52.0020.0002] # ALMOST EQUAL TO WITH CIRCUMFLEX ACCENT +2A70 ; [*0C53.0020.0002] # APPROXIMATELY EQUAL OR EQUAL TO +2A71 ; [*0C54.0020.0002] # EQUALS SIGN ABOVE PLUS SIGN +2A72 ; [*0C55.0020.0002] # PLUS SIGN ABOVE EQUALS SIGN +2A73 ; [*0C56.0020.0002] # EQUALS SIGN ABOVE TILDE OPERATOR +2A74 ; [*023A.0020.0004][*023A.0020.0004][*0631.0020.0004] # DOUBLE COLON EQUAL +2A75 ; [*0631.0020.0004][*0631.0020.0004] # TWO CONSECUTIVE EQUALS SIGNS +2A76 ; [*0631.0020.0004][*0631.0020.0004][*0631.0020.0004] # THREE CONSECUTIVE EQUALS SIGNS +2A77 ; [*0C57.0020.0002] # EQUALS SIGN WITH TWO DOTS ABOVE AND TWO DOTS BELOW +2A78 ; [*0C58.0020.0002] # EQUIVALENT WITH FOUR DOTS ABOVE +2A79 ; [*0C59.0020.0002] # LESS-THAN WITH CIRCLE INSIDE +2A7A ; [*0C5A.0020.0002] # GREATER-THAN WITH CIRCLE INSIDE +2A7B ; [*0C5B.0020.0002] # LESS-THAN WITH QUESTION MARK ABOVE +2A7C ; [*0C5C.0020.0002] # GREATER-THAN WITH QUESTION MARK ABOVE +2A7D ; [*0C5D.0020.0002] # LESS-THAN OR SLANTED EQUAL TO +2A7E ; [*0C5E.0020.0002] # GREATER-THAN OR SLANTED EQUAL TO +2A7F ; [*0C5F.0020.0002] # LESS-THAN OR SLANTED EQUAL TO WITH DOT INSIDE +2A80 ; [*0C60.0020.0002] # GREATER-THAN OR SLANTED EQUAL TO WITH DOT INSIDE +2A81 ; [*0C61.0020.0002] # LESS-THAN OR SLANTED EQUAL TO WITH DOT ABOVE +2A82 ; [*0C62.0020.0002] # GREATER-THAN OR SLANTED EQUAL TO WITH DOT ABOVE +2A83 ; [*0C63.0020.0002] # LESS-THAN OR SLANTED EQUAL TO WITH DOT ABOVE RIGHT +2A84 ; [*0C64.0020.0002] # GREATER-THAN OR SLANTED EQUAL TO WITH DOT ABOVE LEFT +2A85 ; [*0C65.0020.0002] # LESS-THAN OR APPROXIMATE +2A86 ; [*0C66.0020.0002] # GREATER-THAN OR APPROXIMATE +2A87 ; [*0C67.0020.0002] # LESS-THAN AND SINGLE-LINE NOT EQUAL TO +2A88 ; [*0C68.0020.0002] # GREATER-THAN AND SINGLE-LINE NOT EQUAL TO +2A89 ; [*0C69.0020.0002] # LESS-THAN AND NOT APPROXIMATE +2A8A ; [*0C6A.0020.0002] # GREATER-THAN AND NOT APPROXIMATE +2A8B ; [*0C6B.0020.0002] # LESS-THAN ABOVE DOUBLE-LINE EQUAL ABOVE GREATER-THAN +2A8C ; [*0C6C.0020.0002] # GREATER-THAN ABOVE DOUBLE-LINE EQUAL ABOVE LESS-THAN +2A8D ; [*0C6D.0020.0002] # LESS-THAN ABOVE SIMILAR OR EQUAL +2A8E ; [*0C6E.0020.0002] # GREATER-THAN ABOVE SIMILAR OR EQUAL +2A8F ; [*0C6F.0020.0002] # LESS-THAN ABOVE SIMILAR ABOVE GREATER-THAN +2A90 ; [*0C70.0020.0002] # GREATER-THAN ABOVE SIMILAR ABOVE LESS-THAN +2A91 ; [*0C71.0020.0002] # LESS-THAN ABOVE GREATER-THAN ABOVE DOUBLE-LINE EQUAL +2A92 ; [*0C72.0020.0002] # GREATER-THAN ABOVE LESS-THAN ABOVE DOUBLE-LINE EQUAL +2A93 ; [*0C73.0020.0002] # LESS-THAN ABOVE SLANTED EQUAL ABOVE GREATER-THAN ABOVE SLANTED EQUAL +2A94 ; [*0C74.0020.0002] # GREATER-THAN ABOVE SLANTED EQUAL ABOVE LESS-THAN ABOVE SLANTED EQUAL +2A95 ; [*0C75.0020.0002] # SLANTED EQUAL TO OR LESS-THAN +2A96 ; [*0C76.0020.0002] # SLANTED EQUAL TO OR GREATER-THAN +2A97 ; [*0C77.0020.0002] # SLANTED EQUAL TO OR LESS-THAN WITH DOT INSIDE +2A98 ; [*0C78.0020.0002] # SLANTED EQUAL TO OR GREATER-THAN WITH DOT INSIDE +2A99 ; [*0C79.0020.0002] # DOUBLE-LINE EQUAL TO OR LESS-THAN +2A9A ; [*0C7A.0020.0002] # DOUBLE-LINE EQUAL TO OR GREATER-THAN +2A9B ; [*0C7B.0020.0002] # DOUBLE-LINE SLANTED EQUAL TO OR LESS-THAN +2A9C ; [*0C7C.0020.0002] # DOUBLE-LINE SLANTED EQUAL TO OR GREATER-THAN +2A9D ; [*0C7D.0020.0002] # SIMILAR OR LESS-THAN +2A9E ; [*0C7E.0020.0002] # SIMILAR OR GREATER-THAN +2A9F ; [*0C7F.0020.0002] # SIMILAR ABOVE LESS-THAN ABOVE EQUALS SIGN +2AA0 ; [*0C80.0020.0002] # SIMILAR ABOVE GREATER-THAN ABOVE EQUALS SIGN +2AA1 ; [*0C81.0020.0002] # DOUBLE NESTED LESS-THAN +2AA2 ; [*0C82.0020.0002] # DOUBLE NESTED GREATER-THAN +2AA3 ; [*0C83.0020.0002] # DOUBLE NESTED LESS-THAN WITH UNDERBAR +2AA4 ; [*0C84.0020.0002] # GREATER-THAN OVERLAPPING LESS-THAN +2AA5 ; [*0C85.0020.0002] # GREATER-THAN BESIDE LESS-THAN +2AA6 ; [*0C86.0020.0002] # LESS-THAN CLOSED BY CURVE +2AA7 ; [*0C87.0020.0002] # GREATER-THAN CLOSED BY CURVE +2AA8 ; [*0C88.0020.0002] # LESS-THAN CLOSED BY CURVE ABOVE SLANTED EQUAL +2AA9 ; [*0C89.0020.0002] # GREATER-THAN CLOSED BY CURVE ABOVE SLANTED EQUAL +2AAA ; [*0C8A.0020.0002] # SMALLER THAN +2AAB ; [*0C8B.0020.0002] # LARGER THAN +2AAC ; [*0C8C.0020.0002] # SMALLER THAN OR EQUAL TO +2AAD ; [*0C8D.0020.0002] # LARGER THAN OR EQUAL TO +2AAE ; [*0C8E.0020.0002] # EQUALS SIGN WITH BUMPY ABOVE +2AAF ; [*0C8F.0020.0002] # PRECEDES ABOVE SINGLE-LINE EQUALS SIGN +2AB0 ; [*0C90.0020.0002] # SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN +2AB1 ; [*0C91.0020.0002] # PRECEDES ABOVE SINGLE-LINE NOT EQUAL TO +2AB2 ; [*0C92.0020.0002] # SUCCEEDS ABOVE SINGLE-LINE NOT EQUAL TO +2AB3 ; [*0C93.0020.0002] # PRECEDES ABOVE EQUALS SIGN +2AB4 ; [*0C94.0020.0002] # SUCCEEDS ABOVE EQUALS SIGN +2AB5 ; [*0C95.0020.0002] # PRECEDES ABOVE NOT EQUAL TO +2AB6 ; [*0C96.0020.0002] # SUCCEEDS ABOVE NOT EQUAL TO +2AB7 ; [*0C97.0020.0002] # PRECEDES ABOVE ALMOST EQUAL TO +2AB8 ; [*0C98.0020.0002] # SUCCEEDS ABOVE ALMOST EQUAL TO +2AB9 ; [*0C99.0020.0002] # PRECEDES ABOVE NOT ALMOST EQUAL TO +2ABA ; [*0C9A.0020.0002] # SUCCEEDS ABOVE NOT ALMOST EQUAL TO +2ABB ; [*0C9B.0020.0002] # DOUBLE PRECEDES +2ABC ; [*0C9C.0020.0002] # DOUBLE SUCCEEDS +2ABD ; [*0C9D.0020.0002] # SUBSET WITH DOT +2ABE ; [*0C9E.0020.0002] # SUPERSET WITH DOT +2ABF ; [*0C9F.0020.0002] # SUBSET WITH PLUS SIGN BELOW +2AC0 ; [*0CA0.0020.0002] # SUPERSET WITH PLUS SIGN BELOW +2AC1 ; [*0CA1.0020.0002] # SUBSET WITH MULTIPLICATION SIGN BELOW +2AC2 ; [*0CA2.0020.0002] # SUPERSET WITH MULTIPLICATION SIGN BELOW +2AC3 ; [*0CA3.0020.0002] # SUBSET OF OR EQUAL TO WITH DOT ABOVE +2AC4 ; [*0CA4.0020.0002] # SUPERSET OF OR EQUAL TO WITH DOT ABOVE +2AC5 ; [*0CA5.0020.0002] # SUBSET OF ABOVE EQUALS SIGN +2AC6 ; [*0CA6.0020.0002] # SUPERSET OF ABOVE EQUALS SIGN +2AC7 ; [*0CA7.0020.0002] # SUBSET OF ABOVE TILDE OPERATOR +2AC8 ; [*0CA8.0020.0002] # SUPERSET OF ABOVE TILDE OPERATOR +2AC9 ; [*0CA9.0020.0002] # SUBSET OF ABOVE ALMOST EQUAL TO +2ACA ; [*0CAA.0020.0002] # SUPERSET OF ABOVE ALMOST EQUAL TO +2ACB ; [*0CAB.0020.0002] # SUBSET OF ABOVE NOT EQUAL TO +2ACC ; [*0CAC.0020.0002] # SUPERSET OF ABOVE NOT EQUAL TO +2ACD ; [*0CAD.0020.0002] # SQUARE LEFT OPEN BOX OPERATOR +2ACE ; [*0CAE.0020.0002] # SQUARE RIGHT OPEN BOX OPERATOR +2ACF ; [*0CAF.0020.0002] # CLOSED SUBSET +2AD0 ; [*0CB0.0020.0002] # CLOSED SUPERSET +2AD1 ; [*0CB1.0020.0002] # CLOSED SUBSET OR EQUAL TO +2AD2 ; [*0CB2.0020.0002] # CLOSED SUPERSET OR EQUAL TO +2AD3 ; [*0CB3.0020.0002] # SUBSET ABOVE SUPERSET +2AD4 ; [*0CB4.0020.0002] # SUPERSET ABOVE SUBSET +2AD5 ; [*0CB5.0020.0002] # SUBSET ABOVE SUBSET +2AD6 ; [*0CB6.0020.0002] # SUPERSET ABOVE SUPERSET +2AD7 ; [*0CB7.0020.0002] # SUPERSET BESIDE SUBSET +2AD8 ; [*0CB8.0020.0002] # SUPERSET BESIDE AND JOINED BY DASH WITH SUBSET +2AD9 ; [*0CB9.0020.0002] # ELEMENT OF OPENING DOWNWARDS +2ADA ; [*0CBA.0020.0002] # PITCHFORK WITH TEE TOP +2ADB ; [*0CBB.0020.0002] # TRANSVERSAL INTERSECTION +2ADC ; [*0CBC.0020.0002][.0000.002F.0002] # FORKING +2ADD ; [*0CBC.0020.0002] # NONFORKING +2ADE ; [*0CBD.0020.0002] # SHORT LEFT TACK +2ADF ; [*0CBE.0020.0002] # SHORT DOWN TACK +2AE0 ; [*0CBF.0020.0002] # SHORT UP TACK +2AE1 ; [*0CC0.0020.0002] # PERPENDICULAR WITH S +2AE2 ; [*0CC1.0020.0002] # VERTICAL BAR TRIPLE RIGHT TURNSTILE +2AE3 ; [*0CC2.0020.0002] # DOUBLE VERTICAL BAR LEFT TURNSTILE +2AE4 ; [*0CC3.0020.0002] # VERTICAL BAR DOUBLE LEFT TURNSTILE +2AE5 ; [*0CC4.0020.0002] # DOUBLE VERTICAL BAR DOUBLE LEFT TURNSTILE +2AE6 ; [*0CC5.0020.0002] # LONG DASH FROM LEFT MEMBER OF DOUBLE VERTICAL +2AE7 ; [*0CC6.0020.0002] # SHORT DOWN TACK WITH OVERBAR +2AE8 ; [*0CC7.0020.0002] # SHORT UP TACK WITH UNDERBAR +2AE9 ; [*0CC8.0020.0002] # SHORT UP TACK ABOVE SHORT DOWN TACK +2AEA ; [*0CC9.0020.0002] # DOUBLE DOWN TACK +2AEB ; [*0CCA.0020.0002] # DOUBLE UP TACK +2AEC ; [*0CCB.0020.0002] # DOUBLE STROKE NOT SIGN +2AED ; [*0CCC.0020.0002] # REVERSED DOUBLE STROKE NOT SIGN +2AEE ; [*0CCD.0020.0002] # DOES NOT DIVIDE WITH REVERSED NEGATION SLASH +2AEF ; [*0CCE.0020.0002] # VERTICAL LINE WITH CIRCLE ABOVE +2AF0 ; [*0CCF.0020.0002] # VERTICAL LINE WITH CIRCLE BELOW +2AF1 ; [*0CD0.0020.0002] # DOWN TACK WITH CIRCLE BELOW +2AF2 ; [*0CD1.0020.0002] # PARALLEL WITH HORIZONTAL STROKE +2AF3 ; [*0CD2.0020.0002] # PARALLEL WITH TILDE OPERATOR +2AF4 ; [*0CD3.0020.0002] # TRIPLE VERTICAL BAR BINARY RELATION +2AF5 ; [*0CD4.0020.0002] # TRIPLE VERTICAL BAR WITH HORIZONTAL STROKE +2AF6 ; [*0CD5.0020.0002] # TRIPLE COLON OPERATOR +2AF7 ; [*0CD6.0020.0002] # TRIPLE NESTED LESS-THAN +2AF8 ; [*0CD7.0020.0002] # TRIPLE NESTED GREATER-THAN +2AF9 ; [*0CD8.0020.0002] # DOUBLE-LINE SLANTED LESS-THAN OR EQUAL TO +2AFA ; [*0CD9.0020.0002] # DOUBLE-LINE SLANTED GREATER-THAN OR EQUAL TO +2AFB ; [*0CDA.0020.0002] # TRIPLE SOLIDUS BINARY RELATION +2AFC ; [*0CDB.0020.0002] # LARGE TRIPLE VERTICAL BAR OPERATOR +2AFD ; [*0CDC.0020.0002] # DOUBLE SOLIDUS OPERATOR +2AFE ; [*0CDD.0020.0002] # WHITE VERTICAL BAR +2AFF ; [*0CDE.0020.0002] # N-ARY WHITE VERTICAL BAR +2B00 ; [*0CDF.0020.0002] # NORTH EAST WHITE ARROW +2B01 ; [*0CE0.0020.0002] # NORTH WEST WHITE ARROW +2B02 ; [*0CE1.0020.0002] # SOUTH EAST WHITE ARROW +2B03 ; [*0CE2.0020.0002] # SOUTH WEST WHITE ARROW +2B04 ; [*0CE3.0020.0002] # LEFT RIGHT WHITE ARROW +2B05 ; [*0CE4.0020.0002] # LEFTWARDS BLACK ARROW +2B06 ; [*0CE5.0020.0002] # UPWARDS BLACK ARROW +2B07 ; [*0CE6.0020.0002] # DOWNWARDS BLACK ARROW +2B08 ; [*0CE7.0020.0002] # NORTH EAST BLACK ARROW +2B09 ; [*0CE8.0020.0002] # NORTH WEST BLACK ARROW +2B0A ; [*0CE9.0020.0002] # SOUTH EAST BLACK ARROW +2B0B ; [*0CEA.0020.0002] # SOUTH WEST BLACK ARROW +2B0C ; [*0CEB.0020.0002] # LEFT RIGHT BLACK ARROW +2B0D ; [*0CEC.0020.0002] # UP DOWN BLACK ARROW +2B0E ; [*0CED.0020.0002] # RIGHTWARDS ARROW WITH TIP DOWNWARDS +2B0F ; [*0CEE.0020.0002] # RIGHTWARDS ARROW WITH TIP UPWARDS +2B10 ; [*0CEF.0020.0002] # LEFTWARDS ARROW WITH TIP DOWNWARDS +2B11 ; [*0CF0.0020.0002] # LEFTWARDS ARROW WITH TIP UPWARDS +2B12 ; [*0CF1.0020.0002] # SQUARE WITH TOP HALF BLACK +2B13 ; [*0CF2.0020.0002] # SQUARE WITH BOTTOM HALF BLACK +2B14 ; [*0CF3.0020.0002] # SQUARE WITH UPPER RIGHT DIAGONAL HALF BLACK +2B15 ; [*0CF4.0020.0002] # SQUARE WITH LOWER LEFT DIAGONAL HALF BLACK +2B16 ; [*0CF5.0020.0002] # DIAMOND WITH LEFT HALF BLACK +2B17 ; [*0CF6.0020.0002] # DIAMOND WITH RIGHT HALF BLACK +2B18 ; [*0CF7.0020.0002] # DIAMOND WITH TOP HALF BLACK +2B19 ; [*0CF8.0020.0002] # DIAMOND WITH BOTTOM HALF BLACK +2B1A ; [*0CF9.0020.0002] # DOTTED SQUARE +2B1B ; [*0CFA.0020.0002] # BLACK LARGE SQUARE +2B1C ; [*0CFB.0020.0002] # WHITE LARGE SQUARE +2B1D ; [*0CFC.0020.0002] # BLACK VERY SMALL SQUARE +2B1E ; [*0CFD.0020.0002] # WHITE VERY SMALL SQUARE +2B1F ; [*0CFE.0020.0002] # BLACK PENTAGON +2B20 ; [*0CFF.0020.0002] # WHITE PENTAGON +2B21 ; [*0D00.0020.0002] # WHITE HEXAGON +2B22 ; [*0D01.0020.0002] # BLACK HEXAGON +2B23 ; [*0D02.0020.0002] # HORIZONTAL BLACK HEXAGON +2B24 ; [*0D03.0020.0002] # BLACK LARGE CIRCLE +2B25 ; [*0D04.0020.0002] # BLACK MEDIUM DIAMOND +2B26 ; [*0D05.0020.0002] # WHITE MEDIUM DIAMOND +2B27 ; [*0D06.0020.0002] # BLACK MEDIUM LOZENGE +2B28 ; [*0D07.0020.0002] # WHITE MEDIUM LOZENGE +2B29 ; [*0D08.0020.0002] # BLACK SMALL DIAMOND +2B2A ; [*0D09.0020.0002] # BLACK SMALL LOZENGE +2B2B ; [*0D0A.0020.0002] # WHITE SMALL LOZENGE +2B2C ; [*0D0B.0020.0002] # BLACK HORIZONTAL ELLIPSE +2B2D ; [*0D0C.0020.0002] # WHITE HORIZONTAL ELLIPSE +2B2E ; [*0D0D.0020.0002] # BLACK VERTICAL ELLIPSE +2B2F ; [*0D0E.0020.0002] # WHITE VERTICAL ELLIPSE +2B30 ; [*0D0F.0020.0002] # LEFT ARROW WITH SMALL CIRCLE +2B31 ; [*0D10.0020.0002] # THREE LEFTWARDS ARROWS +2B32 ; [*0D11.0020.0002] # LEFT ARROW WITH CIRCLED PLUS +2B33 ; [*0D12.0020.0002] # LONG LEFTWARDS SQUIGGLE ARROW +2B34 ; [*0D13.0020.0002] # LEFTWARDS TWO-HEADED ARROW WITH VERTICAL STROKE +2B35 ; [*0D14.0020.0002] # LEFTWARDS TWO-HEADED ARROW WITH DOUBLE VERTICAL STROKE +2B36 ; [*0D15.0020.0002] # LEFTWARDS TWO-HEADED ARROW FROM BAR +2B37 ; [*0D16.0020.0002] # LEFTWARDS TWO-HEADED TRIPLE DASH ARROW +2B38 ; [*0D17.0020.0002] # LEFTWARDS ARROW WITH DOTTED STEM +2B39 ; [*0D18.0020.0002] # LEFTWARDS ARROW WITH TAIL WITH VERTICAL STROKE +2B3A ; [*0D19.0020.0002] # LEFTWARDS ARROW WITH TAIL WITH DOUBLE VERTICAL STROKE +2B3B ; [*0D1A.0020.0002] # LEFTWARDS TWO-HEADED ARROW WITH TAIL +2B3C ; [*0D1B.0020.0002] # LEFTWARDS TWO-HEADED ARROW WITH TAIL WITH VERTICAL STROKE +2B3D ; [*0D1C.0020.0002] # LEFTWARDS TWO-HEADED ARROW WITH TAIL WITH DOUBLE VERTICAL STROKE +2B3E ; [*0D1D.0020.0002] # LEFTWARDS ARROW THROUGH X +2B3F ; [*0D1E.0020.0002] # WAVE ARROW POINTING DIRECTLY LEFT +2B40 ; [*0D1F.0020.0002] # EQUALS SIGN ABOVE LEFTWARDS ARROW +2B41 ; [*0D20.0020.0002] # REVERSE TILDE OPERATOR ABOVE LEFTWARDS ARROW +2B42 ; [*0D21.0020.0002] # LEFTWARDS ARROW ABOVE REVERSE ALMOST EQUAL TO +2B43 ; [*0D22.0020.0002] # RIGHTWARDS ARROW THROUGH GREATER-THAN +2B44 ; [*0D23.0020.0002] # RIGHTWARDS ARROW THROUGH SUPERSET +2B45 ; [*0D24.0020.0002] # LEFTWARDS QUADRUPLE ARROW +2B46 ; [*0D25.0020.0002] # RIGHTWARDS QUADRUPLE ARROW +2B47 ; [*0D26.0020.0002] # REVERSE TILDE OPERATOR ABOVE RIGHTWARDS ARROW +2B48 ; [*0D27.0020.0002] # RIGHTWARDS ARROW ABOVE REVERSE ALMOST EQUAL TO +2B49 ; [*0D28.0020.0002] # TILDE OPERATOR ABOVE LEFTWARDS ARROW +2B4A ; [*0D29.0020.0002] # LEFTWARDS ARROW ABOVE ALMOST EQUAL TO +2B4B ; [*0D2A.0020.0002] # LEFTWARDS ARROW ABOVE REVERSE TILDE OPERATOR +2B4C ; [*0D2B.0020.0002] # RIGHTWARDS ARROW ABOVE REVERSE TILDE OPERATOR +2B4D ; [*0D2C.0020.0002] # DOWNWARDS TRIANGLE-HEADED ZIGZAG ARROW +2B4E ; [*0D2D.0020.0002] # SHORT SLANTED NORTH ARROW +2B4F ; [*0D2E.0020.0002] # SHORT BACKSLANTED SOUTH ARROW +2B50 ; [*0D2F.0020.0002] # WHITE MEDIUM STAR +2B51 ; [*0D30.0020.0002] # BLACK SMALL STAR +2B52 ; [*0D31.0020.0002] # WHITE SMALL STAR +2B53 ; [*0D32.0020.0002] # BLACK RIGHT-POINTING PENTAGON +2B54 ; [*0D33.0020.0002] # WHITE RIGHT-POINTING PENTAGON +2B55 ; [*0D34.0020.0002] # HEAVY LARGE CIRCLE +2B56 ; [*0D35.0020.0002] # HEAVY OVAL WITH OVAL INSIDE +2B57 ; [*0D36.0020.0002] # HEAVY CIRCLE WITH CIRCLE INSIDE +2B58 ; [*0D37.0020.0002] # HEAVY CIRCLE +2B59 ; [*0D38.0020.0002] # HEAVY CIRCLED SALTIRE +2B5A ; [*0D39.0020.0002] # SLANTED NORTH ARROW WITH HOOKED HEAD +2B5B ; [*0D3A.0020.0002] # BACKSLANTED SOUTH ARROW WITH HOOKED TAIL +2B5C ; [*0D3B.0020.0002] # SLANTED NORTH ARROW WITH HORIZONTAL TAIL +2B5D ; [*0D3C.0020.0002] # BACKSLANTED SOUTH ARROW WITH HORIZONTAL TAIL +2B5E ; [*0D3D.0020.0002] # BENT ARROW POINTING DOWNWARDS THEN NORTH EAST +2B5F ; [*0D3E.0020.0002] # SHORT BENT ARROW POINTING DOWNWARDS THEN NORTH EAST +2B60 ; [*0D3F.0020.0002] # LEFTWARDS TRIANGLE-HEADED ARROW +2B61 ; [*0D40.0020.0002] # UPWARDS TRIANGLE-HEADED ARROW +2B62 ; [*0D41.0020.0002] # RIGHTWARDS TRIANGLE-HEADED ARROW +2B63 ; [*0D42.0020.0002] # DOWNWARDS TRIANGLE-HEADED ARROW +2B64 ; [*0D43.0020.0002] # LEFT RIGHT TRIANGLE-HEADED ARROW +2B65 ; [*0D44.0020.0002] # UP DOWN TRIANGLE-HEADED ARROW +2B66 ; [*0D45.0020.0002] # NORTH WEST TRIANGLE-HEADED ARROW +2B67 ; [*0D46.0020.0002] # NORTH EAST TRIANGLE-HEADED ARROW +2B68 ; [*0D47.0020.0002] # SOUTH EAST TRIANGLE-HEADED ARROW +2B69 ; [*0D48.0020.0002] # SOUTH WEST TRIANGLE-HEADED ARROW +2B6A ; [*0D49.0020.0002] # LEFTWARDS TRIANGLE-HEADED DASHED ARROW +2B6B ; [*0D4A.0020.0002] # UPWARDS TRIANGLE-HEADED DASHED ARROW +2B6C ; [*0D4B.0020.0002] # RIGHTWARDS TRIANGLE-HEADED DASHED ARROW +2B6D ; [*0D4C.0020.0002] # DOWNWARDS TRIANGLE-HEADED DASHED ARROW +2B6E ; [*0D4D.0020.0002] # CLOCKWISE TRIANGLE-HEADED OPEN CIRCLE ARROW +2B6F ; [*0D4E.0020.0002] # ANTICLOCKWISE TRIANGLE-HEADED OPEN CIRCLE ARROW +2B70 ; [*0D4F.0020.0002] # LEFTWARDS TRIANGLE-HEADED ARROW TO BAR +2B71 ; [*0D50.0020.0002] # UPWARDS TRIANGLE-HEADED ARROW TO BAR +2B72 ; [*0D51.0020.0002] # RIGHTWARDS TRIANGLE-HEADED ARROW TO BAR +2B73 ; [*0D52.0020.0002] # DOWNWARDS TRIANGLE-HEADED ARROW TO BAR +2B76 ; [*0D53.0020.0002] # NORTH WEST TRIANGLE-HEADED ARROW TO BAR +2B77 ; [*0D54.0020.0002] # NORTH EAST TRIANGLE-HEADED ARROW TO BAR +2B78 ; [*0D55.0020.0002] # SOUTH EAST TRIANGLE-HEADED ARROW TO BAR +2B79 ; [*0D56.0020.0002] # SOUTH WEST TRIANGLE-HEADED ARROW TO BAR +2B7A ; [*0D57.0020.0002] # LEFTWARDS TRIANGLE-HEADED ARROW WITH DOUBLE HORIZONTAL STROKE +2B7B ; [*0D58.0020.0002] # UPWARDS TRIANGLE-HEADED ARROW WITH DOUBLE HORIZONTAL STROKE +2B7C ; [*0D59.0020.0002] # RIGHTWARDS TRIANGLE-HEADED ARROW WITH DOUBLE HORIZONTAL STROKE +2B7D ; [*0D5A.0020.0002] # DOWNWARDS TRIANGLE-HEADED ARROW WITH DOUBLE HORIZONTAL STROKE +2B7E ; [*0D5B.0020.0002] # HORIZONTAL TAB KEY +2B7F ; [*0D5C.0020.0002] # VERTICAL TAB KEY +2B80 ; [*0D5D.0020.0002] # LEFTWARDS TRIANGLE-HEADED ARROW OVER RIGHTWARDS TRIANGLE-HEADED ARROW +2B81 ; [*0D5E.0020.0002] # UPWARDS TRIANGLE-HEADED ARROW LEFTWARDS OF DOWNWARDS TRIANGLE-HEADED ARROW +2B82 ; [*0D5F.0020.0002] # RIGHTWARDS TRIANGLE-HEADED ARROW OVER LEFTWARDS TRIANGLE-HEADED ARROW +2B83 ; [*0D60.0020.0002] # DOWNWARDS TRIANGLE-HEADED ARROW LEFTWARDS OF UPWARDS TRIANGLE-HEADED ARROW +2B84 ; [*0D61.0020.0002] # LEFTWARDS TRIANGLE-HEADED PAIRED ARROWS +2B85 ; [*0D62.0020.0002] # UPWARDS TRIANGLE-HEADED PAIRED ARROWS +2B86 ; [*0D63.0020.0002] # RIGHTWARDS TRIANGLE-HEADED PAIRED ARROWS +2B87 ; [*0D64.0020.0002] # DOWNWARDS TRIANGLE-HEADED PAIRED ARROWS +2B88 ; [*0D65.0020.0002] # LEFTWARDS BLACK CIRCLED WHITE ARROW +2B89 ; [*0D66.0020.0002] # UPWARDS BLACK CIRCLED WHITE ARROW +2B8A ; [*0D67.0020.0002] # RIGHTWARDS BLACK CIRCLED WHITE ARROW +2B8B ; [*0D68.0020.0002] # DOWNWARDS BLACK CIRCLED WHITE ARROW +2B8C ; [*0D69.0020.0002] # ANTICLOCKWISE TRIANGLE-HEADED RIGHT U-SHAPED ARROW +2B8D ; [*0D6A.0020.0002] # ANTICLOCKWISE TRIANGLE-HEADED BOTTOM U-SHAPED ARROW +2B8E ; [*0D6B.0020.0002] # ANTICLOCKWISE TRIANGLE-HEADED LEFT U-SHAPED ARROW +2B8F ; [*0D6C.0020.0002] # ANTICLOCKWISE TRIANGLE-HEADED TOP U-SHAPED ARROW +2B90 ; [*0D6D.0020.0002] # RETURN LEFT +2B91 ; [*0D6E.0020.0002] # RETURN RIGHT +2B92 ; [*0D6F.0020.0002] # NEWLINE LEFT +2B93 ; [*0D70.0020.0002] # NEWLINE RIGHT +2B94 ; [*0D71.0020.0002] # FOUR CORNER ARROWS CIRCLING ANTICLOCKWISE +2B95 ; [*0D72.0020.0002] # RIGHTWARDS BLACK ARROW +2B98 ; [*0D73.0020.0002] # THREE-D TOP-LIGHTED LEFTWARDS EQUILATERAL ARROWHEAD +2B99 ; [*0D74.0020.0002] # THREE-D RIGHT-LIGHTED UPWARDS EQUILATERAL ARROWHEAD +2B9A ; [*0D75.0020.0002] # THREE-D TOP-LIGHTED RIGHTWARDS EQUILATERAL ARROWHEAD +2B9B ; [*0D76.0020.0002] # THREE-D LEFT-LIGHTED DOWNWARDS EQUILATERAL ARROWHEAD +2B9C ; [*0D77.0020.0002] # BLACK LEFTWARDS EQUILATERAL ARROWHEAD +2B9D ; [*0D78.0020.0002] # BLACK UPWARDS EQUILATERAL ARROWHEAD +2B9E ; [*0D79.0020.0002] # BLACK RIGHTWARDS EQUILATERAL ARROWHEAD +2B9F ; [*0D7A.0020.0002] # BLACK DOWNWARDS EQUILATERAL ARROWHEAD +2BA0 ; [*0D7B.0020.0002] # DOWNWARDS TRIANGLE-HEADED ARROW WITH LONG TIP LEFTWARDS +2BA1 ; [*0D7C.0020.0002] # DOWNWARDS TRIANGLE-HEADED ARROW WITH LONG TIP RIGHTWARDS +2BA2 ; [*0D7D.0020.0002] # UPWARDS TRIANGLE-HEADED ARROW WITH LONG TIP LEFTWARDS +2BA3 ; [*0D7E.0020.0002] # UPWARDS TRIANGLE-HEADED ARROW WITH LONG TIP RIGHTWARDS +2BA4 ; [*0D7F.0020.0002] # LEFTWARDS TRIANGLE-HEADED ARROW WITH LONG TIP UPWARDS +2BA5 ; [*0D80.0020.0002] # RIGHTWARDS TRIANGLE-HEADED ARROW WITH LONG TIP UPWARDS +2BA6 ; [*0D81.0020.0002] # LEFTWARDS TRIANGLE-HEADED ARROW WITH LONG TIP DOWNWARDS +2BA7 ; [*0D82.0020.0002] # RIGHTWARDS TRIANGLE-HEADED ARROW WITH LONG TIP DOWNWARDS +2BA8 ; [*0D83.0020.0002] # BLACK CURVED DOWNWARDS AND LEFTWARDS ARROW +2BA9 ; [*0D84.0020.0002] # BLACK CURVED DOWNWARDS AND RIGHTWARDS ARROW +2BAA ; [*0D85.0020.0002] # BLACK CURVED UPWARDS AND LEFTWARDS ARROW +2BAB ; [*0D86.0020.0002] # BLACK CURVED UPWARDS AND RIGHTWARDS ARROW +2BAC ; [*0D87.0020.0002] # BLACK CURVED LEFTWARDS AND UPWARDS ARROW +2BAD ; [*0D88.0020.0002] # BLACK CURVED RIGHTWARDS AND UPWARDS ARROW +2BAE ; [*0D89.0020.0002] # BLACK CURVED LEFTWARDS AND DOWNWARDS ARROW +2BAF ; [*0D8A.0020.0002] # BLACK CURVED RIGHTWARDS AND DOWNWARDS ARROW +2BB0 ; [*0D8B.0020.0002] # RIBBON ARROW DOWN LEFT +2BB1 ; [*0D8C.0020.0002] # RIBBON ARROW DOWN RIGHT +2BB2 ; [*0D8D.0020.0002] # RIBBON ARROW UP LEFT +2BB3 ; [*0D8E.0020.0002] # RIBBON ARROW UP RIGHT +2BB4 ; [*0D8F.0020.0002] # RIBBON ARROW LEFT UP +2BB5 ; [*0D90.0020.0002] # RIBBON ARROW RIGHT UP +2BB6 ; [*0D91.0020.0002] # RIBBON ARROW LEFT DOWN +2BB7 ; [*0D92.0020.0002] # RIBBON ARROW RIGHT DOWN +2BB8 ; [*0D93.0020.0002] # UPWARDS WHITE ARROW FROM BAR WITH HORIZONTAL BAR +2BB9 ; [*0D94.0020.0002] # UP ARROWHEAD IN A RECTANGLE BOX +2BBD ; [*0D95.0020.0002] # BALLOT BOX WITH LIGHT X +2BBE ; [*0D96.0020.0002] # CIRCLED X +2BBF ; [*0D97.0020.0002] # CIRCLED BOLD X +2BC0 ; [*0D98.0020.0002] # BLACK SQUARE CENTRED +2BC1 ; [*0D99.0020.0002] # BLACK DIAMOND CENTRED +2BC2 ; [*0D9A.0020.0002] # TURNED BLACK PENTAGON +2BC3 ; [*0D9B.0020.0002] # HORIZONTAL BLACK OCTAGON +2BC4 ; [*0D9C.0020.0002] # BLACK OCTAGON +2BC5 ; [*0D9D.0020.0002] # BLACK MEDIUM UP-POINTING TRIANGLE CENTRED +2BC6 ; [*0D9E.0020.0002] # BLACK MEDIUM DOWN-POINTING TRIANGLE CENTRED +2BC7 ; [*0D9F.0020.0002] # BLACK MEDIUM LEFT-POINTING TRIANGLE CENTRED +2BC8 ; [*0DA0.0020.0002] # BLACK MEDIUM RIGHT-POINTING TRIANGLE CENTRED +2BCA ; [*0DA1.0020.0002] # TOP HALF BLACK CIRCLE +2BCB ; [*0DA2.0020.0002] # BOTTOM HALF BLACK CIRCLE +2BCC ; [*0DA3.0020.0002] # LIGHT FOUR POINTED BLACK CUSP +2BCD ; [*0DA4.0020.0002] # ROTATED LIGHT FOUR POINTED BLACK CUSP +2BCE ; [*0DA5.0020.0002] # WHITE FOUR POINTED CUSP +2BCF ; [*0DA6.0020.0002] # ROTATED WHITE FOUR POINTED CUSP +2BD0 ; [*0DA7.0020.0002] # SQUARE POSITION INDICATOR +2BD1 ; [*0DA8.0020.0002] # UNCERTAINTY SIGN +2BD2 ; [*0DA9.0020.0002] # GROUP MARK +2BEC ; [*0DAA.0020.0002] # LEFTWARDS TWO-HEADED ARROW WITH TRIANGLE ARROWHEADS +2BED ; [*0DAB.0020.0002] # UPWARDS TWO-HEADED ARROW WITH TRIANGLE ARROWHEADS +2BEE ; [*0DAC.0020.0002] # RIGHTWARDS TWO-HEADED ARROW WITH TRIANGLE ARROWHEADS +2BEF ; [*0DAD.0020.0002] # DOWNWARDS TWO-HEADED ARROW WITH TRIANGLE ARROWHEADS +2CE5 ; [*0DAE.0020.0002] # COPTIC SYMBOL MI RO +2CE6 ; [*0DAF.0020.0002] # COPTIC SYMBOL PI RO +2CE7 ; [*0DB0.0020.0002] # COPTIC SYMBOL STAUROS +2CE8 ; [*0DB1.0020.0002] # COPTIC SYMBOL TAU RO +2CE9 ; [*0DB2.0020.0002] # COPTIC SYMBOL KHI RO +2CEA ; [*0DB3.0020.0002] # COPTIC SYMBOL SHIMA SIMA +2CF9 ; [*0282.0020.0002] # COPTIC OLD NUBIAN FULL STOP +2CFA ; [*026F.0020.0002] # COPTIC OLD NUBIAN DIRECT QUESTION MARK +2CFB ; [*0270.0020.0002] # COPTIC OLD NUBIAN INDIRECT QUESTION MARK +2CFC ; [*02F7.0020.0002] # COPTIC OLD NUBIAN VERSE DIVIDER +2CFD ; [*1B46.0020.0002] # COPTIC FRACTION ONE HALF +2CFE ; [*0283.0020.0002] # COPTIC FULL STOP +2CFF ; [*02F8.0020.0002] # COPTIC MORPHOLOGICAL DIVIDER +2D70 ; [*043D.0020.0002] # TIFINAGH SEPARATOR MARK +2D7F ; [.0000.0000.0000] # TIFINAGH CONSONANT JOINER +2E00 ; [*03B7.0020.0002] # RIGHT ANGLE SUBSTITUTION MARKER +2E01 ; [*03B8.0020.0002] # RIGHT ANGLE DOTTED SUBSTITUTION MARKER +2E02 ; [*035C.0020.0002] # LEFT SUBSTITUTION BRACKET +2E03 ; [*035D.0020.0002] # RIGHT SUBSTITUTION BRACKET +2E04 ; [*035E.0020.0002] # LEFT DOTTED SUBSTITUTION BRACKET +2E05 ; [*035F.0020.0002] # RIGHT DOTTED SUBSTITUTION BRACKET +2E06 ; [*03B9.0020.0002] # RAISED INTERPOLATION MARKER +2E07 ; [*03BA.0020.0002] # RAISED DOTTED INTERPOLATION MARKER +2E08 ; [*03BB.0020.0002] # DOTTED TRANSPOSITION MARKER +2E09 ; [*0360.0020.0002] # LEFT TRANSPOSITION BRACKET +2E0A ; [*0361.0020.0002] # RIGHT TRANSPOSITION BRACKET +2E0B ; [*03BC.0020.0002] # RAISED SQUARE +2E0C ; [*0362.0020.0002] # LEFT RAISED OMISSION BRACKET +2E0D ; [*0363.0020.0002] # RIGHT RAISED OMISSION BRACKET +2E0E ; [*03BD.0020.0002] # EDITORIAL CORONIS +2E0F ; [*03BE.0020.0002] # PARAGRAPHOS +2E10 ; [*03BF.0020.0002] # FORKED PARAGRAPHOS +2E11 ; [*03C0.0020.0002] # REVERSED FORKED PARAGRAPHOS +2E12 ; [*03C1.0020.0002] # HYPODIASTOLE +2E13 ; [*03C2.0020.0002] # DOTTED OBELOS +2E14 ; [*03C3.0020.0002] # DOWNWARDS ANCORA +2E15 ; [*03C4.0020.0002] # UPWARDS ANCORA +2E16 ; [*03C5.0020.0002] # DOTTED RIGHT-POINTING ANGLE +2E17 ; [*021C.0020.0002] # DOUBLE OBLIQUE HYPHEN +2E18 ; [*0277.0020.0002] # INVERTED INTERROBANG +2E19 ; [*02F9.0020.0002] # PALM BRANCH +2E1A ; [*03C6.0020.0002] # HYPHEN WITH DIAERESIS +2E1B ; [*03C7.0020.0002] # TILDE WITH RING ABOVE +2E1C ; [*0364.0020.0002] # LEFT LOW PARAPHRASE BRACKET +2E1D ; [*0365.0020.0002] # RIGHT LOW PARAPHRASE BRACKET +2E1E ; [*03C8.0020.0002] # TILDE WITH DOT ABOVE +2E1F ; [*03C9.0020.0002] # TILDE WITH DOT BELOW +2E20 ; [*0366.0020.0002] # LEFT VERTICAL BAR WITH QUILL +2E21 ; [*0367.0020.0002] # RIGHT VERTICAL BAR WITH QUILL +2E22 ; [*0368.0020.0002] # TOP LEFT HALF BRACKET +2E23 ; [*0369.0020.0002] # TOP RIGHT HALF BRACKET +2E24 ; [*036A.0020.0002] # BOTTOM LEFT HALF BRACKET +2E25 ; [*036B.0020.0002] # BOTTOM RIGHT HALF BRACKET +2E26 ; [*036C.0020.0002] # LEFT SIDEWAYS U BRACKET +2E27 ; [*036D.0020.0002] # RIGHT SIDEWAYS U BRACKET +2E28 ; [*036E.0020.0002] # LEFT DOUBLE PARENTHESIS +2E29 ; [*036F.0020.0002] # RIGHT DOUBLE PARENTHESIS +2E2A ; [*02F2.0020.0002] # TWO DOTS OVER ONE DOT PUNCTUATION +2E2B ; [*02F3.0020.0002] # ONE DOT OVER TWO DOTS PUNCTUATION +2E2C ; [*02F4.0020.0002] # SQUARED FOUR DOT PUNCTUATION +2E2D ; [*02F5.0020.0002] # FIVE DOT MARK +2E2E ; [*0269.0020.0002] # REVERSED QUESTION MARK +2E30 ; [*0284.0020.0002] # RING POINT +2E31 ; [*028D.0020.0002] # WORD SEPARATOR MIDDLE DOT +2E32 ; [*0224.0020.0002] # TURNED COMMA +2E33 ; [*028E.0020.0002] # RAISED DOT +2E34 ; [*0223.0020.0002] # RAISED COMMA +2E35 ; [*0237.0020.0002] # TURNED SEMICOLON +2E36 ; [*03A2.0020.0002] # DAGGER WITH LEFT GUARD +2E37 ; [*03A3.0020.0002] # DAGGER WITH RIGHT GUARD +2E38 ; [*03A4.0020.0002] # TURNED DAGGER +2E39 ; [*038B.0020.0002] # TOP HALF SECTION SIGN +2E3A ; [*0218.0020.0002] # TWO-EM DASH +2E3B ; [*0219.0020.0002] # THREE-EM DASH +2E3C ; [*0285.0020.0002] # STENOGRAPHIC FULL STOP +2E3D ; [*02F6.0020.0002] # VERTICAL SIX DOTS +2E3E ; [*0385.0020.0002] # WIGGLY VERTICAL LINE +2E3F ; [*038E.0020.0002] # CAPITULUM +2E40 ; [*021D.0020.0002] # DOUBLE HYPHEN +2E41 ; [*0225.0020.0002] # REVERSED COMMA +2E42 ; [*0312.0020.0002] # DOUBLE LOW-REVERSED-9 QUOTATION MARK +2E43 ; [*021B.0020.0002] # DASH WITH LEFT UPTURN +2E44 ; [*03CA.0020.0002] # DOUBLE SUSPENSION MARK +2E45 ; [*03CB.0020.0002] # INVERTED LOW KAVYKA +2E46 ; [*03CC.0020.0002] # INVERTED LOW KAVYKA WITH KAVYKA ABOVE +2E47 ; [*03CD.0020.0002] # LOW KAVYKA +2E48 ; [*03CE.0020.0002] # LOW KAVYKA WITH DOT +2E49 ; [*0239.0020.0002] # DOUBLE STACKED COMMA +2FF0 ; [*1ABF.0020.0002] # IDEOGRAPHIC DESCRIPTION CHARACTER LEFT TO RIGHT +2FF1 ; [*1AC0.0020.0002] # IDEOGRAPHIC DESCRIPTION CHARACTER ABOVE TO BELOW +2FF2 ; [*1AC1.0020.0002] # IDEOGRAPHIC DESCRIPTION CHARACTER LEFT TO MIDDLE AND RIGHT +2FF3 ; [*1AC2.0020.0002] # IDEOGRAPHIC DESCRIPTION CHARACTER ABOVE TO MIDDLE AND BELOW +2FF4 ; [*1AC3.0020.0002] # IDEOGRAPHIC DESCRIPTION CHARACTER FULL SURROUND +2FF5 ; [*1AC4.0020.0002] # IDEOGRAPHIC DESCRIPTION CHARACTER SURROUND FROM ABOVE +2FF6 ; [*1AC5.0020.0002] # IDEOGRAPHIC DESCRIPTION CHARACTER SURROUND FROM BELOW +2FF7 ; [*1AC6.0020.0002] # IDEOGRAPHIC DESCRIPTION CHARACTER SURROUND FROM LEFT +2FF8 ; [*1AC7.0020.0002] # IDEOGRAPHIC DESCRIPTION CHARACTER SURROUND FROM UPPER LEFT +2FF9 ; [*1AC8.0020.0002] # IDEOGRAPHIC DESCRIPTION CHARACTER SURROUND FROM UPPER RIGHT +2FFA ; [*1AC9.0020.0002] # IDEOGRAPHIC DESCRIPTION CHARACTER SURROUND FROM LOWER LEFT +2FFB ; [*1ACA.0020.0002] # IDEOGRAPHIC DESCRIPTION CHARACTER OVERLAID +3000 ; [*0209.0020.0003] # IDEOGRAPHIC SPACE +3001 ; [*0231.0020.0002] # IDEOGRAPHIC COMMA +3002 ; [*028B.0020.0002] # IDEOGRAPHIC FULL STOP +3003 ; [*03AD.0020.0002] # DITTO MARK +3004 ; [*1AEF.0020.0002] # JAPANESE INDUSTRIAL STANDARD SYMBOL +3008 ; [*0370.0020.0002] # LEFT ANGLE BRACKET +3009 ; [*0371.0020.0002] # RIGHT ANGLE BRACKET +300A ; [*0372.0020.0002] # LEFT DOUBLE ANGLE BRACKET +300B ; [*0373.0020.0002] # RIGHT DOUBLE ANGLE BRACKET +300C ; [*0374.0020.0002] # LEFT CORNER BRACKET +300D ; [*0375.0020.0002] # RIGHT CORNER BRACKET +300E ; [*0376.0020.0002] # LEFT WHITE CORNER BRACKET +300F ; [*0377.0020.0002] # RIGHT WHITE CORNER BRACKET +3010 ; [*0378.0020.0002] # LEFT BLACK LENTICULAR BRACKET +3011 ; [*0379.0020.0002] # RIGHT BLACK LENTICULAR BRACKET +3012 ; [*1AF0.0020.0002] # POSTAL MARK +3013 ; [*1AF1.0020.0002] # GETA MARK +3014 ; [*037A.0020.0002] # LEFT TORTOISE SHELL BRACKET +3015 ; [*037B.0020.0002] # RIGHT TORTOISE SHELL BRACKET +3016 ; [*037C.0020.0002] # LEFT WHITE LENTICULAR BRACKET +3017 ; [*037D.0020.0002] # RIGHT WHITE LENTICULAR BRACKET +3018 ; [*037E.0020.0002] # LEFT WHITE TORTOISE SHELL BRACKET +3019 ; [*037F.0020.0002] # RIGHT WHITE TORTOISE SHELL BRACKET +301A ; [*0380.0020.0002] # LEFT WHITE SQUARE BRACKET +301B ; [*0381.0020.0002] # RIGHT WHITE SQUARE BRACKET +301C ; [*021E.0020.0002] # WAVE DASH +301D ; [*0313.0020.0002] # REVERSED DOUBLE PRIME QUOTATION MARK +301E ; [*0314.0020.0002] # DOUBLE PRIME QUOTATION MARK +301F ; [*0315.0020.0002] # LOW DOUBLE PRIME QUOTATION MARK +3020 ; [*1AF2.0020.0002] # POSTAL MARK FACE +3030 ; [*021F.0020.0002] # WAVY DASH +3036 ; [*1AF0.0020.0004] # CIRCLED POSTAL MARK +3037 ; [*1AF3.0020.0002] # IDEOGRAPHIC TELEGRAPH LINE FEED SEPARATOR SYMBOL +303D ; [*03AE.0020.0002] # PART ALTERNATION MARK +303E ; [*1AF4.0020.0002] # IDEOGRAPHIC VARIATION INDICATOR +303F ; [*1AF5.0020.0002] # IDEOGRAPHIC HALF FILL SPACE +309B ; [*04A7.0020.0002] # KATAKANA-HIRAGANA VOICED SOUND MARK +309C ; [*04A8.0020.0002] # KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK +30A0 ; [*0220.0020.0002] # KATAKANA-HIRAGANA DOUBLE HYPHEN +30FB ; [*0221.0020.0002] # KATAKANA MIDDLE DOT +3190 ; [*1AF6.0020.0002] # IDEOGRAPHIC ANNOTATION LINKING MARK +3191 ; [*1AF7.0020.0002] # IDEOGRAPHIC ANNOTATION REVERSE MARK +31C0 ; [*1ACB.0020.0002] # CJK STROKE T +31C1 ; [*1ACC.0020.0002] # CJK STROKE WG +31C2 ; [*1ACD.0020.0002] # CJK STROKE XG +31C3 ; [*1ACE.0020.0002] # CJK STROKE BXG +31C4 ; [*1ACF.0020.0002] # CJK STROKE SW +31C5 ; [*1AD0.0020.0002] # CJK STROKE HZZ +31C6 ; [*1AD1.0020.0002] # CJK STROKE HZG +31C7 ; [*1AD2.0020.0002] # CJK STROKE HP +31C8 ; [*1AD3.0020.0002] # CJK STROKE HZWG +31C9 ; [*1AD4.0020.0002] # CJK STROKE SZWG +31CA ; [*1AD5.0020.0002] # CJK STROKE HZT +31CB ; [*1AD6.0020.0002] # CJK STROKE HZZP +31CC ; [*1AD7.0020.0002] # CJK STROKE HPWG +31CD ; [*1AD8.0020.0002] # CJK STROKE HZW +31CE ; [*1AD9.0020.0002] # CJK STROKE HZZZ +31CF ; [*1ADA.0020.0002] # CJK STROKE N +31D0 ; [*1ADB.0020.0002] # CJK STROKE H +31D1 ; [*1ADC.0020.0002] # CJK STROKE S +31D2 ; [*1ADD.0020.0002] # CJK STROKE P +31D3 ; [*1ADE.0020.0002] # CJK STROKE SP +31D4 ; [*1ADF.0020.0002] # CJK STROKE D +31D5 ; [*1AE0.0020.0002] # CJK STROKE HZ +31D6 ; [*1AE1.0020.0002] # CJK STROKE HG +31D7 ; [*1AE2.0020.0002] # CJK STROKE SZ +31D8 ; [*1AE3.0020.0002] # CJK STROKE SWZ +31D9 ; [*1AE4.0020.0002] # CJK STROKE ST +31DA ; [*1AE5.0020.0002] # CJK STROKE SG +31DB ; [*1AE6.0020.0002] # CJK STROKE PD +31DC ; [*1AE7.0020.0002] # CJK STROKE PZ +31DD ; [*1AE8.0020.0002] # CJK STROKE TN +31DE ; [*1AE9.0020.0002] # CJK STROKE SZZ +31DF ; [*1AEA.0020.0002] # CJK STROKE SWG +31E0 ; [*1AEB.0020.0002] # CJK STROKE HXWG +31E1 ; [*1AEC.0020.0002] # CJK STROKE HZZZG +31E2 ; [*1AED.0020.0002] # CJK STROKE PG +31E3 ; [*1AEE.0020.0002] # CJK STROKE Q +327F ; [*1AF8.0020.0002] # KOREAN STANDARD SYMBOL +4DC0 ; [*0EC2.0020.0002] # HEXAGRAM FOR THE CREATIVE HEAVEN +4DC1 ; [*0EC3.0020.0002] # HEXAGRAM FOR THE RECEPTIVE EARTH +4DC2 ; [*0EC4.0020.0002] # HEXAGRAM FOR DIFFICULTY AT THE BEGINNING +4DC3 ; [*0EC5.0020.0002] # HEXAGRAM FOR YOUTHFUL FOLLY +4DC4 ; [*0EC6.0020.0002] # HEXAGRAM FOR WAITING +4DC5 ; [*0EC7.0020.0002] # HEXAGRAM FOR CONFLICT +4DC6 ; [*0EC8.0020.0002] # HEXAGRAM FOR THE ARMY +4DC7 ; [*0EC9.0020.0002] # HEXAGRAM FOR HOLDING TOGETHER +4DC8 ; [*0ECA.0020.0002] # HEXAGRAM FOR SMALL TAMING +4DC9 ; [*0ECB.0020.0002] # HEXAGRAM FOR TREADING +4DCA ; [*0ECC.0020.0002] # HEXAGRAM FOR PEACE +4DCB ; [*0ECD.0020.0002] # HEXAGRAM FOR STANDSTILL +4DCC ; [*0ECE.0020.0002] # HEXAGRAM FOR FELLOWSHIP +4DCD ; [*0ECF.0020.0002] # HEXAGRAM FOR GREAT POSSESSION +4DCE ; [*0ED0.0020.0002] # HEXAGRAM FOR MODESTY +4DCF ; [*0ED1.0020.0002] # HEXAGRAM FOR ENTHUSIASM +4DD0 ; [*0ED2.0020.0002] # HEXAGRAM FOR FOLLOWING +4DD1 ; [*0ED3.0020.0002] # HEXAGRAM FOR WORK ON THE DECAYED +4DD2 ; [*0ED4.0020.0002] # HEXAGRAM FOR APPROACH +4DD3 ; [*0ED5.0020.0002] # HEXAGRAM FOR CONTEMPLATION +4DD4 ; [*0ED6.0020.0002] # HEXAGRAM FOR BITING THROUGH +4DD5 ; [*0ED7.0020.0002] # HEXAGRAM FOR GRACE +4DD6 ; [*0ED8.0020.0002] # HEXAGRAM FOR SPLITTING APART +4DD7 ; [*0ED9.0020.0002] # HEXAGRAM FOR RETURN +4DD8 ; [*0EDA.0020.0002] # HEXAGRAM FOR INNOCENCE +4DD9 ; [*0EDB.0020.0002] # HEXAGRAM FOR GREAT TAMING +4DDA ; [*0EDC.0020.0002] # HEXAGRAM FOR MOUTH CORNERS +4DDB ; [*0EDD.0020.0002] # HEXAGRAM FOR GREAT PREPONDERANCE +4DDC ; [*0EDE.0020.0002] # HEXAGRAM FOR THE ABYSMAL WATER +4DDD ; [*0EDF.0020.0002] # HEXAGRAM FOR THE CLINGING FIRE +4DDE ; [*0EE0.0020.0002] # HEXAGRAM FOR INFLUENCE +4DDF ; [*0EE1.0020.0002] # HEXAGRAM FOR DURATION +4DE0 ; [*0EE2.0020.0002] # HEXAGRAM FOR RETREAT +4DE1 ; [*0EE3.0020.0002] # HEXAGRAM FOR GREAT POWER +4DE2 ; [*0EE4.0020.0002] # HEXAGRAM FOR PROGRESS +4DE3 ; [*0EE5.0020.0002] # HEXAGRAM FOR DARKENING OF THE LIGHT +4DE4 ; [*0EE6.0020.0002] # HEXAGRAM FOR THE FAMILY +4DE5 ; [*0EE7.0020.0002] # HEXAGRAM FOR OPPOSITION +4DE6 ; [*0EE8.0020.0002] # HEXAGRAM FOR OBSTRUCTION +4DE7 ; [*0EE9.0020.0002] # HEXAGRAM FOR DELIVERANCE +4DE8 ; [*0EEA.0020.0002] # HEXAGRAM FOR DECREASE +4DE9 ; [*0EEB.0020.0002] # HEXAGRAM FOR INCREASE +4DEA ; [*0EEC.0020.0002] # HEXAGRAM FOR BREAKTHROUGH +4DEB ; [*0EED.0020.0002] # HEXAGRAM FOR COMING TO MEET +4DEC ; [*0EEE.0020.0002] # HEXAGRAM FOR GATHERING TOGETHER +4DED ; [*0EEF.0020.0002] # HEXAGRAM FOR PUSHING UPWARD +4DEE ; [*0EF0.0020.0002] # HEXAGRAM FOR OPPRESSION +4DEF ; [*0EF1.0020.0002] # HEXAGRAM FOR THE WELL +4DF0 ; [*0EF2.0020.0002] # HEXAGRAM FOR REVOLUTION +4DF1 ; [*0EF3.0020.0002] # HEXAGRAM FOR THE CAULDRON +4DF2 ; [*0EF4.0020.0002] # HEXAGRAM FOR THE AROUSING THUNDER +4DF3 ; [*0EF5.0020.0002] # HEXAGRAM FOR THE KEEPING STILL MOUNTAIN +4DF4 ; [*0EF6.0020.0002] # HEXAGRAM FOR DEVELOPMENT +4DF5 ; [*0EF7.0020.0002] # HEXAGRAM FOR THE MARRYING MAIDEN +4DF6 ; [*0EF8.0020.0002] # HEXAGRAM FOR ABUNDANCE +4DF7 ; [*0EF9.0020.0002] # HEXAGRAM FOR THE WANDERER +4DF8 ; [*0EFA.0020.0002] # HEXAGRAM FOR THE GENTLE WIND +4DF9 ; [*0EFB.0020.0002] # HEXAGRAM FOR THE JOYOUS LAKE +4DFA ; [*0EFC.0020.0002] # HEXAGRAM FOR DISPERSION +4DFB ; [*0EFD.0020.0002] # HEXAGRAM FOR LIMITATION +4DFC ; [*0EFE.0020.0002] # HEXAGRAM FOR INNER TRUTH +4DFD ; [*0EFF.0020.0002] # HEXAGRAM FOR SMALL PREPONDERANCE +4DFE ; [*0F00.0020.0002] # HEXAGRAM FOR AFTER COMPLETION +4DFF ; [*0F01.0020.0002] # HEXAGRAM FOR BEFORE COMPLETION +A490 ; [*0F59.0020.0002] # YI RADICAL QOT +A491 ; [*0F5A.0020.0002] # YI RADICAL LI +A492 ; [*0F5B.0020.0002] # YI RADICAL KIT +A493 ; [*0F5C.0020.0002] # YI RADICAL NYIP +A494 ; [*0F5D.0020.0002] # YI RADICAL CYP +A495 ; [*0F5E.0020.0002] # YI RADICAL SSI +A496 ; [*0F5F.0020.0002] # YI RADICAL GGOP +A497 ; [*0F60.0020.0002] # YI RADICAL GEP +A498 ; [*0F61.0020.0002] # YI RADICAL MI +A499 ; [*0F62.0020.0002] # YI RADICAL HXIT +A49A ; [*0F63.0020.0002] # YI RADICAL LYR +A49B ; [*0F64.0020.0002] # YI RADICAL BBUT +A49C ; [*0F65.0020.0002] # YI RADICAL MOP +A49D ; [*0F66.0020.0002] # YI RADICAL YO +A49E ; [*0F67.0020.0002] # YI RADICAL PUT +A49F ; [*0F68.0020.0002] # YI RADICAL HXUO +A4A0 ; [*0F69.0020.0002] # YI RADICAL TAT +A4A1 ; [*0F6A.0020.0002] # YI RADICAL GA +A4A2 ; [*0F6B.0020.0002] # YI RADICAL ZUP +A4A3 ; [*0F6C.0020.0002] # YI RADICAL CYT +A4A4 ; [*0F6D.0020.0002] # YI RADICAL DDUR +A4A5 ; [*0F6E.0020.0002] # YI RADICAL BUR +A4A6 ; [*0F6F.0020.0002] # YI RADICAL GGUO +A4A7 ; [*0F70.0020.0002] # YI RADICAL NYOP +A4A8 ; [*0F71.0020.0002] # YI RADICAL TU +A4A9 ; [*0F72.0020.0002] # YI RADICAL OP +A4AA ; [*0F73.0020.0002] # YI RADICAL JJUT +A4AB ; [*0F74.0020.0002] # YI RADICAL ZOT +A4AC ; [*0F75.0020.0002] # YI RADICAL PYT +A4AD ; [*0F76.0020.0002] # YI RADICAL HMO +A4AE ; [*0F77.0020.0002] # YI RADICAL YIT +A4AF ; [*0F78.0020.0002] # YI RADICAL VUR +A4B0 ; [*0F79.0020.0002] # YI RADICAL SHY +A4B1 ; [*0F7A.0020.0002] # YI RADICAL VEP +A4B2 ; [*0F7B.0020.0002] # YI RADICAL ZA +A4B3 ; [*0F7C.0020.0002] # YI RADICAL JO +A4B4 ; [*0F7D.0020.0002] # YI RADICAL NZUP +A4B5 ; [*0F7E.0020.0002] # YI RADICAL JJY +A4B6 ; [*0F7F.0020.0002] # YI RADICAL GOT +A4B7 ; [*0F80.0020.0002] # YI RADICAL JJIE +A4B8 ; [*0F81.0020.0002] # YI RADICAL WO +A4B9 ; [*0F82.0020.0002] # YI RADICAL DU +A4BA ; [*0F83.0020.0002] # YI RADICAL SHUR +A4BB ; [*0F84.0020.0002] # YI RADICAL LIE +A4BC ; [*0F85.0020.0002] # YI RADICAL CY +A4BD ; [*0F86.0020.0002] # YI RADICAL CUOP +A4BE ; [*0F87.0020.0002] # YI RADICAL CIP +A4BF ; [*0F88.0020.0002] # YI RADICAL HXOP +A4C0 ; [*0F89.0020.0002] # YI RADICAL SHAT +A4C1 ; [*0F8A.0020.0002] # YI RADICAL ZUR +A4C2 ; [*0F8B.0020.0002] # YI RADICAL SHOP +A4C3 ; [*0F8C.0020.0002] # YI RADICAL CHE +A4C4 ; [*0F8D.0020.0002] # YI RADICAL ZZIET +A4C5 ; [*0F8E.0020.0002] # YI RADICAL NBIE +A4C6 ; [*0F8F.0020.0002] # YI RADICAL KE +A4FE ; [*022E.0020.0002] # LISU PUNCTUATION COMMA +A4FF ; [*0286.0020.0002] # LISU PUNCTUATION FULL STOP +A60D ; [*022F.0020.0002] # VAI COMMA +A60E ; [*0287.0020.0002] # VAI FULL STOP +A60F ; [*0271.0020.0002] # VAI QUESTION MARK +A670 ; [.0000.0000.0000] # COMBINING CYRILLIC TEN MILLIONS SIGN +A671 ; [.0000.0000.0000] # COMBINING CYRILLIC HUNDRED MILLIONS SIGN +A672 ; [.0000.0000.0000] # COMBINING CYRILLIC THOUSAND MILLIONS SIGN +A673 ; [*0394.0020.0002] # SLAVONIC ASTERISK +A67E ; [*03CF.0020.0002] # CYRILLIC KAVYKA +A6F2 ; [*02D8.0020.0002] # BAMUM NJAEMLI +A6F3 ; [*0288.0020.0002] # BAMUM FULL STOP +A6F4 ; [*0260.0020.0002] # BAMUM COLON +A6F5 ; [*0230.0020.0002] # BAMUM COMMA +A6F6 ; [*0238.0020.0002] # BAMUM SEMICOLON +A6F7 ; [*0272.0020.0002] # BAMUM QUESTION MARK +A700 ; [*04E6.0020.0002] # MODIFIER LETTER CHINESE TONE YIN PING +A701 ; [*04E7.0020.0002] # MODIFIER LETTER CHINESE TONE YANG PING +A702 ; [*04E8.0020.0002] # MODIFIER LETTER CHINESE TONE YIN SHANG +A703 ; [*04E9.0020.0002] # MODIFIER LETTER CHINESE TONE YANG SHANG +A704 ; [*04EA.0020.0002] # MODIFIER LETTER CHINESE TONE YIN QU +A705 ; [*04EB.0020.0002] # MODIFIER LETTER CHINESE TONE YANG QU +A706 ; [*04EC.0020.0002] # MODIFIER LETTER CHINESE TONE YIN RU +A707 ; [*04ED.0020.0002] # MODIFIER LETTER CHINESE TONE YANG RU +A708 ; [*04EE.0020.0002] # MODIFIER LETTER EXTRA-HIGH DOTTED TONE BAR +A709 ; [*04EF.0020.0002] # MODIFIER LETTER HIGH DOTTED TONE BAR +A70A ; [*04F0.0020.0002] # MODIFIER LETTER MID DOTTED TONE BAR +A70B ; [*04F1.0020.0002] # MODIFIER LETTER LOW DOTTED TONE BAR +A70C ; [*04F2.0020.0002] # MODIFIER LETTER EXTRA-LOW DOTTED TONE BAR +A70D ; [*04F3.0020.0002] # MODIFIER LETTER EXTRA-HIGH DOTTED LEFT-STEM TONE BAR +A70E ; [*04F4.0020.0002] # MODIFIER LETTER HIGH DOTTED LEFT-STEM TONE BAR +A70F ; [*04F5.0020.0002] # MODIFIER LETTER MID DOTTED LEFT-STEM TONE BAR +A710 ; [*04F6.0020.0002] # MODIFIER LETTER LOW DOTTED LEFT-STEM TONE BAR +A711 ; [*04F7.0020.0002] # MODIFIER LETTER EXTRA-LOW DOTTED LEFT-STEM TONE BAR +A712 ; [*04F8.0020.0002] # MODIFIER LETTER EXTRA-HIGH LEFT-STEM TONE BAR +A713 ; [*04F9.0020.0002] # MODIFIER LETTER HIGH LEFT-STEM TONE BAR +A714 ; [*04FA.0020.0002] # MODIFIER LETTER MID LEFT-STEM TONE BAR +A715 ; [*04FB.0020.0002] # MODIFIER LETTER LOW LEFT-STEM TONE BAR +A716 ; [*04FC.0020.0002] # MODIFIER LETTER EXTRA-LOW LEFT-STEM TONE BAR +A717 ; [*04FD.0020.0002] # MODIFIER LETTER DOT VERTICAL BAR +A718 ; [*04FE.0020.0002] # MODIFIER LETTER DOT SLASH +A719 ; [*04FF.0020.0002] # MODIFIER LETTER DOT HORIZONTAL BAR +A71A ; [*0500.0020.0002] # MODIFIER LETTER LOWER RIGHT CORNER ANGLE +A71B ; [*0501.0020.0002] # MODIFIER LETTER RAISED UP ARROW +A71C ; [*0502.0020.0002] # MODIFIER LETTER RAISED DOWN ARROW +A71D ; [*0503.0020.0002] # MODIFIER LETTER RAISED EXCLAMATION MARK +A71E ; [*0504.0020.0002] # MODIFIER LETTER RAISED INVERTED EXCLAMATION MARK +A71F ; [*0505.0020.0002] # MODIFIER LETTER LOW INVERTED EXCLAMATION MARK +A720 ; [*0506.0020.0002] # MODIFIER LETTER STRESS AND HIGH TONE +A721 ; [*0507.0020.0002] # MODIFIER LETTER STRESS AND LOW TONE +A788 ; [*0508.0020.0002] # MODIFIER LETTER LOW CIRCUMFLEX ACCENT +A789 ; [*0509.0020.0002] # MODIFIER LETTER COLON +A78A ; [*050A.0020.0002] # MODIFIER LETTER SHORT EQUALS SIGN +A828 ; [*0535.0020.0002] # SYLOTI NAGRI POETRY MARK-1 +A829 ; [*0536.0020.0002] # SYLOTI NAGRI POETRY MARK-2 +A82A ; [*0537.0020.0002] # SYLOTI NAGRI POETRY MARK-3 +A82B ; [*0538.0020.0002] # SYLOTI NAGRI POETRY MARK-4 +A830 ; [*1B06.0020.0002] # NORTH INDIC FRACTION ONE QUARTER +A831 ; [*1B07.0020.0002] # NORTH INDIC FRACTION ONE HALF +A832 ; [*1B08.0020.0002] # NORTH INDIC FRACTION THREE QUARTERS +A833 ; [*1B09.0020.0002] # NORTH INDIC FRACTION ONE SIXTEENTH +A834 ; [*1B0A.0020.0002] # NORTH INDIC FRACTION ONE EIGHTH +A835 ; [*1B0B.0020.0002] # NORTH INDIC FRACTION THREE SIXTEENTHS +A836 ; [*0539.0020.0002] # NORTH INDIC QUARTER MARK +A837 ; [*053A.0020.0002] # NORTH INDIC PLACEHOLDER MARK +A839 ; [*053B.0020.0002] # NORTH INDIC QUANTITY MARK +A874 ; [*043E.0020.0002] # PHAGS-PA SINGLE HEAD MARK +A875 ; [*043F.0020.0002] # PHAGS-PA DOUBLE HEAD MARK +A876 ; [*0295.0020.0002] # PHAGS-PA MARK SHAD +A877 ; [*0296.0020.0002] # PHAGS-PA MARK DOUBLE SHAD +A8CE ; [*0291.0020.0002] # SAURASHTRA DANDA +A8CF ; [*0292.0020.0002] # SAURASHTRA DOUBLE DANDA +A8E0 ; [.0000.0000.0000] # COMBINING DEVANAGARI DIGIT ZERO +A8E1 ; [.0000.0000.0000] # COMBINING DEVANAGARI DIGIT ONE +A8E2 ; [.0000.0000.0000] # COMBINING DEVANAGARI DIGIT TWO +A8E3 ; [.0000.0000.0000] # COMBINING DEVANAGARI DIGIT THREE +A8E4 ; [.0000.0000.0000] # COMBINING DEVANAGARI DIGIT FOUR +A8E5 ; [.0000.0000.0000] # COMBINING DEVANAGARI DIGIT FIVE +A8E6 ; [.0000.0000.0000] # COMBINING DEVANAGARI DIGIT SIX +A8E7 ; [.0000.0000.0000] # COMBINING DEVANAGARI DIGIT SEVEN +A8E8 ; [.0000.0000.0000] # COMBINING DEVANAGARI DIGIT EIGHT +A8E9 ; [.0000.0000.0000] # COMBINING DEVANAGARI DIGIT NINE +A8EA ; [.0000.0000.0000] # COMBINING DEVANAGARI LETTER A +A8EB ; [.0000.0000.0000] # COMBINING DEVANAGARI LETTER U +A8EC ; [.0000.0000.0000] # COMBINING DEVANAGARI LETTER KA +A8ED ; [.0000.0000.0000] # COMBINING DEVANAGARI LETTER NA +A8EE ; [.0000.0000.0000] # COMBINING DEVANAGARI LETTER PA +A8EF ; [.0000.0000.0000] # COMBINING DEVANAGARI LETTER RA +A8F0 ; [.0000.0000.0000] # COMBINING DEVANAGARI LETTER VI +A8F1 ; [.0000.0000.0000] # COMBINING DEVANAGARI SIGN AVAGRAHA +A8F8 ; [*03ED.0020.0002] # DEVANAGARI SIGN PUSHPIKA +A8F9 ; [*03EE.0020.0002] # DEVANAGARI GAP FILLER +A8FA ; [*03EF.0020.0002] # DEVANAGARI CARET +A8FC ; [*03F0.0020.0002] # DEVANAGARI SIGN SIDDHAM +A92E ; [*0444.0020.0002] # KAYAH LI SIGN CWI +A92F ; [*0299.0020.0002] # KAYAH LI SIGN SHYA +A95F ; [*02D9.0020.0002] # REJANG SECTION MARK +A9C1 ; [*02CE.0020.0002] # JAVANESE LEFT RERENGGAN +A9C2 ; [*02CF.0020.0002] # JAVANESE RIGHT RERENGGAN +A9C3 ; [*02D0.0020.0002] # JAVANESE PADA ANDAP +A9C4 ; [*02D1.0020.0002] # JAVANESE PADA MADYA +A9C5 ; [*02D2.0020.0002] # JAVANESE PADA LUHUR +A9C6 ; [*02D3.0020.0002] # JAVANESE PADA WINDU +A9C7 ; [*025C.0020.0002] # JAVANESE PADA PANGKAT +A9C8 ; [*02A4.0020.0002] # JAVANESE PADA LINGSA +A9C9 ; [*02A5.0020.0002] # JAVANESE PADA LUNGSI +A9CA ; [*02D4.0020.0002] # JAVANESE PADA ADEG +A9CB ; [*02D5.0020.0002] # JAVANESE PADA ADEG ADEG +A9CC ; [*02D6.0020.0002] # JAVANESE PADA PISELEH +A9CD ; [*02D7.0020.0002] # JAVANESE TURNED PADA PISELEH +A9DE ; [*0445.0020.0002] # JAVANESE PADA TIRTA TUMETES +A9DF ; [*0446.0020.0002] # JAVANESE PADA ISEN-ISEN +AA5C ; [*0447.0020.0002] # CHAM PUNCTUATION SPIRAL +AA5D ; [*02A6.0020.0002] # CHAM PUNCTUATION DANDA +AA5E ; [*02A7.0020.0002] # CHAM PUNCTUATION DOUBLE DANDA +AA5F ; [*02A8.0020.0002] # CHAM PUNCTUATION TRIPLE DANDA +AA77 ; [*0563.0020.0002] # MYANMAR SYMBOL AITON EXCLAMATION +AA78 ; [*0564.0020.0002] # MYANMAR SYMBOL AITON ONE +AA79 ; [*0565.0020.0002] # MYANMAR SYMBOL AITON TWO +AADE ; [*03F7.0020.0002] # TAI VIET SYMBOL HO HOI +AADF ; [*03F8.0020.0002] # TAI VIET SYMBOL KOI KOI +AAF0 ; [*02A9.0020.0002] # MEETEI MAYEK CHEIKHAN +AAF1 ; [*0273.0020.0002] # MEETEI MAYEK AHANG KHUDAM +AB5B ; [*050B.0020.0002] # MODIFIER BREVE WITH INVERTED BREVE +ABEB ; [*02AA.0020.0002] # MEETEI MAYEK CHEIKHEI +FB29 ; [*062C.0020.0005] # HEBREW LETTER ALTERNATIVE PLUS SIGN +FBB2 ; [*0518.0020.0002] # ARABIC SYMBOL DOT ABOVE +FBB3 ; [*0519.0020.0002] # ARABIC SYMBOL DOT BELOW +FBB4 ; [*051A.0020.0002] # ARABIC SYMBOL TWO DOTS ABOVE +FBB5 ; [*051B.0020.0002] # ARABIC SYMBOL TWO DOTS BELOW +FBB6 ; [*051C.0020.0002] # ARABIC SYMBOL THREE DOTS ABOVE +FBB7 ; [*051D.0020.0002] # ARABIC SYMBOL THREE DOTS BELOW +FBB8 ; [*051E.0020.0002] # ARABIC SYMBOL THREE DOTS POINTING DOWNWARDS ABOVE +FBB9 ; [*051F.0020.0002] # ARABIC SYMBOL THREE DOTS POINTING DOWNWARDS BELOW +FBBA ; [*0520.0020.0002] # ARABIC SYMBOL FOUR DOTS ABOVE +FBBB ; [*0521.0020.0002] # ARABIC SYMBOL FOUR DOTS BELOW +FBBC ; [*0522.0020.0002] # ARABIC SYMBOL DOUBLE VERTICAL BAR BELOW +FBBD ; [*0523.0020.0002] # ARABIC SYMBOL TWO DOTS VERTICALLY ABOVE +FBBE ; [*0524.0020.0002] # ARABIC SYMBOL TWO DOTS VERTICALLY BELOW +FBBF ; [*0525.0020.0002] # ARABIC SYMBOL RING +FBC0 ; [*0526.0020.0002] # ARABIC SYMBOL SMALL TAH ABOVE +FBC1 ; [*0527.0020.0002] # ARABIC SYMBOL SMALL TAH BELOW +FD3E ; [*0382.0020.0002] # ORNATE LEFT PARENTHESIS +FD3F ; [*0383.0020.0002] # ORNATE RIGHT PARENTHESIS +FDFD ; [*0517.0020.0002] # ARABIC LIGATURE BISMILLAH AR-RAHMAN AR-RAHEEM +FE10 ; [*0222.0020.0016] # PRESENTATION FORM FOR VERTICAL COMMA +FE11 ; [*0231.0020.0016] # PRESENTATION FORM FOR VERTICAL IDEOGRAPHIC COMMA +FE12 ; [*028B.0020.0016] # PRESENTATION FORM FOR VERTICAL IDEOGRAPHIC FULL STOP +FE13 ; [*023A.0020.0016] # PRESENTATION FORM FOR VERTICAL COLON +FE14 ; [*0234.0020.0016] # PRESENTATION FORM FOR VERTICAL SEMICOLON +FE15 ; [*0261.0020.0016] # PRESENTATION FORM FOR VERTICAL EXCLAMATION MARK +FE16 ; [*0267.0020.0016] # PRESENTATION FORM FOR VERTICAL QUESTION MARK +FE17 ; [*037C.0020.0016] # PRESENTATION FORM FOR VERTICAL LEFT WHITE LENTICULAR BRACKET +FE18 ; [*037D.0020.0016] # PRESENTATION FORM FOR VERTICAL RIGHT WHITE LENTICULAR BRAKCET +FE19 ; [*0278.0020.0016][*0278.0020.0016][*0278.0020.0016] # PRESENTATION FORM FOR VERTICAL HORIZONTAL ELLIPSIS +FE21 ; [.0000.0000.0000] # COMBINING LIGATURE RIGHT HALF +FE23 ; [.0000.0000.0000] # COMBINING DOUBLE TILDE RIGHT HALF +FE24 ; [.0000.0000.0000] # COMBINING MACRON LEFT HALF +FE25 ; [.0000.0000.0000] # COMBINING MACRON RIGHT HALF +FE26 ; [.0000.0000.0000] # COMBINING CONJOINING MACRON +FE28 ; [.0000.0000.0000] # COMBINING LIGATURE RIGHT HALF BELOW +FE2A ; [.0000.0000.0000] # COMBINING TILDE RIGHT HALF BELOW +FE2B ; [.0000.0000.0000] # COMBINING MACRON LEFT HALF BELOW +FE2C ; [.0000.0000.0000] # COMBINING MACRON RIGHT HALF BELOW +FE2D ; [.0000.0000.0000] # COMBINING CONJOINING MACRON BELOW +FE2F ; [.0000.0000.0000] # COMBINING CYRILLIC TITLO RIGHT HALF +FE30 ; [*0278.0020.0016][*0278.0020.0016] # PRESENTATION FORM FOR VERTICAL TWO DOT LEADER +FE31 ; [*0216.0020.0016] # PRESENTATION FORM FOR VERTICAL EM DASH +FE32 ; [*0215.0020.0016] # PRESENTATION FORM FOR VERTICAL EN DASH +FE33 ; [*020B.0020.0016] # PRESENTATION FORM FOR VERTICAL LOW LINE +FE34 ; [*020B.0020.0016] # PRESENTATION FORM FOR VERTICAL WAVY LOW LINE +FE35 ; [*0318.0020.0016] # PRESENTATION FORM FOR VERTICAL LEFT PARENTHESIS +FE36 ; [*0319.0020.0016] # PRESENTATION FORM FOR VERTICAL RIGHT PARENTHESIS +FE37 ; [*031C.0020.0016] # PRESENTATION FORM FOR VERTICAL LEFT CURLY BRACKET +FE38 ; [*031D.0020.0016] # PRESENTATION FORM FOR VERTICAL RIGHT CURLY BRACKET +FE39 ; [*037A.0020.0016] # PRESENTATION FORM FOR VERTICAL LEFT TORTOISE SHELL BRACKET +FE3A ; [*037B.0020.0016] # PRESENTATION FORM FOR VERTICAL RIGHT TORTOISE SHELL BRACKET +FE3B ; [*0378.0020.0016] # PRESENTATION FORM FOR VERTICAL LEFT BLACK LENTICULAR BRACKET +FE3C ; [*0379.0020.0016] # PRESENTATION FORM FOR VERTICAL RIGHT BLACK LENTICULAR BRACKET +FE3D ; [*0372.0020.0016] # PRESENTATION FORM FOR VERTICAL LEFT DOUBLE ANGLE BRACKET +FE3E ; [*0373.0020.0016] # PRESENTATION FORM FOR VERTICAL RIGHT DOUBLE ANGLE BRACKET +FE3F ; [*0370.0020.0016] # PRESENTATION FORM FOR VERTICAL LEFT ANGLE BRACKET +FE40 ; [*0371.0020.0016] # PRESENTATION FORM FOR VERTICAL RIGHT ANGLE BRACKET +FE41 ; [*0374.0020.0016] # PRESENTATION FORM FOR VERTICAL LEFT CORNER BRACKET +FE42 ; [*0375.0020.0016] # PRESENTATION FORM FOR VERTICAL RIGHT CORNER BRACKET +FE43 ; [*0376.0020.0016] # PRESENTATION FORM FOR VERTICAL LEFT WHITE CORNER BRACKET +FE44 ; [*0377.0020.0016] # PRESENTATION FORM FOR VERTICAL RIGHT WHITE CORNER BRACKET +FE45 ; [*0232.0020.0002] # SESAME DOT +FE46 ; [*0233.0020.0002] # WHITE SESAME DOT +FE47 ; [*031A.0020.0016] # PRESENTATION FORM FOR VERTICAL LEFT SQUARE BRACKET +FE48 ; [*031B.0020.0016] # PRESENTATION FORM FOR VERTICAL RIGHT SQUARE BRACKET +FE49 ; [*020A.0020.0004] # DASHED OVERLINE +FE4A ; [*020A.0020.0004] # CENTRELINE OVERLINE +FE4B ; [*020A.0020.0004] # WAVY OVERLINE +FE4C ; [*020A.0020.0004] # DOUBLE WAVY OVERLINE +FE4D ; [*020B.0020.0004] # DASHED LOW LINE +FE4E ; [*020B.0020.0004] # CENTRELINE LOW LINE +FE4F ; [*020B.0020.0004] # WAVY LOW LINE +FE50 ; [*0222.0020.000F] # SMALL COMMA +FE51 ; [*0231.0020.000F] # SMALL IDEOGRAPHIC COMMA +FE52 ; [*0278.0020.000F] # SMALL FULL STOP +FE54 ; [*0234.0020.000F] # SMALL SEMICOLON +FE55 ; [*023A.0020.000F] # SMALL COLON +FE56 ; [*0267.0020.000F] # SMALL QUESTION MARK +FE57 ; [*0261.0020.000F] # SMALL EXCLAMATION MARK +FE58 ; [*0216.0020.000F] # SMALL EM DASH +FE59 ; [*0318.0020.000F] # SMALL LEFT PARENTHESIS +FE5A ; [*0319.0020.000F] # SMALL RIGHT PARENTHESIS +FE5B ; [*031C.0020.000F] # SMALL LEFT CURLY BRACKET +FE5C ; [*031D.0020.000F] # SMALL RIGHT CURLY BRACKET +FE5D ; [*037A.0020.000F] # SMALL LEFT TORTOISE SHELL BRACKET +FE5E ; [*037B.0020.000F] # SMALL RIGHT TORTOISE SHELL BRACKET +FE5F ; [*0399.0020.000F] # SMALL NUMBER SIGN +FE60 ; [*0397.0020.000F] # SMALL AMPERSAND +FE61 ; [*0390.0020.000F] # SMALL ASTERISK +FE62 ; [*062C.0020.000F] # SMALL PLUS SIGN +FE63 ; [*020D.0020.000F] # SMALL HYPHEN-MINUS +FE64 ; [*0630.0020.000F] # SMALL LESS-THAN SIGN +FE65 ; [*0632.0020.000F] # SMALL GREATER-THAN SIGN +FE66 ; [*0631.0020.000F] # SMALL EQUALS SIGN +FE68 ; [*0396.0020.000F] # SMALL REVERSE SOLIDUS +FE6A ; [*039A.0020.000F] # SMALL PERCENT SIGN +FE6B ; [*038F.0020.000F] # SMALL COMMERCIAL AT +FE73 ; [.0000.0000.0000] # ARABIC TAIL FRAGMENT +FF01 ; [*0261.0020.0003] # FULLWIDTH EXCLAMATION MARK +FF02 ; [*030D.0020.0003] # FULLWIDTH QUOTATION MARK +FF03 ; [*0399.0020.0003] # FULLWIDTH NUMBER SIGN +FF05 ; [*039A.0020.0003] # FULLWIDTH PERCENT SIGN +FF06 ; [*0397.0020.0003] # FULLWIDTH AMPERSAND +FF07 ; [*0306.0020.0003] # FULLWIDTH APOSTROPHE +FF08 ; [*0318.0020.0003] # FULLWIDTH LEFT PARENTHESIS +FF09 ; [*0319.0020.0003] # FULLWIDTH RIGHT PARENTHESIS +FF0A ; [*0390.0020.0003] # FULLWIDTH ASTERISK +FF0B ; [*062C.0020.0003] # FULLWIDTH PLUS SIGN +FF0C ; [*0222.0020.0003] # FULLWIDTH COMMA +FF0D ; [*020D.0020.0003] # FULLWIDTH HYPHEN-MINUS +FF0E ; [*0278.0020.0003] # FULLWIDTH FULL STOP +FF0F ; [*0395.0020.0003] # FULLWIDTH SOLIDUS +FF1A ; [*023A.0020.0003] # FULLWIDTH COLON +FF1B ; [*0234.0020.0003] # FULLWIDTH SEMICOLON +FF1C ; [*0630.0020.0003] # FULLWIDTH LESS-THAN SIGN +FF1D ; [*0631.0020.0003] # FULLWIDTH EQUALS SIGN +FF1E ; [*0632.0020.0003] # FULLWIDTH GREATER-THAN SIGN +FF1F ; [*0267.0020.0003] # FULLWIDTH QUESTION MARK +FF20 ; [*038F.0020.0003] # FULLWIDTH COMMERCIAL AT +FF3B ; [*031A.0020.0003] # FULLWIDTH LEFT SQUARE BRACKET +FF3C ; [*0396.0020.0003] # FULLWIDTH REVERSE SOLIDUS +FF3D ; [*031B.0020.0003] # FULLWIDTH RIGHT SQUARE BRACKET +FF3E ; [*049B.0020.0003] # FULLWIDTH CIRCUMFLEX ACCENT +FF3F ; [*020B.0020.0003] # FULLWIDTH LOW LINE +FF40 ; [*0498.0020.0003] # FULLWIDTH GRAVE ACCENT +FF5B ; [*031C.0020.0003] # FULLWIDTH LEFT CURLY BRACKET +FF5C ; [*0634.0020.0003] # FULLWIDTH VERTICAL LINE +FF5D ; [*031D.0020.0003] # FULLWIDTH RIGHT CURLY BRACKET +FF5E ; [*0636.0020.0003] # FULLWIDTH TILDE +FF5F ; [*032E.0020.0003] # FULLWIDTH LEFT WHITE PARENTHESIS +FF60 ; [*032F.0020.0003] # FULLWIDTH RIGHT WHITE PARENTHESIS +FF61 ; [*028B.0020.0012] # HALFWIDTH IDEOGRAPHIC FULL STOP +FF62 ; [*0374.0020.0012] # HALFWIDTH LEFT CORNER BRACKET +FF63 ; [*0375.0020.0012] # HALFWIDTH RIGHT CORNER BRACKET +FF64 ; [*0231.0020.0012] # HALFWIDTH IDEOGRAPHIC COMMA +FF65 ; [*0221.0020.0012] # HALFWIDTH KATAKANA MIDDLE DOT +FFE2 ; [*0633.0020.0003] # FULLWIDTH NOT SIGN +FFE3 ; [*049C.0020.0003] # FULLWIDTH MACRON +FFE4 ; [*0635.0020.0003] # FULLWIDTH BROKEN BAR +FFE8 ; [*0831.0020.0012] # HALFWIDTH FORMS LIGHT VERTICAL +FFE9 ; [*05B2.0020.0012] # HALFWIDTH LEFTWARDS ARROW +FFEA ; [*05B4.0020.0012] # HALFWIDTH UPWARDS ARROW +FFEB ; [*05B3.0020.0012] # HALFWIDTH RIGHTWARDS ARROW +FFEC ; [*05B5.0020.0012] # HALFWIDTH DOWNWARDS ARROW +FFED ; [*08CF.0020.0012] # HALFWIDTH BLACK SQUARE +FFEE ; [*08FA.0020.0012] # HALFWIDTH WHITE CIRCLE +FFFC ; [*1AF9.0020.0002] # OBJECT REPLACEMENT CHARACTER +10100 ; [*02FB.0020.0002] # AEGEAN WORD SEPARATOR LINE +10101 ; [*02FC.0020.0002] # AEGEAN WORD SEPARATOR DOT +10102 ; [*02FD.0020.0002] # AEGEAN CHECK MARK +10110 ; [*1B4D.0020.0002] # AEGEAN NUMBER TEN +10111 ; [*1B4E.0020.0002] # AEGEAN NUMBER TWENTY +10112 ; [*1B4F.0020.0002] # AEGEAN NUMBER THIRTY +10113 ; [*1B50.0020.0002] # AEGEAN NUMBER FORTY +10114 ; [*1B51.0020.0002] # AEGEAN NUMBER FIFTY +10115 ; [*1B52.0020.0002] # AEGEAN NUMBER SIXTY +10116 ; [*1B53.0020.0002] # AEGEAN NUMBER SEVENTY +10117 ; [*1B54.0020.0002] # AEGEAN NUMBER EIGHTY +10118 ; [*1B55.0020.0002] # AEGEAN NUMBER NINETY +10119 ; [*1B56.0020.0002] # AEGEAN NUMBER ONE HUNDRED +1011A ; [*1B57.0020.0002] # AEGEAN NUMBER TWO HUNDRED +1011B ; [*1B58.0020.0002] # AEGEAN NUMBER THREE HUNDRED +1011C ; [*1B59.0020.0002] # AEGEAN NUMBER FOUR HUNDRED +1011D ; [*1B5A.0020.0002] # AEGEAN NUMBER FIVE HUNDRED +1011E ; [*1B5B.0020.0002] # AEGEAN NUMBER SIX HUNDRED +1011F ; [*1B5C.0020.0002] # AEGEAN NUMBER SEVEN HUNDRED +10120 ; [*1B5D.0020.0002] # AEGEAN NUMBER EIGHT HUNDRED +10121 ; [*1B5E.0020.0002] # AEGEAN NUMBER NINE HUNDRED +10122 ; [*1B5F.0020.0002] # AEGEAN NUMBER ONE THOUSAND +10123 ; [*1B60.0020.0002] # AEGEAN NUMBER TWO THOUSAND +10124 ; [*1B61.0020.0002] # AEGEAN NUMBER THREE THOUSAND +10125 ; [*1B62.0020.0002] # AEGEAN NUMBER FOUR THOUSAND +10126 ; [*1B63.0020.0002] # AEGEAN NUMBER FIVE THOUSAND +10127 ; [*1B64.0020.0002] # AEGEAN NUMBER SIX THOUSAND +10128 ; [*1B65.0020.0002] # AEGEAN NUMBER SEVEN THOUSAND +10129 ; [*1B66.0020.0002] # AEGEAN NUMBER EIGHT THOUSAND +1012A ; [*1B67.0020.0002] # AEGEAN NUMBER NINE THOUSAND +1012B ; [*1B68.0020.0002] # AEGEAN NUMBER TEN THOUSAND +1012C ; [*1B69.0020.0002] # AEGEAN NUMBER TWENTY THOUSAND +1012D ; [*1B6A.0020.0002] # AEGEAN NUMBER THIRTY THOUSAND +1012E ; [*1B6B.0020.0002] # AEGEAN NUMBER FORTY THOUSAND +1012F ; [*1B6C.0020.0002] # AEGEAN NUMBER FIFTY THOUSAND +10130 ; [*1B6D.0020.0002] # AEGEAN NUMBER SIXTY THOUSAND +10131 ; [*1B6E.0020.0002] # AEGEAN NUMBER SEVENTY THOUSAND +10132 ; [*1B6F.0020.0002] # AEGEAN NUMBER EIGHTY THOUSAND +10133 ; [*1B70.0020.0002] # AEGEAN NUMBER NINETY THOUSAND +10137 ; [*0F90.0020.0002] # AEGEAN WEIGHT BASE UNIT +10138 ; [*0F91.0020.0002] # AEGEAN WEIGHT FIRST SUBUNIT +10139 ; [*0F92.0020.0002] # AEGEAN WEIGHT SECOND SUBUNIT +1013A ; [*0F93.0020.0002] # AEGEAN WEIGHT THIRD SUBUNIT +1013B ; [*0F94.0020.0002] # AEGEAN WEIGHT FOURTH SUBUNIT +1013C ; [*0F95.0020.0002] # AEGEAN DRY MEASURE FIRST SUBUNIT +1013D ; [*0F96.0020.0002] # AEGEAN LIQUID MEASURE FIRST SUBUNIT +1013E ; [*0F97.0020.0002] # AEGEAN MEASURE SECOND SUBUNIT +1013F ; [*0F98.0020.0002] # AEGEAN MEASURE THIRD SUBUNIT +10140 ; [*1B71.0020.0002] # GREEK ACROPHONIC ATTIC ONE QUARTER +10141 ; [*1B72.0020.0002] # GREEK ACROPHONIC ATTIC ONE HALF +10144 ; [*1B73.0020.0002] # GREEK ACROPHONIC ATTIC FIFTY +10145 ; [*1B74.0020.0002] # GREEK ACROPHONIC ATTIC FIVE HUNDRED +10146 ; [*1B75.0020.0002] # GREEK ACROPHONIC ATTIC FIVE THOUSAND +10147 ; [*1B76.0020.0002] # GREEK ACROPHONIC ATTIC FIFTY THOUSAND +10149 ; [*1B77.0020.0002] # GREEK ACROPHONIC ATTIC TEN TALENTS +1014A ; [*1B78.0020.0002] # GREEK ACROPHONIC ATTIC FIFTY TALENTS +1014B ; [*1B79.0020.0002] # GREEK ACROPHONIC ATTIC ONE HUNDRED TALENTS +1014C ; [*1B7A.0020.0002] # GREEK ACROPHONIC ATTIC FIVE HUNDRED TALENTS +1014D ; [*1B7B.0020.0002] # GREEK ACROPHONIC ATTIC ONE THOUSAND TALENTS +1014E ; [*1B7C.0020.0002] # GREEK ACROPHONIC ATTIC FIVE THOUSAND TALENTS +10150 ; [*1B7D.0020.0002] # GREEK ACROPHONIC ATTIC TEN STATERS +10151 ; [*1B7E.0020.0002] # GREEK ACROPHONIC ATTIC FIFTY STATERS +10152 ; [*1B7F.0020.0002] # GREEK ACROPHONIC ATTIC ONE HUNDRED STATERS +10153 ; [*1B80.0020.0002] # GREEK ACROPHONIC ATTIC FIVE HUNDRED STATERS +10154 ; [*1B81.0020.0002] # GREEK ACROPHONIC ATTIC ONE THOUSAND STATERS +10155 ; [*1B82.0020.0002] # GREEK ACROPHONIC ATTIC TEN THOUSAND STATERS +10156 ; [*1B83.0020.0002] # GREEK ACROPHONIC ATTIC FIFTY THOUSAND STATERS +10157 ; [*1B84.0020.0002] # GREEK ACROPHONIC ATTIC TEN MNAS +10160 ; [*1B85.0020.0002] # GREEK ACROPHONIC TROEZENIAN TEN +10161 ; [*1B86.0020.0002] # GREEK ACROPHONIC TROEZENIAN TEN ALTERNATE FORM +10162 ; [*1B87.0020.0002] # GREEK ACROPHONIC HERMIONIAN TEN +10163 ; [*1B88.0020.0002] # GREEK ACROPHONIC MESSENIAN TEN +10164 ; [*1B89.0020.0002] # GREEK ACROPHONIC THESPIAN TEN +10165 ; [*1B8A.0020.0002] # GREEK ACROPHONIC THESPIAN THIRTY +10166 ; [*1B8B.0020.0002] # GREEK ACROPHONIC TROEZENIAN FIFTY +10167 ; [*1B8C.0020.0002] # GREEK ACROPHONIC TROEZENIAN FIFTY ALTERNATE FORM +10168 ; [*1B8D.0020.0002] # GREEK ACROPHONIC HERMIONIAN FIFTY +10169 ; [*1B8E.0020.0002] # GREEK ACROPHONIC THESPIAN FIFTY +1016A ; [*1B8F.0020.0002] # GREEK ACROPHONIC THESPIAN ONE HUNDRED +1016B ; [*1B90.0020.0002] # GREEK ACROPHONIC THESPIAN THREE HUNDRED +1016C ; [*1B91.0020.0002] # GREEK ACROPHONIC EPIDAUREAN FIVE HUNDRED +1016D ; [*1B92.0020.0002] # GREEK ACROPHONIC TROEZENIAN FIVE HUNDRED +1016E ; [*1B93.0020.0002] # GREEK ACROPHONIC THESPIAN FIVE HUNDRED +1016F ; [*1B94.0020.0002] # GREEK ACROPHONIC CARYSTIAN FIVE HUNDRED +10170 ; [*1B95.0020.0002] # GREEK ACROPHONIC NAXIAN FIVE HUNDRED +10171 ; [*1B96.0020.0002] # GREEK ACROPHONIC THESPIAN ONE THOUSAND +10172 ; [*1B97.0020.0002] # GREEK ACROPHONIC THESPIAN FIVE THOUSAND +10174 ; [*1B98.0020.0002] # GREEK ACROPHONIC STRATIAN FIFTY MNAS +10175 ; [*1B99.0020.0002] # GREEK ONE HALF SIGN +10176 ; [*1B9A.0020.0002] # GREEK ONE HALF SIGN ALTERNATE FORM +10177 ; [*1B9B.0020.0002] # GREEK TWO THIRDS SIGN +10178 ; [*1B9C.0020.0002] # GREEK THREE QUARTERS SIGN +10179 ; [*0F99.0020.0002] # GREEK YEAR SIGN +1017A ; [*0F9A.0020.0002] # GREEK TALENT SIGN +1017B ; [*0F9B.0020.0002] # GREEK DRACHMA SIGN +1017C ; [*0F9C.0020.0002] # GREEK OBOL SIGN +1017D ; [*0F9D.0020.0002] # GREEK TWO OBOLS SIGN +1017E ; [*0F9E.0020.0002] # GREEK THREE OBOLS SIGN +1017F ; [*0F9F.0020.0002] # GREEK FOUR OBOLS SIGN +10180 ; [*0FA0.0020.0002] # GREEK FIVE OBOLS SIGN +10181 ; [*0FA1.0020.0002] # GREEK METRETES SIGN +10182 ; [*0FA2.0020.0002] # GREEK KYATHOS BASE SIGN +10183 ; [*0FA3.0020.0002] # GREEK LITRA SIGN +10184 ; [*0FA4.0020.0002] # GREEK OUNKIA SIGN +10185 ; [*0FA5.0020.0002] # GREEK XESTES SIGN +10186 ; [*0FA6.0020.0002] # GREEK ARTABE SIGN +10187 ; [*0FA7.0020.0002] # GREEK AROURA SIGN +10188 ; [*0FA8.0020.0002] # GREEK GRAMMA SIGN +10189 ; [*0FA9.0020.0002] # GREEK TRYBLION BASE SIGN +1018B ; [*1B9D.0020.0002] # GREEK ONE QUARTER SIGN +1018C ; [*0FAA.0020.0002] # GREEK SINUSOID SIGN +1018D ; [*0FAB.0020.0002] # GREEK INDICTION SIGN +1018E ; [*0FAC.0020.0002] # NOMISMA SIGN +10190 ; [*0FAD.0020.0002] # ROMAN SEXTANS SIGN +10191 ; [*0FAE.0020.0002] # ROMAN UNCIA SIGN +10192 ; [*0FAF.0020.0002] # ROMAN SEMUNCIA SIGN +10193 ; [*0FB0.0020.0002] # ROMAN SEXTULA SIGN +10194 ; [*0FB1.0020.0002] # ROMAN DIMIDIA SEXTULA SIGN +10195 ; [*0FB2.0020.0002] # ROMAN SILIQUA SIGN +10196 ; [*0FB3.0020.0002] # ROMAN DENARIUS SIGN +10197 ; [*0FB4.0020.0002] # ROMAN QUINARIUS SIGN +10198 ; [*0FB5.0020.0002] # ROMAN SESTERTIUS SIGN +10199 ; [*0FB6.0020.0002] # ROMAN DUPONDIUS SIGN +1019A ; [*0FB7.0020.0002] # ROMAN AS SIGN +1019B ; [*0FB8.0020.0002] # ROMAN CENTURIAL SIGN +101A0 ; [*0FB9.0020.0002] # GREEK SYMBOL TAU RHO +101D0 ; [*0FBA.0020.0002] # PHAISTOS DISC SIGN PEDESTRIAN +101D1 ; [*0FBB.0020.0002] # PHAISTOS DISC SIGN PLUMED HEAD +101D2 ; [*0FBC.0020.0002] # PHAISTOS DISC SIGN TATTOOED HEAD +101D3 ; [*0FBD.0020.0002] # PHAISTOS DISC SIGN CAPTIVE +101D4 ; [*0FBE.0020.0002] # PHAISTOS DISC SIGN CHILD +101D5 ; [*0FBF.0020.0002] # PHAISTOS DISC SIGN WOMAN +101D6 ; [*0FC0.0020.0002] # PHAISTOS DISC SIGN HELMET +101D7 ; [*0FC1.0020.0002] # PHAISTOS DISC SIGN GAUNTLET +101D8 ; [*0FC2.0020.0002] # PHAISTOS DISC SIGN TIARA +101D9 ; [*0FC3.0020.0002] # PHAISTOS DISC SIGN ARROW +101DA ; [*0FC4.0020.0002] # PHAISTOS DISC SIGN BOW +101DB ; [*0FC5.0020.0002] # PHAISTOS DISC SIGN SHIELD +101DC ; [*0FC6.0020.0002] # PHAISTOS DISC SIGN CLUB +101DD ; [*0FC7.0020.0002] # PHAISTOS DISC SIGN MANACLES +101DE ; [*0FC8.0020.0002] # PHAISTOS DISC SIGN MATTOCK +101DF ; [*0FC9.0020.0002] # PHAISTOS DISC SIGN SAW +101E0 ; [*0FCA.0020.0002] # PHAISTOS DISC SIGN LID +101E1 ; [*0FCB.0020.0002] # PHAISTOS DISC SIGN BOOMERANG +101E2 ; [*0FCC.0020.0002] # PHAISTOS DISC SIGN CARPENTRY PLANE +101E3 ; [*0FCD.0020.0002] # PHAISTOS DISC SIGN DOLIUM +101E4 ; [*0FCE.0020.0002] # PHAISTOS DISC SIGN COMB +101E5 ; [*0FCF.0020.0002] # PHAISTOS DISC SIGN SLING +101E6 ; [*0FD0.0020.0002] # PHAISTOS DISC SIGN COLUMN +101E7 ; [*0FD1.0020.0002] # PHAISTOS DISC SIGN BEEHIVE +101E8 ; [*0FD2.0020.0002] # PHAISTOS DISC SIGN SHIP +101E9 ; [*0FD3.0020.0002] # PHAISTOS DISC SIGN HORN +101EA ; [*0FD4.0020.0002] # PHAISTOS DISC SIGN HIDE +101EB ; [*0FD5.0020.0002] # PHAISTOS DISC SIGN BULLS LEG +101EC ; [*0FD6.0020.0002] # PHAISTOS DISC SIGN CAT +101ED ; [*0FD7.0020.0002] # PHAISTOS DISC SIGN RAM +101EE ; [*0FD8.0020.0002] # PHAISTOS DISC SIGN EAGLE +101EF ; [*0FD9.0020.0002] # PHAISTOS DISC SIGN DOVE +101F0 ; [*0FDA.0020.0002] # PHAISTOS DISC SIGN TUNNY +101F1 ; [*0FDB.0020.0002] # PHAISTOS DISC SIGN BEE +101F2 ; [*0FDC.0020.0002] # PHAISTOS DISC SIGN PLANE TREE +101F3 ; [*0FDD.0020.0002] # PHAISTOS DISC SIGN VINE +101F4 ; [*0FDE.0020.0002] # PHAISTOS DISC SIGN PAPYRUS +101F5 ; [*0FDF.0020.0002] # PHAISTOS DISC SIGN ROSETTE +101F6 ; [*0FE0.0020.0002] # PHAISTOS DISC SIGN LILY +101F7 ; [*0FE1.0020.0002] # PHAISTOS DISC SIGN OX BACK +101F8 ; [*0FE2.0020.0002] # PHAISTOS DISC SIGN FLUTE +101F9 ; [*0FE3.0020.0002] # PHAISTOS DISC SIGN GRATER +101FA ; [*0FE4.0020.0002] # PHAISTOS DISC SIGN STRAINER +101FB ; [*0FE5.0020.0002] # PHAISTOS DISC SIGN SMALL AXE +101FC ; [*0FE6.0020.0002] # PHAISTOS DISC SIGN WAVY BAND +102E0 ; [.0000.0000.0000] # COPTIC EPACT THOUSANDS MARK +102EA ; [*1B9E.0020.0002] # COPTIC EPACT NUMBER TEN +102EB ; [*1B9F.0020.0002] # COPTIC EPACT NUMBER TWENTY +102EC ; [*1BA0.0020.0002] # COPTIC EPACT NUMBER THIRTY +102ED ; [*1BA1.0020.0002] # COPTIC EPACT NUMBER FORTY +102EE ; [*1BA2.0020.0002] # COPTIC EPACT NUMBER FIFTY +102EF ; [*1BA3.0020.0002] # COPTIC EPACT NUMBER SIXTY +102F0 ; [*1BA4.0020.0002] # COPTIC EPACT NUMBER SEVENTY +102F1 ; [*1BA5.0020.0002] # COPTIC EPACT NUMBER EIGHTY +102F2 ; [*1BA6.0020.0002] # COPTIC EPACT NUMBER NINETY +102F3 ; [*1BA7.0020.0002] # COPTIC EPACT NUMBER ONE HUNDRED +102F4 ; [*1BA8.0020.0002] # COPTIC EPACT NUMBER TWO HUNDRED +102F5 ; [*1BA9.0020.0002] # COPTIC EPACT NUMBER THREE HUNDRED +102F6 ; [*1BAA.0020.0002] # COPTIC EPACT NUMBER FOUR HUNDRED +102F7 ; [*1BAB.0020.0002] # COPTIC EPACT NUMBER FIVE HUNDRED +102F8 ; [*1BAC.0020.0002] # COPTIC EPACT NUMBER SIX HUNDRED +102F9 ; [*1BAD.0020.0002] # COPTIC EPACT NUMBER SEVEN HUNDRED +102FA ; [*1BAE.0020.0002] # COPTIC EPACT NUMBER EIGHT HUNDRED +102FB ; [*1BAF.0020.0002] # COPTIC EPACT NUMBER NINE HUNDRED +10322 ; [*1B47.0020.0002] # OLD ITALIC NUMERAL TEN +10323 ; [*1B48.0020.0002] # OLD ITALIC NUMERAL FIFTY +1039F ; [*02FE.0020.0002] # UGARITIC WORD DIVIDER +103D0 ; [*02FF.0020.0002] # OLD PERSIAN WORD DIVIDER +103D3 ; [*1BB0.0020.0002] # OLD PERSIAN NUMBER TEN +103D4 ; [*1BB1.0020.0002] # OLD PERSIAN NUMBER TWENTY +103D5 ; [*1BB2.0020.0002] # OLD PERSIAN NUMBER HUNDRED +1056F ; [*0448.0020.0002] # CAUCASIAN ALBANIAN CITATION MARK +10857 ; [*02DA.0020.0002] # IMPERIAL ARAMAIC SECTION SIGN +1085B ; [*1BC2.0020.0002] # IMPERIAL ARAMAIC NUMBER TEN +1085C ; [*1BC3.0020.0002] # IMPERIAL ARAMAIC NUMBER TWENTY +1085D ; [*1BC4.0020.0002] # IMPERIAL ARAMAIC NUMBER ONE HUNDRED +1085E ; [*1BC5.0020.0002] # IMPERIAL ARAMAIC NUMBER ONE THOUSAND +1085F ; [*1BC6.0020.0002] # IMPERIAL ARAMAIC NUMBER TEN THOUSAND +10877 ; [*0FE7.0020.0002] # PALMYRENE LEFT-POINTING FLEURON +10878 ; [*0FE8.0020.0002] # PALMYRENE RIGHT-POINTING FLEURON +1087E ; [*1BB3.0020.0002] # PALMYRENE NUMBER TEN +1087F ; [*1BB4.0020.0002] # PALMYRENE NUMBER TWENTY +108AD ; [*1BB5.0020.0002] # NABATAEAN NUMBER TEN +108AE ; [*1BB6.0020.0002] # NABATAEAN NUMBER TWENTY +108AF ; [*1BB7.0020.0002] # NABATAEAN NUMBER ONE HUNDRED +108FD ; [*1BB8.0020.0002] # HATRAN NUMBER TEN +108FE ; [*1BB9.0020.0002] # HATRAN NUMBER TWENTY +108FF ; [*1BBA.0020.0002] # HATRAN NUMBER ONE HUNDRED +10917 ; [*1BBF.0020.0002] # PHOENICIAN NUMBER TEN +10918 ; [*1BC0.0020.0002] # PHOENICIAN NUMBER TWENTY +10919 ; [*1BC1.0020.0002] # PHOENICIAN NUMBER ONE HUNDRED +1091F ; [*0300.0020.0002] # PHOENICIAN WORD SEPARATOR +1093F ; [*02FA.0020.0002] # LYDIAN TRIANGULAR MARK +109BC ; [*1C41.0020.0002] # MEROITIC CURSIVE FRACTION ELEVEN TWELFTHS +109BD ; [*1C36.0020.0002] # MEROITIC CURSIVE FRACTION ONE HALF +109C9 ; [*1C0B.0020.0002] # MEROITIC CURSIVE NUMBER TEN +109CA ; [*1C0C.0020.0002] # MEROITIC CURSIVE NUMBER TWENTY +109CB ; [*1C0D.0020.0002] # MEROITIC CURSIVE NUMBER THIRTY +109CC ; [*1C0E.0020.0002] # MEROITIC CURSIVE NUMBER FORTY +109CD ; [*1C0F.0020.0002] # MEROITIC CURSIVE NUMBER FIFTY +109CE ; [*1C10.0020.0002] # MEROITIC CURSIVE NUMBER SIXTY +109CF ; [*1C11.0020.0002] # MEROITIC CURSIVE NUMBER SEVENTY +109D2 ; [*1C12.0020.0002] # MEROITIC CURSIVE NUMBER ONE HUNDRED +109D3 ; [*1C13.0020.0002] # MEROITIC CURSIVE NUMBER TWO HUNDRED +109D4 ; [*1C14.0020.0002] # MEROITIC CURSIVE NUMBER THREE HUNDRED +109D5 ; [*1C15.0020.0002] # MEROITIC CURSIVE NUMBER FOUR HUNDRED +109D6 ; [*1C16.0020.0002] # MEROITIC CURSIVE NUMBER FIVE HUNDRED +109D7 ; [*1C17.0020.0002] # MEROITIC CURSIVE NUMBER SIX HUNDRED +109D8 ; [*1C18.0020.0002] # MEROITIC CURSIVE NUMBER SEVEN HUNDRED +109D9 ; [*1C19.0020.0002] # MEROITIC CURSIVE NUMBER EIGHT HUNDRED +109DA ; [*1C1A.0020.0002] # MEROITIC CURSIVE NUMBER NINE HUNDRED +109DB ; [*1C1B.0020.0002] # MEROITIC CURSIVE NUMBER ONE THOUSAND +109DC ; [*1C1C.0020.0002] # MEROITIC CURSIVE NUMBER TWO THOUSAND +109DD ; [*1C1D.0020.0002] # MEROITIC CURSIVE NUMBER THREE THOUSAND +109DE ; [*1C1E.0020.0002] # MEROITIC CURSIVE NUMBER FOUR THOUSAND +109DF ; [*1C1F.0020.0002] # MEROITIC CURSIVE NUMBER FIVE THOUSAND +109E0 ; [*1C20.0020.0002] # MEROITIC CURSIVE NUMBER SIX THOUSAND +109E1 ; [*1C21.0020.0002] # MEROITIC CURSIVE NUMBER SEVEN THOUSAND +109E2 ; [*1C22.0020.0002] # MEROITIC CURSIVE NUMBER EIGHT THOUSAND +109E3 ; [*1C23.0020.0002] # MEROITIC CURSIVE NUMBER NINE THOUSAND +109E4 ; [*1C24.0020.0002] # MEROITIC CURSIVE NUMBER TEN THOUSAND +109E5 ; [*1C25.0020.0002] # MEROITIC CURSIVE NUMBER TWENTY THOUSAND +109E6 ; [*1C26.0020.0002] # MEROITIC CURSIVE NUMBER THIRTY THOUSAND +109E7 ; [*1C27.0020.0002] # MEROITIC CURSIVE NUMBER FORTY THOUSAND +109E8 ; [*1C28.0020.0002] # MEROITIC CURSIVE NUMBER FIFTY THOUSAND +109E9 ; [*1C29.0020.0002] # MEROITIC CURSIVE NUMBER SIXTY THOUSAND +109EA ; [*1C2A.0020.0002] # MEROITIC CURSIVE NUMBER SEVENTY THOUSAND +109EB ; [*1C2B.0020.0002] # MEROITIC CURSIVE NUMBER EIGHTY THOUSAND +109EC ; [*1C2C.0020.0002] # MEROITIC CURSIVE NUMBER NINETY THOUSAND +109ED ; [*1C2D.0020.0002] # MEROITIC CURSIVE NUMBER ONE HUNDRED THOUSAND +109EE ; [*1C2E.0020.0002] # MEROITIC CURSIVE NUMBER TWO HUNDRED THOUSAND +109EF ; [*1C2F.0020.0002] # MEROITIC CURSIVE NUMBER THREE HUNDRED THOUSAND +109F0 ; [*1C30.0020.0002] # MEROITIC CURSIVE NUMBER FOUR HUNDRED THOUSAND +109F1 ; [*1C31.0020.0002] # MEROITIC CURSIVE NUMBER FIVE HUNDRED THOUSAND +109F2 ; [*1C32.0020.0002] # MEROITIC CURSIVE NUMBER SIX HUNDRED THOUSAND +109F3 ; [*1C33.0020.0002] # MEROITIC CURSIVE NUMBER SEVEN HUNDRED THOUSAND +109F4 ; [*1C34.0020.0002] # MEROITIC CURSIVE NUMBER EIGHT HUNDRED THOUSAND +109F5 ; [*1C35.0020.0002] # MEROITIC CURSIVE NUMBER NINE HUNDRED THOUSAND +109F6 ; [*1C37.0020.0002] # MEROITIC CURSIVE FRACTION ONE TWELFTH +109F7 ; [*1C38.0020.0002] # MEROITIC CURSIVE FRACTION TWO TWELFTHS +109F8 ; [*1C39.0020.0002] # MEROITIC CURSIVE FRACTION THREE TWELFTHS +109F9 ; [*1C3A.0020.0002] # MEROITIC CURSIVE FRACTION FOUR TWELFTHS +109FA ; [*1C3B.0020.0002] # MEROITIC CURSIVE FRACTION FIVE TWELFTHS +109FB ; [*1C3C.0020.0002] # MEROITIC CURSIVE FRACTION SIX TWELFTHS +109FC ; [*1C3D.0020.0002] # MEROITIC CURSIVE FRACTION SEVEN TWELFTHS +109FD ; [*1C3E.0020.0002] # MEROITIC CURSIVE FRACTION EIGHT TWELFTHS +109FE ; [*1C3F.0020.0002] # MEROITIC CURSIVE FRACTION NINE TWELFTHS +109FF ; [*1C40.0020.0002] # MEROITIC CURSIVE FRACTION TEN TWELFTHS +10A44 ; [*1BE2.0020.0002] # KHAROSHTHI NUMBER TEN +10A45 ; [*1BE3.0020.0002] # KHAROSHTHI NUMBER TWENTY +10A46 ; [*1BE4.0020.0002] # KHAROSHTHI NUMBER ONE HUNDRED +10A47 ; [*1BE5.0020.0002] # KHAROSHTHI NUMBER ONE THOUSAND +10A50 ; [*044E.0020.0002] # KHAROSHTHI PUNCTUATION DOT +10A51 ; [*044F.0020.0002] # KHAROSHTHI PUNCTUATION SMALL CIRCLE +10A52 ; [*0450.0020.0002] # KHAROSHTHI PUNCTUATION CIRCLE +10A53 ; [*0451.0020.0002] # KHAROSHTHI PUNCTUATION CRESCENT BAR +10A54 ; [*0452.0020.0002] # KHAROSHTHI PUNCTUATION MANGALAM +10A55 ; [*0453.0020.0002] # KHAROSHTHI PUNCTUATION LOTUS +10A56 ; [*02AB.0020.0002] # KHAROSHTHI PUNCTUATION DANDA +10A57 ; [*02AC.0020.0002] # KHAROSHTHI PUNCTUATION DOUBLE DANDA +10A58 ; [*0454.0020.0002] # KHAROSHTHI PUNCTUATION LINES +10A7E ; [*1BBB.0020.0002] # OLD SOUTH ARABIAN NUMBER FIFTY +10A7F ; [*1BBC.0020.0002] # OLD SOUTH ARABIAN NUMERIC INDICATOR +10A9E ; [*1BBD.0020.0002] # OLD NORTH ARABIAN NUMBER TEN +10A9F ; [*1BBE.0020.0002] # OLD NORTH ARABIAN NUMBER TWENTY +10AED ; [*1BC7.0020.0002] # MANICHAEAN NUMBER TEN +10AEE ; [*1BC8.0020.0002] # MANICHAEAN NUMBER TWENTY +10AEF ; [*1BC9.0020.0002] # MANICHAEAN NUMBER ONE HUNDRED +10AF0 ; [*0459.0020.0002] # MANICHAEAN PUNCTUATION STAR +10AF1 ; [*045A.0020.0002] # MANICHAEAN PUNCTUATION FLEURON +10AF2 ; [*045B.0020.0002] # MANICHAEAN PUNCTUATION DOUBLE DOT WITHIN DOT +10AF3 ; [*045C.0020.0002] # MANICHAEAN PUNCTUATION DOT WITHIN DOT +10AF4 ; [*045D.0020.0002] # MANICHAEAN PUNCTUATION DOT +10AF5 ; [*045E.0020.0002] # MANICHAEAN PUNCTUATION TWO DOTS +10AF6 ; [*045F.0020.0002] # MANICHAEAN PUNCTUATION LINE FILLER +10B39 ; [*0458.0020.0002] # AVESTAN ABBREVIATION MARK +10B3A ; [*02DB.0020.0002] # TINY TWO DOTS OVER ONE DOT PUNCTUATION +10B3B ; [*02DC.0020.0002] # SMALL TWO DOTS OVER ONE DOT PUNCTUATION +10B3C ; [*02DD.0020.0002] # LARGE TWO DOTS OVER ONE DOT PUNCTUATION +10B3D ; [*02DE.0020.0002] # LARGE ONE DOT OVER TWO DOTS PUNCTUATION +10B3E ; [*02DF.0020.0002] # LARGE TWO RINGS OVER ONE RING PUNCTUATION +10B3F ; [*02E0.0020.0002] # LARGE ONE RING OVER TWO RINGS PUNCTUATION +10B5C ; [*1BCA.0020.0002] # INSCRIPTIONAL PARTHIAN NUMBER TEN +10B5D ; [*1BCB.0020.0002] # INSCRIPTIONAL PARTHIAN NUMBER TWENTY +10B5E ; [*1BCC.0020.0002] # INSCRIPTIONAL PARTHIAN NUMBER ONE HUNDRED +10B5F ; [*1BCD.0020.0002] # INSCRIPTIONAL PARTHIAN NUMBER ONE THOUSAND +10B7C ; [*1BCE.0020.0002] # INSCRIPTIONAL PAHLAVI NUMBER TEN +10B7D ; [*1BCF.0020.0002] # INSCRIPTIONAL PAHLAVI NUMBER TWENTY +10B7E ; [*1BD0.0020.0002] # INSCRIPTIONAL PAHLAVI NUMBER ONE HUNDRED +10B7F ; [*1BD1.0020.0002] # INSCRIPTIONAL PAHLAVI NUMBER ONE THOUSAND +10B99 ; [*0460.0020.0002] # PSALTER PAHLAVI SECTION MARK +10B9A ; [*0461.0020.0002] # PSALTER PAHLAVI TURNED SECTION MARK +10B9B ; [*0462.0020.0002] # PSALTER PAHLAVI FOUR DOTS WITH CROSS +10B9C ; [*0463.0020.0002] # PSALTER PAHLAVI FOUR DOTS WITH DOT +10BAD ; [*1BD2.0020.0002] # PSALTER PAHLAVI NUMBER TEN +10BAE ; [*1BD3.0020.0002] # PSALTER PAHLAVI NUMBER TWENTY +10BAF ; [*1BD4.0020.0002] # PSALTER PAHLAVI NUMBER ONE HUNDRED +10CFC ; [*1B49.0020.0002] # OLD HUNGARIAN NUMBER TEN +10CFD ; [*1B4A.0020.0002] # OLD HUNGARIAN NUMBER FIFTY +10CFE ; [*1B4B.0020.0002] # OLD HUNGARIAN NUMBER ONE HUNDRED +10CFF ; [*1B4C.0020.0002] # OLD HUNGARIAN NUMBER ONE THOUSAND +10E69 ; [*1B30.0020.0002] # RUMI NUMBER TEN +10E6A ; [*1B31.0020.0002] # RUMI NUMBER TWENTY +10E6B ; [*1B32.0020.0002] # RUMI NUMBER THIRTY +10E6C ; [*1B33.0020.0002] # RUMI NUMBER FORTY +10E6D ; [*1B34.0020.0002] # RUMI NUMBER FIFTY +10E6E ; [*1B35.0020.0002] # RUMI NUMBER SIXTY +10E6F ; [*1B36.0020.0002] # RUMI NUMBER SEVENTY +10E70 ; [*1B37.0020.0002] # RUMI NUMBER EIGHTY +10E71 ; [*1B38.0020.0002] # RUMI NUMBER NINETY +10E72 ; [*1B39.0020.0002] # RUMI NUMBER ONE HUNDRED +10E73 ; [*1B3A.0020.0002] # RUMI NUMBER TWO HUNDRED +10E74 ; [*1B3B.0020.0002] # RUMI NUMBER THREE HUNDRED +10E75 ; [*1B3C.0020.0002] # RUMI NUMBER FOUR HUNDRED +10E76 ; [*1B3D.0020.0002] # RUMI NUMBER FIVE HUNDRED +10E77 ; [*1B3E.0020.0002] # RUMI NUMBER SIX HUNDRED +10E78 ; [*1B3F.0020.0002] # RUMI NUMBER SEVEN HUNDRED +10E79 ; [*1B40.0020.0002] # RUMI NUMBER EIGHT HUNDRED +10E7A ; [*1B41.0020.0002] # RUMI NUMBER NINE HUNDRED +10E7B ; [*1B42.0020.0002] # RUMI FRACTION ONE HALF +10E7C ; [*1B43.0020.0002] # RUMI FRACTION ONE QUARTER +10E7D ; [*1B44.0020.0002] # RUMI FRACTION ONE THIRD +10E7E ; [*1B45.0020.0002] # RUMI FRACTION TWO THIRDS +11047 ; [*02AD.0020.0002] # BRAHMI DANDA +11048 ; [*02AE.0020.0002] # BRAHMI DOUBLE DANDA +11049 ; [*0449.0020.0002] # BRAHMI PUNCTUATION DOT +1104A ; [*044A.0020.0002] # BRAHMI PUNCTUATION DOUBLE DOT +1104B ; [*044B.0020.0002] # BRAHMI PUNCTUATION LINE +1104C ; [*044C.0020.0002] # BRAHMI PUNCTUATION CRESCENT BAR +1104D ; [*044D.0020.0002] # BRAHMI PUNCTUATION LOTUS +1105B ; [*1BD7.0020.0002] # BRAHMI NUMBER TEN +1105C ; [*1BD8.0020.0002] # BRAHMI NUMBER TWENTY +1105D ; [*1BD9.0020.0002] # BRAHMI NUMBER THIRTY +1105E ; [*1BDA.0020.0002] # BRAHMI NUMBER FORTY +1105F ; [*1BDB.0020.0002] # BRAHMI NUMBER FIFTY +11060 ; [*1BDC.0020.0002] # BRAHMI NUMBER SIXTY +11061 ; [*1BDD.0020.0002] # BRAHMI NUMBER SEVENTY +11062 ; [*1BDE.0020.0002] # BRAHMI NUMBER EIGHTY +11063 ; [*1BDF.0020.0002] # BRAHMI NUMBER NINETY +11064 ; [*1BE0.0020.0002] # BRAHMI NUMBER ONE HUNDRED +11065 ; [*1BE1.0020.0002] # BRAHMI NUMBER ONE THOUSAND +110BB ; [*0464.0020.0002] # KAITHI ABBREVIATION SIGN +110BC ; [*0465.0020.0002] # KAITHI ENUMERATION SIGN +110BD ; [.0000.0000.0000] # KAITHI NUMBER SIGN +110BE ; [*02E1.0020.0002] # KAITHI SECTION MARK +110BF ; [*02E2.0020.0002] # KAITHI DOUBLE SECTION MARK +110C0 ; [*02AF.0020.0002] # KAITHI DANDA +110C1 ; [*02B0.0020.0002] # KAITHI DOUBLE DANDA +11140 ; [*02E3.0020.0002] # CHAKMA SECTION MARK +11141 ; [*02B1.0020.0002] # CHAKMA DANDA +11142 ; [*02B2.0020.0002] # CHAKMA DOUBLE DANDA +11143 ; [*0274.0020.0002] # CHAKMA QUESTION MARK +11174 ; [*0466.0020.0002] # MAHAJANI ABBREVIATION SIGN +11175 ; [*0467.0020.0002] # MAHAJANI SECTION MARK +111C5 ; [*02B3.0020.0002] # SHARADA DANDA +111C6 ; [*02B4.0020.0002] # SHARADA DOUBLE DANDA +111C7 ; [*0469.0020.0002] # SHARADA ABBREVIATION SIGN +111C8 ; [*02E4.0020.0002] # SHARADA SEPARATOR +111C9 ; [*046A.0020.0002] # SHARADA SANDHI MARK +111CD ; [*0468.0020.0002] # SHARADA SUTRA MARK +111DB ; [*046B.0020.0002] # SHARADA SIGN SIDDHAM +111DD ; [*046C.0020.0002] # SHARADA CONTINUATION SIGN +111DE ; [*02E5.0020.0002] # SHARADA SECTION MARK-1 +111DF ; [*02E6.0020.0002] # SHARADA SECTION MARK-2 +111EA ; [*1BF0.0020.0002] # SINHALA ARCHAIC NUMBER TEN +111EB ; [*1BF1.0020.0002] # SINHALA ARCHAIC NUMBER TWENTY +111EC ; [*1BF2.0020.0002] # SINHALA ARCHAIC NUMBER THIRTY +111ED ; [*1BF3.0020.0002] # SINHALA ARCHAIC NUMBER FORTY +111EE ; [*1BF4.0020.0002] # SINHALA ARCHAIC NUMBER FIFTY +111EF ; [*1BF5.0020.0002] # SINHALA ARCHAIC NUMBER SIXTY +111F0 ; [*1BF6.0020.0002] # SINHALA ARCHAIC NUMBER SEVENTY +111F1 ; [*1BF7.0020.0002] # SINHALA ARCHAIC NUMBER EIGHTY +111F2 ; [*1BF8.0020.0002] # SINHALA ARCHAIC NUMBER NINETY +111F3 ; [*1BF9.0020.0002] # SINHALA ARCHAIC NUMBER ONE HUNDRED +111F4 ; [*1BFA.0020.0002] # SINHALA ARCHAIC NUMBER ONE THOUSAND +11238 ; [*02B5.0020.0002] # KHOJKI DANDA +11239 ; [*02B6.0020.0002] # KHOJKI DOUBLE DANDA +1123A ; [*046D.0020.0002] # KHOJKI WORD SEPARATOR +1123B ; [*046E.0020.0002] # KHOJKI SECTION MARK +1123C ; [*046F.0020.0002] # KHOJKI DOUBLE SECTION MARK +1123D ; [*0470.0020.0002] # KHOJKI ABBREVIATION SIGN +112A9 ; [*02E7.0020.0002] # MULTANI SECTION MARK +11366 ; [.0000.0000.0000] # COMBINING GRANTHA DIGIT ZERO +11367 ; [.0000.0000.0000] # COMBINING GRANTHA DIGIT ONE +11368 ; [.0000.0000.0000] # COMBINING GRANTHA DIGIT TWO +11369 ; [.0000.0000.0000] # COMBINING GRANTHA DIGIT THREE +1136A ; [.0000.0000.0000] # COMBINING GRANTHA DIGIT FOUR +1136B ; [.0000.0000.0000] # COMBINING GRANTHA DIGIT FIVE +1136C ; [.0000.0000.0000] # COMBINING GRANTHA DIGIT SIX +11370 ; [.0000.0000.0000] # COMBINING GRANTHA LETTER A +11371 ; [.0000.0000.0000] # COMBINING GRANTHA LETTER KA +11372 ; [.0000.0000.0000] # COMBINING GRANTHA LETTER NA +11373 ; [.0000.0000.0000] # COMBINING GRANTHA LETTER VI +11374 ; [.0000.0000.0000] # COMBINING GRANTHA LETTER PA +1144B ; [*02B7.0020.0002] # NEWA DANDA +1144C ; [*02B8.0020.0002] # NEWA DOUBLE DANDA +1144D ; [*0471.0020.0002] # NEWA COMMA +1144E ; [*0472.0020.0002] # NEWA GAP FILLER +1144F ; [*0473.0020.0002] # NEWA ABBREVIATION SIGN +1145B ; [*0474.0020.0002] # NEWA PLACEHOLDER MARK +1145D ; [*0475.0020.0002] # NEWA INSERTION SIGN +114C6 ; [*0476.0020.0002] # TIRHUTA ABBREVIATION SIGN +115C1 ; [*0477.0020.0002] # SIDDHAM SIGN SIDDHAM +115C2 ; [*02B9.0020.0002] # SIDDHAM DANDA +115C3 ; [*02BA.0020.0002] # SIDDHAM DOUBLE DANDA +115C4 ; [*0478.0020.0002] # SIDDHAM SEPARATOR DOT +115C5 ; [*0479.0020.0002] # SIDDHAM SEPARATOR BAR +115C6 ; [*047A.0020.0002] # SIDDHAM REPETITION MARK-1 +115C7 ; [*047B.0020.0002] # SIDDHAM REPETITION MARK-2 +115C8 ; [*047C.0020.0002] # SIDDHAM REPETITION MARK-3 +115C9 ; [*047D.0020.0002] # SIDDHAM END OF TEXT MARK +115CA ; [*047E.0020.0002] # SIDDHAM SECTION MARK WITH TRIDENT AND U-SHAPED ORNAMENTS +115CB ; [*047F.0020.0002] # SIDDHAM SECTION MARK WITH TRIDENT AND DOTTED CRESCENTS +115CC ; [*0480.0020.0002] # SIDDHAM SECTION MARK WITH RAYS AND DOTTED CRESCENTS +115CD ; [*0481.0020.0002] # SIDDHAM SECTION MARK WITH RAYS AND DOTTED DOUBLE CRESCENTS +115CE ; [*0482.0020.0002] # SIDDHAM SECTION MARK WITH RAYS AND DOTTED TRIPLE CRESCENTS +115CF ; [*0483.0020.0002] # SIDDHAM SECTION MARK DOUBLE RING +115D0 ; [*0484.0020.0002] # SIDDHAM SECTION MARK DOUBLE RING WITH RAYS +115D1 ; [*0485.0020.0002] # SIDDHAM SECTION MARK WITH DOUBLE CRESCENTS +115D2 ; [*0486.0020.0002] # SIDDHAM SECTION MARK WITH TRIPLE CRESCENTS +115D3 ; [*0487.0020.0002] # SIDDHAM SECTION MARK WITH QUADRUPLE CRESCENTS +115D4 ; [*0488.0020.0002] # SIDDHAM SECTION MARK WITH SEPTUPLE CRESCENTS +115D5 ; [*0489.0020.0002] # SIDDHAM SECTION MARK WITH CIRCLES AND RAYS +115D6 ; [*048A.0020.0002] # SIDDHAM SECTION MARK WITH CIRCLES AND TWO ENCLOSURES +115D7 ; [*048B.0020.0002] # SIDDHAM SECTION MARK WITH CIRCLES AND FOUR ENCLOSURES +11641 ; [*02BB.0020.0002] # MODI DANDA +11642 ; [*02BC.0020.0002] # MODI DOUBLE DANDA +11643 ; [*048C.0020.0002] # MODI ABBREVIATION SIGN +11660 ; [*03DF.0020.0002] # MONGOLIAN BIRGA WITH ORNAMENT +11661 ; [*03E0.0020.0002] # MONGOLIAN ROTATED BIRGA +11662 ; [*03E1.0020.0002] # MONGOLIAN DOUBLE BIRGA WITH ORNAMENT +11663 ; [*03E2.0020.0002] # MONGOLIAN TRIPLE BIRGA WITH ORNAMENT +11664 ; [*03E3.0020.0002] # MONGOLIAN BIRGA WITH DOUBLE ORNAMENT +11665 ; [*03E4.0020.0002] # MONGOLIAN ROTATED BIRGA WITH ORNAMENT +11666 ; [*03E5.0020.0002] # MONGOLIAN ROTATED BIRGA WITH DOUBLE ORNAMENT +11667 ; [*03E6.0020.0002] # MONGOLIAN INVERTED BIRGA +11668 ; [*03E7.0020.0002] # MONGOLIAN INVERTED BIRGA WITH DOUBLE ORNAMENT +11669 ; [*03E8.0020.0002] # MONGOLIAN SWIRL BIRGA +1166A ; [*03E9.0020.0002] # MONGOLIAN SWIRL BIRGA WITH ORNAMENT +1166B ; [*03EA.0020.0002] # MONGOLIAN SWIRL BIRGA WITH DOUBLE ORNAMENT +1166C ; [*03EB.0020.0002] # MONGOLIAN TURNED SWIRL BIRGA WITH DOUBLE ORNAMENT +1173A ; [*1BD5.0020.0002] # AHOM NUMBER TEN +1173B ; [*1BD6.0020.0002] # AHOM NUMBER TWENTY +1173C ; [*02BD.0020.0002] # AHOM SIGN SMALL SECTION +1173D ; [*02BE.0020.0002] # AHOM SIGN SECTION +1173E ; [*02E8.0020.0002] # AHOM SIGN RULAI +1173F ; [*0566.0020.0002] # AHOM SYMBOL VI +118EA ; [*1BFB.0020.0002] # WARANG CITI NUMBER TEN +118EB ; [*1BFC.0020.0002] # WARANG CITI NUMBER TWENTY +118EC ; [*1BFD.0020.0002] # WARANG CITI NUMBER THIRTY +118ED ; [*1BFE.0020.0002] # WARANG CITI NUMBER FORTY +118EE ; [*1BFF.0020.0002] # WARANG CITI NUMBER FIFTY +118EF ; [*1C00.0020.0002] # WARANG CITI NUMBER SIXTY +118F0 ; [*1C01.0020.0002] # WARANG CITI NUMBER SEVENTY +118F1 ; [*1C02.0020.0002] # WARANG CITI NUMBER EIGHTY +118F2 ; [*1C03.0020.0002] # WARANG CITI NUMBER NINETY +11A3F ; [*040F.0020.0002] # ZANABAZAR SQUARE INITIAL HEAD MARK +11A40 ; [*0410.0020.0002] # ZANABAZAR SQUARE CLOSING HEAD MARK +11A41 ; [*0411.0020.0002] # ZANABAZAR SQUARE MARK TSHEG +11A42 ; [*0412.0020.0002] # ZANABAZAR SQUARE MARK SHAD +11A43 ; [*0413.0020.0002] # ZANABAZAR SQUARE MARK DOUBLE SHAD +11A44 ; [*0414.0020.0002] # ZANABAZAR SQUARE MARK LONG TSHEG +11A45 ; [*0415.0020.0002] # ZANABAZAR SQUARE INITIAL DOUBLE-LINED HEAD MARK +11A46 ; [*0416.0020.0002] # ZANABAZAR SQUARE CLOSING DOUBLE-LINED HEAD MARK +11A9A ; [*0417.0020.0002] # SOYOMBO MARK TSHEG +11A9B ; [*0418.0020.0002] # SOYOMBO MARK SHAD +11A9C ; [*0419.0020.0002] # SOYOMBO MARK DOUBLE SHAD +11A9E ; [*041A.0020.0002] # SOYOMBO HEAD MARK WITH MOON AND SUN AND TRIPLE FLAME +11A9F ; [*041B.0020.0002] # SOYOMBO HEAD MARK WITH MOON AND SUN AND FLAME +11AA0 ; [*041C.0020.0002] # SOYOMBO HEAD MARK WITH MOON AND SUN +11AA1 ; [*041D.0020.0002] # SOYOMBO TERMINAL MARK-1 +11AA2 ; [*041E.0020.0002] # SOYOMBO TERMINAL MARK-2 +11C41 ; [*02BF.0020.0002] # BHAIKSUKI DANDA +11C42 ; [*02C0.0020.0002] # BHAIKSUKI DOUBLE DANDA +11C43 ; [*0455.0020.0002] # BHAIKSUKI WORD SEPARATOR +11C44 ; [*0456.0020.0002] # BHAIKSUKI GAP FILLER-1 +11C45 ; [*0457.0020.0002] # BHAIKSUKI GAP FILLER-2 +11C63 ; [*1BE6.0020.0002] # BHAIKSUKI NUMBER TEN +11C64 ; [*1BE7.0020.0002] # BHAIKSUKI NUMBER TWENTY +11C65 ; [*1BE8.0020.0002] # BHAIKSUKI NUMBER THIRTY +11C66 ; [*1BE9.0020.0002] # BHAIKSUKI NUMBER FORTY +11C67 ; [*1BEA.0020.0002] # BHAIKSUKI NUMBER FIFTY +11C68 ; [*1BEB.0020.0002] # BHAIKSUKI NUMBER SIXTY +11C69 ; [*1BEC.0020.0002] # BHAIKSUKI NUMBER SEVENTY +11C6A ; [*1BED.0020.0002] # BHAIKSUKI NUMBER EIGHTY +11C6B ; [*1BEE.0020.0002] # BHAIKSUKI NUMBER NINETY +11C6C ; [*1BEF.0020.0002] # BHAIKSUKI HUNDREDS UNIT MARK +11C70 ; [*041F.0020.0002] # MARCHEN HEAD MARK +11C71 ; [*0420.0020.0002] # MARCHEN MARK SHAD +12432 ; [*1C42.0020.0002] # CUNEIFORM NUMERIC SIGN SHAR2 TIMES GAL PLUS DISH +12433 ; [*1C43.0020.0002] # CUNEIFORM NUMERIC SIGN SHAR2 TIMES GAL PLUS MIN +1245A ; [*1C44.0020.0002] # CUNEIFORM NUMERIC SIGN ONE THIRD DISH +1245B ; [*1C45.0020.0002] # CUNEIFORM NUMERIC SIGN TWO THIRDS DISH +1245C ; [*1C46.0020.0002] # CUNEIFORM NUMERIC SIGN FIVE SIXTHS DISH +1245D ; [*1C47.0020.0002] # CUNEIFORM NUMERIC SIGN ONE THIRD VARIANT FORM A +1245E ; [*1C48.0020.0002] # CUNEIFORM NUMERIC SIGN TWO THIRDS VARIANT FORM A +1245F ; [*1C49.0020.0002] # CUNEIFORM NUMERIC SIGN ONE EIGHTH ASH +12460 ; [*1C4A.0020.0002] # CUNEIFORM NUMERIC SIGN ONE QUARTER ASH +12461 ; [*1C4B.0020.0002] # CUNEIFORM NUMERIC SIGN OLD ASSYRIAN ONE SIXTH +12462 ; [*1C4C.0020.0002] # CUNEIFORM NUMERIC SIGN OLD ASSYRIAN ONE QUARTER +12463 ; [*1C4D.0020.0002] # CUNEIFORM NUMERIC SIGN ONE QUARTER GUR +12464 ; [*1C4E.0020.0002] # CUNEIFORM NUMERIC SIGN ONE HALF GUR +12465 ; [*1C4F.0020.0002] # CUNEIFORM NUMERIC SIGN ELAMITE ONE THIRD +12466 ; [*1C50.0020.0002] # CUNEIFORM NUMERIC SIGN ELAMITE TWO THIRDS +12467 ; [*1C51.0020.0002] # CUNEIFORM NUMERIC SIGN ELAMITE FORTY +12468 ; [*1C52.0020.0002] # CUNEIFORM NUMERIC SIGN ELAMITE FIFTY +12470 ; [*0301.0020.0002] # CUNEIFORM PUNCTUATION SIGN OLD ASSYRIAN WORD DIVIDER +12471 ; [*0302.0020.0002] # CUNEIFORM PUNCTUATION SIGN VERTICAL COLON +12472 ; [*0303.0020.0002] # CUNEIFORM PUNCTUATION SIGN DIAGONAL COLON +12473 ; [*0304.0020.0002] # CUNEIFORM PUNCTUATION SIGN DIAGONAL TRICOLON +12474 ; [*0305.0020.0002] # CUNEIFORM PUNCTUATION SIGN DIAGONAL QUADCOLON +16A6E ; [*02C1.0020.0002] # MRO DANDA +16A6F ; [*02C2.0020.0002] # MRO DOUBLE DANDA +16AF5 ; [*0289.0020.0002] # BASSA VAH FULL STOP +16B37 ; [*048D.0020.0002] # PAHAWH HMONG SIGN VOS THOM +16B38 ; [*048E.0020.0002] # PAHAWH HMONG SIGN VOS TSHAB CEEB +16B39 ; [*048F.0020.0002] # PAHAWH HMONG SIGN CIM CHEEM +16B3A ; [*0490.0020.0002] # PAHAWH HMONG SIGN VOS THIAB +16B3B ; [*0491.0020.0002] # PAHAWH HMONG SIGN VOS FEEM +16B3C ; [*0FE9.0020.0002] # PAHAWH HMONG SIGN XYEEM NTXIV +16B3D ; [*0FEA.0020.0002] # PAHAWH HMONG SIGN XYEEM RHO +16B3E ; [*0FEB.0020.0002] # PAHAWH HMONG SIGN XYEEM TOV +16B3F ; [*0FEC.0020.0002] # PAHAWH HMONG SIGN XYEEM FAIB +16B44 ; [*0492.0020.0002] # PAHAWH HMONG SIGN XAUS +16B45 ; [*0FED.0020.0002] # PAHAWH HMONG SIGN CIM TSOV ROG +16B5B ; [*1C04.0020.0002] # PAHAWH HMONG NUMBER TENS +16B5C ; [*1C05.0020.0002] # PAHAWH HMONG NUMBER HUNDREDS +16B5D ; [*1C06.0020.0002] # PAHAWH HMONG NUMBER TEN THOUSANDS +16B5E ; [*1C07.0020.0002] # PAHAWH HMONG NUMBER MILLIONS +16B5F ; [*1C08.0020.0002] # PAHAWH HMONG NUMBER HUNDRED MILLIONS +16B60 ; [*1C09.0020.0002] # PAHAWH HMONG NUMBER TEN BILLIONS +16B61 ; [*1C0A.0020.0002] # PAHAWH HMONG NUMBER TRILLIONS +1BC9C ; [*11DE.0020.0002] # DUPLOYAN SIGN O WITH CROSS +1BC9F ; [*028A.0020.0002] # DUPLOYAN PUNCTUATION CHINOOK FULL STOP +1D000 ; [*0FEE.0020.0002] # BYZANTINE MUSICAL SYMBOL PSILI +1D001 ; [*0FEF.0020.0002] # BYZANTINE MUSICAL SYMBOL DASEIA +1D002 ; [*0FF0.0020.0002] # BYZANTINE MUSICAL SYMBOL PERISPOMENI +1D003 ; [*0FF1.0020.0002] # BYZANTINE MUSICAL SYMBOL OXEIA EKFONITIKON +1D004 ; [*0FF2.0020.0002] # BYZANTINE MUSICAL SYMBOL OXEIA DIPLI +1D005 ; [*0FF3.0020.0002] # BYZANTINE MUSICAL SYMBOL VAREIA EKFONITIKON +1D006 ; [*0FF4.0020.0002] # BYZANTINE MUSICAL SYMBOL VAREIA DIPLI +1D007 ; [*0FF5.0020.0002] # BYZANTINE MUSICAL SYMBOL KATHISTI +1D008 ; [*0FF6.0020.0002] # BYZANTINE MUSICAL SYMBOL SYRMATIKI +1D009 ; [*0FF7.0020.0002] # BYZANTINE MUSICAL SYMBOL PARAKLITIKI +1D00A ; [*0FF8.0020.0002] # BYZANTINE MUSICAL SYMBOL YPOKRISIS +1D00B ; [*0FF9.0020.0002] # BYZANTINE MUSICAL SYMBOL YPOKRISIS DIPLI +1D00C ; [*0FFA.0020.0002] # BYZANTINE MUSICAL SYMBOL KREMASTI +1D00D ; [*0FFB.0020.0002] # BYZANTINE MUSICAL SYMBOL APESO EKFONITIKON +1D00E ; [*0FFC.0020.0002] # BYZANTINE MUSICAL SYMBOL EXO EKFONITIKON +1D00F ; [*0FFD.0020.0002] # BYZANTINE MUSICAL SYMBOL TELEIA +1D010 ; [*0FFE.0020.0002] # BYZANTINE MUSICAL SYMBOL KENTIMATA +1D011 ; [*0FFF.0020.0002] # BYZANTINE MUSICAL SYMBOL APOSTROFOS +1D012 ; [*1000.0020.0002] # BYZANTINE MUSICAL SYMBOL APOSTROFOS DIPLI +1D013 ; [*1001.0020.0002] # BYZANTINE MUSICAL SYMBOL SYNEVMA +1D014 ; [*1002.0020.0002] # BYZANTINE MUSICAL SYMBOL THITA +1D015 ; [*1003.0020.0002] # BYZANTINE MUSICAL SYMBOL OLIGON ARCHAION +1D016 ; [*1004.0020.0002] # BYZANTINE MUSICAL SYMBOL GORGON ARCHAION +1D017 ; [*1005.0020.0002] # BYZANTINE MUSICAL SYMBOL PSILON +1D018 ; [*1006.0020.0002] # BYZANTINE MUSICAL SYMBOL CHAMILON +1D019 ; [*1007.0020.0002] # BYZANTINE MUSICAL SYMBOL VATHY +1D01A ; [*1008.0020.0002] # BYZANTINE MUSICAL SYMBOL ISON ARCHAION +1D01B ; [*1009.0020.0002] # BYZANTINE MUSICAL SYMBOL KENTIMA ARCHAION +1D01C ; [*100A.0020.0002] # BYZANTINE MUSICAL SYMBOL KENTIMATA ARCHAION +1D01D ; [*100B.0020.0002] # BYZANTINE MUSICAL SYMBOL SAXIMATA +1D01E ; [*100C.0020.0002] # BYZANTINE MUSICAL SYMBOL PARICHON +1D01F ; [*100D.0020.0002] # BYZANTINE MUSICAL SYMBOL STAVROS APODEXIA +1D020 ; [*100E.0020.0002] # BYZANTINE MUSICAL SYMBOL OXEIAI ARCHAION +1D021 ; [*100F.0020.0002] # BYZANTINE MUSICAL SYMBOL VAREIAI ARCHAION +1D022 ; [*1010.0020.0002] # BYZANTINE MUSICAL SYMBOL APODERMA ARCHAION +1D023 ; [*1011.0020.0002] # BYZANTINE MUSICAL SYMBOL APOTHEMA +1D024 ; [*1012.0020.0002] # BYZANTINE MUSICAL SYMBOL KLASMA +1D025 ; [*1013.0020.0002] # BYZANTINE MUSICAL SYMBOL REVMA +1D026 ; [*1014.0020.0002] # BYZANTINE MUSICAL SYMBOL PIASMA ARCHAION +1D027 ; [*1015.0020.0002] # BYZANTINE MUSICAL SYMBOL TINAGMA +1D028 ; [*1016.0020.0002] # BYZANTINE MUSICAL SYMBOL ANATRICHISMA +1D029 ; [*1017.0020.0002] # BYZANTINE MUSICAL SYMBOL SEISMA +1D02A ; [*1018.0020.0002] # BYZANTINE MUSICAL SYMBOL SYNAGMA ARCHAION +1D02B ; [*1019.0020.0002] # BYZANTINE MUSICAL SYMBOL SYNAGMA META STAVROU +1D02C ; [*101A.0020.0002] # BYZANTINE MUSICAL SYMBOL OYRANISMA ARCHAION +1D02D ; [*101B.0020.0002] # BYZANTINE MUSICAL SYMBOL THEMA +1D02E ; [*101C.0020.0002] # BYZANTINE MUSICAL SYMBOL LEMOI +1D02F ; [*101D.0020.0002] # BYZANTINE MUSICAL SYMBOL DYO +1D030 ; [*101E.0020.0002] # BYZANTINE MUSICAL SYMBOL TRIA +1D031 ; [*101F.0020.0002] # BYZANTINE MUSICAL SYMBOL TESSERA +1D032 ; [*1020.0020.0002] # BYZANTINE MUSICAL SYMBOL KRATIMATA +1D033 ; [*1021.0020.0002] # BYZANTINE MUSICAL SYMBOL APESO EXO NEO +1D034 ; [*1022.0020.0002] # BYZANTINE MUSICAL SYMBOL FTHORA ARCHAION +1D035 ; [*1023.0020.0002] # BYZANTINE MUSICAL SYMBOL IMIFTHORA +1D036 ; [*1024.0020.0002] # BYZANTINE MUSICAL SYMBOL TROMIKON ARCHAION +1D037 ; [*1025.0020.0002] # BYZANTINE MUSICAL SYMBOL KATAVA TROMIKON +1D038 ; [*1026.0020.0002] # BYZANTINE MUSICAL SYMBOL PELASTON +1D039 ; [*1027.0020.0002] # BYZANTINE MUSICAL SYMBOL PSIFISTON +1D03A ; [*1028.0020.0002] # BYZANTINE MUSICAL SYMBOL KONTEVMA +1D03B ; [*1029.0020.0002] # BYZANTINE MUSICAL SYMBOL CHOREVMA ARCHAION +1D03C ; [*102A.0020.0002] # BYZANTINE MUSICAL SYMBOL RAPISMA +1D03D ; [*102B.0020.0002] # BYZANTINE MUSICAL SYMBOL PARAKALESMA ARCHAION +1D03E ; [*102C.0020.0002] # BYZANTINE MUSICAL SYMBOL PARAKLITIKI ARCHAION +1D03F ; [*102D.0020.0002] # BYZANTINE MUSICAL SYMBOL ICHADIN +1D040 ; [*102E.0020.0002] # BYZANTINE MUSICAL SYMBOL NANA +1D041 ; [*102F.0020.0002] # BYZANTINE MUSICAL SYMBOL PETASMA +1D042 ; [*1030.0020.0002] # BYZANTINE MUSICAL SYMBOL KONTEVMA ALLO +1D043 ; [*1031.0020.0002] # BYZANTINE MUSICAL SYMBOL TROMIKON ALLO +1D044 ; [*1032.0020.0002] # BYZANTINE MUSICAL SYMBOL STRAGGISMATA +1D045 ; [*1033.0020.0002] # BYZANTINE MUSICAL SYMBOL GRONTHISMATA +1D046 ; [*1034.0020.0002] # BYZANTINE MUSICAL SYMBOL ISON NEO +1D047 ; [*1035.0020.0002] # BYZANTINE MUSICAL SYMBOL OLIGON NEO +1D048 ; [*1036.0020.0002] # BYZANTINE MUSICAL SYMBOL OXEIA NEO +1D049 ; [*1037.0020.0002] # BYZANTINE MUSICAL SYMBOL PETASTI +1D04A ; [*1038.0020.0002] # BYZANTINE MUSICAL SYMBOL KOUFISMA +1D04B ; [*1039.0020.0002] # BYZANTINE MUSICAL SYMBOL PETASTOKOUFISMA +1D04C ; [*103A.0020.0002] # BYZANTINE MUSICAL SYMBOL KRATIMOKOUFISMA +1D04D ; [*103B.0020.0002] # BYZANTINE MUSICAL SYMBOL PELASTON NEO +1D04E ; [*103C.0020.0002] # BYZANTINE MUSICAL SYMBOL KENTIMATA NEO ANO +1D04F ; [*103D.0020.0002] # BYZANTINE MUSICAL SYMBOL KENTIMA NEO ANO +1D050 ; [*103E.0020.0002] # BYZANTINE MUSICAL SYMBOL YPSILI +1D051 ; [*103F.0020.0002] # BYZANTINE MUSICAL SYMBOL APOSTROFOS NEO +1D052 ; [*1040.0020.0002] # BYZANTINE MUSICAL SYMBOL APOSTROFOI SYNDESMOS NEO +1D053 ; [*1041.0020.0002] # BYZANTINE MUSICAL SYMBOL YPORROI +1D054 ; [*1042.0020.0002] # BYZANTINE MUSICAL SYMBOL KRATIMOYPORROON +1D055 ; [*1043.0020.0002] # BYZANTINE MUSICAL SYMBOL ELAFRON +1D056 ; [*1044.0020.0002] # BYZANTINE MUSICAL SYMBOL CHAMILI +1D057 ; [*1045.0020.0002] # BYZANTINE MUSICAL SYMBOL MIKRON ISON +1D058 ; [*1046.0020.0002] # BYZANTINE MUSICAL SYMBOL VAREIA NEO +1D059 ; [*1047.0020.0002] # BYZANTINE MUSICAL SYMBOL PIASMA NEO +1D05A ; [*1048.0020.0002] # BYZANTINE MUSICAL SYMBOL PSIFISTON NEO +1D05B ; [*1049.0020.0002] # BYZANTINE MUSICAL SYMBOL OMALON +1D05C ; [*104A.0020.0002] # BYZANTINE MUSICAL SYMBOL ANTIKENOMA +1D05D ; [*104B.0020.0002] # BYZANTINE MUSICAL SYMBOL LYGISMA +1D05E ; [*104C.0020.0002] # BYZANTINE MUSICAL SYMBOL PARAKLITIKI NEO +1D05F ; [*104D.0020.0002] # BYZANTINE MUSICAL SYMBOL PARAKALESMA NEO +1D060 ; [*104E.0020.0002] # BYZANTINE MUSICAL SYMBOL ETERON PARAKALESMA +1D061 ; [*104F.0020.0002] # BYZANTINE MUSICAL SYMBOL KYLISMA +1D062 ; [*1050.0020.0002] # BYZANTINE MUSICAL SYMBOL ANTIKENOKYLISMA +1D063 ; [*1051.0020.0002] # BYZANTINE MUSICAL SYMBOL TROMIKON NEO +1D064 ; [*1052.0020.0002] # BYZANTINE MUSICAL SYMBOL EKSTREPTON +1D065 ; [*1053.0020.0002] # BYZANTINE MUSICAL SYMBOL SYNAGMA NEO +1D066 ; [*1054.0020.0002] # BYZANTINE MUSICAL SYMBOL SYRMA +1D067 ; [*1055.0020.0002] # BYZANTINE MUSICAL SYMBOL CHOREVMA NEO +1D068 ; [*1056.0020.0002] # BYZANTINE MUSICAL SYMBOL EPEGERMA +1D069 ; [*1057.0020.0002] # BYZANTINE MUSICAL SYMBOL SEISMA NEO +1D06A ; [*1058.0020.0002] # BYZANTINE MUSICAL SYMBOL XIRON KLASMA +1D06B ; [*1059.0020.0002] # BYZANTINE MUSICAL SYMBOL TROMIKOPSIFISTON +1D06C ; [*105A.0020.0002] # BYZANTINE MUSICAL SYMBOL PSIFISTOLYGISMA +1D06D ; [*105B.0020.0002] # BYZANTINE MUSICAL SYMBOL TROMIKOLYGISMA +1D06E ; [*105C.0020.0002] # BYZANTINE MUSICAL SYMBOL TROMIKOPARAKALESMA +1D06F ; [*105D.0020.0002] # BYZANTINE MUSICAL SYMBOL PSIFISTOPARAKALESMA +1D070 ; [*105E.0020.0002] # BYZANTINE MUSICAL SYMBOL TROMIKOSYNAGMA +1D071 ; [*105F.0020.0002] # BYZANTINE MUSICAL SYMBOL PSIFISTOSYNAGMA +1D072 ; [*1060.0020.0002] # BYZANTINE MUSICAL SYMBOL GORGOSYNTHETON +1D073 ; [*1061.0020.0002] # BYZANTINE MUSICAL SYMBOL ARGOSYNTHETON +1D074 ; [*1062.0020.0002] # BYZANTINE MUSICAL SYMBOL ETERON ARGOSYNTHETON +1D075 ; [*1063.0020.0002] # BYZANTINE MUSICAL SYMBOL OYRANISMA NEO +1D076 ; [*1064.0020.0002] # BYZANTINE MUSICAL SYMBOL THEMATISMOS ESO +1D077 ; [*1065.0020.0002] # BYZANTINE MUSICAL SYMBOL THEMATISMOS EXO +1D078 ; [*1066.0020.0002] # BYZANTINE MUSICAL SYMBOL THEMA APLOUN +1D079 ; [*1067.0020.0002] # BYZANTINE MUSICAL SYMBOL THES KAI APOTHES +1D07A ; [*1068.0020.0002] # BYZANTINE MUSICAL SYMBOL KATAVASMA +1D07B ; [*1069.0020.0002] # BYZANTINE MUSICAL SYMBOL ENDOFONON +1D07C ; [*106A.0020.0002] # BYZANTINE MUSICAL SYMBOL YFEN KATO +1D07D ; [*106B.0020.0002] # BYZANTINE MUSICAL SYMBOL YFEN ANO +1D07E ; [*106C.0020.0002] # BYZANTINE MUSICAL SYMBOL STAVROS +1D07F ; [*106D.0020.0002] # BYZANTINE MUSICAL SYMBOL KLASMA ANO +1D080 ; [*106E.0020.0002] # BYZANTINE MUSICAL SYMBOL DIPLI ARCHAION +1D081 ; [*106F.0020.0002] # BYZANTINE MUSICAL SYMBOL KRATIMA ARCHAION +1D082 ; [*1070.0020.0002] # BYZANTINE MUSICAL SYMBOL KRATIMA ALLO +1D083 ; [*1071.0020.0002] # BYZANTINE MUSICAL SYMBOL KRATIMA NEO +1D084 ; [*1072.0020.0002] # BYZANTINE MUSICAL SYMBOL APODERMA NEO +1D085 ; [*1073.0020.0002] # BYZANTINE MUSICAL SYMBOL APLI +1D086 ; [*1074.0020.0002] # BYZANTINE MUSICAL SYMBOL DIPLI +1D087 ; [*1075.0020.0002] # BYZANTINE MUSICAL SYMBOL TRIPLI +1D088 ; [*1076.0020.0002] # BYZANTINE MUSICAL SYMBOL TETRAPLI +1D089 ; [*1077.0020.0002] # BYZANTINE MUSICAL SYMBOL KORONIS +1D08A ; [*1078.0020.0002] # BYZANTINE MUSICAL SYMBOL LEIMMA ENOS CHRONOU +1D08B ; [*1079.0020.0002] # BYZANTINE MUSICAL SYMBOL LEIMMA DYO CHRONON +1D08C ; [*107A.0020.0002] # BYZANTINE MUSICAL SYMBOL LEIMMA TRION CHRONON +1D08D ; [*107B.0020.0002] # BYZANTINE MUSICAL SYMBOL LEIMMA TESSARON CHRONON +1D08E ; [*107C.0020.0002] # BYZANTINE MUSICAL SYMBOL LEIMMA IMISEOS CHRONOU +1D08F ; [*107D.0020.0002] # BYZANTINE MUSICAL SYMBOL GORGON NEO ANO +1D090 ; [*107E.0020.0002] # BYZANTINE MUSICAL SYMBOL GORGON PARESTIGMENON ARISTERA +1D091 ; [*107F.0020.0002] # BYZANTINE MUSICAL SYMBOL GORGON PARESTIGMENON DEXIA +1D092 ; [*1080.0020.0002] # BYZANTINE MUSICAL SYMBOL DIGORGON +1D093 ; [*1081.0020.0002] # BYZANTINE MUSICAL SYMBOL DIGORGON PARESTIGMENON ARISTERA KATO +1D094 ; [*1082.0020.0002] # BYZANTINE MUSICAL SYMBOL DIGORGON PARESTIGMENON ARISTERA ANO +1D095 ; [*1083.0020.0002] # BYZANTINE MUSICAL SYMBOL DIGORGON PARESTIGMENON DEXIA +1D096 ; [*1084.0020.0002] # BYZANTINE MUSICAL SYMBOL TRIGORGON +1D097 ; [*1085.0020.0002] # BYZANTINE MUSICAL SYMBOL ARGON +1D098 ; [*1086.0020.0002] # BYZANTINE MUSICAL SYMBOL IMIDIARGON +1D099 ; [*1087.0020.0002] # BYZANTINE MUSICAL SYMBOL DIARGON +1D09A ; [*1088.0020.0002] # BYZANTINE MUSICAL SYMBOL AGOGI POLI ARGI +1D09B ; [*1089.0020.0002] # BYZANTINE MUSICAL SYMBOL AGOGI ARGOTERI +1D09C ; [*108A.0020.0002] # BYZANTINE MUSICAL SYMBOL AGOGI ARGI +1D09D ; [*108B.0020.0002] # BYZANTINE MUSICAL SYMBOL AGOGI METRIA +1D09E ; [*108C.0020.0002] # BYZANTINE MUSICAL SYMBOL AGOGI MESI +1D09F ; [*108D.0020.0002] # BYZANTINE MUSICAL SYMBOL AGOGI GORGI +1D0A0 ; [*108E.0020.0002] # BYZANTINE MUSICAL SYMBOL AGOGI GORGOTERI +1D0A1 ; [*108F.0020.0002] # BYZANTINE MUSICAL SYMBOL AGOGI POLI GORGI +1D0A2 ; [*1090.0020.0002] # BYZANTINE MUSICAL SYMBOL MARTYRIA PROTOS ICHOS +1D0A3 ; [*1091.0020.0002] # BYZANTINE MUSICAL SYMBOL MARTYRIA ALLI PROTOS ICHOS +1D0A4 ; [*1092.0020.0002] # BYZANTINE MUSICAL SYMBOL MARTYRIA DEYTEROS ICHOS +1D0A5 ; [*1093.0020.0002] # BYZANTINE MUSICAL SYMBOL MARTYRIA ALLI DEYTEROS ICHOS +1D0A6 ; [*1094.0020.0002] # BYZANTINE MUSICAL SYMBOL MARTYRIA TRITOS ICHOS +1D0A7 ; [*1095.0020.0002] # BYZANTINE MUSICAL SYMBOL MARTYRIA TRIFONIAS +1D0A8 ; [*1096.0020.0002] # BYZANTINE MUSICAL SYMBOL MARTYRIA TETARTOS ICHOS +1D0A9 ; [*1097.0020.0002] # BYZANTINE MUSICAL SYMBOL MARTYRIA TETARTOS LEGETOS ICHOS +1D0AA ; [*1098.0020.0002] # BYZANTINE MUSICAL SYMBOL MARTYRIA LEGETOS ICHOS +1D0AB ; [*1099.0020.0002] # BYZANTINE MUSICAL SYMBOL MARTYRIA PLAGIOS ICHOS +1D0AC ; [*109A.0020.0002] # BYZANTINE MUSICAL SYMBOL ISAKIA TELOUS ICHIMATOS +1D0AD ; [*109B.0020.0002] # BYZANTINE MUSICAL SYMBOL APOSTROFOI TELOUS ICHIMATOS +1D0AE ; [*109C.0020.0002] # BYZANTINE MUSICAL SYMBOL FANEROSIS TETRAFONIAS +1D0AF ; [*109D.0020.0002] # BYZANTINE MUSICAL SYMBOL FANEROSIS MONOFONIAS +1D0B0 ; [*109E.0020.0002] # BYZANTINE MUSICAL SYMBOL FANEROSIS DIFONIAS +1D0B1 ; [*109F.0020.0002] # BYZANTINE MUSICAL SYMBOL MARTYRIA VARYS ICHOS +1D0B2 ; [*10A0.0020.0002] # BYZANTINE MUSICAL SYMBOL MARTYRIA PROTOVARYS ICHOS +1D0B3 ; [*10A1.0020.0002] # BYZANTINE MUSICAL SYMBOL MARTYRIA PLAGIOS TETARTOS ICHOS +1D0B4 ; [*10A2.0020.0002] # BYZANTINE MUSICAL SYMBOL GORTHMIKON N APLOUN +1D0B5 ; [*10A3.0020.0002] # BYZANTINE MUSICAL SYMBOL GORTHMIKON N DIPLOUN +1D0B6 ; [*10A4.0020.0002] # BYZANTINE MUSICAL SYMBOL ENARXIS KAI FTHORA VOU +1D0B7 ; [*10A5.0020.0002] # BYZANTINE MUSICAL SYMBOL IMIFONON +1D0B8 ; [*10A6.0020.0002] # BYZANTINE MUSICAL SYMBOL IMIFTHORON +1D0B9 ; [*10A7.0020.0002] # BYZANTINE MUSICAL SYMBOL FTHORA ARCHAION DEYTEROU ICHOU +1D0BA ; [*10A8.0020.0002] # BYZANTINE MUSICAL SYMBOL FTHORA DIATONIKI PA +1D0BB ; [*10A9.0020.0002] # BYZANTINE MUSICAL SYMBOL FTHORA DIATONIKI NANA +1D0BC ; [*10AA.0020.0002] # BYZANTINE MUSICAL SYMBOL FTHORA NAOS ICHOS +1D0BD ; [*10AB.0020.0002] # BYZANTINE MUSICAL SYMBOL FTHORA DIATONIKI DI +1D0BE ; [*10AC.0020.0002] # BYZANTINE MUSICAL SYMBOL FTHORA SKLIRON DIATONON DI +1D0BF ; [*10AD.0020.0002] # BYZANTINE MUSICAL SYMBOL FTHORA DIATONIKI KE +1D0C0 ; [*10AE.0020.0002] # BYZANTINE MUSICAL SYMBOL FTHORA DIATONIKI ZO +1D0C1 ; [*10AF.0020.0002] # BYZANTINE MUSICAL SYMBOL FTHORA DIATONIKI NI KATO +1D0C2 ; [*10B0.0020.0002] # BYZANTINE MUSICAL SYMBOL FTHORA DIATONIKI NI ANO +1D0C3 ; [*10B1.0020.0002] # BYZANTINE MUSICAL SYMBOL FTHORA MALAKON CHROMA DIFONIAS +1D0C4 ; [*10B2.0020.0002] # BYZANTINE MUSICAL SYMBOL FTHORA MALAKON CHROMA MONOFONIAS +1D0C5 ; [*10B3.0020.0002] # BYZANTINE MUSICAL SYMBOL FHTORA SKLIRON CHROMA VASIS +1D0C6 ; [*10B4.0020.0002] # BYZANTINE MUSICAL SYMBOL FTHORA SKLIRON CHROMA SYNAFI +1D0C7 ; [*10B5.0020.0002] # BYZANTINE MUSICAL SYMBOL FTHORA NENANO +1D0C8 ; [*10B6.0020.0002] # BYZANTINE MUSICAL SYMBOL CHROA ZYGOS +1D0C9 ; [*10B7.0020.0002] # BYZANTINE MUSICAL SYMBOL CHROA KLITON +1D0CA ; [*10B8.0020.0002] # BYZANTINE MUSICAL SYMBOL CHROA SPATHI +1D0CB ; [*10B9.0020.0002] # BYZANTINE MUSICAL SYMBOL FTHORA I YFESIS TETARTIMORION +1D0CC ; [*10BA.0020.0002] # BYZANTINE MUSICAL SYMBOL FTHORA ENARMONIOS ANTIFONIA +1D0CD ; [*10BB.0020.0002] # BYZANTINE MUSICAL SYMBOL YFESIS TRITIMORION +1D0CE ; [*10BC.0020.0002] # BYZANTINE MUSICAL SYMBOL DIESIS TRITIMORION +1D0CF ; [*10BD.0020.0002] # BYZANTINE MUSICAL SYMBOL DIESIS TETARTIMORION +1D0D0 ; [*10BE.0020.0002] # BYZANTINE MUSICAL SYMBOL DIESIS APLI DYO DODEKATA +1D0D1 ; [*10BF.0020.0002] # BYZANTINE MUSICAL SYMBOL DIESIS MONOGRAMMOS TESSERA DODEKATA +1D0D2 ; [*10C0.0020.0002] # BYZANTINE MUSICAL SYMBOL DIESIS DIGRAMMOS EX DODEKATA +1D0D3 ; [*10C1.0020.0002] # BYZANTINE MUSICAL SYMBOL DIESIS TRIGRAMMOS OKTO DODEKATA +1D0D4 ; [*10C2.0020.0002] # BYZANTINE MUSICAL SYMBOL YFESIS APLI DYO DODEKATA +1D0D5 ; [*10C3.0020.0002] # BYZANTINE MUSICAL SYMBOL YFESIS MONOGRAMMOS TESSERA DODEKATA +1D0D6 ; [*10C4.0020.0002] # BYZANTINE MUSICAL SYMBOL YFESIS DIGRAMMOS EX DODEKATA +1D0D7 ; [*10C5.0020.0002] # BYZANTINE MUSICAL SYMBOL YFESIS TRIGRAMMOS OKTO DODEKATA +1D0D8 ; [*10C6.0020.0002] # BYZANTINE MUSICAL SYMBOL GENIKI DIESIS +1D0D9 ; [*10C7.0020.0002] # BYZANTINE MUSICAL SYMBOL GENIKI YFESIS +1D0DA ; [*10C8.0020.0002] # BYZANTINE MUSICAL SYMBOL DIASTOLI APLI MIKRI +1D0DB ; [*10C9.0020.0002] # BYZANTINE MUSICAL SYMBOL DIASTOLI APLI MEGALI +1D0DC ; [*10CA.0020.0002] # BYZANTINE MUSICAL SYMBOL DIASTOLI DIPLI +1D0DD ; [*10CB.0020.0002] # BYZANTINE MUSICAL SYMBOL DIASTOLI THESEOS +1D0DE ; [*10CC.0020.0002] # BYZANTINE MUSICAL SYMBOL SIMANSIS THESEOS +1D0DF ; [*10CD.0020.0002] # BYZANTINE MUSICAL SYMBOL SIMANSIS THESEOS DISIMOU +1D0E0 ; [*10CE.0020.0002] # BYZANTINE MUSICAL SYMBOL SIMANSIS THESEOS TRISIMOU +1D0E1 ; [*10CF.0020.0002] # BYZANTINE MUSICAL SYMBOL SIMANSIS THESEOS TETRASIMOU +1D0E2 ; [*10D0.0020.0002] # BYZANTINE MUSICAL SYMBOL SIMANSIS ARSEOS +1D0E3 ; [*10D1.0020.0002] # BYZANTINE MUSICAL SYMBOL SIMANSIS ARSEOS DISIMOU +1D0E4 ; [*10D2.0020.0002] # BYZANTINE MUSICAL SYMBOL SIMANSIS ARSEOS TRISIMOU +1D0E5 ; [*10D3.0020.0002] # BYZANTINE MUSICAL SYMBOL SIMANSIS ARSEOS TETRASIMOU +1D0E6 ; [*10D4.0020.0002] # BYZANTINE MUSICAL SYMBOL DIGRAMMA GG +1D0E7 ; [*10D5.0020.0002] # BYZANTINE MUSICAL SYMBOL DIFTOGGOS OU +1D0E8 ; [*10D6.0020.0002] # BYZANTINE MUSICAL SYMBOL STIGMA +1D0E9 ; [*10D7.0020.0002] # BYZANTINE MUSICAL SYMBOL ARKTIKO PA +1D0EA ; [*10D8.0020.0002] # BYZANTINE MUSICAL SYMBOL ARKTIKO VOU +1D0EB ; [*10D9.0020.0002] # BYZANTINE MUSICAL SYMBOL ARKTIKO GA +1D0EC ; [*10DA.0020.0002] # BYZANTINE MUSICAL SYMBOL ARKTIKO DI +1D0ED ; [*10DB.0020.0002] # BYZANTINE MUSICAL SYMBOL ARKTIKO KE +1D0EE ; [*10DC.0020.0002] # BYZANTINE MUSICAL SYMBOL ARKTIKO ZO +1D0EF ; [*10DD.0020.0002] # BYZANTINE MUSICAL SYMBOL ARKTIKO NI +1D0F0 ; [*10DE.0020.0002] # BYZANTINE MUSICAL SYMBOL KENTIMATA NEO MESO +1D0F1 ; [*10DF.0020.0002] # BYZANTINE MUSICAL SYMBOL KENTIMA NEO MESO +1D0F2 ; [*10E0.0020.0002] # BYZANTINE MUSICAL SYMBOL KENTIMATA NEO KATO +1D0F3 ; [*10E1.0020.0002] # BYZANTINE MUSICAL SYMBOL KENTIMA NEO KATO +1D0F4 ; [*10E2.0020.0002] # BYZANTINE MUSICAL SYMBOL KLASMA KATO +1D0F5 ; [*10E3.0020.0002] # BYZANTINE MUSICAL SYMBOL GORGON NEO KATO +1D100 ; [*10E4.0020.0002] # MUSICAL SYMBOL SINGLE BARLINE +1D101 ; [*10E5.0020.0002] # MUSICAL SYMBOL DOUBLE BARLINE +1D102 ; [*10E6.0020.0002] # MUSICAL SYMBOL FINAL BARLINE +1D103 ; [*10E7.0020.0002] # MUSICAL SYMBOL REVERSE FINAL BARLINE +1D104 ; [*10E8.0020.0002] # MUSICAL SYMBOL DASHED BARLINE +1D105 ; [*10E9.0020.0002] # MUSICAL SYMBOL SHORT BARLINE +1D106 ; [*10EA.0020.0002] # MUSICAL SYMBOL LEFT REPEAT SIGN +1D107 ; [*10EB.0020.0002] # MUSICAL SYMBOL RIGHT REPEAT SIGN +1D108 ; [*10EC.0020.0002] # MUSICAL SYMBOL REPEAT DOTS +1D109 ; [*10ED.0020.0002] # MUSICAL SYMBOL DAL SEGNO +1D10A ; [*10EE.0020.0002] # MUSICAL SYMBOL DA CAPO +1D10B ; [*10EF.0020.0002] # MUSICAL SYMBOL SEGNO +1D10C ; [*10F0.0020.0002] # MUSICAL SYMBOL CODA +1D10D ; [*10F1.0020.0002] # MUSICAL SYMBOL REPEATED FIGURE-1 +1D10E ; [*10F2.0020.0002] # MUSICAL SYMBOL REPEATED FIGURE-2 +1D10F ; [*10F3.0020.0002] # MUSICAL SYMBOL REPEATED FIGURE-3 +1D110 ; [*10F4.0020.0002] # MUSICAL SYMBOL FERMATA +1D111 ; [*10F5.0020.0002] # MUSICAL SYMBOL FERMATA BELOW +1D112 ; [*10F6.0020.0002] # MUSICAL SYMBOL BREATH MARK +1D113 ; [*10F7.0020.0002] # MUSICAL SYMBOL CAESURA +1D114 ; [*10F8.0020.0002] # MUSICAL SYMBOL BRACE +1D115 ; [*10F9.0020.0002] # MUSICAL SYMBOL BRACKET +1D116 ; [*10FA.0020.0002] # MUSICAL SYMBOL ONE-LINE STAFF +1D117 ; [*10FB.0020.0002] # MUSICAL SYMBOL TWO-LINE STAFF +1D118 ; [*10FC.0020.0002] # MUSICAL SYMBOL THREE-LINE STAFF +1D119 ; [*10FD.0020.0002] # MUSICAL SYMBOL FOUR-LINE STAFF +1D11A ; [*10FE.0020.0002] # MUSICAL SYMBOL FIVE-LINE STAFF +1D11B ; [*10FF.0020.0002] # MUSICAL SYMBOL SIX-LINE STAFF +1D11C ; [*1100.0020.0002] # MUSICAL SYMBOL SIX-STRING FRETBOARD +1D11D ; [*1101.0020.0002] # MUSICAL SYMBOL FOUR-STRING FRETBOARD +1D11E ; [*1102.0020.0002] # MUSICAL SYMBOL G CLEF +1D11F ; [*1103.0020.0002] # MUSICAL SYMBOL G CLEF OTTAVA ALTA +1D120 ; [*1104.0020.0002] # MUSICAL SYMBOL G CLEF OTTAVA BASSA +1D121 ; [*1105.0020.0002] # MUSICAL SYMBOL C CLEF +1D122 ; [*1106.0020.0002] # MUSICAL SYMBOL F CLEF +1D123 ; [*1107.0020.0002] # MUSICAL SYMBOL F CLEF OTTAVA ALTA +1D124 ; [*1108.0020.0002] # MUSICAL SYMBOL F CLEF OTTAVA BASSA +1D125 ; [*1109.0020.0002] # MUSICAL SYMBOL DRUM CLEF-1 +1D126 ; [*110A.0020.0002] # MUSICAL SYMBOL DRUM CLEF-2 +1D129 ; [*111E.0020.0002] # MUSICAL SYMBOL MULTIPLE MEASURE REST +1D12A ; [*110E.0020.0002] # MUSICAL SYMBOL DOUBLE SHARP +1D12B ; [*110F.0020.0002] # MUSICAL SYMBOL DOUBLE FLAT +1D12C ; [*1110.0020.0002] # MUSICAL SYMBOL FLAT UP +1D12D ; [*1111.0020.0002] # MUSICAL SYMBOL FLAT DOWN +1D12E ; [*1112.0020.0002] # MUSICAL SYMBOL NATURAL UP +1D12F ; [*1113.0020.0002] # MUSICAL SYMBOL NATURAL DOWN +1D130 ; [*1114.0020.0002] # MUSICAL SYMBOL SHARP UP +1D131 ; [*1115.0020.0002] # MUSICAL SYMBOL SHARP DOWN +1D132 ; [*1116.0020.0002] # MUSICAL SYMBOL QUARTER TONE SHARP +1D133 ; [*1117.0020.0002] # MUSICAL SYMBOL QUARTER TONE FLAT +1D134 ; [*1118.0020.0002] # MUSICAL SYMBOL COMMON TIME +1D135 ; [*1119.0020.0002] # MUSICAL SYMBOL CUT TIME +1D136 ; [*111A.0020.0002] # MUSICAL SYMBOL OTTAVA ALTA +1D137 ; [*111B.0020.0002] # MUSICAL SYMBOL OTTAVA BASSA +1D138 ; [*111C.0020.0002] # MUSICAL SYMBOL QUINDICESIMA ALTA +1D139 ; [*111D.0020.0002] # MUSICAL SYMBOL QUINDICESIMA BASSA +1D13A ; [*111F.0020.0002] # MUSICAL SYMBOL MULTI REST +1D13B ; [*1120.0020.0002] # MUSICAL SYMBOL WHOLE REST +1D13C ; [*1121.0020.0002] # MUSICAL SYMBOL HALF REST +1D13D ; [*1122.0020.0002] # MUSICAL SYMBOL QUARTER REST +1D13E ; [*1123.0020.0002] # MUSICAL SYMBOL EIGHTH REST +1D13F ; [*1124.0020.0002] # MUSICAL SYMBOL SIXTEENTH REST +1D140 ; [*1125.0020.0002] # MUSICAL SYMBOL THIRTY-SECOND REST +1D141 ; [*1126.0020.0002] # MUSICAL SYMBOL SIXTY-FOURTH REST +1D142 ; [*1127.0020.0002] # MUSICAL SYMBOL ONE HUNDRED TWENTY-EIGHTH REST +1D143 ; [*1128.0020.0002] # MUSICAL SYMBOL X NOTEHEAD +1D144 ; [*1129.0020.0002] # MUSICAL SYMBOL PLUS NOTEHEAD +1D145 ; [*112A.0020.0002] # MUSICAL SYMBOL CIRCLE X NOTEHEAD +1D146 ; [*112B.0020.0002] # MUSICAL SYMBOL SQUARE NOTEHEAD WHITE +1D147 ; [*112C.0020.0002] # MUSICAL SYMBOL SQUARE NOTEHEAD BLACK +1D148 ; [*112D.0020.0002] # MUSICAL SYMBOL TRIANGLE NOTEHEAD UP WHITE +1D149 ; [*112E.0020.0002] # MUSICAL SYMBOL TRIANGLE NOTEHEAD UP BLACK +1D14A ; [*112F.0020.0002] # MUSICAL SYMBOL TRIANGLE NOTEHEAD LEFT WHITE +1D14B ; [*1130.0020.0002] # MUSICAL SYMBOL TRIANGLE NOTEHEAD LEFT BLACK +1D14C ; [*1131.0020.0002] # MUSICAL SYMBOL TRIANGLE NOTEHEAD RIGHT WHITE +1D14D ; [*1132.0020.0002] # MUSICAL SYMBOL TRIANGLE NOTEHEAD RIGHT BLACK +1D14E ; [*1133.0020.0002] # MUSICAL SYMBOL TRIANGLE NOTEHEAD DOWN WHITE +1D14F ; [*1134.0020.0002] # MUSICAL SYMBOL TRIANGLE NOTEHEAD DOWN BLACK +1D150 ; [*1135.0020.0002] # MUSICAL SYMBOL TRIANGLE NOTEHEAD UP RIGHT WHITE +1D151 ; [*1136.0020.0002] # MUSICAL SYMBOL TRIANGLE NOTEHEAD UP RIGHT BLACK +1D152 ; [*1137.0020.0002] # MUSICAL SYMBOL MOON NOTEHEAD WHITE +1D153 ; [*1138.0020.0002] # MUSICAL SYMBOL MOON NOTEHEAD BLACK +1D154 ; [*1139.0020.0002] # MUSICAL SYMBOL TRIANGLE-ROUND NOTEHEAD DOWN WHITE +1D155 ; [*113A.0020.0002] # MUSICAL SYMBOL TRIANGLE-ROUND NOTEHEAD DOWN BLACK +1D156 ; [*113B.0020.0002] # MUSICAL SYMBOL PARENTHESIS NOTEHEAD +1D157 ; [*113C.0020.0002] # MUSICAL SYMBOL VOID NOTEHEAD +1D158 ; [*113D.0020.0002] # MUSICAL SYMBOL NOTEHEAD BLACK +1D159 ; [*113E.0020.0002] # MUSICAL SYMBOL NULL NOTEHEAD +1D15A ; [*113F.0020.0002] # MUSICAL SYMBOL CLUSTER NOTEHEAD WHITE +1D15B ; [*1140.0020.0002] # MUSICAL SYMBOL CLUSTER NOTEHEAD BLACK +1D15C ; [*1141.0020.0002] # MUSICAL SYMBOL BREVE +1D15D ; [*1142.0020.0002] # MUSICAL SYMBOL WHOLE NOTE +1D15E ; [*113C.0020.0002][.0000.0000.0000] # MUSICAL SYMBOL HALF NOTE +1D15F ; [*113D.0020.0002][.0000.0000.0000] # MUSICAL SYMBOL QUARTER NOTE +1D160 ; [*113D.0020.0002][.0000.0000.0000][.0000.0000.0000] # MUSICAL SYMBOL EIGHTH NOTE +1D161 ; [*113D.0020.0002][.0000.0000.0000][.0000.0000.0000] # MUSICAL SYMBOL SIXTEENTH NOTE +1D162 ; [*113D.0020.0002][.0000.0000.0000][.0000.0000.0000] # MUSICAL SYMBOL THIRTY-SECOND NOTE +1D163 ; [*113D.0020.0002][.0000.0000.0000][.0000.0000.0000] # MUSICAL SYMBOL SIXTY-FOURTH NOTE +1D164 ; [*113D.0020.0002][.0000.0000.0000][.0000.0000.0000] # MUSICAL SYMBOL ONE HUNDRED TWENTY-EIGHTH NOTE +1D165 ; [.0000.0000.0000] # MUSICAL SYMBOL COMBINING STEM +1D166 ; [.0000.0000.0000] # MUSICAL SYMBOL COMBINING SPRECHGESANG STEM +1D167 ; [.0000.0000.0000] # MUSICAL SYMBOL COMBINING TREMOLO-1 +1D168 ; [.0000.0000.0000] # MUSICAL SYMBOL COMBINING TREMOLO-2 +1D169 ; [.0000.0000.0000] # MUSICAL SYMBOL COMBINING TREMOLO-3 +1D16A ; [*1143.0020.0002] # MUSICAL SYMBOL FINGERED TREMOLO-1 +1D16B ; [*1144.0020.0002] # MUSICAL SYMBOL FINGERED TREMOLO-2 +1D16C ; [*1145.0020.0002] # MUSICAL SYMBOL FINGERED TREMOLO-3 +1D16D ; [.0000.0000.0000] # MUSICAL SYMBOL COMBINING AUGMENTATION DOT +1D16E ; [.0000.0000.0000] # MUSICAL SYMBOL COMBINING FLAG-1 +1D16F ; [.0000.0000.0000] # MUSICAL SYMBOL COMBINING FLAG-2 +1D170 ; [.0000.0000.0000] # MUSICAL SYMBOL COMBINING FLAG-3 +1D171 ; [.0000.0000.0000] # MUSICAL SYMBOL COMBINING FLAG-4 +1D172 ; [.0000.0000.0000] # MUSICAL SYMBOL COMBINING FLAG-5 +1D17B ; [.0000.0000.0000] # MUSICAL SYMBOL COMBINING ACCENT +1D17C ; [.0000.0000.0000] # MUSICAL SYMBOL COMBINING STACCATO +1D17D ; [.0000.0000.0000] # MUSICAL SYMBOL COMBINING TENUTO +1D17E ; [.0000.0000.0000] # MUSICAL SYMBOL COMBINING STACCATISSIMO +1D17F ; [.0000.0000.0000] # MUSICAL SYMBOL COMBINING MARCATO +1D180 ; [.0000.0000.0000] # MUSICAL SYMBOL COMBINING MARCATO-STACCATO +1D181 ; [.0000.0000.0000] # MUSICAL SYMBOL COMBINING ACCENT-STACCATO +1D182 ; [.0000.0000.0000] # MUSICAL SYMBOL COMBINING LOURE +1D183 ; [*1146.0020.0002] # MUSICAL SYMBOL ARPEGGIATO UP +1D184 ; [*1147.0020.0002] # MUSICAL SYMBOL ARPEGGIATO DOWN +1D185 ; [.0000.0000.0000] # MUSICAL SYMBOL COMBINING DOIT +1D186 ; [.0000.0000.0000] # MUSICAL SYMBOL COMBINING RIP +1D187 ; [.0000.0000.0000] # MUSICAL SYMBOL COMBINING FLIP +1D188 ; [.0000.0000.0000] # MUSICAL SYMBOL COMBINING SMEAR +1D189 ; [.0000.0000.0000] # MUSICAL SYMBOL COMBINING BEND +1D18A ; [.0000.0000.0000] # MUSICAL SYMBOL COMBINING DOUBLE TONGUE +1D18B ; [.0000.0000.0000] # MUSICAL SYMBOL COMBINING TRIPLE TONGUE +1D18C ; [*1148.0020.0002] # MUSICAL SYMBOL RINFORZANDO +1D18D ; [*1149.0020.0002] # MUSICAL SYMBOL SUBITO +1D18E ; [*114A.0020.0002] # MUSICAL SYMBOL Z +1D18F ; [*114B.0020.0002] # MUSICAL SYMBOL PIANO +1D190 ; [*114C.0020.0002] # MUSICAL SYMBOL MEZZO +1D191 ; [*114D.0020.0002] # MUSICAL SYMBOL FORTE +1D192 ; [*114E.0020.0002] # MUSICAL SYMBOL CRESCENDO +1D193 ; [*114F.0020.0002] # MUSICAL SYMBOL DECRESCENDO +1D194 ; [*1150.0020.0002] # MUSICAL SYMBOL GRACE NOTE SLASH +1D195 ; [*1151.0020.0002] # MUSICAL SYMBOL GRACE NOTE NO SLASH +1D196 ; [*1152.0020.0002] # MUSICAL SYMBOL TR +1D197 ; [*1153.0020.0002] # MUSICAL SYMBOL TURN +1D198 ; [*1154.0020.0002] # MUSICAL SYMBOL INVERTED TURN +1D199 ; [*1155.0020.0002] # MUSICAL SYMBOL TURN SLASH +1D19A ; [*1156.0020.0002] # MUSICAL SYMBOL TURN UP +1D19B ; [*1157.0020.0002] # MUSICAL SYMBOL ORNAMENT STROKE-1 +1D19C ; [*1158.0020.0002] # MUSICAL SYMBOL ORNAMENT STROKE-2 +1D19D ; [*1159.0020.0002] # MUSICAL SYMBOL ORNAMENT STROKE-3 +1D19E ; [*115A.0020.0002] # MUSICAL SYMBOL ORNAMENT STROKE-4 +1D19F ; [*115B.0020.0002] # MUSICAL SYMBOL ORNAMENT STROKE-5 +1D1A0 ; [*115C.0020.0002] # MUSICAL SYMBOL ORNAMENT STROKE-6 +1D1A1 ; [*115D.0020.0002] # MUSICAL SYMBOL ORNAMENT STROKE-7 +1D1A2 ; [*115E.0020.0002] # MUSICAL SYMBOL ORNAMENT STROKE-8 +1D1A3 ; [*115F.0020.0002] # MUSICAL SYMBOL ORNAMENT STROKE-9 +1D1A4 ; [*1160.0020.0002] # MUSICAL SYMBOL ORNAMENT STROKE-10 +1D1A5 ; [*1161.0020.0002] # MUSICAL SYMBOL ORNAMENT STROKE-11 +1D1A6 ; [*1162.0020.0002] # MUSICAL SYMBOL HAUPTSTIMME +1D1A7 ; [*1163.0020.0002] # MUSICAL SYMBOL NEBENSTIMME +1D1A8 ; [*1164.0020.0002] # MUSICAL SYMBOL END OF STIMME +1D1A9 ; [*1165.0020.0002] # MUSICAL SYMBOL DEGREE SLASH +1D1AA ; [.0000.0000.0000] # MUSICAL SYMBOL COMBINING DOWN BOW +1D1AB ; [.0000.0000.0000] # MUSICAL SYMBOL COMBINING UP BOW +1D1AC ; [.0000.0000.0000] # MUSICAL SYMBOL COMBINING HARMONIC +1D1AD ; [.0000.0000.0000] # MUSICAL SYMBOL COMBINING SNAP PIZZICATO +1D1AE ; [*1166.0020.0002] # MUSICAL SYMBOL PEDAL MARK +1D1AF ; [*1167.0020.0002] # MUSICAL SYMBOL PEDAL UP MARK +1D1B0 ; [*1168.0020.0002] # MUSICAL SYMBOL HALF PEDAL MARK +1D1B1 ; [*1169.0020.0002] # MUSICAL SYMBOL GLISSANDO UP +1D1B2 ; [*116A.0020.0002] # MUSICAL SYMBOL GLISSANDO DOWN +1D1B3 ; [*116B.0020.0002] # MUSICAL SYMBOL WITH FINGERNAILS +1D1B4 ; [*116C.0020.0002] # MUSICAL SYMBOL DAMP +1D1B5 ; [*116D.0020.0002] # MUSICAL SYMBOL DAMP ALL +1D1B6 ; [*116E.0020.0002] # MUSICAL SYMBOL MAXIMA +1D1B7 ; [*116F.0020.0002] # MUSICAL SYMBOL LONGA +1D1B8 ; [*1170.0020.0002] # MUSICAL SYMBOL BREVIS +1D1B9 ; [*1171.0020.0002] # MUSICAL SYMBOL SEMIBREVIS WHITE +1D1BA ; [*1172.0020.0002] # MUSICAL SYMBOL SEMIBREVIS BLACK +1D1BB ; [*1171.0020.0002][.0000.0000.0000] # MUSICAL SYMBOL MINIMA +1D1BC ; [*1172.0020.0002][.0000.0000.0000] # MUSICAL SYMBOL MINIMA BLACK +1D1BD ; [*1171.0020.0002][.0000.0000.0000][.0000.0000.0000] # MUSICAL SYMBOL SEMIMINIMA WHITE +1D1BE ; [*1172.0020.0002][.0000.0000.0000][.0000.0000.0000] # MUSICAL SYMBOL SEMIMINIMA BLACK +1D1BF ; [*1171.0020.0002][.0000.0000.0000][.0000.0000.0000] # MUSICAL SYMBOL FUSA WHITE +1D1C0 ; [*1172.0020.0002][.0000.0000.0000][.0000.0000.0000] # MUSICAL SYMBOL FUSA BLACK +1D1C1 ; [*1173.0020.0002] # MUSICAL SYMBOL LONGA PERFECTA REST +1D1C2 ; [*1174.0020.0002] # MUSICAL SYMBOL LONGA IMPERFECTA REST +1D1C3 ; [*1175.0020.0002] # MUSICAL SYMBOL BREVIS REST +1D1C4 ; [*1176.0020.0002] # MUSICAL SYMBOL SEMIBREVIS REST +1D1C5 ; [*1177.0020.0002] # MUSICAL SYMBOL MINIMA REST +1D1C6 ; [*1178.0020.0002] # MUSICAL SYMBOL SEMIMINIMA REST +1D1C7 ; [*1179.0020.0002] # MUSICAL SYMBOL TEMPUS PERFECTUM CUM PROLATIONE PERFECTA +1D1C8 ; [*117A.0020.0002] # MUSICAL SYMBOL TEMPUS PERFECTUM CUM PROLATIONE IMPERFECTA +1D1C9 ; [*117B.0020.0002] # MUSICAL SYMBOL TEMPUS PERFECTUM CUM PROLATIONE PERFECTA DIMINUTION-1 +1D1CA ; [*117C.0020.0002] # MUSICAL SYMBOL TEMPUS IMPERFECTUM CUM PROLATIONE PERFECTA +1D1CB ; [*117D.0020.0002] # MUSICAL SYMBOL TEMPUS IMPERFECTUM CUM PROLATIONE IMPERFECTA +1D1CC ; [*117E.0020.0002] # MUSICAL SYMBOL TEMPUS IMPERFECTUM CUM PROLATIONE IMPERFECTA DIMINUTION-1 +1D1CD ; [*117F.0020.0002] # MUSICAL SYMBOL TEMPUS IMPERFECTUM CUM PROLATIONE IMPERFECTA DIMINUTION-2 +1D1CE ; [*1180.0020.0002] # MUSICAL SYMBOL TEMPUS IMPERFECTUM CUM PROLATIONE IMPERFECTA DIMINUTION-3 +1D1CF ; [*1181.0020.0002] # MUSICAL SYMBOL CROIX +1D1D0 ; [*1182.0020.0002] # MUSICAL SYMBOL GREGORIAN C CLEF +1D1D1 ; [*1183.0020.0002] # MUSICAL SYMBOL GREGORIAN F CLEF +1D1D2 ; [*1184.0020.0002] # MUSICAL SYMBOL SQUARE B +1D1D3 ; [*1185.0020.0002] # MUSICAL SYMBOL VIRGA +1D1D4 ; [*1186.0020.0002] # MUSICAL SYMBOL PODATUS +1D1D5 ; [*1187.0020.0002] # MUSICAL SYMBOL CLIVIS +1D1D6 ; [*1188.0020.0002] # MUSICAL SYMBOL SCANDICUS +1D1D7 ; [*1189.0020.0002] # MUSICAL SYMBOL CLIMACUS +1D1D8 ; [*118A.0020.0002] # MUSICAL SYMBOL TORCULUS +1D1D9 ; [*118B.0020.0002] # MUSICAL SYMBOL PORRECTUS +1D1DA ; [*118C.0020.0002] # MUSICAL SYMBOL PORRECTUS FLEXUS +1D1DB ; [*118D.0020.0002] # MUSICAL SYMBOL SCANDICUS FLEXUS +1D1DC ; [*118E.0020.0002] # MUSICAL SYMBOL TORCULUS RESUPINUS +1D1DD ; [*118F.0020.0002] # MUSICAL SYMBOL PES SUBPUNCTIS +1D1DE ; [*1190.0020.0002] # MUSICAL SYMBOL KIEVAN C CLEF +1D1DF ; [*1191.0020.0002] # MUSICAL SYMBOL KIEVAN END OF PIECE +1D1E0 ; [*1192.0020.0002] # MUSICAL SYMBOL KIEVAN FINAL NOTE +1D1E1 ; [*1193.0020.0002] # MUSICAL SYMBOL KIEVAN RECITATIVE MARK +1D1E2 ; [*1194.0020.0002] # MUSICAL SYMBOL KIEVAN WHOLE NOTE +1D1E3 ; [*1195.0020.0002] # MUSICAL SYMBOL KIEVAN HALF NOTE +1D1E4 ; [*1196.0020.0002] # MUSICAL SYMBOL KIEVAN QUARTER NOTE STEM DOWN +1D1E5 ; [*1197.0020.0002] # MUSICAL SYMBOL KIEVAN QUARTER NOTE STEM UP +1D1E6 ; [*1198.0020.0002] # MUSICAL SYMBOL KIEVAN EIGHTH NOTE STEM DOWN +1D1E7 ; [*1199.0020.0002] # MUSICAL SYMBOL KIEVAN EIGHTH NOTE STEM UP +1D1E8 ; [*119A.0020.0002] # MUSICAL SYMBOL KIEVAN FLAT SIGN +1D200 ; [*119B.0020.0002] # GREEK VOCAL NOTATION SYMBOL-1 +1D201 ; [*119C.0020.0002] # GREEK VOCAL NOTATION SYMBOL-2 +1D202 ; [*119D.0020.0002] # GREEK VOCAL NOTATION SYMBOL-3 +1D203 ; [*119E.0020.0002] # GREEK VOCAL NOTATION SYMBOL-4 +1D204 ; [*119F.0020.0002] # GREEK VOCAL NOTATION SYMBOL-5 +1D205 ; [*11A0.0020.0002] # GREEK VOCAL NOTATION SYMBOL-6 +1D206 ; [*11A1.0020.0002] # GREEK VOCAL NOTATION SYMBOL-7 +1D207 ; [*11A2.0020.0002] # GREEK VOCAL NOTATION SYMBOL-8 +1D208 ; [*11A3.0020.0002] # GREEK VOCAL NOTATION SYMBOL-9 +1D209 ; [*11A4.0020.0002] # GREEK VOCAL NOTATION SYMBOL-10 +1D20A ; [*11A5.0020.0002] # GREEK VOCAL NOTATION SYMBOL-11 +1D20B ; [*11A6.0020.0002] # GREEK VOCAL NOTATION SYMBOL-12 +1D20C ; [*11A7.0020.0002] # GREEK VOCAL NOTATION SYMBOL-13 +1D20D ; [*11A8.0020.0002] # GREEK VOCAL NOTATION SYMBOL-14 +1D20E ; [*11A9.0020.0002] # GREEK VOCAL NOTATION SYMBOL-15 +1D20F ; [*11AA.0020.0002] # GREEK VOCAL NOTATION SYMBOL-16 +1D210 ; [*11AB.0020.0002] # GREEK VOCAL NOTATION SYMBOL-17 +1D211 ; [*11AC.0020.0002] # GREEK VOCAL NOTATION SYMBOL-18 +1D212 ; [*11AD.0020.0002] # GREEK VOCAL NOTATION SYMBOL-19 +1D213 ; [*11AE.0020.0002] # GREEK VOCAL NOTATION SYMBOL-20 +1D214 ; [*11AF.0020.0002] # GREEK VOCAL NOTATION SYMBOL-21 +1D215 ; [*11B0.0020.0002] # GREEK VOCAL NOTATION SYMBOL-22 +1D216 ; [*11B1.0020.0002] # GREEK VOCAL NOTATION SYMBOL-23 +1D217 ; [*11B2.0020.0002] # GREEK VOCAL NOTATION SYMBOL-24 +1D218 ; [*11B3.0020.0002] # GREEK VOCAL NOTATION SYMBOL-50 +1D219 ; [*11B4.0020.0002] # GREEK VOCAL NOTATION SYMBOL-51 +1D21A ; [*11B5.0020.0002] # GREEK VOCAL NOTATION SYMBOL-52 +1D21B ; [*11B6.0020.0002] # GREEK VOCAL NOTATION SYMBOL-53 +1D21C ; [*11B7.0020.0002] # GREEK VOCAL NOTATION SYMBOL-54 +1D21D ; [*11B8.0020.0002] # GREEK INSTRUMENTAL NOTATION SYMBOL-1 +1D21E ; [*11B9.0020.0002] # GREEK INSTRUMENTAL NOTATION SYMBOL-2 +1D21F ; [*11BA.0020.0002] # GREEK INSTRUMENTAL NOTATION SYMBOL-4 +1D220 ; [*11BB.0020.0002] # GREEK INSTRUMENTAL NOTATION SYMBOL-5 +1D221 ; [*11BC.0020.0002] # GREEK INSTRUMENTAL NOTATION SYMBOL-7 +1D222 ; [*11BD.0020.0002] # GREEK INSTRUMENTAL NOTATION SYMBOL-8 +1D223 ; [*11BE.0020.0002] # GREEK INSTRUMENTAL NOTATION SYMBOL-11 +1D224 ; [*11BF.0020.0002] # GREEK INSTRUMENTAL NOTATION SYMBOL-12 +1D225 ; [*11C0.0020.0002] # GREEK INSTRUMENTAL NOTATION SYMBOL-13 +1D226 ; [*11C1.0020.0002] # GREEK INSTRUMENTAL NOTATION SYMBOL-14 +1D227 ; [*11C2.0020.0002] # GREEK INSTRUMENTAL NOTATION SYMBOL-17 +1D228 ; [*11C3.0020.0002] # GREEK INSTRUMENTAL NOTATION SYMBOL-18 +1D229 ; [*11C4.0020.0002] # GREEK INSTRUMENTAL NOTATION SYMBOL-19 +1D22A ; [*11C5.0020.0002] # GREEK INSTRUMENTAL NOTATION SYMBOL-23 +1D22B ; [*11C6.0020.0002] # GREEK INSTRUMENTAL NOTATION SYMBOL-24 +1D22C ; [*11C7.0020.0002] # GREEK INSTRUMENTAL NOTATION SYMBOL-25 +1D22D ; [*11C8.0020.0002] # GREEK INSTRUMENTAL NOTATION SYMBOL-26 +1D22E ; [*11C9.0020.0002] # GREEK INSTRUMENTAL NOTATION SYMBOL-27 +1D22F ; [*11CA.0020.0002] # GREEK INSTRUMENTAL NOTATION SYMBOL-29 +1D230 ; [*11CB.0020.0002] # GREEK INSTRUMENTAL NOTATION SYMBOL-30 +1D231 ; [*11CC.0020.0002] # GREEK INSTRUMENTAL NOTATION SYMBOL-32 +1D232 ; [*11CD.0020.0002] # GREEK INSTRUMENTAL NOTATION SYMBOL-36 +1D233 ; [*11CE.0020.0002] # GREEK INSTRUMENTAL NOTATION SYMBOL-37 +1D234 ; [*11CF.0020.0002] # GREEK INSTRUMENTAL NOTATION SYMBOL-38 +1D235 ; [*11D0.0020.0002] # GREEK INSTRUMENTAL NOTATION SYMBOL-39 +1D236 ; [*11D1.0020.0002] # GREEK INSTRUMENTAL NOTATION SYMBOL-40 +1D237 ; [*11D2.0020.0002] # GREEK INSTRUMENTAL NOTATION SYMBOL-42 +1D238 ; [*11D3.0020.0002] # GREEK INSTRUMENTAL NOTATION SYMBOL-43 +1D239 ; [*11D4.0020.0002] # GREEK INSTRUMENTAL NOTATION SYMBOL-45 +1D23A ; [*11D5.0020.0002] # GREEK INSTRUMENTAL NOTATION SYMBOL-47 +1D23B ; [*11D6.0020.0002] # GREEK INSTRUMENTAL NOTATION SYMBOL-48 +1D23C ; [*11D7.0020.0002] # GREEK INSTRUMENTAL NOTATION SYMBOL-49 +1D23D ; [*11D8.0020.0002] # GREEK INSTRUMENTAL NOTATION SYMBOL-50 +1D23E ; [*11D9.0020.0002] # GREEK INSTRUMENTAL NOTATION SYMBOL-51 +1D23F ; [*11DA.0020.0002] # GREEK INSTRUMENTAL NOTATION SYMBOL-52 +1D240 ; [*11DB.0020.0002] # GREEK INSTRUMENTAL NOTATION SYMBOL-53 +1D241 ; [*11DC.0020.0002] # GREEK INSTRUMENTAL NOTATION SYMBOL-54 +1D242 ; [.0000.0000.0000] # COMBINING GREEK MUSICAL TRISEME +1D243 ; [.0000.0000.0000] # COMBINING GREEK MUSICAL TETRASEME +1D244 ; [.0000.0000.0000] # COMBINING GREEK MUSICAL PENTASEME +1D245 ; [*11DD.0020.0002] # GREEK MUSICAL LEIMMA +1D300 ; [*0F02.0020.0002] # MONOGRAM FOR EARTH +1D301 ; [*0F03.0020.0002] # DIGRAM FOR HEAVENLY EARTH +1D302 ; [*0F04.0020.0002] # DIGRAM FOR HUMAN EARTH +1D303 ; [*0F05.0020.0002] # DIGRAM FOR EARTHLY HEAVEN +1D304 ; [*0F06.0020.0002] # DIGRAM FOR EARTHLY HUMAN +1D305 ; [*0F07.0020.0002] # DIGRAM FOR EARTH +1D306 ; [*0F08.0020.0002] # TETRAGRAM FOR CENTRE +1D307 ; [*0F09.0020.0002] # TETRAGRAM FOR FULL CIRCLE +1D308 ; [*0F0A.0020.0002] # TETRAGRAM FOR MIRED +1D309 ; [*0F0B.0020.0002] # TETRAGRAM FOR BARRIER +1D30A ; [*0F0C.0020.0002] # TETRAGRAM FOR KEEPING SMALL +1D30B ; [*0F0D.0020.0002] # TETRAGRAM FOR CONTRARIETY +1D30C ; [*0F0E.0020.0002] # TETRAGRAM FOR ASCENT +1D30D ; [*0F0F.0020.0002] # TETRAGRAM FOR OPPOSITION +1D30E ; [*0F10.0020.0002] # TETRAGRAM FOR BRANCHING OUT +1D30F ; [*0F11.0020.0002] # TETRAGRAM FOR DEFECTIVENESS OR DISTORTION +1D310 ; [*0F12.0020.0002] # TETRAGRAM FOR DIVERGENCE +1D311 ; [*0F13.0020.0002] # TETRAGRAM FOR YOUTHFULNESS +1D312 ; [*0F14.0020.0002] # TETRAGRAM FOR INCREASE +1D313 ; [*0F15.0020.0002] # TETRAGRAM FOR PENETRATION +1D314 ; [*0F16.0020.0002] # TETRAGRAM FOR REACH +1D315 ; [*0F17.0020.0002] # TETRAGRAM FOR CONTACT +1D316 ; [*0F18.0020.0002] # TETRAGRAM FOR HOLDING BACK +1D317 ; [*0F19.0020.0002] # TETRAGRAM FOR WAITING +1D318 ; [*0F1A.0020.0002] # TETRAGRAM FOR FOLLOWING +1D319 ; [*0F1B.0020.0002] # TETRAGRAM FOR ADVANCE +1D31A ; [*0F1C.0020.0002] # TETRAGRAM FOR RELEASE +1D31B ; [*0F1D.0020.0002] # TETRAGRAM FOR RESISTANCE +1D31C ; [*0F1E.0020.0002] # TETRAGRAM FOR EASE +1D31D ; [*0F1F.0020.0002] # TETRAGRAM FOR JOY +1D31E ; [*0F20.0020.0002] # TETRAGRAM FOR CONTENTION +1D31F ; [*0F21.0020.0002] # TETRAGRAM FOR ENDEAVOUR +1D320 ; [*0F22.0020.0002] # TETRAGRAM FOR DUTIES +1D321 ; [*0F23.0020.0002] # TETRAGRAM FOR CHANGE +1D322 ; [*0F24.0020.0002] # TETRAGRAM FOR DECISIVENESS +1D323 ; [*0F25.0020.0002] # TETRAGRAM FOR BOLD RESOLUTION +1D324 ; [*0F26.0020.0002] # TETRAGRAM FOR PACKING +1D325 ; [*0F27.0020.0002] # TETRAGRAM FOR LEGION +1D326 ; [*0F28.0020.0002] # TETRAGRAM FOR CLOSENESS +1D327 ; [*0F29.0020.0002] # TETRAGRAM FOR KINSHIP +1D328 ; [*0F2A.0020.0002] # TETRAGRAM FOR GATHERING +1D329 ; [*0F2B.0020.0002] # TETRAGRAM FOR STRENGTH +1D32A ; [*0F2C.0020.0002] # TETRAGRAM FOR PURITY +1D32B ; [*0F2D.0020.0002] # TETRAGRAM FOR FULLNESS +1D32C ; [*0F2E.0020.0002] # TETRAGRAM FOR RESIDENCE +1D32D ; [*0F2F.0020.0002] # TETRAGRAM FOR LAW OR MODEL +1D32E ; [*0F30.0020.0002] # TETRAGRAM FOR RESPONSE +1D32F ; [*0F31.0020.0002] # TETRAGRAM FOR GOING TO MEET +1D330 ; [*0F32.0020.0002] # TETRAGRAM FOR ENCOUNTERS +1D331 ; [*0F33.0020.0002] # TETRAGRAM FOR STOVE +1D332 ; [*0F34.0020.0002] # TETRAGRAM FOR GREATNESS +1D333 ; [*0F35.0020.0002] # TETRAGRAM FOR ENLARGEMENT +1D334 ; [*0F36.0020.0002] # TETRAGRAM FOR PATTERN +1D335 ; [*0F37.0020.0002] # TETRAGRAM FOR RITUAL +1D336 ; [*0F38.0020.0002] # TETRAGRAM FOR FLIGHT +1D337 ; [*0F39.0020.0002] # TETRAGRAM FOR VASTNESS OR WASTING +1D338 ; [*0F3A.0020.0002] # TETRAGRAM FOR CONSTANCY +1D339 ; [*0F3B.0020.0002] # TETRAGRAM FOR MEASURE +1D33A ; [*0F3C.0020.0002] # TETRAGRAM FOR ETERNITY +1D33B ; [*0F3D.0020.0002] # TETRAGRAM FOR UNITY +1D33C ; [*0F3E.0020.0002] # TETRAGRAM FOR DIMINISHMENT +1D33D ; [*0F3F.0020.0002] # TETRAGRAM FOR CLOSED MOUTH +1D33E ; [*0F40.0020.0002] # TETRAGRAM FOR GUARDEDNESS +1D33F ; [*0F41.0020.0002] # TETRAGRAM FOR GATHERING IN +1D340 ; [*0F42.0020.0002] # TETRAGRAM FOR MASSING +1D341 ; [*0F43.0020.0002] # TETRAGRAM FOR ACCUMULATION +1D342 ; [*0F44.0020.0002] # TETRAGRAM FOR EMBELLISHMENT +1D343 ; [*0F45.0020.0002] # TETRAGRAM FOR DOUBT +1D344 ; [*0F46.0020.0002] # TETRAGRAM FOR WATCH +1D345 ; [*0F47.0020.0002] # TETRAGRAM FOR SINKING +1D346 ; [*0F48.0020.0002] # TETRAGRAM FOR INNER +1D347 ; [*0F49.0020.0002] # TETRAGRAM FOR DEPARTURE +1D348 ; [*0F4A.0020.0002] # TETRAGRAM FOR DARKENING +1D349 ; [*0F4B.0020.0002] # TETRAGRAM FOR DIMMING +1D34A ; [*0F4C.0020.0002] # TETRAGRAM FOR EXHAUSTION +1D34B ; [*0F4D.0020.0002] # TETRAGRAM FOR SEVERANCE +1D34C ; [*0F4E.0020.0002] # TETRAGRAM FOR STOPPAGE +1D34D ; [*0F4F.0020.0002] # TETRAGRAM FOR HARDNESS +1D34E ; [*0F50.0020.0002] # TETRAGRAM FOR COMPLETION +1D34F ; [*0F51.0020.0002] # TETRAGRAM FOR CLOSURE +1D350 ; [*0F52.0020.0002] # TETRAGRAM FOR FAILURE +1D351 ; [*0F53.0020.0002] # TETRAGRAM FOR AGGRAVATION +1D352 ; [*0F54.0020.0002] # TETRAGRAM FOR COMPLIANCE +1D353 ; [*0F55.0020.0002] # TETRAGRAM FOR ON THE VERGE +1D354 ; [*0F56.0020.0002] # TETRAGRAM FOR DIFFICULTIES +1D355 ; [*0F57.0020.0002] # TETRAGRAM FOR LABOURING +1D356 ; [*0F58.0020.0002] # TETRAGRAM FOR FOSTERING +1D369 ; [*1C53.0020.0002] # COUNTING ROD TENS DIGIT ONE +1D36A ; [*1C54.0020.0002] # COUNTING ROD TENS DIGIT TWO +1D36B ; [*1C55.0020.0002] # COUNTING ROD TENS DIGIT THREE +1D36C ; [*1C56.0020.0002] # COUNTING ROD TENS DIGIT FOUR +1D36D ; [*1C57.0020.0002] # COUNTING ROD TENS DIGIT FIVE +1D36E ; [*1C58.0020.0002] # COUNTING ROD TENS DIGIT SIX +1D36F ; [*1C59.0020.0002] # COUNTING ROD TENS DIGIT SEVEN +1D370 ; [*1C5A.0020.0002] # COUNTING ROD TENS DIGIT EIGHT +1D371 ; [*1C5B.0020.0002] # COUNTING ROD TENS DIGIT NINE +1D6C1 ; [*0622.0020.0005] # MATHEMATICAL BOLD NABLA +1D6DB ; [*061E.0020.0005] # MATHEMATICAL BOLD PARTIAL DIFFERENTIAL +1D6FB ; [*0622.0020.0005] # MATHEMATICAL ITALIC NABLA +1D715 ; [*061E.0020.0005] # MATHEMATICAL ITALIC PARTIAL DIFFERENTIAL +1D735 ; [*0622.0020.0005] # MATHEMATICAL BOLD ITALIC NABLA +1D74F ; [*061E.0020.0005] # MATHEMATICAL BOLD ITALIC PARTIAL DIFFERENTIAL +1D76F ; [*0622.0020.0005] # MATHEMATICAL SANS-SERIF BOLD NABLA +1D789 ; [*061E.0020.0005] # MATHEMATICAL SANS-SERIF BOLD PARTIAL DIFFERENTIAL +1D7A9 ; [*0622.0020.0005] # MATHEMATICAL SANS-SERIF BOLD ITALIC NABLA +1D7C3 ; [*061E.0020.0005] # MATHEMATICAL SANS-SERIF BOLD ITALIC PARTIAL DIFFERENTIAL +1D800 ; [*18A3.0020.0002] # SIGNWRITING HAND-FIST INDEX +1D801 ; [*18A4.0020.0002] # SIGNWRITING HAND-CIRCLE INDEX +1D802 ; [*18A5.0020.0002] # SIGNWRITING HAND-CUP INDEX +1D803 ; [*18A6.0020.0002] # SIGNWRITING HAND-OVAL INDEX +1D804 ; [*18A7.0020.0002] # SIGNWRITING HAND-HINGE INDEX +1D805 ; [*18A8.0020.0002] # SIGNWRITING HAND-ANGLE INDEX +1D806 ; [*18A9.0020.0002] # SIGNWRITING HAND-FIST INDEX BENT +1D807 ; [*18AA.0020.0002] # SIGNWRITING HAND-CIRCLE INDEX BENT +1D808 ; [*18AB.0020.0002] # SIGNWRITING HAND-FIST THUMB UNDER INDEX BENT +1D809 ; [*18AC.0020.0002] # SIGNWRITING HAND-FIST INDEX RAISED KNUCKLE +1D80A ; [*18AD.0020.0002] # SIGNWRITING HAND-FIST INDEX CUPPED +1D80B ; [*18AE.0020.0002] # SIGNWRITING HAND-FIST INDEX HINGED +1D80C ; [*18AF.0020.0002] # SIGNWRITING HAND-FIST INDEX HINGED LOW +1D80D ; [*18B0.0020.0002] # SIGNWRITING HAND-CIRCLE INDEX HINGE +1D80E ; [*18B1.0020.0002] # SIGNWRITING HAND-FIST INDEX MIDDLE +1D80F ; [*18B2.0020.0002] # SIGNWRITING HAND-CIRCLE INDEX MIDDLE +1D810 ; [*18B3.0020.0002] # SIGNWRITING HAND-FIST INDEX MIDDLE BENT +1D811 ; [*18B4.0020.0002] # SIGNWRITING HAND-FIST INDEX MIDDLE RAISED KNUCKLES +1D812 ; [*18B5.0020.0002] # SIGNWRITING HAND-FIST INDEX MIDDLE HINGED +1D813 ; [*18B6.0020.0002] # SIGNWRITING HAND-FIST INDEX UP MIDDLE HINGED +1D814 ; [*18B7.0020.0002] # SIGNWRITING HAND-FIST INDEX HINGED MIDDLE UP +1D815 ; [*18B8.0020.0002] # SIGNWRITING HAND-FIST INDEX MIDDLE CONJOINED +1D816 ; [*18B9.0020.0002] # SIGNWRITING HAND-FIST INDEX MIDDLE CONJOINED INDEX BENT +1D817 ; [*18BA.0020.0002] # SIGNWRITING HAND-FIST INDEX MIDDLE CONJOINED MIDDLE BENT +1D818 ; [*18BB.0020.0002] # SIGNWRITING HAND-FIST INDEX MIDDLE CONJOINED CUPPED +1D819 ; [*18BC.0020.0002] # SIGNWRITING HAND-FIST INDEX MIDDLE CONJOINED HINGED +1D81A ; [*18BD.0020.0002] # SIGNWRITING HAND-FIST INDEX MIDDLE CROSSED +1D81B ; [*18BE.0020.0002] # SIGNWRITING HAND-CIRCLE INDEX MIDDLE CROSSED +1D81C ; [*18BF.0020.0002] # SIGNWRITING HAND-FIST MIDDLE BENT OVER INDEX +1D81D ; [*18C0.0020.0002] # SIGNWRITING HAND-FIST INDEX BENT OVER MIDDLE +1D81E ; [*18C1.0020.0002] # SIGNWRITING HAND-FIST INDEX MIDDLE THUMB +1D81F ; [*18C2.0020.0002] # SIGNWRITING HAND-CIRCLE INDEX MIDDLE THUMB +1D820 ; [*18C3.0020.0002] # SIGNWRITING HAND-FIST INDEX MIDDLE STRAIGHT THUMB BENT +1D821 ; [*18C4.0020.0002] # SIGNWRITING HAND-FIST INDEX MIDDLE BENT THUMB STRAIGHT +1D822 ; [*18C5.0020.0002] # SIGNWRITING HAND-FIST INDEX MIDDLE THUMB BENT +1D823 ; [*18C6.0020.0002] # SIGNWRITING HAND-FIST INDEX MIDDLE HINGED SPREAD THUMB SIDE +1D824 ; [*18C7.0020.0002] # SIGNWRITING HAND-FIST INDEX UP MIDDLE HINGED THUMB SIDE +1D825 ; [*18C8.0020.0002] # SIGNWRITING HAND-FIST INDEX UP MIDDLE HINGED THUMB CONJOINED +1D826 ; [*18C9.0020.0002] # SIGNWRITING HAND-FIST INDEX HINGED MIDDLE UP THUMB SIDE +1D827 ; [*18CA.0020.0002] # SIGNWRITING HAND-FIST INDEX MIDDLE UP SPREAD THUMB FORWARD +1D828 ; [*18CB.0020.0002] # SIGNWRITING HAND-FIST INDEX MIDDLE THUMB CUPPED +1D829 ; [*18CC.0020.0002] # SIGNWRITING HAND-FIST INDEX MIDDLE THUMB CIRCLED +1D82A ; [*18CD.0020.0002] # SIGNWRITING HAND-FIST INDEX MIDDLE THUMB HOOKED +1D82B ; [*18CE.0020.0002] # SIGNWRITING HAND-FIST INDEX MIDDLE THUMB HINGED +1D82C ; [*18CF.0020.0002] # SIGNWRITING HAND-FIST THUMB BETWEEN INDEX MIDDLE STRAIGHT +1D82D ; [*18D0.0020.0002] # SIGNWRITING HAND-FIST INDEX MIDDLE CONJOINED THUMB SIDE +1D82E ; [*18D1.0020.0002] # SIGNWRITING HAND-FIST INDEX MIDDLE CONJOINED THUMB SIDE CONJOINED +1D82F ; [*18D2.0020.0002] # SIGNWRITING HAND-FIST INDEX MIDDLE CONJOINED THUMB SIDE BENT +1D830 ; [*18D3.0020.0002] # SIGNWRITING HAND-FIST MIDDLE THUMB HOOKED INDEX UP +1D831 ; [*18D4.0020.0002] # SIGNWRITING HAND-FIST INDEX THUMB HOOKED MIDDLE UP +1D832 ; [*18D5.0020.0002] # SIGNWRITING HAND-FIST INDEX MIDDLE CONJOINED HINGED THUMB SIDE +1D833 ; [*18D6.0020.0002] # SIGNWRITING HAND-FIST INDEX MIDDLE CROSSED THUMB SIDE +1D834 ; [*18D7.0020.0002] # SIGNWRITING HAND-FIST INDEX MIDDLE CONJOINED THUMB FORWARD +1D835 ; [*18D8.0020.0002] # SIGNWRITING HAND-FIST INDEX MIDDLE CONJOINED CUPPED THUMB FORWARD +1D836 ; [*18D9.0020.0002] # SIGNWRITING HAND-FIST MIDDLE THUMB CUPPED INDEX UP +1D837 ; [*18DA.0020.0002] # SIGNWRITING HAND-FIST INDEX THUMB CUPPED MIDDLE UP +1D838 ; [*18DB.0020.0002] # SIGNWRITING HAND-FIST MIDDLE THUMB CIRCLED INDEX UP +1D839 ; [*18DC.0020.0002] # SIGNWRITING HAND-FIST MIDDLE THUMB CIRCLED INDEX HINGED +1D83A ; [*18DD.0020.0002] # SIGNWRITING HAND-FIST INDEX THUMB ANGLED OUT MIDDLE UP +1D83B ; [*18DE.0020.0002] # SIGNWRITING HAND-FIST INDEX THUMB ANGLED IN MIDDLE UP +1D83C ; [*18DF.0020.0002] # SIGNWRITING HAND-FIST INDEX THUMB CIRCLED MIDDLE UP +1D83D ; [*18E0.0020.0002] # SIGNWRITING HAND-FIST INDEX MIDDLE THUMB CONJOINED HINGED +1D83E ; [*18E1.0020.0002] # SIGNWRITING HAND-FIST INDEX MIDDLE THUMB ANGLED OUT +1D83F ; [*18E2.0020.0002] # SIGNWRITING HAND-FIST INDEX MIDDLE THUMB ANGLED +1D840 ; [*18E3.0020.0002] # SIGNWRITING HAND-FIST MIDDLE THUMB ANGLED OUT INDEX UP +1D841 ; [*18E4.0020.0002] # SIGNWRITING HAND-FIST MIDDLE THUMB ANGLED OUT INDEX CROSSED +1D842 ; [*18E5.0020.0002] # SIGNWRITING HAND-FIST MIDDLE THUMB ANGLED INDEX UP +1D843 ; [*18E6.0020.0002] # SIGNWRITING HAND-FIST INDEX THUMB HOOKED MIDDLE HINGED +1D844 ; [*18E7.0020.0002] # SIGNWRITING HAND-FLAT FOUR FINGERS +1D845 ; [*18E8.0020.0002] # SIGNWRITING HAND-FLAT FOUR FINGERS BENT +1D846 ; [*18E9.0020.0002] # SIGNWRITING HAND-FLAT FOUR FINGERS HINGED +1D847 ; [*18EA.0020.0002] # SIGNWRITING HAND-FLAT FOUR FINGERS CONJOINED +1D848 ; [*18EB.0020.0002] # SIGNWRITING HAND-FLAT FOUR FINGERS CONJOINED SPLIT +1D849 ; [*18EC.0020.0002] # SIGNWRITING HAND-CLAW FOUR FINGERS CONJOINED +1D84A ; [*18ED.0020.0002] # SIGNWRITING HAND-FIST FOUR FINGERS CONJOINED BENT +1D84B ; [*18EE.0020.0002] # SIGNWRITING HAND-HINGE FOUR FINGERS CONJOINED +1D84C ; [*18EF.0020.0002] # SIGNWRITING HAND-FLAT FIVE FINGERS SPREAD +1D84D ; [*18F0.0020.0002] # SIGNWRITING HAND-FLAT HEEL FIVE FINGERS SPREAD +1D84E ; [*18F1.0020.0002] # SIGNWRITING HAND-FLAT FIVE FINGERS SPREAD FOUR BENT +1D84F ; [*18F2.0020.0002] # SIGNWRITING HAND-FLAT HEEL FIVE FINGERS SPREAD FOUR BENT +1D850 ; [*18F3.0020.0002] # SIGNWRITING HAND-FLAT FIVE FINGERS SPREAD BENT +1D851 ; [*18F4.0020.0002] # SIGNWRITING HAND-FLAT HEEL FIVE FINGERS SPREAD BENT +1D852 ; [*18F5.0020.0002] # SIGNWRITING HAND-FLAT FIVE FINGERS SPREAD THUMB FORWARD +1D853 ; [*18F6.0020.0002] # SIGNWRITING HAND-CUP FIVE FINGERS SPREAD +1D854 ; [*18F7.0020.0002] # SIGNWRITING HAND-CUP FIVE FINGERS SPREAD OPEN +1D855 ; [*18F8.0020.0002] # SIGNWRITING HAND-HINGE FIVE FINGERS SPREAD OPEN +1D856 ; [*18F9.0020.0002] # SIGNWRITING HAND-OVAL FIVE FINGERS SPREAD +1D857 ; [*18FA.0020.0002] # SIGNWRITING HAND-FLAT FIVE FINGERS SPREAD HINGED +1D858 ; [*18FB.0020.0002] # SIGNWRITING HAND-FLAT FIVE FINGERS SPREAD HINGED THUMB SIDE +1D859 ; [*18FC.0020.0002] # SIGNWRITING HAND-FLAT FIVE FINGERS SPREAD HINGED NO THUMB +1D85A ; [*18FD.0020.0002] # SIGNWRITING HAND-FLAT +1D85B ; [*18FE.0020.0002] # SIGNWRITING HAND-FLAT BETWEEN PALM FACINGS +1D85C ; [*18FF.0020.0002] # SIGNWRITING HAND-FLAT HEEL +1D85D ; [*1900.0020.0002] # SIGNWRITING HAND-FLAT THUMB SIDE +1D85E ; [*1901.0020.0002] # SIGNWRITING HAND-FLAT HEEL THUMB SIDE +1D85F ; [*1902.0020.0002] # SIGNWRITING HAND-FLAT THUMB BENT +1D860 ; [*1903.0020.0002] # SIGNWRITING HAND-FLAT THUMB FORWARD +1D861 ; [*1904.0020.0002] # SIGNWRITING HAND-FLAT SPLIT INDEX THUMB SIDE +1D862 ; [*1905.0020.0002] # SIGNWRITING HAND-FLAT SPLIT CENTRE +1D863 ; [*1906.0020.0002] # SIGNWRITING HAND-FLAT SPLIT CENTRE THUMB SIDE +1D864 ; [*1907.0020.0002] # SIGNWRITING HAND-FLAT SPLIT CENTRE THUMB SIDE BENT +1D865 ; [*1908.0020.0002] # SIGNWRITING HAND-FLAT SPLIT LITTLE +1D866 ; [*1909.0020.0002] # SIGNWRITING HAND-CLAW +1D867 ; [*190A.0020.0002] # SIGNWRITING HAND-CLAW THUMB SIDE +1D868 ; [*190B.0020.0002] # SIGNWRITING HAND-CLAW NO THUMB +1D869 ; [*190C.0020.0002] # SIGNWRITING HAND-CLAW THUMB FORWARD +1D86A ; [*190D.0020.0002] # SIGNWRITING HAND-HOOK CURLICUE +1D86B ; [*190E.0020.0002] # SIGNWRITING HAND-HOOK +1D86C ; [*190F.0020.0002] # SIGNWRITING HAND-CUP OPEN +1D86D ; [*1910.0020.0002] # SIGNWRITING HAND-CUP +1D86E ; [*1911.0020.0002] # SIGNWRITING HAND-CUP OPEN THUMB SIDE +1D86F ; [*1912.0020.0002] # SIGNWRITING HAND-CUP THUMB SIDE +1D870 ; [*1913.0020.0002] # SIGNWRITING HAND-CUP OPEN NO THUMB +1D871 ; [*1914.0020.0002] # SIGNWRITING HAND-CUP NO THUMB +1D872 ; [*1915.0020.0002] # SIGNWRITING HAND-CUP OPEN THUMB FORWARD +1D873 ; [*1916.0020.0002] # SIGNWRITING HAND-CUP THUMB FORWARD +1D874 ; [*1917.0020.0002] # SIGNWRITING HAND-CURLICUE OPEN +1D875 ; [*1918.0020.0002] # SIGNWRITING HAND-CURLICUE +1D876 ; [*1919.0020.0002] # SIGNWRITING HAND-CIRCLE +1D877 ; [*191A.0020.0002] # SIGNWRITING HAND-OVAL +1D878 ; [*191B.0020.0002] # SIGNWRITING HAND-OVAL THUMB SIDE +1D879 ; [*191C.0020.0002] # SIGNWRITING HAND-OVAL NO THUMB +1D87A ; [*191D.0020.0002] # SIGNWRITING HAND-OVAL THUMB FORWARD +1D87B ; [*191E.0020.0002] # SIGNWRITING HAND-HINGE OPEN +1D87C ; [*191F.0020.0002] # SIGNWRITING HAND-HINGE OPEN THUMB FORWARD +1D87D ; [*1920.0020.0002] # SIGNWRITING HAND-HINGE +1D87E ; [*1921.0020.0002] # SIGNWRITING HAND-HINGE SMALL +1D87F ; [*1922.0020.0002] # SIGNWRITING HAND-HINGE OPEN THUMB SIDE +1D880 ; [*1923.0020.0002] # SIGNWRITING HAND-HINGE THUMB SIDE +1D881 ; [*1924.0020.0002] # SIGNWRITING HAND-HINGE OPEN NO THUMB +1D882 ; [*1925.0020.0002] # SIGNWRITING HAND-HINGE NO THUMB +1D883 ; [*1926.0020.0002] # SIGNWRITING HAND-HINGE THUMB SIDE TOUCHING INDEX +1D884 ; [*1927.0020.0002] # SIGNWRITING HAND-HINGE THUMB BETWEEN MIDDLE RING +1D885 ; [*1928.0020.0002] # SIGNWRITING HAND-ANGLE +1D886 ; [*1929.0020.0002] # SIGNWRITING HAND-FIST INDEX MIDDLE RING +1D887 ; [*192A.0020.0002] # SIGNWRITING HAND-CIRCLE INDEX MIDDLE RING +1D888 ; [*192B.0020.0002] # SIGNWRITING HAND-HINGE INDEX MIDDLE RING +1D889 ; [*192C.0020.0002] # SIGNWRITING HAND-ANGLE INDEX MIDDLE RING +1D88A ; [*192D.0020.0002] # SIGNWRITING HAND-HINGE LITTLE +1D88B ; [*192E.0020.0002] # SIGNWRITING HAND-FIST INDEX MIDDLE RING BENT +1D88C ; [*192F.0020.0002] # SIGNWRITING HAND-FIST INDEX MIDDLE RING CONJOINED +1D88D ; [*1930.0020.0002] # SIGNWRITING HAND-HINGE INDEX MIDDLE RING CONJOINED +1D88E ; [*1931.0020.0002] # SIGNWRITING HAND-FIST LITTLE DOWN +1D88F ; [*1932.0020.0002] # SIGNWRITING HAND-FIST LITTLE DOWN RIPPLE STRAIGHT +1D890 ; [*1933.0020.0002] # SIGNWRITING HAND-FIST LITTLE DOWN RIPPLE CURVED +1D891 ; [*1934.0020.0002] # SIGNWRITING HAND-FIST LITTLE DOWN OTHERS CIRCLED +1D892 ; [*1935.0020.0002] # SIGNWRITING HAND-FIST LITTLE UP +1D893 ; [*1936.0020.0002] # SIGNWRITING HAND-FIST THUMB UNDER LITTLE UP +1D894 ; [*1937.0020.0002] # SIGNWRITING HAND-CIRCLE LITTLE UP +1D895 ; [*1938.0020.0002] # SIGNWRITING HAND-OVAL LITTLE UP +1D896 ; [*1939.0020.0002] # SIGNWRITING HAND-ANGLE LITTLE UP +1D897 ; [*193A.0020.0002] # SIGNWRITING HAND-FIST LITTLE RAISED KNUCKLE +1D898 ; [*193B.0020.0002] # SIGNWRITING HAND-FIST LITTLE BENT +1D899 ; [*193C.0020.0002] # SIGNWRITING HAND-FIST LITTLE TOUCHES THUMB +1D89A ; [*193D.0020.0002] # SIGNWRITING HAND-FIST LITTLE THUMB +1D89B ; [*193E.0020.0002] # SIGNWRITING HAND-HINGE LITTLE THUMB +1D89C ; [*193F.0020.0002] # SIGNWRITING HAND-FIST LITTLE INDEX THUMB +1D89D ; [*1940.0020.0002] # SIGNWRITING HAND-HINGE LITTLE INDEX THUMB +1D89E ; [*1941.0020.0002] # SIGNWRITING HAND-ANGLE LITTLE INDEX THUMB INDEX THUMB OUT +1D89F ; [*1942.0020.0002] # SIGNWRITING HAND-ANGLE LITTLE INDEX THUMB INDEX THUMB +1D8A0 ; [*1943.0020.0002] # SIGNWRITING HAND-FIST LITTLE INDEX +1D8A1 ; [*1944.0020.0002] # SIGNWRITING HAND-CIRCLE LITTLE INDEX +1D8A2 ; [*1945.0020.0002] # SIGNWRITING HAND-HINGE LITTLE INDEX +1D8A3 ; [*1946.0020.0002] # SIGNWRITING HAND-ANGLE LITTLE INDEX +1D8A4 ; [*1947.0020.0002] # SIGNWRITING HAND-FIST INDEX MIDDLE LITTLE +1D8A5 ; [*1948.0020.0002] # SIGNWRITING HAND-CIRCLE INDEX MIDDLE LITTLE +1D8A6 ; [*1949.0020.0002] # SIGNWRITING HAND-HINGE INDEX MIDDLE LITTLE +1D8A7 ; [*194A.0020.0002] # SIGNWRITING HAND-HINGE RING +1D8A8 ; [*194B.0020.0002] # SIGNWRITING HAND-ANGLE INDEX MIDDLE LITTLE +1D8A9 ; [*194C.0020.0002] # SIGNWRITING HAND-FIST INDEX MIDDLE CROSS LITTLE +1D8AA ; [*194D.0020.0002] # SIGNWRITING HAND-CIRCLE INDEX MIDDLE CROSS LITTLE +1D8AB ; [*194E.0020.0002] # SIGNWRITING HAND-FIST RING DOWN +1D8AC ; [*194F.0020.0002] # SIGNWRITING HAND-HINGE RING DOWN INDEX THUMB HOOK MIDDLE +1D8AD ; [*1950.0020.0002] # SIGNWRITING HAND-ANGLE RING DOWN MIDDLE THUMB INDEX CROSS +1D8AE ; [*1951.0020.0002] # SIGNWRITING HAND-FIST RING UP +1D8AF ; [*1952.0020.0002] # SIGNWRITING HAND-FIST RING RAISED KNUCKLE +1D8B0 ; [*1953.0020.0002] # SIGNWRITING HAND-FIST RING LITTLE +1D8B1 ; [*1954.0020.0002] # SIGNWRITING HAND-CIRCLE RING LITTLE +1D8B2 ; [*1955.0020.0002] # SIGNWRITING HAND-OVAL RING LITTLE +1D8B3 ; [*1956.0020.0002] # SIGNWRITING HAND-ANGLE RING LITTLE +1D8B4 ; [*1957.0020.0002] # SIGNWRITING HAND-FIST RING MIDDLE +1D8B5 ; [*1958.0020.0002] # SIGNWRITING HAND-FIST RING MIDDLE CONJOINED +1D8B6 ; [*1959.0020.0002] # SIGNWRITING HAND-FIST RING MIDDLE RAISED KNUCKLES +1D8B7 ; [*195A.0020.0002] # SIGNWRITING HAND-FIST RING INDEX +1D8B8 ; [*195B.0020.0002] # SIGNWRITING HAND-FIST RING THUMB +1D8B9 ; [*195C.0020.0002] # SIGNWRITING HAND-HOOK RING THUMB +1D8BA ; [*195D.0020.0002] # SIGNWRITING HAND-FIST INDEX RING LITTLE +1D8BB ; [*195E.0020.0002] # SIGNWRITING HAND-CIRCLE INDEX RING LITTLE +1D8BC ; [*195F.0020.0002] # SIGNWRITING HAND-CURLICUE INDEX RING LITTLE ON +1D8BD ; [*1960.0020.0002] # SIGNWRITING HAND-HOOK INDEX RING LITTLE OUT +1D8BE ; [*1961.0020.0002] # SIGNWRITING HAND-HOOK INDEX RING LITTLE IN +1D8BF ; [*1962.0020.0002] # SIGNWRITING HAND-HOOK INDEX RING LITTLE UNDER +1D8C0 ; [*1963.0020.0002] # SIGNWRITING HAND-CUP INDEX RING LITTLE +1D8C1 ; [*1964.0020.0002] # SIGNWRITING HAND-HINGE INDEX RING LITTLE +1D8C2 ; [*1965.0020.0002] # SIGNWRITING HAND-ANGLE INDEX RING LITTLE OUT +1D8C3 ; [*1966.0020.0002] # SIGNWRITING HAND-ANGLE INDEX RING LITTLE +1D8C4 ; [*1967.0020.0002] # SIGNWRITING HAND-FIST MIDDLE DOWN +1D8C5 ; [*1968.0020.0002] # SIGNWRITING HAND-HINGE MIDDLE +1D8C6 ; [*1969.0020.0002] # SIGNWRITING HAND-FIST MIDDLE UP +1D8C7 ; [*196A.0020.0002] # SIGNWRITING HAND-CIRCLE MIDDLE UP +1D8C8 ; [*196B.0020.0002] # SIGNWRITING HAND-FIST MIDDLE RAISED KNUCKLE +1D8C9 ; [*196C.0020.0002] # SIGNWRITING HAND-FIST MIDDLE UP THUMB SIDE +1D8CA ; [*196D.0020.0002] # SIGNWRITING HAND-HOOK MIDDLE THUMB +1D8CB ; [*196E.0020.0002] # SIGNWRITING HAND-FIST MIDDLE THUMB LITTLE +1D8CC ; [*196F.0020.0002] # SIGNWRITING HAND-FIST MIDDLE LITTLE +1D8CD ; [*1970.0020.0002] # SIGNWRITING HAND-FIST MIDDLE RING LITTLE +1D8CE ; [*1971.0020.0002] # SIGNWRITING HAND-CIRCLE MIDDLE RING LITTLE +1D8CF ; [*1972.0020.0002] # SIGNWRITING HAND-CURLICUE MIDDLE RING LITTLE ON +1D8D0 ; [*1973.0020.0002] # SIGNWRITING HAND-CUP MIDDLE RING LITTLE +1D8D1 ; [*1974.0020.0002] # SIGNWRITING HAND-HINGE MIDDLE RING LITTLE +1D8D2 ; [*1975.0020.0002] # SIGNWRITING HAND-ANGLE MIDDLE RING LITTLE OUT +1D8D3 ; [*1976.0020.0002] # SIGNWRITING HAND-ANGLE MIDDLE RING LITTLE IN +1D8D4 ; [*1977.0020.0002] # SIGNWRITING HAND-ANGLE MIDDLE RING LITTLE +1D8D5 ; [*1978.0020.0002] # SIGNWRITING HAND-CIRCLE MIDDLE RING LITTLE BENT +1D8D6 ; [*1979.0020.0002] # SIGNWRITING HAND-CLAW MIDDLE RING LITTLE CONJOINED +1D8D7 ; [*197A.0020.0002] # SIGNWRITING HAND-CLAW MIDDLE RING LITTLE CONJOINED SIDE +1D8D8 ; [*197B.0020.0002] # SIGNWRITING HAND-HOOK MIDDLE RING LITTLE CONJOINED OUT +1D8D9 ; [*197C.0020.0002] # SIGNWRITING HAND-HOOK MIDDLE RING LITTLE CONJOINED IN +1D8DA ; [*197D.0020.0002] # SIGNWRITING HAND-HOOK MIDDLE RING LITTLE CONJOINED +1D8DB ; [*197E.0020.0002] # SIGNWRITING HAND-HINGE INDEX HINGED +1D8DC ; [*197F.0020.0002] # SIGNWRITING HAND-FIST INDEX THUMB SIDE +1D8DD ; [*1980.0020.0002] # SIGNWRITING HAND-HINGE INDEX THUMB SIDE +1D8DE ; [*1981.0020.0002] # SIGNWRITING HAND-FIST INDEX THUMB SIDE THUMB DIAGONAL +1D8DF ; [*1982.0020.0002] # SIGNWRITING HAND-FIST INDEX THUMB SIDE THUMB CONJOINED +1D8E0 ; [*1983.0020.0002] # SIGNWRITING HAND-FIST INDEX THUMB SIDE THUMB BENT +1D8E1 ; [*1984.0020.0002] # SIGNWRITING HAND-FIST INDEX THUMB SIDE INDEX BENT +1D8E2 ; [*1985.0020.0002] # SIGNWRITING HAND-FIST INDEX THUMB SIDE BOTH BENT +1D8E3 ; [*1986.0020.0002] # SIGNWRITING HAND-FIST INDEX THUMB SIDE INDEX HINGE +1D8E4 ; [*1987.0020.0002] # SIGNWRITING HAND-FIST INDEX THUMB FORWARD INDEX STRAIGHT +1D8E5 ; [*1988.0020.0002] # SIGNWRITING HAND-FIST INDEX THUMB FORWARD INDEX BENT +1D8E6 ; [*1989.0020.0002] # SIGNWRITING HAND-FIST INDEX THUMB HOOK +1D8E7 ; [*198A.0020.0002] # SIGNWRITING HAND-FIST INDEX THUMB CURLICUE +1D8E8 ; [*198B.0020.0002] # SIGNWRITING HAND-FIST INDEX THUMB CURVE THUMB INSIDE +1D8E9 ; [*198C.0020.0002] # SIGNWRITING HAND-CLAW INDEX THUMB CURVE THUMB INSIDE +1D8EA ; [*198D.0020.0002] # SIGNWRITING HAND-FIST INDEX THUMB CURVE THUMB UNDER +1D8EB ; [*198E.0020.0002] # SIGNWRITING HAND-FIST INDEX THUMB CIRCLE +1D8EC ; [*198F.0020.0002] # SIGNWRITING HAND-CUP INDEX THUMB +1D8ED ; [*1990.0020.0002] # SIGNWRITING HAND-CUP INDEX THUMB OPEN +1D8EE ; [*1991.0020.0002] # SIGNWRITING HAND-HINGE INDEX THUMB OPEN +1D8EF ; [*1992.0020.0002] # SIGNWRITING HAND-HINGE INDEX THUMB LARGE +1D8F0 ; [*1993.0020.0002] # SIGNWRITING HAND-HINGE INDEX THUMB +1D8F1 ; [*1994.0020.0002] # SIGNWRITING HAND-HINGE INDEX THUMB SMALL +1D8F2 ; [*1995.0020.0002] # SIGNWRITING HAND-ANGLE INDEX THUMB OUT +1D8F3 ; [*1996.0020.0002] # SIGNWRITING HAND-ANGLE INDEX THUMB IN +1D8F4 ; [*1997.0020.0002] # SIGNWRITING HAND-ANGLE INDEX THUMB +1D8F5 ; [*1998.0020.0002] # SIGNWRITING HAND-FIST THUMB +1D8F6 ; [*1999.0020.0002] # SIGNWRITING HAND-FIST THUMB HEEL +1D8F7 ; [*199A.0020.0002] # SIGNWRITING HAND-FIST THUMB SIDE DIAGONAL +1D8F8 ; [*199B.0020.0002] # SIGNWRITING HAND-FIST THUMB SIDE CONJOINED +1D8F9 ; [*199C.0020.0002] # SIGNWRITING HAND-FIST THUMB SIDE BENT +1D8FA ; [*199D.0020.0002] # SIGNWRITING HAND-FIST THUMB FORWARD +1D8FB ; [*199E.0020.0002] # SIGNWRITING HAND-FIST THUMB BETWEEN INDEX MIDDLE +1D8FC ; [*199F.0020.0002] # SIGNWRITING HAND-FIST THUMB BETWEEN MIDDLE RING +1D8FD ; [*19A0.0020.0002] # SIGNWRITING HAND-FIST THUMB BETWEEN RING LITTLE +1D8FE ; [*19A1.0020.0002] # SIGNWRITING HAND-FIST THUMB UNDER TWO FINGERS +1D8FF ; [*19A2.0020.0002] # SIGNWRITING HAND-FIST THUMB OVER TWO FINGERS +1D900 ; [*19A3.0020.0002] # SIGNWRITING HAND-FIST THUMB UNDER THREE FINGERS +1D901 ; [*19A4.0020.0002] # SIGNWRITING HAND-FIST THUMB UNDER FOUR FINGERS +1D902 ; [*19A5.0020.0002] # SIGNWRITING HAND-FIST THUMB OVER FOUR RAISED KNUCKLES +1D903 ; [*19A6.0020.0002] # SIGNWRITING HAND-FIST +1D904 ; [*19A7.0020.0002] # SIGNWRITING HAND-FIST HEEL +1D905 ; [*19A8.0020.0002] # SIGNWRITING TOUCH SINGLE +1D906 ; [*19A9.0020.0002] # SIGNWRITING TOUCH MULTIPLE +1D907 ; [*19AA.0020.0002] # SIGNWRITING TOUCH BETWEEN +1D908 ; [*19AB.0020.0002] # SIGNWRITING GRASP SINGLE +1D909 ; [*19AC.0020.0002] # SIGNWRITING GRASP MULTIPLE +1D90A ; [*19AD.0020.0002] # SIGNWRITING GRASP BETWEEN +1D90B ; [*19AE.0020.0002] # SIGNWRITING STRIKE SINGLE +1D90C ; [*19AF.0020.0002] # SIGNWRITING STRIKE MULTIPLE +1D90D ; [*19B0.0020.0002] # SIGNWRITING STRIKE BETWEEN +1D90E ; [*19B1.0020.0002] # SIGNWRITING BRUSH SINGLE +1D90F ; [*19B2.0020.0002] # SIGNWRITING BRUSH MULTIPLE +1D910 ; [*19B3.0020.0002] # SIGNWRITING BRUSH BETWEEN +1D911 ; [*19B4.0020.0002] # SIGNWRITING RUB SINGLE +1D912 ; [*19B5.0020.0002] # SIGNWRITING RUB MULTIPLE +1D913 ; [*19B6.0020.0002] # SIGNWRITING RUB BETWEEN +1D914 ; [*19B7.0020.0002] # SIGNWRITING SURFACE SYMBOLS +1D915 ; [*19B8.0020.0002] # SIGNWRITING SURFACE BETWEEN +1D916 ; [*19B9.0020.0002] # SIGNWRITING SQUEEZE LARGE SINGLE +1D917 ; [*19BA.0020.0002] # SIGNWRITING SQUEEZE SMALL SINGLE +1D918 ; [*19BB.0020.0002] # SIGNWRITING SQUEEZE LARGE MULTIPLE +1D919 ; [*19BC.0020.0002] # SIGNWRITING SQUEEZE SMALL MULTIPLE +1D91A ; [*19BD.0020.0002] # SIGNWRITING SQUEEZE SEQUENTIAL +1D91B ; [*19BE.0020.0002] # SIGNWRITING FLICK LARGE SINGLE +1D91C ; [*19BF.0020.0002] # SIGNWRITING FLICK SMALL SINGLE +1D91D ; [*19C0.0020.0002] # SIGNWRITING FLICK LARGE MULTIPLE +1D91E ; [*19C1.0020.0002] # SIGNWRITING FLICK SMALL MULTIPLE +1D91F ; [*19C2.0020.0002] # SIGNWRITING FLICK SEQUENTIAL +1D920 ; [*19C3.0020.0002] # SIGNWRITING SQUEEZE FLICK ALTERNATING +1D921 ; [*19C4.0020.0002] # SIGNWRITING MOVEMENT-HINGE UP DOWN LARGE +1D922 ; [*19C5.0020.0002] # SIGNWRITING MOVEMENT-HINGE UP DOWN SMALL +1D923 ; [*19C6.0020.0002] # SIGNWRITING MOVEMENT-HINGE UP SEQUENTIAL +1D924 ; [*19C7.0020.0002] # SIGNWRITING MOVEMENT-HINGE DOWN SEQUENTIAL +1D925 ; [*19C8.0020.0002] # SIGNWRITING MOVEMENT-HINGE UP DOWN ALTERNATING LARGE +1D926 ; [*19C9.0020.0002] # SIGNWRITING MOVEMENT-HINGE UP DOWN ALTERNATING SMALL +1D927 ; [*19CA.0020.0002] # SIGNWRITING MOVEMENT-HINGE SIDE TO SIDE SCISSORS +1D928 ; [*19CB.0020.0002] # SIGNWRITING MOVEMENT-WALLPLANE FINGER CONTACT +1D929 ; [*19CC.0020.0002] # SIGNWRITING MOVEMENT-FLOORPLANE FINGER CONTACT +1D92A ; [*19CD.0020.0002] # SIGNWRITING MOVEMENT-WALLPLANE SINGLE STRAIGHT SMALL +1D92B ; [*19CE.0020.0002] # SIGNWRITING MOVEMENT-WALLPLANE SINGLE STRAIGHT MEDIUM +1D92C ; [*19CF.0020.0002] # SIGNWRITING MOVEMENT-WALLPLANE SINGLE STRAIGHT LARGE +1D92D ; [*19D0.0020.0002] # SIGNWRITING MOVEMENT-WALLPLANE SINGLE STRAIGHT LARGEST +1D92E ; [*19D1.0020.0002] # SIGNWRITING MOVEMENT-WALLPLANE SINGLE WRIST FLEX +1D92F ; [*19D2.0020.0002] # SIGNWRITING MOVEMENT-WALLPLANE DOUBLE STRAIGHT +1D930 ; [*19D3.0020.0002] # SIGNWRITING MOVEMENT-WALLPLANE DOUBLE WRIST FLEX +1D931 ; [*19D4.0020.0002] # SIGNWRITING MOVEMENT-WALLPLANE DOUBLE ALTERNATING +1D932 ; [*19D5.0020.0002] # SIGNWRITING MOVEMENT-WALLPLANE DOUBLE ALTERNATING WRIST FLEX +1D933 ; [*19D6.0020.0002] # SIGNWRITING MOVEMENT-WALLPLANE CROSS +1D934 ; [*19D7.0020.0002] # SIGNWRITING MOVEMENT-WALLPLANE TRIPLE STRAIGHT MOVEMENT +1D935 ; [*19D8.0020.0002] # SIGNWRITING MOVEMENT-WALLPLANE TRIPLE WRIST FLEX +1D936 ; [*19D9.0020.0002] # SIGNWRITING MOVEMENT-WALLPLANE TRIPLE ALTERNATING +1D937 ; [*19DA.0020.0002] # SIGNWRITING MOVEMENT-WALLPLANE TRIPLE ALTERNATING WRIST FLEX +1D938 ; [*19DB.0020.0002] # SIGNWRITING MOVEMENT-WALLPLANE BEND SMALL +1D939 ; [*19DC.0020.0002] # SIGNWRITING MOVEMENT-WALLPLANE BEND MEDIUM +1D93A ; [*19DD.0020.0002] # SIGNWRITING MOVEMENT-WALLPLANE BEND LARGE +1D93B ; [*19DE.0020.0002] # SIGNWRITING MOVEMENT-WALLPLANE CORNER SMALL +1D93C ; [*19DF.0020.0002] # SIGNWRITING MOVEMENT-WALLPLANE CORNER MEDIUM +1D93D ; [*19E0.0020.0002] # SIGNWRITING MOVEMENT-WALLPLANE CORNER LARGE +1D93E ; [*19E1.0020.0002] # SIGNWRITING MOVEMENT-WALLPLANE CORNER ROTATION +1D93F ; [*19E2.0020.0002] # SIGNWRITING MOVEMENT-WALLPLANE CHECK SMALL +1D940 ; [*19E3.0020.0002] # SIGNWRITING MOVEMENT-WALLPLANE CHECK MEDIUM +1D941 ; [*19E4.0020.0002] # SIGNWRITING MOVEMENT-WALLPLANE CHECK LARGE +1D942 ; [*19E5.0020.0002] # SIGNWRITING MOVEMENT-WALLPLANE BOX SMALL +1D943 ; [*19E6.0020.0002] # SIGNWRITING MOVEMENT-WALLPLANE BOX MEDIUM +1D944 ; [*19E7.0020.0002] # SIGNWRITING MOVEMENT-WALLPLANE BOX LARGE +1D945 ; [*19E8.0020.0002] # SIGNWRITING MOVEMENT-WALLPLANE ZIGZAG SMALL +1D946 ; [*19E9.0020.0002] # SIGNWRITING MOVEMENT-WALLPLANE ZIGZAG MEDIUM +1D947 ; [*19EA.0020.0002] # SIGNWRITING MOVEMENT-WALLPLANE ZIGZAG LARGE +1D948 ; [*19EB.0020.0002] # SIGNWRITING MOVEMENT-WALLPLANE PEAKS SMALL +1D949 ; [*19EC.0020.0002] # SIGNWRITING MOVEMENT-WALLPLANE PEAKS MEDIUM +1D94A ; [*19ED.0020.0002] # SIGNWRITING MOVEMENT-WALLPLANE PEAKS LARGE +1D94B ; [*19EE.0020.0002] # SIGNWRITING TRAVEL-WALLPLANE ROTATION-WALLPLANE SINGLE +1D94C ; [*19EF.0020.0002] # SIGNWRITING TRAVEL-WALLPLANE ROTATION-WALLPLANE DOUBLE +1D94D ; [*19F0.0020.0002] # SIGNWRITING TRAVEL-WALLPLANE ROTATION-WALLPLANE ALTERNATING +1D94E ; [*19F1.0020.0002] # SIGNWRITING TRAVEL-WALLPLANE ROTATION-FLOORPLANE SINGLE +1D94F ; [*19F2.0020.0002] # SIGNWRITING TRAVEL-WALLPLANE ROTATION-FLOORPLANE DOUBLE +1D950 ; [*19F3.0020.0002] # SIGNWRITING TRAVEL-WALLPLANE ROTATION-FLOORPLANE ALTERNATING +1D951 ; [*19F4.0020.0002] # SIGNWRITING TRAVEL-WALLPLANE SHAKING +1D952 ; [*19F5.0020.0002] # SIGNWRITING TRAVEL-WALLPLANE ARM SPIRAL SINGLE +1D953 ; [*19F6.0020.0002] # SIGNWRITING TRAVEL-WALLPLANE ARM SPIRAL DOUBLE +1D954 ; [*19F7.0020.0002] # SIGNWRITING TRAVEL-WALLPLANE ARM SPIRAL TRIPLE +1D955 ; [*19F8.0020.0002] # SIGNWRITING MOVEMENT-DIAGONAL AWAY SMALL +1D956 ; [*19F9.0020.0002] # SIGNWRITING MOVEMENT-DIAGONAL AWAY MEDIUM +1D957 ; [*19FA.0020.0002] # SIGNWRITING MOVEMENT-DIAGONAL AWAY LARGE +1D958 ; [*19FB.0020.0002] # SIGNWRITING MOVEMENT-DIAGONAL AWAY LARGEST +1D959 ; [*19FC.0020.0002] # SIGNWRITING MOVEMENT-DIAGONAL TOWARDS SMALL +1D95A ; [*19FD.0020.0002] # SIGNWRITING MOVEMENT-DIAGONAL TOWARDS MEDIUM +1D95B ; [*19FE.0020.0002] # SIGNWRITING MOVEMENT-DIAGONAL TOWARDS LARGE +1D95C ; [*19FF.0020.0002] # SIGNWRITING MOVEMENT-DIAGONAL TOWARDS LARGEST +1D95D ; [*1A00.0020.0002] # SIGNWRITING MOVEMENT-DIAGONAL BETWEEN AWAY SMALL +1D95E ; [*1A01.0020.0002] # SIGNWRITING MOVEMENT-DIAGONAL BETWEEN AWAY MEDIUM +1D95F ; [*1A02.0020.0002] # SIGNWRITING MOVEMENT-DIAGONAL BETWEEN AWAY LARGE +1D960 ; [*1A03.0020.0002] # SIGNWRITING MOVEMENT-DIAGONAL BETWEEN AWAY LARGEST +1D961 ; [*1A04.0020.0002] # SIGNWRITING MOVEMENT-DIAGONAL BETWEEN TOWARDS SMALL +1D962 ; [*1A05.0020.0002] # SIGNWRITING MOVEMENT-DIAGONAL BETWEEN TOWARDS MEDIUM +1D963 ; [*1A06.0020.0002] # SIGNWRITING MOVEMENT-DIAGONAL BETWEEN TOWARDS LARGE +1D964 ; [*1A07.0020.0002] # SIGNWRITING MOVEMENT-DIAGONAL BETWEEN TOWARDS LARGEST +1D965 ; [*1A08.0020.0002] # SIGNWRITING MOVEMENT-FLOORPLANE SINGLE STRAIGHT SMALL +1D966 ; [*1A09.0020.0002] # SIGNWRITING MOVEMENT-FLOORPLANE SINGLE STRAIGHT MEDIUM +1D967 ; [*1A0A.0020.0002] # SIGNWRITING MOVEMENT-FLOORPLANE SINGLE STRAIGHT LARGE +1D968 ; [*1A0B.0020.0002] # SIGNWRITING MOVEMENT-FLOORPLANE SINGLE STRAIGHT LARGEST +1D969 ; [*1A0C.0020.0002] # SIGNWRITING MOVEMENT-FLOORPLANE SINGLE WRIST FLEX +1D96A ; [*1A0D.0020.0002] # SIGNWRITING MOVEMENT-FLOORPLANE DOUBLE STRAIGHT +1D96B ; [*1A0E.0020.0002] # SIGNWRITING MOVEMENT-FLOORPLANE DOUBLE WRIST FLEX +1D96C ; [*1A0F.0020.0002] # SIGNWRITING MOVEMENT-FLOORPLANE DOUBLE ALTERNATING +1D96D ; [*1A10.0020.0002] # SIGNWRITING MOVEMENT-FLOORPLANE DOUBLE ALTERNATING WRIST FLEX +1D96E ; [*1A11.0020.0002] # SIGNWRITING MOVEMENT-FLOORPLANE CROSS +1D96F ; [*1A12.0020.0002] # SIGNWRITING MOVEMENT-FLOORPLANE TRIPLE STRAIGHT MOVEMENT +1D970 ; [*1A13.0020.0002] # SIGNWRITING MOVEMENT-FLOORPLANE TRIPLE WRIST FLEX +1D971 ; [*1A14.0020.0002] # SIGNWRITING MOVEMENT-FLOORPLANE TRIPLE ALTERNATING MOVEMENT +1D972 ; [*1A15.0020.0002] # SIGNWRITING MOVEMENT-FLOORPLANE TRIPLE ALTERNATING WRIST FLEX +1D973 ; [*1A16.0020.0002] # SIGNWRITING MOVEMENT-FLOORPLANE BEND +1D974 ; [*1A17.0020.0002] # SIGNWRITING MOVEMENT-FLOORPLANE CORNER SMALL +1D975 ; [*1A18.0020.0002] # SIGNWRITING MOVEMENT-FLOORPLANE CORNER MEDIUM +1D976 ; [*1A19.0020.0002] # SIGNWRITING MOVEMENT-FLOORPLANE CORNER LARGE +1D977 ; [*1A1A.0020.0002] # SIGNWRITING MOVEMENT-FLOORPLANE CHECK +1D978 ; [*1A1B.0020.0002] # SIGNWRITING MOVEMENT-FLOORPLANE BOX SMALL +1D979 ; [*1A1C.0020.0002] # SIGNWRITING MOVEMENT-FLOORPLANE BOX MEDIUM +1D97A ; [*1A1D.0020.0002] # SIGNWRITING MOVEMENT-FLOORPLANE BOX LARGE +1D97B ; [*1A1E.0020.0002] # SIGNWRITING MOVEMENT-FLOORPLANE ZIGZAG SMALL +1D97C ; [*1A1F.0020.0002] # SIGNWRITING MOVEMENT-FLOORPLANE ZIGZAG MEDIUM +1D97D ; [*1A20.0020.0002] # SIGNWRITING MOVEMENT-FLOORPLANE ZIGZAG LARGE +1D97E ; [*1A21.0020.0002] # SIGNWRITING MOVEMENT-FLOORPLANE PEAKS SMALL +1D97F ; [*1A22.0020.0002] # SIGNWRITING MOVEMENT-FLOORPLANE PEAKS MEDIUM +1D980 ; [*1A23.0020.0002] # SIGNWRITING MOVEMENT-FLOORPLANE PEAKS LARGE +1D981 ; [*1A24.0020.0002] # SIGNWRITING TRAVEL-FLOORPLANE ROTATION-FLOORPLANE SINGLE +1D982 ; [*1A25.0020.0002] # SIGNWRITING TRAVEL-FLOORPLANE ROTATION-FLOORPLANE DOUBLE +1D983 ; [*1A26.0020.0002] # SIGNWRITING TRAVEL-FLOORPLANE ROTATION-FLOORPLANE ALTERNATING +1D984 ; [*1A27.0020.0002] # SIGNWRITING TRAVEL-FLOORPLANE ROTATION-WALLPLANE SINGLE +1D985 ; [*1A28.0020.0002] # SIGNWRITING TRAVEL-FLOORPLANE ROTATION-WALLPLANE DOUBLE +1D986 ; [*1A29.0020.0002] # SIGNWRITING TRAVEL-FLOORPLANE ROTATION-WALLPLANE ALTERNATING +1D987 ; [*1A2A.0020.0002] # SIGNWRITING TRAVEL-FLOORPLANE SHAKING +1D988 ; [*1A2B.0020.0002] # SIGNWRITING MOVEMENT-WALLPLANE CURVE QUARTER SMALL +1D989 ; [*1A2C.0020.0002] # SIGNWRITING MOVEMENT-WALLPLANE CURVE QUARTER MEDIUM +1D98A ; [*1A2D.0020.0002] # SIGNWRITING MOVEMENT-WALLPLANE CURVE QUARTER LARGE +1D98B ; [*1A2E.0020.0002] # SIGNWRITING MOVEMENT-WALLPLANE CURVE QUARTER LARGEST +1D98C ; [*1A2F.0020.0002] # SIGNWRITING MOVEMENT-WALLPLANE CURVE HALF-CIRCLE SMALL +1D98D ; [*1A30.0020.0002] # SIGNWRITING MOVEMENT-WALLPLANE CURVE HALF-CIRCLE MEDIUM +1D98E ; [*1A31.0020.0002] # SIGNWRITING MOVEMENT-WALLPLANE CURVE HALF-CIRCLE LARGE +1D98F ; [*1A32.0020.0002] # SIGNWRITING MOVEMENT-WALLPLANE CURVE HALF-CIRCLE LARGEST +1D990 ; [*1A33.0020.0002] # SIGNWRITING MOVEMENT-WALLPLANE CURVE THREE-QUARTER CIRCLE SMALL +1D991 ; [*1A34.0020.0002] # SIGNWRITING MOVEMENT-WALLPLANE CURVE THREE-QUARTER CIRCLE MEDIUM +1D992 ; [*1A35.0020.0002] # SIGNWRITING MOVEMENT-WALLPLANE HUMP SMALL +1D993 ; [*1A36.0020.0002] # SIGNWRITING MOVEMENT-WALLPLANE HUMP MEDIUM +1D994 ; [*1A37.0020.0002] # SIGNWRITING MOVEMENT-WALLPLANE HUMP LARGE +1D995 ; [*1A38.0020.0002] # SIGNWRITING MOVEMENT-WALLPLANE LOOP SMALL +1D996 ; [*1A39.0020.0002] # SIGNWRITING MOVEMENT-WALLPLANE LOOP MEDIUM +1D997 ; [*1A3A.0020.0002] # SIGNWRITING MOVEMENT-WALLPLANE LOOP LARGE +1D998 ; [*1A3B.0020.0002] # SIGNWRITING MOVEMENT-WALLPLANE LOOP SMALL DOUBLE +1D999 ; [*1A3C.0020.0002] # SIGNWRITING MOVEMENT-WALLPLANE WAVE CURVE DOUBLE SMALL +1D99A ; [*1A3D.0020.0002] # SIGNWRITING MOVEMENT-WALLPLANE WAVE CURVE DOUBLE MEDIUM +1D99B ; [*1A3E.0020.0002] # SIGNWRITING MOVEMENT-WALLPLANE WAVE CURVE DOUBLE LARGE +1D99C ; [*1A3F.0020.0002] # SIGNWRITING MOVEMENT-WALLPLANE WAVE CURVE TRIPLE SMALL +1D99D ; [*1A40.0020.0002] # SIGNWRITING MOVEMENT-WALLPLANE WAVE CURVE TRIPLE MEDIUM +1D99E ; [*1A41.0020.0002] # SIGNWRITING MOVEMENT-WALLPLANE WAVE CURVE TRIPLE LARGE +1D99F ; [*1A42.0020.0002] # SIGNWRITING MOVEMENT-WALLPLANE CURVE THEN STRAIGHT +1D9A0 ; [*1A43.0020.0002] # SIGNWRITING MOVEMENT-WALLPLANE CURVED CROSS SMALL +1D9A1 ; [*1A44.0020.0002] # SIGNWRITING MOVEMENT-WALLPLANE CURVED CROSS MEDIUM +1D9A2 ; [*1A45.0020.0002] # SIGNWRITING ROTATION-WALLPLANE SINGLE +1D9A3 ; [*1A46.0020.0002] # SIGNWRITING ROTATION-WALLPLANE DOUBLE +1D9A4 ; [*1A47.0020.0002] # SIGNWRITING ROTATION-WALLPLANE ALTERNATE +1D9A5 ; [*1A48.0020.0002] # SIGNWRITING MOVEMENT-WALLPLANE SHAKING +1D9A6 ; [*1A49.0020.0002] # SIGNWRITING MOVEMENT-WALLPLANE CURVE HITTING FRONT WALL +1D9A7 ; [*1A4A.0020.0002] # SIGNWRITING MOVEMENT-WALLPLANE HUMP HITTING FRONT WALL +1D9A8 ; [*1A4B.0020.0002] # SIGNWRITING MOVEMENT-WALLPLANE LOOP HITTING FRONT WALL +1D9A9 ; [*1A4C.0020.0002] # SIGNWRITING MOVEMENT-WALLPLANE WAVE HITTING FRONT WALL +1D9AA ; [*1A4D.0020.0002] # SIGNWRITING ROTATION-WALLPLANE SINGLE HITTING FRONT WALL +1D9AB ; [*1A4E.0020.0002] # SIGNWRITING ROTATION-WALLPLANE DOUBLE HITTING FRONT WALL +1D9AC ; [*1A4F.0020.0002] # SIGNWRITING ROTATION-WALLPLANE ALTERNATING HITTING FRONT WALL +1D9AD ; [*1A50.0020.0002] # SIGNWRITING MOVEMENT-WALLPLANE CURVE HITTING CHEST +1D9AE ; [*1A51.0020.0002] # SIGNWRITING MOVEMENT-WALLPLANE HUMP HITTING CHEST +1D9AF ; [*1A52.0020.0002] # SIGNWRITING MOVEMENT-WALLPLANE LOOP HITTING CHEST +1D9B0 ; [*1A53.0020.0002] # SIGNWRITING MOVEMENT-WALLPLANE WAVE HITTING CHEST +1D9B1 ; [*1A54.0020.0002] # SIGNWRITING ROTATION-WALLPLANE SINGLE HITTING CHEST +1D9B2 ; [*1A55.0020.0002] # SIGNWRITING ROTATION-WALLPLANE DOUBLE HITTING CHEST +1D9B3 ; [*1A56.0020.0002] # SIGNWRITING ROTATION-WALLPLANE ALTERNATING HITTING CHEST +1D9B4 ; [*1A57.0020.0002] # SIGNWRITING MOVEMENT-WALLPLANE WAVE DIAGONAL PATH SMALL +1D9B5 ; [*1A58.0020.0002] # SIGNWRITING MOVEMENT-WALLPLANE WAVE DIAGONAL PATH MEDIUM +1D9B6 ; [*1A59.0020.0002] # SIGNWRITING MOVEMENT-WALLPLANE WAVE DIAGONAL PATH LARGE +1D9B7 ; [*1A5A.0020.0002] # SIGNWRITING MOVEMENT-FLOORPLANE CURVE HITTING CEILING SMALL +1D9B8 ; [*1A5B.0020.0002] # SIGNWRITING MOVEMENT-FLOORPLANE CURVE HITTING CEILING LARGE +1D9B9 ; [*1A5C.0020.0002] # SIGNWRITING MOVEMENT-FLOORPLANE HUMP HITTING CEILING SMALL DOUBLE +1D9BA ; [*1A5D.0020.0002] # SIGNWRITING MOVEMENT-FLOORPLANE HUMP HITTING CEILING LARGE DOUBLE +1D9BB ; [*1A5E.0020.0002] # SIGNWRITING MOVEMENT-FLOORPLANE HUMP HITTING CEILING SMALL TRIPLE +1D9BC ; [*1A5F.0020.0002] # SIGNWRITING MOVEMENT-FLOORPLANE HUMP HITTING CEILING LARGE TRIPLE +1D9BD ; [*1A60.0020.0002] # SIGNWRITING MOVEMENT-FLOORPLANE LOOP HITTING CEILING SMALL SINGLE +1D9BE ; [*1A61.0020.0002] # SIGNWRITING MOVEMENT-FLOORPLANE LOOP HITTING CEILING LARGE SINGLE +1D9BF ; [*1A62.0020.0002] # SIGNWRITING MOVEMENT-FLOORPLANE LOOP HITTING CEILING SMALL DOUBLE +1D9C0 ; [*1A63.0020.0002] # SIGNWRITING MOVEMENT-FLOORPLANE LOOP HITTING CEILING LARGE DOUBLE +1D9C1 ; [*1A64.0020.0002] # SIGNWRITING MOVEMENT-FLOORPLANE WAVE HITTING CEILING SMALL +1D9C2 ; [*1A65.0020.0002] # SIGNWRITING MOVEMENT-FLOORPLANE WAVE HITTING CEILING LARGE +1D9C3 ; [*1A66.0020.0002] # SIGNWRITING ROTATION-FLOORPLANE SINGLE HITTING CEILING +1D9C4 ; [*1A67.0020.0002] # SIGNWRITING ROTATION-FLOORPLANE DOUBLE HITTING CEILING +1D9C5 ; [*1A68.0020.0002] # SIGNWRITING ROTATION-FLOORPLANE ALTERNATING HITTING CEILING +1D9C6 ; [*1A69.0020.0002] # SIGNWRITING MOVEMENT-FLOORPLANE CURVE HITTING FLOOR SMALL +1D9C7 ; [*1A6A.0020.0002] # SIGNWRITING MOVEMENT-FLOORPLANE CURVE HITTING FLOOR LARGE +1D9C8 ; [*1A6B.0020.0002] # SIGNWRITING MOVEMENT-FLOORPLANE HUMP HITTING FLOOR SMALL DOUBLE +1D9C9 ; [*1A6C.0020.0002] # SIGNWRITING MOVEMENT-FLOORPLANE HUMP HITTING FLOOR LARGE DOUBLE +1D9CA ; [*1A6D.0020.0002] # SIGNWRITING MOVEMENT-FLOORPLANE HUMP HITTING FLOOR TRIPLE SMALL TRIPLE +1D9CB ; [*1A6E.0020.0002] # SIGNWRITING MOVEMENT-FLOORPLANE HUMP HITTING FLOOR TRIPLE LARGE TRIPLE +1D9CC ; [*1A6F.0020.0002] # SIGNWRITING MOVEMENT-FLOORPLANE LOOP HITTING FLOOR SMALL SINGLE +1D9CD ; [*1A70.0020.0002] # SIGNWRITING MOVEMENT-FLOORPLANE LOOP HITTING FLOOR LARGE SINGLE +1D9CE ; [*1A71.0020.0002] # SIGNWRITING MOVEMENT-FLOORPLANE LOOP HITTING FLOOR SMALL DOUBLE +1D9CF ; [*1A72.0020.0002] # SIGNWRITING MOVEMENT-FLOORPLANE LOOP HITTING FLOOR LARGE DOUBLE +1D9D0 ; [*1A73.0020.0002] # SIGNWRITING MOVEMENT-FLOORPLANE WAVE HITTING FLOOR SMALL +1D9D1 ; [*1A74.0020.0002] # SIGNWRITING MOVEMENT-FLOORPLANE WAVE HITTING FLOOR LARGE +1D9D2 ; [*1A75.0020.0002] # SIGNWRITING ROTATION-FLOORPLANE SINGLE HITTING FLOOR +1D9D3 ; [*1A76.0020.0002] # SIGNWRITING ROTATION-FLOORPLANE DOUBLE HITTING FLOOR +1D9D4 ; [*1A77.0020.0002] # SIGNWRITING ROTATION-FLOORPLANE ALTERNATING HITTING FLOOR +1D9D5 ; [*1A78.0020.0002] # SIGNWRITING MOVEMENT-FLOORPLANE CURVE SMALL +1D9D6 ; [*1A79.0020.0002] # SIGNWRITING MOVEMENT-FLOORPLANE CURVE MEDIUM +1D9D7 ; [*1A7A.0020.0002] # SIGNWRITING MOVEMENT-FLOORPLANE CURVE LARGE +1D9D8 ; [*1A7B.0020.0002] # SIGNWRITING MOVEMENT-FLOORPLANE CURVE LARGEST +1D9D9 ; [*1A7C.0020.0002] # SIGNWRITING MOVEMENT-FLOORPLANE CURVE COMBINED +1D9DA ; [*1A7D.0020.0002] # SIGNWRITING MOVEMENT-FLOORPLANE HUMP SMALL +1D9DB ; [*1A7E.0020.0002] # SIGNWRITING MOVEMENT-FLOORPLANE LOOP SMALL +1D9DC ; [*1A7F.0020.0002] # SIGNWRITING MOVEMENT-FLOORPLANE WAVE SNAKE +1D9DD ; [*1A80.0020.0002] # SIGNWRITING MOVEMENT-FLOORPLANE WAVE SMALL +1D9DE ; [*1A81.0020.0002] # SIGNWRITING MOVEMENT-FLOORPLANE WAVE LARGE +1D9DF ; [*1A82.0020.0002] # SIGNWRITING ROTATION-FLOORPLANE SINGLE +1D9E0 ; [*1A83.0020.0002] # SIGNWRITING ROTATION-FLOORPLANE DOUBLE +1D9E1 ; [*1A84.0020.0002] # SIGNWRITING ROTATION-FLOORPLANE ALTERNATING +1D9E2 ; [*1A85.0020.0002] # SIGNWRITING MOVEMENT-FLOORPLANE SHAKING PARALLEL +1D9E3 ; [*1A86.0020.0002] # SIGNWRITING MOVEMENT-WALLPLANE ARM CIRCLE SMALL SINGLE +1D9E4 ; [*1A87.0020.0002] # SIGNWRITING MOVEMENT-WALLPLANE ARM CIRCLE MEDIUM SINGLE +1D9E5 ; [*1A88.0020.0002] # SIGNWRITING MOVEMENT-WALLPLANE ARM CIRCLE SMALL DOUBLE +1D9E6 ; [*1A89.0020.0002] # SIGNWRITING MOVEMENT-WALLPLANE ARM CIRCLE MEDIUM DOUBLE +1D9E7 ; [*1A8A.0020.0002] # SIGNWRITING MOVEMENT-FLOORPLANE ARM CIRCLE HITTING WALL SMALL SINGLE +1D9E8 ; [*1A8B.0020.0002] # SIGNWRITING MOVEMENT-FLOORPLANE ARM CIRCLE HITTING WALL MEDIUM SINGLE +1D9E9 ; [*1A8C.0020.0002] # SIGNWRITING MOVEMENT-FLOORPLANE ARM CIRCLE HITTING WALL LARGE SINGLE +1D9EA ; [*1A8D.0020.0002] # SIGNWRITING MOVEMENT-FLOORPLANE ARM CIRCLE HITTING WALL SMALL DOUBLE +1D9EB ; [*1A8E.0020.0002] # SIGNWRITING MOVEMENT-FLOORPLANE ARM CIRCLE HITTING WALL MEDIUM DOUBLE +1D9EC ; [*1A8F.0020.0002] # SIGNWRITING MOVEMENT-FLOORPLANE ARM CIRCLE HITTING WALL LARGE DOUBLE +1D9ED ; [*1A90.0020.0002] # SIGNWRITING MOVEMENT-WALLPLANE WRIST CIRCLE FRONT SINGLE +1D9EE ; [*1A91.0020.0002] # SIGNWRITING MOVEMENT-WALLPLANE WRIST CIRCLE FRONT DOUBLE +1D9EF ; [*1A92.0020.0002] # SIGNWRITING MOVEMENT-FLOORPLANE WRIST CIRCLE HITTING WALL SINGLE +1D9F0 ; [*1A93.0020.0002] # SIGNWRITING MOVEMENT-FLOORPLANE WRIST CIRCLE HITTING WALL DOUBLE +1D9F1 ; [*1A94.0020.0002] # SIGNWRITING MOVEMENT-WALLPLANE FINGER CIRCLES SINGLE +1D9F2 ; [*1A95.0020.0002] # SIGNWRITING MOVEMENT-WALLPLANE FINGER CIRCLES DOUBLE +1D9F3 ; [*1A96.0020.0002] # SIGNWRITING MOVEMENT-FLOORPLANE FINGER CIRCLES HITTING WALL SINGLE +1D9F4 ; [*1A97.0020.0002] # SIGNWRITING MOVEMENT-FLOORPLANE FINGER CIRCLES HITTING WALL DOUBLE +1D9F5 ; [*1A98.0020.0002] # SIGNWRITING DYNAMIC ARROWHEAD SMALL +1D9F6 ; [*1A99.0020.0002] # SIGNWRITING DYNAMIC ARROWHEAD LARGE +1D9F7 ; [*1A9A.0020.0002] # SIGNWRITING DYNAMIC FAST +1D9F8 ; [*1A9B.0020.0002] # SIGNWRITING DYNAMIC SLOW +1D9F9 ; [*1A9C.0020.0002] # SIGNWRITING DYNAMIC TENSE +1D9FA ; [*1A9D.0020.0002] # SIGNWRITING DYNAMIC RELAXED +1D9FB ; [*1A9E.0020.0002] # SIGNWRITING DYNAMIC SIMULTANEOUS +1D9FC ; [*1A9F.0020.0002] # SIGNWRITING DYNAMIC SIMULTANEOUS ALTERNATING +1D9FD ; [*1AA0.0020.0002] # SIGNWRITING DYNAMIC EVERY OTHER TIME +1D9FE ; [*1AA1.0020.0002] # SIGNWRITING DYNAMIC GRADUAL +1D9FF ; [*1AA2.0020.0002] # SIGNWRITING HEAD +1DA00 ; [.0000.0000.0000] # SIGNWRITING HEAD RIM +1DA01 ; [.0000.0000.0000] # SIGNWRITING HEAD MOVEMENT-WALLPLANE STRAIGHT +1DA02 ; [.0000.0000.0000] # SIGNWRITING HEAD MOVEMENT-WALLPLANE TILT +1DA03 ; [.0000.0000.0000] # SIGNWRITING HEAD MOVEMENT-FLOORPLANE STRAIGHT +1DA04 ; [.0000.0000.0000] # SIGNWRITING HEAD MOVEMENT-WALLPLANE CURVE +1DA05 ; [.0000.0000.0000] # SIGNWRITING HEAD MOVEMENT-FLOORPLANE CURVE +1DA06 ; [.0000.0000.0000] # SIGNWRITING HEAD MOVEMENT CIRCLE +1DA07 ; [.0000.0000.0000] # SIGNWRITING FACE DIRECTION POSITION NOSE FORWARD TILTING +1DA08 ; [.0000.0000.0000] # SIGNWRITING FACE DIRECTION POSITION NOSE UP OR DOWN +1DA09 ; [.0000.0000.0000] # SIGNWRITING FACE DIRECTION POSITION NOSE UP OR DOWN TILTING +1DA0A ; [.0000.0000.0000] # SIGNWRITING EYEBROWS STRAIGHT UP +1DA0B ; [.0000.0000.0000] # SIGNWRITING EYEBROWS STRAIGHT NEUTRAL +1DA0C ; [.0000.0000.0000] # SIGNWRITING EYEBROWS STRAIGHT DOWN +1DA0D ; [.0000.0000.0000] # SIGNWRITING DREAMY EYEBROWS NEUTRAL DOWN +1DA0E ; [.0000.0000.0000] # SIGNWRITING DREAMY EYEBROWS DOWN NEUTRAL +1DA0F ; [.0000.0000.0000] # SIGNWRITING DREAMY EYEBROWS UP NEUTRAL +1DA10 ; [.0000.0000.0000] # SIGNWRITING DREAMY EYEBROWS NEUTRAL UP +1DA11 ; [.0000.0000.0000] # SIGNWRITING FOREHEAD NEUTRAL +1DA12 ; [.0000.0000.0000] # SIGNWRITING FOREHEAD CONTACT +1DA13 ; [.0000.0000.0000] # SIGNWRITING FOREHEAD WRINKLED +1DA14 ; [.0000.0000.0000] # SIGNWRITING EYES OPEN +1DA15 ; [.0000.0000.0000] # SIGNWRITING EYES SQUEEZED +1DA16 ; [.0000.0000.0000] # SIGNWRITING EYES CLOSED +1DA17 ; [.0000.0000.0000] # SIGNWRITING EYE BLINK SINGLE +1DA18 ; [.0000.0000.0000] # SIGNWRITING EYE BLINK MULTIPLE +1DA19 ; [.0000.0000.0000] # SIGNWRITING EYES HALF OPEN +1DA1A ; [.0000.0000.0000] # SIGNWRITING EYES WIDE OPEN +1DA1B ; [.0000.0000.0000] # SIGNWRITING EYES HALF CLOSED +1DA1C ; [.0000.0000.0000] # SIGNWRITING EYES WIDENING MOVEMENT +1DA1D ; [.0000.0000.0000] # SIGNWRITING EYE WINK +1DA1E ; [.0000.0000.0000] # SIGNWRITING EYELASHES UP +1DA1F ; [.0000.0000.0000] # SIGNWRITING EYELASHES DOWN +1DA20 ; [.0000.0000.0000] # SIGNWRITING EYELASHES FLUTTERING +1DA21 ; [.0000.0000.0000] # SIGNWRITING EYEGAZE-WALLPLANE STRAIGHT +1DA22 ; [.0000.0000.0000] # SIGNWRITING EYEGAZE-WALLPLANE STRAIGHT DOUBLE +1DA23 ; [.0000.0000.0000] # SIGNWRITING EYEGAZE-WALLPLANE STRAIGHT ALTERNATING +1DA24 ; [.0000.0000.0000] # SIGNWRITING EYEGAZE-FLOORPLANE STRAIGHT +1DA25 ; [.0000.0000.0000] # SIGNWRITING EYEGAZE-FLOORPLANE STRAIGHT DOUBLE +1DA26 ; [.0000.0000.0000] # SIGNWRITING EYEGAZE-FLOORPLANE STRAIGHT ALTERNATING +1DA27 ; [.0000.0000.0000] # SIGNWRITING EYEGAZE-WALLPLANE CURVED +1DA28 ; [.0000.0000.0000] # SIGNWRITING EYEGAZE-FLOORPLANE CURVED +1DA29 ; [.0000.0000.0000] # SIGNWRITING EYEGAZE-WALLPLANE CIRCLING +1DA2A ; [.0000.0000.0000] # SIGNWRITING CHEEKS PUFFED +1DA2B ; [.0000.0000.0000] # SIGNWRITING CHEEKS NEUTRAL +1DA2C ; [.0000.0000.0000] # SIGNWRITING CHEEKS SUCKED +1DA2D ; [.0000.0000.0000] # SIGNWRITING TENSE CHEEKS HIGH +1DA2E ; [.0000.0000.0000] # SIGNWRITING TENSE CHEEKS MIDDLE +1DA2F ; [.0000.0000.0000] # SIGNWRITING TENSE CHEEKS LOW +1DA30 ; [.0000.0000.0000] # SIGNWRITING EARS +1DA31 ; [.0000.0000.0000] # SIGNWRITING NOSE NEUTRAL +1DA32 ; [.0000.0000.0000] # SIGNWRITING NOSE CONTACT +1DA33 ; [.0000.0000.0000] # SIGNWRITING NOSE WRINKLES +1DA34 ; [.0000.0000.0000] # SIGNWRITING NOSE WIGGLES +1DA35 ; [.0000.0000.0000] # SIGNWRITING AIR BLOWING OUT +1DA36 ; [.0000.0000.0000] # SIGNWRITING AIR SUCKING IN +1DA37 ; [*1AA3.0020.0002] # SIGNWRITING AIR BLOW SMALL ROTATIONS +1DA38 ; [*1AA4.0020.0002] # SIGNWRITING AIR SUCK SMALL ROTATIONS +1DA39 ; [*1AA5.0020.0002] # SIGNWRITING BREATH INHALE +1DA3A ; [*1AA6.0020.0002] # SIGNWRITING BREATH EXHALE +1DA3B ; [.0000.0000.0000] # SIGNWRITING MOUTH CLOSED NEUTRAL +1DA3C ; [.0000.0000.0000] # SIGNWRITING MOUTH CLOSED FORWARD +1DA3D ; [.0000.0000.0000] # SIGNWRITING MOUTH CLOSED CONTACT +1DA3E ; [.0000.0000.0000] # SIGNWRITING MOUTH SMILE +1DA3F ; [.0000.0000.0000] # SIGNWRITING MOUTH SMILE WRINKLED +1DA40 ; [.0000.0000.0000] # SIGNWRITING MOUTH SMILE OPEN +1DA41 ; [.0000.0000.0000] # SIGNWRITING MOUTH FROWN +1DA42 ; [.0000.0000.0000] # SIGNWRITING MOUTH FROWN WRINKLED +1DA43 ; [.0000.0000.0000] # SIGNWRITING MOUTH FROWN OPEN +1DA44 ; [.0000.0000.0000] # SIGNWRITING MOUTH OPEN CIRCLE +1DA45 ; [.0000.0000.0000] # SIGNWRITING MOUTH OPEN FORWARD +1DA46 ; [.0000.0000.0000] # SIGNWRITING MOUTH OPEN WRINKLED +1DA47 ; [.0000.0000.0000] # SIGNWRITING MOUTH OPEN OVAL +1DA48 ; [.0000.0000.0000] # SIGNWRITING MOUTH OPEN OVAL WRINKLED +1DA49 ; [.0000.0000.0000] # SIGNWRITING MOUTH OPEN OVAL YAWN +1DA4A ; [.0000.0000.0000] # SIGNWRITING MOUTH OPEN RECTANGLE +1DA4B ; [.0000.0000.0000] # SIGNWRITING MOUTH OPEN RECTANGLE WRINKLED +1DA4C ; [.0000.0000.0000] # SIGNWRITING MOUTH OPEN RECTANGLE YAWN +1DA4D ; [.0000.0000.0000] # SIGNWRITING MOUTH KISS +1DA4E ; [.0000.0000.0000] # SIGNWRITING MOUTH KISS FORWARD +1DA4F ; [.0000.0000.0000] # SIGNWRITING MOUTH KISS WRINKLED +1DA50 ; [.0000.0000.0000] # SIGNWRITING MOUTH TENSE +1DA51 ; [.0000.0000.0000] # SIGNWRITING MOUTH TENSE FORWARD +1DA52 ; [.0000.0000.0000] # SIGNWRITING MOUTH TENSE SUCKED +1DA53 ; [.0000.0000.0000] # SIGNWRITING LIPS PRESSED TOGETHER +1DA54 ; [.0000.0000.0000] # SIGNWRITING LIP LOWER OVER UPPER +1DA55 ; [.0000.0000.0000] # SIGNWRITING LIP UPPER OVER LOWER +1DA56 ; [.0000.0000.0000] # SIGNWRITING MOUTH CORNERS +1DA57 ; [.0000.0000.0000] # SIGNWRITING MOUTH WRINKLES SINGLE +1DA58 ; [.0000.0000.0000] # SIGNWRITING MOUTH WRINKLES DOUBLE +1DA59 ; [.0000.0000.0000] # SIGNWRITING TONGUE STICKING OUT FAR +1DA5A ; [.0000.0000.0000] # SIGNWRITING TONGUE LICKING LIPS +1DA5B ; [.0000.0000.0000] # SIGNWRITING TONGUE TIP BETWEEN LIPS +1DA5C ; [.0000.0000.0000] # SIGNWRITING TONGUE TIP TOUCHING INSIDE MOUTH +1DA5D ; [.0000.0000.0000] # SIGNWRITING TONGUE INSIDE MOUTH RELAXED +1DA5E ; [.0000.0000.0000] # SIGNWRITING TONGUE MOVES AGAINST CHEEK +1DA5F ; [.0000.0000.0000] # SIGNWRITING TONGUE CENTRE STICKING OUT +1DA60 ; [.0000.0000.0000] # SIGNWRITING TONGUE CENTRE INSIDE MOUTH +1DA61 ; [.0000.0000.0000] # SIGNWRITING TEETH +1DA62 ; [.0000.0000.0000] # SIGNWRITING TEETH MOVEMENT +1DA63 ; [.0000.0000.0000] # SIGNWRITING TEETH ON TONGUE +1DA64 ; [.0000.0000.0000] # SIGNWRITING TEETH ON TONGUE MOVEMENT +1DA65 ; [.0000.0000.0000] # SIGNWRITING TEETH ON LIPS +1DA66 ; [.0000.0000.0000] # SIGNWRITING TEETH ON LIPS MOVEMENT +1DA67 ; [.0000.0000.0000] # SIGNWRITING TEETH BITE LIPS +1DA68 ; [.0000.0000.0000] # SIGNWRITING MOVEMENT-WALLPLANE JAW +1DA69 ; [.0000.0000.0000] # SIGNWRITING MOVEMENT-FLOORPLANE JAW +1DA6A ; [.0000.0000.0000] # SIGNWRITING NECK +1DA6B ; [.0000.0000.0000] # SIGNWRITING HAIR +1DA6C ; [.0000.0000.0000] # SIGNWRITING EXCITEMENT +1DA6D ; [*1AA7.0020.0002] # SIGNWRITING SHOULDER HIP SPINE +1DA6E ; [*1AA8.0020.0002] # SIGNWRITING SHOULDER HIP POSITIONS +1DA6F ; [*1AA9.0020.0002] # SIGNWRITING WALLPLANE SHOULDER HIP MOVE +1DA70 ; [*1AAA.0020.0002] # SIGNWRITING FLOORPLANE SHOULDER HIP MOVE +1DA71 ; [*1AAB.0020.0002] # SIGNWRITING SHOULDER TILTING FROM WAIST +1DA72 ; [*1AAC.0020.0002] # SIGNWRITING TORSO-WALLPLANE STRAIGHT STRETCH +1DA73 ; [*1AAD.0020.0002] # SIGNWRITING TORSO-WALLPLANE CURVED BEND +1DA74 ; [*1AAE.0020.0002] # SIGNWRITING TORSO-FLOORPLANE TWISTING +1DA75 ; [.0000.0000.0000] # SIGNWRITING UPPER BODY TILTING FROM HIP JOINTS +1DA76 ; [*1AAF.0020.0002] # SIGNWRITING LIMB COMBINATION +1DA77 ; [*1AB0.0020.0002] # SIGNWRITING LIMB LENGTH-1 +1DA78 ; [*1AB1.0020.0002] # SIGNWRITING LIMB LENGTH-2 +1DA79 ; [*1AB2.0020.0002] # SIGNWRITING LIMB LENGTH-3 +1DA7A ; [*1AB3.0020.0002] # SIGNWRITING LIMB LENGTH-4 +1DA7B ; [*1AB4.0020.0002] # SIGNWRITING LIMB LENGTH-5 +1DA7C ; [*1AB5.0020.0002] # SIGNWRITING LIMB LENGTH-6 +1DA7D ; [*1AB6.0020.0002] # SIGNWRITING LIMB LENGTH-7 +1DA7E ; [*1AB7.0020.0002] # SIGNWRITING FINGER +1DA7F ; [*1AB8.0020.0002] # SIGNWRITING LOCATION-WALLPLANE SPACE +1DA80 ; [*1AB9.0020.0002] # SIGNWRITING LOCATION-FLOORPLANE SPACE +1DA81 ; [*1ABA.0020.0002] # SIGNWRITING LOCATION HEIGHT +1DA82 ; [*1ABB.0020.0002] # SIGNWRITING LOCATION WIDTH +1DA83 ; [*1ABC.0020.0002] # SIGNWRITING LOCATION DEPTH +1DA84 ; [.0000.0000.0000] # SIGNWRITING LOCATION HEAD NECK +1DA85 ; [*1ABD.0020.0002] # SIGNWRITING LOCATION TORSO +1DA86 ; [*1ABE.0020.0002] # SIGNWRITING LOCATION LIMBS DIGITS +1DA87 ; [*0493.0020.0002] # SIGNWRITING COMMA +1DA88 ; [*0494.0020.0002] # SIGNWRITING FULL STOP +1DA89 ; [*0495.0020.0002] # SIGNWRITING SEMICOLON +1DA8A ; [*0496.0020.0002] # SIGNWRITING COLON +1DA8B ; [*0497.0020.0002] # SIGNWRITING PARENTHESIS +1DA9B ; [.0000.0000.0000] # SIGNWRITING FILL MODIFIER-2 +1DA9C ; [.0000.0000.0000] # SIGNWRITING FILL MODIFIER-3 +1DA9D ; [.0000.0000.0000] # SIGNWRITING FILL MODIFIER-4 +1DA9E ; [.0000.0000.0000] # SIGNWRITING FILL MODIFIER-5 +1DA9F ; [.0000.0000.0000] # SIGNWRITING FILL MODIFIER-6 +1DAA1 ; [.0000.0000.0000] # SIGNWRITING ROTATION MODIFIER-2 +1DAA2 ; [.0000.0000.0000] # SIGNWRITING ROTATION MODIFIER-3 +1DAA3 ; [.0000.0000.0000] # SIGNWRITING ROTATION MODIFIER-4 +1DAA4 ; [.0000.0000.0000] # SIGNWRITING ROTATION MODIFIER-5 +1DAA5 ; [.0000.0000.0000] # SIGNWRITING ROTATION MODIFIER-6 +1DAA6 ; [.0000.0000.0000] # SIGNWRITING ROTATION MODIFIER-7 +1DAA7 ; [.0000.0000.0000] # SIGNWRITING ROTATION MODIFIER-8 +1DAA8 ; [.0000.0000.0000] # SIGNWRITING ROTATION MODIFIER-9 +1DAA9 ; [.0000.0000.0000] # SIGNWRITING ROTATION MODIFIER-10 +1DAAA ; [.0000.0000.0000] # SIGNWRITING ROTATION MODIFIER-11 +1DAAB ; [.0000.0000.0000] # SIGNWRITING ROTATION MODIFIER-12 +1DAAC ; [.0000.0000.0000] # SIGNWRITING ROTATION MODIFIER-13 +1DAAD ; [.0000.0000.0000] # SIGNWRITING ROTATION MODIFIER-14 +1DAAE ; [.0000.0000.0000] # SIGNWRITING ROTATION MODIFIER-15 +1DAAF ; [.0000.0000.0000] # SIGNWRITING ROTATION MODIFIER-16 +1E8D0 ; [.0000.0000.0000] # MENDE KIKAKUI COMBINING NUMBER TEENS +1E8D1 ; [.0000.0000.0000] # MENDE KIKAKUI COMBINING NUMBER TENS +1E8D2 ; [.0000.0000.0000] # MENDE KIKAKUI COMBINING NUMBER HUNDREDS +1E8D3 ; [.0000.0000.0000] # MENDE KIKAKUI COMBINING NUMBER THOUSANDS +1E8D4 ; [.0000.0000.0000] # MENDE KIKAKUI COMBINING NUMBER TEN THOUSANDS +1E8D5 ; [.0000.0000.0000] # MENDE KIKAKUI COMBINING NUMBER HUNDRED THOUSANDS +1E8D6 ; [.0000.0000.0000] # MENDE KIKAKUI COMBINING NUMBER MILLIONS +1E95E ; [*0266.0020.0002] # ADLAM INITIAL EXCLAMATION MARK +1E95F ; [*0275.0020.0002] # ADLAM INITIAL QUESTION MARK +1EEF0 ; [*0511.0020.0002] # ARABIC MATHEMATICAL OPERATOR MEEM WITH HAH WITH TATWEEL +1EEF1 ; [*0512.0020.0002] # ARABIC MATHEMATICAL OPERATOR HAH WITH DAL +1F000 ; [*11DF.0020.0002] # MAHJONG TILE EAST WIND +1F001 ; [*11E0.0020.0002] # MAHJONG TILE SOUTH WIND +1F002 ; [*11E1.0020.0002] # MAHJONG TILE WEST WIND +1F003 ; [*11E2.0020.0002] # MAHJONG TILE NORTH WIND +1F004 ; [*11E3.0020.0002] # MAHJONG TILE RED DRAGON +1F005 ; [*11E4.0020.0002] # MAHJONG TILE GREEN DRAGON +1F006 ; [*11E5.0020.0002] # MAHJONG TILE WHITE DRAGON +1F007 ; [*11E6.0020.0002] # MAHJONG TILE ONE OF CHARACTERS +1F008 ; [*11E7.0020.0002] # MAHJONG TILE TWO OF CHARACTERS +1F009 ; [*11E8.0020.0002] # MAHJONG TILE THREE OF CHARACTERS +1F00A ; [*11E9.0020.0002] # MAHJONG TILE FOUR OF CHARACTERS +1F00B ; [*11EA.0020.0002] # MAHJONG TILE FIVE OF CHARACTERS +1F00C ; [*11EB.0020.0002] # MAHJONG TILE SIX OF CHARACTERS +1F00D ; [*11EC.0020.0002] # MAHJONG TILE SEVEN OF CHARACTERS +1F00E ; [*11ED.0020.0002] # MAHJONG TILE EIGHT OF CHARACTERS +1F00F ; [*11EE.0020.0002] # MAHJONG TILE NINE OF CHARACTERS +1F010 ; [*11EF.0020.0002] # MAHJONG TILE ONE OF BAMBOOS +1F011 ; [*11F0.0020.0002] # MAHJONG TILE TWO OF BAMBOOS +1F012 ; [*11F1.0020.0002] # MAHJONG TILE THREE OF BAMBOOS +1F013 ; [*11F2.0020.0002] # MAHJONG TILE FOUR OF BAMBOOS +1F014 ; [*11F3.0020.0002] # MAHJONG TILE FIVE OF BAMBOOS +1F015 ; [*11F4.0020.0002] # MAHJONG TILE SIX OF BAMBOOS +1F016 ; [*11F5.0020.0002] # MAHJONG TILE SEVEN OF BAMBOOS +1F017 ; [*11F6.0020.0002] # MAHJONG TILE EIGHT OF BAMBOOS +1F018 ; [*11F7.0020.0002] # MAHJONG TILE NINE OF BAMBOOS +1F019 ; [*11F8.0020.0002] # MAHJONG TILE ONE OF CIRCLES +1F01A ; [*11F9.0020.0002] # MAHJONG TILE TWO OF CIRCLES +1F01B ; [*11FA.0020.0002] # MAHJONG TILE THREE OF CIRCLES +1F01C ; [*11FB.0020.0002] # MAHJONG TILE FOUR OF CIRCLES +1F01D ; [*11FC.0020.0002] # MAHJONG TILE FIVE OF CIRCLES +1F01E ; [*11FD.0020.0002] # MAHJONG TILE SIX OF CIRCLES +1F01F ; [*11FE.0020.0002] # MAHJONG TILE SEVEN OF CIRCLES +1F020 ; [*11FF.0020.0002] # MAHJONG TILE EIGHT OF CIRCLES +1F021 ; [*1200.0020.0002] # MAHJONG TILE NINE OF CIRCLES +1F022 ; [*1201.0020.0002] # MAHJONG TILE PLUM +1F023 ; [*1202.0020.0002] # MAHJONG TILE ORCHID +1F024 ; [*1203.0020.0002] # MAHJONG TILE BAMBOO +1F025 ; [*1204.0020.0002] # MAHJONG TILE CHRYSANTHEMUM +1F026 ; [*1205.0020.0002] # MAHJONG TILE SPRING +1F027 ; [*1206.0020.0002] # MAHJONG TILE SUMMER +1F028 ; [*1207.0020.0002] # MAHJONG TILE AUTUMN +1F029 ; [*1208.0020.0002] # MAHJONG TILE WINTER +1F02A ; [*1209.0020.0002] # MAHJONG TILE JOKER +1F02B ; [*120A.0020.0002] # MAHJONG TILE BACK +1F030 ; [*120B.0020.0002] # DOMINO TILE HORIZONTAL BACK +1F031 ; [*120C.0020.0002] # DOMINO TILE HORIZONTAL-00-00 +1F032 ; [*120D.0020.0002] # DOMINO TILE HORIZONTAL-00-01 +1F033 ; [*120E.0020.0002] # DOMINO TILE HORIZONTAL-00-02 +1F034 ; [*120F.0020.0002] # DOMINO TILE HORIZONTAL-00-03 +1F035 ; [*1210.0020.0002] # DOMINO TILE HORIZONTAL-00-04 +1F036 ; [*1211.0020.0002] # DOMINO TILE HORIZONTAL-00-05 +1F037 ; [*1212.0020.0002] # DOMINO TILE HORIZONTAL-00-06 +1F038 ; [*1213.0020.0002] # DOMINO TILE HORIZONTAL-01-00 +1F039 ; [*1214.0020.0002] # DOMINO TILE HORIZONTAL-01-01 +1F03A ; [*1215.0020.0002] # DOMINO TILE HORIZONTAL-01-02 +1F03B ; [*1216.0020.0002] # DOMINO TILE HORIZONTAL-01-03 +1F03C ; [*1217.0020.0002] # DOMINO TILE HORIZONTAL-01-04 +1F03D ; [*1218.0020.0002] # DOMINO TILE HORIZONTAL-01-05 +1F03E ; [*1219.0020.0002] # DOMINO TILE HORIZONTAL-01-06 +1F03F ; [*121A.0020.0002] # DOMINO TILE HORIZONTAL-02-00 +1F040 ; [*121B.0020.0002] # DOMINO TILE HORIZONTAL-02-01 +1F041 ; [*121C.0020.0002] # DOMINO TILE HORIZONTAL-02-02 +1F042 ; [*121D.0020.0002] # DOMINO TILE HORIZONTAL-02-03 +1F043 ; [*121E.0020.0002] # DOMINO TILE HORIZONTAL-02-04 +1F044 ; [*121F.0020.0002] # DOMINO TILE HORIZONTAL-02-05 +1F045 ; [*1220.0020.0002] # DOMINO TILE HORIZONTAL-02-06 +1F046 ; [*1221.0020.0002] # DOMINO TILE HORIZONTAL-03-00 +1F047 ; [*1222.0020.0002] # DOMINO TILE HORIZONTAL-03-01 +1F048 ; [*1223.0020.0002] # DOMINO TILE HORIZONTAL-03-02 +1F049 ; [*1224.0020.0002] # DOMINO TILE HORIZONTAL-03-03 +1F04A ; [*1225.0020.0002] # DOMINO TILE HORIZONTAL-03-04 +1F04B ; [*1226.0020.0002] # DOMINO TILE HORIZONTAL-03-05 +1F04C ; [*1227.0020.0002] # DOMINO TILE HORIZONTAL-03-06 +1F04D ; [*1228.0020.0002] # DOMINO TILE HORIZONTAL-04-00 +1F04E ; [*1229.0020.0002] # DOMINO TILE HORIZONTAL-04-01 +1F04F ; [*122A.0020.0002] # DOMINO TILE HORIZONTAL-04-02 +1F050 ; [*122B.0020.0002] # DOMINO TILE HORIZONTAL-04-03 +1F051 ; [*122C.0020.0002] # DOMINO TILE HORIZONTAL-04-04 +1F052 ; [*122D.0020.0002] # DOMINO TILE HORIZONTAL-04-05 +1F053 ; [*122E.0020.0002] # DOMINO TILE HORIZONTAL-04-06 +1F054 ; [*122F.0020.0002] # DOMINO TILE HORIZONTAL-05-00 +1F055 ; [*1230.0020.0002] # DOMINO TILE HORIZONTAL-05-01 +1F056 ; [*1231.0020.0002] # DOMINO TILE HORIZONTAL-05-02 +1F057 ; [*1232.0020.0002] # DOMINO TILE HORIZONTAL-05-03 +1F058 ; [*1233.0020.0002] # DOMINO TILE HORIZONTAL-05-04 +1F059 ; [*1234.0020.0002] # DOMINO TILE HORIZONTAL-05-05 +1F05A ; [*1235.0020.0002] # DOMINO TILE HORIZONTAL-05-06 +1F05B ; [*1236.0020.0002] # DOMINO TILE HORIZONTAL-06-00 +1F05C ; [*1237.0020.0002] # DOMINO TILE HORIZONTAL-06-01 +1F05D ; [*1238.0020.0002] # DOMINO TILE HORIZONTAL-06-02 +1F05E ; [*1239.0020.0002] # DOMINO TILE HORIZONTAL-06-03 +1F05F ; [*123A.0020.0002] # DOMINO TILE HORIZONTAL-06-04 +1F060 ; [*123B.0020.0002] # DOMINO TILE HORIZONTAL-06-05 +1F061 ; [*123C.0020.0002] # DOMINO TILE HORIZONTAL-06-06 +1F062 ; [*123D.0020.0002] # DOMINO TILE VERTICAL BACK +1F063 ; [*123E.0020.0002] # DOMINO TILE VERTICAL-00-00 +1F064 ; [*123F.0020.0002] # DOMINO TILE VERTICAL-00-01 +1F065 ; [*1240.0020.0002] # DOMINO TILE VERTICAL-00-02 +1F066 ; [*1241.0020.0002] # DOMINO TILE VERTICAL-00-03 +1F067 ; [*1242.0020.0002] # DOMINO TILE VERTICAL-00-04 +1F068 ; [*1243.0020.0002] # DOMINO TILE VERTICAL-00-05 +1F069 ; [*1244.0020.0002] # DOMINO TILE VERTICAL-00-06 +1F06A ; [*1245.0020.0002] # DOMINO TILE VERTICAL-01-00 +1F06B ; [*1246.0020.0002] # DOMINO TILE VERTICAL-01-01 +1F06C ; [*1247.0020.0002] # DOMINO TILE VERTICAL-01-02 +1F06D ; [*1248.0020.0002] # DOMINO TILE VERTICAL-01-03 +1F06E ; [*1249.0020.0002] # DOMINO TILE VERTICAL-01-04 +1F06F ; [*124A.0020.0002] # DOMINO TILE VERTICAL-01-05 +1F070 ; [*124B.0020.0002] # DOMINO TILE VERTICAL-01-06 +1F071 ; [*124C.0020.0002] # DOMINO TILE VERTICAL-02-00 +1F072 ; [*124D.0020.0002] # DOMINO TILE VERTICAL-02-01 +1F073 ; [*124E.0020.0002] # DOMINO TILE VERTICAL-02-02 +1F074 ; [*124F.0020.0002] # DOMINO TILE VERTICAL-02-03 +1F075 ; [*1250.0020.0002] # DOMINO TILE VERTICAL-02-04 +1F076 ; [*1251.0020.0002] # DOMINO TILE VERTICAL-02-05 +1F077 ; [*1252.0020.0002] # DOMINO TILE VERTICAL-02-06 +1F078 ; [*1253.0020.0002] # DOMINO TILE VERTICAL-03-00 +1F079 ; [*1254.0020.0002] # DOMINO TILE VERTICAL-03-01 +1F07A ; [*1255.0020.0002] # DOMINO TILE VERTICAL-03-02 +1F07B ; [*1256.0020.0002] # DOMINO TILE VERTICAL-03-03 +1F07C ; [*1257.0020.0002] # DOMINO TILE VERTICAL-03-04 +1F07D ; [*1258.0020.0002] # DOMINO TILE VERTICAL-03-05 +1F07E ; [*1259.0020.0002] # DOMINO TILE VERTICAL-03-06 +1F07F ; [*125A.0020.0002] # DOMINO TILE VERTICAL-04-00 +1F080 ; [*125B.0020.0002] # DOMINO TILE VERTICAL-04-01 +1F081 ; [*125C.0020.0002] # DOMINO TILE VERTICAL-04-02 +1F082 ; [*125D.0020.0002] # DOMINO TILE VERTICAL-04-03 +1F083 ; [*125E.0020.0002] # DOMINO TILE VERTICAL-04-04 +1F084 ; [*125F.0020.0002] # DOMINO TILE VERTICAL-04-05 +1F085 ; [*1260.0020.0002] # DOMINO TILE VERTICAL-04-06 +1F086 ; [*1261.0020.0002] # DOMINO TILE VERTICAL-05-00 +1F087 ; [*1262.0020.0002] # DOMINO TILE VERTICAL-05-01 +1F088 ; [*1263.0020.0002] # DOMINO TILE VERTICAL-05-02 +1F089 ; [*1264.0020.0002] # DOMINO TILE VERTICAL-05-03 +1F08A ; [*1265.0020.0002] # DOMINO TILE VERTICAL-05-04 +1F08B ; [*1266.0020.0002] # DOMINO TILE VERTICAL-05-05 +1F08C ; [*1267.0020.0002] # DOMINO TILE VERTICAL-05-06 +1F08D ; [*1268.0020.0002] # DOMINO TILE VERTICAL-06-00 +1F08E ; [*1269.0020.0002] # DOMINO TILE VERTICAL-06-01 +1F08F ; [*126A.0020.0002] # DOMINO TILE VERTICAL-06-02 +1F090 ; [*126B.0020.0002] # DOMINO TILE VERTICAL-06-03 +1F091 ; [*126C.0020.0002] # DOMINO TILE VERTICAL-06-04 +1F092 ; [*126D.0020.0002] # DOMINO TILE VERTICAL-06-05 +1F093 ; [*126E.0020.0002] # DOMINO TILE VERTICAL-06-06 +1F0A0 ; [*126F.0020.0002] # PLAYING CARD BACK +1F0A1 ; [*1270.0020.0002] # PLAYING CARD ACE OF SPADES +1F0A2 ; [*1271.0020.0002] # PLAYING CARD TWO OF SPADES +1F0A3 ; [*1272.0020.0002] # PLAYING CARD THREE OF SPADES +1F0A4 ; [*1273.0020.0002] # PLAYING CARD FOUR OF SPADES +1F0A5 ; [*1274.0020.0002] # PLAYING CARD FIVE OF SPADES +1F0A6 ; [*1275.0020.0002] # PLAYING CARD SIX OF SPADES +1F0A7 ; [*1276.0020.0002] # PLAYING CARD SEVEN OF SPADES +1F0A8 ; [*1277.0020.0002] # PLAYING CARD EIGHT OF SPADES +1F0A9 ; [*1278.0020.0002] # PLAYING CARD NINE OF SPADES +1F0AA ; [*1279.0020.0002] # PLAYING CARD TEN OF SPADES +1F0AB ; [*127A.0020.0002] # PLAYING CARD JACK OF SPADES +1F0AC ; [*127B.0020.0002] # PLAYING CARD KNIGHT OF SPADES +1F0AD ; [*127C.0020.0002] # PLAYING CARD QUEEN OF SPADES +1F0AE ; [*127D.0020.0002] # PLAYING CARD KING OF SPADES +1F0B1 ; [*127E.0020.0002] # PLAYING CARD ACE OF HEARTS +1F0B2 ; [*127F.0020.0002] # PLAYING CARD TWO OF HEARTS +1F0B3 ; [*1280.0020.0002] # PLAYING CARD THREE OF HEARTS +1F0B4 ; [*1281.0020.0002] # PLAYING CARD FOUR OF HEARTS +1F0B5 ; [*1282.0020.0002] # PLAYING CARD FIVE OF HEARTS +1F0B6 ; [*1283.0020.0002] # PLAYING CARD SIX OF HEARTS +1F0B7 ; [*1284.0020.0002] # PLAYING CARD SEVEN OF HEARTS +1F0B8 ; [*1285.0020.0002] # PLAYING CARD EIGHT OF HEARTS +1F0B9 ; [*1286.0020.0002] # PLAYING CARD NINE OF HEARTS +1F0BA ; [*1287.0020.0002] # PLAYING CARD TEN OF HEARTS +1F0BB ; [*1288.0020.0002] # PLAYING CARD JACK OF HEARTS +1F0BC ; [*1289.0020.0002] # PLAYING CARD KNIGHT OF HEARTS +1F0BD ; [*128A.0020.0002] # PLAYING CARD QUEEN OF HEARTS +1F0BE ; [*128B.0020.0002] # PLAYING CARD KING OF HEARTS +1F0BF ; [*128C.0020.0002] # PLAYING CARD RED JOKER +1F0C1 ; [*128D.0020.0002] # PLAYING CARD ACE OF DIAMONDS +1F0C2 ; [*128E.0020.0002] # PLAYING CARD TWO OF DIAMONDS +1F0C3 ; [*128F.0020.0002] # PLAYING CARD THREE OF DIAMONDS +1F0C4 ; [*1290.0020.0002] # PLAYING CARD FOUR OF DIAMONDS +1F0C5 ; [*1291.0020.0002] # PLAYING CARD FIVE OF DIAMONDS +1F0C6 ; [*1292.0020.0002] # PLAYING CARD SIX OF DIAMONDS +1F0C7 ; [*1293.0020.0002] # PLAYING CARD SEVEN OF DIAMONDS +1F0C8 ; [*1294.0020.0002] # PLAYING CARD EIGHT OF DIAMONDS +1F0C9 ; [*1295.0020.0002] # PLAYING CARD NINE OF DIAMONDS +1F0CA ; [*1296.0020.0002] # PLAYING CARD TEN OF DIAMONDS +1F0CB ; [*1297.0020.0002] # PLAYING CARD JACK OF DIAMONDS +1F0CC ; [*1298.0020.0002] # PLAYING CARD KNIGHT OF DIAMONDS +1F0CD ; [*1299.0020.0002] # PLAYING CARD QUEEN OF DIAMONDS +1F0CE ; [*129A.0020.0002] # PLAYING CARD KING OF DIAMONDS +1F0CF ; [*129B.0020.0002] # PLAYING CARD BLACK JOKER +1F0D1 ; [*129C.0020.0002] # PLAYING CARD ACE OF CLUBS +1F0D2 ; [*129D.0020.0002] # PLAYING CARD TWO OF CLUBS +1F0D3 ; [*129E.0020.0002] # PLAYING CARD THREE OF CLUBS +1F0D4 ; [*129F.0020.0002] # PLAYING CARD FOUR OF CLUBS +1F0D5 ; [*12A0.0020.0002] # PLAYING CARD FIVE OF CLUBS +1F0D6 ; [*12A1.0020.0002] # PLAYING CARD SIX OF CLUBS +1F0D7 ; [*12A2.0020.0002] # PLAYING CARD SEVEN OF CLUBS +1F0D8 ; [*12A3.0020.0002] # PLAYING CARD EIGHT OF CLUBS +1F0D9 ; [*12A4.0020.0002] # PLAYING CARD NINE OF CLUBS +1F0DA ; [*12A5.0020.0002] # PLAYING CARD TEN OF CLUBS +1F0DB ; [*12A6.0020.0002] # PLAYING CARD JACK OF CLUBS +1F0DC ; [*12A7.0020.0002] # PLAYING CARD KNIGHT OF CLUBS +1F0DD ; [*12A8.0020.0002] # PLAYING CARD QUEEN OF CLUBS +1F0DE ; [*12A9.0020.0002] # PLAYING CARD KING OF CLUBS +1F0DF ; [*12AA.0020.0002] # PLAYING CARD WHITE JOKER +1F0E0 ; [*12AB.0020.0002] # PLAYING CARD FOOL +1F0E1 ; [*12AC.0020.0002] # PLAYING CARD TRUMP-1 +1F0E2 ; [*12AD.0020.0002] # PLAYING CARD TRUMP-2 +1F0E3 ; [*12AE.0020.0002] # PLAYING CARD TRUMP-3 +1F0E4 ; [*12AF.0020.0002] # PLAYING CARD TRUMP-4 +1F0E5 ; [*12B0.0020.0002] # PLAYING CARD TRUMP-5 +1F0E6 ; [*12B1.0020.0002] # PLAYING CARD TRUMP-6 +1F0E7 ; [*12B2.0020.0002] # PLAYING CARD TRUMP-7 +1F0E8 ; [*12B3.0020.0002] # PLAYING CARD TRUMP-8 +1F0E9 ; [*12B4.0020.0002] # PLAYING CARD TRUMP-9 +1F0EA ; [*12B5.0020.0002] # PLAYING CARD TRUMP-10 +1F0EB ; [*12B6.0020.0002] # PLAYING CARD TRUMP-11 +1F0EC ; [*12B7.0020.0002] # PLAYING CARD TRUMP-12 +1F0ED ; [*12B8.0020.0002] # PLAYING CARD TRUMP-13 +1F0EE ; [*12B9.0020.0002] # PLAYING CARD TRUMP-14 +1F0EF ; [*12BA.0020.0002] # PLAYING CARD TRUMP-15 +1F0F0 ; [*12BB.0020.0002] # PLAYING CARD TRUMP-16 +1F0F1 ; [*12BC.0020.0002] # PLAYING CARD TRUMP-17 +1F0F2 ; [*12BD.0020.0002] # PLAYING CARD TRUMP-18 +1F0F3 ; [*12BE.0020.0002] # PLAYING CARD TRUMP-19 +1F0F4 ; [*12BF.0020.0002] # PLAYING CARD TRUMP-20 +1F0F5 ; [*12C0.0020.0002] # PLAYING CARD TRUMP-21 +1F1E6 ; [*0A1E.0020.0002] # REGIONAL INDICATOR SYMBOL LETTER A +1F1E7 ; [*0A1F.0020.0002] # REGIONAL INDICATOR SYMBOL LETTER B +1F1E8 ; [*0A20.0020.0002] # REGIONAL INDICATOR SYMBOL LETTER C +1F1E9 ; [*0A21.0020.0002] # REGIONAL INDICATOR SYMBOL LETTER D +1F1EA ; [*0A22.0020.0002] # REGIONAL INDICATOR SYMBOL LETTER E +1F1EB ; [*0A23.0020.0002] # REGIONAL INDICATOR SYMBOL LETTER F +1F1EC ; [*0A24.0020.0002] # REGIONAL INDICATOR SYMBOL LETTER G +1F1ED ; [*0A25.0020.0002] # REGIONAL INDICATOR SYMBOL LETTER H +1F1EE ; [*0A26.0020.0002] # REGIONAL INDICATOR SYMBOL LETTER I +1F1EF ; [*0A27.0020.0002] # REGIONAL INDICATOR SYMBOL LETTER J +1F1F0 ; [*0A28.0020.0002] # REGIONAL INDICATOR SYMBOL LETTER K +1F1F1 ; [*0A29.0020.0002] # REGIONAL INDICATOR SYMBOL LETTER L +1F1F2 ; [*0A2A.0020.0002] # REGIONAL INDICATOR SYMBOL LETTER M +1F1F3 ; [*0A2B.0020.0002] # REGIONAL INDICATOR SYMBOL LETTER N +1F1F4 ; [*0A2C.0020.0002] # REGIONAL INDICATOR SYMBOL LETTER O +1F1F5 ; [*0A2D.0020.0002] # REGIONAL INDICATOR SYMBOL LETTER P +1F1F6 ; [*0A2E.0020.0002] # REGIONAL INDICATOR SYMBOL LETTER Q +1F1F7 ; [*0A2F.0020.0002] # REGIONAL INDICATOR SYMBOL LETTER R +1F1F8 ; [*0A30.0020.0002] # REGIONAL INDICATOR SYMBOL LETTER S +1F1F9 ; [*0A31.0020.0002] # REGIONAL INDICATOR SYMBOL LETTER T +1F1FA ; [*0A32.0020.0002] # REGIONAL INDICATOR SYMBOL LETTER U +1F1FB ; [*0A33.0020.0002] # REGIONAL INDICATOR SYMBOL LETTER V +1F1FC ; [*0A34.0020.0002] # REGIONAL INDICATOR SYMBOL LETTER W +1F1FD ; [*0A35.0020.0002] # REGIONAL INDICATOR SYMBOL LETTER X +1F1FE ; [*0A36.0020.0002] # REGIONAL INDICATOR SYMBOL LETTER Y +1F1FF ; [*0A37.0020.0002] # REGIONAL INDICATOR SYMBOL LETTER Z +1F260 ; [*12C1.0020.0002] # ROUNDED SYMBOL FOR FU +1F261 ; [*12C2.0020.0002] # ROUNDED SYMBOL FOR LU +1F262 ; [*12C3.0020.0002] # ROUNDED SYMBOL FOR SHOU +1F263 ; [*12C4.0020.0002] # ROUNDED SYMBOL FOR XI +1F264 ; [*12C5.0020.0002] # ROUNDED SYMBOL FOR SHUANGXI +1F265 ; [*12C6.0020.0002] # ROUNDED SYMBOL FOR CAI +1F300 ; [*12C7.0020.0002] # CYCLONE +1F301 ; [*12C8.0020.0002] # FOGGY +1F302 ; [*12C9.0020.0002] # CLOSED UMBRELLA +1F303 ; [*12CA.0020.0002] # NIGHT WITH STARS +1F304 ; [*12CB.0020.0002] # SUNRISE OVER MOUNTAINS +1F305 ; [*12CC.0020.0002] # SUNRISE +1F306 ; [*12CD.0020.0002] # CITYSCAPE AT DUSK +1F307 ; [*12CE.0020.0002] # SUNSET OVER BUILDINGS +1F308 ; [*12CF.0020.0002] # RAINBOW +1F309 ; [*12D0.0020.0002] # BRIDGE AT NIGHT +1F30A ; [*12D1.0020.0002] # WATER WAVE +1F30B ; [*12D2.0020.0002] # VOLCANO +1F30C ; [*12D3.0020.0002] # MILKY WAY +1F30D ; [*12D4.0020.0002] # EARTH GLOBE EUROPE-AFRICA +1F30E ; [*12D5.0020.0002] # EARTH GLOBE AMERICAS +1F30F ; [*12D6.0020.0002] # EARTH GLOBE ASIA-AUSTRALIA +1F310 ; [*12D7.0020.0002] # GLOBE WITH MERIDIANS +1F311 ; [*12D8.0020.0002] # NEW MOON SYMBOL +1F312 ; [*12D9.0020.0002] # WAXING CRESCENT MOON SYMBOL +1F313 ; [*12DA.0020.0002] # FIRST QUARTER MOON SYMBOL +1F314 ; [*12DB.0020.0002] # WAXING GIBBOUS MOON SYMBOL +1F315 ; [*12DC.0020.0002] # FULL MOON SYMBOL +1F316 ; [*12DD.0020.0002] # WANING GIBBOUS MOON SYMBOL +1F317 ; [*12DE.0020.0002] # LAST QUARTER MOON SYMBOL +1F318 ; [*12DF.0020.0002] # WANING CRESCENT MOON SYMBOL +1F319 ; [*12E0.0020.0002] # CRESCENT MOON +1F31A ; [*12E1.0020.0002] # NEW MOON WITH FACE +1F31B ; [*12E2.0020.0002] # FIRST QUARTER MOON WITH FACE +1F31C ; [*12E3.0020.0002] # LAST QUARTER MOON WITH FACE +1F31D ; [*12E4.0020.0002] # FULL MOON WITH FACE +1F31E ; [*12E5.0020.0002] # SUN WITH FACE +1F31F ; [*12E6.0020.0002] # GLOWING STAR +1F320 ; [*12E7.0020.0002] # SHOOTING STAR +1F321 ; [*12E8.0020.0002] # THERMOMETER +1F322 ; [*12E9.0020.0002] # BLACK DROPLET +1F323 ; [*12EA.0020.0002] # WHITE SUN +1F324 ; [*12EB.0020.0002] # WHITE SUN WITH SMALL CLOUD +1F325 ; [*12EC.0020.0002] # WHITE SUN BEHIND CLOUD +1F326 ; [*12ED.0020.0002] # WHITE SUN BEHIND CLOUD WITH RAIN +1F327 ; [*12EE.0020.0002] # CLOUD WITH RAIN +1F328 ; [*12EF.0020.0002] # CLOUD WITH SNOW +1F329 ; [*12F0.0020.0002] # CLOUD WITH LIGHTNING +1F32A ; [*12F1.0020.0002] # CLOUD WITH TORNADO +1F32B ; [*12F2.0020.0002] # FOG +1F32C ; [*12F3.0020.0002] # WIND BLOWING FACE +1F32D ; [*12F4.0020.0002] # HOT DOG +1F32E ; [*12F5.0020.0002] # TACO +1F32F ; [*12F6.0020.0002] # BURRITO +1F330 ; [*12F7.0020.0002] # CHESTNUT +1F331 ; [*12F8.0020.0002] # SEEDLING +1F332 ; [*12F9.0020.0002] # EVERGREEN TREE +1F333 ; [*12FA.0020.0002] # DECIDUOUS TREE +1F334 ; [*12FB.0020.0002] # PALM TREE +1F335 ; [*12FC.0020.0002] # CACTUS +1F336 ; [*12FD.0020.0002] # HOT PEPPER +1F337 ; [*12FE.0020.0002] # TULIP +1F338 ; [*12FF.0020.0002] # CHERRY BLOSSOM +1F339 ; [*1300.0020.0002] # ROSE +1F33A ; [*1301.0020.0002] # HIBISCUS +1F33B ; [*1302.0020.0002] # SUNFLOWER +1F33C ; [*1303.0020.0002] # BLOSSOM +1F33D ; [*1304.0020.0002] # EAR OF MAIZE +1F33E ; [*1305.0020.0002] # EAR OF RICE +1F33F ; [*1306.0020.0002] # HERB +1F340 ; [*1307.0020.0002] # FOUR LEAF CLOVER +1F341 ; [*1308.0020.0002] # MAPLE LEAF +1F342 ; [*1309.0020.0002] # FALLEN LEAF +1F343 ; [*130A.0020.0002] # LEAF FLUTTERING IN WIND +1F344 ; [*130B.0020.0002] # MUSHROOM +1F345 ; [*130C.0020.0002] # TOMATO +1F346 ; [*130D.0020.0002] # AUBERGINE +1F347 ; [*130E.0020.0002] # GRAPES +1F348 ; [*130F.0020.0002] # MELON +1F349 ; [*1310.0020.0002] # WATERMELON +1F34A ; [*1311.0020.0002] # TANGERINE +1F34B ; [*1312.0020.0002] # LEMON +1F34C ; [*1313.0020.0002] # BANANA +1F34D ; [*1314.0020.0002] # PINEAPPLE +1F34E ; [*1315.0020.0002] # RED APPLE +1F34F ; [*1316.0020.0002] # GREEN APPLE +1F350 ; [*1317.0020.0002] # PEAR +1F351 ; [*1318.0020.0002] # PEACH +1F352 ; [*1319.0020.0002] # CHERRIES +1F353 ; [*131A.0020.0002] # STRAWBERRY +1F354 ; [*131B.0020.0002] # HAMBURGER +1F355 ; [*131C.0020.0002] # SLICE OF PIZZA +1F356 ; [*131D.0020.0002] # MEAT ON BONE +1F357 ; [*131E.0020.0002] # POULTRY LEG +1F358 ; [*131F.0020.0002] # RICE CRACKER +1F359 ; [*1320.0020.0002] # RICE BALL +1F35A ; [*1321.0020.0002] # COOKED RICE +1F35B ; [*1322.0020.0002] # CURRY AND RICE +1F35C ; [*1323.0020.0002] # STEAMING BOWL +1F35D ; [*1324.0020.0002] # SPAGHETTI +1F35E ; [*1325.0020.0002] # BREAD +1F35F ; [*1326.0020.0002] # FRENCH FRIES +1F360 ; [*1327.0020.0002] # ROASTED SWEET POTATO +1F361 ; [*1328.0020.0002] # DANGO +1F362 ; [*1329.0020.0002] # ODEN +1F363 ; [*132A.0020.0002] # SUSHI +1F364 ; [*132B.0020.0002] # FRIED SHRIMP +1F365 ; [*132C.0020.0002] # FISH CAKE WITH SWIRL DESIGN +1F366 ; [*132D.0020.0002] # SOFT ICE CREAM +1F367 ; [*132E.0020.0002] # SHAVED ICE +1F368 ; [*132F.0020.0002] # ICE CREAM +1F369 ; [*1330.0020.0002] # DOUGHNUT +1F36A ; [*1331.0020.0002] # COOKIE +1F36B ; [*1332.0020.0002] # CHOCOLATE BAR +1F36C ; [*1333.0020.0002] # CANDY +1F36D ; [*1334.0020.0002] # LOLLIPOP +1F36E ; [*1335.0020.0002] # CUSTARD +1F36F ; [*1336.0020.0002] # HONEY POT +1F370 ; [*1337.0020.0002] # SHORTCAKE +1F371 ; [*1338.0020.0002] # BENTO BOX +1F372 ; [*1339.0020.0002] # POT OF FOOD +1F373 ; [*133A.0020.0002] # COOKING +1F374 ; [*133B.0020.0002] # FORK AND KNIFE +1F375 ; [*133C.0020.0002] # TEACUP WITHOUT HANDLE +1F376 ; [*133D.0020.0002] # SAKE BOTTLE AND CUP +1F377 ; [*133E.0020.0002] # WINE GLASS +1F378 ; [*133F.0020.0002] # COCKTAIL GLASS +1F379 ; [*1340.0020.0002] # TROPICAL DRINK +1F37A ; [*1341.0020.0002] # BEER MUG +1F37B ; [*1342.0020.0002] # CLINKING BEER MUGS +1F37C ; [*1343.0020.0002] # BABY BOTTLE +1F37D ; [*1344.0020.0002] # FORK AND KNIFE WITH PLATE +1F37E ; [*1345.0020.0002] # BOTTLE WITH POPPING CORK +1F37F ; [*1346.0020.0002] # POPCORN +1F380 ; [*1347.0020.0002] # RIBBON +1F381 ; [*1348.0020.0002] # WRAPPED PRESENT +1F382 ; [*1349.0020.0002] # BIRTHDAY CAKE +1F383 ; [*134A.0020.0002] # JACK-O-LANTERN +1F384 ; [*134B.0020.0002] # CHRISTMAS TREE +1F385 ; [*134C.0020.0002] # FATHER CHRISTMAS +1F386 ; [*134D.0020.0002] # FIREWORKS +1F387 ; [*134E.0020.0002] # FIREWORK SPARKLER +1F388 ; [*134F.0020.0002] # BALLOON +1F389 ; [*1350.0020.0002] # PARTY POPPER +1F38A ; [*1351.0020.0002] # CONFETTI BALL +1F38B ; [*1352.0020.0002] # TANABATA TREE +1F38C ; [*1353.0020.0002] # CROSSED FLAGS +1F38D ; [*1354.0020.0002] # PINE DECORATION +1F38E ; [*1355.0020.0002] # JAPANESE DOLLS +1F38F ; [*1356.0020.0002] # CARP STREAMER +1F390 ; [*1357.0020.0002] # WIND CHIME +1F391 ; [*1358.0020.0002] # MOON VIEWING CEREMONY +1F392 ; [*1359.0020.0002] # SCHOOL SATCHEL +1F393 ; [*135A.0020.0002] # GRADUATION CAP +1F394 ; [*135B.0020.0002] # HEART WITH TIP ON THE LEFT +1F395 ; [*135C.0020.0002] # BOUQUET OF FLOWERS +1F396 ; [*135D.0020.0002] # MILITARY MEDAL +1F397 ; [*135E.0020.0002] # REMINDER RIBBON +1F398 ; [*135F.0020.0002] # MUSICAL KEYBOARD WITH JACKS +1F399 ; [*1360.0020.0002] # STUDIO MICROPHONE +1F39A ; [*1361.0020.0002] # LEVEL SLIDER +1F39B ; [*1362.0020.0002] # CONTROL KNOBS +1F39C ; [*1363.0020.0002] # BEAMED ASCENDING MUSICAL NOTES +1F39D ; [*1364.0020.0002] # BEAMED DESCENDING MUSICAL NOTES +1F39E ; [*1365.0020.0002] # FILM FRAMES +1F39F ; [*1366.0020.0002] # ADMISSION TICKETS +1F3A0 ; [*1367.0020.0002] # CAROUSEL HORSE +1F3A1 ; [*1368.0020.0002] # FERRIS WHEEL +1F3A2 ; [*1369.0020.0002] # ROLLER COASTER +1F3A3 ; [*136A.0020.0002] # FISHING POLE AND FISH +1F3A4 ; [*136B.0020.0002] # MICROPHONE +1F3A5 ; [*136C.0020.0002] # MOVIE CAMERA +1F3A6 ; [*136D.0020.0002] # CINEMA +1F3A7 ; [*136E.0020.0002] # HEADPHONE +1F3A8 ; [*136F.0020.0002] # ARTIST PALETTE +1F3A9 ; [*1370.0020.0002] # TOP HAT +1F3AA ; [*1371.0020.0002] # CIRCUS TENT +1F3AB ; [*1372.0020.0002] # TICKET +1F3AC ; [*1373.0020.0002] # CLAPPER BOARD +1F3AD ; [*1374.0020.0002] # PERFORMING ARTS +1F3AE ; [*1375.0020.0002] # VIDEO GAME +1F3AF ; [*1376.0020.0002] # DIRECT HIT +1F3B0 ; [*1377.0020.0002] # SLOT MACHINE +1F3B1 ; [*1378.0020.0002] # BILLIARDS +1F3B2 ; [*1379.0020.0002] # GAME DIE +1F3B3 ; [*137A.0020.0002] # BOWLING +1F3B4 ; [*137B.0020.0002] # FLOWER PLAYING CARDS +1F3B5 ; [*137C.0020.0002] # MUSICAL NOTE +1F3B6 ; [*137D.0020.0002] # MULTIPLE MUSICAL NOTES +1F3B7 ; [*137E.0020.0002] # SAXOPHONE +1F3B8 ; [*137F.0020.0002] # GUITAR +1F3B9 ; [*1380.0020.0002] # MUSICAL KEYBOARD +1F3BA ; [*1381.0020.0002] # TRUMPET +1F3BB ; [*1382.0020.0002] # VIOLIN +1F3BC ; [*1383.0020.0002] # MUSICAL SCORE +1F3BD ; [*1384.0020.0002] # RUNNING SHIRT WITH SASH +1F3BE ; [*1385.0020.0002] # TENNIS RACQUET AND BALL +1F3BF ; [*1386.0020.0002] # SKI AND SKI BOOT +1F3C0 ; [*1387.0020.0002] # BASKETBALL AND HOOP +1F3C1 ; [*1388.0020.0002] # CHEQUERED FLAG +1F3C2 ; [*1389.0020.0002] # SNOWBOARDER +1F3C3 ; [*138A.0020.0002] # RUNNER +1F3C4 ; [*138B.0020.0002] # SURFER +1F3C5 ; [*138C.0020.0002] # SPORTS MEDAL +1F3C6 ; [*138D.0020.0002] # TROPHY +1F3C7 ; [*138E.0020.0002] # HORSE RACING +1F3C8 ; [*138F.0020.0002] # AMERICAN FOOTBALL +1F3C9 ; [*1390.0020.0002] # RUGBY FOOTBALL +1F3CA ; [*1391.0020.0002] # SWIMMER +1F3CB ; [*1392.0020.0002] # WEIGHT LIFTER +1F3CC ; [*1393.0020.0002] # GOLFER +1F3CD ; [*1394.0020.0002] # RACING MOTORCYCLE +1F3CE ; [*1395.0020.0002] # RACING CAR +1F3CF ; [*1396.0020.0002] # CRICKET BAT AND BALL +1F3D0 ; [*1397.0020.0002] # VOLLEYBALL +1F3D1 ; [*1398.0020.0002] # FIELD HOCKEY STICK AND BALL +1F3D2 ; [*1399.0020.0002] # ICE HOCKEY STICK AND PUCK +1F3D3 ; [*139A.0020.0002] # TABLE TENNIS PADDLE AND BALL +1F3D4 ; [*139B.0020.0002] # SNOW CAPPED MOUNTAIN +1F3D5 ; [*139C.0020.0002] # CAMPING +1F3D6 ; [*139D.0020.0002] # BEACH WITH UMBRELLA +1F3D7 ; [*139E.0020.0002] # BUILDING CONSTRUCTION +1F3D8 ; [*139F.0020.0002] # HOUSE BUILDINGS +1F3D9 ; [*13A0.0020.0002] # CITYSCAPE +1F3DA ; [*13A1.0020.0002] # DERELICT HOUSE BUILDING +1F3DB ; [*13A2.0020.0002] # CLASSICAL BUILDING +1F3DC ; [*13A3.0020.0002] # DESERT +1F3DD ; [*13A4.0020.0002] # DESERT ISLAND +1F3DE ; [*13A5.0020.0002] # NATIONAL PARK +1F3DF ; [*13A6.0020.0002] # STADIUM +1F3E0 ; [*13A7.0020.0002] # HOUSE BUILDING +1F3E1 ; [*13A8.0020.0002] # HOUSE WITH GARDEN +1F3E2 ; [*13A9.0020.0002] # OFFICE BUILDING +1F3E3 ; [*13AA.0020.0002] # JAPANESE POST OFFICE +1F3E4 ; [*13AB.0020.0002] # EUROPEAN POST OFFICE +1F3E5 ; [*13AC.0020.0002] # HOSPITAL +1F3E6 ; [*13AD.0020.0002] # BANK +1F3E7 ; [*13AE.0020.0002] # AUTOMATED TELLER MACHINE +1F3E8 ; [*13AF.0020.0002] # HOTEL +1F3E9 ; [*13B0.0020.0002] # LOVE HOTEL +1F3EA ; [*13B1.0020.0002] # CONVENIENCE STORE +1F3EB ; [*13B2.0020.0002] # SCHOOL +1F3EC ; [*13B3.0020.0002] # DEPARTMENT STORE +1F3ED ; [*13B4.0020.0002] # FACTORY +1F3EE ; [*13B5.0020.0002] # IZAKAYA LANTERN +1F3EF ; [*13B6.0020.0002] # JAPANESE CASTLE +1F3F0 ; [*13B7.0020.0002] # EUROPEAN CASTLE +1F3F1 ; [*13B8.0020.0002] # WHITE PENNANT +1F3F2 ; [*13B9.0020.0002] # BLACK PENNANT +1F3F3 ; [*13BA.0020.0002] # WAVING WHITE FLAG +1F3F4 ; [*13BB.0020.0002] # WAVING BLACK FLAG +1F3F5 ; [*13BC.0020.0002] # ROSETTE +1F3F6 ; [*13BD.0020.0002] # BLACK ROSETTE +1F3F7 ; [*13BE.0020.0002] # LABEL +1F3F8 ; [*13BF.0020.0002] # BADMINTON RACQUET AND SHUTTLECOCK +1F3F9 ; [*13C0.0020.0002] # BOW AND ARROW +1F3FA ; [*13C1.0020.0002] # AMPHORA +1F3FB ; [*13C2.0020.0002] # EMOJI MODIFIER FITZPATRICK TYPE-1-2 +1F3FC ; [*13C3.0020.0002] # EMOJI MODIFIER FITZPATRICK TYPE-3 +1F3FD ; [*13C4.0020.0002] # EMOJI MODIFIER FITZPATRICK TYPE-4 +1F3FE ; [*13C5.0020.0002] # EMOJI MODIFIER FITZPATRICK TYPE-5 +1F3FF ; [*13C6.0020.0002] # EMOJI MODIFIER FITZPATRICK TYPE-6 +1F400 ; [*13C7.0020.0002] # RAT +1F401 ; [*13C8.0020.0002] # MOUSE +1F402 ; [*13C9.0020.0002] # OX +1F403 ; [*13CA.0020.0002] # WATER BUFFALO +1F404 ; [*13CB.0020.0002] # COW +1F405 ; [*13CC.0020.0002] # TIGER +1F406 ; [*13CD.0020.0002] # LEOPARD +1F407 ; [*13CE.0020.0002] # RABBIT +1F408 ; [*13CF.0020.0002] # CAT +1F409 ; [*13D0.0020.0002] # DRAGON +1F40A ; [*13D1.0020.0002] # CROCODILE +1F40B ; [*13D2.0020.0002] # WHALE +1F40C ; [*13D3.0020.0002] # SNAIL +1F40D ; [*13D4.0020.0002] # SNAKE +1F40E ; [*13D5.0020.0002] # HORSE +1F40F ; [*13D6.0020.0002] # RAM +1F410 ; [*13D7.0020.0002] # GOAT +1F411 ; [*13D8.0020.0002] # SHEEP +1F412 ; [*13D9.0020.0002] # MONKEY +1F413 ; [*13DA.0020.0002] # ROOSTER +1F414 ; [*13DB.0020.0002] # CHICKEN +1F415 ; [*13DC.0020.0002] # DOG +1F416 ; [*13DD.0020.0002] # PIG +1F417 ; [*13DE.0020.0002] # BOAR +1F418 ; [*13DF.0020.0002] # ELEPHANT +1F419 ; [*13E0.0020.0002] # OCTOPUS +1F41A ; [*13E1.0020.0002] # SPIRAL SHELL +1F41B ; [*13E2.0020.0002] # BUG +1F41C ; [*13E3.0020.0002] # ANT +1F41D ; [*13E4.0020.0002] # HONEYBEE +1F41E ; [*13E5.0020.0002] # LADY BEETLE +1F41F ; [*13E6.0020.0002] # FISH +1F420 ; [*13E7.0020.0002] # TROPICAL FISH +1F421 ; [*13E8.0020.0002] # BLOWFISH +1F422 ; [*13E9.0020.0002] # TURTLE +1F423 ; [*13EA.0020.0002] # HATCHING CHICK +1F424 ; [*13EB.0020.0002] # BABY CHICK +1F425 ; [*13EC.0020.0002] # FRONT-FACING BABY CHICK +1F426 ; [*13ED.0020.0002] # BIRD +1F427 ; [*13EE.0020.0002] # PENGUIN +1F428 ; [*13EF.0020.0002] # KOALA +1F429 ; [*13F0.0020.0002] # POODLE +1F42A ; [*13F1.0020.0002] # DROMEDARY CAMEL +1F42B ; [*13F2.0020.0002] # BACTRIAN CAMEL +1F42C ; [*13F3.0020.0002] # DOLPHIN +1F42D ; [*13F4.0020.0002] # MOUSE FACE +1F42E ; [*13F5.0020.0002] # COW FACE +1F42F ; [*13F6.0020.0002] # TIGER FACE +1F430 ; [*13F7.0020.0002] # RABBIT FACE +1F431 ; [*13F8.0020.0002] # CAT FACE +1F432 ; [*13F9.0020.0002] # DRAGON FACE +1F433 ; [*13FA.0020.0002] # SPOUTING WHALE +1F434 ; [*13FB.0020.0002] # HORSE FACE +1F435 ; [*13FC.0020.0002] # MONKEY FACE +1F436 ; [*13FD.0020.0002] # DOG FACE +1F437 ; [*13FE.0020.0002] # PIG FACE +1F438 ; [*13FF.0020.0002] # FROG FACE +1F439 ; [*1400.0020.0002] # HAMSTER FACE +1F43A ; [*1401.0020.0002] # WOLF FACE +1F43B ; [*1402.0020.0002] # BEAR FACE +1F43C ; [*1403.0020.0002] # PANDA FACE +1F43D ; [*1404.0020.0002] # PIG NOSE +1F43E ; [*1405.0020.0002] # PAW PRINTS +1F43F ; [*1406.0020.0002] # CHIPMUNK +1F440 ; [*1407.0020.0002] # EYES +1F441 ; [*1408.0020.0002] # EYE +1F442 ; [*1409.0020.0002] # EAR +1F443 ; [*140A.0020.0002] # NOSE +1F444 ; [*140B.0020.0002] # MOUTH +1F445 ; [*140C.0020.0002] # TONGUE +1F446 ; [*140D.0020.0002] # WHITE UP POINTING BACKHAND INDEX +1F447 ; [*140E.0020.0002] # WHITE DOWN POINTING BACKHAND INDEX +1F448 ; [*140F.0020.0002] # WHITE LEFT POINTING BACKHAND INDEX +1F449 ; [*1410.0020.0002] # WHITE RIGHT POINTING BACKHAND INDEX +1F44A ; [*1411.0020.0002] # FISTED HAND SIGN +1F44B ; [*1412.0020.0002] # WAVING HAND SIGN +1F44C ; [*1413.0020.0002] # OK HAND SIGN +1F44D ; [*1414.0020.0002] # THUMBS UP SIGN +1F44E ; [*1415.0020.0002] # THUMBS DOWN SIGN +1F44F ; [*1416.0020.0002] # CLAPPING HANDS SIGN +1F450 ; [*1417.0020.0002] # OPEN HANDS SIGN +1F451 ; [*1418.0020.0002] # CROWN +1F452 ; [*1419.0020.0002] # WOMANS HAT +1F453 ; [*141A.0020.0002] # EYEGLASSES +1F454 ; [*141B.0020.0002] # NECKTIE +1F455 ; [*141C.0020.0002] # T-SHIRT +1F456 ; [*141D.0020.0002] # JEANS +1F457 ; [*141E.0020.0002] # DRESS +1F458 ; [*141F.0020.0002] # KIMONO +1F459 ; [*1420.0020.0002] # BIKINI +1F45A ; [*1421.0020.0002] # WOMANS CLOTHES +1F45B ; [*1422.0020.0002] # PURSE +1F45C ; [*1423.0020.0002] # HANDBAG +1F45D ; [*1424.0020.0002] # POUCH +1F45E ; [*1425.0020.0002] # MANS SHOE +1F45F ; [*1426.0020.0002] # ATHLETIC SHOE +1F460 ; [*1427.0020.0002] # HIGH-HEELED SHOE +1F461 ; [*1428.0020.0002] # WOMANS SANDAL +1F462 ; [*1429.0020.0002] # WOMANS BOOTS +1F463 ; [*142A.0020.0002] # FOOTPRINTS +1F464 ; [*142B.0020.0002] # BUST IN SILHOUETTE +1F465 ; [*142C.0020.0002] # BUSTS IN SILHOUETTE +1F466 ; [*142D.0020.0002] # BOY +1F467 ; [*142E.0020.0002] # GIRL +1F468 ; [*142F.0020.0002] # MAN +1F469 ; [*1430.0020.0002] # WOMAN +1F46A ; [*1431.0020.0002] # FAMILY +1F46B ; [*1432.0020.0002] # MAN AND WOMAN HOLDING HANDS +1F46C ; [*1433.0020.0002] # TWO MEN HOLDING HANDS +1F46D ; [*1434.0020.0002] # TWO WOMEN HOLDING HANDS +1F46E ; [*1435.0020.0002] # POLICE OFFICER +1F46F ; [*1436.0020.0002] # WOMAN WITH BUNNY EARS +1F470 ; [*1437.0020.0002] # BRIDE WITH VEIL +1F471 ; [*1438.0020.0002] # PERSON WITH BLOND HAIR +1F472 ; [*1439.0020.0002] # MAN WITH GUA PI MAO +1F473 ; [*143A.0020.0002] # MAN WITH TURBAN +1F474 ; [*143B.0020.0002] # OLDER MAN +1F475 ; [*143C.0020.0002] # OLDER WOMAN +1F476 ; [*143D.0020.0002] # BABY +1F477 ; [*143E.0020.0002] # CONSTRUCTION WORKER +1F478 ; [*143F.0020.0002] # PRINCESS +1F479 ; [*1440.0020.0002] # JAPANESE OGRE +1F47A ; [*1441.0020.0002] # JAPANESE GOBLIN +1F47B ; [*1442.0020.0002] # GHOST +1F47C ; [*1443.0020.0002] # BABY ANGEL +1F47D ; [*1444.0020.0002] # EXTRATERRESTRIAL ALIEN +1F47E ; [*1445.0020.0002] # ALIEN MONSTER +1F47F ; [*1446.0020.0002] # IMP +1F480 ; [*1447.0020.0002] # SKULL +1F481 ; [*1448.0020.0002] # INFORMATION DESK PERSON +1F482 ; [*1449.0020.0002] # GUARDSMAN +1F483 ; [*144A.0020.0002] # DANCER +1F484 ; [*144B.0020.0002] # LIPSTICK +1F485 ; [*144C.0020.0002] # NAIL POLISH +1F486 ; [*144D.0020.0002] # FACE MASSAGE +1F487 ; [*144E.0020.0002] # HAIRCUT +1F488 ; [*144F.0020.0002] # BARBER POLE +1F489 ; [*1450.0020.0002] # SYRINGE +1F48A ; [*1451.0020.0002] # PILL +1F48B ; [*1452.0020.0002] # KISS MARK +1F48C ; [*1453.0020.0002] # LOVE LETTER +1F48D ; [*1454.0020.0002] # RING +1F48E ; [*1455.0020.0002] # GEM STONE +1F48F ; [*1456.0020.0002] # KISS +1F490 ; [*1457.0020.0002] # BOUQUET +1F491 ; [*1458.0020.0002] # COUPLE WITH HEART +1F492 ; [*1459.0020.0002] # WEDDING +1F493 ; [*145A.0020.0002] # BEATING HEART +1F494 ; [*145B.0020.0002] # BROKEN HEART +1F495 ; [*145C.0020.0002] # TWO HEARTS +1F496 ; [*145D.0020.0002] # SPARKLING HEART +1F497 ; [*145E.0020.0002] # GROWING HEART +1F498 ; [*145F.0020.0002] # HEART WITH ARROW +1F499 ; [*1460.0020.0002] # BLUE HEART +1F49A ; [*1461.0020.0002] # GREEN HEART +1F49B ; [*1462.0020.0002] # YELLOW HEART +1F49C ; [*1463.0020.0002] # PURPLE HEART +1F49D ; [*1464.0020.0002] # HEART WITH RIBBON +1F49E ; [*1465.0020.0002] # REVOLVING HEARTS +1F49F ; [*1466.0020.0002] # HEART DECORATION +1F4A0 ; [*1467.0020.0002] # DIAMOND SHAPE WITH A DOT INSIDE +1F4A1 ; [*1468.0020.0002] # ELECTRIC LIGHT BULB +1F4A2 ; [*1469.0020.0002] # ANGER SYMBOL +1F4A3 ; [*146A.0020.0002] # BOMB +1F4A4 ; [*146B.0020.0002] # SLEEPING SYMBOL +1F4A5 ; [*146C.0020.0002] # COLLISION SYMBOL +1F4A6 ; [*146D.0020.0002] # SPLASHING SWEAT SYMBOL +1F4A7 ; [*146E.0020.0002] # DROPLET +1F4A8 ; [*146F.0020.0002] # DASH SYMBOL +1F4A9 ; [*1470.0020.0002] # PILE OF POO +1F4AA ; [*1471.0020.0002] # FLEXED BICEPS +1F4AB ; [*1472.0020.0002] # DIZZY SYMBOL +1F4AC ; [*1473.0020.0002] # SPEECH BALLOON +1F4AD ; [*1474.0020.0002] # THOUGHT BALLOON +1F4AE ; [*1475.0020.0002] # WHITE FLOWER +1F4AF ; [*1476.0020.0002] # HUNDRED POINTS SYMBOL +1F4B0 ; [*1477.0020.0002] # MONEY BAG +1F4B1 ; [*1478.0020.0002] # CURRENCY EXCHANGE +1F4B2 ; [*1479.0020.0002] # HEAVY DOLLAR SIGN +1F4B3 ; [*147A.0020.0002] # CREDIT CARD +1F4B4 ; [*147B.0020.0002] # BANKNOTE WITH YEN SIGN +1F4B5 ; [*147C.0020.0002] # BANKNOTE WITH DOLLAR SIGN +1F4B6 ; [*147D.0020.0002] # BANKNOTE WITH EURO SIGN +1F4B7 ; [*147E.0020.0002] # BANKNOTE WITH POUND SIGN +1F4B8 ; [*147F.0020.0002] # MONEY WITH WINGS +1F4B9 ; [*1480.0020.0002] # CHART WITH UPWARDS TREND AND YEN SIGN +1F4BA ; [*1481.0020.0002] # SEAT +1F4BB ; [*1482.0020.0002] # PERSONAL COMPUTER +1F4BC ; [*1483.0020.0002] # BRIEFCASE +1F4BD ; [*1484.0020.0002] # MINIDISC +1F4BE ; [*1485.0020.0002] # FLOPPY DISK +1F4BF ; [*1486.0020.0002] # OPTICAL DISC +1F4C0 ; [*1487.0020.0002] # DVD +1F4C1 ; [*1488.0020.0002] # FILE FOLDER +1F4C2 ; [*1489.0020.0002] # OPEN FILE FOLDER +1F4C3 ; [*148A.0020.0002] # PAGE WITH CURL +1F4C4 ; [*148B.0020.0002] # PAGE FACING UP +1F4C5 ; [*148C.0020.0002] # CALENDAR +1F4C6 ; [*148D.0020.0002] # TEAR-OFF CALENDAR +1F4C7 ; [*148E.0020.0002] # CARD INDEX +1F4C8 ; [*148F.0020.0002] # CHART WITH UPWARDS TREND +1F4C9 ; [*1490.0020.0002] # CHART WITH DOWNWARDS TREND +1F4CA ; [*1491.0020.0002] # BAR CHART +1F4CB ; [*1492.0020.0002] # CLIPBOARD +1F4CC ; [*1493.0020.0002] # PUSHPIN +1F4CD ; [*1494.0020.0002] # ROUND PUSHPIN +1F4CE ; [*1495.0020.0002] # PAPERCLIP +1F4CF ; [*1496.0020.0002] # STRAIGHT RULER +1F4D0 ; [*1497.0020.0002] # TRIANGULAR RULER +1F4D1 ; [*1498.0020.0002] # BOOKMARK TABS +1F4D2 ; [*1499.0020.0002] # LEDGER +1F4D3 ; [*149A.0020.0002] # NOTEBOOK +1F4D4 ; [*149B.0020.0002] # NOTEBOOK WITH DECORATIVE COVER +1F4D5 ; [*149C.0020.0002] # CLOSED BOOK +1F4D6 ; [*149D.0020.0002] # OPEN BOOK +1F4D7 ; [*149E.0020.0002] # GREEN BOOK +1F4D8 ; [*149F.0020.0002] # BLUE BOOK +1F4D9 ; [*14A0.0020.0002] # ORANGE BOOK +1F4DA ; [*14A1.0020.0002] # BOOKS +1F4DB ; [*14A2.0020.0002] # NAME BADGE +1F4DC ; [*14A3.0020.0002] # SCROLL +1F4DD ; [*14A4.0020.0002] # MEMO +1F4DE ; [*14A5.0020.0002] # TELEPHONE RECEIVER +1F4DF ; [*14A6.0020.0002] # PAGER +1F4E0 ; [*14A7.0020.0002] # FAX MACHINE +1F4E1 ; [*14A8.0020.0002] # SATELLITE ANTENNA +1F4E2 ; [*14A9.0020.0002] # PUBLIC ADDRESS LOUDSPEAKER +1F4E3 ; [*14AA.0020.0002] # CHEERING MEGAPHONE +1F4E4 ; [*14AB.0020.0002] # OUTBOX TRAY +1F4E5 ; [*14AC.0020.0002] # INBOX TRAY +1F4E6 ; [*14AD.0020.0002] # PACKAGE +1F4E7 ; [*14AE.0020.0002] # E-MAIL SYMBOL +1F4E8 ; [*14AF.0020.0002] # INCOMING ENVELOPE +1F4E9 ; [*14B0.0020.0002] # ENVELOPE WITH DOWNWARDS ARROW ABOVE +1F4EA ; [*14B1.0020.0002] # CLOSED MAILBOX WITH LOWERED FLAG +1F4EB ; [*14B2.0020.0002] # CLOSED MAILBOX WITH RAISED FLAG +1F4EC ; [*14B3.0020.0002] # OPEN MAILBOX WITH RAISED FLAG +1F4ED ; [*14B4.0020.0002] # OPEN MAILBOX WITH LOWERED FLAG +1F4EE ; [*14B5.0020.0002] # POSTBOX +1F4EF ; [*14B6.0020.0002] # POSTAL HORN +1F4F0 ; [*14B7.0020.0002] # NEWSPAPER +1F4F1 ; [*14B8.0020.0002] # MOBILE PHONE +1F4F2 ; [*14B9.0020.0002] # MOBILE PHONE WITH RIGHTWARDS ARROW AT LEFT +1F4F3 ; [*14BA.0020.0002] # VIBRATION MODE +1F4F4 ; [*14BB.0020.0002] # MOBILE PHONE OFF +1F4F5 ; [*14BC.0020.0002] # NO MOBILE PHONES +1F4F6 ; [*14BD.0020.0002] # ANTENNA WITH BARS +1F4F7 ; [*14BE.0020.0002] # CAMERA +1F4F8 ; [*14BF.0020.0002] # CAMERA WITH FLASH +1F4F9 ; [*14C0.0020.0002] # VIDEO CAMERA +1F4FA ; [*14C1.0020.0002] # TELEVISION +1F4FB ; [*14C2.0020.0002] # RADIO +1F4FC ; [*14C3.0020.0002] # VIDEOCASSETTE +1F4FD ; [*14C4.0020.0002] # FILM PROJECTOR +1F4FE ; [*14C5.0020.0002] # PORTABLE STEREO +1F4FF ; [*14C6.0020.0002] # PRAYER BEADS +1F500 ; [*14C7.0020.0002] # TWISTED RIGHTWARDS ARROWS +1F501 ; [*14C8.0020.0002] # CLOCKWISE RIGHTWARDS AND LEFTWARDS OPEN CIRCLE ARROWS +1F502 ; [*14C9.0020.0002] # CLOCKWISE RIGHTWARDS AND LEFTWARDS OPEN CIRCLE ARROWS WITH CIRCLED ONE OVERLAY +1F503 ; [*14CA.0020.0002] # CLOCKWISE DOWNWARDS AND UPWARDS OPEN CIRCLE ARROWS +1F504 ; [*14CB.0020.0002] # ANTICLOCKWISE DOWNWARDS AND UPWARDS OPEN CIRCLE ARROWS +1F505 ; [*14CC.0020.0002] # LOW BRIGHTNESS SYMBOL +1F506 ; [*14CD.0020.0002] # HIGH BRIGHTNESS SYMBOL +1F507 ; [*14CE.0020.0002] # SPEAKER WITH CANCELLATION STROKE +1F508 ; [*14CF.0020.0002] # SPEAKER +1F509 ; [*14D0.0020.0002] # SPEAKER WITH ONE SOUND WAVE +1F50A ; [*14D1.0020.0002] # SPEAKER WITH THREE SOUND WAVES +1F50B ; [*14D2.0020.0002] # BATTERY +1F50C ; [*14D3.0020.0002] # ELECTRIC PLUG +1F50D ; [*14D4.0020.0002] # LEFT-POINTING MAGNIFYING GLASS +1F50E ; [*14D5.0020.0002] # RIGHT-POINTING MAGNIFYING GLASS +1F50F ; [*14D6.0020.0002] # LOCK WITH INK PEN +1F510 ; [*14D7.0020.0002] # CLOSED LOCK WITH KEY +1F511 ; [*14D8.0020.0002] # KEY +1F512 ; [*14D9.0020.0002] # LOCK +1F513 ; [*14DA.0020.0002] # OPEN LOCK +1F514 ; [*14DB.0020.0002] # BELL +1F515 ; [*14DC.0020.0002] # BELL WITH CANCELLATION STROKE +1F516 ; [*14DD.0020.0002] # BOOKMARK +1F517 ; [*14DE.0020.0002] # LINK SYMBOL +1F518 ; [*14DF.0020.0002] # RADIO BUTTON +1F519 ; [*14E0.0020.0002] # BACK WITH LEFTWARDS ARROW ABOVE +1F51A ; [*14E1.0020.0002] # END WITH LEFTWARDS ARROW ABOVE +1F51B ; [*14E2.0020.0002] # ON WITH EXCLAMATION MARK WITH LEFT RIGHT ARROW ABOVE +1F51C ; [*14E3.0020.0002] # SOON WITH RIGHTWARDS ARROW ABOVE +1F51D ; [*14E4.0020.0002] # TOP WITH UPWARDS ARROW ABOVE +1F51E ; [*14E5.0020.0002] # NO ONE UNDER EIGHTEEN SYMBOL +1F51F ; [*14E6.0020.0002] # KEYCAP TEN +1F520 ; [*14E7.0020.0002] # INPUT SYMBOL FOR LATIN CAPITAL LETTERS +1F521 ; [*14E8.0020.0002] # INPUT SYMBOL FOR LATIN SMALL LETTERS +1F522 ; [*14E9.0020.0002] # INPUT SYMBOL FOR NUMBERS +1F523 ; [*14EA.0020.0002] # INPUT SYMBOL FOR SYMBOLS +1F524 ; [*14EB.0020.0002] # INPUT SYMBOL FOR LATIN LETTERS +1F525 ; [*14EC.0020.0002] # FIRE +1F526 ; [*14ED.0020.0002] # ELECTRIC TORCH +1F527 ; [*14EE.0020.0002] # WRENCH +1F528 ; [*14EF.0020.0002] # HAMMER +1F529 ; [*14F0.0020.0002] # NUT AND BOLT +1F52A ; [*14F1.0020.0002] # HOCHO +1F52B ; [*14F2.0020.0002] # PISTOL +1F52C ; [*14F3.0020.0002] # MICROSCOPE +1F52D ; [*14F4.0020.0002] # TELESCOPE +1F52E ; [*14F5.0020.0002] # CRYSTAL BALL +1F52F ; [*14F6.0020.0002] # SIX POINTED STAR WITH MIDDLE DOT +1F530 ; [*14F7.0020.0002] # JAPANESE SYMBOL FOR BEGINNER +1F531 ; [*14F8.0020.0002] # TRIDENT EMBLEM +1F532 ; [*14F9.0020.0002] # BLACK SQUARE BUTTON +1F533 ; [*14FA.0020.0002] # WHITE SQUARE BUTTON +1F534 ; [*14FB.0020.0002] # LARGE RED CIRCLE +1F535 ; [*14FC.0020.0002] # LARGE BLUE CIRCLE +1F536 ; [*14FD.0020.0002] # LARGE ORANGE DIAMOND +1F537 ; [*14FE.0020.0002] # LARGE BLUE DIAMOND +1F538 ; [*14FF.0020.0002] # SMALL ORANGE DIAMOND +1F539 ; [*1500.0020.0002] # SMALL BLUE DIAMOND +1F53A ; [*1501.0020.0002] # UP-POINTING RED TRIANGLE +1F53B ; [*1502.0020.0002] # DOWN-POINTING RED TRIANGLE +1F53C ; [*1503.0020.0002] # UP-POINTING SMALL RED TRIANGLE +1F53D ; [*1504.0020.0002] # DOWN-POINTING SMALL RED TRIANGLE +1F53E ; [*1505.0020.0002] # LOWER RIGHT SHADOWED WHITE CIRCLE +1F53F ; [*1506.0020.0002] # UPPER RIGHT SHADOWED WHITE CIRCLE +1F540 ; [*1507.0020.0002] # CIRCLED CROSS POMMEE +1F541 ; [*1508.0020.0002] # CROSS POMMEE WITH HALF-CIRCLE BELOW +1F542 ; [*1509.0020.0002] # CROSS POMMEE +1F543 ; [*150A.0020.0002] # NOTCHED LEFT SEMICIRCLE WITH THREE DOTS +1F544 ; [*150B.0020.0002] # NOTCHED RIGHT SEMICIRCLE WITH THREE DOTS +1F545 ; [*150C.0020.0002] # SYMBOL FOR MARKS CHAPTER +1F546 ; [*150D.0020.0002] # WHITE LATIN CROSS +1F547 ; [*150E.0020.0002] # HEAVY LATIN CROSS +1F548 ; [*150F.0020.0002] # CELTIC CROSS +1F549 ; [*1510.0020.0002] # OM SYMBOL +1F54A ; [*1511.0020.0002] # DOVE OF PEACE +1F54B ; [*1512.0020.0002] # KAABA +1F54C ; [*1513.0020.0002] # MOSQUE +1F54D ; [*1514.0020.0002] # SYNAGOGUE +1F54E ; [*1515.0020.0002] # MENORAH WITH NINE BRANCHES +1F54F ; [*1516.0020.0002] # BOWL OF HYGIEIA +1F550 ; [*1517.0020.0002] # CLOCK FACE ONE OCLOCK +1F551 ; [*1518.0020.0002] # CLOCK FACE TWO OCLOCK +1F552 ; [*1519.0020.0002] # CLOCK FACE THREE OCLOCK +1F553 ; [*151A.0020.0002] # CLOCK FACE FOUR OCLOCK +1F554 ; [*151B.0020.0002] # CLOCK FACE FIVE OCLOCK +1F555 ; [*151C.0020.0002] # CLOCK FACE SIX OCLOCK +1F556 ; [*151D.0020.0002] # CLOCK FACE SEVEN OCLOCK +1F557 ; [*151E.0020.0002] # CLOCK FACE EIGHT OCLOCK +1F558 ; [*151F.0020.0002] # CLOCK FACE NINE OCLOCK +1F559 ; [*1520.0020.0002] # CLOCK FACE TEN OCLOCK +1F55A ; [*1521.0020.0002] # CLOCK FACE ELEVEN OCLOCK +1F55B ; [*1522.0020.0002] # CLOCK FACE TWELVE OCLOCK +1F55C ; [*1523.0020.0002] # CLOCK FACE ONE-THIRTY +1F55D ; [*1524.0020.0002] # CLOCK FACE TWO-THIRTY +1F55E ; [*1525.0020.0002] # CLOCK FACE THREE-THIRTY +1F55F ; [*1526.0020.0002] # CLOCK FACE FOUR-THIRTY +1F560 ; [*1527.0020.0002] # CLOCK FACE FIVE-THIRTY +1F561 ; [*1528.0020.0002] # CLOCK FACE SIX-THIRTY +1F562 ; [*1529.0020.0002] # CLOCK FACE SEVEN-THIRTY +1F563 ; [*152A.0020.0002] # CLOCK FACE EIGHT-THIRTY +1F564 ; [*152B.0020.0002] # CLOCK FACE NINE-THIRTY +1F565 ; [*152C.0020.0002] # CLOCK FACE TEN-THIRTY +1F566 ; [*152D.0020.0002] # CLOCK FACE ELEVEN-THIRTY +1F567 ; [*152E.0020.0002] # CLOCK FACE TWELVE-THIRTY +1F568 ; [*152F.0020.0002] # RIGHT SPEAKER +1F569 ; [*1530.0020.0002] # RIGHT SPEAKER WITH ONE SOUND WAVE +1F56A ; [*1531.0020.0002] # RIGHT SPEAKER WITH THREE SOUND WAVES +1F56B ; [*1532.0020.0002] # BULLHORN +1F56C ; [*1533.0020.0002] # BULLHORN WITH SOUND WAVES +1F56D ; [*1534.0020.0002] # RINGING BELL +1F56E ; [*1535.0020.0002] # BOOK +1F56F ; [*1536.0020.0002] # CANDLE +1F570 ; [*1537.0020.0002] # MANTELPIECE CLOCK +1F571 ; [*1538.0020.0002] # BLACK SKULL AND CROSSBONES +1F572 ; [*1539.0020.0002] # NO PIRACY +1F573 ; [*153A.0020.0002] # HOLE +1F574 ; [*153B.0020.0002] # MAN IN BUSINESS SUIT LEVITATING +1F575 ; [*153C.0020.0002] # SLEUTH OR SPY +1F576 ; [*153D.0020.0002] # DARK SUNGLASSES +1F577 ; [*153E.0020.0002] # SPIDER +1F578 ; [*153F.0020.0002] # SPIDER WEB +1F579 ; [*1540.0020.0002] # JOYSTICK +1F57A ; [*1541.0020.0002] # MAN DANCING +1F57B ; [*1542.0020.0002] # LEFT HAND TELEPHONE RECEIVER +1F57C ; [*1543.0020.0002] # TELEPHONE RECEIVER WITH PAGE +1F57D ; [*1544.0020.0002] # RIGHT HAND TELEPHONE RECEIVER +1F57E ; [*1545.0020.0002] # WHITE TOUCHTONE TELEPHONE +1F57F ; [*1546.0020.0002] # BLACK TOUCHTONE TELEPHONE +1F580 ; [*1547.0020.0002] # TELEPHONE ON TOP OF MODEM +1F581 ; [*1548.0020.0002] # CLAMSHELL MOBILE PHONE +1F582 ; [*1549.0020.0002] # BACK OF ENVELOPE +1F583 ; [*154A.0020.0002] # STAMPED ENVELOPE +1F584 ; [*154B.0020.0002] # ENVELOPE WITH LIGHTNING +1F585 ; [*154C.0020.0002] # FLYING ENVELOPE +1F586 ; [*154D.0020.0002] # PEN OVER STAMPED ENVELOPE +1F587 ; [*154E.0020.0002] # LINKED PAPERCLIPS +1F588 ; [*154F.0020.0002] # BLACK PUSHPIN +1F589 ; [*1550.0020.0002] # LOWER LEFT PENCIL +1F58A ; [*1551.0020.0002] # LOWER LEFT BALLPOINT PEN +1F58B ; [*1552.0020.0002] # LOWER LEFT FOUNTAIN PEN +1F58C ; [*1553.0020.0002] # LOWER LEFT PAINTBRUSH +1F58D ; [*1554.0020.0002] # LOWER LEFT CRAYON +1F58E ; [*1555.0020.0002] # LEFT WRITING HAND +1F58F ; [*1556.0020.0002] # TURNED OK HAND SIGN +1F590 ; [*1557.0020.0002] # RAISED HAND WITH FINGERS SPLAYED +1F591 ; [*1558.0020.0002] # REVERSED RAISED HAND WITH FINGERS SPLAYED +1F592 ; [*1559.0020.0002] # REVERSED THUMBS UP SIGN +1F593 ; [*155A.0020.0002] # REVERSED THUMBS DOWN SIGN +1F594 ; [*155B.0020.0002] # REVERSED VICTORY HAND +1F595 ; [*155C.0020.0002] # REVERSED HAND WITH MIDDLE FINGER EXTENDED +1F596 ; [*155D.0020.0002] # RAISED HAND WITH PART BETWEEN MIDDLE AND RING FINGERS +1F597 ; [*155E.0020.0002] # WHITE DOWN POINTING LEFT HAND INDEX +1F598 ; [*155F.0020.0002] # SIDEWAYS WHITE LEFT POINTING INDEX +1F599 ; [*1560.0020.0002] # SIDEWAYS WHITE RIGHT POINTING INDEX +1F59A ; [*1561.0020.0002] # SIDEWAYS BLACK LEFT POINTING INDEX +1F59B ; [*1562.0020.0002] # SIDEWAYS BLACK RIGHT POINTING INDEX +1F59C ; [*1563.0020.0002] # BLACK LEFT POINTING BACKHAND INDEX +1F59D ; [*1564.0020.0002] # BLACK RIGHT POINTING BACKHAND INDEX +1F59E ; [*1565.0020.0002] # SIDEWAYS WHITE UP POINTING INDEX +1F59F ; [*1566.0020.0002] # SIDEWAYS WHITE DOWN POINTING INDEX +1F5A0 ; [*1567.0020.0002] # SIDEWAYS BLACK UP POINTING INDEX +1F5A1 ; [*1568.0020.0002] # SIDEWAYS BLACK DOWN POINTING INDEX +1F5A2 ; [*1569.0020.0002] # BLACK UP POINTING BACKHAND INDEX +1F5A3 ; [*156A.0020.0002] # BLACK DOWN POINTING BACKHAND INDEX +1F5A4 ; [*156B.0020.0002] # BLACK HEART +1F5A5 ; [*156C.0020.0002] # DESKTOP COMPUTER +1F5A6 ; [*156D.0020.0002] # KEYBOARD AND MOUSE +1F5A7 ; [*156E.0020.0002] # THREE NETWORKED COMPUTERS +1F5A8 ; [*156F.0020.0002] # PRINTER +1F5A9 ; [*1570.0020.0002] # POCKET CALCULATOR +1F5AA ; [*1571.0020.0002] # BLACK HARD SHELL FLOPPY DISK +1F5AB ; [*1572.0020.0002] # WHITE HARD SHELL FLOPPY DISK +1F5AC ; [*1573.0020.0002] # SOFT SHELL FLOPPY DISK +1F5AD ; [*1574.0020.0002] # TAPE CARTRIDGE +1F5AE ; [*1575.0020.0002] # WIRED KEYBOARD +1F5AF ; [*1576.0020.0002] # ONE BUTTON MOUSE +1F5B0 ; [*1577.0020.0002] # TWO BUTTON MOUSE +1F5B1 ; [*1578.0020.0002] # THREE BUTTON MOUSE +1F5B2 ; [*1579.0020.0002] # TRACKBALL +1F5B3 ; [*157A.0020.0002] # OLD PERSONAL COMPUTER +1F5B4 ; [*157B.0020.0002] # HARD DISK +1F5B5 ; [*157C.0020.0002] # SCREEN +1F5B6 ; [*157D.0020.0002] # PRINTER ICON +1F5B7 ; [*157E.0020.0002] # FAX ICON +1F5B8 ; [*157F.0020.0002] # OPTICAL DISC ICON +1F5B9 ; [*1580.0020.0002] # DOCUMENT WITH TEXT +1F5BA ; [*1581.0020.0002] # DOCUMENT WITH TEXT AND PICTURE +1F5BB ; [*1582.0020.0002] # DOCUMENT WITH PICTURE +1F5BC ; [*1583.0020.0002] # FRAME WITH PICTURE +1F5BD ; [*1584.0020.0002] # FRAME WITH TILES +1F5BE ; [*1585.0020.0002] # FRAME WITH AN X +1F5BF ; [*1586.0020.0002] # BLACK FOLDER +1F5C0 ; [*1587.0020.0002] # FOLDER +1F5C1 ; [*1588.0020.0002] # OPEN FOLDER +1F5C2 ; [*1589.0020.0002] # CARD INDEX DIVIDERS +1F5C3 ; [*158A.0020.0002] # CARD FILE BOX +1F5C4 ; [*158B.0020.0002] # FILE CABINET +1F5C5 ; [*158C.0020.0002] # EMPTY NOTE +1F5C6 ; [*158D.0020.0002] # EMPTY NOTE PAGE +1F5C7 ; [*158E.0020.0002] # EMPTY NOTE PAD +1F5C8 ; [*158F.0020.0002] # NOTE +1F5C9 ; [*1590.0020.0002] # NOTE PAGE +1F5CA ; [*1591.0020.0002] # NOTE PAD +1F5CB ; [*1592.0020.0002] # EMPTY DOCUMENT +1F5CC ; [*1593.0020.0002] # EMPTY PAGE +1F5CD ; [*1594.0020.0002] # EMPTY PAGES +1F5CE ; [*1595.0020.0002] # DOCUMENT +1F5CF ; [*1596.0020.0002] # PAGE +1F5D0 ; [*1597.0020.0002] # PAGES +1F5D1 ; [*1598.0020.0002] # WASTEBASKET +1F5D2 ; [*1599.0020.0002] # SPIRAL NOTE PAD +1F5D3 ; [*159A.0020.0002] # SPIRAL CALENDAR PAD +1F5D4 ; [*159B.0020.0002] # DESKTOP WINDOW +1F5D5 ; [*159C.0020.0002] # MINIMIZE +1F5D6 ; [*159D.0020.0002] # MAXIMIZE +1F5D7 ; [*159E.0020.0002] # OVERLAP +1F5D8 ; [*159F.0020.0002] # CLOCKWISE RIGHT AND LEFT SEMICIRCLE ARROWS +1F5D9 ; [*15A0.0020.0002] # CANCELLATION X +1F5DA ; [*15A1.0020.0002] # INCREASE FONT SIZE SYMBOL +1F5DB ; [*15A2.0020.0002] # DECREASE FONT SIZE SYMBOL +1F5DC ; [*15A3.0020.0002] # COMPRESSION +1F5DD ; [*15A4.0020.0002] # OLD KEY +1F5DE ; [*15A5.0020.0002] # ROLLED-UP NEWSPAPER +1F5DF ; [*15A6.0020.0002] # PAGE WITH CIRCLED TEXT +1F5E0 ; [*15A7.0020.0002] # STOCK CHART +1F5E1 ; [*15A8.0020.0002] # DAGGER KNIFE +1F5E2 ; [*15A9.0020.0002] # LIPS +1F5E3 ; [*15AA.0020.0002] # SPEAKING HEAD IN SILHOUETTE +1F5E4 ; [*15AB.0020.0002] # THREE RAYS ABOVE +1F5E5 ; [*15AC.0020.0002] # THREE RAYS BELOW +1F5E6 ; [*15AD.0020.0002] # THREE RAYS LEFT +1F5E7 ; [*15AE.0020.0002] # THREE RAYS RIGHT +1F5E8 ; [*15AF.0020.0002] # LEFT SPEECH BUBBLE +1F5E9 ; [*15B0.0020.0002] # RIGHT SPEECH BUBBLE +1F5EA ; [*15B1.0020.0002] # TWO SPEECH BUBBLES +1F5EB ; [*15B2.0020.0002] # THREE SPEECH BUBBLES +1F5EC ; [*15B3.0020.0002] # LEFT THOUGHT BUBBLE +1F5ED ; [*15B4.0020.0002] # RIGHT THOUGHT BUBBLE +1F5EE ; [*15B5.0020.0002] # LEFT ANGER BUBBLE +1F5EF ; [*15B6.0020.0002] # RIGHT ANGER BUBBLE +1F5F0 ; [*15B7.0020.0002] # MOOD BUBBLE +1F5F1 ; [*15B8.0020.0002] # LIGHTNING MOOD BUBBLE +1F5F2 ; [*15B9.0020.0002] # LIGHTNING MOOD +1F5F3 ; [*15BA.0020.0002] # BALLOT BOX WITH BALLOT +1F5F4 ; [*15BB.0020.0002] # BALLOT SCRIPT X +1F5F5 ; [*15BC.0020.0002] # BALLOT BOX WITH SCRIPT X +1F5F6 ; [*15BD.0020.0002] # BALLOT BOLD SCRIPT X +1F5F7 ; [*15BE.0020.0002] # BALLOT BOX WITH BOLD SCRIPT X +1F5F8 ; [*15BF.0020.0002] # LIGHT CHECK MARK +1F5F9 ; [*15C0.0020.0002] # BALLOT BOX WITH BOLD CHECK +1F5FA ; [*15C1.0020.0002] # WORLD MAP +1F5FB ; [*15C2.0020.0002] # MOUNT FUJI +1F5FC ; [*15C3.0020.0002] # TOKYO TOWER +1F5FD ; [*15C4.0020.0002] # STATUE OF LIBERTY +1F5FE ; [*15C5.0020.0002] # SILHOUETTE OF JAPAN +1F5FF ; [*15C6.0020.0002] # MOYAI +1F600 ; [*165B.0020.0002] # GRINNING FACE +1F601 ; [*165C.0020.0002] # GRINNING FACE WITH SMILING EYES +1F602 ; [*165D.0020.0002] # FACE WITH TEARS OF JOY +1F603 ; [*165E.0020.0002] # SMILING FACE WITH OPEN MOUTH +1F604 ; [*165F.0020.0002] # SMILING FACE WITH OPEN MOUTH AND SMILING EYES +1F605 ; [*1660.0020.0002] # SMILING FACE WITH OPEN MOUTH AND COLD SWEAT +1F606 ; [*1661.0020.0002] # SMILING FACE WITH OPEN MOUTH AND TIGHTLY-CLOSED EYES +1F607 ; [*1662.0020.0002] # SMILING FACE WITH HALO +1F608 ; [*1663.0020.0002] # SMILING FACE WITH HORNS +1F609 ; [*1664.0020.0002] # WINKING FACE +1F60A ; [*1665.0020.0002] # SMILING FACE WITH SMILING EYES +1F60B ; [*1666.0020.0002] # FACE SAVOURING DELICIOUS FOOD +1F60C ; [*1667.0020.0002] # RELIEVED FACE +1F60D ; [*1668.0020.0002] # SMILING FACE WITH HEART-SHAPED EYES +1F60E ; [*1669.0020.0002] # SMILING FACE WITH SUNGLASSES +1F60F ; [*166A.0020.0002] # SMIRKING FACE +1F610 ; [*166B.0020.0002] # NEUTRAL FACE +1F611 ; [*166C.0020.0002] # EXPRESSIONLESS FACE +1F612 ; [*166D.0020.0002] # UNAMUSED FACE +1F613 ; [*166E.0020.0002] # FACE WITH COLD SWEAT +1F614 ; [*166F.0020.0002] # PENSIVE FACE +1F615 ; [*1670.0020.0002] # CONFUSED FACE +1F616 ; [*1671.0020.0002] # CONFOUNDED FACE +1F617 ; [*1672.0020.0002] # KISSING FACE +1F618 ; [*1673.0020.0002] # FACE THROWING A KISS +1F619 ; [*1674.0020.0002] # KISSING FACE WITH SMILING EYES +1F61A ; [*1675.0020.0002] # KISSING FACE WITH CLOSED EYES +1F61B ; [*1676.0020.0002] # FACE WITH STUCK-OUT TONGUE +1F61C ; [*1677.0020.0002] # FACE WITH STUCK-OUT TONGUE AND WINKING EYE +1F61D ; [*1678.0020.0002] # FACE WITH STUCK-OUT TONGUE AND TIGHTLY-CLOSED EYES +1F61E ; [*1679.0020.0002] # DISAPPOINTED FACE +1F61F ; [*167A.0020.0002] # WORRIED FACE +1F620 ; [*167B.0020.0002] # ANGRY FACE +1F621 ; [*167C.0020.0002] # POUTING FACE +1F622 ; [*167D.0020.0002] # CRYING FACE +1F623 ; [*167E.0020.0002] # PERSEVERING FACE +1F624 ; [*167F.0020.0002] # FACE WITH LOOK OF TRIUMPH +1F625 ; [*1680.0020.0002] # DISAPPOINTED BUT RELIEVED FACE +1F626 ; [*1681.0020.0002] # FROWNING FACE WITH OPEN MOUTH +1F627 ; [*1682.0020.0002] # ANGUISHED FACE +1F628 ; [*1683.0020.0002] # FEARFUL FACE +1F629 ; [*1684.0020.0002] # WEARY FACE +1F62A ; [*1685.0020.0002] # SLEEPY FACE +1F62B ; [*1686.0020.0002] # TIRED FACE +1F62C ; [*1687.0020.0002] # GRIMACING FACE +1F62D ; [*1688.0020.0002] # LOUDLY CRYING FACE +1F62E ; [*1689.0020.0002] # FACE WITH OPEN MOUTH +1F62F ; [*168A.0020.0002] # HUSHED FACE +1F630 ; [*168B.0020.0002] # FACE WITH OPEN MOUTH AND COLD SWEAT +1F631 ; [*168C.0020.0002] # FACE SCREAMING IN FEAR +1F632 ; [*168D.0020.0002] # ASTONISHED FACE +1F633 ; [*168E.0020.0002] # FLUSHED FACE +1F634 ; [*168F.0020.0002] # SLEEPING FACE +1F635 ; [*1690.0020.0002] # DIZZY FACE +1F636 ; [*1691.0020.0002] # FACE WITHOUT MOUTH +1F637 ; [*1692.0020.0002] # FACE WITH MEDICAL MASK +1F638 ; [*1693.0020.0002] # GRINNING CAT FACE WITH SMILING EYES +1F639 ; [*1694.0020.0002] # CAT FACE WITH TEARS OF JOY +1F63A ; [*1695.0020.0002] # SMILING CAT FACE WITH OPEN MOUTH +1F63B ; [*1696.0020.0002] # SMILING CAT FACE WITH HEART-SHAPED EYES +1F63C ; [*1697.0020.0002] # CAT FACE WITH WRY SMILE +1F63D ; [*1698.0020.0002] # KISSING CAT FACE WITH CLOSED EYES +1F63E ; [*1699.0020.0002] # POUTING CAT FACE +1F63F ; [*169A.0020.0002] # CRYING CAT FACE +1F640 ; [*169B.0020.0002] # WEARY CAT FACE +1F641 ; [*169C.0020.0002] # SLIGHTLY FROWNING FACE +1F642 ; [*169D.0020.0002] # SLIGHTLY SMILING FACE +1F643 ; [*169E.0020.0002] # UPSIDE-DOWN FACE +1F644 ; [*169F.0020.0002] # FACE WITH ROLLING EYES +1F645 ; [*16A0.0020.0002] # FACE WITH NO GOOD GESTURE +1F646 ; [*16A1.0020.0002] # FACE WITH OK GESTURE +1F647 ; [*16A2.0020.0002] # PERSON BOWING DEEPLY +1F648 ; [*16A3.0020.0002] # SEE-NO-EVIL MONKEY +1F649 ; [*16A4.0020.0002] # HEAR-NO-EVIL MONKEY +1F64A ; [*16A5.0020.0002] # SPEAK-NO-EVIL MONKEY +1F64B ; [*16A6.0020.0002] # HAPPY PERSON RAISING ONE HAND +1F64C ; [*16A7.0020.0002] # PERSON RAISING BOTH HANDS IN CELEBRATION +1F64D ; [*16A8.0020.0002] # PERSON FROWNING +1F64E ; [*16A9.0020.0002] # PERSON WITH POUTING FACE +1F64F ; [*16AA.0020.0002] # PERSON WITH FOLDED HANDS +1F650 ; [*16AB.0020.0002] # NORTH WEST POINTING LEAF +1F651 ; [*16AC.0020.0002] # SOUTH WEST POINTING LEAF +1F652 ; [*16AD.0020.0002] # NORTH EAST POINTING LEAF +1F653 ; [*16AE.0020.0002] # SOUTH EAST POINTING LEAF +1F654 ; [*16AF.0020.0002] # TURNED NORTH WEST POINTING LEAF +1F655 ; [*16B0.0020.0002] # TURNED SOUTH WEST POINTING LEAF +1F656 ; [*16B1.0020.0002] # TURNED NORTH EAST POINTING LEAF +1F657 ; [*16B2.0020.0002] # TURNED SOUTH EAST POINTING LEAF +1F658 ; [*16B3.0020.0002] # NORTH WEST POINTING VINE LEAF +1F659 ; [*16B4.0020.0002] # SOUTH WEST POINTING VINE LEAF +1F65A ; [*16B5.0020.0002] # NORTH EAST POINTING VINE LEAF +1F65B ; [*16B6.0020.0002] # SOUTH EAST POINTING VINE LEAF +1F65C ; [*16B7.0020.0002] # HEAVY NORTH WEST POINTING VINE LEAF +1F65D ; [*16B8.0020.0002] # HEAVY SOUTH WEST POINTING VINE LEAF +1F65E ; [*16B9.0020.0002] # HEAVY NORTH EAST POINTING VINE LEAF +1F65F ; [*16BA.0020.0002] # HEAVY SOUTH EAST POINTING VINE LEAF +1F660 ; [*16BB.0020.0002] # NORTH WEST POINTING BUD +1F661 ; [*16BC.0020.0002] # SOUTH WEST POINTING BUD +1F662 ; [*16BD.0020.0002] # NORTH EAST POINTING BUD +1F663 ; [*16BE.0020.0002] # SOUTH EAST POINTING BUD +1F664 ; [*16BF.0020.0002] # HEAVY NORTH WEST POINTING BUD +1F665 ; [*16C0.0020.0002] # HEAVY SOUTH WEST POINTING BUD +1F666 ; [*16C1.0020.0002] # HEAVY NORTH EAST POINTING BUD +1F667 ; [*16C2.0020.0002] # HEAVY SOUTH EAST POINTING BUD +1F668 ; [*16C3.0020.0002] # HOLLOW QUILT SQUARE ORNAMENT +1F669 ; [*16C4.0020.0002] # HOLLOW QUILT SQUARE ORNAMENT IN BLACK SQUARE +1F66A ; [*16C5.0020.0002] # SOLID QUILT SQUARE ORNAMENT +1F66B ; [*16C6.0020.0002] # SOLID QUILT SQUARE ORNAMENT IN BLACK SQUARE +1F66C ; [*16C7.0020.0002] # LEFTWARDS ROCKET +1F66D ; [*16C8.0020.0002] # UPWARDS ROCKET +1F66E ; [*16C9.0020.0002] # RIGHTWARDS ROCKET +1F66F ; [*16CA.0020.0002] # DOWNWARDS ROCKET +1F670 ; [*16CB.0020.0002] # SCRIPT LIGATURE ET ORNAMENT +1F671 ; [*16CC.0020.0002] # HEAVY SCRIPT LIGATURE ET ORNAMENT +1F672 ; [*16CD.0020.0002] # LIGATURE OPEN ET ORNAMENT +1F673 ; [*16CE.0020.0002] # HEAVY LIGATURE OPEN ET ORNAMENT +1F674 ; [*16CF.0020.0002] # HEAVY AMPERSAND ORNAMENT +1F675 ; [*16D0.0020.0002] # SWASH AMPERSAND ORNAMENT +1F676 ; [*16D1.0020.0002] # SANS-SERIF HEAVY DOUBLE TURNED COMMA QUOTATION MARK ORNAMENT +1F677 ; [*16D2.0020.0002] # SANS-SERIF HEAVY DOUBLE COMMA QUOTATION MARK ORNAMENT +1F678 ; [*16D3.0020.0002] # SANS-SERIF HEAVY LOW DOUBLE COMMA QUOTATION MARK ORNAMENT +1F679 ; [*16D4.0020.0002] # HEAVY INTERROBANG ORNAMENT +1F67A ; [*16D5.0020.0002] # SANS-SERIF INTERROBANG ORNAMENT +1F67B ; [*16D6.0020.0002] # HEAVY SANS-SERIF INTERROBANG ORNAMENT +1F67C ; [*16D7.0020.0002] # VERY HEAVY SOLIDUS +1F67D ; [*16D8.0020.0002] # VERY HEAVY REVERSE SOLIDUS +1F67E ; [*16D9.0020.0002] # CHECKER BOARD +1F67F ; [*16DA.0020.0002] # REVERSE CHECKER BOARD +1F680 ; [*16DB.0020.0002] # ROCKET +1F681 ; [*16DC.0020.0002] # HELICOPTER +1F682 ; [*16DD.0020.0002] # STEAM LOCOMOTIVE +1F683 ; [*16DE.0020.0002] # RAILWAY CAR +1F684 ; [*16DF.0020.0002] # HIGH-SPEED TRAIN +1F685 ; [*16E0.0020.0002] # HIGH-SPEED TRAIN WITH BULLET NOSE +1F686 ; [*16E1.0020.0002] # TRAIN +1F687 ; [*16E2.0020.0002] # METRO +1F688 ; [*16E3.0020.0002] # LIGHT RAIL +1F689 ; [*16E4.0020.0002] # STATION +1F68A ; [*16E5.0020.0002] # TRAM +1F68B ; [*16E6.0020.0002] # TRAM CAR +1F68C ; [*16E7.0020.0002] # BUS +1F68D ; [*16E8.0020.0002] # ONCOMING BUS +1F68E ; [*16E9.0020.0002] # TROLLEYBUS +1F68F ; [*16EA.0020.0002] # BUS STOP +1F690 ; [*16EB.0020.0002] # MINIBUS +1F691 ; [*16EC.0020.0002] # AMBULANCE +1F692 ; [*16ED.0020.0002] # FIRE ENGINE +1F693 ; [*16EE.0020.0002] # POLICE CAR +1F694 ; [*16EF.0020.0002] # ONCOMING POLICE CAR +1F695 ; [*16F0.0020.0002] # TAXI +1F696 ; [*16F1.0020.0002] # ONCOMING TAXI +1F697 ; [*16F2.0020.0002] # AUTOMOBILE +1F698 ; [*16F3.0020.0002] # ONCOMING AUTOMOBILE +1F699 ; [*16F4.0020.0002] # RECREATIONAL VEHICLE +1F69A ; [*16F5.0020.0002] # DELIVERY TRUCK +1F69B ; [*16F6.0020.0002] # ARTICULATED LORRY +1F69C ; [*16F7.0020.0002] # TRACTOR +1F69D ; [*16F8.0020.0002] # MONORAIL +1F69E ; [*16F9.0020.0002] # MOUNTAIN RAILWAY +1F69F ; [*16FA.0020.0002] # SUSPENSION RAILWAY +1F6A0 ; [*16FB.0020.0002] # MOUNTAIN CABLEWAY +1F6A1 ; [*16FC.0020.0002] # AERIAL TRAMWAY +1F6A2 ; [*16FD.0020.0002] # SHIP +1F6A3 ; [*16FE.0020.0002] # ROWBOAT +1F6A4 ; [*16FF.0020.0002] # SPEEDBOAT +1F6A5 ; [*1700.0020.0002] # HORIZONTAL TRAFFIC LIGHT +1F6A6 ; [*1701.0020.0002] # VERTICAL TRAFFIC LIGHT +1F6A7 ; [*1702.0020.0002] # CONSTRUCTION SIGN +1F6A8 ; [*1703.0020.0002] # POLICE CARS REVOLVING LIGHT +1F6A9 ; [*1704.0020.0002] # TRIANGULAR FLAG ON POST +1F6AA ; [*1705.0020.0002] # DOOR +1F6AB ; [*1706.0020.0002] # NO ENTRY SIGN +1F6AC ; [*1707.0020.0002] # SMOKING SYMBOL +1F6AD ; [*1708.0020.0002] # NO SMOKING SYMBOL +1F6AE ; [*1709.0020.0002] # PUT LITTER IN ITS PLACE SYMBOL +1F6AF ; [*170A.0020.0002] # DO NOT LITTER SYMBOL +1F6B0 ; [*170B.0020.0002] # POTABLE WATER SYMBOL +1F6B1 ; [*170C.0020.0002] # NON-POTABLE WATER SYMBOL +1F6B2 ; [*170D.0020.0002] # BICYCLE +1F6B3 ; [*170E.0020.0002] # NO BICYCLES +1F6B4 ; [*170F.0020.0002] # BICYCLIST +1F6B5 ; [*1710.0020.0002] # MOUNTAIN BICYCLIST +1F6B6 ; [*1711.0020.0002] # PEDESTRIAN +1F6B7 ; [*1712.0020.0002] # NO PEDESTRIANS +1F6B8 ; [*1713.0020.0002] # CHILDREN CROSSING +1F6B9 ; [*1714.0020.0002] # MENS SYMBOL +1F6BA ; [*1715.0020.0002] # WOMENS SYMBOL +1F6BB ; [*1716.0020.0002] # RESTROOM +1F6BC ; [*1717.0020.0002] # BABY SYMBOL +1F6BD ; [*1718.0020.0002] # TOILET +1F6BE ; [*1719.0020.0002] # WATER CLOSET +1F6BF ; [*171A.0020.0002] # SHOWER +1F6C0 ; [*171B.0020.0002] # BATH +1F6C1 ; [*171C.0020.0002] # BATHTUB +1F6C2 ; [*171D.0020.0002] # PASSPORT CONTROL +1F6C3 ; [*171E.0020.0002] # CUSTOMS +1F6C4 ; [*171F.0020.0002] # BAGGAGE CLAIM +1F6C5 ; [*1720.0020.0002] # LEFT LUGGAGE +1F6C6 ; [*1721.0020.0002] # TRIANGLE WITH ROUNDED CORNERS +1F6C7 ; [*1722.0020.0002] # PROHIBITED SIGN +1F6C8 ; [*1723.0020.0002] # CIRCLED INFORMATION SOURCE +1F6C9 ; [*1724.0020.0002] # BOYS SYMBOL +1F6CA ; [*1725.0020.0002] # GIRLS SYMBOL +1F6CB ; [*1726.0020.0002] # COUCH AND LAMP +1F6CC ; [*1727.0020.0002] # SLEEPING ACCOMMODATION +1F6CD ; [*1728.0020.0002] # SHOPPING BAGS +1F6CE ; [*1729.0020.0002] # BELLHOP BELL +1F6CF ; [*172A.0020.0002] # BED +1F6D0 ; [*172B.0020.0002] # PLACE OF WORSHIP +1F6D1 ; [*172C.0020.0002] # OCTAGONAL SIGN +1F6D2 ; [*172D.0020.0002] # SHOPPING TROLLEY +1F6D3 ; [*172E.0020.0002] # STUPA +1F6D4 ; [*172F.0020.0002] # PAGODA +1F6E0 ; [*1730.0020.0002] # HAMMER AND WRENCH +1F6E1 ; [*1731.0020.0002] # SHIELD +1F6E2 ; [*1732.0020.0002] # OIL DRUM +1F6E3 ; [*1733.0020.0002] # MOTORWAY +1F6E4 ; [*1734.0020.0002] # RAILWAY TRACK +1F6E5 ; [*1735.0020.0002] # MOTOR BOAT +1F6E6 ; [*1736.0020.0002] # UP-POINTING MILITARY AIRPLANE +1F6E7 ; [*1737.0020.0002] # UP-POINTING AIRPLANE +1F6E8 ; [*1738.0020.0002] # UP-POINTING SMALL AIRPLANE +1F6E9 ; [*1739.0020.0002] # SMALL AIRPLANE +1F6EA ; [*173A.0020.0002] # NORTHEAST-POINTING AIRPLANE +1F6EB ; [*173B.0020.0002] # AIRPLANE DEPARTURE +1F6EC ; [*173C.0020.0002] # AIRPLANE ARRIVING +1F6F0 ; [*173D.0020.0002] # SATELLITE +1F6F1 ; [*173E.0020.0002] # ONCOMING FIRE ENGINE +1F6F2 ; [*173F.0020.0002] # DIESEL LOCOMOTIVE +1F6F3 ; [*1740.0020.0002] # PASSENGER SHIP +1F6F4 ; [*1741.0020.0002] # SCOOTER +1F6F5 ; [*1742.0020.0002] # MOTOR SCOOTER +1F6F6 ; [*1743.0020.0002] # CANOE +1F6F7 ; [*1744.0020.0002] # SLED +1F6F8 ; [*1745.0020.0002] # FLYING SAUCER +1F700 ; [*1746.0020.0002] # ALCHEMICAL SYMBOL FOR QUINTESSENCE +1F701 ; [*1747.0020.0002] # ALCHEMICAL SYMBOL FOR AIR +1F702 ; [*1748.0020.0002] # ALCHEMICAL SYMBOL FOR FIRE +1F703 ; [*1749.0020.0002] # ALCHEMICAL SYMBOL FOR EARTH +1F704 ; [*174A.0020.0002] # ALCHEMICAL SYMBOL FOR WATER +1F705 ; [*174B.0020.0002] # ALCHEMICAL SYMBOL FOR AQUAFORTIS +1F706 ; [*174C.0020.0002] # ALCHEMICAL SYMBOL FOR AQUA REGIA +1F707 ; [*174D.0020.0002] # ALCHEMICAL SYMBOL FOR AQUA REGIA-2 +1F708 ; [*174E.0020.0002] # ALCHEMICAL SYMBOL FOR AQUA VITAE +1F709 ; [*174F.0020.0002] # ALCHEMICAL SYMBOL FOR AQUA VITAE-2 +1F70A ; [*1750.0020.0002] # ALCHEMICAL SYMBOL FOR VINEGAR +1F70B ; [*1751.0020.0002] # ALCHEMICAL SYMBOL FOR VINEGAR-2 +1F70C ; [*1752.0020.0002] # ALCHEMICAL SYMBOL FOR VINEGAR-3 +1F70D ; [*1753.0020.0002] # ALCHEMICAL SYMBOL FOR SULFUR +1F70E ; [*1754.0020.0002] # ALCHEMICAL SYMBOL FOR PHILOSOPHERS SULFUR +1F70F ; [*1755.0020.0002] # ALCHEMICAL SYMBOL FOR BLACK SULFUR +1F710 ; [*1756.0020.0002] # ALCHEMICAL SYMBOL FOR MERCURY SUBLIMATE +1F711 ; [*1757.0020.0002] # ALCHEMICAL SYMBOL FOR MERCURY SUBLIMATE-2 +1F712 ; [*1758.0020.0002] # ALCHEMICAL SYMBOL FOR MERCURY SUBLIMATE-3 +1F713 ; [*1759.0020.0002] # ALCHEMICAL SYMBOL FOR CINNABAR +1F714 ; [*175A.0020.0002] # ALCHEMICAL SYMBOL FOR SALT +1F715 ; [*175B.0020.0002] # ALCHEMICAL SYMBOL FOR NITRE +1F716 ; [*175C.0020.0002] # ALCHEMICAL SYMBOL FOR VITRIOL +1F717 ; [*175D.0020.0002] # ALCHEMICAL SYMBOL FOR VITRIOL-2 +1F718 ; [*175E.0020.0002] # ALCHEMICAL SYMBOL FOR ROCK SALT +1F719 ; [*175F.0020.0002] # ALCHEMICAL SYMBOL FOR ROCK SALT-2 +1F71A ; [*1760.0020.0002] # ALCHEMICAL SYMBOL FOR GOLD +1F71B ; [*1761.0020.0002] # ALCHEMICAL SYMBOL FOR SILVER +1F71C ; [*1762.0020.0002] # ALCHEMICAL SYMBOL FOR IRON ORE +1F71D ; [*1763.0020.0002] # ALCHEMICAL SYMBOL FOR IRON ORE-2 +1F71E ; [*1764.0020.0002] # ALCHEMICAL SYMBOL FOR CROCUS OF IRON +1F71F ; [*1765.0020.0002] # ALCHEMICAL SYMBOL FOR REGULUS OF IRON +1F720 ; [*1766.0020.0002] # ALCHEMICAL SYMBOL FOR COPPER ORE +1F721 ; [*1767.0020.0002] # ALCHEMICAL SYMBOL FOR IRON-COPPER ORE +1F722 ; [*1768.0020.0002] # ALCHEMICAL SYMBOL FOR SUBLIMATE OF COPPER +1F723 ; [*1769.0020.0002] # ALCHEMICAL SYMBOL FOR CROCUS OF COPPER +1F724 ; [*176A.0020.0002] # ALCHEMICAL SYMBOL FOR CROCUS OF COPPER-2 +1F725 ; [*176B.0020.0002] # ALCHEMICAL SYMBOL FOR COPPER ANTIMONIATE +1F726 ; [*176C.0020.0002] # ALCHEMICAL SYMBOL FOR SALT OF COPPER ANTIMONIATE +1F727 ; [*176D.0020.0002] # ALCHEMICAL SYMBOL FOR SUBLIMATE OF SALT OF COPPER +1F728 ; [*176E.0020.0002] # ALCHEMICAL SYMBOL FOR VERDIGRIS +1F729 ; [*176F.0020.0002] # ALCHEMICAL SYMBOL FOR TIN ORE +1F72A ; [*1770.0020.0002] # ALCHEMICAL SYMBOL FOR LEAD ORE +1F72B ; [*1771.0020.0002] # ALCHEMICAL SYMBOL FOR ANTIMONY ORE +1F72C ; [*1772.0020.0002] # ALCHEMICAL SYMBOL FOR SUBLIMATE OF ANTIMONY +1F72D ; [*1773.0020.0002] # ALCHEMICAL SYMBOL FOR SALT OF ANTIMONY +1F72E ; [*1774.0020.0002] # ALCHEMICAL SYMBOL FOR SUBLIMATE OF SALT OF ANTIMONY +1F72F ; [*1775.0020.0002] # ALCHEMICAL SYMBOL FOR VINEGAR OF ANTIMONY +1F730 ; [*1776.0020.0002] # ALCHEMICAL SYMBOL FOR REGULUS OF ANTIMONY +1F731 ; [*1777.0020.0002] # ALCHEMICAL SYMBOL FOR REGULUS OF ANTIMONY-2 +1F732 ; [*1778.0020.0002] # ALCHEMICAL SYMBOL FOR REGULUS +1F733 ; [*1779.0020.0002] # ALCHEMICAL SYMBOL FOR REGULUS-2 +1F734 ; [*177A.0020.0002] # ALCHEMICAL SYMBOL FOR REGULUS-3 +1F735 ; [*177B.0020.0002] # ALCHEMICAL SYMBOL FOR REGULUS-4 +1F736 ; [*177C.0020.0002] # ALCHEMICAL SYMBOL FOR ALKALI +1F737 ; [*177D.0020.0002] # ALCHEMICAL SYMBOL FOR ALKALI-2 +1F738 ; [*177E.0020.0002] # ALCHEMICAL SYMBOL FOR MARCASITE +1F739 ; [*177F.0020.0002] # ALCHEMICAL SYMBOL FOR SAL-AMMONIAC +1F73A ; [*1780.0020.0002] # ALCHEMICAL SYMBOL FOR ARSENIC +1F73B ; [*1781.0020.0002] # ALCHEMICAL SYMBOL FOR REALGAR +1F73C ; [*1782.0020.0002] # ALCHEMICAL SYMBOL FOR REALGAR-2 +1F73D ; [*1783.0020.0002] # ALCHEMICAL SYMBOL FOR AURIPIGMENT +1F73E ; [*1784.0020.0002] # ALCHEMICAL SYMBOL FOR BISMUTH ORE +1F73F ; [*1785.0020.0002] # ALCHEMICAL SYMBOL FOR TARTAR +1F740 ; [*1786.0020.0002] # ALCHEMICAL SYMBOL FOR TARTAR-2 +1F741 ; [*1787.0020.0002] # ALCHEMICAL SYMBOL FOR QUICK LIME +1F742 ; [*1788.0020.0002] # ALCHEMICAL SYMBOL FOR BORAX +1F743 ; [*1789.0020.0002] # ALCHEMICAL SYMBOL FOR BORAX-2 +1F744 ; [*178A.0020.0002] # ALCHEMICAL SYMBOL FOR BORAX-3 +1F745 ; [*178B.0020.0002] # ALCHEMICAL SYMBOL FOR ALUM +1F746 ; [*178C.0020.0002] # ALCHEMICAL SYMBOL FOR OIL +1F747 ; [*178D.0020.0002] # ALCHEMICAL SYMBOL FOR SPIRIT +1F748 ; [*178E.0020.0002] # ALCHEMICAL SYMBOL FOR TINCTURE +1F749 ; [*178F.0020.0002] # ALCHEMICAL SYMBOL FOR GUM +1F74A ; [*1790.0020.0002] # ALCHEMICAL SYMBOL FOR WAX +1F74B ; [*1791.0020.0002] # ALCHEMICAL SYMBOL FOR POWDER +1F74C ; [*1792.0020.0002] # ALCHEMICAL SYMBOL FOR CALX +1F74D ; [*1793.0020.0002] # ALCHEMICAL SYMBOL FOR TUTTY +1F74E ; [*1794.0020.0002] # ALCHEMICAL SYMBOL FOR CAPUT MORTUUM +1F74F ; [*1795.0020.0002] # ALCHEMICAL SYMBOL FOR SCEPTER OF JOVE +1F750 ; [*1796.0020.0002] # ALCHEMICAL SYMBOL FOR CADUCEUS +1F751 ; [*1797.0020.0002] # ALCHEMICAL SYMBOL FOR TRIDENT +1F752 ; [*1798.0020.0002] # ALCHEMICAL SYMBOL FOR STARRED TRIDENT +1F753 ; [*1799.0020.0002] # ALCHEMICAL SYMBOL FOR LODESTONE +1F754 ; [*179A.0020.0002] # ALCHEMICAL SYMBOL FOR SOAP +1F755 ; [*179B.0020.0002] # ALCHEMICAL SYMBOL FOR URINE +1F756 ; [*179C.0020.0002] # ALCHEMICAL SYMBOL FOR HORSE DUNG +1F757 ; [*179D.0020.0002] # ALCHEMICAL SYMBOL FOR ASHES +1F758 ; [*179E.0020.0002] # ALCHEMICAL SYMBOL FOR POT ASHES +1F759 ; [*179F.0020.0002] # ALCHEMICAL SYMBOL FOR BRICK +1F75A ; [*17A0.0020.0002] # ALCHEMICAL SYMBOL FOR POWDERED BRICK +1F75B ; [*17A1.0020.0002] # ALCHEMICAL SYMBOL FOR AMALGAM +1F75C ; [*17A2.0020.0002] # ALCHEMICAL SYMBOL FOR STRATUM SUPER STRATUM +1F75D ; [*17A3.0020.0002] # ALCHEMICAL SYMBOL FOR STRATUM SUPER STRATUM-2 +1F75E ; [*17A4.0020.0002] # ALCHEMICAL SYMBOL FOR SUBLIMATION +1F75F ; [*17A5.0020.0002] # ALCHEMICAL SYMBOL FOR PRECIPITATE +1F760 ; [*17A6.0020.0002] # ALCHEMICAL SYMBOL FOR DISTILL +1F761 ; [*17A7.0020.0002] # ALCHEMICAL SYMBOL FOR DISSOLVE +1F762 ; [*17A8.0020.0002] # ALCHEMICAL SYMBOL FOR DISSOLVE-2 +1F763 ; [*17A9.0020.0002] # ALCHEMICAL SYMBOL FOR PURIFY +1F764 ; [*17AA.0020.0002] # ALCHEMICAL SYMBOL FOR PUTREFACTION +1F765 ; [*17AB.0020.0002] # ALCHEMICAL SYMBOL FOR CRUCIBLE +1F766 ; [*17AC.0020.0002] # ALCHEMICAL SYMBOL FOR CRUCIBLE-2 +1F767 ; [*17AD.0020.0002] # ALCHEMICAL SYMBOL FOR CRUCIBLE-3 +1F768 ; [*17AE.0020.0002] # ALCHEMICAL SYMBOL FOR CRUCIBLE-4 +1F769 ; [*17AF.0020.0002] # ALCHEMICAL SYMBOL FOR CRUCIBLE-5 +1F76A ; [*17B0.0020.0002] # ALCHEMICAL SYMBOL FOR ALEMBIC +1F76B ; [*17B1.0020.0002] # ALCHEMICAL SYMBOL FOR BATH OF MARY +1F76C ; [*17B2.0020.0002] # ALCHEMICAL SYMBOL FOR BATH OF VAPOURS +1F76D ; [*17B3.0020.0002] # ALCHEMICAL SYMBOL FOR RETORT +1F76E ; [*17B4.0020.0002] # ALCHEMICAL SYMBOL FOR HOUR +1F76F ; [*17B5.0020.0002] # ALCHEMICAL SYMBOL FOR NIGHT +1F770 ; [*17B6.0020.0002] # ALCHEMICAL SYMBOL FOR DAY-NIGHT +1F771 ; [*17B7.0020.0002] # ALCHEMICAL SYMBOL FOR MONTH +1F772 ; [*17B8.0020.0002] # ALCHEMICAL SYMBOL FOR HALF DRAM +1F773 ; [*17B9.0020.0002] # ALCHEMICAL SYMBOL FOR HALF OUNCE +1F780 ; [*17BA.0020.0002] # BLACK LEFT-POINTING ISOSCELES RIGHT TRIANGLE +1F781 ; [*17BB.0020.0002] # BLACK UP-POINTING ISOSCELES RIGHT TRIANGLE +1F782 ; [*17BC.0020.0002] # BLACK RIGHT-POINTING ISOSCELES RIGHT TRIANGLE +1F783 ; [*17BD.0020.0002] # BLACK DOWN-POINTING ISOSCELES RIGHT TRIANGLE +1F784 ; [*17BE.0020.0002] # BLACK SLIGHTLY SMALL CIRCLE +1F785 ; [*17BF.0020.0002] # MEDIUM BOLD WHITE CIRCLE +1F786 ; [*17C0.0020.0002] # BOLD WHITE CIRCLE +1F787 ; [*17C1.0020.0002] # HEAVY WHITE CIRCLE +1F788 ; [*17C2.0020.0002] # VERY HEAVY WHITE CIRCLE +1F789 ; [*17C3.0020.0002] # EXTREMELY HEAVY WHITE CIRCLE +1F78A ; [*17C4.0020.0002] # WHITE CIRCLE CONTAINING BLACK SMALL CIRCLE +1F78B ; [*17C5.0020.0002] # ROUND TARGET +1F78C ; [*17C6.0020.0002] # BLACK TINY SQUARE +1F78D ; [*17C7.0020.0002] # BLACK SLIGHTLY SMALL SQUARE +1F78E ; [*17C8.0020.0002] # LIGHT WHITE SQUARE +1F78F ; [*17C9.0020.0002] # MEDIUM WHITE SQUARE +1F790 ; [*17CA.0020.0002] # BOLD WHITE SQUARE +1F791 ; [*17CB.0020.0002] # HEAVY WHITE SQUARE +1F792 ; [*17CC.0020.0002] # VERY HEAVY WHITE SQUARE +1F793 ; [*17CD.0020.0002] # EXTREMELY HEAVY WHITE SQUARE +1F794 ; [*17CE.0020.0002] # WHITE SQUARE CONTAINING BLACK VERY SMALL SQUARE +1F795 ; [*17CF.0020.0002] # WHITE SQUARE CONTAINING BLACK MEDIUM SQUARE +1F796 ; [*17D0.0020.0002] # SQUARE TARGET +1F797 ; [*17D1.0020.0002] # BLACK TINY DIAMOND +1F798 ; [*17D2.0020.0002] # BLACK VERY SMALL DIAMOND +1F799 ; [*17D3.0020.0002] # BLACK MEDIUM SMALL DIAMOND +1F79A ; [*17D4.0020.0002] # WHITE DIAMOND CONTAINING BLACK VERY SMALL DIAMOND +1F79B ; [*17D5.0020.0002] # WHITE DIAMOND CONTAINING BLACK MEDIUM DIAMOND +1F79C ; [*17D6.0020.0002] # DIAMOND TARGET +1F79D ; [*17D7.0020.0002] # BLACK TINY LOZENGE +1F79E ; [*17D8.0020.0002] # BLACK VERY SMALL LOZENGE +1F79F ; [*17D9.0020.0002] # BLACK MEDIUM SMALL LOZENGE +1F7A0 ; [*17DA.0020.0002] # WHITE LOZENGE CONTAINING BLACK SMALL LOZENGE +1F7A1 ; [*17DB.0020.0002] # THIN GREEK CROSS +1F7A2 ; [*17DC.0020.0002] # LIGHT GREEK CROSS +1F7A3 ; [*17DD.0020.0002] # MEDIUM GREEK CROSS +1F7A4 ; [*17DE.0020.0002] # BOLD GREEK CROSS +1F7A5 ; [*17DF.0020.0002] # VERY BOLD GREEK CROSS +1F7A6 ; [*17E0.0020.0002] # VERY HEAVY GREEK CROSS +1F7A7 ; [*17E1.0020.0002] # EXTREMELY HEAVY GREEK CROSS +1F7A8 ; [*17E2.0020.0002] # THIN SALTIRE +1F7A9 ; [*17E3.0020.0002] # LIGHT SALTIRE +1F7AA ; [*17E4.0020.0002] # MEDIUM SALTIRE +1F7AB ; [*17E5.0020.0002] # BOLD SALTIRE +1F7AC ; [*17E6.0020.0002] # HEAVY SALTIRE +1F7AD ; [*17E7.0020.0002] # VERY HEAVY SALTIRE +1F7AE ; [*17E8.0020.0002] # EXTREMELY HEAVY SALTIRE +1F7AF ; [*17E9.0020.0002] # LIGHT FIVE SPOKED ASTERISK +1F7B0 ; [*17EA.0020.0002] # MEDIUM FIVE SPOKED ASTERISK +1F7B1 ; [*17EB.0020.0002] # BOLD FIVE SPOKED ASTERISK +1F7B2 ; [*17EC.0020.0002] # HEAVY FIVE SPOKED ASTERISK +1F7B3 ; [*17ED.0020.0002] # VERY HEAVY FIVE SPOKED ASTERISK +1F7B4 ; [*17EE.0020.0002] # EXTREMELY HEAVY FIVE SPOKED ASTERISK +1F7B5 ; [*17EF.0020.0002] # LIGHT SIX SPOKED ASTERISK +1F7B6 ; [*17F0.0020.0002] # MEDIUM SIX SPOKED ASTERISK +1F7B7 ; [*17F1.0020.0002] # BOLD SIX SPOKED ASTERISK +1F7B8 ; [*17F2.0020.0002] # HEAVY SIX SPOKED ASTERISK +1F7B9 ; [*17F3.0020.0002] # VERY HEAVY SIX SPOKED ASTERISK +1F7BA ; [*17F4.0020.0002] # EXTREMELY HEAVY SIX SPOKED ASTERISK +1F7BB ; [*17F5.0020.0002] # LIGHT EIGHT SPOKED ASTERISK +1F7BC ; [*17F6.0020.0002] # MEDIUM EIGHT SPOKED ASTERISK +1F7BD ; [*17F7.0020.0002] # BOLD EIGHT SPOKED ASTERISK +1F7BE ; [*17F8.0020.0002] # HEAVY EIGHT SPOKED ASTERISK +1F7BF ; [*17F9.0020.0002] # VERY HEAVY EIGHT SPOKED ASTERISK +1F7C0 ; [*17FA.0020.0002] # LIGHT THREE POINTED BLACK STAR +1F7C1 ; [*17FB.0020.0002] # MEDIUM THREE POINTED BLACK STAR +1F7C2 ; [*17FC.0020.0002] # THREE POINTED BLACK STAR +1F7C3 ; [*17FD.0020.0002] # MEDIUM THREE POINTED PINWHEEL STAR +1F7C4 ; [*17FE.0020.0002] # LIGHT FOUR POINTED BLACK STAR +1F7C5 ; [*17FF.0020.0002] # MEDIUM FOUR POINTED BLACK STAR +1F7C6 ; [*1800.0020.0002] # FOUR POINTED BLACK STAR +1F7C7 ; [*1801.0020.0002] # MEDIUM FOUR POINTED PINWHEEL STAR +1F7C8 ; [*1802.0020.0002] # REVERSE LIGHT FOUR POINTED PINWHEEL STAR +1F7C9 ; [*1803.0020.0002] # LIGHT FIVE POINTED BLACK STAR +1F7CA ; [*1804.0020.0002] # HEAVY FIVE POINTED BLACK STAR +1F7CB ; [*1805.0020.0002] # MEDIUM SIX POINTED BLACK STAR +1F7CC ; [*1806.0020.0002] # HEAVY SIX POINTED BLACK STAR +1F7CD ; [*1807.0020.0002] # SIX POINTED PINWHEEL STAR +1F7CE ; [*1808.0020.0002] # MEDIUM EIGHT POINTED BLACK STAR +1F7CF ; [*1809.0020.0002] # HEAVY EIGHT POINTED BLACK STAR +1F7D0 ; [*180A.0020.0002] # VERY HEAVY EIGHT POINTED BLACK STAR +1F7D1 ; [*180B.0020.0002] # HEAVY EIGHT POINTED PINWHEEL STAR +1F7D2 ; [*180C.0020.0002] # LIGHT TWELVE POINTED BLACK STAR +1F7D3 ; [*180D.0020.0002] # HEAVY TWELVE POINTED BLACK STAR +1F7D4 ; [*180E.0020.0002] # HEAVY TWELVE POINTED PINWHEEL STAR +1F800 ; [*180F.0020.0002] # LEFTWARDS ARROW WITH SMALL TRIANGLE ARROWHEAD +1F801 ; [*1810.0020.0002] # UPWARDS ARROW WITH SMALL TRIANGLE ARROWHEAD +1F802 ; [*1811.0020.0002] # RIGHTWARDS ARROW WITH SMALL TRIANGLE ARROWHEAD +1F803 ; [*1812.0020.0002] # DOWNWARDS ARROW WITH SMALL TRIANGLE ARROWHEAD +1F804 ; [*1813.0020.0002] # LEFTWARDS ARROW WITH MEDIUM TRIANGLE ARROWHEAD +1F805 ; [*1814.0020.0002] # UPWARDS ARROW WITH MEDIUM TRIANGLE ARROWHEAD +1F806 ; [*1815.0020.0002] # RIGHTWARDS ARROW WITH MEDIUM TRIANGLE ARROWHEAD +1F807 ; [*1816.0020.0002] # DOWNWARDS ARROW WITH MEDIUM TRIANGLE ARROWHEAD +1F808 ; [*1817.0020.0002] # LEFTWARDS ARROW WITH LARGE TRIANGLE ARROWHEAD +1F809 ; [*1818.0020.0002] # UPWARDS ARROW WITH LARGE TRIANGLE ARROWHEAD +1F80A ; [*1819.0020.0002] # RIGHTWARDS ARROW WITH LARGE TRIANGLE ARROWHEAD +1F80B ; [*181A.0020.0002] # DOWNWARDS ARROW WITH LARGE TRIANGLE ARROWHEAD +1F810 ; [*181B.0020.0002] # LEFTWARDS ARROW WITH SMALL EQUILATERAL ARROWHEAD +1F811 ; [*181C.0020.0002] # UPWARDS ARROW WITH SMALL EQUILATERAL ARROWHEAD +1F812 ; [*181D.0020.0002] # RIGHTWARDS ARROW WITH SMALL EQUILATERAL ARROWHEAD +1F813 ; [*181E.0020.0002] # DOWNWARDS ARROW WITH SMALL EQUILATERAL ARROWHEAD +1F814 ; [*181F.0020.0002] # LEFTWARDS ARROW WITH EQUILATERAL ARROWHEAD +1F815 ; [*1820.0020.0002] # UPWARDS ARROW WITH EQUILATERAL ARROWHEAD +1F816 ; [*1821.0020.0002] # RIGHTWARDS ARROW WITH EQUILATERAL ARROWHEAD +1F817 ; [*1822.0020.0002] # DOWNWARDS ARROW WITH EQUILATERAL ARROWHEAD +1F818 ; [*1823.0020.0002] # HEAVY LEFTWARDS ARROW WITH EQUILATERAL ARROWHEAD +1F819 ; [*1824.0020.0002] # HEAVY UPWARDS ARROW WITH EQUILATERAL ARROWHEAD +1F81A ; [*1825.0020.0002] # HEAVY RIGHTWARDS ARROW WITH EQUILATERAL ARROWHEAD +1F81B ; [*1826.0020.0002] # HEAVY DOWNWARDS ARROW WITH EQUILATERAL ARROWHEAD +1F81C ; [*1827.0020.0002] # HEAVY LEFTWARDS ARROW WITH LARGE EQUILATERAL ARROWHEAD +1F81D ; [*1828.0020.0002] # HEAVY UPWARDS ARROW WITH LARGE EQUILATERAL ARROWHEAD +1F81E ; [*1829.0020.0002] # HEAVY RIGHTWARDS ARROW WITH LARGE EQUILATERAL ARROWHEAD +1F81F ; [*182A.0020.0002] # HEAVY DOWNWARDS ARROW WITH LARGE EQUILATERAL ARROWHEAD +1F820 ; [*182B.0020.0002] # LEFTWARDS TRIANGLE-HEADED ARROW WITH NARROW SHAFT +1F821 ; [*182C.0020.0002] # UPWARDS TRIANGLE-HEADED ARROW WITH NARROW SHAFT +1F822 ; [*182D.0020.0002] # RIGHTWARDS TRIANGLE-HEADED ARROW WITH NARROW SHAFT +1F823 ; [*182E.0020.0002] # DOWNWARDS TRIANGLE-HEADED ARROW WITH NARROW SHAFT +1F824 ; [*182F.0020.0002] # LEFTWARDS TRIANGLE-HEADED ARROW WITH MEDIUM SHAFT +1F825 ; [*1830.0020.0002] # UPWARDS TRIANGLE-HEADED ARROW WITH MEDIUM SHAFT +1F826 ; [*1831.0020.0002] # RIGHTWARDS TRIANGLE-HEADED ARROW WITH MEDIUM SHAFT +1F827 ; [*1832.0020.0002] # DOWNWARDS TRIANGLE-HEADED ARROW WITH MEDIUM SHAFT +1F828 ; [*1833.0020.0002] # LEFTWARDS TRIANGLE-HEADED ARROW WITH BOLD SHAFT +1F829 ; [*1834.0020.0002] # UPWARDS TRIANGLE-HEADED ARROW WITH BOLD SHAFT +1F82A ; [*1835.0020.0002] # RIGHTWARDS TRIANGLE-HEADED ARROW WITH BOLD SHAFT +1F82B ; [*1836.0020.0002] # DOWNWARDS TRIANGLE-HEADED ARROW WITH BOLD SHAFT +1F82C ; [*1837.0020.0002] # LEFTWARDS TRIANGLE-HEADED ARROW WITH HEAVY SHAFT +1F82D ; [*1838.0020.0002] # UPWARDS TRIANGLE-HEADED ARROW WITH HEAVY SHAFT +1F82E ; [*1839.0020.0002] # RIGHTWARDS TRIANGLE-HEADED ARROW WITH HEAVY SHAFT +1F82F ; [*183A.0020.0002] # DOWNWARDS TRIANGLE-HEADED ARROW WITH HEAVY SHAFT +1F830 ; [*183B.0020.0002] # LEFTWARDS TRIANGLE-HEADED ARROW WITH VERY HEAVY SHAFT +1F831 ; [*183C.0020.0002] # UPWARDS TRIANGLE-HEADED ARROW WITH VERY HEAVY SHAFT +1F832 ; [*183D.0020.0002] # RIGHTWARDS TRIANGLE-HEADED ARROW WITH VERY HEAVY SHAFT +1F833 ; [*183E.0020.0002] # DOWNWARDS TRIANGLE-HEADED ARROW WITH VERY HEAVY SHAFT +1F834 ; [*183F.0020.0002] # LEFTWARDS FINGER-POST ARROW +1F835 ; [*1840.0020.0002] # UPWARDS FINGER-POST ARROW +1F836 ; [*1841.0020.0002] # RIGHTWARDS FINGER-POST ARROW +1F837 ; [*1842.0020.0002] # DOWNWARDS FINGER-POST ARROW +1F838 ; [*1843.0020.0002] # LEFTWARDS SQUARED ARROW +1F839 ; [*1844.0020.0002] # UPWARDS SQUARED ARROW +1F83A ; [*1845.0020.0002] # RIGHTWARDS SQUARED ARROW +1F83B ; [*1846.0020.0002] # DOWNWARDS SQUARED ARROW +1F83C ; [*1847.0020.0002] # LEFTWARDS COMPRESSED ARROW +1F83D ; [*1848.0020.0002] # UPWARDS COMPRESSED ARROW +1F83E ; [*1849.0020.0002] # RIGHTWARDS COMPRESSED ARROW +1F83F ; [*184A.0020.0002] # DOWNWARDS COMPRESSED ARROW +1F840 ; [*184B.0020.0002] # LEFTWARDS HEAVY COMPRESSED ARROW +1F841 ; [*184C.0020.0002] # UPWARDS HEAVY COMPRESSED ARROW +1F842 ; [*184D.0020.0002] # RIGHTWARDS HEAVY COMPRESSED ARROW +1F843 ; [*184E.0020.0002] # DOWNWARDS HEAVY COMPRESSED ARROW +1F844 ; [*184F.0020.0002] # LEFTWARDS HEAVY ARROW +1F845 ; [*1850.0020.0002] # UPWARDS HEAVY ARROW +1F846 ; [*1851.0020.0002] # RIGHTWARDS HEAVY ARROW +1F847 ; [*1852.0020.0002] # DOWNWARDS HEAVY ARROW +1F850 ; [*1853.0020.0002] # LEFTWARDS SANS-SERIF ARROW +1F851 ; [*1854.0020.0002] # UPWARDS SANS-SERIF ARROW +1F852 ; [*1855.0020.0002] # RIGHTWARDS SANS-SERIF ARROW +1F853 ; [*1856.0020.0002] # DOWNWARDS SANS-SERIF ARROW +1F854 ; [*1857.0020.0002] # NORTH WEST SANS-SERIF ARROW +1F855 ; [*1858.0020.0002] # NORTH EAST SANS-SERIF ARROW +1F856 ; [*1859.0020.0002] # SOUTH EAST SANS-SERIF ARROW +1F857 ; [*185A.0020.0002] # SOUTH WEST SANS-SERIF ARROW +1F858 ; [*185B.0020.0002] # LEFT RIGHT SANS-SERIF ARROW +1F859 ; [*185C.0020.0002] # UP DOWN SANS-SERIF ARROW +1F860 ; [*185D.0020.0002] # WIDE-HEADED LEFTWARDS LIGHT BARB ARROW +1F861 ; [*185E.0020.0002] # WIDE-HEADED UPWARDS LIGHT BARB ARROW +1F862 ; [*185F.0020.0002] # WIDE-HEADED RIGHTWARDS LIGHT BARB ARROW +1F863 ; [*1860.0020.0002] # WIDE-HEADED DOWNWARDS LIGHT BARB ARROW +1F864 ; [*1861.0020.0002] # WIDE-HEADED NORTH WEST LIGHT BARB ARROW +1F865 ; [*1862.0020.0002] # WIDE-HEADED NORTH EAST LIGHT BARB ARROW +1F866 ; [*1863.0020.0002] # WIDE-HEADED SOUTH EAST LIGHT BARB ARROW +1F867 ; [*1864.0020.0002] # WIDE-HEADED SOUTH WEST LIGHT BARB ARROW +1F868 ; [*1865.0020.0002] # WIDE-HEADED LEFTWARDS BARB ARROW +1F869 ; [*1866.0020.0002] # WIDE-HEADED UPWARDS BARB ARROW +1F86A ; [*1867.0020.0002] # WIDE-HEADED RIGHTWARDS BARB ARROW +1F86B ; [*1868.0020.0002] # WIDE-HEADED DOWNWARDS BARB ARROW +1F86C ; [*1869.0020.0002] # WIDE-HEADED NORTH WEST BARB ARROW +1F86D ; [*186A.0020.0002] # WIDE-HEADED NORTH EAST BARB ARROW +1F86E ; [*186B.0020.0002] # WIDE-HEADED SOUTH EAST BARB ARROW +1F86F ; [*186C.0020.0002] # WIDE-HEADED SOUTH WEST BARB ARROW +1F870 ; [*186D.0020.0002] # WIDE-HEADED LEFTWARDS MEDIUM BARB ARROW +1F871 ; [*186E.0020.0002] # WIDE-HEADED UPWARDS MEDIUM BARB ARROW +1F872 ; [*186F.0020.0002] # WIDE-HEADED RIGHTWARDS MEDIUM BARB ARROW +1F873 ; [*1870.0020.0002] # WIDE-HEADED DOWNWARDS MEDIUM BARB ARROW +1F874 ; [*1871.0020.0002] # WIDE-HEADED NORTH WEST MEDIUM BARB ARROW +1F875 ; [*1872.0020.0002] # WIDE-HEADED NORTH EAST MEDIUM BARB ARROW +1F876 ; [*1873.0020.0002] # WIDE-HEADED SOUTH EAST MEDIUM BARB ARROW +1F877 ; [*1874.0020.0002] # WIDE-HEADED SOUTH WEST MEDIUM BARB ARROW +1F878 ; [*1875.0020.0002] # WIDE-HEADED LEFTWARDS HEAVY BARB ARROW +1F879 ; [*1876.0020.0002] # WIDE-HEADED UPWARDS HEAVY BARB ARROW +1F87A ; [*1877.0020.0002] # WIDE-HEADED RIGHTWARDS HEAVY BARB ARROW +1F87B ; [*1878.0020.0002] # WIDE-HEADED DOWNWARDS HEAVY BARB ARROW +1F87C ; [*1879.0020.0002] # WIDE-HEADED NORTH WEST HEAVY BARB ARROW +1F87D ; [*187A.0020.0002] # WIDE-HEADED NORTH EAST HEAVY BARB ARROW +1F87E ; [*187B.0020.0002] # WIDE-HEADED SOUTH EAST HEAVY BARB ARROW +1F87F ; [*187C.0020.0002] # WIDE-HEADED SOUTH WEST HEAVY BARB ARROW +1F880 ; [*187D.0020.0002] # WIDE-HEADED LEFTWARDS VERY HEAVY BARB ARROW +1F881 ; [*187E.0020.0002] # WIDE-HEADED UPWARDS VERY HEAVY BARB ARROW +1F882 ; [*187F.0020.0002] # WIDE-HEADED RIGHTWARDS VERY HEAVY BARB ARROW +1F883 ; [*1880.0020.0002] # WIDE-HEADED DOWNWARDS VERY HEAVY BARB ARROW +1F884 ; [*1881.0020.0002] # WIDE-HEADED NORTH WEST VERY HEAVY BARB ARROW +1F885 ; [*1882.0020.0002] # WIDE-HEADED NORTH EAST VERY HEAVY BARB ARROW +1F886 ; [*1883.0020.0002] # WIDE-HEADED SOUTH EAST VERY HEAVY BARB ARROW +1F887 ; [*1884.0020.0002] # WIDE-HEADED SOUTH WEST VERY HEAVY BARB ARROW +1F890 ; [*1885.0020.0002] # LEFTWARDS TRIANGLE ARROWHEAD +1F891 ; [*1886.0020.0002] # UPWARDS TRIANGLE ARROWHEAD +1F892 ; [*1887.0020.0002] # RIGHTWARDS TRIANGLE ARROWHEAD +1F893 ; [*1888.0020.0002] # DOWNWARDS TRIANGLE ARROWHEAD +1F894 ; [*1889.0020.0002] # LEFTWARDS WHITE ARROW WITHIN TRIANGLE ARROWHEAD +1F895 ; [*188A.0020.0002] # UPWARDS WHITE ARROW WITHIN TRIANGLE ARROWHEAD +1F896 ; [*188B.0020.0002] # RIGHTWARDS WHITE ARROW WITHIN TRIANGLE ARROWHEAD +1F897 ; [*188C.0020.0002] # DOWNWARDS WHITE ARROW WITHIN TRIANGLE ARROWHEAD +1F898 ; [*188D.0020.0002] # LEFTWARDS ARROW WITH NOTCHED TAIL +1F899 ; [*188E.0020.0002] # UPWARDS ARROW WITH NOTCHED TAIL +1F89A ; [*188F.0020.0002] # RIGHTWARDS ARROW WITH NOTCHED TAIL +1F89B ; [*1890.0020.0002] # DOWNWARDS ARROW WITH NOTCHED TAIL +1F89C ; [*1891.0020.0002] # HEAVY ARROW SHAFT WIDTH ONE +1F89D ; [*1892.0020.0002] # HEAVY ARROW SHAFT WIDTH TWO THIRDS +1F89E ; [*1893.0020.0002] # HEAVY ARROW SHAFT WIDTH ONE HALF +1F89F ; [*1894.0020.0002] # HEAVY ARROW SHAFT WIDTH ONE THIRD +1F8A0 ; [*1895.0020.0002] # LEFTWARDS BOTTOM-SHADED WHITE ARROW +1F8A1 ; [*1896.0020.0002] # RIGHTWARDS BOTTOM SHADED WHITE ARROW +1F8A2 ; [*1897.0020.0002] # LEFTWARDS TOP SHADED WHITE ARROW +1F8A3 ; [*1898.0020.0002] # RIGHTWARDS TOP SHADED WHITE ARROW +1F8A4 ; [*1899.0020.0002] # LEFTWARDS LEFT-SHADED WHITE ARROW +1F8A5 ; [*189A.0020.0002] # RIGHTWARDS RIGHT-SHADED WHITE ARROW +1F8A6 ; [*189B.0020.0002] # LEFTWARDS RIGHT-SHADED WHITE ARROW +1F8A7 ; [*189C.0020.0002] # RIGHTWARDS LEFT-SHADED WHITE ARROW +1F8A8 ; [*189D.0020.0002] # LEFTWARDS BACK-TILTED SHADOWED WHITE ARROW +1F8A9 ; [*189E.0020.0002] # RIGHTWARDS BACK-TILTED SHADOWED WHITE ARROW +1F8AA ; [*189F.0020.0002] # LEFTWARDS FRONT-TILTED SHADOWED WHITE ARROW +1F8AB ; [*18A0.0020.0002] # RIGHTWARDS FRONT-TILTED SHADOWED WHITE ARROW +1F8AC ; [*18A1.0020.0002] # WHITE ARROW SHAFT WIDTH ONE +1F8AD ; [*18A2.0020.0002] # WHITE ARROW SHAFT WIDTH TWO THIRDS +1F900 ; [*15C7.0020.0002] # CIRCLED CROSS FORMEE WITH FOUR DOTS +1F901 ; [*15C8.0020.0002] # CIRCLED CROSS FORMEE WITH TWO DOTS +1F902 ; [*15C9.0020.0002] # CIRCLED CROSS FORMEE +1F903 ; [*15CA.0020.0002] # LEFT HALF CIRCLE WITH FOUR DOTS +1F904 ; [*15CB.0020.0002] # LEFT HALF CIRCLE WITH THREE DOTS +1F905 ; [*15CC.0020.0002] # LEFT HALF CIRCLE WITH TWO DOTS +1F906 ; [*15CD.0020.0002] # LEFT HALF CIRCLE WITH DOT +1F907 ; [*15CE.0020.0002] # LEFT HALF CIRCLE +1F908 ; [*15CF.0020.0002] # DOWNWARD FACING HOOK +1F909 ; [*15D0.0020.0002] # DOWNWARD FACING NOTCHED HOOK +1F90A ; [*15D1.0020.0002] # DOWNWARD FACING HOOK WITH DOT +1F90B ; [*15D2.0020.0002] # DOWNWARD FACING NOTCHED HOOK WITH DOT +1F910 ; [*15D3.0020.0002] # ZIPPER-MOUTH FACE +1F911 ; [*15D4.0020.0002] # MONEY-MOUTH FACE +1F912 ; [*15D5.0020.0002] # FACE WITH THERMOMETER +1F913 ; [*15D6.0020.0002] # NERD FACE +1F914 ; [*15D7.0020.0002] # THINKING FACE +1F915 ; [*15D8.0020.0002] # FACE WITH HEAD-BANDAGE +1F916 ; [*15D9.0020.0002] # ROBOT FACE +1F917 ; [*15DA.0020.0002] # HUGGING FACE +1F918 ; [*15DB.0020.0002] # SIGN OF THE HORNS +1F919 ; [*15DC.0020.0002] # CALL ME HAND +1F91A ; [*15DD.0020.0002] # RAISED BACK OF HAND +1F91B ; [*15DE.0020.0002] # LEFT-FACING FIST +1F91C ; [*15DF.0020.0002] # RIGHT-FACING FIST +1F91D ; [*15E0.0020.0002] # HANDSHAKE +1F91E ; [*15E1.0020.0002] # HAND WITH INDEX AND MIDDLE FINGERS CROSSED +1F91F ; [*15E2.0020.0002] # I LOVE YOU HAND SIGN +1F920 ; [*15E3.0020.0002] # FACE WITH COWBOY HAT +1F921 ; [*15E4.0020.0002] # CLOWN FACE +1F922 ; [*15E5.0020.0002] # NAUSEATED FACE +1F923 ; [*15E6.0020.0002] # ROLLING ON THE FLOOR LAUGHING +1F924 ; [*15E7.0020.0002] # DROOLING FACE +1F925 ; [*15E8.0020.0002] # LYING FACE +1F926 ; [*15E9.0020.0002] # FACE PALM +1F927 ; [*15EA.0020.0002] # SNEEZING FACE +1F928 ; [*15EB.0020.0002] # FACE WITH ONE EYEBROW RAISED +1F929 ; [*15EC.0020.0002] # GRINNING FACE WITH STAR EYES +1F92A ; [*15ED.0020.0002] # GRINNING FACE WITH ONE LARGE AND ONE SMALL EYE +1F92B ; [*15EE.0020.0002] # FACE WITH FINGER COVERING CLOSED LIPS +1F92C ; [*15EF.0020.0002] # SERIOUS FACE WITH SYMBOLS COVERING MOUTH +1F92D ; [*15F0.0020.0002] # SMILING FACE WITH SMILING EYES AND HAND COVERING MOUTH +1F92E ; [*15F1.0020.0002] # FACE WITH OPEN MOUTH VOMITING +1F92F ; [*15F2.0020.0002] # SHOCKED FACE WITH EXPLODING HEAD +1F930 ; [*15F3.0020.0002] # PREGNANT WOMAN +1F931 ; [*15F4.0020.0002] # BREAST-FEEDING +1F932 ; [*15F5.0020.0002] # PALMS UP TOGETHER +1F933 ; [*15F6.0020.0002] # SELFIE +1F934 ; [*15F7.0020.0002] # PRINCE +1F935 ; [*15F8.0020.0002] # MAN IN TUXEDO +1F936 ; [*15F9.0020.0002] # MOTHER CHRISTMAS +1F937 ; [*15FA.0020.0002] # SHRUG +1F938 ; [*15FB.0020.0002] # PERSON DOING CARTWHEEL +1F939 ; [*15FC.0020.0002] # JUGGLING +1F93A ; [*15FD.0020.0002] # FENCER +1F93B ; [*15FE.0020.0002] # MODERN PENTATHLON +1F93C ; [*15FF.0020.0002] # WRESTLERS +1F93D ; [*1600.0020.0002] # WATER POLO +1F93E ; [*1601.0020.0002] # HANDBALL +1F940 ; [*1602.0020.0002] # WILTED FLOWER +1F941 ; [*1603.0020.0002] # DRUM WITH DRUMSTICKS +1F942 ; [*1604.0020.0002] # CLINKING GLASSES +1F943 ; [*1605.0020.0002] # TUMBLER GLASS +1F944 ; [*1606.0020.0002] # SPOON +1F945 ; [*1607.0020.0002] # GOAL NET +1F946 ; [*1608.0020.0002] # RIFLE +1F947 ; [*1609.0020.0002] # FIRST PLACE MEDAL +1F948 ; [*160A.0020.0002] # SECOND PLACE MEDAL +1F949 ; [*160B.0020.0002] # THIRD PLACE MEDAL +1F94A ; [*160C.0020.0002] # BOXING GLOVE +1F94B ; [*160D.0020.0002] # MARTIAL ARTS UNIFORM +1F94C ; [*160E.0020.0002] # CURLING STONE +1F950 ; [*160F.0020.0002] # CROISSANT +1F951 ; [*1610.0020.0002] # AVOCADO +1F952 ; [*1611.0020.0002] # CUCUMBER +1F953 ; [*1612.0020.0002] # BACON +1F954 ; [*1613.0020.0002] # POTATO +1F955 ; [*1614.0020.0002] # CARROT +1F956 ; [*1615.0020.0002] # BAGUETTE BREAD +1F957 ; [*1616.0020.0002] # GREEN SALAD +1F958 ; [*1617.0020.0002] # SHALLOW PAN OF FOOD +1F959 ; [*1618.0020.0002] # STUFFED FLATBREAD +1F95A ; [*1619.0020.0002] # EGG +1F95B ; [*161A.0020.0002] # GLASS OF MILK +1F95C ; [*161B.0020.0002] # PEANUTS +1F95D ; [*161C.0020.0002] # KIWIFRUIT +1F95E ; [*161D.0020.0002] # PANCAKES +1F95F ; [*161E.0020.0002] # DUMPLING +1F960 ; [*161F.0020.0002] # FORTUNE COOKIE +1F961 ; [*1620.0020.0002] # TAKEOUT BOX +1F962 ; [*1621.0020.0002] # CHOPSTICKS +1F963 ; [*1622.0020.0002] # BOWL WITH SPOON +1F964 ; [*1623.0020.0002] # CUP WITH STRAW +1F965 ; [*1624.0020.0002] # COCONUT +1F966 ; [*1625.0020.0002] # BROCCOLI +1F967 ; [*1626.0020.0002] # PIE +1F968 ; [*1627.0020.0002] # PRETZEL +1F969 ; [*1628.0020.0002] # CUT OF MEAT +1F96A ; [*1629.0020.0002] # SANDWICH +1F96B ; [*162A.0020.0002] # CANNED FOOD +1F980 ; [*162B.0020.0002] # CRAB +1F981 ; [*162C.0020.0002] # LION FACE +1F982 ; [*162D.0020.0002] # SCORPION +1F983 ; [*162E.0020.0002] # TURKEY +1F984 ; [*162F.0020.0002] # UNICORN FACE +1F985 ; [*1630.0020.0002] # EAGLE +1F986 ; [*1631.0020.0002] # DUCK +1F987 ; [*1632.0020.0002] # BAT +1F988 ; [*1633.0020.0002] # SHARK +1F989 ; [*1634.0020.0002] # OWL +1F98A ; [*1635.0020.0002] # FOX FACE +1F98B ; [*1636.0020.0002] # BUTTERFLY +1F98C ; [*1637.0020.0002] # DEER +1F98D ; [*1638.0020.0002] # GORILLA +1F98E ; [*1639.0020.0002] # LIZARD +1F98F ; [*163A.0020.0002] # RHINOCEROS +1F990 ; [*163B.0020.0002] # SHRIMP +1F991 ; [*163C.0020.0002] # SQUID +1F992 ; [*163D.0020.0002] # GIRAFFE FACE +1F993 ; [*163E.0020.0002] # ZEBRA FACE +1F994 ; [*163F.0020.0002] # HEDGEHOG +1F995 ; [*1640.0020.0002] # SAUROPOD +1F996 ; [*1641.0020.0002] # T-REX +1F997 ; [*1642.0020.0002] # CRICKET +1F9C0 ; [*1643.0020.0002] # CHEESE WEDGE +1F9D0 ; [*1644.0020.0002] # FACE WITH MONOCLE +1F9D1 ; [*1645.0020.0002] # ADULT +1F9D2 ; [*1646.0020.0002] # CHILD +1F9D3 ; [*1647.0020.0002] # OLDER ADULT +1F9D4 ; [*1648.0020.0002] # BEARDED PERSON +1F9D5 ; [*1649.0020.0002] # PERSON WITH HEADSCARF +1F9D6 ; [*164A.0020.0002] # PERSON IN STEAMY ROOM +1F9D7 ; [*164B.0020.0002] # PERSON CLIMBING +1F9D8 ; [*164C.0020.0002] # PERSON IN LOTUS POSITION +1F9D9 ; [*164D.0020.0002] # MAGE +1F9DA ; [*164E.0020.0002] # FAIRY +1F9DB ; [*164F.0020.0002] # VAMPIRE +1F9DC ; [*1650.0020.0002] # MERPERSON +1F9DD ; [*1651.0020.0002] # ELF +1F9DE ; [*1652.0020.0002] # GENIE +1F9DF ; [*1653.0020.0002] # ZOMBIE +1F9E0 ; [*1654.0020.0002] # BRAIN +1F9E1 ; [*1655.0020.0002] # ORANGE HEART +1F9E2 ; [*1656.0020.0002] # BILLED CAP +1F9E3 ; [*1657.0020.0002] # SCARF +1F9E4 ; [*1658.0020.0002] # GLOVES +1F9E5 ; [*1659.0020.0002] # COAT +1F9E6 ; [*165A.0020.0002] # SOCKS +0332 ; [.0000.0021.0002] # COMBINING LOW LINE +0313 ; [.0000.0022.0002] # COMBINING COMMA ABOVE +0343 ; [.0000.0022.0002] # COMBINING GREEK KORONIS +0486 ; [.0000.0022.0002] # COMBINING CYRILLIC PSILI PNEUMATA +2CF1 ; [.0000.0022.0002] # COPTIC COMBINING SPIRITUS LENIS +0314 ; [.0000.0023.0002] # COMBINING REVERSED COMMA ABOVE +0485 ; [.0000.0023.0002] # COMBINING CYRILLIC DASIA PNEUMATA +2CF0 ; [.0000.0023.0002] # COPTIC COMBINING SPIRITUS ASPER +0301 ; [.0000.0024.0002] # COMBINING ACUTE ACCENT +0341 ; [.0000.0024.0002] # COMBINING ACUTE TONE MARK +0954 ; [.0000.0024.0002] # DEVANAGARI ACUTE ACCENT +0300 ; [.0000.0025.0002] # COMBINING GRAVE ACCENT +0340 ; [.0000.0025.0002] # COMBINING GRAVE TONE MARK +0953 ; [.0000.0025.0002] # DEVANAGARI GRAVE ACCENT +0306 ; [.0000.0026.0002] # COMBINING BREVE +0302 ; [.0000.0027.0002] # COMBINING CIRCUMFLEX ACCENT +030C ; [.0000.0028.0002] # COMBINING CARON +030A ; [.0000.0029.0002] # COMBINING RING ABOVE +0342 ; [.0000.002A.0002] # COMBINING GREEK PERISPOMENI +0308 ; [.0000.002B.0002] # COMBINING DIAERESIS +0344 ; [.0000.002B.0002][.0000.0024.0002] # COMBINING GREEK DIALYTIKA TONOS +030B ; [.0000.002C.0002] # COMBINING DOUBLE ACUTE ACCENT +0303 ; [.0000.002D.0002] # COMBINING TILDE +0307 ; [.0000.002E.0002] # COMBINING DOT ABOVE +0338 ; [.0000.002F.0002] # COMBINING LONG SOLIDUS OVERLAY +0327 ; [.0000.0030.0002] # COMBINING CEDILLA +0328 ; [.0000.0031.0002] # COMBINING OGONEK +0304 ; [.0000.0032.0002] # COMBINING MACRON +030D ; [.0000.0033.0002] # COMBINING VERTICAL LINE ABOVE +030E ; [.0000.0033.0002] # COMBINING DOUBLE VERTICAL LINE ABOVE +0312 ; [.0000.0033.0002] # COMBINING TURNED COMMA ABOVE +0315 ; [.0000.0033.0002] # COMBINING COMMA ABOVE RIGHT +031A ; [.0000.0033.0002] # COMBINING LEFT ANGLE ABOVE +033D ; [.0000.0033.0002] # COMBINING X ABOVE +033E ; [.0000.0033.0002] # COMBINING VERTICAL TILDE +033F ; [.0000.0033.0002] # COMBINING DOUBLE OVERLINE +0346 ; [.0000.0033.0002] # COMBINING BRIDGE ABOVE +034A ; [.0000.0033.0002] # COMBINING NOT TILDE ABOVE +034B ; [.0000.0033.0002] # COMBINING HOMOTHETIC ABOVE +034C ; [.0000.0033.0002] # COMBINING ALMOST EQUAL TO ABOVE +0350 ; [.0000.0033.0002] # COMBINING RIGHT ARROWHEAD ABOVE +0351 ; [.0000.0033.0002] # COMBINING LEFT HALF RING ABOVE +0352 ; [.0000.0033.0002] # COMBINING FERMATA +0357 ; [.0000.0033.0002] # COMBINING RIGHT HALF RING ABOVE +035B ; [.0000.0033.0002] # COMBINING ZIGZAG ABOVE +035D ; [.0000.0033.0002] # COMBINING DOUBLE BREVE +035E ; [.0000.0033.0002] # COMBINING DOUBLE MACRON +0484 ; [.0000.0033.0002] # COMBINING CYRILLIC PALATALIZATION +0487 ; [.0000.0033.0002] # COMBINING CYRILLIC POKRYTIE +0741 ; [.0000.0033.0002] # SYRIAC QUSHSHAYA +0745 ; [.0000.0033.0002] # SYRIAC THREE DOTS ABOVE +17CB ; [.0000.0033.0002] # KHMER SIGN BANTOC +17CC ; [.0000.0033.0002] # KHMER SIGN ROBAT +17CD ; [.0000.0033.0002] # KHMER SIGN TOANDAKHIAT +17CE ; [.0000.0033.0002] # KHMER SIGN KAKABAT +17CF ; [.0000.0033.0002] # KHMER SIGN AHSDA +17D0 ; [.0000.0033.0002] # KHMER SIGN SAMYOK SANNYA +17D1 ; [.0000.0033.0002] # KHMER SIGN VIRIAM +17DD ; [.0000.0033.0002] # KHMER SIGN ATTHACAN +1AB0 ; [.0000.0033.0002] # COMBINING DOUBLED CIRCUMFLEX ACCENT +1AB1 ; [.0000.0033.0002] # COMBINING DIAERESIS-RING +1AB2 ; [.0000.0033.0002] # COMBINING INFINITY +1AB3 ; [.0000.0033.0002] # COMBINING DOWNWARDS ARROW +1AB4 ; [.0000.0033.0002] # COMBINING TRIPLE DOT +1ABB ; [.0000.0033.0002] # COMBINING PARENTHESES ABOVE +1ABC ; [.0000.0033.0002] # COMBINING DOUBLE PARENTHESES ABOVE +1DC0 ; [.0000.0033.0002] # COMBINING DOTTED GRAVE ACCENT +1DC1 ; [.0000.0033.0002] # COMBINING DOTTED ACUTE ACCENT +1DC3 ; [.0000.0033.0002] # COMBINING SUSPENSION MARK +1DC4 ; [.0000.0033.0002] # COMBINING MACRON-ACUTE +1DC5 ; [.0000.0033.0002] # COMBINING GRAVE-MACRON +1DC6 ; [.0000.0033.0002] # COMBINING MACRON-GRAVE +1DC7 ; [.0000.0033.0002] # COMBINING ACUTE-MACRON +1DC8 ; [.0000.0033.0002] # COMBINING GRAVE-ACUTE-GRAVE +1DC9 ; [.0000.0033.0002] # COMBINING ACUTE-GRAVE-ACUTE +1DCB ; [.0000.0033.0002] # COMBINING BREVE-MACRON +1DCC ; [.0000.0033.0002] # COMBINING MACRON-BREVE +1DCD ; [.0000.0033.0002] # COMBINING DOUBLE CIRCUMFLEX ABOVE +1DCE ; [.0000.0033.0002] # COMBINING OGONEK ABOVE +1DD1 ; [.0000.0033.0002] # COMBINING UR ABOVE +1DF5 ; [.0000.0033.0002] # COMBINING UP TACK ABOVE +1DF6 ; [.0000.0033.0002] # COMBINING KAVYKA ABOVE RIGHT +1DF7 ; [.0000.0033.0002] # COMBINING KAVYKA ABOVE LEFT +1DF8 ; [.0000.0033.0002] # COMBINING DOT ABOVE LEFT +1DFB ; [.0000.0033.0002] # COMBINING DELETION MARK +1DFE ; [.0000.0033.0002] # COMBINING LEFT ARROWHEAD ABOVE +20F0 ; [.0000.0033.0002] # COMBINING ASTERISK ABOVE +2CEF ; [.0000.0033.0002] # COPTIC COMBINING NI ABOVE +A67C ; [.0000.0033.0002] # COMBINING CYRILLIC KAVYKA +A67D ; [.0000.0033.0002] # COMBINING CYRILLIC PAYEROK +10AE5 ; [.0000.0033.0002] # MANICHAEAN ABBREVIATION MARK ABOVE +1BC9D ; [.0000.0033.0002] # DUPLOYAN THICK LETTER SELECTOR +0316 ; [.0000.0034.0002] # COMBINING GRAVE ACCENT BELOW +0317 ; [.0000.0034.0002] # COMBINING ACUTE ACCENT BELOW +0318 ; [.0000.0034.0002] # COMBINING LEFT TACK BELOW +0319 ; [.0000.0034.0002] # COMBINING RIGHT TACK BELOW +031C ; [.0000.0034.0002] # COMBINING LEFT HALF RING BELOW +031D ; [.0000.0034.0002] # COMBINING UP TACK BELOW +031E ; [.0000.0034.0002] # COMBINING DOWN TACK BELOW +031F ; [.0000.0034.0002] # COMBINING PLUS SIGN BELOW +0320 ; [.0000.0034.0002] # COMBINING MINUS SIGN BELOW +0329 ; [.0000.0034.0002] # COMBINING VERTICAL LINE BELOW +032A ; [.0000.0034.0002] # COMBINING BRIDGE BELOW +032B ; [.0000.0034.0002] # COMBINING INVERTED DOUBLE ARCH BELOW +032C ; [.0000.0034.0002] # COMBINING CARON BELOW +032F ; [.0000.0034.0002] # COMBINING INVERTED BREVE BELOW +0333 ; [.0000.0034.0002] # COMBINING DOUBLE LOW LINE +033A ; [.0000.0034.0002] # COMBINING INVERTED BRIDGE BELOW +033B ; [.0000.0034.0002] # COMBINING SQUARE BELOW +033C ; [.0000.0034.0002] # COMBINING SEAGULL BELOW +0347 ; [.0000.0034.0002] # COMBINING EQUALS SIGN BELOW +0348 ; [.0000.0034.0002] # COMBINING DOUBLE VERTICAL LINE BELOW +0349 ; [.0000.0034.0002] # COMBINING LEFT ANGLE BELOW +034D ; [.0000.0034.0002] # COMBINING LEFT RIGHT ARROW BELOW +034E ; [.0000.0034.0002] # COMBINING UPWARDS ARROW BELOW +0353 ; [.0000.0034.0002] # COMBINING X BELOW +0354 ; [.0000.0034.0002] # COMBINING LEFT ARROWHEAD BELOW +0355 ; [.0000.0034.0002] # COMBINING RIGHT ARROWHEAD BELOW +0356 ; [.0000.0034.0002] # COMBINING RIGHT ARROWHEAD AND UP ARROWHEAD BELOW +0359 ; [.0000.0034.0002] # COMBINING ASTERISK BELOW +035A ; [.0000.0034.0002] # COMBINING DOUBLE RING BELOW +035C ; [.0000.0034.0002] # COMBINING DOUBLE BREVE BELOW +035F ; [.0000.0034.0002] # COMBINING DOUBLE MACRON BELOW +0362 ; [.0000.0034.0002] # COMBINING DOUBLE RIGHTWARDS ARROW BELOW +0742 ; [.0000.0034.0002] # SYRIAC RUKKAKHA +0746 ; [.0000.0034.0002] # SYRIAC THREE DOTS BELOW +0859 ; [.0000.0034.0002] # MANDAIC AFFRICATION MARK +085A ; [.0000.0034.0002] # MANDAIC VOCALIZATION MARK +085B ; [.0000.0034.0002] # MANDAIC GEMINATION MARK +1AB5 ; [.0000.0034.0002] # COMBINING X-X BELOW +1AB6 ; [.0000.0034.0002] # COMBINING WIGGLY LINE BELOW +1AB7 ; [.0000.0034.0002] # COMBINING OPEN MARK BELOW +1AB8 ; [.0000.0034.0002] # COMBINING DOUBLE OPEN MARK BELOW +1AB9 ; [.0000.0034.0002] # COMBINING LIGHT CENTRALIZATION STROKE BELOW +1ABA ; [.0000.0034.0002] # COMBINING STRONG CENTRALIZATION STROKE BELOW +1ABD ; [.0000.0034.0002] # COMBINING PARENTHESES BELOW +1DC2 ; [.0000.0034.0002] # COMBINING SNAKE BELOW +1DCF ; [.0000.0034.0002] # COMBINING ZIGZAG BELOW +1DD0 ; [.0000.0034.0002] # COMBINING IS BELOW +1DF9 ; [.0000.0034.0002] # COMBINING WIDE INVERTED BRIDGE BELOW +1DFC ; [.0000.0034.0002] # COMBINING DOUBLE INVERTED BREVE BELOW +1DFD ; [.0000.0034.0002] # COMBINING ALMOST EQUAL TO BELOW +1DFF ; [.0000.0034.0002] # COMBINING RIGHT ARROWHEAD AND DOWN ARROWHEAD BELOW +20EC ; [.0000.0034.0002] # COMBINING RIGHTWARDS HARPOON WITH BARB DOWNWARDS +20ED ; [.0000.0034.0002] # COMBINING LEFTWARDS HARPOON WITH BARB DOWNWARDS +20EE ; [.0000.0034.0002] # COMBINING LEFT ARROW BELOW +20EF ; [.0000.0034.0002] # COMBINING RIGHT ARROW BELOW +FE27 ; [.0000.0034.0002] # COMBINING LIGATURE LEFT HALF BELOW +10A0D ; [.0000.0034.0002] # KHAROSHTHI SIGN DOUBLE RING BELOW +10AE6 ; [.0000.0034.0002] # MANICHAEAN ABBREVIATION MARK BELOW +0336 ; [.0000.0035.0002] # COMBINING LONG STROKE OVERLAY +0337 ; [.0000.0035.0002] # COMBINING SHORT SOLIDUS OVERLAY +20D8 ; [.0000.0035.0002] # COMBINING RING OVERLAY +20D9 ; [.0000.0035.0002] # COMBINING CLOCKWISE RING OVERLAY +20DA ; [.0000.0035.0002] # COMBINING ANTICLOCKWISE RING OVERLAY +20E5 ; [.0000.0035.0002] # COMBINING REVERSE SOLIDUS OVERLAY +20EA ; [.0000.0035.0002] # COMBINING LEFTWARDS ARROW OVERLAY +20EB ; [.0000.0035.0002] # COMBINING LONG DOUBLE SOLIDUS OVERLAY +1BC9E ; [.0000.0035.0002] # DUPLOYAN DOUBLE MARK +1ABE ; [.0000.0036.0002] # COMBINING PARENTHESES OVERLAY +20DD ; [.0000.0036.0002] # COMBINING ENCLOSING CIRCLE +20DE ; [.0000.0036.0002] # COMBINING ENCLOSING SQUARE +20DF ; [.0000.0036.0002] # COMBINING ENCLOSING DIAMOND +20E0 ; [.0000.0036.0002] # COMBINING ENCLOSING CIRCLE BACKSLASH +20E2 ; [.0000.0036.0002] # COMBINING ENCLOSING SCREEN +20E3 ; [.0000.0036.0002] # COMBINING ENCLOSING KEYCAP +20E4 ; [.0000.0036.0002] # COMBINING ENCLOSING UPWARD POINTING TRIANGLE +3099 ; [.0000.0037.0002] # COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK +FF9E ; [.0000.0037.0012] # HALFWIDTH KATAKANA VOICED SOUND MARK +309A ; [.0000.0038.0002] # COMBINING KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK +FF9F ; [.0000.0038.0012] # HALFWIDTH KATAKANA SEMI-VOICED SOUND MARK +0335 ; [.0000.0039.0002] # COMBINING SHORT STROKE OVERLAY +0305 ; [.0000.003A.0002] # COMBINING OVERLINE +0309 ; [.0000.003B.0002] # COMBINING HOOK ABOVE +030F ; [.0000.003C.0002] # COMBINING DOUBLE GRAVE ACCENT +0310 ; [.0000.003D.0002] # COMBINING CANDRABINDU +0311 ; [.0000.003E.0002] # COMBINING INVERTED BREVE +031B ; [.0000.003F.0002] # COMBINING HORN +0321 ; [.0000.0040.0002] # COMBINING PALATALIZED HOOK BELOW +0322 ; [.0000.0041.0002] # COMBINING RETROFLEX HOOK BELOW +0323 ; [.0000.0042.0002] # COMBINING DOT BELOW +0324 ; [.0000.0043.0002] # COMBINING DIAERESIS BELOW +0325 ; [.0000.0044.0002] # COMBINING RING BELOW +0326 ; [.0000.0045.0002] # COMBINING COMMA BELOW +032D ; [.0000.0046.0002] # COMBINING CIRCUMFLEX ACCENT BELOW +032E ; [.0000.0047.0002] # COMBINING BREVE BELOW +0330 ; [.0000.0048.0002] # COMBINING TILDE BELOW +0331 ; [.0000.0049.0002] # COMBINING MACRON BELOW +0334 ; [.0000.004A.0002] # COMBINING TILDE OVERLAY +0339 ; [.0000.004B.0002] # COMBINING RIGHT HALF RING BELOW +0345 ; [.0000.004C.0002] # COMBINING GREEK YPOGEGRAMMENI +0358 ; [.0000.004D.0002] # COMBINING DOT ABOVE RIGHT +0360 ; [.0000.004E.0002] # COMBINING DOUBLE TILDE +FE22 ; [.0000.004E.0002] # COMBINING DOUBLE TILDE LEFT HALF +FE29 ; [.0000.004E.0002] # COMBINING TILDE LEFT HALF BELOW +0361 ; [.0000.004F.0002] # COMBINING DOUBLE INVERTED BREVE +FE20 ; [.0000.004F.0002] # COMBINING LIGATURE LEFT HALF +0483 ; [.0000.0050.0002] # COMBINING CYRILLIC TITLO +FE2E ; [.0000.0050.0002] # COMBINING CYRILLIC TITLO LEFT HALF +A66F ; [.0000.0051.0002] # COMBINING CYRILLIC VZMET +05B0 ; [.0000.0052.0002] # HEBREW POINT SHEVA +05B1 ; [.0000.0053.0002] # HEBREW POINT HATAF SEGOL +05B2 ; [.0000.0054.0002] # HEBREW POINT HATAF PATAH +05B3 ; [.0000.0055.0002] # HEBREW POINT HATAF QAMATS +05B4 ; [.0000.0056.0002] # HEBREW POINT HIRIQ +05B5 ; [.0000.0057.0002] # HEBREW POINT TSERE +05B6 ; [.0000.0058.0002] # HEBREW POINT SEGOL +05B7 ; [.0000.0059.0002] # HEBREW POINT PATAH +05B8 ; [.0000.005A.0002] # HEBREW POINT QAMATS +05C7 ; [.0000.005A.0002] # HEBREW POINT QAMATS QATAN +05B9 ; [.0000.005B.0002] # HEBREW POINT HOLAM +05BA ; [.0000.005B.0002] # HEBREW POINT HOLAM HASER FOR VAV +05BB ; [.0000.005C.0002] # HEBREW POINT QUBUTS +05C2 ; [.0000.005D.0002] # HEBREW POINT SIN DOT +05C1 ; [.0000.005E.0002] # HEBREW POINT SHIN DOT +05BC ; [.0000.005F.0002] # HEBREW POINT DAGESH OR MAPIQ +05BF ; [.0000.0060.0002] # HEBREW POINT RAFE +FB1E ; [.0000.0061.0002] # HEBREW POINT JUDEO-SPANISH VARIKA +081C ; [.0000.0062.0002] # SAMARITAN VOWEL SIGN LONG E +081D ; [.0000.0062.0002] # SAMARITAN VOWEL SIGN E +081E ; [.0000.0063.0002] # SAMARITAN VOWEL SIGN OVERLONG AA +081F ; [.0000.0063.0002] # SAMARITAN VOWEL SIGN LONG AA +0820 ; [.0000.0063.0002] # SAMARITAN VOWEL SIGN AA +0821 ; [.0000.0064.0002] # SAMARITAN VOWEL SIGN OVERLONG A +0822 ; [.0000.0064.0002] # SAMARITAN VOWEL SIGN LONG A +0823 ; [.0000.0064.0002] # SAMARITAN VOWEL SIGN A +0824 ; [.0000.0065.0002] # SAMARITAN MODIFIER LETTER SHORT A +0825 ; [.0000.0065.0002] # SAMARITAN VOWEL SIGN SHORT A +0826 ; [.0000.0066.0002] # SAMARITAN VOWEL SIGN LONG U +0827 ; [.0000.0066.0002] # SAMARITAN VOWEL SIGN U +0828 ; [.0000.0067.0002] # SAMARITAN MODIFIER LETTER I +0829 ; [.0000.0067.0002] # SAMARITAN VOWEL SIGN LONG I +082A ; [.0000.0067.0002] # SAMARITAN VOWEL SIGN I +082B ; [.0000.0068.0002] # SAMARITAN VOWEL SIGN O +082C ; [.0000.0069.0002] # SAMARITAN VOWEL SIGN SUKUN +0818 ; [.0000.006A.0002] # SAMARITAN MARK OCCLUSION +0819 ; [.0000.006B.0002] # SAMARITAN MARK DAGESH +082D ; [.0000.006C.0002] # SAMARITAN MARK NEQUDAA +064B ; [.0000.006D.0002] # ARABIC FATHATAN +FE71 ; [.0000.006D.0018] # ARABIC TATWEEL WITH FATHATAN ABOVE +FE70 ; [.0000.006D.001A] # ARABIC FATHATAN ISOLATED FORM +08F0 ; [.0000.006E.0002] # ARABIC OPEN FATHATAN +08E7 ; [.0000.006F.0002] # ARABIC CURLY FATHATAN +064C ; [.0000.0070.0002] # ARABIC DAMMATAN +FE72 ; [.0000.0070.001A] # ARABIC DAMMATAN ISOLATED FORM +FC5E ; [.0000.0070.001A][.0000.0080.001A] # ARABIC LIGATURE SHADDA WITH DAMMATAN ISOLATED FORM +08F1 ; [.0000.0071.0002] # ARABIC OPEN DAMMATAN +08E8 ; [.0000.0072.0002] # ARABIC CURLY DAMMATAN +064D ; [.0000.0073.0002] # ARABIC KASRATAN +FE74 ; [.0000.0073.001A] # ARABIC KASRATAN ISOLATED FORM +FC5F ; [.0000.0073.001A][.0000.0080.001A] # ARABIC LIGATURE SHADDA WITH KASRATAN ISOLATED FORM +08F2 ; [.0000.0074.0002] # ARABIC OPEN KASRATAN +08E9 ; [.0000.0075.0002] # ARABIC CURLY KASRATAN +064E ; [.0000.0076.0002] # ARABIC FATHA +FE77 ; [.0000.0076.0018] # ARABIC FATHA MEDIAL FORM +FE76 ; [.0000.0076.001A] # ARABIC FATHA ISOLATED FORM +FCF2 ; [.0000.0076.0018][.0000.0080.0018] # ARABIC LIGATURE SHADDA WITH FATHA MEDIAL FORM +FC60 ; [.0000.0076.001A][.0000.0080.001A] # ARABIC LIGATURE SHADDA WITH FATHA ISOLATED FORM +08E4 ; [.0000.0077.0002] # ARABIC CURLY FATHA +08F4 ; [.0000.0078.0002] # ARABIC FATHA WITH RING +08F5 ; [.0000.0079.0002] # ARABIC FATHA WITH DOT ABOVE +064F ; [.0000.007A.0002] # ARABIC DAMMA +FE79 ; [.0000.007A.0018] # ARABIC DAMMA MEDIAL FORM +FE78 ; [.0000.007A.001A] # ARABIC DAMMA ISOLATED FORM +FCF3 ; [.0000.007A.0018][.0000.0080.0018] # ARABIC LIGATURE SHADDA WITH DAMMA MEDIAL FORM +FC61 ; [.0000.007A.001A][.0000.0080.001A] # ARABIC LIGATURE SHADDA WITH DAMMA ISOLATED FORM +08E5 ; [.0000.007B.0002] # ARABIC CURLY DAMMA +08FE ; [.0000.007C.0002] # ARABIC DAMMA WITH DOT +0650 ; [.0000.007D.0002] # ARABIC KASRA +FE7B ; [.0000.007D.0018] # ARABIC KASRA MEDIAL FORM +FE7A ; [.0000.007D.001A] # ARABIC KASRA ISOLATED FORM +FCF4 ; [.0000.007D.0018][.0000.0080.0018] # ARABIC LIGATURE SHADDA WITH KASRA MEDIAL FORM +FC62 ; [.0000.007D.001A][.0000.0080.001A] # ARABIC LIGATURE SHADDA WITH KASRA ISOLATED FORM +08E6 ; [.0000.007E.0002] # ARABIC CURLY KASRA +08F6 ; [.0000.007F.0002] # ARABIC KASRA WITH DOT BELOW +0651 ; [.0000.0080.0002] # ARABIC SHADDA +0AFB ; [.0000.0080.0002] # GUJARATI SIGN SHADDA +11237 ; [.0000.0080.0002] # KHOJKI SIGN SHADDA +FE7D ; [.0000.0080.0018] # ARABIC SHADDA MEDIAL FORM +FE7C ; [.0000.0080.001A] # ARABIC SHADDA ISOLATED FORM +FC63 ; [.0000.0080.001A][.0000.0098.001A] # ARABIC LIGATURE SHADDA WITH SUPERSCRIPT ALEF ISOLATED FORM +0652 ; [.0000.0081.0002] # ARABIC SUKUN +0AFA ; [.0000.0081.0002] # GUJARATI SIGN SUKUN +1123E ; [.0000.0081.0002] # KHOJKI SIGN SUKUN +FE7F ; [.0000.0081.0018] # ARABIC SUKUN MEDIAL FORM +FE7E ; [.0000.0081.001A] # ARABIC SUKUN ISOLATED FORM +0653 ; [.0000.0082.0002] # ARABIC MADDAH ABOVE +0AFC ; [.0000.0082.0002] # GUJARATI SIGN MADDAH +0654 ; [.0000.0083.0002] # ARABIC HAMZA ABOVE +0655 ; [.0000.0084.0002] # ARABIC HAMZA BELOW +065F ; [.0000.0085.0002] # ARABIC WAVY HAMZA BELOW +0656 ; [.0000.0086.0002] # ARABIC SUBSCRIPT ALEF +0657 ; [.0000.0087.0002] # ARABIC INVERTED DAMMA +0658 ; [.0000.0088.0002] # ARABIC MARK NOON GHUNNA +08FF ; [.0000.0089.0002] # ARABIC MARK SIDEWAYS NOON GHUNNA +0659 ; [.0000.008A.0002] # ARABIC ZWARAKAY +065A ; [.0000.008B.0002] # ARABIC VOWEL SIGN SMALL V ABOVE +065B ; [.0000.008C.0002] # ARABIC VOWEL SIGN INVERTED SMALL V ABOVE +065C ; [.0000.008D.0002] # ARABIC VOWEL SIGN DOT BELOW +065D ; [.0000.008E.0002] # ARABIC REVERSED DAMMA +065E ; [.0000.008F.0002] # ARABIC FATHA WITH TWO DOTS +08E3 ; [.0000.0090.0002] # ARABIC TURNED DAMMA BELOW +08F7 ; [.0000.0091.0002] # ARABIC LEFT ARROWHEAD ABOVE +08F8 ; [.0000.0092.0002] # ARABIC RIGHT ARROWHEAD ABOVE +08FD ; [.0000.0093.0002] # ARABIC RIGHT ARROWHEAD ABOVE WITH DOT +08FB ; [.0000.0094.0002] # ARABIC DOUBLE RIGHT ARROWHEAD ABOVE +08FC ; [.0000.0095.0002] # ARABIC DOUBLE RIGHT ARROWHEAD ABOVE WITH DOT +08F9 ; [.0000.0096.0002] # ARABIC LEFT ARROWHEAD BELOW +08FA ; [.0000.0097.0002] # ARABIC RIGHT ARROWHEAD BELOW +0670 ; [.0000.0098.0002] # ARABIC LETTER SUPERSCRIPT ALEF +0711 ; [.0000.0099.0002] # SYRIAC LETTER SUPERSCRIPT ALAPH +0730 ; [.0000.009A.0002] # SYRIAC PTHAHA ABOVE +0731 ; [.0000.009B.0002] # SYRIAC PTHAHA BELOW +0732 ; [.0000.009C.0002] # SYRIAC PTHAHA DOTTED +0733 ; [.0000.009D.0002] # SYRIAC ZQAPHA ABOVE +0734 ; [.0000.009E.0002] # SYRIAC ZQAPHA BELOW +0735 ; [.0000.009F.0002] # SYRIAC ZQAPHA DOTTED +0736 ; [.0000.00A0.0002] # SYRIAC RBASA ABOVE +0737 ; [.0000.00A1.0002] # SYRIAC RBASA BELOW +0738 ; [.0000.00A2.0002] # SYRIAC DOTTED ZLAMA HORIZONTAL +0739 ; [.0000.00A3.0002] # SYRIAC DOTTED ZLAMA ANGULAR +073A ; [.0000.00A4.0002] # SYRIAC HBASA ABOVE +073B ; [.0000.00A5.0002] # SYRIAC HBASA BELOW +073C ; [.0000.00A6.0002] # SYRIAC HBASA-ESASA DOTTED +073D ; [.0000.00A7.0002] # SYRIAC ESASA ABOVE +073E ; [.0000.00A8.0002] # SYRIAC ESASA BELOW +073F ; [.0000.00A9.0002] # SYRIAC RWAHA +07EB ; [.0000.00AA.0002] # NKO COMBINING SHORT HIGH TONE +07EC ; [.0000.00AB.0002] # NKO COMBINING SHORT LOW TONE +07ED ; [.0000.00AC.0002] # NKO COMBINING SHORT RISING TONE +07EE ; [.0000.00AD.0002] # NKO COMBINING LONG DESCENDING TONE +07EF ; [.0000.00AE.0002] # NKO COMBINING LONG HIGH TONE +07F0 ; [.0000.00AF.0002] # NKO COMBINING LONG LOW TONE +07F1 ; [.0000.00B0.0002] # NKO COMBINING LONG RISING TONE +07F2 ; [.0000.00B1.0002] # NKO COMBINING NASALIZATION MARK +07F3 ; [.0000.00B2.0002] # NKO COMBINING DOUBLE DOT ABOVE +135F ; [.0000.00B3.0002] # ETHIOPIC COMBINING GEMINATION MARK +135E ; [.0000.00B4.0002] # ETHIOPIC COMBINING VOWEL LENGTH MARK +135D ; [.0000.00B5.0002] # ETHIOPIC COMBINING GEMINATION AND VOWEL LENGTH MARK +A6F0 ; [.0000.00B6.0002] # BAMUM COMBINING MARK KOQNDON +A6F1 ; [.0000.00B7.0002] # BAMUM COMBINING MARK TUKWENTIS +16AF0 ; [.0000.00B8.0002] # BASSA VAH COMBINING HIGH TONE +16AF1 ; [.0000.00B9.0002] # BASSA VAH COMBINING LOW TONE +16AF2 ; [.0000.00BA.0002] # BASSA VAH COMBINING MID TONE +16AF3 ; [.0000.00BB.0002] # BASSA VAH COMBINING LOW-MID TONE +16AF4 ; [.0000.00BC.0002] # BASSA VAH COMBINING HIGH-LOW TONE +1E944 ; [.0000.00BD.0002] # ADLAM ALIF LENGTHENER +1E945 ; [.0000.00BD.0002] # ADLAM VOWEL LENGTHENER +1E946 ; [.0000.00BD.0002] # ADLAM GEMINATION MARK +1E94A ; [.0000.00BE.0002] # ADLAM NUKTA +1E947 ; [.0000.00BF.0002] # ADLAM HAMZA +1E948 ; [.0000.00C0.0002] # ADLAM CONSONANT MODIFIER +1E949 ; [.0000.00C1.0002] # ADLAM GEMINATE CONSONANT MODIFIER +093C ; [.0000.00C2.0002] # DEVANAGARI SIGN NUKTA +09BC ; [.0000.00C2.0002] # BENGALI SIGN NUKTA +0A3C ; [.0000.00C2.0002] # GURMUKHI SIGN NUKTA +0ABC ; [.0000.00C2.0002] # GUJARATI SIGN NUKTA +0AFD ; [.0000.00C2.0002] # GUJARATI SIGN THREE-DOT NUKTA ABOVE +0AFE ; [.0000.00C2.0002] # GUJARATI SIGN CIRCLE NUKTA ABOVE +0AFF ; [.0000.00C2.0002] # GUJARATI SIGN TWO-CIRCLE NUKTA ABOVE +0B3C ; [.0000.00C2.0002] # ORIYA SIGN NUKTA +0CBC ; [.0000.00C2.0002] # KANNADA SIGN NUKTA +1B34 ; [.0000.00C2.0002] # BALINESE SIGN REREKAN +1BE6 ; [.0000.00C2.0002] # BATAK SIGN TOMPI +1C37 ; [.0000.00C2.0002] # LEPCHA SIGN NUKTA +A9B3 ; [.0000.00C2.0002] # JAVANESE SIGN CECAK TELU +110BA ; [.0000.00C2.0002] # KAITHI SIGN NUKTA +11173 ; [.0000.00C2.0002] # MAHAJANI SIGN NUKTA +111CA ; [.0000.00C2.0002] # SHARADA SIGN NUKTA +11236 ; [.0000.00C2.0002] # KHOJKI SIGN NUKTA +112E9 ; [.0000.00C2.0002] # KHUDAWADI SIGN NUKTA +1133C ; [.0000.00C2.0002] # GRANTHA SIGN NUKTA +11446 ; [.0000.00C2.0002] # NEWA SIGN NUKTA +114C3 ; [.0000.00C2.0002] # TIRHUTA SIGN NUKTA +115C0 ; [.0000.00C2.0002] # SIDDHAM SIGN NUKTA +116B7 ; [.0000.00C2.0002] # TAKRI SIGN NUKTA +11A33 ; [.0000.00C2.0002] # ZANABAZAR SQUARE FINAL CONSONANT MARK +11D42 ; [.0000.00C2.0002] # MASARAM GONDI SIGN NUKTA +0900 ; [.0000.00C3.0002] # DEVANAGARI SIGN INVERTED CANDRABINDU +0901 ; [.0000.00C3.0002] # DEVANAGARI SIGN CANDRABINDU +0981 ; [.0000.00C3.0002] # BENGALI SIGN CANDRABINDU +0A01 ; [.0000.00C3.0002] # GURMUKHI SIGN ADAK BINDI +0A81 ; [.0000.00C3.0002] # GUJARATI SIGN CANDRABINDU +0B01 ; [.0000.00C3.0002] # ORIYA SIGN CANDRABINDU +0C00 ; [.0000.00C3.0002] # TELUGU SIGN COMBINING CANDRABINDU ABOVE +0C01 ; [.0000.00C3.0002] # TELUGU SIGN CANDRABINDU +0C81 ; [.0000.00C3.0002] # KANNADA SIGN CANDRABINDU +0D01 ; [.0000.00C3.0002] # MALAYALAM SIGN CANDRABINDU +1B00 ; [.0000.00C3.0002] # BALINESE SIGN ULU RICEM +1B01 ; [.0000.00C3.0002] # BALINESE SIGN ULU CANDRA +A8C5 ; [.0000.00C3.0002] # SAURASHTRA SIGN CANDRABINDU +A980 ; [.0000.00C3.0002] # JAVANESE SIGN PANYANGGA +11000 ; [.0000.00C3.0002] # BRAHMI SIGN CANDRABINDU +11080 ; [.0000.00C3.0002] # KAITHI SIGN CANDRABINDU +11100 ; [.0000.00C3.0002] # CHAKMA SIGN CANDRABINDU +11180 ; [.0000.00C3.0002] # SHARADA SIGN CANDRABINDU +11301 ; [.0000.00C3.0002] # GRANTHA SIGN CANDRABINDU +11443 ; [.0000.00C3.0002] # NEWA SIGN CANDRABINDU +114BF ; [.0000.00C3.0002] # TIRHUTA SIGN CANDRABINDU +115BC ; [.0000.00C3.0002] # SIDDHAM SIGN CANDRABINDU +11640 ; [.0000.00C3.0002] # MODI SIGN ARDHACANDRA +11A35 ; [.0000.00C3.0002] # ZANABAZAR SQUARE SIGN CANDRABINDU +11A36 ; [.0000.00C3.0002] # ZANABAZAR SQUARE SIGN CANDRABINDU WITH ORNAMENT +11A37 ; [.0000.00C3.0002] # ZANABAZAR SQUARE SIGN CANDRA WITH ORNAMENT +11C3C ; [.0000.00C3.0002] # BHAIKSUKI SIGN CANDRABINDU +11CB6 ; [.0000.00C3.0002] # MARCHEN SIGN CANDRABINDU +11D43 ; [.0000.00C3.0002] # MASARAM GONDI SIGN CANDRA +0902 ; [.0000.00C4.0002] # DEVANAGARI SIGN ANUSVARA +0982 ; [.0000.00C4.0002] # BENGALI SIGN ANUSVARA +0A02 ; [.0000.00C4.0002] # GURMUKHI SIGN BINDI +0A82 ; [.0000.00C4.0002] # GUJARATI SIGN ANUSVARA +0B02 ; [.0000.00C4.0002] # ORIYA SIGN ANUSVARA +0B82 ; [.0000.00C4.0002] # TAMIL SIGN ANUSVARA +0C02 ; [.0000.00C4.0002] # TELUGU SIGN ANUSVARA +0C82 ; [.0000.00C4.0002] # KANNADA SIGN ANUSVARA +0D00 ; [.0000.00C4.0002] # MALAYALAM SIGN COMBINING ANUSVARA ABOVE +0D02 ; [.0000.00C4.0002] # MALAYALAM SIGN ANUSVARA +0D82 ; [.0000.00C4.0002] # SINHALA SIGN ANUSVARAYA +0F7E ; [.0000.00C4.0002] # TIBETAN SIGN RJES SU NGA RO +1036 ; [.0000.00C4.0002] # MYANMAR SIGN ANUSVARA +17C6 ; [.0000.00C4.0002] # KHMER SIGN NIKAHIT +1A74 ; [.0000.00C4.0002] # TAI THAM SIGN MAI KANG +1B02 ; [.0000.00C4.0002] # BALINESE SIGN CECEK +1B80 ; [.0000.00C4.0002] # SUNDANESE SIGN PANYECEK +1CED ; [.0000.00C4.0002] # VEDIC SIGN TIRYAK +A80B ; [.0000.00C4.0002] # SYLOTI NAGRI SIGN ANUSVARA +A880 ; [.0000.00C4.0002] # SAURASHTRA SIGN ANUSVARA +A981 ; [.0000.00C4.0002] # JAVANESE SIGN CECAK +10A0E ; [.0000.00C4.0002] # KHAROSHTHI SIGN ANUSVARA +11001 ; [.0000.00C4.0002] # BRAHMI SIGN ANUSVARA +11081 ; [.0000.00C4.0002] # KAITHI SIGN ANUSVARA +11101 ; [.0000.00C4.0002] # CHAKMA SIGN ANUSVARA +11181 ; [.0000.00C4.0002] # SHARADA SIGN ANUSVARA +11234 ; [.0000.00C4.0002] # KHOJKI SIGN ANUSVARA +112DF ; [.0000.00C4.0002] # KHUDAWADI SIGN ANUSVARA +11300 ; [.0000.00C4.0002] # GRANTHA SIGN COMBINING ANUSVARA ABOVE +11302 ; [.0000.00C4.0002] # GRANTHA SIGN ANUSVARA +11444 ; [.0000.00C4.0002] # NEWA SIGN ANUSVARA +114C0 ; [.0000.00C4.0002] # TIRHUTA SIGN ANUSVARA +115BD ; [.0000.00C4.0002] # SIDDHAM SIGN ANUSVARA +1163D ; [.0000.00C4.0002] # MODI SIGN ANUSVARA +116AB ; [.0000.00C4.0002] # TAKRI SIGN ANUSVARA +11A38 ; [.0000.00C4.0002] # ZANABAZAR SQUARE SIGN ANUSVARA +11A96 ; [.0000.00C4.0002] # SOYOMBO SIGN ANUSVARA +11C3D ; [.0000.00C4.0002] # BHAIKSUKI SIGN ANUSVARA +11CB5 ; [.0000.00C4.0002] # MARCHEN SIGN ANUSVARA +11D40 ; [.0000.00C4.0002] # MASARAM GONDI SIGN ANUSVARA +0903 ; [.0000.00C5.0002] # DEVANAGARI SIGN VISARGA +0983 ; [.0000.00C5.0002] # BENGALI SIGN VISARGA +0A03 ; [.0000.00C5.0002] # GURMUKHI SIGN VISARGA +0A83 ; [.0000.00C5.0002] # GUJARATI SIGN VISARGA +0B03 ; [.0000.00C5.0002] # ORIYA SIGN VISARGA +0C03 ; [.0000.00C5.0002] # TELUGU SIGN VISARGA +0C83 ; [.0000.00C5.0002] # KANNADA SIGN VISARGA +0D03 ; [.0000.00C5.0002] # MALAYALAM SIGN VISARGA +0D83 ; [.0000.00C5.0002] # SINHALA SIGN VISARGAYA +0F7F ; [.0000.00C5.0002] # TIBETAN SIGN RNAM BCAD +1038 ; [.0000.00C5.0002] # MYANMAR SIGN VISARGA +17C7 ; [.0000.00C5.0002] # KHMER SIGN REAHMUK +1B04 ; [.0000.00C5.0002] # BALINESE SIGN BISAH +1B82 ; [.0000.00C5.0002] # SUNDANESE SIGN PANGWISAD +1CF2 ; [.0000.00C5.0002] # VEDIC SIGN ARDHAVISARGA +1CF3 ; [.0000.00C5.0002] # VEDIC SIGN ROTATED ARDHAVISARGA +A881 ; [.0000.00C5.0002] # SAURASHTRA SIGN VISARGA +A983 ; [.0000.00C5.0002] # JAVANESE SIGN WIGNYAN +10A0F ; [.0000.00C5.0002] # KHAROSHTHI SIGN VISARGA +11002 ; [.0000.00C5.0002] # BRAHMI SIGN VISARGA +11082 ; [.0000.00C5.0002] # KAITHI SIGN VISARGA +11102 ; [.0000.00C5.0002] # CHAKMA SIGN VISARGA +11182 ; [.0000.00C5.0002] # SHARADA SIGN VISARGA +11303 ; [.0000.00C5.0002] # GRANTHA SIGN VISARGA +11445 ; [.0000.00C5.0002] # NEWA SIGN VISARGA +114C1 ; [.0000.00C5.0002] # TIRHUTA SIGN VISARGA +115BE ; [.0000.00C5.0002] # SIDDHAM SIGN VISARGA +1163E ; [.0000.00C5.0002] # MODI SIGN VISARGA +116AC ; [.0000.00C5.0002] # TAKRI SIGN VISARGA +11A39 ; [.0000.00C5.0002] # ZANABAZAR SQUARE SIGN VISARGA +11A97 ; [.0000.00C5.0002] # SOYOMBO SIGN VISARGA +11C3E ; [.0000.00C5.0002] # BHAIKSUKI SIGN VISARGA +11D41 ; [.0000.00C5.0002] # MASARAM GONDI SIGN VISARGA +0A70 ; [.0000.00C6.0002] # GURMUKHI TIPPI +0A71 ; [.0000.00C7.0002] # GURMUKHI ADDAK +1B03 ; [.0000.00C8.0002] # BALINESE SIGN SURANG +A982 ; [.0000.00C9.0002] # JAVANESE SIGN LAYAR +1B81 ; [.0000.00CA.0002] # SUNDANESE SIGN PANGLAYAR +ABEC ; [.0000.00CB.0002] # MEETEI MAYEK LUM IYEK +10A38 ; [.0000.00CC.0002] # KHAROSHTHI SIGN BAR ABOVE +10A39 ; [.0000.00CD.0002] # KHAROSHTHI SIGN CAUDA +10A3A ; [.0000.00CE.0002] # KHAROSHTHI SIGN DOT BELOW +111CB ; [.0000.00CF.0002] # SHARADA VOWEL MODIFIER MARK +111CC ; [.0000.00D0.0002] # SHARADA EXTRA SHORT VOWEL MARK +11A98 ; [.0000.00D1.0002] # SOYOMBO GEMINATION MARK +0E4E ; [.0000.00D2.0002] # THAI CHARACTER YAMAKKAN +0E47 ; [.0000.00D3.0002] # THAI CHARACTER MAITAIKHU +0E48 ; [.0000.00D4.0002] # THAI CHARACTER MAI EK +0E49 ; [.0000.00D5.0002] # THAI CHARACTER MAI THO +0E4A ; [.0000.00D6.0002] # THAI CHARACTER MAI TRI +0E4B ; [.0000.00D7.0002] # THAI CHARACTER MAI CHATTAWA +0E4C ; [.0000.00D8.0002] # THAI CHARACTER THANTHAKHAT +0E4D ; [.0000.00D9.0002] # THAI CHARACTER NIKHAHIT +0EC8 ; [.0000.00DA.0002] # LAO TONE MAI EK +0EC9 ; [.0000.00DB.0002] # LAO TONE MAI THO +0ECA ; [.0000.00DC.0002] # LAO TONE MAI TI +0ECB ; [.0000.00DD.0002] # LAO TONE MAI CATAWA +0ECC ; [.0000.00DE.0002] # LAO CANCELLATION MARK +0ECD ; [.0000.00DF.0002] # LAO NIGGAHITA +AABF ; [.0000.00E0.0002] # TAI VIET TONE MAI EK +AAC1 ; [.0000.00E1.0002] # TAI VIET TONE MAI THO +0F39 ; [.0000.00E2.0002] # TIBETAN MARK TSA -PHRU +A92B ; [.0000.00E3.0002] # KAYAH LI TONE PLOPHU +A92C ; [.0000.00E4.0002] # KAYAH LI TONE CALYA +A92D ; [.0000.00E5.0002] # KAYAH LI TONE CALYA PLOPHU +1037 ; [.0000.00E6.0002] # MYANMAR SIGN DOT BELOW +17C8 ; [.0000.00E7.0002] # KHMER SIGN YUUKALEAPINTU +17C9 ; [.0000.00E8.0002] # KHMER SIGN MUUSIKATOAN +17CA ; [.0000.00E9.0002] # KHMER SIGN TRIISAP +1A75 ; [.0000.00EA.0002] # TAI THAM SIGN TONE-1 +1A76 ; [.0000.00EB.0002] # TAI THAM SIGN TONE-2 +1A77 ; [.0000.00EC.0002] # TAI THAM SIGN KHUEN TONE-3 +1A78 ; [.0000.00ED.0002] # TAI THAM SIGN KHUEN TONE-4 +1A79 ; [.0000.00EE.0002] # TAI THAM SIGN KHUEN TONE-5 +1A7A ; [.0000.00EF.0002] # TAI THAM SIGN RA HAAM +1A7B ; [.0000.00F0.0002] # TAI THAM SIGN MAI SAM +1A7C ; [.0000.00F1.0002] # TAI THAM SIGN KHUEN-LUE KARAN +1939 ; [.0000.00F2.0002] # LIMBU SIGN MUKPHRENG +193A ; [.0000.00F3.0002] # LIMBU SIGN KEMPHRENG +193B ; [.0000.00F4.0002] # LIMBU SIGN SA-I +16B30 ; [.0000.00F5.0002] # PAHAWH HMONG MARK CIM TUB +16B31 ; [.0000.00F6.0002] # PAHAWH HMONG MARK CIM SO +16B32 ; [.0000.00F7.0002] # PAHAWH HMONG MARK CIM KES +16B33 ; [.0000.00F8.0002] # PAHAWH HMONG MARK CIM KHAV +16B34 ; [.0000.00F9.0002] # PAHAWH HMONG MARK CIM SUAM +16B35 ; [.0000.00FA.0002] # PAHAWH HMONG MARK CIM HOM +16B36 ; [.0000.00FB.0002] # PAHAWH HMONG MARK CIM TAUM +302A ; [.0000.00FC.0002] # IDEOGRAPHIC LEVEL TONE MARK +302B ; [.0000.00FD.0002] # IDEOGRAPHIC RISING TONE MARK +302C ; [.0000.00FE.0002] # IDEOGRAPHIC DEPARTING TONE MARK +302D ; [.0000.00FF.0002] # IDEOGRAPHIC ENTERING TONE MARK +302E ; [.0000.0100.0002] # HANGUL SINGLE DOT TONE MARK +302F ; [.0000.0101.0002] # HANGUL DOUBLE DOT TONE MARK +20D0 ; [.0000.0102.0002] # COMBINING LEFT HARPOON ABOVE +20D1 ; [.0000.0103.0002] # COMBINING RIGHT HARPOON ABOVE +20D2 ; [.0000.0104.0002] # COMBINING LONG VERTICAL LINE OVERLAY +20D3 ; [.0000.0104.0002] # COMBINING SHORT VERTICAL LINE OVERLAY +20D4 ; [.0000.0105.0002] # COMBINING ANTICLOCKWISE ARROW ABOVE +20D5 ; [.0000.0106.0002] # COMBINING CLOCKWISE ARROW ABOVE +20D6 ; [.0000.0107.0002] # COMBINING LEFT ARROW ABOVE +20D7 ; [.0000.0108.0002] # COMBINING RIGHT ARROW ABOVE +20DB ; [.0000.0109.0002] # COMBINING THREE DOTS ABOVE +20DC ; [.0000.010A.0002] # COMBINING FOUR DOTS ABOVE +20E1 ; [.0000.010B.0002] # COMBINING LEFT RIGHT ARROW ABOVE +20E6 ; [.0000.010C.0002] # COMBINING DOUBLE VERTICAL STROKE OVERLAY +20E7 ; [.0000.010D.0002] # COMBINING ANNUITY SYMBOL +20E8 ; [.0000.010E.0002] # COMBINING TRIPLE UNDERDOT +20E9 ; [.0000.010F.0002] # COMBINING WIDE BRIDGE ABOVE +101FD ; [.0000.0110.0002] # PHAISTOS DISC SIGN COMBINING OBLIQUE STROKE +02D0 ; [.1C5C.0020.0002] # MODIFIER LETTER TRIANGULAR COLON +02D1 ; [.1C5D.0020.0002] # MODIFIER LETTER HALF TRIANGULAR COLON +0971 ; [.1C5E.0020.0002] # DEVANAGARI SIGN HIGH SPACING DOT +0E46 ; [.1C5F.0020.0002] # THAI CHARACTER MAIYAMOK +0EC6 ; [.1C60.0020.0002] # LAO KO LA +17D7 ; [.1C61.0020.0002] # KHMER SIGN LEK TOO +1AA7 ; [.1C62.0020.0002] # TAI THAM SIGN MAI YAMOK +A9CF ; [.1C63.0020.0002] # JAVANESE PANGRANGKEP +A9E6 ; [.1C64.0020.0002] # MYANMAR MODIFIER LETTER SHAN REDUPLICATION +AA70 ; [.1C65.0020.0002] # MYANMAR MODIFIER LETTER KHAMTI REDUPLICATION +AADD ; [.1C66.0020.0002] # TAI VIET SYMBOL SAM +AAF3 ; [.1C67.0020.0002] # MEETEI MAYEK SYLLABLE REPETITION MARK +AAF4 ; [.1C68.0020.0002] # MEETEI MAYEK WORD REPETITION MARK +16B42 ; [.1C69.0020.0002] # PAHAWH HMONG SIGN VOS NRUA +16B43 ; [.1C6A.0020.0002] # PAHAWH HMONG SIGN IB YAM +3005 ; [.1C6B.0020.0002] # IDEOGRAPHIC ITERATION MARK +303B ; [.1C6C.0020.0002] # VERTICAL IDEOGRAPHIC ITERATION MARK +16FE0 ; [.1C6D.0020.0002] # TANGUT ITERATION MARK +16FE1 ; [.1C6E.0020.0002] # NUSHU ITERATION MARK +3031 ; [.1C6F.0020.0002] # VERTICAL KANA REPEAT MARK +3032 ; [.1C6F.0020.0002][.0000.0037.0002] # VERTICAL KANA REPEAT WITH VOICED SOUND MARK +3033 ; [.1C70.0020.0002] # VERTICAL KANA REPEAT MARK UPPER HALF +3034 ; [.1C70.0020.0002][.0000.0037.0002] # VERTICAL KANA REPEAT WITH VOICED SOUND MARK UPPER HALF +3035 ; [.1C71.0020.0002] # VERTICAL KANA REPEAT MARK LOWER HALF +309D ; [.1C72.0020.0002] # HIRAGANA ITERATION MARK +309E ; [.1C72.0020.0002][.0000.0037.0002] # HIRAGANA VOICED ITERATION MARK +30FC ; [.1C73.0020.0002] # KATAKANA-HIRAGANA PROLONGED SOUND MARK +FF70 ; [.1C73.0020.0012] # HALFWIDTH KATAKANA-HIRAGANA PROLONGED SOUND MARK +30FD ; [.1C74.0020.0002] # KATAKANA ITERATION MARK +30FE ; [.1C74.0020.0002][.0000.0037.0002] # KATAKANA VOICED ITERATION MARK +00A4 ; [.1C75.0020.0002] # CURRENCY SIGN +00A2 ; [.1C76.0020.0002] # CENT SIGN +FFE0 ; [.1C76.0020.0003] # FULLWIDTH CENT SIGN +0024 ; [.1C77.0020.0002] # DOLLAR SIGN +FF04 ; [.1C77.0020.0003] # FULLWIDTH DOLLAR SIGN +FE69 ; [.1C77.0020.000F] # SMALL DOLLAR SIGN +00A3 ; [.1C78.0020.0002] # POUND SIGN +FFE1 ; [.1C78.0020.0003] # FULLWIDTH POUND SIGN +00A5 ; [.1C79.0020.0002] # YEN SIGN +FFE5 ; [.1C79.0020.0003] # FULLWIDTH YEN SIGN +058F ; [.1C7A.0020.0002] # ARMENIAN DRAM SIGN +060B ; [.1C7B.0020.0002] # AFGHANI SIGN +09F2 ; [.1C7C.0020.0002] # BENGALI RUPEE MARK +09F3 ; [.1C7D.0020.0002] # BENGALI RUPEE SIGN +09FB ; [.1C7E.0020.0002] # BENGALI GANDA MARK +0AF1 ; [.1C7F.0020.0002] # GUJARATI RUPEE SIGN +A838 ; [.1C80.0020.0002] # NORTH INDIC RUPEE MARK +0BF9 ; [.1C81.0020.0002] # TAMIL RUPEE SIGN +0E3F ; [.1C82.0020.0002] # THAI CURRENCY SYMBOL BAHT +17DB ; [.1C83.0020.0002] # KHMER CURRENCY SYMBOL RIEL +20A0 ; [.1C84.0020.0002] # EURO-CURRENCY SIGN +20A1 ; [.1C85.0020.0002] # COLON SIGN +20A2 ; [.1C86.0020.0002] # CRUZEIRO SIGN +20A3 ; [.1C87.0020.0002] # FRENCH FRANC SIGN +20A4 ; [.1C88.0020.0002] # LIRA SIGN +20A5 ; [.1C89.0020.0002] # MILL SIGN +20A6 ; [.1C8A.0020.0002] # NAIRA SIGN +20A7 ; [.1C8B.0020.0002] # PESETA SIGN +20A9 ; [.1C8C.0020.0002] # WON SIGN +FFE6 ; [.1C8C.0020.0003] # FULLWIDTH WON SIGN +20AA ; [.1C8D.0020.0002] # NEW SHEQEL SIGN +20AB ; [.1C8E.0020.0002] # DONG SIGN +20AC ; [.1C8F.0020.0002] # EURO SIGN +20AD ; [.1C90.0020.0002] # KIP SIGN +20AE ; [.1C91.0020.0002] # TUGRIK SIGN +20AF ; [.1C92.0020.0002] # DRACHMA SIGN +20B0 ; [.1C93.0020.0002] # GERMAN PENNY SIGN +20B1 ; [.1C94.0020.0002] # PESO SIGN +20B2 ; [.1C95.0020.0002] # GUARANI SIGN +20B3 ; [.1C96.0020.0002] # AUSTRAL SIGN +20B4 ; [.1C97.0020.0002] # HRYVNIA SIGN +20B5 ; [.1C98.0020.0002] # CEDI SIGN +20B6 ; [.1C99.0020.0002] # LIVRE TOURNOIS SIGN +20B7 ; [.1C9A.0020.0002] # SPESMILO SIGN +20B8 ; [.1C9B.0020.0002] # TENGE SIGN +20B9 ; [.1C9C.0020.0002] # INDIAN RUPEE SIGN +20BA ; [.1C9D.0020.0002] # TURKISH LIRA SIGN +20BB ; [.1C9E.0020.0002] # NORDIC MARK SIGN +20BC ; [.1C9F.0020.0002] # MANAT SIGN +20BD ; [.1CA0.0020.0002] # RUBLE SIGN +20BE ; [.1CA1.0020.0002] # LARI SIGN +20BF ; [.1CA2.0020.0002] # BITCOIN SIGN +0030 ; [.1CA3.0020.0002] # DIGIT ZERO +0660 ; [.1CA3.0020.0002] # ARABIC-INDIC DIGIT ZERO +06F0 ; [.1CA3.0020.0002] # EXTENDED ARABIC-INDIC DIGIT ZERO +07C0 ; [.1CA3.0020.0002] # NKO DIGIT ZERO +0966 ; [.1CA3.0020.0002] # DEVANAGARI DIGIT ZERO +09E6 ; [.1CA3.0020.0002] # BENGALI DIGIT ZERO +0A66 ; [.1CA3.0020.0002] # GURMUKHI DIGIT ZERO +0AE6 ; [.1CA3.0020.0002] # GUJARATI DIGIT ZERO +0B66 ; [.1CA3.0020.0002] # ORIYA DIGIT ZERO +0BE6 ; [.1CA3.0020.0002] # TAMIL DIGIT ZERO +0C66 ; [.1CA3.0020.0002] # TELUGU DIGIT ZERO +0C78 ; [.1CA3.0020.0002] # TELUGU FRACTION DIGIT ZERO FOR ODD POWERS OF FOUR +0CE6 ; [.1CA3.0020.0002] # KANNADA DIGIT ZERO +0D66 ; [.1CA3.0020.0002] # MALAYALAM DIGIT ZERO +0DE6 ; [.1CA3.0020.0002] # SINHALA LITH DIGIT ZERO +0E50 ; [.1CA3.0020.0002] # THAI DIGIT ZERO +0ED0 ; [.1CA3.0020.0002] # LAO DIGIT ZERO +0F20 ; [.1CA3.0020.0002] # TIBETAN DIGIT ZERO +1040 ; [.1CA3.0020.0002] # MYANMAR DIGIT ZERO +1090 ; [.1CA3.0020.0002] # MYANMAR SHAN DIGIT ZERO +17E0 ; [.1CA3.0020.0002] # KHMER DIGIT ZERO +17F0 ; [.1CA3.0020.0002] # KHMER SYMBOL LEK ATTAK SON +1810 ; [.1CA3.0020.0002] # MONGOLIAN DIGIT ZERO +1946 ; [.1CA3.0020.0002] # LIMBU DIGIT ZERO +19D0 ; [.1CA3.0020.0002] # NEW TAI LUE DIGIT ZERO +1A80 ; [.1CA3.0020.0002] # TAI THAM HORA DIGIT ZERO +1A90 ; [.1CA3.0020.0002] # TAI THAM THAM DIGIT ZERO +1B50 ; [.1CA3.0020.0002] # BALINESE DIGIT ZERO +1BB0 ; [.1CA3.0020.0002] # SUNDANESE DIGIT ZERO +1C40 ; [.1CA3.0020.0002] # LEPCHA DIGIT ZERO +1C50 ; [.1CA3.0020.0002] # OL CHIKI DIGIT ZERO +3007 ; [.1CA3.0020.0002] # IDEOGRAPHIC NUMBER ZERO +A620 ; [.1CA3.0020.0002] # VAI DIGIT ZERO +A8D0 ; [.1CA3.0020.0002] # SAURASHTRA DIGIT ZERO +A900 ; [.1CA3.0020.0002] # KAYAH LI DIGIT ZERO +A9D0 ; [.1CA3.0020.0002] # JAVANESE DIGIT ZERO +A9F0 ; [.1CA3.0020.0002] # MYANMAR TAI LAING DIGIT ZERO +AA50 ; [.1CA3.0020.0002] # CHAM DIGIT ZERO +ABF0 ; [.1CA3.0020.0002] # MEETEI MAYEK DIGIT ZERO +1018A ; [.1CA3.0020.0002] # GREEK ZERO SIGN +104A0 ; [.1CA3.0020.0002] # OSMANYA DIGIT ZERO +11066 ; [.1CA3.0020.0002] # BRAHMI DIGIT ZERO +110F0 ; [.1CA3.0020.0002] # SORA SOMPENG DIGIT ZERO +11136 ; [.1CA3.0020.0002] # CHAKMA DIGIT ZERO +111D0 ; [.1CA3.0020.0002] # SHARADA DIGIT ZERO +112F0 ; [.1CA3.0020.0002] # KHUDAWADI DIGIT ZERO +11450 ; [.1CA3.0020.0002] # NEWA DIGIT ZERO +114D0 ; [.1CA3.0020.0002] # TIRHUTA DIGIT ZERO +11650 ; [.1CA3.0020.0002] # MODI DIGIT ZERO +116C0 ; [.1CA3.0020.0002] # TAKRI DIGIT ZERO +11730 ; [.1CA3.0020.0002] # AHOM DIGIT ZERO +118E0 ; [.1CA3.0020.0002] # WARANG CITI DIGIT ZERO +11C50 ; [.1CA3.0020.0002] # BHAIKSUKI DIGIT ZERO +11D50 ; [.1CA3.0020.0002] # MASARAM GONDI DIGIT ZERO +16A60 ; [.1CA3.0020.0002] # MRO DIGIT ZERO +16B50 ; [.1CA3.0020.0002] # PAHAWH HMONG DIGIT ZERO +1E950 ; [.1CA3.0020.0002] # ADLAM DIGIT ZERO +FF10 ; [.1CA3.0020.0003] # FULLWIDTH DIGIT ZERO +0F33 ; [.1CA3.0020.0004] # TIBETAN DIGIT HALF ZERO +1F100 ; [.1CA3.0020.0004][*0278.0020.0004] # DIGIT ZERO FULL STOP +1F101 ; [.1CA3.0020.0004][*0222.0020.0004] # DIGIT ZERO COMMA +1D7CE ; [.1CA3.0020.0005] # MATHEMATICAL BOLD DIGIT ZERO +1D7D8 ; [.1CA3.0020.0005] # MATHEMATICAL DOUBLE-STRUCK DIGIT ZERO +1D7E2 ; [.1CA3.0020.0005] # MATHEMATICAL SANS-SERIF DIGIT ZERO +1D7EC ; [.1CA3.0020.0005] # MATHEMATICAL SANS-SERIF BOLD DIGIT ZERO +1D7F6 ; [.1CA3.0020.0005] # MATHEMATICAL MONOSPACE DIGIT ZERO +24EA ; [.1CA3.0020.0006] # CIRCLED DIGIT ZERO +24FF ; [.1CA3.0020.0006] # NEGATIVE CIRCLED DIGIT ZERO +1F10B ; [.1CA3.0020.0006] # DINGBAT CIRCLED SANS-SERIF DIGIT ZERO +1F10C ; [.1CA3.0020.0006] # DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT ZERO +2070 ; [.1CA3.0020.0014] # SUPERSCRIPT ZERO +2080 ; [.1CA3.0020.0015] # SUBSCRIPT ZERO +2189 ; [.1CA3.0020.001E][*063C.0020.001E][.1CA6.0020.001E] # VULGAR FRACTION ZERO THIRDS +3358 ; [.1CA3.0020.0004][.FB40.0020.0004][.F0B9.0000.0000] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR ZERO +0031 ; [.1CA4.0020.0002] # DIGIT ONE +0661 ; [.1CA4.0020.0002] # ARABIC-INDIC DIGIT ONE +06F1 ; [.1CA4.0020.0002] # EXTENDED ARABIC-INDIC DIGIT ONE +07C1 ; [.1CA4.0020.0002] # NKO DIGIT ONE +0967 ; [.1CA4.0020.0002] # DEVANAGARI DIGIT ONE +09E7 ; [.1CA4.0020.0002] # BENGALI DIGIT ONE +0A67 ; [.1CA4.0020.0002] # GURMUKHI DIGIT ONE +0AE7 ; [.1CA4.0020.0002] # GUJARATI DIGIT ONE +0B67 ; [.1CA4.0020.0002] # ORIYA DIGIT ONE +0BE7 ; [.1CA4.0020.0002] # TAMIL DIGIT ONE +0C67 ; [.1CA4.0020.0002] # TELUGU DIGIT ONE +0C79 ; [.1CA4.0020.0002] # TELUGU FRACTION DIGIT ONE FOR ODD POWERS OF FOUR +0C7C ; [.1CA4.0020.0002] # TELUGU FRACTION DIGIT ONE FOR EVEN POWERS OF FOUR +0CE7 ; [.1CA4.0020.0002] # KANNADA DIGIT ONE +0D67 ; [.1CA4.0020.0002] # MALAYALAM DIGIT ONE +0DE7 ; [.1CA4.0020.0002] # SINHALA LITH DIGIT ONE +0E51 ; [.1CA4.0020.0002] # THAI DIGIT ONE +0ED1 ; [.1CA4.0020.0002] # LAO DIGIT ONE +0F21 ; [.1CA4.0020.0002] # TIBETAN DIGIT ONE +1041 ; [.1CA4.0020.0002] # MYANMAR DIGIT ONE +1091 ; [.1CA4.0020.0002] # MYANMAR SHAN DIGIT ONE +1369 ; [.1CA4.0020.0002] # ETHIOPIC DIGIT ONE +17E1 ; [.1CA4.0020.0002] # KHMER DIGIT ONE +17F1 ; [.1CA4.0020.0002] # KHMER SYMBOL LEK ATTAK MUOY +1811 ; [.1CA4.0020.0002] # MONGOLIAN DIGIT ONE +1947 ; [.1CA4.0020.0002] # LIMBU DIGIT ONE +19D1 ; [.1CA4.0020.0002] # NEW TAI LUE DIGIT ONE +19DA ; [.1CA4.0020.0002] # NEW TAI LUE THAM DIGIT ONE +1A81 ; [.1CA4.0020.0002] # TAI THAM HORA DIGIT ONE +1A91 ; [.1CA4.0020.0002] # TAI THAM THAM DIGIT ONE +1B51 ; [.1CA4.0020.0002] # BALINESE DIGIT ONE +1BB1 ; [.1CA4.0020.0002] # SUNDANESE DIGIT ONE +1C41 ; [.1CA4.0020.0002] # LEPCHA DIGIT ONE +1C51 ; [.1CA4.0020.0002] # OL CHIKI DIGIT ONE +3021 ; [.1CA4.0020.0002] # HANGZHOU NUMERAL ONE +A621 ; [.1CA4.0020.0002] # VAI DIGIT ONE +A8D1 ; [.1CA4.0020.0002] # SAURASHTRA DIGIT ONE +A901 ; [.1CA4.0020.0002] # KAYAH LI DIGIT ONE +A9D1 ; [.1CA4.0020.0002] # JAVANESE DIGIT ONE +A9F1 ; [.1CA4.0020.0002] # MYANMAR TAI LAING DIGIT ONE +AA51 ; [.1CA4.0020.0002] # CHAM DIGIT ONE +ABF1 ; [.1CA4.0020.0002] # MEETEI MAYEK DIGIT ONE +10107 ; [.1CA4.0020.0002] # AEGEAN NUMBER ONE +10142 ; [.1CA4.0020.0002] # GREEK ACROPHONIC ATTIC ONE DRACHMA +10158 ; [.1CA4.0020.0002] # GREEK ACROPHONIC HERAEUM ONE PLETHRON +10159 ; [.1CA4.0020.0002] # GREEK ACROPHONIC THESPIAN ONE +1015A ; [.1CA4.0020.0002] # GREEK ACROPHONIC HERMIONIAN ONE +102E1 ; [.1CA4.0020.0002] # COPTIC EPACT DIGIT ONE +10320 ; [.1CA4.0020.0002] # OLD ITALIC NUMERAL ONE +103D1 ; [.1CA4.0020.0002] # OLD PERSIAN NUMBER ONE +104A1 ; [.1CA4.0020.0002] # OSMANYA DIGIT ONE +10858 ; [.1CA4.0020.0002] # IMPERIAL ARAMAIC NUMBER ONE +10879 ; [.1CA4.0020.0002] # PALMYRENE NUMBER ONE +108A7 ; [.1CA4.0020.0002] # NABATAEAN NUMBER ONE +108FB ; [.1CA4.0020.0002] # HATRAN NUMBER ONE +10916 ; [.1CA4.0020.0002] # PHOENICIAN NUMBER ONE +109C0 ; [.1CA4.0020.0002] # MEROITIC CURSIVE NUMBER ONE +10A40 ; [.1CA4.0020.0002] # KHAROSHTHI DIGIT ONE +10A7D ; [.1CA4.0020.0002] # OLD SOUTH ARABIAN NUMBER ONE +10A9D ; [.1CA4.0020.0002] # OLD NORTH ARABIAN NUMBER ONE +10AEB ; [.1CA4.0020.0002] # MANICHAEAN NUMBER ONE +10B58 ; [.1CA4.0020.0002] # INSCRIPTIONAL PARTHIAN NUMBER ONE +10B78 ; [.1CA4.0020.0002] # INSCRIPTIONAL PAHLAVI NUMBER ONE +10BA9 ; [.1CA4.0020.0002] # PSALTER PAHLAVI NUMBER ONE +10CFA ; [.1CA4.0020.0002] # OLD HUNGARIAN NUMBER ONE +10E60 ; [.1CA4.0020.0002] # RUMI DIGIT ONE +11052 ; [.1CA4.0020.0002] # BRAHMI NUMBER ONE +11067 ; [.1CA4.0020.0002] # BRAHMI DIGIT ONE +110F1 ; [.1CA4.0020.0002] # SORA SOMPENG DIGIT ONE +11137 ; [.1CA4.0020.0002] # CHAKMA DIGIT ONE +111D1 ; [.1CA4.0020.0002] # SHARADA DIGIT ONE +111E1 ; [.1CA4.0020.0002] # SINHALA ARCHAIC DIGIT ONE +112F1 ; [.1CA4.0020.0002] # KHUDAWADI DIGIT ONE +11451 ; [.1CA4.0020.0002] # NEWA DIGIT ONE +114D1 ; [.1CA4.0020.0002] # TIRHUTA DIGIT ONE +11651 ; [.1CA4.0020.0002] # MODI DIGIT ONE +116C1 ; [.1CA4.0020.0002] # TAKRI DIGIT ONE +11731 ; [.1CA4.0020.0002] # AHOM DIGIT ONE +118E1 ; [.1CA4.0020.0002] # WARANG CITI DIGIT ONE +11C51 ; [.1CA4.0020.0002] # BHAIKSUKI DIGIT ONE +11C5A ; [.1CA4.0020.0002] # BHAIKSUKI NUMBER ONE +11D51 ; [.1CA4.0020.0002] # MASARAM GONDI DIGIT ONE +12415 ; [.1CA4.0020.0002] # CUNEIFORM NUMERIC SIGN ONE GESH2 +1241E ; [.1CA4.0020.0002] # CUNEIFORM NUMERIC SIGN ONE GESHU +1242C ; [.1CA4.0020.0002] # CUNEIFORM NUMERIC SIGN ONE SHARU +12434 ; [.1CA4.0020.0002] # CUNEIFORM NUMERIC SIGN ONE BURU +1244F ; [.1CA4.0020.0002] # CUNEIFORM NUMERIC SIGN ONE BAN2 +12458 ; [.1CA4.0020.0002] # CUNEIFORM NUMERIC SIGN ONE ESHE3 +16A61 ; [.1CA4.0020.0002] # MRO DIGIT ONE +16B51 ; [.1CA4.0020.0002] # PAHAWH HMONG DIGIT ONE +1D360 ; [.1CA4.0020.0002] # COUNTING ROD UNIT DIGIT ONE +1E8C7 ; [.1CA4.0020.0002] # MENDE KIKAKUI DIGIT ONE +1E951 ; [.1CA4.0020.0002] # ADLAM DIGIT ONE +FF11 ; [.1CA4.0020.0003] # FULLWIDTH DIGIT ONE +0F2A ; [.1CA4.0020.0004] # TIBETAN DIGIT HALF ONE +2474 ; [*0318.0020.0004][.1CA4.0020.0004][*0319.0020.0004] # PARENTHESIZED DIGIT ONE +2488 ; [.1CA4.0020.0004][*0278.0020.0004] # DIGIT ONE FULL STOP +1F102 ; [.1CA4.0020.0004][*0222.0020.0004] # DIGIT ONE COMMA +1D7CF ; [.1CA4.0020.0005] # MATHEMATICAL BOLD DIGIT ONE +1D7D9 ; [.1CA4.0020.0005] # MATHEMATICAL DOUBLE-STRUCK DIGIT ONE +1D7E3 ; [.1CA4.0020.0005] # MATHEMATICAL SANS-SERIF DIGIT ONE +1D7ED ; [.1CA4.0020.0005] # MATHEMATICAL SANS-SERIF BOLD DIGIT ONE +1D7F7 ; [.1CA4.0020.0005] # MATHEMATICAL MONOSPACE DIGIT ONE +2460 ; [.1CA4.0020.0006] # CIRCLED DIGIT ONE +24F5 ; [.1CA4.0020.0006] # DOUBLE CIRCLED DIGIT ONE +2776 ; [.1CA4.0020.0006] # DINGBAT NEGATIVE CIRCLED DIGIT ONE +2780 ; [.1CA4.0020.0006] # DINGBAT CIRCLED SANS-SERIF DIGIT ONE +278A ; [.1CA4.0020.0006] # DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT ONE +00B9 ; [.1CA4.0020.0014] # SUPERSCRIPT ONE +2081 ; [.1CA4.0020.0015] # SUBSCRIPT ONE +215F ; [.1CA4.0020.001E][*063C.0020.001E] # FRACTION NUMERATOR ONE +247D ; [*0318.0020.0004][.1CA4.0020.0004][.1CA3.0020.0004][*0319.0020.0004] # PARENTHESIZED NUMBER TEN +2491 ; [.1CA4.0020.0004][.1CA3.0020.0004][*0278.0020.0004] # NUMBER TEN FULL STOP +2469 ; [.1CA4.0020.0006][.1CA3.0020.0006] # CIRCLED NUMBER TEN +24FE ; [.1CA4.0020.0006][.1CA3.0020.0006] # DOUBLE CIRCLED NUMBER TEN +277F ; [.1CA4.0020.0006][.1CA3.0020.0006] # DINGBAT NEGATIVE CIRCLED NUMBER TEN +2789 ; [.1CA4.0020.0006][.1CA3.0020.0006] # DINGBAT CIRCLED SANS-SERIF NUMBER TEN +2793 ; [.1CA4.0020.0006][.1CA3.0020.0006] # DINGBAT NEGATIVE CIRCLED SANS-SERIF NUMBER TEN +3248 ; [.1CA4.0020.0006][.1CA3.0020.0006] # CIRCLED NUMBER TEN ON BLACK SQUARE +33E9 ; [.1CA4.0020.0004][.1CA3.0020.0004][.FB40.0020.0004][.E5E5.0000.0000] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TEN +32C9 ; [.1CA4.0020.0004][.1CA3.0020.0004][.FB40.0020.0004][.E708.0000.0000] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR OCTOBER +3362 ; [.1CA4.0020.0004][.1CA3.0020.0004][.FB40.0020.0004][.F0B9.0000.0000] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TEN +247E ; [*0318.0020.0004][.1CA4.0020.0004][.1CA4.0020.0004][*0319.0020.0004] # PARENTHESIZED NUMBER ELEVEN +2492 ; [.1CA4.0020.0004][.1CA4.0020.0004][*0278.0020.0004] # NUMBER ELEVEN FULL STOP +246A ; [.1CA4.0020.0006][.1CA4.0020.0006] # CIRCLED NUMBER ELEVEN +24EB ; [.1CA4.0020.0006][.1CA4.0020.0006] # NEGATIVE CIRCLED NUMBER ELEVEN +2152 ; [.1CA4.0020.001E][*063C.0020.001E][.1CA4.0020.001E][.1CA3.0020.001E] # VULGAR FRACTION ONE TENTH +33EA ; [.1CA4.0020.0004][.1CA4.0020.0004][.FB40.0020.0004][.E5E5.0000.0000] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY ELEVEN +32CA ; [.1CA4.0020.0004][.1CA4.0020.0004][.FB40.0020.0004][.E708.0000.0000] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR NOVEMBER +3363 ; [.1CA4.0020.0004][.1CA4.0020.0004][.FB40.0020.0004][.F0B9.0000.0000] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR ELEVEN +247F ; [*0318.0020.0004][.1CA4.0020.0004][.1CA5.0020.0004][*0319.0020.0004] # PARENTHESIZED NUMBER TWELVE +2493 ; [.1CA4.0020.0004][.1CA5.0020.0004][*0278.0020.0004] # NUMBER TWELVE FULL STOP +246B ; [.1CA4.0020.0006][.1CA5.0020.0006] # CIRCLED NUMBER TWELVE +24EC ; [.1CA4.0020.0006][.1CA5.0020.0006] # NEGATIVE CIRCLED NUMBER TWELVE +00BD ; [.1CA4.0020.001E][*063C.0020.001E][.1CA5.0020.001E] # VULGAR FRACTION ONE HALF +1F1A4 ; [.1CA4.0020.001C][.1CA5.0020.001C][.1CA3.0020.001C][.1E72.0020.001D] # SQUARED ONE HUNDRED TWENTY P +33EB ; [.1CA4.0020.0004][.1CA5.0020.0004][.FB40.0020.0004][.E5E5.0000.0000] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWELVE +32CB ; [.1CA4.0020.0004][.1CA5.0020.0004][.FB40.0020.0004][.E708.0000.0000] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR DECEMBER +3364 ; [.1CA4.0020.0004][.1CA5.0020.0004][.FB40.0020.0004][.F0B9.0000.0000] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWELVE +2480 ; [*0318.0020.0004][.1CA4.0020.0004][.1CA6.0020.0004][*0319.0020.0004] # PARENTHESIZED NUMBER THIRTEEN +2494 ; [.1CA4.0020.0004][.1CA6.0020.0004][*0278.0020.0004] # NUMBER THIRTEEN FULL STOP +246C ; [.1CA4.0020.0006][.1CA6.0020.0006] # CIRCLED NUMBER THIRTEEN +24ED ; [.1CA4.0020.0006][.1CA6.0020.0006] # NEGATIVE CIRCLED NUMBER THIRTEEN +2153 ; [.1CA4.0020.001E][*063C.0020.001E][.1CA6.0020.001E] # VULGAR FRACTION ONE THIRD +33EC ; [.1CA4.0020.0004][.1CA6.0020.0004][.FB40.0020.0004][.E5E5.0000.0000] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY THIRTEEN +3365 ; [.1CA4.0020.0004][.1CA6.0020.0004][.FB40.0020.0004][.F0B9.0000.0000] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR THIRTEEN +2481 ; [*0318.0020.0004][.1CA4.0020.0004][.1CA7.0020.0004][*0319.0020.0004] # PARENTHESIZED NUMBER FOURTEEN +2495 ; [.1CA4.0020.0004][.1CA7.0020.0004][*0278.0020.0004] # NUMBER FOURTEEN FULL STOP +246D ; [.1CA4.0020.0006][.1CA7.0020.0006] # CIRCLED NUMBER FOURTEEN +24EE ; [.1CA4.0020.0006][.1CA7.0020.0006] # NEGATIVE CIRCLED NUMBER FOURTEEN +00BC ; [.1CA4.0020.001E][*063C.0020.001E][.1CA7.0020.001E] # VULGAR FRACTION ONE QUARTER +33ED ; [.1CA4.0020.0004][.1CA7.0020.0004][.FB40.0020.0004][.E5E5.0000.0000] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY FOURTEEN +3366 ; [.1CA4.0020.0004][.1CA7.0020.0004][.FB40.0020.0004][.F0B9.0000.0000] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR FOURTEEN +2482 ; [*0318.0020.0004][.1CA4.0020.0004][.1CA8.0020.0004][*0319.0020.0004] # PARENTHESIZED NUMBER FIFTEEN +2496 ; [.1CA4.0020.0004][.1CA8.0020.0004][*0278.0020.0004] # NUMBER FIFTEEN FULL STOP +246E ; [.1CA4.0020.0006][.1CA8.0020.0006] # CIRCLED NUMBER FIFTEEN +24EF ; [.1CA4.0020.0006][.1CA8.0020.0006] # NEGATIVE CIRCLED NUMBER FIFTEEN +2155 ; [.1CA4.0020.001E][*063C.0020.001E][.1CA8.0020.001E] # VULGAR FRACTION ONE FIFTH +33EE ; [.1CA4.0020.0004][.1CA8.0020.0004][.FB40.0020.0004][.E5E5.0000.0000] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY FIFTEEN +3367 ; [.1CA4.0020.0004][.1CA8.0020.0004][.FB40.0020.0004][.F0B9.0000.0000] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR FIFTEEN +2483 ; [*0318.0020.0004][.1CA4.0020.0004][.1CA9.0020.0004][*0319.0020.0004] # PARENTHESIZED NUMBER SIXTEEN +2497 ; [.1CA4.0020.0004][.1CA9.0020.0004][*0278.0020.0004] # NUMBER SIXTEEN FULL STOP +246F ; [.1CA4.0020.0006][.1CA9.0020.0006] # CIRCLED NUMBER SIXTEEN +24F0 ; [.1CA4.0020.0006][.1CA9.0020.0006] # NEGATIVE CIRCLED NUMBER SIXTEEN +2159 ; [.1CA4.0020.001E][*063C.0020.001E][.1CA9.0020.001E] # VULGAR FRACTION ONE SIXTH +33EF ; [.1CA4.0020.0004][.1CA9.0020.0004][.FB40.0020.0004][.E5E5.0000.0000] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY SIXTEEN +3368 ; [.1CA4.0020.0004][.1CA9.0020.0004][.FB40.0020.0004][.F0B9.0000.0000] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR SIXTEEN +2484 ; [*0318.0020.0004][.1CA4.0020.0004][.1CAA.0020.0004][*0319.0020.0004] # PARENTHESIZED NUMBER SEVENTEEN +2498 ; [.1CA4.0020.0004][.1CAA.0020.0004][*0278.0020.0004] # NUMBER SEVENTEEN FULL STOP +2470 ; [.1CA4.0020.0006][.1CAA.0020.0006] # CIRCLED NUMBER SEVENTEEN +24F1 ; [.1CA4.0020.0006][.1CAA.0020.0006] # NEGATIVE CIRCLED NUMBER SEVENTEEN +2150 ; [.1CA4.0020.001E][*063C.0020.001E][.1CAA.0020.001E] # VULGAR FRACTION ONE SEVENTH +33F0 ; [.1CA4.0020.0004][.1CAA.0020.0004][.FB40.0020.0004][.E5E5.0000.0000] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY SEVENTEEN +3369 ; [.1CA4.0020.0004][.1CAA.0020.0004][.FB40.0020.0004][.F0B9.0000.0000] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR SEVENTEEN +2485 ; [*0318.0020.0004][.1CA4.0020.0004][.1CAB.0020.0004][*0319.0020.0004] # PARENTHESIZED NUMBER EIGHTEEN +2499 ; [.1CA4.0020.0004][.1CAB.0020.0004][*0278.0020.0004] # NUMBER EIGHTEEN FULL STOP +2471 ; [.1CA4.0020.0006][.1CAB.0020.0006] # CIRCLED NUMBER EIGHTEEN +24F2 ; [.1CA4.0020.0006][.1CAB.0020.0006] # NEGATIVE CIRCLED NUMBER EIGHTEEN +215B ; [.1CA4.0020.001E][*063C.0020.001E][.1CAB.0020.001E] # VULGAR FRACTION ONE EIGHTH +33F1 ; [.1CA4.0020.0004][.1CAB.0020.0004][.FB40.0020.0004][.E5E5.0000.0000] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY EIGHTEEN +336A ; [.1CA4.0020.0004][.1CAB.0020.0004][.FB40.0020.0004][.F0B9.0000.0000] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR EIGHTEEN +2486 ; [*0318.0020.0004][.1CA4.0020.0004][.1CAC.0020.0004][*0319.0020.0004] # PARENTHESIZED NUMBER NINETEEN +249A ; [.1CA4.0020.0004][.1CAC.0020.0004][*0278.0020.0004] # NUMBER NINETEEN FULL STOP +2472 ; [.1CA4.0020.0006][.1CAC.0020.0006] # CIRCLED NUMBER NINETEEN +24F3 ; [.1CA4.0020.0006][.1CAC.0020.0006] # NEGATIVE CIRCLED NUMBER NINETEEN +2151 ; [.1CA4.0020.001E][*063C.0020.001E][.1CAC.0020.001E] # VULGAR FRACTION ONE NINTH +33F2 ; [.1CA4.0020.0004][.1CAC.0020.0004][.FB40.0020.0004][.E5E5.0000.0000] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY NINETEEN +336B ; [.1CA4.0020.0004][.1CAC.0020.0004][.FB40.0020.0004][.F0B9.0000.0000] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR NINETEEN +33E0 ; [.1CA4.0020.0004][.FB40.0020.0004][.E5E5.0000.0000] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY ONE +32C0 ; [.1CA4.0020.0004][.FB40.0020.0004][.E708.0000.0000] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR JANUARY +3359 ; [.1CA4.0020.0004][.FB40.0020.0004][.F0B9.0000.0000] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR ONE +0032 ; [.1CA5.0020.0002] # DIGIT TWO +0662 ; [.1CA5.0020.0002] # ARABIC-INDIC DIGIT TWO +06F2 ; [.1CA5.0020.0002] # EXTENDED ARABIC-INDIC DIGIT TWO +07C2 ; [.1CA5.0020.0002] # NKO DIGIT TWO +0968 ; [.1CA5.0020.0002] # DEVANAGARI DIGIT TWO +09E8 ; [.1CA5.0020.0002] # BENGALI DIGIT TWO +0A68 ; [.1CA5.0020.0002] # GURMUKHI DIGIT TWO +0AE8 ; [.1CA5.0020.0002] # GUJARATI DIGIT TWO +0B68 ; [.1CA5.0020.0002] # ORIYA DIGIT TWO +0BE8 ; [.1CA5.0020.0002] # TAMIL DIGIT TWO +0C68 ; [.1CA5.0020.0002] # TELUGU DIGIT TWO +0C7A ; [.1CA5.0020.0002] # TELUGU FRACTION DIGIT TWO FOR ODD POWERS OF FOUR +0C7D ; [.1CA5.0020.0002] # TELUGU FRACTION DIGIT TWO FOR EVEN POWERS OF FOUR +0CE8 ; [.1CA5.0020.0002] # KANNADA DIGIT TWO +0D68 ; [.1CA5.0020.0002] # MALAYALAM DIGIT TWO +0DE8 ; [.1CA5.0020.0002] # SINHALA LITH DIGIT TWO +0E52 ; [.1CA5.0020.0002] # THAI DIGIT TWO +0ED2 ; [.1CA5.0020.0002] # LAO DIGIT TWO +0F22 ; [.1CA5.0020.0002] # TIBETAN DIGIT TWO +1042 ; [.1CA5.0020.0002] # MYANMAR DIGIT TWO +1092 ; [.1CA5.0020.0002] # MYANMAR SHAN DIGIT TWO +136A ; [.1CA5.0020.0002] # ETHIOPIC DIGIT TWO +17E2 ; [.1CA5.0020.0002] # KHMER DIGIT TWO +17F2 ; [.1CA5.0020.0002] # KHMER SYMBOL LEK ATTAK PII +1812 ; [.1CA5.0020.0002] # MONGOLIAN DIGIT TWO +1948 ; [.1CA5.0020.0002] # LIMBU DIGIT TWO +19D2 ; [.1CA5.0020.0002] # NEW TAI LUE DIGIT TWO +1A82 ; [.1CA5.0020.0002] # TAI THAM HORA DIGIT TWO +1A92 ; [.1CA5.0020.0002] # TAI THAM THAM DIGIT TWO +1B52 ; [.1CA5.0020.0002] # BALINESE DIGIT TWO +1BB2 ; [.1CA5.0020.0002] # SUNDANESE DIGIT TWO +1C42 ; [.1CA5.0020.0002] # LEPCHA DIGIT TWO +1C52 ; [.1CA5.0020.0002] # OL CHIKI DIGIT TWO +3022 ; [.1CA5.0020.0002] # HANGZHOU NUMERAL TWO +A622 ; [.1CA5.0020.0002] # VAI DIGIT TWO +A8D2 ; [.1CA5.0020.0002] # SAURASHTRA DIGIT TWO +A902 ; [.1CA5.0020.0002] # KAYAH LI DIGIT TWO +A9D2 ; [.1CA5.0020.0002] # JAVANESE DIGIT TWO +A9F2 ; [.1CA5.0020.0002] # MYANMAR TAI LAING DIGIT TWO +AA52 ; [.1CA5.0020.0002] # CHAM DIGIT TWO +ABF2 ; [.1CA5.0020.0002] # MEETEI MAYEK DIGIT TWO +10108 ; [.1CA5.0020.0002] # AEGEAN NUMBER TWO +1015B ; [.1CA5.0020.0002] # GREEK ACROPHONIC EPIDAUREAN TWO +1015C ; [.1CA5.0020.0002] # GREEK ACROPHONIC THESPIAN TWO +1015D ; [.1CA5.0020.0002] # GREEK ACROPHONIC CYRENAIC TWO DRACHMAS +1015E ; [.1CA5.0020.0002] # GREEK ACROPHONIC EPIDAUREAN TWO DRACHMAS +102E2 ; [.1CA5.0020.0002] # COPTIC EPACT DIGIT TWO +103D2 ; [.1CA5.0020.0002] # OLD PERSIAN NUMBER TWO +104A2 ; [.1CA5.0020.0002] # OSMANYA DIGIT TWO +10859 ; [.1CA5.0020.0002] # IMPERIAL ARAMAIC NUMBER TWO +1087A ; [.1CA5.0020.0002] # PALMYRENE NUMBER TWO +108A8 ; [.1CA5.0020.0002] # NABATAEAN NUMBER TWO +1091A ; [.1CA5.0020.0002] # PHOENICIAN NUMBER TWO +109C1 ; [.1CA5.0020.0002] # MEROITIC CURSIVE NUMBER TWO +10A41 ; [.1CA5.0020.0002] # KHAROSHTHI DIGIT TWO +10B59 ; [.1CA5.0020.0002] # INSCRIPTIONAL PARTHIAN NUMBER TWO +10B79 ; [.1CA5.0020.0002] # INSCRIPTIONAL PAHLAVI NUMBER TWO +10BAA ; [.1CA5.0020.0002] # PSALTER PAHLAVI NUMBER TWO +10E61 ; [.1CA5.0020.0002] # RUMI DIGIT TWO +11053 ; [.1CA5.0020.0002] # BRAHMI NUMBER TWO +11068 ; [.1CA5.0020.0002] # BRAHMI DIGIT TWO +110F2 ; [.1CA5.0020.0002] # SORA SOMPENG DIGIT TWO +11138 ; [.1CA5.0020.0002] # CHAKMA DIGIT TWO +111D2 ; [.1CA5.0020.0002] # SHARADA DIGIT TWO +111E2 ; [.1CA5.0020.0002] # SINHALA ARCHAIC DIGIT TWO +112F2 ; [.1CA5.0020.0002] # KHUDAWADI DIGIT TWO +11452 ; [.1CA5.0020.0002] # NEWA DIGIT TWO +114D2 ; [.1CA5.0020.0002] # TIRHUTA DIGIT TWO +11652 ; [.1CA5.0020.0002] # MODI DIGIT TWO +116C2 ; [.1CA5.0020.0002] # TAKRI DIGIT TWO +11732 ; [.1CA5.0020.0002] # AHOM DIGIT TWO +118E2 ; [.1CA5.0020.0002] # WARANG CITI DIGIT TWO +11C52 ; [.1CA5.0020.0002] # BHAIKSUKI DIGIT TWO +11C5B ; [.1CA5.0020.0002] # BHAIKSUKI NUMBER TWO +11D52 ; [.1CA5.0020.0002] # MASARAM GONDI DIGIT TWO +12400 ; [.1CA5.0020.0002] # CUNEIFORM NUMERIC SIGN TWO ASH +12416 ; [.1CA5.0020.0002] # CUNEIFORM NUMERIC SIGN TWO GESH2 +1241F ; [.1CA5.0020.0002] # CUNEIFORM NUMERIC SIGN TWO GESHU +12423 ; [.1CA5.0020.0002] # CUNEIFORM NUMERIC SIGN TWO SHAR2 +1242D ; [.1CA5.0020.0002] # CUNEIFORM NUMERIC SIGN TWO SHARU +12435 ; [.1CA5.0020.0002] # CUNEIFORM NUMERIC SIGN TWO BURU +1244A ; [.1CA5.0020.0002] # CUNEIFORM NUMERIC SIGN TWO ASH TENU +12450 ; [.1CA5.0020.0002] # CUNEIFORM NUMERIC SIGN TWO BAN2 +12456 ; [.1CA5.0020.0002] # CUNEIFORM NUMERIC SIGN NIGIDAMIN +12459 ; [.1CA5.0020.0002] # CUNEIFORM NUMERIC SIGN TWO ESHE3 +16A62 ; [.1CA5.0020.0002] # MRO DIGIT TWO +16B52 ; [.1CA5.0020.0002] # PAHAWH HMONG DIGIT TWO +1D361 ; [.1CA5.0020.0002] # COUNTING ROD UNIT DIGIT TWO +1E8C8 ; [.1CA5.0020.0002] # MENDE KIKAKUI DIGIT TWO +1E952 ; [.1CA5.0020.0002] # ADLAM DIGIT TWO +FF12 ; [.1CA5.0020.0003] # FULLWIDTH DIGIT TWO +0F2B ; [.1CA5.0020.0004] # TIBETAN DIGIT HALF TWO +2475 ; [*0318.0020.0004][.1CA5.0020.0004][*0319.0020.0004] # PARENTHESIZED DIGIT TWO +2489 ; [.1CA5.0020.0004][*0278.0020.0004] # DIGIT TWO FULL STOP +1F103 ; [.1CA5.0020.0004][*0222.0020.0004] # DIGIT TWO COMMA +1D7D0 ; [.1CA5.0020.0005] # MATHEMATICAL BOLD DIGIT TWO +1D7DA ; [.1CA5.0020.0005] # MATHEMATICAL DOUBLE-STRUCK DIGIT TWO +1D7E4 ; [.1CA5.0020.0005] # MATHEMATICAL SANS-SERIF DIGIT TWO +1D7EE ; [.1CA5.0020.0005] # MATHEMATICAL SANS-SERIF BOLD DIGIT TWO +1D7F8 ; [.1CA5.0020.0005] # MATHEMATICAL MONOSPACE DIGIT TWO +2461 ; [.1CA5.0020.0006] # CIRCLED DIGIT TWO +24F6 ; [.1CA5.0020.0006] # DOUBLE CIRCLED DIGIT TWO +2777 ; [.1CA5.0020.0006] # DINGBAT NEGATIVE CIRCLED DIGIT TWO +2781 ; [.1CA5.0020.0006] # DINGBAT CIRCLED SANS-SERIF DIGIT TWO +278B ; [.1CA5.0020.0006] # DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT TWO +00B2 ; [.1CA5.0020.0014] # SUPERSCRIPT TWO +2082 ; [.1CA5.0020.0015] # SUBSCRIPT TWO +2487 ; [*0318.0020.0004][.1CA5.0020.0004][.1CA3.0020.0004][*0319.0020.0004] # PARENTHESIZED NUMBER TWENTY +249B ; [.1CA5.0020.0004][.1CA3.0020.0004][*0278.0020.0004] # NUMBER TWENTY FULL STOP +2473 ; [.1CA5.0020.0006][.1CA3.0020.0006] # CIRCLED NUMBER TWENTY +24F4 ; [.1CA5.0020.0006][.1CA3.0020.0006] # NEGATIVE CIRCLED NUMBER TWENTY +3249 ; [.1CA5.0020.0006][.1CA3.0020.0006] # CIRCLED NUMBER TWENTY ON BLACK SQUARE +33F3 ; [.1CA5.0020.0004][.1CA3.0020.0004][.FB40.0020.0004][.E5E5.0000.0000] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY +336C ; [.1CA5.0020.0004][.1CA3.0020.0004][.FB40.0020.0004][.F0B9.0000.0000] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWENTY +3251 ; [.1CA5.0020.0006][.1CA4.0020.0006] # CIRCLED NUMBER TWENTY ONE +33F4 ; [.1CA5.0020.0004][.1CA4.0020.0004][.FB40.0020.0004][.E5E5.0000.0000] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-ONE +336D ; [.1CA5.0020.0004][.1CA4.0020.0004][.FB40.0020.0004][.F0B9.0000.0000] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWENTY-ONE +3252 ; [.1CA5.0020.0006][.1CA5.0020.0006] # CIRCLED NUMBER TWENTY TWO +1F1A2 ; [.1CA5.0020.001C][.1CA5.0020.001C][*0278.0020.001C][.1CA5.0020.001C] # SQUARED TWENTY-TWO POINT TWO +33F5 ; [.1CA5.0020.0004][.1CA5.0020.0004][.FB40.0020.0004][.E5E5.0000.0000] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-TWO +336E ; [.1CA5.0020.0004][.1CA5.0020.0004][.FB40.0020.0004][.F0B9.0000.0000] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWENTY-TWO +3253 ; [.1CA5.0020.0006][.1CA6.0020.0006] # CIRCLED NUMBER TWENTY THREE +2154 ; [.1CA5.0020.001E][*063C.0020.001E][.1CA6.0020.001E] # VULGAR FRACTION TWO THIRDS +33F6 ; [.1CA5.0020.0004][.1CA6.0020.0004][.FB40.0020.0004][.E5E5.0000.0000] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-THREE +336F ; [.1CA5.0020.0004][.1CA6.0020.0004][.FB40.0020.0004][.F0B9.0000.0000] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWENTY-THREE +3254 ; [.1CA5.0020.0006][.1CA7.0020.0006] # CIRCLED NUMBER TWENTY FOUR +33F7 ; [.1CA5.0020.0004][.1CA7.0020.0004][.FB40.0020.0004][.E5E5.0000.0000] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-FOUR +3370 ; [.1CA5.0020.0004][.1CA7.0020.0004][.FB40.0020.0004][.F0B9.0000.0000] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWENTY-FOUR +3255 ; [.1CA5.0020.0006][.1CA8.0020.0006] # CIRCLED NUMBER TWENTY FIVE +2156 ; [.1CA5.0020.001E][*063C.0020.001E][.1CA8.0020.001E] # VULGAR FRACTION TWO FIFTHS +33F8 ; [.1CA5.0020.0004][.1CA8.0020.0004][.FB40.0020.0004][.E5E5.0000.0000] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-FIVE +3256 ; [.1CA5.0020.0006][.1CA9.0020.0006] # CIRCLED NUMBER TWENTY SIX +33F9 ; [.1CA5.0020.0004][.1CA9.0020.0004][.FB40.0020.0004][.E5E5.0000.0000] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-SIX +3257 ; [.1CA5.0020.0006][.1CAA.0020.0006] # CIRCLED NUMBER TWENTY SEVEN +33FA ; [.1CA5.0020.0004][.1CAA.0020.0004][.FB40.0020.0004][.E5E5.0000.0000] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-SEVEN +3258 ; [.1CA5.0020.0006][.1CAB.0020.0006] # CIRCLED NUMBER TWENTY EIGHT +33FB ; [.1CA5.0020.0004][.1CAB.0020.0004][.FB40.0020.0004][.E5E5.0000.0000] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-EIGHT +3259 ; [.1CA5.0020.0006][.1CAC.0020.0006] # CIRCLED NUMBER TWENTY NINE +33FC ; [.1CA5.0020.0004][.1CAC.0020.0004][.FB40.0020.0004][.E5E5.0000.0000] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-NINE +1F19D ; [.1CA5.0020.001C][.1DCB.0020.001D] # SQUARED TWO K +1F19C ; [.1CA5.0020.001C][.1E1F.0020.001C][.1CF5.0020.001C][*0209.0020.001C][.1ED7.0020.001D][.1CE0.0020.001C][.1E99.0020.001C] # SQUARED SECOND SCREEN +33E1 ; [.1CA5.0020.0004][.FB40.0020.0004][.E5E5.0000.0000] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWO +32C1 ; [.1CA5.0020.0004][.FB40.0020.0004][.E708.0000.0000] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR FEBRUARY +335A ; [.1CA5.0020.0004][.FB40.0020.0004][.F0B9.0000.0000] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWO +0033 ; [.1CA6.0020.0002] # DIGIT THREE +0663 ; [.1CA6.0020.0002] # ARABIC-INDIC DIGIT THREE +06F3 ; [.1CA6.0020.0002] # EXTENDED ARABIC-INDIC DIGIT THREE +07C3 ; [.1CA6.0020.0002] # NKO DIGIT THREE +0969 ; [.1CA6.0020.0002] # DEVANAGARI DIGIT THREE +09E9 ; [.1CA6.0020.0002] # BENGALI DIGIT THREE +0A69 ; [.1CA6.0020.0002] # GURMUKHI DIGIT THREE +0AE9 ; [.1CA6.0020.0002] # GUJARATI DIGIT THREE +0B69 ; [.1CA6.0020.0002] # ORIYA DIGIT THREE +0BE9 ; [.1CA6.0020.0002] # TAMIL DIGIT THREE +0C69 ; [.1CA6.0020.0002] # TELUGU DIGIT THREE +0C7B ; [.1CA6.0020.0002] # TELUGU FRACTION DIGIT THREE FOR ODD POWERS OF FOUR +0C7E ; [.1CA6.0020.0002] # TELUGU FRACTION DIGIT THREE FOR EVEN POWERS OF FOUR +0CE9 ; [.1CA6.0020.0002] # KANNADA DIGIT THREE +0D69 ; [.1CA6.0020.0002] # MALAYALAM DIGIT THREE +0DE9 ; [.1CA6.0020.0002] # SINHALA LITH DIGIT THREE +0E53 ; [.1CA6.0020.0002] # THAI DIGIT THREE +0ED3 ; [.1CA6.0020.0002] # LAO DIGIT THREE +0F23 ; [.1CA6.0020.0002] # TIBETAN DIGIT THREE +1043 ; [.1CA6.0020.0002] # MYANMAR DIGIT THREE +1093 ; [.1CA6.0020.0002] # MYANMAR SHAN DIGIT THREE +136B ; [.1CA6.0020.0002] # ETHIOPIC DIGIT THREE +17E3 ; [.1CA6.0020.0002] # KHMER DIGIT THREE +17F3 ; [.1CA6.0020.0002] # KHMER SYMBOL LEK ATTAK BEI +1813 ; [.1CA6.0020.0002] # MONGOLIAN DIGIT THREE +1949 ; [.1CA6.0020.0002] # LIMBU DIGIT THREE +19D3 ; [.1CA6.0020.0002] # NEW TAI LUE DIGIT THREE +1A83 ; [.1CA6.0020.0002] # TAI THAM HORA DIGIT THREE +1A93 ; [.1CA6.0020.0002] # TAI THAM THAM DIGIT THREE +1B53 ; [.1CA6.0020.0002] # BALINESE DIGIT THREE +1BB3 ; [.1CA6.0020.0002] # SUNDANESE DIGIT THREE +1C43 ; [.1CA6.0020.0002] # LEPCHA DIGIT THREE +1C53 ; [.1CA6.0020.0002] # OL CHIKI DIGIT THREE +3023 ; [.1CA6.0020.0002] # HANGZHOU NUMERAL THREE +A623 ; [.1CA6.0020.0002] # VAI DIGIT THREE +A8D3 ; [.1CA6.0020.0002] # SAURASHTRA DIGIT THREE +A903 ; [.1CA6.0020.0002] # KAYAH LI DIGIT THREE +A9D3 ; [.1CA6.0020.0002] # JAVANESE DIGIT THREE +A9F3 ; [.1CA6.0020.0002] # MYANMAR TAI LAING DIGIT THREE +AA53 ; [.1CA6.0020.0002] # CHAM DIGIT THREE +ABF3 ; [.1CA6.0020.0002] # MEETEI MAYEK DIGIT THREE +10109 ; [.1CA6.0020.0002] # AEGEAN NUMBER THREE +102E3 ; [.1CA6.0020.0002] # COPTIC EPACT DIGIT THREE +104A3 ; [.1CA6.0020.0002] # OSMANYA DIGIT THREE +1085A ; [.1CA6.0020.0002] # IMPERIAL ARAMAIC NUMBER THREE +1087B ; [.1CA6.0020.0002] # PALMYRENE NUMBER THREE +108A9 ; [.1CA6.0020.0002] # NABATAEAN NUMBER THREE +1091B ; [.1CA6.0020.0002] # PHOENICIAN NUMBER THREE +109C2 ; [.1CA6.0020.0002] # MEROITIC CURSIVE NUMBER THREE +10A42 ; [.1CA6.0020.0002] # KHAROSHTHI DIGIT THREE +10B5A ; [.1CA6.0020.0002] # INSCRIPTIONAL PARTHIAN NUMBER THREE +10B7A ; [.1CA6.0020.0002] # INSCRIPTIONAL PAHLAVI NUMBER THREE +10BAB ; [.1CA6.0020.0002] # PSALTER PAHLAVI NUMBER THREE +10E62 ; [.1CA6.0020.0002] # RUMI DIGIT THREE +11054 ; [.1CA6.0020.0002] # BRAHMI NUMBER THREE +11069 ; [.1CA6.0020.0002] # BRAHMI DIGIT THREE +110F3 ; [.1CA6.0020.0002] # SORA SOMPENG DIGIT THREE +11139 ; [.1CA6.0020.0002] # CHAKMA DIGIT THREE +111D3 ; [.1CA6.0020.0002] # SHARADA DIGIT THREE +111E3 ; [.1CA6.0020.0002] # SINHALA ARCHAIC DIGIT THREE +112F3 ; [.1CA6.0020.0002] # KHUDAWADI DIGIT THREE +11453 ; [.1CA6.0020.0002] # NEWA DIGIT THREE +114D3 ; [.1CA6.0020.0002] # TIRHUTA DIGIT THREE +11653 ; [.1CA6.0020.0002] # MODI DIGIT THREE +116C3 ; [.1CA6.0020.0002] # TAKRI DIGIT THREE +11733 ; [.1CA6.0020.0002] # AHOM DIGIT THREE +118E3 ; [.1CA6.0020.0002] # WARANG CITI DIGIT THREE +11C53 ; [.1CA6.0020.0002] # BHAIKSUKI DIGIT THREE +11C5C ; [.1CA6.0020.0002] # BHAIKSUKI NUMBER THREE +11D53 ; [.1CA6.0020.0002] # MASARAM GONDI DIGIT THREE +12401 ; [.1CA6.0020.0002] # CUNEIFORM NUMERIC SIGN THREE ASH +12408 ; [.1CA6.0020.0002] # CUNEIFORM NUMERIC SIGN THREE DISH +12417 ; [.1CA6.0020.0002] # CUNEIFORM NUMERIC SIGN THREE GESH2 +12420 ; [.1CA6.0020.0002] # CUNEIFORM NUMERIC SIGN THREE GESHU +12424 ; [.1CA6.0020.0002] # CUNEIFORM NUMERIC SIGN THREE SHAR2 +12425 ; [.1CA6.0020.0002] # CUNEIFORM NUMERIC SIGN THREE SHAR2 VARIANT FORM +1242E ; [.1CA6.0020.0002] # CUNEIFORM NUMERIC SIGN THREE SHARU +1242F ; [.1CA6.0020.0002] # CUNEIFORM NUMERIC SIGN THREE SHARU VARIANT FORM +12436 ; [.1CA6.0020.0002] # CUNEIFORM NUMERIC SIGN THREE BURU +12437 ; [.1CA6.0020.0002] # CUNEIFORM NUMERIC SIGN THREE BURU VARIANT FORM +1243A ; [.1CA6.0020.0002] # CUNEIFORM NUMERIC SIGN THREE VARIANT FORM ESH16 +1243B ; [.1CA6.0020.0002] # CUNEIFORM NUMERIC SIGN THREE VARIANT FORM ESH21 +1244B ; [.1CA6.0020.0002] # CUNEIFORM NUMERIC SIGN THREE ASH TENU +12451 ; [.1CA6.0020.0002] # CUNEIFORM NUMERIC SIGN THREE BAN2 +12457 ; [.1CA6.0020.0002] # CUNEIFORM NUMERIC SIGN NIGIDAESH +16A63 ; [.1CA6.0020.0002] # MRO DIGIT THREE +16B53 ; [.1CA6.0020.0002] # PAHAWH HMONG DIGIT THREE +1D362 ; [.1CA6.0020.0002] # COUNTING ROD UNIT DIGIT THREE +1E8C9 ; [.1CA6.0020.0002] # MENDE KIKAKUI DIGIT THREE +1E953 ; [.1CA6.0020.0002] # ADLAM DIGIT THREE +FF13 ; [.1CA6.0020.0003] # FULLWIDTH DIGIT THREE +0F2C ; [.1CA6.0020.0004] # TIBETAN DIGIT HALF THREE +2476 ; [*0318.0020.0004][.1CA6.0020.0004][*0319.0020.0004] # PARENTHESIZED DIGIT THREE +248A ; [.1CA6.0020.0004][*0278.0020.0004] # DIGIT THREE FULL STOP +1F104 ; [.1CA6.0020.0004][*0222.0020.0004] # DIGIT THREE COMMA +1D7D1 ; [.1CA6.0020.0005] # MATHEMATICAL BOLD DIGIT THREE +1D7DB ; [.1CA6.0020.0005] # MATHEMATICAL DOUBLE-STRUCK DIGIT THREE +1D7E5 ; [.1CA6.0020.0005] # MATHEMATICAL SANS-SERIF DIGIT THREE +1D7EF ; [.1CA6.0020.0005] # MATHEMATICAL SANS-SERIF BOLD DIGIT THREE +1D7F9 ; [.1CA6.0020.0005] # MATHEMATICAL MONOSPACE DIGIT THREE +2462 ; [.1CA6.0020.0006] # CIRCLED DIGIT THREE +24F7 ; [.1CA6.0020.0006] # DOUBLE CIRCLED DIGIT THREE +2778 ; [.1CA6.0020.0006] # DINGBAT NEGATIVE CIRCLED DIGIT THREE +2782 ; [.1CA6.0020.0006] # DINGBAT CIRCLED SANS-SERIF DIGIT THREE +278C ; [.1CA6.0020.0006] # DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT THREE +00B3 ; [.1CA6.0020.0014] # SUPERSCRIPT THREE +2083 ; [.1CA6.0020.0015] # SUBSCRIPT THREE +324A ; [.1CA6.0020.0006][.1CA3.0020.0006] # CIRCLED NUMBER THIRTY ON BLACK SQUARE +325A ; [.1CA6.0020.0006][.1CA3.0020.0006] # CIRCLED NUMBER THIRTY +33FD ; [.1CA6.0020.0004][.1CA3.0020.0004][.FB40.0020.0004][.E5E5.0000.0000] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY THIRTY +325B ; [.1CA6.0020.0006][.1CA4.0020.0006] # CIRCLED NUMBER THIRTY ONE +33FE ; [.1CA6.0020.0004][.1CA4.0020.0004][.FB40.0020.0004][.E5E5.0000.0000] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY THIRTY-ONE +325C ; [.1CA6.0020.0006][.1CA5.0020.0006] # CIRCLED NUMBER THIRTY TWO +325D ; [.1CA6.0020.0006][.1CA6.0020.0006] # CIRCLED NUMBER THIRTY THREE +325E ; [.1CA6.0020.0006][.1CA7.0020.0006] # CIRCLED NUMBER THIRTY FOUR +00BE ; [.1CA6.0020.001E][*063C.0020.001E][.1CA7.0020.001E] # VULGAR FRACTION THREE QUARTERS +325F ; [.1CA6.0020.0006][.1CA8.0020.0006] # CIRCLED NUMBER THIRTY FIVE +2157 ; [.1CA6.0020.001E][*063C.0020.001E][.1CA8.0020.001E] # VULGAR FRACTION THREE FIFTHS +32B1 ; [.1CA6.0020.0006][.1CA9.0020.0006] # CIRCLED NUMBER THIRTY SIX +32B2 ; [.1CA6.0020.0006][.1CAA.0020.0006] # CIRCLED NUMBER THIRTY SEVEN +32B3 ; [.1CA6.0020.0006][.1CAB.0020.0006] # CIRCLED NUMBER THIRTY EIGHT +215C ; [.1CA6.0020.001E][*063C.0020.001E][.1CAB.0020.001E] # VULGAR FRACTION THREE EIGHTHS +32B4 ; [.1CA6.0020.0006][.1CAC.0020.0006] # CIRCLED NUMBER THIRTY NINE +1F19B ; [.1CA6.0020.001C][.1CF5.0020.001D] # SQUARED THREE D +33E2 ; [.1CA6.0020.0004][.FB40.0020.0004][.E5E5.0000.0000] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY THREE +32C2 ; [.1CA6.0020.0004][.FB40.0020.0004][.E708.0000.0000] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR MARCH +335B ; [.1CA6.0020.0004][.FB40.0020.0004][.F0B9.0000.0000] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR THREE +0034 ; [.1CA7.0020.0002] # DIGIT FOUR +0664 ; [.1CA7.0020.0002] # ARABIC-INDIC DIGIT FOUR +06F4 ; [.1CA7.0020.0002] # EXTENDED ARABIC-INDIC DIGIT FOUR +07C4 ; [.1CA7.0020.0002] # NKO DIGIT FOUR +096A ; [.1CA7.0020.0002] # DEVANAGARI DIGIT FOUR +09EA ; [.1CA7.0020.0002] # BENGALI DIGIT FOUR +0A6A ; [.1CA7.0020.0002] # GURMUKHI DIGIT FOUR +0AEA ; [.1CA7.0020.0002] # GUJARATI DIGIT FOUR +0B6A ; [.1CA7.0020.0002] # ORIYA DIGIT FOUR +0BEA ; [.1CA7.0020.0002] # TAMIL DIGIT FOUR +0C6A ; [.1CA7.0020.0002] # TELUGU DIGIT FOUR +0CEA ; [.1CA7.0020.0002] # KANNADA DIGIT FOUR +0D6A ; [.1CA7.0020.0002] # MALAYALAM DIGIT FOUR +0DEA ; [.1CA7.0020.0002] # SINHALA LITH DIGIT FOUR +0E54 ; [.1CA7.0020.0002] # THAI DIGIT FOUR +0ED4 ; [.1CA7.0020.0002] # LAO DIGIT FOUR +0F24 ; [.1CA7.0020.0002] # TIBETAN DIGIT FOUR +1044 ; [.1CA7.0020.0002] # MYANMAR DIGIT FOUR +1094 ; [.1CA7.0020.0002] # MYANMAR SHAN DIGIT FOUR +136C ; [.1CA7.0020.0002] # ETHIOPIC DIGIT FOUR +17E4 ; [.1CA7.0020.0002] # KHMER DIGIT FOUR +17F4 ; [.1CA7.0020.0002] # KHMER SYMBOL LEK ATTAK BUON +1814 ; [.1CA7.0020.0002] # MONGOLIAN DIGIT FOUR +194A ; [.1CA7.0020.0002] # LIMBU DIGIT FOUR +19D4 ; [.1CA7.0020.0002] # NEW TAI LUE DIGIT FOUR +1A84 ; [.1CA7.0020.0002] # TAI THAM HORA DIGIT FOUR +1A94 ; [.1CA7.0020.0002] # TAI THAM THAM DIGIT FOUR +1B54 ; [.1CA7.0020.0002] # BALINESE DIGIT FOUR +1BB4 ; [.1CA7.0020.0002] # SUNDANESE DIGIT FOUR +1C44 ; [.1CA7.0020.0002] # LEPCHA DIGIT FOUR +1C54 ; [.1CA7.0020.0002] # OL CHIKI DIGIT FOUR +3024 ; [.1CA7.0020.0002] # HANGZHOU NUMERAL FOUR +A624 ; [.1CA7.0020.0002] # VAI DIGIT FOUR +A8D4 ; [.1CA7.0020.0002] # SAURASHTRA DIGIT FOUR +A904 ; [.1CA7.0020.0002] # KAYAH LI DIGIT FOUR +A9D4 ; [.1CA7.0020.0002] # JAVANESE DIGIT FOUR +A9F4 ; [.1CA7.0020.0002] # MYANMAR TAI LAING DIGIT FOUR +AA54 ; [.1CA7.0020.0002] # CHAM DIGIT FOUR +ABF4 ; [.1CA7.0020.0002] # MEETEI MAYEK DIGIT FOUR +1010A ; [.1CA7.0020.0002] # AEGEAN NUMBER FOUR +102E4 ; [.1CA7.0020.0002] # COPTIC EPACT DIGIT FOUR +104A4 ; [.1CA7.0020.0002] # OSMANYA DIGIT FOUR +1087C ; [.1CA7.0020.0002] # PALMYRENE NUMBER FOUR +108AA ; [.1CA7.0020.0002] # NABATAEAN NUMBER FOUR +108AB ; [.1CA7.0020.0002] # NABATAEAN CRUCIFORM NUMBER FOUR +109C3 ; [.1CA7.0020.0002] # MEROITIC CURSIVE NUMBER FOUR +10A43 ; [.1CA7.0020.0002] # KHAROSHTHI DIGIT FOUR +10B5B ; [.1CA7.0020.0002] # INSCRIPTIONAL PARTHIAN NUMBER FOUR +10B7B ; [.1CA7.0020.0002] # INSCRIPTIONAL PAHLAVI NUMBER FOUR +10BAC ; [.1CA7.0020.0002] # PSALTER PAHLAVI NUMBER FOUR +10E63 ; [.1CA7.0020.0002] # RUMI DIGIT FOUR +11055 ; [.1CA7.0020.0002] # BRAHMI NUMBER FOUR +1106A ; [.1CA7.0020.0002] # BRAHMI DIGIT FOUR +110F4 ; [.1CA7.0020.0002] # SORA SOMPENG DIGIT FOUR +1113A ; [.1CA7.0020.0002] # CHAKMA DIGIT FOUR +111D4 ; [.1CA7.0020.0002] # SHARADA DIGIT FOUR +111E4 ; [.1CA7.0020.0002] # SINHALA ARCHAIC DIGIT FOUR +112F4 ; [.1CA7.0020.0002] # KHUDAWADI DIGIT FOUR +11454 ; [.1CA7.0020.0002] # NEWA DIGIT FOUR +114D4 ; [.1CA7.0020.0002] # TIRHUTA DIGIT FOUR +11654 ; [.1CA7.0020.0002] # MODI DIGIT FOUR +116C4 ; [.1CA7.0020.0002] # TAKRI DIGIT FOUR +11734 ; [.1CA7.0020.0002] # AHOM DIGIT FOUR +118E4 ; [.1CA7.0020.0002] # WARANG CITI DIGIT FOUR +11C54 ; [.1CA7.0020.0002] # BHAIKSUKI DIGIT FOUR +11C5D ; [.1CA7.0020.0002] # BHAIKSUKI NUMBER FOUR +11D54 ; [.1CA7.0020.0002] # MASARAM GONDI DIGIT FOUR +12402 ; [.1CA7.0020.0002] # CUNEIFORM NUMERIC SIGN FOUR ASH +12409 ; [.1CA7.0020.0002] # CUNEIFORM NUMERIC SIGN FOUR DISH +1240F ; [.1CA7.0020.0002] # CUNEIFORM NUMERIC SIGN FOUR U +12418 ; [.1CA7.0020.0002] # CUNEIFORM NUMERIC SIGN FOUR GESH2 +12421 ; [.1CA7.0020.0002] # CUNEIFORM NUMERIC SIGN FOUR GESHU +12426 ; [.1CA7.0020.0002] # CUNEIFORM NUMERIC SIGN FOUR SHAR2 +12430 ; [.1CA7.0020.0002] # CUNEIFORM NUMERIC SIGN FOUR SHARU +12438 ; [.1CA7.0020.0002] # CUNEIFORM NUMERIC SIGN FOUR BURU +1243C ; [.1CA7.0020.0002] # CUNEIFORM NUMERIC SIGN FOUR VARIANT FORM LIMMU +1243D ; [.1CA7.0020.0002] # CUNEIFORM NUMERIC SIGN FOUR VARIANT FORM LIMMU4 +1243E ; [.1CA7.0020.0002] # CUNEIFORM NUMERIC SIGN FOUR VARIANT FORM LIMMU A +1243F ; [.1CA7.0020.0002] # CUNEIFORM NUMERIC SIGN FOUR VARIANT FORM LIMMU B +1244C ; [.1CA7.0020.0002] # CUNEIFORM NUMERIC SIGN FOUR ASH TENU +12452 ; [.1CA7.0020.0002] # CUNEIFORM NUMERIC SIGN FOUR BAN2 +12453 ; [.1CA7.0020.0002] # CUNEIFORM NUMERIC SIGN FOUR BAN2 VARIANT FORM +12469 ; [.1CA7.0020.0002] # CUNEIFORM NUMERIC SIGN FOUR U VARIANT FORM +16A64 ; [.1CA7.0020.0002] # MRO DIGIT FOUR +16B54 ; [.1CA7.0020.0002] # PAHAWH HMONG DIGIT FOUR +1D363 ; [.1CA7.0020.0002] # COUNTING ROD UNIT DIGIT FOUR +1E8CA ; [.1CA7.0020.0002] # MENDE KIKAKUI DIGIT FOUR +1E954 ; [.1CA7.0020.0002] # ADLAM DIGIT FOUR +FF14 ; [.1CA7.0020.0003] # FULLWIDTH DIGIT FOUR +0F2D ; [.1CA7.0020.0004] # TIBETAN DIGIT HALF FOUR +2477 ; [*0318.0020.0004][.1CA7.0020.0004][*0319.0020.0004] # PARENTHESIZED DIGIT FOUR +248B ; [.1CA7.0020.0004][*0278.0020.0004] # DIGIT FOUR FULL STOP +1F105 ; [.1CA7.0020.0004][*0222.0020.0004] # DIGIT FOUR COMMA +1D7D2 ; [.1CA7.0020.0005] # MATHEMATICAL BOLD DIGIT FOUR +1D7DC ; [.1CA7.0020.0005] # MATHEMATICAL DOUBLE-STRUCK DIGIT FOUR +1D7E6 ; [.1CA7.0020.0005] # MATHEMATICAL SANS-SERIF DIGIT FOUR +1D7F0 ; [.1CA7.0020.0005] # MATHEMATICAL SANS-SERIF BOLD DIGIT FOUR +1D7FA ; [.1CA7.0020.0005] # MATHEMATICAL MONOSPACE DIGIT FOUR +2463 ; [.1CA7.0020.0006] # CIRCLED DIGIT FOUR +24F8 ; [.1CA7.0020.0006] # DOUBLE CIRCLED DIGIT FOUR +2779 ; [.1CA7.0020.0006] # DINGBAT NEGATIVE CIRCLED DIGIT FOUR +2783 ; [.1CA7.0020.0006] # DINGBAT CIRCLED SANS-SERIF DIGIT FOUR +278D ; [.1CA7.0020.0006] # DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT FOUR +2074 ; [.1CA7.0020.0014] # SUPERSCRIPT FOUR +2084 ; [.1CA7.0020.0015] # SUBSCRIPT FOUR +324B ; [.1CA7.0020.0006][.1CA3.0020.0006] # CIRCLED NUMBER FORTY ON BLACK SQUARE +32B5 ; [.1CA7.0020.0006][.1CA3.0020.0006] # CIRCLED NUMBER FORTY +32B6 ; [.1CA7.0020.0006][.1CA4.0020.0006] # CIRCLED NUMBER FORTY ONE +32B7 ; [.1CA7.0020.0006][.1CA5.0020.0006] # CIRCLED NUMBER FORTY TWO +32B8 ; [.1CA7.0020.0006][.1CA6.0020.0006] # CIRCLED NUMBER FORTY THREE +32B9 ; [.1CA7.0020.0006][.1CA7.0020.0006] # CIRCLED NUMBER FORTY FOUR +32BA ; [.1CA7.0020.0006][.1CA8.0020.0006] # CIRCLED NUMBER FORTY FIVE +2158 ; [.1CA7.0020.001E][*063C.0020.001E][.1CA8.0020.001E] # VULGAR FRACTION FOUR FIFTHS +32BB ; [.1CA7.0020.0006][.1CA9.0020.0006] # CIRCLED NUMBER FORTY SIX +32BC ; [.1CA7.0020.0006][.1CAA.0020.0006] # CIRCLED NUMBER FORTY SEVEN +32BD ; [.1CA7.0020.0006][.1CAB.0020.0006] # CIRCLED NUMBER FORTY EIGHT +32BE ; [.1CA7.0020.0006][.1CAC.0020.0006] # CIRCLED NUMBER FORTY NINE +1F19E ; [.1CA7.0020.001C][.1DCB.0020.001D] # SQUARED FOUR K +33E3 ; [.1CA7.0020.0004][.FB40.0020.0004][.E5E5.0000.0000] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY FOUR +32C3 ; [.1CA7.0020.0004][.FB40.0020.0004][.E708.0000.0000] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR APRIL +335C ; [.1CA7.0020.0004][.FB40.0020.0004][.F0B9.0000.0000] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR FOUR +0035 ; [.1CA8.0020.0002] # DIGIT FIVE +0665 ; [.1CA8.0020.0002] # ARABIC-INDIC DIGIT FIVE +06F5 ; [.1CA8.0020.0002] # EXTENDED ARABIC-INDIC DIGIT FIVE +07C5 ; [.1CA8.0020.0002] # NKO DIGIT FIVE +096B ; [.1CA8.0020.0002] # DEVANAGARI DIGIT FIVE +09EB ; [.1CA8.0020.0002] # BENGALI DIGIT FIVE +0A6B ; [.1CA8.0020.0002] # GURMUKHI DIGIT FIVE +0AEB ; [.1CA8.0020.0002] # GUJARATI DIGIT FIVE +0B6B ; [.1CA8.0020.0002] # ORIYA DIGIT FIVE +0BEB ; [.1CA8.0020.0002] # TAMIL DIGIT FIVE +0C6B ; [.1CA8.0020.0002] # TELUGU DIGIT FIVE +0CEB ; [.1CA8.0020.0002] # KANNADA DIGIT FIVE +0D6B ; [.1CA8.0020.0002] # MALAYALAM DIGIT FIVE +0DEB ; [.1CA8.0020.0002] # SINHALA LITH DIGIT FIVE +0E55 ; [.1CA8.0020.0002] # THAI DIGIT FIVE +0ED5 ; [.1CA8.0020.0002] # LAO DIGIT FIVE +0F25 ; [.1CA8.0020.0002] # TIBETAN DIGIT FIVE +1045 ; [.1CA8.0020.0002] # MYANMAR DIGIT FIVE +1095 ; [.1CA8.0020.0002] # MYANMAR SHAN DIGIT FIVE +136D ; [.1CA8.0020.0002] # ETHIOPIC DIGIT FIVE +17E5 ; [.1CA8.0020.0002] # KHMER DIGIT FIVE +17F5 ; [.1CA8.0020.0002] # KHMER SYMBOL LEK ATTAK PRAM +1815 ; [.1CA8.0020.0002] # MONGOLIAN DIGIT FIVE +194B ; [.1CA8.0020.0002] # LIMBU DIGIT FIVE +19D5 ; [.1CA8.0020.0002] # NEW TAI LUE DIGIT FIVE +1A85 ; [.1CA8.0020.0002] # TAI THAM HORA DIGIT FIVE +1A95 ; [.1CA8.0020.0002] # TAI THAM THAM DIGIT FIVE +1B55 ; [.1CA8.0020.0002] # BALINESE DIGIT FIVE +1BB5 ; [.1CA8.0020.0002] # SUNDANESE DIGIT FIVE +1C45 ; [.1CA8.0020.0002] # LEPCHA DIGIT FIVE +1C55 ; [.1CA8.0020.0002] # OL CHIKI DIGIT FIVE +3025 ; [.1CA8.0020.0002] # HANGZHOU NUMERAL FIVE +A625 ; [.1CA8.0020.0002] # VAI DIGIT FIVE +A8D5 ; [.1CA8.0020.0002] # SAURASHTRA DIGIT FIVE +A905 ; [.1CA8.0020.0002] # KAYAH LI DIGIT FIVE +A9D5 ; [.1CA8.0020.0002] # JAVANESE DIGIT FIVE +A9F5 ; [.1CA8.0020.0002] # MYANMAR TAI LAING DIGIT FIVE +AA55 ; [.1CA8.0020.0002] # CHAM DIGIT FIVE +ABF5 ; [.1CA8.0020.0002] # MEETEI MAYEK DIGIT FIVE +1010B ; [.1CA8.0020.0002] # AEGEAN NUMBER FIVE +10143 ; [.1CA8.0020.0002] # GREEK ACROPHONIC ATTIC FIVE +10148 ; [.1CA8.0020.0002] # GREEK ACROPHONIC ATTIC FIVE TALENTS +1014F ; [.1CA8.0020.0002] # GREEK ACROPHONIC ATTIC FIVE STATERS +1015F ; [.1CA8.0020.0002] # GREEK ACROPHONIC TROEZENIAN FIVE +10173 ; [.1CA8.0020.0002] # GREEK ACROPHONIC DELPHIC FIVE MNAS +102E5 ; [.1CA8.0020.0002] # COPTIC EPACT DIGIT FIVE +10321 ; [.1CA8.0020.0002] # OLD ITALIC NUMERAL FIVE +104A5 ; [.1CA8.0020.0002] # OSMANYA DIGIT FIVE +1087D ; [.1CA8.0020.0002] # PALMYRENE NUMBER FIVE +108AC ; [.1CA8.0020.0002] # NABATAEAN NUMBER FIVE +108FC ; [.1CA8.0020.0002] # HATRAN NUMBER FIVE +109C4 ; [.1CA8.0020.0002] # MEROITIC CURSIVE NUMBER FIVE +10AEC ; [.1CA8.0020.0002] # MANICHAEAN NUMBER FIVE +10CFB ; [.1CA8.0020.0002] # OLD HUNGARIAN NUMBER FIVE +10E64 ; [.1CA8.0020.0002] # RUMI DIGIT FIVE +11056 ; [.1CA8.0020.0002] # BRAHMI NUMBER FIVE +1106B ; [.1CA8.0020.0002] # BRAHMI DIGIT FIVE +110F5 ; [.1CA8.0020.0002] # SORA SOMPENG DIGIT FIVE +1113B ; [.1CA8.0020.0002] # CHAKMA DIGIT FIVE +111D5 ; [.1CA8.0020.0002] # SHARADA DIGIT FIVE +111E5 ; [.1CA8.0020.0002] # SINHALA ARCHAIC DIGIT FIVE +112F5 ; [.1CA8.0020.0002] # KHUDAWADI DIGIT FIVE +11455 ; [.1CA8.0020.0002] # NEWA DIGIT FIVE +114D5 ; [.1CA8.0020.0002] # TIRHUTA DIGIT FIVE +11655 ; [.1CA8.0020.0002] # MODI DIGIT FIVE +116C5 ; [.1CA8.0020.0002] # TAKRI DIGIT FIVE +11735 ; [.1CA8.0020.0002] # AHOM DIGIT FIVE +118E5 ; [.1CA8.0020.0002] # WARANG CITI DIGIT FIVE +11C55 ; [.1CA8.0020.0002] # BHAIKSUKI DIGIT FIVE +11C5E ; [.1CA8.0020.0002] # BHAIKSUKI NUMBER FIVE +11D55 ; [.1CA8.0020.0002] # MASARAM GONDI DIGIT FIVE +12403 ; [.1CA8.0020.0002] # CUNEIFORM NUMERIC SIGN FIVE ASH +1240A ; [.1CA8.0020.0002] # CUNEIFORM NUMERIC SIGN FIVE DISH +12410 ; [.1CA8.0020.0002] # CUNEIFORM NUMERIC SIGN FIVE U +12419 ; [.1CA8.0020.0002] # CUNEIFORM NUMERIC SIGN FIVE GESH2 +12422 ; [.1CA8.0020.0002] # CUNEIFORM NUMERIC SIGN FIVE GESHU +12427 ; [.1CA8.0020.0002] # CUNEIFORM NUMERIC SIGN FIVE SHAR2 +12431 ; [.1CA8.0020.0002] # CUNEIFORM NUMERIC SIGN FIVE SHARU +12439 ; [.1CA8.0020.0002] # CUNEIFORM NUMERIC SIGN FIVE BURU +1244D ; [.1CA8.0020.0002] # CUNEIFORM NUMERIC SIGN FIVE ASH TENU +12454 ; [.1CA8.0020.0002] # CUNEIFORM NUMERIC SIGN FIVE BAN2 +12455 ; [.1CA8.0020.0002] # CUNEIFORM NUMERIC SIGN FIVE BAN2 VARIANT FORM +1246A ; [.1CA8.0020.0002] # CUNEIFORM NUMERIC SIGN FIVE U VARIANT FORM +16A65 ; [.1CA8.0020.0002] # MRO DIGIT FIVE +16B55 ; [.1CA8.0020.0002] # PAHAWH HMONG DIGIT FIVE +1D364 ; [.1CA8.0020.0002] # COUNTING ROD UNIT DIGIT FIVE +1E8CB ; [.1CA8.0020.0002] # MENDE KIKAKUI DIGIT FIVE +1E955 ; [.1CA8.0020.0002] # ADLAM DIGIT FIVE +FF15 ; [.1CA8.0020.0003] # FULLWIDTH DIGIT FIVE +0F2E ; [.1CA8.0020.0004] # TIBETAN DIGIT HALF FIVE +2478 ; [*0318.0020.0004][.1CA8.0020.0004][*0319.0020.0004] # PARENTHESIZED DIGIT FIVE +248C ; [.1CA8.0020.0004][*0278.0020.0004] # DIGIT FIVE FULL STOP +1F106 ; [.1CA8.0020.0004][*0222.0020.0004] # DIGIT FIVE COMMA +1D7D3 ; [.1CA8.0020.0005] # MATHEMATICAL BOLD DIGIT FIVE +1D7DD ; [.1CA8.0020.0005] # MATHEMATICAL DOUBLE-STRUCK DIGIT FIVE +1D7E7 ; [.1CA8.0020.0005] # MATHEMATICAL SANS-SERIF DIGIT FIVE +1D7F1 ; [.1CA8.0020.0005] # MATHEMATICAL SANS-SERIF BOLD DIGIT FIVE +1D7FB ; [.1CA8.0020.0005] # MATHEMATICAL MONOSPACE DIGIT FIVE +2464 ; [.1CA8.0020.0006] # CIRCLED DIGIT FIVE +24F9 ; [.1CA8.0020.0006] # DOUBLE CIRCLED DIGIT FIVE +277A ; [.1CA8.0020.0006] # DINGBAT NEGATIVE CIRCLED DIGIT FIVE +2784 ; [.1CA8.0020.0006] # DINGBAT CIRCLED SANS-SERIF DIGIT FIVE +278E ; [.1CA8.0020.0006] # DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT FIVE +2075 ; [.1CA8.0020.0014] # SUPERSCRIPT FIVE +2085 ; [.1CA8.0020.0015] # SUBSCRIPT FIVE +324C ; [.1CA8.0020.0006][.1CA3.0020.0006] # CIRCLED NUMBER FIFTY ON BLACK SQUARE +32BF ; [.1CA8.0020.0006][.1CA3.0020.0006] # CIRCLED NUMBER FIFTY +1F1A0 ; [.1CA8.0020.001C][*0278.0020.001C][.1CA4.0020.001C] # SQUARED FIVE POINT ONE +215A ; [.1CA8.0020.001E][*063C.0020.001E][.1CA9.0020.001E] # VULGAR FRACTION FIVE SIXTHS +215D ; [.1CA8.0020.001E][*063C.0020.001E][.1CAB.0020.001E] # VULGAR FRACTION FIVE EIGHTHS +33E4 ; [.1CA8.0020.0004][.FB40.0020.0004][.E5E5.0000.0000] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY FIVE +32C4 ; [.1CA8.0020.0004][.FB40.0020.0004][.E708.0000.0000] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR MAY +335D ; [.1CA8.0020.0004][.FB40.0020.0004][.F0B9.0000.0000] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR FIVE +0036 ; [.1CA9.0020.0002] # DIGIT SIX +0666 ; [.1CA9.0020.0002] # ARABIC-INDIC DIGIT SIX +06F6 ; [.1CA9.0020.0002] # EXTENDED ARABIC-INDIC DIGIT SIX +07C6 ; [.1CA9.0020.0002] # NKO DIGIT SIX +096C ; [.1CA9.0020.0002] # DEVANAGARI DIGIT SIX +09EC ; [.1CA9.0020.0002] # BENGALI DIGIT SIX +0A6C ; [.1CA9.0020.0002] # GURMUKHI DIGIT SIX +0AEC ; [.1CA9.0020.0002] # GUJARATI DIGIT SIX +0B6C ; [.1CA9.0020.0002] # ORIYA DIGIT SIX +0BEC ; [.1CA9.0020.0002] # TAMIL DIGIT SIX +0C6C ; [.1CA9.0020.0002] # TELUGU DIGIT SIX +0CEC ; [.1CA9.0020.0002] # KANNADA DIGIT SIX +0D6C ; [.1CA9.0020.0002] # MALAYALAM DIGIT SIX +0DEC ; [.1CA9.0020.0002] # SINHALA LITH DIGIT SIX +0E56 ; [.1CA9.0020.0002] # THAI DIGIT SIX +0ED6 ; [.1CA9.0020.0002] # LAO DIGIT SIX +0F26 ; [.1CA9.0020.0002] # TIBETAN DIGIT SIX +1046 ; [.1CA9.0020.0002] # MYANMAR DIGIT SIX +1096 ; [.1CA9.0020.0002] # MYANMAR SHAN DIGIT SIX +136E ; [.1CA9.0020.0002] # ETHIOPIC DIGIT SIX +17E6 ; [.1CA9.0020.0002] # KHMER DIGIT SIX +17F6 ; [.1CA9.0020.0002] # KHMER SYMBOL LEK ATTAK PRAM-MUOY +1816 ; [.1CA9.0020.0002] # MONGOLIAN DIGIT SIX +194C ; [.1CA9.0020.0002] # LIMBU DIGIT SIX +19D6 ; [.1CA9.0020.0002] # NEW TAI LUE DIGIT SIX +1A86 ; [.1CA9.0020.0002] # TAI THAM HORA DIGIT SIX +1A96 ; [.1CA9.0020.0002] # TAI THAM THAM DIGIT SIX +1B56 ; [.1CA9.0020.0002] # BALINESE DIGIT SIX +1BB6 ; [.1CA9.0020.0002] # SUNDANESE DIGIT SIX +1C46 ; [.1CA9.0020.0002] # LEPCHA DIGIT SIX +1C56 ; [.1CA9.0020.0002] # OL CHIKI DIGIT SIX +2185 ; [.1CA9.0020.0002] # ROMAN NUMERAL SIX LATE FORM +3026 ; [.1CA9.0020.0002] # HANGZHOU NUMERAL SIX +A626 ; [.1CA9.0020.0002] # VAI DIGIT SIX +A8D6 ; [.1CA9.0020.0002] # SAURASHTRA DIGIT SIX +A906 ; [.1CA9.0020.0002] # KAYAH LI DIGIT SIX +A9D6 ; [.1CA9.0020.0002] # JAVANESE DIGIT SIX +A9F6 ; [.1CA9.0020.0002] # MYANMAR TAI LAING DIGIT SIX +AA56 ; [.1CA9.0020.0002] # CHAM DIGIT SIX +ABF6 ; [.1CA9.0020.0002] # MEETEI MAYEK DIGIT SIX +1010C ; [.1CA9.0020.0002] # AEGEAN NUMBER SIX +102E6 ; [.1CA9.0020.0002] # COPTIC EPACT DIGIT SIX +104A6 ; [.1CA9.0020.0002] # OSMANYA DIGIT SIX +109C5 ; [.1CA9.0020.0002] # MEROITIC CURSIVE NUMBER SIX +10E65 ; [.1CA9.0020.0002] # RUMI DIGIT SIX +11057 ; [.1CA9.0020.0002] # BRAHMI NUMBER SIX +1106C ; [.1CA9.0020.0002] # BRAHMI DIGIT SIX +110F6 ; [.1CA9.0020.0002] # SORA SOMPENG DIGIT SIX +1113C ; [.1CA9.0020.0002] # CHAKMA DIGIT SIX +111D6 ; [.1CA9.0020.0002] # SHARADA DIGIT SIX +111E6 ; [.1CA9.0020.0002] # SINHALA ARCHAIC DIGIT SIX +112F6 ; [.1CA9.0020.0002] # KHUDAWADI DIGIT SIX +11456 ; [.1CA9.0020.0002] # NEWA DIGIT SIX +114D6 ; [.1CA9.0020.0002] # TIRHUTA DIGIT SIX +11656 ; [.1CA9.0020.0002] # MODI DIGIT SIX +116C6 ; [.1CA9.0020.0002] # TAKRI DIGIT SIX +11736 ; [.1CA9.0020.0002] # AHOM DIGIT SIX +118E6 ; [.1CA9.0020.0002] # WARANG CITI DIGIT SIX +11C56 ; [.1CA9.0020.0002] # BHAIKSUKI DIGIT SIX +11C5F ; [.1CA9.0020.0002] # BHAIKSUKI NUMBER SIX +11D56 ; [.1CA9.0020.0002] # MASARAM GONDI DIGIT SIX +12404 ; [.1CA9.0020.0002] # CUNEIFORM NUMERIC SIGN SIX ASH +1240B ; [.1CA9.0020.0002] # CUNEIFORM NUMERIC SIGN SIX DISH +12411 ; [.1CA9.0020.0002] # CUNEIFORM NUMERIC SIGN SIX U +1241A ; [.1CA9.0020.0002] # CUNEIFORM NUMERIC SIGN SIX GESH2 +12428 ; [.1CA9.0020.0002] # CUNEIFORM NUMERIC SIGN SIX SHAR2 +12440 ; [.1CA9.0020.0002] # CUNEIFORM NUMERIC SIGN SIX VARIANT FORM ASH9 +1244E ; [.1CA9.0020.0002] # CUNEIFORM NUMERIC SIGN SIX ASH TENU +1246B ; [.1CA9.0020.0002] # CUNEIFORM NUMERIC SIGN SIX U VARIANT FORM +16A66 ; [.1CA9.0020.0002] # MRO DIGIT SIX +16B56 ; [.1CA9.0020.0002] # PAHAWH HMONG DIGIT SIX +1D365 ; [.1CA9.0020.0002] # COUNTING ROD UNIT DIGIT SIX +1E8CC ; [.1CA9.0020.0002] # MENDE KIKAKUI DIGIT SIX +1E956 ; [.1CA9.0020.0002] # ADLAM DIGIT SIX +FF16 ; [.1CA9.0020.0003] # FULLWIDTH DIGIT SIX +0F2F ; [.1CA9.0020.0004] # TIBETAN DIGIT HALF SIX +2479 ; [*0318.0020.0004][.1CA9.0020.0004][*0319.0020.0004] # PARENTHESIZED DIGIT SIX +248D ; [.1CA9.0020.0004][*0278.0020.0004] # DIGIT SIX FULL STOP +1F107 ; [.1CA9.0020.0004][*0222.0020.0004] # DIGIT SIX COMMA +1D7D4 ; [.1CA9.0020.0005] # MATHEMATICAL BOLD DIGIT SIX +1D7DE ; [.1CA9.0020.0005] # MATHEMATICAL DOUBLE-STRUCK DIGIT SIX +1D7E8 ; [.1CA9.0020.0005] # MATHEMATICAL SANS-SERIF DIGIT SIX +1D7F2 ; [.1CA9.0020.0005] # MATHEMATICAL SANS-SERIF BOLD DIGIT SIX +1D7FC ; [.1CA9.0020.0005] # MATHEMATICAL MONOSPACE DIGIT SIX +2465 ; [.1CA9.0020.0006] # CIRCLED DIGIT SIX +24FA ; [.1CA9.0020.0006] # DOUBLE CIRCLED DIGIT SIX +277B ; [.1CA9.0020.0006] # DINGBAT NEGATIVE CIRCLED DIGIT SIX +2785 ; [.1CA9.0020.0006] # DINGBAT CIRCLED SANS-SERIF DIGIT SIX +278F ; [.1CA9.0020.0006] # DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT SIX +2076 ; [.1CA9.0020.0014] # SUPERSCRIPT SIX +2086 ; [.1CA9.0020.0015] # SUBSCRIPT SIX +324D ; [.1CA9.0020.0006][.1CA3.0020.0006] # CIRCLED NUMBER SIXTY ON BLACK SQUARE +1F1A3 ; [.1CA9.0020.001C][.1CA3.0020.001C][.1E72.0020.001D] # SQUARED SIXTY P +33E5 ; [.1CA9.0020.0004][.FB40.0020.0004][.E5E5.0000.0000] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY SIX +32C5 ; [.1CA9.0020.0004][.FB40.0020.0004][.E708.0000.0000] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR JUNE +335E ; [.1CA9.0020.0004][.FB40.0020.0004][.F0B9.0000.0000] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR SIX +0037 ; [.1CAA.0020.0002] # DIGIT SEVEN +0667 ; [.1CAA.0020.0002] # ARABIC-INDIC DIGIT SEVEN +06F7 ; [.1CAA.0020.0002] # EXTENDED ARABIC-INDIC DIGIT SEVEN +07C7 ; [.1CAA.0020.0002] # NKO DIGIT SEVEN +096D ; [.1CAA.0020.0002] # DEVANAGARI DIGIT SEVEN +09ED ; [.1CAA.0020.0002] # BENGALI DIGIT SEVEN +0A6D ; [.1CAA.0020.0002] # GURMUKHI DIGIT SEVEN +0AED ; [.1CAA.0020.0002] # GUJARATI DIGIT SEVEN +0B6D ; [.1CAA.0020.0002] # ORIYA DIGIT SEVEN +0BED ; [.1CAA.0020.0002] # TAMIL DIGIT SEVEN +0C6D ; [.1CAA.0020.0002] # TELUGU DIGIT SEVEN +0CED ; [.1CAA.0020.0002] # KANNADA DIGIT SEVEN +0D6D ; [.1CAA.0020.0002] # MALAYALAM DIGIT SEVEN +0DED ; [.1CAA.0020.0002] # SINHALA LITH DIGIT SEVEN +0E57 ; [.1CAA.0020.0002] # THAI DIGIT SEVEN +0ED7 ; [.1CAA.0020.0002] # LAO DIGIT SEVEN +0F27 ; [.1CAA.0020.0002] # TIBETAN DIGIT SEVEN +1047 ; [.1CAA.0020.0002] # MYANMAR DIGIT SEVEN +1097 ; [.1CAA.0020.0002] # MYANMAR SHAN DIGIT SEVEN +136F ; [.1CAA.0020.0002] # ETHIOPIC DIGIT SEVEN +17E7 ; [.1CAA.0020.0002] # KHMER DIGIT SEVEN +17F7 ; [.1CAA.0020.0002] # KHMER SYMBOL LEK ATTAK PRAM-PII +1817 ; [.1CAA.0020.0002] # MONGOLIAN DIGIT SEVEN +194D ; [.1CAA.0020.0002] # LIMBU DIGIT SEVEN +19D7 ; [.1CAA.0020.0002] # NEW TAI LUE DIGIT SEVEN +1A87 ; [.1CAA.0020.0002] # TAI THAM HORA DIGIT SEVEN +1A97 ; [.1CAA.0020.0002] # TAI THAM THAM DIGIT SEVEN +1B57 ; [.1CAA.0020.0002] # BALINESE DIGIT SEVEN +1BB7 ; [.1CAA.0020.0002] # SUNDANESE DIGIT SEVEN +1C47 ; [.1CAA.0020.0002] # LEPCHA DIGIT SEVEN +1C57 ; [.1CAA.0020.0002] # OL CHIKI DIGIT SEVEN +3027 ; [.1CAA.0020.0002] # HANGZHOU NUMERAL SEVEN +A627 ; [.1CAA.0020.0002] # VAI DIGIT SEVEN +A8D7 ; [.1CAA.0020.0002] # SAURASHTRA DIGIT SEVEN +A907 ; [.1CAA.0020.0002] # KAYAH LI DIGIT SEVEN +A9D7 ; [.1CAA.0020.0002] # JAVANESE DIGIT SEVEN +A9F7 ; [.1CAA.0020.0002] # MYANMAR TAI LAING DIGIT SEVEN +AA57 ; [.1CAA.0020.0002] # CHAM DIGIT SEVEN +ABF7 ; [.1CAA.0020.0002] # MEETEI MAYEK DIGIT SEVEN +1010D ; [.1CAA.0020.0002] # AEGEAN NUMBER SEVEN +102E7 ; [.1CAA.0020.0002] # COPTIC EPACT DIGIT SEVEN +104A7 ; [.1CAA.0020.0002] # OSMANYA DIGIT SEVEN +109C6 ; [.1CAA.0020.0002] # MEROITIC CURSIVE NUMBER SEVEN +10E66 ; [.1CAA.0020.0002] # RUMI DIGIT SEVEN +11058 ; [.1CAA.0020.0002] # BRAHMI NUMBER SEVEN +1106D ; [.1CAA.0020.0002] # BRAHMI DIGIT SEVEN +110F7 ; [.1CAA.0020.0002] # SORA SOMPENG DIGIT SEVEN +1113D ; [.1CAA.0020.0002] # CHAKMA DIGIT SEVEN +111D7 ; [.1CAA.0020.0002] # SHARADA DIGIT SEVEN +111E7 ; [.1CAA.0020.0002] # SINHALA ARCHAIC DIGIT SEVEN +112F7 ; [.1CAA.0020.0002] # KHUDAWADI DIGIT SEVEN +11457 ; [.1CAA.0020.0002] # NEWA DIGIT SEVEN +114D7 ; [.1CAA.0020.0002] # TIRHUTA DIGIT SEVEN +11657 ; [.1CAA.0020.0002] # MODI DIGIT SEVEN +116C7 ; [.1CAA.0020.0002] # TAKRI DIGIT SEVEN +11737 ; [.1CAA.0020.0002] # AHOM DIGIT SEVEN +118E7 ; [.1CAA.0020.0002] # WARANG CITI DIGIT SEVEN +11C57 ; [.1CAA.0020.0002] # BHAIKSUKI DIGIT SEVEN +11C60 ; [.1CAA.0020.0002] # BHAIKSUKI NUMBER SEVEN +11D57 ; [.1CAA.0020.0002] # MASARAM GONDI DIGIT SEVEN +12405 ; [.1CAA.0020.0002] # CUNEIFORM NUMERIC SIGN SEVEN ASH +1240C ; [.1CAA.0020.0002] # CUNEIFORM NUMERIC SIGN SEVEN DISH +12412 ; [.1CAA.0020.0002] # CUNEIFORM NUMERIC SIGN SEVEN U +1241B ; [.1CAA.0020.0002] # CUNEIFORM NUMERIC SIGN SEVEN GESH2 +12429 ; [.1CAA.0020.0002] # CUNEIFORM NUMERIC SIGN SEVEN SHAR2 +12441 ; [.1CAA.0020.0002] # CUNEIFORM NUMERIC SIGN SEVEN VARIANT FORM IMIN3 +12442 ; [.1CAA.0020.0002] # CUNEIFORM NUMERIC SIGN SEVEN VARIANT FORM IMIN A +12443 ; [.1CAA.0020.0002] # CUNEIFORM NUMERIC SIGN SEVEN VARIANT FORM IMIN B +1246C ; [.1CAA.0020.0002] # CUNEIFORM NUMERIC SIGN SEVEN U VARIANT FORM +16A67 ; [.1CAA.0020.0002] # MRO DIGIT SEVEN +16B57 ; [.1CAA.0020.0002] # PAHAWH HMONG DIGIT SEVEN +1D366 ; [.1CAA.0020.0002] # COUNTING ROD UNIT DIGIT SEVEN +1E8CD ; [.1CAA.0020.0002] # MENDE KIKAKUI DIGIT SEVEN +1E957 ; [.1CAA.0020.0002] # ADLAM DIGIT SEVEN +FF17 ; [.1CAA.0020.0003] # FULLWIDTH DIGIT SEVEN +0F30 ; [.1CAA.0020.0004] # TIBETAN DIGIT HALF SEVEN +247A ; [*0318.0020.0004][.1CAA.0020.0004][*0319.0020.0004] # PARENTHESIZED DIGIT SEVEN +248E ; [.1CAA.0020.0004][*0278.0020.0004] # DIGIT SEVEN FULL STOP +1F108 ; [.1CAA.0020.0004][*0222.0020.0004] # DIGIT SEVEN COMMA +1D7D5 ; [.1CAA.0020.0005] # MATHEMATICAL BOLD DIGIT SEVEN +1D7DF ; [.1CAA.0020.0005] # MATHEMATICAL DOUBLE-STRUCK DIGIT SEVEN +1D7E9 ; [.1CAA.0020.0005] # MATHEMATICAL SANS-SERIF DIGIT SEVEN +1D7F3 ; [.1CAA.0020.0005] # MATHEMATICAL SANS-SERIF BOLD DIGIT SEVEN +1D7FD ; [.1CAA.0020.0005] # MATHEMATICAL MONOSPACE DIGIT SEVEN +2466 ; [.1CAA.0020.0006] # CIRCLED DIGIT SEVEN +24FB ; [.1CAA.0020.0006] # DOUBLE CIRCLED DIGIT SEVEN +277C ; [.1CAA.0020.0006] # DINGBAT NEGATIVE CIRCLED DIGIT SEVEN +2786 ; [.1CAA.0020.0006] # DINGBAT CIRCLED SANS-SERIF DIGIT SEVEN +2790 ; [.1CAA.0020.0006] # DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT SEVEN +2077 ; [.1CAA.0020.0014] # SUPERSCRIPT SEVEN +2087 ; [.1CAA.0020.0015] # SUBSCRIPT SEVEN +324E ; [.1CAA.0020.0006][.1CA3.0020.0006] # CIRCLED NUMBER SEVENTY ON BLACK SQUARE +1F1A1 ; [.1CAA.0020.001C][*0278.0020.001C][.1CA4.0020.001C] # SQUARED SEVEN POINT ONE +215E ; [.1CAA.0020.001E][*063C.0020.001E][.1CAB.0020.001E] # VULGAR FRACTION SEVEN EIGHTHS +33E6 ; [.1CAA.0020.0004][.FB40.0020.0004][.E5E5.0000.0000] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY SEVEN +32C6 ; [.1CAA.0020.0004][.FB40.0020.0004][.E708.0000.0000] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR JULY +335F ; [.1CAA.0020.0004][.FB40.0020.0004][.F0B9.0000.0000] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR SEVEN +0038 ; [.1CAB.0020.0002] # DIGIT EIGHT +0668 ; [.1CAB.0020.0002] # ARABIC-INDIC DIGIT EIGHT +06F8 ; [.1CAB.0020.0002] # EXTENDED ARABIC-INDIC DIGIT EIGHT +07C8 ; [.1CAB.0020.0002] # NKO DIGIT EIGHT +096E ; [.1CAB.0020.0002] # DEVANAGARI DIGIT EIGHT +09EE ; [.1CAB.0020.0002] # BENGALI DIGIT EIGHT +0A6E ; [.1CAB.0020.0002] # GURMUKHI DIGIT EIGHT +0AEE ; [.1CAB.0020.0002] # GUJARATI DIGIT EIGHT +0B6E ; [.1CAB.0020.0002] # ORIYA DIGIT EIGHT +0BEE ; [.1CAB.0020.0002] # TAMIL DIGIT EIGHT +0C6E ; [.1CAB.0020.0002] # TELUGU DIGIT EIGHT +0CEE ; [.1CAB.0020.0002] # KANNADA DIGIT EIGHT +0D6E ; [.1CAB.0020.0002] # MALAYALAM DIGIT EIGHT +0DEE ; [.1CAB.0020.0002] # SINHALA LITH DIGIT EIGHT +0E58 ; [.1CAB.0020.0002] # THAI DIGIT EIGHT +0ED8 ; [.1CAB.0020.0002] # LAO DIGIT EIGHT +0F28 ; [.1CAB.0020.0002] # TIBETAN DIGIT EIGHT +1048 ; [.1CAB.0020.0002] # MYANMAR DIGIT EIGHT +1098 ; [.1CAB.0020.0002] # MYANMAR SHAN DIGIT EIGHT +1370 ; [.1CAB.0020.0002] # ETHIOPIC DIGIT EIGHT +17E8 ; [.1CAB.0020.0002] # KHMER DIGIT EIGHT +17F8 ; [.1CAB.0020.0002] # KHMER SYMBOL LEK ATTAK PRAM-BEI +1818 ; [.1CAB.0020.0002] # MONGOLIAN DIGIT EIGHT +194E ; [.1CAB.0020.0002] # LIMBU DIGIT EIGHT +19D8 ; [.1CAB.0020.0002] # NEW TAI LUE DIGIT EIGHT +1A88 ; [.1CAB.0020.0002] # TAI THAM HORA DIGIT EIGHT +1A98 ; [.1CAB.0020.0002] # TAI THAM THAM DIGIT EIGHT +1B58 ; [.1CAB.0020.0002] # BALINESE DIGIT EIGHT +1BB8 ; [.1CAB.0020.0002] # SUNDANESE DIGIT EIGHT +1C48 ; [.1CAB.0020.0002] # LEPCHA DIGIT EIGHT +1C58 ; [.1CAB.0020.0002] # OL CHIKI DIGIT EIGHT +3028 ; [.1CAB.0020.0002] # HANGZHOU NUMERAL EIGHT +A628 ; [.1CAB.0020.0002] # VAI DIGIT EIGHT +A8D8 ; [.1CAB.0020.0002] # SAURASHTRA DIGIT EIGHT +A908 ; [.1CAB.0020.0002] # KAYAH LI DIGIT EIGHT +A9D8 ; [.1CAB.0020.0002] # JAVANESE DIGIT EIGHT +A9F8 ; [.1CAB.0020.0002] # MYANMAR TAI LAING DIGIT EIGHT +AA58 ; [.1CAB.0020.0002] # CHAM DIGIT EIGHT +ABF8 ; [.1CAB.0020.0002] # MEETEI MAYEK DIGIT EIGHT +1010E ; [.1CAB.0020.0002] # AEGEAN NUMBER EIGHT +102E8 ; [.1CAB.0020.0002] # COPTIC EPACT DIGIT EIGHT +104A8 ; [.1CAB.0020.0002] # OSMANYA DIGIT EIGHT +109C7 ; [.1CAB.0020.0002] # MEROITIC CURSIVE NUMBER EIGHT +10E67 ; [.1CAB.0020.0002] # RUMI DIGIT EIGHT +11059 ; [.1CAB.0020.0002] # BRAHMI NUMBER EIGHT +1106E ; [.1CAB.0020.0002] # BRAHMI DIGIT EIGHT +110F8 ; [.1CAB.0020.0002] # SORA SOMPENG DIGIT EIGHT +1113E ; [.1CAB.0020.0002] # CHAKMA DIGIT EIGHT +111D8 ; [.1CAB.0020.0002] # SHARADA DIGIT EIGHT +111E8 ; [.1CAB.0020.0002] # SINHALA ARCHAIC DIGIT EIGHT +112F8 ; [.1CAB.0020.0002] # KHUDAWADI DIGIT EIGHT +11458 ; [.1CAB.0020.0002] # NEWA DIGIT EIGHT +114D8 ; [.1CAB.0020.0002] # TIRHUTA DIGIT EIGHT +11658 ; [.1CAB.0020.0002] # MODI DIGIT EIGHT +116C8 ; [.1CAB.0020.0002] # TAKRI DIGIT EIGHT +11738 ; [.1CAB.0020.0002] # AHOM DIGIT EIGHT +118E8 ; [.1CAB.0020.0002] # WARANG CITI DIGIT EIGHT +11C58 ; [.1CAB.0020.0002] # BHAIKSUKI DIGIT EIGHT +11C61 ; [.1CAB.0020.0002] # BHAIKSUKI NUMBER EIGHT +11D58 ; [.1CAB.0020.0002] # MASARAM GONDI DIGIT EIGHT +12406 ; [.1CAB.0020.0002] # CUNEIFORM NUMERIC SIGN EIGHT ASH +1240D ; [.1CAB.0020.0002] # CUNEIFORM NUMERIC SIGN EIGHT DISH +12413 ; [.1CAB.0020.0002] # CUNEIFORM NUMERIC SIGN EIGHT U +1241C ; [.1CAB.0020.0002] # CUNEIFORM NUMERIC SIGN EIGHT GESH2 +1242A ; [.1CAB.0020.0002] # CUNEIFORM NUMERIC SIGN EIGHT SHAR2 +12444 ; [.1CAB.0020.0002] # CUNEIFORM NUMERIC SIGN EIGHT VARIANT FORM USSU +12445 ; [.1CAB.0020.0002] # CUNEIFORM NUMERIC SIGN EIGHT VARIANT FORM USSU3 +1246D ; [.1CAB.0020.0002] # CUNEIFORM NUMERIC SIGN EIGHT U VARIANT FORM +16A68 ; [.1CAB.0020.0002] # MRO DIGIT EIGHT +16B58 ; [.1CAB.0020.0002] # PAHAWH HMONG DIGIT EIGHT +1D367 ; [.1CAB.0020.0002] # COUNTING ROD UNIT DIGIT EIGHT +1E8CE ; [.1CAB.0020.0002] # MENDE KIKAKUI DIGIT EIGHT +1E958 ; [.1CAB.0020.0002] # ADLAM DIGIT EIGHT +FF18 ; [.1CAB.0020.0003] # FULLWIDTH DIGIT EIGHT +0F31 ; [.1CAB.0020.0004] # TIBETAN DIGIT HALF EIGHT +247B ; [*0318.0020.0004][.1CAB.0020.0004][*0319.0020.0004] # PARENTHESIZED DIGIT EIGHT +248F ; [.1CAB.0020.0004][*0278.0020.0004] # DIGIT EIGHT FULL STOP +1F109 ; [.1CAB.0020.0004][*0222.0020.0004] # DIGIT EIGHT COMMA +1D7D6 ; [.1CAB.0020.0005] # MATHEMATICAL BOLD DIGIT EIGHT +1D7E0 ; [.1CAB.0020.0005] # MATHEMATICAL DOUBLE-STRUCK DIGIT EIGHT +1D7EA ; [.1CAB.0020.0005] # MATHEMATICAL SANS-SERIF DIGIT EIGHT +1D7F4 ; [.1CAB.0020.0005] # MATHEMATICAL SANS-SERIF BOLD DIGIT EIGHT +1D7FE ; [.1CAB.0020.0005] # MATHEMATICAL MONOSPACE DIGIT EIGHT +2467 ; [.1CAB.0020.0006] # CIRCLED DIGIT EIGHT +24FC ; [.1CAB.0020.0006] # DOUBLE CIRCLED DIGIT EIGHT +277D ; [.1CAB.0020.0006] # DINGBAT NEGATIVE CIRCLED DIGIT EIGHT +2787 ; [.1CAB.0020.0006] # DINGBAT CIRCLED SANS-SERIF DIGIT EIGHT +2791 ; [.1CAB.0020.0006] # DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT EIGHT +2078 ; [.1CAB.0020.0014] # SUPERSCRIPT EIGHT +2088 ; [.1CAB.0020.0015] # SUBSCRIPT EIGHT +324F ; [.1CAB.0020.0006][.1CA3.0020.0006] # CIRCLED NUMBER EIGHTY ON BLACK SQUARE +1F19F ; [.1CAB.0020.001C][.1DCB.0020.001D] # SQUARED EIGHT K +33E7 ; [.1CAB.0020.0004][.FB40.0020.0004][.E5E5.0000.0000] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY EIGHT +32C7 ; [.1CAB.0020.0004][.FB40.0020.0004][.E708.0000.0000] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR AUGUST +3360 ; [.1CAB.0020.0004][.FB40.0020.0004][.F0B9.0000.0000] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR EIGHT +0039 ; [.1CAC.0020.0002] # DIGIT NINE +0669 ; [.1CAC.0020.0002] # ARABIC-INDIC DIGIT NINE +06F9 ; [.1CAC.0020.0002] # EXTENDED ARABIC-INDIC DIGIT NINE +07C9 ; [.1CAC.0020.0002] # NKO DIGIT NINE +096F ; [.1CAC.0020.0002] # DEVANAGARI DIGIT NINE +09EF ; [.1CAC.0020.0002] # BENGALI DIGIT NINE +0A6F ; [.1CAC.0020.0002] # GURMUKHI DIGIT NINE +0AEF ; [.1CAC.0020.0002] # GUJARATI DIGIT NINE +0B6F ; [.1CAC.0020.0002] # ORIYA DIGIT NINE +0BEF ; [.1CAC.0020.0002] # TAMIL DIGIT NINE +0C6F ; [.1CAC.0020.0002] # TELUGU DIGIT NINE +0CEF ; [.1CAC.0020.0002] # KANNADA DIGIT NINE +0D6F ; [.1CAC.0020.0002] # MALAYALAM DIGIT NINE +0DEF ; [.1CAC.0020.0002] # SINHALA LITH DIGIT NINE +0E59 ; [.1CAC.0020.0002] # THAI DIGIT NINE +0ED9 ; [.1CAC.0020.0002] # LAO DIGIT NINE +0F29 ; [.1CAC.0020.0002] # TIBETAN DIGIT NINE +1049 ; [.1CAC.0020.0002] # MYANMAR DIGIT NINE +1099 ; [.1CAC.0020.0002] # MYANMAR SHAN DIGIT NINE +1371 ; [.1CAC.0020.0002] # ETHIOPIC DIGIT NINE +17E9 ; [.1CAC.0020.0002] # KHMER DIGIT NINE +17F9 ; [.1CAC.0020.0002] # KHMER SYMBOL LEK ATTAK PRAM-BUON +1819 ; [.1CAC.0020.0002] # MONGOLIAN DIGIT NINE +194F ; [.1CAC.0020.0002] # LIMBU DIGIT NINE +19D9 ; [.1CAC.0020.0002] # NEW TAI LUE DIGIT NINE +1A89 ; [.1CAC.0020.0002] # TAI THAM HORA DIGIT NINE +1A99 ; [.1CAC.0020.0002] # TAI THAM THAM DIGIT NINE +1B59 ; [.1CAC.0020.0002] # BALINESE DIGIT NINE +1BB9 ; [.1CAC.0020.0002] # SUNDANESE DIGIT NINE +1C49 ; [.1CAC.0020.0002] # LEPCHA DIGIT NINE +1C59 ; [.1CAC.0020.0002] # OL CHIKI DIGIT NINE +3029 ; [.1CAC.0020.0002] # HANGZHOU NUMERAL NINE +A629 ; [.1CAC.0020.0002] # VAI DIGIT NINE +A8D9 ; [.1CAC.0020.0002] # SAURASHTRA DIGIT NINE +A909 ; [.1CAC.0020.0002] # KAYAH LI DIGIT NINE +A9D9 ; [.1CAC.0020.0002] # JAVANESE DIGIT NINE +A9F9 ; [.1CAC.0020.0002] # MYANMAR TAI LAING DIGIT NINE +AA59 ; [.1CAC.0020.0002] # CHAM DIGIT NINE +ABF9 ; [.1CAC.0020.0002] # MEETEI MAYEK DIGIT NINE +1010F ; [.1CAC.0020.0002] # AEGEAN NUMBER NINE +102E9 ; [.1CAC.0020.0002] # COPTIC EPACT DIGIT NINE +104A9 ; [.1CAC.0020.0002] # OSMANYA DIGIT NINE +109C8 ; [.1CAC.0020.0002] # MEROITIC CURSIVE NUMBER NINE +10E68 ; [.1CAC.0020.0002] # RUMI DIGIT NINE +1105A ; [.1CAC.0020.0002] # BRAHMI NUMBER NINE +1106F ; [.1CAC.0020.0002] # BRAHMI DIGIT NINE +110F9 ; [.1CAC.0020.0002] # SORA SOMPENG DIGIT NINE +1113F ; [.1CAC.0020.0002] # CHAKMA DIGIT NINE +111D9 ; [.1CAC.0020.0002] # SHARADA DIGIT NINE +111E9 ; [.1CAC.0020.0002] # SINHALA ARCHAIC DIGIT NINE +112F9 ; [.1CAC.0020.0002] # KHUDAWADI DIGIT NINE +11459 ; [.1CAC.0020.0002] # NEWA DIGIT NINE +114D9 ; [.1CAC.0020.0002] # TIRHUTA DIGIT NINE +11659 ; [.1CAC.0020.0002] # MODI DIGIT NINE +116C9 ; [.1CAC.0020.0002] # TAKRI DIGIT NINE +11739 ; [.1CAC.0020.0002] # AHOM DIGIT NINE +118E9 ; [.1CAC.0020.0002] # WARANG CITI DIGIT NINE +11C59 ; [.1CAC.0020.0002] # BHAIKSUKI DIGIT NINE +11C62 ; [.1CAC.0020.0002] # BHAIKSUKI NUMBER NINE +11D59 ; [.1CAC.0020.0002] # MASARAM GONDI DIGIT NINE +12407 ; [.1CAC.0020.0002] # CUNEIFORM NUMERIC SIGN NINE ASH +1240E ; [.1CAC.0020.0002] # CUNEIFORM NUMERIC SIGN NINE DISH +12414 ; [.1CAC.0020.0002] # CUNEIFORM NUMERIC SIGN NINE U +1241D ; [.1CAC.0020.0002] # CUNEIFORM NUMERIC SIGN NINE GESH2 +1242B ; [.1CAC.0020.0002] # CUNEIFORM NUMERIC SIGN NINE SHAR2 +12446 ; [.1CAC.0020.0002] # CUNEIFORM NUMERIC SIGN NINE VARIANT FORM ILIMMU +12447 ; [.1CAC.0020.0002] # CUNEIFORM NUMERIC SIGN NINE VARIANT FORM ILIMMU3 +12448 ; [.1CAC.0020.0002] # CUNEIFORM NUMERIC SIGN NINE VARIANT FORM ILIMMU4 +12449 ; [.1CAC.0020.0002] # CUNEIFORM NUMERIC SIGN NINE VARIANT FORM ILIMMU A +1246E ; [.1CAC.0020.0002] # CUNEIFORM NUMERIC SIGN NINE U VARIANT FORM +16A69 ; [.1CAC.0020.0002] # MRO DIGIT NINE +16B59 ; [.1CAC.0020.0002] # PAHAWH HMONG DIGIT NINE +1D368 ; [.1CAC.0020.0002] # COUNTING ROD UNIT DIGIT NINE +1E8CF ; [.1CAC.0020.0002] # MENDE KIKAKUI DIGIT NINE +1E959 ; [.1CAC.0020.0002] # ADLAM DIGIT NINE +FF19 ; [.1CAC.0020.0003] # FULLWIDTH DIGIT NINE +0F32 ; [.1CAC.0020.0004] # TIBETAN DIGIT HALF NINE +247C ; [*0318.0020.0004][.1CAC.0020.0004][*0319.0020.0004] # PARENTHESIZED DIGIT NINE +2490 ; [.1CAC.0020.0004][*0278.0020.0004] # DIGIT NINE FULL STOP +1F10A ; [.1CAC.0020.0004][*0222.0020.0004] # DIGIT NINE COMMA +1D7D7 ; [.1CAC.0020.0005] # MATHEMATICAL BOLD DIGIT NINE +1D7E1 ; [.1CAC.0020.0005] # MATHEMATICAL DOUBLE-STRUCK DIGIT NINE +1D7EB ; [.1CAC.0020.0005] # MATHEMATICAL SANS-SERIF DIGIT NINE +1D7F5 ; [.1CAC.0020.0005] # MATHEMATICAL SANS-SERIF BOLD DIGIT NINE +1D7FF ; [.1CAC.0020.0005] # MATHEMATICAL MONOSPACE DIGIT NINE +2468 ; [.1CAC.0020.0006] # CIRCLED DIGIT NINE +24FD ; [.1CAC.0020.0006] # DOUBLE CIRCLED DIGIT NINE +277E ; [.1CAC.0020.0006] # DINGBAT NEGATIVE CIRCLED DIGIT NINE +2788 ; [.1CAC.0020.0006] # DINGBAT CIRCLED SANS-SERIF DIGIT NINE +2792 ; [.1CAC.0020.0006] # DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT NINE +2079 ; [.1CAC.0020.0014] # SUPERSCRIPT NINE +2089 ; [.1CAC.0020.0015] # SUBSCRIPT NINE +33E8 ; [.1CAC.0020.0004][.FB40.0020.0004][.E5E5.0000.0000] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY NINE +32C8 ; [.1CAC.0020.0004][.FB40.0020.0004][.E708.0000.0000] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR SEPTEMBER +3361 ; [.1CAC.0020.0004][.FB40.0020.0004][.F0B9.0000.0000] # IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR NINE +0061 ; [.1CAD.0020.0002] # LATIN SMALL LETTER A +FF41 ; [.1CAD.0020.0003] # FULLWIDTH LATIN SMALL LETTER A +0363 ; [.1CAD.0020.0004] # COMBINING LATIN SMALL LETTER A +249C ; [*0318.0020.0004][.1CAD.0020.0004][*0319.0020.0004] # PARENTHESIZED LATIN SMALL LETTER A +1D41A ; [.1CAD.0020.0005] # MATHEMATICAL BOLD SMALL A +1D44E ; [.1CAD.0020.0005] # MATHEMATICAL ITALIC SMALL A +1D482 ; [.1CAD.0020.0005] # MATHEMATICAL BOLD ITALIC SMALL A +1D4B6 ; [.1CAD.0020.0005] # MATHEMATICAL SCRIPT SMALL A +1D4EA ; [.1CAD.0020.0005] # MATHEMATICAL BOLD SCRIPT SMALL A +1D51E ; [.1CAD.0020.0005] # MATHEMATICAL FRAKTUR SMALL A +1D552 ; [.1CAD.0020.0005] # MATHEMATICAL DOUBLE-STRUCK SMALL A +1D586 ; [.1CAD.0020.0005] # MATHEMATICAL BOLD FRAKTUR SMALL A +1D5BA ; [.1CAD.0020.0005] # MATHEMATICAL SANS-SERIF SMALL A +1D5EE ; [.1CAD.0020.0005] # MATHEMATICAL SANS-SERIF BOLD SMALL A +1D622 ; [.1CAD.0020.0005] # MATHEMATICAL SANS-SERIF ITALIC SMALL A +1D656 ; [.1CAD.0020.0005] # MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL A +1D68A ; [.1CAD.0020.0005] # MATHEMATICAL MONOSPACE SMALL A +24D0 ; [.1CAD.0020.0006] # CIRCLED LATIN SMALL LETTER A +0041 ; [.1CAD.0020.0008] # LATIN CAPITAL LETTER A +FF21 ; [.1CAD.0020.0009] # FULLWIDTH LATIN CAPITAL LETTER A +1F110 ; [*0318.0020.0004][.1CAD.0020.000A][*0319.0020.0004] # PARENTHESIZED LATIN CAPITAL LETTER A +1D400 ; [.1CAD.0020.000B] # MATHEMATICAL BOLD CAPITAL A +1D434 ; [.1CAD.0020.000B] # MATHEMATICAL ITALIC CAPITAL A +1D468 ; [.1CAD.0020.000B] # MATHEMATICAL BOLD ITALIC CAPITAL A +1D49C ; [.1CAD.0020.000B] # MATHEMATICAL SCRIPT CAPITAL A +1D4D0 ; [.1CAD.0020.000B] # MATHEMATICAL BOLD SCRIPT CAPITAL A +1D504 ; [.1CAD.0020.000B] # MATHEMATICAL FRAKTUR CAPITAL A +1D538 ; [.1CAD.0020.000B] # MATHEMATICAL DOUBLE-STRUCK CAPITAL A +1D56C ; [.1CAD.0020.000B] # MATHEMATICAL BOLD FRAKTUR CAPITAL A +1D5A0 ; [.1CAD.0020.000B] # MATHEMATICAL SANS-SERIF CAPITAL A +1D5D4 ; [.1CAD.0020.000B] # MATHEMATICAL SANS-SERIF BOLD CAPITAL A +1D608 ; [.1CAD.0020.000B] # MATHEMATICAL SANS-SERIF ITALIC CAPITAL A +1D63C ; [.1CAD.0020.000B] # MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL A +1D670 ; [.1CAD.0020.000B] # MATHEMATICAL MONOSPACE CAPITAL A +24B6 ; [.1CAD.0020.000C] # CIRCLED LATIN CAPITAL LETTER A +1F150 ; [.1CAD.0020.000C] # NEGATIVE CIRCLED LATIN CAPITAL LETTER A +00AA ; [.1CAD.0020.0014] # FEMININE ORDINAL INDICATOR +1D43 ; [.1CAD.0020.0014] # MODIFIER LETTER SMALL A +2090 ; [.1CAD.0020.0015] # LATIN SUBSCRIPT SMALL LETTER A +1D2C ; [.1CAD.0020.001D] # MODIFIER LETTER CAPITAL A +1F130 ; [.1CAD.0020.001D] # SQUARED LATIN CAPITAL LETTER A +1F170 ; [.1CAD.0020.001D] # NEGATIVE SQUARED LATIN CAPITAL LETTER A +00E1 ; [.1CAD.0020.0002][.0000.0024.0002] # LATIN SMALL LETTER A WITH ACUTE +00C1 ; [.1CAD.0020.0008][.0000.0024.0002] # LATIN CAPITAL LETTER A WITH ACUTE +00E0 ; [.1CAD.0020.0002][.0000.0025.0002] # LATIN SMALL LETTER A WITH GRAVE +00C0 ; [.1CAD.0020.0008][.0000.0025.0002] # LATIN CAPITAL LETTER A WITH GRAVE +0103 ; [.1CAD.0020.0002][.0000.0026.0002] # LATIN SMALL LETTER A WITH BREVE +0102 ; [.1CAD.0020.0008][.0000.0026.0002] # LATIN CAPITAL LETTER A WITH BREVE +1EAF ; [.1CAD.0020.0002][.0000.0026.0002][.0000.0024.0002] # LATIN SMALL LETTER A WITH BREVE AND ACUTE +1EAE ; [.1CAD.0020.0008][.0000.0026.0002][.0000.0024.0002] # LATIN CAPITAL LETTER A WITH BREVE AND ACUTE +1EB1 ; [.1CAD.0020.0002][.0000.0026.0002][.0000.0025.0002] # LATIN SMALL LETTER A WITH BREVE AND GRAVE +1EB0 ; [.1CAD.0020.0008][.0000.0026.0002][.0000.0025.0002] # LATIN CAPITAL LETTER A WITH BREVE AND GRAVE +1EB5 ; [.1CAD.0020.0002][.0000.0026.0002][.0000.002D.0002] # LATIN SMALL LETTER A WITH BREVE AND TILDE +1EB4 ; [.1CAD.0020.0008][.0000.0026.0002][.0000.002D.0002] # LATIN CAPITAL LETTER A WITH BREVE AND TILDE +1EB3 ; [.1CAD.0020.0002][.0000.0026.0002][.0000.003B.0002] # LATIN SMALL LETTER A WITH BREVE AND HOOK ABOVE +1EB2 ; [.1CAD.0020.0008][.0000.0026.0002][.0000.003B.0002] # LATIN CAPITAL LETTER A WITH BREVE AND HOOK ABOVE +00E2 ; [.1CAD.0020.0002][.0000.0027.0002] # LATIN SMALL LETTER A WITH CIRCUMFLEX +00C2 ; [.1CAD.0020.0008][.0000.0027.0002] # LATIN CAPITAL LETTER A WITH CIRCUMFLEX +1EA5 ; [.1CAD.0020.0002][.0000.0027.0002][.0000.0024.0002] # LATIN SMALL LETTER A WITH CIRCUMFLEX AND ACUTE +1EA4 ; [.1CAD.0020.0008][.0000.0027.0002][.0000.0024.0002] # LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND ACUTE +1EA7 ; [.1CAD.0020.0002][.0000.0027.0002][.0000.0025.0002] # LATIN SMALL LETTER A WITH CIRCUMFLEX AND GRAVE +1EA6 ; [.1CAD.0020.0008][.0000.0027.0002][.0000.0025.0002] # LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND GRAVE +1EAB ; [.1CAD.0020.0002][.0000.0027.0002][.0000.002D.0002] # LATIN SMALL LETTER A WITH CIRCUMFLEX AND TILDE +1EAA ; [.1CAD.0020.0008][.0000.0027.0002][.0000.002D.0002] # LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND TILDE +1EA9 ; [.1CAD.0020.0002][.0000.0027.0002][.0000.003B.0002] # LATIN SMALL LETTER A WITH CIRCUMFLEX AND HOOK ABOVE +1EA8 ; [.1CAD.0020.0008][.0000.0027.0002][.0000.003B.0002] # LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND HOOK ABOVE +01CE ; [.1CAD.0020.0002][.0000.0028.0002] # LATIN SMALL LETTER A WITH CARON +01CD ; [.1CAD.0020.0008][.0000.0028.0002] # LATIN CAPITAL LETTER A WITH CARON +00E5 ; [.1CAD.0020.0002][.0000.0029.0002] # LATIN SMALL LETTER A WITH RING ABOVE +00C5 ; [.1CAD.0020.0008][.0000.0029.0002] # LATIN CAPITAL LETTER A WITH RING ABOVE +212B ; [.1CAD.0020.0008][.0000.0029.0002] # ANGSTROM SIGN +01FB ; [.1CAD.0020.0002][.0000.0029.0002][.0000.0024.0002] # LATIN SMALL LETTER A WITH RING ABOVE AND ACUTE +01FA ; [.1CAD.0020.0008][.0000.0029.0002][.0000.0024.0002] # LATIN CAPITAL LETTER A WITH RING ABOVE AND ACUTE +00E4 ; [.1CAD.0020.0002][.0000.002B.0002] # LATIN SMALL LETTER A WITH DIAERESIS +1DF2 ; [.1CAD.0020.0004][.0000.002B.0004] # COMBINING LATIN SMALL LETTER A WITH DIAERESIS +A79B ; [.1CAD.0020.0004][.0000.002B.0004] # LATIN SMALL LETTER VOLAPUK AE +00C4 ; [.1CAD.0020.0008][.0000.002B.0002] # LATIN CAPITAL LETTER A WITH DIAERESIS +A79A ; [.1CAD.0020.000A][.0000.002B.0004] # LATIN CAPITAL LETTER VOLAPUK AE +01DF ; [.1CAD.0020.0002][.0000.002B.0002][.0000.0032.0002] # LATIN SMALL LETTER A WITH DIAERESIS AND MACRON +01DE ; [.1CAD.0020.0008][.0000.002B.0002][.0000.0032.0002] # LATIN CAPITAL LETTER A WITH DIAERESIS AND MACRON +00E3 ; [.1CAD.0020.0002][.0000.002D.0002] # LATIN SMALL LETTER A WITH TILDE +00C3 ; [.1CAD.0020.0008][.0000.002D.0002] # LATIN CAPITAL LETTER A WITH TILDE +0227 ; [.1CAD.0020.0002][.0000.002E.0002] # LATIN SMALL LETTER A WITH DOT ABOVE +0226 ; [.1CAD.0020.0008][.0000.002E.0002] # LATIN CAPITAL LETTER A WITH DOT ABOVE +01E1 ; [.1CAD.0020.0002][.0000.002E.0002][.0000.0032.0002] # LATIN SMALL LETTER A WITH DOT ABOVE AND MACRON +01E0 ; [.1CAD.0020.0008][.0000.002E.0002][.0000.0032.0002] # LATIN CAPITAL LETTER A WITH DOT ABOVE AND MACRON +0105 ; [.1CAD.0020.0002][.0000.0031.0002] # LATIN SMALL LETTER A WITH OGONEK +0104 ; [.1CAD.0020.0008][.0000.0031.0002] # LATIN CAPITAL LETTER A WITH OGONEK +0101 ; [.1CAD.0020.0002][.0000.0032.0002] # LATIN SMALL LETTER A WITH MACRON +0100 ; [.1CAD.0020.0008][.0000.0032.0002] # LATIN CAPITAL LETTER A WITH MACRON +1EA3 ; [.1CAD.0020.0002][.0000.003B.0002] # LATIN SMALL LETTER A WITH HOOK ABOVE +1EA2 ; [.1CAD.0020.0008][.0000.003B.0002] # LATIN CAPITAL LETTER A WITH HOOK ABOVE +0201 ; [.1CAD.0020.0002][.0000.003C.0002] # LATIN SMALL LETTER A WITH DOUBLE GRAVE +0200 ; [.1CAD.0020.0008][.0000.003C.0002] # LATIN CAPITAL LETTER A WITH DOUBLE GRAVE +0203 ; [.1CAD.0020.0002][.0000.003E.0002] # LATIN SMALL LETTER A WITH INVERTED BREVE +0202 ; [.1CAD.0020.0008][.0000.003E.0002] # LATIN CAPITAL LETTER A WITH INVERTED BREVE +1EA1 ; [.1CAD.0020.0002][.0000.0042.0002] # LATIN SMALL LETTER A WITH DOT BELOW +1EA0 ; [.1CAD.0020.0008][.0000.0042.0002] # LATIN CAPITAL LETTER A WITH DOT BELOW +1EB7 ; [.1CAD.0020.0002][.0000.0042.0002][.0000.0026.0002] # LATIN SMALL LETTER A WITH BREVE AND DOT BELOW +1EB6 ; [.1CAD.0020.0008][.0000.0042.0002][.0000.0026.0002] # LATIN CAPITAL LETTER A WITH BREVE AND DOT BELOW +1EAD ; [.1CAD.0020.0002][.0000.0042.0002][.0000.0027.0002] # LATIN SMALL LETTER A WITH CIRCUMFLEX AND DOT BELOW +1EAC ; [.1CAD.0020.0008][.0000.0042.0002][.0000.0027.0002] # LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND DOT BELOW +1E01 ; [.1CAD.0020.0002][.0000.0044.0002] # LATIN SMALL LETTER A WITH RING BELOW +1E00 ; [.1CAD.0020.0008][.0000.0044.0002] # LATIN CAPITAL LETTER A WITH RING BELOW +1DD3 ; [.1CAD.0020.0004][.0000.0111.0004] # COMBINING LATIN SMALL LETTER FLATTENED OPEN A ABOVE +A733 ; [.1CAD.0020.0004][.1CAD.0020.0004] # LATIN SMALL LETTER AA +A732 ; [.1CAD.0020.000A][.1CAD.0020.000A] # LATIN CAPITAL LETTER AA +1F18E ; [.1CAD.0020.001D][.1CC6.0020.001D] # NEGATIVE SQUARED AB +2100 ; [.1CAD.0020.0004][*0395.0020.0004][.1CE0.0020.0004] # ACCOUNT OF +00E6 ; [.1CAD.0020.0004][.0000.0111.0004][.1D10.0020.0004] # LATIN SMALL LETTER AE +1DD4 ; [.1CAD.0020.0004][.0000.0111.0004][.1D10.0020.0004] # COMBINING LATIN SMALL LETTER AE +00C6 ; [.1CAD.0020.000A][.0000.0111.0004][.1D10.0020.000A] # LATIN CAPITAL LETTER AE +1D2D ; [.1CAD.0020.0014][.0000.0111.0014][.1D10.0020.0014] # MODIFIER LETTER CAPITAL AE +01FD ; [.1CAD.0020.0004][.0000.0111.0004][.1D10.0020.0004][.0000.0024.0002] # LATIN SMALL LETTER AE WITH ACUTE +01FC ; [.1CAD.0020.000A][.0000.0111.0004][.1D10.0020.000A][.0000.0024.0002] # LATIN CAPITAL LETTER AE WITH ACUTE +01E3 ; [.1CAD.0020.0004][.0000.0111.0004][.1D10.0020.0004][.0000.0032.0002] # LATIN SMALL LETTER AE WITH MACRON +01E2 ; [.1CAD.0020.000A][.0000.0111.0004][.1D10.0020.000A][.0000.0032.0002] # LATIN CAPITAL LETTER AE WITH MACRON +33C2 ; [.1CAD.0020.001C][*0278.0020.001C][.1E10.0020.001C][*0278.0020.001C] # SQUARE AM +33DF ; [.1CAD.0020.001D][*063B.0020.001C][.1E10.0020.001C] # SQUARE A OVER M +1DD5 ; [.1CAD.0020.0004][.1E43.0020.0004] # COMBINING LATIN SMALL LETTER AO +A735 ; [.1CAD.0020.0004][.1E43.0020.0004] # LATIN SMALL LETTER AO +A734 ; [.1CAD.0020.000A][.1E43.0020.000A] # LATIN CAPITAL LETTER AO +2101 ; [.1CAD.0020.0004][*0395.0020.0004][.1ED7.0020.0004] # ADDRESSED TO THE SUBJECT +214D ; [.1CAD.0020.000A][*0395.0020.0004][.1ED7.0020.000A] # AKTIESELSKAB +A737 ; [.1CAD.0020.0004][.1F1B.0020.0004] # LATIN SMALL LETTER AU +A736 ; [.1CAD.0020.000A][.1F1B.0020.000A] # LATIN CAPITAL LETTER AU +3373 ; [.1CAD.0020.001D][.1F1B.0020.001D] # SQUARE AU +1DD6 ; [.1CAD.0020.0004][.1F49.0020.0004] # COMBINING LATIN SMALL LETTER AV +A739 ; [.1CAD.0020.0004][.1F49.0020.0004] # LATIN SMALL LETTER AV +A738 ; [.1CAD.0020.000A][.1F49.0020.000A] # LATIN CAPITAL LETTER AV +A73B ; [.1CAD.0020.0004][.0000.0111.0004][.1F49.0020.0004] # LATIN SMALL LETTER AV WITH HORIZONTAL BAR +A73A ; [.1CAD.0020.000A][.0000.0111.0004][.1F49.0020.000A] # LATIN CAPITAL LETTER AV WITH HORIZONTAL BAR +A73D ; [.1CAD.0020.0004][.1F71.0020.0004] # LATIN SMALL LETTER AY +A73C ; [.1CAD.0020.000A][.1F71.0020.000A] # LATIN CAPITAL LETTER AY +1E9A ; [.1CAD.0020.0004][.1FE6.0020.0004] # LATIN SMALL LETTER A WITH RIGHT HALF RING +1D00 ; [.1CB1.0020.0002] # LATIN LETTER SMALL CAPITAL A +2C65 ; [.1CB2.0020.0002] # LATIN SMALL LETTER A WITH STROKE +023A ; [.1CB2.0020.0008] # LATIN CAPITAL LETTER A WITH STROKE +1D8F ; [.1CB3.0020.0002] # LATIN SMALL LETTER A WITH RETROFLEX HOOK +1D01 ; [.1CB4.0020.0002] # LATIN LETTER SMALL CAPITAL AE +1D02 ; [.1CB5.0020.0002] # LATIN SMALL LETTER TURNED AE +1D46 ; [.1CB5.0020.0014] # MODIFIER LETTER SMALL TURNED AE +AB31 ; [.1CB6.0020.0002] # LATIN SMALL LETTER A REVERSED-SCHWA +0250 ; [.1CB7.0020.0002] # LATIN SMALL LETTER TURNED A +2C6F ; [.1CB7.0020.0008] # LATIN CAPITAL LETTER TURNED A +1D44 ; [.1CB7.0020.0014] # MODIFIER LETTER SMALL TURNED A +0251 ; [.1CBB.0020.0002] # LATIN SMALL LETTER ALPHA +1DE7 ; [.1CBB.0020.0004] # COMBINING LATIN SMALL LETTER ALPHA +2C6D ; [.1CBB.0020.0008] # LATIN CAPITAL LETTER ALPHA +1D45 ; [.1CBB.0020.0014] # MODIFIER LETTER SMALL ALPHA +AB30 ; [.1CBF.0020.0002] # LATIN SMALL LETTER BARRED ALPHA +1D90 ; [.1CC0.0020.0002] # LATIN SMALL LETTER ALPHA WITH RETROFLEX HOOK +0252 ; [.1CC1.0020.0002] # LATIN SMALL LETTER TURNED ALPHA +2C70 ; [.1CC1.0020.0008] # LATIN CAPITAL LETTER TURNED ALPHA +1D9B ; [.1CC1.0020.0014] # MODIFIER LETTER SMALL TURNED ALPHA +AB64 ; [.1CC5.0020.0002] # LATIN SMALL LETTER INVERTED ALPHA +0062 ; [.1CC6.0020.0002] # LATIN SMALL LETTER B +FF42 ; [.1CC6.0020.0003] # FULLWIDTH LATIN SMALL LETTER B +1DE8 ; [.1CC6.0020.0004] # COMBINING LATIN SMALL LETTER B +249D ; [*0318.0020.0004][.1CC6.0020.0004][*0319.0020.0004] # PARENTHESIZED LATIN SMALL LETTER B +1D41B ; [.1CC6.0020.0005] # MATHEMATICAL BOLD SMALL B +1D44F ; [.1CC6.0020.0005] # MATHEMATICAL ITALIC SMALL B +1D483 ; [.1CC6.0020.0005] # MATHEMATICAL BOLD ITALIC SMALL B +1D4B7 ; [.1CC6.0020.0005] # MATHEMATICAL SCRIPT SMALL B +1D4EB ; [.1CC6.0020.0005] # MATHEMATICAL BOLD SCRIPT SMALL B +1D51F ; [.1CC6.0020.0005] # MATHEMATICAL FRAKTUR SMALL B +1D553 ; [.1CC6.0020.0005] # MATHEMATICAL DOUBLE-STRUCK SMALL B +1D587 ; [.1CC6.0020.0005] # MATHEMATICAL BOLD FRAKTUR SMALL B +1D5BB ; [.1CC6.0020.0005] # MATHEMATICAL SANS-SERIF SMALL B +1D5EF ; [.1CC6.0020.0005] # MATHEMATICAL SANS-SERIF BOLD SMALL B +1D623 ; [.1CC6.0020.0005] # MATHEMATICAL SANS-SERIF ITALIC SMALL B +1D657 ; [.1CC6.0020.0005] # MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL B +1D68B ; [.1CC6.0020.0005] # MATHEMATICAL MONOSPACE SMALL B +24D1 ; [.1CC6.0020.0006] # CIRCLED LATIN SMALL LETTER B +0042 ; [.1CC6.0020.0008] # LATIN CAPITAL LETTER B +FF22 ; [.1CC6.0020.0009] # FULLWIDTH LATIN CAPITAL LETTER B +1F111 ; [*0318.0020.0004][.1CC6.0020.000A][*0319.0020.0004] # PARENTHESIZED LATIN CAPITAL LETTER B +212C ; [.1CC6.0020.000B] # SCRIPT CAPITAL B +1D401 ; [.1CC6.0020.000B] # MATHEMATICAL BOLD CAPITAL B +1D435 ; [.1CC6.0020.000B] # MATHEMATICAL ITALIC CAPITAL B +1D469 ; [.1CC6.0020.000B] # MATHEMATICAL BOLD ITALIC CAPITAL B +1D4D1 ; [.1CC6.0020.000B] # MATHEMATICAL BOLD SCRIPT CAPITAL B +1D505 ; [.1CC6.0020.000B] # MATHEMATICAL FRAKTUR CAPITAL B +1D539 ; [.1CC6.0020.000B] # MATHEMATICAL DOUBLE-STRUCK CAPITAL B +1D56D ; [.1CC6.0020.000B] # MATHEMATICAL BOLD FRAKTUR CAPITAL B +1D5A1 ; [.1CC6.0020.000B] # MATHEMATICAL SANS-SERIF CAPITAL B +1D5D5 ; [.1CC6.0020.000B] # MATHEMATICAL SANS-SERIF BOLD CAPITAL B +1D609 ; [.1CC6.0020.000B] # MATHEMATICAL SANS-SERIF ITALIC CAPITAL B +1D63D ; [.1CC6.0020.000B] # MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL B +1D671 ; [.1CC6.0020.000B] # MATHEMATICAL MONOSPACE CAPITAL B +24B7 ; [.1CC6.0020.000C] # CIRCLED LATIN CAPITAL LETTER B +1F151 ; [.1CC6.0020.000C] # NEGATIVE CIRCLED LATIN CAPITAL LETTER B +1D47 ; [.1CC6.0020.0014] # MODIFIER LETTER SMALL B +1D2E ; [.1CC6.0020.001D] # MODIFIER LETTER CAPITAL B +1F131 ; [.1CC6.0020.001D] # SQUARED LATIN CAPITAL LETTER B +1F171 ; [.1CC6.0020.001D] # NEGATIVE SQUARED LATIN CAPITAL LETTER B +1E03 ; [.1CC6.0020.0002][.0000.002E.0002] # LATIN SMALL LETTER B WITH DOT ABOVE +1E02 ; [.1CC6.0020.0008][.0000.002E.0002] # LATIN CAPITAL LETTER B WITH DOT ABOVE +1E05 ; [.1CC6.0020.0002][.0000.0042.0002] # LATIN SMALL LETTER B WITH DOT BELOW +1E04 ; [.1CC6.0020.0008][.0000.0042.0002] # LATIN CAPITAL LETTER B WITH DOT BELOW +1E07 ; [.1CC6.0020.0002][.0000.0049.0002] # LATIN SMALL LETTER B WITH LINE BELOW +1E06 ; [.1CC6.0020.0008][.0000.0049.0002] # LATIN CAPITAL LETTER B WITH LINE BELOW +3374 ; [.1CC6.0020.001C][.1CAD.0020.001C][.1E99.0020.001C] # SQUARE BAR +33C3 ; [.1CC6.0020.001D][.1E87.0020.001C] # SQUARE BQ +0299 ; [.1CCA.0020.0002] # LATIN LETTER SMALL CAPITAL B +0180 ; [.1CCE.0020.0002] # LATIN SMALL LETTER B WITH STROKE +0243 ; [.1CCE.0020.0008] # LATIN CAPITAL LETTER B WITH STROKE +1D2F ; [.1CD2.0020.0002] # MODIFIER LETTER CAPITAL BARRED B +1D03 ; [.1CD3.0020.0002] # LATIN LETTER SMALL CAPITAL BARRED B +1D6C ; [.1CD4.0020.0002] # LATIN SMALL LETTER B WITH MIDDLE TILDE +A797 ; [.1CD5.0020.0002] # LATIN SMALL LETTER B WITH FLOURISH +A796 ; [.1CD5.0020.0008] # LATIN CAPITAL LETTER B WITH FLOURISH +1D80 ; [.1CD6.0020.0002] # LATIN SMALL LETTER B WITH PALATAL HOOK +0253 ; [.1CD7.0020.0002] # LATIN SMALL LETTER B WITH HOOK +0181 ; [.1CD7.0020.0008] # LATIN CAPITAL LETTER B WITH HOOK +0183 ; [.1CDB.0020.0002] # LATIN SMALL LETTER B WITH TOPBAR +0182 ; [.1CDB.0020.0008] # LATIN CAPITAL LETTER B WITH TOPBAR +A7B5 ; [.1CDF.0020.0002] # LATIN SMALL LETTER BETA +1DE9 ; [.1CDF.0020.0004] # COMBINING LATIN SMALL LETTER BETA +A7B4 ; [.1CDF.0020.0008] # LATIN CAPITAL LETTER BETA +0063 ; [.1CE0.0020.0002] # LATIN SMALL LETTER C +FF43 ; [.1CE0.0020.0003] # FULLWIDTH LATIN SMALL LETTER C +0368 ; [.1CE0.0020.0004] # COMBINING LATIN SMALL LETTER C +217D ; [.1CE0.0020.0004] # SMALL ROMAN NUMERAL ONE HUNDRED +249E ; [*0318.0020.0004][.1CE0.0020.0004][*0319.0020.0004] # PARENTHESIZED LATIN SMALL LETTER C +1D41C ; [.1CE0.0020.0005] # MATHEMATICAL BOLD SMALL C +1D450 ; [.1CE0.0020.0005] # MATHEMATICAL ITALIC SMALL C +1D484 ; [.1CE0.0020.0005] # MATHEMATICAL BOLD ITALIC SMALL C +1D4B8 ; [.1CE0.0020.0005] # MATHEMATICAL SCRIPT SMALL C +1D4EC ; [.1CE0.0020.0005] # MATHEMATICAL BOLD SCRIPT SMALL C +1D520 ; [.1CE0.0020.0005] # MATHEMATICAL FRAKTUR SMALL C +1D554 ; [.1CE0.0020.0005] # MATHEMATICAL DOUBLE-STRUCK SMALL C +1D588 ; [.1CE0.0020.0005] # MATHEMATICAL BOLD FRAKTUR SMALL C +1D5BC ; [.1CE0.0020.0005] # MATHEMATICAL SANS-SERIF SMALL C +1D5F0 ; [.1CE0.0020.0005] # MATHEMATICAL SANS-SERIF BOLD SMALL C +1D624 ; [.1CE0.0020.0005] # MATHEMATICAL SANS-SERIF ITALIC SMALL C +1D658 ; [.1CE0.0020.0005] # MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL C +1D68C ; [.1CE0.0020.0005] # MATHEMATICAL MONOSPACE SMALL C +24D2 ; [.1CE0.0020.0006] # CIRCLED LATIN SMALL LETTER C +0043 ; [.1CE0.0020.0008] # LATIN CAPITAL LETTER C +FF23 ; [.1CE0.0020.0009] # FULLWIDTH LATIN CAPITAL LETTER C +2103 ; [*050C.0020.0004][.1CE0.0020.000A] # DEGREE CELSIUS +216D ; [.1CE0.0020.000A] # ROMAN NUMERAL ONE HUNDRED +1F112 ; [*0318.0020.0004][.1CE0.0020.000A][*0319.0020.0004] # PARENTHESIZED LATIN CAPITAL LETTER C +2102 ; [.1CE0.0020.000B] # DOUBLE-STRUCK CAPITAL C +212D ; [.1CE0.0020.000B] # BLACK-LETTER CAPITAL C +1D402 ; [.1CE0.0020.000B] # MATHEMATICAL BOLD CAPITAL C +1D436 ; [.1CE0.0020.000B] # MATHEMATICAL ITALIC CAPITAL C +1D46A ; [.1CE0.0020.000B] # MATHEMATICAL BOLD ITALIC CAPITAL C +1D49E ; [.1CE0.0020.000B] # MATHEMATICAL SCRIPT CAPITAL C +1D4D2 ; [.1CE0.0020.000B] # MATHEMATICAL BOLD SCRIPT CAPITAL C +1D56E ; [.1CE0.0020.000B] # MATHEMATICAL BOLD FRAKTUR CAPITAL C +1D5A2 ; [.1CE0.0020.000B] # MATHEMATICAL SANS-SERIF CAPITAL C +1D5D6 ; [.1CE0.0020.000B] # MATHEMATICAL SANS-SERIF BOLD CAPITAL C +1D60A ; [.1CE0.0020.000B] # MATHEMATICAL SANS-SERIF ITALIC CAPITAL C +1D63E ; [.1CE0.0020.000B] # MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL C +1D672 ; [.1CE0.0020.000B] # MATHEMATICAL MONOSPACE CAPITAL C +24B8 ; [.1CE0.0020.000C] # CIRCLED LATIN CAPITAL LETTER C +1F12B ; [.1CE0.0020.000C] # CIRCLED ITALIC LATIN CAPITAL LETTER C +1F152 ; [.1CE0.0020.000C] # NEGATIVE CIRCLED LATIN CAPITAL LETTER C +1D9C ; [.1CE0.0020.0014] # MODIFIER LETTER SMALL C +1F132 ; [.1CE0.0020.001D] # SQUARED LATIN CAPITAL LETTER C +1F172 ; [.1CE0.0020.001D] # NEGATIVE SQUARED LATIN CAPITAL LETTER C +0107 ; [.1CE0.0020.0002][.0000.0024.0002] # LATIN SMALL LETTER C WITH ACUTE +0106 ; [.1CE0.0020.0008][.0000.0024.0002] # LATIN CAPITAL LETTER C WITH ACUTE +0109 ; [.1CE0.0020.0002][.0000.0027.0002] # LATIN SMALL LETTER C WITH CIRCUMFLEX +0108 ; [.1CE0.0020.0008][.0000.0027.0002] # LATIN CAPITAL LETTER C WITH CIRCUMFLEX +010D ; [.1CE0.0020.0002][.0000.0028.0002] # LATIN SMALL LETTER C WITH CARON +010C ; [.1CE0.0020.0008][.0000.0028.0002] # LATIN CAPITAL LETTER C WITH CARON +010B ; [.1CE0.0020.0002][.0000.002E.0002] # LATIN SMALL LETTER C WITH DOT ABOVE +010A ; [.1CE0.0020.0008][.0000.002E.0002] # LATIN CAPITAL LETTER C WITH DOT ABOVE +00E7 ; [.1CE0.0020.0002][.0000.0030.0002] # LATIN SMALL LETTER C WITH CEDILLA +1DD7 ; [.1CE0.0020.0004][.0000.0030.0004] # COMBINING LATIN SMALL LETTER C CEDILLA +00C7 ; [.1CE0.0020.0008][.0000.0030.0002] # LATIN CAPITAL LETTER C WITH CEDILLA +1E09 ; [.1CE0.0020.0002][.0000.0030.0002][.0000.0024.0002] # LATIN SMALL LETTER C WITH CEDILLA AND ACUTE +1E08 ; [.1CE0.0020.0008][.0000.0030.0002][.0000.0024.0002] # LATIN CAPITAL LETTER C WITH CEDILLA AND ACUTE +3388 ; [.1CE0.0020.001C][.1CAD.0020.001C][.1DDD.0020.001C] # SQUARE CAL +33C4 ; [.1CE0.0020.001C][.1CE0.0020.001C] # SQUARE CC +1F12D ; [.1CE0.0020.000C][.1CF5.0020.000C] # CIRCLED CD +33C5 ; [.1CE0.0020.001C][.1CF5.0020.001C] # SQUARE CD +33C6 ; [.1CE0.0020.001D][*063B.0020.001C][.1DCB.0020.001C][.1D5A.0020.001C] # SQUARE C OVER KG +1F191 ; [.1CE0.0020.001D][.1DDD.0020.001D] # SQUARED CL +339D ; [.1CE0.0020.001C][.1E10.0020.001C] # SQUARE CM +33A0 ; [.1CE0.0020.001C][.1E10.0020.001C][.1CA5.0020.001C] # SQUARE CM SQUARED +33A4 ; [.1CE0.0020.001C][.1E10.0020.001C][.1CA6.0020.001C] # SQUARE CM CUBED +2105 ; [.1CE0.0020.0004][*0395.0020.0004][.1E43.0020.0004] # CARE OF +33C7 ; [.1CE0.0020.001D][.1E43.0020.001C][*0278.0020.001C] # SQUARE CO +1F192 ; [.1CE0.0020.001D][.1E43.0020.001D][.1E43.0020.001D][.1DDD.0020.001D] # SQUARED COOL +2106 ; [.1CE0.0020.0004][*0395.0020.0004][.1F1B.0020.0004] # CADA UNA +1D04 ; [.1CE4.0020.0002] # LATIN LETTER SMALL CAPITAL C +023C ; [.1CE5.0020.0002] # LATIN SMALL LETTER C WITH STROKE +023B ; [.1CE5.0020.0008] # LATIN CAPITAL LETTER C WITH STROKE +A793 ; [.1CE9.0020.0002] # LATIN SMALL LETTER C WITH BAR +A792 ; [.1CE9.0020.0008] # LATIN CAPITAL LETTER C WITH BAR +A794 ; [.1CEA.0020.0002] # LATIN SMALL LETTER C WITH PALATAL HOOK +0188 ; [.1CEB.0020.0002] # LATIN SMALL LETTER C WITH HOOK +0187 ; [.1CEB.0020.0008] # LATIN CAPITAL LETTER C WITH HOOK +0255 ; [.1CEF.0020.0002] # LATIN SMALL LETTER C WITH CURL +1D9D ; [.1CEF.0020.0014] # MODIFIER LETTER SMALL C WITH CURL +2184 ; [.1CF3.0020.0002] # LATIN SMALL LETTER REVERSED C +2183 ; [.1CF3.0020.0008] # ROMAN NUMERAL REVERSED ONE HUNDRED +A73F ; [.1CF4.0020.0002] # LATIN SMALL LETTER REVERSED C WITH DOT +A73E ; [.1CF4.0020.0008] # LATIN CAPITAL LETTER REVERSED C WITH DOT +0064 ; [.1CF5.0020.0002] # LATIN SMALL LETTER D +FF44 ; [.1CF5.0020.0003] # FULLWIDTH LATIN SMALL LETTER D +0369 ; [.1CF5.0020.0004] # COMBINING LATIN SMALL LETTER D +217E ; [.1CF5.0020.0004] # SMALL ROMAN NUMERAL FIVE HUNDRED +249F ; [*0318.0020.0004][.1CF5.0020.0004][*0319.0020.0004] # PARENTHESIZED LATIN SMALL LETTER D +2146 ; [.1CF5.0020.0005] # DOUBLE-STRUCK ITALIC SMALL D +1D41D ; [.1CF5.0020.0005] # MATHEMATICAL BOLD SMALL D +1D451 ; [.1CF5.0020.0005] # MATHEMATICAL ITALIC SMALL D +1D485 ; [.1CF5.0020.0005] # MATHEMATICAL BOLD ITALIC SMALL D +1D4B9 ; [.1CF5.0020.0005] # MATHEMATICAL SCRIPT SMALL D +1D4ED ; [.1CF5.0020.0005] # MATHEMATICAL BOLD SCRIPT SMALL D +1D521 ; [.1CF5.0020.0005] # MATHEMATICAL FRAKTUR SMALL D +1D555 ; [.1CF5.0020.0005] # MATHEMATICAL DOUBLE-STRUCK SMALL D +1D589 ; [.1CF5.0020.0005] # MATHEMATICAL BOLD FRAKTUR SMALL D +1D5BD ; [.1CF5.0020.0005] # MATHEMATICAL SANS-SERIF SMALL D +1D5F1 ; [.1CF5.0020.0005] # MATHEMATICAL SANS-SERIF BOLD SMALL D +1D625 ; [.1CF5.0020.0005] # MATHEMATICAL SANS-SERIF ITALIC SMALL D +1D659 ; [.1CF5.0020.0005] # MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL D +1D68D ; [.1CF5.0020.0005] # MATHEMATICAL MONOSPACE SMALL D +24D3 ; [.1CF5.0020.0006] # CIRCLED LATIN SMALL LETTER D +0044 ; [.1CF5.0020.0008] # LATIN CAPITAL LETTER D +FF24 ; [.1CF5.0020.0009] # FULLWIDTH LATIN CAPITAL LETTER D +216E ; [.1CF5.0020.000A] # ROMAN NUMERAL FIVE HUNDRED +1F113 ; [*0318.0020.0004][.1CF5.0020.000A][*0319.0020.0004] # PARENTHESIZED LATIN CAPITAL LETTER D +2145 ; [.1CF5.0020.000B] # DOUBLE-STRUCK ITALIC CAPITAL D +1D403 ; [.1CF5.0020.000B] # MATHEMATICAL BOLD CAPITAL D +1D437 ; [.1CF5.0020.000B] # MATHEMATICAL ITALIC CAPITAL D +1D46B ; [.1CF5.0020.000B] # MATHEMATICAL BOLD ITALIC CAPITAL D +1D49F ; [.1CF5.0020.000B] # MATHEMATICAL SCRIPT CAPITAL D +1D4D3 ; [.1CF5.0020.000B] # MATHEMATICAL BOLD SCRIPT CAPITAL D +1D507 ; [.1CF5.0020.000B] # MATHEMATICAL FRAKTUR CAPITAL D +1D53B ; [.1CF5.0020.000B] # MATHEMATICAL DOUBLE-STRUCK CAPITAL D +1D56F ; [.1CF5.0020.000B] # MATHEMATICAL BOLD FRAKTUR CAPITAL D +1D5A3 ; [.1CF5.0020.000B] # MATHEMATICAL SANS-SERIF CAPITAL D +1D5D7 ; [.1CF5.0020.000B] # MATHEMATICAL SANS-SERIF BOLD CAPITAL D +1D60B ; [.1CF5.0020.000B] # MATHEMATICAL SANS-SERIF ITALIC CAPITAL D +1D63F ; [.1CF5.0020.000B] # MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL D +1D673 ; [.1CF5.0020.000B] # MATHEMATICAL MONOSPACE CAPITAL D +24B9 ; [.1CF5.0020.000C] # CIRCLED LATIN CAPITAL LETTER D +1F153 ; [.1CF5.0020.000C] # NEGATIVE CIRCLED LATIN CAPITAL LETTER D +1D48 ; [.1CF5.0020.0014] # MODIFIER LETTER SMALL D +1F1A5 ; [.1CF5.0020.001C] # SQUARED LATIN SMALL LETTER D +1D30 ; [.1CF5.0020.001D] # MODIFIER LETTER CAPITAL D +1F133 ; [.1CF5.0020.001D] # SQUARED LATIN CAPITAL LETTER D +1F173 ; [.1CF5.0020.001D] # NEGATIVE SQUARED LATIN CAPITAL LETTER D +010F ; [.1CF5.0020.0002][.0000.0028.0002] # LATIN SMALL LETTER D WITH CARON +010E ; [.1CF5.0020.0008][.0000.0028.0002] # LATIN CAPITAL LETTER D WITH CARON +1E0B ; [.1CF5.0020.0002][.0000.002E.0002] # LATIN SMALL LETTER D WITH DOT ABOVE +1E0A ; [.1CF5.0020.0008][.0000.002E.0002] # LATIN CAPITAL LETTER D WITH DOT ABOVE +1E11 ; [.1CF5.0020.0002][.0000.0030.0002] # LATIN SMALL LETTER D WITH CEDILLA +1E10 ; [.1CF5.0020.0008][.0000.0030.0002] # LATIN CAPITAL LETTER D WITH CEDILLA +0111 ; [.1CF5.0020.0002][.0000.0039.0002] # LATIN SMALL LETTER D WITH STROKE +0110 ; [.1CF5.0020.0008][.0000.0039.0002] # LATIN CAPITAL LETTER D WITH STROKE +1E0D ; [.1CF5.0020.0002][.0000.0042.0002] # LATIN SMALL LETTER D WITH DOT BELOW +1E0C ; [.1CF5.0020.0008][.0000.0042.0002] # LATIN CAPITAL LETTER D WITH DOT BELOW +1E13 ; [.1CF5.0020.0002][.0000.0046.0002] # LATIN SMALL LETTER D WITH CIRCUMFLEX BELOW +1E12 ; [.1CF5.0020.0008][.0000.0046.0002] # LATIN CAPITAL LETTER D WITH CIRCUMFLEX BELOW +1E0F ; [.1CF5.0020.0002][.0000.0049.0002] # LATIN SMALL LETTER D WITH LINE BELOW +1E0E ; [.1CF5.0020.0008][.0000.0049.0002] # LATIN CAPITAL LETTER D WITH LINE BELOW +00F0 ; [.1CF5.0020.0004][.0000.0111.0004] # LATIN SMALL LETTER ETH +1DD9 ; [.1CF5.0020.0004][.0000.0111.0004] # COMBINING LATIN SMALL LETTER ETH +00D0 ; [.1CF5.0020.000A][.0000.0111.0004] # LATIN CAPITAL LETTER ETH +1D9E ; [.1CF5.0020.0014][.0000.0111.0014] # MODIFIER LETTER SMALL ETH +1DD8 ; [.1CF5.0020.0004][.0000.0112.0004] # COMBINING LATIN SMALL LETTER INSULAR D +A77A ; [.1CF5.0020.0004][.0000.0112.0004] # LATIN SMALL LETTER INSULAR D +A779 ; [.1CF5.0020.000A][.0000.0112.0004] # LATIN CAPITAL LETTER INSULAR D +3372 ; [.1CF5.0020.001C][.1CAD.0020.001C] # SQUARE DA +0238 ; [.1CF5.0020.0004][.1CC6.0020.0004] # LATIN SMALL LETTER DB DIGRAPH +33C8 ; [.1CF5.0020.001C][.1CC6.0020.001D] # SQUARE DB +1F190 ; [.1CF5.0020.001D][.1DB2.0020.001D] # SQUARE DJ +3397 ; [.1CF5.0020.001C][.1DDD.0020.001C] # SQUARE DL +3377 ; [.1CF5.0020.001C][.1E10.0020.001C] # SQUARE DM +3378 ; [.1CF5.0020.001C][.1E10.0020.001C][.1CA5.0020.001C] # SQUARE DM SQUARED +3379 ; [.1CF5.0020.001C][.1E10.0020.001C][.1CA6.0020.001C] # SQUARE DM CUBED +01F3 ; [.1CF5.0020.0004][.1F87.0020.0004] # LATIN SMALL LETTER DZ +02A3 ; [.1CF5.0020.0004][.1F87.0020.0004] # LATIN SMALL LETTER DZ DIGRAPH +01F2 ; [.1CF5.0020.000A][.1F87.0020.0004] # LATIN CAPITAL LETTER D WITH SMALL LETTER Z +01F1 ; [.1CF5.0020.000A][.1F87.0020.000A] # LATIN CAPITAL LETTER DZ +01C6 ; [.1CF5.0020.0004][.1F87.0020.0004][.0000.0028.0004] # LATIN SMALL LETTER DZ WITH CARON +01C5 ; [.1CF5.0020.000A][.1F87.0020.0004][.0000.0028.0004] # LATIN CAPITAL LETTER D WITH SMALL LETTER Z WITH CARON +01C4 ; [.1CF5.0020.000A][.1F87.0020.000A][.0000.0028.0004] # LATIN CAPITAL LETTER DZ WITH CARON +02A5 ; [.1CF5.0020.0004][.1F9A.0020.0004] # LATIN SMALL LETTER DZ DIGRAPH WITH CURL +02A4 ; [.1CF5.0020.0004][.1FA4.0020.0004] # LATIN SMALL LETTER DEZH DIGRAPH +1D05 ; [.1CF9.0020.0002] # LATIN LETTER SMALL CAPITAL D +1D06 ; [.1CFA.0020.0002] # LATIN LETTER SMALL CAPITAL ETH +1D6D ; [.1CFB.0020.0002] # LATIN SMALL LETTER D WITH MIDDLE TILDE +1D81 ; [.1CFC.0020.0002] # LATIN SMALL LETTER D WITH PALATAL HOOK +0256 ; [.1CFD.0020.0002] # LATIN SMALL LETTER D WITH TAIL +0189 ; [.1CFD.0020.0008] # LATIN CAPITAL LETTER AFRICAN D +0257 ; [.1D01.0020.0002] # LATIN SMALL LETTER D WITH HOOK +018A ; [.1D01.0020.0008] # LATIN CAPITAL LETTER D WITH HOOK +1D91 ; [.1D05.0020.0002] # LATIN SMALL LETTER D WITH HOOK AND TAIL +018C ; [.1D06.0020.0002] # LATIN SMALL LETTER D WITH TOPBAR +018B ; [.1D06.0020.0008] # LATIN CAPITAL LETTER D WITH TOPBAR +0221 ; [.1D0A.0020.0002] # LATIN SMALL LETTER D WITH CURL +A771 ; [.1D0E.0020.0002] # LATIN SMALL LETTER DUM +1E9F ; [.1D0F.0020.0002] # LATIN SMALL LETTER DELTA +0065 ; [.1D10.0020.0002] # LATIN SMALL LETTER E +FF45 ; [.1D10.0020.0003] # FULLWIDTH LATIN SMALL LETTER E +0364 ; [.1D10.0020.0004] # COMBINING LATIN SMALL LETTER E +24A0 ; [*0318.0020.0004][.1D10.0020.0004][*0319.0020.0004] # PARENTHESIZED LATIN SMALL LETTER E +212F ; [.1D10.0020.0005] # SCRIPT SMALL E +2147 ; [.1D10.0020.0005] # DOUBLE-STRUCK ITALIC SMALL E +1D41E ; [.1D10.0020.0005] # MATHEMATICAL BOLD SMALL E +1D452 ; [.1D10.0020.0005] # MATHEMATICAL ITALIC SMALL E +1D486 ; [.1D10.0020.0005] # MATHEMATICAL BOLD ITALIC SMALL E +1D4EE ; [.1D10.0020.0005] # MATHEMATICAL BOLD SCRIPT SMALL E +1D522 ; [.1D10.0020.0005] # MATHEMATICAL FRAKTUR SMALL E +1D556 ; [.1D10.0020.0005] # MATHEMATICAL DOUBLE-STRUCK SMALL E +1D58A ; [.1D10.0020.0005] # MATHEMATICAL BOLD FRAKTUR SMALL E +1D5BE ; [.1D10.0020.0005] # MATHEMATICAL SANS-SERIF SMALL E +1D5F2 ; [.1D10.0020.0005] # MATHEMATICAL SANS-SERIF BOLD SMALL E +1D626 ; [.1D10.0020.0005] # MATHEMATICAL SANS-SERIF ITALIC SMALL E +1D65A ; [.1D10.0020.0005] # MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL E +1D68E ; [.1D10.0020.0005] # MATHEMATICAL MONOSPACE SMALL E +24D4 ; [.1D10.0020.0006] # CIRCLED LATIN SMALL LETTER E +0045 ; [.1D10.0020.0008] # LATIN CAPITAL LETTER E +FF25 ; [.1D10.0020.0009] # FULLWIDTH LATIN CAPITAL LETTER E +1F114 ; [*0318.0020.0004][.1D10.0020.000A][*0319.0020.0004] # PARENTHESIZED LATIN CAPITAL LETTER E +2130 ; [.1D10.0020.000B] # SCRIPT CAPITAL E +1D404 ; [.1D10.0020.000B] # MATHEMATICAL BOLD CAPITAL E +1D438 ; [.1D10.0020.000B] # MATHEMATICAL ITALIC CAPITAL E +1D46C ; [.1D10.0020.000B] # MATHEMATICAL BOLD ITALIC CAPITAL E +1D4D4 ; [.1D10.0020.000B] # MATHEMATICAL BOLD SCRIPT CAPITAL E +1D508 ; [.1D10.0020.000B] # MATHEMATICAL FRAKTUR CAPITAL E +1D53C ; [.1D10.0020.000B] # MATHEMATICAL DOUBLE-STRUCK CAPITAL E +1D570 ; [.1D10.0020.000B] # MATHEMATICAL BOLD FRAKTUR CAPITAL E +1D5A4 ; [.1D10.0020.000B] # MATHEMATICAL SANS-SERIF CAPITAL E +1D5D8 ; [.1D10.0020.000B] # MATHEMATICAL SANS-SERIF BOLD CAPITAL E +1D60C ; [.1D10.0020.000B] # MATHEMATICAL SANS-SERIF ITALIC CAPITAL E +1D640 ; [.1D10.0020.000B] # MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL E +1D674 ; [.1D10.0020.000B] # MATHEMATICAL MONOSPACE CAPITAL E +24BA ; [.1D10.0020.000C] # CIRCLED LATIN CAPITAL LETTER E +1F154 ; [.1D10.0020.000C] # NEGATIVE CIRCLED LATIN CAPITAL LETTER E +1D49 ; [.1D10.0020.0014] # MODIFIER LETTER SMALL E +2091 ; [.1D10.0020.0015] # LATIN SUBSCRIPT SMALL LETTER E +1D31 ; [.1D10.0020.001D] # MODIFIER LETTER CAPITAL E +1F134 ; [.1D10.0020.001D] # SQUARED LATIN CAPITAL LETTER E +1F174 ; [.1D10.0020.001D] # NEGATIVE SQUARED LATIN CAPITAL LETTER E +00E9 ; [.1D10.0020.0002][.0000.0024.0002] # LATIN SMALL LETTER E WITH ACUTE +00C9 ; [.1D10.0020.0008][.0000.0024.0002] # LATIN CAPITAL LETTER E WITH ACUTE +00E8 ; [.1D10.0020.0002][.0000.0025.0002] # LATIN SMALL LETTER E WITH GRAVE +00C8 ; [.1D10.0020.0008][.0000.0025.0002] # LATIN CAPITAL LETTER E WITH GRAVE +0115 ; [.1D10.0020.0002][.0000.0026.0002] # LATIN SMALL LETTER E WITH BREVE +0114 ; [.1D10.0020.0008][.0000.0026.0002] # LATIN CAPITAL LETTER E WITH BREVE +00EA ; [.1D10.0020.0002][.0000.0027.0002] # LATIN SMALL LETTER E WITH CIRCUMFLEX +00CA ; [.1D10.0020.0008][.0000.0027.0002] # LATIN CAPITAL LETTER E WITH CIRCUMFLEX +1EBF ; [.1D10.0020.0002][.0000.0027.0002][.0000.0024.0002] # LATIN SMALL LETTER E WITH CIRCUMFLEX AND ACUTE +1EBE ; [.1D10.0020.0008][.0000.0027.0002][.0000.0024.0002] # LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND ACUTE +1EC1 ; [.1D10.0020.0002][.0000.0027.0002][.0000.0025.0002] # LATIN SMALL LETTER E WITH CIRCUMFLEX AND GRAVE +1EC0 ; [.1D10.0020.0008][.0000.0027.0002][.0000.0025.0002] # LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND GRAVE +1EC5 ; [.1D10.0020.0002][.0000.0027.0002][.0000.002D.0002] # LATIN SMALL LETTER E WITH CIRCUMFLEX AND TILDE +1EC4 ; [.1D10.0020.0008][.0000.0027.0002][.0000.002D.0002] # LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND TILDE +1EC3 ; [.1D10.0020.0002][.0000.0027.0002][.0000.003B.0002] # LATIN SMALL LETTER E WITH CIRCUMFLEX AND HOOK ABOVE +1EC2 ; [.1D10.0020.0008][.0000.0027.0002][.0000.003B.0002] # LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND HOOK ABOVE +011B ; [.1D10.0020.0002][.0000.0028.0002] # LATIN SMALL LETTER E WITH CARON +011A ; [.1D10.0020.0008][.0000.0028.0002] # LATIN CAPITAL LETTER E WITH CARON +00EB ; [.1D10.0020.0002][.0000.002B.0002] # LATIN SMALL LETTER E WITH DIAERESIS +00CB ; [.1D10.0020.0008][.0000.002B.0002] # LATIN CAPITAL LETTER E WITH DIAERESIS +1EBD ; [.1D10.0020.0002][.0000.002D.0002] # LATIN SMALL LETTER E WITH TILDE +1EBC ; [.1D10.0020.0008][.0000.002D.0002] # LATIN CAPITAL LETTER E WITH TILDE +0117 ; [.1D10.0020.0002][.0000.002E.0002] # LATIN SMALL LETTER E WITH DOT ABOVE +0116 ; [.1D10.0020.0008][.0000.002E.0002] # LATIN CAPITAL LETTER E WITH DOT ABOVE +0229 ; [.1D10.0020.0002][.0000.0030.0002] # LATIN SMALL LETTER E WITH CEDILLA +0228 ; [.1D10.0020.0008][.0000.0030.0002] # LATIN CAPITAL LETTER E WITH CEDILLA +1E1D ; [.1D10.0020.0002][.0000.0030.0002][.0000.0026.0002] # LATIN SMALL LETTER E WITH CEDILLA AND BREVE +1E1C ; [.1D10.0020.0008][.0000.0030.0002][.0000.0026.0002] # LATIN CAPITAL LETTER E WITH CEDILLA AND BREVE +0119 ; [.1D10.0020.0002][.0000.0031.0002] # LATIN SMALL LETTER E WITH OGONEK +0118 ; [.1D10.0020.0008][.0000.0031.0002] # LATIN CAPITAL LETTER E WITH OGONEK +0113 ; [.1D10.0020.0002][.0000.0032.0002] # LATIN SMALL LETTER E WITH MACRON +0112 ; [.1D10.0020.0008][.0000.0032.0002] # LATIN CAPITAL LETTER E WITH MACRON +1E17 ; [.1D10.0020.0002][.0000.0032.0002][.0000.0024.0002] # LATIN SMALL LETTER E WITH MACRON AND ACUTE +1E16 ; [.1D10.0020.0008][.0000.0032.0002][.0000.0024.0002] # LATIN CAPITAL LETTER E WITH MACRON AND ACUTE +1E15 ; [.1D10.0020.0002][.0000.0032.0002][.0000.0025.0002] # LATIN SMALL LETTER E WITH MACRON AND GRAVE +1E14 ; [.1D10.0020.0008][.0000.0032.0002][.0000.0025.0002] # LATIN CAPITAL LETTER E WITH MACRON AND GRAVE +1EBB ; [.1D10.0020.0002][.0000.003B.0002] # LATIN SMALL LETTER E WITH HOOK ABOVE +1EBA ; [.1D10.0020.0008][.0000.003B.0002] # LATIN CAPITAL LETTER E WITH HOOK ABOVE +0205 ; [.1D10.0020.0002][.0000.003C.0002] # LATIN SMALL LETTER E WITH DOUBLE GRAVE +0204 ; [.1D10.0020.0008][.0000.003C.0002] # LATIN CAPITAL LETTER E WITH DOUBLE GRAVE +0207 ; [.1D10.0020.0002][.0000.003E.0002] # LATIN SMALL LETTER E WITH INVERTED BREVE +0206 ; [.1D10.0020.0008][.0000.003E.0002] # LATIN CAPITAL LETTER E WITH INVERTED BREVE +1EB9 ; [.1D10.0020.0002][.0000.0042.0002] # LATIN SMALL LETTER E WITH DOT BELOW +1EB8 ; [.1D10.0020.0008][.0000.0042.0002] # LATIN CAPITAL LETTER E WITH DOT BELOW +1EC7 ; [.1D10.0020.0002][.0000.0042.0002][.0000.0027.0002] # LATIN SMALL LETTER E WITH CIRCUMFLEX AND DOT BELOW +1EC6 ; [.1D10.0020.0008][.0000.0042.0002][.0000.0027.0002] # LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND DOT BELOW +1E19 ; [.1D10.0020.0002][.0000.0046.0002] # LATIN SMALL LETTER E WITH CIRCUMFLEX BELOW +1E18 ; [.1D10.0020.0008][.0000.0046.0002] # LATIN CAPITAL LETTER E WITH CIRCUMFLEX BELOW +1E1B ; [.1D10.0020.0002][.0000.0048.0002] # LATIN SMALL LETTER E WITH TILDE BELOW +1E1A ; [.1D10.0020.0008][.0000.0048.0002] # LATIN CAPITAL LETTER E WITH TILDE BELOW +32CD ; [.1D10.0020.001C][.1E99.0020.001C][.1D5A.0020.001C] # SQUARE ERG +32CE ; [.1D10.0020.001C][.1F49.0020.001D] # SQUARE EV +1D07 ; [.1D14.0020.0002] # LATIN LETTER SMALL CAPITAL E +AB32 ; [.1D15.0020.0002] # LATIN SMALL LETTER BLACKLETTER E +AB33 ; [.1D16.0020.0002] # LATIN SMALL LETTER BARRED E +0247 ; [.1D17.0020.0002] # LATIN SMALL LETTER E WITH STROKE +0246 ; [.1D17.0020.0008] # LATIN CAPITAL LETTER E WITH STROKE +1D92 ; [.1D1B.0020.0002] # LATIN SMALL LETTER E WITH RETROFLEX HOOK +AB34 ; [.1D1C.0020.0002] # LATIN SMALL LETTER E WITH FLOURISH +2C78 ; [.1D1D.0020.0002] # LATIN SMALL LETTER E WITH NOTCH +01DD ; [.1D1E.0020.0002] # LATIN SMALL LETTER TURNED E +018E ; [.1D1E.0020.0008] # LATIN CAPITAL LETTER REVERSED E +1D32 ; [.1D1E.0020.001D] # MODIFIER LETTER CAPITAL REVERSED E +2C7B ; [.1D22.0020.0002] # LATIN LETTER SMALL CAPITAL TURNED E +0259 ; [.1D23.0020.0002] # LATIN SMALL LETTER SCHWA +1DEA ; [.1D23.0020.0004] # COMBINING LATIN SMALL LETTER SCHWA +018F ; [.1D23.0020.0008] # LATIN CAPITAL LETTER SCHWA +1D4A ; [.1D23.0020.0014] # MODIFIER LETTER SMALL SCHWA +2094 ; [.1D23.0020.0015] # LATIN SUBSCRIPT SMALL LETTER SCHWA +1D95 ; [.1D27.0020.0002] # LATIN SMALL LETTER SCHWA WITH RETROFLEX HOOK +025B ; [.1D28.0020.0002] # LATIN SMALL LETTER OPEN E +0190 ; [.1D28.0020.0008] # LATIN CAPITAL LETTER OPEN E +2107 ; [.1D28.0020.000A] # EULER CONSTANT +1D4B ; [.1D28.0020.0014] # MODIFIER LETTER SMALL OPEN E +1D93 ; [.1D2C.0020.0002] # LATIN SMALL LETTER OPEN E WITH RETROFLEX HOOK +0258 ; [.1D2D.0020.0002] # LATIN SMALL LETTER REVERSED E +025A ; [.1D31.0020.0002] # LATIN SMALL LETTER SCHWA WITH HOOK +025C ; [.1D35.0020.0002] # LATIN SMALL LETTER REVERSED OPEN E +A7AB ; [.1D35.0020.0008] # LATIN CAPITAL LETTER REVERSED OPEN E +1D9F ; [.1D35.0020.0014] # MODIFIER LETTER SMALL REVERSED OPEN E +1D94 ; [.1D39.0020.0002] # LATIN SMALL LETTER REVERSED OPEN E WITH RETROFLEX HOOK +1D08 ; [.1D3A.0020.0002] # LATIN SMALL LETTER TURNED OPEN E +1D4C ; [.1D3A.0020.0014] # MODIFIER LETTER SMALL TURNED OPEN E +025D ; [.1D3B.0020.0002] # LATIN SMALL LETTER REVERSED OPEN E WITH HOOK +025E ; [.1D3F.0020.0002] # LATIN SMALL LETTER CLOSED REVERSED OPEN E +029A ; [.1D43.0020.0002] # LATIN SMALL LETTER CLOSED OPEN E +0264 ; [.1D47.0020.0002] # LATIN SMALL LETTER RAMS HORN +0066 ; [.1D4B.0020.0002] # LATIN SMALL LETTER F +FF46 ; [.1D4B.0020.0003] # FULLWIDTH LATIN SMALL LETTER F +1DEB ; [.1D4B.0020.0004] # COMBINING LATIN SMALL LETTER F +24A1 ; [*0318.0020.0004][.1D4B.0020.0004][*0319.0020.0004] # PARENTHESIZED LATIN SMALL LETTER F +1D41F ; [.1D4B.0020.0005] # MATHEMATICAL BOLD SMALL F +1D453 ; [.1D4B.0020.0005] # MATHEMATICAL ITALIC SMALL F +1D487 ; [.1D4B.0020.0005] # MATHEMATICAL BOLD ITALIC SMALL F +1D4BB ; [.1D4B.0020.0005] # MATHEMATICAL SCRIPT SMALL F +1D4EF ; [.1D4B.0020.0005] # MATHEMATICAL BOLD SCRIPT SMALL F +1D523 ; [.1D4B.0020.0005] # MATHEMATICAL FRAKTUR SMALL F +1D557 ; [.1D4B.0020.0005] # MATHEMATICAL DOUBLE-STRUCK SMALL F +1D58B ; [.1D4B.0020.0005] # MATHEMATICAL BOLD FRAKTUR SMALL F +1D5BF ; [.1D4B.0020.0005] # MATHEMATICAL SANS-SERIF SMALL F +1D5F3 ; [.1D4B.0020.0005] # MATHEMATICAL SANS-SERIF BOLD SMALL F +1D627 ; [.1D4B.0020.0005] # MATHEMATICAL SANS-SERIF ITALIC SMALL F +1D65B ; [.1D4B.0020.0005] # MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL F +1D68F ; [.1D4B.0020.0005] # MATHEMATICAL MONOSPACE SMALL F +24D5 ; [.1D4B.0020.0006] # CIRCLED LATIN SMALL LETTER F +0046 ; [.1D4B.0020.0008] # LATIN CAPITAL LETTER F +FF26 ; [.1D4B.0020.0009] # FULLWIDTH LATIN CAPITAL LETTER F +2109 ; [*050C.0020.0004][.1D4B.0020.000A] # DEGREE FAHRENHEIT +1F115 ; [*0318.0020.0004][.1D4B.0020.000A][*0319.0020.0004] # PARENTHESIZED LATIN CAPITAL LETTER F +2131 ; [.1D4B.0020.000B] # SCRIPT CAPITAL F +1D405 ; [.1D4B.0020.000B] # MATHEMATICAL BOLD CAPITAL F +1D439 ; [.1D4B.0020.000B] # MATHEMATICAL ITALIC CAPITAL F +1D46D ; [.1D4B.0020.000B] # MATHEMATICAL BOLD ITALIC CAPITAL F +1D4D5 ; [.1D4B.0020.000B] # MATHEMATICAL BOLD SCRIPT CAPITAL F +1D509 ; [.1D4B.0020.000B] # MATHEMATICAL FRAKTUR CAPITAL F +1D53D ; [.1D4B.0020.000B] # MATHEMATICAL DOUBLE-STRUCK CAPITAL F +1D571 ; [.1D4B.0020.000B] # MATHEMATICAL BOLD FRAKTUR CAPITAL F +1D5A5 ; [.1D4B.0020.000B] # MATHEMATICAL SANS-SERIF CAPITAL F +1D5D9 ; [.1D4B.0020.000B] # MATHEMATICAL SANS-SERIF BOLD CAPITAL F +1D60D ; [.1D4B.0020.000B] # MATHEMATICAL SANS-SERIF ITALIC CAPITAL F +1D641 ; [.1D4B.0020.000B] # MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL F +1D675 ; [.1D4B.0020.000B] # MATHEMATICAL MONOSPACE CAPITAL F +24BB ; [.1D4B.0020.000C] # CIRCLED LATIN CAPITAL LETTER F +1F155 ; [.1D4B.0020.000C] # NEGATIVE CIRCLED LATIN CAPITAL LETTER F +1DA0 ; [.1D4B.0020.0014] # MODIFIER LETTER SMALL F +1F135 ; [.1D4B.0020.001D] # SQUARED LATIN CAPITAL LETTER F +1F175 ; [.1D4B.0020.001D] # NEGATIVE SQUARED LATIN CAPITAL LETTER F +1E1F ; [.1D4B.0020.0002][.0000.002E.0002] # LATIN SMALL LETTER F WITH DOT ABOVE +1E1E ; [.1D4B.0020.0008][.0000.002E.0002] # LATIN CAPITAL LETTER F WITH DOT ABOVE +A77C ; [.1D4B.0020.0004][.0000.0112.0004] # LATIN SMALL LETTER INSULAR F +A77B ; [.1D4B.0020.000A][.0000.0112.0004] # LATIN CAPITAL LETTER INSULAR F +213B ; [.1D4B.0020.000A][.1CAD.0020.000A][.1F65.0020.000A] # FACSIMILE SIGN +FB00 ; [.1D4B.0020.0004][.1D4B.0020.0004] # LATIN SMALL LIGATURE FF +FB03 ; [.1D4B.0020.0004][.1D4B.0020.0004][.1D98.0020.0004] # LATIN SMALL LIGATURE FFI +FB04 ; [.1D4B.0020.0004][.1D4B.0020.0004][.1DDD.0020.0004] # LATIN SMALL LIGATURE FFL +FB01 ; [.1D4B.0020.0004][.1D98.0020.0004] # LATIN SMALL LIGATURE FI +FB02 ; [.1D4B.0020.0004][.1DDD.0020.0004] # LATIN SMALL LIGATURE FL +3399 ; [.1D4B.0020.001C][.1E10.0020.001C] # SQUARE FM +02A9 ; [.1D4B.0020.0004][.1E3E.0020.0004] # LATIN SMALL LETTER FENG DIGRAPH +1F193 ; [.1D4B.0020.001D][.1E99.0020.001D][.1D10.0020.001D][.1D10.0020.001D] # SQUARED FREE +A730 ; [.1D4F.0020.0002] # LATIN LETTER SMALL CAPITAL F +AB35 ; [.1D50.0020.0002] # LATIN SMALL LETTER LENIS F +A799 ; [.1D51.0020.0002] # LATIN SMALL LETTER F WITH STROKE +A798 ; [.1D51.0020.0008] # LATIN CAPITAL LETTER F WITH STROKE +1D6E ; [.1D52.0020.0002] # LATIN SMALL LETTER F WITH MIDDLE TILDE +1D82 ; [.1D53.0020.0002] # LATIN SMALL LETTER F WITH PALATAL HOOK +0192 ; [.1D54.0020.0002] # LATIN SMALL LETTER F WITH HOOK +0191 ; [.1D54.0020.0008] # LATIN CAPITAL LETTER F WITH HOOK +214E ; [.1D58.0020.0002] # TURNED SMALL F +2132 ; [.1D58.0020.0008] # TURNED CAPITAL F +A7FB ; [.1D59.0020.0002] # LATIN EPIGRAPHIC LETTER REVERSED F +0067 ; [.1D5A.0020.0002] # LATIN SMALL LETTER G +FF47 ; [.1D5A.0020.0003] # FULLWIDTH LATIN SMALL LETTER G +1DDA ; [.1D5A.0020.0004] # COMBINING LATIN SMALL LETTER G +24A2 ; [*0318.0020.0004][.1D5A.0020.0004][*0319.0020.0004] # PARENTHESIZED LATIN SMALL LETTER G +210A ; [.1D5A.0020.0005] # SCRIPT SMALL G +1D420 ; [.1D5A.0020.0005] # MATHEMATICAL BOLD SMALL G +1D454 ; [.1D5A.0020.0005] # MATHEMATICAL ITALIC SMALL G +1D488 ; [.1D5A.0020.0005] # MATHEMATICAL BOLD ITALIC SMALL G +1D4F0 ; [.1D5A.0020.0005] # MATHEMATICAL BOLD SCRIPT SMALL G +1D524 ; [.1D5A.0020.0005] # MATHEMATICAL FRAKTUR SMALL G +1D558 ; [.1D5A.0020.0005] # MATHEMATICAL DOUBLE-STRUCK SMALL G +1D58C ; [.1D5A.0020.0005] # MATHEMATICAL BOLD FRAKTUR SMALL G +1D5C0 ; [.1D5A.0020.0005] # MATHEMATICAL SANS-SERIF SMALL G +1D5F4 ; [.1D5A.0020.0005] # MATHEMATICAL SANS-SERIF BOLD SMALL G +1D628 ; [.1D5A.0020.0005] # MATHEMATICAL SANS-SERIF ITALIC SMALL G +1D65C ; [.1D5A.0020.0005] # MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL G +1D690 ; [.1D5A.0020.0005] # MATHEMATICAL MONOSPACE SMALL G +24D6 ; [.1D5A.0020.0006] # CIRCLED LATIN SMALL LETTER G +0047 ; [.1D5A.0020.0008] # LATIN CAPITAL LETTER G +FF27 ; [.1D5A.0020.0009] # FULLWIDTH LATIN CAPITAL LETTER G +1F116 ; [*0318.0020.0004][.1D5A.0020.000A][*0319.0020.0004] # PARENTHESIZED LATIN CAPITAL LETTER G +1D406 ; [.1D5A.0020.000B] # MATHEMATICAL BOLD CAPITAL G +1D43A ; [.1D5A.0020.000B] # MATHEMATICAL ITALIC CAPITAL G +1D46E ; [.1D5A.0020.000B] # MATHEMATICAL BOLD ITALIC CAPITAL G +1D4A2 ; [.1D5A.0020.000B] # MATHEMATICAL SCRIPT CAPITAL G +1D4D6 ; [.1D5A.0020.000B] # MATHEMATICAL BOLD SCRIPT CAPITAL G +1D50A ; [.1D5A.0020.000B] # MATHEMATICAL FRAKTUR CAPITAL G +1D53E ; [.1D5A.0020.000B] # MATHEMATICAL DOUBLE-STRUCK CAPITAL G +1D572 ; [.1D5A.0020.000B] # MATHEMATICAL BOLD FRAKTUR CAPITAL G +1D5A6 ; [.1D5A.0020.000B] # MATHEMATICAL SANS-SERIF CAPITAL G +1D5DA ; [.1D5A.0020.000B] # MATHEMATICAL SANS-SERIF BOLD CAPITAL G +1D60E ; [.1D5A.0020.000B] # MATHEMATICAL SANS-SERIF ITALIC CAPITAL G +1D642 ; [.1D5A.0020.000B] # MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL G +1D676 ; [.1D5A.0020.000B] # MATHEMATICAL MONOSPACE CAPITAL G +24BC ; [.1D5A.0020.000C] # CIRCLED LATIN CAPITAL LETTER G +1F156 ; [.1D5A.0020.000C] # NEGATIVE CIRCLED LATIN CAPITAL LETTER G +1D4D ; [.1D5A.0020.0014] # MODIFIER LETTER SMALL G +1D33 ; [.1D5A.0020.001D] # MODIFIER LETTER CAPITAL G +1F136 ; [.1D5A.0020.001D] # SQUARED LATIN CAPITAL LETTER G +1F176 ; [.1D5A.0020.001D] # NEGATIVE SQUARED LATIN CAPITAL LETTER G +01F5 ; [.1D5A.0020.0002][.0000.0024.0002] # LATIN SMALL LETTER G WITH ACUTE +01F4 ; [.1D5A.0020.0008][.0000.0024.0002] # LATIN CAPITAL LETTER G WITH ACUTE +011F ; [.1D5A.0020.0002][.0000.0026.0002] # LATIN SMALL LETTER G WITH BREVE +011E ; [.1D5A.0020.0008][.0000.0026.0002] # LATIN CAPITAL LETTER G WITH BREVE +011D ; [.1D5A.0020.0002][.0000.0027.0002] # LATIN SMALL LETTER G WITH CIRCUMFLEX +011C ; [.1D5A.0020.0008][.0000.0027.0002] # LATIN CAPITAL LETTER G WITH CIRCUMFLEX +01E7 ; [.1D5A.0020.0002][.0000.0028.0002] # LATIN SMALL LETTER G WITH CARON +01E6 ; [.1D5A.0020.0008][.0000.0028.0002] # LATIN CAPITAL LETTER G WITH CARON +0121 ; [.1D5A.0020.0002][.0000.002E.0002] # LATIN SMALL LETTER G WITH DOT ABOVE +0120 ; [.1D5A.0020.0008][.0000.002E.0002] # LATIN CAPITAL LETTER G WITH DOT ABOVE +0123 ; [.1D5A.0020.0002][.0000.0030.0002] # LATIN SMALL LETTER G WITH CEDILLA +0122 ; [.1D5A.0020.0008][.0000.0030.0002] # LATIN CAPITAL LETTER G WITH CEDILLA +1E21 ; [.1D5A.0020.0002][.0000.0032.0002] # LATIN SMALL LETTER G WITH MACRON +1E20 ; [.1D5A.0020.0008][.0000.0032.0002] # LATIN CAPITAL LETTER G WITH MACRON +A7A1 ; [.1D5A.0020.0004][.0000.0035.0004] # LATIN SMALL LETTER G WITH OBLIQUE STROKE +A7A0 ; [.1D5A.0020.000A][.0000.0035.0004] # LATIN CAPITAL LETTER G WITH OBLIQUE STROKE +1D79 ; [.1D5A.0020.0004][.0000.0112.0004] # LATIN SMALL LETTER INSULAR G +A77D ; [.1D5A.0020.000A][.0000.0112.0004] # LATIN CAPITAL LETTER INSULAR G +33FF ; [.1D5A.0020.001C][.1CAD.0020.001C][.1DDD.0020.001C] # SQUARE GAL +3387 ; [.1D5A.0020.001D][.1CC6.0020.001D] # SQUARE GB +3393 ; [.1D5A.0020.001D][.1D7E.0020.001D][.1F87.0020.001C] # SQUARE GHZ +33AC ; [.1D5A.0020.001D][.1E72.0020.001D][.1CAD.0020.001C] # SQUARE GPA +33C9 ; [.1D5A.0020.001D][.1F71.0020.001C] # SQUARE GY +0261 ; [.1D5E.0020.0002] # LATIN SMALL LETTER SCRIPT G +A7AC ; [.1D5E.0020.0008] # LATIN CAPITAL LETTER SCRIPT G +1DA2 ; [.1D5E.0020.0014] # MODIFIER LETTER SMALL SCRIPT G +AB36 ; [.1D62.0020.0002] # LATIN SMALL LETTER SCRIPT G WITH CROSSED-TAIL +0262 ; [.1D63.0020.0002] # LATIN LETTER SMALL CAPITAL G +1DDB ; [.1D63.0020.0004] # COMBINING LATIN LETTER SMALL CAPITAL G +01E5 ; [.1D67.0020.0002] # LATIN SMALL LETTER G WITH STROKE +01E4 ; [.1D67.0020.0008] # LATIN CAPITAL LETTER G WITH STROKE +1D83 ; [.1D6B.0020.0002] # LATIN SMALL LETTER G WITH PALATAL HOOK +0260 ; [.1D6C.0020.0002] # LATIN SMALL LETTER G WITH HOOK +0193 ; [.1D6C.0020.0008] # LATIN CAPITAL LETTER G WITH HOOK +029B ; [.1D70.0020.0002] # LATIN LETTER SMALL CAPITAL G WITH HOOK +1D77 ; [.1D74.0020.0002] # LATIN SMALL LETTER TURNED G +A77F ; [.1D75.0020.0002] # LATIN SMALL LETTER TURNED INSULAR G +A77E ; [.1D75.0020.0008] # LATIN CAPITAL LETTER TURNED INSULAR G +0263 ; [.1D76.0020.0002] # LATIN SMALL LETTER GAMMA +0194 ; [.1D76.0020.0008] # LATIN CAPITAL LETTER GAMMA +02E0 ; [.1D76.0020.0014] # MODIFIER LETTER SMALL GAMMA +01A3 ; [.1D7A.0020.0002] # LATIN SMALL LETTER OI +01A2 ; [.1D7A.0020.0008] # LATIN CAPITAL LETTER OI +0068 ; [.1D7E.0020.0002] # LATIN SMALL LETTER H +FF48 ; [.1D7E.0020.0003] # FULLWIDTH LATIN SMALL LETTER H +036A ; [.1D7E.0020.0004] # COMBINING LATIN SMALL LETTER H +24A3 ; [*0318.0020.0004][.1D7E.0020.0004][*0319.0020.0004] # PARENTHESIZED LATIN SMALL LETTER H +210E ; [.1D7E.0020.0005] # PLANCK CONSTANT +1D421 ; [.1D7E.0020.0005] # MATHEMATICAL BOLD SMALL H +1D489 ; [.1D7E.0020.0005] # MATHEMATICAL BOLD ITALIC SMALL H +1D4BD ; [.1D7E.0020.0005] # MATHEMATICAL SCRIPT SMALL H +1D4F1 ; [.1D7E.0020.0005] # MATHEMATICAL BOLD SCRIPT SMALL H +1D525 ; [.1D7E.0020.0005] # MATHEMATICAL FRAKTUR SMALL H +1D559 ; [.1D7E.0020.0005] # MATHEMATICAL DOUBLE-STRUCK SMALL H +1D58D ; [.1D7E.0020.0005] # MATHEMATICAL BOLD FRAKTUR SMALL H +1D5C1 ; [.1D7E.0020.0005] # MATHEMATICAL SANS-SERIF SMALL H +1D5F5 ; [.1D7E.0020.0005] # MATHEMATICAL SANS-SERIF BOLD SMALL H +1D629 ; [.1D7E.0020.0005] # MATHEMATICAL SANS-SERIF ITALIC SMALL H +1D65D ; [.1D7E.0020.0005] # MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL H +1D691 ; [.1D7E.0020.0005] # MATHEMATICAL MONOSPACE SMALL H +24D7 ; [.1D7E.0020.0006] # CIRCLED LATIN SMALL LETTER H +0048 ; [.1D7E.0020.0008] # LATIN CAPITAL LETTER H +FF28 ; [.1D7E.0020.0009] # FULLWIDTH LATIN CAPITAL LETTER H +1F117 ; [*0318.0020.0004][.1D7E.0020.000A][*0319.0020.0004] # PARENTHESIZED LATIN CAPITAL LETTER H +210B ; [.1D7E.0020.000B] # SCRIPT CAPITAL H +210C ; [.1D7E.0020.000B] # BLACK-LETTER CAPITAL H +210D ; [.1D7E.0020.000B] # DOUBLE-STRUCK CAPITAL H +1D407 ; [.1D7E.0020.000B] # MATHEMATICAL BOLD CAPITAL H +1D43B ; [.1D7E.0020.000B] # MATHEMATICAL ITALIC CAPITAL H +1D46F ; [.1D7E.0020.000B] # MATHEMATICAL BOLD ITALIC CAPITAL H +1D4D7 ; [.1D7E.0020.000B] # MATHEMATICAL BOLD SCRIPT CAPITAL H +1D573 ; [.1D7E.0020.000B] # MATHEMATICAL BOLD FRAKTUR CAPITAL H +1D5A7 ; [.1D7E.0020.000B] # MATHEMATICAL SANS-SERIF CAPITAL H +1D5DB ; [.1D7E.0020.000B] # MATHEMATICAL SANS-SERIF BOLD CAPITAL H +1D60F ; [.1D7E.0020.000B] # MATHEMATICAL SANS-SERIF ITALIC CAPITAL H +1D643 ; [.1D7E.0020.000B] # MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL H +1D677 ; [.1D7E.0020.000B] # MATHEMATICAL MONOSPACE CAPITAL H +24BD ; [.1D7E.0020.000C] # CIRCLED LATIN CAPITAL LETTER H +1F157 ; [.1D7E.0020.000C] # NEGATIVE CIRCLED LATIN CAPITAL LETTER H +02B0 ; [.1D7E.0020.0014] # MODIFIER LETTER SMALL H +2095 ; [.1D7E.0020.0015] # LATIN SUBSCRIPT SMALL LETTER H +1D34 ; [.1D7E.0020.001D] # MODIFIER LETTER CAPITAL H +1F137 ; [.1D7E.0020.001D] # SQUARED LATIN CAPITAL LETTER H +1F177 ; [.1D7E.0020.001D] # NEGATIVE SQUARED LATIN CAPITAL LETTER H +0125 ; [.1D7E.0020.0002][.0000.0027.0002] # LATIN SMALL LETTER H WITH CIRCUMFLEX +0124 ; [.1D7E.0020.0008][.0000.0027.0002] # LATIN CAPITAL LETTER H WITH CIRCUMFLEX +021F ; [.1D7E.0020.0002][.0000.0028.0002] # LATIN SMALL LETTER H WITH CARON +021E ; [.1D7E.0020.0008][.0000.0028.0002] # LATIN CAPITAL LETTER H WITH CARON +1E27 ; [.1D7E.0020.0002][.0000.002B.0002] # LATIN SMALL LETTER H WITH DIAERESIS +1E26 ; [.1D7E.0020.0008][.0000.002B.0002] # LATIN CAPITAL LETTER H WITH DIAERESIS +1E23 ; [.1D7E.0020.0002][.0000.002E.0002] # LATIN SMALL LETTER H WITH DOT ABOVE +1E22 ; [.1D7E.0020.0008][.0000.002E.0002] # LATIN CAPITAL LETTER H WITH DOT ABOVE +1E29 ; [.1D7E.0020.0002][.0000.0030.0002] # LATIN SMALL LETTER H WITH CEDILLA +1E28 ; [.1D7E.0020.0008][.0000.0030.0002] # LATIN CAPITAL LETTER H WITH CEDILLA +0127 ; [.1D7E.0020.0002][.0000.0039.0002] # LATIN SMALL LETTER H WITH STROKE +210F ; [.1D7E.0020.0002][.0000.0039.0002] # PLANCK CONSTANT OVER TWO PI +0126 ; [.1D7E.0020.0008][.0000.0039.0002] # LATIN CAPITAL LETTER H WITH STROKE +A7F8 ; [.1D7E.0020.0014][.0000.0039.0014] # MODIFIER LETTER CAPITAL H WITH STROKE +1E25 ; [.1D7E.0020.0002][.0000.0042.0002] # LATIN SMALL LETTER H WITH DOT BELOW +1E24 ; [.1D7E.0020.0008][.0000.0042.0002] # LATIN CAPITAL LETTER H WITH DOT BELOW +1E2B ; [.1D7E.0020.0002][.0000.0047.0002] # LATIN SMALL LETTER H WITH BREVE BELOW +1E2A ; [.1D7E.0020.0008][.0000.0047.0002] # LATIN CAPITAL LETTER H WITH BREVE BELOW +1E96 ; [.1D7E.0020.0002][.0000.0049.0002] # LATIN SMALL LETTER H WITH LINE BELOW +33CA ; [.1D7E.0020.001C][.1CAD.0020.001C] # SQUARE HA +1F1A6 ; [.1D7E.0020.001D][.1CE0.0020.001C] # SQUARED HC +1F1A7 ; [.1D7E.0020.001D][.1CF5.0020.001C][.1E99.0020.001D] # SQUARED HDR +32CC ; [.1D7E.0020.001D][.1D5A.0020.001C] # SQUARE HG +1F1A8 ; [.1D7E.0020.001D][.1D98.0020.001C][*0209.0020.001C][.1E99.0020.001D][.1D10.0020.001C][.1ED7.0020.001C] # SQUARED HI-RES +33CB ; [.1D7E.0020.001D][.1E72.0020.001D] # SQUARE HP +3371 ; [.1D7E.0020.001C][.1E72.0020.001D][.1CAD.0020.001C] # SQUARE HPA +1F14A ; [.1D7E.0020.001D][.1F49.0020.001D] # SQUARED HV +3390 ; [.1D7E.0020.001D][.1F87.0020.001C] # SQUARE HZ +029C ; [.1D82.0020.0002] # LATIN LETTER SMALL CAPITAL H +0195 ; [.1D86.0020.0002] # LATIN SMALL LETTER HV +01F6 ; [.1D86.0020.0008] # LATIN CAPITAL LETTER HWAIR +A795 ; [.1D8A.0020.0002] # LATIN SMALL LETTER H WITH PALATAL HOOK +0266 ; [.1D8B.0020.0002] # LATIN SMALL LETTER H WITH HOOK +A7AA ; [.1D8B.0020.0008] # LATIN CAPITAL LETTER H WITH HOOK +02B1 ; [.1D8B.0020.0014] # MODIFIER LETTER SMALL H WITH HOOK +2C68 ; [.1D8F.0020.0002] # LATIN SMALL LETTER H WITH DESCENDER +2C67 ; [.1D8F.0020.0008] # LATIN CAPITAL LETTER H WITH DESCENDER +2C76 ; [.1D90.0020.0002] # LATIN SMALL LETTER HALF H +2C75 ; [.1D90.0020.0008] # LATIN CAPITAL LETTER HALF H +A727 ; [.1D91.0020.0002] # LATIN SMALL LETTER HENG +A726 ; [.1D91.0020.0008] # LATIN CAPITAL LETTER HENG +AB5C ; [.1D91.0020.0014] # MODIFIER LETTER SMALL HENG +0267 ; [.1D92.0020.0002] # LATIN SMALL LETTER HENG WITH HOOK +02BB ; [.1D96.0020.0002] # MODIFIER LETTER TURNED COMMA +02BD ; [.1D97.0020.0002] # MODIFIER LETTER REVERSED COMMA +0069 ; [.1D98.0020.0002] # LATIN SMALL LETTER I +FF49 ; [.1D98.0020.0003] # FULLWIDTH LATIN SMALL LETTER I +0365 ; [.1D98.0020.0004] # COMBINING LATIN SMALL LETTER I +2170 ; [.1D98.0020.0004] # SMALL ROMAN NUMERAL ONE +24A4 ; [*0318.0020.0004][.1D98.0020.0004][*0319.0020.0004] # PARENTHESIZED LATIN SMALL LETTER I +2139 ; [.1D98.0020.0005] # INFORMATION SOURCE +2148 ; [.1D98.0020.0005] # DOUBLE-STRUCK ITALIC SMALL I +1D422 ; [.1D98.0020.0005] # MATHEMATICAL BOLD SMALL I +1D456 ; [.1D98.0020.0005] # MATHEMATICAL ITALIC SMALL I +1D48A ; [.1D98.0020.0005] # MATHEMATICAL BOLD ITALIC SMALL I +1D4BE ; [.1D98.0020.0005] # MATHEMATICAL SCRIPT SMALL I +1D4F2 ; [.1D98.0020.0005] # MATHEMATICAL BOLD SCRIPT SMALL I +1D526 ; [.1D98.0020.0005] # MATHEMATICAL FRAKTUR SMALL I +1D55A ; [.1D98.0020.0005] # MATHEMATICAL DOUBLE-STRUCK SMALL I +1D58E ; [.1D98.0020.0005] # MATHEMATICAL BOLD FRAKTUR SMALL I +1D5C2 ; [.1D98.0020.0005] # MATHEMATICAL SANS-SERIF SMALL I +1D5F6 ; [.1D98.0020.0005] # MATHEMATICAL SANS-SERIF BOLD SMALL I +1D62A ; [.1D98.0020.0005] # MATHEMATICAL SANS-SERIF ITALIC SMALL I +1D65E ; [.1D98.0020.0005] # MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL I +1D692 ; [.1D98.0020.0005] # MATHEMATICAL MONOSPACE SMALL I +24D8 ; [.1D98.0020.0006] # CIRCLED LATIN SMALL LETTER I +0049 ; [.1D98.0020.0008] # LATIN CAPITAL LETTER I +FF29 ; [.1D98.0020.0009] # FULLWIDTH LATIN CAPITAL LETTER I +2160 ; [.1D98.0020.000A] # ROMAN NUMERAL ONE +1F118 ; [*0318.0020.0004][.1D98.0020.000A][*0319.0020.0004] # PARENTHESIZED LATIN CAPITAL LETTER I +2110 ; [.1D98.0020.000B] # SCRIPT CAPITAL I +2111 ; [.1D98.0020.000B] # BLACK-LETTER CAPITAL I +1D408 ; [.1D98.0020.000B] # MATHEMATICAL BOLD CAPITAL I +1D43C ; [.1D98.0020.000B] # MATHEMATICAL ITALIC CAPITAL I +1D470 ; [.1D98.0020.000B] # MATHEMATICAL BOLD ITALIC CAPITAL I +1D4D8 ; [.1D98.0020.000B] # MATHEMATICAL BOLD SCRIPT CAPITAL I +1D540 ; [.1D98.0020.000B] # MATHEMATICAL DOUBLE-STRUCK CAPITAL I +1D574 ; [.1D98.0020.000B] # MATHEMATICAL BOLD FRAKTUR CAPITAL I +1D5A8 ; [.1D98.0020.000B] # MATHEMATICAL SANS-SERIF CAPITAL I +1D5DC ; [.1D98.0020.000B] # MATHEMATICAL SANS-SERIF BOLD CAPITAL I +1D610 ; [.1D98.0020.000B] # MATHEMATICAL SANS-SERIF ITALIC CAPITAL I +1D644 ; [.1D98.0020.000B] # MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL I +1D678 ; [.1D98.0020.000B] # MATHEMATICAL MONOSPACE CAPITAL I +24BE ; [.1D98.0020.000C] # CIRCLED LATIN CAPITAL LETTER I +1F158 ; [.1D98.0020.000C] # NEGATIVE CIRCLED LATIN CAPITAL LETTER I +2071 ; [.1D98.0020.0014] # SUPERSCRIPT LATIN SMALL LETTER I +1D62 ; [.1D98.0020.0015] # LATIN SUBSCRIPT SMALL LETTER I +1D35 ; [.1D98.0020.001D] # MODIFIER LETTER CAPITAL I +1F138 ; [.1D98.0020.001D] # SQUARED LATIN CAPITAL LETTER I +1F178 ; [.1D98.0020.001D] # NEGATIVE SQUARED LATIN CAPITAL LETTER I +00ED ; [.1D98.0020.0002][.0000.0024.0002] # LATIN SMALL LETTER I WITH ACUTE +00CD ; [.1D98.0020.0008][.0000.0024.0002] # LATIN CAPITAL LETTER I WITH ACUTE +00EC ; [.1D98.0020.0002][.0000.0025.0002] # LATIN SMALL LETTER I WITH GRAVE +00CC ; [.1D98.0020.0008][.0000.0025.0002] # LATIN CAPITAL LETTER I WITH GRAVE +012D ; [.1D98.0020.0002][.0000.0026.0002] # LATIN SMALL LETTER I WITH BREVE +012C ; [.1D98.0020.0008][.0000.0026.0002] # LATIN CAPITAL LETTER I WITH BREVE +00EE ; [.1D98.0020.0002][.0000.0027.0002] # LATIN SMALL LETTER I WITH CIRCUMFLEX +00CE ; [.1D98.0020.0008][.0000.0027.0002] # LATIN CAPITAL LETTER I WITH CIRCUMFLEX +01D0 ; [.1D98.0020.0002][.0000.0028.0002] # LATIN SMALL LETTER I WITH CARON +01CF ; [.1D98.0020.0008][.0000.0028.0002] # LATIN CAPITAL LETTER I WITH CARON +00EF ; [.1D98.0020.0002][.0000.002B.0002] # LATIN SMALL LETTER I WITH DIAERESIS +00CF ; [.1D98.0020.0008][.0000.002B.0002] # LATIN CAPITAL LETTER I WITH DIAERESIS +1E2F ; [.1D98.0020.0002][.0000.002B.0002][.0000.0024.0002] # LATIN SMALL LETTER I WITH DIAERESIS AND ACUTE +1E2E ; [.1D98.0020.0008][.0000.002B.0002][.0000.0024.0002] # LATIN CAPITAL LETTER I WITH DIAERESIS AND ACUTE +0129 ; [.1D98.0020.0002][.0000.002D.0002] # LATIN SMALL LETTER I WITH TILDE +0128 ; [.1D98.0020.0008][.0000.002D.0002] # LATIN CAPITAL LETTER I WITH TILDE +0130 ; [.1D98.0020.0008][.0000.002E.0002] # LATIN CAPITAL LETTER I WITH DOT ABOVE +012F ; [.1D98.0020.0002][.0000.0031.0002] # LATIN SMALL LETTER I WITH OGONEK +012E ; [.1D98.0020.0008][.0000.0031.0002] # LATIN CAPITAL LETTER I WITH OGONEK +012B ; [.1D98.0020.0002][.0000.0032.0002] # LATIN SMALL LETTER I WITH MACRON +012A ; [.1D98.0020.0008][.0000.0032.0002] # LATIN CAPITAL LETTER I WITH MACRON +1EC9 ; [.1D98.0020.0002][.0000.003B.0002] # LATIN SMALL LETTER I WITH HOOK ABOVE +1EC8 ; [.1D98.0020.0008][.0000.003B.0002] # LATIN CAPITAL LETTER I WITH HOOK ABOVE +0209 ; [.1D98.0020.0002][.0000.003C.0002] # LATIN SMALL LETTER I WITH DOUBLE GRAVE +0208 ; [.1D98.0020.0008][.0000.003C.0002] # LATIN CAPITAL LETTER I WITH DOUBLE GRAVE +020B ; [.1D98.0020.0002][.0000.003E.0002] # LATIN SMALL LETTER I WITH INVERTED BREVE +020A ; [.1D98.0020.0008][.0000.003E.0002] # LATIN CAPITAL LETTER I WITH INVERTED BREVE +1ECB ; [.1D98.0020.0002][.0000.0042.0002] # LATIN SMALL LETTER I WITH DOT BELOW +1ECA ; [.1D98.0020.0008][.0000.0042.0002] # LATIN CAPITAL LETTER I WITH DOT BELOW +1E2D ; [.1D98.0020.0002][.0000.0048.0002] # LATIN SMALL LETTER I WITH TILDE BELOW +1E2C ; [.1D98.0020.0008][.0000.0048.0002] # LATIN CAPITAL LETTER I WITH TILDE BELOW +1F18B ; [.1D98.0020.001D][.1CE0.0020.001D] # NEGATIVE SQUARED IC +1F194 ; [.1D98.0020.001D][.1CF5.0020.001D] # SQUARED ID +2171 ; [.1D98.0020.0004][.1D98.0020.0004] # SMALL ROMAN NUMERAL TWO +2161 ; [.1D98.0020.000A][.1D98.0020.000A] # ROMAN NUMERAL TWO +2172 ; [.1D98.0020.0004][.1D98.0020.0004][.1D98.0020.0004] # SMALL ROMAN NUMERAL THREE +2162 ; [.1D98.0020.000A][.1D98.0020.000A][.1D98.0020.000A] # ROMAN NUMERAL THREE +0133 ; [.1D98.0020.0004][.1DB2.0020.0004] # LATIN SMALL LIGATURE IJ +0132 ; [.1D98.0020.000A][.1DB2.0020.000A] # LATIN CAPITAL LIGATURE IJ +33CC ; [.1D98.0020.001C][.1E1F.0020.001C] # SQUARE IN +337A ; [.1D98.0020.001D][.1F1B.0020.001D] # SQUARE IU +2173 ; [.1D98.0020.0004][.1F49.0020.0004] # SMALL ROMAN NUMERAL FOUR +2163 ; [.1D98.0020.000A][.1F49.0020.000A] # ROMAN NUMERAL FOUR +2178 ; [.1D98.0020.0004][.1F65.0020.0004] # SMALL ROMAN NUMERAL NINE +2168 ; [.1D98.0020.000A][.1F65.0020.000A] # ROMAN NUMERAL NINE +0131 ; [.1D9C.0020.0002] # LATIN SMALL LETTER DOTLESS I +1D6A4 ; [.1D9C.0020.0005] # MATHEMATICAL ITALIC SMALL DOTLESS I +026A ; [.1DA0.0020.0002] # LATIN LETTER SMALL CAPITAL I +A7AE ; [.1DA0.0020.0008] # LATIN CAPITAL LETTER SMALL CAPITAL I +1DA6 ; [.1DA0.0020.0014] # MODIFIER LETTER SMALL CAPITAL I +A7FE ; [.1DA4.0020.0002] # LATIN EPIGRAPHIC LETTER I LONGA +A7F7 ; [.1DA5.0020.0002] # LATIN EPIGRAPHIC LETTER SIDEWAYS I +1D09 ; [.1DA6.0020.0002] # LATIN SMALL LETTER TURNED I +1D4E ; [.1DA6.0020.0014] # MODIFIER LETTER SMALL TURNED I +0268 ; [.1DA7.0020.0002] # LATIN SMALL LETTER I WITH STROKE +0197 ; [.1DA7.0020.0008] # LATIN CAPITAL LETTER I WITH STROKE +1DA4 ; [.1DA7.0020.0014] # MODIFIER LETTER SMALL I WITH STROKE +1D7B ; [.1DAB.0020.0002] # LATIN SMALL CAPITAL LETTER I WITH STROKE +1DA7 ; [.1DAB.0020.0014] # MODIFIER LETTER SMALL CAPITAL I WITH STROKE +1D96 ; [.1DAC.0020.0002] # LATIN SMALL LETTER I WITH RETROFLEX HOOK +0269 ; [.1DAD.0020.0002] # LATIN SMALL LETTER IOTA +0196 ; [.1DAD.0020.0008] # LATIN CAPITAL LETTER IOTA +1DA5 ; [.1DAD.0020.0014] # MODIFIER LETTER SMALL IOTA +1D7C ; [.1DB1.0020.0002] # LATIN SMALL LETTER IOTA WITH STROKE +006A ; [.1DB2.0020.0002] # LATIN SMALL LETTER J +FF4A ; [.1DB2.0020.0003] # FULLWIDTH LATIN SMALL LETTER J +24A5 ; [*0318.0020.0004][.1DB2.0020.0004][*0319.0020.0004] # PARENTHESIZED LATIN SMALL LETTER J +2149 ; [.1DB2.0020.0005] # DOUBLE-STRUCK ITALIC SMALL J +1D423 ; [.1DB2.0020.0005] # MATHEMATICAL BOLD SMALL J +1D457 ; [.1DB2.0020.0005] # MATHEMATICAL ITALIC SMALL J +1D48B ; [.1DB2.0020.0005] # MATHEMATICAL BOLD ITALIC SMALL J +1D4BF ; [.1DB2.0020.0005] # MATHEMATICAL SCRIPT SMALL J +1D4F3 ; [.1DB2.0020.0005] # MATHEMATICAL BOLD SCRIPT SMALL J +1D527 ; [.1DB2.0020.0005] # MATHEMATICAL FRAKTUR SMALL J +1D55B ; [.1DB2.0020.0005] # MATHEMATICAL DOUBLE-STRUCK SMALL J +1D58F ; [.1DB2.0020.0005] # MATHEMATICAL BOLD FRAKTUR SMALL J +1D5C3 ; [.1DB2.0020.0005] # MATHEMATICAL SANS-SERIF SMALL J +1D5F7 ; [.1DB2.0020.0005] # MATHEMATICAL SANS-SERIF BOLD SMALL J +1D62B ; [.1DB2.0020.0005] # MATHEMATICAL SANS-SERIF ITALIC SMALL J +1D65F ; [.1DB2.0020.0005] # MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL J +1D693 ; [.1DB2.0020.0005] # MATHEMATICAL MONOSPACE SMALL J +24D9 ; [.1DB2.0020.0006] # CIRCLED LATIN SMALL LETTER J +004A ; [.1DB2.0020.0008] # LATIN CAPITAL LETTER J +FF2A ; [.1DB2.0020.0009] # FULLWIDTH LATIN CAPITAL LETTER J +1F119 ; [*0318.0020.0004][.1DB2.0020.000A][*0319.0020.0004] # PARENTHESIZED LATIN CAPITAL LETTER J +1D409 ; [.1DB2.0020.000B] # MATHEMATICAL BOLD CAPITAL J +1D43D ; [.1DB2.0020.000B] # MATHEMATICAL ITALIC CAPITAL J +1D471 ; [.1DB2.0020.000B] # MATHEMATICAL BOLD ITALIC CAPITAL J +1D4A5 ; [.1DB2.0020.000B] # MATHEMATICAL SCRIPT CAPITAL J +1D4D9 ; [.1DB2.0020.000B] # MATHEMATICAL BOLD SCRIPT CAPITAL J +1D50D ; [.1DB2.0020.000B] # MATHEMATICAL FRAKTUR CAPITAL J +1D541 ; [.1DB2.0020.000B] # MATHEMATICAL DOUBLE-STRUCK CAPITAL J +1D575 ; [.1DB2.0020.000B] # MATHEMATICAL BOLD FRAKTUR CAPITAL J +1D5A9 ; [.1DB2.0020.000B] # MATHEMATICAL SANS-SERIF CAPITAL J +1D5DD ; [.1DB2.0020.000B] # MATHEMATICAL SANS-SERIF BOLD CAPITAL J +1D611 ; [.1DB2.0020.000B] # MATHEMATICAL SANS-SERIF ITALIC CAPITAL J +1D645 ; [.1DB2.0020.000B] # MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL J +1D679 ; [.1DB2.0020.000B] # MATHEMATICAL MONOSPACE CAPITAL J +24BF ; [.1DB2.0020.000C] # CIRCLED LATIN CAPITAL LETTER J +1F159 ; [.1DB2.0020.000C] # NEGATIVE CIRCLED LATIN CAPITAL LETTER J +02B2 ; [.1DB2.0020.0014] # MODIFIER LETTER SMALL J +2C7C ; [.1DB2.0020.0015] # LATIN SUBSCRIPT SMALL LETTER J +1D36 ; [.1DB2.0020.001D] # MODIFIER LETTER CAPITAL J +1F139 ; [.1DB2.0020.001D] # SQUARED LATIN CAPITAL LETTER J +1F179 ; [.1DB2.0020.001D] # NEGATIVE SQUARED LATIN CAPITAL LETTER J +0135 ; [.1DB2.0020.0002][.0000.0027.0002] # LATIN SMALL LETTER J WITH CIRCUMFLEX +0134 ; [.1DB2.0020.0008][.0000.0027.0002] # LATIN CAPITAL LETTER J WITH CIRCUMFLEX +01F0 ; [.1DB2.0020.0002][.0000.0028.0002] # LATIN SMALL LETTER J WITH CARON +0237 ; [.1DB6.0020.0002] # LATIN SMALL LETTER DOTLESS J +1D6A5 ; [.1DB6.0020.0005] # MATHEMATICAL ITALIC SMALL DOTLESS J +1D0A ; [.1DBA.0020.0002] # LATIN LETTER SMALL CAPITAL J +0249 ; [.1DBB.0020.0002] # LATIN SMALL LETTER J WITH STROKE +0248 ; [.1DBB.0020.0008] # LATIN CAPITAL LETTER J WITH STROKE +029D ; [.1DBF.0020.0002] # LATIN SMALL LETTER J WITH CROSSED-TAIL +A7B2 ; [.1DBF.0020.0008] # LATIN CAPITAL LETTER J WITH CROSSED-TAIL +1DA8 ; [.1DBF.0020.0014] # MODIFIER LETTER SMALL J WITH CROSSED-TAIL +025F ; [.1DC3.0020.0002] # LATIN SMALL LETTER DOTLESS J WITH STROKE +1DA1 ; [.1DC3.0020.0014] # MODIFIER LETTER SMALL DOTLESS J WITH STROKE +0284 ; [.1DC7.0020.0002] # LATIN SMALL LETTER DOTLESS J WITH STROKE AND HOOK +006B ; [.1DCB.0020.0002] # LATIN SMALL LETTER K +FF4B ; [.1DCB.0020.0003] # FULLWIDTH LATIN SMALL LETTER K +1DDC ; [.1DCB.0020.0004] # COMBINING LATIN SMALL LETTER K +24A6 ; [*0318.0020.0004][.1DCB.0020.0004][*0319.0020.0004] # PARENTHESIZED LATIN SMALL LETTER K +1D424 ; [.1DCB.0020.0005] # MATHEMATICAL BOLD SMALL K +1D458 ; [.1DCB.0020.0005] # MATHEMATICAL ITALIC SMALL K +1D48C ; [.1DCB.0020.0005] # MATHEMATICAL BOLD ITALIC SMALL K +1D4C0 ; [.1DCB.0020.0005] # MATHEMATICAL SCRIPT SMALL K +1D4F4 ; [.1DCB.0020.0005] # MATHEMATICAL BOLD SCRIPT SMALL K +1D528 ; [.1DCB.0020.0005] # MATHEMATICAL FRAKTUR SMALL K +1D55C ; [.1DCB.0020.0005] # MATHEMATICAL DOUBLE-STRUCK SMALL K +1D590 ; [.1DCB.0020.0005] # MATHEMATICAL BOLD FRAKTUR SMALL K +1D5C4 ; [.1DCB.0020.0005] # MATHEMATICAL SANS-SERIF SMALL K +1D5F8 ; [.1DCB.0020.0005] # MATHEMATICAL SANS-SERIF BOLD SMALL K +1D62C ; [.1DCB.0020.0005] # MATHEMATICAL SANS-SERIF ITALIC SMALL K +1D660 ; [.1DCB.0020.0005] # MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL K +1D694 ; [.1DCB.0020.0005] # MATHEMATICAL MONOSPACE SMALL K +24DA ; [.1DCB.0020.0006] # CIRCLED LATIN SMALL LETTER K +004B ; [.1DCB.0020.0008] # LATIN CAPITAL LETTER K +212A ; [.1DCB.0020.0008] # KELVIN SIGN +FF2B ; [.1DCB.0020.0009] # FULLWIDTH LATIN CAPITAL LETTER K +1F11A ; [*0318.0020.0004][.1DCB.0020.000A][*0319.0020.0004] # PARENTHESIZED LATIN CAPITAL LETTER K +1D40A ; [.1DCB.0020.000B] # MATHEMATICAL BOLD CAPITAL K +1D43E ; [.1DCB.0020.000B] # MATHEMATICAL ITALIC CAPITAL K +1D472 ; [.1DCB.0020.000B] # MATHEMATICAL BOLD ITALIC CAPITAL K +1D4A6 ; [.1DCB.0020.000B] # MATHEMATICAL SCRIPT CAPITAL K +1D4DA ; [.1DCB.0020.000B] # MATHEMATICAL BOLD SCRIPT CAPITAL K +1D50E ; [.1DCB.0020.000B] # MATHEMATICAL FRAKTUR CAPITAL K +1D542 ; [.1DCB.0020.000B] # MATHEMATICAL DOUBLE-STRUCK CAPITAL K +1D576 ; [.1DCB.0020.000B] # MATHEMATICAL BOLD FRAKTUR CAPITAL K +1D5AA ; [.1DCB.0020.000B] # MATHEMATICAL SANS-SERIF CAPITAL K +1D5DE ; [.1DCB.0020.000B] # MATHEMATICAL SANS-SERIF BOLD CAPITAL K +1D612 ; [.1DCB.0020.000B] # MATHEMATICAL SANS-SERIF ITALIC CAPITAL K +1D646 ; [.1DCB.0020.000B] # MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL K +1D67A ; [.1DCB.0020.000B] # MATHEMATICAL MONOSPACE CAPITAL K +24C0 ; [.1DCB.0020.000C] # CIRCLED LATIN CAPITAL LETTER K +1F15A ; [.1DCB.0020.000C] # NEGATIVE CIRCLED LATIN CAPITAL LETTER K +1D4F ; [.1DCB.0020.0014] # MODIFIER LETTER SMALL K +2096 ; [.1DCB.0020.0015] # LATIN SUBSCRIPT SMALL LETTER K +1D37 ; [.1DCB.0020.001D] # MODIFIER LETTER CAPITAL K +1F13A ; [.1DCB.0020.001D] # SQUARED LATIN CAPITAL LETTER K +1F17A ; [.1DCB.0020.001D] # NEGATIVE SQUARED LATIN CAPITAL LETTER K +1E31 ; [.1DCB.0020.0002][.0000.0024.0002] # LATIN SMALL LETTER K WITH ACUTE +1E30 ; [.1DCB.0020.0008][.0000.0024.0002] # LATIN CAPITAL LETTER K WITH ACUTE +01E9 ; [.1DCB.0020.0002][.0000.0028.0002] # LATIN SMALL LETTER K WITH CARON +01E8 ; [.1DCB.0020.0008][.0000.0028.0002] # LATIN CAPITAL LETTER K WITH CARON +0137 ; [.1DCB.0020.0002][.0000.0030.0002] # LATIN SMALL LETTER K WITH CEDILLA +0136 ; [.1DCB.0020.0008][.0000.0030.0002] # LATIN CAPITAL LETTER K WITH CEDILLA +A7A3 ; [.1DCB.0020.0004][.0000.0035.0004] # LATIN SMALL LETTER K WITH OBLIQUE STROKE +A7A2 ; [.1DCB.0020.000A][.0000.0035.0004] # LATIN CAPITAL LETTER K WITH OBLIQUE STROKE +1E33 ; [.1DCB.0020.0002][.0000.0042.0002] # LATIN SMALL LETTER K WITH DOT BELOW +1E32 ; [.1DCB.0020.0008][.0000.0042.0002] # LATIN CAPITAL LETTER K WITH DOT BELOW +1E35 ; [.1DCB.0020.0002][.0000.0049.0002] # LATIN SMALL LETTER K WITH LINE BELOW +1E34 ; [.1DCB.0020.0008][.0000.0049.0002] # LATIN CAPITAL LETTER K WITH LINE BELOW +3384 ; [.1DCB.0020.001C][.1CAD.0020.001D] # SQUARE KA +3385 ; [.1DCB.0020.001D][.1CC6.0020.001D] # SQUARE KB +3389 ; [.1DCB.0020.001C][.1CE0.0020.001C][.1CAD.0020.001C][.1DDD.0020.001C] # SQUARE KCAL +338F ; [.1DCB.0020.001C][.1D5A.0020.001C] # SQUARE KG +3391 ; [.1DCB.0020.001C][.1D7E.0020.001D][.1F87.0020.001C] # SQUARE KHZ +33CD ; [.1DCB.0020.001D][.1DCB.0020.001D] # SQUARE KK +3398 ; [.1DCB.0020.001C][.1DDD.0020.001C] # SQUARE KL +339E ; [.1DCB.0020.001C][.1E10.0020.001C] # SQUARE KM +33CE ; [.1DCB.0020.001D][.1E10.0020.001D] # SQUARE KM CAPITAL +33A2 ; [.1DCB.0020.001C][.1E10.0020.001C][.1CA5.0020.001C] # SQUARE KM SQUARED +33A6 ; [.1DCB.0020.001C][.1E10.0020.001C][.1CA6.0020.001C] # SQUARE KM CUBED +33AA ; [.1DCB.0020.001C][.1E72.0020.001D][.1CAD.0020.001C] # SQUARE KPA +33CF ; [.1DCB.0020.001C][.1EFB.0020.001C] # SQUARE KT +33B8 ; [.1DCB.0020.001C][.1F49.0020.001D] # SQUARE KV +33BE ; [.1DCB.0020.001C][.1F5B.0020.001D] # SQUARE KW +33C0 ; [.1DCB.0020.001C][.2047.0020.001D] # SQUARE K OHM +1D0B ; [.1DCF.0020.0002] # LATIN LETTER SMALL CAPITAL K +1D84 ; [.1DD0.0020.0002] # LATIN SMALL LETTER K WITH PALATAL HOOK +0199 ; [.1DD1.0020.0002] # LATIN SMALL LETTER K WITH HOOK +0198 ; [.1DD1.0020.0008] # LATIN CAPITAL LETTER K WITH HOOK +2C6A ; [.1DD5.0020.0002] # LATIN SMALL LETTER K WITH DESCENDER +2C69 ; [.1DD5.0020.0008] # LATIN CAPITAL LETTER K WITH DESCENDER +A741 ; [.1DD6.0020.0002] # LATIN SMALL LETTER K WITH STROKE +A740 ; [.1DD6.0020.0008] # LATIN CAPITAL LETTER K WITH STROKE +A743 ; [.1DD7.0020.0002] # LATIN SMALL LETTER K WITH DIAGONAL STROKE +A742 ; [.1DD7.0020.0008] # LATIN CAPITAL LETTER K WITH DIAGONAL STROKE +A745 ; [.1DD8.0020.0002] # LATIN SMALL LETTER K WITH STROKE AND DIAGONAL STROKE +A744 ; [.1DD8.0020.0008] # LATIN CAPITAL LETTER K WITH STROKE AND DIAGONAL STROKE +029E ; [.1DD9.0020.0002] # LATIN SMALL LETTER TURNED K +A7B0 ; [.1DD9.0020.0008] # LATIN CAPITAL LETTER TURNED K +006C ; [.1DDD.0020.0002] # LATIN SMALL LETTER L +FF4C ; [.1DDD.0020.0003] # FULLWIDTH LATIN SMALL LETTER L +1DDD ; [.1DDD.0020.0004] # COMBINING LATIN SMALL LETTER L +217C ; [.1DDD.0020.0004] # SMALL ROMAN NUMERAL FIFTY +24A7 ; [*0318.0020.0004][.1DDD.0020.0004][*0319.0020.0004] # PARENTHESIZED LATIN SMALL LETTER L +2113 ; [.1DDD.0020.0005] # SCRIPT SMALL L +1D425 ; [.1DDD.0020.0005] # MATHEMATICAL BOLD SMALL L +1D459 ; [.1DDD.0020.0005] # MATHEMATICAL ITALIC SMALL L +1D48D ; [.1DDD.0020.0005] # MATHEMATICAL BOLD ITALIC SMALL L +1D4C1 ; [.1DDD.0020.0005] # MATHEMATICAL SCRIPT SMALL L +1D4F5 ; [.1DDD.0020.0005] # MATHEMATICAL BOLD SCRIPT SMALL L +1D529 ; [.1DDD.0020.0005] # MATHEMATICAL FRAKTUR SMALL L +1D55D ; [.1DDD.0020.0005] # MATHEMATICAL DOUBLE-STRUCK SMALL L +1D591 ; [.1DDD.0020.0005] # MATHEMATICAL BOLD FRAKTUR SMALL L +1D5C5 ; [.1DDD.0020.0005] # MATHEMATICAL SANS-SERIF SMALL L +1D5F9 ; [.1DDD.0020.0005] # MATHEMATICAL SANS-SERIF BOLD SMALL L +1D62D ; [.1DDD.0020.0005] # MATHEMATICAL SANS-SERIF ITALIC SMALL L +1D661 ; [.1DDD.0020.0005] # MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL L +1D695 ; [.1DDD.0020.0005] # MATHEMATICAL MONOSPACE SMALL L +24DB ; [.1DDD.0020.0006] # CIRCLED LATIN SMALL LETTER L +004C ; [.1DDD.0020.0008] # LATIN CAPITAL LETTER L +FF2C ; [.1DDD.0020.0009] # FULLWIDTH LATIN CAPITAL LETTER L +216C ; [.1DDD.0020.000A] # ROMAN NUMERAL FIFTY +1F11B ; [*0318.0020.0004][.1DDD.0020.000A][*0319.0020.0004] # PARENTHESIZED LATIN CAPITAL LETTER L +2112 ; [.1DDD.0020.000B] # SCRIPT CAPITAL L +1D40B ; [.1DDD.0020.000B] # MATHEMATICAL BOLD CAPITAL L +1D43F ; [.1DDD.0020.000B] # MATHEMATICAL ITALIC CAPITAL L +1D473 ; [.1DDD.0020.000B] # MATHEMATICAL BOLD ITALIC CAPITAL L +1D4DB ; [.1DDD.0020.000B] # MATHEMATICAL BOLD SCRIPT CAPITAL L +1D50F ; [.1DDD.0020.000B] # MATHEMATICAL FRAKTUR CAPITAL L +1D543 ; [.1DDD.0020.000B] # MATHEMATICAL DOUBLE-STRUCK CAPITAL L +1D577 ; [.1DDD.0020.000B] # MATHEMATICAL BOLD FRAKTUR CAPITAL L +1D5AB ; [.1DDD.0020.000B] # MATHEMATICAL SANS-SERIF CAPITAL L +1D5DF ; [.1DDD.0020.000B] # MATHEMATICAL SANS-SERIF BOLD CAPITAL L +1D613 ; [.1DDD.0020.000B] # MATHEMATICAL SANS-SERIF ITALIC CAPITAL L +1D647 ; [.1DDD.0020.000B] # MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL L +1D67B ; [.1DDD.0020.000B] # MATHEMATICAL MONOSPACE CAPITAL L +24C1 ; [.1DDD.0020.000C] # CIRCLED LATIN CAPITAL LETTER L +1F15B ; [.1DDD.0020.000C] # NEGATIVE CIRCLED LATIN CAPITAL LETTER L +02E1 ; [.1DDD.0020.0014] # MODIFIER LETTER SMALL L +2097 ; [.1DDD.0020.0015] # LATIN SUBSCRIPT SMALL LETTER L +1D38 ; [.1DDD.0020.001D] # MODIFIER LETTER CAPITAL L +1F13B ; [.1DDD.0020.001D] # SQUARED LATIN CAPITAL LETTER L +1F17B ; [.1DDD.0020.001D] # NEGATIVE SQUARED LATIN CAPITAL LETTER L +013A ; [.1DDD.0020.0002][.0000.0024.0002] # LATIN SMALL LETTER L WITH ACUTE +0139 ; [.1DDD.0020.0008][.0000.0024.0002] # LATIN CAPITAL LETTER L WITH ACUTE +013E ; [.1DDD.0020.0002][.0000.0028.0002] # LATIN SMALL LETTER L WITH CARON +013D ; [.1DDD.0020.0008][.0000.0028.0002] # LATIN CAPITAL LETTER L WITH CARON +013C ; [.1DDD.0020.0002][.0000.0030.0002] # LATIN SMALL LETTER L WITH CEDILLA +013B ; [.1DDD.0020.0008][.0000.0030.0002] # LATIN CAPITAL LETTER L WITH CEDILLA +0142 ; [.1DDD.0020.0002][.0000.0039.0002] # LATIN SMALL LETTER L WITH STROKE +0141 ; [.1DDD.0020.0008][.0000.0039.0002] # LATIN CAPITAL LETTER L WITH STROKE +1E37 ; [.1DDD.0020.0002][.0000.0042.0002] # LATIN SMALL LETTER L WITH DOT BELOW +1E36 ; [.1DDD.0020.0008][.0000.0042.0002] # LATIN CAPITAL LETTER L WITH DOT BELOW +1E39 ; [.1DDD.0020.0002][.0000.0042.0002][.0000.0032.0002] # LATIN SMALL LETTER L WITH DOT BELOW AND MACRON +1E38 ; [.1DDD.0020.0008][.0000.0042.0002][.0000.0032.0002] # LATIN CAPITAL LETTER L WITH DOT BELOW AND MACRON +1E3D ; [.1DDD.0020.0002][.0000.0046.0002] # LATIN SMALL LETTER L WITH CIRCUMFLEX BELOW +1E3C ; [.1DDD.0020.0008][.0000.0046.0002] # LATIN CAPITAL LETTER L WITH CIRCUMFLEX BELOW +1E3B ; [.1DDD.0020.0002][.0000.0049.0002] # LATIN SMALL LETTER L WITH LINE BELOW +1E3A ; [.1DDD.0020.0008][.0000.0049.0002] # LATIN CAPITAL LETTER L WITH LINE BELOW +0140 ; [.1DDD.0020.0002][.0000.0111.0002] # LATIN SMALL LETTER L WITH MIDDLE DOT +006C 00B7 ; [.1DDD.0020.0002][.0000.0111.0002] # LATIN SMALL LETTER L WITH MIDDLE DOT +006C 0387 ; [.1DDD.0020.0002][.0000.0111.0002] # LATIN SMALL LETTER L WITH MIDDLE DOT +013F ; [.1DDD.0020.0008][.0000.0111.0002] # LATIN CAPITAL LETTER L WITH MIDDLE DOT +004C 00B7 ; [.1DDD.0020.0008][.0000.0111.0002] # LATIN CAPITAL LETTER L WITH MIDDLE DOT +004C 0387 ; [.1DDD.0020.0008][.0000.0111.0002] # LATIN CAPITAL LETTER L WITH MIDDLE DOT +01C9 ; [.1DDD.0020.0004][.1DB2.0020.0004] # LATIN SMALL LETTER LJ +01C8 ; [.1DDD.0020.000A][.1DB2.0020.0004] # LATIN CAPITAL LETTER L WITH SMALL LETTER J +01C7 ; [.1DDD.0020.000A][.1DB2.0020.000A] # LATIN CAPITAL LETTER LJ +1EFB ; [.1DDD.0020.0004][.1DDD.0020.0004] # LATIN SMALL LETTER MIDDLE-WELSH LL +1EFA ; [.1DDD.0020.000A][.1DDD.0020.000A] # LATIN CAPITAL LETTER MIDDLE-WELSH LL +33D0 ; [.1DDD.0020.001C][.1E10.0020.001C] # SQUARE LM +33D1 ; [.1DDD.0020.001C][.1E1F.0020.001C] # SQUARE LN +33D2 ; [.1DDD.0020.001C][.1E43.0020.001C][.1D5A.0020.001C] # SQUARE LOG +1F1A9 ; [.1DDD.0020.001D][.1E43.0020.001C][.1ED7.0020.001C][.1ED7.0020.001C][.1DDD.0020.001C][.1D10.0020.001C][.1ED7.0020.001C][.1ED7.0020.001C] # SQUARED LOSSLESS +02AA ; [.1DDD.0020.0004][.1ED7.0020.0004] # LATIN SMALL LETTER LS DIGRAPH +32CF ; [.1DDD.0020.001D][.1EFB.0020.001D][.1CF5.0020.001D] # LIMITED LIABILITY SIGN +33D3 ; [.1DDD.0020.001C][.1F65.0020.001C] # SQUARE LX +02AB ; [.1DDD.0020.0004][.1F87.0020.0004] # LATIN SMALL LETTER LZ DIGRAPH +029F ; [.1DE1.0020.0002] # LATIN LETTER SMALL CAPITAL L +1DDE ; [.1DE1.0020.0004] # COMBINING LATIN LETTER SMALL CAPITAL L +1DAB ; [.1DE1.0020.0014] # MODIFIER LETTER SMALL CAPITAL L +A747 ; [.1DE5.0020.0002] # LATIN SMALL LETTER BROKEN L +A746 ; [.1DE5.0020.0008] # LATIN CAPITAL LETTER BROKEN L +1D0C ; [.1DE6.0020.0002] # LATIN LETTER SMALL CAPITAL L WITH STROKE +A749 ; [.1DE7.0020.0002] # LATIN SMALL LETTER L WITH HIGH STROKE +A748 ; [.1DE7.0020.0008] # LATIN CAPITAL LETTER L WITH HIGH STROKE +019A ; [.1DE8.0020.0002] # LATIN SMALL LETTER L WITH BAR +023D ; [.1DE8.0020.0008] # LATIN CAPITAL LETTER L WITH BAR +2C61 ; [.1DEC.0020.0002] # LATIN SMALL LETTER L WITH DOUBLE BAR +2C60 ; [.1DEC.0020.0008] # LATIN CAPITAL LETTER L WITH DOUBLE BAR +026B ; [.1DED.0020.0002] # LATIN SMALL LETTER L WITH MIDDLE TILDE +2C62 ; [.1DED.0020.0008] # LATIN CAPITAL LETTER L WITH MIDDLE TILDE +AB5E ; [.1DED.0020.0014] # MODIFIER LETTER SMALL L WITH MIDDLE TILDE +AB38 ; [.1DF1.0020.0002] # LATIN SMALL LETTER L WITH DOUBLE MIDDLE TILDE +1DEC ; [.1DF1.0020.0004] # COMBINING LATIN SMALL LETTER L WITH DOUBLE MIDDLE TILDE +AB39 ; [.1DF2.0020.0002] # LATIN SMALL LETTER L WITH MIDDLE RING +026C ; [.1DF3.0020.0002] # LATIN SMALL LETTER L WITH BELT +A7AD ; [.1DF3.0020.0008] # LATIN CAPITAL LETTER L WITH BELT +AB37 ; [.1DF7.0020.0002] # LATIN SMALL LETTER L WITH INVERTED LAZY S +AB5D ; [.1DF7.0020.0014] # MODIFIER LETTER SMALL L WITH INVERTED LAZY S +1D85 ; [.1DF8.0020.0002] # LATIN SMALL LETTER L WITH PALATAL HOOK +1DAA ; [.1DF8.0020.0014] # MODIFIER LETTER SMALL L WITH PALATAL HOOK +026D ; [.1DF9.0020.0002] # LATIN SMALL LETTER L WITH RETROFLEX HOOK +1DA9 ; [.1DF9.0020.0014] # MODIFIER LETTER SMALL L WITH RETROFLEX HOOK +A78E ; [.1DFD.0020.0002] # LATIN SMALL LETTER L WITH RETROFLEX HOOK AND BELT +0234 ; [.1DFE.0020.0002] # LATIN SMALL LETTER L WITH CURL +A772 ; [.1E02.0020.0002] # LATIN SMALL LETTER LUM +026E ; [.1E03.0020.0002] # LATIN SMALL LETTER LEZH +A781 ; [.1E07.0020.0002] # LATIN SMALL LETTER TURNED L +A780 ; [.1E07.0020.0008] # LATIN CAPITAL LETTER TURNED L +019B ; [.1E08.0020.0002] # LATIN SMALL LETTER LAMBDA WITH STROKE +028E ; [.1E0C.0020.0002] # LATIN SMALL LETTER TURNED Y +006D ; [.1E10.0020.0002] # LATIN SMALL LETTER M +FF4D ; [.1E10.0020.0003] # FULLWIDTH LATIN SMALL LETTER M +036B ; [.1E10.0020.0004] # COMBINING LATIN SMALL LETTER M +217F ; [.1E10.0020.0004] # SMALL ROMAN NUMERAL ONE THOUSAND +24A8 ; [*0318.0020.0004][.1E10.0020.0004][*0319.0020.0004] # PARENTHESIZED LATIN SMALL LETTER M +1D426 ; [.1E10.0020.0005] # MATHEMATICAL BOLD SMALL M +1D45A ; [.1E10.0020.0005] # MATHEMATICAL ITALIC SMALL M +1D48E ; [.1E10.0020.0005] # MATHEMATICAL BOLD ITALIC SMALL M +1D4C2 ; [.1E10.0020.0005] # MATHEMATICAL SCRIPT SMALL M +1D4F6 ; [.1E10.0020.0005] # MATHEMATICAL BOLD SCRIPT SMALL M +1D52A ; [.1E10.0020.0005] # MATHEMATICAL FRAKTUR SMALL M +1D55E ; [.1E10.0020.0005] # MATHEMATICAL DOUBLE-STRUCK SMALL M +1D592 ; [.1E10.0020.0005] # MATHEMATICAL BOLD FRAKTUR SMALL M +1D5C6 ; [.1E10.0020.0005] # MATHEMATICAL SANS-SERIF SMALL M +1D5FA ; [.1E10.0020.0005] # MATHEMATICAL SANS-SERIF BOLD SMALL M +1D62E ; [.1E10.0020.0005] # MATHEMATICAL SANS-SERIF ITALIC SMALL M +1D662 ; [.1E10.0020.0005] # MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL M +1D696 ; [.1E10.0020.0005] # MATHEMATICAL MONOSPACE SMALL M +24DC ; [.1E10.0020.0006] # CIRCLED LATIN SMALL LETTER M +004D ; [.1E10.0020.0008] # LATIN CAPITAL LETTER M +FF2D ; [.1E10.0020.0009] # FULLWIDTH LATIN CAPITAL LETTER M +216F ; [.1E10.0020.000A] # ROMAN NUMERAL ONE THOUSAND +1F11C ; [*0318.0020.0004][.1E10.0020.000A][*0319.0020.0004] # PARENTHESIZED LATIN CAPITAL LETTER M +2133 ; [.1E10.0020.000B] # SCRIPT CAPITAL M +1D40C ; [.1E10.0020.000B] # MATHEMATICAL BOLD CAPITAL M +1D440 ; [.1E10.0020.000B] # MATHEMATICAL ITALIC CAPITAL M +1D474 ; [.1E10.0020.000B] # MATHEMATICAL BOLD ITALIC CAPITAL M +1D4DC ; [.1E10.0020.000B] # MATHEMATICAL BOLD SCRIPT CAPITAL M +1D510 ; [.1E10.0020.000B] # MATHEMATICAL FRAKTUR CAPITAL M +1D544 ; [.1E10.0020.000B] # MATHEMATICAL DOUBLE-STRUCK CAPITAL M +1D578 ; [.1E10.0020.000B] # MATHEMATICAL BOLD FRAKTUR CAPITAL M +1D5AC ; [.1E10.0020.000B] # MATHEMATICAL SANS-SERIF CAPITAL M +1D5E0 ; [.1E10.0020.000B] # MATHEMATICAL SANS-SERIF BOLD CAPITAL M +1D614 ; [.1E10.0020.000B] # MATHEMATICAL SANS-SERIF ITALIC CAPITAL M +1D648 ; [.1E10.0020.000B] # MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL M +1D67C ; [.1E10.0020.000B] # MATHEMATICAL MONOSPACE CAPITAL M +24C2 ; [.1E10.0020.000C] # CIRCLED LATIN CAPITAL LETTER M +1F15C ; [.1E10.0020.000C] # NEGATIVE CIRCLED LATIN CAPITAL LETTER M +1D50 ; [.1E10.0020.0014] # MODIFIER LETTER SMALL M +2098 ; [.1E10.0020.0015] # LATIN SUBSCRIPT SMALL LETTER M +1D39 ; [.1E10.0020.001D] # MODIFIER LETTER CAPITAL M +1F13C ; [.1E10.0020.001D] # SQUARED LATIN CAPITAL LETTER M +1F17C ; [.1E10.0020.001D] # NEGATIVE SQUARED LATIN CAPITAL LETTER M +1E3F ; [.1E10.0020.0002][.0000.0024.0002] # LATIN SMALL LETTER M WITH ACUTE +1E3E ; [.1E10.0020.0008][.0000.0024.0002] # LATIN CAPITAL LETTER M WITH ACUTE +1E41 ; [.1E10.0020.0002][.0000.002E.0002] # LATIN SMALL LETTER M WITH DOT ABOVE +1E40 ; [.1E10.0020.0008][.0000.002E.0002] # LATIN CAPITAL LETTER M WITH DOT ABOVE +1E43 ; [.1E10.0020.0002][.0000.0042.0002] # LATIN SMALL LETTER M WITH DOT BELOW +1E42 ; [.1E10.0020.0008][.0000.0042.0002] # LATIN CAPITAL LETTER M WITH DOT BELOW +33A1 ; [.1E10.0020.001C][.1CA5.0020.001C] # SQUARE M SQUARED +33A5 ; [.1E10.0020.001C][.1CA6.0020.001C] # SQUARE M CUBED +3383 ; [.1E10.0020.001C][.1CAD.0020.001D] # SQUARE MA +33D4 ; [.1E10.0020.001C][.1CC6.0020.001C] # SQUARE MB SMALL +3386 ; [.1E10.0020.001D][.1CC6.0020.001D] # SQUARE MB +1F16A ; [.1E10.0020.0014][.1CE0.0020.0014] # RAISED MC SIGN +1F16B ; [.1E10.0020.0014][.1CF5.0020.0014] # RAISED MD SIGN +338E ; [.1E10.0020.001C][.1D5A.0020.001C] # SQUARE MG +3392 ; [.1E10.0020.001D][.1D7E.0020.001D][.1F87.0020.001C] # SQUARE MHZ +33D5 ; [.1E10.0020.001C][.1D98.0020.001C][.1DDD.0020.001C] # SQUARE MIL +3396 ; [.1E10.0020.001C][.1DDD.0020.001C] # SQUARE ML +339C ; [.1E10.0020.001C][.1E10.0020.001C] # SQUARE MM +339F ; [.1E10.0020.001C][.1E10.0020.001C][.1CA5.0020.001C] # SQUARE MM SQUARED +33A3 ; [.1E10.0020.001C][.1E10.0020.001C][.1CA6.0020.001C] # SQUARE MM CUBED +33D6 ; [.1E10.0020.001C][.1E43.0020.001C][.1DDD.0020.001C] # SQUARE MOL +33AB ; [.1E10.0020.001D][.1E72.0020.001D][.1CAD.0020.001C] # SQUARE MPA +33A7 ; [.1E10.0020.001C][*063B.0020.001C][.1ED7.0020.001C] # SQUARE M OVER S +33B3 ; [.1E10.0020.001C][.1ED7.0020.001C] # SQUARE MS +33A8 ; [.1E10.0020.001C][*063B.0020.001C][.1ED7.0020.001C][.1CA5.0020.001C] # SQUARE M OVER S SQUARED +33B7 ; [.1E10.0020.001C][.1F49.0020.001D] # SQUARE MV +33B9 ; [.1E10.0020.001D][.1F49.0020.001D] # SQUARE MV MEGA +1F14B ; [.1E10.0020.001D][.1F49.0020.001D] # SQUARED MV +33BD ; [.1E10.0020.001C][.1F5B.0020.001D] # SQUARE MW +33BF ; [.1E10.0020.001D][.1F5B.0020.001D] # SQUARE MW MEGA +33C1 ; [.1E10.0020.001D][.2047.0020.001D] # SQUARE M OHM +1D0D ; [.1E14.0020.0002] # LATIN LETTER SMALL CAPITAL M +1DDF ; [.1E14.0020.0004] # COMBINING LATIN LETTER SMALL CAPITAL M +1D6F ; [.1E15.0020.0002] # LATIN SMALL LETTER M WITH MIDDLE TILDE +1D86 ; [.1E16.0020.0002] # LATIN SMALL LETTER M WITH PALATAL HOOK +0271 ; [.1E17.0020.0002] # LATIN SMALL LETTER M WITH HOOK +2C6E ; [.1E17.0020.0008] # LATIN CAPITAL LETTER M WITH HOOK +1DAC ; [.1E17.0020.0014] # MODIFIER LETTER SMALL M WITH HOOK +AB3A ; [.1E1B.0020.0002] # LATIN SMALL LETTER M WITH CROSSED-TAIL +A7FD ; [.1E1C.0020.0002] # LATIN EPIGRAPHIC LETTER INVERTED M +A7FF ; [.1E1D.0020.0002] # LATIN EPIGRAPHIC LETTER ARCHAIC M +A773 ; [.1E1E.0020.0002] # LATIN SMALL LETTER MUM +006E ; [.1E1F.0020.0002] # LATIN SMALL LETTER N +FF4E ; [.1E1F.0020.0003] # FULLWIDTH LATIN SMALL LETTER N +1DE0 ; [.1E1F.0020.0004] # COMBINING LATIN SMALL LETTER N +24A9 ; [*0318.0020.0004][.1E1F.0020.0004][*0319.0020.0004] # PARENTHESIZED LATIN SMALL LETTER N +1D427 ; [.1E1F.0020.0005] # MATHEMATICAL BOLD SMALL N +1D45B ; [.1E1F.0020.0005] # MATHEMATICAL ITALIC SMALL N +1D48F ; [.1E1F.0020.0005] # MATHEMATICAL BOLD ITALIC SMALL N +1D4C3 ; [.1E1F.0020.0005] # MATHEMATICAL SCRIPT SMALL N +1D4F7 ; [.1E1F.0020.0005] # MATHEMATICAL BOLD SCRIPT SMALL N +1D52B ; [.1E1F.0020.0005] # MATHEMATICAL FRAKTUR SMALL N +1D55F ; [.1E1F.0020.0005] # MATHEMATICAL DOUBLE-STRUCK SMALL N +1D593 ; [.1E1F.0020.0005] # MATHEMATICAL BOLD FRAKTUR SMALL N +1D5C7 ; [.1E1F.0020.0005] # MATHEMATICAL SANS-SERIF SMALL N +1D5FB ; [.1E1F.0020.0005] # MATHEMATICAL SANS-SERIF BOLD SMALL N +1D62F ; [.1E1F.0020.0005] # MATHEMATICAL SANS-SERIF ITALIC SMALL N +1D663 ; [.1E1F.0020.0005] # MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL N +1D697 ; [.1E1F.0020.0005] # MATHEMATICAL MONOSPACE SMALL N +24DD ; [.1E1F.0020.0006] # CIRCLED LATIN SMALL LETTER N +004E ; [.1E1F.0020.0008] # LATIN CAPITAL LETTER N +FF2E ; [.1E1F.0020.0009] # FULLWIDTH LATIN CAPITAL LETTER N +1F11D ; [*0318.0020.0004][.1E1F.0020.000A][*0319.0020.0004] # PARENTHESIZED LATIN CAPITAL LETTER N +2115 ; [.1E1F.0020.000B] # DOUBLE-STRUCK CAPITAL N +1D40D ; [.1E1F.0020.000B] # MATHEMATICAL BOLD CAPITAL N +1D441 ; [.1E1F.0020.000B] # MATHEMATICAL ITALIC CAPITAL N +1D475 ; [.1E1F.0020.000B] # MATHEMATICAL BOLD ITALIC CAPITAL N +1D4A9 ; [.1E1F.0020.000B] # MATHEMATICAL SCRIPT CAPITAL N +1D4DD ; [.1E1F.0020.000B] # MATHEMATICAL BOLD SCRIPT CAPITAL N +1D511 ; [.1E1F.0020.000B] # MATHEMATICAL FRAKTUR CAPITAL N +1D579 ; [.1E1F.0020.000B] # MATHEMATICAL BOLD FRAKTUR CAPITAL N +1D5AD ; [.1E1F.0020.000B] # MATHEMATICAL SANS-SERIF CAPITAL N +1D5E1 ; [.1E1F.0020.000B] # MATHEMATICAL SANS-SERIF BOLD CAPITAL N +1D615 ; [.1E1F.0020.000B] # MATHEMATICAL SANS-SERIF ITALIC CAPITAL N +1D649 ; [.1E1F.0020.000B] # MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL N +1D67D ; [.1E1F.0020.000B] # MATHEMATICAL MONOSPACE CAPITAL N +24C3 ; [.1E1F.0020.000C] # CIRCLED LATIN CAPITAL LETTER N +1F15D ; [.1E1F.0020.000C] # NEGATIVE CIRCLED LATIN CAPITAL LETTER N +207F ; [.1E1F.0020.0014] # SUPERSCRIPT LATIN SMALL LETTER N +2099 ; [.1E1F.0020.0015] # LATIN SUBSCRIPT SMALL LETTER N +1D3A ; [.1E1F.0020.001D] # MODIFIER LETTER CAPITAL N +1F13D ; [.1E1F.0020.001D] # SQUARED LATIN CAPITAL LETTER N +1F17D ; [.1E1F.0020.001D] # NEGATIVE SQUARED LATIN CAPITAL LETTER N +0144 ; [.1E1F.0020.0002][.0000.0024.0002] # LATIN SMALL LETTER N WITH ACUTE +0143 ; [.1E1F.0020.0008][.0000.0024.0002] # LATIN CAPITAL LETTER N WITH ACUTE +01F9 ; [.1E1F.0020.0002][.0000.0025.0002] # LATIN SMALL LETTER N WITH GRAVE +01F8 ; [.1E1F.0020.0008][.0000.0025.0002] # LATIN CAPITAL LETTER N WITH GRAVE +0148 ; [.1E1F.0020.0002][.0000.0028.0002] # LATIN SMALL LETTER N WITH CARON +0147 ; [.1E1F.0020.0008][.0000.0028.0002] # LATIN CAPITAL LETTER N WITH CARON +00F1 ; [.1E1F.0020.0002][.0000.002D.0002] # LATIN SMALL LETTER N WITH TILDE +00D1 ; [.1E1F.0020.0008][.0000.002D.0002] # LATIN CAPITAL LETTER N WITH TILDE +1E45 ; [.1E1F.0020.0002][.0000.002E.0002] # LATIN SMALL LETTER N WITH DOT ABOVE +1E44 ; [.1E1F.0020.0008][.0000.002E.0002] # LATIN CAPITAL LETTER N WITH DOT ABOVE +0146 ; [.1E1F.0020.0002][.0000.0030.0002] # LATIN SMALL LETTER N WITH CEDILLA +0145 ; [.1E1F.0020.0008][.0000.0030.0002] # LATIN CAPITAL LETTER N WITH CEDILLA +A7A5 ; [.1E1F.0020.0004][.0000.0035.0004] # LATIN SMALL LETTER N WITH OBLIQUE STROKE +A7A4 ; [.1E1F.0020.000A][.0000.0035.0004] # LATIN CAPITAL LETTER N WITH OBLIQUE STROKE +1E47 ; [.1E1F.0020.0002][.0000.0042.0002] # LATIN SMALL LETTER N WITH DOT BELOW +1E46 ; [.1E1F.0020.0008][.0000.0042.0002] # LATIN CAPITAL LETTER N WITH DOT BELOW +1E4B ; [.1E1F.0020.0002][.0000.0046.0002] # LATIN SMALL LETTER N WITH CIRCUMFLEX BELOW +1E4A ; [.1E1F.0020.0008][.0000.0046.0002] # LATIN CAPITAL LETTER N WITH CIRCUMFLEX BELOW +1E49 ; [.1E1F.0020.0002][.0000.0049.0002] # LATIN SMALL LETTER N WITH LINE BELOW +1E48 ; [.1E1F.0020.0008][.0000.0049.0002] # LATIN CAPITAL LETTER N WITH LINE BELOW +3381 ; [.1E1F.0020.001C][.1CAD.0020.001D] # SQUARE NA +1F195 ; [.1E1F.0020.001D][.1D10.0020.001D][.1F5B.0020.001D] # SQUARED NEW +338B ; [.1E1F.0020.001C][.1D4B.0020.001D] # SQUARE NF +1F196 ; [.1E1F.0020.001D][.1D5A.0020.001D] # SQUARED NG +01CC ; [.1E1F.0020.0004][.1DB2.0020.0004] # LATIN SMALL LETTER NJ +01CB ; [.1E1F.0020.000A][.1DB2.0020.0004] # LATIN CAPITAL LETTER N WITH SMALL LETTER J +01CA ; [.1E1F.0020.000A][.1DB2.0020.000A] # LATIN CAPITAL LETTER NJ +339A ; [.1E1F.0020.001C][.1E10.0020.001C] # SQUARE NM +2116 ; [.1E1F.0020.000A][.1E43.0020.0004] # NUMERO SIGN +33B1 ; [.1E1F.0020.001C][.1ED7.0020.001C] # SQUARE NS +33B5 ; [.1E1F.0020.001C][.1F49.0020.001D] # SQUARE NV +33BB ; [.1E1F.0020.001C][.1F5B.0020.001D] # SQUARE NW +0274 ; [.1E23.0020.0002] # LATIN LETTER SMALL CAPITAL N +1DE1 ; [.1E23.0020.0004] # COMBINING LATIN LETTER SMALL CAPITAL N +1DB0 ; [.1E23.0020.0014] # MODIFIER LETTER SMALL CAPITAL N +1D3B ; [.1E27.0020.0002] # MODIFIER LETTER CAPITAL REVERSED N +1D0E ; [.1E28.0020.0002] # LATIN LETTER SMALL CAPITAL REVERSED N +1D70 ; [.1E29.0020.0002] # LATIN SMALL LETTER N WITH MIDDLE TILDE +0272 ; [.1E2A.0020.0002] # LATIN SMALL LETTER N WITH LEFT HOOK +019D ; [.1E2A.0020.0008] # LATIN CAPITAL LETTER N WITH LEFT HOOK +1DAE ; [.1E2A.0020.0014] # MODIFIER LETTER SMALL N WITH LEFT HOOK +019E ; [.1E2E.0020.0002] # LATIN SMALL LETTER N WITH LONG RIGHT LEG +0220 ; [.1E2E.0020.0008] # LATIN CAPITAL LETTER N WITH LONG RIGHT LEG +A791 ; [.1E32.0020.0002] # LATIN SMALL LETTER N WITH DESCENDER +A790 ; [.1E32.0020.0008] # LATIN CAPITAL LETTER N WITH DESCENDER +1D87 ; [.1E33.0020.0002] # LATIN SMALL LETTER N WITH PALATAL HOOK +0273 ; [.1E34.0020.0002] # LATIN SMALL LETTER N WITH RETROFLEX HOOK +1DAF ; [.1E34.0020.0014] # MODIFIER LETTER SMALL N WITH RETROFLEX HOOK +0235 ; [.1E38.0020.0002] # LATIN SMALL LETTER N WITH CURL +AB3B ; [.1E3C.0020.0002] # LATIN SMALL LETTER N WITH CROSSED-TAIL +A774 ; [.1E3D.0020.0002] # LATIN SMALL LETTER NUM +014B ; [.1E3E.0020.0002] # LATIN SMALL LETTER ENG +014A ; [.1E3E.0020.0008] # LATIN CAPITAL LETTER ENG +1D51 ; [.1E3E.0020.0014] # MODIFIER LETTER SMALL ENG +AB3C ; [.1E42.0020.0002] # LATIN SMALL LETTER ENG WITH CROSSED-TAIL +006F ; [.1E43.0020.0002] # LATIN SMALL LETTER O +FF4F ; [.1E43.0020.0003] # FULLWIDTH LATIN SMALL LETTER O +0366 ; [.1E43.0020.0004] # COMBINING LATIN SMALL LETTER O +24AA ; [*0318.0020.0004][.1E43.0020.0004][*0319.0020.0004] # PARENTHESIZED LATIN SMALL LETTER O +2134 ; [.1E43.0020.0005] # SCRIPT SMALL O +1D428 ; [.1E43.0020.0005] # MATHEMATICAL BOLD SMALL O +1D45C ; [.1E43.0020.0005] # MATHEMATICAL ITALIC SMALL O +1D490 ; [.1E43.0020.0005] # MATHEMATICAL BOLD ITALIC SMALL O +1D4F8 ; [.1E43.0020.0005] # MATHEMATICAL BOLD SCRIPT SMALL O +1D52C ; [.1E43.0020.0005] # MATHEMATICAL FRAKTUR SMALL O +1D560 ; [.1E43.0020.0005] # MATHEMATICAL DOUBLE-STRUCK SMALL O +1D594 ; [.1E43.0020.0005] # MATHEMATICAL BOLD FRAKTUR SMALL O +1D5C8 ; [.1E43.0020.0005] # MATHEMATICAL SANS-SERIF SMALL O +1D5FC ; [.1E43.0020.0005] # MATHEMATICAL SANS-SERIF BOLD SMALL O +1D630 ; [.1E43.0020.0005] # MATHEMATICAL SANS-SERIF ITALIC SMALL O +1D664 ; [.1E43.0020.0005] # MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL O +1D698 ; [.1E43.0020.0005] # MATHEMATICAL MONOSPACE SMALL O +24DE ; [.1E43.0020.0006] # CIRCLED LATIN SMALL LETTER O +004F ; [.1E43.0020.0008] # LATIN CAPITAL LETTER O +FF2F ; [.1E43.0020.0009] # FULLWIDTH LATIN CAPITAL LETTER O +1F11E ; [*0318.0020.0004][.1E43.0020.000A][*0319.0020.0004] # PARENTHESIZED LATIN CAPITAL LETTER O +1D40E ; [.1E43.0020.000B] # MATHEMATICAL BOLD CAPITAL O +1D442 ; [.1E43.0020.000B] # MATHEMATICAL ITALIC CAPITAL O +1D476 ; [.1E43.0020.000B] # MATHEMATICAL BOLD ITALIC CAPITAL O +1D4AA ; [.1E43.0020.000B] # MATHEMATICAL SCRIPT CAPITAL O +1D4DE ; [.1E43.0020.000B] # MATHEMATICAL BOLD SCRIPT CAPITAL O +1D512 ; [.1E43.0020.000B] # MATHEMATICAL FRAKTUR CAPITAL O +1D546 ; [.1E43.0020.000B] # MATHEMATICAL DOUBLE-STRUCK CAPITAL O +1D57A ; [.1E43.0020.000B] # MATHEMATICAL BOLD FRAKTUR CAPITAL O +1D5AE ; [.1E43.0020.000B] # MATHEMATICAL SANS-SERIF CAPITAL O +1D5E2 ; [.1E43.0020.000B] # MATHEMATICAL SANS-SERIF BOLD CAPITAL O +1D616 ; [.1E43.0020.000B] # MATHEMATICAL SANS-SERIF ITALIC CAPITAL O +1D64A ; [.1E43.0020.000B] # MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL O +1D67E ; [.1E43.0020.000B] # MATHEMATICAL MONOSPACE CAPITAL O +24C4 ; [.1E43.0020.000C] # CIRCLED LATIN CAPITAL LETTER O +1F15E ; [.1E43.0020.000C] # NEGATIVE CIRCLED LATIN CAPITAL LETTER O +00BA ; [.1E43.0020.0014] # MASCULINE ORDINAL INDICATOR +1D52 ; [.1E43.0020.0014] # MODIFIER LETTER SMALL O +2092 ; [.1E43.0020.0015] # LATIN SUBSCRIPT SMALL LETTER O +1D3C ; [.1E43.0020.001D] # MODIFIER LETTER CAPITAL O +1F13E ; [.1E43.0020.001D] # SQUARED LATIN CAPITAL LETTER O +1F17E ; [.1E43.0020.001D] # NEGATIVE SQUARED LATIN CAPITAL LETTER O +00F3 ; [.1E43.0020.0002][.0000.0024.0002] # LATIN SMALL LETTER O WITH ACUTE +00D3 ; [.1E43.0020.0008][.0000.0024.0002] # LATIN CAPITAL LETTER O WITH ACUTE +00F2 ; [.1E43.0020.0002][.0000.0025.0002] # LATIN SMALL LETTER O WITH GRAVE +00D2 ; [.1E43.0020.0008][.0000.0025.0002] # LATIN CAPITAL LETTER O WITH GRAVE +014F ; [.1E43.0020.0002][.0000.0026.0002] # LATIN SMALL LETTER O WITH BREVE +014E ; [.1E43.0020.0008][.0000.0026.0002] # LATIN CAPITAL LETTER O WITH BREVE +00F4 ; [.1E43.0020.0002][.0000.0027.0002] # LATIN SMALL LETTER O WITH CIRCUMFLEX +00D4 ; [.1E43.0020.0008][.0000.0027.0002] # LATIN CAPITAL LETTER O WITH CIRCUMFLEX +1ED1 ; [.1E43.0020.0002][.0000.0027.0002][.0000.0024.0002] # LATIN SMALL LETTER O WITH CIRCUMFLEX AND ACUTE +1ED0 ; [.1E43.0020.0008][.0000.0027.0002][.0000.0024.0002] # LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND ACUTE +1ED3 ; [.1E43.0020.0002][.0000.0027.0002][.0000.0025.0002] # LATIN SMALL LETTER O WITH CIRCUMFLEX AND GRAVE +1ED2 ; [.1E43.0020.0008][.0000.0027.0002][.0000.0025.0002] # LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND GRAVE +1ED7 ; [.1E43.0020.0002][.0000.0027.0002][.0000.002D.0002] # LATIN SMALL LETTER O WITH CIRCUMFLEX AND TILDE +1ED6 ; [.1E43.0020.0008][.0000.0027.0002][.0000.002D.0002] # LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND TILDE +1ED5 ; [.1E43.0020.0002][.0000.0027.0002][.0000.003B.0002] # LATIN SMALL LETTER O WITH CIRCUMFLEX AND HOOK ABOVE +1ED4 ; [.1E43.0020.0008][.0000.0027.0002][.0000.003B.0002] # LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND HOOK ABOVE +01D2 ; [.1E43.0020.0002][.0000.0028.0002] # LATIN SMALL LETTER O WITH CARON +01D1 ; [.1E43.0020.0008][.0000.0028.0002] # LATIN CAPITAL LETTER O WITH CARON +00F6 ; [.1E43.0020.0002][.0000.002B.0002] # LATIN SMALL LETTER O WITH DIAERESIS +1DF3 ; [.1E43.0020.0004][.0000.002B.0004] # COMBINING LATIN SMALL LETTER O WITH DIAERESIS +A79D ; [.1E43.0020.0004][.0000.002B.0004] # LATIN SMALL LETTER VOLAPUK OE +00D6 ; [.1E43.0020.0008][.0000.002B.0002] # LATIN CAPITAL LETTER O WITH DIAERESIS +A79C ; [.1E43.0020.000A][.0000.002B.0004] # LATIN CAPITAL LETTER VOLAPUK OE +022B ; [.1E43.0020.0002][.0000.002B.0002][.0000.0032.0002] # LATIN SMALL LETTER O WITH DIAERESIS AND MACRON +022A ; [.1E43.0020.0008][.0000.002B.0002][.0000.0032.0002] # LATIN CAPITAL LETTER O WITH DIAERESIS AND MACRON +0151 ; [.1E43.0020.0002][.0000.002C.0002] # LATIN SMALL LETTER O WITH DOUBLE ACUTE +0150 ; [.1E43.0020.0008][.0000.002C.0002] # LATIN CAPITAL LETTER O WITH DOUBLE ACUTE +00F5 ; [.1E43.0020.0002][.0000.002D.0002] # LATIN SMALL LETTER O WITH TILDE +00D5 ; [.1E43.0020.0008][.0000.002D.0002] # LATIN CAPITAL LETTER O WITH TILDE +1E4D ; [.1E43.0020.0002][.0000.002D.0002][.0000.0024.0002] # LATIN SMALL LETTER O WITH TILDE AND ACUTE +1E4C ; [.1E43.0020.0008][.0000.002D.0002][.0000.0024.0002] # LATIN CAPITAL LETTER O WITH TILDE AND ACUTE +1E4F ; [.1E43.0020.0002][.0000.002D.0002][.0000.002B.0002] # LATIN SMALL LETTER O WITH TILDE AND DIAERESIS +1E4E ; [.1E43.0020.0008][.0000.002D.0002][.0000.002B.0002] # LATIN CAPITAL LETTER O WITH TILDE AND DIAERESIS +022D ; [.1E43.0020.0002][.0000.002D.0002][.0000.0032.0002] # LATIN SMALL LETTER O WITH TILDE AND MACRON +022C ; [.1E43.0020.0008][.0000.002D.0002][.0000.0032.0002] # LATIN CAPITAL LETTER O WITH TILDE AND MACRON +022F ; [.1E43.0020.0002][.0000.002E.0002] # LATIN SMALL LETTER O WITH DOT ABOVE +022E ; [.1E43.0020.0008][.0000.002E.0002] # LATIN CAPITAL LETTER O WITH DOT ABOVE +0231 ; [.1E43.0020.0002][.0000.002E.0002][.0000.0032.0002] # LATIN SMALL LETTER O WITH DOT ABOVE AND MACRON +0230 ; [.1E43.0020.0008][.0000.002E.0002][.0000.0032.0002] # LATIN CAPITAL LETTER O WITH DOT ABOVE AND MACRON +00F8 ; [.1E43.0020.0002][.0000.002F.0002] # LATIN SMALL LETTER O WITH STROKE +00D8 ; [.1E43.0020.0008][.0000.002F.0002] # LATIN CAPITAL LETTER O WITH STROKE +01FF ; [.1E43.0020.0002][.0000.002F.0002][.0000.0024.0002] # LATIN SMALL LETTER O WITH STROKE AND ACUTE +01FE ; [.1E43.0020.0008][.0000.002F.0002][.0000.0024.0002] # LATIN CAPITAL LETTER O WITH STROKE AND ACUTE +01EB ; [.1E43.0020.0002][.0000.0031.0002] # LATIN SMALL LETTER O WITH OGONEK +01EA ; [.1E43.0020.0008][.0000.0031.0002] # LATIN CAPITAL LETTER O WITH OGONEK +01ED ; [.1E43.0020.0002][.0000.0031.0002][.0000.0032.0002] # LATIN SMALL LETTER O WITH OGONEK AND MACRON +01EC ; [.1E43.0020.0008][.0000.0031.0002][.0000.0032.0002] # LATIN CAPITAL LETTER O WITH OGONEK AND MACRON +014D ; [.1E43.0020.0002][.0000.0032.0002] # LATIN SMALL LETTER O WITH MACRON +014C ; [.1E43.0020.0008][.0000.0032.0002] # LATIN CAPITAL LETTER O WITH MACRON +1E53 ; [.1E43.0020.0002][.0000.0032.0002][.0000.0024.0002] # LATIN SMALL LETTER O WITH MACRON AND ACUTE +1E52 ; [.1E43.0020.0008][.0000.0032.0002][.0000.0024.0002] # LATIN CAPITAL LETTER O WITH MACRON AND ACUTE +1E51 ; [.1E43.0020.0002][.0000.0032.0002][.0000.0025.0002] # LATIN SMALL LETTER O WITH MACRON AND GRAVE +1E50 ; [.1E43.0020.0008][.0000.0032.0002][.0000.0025.0002] # LATIN CAPITAL LETTER O WITH MACRON AND GRAVE +1DED ; [.1E43.0020.0004][.0000.0034.0004] # COMBINING LATIN SMALL LETTER O WITH LIGHT CENTRALIZATION STROKE +1ECF ; [.1E43.0020.0002][.0000.003B.0002] # LATIN SMALL LETTER O WITH HOOK ABOVE +1ECE ; [.1E43.0020.0008][.0000.003B.0002] # LATIN CAPITAL LETTER O WITH HOOK ABOVE +020D ; [.1E43.0020.0002][.0000.003C.0002] # LATIN SMALL LETTER O WITH DOUBLE GRAVE +020C ; [.1E43.0020.0008][.0000.003C.0002] # LATIN CAPITAL LETTER O WITH DOUBLE GRAVE +020F ; [.1E43.0020.0002][.0000.003E.0002] # LATIN SMALL LETTER O WITH INVERTED BREVE +020E ; [.1E43.0020.0008][.0000.003E.0002] # LATIN CAPITAL LETTER O WITH INVERTED BREVE +01A1 ; [.1E43.0020.0002][.0000.003F.0002] # LATIN SMALL LETTER O WITH HORN +01A0 ; [.1E43.0020.0008][.0000.003F.0002] # LATIN CAPITAL LETTER O WITH HORN +1EDB ; [.1E43.0020.0002][.0000.003F.0002][.0000.0024.0002] # LATIN SMALL LETTER O WITH HORN AND ACUTE +1EDA ; [.1E43.0020.0008][.0000.003F.0002][.0000.0024.0002] # LATIN CAPITAL LETTER O WITH HORN AND ACUTE +1EDD ; [.1E43.0020.0002][.0000.003F.0002][.0000.0025.0002] # LATIN SMALL LETTER O WITH HORN AND GRAVE +1EDC ; [.1E43.0020.0008][.0000.003F.0002][.0000.0025.0002] # LATIN CAPITAL LETTER O WITH HORN AND GRAVE +1EE1 ; [.1E43.0020.0002][.0000.003F.0002][.0000.002D.0002] # LATIN SMALL LETTER O WITH HORN AND TILDE +1EE0 ; [.1E43.0020.0008][.0000.003F.0002][.0000.002D.0002] # LATIN CAPITAL LETTER O WITH HORN AND TILDE +1EDF ; [.1E43.0020.0002][.0000.003F.0002][.0000.003B.0002] # LATIN SMALL LETTER O WITH HORN AND HOOK ABOVE +1EDE ; [.1E43.0020.0008][.0000.003F.0002][.0000.003B.0002] # LATIN CAPITAL LETTER O WITH HORN AND HOOK ABOVE +1EE3 ; [.1E43.0020.0002][.0000.003F.0002][.0000.0042.0002] # LATIN SMALL LETTER O WITH HORN AND DOT BELOW +1EE2 ; [.1E43.0020.0008][.0000.003F.0002][.0000.0042.0002] # LATIN CAPITAL LETTER O WITH HORN AND DOT BELOW +1ECD ; [.1E43.0020.0002][.0000.0042.0002] # LATIN SMALL LETTER O WITH DOT BELOW +1ECC ; [.1E43.0020.0008][.0000.0042.0002] # LATIN CAPITAL LETTER O WITH DOT BELOW +1ED9 ; [.1E43.0020.0002][.0000.0042.0002][.0000.0027.0002] # LATIN SMALL LETTER O WITH CIRCUMFLEX AND DOT BELOW +1ED8 ; [.1E43.0020.0008][.0000.0042.0002][.0000.0027.0002] # LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND DOT BELOW +0153 ; [.1E43.0020.0004][.0000.0111.0004][.1D10.0020.0004] # LATIN SMALL LIGATURE OE +0152 ; [.1E43.0020.000A][.0000.0111.0004][.1D10.0020.000A] # LATIN CAPITAL LIGATURE OE +A7F9 ; [.1E43.0020.0014][.0000.0111.0014][.1D10.0020.0014] # MODIFIER LETTER SMALL LIGATURE OE +1F197 ; [.1E43.0020.001D][.1DCB.0020.001D] # SQUARED OK +A74F ; [.1E43.0020.0004][.1E43.0020.0004] # LATIN SMALL LETTER OO +A74E ; [.1E43.0020.000A][.1E43.0020.000A] # LATIN CAPITAL LETTER OO +3375 ; [.1E43.0020.001C][.1F49.0020.001D] # SQUARE OV +1D0F ; [.1E47.0020.0002] # LATIN LETTER SMALL CAPITAL O +1D11 ; [.1E48.0020.0002] # LATIN SMALL LETTER SIDEWAYS O +AB3D ; [.1E49.0020.0002] # LATIN SMALL LETTER BLACKLETTER O +0276 ; [.1E4A.0020.0002] # LATIN LETTER SMALL CAPITAL OE +1D14 ; [.1E4E.0020.0002] # LATIN SMALL LETTER TURNED OE +AB41 ; [.1E4F.0020.0002] # LATIN SMALL LETTER TURNED OE WITH STROKE +AB42 ; [.1E50.0020.0002] # LATIN SMALL LETTER TURNED OE WITH HORIZONTAL STROKE +AB40 ; [.1E51.0020.0002] # LATIN SMALL LETTER INVERTED OE +AB43 ; [.1E52.0020.0002] # LATIN SMALL LETTER TURNED O OPEN-O +AB44 ; [.1E53.0020.0002] # LATIN SMALL LETTER TURNED O OPEN-O WITH STROKE +1D13 ; [.1E54.0020.0002] # LATIN SMALL LETTER SIDEWAYS O WITH STROKE +AB3E ; [.1E55.0020.0002] # LATIN SMALL LETTER BLACKLETTER O WITH STROKE +0254 ; [.1E56.0020.0002] # LATIN SMALL LETTER OPEN O +0186 ; [.1E56.0020.0008] # LATIN CAPITAL LETTER OPEN O +1D53 ; [.1E56.0020.0014] # MODIFIER LETTER SMALL OPEN O +1D10 ; [.1E5A.0020.0002] # LATIN LETTER SMALL CAPITAL OPEN O +1D12 ; [.1E5B.0020.0002] # LATIN SMALL LETTER SIDEWAYS OPEN O +AB3F ; [.1E5C.0020.0002] # LATIN SMALL LETTER OPEN O WITH STROKE +1D97 ; [.1E5D.0020.0002] # LATIN SMALL LETTER OPEN O WITH RETROFLEX HOOK +AB62 ; [.1E5E.0020.0002] # LATIN SMALL LETTER OPEN OE +A74D ; [.1E5F.0020.0002] # LATIN SMALL LETTER O WITH LOOP +A74C ; [.1E5F.0020.0008] # LATIN CAPITAL LETTER O WITH LOOP +1D16 ; [.1E60.0020.0002] # LATIN SMALL LETTER TOP HALF O +1D54 ; [.1E60.0020.0014] # MODIFIER LETTER SMALL TOP HALF O +1D17 ; [.1E61.0020.0002] # LATIN SMALL LETTER BOTTOM HALF O +1D55 ; [.1E61.0020.0014] # MODIFIER LETTER SMALL BOTTOM HALF O +2C7A ; [.1E62.0020.0002] # LATIN SMALL LETTER O WITH LOW RING INSIDE +0275 ; [.1E63.0020.0002] # LATIN SMALL LETTER BARRED O +019F ; [.1E63.0020.0008] # LATIN CAPITAL LETTER O WITH MIDDLE TILDE +1DB1 ; [.1E63.0020.0014] # MODIFIER LETTER SMALL BARRED O +A74B ; [.1E67.0020.0002] # LATIN SMALL LETTER O WITH LONG STROKE OVERLAY +A74A ; [.1E67.0020.0008] # LATIN CAPITAL LETTER O WITH LONG STROKE OVERLAY +0277 ; [.1E68.0020.0002] # LATIN SMALL LETTER CLOSED OMEGA +A7B7 ; [.1E6C.0020.0002] # LATIN SMALL LETTER OMEGA +A7B6 ; [.1E6C.0020.0008] # LATIN CAPITAL LETTER OMEGA +0223 ; [.1E6D.0020.0002] # LATIN SMALL LETTER OU +0222 ; [.1E6D.0020.0008] # LATIN CAPITAL LETTER OU +1D3D ; [.1E6D.0020.001D] # MODIFIER LETTER CAPITAL OU +1D15 ; [.1E71.0020.0002] # LATIN LETTER SMALL CAPITAL OU +0070 ; [.1E72.0020.0002] # LATIN SMALL LETTER P +FF50 ; [.1E72.0020.0003] # FULLWIDTH LATIN SMALL LETTER P +1DEE ; [.1E72.0020.0004] # COMBINING LATIN SMALL LETTER P +24AB ; [*0318.0020.0004][.1E72.0020.0004][*0319.0020.0004] # PARENTHESIZED LATIN SMALL LETTER P +1D429 ; [.1E72.0020.0005] # MATHEMATICAL BOLD SMALL P +1D45D ; [.1E72.0020.0005] # MATHEMATICAL ITALIC SMALL P +1D491 ; [.1E72.0020.0005] # MATHEMATICAL BOLD ITALIC SMALL P +1D4C5 ; [.1E72.0020.0005] # MATHEMATICAL SCRIPT SMALL P +1D4F9 ; [.1E72.0020.0005] # MATHEMATICAL BOLD SCRIPT SMALL P +1D52D ; [.1E72.0020.0005] # MATHEMATICAL FRAKTUR SMALL P +1D561 ; [.1E72.0020.0005] # MATHEMATICAL DOUBLE-STRUCK SMALL P +1D595 ; [.1E72.0020.0005] # MATHEMATICAL BOLD FRAKTUR SMALL P +1D5C9 ; [.1E72.0020.0005] # MATHEMATICAL SANS-SERIF SMALL P +1D5FD ; [.1E72.0020.0005] # MATHEMATICAL SANS-SERIF BOLD SMALL P +1D631 ; [.1E72.0020.0005] # MATHEMATICAL SANS-SERIF ITALIC SMALL P +1D665 ; [.1E72.0020.0005] # MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL P +1D699 ; [.1E72.0020.0005] # MATHEMATICAL MONOSPACE SMALL P +24DF ; [.1E72.0020.0006] # CIRCLED LATIN SMALL LETTER P +0050 ; [.1E72.0020.0008] # LATIN CAPITAL LETTER P +FF30 ; [.1E72.0020.0009] # FULLWIDTH LATIN CAPITAL LETTER P +1F11F ; [*0318.0020.0004][.1E72.0020.000A][*0319.0020.0004] # PARENTHESIZED LATIN CAPITAL LETTER P +2119 ; [.1E72.0020.000B] # DOUBLE-STRUCK CAPITAL P +1D40F ; [.1E72.0020.000B] # MATHEMATICAL BOLD CAPITAL P +1D443 ; [.1E72.0020.000B] # MATHEMATICAL ITALIC CAPITAL P +1D477 ; [.1E72.0020.000B] # MATHEMATICAL BOLD ITALIC CAPITAL P +1D4AB ; [.1E72.0020.000B] # MATHEMATICAL SCRIPT CAPITAL P +1D4DF ; [.1E72.0020.000B] # MATHEMATICAL BOLD SCRIPT CAPITAL P +1D513 ; [.1E72.0020.000B] # MATHEMATICAL FRAKTUR CAPITAL P +1D57B ; [.1E72.0020.000B] # MATHEMATICAL BOLD FRAKTUR CAPITAL P +1D5AF ; [.1E72.0020.000B] # MATHEMATICAL SANS-SERIF CAPITAL P +1D5E3 ; [.1E72.0020.000B] # MATHEMATICAL SANS-SERIF BOLD CAPITAL P +1D617 ; [.1E72.0020.000B] # MATHEMATICAL SANS-SERIF ITALIC CAPITAL P +1D64B ; [.1E72.0020.000B] # MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL P +1D67F ; [.1E72.0020.000B] # MATHEMATICAL MONOSPACE CAPITAL P +24C5 ; [.1E72.0020.000C] # CIRCLED LATIN CAPITAL LETTER P +1F15F ; [.1E72.0020.000C] # NEGATIVE CIRCLED LATIN CAPITAL LETTER P +1D56 ; [.1E72.0020.0014] # MODIFIER LETTER SMALL P +209A ; [.1E72.0020.0015] # LATIN SUBSCRIPT SMALL LETTER P +1D3E ; [.1E72.0020.001D] # MODIFIER LETTER CAPITAL P +1F13F ; [.1E72.0020.001D] # SQUARED LATIN CAPITAL LETTER P +1F17F ; [.1E72.0020.001D] # NEGATIVE SQUARED LATIN CAPITAL LETTER P +1F18A ; [.1E72.0020.001D] # CROSSED NEGATIVE SQUARED LATIN CAPITAL LETTER P +1E55 ; [.1E72.0020.0002][.0000.0024.0002] # LATIN SMALL LETTER P WITH ACUTE +1E54 ; [.1E72.0020.0008][.0000.0024.0002] # LATIN CAPITAL LETTER P WITH ACUTE +1E57 ; [.1E72.0020.0002][.0000.002E.0002] # LATIN SMALL LETTER P WITH DOT ABOVE +1E56 ; [.1E72.0020.0008][.0000.002E.0002] # LATIN CAPITAL LETTER P WITH DOT ABOVE +3380 ; [.1E72.0020.001C][.1CAD.0020.001D] # SQUARE PA AMPS +33A9 ; [.1E72.0020.001D][.1CAD.0020.001C] # SQUARE PA +1F18C ; [.1E72.0020.001D][.1CAD.0020.001D] # NEGATIVE SQUARED PA +3376 ; [.1E72.0020.001C][.1CE0.0020.001C] # SQUARE PC +338A ; [.1E72.0020.001C][.1D4B.0020.001D] # SQUARE PF +33D7 ; [.1E72.0020.001D][.1D7E.0020.001D] # SQUARE PH +33D8 ; [.1E72.0020.001C][*0278.0020.001C][.1E10.0020.001C][*0278.0020.001C] # SQUARE PM +33D9 ; [.1E72.0020.001D][.1E72.0020.001D][.1E10.0020.001D] # SQUARE PPM +1F14E ; [.1E72.0020.001D][.1E72.0020.001D][.1F49.0020.001D] # SQUARED PPV +33DA ; [.1E72.0020.001D][.1E99.0020.001D] # SQUARE PR +33B0 ; [.1E72.0020.001C][.1ED7.0020.001C] # SQUARE PS +3250 ; [.1E72.0020.001D][.1EFB.0020.001D][.1D10.0020.001D] # PARTNERSHIP SIGN +33B4 ; [.1E72.0020.001C][.1F49.0020.001D] # SQUARE PV +33BA ; [.1E72.0020.001C][.1F5B.0020.001D] # SQUARE PW +1D18 ; [.1E76.0020.0002] # LATIN LETTER SMALL CAPITAL P +1D7D ; [.1E77.0020.0002] # LATIN SMALL LETTER P WITH STROKE +2C63 ; [.1E77.0020.0008] # LATIN CAPITAL LETTER P WITH STROKE +A751 ; [.1E78.0020.0002] # LATIN SMALL LETTER P WITH STROKE THROUGH DESCENDER +A750 ; [.1E78.0020.0008] # LATIN CAPITAL LETTER P WITH STROKE THROUGH DESCENDER +1D71 ; [.1E79.0020.0002] # LATIN SMALL LETTER P WITH MIDDLE TILDE +1D88 ; [.1E7A.0020.0002] # LATIN SMALL LETTER P WITH PALATAL HOOK +01A5 ; [.1E7B.0020.0002] # LATIN SMALL LETTER P WITH HOOK +01A4 ; [.1E7B.0020.0008] # LATIN CAPITAL LETTER P WITH HOOK +A753 ; [.1E7F.0020.0002] # LATIN SMALL LETTER P WITH FLOURISH +A752 ; [.1E7F.0020.0008] # LATIN CAPITAL LETTER P WITH FLOURISH +A755 ; [.1E80.0020.0002] # LATIN SMALL LETTER P WITH SQUIRREL TAIL +A754 ; [.1E80.0020.0008] # LATIN CAPITAL LETTER P WITH SQUIRREL TAIL +A7FC ; [.1E81.0020.0002] # LATIN EPIGRAPHIC LETTER REVERSED P +0278 ; [.1E82.0020.0002] # LATIN SMALL LETTER PHI +1DB2 ; [.1E82.0020.0014] # MODIFIER LETTER SMALL PHI +2C77 ; [.1E86.0020.0002] # LATIN SMALL LETTER TAILLESS PHI +0071 ; [.1E87.0020.0002] # LATIN SMALL LETTER Q +FF51 ; [.1E87.0020.0003] # FULLWIDTH LATIN SMALL LETTER Q +24AC ; [*0318.0020.0004][.1E87.0020.0004][*0319.0020.0004] # PARENTHESIZED LATIN SMALL LETTER Q +1D42A ; [.1E87.0020.0005] # MATHEMATICAL BOLD SMALL Q +1D45E ; [.1E87.0020.0005] # MATHEMATICAL ITALIC SMALL Q +1D492 ; [.1E87.0020.0005] # MATHEMATICAL BOLD ITALIC SMALL Q +1D4C6 ; [.1E87.0020.0005] # MATHEMATICAL SCRIPT SMALL Q +1D4FA ; [.1E87.0020.0005] # MATHEMATICAL BOLD SCRIPT SMALL Q +1D52E ; [.1E87.0020.0005] # MATHEMATICAL FRAKTUR SMALL Q +1D562 ; [.1E87.0020.0005] # MATHEMATICAL DOUBLE-STRUCK SMALL Q +1D596 ; [.1E87.0020.0005] # MATHEMATICAL BOLD FRAKTUR SMALL Q +1D5CA ; [.1E87.0020.0005] # MATHEMATICAL SANS-SERIF SMALL Q +1D5FE ; [.1E87.0020.0005] # MATHEMATICAL SANS-SERIF BOLD SMALL Q +1D632 ; [.1E87.0020.0005] # MATHEMATICAL SANS-SERIF ITALIC SMALL Q +1D666 ; [.1E87.0020.0005] # MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL Q +1D69A ; [.1E87.0020.0005] # MATHEMATICAL MONOSPACE SMALL Q +24E0 ; [.1E87.0020.0006] # CIRCLED LATIN SMALL LETTER Q +0051 ; [.1E87.0020.0008] # LATIN CAPITAL LETTER Q +FF31 ; [.1E87.0020.0009] # FULLWIDTH LATIN CAPITAL LETTER Q +1F120 ; [*0318.0020.0004][.1E87.0020.000A][*0319.0020.0004] # PARENTHESIZED LATIN CAPITAL LETTER Q +211A ; [.1E87.0020.000B] # DOUBLE-STRUCK CAPITAL Q +1D410 ; [.1E87.0020.000B] # MATHEMATICAL BOLD CAPITAL Q +1D444 ; [.1E87.0020.000B] # MATHEMATICAL ITALIC CAPITAL Q +1D478 ; [.1E87.0020.000B] # MATHEMATICAL BOLD ITALIC CAPITAL Q +1D4AC ; [.1E87.0020.000B] # MATHEMATICAL SCRIPT CAPITAL Q +1D4E0 ; [.1E87.0020.000B] # MATHEMATICAL BOLD SCRIPT CAPITAL Q +1D514 ; [.1E87.0020.000B] # MATHEMATICAL FRAKTUR CAPITAL Q +1D57C ; [.1E87.0020.000B] # MATHEMATICAL BOLD FRAKTUR CAPITAL Q +1D5B0 ; [.1E87.0020.000B] # MATHEMATICAL SANS-SERIF CAPITAL Q +1D5E4 ; [.1E87.0020.000B] # MATHEMATICAL SANS-SERIF BOLD CAPITAL Q +1D618 ; [.1E87.0020.000B] # MATHEMATICAL SANS-SERIF ITALIC CAPITAL Q +1D64C ; [.1E87.0020.000B] # MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL Q +1D680 ; [.1E87.0020.000B] # MATHEMATICAL MONOSPACE CAPITAL Q +24C6 ; [.1E87.0020.000C] # CIRCLED LATIN CAPITAL LETTER Q +1F160 ; [.1E87.0020.000C] # NEGATIVE CIRCLED LATIN CAPITAL LETTER Q +1F140 ; [.1E87.0020.001D] # SQUARED LATIN CAPITAL LETTER Q +1F180 ; [.1E87.0020.001D] # NEGATIVE SQUARED LATIN CAPITAL LETTER Q +0239 ; [.1E87.0020.0004][.1E72.0020.0004] # LATIN SMALL LETTER QP DIGRAPH +A757 ; [.1E8B.0020.0002] # LATIN SMALL LETTER Q WITH STROKE THROUGH DESCENDER +A756 ; [.1E8B.0020.0008] # LATIN CAPITAL LETTER Q WITH STROKE THROUGH DESCENDER +A759 ; [.1E8C.0020.0002] # LATIN SMALL LETTER Q WITH DIAGONAL STROKE +A758 ; [.1E8C.0020.0008] # LATIN CAPITAL LETTER Q WITH DIAGONAL STROKE +02A0 ; [.1E8D.0020.0002] # LATIN SMALL LETTER Q WITH HOOK +024B ; [.1E91.0020.0002] # LATIN SMALL LETTER Q WITH HOOK TAIL +024A ; [.1E91.0020.0008] # LATIN CAPITAL LETTER SMALL Q WITH HOOK TAIL +0138 ; [.1E95.0020.0002] # LATIN SMALL LETTER KRA +0072 ; [.1E99.0020.0002] # LATIN SMALL LETTER R +FF52 ; [.1E99.0020.0003] # FULLWIDTH LATIN SMALL LETTER R +036C ; [.1E99.0020.0004] # COMBINING LATIN SMALL LETTER R +1DCA ; [.1E99.0020.0004] # COMBINING LATIN SMALL LETTER R BELOW +24AD ; [*0318.0020.0004][.1E99.0020.0004][*0319.0020.0004] # PARENTHESIZED LATIN SMALL LETTER R +1D42B ; [.1E99.0020.0005] # MATHEMATICAL BOLD SMALL R +1D45F ; [.1E99.0020.0005] # MATHEMATICAL ITALIC SMALL R +1D493 ; [.1E99.0020.0005] # MATHEMATICAL BOLD ITALIC SMALL R +1D4C7 ; [.1E99.0020.0005] # MATHEMATICAL SCRIPT SMALL R +1D4FB ; [.1E99.0020.0005] # MATHEMATICAL BOLD SCRIPT SMALL R +1D52F ; [.1E99.0020.0005] # MATHEMATICAL FRAKTUR SMALL R +1D563 ; [.1E99.0020.0005] # MATHEMATICAL DOUBLE-STRUCK SMALL R +1D597 ; [.1E99.0020.0005] # MATHEMATICAL BOLD FRAKTUR SMALL R +1D5CB ; [.1E99.0020.0005] # MATHEMATICAL SANS-SERIF SMALL R +1D5FF ; [.1E99.0020.0005] # MATHEMATICAL SANS-SERIF BOLD SMALL R +1D633 ; [.1E99.0020.0005] # MATHEMATICAL SANS-SERIF ITALIC SMALL R +1D667 ; [.1E99.0020.0005] # MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL R +1D69B ; [.1E99.0020.0005] # MATHEMATICAL MONOSPACE SMALL R +24E1 ; [.1E99.0020.0006] # CIRCLED LATIN SMALL LETTER R +0052 ; [.1E99.0020.0008] # LATIN CAPITAL LETTER R +FF32 ; [.1E99.0020.0009] # FULLWIDTH LATIN CAPITAL LETTER R +1F121 ; [*0318.0020.0004][.1E99.0020.000A][*0319.0020.0004] # PARENTHESIZED LATIN CAPITAL LETTER R +211B ; [.1E99.0020.000B] # SCRIPT CAPITAL R +211C ; [.1E99.0020.000B] # BLACK-LETTER CAPITAL R +211D ; [.1E99.0020.000B] # DOUBLE-STRUCK CAPITAL R +1D411 ; [.1E99.0020.000B] # MATHEMATICAL BOLD CAPITAL R +1D445 ; [.1E99.0020.000B] # MATHEMATICAL ITALIC CAPITAL R +1D479 ; [.1E99.0020.000B] # MATHEMATICAL BOLD ITALIC CAPITAL R +1D4E1 ; [.1E99.0020.000B] # MATHEMATICAL BOLD SCRIPT CAPITAL R +1D57D ; [.1E99.0020.000B] # MATHEMATICAL BOLD FRAKTUR CAPITAL R +1D5B1 ; [.1E99.0020.000B] # MATHEMATICAL SANS-SERIF CAPITAL R +1D5E5 ; [.1E99.0020.000B] # MATHEMATICAL SANS-SERIF BOLD CAPITAL R +1D619 ; [.1E99.0020.000B] # MATHEMATICAL SANS-SERIF ITALIC CAPITAL R +1D64D ; [.1E99.0020.000B] # MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL R +1D681 ; [.1E99.0020.000B] # MATHEMATICAL MONOSPACE CAPITAL R +24C7 ; [.1E99.0020.000C] # CIRCLED LATIN CAPITAL LETTER R +1F12C ; [.1E99.0020.000C] # CIRCLED ITALIC LATIN CAPITAL LETTER R +1F161 ; [.1E99.0020.000C] # NEGATIVE CIRCLED LATIN CAPITAL LETTER R +02B3 ; [.1E99.0020.0014] # MODIFIER LETTER SMALL R +1D63 ; [.1E99.0020.0015] # LATIN SUBSCRIPT SMALL LETTER R +1D3F ; [.1E99.0020.001D] # MODIFIER LETTER CAPITAL R +1F141 ; [.1E99.0020.001D] # SQUARED LATIN CAPITAL LETTER R +1F181 ; [.1E99.0020.001D] # NEGATIVE SQUARED LATIN CAPITAL LETTER R +0155 ; [.1E99.0020.0002][.0000.0024.0002] # LATIN SMALL LETTER R WITH ACUTE +0154 ; [.1E99.0020.0008][.0000.0024.0002] # LATIN CAPITAL LETTER R WITH ACUTE +0159 ; [.1E99.0020.0002][.0000.0028.0002] # LATIN SMALL LETTER R WITH CARON +0158 ; [.1E99.0020.0008][.0000.0028.0002] # LATIN CAPITAL LETTER R WITH CARON +1E59 ; [.1E99.0020.0002][.0000.002E.0002] # LATIN SMALL LETTER R WITH DOT ABOVE +1E58 ; [.1E99.0020.0008][.0000.002E.0002] # LATIN CAPITAL LETTER R WITH DOT ABOVE +0157 ; [.1E99.0020.0002][.0000.0030.0002] # LATIN SMALL LETTER R WITH CEDILLA +0156 ; [.1E99.0020.0008][.0000.0030.0002] # LATIN CAPITAL LETTER R WITH CEDILLA +A7A7 ; [.1E99.0020.0004][.0000.0035.0004] # LATIN SMALL LETTER R WITH OBLIQUE STROKE +A7A6 ; [.1E99.0020.000A][.0000.0035.0004] # LATIN CAPITAL LETTER R WITH OBLIQUE STROKE +0211 ; [.1E99.0020.0002][.0000.003C.0002] # LATIN SMALL LETTER R WITH DOUBLE GRAVE +0210 ; [.1E99.0020.0008][.0000.003C.0002] # LATIN CAPITAL LETTER R WITH DOUBLE GRAVE +0213 ; [.1E99.0020.0002][.0000.003E.0002] # LATIN SMALL LETTER R WITH INVERTED BREVE +0212 ; [.1E99.0020.0008][.0000.003E.0002] # LATIN CAPITAL LETTER R WITH INVERTED BREVE +1E5B ; [.1E99.0020.0002][.0000.0042.0002] # LATIN SMALL LETTER R WITH DOT BELOW +1E5A ; [.1E99.0020.0008][.0000.0042.0002] # LATIN CAPITAL LETTER R WITH DOT BELOW +1E5D ; [.1E99.0020.0002][.0000.0042.0002][.0000.0032.0002] # LATIN SMALL LETTER R WITH DOT BELOW AND MACRON +1E5C ; [.1E99.0020.0008][.0000.0042.0002][.0000.0032.0002] # LATIN CAPITAL LETTER R WITH DOT BELOW AND MACRON +1E5F ; [.1E99.0020.0002][.0000.0049.0002] # LATIN SMALL LETTER R WITH LINE BELOW +1E5E ; [.1E99.0020.0008][.0000.0049.0002] # LATIN CAPITAL LETTER R WITH LINE BELOW +A783 ; [.1E99.0020.0004][.0000.0112.0004] # LATIN SMALL LETTER INSULAR R +A782 ; [.1E99.0020.000A][.0000.0112.0004] # LATIN CAPITAL LETTER INSULAR R +33AD ; [.1E99.0020.001C][.1CAD.0020.001C][.1CF5.0020.001C] # SQUARE RAD +33AE ; [.1E99.0020.001C][.1CAD.0020.001C][.1CF5.0020.001C][*063B.0020.001C][.1ED7.0020.001C] # SQUARE RAD OVER S +33AF ; [.1E99.0020.001C][.1CAD.0020.001C][.1CF5.0020.001C][*063B.0020.001C][.1ED7.0020.001C][.1CA5.0020.001C] # SQUARE RAD OVER S SQUARED +20A8 ; [.1E99.0020.000A][.1ED7.0020.0004] # RUPEE SIGN +AB45 ; [.1E9D.0020.0002] # LATIN SMALL LETTER STIRRUP R +0280 ; [.1E9E.0020.0002] # LATIN LETTER SMALL CAPITAL R +1DE2 ; [.1E9E.0020.0004] # COMBINING LATIN LETTER SMALL CAPITAL R +01A6 ; [.1E9E.0020.0008] # LATIN LETTER YR +AB46 ; [.1EA2.0020.0002] # LATIN LETTER SMALL CAPITAL R WITH RIGHT LEG +A75B ; [.1EA3.0020.0002] # LATIN SMALL LETTER R ROTUNDA +1DE3 ; [.1EA3.0020.0004] # COMBINING LATIN SMALL LETTER R ROTUNDA +A75A ; [.1EA3.0020.0008] # LATIN CAPITAL LETTER R ROTUNDA +1D19 ; [.1EA4.0020.0002] # LATIN LETTER SMALL CAPITAL REVERSED R +024D ; [.1EA5.0020.0002] # LATIN SMALL LETTER R WITH STROKE +024C ; [.1EA5.0020.0008] # LATIN CAPITAL LETTER R WITH STROKE +1D72 ; [.1EA9.0020.0002] # LATIN SMALL LETTER R WITH MIDDLE TILDE +0279 ; [.1EAA.0020.0002] # LATIN SMALL LETTER TURNED R +02B4 ; [.1EAA.0020.0014] # MODIFIER LETTER SMALL TURNED R +1D1A ; [.1EAE.0020.0002] # LATIN LETTER SMALL CAPITAL TURNED R +027A ; [.1EAF.0020.0002] # LATIN SMALL LETTER TURNED R WITH LONG LEG +1D89 ; [.1EB3.0020.0002] # LATIN SMALL LETTER R WITH PALATAL HOOK +027B ; [.1EB4.0020.0002] # LATIN SMALL LETTER TURNED R WITH HOOK +02B5 ; [.1EB4.0020.0014] # MODIFIER LETTER SMALL TURNED R WITH HOOK +2C79 ; [.1EB8.0020.0002] # LATIN SMALL LETTER TURNED R WITH TAIL +027C ; [.1EB9.0020.0002] # LATIN SMALL LETTER R WITH LONG LEG +027D ; [.1EBD.0020.0002] # LATIN SMALL LETTER R WITH TAIL +2C64 ; [.1EBD.0020.0008] # LATIN CAPITAL LETTER R WITH TAIL +AB49 ; [.1EC1.0020.0002] # LATIN SMALL LETTER R WITH CROSSED-TAIL +027E ; [.1EC2.0020.0002] # LATIN SMALL LETTER R WITH FISHHOOK +1D73 ; [.1EC6.0020.0002] # LATIN SMALL LETTER R WITH FISHHOOK AND MIDDLE TILDE +027F ; [.1EC7.0020.0002] # LATIN SMALL LETTER REVERSED R WITH FISHHOOK +AB47 ; [.1ECB.0020.0002] # LATIN SMALL LETTER R WITHOUT HANDLE +AB48 ; [.1ECC.0020.0002] # LATIN SMALL LETTER DOUBLE R +AB4A ; [.1ECD.0020.0002] # LATIN SMALL LETTER DOUBLE R WITH CROSSED-TAIL +AB4B ; [.1ECE.0020.0002] # LATIN SMALL LETTER SCRIPT R +AB4C ; [.1ECF.0020.0002] # LATIN SMALL LETTER SCRIPT R WITH RING +0281 ; [.1ED0.0020.0002] # LATIN LETTER SMALL CAPITAL INVERTED R +02B6 ; [.1ED0.0020.0014] # MODIFIER LETTER SMALL CAPITAL INVERTED R +A775 ; [.1ED4.0020.0002] # LATIN SMALL LETTER RUM +A776 ; [.1ED5.0020.0002] # LATIN LETTER SMALL CAPITAL RUM +A75D ; [.1ED6.0020.0002] # LATIN SMALL LETTER RUM ROTUNDA +A75C ; [.1ED6.0020.0008] # LATIN CAPITAL LETTER RUM ROTUNDA +0073 ; [.1ED7.0020.0002] # LATIN SMALL LETTER S +FF53 ; [.1ED7.0020.0003] # FULLWIDTH LATIN SMALL LETTER S +1DE4 ; [.1ED7.0020.0004] # COMBINING LATIN SMALL LETTER S +24AE ; [*0318.0020.0004][.1ED7.0020.0004][*0319.0020.0004] # PARENTHESIZED LATIN SMALL LETTER S +1D42C ; [.1ED7.0020.0005] # MATHEMATICAL BOLD SMALL S +1D460 ; [.1ED7.0020.0005] # MATHEMATICAL ITALIC SMALL S +1D494 ; [.1ED7.0020.0005] # MATHEMATICAL BOLD ITALIC SMALL S +1D4C8 ; [.1ED7.0020.0005] # MATHEMATICAL SCRIPT SMALL S +1D4FC ; [.1ED7.0020.0005] # MATHEMATICAL BOLD SCRIPT SMALL S +1D530 ; [.1ED7.0020.0005] # MATHEMATICAL FRAKTUR SMALL S +1D564 ; [.1ED7.0020.0005] # MATHEMATICAL DOUBLE-STRUCK SMALL S +1D598 ; [.1ED7.0020.0005] # MATHEMATICAL BOLD FRAKTUR SMALL S +1D5CC ; [.1ED7.0020.0005] # MATHEMATICAL SANS-SERIF SMALL S +1D600 ; [.1ED7.0020.0005] # MATHEMATICAL SANS-SERIF BOLD SMALL S +1D634 ; [.1ED7.0020.0005] # MATHEMATICAL SANS-SERIF ITALIC SMALL S +1D668 ; [.1ED7.0020.0005] # MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL S +1D69C ; [.1ED7.0020.0005] # MATHEMATICAL MONOSPACE SMALL S +24E2 ; [.1ED7.0020.0006] # CIRCLED LATIN SMALL LETTER S +0053 ; [.1ED7.0020.0008] # LATIN CAPITAL LETTER S +FF33 ; [.1ED7.0020.0009] # FULLWIDTH LATIN CAPITAL LETTER S +1F122 ; [*0318.0020.0004][.1ED7.0020.000A][*0319.0020.0004] # PARENTHESIZED LATIN CAPITAL LETTER S +1F12A ; [*037A.0020.0004][.1ED7.0020.000A][*037B.0020.0004] # TORTOISE SHELL BRACKETED LATIN CAPITAL LETTER S +1D412 ; [.1ED7.0020.000B] # MATHEMATICAL BOLD CAPITAL S +1D446 ; [.1ED7.0020.000B] # MATHEMATICAL ITALIC CAPITAL S +1D47A ; [.1ED7.0020.000B] # MATHEMATICAL BOLD ITALIC CAPITAL S +1D4AE ; [.1ED7.0020.000B] # MATHEMATICAL SCRIPT CAPITAL S +1D4E2 ; [.1ED7.0020.000B] # MATHEMATICAL BOLD SCRIPT CAPITAL S +1D516 ; [.1ED7.0020.000B] # MATHEMATICAL FRAKTUR CAPITAL S +1D54A ; [.1ED7.0020.000B] # MATHEMATICAL DOUBLE-STRUCK CAPITAL S +1D57E ; [.1ED7.0020.000B] # MATHEMATICAL BOLD FRAKTUR CAPITAL S +1D5B2 ; [.1ED7.0020.000B] # MATHEMATICAL SANS-SERIF CAPITAL S +1D5E6 ; [.1ED7.0020.000B] # MATHEMATICAL SANS-SERIF BOLD CAPITAL S +1D61A ; [.1ED7.0020.000B] # MATHEMATICAL SANS-SERIF ITALIC CAPITAL S +1D64E ; [.1ED7.0020.000B] # MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL S +1D682 ; [.1ED7.0020.000B] # MATHEMATICAL MONOSPACE CAPITAL S +24C8 ; [.1ED7.0020.000C] # CIRCLED LATIN CAPITAL LETTER S +1F162 ; [.1ED7.0020.000C] # NEGATIVE CIRCLED LATIN CAPITAL LETTER S +02E2 ; [.1ED7.0020.0014] # MODIFIER LETTER SMALL S +209B ; [.1ED7.0020.0015] # LATIN SUBSCRIPT SMALL LETTER S +1F142 ; [.1ED7.0020.001D] # SQUARED LATIN CAPITAL LETTER S +1F182 ; [.1ED7.0020.001D] # NEGATIVE SQUARED LATIN CAPITAL LETTER S +015B ; [.1ED7.0020.0002][.0000.0024.0002] # LATIN SMALL LETTER S WITH ACUTE +015A ; [.1ED7.0020.0008][.0000.0024.0002] # LATIN CAPITAL LETTER S WITH ACUTE +1E65 ; [.1ED7.0020.0002][.0000.0024.0002][.0000.002E.0002] # LATIN SMALL LETTER S WITH ACUTE AND DOT ABOVE +1E64 ; [.1ED7.0020.0008][.0000.0024.0002][.0000.002E.0002] # LATIN CAPITAL LETTER S WITH ACUTE AND DOT ABOVE +015D ; [.1ED7.0020.0002][.0000.0027.0002] # LATIN SMALL LETTER S WITH CIRCUMFLEX +015C ; [.1ED7.0020.0008][.0000.0027.0002] # LATIN CAPITAL LETTER S WITH CIRCUMFLEX +0161 ; [.1ED7.0020.0002][.0000.0028.0002] # LATIN SMALL LETTER S WITH CARON +0160 ; [.1ED7.0020.0008][.0000.0028.0002] # LATIN CAPITAL LETTER S WITH CARON +1E67 ; [.1ED7.0020.0002][.0000.0028.0002][.0000.002E.0002] # LATIN SMALL LETTER S WITH CARON AND DOT ABOVE +1E66 ; [.1ED7.0020.0008][.0000.0028.0002][.0000.002E.0002] # LATIN CAPITAL LETTER S WITH CARON AND DOT ABOVE +1E61 ; [.1ED7.0020.0002][.0000.002E.0002] # LATIN SMALL LETTER S WITH DOT ABOVE +1E60 ; [.1ED7.0020.0008][.0000.002E.0002] # LATIN CAPITAL LETTER S WITH DOT ABOVE +015F ; [.1ED7.0020.0002][.0000.0030.0002] # LATIN SMALL LETTER S WITH CEDILLA +015E ; [.1ED7.0020.0008][.0000.0030.0002] # LATIN CAPITAL LETTER S WITH CEDILLA +A7A9 ; [.1ED7.0020.0004][.0000.0035.0004] # LATIN SMALL LETTER S WITH OBLIQUE STROKE +A7A8 ; [.1ED7.0020.000A][.0000.0035.0004] # LATIN CAPITAL LETTER S WITH OBLIQUE STROKE +1E63 ; [.1ED7.0020.0002][.0000.0042.0002] # LATIN SMALL LETTER S WITH DOT BELOW +1E62 ; [.1ED7.0020.0008][.0000.0042.0002] # LATIN CAPITAL LETTER S WITH DOT BELOW +1E69 ; [.1ED7.0020.0002][.0000.0042.0002][.0000.002E.0002] # LATIN SMALL LETTER S WITH DOT BELOW AND DOT ABOVE +1E68 ; [.1ED7.0020.0008][.0000.0042.0002][.0000.002E.0002] # LATIN CAPITAL LETTER S WITH DOT BELOW AND DOT ABOVE +0219 ; [.1ED7.0020.0002][.0000.0045.0002] # LATIN SMALL LETTER S WITH COMMA BELOW +0218 ; [.1ED7.0020.0008][.0000.0045.0002] # LATIN CAPITAL LETTER S WITH COMMA BELOW +017F ; [.1ED7.0020.0004][.0000.0112.0004] # LATIN SMALL LETTER LONG S +1DE5 ; [.1ED7.0020.0004][.0000.0112.0004] # COMBINING LATIN SMALL LETTER LONG S +A785 ; [.1ED7.0020.0004][.0000.0112.0004] # LATIN SMALL LETTER INSULAR S +A784 ; [.1ED7.0020.000A][.0000.0112.0004] # LATIN CAPITAL LETTER INSULAR S +1E9B ; [.1ED7.0020.0004][.0000.0112.0004][.0000.002E.0002] # LATIN SMALL LETTER LONG S WITH DOT ABOVE +1F18D ; [.1ED7.0020.001D][.1CAD.0020.001D] # NEGATIVE SQUARED SA +1F14C ; [.1ED7.0020.001D][.1CF5.0020.001D] # SQUARED SD +1F1AA ; [.1ED7.0020.001D][.1D7E.0020.001D][.1F49.0020.001D] # SQUARED SHV +2120 ; [.1ED7.0020.0014][.1E10.0020.0014] # SERVICE MARK +1F198 ; [.1ED7.0020.001D][.1E43.0020.001D][.1ED7.0020.001D] # SQUARED SOS +33DB ; [.1ED7.0020.001C][.1E99.0020.001C] # SQUARE SR +1F14D ; [.1ED7.0020.001D][.1ED7.0020.001D] # SQUARED SS +00DF ; [.1ED7.0020.0004][.0000.0111.0004][.1ED7.0020.0004] # LATIN SMALL LETTER SHARP S +1E9E ; [.1ED7.0020.000A][.0000.0111.0004][.1ED7.0020.000A] # LATIN CAPITAL LETTER SHARP S +FB06 ; [.1ED7.0020.0004][.1EFB.0020.0004] # LATIN SMALL LIGATURE ST +FB05 ; [.1ED7.0020.0004][.0000.0112.0004][.1EFB.0020.0004] # LATIN SMALL LIGATURE LONG S T +33DC ; [.1ED7.0020.001D][.1F49.0020.001C] # SQUARE SV +A731 ; [.1EDB.0020.0002] # LATIN LETTER SMALL CAPITAL S +1D74 ; [.1EDC.0020.0002] # LATIN SMALL LETTER S WITH MIDDLE TILDE +1D8A ; [.1EDD.0020.0002] # LATIN SMALL LETTER S WITH PALATAL HOOK +0282 ; [.1EDE.0020.0002] # LATIN SMALL LETTER S WITH HOOK +1DB3 ; [.1EDE.0020.0014] # MODIFIER LETTER SMALL S WITH HOOK +023F ; [.1EE2.0020.0002] # LATIN SMALL LETTER S WITH SWASH TAIL +2C7E ; [.1EE2.0020.0008] # LATIN CAPITAL LETTER S WITH SWASH TAIL +1E9C ; [.1EE6.0020.0002] # LATIN SMALL LETTER LONG S WITH DIAGONAL STROKE +1E9D ; [.1EE7.0020.0002] # LATIN SMALL LETTER LONG S WITH HIGH STROKE +0283 ; [.1EE8.0020.0002] # LATIN SMALL LETTER ESH +1DEF ; [.1EE8.0020.0004] # COMBINING LATIN SMALL LETTER ESH +01A9 ; [.1EE8.0020.0008] # LATIN CAPITAL LETTER ESH +1DB4 ; [.1EE8.0020.0014] # MODIFIER LETTER SMALL ESH +AB4D ; [.1EEC.0020.0002] # LATIN SMALL LETTER BASELINE ESH +1D8B ; [.1EED.0020.0002] # LATIN SMALL LETTER ESH WITH PALATAL HOOK +01AA ; [.1EEE.0020.0002] # LATIN LETTER REVERSED ESH LOOP +0285 ; [.1EF2.0020.0002] # LATIN SMALL LETTER SQUAT REVERSED ESH +1D98 ; [.1EF6.0020.0002] # LATIN SMALL LETTER ESH WITH RETROFLEX HOOK +0286 ; [.1EF7.0020.0002] # LATIN SMALL LETTER ESH WITH CURL +0074 ; [.1EFB.0020.0002] # LATIN SMALL LETTER T +FF54 ; [.1EFB.0020.0003] # FULLWIDTH LATIN SMALL LETTER T +036D ; [.1EFB.0020.0004] # COMBINING LATIN SMALL LETTER T +24AF ; [*0318.0020.0004][.1EFB.0020.0004][*0319.0020.0004] # PARENTHESIZED LATIN SMALL LETTER T +1D42D ; [.1EFB.0020.0005] # MATHEMATICAL BOLD SMALL T +1D461 ; [.1EFB.0020.0005] # MATHEMATICAL ITALIC SMALL T +1D495 ; [.1EFB.0020.0005] # MATHEMATICAL BOLD ITALIC SMALL T +1D4C9 ; [.1EFB.0020.0005] # MATHEMATICAL SCRIPT SMALL T +1D4FD ; [.1EFB.0020.0005] # MATHEMATICAL BOLD SCRIPT SMALL T +1D531 ; [.1EFB.0020.0005] # MATHEMATICAL FRAKTUR SMALL T +1D565 ; [.1EFB.0020.0005] # MATHEMATICAL DOUBLE-STRUCK SMALL T +1D599 ; [.1EFB.0020.0005] # MATHEMATICAL BOLD FRAKTUR SMALL T +1D5CD ; [.1EFB.0020.0005] # MATHEMATICAL SANS-SERIF SMALL T +1D601 ; [.1EFB.0020.0005] # MATHEMATICAL SANS-SERIF BOLD SMALL T +1D635 ; [.1EFB.0020.0005] # MATHEMATICAL SANS-SERIF ITALIC SMALL T +1D669 ; [.1EFB.0020.0005] # MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL T +1D69D ; [.1EFB.0020.0005] # MATHEMATICAL MONOSPACE SMALL T +24E3 ; [.1EFB.0020.0006] # CIRCLED LATIN SMALL LETTER T +0054 ; [.1EFB.0020.0008] # LATIN CAPITAL LETTER T +FF34 ; [.1EFB.0020.0009] # FULLWIDTH LATIN CAPITAL LETTER T +1F123 ; [*0318.0020.0004][.1EFB.0020.000A][*0319.0020.0004] # PARENTHESIZED LATIN CAPITAL LETTER T +1D413 ; [.1EFB.0020.000B] # MATHEMATICAL BOLD CAPITAL T +1D447 ; [.1EFB.0020.000B] # MATHEMATICAL ITALIC CAPITAL T +1D47B ; [.1EFB.0020.000B] # MATHEMATICAL BOLD ITALIC CAPITAL T +1D4AF ; [.1EFB.0020.000B] # MATHEMATICAL SCRIPT CAPITAL T +1D4E3 ; [.1EFB.0020.000B] # MATHEMATICAL BOLD SCRIPT CAPITAL T +1D517 ; [.1EFB.0020.000B] # MATHEMATICAL FRAKTUR CAPITAL T +1D54B ; [.1EFB.0020.000B] # MATHEMATICAL DOUBLE-STRUCK CAPITAL T +1D57F ; [.1EFB.0020.000B] # MATHEMATICAL BOLD FRAKTUR CAPITAL T +1D5B3 ; [.1EFB.0020.000B] # MATHEMATICAL SANS-SERIF CAPITAL T +1D5E7 ; [.1EFB.0020.000B] # MATHEMATICAL SANS-SERIF BOLD CAPITAL T +1D61B ; [.1EFB.0020.000B] # MATHEMATICAL SANS-SERIF ITALIC CAPITAL T +1D64F ; [.1EFB.0020.000B] # MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL T +1D683 ; [.1EFB.0020.000B] # MATHEMATICAL MONOSPACE CAPITAL T +24C9 ; [.1EFB.0020.000C] # CIRCLED LATIN CAPITAL LETTER T +1F163 ; [.1EFB.0020.000C] # NEGATIVE CIRCLED LATIN CAPITAL LETTER T +1D57 ; [.1EFB.0020.0014] # MODIFIER LETTER SMALL T +209C ; [.1EFB.0020.0015] # LATIN SUBSCRIPT SMALL LETTER T +1D40 ; [.1EFB.0020.001D] # MODIFIER LETTER CAPITAL T +1F143 ; [.1EFB.0020.001D] # SQUARED LATIN CAPITAL LETTER T +1F183 ; [.1EFB.0020.001D] # NEGATIVE SQUARED LATIN CAPITAL LETTER T +0165 ; [.1EFB.0020.0002][.0000.0028.0002] # LATIN SMALL LETTER T WITH CARON +0164 ; [.1EFB.0020.0008][.0000.0028.0002] # LATIN CAPITAL LETTER T WITH CARON +1E97 ; [.1EFB.0020.0002][.0000.002B.0002] # LATIN SMALL LETTER T WITH DIAERESIS +1E6B ; [.1EFB.0020.0002][.0000.002E.0002] # LATIN SMALL LETTER T WITH DOT ABOVE +1E6A ; [.1EFB.0020.0008][.0000.002E.0002] # LATIN CAPITAL LETTER T WITH DOT ABOVE +0163 ; [.1EFB.0020.0002][.0000.0030.0002] # LATIN SMALL LETTER T WITH CEDILLA +0162 ; [.1EFB.0020.0008][.0000.0030.0002] # LATIN CAPITAL LETTER T WITH CEDILLA +1E6D ; [.1EFB.0020.0002][.0000.0042.0002] # LATIN SMALL LETTER T WITH DOT BELOW +1E6C ; [.1EFB.0020.0008][.0000.0042.0002] # LATIN CAPITAL LETTER T WITH DOT BELOW +021B ; [.1EFB.0020.0002][.0000.0045.0002] # LATIN SMALL LETTER T WITH COMMA BELOW +021A ; [.1EFB.0020.0008][.0000.0045.0002] # LATIN CAPITAL LETTER T WITH COMMA BELOW +1E71 ; [.1EFB.0020.0002][.0000.0046.0002] # LATIN SMALL LETTER T WITH CIRCUMFLEX BELOW +1E70 ; [.1EFB.0020.0008][.0000.0046.0002] # LATIN CAPITAL LETTER T WITH CIRCUMFLEX BELOW +1E6F ; [.1EFB.0020.0002][.0000.0049.0002] # LATIN SMALL LETTER T WITH LINE BELOW +1E6E ; [.1EFB.0020.0008][.0000.0049.0002] # LATIN CAPITAL LETTER T WITH LINE BELOW +A787 ; [.1EFB.0020.0004][.0000.0112.0004] # LATIN SMALL LETTER INSULAR T +A786 ; [.1EFB.0020.000A][.0000.0112.0004] # LATIN CAPITAL LETTER INSULAR T +02A8 ; [.1EFB.0020.0004][.1CEF.0020.0004] # LATIN SMALL LETTER TC DIGRAPH WITH CURL +2121 ; [.1EFB.0020.000A][.1D10.0020.000A][.1DDD.0020.000A] # TELEPHONE SIGN +1D7A ; [.1EFB.0020.0004][.0000.0111.0004][.1D7E.0020.0004] # LATIN SMALL LETTER TH WITH STRIKETHROUGH +3394 ; [.1EFB.0020.001D][.1D7E.0020.001D][.1F87.0020.001C] # SQUARE THZ +2122 ; [.1EFB.0020.0014][.1E10.0020.0014] # TRADE MARK SIGN +01BE ; [.1EFB.0020.0004][.1ED7.0020.0004] # LATIN LETTER INVERTED GLOTTAL STOP WITH STROKE +02A6 ; [.1EFB.0020.0004][.1ED7.0020.0004] # LATIN SMALL LETTER TS DIGRAPH +02A7 ; [.1EFB.0020.0004][.1EE8.0020.0004] # LATIN SMALL LETTER TESH DIGRAPH +A729 ; [.1EFB.0020.0004][.1F87.0020.0004] # LATIN SMALL LETTER TZ +A728 ; [.1EFB.0020.000A][.1F87.0020.0004] # LATIN CAPITAL LETTER TZ +1D1B ; [.1EFF.0020.0002] # LATIN LETTER SMALL CAPITAL T +0167 ; [.1F00.0020.0002] # LATIN SMALL LETTER T WITH STROKE +0166 ; [.1F00.0020.0008] # LATIN CAPITAL LETTER T WITH STROKE +2C66 ; [.1F04.0020.0002] # LATIN SMALL LETTER T WITH DIAGONAL STROKE +023E ; [.1F04.0020.0008] # LATIN CAPITAL LETTER T WITH DIAGONAL STROKE +1D75 ; [.1F05.0020.0002] # LATIN SMALL LETTER T WITH MIDDLE TILDE +01AB ; [.1F06.0020.0002] # LATIN SMALL LETTER T WITH PALATAL HOOK +1DB5 ; [.1F06.0020.0014] # MODIFIER LETTER SMALL T WITH PALATAL HOOK +01AD ; [.1F0A.0020.0002] # LATIN SMALL LETTER T WITH HOOK +01AC ; [.1F0A.0020.0008] # LATIN CAPITAL LETTER T WITH HOOK +0288 ; [.1F0E.0020.0002] # LATIN SMALL LETTER T WITH RETROFLEX HOOK +01AE ; [.1F0E.0020.0008] # LATIN CAPITAL LETTER T WITH RETROFLEX HOOK +0236 ; [.1F12.0020.0002] # LATIN SMALL LETTER T WITH CURL +A777 ; [.1F16.0020.0002] # LATIN SMALL LETTER TUM +0287 ; [.1F17.0020.0002] # LATIN SMALL LETTER TURNED T +A7B1 ; [.1F17.0020.0008] # LATIN CAPITAL LETTER TURNED T +0075 ; [.1F1B.0020.0002] # LATIN SMALL LETTER U +FF55 ; [.1F1B.0020.0003] # FULLWIDTH LATIN SMALL LETTER U +0367 ; [.1F1B.0020.0004] # COMBINING LATIN SMALL LETTER U +24B0 ; [*0318.0020.0004][.1F1B.0020.0004][*0319.0020.0004] # PARENTHESIZED LATIN SMALL LETTER U +1D42E ; [.1F1B.0020.0005] # MATHEMATICAL BOLD SMALL U +1D462 ; [.1F1B.0020.0005] # MATHEMATICAL ITALIC SMALL U +1D496 ; [.1F1B.0020.0005] # MATHEMATICAL BOLD ITALIC SMALL U +1D4CA ; [.1F1B.0020.0005] # MATHEMATICAL SCRIPT SMALL U +1D4FE ; [.1F1B.0020.0005] # MATHEMATICAL BOLD SCRIPT SMALL U +1D532 ; [.1F1B.0020.0005] # MATHEMATICAL FRAKTUR SMALL U +1D566 ; [.1F1B.0020.0005] # MATHEMATICAL DOUBLE-STRUCK SMALL U +1D59A ; [.1F1B.0020.0005] # MATHEMATICAL BOLD FRAKTUR SMALL U +1D5CE ; [.1F1B.0020.0005] # MATHEMATICAL SANS-SERIF SMALL U +1D602 ; [.1F1B.0020.0005] # MATHEMATICAL SANS-SERIF BOLD SMALL U +1D636 ; [.1F1B.0020.0005] # MATHEMATICAL SANS-SERIF ITALIC SMALL U +1D66A ; [.1F1B.0020.0005] # MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL U +1D69E ; [.1F1B.0020.0005] # MATHEMATICAL MONOSPACE SMALL U +24E4 ; [.1F1B.0020.0006] # CIRCLED LATIN SMALL LETTER U +0055 ; [.1F1B.0020.0008] # LATIN CAPITAL LETTER U +FF35 ; [.1F1B.0020.0009] # FULLWIDTH LATIN CAPITAL LETTER U +1F124 ; [*0318.0020.0004][.1F1B.0020.000A][*0319.0020.0004] # PARENTHESIZED LATIN CAPITAL LETTER U +1D414 ; [.1F1B.0020.000B] # MATHEMATICAL BOLD CAPITAL U +1D448 ; [.1F1B.0020.000B] # MATHEMATICAL ITALIC CAPITAL U +1D47C ; [.1F1B.0020.000B] # MATHEMATICAL BOLD ITALIC CAPITAL U +1D4B0 ; [.1F1B.0020.000B] # MATHEMATICAL SCRIPT CAPITAL U +1D4E4 ; [.1F1B.0020.000B] # MATHEMATICAL BOLD SCRIPT CAPITAL U +1D518 ; [.1F1B.0020.000B] # MATHEMATICAL FRAKTUR CAPITAL U +1D54C ; [.1F1B.0020.000B] # MATHEMATICAL DOUBLE-STRUCK CAPITAL U +1D580 ; [.1F1B.0020.000B] # MATHEMATICAL BOLD FRAKTUR CAPITAL U +1D5B4 ; [.1F1B.0020.000B] # MATHEMATICAL SANS-SERIF CAPITAL U +1D5E8 ; [.1F1B.0020.000B] # MATHEMATICAL SANS-SERIF BOLD CAPITAL U +1D61C ; [.1F1B.0020.000B] # MATHEMATICAL SANS-SERIF ITALIC CAPITAL U +1D650 ; [.1F1B.0020.000B] # MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL U +1D684 ; [.1F1B.0020.000B] # MATHEMATICAL MONOSPACE CAPITAL U +24CA ; [.1F1B.0020.000C] # CIRCLED LATIN CAPITAL LETTER U +1F164 ; [.1F1B.0020.000C] # NEGATIVE CIRCLED LATIN CAPITAL LETTER U +1D58 ; [.1F1B.0020.0014] # MODIFIER LETTER SMALL U +1D64 ; [.1F1B.0020.0015] # LATIN SUBSCRIPT SMALL LETTER U +1D41 ; [.1F1B.0020.001D] # MODIFIER LETTER CAPITAL U +1F144 ; [.1F1B.0020.001D] # SQUARED LATIN CAPITAL LETTER U +1F184 ; [.1F1B.0020.001D] # NEGATIVE SQUARED LATIN CAPITAL LETTER U +00FA ; [.1F1B.0020.0002][.0000.0024.0002] # LATIN SMALL LETTER U WITH ACUTE +00DA ; [.1F1B.0020.0008][.0000.0024.0002] # LATIN CAPITAL LETTER U WITH ACUTE +00F9 ; [.1F1B.0020.0002][.0000.0025.0002] # LATIN SMALL LETTER U WITH GRAVE +00D9 ; [.1F1B.0020.0008][.0000.0025.0002] # LATIN CAPITAL LETTER U WITH GRAVE +016D ; [.1F1B.0020.0002][.0000.0026.0002] # LATIN SMALL LETTER U WITH BREVE +016C ; [.1F1B.0020.0008][.0000.0026.0002] # LATIN CAPITAL LETTER U WITH BREVE +00FB ; [.1F1B.0020.0002][.0000.0027.0002] # LATIN SMALL LETTER U WITH CIRCUMFLEX +00DB ; [.1F1B.0020.0008][.0000.0027.0002] # LATIN CAPITAL LETTER U WITH CIRCUMFLEX +01D4 ; [.1F1B.0020.0002][.0000.0028.0002] # LATIN SMALL LETTER U WITH CARON +01D3 ; [.1F1B.0020.0008][.0000.0028.0002] # LATIN CAPITAL LETTER U WITH CARON +016F ; [.1F1B.0020.0002][.0000.0029.0002] # LATIN SMALL LETTER U WITH RING ABOVE +016E ; [.1F1B.0020.0008][.0000.0029.0002] # LATIN CAPITAL LETTER U WITH RING ABOVE +00FC ; [.1F1B.0020.0002][.0000.002B.0002] # LATIN SMALL LETTER U WITH DIAERESIS +1DF4 ; [.1F1B.0020.0004][.0000.002B.0004] # COMBINING LATIN SMALL LETTER U WITH DIAERESIS +A79F ; [.1F1B.0020.0004][.0000.002B.0004] # LATIN SMALL LETTER VOLAPUK UE +00DC ; [.1F1B.0020.0008][.0000.002B.0002] # LATIN CAPITAL LETTER U WITH DIAERESIS +A79E ; [.1F1B.0020.000A][.0000.002B.0004] # LATIN CAPITAL LETTER VOLAPUK UE +01D8 ; [.1F1B.0020.0002][.0000.002B.0002][.0000.0024.0002] # LATIN SMALL LETTER U WITH DIAERESIS AND ACUTE +01D7 ; [.1F1B.0020.0008][.0000.002B.0002][.0000.0024.0002] # LATIN CAPITAL LETTER U WITH DIAERESIS AND ACUTE +01DC ; [.1F1B.0020.0002][.0000.002B.0002][.0000.0025.0002] # LATIN SMALL LETTER U WITH DIAERESIS AND GRAVE +01DB ; [.1F1B.0020.0008][.0000.002B.0002][.0000.0025.0002] # LATIN CAPITAL LETTER U WITH DIAERESIS AND GRAVE +01DA ; [.1F1B.0020.0002][.0000.002B.0002][.0000.0028.0002] # LATIN SMALL LETTER U WITH DIAERESIS AND CARON +01D9 ; [.1F1B.0020.0008][.0000.002B.0002][.0000.0028.0002] # LATIN CAPITAL LETTER U WITH DIAERESIS AND CARON +01D6 ; [.1F1B.0020.0002][.0000.002B.0002][.0000.0032.0002] # LATIN SMALL LETTER U WITH DIAERESIS AND MACRON +01D5 ; [.1F1B.0020.0008][.0000.002B.0002][.0000.0032.0002] # LATIN CAPITAL LETTER U WITH DIAERESIS AND MACRON +0171 ; [.1F1B.0020.0002][.0000.002C.0002] # LATIN SMALL LETTER U WITH DOUBLE ACUTE +0170 ; [.1F1B.0020.0008][.0000.002C.0002] # LATIN CAPITAL LETTER U WITH DOUBLE ACUTE +0169 ; [.1F1B.0020.0002][.0000.002D.0002] # LATIN SMALL LETTER U WITH TILDE +0168 ; [.1F1B.0020.0008][.0000.002D.0002] # LATIN CAPITAL LETTER U WITH TILDE +1E79 ; [.1F1B.0020.0002][.0000.002D.0002][.0000.0024.0002] # LATIN SMALL LETTER U WITH TILDE AND ACUTE +1E78 ; [.1F1B.0020.0008][.0000.002D.0002][.0000.0024.0002] # LATIN CAPITAL LETTER U WITH TILDE AND ACUTE +0173 ; [.1F1B.0020.0002][.0000.0031.0002] # LATIN SMALL LETTER U WITH OGONEK +0172 ; [.1F1B.0020.0008][.0000.0031.0002] # LATIN CAPITAL LETTER U WITH OGONEK +016B ; [.1F1B.0020.0002][.0000.0032.0002] # LATIN SMALL LETTER U WITH MACRON +016A ; [.1F1B.0020.0008][.0000.0032.0002] # LATIN CAPITAL LETTER U WITH MACRON +1E7B ; [.1F1B.0020.0002][.0000.0032.0002][.0000.002B.0002] # LATIN SMALL LETTER U WITH MACRON AND DIAERESIS +1E7A ; [.1F1B.0020.0008][.0000.0032.0002][.0000.002B.0002] # LATIN CAPITAL LETTER U WITH MACRON AND DIAERESIS +1DF0 ; [.1F1B.0020.0004][.0000.0034.0004] # COMBINING LATIN SMALL LETTER U WITH LIGHT CENTRALIZATION STROKE +1EE7 ; [.1F1B.0020.0002][.0000.003B.0002] # LATIN SMALL LETTER U WITH HOOK ABOVE +1EE6 ; [.1F1B.0020.0008][.0000.003B.0002] # LATIN CAPITAL LETTER U WITH HOOK ABOVE +0215 ; [.1F1B.0020.0002][.0000.003C.0002] # LATIN SMALL LETTER U WITH DOUBLE GRAVE +0214 ; [.1F1B.0020.0008][.0000.003C.0002] # LATIN CAPITAL LETTER U WITH DOUBLE GRAVE +0217 ; [.1F1B.0020.0002][.0000.003E.0002] # LATIN SMALL LETTER U WITH INVERTED BREVE +0216 ; [.1F1B.0020.0008][.0000.003E.0002] # LATIN CAPITAL LETTER U WITH INVERTED BREVE +01B0 ; [.1F1B.0020.0002][.0000.003F.0002] # LATIN SMALL LETTER U WITH HORN +01AF ; [.1F1B.0020.0008][.0000.003F.0002] # LATIN CAPITAL LETTER U WITH HORN +1EE9 ; [.1F1B.0020.0002][.0000.003F.0002][.0000.0024.0002] # LATIN SMALL LETTER U WITH HORN AND ACUTE +1EE8 ; [.1F1B.0020.0008][.0000.003F.0002][.0000.0024.0002] # LATIN CAPITAL LETTER U WITH HORN AND ACUTE +1EEB ; [.1F1B.0020.0002][.0000.003F.0002][.0000.0025.0002] # LATIN SMALL LETTER U WITH HORN AND GRAVE +1EEA ; [.1F1B.0020.0008][.0000.003F.0002][.0000.0025.0002] # LATIN CAPITAL LETTER U WITH HORN AND GRAVE +1EEF ; [.1F1B.0020.0002][.0000.003F.0002][.0000.002D.0002] # LATIN SMALL LETTER U WITH HORN AND TILDE +1EEE ; [.1F1B.0020.0008][.0000.003F.0002][.0000.002D.0002] # LATIN CAPITAL LETTER U WITH HORN AND TILDE +1EED ; [.1F1B.0020.0002][.0000.003F.0002][.0000.003B.0002] # LATIN SMALL LETTER U WITH HORN AND HOOK ABOVE +1EEC ; [.1F1B.0020.0008][.0000.003F.0002][.0000.003B.0002] # LATIN CAPITAL LETTER U WITH HORN AND HOOK ABOVE +1EF1 ; [.1F1B.0020.0002][.0000.003F.0002][.0000.0042.0002] # LATIN SMALL LETTER U WITH HORN AND DOT BELOW +1EF0 ; [.1F1B.0020.0008][.0000.003F.0002][.0000.0042.0002] # LATIN CAPITAL LETTER U WITH HORN AND DOT BELOW +1EE5 ; [.1F1B.0020.0002][.0000.0042.0002] # LATIN SMALL LETTER U WITH DOT BELOW +1EE4 ; [.1F1B.0020.0008][.0000.0042.0002] # LATIN CAPITAL LETTER U WITH DOT BELOW +1E73 ; [.1F1B.0020.0002][.0000.0043.0002] # LATIN SMALL LETTER U WITH DIAERESIS BELOW +1E72 ; [.1F1B.0020.0008][.0000.0043.0002] # LATIN CAPITAL LETTER U WITH DIAERESIS BELOW +1E77 ; [.1F1B.0020.0002][.0000.0046.0002] # LATIN SMALL LETTER U WITH CIRCUMFLEX BELOW +1E76 ; [.1F1B.0020.0008][.0000.0046.0002] # LATIN CAPITAL LETTER U WITH CIRCUMFLEX BELOW +1E75 ; [.1F1B.0020.0002][.0000.0048.0002] # LATIN SMALL LETTER U WITH TILDE BELOW +1E74 ; [.1F1B.0020.0008][.0000.0048.0002] # LATIN CAPITAL LETTER U WITH TILDE BELOW +1F1AB ; [.1F1B.0020.001D][.1D7E.0020.001D][.1CF5.0020.001D] # SQUARED UHD +1F199 ; [.1F1B.0020.001D][.1E72.0020.001D][*0261.0020.001C] # SQUARED UP WITH EXCLAMATION MARK +1D1C ; [.1F1F.0020.0002] # LATIN LETTER SMALL CAPITAL U +1DB8 ; [.1F1F.0020.0014] # MODIFIER LETTER SMALL CAPITAL U +AB4E ; [.1F20.0020.0002] # LATIN SMALL LETTER U WITH SHORT RIGHT LEG +1D1D ; [.1F21.0020.0002] # LATIN SMALL LETTER SIDEWAYS U +1D59 ; [.1F21.0020.0014] # MODIFIER LETTER SMALL SIDEWAYS U +1D1E ; [.1F22.0020.0002] # LATIN SMALL LETTER SIDEWAYS DIAERESIZED U +1D6B ; [.1F23.0020.0002] # LATIN SMALL LETTER UE +AB50 ; [.1F24.0020.0002] # LATIN SMALL LETTER UI +AB51 ; [.1F25.0020.0002] # LATIN SMALL LETTER TURNED UI +0289 ; [.1F26.0020.0002] # LATIN SMALL LETTER U BAR +0244 ; [.1F26.0020.0008] # LATIN CAPITAL LETTER U BAR +1DB6 ; [.1F26.0020.0014] # MODIFIER LETTER SMALL U BAR +AB4F ; [.1F2A.0020.0002] # LATIN SMALL LETTER U BAR WITH SHORT RIGHT LEG +1D7E ; [.1F2B.0020.0002] # LATIN SMALL CAPITAL LETTER U WITH STROKE +1D99 ; [.1F2C.0020.0002] # LATIN SMALL LETTER U WITH RETROFLEX HOOK +AB52 ; [.1F2D.0020.0002] # LATIN SMALL LETTER U WITH LEFT HOOK +AB5F ; [.1F2D.0020.0014] # MODIFIER LETTER SMALL U WITH LEFT HOOK +0265 ; [.1F2E.0020.0002] # LATIN SMALL LETTER TURNED H +A78D ; [.1F2E.0020.0008] # LATIN CAPITAL LETTER TURNED H +1DA3 ; [.1F2E.0020.0014] # MODIFIER LETTER SMALL TURNED H +02AE ; [.1F32.0020.0002] # LATIN SMALL LETTER TURNED H WITH FISHHOOK +02AF ; [.1F36.0020.0002] # LATIN SMALL LETTER TURNED H WITH FISHHOOK AND TAIL +026F ; [.1F3A.0020.0002] # LATIN SMALL LETTER TURNED M +019C ; [.1F3A.0020.0008] # LATIN CAPITAL LETTER TURNED M +1D5A ; [.1F3A.0020.0014] # MODIFIER LETTER SMALL TURNED M +A7FA ; [.1F3E.0020.0002] # LATIN LETTER SMALL CAPITAL TURNED M +1D1F ; [.1F3F.0020.0002] # LATIN SMALL LETTER SIDEWAYS TURNED M +0270 ; [.1F40.0020.0002] # LATIN SMALL LETTER TURNED M WITH LONG LEG +1DAD ; [.1F40.0020.0014] # MODIFIER LETTER SMALL TURNED M WITH LONG LEG +028A ; [.1F44.0020.0002] # LATIN SMALL LETTER UPSILON +01B1 ; [.1F44.0020.0008] # LATIN CAPITAL LETTER UPSILON +1DB7 ; [.1F44.0020.0014] # MODIFIER LETTER SMALL UPSILON +1D7F ; [.1F48.0020.0002] # LATIN SMALL LETTER UPSILON WITH STROKE +0076 ; [.1F49.0020.0002] # LATIN SMALL LETTER V +FF56 ; [.1F49.0020.0003] # FULLWIDTH LATIN SMALL LETTER V +036E ; [.1F49.0020.0004] # COMBINING LATIN SMALL LETTER V +2174 ; [.1F49.0020.0004] # SMALL ROMAN NUMERAL FIVE +24B1 ; [*0318.0020.0004][.1F49.0020.0004][*0319.0020.0004] # PARENTHESIZED LATIN SMALL LETTER V +1D42F ; [.1F49.0020.0005] # MATHEMATICAL BOLD SMALL V +1D463 ; [.1F49.0020.0005] # MATHEMATICAL ITALIC SMALL V +1D497 ; [.1F49.0020.0005] # MATHEMATICAL BOLD ITALIC SMALL V +1D4CB ; [.1F49.0020.0005] # MATHEMATICAL SCRIPT SMALL V +1D4FF ; [.1F49.0020.0005] # MATHEMATICAL BOLD SCRIPT SMALL V +1D533 ; [.1F49.0020.0005] # MATHEMATICAL FRAKTUR SMALL V +1D567 ; [.1F49.0020.0005] # MATHEMATICAL DOUBLE-STRUCK SMALL V +1D59B ; [.1F49.0020.0005] # MATHEMATICAL BOLD FRAKTUR SMALL V +1D5CF ; [.1F49.0020.0005] # MATHEMATICAL SANS-SERIF SMALL V +1D603 ; [.1F49.0020.0005] # MATHEMATICAL SANS-SERIF BOLD SMALL V +1D637 ; [.1F49.0020.0005] # MATHEMATICAL SANS-SERIF ITALIC SMALL V +1D66B ; [.1F49.0020.0005] # MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL V +1D69F ; [.1F49.0020.0005] # MATHEMATICAL MONOSPACE SMALL V +24E5 ; [.1F49.0020.0006] # CIRCLED LATIN SMALL LETTER V +0056 ; [.1F49.0020.0008] # LATIN CAPITAL LETTER V +FF36 ; [.1F49.0020.0009] # FULLWIDTH LATIN CAPITAL LETTER V +2164 ; [.1F49.0020.000A] # ROMAN NUMERAL FIVE +1F125 ; [*0318.0020.0004][.1F49.0020.000A][*0319.0020.0004] # PARENTHESIZED LATIN CAPITAL LETTER V +1D415 ; [.1F49.0020.000B] # MATHEMATICAL BOLD CAPITAL V +1D449 ; [.1F49.0020.000B] # MATHEMATICAL ITALIC CAPITAL V +1D47D ; [.1F49.0020.000B] # MATHEMATICAL BOLD ITALIC CAPITAL V +1D4B1 ; [.1F49.0020.000B] # MATHEMATICAL SCRIPT CAPITAL V +1D4E5 ; [.1F49.0020.000B] # MATHEMATICAL BOLD SCRIPT CAPITAL V +1D519 ; [.1F49.0020.000B] # MATHEMATICAL FRAKTUR CAPITAL V +1D54D ; [.1F49.0020.000B] # MATHEMATICAL DOUBLE-STRUCK CAPITAL V +1D581 ; [.1F49.0020.000B] # MATHEMATICAL BOLD FRAKTUR CAPITAL V +1D5B5 ; [.1F49.0020.000B] # MATHEMATICAL SANS-SERIF CAPITAL V +1D5E9 ; [.1F49.0020.000B] # MATHEMATICAL SANS-SERIF BOLD CAPITAL V +1D61D ; [.1F49.0020.000B] # MATHEMATICAL SANS-SERIF ITALIC CAPITAL V +1D651 ; [.1F49.0020.000B] # MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL V +1D685 ; [.1F49.0020.000B] # MATHEMATICAL MONOSPACE CAPITAL V +24CB ; [.1F49.0020.000C] # CIRCLED LATIN CAPITAL LETTER V +1F165 ; [.1F49.0020.000C] # NEGATIVE CIRCLED LATIN CAPITAL LETTER V +1D5B ; [.1F49.0020.0014] # MODIFIER LETTER SMALL V +1D65 ; [.1F49.0020.0015] # LATIN SUBSCRIPT SMALL LETTER V +2C7D ; [.1F49.0020.001D] # MODIFIER LETTER CAPITAL V +1F145 ; [.1F49.0020.001D] # SQUARED LATIN CAPITAL LETTER V +1F185 ; [.1F49.0020.001D] # NEGATIVE SQUARED LATIN CAPITAL LETTER V +1E7D ; [.1F49.0020.0002][.0000.002D.0002] # LATIN SMALL LETTER V WITH TILDE +1E7C ; [.1F49.0020.0008][.0000.002D.0002] # LATIN CAPITAL LETTER V WITH TILDE +1E7F ; [.1F49.0020.0002][.0000.0042.0002] # LATIN SMALL LETTER V WITH DOT BELOW +1E7E ; [.1F49.0020.0008][.0000.0042.0002] # LATIN CAPITAL LETTER V WITH DOT BELOW +2175 ; [.1F49.0020.0004][.1D98.0020.0004] # SMALL ROMAN NUMERAL SIX +2165 ; [.1F49.0020.000A][.1D98.0020.000A] # ROMAN NUMERAL SIX +2176 ; [.1F49.0020.0004][.1D98.0020.0004][.1D98.0020.0004] # SMALL ROMAN NUMERAL SEVEN +2166 ; [.1F49.0020.000A][.1D98.0020.000A][.1D98.0020.000A] # ROMAN NUMERAL SEVEN +2177 ; [.1F49.0020.0004][.1D98.0020.0004][.1D98.0020.0004][.1D98.0020.0004] # SMALL ROMAN NUMERAL EIGHT +2167 ; [.1F49.0020.000A][.1D98.0020.000A][.1D98.0020.000A][.1D98.0020.000A] # ROMAN NUMERAL EIGHT +33DE ; [.1F49.0020.001D][*063B.0020.001C][.1E10.0020.001C] # SQUARE V OVER M +1F1AC ; [.1F49.0020.001D][.1E43.0020.001D][.1CF5.0020.001D] # SQUARED VOD +1F19A ; [.1F49.0020.001D][.1ED7.0020.001D] # SQUARED VS +A761 ; [.1F49.0020.0004][.1F71.0020.0004] # LATIN SMALL LETTER VY +A760 ; [.1F49.0020.000A][.1F71.0020.000A] # LATIN CAPITAL LETTER VY +1D20 ; [.1F4D.0020.0002] # LATIN LETTER SMALL CAPITAL V +A75F ; [.1F4E.0020.0002] # LATIN SMALL LETTER V WITH DIAGONAL STROKE +A75E ; [.1F4E.0020.0008] # LATIN CAPITAL LETTER V WITH DIAGONAL STROKE +1D8C ; [.1F4F.0020.0002] # LATIN SMALL LETTER V WITH PALATAL HOOK +028B ; [.1F50.0020.0002] # LATIN SMALL LETTER V WITH HOOK +01B2 ; [.1F50.0020.0008] # LATIN CAPITAL LETTER V WITH HOOK +1DB9 ; [.1F50.0020.0014] # MODIFIER LETTER SMALL V WITH HOOK +2C71 ; [.1F54.0020.0002] # LATIN SMALL LETTER V WITH RIGHT HOOK +2C74 ; [.1F55.0020.0002] # LATIN SMALL LETTER V WITH CURL +1EFD ; [.1F56.0020.0002] # LATIN SMALL LETTER MIDDLE-WELSH V +1EFC ; [.1F56.0020.0008] # LATIN CAPITAL LETTER MIDDLE-WELSH V +028C ; [.1F57.0020.0002] # LATIN SMALL LETTER TURNED V +0245 ; [.1F57.0020.0008] # LATIN CAPITAL LETTER TURNED V +1DBA ; [.1F57.0020.0014] # MODIFIER LETTER SMALL TURNED V +0077 ; [.1F5B.0020.0002] # LATIN SMALL LETTER W +FF57 ; [.1F5B.0020.0003] # FULLWIDTH LATIN SMALL LETTER W +1DF1 ; [.1F5B.0020.0004] # COMBINING LATIN SMALL LETTER W +24B2 ; [*0318.0020.0004][.1F5B.0020.0004][*0319.0020.0004] # PARENTHESIZED LATIN SMALL LETTER W +1D430 ; [.1F5B.0020.0005] # MATHEMATICAL BOLD SMALL W +1D464 ; [.1F5B.0020.0005] # MATHEMATICAL ITALIC SMALL W +1D498 ; [.1F5B.0020.0005] # MATHEMATICAL BOLD ITALIC SMALL W +1D4CC ; [.1F5B.0020.0005] # MATHEMATICAL SCRIPT SMALL W +1D500 ; [.1F5B.0020.0005] # MATHEMATICAL BOLD SCRIPT SMALL W +1D534 ; [.1F5B.0020.0005] # MATHEMATICAL FRAKTUR SMALL W +1D568 ; [.1F5B.0020.0005] # MATHEMATICAL DOUBLE-STRUCK SMALL W +1D59C ; [.1F5B.0020.0005] # MATHEMATICAL BOLD FRAKTUR SMALL W +1D5D0 ; [.1F5B.0020.0005] # MATHEMATICAL SANS-SERIF SMALL W +1D604 ; [.1F5B.0020.0005] # MATHEMATICAL SANS-SERIF BOLD SMALL W +1D638 ; [.1F5B.0020.0005] # MATHEMATICAL SANS-SERIF ITALIC SMALL W +1D66C ; [.1F5B.0020.0005] # MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL W +1D6A0 ; [.1F5B.0020.0005] # MATHEMATICAL MONOSPACE SMALL W +24E6 ; [.1F5B.0020.0006] # CIRCLED LATIN SMALL LETTER W +0057 ; [.1F5B.0020.0008] # LATIN CAPITAL LETTER W +FF37 ; [.1F5B.0020.0009] # FULLWIDTH LATIN CAPITAL LETTER W +1F126 ; [*0318.0020.0004][.1F5B.0020.000A][*0319.0020.0004] # PARENTHESIZED LATIN CAPITAL LETTER W +1D416 ; [.1F5B.0020.000B] # MATHEMATICAL BOLD CAPITAL W +1D44A ; [.1F5B.0020.000B] # MATHEMATICAL ITALIC CAPITAL W +1D47E ; [.1F5B.0020.000B] # MATHEMATICAL BOLD ITALIC CAPITAL W +1D4B2 ; [.1F5B.0020.000B] # MATHEMATICAL SCRIPT CAPITAL W +1D4E6 ; [.1F5B.0020.000B] # MATHEMATICAL BOLD SCRIPT CAPITAL W +1D51A ; [.1F5B.0020.000B] # MATHEMATICAL FRAKTUR CAPITAL W +1D54E ; [.1F5B.0020.000B] # MATHEMATICAL DOUBLE-STRUCK CAPITAL W +1D582 ; [.1F5B.0020.000B] # MATHEMATICAL BOLD FRAKTUR CAPITAL W +1D5B6 ; [.1F5B.0020.000B] # MATHEMATICAL SANS-SERIF CAPITAL W +1D5EA ; [.1F5B.0020.000B] # MATHEMATICAL SANS-SERIF BOLD CAPITAL W +1D61E ; [.1F5B.0020.000B] # MATHEMATICAL SANS-SERIF ITALIC CAPITAL W +1D652 ; [.1F5B.0020.000B] # MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL W +1D686 ; [.1F5B.0020.000B] # MATHEMATICAL MONOSPACE CAPITAL W +24CC ; [.1F5B.0020.000C] # CIRCLED LATIN CAPITAL LETTER W +1F166 ; [.1F5B.0020.000C] # NEGATIVE CIRCLED LATIN CAPITAL LETTER W +02B7 ; [.1F5B.0020.0014] # MODIFIER LETTER SMALL W +1D42 ; [.1F5B.0020.001D] # MODIFIER LETTER CAPITAL W +1F146 ; [.1F5B.0020.001D] # SQUARED LATIN CAPITAL LETTER W +1F186 ; [.1F5B.0020.001D] # NEGATIVE SQUARED LATIN CAPITAL LETTER W +1E83 ; [.1F5B.0020.0002][.0000.0024.0002] # LATIN SMALL LETTER W WITH ACUTE +1E82 ; [.1F5B.0020.0008][.0000.0024.0002] # LATIN CAPITAL LETTER W WITH ACUTE +1E81 ; [.1F5B.0020.0002][.0000.0025.0002] # LATIN SMALL LETTER W WITH GRAVE +1E80 ; [.1F5B.0020.0008][.0000.0025.0002] # LATIN CAPITAL LETTER W WITH GRAVE +0175 ; [.1F5B.0020.0002][.0000.0027.0002] # LATIN SMALL LETTER W WITH CIRCUMFLEX +0174 ; [.1F5B.0020.0008][.0000.0027.0002] # LATIN CAPITAL LETTER W WITH CIRCUMFLEX +1E98 ; [.1F5B.0020.0002][.0000.0029.0002] # LATIN SMALL LETTER W WITH RING ABOVE +1E85 ; [.1F5B.0020.0002][.0000.002B.0002] # LATIN SMALL LETTER W WITH DIAERESIS +1E84 ; [.1F5B.0020.0008][.0000.002B.0002] # LATIN CAPITAL LETTER W WITH DIAERESIS +1E87 ; [.1F5B.0020.0002][.0000.002E.0002] # LATIN SMALL LETTER W WITH DOT ABOVE +1E86 ; [.1F5B.0020.0008][.0000.002E.0002] # LATIN CAPITAL LETTER W WITH DOT ABOVE +1E89 ; [.1F5B.0020.0002][.0000.0042.0002] # LATIN SMALL LETTER W WITH DOT BELOW +1E88 ; [.1F5B.0020.0008][.0000.0042.0002] # LATIN CAPITAL LETTER W WITH DOT BELOW +33DD ; [.1F5B.0020.001D][.1CC6.0020.001C] # SQUARE WB +1F14F ; [.1F5B.0020.001D][.1CE0.0020.001D] # SQUARED WC +1F18F ; [.1F5B.0020.001D][.1CE0.0020.001D] # NEGATIVE SQUARED WC +1F12E ; [.1F5B.0020.000C][.1F87.0020.000C] # CIRCLED WZ +1D21 ; [.1F5F.0020.0002] # LATIN LETTER SMALL CAPITAL W +2C73 ; [.1F60.0020.0002] # LATIN SMALL LETTER W WITH HOOK +2C72 ; [.1F60.0020.0008] # LATIN CAPITAL LETTER W WITH HOOK +028D ; [.1F61.0020.0002] # LATIN SMALL LETTER TURNED W +0078 ; [.1F65.0020.0002] # LATIN SMALL LETTER X +FF58 ; [.1F65.0020.0003] # FULLWIDTH LATIN SMALL LETTER X +036F ; [.1F65.0020.0004] # COMBINING LATIN SMALL LETTER X +2179 ; [.1F65.0020.0004] # SMALL ROMAN NUMERAL TEN +24B3 ; [*0318.0020.0004][.1F65.0020.0004][*0319.0020.0004] # PARENTHESIZED LATIN SMALL LETTER X +1D431 ; [.1F65.0020.0005] # MATHEMATICAL BOLD SMALL X +1D465 ; [.1F65.0020.0005] # MATHEMATICAL ITALIC SMALL X +1D499 ; [.1F65.0020.0005] # MATHEMATICAL BOLD ITALIC SMALL X +1D4CD ; [.1F65.0020.0005] # MATHEMATICAL SCRIPT SMALL X +1D501 ; [.1F65.0020.0005] # MATHEMATICAL BOLD SCRIPT SMALL X +1D535 ; [.1F65.0020.0005] # MATHEMATICAL FRAKTUR SMALL X +1D569 ; [.1F65.0020.0005] # MATHEMATICAL DOUBLE-STRUCK SMALL X +1D59D ; [.1F65.0020.0005] # MATHEMATICAL BOLD FRAKTUR SMALL X +1D5D1 ; [.1F65.0020.0005] # MATHEMATICAL SANS-SERIF SMALL X +1D605 ; [.1F65.0020.0005] # MATHEMATICAL SANS-SERIF BOLD SMALL X +1D639 ; [.1F65.0020.0005] # MATHEMATICAL SANS-SERIF ITALIC SMALL X +1D66D ; [.1F65.0020.0005] # MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL X +1D6A1 ; [.1F65.0020.0005] # MATHEMATICAL MONOSPACE SMALL X +24E7 ; [.1F65.0020.0006] # CIRCLED LATIN SMALL LETTER X +0058 ; [.1F65.0020.0008] # LATIN CAPITAL LETTER X +FF38 ; [.1F65.0020.0009] # FULLWIDTH LATIN CAPITAL LETTER X +2169 ; [.1F65.0020.000A] # ROMAN NUMERAL TEN +1F127 ; [*0318.0020.0004][.1F65.0020.000A][*0319.0020.0004] # PARENTHESIZED LATIN CAPITAL LETTER X +1D417 ; [.1F65.0020.000B] # MATHEMATICAL BOLD CAPITAL X +1D44B ; [.1F65.0020.000B] # MATHEMATICAL ITALIC CAPITAL X +1D47F ; [.1F65.0020.000B] # MATHEMATICAL BOLD ITALIC CAPITAL X +1D4B3 ; [.1F65.0020.000B] # MATHEMATICAL SCRIPT CAPITAL X +1D4E7 ; [.1F65.0020.000B] # MATHEMATICAL BOLD SCRIPT CAPITAL X +1D51B ; [.1F65.0020.000B] # MATHEMATICAL FRAKTUR CAPITAL X +1D54F ; [.1F65.0020.000B] # MATHEMATICAL DOUBLE-STRUCK CAPITAL X +1D583 ; [.1F65.0020.000B] # MATHEMATICAL BOLD FRAKTUR CAPITAL X +1D5B7 ; [.1F65.0020.000B] # MATHEMATICAL SANS-SERIF CAPITAL X +1D5EB ; [.1F65.0020.000B] # MATHEMATICAL SANS-SERIF BOLD CAPITAL X +1D61F ; [.1F65.0020.000B] # MATHEMATICAL SANS-SERIF ITALIC CAPITAL X +1D653 ; [.1F65.0020.000B] # MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL X +1D687 ; [.1F65.0020.000B] # MATHEMATICAL MONOSPACE CAPITAL X +24CD ; [.1F65.0020.000C] # CIRCLED LATIN CAPITAL LETTER X +1F167 ; [.1F65.0020.000C] # NEGATIVE CIRCLED LATIN CAPITAL LETTER X +02E3 ; [.1F65.0020.0014] # MODIFIER LETTER SMALL X +2093 ; [.1F65.0020.0015] # LATIN SUBSCRIPT SMALL LETTER X +1F147 ; [.1F65.0020.001D] # SQUARED LATIN CAPITAL LETTER X +1F187 ; [.1F65.0020.001D] # NEGATIVE SQUARED LATIN CAPITAL LETTER X +1E8D ; [.1F65.0020.0002][.0000.002B.0002] # LATIN SMALL LETTER X WITH DIAERESIS +1E8C ; [.1F65.0020.0008][.0000.002B.0002] # LATIN CAPITAL LETTER X WITH DIAERESIS +1E8B ; [.1F65.0020.0002][.0000.002E.0002] # LATIN SMALL LETTER X WITH DOT ABOVE +1E8A ; [.1F65.0020.0008][.0000.002E.0002] # LATIN CAPITAL LETTER X WITH DOT ABOVE +217A ; [.1F65.0020.0004][.1D98.0020.0004] # SMALL ROMAN NUMERAL ELEVEN +216A ; [.1F65.0020.000A][.1D98.0020.000A] # ROMAN NUMERAL ELEVEN +217B ; [.1F65.0020.0004][.1D98.0020.0004][.1D98.0020.0004] # SMALL ROMAN NUMERAL TWELVE +216B ; [.1F65.0020.000A][.1D98.0020.000A][.1D98.0020.000A] # ROMAN NUMERAL TWELVE +1D8D ; [.1F69.0020.0002] # LATIN SMALL LETTER X WITH PALATAL HOOK +AB56 ; [.1F6A.0020.0002] # LATIN SMALL LETTER X WITH LOW RIGHT RING +AB57 ; [.1F6B.0020.0002] # LATIN SMALL LETTER X WITH LONG LEFT LEG +AB58 ; [.1F6C.0020.0002] # LATIN SMALL LETTER X WITH LONG LEFT LEG AND LOW RIGHT RING +AB59 ; [.1F6D.0020.0002] # LATIN SMALL LETTER X WITH LONG LEFT LEG WITH SERIF +AB53 ; [.1F6E.0020.0002] # LATIN SMALL LETTER CHI +A7B3 ; [.1F6E.0020.0008] # LATIN CAPITAL LETTER CHI +AB54 ; [.1F6F.0020.0002] # LATIN SMALL LETTER CHI WITH LOW RIGHT RING +AB55 ; [.1F70.0020.0002] # LATIN SMALL LETTER CHI WITH LOW LEFT SERIF +0079 ; [.1F71.0020.0002] # LATIN SMALL LETTER Y +FF59 ; [.1F71.0020.0003] # FULLWIDTH LATIN SMALL LETTER Y +24B4 ; [*0318.0020.0004][.1F71.0020.0004][*0319.0020.0004] # PARENTHESIZED LATIN SMALL LETTER Y +1D432 ; [.1F71.0020.0005] # MATHEMATICAL BOLD SMALL Y +1D466 ; [.1F71.0020.0005] # MATHEMATICAL ITALIC SMALL Y +1D49A ; [.1F71.0020.0005] # MATHEMATICAL BOLD ITALIC SMALL Y +1D4CE ; [.1F71.0020.0005] # MATHEMATICAL SCRIPT SMALL Y +1D502 ; [.1F71.0020.0005] # MATHEMATICAL BOLD SCRIPT SMALL Y +1D536 ; [.1F71.0020.0005] # MATHEMATICAL FRAKTUR SMALL Y +1D56A ; [.1F71.0020.0005] # MATHEMATICAL DOUBLE-STRUCK SMALL Y +1D59E ; [.1F71.0020.0005] # MATHEMATICAL BOLD FRAKTUR SMALL Y +1D5D2 ; [.1F71.0020.0005] # MATHEMATICAL SANS-SERIF SMALL Y +1D606 ; [.1F71.0020.0005] # MATHEMATICAL SANS-SERIF BOLD SMALL Y +1D63A ; [.1F71.0020.0005] # MATHEMATICAL SANS-SERIF ITALIC SMALL Y +1D66E ; [.1F71.0020.0005] # MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL Y +1D6A2 ; [.1F71.0020.0005] # MATHEMATICAL MONOSPACE SMALL Y +24E8 ; [.1F71.0020.0006] # CIRCLED LATIN SMALL LETTER Y +0059 ; [.1F71.0020.0008] # LATIN CAPITAL LETTER Y +FF39 ; [.1F71.0020.0009] # FULLWIDTH LATIN CAPITAL LETTER Y +1F128 ; [*0318.0020.0004][.1F71.0020.000A][*0319.0020.0004] # PARENTHESIZED LATIN CAPITAL LETTER Y +1D418 ; [.1F71.0020.000B] # MATHEMATICAL BOLD CAPITAL Y +1D44C ; [.1F71.0020.000B] # MATHEMATICAL ITALIC CAPITAL Y +1D480 ; [.1F71.0020.000B] # MATHEMATICAL BOLD ITALIC CAPITAL Y +1D4B4 ; [.1F71.0020.000B] # MATHEMATICAL SCRIPT CAPITAL Y +1D4E8 ; [.1F71.0020.000B] # MATHEMATICAL BOLD SCRIPT CAPITAL Y +1D51C ; [.1F71.0020.000B] # MATHEMATICAL FRAKTUR CAPITAL Y +1D550 ; [.1F71.0020.000B] # MATHEMATICAL DOUBLE-STRUCK CAPITAL Y +1D584 ; [.1F71.0020.000B] # MATHEMATICAL BOLD FRAKTUR CAPITAL Y +1D5B8 ; [.1F71.0020.000B] # MATHEMATICAL SANS-SERIF CAPITAL Y +1D5EC ; [.1F71.0020.000B] # MATHEMATICAL SANS-SERIF BOLD CAPITAL Y +1D620 ; [.1F71.0020.000B] # MATHEMATICAL SANS-SERIF ITALIC CAPITAL Y +1D654 ; [.1F71.0020.000B] # MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL Y +1D688 ; [.1F71.0020.000B] # MATHEMATICAL MONOSPACE CAPITAL Y +24CE ; [.1F71.0020.000C] # CIRCLED LATIN CAPITAL LETTER Y +1F168 ; [.1F71.0020.000C] # NEGATIVE CIRCLED LATIN CAPITAL LETTER Y +02B8 ; [.1F71.0020.0014] # MODIFIER LETTER SMALL Y +1F148 ; [.1F71.0020.001D] # SQUARED LATIN CAPITAL LETTER Y +1F188 ; [.1F71.0020.001D] # NEGATIVE SQUARED LATIN CAPITAL LETTER Y +00FD ; [.1F71.0020.0002][.0000.0024.0002] # LATIN SMALL LETTER Y WITH ACUTE +00DD ; [.1F71.0020.0008][.0000.0024.0002] # LATIN CAPITAL LETTER Y WITH ACUTE +1EF3 ; [.1F71.0020.0002][.0000.0025.0002] # LATIN SMALL LETTER Y WITH GRAVE +1EF2 ; [.1F71.0020.0008][.0000.0025.0002] # LATIN CAPITAL LETTER Y WITH GRAVE +0177 ; [.1F71.0020.0002][.0000.0027.0002] # LATIN SMALL LETTER Y WITH CIRCUMFLEX +0176 ; [.1F71.0020.0008][.0000.0027.0002] # LATIN CAPITAL LETTER Y WITH CIRCUMFLEX +1E99 ; [.1F71.0020.0002][.0000.0029.0002] # LATIN SMALL LETTER Y WITH RING ABOVE +00FF ; [.1F71.0020.0002][.0000.002B.0002] # LATIN SMALL LETTER Y WITH DIAERESIS +0178 ; [.1F71.0020.0008][.0000.002B.0002] # LATIN CAPITAL LETTER Y WITH DIAERESIS +1EF9 ; [.1F71.0020.0002][.0000.002D.0002] # LATIN SMALL LETTER Y WITH TILDE +1EF8 ; [.1F71.0020.0008][.0000.002D.0002] # LATIN CAPITAL LETTER Y WITH TILDE +1E8F ; [.1F71.0020.0002][.0000.002E.0002] # LATIN SMALL LETTER Y WITH DOT ABOVE +1E8E ; [.1F71.0020.0008][.0000.002E.0002] # LATIN CAPITAL LETTER Y WITH DOT ABOVE +0233 ; [.1F71.0020.0002][.0000.0032.0002] # LATIN SMALL LETTER Y WITH MACRON +0232 ; [.1F71.0020.0008][.0000.0032.0002] # LATIN CAPITAL LETTER Y WITH MACRON +1EF7 ; [.1F71.0020.0002][.0000.003B.0002] # LATIN SMALL LETTER Y WITH HOOK ABOVE +1EF6 ; [.1F71.0020.0008][.0000.003B.0002] # LATIN CAPITAL LETTER Y WITH HOOK ABOVE +1EF5 ; [.1F71.0020.0002][.0000.0042.0002] # LATIN SMALL LETTER Y WITH DOT BELOW +1EF4 ; [.1F71.0020.0008][.0000.0042.0002] # LATIN CAPITAL LETTER Y WITH DOT BELOW +028F ; [.1F75.0020.0002] # LATIN LETTER SMALL CAPITAL Y +024F ; [.1F79.0020.0002] # LATIN SMALL LETTER Y WITH STROKE +024E ; [.1F79.0020.0008] # LATIN CAPITAL LETTER Y WITH STROKE +01B4 ; [.1F7D.0020.0002] # LATIN SMALL LETTER Y WITH HOOK +01B3 ; [.1F7D.0020.0008] # LATIN CAPITAL LETTER Y WITH HOOK +1EFF ; [.1F81.0020.0002] # LATIN SMALL LETTER Y WITH LOOP +1EFE ; [.1F81.0020.0008] # LATIN CAPITAL LETTER Y WITH LOOP +AB5A ; [.1F82.0020.0002] # LATIN SMALL LETTER Y WITH SHORT RIGHT LEG +021D ; [.1F83.0020.0002] # LATIN SMALL LETTER YOGH +021C ; [.1F83.0020.0008] # LATIN CAPITAL LETTER YOGH +007A ; [.1F87.0020.0002] # LATIN SMALL LETTER Z +FF5A ; [.1F87.0020.0003] # FULLWIDTH LATIN SMALL LETTER Z +1DE6 ; [.1F87.0020.0004] # COMBINING LATIN SMALL LETTER Z +24B5 ; [*0318.0020.0004][.1F87.0020.0004][*0319.0020.0004] # PARENTHESIZED LATIN SMALL LETTER Z +1D433 ; [.1F87.0020.0005] # MATHEMATICAL BOLD SMALL Z +1D467 ; [.1F87.0020.0005] # MATHEMATICAL ITALIC SMALL Z +1D49B ; [.1F87.0020.0005] # MATHEMATICAL BOLD ITALIC SMALL Z +1D4CF ; [.1F87.0020.0005] # MATHEMATICAL SCRIPT SMALL Z +1D503 ; [.1F87.0020.0005] # MATHEMATICAL BOLD SCRIPT SMALL Z +1D537 ; [.1F87.0020.0005] # MATHEMATICAL FRAKTUR SMALL Z +1D56B ; [.1F87.0020.0005] # MATHEMATICAL DOUBLE-STRUCK SMALL Z +1D59F ; [.1F87.0020.0005] # MATHEMATICAL BOLD FRAKTUR SMALL Z +1D5D3 ; [.1F87.0020.0005] # MATHEMATICAL SANS-SERIF SMALL Z +1D607 ; [.1F87.0020.0005] # MATHEMATICAL SANS-SERIF BOLD SMALL Z +1D63B ; [.1F87.0020.0005] # MATHEMATICAL SANS-SERIF ITALIC SMALL Z +1D66F ; [.1F87.0020.0005] # MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL Z +1D6A3 ; [.1F87.0020.0005] # MATHEMATICAL MONOSPACE SMALL Z +24E9 ; [.1F87.0020.0006] # CIRCLED LATIN SMALL LETTER Z +005A ; [.1F87.0020.0008] # LATIN CAPITAL LETTER Z +FF3A ; [.1F87.0020.0009] # FULLWIDTH LATIN CAPITAL LETTER Z +1F129 ; [*0318.0020.0004][.1F87.0020.000A][*0319.0020.0004] # PARENTHESIZED LATIN CAPITAL LETTER Z +2124 ; [.1F87.0020.000B] # DOUBLE-STRUCK CAPITAL Z +2128 ; [.1F87.0020.000B] # BLACK-LETTER CAPITAL Z +1D419 ; [.1F87.0020.000B] # MATHEMATICAL BOLD CAPITAL Z +1D44D ; [.1F87.0020.000B] # MATHEMATICAL ITALIC CAPITAL Z +1D481 ; [.1F87.0020.000B] # MATHEMATICAL BOLD ITALIC CAPITAL Z +1D4B5 ; [.1F87.0020.000B] # MATHEMATICAL SCRIPT CAPITAL Z +1D4E9 ; [.1F87.0020.000B] # MATHEMATICAL BOLD SCRIPT CAPITAL Z +1D585 ; [.1F87.0020.000B] # MATHEMATICAL BOLD FRAKTUR CAPITAL Z +1D5B9 ; [.1F87.0020.000B] # MATHEMATICAL SANS-SERIF CAPITAL Z +1D5ED ; [.1F87.0020.000B] # MATHEMATICAL SANS-SERIF BOLD CAPITAL Z +1D621 ; [.1F87.0020.000B] # MATHEMATICAL SANS-SERIF ITALIC CAPITAL Z +1D655 ; [.1F87.0020.000B] # MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL Z +1D689 ; [.1F87.0020.000B] # MATHEMATICAL MONOSPACE CAPITAL Z +24CF ; [.1F87.0020.000C] # CIRCLED LATIN CAPITAL LETTER Z +1F169 ; [.1F87.0020.000C] # NEGATIVE CIRCLED LATIN CAPITAL LETTER Z +1DBB ; [.1F87.0020.0014] # MODIFIER LETTER SMALL Z +1F149 ; [.1F87.0020.001D] # SQUARED LATIN CAPITAL LETTER Z +1F189 ; [.1F87.0020.001D] # NEGATIVE SQUARED LATIN CAPITAL LETTER Z +017A ; [.1F87.0020.0002][.0000.0024.0002] # LATIN SMALL LETTER Z WITH ACUTE +0179 ; [.1F87.0020.0008][.0000.0024.0002] # LATIN CAPITAL LETTER Z WITH ACUTE +1E91 ; [.1F87.0020.0002][.0000.0027.0002] # LATIN SMALL LETTER Z WITH CIRCUMFLEX +1E90 ; [.1F87.0020.0008][.0000.0027.0002] # LATIN CAPITAL LETTER Z WITH CIRCUMFLEX +017E ; [.1F87.0020.0002][.0000.0028.0002] # LATIN SMALL LETTER Z WITH CARON +017D ; [.1F87.0020.0008][.0000.0028.0002] # LATIN CAPITAL LETTER Z WITH CARON +017C ; [.1F87.0020.0002][.0000.002E.0002] # LATIN SMALL LETTER Z WITH DOT ABOVE +017B ; [.1F87.0020.0008][.0000.002E.0002] # LATIN CAPITAL LETTER Z WITH DOT ABOVE +1E93 ; [.1F87.0020.0002][.0000.0042.0002] # LATIN SMALL LETTER Z WITH DOT BELOW +1E92 ; [.1F87.0020.0008][.0000.0042.0002] # LATIN CAPITAL LETTER Z WITH DOT BELOW +1E95 ; [.1F87.0020.0002][.0000.0049.0002] # LATIN SMALL LETTER Z WITH LINE BELOW +1E94 ; [.1F87.0020.0008][.0000.0049.0002] # LATIN CAPITAL LETTER Z WITH LINE BELOW +018D ; [.1F87.0020.0004][.1F5B.0020.0004] # LATIN SMALL LETTER TURNED DELTA +1D22 ; [.1F8B.0020.0002] # LATIN LETTER SMALL CAPITAL Z +01B6 ; [.1F8C.0020.0002] # LATIN SMALL LETTER Z WITH STROKE +01B5 ; [.1F8C.0020.0008] # LATIN CAPITAL LETTER Z WITH STROKE +1D76 ; [.1F90.0020.0002] # LATIN SMALL LETTER Z WITH MIDDLE TILDE +1D8E ; [.1F91.0020.0002] # LATIN SMALL LETTER Z WITH PALATAL HOOK +0225 ; [.1F92.0020.0002] # LATIN SMALL LETTER Z WITH HOOK +0224 ; [.1F92.0020.0008] # LATIN CAPITAL LETTER Z WITH HOOK +0290 ; [.1F96.0020.0002] # LATIN SMALL LETTER Z WITH RETROFLEX HOOK +1DBC ; [.1F96.0020.0014] # MODIFIER LETTER SMALL Z WITH RETROFLEX HOOK +0291 ; [.1F9A.0020.0002] # LATIN SMALL LETTER Z WITH CURL +1DBD ; [.1F9A.0020.0014] # MODIFIER LETTER SMALL Z WITH CURL +0240 ; [.1F9E.0020.0002] # LATIN SMALL LETTER Z WITH SWASH TAIL +2C7F ; [.1F9E.0020.0008] # LATIN CAPITAL LETTER Z WITH SWASH TAIL +2C6C ; [.1FA2.0020.0002] # LATIN SMALL LETTER Z WITH DESCENDER +2C6B ; [.1FA2.0020.0008] # LATIN CAPITAL LETTER Z WITH DESCENDER +A763 ; [.1FA3.0020.0002] # LATIN SMALL LETTER VISIGOTHIC Z +A762 ; [.1FA3.0020.0008] # LATIN CAPITAL LETTER VISIGOTHIC Z +0292 ; [.1FA4.0020.0002] # LATIN SMALL LETTER EZH +01B7 ; [.1FA4.0020.0008] # LATIN CAPITAL LETTER EZH +1DBE ; [.1FA4.0020.0014] # MODIFIER LETTER SMALL EZH +01EF ; [.1FA4.0020.0002][.0000.0028.0002] # LATIN SMALL LETTER EZH WITH CARON +01EE ; [.1FA4.0020.0008][.0000.0028.0002] # LATIN CAPITAL LETTER EZH WITH CARON +1D23 ; [.1FA8.0020.0002] # LATIN LETTER SMALL CAPITAL EZH +01B9 ; [.1FA9.0020.0002] # LATIN SMALL LETTER EZH REVERSED +01B8 ; [.1FA9.0020.0008] # LATIN CAPITAL LETTER EZH REVERSED +1D9A ; [.1FAD.0020.0002] # LATIN SMALL LETTER EZH WITH RETROFLEX HOOK +01BA ; [.1FAE.0020.0002] # LATIN SMALL LETTER EZH WITH TAIL +0293 ; [.1FB2.0020.0002] # LATIN SMALL LETTER EZH WITH CURL +00FE ; [.1FB6.0020.0002] # LATIN SMALL LETTER THORN +00DE ; [.1FB6.0020.0008] # LATIN CAPITAL LETTER THORN +A765 ; [.1FBA.0020.0002] # LATIN SMALL LETTER THORN WITH STROKE +A764 ; [.1FBA.0020.0008] # LATIN CAPITAL LETTER THORN WITH STROKE +A767 ; [.1FBB.0020.0002] # LATIN SMALL LETTER THORN WITH STROKE THROUGH DESCENDER +A766 ; [.1FBB.0020.0008] # LATIN CAPITAL LETTER THORN WITH STROKE THROUGH DESCENDER +01BF ; [.1FBC.0020.0002] # LATIN LETTER WYNN +01F7 ; [.1FBC.0020.0008] # LATIN CAPITAL LETTER WYNN +A769 ; [.1FC0.0020.0002] # LATIN SMALL LETTER VEND +A768 ; [.1FC0.0020.0008] # LATIN CAPITAL LETTER VEND +AB60 ; [.1FC1.0020.0002] # LATIN SMALL LETTER SAKHA YAT +AB61 ; [.1FC2.0020.0002] # LATIN SMALL LETTER IOTIFIED E +AB63 ; [.1FC3.0020.0002] # LATIN SMALL LETTER UO +A76B ; [.1FC4.0020.0002] # LATIN SMALL LETTER ET +A76A ; [.1FC4.0020.0008] # LATIN CAPITAL LETTER ET +A76D ; [.1FC5.0020.0002] # LATIN SMALL LETTER IS +A76C ; [.1FC5.0020.0008] # LATIN CAPITAL LETTER IS +A76F ; [.1FC6.0020.0002] # LATIN SMALL LETTER CON +1DD2 ; [.1FC6.0020.0004] # COMBINING US ABOVE +A76E ; [.1FC6.0020.0008] # LATIN CAPITAL LETTER CON +A770 ; [.1FC6.0020.0014] # MODIFIER LETTER US +A778 ; [.1FC7.0020.0002] # LATIN SMALL LETTER UM +01BB ; [.1FC8.0020.0002] # LATIN LETTER TWO WITH STROKE +A72B ; [.1FCC.0020.0002] # LATIN SMALL LETTER TRESILLO +A72A ; [.1FCC.0020.0008] # LATIN CAPITAL LETTER TRESILLO +A72D ; [.1FCD.0020.0002] # LATIN SMALL LETTER CUATRILLO +A72C ; [.1FCD.0020.0008] # LATIN CAPITAL LETTER CUATRILLO +A72F ; [.1FCE.0020.0002] # LATIN SMALL LETTER CUATRILLO WITH COMMA +A72E ; [.1FCE.0020.0008] # LATIN CAPITAL LETTER CUATRILLO WITH COMMA +01A8 ; [.1FCF.0020.0002] # LATIN SMALL LETTER TONE TWO +01A7 ; [.1FCF.0020.0008] # LATIN CAPITAL LETTER TONE TWO +01BD ; [.1FD3.0020.0002] # LATIN SMALL LETTER TONE FIVE +01BC ; [.1FD3.0020.0008] # LATIN CAPITAL LETTER TONE FIVE +0185 ; [.1FD7.0020.0002] # LATIN SMALL LETTER TONE SIX +0184 ; [.1FD7.0020.0008] # LATIN CAPITAL LETTER TONE SIX +0294 ; [.1FDB.0020.0002] # LATIN LETTER GLOTTAL STOP +0242 ; [.1FDF.0020.0002] # LATIN SMALL LETTER GLOTTAL STOP +0241 ; [.1FDF.0020.0008] # LATIN CAPITAL LETTER GLOTTAL STOP +02C0 ; [.1FE3.0020.0002] # MODIFIER LETTER GLOTTAL STOP +02BC ; [.1FE4.0020.0002] # MODIFIER LETTER APOSTROPHE +0149 ; [.1FE4.0020.0004][.1E1F.0020.0004] # LATIN SMALL LETTER N PRECEDED BY APOSTROPHE +02EE ; [.1FE5.0020.0002] # MODIFIER LETTER DOUBLE APOSTROPHE +02BE ; [.1FE6.0020.0002] # MODIFIER LETTER RIGHT HALF RING +A723 ; [.1FE7.0020.0002] # LATIN SMALL LETTER EGYPTOLOGICAL ALEF +A722 ; [.1FE7.0020.0008] # LATIN CAPITAL LETTER EGYPTOLOGICAL ALEF +A78C ; [.1FE8.0020.0002] # LATIN SMALL LETTER SALTILLO +A78B ; [.1FE8.0020.0008] # LATIN CAPITAL LETTER SALTILLO +A78F ; [.1FE9.0020.0002] # LATIN LETTER SINOLOGICAL DOT +0295 ; [.1FEA.0020.0002] # LATIN LETTER PHARYNGEAL VOICED FRICATIVE +02E4 ; [.1FEA.0020.0014] # MODIFIER LETTER SMALL REVERSED GLOTTAL STOP +02BF ; [.1FEE.0020.0002] # MODIFIER LETTER LEFT HALF RING +02C1 ; [.1FEF.0020.0002] # MODIFIER LETTER REVERSED GLOTTAL STOP +1D24 ; [.1FF0.0020.0002] # LATIN LETTER VOICED LARYNGEAL SPIRANT +1D25 ; [.1FF1.0020.0002] # LATIN LETTER AIN +1D5C ; [.1FF1.0020.0014] # MODIFIER LETTER SMALL AIN +A725 ; [.1FF2.0020.0002] # LATIN SMALL LETTER EGYPTOLOGICAL AIN +A724 ; [.1FF2.0020.0008] # LATIN CAPITAL LETTER EGYPTOLOGICAL AIN +02A1 ; [.1FF3.0020.0002] # LATIN LETTER GLOTTAL STOP WITH STROKE +02A2 ; [.1FF7.0020.0002] # LATIN LETTER REVERSED GLOTTAL STOP WITH STROKE +0296 ; [.1FFB.0020.0002] # LATIN LETTER INVERTED GLOTTAL STOP +01C0 ; [.1FFF.0020.0002] # LATIN LETTER DENTAL CLICK +01C1 ; [.2003.0020.0002] # LATIN LETTER LATERAL CLICK +01C2 ; [.2007.0020.0002] # LATIN LETTER ALVEOLAR CLICK +01C3 ; [.200B.0020.0002] # LATIN LETTER RETROFLEX CLICK +0297 ; [.200F.0020.0002] # LATIN LETTER STRETCHED C +0298 ; [.2013.0020.0002] # LATIN LETTER BILABIAL CLICK +02AC ; [.2017.0020.0002] # LATIN LETTER BILABIAL PERCUSSIVE +02AD ; [.201B.0020.0002] # LATIN LETTER BIDENTAL PERCUSSIVE +03B1 ; [.201F.0020.0002] # GREEK SMALL LETTER ALPHA +1D6C2 ; [.201F.0020.0005] # MATHEMATICAL BOLD SMALL ALPHA +1D6FC ; [.201F.0020.0005] # MATHEMATICAL ITALIC SMALL ALPHA +1D736 ; [.201F.0020.0005] # MATHEMATICAL BOLD ITALIC SMALL ALPHA +1D770 ; [.201F.0020.0005] # MATHEMATICAL SANS-SERIF BOLD SMALL ALPHA +1D7AA ; [.201F.0020.0005] # MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL ALPHA +0391 ; [.201F.0020.0008] # GREEK CAPITAL LETTER ALPHA +1D6A8 ; [.201F.0020.000B] # MATHEMATICAL BOLD CAPITAL ALPHA +1D6E2 ; [.201F.0020.000B] # MATHEMATICAL ITALIC CAPITAL ALPHA +1D71C ; [.201F.0020.000B] # MATHEMATICAL BOLD ITALIC CAPITAL ALPHA +1D756 ; [.201F.0020.000B] # MATHEMATICAL SANS-SERIF BOLD CAPITAL ALPHA +1D790 ; [.201F.0020.000B] # MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL ALPHA +1F00 ; [.201F.0020.0002][.0000.0022.0002] # GREEK SMALL LETTER ALPHA WITH PSILI +1F08 ; [.201F.0020.0008][.0000.0022.0002] # GREEK CAPITAL LETTER ALPHA WITH PSILI +1F04 ; [.201F.0020.0002][.0000.0022.0002][.0000.0024.0002] # GREEK SMALL LETTER ALPHA WITH PSILI AND OXIA +1F0C ; [.201F.0020.0008][.0000.0022.0002][.0000.0024.0002] # GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA +1F84 ; [.201F.0020.0002][.0000.0022.0002][.0000.0024.0002][.0000.004C.0002] # GREEK SMALL LETTER ALPHA WITH PSILI AND OXIA AND YPOGEGRAMMENI +1F8C ; [.201F.0020.0008][.0000.0022.0002][.0000.0024.0002][.0000.004C.0002] # GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA AND PROSGEGRAMMENI +1F02 ; [.201F.0020.0002][.0000.0022.0002][.0000.0025.0002] # GREEK SMALL LETTER ALPHA WITH PSILI AND VARIA +1F0A ; [.201F.0020.0008][.0000.0022.0002][.0000.0025.0002] # GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA +1F82 ; [.201F.0020.0002][.0000.0022.0002][.0000.0025.0002][.0000.004C.0002] # GREEK SMALL LETTER ALPHA WITH PSILI AND VARIA AND YPOGEGRAMMENI +1F8A ; [.201F.0020.0008][.0000.0022.0002][.0000.0025.0002][.0000.004C.0002] # GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA AND PROSGEGRAMMENI +1F06 ; [.201F.0020.0002][.0000.0022.0002][.0000.002A.0002] # GREEK SMALL LETTER ALPHA WITH PSILI AND PERISPOMENI +1F0E ; [.201F.0020.0008][.0000.0022.0002][.0000.002A.0002] # GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI +1F86 ; [.201F.0020.0002][.0000.0022.0002][.0000.002A.0002][.0000.004C.0002] # GREEK SMALL LETTER ALPHA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI +1F8E ; [.201F.0020.0008][.0000.0022.0002][.0000.002A.0002][.0000.004C.0002] # GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI +1F80 ; [.201F.0020.0002][.0000.0022.0002][.0000.004C.0002] # GREEK SMALL LETTER ALPHA WITH PSILI AND YPOGEGRAMMENI +1F88 ; [.201F.0020.0008][.0000.0022.0002][.0000.004C.0002] # GREEK CAPITAL LETTER ALPHA WITH PSILI AND PROSGEGRAMMENI +1F01 ; [.201F.0020.0002][.0000.0023.0002] # GREEK SMALL LETTER ALPHA WITH DASIA +1F09 ; [.201F.0020.0008][.0000.0023.0002] # GREEK CAPITAL LETTER ALPHA WITH DASIA +1F05 ; [.201F.0020.0002][.0000.0023.0002][.0000.0024.0002] # GREEK SMALL LETTER ALPHA WITH DASIA AND OXIA +1F0D ; [.201F.0020.0008][.0000.0023.0002][.0000.0024.0002] # GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA +1F85 ; [.201F.0020.0002][.0000.0023.0002][.0000.0024.0002][.0000.004C.0002] # GREEK SMALL LETTER ALPHA WITH DASIA AND OXIA AND YPOGEGRAMMENI +1F8D ; [.201F.0020.0008][.0000.0023.0002][.0000.0024.0002][.0000.004C.0002] # GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA AND PROSGEGRAMMENI +1F03 ; [.201F.0020.0002][.0000.0023.0002][.0000.0025.0002] # GREEK SMALL LETTER ALPHA WITH DASIA AND VARIA +1F0B ; [.201F.0020.0008][.0000.0023.0002][.0000.0025.0002] # GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA +1F83 ; [.201F.0020.0002][.0000.0023.0002][.0000.0025.0002][.0000.004C.0002] # GREEK SMALL LETTER ALPHA WITH DASIA AND VARIA AND YPOGEGRAMMENI +1F8B ; [.201F.0020.0008][.0000.0023.0002][.0000.0025.0002][.0000.004C.0002] # GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA AND PROSGEGRAMMENI +1F07 ; [.201F.0020.0002][.0000.0023.0002][.0000.002A.0002] # GREEK SMALL LETTER ALPHA WITH DASIA AND PERISPOMENI +1F0F ; [.201F.0020.0008][.0000.0023.0002][.0000.002A.0002] # GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI +1F87 ; [.201F.0020.0002][.0000.0023.0002][.0000.002A.0002][.0000.004C.0002] # GREEK SMALL LETTER ALPHA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI +1F8F ; [.201F.0020.0008][.0000.0023.0002][.0000.002A.0002][.0000.004C.0002] # GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI +1F81 ; [.201F.0020.0002][.0000.0023.0002][.0000.004C.0002] # GREEK SMALL LETTER ALPHA WITH DASIA AND YPOGEGRAMMENI +1F89 ; [.201F.0020.0008][.0000.0023.0002][.0000.004C.0002] # GREEK CAPITAL LETTER ALPHA WITH DASIA AND PROSGEGRAMMENI +03AC ; [.201F.0020.0002][.0000.0024.0002] # GREEK SMALL LETTER ALPHA WITH TONOS +1F71 ; [.201F.0020.0002][.0000.0024.0002] # GREEK SMALL LETTER ALPHA WITH OXIA +0386 ; [.201F.0020.0008][.0000.0024.0002] # GREEK CAPITAL LETTER ALPHA WITH TONOS +1FBB ; [.201F.0020.0008][.0000.0024.0002] # GREEK CAPITAL LETTER ALPHA WITH OXIA +1FB4 ; [.201F.0020.0002][.0000.0024.0002][.0000.004C.0002] # GREEK SMALL LETTER ALPHA WITH OXIA AND YPOGEGRAMMENI +1F70 ; [.201F.0020.0002][.0000.0025.0002] # GREEK SMALL LETTER ALPHA WITH VARIA +1FBA ; [.201F.0020.0008][.0000.0025.0002] # GREEK CAPITAL LETTER ALPHA WITH VARIA +1FB2 ; [.201F.0020.0002][.0000.0025.0002][.0000.004C.0002] # GREEK SMALL LETTER ALPHA WITH VARIA AND YPOGEGRAMMENI +1FB0 ; [.201F.0020.0002][.0000.0026.0002] # GREEK SMALL LETTER ALPHA WITH VRACHY +1FB8 ; [.201F.0020.0008][.0000.0026.0002] # GREEK CAPITAL LETTER ALPHA WITH VRACHY +1FB6 ; [.201F.0020.0002][.0000.002A.0002] # GREEK SMALL LETTER ALPHA WITH PERISPOMENI +1FB7 ; [.201F.0020.0002][.0000.002A.0002][.0000.004C.0002] # GREEK SMALL LETTER ALPHA WITH PERISPOMENI AND YPOGEGRAMMENI +1FB1 ; [.201F.0020.0002][.0000.0032.0002] # GREEK SMALL LETTER ALPHA WITH MACRON +1FB9 ; [.201F.0020.0008][.0000.0032.0002] # GREEK CAPITAL LETTER ALPHA WITH MACRON +1FB3 ; [.201F.0020.0002][.0000.004C.0002] # GREEK SMALL LETTER ALPHA WITH YPOGEGRAMMENI +1FBC ; [.201F.0020.0008][.0000.004C.0002] # GREEK CAPITAL LETTER ALPHA WITH PROSGEGRAMMENI +03B2 ; [.2020.0020.0002] # GREEK SMALL LETTER BETA +03D0 ; [.2020.0020.0004] # GREEK BETA SYMBOL +1D6C3 ; [.2020.0020.0005] # MATHEMATICAL BOLD SMALL BETA +1D6FD ; [.2020.0020.0005] # MATHEMATICAL ITALIC SMALL BETA +1D737 ; [.2020.0020.0005] # MATHEMATICAL BOLD ITALIC SMALL BETA +1D771 ; [.2020.0020.0005] # MATHEMATICAL SANS-SERIF BOLD SMALL BETA +1D7AB ; [.2020.0020.0005] # MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL BETA +0392 ; [.2020.0020.0008] # GREEK CAPITAL LETTER BETA +1D6A9 ; [.2020.0020.000B] # MATHEMATICAL BOLD CAPITAL BETA +1D6E3 ; [.2020.0020.000B] # MATHEMATICAL ITALIC CAPITAL BETA +1D71D ; [.2020.0020.000B] # MATHEMATICAL BOLD ITALIC CAPITAL BETA +1D757 ; [.2020.0020.000B] # MATHEMATICAL SANS-SERIF BOLD CAPITAL BETA +1D791 ; [.2020.0020.000B] # MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL BETA +1D5D ; [.2020.0020.0014] # MODIFIER LETTER SMALL BETA +1D66 ; [.2020.0020.0015] # GREEK SUBSCRIPT SMALL LETTER BETA +03B3 ; [.2021.0020.0002] # GREEK SMALL LETTER GAMMA +213D ; [.2021.0020.0005] # DOUBLE-STRUCK SMALL GAMMA +1D6C4 ; [.2021.0020.0005] # MATHEMATICAL BOLD SMALL GAMMA +1D6FE ; [.2021.0020.0005] # MATHEMATICAL ITALIC SMALL GAMMA +1D738 ; [.2021.0020.0005] # MATHEMATICAL BOLD ITALIC SMALL GAMMA +1D772 ; [.2021.0020.0005] # MATHEMATICAL SANS-SERIF BOLD SMALL GAMMA +1D7AC ; [.2021.0020.0005] # MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL GAMMA +0393 ; [.2021.0020.0008] # GREEK CAPITAL LETTER GAMMA +213E ; [.2021.0020.000B] # DOUBLE-STRUCK CAPITAL GAMMA +1D6AA ; [.2021.0020.000B] # MATHEMATICAL BOLD CAPITAL GAMMA +1D6E4 ; [.2021.0020.000B] # MATHEMATICAL ITALIC CAPITAL GAMMA +1D71E ; [.2021.0020.000B] # MATHEMATICAL BOLD ITALIC CAPITAL GAMMA +1D758 ; [.2021.0020.000B] # MATHEMATICAL SANS-SERIF BOLD CAPITAL GAMMA +1D792 ; [.2021.0020.000B] # MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL GAMMA +1D5E ; [.2021.0020.0014] # MODIFIER LETTER SMALL GREEK GAMMA +1D67 ; [.2021.0020.0015] # GREEK SUBSCRIPT SMALL LETTER GAMMA +1D26 ; [.2022.0020.0002] # GREEK LETTER SMALL CAPITAL GAMMA +03B4 ; [.2023.0020.0002] # GREEK SMALL LETTER DELTA +1D6C5 ; [.2023.0020.0005] # MATHEMATICAL BOLD SMALL DELTA +1D6FF ; [.2023.0020.0005] # MATHEMATICAL ITALIC SMALL DELTA +1D739 ; [.2023.0020.0005] # MATHEMATICAL BOLD ITALIC SMALL DELTA +1D773 ; [.2023.0020.0005] # MATHEMATICAL SANS-SERIF BOLD SMALL DELTA +1D7AD ; [.2023.0020.0005] # MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL DELTA +0394 ; [.2023.0020.0008] # GREEK CAPITAL LETTER DELTA +1D6AB ; [.2023.0020.000B] # MATHEMATICAL BOLD CAPITAL DELTA +1D6E5 ; [.2023.0020.000B] # MATHEMATICAL ITALIC CAPITAL DELTA +1D71F ; [.2023.0020.000B] # MATHEMATICAL BOLD ITALIC CAPITAL DELTA +1D759 ; [.2023.0020.000B] # MATHEMATICAL SANS-SERIF BOLD CAPITAL DELTA +1D793 ; [.2023.0020.000B] # MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL DELTA +1D5F ; [.2023.0020.0014] # MODIFIER LETTER SMALL DELTA +03B5 ; [.2024.0020.0002] # GREEK SMALL LETTER EPSILON +03F5 ; [.2024.0020.0004] # GREEK LUNATE EPSILON SYMBOL +1D6C6 ; [.2024.0020.0005] # MATHEMATICAL BOLD SMALL EPSILON +1D6DC ; [.2024.0020.0005] # MATHEMATICAL BOLD EPSILON SYMBOL +1D700 ; [.2024.0020.0005] # MATHEMATICAL ITALIC SMALL EPSILON +1D716 ; [.2024.0020.0005] # MATHEMATICAL ITALIC EPSILON SYMBOL +1D73A ; [.2024.0020.0005] # MATHEMATICAL BOLD ITALIC SMALL EPSILON +1D750 ; [.2024.0020.0005] # MATHEMATICAL BOLD ITALIC EPSILON SYMBOL +1D774 ; [.2024.0020.0005] # MATHEMATICAL SANS-SERIF BOLD SMALL EPSILON +1D78A ; [.2024.0020.0005] # MATHEMATICAL SANS-SERIF BOLD EPSILON SYMBOL +1D7AE ; [.2024.0020.0005] # MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL EPSILON +1D7C4 ; [.2024.0020.0005] # MATHEMATICAL SANS-SERIF BOLD ITALIC EPSILON SYMBOL +0395 ; [.2024.0020.0008] # GREEK CAPITAL LETTER EPSILON +1D6AC ; [.2024.0020.000B] # MATHEMATICAL BOLD CAPITAL EPSILON +1D6E6 ; [.2024.0020.000B] # MATHEMATICAL ITALIC CAPITAL EPSILON +1D720 ; [.2024.0020.000B] # MATHEMATICAL BOLD ITALIC CAPITAL EPSILON +1D75A ; [.2024.0020.000B] # MATHEMATICAL SANS-SERIF BOLD CAPITAL EPSILON +1D794 ; [.2024.0020.000B] # MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL EPSILON +1F10 ; [.2024.0020.0002][.0000.0022.0002] # GREEK SMALL LETTER EPSILON WITH PSILI +1F18 ; [.2024.0020.0008][.0000.0022.0002] # GREEK CAPITAL LETTER EPSILON WITH PSILI +1F14 ; [.2024.0020.0002][.0000.0022.0002][.0000.0024.0002] # GREEK SMALL LETTER EPSILON WITH PSILI AND OXIA +1F1C ; [.2024.0020.0008][.0000.0022.0002][.0000.0024.0002] # GREEK CAPITAL LETTER EPSILON WITH PSILI AND OXIA +1F12 ; [.2024.0020.0002][.0000.0022.0002][.0000.0025.0002] # GREEK SMALL LETTER EPSILON WITH PSILI AND VARIA +1F1A ; [.2024.0020.0008][.0000.0022.0002][.0000.0025.0002] # GREEK CAPITAL LETTER EPSILON WITH PSILI AND VARIA +1F11 ; [.2024.0020.0002][.0000.0023.0002] # GREEK SMALL LETTER EPSILON WITH DASIA +1F19 ; [.2024.0020.0008][.0000.0023.0002] # GREEK CAPITAL LETTER EPSILON WITH DASIA +1F15 ; [.2024.0020.0002][.0000.0023.0002][.0000.0024.0002] # GREEK SMALL LETTER EPSILON WITH DASIA AND OXIA +1F1D ; [.2024.0020.0008][.0000.0023.0002][.0000.0024.0002] # GREEK CAPITAL LETTER EPSILON WITH DASIA AND OXIA +1F13 ; [.2024.0020.0002][.0000.0023.0002][.0000.0025.0002] # GREEK SMALL LETTER EPSILON WITH DASIA AND VARIA +1F1B ; [.2024.0020.0008][.0000.0023.0002][.0000.0025.0002] # GREEK CAPITAL LETTER EPSILON WITH DASIA AND VARIA +03AD ; [.2024.0020.0002][.0000.0024.0002] # GREEK SMALL LETTER EPSILON WITH TONOS +1F73 ; [.2024.0020.0002][.0000.0024.0002] # GREEK SMALL LETTER EPSILON WITH OXIA +0388 ; [.2024.0020.0008][.0000.0024.0002] # GREEK CAPITAL LETTER EPSILON WITH TONOS +1FC9 ; [.2024.0020.0008][.0000.0024.0002] # GREEK CAPITAL LETTER EPSILON WITH OXIA +1F72 ; [.2024.0020.0002][.0000.0025.0002] # GREEK SMALL LETTER EPSILON WITH VARIA +1FC8 ; [.2024.0020.0008][.0000.0025.0002] # GREEK CAPITAL LETTER EPSILON WITH VARIA +03DD ; [.2025.0020.0002] # GREEK SMALL LETTER DIGAMMA +1D7CB ; [.2025.0020.0005] # MATHEMATICAL BOLD SMALL DIGAMMA +03DC ; [.2025.0020.0008] # GREEK LETTER DIGAMMA +1D7CA ; [.2025.0020.000B] # MATHEMATICAL BOLD CAPITAL DIGAMMA +0377 ; [.2026.0020.0002] # GREEK SMALL LETTER PAMPHYLIAN DIGAMMA +0376 ; [.2026.0020.0008] # GREEK CAPITAL LETTER PAMPHYLIAN DIGAMMA +03DB ; [.2027.0020.0002] # GREEK SMALL LETTER STIGMA +03DA ; [.2027.0020.0008] # GREEK LETTER STIGMA +03B6 ; [.2028.0020.0002] # GREEK SMALL LETTER ZETA +1D6C7 ; [.2028.0020.0005] # MATHEMATICAL BOLD SMALL ZETA +1D701 ; [.2028.0020.0005] # MATHEMATICAL ITALIC SMALL ZETA +1D73B ; [.2028.0020.0005] # MATHEMATICAL BOLD ITALIC SMALL ZETA +1D775 ; [.2028.0020.0005] # MATHEMATICAL SANS-SERIF BOLD SMALL ZETA +1D7AF ; [.2028.0020.0005] # MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL ZETA +0396 ; [.2028.0020.0008] # GREEK CAPITAL LETTER ZETA +1D6AD ; [.2028.0020.000B] # MATHEMATICAL BOLD CAPITAL ZETA +1D6E7 ; [.2028.0020.000B] # MATHEMATICAL ITALIC CAPITAL ZETA +1D721 ; [.2028.0020.000B] # MATHEMATICAL BOLD ITALIC CAPITAL ZETA +1D75B ; [.2028.0020.000B] # MATHEMATICAL SANS-SERIF BOLD CAPITAL ZETA +1D795 ; [.2028.0020.000B] # MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL ZETA +0371 ; [.2029.0020.0002] # GREEK SMALL LETTER HETA +0370 ; [.2029.0020.0008] # GREEK CAPITAL LETTER HETA +03B7 ; [.202A.0020.0002] # GREEK SMALL LETTER ETA +1D6C8 ; [.202A.0020.0005] # MATHEMATICAL BOLD SMALL ETA +1D702 ; [.202A.0020.0005] # MATHEMATICAL ITALIC SMALL ETA +1D73C ; [.202A.0020.0005] # MATHEMATICAL BOLD ITALIC SMALL ETA +1D776 ; [.202A.0020.0005] # MATHEMATICAL SANS-SERIF BOLD SMALL ETA +1D7B0 ; [.202A.0020.0005] # MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL ETA +0397 ; [.202A.0020.0008] # GREEK CAPITAL LETTER ETA +1D6AE ; [.202A.0020.000B] # MATHEMATICAL BOLD CAPITAL ETA +1D6E8 ; [.202A.0020.000B] # MATHEMATICAL ITALIC CAPITAL ETA +1D722 ; [.202A.0020.000B] # MATHEMATICAL BOLD ITALIC CAPITAL ETA +1D75C ; [.202A.0020.000B] # MATHEMATICAL SANS-SERIF BOLD CAPITAL ETA +1D796 ; [.202A.0020.000B] # MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL ETA +1F20 ; [.202A.0020.0002][.0000.0022.0002] # GREEK SMALL LETTER ETA WITH PSILI +1F28 ; [.202A.0020.0008][.0000.0022.0002] # GREEK CAPITAL LETTER ETA WITH PSILI +1F24 ; [.202A.0020.0002][.0000.0022.0002][.0000.0024.0002] # GREEK SMALL LETTER ETA WITH PSILI AND OXIA +1F2C ; [.202A.0020.0008][.0000.0022.0002][.0000.0024.0002] # GREEK CAPITAL LETTER ETA WITH PSILI AND OXIA +1F94 ; [.202A.0020.0002][.0000.0022.0002][.0000.0024.0002][.0000.004C.0002] # GREEK SMALL LETTER ETA WITH PSILI AND OXIA AND YPOGEGRAMMENI +1F9C ; [.202A.0020.0008][.0000.0022.0002][.0000.0024.0002][.0000.004C.0002] # GREEK CAPITAL LETTER ETA WITH PSILI AND OXIA AND PROSGEGRAMMENI +1F22 ; [.202A.0020.0002][.0000.0022.0002][.0000.0025.0002] # GREEK SMALL LETTER ETA WITH PSILI AND VARIA +1F2A ; [.202A.0020.0008][.0000.0022.0002][.0000.0025.0002] # GREEK CAPITAL LETTER ETA WITH PSILI AND VARIA +1F92 ; [.202A.0020.0002][.0000.0022.0002][.0000.0025.0002][.0000.004C.0002] # GREEK SMALL LETTER ETA WITH PSILI AND VARIA AND YPOGEGRAMMENI +1F9A ; [.202A.0020.0008][.0000.0022.0002][.0000.0025.0002][.0000.004C.0002] # GREEK CAPITAL LETTER ETA WITH PSILI AND VARIA AND PROSGEGRAMMENI +1F26 ; [.202A.0020.0002][.0000.0022.0002][.0000.002A.0002] # GREEK SMALL LETTER ETA WITH PSILI AND PERISPOMENI +1F2E ; [.202A.0020.0008][.0000.0022.0002][.0000.002A.0002] # GREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENI +1F96 ; [.202A.0020.0002][.0000.0022.0002][.0000.002A.0002][.0000.004C.0002] # GREEK SMALL LETTER ETA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI +1F9E ; [.202A.0020.0008][.0000.0022.0002][.0000.002A.0002][.0000.004C.0002] # GREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI +1F90 ; [.202A.0020.0002][.0000.0022.0002][.0000.004C.0002] # GREEK SMALL LETTER ETA WITH PSILI AND YPOGEGRAMMENI +1F98 ; [.202A.0020.0008][.0000.0022.0002][.0000.004C.0002] # GREEK CAPITAL LETTER ETA WITH PSILI AND PROSGEGRAMMENI +1F21 ; [.202A.0020.0002][.0000.0023.0002] # GREEK SMALL LETTER ETA WITH DASIA +1F29 ; [.202A.0020.0008][.0000.0023.0002] # GREEK CAPITAL LETTER ETA WITH DASIA +1F25 ; [.202A.0020.0002][.0000.0023.0002][.0000.0024.0002] # GREEK SMALL LETTER ETA WITH DASIA AND OXIA +1F2D ; [.202A.0020.0008][.0000.0023.0002][.0000.0024.0002] # GREEK CAPITAL LETTER ETA WITH DASIA AND OXIA +1F95 ; [.202A.0020.0002][.0000.0023.0002][.0000.0024.0002][.0000.004C.0002] # GREEK SMALL LETTER ETA WITH DASIA AND OXIA AND YPOGEGRAMMENI +1F9D ; [.202A.0020.0008][.0000.0023.0002][.0000.0024.0002][.0000.004C.0002] # GREEK CAPITAL LETTER ETA WITH DASIA AND OXIA AND PROSGEGRAMMENI +1F23 ; [.202A.0020.0002][.0000.0023.0002][.0000.0025.0002] # GREEK SMALL LETTER ETA WITH DASIA AND VARIA +1F2B ; [.202A.0020.0008][.0000.0023.0002][.0000.0025.0002] # GREEK CAPITAL LETTER ETA WITH DASIA AND VARIA +1F93 ; [.202A.0020.0002][.0000.0023.0002][.0000.0025.0002][.0000.004C.0002] # GREEK SMALL LETTER ETA WITH DASIA AND VARIA AND YPOGEGRAMMENI +1F9B ; [.202A.0020.0008][.0000.0023.0002][.0000.0025.0002][.0000.004C.0002] # GREEK CAPITAL LETTER ETA WITH DASIA AND VARIA AND PROSGEGRAMMENI +1F27 ; [.202A.0020.0002][.0000.0023.0002][.0000.002A.0002] # GREEK SMALL LETTER ETA WITH DASIA AND PERISPOMENI +1F2F ; [.202A.0020.0008][.0000.0023.0002][.0000.002A.0002] # GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI +1F97 ; [.202A.0020.0002][.0000.0023.0002][.0000.002A.0002][.0000.004C.0002] # GREEK SMALL LETTER ETA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI +1F9F ; [.202A.0020.0008][.0000.0023.0002][.0000.002A.0002][.0000.004C.0002] # GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI +1F91 ; [.202A.0020.0002][.0000.0023.0002][.0000.004C.0002] # GREEK SMALL LETTER ETA WITH DASIA AND YPOGEGRAMMENI +1F99 ; [.202A.0020.0008][.0000.0023.0002][.0000.004C.0002] # GREEK CAPITAL LETTER ETA WITH DASIA AND PROSGEGRAMMENI +03AE ; [.202A.0020.0002][.0000.0024.0002] # GREEK SMALL LETTER ETA WITH TONOS +1F75 ; [.202A.0020.0002][.0000.0024.0002] # GREEK SMALL LETTER ETA WITH OXIA +0389 ; [.202A.0020.0008][.0000.0024.0002] # GREEK CAPITAL LETTER ETA WITH TONOS +1FCB ; [.202A.0020.0008][.0000.0024.0002] # GREEK CAPITAL LETTER ETA WITH OXIA +1FC4 ; [.202A.0020.0002][.0000.0024.0002][.0000.004C.0002] # GREEK SMALL LETTER ETA WITH OXIA AND YPOGEGRAMMENI +1F74 ; [.202A.0020.0002][.0000.0025.0002] # GREEK SMALL LETTER ETA WITH VARIA +1FCA ; [.202A.0020.0008][.0000.0025.0002] # GREEK CAPITAL LETTER ETA WITH VARIA +1FC2 ; [.202A.0020.0002][.0000.0025.0002][.0000.004C.0002] # GREEK SMALL LETTER ETA WITH VARIA AND YPOGEGRAMMENI +1FC6 ; [.202A.0020.0002][.0000.002A.0002] # GREEK SMALL LETTER ETA WITH PERISPOMENI +1FC7 ; [.202A.0020.0002][.0000.002A.0002][.0000.004C.0002] # GREEK SMALL LETTER ETA WITH PERISPOMENI AND YPOGEGRAMMENI +1FC3 ; [.202A.0020.0002][.0000.004C.0002] # GREEK SMALL LETTER ETA WITH YPOGEGRAMMENI +1FCC ; [.202A.0020.0008][.0000.004C.0002] # GREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENI +03B8 ; [.202B.0020.0002] # GREEK SMALL LETTER THETA +03D1 ; [.202B.0020.0004] # GREEK THETA SYMBOL +1D6C9 ; [.202B.0020.0005] # MATHEMATICAL BOLD SMALL THETA +1D6DD ; [.202B.0020.0005] # MATHEMATICAL BOLD THETA SYMBOL +1D703 ; [.202B.0020.0005] # MATHEMATICAL ITALIC SMALL THETA +1D717 ; [.202B.0020.0005] # MATHEMATICAL ITALIC THETA SYMBOL +1D73D ; [.202B.0020.0005] # MATHEMATICAL BOLD ITALIC SMALL THETA +1D751 ; [.202B.0020.0005] # MATHEMATICAL BOLD ITALIC THETA SYMBOL +1D777 ; [.202B.0020.0005] # MATHEMATICAL SANS-SERIF BOLD SMALL THETA +1D78B ; [.202B.0020.0005] # MATHEMATICAL SANS-SERIF BOLD THETA SYMBOL +1D7B1 ; [.202B.0020.0005] # MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL THETA +1D7C5 ; [.202B.0020.0005] # MATHEMATICAL SANS-SERIF BOLD ITALIC THETA SYMBOL +0398 ; [.202B.0020.0008] # GREEK CAPITAL LETTER THETA +03F4 ; [.202B.0020.000A] # GREEK CAPITAL THETA SYMBOL +1D6AF ; [.202B.0020.000B] # MATHEMATICAL BOLD CAPITAL THETA +1D6B9 ; [.202B.0020.000B] # MATHEMATICAL BOLD CAPITAL THETA SYMBOL +1D6E9 ; [.202B.0020.000B] # MATHEMATICAL ITALIC CAPITAL THETA +1D6F3 ; [.202B.0020.000B] # MATHEMATICAL ITALIC CAPITAL THETA SYMBOL +1D723 ; [.202B.0020.000B] # MATHEMATICAL BOLD ITALIC CAPITAL THETA +1D72D ; [.202B.0020.000B] # MATHEMATICAL BOLD ITALIC CAPITAL THETA SYMBOL +1D75D ; [.202B.0020.000B] # MATHEMATICAL SANS-SERIF BOLD CAPITAL THETA +1D767 ; [.202B.0020.000B] # MATHEMATICAL SANS-SERIF BOLD CAPITAL THETA SYMBOL +1D797 ; [.202B.0020.000B] # MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL THETA +1D7A1 ; [.202B.0020.000B] # MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL THETA SYMBOL +1DBF ; [.202B.0020.0014] # MODIFIER LETTER SMALL THETA +03B9 ; [.202C.0020.0002] # GREEK SMALL LETTER IOTA +1FBE ; [.202C.0020.0002] # GREEK PROSGEGRAMMENI +037A ; [.202C.0020.0004] # GREEK YPOGEGRAMMENI +1D6CA ; [.202C.0020.0005] # MATHEMATICAL BOLD SMALL IOTA +1D704 ; [.202C.0020.0005] # MATHEMATICAL ITALIC SMALL IOTA +1D73E ; [.202C.0020.0005] # MATHEMATICAL BOLD ITALIC SMALL IOTA +1D778 ; [.202C.0020.0005] # MATHEMATICAL SANS-SERIF BOLD SMALL IOTA +1D7B2 ; [.202C.0020.0005] # MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL IOTA +0399 ; [.202C.0020.0008] # GREEK CAPITAL LETTER IOTA +1D6B0 ; [.202C.0020.000B] # MATHEMATICAL BOLD CAPITAL IOTA +1D6EA ; [.202C.0020.000B] # MATHEMATICAL ITALIC CAPITAL IOTA +1D724 ; [.202C.0020.000B] # MATHEMATICAL BOLD ITALIC CAPITAL IOTA +1D75E ; [.202C.0020.000B] # MATHEMATICAL SANS-SERIF BOLD CAPITAL IOTA +1D798 ; [.202C.0020.000B] # MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL IOTA +1F30 ; [.202C.0020.0002][.0000.0022.0002] # GREEK SMALL LETTER IOTA WITH PSILI +1F38 ; [.202C.0020.0008][.0000.0022.0002] # GREEK CAPITAL LETTER IOTA WITH PSILI +1F34 ; [.202C.0020.0002][.0000.0022.0002][.0000.0024.0002] # GREEK SMALL LETTER IOTA WITH PSILI AND OXIA +1F3C ; [.202C.0020.0008][.0000.0022.0002][.0000.0024.0002] # GREEK CAPITAL LETTER IOTA WITH PSILI AND OXIA +1F32 ; [.202C.0020.0002][.0000.0022.0002][.0000.0025.0002] # GREEK SMALL LETTER IOTA WITH PSILI AND VARIA +1F3A ; [.202C.0020.0008][.0000.0022.0002][.0000.0025.0002] # GREEK CAPITAL LETTER IOTA WITH PSILI AND VARIA +1F36 ; [.202C.0020.0002][.0000.0022.0002][.0000.002A.0002] # GREEK SMALL LETTER IOTA WITH PSILI AND PERISPOMENI +1F3E ; [.202C.0020.0008][.0000.0022.0002][.0000.002A.0002] # GREEK CAPITAL LETTER IOTA WITH PSILI AND PERISPOMENI +1F31 ; [.202C.0020.0002][.0000.0023.0002] # GREEK SMALL LETTER IOTA WITH DASIA +1F39 ; [.202C.0020.0008][.0000.0023.0002] # GREEK CAPITAL LETTER IOTA WITH DASIA +1F35 ; [.202C.0020.0002][.0000.0023.0002][.0000.0024.0002] # GREEK SMALL LETTER IOTA WITH DASIA AND OXIA +1F3D ; [.202C.0020.0008][.0000.0023.0002][.0000.0024.0002] # GREEK CAPITAL LETTER IOTA WITH DASIA AND OXIA +1F33 ; [.202C.0020.0002][.0000.0023.0002][.0000.0025.0002] # GREEK SMALL LETTER IOTA WITH DASIA AND VARIA +1F3B ; [.202C.0020.0008][.0000.0023.0002][.0000.0025.0002] # GREEK CAPITAL LETTER IOTA WITH DASIA AND VARIA +1F37 ; [.202C.0020.0002][.0000.0023.0002][.0000.002A.0002] # GREEK SMALL LETTER IOTA WITH DASIA AND PERISPOMENI +1F3F ; [.202C.0020.0008][.0000.0023.0002][.0000.002A.0002] # GREEK CAPITAL LETTER IOTA WITH DASIA AND PERISPOMENI +03AF ; [.202C.0020.0002][.0000.0024.0002] # GREEK SMALL LETTER IOTA WITH TONOS +1F77 ; [.202C.0020.0002][.0000.0024.0002] # GREEK SMALL LETTER IOTA WITH OXIA +038A ; [.202C.0020.0008][.0000.0024.0002] # GREEK CAPITAL LETTER IOTA WITH TONOS +1FDB ; [.202C.0020.0008][.0000.0024.0002] # GREEK CAPITAL LETTER IOTA WITH OXIA +1F76 ; [.202C.0020.0002][.0000.0025.0002] # GREEK SMALL LETTER IOTA WITH VARIA +1FDA ; [.202C.0020.0008][.0000.0025.0002] # GREEK CAPITAL LETTER IOTA WITH VARIA +1FD0 ; [.202C.0020.0002][.0000.0026.0002] # GREEK SMALL LETTER IOTA WITH VRACHY +1FD8 ; [.202C.0020.0008][.0000.0026.0002] # GREEK CAPITAL LETTER IOTA WITH VRACHY +1FD6 ; [.202C.0020.0002][.0000.002A.0002] # GREEK SMALL LETTER IOTA WITH PERISPOMENI +03CA ; [.202C.0020.0002][.0000.002B.0002] # GREEK SMALL LETTER IOTA WITH DIALYTIKA +03AA ; [.202C.0020.0008][.0000.002B.0002] # GREEK CAPITAL LETTER IOTA WITH DIALYTIKA +0390 ; [.202C.0020.0002][.0000.002B.0002][.0000.0024.0002] # GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS +1FD3 ; [.202C.0020.0002][.0000.002B.0002][.0000.0024.0002] # GREEK SMALL LETTER IOTA WITH DIALYTIKA AND OXIA +1FD2 ; [.202C.0020.0002][.0000.002B.0002][.0000.0025.0002] # GREEK SMALL LETTER IOTA WITH DIALYTIKA AND VARIA +1FD7 ; [.202C.0020.0002][.0000.002B.0002][.0000.002A.0002] # GREEK SMALL LETTER IOTA WITH DIALYTIKA AND PERISPOMENI +1FD1 ; [.202C.0020.0002][.0000.0032.0002] # GREEK SMALL LETTER IOTA WITH MACRON +1FD9 ; [.202C.0020.0008][.0000.0032.0002] # GREEK CAPITAL LETTER IOTA WITH MACRON +03F3 ; [.202D.0020.0002] # GREEK LETTER YOT +037F ; [.202D.0020.0008] # GREEK CAPITAL LETTER YOT +03BA ; [.202E.0020.0002] # GREEK SMALL LETTER KAPPA +03F0 ; [.202E.0020.0004] # GREEK KAPPA SYMBOL +1D6CB ; [.202E.0020.0005] # MATHEMATICAL BOLD SMALL KAPPA +1D6DE ; [.202E.0020.0005] # MATHEMATICAL BOLD KAPPA SYMBOL +1D705 ; [.202E.0020.0005] # MATHEMATICAL ITALIC SMALL KAPPA +1D718 ; [.202E.0020.0005] # MATHEMATICAL ITALIC KAPPA SYMBOL +1D73F ; [.202E.0020.0005] # MATHEMATICAL BOLD ITALIC SMALL KAPPA +1D752 ; [.202E.0020.0005] # MATHEMATICAL BOLD ITALIC KAPPA SYMBOL +1D779 ; [.202E.0020.0005] # MATHEMATICAL SANS-SERIF BOLD SMALL KAPPA +1D78C ; [.202E.0020.0005] # MATHEMATICAL SANS-SERIF BOLD KAPPA SYMBOL +1D7B3 ; [.202E.0020.0005] # MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL KAPPA +1D7C6 ; [.202E.0020.0005] # MATHEMATICAL SANS-SERIF BOLD ITALIC KAPPA SYMBOL +039A ; [.202E.0020.0008] # GREEK CAPITAL LETTER KAPPA +1D6B1 ; [.202E.0020.000B] # MATHEMATICAL BOLD CAPITAL KAPPA +1D6EB ; [.202E.0020.000B] # MATHEMATICAL ITALIC CAPITAL KAPPA +1D725 ; [.202E.0020.000B] # MATHEMATICAL BOLD ITALIC CAPITAL KAPPA +1D75F ; [.202E.0020.000B] # MATHEMATICAL SANS-SERIF BOLD CAPITAL KAPPA +1D799 ; [.202E.0020.000B] # MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL KAPPA +03D7 ; [.202E.0020.0004][.201F.0020.0004][.202C.0020.0004] # GREEK KAI SYMBOL +03CF ; [.202E.0020.000A][.201F.0020.0004][.202C.0020.0004] # GREEK CAPITAL KAI SYMBOL +03BB ; [.202F.0020.0002] # GREEK SMALL LETTER LAMDA +1D6CC ; [.202F.0020.0005] # MATHEMATICAL BOLD SMALL LAMDA +1D706 ; [.202F.0020.0005] # MATHEMATICAL ITALIC SMALL LAMDA +1D740 ; [.202F.0020.0005] # MATHEMATICAL BOLD ITALIC SMALL LAMDA +1D77A ; [.202F.0020.0005] # MATHEMATICAL SANS-SERIF BOLD SMALL LAMDA +1D7B4 ; [.202F.0020.0005] # MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL LAMDA +039B ; [.202F.0020.0008] # GREEK CAPITAL LETTER LAMDA +1D6B2 ; [.202F.0020.000B] # MATHEMATICAL BOLD CAPITAL LAMDA +1D6EC ; [.202F.0020.000B] # MATHEMATICAL ITALIC CAPITAL LAMDA +1D726 ; [.202F.0020.000B] # MATHEMATICAL BOLD ITALIC CAPITAL LAMDA +1D760 ; [.202F.0020.000B] # MATHEMATICAL SANS-SERIF BOLD CAPITAL LAMDA +1D79A ; [.202F.0020.000B] # MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL LAMDA +1D27 ; [.2030.0020.0002] # GREEK LETTER SMALL CAPITAL LAMDA +03BC ; [.2031.0020.0002] # GREEK SMALL LETTER MU +00B5 ; [.2031.0020.0004] # MICRO SIGN +1D6CD ; [.2031.0020.0005] # MATHEMATICAL BOLD SMALL MU +1D707 ; [.2031.0020.0005] # MATHEMATICAL ITALIC SMALL MU +1D741 ; [.2031.0020.0005] # MATHEMATICAL BOLD ITALIC SMALL MU +1D77B ; [.2031.0020.0005] # MATHEMATICAL SANS-SERIF BOLD SMALL MU +1D7B5 ; [.2031.0020.0005] # MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL MU +039C ; [.2031.0020.0008] # GREEK CAPITAL LETTER MU +1D6B3 ; [.2031.0020.000B] # MATHEMATICAL BOLD CAPITAL MU +1D6ED ; [.2031.0020.000B] # MATHEMATICAL ITALIC CAPITAL MU +1D727 ; [.2031.0020.000B] # MATHEMATICAL BOLD ITALIC CAPITAL MU +1D761 ; [.2031.0020.000B] # MATHEMATICAL SANS-SERIF BOLD CAPITAL MU +1D79B ; [.2031.0020.000B] # MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL MU +3382 ; [.2031.0020.001C][.1CAD.0020.001D] # SQUARE MU A +338C ; [.2031.0020.001C][.1D4B.0020.001D] # SQUARE MU F +338D ; [.2031.0020.001C][.1D5A.0020.001C] # SQUARE MU G +3395 ; [.2031.0020.001C][.1DDD.0020.001C] # SQUARE MU L +339B ; [.2031.0020.001C][.1E10.0020.001C] # SQUARE MU M +33B2 ; [.2031.0020.001C][.1ED7.0020.001C] # SQUARE MU S +33B6 ; [.2031.0020.001C][.1F49.0020.001D] # SQUARE MU V +33BC ; [.2031.0020.001C][.1F5B.0020.001D] # SQUARE MU W +03BD ; [.2032.0020.0002] # GREEK SMALL LETTER NU +1D6CE ; [.2032.0020.0005] # MATHEMATICAL BOLD SMALL NU +1D708 ; [.2032.0020.0005] # MATHEMATICAL ITALIC SMALL NU +1D742 ; [.2032.0020.0005] # MATHEMATICAL BOLD ITALIC SMALL NU +1D77C ; [.2032.0020.0005] # MATHEMATICAL SANS-SERIF BOLD SMALL NU +1D7B6 ; [.2032.0020.0005] # MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL NU +039D ; [.2032.0020.0008] # GREEK CAPITAL LETTER NU +1D6B4 ; [.2032.0020.000B] # MATHEMATICAL BOLD CAPITAL NU +1D6EE ; [.2032.0020.000B] # MATHEMATICAL ITALIC CAPITAL NU +1D728 ; [.2032.0020.000B] # MATHEMATICAL BOLD ITALIC CAPITAL NU +1D762 ; [.2032.0020.000B] # MATHEMATICAL SANS-SERIF BOLD CAPITAL NU +1D79C ; [.2032.0020.000B] # MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL NU +03BE ; [.2033.0020.0002] # GREEK SMALL LETTER XI +1D6CF ; [.2033.0020.0005] # MATHEMATICAL BOLD SMALL XI +1D709 ; [.2033.0020.0005] # MATHEMATICAL ITALIC SMALL XI +1D743 ; [.2033.0020.0005] # MATHEMATICAL BOLD ITALIC SMALL XI +1D77D ; [.2033.0020.0005] # MATHEMATICAL SANS-SERIF BOLD SMALL XI +1D7B7 ; [.2033.0020.0005] # MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL XI +039E ; [.2033.0020.0008] # GREEK CAPITAL LETTER XI +1D6B5 ; [.2033.0020.000B] # MATHEMATICAL BOLD CAPITAL XI +1D6EF ; [.2033.0020.000B] # MATHEMATICAL ITALIC CAPITAL XI +1D729 ; [.2033.0020.000B] # MATHEMATICAL BOLD ITALIC CAPITAL XI +1D763 ; [.2033.0020.000B] # MATHEMATICAL SANS-SERIF BOLD CAPITAL XI +1D79D ; [.2033.0020.000B] # MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL XI +03BF ; [.2034.0020.0002] # GREEK SMALL LETTER OMICRON +1D6D0 ; [.2034.0020.0005] # MATHEMATICAL BOLD SMALL OMICRON +1D70A ; [.2034.0020.0005] # MATHEMATICAL ITALIC SMALL OMICRON +1D744 ; [.2034.0020.0005] # MATHEMATICAL BOLD ITALIC SMALL OMICRON +1D77E ; [.2034.0020.0005] # MATHEMATICAL SANS-SERIF BOLD SMALL OMICRON +1D7B8 ; [.2034.0020.0005] # MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL OMICRON +039F ; [.2034.0020.0008] # GREEK CAPITAL LETTER OMICRON +1D6B6 ; [.2034.0020.000B] # MATHEMATICAL BOLD CAPITAL OMICRON +1D6F0 ; [.2034.0020.000B] # MATHEMATICAL ITALIC CAPITAL OMICRON +1D72A ; [.2034.0020.000B] # MATHEMATICAL BOLD ITALIC CAPITAL OMICRON +1D764 ; [.2034.0020.000B] # MATHEMATICAL SANS-SERIF BOLD CAPITAL OMICRON +1D79E ; [.2034.0020.000B] # MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL OMICRON +1F40 ; [.2034.0020.0002][.0000.0022.0002] # GREEK SMALL LETTER OMICRON WITH PSILI +1F48 ; [.2034.0020.0008][.0000.0022.0002] # GREEK CAPITAL LETTER OMICRON WITH PSILI +1F44 ; [.2034.0020.0002][.0000.0022.0002][.0000.0024.0002] # GREEK SMALL LETTER OMICRON WITH PSILI AND OXIA +1F4C ; [.2034.0020.0008][.0000.0022.0002][.0000.0024.0002] # GREEK CAPITAL LETTER OMICRON WITH PSILI AND OXIA +1F42 ; [.2034.0020.0002][.0000.0022.0002][.0000.0025.0002] # GREEK SMALL LETTER OMICRON WITH PSILI AND VARIA +1F4A ; [.2034.0020.0008][.0000.0022.0002][.0000.0025.0002] # GREEK CAPITAL LETTER OMICRON WITH PSILI AND VARIA +1F41 ; [.2034.0020.0002][.0000.0023.0002] # GREEK SMALL LETTER OMICRON WITH DASIA +1F49 ; [.2034.0020.0008][.0000.0023.0002] # GREEK CAPITAL LETTER OMICRON WITH DASIA +1F45 ; [.2034.0020.0002][.0000.0023.0002][.0000.0024.0002] # GREEK SMALL LETTER OMICRON WITH DASIA AND OXIA +1F4D ; [.2034.0020.0008][.0000.0023.0002][.0000.0024.0002] # GREEK CAPITAL LETTER OMICRON WITH DASIA AND OXIA +1F43 ; [.2034.0020.0002][.0000.0023.0002][.0000.0025.0002] # GREEK SMALL LETTER OMICRON WITH DASIA AND VARIA +1F4B ; [.2034.0020.0008][.0000.0023.0002][.0000.0025.0002] # GREEK CAPITAL LETTER OMICRON WITH DASIA AND VARIA +03CC ; [.2034.0020.0002][.0000.0024.0002] # GREEK SMALL LETTER OMICRON WITH TONOS +1F79 ; [.2034.0020.0002][.0000.0024.0002] # GREEK SMALL LETTER OMICRON WITH OXIA +038C ; [.2034.0020.0008][.0000.0024.0002] # GREEK CAPITAL LETTER OMICRON WITH TONOS +1FF9 ; [.2034.0020.0008][.0000.0024.0002] # GREEK CAPITAL LETTER OMICRON WITH OXIA +1F78 ; [.2034.0020.0002][.0000.0025.0002] # GREEK SMALL LETTER OMICRON WITH VARIA +1FF8 ; [.2034.0020.0008][.0000.0025.0002] # GREEK CAPITAL LETTER OMICRON WITH VARIA +03C0 ; [.2035.0020.0002] # GREEK SMALL LETTER PI +03D6 ; [.2035.0020.0004] # GREEK PI SYMBOL +213C ; [.2035.0020.0005] # DOUBLE-STRUCK SMALL PI +1D6D1 ; [.2035.0020.0005] # MATHEMATICAL BOLD SMALL PI +1D6E1 ; [.2035.0020.0005] # MATHEMATICAL BOLD PI SYMBOL +1D70B ; [.2035.0020.0005] # MATHEMATICAL ITALIC SMALL PI +1D71B ; [.2035.0020.0005] # MATHEMATICAL ITALIC PI SYMBOL +1D745 ; [.2035.0020.0005] # MATHEMATICAL BOLD ITALIC SMALL PI +1D755 ; [.2035.0020.0005] # MATHEMATICAL BOLD ITALIC PI SYMBOL +1D77F ; [.2035.0020.0005] # MATHEMATICAL SANS-SERIF BOLD SMALL PI +1D78F ; [.2035.0020.0005] # MATHEMATICAL SANS-SERIF BOLD PI SYMBOL +1D7B9 ; [.2035.0020.0005] # MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL PI +1D7C9 ; [.2035.0020.0005] # MATHEMATICAL SANS-SERIF BOLD ITALIC PI SYMBOL +03A0 ; [.2035.0020.0008] # GREEK CAPITAL LETTER PI +213F ; [.2035.0020.000B] # DOUBLE-STRUCK CAPITAL PI +1D6B7 ; [.2035.0020.000B] # MATHEMATICAL BOLD CAPITAL PI +1D6F1 ; [.2035.0020.000B] # MATHEMATICAL ITALIC CAPITAL PI +1D72B ; [.2035.0020.000B] # MATHEMATICAL BOLD ITALIC CAPITAL PI +1D765 ; [.2035.0020.000B] # MATHEMATICAL SANS-SERIF BOLD CAPITAL PI +1D79F ; [.2035.0020.000B] # MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL PI +1D28 ; [.2036.0020.0002] # GREEK LETTER SMALL CAPITAL PI +03FB ; [.2037.0020.0002] # GREEK SMALL LETTER SAN +03FA ; [.2037.0020.0008] # GREEK CAPITAL LETTER SAN +03DF ; [.2038.0020.0002] # GREEK SMALL LETTER KOPPA +03DE ; [.2038.0020.0008] # GREEK LETTER KOPPA +03D9 ; [.2039.0020.0002] # GREEK SMALL LETTER ARCHAIC KOPPA +03D8 ; [.2039.0020.0008] # GREEK LETTER ARCHAIC KOPPA +03C1 ; [.203A.0020.0002] # GREEK SMALL LETTER RHO +03F1 ; [.203A.0020.0004] # GREEK RHO SYMBOL +1D6D2 ; [.203A.0020.0005] # MATHEMATICAL BOLD SMALL RHO +1D6E0 ; [.203A.0020.0005] # MATHEMATICAL BOLD RHO SYMBOL +1D70C ; [.203A.0020.0005] # MATHEMATICAL ITALIC SMALL RHO +1D71A ; [.203A.0020.0005] # MATHEMATICAL ITALIC RHO SYMBOL +1D746 ; [.203A.0020.0005] # MATHEMATICAL BOLD ITALIC SMALL RHO +1D754 ; [.203A.0020.0005] # MATHEMATICAL BOLD ITALIC RHO SYMBOL +1D780 ; [.203A.0020.0005] # MATHEMATICAL SANS-SERIF BOLD SMALL RHO +1D78E ; [.203A.0020.0005] # MATHEMATICAL SANS-SERIF BOLD RHO SYMBOL +1D7BA ; [.203A.0020.0005] # MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL RHO +1D7C8 ; [.203A.0020.0005] # MATHEMATICAL SANS-SERIF BOLD ITALIC RHO SYMBOL +03A1 ; [.203A.0020.0008] # GREEK CAPITAL LETTER RHO +1D6B8 ; [.203A.0020.000B] # MATHEMATICAL BOLD CAPITAL RHO +1D6F2 ; [.203A.0020.000B] # MATHEMATICAL ITALIC CAPITAL RHO +1D72C ; [.203A.0020.000B] # MATHEMATICAL BOLD ITALIC CAPITAL RHO +1D766 ; [.203A.0020.000B] # MATHEMATICAL SANS-SERIF BOLD CAPITAL RHO +1D7A0 ; [.203A.0020.000B] # MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL RHO +1D68 ; [.203A.0020.0015] # GREEK SUBSCRIPT SMALL LETTER RHO +1FE4 ; [.203A.0020.0002][.0000.0022.0002] # GREEK SMALL LETTER RHO WITH PSILI +1FE5 ; [.203A.0020.0002][.0000.0023.0002] # GREEK SMALL LETTER RHO WITH DASIA +1FEC ; [.203A.0020.0008][.0000.0023.0002] # GREEK CAPITAL LETTER RHO WITH DASIA +1D29 ; [.203B.0020.0002] # GREEK LETTER SMALL CAPITAL RHO +03FC ; [.203C.0020.0002] # GREEK RHO WITH STROKE SYMBOL +03C3 ; [.203D.0020.0002] # GREEK SMALL LETTER SIGMA +03F2 ; [.203D.0020.0004] # GREEK LUNATE SIGMA SYMBOL +1D6D3 ; [.203D.0020.0005] # MATHEMATICAL BOLD SMALL FINAL SIGMA +1D6D4 ; [.203D.0020.0005] # MATHEMATICAL BOLD SMALL SIGMA +1D70D ; [.203D.0020.0005] # MATHEMATICAL ITALIC SMALL FINAL SIGMA +1D70E ; [.203D.0020.0005] # MATHEMATICAL ITALIC SMALL SIGMA +1D747 ; [.203D.0020.0005] # MATHEMATICAL BOLD ITALIC SMALL FINAL SIGMA +1D748 ; [.203D.0020.0005] # MATHEMATICAL BOLD ITALIC SMALL SIGMA +1D781 ; [.203D.0020.0005] # MATHEMATICAL SANS-SERIF BOLD SMALL FINAL SIGMA +1D782 ; [.203D.0020.0005] # MATHEMATICAL SANS-SERIF BOLD SMALL SIGMA +1D7BB ; [.203D.0020.0005] # MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL FINAL SIGMA +1D7BC ; [.203D.0020.0005] # MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL SIGMA +03A3 ; [.203D.0020.0008] # GREEK CAPITAL LETTER SIGMA +03F9 ; [.203D.0020.000A] # GREEK CAPITAL LUNATE SIGMA SYMBOL +1D6BA ; [.203D.0020.000B] # MATHEMATICAL BOLD CAPITAL SIGMA +1D6F4 ; [.203D.0020.000B] # MATHEMATICAL ITALIC CAPITAL SIGMA +1D72E ; [.203D.0020.000B] # MATHEMATICAL BOLD ITALIC CAPITAL SIGMA +1D768 ; [.203D.0020.000B] # MATHEMATICAL SANS-SERIF BOLD CAPITAL SIGMA +1D7A2 ; [.203D.0020.000B] # MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL SIGMA +03C2 ; [.203D.0020.0019] # GREEK SMALL LETTER FINAL SIGMA +037C ; [.203E.0020.0002] # GREEK SMALL DOTTED LUNATE SIGMA SYMBOL +03FE ; [.203E.0020.0008] # GREEK CAPITAL DOTTED LUNATE SIGMA SYMBOL +037B ; [.203F.0020.0002] # GREEK SMALL REVERSED LUNATE SIGMA SYMBOL +03FD ; [.203F.0020.0008] # GREEK CAPITAL REVERSED LUNATE SIGMA SYMBOL +037D ; [.2040.0020.0002] # GREEK SMALL REVERSED DOTTED LUNATE SIGMA SYMBOL +03FF ; [.2040.0020.0008] # GREEK CAPITAL REVERSED DOTTED LUNATE SIGMA SYMBOL +03C4 ; [.2041.0020.0002] # GREEK SMALL LETTER TAU +1D6D5 ; [.2041.0020.0005] # MATHEMATICAL BOLD SMALL TAU +1D70F ; [.2041.0020.0005] # MATHEMATICAL ITALIC SMALL TAU +1D749 ; [.2041.0020.0005] # MATHEMATICAL BOLD ITALIC SMALL TAU +1D783 ; [.2041.0020.0005] # MATHEMATICAL SANS-SERIF BOLD SMALL TAU +1D7BD ; [.2041.0020.0005] # MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL TAU +03A4 ; [.2041.0020.0008] # GREEK CAPITAL LETTER TAU +1D6BB ; [.2041.0020.000B] # MATHEMATICAL BOLD CAPITAL TAU +1D6F5 ; [.2041.0020.000B] # MATHEMATICAL ITALIC CAPITAL TAU +1D72F ; [.2041.0020.000B] # MATHEMATICAL BOLD ITALIC CAPITAL TAU +1D769 ; [.2041.0020.000B] # MATHEMATICAL SANS-SERIF BOLD CAPITAL TAU +1D7A3 ; [.2041.0020.000B] # MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL TAU +03C5 ; [.2042.0020.0002] # GREEK SMALL LETTER UPSILON +1D6D6 ; [.2042.0020.0005] # MATHEMATICAL BOLD SMALL UPSILON +1D710 ; [.2042.0020.0005] # MATHEMATICAL ITALIC SMALL UPSILON +1D74A ; [.2042.0020.0005] # MATHEMATICAL BOLD ITALIC SMALL UPSILON +1D784 ; [.2042.0020.0005] # MATHEMATICAL SANS-SERIF BOLD SMALL UPSILON +1D7BE ; [.2042.0020.0005] # MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL UPSILON +03A5 ; [.2042.0020.0008] # GREEK CAPITAL LETTER UPSILON +03D2 ; [.2042.0020.000A] # GREEK UPSILON WITH HOOK SYMBOL +1D6BC ; [.2042.0020.000B] # MATHEMATICAL BOLD CAPITAL UPSILON +1D6F6 ; [.2042.0020.000B] # MATHEMATICAL ITALIC CAPITAL UPSILON +1D730 ; [.2042.0020.000B] # MATHEMATICAL BOLD ITALIC CAPITAL UPSILON +1D76A ; [.2042.0020.000B] # MATHEMATICAL SANS-SERIF BOLD CAPITAL UPSILON +1D7A4 ; [.2042.0020.000B] # MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL UPSILON +1F50 ; [.2042.0020.0002][.0000.0022.0002] # GREEK SMALL LETTER UPSILON WITH PSILI +1F54 ; [.2042.0020.0002][.0000.0022.0002][.0000.0024.0002] # GREEK SMALL LETTER UPSILON WITH PSILI AND OXIA +1F52 ; [.2042.0020.0002][.0000.0022.0002][.0000.0025.0002] # GREEK SMALL LETTER UPSILON WITH PSILI AND VARIA +1F56 ; [.2042.0020.0002][.0000.0022.0002][.0000.002A.0002] # GREEK SMALL LETTER UPSILON WITH PSILI AND PERISPOMENI +1F51 ; [.2042.0020.0002][.0000.0023.0002] # GREEK SMALL LETTER UPSILON WITH DASIA +1F59 ; [.2042.0020.0008][.0000.0023.0002] # GREEK CAPITAL LETTER UPSILON WITH DASIA +1F55 ; [.2042.0020.0002][.0000.0023.0002][.0000.0024.0002] # GREEK SMALL LETTER UPSILON WITH DASIA AND OXIA +1F5D ; [.2042.0020.0008][.0000.0023.0002][.0000.0024.0002] # GREEK CAPITAL LETTER UPSILON WITH DASIA AND OXIA +1F53 ; [.2042.0020.0002][.0000.0023.0002][.0000.0025.0002] # GREEK SMALL LETTER UPSILON WITH DASIA AND VARIA +1F5B ; [.2042.0020.0008][.0000.0023.0002][.0000.0025.0002] # GREEK CAPITAL LETTER UPSILON WITH DASIA AND VARIA +1F57 ; [.2042.0020.0002][.0000.0023.0002][.0000.002A.0002] # GREEK SMALL LETTER UPSILON WITH DASIA AND PERISPOMENI +1F5F ; [.2042.0020.0008][.0000.0023.0002][.0000.002A.0002] # GREEK CAPITAL LETTER UPSILON WITH DASIA AND PERISPOMENI +03CD ; [.2042.0020.0002][.0000.0024.0002] # GREEK SMALL LETTER UPSILON WITH TONOS +1F7B ; [.2042.0020.0002][.0000.0024.0002] # GREEK SMALL LETTER UPSILON WITH OXIA +038E ; [.2042.0020.0008][.0000.0024.0002] # GREEK CAPITAL LETTER UPSILON WITH TONOS +1FEB ; [.2042.0020.0008][.0000.0024.0002] # GREEK CAPITAL LETTER UPSILON WITH OXIA +03D3 ; [.2042.0020.000A][.0000.0024.0002] # GREEK UPSILON WITH ACUTE AND HOOK SYMBOL +1F7A ; [.2042.0020.0002][.0000.0025.0002] # GREEK SMALL LETTER UPSILON WITH VARIA +1FEA ; [.2042.0020.0008][.0000.0025.0002] # GREEK CAPITAL LETTER UPSILON WITH VARIA +1FE0 ; [.2042.0020.0002][.0000.0026.0002] # GREEK SMALL LETTER UPSILON WITH VRACHY +1FE8 ; [.2042.0020.0008][.0000.0026.0002] # GREEK CAPITAL LETTER UPSILON WITH VRACHY +1FE6 ; [.2042.0020.0002][.0000.002A.0002] # GREEK SMALL LETTER UPSILON WITH PERISPOMENI +03CB ; [.2042.0020.0002][.0000.002B.0002] # GREEK SMALL LETTER UPSILON WITH DIALYTIKA +03AB ; [.2042.0020.0008][.0000.002B.0002] # GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA +03D4 ; [.2042.0020.000A][.0000.002B.0002] # GREEK UPSILON WITH DIAERESIS AND HOOK SYMBOL +03B0 ; [.2042.0020.0002][.0000.002B.0002][.0000.0024.0002] # GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS +1FE3 ; [.2042.0020.0002][.0000.002B.0002][.0000.0024.0002] # GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND OXIA +1FE2 ; [.2042.0020.0002][.0000.002B.0002][.0000.0025.0002] # GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND VARIA +1FE7 ; [.2042.0020.0002][.0000.002B.0002][.0000.002A.0002] # GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND PERISPOMENI +1FE1 ; [.2042.0020.0002][.0000.0032.0002] # GREEK SMALL LETTER UPSILON WITH MACRON +1FE9 ; [.2042.0020.0008][.0000.0032.0002] # GREEK CAPITAL LETTER UPSILON WITH MACRON +03C6 ; [.2043.0020.0002] # GREEK SMALL LETTER PHI +03D5 ; [.2043.0020.0004] # GREEK PHI SYMBOL +1D6D7 ; [.2043.0020.0005] # MATHEMATICAL BOLD SMALL PHI +1D6DF ; [.2043.0020.0005] # MATHEMATICAL BOLD PHI SYMBOL +1D711 ; [.2043.0020.0005] # MATHEMATICAL ITALIC SMALL PHI +1D719 ; [.2043.0020.0005] # MATHEMATICAL ITALIC PHI SYMBOL +1D74B ; [.2043.0020.0005] # MATHEMATICAL BOLD ITALIC SMALL PHI +1D753 ; [.2043.0020.0005] # MATHEMATICAL BOLD ITALIC PHI SYMBOL +1D785 ; [.2043.0020.0005] # MATHEMATICAL SANS-SERIF BOLD SMALL PHI +1D78D ; [.2043.0020.0005] # MATHEMATICAL SANS-SERIF BOLD PHI SYMBOL +1D7BF ; [.2043.0020.0005] # MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL PHI +1D7C7 ; [.2043.0020.0005] # MATHEMATICAL SANS-SERIF BOLD ITALIC PHI SYMBOL +03A6 ; [.2043.0020.0008] # GREEK CAPITAL LETTER PHI +1D6BD ; [.2043.0020.000B] # MATHEMATICAL BOLD CAPITAL PHI +1D6F7 ; [.2043.0020.000B] # MATHEMATICAL ITALIC CAPITAL PHI +1D731 ; [.2043.0020.000B] # MATHEMATICAL BOLD ITALIC CAPITAL PHI +1D76B ; [.2043.0020.000B] # MATHEMATICAL SANS-SERIF BOLD CAPITAL PHI +1D7A5 ; [.2043.0020.000B] # MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL PHI +1D60 ; [.2043.0020.0014] # MODIFIER LETTER SMALL GREEK PHI +1D69 ; [.2043.0020.0015] # GREEK SUBSCRIPT SMALL LETTER PHI +03C7 ; [.2044.0020.0002] # GREEK SMALL LETTER CHI +1D6D8 ; [.2044.0020.0005] # MATHEMATICAL BOLD SMALL CHI +1D712 ; [.2044.0020.0005] # MATHEMATICAL ITALIC SMALL CHI +1D74C ; [.2044.0020.0005] # MATHEMATICAL BOLD ITALIC SMALL CHI +1D786 ; [.2044.0020.0005] # MATHEMATICAL SANS-SERIF BOLD SMALL CHI +1D7C0 ; [.2044.0020.0005] # MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL CHI +03A7 ; [.2044.0020.0008] # GREEK CAPITAL LETTER CHI +1D6BE ; [.2044.0020.000B] # MATHEMATICAL BOLD CAPITAL CHI +1D6F8 ; [.2044.0020.000B] # MATHEMATICAL ITALIC CAPITAL CHI +1D732 ; [.2044.0020.000B] # MATHEMATICAL BOLD ITALIC CAPITAL CHI +1D76C ; [.2044.0020.000B] # MATHEMATICAL SANS-SERIF BOLD CAPITAL CHI +1D7A6 ; [.2044.0020.000B] # MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL CHI +1D61 ; [.2044.0020.0014] # MODIFIER LETTER SMALL CHI +1D6A ; [.2044.0020.0015] # GREEK SUBSCRIPT SMALL LETTER CHI +03C8 ; [.2045.0020.0002] # GREEK SMALL LETTER PSI +1D6D9 ; [.2045.0020.0005] # MATHEMATICAL BOLD SMALL PSI +1D713 ; [.2045.0020.0005] # MATHEMATICAL ITALIC SMALL PSI +1D74D ; [.2045.0020.0005] # MATHEMATICAL BOLD ITALIC SMALL PSI +1D787 ; [.2045.0020.0005] # MATHEMATICAL SANS-SERIF BOLD SMALL PSI +1D7C1 ; [.2045.0020.0005] # MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL PSI +03A8 ; [.2045.0020.0008] # GREEK CAPITAL LETTER PSI +1D6BF ; [.2045.0020.000B] # MATHEMATICAL BOLD CAPITAL PSI +1D6F9 ; [.2045.0020.000B] # MATHEMATICAL ITALIC CAPITAL PSI +1D733 ; [.2045.0020.000B] # MATHEMATICAL BOLD ITALIC CAPITAL PSI +1D76D ; [.2045.0020.000B] # MATHEMATICAL SANS-SERIF BOLD CAPITAL PSI +1D7A7 ; [.2045.0020.000B] # MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL PSI +1D2A ; [.2046.0020.0002] # GREEK LETTER SMALL CAPITAL PSI +03C9 ; [.2047.0020.0002] # GREEK SMALL LETTER OMEGA +1D6DA ; [.2047.0020.0005] # MATHEMATICAL BOLD SMALL OMEGA +1D714 ; [.2047.0020.0005] # MATHEMATICAL ITALIC SMALL OMEGA +1D74E ; [.2047.0020.0005] # MATHEMATICAL BOLD ITALIC SMALL OMEGA +1D788 ; [.2047.0020.0005] # MATHEMATICAL SANS-SERIF BOLD SMALL OMEGA +1D7C2 ; [.2047.0020.0005] # MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL OMEGA +03A9 ; [.2047.0020.0008] # GREEK CAPITAL LETTER OMEGA +2126 ; [.2047.0020.0008] # OHM SIGN +1D6C0 ; [.2047.0020.000B] # MATHEMATICAL BOLD CAPITAL OMEGA +1D6FA ; [.2047.0020.000B] # MATHEMATICAL ITALIC CAPITAL OMEGA +1D734 ; [.2047.0020.000B] # MATHEMATICAL BOLD ITALIC CAPITAL OMEGA +1D76E ; [.2047.0020.000B] # MATHEMATICAL SANS-SERIF BOLD CAPITAL OMEGA +1D7A8 ; [.2047.0020.000B] # MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL OMEGA +1F60 ; [.2047.0020.0002][.0000.0022.0002] # GREEK SMALL LETTER OMEGA WITH PSILI +1F68 ; [.2047.0020.0008][.0000.0022.0002] # GREEK CAPITAL LETTER OMEGA WITH PSILI +1F64 ; [.2047.0020.0002][.0000.0022.0002][.0000.0024.0002] # GREEK SMALL LETTER OMEGA WITH PSILI AND OXIA +1F6C ; [.2047.0020.0008][.0000.0022.0002][.0000.0024.0002] # GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA +1FA4 ; [.2047.0020.0002][.0000.0022.0002][.0000.0024.0002][.0000.004C.0002] # GREEK SMALL LETTER OMEGA WITH PSILI AND OXIA AND YPOGEGRAMMENI +1FAC ; [.2047.0020.0008][.0000.0022.0002][.0000.0024.0002][.0000.004C.0002] # GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA AND PROSGEGRAMMENI +1F62 ; [.2047.0020.0002][.0000.0022.0002][.0000.0025.0002] # GREEK SMALL LETTER OMEGA WITH PSILI AND VARIA +1F6A ; [.2047.0020.0008][.0000.0022.0002][.0000.0025.0002] # GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA +1FA2 ; [.2047.0020.0002][.0000.0022.0002][.0000.0025.0002][.0000.004C.0002] # GREEK SMALL LETTER OMEGA WITH PSILI AND VARIA AND YPOGEGRAMMENI +1FAA ; [.2047.0020.0008][.0000.0022.0002][.0000.0025.0002][.0000.004C.0002] # GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA AND PROSGEGRAMMENI +1F66 ; [.2047.0020.0002][.0000.0022.0002][.0000.002A.0002] # GREEK SMALL LETTER OMEGA WITH PSILI AND PERISPOMENI +1F6E ; [.2047.0020.0008][.0000.0022.0002][.0000.002A.0002] # GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI +1FA6 ; [.2047.0020.0002][.0000.0022.0002][.0000.002A.0002][.0000.004C.0002] # GREEK SMALL LETTER OMEGA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI +1FAE ; [.2047.0020.0008][.0000.0022.0002][.0000.002A.0002][.0000.004C.0002] # GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI +1FA0 ; [.2047.0020.0002][.0000.0022.0002][.0000.004C.0002] # GREEK SMALL LETTER OMEGA WITH PSILI AND YPOGEGRAMMENI +1FA8 ; [.2047.0020.0008][.0000.0022.0002][.0000.004C.0002] # GREEK CAPITAL LETTER OMEGA WITH PSILI AND PROSGEGRAMMENI +1F61 ; [.2047.0020.0002][.0000.0023.0002] # GREEK SMALL LETTER OMEGA WITH DASIA +1F69 ; [.2047.0020.0008][.0000.0023.0002] # GREEK CAPITAL LETTER OMEGA WITH DASIA +1F65 ; [.2047.0020.0002][.0000.0023.0002][.0000.0024.0002] # GREEK SMALL LETTER OMEGA WITH DASIA AND OXIA +1F6D ; [.2047.0020.0008][.0000.0023.0002][.0000.0024.0002] # GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA +1FA5 ; [.2047.0020.0002][.0000.0023.0002][.0000.0024.0002][.0000.004C.0002] # GREEK SMALL LETTER OMEGA WITH DASIA AND OXIA AND YPOGEGRAMMENI +1FAD ; [.2047.0020.0008][.0000.0023.0002][.0000.0024.0002][.0000.004C.0002] # GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA AND PROSGEGRAMMENI +1F63 ; [.2047.0020.0002][.0000.0023.0002][.0000.0025.0002] # GREEK SMALL LETTER OMEGA WITH DASIA AND VARIA +1F6B ; [.2047.0020.0008][.0000.0023.0002][.0000.0025.0002] # GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA +1FA3 ; [.2047.0020.0002][.0000.0023.0002][.0000.0025.0002][.0000.004C.0002] # GREEK SMALL LETTER OMEGA WITH DASIA AND VARIA AND YPOGEGRAMMENI +1FAB ; [.2047.0020.0008][.0000.0023.0002][.0000.0025.0002][.0000.004C.0002] # GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA AND PROSGEGRAMMENI +1F67 ; [.2047.0020.0002][.0000.0023.0002][.0000.002A.0002] # GREEK SMALL LETTER OMEGA WITH DASIA AND PERISPOMENI +1F6F ; [.2047.0020.0008][.0000.0023.0002][.0000.002A.0002] # GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI +1FA7 ; [.2047.0020.0002][.0000.0023.0002][.0000.002A.0002][.0000.004C.0002] # GREEK SMALL LETTER OMEGA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI +1FAF ; [.2047.0020.0008][.0000.0023.0002][.0000.002A.0002][.0000.004C.0002] # GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI +1FA1 ; [.2047.0020.0002][.0000.0023.0002][.0000.004C.0002] # GREEK SMALL LETTER OMEGA WITH DASIA AND YPOGEGRAMMENI +1FA9 ; [.2047.0020.0008][.0000.0023.0002][.0000.004C.0002] # GREEK CAPITAL LETTER OMEGA WITH DASIA AND PROSGEGRAMMENI +03CE ; [.2047.0020.0002][.0000.0024.0002] # GREEK SMALL LETTER OMEGA WITH TONOS +1F7D ; [.2047.0020.0002][.0000.0024.0002] # GREEK SMALL LETTER OMEGA WITH OXIA +038F ; [.2047.0020.0008][.0000.0024.0002] # GREEK CAPITAL LETTER OMEGA WITH TONOS +1FFB ; [.2047.0020.0008][.0000.0024.0002] # GREEK CAPITAL LETTER OMEGA WITH OXIA +1FF4 ; [.2047.0020.0002][.0000.0024.0002][.0000.004C.0002] # GREEK SMALL LETTER OMEGA WITH OXIA AND YPOGEGRAMMENI +1F7C ; [.2047.0020.0002][.0000.0025.0002] # GREEK SMALL LETTER OMEGA WITH VARIA +1FFA ; [.2047.0020.0008][.0000.0025.0002] # GREEK CAPITAL LETTER OMEGA WITH VARIA +1FF2 ; [.2047.0020.0002][.0000.0025.0002][.0000.004C.0002] # GREEK SMALL LETTER OMEGA WITH VARIA AND YPOGEGRAMMENI +1FF6 ; [.2047.0020.0002][.0000.002A.0002] # GREEK SMALL LETTER OMEGA WITH PERISPOMENI +1FF7 ; [.2047.0020.0002][.0000.002A.0002][.0000.004C.0002] # GREEK SMALL LETTER OMEGA WITH PERISPOMENI AND YPOGEGRAMMENI +1FF3 ; [.2047.0020.0002][.0000.004C.0002] # GREEK SMALL LETTER OMEGA WITH YPOGEGRAMMENI +1FFC ; [.2047.0020.0008][.0000.004C.0002] # GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI +AB65 ; [.2048.0020.0002] # GREEK LETTER SMALL CAPITAL OMEGA +03E1 ; [.2049.0020.0002] # GREEK SMALL LETTER SAMPI +03E0 ; [.2049.0020.0008] # GREEK LETTER SAMPI +0373 ; [.204A.0020.0002] # GREEK SMALL LETTER ARCHAIC SAMPI +0372 ; [.204A.0020.0008] # GREEK CAPITAL LETTER ARCHAIC SAMPI +03F8 ; [.204B.0020.0002] # GREEK SMALL LETTER SHO +03F7 ; [.204B.0020.0008] # GREEK CAPITAL LETTER SHO +2C81 ; [.204C.0020.0002] # COPTIC SMALL LETTER ALFA +2C80 ; [.204C.0020.0008] # COPTIC CAPITAL LETTER ALFA +2C83 ; [.204D.0020.0002] # COPTIC SMALL LETTER VIDA +2C82 ; [.204D.0020.0008] # COPTIC CAPITAL LETTER VIDA +2C85 ; [.204E.0020.0002] # COPTIC SMALL LETTER GAMMA +2C84 ; [.204E.0020.0008] # COPTIC CAPITAL LETTER GAMMA +2C87 ; [.204F.0020.0002] # COPTIC SMALL LETTER DALDA +2C86 ; [.204F.0020.0008] # COPTIC CAPITAL LETTER DALDA +2C89 ; [.2050.0020.0002] # COPTIC SMALL LETTER EIE +2C88 ; [.2050.0020.0008] # COPTIC CAPITAL LETTER EIE +2CB7 ; [.2051.0020.0002] # COPTIC SMALL LETTER CRYPTOGRAMMIC EIE +2CB6 ; [.2051.0020.0008] # COPTIC CAPITAL LETTER CRYPTOGRAMMIC EIE +2C8B ; [.2052.0020.0002] # COPTIC SMALL LETTER SOU +2C8A ; [.2052.0020.0008] # COPTIC CAPITAL LETTER SOU +2C8D ; [.2053.0020.0002] # COPTIC SMALL LETTER ZATA +2C8C ; [.2053.0020.0008] # COPTIC CAPITAL LETTER ZATA +2C8F ; [.2054.0020.0002] # COPTIC SMALL LETTER HATE +2C8E ; [.2054.0020.0008] # COPTIC CAPITAL LETTER HATE +2C91 ; [.2055.0020.0002] # COPTIC SMALL LETTER THETHE +2C90 ; [.2055.0020.0008] # COPTIC CAPITAL LETTER THETHE +2C93 ; [.2056.0020.0002] # COPTIC SMALL LETTER IAUDA +2C92 ; [.2056.0020.0008] # COPTIC CAPITAL LETTER IAUDA +2C95 ; [.2057.0020.0002] # COPTIC SMALL LETTER KAPA +2C94 ; [.2057.0020.0008] # COPTIC CAPITAL LETTER KAPA +2CE4 ; [.2057.0020.0004][.204C.0020.0004][.2056.0020.0004] # COPTIC SYMBOL KAI +2CB9 ; [.2058.0020.0002] # COPTIC SMALL LETTER DIALECT-P KAPA +2CB8 ; [.2058.0020.0008] # COPTIC CAPITAL LETTER DIALECT-P KAPA +2C97 ; [.2059.0020.0002] # COPTIC SMALL LETTER LAULA +2C96 ; [.2059.0020.0008] # COPTIC CAPITAL LETTER LAULA +2C99 ; [.205A.0020.0002] # COPTIC SMALL LETTER MI +2C98 ; [.205A.0020.0008] # COPTIC CAPITAL LETTER MI +2C9B ; [.205B.0020.0002] # COPTIC SMALL LETTER NI +2C9A ; [.205B.0020.0008] # COPTIC CAPITAL LETTER NI +2CBB ; [.205C.0020.0002] # COPTIC SMALL LETTER DIALECT-P NI +2CBA ; [.205C.0020.0008] # COPTIC CAPITAL LETTER DIALECT-P NI +2CBD ; [.205D.0020.0002] # COPTIC SMALL LETTER CRYPTOGRAMMIC NI +2CBC ; [.205D.0020.0008] # COPTIC CAPITAL LETTER CRYPTOGRAMMIC NI +2C9D ; [.205E.0020.0002] # COPTIC SMALL LETTER KSI +2C9C ; [.205E.0020.0008] # COPTIC CAPITAL LETTER KSI +2C9F ; [.205F.0020.0002] # COPTIC SMALL LETTER O +2C9E ; [.205F.0020.0008] # COPTIC CAPITAL LETTER O +2CA1 ; [.2060.0020.0002] # COPTIC SMALL LETTER PI +2CA0 ; [.2060.0020.0008] # COPTIC CAPITAL LETTER PI +2CA3 ; [.2061.0020.0002] # COPTIC SMALL LETTER RO +2CA2 ; [.2061.0020.0008] # COPTIC CAPITAL LETTER RO +2CA5 ; [.2062.0020.0002] # COPTIC SMALL LETTER SIMA +2CA4 ; [.2062.0020.0008] # COPTIC CAPITAL LETTER SIMA +2CA7 ; [.2063.0020.0002] # COPTIC SMALL LETTER TAU +2CA6 ; [.2063.0020.0008] # COPTIC CAPITAL LETTER TAU +2CA9 ; [.2064.0020.0002] # COPTIC SMALL LETTER UA +2CA8 ; [.2064.0020.0008] # COPTIC CAPITAL LETTER UA +2CAB ; [.2065.0020.0002] # COPTIC SMALL LETTER FI +2CAA ; [.2065.0020.0008] # COPTIC CAPITAL LETTER FI +2CAD ; [.2066.0020.0002] # COPTIC SMALL LETTER KHI +2CAC ; [.2066.0020.0008] # COPTIC CAPITAL LETTER KHI +2CAF ; [.2067.0020.0002] # COPTIC SMALL LETTER PSI +2CAE ; [.2067.0020.0008] # COPTIC CAPITAL LETTER PSI +2CB1 ; [.2068.0020.0002] # COPTIC SMALL LETTER OOU +2CB0 ; [.2068.0020.0008] # COPTIC CAPITAL LETTER OOU +2CBF ; [.2069.0020.0002] # COPTIC SMALL LETTER OLD COPTIC OOU +2CBE ; [.2069.0020.0008] # COPTIC CAPITAL LETTER OLD COPTIC OOU +2CC1 ; [.206A.0020.0002] # COPTIC SMALL LETTER SAMPI +2CC0 ; [.206A.0020.0008] # COPTIC CAPITAL LETTER SAMPI +03E3 ; [.206B.0020.0002] # COPTIC SMALL LETTER SHEI +03E2 ; [.206B.0020.0008] # COPTIC CAPITAL LETTER SHEI +2CEC ; [.206C.0020.0002] # COPTIC SMALL LETTER CRYPTOGRAMMIC SHEI +2CEB ; [.206C.0020.0008] # COPTIC CAPITAL LETTER CRYPTOGRAMMIC SHEI +2CC3 ; [.206D.0020.0002] # COPTIC SMALL LETTER CROSSED SHEI +2CC2 ; [.206D.0020.0008] # COPTIC CAPITAL LETTER CROSSED SHEI +2CC5 ; [.206E.0020.0002] # COPTIC SMALL LETTER OLD COPTIC SHEI +2CC4 ; [.206E.0020.0008] # COPTIC CAPITAL LETTER OLD COPTIC SHEI +2CC7 ; [.206F.0020.0002] # COPTIC SMALL LETTER OLD COPTIC ESH +2CC6 ; [.206F.0020.0008] # COPTIC CAPITAL LETTER OLD COPTIC ESH +03E5 ; [.2070.0020.0002] # COPTIC SMALL LETTER FEI +03E4 ; [.2070.0020.0008] # COPTIC CAPITAL LETTER FEI +03E7 ; [.2071.0020.0002] # COPTIC SMALL LETTER KHEI +03E6 ; [.2071.0020.0008] # COPTIC CAPITAL LETTER KHEI +2CF3 ; [.2072.0020.0002] # COPTIC SMALL LETTER BOHAIRIC KHEI +2CF2 ; [.2072.0020.0008] # COPTIC CAPITAL LETTER BOHAIRIC KHEI +2CC9 ; [.2073.0020.0002] # COPTIC SMALL LETTER AKHMIMIC KHEI +2CC8 ; [.2073.0020.0008] # COPTIC CAPITAL LETTER AKHMIMIC KHEI +03E9 ; [.2074.0020.0002] # COPTIC SMALL LETTER HORI +03E8 ; [.2074.0020.0008] # COPTIC CAPITAL LETTER HORI +2CCB ; [.2075.0020.0002] # COPTIC SMALL LETTER DIALECT-P HORI +2CCA ; [.2075.0020.0008] # COPTIC CAPITAL LETTER DIALECT-P HORI +2CCD ; [.2076.0020.0002] # COPTIC SMALL LETTER OLD COPTIC HORI +2CCC ; [.2076.0020.0008] # COPTIC CAPITAL LETTER OLD COPTIC HORI +2CCF ; [.2077.0020.0002] # COPTIC SMALL LETTER OLD COPTIC HA +2CCE ; [.2077.0020.0008] # COPTIC CAPITAL LETTER OLD COPTIC HA +2CD1 ; [.2078.0020.0002] # COPTIC SMALL LETTER L-SHAPED HA +2CD0 ; [.2078.0020.0008] # COPTIC CAPITAL LETTER L-SHAPED HA +2CD3 ; [.2079.0020.0002] # COPTIC SMALL LETTER OLD COPTIC HEI +2CD2 ; [.2079.0020.0008] # COPTIC CAPITAL LETTER OLD COPTIC HEI +2CD5 ; [.207A.0020.0002] # COPTIC SMALL LETTER OLD COPTIC HAT +2CD4 ; [.207A.0020.0008] # COPTIC CAPITAL LETTER OLD COPTIC HAT +03EB ; [.207B.0020.0002] # COPTIC SMALL LETTER GANGIA +03EA ; [.207B.0020.0008] # COPTIC CAPITAL LETTER GANGIA +2CEE ; [.207C.0020.0002] # COPTIC SMALL LETTER CRYPTOGRAMMIC GANGIA +2CED ; [.207C.0020.0008] # COPTIC CAPITAL LETTER CRYPTOGRAMMIC GANGIA +2CD7 ; [.207D.0020.0002] # COPTIC SMALL LETTER OLD COPTIC GANGIA +2CD6 ; [.207D.0020.0008] # COPTIC CAPITAL LETTER OLD COPTIC GANGIA +03ED ; [.207E.0020.0002] # COPTIC SMALL LETTER SHIMA +03EC ; [.207E.0020.0008] # COPTIC CAPITAL LETTER SHIMA +2CD9 ; [.207F.0020.0002] # COPTIC SMALL LETTER OLD COPTIC DJA +2CD8 ; [.207F.0020.0008] # COPTIC CAPITAL LETTER OLD COPTIC DJA +2CDB ; [.2080.0020.0002] # COPTIC SMALL LETTER OLD COPTIC SHIMA +2CDA ; [.2080.0020.0008] # COPTIC CAPITAL LETTER OLD COPTIC SHIMA +2CDD ; [.2081.0020.0002] # COPTIC SMALL LETTER OLD NUBIAN SHIMA +2CDC ; [.2081.0020.0008] # COPTIC CAPITAL LETTER OLD NUBIAN SHIMA +03EF ; [.2082.0020.0002] # COPTIC SMALL LETTER DEI +03EE ; [.2082.0020.0008] # COPTIC CAPITAL LETTER DEI +2CB3 ; [.2083.0020.0002] # COPTIC SMALL LETTER DIALECT-P ALEF +2CB2 ; [.2083.0020.0008] # COPTIC CAPITAL LETTER DIALECT-P ALEF +2CB5 ; [.2084.0020.0002] # COPTIC SMALL LETTER OLD COPTIC AIN +2CB4 ; [.2084.0020.0008] # COPTIC CAPITAL LETTER OLD COPTIC AIN +2CDF ; [.2085.0020.0002] # COPTIC SMALL LETTER OLD NUBIAN NGI +2CDE ; [.2085.0020.0008] # COPTIC CAPITAL LETTER OLD NUBIAN NGI +2CE1 ; [.2086.0020.0002] # COPTIC SMALL LETTER OLD NUBIAN NYI +2CE0 ; [.2086.0020.0008] # COPTIC CAPITAL LETTER OLD NUBIAN NYI +2CE3 ; [.2087.0020.0002] # COPTIC SMALL LETTER OLD NUBIAN WAU +2CE2 ; [.2087.0020.0008] # COPTIC CAPITAL LETTER OLD NUBIAN WAU +0430 ; [.2088.0020.0002] # CYRILLIC SMALL LETTER A +2DF6 ; [.2088.0020.0004] # COMBINING CYRILLIC LETTER A +0410 ; [.2088.0020.0008] # CYRILLIC CAPITAL LETTER A +04D1 ; [.2088.0020.0002][.0000.0026.0002] # CYRILLIC SMALL LETTER A WITH BREVE +04D0 ; [.2088.0020.0008][.0000.0026.0002] # CYRILLIC CAPITAL LETTER A WITH BREVE +04D3 ; [.2088.0020.0002][.0000.002B.0002] # CYRILLIC SMALL LETTER A WITH DIAERESIS +04D2 ; [.2088.0020.0008][.0000.002B.0002] # CYRILLIC CAPITAL LETTER A WITH DIAERESIS +04D9 ; [.208C.0020.0002] # CYRILLIC SMALL LETTER SCHWA +04D8 ; [.208C.0020.0008] # CYRILLIC CAPITAL LETTER SCHWA +04DB ; [.208C.0020.0002][.0000.002B.0002] # CYRILLIC SMALL LETTER SCHWA WITH DIAERESIS +04DA ; [.208C.0020.0008][.0000.002B.0002] # CYRILLIC CAPITAL LETTER SCHWA WITH DIAERESIS +04D5 ; [.2090.0020.0002] # CYRILLIC SMALL LIGATURE A IE +04D4 ; [.2090.0020.0008] # CYRILLIC CAPITAL LIGATURE A IE +0431 ; [.2094.0020.0002] # CYRILLIC SMALL LETTER BE +2DE0 ; [.2094.0020.0004] # COMBINING CYRILLIC LETTER BE +0411 ; [.2094.0020.0008] # CYRILLIC CAPITAL LETTER BE +0432 ; [.2098.0020.0002] # CYRILLIC SMALL LETTER VE +1C80 ; [.2098.0020.0004] # CYRILLIC SMALL LETTER ROUNDED VE +2DE1 ; [.2098.0020.0004] # COMBINING CYRILLIC LETTER VE +0412 ; [.2098.0020.0008] # CYRILLIC CAPITAL LETTER VE +0433 ; [.209C.0020.0002] # CYRILLIC SMALL LETTER GHE +2DE2 ; [.209C.0020.0004] # COMBINING CYRILLIC LETTER GHE +0413 ; [.209C.0020.0008] # CYRILLIC CAPITAL LETTER GHE +0453 ; [.209C.0020.0002][.0000.0024.0002] # CYRILLIC SMALL LETTER GJE +0403 ; [.209C.0020.0008][.0000.0024.0002] # CYRILLIC CAPITAL LETTER GJE +0491 ; [.209C.0020.0004][.0000.0112.0004] # CYRILLIC SMALL LETTER GHE WITH UPTURN +0490 ; [.209C.0020.000A][.0000.0112.0004] # CYRILLIC CAPITAL LETTER GHE WITH UPTURN +0493 ; [.20A0.0020.0002] # CYRILLIC SMALL LETTER GHE WITH STROKE +0492 ; [.20A0.0020.0008] # CYRILLIC CAPITAL LETTER GHE WITH STROKE +04FB ; [.20A4.0020.0002] # CYRILLIC SMALL LETTER GHE WITH STROKE AND HOOK +04FA ; [.20A4.0020.0008] # CYRILLIC CAPITAL LETTER GHE WITH STROKE AND HOOK +0495 ; [.20A8.0020.0002] # CYRILLIC SMALL LETTER GHE WITH MIDDLE HOOK +0494 ; [.20A8.0020.0008] # CYRILLIC CAPITAL LETTER GHE WITH MIDDLE HOOK +04F7 ; [.20AC.0020.0002] # CYRILLIC SMALL LETTER GHE WITH DESCENDER +04F6 ; [.20AC.0020.0008] # CYRILLIC CAPITAL LETTER GHE WITH DESCENDER +0434 ; [.20B0.0020.0002] # CYRILLIC SMALL LETTER DE +1C81 ; [.20B0.0020.0004] # CYRILLIC SMALL LETTER LONG-LEGGED DE +2DE3 ; [.20B0.0020.0004] # COMBINING CYRILLIC LETTER DE +0414 ; [.20B0.0020.0008] # CYRILLIC CAPITAL LETTER DE +0501 ; [.20B4.0020.0002] # CYRILLIC SMALL LETTER KOMI DE +0500 ; [.20B4.0020.0008] # CYRILLIC CAPITAL LETTER KOMI DE +A681 ; [.20B5.0020.0002] # CYRILLIC SMALL LETTER DWE +A680 ; [.20B5.0020.0008] # CYRILLIC CAPITAL LETTER DWE +0452 ; [.20B6.0020.0002] # CYRILLIC SMALL LETTER DJE +0402 ; [.20B6.0020.0008] # CYRILLIC CAPITAL LETTER DJE +A663 ; [.20BA.0020.0002] # CYRILLIC SMALL LETTER SOFT DE +A662 ; [.20BA.0020.0008] # CYRILLIC CAPITAL LETTER SOFT DE +0503 ; [.20BB.0020.0002] # CYRILLIC SMALL LETTER KOMI DJE +0502 ; [.20BB.0020.0008] # CYRILLIC CAPITAL LETTER KOMI DJE +0499 ; [.20BC.0020.0002] # CYRILLIC SMALL LETTER ZE WITH DESCENDER +0498 ; [.20BC.0020.0008] # CYRILLIC CAPITAL LETTER ZE WITH DESCENDER +0435 ; [.20C0.0020.0002] # CYRILLIC SMALL LETTER IE +2DF7 ; [.20C0.0020.0004] # COMBINING CYRILLIC LETTER IE +0415 ; [.20C0.0020.0008] # CYRILLIC CAPITAL LETTER IE +0450 ; [.20C0.0020.0002][.0000.0025.0002] # CYRILLIC SMALL LETTER IE WITH GRAVE +0400 ; [.20C0.0020.0008][.0000.0025.0002] # CYRILLIC CAPITAL LETTER IE WITH GRAVE +04D7 ; [.20C0.0020.0002][.0000.0026.0002] # CYRILLIC SMALL LETTER IE WITH BREVE +04D6 ; [.20C0.0020.0008][.0000.0026.0002] # CYRILLIC CAPITAL LETTER IE WITH BREVE +0451 ; [.20C0.0020.0002][.0000.002B.0002] # CYRILLIC SMALL LETTER IO +0401 ; [.20C0.0020.0008][.0000.002B.0002] # CYRILLIC CAPITAL LETTER IO +0454 ; [.20C4.0020.0002] # CYRILLIC SMALL LETTER UKRAINIAN IE +A674 ; [.20C4.0020.0004] # COMBINING CYRILLIC LETTER UKRAINIAN IE +0404 ; [.20C4.0020.0008] # CYRILLIC CAPITAL LETTER UKRAINIAN IE +0436 ; [.20C8.0020.0002] # CYRILLIC SMALL LETTER ZHE +2DE4 ; [.20C8.0020.0004] # COMBINING CYRILLIC LETTER ZHE +0416 ; [.20C8.0020.0008] # CYRILLIC CAPITAL LETTER ZHE +04C2 ; [.20C8.0020.0002][.0000.0026.0002] # CYRILLIC SMALL LETTER ZHE WITH BREVE +04C1 ; [.20C8.0020.0008][.0000.0026.0002] # CYRILLIC CAPITAL LETTER ZHE WITH BREVE +04DD ; [.20C8.0020.0002][.0000.002B.0002] # CYRILLIC SMALL LETTER ZHE WITH DIAERESIS +04DC ; [.20C8.0020.0008][.0000.002B.0002] # CYRILLIC CAPITAL LETTER ZHE WITH DIAERESIS +052B ; [.20CC.0020.0002] # CYRILLIC SMALL LETTER DZZHE +052A ; [.20CC.0020.0008] # CYRILLIC CAPITAL LETTER DZZHE +A685 ; [.20CD.0020.0002] # CYRILLIC SMALL LETTER ZHWE +A684 ; [.20CD.0020.0008] # CYRILLIC CAPITAL LETTER ZHWE +0497 ; [.20CE.0020.0002] # CYRILLIC SMALL LETTER ZHE WITH DESCENDER +0496 ; [.20CE.0020.0008] # CYRILLIC CAPITAL LETTER ZHE WITH DESCENDER +0437 ; [.20D2.0020.0002] # CYRILLIC SMALL LETTER ZE +2DE5 ; [.20D2.0020.0004] # COMBINING CYRILLIC LETTER ZE +0417 ; [.20D2.0020.0008] # CYRILLIC CAPITAL LETTER ZE +04DF ; [.20D2.0020.0002][.0000.002B.0002] # CYRILLIC SMALL LETTER ZE WITH DIAERESIS +04DE ; [.20D2.0020.0008][.0000.002B.0002] # CYRILLIC CAPITAL LETTER ZE WITH DIAERESIS +A641 ; [.20D6.0020.0002] # CYRILLIC SMALL LETTER ZEMLYA +A640 ; [.20D6.0020.0008] # CYRILLIC CAPITAL LETTER ZEMLYA +0505 ; [.20D7.0020.0002] # CYRILLIC SMALL LETTER KOMI ZJE +0504 ; [.20D7.0020.0008] # CYRILLIC CAPITAL LETTER KOMI ZJE +0511 ; [.20D8.0020.0002] # CYRILLIC SMALL LETTER REVERSED ZE +0510 ; [.20D8.0020.0008] # CYRILLIC CAPITAL LETTER REVERSED ZE +A643 ; [.20D9.0020.0002] # CYRILLIC SMALL LETTER DZELO +A642 ; [.20D9.0020.0008] # CYRILLIC CAPITAL LETTER DZELO +0455 ; [.20DA.0020.0002] # CYRILLIC SMALL LETTER DZE +0405 ; [.20DA.0020.0008] # CYRILLIC CAPITAL LETTER DZE +A645 ; [.20DE.0020.0002] # CYRILLIC SMALL LETTER REVERSED DZE +A644 ; [.20DE.0020.0008] # CYRILLIC CAPITAL LETTER REVERSED DZE +04E1 ; [.20DF.0020.0002] # CYRILLIC SMALL LETTER ABKHASIAN DZE +04E0 ; [.20DF.0020.0008] # CYRILLIC CAPITAL LETTER ABKHASIAN DZE +A689 ; [.20E3.0020.0002] # CYRILLIC SMALL LETTER DZZE +A688 ; [.20E3.0020.0008] # CYRILLIC CAPITAL LETTER DZZE +0507 ; [.20E4.0020.0002] # CYRILLIC SMALL LETTER KOMI DZJE +0506 ; [.20E4.0020.0008] # CYRILLIC CAPITAL LETTER KOMI DZJE +A683 ; [.20E5.0020.0002] # CYRILLIC SMALL LETTER DZWE +A682 ; [.20E5.0020.0008] # CYRILLIC CAPITAL LETTER DZWE +0438 ; [.20E6.0020.0002] # CYRILLIC SMALL LETTER I +A675 ; [.20E6.0020.0004] # COMBINING CYRILLIC LETTER I +0418 ; [.20E6.0020.0008] # CYRILLIC CAPITAL LETTER I +045D ; [.20E6.0020.0002][.0000.0025.0002] # CYRILLIC SMALL LETTER I WITH GRAVE +040D ; [.20E6.0020.0008][.0000.0025.0002] # CYRILLIC CAPITAL LETTER I WITH GRAVE +04E5 ; [.20E6.0020.0002][.0000.002B.0002] # CYRILLIC SMALL LETTER I WITH DIAERESIS +04E4 ; [.20E6.0020.0008][.0000.002B.0002] # CYRILLIC CAPITAL LETTER I WITH DIAERESIS +04E3 ; [.20E6.0020.0002][.0000.0032.0002] # CYRILLIC SMALL LETTER I WITH MACRON +04E2 ; [.20E6.0020.0008][.0000.0032.0002] # CYRILLIC CAPITAL LETTER I WITH MACRON +048B ; [.20EA.0020.0002] # CYRILLIC SMALL LETTER SHORT I WITH TAIL +048A ; [.20EA.0020.0008] # CYRILLIC CAPITAL LETTER SHORT I WITH TAIL +0456 ; [.20EE.0020.0002] # CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I +0406 ; [.20EE.0020.0008] # CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I +0457 ; [.20EE.0020.0002][.0000.002B.0002] # CYRILLIC SMALL LETTER YI +A676 ; [.20EE.0020.0004][.0000.002B.0004] # COMBINING CYRILLIC LETTER YI +0407 ; [.20EE.0020.0008][.0000.002B.0002] # CYRILLIC CAPITAL LETTER YI +A647 ; [.20F2.0020.0002] # CYRILLIC SMALL LETTER IOTA +A646 ; [.20F2.0020.0008] # CYRILLIC CAPITAL LETTER IOTA +0439 ; [.20F3.0020.0002] # CYRILLIC SMALL LETTER SHORT I +0438 0306 ; [.20F3.0020.0002] # CYRILLIC SMALL LETTER SHORT I +0419 ; [.20F3.0020.0008] # CYRILLIC CAPITAL LETTER SHORT I +0418 0306 ; [.20F3.0020.0008] # CYRILLIC CAPITAL LETTER SHORT I +0458 ; [.20F7.0020.0002] # CYRILLIC SMALL LETTER JE +0408 ; [.20F7.0020.0008] # CYRILLIC CAPITAL LETTER JE +A649 ; [.20FB.0020.0002] # CYRILLIC SMALL LETTER DJERV +2DF8 ; [.20FB.0020.0004] # COMBINING CYRILLIC LETTER DJERV +A648 ; [.20FB.0020.0008] # CYRILLIC CAPITAL LETTER DJERV +043A ; [.20FC.0020.0002] # CYRILLIC SMALL LETTER KA +2DE6 ; [.20FC.0020.0004] # COMBINING CYRILLIC LETTER KA +041A ; [.20FC.0020.0008] # CYRILLIC CAPITAL LETTER KA +045C ; [.20FC.0020.0002][.0000.0024.0002] # CYRILLIC SMALL LETTER KJE +040C ; [.20FC.0020.0008][.0000.0024.0002] # CYRILLIC CAPITAL LETTER KJE +049B ; [.2100.0020.0002] # CYRILLIC SMALL LETTER KA WITH DESCENDER +049A ; [.2100.0020.0008] # CYRILLIC CAPITAL LETTER KA WITH DESCENDER +04C4 ; [.2104.0020.0002] # CYRILLIC SMALL LETTER KA WITH HOOK +04C3 ; [.2104.0020.0008] # CYRILLIC CAPITAL LETTER KA WITH HOOK +04A1 ; [.2108.0020.0002] # CYRILLIC SMALL LETTER BASHKIR KA +04A0 ; [.2108.0020.0008] # CYRILLIC CAPITAL LETTER BASHKIR KA +049F ; [.210C.0020.0002] # CYRILLIC SMALL LETTER KA WITH STROKE +049E ; [.210C.0020.0008] # CYRILLIC CAPITAL LETTER KA WITH STROKE +049D ; [.2110.0020.0002] # CYRILLIC SMALL LETTER KA WITH VERTICAL STROKE +049C ; [.2110.0020.0008] # CYRILLIC CAPITAL LETTER KA WITH VERTICAL STROKE +051F ; [.2114.0020.0002] # CYRILLIC SMALL LETTER ALEUT KA +051E ; [.2114.0020.0008] # CYRILLIC CAPITAL LETTER ALEUT KA +051B ; [.2115.0020.0002] # CYRILLIC SMALL LETTER QA +051A ; [.2115.0020.0008] # CYRILLIC CAPITAL LETTER QA +043B ; [.2116.0020.0002] # CYRILLIC SMALL LETTER EL +2DE7 ; [.2116.0020.0004] # COMBINING CYRILLIC LETTER EL +041B ; [.2116.0020.0008] # CYRILLIC CAPITAL LETTER EL +1D2B ; [.211A.0020.0002] # CYRILLIC LETTER SMALL CAPITAL EL +04C6 ; [.211B.0020.0002] # CYRILLIC SMALL LETTER EL WITH TAIL +04C5 ; [.211B.0020.0008] # CYRILLIC CAPITAL LETTER EL WITH TAIL +052F ; [.211F.0020.0002] # CYRILLIC SMALL LETTER EL WITH DESCENDER +052E ; [.211F.0020.0008] # CYRILLIC CAPITAL LETTER EL WITH DESCENDER +0513 ; [.2120.0020.0002] # CYRILLIC SMALL LETTER EL WITH HOOK +0512 ; [.2120.0020.0008] # CYRILLIC CAPITAL LETTER EL WITH HOOK +0521 ; [.2121.0020.0002] # CYRILLIC SMALL LETTER EL WITH MIDDLE HOOK +0520 ; [.2121.0020.0008] # CYRILLIC CAPITAL LETTER EL WITH MIDDLE HOOK +0459 ; [.2122.0020.0002] # CYRILLIC SMALL LETTER LJE +0409 ; [.2122.0020.0008] # CYRILLIC CAPITAL LETTER LJE +A665 ; [.2126.0020.0002] # CYRILLIC SMALL LETTER SOFT EL +A664 ; [.2126.0020.0008] # CYRILLIC CAPITAL LETTER SOFT EL +0509 ; [.2127.0020.0002] # CYRILLIC SMALL LETTER KOMI LJE +0508 ; [.2127.0020.0008] # CYRILLIC CAPITAL LETTER KOMI LJE +0515 ; [.2128.0020.0002] # CYRILLIC SMALL LETTER LHA +0514 ; [.2128.0020.0008] # CYRILLIC CAPITAL LETTER LHA +043C ; [.2129.0020.0002] # CYRILLIC SMALL LETTER EM +2DE8 ; [.2129.0020.0004] # COMBINING CYRILLIC LETTER EM +041C ; [.2129.0020.0008] # CYRILLIC CAPITAL LETTER EM +04CE ; [.212D.0020.0002] # CYRILLIC SMALL LETTER EM WITH TAIL +04CD ; [.212D.0020.0008] # CYRILLIC CAPITAL LETTER EM WITH TAIL +A667 ; [.2131.0020.0002] # CYRILLIC SMALL LETTER SOFT EM +A666 ; [.2131.0020.0008] # CYRILLIC CAPITAL LETTER SOFT EM +043D ; [.2132.0020.0002] # CYRILLIC SMALL LETTER EN +2DE9 ; [.2132.0020.0004] # COMBINING CYRILLIC LETTER EN +041D ; [.2132.0020.0008] # CYRILLIC CAPITAL LETTER EN +1D78 ; [.2132.0020.0014] # MODIFIER LETTER CYRILLIC EN +0529 ; [.2136.0020.0002] # CYRILLIC SMALL LETTER EN WITH LEFT HOOK +0528 ; [.2136.0020.0008] # CYRILLIC CAPITAL LETTER EN WITH LEFT HOOK +04CA ; [.2137.0020.0002] # CYRILLIC SMALL LETTER EN WITH TAIL +04C9 ; [.2137.0020.0008] # CYRILLIC CAPITAL LETTER EN WITH TAIL +04A3 ; [.213B.0020.0002] # CYRILLIC SMALL LETTER EN WITH DESCENDER +04A2 ; [.213B.0020.0008] # CYRILLIC CAPITAL LETTER EN WITH DESCENDER +04C8 ; [.213F.0020.0002] # CYRILLIC SMALL LETTER EN WITH HOOK +04C7 ; [.213F.0020.0008] # CYRILLIC CAPITAL LETTER EN WITH HOOK +0523 ; [.2143.0020.0002] # CYRILLIC SMALL LETTER EN WITH MIDDLE HOOK +0522 ; [.2143.0020.0008] # CYRILLIC CAPITAL LETTER EN WITH MIDDLE HOOK +04A5 ; [.2144.0020.0002] # CYRILLIC SMALL LIGATURE EN GHE +04A4 ; [.2144.0020.0008] # CYRILLIC CAPITAL LIGATURE EN GHE +045A ; [.2148.0020.0002] # CYRILLIC SMALL LETTER NJE +040A ; [.2148.0020.0008] # CYRILLIC CAPITAL LETTER NJE +050B ; [.214C.0020.0002] # CYRILLIC SMALL LETTER KOMI NJE +050A ; [.214C.0020.0008] # CYRILLIC CAPITAL LETTER KOMI NJE +043E ; [.214D.0020.0002] # CYRILLIC SMALL LETTER O +1C82 ; [.214D.0020.0004] # CYRILLIC SMALL LETTER NARROW O +2DEA ; [.214D.0020.0004] # COMBINING CYRILLIC LETTER O +A669 ; [.214D.0020.0004] # CYRILLIC SMALL LETTER MONOCULAR O +A66B ; [.214D.0020.0004] # CYRILLIC SMALL LETTER BINOCULAR O +A66D ; [.214D.0020.0004] # CYRILLIC SMALL LETTER DOUBLE MONOCULAR O +A66E ; [.214D.0020.0004] # CYRILLIC LETTER MULTIOCULAR O +A699 ; [.214D.0020.0004] # CYRILLIC SMALL LETTER DOUBLE O +A69B ; [.214D.0020.0004] # CYRILLIC SMALL LETTER CROSSED O +041E ; [.214D.0020.0008] # CYRILLIC CAPITAL LETTER O +A668 ; [.214D.0020.000A] # CYRILLIC CAPITAL LETTER MONOCULAR O +A66A ; [.214D.0020.000A] # CYRILLIC CAPITAL LETTER BINOCULAR O +A66C ; [.214D.0020.000A] # CYRILLIC CAPITAL LETTER DOUBLE MONOCULAR O +A698 ; [.214D.0020.000A] # CYRILLIC CAPITAL LETTER DOUBLE O +A69A ; [.214D.0020.000A] # CYRILLIC CAPITAL LETTER CROSSED O +04E7 ; [.214D.0020.0002][.0000.002B.0002] # CYRILLIC SMALL LETTER O WITH DIAERESIS +04E6 ; [.214D.0020.0008][.0000.002B.0002] # CYRILLIC CAPITAL LETTER O WITH DIAERESIS +04E9 ; [.2151.0020.0002] # CYRILLIC SMALL LETTER BARRED O +04E8 ; [.2151.0020.0008] # CYRILLIC CAPITAL LETTER BARRED O +04EB ; [.2151.0020.0002][.0000.002B.0002] # CYRILLIC SMALL LETTER BARRED O WITH DIAERESIS +04EA ; [.2151.0020.0008][.0000.002B.0002] # CYRILLIC CAPITAL LETTER BARRED O WITH DIAERESIS +043F ; [.2155.0020.0002] # CYRILLIC SMALL LETTER PE +2DEB ; [.2155.0020.0004] # COMBINING CYRILLIC LETTER PE +041F ; [.2155.0020.0008] # CYRILLIC CAPITAL LETTER PE +0525 ; [.2159.0020.0002] # CYRILLIC SMALL LETTER PE WITH DESCENDER +0524 ; [.2159.0020.0008] # CYRILLIC CAPITAL LETTER PE WITH DESCENDER +04A7 ; [.215A.0020.0002] # CYRILLIC SMALL LETTER PE WITH MIDDLE HOOK +04A6 ; [.215A.0020.0008] # CYRILLIC CAPITAL LETTER PE WITH MIDDLE HOOK +0481 ; [.215E.0020.0002] # CYRILLIC SMALL LETTER KOPPA +0480 ; [.215E.0020.0008] # CYRILLIC CAPITAL LETTER KOPPA +0440 ; [.2162.0020.0002] # CYRILLIC SMALL LETTER ER +2DEC ; [.2162.0020.0004] # COMBINING CYRILLIC LETTER ER +0420 ; [.2162.0020.0008] # CYRILLIC CAPITAL LETTER ER +048F ; [.2166.0020.0002] # CYRILLIC SMALL LETTER ER WITH TICK +048E ; [.2166.0020.0008] # CYRILLIC CAPITAL LETTER ER WITH TICK +0517 ; [.216A.0020.0002] # CYRILLIC SMALL LETTER RHA +0516 ; [.216A.0020.0008] # CYRILLIC CAPITAL LETTER RHA +0441 ; [.216B.0020.0002] # CYRILLIC SMALL LETTER ES +1C83 ; [.216B.0020.0004] # CYRILLIC SMALL LETTER WIDE ES +2DED ; [.216B.0020.0004] # COMBINING CYRILLIC LETTER ES +0421 ; [.216B.0020.0008] # CYRILLIC CAPITAL LETTER ES +2DF5 ; [.216B.0020.0004][.2174.0020.0004] # COMBINING CYRILLIC LETTER ES-TE +050D ; [.216F.0020.0002] # CYRILLIC SMALL LETTER KOMI SJE +050C ; [.216F.0020.0008] # CYRILLIC CAPITAL LETTER KOMI SJE +04AB ; [.2170.0020.0002] # CYRILLIC SMALL LETTER ES WITH DESCENDER +04AA ; [.2170.0020.0008] # CYRILLIC CAPITAL LETTER ES WITH DESCENDER +0442 ; [.2174.0020.0002] # CYRILLIC SMALL LETTER TE +1C84 ; [.2174.0020.0004] # CYRILLIC SMALL LETTER TALL TE +1C85 ; [.2174.0020.0004] # CYRILLIC SMALL LETTER THREE-LEGGED TE +2DEE ; [.2174.0020.0004] # COMBINING CYRILLIC LETTER TE +0422 ; [.2174.0020.0008] # CYRILLIC CAPITAL LETTER TE +A68D ; [.2178.0020.0002] # CYRILLIC SMALL LETTER TWE +A68C ; [.2178.0020.0008] # CYRILLIC CAPITAL LETTER TWE +050F ; [.2179.0020.0002] # CYRILLIC SMALL LETTER KOMI TJE +050E ; [.2179.0020.0008] # CYRILLIC CAPITAL LETTER KOMI TJE +04AD ; [.217A.0020.0002] # CYRILLIC SMALL LETTER TE WITH DESCENDER +04AC ; [.217A.0020.0008] # CYRILLIC CAPITAL LETTER TE WITH DESCENDER +A68B ; [.217E.0020.0002] # CYRILLIC SMALL LETTER TE WITH MIDDLE HOOK +A68A ; [.217E.0020.0008] # CYRILLIC CAPITAL LETTER TE WITH MIDDLE HOOK +045B ; [.217F.0020.0002] # CYRILLIC SMALL LETTER TSHE +040B ; [.217F.0020.0008] # CYRILLIC CAPITAL LETTER TSHE +0443 ; [.2183.0020.0002] # CYRILLIC SMALL LETTER U +A677 ; [.2183.0020.0004] # COMBINING CYRILLIC LETTER U +0423 ; [.2183.0020.0008] # CYRILLIC CAPITAL LETTER U +045E ; [.2183.0020.0002][.0000.0026.0002] # CYRILLIC SMALL LETTER SHORT U +040E ; [.2183.0020.0008][.0000.0026.0002] # CYRILLIC CAPITAL LETTER SHORT U +04F1 ; [.2183.0020.0002][.0000.002B.0002] # CYRILLIC SMALL LETTER U WITH DIAERESIS +04F0 ; [.2183.0020.0008][.0000.002B.0002] # CYRILLIC CAPITAL LETTER U WITH DIAERESIS +04F3 ; [.2183.0020.0002][.0000.002C.0002] # CYRILLIC SMALL LETTER U WITH DOUBLE ACUTE +04F2 ; [.2183.0020.0008][.0000.002C.0002] # CYRILLIC CAPITAL LETTER U WITH DOUBLE ACUTE +04EF ; [.2183.0020.0002][.0000.0032.0002] # CYRILLIC SMALL LETTER U WITH MACRON +04EE ; [.2183.0020.0008][.0000.0032.0002] # CYRILLIC CAPITAL LETTER U WITH MACRON +04AF ; [.2187.0020.0002] # CYRILLIC SMALL LETTER STRAIGHT U +04AE ; [.2187.0020.0008] # CYRILLIC CAPITAL LETTER STRAIGHT U +04B1 ; [.218B.0020.0002] # CYRILLIC SMALL LETTER STRAIGHT U WITH STROKE +04B0 ; [.218B.0020.0008] # CYRILLIC CAPITAL LETTER STRAIGHT U WITH STROKE +A64B ; [.218F.0020.0002] # CYRILLIC SMALL LETTER MONOGRAPH UK +1C88 ; [.218F.0020.0004] # CYRILLIC SMALL LETTER UNBLENDED UK +2DF9 ; [.218F.0020.0004] # COMBINING CYRILLIC LETTER MONOGRAPH UK +A64A ; [.218F.0020.0008] # CYRILLIC CAPITAL LETTER MONOGRAPH UK +0479 ; [.2190.0020.0002] # CYRILLIC SMALL LETTER UK +0478 ; [.2190.0020.0008] # CYRILLIC CAPITAL LETTER UK +0444 ; [.2194.0020.0002] # CYRILLIC SMALL LETTER EF +A69E ; [.2194.0020.0004] # COMBINING CYRILLIC LETTER EF +0424 ; [.2194.0020.0008] # CYRILLIC CAPITAL LETTER EF +0445 ; [.2198.0020.0002] # CYRILLIC SMALL LETTER HA +2DEF ; [.2198.0020.0004] # COMBINING CYRILLIC LETTER HA +0425 ; [.2198.0020.0008] # CYRILLIC CAPITAL LETTER HA +04FD ; [.219C.0020.0002] # CYRILLIC SMALL LETTER HA WITH HOOK +04FC ; [.219C.0020.0008] # CYRILLIC CAPITAL LETTER HA WITH HOOK +04FF ; [.21A0.0020.0002] # CYRILLIC SMALL LETTER HA WITH STROKE +04FE ; [.21A0.0020.0008] # CYRILLIC CAPITAL LETTER HA WITH STROKE +04B3 ; [.21A4.0020.0002] # CYRILLIC SMALL LETTER HA WITH DESCENDER +04B2 ; [.21A4.0020.0008] # CYRILLIC CAPITAL LETTER HA WITH DESCENDER +04BB ; [.21A8.0020.0002] # CYRILLIC SMALL LETTER SHHA +04BA ; [.21A8.0020.0008] # CYRILLIC CAPITAL LETTER SHHA +0527 ; [.21AC.0020.0002] # CYRILLIC SMALL LETTER SHHA WITH DESCENDER +0526 ; [.21AC.0020.0008] # CYRILLIC CAPITAL LETTER SHHA WITH DESCENDER +A695 ; [.21AD.0020.0002] # CYRILLIC SMALL LETTER HWE +A694 ; [.21AD.0020.0008] # CYRILLIC CAPITAL LETTER HWE +0461 ; [.21AE.0020.0002] # CYRILLIC SMALL LETTER OMEGA +A67B ; [.21AE.0020.0004] # COMBINING CYRILLIC LETTER OMEGA +0460 ; [.21AE.0020.0008] # CYRILLIC CAPITAL LETTER OMEGA +047F ; [.21B2.0020.0002] # CYRILLIC SMALL LETTER OT +047E ; [.21B2.0020.0008] # CYRILLIC CAPITAL LETTER OT +A64D ; [.21B6.0020.0002] # CYRILLIC SMALL LETTER BROAD OMEGA +A64C ; [.21B6.0020.0008] # CYRILLIC CAPITAL LETTER BROAD OMEGA +047D ; [.21B7.0020.0002] # CYRILLIC SMALL LETTER OMEGA WITH TITLO +047C ; [.21B7.0020.0008] # CYRILLIC CAPITAL LETTER OMEGA WITH TITLO +047B ; [.21BB.0020.0002] # CYRILLIC SMALL LETTER ROUND OMEGA +047A ; [.21BB.0020.0008] # CYRILLIC CAPITAL LETTER ROUND OMEGA +0446 ; [.21BF.0020.0002] # CYRILLIC SMALL LETTER TSE +2DF0 ; [.21BF.0020.0004] # COMBINING CYRILLIC LETTER TSE +0426 ; [.21BF.0020.0008] # CYRILLIC CAPITAL LETTER TSE +A661 ; [.21C3.0020.0002] # CYRILLIC SMALL LETTER REVERSED TSE +A660 ; [.21C3.0020.0008] # CYRILLIC CAPITAL LETTER REVERSED TSE +A68F ; [.21C4.0020.0002] # CYRILLIC SMALL LETTER TSWE +A68E ; [.21C4.0020.0008] # CYRILLIC CAPITAL LETTER TSWE +04B5 ; [.21C5.0020.0002] # CYRILLIC SMALL LIGATURE TE TSE +04B4 ; [.21C5.0020.0008] # CYRILLIC CAPITAL LIGATURE TE TSE +A691 ; [.21C9.0020.0002] # CYRILLIC SMALL LETTER TSSE +A690 ; [.21C9.0020.0008] # CYRILLIC CAPITAL LETTER TSSE +0447 ; [.21CA.0020.0002] # CYRILLIC SMALL LETTER CHE +2DF1 ; [.21CA.0020.0004] # COMBINING CYRILLIC LETTER CHE +0427 ; [.21CA.0020.0008] # CYRILLIC CAPITAL LETTER CHE +04F5 ; [.21CA.0020.0002][.0000.002B.0002] # CYRILLIC SMALL LETTER CHE WITH DIAERESIS +04F4 ; [.21CA.0020.0008][.0000.002B.0002] # CYRILLIC CAPITAL LETTER CHE WITH DIAERESIS +052D ; [.21CE.0020.0002] # CYRILLIC SMALL LETTER DCHE +052C ; [.21CE.0020.0008] # CYRILLIC CAPITAL LETTER DCHE +A693 ; [.21CF.0020.0002] # CYRILLIC SMALL LETTER TCHE +A692 ; [.21CF.0020.0008] # CYRILLIC CAPITAL LETTER TCHE +04B7 ; [.21D0.0020.0002] # CYRILLIC SMALL LETTER CHE WITH DESCENDER +04B6 ; [.21D0.0020.0008] # CYRILLIC CAPITAL LETTER CHE WITH DESCENDER +04CC ; [.21D4.0020.0002] # CYRILLIC SMALL LETTER KHAKASSIAN CHE +04CB ; [.21D4.0020.0008] # CYRILLIC CAPITAL LETTER KHAKASSIAN CHE +04B9 ; [.21D8.0020.0002] # CYRILLIC SMALL LETTER CHE WITH VERTICAL STROKE +04B8 ; [.21D8.0020.0008] # CYRILLIC CAPITAL LETTER CHE WITH VERTICAL STROKE +A687 ; [.21DC.0020.0002] # CYRILLIC SMALL LETTER CCHE +A686 ; [.21DC.0020.0008] # CYRILLIC CAPITAL LETTER CCHE +04BD ; [.21DD.0020.0002] # CYRILLIC SMALL LETTER ABKHASIAN CHE +04BC ; [.21DD.0020.0008] # CYRILLIC CAPITAL LETTER ABKHASIAN CHE +04BF ; [.21E1.0020.0002] # CYRILLIC SMALL LETTER ABKHASIAN CHE WITH DESCENDER +04BE ; [.21E1.0020.0008] # CYRILLIC CAPITAL LETTER ABKHASIAN CHE WITH DESCENDER +045F ; [.21E5.0020.0002] # CYRILLIC SMALL LETTER DZHE +040F ; [.21E5.0020.0008] # CYRILLIC CAPITAL LETTER DZHE +0448 ; [.21E9.0020.0002] # CYRILLIC SMALL LETTER SHA +2DF2 ; [.21E9.0020.0004] # COMBINING CYRILLIC LETTER SHA +0428 ; [.21E9.0020.0008] # CYRILLIC CAPITAL LETTER SHA +A697 ; [.21ED.0020.0002] # CYRILLIC SMALL LETTER SHWE +A696 ; [.21ED.0020.0008] # CYRILLIC CAPITAL LETTER SHWE +0449 ; [.21EE.0020.0002] # CYRILLIC SMALL LETTER SHCHA +2DF3 ; [.21EE.0020.0004] # COMBINING CYRILLIC LETTER SHCHA +0429 ; [.21EE.0020.0008] # CYRILLIC CAPITAL LETTER SHCHA +A64F ; [.21F2.0020.0002] # CYRILLIC SMALL LETTER NEUTRAL YER +A64E ; [.21F2.0020.0008] # CYRILLIC CAPITAL LETTER NEUTRAL YER +2E2F ; [.21F3.0020.0002] # VERTICAL TILDE +A67F ; [.21F4.0020.0002] # CYRILLIC PAYEROK +044A ; [.21F5.0020.0002] # CYRILLIC SMALL LETTER HARD SIGN +1C86 ; [.21F5.0020.0004] # CYRILLIC SMALL LETTER TALL HARD SIGN +A678 ; [.21F5.0020.0004] # COMBINING CYRILLIC LETTER HARD SIGN +042A ; [.21F5.0020.0008] # CYRILLIC CAPITAL LETTER HARD SIGN +A69C ; [.21F5.0020.0014] # MODIFIER LETTER CYRILLIC HARD SIGN +A651 ; [.21F9.0020.0002] # CYRILLIC SMALL LETTER YERU WITH BACK YER +A650 ; [.21F9.0020.0008] # CYRILLIC CAPITAL LETTER YERU WITH BACK YER +044B ; [.21FA.0020.0002] # CYRILLIC SMALL LETTER YERU +A679 ; [.21FA.0020.0004] # COMBINING CYRILLIC LETTER YERU +042B ; [.21FA.0020.0008] # CYRILLIC CAPITAL LETTER YERU +04F9 ; [.21FA.0020.0002][.0000.002B.0002] # CYRILLIC SMALL LETTER YERU WITH DIAERESIS +04F8 ; [.21FA.0020.0008][.0000.002B.0002] # CYRILLIC CAPITAL LETTER YERU WITH DIAERESIS +044C ; [.21FE.0020.0002] # CYRILLIC SMALL LETTER SOFT SIGN +A67A ; [.21FE.0020.0004] # COMBINING CYRILLIC LETTER SOFT SIGN +042C ; [.21FE.0020.0008] # CYRILLIC CAPITAL LETTER SOFT SIGN +A69D ; [.21FE.0020.0014] # MODIFIER LETTER CYRILLIC SOFT SIGN +048D ; [.2202.0020.0002] # CYRILLIC SMALL LETTER SEMISOFT SIGN +048C ; [.2202.0020.0008] # CYRILLIC CAPITAL LETTER SEMISOFT SIGN +0463 ; [.2206.0020.0002] # CYRILLIC SMALL LETTER YAT +1C87 ; [.2206.0020.0004] # CYRILLIC SMALL LETTER TALL YAT +2DFA ; [.2206.0020.0004] # COMBINING CYRILLIC LETTER YAT +0462 ; [.2206.0020.0008] # CYRILLIC CAPITAL LETTER YAT +A653 ; [.220A.0020.0002] # CYRILLIC SMALL LETTER IOTIFIED YAT +A652 ; [.220A.0020.0008] # CYRILLIC CAPITAL LETTER IOTIFIED YAT +044D ; [.220B.0020.0002] # CYRILLIC SMALL LETTER E +042D ; [.220B.0020.0008] # CYRILLIC CAPITAL LETTER E +04ED ; [.220B.0020.0002][.0000.002B.0002] # CYRILLIC SMALL LETTER E WITH DIAERESIS +04EC ; [.220B.0020.0008][.0000.002B.0002] # CYRILLIC CAPITAL LETTER E WITH DIAERESIS +044E ; [.220F.0020.0002] # CYRILLIC SMALL LETTER YU +2DFB ; [.220F.0020.0004] # COMBINING CYRILLIC LETTER YU +042E ; [.220F.0020.0008] # CYRILLIC CAPITAL LETTER YU +A655 ; [.2213.0020.0002] # CYRILLIC SMALL LETTER REVERSED YU +A654 ; [.2213.0020.0008] # CYRILLIC CAPITAL LETTER REVERSED YU +A657 ; [.2214.0020.0002] # CYRILLIC SMALL LETTER IOTIFIED A +2DFC ; [.2214.0020.0004] # COMBINING CYRILLIC LETTER IOTIFIED A +A656 ; [.2214.0020.0008] # CYRILLIC CAPITAL LETTER IOTIFIED A +044F ; [.2215.0020.0002] # CYRILLIC SMALL LETTER YA +042F ; [.2215.0020.0008] # CYRILLIC CAPITAL LETTER YA +0519 ; [.2219.0020.0002] # CYRILLIC SMALL LETTER YAE +0518 ; [.2219.0020.0008] # CYRILLIC CAPITAL LETTER YAE +0465 ; [.221A.0020.0002] # CYRILLIC SMALL LETTER IOTIFIED E +A69F ; [.221A.0020.0004] # COMBINING CYRILLIC LETTER IOTIFIED E +0464 ; [.221A.0020.0008] # CYRILLIC CAPITAL LETTER IOTIFIED E +0467 ; [.221E.0020.0002] # CYRILLIC SMALL LETTER LITTLE YUS +2DFD ; [.221E.0020.0004] # COMBINING CYRILLIC LETTER LITTLE YUS +0466 ; [.221E.0020.0008] # CYRILLIC CAPITAL LETTER LITTLE YUS +A659 ; [.2222.0020.0002] # CYRILLIC SMALL LETTER CLOSED LITTLE YUS +A658 ; [.2222.0020.0008] # CYRILLIC CAPITAL LETTER CLOSED LITTLE YUS +046B ; [.2223.0020.0002] # CYRILLIC SMALL LETTER BIG YUS +2DFE ; [.2223.0020.0004] # COMBINING CYRILLIC LETTER BIG YUS +046A ; [.2223.0020.0008] # CYRILLIC CAPITAL LETTER BIG YUS +A65B ; [.2227.0020.0002] # CYRILLIC SMALL LETTER BLENDED YUS +A65A ; [.2227.0020.0008] # CYRILLIC CAPITAL LETTER BLENDED YUS +0469 ; [.2228.0020.0002] # CYRILLIC SMALL LETTER IOTIFIED LITTLE YUS +0468 ; [.2228.0020.0008] # CYRILLIC CAPITAL LETTER IOTIFIED LITTLE YUS +A65D ; [.222C.0020.0002] # CYRILLIC SMALL LETTER IOTIFIED CLOSED LITTLE YUS +A65C ; [.222C.0020.0008] # CYRILLIC CAPITAL LETTER IOTIFIED CLOSED LITTLE YUS +046D ; [.222D.0020.0002] # CYRILLIC SMALL LETTER IOTIFIED BIG YUS +2DFF ; [.222D.0020.0004] # COMBINING CYRILLIC LETTER IOTIFIED BIG YUS +046C ; [.222D.0020.0008] # CYRILLIC CAPITAL LETTER IOTIFIED BIG YUS +046F ; [.2231.0020.0002] # CYRILLIC SMALL LETTER KSI +046E ; [.2231.0020.0008] # CYRILLIC CAPITAL LETTER KSI +0471 ; [.2235.0020.0002] # CYRILLIC SMALL LETTER PSI +0470 ; [.2235.0020.0008] # CYRILLIC CAPITAL LETTER PSI +0473 ; [.2239.0020.0002] # CYRILLIC SMALL LETTER FITA +2DF4 ; [.2239.0020.0004] # COMBINING CYRILLIC LETTER FITA +0472 ; [.2239.0020.0008] # CYRILLIC CAPITAL LETTER FITA +0475 ; [.223D.0020.0002] # CYRILLIC SMALL LETTER IZHITSA +0474 ; [.223D.0020.0008] # CYRILLIC CAPITAL LETTER IZHITSA +0477 ; [.223D.0020.0002][.0000.003C.0002] # CYRILLIC SMALL LETTER IZHITSA WITH DOUBLE GRAVE ACCENT +0476 ; [.223D.0020.0008][.0000.003C.0002] # CYRILLIC CAPITAL LETTER IZHITSA WITH DOUBLE GRAVE ACCENT +A65F ; [.2241.0020.0002] # CYRILLIC SMALL LETTER YN +A65E ; [.2241.0020.0008] # CYRILLIC CAPITAL LETTER YN +04A9 ; [.2242.0020.0002] # CYRILLIC SMALL LETTER ABKHASIAN HA +04A8 ; [.2242.0020.0008] # CYRILLIC CAPITAL LETTER ABKHASIAN HA +051D ; [.2246.0020.0002] # CYRILLIC SMALL LETTER WE +051C ; [.2246.0020.0008] # CYRILLIC CAPITAL LETTER WE +04CF ; [.2247.0020.0002] # CYRILLIC SMALL LETTER PALOCHKA +04C0 ; [.2247.0020.0008] # CYRILLIC LETTER PALOCHKA +2C30 ; [.224B.0020.0002] # GLAGOLITIC SMALL LETTER AZU +1E000 ; [.224B.0020.0004] # COMBINING GLAGOLITIC LETTER AZU +2C00 ; [.224B.0020.0008] # GLAGOLITIC CAPITAL LETTER AZU +2C31 ; [.224C.0020.0002] # GLAGOLITIC SMALL LETTER BUKY +1E001 ; [.224C.0020.0004] # COMBINING GLAGOLITIC LETTER BUKY +2C01 ; [.224C.0020.0008] # GLAGOLITIC CAPITAL LETTER BUKY +2C32 ; [.224D.0020.0002] # GLAGOLITIC SMALL LETTER VEDE +1E002 ; [.224D.0020.0004] # COMBINING GLAGOLITIC LETTER VEDE +2C02 ; [.224D.0020.0008] # GLAGOLITIC CAPITAL LETTER VEDE +2C33 ; [.224E.0020.0002] # GLAGOLITIC SMALL LETTER GLAGOLI +1E003 ; [.224E.0020.0004] # COMBINING GLAGOLITIC LETTER GLAGOLI +2C03 ; [.224E.0020.0008] # GLAGOLITIC CAPITAL LETTER GLAGOLI +2C34 ; [.224F.0020.0002] # GLAGOLITIC SMALL LETTER DOBRO +1E004 ; [.224F.0020.0004] # COMBINING GLAGOLITIC LETTER DOBRO +2C04 ; [.224F.0020.0008] # GLAGOLITIC CAPITAL LETTER DOBRO +2C35 ; [.2250.0020.0002] # GLAGOLITIC SMALL LETTER YESTU +1E005 ; [.2250.0020.0004] # COMBINING GLAGOLITIC LETTER YESTU +2C05 ; [.2250.0020.0008] # GLAGOLITIC CAPITAL LETTER YESTU +2C36 ; [.2251.0020.0002] # GLAGOLITIC SMALL LETTER ZHIVETE +1E006 ; [.2251.0020.0004] # COMBINING GLAGOLITIC LETTER ZHIVETE +2C06 ; [.2251.0020.0008] # GLAGOLITIC CAPITAL LETTER ZHIVETE +2C37 ; [.2252.0020.0002] # GLAGOLITIC SMALL LETTER DZELO +2C07 ; [.2252.0020.0008] # GLAGOLITIC CAPITAL LETTER DZELO +2C38 ; [.2253.0020.0002] # GLAGOLITIC SMALL LETTER ZEMLJA +1E008 ; [.2253.0020.0004] # COMBINING GLAGOLITIC LETTER ZEMLJA +2C08 ; [.2253.0020.0008] # GLAGOLITIC CAPITAL LETTER ZEMLJA +2C39 ; [.2254.0020.0002] # GLAGOLITIC SMALL LETTER IZHE +1E009 ; [.2254.0020.0004] # COMBINING GLAGOLITIC LETTER IZHE +2C09 ; [.2254.0020.0008] # GLAGOLITIC CAPITAL LETTER IZHE +2C3A ; [.2255.0020.0002] # GLAGOLITIC SMALL LETTER INITIAL IZHE +1E00A ; [.2255.0020.0004] # COMBINING GLAGOLITIC LETTER INITIAL IZHE +2C0A ; [.2255.0020.0008] # GLAGOLITIC CAPITAL LETTER INITIAL IZHE +2C3B ; [.2256.0020.0002] # GLAGOLITIC SMALL LETTER I +1E00B ; [.2256.0020.0004] # COMBINING GLAGOLITIC LETTER I +2C0B ; [.2256.0020.0008] # GLAGOLITIC CAPITAL LETTER I +2C3C ; [.2257.0020.0002] # GLAGOLITIC SMALL LETTER DJERVI +1E00C ; [.2257.0020.0004] # COMBINING GLAGOLITIC LETTER DJERVI +2C0C ; [.2257.0020.0008] # GLAGOLITIC CAPITAL LETTER DJERVI +2C3D ; [.2258.0020.0002] # GLAGOLITIC SMALL LETTER KAKO +1E00D ; [.2258.0020.0004] # COMBINING GLAGOLITIC LETTER KAKO +2C0D ; [.2258.0020.0008] # GLAGOLITIC CAPITAL LETTER KAKO +2C3E ; [.2259.0020.0002] # GLAGOLITIC SMALL LETTER LJUDIJE +1E00E ; [.2259.0020.0004] # COMBINING GLAGOLITIC LETTER LJUDIJE +2C0E ; [.2259.0020.0008] # GLAGOLITIC CAPITAL LETTER LJUDIJE +2C3F ; [.225A.0020.0002] # GLAGOLITIC SMALL LETTER MYSLITE +1E00F ; [.225A.0020.0004] # COMBINING GLAGOLITIC LETTER MYSLITE +2C0F ; [.225A.0020.0008] # GLAGOLITIC CAPITAL LETTER MYSLITE +2C40 ; [.225B.0020.0002] # GLAGOLITIC SMALL LETTER NASHI +1E010 ; [.225B.0020.0004] # COMBINING GLAGOLITIC LETTER NASHI +2C10 ; [.225B.0020.0008] # GLAGOLITIC CAPITAL LETTER NASHI +2C41 ; [.225C.0020.0002] # GLAGOLITIC SMALL LETTER ONU +1E011 ; [.225C.0020.0004] # COMBINING GLAGOLITIC LETTER ONU +2C11 ; [.225C.0020.0008] # GLAGOLITIC CAPITAL LETTER ONU +2C42 ; [.225D.0020.0002] # GLAGOLITIC SMALL LETTER POKOJI +1E012 ; [.225D.0020.0004] # COMBINING GLAGOLITIC LETTER POKOJI +2C12 ; [.225D.0020.0008] # GLAGOLITIC CAPITAL LETTER POKOJI +2C43 ; [.225E.0020.0002] # GLAGOLITIC SMALL LETTER RITSI +1E013 ; [.225E.0020.0004] # COMBINING GLAGOLITIC LETTER RITSI +2C13 ; [.225E.0020.0008] # GLAGOLITIC CAPITAL LETTER RITSI +2C44 ; [.225F.0020.0002] # GLAGOLITIC SMALL LETTER SLOVO +1E014 ; [.225F.0020.0004] # COMBINING GLAGOLITIC LETTER SLOVO +2C14 ; [.225F.0020.0008] # GLAGOLITIC CAPITAL LETTER SLOVO +2C45 ; [.2260.0020.0002] # GLAGOLITIC SMALL LETTER TVRIDO +1E015 ; [.2260.0020.0004] # COMBINING GLAGOLITIC LETTER TVRIDO +2C15 ; [.2260.0020.0008] # GLAGOLITIC CAPITAL LETTER TVRIDO +2C46 ; [.2261.0020.0002] # GLAGOLITIC SMALL LETTER UKU +1E016 ; [.2261.0020.0004] # COMBINING GLAGOLITIC LETTER UKU +2C16 ; [.2261.0020.0008] # GLAGOLITIC CAPITAL LETTER UKU +2C47 ; [.2262.0020.0002] # GLAGOLITIC SMALL LETTER FRITU +1E017 ; [.2262.0020.0004] # COMBINING GLAGOLITIC LETTER FRITU +2C17 ; [.2262.0020.0008] # GLAGOLITIC CAPITAL LETTER FRITU +2C48 ; [.2263.0020.0002] # GLAGOLITIC SMALL LETTER HERU +1E018 ; [.2263.0020.0004] # COMBINING GLAGOLITIC LETTER HERU +2C18 ; [.2263.0020.0008] # GLAGOLITIC CAPITAL LETTER HERU +2C49 ; [.2264.0020.0002] # GLAGOLITIC SMALL LETTER OTU +2C19 ; [.2264.0020.0008] # GLAGOLITIC CAPITAL LETTER OTU +2C4A ; [.2265.0020.0002] # GLAGOLITIC SMALL LETTER PE +2C1A ; [.2265.0020.0008] # GLAGOLITIC CAPITAL LETTER PE +2C4B ; [.2266.0020.0002] # GLAGOLITIC SMALL LETTER SHTA +1E01B ; [.2266.0020.0004] # COMBINING GLAGOLITIC LETTER SHTA +2C1B ; [.2266.0020.0008] # GLAGOLITIC CAPITAL LETTER SHTA +2C4C ; [.2267.0020.0002] # GLAGOLITIC SMALL LETTER TSI +1E01C ; [.2267.0020.0004] # COMBINING GLAGOLITIC LETTER TSI +2C1C ; [.2267.0020.0008] # GLAGOLITIC CAPITAL LETTER TSI +2C4D ; [.2268.0020.0002] # GLAGOLITIC SMALL LETTER CHRIVI +1E01D ; [.2268.0020.0004] # COMBINING GLAGOLITIC LETTER CHRIVI +2C1D ; [.2268.0020.0008] # GLAGOLITIC CAPITAL LETTER CHRIVI +2C4E ; [.2269.0020.0002] # GLAGOLITIC SMALL LETTER SHA +1E01E ; [.2269.0020.0004] # COMBINING GLAGOLITIC LETTER SHA +2C1E ; [.2269.0020.0008] # GLAGOLITIC CAPITAL LETTER SHA +2C4F ; [.226A.0020.0002] # GLAGOLITIC SMALL LETTER YERU +1E01F ; [.226A.0020.0004] # COMBINING GLAGOLITIC LETTER YERU +2C1F ; [.226A.0020.0008] # GLAGOLITIC CAPITAL LETTER YERU +2C50 ; [.226B.0020.0002] # GLAGOLITIC SMALL LETTER YERI +1E020 ; [.226B.0020.0004] # COMBINING GLAGOLITIC LETTER YERI +2C20 ; [.226B.0020.0008] # GLAGOLITIC CAPITAL LETTER YERI +2C51 ; [.226C.0020.0002] # GLAGOLITIC SMALL LETTER YATI +1E021 ; [.226C.0020.0004] # COMBINING GLAGOLITIC LETTER YATI +2C21 ; [.226C.0020.0008] # GLAGOLITIC CAPITAL LETTER YATI +2C52 ; [.226D.0020.0002] # GLAGOLITIC SMALL LETTER SPIDERY HA +2C22 ; [.226D.0020.0008] # GLAGOLITIC CAPITAL LETTER SPIDERY HA +2C53 ; [.226E.0020.0002] # GLAGOLITIC SMALL LETTER YU +1E023 ; [.226E.0020.0004] # COMBINING GLAGOLITIC LETTER YU +2C23 ; [.226E.0020.0008] # GLAGOLITIC CAPITAL LETTER YU +2C54 ; [.226F.0020.0002] # GLAGOLITIC SMALL LETTER SMALL YUS +1E024 ; [.226F.0020.0004] # COMBINING GLAGOLITIC LETTER SMALL YUS +2C24 ; [.226F.0020.0008] # GLAGOLITIC CAPITAL LETTER SMALL YUS +2C55 ; [.2270.0020.0002] # GLAGOLITIC SMALL LETTER SMALL YUS WITH TAIL +2C25 ; [.2270.0020.0008] # GLAGOLITIC CAPITAL LETTER SMALL YUS WITH TAIL +2C56 ; [.2271.0020.0002] # GLAGOLITIC SMALL LETTER YO +1E026 ; [.2271.0020.0004] # COMBINING GLAGOLITIC LETTER YO +2C26 ; [.2271.0020.0008] # GLAGOLITIC CAPITAL LETTER YO +2C57 ; [.2272.0020.0002] # GLAGOLITIC SMALL LETTER IOTATED SMALL YUS +1E027 ; [.2272.0020.0004] # COMBINING GLAGOLITIC LETTER IOTATED SMALL YUS +2C27 ; [.2272.0020.0008] # GLAGOLITIC CAPITAL LETTER IOTATED SMALL YUS +2C58 ; [.2273.0020.0002] # GLAGOLITIC SMALL LETTER BIG YUS +1E028 ; [.2273.0020.0004] # COMBINING GLAGOLITIC LETTER BIG YUS +2C28 ; [.2273.0020.0008] # GLAGOLITIC CAPITAL LETTER BIG YUS +2C59 ; [.2274.0020.0002] # GLAGOLITIC SMALL LETTER IOTATED BIG YUS +1E029 ; [.2274.0020.0004] # COMBINING GLAGOLITIC LETTER IOTATED BIG YUS +2C29 ; [.2274.0020.0008] # GLAGOLITIC CAPITAL LETTER IOTATED BIG YUS +2C5A ; [.2275.0020.0002] # GLAGOLITIC SMALL LETTER FITA +1E02A ; [.2275.0020.0004] # COMBINING GLAGOLITIC LETTER FITA +2C2A ; [.2275.0020.0008] # GLAGOLITIC CAPITAL LETTER FITA +2C5B ; [.2276.0020.0002] # GLAGOLITIC SMALL LETTER IZHITSA +2C2B ; [.2276.0020.0008] # GLAGOLITIC CAPITAL LETTER IZHITSA +2C5C ; [.2277.0020.0002] # GLAGOLITIC SMALL LETTER SHTAPIC +2C2C ; [.2277.0020.0008] # GLAGOLITIC CAPITAL LETTER SHTAPIC +2C5D ; [.2278.0020.0002] # GLAGOLITIC SMALL LETTER TROKUTASTI A +2C2D ; [.2278.0020.0008] # GLAGOLITIC CAPITAL LETTER TROKUTASTI A +2C5E ; [.2279.0020.0002] # GLAGOLITIC SMALL LETTER LATINATE MYSLITE +2C2E ; [.2279.0020.0008] # GLAGOLITIC CAPITAL LETTER LATINATE MYSLITE +10350 ; [.227A.0020.0002] # OLD PERMIC LETTER AN +10376 ; [.227A.0020.0004] # COMBINING OLD PERMIC LETTER AN +10351 ; [.227B.0020.0002] # OLD PERMIC LETTER BUR +10352 ; [.227C.0020.0002] # OLD PERMIC LETTER GAI +10353 ; [.227D.0020.0002] # OLD PERMIC LETTER DOI +10377 ; [.227D.0020.0004] # COMBINING OLD PERMIC LETTER DOI +10354 ; [.227E.0020.0002] # OLD PERMIC LETTER E +10355 ; [.227F.0020.0002] # OLD PERMIC LETTER ZHOI +10356 ; [.2280.0020.0002] # OLD PERMIC LETTER DZHOI +10357 ; [.2281.0020.0002] # OLD PERMIC LETTER ZATA +10378 ; [.2281.0020.0004] # COMBINING OLD PERMIC LETTER ZATA +10358 ; [.2282.0020.0002] # OLD PERMIC LETTER DZITA +10359 ; [.2283.0020.0002] # OLD PERMIC LETTER I +1035A ; [.2284.0020.0002] # OLD PERMIC LETTER KOKE +1035B ; [.2285.0020.0002] # OLD PERMIC LETTER LEI +1035C ; [.2286.0020.0002] # OLD PERMIC LETTER MENOE +1035D ; [.2287.0020.0002] # OLD PERMIC LETTER NENOE +10379 ; [.2287.0020.0004] # COMBINING OLD PERMIC LETTER NENOE +1035E ; [.2288.0020.0002] # OLD PERMIC LETTER VOOI +1035F ; [.2289.0020.0002] # OLD PERMIC LETTER PEEI +10360 ; [.228A.0020.0002] # OLD PERMIC LETTER REI +10361 ; [.228B.0020.0002] # OLD PERMIC LETTER SII +1037A ; [.228B.0020.0004] # COMBINING OLD PERMIC LETTER SII +10362 ; [.228C.0020.0002] # OLD PERMIC LETTER TAI +10363 ; [.228D.0020.0002] # OLD PERMIC LETTER U +10364 ; [.228E.0020.0002] # OLD PERMIC LETTER CHERY +10365 ; [.228F.0020.0002] # OLD PERMIC LETTER SHOOI +10366 ; [.2290.0020.0002] # OLD PERMIC LETTER SHCHOOI +10367 ; [.2291.0020.0002] # OLD PERMIC LETTER YRY +10368 ; [.2292.0020.0002] # OLD PERMIC LETTER YERU +10369 ; [.2293.0020.0002] # OLD PERMIC LETTER O +1036A ; [.2294.0020.0002] # OLD PERMIC LETTER OO +1036B ; [.2295.0020.0002] # OLD PERMIC LETTER EF +1036C ; [.2296.0020.0002] # OLD PERMIC LETTER HA +1036D ; [.2297.0020.0002] # OLD PERMIC LETTER TSIU +1036E ; [.2298.0020.0002] # OLD PERMIC LETTER VER +1036F ; [.2299.0020.0002] # OLD PERMIC LETTER YER +10370 ; [.229A.0020.0002] # OLD PERMIC LETTER YERI +10371 ; [.229B.0020.0002] # OLD PERMIC LETTER YAT +10372 ; [.229C.0020.0002] # OLD PERMIC LETTER IE +10373 ; [.229D.0020.0002] # OLD PERMIC LETTER YU +10374 ; [.229E.0020.0002] # OLD PERMIC LETTER YA +10375 ; [.229F.0020.0002] # OLD PERMIC LETTER IA +10D0 ; [.22A0.0020.0002] # GEORGIAN LETTER AN +2D00 ; [.22A1.0020.0002] # GEORGIAN SMALL LETTER AN +10A0 ; [.22A1.0020.0008] # GEORGIAN CAPITAL LETTER AN +10D1 ; [.22A2.0020.0002] # GEORGIAN LETTER BAN +2D01 ; [.22A3.0020.0002] # GEORGIAN SMALL LETTER BAN +10A1 ; [.22A3.0020.0008] # GEORGIAN CAPITAL LETTER BAN +10D2 ; [.22A4.0020.0002] # GEORGIAN LETTER GAN +2D02 ; [.22A5.0020.0002] # GEORGIAN SMALL LETTER GAN +10A2 ; [.22A5.0020.0008] # GEORGIAN CAPITAL LETTER GAN +10D3 ; [.22A6.0020.0002] # GEORGIAN LETTER DON +2D03 ; [.22A7.0020.0002] # GEORGIAN SMALL LETTER DON +10A3 ; [.22A7.0020.0008] # GEORGIAN CAPITAL LETTER DON +10D4 ; [.22A8.0020.0002] # GEORGIAN LETTER EN +2D04 ; [.22A9.0020.0002] # GEORGIAN SMALL LETTER EN +10A4 ; [.22A9.0020.0008] # GEORGIAN CAPITAL LETTER EN +10D5 ; [.22AA.0020.0002] # GEORGIAN LETTER VIN +2D05 ; [.22AB.0020.0002] # GEORGIAN SMALL LETTER VIN +10A5 ; [.22AB.0020.0008] # GEORGIAN CAPITAL LETTER VIN +10D6 ; [.22AC.0020.0002] # GEORGIAN LETTER ZEN +2D06 ; [.22AD.0020.0002] # GEORGIAN SMALL LETTER ZEN +10A6 ; [.22AD.0020.0008] # GEORGIAN CAPITAL LETTER ZEN +10F1 ; [.22AE.0020.0002] # GEORGIAN LETTER HE +2D21 ; [.22AF.0020.0002] # GEORGIAN SMALL LETTER HE +10C1 ; [.22AF.0020.0008] # GEORGIAN CAPITAL LETTER HE +10D7 ; [.22B0.0020.0002] # GEORGIAN LETTER TAN +2D07 ; [.22B1.0020.0002] # GEORGIAN SMALL LETTER TAN +10A7 ; [.22B1.0020.0008] # GEORGIAN CAPITAL LETTER TAN +10D8 ; [.22B2.0020.0002] # GEORGIAN LETTER IN +2D08 ; [.22B3.0020.0002] # GEORGIAN SMALL LETTER IN +10A8 ; [.22B3.0020.0008] # GEORGIAN CAPITAL LETTER IN +10D9 ; [.22B4.0020.0002] # GEORGIAN LETTER KAN +2D09 ; [.22B5.0020.0002] # GEORGIAN SMALL LETTER KAN +10A9 ; [.22B5.0020.0008] # GEORGIAN CAPITAL LETTER KAN +10DA ; [.22B6.0020.0002] # GEORGIAN LETTER LAS +2D0A ; [.22B7.0020.0002] # GEORGIAN SMALL LETTER LAS +10AA ; [.22B7.0020.0008] # GEORGIAN CAPITAL LETTER LAS +10DB ; [.22B8.0020.0002] # GEORGIAN LETTER MAN +2D0B ; [.22B9.0020.0002] # GEORGIAN SMALL LETTER MAN +10AB ; [.22B9.0020.0008] # GEORGIAN CAPITAL LETTER MAN +10DC ; [.22BA.0020.0002] # GEORGIAN LETTER NAR +10FC ; [.22BA.0020.0014] # MODIFIER LETTER GEORGIAN NAR +2D0C ; [.22BB.0020.0002] # GEORGIAN SMALL LETTER NAR +10AC ; [.22BB.0020.0008] # GEORGIAN CAPITAL LETTER NAR +10F2 ; [.22BC.0020.0002] # GEORGIAN LETTER HIE +2D22 ; [.22BD.0020.0002] # GEORGIAN SMALL LETTER HIE +10C2 ; [.22BD.0020.0008] # GEORGIAN CAPITAL LETTER HIE +10DD ; [.22BE.0020.0002] # GEORGIAN LETTER ON +2D0D ; [.22BF.0020.0002] # GEORGIAN SMALL LETTER ON +10AD ; [.22BF.0020.0008] # GEORGIAN CAPITAL LETTER ON +10DE ; [.22C0.0020.0002] # GEORGIAN LETTER PAR +2D0E ; [.22C1.0020.0002] # GEORGIAN SMALL LETTER PAR +10AE ; [.22C1.0020.0008] # GEORGIAN CAPITAL LETTER PAR +10DF ; [.22C2.0020.0002] # GEORGIAN LETTER ZHAR +2D0F ; [.22C3.0020.0002] # GEORGIAN SMALL LETTER ZHAR +10AF ; [.22C3.0020.0008] # GEORGIAN CAPITAL LETTER ZHAR +10E0 ; [.22C4.0020.0002] # GEORGIAN LETTER RAE +2D10 ; [.22C5.0020.0002] # GEORGIAN SMALL LETTER RAE +10B0 ; [.22C5.0020.0008] # GEORGIAN CAPITAL LETTER RAE +10E1 ; [.22C6.0020.0002] # GEORGIAN LETTER SAN +2D11 ; [.22C7.0020.0002] # GEORGIAN SMALL LETTER SAN +10B1 ; [.22C7.0020.0008] # GEORGIAN CAPITAL LETTER SAN +10E2 ; [.22C8.0020.0002] # GEORGIAN LETTER TAR +2D12 ; [.22C9.0020.0002] # GEORGIAN SMALL LETTER TAR +10B2 ; [.22C9.0020.0008] # GEORGIAN CAPITAL LETTER TAR +10F3 ; [.22CA.0020.0002] # GEORGIAN LETTER WE +2D23 ; [.22CB.0020.0002] # GEORGIAN SMALL LETTER WE +10C3 ; [.22CB.0020.0008] # GEORGIAN CAPITAL LETTER WE +10E3 ; [.22CC.0020.0002] # GEORGIAN LETTER UN +2D13 ; [.22CD.0020.0002] # GEORGIAN SMALL LETTER UN +10B3 ; [.22CD.0020.0008] # GEORGIAN CAPITAL LETTER UN +10E4 ; [.22CE.0020.0002] # GEORGIAN LETTER PHAR +2D14 ; [.22CF.0020.0002] # GEORGIAN SMALL LETTER PHAR +10B4 ; [.22CF.0020.0008] # GEORGIAN CAPITAL LETTER PHAR +10E5 ; [.22D0.0020.0002] # GEORGIAN LETTER KHAR +2D15 ; [.22D1.0020.0002] # GEORGIAN SMALL LETTER KHAR +10B5 ; [.22D1.0020.0008] # GEORGIAN CAPITAL LETTER KHAR +10E6 ; [.22D2.0020.0002] # GEORGIAN LETTER GHAN +2D16 ; [.22D3.0020.0002] # GEORGIAN SMALL LETTER GHAN +10B6 ; [.22D3.0020.0008] # GEORGIAN CAPITAL LETTER GHAN +10E7 ; [.22D4.0020.0002] # GEORGIAN LETTER QAR +2D17 ; [.22D5.0020.0002] # GEORGIAN SMALL LETTER QAR +10B7 ; [.22D5.0020.0008] # GEORGIAN CAPITAL LETTER QAR +10E8 ; [.22D6.0020.0002] # GEORGIAN LETTER SHIN +2D18 ; [.22D7.0020.0002] # GEORGIAN SMALL LETTER SHIN +10B8 ; [.22D7.0020.0008] # GEORGIAN CAPITAL LETTER SHIN +10E9 ; [.22D8.0020.0002] # GEORGIAN LETTER CHIN +2D19 ; [.22D9.0020.0002] # GEORGIAN SMALL LETTER CHIN +10B9 ; [.22D9.0020.0008] # GEORGIAN CAPITAL LETTER CHIN +10EA ; [.22DA.0020.0002] # GEORGIAN LETTER CAN +2D1A ; [.22DB.0020.0002] # GEORGIAN SMALL LETTER CAN +10BA ; [.22DB.0020.0008] # GEORGIAN CAPITAL LETTER CAN +10EB ; [.22DC.0020.0002] # GEORGIAN LETTER JIL +2D1B ; [.22DD.0020.0002] # GEORGIAN SMALL LETTER JIL +10BB ; [.22DD.0020.0008] # GEORGIAN CAPITAL LETTER JIL +10EC ; [.22DE.0020.0002] # GEORGIAN LETTER CIL +2D1C ; [.22DF.0020.0002] # GEORGIAN SMALL LETTER CIL +10BC ; [.22DF.0020.0008] # GEORGIAN CAPITAL LETTER CIL +10ED ; [.22E0.0020.0002] # GEORGIAN LETTER CHAR +2D1D ; [.22E1.0020.0002] # GEORGIAN SMALL LETTER CHAR +10BD ; [.22E1.0020.0008] # GEORGIAN CAPITAL LETTER CHAR +10EE ; [.22E2.0020.0002] # GEORGIAN LETTER XAN +2D1E ; [.22E3.0020.0002] # GEORGIAN SMALL LETTER XAN +10BE ; [.22E3.0020.0008] # GEORGIAN CAPITAL LETTER XAN +10F4 ; [.22E4.0020.0002] # GEORGIAN LETTER HAR +2D24 ; [.22E5.0020.0002] # GEORGIAN SMALL LETTER HAR +10C4 ; [.22E5.0020.0008] # GEORGIAN CAPITAL LETTER HAR +10EF ; [.22E6.0020.0002] # GEORGIAN LETTER JHAN +2D1F ; [.22E7.0020.0002] # GEORGIAN SMALL LETTER JHAN +10BF ; [.22E7.0020.0008] # GEORGIAN CAPITAL LETTER JHAN +10F0 ; [.22E8.0020.0002] # GEORGIAN LETTER HAE +2D20 ; [.22E9.0020.0002] # GEORGIAN SMALL LETTER HAE +10C0 ; [.22E9.0020.0008] # GEORGIAN CAPITAL LETTER HAE +10F5 ; [.22EA.0020.0002] # GEORGIAN LETTER HOE +2D25 ; [.22EB.0020.0002] # GEORGIAN SMALL LETTER HOE +10C5 ; [.22EB.0020.0008] # GEORGIAN CAPITAL LETTER HOE +10F6 ; [.22EC.0020.0002] # GEORGIAN LETTER FI +10F7 ; [.22ED.0020.0002] # GEORGIAN LETTER YN +2D27 ; [.22EE.0020.0002] # GEORGIAN SMALL LETTER YN +10C7 ; [.22EE.0020.0008] # GEORGIAN CAPITAL LETTER YN +10F8 ; [.22EF.0020.0002] # GEORGIAN LETTER ELIFI +10F9 ; [.22F0.0020.0002] # GEORGIAN LETTER TURNED GAN +10FA ; [.22F1.0020.0002] # GEORGIAN LETTER AIN +10FD ; [.22F2.0020.0002] # GEORGIAN LETTER AEN +2D2D ; [.22F3.0020.0002] # GEORGIAN SMALL LETTER AEN +10CD ; [.22F3.0020.0008] # GEORGIAN CAPITAL LETTER AEN +10FE ; [.22F4.0020.0002] # GEORGIAN LETTER HARD SIGN +10FF ; [.22F5.0020.0002] # GEORGIAN LETTER LABIAL SIGN +0561 ; [.22F6.0020.0002] # ARMENIAN SMALL LETTER AYB +0531 ; [.22F6.0020.0008] # ARMENIAN CAPITAL LETTER AYB +0562 ; [.22F7.0020.0002] # ARMENIAN SMALL LETTER BEN +0532 ; [.22F7.0020.0008] # ARMENIAN CAPITAL LETTER BEN +0563 ; [.22F8.0020.0002] # ARMENIAN SMALL LETTER GIM +0533 ; [.22F8.0020.0008] # ARMENIAN CAPITAL LETTER GIM +0564 ; [.22F9.0020.0002] # ARMENIAN SMALL LETTER DA +0534 ; [.22F9.0020.0008] # ARMENIAN CAPITAL LETTER DA +0565 ; [.22FA.0020.0002] # ARMENIAN SMALL LETTER ECH +0535 ; [.22FA.0020.0008] # ARMENIAN CAPITAL LETTER ECH +0587 ; [.22FA.0020.0004][.2317.0020.0004] # ARMENIAN SMALL LIGATURE ECH YIWN +0566 ; [.22FB.0020.0002] # ARMENIAN SMALL LETTER ZA +0536 ; [.22FB.0020.0008] # ARMENIAN CAPITAL LETTER ZA +0567 ; [.22FC.0020.0002] # ARMENIAN SMALL LETTER EH +0537 ; [.22FC.0020.0008] # ARMENIAN CAPITAL LETTER EH +0568 ; [.22FD.0020.0002] # ARMENIAN SMALL LETTER ET +0538 ; [.22FD.0020.0008] # ARMENIAN CAPITAL LETTER ET +0569 ; [.22FE.0020.0002] # ARMENIAN SMALL LETTER TO +0539 ; [.22FE.0020.0008] # ARMENIAN CAPITAL LETTER TO +056A ; [.22FF.0020.0002] # ARMENIAN SMALL LETTER ZHE +053A ; [.22FF.0020.0008] # ARMENIAN CAPITAL LETTER ZHE +056B ; [.2300.0020.0002] # ARMENIAN SMALL LETTER INI +053B ; [.2300.0020.0008] # ARMENIAN CAPITAL LETTER INI +056C ; [.2301.0020.0002] # ARMENIAN SMALL LETTER LIWN +053C ; [.2301.0020.0008] # ARMENIAN CAPITAL LETTER LIWN +056D ; [.2302.0020.0002] # ARMENIAN SMALL LETTER XEH +053D ; [.2302.0020.0008] # ARMENIAN CAPITAL LETTER XEH +056E ; [.2303.0020.0002] # ARMENIAN SMALL LETTER CA +053E ; [.2303.0020.0008] # ARMENIAN CAPITAL LETTER CA +056F ; [.2304.0020.0002] # ARMENIAN SMALL LETTER KEN +053F ; [.2304.0020.0008] # ARMENIAN CAPITAL LETTER KEN +0570 ; [.2305.0020.0002] # ARMENIAN SMALL LETTER HO +0540 ; [.2305.0020.0008] # ARMENIAN CAPITAL LETTER HO +0571 ; [.2306.0020.0002] # ARMENIAN SMALL LETTER JA +0541 ; [.2306.0020.0008] # ARMENIAN CAPITAL LETTER JA +0572 ; [.2307.0020.0002] # ARMENIAN SMALL LETTER GHAD +0542 ; [.2307.0020.0008] # ARMENIAN CAPITAL LETTER GHAD +0573 ; [.2308.0020.0002] # ARMENIAN SMALL LETTER CHEH +0543 ; [.2308.0020.0008] # ARMENIAN CAPITAL LETTER CHEH +0574 ; [.2309.0020.0002] # ARMENIAN SMALL LETTER MEN +0544 ; [.2309.0020.0008] # ARMENIAN CAPITAL LETTER MEN +FB14 ; [.2309.0020.0004][.22FA.0020.0004] # ARMENIAN SMALL LIGATURE MEN ECH +FB15 ; [.2309.0020.0004][.2300.0020.0004] # ARMENIAN SMALL LIGATURE MEN INI +FB17 ; [.2309.0020.0004][.2302.0020.0004] # ARMENIAN SMALL LIGATURE MEN XEH +FB13 ; [.2309.0020.0004][.230B.0020.0004] # ARMENIAN SMALL LIGATURE MEN NOW +0575 ; [.230A.0020.0002] # ARMENIAN SMALL LETTER YI +0545 ; [.230A.0020.0008] # ARMENIAN CAPITAL LETTER YI +0576 ; [.230B.0020.0002] # ARMENIAN SMALL LETTER NOW +0546 ; [.230B.0020.0008] # ARMENIAN CAPITAL LETTER NOW +0577 ; [.230C.0020.0002] # ARMENIAN SMALL LETTER SHA +0547 ; [.230C.0020.0008] # ARMENIAN CAPITAL LETTER SHA +0578 ; [.230D.0020.0002] # ARMENIAN SMALL LETTER VO +0548 ; [.230D.0020.0008] # ARMENIAN CAPITAL LETTER VO +0579 ; [.230E.0020.0002] # ARMENIAN SMALL LETTER CHA +0549 ; [.230E.0020.0008] # ARMENIAN CAPITAL LETTER CHA +057A ; [.230F.0020.0002] # ARMENIAN SMALL LETTER PEH +054A ; [.230F.0020.0008] # ARMENIAN CAPITAL LETTER PEH +057B ; [.2310.0020.0002] # ARMENIAN SMALL LETTER JHEH +054B ; [.2310.0020.0008] # ARMENIAN CAPITAL LETTER JHEH +057C ; [.2311.0020.0002] # ARMENIAN SMALL LETTER RA +054C ; [.2311.0020.0008] # ARMENIAN CAPITAL LETTER RA +057D ; [.2312.0020.0002] # ARMENIAN SMALL LETTER SEH +054D ; [.2312.0020.0008] # ARMENIAN CAPITAL LETTER SEH +057E ; [.2313.0020.0002] # ARMENIAN SMALL LETTER VEW +054E ; [.2313.0020.0008] # ARMENIAN CAPITAL LETTER VEW +FB16 ; [.2313.0020.0004][.230B.0020.0004] # ARMENIAN SMALL LIGATURE VEW NOW +057F ; [.2314.0020.0002] # ARMENIAN SMALL LETTER TIWN +054F ; [.2314.0020.0008] # ARMENIAN CAPITAL LETTER TIWN +0580 ; [.2315.0020.0002] # ARMENIAN SMALL LETTER REH +0550 ; [.2315.0020.0008] # ARMENIAN CAPITAL LETTER REH +0581 ; [.2316.0020.0002] # ARMENIAN SMALL LETTER CO +0551 ; [.2316.0020.0008] # ARMENIAN CAPITAL LETTER CO +0582 ; [.2317.0020.0002] # ARMENIAN SMALL LETTER YIWN +0552 ; [.2317.0020.0008] # ARMENIAN CAPITAL LETTER YIWN +0583 ; [.2318.0020.0002] # ARMENIAN SMALL LETTER PIWR +0553 ; [.2318.0020.0008] # ARMENIAN CAPITAL LETTER PIWR +0584 ; [.2319.0020.0002] # ARMENIAN SMALL LETTER KEH +0554 ; [.2319.0020.0008] # ARMENIAN CAPITAL LETTER KEH +0585 ; [.231A.0020.0002] # ARMENIAN SMALL LETTER OH +0555 ; [.231A.0020.0008] # ARMENIAN CAPITAL LETTER OH +0586 ; [.231B.0020.0002] # ARMENIAN SMALL LETTER FEH +0556 ; [.231B.0020.0008] # ARMENIAN CAPITAL LETTER FEH +0559 ; [.231C.0020.0002] # ARMENIAN MODIFIER LETTER LEFT HALF RING +05D0 ; [.231D.0020.0002] # HEBREW LETTER ALEF +2135 ; [.231D.0020.0004] # ALEF SYMBOL +FB21 ; [.231D.0020.0005] # HEBREW LETTER WIDE ALEF +FB2E ; [.231D.0020.0002][.0000.0059.0002] # HEBREW LETTER ALEF WITH PATAH +FB2F ; [.231D.0020.0002][.0000.005A.0002] # HEBREW LETTER ALEF WITH QAMATS +FB30 ; [.231D.0020.0002][.0000.005F.0002] # HEBREW LETTER ALEF WITH MAPIQ +FB4F ; [.231D.0020.0004][.2328.0020.0004] # HEBREW LIGATURE ALEF LAMED +05D1 ; [.231E.0020.0002] # HEBREW LETTER BET +2136 ; [.231E.0020.0004] # BET SYMBOL +FB31 ; [.231E.0020.0002][.0000.005F.0002] # HEBREW LETTER BET WITH DAGESH +FB4C ; [.231E.0020.0002][.0000.0060.0002] # HEBREW LETTER BET WITH RAFE +05D2 ; [.231F.0020.0002] # HEBREW LETTER GIMEL +2137 ; [.231F.0020.0004] # GIMEL SYMBOL +FB32 ; [.231F.0020.0002][.0000.005F.0002] # HEBREW LETTER GIMEL WITH DAGESH +05D3 ; [.2320.0020.0002] # HEBREW LETTER DALET +2138 ; [.2320.0020.0004] # DALET SYMBOL +FB22 ; [.2320.0020.0005] # HEBREW LETTER WIDE DALET +FB33 ; [.2320.0020.0002][.0000.005F.0002] # HEBREW LETTER DALET WITH DAGESH +05D4 ; [.2321.0020.0002] # HEBREW LETTER HE +FB23 ; [.2321.0020.0005] # HEBREW LETTER WIDE HE +FB34 ; [.2321.0020.0002][.0000.005F.0002] # HEBREW LETTER HE WITH MAPIQ +05D5 ; [.2322.0020.0002] # HEBREW LETTER VAV +FB4B ; [.2322.0020.0002][.0000.005B.0002] # HEBREW LETTER VAV WITH HOLAM +FB35 ; [.2322.0020.0002][.0000.005F.0002] # HEBREW LETTER VAV WITH DAGESH +05F0 ; [.2322.0020.0004][.2322.0020.0004] # HEBREW LIGATURE YIDDISH DOUBLE VAV +05F1 ; [.2322.0020.0004][.2326.0020.0004] # HEBREW LIGATURE YIDDISH VAV YOD +05D6 ; [.2323.0020.0002] # HEBREW LETTER ZAYIN +FB36 ; [.2323.0020.0002][.0000.005F.0002] # HEBREW LETTER ZAYIN WITH DAGESH +05D7 ; [.2324.0020.0002] # HEBREW LETTER HET +05D8 ; [.2325.0020.0002] # HEBREW LETTER TET +FB38 ; [.2325.0020.0002][.0000.005F.0002] # HEBREW LETTER TET WITH DAGESH +05D9 ; [.2326.0020.0002] # HEBREW LETTER YOD +FB1D ; [.2326.0020.0002][.0000.0056.0002] # HEBREW LETTER YOD WITH HIRIQ +FB39 ; [.2326.0020.0002][.0000.005F.0002] # HEBREW LETTER YOD WITH DAGESH +05F2 ; [.2326.0020.0004][.2326.0020.0004] # HEBREW LIGATURE YIDDISH DOUBLE YOD +FB1F ; [.2326.0020.0004][.2326.0020.0004][.0000.0059.0002] # HEBREW LIGATURE YIDDISH YOD YOD PATAH +05DB ; [.2327.0020.0002] # HEBREW LETTER KAF +FB24 ; [.2327.0020.0005] # HEBREW LETTER WIDE KAF +05DA ; [.2327.0020.0019] # HEBREW LETTER FINAL KAF +FB3B ; [.2327.0020.0002][.0000.005F.0002] # HEBREW LETTER KAF WITH DAGESH +FB3A ; [.2327.0020.0019][.0000.005F.0002] # HEBREW LETTER FINAL KAF WITH DAGESH +FB4D ; [.2327.0020.0002][.0000.0060.0002] # HEBREW LETTER KAF WITH RAFE +05DC ; [.2328.0020.0002] # HEBREW LETTER LAMED +FB25 ; [.2328.0020.0005] # HEBREW LETTER WIDE LAMED +FB3C ; [.2328.0020.0002][.0000.005F.0002] # HEBREW LETTER LAMED WITH DAGESH +05DE ; [.2329.0020.0002] # HEBREW LETTER MEM +FB26 ; [.2329.0020.0005] # HEBREW LETTER WIDE FINAL MEM +05DD ; [.2329.0020.0019] # HEBREW LETTER FINAL MEM +FB3E ; [.2329.0020.0002][.0000.005F.0002] # HEBREW LETTER MEM WITH DAGESH +05E0 ; [.232A.0020.0002] # HEBREW LETTER NUN +05DF ; [.232A.0020.0019] # HEBREW LETTER FINAL NUN +FB40 ; [.232A.0020.0002][.0000.005F.0002] # HEBREW LETTER NUN WITH DAGESH +05E1 ; [.232B.0020.0002] # HEBREW LETTER SAMEKH +FB41 ; [.232B.0020.0002][.0000.005F.0002] # HEBREW LETTER SAMEKH WITH DAGESH +05E2 ; [.232C.0020.0002] # HEBREW LETTER AYIN +FB20 ; [.232C.0020.0005] # HEBREW LETTER ALTERNATIVE AYIN +05E4 ; [.232D.0020.0002] # HEBREW LETTER PE +05E3 ; [.232D.0020.0019] # HEBREW LETTER FINAL PE +FB44 ; [.232D.0020.0002][.0000.005F.0002] # HEBREW LETTER PE WITH DAGESH +FB43 ; [.232D.0020.0019][.0000.005F.0002] # HEBREW LETTER FINAL PE WITH DAGESH +FB4E ; [.232D.0020.0002][.0000.0060.0002] # HEBREW LETTER PE WITH RAFE +05E6 ; [.232E.0020.0002] # HEBREW LETTER TSADI +05E5 ; [.232E.0020.0019] # HEBREW LETTER FINAL TSADI +FB46 ; [.232E.0020.0002][.0000.005F.0002] # HEBREW LETTER TSADI WITH DAGESH +05E7 ; [.232F.0020.0002] # HEBREW LETTER QOF +FB47 ; [.232F.0020.0002][.0000.005F.0002] # HEBREW LETTER QOF WITH DAGESH +05E8 ; [.2330.0020.0002] # HEBREW LETTER RESH +FB27 ; [.2330.0020.0005] # HEBREW LETTER WIDE RESH +FB48 ; [.2330.0020.0002][.0000.005F.0002] # HEBREW LETTER RESH WITH DAGESH +05E9 ; [.2331.0020.0002] # HEBREW LETTER SHIN +FB2B ; [.2331.0020.0002][.0000.005D.0002] # HEBREW LETTER SHIN WITH SIN DOT +FB2A ; [.2331.0020.0002][.0000.005E.0002] # HEBREW LETTER SHIN WITH SHIN DOT +FB49 ; [.2331.0020.0002][.0000.005F.0002] # HEBREW LETTER SHIN WITH DAGESH +FB2D ; [.2331.0020.0002][.0000.005F.0002][.0000.005D.0002] # HEBREW LETTER SHIN WITH DAGESH AND SIN DOT +FB2C ; [.2331.0020.0002][.0000.005F.0002][.0000.005E.0002] # HEBREW LETTER SHIN WITH DAGESH AND SHIN DOT +05EA ; [.2332.0020.0002] # HEBREW LETTER TAV +FB28 ; [.2332.0020.0005] # HEBREW LETTER WIDE TAV +FB4A ; [.2332.0020.0002][.0000.005F.0002] # HEBREW LETTER TAV WITH DAGESH +10900 ; [.2333.0020.0002] # PHOENICIAN LETTER ALF +10901 ; [.2334.0020.0002] # PHOENICIAN LETTER BET +10902 ; [.2335.0020.0002] # PHOENICIAN LETTER GAML +10903 ; [.2336.0020.0002] # PHOENICIAN LETTER DELT +10904 ; [.2337.0020.0002] # PHOENICIAN LETTER HE +10905 ; [.2338.0020.0002] # PHOENICIAN LETTER WAU +10906 ; [.2339.0020.0002] # PHOENICIAN LETTER ZAI +10907 ; [.233A.0020.0002] # PHOENICIAN LETTER HET +10908 ; [.233B.0020.0002] # PHOENICIAN LETTER TET +10909 ; [.233C.0020.0002] # PHOENICIAN LETTER YOD +1090A ; [.233D.0020.0002] # PHOENICIAN LETTER KAF +1090B ; [.233E.0020.0002] # PHOENICIAN LETTER LAMD +1090C ; [.233F.0020.0002] # PHOENICIAN LETTER MEM +1090D ; [.2340.0020.0002] # PHOENICIAN LETTER NUN +1090E ; [.2341.0020.0002] # PHOENICIAN LETTER SEMK +1090F ; [.2342.0020.0002] # PHOENICIAN LETTER AIN +10910 ; [.2343.0020.0002] # PHOENICIAN LETTER PE +10911 ; [.2344.0020.0002] # PHOENICIAN LETTER SADE +10912 ; [.2345.0020.0002] # PHOENICIAN LETTER QOF +10913 ; [.2346.0020.0002] # PHOENICIAN LETTER ROSH +10914 ; [.2347.0020.0002] # PHOENICIAN LETTER SHIN +10915 ; [.2348.0020.0002] # PHOENICIAN LETTER TAU +0800 ; [.2349.0020.0002] # SAMARITAN LETTER ALAF +0801 ; [.234A.0020.0002] # SAMARITAN LETTER BIT +0802 ; [.234B.0020.0002] # SAMARITAN LETTER GAMAN +0803 ; [.234C.0020.0002] # SAMARITAN LETTER DALAT +0804 ; [.234D.0020.0002] # SAMARITAN LETTER IY +0805 ; [.234E.0020.0002] # SAMARITAN LETTER BAA +0806 ; [.234F.0020.0002] # SAMARITAN LETTER ZEN +0807 ; [.2350.0020.0002] # SAMARITAN LETTER IT +0808 ; [.2351.0020.0002] # SAMARITAN LETTER TIT +0809 ; [.2352.0020.0002] # SAMARITAN LETTER YUT +080A ; [.2353.0020.0002] # SAMARITAN LETTER KAAF +080B ; [.2354.0020.0002] # SAMARITAN LETTER LABAT +080C ; [.2355.0020.0002] # SAMARITAN LETTER MIM +080D ; [.2356.0020.0002] # SAMARITAN LETTER NUN +080E ; [.2357.0020.0002] # SAMARITAN LETTER SINGAAT +080F ; [.2358.0020.0002] # SAMARITAN LETTER IN +0810 ; [.2359.0020.0002] # SAMARITAN LETTER FI +0811 ; [.235A.0020.0002] # SAMARITAN LETTER TSAADIY +0812 ; [.235B.0020.0002] # SAMARITAN LETTER QUF +0813 ; [.235C.0020.0002] # SAMARITAN LETTER RISH +0814 ; [.235D.0020.0002] # SAMARITAN LETTER SHAN +0815 ; [.235E.0020.0002] # SAMARITAN LETTER TAAF +0816 ; [.235F.0020.0002] # SAMARITAN MARK IN +0817 ; [.2360.0020.0002] # SAMARITAN MARK IN-ALAF +081A ; [.2361.0020.0002] # SAMARITAN MODIFIER LETTER EPENTHETIC YUT +081B ; [.2362.0020.0002] # SAMARITAN MARK EPENTHETIC YUT +0621 ; [.2363.0020.0002] # ARABIC LETTER HAMZA +0674 ; [.2363.0020.0004] # ARABIC LETTER HIGH HAMZA +FE80 ; [.2363.0020.001A] # ARABIC LETTER HAMZA ISOLATED FORM +06FD ; [.2363.0020.0004][.0000.0112.0004] # ARABIC SIGN SINDHI AMPERSAND +0622 ; [.2364.0020.0002] # ARABIC LETTER ALEF WITH MADDA ABOVE +0627 0653 ; [.2364.0020.0002] # ARABIC LETTER ALEF WITH MADDA ABOVE +FE82 ; [.2364.0020.0019] # ARABIC LETTER ALEF WITH MADDA ABOVE FINAL FORM +FE81 ; [.2364.0020.001A] # ARABIC LETTER ALEF WITH MADDA ABOVE ISOLATED FORM +0623 ; [.2365.0020.0002] # ARABIC LETTER ALEF WITH HAMZA ABOVE +0627 0654 ; [.2365.0020.0002] # ARABIC LETTER ALEF WITH HAMZA ABOVE +FE84 ; [.2365.0020.0019] # ARABIC LETTER ALEF WITH HAMZA ABOVE FINAL FORM +FE83 ; [.2365.0020.001A] # ARABIC LETTER ALEF WITH HAMZA ABOVE ISOLATED FORM +0672 ; [.2366.0020.0002] # ARABIC LETTER ALEF WITH WAVY HAMZA ABOVE +0671 ; [.2367.0020.0002] # ARABIC LETTER ALEF WASLA +FB51 ; [.2367.0020.0019] # ARABIC LETTER ALEF WASLA FINAL FORM +FB50 ; [.2367.0020.001A] # ARABIC LETTER ALEF WASLA ISOLATED FORM +0624 ; [.2368.0020.0002] # ARABIC LETTER WAW WITH HAMZA ABOVE +0648 0654 ; [.2368.0020.0002] # ARABIC LETTER WAW WITH HAMZA ABOVE +FE86 ; [.2368.0020.0019] # ARABIC LETTER WAW WITH HAMZA ABOVE FINAL FORM +FE85 ; [.2368.0020.001A] # ARABIC LETTER WAW WITH HAMZA ABOVE ISOLATED FORM +0625 ; [.2369.0020.0002] # ARABIC LETTER ALEF WITH HAMZA BELOW +0627 0655 ; [.2369.0020.0002] # ARABIC LETTER ALEF WITH HAMZA BELOW +FE88 ; [.2369.0020.0019] # ARABIC LETTER ALEF WITH HAMZA BELOW FINAL FORM +FE87 ; [.2369.0020.001A] # ARABIC LETTER ALEF WITH HAMZA BELOW ISOLATED FORM +0673 ; [.236A.0020.0002] # ARABIC LETTER ALEF WITH WAVY HAMZA BELOW +0773 ; [.236B.0020.0002] # ARABIC LETTER ALEF WITH EXTENDED ARABIC-INDIC DIGIT TWO ABOVE +0774 ; [.236C.0020.0002] # ARABIC LETTER ALEF WITH EXTENDED ARABIC-INDIC DIGIT THREE ABOVE +0626 ; [.236D.0020.0002] # ARABIC LETTER YEH WITH HAMZA ABOVE +064A 0654 ; [.236D.0020.0002] # ARABIC LETTER YEH WITH HAMZA ABOVE +FE8B ; [.236D.0020.0017] # ARABIC LETTER YEH WITH HAMZA ABOVE INITIAL FORM +FE8C ; [.236D.0020.0018] # ARABIC LETTER YEH WITH HAMZA ABOVE MEDIAL FORM +FE8A ; [.236D.0020.0019] # ARABIC LETTER YEH WITH HAMZA ABOVE FINAL FORM +FE89 ; [.236D.0020.001A] # ARABIC LETTER YEH WITH HAMZA ABOVE ISOLATED FORM +FBEB ; [.236D.0020.0019][.2371.0020.0019] # ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH ALEF FINAL FORM +FBEA ; [.236D.0020.001A][.2371.0020.001A] # ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH ALEF ISOLATED FORM +FC97 ; [.236D.0020.0017][.238B.0020.0017] # ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH JEEM INITIAL FORM +FC00 ; [.236D.0020.001A][.238B.0020.001A] # ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH JEEM ISOLATED FORM +FC98 ; [.236D.0020.0017][.2392.0020.0017] # ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH HAH INITIAL FORM +FC01 ; [.236D.0020.001A][.2392.0020.001A] # ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH HAH ISOLATED FORM +FC99 ; [.236D.0020.0017][.2393.0020.0017] # ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH KHAH INITIAL FORM +FC64 ; [.236D.0020.0019][.23AC.0020.0019] # ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH REH FINAL FORM +FC65 ; [.236D.0020.0019][.23AD.0020.0019] # ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH ZAIN FINAL FORM +FC9A ; [.236D.0020.0017][.2409.0020.0017] # ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH MEEM INITIAL FORM +FCDF ; [.236D.0020.0018][.2409.0020.0018] # ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH MEEM MEDIAL FORM +FC66 ; [.236D.0020.0019][.2409.0020.0019] # ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH MEEM FINAL FORM +FC02 ; [.236D.0020.001A][.2409.0020.001A] # ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH MEEM ISOLATED FORM +FC67 ; [.236D.0020.0019][.240D.0020.0019] # ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH NOON FINAL FORM +FC9B ; [.236D.0020.0017][.2417.0020.0017] # ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH HEH INITIAL FORM +FCE0 ; [.236D.0020.0018][.2417.0020.0018] # ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH HEH MEDIAL FORM +FBED ; [.236D.0020.0019][.241C.0020.0019] # ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH AE FINAL FORM +FBEC ; [.236D.0020.001A][.241C.0020.001A] # ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH AE ISOLATED FORM +FBEF ; [.236D.0020.0019][.241D.0020.0019] # ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH WAW FINAL FORM +FBEE ; [.236D.0020.001A][.241D.0020.001A] # ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH WAW ISOLATED FORM +FBF3 ; [.236D.0020.0019][.2420.0020.0019] # ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH OE FINAL FORM +FBF2 ; [.236D.0020.001A][.2420.0020.001A] # ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH OE ISOLATED FORM +FBF1 ; [.236D.0020.0019][.2421.0020.0019] # ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH U FINAL FORM +FBF0 ; [.236D.0020.001A][.2421.0020.001A] # ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH U ISOLATED FORM +FBF5 ; [.236D.0020.0019][.2422.0020.0019] # ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH YU FINAL FORM +FBF4 ; [.236D.0020.001A][.2422.0020.001A] # ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH YU ISOLATED FORM +FBFB ; [.236D.0020.0017][.242B.0020.0017] # ARABIC LIGATURE UIGHUR KIRGHIZ YEH WITH HAMZA ABOVE WITH ALEF MAKSURA INITIAL FORM +FBFA ; [.236D.0020.0019][.242B.0020.0019] # ARABIC LIGATURE UIGHUR KIRGHIZ YEH WITH HAMZA ABOVE WITH ALEF MAKSURA FINAL FORM +FC68 ; [.236D.0020.0019][.242B.0020.0019] # ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH ALEF MAKSURA FINAL FORM +FBF9 ; [.236D.0020.001A][.242B.0020.001A] # ARABIC LIGATURE UIGHUR KIRGHIZ YEH WITH HAMZA ABOVE WITH ALEF MAKSURA ISOLATED FORM +FC03 ; [.236D.0020.001A][.242B.0020.001A] # ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH ALEF MAKSURA ISOLATED FORM +FC69 ; [.236D.0020.0019][.242C.0020.0019] # ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH YEH FINAL FORM +FC04 ; [.236D.0020.001A][.242C.0020.001A] # ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH YEH ISOLATED FORM +FBF8 ; [.236D.0020.0017][.2430.0020.0017] # ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH E INITIAL FORM +FBF7 ; [.236D.0020.0019][.2430.0020.0019] # ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH E FINAL FORM +FBF6 ; [.236D.0020.001A][.2430.0020.001A] # ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH E ISOLATED FORM +08A8 ; [.236E.0020.0002] # ARABIC LETTER YEH WITH TWO DOTS BELOW AND HAMZA ABOVE +08A9 ; [.236F.0020.0002] # ARABIC LETTER YEH WITH TWO DOTS BELOW AND DOT ABOVE +08AC ; [.2370.0020.0002] # ARABIC LETTER ROHINGYA YEH +0627 ; [.2371.0020.0002] # ARABIC LETTER ALEF +08AD ; [.2371.0020.0004] # ARABIC LETTER LOW ALEF +1EE00 ; [.2371.0020.0005] # ARABIC MATHEMATICAL ALEF +1EE80 ; [.2371.0020.0005] # ARABIC MATHEMATICAL LOOPED ALEF +FE8E ; [.2371.0020.0019] # ARABIC LETTER ALEF FINAL FORM +FE8D ; [.2371.0020.001A] # ARABIC LETTER ALEF ISOLATED FORM +FD3C ; [.2371.0020.0019][.0000.006D.0019] # ARABIC LIGATURE ALEF WITH FATHATAN FINAL FORM +FD3D ; [.2371.0020.001A][.0000.006D.001A] # ARABIC LIGATURE ALEF WITH FATHATAN ISOLATED FORM +0675 ; [.2371.0020.0004][.2363.0020.0004] # ARABIC LETTER HIGH HAMZA ALEF +FDF3 ; [.2371.0020.001A][.23ED.0020.001A][.2373.0020.001A][.23AC.0020.001A] # ARABIC LIGATURE AKBAR ISOLATED FORM +FDF2 ; [.2371.0020.001A][.2402.0020.001A][.2402.0020.001A][.2417.0020.001A] # ARABIC LIGATURE ALLAH ISOLATED FORM +066E ; [.2372.0020.0002] # ARABIC LETTER DOTLESS BEH +1EE1C ; [.2372.0020.0005] # ARABIC MATHEMATICAL DOTLESS BEH +1EE7C ; [.2372.0020.0005] # ARABIC MATHEMATICAL STRETCHED DOTLESS BEH +0628 ; [.2373.0020.0002] # ARABIC LETTER BEH +1EE01 ; [.2373.0020.0005] # ARABIC MATHEMATICAL BEH +1EE21 ; [.2373.0020.0005] # ARABIC MATHEMATICAL INITIAL BEH +1EE61 ; [.2373.0020.0005] # ARABIC MATHEMATICAL STRETCHED BEH +1EE81 ; [.2373.0020.0005] # ARABIC MATHEMATICAL LOOPED BEH +1EEA1 ; [.2373.0020.0005] # ARABIC MATHEMATICAL DOUBLE-STRUCK BEH +FE91 ; [.2373.0020.0017] # ARABIC LETTER BEH INITIAL FORM +FE92 ; [.2373.0020.0018] # ARABIC LETTER BEH MEDIAL FORM +FE90 ; [.2373.0020.0019] # ARABIC LETTER BEH FINAL FORM +FE8F ; [.2373.0020.001A] # ARABIC LETTER BEH ISOLATED FORM +FC9C ; [.2373.0020.0017][.238B.0020.0017] # ARABIC LIGATURE BEH WITH JEEM INITIAL FORM +FC05 ; [.2373.0020.001A][.238B.0020.001A] # ARABIC LIGATURE BEH WITH JEEM ISOLATED FORM +FC9D ; [.2373.0020.0017][.2392.0020.0017] # ARABIC LIGATURE BEH WITH HAH INITIAL FORM +FC06 ; [.2373.0020.001A][.2392.0020.001A] # ARABIC LIGATURE BEH WITH HAH ISOLATED FORM +FDC2 ; [.2373.0020.0019][.2392.0020.0019][.242C.0020.0019] # ARABIC LIGATURE BEH WITH HAH WITH YEH FINAL FORM +FC9E ; [.2373.0020.0017][.2393.0020.0017] # ARABIC LIGATURE BEH WITH KHAH INITIAL FORM +FC07 ; [.2373.0020.001A][.2393.0020.001A] # ARABIC LIGATURE BEH WITH KHAH ISOLATED FORM +FD9E ; [.2373.0020.0019][.2393.0020.0019][.242C.0020.0019] # ARABIC LIGATURE BEH WITH KHAH WITH YEH FINAL FORM +FC6A ; [.2373.0020.0019][.23AC.0020.0019] # ARABIC LIGATURE BEH WITH REH FINAL FORM +FC6B ; [.2373.0020.0019][.23AD.0020.0019] # ARABIC LIGATURE BEH WITH ZAIN FINAL FORM +FC9F ; [.2373.0020.0017][.2409.0020.0017] # ARABIC LIGATURE BEH WITH MEEM INITIAL FORM +FCE1 ; [.2373.0020.0018][.2409.0020.0018] # ARABIC LIGATURE BEH WITH MEEM MEDIAL FORM +FC6C ; [.2373.0020.0019][.2409.0020.0019] # ARABIC LIGATURE BEH WITH MEEM FINAL FORM +FC08 ; [.2373.0020.001A][.2409.0020.001A] # ARABIC LIGATURE BEH WITH MEEM ISOLATED FORM +FC6D ; [.2373.0020.0019][.240D.0020.0019] # ARABIC LIGATURE BEH WITH NOON FINAL FORM +FCA0 ; [.2373.0020.0017][.2417.0020.0017] # ARABIC LIGATURE BEH WITH HEH INITIAL FORM +FCE2 ; [.2373.0020.0018][.2417.0020.0018] # ARABIC LIGATURE BEH WITH HEH MEDIAL FORM +FC6E ; [.2373.0020.0019][.242B.0020.0019] # ARABIC LIGATURE BEH WITH ALEF MAKSURA FINAL FORM +FC09 ; [.2373.0020.001A][.242B.0020.001A] # ARABIC LIGATURE BEH WITH ALEF MAKSURA ISOLATED FORM +FC6F ; [.2373.0020.0019][.242C.0020.0019] # ARABIC LIGATURE BEH WITH YEH FINAL FORM +FC0A ; [.2373.0020.001A][.242C.0020.001A] # ARABIC LIGATURE BEH WITH YEH ISOLATED FORM +067B ; [.2374.0020.0002] # ARABIC LETTER BEEH +FB54 ; [.2374.0020.0017] # ARABIC LETTER BEEH INITIAL FORM +FB55 ; [.2374.0020.0018] # ARABIC LETTER BEEH MEDIAL FORM +FB53 ; [.2374.0020.0019] # ARABIC LETTER BEEH FINAL FORM +FB52 ; [.2374.0020.001A] # ARABIC LETTER BEEH ISOLATED FORM +067E ; [.2375.0020.0002] # ARABIC LETTER PEH +FB58 ; [.2375.0020.0017] # ARABIC LETTER PEH INITIAL FORM +FB59 ; [.2375.0020.0018] # ARABIC LETTER PEH MEDIAL FORM +FB57 ; [.2375.0020.0019] # ARABIC LETTER PEH FINAL FORM +FB56 ; [.2375.0020.001A] # ARABIC LETTER PEH ISOLATED FORM +0680 ; [.2376.0020.0002] # ARABIC LETTER BEHEH +FB5C ; [.2376.0020.0017] # ARABIC LETTER BEHEH INITIAL FORM +FB5D ; [.2376.0020.0018] # ARABIC LETTER BEHEH MEDIAL FORM +FB5B ; [.2376.0020.0019] # ARABIC LETTER BEHEH FINAL FORM +FB5A ; [.2376.0020.001A] # ARABIC LETTER BEHEH ISOLATED FORM +0750 ; [.2377.0020.0002] # ARABIC LETTER BEH WITH THREE DOTS HORIZONTALLY BELOW +0751 ; [.2378.0020.0002] # ARABIC LETTER BEH WITH DOT BELOW AND THREE DOTS ABOVE +0752 ; [.2379.0020.0002] # ARABIC LETTER BEH WITH THREE DOTS POINTING UPWARDS BELOW +0753 ; [.237A.0020.0002] # ARABIC LETTER BEH WITH THREE DOTS POINTING UPWARDS BELOW AND TWO DOTS ABOVE +0754 ; [.237B.0020.0002] # ARABIC LETTER BEH WITH TWO DOTS BELOW AND DOT ABOVE +0755 ; [.237C.0020.0002] # ARABIC LETTER BEH WITH INVERTED SMALL V BELOW +08A0 ; [.237D.0020.0002] # ARABIC LETTER BEH WITH SMALL V BELOW +0756 ; [.237E.0020.0002] # ARABIC LETTER BEH WITH SMALL V +08A1 ; [.237F.0020.0002] # ARABIC LETTER BEH WITH HAMZA ABOVE +08B6 ; [.2380.0020.0002] # ARABIC LETTER BEH WITH SMALL MEEM ABOVE +08B7 ; [.2381.0020.0002] # ARABIC LETTER PEH WITH SMALL MEEM ABOVE +0629 ; [.2382.0020.0002] # ARABIC LETTER TEH MARBUTA +FE94 ; [.2382.0020.0019] # ARABIC LETTER TEH MARBUTA FINAL FORM +FE93 ; [.2382.0020.001A] # ARABIC LETTER TEH MARBUTA ISOLATED FORM +062A ; [.2383.0020.0002] # ARABIC LETTER TEH +1EE15 ; [.2383.0020.0005] # ARABIC MATHEMATICAL TEH +1EE35 ; [.2383.0020.0005] # ARABIC MATHEMATICAL INITIAL TEH +1EE75 ; [.2383.0020.0005] # ARABIC MATHEMATICAL STRETCHED TEH +1EE95 ; [.2383.0020.0005] # ARABIC MATHEMATICAL LOOPED TEH +1EEB5 ; [.2383.0020.0005] # ARABIC MATHEMATICAL DOUBLE-STRUCK TEH +FE97 ; [.2383.0020.0017] # ARABIC LETTER TEH INITIAL FORM +FE98 ; [.2383.0020.0018] # ARABIC LETTER TEH MEDIAL FORM +FE96 ; [.2383.0020.0019] # ARABIC LETTER TEH FINAL FORM +FE95 ; [.2383.0020.001A] # ARABIC LETTER TEH ISOLATED FORM +FCA1 ; [.2383.0020.0017][.238B.0020.0017] # ARABIC LIGATURE TEH WITH JEEM INITIAL FORM +FC0B ; [.2383.0020.001A][.238B.0020.001A] # ARABIC LIGATURE TEH WITH JEEM ISOLATED FORM +FD50 ; [.2383.0020.0017][.238B.0020.0017][.2409.0020.0017] # ARABIC LIGATURE TEH WITH JEEM WITH MEEM INITIAL FORM +FDA0 ; [.2383.0020.0019][.238B.0020.0019][.242B.0020.0019] # ARABIC LIGATURE TEH WITH JEEM WITH ALEF MAKSURA FINAL FORM +FD9F ; [.2383.0020.0019][.238B.0020.0019][.242C.0020.0019] # ARABIC LIGATURE TEH WITH JEEM WITH YEH FINAL FORM +FCA2 ; [.2383.0020.0017][.2392.0020.0017] # ARABIC LIGATURE TEH WITH HAH INITIAL FORM +FC0C ; [.2383.0020.001A][.2392.0020.001A] # ARABIC LIGATURE TEH WITH HAH ISOLATED FORM +FD52 ; [.2383.0020.0017][.2392.0020.0017][.238B.0020.0017] # ARABIC LIGATURE TEH WITH HAH WITH JEEM INITIAL FORM +FD51 ; [.2383.0020.0019][.2392.0020.0019][.238B.0020.0019] # ARABIC LIGATURE TEH WITH HAH WITH JEEM FINAL FORM +FD53 ; [.2383.0020.0017][.2392.0020.0017][.2409.0020.0017] # ARABIC LIGATURE TEH WITH HAH WITH MEEM INITIAL FORM +FCA3 ; [.2383.0020.0017][.2393.0020.0017] # ARABIC LIGATURE TEH WITH KHAH INITIAL FORM +FC0D ; [.2383.0020.001A][.2393.0020.001A] # ARABIC LIGATURE TEH WITH KHAH ISOLATED FORM +FD54 ; [.2383.0020.0017][.2393.0020.0017][.2409.0020.0017] # ARABIC LIGATURE TEH WITH KHAH WITH MEEM INITIAL FORM +FDA2 ; [.2383.0020.0019][.2393.0020.0019][.242B.0020.0019] # ARABIC LIGATURE TEH WITH KHAH WITH ALEF MAKSURA FINAL FORM +FDA1 ; [.2383.0020.0019][.2393.0020.0019][.242C.0020.0019] # ARABIC LIGATURE TEH WITH KHAH WITH YEH FINAL FORM +FC70 ; [.2383.0020.0019][.23AC.0020.0019] # ARABIC LIGATURE TEH WITH REH FINAL FORM +FC71 ; [.2383.0020.0019][.23AD.0020.0019] # ARABIC LIGATURE TEH WITH ZAIN FINAL FORM +FCA4 ; [.2383.0020.0017][.2409.0020.0017] # ARABIC LIGATURE TEH WITH MEEM INITIAL FORM +FCE3 ; [.2383.0020.0018][.2409.0020.0018] # ARABIC LIGATURE TEH WITH MEEM MEDIAL FORM +FC72 ; [.2383.0020.0019][.2409.0020.0019] # ARABIC LIGATURE TEH WITH MEEM FINAL FORM +FC0E ; [.2383.0020.001A][.2409.0020.001A] # ARABIC LIGATURE TEH WITH MEEM ISOLATED FORM +FD55 ; [.2383.0020.0017][.2409.0020.0017][.238B.0020.0017] # ARABIC LIGATURE TEH WITH MEEM WITH JEEM INITIAL FORM +FD56 ; [.2383.0020.0017][.2409.0020.0017][.2392.0020.0017] # ARABIC LIGATURE TEH WITH MEEM WITH HAH INITIAL FORM +FD57 ; [.2383.0020.0017][.2409.0020.0017][.2393.0020.0017] # ARABIC LIGATURE TEH WITH MEEM WITH KHAH INITIAL FORM +FDA4 ; [.2383.0020.0019][.2409.0020.0019][.242B.0020.0019] # ARABIC LIGATURE TEH WITH MEEM WITH ALEF MAKSURA FINAL FORM +FDA3 ; [.2383.0020.0019][.2409.0020.0019][.242C.0020.0019] # ARABIC LIGATURE TEH WITH MEEM WITH YEH FINAL FORM +FC73 ; [.2383.0020.0019][.240D.0020.0019] # ARABIC LIGATURE TEH WITH NOON FINAL FORM +FCA5 ; [.2383.0020.0017][.2417.0020.0017] # ARABIC LIGATURE TEH WITH HEH INITIAL FORM +FCE4 ; [.2383.0020.0018][.2417.0020.0018] # ARABIC LIGATURE TEH WITH HEH MEDIAL FORM +FC74 ; [.2383.0020.0019][.242B.0020.0019] # ARABIC LIGATURE TEH WITH ALEF MAKSURA FINAL FORM +FC0F ; [.2383.0020.001A][.242B.0020.001A] # ARABIC LIGATURE TEH WITH ALEF MAKSURA ISOLATED FORM +FC75 ; [.2383.0020.0019][.242C.0020.0019] # ARABIC LIGATURE TEH WITH YEH FINAL FORM +FC10 ; [.2383.0020.001A][.242C.0020.001A] # ARABIC LIGATURE TEH WITH YEH ISOLATED FORM +062B ; [.2384.0020.0002] # ARABIC LETTER THEH +1EE16 ; [.2384.0020.0005] # ARABIC MATHEMATICAL THEH +1EE36 ; [.2384.0020.0005] # ARABIC MATHEMATICAL INITIAL THEH +1EE76 ; [.2384.0020.0005] # ARABIC MATHEMATICAL STRETCHED THEH +1EE96 ; [.2384.0020.0005] # ARABIC MATHEMATICAL LOOPED THEH +1EEB6 ; [.2384.0020.0005] # ARABIC MATHEMATICAL DOUBLE-STRUCK THEH +FE9B ; [.2384.0020.0017] # ARABIC LETTER THEH INITIAL FORM +FE9C ; [.2384.0020.0018] # ARABIC LETTER THEH MEDIAL FORM +FE9A ; [.2384.0020.0019] # ARABIC LETTER THEH FINAL FORM +FE99 ; [.2384.0020.001A] # ARABIC LETTER THEH ISOLATED FORM +FC11 ; [.2384.0020.001A][.238B.0020.001A] # ARABIC LIGATURE THEH WITH JEEM ISOLATED FORM +FC76 ; [.2384.0020.0019][.23AC.0020.0019] # ARABIC LIGATURE THEH WITH REH FINAL FORM +FC77 ; [.2384.0020.0019][.23AD.0020.0019] # ARABIC LIGATURE THEH WITH ZAIN FINAL FORM +FCA6 ; [.2384.0020.0017][.2409.0020.0017] # ARABIC LIGATURE THEH WITH MEEM INITIAL FORM +FCE5 ; [.2384.0020.0018][.2409.0020.0018] # ARABIC LIGATURE THEH WITH MEEM MEDIAL FORM +FC78 ; [.2384.0020.0019][.2409.0020.0019] # ARABIC LIGATURE THEH WITH MEEM FINAL FORM +FC12 ; [.2384.0020.001A][.2409.0020.001A] # ARABIC LIGATURE THEH WITH MEEM ISOLATED FORM +FC79 ; [.2384.0020.0019][.240D.0020.0019] # ARABIC LIGATURE THEH WITH NOON FINAL FORM +FCE6 ; [.2384.0020.0018][.2417.0020.0018] # ARABIC LIGATURE THEH WITH HEH MEDIAL FORM +FC7A ; [.2384.0020.0019][.242B.0020.0019] # ARABIC LIGATURE THEH WITH ALEF MAKSURA FINAL FORM +FC13 ; [.2384.0020.001A][.242B.0020.001A] # ARABIC LIGATURE THEH WITH ALEF MAKSURA ISOLATED FORM +FC7B ; [.2384.0020.0019][.242C.0020.0019] # ARABIC LIGATURE THEH WITH YEH FINAL FORM +FC14 ; [.2384.0020.001A][.242C.0020.001A] # ARABIC LIGATURE THEH WITH YEH ISOLATED FORM +0679 ; [.2385.0020.0002] # ARABIC LETTER TTEH +FB68 ; [.2385.0020.0017] # ARABIC LETTER TTEH INITIAL FORM +FB69 ; [.2385.0020.0018] # ARABIC LETTER TTEH MEDIAL FORM +FB67 ; [.2385.0020.0019] # ARABIC LETTER TTEH FINAL FORM +FB66 ; [.2385.0020.001A] # ARABIC LETTER TTEH ISOLATED FORM +067A ; [.2386.0020.0002] # ARABIC LETTER TTEHEH +FB60 ; [.2386.0020.0017] # ARABIC LETTER TTEHEH INITIAL FORM +FB61 ; [.2386.0020.0018] # ARABIC LETTER TTEHEH MEDIAL FORM +FB5F ; [.2386.0020.0019] # ARABIC LETTER TTEHEH FINAL FORM +FB5E ; [.2386.0020.001A] # ARABIC LETTER TTEHEH ISOLATED FORM +067C ; [.2387.0020.0002] # ARABIC LETTER TEH WITH RING +067D ; [.2388.0020.0002] # ARABIC LETTER TEH WITH THREE DOTS ABOVE DOWNWARDS +067F ; [.2389.0020.0002] # ARABIC LETTER TEHEH +FB64 ; [.2389.0020.0017] # ARABIC LETTER TEHEH INITIAL FORM +FB65 ; [.2389.0020.0018] # ARABIC LETTER TEHEH MEDIAL FORM +FB63 ; [.2389.0020.0019] # ARABIC LETTER TEHEH FINAL FORM +FB62 ; [.2389.0020.001A] # ARABIC LETTER TEHEH ISOLATED FORM +08B8 ; [.238A.0020.0002] # ARABIC LETTER TEH WITH SMALL TEH ABOVE +062C ; [.238B.0020.0002] # ARABIC LETTER JEEM +1EE02 ; [.238B.0020.0005] # ARABIC MATHEMATICAL JEEM +1EE22 ; [.238B.0020.0005] # ARABIC MATHEMATICAL INITIAL JEEM +1EE42 ; [.238B.0020.0005] # ARABIC MATHEMATICAL TAILED JEEM +1EE62 ; [.238B.0020.0005] # ARABIC MATHEMATICAL STRETCHED JEEM +1EE82 ; [.238B.0020.0005] # ARABIC MATHEMATICAL LOOPED JEEM +1EEA2 ; [.238B.0020.0005] # ARABIC MATHEMATICAL DOUBLE-STRUCK JEEM +FE9F ; [.238B.0020.0017] # ARABIC LETTER JEEM INITIAL FORM +FEA0 ; [.238B.0020.0018] # ARABIC LETTER JEEM MEDIAL FORM +FE9E ; [.238B.0020.0019] # ARABIC LETTER JEEM FINAL FORM +FE9D ; [.238B.0020.001A] # ARABIC LETTER JEEM ISOLATED FORM +FCA7 ; [.238B.0020.0017][.2392.0020.0017] # ARABIC LIGATURE JEEM WITH HAH INITIAL FORM +FC15 ; [.238B.0020.001A][.2392.0020.001A] # ARABIC LIGATURE JEEM WITH HAH ISOLATED FORM +FDA6 ; [.238B.0020.0019][.2392.0020.0019][.242B.0020.0019] # ARABIC LIGATURE JEEM WITH HAH WITH ALEF MAKSURA FINAL FORM +FDBE ; [.238B.0020.0019][.2392.0020.0019][.242C.0020.0019] # ARABIC LIGATURE JEEM WITH HAH WITH YEH FINAL FORM +FDFB ; [.238B.0020.001A][.2402.0020.001A][*0209.0020.001A][.238B.0020.001A][.2402.0020.001A][.2371.0020.001A][.2402.0020.001A][.2417.0020.001A] # ARABIC LIGATURE JALLAJALALOUHOU +FCA8 ; [.238B.0020.0017][.2409.0020.0017] # ARABIC LIGATURE JEEM WITH MEEM INITIAL FORM +FC16 ; [.238B.0020.001A][.2409.0020.001A] # ARABIC LIGATURE JEEM WITH MEEM ISOLATED FORM +FD59 ; [.238B.0020.0017][.2409.0020.0017][.2392.0020.0017] # ARABIC LIGATURE JEEM WITH MEEM WITH HAH INITIAL FORM +FD58 ; [.238B.0020.0019][.2409.0020.0019][.2392.0020.0019] # ARABIC LIGATURE JEEM WITH MEEM WITH HAH FINAL FORM +FDA7 ; [.238B.0020.0019][.2409.0020.0019][.242B.0020.0019] # ARABIC LIGATURE JEEM WITH MEEM WITH ALEF MAKSURA FINAL FORM +FDA5 ; [.238B.0020.0019][.2409.0020.0019][.242C.0020.0019] # ARABIC LIGATURE JEEM WITH MEEM WITH YEH FINAL FORM +FD1D ; [.238B.0020.0019][.242B.0020.0019] # ARABIC LIGATURE JEEM WITH ALEF MAKSURA FINAL FORM +FD01 ; [.238B.0020.001A][.242B.0020.001A] # ARABIC LIGATURE JEEM WITH ALEF MAKSURA ISOLATED FORM +FD1E ; [.238B.0020.0019][.242C.0020.0019] # ARABIC LIGATURE JEEM WITH YEH FINAL FORM +FD02 ; [.238B.0020.001A][.242C.0020.001A] # ARABIC LIGATURE JEEM WITH YEH ISOLATED FORM +0683 ; [.238C.0020.0002] # ARABIC LETTER NYEH +FB78 ; [.238C.0020.0017] # ARABIC LETTER NYEH INITIAL FORM +FB79 ; [.238C.0020.0018] # ARABIC LETTER NYEH MEDIAL FORM +FB77 ; [.238C.0020.0019] # ARABIC LETTER NYEH FINAL FORM +FB76 ; [.238C.0020.001A] # ARABIC LETTER NYEH ISOLATED FORM +0684 ; [.238D.0020.0002] # ARABIC LETTER DYEH +FB74 ; [.238D.0020.0017] # ARABIC LETTER DYEH INITIAL FORM +FB75 ; [.238D.0020.0018] # ARABIC LETTER DYEH MEDIAL FORM +FB73 ; [.238D.0020.0019] # ARABIC LETTER DYEH FINAL FORM +FB72 ; [.238D.0020.001A] # ARABIC LETTER DYEH ISOLATED FORM +0686 ; [.238E.0020.0002] # ARABIC LETTER TCHEH +FB7C ; [.238E.0020.0017] # ARABIC LETTER TCHEH INITIAL FORM +FB7D ; [.238E.0020.0018] # ARABIC LETTER TCHEH MEDIAL FORM +FB7B ; [.238E.0020.0019] # ARABIC LETTER TCHEH FINAL FORM +FB7A ; [.238E.0020.001A] # ARABIC LETTER TCHEH ISOLATED FORM +06BF ; [.238F.0020.0002] # ARABIC LETTER TCHEH WITH DOT ABOVE +0687 ; [.2390.0020.0002] # ARABIC LETTER TCHEHEH +FB80 ; [.2390.0020.0017] # ARABIC LETTER TCHEHEH INITIAL FORM +FB81 ; [.2390.0020.0018] # ARABIC LETTER TCHEHEH MEDIAL FORM +FB7F ; [.2390.0020.0019] # ARABIC LETTER TCHEHEH FINAL FORM +FB7E ; [.2390.0020.001A] # ARABIC LETTER TCHEHEH ISOLATED FORM +08A2 ; [.2391.0020.0002] # ARABIC LETTER JEEM WITH TWO DOTS ABOVE +062D ; [.2392.0020.0002] # ARABIC LETTER HAH +1EE07 ; [.2392.0020.0005] # ARABIC MATHEMATICAL HAH +1EE27 ; [.2392.0020.0005] # ARABIC MATHEMATICAL INITIAL HAH +1EE47 ; [.2392.0020.0005] # ARABIC MATHEMATICAL TAILED HAH +1EE67 ; [.2392.0020.0005] # ARABIC MATHEMATICAL STRETCHED HAH +1EE87 ; [.2392.0020.0005] # ARABIC MATHEMATICAL LOOPED HAH +1EEA7 ; [.2392.0020.0005] # ARABIC MATHEMATICAL DOUBLE-STRUCK HAH +FEA3 ; [.2392.0020.0017] # ARABIC LETTER HAH INITIAL FORM +FEA4 ; [.2392.0020.0018] # ARABIC LETTER HAH MEDIAL FORM +FEA2 ; [.2392.0020.0019] # ARABIC LETTER HAH FINAL FORM +FEA1 ; [.2392.0020.001A] # ARABIC LETTER HAH ISOLATED FORM +FCA9 ; [.2392.0020.0017][.238B.0020.0017] # ARABIC LIGATURE HAH WITH JEEM INITIAL FORM +FC17 ; [.2392.0020.001A][.238B.0020.001A] # ARABIC LIGATURE HAH WITH JEEM ISOLATED FORM +FDBF ; [.2392.0020.0019][.238B.0020.0019][.242C.0020.0019] # ARABIC LIGATURE HAH WITH JEEM WITH YEH FINAL FORM +FCAA ; [.2392.0020.0017][.2409.0020.0017] # ARABIC LIGATURE HAH WITH MEEM INITIAL FORM +FC18 ; [.2392.0020.001A][.2409.0020.001A] # ARABIC LIGATURE HAH WITH MEEM ISOLATED FORM +FD5B ; [.2392.0020.0019][.2409.0020.0019][.242B.0020.0019] # ARABIC LIGATURE HAH WITH MEEM WITH ALEF MAKSURA FINAL FORM +FD5A ; [.2392.0020.0019][.2409.0020.0019][.242C.0020.0019] # ARABIC LIGATURE HAH WITH MEEM WITH YEH FINAL FORM +FD1B ; [.2392.0020.0019][.242B.0020.0019] # ARABIC LIGATURE HAH WITH ALEF MAKSURA FINAL FORM +FCFF ; [.2392.0020.001A][.242B.0020.001A] # ARABIC LIGATURE HAH WITH ALEF MAKSURA ISOLATED FORM +FD1C ; [.2392.0020.0019][.242C.0020.0019] # ARABIC LIGATURE HAH WITH YEH FINAL FORM +FD00 ; [.2392.0020.001A][.242C.0020.001A] # ARABIC LIGATURE HAH WITH YEH ISOLATED FORM +062E ; [.2393.0020.0002] # ARABIC LETTER KHAH +1EE17 ; [.2393.0020.0005] # ARABIC MATHEMATICAL KHAH +1EE37 ; [.2393.0020.0005] # ARABIC MATHEMATICAL INITIAL KHAH +1EE57 ; [.2393.0020.0005] # ARABIC MATHEMATICAL TAILED KHAH +1EE77 ; [.2393.0020.0005] # ARABIC MATHEMATICAL STRETCHED KHAH +1EE97 ; [.2393.0020.0005] # ARABIC MATHEMATICAL LOOPED KHAH +1EEB7 ; [.2393.0020.0005] # ARABIC MATHEMATICAL DOUBLE-STRUCK KHAH +FEA7 ; [.2393.0020.0017] # ARABIC LETTER KHAH INITIAL FORM +FEA8 ; [.2393.0020.0018] # ARABIC LETTER KHAH MEDIAL FORM +FEA6 ; [.2393.0020.0019] # ARABIC LETTER KHAH FINAL FORM +FEA5 ; [.2393.0020.001A] # ARABIC LETTER KHAH ISOLATED FORM +FCAB ; [.2393.0020.0017][.238B.0020.0017] # ARABIC LIGATURE KHAH WITH JEEM INITIAL FORM +FC19 ; [.2393.0020.001A][.238B.0020.001A] # ARABIC LIGATURE KHAH WITH JEEM ISOLATED FORM +FC1A ; [.2393.0020.001A][.2392.0020.001A] # ARABIC LIGATURE KHAH WITH HAH ISOLATED FORM +FCAC ; [.2393.0020.0017][.2409.0020.0017] # ARABIC LIGATURE KHAH WITH MEEM INITIAL FORM +FC1B ; [.2393.0020.001A][.2409.0020.001A] # ARABIC LIGATURE KHAH WITH MEEM ISOLATED FORM +FD1F ; [.2393.0020.0019][.242B.0020.0019] # ARABIC LIGATURE KHAH WITH ALEF MAKSURA FINAL FORM +FD03 ; [.2393.0020.001A][.242B.0020.001A] # ARABIC LIGATURE KHAH WITH ALEF MAKSURA ISOLATED FORM +FD20 ; [.2393.0020.0019][.242C.0020.0019] # ARABIC LIGATURE KHAH WITH YEH FINAL FORM +FD04 ; [.2393.0020.001A][.242C.0020.001A] # ARABIC LIGATURE KHAH WITH YEH ISOLATED FORM +0681 ; [.2394.0020.0002] # ARABIC LETTER HAH WITH HAMZA ABOVE +0682 ; [.2395.0020.0002] # ARABIC LETTER HAH WITH TWO DOTS VERTICAL ABOVE +0685 ; [.2396.0020.0002] # ARABIC LETTER HAH WITH THREE DOTS ABOVE +0757 ; [.2397.0020.0002] # ARABIC LETTER HAH WITH TWO DOTS ABOVE +0758 ; [.2398.0020.0002] # ARABIC LETTER HAH WITH THREE DOTS POINTING UPWARDS BELOW +076E ; [.2399.0020.0002] # ARABIC LETTER HAH WITH SMALL ARABIC LETTER TAH BELOW +076F ; [.239A.0020.0002] # ARABIC LETTER HAH WITH SMALL ARABIC LETTER TAH AND TWO DOTS +0772 ; [.239B.0020.0002] # ARABIC LETTER HAH WITH SMALL ARABIC LETTER TAH ABOVE +077C ; [.239C.0020.0002] # ARABIC LETTER HAH WITH EXTENDED ARABIC-INDIC DIGIT FOUR BELOW +062F ; [.239D.0020.0002] # ARABIC LETTER DAL +1EE03 ; [.239D.0020.0005] # ARABIC MATHEMATICAL DAL +1EE83 ; [.239D.0020.0005] # ARABIC MATHEMATICAL LOOPED DAL +1EEA3 ; [.239D.0020.0005] # ARABIC MATHEMATICAL DOUBLE-STRUCK DAL +FEAA ; [.239D.0020.0019] # ARABIC LETTER DAL FINAL FORM +FEA9 ; [.239D.0020.001A] # ARABIC LETTER DAL ISOLATED FORM +0630 ; [.239E.0020.0002] # ARABIC LETTER THAL +1EE18 ; [.239E.0020.0005] # ARABIC MATHEMATICAL THAL +1EE98 ; [.239E.0020.0005] # ARABIC MATHEMATICAL LOOPED THAL +1EEB8 ; [.239E.0020.0005] # ARABIC MATHEMATICAL DOUBLE-STRUCK THAL +FEAC ; [.239E.0020.0019] # ARABIC LETTER THAL FINAL FORM +FEAB ; [.239E.0020.001A] # ARABIC LETTER THAL ISOLATED FORM +FC5B ; [.239E.0020.001A][.0000.0098.001A] # ARABIC LIGATURE THAL WITH SUPERSCRIPT ALEF ISOLATED FORM +0688 ; [.239F.0020.0002] # ARABIC LETTER DDAL +FB89 ; [.239F.0020.0019] # ARABIC LETTER DDAL FINAL FORM +FB88 ; [.239F.0020.001A] # ARABIC LETTER DDAL ISOLATED FORM +0689 ; [.23A0.0020.0002] # ARABIC LETTER DAL WITH RING +068A ; [.23A1.0020.0002] # ARABIC LETTER DAL WITH DOT BELOW +068B ; [.23A2.0020.0002] # ARABIC LETTER DAL WITH DOT BELOW AND SMALL TAH +068C ; [.23A3.0020.0002] # ARABIC LETTER DAHAL +FB85 ; [.23A3.0020.0019] # ARABIC LETTER DAHAL FINAL FORM +FB84 ; [.23A3.0020.001A] # ARABIC LETTER DAHAL ISOLATED FORM +068D ; [.23A4.0020.0002] # ARABIC LETTER DDAHAL +FB83 ; [.23A4.0020.0019] # ARABIC LETTER DDAHAL FINAL FORM +FB82 ; [.23A4.0020.001A] # ARABIC LETTER DDAHAL ISOLATED FORM +08AE ; [.23A5.0020.0002] # ARABIC LETTER DAL WITH THREE DOTS BELOW +068E ; [.23A6.0020.0002] # ARABIC LETTER DUL +FB87 ; [.23A6.0020.0019] # ARABIC LETTER DUL FINAL FORM +FB86 ; [.23A6.0020.001A] # ARABIC LETTER DUL ISOLATED FORM +068F ; [.23A7.0020.0002] # ARABIC LETTER DAL WITH THREE DOTS ABOVE DOWNWARDS +0690 ; [.23A8.0020.0002] # ARABIC LETTER DAL WITH FOUR DOTS ABOVE +06EE ; [.23A9.0020.0002] # ARABIC LETTER DAL WITH INVERTED V +0759 ; [.23AA.0020.0002] # ARABIC LETTER DAL WITH TWO DOTS VERTICALLY BELOW AND SMALL TAH +075A ; [.23AB.0020.0002] # ARABIC LETTER DAL WITH INVERTED SMALL V BELOW +0631 ; [.23AC.0020.0002] # ARABIC LETTER REH +1EE13 ; [.23AC.0020.0005] # ARABIC MATHEMATICAL REH +1EE93 ; [.23AC.0020.0005] # ARABIC MATHEMATICAL LOOPED REH +1EEB3 ; [.23AC.0020.0005] # ARABIC MATHEMATICAL DOUBLE-STRUCK REH +FEAE ; [.23AC.0020.0019] # ARABIC LETTER REH FINAL FORM +FEAD ; [.23AC.0020.001A] # ARABIC LETTER REH ISOLATED FORM +FC5C ; [.23AC.0020.001A][.0000.0098.001A] # ARABIC LIGATURE REH WITH SUPERSCRIPT ALEF ISOLATED FORM +FDF6 ; [.23AC.0020.001A][.23BF.0020.001A][.241D.0020.001A][.2402.0020.001A] # ARABIC LIGATURE RASOUL ISOLATED FORM +FDFC ; [.23AC.0020.001A][.242D.0020.001A][.2371.0020.001A][.2402.0020.001A] # RIAL SIGN +0632 ; [.23AD.0020.0002] # ARABIC LETTER ZAIN +1EE06 ; [.23AD.0020.0005] # ARABIC MATHEMATICAL ZAIN +1EE86 ; [.23AD.0020.0005] # ARABIC MATHEMATICAL LOOPED ZAIN +1EEA6 ; [.23AD.0020.0005] # ARABIC MATHEMATICAL DOUBLE-STRUCK ZAIN +FEB0 ; [.23AD.0020.0019] # ARABIC LETTER ZAIN FINAL FORM +FEAF ; [.23AD.0020.001A] # ARABIC LETTER ZAIN ISOLATED FORM +0691 ; [.23AE.0020.0002] # ARABIC LETTER RREH +FB8D ; [.23AE.0020.0019] # ARABIC LETTER RREH FINAL FORM +FB8C ; [.23AE.0020.001A] # ARABIC LETTER RREH ISOLATED FORM +0692 ; [.23AF.0020.0002] # ARABIC LETTER REH WITH SMALL V +0693 ; [.23B0.0020.0002] # ARABIC LETTER REH WITH RING +0694 ; [.23B1.0020.0002] # ARABIC LETTER REH WITH DOT BELOW +0695 ; [.23B2.0020.0002] # ARABIC LETTER REH WITH SMALL V BELOW +0696 ; [.23B3.0020.0002] # ARABIC LETTER REH WITH DOT BELOW AND DOT ABOVE +0697 ; [.23B4.0020.0002] # ARABIC LETTER REH WITH TWO DOTS ABOVE +0698 ; [.23B5.0020.0002] # ARABIC LETTER JEH +FB8B ; [.23B5.0020.0019] # ARABIC LETTER JEH FINAL FORM +FB8A ; [.23B5.0020.001A] # ARABIC LETTER JEH ISOLATED FORM +0699 ; [.23B6.0020.0002] # ARABIC LETTER REH WITH FOUR DOTS ABOVE +06EF ; [.23B7.0020.0002] # ARABIC LETTER REH WITH INVERTED V +075B ; [.23B8.0020.0002] # ARABIC LETTER REH WITH STROKE +076B ; [.23B9.0020.0002] # ARABIC LETTER REH WITH TWO DOTS VERTICALLY ABOVE +076C ; [.23BA.0020.0002] # ARABIC LETTER REH WITH HAMZA ABOVE +0771 ; [.23BB.0020.0002] # ARABIC LETTER REH WITH SMALL ARABIC LETTER TAH AND TWO DOTS +08AA ; [.23BC.0020.0002] # ARABIC LETTER REH WITH LOOP +08B2 ; [.23BD.0020.0002] # ARABIC LETTER ZAIN WITH INVERTED V ABOVE +08B9 ; [.23BE.0020.0002] # ARABIC LETTER REH WITH SMALL NOON ABOVE +0633 ; [.23BF.0020.0002] # ARABIC LETTER SEEN +1EE0E ; [.23BF.0020.0005] # ARABIC MATHEMATICAL SEEN +1EE2E ; [.23BF.0020.0005] # ARABIC MATHEMATICAL INITIAL SEEN +1EE4E ; [.23BF.0020.0005] # ARABIC MATHEMATICAL TAILED SEEN +1EE6E ; [.23BF.0020.0005] # ARABIC MATHEMATICAL STRETCHED SEEN +1EE8E ; [.23BF.0020.0005] # ARABIC MATHEMATICAL LOOPED SEEN +1EEAE ; [.23BF.0020.0005] # ARABIC MATHEMATICAL DOUBLE-STRUCK SEEN +FEB3 ; [.23BF.0020.0017] # ARABIC LETTER SEEN INITIAL FORM +FEB4 ; [.23BF.0020.0018] # ARABIC LETTER SEEN MEDIAL FORM +FEB2 ; [.23BF.0020.0019] # ARABIC LETTER SEEN FINAL FORM +FEB1 ; [.23BF.0020.001A] # ARABIC LETTER SEEN ISOLATED FORM +FCAD ; [.23BF.0020.0017][.238B.0020.0017] # ARABIC LIGATURE SEEN WITH JEEM INITIAL FORM +FD34 ; [.23BF.0020.0018][.238B.0020.0018] # ARABIC LIGATURE SEEN WITH JEEM MEDIAL FORM +FC1C ; [.23BF.0020.001A][.238B.0020.001A] # ARABIC LIGATURE SEEN WITH JEEM ISOLATED FORM +FD5D ; [.23BF.0020.0017][.238B.0020.0017][.2392.0020.0017] # ARABIC LIGATURE SEEN WITH JEEM WITH HAH INITIAL FORM +FD5E ; [.23BF.0020.0019][.238B.0020.0019][.242B.0020.0019] # ARABIC LIGATURE SEEN WITH JEEM WITH ALEF MAKSURA FINAL FORM +FCAE ; [.23BF.0020.0017][.2392.0020.0017] # ARABIC LIGATURE SEEN WITH HAH INITIAL FORM +FD35 ; [.23BF.0020.0018][.2392.0020.0018] # ARABIC LIGATURE SEEN WITH HAH MEDIAL FORM +FC1D ; [.23BF.0020.001A][.2392.0020.001A] # ARABIC LIGATURE SEEN WITH HAH ISOLATED FORM +FD5C ; [.23BF.0020.0017][.2392.0020.0017][.238B.0020.0017] # ARABIC LIGATURE SEEN WITH HAH WITH JEEM INITIAL FORM +FCAF ; [.23BF.0020.0017][.2393.0020.0017] # ARABIC LIGATURE SEEN WITH KHAH INITIAL FORM +FD36 ; [.23BF.0020.0018][.2393.0020.0018] # ARABIC LIGATURE SEEN WITH KHAH MEDIAL FORM +FC1E ; [.23BF.0020.001A][.2393.0020.001A] # ARABIC LIGATURE SEEN WITH KHAH ISOLATED FORM +FDA8 ; [.23BF.0020.0019][.2393.0020.0019][.242B.0020.0019] # ARABIC LIGATURE SEEN WITH KHAH WITH ALEF MAKSURA FINAL FORM +FDC6 ; [.23BF.0020.0019][.2393.0020.0019][.242C.0020.0019] # ARABIC LIGATURE SEEN WITH KHAH WITH YEH FINAL FORM +FD2A ; [.23BF.0020.0019][.23AC.0020.0019] # ARABIC LIGATURE SEEN WITH REH FINAL FORM +FD0E ; [.23BF.0020.001A][.23AC.0020.001A] # ARABIC LIGATURE SEEN WITH REH ISOLATED FORM +FCB0 ; [.23BF.0020.0017][.2409.0020.0017] # ARABIC LIGATURE SEEN WITH MEEM INITIAL FORM +FCE7 ; [.23BF.0020.0018][.2409.0020.0018] # ARABIC LIGATURE SEEN WITH MEEM MEDIAL FORM +FC1F ; [.23BF.0020.001A][.2409.0020.001A] # ARABIC LIGATURE SEEN WITH MEEM ISOLATED FORM +FD61 ; [.23BF.0020.0017][.2409.0020.0017][.238B.0020.0017] # ARABIC LIGATURE SEEN WITH MEEM WITH JEEM INITIAL FORM +FD60 ; [.23BF.0020.0017][.2409.0020.0017][.2392.0020.0017] # ARABIC LIGATURE SEEN WITH MEEM WITH HAH INITIAL FORM +FD5F ; [.23BF.0020.0019][.2409.0020.0019][.2392.0020.0019] # ARABIC LIGATURE SEEN WITH MEEM WITH HAH FINAL FORM +FD63 ; [.23BF.0020.0017][.2409.0020.0017][.2409.0020.0017] # ARABIC LIGATURE SEEN WITH MEEM WITH MEEM INITIAL FORM +FD62 ; [.23BF.0020.0019][.2409.0020.0019][.2409.0020.0019] # ARABIC LIGATURE SEEN WITH MEEM WITH MEEM FINAL FORM +FD31 ; [.23BF.0020.0017][.2417.0020.0017] # ARABIC LIGATURE SEEN WITH HEH INITIAL FORM +FCE8 ; [.23BF.0020.0018][.2417.0020.0018] # ARABIC LIGATURE SEEN WITH HEH MEDIAL FORM +FD17 ; [.23BF.0020.0019][.242B.0020.0019] # ARABIC LIGATURE SEEN WITH ALEF MAKSURA FINAL FORM +FCFB ; [.23BF.0020.001A][.242B.0020.001A] # ARABIC LIGATURE SEEN WITH ALEF MAKSURA ISOLATED FORM +FD18 ; [.23BF.0020.0019][.242C.0020.0019] # ARABIC LIGATURE SEEN WITH YEH FINAL FORM +FCFC ; [.23BF.0020.001A][.242C.0020.001A] # ARABIC LIGATURE SEEN WITH YEH ISOLATED FORM +0634 ; [.23C0.0020.0002] # ARABIC LETTER SHEEN +1EE14 ; [.23C0.0020.0005] # ARABIC MATHEMATICAL SHEEN +1EE34 ; [.23C0.0020.0005] # ARABIC MATHEMATICAL INITIAL SHEEN +1EE54 ; [.23C0.0020.0005] # ARABIC MATHEMATICAL TAILED SHEEN +1EE74 ; [.23C0.0020.0005] # ARABIC MATHEMATICAL STRETCHED SHEEN +1EE94 ; [.23C0.0020.0005] # ARABIC MATHEMATICAL LOOPED SHEEN +1EEB4 ; [.23C0.0020.0005] # ARABIC MATHEMATICAL DOUBLE-STRUCK SHEEN +FEB7 ; [.23C0.0020.0017] # ARABIC LETTER SHEEN INITIAL FORM +FEB8 ; [.23C0.0020.0018] # ARABIC LETTER SHEEN MEDIAL FORM +FEB6 ; [.23C0.0020.0019] # ARABIC LETTER SHEEN FINAL FORM +FEB5 ; [.23C0.0020.001A] # ARABIC LETTER SHEEN ISOLATED FORM +FD2D ; [.23C0.0020.0017][.238B.0020.0017] # ARABIC LIGATURE SHEEN WITH JEEM INITIAL FORM +FD37 ; [.23C0.0020.0018][.238B.0020.0018] # ARABIC LIGATURE SHEEN WITH JEEM MEDIAL FORM +FD25 ; [.23C0.0020.0019][.238B.0020.0019] # ARABIC LIGATURE SHEEN WITH JEEM FINAL FORM +FD09 ; [.23C0.0020.001A][.238B.0020.001A] # ARABIC LIGATURE SHEEN WITH JEEM ISOLATED FORM +FD69 ; [.23C0.0020.0019][.238B.0020.0019][.242C.0020.0019] # ARABIC LIGATURE SHEEN WITH JEEM WITH YEH FINAL FORM +FD2E ; [.23C0.0020.0017][.2392.0020.0017] # ARABIC LIGATURE SHEEN WITH HAH INITIAL FORM +FD38 ; [.23C0.0020.0018][.2392.0020.0018] # ARABIC LIGATURE SHEEN WITH HAH MEDIAL FORM +FD26 ; [.23C0.0020.0019][.2392.0020.0019] # ARABIC LIGATURE SHEEN WITH HAH FINAL FORM +FD0A ; [.23C0.0020.001A][.2392.0020.001A] # ARABIC LIGATURE SHEEN WITH HAH ISOLATED FORM +FD68 ; [.23C0.0020.0017][.2392.0020.0017][.2409.0020.0017] # ARABIC LIGATURE SHEEN WITH HAH WITH MEEM INITIAL FORM +FD67 ; [.23C0.0020.0019][.2392.0020.0019][.2409.0020.0019] # ARABIC LIGATURE SHEEN WITH HAH WITH MEEM FINAL FORM +FDAA ; [.23C0.0020.0019][.2392.0020.0019][.242C.0020.0019] # ARABIC LIGATURE SHEEN WITH HAH WITH YEH FINAL FORM +FD2F ; [.23C0.0020.0017][.2393.0020.0017] # ARABIC LIGATURE SHEEN WITH KHAH INITIAL FORM +FD39 ; [.23C0.0020.0018][.2393.0020.0018] # ARABIC LIGATURE SHEEN WITH KHAH MEDIAL FORM +FD27 ; [.23C0.0020.0019][.2393.0020.0019] # ARABIC LIGATURE SHEEN WITH KHAH FINAL FORM +FD0B ; [.23C0.0020.001A][.2393.0020.001A] # ARABIC LIGATURE SHEEN WITH KHAH ISOLATED FORM +FD29 ; [.23C0.0020.0019][.23AC.0020.0019] # ARABIC LIGATURE SHEEN WITH REH FINAL FORM +FD0D ; [.23C0.0020.001A][.23AC.0020.001A] # ARABIC LIGATURE SHEEN WITH REH ISOLATED FORM +FD30 ; [.23C0.0020.0017][.2409.0020.0017] # ARABIC LIGATURE SHEEN WITH MEEM INITIAL FORM +FCE9 ; [.23C0.0020.0018][.2409.0020.0018] # ARABIC LIGATURE SHEEN WITH MEEM MEDIAL FORM +FD28 ; [.23C0.0020.0019][.2409.0020.0019] # ARABIC LIGATURE SHEEN WITH MEEM FINAL FORM +FD0C ; [.23C0.0020.001A][.2409.0020.001A] # ARABIC LIGATURE SHEEN WITH MEEM ISOLATED FORM +FD6B ; [.23C0.0020.0017][.2409.0020.0017][.2393.0020.0017] # ARABIC LIGATURE SHEEN WITH MEEM WITH KHAH INITIAL FORM +FD6A ; [.23C0.0020.0019][.2409.0020.0019][.2393.0020.0019] # ARABIC LIGATURE SHEEN WITH MEEM WITH KHAH FINAL FORM +FD6D ; [.23C0.0020.0017][.2409.0020.0017][.2409.0020.0017] # ARABIC LIGATURE SHEEN WITH MEEM WITH MEEM INITIAL FORM +FD6C ; [.23C0.0020.0019][.2409.0020.0019][.2409.0020.0019] # ARABIC LIGATURE SHEEN WITH MEEM WITH MEEM FINAL FORM +FD32 ; [.23C0.0020.0017][.2417.0020.0017] # ARABIC LIGATURE SHEEN WITH HEH INITIAL FORM +FCEA ; [.23C0.0020.0018][.2417.0020.0018] # ARABIC LIGATURE SHEEN WITH HEH MEDIAL FORM +FD19 ; [.23C0.0020.0019][.242B.0020.0019] # ARABIC LIGATURE SHEEN WITH ALEF MAKSURA FINAL FORM +FCFD ; [.23C0.0020.001A][.242B.0020.001A] # ARABIC LIGATURE SHEEN WITH ALEF MAKSURA ISOLATED FORM +FD1A ; [.23C0.0020.0019][.242C.0020.0019] # ARABIC LIGATURE SHEEN WITH YEH FINAL FORM +FCFE ; [.23C0.0020.001A][.242C.0020.001A] # ARABIC LIGATURE SHEEN WITH YEH ISOLATED FORM +069A ; [.23C1.0020.0002] # ARABIC LETTER SEEN WITH DOT BELOW AND DOT ABOVE +069B ; [.23C2.0020.0002] # ARABIC LETTER SEEN WITH THREE DOTS BELOW +069C ; [.23C3.0020.0002] # ARABIC LETTER SEEN WITH THREE DOTS BELOW AND THREE DOTS ABOVE +06FA ; [.23C4.0020.0002] # ARABIC LETTER SHEEN WITH DOT BELOW +075C ; [.23C5.0020.0002] # ARABIC LETTER SEEN WITH FOUR DOTS ABOVE +076D ; [.23C6.0020.0002] # ARABIC LETTER SEEN WITH TWO DOTS VERTICALLY ABOVE +0770 ; [.23C7.0020.0002] # ARABIC LETTER SEEN WITH SMALL ARABIC LETTER TAH AND TWO DOTS +077D ; [.23C8.0020.0002] # ARABIC LETTER SEEN WITH EXTENDED ARABIC-INDIC DIGIT FOUR ABOVE +077E ; [.23C9.0020.0002] # ARABIC LETTER SEEN WITH INVERTED V +0635 ; [.23CA.0020.0002] # ARABIC LETTER SAD +1EE11 ; [.23CA.0020.0005] # ARABIC MATHEMATICAL SAD +1EE31 ; [.23CA.0020.0005] # ARABIC MATHEMATICAL INITIAL SAD +1EE51 ; [.23CA.0020.0005] # ARABIC MATHEMATICAL TAILED SAD +1EE71 ; [.23CA.0020.0005] # ARABIC MATHEMATICAL STRETCHED SAD +1EE91 ; [.23CA.0020.0005] # ARABIC MATHEMATICAL LOOPED SAD +1EEB1 ; [.23CA.0020.0005] # ARABIC MATHEMATICAL DOUBLE-STRUCK SAD +FEBB ; [.23CA.0020.0017] # ARABIC LETTER SAD INITIAL FORM +FEBC ; [.23CA.0020.0018] # ARABIC LETTER SAD MEDIAL FORM +FEBA ; [.23CA.0020.0019] # ARABIC LETTER SAD FINAL FORM +FEB9 ; [.23CA.0020.001A] # ARABIC LETTER SAD ISOLATED FORM +FCB1 ; [.23CA.0020.0017][.2392.0020.0017] # ARABIC LIGATURE SAD WITH HAH INITIAL FORM +FC20 ; [.23CA.0020.001A][.2392.0020.001A] # ARABIC LIGATURE SAD WITH HAH ISOLATED FORM +FD65 ; [.23CA.0020.0017][.2392.0020.0017][.2392.0020.0017] # ARABIC LIGATURE SAD WITH HAH WITH HAH INITIAL FORM +FD64 ; [.23CA.0020.0019][.2392.0020.0019][.2392.0020.0019] # ARABIC LIGATURE SAD WITH HAH WITH HAH FINAL FORM +FDA9 ; [.23CA.0020.0019][.2392.0020.0019][.242C.0020.0019] # ARABIC LIGATURE SAD WITH HAH WITH YEH FINAL FORM +FCB2 ; [.23CA.0020.0017][.2393.0020.0017] # ARABIC LIGATURE SAD WITH KHAH INITIAL FORM +FD2B ; [.23CA.0020.0019][.23AC.0020.0019] # ARABIC LIGATURE SAD WITH REH FINAL FORM +FD0F ; [.23CA.0020.001A][.23AC.0020.001A] # ARABIC LIGATURE SAD WITH REH ISOLATED FORM +FDF5 ; [.23CA.0020.001A][.2402.0020.001A][.23D4.0020.001A][.2409.0020.001A] # ARABIC LIGATURE SALAM ISOLATED FORM +FDF9 ; [.23CA.0020.001A][.2402.0020.001A][.242B.0020.001A] # ARABIC LIGATURE SALLA ISOLATED FORM +FDFA ; [.23CA.0020.001A][.2402.0020.001A][.242B.0020.001A][*0209.0020.001A][.2371.0020.001A][.2402.0020.001A][.2402.0020.001A][.2417.0020.001A][*0209.0020.001A][.23D4.0020.001A][.2402.0020.001A][.242C.0020.001A][.2417.0020.001A][*0209.0020.001A][.241D.0020.001A][.23BF.0020.001A][.2402.0020.001A][.2409.0020.001A] # ARABIC LIGATURE SALLALLAHOU ALAYHE WASALLAM +FDF0 ; [.23CA.0020.001A][.2402.0020.001A][.243A.0020.001A] # ARABIC LIGATURE SALLA USED AS KORANIC STOP SIGN ISOLATED FORM +FCB3 ; [.23CA.0020.0017][.2409.0020.0017] # ARABIC LIGATURE SAD WITH MEEM INITIAL FORM +FC21 ; [.23CA.0020.001A][.2409.0020.001A] # ARABIC LIGATURE SAD WITH MEEM ISOLATED FORM +FDC5 ; [.23CA.0020.0017][.2409.0020.0017][.2409.0020.0017] # ARABIC LIGATURE SAD WITH MEEM WITH MEEM INITIAL FORM +FD66 ; [.23CA.0020.0019][.2409.0020.0019][.2409.0020.0019] # ARABIC LIGATURE SAD WITH MEEM WITH MEEM FINAL FORM +FD21 ; [.23CA.0020.0019][.242B.0020.0019] # ARABIC LIGATURE SAD WITH ALEF MAKSURA FINAL FORM +FD05 ; [.23CA.0020.001A][.242B.0020.001A] # ARABIC LIGATURE SAD WITH ALEF MAKSURA ISOLATED FORM +FD22 ; [.23CA.0020.0019][.242C.0020.0019] # ARABIC LIGATURE SAD WITH YEH FINAL FORM +FD06 ; [.23CA.0020.001A][.242C.0020.001A] # ARABIC LIGATURE SAD WITH YEH ISOLATED FORM +0636 ; [.23CB.0020.0002] # ARABIC LETTER DAD +1EE19 ; [.23CB.0020.0005] # ARABIC MATHEMATICAL DAD +1EE39 ; [.23CB.0020.0005] # ARABIC MATHEMATICAL INITIAL DAD +1EE59 ; [.23CB.0020.0005] # ARABIC MATHEMATICAL TAILED DAD +1EE79 ; [.23CB.0020.0005] # ARABIC MATHEMATICAL STRETCHED DAD +1EE99 ; [.23CB.0020.0005] # ARABIC MATHEMATICAL LOOPED DAD +1EEB9 ; [.23CB.0020.0005] # ARABIC MATHEMATICAL DOUBLE-STRUCK DAD +FEBF ; [.23CB.0020.0017] # ARABIC LETTER DAD INITIAL FORM +FEC0 ; [.23CB.0020.0018] # ARABIC LETTER DAD MEDIAL FORM +FEBE ; [.23CB.0020.0019] # ARABIC LETTER DAD FINAL FORM +FEBD ; [.23CB.0020.001A] # ARABIC LETTER DAD ISOLATED FORM +FCB4 ; [.23CB.0020.0017][.238B.0020.0017] # ARABIC LIGATURE DAD WITH JEEM INITIAL FORM +FC22 ; [.23CB.0020.001A][.238B.0020.001A] # ARABIC LIGATURE DAD WITH JEEM ISOLATED FORM +FCB5 ; [.23CB.0020.0017][.2392.0020.0017] # ARABIC LIGATURE DAD WITH HAH INITIAL FORM +FC23 ; [.23CB.0020.001A][.2392.0020.001A] # ARABIC LIGATURE DAD WITH HAH ISOLATED FORM +FD6E ; [.23CB.0020.0019][.2392.0020.0019][.242B.0020.0019] # ARABIC LIGATURE DAD WITH HAH WITH ALEF MAKSURA FINAL FORM +FDAB ; [.23CB.0020.0019][.2392.0020.0019][.242C.0020.0019] # ARABIC LIGATURE DAD WITH HAH WITH YEH FINAL FORM +FCB6 ; [.23CB.0020.0017][.2393.0020.0017] # ARABIC LIGATURE DAD WITH KHAH INITIAL FORM +FC24 ; [.23CB.0020.001A][.2393.0020.001A] # ARABIC LIGATURE DAD WITH KHAH ISOLATED FORM +FD70 ; [.23CB.0020.0017][.2393.0020.0017][.2409.0020.0017] # ARABIC LIGATURE DAD WITH KHAH WITH MEEM INITIAL FORM +FD6F ; [.23CB.0020.0019][.2393.0020.0019][.2409.0020.0019] # ARABIC LIGATURE DAD WITH KHAH WITH MEEM FINAL FORM +FD2C ; [.23CB.0020.0019][.23AC.0020.0019] # ARABIC LIGATURE DAD WITH REH FINAL FORM +FD10 ; [.23CB.0020.001A][.23AC.0020.001A] # ARABIC LIGATURE DAD WITH REH ISOLATED FORM +FCB7 ; [.23CB.0020.0017][.2409.0020.0017] # ARABIC LIGATURE DAD WITH MEEM INITIAL FORM +FC25 ; [.23CB.0020.001A][.2409.0020.001A] # ARABIC LIGATURE DAD WITH MEEM ISOLATED FORM +FD23 ; [.23CB.0020.0019][.242B.0020.0019] # ARABIC LIGATURE DAD WITH ALEF MAKSURA FINAL FORM +FD07 ; [.23CB.0020.001A][.242B.0020.001A] # ARABIC LIGATURE DAD WITH ALEF MAKSURA ISOLATED FORM +FD24 ; [.23CB.0020.0019][.242C.0020.0019] # ARABIC LIGATURE DAD WITH YEH FINAL FORM +FD08 ; [.23CB.0020.001A][.242C.0020.001A] # ARABIC LIGATURE DAD WITH YEH ISOLATED FORM +069D ; [.23CC.0020.0002] # ARABIC LETTER SAD WITH TWO DOTS BELOW +08AF ; [.23CD.0020.0002] # ARABIC LETTER SAD WITH THREE DOTS BELOW +069E ; [.23CE.0020.0002] # ARABIC LETTER SAD WITH THREE DOTS ABOVE +06FB ; [.23CF.0020.0002] # ARABIC LETTER DAD WITH DOT BELOW +0637 ; [.23D0.0020.0002] # ARABIC LETTER TAH +1EE08 ; [.23D0.0020.0005] # ARABIC MATHEMATICAL TAH +1EE68 ; [.23D0.0020.0005] # ARABIC MATHEMATICAL STRETCHED TAH +1EE88 ; [.23D0.0020.0005] # ARABIC MATHEMATICAL LOOPED TAH +1EEA8 ; [.23D0.0020.0005] # ARABIC MATHEMATICAL DOUBLE-STRUCK TAH +FEC3 ; [.23D0.0020.0017] # ARABIC LETTER TAH INITIAL FORM +FEC4 ; [.23D0.0020.0018] # ARABIC LETTER TAH MEDIAL FORM +FEC2 ; [.23D0.0020.0019] # ARABIC LETTER TAH FINAL FORM +FEC1 ; [.23D0.0020.001A] # ARABIC LETTER TAH ISOLATED FORM +FCB8 ; [.23D0.0020.0017][.2392.0020.0017] # ARABIC LIGATURE TAH WITH HAH INITIAL FORM +FC26 ; [.23D0.0020.001A][.2392.0020.001A] # ARABIC LIGATURE TAH WITH HAH ISOLATED FORM +FD33 ; [.23D0.0020.0017][.2409.0020.0017] # ARABIC LIGATURE TAH WITH MEEM INITIAL FORM +FD3A ; [.23D0.0020.0018][.2409.0020.0018] # ARABIC LIGATURE TAH WITH MEEM MEDIAL FORM +FC27 ; [.23D0.0020.001A][.2409.0020.001A] # ARABIC LIGATURE TAH WITH MEEM ISOLATED FORM +FD72 ; [.23D0.0020.0017][.2409.0020.0017][.2392.0020.0017] # ARABIC LIGATURE TAH WITH MEEM WITH HAH INITIAL FORM +FD71 ; [.23D0.0020.0019][.2409.0020.0019][.2392.0020.0019] # ARABIC LIGATURE TAH WITH MEEM WITH HAH FINAL FORM +FD73 ; [.23D0.0020.0017][.2409.0020.0017][.2409.0020.0017] # ARABIC LIGATURE TAH WITH MEEM WITH MEEM INITIAL FORM +FD74 ; [.23D0.0020.0019][.2409.0020.0019][.242C.0020.0019] # ARABIC LIGATURE TAH WITH MEEM WITH YEH FINAL FORM +FD11 ; [.23D0.0020.0019][.242B.0020.0019] # ARABIC LIGATURE TAH WITH ALEF MAKSURA FINAL FORM +FCF5 ; [.23D0.0020.001A][.242B.0020.001A] # ARABIC LIGATURE TAH WITH ALEF MAKSURA ISOLATED FORM +FD12 ; [.23D0.0020.0019][.242C.0020.0019] # ARABIC LIGATURE TAH WITH YEH FINAL FORM +FCF6 ; [.23D0.0020.001A][.242C.0020.001A] # ARABIC LIGATURE TAH WITH YEH ISOLATED FORM +0638 ; [.23D1.0020.0002] # ARABIC LETTER ZAH +1EE1A ; [.23D1.0020.0005] # ARABIC MATHEMATICAL ZAH +1EE7A ; [.23D1.0020.0005] # ARABIC MATHEMATICAL STRETCHED ZAH +1EE9A ; [.23D1.0020.0005] # ARABIC MATHEMATICAL LOOPED ZAH +1EEBA ; [.23D1.0020.0005] # ARABIC MATHEMATICAL DOUBLE-STRUCK ZAH +FEC7 ; [.23D1.0020.0017] # ARABIC LETTER ZAH INITIAL FORM +FEC8 ; [.23D1.0020.0018] # ARABIC LETTER ZAH MEDIAL FORM +FEC6 ; [.23D1.0020.0019] # ARABIC LETTER ZAH FINAL FORM +FEC5 ; [.23D1.0020.001A] # ARABIC LETTER ZAH ISOLATED FORM +FCB9 ; [.23D1.0020.0017][.2409.0020.0017] # ARABIC LIGATURE ZAH WITH MEEM INITIAL FORM +FD3B ; [.23D1.0020.0018][.2409.0020.0018] # ARABIC LIGATURE ZAH WITH MEEM MEDIAL FORM +FC28 ; [.23D1.0020.001A][.2409.0020.001A] # ARABIC LIGATURE ZAH WITH MEEM ISOLATED FORM +069F ; [.23D2.0020.0002] # ARABIC LETTER TAH WITH THREE DOTS ABOVE +08A3 ; [.23D3.0020.0002] # ARABIC LETTER TAH WITH TWO DOTS ABOVE +0639 ; [.23D4.0020.0002] # ARABIC LETTER AIN +1EE0F ; [.23D4.0020.0005] # ARABIC MATHEMATICAL AIN +1EE2F ; [.23D4.0020.0005] # ARABIC MATHEMATICAL INITIAL AIN +1EE4F ; [.23D4.0020.0005] # ARABIC MATHEMATICAL TAILED AIN +1EE6F ; [.23D4.0020.0005] # ARABIC MATHEMATICAL STRETCHED AIN +1EE8F ; [.23D4.0020.0005] # ARABIC MATHEMATICAL LOOPED AIN +1EEAF ; [.23D4.0020.0005] # ARABIC MATHEMATICAL DOUBLE-STRUCK AIN +FECB ; [.23D4.0020.0017] # ARABIC LETTER AIN INITIAL FORM +FECC ; [.23D4.0020.0018] # ARABIC LETTER AIN MEDIAL FORM +FECA ; [.23D4.0020.0019] # ARABIC LETTER AIN FINAL FORM +FEC9 ; [.23D4.0020.001A] # ARABIC LETTER AIN ISOLATED FORM +FCBA ; [.23D4.0020.0017][.238B.0020.0017] # ARABIC LIGATURE AIN WITH JEEM INITIAL FORM +FC29 ; [.23D4.0020.001A][.238B.0020.001A] # ARABIC LIGATURE AIN WITH JEEM ISOLATED FORM +FDC4 ; [.23D4.0020.0017][.238B.0020.0017][.2409.0020.0017] # ARABIC LIGATURE AIN WITH JEEM WITH MEEM INITIAL FORM +FD75 ; [.23D4.0020.0019][.238B.0020.0019][.2409.0020.0019] # ARABIC LIGATURE AIN WITH JEEM WITH MEEM FINAL FORM +FDF7 ; [.23D4.0020.001A][.2402.0020.001A][.242C.0020.001A][.2417.0020.001A] # ARABIC LIGATURE ALAYHE ISOLATED FORM +FCBB ; [.23D4.0020.0017][.2409.0020.0017] # ARABIC LIGATURE AIN WITH MEEM INITIAL FORM +FC2A ; [.23D4.0020.001A][.2409.0020.001A] # ARABIC LIGATURE AIN WITH MEEM ISOLATED FORM +FD77 ; [.23D4.0020.0017][.2409.0020.0017][.2409.0020.0017] # ARABIC LIGATURE AIN WITH MEEM WITH MEEM INITIAL FORM +FD76 ; [.23D4.0020.0019][.2409.0020.0019][.2409.0020.0019] # ARABIC LIGATURE AIN WITH MEEM WITH MEEM FINAL FORM +FD78 ; [.23D4.0020.0019][.2409.0020.0019][.242B.0020.0019] # ARABIC LIGATURE AIN WITH MEEM WITH ALEF MAKSURA FINAL FORM +FDB6 ; [.23D4.0020.0019][.2409.0020.0019][.242C.0020.0019] # ARABIC LIGATURE AIN WITH MEEM WITH YEH FINAL FORM +FD13 ; [.23D4.0020.0019][.242B.0020.0019] # ARABIC LIGATURE AIN WITH ALEF MAKSURA FINAL FORM +FCF7 ; [.23D4.0020.001A][.242B.0020.001A] # ARABIC LIGATURE AIN WITH ALEF MAKSURA ISOLATED FORM +FD14 ; [.23D4.0020.0019][.242C.0020.0019] # ARABIC LIGATURE AIN WITH YEH FINAL FORM +FCF8 ; [.23D4.0020.001A][.242C.0020.001A] # ARABIC LIGATURE AIN WITH YEH ISOLATED FORM +063A ; [.23D5.0020.0002] # ARABIC LETTER GHAIN +1EE1B ; [.23D5.0020.0005] # ARABIC MATHEMATICAL GHAIN +1EE3B ; [.23D5.0020.0005] # ARABIC MATHEMATICAL INITIAL GHAIN +1EE5B ; [.23D5.0020.0005] # ARABIC MATHEMATICAL TAILED GHAIN +1EE7B ; [.23D5.0020.0005] # ARABIC MATHEMATICAL STRETCHED GHAIN +1EE9B ; [.23D5.0020.0005] # ARABIC MATHEMATICAL LOOPED GHAIN +1EEBB ; [.23D5.0020.0005] # ARABIC MATHEMATICAL DOUBLE-STRUCK GHAIN +FECF ; [.23D5.0020.0017] # ARABIC LETTER GHAIN INITIAL FORM +FED0 ; [.23D5.0020.0018] # ARABIC LETTER GHAIN MEDIAL FORM +FECE ; [.23D5.0020.0019] # ARABIC LETTER GHAIN FINAL FORM +FECD ; [.23D5.0020.001A] # ARABIC LETTER GHAIN ISOLATED FORM +FCBC ; [.23D5.0020.0017][.238B.0020.0017] # ARABIC LIGATURE GHAIN WITH JEEM INITIAL FORM +FC2B ; [.23D5.0020.001A][.238B.0020.001A] # ARABIC LIGATURE GHAIN WITH JEEM ISOLATED FORM +FCBD ; [.23D5.0020.0017][.2409.0020.0017] # ARABIC LIGATURE GHAIN WITH MEEM INITIAL FORM +FC2C ; [.23D5.0020.001A][.2409.0020.001A] # ARABIC LIGATURE GHAIN WITH MEEM ISOLATED FORM +FD79 ; [.23D5.0020.0019][.2409.0020.0019][.2409.0020.0019] # ARABIC LIGATURE GHAIN WITH MEEM WITH MEEM FINAL FORM +FD7B ; [.23D5.0020.0019][.2409.0020.0019][.242B.0020.0019] # ARABIC LIGATURE GHAIN WITH MEEM WITH ALEF MAKSURA FINAL FORM +FD7A ; [.23D5.0020.0019][.2409.0020.0019][.242C.0020.0019] # ARABIC LIGATURE GHAIN WITH MEEM WITH YEH FINAL FORM +FD15 ; [.23D5.0020.0019][.242B.0020.0019] # ARABIC LIGATURE GHAIN WITH ALEF MAKSURA FINAL FORM +FCF9 ; [.23D5.0020.001A][.242B.0020.001A] # ARABIC LIGATURE GHAIN WITH ALEF MAKSURA ISOLATED FORM +FD16 ; [.23D5.0020.0019][.242C.0020.0019] # ARABIC LIGATURE GHAIN WITH YEH FINAL FORM +FCFA ; [.23D5.0020.001A][.242C.0020.001A] # ARABIC LIGATURE GHAIN WITH YEH ISOLATED FORM +06A0 ; [.23D6.0020.0002] # ARABIC LETTER AIN WITH THREE DOTS ABOVE +06FC ; [.23D7.0020.0002] # ARABIC LETTER GHAIN WITH DOT BELOW +075D ; [.23D8.0020.0002] # ARABIC LETTER AIN WITH TWO DOTS ABOVE +075E ; [.23D9.0020.0002] # ARABIC LETTER AIN WITH THREE DOTS POINTING DOWNWARDS ABOVE +075F ; [.23DA.0020.0002] # ARABIC LETTER AIN WITH TWO DOTS VERTICALLY ABOVE +08B3 ; [.23DB.0020.0002] # ARABIC LETTER AIN WITH THREE DOTS BELOW +0641 ; [.23DC.0020.0002] # ARABIC LETTER FEH +1EE10 ; [.23DC.0020.0005] # ARABIC MATHEMATICAL FEH +1EE30 ; [.23DC.0020.0005] # ARABIC MATHEMATICAL INITIAL FEH +1EE70 ; [.23DC.0020.0005] # ARABIC MATHEMATICAL STRETCHED FEH +1EE90 ; [.23DC.0020.0005] # ARABIC MATHEMATICAL LOOPED FEH +1EEB0 ; [.23DC.0020.0005] # ARABIC MATHEMATICAL DOUBLE-STRUCK FEH +FED3 ; [.23DC.0020.0017] # ARABIC LETTER FEH INITIAL FORM +FED4 ; [.23DC.0020.0018] # ARABIC LETTER FEH MEDIAL FORM +FED2 ; [.23DC.0020.0019] # ARABIC LETTER FEH FINAL FORM +FED1 ; [.23DC.0020.001A] # ARABIC LETTER FEH ISOLATED FORM +FCBE ; [.23DC.0020.0017][.238B.0020.0017] # ARABIC LIGATURE FEH WITH JEEM INITIAL FORM +FC2D ; [.23DC.0020.001A][.238B.0020.001A] # ARABIC LIGATURE FEH WITH JEEM ISOLATED FORM +FCBF ; [.23DC.0020.0017][.2392.0020.0017] # ARABIC LIGATURE FEH WITH HAH INITIAL FORM +FC2E ; [.23DC.0020.001A][.2392.0020.001A] # ARABIC LIGATURE FEH WITH HAH ISOLATED FORM +FCC0 ; [.23DC.0020.0017][.2393.0020.0017] # ARABIC LIGATURE FEH WITH KHAH INITIAL FORM +FC2F ; [.23DC.0020.001A][.2393.0020.001A] # ARABIC LIGATURE FEH WITH KHAH ISOLATED FORM +FD7D ; [.23DC.0020.0017][.2393.0020.0017][.2409.0020.0017] # ARABIC LIGATURE FEH WITH KHAH WITH MEEM INITIAL FORM +FD7C ; [.23DC.0020.0019][.2393.0020.0019][.2409.0020.0019] # ARABIC LIGATURE FEH WITH KHAH WITH MEEM FINAL FORM +FCC1 ; [.23DC.0020.0017][.2409.0020.0017] # ARABIC LIGATURE FEH WITH MEEM INITIAL FORM +FC30 ; [.23DC.0020.001A][.2409.0020.001A] # ARABIC LIGATURE FEH WITH MEEM ISOLATED FORM +FDC1 ; [.23DC.0020.0019][.2409.0020.0019][.242C.0020.0019] # ARABIC LIGATURE FEH WITH MEEM WITH YEH FINAL FORM +FC7C ; [.23DC.0020.0019][.242B.0020.0019] # ARABIC LIGATURE FEH WITH ALEF MAKSURA FINAL FORM +FC31 ; [.23DC.0020.001A][.242B.0020.001A] # ARABIC LIGATURE FEH WITH ALEF MAKSURA ISOLATED FORM +FC7D ; [.23DC.0020.0019][.242C.0020.0019] # ARABIC LIGATURE FEH WITH YEH FINAL FORM +FC32 ; [.23DC.0020.001A][.242C.0020.001A] # ARABIC LIGATURE FEH WITH YEH ISOLATED FORM +06A1 ; [.23DD.0020.0002] # ARABIC LETTER DOTLESS FEH +1EE1E ; [.23DD.0020.0005] # ARABIC MATHEMATICAL DOTLESS FEH +1EE7E ; [.23DD.0020.0005] # ARABIC MATHEMATICAL STRETCHED DOTLESS FEH +06A2 ; [.23DE.0020.0002] # ARABIC LETTER FEH WITH DOT MOVED BELOW +08BB ; [.23DF.0020.0002] # ARABIC LETTER AFRICAN FEH +06A3 ; [.23E0.0020.0002] # ARABIC LETTER FEH WITH DOT BELOW +06A4 ; [.23E1.0020.0002] # ARABIC LETTER VEH +FB6C ; [.23E1.0020.0017] # ARABIC LETTER VEH INITIAL FORM +FB6D ; [.23E1.0020.0018] # ARABIC LETTER VEH MEDIAL FORM +FB6B ; [.23E1.0020.0019] # ARABIC LETTER VEH FINAL FORM +FB6A ; [.23E1.0020.001A] # ARABIC LETTER VEH ISOLATED FORM +08A4 ; [.23E2.0020.0002] # ARABIC LETTER FEH WITH DOT BELOW AND THREE DOTS ABOVE +06A5 ; [.23E3.0020.0002] # ARABIC LETTER FEH WITH THREE DOTS BELOW +06A6 ; [.23E4.0020.0002] # ARABIC LETTER PEHEH +FB70 ; [.23E4.0020.0017] # ARABIC LETTER PEHEH INITIAL FORM +FB71 ; [.23E4.0020.0018] # ARABIC LETTER PEHEH MEDIAL FORM +FB6F ; [.23E4.0020.0019] # ARABIC LETTER PEHEH FINAL FORM +FB6E ; [.23E4.0020.001A] # ARABIC LETTER PEHEH ISOLATED FORM +0760 ; [.23E5.0020.0002] # ARABIC LETTER FEH WITH TWO DOTS BELOW +0761 ; [.23E6.0020.0002] # ARABIC LETTER FEH WITH THREE DOTS POINTING UPWARDS BELOW +066F ; [.23E7.0020.0002] # ARABIC LETTER DOTLESS QAF +1EE1F ; [.23E7.0020.0005] # ARABIC MATHEMATICAL DOTLESS QAF +1EE5F ; [.23E7.0020.0005] # ARABIC MATHEMATICAL TAILED DOTLESS QAF +0642 ; [.23E8.0020.0002] # ARABIC LETTER QAF +1EE12 ; [.23E8.0020.0005] # ARABIC MATHEMATICAL QAF +1EE32 ; [.23E8.0020.0005] # ARABIC MATHEMATICAL INITIAL QAF +1EE52 ; [.23E8.0020.0005] # ARABIC MATHEMATICAL TAILED QAF +1EE72 ; [.23E8.0020.0005] # ARABIC MATHEMATICAL STRETCHED QAF +1EE92 ; [.23E8.0020.0005] # ARABIC MATHEMATICAL LOOPED QAF +1EEB2 ; [.23E8.0020.0005] # ARABIC MATHEMATICAL DOUBLE-STRUCK QAF +FED7 ; [.23E8.0020.0017] # ARABIC LETTER QAF INITIAL FORM +FED8 ; [.23E8.0020.0018] # ARABIC LETTER QAF MEDIAL FORM +FED6 ; [.23E8.0020.0019] # ARABIC LETTER QAF FINAL FORM +FED5 ; [.23E8.0020.001A] # ARABIC LETTER QAF ISOLATED FORM +FCC2 ; [.23E8.0020.0017][.2392.0020.0017] # ARABIC LIGATURE QAF WITH HAH INITIAL FORM +FC33 ; [.23E8.0020.001A][.2392.0020.001A] # ARABIC LIGATURE QAF WITH HAH ISOLATED FORM +FDF1 ; [.23E8.0020.001A][.2402.0020.001A][.243A.0020.001A] # ARABIC LIGATURE QALA USED AS KORANIC STOP SIGN ISOLATED FORM +FCC3 ; [.23E8.0020.0017][.2409.0020.0017] # ARABIC LIGATURE QAF WITH MEEM INITIAL FORM +FC34 ; [.23E8.0020.001A][.2409.0020.001A] # ARABIC LIGATURE QAF WITH MEEM ISOLATED FORM +FDB4 ; [.23E8.0020.0017][.2409.0020.0017][.2392.0020.0017] # ARABIC LIGATURE QAF WITH MEEM WITH HAH INITIAL FORM +FD7E ; [.23E8.0020.0019][.2409.0020.0019][.2392.0020.0019] # ARABIC LIGATURE QAF WITH MEEM WITH HAH FINAL FORM +FD7F ; [.23E8.0020.0019][.2409.0020.0019][.2409.0020.0019] # ARABIC LIGATURE QAF WITH MEEM WITH MEEM FINAL FORM +FDB2 ; [.23E8.0020.0019][.2409.0020.0019][.242C.0020.0019] # ARABIC LIGATURE QAF WITH MEEM WITH YEH FINAL FORM +FC7E ; [.23E8.0020.0019][.242B.0020.0019] # ARABIC LIGATURE QAF WITH ALEF MAKSURA FINAL FORM +FC35 ; [.23E8.0020.001A][.242B.0020.001A] # ARABIC LIGATURE QAF WITH ALEF MAKSURA ISOLATED FORM +FC7F ; [.23E8.0020.0019][.242C.0020.0019] # ARABIC LIGATURE QAF WITH YEH FINAL FORM +FC36 ; [.23E8.0020.001A][.242C.0020.001A] # ARABIC LIGATURE QAF WITH YEH ISOLATED FORM +06A7 ; [.23E9.0020.0002] # ARABIC LETTER QAF WITH DOT ABOVE +08BC ; [.23EA.0020.0002] # ARABIC LETTER AFRICAN QAF +06A8 ; [.23EB.0020.0002] # ARABIC LETTER QAF WITH THREE DOTS ABOVE +08A5 ; [.23EC.0020.0002] # ARABIC LETTER QAF WITH DOT BELOW +0643 ; [.23ED.0020.0002] # ARABIC LETTER KAF +1EE0A ; [.23ED.0020.0005] # ARABIC MATHEMATICAL KAF +1EE2A ; [.23ED.0020.0005] # ARABIC MATHEMATICAL INITIAL KAF +1EE6A ; [.23ED.0020.0005] # ARABIC MATHEMATICAL STRETCHED KAF +FEDB ; [.23ED.0020.0017] # ARABIC LETTER KAF INITIAL FORM +FEDC ; [.23ED.0020.0018] # ARABIC LETTER KAF MEDIAL FORM +FEDA ; [.23ED.0020.0019] # ARABIC LETTER KAF FINAL FORM +FED9 ; [.23ED.0020.001A] # ARABIC LETTER KAF ISOLATED FORM +FC80 ; [.23ED.0020.0019][.2371.0020.0019] # ARABIC LIGATURE KAF WITH ALEF FINAL FORM +FC37 ; [.23ED.0020.001A][.2371.0020.001A] # ARABIC LIGATURE KAF WITH ALEF ISOLATED FORM +FCC4 ; [.23ED.0020.0017][.238B.0020.0017] # ARABIC LIGATURE KAF WITH JEEM INITIAL FORM +FC38 ; [.23ED.0020.001A][.238B.0020.001A] # ARABIC LIGATURE KAF WITH JEEM ISOLATED FORM +FCC5 ; [.23ED.0020.0017][.2392.0020.0017] # ARABIC LIGATURE KAF WITH HAH INITIAL FORM +FC39 ; [.23ED.0020.001A][.2392.0020.001A] # ARABIC LIGATURE KAF WITH HAH ISOLATED FORM +FCC6 ; [.23ED.0020.0017][.2393.0020.0017] # ARABIC LIGATURE KAF WITH KHAH INITIAL FORM +FC3A ; [.23ED.0020.001A][.2393.0020.001A] # ARABIC LIGATURE KAF WITH KHAH ISOLATED FORM +FCC7 ; [.23ED.0020.0017][.2402.0020.0017] # ARABIC LIGATURE KAF WITH LAM INITIAL FORM +FCEB ; [.23ED.0020.0018][.2402.0020.0018] # ARABIC LIGATURE KAF WITH LAM MEDIAL FORM +FC81 ; [.23ED.0020.0019][.2402.0020.0019] # ARABIC LIGATURE KAF WITH LAM FINAL FORM +FC3B ; [.23ED.0020.001A][.2402.0020.001A] # ARABIC LIGATURE KAF WITH LAM ISOLATED FORM +FCC8 ; [.23ED.0020.0017][.2409.0020.0017] # ARABIC LIGATURE KAF WITH MEEM INITIAL FORM +FCEC ; [.23ED.0020.0018][.2409.0020.0018] # ARABIC LIGATURE KAF WITH MEEM MEDIAL FORM +FC82 ; [.23ED.0020.0019][.2409.0020.0019] # ARABIC LIGATURE KAF WITH MEEM FINAL FORM +FC3C ; [.23ED.0020.001A][.2409.0020.001A] # ARABIC LIGATURE KAF WITH MEEM ISOLATED FORM +FDC3 ; [.23ED.0020.0017][.2409.0020.0017][.2409.0020.0017] # ARABIC LIGATURE KAF WITH MEEM WITH MEEM INITIAL FORM +FDBB ; [.23ED.0020.0019][.2409.0020.0019][.2409.0020.0019] # ARABIC LIGATURE KAF WITH MEEM WITH MEEM FINAL FORM +FDB7 ; [.23ED.0020.0019][.2409.0020.0019][.242C.0020.0019] # ARABIC LIGATURE KAF WITH MEEM WITH YEH FINAL FORM +FC83 ; [.23ED.0020.0019][.242B.0020.0019] # ARABIC LIGATURE KAF WITH ALEF MAKSURA FINAL FORM +FC3D ; [.23ED.0020.001A][.242B.0020.001A] # ARABIC LIGATURE KAF WITH ALEF MAKSURA ISOLATED FORM +FC84 ; [.23ED.0020.0019][.242C.0020.0019] # ARABIC LIGATURE KAF WITH YEH FINAL FORM +FC3E ; [.23ED.0020.001A][.242C.0020.001A] # ARABIC LIGATURE KAF WITH YEH ISOLATED FORM +06A9 ; [.23EE.0020.0002] # ARABIC LETTER KEHEH +FB90 ; [.23EE.0020.0017] # ARABIC LETTER KEHEH INITIAL FORM +FB91 ; [.23EE.0020.0018] # ARABIC LETTER KEHEH MEDIAL FORM +FB8F ; [.23EE.0020.0019] # ARABIC LETTER KEHEH FINAL FORM +FB8E ; [.23EE.0020.001A] # ARABIC LETTER KEHEH ISOLATED FORM +06AA ; [.23EF.0020.0002] # ARABIC LETTER SWASH KAF +06AB ; [.23F0.0020.0002] # ARABIC LETTER KAF WITH RING +06AC ; [.23F1.0020.0002] # ARABIC LETTER KAF WITH DOT ABOVE +077F ; [.23F2.0020.0002] # ARABIC LETTER KAF WITH TWO DOTS ABOVE +06AD ; [.23F3.0020.0002] # ARABIC LETTER NG +FBD5 ; [.23F3.0020.0017] # ARABIC LETTER NG INITIAL FORM +FBD6 ; [.23F3.0020.0018] # ARABIC LETTER NG MEDIAL FORM +FBD4 ; [.23F3.0020.0019] # ARABIC LETTER NG FINAL FORM +FBD3 ; [.23F3.0020.001A] # ARABIC LETTER NG ISOLATED FORM +06AE ; [.23F4.0020.0002] # ARABIC LETTER KAF WITH THREE DOTS BELOW +08B4 ; [.23F5.0020.0002] # ARABIC LETTER KAF WITH DOT BELOW +06AF ; [.23F6.0020.0002] # ARABIC LETTER GAF +FB94 ; [.23F6.0020.0017] # ARABIC LETTER GAF INITIAL FORM +FB95 ; [.23F6.0020.0018] # ARABIC LETTER GAF MEDIAL FORM +FB93 ; [.23F6.0020.0019] # ARABIC LETTER GAF FINAL FORM +FB92 ; [.23F6.0020.001A] # ARABIC LETTER GAF ISOLATED FORM +08B0 ; [.23F7.0020.0002] # ARABIC LETTER GAF WITH INVERTED STROKE +06B0 ; [.23F8.0020.0002] # ARABIC LETTER GAF WITH RING +06B1 ; [.23F9.0020.0002] # ARABIC LETTER NGOEH +FB9C ; [.23F9.0020.0017] # ARABIC LETTER NGOEH INITIAL FORM +FB9D ; [.23F9.0020.0018] # ARABIC LETTER NGOEH MEDIAL FORM +FB9B ; [.23F9.0020.0019] # ARABIC LETTER NGOEH FINAL FORM +FB9A ; [.23F9.0020.001A] # ARABIC LETTER NGOEH ISOLATED FORM +06B2 ; [.23FA.0020.0002] # ARABIC LETTER GAF WITH TWO DOTS BELOW +06B3 ; [.23FB.0020.0002] # ARABIC LETTER GUEH +FB98 ; [.23FB.0020.0017] # ARABIC LETTER GUEH INITIAL FORM +FB99 ; [.23FB.0020.0018] # ARABIC LETTER GUEH MEDIAL FORM +FB97 ; [.23FB.0020.0019] # ARABIC LETTER GUEH FINAL FORM +FB96 ; [.23FB.0020.001A] # ARABIC LETTER GUEH ISOLATED FORM +06B4 ; [.23FC.0020.0002] # ARABIC LETTER GAF WITH THREE DOTS ABOVE +0762 ; [.23FD.0020.0002] # ARABIC LETTER KEHEH WITH DOT ABOVE +063B ; [.23FE.0020.0002] # ARABIC LETTER KEHEH WITH TWO DOTS ABOVE +063C ; [.23FF.0020.0002] # ARABIC LETTER KEHEH WITH THREE DOTS BELOW +0763 ; [.2400.0020.0002] # ARABIC LETTER KEHEH WITH THREE DOTS ABOVE +0764 ; [.2401.0020.0002] # ARABIC LETTER KEHEH WITH THREE DOTS POINTING UPWARDS BELOW +0644 ; [.2402.0020.0002] # ARABIC LETTER LAM +1EE0B ; [.2402.0020.0005] # ARABIC MATHEMATICAL LAM +1EE2B ; [.2402.0020.0005] # ARABIC MATHEMATICAL INITIAL LAM +1EE4B ; [.2402.0020.0005] # ARABIC MATHEMATICAL TAILED LAM +1EE8B ; [.2402.0020.0005] # ARABIC MATHEMATICAL LOOPED LAM +1EEAB ; [.2402.0020.0005] # ARABIC MATHEMATICAL DOUBLE-STRUCK LAM +FEDF ; [.2402.0020.0017] # ARABIC LETTER LAM INITIAL FORM +FEE0 ; [.2402.0020.0018] # ARABIC LETTER LAM MEDIAL FORM +FEDE ; [.2402.0020.0019] # ARABIC LETTER LAM FINAL FORM +FEDD ; [.2402.0020.001A] # ARABIC LETTER LAM ISOLATED FORM +FEF6 ; [.2402.0020.0019][.2364.0020.0019] # ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE FINAL FORM +FEF5 ; [.2402.0020.001A][.2364.0020.001A] # ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE ISOLATED FORM +FEF8 ; [.2402.0020.0019][.2365.0020.0019] # ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE FINAL FORM +FEF7 ; [.2402.0020.001A][.2365.0020.001A] # ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE ISOLATED FORM +FEFA ; [.2402.0020.0019][.2369.0020.0019] # ARABIC LIGATURE LAM WITH ALEF WITH HAMZA BELOW FINAL FORM +FEF9 ; [.2402.0020.001A][.2369.0020.001A] # ARABIC LIGATURE LAM WITH ALEF WITH HAMZA BELOW ISOLATED FORM +FEFC ; [.2402.0020.0019][.2371.0020.0019] # ARABIC LIGATURE LAM WITH ALEF FINAL FORM +FEFB ; [.2402.0020.001A][.2371.0020.001A] # ARABIC LIGATURE LAM WITH ALEF ISOLATED FORM +FCC9 ; [.2402.0020.0017][.238B.0020.0017] # ARABIC LIGATURE LAM WITH JEEM INITIAL FORM +FC3F ; [.2402.0020.001A][.238B.0020.001A] # ARABIC LIGATURE LAM WITH JEEM ISOLATED FORM +FD83 ; [.2402.0020.0017][.238B.0020.0017][.238B.0020.0017] # ARABIC LIGATURE LAM WITH JEEM WITH JEEM INITIAL FORM +FD84 ; [.2402.0020.0019][.238B.0020.0019][.238B.0020.0019] # ARABIC LIGATURE LAM WITH JEEM WITH JEEM FINAL FORM +FDBA ; [.2402.0020.0017][.238B.0020.0017][.2409.0020.0017] # ARABIC LIGATURE LAM WITH JEEM WITH MEEM INITIAL FORM +FDBC ; [.2402.0020.0019][.238B.0020.0019][.2409.0020.0019] # ARABIC LIGATURE LAM WITH JEEM WITH MEEM FINAL FORM +FDAC ; [.2402.0020.0019][.238B.0020.0019][.242C.0020.0019] # ARABIC LIGATURE LAM WITH JEEM WITH YEH FINAL FORM +FCCA ; [.2402.0020.0017][.2392.0020.0017] # ARABIC LIGATURE LAM WITH HAH INITIAL FORM +FC40 ; [.2402.0020.001A][.2392.0020.001A] # ARABIC LIGATURE LAM WITH HAH ISOLATED FORM +FDB5 ; [.2402.0020.0017][.2392.0020.0017][.2409.0020.0017] # ARABIC LIGATURE LAM WITH HAH WITH MEEM INITIAL FORM +FD80 ; [.2402.0020.0019][.2392.0020.0019][.2409.0020.0019] # ARABIC LIGATURE LAM WITH HAH WITH MEEM FINAL FORM +FD82 ; [.2402.0020.0019][.2392.0020.0019][.242B.0020.0019] # ARABIC LIGATURE LAM WITH HAH WITH ALEF MAKSURA FINAL FORM +FD81 ; [.2402.0020.0019][.2392.0020.0019][.242C.0020.0019] # ARABIC LIGATURE LAM WITH HAH WITH YEH FINAL FORM +FCCB ; [.2402.0020.0017][.2393.0020.0017] # ARABIC LIGATURE LAM WITH KHAH INITIAL FORM +FC41 ; [.2402.0020.001A][.2393.0020.001A] # ARABIC LIGATURE LAM WITH KHAH ISOLATED FORM +FD86 ; [.2402.0020.0017][.2393.0020.0017][.2409.0020.0017] # ARABIC LIGATURE LAM WITH KHAH WITH MEEM INITIAL FORM +FD85 ; [.2402.0020.0019][.2393.0020.0019][.2409.0020.0019] # ARABIC LIGATURE LAM WITH KHAH WITH MEEM FINAL FORM +FCCC ; [.2402.0020.0017][.2409.0020.0017] # ARABIC LIGATURE LAM WITH MEEM INITIAL FORM +FCED ; [.2402.0020.0018][.2409.0020.0018] # ARABIC LIGATURE LAM WITH MEEM MEDIAL FORM +FC85 ; [.2402.0020.0019][.2409.0020.0019] # ARABIC LIGATURE LAM WITH MEEM FINAL FORM +FC42 ; [.2402.0020.001A][.2409.0020.001A] # ARABIC LIGATURE LAM WITH MEEM ISOLATED FORM +FD88 ; [.2402.0020.0017][.2409.0020.0017][.2392.0020.0017] # ARABIC LIGATURE LAM WITH MEEM WITH HAH INITIAL FORM +FD87 ; [.2402.0020.0019][.2409.0020.0019][.2392.0020.0019] # ARABIC LIGATURE LAM WITH MEEM WITH HAH FINAL FORM +FDAD ; [.2402.0020.0019][.2409.0020.0019][.242C.0020.0019] # ARABIC LIGATURE LAM WITH MEEM WITH YEH FINAL FORM +FCCD ; [.2402.0020.0017][.2417.0020.0017] # ARABIC LIGATURE LAM WITH HEH INITIAL FORM +FC86 ; [.2402.0020.0019][.242B.0020.0019] # ARABIC LIGATURE LAM WITH ALEF MAKSURA FINAL FORM +FC43 ; [.2402.0020.001A][.242B.0020.001A] # ARABIC LIGATURE LAM WITH ALEF MAKSURA ISOLATED FORM +FC87 ; [.2402.0020.0019][.242C.0020.0019] # ARABIC LIGATURE LAM WITH YEH FINAL FORM +FC44 ; [.2402.0020.001A][.242C.0020.001A] # ARABIC LIGATURE LAM WITH YEH ISOLATED FORM +06B5 ; [.2403.0020.0002] # ARABIC LETTER LAM WITH SMALL V +06B6 ; [.2404.0020.0002] # ARABIC LETTER LAM WITH DOT ABOVE +06B7 ; [.2405.0020.0002] # ARABIC LETTER LAM WITH THREE DOTS ABOVE +06B8 ; [.2406.0020.0002] # ARABIC LETTER LAM WITH THREE DOTS BELOW +076A ; [.2407.0020.0002] # ARABIC LETTER LAM WITH BAR +08A6 ; [.2408.0020.0002] # ARABIC LETTER LAM WITH DOUBLE BAR +0645 ; [.2409.0020.0002] # ARABIC LETTER MEEM +1EE0C ; [.2409.0020.0005] # ARABIC MATHEMATICAL MEEM +1EE2C ; [.2409.0020.0005] # ARABIC MATHEMATICAL INITIAL MEEM +1EE6C ; [.2409.0020.0005] # ARABIC MATHEMATICAL STRETCHED MEEM +1EE8C ; [.2409.0020.0005] # ARABIC MATHEMATICAL LOOPED MEEM +1EEAC ; [.2409.0020.0005] # ARABIC MATHEMATICAL DOUBLE-STRUCK MEEM +FEE3 ; [.2409.0020.0017] # ARABIC LETTER MEEM INITIAL FORM +FEE4 ; [.2409.0020.0018] # ARABIC LETTER MEEM MEDIAL FORM +FEE2 ; [.2409.0020.0019] # ARABIC LETTER MEEM FINAL FORM +FEE1 ; [.2409.0020.001A] # ARABIC LETTER MEEM ISOLATED FORM +06FE ; [.2409.0020.0004][.0000.0112.0004] # ARABIC SIGN SINDHI POSTPOSITION MEN +FC88 ; [.2409.0020.0019][.2371.0020.0019] # ARABIC LIGATURE MEEM WITH ALEF FINAL FORM +FCCE ; [.2409.0020.0017][.238B.0020.0017] # ARABIC LIGATURE MEEM WITH JEEM INITIAL FORM +FC45 ; [.2409.0020.001A][.238B.0020.001A] # ARABIC LIGATURE MEEM WITH JEEM ISOLATED FORM +FD8C ; [.2409.0020.0017][.238B.0020.0017][.2392.0020.0017] # ARABIC LIGATURE MEEM WITH JEEM WITH HAH INITIAL FORM +FD92 ; [.2409.0020.0017][.238B.0020.0017][.2393.0020.0017] # ARABIC LIGATURE MEEM WITH JEEM WITH KHAH INITIAL FORM +FD8D ; [.2409.0020.0017][.238B.0020.0017][.2409.0020.0017] # ARABIC LIGATURE MEEM WITH JEEM WITH MEEM INITIAL FORM +FDC0 ; [.2409.0020.0019][.238B.0020.0019][.242C.0020.0019] # ARABIC LIGATURE MEEM WITH JEEM WITH YEH FINAL FORM +FCCF ; [.2409.0020.0017][.2392.0020.0017] # ARABIC LIGATURE MEEM WITH HAH INITIAL FORM +FC46 ; [.2409.0020.001A][.2392.0020.001A] # ARABIC LIGATURE MEEM WITH HAH ISOLATED FORM +FD89 ; [.2409.0020.0017][.2392.0020.0017][.238B.0020.0017] # ARABIC LIGATURE MEEM WITH HAH WITH JEEM INITIAL FORM +FD8A ; [.2409.0020.0017][.2392.0020.0017][.2409.0020.0017] # ARABIC LIGATURE MEEM WITH HAH WITH MEEM INITIAL FORM +FDF4 ; [.2409.0020.001A][.2392.0020.001A][.2409.0020.001A][.239D.0020.001A] # ARABIC LIGATURE MOHAMMAD ISOLATED FORM +FD8B ; [.2409.0020.0019][.2392.0020.0019][.242C.0020.0019] # ARABIC LIGATURE MEEM WITH HAH WITH YEH FINAL FORM +FCD0 ; [.2409.0020.0017][.2393.0020.0017] # ARABIC LIGATURE MEEM WITH KHAH INITIAL FORM +FC47 ; [.2409.0020.001A][.2393.0020.001A] # ARABIC LIGATURE MEEM WITH KHAH ISOLATED FORM +FD8E ; [.2409.0020.0017][.2393.0020.0017][.238B.0020.0017] # ARABIC LIGATURE MEEM WITH KHAH WITH JEEM INITIAL FORM +FD8F ; [.2409.0020.0017][.2393.0020.0017][.2409.0020.0017] # ARABIC LIGATURE MEEM WITH KHAH WITH MEEM INITIAL FORM +FDB9 ; [.2409.0020.0019][.2393.0020.0019][.242C.0020.0019] # ARABIC LIGATURE MEEM WITH KHAH WITH YEH FINAL FORM +FCD1 ; [.2409.0020.0017][.2409.0020.0017] # ARABIC LIGATURE MEEM WITH MEEM INITIAL FORM +FC89 ; [.2409.0020.0019][.2409.0020.0019] # ARABIC LIGATURE MEEM WITH MEEM FINAL FORM +FC48 ; [.2409.0020.001A][.2409.0020.001A] # ARABIC LIGATURE MEEM WITH MEEM ISOLATED FORM +FDB1 ; [.2409.0020.0019][.2409.0020.0019][.242C.0020.0019] # ARABIC LIGATURE MEEM WITH MEEM WITH YEH FINAL FORM +FC49 ; [.2409.0020.001A][.242B.0020.001A] # ARABIC LIGATURE MEEM WITH ALEF MAKSURA ISOLATED FORM +FC4A ; [.2409.0020.001A][.242C.0020.001A] # ARABIC LIGATURE MEEM WITH YEH ISOLATED FORM +0765 ; [.240A.0020.0002] # ARABIC LETTER MEEM WITH DOT ABOVE +0766 ; [.240B.0020.0002] # ARABIC LETTER MEEM WITH DOT BELOW +08A7 ; [.240C.0020.0002] # ARABIC LETTER MEEM WITH THREE DOTS ABOVE +0646 ; [.240D.0020.0002] # ARABIC LETTER NOON +1EE0D ; [.240D.0020.0005] # ARABIC MATHEMATICAL NOON +1EE2D ; [.240D.0020.0005] # ARABIC MATHEMATICAL INITIAL NOON +1EE4D ; [.240D.0020.0005] # ARABIC MATHEMATICAL TAILED NOON +1EE6D ; [.240D.0020.0005] # ARABIC MATHEMATICAL STRETCHED NOON +1EE8D ; [.240D.0020.0005] # ARABIC MATHEMATICAL LOOPED NOON +1EEAD ; [.240D.0020.0005] # ARABIC MATHEMATICAL DOUBLE-STRUCK NOON +FEE7 ; [.240D.0020.0017] # ARABIC LETTER NOON INITIAL FORM +FEE8 ; [.240D.0020.0018] # ARABIC LETTER NOON MEDIAL FORM +FEE6 ; [.240D.0020.0019] # ARABIC LETTER NOON FINAL FORM +FEE5 ; [.240D.0020.001A] # ARABIC LETTER NOON ISOLATED FORM +FCD2 ; [.240D.0020.0017][.238B.0020.0017] # ARABIC LIGATURE NOON WITH JEEM INITIAL FORM +FC4B ; [.240D.0020.001A][.238B.0020.001A] # ARABIC LIGATURE NOON WITH JEEM ISOLATED FORM +FDB8 ; [.240D.0020.0017][.238B.0020.0017][.2392.0020.0017] # ARABIC LIGATURE NOON WITH JEEM WITH HAH INITIAL FORM +FDBD ; [.240D.0020.0019][.238B.0020.0019][.2392.0020.0019] # ARABIC LIGATURE NOON WITH JEEM WITH HAH FINAL FORM +FD98 ; [.240D.0020.0017][.238B.0020.0017][.2409.0020.0017] # ARABIC LIGATURE NOON WITH JEEM WITH MEEM INITIAL FORM +FD97 ; [.240D.0020.0019][.238B.0020.0019][.2409.0020.0019] # ARABIC LIGATURE NOON WITH JEEM WITH MEEM FINAL FORM +FD99 ; [.240D.0020.0019][.238B.0020.0019][.242B.0020.0019] # ARABIC LIGATURE NOON WITH JEEM WITH ALEF MAKSURA FINAL FORM +FDC7 ; [.240D.0020.0019][.238B.0020.0019][.242C.0020.0019] # ARABIC LIGATURE NOON WITH JEEM WITH YEH FINAL FORM +FCD3 ; [.240D.0020.0017][.2392.0020.0017] # ARABIC LIGATURE NOON WITH HAH INITIAL FORM +FC4C ; [.240D.0020.001A][.2392.0020.001A] # ARABIC LIGATURE NOON WITH HAH ISOLATED FORM +FD95 ; [.240D.0020.0017][.2392.0020.0017][.2409.0020.0017] # ARABIC LIGATURE NOON WITH HAH WITH MEEM INITIAL FORM +FD96 ; [.240D.0020.0019][.2392.0020.0019][.242B.0020.0019] # ARABIC LIGATURE NOON WITH HAH WITH ALEF MAKSURA FINAL FORM +FDB3 ; [.240D.0020.0019][.2392.0020.0019][.242C.0020.0019] # ARABIC LIGATURE NOON WITH HAH WITH YEH FINAL FORM +FCD4 ; [.240D.0020.0017][.2393.0020.0017] # ARABIC LIGATURE NOON WITH KHAH INITIAL FORM +FC4D ; [.240D.0020.001A][.2393.0020.001A] # ARABIC LIGATURE NOON WITH KHAH ISOLATED FORM +FC8A ; [.240D.0020.0019][.23AC.0020.0019] # ARABIC LIGATURE NOON WITH REH FINAL FORM +FC8B ; [.240D.0020.0019][.23AD.0020.0019] # ARABIC LIGATURE NOON WITH ZAIN FINAL FORM +FCD5 ; [.240D.0020.0017][.2409.0020.0017] # ARABIC LIGATURE NOON WITH MEEM INITIAL FORM +FCEE ; [.240D.0020.0018][.2409.0020.0018] # ARABIC LIGATURE NOON WITH MEEM MEDIAL FORM +FC8C ; [.240D.0020.0019][.2409.0020.0019] # ARABIC LIGATURE NOON WITH MEEM FINAL FORM +FC4E ; [.240D.0020.001A][.2409.0020.001A] # ARABIC LIGATURE NOON WITH MEEM ISOLATED FORM +FD9B ; [.240D.0020.0019][.2409.0020.0019][.242B.0020.0019] # ARABIC LIGATURE NOON WITH MEEM WITH ALEF MAKSURA FINAL FORM +FD9A ; [.240D.0020.0019][.2409.0020.0019][.242C.0020.0019] # ARABIC LIGATURE NOON WITH MEEM WITH YEH FINAL FORM +FC8D ; [.240D.0020.0019][.240D.0020.0019] # ARABIC LIGATURE NOON WITH NOON FINAL FORM +FCD6 ; [.240D.0020.0017][.2417.0020.0017] # ARABIC LIGATURE NOON WITH HEH INITIAL FORM +FCEF ; [.240D.0020.0018][.2417.0020.0018] # ARABIC LIGATURE NOON WITH HEH MEDIAL FORM +FC8E ; [.240D.0020.0019][.242B.0020.0019] # ARABIC LIGATURE NOON WITH ALEF MAKSURA FINAL FORM +FC4F ; [.240D.0020.001A][.242B.0020.001A] # ARABIC LIGATURE NOON WITH ALEF MAKSURA ISOLATED FORM +FC8F ; [.240D.0020.0019][.242C.0020.0019] # ARABIC LIGATURE NOON WITH YEH FINAL FORM +FC50 ; [.240D.0020.001A][.242C.0020.001A] # ARABIC LIGATURE NOON WITH YEH ISOLATED FORM +06BA ; [.240E.0020.0002] # ARABIC LETTER NOON GHUNNA +1EE1D ; [.240E.0020.0005] # ARABIC MATHEMATICAL DOTLESS NOON +1EE5D ; [.240E.0020.0005] # ARABIC MATHEMATICAL TAILED DOTLESS NOON +FB9F ; [.240E.0020.0019] # ARABIC LETTER NOON GHUNNA FINAL FORM +FB9E ; [.240E.0020.001A] # ARABIC LETTER NOON GHUNNA ISOLATED FORM +08BD ; [.240F.0020.0002] # ARABIC LETTER AFRICAN NOON +06BB ; [.2410.0020.0002] # ARABIC LETTER RNOON +FBA2 ; [.2410.0020.0017] # ARABIC LETTER RNOON INITIAL FORM +FBA3 ; [.2410.0020.0018] # ARABIC LETTER RNOON MEDIAL FORM +FBA1 ; [.2410.0020.0019] # ARABIC LETTER RNOON FINAL FORM +FBA0 ; [.2410.0020.001A] # ARABIC LETTER RNOON ISOLATED FORM +06BC ; [.2411.0020.0002] # ARABIC LETTER NOON WITH RING +06BD ; [.2412.0020.0002] # ARABIC LETTER NOON WITH THREE DOTS ABOVE +06B9 ; [.2413.0020.0002] # ARABIC LETTER NOON WITH DOT BELOW +0767 ; [.2414.0020.0002] # ARABIC LETTER NOON WITH TWO DOTS BELOW +0768 ; [.2415.0020.0002] # ARABIC LETTER NOON WITH SMALL TAH +0769 ; [.2416.0020.0002] # ARABIC LETTER NOON WITH SMALL V +0647 ; [.2417.0020.0002] # ARABIC LETTER HEH +1EE24 ; [.2417.0020.0005] # ARABIC MATHEMATICAL INITIAL HEH +1EE64 ; [.2417.0020.0005] # ARABIC MATHEMATICAL STRETCHED HEH +1EE84 ; [.2417.0020.0005] # ARABIC MATHEMATICAL LOOPED HEH +FEEB ; [.2417.0020.0017] # ARABIC LETTER HEH INITIAL FORM +FEEC ; [.2417.0020.0018] # ARABIC LETTER HEH MEDIAL FORM +FEEA ; [.2417.0020.0019] # ARABIC LETTER HEH FINAL FORM +FEE9 ; [.2417.0020.001A] # ARABIC LETTER HEH ISOLATED FORM +FCD9 ; [.2417.0020.0017][.0000.0098.0017] # ARABIC LIGATURE HEH WITH SUPERSCRIPT ALEF INITIAL FORM +FCD7 ; [.2417.0020.0017][.238B.0020.0017] # ARABIC LIGATURE HEH WITH JEEM INITIAL FORM +FC51 ; [.2417.0020.001A][.238B.0020.001A] # ARABIC LIGATURE HEH WITH JEEM ISOLATED FORM +FCD8 ; [.2417.0020.0017][.2409.0020.0017] # ARABIC LIGATURE HEH WITH MEEM INITIAL FORM +FC52 ; [.2417.0020.001A][.2409.0020.001A] # ARABIC LIGATURE HEH WITH MEEM ISOLATED FORM +FD93 ; [.2417.0020.0017][.2409.0020.0017][.238B.0020.0017] # ARABIC LIGATURE HEH WITH MEEM WITH JEEM INITIAL FORM +FD94 ; [.2417.0020.0017][.2409.0020.0017][.2409.0020.0017] # ARABIC LIGATURE HEH WITH MEEM WITH MEEM INITIAL FORM +FC53 ; [.2417.0020.001A][.242B.0020.001A] # ARABIC LIGATURE HEH WITH ALEF MAKSURA ISOLATED FORM +FC54 ; [.2417.0020.001A][.242C.0020.001A] # ARABIC LIGATURE HEH WITH YEH ISOLATED FORM +06BE ; [.2418.0020.0002] # ARABIC LETTER HEH DOACHASHMEE +FBAC ; [.2418.0020.0017] # ARABIC LETTER HEH DOACHASHMEE INITIAL FORM +FBAD ; [.2418.0020.0018] # ARABIC LETTER HEH DOACHASHMEE MEDIAL FORM +FBAB ; [.2418.0020.0019] # ARABIC LETTER HEH DOACHASHMEE FINAL FORM +FBAA ; [.2418.0020.001A] # ARABIC LETTER HEH DOACHASHMEE ISOLATED FORM +06C1 ; [.2419.0020.0002] # ARABIC LETTER HEH GOAL +FBA8 ; [.2419.0020.0017] # ARABIC LETTER HEH GOAL INITIAL FORM +FBA9 ; [.2419.0020.0018] # ARABIC LETTER HEH GOAL MEDIAL FORM +FBA7 ; [.2419.0020.0019] # ARABIC LETTER HEH GOAL FINAL FORM +FBA6 ; [.2419.0020.001A] # ARABIC LETTER HEH GOAL ISOLATED FORM +06C2 ; [.2419.0020.0002][.0000.0083.0002] # ARABIC LETTER HEH GOAL WITH HAMZA ABOVE +06C3 ; [.241A.0020.0002] # ARABIC LETTER TEH MARBUTA GOAL +06FF ; [.241B.0020.0002] # ARABIC LETTER HEH WITH INVERTED V +06D5 ; [.241C.0020.0002] # ARABIC LETTER AE +06C0 ; [.241C.0020.0002][.0000.0083.0002] # ARABIC LETTER HEH WITH YEH ABOVE +FBA5 ; [.241C.0020.0019][.0000.0083.0019] # ARABIC LETTER HEH WITH YEH ABOVE FINAL FORM +FBA4 ; [.241C.0020.001A][.0000.0083.001A] # ARABIC LETTER HEH WITH YEH ABOVE ISOLATED FORM +0648 ; [.241D.0020.0002] # ARABIC LETTER WAW +06E5 ; [.241D.0020.0004] # ARABIC SMALL WAW +1EE05 ; [.241D.0020.0005] # ARABIC MATHEMATICAL WAW +1EE85 ; [.241D.0020.0005] # ARABIC MATHEMATICAL LOOPED WAW +1EEA5 ; [.241D.0020.0005] # ARABIC MATHEMATICAL DOUBLE-STRUCK WAW +FEEE ; [.241D.0020.0019] # ARABIC LETTER WAW FINAL FORM +FEED ; [.241D.0020.001A] # ARABIC LETTER WAW ISOLATED FORM +0676 ; [.241D.0020.0004][.2363.0020.0004] # ARABIC LETTER HIGH HAMZA WAW +FDF8 ; [.241D.0020.001A][.23BF.0020.001A][.2402.0020.001A][.2409.0020.001A] # ARABIC LIGATURE WASALLAM ISOLATED FORM +06C4 ; [.241E.0020.0002] # ARABIC LETTER WAW WITH RING +06C5 ; [.241F.0020.0002] # ARABIC LETTER KIRGHIZ OE +FBE1 ; [.241F.0020.0019] # ARABIC LETTER KIRGHIZ OE FINAL FORM +FBE0 ; [.241F.0020.001A] # ARABIC LETTER KIRGHIZ OE ISOLATED FORM +06C6 ; [.2420.0020.0002] # ARABIC LETTER OE +FBDA ; [.2420.0020.0019] # ARABIC LETTER OE FINAL FORM +FBD9 ; [.2420.0020.001A] # ARABIC LETTER OE ISOLATED FORM +06C7 ; [.2421.0020.0002] # ARABIC LETTER U +FBD8 ; [.2421.0020.0019] # ARABIC LETTER U FINAL FORM +FBD7 ; [.2421.0020.001A] # ARABIC LETTER U ISOLATED FORM +0677 ; [.2421.0020.0004][.2363.0020.0004] # ARABIC LETTER U WITH HAMZA ABOVE +FBDD ; [.2421.0020.001A][.2363.0020.001A] # ARABIC LETTER U WITH HAMZA ABOVE ISOLATED FORM +06C8 ; [.2422.0020.0002] # ARABIC LETTER YU +FBDC ; [.2422.0020.0019] # ARABIC LETTER YU FINAL FORM +FBDB ; [.2422.0020.001A] # ARABIC LETTER YU ISOLATED FORM +06C9 ; [.2423.0020.0002] # ARABIC LETTER KIRGHIZ YU +FBE3 ; [.2423.0020.0019] # ARABIC LETTER KIRGHIZ YU FINAL FORM +FBE2 ; [.2423.0020.001A] # ARABIC LETTER KIRGHIZ YU ISOLATED FORM +06CA ; [.2424.0020.0002] # ARABIC LETTER WAW WITH TWO DOTS ABOVE +06CB ; [.2425.0020.0002] # ARABIC LETTER VE +FBDF ; [.2425.0020.0019] # ARABIC LETTER VE FINAL FORM +FBDE ; [.2425.0020.001A] # ARABIC LETTER VE ISOLATED FORM +08B1 ; [.2426.0020.0002] # ARABIC LETTER STRAIGHT WAW +06CF ; [.2427.0020.0002] # ARABIC LETTER WAW WITH DOT ABOVE +0778 ; [.2428.0020.0002] # ARABIC LETTER WAW WITH EXTENDED ARABIC-INDIC DIGIT TWO ABOVE +0779 ; [.2429.0020.0002] # ARABIC LETTER WAW WITH EXTENDED ARABIC-INDIC DIGIT THREE ABOVE +08AB ; [.242A.0020.0002] # ARABIC LETTER WAW WITH DOT WITHIN +0649 ; [.242B.0020.0002] # ARABIC LETTER ALEF MAKSURA +FBE8 ; [.242B.0020.0017] # ARABIC LETTER UIGHUR KAZAKH KIRGHIZ ALEF MAKSURA INITIAL FORM +FBE9 ; [.242B.0020.0018] # ARABIC LETTER UIGHUR KAZAKH KIRGHIZ ALEF MAKSURA MEDIAL FORM +FEF0 ; [.242B.0020.0019] # ARABIC LETTER ALEF MAKSURA FINAL FORM +FEEF ; [.242B.0020.001A] # ARABIC LETTER ALEF MAKSURA ISOLATED FORM +FC90 ; [.242B.0020.0019][.0000.0098.0019] # ARABIC LIGATURE ALEF MAKSURA WITH SUPERSCRIPT ALEF FINAL FORM +FC5D ; [.242B.0020.001A][.0000.0098.001A] # ARABIC LIGATURE ALEF MAKSURA WITH SUPERSCRIPT ALEF ISOLATED FORM +064A ; [.242C.0020.0002] # ARABIC LETTER YEH +06E6 ; [.242C.0020.0004] # ARABIC SMALL YEH +1EE09 ; [.242C.0020.0005] # ARABIC MATHEMATICAL YEH +1EE29 ; [.242C.0020.0005] # ARABIC MATHEMATICAL INITIAL YEH +1EE49 ; [.242C.0020.0005] # ARABIC MATHEMATICAL TAILED YEH +1EE69 ; [.242C.0020.0005] # ARABIC MATHEMATICAL STRETCHED YEH +1EE89 ; [.242C.0020.0005] # ARABIC MATHEMATICAL LOOPED YEH +1EEA9 ; [.242C.0020.0005] # ARABIC MATHEMATICAL DOUBLE-STRUCK YEH +FEF3 ; [.242C.0020.0017] # ARABIC LETTER YEH INITIAL FORM +FEF4 ; [.242C.0020.0018] # ARABIC LETTER YEH MEDIAL FORM +FEF2 ; [.242C.0020.0019] # ARABIC LETTER YEH FINAL FORM +FEF1 ; [.242C.0020.001A] # ARABIC LETTER YEH ISOLATED FORM +0678 ; [.242C.0020.0004][.2363.0020.0004] # ARABIC LETTER HIGH HAMZA YEH +FCDA ; [.242C.0020.0017][.238B.0020.0017] # ARABIC LIGATURE YEH WITH JEEM INITIAL FORM +FC55 ; [.242C.0020.001A][.238B.0020.001A] # ARABIC LIGATURE YEH WITH JEEM ISOLATED FORM +FDAF ; [.242C.0020.0019][.238B.0020.0019][.242C.0020.0019] # ARABIC LIGATURE YEH WITH JEEM WITH YEH FINAL FORM +FCDB ; [.242C.0020.0017][.2392.0020.0017] # ARABIC LIGATURE YEH WITH HAH INITIAL FORM +FC56 ; [.242C.0020.001A][.2392.0020.001A] # ARABIC LIGATURE YEH WITH HAH ISOLATED FORM +FDAE ; [.242C.0020.0019][.2392.0020.0019][.242C.0020.0019] # ARABIC LIGATURE YEH WITH HAH WITH YEH FINAL FORM +FCDC ; [.242C.0020.0017][.2393.0020.0017] # ARABIC LIGATURE YEH WITH KHAH INITIAL FORM +FC57 ; [.242C.0020.001A][.2393.0020.001A] # ARABIC LIGATURE YEH WITH KHAH ISOLATED FORM +FC91 ; [.242C.0020.0019][.23AC.0020.0019] # ARABIC LIGATURE YEH WITH REH FINAL FORM +FC92 ; [.242C.0020.0019][.23AD.0020.0019] # ARABIC LIGATURE YEH WITH ZAIN FINAL FORM +FCDD ; [.242C.0020.0017][.2409.0020.0017] # ARABIC LIGATURE YEH WITH MEEM INITIAL FORM +FCF0 ; [.242C.0020.0018][.2409.0020.0018] # ARABIC LIGATURE YEH WITH MEEM MEDIAL FORM +FC93 ; [.242C.0020.0019][.2409.0020.0019] # ARABIC LIGATURE YEH WITH MEEM FINAL FORM +FC58 ; [.242C.0020.001A][.2409.0020.001A] # ARABIC LIGATURE YEH WITH MEEM ISOLATED FORM +FD9D ; [.242C.0020.0017][.2409.0020.0017][.2409.0020.0017] # ARABIC LIGATURE YEH WITH MEEM WITH MEEM INITIAL FORM +FD9C ; [.242C.0020.0019][.2409.0020.0019][.2409.0020.0019] # ARABIC LIGATURE YEH WITH MEEM WITH MEEM FINAL FORM +FDB0 ; [.242C.0020.0019][.2409.0020.0019][.242C.0020.0019] # ARABIC LIGATURE YEH WITH MEEM WITH YEH FINAL FORM +FC94 ; [.242C.0020.0019][.240D.0020.0019] # ARABIC LIGATURE YEH WITH NOON FINAL FORM +FCDE ; [.242C.0020.0017][.2417.0020.0017] # ARABIC LIGATURE YEH WITH HEH INITIAL FORM +FCF1 ; [.242C.0020.0018][.2417.0020.0018] # ARABIC LIGATURE YEH WITH HEH MEDIAL FORM +FC95 ; [.242C.0020.0019][.242B.0020.0019] # ARABIC LIGATURE YEH WITH ALEF MAKSURA FINAL FORM +FC59 ; [.242C.0020.001A][.242B.0020.001A] # ARABIC LIGATURE YEH WITH ALEF MAKSURA ISOLATED FORM +FC96 ; [.242C.0020.0019][.242C.0020.0019] # ARABIC LIGATURE YEH WITH YEH FINAL FORM +FC5A ; [.242C.0020.001A][.242C.0020.001A] # ARABIC LIGATURE YEH WITH YEH ISOLATED FORM +06CC ; [.242D.0020.0002] # ARABIC LETTER FARSI YEH +FBFE ; [.242D.0020.0017] # ARABIC LETTER FARSI YEH INITIAL FORM +FBFF ; [.242D.0020.0018] # ARABIC LETTER FARSI YEH MEDIAL FORM +FBFD ; [.242D.0020.0019] # ARABIC LETTER FARSI YEH FINAL FORM +FBFC ; [.242D.0020.001A] # ARABIC LETTER FARSI YEH ISOLATED FORM +06CD ; [.242E.0020.0002] # ARABIC LETTER YEH WITH TAIL +06CE ; [.242F.0020.0002] # ARABIC LETTER YEH WITH SMALL V +06D0 ; [.2430.0020.0002] # ARABIC LETTER E +FBE6 ; [.2430.0020.0017] # ARABIC LETTER E INITIAL FORM +FBE7 ; [.2430.0020.0018] # ARABIC LETTER E MEDIAL FORM +FBE5 ; [.2430.0020.0019] # ARABIC LETTER E FINAL FORM +FBE4 ; [.2430.0020.001A] # ARABIC LETTER E ISOLATED FORM +06D1 ; [.2431.0020.0002] # ARABIC LETTER YEH WITH THREE DOTS BELOW +063D ; [.2432.0020.0002] # ARABIC LETTER FARSI YEH WITH INVERTED V +063E ; [.2433.0020.0002] # ARABIC LETTER FARSI YEH WITH TWO DOTS ABOVE +063F ; [.2434.0020.0002] # ARABIC LETTER FARSI YEH WITH THREE DOTS ABOVE +0620 ; [.2435.0020.0002] # ARABIC LETTER KASHMIRI YEH +0775 ; [.2436.0020.0002] # ARABIC LETTER FARSI YEH WITH EXTENDED ARABIC-INDIC DIGIT TWO ABOVE +0776 ; [.2437.0020.0002] # ARABIC LETTER FARSI YEH WITH EXTENDED ARABIC-INDIC DIGIT THREE ABOVE +0777 ; [.2438.0020.0002] # ARABIC LETTER FARSI YEH WITH EXTENDED ARABIC-INDIC DIGIT FOUR BELOW +08BA ; [.2439.0020.0002] # ARABIC LETTER YEH WITH TWO DOTS BELOW AND SMALL NOON ABOVE +06D2 ; [.243A.0020.0002] # ARABIC LETTER YEH BARREE +FBAF ; [.243A.0020.0019] # ARABIC LETTER YEH BARREE FINAL FORM +FBAE ; [.243A.0020.001A] # ARABIC LETTER YEH BARREE ISOLATED FORM +06D3 ; [.243A.0020.0002][.0000.0083.0002] # ARABIC LETTER YEH BARREE WITH HAMZA ABOVE +FBB1 ; [.243A.0020.0019][.0000.0083.0019] # ARABIC LETTER YEH BARREE WITH HAMZA ABOVE FINAL FORM +FBB0 ; [.243A.0020.001A][.0000.0083.001A] # ARABIC LETTER YEH BARREE WITH HAMZA ABOVE ISOLATED FORM +077A ; [.243B.0020.0002] # ARABIC LETTER YEH BARREE WITH EXTENDED ARABIC-INDIC DIGIT TWO ABOVE +077B ; [.243C.0020.0002] # ARABIC LETTER YEH BARREE WITH EXTENDED ARABIC-INDIC DIGIT THREE ABOVE +0710 ; [.243D.0020.0002] # SYRIAC LETTER ALAPH +0712 ; [.243E.0020.0002] # SYRIAC LETTER BETH +072D ; [.243E.0020.0004][.0000.0113.0004] # SYRIAC LETTER PERSIAN BHETH +0713 ; [.243F.0020.0002] # SYRIAC LETTER GAMAL +0714 ; [.243F.0020.0004][.0000.0112.0004] # SYRIAC LETTER GAMAL GARSHUNI +072E ; [.243F.0020.0004][.0000.0113.0004] # SYRIAC LETTER PERSIAN GHAMAL +0716 ; [.2440.0020.0002] # SYRIAC LETTER DOTLESS DALATH RISH +0715 ; [.2441.0020.0002] # SYRIAC LETTER DALATH +072F ; [.2441.0020.0004][.0000.0113.0004] # SYRIAC LETTER PERSIAN DHALATH +0717 ; [.2442.0020.0002] # SYRIAC LETTER HE +0718 ; [.2443.0020.0002] # SYRIAC LETTER WAW +0719 ; [.2444.0020.0002] # SYRIAC LETTER ZAIN +074D ; [.2445.0020.0002] # SYRIAC LETTER SOGDIAN ZHAIN +071A ; [.2446.0020.0002] # SYRIAC LETTER HETH +071B ; [.2447.0020.0002] # SYRIAC LETTER TETH +071C ; [.2447.0020.0004][.0000.0112.0004] # SYRIAC LETTER TETH GARSHUNI +071D ; [.2448.0020.0002] # SYRIAC LETTER YUDH +071E ; [.2449.0020.0002] # SYRIAC LETTER YUDH HE +071F ; [.244A.0020.0002] # SYRIAC LETTER KAPH +074E ; [.244B.0020.0002] # SYRIAC LETTER SOGDIAN KHAPH +0720 ; [.244C.0020.0002] # SYRIAC LETTER LAMADH +0721 ; [.244D.0020.0002] # SYRIAC LETTER MIM +0722 ; [.244E.0020.0002] # SYRIAC LETTER NUN +0723 ; [.244F.0020.0002] # SYRIAC LETTER SEMKATH +0724 ; [.244F.0020.0019] # SYRIAC LETTER FINAL SEMKATH +0725 ; [.2450.0020.0002] # SYRIAC LETTER E +0726 ; [.2451.0020.0002] # SYRIAC LETTER PE +0727 ; [.2451.0020.0004][.0000.0112.0004] # SYRIAC LETTER REVERSED PE +074F ; [.2452.0020.0002] # SYRIAC LETTER SOGDIAN FE +0728 ; [.2453.0020.0002] # SYRIAC LETTER SADHE +0729 ; [.2454.0020.0002] # SYRIAC LETTER QAPH +072A ; [.2455.0020.0002] # SYRIAC LETTER RISH +072B ; [.2456.0020.0002] # SYRIAC LETTER SHIN +072C ; [.2457.0020.0002] # SYRIAC LETTER TAW +0860 ; [.2458.0020.0002] # SYRIAC LETTER MALAYALAM NGA +0861 ; [.2459.0020.0002] # SYRIAC LETTER MALAYALAM JA +0862 ; [.245A.0020.0002] # SYRIAC LETTER MALAYALAM NYA +0863 ; [.245B.0020.0002] # SYRIAC LETTER MALAYALAM TTA +0864 ; [.245C.0020.0002] # SYRIAC LETTER MALAYALAM NNA +0865 ; [.245D.0020.0002] # SYRIAC LETTER MALAYALAM NNNA +0866 ; [.245E.0020.0002] # SYRIAC LETTER MALAYALAM BHA +0867 ; [.245F.0020.0002] # SYRIAC LETTER MALAYALAM RA +0868 ; [.2460.0020.0002] # SYRIAC LETTER MALAYALAM LLA +0869 ; [.2461.0020.0002] # SYRIAC LETTER MALAYALAM LLLA +086A ; [.2462.0020.0002] # SYRIAC LETTER MALAYALAM SSA +0840 ; [.2463.0020.0002] # MANDAIC LETTER HALQA +0841 ; [.2464.0020.0002] # MANDAIC LETTER AB +0842 ; [.2465.0020.0002] # MANDAIC LETTER AG +0843 ; [.2466.0020.0002] # MANDAIC LETTER AD +0844 ; [.2467.0020.0002] # MANDAIC LETTER AH +0845 ; [.2468.0020.0002] # MANDAIC LETTER USHENNA +0846 ; [.2469.0020.0002] # MANDAIC LETTER AZ +0847 ; [.246A.0020.0002] # MANDAIC LETTER IT +0848 ; [.246B.0020.0002] # MANDAIC LETTER ATT +0849 ; [.246C.0020.0002] # MANDAIC LETTER AKSA +084A ; [.246D.0020.0002] # MANDAIC LETTER AK +084B ; [.246E.0020.0002] # MANDAIC LETTER AL +084C ; [.246F.0020.0002] # MANDAIC LETTER AM +084D ; [.2470.0020.0002] # MANDAIC LETTER AN +084E ; [.2471.0020.0002] # MANDAIC LETTER AS +084F ; [.2472.0020.0002] # MANDAIC LETTER IN +0850 ; [.2473.0020.0002] # MANDAIC LETTER AP +0851 ; [.2474.0020.0002] # MANDAIC LETTER ASZ +0852 ; [.2475.0020.0002] # MANDAIC LETTER AQ +0853 ; [.2476.0020.0002] # MANDAIC LETTER AR +0854 ; [.2477.0020.0002] # MANDAIC LETTER ASH +0855 ; [.2478.0020.0002] # MANDAIC LETTER AT +0856 ; [.2479.0020.0002] # MANDAIC LETTER DUSHENNA +0857 ; [.247A.0020.0002] # MANDAIC LETTER KAD +0858 ; [.247B.0020.0002] # MANDAIC LETTER AIN +0780 ; [.247C.0020.0002] # THAANA LETTER HAA +0799 ; [.247D.0020.0002] # THAANA LETTER HHAA +079A ; [.247E.0020.0002] # THAANA LETTER KHAA +0781 ; [.247F.0020.0002] # THAANA LETTER SHAVIYANI +0782 ; [.2480.0020.0002] # THAANA LETTER NOONU +0783 ; [.2481.0020.0002] # THAANA LETTER RAA +079C ; [.2482.0020.0002] # THAANA LETTER ZAA +0784 ; [.2483.0020.0002] # THAANA LETTER BAA +0785 ; [.2484.0020.0002] # THAANA LETTER LHAVIYANI +0786 ; [.2485.0020.0002] # THAANA LETTER KAAFU +0787 ; [.2486.0020.0002] # THAANA LETTER ALIFU +07A2 ; [.2487.0020.0002] # THAANA LETTER AINU +07A3 ; [.2488.0020.0002] # THAANA LETTER GHAINU +0788 ; [.2489.0020.0002] # THAANA LETTER VAAVU +07A5 ; [.248A.0020.0002] # THAANA LETTER WAAVU +0789 ; [.248B.0020.0002] # THAANA LETTER MEEMU +078A ; [.248C.0020.0002] # THAANA LETTER FAAFU +078B ; [.248D.0020.0002] # THAANA LETTER DHAALU +079B ; [.248E.0020.0002] # THAANA LETTER THAALU +078C ; [.248F.0020.0002] # THAANA LETTER THAA +0798 ; [.2490.0020.0002] # THAANA LETTER TTAA +07A0 ; [.2491.0020.0002] # THAANA LETTER TO +07A1 ; [.2492.0020.0002] # THAANA LETTER ZO +078D ; [.2493.0020.0002] # THAANA LETTER LAAMU +078E ; [.2494.0020.0002] # THAANA LETTER GAAFU +07A4 ; [.2495.0020.0002] # THAANA LETTER QAAFU +078F ; [.2496.0020.0002] # THAANA LETTER GNAVIYANI +0790 ; [.2497.0020.0002] # THAANA LETTER SEENU +079D ; [.2498.0020.0002] # THAANA LETTER SHEENU +079E ; [.2499.0020.0002] # THAANA LETTER SAADHU +079F ; [.249A.0020.0002] # THAANA LETTER DAADHU +0791 ; [.249B.0020.0002] # THAANA LETTER DAVIYANI +0792 ; [.249C.0020.0002] # THAANA LETTER ZAVIYANI +0793 ; [.249D.0020.0002] # THAANA LETTER TAVIYANI +0794 ; [.249E.0020.0002] # THAANA LETTER YAA +0795 ; [.249F.0020.0002] # THAANA LETTER PAVIYANI +0796 ; [.24A0.0020.0002] # THAANA LETTER JAVIYANI +0797 ; [.24A1.0020.0002] # THAANA LETTER CHAVIYANI +07B1 ; [.24A2.0020.0002] # THAANA LETTER NAA +07A6 ; [.24A3.0020.0002] # THAANA ABAFILI +07A7 ; [.24A4.0020.0002] # THAANA AABAAFILI +07A8 ; [.24A5.0020.0002] # THAANA IBIFILI +07A9 ; [.24A6.0020.0002] # THAANA EEBEEFILI +07AA ; [.24A7.0020.0002] # THAANA UBUFILI +07AB ; [.24A8.0020.0002] # THAANA OOBOOFILI +07AC ; [.24A9.0020.0002] # THAANA EBEFILI +07AD ; [.24AA.0020.0002] # THAANA EYBEYFILI +07AE ; [.24AB.0020.0002] # THAANA OBOFILI +07AF ; [.24AC.0020.0002] # THAANA OABOAFILI +07B0 ; [.24AD.0020.0002] # THAANA SUKUN +07CA ; [.24AE.0020.0002] # NKO LETTER A +07CB ; [.24AF.0020.0002] # NKO LETTER EE +07CC ; [.24B0.0020.0002] # NKO LETTER I +07CD ; [.24B1.0020.0002] # NKO LETTER E +07CE ; [.24B2.0020.0002] # NKO LETTER U +07CF ; [.24B3.0020.0002] # NKO LETTER OO +07D0 ; [.24B4.0020.0002] # NKO LETTER O +07D1 ; [.24B5.0020.0002] # NKO LETTER DAGBASINNA +07D2 ; [.24B6.0020.0002] # NKO LETTER N +07D3 ; [.24B7.0020.0002] # NKO LETTER BA +07D4 ; [.24B8.0020.0002] # NKO LETTER PA +07D5 ; [.24B9.0020.0002] # NKO LETTER TA +07D6 ; [.24BA.0020.0002] # NKO LETTER JA +07E8 ; [.24BA.0020.0004][.0000.0111.0004] # NKO LETTER JONA JA +07D7 ; [.24BB.0020.0002] # NKO LETTER CHA +07E9 ; [.24BB.0020.0004][.0000.0111.0004] # NKO LETTER JONA CHA +07D8 ; [.24BC.0020.0002] # NKO LETTER DA +07D9 ; [.24BD.0020.0002] # NKO LETTER RA +07EA ; [.24BD.0020.0004][.0000.0111.0004] # NKO LETTER JONA RA +07DA ; [.24BE.0020.0002] # NKO LETTER RRA +07DB ; [.24BF.0020.0002] # NKO LETTER SA +07DC ; [.24C0.0020.0002] # NKO LETTER GBA +07DD ; [.24C1.0020.0002] # NKO LETTER FA +07DE ; [.24C2.0020.0002] # NKO LETTER KA +07DF ; [.24C3.0020.0002] # NKO LETTER LA +07E0 ; [.24C4.0020.0002] # NKO LETTER NA WOLOSO +07E1 ; [.24C5.0020.0002] # NKO LETTER MA +07E2 ; [.24C6.0020.0002] # NKO LETTER NYA +07E3 ; [.24C7.0020.0002] # NKO LETTER NA +07E4 ; [.24C8.0020.0002] # NKO LETTER HA +07E5 ; [.24C9.0020.0002] # NKO LETTER WA +07E6 ; [.24CA.0020.0002] # NKO LETTER YA +07E7 ; [.24CB.0020.0002] # NKO LETTER NYA WOLOSO +07F4 ; [.24CC.0020.0002] # NKO HIGH TONE APOSTROPHE +07F5 ; [.24CD.0020.0002] # NKO LOW TONE APOSTROPHE +2D30 ; [.24CE.0020.0002] # TIFINAGH LETTER YA +2D31 ; [.24CF.0020.0002] # TIFINAGH LETTER YAB +2D32 ; [.24D0.0020.0002] # TIFINAGH LETTER YABH +2D33 ; [.24D1.0020.0002] # TIFINAGH LETTER YAG +2D34 ; [.24D2.0020.0002] # TIFINAGH LETTER YAGHH +2D35 ; [.24D3.0020.0002] # TIFINAGH LETTER BERBER ACADEMY YAJ +2D36 ; [.24D4.0020.0002] # TIFINAGH LETTER YAJ +2D37 ; [.24D5.0020.0002] # TIFINAGH LETTER YAD +2D38 ; [.24D6.0020.0002] # TIFINAGH LETTER YADH +2D39 ; [.24D7.0020.0002] # TIFINAGH LETTER YADD +2D3A ; [.24D8.0020.0002] # TIFINAGH LETTER YADDH +2D3B ; [.24D9.0020.0002] # TIFINAGH LETTER YEY +2D66 ; [.24DA.0020.0002] # TIFINAGH LETTER YE +2D3C ; [.24DB.0020.0002] # TIFINAGH LETTER YAF +2D3D ; [.24DC.0020.0002] # TIFINAGH LETTER YAK +2D3E ; [.24DD.0020.0002] # TIFINAGH LETTER TUAREG YAK +2D3F ; [.24DE.0020.0002] # TIFINAGH LETTER YAKHH +2D40 ; [.24DF.0020.0002] # TIFINAGH LETTER YAH +2D41 ; [.24E0.0020.0002] # TIFINAGH LETTER BERBER ACADEMY YAH +2D42 ; [.24E1.0020.0002] # TIFINAGH LETTER TUAREG YAH +2D43 ; [.24E2.0020.0002] # TIFINAGH LETTER YAHH +2D44 ; [.24E3.0020.0002] # TIFINAGH LETTER YAA +2D45 ; [.24E4.0020.0002] # TIFINAGH LETTER YAKH +2D46 ; [.24E5.0020.0002] # TIFINAGH LETTER TUAREG YAKH +2D47 ; [.24E6.0020.0002] # TIFINAGH LETTER YAQ +2D48 ; [.24E7.0020.0002] # TIFINAGH LETTER TUAREG YAQ +2D49 ; [.24E8.0020.0002] # TIFINAGH LETTER YI +2D4A ; [.24E9.0020.0002] # TIFINAGH LETTER YAZH +2D4B ; [.24EA.0020.0002] # TIFINAGH LETTER AHAGGAR YAZH +2D4C ; [.24EB.0020.0002] # TIFINAGH LETTER TUAREG YAZH +2D4D ; [.24EC.0020.0002] # TIFINAGH LETTER YAL +2D4E ; [.24ED.0020.0002] # TIFINAGH LETTER YAM +2D4F ; [.24EE.0020.0002] # TIFINAGH LETTER YAN +2D50 ; [.24EF.0020.0002] # TIFINAGH LETTER TUAREG YAGN +2D51 ; [.24F0.0020.0002] # TIFINAGH LETTER TUAREG YANG +2D52 ; [.24F1.0020.0002] # TIFINAGH LETTER YAP +2D53 ; [.24F2.0020.0002] # TIFINAGH LETTER YU +2D67 ; [.24F3.0020.0002] # TIFINAGH LETTER YO +2D54 ; [.24F4.0020.0002] # TIFINAGH LETTER YAR +2D55 ; [.24F5.0020.0002] # TIFINAGH LETTER YARR +2D56 ; [.24F6.0020.0002] # TIFINAGH LETTER YAGH +2D57 ; [.24F7.0020.0002] # TIFINAGH LETTER TUAREG YAGH +2D58 ; [.24F8.0020.0002] # TIFINAGH LETTER AYER YAGH +2D59 ; [.24F9.0020.0002] # TIFINAGH LETTER YAS +2D5A ; [.24FA.0020.0002] # TIFINAGH LETTER YASS +2D5B ; [.24FB.0020.0002] # TIFINAGH LETTER YASH +2D5C ; [.24FC.0020.0002] # TIFINAGH LETTER YAT +2D5D ; [.24FD.0020.0002] # TIFINAGH LETTER YATH +2D5E ; [.24FE.0020.0002] # TIFINAGH LETTER YACH +2D5F ; [.24FF.0020.0002] # TIFINAGH LETTER YATT +2D60 ; [.2500.0020.0002] # TIFINAGH LETTER YAV +2D61 ; [.2501.0020.0002] # TIFINAGH LETTER YAW +2D62 ; [.2502.0020.0002] # TIFINAGH LETTER YAY +2D63 ; [.2503.0020.0002] # TIFINAGH LETTER YAZ +2D64 ; [.2504.0020.0002] # TIFINAGH LETTER TAWELLEMET YAZ +2D65 ; [.2505.0020.0002] # TIFINAGH LETTER YAZZ +2D6F ; [.2506.0020.0002] # TIFINAGH MODIFIER LETTER LABIALIZATION MARK +1200 ; [.2507.0020.0002] # ETHIOPIC SYLLABLE HA +1201 ; [.2508.0020.0002] # ETHIOPIC SYLLABLE HU +1202 ; [.2509.0020.0002] # ETHIOPIC SYLLABLE HI +1203 ; [.250A.0020.0002] # ETHIOPIC SYLLABLE HAA +1204 ; [.250B.0020.0002] # ETHIOPIC SYLLABLE HEE +1205 ; [.250C.0020.0002] # ETHIOPIC SYLLABLE HE +1206 ; [.250D.0020.0002] # ETHIOPIC SYLLABLE HO +1207 ; [.250E.0020.0002] # ETHIOPIC SYLLABLE HOA +1208 ; [.250F.0020.0002] # ETHIOPIC SYLLABLE LA +1209 ; [.2510.0020.0002] # ETHIOPIC SYLLABLE LU +120A ; [.2511.0020.0002] # ETHIOPIC SYLLABLE LI +120B ; [.2512.0020.0002] # ETHIOPIC SYLLABLE LAA +120C ; [.2513.0020.0002] # ETHIOPIC SYLLABLE LEE +120D ; [.2514.0020.0002] # ETHIOPIC SYLLABLE LE +120E ; [.2515.0020.0002] # ETHIOPIC SYLLABLE LO +120F ; [.2516.0020.0002] # ETHIOPIC SYLLABLE LWA +2D80 ; [.2517.0020.0002] # ETHIOPIC SYLLABLE LOA +1210 ; [.2518.0020.0002] # ETHIOPIC SYLLABLE HHA +1211 ; [.2519.0020.0002] # ETHIOPIC SYLLABLE HHU +1212 ; [.251A.0020.0002] # ETHIOPIC SYLLABLE HHI +1213 ; [.251B.0020.0002] # ETHIOPIC SYLLABLE HHAA +1214 ; [.251C.0020.0002] # ETHIOPIC SYLLABLE HHEE +1215 ; [.251D.0020.0002] # ETHIOPIC SYLLABLE HHE +1216 ; [.251E.0020.0002] # ETHIOPIC SYLLABLE HHO +1217 ; [.251F.0020.0002] # ETHIOPIC SYLLABLE HHWA +1218 ; [.2520.0020.0002] # ETHIOPIC SYLLABLE MA +1219 ; [.2521.0020.0002] # ETHIOPIC SYLLABLE MU +121A ; [.2522.0020.0002] # ETHIOPIC SYLLABLE MI +121B ; [.2523.0020.0002] # ETHIOPIC SYLLABLE MAA +121C ; [.2524.0020.0002] # ETHIOPIC SYLLABLE MEE +121D ; [.2525.0020.0002] # ETHIOPIC SYLLABLE ME +121E ; [.2526.0020.0002] # ETHIOPIC SYLLABLE MO +121F ; [.2527.0020.0002] # ETHIOPIC SYLLABLE MWA +1380 ; [.2528.0020.0002] # ETHIOPIC SYLLABLE SEBATBEIT MWA +1381 ; [.2529.0020.0002] # ETHIOPIC SYLLABLE MWI +1382 ; [.252A.0020.0002] # ETHIOPIC SYLLABLE MWEE +1383 ; [.252B.0020.0002] # ETHIOPIC SYLLABLE MWE +2D81 ; [.252C.0020.0002] # ETHIOPIC SYLLABLE MOA +1220 ; [.252D.0020.0002] # ETHIOPIC SYLLABLE SZA +1221 ; [.252E.0020.0002] # ETHIOPIC SYLLABLE SZU +1222 ; [.252F.0020.0002] # ETHIOPIC SYLLABLE SZI +1223 ; [.2530.0020.0002] # ETHIOPIC SYLLABLE SZAA +1224 ; [.2531.0020.0002] # ETHIOPIC SYLLABLE SZEE +1225 ; [.2532.0020.0002] # ETHIOPIC SYLLABLE SZE +1226 ; [.2533.0020.0002] # ETHIOPIC SYLLABLE SZO +1227 ; [.2534.0020.0002] # ETHIOPIC SYLLABLE SZWA +1228 ; [.2535.0020.0002] # ETHIOPIC SYLLABLE RA +1229 ; [.2536.0020.0002] # ETHIOPIC SYLLABLE RU +122A ; [.2537.0020.0002] # ETHIOPIC SYLLABLE RI +122B ; [.2538.0020.0002] # ETHIOPIC SYLLABLE RAA +122C ; [.2539.0020.0002] # ETHIOPIC SYLLABLE REE +122D ; [.253A.0020.0002] # ETHIOPIC SYLLABLE RE +122E ; [.253B.0020.0002] # ETHIOPIC SYLLABLE RO +122F ; [.253C.0020.0002] # ETHIOPIC SYLLABLE RWA +2D82 ; [.253D.0020.0002] # ETHIOPIC SYLLABLE ROA +1230 ; [.253E.0020.0002] # ETHIOPIC SYLLABLE SA +1231 ; [.253F.0020.0002] # ETHIOPIC SYLLABLE SU +1232 ; [.2540.0020.0002] # ETHIOPIC SYLLABLE SI +1233 ; [.2541.0020.0002] # ETHIOPIC SYLLABLE SAA +1234 ; [.2542.0020.0002] # ETHIOPIC SYLLABLE SEE +1235 ; [.2543.0020.0002] # ETHIOPIC SYLLABLE SE +1236 ; [.2544.0020.0002] # ETHIOPIC SYLLABLE SO +1237 ; [.2545.0020.0002] # ETHIOPIC SYLLABLE SWA +2D83 ; [.2546.0020.0002] # ETHIOPIC SYLLABLE SOA +AB01 ; [.2547.0020.0002] # ETHIOPIC SYLLABLE TTHU +AB02 ; [.2548.0020.0002] # ETHIOPIC SYLLABLE TTHI +AB03 ; [.2549.0020.0002] # ETHIOPIC SYLLABLE TTHAA +AB04 ; [.254A.0020.0002] # ETHIOPIC SYLLABLE TTHEE +AB05 ; [.254B.0020.0002] # ETHIOPIC SYLLABLE TTHE +AB06 ; [.254C.0020.0002] # ETHIOPIC SYLLABLE TTHO +1238 ; [.254D.0020.0002] # ETHIOPIC SYLLABLE SHA +1239 ; [.254E.0020.0002] # ETHIOPIC SYLLABLE SHU +123A ; [.254F.0020.0002] # ETHIOPIC SYLLABLE SHI +123B ; [.2550.0020.0002] # ETHIOPIC SYLLABLE SHAA +123C ; [.2551.0020.0002] # ETHIOPIC SYLLABLE SHEE +123D ; [.2552.0020.0002] # ETHIOPIC SYLLABLE SHE +123E ; [.2553.0020.0002] # ETHIOPIC SYLLABLE SHO +123F ; [.2554.0020.0002] # ETHIOPIC SYLLABLE SHWA +2D84 ; [.2555.0020.0002] # ETHIOPIC SYLLABLE SHOA +1240 ; [.2556.0020.0002] # ETHIOPIC SYLLABLE QA +1241 ; [.2557.0020.0002] # ETHIOPIC SYLLABLE QU +1242 ; [.2558.0020.0002] # ETHIOPIC SYLLABLE QI +1243 ; [.2559.0020.0002] # ETHIOPIC SYLLABLE QAA +1244 ; [.255A.0020.0002] # ETHIOPIC SYLLABLE QEE +1245 ; [.255B.0020.0002] # ETHIOPIC SYLLABLE QE +1246 ; [.255C.0020.0002] # ETHIOPIC SYLLABLE QO +1247 ; [.255D.0020.0002] # ETHIOPIC SYLLABLE QOA +1248 ; [.255E.0020.0002] # ETHIOPIC SYLLABLE QWA +124A ; [.255F.0020.0002] # ETHIOPIC SYLLABLE QWI +124B ; [.2560.0020.0002] # ETHIOPIC SYLLABLE QWAA +124C ; [.2561.0020.0002] # ETHIOPIC SYLLABLE QWEE +124D ; [.2562.0020.0002] # ETHIOPIC SYLLABLE QWE +1250 ; [.2563.0020.0002] # ETHIOPIC SYLLABLE QHA +1251 ; [.2564.0020.0002] # ETHIOPIC SYLLABLE QHU +1252 ; [.2565.0020.0002] # ETHIOPIC SYLLABLE QHI +1253 ; [.2566.0020.0002] # ETHIOPIC SYLLABLE QHAA +1254 ; [.2567.0020.0002] # ETHIOPIC SYLLABLE QHEE +1255 ; [.2568.0020.0002] # ETHIOPIC SYLLABLE QHE +1256 ; [.2569.0020.0002] # ETHIOPIC SYLLABLE QHO +1258 ; [.256A.0020.0002] # ETHIOPIC SYLLABLE QHWA +125A ; [.256B.0020.0002] # ETHIOPIC SYLLABLE QHWI +125B ; [.256C.0020.0002] # ETHIOPIC SYLLABLE QHWAA +125C ; [.256D.0020.0002] # ETHIOPIC SYLLABLE QHWEE +125D ; [.256E.0020.0002] # ETHIOPIC SYLLABLE QHWE +1260 ; [.256F.0020.0002] # ETHIOPIC SYLLABLE BA +1261 ; [.2570.0020.0002] # ETHIOPIC SYLLABLE BU +1262 ; [.2571.0020.0002] # ETHIOPIC SYLLABLE BI +1263 ; [.2572.0020.0002] # ETHIOPIC SYLLABLE BAA +1264 ; [.2573.0020.0002] # ETHIOPIC SYLLABLE BEE +1265 ; [.2574.0020.0002] # ETHIOPIC SYLLABLE BE +1266 ; [.2575.0020.0002] # ETHIOPIC SYLLABLE BO +1267 ; [.2576.0020.0002] # ETHIOPIC SYLLABLE BWA +1384 ; [.2577.0020.0002] # ETHIOPIC SYLLABLE SEBATBEIT BWA +1385 ; [.2578.0020.0002] # ETHIOPIC SYLLABLE BWI +1386 ; [.2579.0020.0002] # ETHIOPIC SYLLABLE BWEE +1387 ; [.257A.0020.0002] # ETHIOPIC SYLLABLE BWE +2D85 ; [.257B.0020.0002] # ETHIOPIC SYLLABLE BOA +1268 ; [.257C.0020.0002] # ETHIOPIC SYLLABLE VA +1269 ; [.257D.0020.0002] # ETHIOPIC SYLLABLE VU +126A ; [.257E.0020.0002] # ETHIOPIC SYLLABLE VI +126B ; [.257F.0020.0002] # ETHIOPIC SYLLABLE VAA +126C ; [.2580.0020.0002] # ETHIOPIC SYLLABLE VEE +126D ; [.2581.0020.0002] # ETHIOPIC SYLLABLE VE +126E ; [.2582.0020.0002] # ETHIOPIC SYLLABLE VO +126F ; [.2583.0020.0002] # ETHIOPIC SYLLABLE VWA +1270 ; [.2584.0020.0002] # ETHIOPIC SYLLABLE TA +1271 ; [.2585.0020.0002] # ETHIOPIC SYLLABLE TU +1272 ; [.2586.0020.0002] # ETHIOPIC SYLLABLE TI +1273 ; [.2587.0020.0002] # ETHIOPIC SYLLABLE TAA +1274 ; [.2588.0020.0002] # ETHIOPIC SYLLABLE TEE +1275 ; [.2589.0020.0002] # ETHIOPIC SYLLABLE TE +1276 ; [.258A.0020.0002] # ETHIOPIC SYLLABLE TO +1277 ; [.258B.0020.0002] # ETHIOPIC SYLLABLE TWA +2D86 ; [.258C.0020.0002] # ETHIOPIC SYLLABLE TOA +1278 ; [.258D.0020.0002] # ETHIOPIC SYLLABLE CA +1279 ; [.258E.0020.0002] # ETHIOPIC SYLLABLE CU +127A ; [.258F.0020.0002] # ETHIOPIC SYLLABLE CI +127B ; [.2590.0020.0002] # ETHIOPIC SYLLABLE CAA +127C ; [.2591.0020.0002] # ETHIOPIC SYLLABLE CEE +127D ; [.2592.0020.0002] # ETHIOPIC SYLLABLE CE +127E ; [.2593.0020.0002] # ETHIOPIC SYLLABLE CO +127F ; [.2594.0020.0002] # ETHIOPIC SYLLABLE CWA +2D87 ; [.2595.0020.0002] # ETHIOPIC SYLLABLE COA +1280 ; [.2596.0020.0002] # ETHIOPIC SYLLABLE XA +1281 ; [.2597.0020.0002] # ETHIOPIC SYLLABLE XU +1282 ; [.2598.0020.0002] # ETHIOPIC SYLLABLE XI +1283 ; [.2599.0020.0002] # ETHIOPIC SYLLABLE XAA +1284 ; [.259A.0020.0002] # ETHIOPIC SYLLABLE XEE +1285 ; [.259B.0020.0002] # ETHIOPIC SYLLABLE XE +1286 ; [.259C.0020.0002] # ETHIOPIC SYLLABLE XO +1287 ; [.259D.0020.0002] # ETHIOPIC SYLLABLE XOA +1288 ; [.259E.0020.0002] # ETHIOPIC SYLLABLE XWA +128A ; [.259F.0020.0002] # ETHIOPIC SYLLABLE XWI +128B ; [.25A0.0020.0002] # ETHIOPIC SYLLABLE XWAA +128C ; [.25A1.0020.0002] # ETHIOPIC SYLLABLE XWEE +128D ; [.25A2.0020.0002] # ETHIOPIC SYLLABLE XWE +1290 ; [.25A3.0020.0002] # ETHIOPIC SYLLABLE NA +1291 ; [.25A4.0020.0002] # ETHIOPIC SYLLABLE NU +1292 ; [.25A5.0020.0002] # ETHIOPIC SYLLABLE NI +1293 ; [.25A6.0020.0002] # ETHIOPIC SYLLABLE NAA +1294 ; [.25A7.0020.0002] # ETHIOPIC SYLLABLE NEE +1295 ; [.25A8.0020.0002] # ETHIOPIC SYLLABLE NE +1296 ; [.25A9.0020.0002] # ETHIOPIC SYLLABLE NO +1297 ; [.25AA.0020.0002] # ETHIOPIC SYLLABLE NWA +2D88 ; [.25AB.0020.0002] # ETHIOPIC SYLLABLE NOA +1298 ; [.25AC.0020.0002] # ETHIOPIC SYLLABLE NYA +1299 ; [.25AD.0020.0002] # ETHIOPIC SYLLABLE NYU +129A ; [.25AE.0020.0002] # ETHIOPIC SYLLABLE NYI +129B ; [.25AF.0020.0002] # ETHIOPIC SYLLABLE NYAA +129C ; [.25B0.0020.0002] # ETHIOPIC SYLLABLE NYEE +129D ; [.25B1.0020.0002] # ETHIOPIC SYLLABLE NYE +129E ; [.25B2.0020.0002] # ETHIOPIC SYLLABLE NYO +129F ; [.25B3.0020.0002] # ETHIOPIC SYLLABLE NYWA +2D89 ; [.25B4.0020.0002] # ETHIOPIC SYLLABLE NYOA +12A0 ; [.25B5.0020.0002] # ETHIOPIC SYLLABLE GLOTTAL A +12A1 ; [.25B6.0020.0002] # ETHIOPIC SYLLABLE GLOTTAL U +12A2 ; [.25B7.0020.0002] # ETHIOPIC SYLLABLE GLOTTAL I +12A3 ; [.25B8.0020.0002] # ETHIOPIC SYLLABLE GLOTTAL AA +12A4 ; [.25B9.0020.0002] # ETHIOPIC SYLLABLE GLOTTAL EE +12A5 ; [.25BA.0020.0002] # ETHIOPIC SYLLABLE GLOTTAL E +12A6 ; [.25BB.0020.0002] # ETHIOPIC SYLLABLE GLOTTAL O +12A7 ; [.25BC.0020.0002] # ETHIOPIC SYLLABLE GLOTTAL WA +2D8A ; [.25BD.0020.0002] # ETHIOPIC SYLLABLE GLOTTAL OA +12A8 ; [.25BE.0020.0002] # ETHIOPIC SYLLABLE KA +12A9 ; [.25BF.0020.0002] # ETHIOPIC SYLLABLE KU +12AA ; [.25C0.0020.0002] # ETHIOPIC SYLLABLE KI +12AB ; [.25C1.0020.0002] # ETHIOPIC SYLLABLE KAA +12AC ; [.25C2.0020.0002] # ETHIOPIC SYLLABLE KEE +12AD ; [.25C3.0020.0002] # ETHIOPIC SYLLABLE KE +12AE ; [.25C4.0020.0002] # ETHIOPIC SYLLABLE KO +12AF ; [.25C5.0020.0002] # ETHIOPIC SYLLABLE KOA +12B0 ; [.25C6.0020.0002] # ETHIOPIC SYLLABLE KWA +12B2 ; [.25C7.0020.0002] # ETHIOPIC SYLLABLE KWI +12B3 ; [.25C8.0020.0002] # ETHIOPIC SYLLABLE KWAA +12B4 ; [.25C9.0020.0002] # ETHIOPIC SYLLABLE KWEE +12B5 ; [.25CA.0020.0002] # ETHIOPIC SYLLABLE KWE +12B8 ; [.25CB.0020.0002] # ETHIOPIC SYLLABLE KXA +12B9 ; [.25CC.0020.0002] # ETHIOPIC SYLLABLE KXU +12BA ; [.25CD.0020.0002] # ETHIOPIC SYLLABLE KXI +12BB ; [.25CE.0020.0002] # ETHIOPIC SYLLABLE KXAA +12BC ; [.25CF.0020.0002] # ETHIOPIC SYLLABLE KXEE +12BD ; [.25D0.0020.0002] # ETHIOPIC SYLLABLE KXE +12BE ; [.25D1.0020.0002] # ETHIOPIC SYLLABLE KXO +12C0 ; [.25D2.0020.0002] # ETHIOPIC SYLLABLE KXWA +12C2 ; [.25D3.0020.0002] # ETHIOPIC SYLLABLE KXWI +12C3 ; [.25D4.0020.0002] # ETHIOPIC SYLLABLE KXWAA +12C4 ; [.25D5.0020.0002] # ETHIOPIC SYLLABLE KXWEE +12C5 ; [.25D6.0020.0002] # ETHIOPIC SYLLABLE KXWE +12C8 ; [.25D7.0020.0002] # ETHIOPIC SYLLABLE WA +12C9 ; [.25D8.0020.0002] # ETHIOPIC SYLLABLE WU +12CA ; [.25D9.0020.0002] # ETHIOPIC SYLLABLE WI +12CB ; [.25DA.0020.0002] # ETHIOPIC SYLLABLE WAA +12CC ; [.25DB.0020.0002] # ETHIOPIC SYLLABLE WEE +12CD ; [.25DC.0020.0002] # ETHIOPIC SYLLABLE WE +12CE ; [.25DD.0020.0002] # ETHIOPIC SYLLABLE WO +12CF ; [.25DE.0020.0002] # ETHIOPIC SYLLABLE WOA +12D0 ; [.25DF.0020.0002] # ETHIOPIC SYLLABLE PHARYNGEAL A +12D1 ; [.25E0.0020.0002] # ETHIOPIC SYLLABLE PHARYNGEAL U +12D2 ; [.25E1.0020.0002] # ETHIOPIC SYLLABLE PHARYNGEAL I +12D3 ; [.25E2.0020.0002] # ETHIOPIC SYLLABLE PHARYNGEAL AA +12D4 ; [.25E3.0020.0002] # ETHIOPIC SYLLABLE PHARYNGEAL EE +12D5 ; [.25E4.0020.0002] # ETHIOPIC SYLLABLE PHARYNGEAL E +12D6 ; [.25E5.0020.0002] # ETHIOPIC SYLLABLE PHARYNGEAL O +12D8 ; [.25E6.0020.0002] # ETHIOPIC SYLLABLE ZA +12D9 ; [.25E7.0020.0002] # ETHIOPIC SYLLABLE ZU +12DA ; [.25E8.0020.0002] # ETHIOPIC SYLLABLE ZI +12DB ; [.25E9.0020.0002] # ETHIOPIC SYLLABLE ZAA +12DC ; [.25EA.0020.0002] # ETHIOPIC SYLLABLE ZEE +12DD ; [.25EB.0020.0002] # ETHIOPIC SYLLABLE ZE +12DE ; [.25EC.0020.0002] # ETHIOPIC SYLLABLE ZO +12DF ; [.25ED.0020.0002] # ETHIOPIC SYLLABLE ZWA +2D8B ; [.25EE.0020.0002] # ETHIOPIC SYLLABLE ZOA +AB11 ; [.25EF.0020.0002] # ETHIOPIC SYLLABLE DZU +AB12 ; [.25F0.0020.0002] # ETHIOPIC SYLLABLE DZI +AB13 ; [.25F1.0020.0002] # ETHIOPIC SYLLABLE DZAA +AB14 ; [.25F2.0020.0002] # ETHIOPIC SYLLABLE DZEE +AB15 ; [.25F3.0020.0002] # ETHIOPIC SYLLABLE DZE +AB16 ; [.25F4.0020.0002] # ETHIOPIC SYLLABLE DZO +12E0 ; [.25F5.0020.0002] # ETHIOPIC SYLLABLE ZHA +12E1 ; [.25F6.0020.0002] # ETHIOPIC SYLLABLE ZHU +12E2 ; [.25F7.0020.0002] # ETHIOPIC SYLLABLE ZHI +12E3 ; [.25F8.0020.0002] # ETHIOPIC SYLLABLE ZHAA +12E4 ; [.25F9.0020.0002] # ETHIOPIC SYLLABLE ZHEE +12E5 ; [.25FA.0020.0002] # ETHIOPIC SYLLABLE ZHE +12E6 ; [.25FB.0020.0002] # ETHIOPIC SYLLABLE ZHO +12E7 ; [.25FC.0020.0002] # ETHIOPIC SYLLABLE ZHWA +12E8 ; [.25FD.0020.0002] # ETHIOPIC SYLLABLE YA +12E9 ; [.25FE.0020.0002] # ETHIOPIC SYLLABLE YU +12EA ; [.25FF.0020.0002] # ETHIOPIC SYLLABLE YI +12EB ; [.2600.0020.0002] # ETHIOPIC SYLLABLE YAA +12EC ; [.2601.0020.0002] # ETHIOPIC SYLLABLE YEE +12ED ; [.2602.0020.0002] # ETHIOPIC SYLLABLE YE +12EE ; [.2603.0020.0002] # ETHIOPIC SYLLABLE YO +12EF ; [.2604.0020.0002] # ETHIOPIC SYLLABLE YOA +12F0 ; [.2605.0020.0002] # ETHIOPIC SYLLABLE DA +12F1 ; [.2606.0020.0002] # ETHIOPIC SYLLABLE DU +12F2 ; [.2607.0020.0002] # ETHIOPIC SYLLABLE DI +12F3 ; [.2608.0020.0002] # ETHIOPIC SYLLABLE DAA +12F4 ; [.2609.0020.0002] # ETHIOPIC SYLLABLE DEE +12F5 ; [.260A.0020.0002] # ETHIOPIC SYLLABLE DE +12F6 ; [.260B.0020.0002] # ETHIOPIC SYLLABLE DO +12F7 ; [.260C.0020.0002] # ETHIOPIC SYLLABLE DWA +2D8C ; [.260D.0020.0002] # ETHIOPIC SYLLABLE DOA +AB09 ; [.260E.0020.0002] # ETHIOPIC SYLLABLE DDHU +AB0A ; [.260F.0020.0002] # ETHIOPIC SYLLABLE DDHI +AB0B ; [.2610.0020.0002] # ETHIOPIC SYLLABLE DDHAA +AB0C ; [.2611.0020.0002] # ETHIOPIC SYLLABLE DDHEE +AB0D ; [.2612.0020.0002] # ETHIOPIC SYLLABLE DDHE +AB0E ; [.2613.0020.0002] # ETHIOPIC SYLLABLE DDHO +12F8 ; [.2614.0020.0002] # ETHIOPIC SYLLABLE DDA +12F9 ; [.2615.0020.0002] # ETHIOPIC SYLLABLE DDU +12FA ; [.2616.0020.0002] # ETHIOPIC SYLLABLE DDI +12FB ; [.2617.0020.0002] # ETHIOPIC SYLLABLE DDAA +12FC ; [.2618.0020.0002] # ETHIOPIC SYLLABLE DDEE +12FD ; [.2619.0020.0002] # ETHIOPIC SYLLABLE DDE +12FE ; [.261A.0020.0002] # ETHIOPIC SYLLABLE DDO +12FF ; [.261B.0020.0002] # ETHIOPIC SYLLABLE DDWA +2D8D ; [.261C.0020.0002] # ETHIOPIC SYLLABLE DDOA +1300 ; [.261D.0020.0002] # ETHIOPIC SYLLABLE JA +1301 ; [.261E.0020.0002] # ETHIOPIC SYLLABLE JU +1302 ; [.261F.0020.0002] # ETHIOPIC SYLLABLE JI +1303 ; [.2620.0020.0002] # ETHIOPIC SYLLABLE JAA +1304 ; [.2621.0020.0002] # ETHIOPIC SYLLABLE JEE +1305 ; [.2622.0020.0002] # ETHIOPIC SYLLABLE JE +1306 ; [.2623.0020.0002] # ETHIOPIC SYLLABLE JO +1307 ; [.2624.0020.0002] # ETHIOPIC SYLLABLE JWA +2D8E ; [.2625.0020.0002] # ETHIOPIC SYLLABLE JOA +1308 ; [.2626.0020.0002] # ETHIOPIC SYLLABLE GA +1309 ; [.2627.0020.0002] # ETHIOPIC SYLLABLE GU +130A ; [.2628.0020.0002] # ETHIOPIC SYLLABLE GI +130B ; [.2629.0020.0002] # ETHIOPIC SYLLABLE GAA +130C ; [.262A.0020.0002] # ETHIOPIC SYLLABLE GEE +130D ; [.262B.0020.0002] # ETHIOPIC SYLLABLE GE +130E ; [.262C.0020.0002] # ETHIOPIC SYLLABLE GO +130F ; [.262D.0020.0002] # ETHIOPIC SYLLABLE GOA +1310 ; [.262E.0020.0002] # ETHIOPIC SYLLABLE GWA +1312 ; [.262F.0020.0002] # ETHIOPIC SYLLABLE GWI +1313 ; [.2630.0020.0002] # ETHIOPIC SYLLABLE GWAA +1314 ; [.2631.0020.0002] # ETHIOPIC SYLLABLE GWEE +1315 ; [.2632.0020.0002] # ETHIOPIC SYLLABLE GWE +1318 ; [.2633.0020.0002] # ETHIOPIC SYLLABLE GGA +1319 ; [.2634.0020.0002] # ETHIOPIC SYLLABLE GGU +131A ; [.2635.0020.0002] # ETHIOPIC SYLLABLE GGI +131B ; [.2636.0020.0002] # ETHIOPIC SYLLABLE GGAA +131C ; [.2637.0020.0002] # ETHIOPIC SYLLABLE GGEE +131D ; [.2638.0020.0002] # ETHIOPIC SYLLABLE GGE +131E ; [.2639.0020.0002] # ETHIOPIC SYLLABLE GGO +131F ; [.263A.0020.0002] # ETHIOPIC SYLLABLE GGWAA +2D93 ; [.263B.0020.0002] # ETHIOPIC SYLLABLE GGWA +2D94 ; [.263C.0020.0002] # ETHIOPIC SYLLABLE GGWI +2D95 ; [.263D.0020.0002] # ETHIOPIC SYLLABLE GGWEE +2D96 ; [.263E.0020.0002] # ETHIOPIC SYLLABLE GGWE +1320 ; [.263F.0020.0002] # ETHIOPIC SYLLABLE THA +1321 ; [.2640.0020.0002] # ETHIOPIC SYLLABLE THU +1322 ; [.2641.0020.0002] # ETHIOPIC SYLLABLE THI +1323 ; [.2642.0020.0002] # ETHIOPIC SYLLABLE THAA +1324 ; [.2643.0020.0002] # ETHIOPIC SYLLABLE THEE +1325 ; [.2644.0020.0002] # ETHIOPIC SYLLABLE THE +1326 ; [.2645.0020.0002] # ETHIOPIC SYLLABLE THO +1327 ; [.2646.0020.0002] # ETHIOPIC SYLLABLE THWA +2D8F ; [.2647.0020.0002] # ETHIOPIC SYLLABLE THOA +1328 ; [.2648.0020.0002] # ETHIOPIC SYLLABLE CHA +1329 ; [.2649.0020.0002] # ETHIOPIC SYLLABLE CHU +132A ; [.264A.0020.0002] # ETHIOPIC SYLLABLE CHI +132B ; [.264B.0020.0002] # ETHIOPIC SYLLABLE CHAA +132C ; [.264C.0020.0002] # ETHIOPIC SYLLABLE CHEE +132D ; [.264D.0020.0002] # ETHIOPIC SYLLABLE CHE +132E ; [.264E.0020.0002] # ETHIOPIC SYLLABLE CHO +132F ; [.264F.0020.0002] # ETHIOPIC SYLLABLE CHWA +2D90 ; [.2650.0020.0002] # ETHIOPIC SYLLABLE CHOA +AB20 ; [.2651.0020.0002] # ETHIOPIC SYLLABLE CCHHA +AB21 ; [.2652.0020.0002] # ETHIOPIC SYLLABLE CCHHU +AB22 ; [.2653.0020.0002] # ETHIOPIC SYLLABLE CCHHI +AB23 ; [.2654.0020.0002] # ETHIOPIC SYLLABLE CCHHAA +AB24 ; [.2655.0020.0002] # ETHIOPIC SYLLABLE CCHHEE +AB25 ; [.2656.0020.0002] # ETHIOPIC SYLLABLE CCHHE +AB26 ; [.2657.0020.0002] # ETHIOPIC SYLLABLE CCHHO +1330 ; [.2658.0020.0002] # ETHIOPIC SYLLABLE PHA +1331 ; [.2659.0020.0002] # ETHIOPIC SYLLABLE PHU +1332 ; [.265A.0020.0002] # ETHIOPIC SYLLABLE PHI +1333 ; [.265B.0020.0002] # ETHIOPIC SYLLABLE PHAA +1334 ; [.265C.0020.0002] # ETHIOPIC SYLLABLE PHEE +1335 ; [.265D.0020.0002] # ETHIOPIC SYLLABLE PHE +1336 ; [.265E.0020.0002] # ETHIOPIC SYLLABLE PHO +1337 ; [.265F.0020.0002] # ETHIOPIC SYLLABLE PHWA +2D91 ; [.2660.0020.0002] # ETHIOPIC SYLLABLE PHOA +1338 ; [.2661.0020.0002] # ETHIOPIC SYLLABLE TSA +1339 ; [.2662.0020.0002] # ETHIOPIC SYLLABLE TSU +133A ; [.2663.0020.0002] # ETHIOPIC SYLLABLE TSI +133B ; [.2664.0020.0002] # ETHIOPIC SYLLABLE TSAA +133C ; [.2665.0020.0002] # ETHIOPIC SYLLABLE TSEE +133D ; [.2666.0020.0002] # ETHIOPIC SYLLABLE TSE +133E ; [.2667.0020.0002] # ETHIOPIC SYLLABLE TSO +133F ; [.2668.0020.0002] # ETHIOPIC SYLLABLE TSWA +AB28 ; [.2669.0020.0002] # ETHIOPIC SYLLABLE BBA +AB29 ; [.266A.0020.0002] # ETHIOPIC SYLLABLE BBU +AB2A ; [.266B.0020.0002] # ETHIOPIC SYLLABLE BBI +AB2B ; [.266C.0020.0002] # ETHIOPIC SYLLABLE BBAA +AB2C ; [.266D.0020.0002] # ETHIOPIC SYLLABLE BBEE +AB2D ; [.266E.0020.0002] # ETHIOPIC SYLLABLE BBE +AB2E ; [.266F.0020.0002] # ETHIOPIC SYLLABLE BBO +1340 ; [.2670.0020.0002] # ETHIOPIC SYLLABLE TZA +1341 ; [.2671.0020.0002] # ETHIOPIC SYLLABLE TZU +1342 ; [.2672.0020.0002] # ETHIOPIC SYLLABLE TZI +1343 ; [.2673.0020.0002] # ETHIOPIC SYLLABLE TZAA +1344 ; [.2674.0020.0002] # ETHIOPIC SYLLABLE TZEE +1345 ; [.2675.0020.0002] # ETHIOPIC SYLLABLE TZE +1346 ; [.2676.0020.0002] # ETHIOPIC SYLLABLE TZO +1347 ; [.2677.0020.0002] # ETHIOPIC SYLLABLE TZOA +1348 ; [.2678.0020.0002] # ETHIOPIC SYLLABLE FA +1349 ; [.2679.0020.0002] # ETHIOPIC SYLLABLE FU +134A ; [.267A.0020.0002] # ETHIOPIC SYLLABLE FI +134B ; [.267B.0020.0002] # ETHIOPIC SYLLABLE FAA +134C ; [.267C.0020.0002] # ETHIOPIC SYLLABLE FEE +134D ; [.267D.0020.0002] # ETHIOPIC SYLLABLE FE +134E ; [.267E.0020.0002] # ETHIOPIC SYLLABLE FO +134F ; [.267F.0020.0002] # ETHIOPIC SYLLABLE FWA +1388 ; [.2680.0020.0002] # ETHIOPIC SYLLABLE SEBATBEIT FWA +1389 ; [.2681.0020.0002] # ETHIOPIC SYLLABLE FWI +138A ; [.2682.0020.0002] # ETHIOPIC SYLLABLE FWEE +138B ; [.2683.0020.0002] # ETHIOPIC SYLLABLE FWE +1350 ; [.2684.0020.0002] # ETHIOPIC SYLLABLE PA +1351 ; [.2685.0020.0002] # ETHIOPIC SYLLABLE PU +1352 ; [.2686.0020.0002] # ETHIOPIC SYLLABLE PI +1353 ; [.2687.0020.0002] # ETHIOPIC SYLLABLE PAA +1354 ; [.2688.0020.0002] # ETHIOPIC SYLLABLE PEE +1355 ; [.2689.0020.0002] # ETHIOPIC SYLLABLE PE +1356 ; [.268A.0020.0002] # ETHIOPIC SYLLABLE PO +1357 ; [.268B.0020.0002] # ETHIOPIC SYLLABLE PWA +138C ; [.268C.0020.0002] # ETHIOPIC SYLLABLE SEBATBEIT PWA +138D ; [.268D.0020.0002] # ETHIOPIC SYLLABLE PWI +138E ; [.268E.0020.0002] # ETHIOPIC SYLLABLE PWEE +138F ; [.268F.0020.0002] # ETHIOPIC SYLLABLE PWE +2D92 ; [.2690.0020.0002] # ETHIOPIC SYLLABLE POA +1358 ; [.2691.0020.0002] # ETHIOPIC SYLLABLE RYA +1359 ; [.2692.0020.0002] # ETHIOPIC SYLLABLE MYA +135A ; [.2693.0020.0002] # ETHIOPIC SYLLABLE FYA +2DA0 ; [.2694.0020.0002] # ETHIOPIC SYLLABLE SSA +2DA1 ; [.2695.0020.0002] # ETHIOPIC SYLLABLE SSU +2DA2 ; [.2696.0020.0002] # ETHIOPIC SYLLABLE SSI +2DA3 ; [.2697.0020.0002] # ETHIOPIC SYLLABLE SSAA +2DA4 ; [.2698.0020.0002] # ETHIOPIC SYLLABLE SSEE +2DA5 ; [.2699.0020.0002] # ETHIOPIC SYLLABLE SSE +2DA6 ; [.269A.0020.0002] # ETHIOPIC SYLLABLE SSO +2DA8 ; [.269B.0020.0002] # ETHIOPIC SYLLABLE CCA +2DA9 ; [.269C.0020.0002] # ETHIOPIC SYLLABLE CCU +2DAA ; [.269D.0020.0002] # ETHIOPIC SYLLABLE CCI +2DAB ; [.269E.0020.0002] # ETHIOPIC SYLLABLE CCAA +2DAC ; [.269F.0020.0002] # ETHIOPIC SYLLABLE CCEE +2DAD ; [.26A0.0020.0002] # ETHIOPIC SYLLABLE CCE +2DAE ; [.26A1.0020.0002] # ETHIOPIC SYLLABLE CCO +2DB0 ; [.26A2.0020.0002] # ETHIOPIC SYLLABLE ZZA +2DB1 ; [.26A3.0020.0002] # ETHIOPIC SYLLABLE ZZU +2DB2 ; [.26A4.0020.0002] # ETHIOPIC SYLLABLE ZZI +2DB3 ; [.26A5.0020.0002] # ETHIOPIC SYLLABLE ZZAA +2DB4 ; [.26A6.0020.0002] # ETHIOPIC SYLLABLE ZZEE +2DB5 ; [.26A7.0020.0002] # ETHIOPIC SYLLABLE ZZE +2DB6 ; [.26A8.0020.0002] # ETHIOPIC SYLLABLE ZZO +2DB8 ; [.26A9.0020.0002] # ETHIOPIC SYLLABLE CCHA +2DB9 ; [.26AA.0020.0002] # ETHIOPIC SYLLABLE CCHU +2DBA ; [.26AB.0020.0002] # ETHIOPIC SYLLABLE CCHI +2DBB ; [.26AC.0020.0002] # ETHIOPIC SYLLABLE CCHAA +2DBC ; [.26AD.0020.0002] # ETHIOPIC SYLLABLE CCHEE +2DBD ; [.26AE.0020.0002] # ETHIOPIC SYLLABLE CCHE +2DBE ; [.26AF.0020.0002] # ETHIOPIC SYLLABLE CCHO +2DC0 ; [.26B0.0020.0002] # ETHIOPIC SYLLABLE QYA +2DC1 ; [.26B1.0020.0002] # ETHIOPIC SYLLABLE QYU +2DC2 ; [.26B2.0020.0002] # ETHIOPIC SYLLABLE QYI +2DC3 ; [.26B3.0020.0002] # ETHIOPIC SYLLABLE QYAA +2DC4 ; [.26B4.0020.0002] # ETHIOPIC SYLLABLE QYEE +2DC5 ; [.26B5.0020.0002] # ETHIOPIC SYLLABLE QYE +2DC6 ; [.26B6.0020.0002] # ETHIOPIC SYLLABLE QYO +2DC8 ; [.26B7.0020.0002] # ETHIOPIC SYLLABLE KYA +2DC9 ; [.26B8.0020.0002] # ETHIOPIC SYLLABLE KYU +2DCA ; [.26B9.0020.0002] # ETHIOPIC SYLLABLE KYI +2DCB ; [.26BA.0020.0002] # ETHIOPIC SYLLABLE KYAA +2DCC ; [.26BB.0020.0002] # ETHIOPIC SYLLABLE KYEE +2DCD ; [.26BC.0020.0002] # ETHIOPIC SYLLABLE KYE +2DCE ; [.26BD.0020.0002] # ETHIOPIC SYLLABLE KYO +2DD0 ; [.26BE.0020.0002] # ETHIOPIC SYLLABLE XYA +2DD1 ; [.26BF.0020.0002] # ETHIOPIC SYLLABLE XYU +2DD2 ; [.26C0.0020.0002] # ETHIOPIC SYLLABLE XYI +2DD3 ; [.26C1.0020.0002] # ETHIOPIC SYLLABLE XYAA +2DD4 ; [.26C2.0020.0002] # ETHIOPIC SYLLABLE XYEE +2DD5 ; [.26C3.0020.0002] # ETHIOPIC SYLLABLE XYE +2DD6 ; [.26C4.0020.0002] # ETHIOPIC SYLLABLE XYO +2DD8 ; [.26C5.0020.0002] # ETHIOPIC SYLLABLE GYA +2DD9 ; [.26C6.0020.0002] # ETHIOPIC SYLLABLE GYU +2DDA ; [.26C7.0020.0002] # ETHIOPIC SYLLABLE GYI +2DDB ; [.26C8.0020.0002] # ETHIOPIC SYLLABLE GYAA +2DDC ; [.26C9.0020.0002] # ETHIOPIC SYLLABLE GYEE +2DDD ; [.26CA.0020.0002] # ETHIOPIC SYLLABLE GYE +2DDE ; [.26CB.0020.0002] # ETHIOPIC SYLLABLE GYO +0950 ; [.26CC.0020.0002] # DEVANAGARI OM +A8FD ; [.26CD.0020.0002] # DEVANAGARI JAIN OM +0972 ; [.26CE.0020.0002] # DEVANAGARI LETTER CANDRA A +0904 ; [.26CF.0020.0002] # DEVANAGARI LETTER SHORT A +0905 ; [.26D0.0020.0002] # DEVANAGARI LETTER A +0906 ; [.26D1.0020.0002] # DEVANAGARI LETTER AA +0973 ; [.26D2.0020.0002] # DEVANAGARI LETTER OE +0974 ; [.26D3.0020.0002] # DEVANAGARI LETTER OOE +0975 ; [.26D4.0020.0002] # DEVANAGARI LETTER AW +0976 ; [.26D5.0020.0002] # DEVANAGARI LETTER UE +0977 ; [.26D6.0020.0002] # DEVANAGARI LETTER UUE +0907 ; [.26D7.0020.0002] # DEVANAGARI LETTER I +0908 ; [.26D8.0020.0002] # DEVANAGARI LETTER II +0909 ; [.26D9.0020.0002] # DEVANAGARI LETTER U +090A ; [.26DA.0020.0002] # DEVANAGARI LETTER UU +090B ; [.26DB.0020.0002] # DEVANAGARI LETTER VOCALIC R +0960 ; [.26DC.0020.0002] # DEVANAGARI LETTER VOCALIC RR +090C ; [.26DD.0020.0002] # DEVANAGARI LETTER VOCALIC L +0961 ; [.26DE.0020.0002] # DEVANAGARI LETTER VOCALIC LL +090D ; [.26DF.0020.0002] # DEVANAGARI LETTER CANDRA E +090E ; [.26E0.0020.0002] # DEVANAGARI LETTER SHORT E +090F ; [.26E1.0020.0002] # DEVANAGARI LETTER E +0910 ; [.26E2.0020.0002] # DEVANAGARI LETTER AI +0911 ; [.26E3.0020.0002] # DEVANAGARI LETTER CANDRA O +0912 ; [.26E4.0020.0002] # DEVANAGARI LETTER SHORT O +0913 ; [.26E5.0020.0002] # DEVANAGARI LETTER O +0914 ; [.26E6.0020.0002] # DEVANAGARI LETTER AU +0915 ; [.26E7.0020.0002] # DEVANAGARI LETTER KA +0958 ; [.26E7.0020.0002][.0000.00C2.0002] # DEVANAGARI LETTER QA +0916 ; [.26E8.0020.0002] # DEVANAGARI LETTER KHA +0959 ; [.26E8.0020.0002][.0000.00C2.0002] # DEVANAGARI LETTER KHHA +0917 ; [.26E9.0020.0002] # DEVANAGARI LETTER GA +095A ; [.26E9.0020.0002][.0000.00C2.0002] # DEVANAGARI LETTER GHHA +097B ; [.26EA.0020.0002] # DEVANAGARI LETTER GGA +0918 ; [.26EB.0020.0002] # DEVANAGARI LETTER GHA +0919 ; [.26EC.0020.0002] # DEVANAGARI LETTER NGA +091A ; [.26ED.0020.0002] # DEVANAGARI LETTER CA +091B ; [.26EE.0020.0002] # DEVANAGARI LETTER CHA +091C ; [.26EF.0020.0002] # DEVANAGARI LETTER JA +095B ; [.26EF.0020.0002][.0000.00C2.0002] # DEVANAGARI LETTER ZA +0979 ; [.26F0.0020.0002] # DEVANAGARI LETTER ZHA +097C ; [.26F1.0020.0002] # DEVANAGARI LETTER JJA +091D ; [.26F2.0020.0002] # DEVANAGARI LETTER JHA +091E ; [.26F3.0020.0002] # DEVANAGARI LETTER NYA +091F ; [.26F4.0020.0002] # DEVANAGARI LETTER TTA +0920 ; [.26F5.0020.0002] # DEVANAGARI LETTER TTHA +0978 ; [.26F6.0020.0002] # DEVANAGARI LETTER MARWARI DDA +0921 ; [.26F7.0020.0002] # DEVANAGARI LETTER DDA +095C ; [.26F7.0020.0002][.0000.00C2.0002] # DEVANAGARI LETTER DDDHA +097E ; [.26F8.0020.0002] # DEVANAGARI LETTER DDDA +0922 ; [.26F9.0020.0002] # DEVANAGARI LETTER DDHA +095D ; [.26F9.0020.0002][.0000.00C2.0002] # DEVANAGARI LETTER RHA +0923 ; [.26FA.0020.0002] # DEVANAGARI LETTER NNA +0924 ; [.26FB.0020.0002] # DEVANAGARI LETTER TA +0925 ; [.26FC.0020.0002] # DEVANAGARI LETTER THA +0926 ; [.26FD.0020.0002] # DEVANAGARI LETTER DA +0927 ; [.26FE.0020.0002] # DEVANAGARI LETTER DHA +0928 ; [.26FF.0020.0002] # DEVANAGARI LETTER NA +0929 ; [.26FF.0020.0002][.0000.00C2.0002] # DEVANAGARI LETTER NNNA +092A ; [.2700.0020.0002] # DEVANAGARI LETTER PA +092B ; [.2701.0020.0002] # DEVANAGARI LETTER PHA +095E ; [.2701.0020.0002][.0000.00C2.0002] # DEVANAGARI LETTER FA +092C ; [.2702.0020.0002] # DEVANAGARI LETTER BA +097F ; [.2703.0020.0002] # DEVANAGARI LETTER BBA +092D ; [.2704.0020.0002] # DEVANAGARI LETTER BHA +092E ; [.2705.0020.0002] # DEVANAGARI LETTER MA +092F ; [.2706.0020.0002] # DEVANAGARI LETTER YA +095F ; [.2706.0020.0002][.0000.00C2.0002] # DEVANAGARI LETTER YYA +097A ; [.2707.0020.0002] # DEVANAGARI LETTER HEAVY YA +0930 ; [.2708.0020.0002] # DEVANAGARI LETTER RA +0931 ; [.2708.0020.0002][.0000.00C2.0002] # DEVANAGARI LETTER RRA +0932 ; [.2709.0020.0002] # DEVANAGARI LETTER LA +0933 ; [.270A.0020.0002] # DEVANAGARI LETTER LLA +0934 ; [.270A.0020.0002][.0000.00C2.0002] # DEVANAGARI LETTER LLLA +0935 ; [.270B.0020.0002] # DEVANAGARI LETTER VA +0936 ; [.270C.0020.0002] # DEVANAGARI LETTER SHA +0937 ; [.270D.0020.0002] # DEVANAGARI LETTER SSA +0938 ; [.270E.0020.0002] # DEVANAGARI LETTER SA +0939 ; [.270F.0020.0002] # DEVANAGARI LETTER HA +093D ; [.2710.0020.0002] # DEVANAGARI SIGN AVAGRAHA +097D ; [.2711.0020.0002] # DEVANAGARI LETTER GLOTTAL STOP +1CE9 ; [.2712.0020.0002] # VEDIC SIGN ANUSVARA ANTARGOMUKHA +1CEA ; [.2712.0020.0004] # VEDIC SIGN ANUSVARA BAHIRGOMUKHA +1CEB ; [.2712.0020.0004] # VEDIC SIGN ANUSVARA VAMAGOMUKHA +1CEC ; [.2712.0020.0004] # VEDIC SIGN ANUSVARA VAMAGOMUKHA WITH TAIL +1CEE ; [.2712.0020.0004] # VEDIC SIGN HEXIFORM LONG ANUSVARA +1CEF ; [.2712.0020.0004] # VEDIC SIGN LONG ANUSVARA +1CF0 ; [.2712.0020.0004] # VEDIC SIGN RTHANG LONG ANUSVARA +1CF1 ; [.2712.0020.0004] # VEDIC SIGN ANUSVARA UBHAYATO MUKHA +1CF5 ; [.2713.0020.0002] # VEDIC SIGN JIHVAMULIYA +1CF6 ; [.2714.0020.0002] # VEDIC SIGN UPADHMANIYA +A8F2 ; [.2715.0020.0002] # DEVANAGARI SIGN SPACING CANDRABINDU +A8F3 ; [.2715.0020.0004] # DEVANAGARI SIGN CANDRABINDU VIRAMA +A8F4 ; [.2715.0020.0004] # DEVANAGARI SIGN DOUBLE CANDRABINDU VIRAMA +A8F5 ; [.2715.0020.0004] # DEVANAGARI SIGN CANDRABINDU TWO +A8F6 ; [.2715.0020.0004] # DEVANAGARI SIGN CANDRABINDU THREE +A8F7 ; [.2715.0020.0004] # DEVANAGARI SIGN CANDRABINDU AVAGRAHA +A8FB ; [.2716.0020.0002] # DEVANAGARI HEADSTROKE +093E ; [.2717.0020.0002] # DEVANAGARI VOWEL SIGN AA +093A ; [.2718.0020.0002] # DEVANAGARI VOWEL SIGN OE +093B ; [.2719.0020.0002] # DEVANAGARI VOWEL SIGN OOE +094F ; [.271A.0020.0002] # DEVANAGARI VOWEL SIGN AW +0956 ; [.271B.0020.0002] # DEVANAGARI VOWEL SIGN UE +0957 ; [.271C.0020.0002] # DEVANAGARI VOWEL SIGN UUE +093F ; [.271D.0020.0002] # DEVANAGARI VOWEL SIGN I +0940 ; [.271E.0020.0002] # DEVANAGARI VOWEL SIGN II +0941 ; [.271F.0020.0002] # DEVANAGARI VOWEL SIGN U +0942 ; [.2720.0020.0002] # DEVANAGARI VOWEL SIGN UU +0943 ; [.2721.0020.0002] # DEVANAGARI VOWEL SIGN VOCALIC R +0944 ; [.2722.0020.0002] # DEVANAGARI VOWEL SIGN VOCALIC RR +0962 ; [.2723.0020.0002] # DEVANAGARI VOWEL SIGN VOCALIC L +0963 ; [.2724.0020.0002] # DEVANAGARI VOWEL SIGN VOCALIC LL +0945 ; [.2725.0020.0002] # DEVANAGARI VOWEL SIGN CANDRA E +0955 ; [.2726.0020.0002] # DEVANAGARI VOWEL SIGN CANDRA LONG E +0946 ; [.2727.0020.0002] # DEVANAGARI VOWEL SIGN SHORT E +0947 ; [.2728.0020.0002] # DEVANAGARI VOWEL SIGN E +094E ; [.2729.0020.0002] # DEVANAGARI VOWEL SIGN PRISHTHAMATRA E +0948 ; [.272A.0020.0002] # DEVANAGARI VOWEL SIGN AI +0949 ; [.272B.0020.0002] # DEVANAGARI VOWEL SIGN CANDRA O +094A ; [.272C.0020.0002] # DEVANAGARI VOWEL SIGN SHORT O +094B ; [.272D.0020.0002] # DEVANAGARI VOWEL SIGN O +094C ; [.272E.0020.0002] # DEVANAGARI VOWEL SIGN AU +094D ; [.272F.0020.0002] # DEVANAGARI SIGN VIRAMA +0980 ; [.2730.0020.0002] # BENGALI ANJI +0985 ; [.2731.0020.0002] # BENGALI LETTER A +0986 ; [.2732.0020.0002] # BENGALI LETTER AA +0987 ; [.2733.0020.0002] # BENGALI LETTER I +0988 ; [.2734.0020.0002] # BENGALI LETTER II +0989 ; [.2735.0020.0002] # BENGALI LETTER U +098A ; [.2736.0020.0002] # BENGALI LETTER UU +098B ; [.2737.0020.0002] # BENGALI LETTER VOCALIC R +09E0 ; [.2738.0020.0002] # BENGALI LETTER VOCALIC RR +098C ; [.2739.0020.0002] # BENGALI LETTER VOCALIC L +09E1 ; [.273A.0020.0002] # BENGALI LETTER VOCALIC LL +098F ; [.273B.0020.0002] # BENGALI LETTER E +0990 ; [.273C.0020.0002] # BENGALI LETTER AI +0993 ; [.273D.0020.0002] # BENGALI LETTER O +0994 ; [.273E.0020.0002] # BENGALI LETTER AU +0995 ; [.273F.0020.0002] # BENGALI LETTER KA +0996 ; [.2740.0020.0002] # BENGALI LETTER KHA +0997 ; [.2741.0020.0002] # BENGALI LETTER GA +0998 ; [.2742.0020.0002] # BENGALI LETTER GHA +0999 ; [.2743.0020.0002] # BENGALI LETTER NGA +099A ; [.2744.0020.0002] # BENGALI LETTER CA +099B ; [.2745.0020.0002] # BENGALI LETTER CHA +099C ; [.2746.0020.0002] # BENGALI LETTER JA +099D ; [.2747.0020.0002] # BENGALI LETTER JHA +099E ; [.2748.0020.0002] # BENGALI LETTER NYA +099F ; [.2749.0020.0002] # BENGALI LETTER TTA +09A0 ; [.274A.0020.0002] # BENGALI LETTER TTHA +09A1 ; [.274B.0020.0002] # BENGALI LETTER DDA +09DC ; [.274B.0020.0002][.0000.00C2.0002] # BENGALI LETTER RRA +09A2 ; [.274C.0020.0002] # BENGALI LETTER DDHA +09DD ; [.274C.0020.0002][.0000.00C2.0002] # BENGALI LETTER RHA +09A3 ; [.274D.0020.0002] # BENGALI LETTER NNA +09A4 ; [.274E.0020.0002] # BENGALI LETTER TA +09CE ; [.274E.0020.0004][.276F.0020.0004] # BENGALI LETTER KHANDA TA +09A5 ; [.274F.0020.0002] # BENGALI LETTER THA +09A6 ; [.2750.0020.0002] # BENGALI LETTER DA +09A7 ; [.2751.0020.0002] # BENGALI LETTER DHA +09A8 ; [.2752.0020.0002] # BENGALI LETTER NA +09AA ; [.2753.0020.0002] # BENGALI LETTER PA +09AB ; [.2754.0020.0002] # BENGALI LETTER PHA +09AC ; [.2755.0020.0002] # BENGALI LETTER BA +09AD ; [.2756.0020.0002] # BENGALI LETTER BHA +09AE ; [.2757.0020.0002] # BENGALI LETTER MA +09AF ; [.2758.0020.0002] # BENGALI LETTER YA +09DF ; [.2758.0020.0002][.0000.00C2.0002] # BENGALI LETTER YYA +09B0 ; [.2759.0020.0002] # BENGALI LETTER RA +09F0 ; [.275A.0020.0002] # BENGALI LETTER RA WITH MIDDLE DIAGONAL +09B2 ; [.275B.0020.0002] # BENGALI LETTER LA +09F1 ; [.275C.0020.0002] # BENGALI LETTER RA WITH LOWER DIAGONAL +09B6 ; [.275D.0020.0002] # BENGALI LETTER SHA +09B7 ; [.275E.0020.0002] # BENGALI LETTER SSA +09B8 ; [.275F.0020.0002] # BENGALI LETTER SA +09B9 ; [.2760.0020.0002] # BENGALI LETTER HA +09BD ; [.2761.0020.0002] # BENGALI SIGN AVAGRAHA +09BE ; [.2762.0020.0002] # BENGALI VOWEL SIGN AA +09BF ; [.2763.0020.0002] # BENGALI VOWEL SIGN I +09C0 ; [.2764.0020.0002] # BENGALI VOWEL SIGN II +09C1 ; [.2765.0020.0002] # BENGALI VOWEL SIGN U +09C2 ; [.2766.0020.0002] # BENGALI VOWEL SIGN UU +09C3 ; [.2767.0020.0002] # BENGALI VOWEL SIGN VOCALIC R +09C4 ; [.2768.0020.0002] # BENGALI VOWEL SIGN VOCALIC RR +09E2 ; [.2769.0020.0002] # BENGALI VOWEL SIGN VOCALIC L +09E3 ; [.276A.0020.0002] # BENGALI VOWEL SIGN VOCALIC LL +09C7 ; [.276B.0020.0002] # BENGALI VOWEL SIGN E +09C8 ; [.276C.0020.0002] # BENGALI VOWEL SIGN AI +09CB ; [.276D.0020.0002] # BENGALI VOWEL SIGN O +09C7 09BE ; [.276D.0020.0002] # BENGALI VOWEL SIGN O +09CC ; [.276E.0020.0002] # BENGALI VOWEL SIGN AU +09C7 09D7 ; [.276E.0020.0002] # BENGALI VOWEL SIGN AU +09CD ; [.276F.0020.0002] # BENGALI SIGN VIRAMA +09D7 ; [.2770.0020.0002] # BENGALI AU LENGTH MARK +09FC ; [.2771.0020.0002] # BENGALI LETTER VEDIC ANUSVARA +0A74 ; [.2772.0020.0002] # GURMUKHI EK ONKAR +0A73 ; [.2773.0020.0002] # GURMUKHI URA +0A09 ; [.2774.0020.0002] # GURMUKHI LETTER U +0A0A ; [.2775.0020.0002] # GURMUKHI LETTER UU +0A13 ; [.2776.0020.0002] # GURMUKHI LETTER OO +0A05 ; [.2777.0020.0002] # GURMUKHI LETTER A +0A06 ; [.2778.0020.0002] # GURMUKHI LETTER AA +0A10 ; [.2779.0020.0002] # GURMUKHI LETTER AI +0A14 ; [.277A.0020.0002] # GURMUKHI LETTER AU +0A72 ; [.277B.0020.0002] # GURMUKHI IRI +0A07 ; [.277C.0020.0002] # GURMUKHI LETTER I +0A08 ; [.277D.0020.0002] # GURMUKHI LETTER II +0A0F ; [.277E.0020.0002] # GURMUKHI LETTER EE +0A38 ; [.277F.0020.0002] # GURMUKHI LETTER SA +0A36 ; [.277F.0020.0002][.0000.00C2.0002] # GURMUKHI LETTER SHA +0A39 ; [.2780.0020.0002] # GURMUKHI LETTER HA +0A51 ; [.2781.0020.0002] # GURMUKHI SIGN UDAAT +0A15 ; [.2782.0020.0002] # GURMUKHI LETTER KA +0A16 ; [.2783.0020.0002] # GURMUKHI LETTER KHA +0A59 ; [.2783.0020.0002][.0000.00C2.0002] # GURMUKHI LETTER KHHA +0A17 ; [.2784.0020.0002] # GURMUKHI LETTER GA +0A5A ; [.2784.0020.0002][.0000.00C2.0002] # GURMUKHI LETTER GHHA +0A18 ; [.2785.0020.0002] # GURMUKHI LETTER GHA +0A19 ; [.2786.0020.0002] # GURMUKHI LETTER NGA +0A1A ; [.2787.0020.0002] # GURMUKHI LETTER CA +0A1B ; [.2788.0020.0002] # GURMUKHI LETTER CHA +0A1C ; [.2789.0020.0002] # GURMUKHI LETTER JA +0A5B ; [.2789.0020.0002][.0000.00C2.0002] # GURMUKHI LETTER ZA +0A1D ; [.278A.0020.0002] # GURMUKHI LETTER JHA +0A1E ; [.278B.0020.0002] # GURMUKHI LETTER NYA +0A1F ; [.278C.0020.0002] # GURMUKHI LETTER TTA +0A20 ; [.278D.0020.0002] # GURMUKHI LETTER TTHA +0A21 ; [.278E.0020.0002] # GURMUKHI LETTER DDA +0A22 ; [.278F.0020.0002] # GURMUKHI LETTER DDHA +0A23 ; [.2790.0020.0002] # GURMUKHI LETTER NNA +0A24 ; [.2791.0020.0002] # GURMUKHI LETTER TA +0A25 ; [.2792.0020.0002] # GURMUKHI LETTER THA +0A26 ; [.2793.0020.0002] # GURMUKHI LETTER DA +0A27 ; [.2794.0020.0002] # GURMUKHI LETTER DHA +0A28 ; [.2795.0020.0002] # GURMUKHI LETTER NA +0A2A ; [.2796.0020.0002] # GURMUKHI LETTER PA +0A2B ; [.2797.0020.0002] # GURMUKHI LETTER PHA +0A5E ; [.2797.0020.0002][.0000.00C2.0002] # GURMUKHI LETTER FA +0A2C ; [.2798.0020.0002] # GURMUKHI LETTER BA +0A2D ; [.2799.0020.0002] # GURMUKHI LETTER BHA +0A2E ; [.279A.0020.0002] # GURMUKHI LETTER MA +0A2F ; [.279B.0020.0002] # GURMUKHI LETTER YA +0A75 ; [.279C.0020.0002] # GURMUKHI SIGN YAKASH +0A30 ; [.279D.0020.0002] # GURMUKHI LETTER RA +0A32 ; [.279E.0020.0002] # GURMUKHI LETTER LA +0A33 ; [.279E.0020.0002][.0000.00C2.0002] # GURMUKHI LETTER LLA +0A35 ; [.279F.0020.0002] # GURMUKHI LETTER VA +0A5C ; [.27A0.0020.0002] # GURMUKHI LETTER RRA +0A3E ; [.27A1.0020.0002] # GURMUKHI VOWEL SIGN AA +0A3F ; [.27A2.0020.0002] # GURMUKHI VOWEL SIGN I +0A40 ; [.27A3.0020.0002] # GURMUKHI VOWEL SIGN II +0A41 ; [.27A4.0020.0002] # GURMUKHI VOWEL SIGN U +0A42 ; [.27A5.0020.0002] # GURMUKHI VOWEL SIGN UU +0A47 ; [.27A6.0020.0002] # GURMUKHI VOWEL SIGN EE +0A48 ; [.27A7.0020.0002] # GURMUKHI VOWEL SIGN AI +0A4B ; [.27A8.0020.0002] # GURMUKHI VOWEL SIGN OO +0A4C ; [.27A9.0020.0002] # GURMUKHI VOWEL SIGN AU +0A4D ; [.27AA.0020.0002] # GURMUKHI SIGN VIRAMA +0AD0 ; [.27AB.0020.0002] # GUJARATI OM +0A85 ; [.27AC.0020.0002] # GUJARATI LETTER A +0A86 ; [.27AD.0020.0002] # GUJARATI LETTER AA +0A87 ; [.27AE.0020.0002] # GUJARATI LETTER I +0A88 ; [.27AF.0020.0002] # GUJARATI LETTER II +0A89 ; [.27B0.0020.0002] # GUJARATI LETTER U +0A8A ; [.27B1.0020.0002] # GUJARATI LETTER UU +0A8B ; [.27B2.0020.0002] # GUJARATI LETTER VOCALIC R +0AE0 ; [.27B3.0020.0002] # GUJARATI LETTER VOCALIC RR +0A8C ; [.27B4.0020.0002] # GUJARATI LETTER VOCALIC L +0AE1 ; [.27B5.0020.0002] # GUJARATI LETTER VOCALIC LL +0A8D ; [.27B6.0020.0002] # GUJARATI VOWEL CANDRA E +0A8F ; [.27B7.0020.0002] # GUJARATI LETTER E +0A90 ; [.27B8.0020.0002] # GUJARATI LETTER AI +0A91 ; [.27B9.0020.0002] # GUJARATI VOWEL CANDRA O +0A93 ; [.27BA.0020.0002] # GUJARATI LETTER O +0A94 ; [.27BB.0020.0002] # GUJARATI LETTER AU +0A95 ; [.27BC.0020.0002] # GUJARATI LETTER KA +0A96 ; [.27BD.0020.0002] # GUJARATI LETTER KHA +0A97 ; [.27BE.0020.0002] # GUJARATI LETTER GA +0A98 ; [.27BF.0020.0002] # GUJARATI LETTER GHA +0A99 ; [.27C0.0020.0002] # GUJARATI LETTER NGA +0A9A ; [.27C1.0020.0002] # GUJARATI LETTER CA +0A9B ; [.27C2.0020.0002] # GUJARATI LETTER CHA +0A9C ; [.27C3.0020.0002] # GUJARATI LETTER JA +0AF9 ; [.27C4.0020.0002] # GUJARATI LETTER ZHA +0A9D ; [.27C5.0020.0002] # GUJARATI LETTER JHA +0A9E ; [.27C6.0020.0002] # GUJARATI LETTER NYA +0A9F ; [.27C7.0020.0002] # GUJARATI LETTER TTA +0AA0 ; [.27C8.0020.0002] # GUJARATI LETTER TTHA +0AA1 ; [.27C9.0020.0002] # GUJARATI LETTER DDA +0AA2 ; [.27CA.0020.0002] # GUJARATI LETTER DDHA +0AA3 ; [.27CB.0020.0002] # GUJARATI LETTER NNA +0AA4 ; [.27CC.0020.0002] # GUJARATI LETTER TA +0AA5 ; [.27CD.0020.0002] # GUJARATI LETTER THA +0AA6 ; [.27CE.0020.0002] # GUJARATI LETTER DA +0AA7 ; [.27CF.0020.0002] # GUJARATI LETTER DHA +0AA8 ; [.27D0.0020.0002] # GUJARATI LETTER NA +0AAA ; [.27D1.0020.0002] # GUJARATI LETTER PA +0AAB ; [.27D2.0020.0002] # GUJARATI LETTER PHA +0AAC ; [.27D3.0020.0002] # GUJARATI LETTER BA +0AAD ; [.27D4.0020.0002] # GUJARATI LETTER BHA +0AAE ; [.27D5.0020.0002] # GUJARATI LETTER MA +0AAF ; [.27D6.0020.0002] # GUJARATI LETTER YA +0AB0 ; [.27D7.0020.0002] # GUJARATI LETTER RA +0AB2 ; [.27D8.0020.0002] # GUJARATI LETTER LA +0AB5 ; [.27D9.0020.0002] # GUJARATI LETTER VA +0AB6 ; [.27DA.0020.0002] # GUJARATI LETTER SHA +0AB7 ; [.27DB.0020.0002] # GUJARATI LETTER SSA +0AB8 ; [.27DC.0020.0002] # GUJARATI LETTER SA +0AB9 ; [.27DD.0020.0002] # GUJARATI LETTER HA +0AB3 ; [.27DE.0020.0002] # GUJARATI LETTER LLA +0ABD ; [.27DF.0020.0002] # GUJARATI SIGN AVAGRAHA +0ABE ; [.27E0.0020.0002] # GUJARATI VOWEL SIGN AA +0ABF ; [.27E1.0020.0002] # GUJARATI VOWEL SIGN I +0AC0 ; [.27E2.0020.0002] # GUJARATI VOWEL SIGN II +0AC1 ; [.27E3.0020.0002] # GUJARATI VOWEL SIGN U +0AC2 ; [.27E4.0020.0002] # GUJARATI VOWEL SIGN UU +0AC3 ; [.27E5.0020.0002] # GUJARATI VOWEL SIGN VOCALIC R +0AC4 ; [.27E6.0020.0002] # GUJARATI VOWEL SIGN VOCALIC RR +0AE2 ; [.27E7.0020.0002] # GUJARATI VOWEL SIGN VOCALIC L +0AE3 ; [.27E8.0020.0002] # GUJARATI VOWEL SIGN VOCALIC LL +0AC5 ; [.27E9.0020.0002] # GUJARATI VOWEL SIGN CANDRA E +0AC7 ; [.27EA.0020.0002] # GUJARATI VOWEL SIGN E +0AC8 ; [.27EB.0020.0002] # GUJARATI VOWEL SIGN AI +0AC9 ; [.27EC.0020.0002] # GUJARATI VOWEL SIGN CANDRA O +0ACB ; [.27ED.0020.0002] # GUJARATI VOWEL SIGN O +0ACC ; [.27EE.0020.0002] # GUJARATI VOWEL SIGN AU +0ACD ; [.27EF.0020.0002] # GUJARATI SIGN VIRAMA +0B05 ; [.27F0.0020.0002] # ORIYA LETTER A +0B06 ; [.27F1.0020.0002] # ORIYA LETTER AA +0B07 ; [.27F2.0020.0002] # ORIYA LETTER I +0B08 ; [.27F3.0020.0002] # ORIYA LETTER II +0B09 ; [.27F4.0020.0002] # ORIYA LETTER U +0B0A ; [.27F5.0020.0002] # ORIYA LETTER UU +0B0B ; [.27F6.0020.0002] # ORIYA LETTER VOCALIC R +0B60 ; [.27F7.0020.0002] # ORIYA LETTER VOCALIC RR +0B0C ; [.27F8.0020.0002] # ORIYA LETTER VOCALIC L +0B61 ; [.27F9.0020.0002] # ORIYA LETTER VOCALIC LL +0B0F ; [.27FA.0020.0002] # ORIYA LETTER E +0B10 ; [.27FB.0020.0002] # ORIYA LETTER AI +0B13 ; [.27FC.0020.0002] # ORIYA LETTER O +0B14 ; [.27FD.0020.0002] # ORIYA LETTER AU +0B15 ; [.27FE.0020.0002] # ORIYA LETTER KA +0B16 ; [.27FF.0020.0002] # ORIYA LETTER KHA +0B17 ; [.2800.0020.0002] # ORIYA LETTER GA +0B18 ; [.2801.0020.0002] # ORIYA LETTER GHA +0B19 ; [.2802.0020.0002] # ORIYA LETTER NGA +0B1A ; [.2803.0020.0002] # ORIYA LETTER CA +0B1B ; [.2804.0020.0002] # ORIYA LETTER CHA +0B1C ; [.2805.0020.0002] # ORIYA LETTER JA +0B1D ; [.2806.0020.0002] # ORIYA LETTER JHA +0B1E ; [.2807.0020.0002] # ORIYA LETTER NYA +0B1F ; [.2808.0020.0002] # ORIYA LETTER TTA +0B20 ; [.2809.0020.0002] # ORIYA LETTER TTHA +0B21 ; [.280A.0020.0002] # ORIYA LETTER DDA +0B5C ; [.280A.0020.0002][.0000.00C2.0002] # ORIYA LETTER RRA +0B22 ; [.280B.0020.0002] # ORIYA LETTER DDHA +0B5D ; [.280B.0020.0002][.0000.00C2.0002] # ORIYA LETTER RHA +0B23 ; [.280C.0020.0002] # ORIYA LETTER NNA +0B24 ; [.280D.0020.0002] # ORIYA LETTER TA +0B25 ; [.280E.0020.0002] # ORIYA LETTER THA +0B26 ; [.280F.0020.0002] # ORIYA LETTER DA +0B27 ; [.2810.0020.0002] # ORIYA LETTER DHA +0B28 ; [.2811.0020.0002] # ORIYA LETTER NA +0B2A ; [.2812.0020.0002] # ORIYA LETTER PA +0B2B ; [.2813.0020.0002] # ORIYA LETTER PHA +0B2C ; [.2814.0020.0002] # ORIYA LETTER BA +0B2D ; [.2815.0020.0002] # ORIYA LETTER BHA +0B2E ; [.2816.0020.0002] # ORIYA LETTER MA +0B2F ; [.2817.0020.0002] # ORIYA LETTER YA +0B5F ; [.2818.0020.0002] # ORIYA LETTER YYA +0B30 ; [.2819.0020.0002] # ORIYA LETTER RA +0B32 ; [.281A.0020.0002] # ORIYA LETTER LA +0B33 ; [.281B.0020.0002] # ORIYA LETTER LLA +0B35 ; [.281C.0020.0002] # ORIYA LETTER VA +0B71 ; [.281D.0020.0002] # ORIYA LETTER WA +0B36 ; [.281E.0020.0002] # ORIYA LETTER SHA +0B37 ; [.281F.0020.0002] # ORIYA LETTER SSA +0B38 ; [.2820.0020.0002] # ORIYA LETTER SA +0B39 ; [.2821.0020.0002] # ORIYA LETTER HA +0B3D ; [.2822.0020.0002] # ORIYA SIGN AVAGRAHA +0B3E ; [.2823.0020.0002] # ORIYA VOWEL SIGN AA +0B3F ; [.2824.0020.0002] # ORIYA VOWEL SIGN I +0B40 ; [.2825.0020.0002] # ORIYA VOWEL SIGN II +0B41 ; [.2826.0020.0002] # ORIYA VOWEL SIGN U +0B42 ; [.2827.0020.0002] # ORIYA VOWEL SIGN UU +0B43 ; [.2828.0020.0002] # ORIYA VOWEL SIGN VOCALIC R +0B44 ; [.2829.0020.0002] # ORIYA VOWEL SIGN VOCALIC RR +0B62 ; [.282A.0020.0002] # ORIYA VOWEL SIGN VOCALIC L +0B63 ; [.282B.0020.0002] # ORIYA VOWEL SIGN VOCALIC LL +0B47 ; [.282C.0020.0002] # ORIYA VOWEL SIGN E +0B48 ; [.282D.0020.0002] # ORIYA VOWEL SIGN AI +0B47 0B56 ; [.282D.0020.0002] # ORIYA VOWEL SIGN AI +0B4B ; [.282E.0020.0002] # ORIYA VOWEL SIGN O +0B47 0B3E ; [.282E.0020.0002] # ORIYA VOWEL SIGN O +0B4C ; [.282F.0020.0002] # ORIYA VOWEL SIGN AU +0B47 0B57 ; [.282F.0020.0002] # ORIYA VOWEL SIGN AU +0B4D ; [.2830.0020.0002] # ORIYA SIGN VIRAMA +0B56 ; [.2831.0020.0002] # ORIYA AI LENGTH MARK +0B57 ; [.2832.0020.0002] # ORIYA AU LENGTH MARK +0BD0 ; [.2833.0020.0002] # TAMIL OM +0B85 ; [.2834.0020.0002] # TAMIL LETTER A +0B86 ; [.2835.0020.0002] # TAMIL LETTER AA +0B87 ; [.2836.0020.0002] # TAMIL LETTER I +0B88 ; [.2837.0020.0002] # TAMIL LETTER II +0B89 ; [.2838.0020.0002] # TAMIL LETTER U +0B8A ; [.2839.0020.0002] # TAMIL LETTER UU +0B8E ; [.283A.0020.0002] # TAMIL LETTER E +0B8F ; [.283B.0020.0002] # TAMIL LETTER EE +0B90 ; [.283C.0020.0002] # TAMIL LETTER AI +0B92 ; [.283D.0020.0002] # TAMIL LETTER O +0B93 ; [.283E.0020.0002] # TAMIL LETTER OO +0B94 ; [.283F.0020.0002] # TAMIL LETTER AU +0B92 0BD7 ; [.283F.0020.0002] # TAMIL LETTER AU +0B83 ; [.2840.0020.0002] # TAMIL SIGN VISARGA +0B95 ; [.2841.0020.0002] # TAMIL LETTER KA +0B99 ; [.2842.0020.0002] # TAMIL LETTER NGA +0B9A ; [.2843.0020.0002] # TAMIL LETTER CA +0B9E ; [.2844.0020.0002] # TAMIL LETTER NYA +0B9F ; [.2845.0020.0002] # TAMIL LETTER TTA +0BA3 ; [.2846.0020.0002] # TAMIL LETTER NNA +0BA4 ; [.2847.0020.0002] # TAMIL LETTER TA +0BA8 ; [.2848.0020.0002] # TAMIL LETTER NA +0BAA ; [.2849.0020.0002] # TAMIL LETTER PA +0BAE ; [.284A.0020.0002] # TAMIL LETTER MA +0BAF ; [.284B.0020.0002] # TAMIL LETTER YA +0BB0 ; [.284C.0020.0002] # TAMIL LETTER RA +0BB2 ; [.284D.0020.0002] # TAMIL LETTER LA +0BB5 ; [.284E.0020.0002] # TAMIL LETTER VA +0BB4 ; [.284F.0020.0002] # TAMIL LETTER LLLA +0BB3 ; [.2850.0020.0002] # TAMIL LETTER LLA +0BB1 ; [.2851.0020.0002] # TAMIL LETTER RRA +0BA9 ; [.2852.0020.0002] # TAMIL LETTER NNNA +0B9C ; [.2853.0020.0002] # TAMIL LETTER JA +0BB6 ; [.2854.0020.0002] # TAMIL LETTER SHA +0BB7 ; [.2855.0020.0002] # TAMIL LETTER SSA +0BB8 ; [.2856.0020.0002] # TAMIL LETTER SA +0BB9 ; [.2857.0020.0002] # TAMIL LETTER HA +0BBE ; [.2858.0020.0002] # TAMIL VOWEL SIGN AA +0BBF ; [.2859.0020.0002] # TAMIL VOWEL SIGN I +0BC0 ; [.285A.0020.0002] # TAMIL VOWEL SIGN II +0BC1 ; [.285B.0020.0002] # TAMIL VOWEL SIGN U +0BC2 ; [.285C.0020.0002] # TAMIL VOWEL SIGN UU +0BC6 ; [.285D.0020.0002] # TAMIL VOWEL SIGN E +0BC7 ; [.285E.0020.0002] # TAMIL VOWEL SIGN EE +0BC8 ; [.285F.0020.0002] # TAMIL VOWEL SIGN AI +0BCA ; [.2860.0020.0002] # TAMIL VOWEL SIGN O +0BC6 0BBE ; [.2860.0020.0002] # TAMIL VOWEL SIGN O +0BCB ; [.2861.0020.0002] # TAMIL VOWEL SIGN OO +0BC7 0BBE ; [.2861.0020.0002] # TAMIL VOWEL SIGN OO +0BCC ; [.2862.0020.0002] # TAMIL VOWEL SIGN AU +0BC6 0BD7 ; [.2862.0020.0002] # TAMIL VOWEL SIGN AU +0BCD ; [.2863.0020.0002] # TAMIL SIGN VIRAMA +0BD7 ; [.2864.0020.0002] # TAMIL AU LENGTH MARK +0C05 ; [.2865.0020.0002] # TELUGU LETTER A +0C06 ; [.2866.0020.0002] # TELUGU LETTER AA +0C07 ; [.2867.0020.0002] # TELUGU LETTER I +0C08 ; [.2868.0020.0002] # TELUGU LETTER II +0C09 ; [.2869.0020.0002] # TELUGU LETTER U +0C0A ; [.286A.0020.0002] # TELUGU LETTER UU +0C0B ; [.286B.0020.0002] # TELUGU LETTER VOCALIC R +0C60 ; [.286C.0020.0002] # TELUGU LETTER VOCALIC RR +0C0C ; [.286D.0020.0002] # TELUGU LETTER VOCALIC L +0C61 ; [.286E.0020.0002] # TELUGU LETTER VOCALIC LL +0C0E ; [.286F.0020.0002] # TELUGU LETTER E +0C0F ; [.2870.0020.0002] # TELUGU LETTER EE +0C10 ; [.2871.0020.0002] # TELUGU LETTER AI +0C12 ; [.2872.0020.0002] # TELUGU LETTER O +0C13 ; [.2873.0020.0002] # TELUGU LETTER OO +0C14 ; [.2874.0020.0002] # TELUGU LETTER AU +0C15 ; [.2875.0020.0002] # TELUGU LETTER KA +0C16 ; [.2876.0020.0002] # TELUGU LETTER KHA +0C17 ; [.2877.0020.0002] # TELUGU LETTER GA +0C18 ; [.2878.0020.0002] # TELUGU LETTER GHA +0C19 ; [.2879.0020.0002] # TELUGU LETTER NGA +0C1A ; [.287A.0020.0002] # TELUGU LETTER CA +0C58 ; [.287B.0020.0002] # TELUGU LETTER TSA +0C1B ; [.287C.0020.0002] # TELUGU LETTER CHA +0C1C ; [.287D.0020.0002] # TELUGU LETTER JA +0C59 ; [.287E.0020.0002] # TELUGU LETTER DZA +0C1D ; [.287F.0020.0002] # TELUGU LETTER JHA +0C1E ; [.2880.0020.0002] # TELUGU LETTER NYA +0C1F ; [.2881.0020.0002] # TELUGU LETTER TTA +0C20 ; [.2882.0020.0002] # TELUGU LETTER TTHA +0C21 ; [.2883.0020.0002] # TELUGU LETTER DDA +0C22 ; [.2884.0020.0002] # TELUGU LETTER DDHA +0C23 ; [.2885.0020.0002] # TELUGU LETTER NNA +0C24 ; [.2886.0020.0002] # TELUGU LETTER TA +0C25 ; [.2887.0020.0002] # TELUGU LETTER THA +0C26 ; [.2888.0020.0002] # TELUGU LETTER DA +0C27 ; [.2889.0020.0002] # TELUGU LETTER DHA +0C28 ; [.288A.0020.0002] # TELUGU LETTER NA +0C2A ; [.288B.0020.0002] # TELUGU LETTER PA +0C2B ; [.288C.0020.0002] # TELUGU LETTER PHA +0C2C ; [.288D.0020.0002] # TELUGU LETTER BA +0C2D ; [.288E.0020.0002] # TELUGU LETTER BHA +0C2E ; [.288F.0020.0002] # TELUGU LETTER MA +0C2F ; [.2890.0020.0002] # TELUGU LETTER YA +0C30 ; [.2891.0020.0002] # TELUGU LETTER RA +0C31 ; [.2892.0020.0002] # TELUGU LETTER RRA +0C32 ; [.2893.0020.0002] # TELUGU LETTER LA +0C35 ; [.2894.0020.0002] # TELUGU LETTER VA +0C36 ; [.2895.0020.0002] # TELUGU LETTER SHA +0C37 ; [.2896.0020.0002] # TELUGU LETTER SSA +0C38 ; [.2897.0020.0002] # TELUGU LETTER SA +0C39 ; [.2898.0020.0002] # TELUGU LETTER HA +0C33 ; [.2899.0020.0002] # TELUGU LETTER LLA +0C34 ; [.289A.0020.0002] # TELUGU LETTER LLLA +0C5A ; [.289B.0020.0002] # TELUGU LETTER RRRA +0C3D ; [.289C.0020.0002] # TELUGU SIGN AVAGRAHA +0C3E ; [.289D.0020.0002] # TELUGU VOWEL SIGN AA +0C3F ; [.289E.0020.0002] # TELUGU VOWEL SIGN I +0C40 ; [.289F.0020.0002] # TELUGU VOWEL SIGN II +0C41 ; [.28A0.0020.0002] # TELUGU VOWEL SIGN U +0C42 ; [.28A1.0020.0002] # TELUGU VOWEL SIGN UU +0C43 ; [.28A2.0020.0002] # TELUGU VOWEL SIGN VOCALIC R +0C44 ; [.28A3.0020.0002] # TELUGU VOWEL SIGN VOCALIC RR +0C62 ; [.28A4.0020.0002] # TELUGU VOWEL SIGN VOCALIC L +0C63 ; [.28A5.0020.0002] # TELUGU VOWEL SIGN VOCALIC LL +0C46 ; [.28A6.0020.0002] # TELUGU VOWEL SIGN E +0C47 ; [.28A7.0020.0002] # TELUGU VOWEL SIGN EE +0C48 ; [.28A8.0020.0002] # TELUGU VOWEL SIGN AI +0C46 0C56 ; [.28A8.0020.0002] # TELUGU VOWEL SIGN AI +0C4A ; [.28A9.0020.0002] # TELUGU VOWEL SIGN O +0C4B ; [.28AA.0020.0002] # TELUGU VOWEL SIGN OO +0C4C ; [.28AB.0020.0002] # TELUGU VOWEL SIGN AU +0C4D ; [.28AC.0020.0002] # TELUGU SIGN VIRAMA +0C55 ; [.28AD.0020.0002] # TELUGU LENGTH MARK +0C56 ; [.28AE.0020.0002] # TELUGU AI LENGTH MARK +0C85 ; [.28AF.0020.0002] # KANNADA LETTER A +0C86 ; [.28B0.0020.0002] # KANNADA LETTER AA +0C87 ; [.28B1.0020.0002] # KANNADA LETTER I +0C88 ; [.28B2.0020.0002] # KANNADA LETTER II +0C89 ; [.28B3.0020.0002] # KANNADA LETTER U +0C8A ; [.28B4.0020.0002] # KANNADA LETTER UU +0C8B ; [.28B5.0020.0002] # KANNADA LETTER VOCALIC R +0CE0 ; [.28B6.0020.0002] # KANNADA LETTER VOCALIC RR +0C8C ; [.28B7.0020.0002] # KANNADA LETTER VOCALIC L +0CE1 ; [.28B8.0020.0002] # KANNADA LETTER VOCALIC LL +0C8E ; [.28B9.0020.0002] # KANNADA LETTER E +0C8F ; [.28BA.0020.0002] # KANNADA LETTER EE +0C90 ; [.28BB.0020.0002] # KANNADA LETTER AI +0C92 ; [.28BC.0020.0002] # KANNADA LETTER O +0C93 ; [.28BD.0020.0002] # KANNADA LETTER OO +0C94 ; [.28BE.0020.0002] # KANNADA LETTER AU +0C95 ; [.28BF.0020.0002] # KANNADA LETTER KA +0C96 ; [.28C0.0020.0002] # KANNADA LETTER KHA +0C97 ; [.28C1.0020.0002] # KANNADA LETTER GA +0C98 ; [.28C2.0020.0002] # KANNADA LETTER GHA +0C99 ; [.28C3.0020.0002] # KANNADA LETTER NGA +0C9A ; [.28C4.0020.0002] # KANNADA LETTER CA +0C9B ; [.28C5.0020.0002] # KANNADA LETTER CHA +0C9C ; [.28C6.0020.0002] # KANNADA LETTER JA +0C9D ; [.28C7.0020.0002] # KANNADA LETTER JHA +0C9E ; [.28C8.0020.0002] # KANNADA LETTER NYA +0C9F ; [.28C9.0020.0002] # KANNADA LETTER TTA +0CA0 ; [.28CA.0020.0002] # KANNADA LETTER TTHA +0CA1 ; [.28CB.0020.0002] # KANNADA LETTER DDA +0CA2 ; [.28CC.0020.0002] # KANNADA LETTER DDHA +0CA3 ; [.28CD.0020.0002] # KANNADA LETTER NNA +0CA4 ; [.28CE.0020.0002] # KANNADA LETTER TA +0CA5 ; [.28CF.0020.0002] # KANNADA LETTER THA +0CA6 ; [.28D0.0020.0002] # KANNADA LETTER DA +0CA7 ; [.28D1.0020.0002] # KANNADA LETTER DHA +0CA8 ; [.28D2.0020.0002] # KANNADA LETTER NA +0CAA ; [.28D3.0020.0002] # KANNADA LETTER PA +0CAB ; [.28D4.0020.0002] # KANNADA LETTER PHA +0CAC ; [.28D5.0020.0002] # KANNADA LETTER BA +0CAD ; [.28D6.0020.0002] # KANNADA LETTER BHA +0CAE ; [.28D7.0020.0002] # KANNADA LETTER MA +0CAF ; [.28D8.0020.0002] # KANNADA LETTER YA +0CB0 ; [.28D9.0020.0002] # KANNADA LETTER RA +0CB1 ; [.28DA.0020.0002] # KANNADA LETTER RRA +0CB2 ; [.28DB.0020.0002] # KANNADA LETTER LA +0CB5 ; [.28DC.0020.0002] # KANNADA LETTER VA +0CB6 ; [.28DD.0020.0002] # KANNADA LETTER SHA +0CB7 ; [.28DE.0020.0002] # KANNADA LETTER SSA +0CB8 ; [.28DF.0020.0002] # KANNADA LETTER SA +0CB9 ; [.28E0.0020.0002] # KANNADA LETTER HA +0CB3 ; [.28E1.0020.0002] # KANNADA LETTER LLA +0CDE ; [.28E2.0020.0002] # KANNADA LETTER FA +0CBD ; [.28E3.0020.0002] # KANNADA SIGN AVAGRAHA +0CF1 ; [.28E4.0020.0002] # KANNADA SIGN JIHVAMULIYA +0CF2 ; [.28E5.0020.0002] # KANNADA SIGN UPADHMANIYA +0C80 ; [.28E6.0020.0002] # KANNADA SIGN SPACING CANDRABINDU +0CBE ; [.28E7.0020.0002] # KANNADA VOWEL SIGN AA +0CBF ; [.28E8.0020.0002] # KANNADA VOWEL SIGN I +0CC0 ; [.28E9.0020.0002] # KANNADA VOWEL SIGN II +0CBF 0CD5 ; [.28E9.0020.0002] # KANNADA VOWEL SIGN II +0CC1 ; [.28EA.0020.0002] # KANNADA VOWEL SIGN U +0CC2 ; [.28EB.0020.0002] # KANNADA VOWEL SIGN UU +0CC3 ; [.28EC.0020.0002] # KANNADA VOWEL SIGN VOCALIC R +0CC4 ; [.28ED.0020.0002] # KANNADA VOWEL SIGN VOCALIC RR +0CE2 ; [.28EE.0020.0002] # KANNADA VOWEL SIGN VOCALIC L +0CE3 ; [.28EF.0020.0002] # KANNADA VOWEL SIGN VOCALIC LL +0CC6 ; [.28F0.0020.0002] # KANNADA VOWEL SIGN E +0CC7 ; [.28F1.0020.0002] # KANNADA VOWEL SIGN EE +0CC6 0CD5 ; [.28F1.0020.0002] # KANNADA VOWEL SIGN EE +0CC8 ; [.28F2.0020.0002] # KANNADA VOWEL SIGN AI +0CC6 0CD6 ; [.28F2.0020.0002] # KANNADA VOWEL SIGN AI +0CCA ; [.28F3.0020.0002] # KANNADA VOWEL SIGN O +0CC6 0CC2 ; [.28F3.0020.0002] # KANNADA VOWEL SIGN O +0CCB ; [.28F4.0020.0002] # KANNADA VOWEL SIGN OO +0CC6 0CC2 0CD5 ; [.28F4.0020.0002] # KANNADA VOWEL SIGN OO +0CCA 0CD5 ; [.28F4.0020.0002] # KANNADA VOWEL SIGN OO +0CCC ; [.28F5.0020.0002] # KANNADA VOWEL SIGN AU +0CCD ; [.28F6.0020.0002] # KANNADA SIGN VIRAMA +0CD5 ; [.28F7.0020.0002] # KANNADA LENGTH MARK +0CD6 ; [.28F8.0020.0002] # KANNADA AI LENGTH MARK +0D05 ; [.28F9.0020.0002] # MALAYALAM LETTER A +0D06 ; [.28FA.0020.0002] # MALAYALAM LETTER AA +0D07 ; [.28FB.0020.0002] # MALAYALAM LETTER I +0D08 ; [.28FC.0020.0002] # MALAYALAM LETTER II +0D5F ; [.28FD.0020.0002] # MALAYALAM LETTER ARCHAIC II +0D09 ; [.28FE.0020.0002] # MALAYALAM LETTER U +0D0A ; [.28FF.0020.0002] # MALAYALAM LETTER UU +0D0B ; [.2900.0020.0002] # MALAYALAM LETTER VOCALIC R +0D60 ; [.2901.0020.0002] # MALAYALAM LETTER VOCALIC RR +0D0C ; [.2902.0020.0002] # MALAYALAM LETTER VOCALIC L +0D61 ; [.2903.0020.0002] # MALAYALAM LETTER VOCALIC LL +0D0E ; [.2904.0020.0002] # MALAYALAM LETTER E +0D0F ; [.2905.0020.0002] # MALAYALAM LETTER EE +0D10 ; [.2906.0020.0002] # MALAYALAM LETTER AI +0D12 ; [.2907.0020.0002] # MALAYALAM LETTER O +0D13 ; [.2908.0020.0002] # MALAYALAM LETTER OO +0D14 ; [.2909.0020.0002] # MALAYALAM LETTER AU +0D15 ; [.290A.0020.0002] # MALAYALAM LETTER KA +0D7F ; [.290A.0020.0004][.2941.0020.0004] # MALAYALAM LETTER CHILLU K +0D16 ; [.290B.0020.0002] # MALAYALAM LETTER KHA +0D17 ; [.290C.0020.0002] # MALAYALAM LETTER GA +0D18 ; [.290D.0020.0002] # MALAYALAM LETTER GHA +0D19 ; [.290E.0020.0002] # MALAYALAM LETTER NGA +0D1A ; [.290F.0020.0002] # MALAYALAM LETTER CA +0D1B ; [.2910.0020.0002] # MALAYALAM LETTER CHA +0D1C ; [.2911.0020.0002] # MALAYALAM LETTER JA +0D1D ; [.2912.0020.0002] # MALAYALAM LETTER JHA +0D1E ; [.2913.0020.0002] # MALAYALAM LETTER NYA +0D1F ; [.2914.0020.0002] # MALAYALAM LETTER TTA +0D20 ; [.2915.0020.0002] # MALAYALAM LETTER TTHA +0D21 ; [.2916.0020.0002] # MALAYALAM LETTER DDA +0D22 ; [.2917.0020.0002] # MALAYALAM LETTER DDHA +0D23 ; [.2918.0020.0002] # MALAYALAM LETTER NNA +0D7A ; [.2918.0020.0004][.2941.0020.0004] # MALAYALAM LETTER CHILLU NN +0D24 ; [.2919.0020.0002] # MALAYALAM LETTER TA +0D25 ; [.291A.0020.0002] # MALAYALAM LETTER THA +0D26 ; [.291B.0020.0002] # MALAYALAM LETTER DA +0D27 ; [.291C.0020.0002] # MALAYALAM LETTER DHA +0D28 ; [.291D.0020.0002] # MALAYALAM LETTER NA +0D7B ; [.291D.0020.0004][.2941.0020.0004] # MALAYALAM LETTER CHILLU N +0D29 ; [.291E.0020.0002] # MALAYALAM LETTER NNNA +0D2A ; [.291F.0020.0002] # MALAYALAM LETTER PA +0D2B ; [.2920.0020.0002] # MALAYALAM LETTER PHA +0D2C ; [.2921.0020.0002] # MALAYALAM LETTER BA +0D2D ; [.2922.0020.0002] # MALAYALAM LETTER BHA +0D2E ; [.2923.0020.0002] # MALAYALAM LETTER MA +0D54 ; [.2923.0020.0004][.2941.0020.0004] # MALAYALAM LETTER CHILLU M +0D2F ; [.2924.0020.0002] # MALAYALAM LETTER YA +0D55 ; [.2924.0020.0004][.2941.0020.0004] # MALAYALAM LETTER CHILLU Y +0D30 ; [.2925.0020.0002] # MALAYALAM LETTER RA +0D4E ; [.2925.0020.0004][.2941.0020.0004] # MALAYALAM LETTER DOT REPH +0D7C ; [.2925.0020.0004][.2941.0020.0004] # MALAYALAM LETTER CHILLU RR +0D32 ; [.2926.0020.0002] # MALAYALAM LETTER LA +0D7D ; [.2926.0020.0004][.2941.0020.0004] # MALAYALAM LETTER CHILLU L +0D35 ; [.2927.0020.0002] # MALAYALAM LETTER VA +0D36 ; [.2928.0020.0002] # MALAYALAM LETTER SHA +0D37 ; [.2929.0020.0002] # MALAYALAM LETTER SSA +0D38 ; [.292A.0020.0002] # MALAYALAM LETTER SA +0D39 ; [.292B.0020.0002] # MALAYALAM LETTER HA +0D33 ; [.292C.0020.0002] # MALAYALAM LETTER LLA +0D7E ; [.292C.0020.0004][.2941.0020.0004] # MALAYALAM LETTER CHILLU LL +0D34 ; [.292D.0020.0002] # MALAYALAM LETTER LLLA +0D56 ; [.292D.0020.0004][.2941.0020.0004] # MALAYALAM LETTER CHILLU LLL +0D31 ; [.292E.0020.0002] # MALAYALAM LETTER RRA +0D3A ; [.292F.0020.0002] # MALAYALAM LETTER TTTA +0D3D ; [.2930.0020.0002] # MALAYALAM SIGN AVAGRAHA +0D3E ; [.2931.0020.0002] # MALAYALAM VOWEL SIGN AA +0D3F ; [.2932.0020.0002] # MALAYALAM VOWEL SIGN I +0D40 ; [.2933.0020.0002] # MALAYALAM VOWEL SIGN II +0D41 ; [.2934.0020.0002] # MALAYALAM VOWEL SIGN U +0D42 ; [.2935.0020.0002] # MALAYALAM VOWEL SIGN UU +0D43 ; [.2936.0020.0002] # MALAYALAM VOWEL SIGN VOCALIC R +0D44 ; [.2937.0020.0002] # MALAYALAM VOWEL SIGN VOCALIC RR +0D62 ; [.2938.0020.0002] # MALAYALAM VOWEL SIGN VOCALIC L +0D63 ; [.2939.0020.0002] # MALAYALAM VOWEL SIGN VOCALIC LL +0D46 ; [.293A.0020.0002] # MALAYALAM VOWEL SIGN E +0D47 ; [.293B.0020.0002] # MALAYALAM VOWEL SIGN EE +0D48 ; [.293C.0020.0002] # MALAYALAM VOWEL SIGN AI +0D4A ; [.293D.0020.0002] # MALAYALAM VOWEL SIGN O +0D46 0D3E ; [.293D.0020.0002] # MALAYALAM VOWEL SIGN O +0D4B ; [.293E.0020.0002] # MALAYALAM VOWEL SIGN OO +0D47 0D3E ; [.293E.0020.0002] # MALAYALAM VOWEL SIGN OO +0D4C ; [.293F.0020.0002] # MALAYALAM VOWEL SIGN AU +0D46 0D57 ; [.293F.0020.0002] # MALAYALAM VOWEL SIGN AU +0D57 ; [.2940.0020.0002] # MALAYALAM AU LENGTH MARK +0D4D ; [.2941.0020.0002] # MALAYALAM SIGN VIRAMA +0D3B ; [.2941.0020.0004] # MALAYALAM SIGN VERTICAL BAR VIRAMA +0D3C ; [.2941.0020.0004] # MALAYALAM SIGN CIRCULAR VIRAMA +0D85 ; [.2942.0020.0002] # SINHALA LETTER AYANNA +0D86 ; [.2943.0020.0002] # SINHALA LETTER AAYANNA +0D87 ; [.2944.0020.0002] # SINHALA LETTER AEYANNA +0D88 ; [.2945.0020.0002] # SINHALA LETTER AEEYANNA +0D89 ; [.2946.0020.0002] # SINHALA LETTER IYANNA +0D8A ; [.2947.0020.0002] # SINHALA LETTER IIYANNA +0D8B ; [.2948.0020.0002] # SINHALA LETTER UYANNA +0D8C ; [.2949.0020.0002] # SINHALA LETTER UUYANNA +0D8D ; [.294A.0020.0002] # SINHALA LETTER IRUYANNA +0D8E ; [.294B.0020.0002] # SINHALA LETTER IRUUYANNA +0D8F ; [.294C.0020.0002] # SINHALA LETTER ILUYANNA +0D90 ; [.294D.0020.0002] # SINHALA LETTER ILUUYANNA +0D91 ; [.294E.0020.0002] # SINHALA LETTER EYANNA +0D92 ; [.294F.0020.0002] # SINHALA LETTER EEYANNA +0D93 ; [.2950.0020.0002] # SINHALA LETTER AIYANNA +0D94 ; [.2951.0020.0002] # SINHALA LETTER OYANNA +0D95 ; [.2952.0020.0002] # SINHALA LETTER OOYANNA +0D96 ; [.2953.0020.0002] # SINHALA LETTER AUYANNA +0D9A ; [.2954.0020.0002] # SINHALA LETTER ALPAPRAANA KAYANNA +0D9B ; [.2955.0020.0002] # SINHALA LETTER MAHAAPRAANA KAYANNA +0D9C ; [.2956.0020.0002] # SINHALA LETTER ALPAPRAANA GAYANNA +0D9D ; [.2957.0020.0002] # SINHALA LETTER MAHAAPRAANA GAYANNA +0D9E ; [.2958.0020.0002] # SINHALA LETTER KANTAJA NAASIKYAYA +0D9F ; [.2959.0020.0002] # SINHALA LETTER SANYAKA GAYANNA +0DA0 ; [.295A.0020.0002] # SINHALA LETTER ALPAPRAANA CAYANNA +0DA1 ; [.295B.0020.0002] # SINHALA LETTER MAHAAPRAANA CAYANNA +0DA2 ; [.295C.0020.0002] # SINHALA LETTER ALPAPRAANA JAYANNA +0DA3 ; [.295D.0020.0002] # SINHALA LETTER MAHAAPRAANA JAYANNA +0DA4 ; [.295E.0020.0002] # SINHALA LETTER TAALUJA NAASIKYAYA +0DA5 ; [.295F.0020.0002] # SINHALA LETTER TAALUJA SANYOOGA NAAKSIKYAYA +0DA6 ; [.2960.0020.0002] # SINHALA LETTER SANYAKA JAYANNA +0DA7 ; [.2961.0020.0002] # SINHALA LETTER ALPAPRAANA TTAYANNA +0DA8 ; [.2962.0020.0002] # SINHALA LETTER MAHAAPRAANA TTAYANNA +0DA9 ; [.2963.0020.0002] # SINHALA LETTER ALPAPRAANA DDAYANNA +0DAA ; [.2964.0020.0002] # SINHALA LETTER MAHAAPRAANA DDAYANNA +0DAB ; [.2965.0020.0002] # SINHALA LETTER MUURDHAJA NAYANNA +0DAC ; [.2966.0020.0002] # SINHALA LETTER SANYAKA DDAYANNA +0DAD ; [.2967.0020.0002] # SINHALA LETTER ALPAPRAANA TAYANNA +0DAE ; [.2968.0020.0002] # SINHALA LETTER MAHAAPRAANA TAYANNA +0DAF ; [.2969.0020.0002] # SINHALA LETTER ALPAPRAANA DAYANNA +0DB0 ; [.296A.0020.0002] # SINHALA LETTER MAHAAPRAANA DAYANNA +0DB1 ; [.296B.0020.0002] # SINHALA LETTER DANTAJA NAYANNA +0DB3 ; [.296C.0020.0002] # SINHALA LETTER SANYAKA DAYANNA +0DB4 ; [.296D.0020.0002] # SINHALA LETTER ALPAPRAANA PAYANNA +0DB5 ; [.296E.0020.0002] # SINHALA LETTER MAHAAPRAANA PAYANNA +0DB6 ; [.296F.0020.0002] # SINHALA LETTER ALPAPRAANA BAYANNA +0DB7 ; [.2970.0020.0002] # SINHALA LETTER MAHAAPRAANA BAYANNA +0DB8 ; [.2971.0020.0002] # SINHALA LETTER MAYANNA +0DB9 ; [.2972.0020.0002] # SINHALA LETTER AMBA BAYANNA +0DBA ; [.2973.0020.0002] # SINHALA LETTER YAYANNA +0DBB ; [.2974.0020.0002] # SINHALA LETTER RAYANNA +0DBD ; [.2975.0020.0002] # SINHALA LETTER DANTAJA LAYANNA +0DC0 ; [.2976.0020.0002] # SINHALA LETTER VAYANNA +0DC1 ; [.2977.0020.0002] # SINHALA LETTER TAALUJA SAYANNA +0DC2 ; [.2978.0020.0002] # SINHALA LETTER MUURDHAJA SAYANNA +0DC3 ; [.2979.0020.0002] # SINHALA LETTER DANTAJA SAYANNA +0DC4 ; [.297A.0020.0002] # SINHALA LETTER HAYANNA +0DC5 ; [.297B.0020.0002] # SINHALA LETTER MUURDHAJA LAYANNA +0DC6 ; [.297C.0020.0002] # SINHALA LETTER FAYANNA +0DCF ; [.297D.0020.0002] # SINHALA VOWEL SIGN AELA-PILLA +0DD0 ; [.297E.0020.0002] # SINHALA VOWEL SIGN KETTI AEDA-PILLA +0DD1 ; [.297F.0020.0002] # SINHALA VOWEL SIGN DIGA AEDA-PILLA +0DD2 ; [.2980.0020.0002] # SINHALA VOWEL SIGN KETTI IS-PILLA +0DD3 ; [.2981.0020.0002] # SINHALA VOWEL SIGN DIGA IS-PILLA +0DD4 ; [.2982.0020.0002] # SINHALA VOWEL SIGN KETTI PAA-PILLA +0DD6 ; [.2983.0020.0002] # SINHALA VOWEL SIGN DIGA PAA-PILLA +0DD8 ; [.2984.0020.0002] # SINHALA VOWEL SIGN GAETTA-PILLA +0DF2 ; [.2985.0020.0002] # SINHALA VOWEL SIGN DIGA GAETTA-PILLA +0DDF ; [.2986.0020.0002] # SINHALA VOWEL SIGN GAYANUKITTA +0DF3 ; [.2987.0020.0002] # SINHALA VOWEL SIGN DIGA GAYANUKITTA +0DD9 ; [.2988.0020.0002] # SINHALA VOWEL SIGN KOMBUVA +0DDA ; [.2989.0020.0002] # SINHALA VOWEL SIGN DIGA KOMBUVA +0DD9 0DCA ; [.2989.0020.0002] # SINHALA VOWEL SIGN DIGA KOMBUVA +0DDB ; [.298A.0020.0002] # SINHALA VOWEL SIGN KOMBU DEKA +0DDC ; [.298B.0020.0002] # SINHALA VOWEL SIGN KOMBUVA HAA AELA-PILLA +0DD9 0DCF ; [.298B.0020.0002] # SINHALA VOWEL SIGN KOMBUVA HAA AELA-PILLA +0DDD ; [.298C.0020.0002] # SINHALA VOWEL SIGN KOMBUVA HAA DIGA AELA-PILLA +0DD9 0DCF 0DCA ; [.298C.0020.0002] # SINHALA VOWEL SIGN KOMBUVA HAA DIGA AELA-PILLA +0DDC 0DCA ; [.298C.0020.0002] # SINHALA VOWEL SIGN KOMBUVA HAA DIGA AELA-PILLA +0DDE ; [.298D.0020.0002] # SINHALA VOWEL SIGN KOMBUVA HAA GAYANUKITTA +0DD9 0DDF ; [.298D.0020.0002] # SINHALA VOWEL SIGN KOMBUVA HAA GAYANUKITTA +0DCA ; [.298E.0020.0002] # SINHALA SIGN AL-LAKUNA +AAF2 ; [.298F.0020.0002] # MEETEI MAYEK ANJI +ABC0 ; [.2990.0020.0002] # MEETEI MAYEK LETTER KOK +ABC1 ; [.2991.0020.0002] # MEETEI MAYEK LETTER SAM +ABC2 ; [.2992.0020.0002] # MEETEI MAYEK LETTER LAI +ABC3 ; [.2993.0020.0002] # MEETEI MAYEK LETTER MIT +ABC4 ; [.2994.0020.0002] # MEETEI MAYEK LETTER PA +ABC5 ; [.2995.0020.0002] # MEETEI MAYEK LETTER NA +ABC6 ; [.2996.0020.0002] # MEETEI MAYEK LETTER CHIL +ABC7 ; [.2997.0020.0002] # MEETEI MAYEK LETTER TIL +ABC8 ; [.2998.0020.0002] # MEETEI MAYEK LETTER KHOU +ABC9 ; [.2999.0020.0002] # MEETEI MAYEK LETTER NGOU +ABCA ; [.299A.0020.0002] # MEETEI MAYEK LETTER THOU +ABCB ; [.299B.0020.0002] # MEETEI MAYEK LETTER WAI +ABCC ; [.299C.0020.0002] # MEETEI MAYEK LETTER YANG +ABCD ; [.299D.0020.0002] # MEETEI MAYEK LETTER HUK +ABCE ; [.299E.0020.0002] # MEETEI MAYEK LETTER UN +ABCF ; [.299F.0020.0002] # MEETEI MAYEK LETTER I +ABD0 ; [.29A0.0020.0002] # MEETEI MAYEK LETTER PHAM +ABD1 ; [.29A1.0020.0002] # MEETEI MAYEK LETTER ATIYA +ABD2 ; [.29A2.0020.0002] # MEETEI MAYEK LETTER GOK +ABD3 ; [.29A3.0020.0002] # MEETEI MAYEK LETTER JHAM +ABD4 ; [.29A4.0020.0002] # MEETEI MAYEK LETTER RAI +ABD5 ; [.29A5.0020.0002] # MEETEI MAYEK LETTER BA +ABD6 ; [.29A6.0020.0002] # MEETEI MAYEK LETTER JIL +ABD7 ; [.29A7.0020.0002] # MEETEI MAYEK LETTER DIL +ABD8 ; [.29A8.0020.0002] # MEETEI MAYEK LETTER GHOU +ABD9 ; [.29A9.0020.0002] # MEETEI MAYEK LETTER DHOU +ABDA ; [.29AA.0020.0002] # MEETEI MAYEK LETTER BHAM +AAE0 ; [.29AB.0020.0002] # MEETEI MAYEK LETTER E +AAE1 ; [.29AC.0020.0002] # MEETEI MAYEK LETTER O +AAE2 ; [.29AD.0020.0002] # MEETEI MAYEK LETTER CHA +AAE3 ; [.29AE.0020.0002] # MEETEI MAYEK LETTER NYA +AAE4 ; [.29AF.0020.0002] # MEETEI MAYEK LETTER TTA +AAE5 ; [.29B0.0020.0002] # MEETEI MAYEK LETTER TTHA +AAE6 ; [.29B1.0020.0002] # MEETEI MAYEK LETTER DDA +AAE7 ; [.29B2.0020.0002] # MEETEI MAYEK LETTER DDHA +AAE8 ; [.29B3.0020.0002] # MEETEI MAYEK LETTER NNA +AAE9 ; [.29B4.0020.0002] # MEETEI MAYEK LETTER SHA +AAEA ; [.29B5.0020.0002] # MEETEI MAYEK LETTER SSA +ABE3 ; [.29B6.0020.0002] # MEETEI MAYEK VOWEL SIGN ONAP +ABE4 ; [.29B7.0020.0002] # MEETEI MAYEK VOWEL SIGN INAP +ABE5 ; [.29B8.0020.0002] # MEETEI MAYEK VOWEL SIGN ANAP +ABE6 ; [.29B9.0020.0002] # MEETEI MAYEK VOWEL SIGN YENAP +ABE7 ; [.29BA.0020.0002] # MEETEI MAYEK VOWEL SIGN SOUNAP +ABE8 ; [.29BB.0020.0002] # MEETEI MAYEK VOWEL SIGN UNAP +ABE9 ; [.29BC.0020.0002] # MEETEI MAYEK VOWEL SIGN CHEINAP +ABEA ; [.29BD.0020.0002] # MEETEI MAYEK VOWEL SIGN NUNG +AAEB ; [.29BE.0020.0002] # MEETEI MAYEK VOWEL SIGN II +AAEC ; [.29BF.0020.0002] # MEETEI MAYEK VOWEL SIGN UU +AAED ; [.29C0.0020.0002] # MEETEI MAYEK VOWEL SIGN AAI +AAEE ; [.29C1.0020.0002] # MEETEI MAYEK VOWEL SIGN AU +AAEF ; [.29C2.0020.0002] # MEETEI MAYEK VOWEL SIGN AAU +AAF5 ; [.29C3.0020.0002] # MEETEI MAYEK VOWEL SIGN VISARGA +ABDB ; [.29C4.0020.0002] # MEETEI MAYEK LETTER KOK LONSUM +ABDC ; [.29C5.0020.0002] # MEETEI MAYEK LETTER LAI LONSUM +ABDD ; [.29C6.0020.0002] # MEETEI MAYEK LETTER MIT LONSUM +ABDE ; [.29C7.0020.0002] # MEETEI MAYEK LETTER PA LONSUM +ABDF ; [.29C8.0020.0002] # MEETEI MAYEK LETTER NA LONSUM +ABE0 ; [.29C9.0020.0002] # MEETEI MAYEK LETTER TIL LONSUM +ABE1 ; [.29CA.0020.0002] # MEETEI MAYEK LETTER NGOU LONSUM +ABE2 ; [.29CB.0020.0002] # MEETEI MAYEK LETTER I LONSUM +ABED ; [.29CC.0020.0002] # MEETEI MAYEK APUN IYEK +AAF6 ; [.29CD.0020.0002] # MEETEI MAYEK VIRAMA +A800 ; [.29CE.0020.0002] # SYLOTI NAGRI LETTER A +A801 ; [.29CF.0020.0002] # SYLOTI NAGRI LETTER I +A802 ; [.29D0.0020.0002] # SYLOTI NAGRI SIGN DVISVARA +A803 ; [.29D1.0020.0002] # SYLOTI NAGRI LETTER U +A804 ; [.29D2.0020.0002] # SYLOTI NAGRI LETTER E +A805 ; [.29D3.0020.0002] # SYLOTI NAGRI LETTER O +A806 ; [.29D4.0020.0002] # SYLOTI NAGRI SIGN HASANTA +A807 ; [.29D5.0020.0002] # SYLOTI NAGRI LETTER KO +A808 ; [.29D6.0020.0002] # SYLOTI NAGRI LETTER KHO +A809 ; [.29D7.0020.0002] # SYLOTI NAGRI LETTER GO +A80A ; [.29D8.0020.0002] # SYLOTI NAGRI LETTER GHO +A80C ; [.29D9.0020.0002] # SYLOTI NAGRI LETTER CO +A80D ; [.29DA.0020.0002] # SYLOTI NAGRI LETTER CHO +A80E ; [.29DB.0020.0002] # SYLOTI NAGRI LETTER JO +A80F ; [.29DC.0020.0002] # SYLOTI NAGRI LETTER JHO +A810 ; [.29DD.0020.0002] # SYLOTI NAGRI LETTER TTO +A811 ; [.29DE.0020.0002] # SYLOTI NAGRI LETTER TTHO +A812 ; [.29DF.0020.0002] # SYLOTI NAGRI LETTER DDO +A813 ; [.29E0.0020.0002] # SYLOTI NAGRI LETTER DDHO +A814 ; [.29E1.0020.0002] # SYLOTI NAGRI LETTER TO +A815 ; [.29E2.0020.0002] # SYLOTI NAGRI LETTER THO +A816 ; [.29E3.0020.0002] # SYLOTI NAGRI LETTER DO +A817 ; [.29E4.0020.0002] # SYLOTI NAGRI LETTER DHO +A818 ; [.29E5.0020.0002] # SYLOTI NAGRI LETTER NO +A819 ; [.29E6.0020.0002] # SYLOTI NAGRI LETTER PO +A81A ; [.29E7.0020.0002] # SYLOTI NAGRI LETTER PHO +A81B ; [.29E8.0020.0002] # SYLOTI NAGRI LETTER BO +A81C ; [.29E9.0020.0002] # SYLOTI NAGRI LETTER BHO +A81D ; [.29EA.0020.0002] # SYLOTI NAGRI LETTER MO +A81E ; [.29EB.0020.0002] # SYLOTI NAGRI LETTER RO +A81F ; [.29EC.0020.0002] # SYLOTI NAGRI LETTER LO +A820 ; [.29ED.0020.0002] # SYLOTI NAGRI LETTER RRO +A821 ; [.29EE.0020.0002] # SYLOTI NAGRI LETTER SO +A822 ; [.29EF.0020.0002] # SYLOTI NAGRI LETTER HO +A823 ; [.29F0.0020.0002] # SYLOTI NAGRI VOWEL SIGN A +A824 ; [.29F1.0020.0002] # SYLOTI NAGRI VOWEL SIGN I +A825 ; [.29F2.0020.0002] # SYLOTI NAGRI VOWEL SIGN U +A826 ; [.29F3.0020.0002] # SYLOTI NAGRI VOWEL SIGN E +A827 ; [.29F4.0020.0002] # SYLOTI NAGRI VOWEL SIGN OO +A882 ; [.29F5.0020.0002] # SAURASHTRA LETTER A +A883 ; [.29F6.0020.0002] # SAURASHTRA LETTER AA +A884 ; [.29F7.0020.0002] # SAURASHTRA LETTER I +A885 ; [.29F8.0020.0002] # SAURASHTRA LETTER II +A886 ; [.29F9.0020.0002] # SAURASHTRA LETTER U +A887 ; [.29FA.0020.0002] # SAURASHTRA LETTER UU +A888 ; [.29FB.0020.0002] # SAURASHTRA LETTER VOCALIC R +A889 ; [.29FC.0020.0002] # SAURASHTRA LETTER VOCALIC RR +A88A ; [.29FD.0020.0002] # SAURASHTRA LETTER VOCALIC L +A88B ; [.29FE.0020.0002] # SAURASHTRA LETTER VOCALIC LL +A88C ; [.29FF.0020.0002] # SAURASHTRA LETTER E +A88D ; [.2A00.0020.0002] # SAURASHTRA LETTER EE +A88E ; [.2A01.0020.0002] # SAURASHTRA LETTER AI +A88F ; [.2A02.0020.0002] # SAURASHTRA LETTER O +A890 ; [.2A03.0020.0002] # SAURASHTRA LETTER OO +A891 ; [.2A04.0020.0002] # SAURASHTRA LETTER AU +A892 ; [.2A05.0020.0002] # SAURASHTRA LETTER KA +A893 ; [.2A06.0020.0002] # SAURASHTRA LETTER KHA +A894 ; [.2A07.0020.0002] # SAURASHTRA LETTER GA +A895 ; [.2A08.0020.0002] # SAURASHTRA LETTER GHA +A896 ; [.2A09.0020.0002] # SAURASHTRA LETTER NGA +A897 ; [.2A0A.0020.0002] # SAURASHTRA LETTER CA +A898 ; [.2A0B.0020.0002] # SAURASHTRA LETTER CHA +A899 ; [.2A0C.0020.0002] # SAURASHTRA LETTER JA +A89A ; [.2A0D.0020.0002] # SAURASHTRA LETTER JHA +A89B ; [.2A0E.0020.0002] # SAURASHTRA LETTER NYA +A89C ; [.2A0F.0020.0002] # SAURASHTRA LETTER TTA +A89D ; [.2A10.0020.0002] # SAURASHTRA LETTER TTHA +A89E ; [.2A11.0020.0002] # SAURASHTRA LETTER DDA +A89F ; [.2A12.0020.0002] # SAURASHTRA LETTER DDHA +A8A0 ; [.2A13.0020.0002] # SAURASHTRA LETTER NNA +A8A1 ; [.2A14.0020.0002] # SAURASHTRA LETTER TA +A8A2 ; [.2A15.0020.0002] # SAURASHTRA LETTER THA +A8A3 ; [.2A16.0020.0002] # SAURASHTRA LETTER DA +A8A4 ; [.2A17.0020.0002] # SAURASHTRA LETTER DHA +A8A5 ; [.2A18.0020.0002] # SAURASHTRA LETTER NA +A8A6 ; [.2A19.0020.0002] # SAURASHTRA LETTER PA +A8A7 ; [.2A1A.0020.0002] # SAURASHTRA LETTER PHA +A8A8 ; [.2A1B.0020.0002] # SAURASHTRA LETTER BA +A8A9 ; [.2A1C.0020.0002] # SAURASHTRA LETTER BHA +A8AA ; [.2A1D.0020.0002] # SAURASHTRA LETTER MA +A8AB ; [.2A1E.0020.0002] # SAURASHTRA LETTER YA +A8AC ; [.2A1F.0020.0002] # SAURASHTRA LETTER RA +A8AD ; [.2A20.0020.0002] # SAURASHTRA LETTER LA +A8AE ; [.2A21.0020.0002] # SAURASHTRA LETTER VA +A8AF ; [.2A22.0020.0002] # SAURASHTRA LETTER SHA +A8B0 ; [.2A23.0020.0002] # SAURASHTRA LETTER SSA +A8B1 ; [.2A24.0020.0002] # SAURASHTRA LETTER SA +A8B2 ; [.2A25.0020.0002] # SAURASHTRA LETTER HA +A8B3 ; [.2A26.0020.0002] # SAURASHTRA LETTER LLA +A8B4 ; [.2A27.0020.0002] # SAURASHTRA CONSONANT SIGN HAARU +A8B5 ; [.2A28.0020.0002] # SAURASHTRA VOWEL SIGN AA +A8B6 ; [.2A29.0020.0002] # SAURASHTRA VOWEL SIGN I +A8B7 ; [.2A2A.0020.0002] # SAURASHTRA VOWEL SIGN II +A8B8 ; [.2A2B.0020.0002] # SAURASHTRA VOWEL SIGN U +A8B9 ; [.2A2C.0020.0002] # SAURASHTRA VOWEL SIGN UU +A8BA ; [.2A2D.0020.0002] # SAURASHTRA VOWEL SIGN VOCALIC R +A8BB ; [.2A2E.0020.0002] # SAURASHTRA VOWEL SIGN VOCALIC RR +A8BC ; [.2A2F.0020.0002] # SAURASHTRA VOWEL SIGN VOCALIC L +A8BD ; [.2A30.0020.0002] # SAURASHTRA VOWEL SIGN VOCALIC LL +A8BE ; [.2A31.0020.0002] # SAURASHTRA VOWEL SIGN E +A8BF ; [.2A32.0020.0002] # SAURASHTRA VOWEL SIGN EE +A8C0 ; [.2A33.0020.0002] # SAURASHTRA VOWEL SIGN AI +A8C1 ; [.2A34.0020.0002] # SAURASHTRA VOWEL SIGN O +A8C2 ; [.2A35.0020.0002] # SAURASHTRA VOWEL SIGN OO +A8C3 ; [.2A36.0020.0002] # SAURASHTRA VOWEL SIGN AU +A8C4 ; [.2A37.0020.0002] # SAURASHTRA SIGN VIRAMA +11083 ; [.2A38.0020.0002] # KAITHI LETTER A +11084 ; [.2A39.0020.0002] # KAITHI LETTER AA +11085 ; [.2A3A.0020.0002] # KAITHI LETTER I +11086 ; [.2A3B.0020.0002] # KAITHI LETTER II +11087 ; [.2A3C.0020.0002] # KAITHI LETTER U +11088 ; [.2A3D.0020.0002] # KAITHI LETTER UU +11089 ; [.2A3E.0020.0002] # KAITHI LETTER E +1108A ; [.2A3F.0020.0002] # KAITHI LETTER AI +1108B ; [.2A40.0020.0002] # KAITHI LETTER O +1108C ; [.2A41.0020.0002] # KAITHI LETTER AU +1108D ; [.2A42.0020.0002] # KAITHI LETTER KA +1108E ; [.2A43.0020.0002] # KAITHI LETTER KHA +1108F ; [.2A44.0020.0002] # KAITHI LETTER GA +11090 ; [.2A45.0020.0002] # KAITHI LETTER GHA +11091 ; [.2A46.0020.0002] # KAITHI LETTER NGA +11092 ; [.2A47.0020.0002] # KAITHI LETTER CA +11093 ; [.2A48.0020.0002] # KAITHI LETTER CHA +11094 ; [.2A49.0020.0002] # KAITHI LETTER JA +11095 ; [.2A4A.0020.0002] # KAITHI LETTER JHA +11096 ; [.2A4B.0020.0002] # KAITHI LETTER NYA +11097 ; [.2A4C.0020.0002] # KAITHI LETTER TTA +11098 ; [.2A4D.0020.0002] # KAITHI LETTER TTHA +11099 ; [.2A4E.0020.0002] # KAITHI LETTER DDA +1109A ; [.2A4E.0020.0002][.0000.00C2.0002] # KAITHI LETTER DDDHA +1109B ; [.2A4F.0020.0002] # KAITHI LETTER DDHA +1109C ; [.2A4F.0020.0002][.0000.00C2.0002] # KAITHI LETTER RHA +1109D ; [.2A50.0020.0002] # KAITHI LETTER NNA +1109E ; [.2A51.0020.0002] # KAITHI LETTER TA +1109F ; [.2A52.0020.0002] # KAITHI LETTER THA +110A0 ; [.2A53.0020.0002] # KAITHI LETTER DA +110A1 ; [.2A54.0020.0002] # KAITHI LETTER DHA +110A2 ; [.2A55.0020.0002] # KAITHI LETTER NA +110A3 ; [.2A56.0020.0002] # KAITHI LETTER PA +110A4 ; [.2A57.0020.0002] # KAITHI LETTER PHA +110A5 ; [.2A58.0020.0002] # KAITHI LETTER BA +110AB ; [.2A58.0020.0002][.0000.00C2.0002] # KAITHI LETTER VA +110A6 ; [.2A59.0020.0002] # KAITHI LETTER BHA +110A7 ; [.2A5A.0020.0002] # KAITHI LETTER MA +110A8 ; [.2A5B.0020.0002] # KAITHI LETTER YA +110A9 ; [.2A5C.0020.0002] # KAITHI LETTER RA +110AA ; [.2A5D.0020.0002] # KAITHI LETTER LA +110AC ; [.2A5E.0020.0002] # KAITHI LETTER SHA +110AD ; [.2A5F.0020.0002] # KAITHI LETTER SSA +110AE ; [.2A60.0020.0002] # KAITHI LETTER SA +110AF ; [.2A61.0020.0002] # KAITHI LETTER HA +110B0 ; [.2A62.0020.0002] # KAITHI VOWEL SIGN AA +110B1 ; [.2A63.0020.0002] # KAITHI VOWEL SIGN I +110B2 ; [.2A64.0020.0002] # KAITHI VOWEL SIGN II +110B3 ; [.2A65.0020.0002] # KAITHI VOWEL SIGN U +110B4 ; [.2A66.0020.0002] # KAITHI VOWEL SIGN UU +110B5 ; [.2A67.0020.0002] # KAITHI VOWEL SIGN E +110B6 ; [.2A68.0020.0002] # KAITHI VOWEL SIGN AI +110B7 ; [.2A69.0020.0002] # KAITHI VOWEL SIGN O +110B8 ; [.2A6A.0020.0002] # KAITHI VOWEL SIGN AU +110B9 ; [.2A6B.0020.0002] # KAITHI SIGN VIRAMA +11150 ; [.2A6C.0020.0002] # MAHAJANI LETTER A +11151 ; [.2A6D.0020.0002] # MAHAJANI LETTER I +11152 ; [.2A6E.0020.0002] # MAHAJANI LETTER U +11153 ; [.2A6F.0020.0002] # MAHAJANI LETTER E +11154 ; [.2A70.0020.0002] # MAHAJANI LETTER O +11155 ; [.2A71.0020.0002] # MAHAJANI LETTER KA +11156 ; [.2A72.0020.0002] # MAHAJANI LETTER KHA +11157 ; [.2A73.0020.0002] # MAHAJANI LETTER GA +11158 ; [.2A74.0020.0002] # MAHAJANI LETTER GHA +11159 ; [.2A75.0020.0002] # MAHAJANI LETTER CA +1115A ; [.2A76.0020.0002] # MAHAJANI LETTER CHA +1115B ; [.2A77.0020.0002] # MAHAJANI LETTER JA +1115C ; [.2A78.0020.0002] # MAHAJANI LETTER JHA +1115D ; [.2A79.0020.0002] # MAHAJANI LETTER NYA +1115E ; [.2A7A.0020.0002] # MAHAJANI LETTER TTA +1115F ; [.2A7B.0020.0002] # MAHAJANI LETTER TTHA +11160 ; [.2A7C.0020.0002] # MAHAJANI LETTER DDA +11161 ; [.2A7D.0020.0002] # MAHAJANI LETTER DDHA +11162 ; [.2A7E.0020.0002] # MAHAJANI LETTER NNA +11163 ; [.2A7F.0020.0002] # MAHAJANI LETTER TA +11164 ; [.2A80.0020.0002] # MAHAJANI LETTER THA +11165 ; [.2A81.0020.0002] # MAHAJANI LETTER DA +11166 ; [.2A82.0020.0002] # MAHAJANI LETTER DHA +11167 ; [.2A83.0020.0002] # MAHAJANI LETTER NA +11168 ; [.2A84.0020.0002] # MAHAJANI LETTER PA +11169 ; [.2A85.0020.0002] # MAHAJANI LETTER PHA +1116A ; [.2A86.0020.0002] # MAHAJANI LETTER BA +1116B ; [.2A87.0020.0002] # MAHAJANI LETTER BHA +1116C ; [.2A88.0020.0002] # MAHAJANI LETTER MA +1116D ; [.2A89.0020.0002] # MAHAJANI LETTER RA +1116E ; [.2A8A.0020.0002] # MAHAJANI LETTER LA +1116F ; [.2A8B.0020.0002] # MAHAJANI LETTER VA +11176 ; [.2A8C.0020.0002] # MAHAJANI LIGATURE SHRI +11170 ; [.2A8D.0020.0002] # MAHAJANI LETTER SA +11171 ; [.2A8E.0020.0002] # MAHAJANI LETTER HA +11172 ; [.2A8F.0020.0002] # MAHAJANI LETTER RRA +111C4 ; [.2A90.0020.0002] # SHARADA OM +111DA ; [.2A91.0020.0002] # SHARADA EKAM +11183 ; [.2A92.0020.0002] # SHARADA LETTER A +11184 ; [.2A93.0020.0002] # SHARADA LETTER AA +11185 ; [.2A94.0020.0002] # SHARADA LETTER I +11186 ; [.2A95.0020.0002] # SHARADA LETTER II +11187 ; [.2A96.0020.0002] # SHARADA LETTER U +11188 ; [.2A97.0020.0002] # SHARADA LETTER UU +11189 ; [.2A98.0020.0002] # SHARADA LETTER VOCALIC R +1118A ; [.2A99.0020.0002] # SHARADA LETTER VOCALIC RR +1118B ; [.2A9A.0020.0002] # SHARADA LETTER VOCALIC L +1118C ; [.2A9B.0020.0002] # SHARADA LETTER VOCALIC LL +1118D ; [.2A9C.0020.0002] # SHARADA LETTER E +1118E ; [.2A9D.0020.0002] # SHARADA LETTER AI +1118F ; [.2A9E.0020.0002] # SHARADA LETTER O +11190 ; [.2A9F.0020.0002] # SHARADA LETTER AU +11191 ; [.2AA0.0020.0002] # SHARADA LETTER KA +11192 ; [.2AA1.0020.0002] # SHARADA LETTER KHA +11193 ; [.2AA2.0020.0002] # SHARADA LETTER GA +11194 ; [.2AA3.0020.0002] # SHARADA LETTER GHA +11195 ; [.2AA4.0020.0002] # SHARADA LETTER NGA +11196 ; [.2AA5.0020.0002] # SHARADA LETTER CA +11197 ; [.2AA6.0020.0002] # SHARADA LETTER CHA +11198 ; [.2AA7.0020.0002] # SHARADA LETTER JA +11199 ; [.2AA8.0020.0002] # SHARADA LETTER JHA +1119A ; [.2AA9.0020.0002] # SHARADA LETTER NYA +1119B ; [.2AAA.0020.0002] # SHARADA LETTER TTA +1119C ; [.2AAB.0020.0002] # SHARADA LETTER TTHA +1119D ; [.2AAC.0020.0002] # SHARADA LETTER DDA +1119E ; [.2AAD.0020.0002] # SHARADA LETTER DDHA +1119F ; [.2AAE.0020.0002] # SHARADA LETTER NNA +111A0 ; [.2AAF.0020.0002] # SHARADA LETTER TA +111A1 ; [.2AB0.0020.0002] # SHARADA LETTER THA +111A2 ; [.2AB1.0020.0002] # SHARADA LETTER DA +111A3 ; [.2AB2.0020.0002] # SHARADA LETTER DHA +111A4 ; [.2AB3.0020.0002] # SHARADA LETTER NA +111A5 ; [.2AB4.0020.0002] # SHARADA LETTER PA +111A6 ; [.2AB5.0020.0002] # SHARADA LETTER PHA +111A7 ; [.2AB6.0020.0002] # SHARADA LETTER BA +111A8 ; [.2AB7.0020.0002] # SHARADA LETTER BHA +111A9 ; [.2AB8.0020.0002] # SHARADA LETTER MA +111AA ; [.2AB9.0020.0002] # SHARADA LETTER YA +111AB ; [.2ABA.0020.0002] # SHARADA LETTER RA +111AC ; [.2ABB.0020.0002] # SHARADA LETTER LA +111AD ; [.2ABC.0020.0002] # SHARADA LETTER LLA +111AE ; [.2ABD.0020.0002] # SHARADA LETTER VA +111AF ; [.2ABE.0020.0002] # SHARADA LETTER SHA +111B0 ; [.2ABF.0020.0002] # SHARADA LETTER SSA +111B1 ; [.2AC0.0020.0002] # SHARADA LETTER SA +111B2 ; [.2AC1.0020.0002] # SHARADA LETTER HA +111C1 ; [.2AC2.0020.0002] # SHARADA SIGN AVAGRAHA +111C2 ; [.2AC3.0020.0002] # SHARADA SIGN JIHVAMULIYA +111C3 ; [.2AC4.0020.0002] # SHARADA SIGN UPADHMANIYA +111DC ; [.2AC5.0020.0002] # SHARADA HEADSTROKE +111B3 ; [.2AC6.0020.0002] # SHARADA VOWEL SIGN AA +111B4 ; [.2AC7.0020.0002] # SHARADA VOWEL SIGN I +111B5 ; [.2AC8.0020.0002] # SHARADA VOWEL SIGN II +111B6 ; [.2AC9.0020.0002] # SHARADA VOWEL SIGN U +111B7 ; [.2ACA.0020.0002] # SHARADA VOWEL SIGN UU +111B8 ; [.2ACB.0020.0002] # SHARADA VOWEL SIGN VOCALIC R +111B9 ; [.2ACC.0020.0002] # SHARADA VOWEL SIGN VOCALIC RR +111BA ; [.2ACD.0020.0002] # SHARADA VOWEL SIGN VOCALIC L +111BB ; [.2ACE.0020.0002] # SHARADA VOWEL SIGN VOCALIC LL +111BC ; [.2ACF.0020.0002] # SHARADA VOWEL SIGN E +111BD ; [.2AD0.0020.0002] # SHARADA VOWEL SIGN AI +111BE ; [.2AD1.0020.0002] # SHARADA VOWEL SIGN O +111BF ; [.2AD2.0020.0002] # SHARADA VOWEL SIGN AU +111C0 ; [.2AD3.0020.0002] # SHARADA SIGN VIRAMA +11200 ; [.2AD4.0020.0002] # KHOJKI LETTER A +11201 ; [.2AD5.0020.0002] # KHOJKI LETTER AA +11202 ; [.2AD6.0020.0002] # KHOJKI LETTER I +11203 ; [.2AD7.0020.0002] # KHOJKI LETTER U +11204 ; [.2AD8.0020.0002] # KHOJKI LETTER E +11205 ; [.2AD9.0020.0002] # KHOJKI LETTER AI +11206 ; [.2ADA.0020.0002] # KHOJKI LETTER O +11207 ; [.2ADB.0020.0002] # KHOJKI LETTER AU +11208 ; [.2ADC.0020.0002] # KHOJKI LETTER KA +11209 ; [.2ADD.0020.0002] # KHOJKI LETTER KHA +1120A ; [.2ADE.0020.0002] # KHOJKI LETTER GA +1120B ; [.2ADF.0020.0002] # KHOJKI LETTER GGA +1120C ; [.2AE0.0020.0002] # KHOJKI LETTER GHA +1120D ; [.2AE1.0020.0002] # KHOJKI LETTER NGA +1120E ; [.2AE2.0020.0002] # KHOJKI LETTER CA +1120F ; [.2AE3.0020.0002] # KHOJKI LETTER CHA +11210 ; [.2AE4.0020.0002] # KHOJKI LETTER JA +11211 ; [.2AE5.0020.0002] # KHOJKI LETTER JJA +11213 ; [.2AE6.0020.0002] # KHOJKI LETTER NYA +11214 ; [.2AE7.0020.0002] # KHOJKI LETTER TTA +11215 ; [.2AE8.0020.0002] # KHOJKI LETTER TTHA +11216 ; [.2AE9.0020.0002] # KHOJKI LETTER DDA +11217 ; [.2AEA.0020.0002] # KHOJKI LETTER DDHA +11218 ; [.2AEB.0020.0002] # KHOJKI LETTER NNA +11219 ; [.2AEC.0020.0002] # KHOJKI LETTER TA +1121A ; [.2AED.0020.0002] # KHOJKI LETTER THA +1121B ; [.2AEE.0020.0002] # KHOJKI LETTER DA +1121C ; [.2AEF.0020.0002] # KHOJKI LETTER DDDA +1121D ; [.2AF0.0020.0002] # KHOJKI LETTER DHA +1121E ; [.2AF1.0020.0002] # KHOJKI LETTER NA +1121F ; [.2AF2.0020.0002] # KHOJKI LETTER PA +11220 ; [.2AF3.0020.0002] # KHOJKI LETTER PHA +11221 ; [.2AF4.0020.0002] # KHOJKI LETTER BA +11222 ; [.2AF5.0020.0002] # KHOJKI LETTER BBA +11223 ; [.2AF6.0020.0002] # KHOJKI LETTER BHA +11224 ; [.2AF7.0020.0002] # KHOJKI LETTER MA +11225 ; [.2AF8.0020.0002] # KHOJKI LETTER YA +11226 ; [.2AF9.0020.0002] # KHOJKI LETTER RA +11227 ; [.2AFA.0020.0002] # KHOJKI LETTER LA +11228 ; [.2AFB.0020.0002] # KHOJKI LETTER VA +11229 ; [.2AFC.0020.0002] # KHOJKI LETTER SA +1122A ; [.2AFD.0020.0002] # KHOJKI LETTER HA +1122B ; [.2AFE.0020.0002] # KHOJKI LETTER LLA +1122C ; [.2AFF.0020.0002] # KHOJKI VOWEL SIGN AA +1122D ; [.2B00.0020.0002] # KHOJKI VOWEL SIGN I +1122E ; [.2B01.0020.0002] # KHOJKI VOWEL SIGN II +1122F ; [.2B02.0020.0002] # KHOJKI VOWEL SIGN U +11230 ; [.2B03.0020.0002] # KHOJKI VOWEL SIGN E +11231 ; [.2B04.0020.0002] # KHOJKI VOWEL SIGN AI +11232 ; [.2B05.0020.0002] # KHOJKI VOWEL SIGN O +11233 ; [.2B06.0020.0002] # KHOJKI VOWEL SIGN AU +11235 ; [.2B07.0020.0002] # KHOJKI SIGN VIRAMA +112B0 ; [.2B08.0020.0002] # KHUDAWADI LETTER A +112B1 ; [.2B09.0020.0002] # KHUDAWADI LETTER AA +112B2 ; [.2B0A.0020.0002] # KHUDAWADI LETTER I +112B3 ; [.2B0B.0020.0002] # KHUDAWADI LETTER II +112B4 ; [.2B0C.0020.0002] # KHUDAWADI LETTER U +112B5 ; [.2B0D.0020.0002] # KHUDAWADI LETTER UU +112B6 ; [.2B0E.0020.0002] # KHUDAWADI LETTER E +112B7 ; [.2B0F.0020.0002] # KHUDAWADI LETTER AI +112B8 ; [.2B10.0020.0002] # KHUDAWADI LETTER O +112B9 ; [.2B11.0020.0002] # KHUDAWADI LETTER AU +112BA ; [.2B12.0020.0002] # KHUDAWADI LETTER KA +112BB ; [.2B13.0020.0002] # KHUDAWADI LETTER KHA +112BC ; [.2B14.0020.0002] # KHUDAWADI LETTER GA +112BD ; [.2B15.0020.0002] # KHUDAWADI LETTER GGA +112BE ; [.2B16.0020.0002] # KHUDAWADI LETTER GHA +112BF ; [.2B17.0020.0002] # KHUDAWADI LETTER NGA +112C0 ; [.2B18.0020.0002] # KHUDAWADI LETTER CA +112C1 ; [.2B19.0020.0002] # KHUDAWADI LETTER CHA +112C2 ; [.2B1A.0020.0002] # KHUDAWADI LETTER JA +112C3 ; [.2B1B.0020.0002] # KHUDAWADI LETTER JJA +112C4 ; [.2B1C.0020.0002] # KHUDAWADI LETTER JHA +112C5 ; [.2B1D.0020.0002] # KHUDAWADI LETTER NYA +112C6 ; [.2B1E.0020.0002] # KHUDAWADI LETTER TTA +112C7 ; [.2B1F.0020.0002] # KHUDAWADI LETTER TTHA +112C8 ; [.2B20.0020.0002] # KHUDAWADI LETTER DDA +112C9 ; [.2B21.0020.0002] # KHUDAWADI LETTER DDDA +112CA ; [.2B22.0020.0002] # KHUDAWADI LETTER RRA +112CB ; [.2B23.0020.0002] # KHUDAWADI LETTER DDHA +112CC ; [.2B24.0020.0002] # KHUDAWADI LETTER NNA +112CD ; [.2B25.0020.0002] # KHUDAWADI LETTER TA +112CE ; [.2B26.0020.0002] # KHUDAWADI LETTER THA +112CF ; [.2B27.0020.0002] # KHUDAWADI LETTER DA +112D0 ; [.2B28.0020.0002] # KHUDAWADI LETTER DHA +112D1 ; [.2B29.0020.0002] # KHUDAWADI LETTER NA +112D2 ; [.2B2A.0020.0002] # KHUDAWADI LETTER PA +112D3 ; [.2B2B.0020.0002] # KHUDAWADI LETTER PHA +112D4 ; [.2B2C.0020.0002] # KHUDAWADI LETTER BA +112D5 ; [.2B2D.0020.0002] # KHUDAWADI LETTER BBA +112D6 ; [.2B2E.0020.0002] # KHUDAWADI LETTER BHA +112D7 ; [.2B2F.0020.0002] # KHUDAWADI LETTER MA +112D8 ; [.2B30.0020.0002] # KHUDAWADI LETTER YA +112D9 ; [.2B31.0020.0002] # KHUDAWADI LETTER RA +112DA ; [.2B32.0020.0002] # KHUDAWADI LETTER LA +112DB ; [.2B33.0020.0002] # KHUDAWADI LETTER VA +112DC ; [.2B34.0020.0002] # KHUDAWADI LETTER SHA +112DD ; [.2B35.0020.0002] # KHUDAWADI LETTER SA +112DE ; [.2B36.0020.0002] # KHUDAWADI LETTER HA +112E0 ; [.2B37.0020.0002] # KHUDAWADI VOWEL SIGN AA +112E1 ; [.2B38.0020.0002] # KHUDAWADI VOWEL SIGN I +112E2 ; [.2B39.0020.0002] # KHUDAWADI VOWEL SIGN II +112E3 ; [.2B3A.0020.0002] # KHUDAWADI VOWEL SIGN U +112E4 ; [.2B3B.0020.0002] # KHUDAWADI VOWEL SIGN UU +112E5 ; [.2B3C.0020.0002] # KHUDAWADI VOWEL SIGN E +112E6 ; [.2B3D.0020.0002] # KHUDAWADI VOWEL SIGN AI +112E7 ; [.2B3E.0020.0002] # KHUDAWADI VOWEL SIGN O +112E8 ; [.2B3F.0020.0002] # KHUDAWADI VOWEL SIGN AU +112EA ; [.2B40.0020.0002] # KHUDAWADI SIGN VIRAMA +11280 ; [.2B41.0020.0002] # MULTANI LETTER A +11281 ; [.2B42.0020.0002] # MULTANI LETTER I +11282 ; [.2B43.0020.0002] # MULTANI LETTER U +11283 ; [.2B44.0020.0002] # MULTANI LETTER E +112A5 ; [.2B45.0020.0002] # MULTANI LETTER SA +112A6 ; [.2B46.0020.0002] # MULTANI LETTER HA +11284 ; [.2B47.0020.0002] # MULTANI LETTER KA +11285 ; [.2B48.0020.0002] # MULTANI LETTER KHA +11286 ; [.2B49.0020.0002] # MULTANI LETTER GA +11288 ; [.2B4A.0020.0002] # MULTANI LETTER GHA +1128A ; [.2B4B.0020.0002] # MULTANI LETTER CA +1128B ; [.2B4C.0020.0002] # MULTANI LETTER CHA +1128C ; [.2B4D.0020.0002] # MULTANI LETTER JA +1128D ; [.2B4E.0020.0002] # MULTANI LETTER JJA +1128F ; [.2B4F.0020.0002] # MULTANI LETTER NYA +11290 ; [.2B50.0020.0002] # MULTANI LETTER TTA +11291 ; [.2B51.0020.0002] # MULTANI LETTER TTHA +11292 ; [.2B52.0020.0002] # MULTANI LETTER DDA +11293 ; [.2B53.0020.0002] # MULTANI LETTER DDDA +11294 ; [.2B54.0020.0002] # MULTANI LETTER DDHA +11295 ; [.2B55.0020.0002] # MULTANI LETTER NNA +11296 ; [.2B56.0020.0002] # MULTANI LETTER TA +11297 ; [.2B57.0020.0002] # MULTANI LETTER THA +11298 ; [.2B58.0020.0002] # MULTANI LETTER DA +11299 ; [.2B59.0020.0002] # MULTANI LETTER DHA +1129A ; [.2B5A.0020.0002] # MULTANI LETTER NA +1129B ; [.2B5B.0020.0002] # MULTANI LETTER PA +1129C ; [.2B5C.0020.0002] # MULTANI LETTER PHA +1129D ; [.2B5D.0020.0002] # MULTANI LETTER BA +1129F ; [.2B5E.0020.0002] # MULTANI LETTER BHA +112A0 ; [.2B5F.0020.0002] # MULTANI LETTER MA +112A1 ; [.2B60.0020.0002] # MULTANI LETTER YA +112A2 ; [.2B61.0020.0002] # MULTANI LETTER RA +112A3 ; [.2B62.0020.0002] # MULTANI LETTER LA +112A4 ; [.2B63.0020.0002] # MULTANI LETTER VA +112A7 ; [.2B64.0020.0002] # MULTANI LETTER RRA +112A8 ; [.2B65.0020.0002] # MULTANI LETTER RHA +11350 ; [.2B66.0020.0002] # GRANTHA OM +11305 ; [.2B67.0020.0002] # GRANTHA LETTER A +11306 ; [.2B68.0020.0002] # GRANTHA LETTER AA +11307 ; [.2B69.0020.0002] # GRANTHA LETTER I +11308 ; [.2B6A.0020.0002] # GRANTHA LETTER II +11309 ; [.2B6B.0020.0002] # GRANTHA LETTER U +1130A ; [.2B6C.0020.0002] # GRANTHA LETTER UU +1130B ; [.2B6D.0020.0002] # GRANTHA LETTER VOCALIC R +11360 ; [.2B6E.0020.0002] # GRANTHA LETTER VOCALIC RR +1130C ; [.2B6F.0020.0002] # GRANTHA LETTER VOCALIC L +11361 ; [.2B70.0020.0002] # GRANTHA LETTER VOCALIC LL +1130F ; [.2B71.0020.0002] # GRANTHA LETTER EE +11310 ; [.2B72.0020.0002] # GRANTHA LETTER AI +11313 ; [.2B73.0020.0002] # GRANTHA LETTER OO +11314 ; [.2B74.0020.0002] # GRANTHA LETTER AU +11315 ; [.2B75.0020.0002] # GRANTHA LETTER KA +11316 ; [.2B76.0020.0002] # GRANTHA LETTER KHA +11317 ; [.2B77.0020.0002] # GRANTHA LETTER GA +11318 ; [.2B78.0020.0002] # GRANTHA LETTER GHA +11319 ; [.2B79.0020.0002] # GRANTHA LETTER NGA +1131A ; [.2B7A.0020.0002] # GRANTHA LETTER CA +1131B ; [.2B7B.0020.0002] # GRANTHA LETTER CHA +1131C ; [.2B7C.0020.0002] # GRANTHA LETTER JA +1131D ; [.2B7D.0020.0002] # GRANTHA LETTER JHA +1131E ; [.2B7E.0020.0002] # GRANTHA LETTER NYA +1131F ; [.2B7F.0020.0002] # GRANTHA LETTER TTA +11320 ; [.2B80.0020.0002] # GRANTHA LETTER TTHA +11321 ; [.2B81.0020.0002] # GRANTHA LETTER DDA +11322 ; [.2B82.0020.0002] # GRANTHA LETTER DDHA +11323 ; [.2B83.0020.0002] # GRANTHA LETTER NNA +11324 ; [.2B84.0020.0002] # GRANTHA LETTER TA +11325 ; [.2B85.0020.0002] # GRANTHA LETTER THA +11326 ; [.2B86.0020.0002] # GRANTHA LETTER DA +11327 ; [.2B87.0020.0002] # GRANTHA LETTER DHA +11328 ; [.2B88.0020.0002] # GRANTHA LETTER NA +1132A ; [.2B89.0020.0002] # GRANTHA LETTER PA +1132B ; [.2B8A.0020.0002] # GRANTHA LETTER PHA +1132C ; [.2B8B.0020.0002] # GRANTHA LETTER BA +1132D ; [.2B8C.0020.0002] # GRANTHA LETTER BHA +1132E ; [.2B8D.0020.0002] # GRANTHA LETTER MA +1132F ; [.2B8E.0020.0002] # GRANTHA LETTER YA +11330 ; [.2B8F.0020.0002] # GRANTHA LETTER RA +11332 ; [.2B90.0020.0002] # GRANTHA LETTER LA +11333 ; [.2B91.0020.0002] # GRANTHA LETTER LLA +11335 ; [.2B92.0020.0002] # GRANTHA LETTER VA +11336 ; [.2B93.0020.0002] # GRANTHA LETTER SHA +11337 ; [.2B94.0020.0002] # GRANTHA LETTER SSA +11338 ; [.2B95.0020.0002] # GRANTHA LETTER SA +11339 ; [.2B96.0020.0002] # GRANTHA LETTER HA +1133D ; [.2B97.0020.0002] # GRANTHA SIGN AVAGRAHA +1135E ; [.2B98.0020.0002] # GRANTHA LETTER VEDIC ANUSVARA +1135F ; [.2B99.0020.0002] # GRANTHA LETTER VEDIC DOUBLE ANUSVARA +1133E ; [.2B9A.0020.0002] # GRANTHA VOWEL SIGN AA +1133F ; [.2B9B.0020.0002] # GRANTHA VOWEL SIGN I +11340 ; [.2B9C.0020.0002] # GRANTHA VOWEL SIGN II +11341 ; [.2B9D.0020.0002] # GRANTHA VOWEL SIGN U +11342 ; [.2B9E.0020.0002] # GRANTHA VOWEL SIGN UU +11343 ; [.2B9F.0020.0002] # GRANTHA VOWEL SIGN VOCALIC R +11344 ; [.2BA0.0020.0002] # GRANTHA VOWEL SIGN VOCALIC RR +11362 ; [.2BA1.0020.0002] # GRANTHA VOWEL SIGN VOCALIC L +11363 ; [.2BA2.0020.0002] # GRANTHA VOWEL SIGN VOCALIC LL +11347 ; [.2BA3.0020.0002] # GRANTHA VOWEL SIGN EE +11348 ; [.2BA4.0020.0002] # GRANTHA VOWEL SIGN AI +1134B ; [.2BA5.0020.0002] # GRANTHA VOWEL SIGN OO +11347 1133E ; [.2BA5.0020.0002] # GRANTHA VOWEL SIGN OO +1134C ; [.2BA6.0020.0002] # GRANTHA VOWEL SIGN AU +11347 11357 ; [.2BA6.0020.0002] # GRANTHA VOWEL SIGN AU +1134D ; [.2BA7.0020.0002] # GRANTHA SIGN VIRAMA +11357 ; [.2BA8.0020.0002] # GRANTHA AU LENGTH MARK +1135D ; [.2BA9.0020.0002] # GRANTHA SIGN PLUTA +11449 ; [.2BAA.0020.0002] # NEWA OM +1144A ; [.2BAB.0020.0002] # NEWA SIDDHI +11400 ; [.2BAC.0020.0002] # NEWA LETTER A +11401 ; [.2BAD.0020.0002] # NEWA LETTER AA +11402 ; [.2BAE.0020.0002] # NEWA LETTER I +11403 ; [.2BAF.0020.0002] # NEWA LETTER II +11404 ; [.2BB0.0020.0002] # NEWA LETTER U +11405 ; [.2BB1.0020.0002] # NEWA LETTER UU +11406 ; [.2BB2.0020.0002] # NEWA LETTER VOCALIC R +11407 ; [.2BB3.0020.0002] # NEWA LETTER VOCALIC RR +11408 ; [.2BB4.0020.0002] # NEWA LETTER VOCALIC L +11409 ; [.2BB5.0020.0002] # NEWA LETTER VOCALIC LL +1140A ; [.2BB6.0020.0002] # NEWA LETTER E +1140B ; [.2BB7.0020.0002] # NEWA LETTER AI +1140C ; [.2BB8.0020.0002] # NEWA LETTER O +1140D ; [.2BB9.0020.0002] # NEWA LETTER AU +1140E ; [.2BBA.0020.0002] # NEWA LETTER KA +1140F ; [.2BBB.0020.0002] # NEWA LETTER KHA +11410 ; [.2BBC.0020.0002] # NEWA LETTER GA +11411 ; [.2BBD.0020.0002] # NEWA LETTER GHA +11412 ; [.2BBE.0020.0002] # NEWA LETTER NGA +11413 ; [.2BBF.0020.0002] # NEWA LETTER NGHA +11414 ; [.2BC0.0020.0002] # NEWA LETTER CA +11415 ; [.2BC1.0020.0002] # NEWA LETTER CHA +11416 ; [.2BC2.0020.0002] # NEWA LETTER JA +11417 ; [.2BC3.0020.0002] # NEWA LETTER JHA +11418 ; [.2BC4.0020.0002] # NEWA LETTER NYA +11419 ; [.2BC5.0020.0002] # NEWA LETTER NYHA +1141A ; [.2BC6.0020.0002] # NEWA LETTER TTA +1141B ; [.2BC7.0020.0002] # NEWA LETTER TTHA +1141C ; [.2BC8.0020.0002] # NEWA LETTER DDA +1141D ; [.2BC9.0020.0002] # NEWA LETTER DDHA +1141E ; [.2BCA.0020.0002] # NEWA LETTER NNA +1141F ; [.2BCB.0020.0002] # NEWA LETTER TA +11420 ; [.2BCC.0020.0002] # NEWA LETTER THA +11421 ; [.2BCD.0020.0002] # NEWA LETTER DA +11422 ; [.2BCE.0020.0002] # NEWA LETTER DHA +11423 ; [.2BCF.0020.0002] # NEWA LETTER NA +11424 ; [.2BD0.0020.0002] # NEWA LETTER NHA +11425 ; [.2BD1.0020.0002] # NEWA LETTER PA +11426 ; [.2BD2.0020.0002] # NEWA LETTER PHA +11427 ; [.2BD3.0020.0002] # NEWA LETTER BA +11428 ; [.2BD4.0020.0002] # NEWA LETTER BHA +11429 ; [.2BD5.0020.0002] # NEWA LETTER MA +1142A ; [.2BD6.0020.0002] # NEWA LETTER MHA +1142B ; [.2BD7.0020.0002] # NEWA LETTER YA +1142C ; [.2BD8.0020.0002] # NEWA LETTER RA +1142D ; [.2BD9.0020.0002] # NEWA LETTER RHA +1142E ; [.2BDA.0020.0002] # NEWA LETTER LA +1142F ; [.2BDB.0020.0002] # NEWA LETTER LHA +11430 ; [.2BDC.0020.0002] # NEWA LETTER WA +11431 ; [.2BDD.0020.0002] # NEWA LETTER SHA +11432 ; [.2BDE.0020.0002] # NEWA LETTER SSA +11433 ; [.2BDF.0020.0002] # NEWA LETTER SA +11434 ; [.2BE0.0020.0002] # NEWA LETTER HA +11447 ; [.2BE1.0020.0002] # NEWA SIGN AVAGRAHA +11448 ; [.2BE2.0020.0002] # NEWA SIGN FINAL ANUSVARA +11435 ; [.2BE3.0020.0002] # NEWA VOWEL SIGN AA +11436 ; [.2BE4.0020.0002] # NEWA VOWEL SIGN I +11437 ; [.2BE5.0020.0002] # NEWA VOWEL SIGN II +11438 ; [.2BE6.0020.0002] # NEWA VOWEL SIGN U +11439 ; [.2BE7.0020.0002] # NEWA VOWEL SIGN UU +1143A ; [.2BE8.0020.0002] # NEWA VOWEL SIGN VOCALIC R +1143B ; [.2BE9.0020.0002] # NEWA VOWEL SIGN VOCALIC RR +1143C ; [.2BEA.0020.0002] # NEWA VOWEL SIGN VOCALIC L +1143D ; [.2BEB.0020.0002] # NEWA VOWEL SIGN VOCALIC LL +1143E ; [.2BEC.0020.0002] # NEWA VOWEL SIGN E +1143F ; [.2BED.0020.0002] # NEWA VOWEL SIGN AI +11440 ; [.2BEE.0020.0002] # NEWA VOWEL SIGN O +11441 ; [.2BEF.0020.0002] # NEWA VOWEL SIGN AU +11442 ; [.2BF0.0020.0002] # NEWA SIGN VIRAMA +114C7 ; [.2BF1.0020.0002] # TIRHUTA OM +11480 ; [.2BF2.0020.0002] # TIRHUTA ANJI +11481 ; [.2BF3.0020.0002] # TIRHUTA LETTER A +11482 ; [.2BF4.0020.0002] # TIRHUTA LETTER AA +11483 ; [.2BF5.0020.0002] # TIRHUTA LETTER I +11484 ; [.2BF6.0020.0002] # TIRHUTA LETTER II +11485 ; [.2BF7.0020.0002] # TIRHUTA LETTER U +11486 ; [.2BF8.0020.0002] # TIRHUTA LETTER UU +11487 ; [.2BF9.0020.0002] # TIRHUTA LETTER VOCALIC R +11488 ; [.2BFA.0020.0002] # TIRHUTA LETTER VOCALIC RR +11489 ; [.2BFB.0020.0002] # TIRHUTA LETTER VOCALIC L +1148A ; [.2BFC.0020.0002] # TIRHUTA LETTER VOCALIC LL +1148B ; [.2BFD.0020.0002] # TIRHUTA LETTER E +1148C ; [.2BFE.0020.0002] # TIRHUTA LETTER AI +1148D ; [.2BFF.0020.0002] # TIRHUTA LETTER O +1148E ; [.2C00.0020.0002] # TIRHUTA LETTER AU +1148F ; [.2C01.0020.0002] # TIRHUTA LETTER KA +11490 ; [.2C02.0020.0002] # TIRHUTA LETTER KHA +11491 ; [.2C03.0020.0002] # TIRHUTA LETTER GA +11492 ; [.2C04.0020.0002] # TIRHUTA LETTER GHA +11493 ; [.2C05.0020.0002] # TIRHUTA LETTER NGA +11494 ; [.2C06.0020.0002] # TIRHUTA LETTER CA +11495 ; [.2C07.0020.0002] # TIRHUTA LETTER CHA +11496 ; [.2C08.0020.0002] # TIRHUTA LETTER JA +11497 ; [.2C09.0020.0002] # TIRHUTA LETTER JHA +11498 ; [.2C0A.0020.0002] # TIRHUTA LETTER NYA +11499 ; [.2C0B.0020.0002] # TIRHUTA LETTER TTA +1149A ; [.2C0C.0020.0002] # TIRHUTA LETTER TTHA +1149B ; [.2C0D.0020.0002] # TIRHUTA LETTER DDA +1149C ; [.2C0E.0020.0002] # TIRHUTA LETTER DDHA +1149D ; [.2C0F.0020.0002] # TIRHUTA LETTER NNA +1149E ; [.2C10.0020.0002] # TIRHUTA LETTER TA +1149F ; [.2C11.0020.0002] # TIRHUTA LETTER THA +114A0 ; [.2C12.0020.0002] # TIRHUTA LETTER DA +114A1 ; [.2C13.0020.0002] # TIRHUTA LETTER DHA +114A2 ; [.2C14.0020.0002] # TIRHUTA LETTER NA +114A3 ; [.2C15.0020.0002] # TIRHUTA LETTER PA +114A4 ; [.2C16.0020.0002] # TIRHUTA LETTER PHA +114A5 ; [.2C17.0020.0002] # TIRHUTA LETTER BA +114A6 ; [.2C18.0020.0002] # TIRHUTA LETTER BHA +114A7 ; [.2C19.0020.0002] # TIRHUTA LETTER MA +114A8 ; [.2C1A.0020.0002] # TIRHUTA LETTER YA +114A9 ; [.2C1B.0020.0002] # TIRHUTA LETTER RA +114AA ; [.2C1C.0020.0002] # TIRHUTA LETTER LA +114AB ; [.2C1D.0020.0002] # TIRHUTA LETTER VA +114AC ; [.2C1E.0020.0002] # TIRHUTA LETTER SHA +114AD ; [.2C1F.0020.0002] # TIRHUTA LETTER SSA +114AE ; [.2C20.0020.0002] # TIRHUTA LETTER SA +114AF ; [.2C21.0020.0002] # TIRHUTA LETTER HA +114C4 ; [.2C22.0020.0002] # TIRHUTA SIGN AVAGRAHA +114C5 ; [.2C23.0020.0002] # TIRHUTA GVANG +114B0 ; [.2C24.0020.0002] # TIRHUTA VOWEL SIGN AA +114B1 ; [.2C25.0020.0002] # TIRHUTA VOWEL SIGN I +114B2 ; [.2C26.0020.0002] # TIRHUTA VOWEL SIGN II +114B3 ; [.2C27.0020.0002] # TIRHUTA VOWEL SIGN U +114B4 ; [.2C28.0020.0002] # TIRHUTA VOWEL SIGN UU +114B5 ; [.2C29.0020.0002] # TIRHUTA VOWEL SIGN VOCALIC R +114B6 ; [.2C2A.0020.0002] # TIRHUTA VOWEL SIGN VOCALIC RR +114B7 ; [.2C2B.0020.0002] # TIRHUTA VOWEL SIGN VOCALIC L +114B8 ; [.2C2C.0020.0002] # TIRHUTA VOWEL SIGN VOCALIC LL +114B9 ; [.2C2D.0020.0002] # TIRHUTA VOWEL SIGN E +114BA ; [.2C2E.0020.0002] # TIRHUTA VOWEL SIGN SHORT E +114BB ; [.2C2F.0020.0002] # TIRHUTA VOWEL SIGN AI +114B9 114BA ; [.2C2F.0020.0002] # TIRHUTA VOWEL SIGN AI +114BC ; [.2C30.0020.0002] # TIRHUTA VOWEL SIGN O +114B9 114B0 ; [.2C30.0020.0002] # TIRHUTA VOWEL SIGN O +114BD ; [.2C31.0020.0002] # TIRHUTA VOWEL SIGN SHORT O +114BE ; [.2C32.0020.0002] # TIRHUTA VOWEL SIGN AU +114B9 114BD ; [.2C32.0020.0002] # TIRHUTA VOWEL SIGN AU +114C2 ; [.2C33.0020.0002] # TIRHUTA SIGN VIRAMA +11580 ; [.2C34.0020.0002] # SIDDHAM LETTER A +11581 ; [.2C35.0020.0002] # SIDDHAM LETTER AA +11582 ; [.2C36.0020.0002] # SIDDHAM LETTER I +115D8 ; [.2C36.0020.0004][.0000.0111.0004] # SIDDHAM LETTER THREE-CIRCLE ALTERNATE I +115D9 ; [.2C36.0020.0004][.0000.0112.0004] # SIDDHAM LETTER TWO-CIRCLE ALTERNATE I +11583 ; [.2C37.0020.0002] # SIDDHAM LETTER II +115DA ; [.2C37.0020.0004][.0000.0111.0004] # SIDDHAM LETTER TWO-CIRCLE ALTERNATE II +11584 ; [.2C38.0020.0002] # SIDDHAM LETTER U +115DB ; [.2C38.0020.0004][.0000.0111.0004] # SIDDHAM LETTER ALTERNATE U +11585 ; [.2C39.0020.0002] # SIDDHAM LETTER UU +11586 ; [.2C3A.0020.0002] # SIDDHAM LETTER VOCALIC R +11587 ; [.2C3B.0020.0002] # SIDDHAM LETTER VOCALIC RR +11588 ; [.2C3C.0020.0002] # SIDDHAM LETTER VOCALIC L +11589 ; [.2C3D.0020.0002] # SIDDHAM LETTER VOCALIC LL +1158A ; [.2C3E.0020.0002] # SIDDHAM LETTER E +1158B ; [.2C3F.0020.0002] # SIDDHAM LETTER AI +1158C ; [.2C40.0020.0002] # SIDDHAM LETTER O +1158D ; [.2C41.0020.0002] # SIDDHAM LETTER AU +1158E ; [.2C42.0020.0002] # SIDDHAM LETTER KA +1158F ; [.2C43.0020.0002] # SIDDHAM LETTER KHA +11590 ; [.2C44.0020.0002] # SIDDHAM LETTER GA +11591 ; [.2C45.0020.0002] # SIDDHAM LETTER GHA +11592 ; [.2C46.0020.0002] # SIDDHAM LETTER NGA +11593 ; [.2C47.0020.0002] # SIDDHAM LETTER CA +11594 ; [.2C48.0020.0002] # SIDDHAM LETTER CHA +11595 ; [.2C49.0020.0002] # SIDDHAM LETTER JA +11596 ; [.2C4A.0020.0002] # SIDDHAM LETTER JHA +11597 ; [.2C4B.0020.0002] # SIDDHAM LETTER NYA +11598 ; [.2C4C.0020.0002] # SIDDHAM LETTER TTA +11599 ; [.2C4D.0020.0002] # SIDDHAM LETTER TTHA +1159A ; [.2C4E.0020.0002] # SIDDHAM LETTER DDA +1159B ; [.2C4F.0020.0002] # SIDDHAM LETTER DDHA +1159C ; [.2C50.0020.0002] # SIDDHAM LETTER NNA +1159D ; [.2C51.0020.0002] # SIDDHAM LETTER TA +1159E ; [.2C52.0020.0002] # SIDDHAM LETTER THA +1159F ; [.2C53.0020.0002] # SIDDHAM LETTER DA +115A0 ; [.2C54.0020.0002] # SIDDHAM LETTER DHA +115A1 ; [.2C55.0020.0002] # SIDDHAM LETTER NA +115A2 ; [.2C56.0020.0002] # SIDDHAM LETTER PA +115A3 ; [.2C57.0020.0002] # SIDDHAM LETTER PHA +115A4 ; [.2C58.0020.0002] # SIDDHAM LETTER BA +115A5 ; [.2C59.0020.0002] # SIDDHAM LETTER BHA +115A6 ; [.2C5A.0020.0002] # SIDDHAM LETTER MA +115A7 ; [.2C5B.0020.0002] # SIDDHAM LETTER YA +115A8 ; [.2C5C.0020.0002] # SIDDHAM LETTER RA +115A9 ; [.2C5D.0020.0002] # SIDDHAM LETTER LA +115AA ; [.2C5E.0020.0002] # SIDDHAM LETTER VA +115AB ; [.2C5F.0020.0002] # SIDDHAM LETTER SHA +115AC ; [.2C60.0020.0002] # SIDDHAM LETTER SSA +115AD ; [.2C61.0020.0002] # SIDDHAM LETTER SA +115AE ; [.2C62.0020.0002] # SIDDHAM LETTER HA +115AF ; [.2C63.0020.0002] # SIDDHAM VOWEL SIGN AA +115B0 ; [.2C64.0020.0002] # SIDDHAM VOWEL SIGN I +115B1 ; [.2C65.0020.0002] # SIDDHAM VOWEL SIGN II +115B2 ; [.2C66.0020.0002] # SIDDHAM VOWEL SIGN U +115DC ; [.2C66.0020.0004][.0000.0111.0004] # SIDDHAM VOWEL SIGN ALTERNATE U +115B3 ; [.2C67.0020.0002] # SIDDHAM VOWEL SIGN UU +115DD ; [.2C67.0020.0004][.0000.0111.0004] # SIDDHAM VOWEL SIGN ALTERNATE UU +115B4 ; [.2C68.0020.0002] # SIDDHAM VOWEL SIGN VOCALIC R +115B5 ; [.2C69.0020.0002] # SIDDHAM VOWEL SIGN VOCALIC RR +115B8 ; [.2C6A.0020.0002] # SIDDHAM VOWEL SIGN E +115B9 ; [.2C6B.0020.0002] # SIDDHAM VOWEL SIGN AI +115BA ; [.2C6C.0020.0002] # SIDDHAM VOWEL SIGN O +115B8 115AF ; [.2C6C.0020.0002] # SIDDHAM VOWEL SIGN O +115BB ; [.2C6D.0020.0002] # SIDDHAM VOWEL SIGN AU +115B9 115AF ; [.2C6D.0020.0002] # SIDDHAM VOWEL SIGN AU +115BF ; [.2C6E.0020.0002] # SIDDHAM SIGN VIRAMA +11600 ; [.2C6F.0020.0002] # MODI LETTER A +11601 ; [.2C70.0020.0002] # MODI LETTER AA +11602 ; [.2C71.0020.0002] # MODI LETTER I +11603 ; [.2C72.0020.0002] # MODI LETTER II +11604 ; [.2C73.0020.0002] # MODI LETTER U +11605 ; [.2C74.0020.0002] # MODI LETTER UU +11606 ; [.2C75.0020.0002] # MODI LETTER VOCALIC R +11607 ; [.2C76.0020.0002] # MODI LETTER VOCALIC RR +11608 ; [.2C77.0020.0002] # MODI LETTER VOCALIC L +11609 ; [.2C78.0020.0002] # MODI LETTER VOCALIC LL +1160A ; [.2C79.0020.0002] # MODI LETTER E +1160B ; [.2C7A.0020.0002] # MODI LETTER AI +1160C ; [.2C7B.0020.0002] # MODI LETTER O +1160D ; [.2C7C.0020.0002] # MODI LETTER AU +1160E ; [.2C7D.0020.0002] # MODI LETTER KA +1160F ; [.2C7E.0020.0002] # MODI LETTER KHA +11610 ; [.2C7F.0020.0002] # MODI LETTER GA +11611 ; [.2C80.0020.0002] # MODI LETTER GHA +11612 ; [.2C81.0020.0002] # MODI LETTER NGA +11613 ; [.2C82.0020.0002] # MODI LETTER CA +11614 ; [.2C83.0020.0002] # MODI LETTER CHA +11615 ; [.2C84.0020.0002] # MODI LETTER JA +11616 ; [.2C85.0020.0002] # MODI LETTER JHA +11617 ; [.2C86.0020.0002] # MODI LETTER NYA +11618 ; [.2C87.0020.0002] # MODI LETTER TTA +11619 ; [.2C88.0020.0002] # MODI LETTER TTHA +1161A ; [.2C89.0020.0002] # MODI LETTER DDA +1161B ; [.2C8A.0020.0002] # MODI LETTER DDHA +1161C ; [.2C8B.0020.0002] # MODI LETTER NNA +1161D ; [.2C8C.0020.0002] # MODI LETTER TA +1161E ; [.2C8D.0020.0002] # MODI LETTER THA +1161F ; [.2C8E.0020.0002] # MODI LETTER DA +11620 ; [.2C8F.0020.0002] # MODI LETTER DHA +11621 ; [.2C90.0020.0002] # MODI LETTER NA +11622 ; [.2C91.0020.0002] # MODI LETTER PA +11623 ; [.2C92.0020.0002] # MODI LETTER PHA +11624 ; [.2C93.0020.0002] # MODI LETTER BA +11625 ; [.2C94.0020.0002] # MODI LETTER BHA +11626 ; [.2C95.0020.0002] # MODI LETTER MA +11627 ; [.2C96.0020.0002] # MODI LETTER YA +11628 ; [.2C97.0020.0002] # MODI LETTER RA +11629 ; [.2C98.0020.0002] # MODI LETTER LA +1162A ; [.2C99.0020.0002] # MODI LETTER VA +1162B ; [.2C9A.0020.0002] # MODI LETTER SHA +1162C ; [.2C9B.0020.0002] # MODI LETTER SSA +1162D ; [.2C9C.0020.0002] # MODI LETTER SA +1162E ; [.2C9D.0020.0002] # MODI LETTER HA +1162F ; [.2C9E.0020.0002] # MODI LETTER LLA +11630 ; [.2C9F.0020.0002] # MODI VOWEL SIGN AA +11631 ; [.2CA0.0020.0002] # MODI VOWEL SIGN I +11632 ; [.2CA1.0020.0002] # MODI VOWEL SIGN II +11633 ; [.2CA2.0020.0002] # MODI VOWEL SIGN U +11634 ; [.2CA3.0020.0002] # MODI VOWEL SIGN UU +11635 ; [.2CA4.0020.0002] # MODI VOWEL SIGN VOCALIC R +11636 ; [.2CA5.0020.0002] # MODI VOWEL SIGN VOCALIC RR +11637 ; [.2CA6.0020.0002] # MODI VOWEL SIGN VOCALIC L +11638 ; [.2CA7.0020.0002] # MODI VOWEL SIGN VOCALIC LL +11639 ; [.2CA8.0020.0002] # MODI VOWEL SIGN E +1163A ; [.2CA9.0020.0002] # MODI VOWEL SIGN AI +1163B ; [.2CAA.0020.0002] # MODI VOWEL SIGN O +1163C ; [.2CAB.0020.0002] # MODI VOWEL SIGN AU +1163F ; [.2CAC.0020.0002] # MODI SIGN VIRAMA +11644 ; [.2CAD.0020.0002] # MODI SIGN HUVA +11680 ; [.2CAE.0020.0002] # TAKRI LETTER A +11681 ; [.2CAF.0020.0002] # TAKRI LETTER AA +11682 ; [.2CB0.0020.0002] # TAKRI LETTER I +11683 ; [.2CB1.0020.0002] # TAKRI LETTER II +11684 ; [.2CB2.0020.0002] # TAKRI LETTER U +11685 ; [.2CB3.0020.0002] # TAKRI LETTER UU +11686 ; [.2CB4.0020.0002] # TAKRI LETTER E +11687 ; [.2CB5.0020.0002] # TAKRI LETTER AI +11688 ; [.2CB6.0020.0002] # TAKRI LETTER O +11689 ; [.2CB7.0020.0002] # TAKRI LETTER AU +116A8 ; [.2CB8.0020.0002] # TAKRI LETTER SA +116A7 ; [.2CB9.0020.0002] # TAKRI LETTER SHA +116A9 ; [.2CBA.0020.0002] # TAKRI LETTER HA +1168A ; [.2CBB.0020.0002] # TAKRI LETTER KA +1168B ; [.2CBC.0020.0002] # TAKRI LETTER KHA +1168C ; [.2CBD.0020.0002] # TAKRI LETTER GA +1168D ; [.2CBE.0020.0002] # TAKRI LETTER GHA +1168E ; [.2CBF.0020.0002] # TAKRI LETTER NGA +1168F ; [.2CC0.0020.0002] # TAKRI LETTER CA +11690 ; [.2CC1.0020.0002] # TAKRI LETTER CHA +11691 ; [.2CC2.0020.0002] # TAKRI LETTER JA +11692 ; [.2CC3.0020.0002] # TAKRI LETTER JHA +11693 ; [.2CC4.0020.0002] # TAKRI LETTER NYA +11694 ; [.2CC5.0020.0002] # TAKRI LETTER TTA +11695 ; [.2CC6.0020.0002] # TAKRI LETTER TTHA +11696 ; [.2CC7.0020.0002] # TAKRI LETTER DDA +11697 ; [.2CC8.0020.0002] # TAKRI LETTER DDHA +11698 ; [.2CC9.0020.0002] # TAKRI LETTER NNA +11699 ; [.2CCA.0020.0002] # TAKRI LETTER TA +1169A ; [.2CCB.0020.0002] # TAKRI LETTER THA +1169B ; [.2CCC.0020.0002] # TAKRI LETTER DA +1169C ; [.2CCD.0020.0002] # TAKRI LETTER DHA +1169D ; [.2CCE.0020.0002] # TAKRI LETTER NA +1169E ; [.2CCF.0020.0002] # TAKRI LETTER PA +1169F ; [.2CD0.0020.0002] # TAKRI LETTER PHA +116A0 ; [.2CD1.0020.0002] # TAKRI LETTER BA +116A1 ; [.2CD2.0020.0002] # TAKRI LETTER BHA +116A2 ; [.2CD3.0020.0002] # TAKRI LETTER MA +116A3 ; [.2CD4.0020.0002] # TAKRI LETTER YA +116A4 ; [.2CD5.0020.0002] # TAKRI LETTER RA +116A5 ; [.2CD6.0020.0002] # TAKRI LETTER LA +116A6 ; [.2CD7.0020.0002] # TAKRI LETTER VA +116AA ; [.2CD8.0020.0002] # TAKRI LETTER RRA +116AD ; [.2CD9.0020.0002] # TAKRI VOWEL SIGN AA +116AE ; [.2CDA.0020.0002] # TAKRI VOWEL SIGN I +116AF ; [.2CDB.0020.0002] # TAKRI VOWEL SIGN II +116B0 ; [.2CDC.0020.0002] # TAKRI VOWEL SIGN U +116B1 ; [.2CDD.0020.0002] # TAKRI VOWEL SIGN UU +116B2 ; [.2CDE.0020.0002] # TAKRI VOWEL SIGN E +116B3 ; [.2CDF.0020.0002] # TAKRI VOWEL SIGN AI +116B4 ; [.2CE0.0020.0002] # TAKRI VOWEL SIGN O +116B5 ; [.2CE1.0020.0002] # TAKRI VOWEL SIGN AU +116B6 ; [.2CE2.0020.0002] # TAKRI SIGN VIRAMA +11700 ; [.2CE3.0020.0002] # AHOM LETTER KA +11701 ; [.2CE4.0020.0002] # AHOM LETTER KHA +11702 ; [.2CE5.0020.0002] # AHOM LETTER NGA +11703 ; [.2CE6.0020.0002] # AHOM LETTER NA +11704 ; [.2CE7.0020.0002] # AHOM LETTER TA +11705 ; [.2CE7.0020.0004][.0000.0111.0004] # AHOM LETTER ALTERNATE TA +11706 ; [.2CE8.0020.0002] # AHOM LETTER PA +11707 ; [.2CE9.0020.0002] # AHOM LETTER PHA +11708 ; [.2CEA.0020.0002] # AHOM LETTER BA +11709 ; [.2CEB.0020.0002] # AHOM LETTER MA +1170A ; [.2CEC.0020.0002] # AHOM LETTER JA +1170B ; [.2CED.0020.0002] # AHOM LETTER CHA +1170C ; [.2CEE.0020.0002] # AHOM LETTER THA +1170D ; [.2CEF.0020.0002] # AHOM LETTER RA +1170E ; [.2CF0.0020.0002] # AHOM LETTER LA +1170F ; [.2CF1.0020.0002] # AHOM LETTER SA +11710 ; [.2CF2.0020.0002] # AHOM LETTER NYA +11711 ; [.2CF3.0020.0002] # AHOM LETTER HA +11712 ; [.2CF4.0020.0002] # AHOM LETTER A +11713 ; [.2CF5.0020.0002] # AHOM LETTER DA +11714 ; [.2CF6.0020.0002] # AHOM LETTER DHA +11715 ; [.2CF7.0020.0002] # AHOM LETTER GA +11716 ; [.2CF7.0020.0004][.0000.0111.0004] # AHOM LETTER ALTERNATE GA +11717 ; [.2CF8.0020.0002] # AHOM LETTER GHA +11718 ; [.2CF9.0020.0002] # AHOM LETTER BHA +11719 ; [.2CFA.0020.0002] # AHOM LETTER JHA +11720 ; [.2CFB.0020.0002] # AHOM VOWEL SIGN A +11721 ; [.2CFC.0020.0002] # AHOM VOWEL SIGN AA +11722 ; [.2CFD.0020.0002] # AHOM VOWEL SIGN I +11723 ; [.2CFE.0020.0002] # AHOM VOWEL SIGN II +11724 ; [.2CFF.0020.0002] # AHOM VOWEL SIGN U +11725 ; [.2D00.0020.0002] # AHOM VOWEL SIGN UU +11726 ; [.2D01.0020.0002] # AHOM VOWEL SIGN E +11727 ; [.2D02.0020.0002] # AHOM VOWEL SIGN AW +11728 ; [.2D03.0020.0002] # AHOM VOWEL SIGN O +11729 ; [.2D04.0020.0002] # AHOM VOWEL SIGN AI +1172A ; [.2D05.0020.0002] # AHOM VOWEL SIGN AM +1172B ; [.2D06.0020.0002] # AHOM SIGN KILLER +1171D ; [.2D07.0020.0002] # AHOM CONSONANT SIGN MEDIAL LA +1171E ; [.2D08.0020.0002] # AHOM CONSONANT SIGN MEDIAL RA +1171F ; [.2D09.0020.0002] # AHOM CONSONANT SIGN MEDIAL LIGATING RA +11D00 ; [.2D0A.0020.0002] # MASARAM GONDI LETTER A +11D01 ; [.2D0B.0020.0002] # MASARAM GONDI LETTER AA +11D02 ; [.2D0C.0020.0002] # MASARAM GONDI LETTER I +11D03 ; [.2D0D.0020.0002] # MASARAM GONDI LETTER II +11D04 ; [.2D0E.0020.0002] # MASARAM GONDI LETTER U +11D05 ; [.2D0F.0020.0002] # MASARAM GONDI LETTER UU +11D06 ; [.2D10.0020.0002] # MASARAM GONDI LETTER E +11D08 ; [.2D11.0020.0002] # MASARAM GONDI LETTER AI +11D09 ; [.2D12.0020.0002] # MASARAM GONDI LETTER O +11D0B ; [.2D13.0020.0002] # MASARAM GONDI LETTER AU +11D0C ; [.2D14.0020.0002] # MASARAM GONDI LETTER KA +11D0D ; [.2D15.0020.0002] # MASARAM GONDI LETTER KHA +11D0E ; [.2D16.0020.0002] # MASARAM GONDI LETTER GA +11D0F ; [.2D17.0020.0002] # MASARAM GONDI LETTER GHA +11D10 ; [.2D18.0020.0002] # MASARAM GONDI LETTER NGA +11D11 ; [.2D19.0020.0002] # MASARAM GONDI LETTER CA +11D12 ; [.2D1A.0020.0002] # MASARAM GONDI LETTER CHA +11D13 ; [.2D1B.0020.0002] # MASARAM GONDI LETTER JA +11D14 ; [.2D1C.0020.0002] # MASARAM GONDI LETTER JHA +11D15 ; [.2D1D.0020.0002] # MASARAM GONDI LETTER NYA +11D16 ; [.2D1E.0020.0002] # MASARAM GONDI LETTER TTA +11D17 ; [.2D1F.0020.0002] # MASARAM GONDI LETTER TTHA +11D18 ; [.2D20.0020.0002] # MASARAM GONDI LETTER DDA +11D19 ; [.2D21.0020.0002] # MASARAM GONDI LETTER DDHA +11D1A ; [.2D22.0020.0002] # MASARAM GONDI LETTER NNA +11D1B ; [.2D23.0020.0002] # MASARAM GONDI LETTER TA +11D1C ; [.2D24.0020.0002] # MASARAM GONDI LETTER THA +11D1D ; [.2D25.0020.0002] # MASARAM GONDI LETTER DA +11D1E ; [.2D26.0020.0002] # MASARAM GONDI LETTER DHA +11D1F ; [.2D27.0020.0002] # MASARAM GONDI LETTER NA +11D20 ; [.2D28.0020.0002] # MASARAM GONDI LETTER PA +11D21 ; [.2D29.0020.0002] # MASARAM GONDI LETTER PHA +11D22 ; [.2D2A.0020.0002] # MASARAM GONDI LETTER BA +11D23 ; [.2D2B.0020.0002] # MASARAM GONDI LETTER BHA +11D24 ; [.2D2C.0020.0002] # MASARAM GONDI LETTER MA +11D25 ; [.2D2D.0020.0002] # MASARAM GONDI LETTER YA +11D26 ; [.2D2E.0020.0002] # MASARAM GONDI LETTER RA +11D46 ; [.2D2E.0020.0017] # MASARAM GONDI REPHA +11D47 ; [.2D2E.0020.0019] # MASARAM GONDI RA-KARA +11D27 ; [.2D2F.0020.0002] # MASARAM GONDI LETTER LA +11D28 ; [.2D30.0020.0002] # MASARAM GONDI LETTER VA +11D29 ; [.2D31.0020.0002] # MASARAM GONDI LETTER SHA +11D2A ; [.2D32.0020.0002] # MASARAM GONDI LETTER SSA +11D2B ; [.2D33.0020.0002] # MASARAM GONDI LETTER SA +11D2C ; [.2D34.0020.0002] # MASARAM GONDI LETTER HA +11D2D ; [.2D35.0020.0002] # MASARAM GONDI LETTER LLA +11D2E ; [.2D36.0020.0002] # MASARAM GONDI LETTER KSSA +11D2F ; [.2D37.0020.0002] # MASARAM GONDI LETTER JNYA +11D30 ; [.2D38.0020.0002] # MASARAM GONDI LETTER TRA +11D31 ; [.2D39.0020.0002] # MASARAM GONDI VOWEL SIGN AA +11D32 ; [.2D3A.0020.0002] # MASARAM GONDI VOWEL SIGN I +11D33 ; [.2D3B.0020.0002] # MASARAM GONDI VOWEL SIGN II +11D34 ; [.2D3C.0020.0002] # MASARAM GONDI VOWEL SIGN U +11D35 ; [.2D3D.0020.0002] # MASARAM GONDI VOWEL SIGN UU +11D36 ; [.2D3E.0020.0002] # MASARAM GONDI VOWEL SIGN VOCALIC R +11D3A ; [.2D3F.0020.0002] # MASARAM GONDI VOWEL SIGN E +11D3C ; [.2D40.0020.0002] # MASARAM GONDI VOWEL SIGN AI +11D3D ; [.2D41.0020.0002] # MASARAM GONDI VOWEL SIGN O +11D3F ; [.2D42.0020.0002] # MASARAM GONDI VOWEL SIGN AU +11D44 ; [.2D43.0020.0002] # MASARAM GONDI SIGN HALANTA +11D45 ; [.2D44.0020.0002] # MASARAM GONDI VIRAMA +1B83 ; [.2D45.0020.0002] # SUNDANESE LETTER A +1BBA ; [.2D45.0020.0004] # SUNDANESE AVAGRAHA +1B84 ; [.2D46.0020.0002] # SUNDANESE LETTER I +1B85 ; [.2D47.0020.0002] # SUNDANESE LETTER U +1B86 ; [.2D48.0020.0002] # SUNDANESE LETTER AE +1B87 ; [.2D49.0020.0002] # SUNDANESE LETTER O +1B88 ; [.2D4A.0020.0002] # SUNDANESE LETTER E +1B89 ; [.2D4B.0020.0002] # SUNDANESE LETTER EU +1B8A ; [.2D4C.0020.0002] # SUNDANESE LETTER KA +1BBE ; [.2D4C.0020.0019] # SUNDANESE LETTER FINAL K +1BAE ; [.2D4D.0020.0002] # SUNDANESE LETTER KHA +1B8B ; [.2D4E.0020.0002] # SUNDANESE LETTER QA +1B8C ; [.2D4F.0020.0002] # SUNDANESE LETTER GA +1B8D ; [.2D50.0020.0002] # SUNDANESE LETTER NGA +1B8E ; [.2D51.0020.0002] # SUNDANESE LETTER CA +1B8F ; [.2D52.0020.0002] # SUNDANESE LETTER JA +1B90 ; [.2D53.0020.0002] # SUNDANESE LETTER ZA +1B91 ; [.2D54.0020.0002] # SUNDANESE LETTER NYA +1B92 ; [.2D55.0020.0002] # SUNDANESE LETTER TA +1B93 ; [.2D56.0020.0002] # SUNDANESE LETTER DA +1B94 ; [.2D57.0020.0002] # SUNDANESE LETTER NA +1B95 ; [.2D58.0020.0002] # SUNDANESE LETTER PA +1B96 ; [.2D59.0020.0002] # SUNDANESE LETTER FA +1B97 ; [.2D5A.0020.0002] # SUNDANESE LETTER VA +1B98 ; [.2D5B.0020.0002] # SUNDANESE LETTER BA +1BBD ; [.2D5C.0020.0002] # SUNDANESE LETTER BHA +1B99 ; [.2D5D.0020.0002] # SUNDANESE LETTER MA +1BBF ; [.2D5D.0020.0019] # SUNDANESE LETTER FINAL M +1BAC ; [.2D5E.0020.0002] # SUNDANESE CONSONANT SIGN PASANGAN MA +1B9A ; [.2D5F.0020.0002] # SUNDANESE LETTER YA +1BA1 ; [.2D60.0020.0002] # SUNDANESE CONSONANT SIGN PAMINGKAL +1B9B ; [.2D61.0020.0002] # SUNDANESE LETTER RA +1BA2 ; [.2D62.0020.0002] # SUNDANESE CONSONANT SIGN PANYAKRA +1BBB ; [.2D63.0020.0002] # SUNDANESE LETTER REU +1B9C ; [.2D64.0020.0002] # SUNDANESE LETTER LA +1BA3 ; [.2D65.0020.0002] # SUNDANESE CONSONANT SIGN PANYIKU +1BBC ; [.2D66.0020.0002] # SUNDANESE LETTER LEU +1B9D ; [.2D67.0020.0002] # SUNDANESE LETTER WA +1BAD ; [.2D68.0020.0002] # SUNDANESE CONSONANT SIGN PASANGAN WA +1B9E ; [.2D69.0020.0002] # SUNDANESE LETTER SA +1B9F ; [.2D6A.0020.0002] # SUNDANESE LETTER XA +1BAF ; [.2D6B.0020.0002] # SUNDANESE LETTER SYA +1BA0 ; [.2D6C.0020.0002] # SUNDANESE LETTER HA +1BA4 ; [.2D6D.0020.0002] # SUNDANESE VOWEL SIGN PANGHULU +1BA5 ; [.2D6E.0020.0002] # SUNDANESE VOWEL SIGN PANYUKU +1BA6 ; [.2D6F.0020.0002] # SUNDANESE VOWEL SIGN PANAELAENG +1BA7 ; [.2D70.0020.0002] # SUNDANESE VOWEL SIGN PANOLONG +1BA8 ; [.2D71.0020.0002] # SUNDANESE VOWEL SIGN PAMEPET +1BA9 ; [.2D72.0020.0002] # SUNDANESE VOWEL SIGN PANEULEUNG +1BAA ; [.2D73.0020.0002] # SUNDANESE SIGN PAMAAEH +1BAB ; [.2D74.0020.0002] # SUNDANESE SIGN VIRAMA +11005 ; [.2D75.0020.0002] # BRAHMI LETTER A +11006 ; [.2D76.0020.0002] # BRAHMI LETTER AA +11007 ; [.2D77.0020.0002] # BRAHMI LETTER I +11008 ; [.2D78.0020.0002] # BRAHMI LETTER II +11009 ; [.2D79.0020.0002] # BRAHMI LETTER U +1100A ; [.2D7A.0020.0002] # BRAHMI LETTER UU +1100B ; [.2D7B.0020.0002] # BRAHMI LETTER VOCALIC R +1100C ; [.2D7C.0020.0002] # BRAHMI LETTER VOCALIC RR +1100D ; [.2D7D.0020.0002] # BRAHMI LETTER VOCALIC L +1100E ; [.2D7E.0020.0002] # BRAHMI LETTER VOCALIC LL +1100F ; [.2D7F.0020.0002] # BRAHMI LETTER E +11010 ; [.2D80.0020.0002] # BRAHMI LETTER AI +11011 ; [.2D81.0020.0002] # BRAHMI LETTER O +11012 ; [.2D82.0020.0002] # BRAHMI LETTER AU +11013 ; [.2D83.0020.0002] # BRAHMI LETTER KA +11014 ; [.2D84.0020.0002] # BRAHMI LETTER KHA +11015 ; [.2D85.0020.0002] # BRAHMI LETTER GA +11016 ; [.2D86.0020.0002] # BRAHMI LETTER GHA +11017 ; [.2D87.0020.0002] # BRAHMI LETTER NGA +11018 ; [.2D88.0020.0002] # BRAHMI LETTER CA +11019 ; [.2D89.0020.0002] # BRAHMI LETTER CHA +1101A ; [.2D8A.0020.0002] # BRAHMI LETTER JA +1101B ; [.2D8B.0020.0002] # BRAHMI LETTER JHA +1101C ; [.2D8C.0020.0002] # BRAHMI LETTER NYA +1101D ; [.2D8D.0020.0002] # BRAHMI LETTER TTA +1101E ; [.2D8E.0020.0002] # BRAHMI LETTER TTHA +1101F ; [.2D8F.0020.0002] # BRAHMI LETTER DDA +11020 ; [.2D90.0020.0002] # BRAHMI LETTER DDHA +11021 ; [.2D91.0020.0002] # BRAHMI LETTER NNA +11022 ; [.2D92.0020.0002] # BRAHMI LETTER TA +11023 ; [.2D93.0020.0002] # BRAHMI LETTER THA +11024 ; [.2D94.0020.0002] # BRAHMI LETTER DA +11025 ; [.2D95.0020.0002] # BRAHMI LETTER DHA +11026 ; [.2D96.0020.0002] # BRAHMI LETTER NA +11027 ; [.2D97.0020.0002] # BRAHMI LETTER PA +11028 ; [.2D98.0020.0002] # BRAHMI LETTER PHA +11029 ; [.2D99.0020.0002] # BRAHMI LETTER BA +1102A ; [.2D9A.0020.0002] # BRAHMI LETTER BHA +1102B ; [.2D9B.0020.0002] # BRAHMI LETTER MA +1102C ; [.2D9C.0020.0002] # BRAHMI LETTER YA +1102D ; [.2D9D.0020.0002] # BRAHMI LETTER RA +1102E ; [.2D9E.0020.0002] # BRAHMI LETTER LA +1102F ; [.2D9F.0020.0002] # BRAHMI LETTER VA +11030 ; [.2DA0.0020.0002] # BRAHMI LETTER SHA +11031 ; [.2DA1.0020.0002] # BRAHMI LETTER SSA +11032 ; [.2DA2.0020.0002] # BRAHMI LETTER SA +11033 ; [.2DA3.0020.0002] # BRAHMI LETTER HA +11003 ; [.2DA4.0020.0002] # BRAHMI SIGN JIHVAMULIYA +11004 ; [.2DA5.0020.0002] # BRAHMI SIGN UPADHMANIYA +11034 ; [.2DA6.0020.0002] # BRAHMI LETTER LLA +11035 ; [.2DA7.0020.0002] # BRAHMI LETTER OLD TAMIL LLLA +11036 ; [.2DA8.0020.0002] # BRAHMI LETTER OLD TAMIL RRA +11037 ; [.2DA9.0020.0002] # BRAHMI LETTER OLD TAMIL NNNA +11038 ; [.2DAA.0020.0002] # BRAHMI VOWEL SIGN AA +11039 ; [.2DAB.0020.0002] # BRAHMI VOWEL SIGN BHATTIPROLU AA +1103A ; [.2DAC.0020.0002] # BRAHMI VOWEL SIGN I +1103B ; [.2DAD.0020.0002] # BRAHMI VOWEL SIGN II +1103C ; [.2DAE.0020.0002] # BRAHMI VOWEL SIGN U +1103D ; [.2DAF.0020.0002] # BRAHMI VOWEL SIGN UU +1103E ; [.2DB0.0020.0002] # BRAHMI VOWEL SIGN VOCALIC R +1103F ; [.2DB1.0020.0002] # BRAHMI VOWEL SIGN VOCALIC RR +11040 ; [.2DB2.0020.0002] # BRAHMI VOWEL SIGN VOCALIC L +11041 ; [.2DB3.0020.0002] # BRAHMI VOWEL SIGN VOCALIC LL +11042 ; [.2DB4.0020.0002] # BRAHMI VOWEL SIGN E +11043 ; [.2DB5.0020.0002] # BRAHMI VOWEL SIGN AI +11044 ; [.2DB6.0020.0002] # BRAHMI VOWEL SIGN O +11045 ; [.2DB7.0020.0002] # BRAHMI VOWEL SIGN AU +11046 ; [.2DB8.0020.0002] # BRAHMI VIRAMA +1107F ; [.2DB9.0020.0002] # BRAHMI NUMBER JOINER +10A00 ; [.2DBA.0020.0002] # KHAROSHTHI LETTER A +10A01 ; [.2DBB.0020.0002] # KHAROSHTHI VOWEL SIGN I +10A02 ; [.2DBC.0020.0002] # KHAROSHTHI VOWEL SIGN U +10A03 ; [.2DBD.0020.0002] # KHAROSHTHI VOWEL SIGN VOCALIC R +10A05 ; [.2DBE.0020.0002] # KHAROSHTHI VOWEL SIGN E +10A06 ; [.2DBF.0020.0002] # KHAROSHTHI VOWEL SIGN O +10A0C ; [.2DC0.0020.0002] # KHAROSHTHI VOWEL LENGTH MARK +10A10 ; [.2DC1.0020.0002] # KHAROSHTHI LETTER KA +10A11 ; [.2DC2.0020.0002] # KHAROSHTHI LETTER KHA +10A12 ; [.2DC3.0020.0002] # KHAROSHTHI LETTER GA +10A13 ; [.2DC4.0020.0002] # KHAROSHTHI LETTER GHA +10A15 ; [.2DC5.0020.0002] # KHAROSHTHI LETTER CA +10A16 ; [.2DC6.0020.0002] # KHAROSHTHI LETTER CHA +10A17 ; [.2DC7.0020.0002] # KHAROSHTHI LETTER JA +10A19 ; [.2DC8.0020.0002] # KHAROSHTHI LETTER NYA +10A1A ; [.2DC9.0020.0002] # KHAROSHTHI LETTER TTA +10A1B ; [.2DCA.0020.0002] # KHAROSHTHI LETTER TTHA +10A1C ; [.2DCB.0020.0002] # KHAROSHTHI LETTER DDA +10A1D ; [.2DCC.0020.0002] # KHAROSHTHI LETTER DDHA +10A1E ; [.2DCD.0020.0002] # KHAROSHTHI LETTER NNA +10A1F ; [.2DCE.0020.0002] # KHAROSHTHI LETTER TA +10A20 ; [.2DCF.0020.0002] # KHAROSHTHI LETTER THA +10A21 ; [.2DD0.0020.0002] # KHAROSHTHI LETTER DA +10A22 ; [.2DD1.0020.0002] # KHAROSHTHI LETTER DHA +10A23 ; [.2DD2.0020.0002] # KHAROSHTHI LETTER NA +10A24 ; [.2DD3.0020.0002] # KHAROSHTHI LETTER PA +10A25 ; [.2DD4.0020.0002] # KHAROSHTHI LETTER PHA +10A26 ; [.2DD5.0020.0002] # KHAROSHTHI LETTER BA +10A27 ; [.2DD6.0020.0002] # KHAROSHTHI LETTER BHA +10A28 ; [.2DD7.0020.0002] # KHAROSHTHI LETTER MA +10A29 ; [.2DD8.0020.0002] # KHAROSHTHI LETTER YA +10A2A ; [.2DD9.0020.0002] # KHAROSHTHI LETTER RA +10A2B ; [.2DDA.0020.0002] # KHAROSHTHI LETTER LA +10A2C ; [.2DDB.0020.0002] # KHAROSHTHI LETTER VA +10A2D ; [.2DDC.0020.0002] # KHAROSHTHI LETTER SHA +10A2E ; [.2DDD.0020.0002] # KHAROSHTHI LETTER SSA +10A2F ; [.2DDE.0020.0002] # KHAROSHTHI LETTER SA +10A30 ; [.2DDF.0020.0002] # KHAROSHTHI LETTER ZA +10A31 ; [.2DE0.0020.0002] # KHAROSHTHI LETTER HA +10A32 ; [.2DE1.0020.0002] # KHAROSHTHI LETTER KKA +10A33 ; [.2DE2.0020.0002] # KHAROSHTHI LETTER TTTHA +10A3F ; [.2DE3.0020.0002] # KHAROSHTHI VIRAMA +11C00 ; [.2DE4.0020.0002] # BHAIKSUKI LETTER A +11C01 ; [.2DE5.0020.0002] # BHAIKSUKI LETTER AA +11C02 ; [.2DE6.0020.0002] # BHAIKSUKI LETTER I +11C03 ; [.2DE7.0020.0002] # BHAIKSUKI LETTER II +11C04 ; [.2DE8.0020.0002] # BHAIKSUKI LETTER U +11C05 ; [.2DE9.0020.0002] # BHAIKSUKI LETTER UU +11C06 ; [.2DEA.0020.0002] # BHAIKSUKI LETTER VOCALIC R +11C07 ; [.2DEB.0020.0002] # BHAIKSUKI LETTER VOCALIC RR +11C08 ; [.2DEC.0020.0002] # BHAIKSUKI LETTER VOCALIC L +11C0A ; [.2DED.0020.0002] # BHAIKSUKI LETTER E +11C0B ; [.2DEE.0020.0002] # BHAIKSUKI LETTER AI +11C0C ; [.2DEF.0020.0002] # BHAIKSUKI LETTER O +11C0D ; [.2DF0.0020.0002] # BHAIKSUKI LETTER AU +11C0E ; [.2DF1.0020.0002] # BHAIKSUKI LETTER KA +11C0F ; [.2DF2.0020.0002] # BHAIKSUKI LETTER KHA +11C10 ; [.2DF3.0020.0002] # BHAIKSUKI LETTER GA +11C11 ; [.2DF4.0020.0002] # BHAIKSUKI LETTER GHA +11C12 ; [.2DF5.0020.0002] # BHAIKSUKI LETTER NGA +11C13 ; [.2DF6.0020.0002] # BHAIKSUKI LETTER CA +11C14 ; [.2DF7.0020.0002] # BHAIKSUKI LETTER CHA +11C15 ; [.2DF8.0020.0002] # BHAIKSUKI LETTER JA +11C16 ; [.2DF9.0020.0002] # BHAIKSUKI LETTER JHA +11C17 ; [.2DFA.0020.0002] # BHAIKSUKI LETTER NYA +11C18 ; [.2DFB.0020.0002] # BHAIKSUKI LETTER TTA +11C19 ; [.2DFC.0020.0002] # BHAIKSUKI LETTER TTHA +11C1A ; [.2DFD.0020.0002] # BHAIKSUKI LETTER DDA +11C1B ; [.2DFE.0020.0002] # BHAIKSUKI LETTER DDHA +11C1C ; [.2DFF.0020.0002] # BHAIKSUKI LETTER NNA +11C1D ; [.2E00.0020.0002] # BHAIKSUKI LETTER TA +11C1E ; [.2E01.0020.0002] # BHAIKSUKI LETTER THA +11C1F ; [.2E02.0020.0002] # BHAIKSUKI LETTER DA +11C20 ; [.2E03.0020.0002] # BHAIKSUKI LETTER DHA +11C21 ; [.2E04.0020.0002] # BHAIKSUKI LETTER NA +11C22 ; [.2E05.0020.0002] # BHAIKSUKI LETTER PA +11C23 ; [.2E06.0020.0002] # BHAIKSUKI LETTER PHA +11C24 ; [.2E07.0020.0002] # BHAIKSUKI LETTER BA +11C25 ; [.2E08.0020.0002] # BHAIKSUKI LETTER BHA +11C26 ; [.2E09.0020.0002] # BHAIKSUKI LETTER MA +11C27 ; [.2E0A.0020.0002] # BHAIKSUKI LETTER YA +11C28 ; [.2E0B.0020.0002] # BHAIKSUKI LETTER RA +11C29 ; [.2E0C.0020.0002] # BHAIKSUKI LETTER LA +11C2A ; [.2E0D.0020.0002] # BHAIKSUKI LETTER VA +11C2B ; [.2E0E.0020.0002] # BHAIKSUKI LETTER SHA +11C2C ; [.2E0F.0020.0002] # BHAIKSUKI LETTER SSA +11C2D ; [.2E10.0020.0002] # BHAIKSUKI LETTER SA +11C2E ; [.2E11.0020.0002] # BHAIKSUKI LETTER HA +11C40 ; [.2E12.0020.0002] # BHAIKSUKI SIGN AVAGRAHA +11C2F ; [.2E13.0020.0002] # BHAIKSUKI VOWEL SIGN AA +11C30 ; [.2E14.0020.0002] # BHAIKSUKI VOWEL SIGN I +11C31 ; [.2E15.0020.0002] # BHAIKSUKI VOWEL SIGN II +11C32 ; [.2E16.0020.0002] # BHAIKSUKI VOWEL SIGN U +11C33 ; [.2E17.0020.0002] # BHAIKSUKI VOWEL SIGN UU +11C34 ; [.2E18.0020.0002] # BHAIKSUKI VOWEL SIGN VOCALIC R +11C35 ; [.2E19.0020.0002] # BHAIKSUKI VOWEL SIGN VOCALIC RR +11C36 ; [.2E1A.0020.0002] # BHAIKSUKI VOWEL SIGN VOCALIC L +11C38 ; [.2E1B.0020.0002] # BHAIKSUKI VOWEL SIGN E +11C39 ; [.2E1C.0020.0002] # BHAIKSUKI VOWEL SIGN AI +11C3A ; [.2E1D.0020.0002] # BHAIKSUKI VOWEL SIGN O +11C3B ; [.2E1E.0020.0002] # BHAIKSUKI VOWEL SIGN AU +11C3F ; [.2E1F.0020.0002] # BHAIKSUKI SIGN VIRAMA +0E01 ; [.2E20.0020.0002] # THAI CHARACTER KO KAI +0E40 0E01 ; [.2E20.0020.0002][.2E5A.0020.0002] # <THAI CHARACTER SARA E, THAI CHARACTER KO KAI> +0E41 0E01 ; [.2E20.0020.0002][.2E5B.0020.0002] # <THAI CHARACTER SARA AE, THAI CHARACTER KO KAI> +0E42 0E01 ; [.2E20.0020.0002][.2E5C.0020.0002] # <THAI CHARACTER SARA O, THAI CHARACTER KO KAI> +0E43 0E01 ; [.2E20.0020.0002][.2E5D.0020.0002] # <THAI CHARACTER SARA AI MAIMUAN, THAI CHARACTER KO KAI> +0E44 0E01 ; [.2E20.0020.0002][.2E5E.0020.0002] # <THAI CHARACTER SARA AI MAIMALAI, THAI CHARACTER KO KAI> +0E02 ; [.2E21.0020.0002] # THAI CHARACTER KHO KHAI +0E40 0E02 ; [.2E21.0020.0002][.2E5A.0020.0002] # <THAI CHARACTER SARA E, THAI CHARACTER KHO KHAI> +0E41 0E02 ; [.2E21.0020.0002][.2E5B.0020.0002] # <THAI CHARACTER SARA AE, THAI CHARACTER KHO KHAI> +0E42 0E02 ; [.2E21.0020.0002][.2E5C.0020.0002] # <THAI CHARACTER SARA O, THAI CHARACTER KHO KHAI> +0E43 0E02 ; [.2E21.0020.0002][.2E5D.0020.0002] # <THAI CHARACTER SARA AI MAIMUAN, THAI CHARACTER KHO KHAI> +0E44 0E02 ; [.2E21.0020.0002][.2E5E.0020.0002] # <THAI CHARACTER SARA AI MAIMALAI, THAI CHARACTER KHO KHAI> +0E03 ; [.2E22.0020.0002] # THAI CHARACTER KHO KHUAT +0E40 0E03 ; [.2E22.0020.0002][.2E5A.0020.0002] # <THAI CHARACTER SARA E, THAI CHARACTER KHO KHUAT> +0E41 0E03 ; [.2E22.0020.0002][.2E5B.0020.0002] # <THAI CHARACTER SARA AE, THAI CHARACTER KHO KHUAT> +0E42 0E03 ; [.2E22.0020.0002][.2E5C.0020.0002] # <THAI CHARACTER SARA O, THAI CHARACTER KHO KHUAT> +0E43 0E03 ; [.2E22.0020.0002][.2E5D.0020.0002] # <THAI CHARACTER SARA AI MAIMUAN, THAI CHARACTER KHO KHUAT> +0E44 0E03 ; [.2E22.0020.0002][.2E5E.0020.0002] # <THAI CHARACTER SARA AI MAIMALAI, THAI CHARACTER KHO KHUAT> +0E04 ; [.2E23.0020.0002] # THAI CHARACTER KHO KHWAI +0E40 0E04 ; [.2E23.0020.0002][.2E5A.0020.0002] # <THAI CHARACTER SARA E, THAI CHARACTER KHO KHWAI> +0E41 0E04 ; [.2E23.0020.0002][.2E5B.0020.0002] # <THAI CHARACTER SARA AE, THAI CHARACTER KHO KHWAI> +0E42 0E04 ; [.2E23.0020.0002][.2E5C.0020.0002] # <THAI CHARACTER SARA O, THAI CHARACTER KHO KHWAI> +0E43 0E04 ; [.2E23.0020.0002][.2E5D.0020.0002] # <THAI CHARACTER SARA AI MAIMUAN, THAI CHARACTER KHO KHWAI> +0E44 0E04 ; [.2E23.0020.0002][.2E5E.0020.0002] # <THAI CHARACTER SARA AI MAIMALAI, THAI CHARACTER KHO KHWAI> +0E05 ; [.2E24.0020.0002] # THAI CHARACTER KHO KHON +0E40 0E05 ; [.2E24.0020.0002][.2E5A.0020.0002] # <THAI CHARACTER SARA E, THAI CHARACTER KHO KHON> +0E41 0E05 ; [.2E24.0020.0002][.2E5B.0020.0002] # <THAI CHARACTER SARA AE, THAI CHARACTER KHO KHON> +0E42 0E05 ; [.2E24.0020.0002][.2E5C.0020.0002] # <THAI CHARACTER SARA O, THAI CHARACTER KHO KHON> +0E43 0E05 ; [.2E24.0020.0002][.2E5D.0020.0002] # <THAI CHARACTER SARA AI MAIMUAN, THAI CHARACTER KHO KHON> +0E44 0E05 ; [.2E24.0020.0002][.2E5E.0020.0002] # <THAI CHARACTER SARA AI MAIMALAI, THAI CHARACTER KHO KHON> +0E06 ; [.2E25.0020.0002] # THAI CHARACTER KHO RAKHANG +0E40 0E06 ; [.2E25.0020.0002][.2E5A.0020.0002] # <THAI CHARACTER SARA E, THAI CHARACTER KHO RAKHANG> +0E41 0E06 ; [.2E25.0020.0002][.2E5B.0020.0002] # <THAI CHARACTER SARA AE, THAI CHARACTER KHO RAKHANG> +0E42 0E06 ; [.2E25.0020.0002][.2E5C.0020.0002] # <THAI CHARACTER SARA O, THAI CHARACTER KHO RAKHANG> +0E43 0E06 ; [.2E25.0020.0002][.2E5D.0020.0002] # <THAI CHARACTER SARA AI MAIMUAN, THAI CHARACTER KHO RAKHANG> +0E44 0E06 ; [.2E25.0020.0002][.2E5E.0020.0002] # <THAI CHARACTER SARA AI MAIMALAI, THAI CHARACTER KHO RAKHANG> +0E07 ; [.2E26.0020.0002] # THAI CHARACTER NGO NGU +0E40 0E07 ; [.2E26.0020.0002][.2E5A.0020.0002] # <THAI CHARACTER SARA E, THAI CHARACTER NGO NGU> +0E41 0E07 ; [.2E26.0020.0002][.2E5B.0020.0002] # <THAI CHARACTER SARA AE, THAI CHARACTER NGO NGU> +0E42 0E07 ; [.2E26.0020.0002][.2E5C.0020.0002] # <THAI CHARACTER SARA O, THAI CHARACTER NGO NGU> +0E43 0E07 ; [.2E26.0020.0002][.2E5D.0020.0002] # <THAI CHARACTER SARA AI MAIMUAN, THAI CHARACTER NGO NGU> +0E44 0E07 ; [.2E26.0020.0002][.2E5E.0020.0002] # <THAI CHARACTER SARA AI MAIMALAI, THAI CHARACTER NGO NGU> +0E08 ; [.2E27.0020.0002] # THAI CHARACTER CHO CHAN +0E40 0E08 ; [.2E27.0020.0002][.2E5A.0020.0002] # <THAI CHARACTER SARA E, THAI CHARACTER CHO CHAN> +0E41 0E08 ; [.2E27.0020.0002][.2E5B.0020.0002] # <THAI CHARACTER SARA AE, THAI CHARACTER CHO CHAN> +0E42 0E08 ; [.2E27.0020.0002][.2E5C.0020.0002] # <THAI CHARACTER SARA O, THAI CHARACTER CHO CHAN> +0E43 0E08 ; [.2E27.0020.0002][.2E5D.0020.0002] # <THAI CHARACTER SARA AI MAIMUAN, THAI CHARACTER CHO CHAN> +0E44 0E08 ; [.2E27.0020.0002][.2E5E.0020.0002] # <THAI CHARACTER SARA AI MAIMALAI, THAI CHARACTER CHO CHAN> +0E09 ; [.2E28.0020.0002] # THAI CHARACTER CHO CHING +0E40 0E09 ; [.2E28.0020.0002][.2E5A.0020.0002] # <THAI CHARACTER SARA E, THAI CHARACTER CHO CHING> +0E41 0E09 ; [.2E28.0020.0002][.2E5B.0020.0002] # <THAI CHARACTER SARA AE, THAI CHARACTER CHO CHING> +0E42 0E09 ; [.2E28.0020.0002][.2E5C.0020.0002] # <THAI CHARACTER SARA O, THAI CHARACTER CHO CHING> +0E43 0E09 ; [.2E28.0020.0002][.2E5D.0020.0002] # <THAI CHARACTER SARA AI MAIMUAN, THAI CHARACTER CHO CHING> +0E44 0E09 ; [.2E28.0020.0002][.2E5E.0020.0002] # <THAI CHARACTER SARA AI MAIMALAI, THAI CHARACTER CHO CHING> +0E0A ; [.2E29.0020.0002] # THAI CHARACTER CHO CHANG +0E40 0E0A ; [.2E29.0020.0002][.2E5A.0020.0002] # <THAI CHARACTER SARA E, THAI CHARACTER CHO CHANG> +0E41 0E0A ; [.2E29.0020.0002][.2E5B.0020.0002] # <THAI CHARACTER SARA AE, THAI CHARACTER CHO CHANG> +0E42 0E0A ; [.2E29.0020.0002][.2E5C.0020.0002] # <THAI CHARACTER SARA O, THAI CHARACTER CHO CHANG> +0E43 0E0A ; [.2E29.0020.0002][.2E5D.0020.0002] # <THAI CHARACTER SARA AI MAIMUAN, THAI CHARACTER CHO CHANG> +0E44 0E0A ; [.2E29.0020.0002][.2E5E.0020.0002] # <THAI CHARACTER SARA AI MAIMALAI, THAI CHARACTER CHO CHANG> +0E0B ; [.2E2A.0020.0002] # THAI CHARACTER SO SO +0E40 0E0B ; [.2E2A.0020.0002][.2E5A.0020.0002] # <THAI CHARACTER SARA E, THAI CHARACTER SO SO> +0E41 0E0B ; [.2E2A.0020.0002][.2E5B.0020.0002] # <THAI CHARACTER SARA AE, THAI CHARACTER SO SO> +0E42 0E0B ; [.2E2A.0020.0002][.2E5C.0020.0002] # <THAI CHARACTER SARA O, THAI CHARACTER SO SO> +0E43 0E0B ; [.2E2A.0020.0002][.2E5D.0020.0002] # <THAI CHARACTER SARA AI MAIMUAN, THAI CHARACTER SO SO> +0E44 0E0B ; [.2E2A.0020.0002][.2E5E.0020.0002] # <THAI CHARACTER SARA AI MAIMALAI, THAI CHARACTER SO SO> +0E0C ; [.2E2B.0020.0002] # THAI CHARACTER CHO CHOE +0E40 0E0C ; [.2E2B.0020.0002][.2E5A.0020.0002] # <THAI CHARACTER SARA E, THAI CHARACTER CHO CHOE> +0E41 0E0C ; [.2E2B.0020.0002][.2E5B.0020.0002] # <THAI CHARACTER SARA AE, THAI CHARACTER CHO CHOE> +0E42 0E0C ; [.2E2B.0020.0002][.2E5C.0020.0002] # <THAI CHARACTER SARA O, THAI CHARACTER CHO CHOE> +0E43 0E0C ; [.2E2B.0020.0002][.2E5D.0020.0002] # <THAI CHARACTER SARA AI MAIMUAN, THAI CHARACTER CHO CHOE> +0E44 0E0C ; [.2E2B.0020.0002][.2E5E.0020.0002] # <THAI CHARACTER SARA AI MAIMALAI, THAI CHARACTER CHO CHOE> +0E0D ; [.2E2C.0020.0002] # THAI CHARACTER YO YING +0E40 0E0D ; [.2E2C.0020.0002][.2E5A.0020.0002] # <THAI CHARACTER SARA E, THAI CHARACTER YO YING> +0E41 0E0D ; [.2E2C.0020.0002][.2E5B.0020.0002] # <THAI CHARACTER SARA AE, THAI CHARACTER YO YING> +0E42 0E0D ; [.2E2C.0020.0002][.2E5C.0020.0002] # <THAI CHARACTER SARA O, THAI CHARACTER YO YING> +0E43 0E0D ; [.2E2C.0020.0002][.2E5D.0020.0002] # <THAI CHARACTER SARA AI MAIMUAN, THAI CHARACTER YO YING> +0E44 0E0D ; [.2E2C.0020.0002][.2E5E.0020.0002] # <THAI CHARACTER SARA AI MAIMALAI, THAI CHARACTER YO YING> +0E0E ; [.2E2D.0020.0002] # THAI CHARACTER DO CHADA +0E40 0E0E ; [.2E2D.0020.0002][.2E5A.0020.0002] # <THAI CHARACTER SARA E, THAI CHARACTER DO CHADA> +0E41 0E0E ; [.2E2D.0020.0002][.2E5B.0020.0002] # <THAI CHARACTER SARA AE, THAI CHARACTER DO CHADA> +0E42 0E0E ; [.2E2D.0020.0002][.2E5C.0020.0002] # <THAI CHARACTER SARA O, THAI CHARACTER DO CHADA> +0E43 0E0E ; [.2E2D.0020.0002][.2E5D.0020.0002] # <THAI CHARACTER SARA AI MAIMUAN, THAI CHARACTER DO CHADA> +0E44 0E0E ; [.2E2D.0020.0002][.2E5E.0020.0002] # <THAI CHARACTER SARA AI MAIMALAI, THAI CHARACTER DO CHADA> +0E0F ; [.2E2E.0020.0002] # THAI CHARACTER TO PATAK +0E40 0E0F ; [.2E2E.0020.0002][.2E5A.0020.0002] # <THAI CHARACTER SARA E, THAI CHARACTER TO PATAK> +0E41 0E0F ; [.2E2E.0020.0002][.2E5B.0020.0002] # <THAI CHARACTER SARA AE, THAI CHARACTER TO PATAK> +0E42 0E0F ; [.2E2E.0020.0002][.2E5C.0020.0002] # <THAI CHARACTER SARA O, THAI CHARACTER TO PATAK> +0E43 0E0F ; [.2E2E.0020.0002][.2E5D.0020.0002] # <THAI CHARACTER SARA AI MAIMUAN, THAI CHARACTER TO PATAK> +0E44 0E0F ; [.2E2E.0020.0002][.2E5E.0020.0002] # <THAI CHARACTER SARA AI MAIMALAI, THAI CHARACTER TO PATAK> +0E10 ; [.2E2F.0020.0002] # THAI CHARACTER THO THAN +0E40 0E10 ; [.2E2F.0020.0002][.2E5A.0020.0002] # <THAI CHARACTER SARA E, THAI CHARACTER THO THAN> +0E41 0E10 ; [.2E2F.0020.0002][.2E5B.0020.0002] # <THAI CHARACTER SARA AE, THAI CHARACTER THO THAN> +0E42 0E10 ; [.2E2F.0020.0002][.2E5C.0020.0002] # <THAI CHARACTER SARA O, THAI CHARACTER THO THAN> +0E43 0E10 ; [.2E2F.0020.0002][.2E5D.0020.0002] # <THAI CHARACTER SARA AI MAIMUAN, THAI CHARACTER THO THAN> +0E44 0E10 ; [.2E2F.0020.0002][.2E5E.0020.0002] # <THAI CHARACTER SARA AI MAIMALAI, THAI CHARACTER THO THAN> +0E11 ; [.2E30.0020.0002] # THAI CHARACTER THO NANGMONTHO +0E40 0E11 ; [.2E30.0020.0002][.2E5A.0020.0002] # <THAI CHARACTER SARA E, THAI CHARACTER THO NANGMONTHO> +0E41 0E11 ; [.2E30.0020.0002][.2E5B.0020.0002] # <THAI CHARACTER SARA AE, THAI CHARACTER THO NANGMONTHO> +0E42 0E11 ; [.2E30.0020.0002][.2E5C.0020.0002] # <THAI CHARACTER SARA O, THAI CHARACTER THO NANGMONTHO> +0E43 0E11 ; [.2E30.0020.0002][.2E5D.0020.0002] # <THAI CHARACTER SARA AI MAIMUAN, THAI CHARACTER THO NANGMONTHO> +0E44 0E11 ; [.2E30.0020.0002][.2E5E.0020.0002] # <THAI CHARACTER SARA AI MAIMALAI, THAI CHARACTER THO NANGMONTHO> +0E12 ; [.2E31.0020.0002] # THAI CHARACTER THO PHUTHAO +0E40 0E12 ; [.2E31.0020.0002][.2E5A.0020.0002] # <THAI CHARACTER SARA E, THAI CHARACTER THO PHUTHAO> +0E41 0E12 ; [.2E31.0020.0002][.2E5B.0020.0002] # <THAI CHARACTER SARA AE, THAI CHARACTER THO PHUTHAO> +0E42 0E12 ; [.2E31.0020.0002][.2E5C.0020.0002] # <THAI CHARACTER SARA O, THAI CHARACTER THO PHUTHAO> +0E43 0E12 ; [.2E31.0020.0002][.2E5D.0020.0002] # <THAI CHARACTER SARA AI MAIMUAN, THAI CHARACTER THO PHUTHAO> +0E44 0E12 ; [.2E31.0020.0002][.2E5E.0020.0002] # <THAI CHARACTER SARA AI MAIMALAI, THAI CHARACTER THO PHUTHAO> +0E13 ; [.2E32.0020.0002] # THAI CHARACTER NO NEN +0E40 0E13 ; [.2E32.0020.0002][.2E5A.0020.0002] # <THAI CHARACTER SARA E, THAI CHARACTER NO NEN> +0E41 0E13 ; [.2E32.0020.0002][.2E5B.0020.0002] # <THAI CHARACTER SARA AE, THAI CHARACTER NO NEN> +0E42 0E13 ; [.2E32.0020.0002][.2E5C.0020.0002] # <THAI CHARACTER SARA O, THAI CHARACTER NO NEN> +0E43 0E13 ; [.2E32.0020.0002][.2E5D.0020.0002] # <THAI CHARACTER SARA AI MAIMUAN, THAI CHARACTER NO NEN> +0E44 0E13 ; [.2E32.0020.0002][.2E5E.0020.0002] # <THAI CHARACTER SARA AI MAIMALAI, THAI CHARACTER NO NEN> +0E14 ; [.2E33.0020.0002] # THAI CHARACTER DO DEK +0E40 0E14 ; [.2E33.0020.0002][.2E5A.0020.0002] # <THAI CHARACTER SARA E, THAI CHARACTER DO DEK> +0E41 0E14 ; [.2E33.0020.0002][.2E5B.0020.0002] # <THAI CHARACTER SARA AE, THAI CHARACTER DO DEK> +0E42 0E14 ; [.2E33.0020.0002][.2E5C.0020.0002] # <THAI CHARACTER SARA O, THAI CHARACTER DO DEK> +0E43 0E14 ; [.2E33.0020.0002][.2E5D.0020.0002] # <THAI CHARACTER SARA AI MAIMUAN, THAI CHARACTER DO DEK> +0E44 0E14 ; [.2E33.0020.0002][.2E5E.0020.0002] # <THAI CHARACTER SARA AI MAIMALAI, THAI CHARACTER DO DEK> +0E15 ; [.2E34.0020.0002] # THAI CHARACTER TO TAO +0E40 0E15 ; [.2E34.0020.0002][.2E5A.0020.0002] # <THAI CHARACTER SARA E, THAI CHARACTER TO TAO> +0E41 0E15 ; [.2E34.0020.0002][.2E5B.0020.0002] # <THAI CHARACTER SARA AE, THAI CHARACTER TO TAO> +0E42 0E15 ; [.2E34.0020.0002][.2E5C.0020.0002] # <THAI CHARACTER SARA O, THAI CHARACTER TO TAO> +0E43 0E15 ; [.2E34.0020.0002][.2E5D.0020.0002] # <THAI CHARACTER SARA AI MAIMUAN, THAI CHARACTER TO TAO> +0E44 0E15 ; [.2E34.0020.0002][.2E5E.0020.0002] # <THAI CHARACTER SARA AI MAIMALAI, THAI CHARACTER TO TAO> +0E16 ; [.2E35.0020.0002] # THAI CHARACTER THO THUNG +0E40 0E16 ; [.2E35.0020.0002][.2E5A.0020.0002] # <THAI CHARACTER SARA E, THAI CHARACTER THO THUNG> +0E41 0E16 ; [.2E35.0020.0002][.2E5B.0020.0002] # <THAI CHARACTER SARA AE, THAI CHARACTER THO THUNG> +0E42 0E16 ; [.2E35.0020.0002][.2E5C.0020.0002] # <THAI CHARACTER SARA O, THAI CHARACTER THO THUNG> +0E43 0E16 ; [.2E35.0020.0002][.2E5D.0020.0002] # <THAI CHARACTER SARA AI MAIMUAN, THAI CHARACTER THO THUNG> +0E44 0E16 ; [.2E35.0020.0002][.2E5E.0020.0002] # <THAI CHARACTER SARA AI MAIMALAI, THAI CHARACTER THO THUNG> +0E17 ; [.2E36.0020.0002] # THAI CHARACTER THO THAHAN +0E40 0E17 ; [.2E36.0020.0002][.2E5A.0020.0002] # <THAI CHARACTER SARA E, THAI CHARACTER THO THAHAN> +0E41 0E17 ; [.2E36.0020.0002][.2E5B.0020.0002] # <THAI CHARACTER SARA AE, THAI CHARACTER THO THAHAN> +0E42 0E17 ; [.2E36.0020.0002][.2E5C.0020.0002] # <THAI CHARACTER SARA O, THAI CHARACTER THO THAHAN> +0E43 0E17 ; [.2E36.0020.0002][.2E5D.0020.0002] # <THAI CHARACTER SARA AI MAIMUAN, THAI CHARACTER THO THAHAN> +0E44 0E17 ; [.2E36.0020.0002][.2E5E.0020.0002] # <THAI CHARACTER SARA AI MAIMALAI, THAI CHARACTER THO THAHAN> +0E18 ; [.2E37.0020.0002] # THAI CHARACTER THO THONG +0E40 0E18 ; [.2E37.0020.0002][.2E5A.0020.0002] # <THAI CHARACTER SARA E, THAI CHARACTER THO THONG> +0E41 0E18 ; [.2E37.0020.0002][.2E5B.0020.0002] # <THAI CHARACTER SARA AE, THAI CHARACTER THO THONG> +0E42 0E18 ; [.2E37.0020.0002][.2E5C.0020.0002] # <THAI CHARACTER SARA O, THAI CHARACTER THO THONG> +0E43 0E18 ; [.2E37.0020.0002][.2E5D.0020.0002] # <THAI CHARACTER SARA AI MAIMUAN, THAI CHARACTER THO THONG> +0E44 0E18 ; [.2E37.0020.0002][.2E5E.0020.0002] # <THAI CHARACTER SARA AI MAIMALAI, THAI CHARACTER THO THONG> +0E19 ; [.2E38.0020.0002] # THAI CHARACTER NO NU +0E40 0E19 ; [.2E38.0020.0002][.2E5A.0020.0002] # <THAI CHARACTER SARA E, THAI CHARACTER NO NU> +0E41 0E19 ; [.2E38.0020.0002][.2E5B.0020.0002] # <THAI CHARACTER SARA AE, THAI CHARACTER NO NU> +0E42 0E19 ; [.2E38.0020.0002][.2E5C.0020.0002] # <THAI CHARACTER SARA O, THAI CHARACTER NO NU> +0E43 0E19 ; [.2E38.0020.0002][.2E5D.0020.0002] # <THAI CHARACTER SARA AI MAIMUAN, THAI CHARACTER NO NU> +0E44 0E19 ; [.2E38.0020.0002][.2E5E.0020.0002] # <THAI CHARACTER SARA AI MAIMALAI, THAI CHARACTER NO NU> +0E1A ; [.2E39.0020.0002] # THAI CHARACTER BO BAIMAI +0E40 0E1A ; [.2E39.0020.0002][.2E5A.0020.0002] # <THAI CHARACTER SARA E, THAI CHARACTER BO BAIMAI> +0E41 0E1A ; [.2E39.0020.0002][.2E5B.0020.0002] # <THAI CHARACTER SARA AE, THAI CHARACTER BO BAIMAI> +0E42 0E1A ; [.2E39.0020.0002][.2E5C.0020.0002] # <THAI CHARACTER SARA O, THAI CHARACTER BO BAIMAI> +0E43 0E1A ; [.2E39.0020.0002][.2E5D.0020.0002] # <THAI CHARACTER SARA AI MAIMUAN, THAI CHARACTER BO BAIMAI> +0E44 0E1A ; [.2E39.0020.0002][.2E5E.0020.0002] # <THAI CHARACTER SARA AI MAIMALAI, THAI CHARACTER BO BAIMAI> +0E1B ; [.2E3A.0020.0002] # THAI CHARACTER PO PLA +0E40 0E1B ; [.2E3A.0020.0002][.2E5A.0020.0002] # <THAI CHARACTER SARA E, THAI CHARACTER PO PLA> +0E41 0E1B ; [.2E3A.0020.0002][.2E5B.0020.0002] # <THAI CHARACTER SARA AE, THAI CHARACTER PO PLA> +0E42 0E1B ; [.2E3A.0020.0002][.2E5C.0020.0002] # <THAI CHARACTER SARA O, THAI CHARACTER PO PLA> +0E43 0E1B ; [.2E3A.0020.0002][.2E5D.0020.0002] # <THAI CHARACTER SARA AI MAIMUAN, THAI CHARACTER PO PLA> +0E44 0E1B ; [.2E3A.0020.0002][.2E5E.0020.0002] # <THAI CHARACTER SARA AI MAIMALAI, THAI CHARACTER PO PLA> +0E1C ; [.2E3B.0020.0002] # THAI CHARACTER PHO PHUNG +0E40 0E1C ; [.2E3B.0020.0002][.2E5A.0020.0002] # <THAI CHARACTER SARA E, THAI CHARACTER PHO PHUNG> +0E41 0E1C ; [.2E3B.0020.0002][.2E5B.0020.0002] # <THAI CHARACTER SARA AE, THAI CHARACTER PHO PHUNG> +0E42 0E1C ; [.2E3B.0020.0002][.2E5C.0020.0002] # <THAI CHARACTER SARA O, THAI CHARACTER PHO PHUNG> +0E43 0E1C ; [.2E3B.0020.0002][.2E5D.0020.0002] # <THAI CHARACTER SARA AI MAIMUAN, THAI CHARACTER PHO PHUNG> +0E44 0E1C ; [.2E3B.0020.0002][.2E5E.0020.0002] # <THAI CHARACTER SARA AI MAIMALAI, THAI CHARACTER PHO PHUNG> +0E1D ; [.2E3C.0020.0002] # THAI CHARACTER FO FA +0E40 0E1D ; [.2E3C.0020.0002][.2E5A.0020.0002] # <THAI CHARACTER SARA E, THAI CHARACTER FO FA> +0E41 0E1D ; [.2E3C.0020.0002][.2E5B.0020.0002] # <THAI CHARACTER SARA AE, THAI CHARACTER FO FA> +0E42 0E1D ; [.2E3C.0020.0002][.2E5C.0020.0002] # <THAI CHARACTER SARA O, THAI CHARACTER FO FA> +0E43 0E1D ; [.2E3C.0020.0002][.2E5D.0020.0002] # <THAI CHARACTER SARA AI MAIMUAN, THAI CHARACTER FO FA> +0E44 0E1D ; [.2E3C.0020.0002][.2E5E.0020.0002] # <THAI CHARACTER SARA AI MAIMALAI, THAI CHARACTER FO FA> +0E1E ; [.2E3D.0020.0002] # THAI CHARACTER PHO PHAN +0E40 0E1E ; [.2E3D.0020.0002][.2E5A.0020.0002] # <THAI CHARACTER SARA E, THAI CHARACTER PHO PHAN> +0E41 0E1E ; [.2E3D.0020.0002][.2E5B.0020.0002] # <THAI CHARACTER SARA AE, THAI CHARACTER PHO PHAN> +0E42 0E1E ; [.2E3D.0020.0002][.2E5C.0020.0002] # <THAI CHARACTER SARA O, THAI CHARACTER PHO PHAN> +0E43 0E1E ; [.2E3D.0020.0002][.2E5D.0020.0002] # <THAI CHARACTER SARA AI MAIMUAN, THAI CHARACTER PHO PHAN> +0E44 0E1E ; [.2E3D.0020.0002][.2E5E.0020.0002] # <THAI CHARACTER SARA AI MAIMALAI, THAI CHARACTER PHO PHAN> +0E1F ; [.2E3E.0020.0002] # THAI CHARACTER FO FAN +0E40 0E1F ; [.2E3E.0020.0002][.2E5A.0020.0002] # <THAI CHARACTER SARA E, THAI CHARACTER FO FAN> +0E41 0E1F ; [.2E3E.0020.0002][.2E5B.0020.0002] # <THAI CHARACTER SARA AE, THAI CHARACTER FO FAN> +0E42 0E1F ; [.2E3E.0020.0002][.2E5C.0020.0002] # <THAI CHARACTER SARA O, THAI CHARACTER FO FAN> +0E43 0E1F ; [.2E3E.0020.0002][.2E5D.0020.0002] # <THAI CHARACTER SARA AI MAIMUAN, THAI CHARACTER FO FAN> +0E44 0E1F ; [.2E3E.0020.0002][.2E5E.0020.0002] # <THAI CHARACTER SARA AI MAIMALAI, THAI CHARACTER FO FAN> +0E20 ; [.2E3F.0020.0002] # THAI CHARACTER PHO SAMPHAO +0E40 0E20 ; [.2E3F.0020.0002][.2E5A.0020.0002] # <THAI CHARACTER SARA E, THAI CHARACTER PHO SAMPHAO> +0E41 0E20 ; [.2E3F.0020.0002][.2E5B.0020.0002] # <THAI CHARACTER SARA AE, THAI CHARACTER PHO SAMPHAO> +0E42 0E20 ; [.2E3F.0020.0002][.2E5C.0020.0002] # <THAI CHARACTER SARA O, THAI CHARACTER PHO SAMPHAO> +0E43 0E20 ; [.2E3F.0020.0002][.2E5D.0020.0002] # <THAI CHARACTER SARA AI MAIMUAN, THAI CHARACTER PHO SAMPHAO> +0E44 0E20 ; [.2E3F.0020.0002][.2E5E.0020.0002] # <THAI CHARACTER SARA AI MAIMALAI, THAI CHARACTER PHO SAMPHAO> +0E21 ; [.2E40.0020.0002] # THAI CHARACTER MO MA +0E40 0E21 ; [.2E40.0020.0002][.2E5A.0020.0002] # <THAI CHARACTER SARA E, THAI CHARACTER MO MA> +0E41 0E21 ; [.2E40.0020.0002][.2E5B.0020.0002] # <THAI CHARACTER SARA AE, THAI CHARACTER MO MA> +0E42 0E21 ; [.2E40.0020.0002][.2E5C.0020.0002] # <THAI CHARACTER SARA O, THAI CHARACTER MO MA> +0E43 0E21 ; [.2E40.0020.0002][.2E5D.0020.0002] # <THAI CHARACTER SARA AI MAIMUAN, THAI CHARACTER MO MA> +0E44 0E21 ; [.2E40.0020.0002][.2E5E.0020.0002] # <THAI CHARACTER SARA AI MAIMALAI, THAI CHARACTER MO MA> +0E22 ; [.2E41.0020.0002] # THAI CHARACTER YO YAK +0E40 0E22 ; [.2E41.0020.0002][.2E5A.0020.0002] # <THAI CHARACTER SARA E, THAI CHARACTER YO YAK> +0E41 0E22 ; [.2E41.0020.0002][.2E5B.0020.0002] # <THAI CHARACTER SARA AE, THAI CHARACTER YO YAK> +0E42 0E22 ; [.2E41.0020.0002][.2E5C.0020.0002] # <THAI CHARACTER SARA O, THAI CHARACTER YO YAK> +0E43 0E22 ; [.2E41.0020.0002][.2E5D.0020.0002] # <THAI CHARACTER SARA AI MAIMUAN, THAI CHARACTER YO YAK> +0E44 0E22 ; [.2E41.0020.0002][.2E5E.0020.0002] # <THAI CHARACTER SARA AI MAIMALAI, THAI CHARACTER YO YAK> +0E23 ; [.2E42.0020.0002] # THAI CHARACTER RO RUA +0E40 0E23 ; [.2E42.0020.0002][.2E5A.0020.0002] # <THAI CHARACTER SARA E, THAI CHARACTER RO RUA> +0E41 0E23 ; [.2E42.0020.0002][.2E5B.0020.0002] # <THAI CHARACTER SARA AE, THAI CHARACTER RO RUA> +0E42 0E23 ; [.2E42.0020.0002][.2E5C.0020.0002] # <THAI CHARACTER SARA O, THAI CHARACTER RO RUA> +0E43 0E23 ; [.2E42.0020.0002][.2E5D.0020.0002] # <THAI CHARACTER SARA AI MAIMUAN, THAI CHARACTER RO RUA> +0E44 0E23 ; [.2E42.0020.0002][.2E5E.0020.0002] # <THAI CHARACTER SARA AI MAIMALAI, THAI CHARACTER RO RUA> +0E24 ; [.2E43.0020.0002] # THAI CHARACTER RU +0E40 0E24 ; [.2E43.0020.0002][.2E5A.0020.0002] # <THAI CHARACTER SARA E, THAI CHARACTER RU> +0E41 0E24 ; [.2E43.0020.0002][.2E5B.0020.0002] # <THAI CHARACTER SARA AE, THAI CHARACTER RU> +0E42 0E24 ; [.2E43.0020.0002][.2E5C.0020.0002] # <THAI CHARACTER SARA O, THAI CHARACTER RU> +0E43 0E24 ; [.2E43.0020.0002][.2E5D.0020.0002] # <THAI CHARACTER SARA AI MAIMUAN, THAI CHARACTER RU> +0E44 0E24 ; [.2E43.0020.0002][.2E5E.0020.0002] # <THAI CHARACTER SARA AI MAIMALAI, THAI CHARACTER RU> +0E25 ; [.2E44.0020.0002] # THAI CHARACTER LO LING +0E40 0E25 ; [.2E44.0020.0002][.2E5A.0020.0002] # <THAI CHARACTER SARA E, THAI CHARACTER LO LING> +0E41 0E25 ; [.2E44.0020.0002][.2E5B.0020.0002] # <THAI CHARACTER SARA AE, THAI CHARACTER LO LING> +0E42 0E25 ; [.2E44.0020.0002][.2E5C.0020.0002] # <THAI CHARACTER SARA O, THAI CHARACTER LO LING> +0E43 0E25 ; [.2E44.0020.0002][.2E5D.0020.0002] # <THAI CHARACTER SARA AI MAIMUAN, THAI CHARACTER LO LING> +0E44 0E25 ; [.2E44.0020.0002][.2E5E.0020.0002] # <THAI CHARACTER SARA AI MAIMALAI, THAI CHARACTER LO LING> +0E26 ; [.2E45.0020.0002] # THAI CHARACTER LU +0E40 0E26 ; [.2E45.0020.0002][.2E5A.0020.0002] # <THAI CHARACTER SARA E, THAI CHARACTER LU> +0E41 0E26 ; [.2E45.0020.0002][.2E5B.0020.0002] # <THAI CHARACTER SARA AE, THAI CHARACTER LU> +0E42 0E26 ; [.2E45.0020.0002][.2E5C.0020.0002] # <THAI CHARACTER SARA O, THAI CHARACTER LU> +0E43 0E26 ; [.2E45.0020.0002][.2E5D.0020.0002] # <THAI CHARACTER SARA AI MAIMUAN, THAI CHARACTER LU> +0E44 0E26 ; [.2E45.0020.0002][.2E5E.0020.0002] # <THAI CHARACTER SARA AI MAIMALAI, THAI CHARACTER LU> +0E27 ; [.2E46.0020.0002] # THAI CHARACTER WO WAEN +0E40 0E27 ; [.2E46.0020.0002][.2E5A.0020.0002] # <THAI CHARACTER SARA E, THAI CHARACTER WO WAEN> +0E41 0E27 ; [.2E46.0020.0002][.2E5B.0020.0002] # <THAI CHARACTER SARA AE, THAI CHARACTER WO WAEN> +0E42 0E27 ; [.2E46.0020.0002][.2E5C.0020.0002] # <THAI CHARACTER SARA O, THAI CHARACTER WO WAEN> +0E43 0E27 ; [.2E46.0020.0002][.2E5D.0020.0002] # <THAI CHARACTER SARA AI MAIMUAN, THAI CHARACTER WO WAEN> +0E44 0E27 ; [.2E46.0020.0002][.2E5E.0020.0002] # <THAI CHARACTER SARA AI MAIMALAI, THAI CHARACTER WO WAEN> +0E28 ; [.2E47.0020.0002] # THAI CHARACTER SO SALA +0E40 0E28 ; [.2E47.0020.0002][.2E5A.0020.0002] # <THAI CHARACTER SARA E, THAI CHARACTER SO SALA> +0E41 0E28 ; [.2E47.0020.0002][.2E5B.0020.0002] # <THAI CHARACTER SARA AE, THAI CHARACTER SO SALA> +0E42 0E28 ; [.2E47.0020.0002][.2E5C.0020.0002] # <THAI CHARACTER SARA O, THAI CHARACTER SO SALA> +0E43 0E28 ; [.2E47.0020.0002][.2E5D.0020.0002] # <THAI CHARACTER SARA AI MAIMUAN, THAI CHARACTER SO SALA> +0E44 0E28 ; [.2E47.0020.0002][.2E5E.0020.0002] # <THAI CHARACTER SARA AI MAIMALAI, THAI CHARACTER SO SALA> +0E29 ; [.2E48.0020.0002] # THAI CHARACTER SO RUSI +0E40 0E29 ; [.2E48.0020.0002][.2E5A.0020.0002] # <THAI CHARACTER SARA E, THAI CHARACTER SO RUSI> +0E41 0E29 ; [.2E48.0020.0002][.2E5B.0020.0002] # <THAI CHARACTER SARA AE, THAI CHARACTER SO RUSI> +0E42 0E29 ; [.2E48.0020.0002][.2E5C.0020.0002] # <THAI CHARACTER SARA O, THAI CHARACTER SO RUSI> +0E43 0E29 ; [.2E48.0020.0002][.2E5D.0020.0002] # <THAI CHARACTER SARA AI MAIMUAN, THAI CHARACTER SO RUSI> +0E44 0E29 ; [.2E48.0020.0002][.2E5E.0020.0002] # <THAI CHARACTER SARA AI MAIMALAI, THAI CHARACTER SO RUSI> +0E2A ; [.2E49.0020.0002] # THAI CHARACTER SO SUA +0E40 0E2A ; [.2E49.0020.0002][.2E5A.0020.0002] # <THAI CHARACTER SARA E, THAI CHARACTER SO SUA> +0E41 0E2A ; [.2E49.0020.0002][.2E5B.0020.0002] # <THAI CHARACTER SARA AE, THAI CHARACTER SO SUA> +0E42 0E2A ; [.2E49.0020.0002][.2E5C.0020.0002] # <THAI CHARACTER SARA O, THAI CHARACTER SO SUA> +0E43 0E2A ; [.2E49.0020.0002][.2E5D.0020.0002] # <THAI CHARACTER SARA AI MAIMUAN, THAI CHARACTER SO SUA> +0E44 0E2A ; [.2E49.0020.0002][.2E5E.0020.0002] # <THAI CHARACTER SARA AI MAIMALAI, THAI CHARACTER SO SUA> +0E2B ; [.2E4A.0020.0002] # THAI CHARACTER HO HIP +0E40 0E2B ; [.2E4A.0020.0002][.2E5A.0020.0002] # <THAI CHARACTER SARA E, THAI CHARACTER HO HIP> +0E41 0E2B ; [.2E4A.0020.0002][.2E5B.0020.0002] # <THAI CHARACTER SARA AE, THAI CHARACTER HO HIP> +0E42 0E2B ; [.2E4A.0020.0002][.2E5C.0020.0002] # <THAI CHARACTER SARA O, THAI CHARACTER HO HIP> +0E43 0E2B ; [.2E4A.0020.0002][.2E5D.0020.0002] # <THAI CHARACTER SARA AI MAIMUAN, THAI CHARACTER HO HIP> +0E44 0E2B ; [.2E4A.0020.0002][.2E5E.0020.0002] # <THAI CHARACTER SARA AI MAIMALAI, THAI CHARACTER HO HIP> +0E2C ; [.2E4B.0020.0002] # THAI CHARACTER LO CHULA +0E40 0E2C ; [.2E4B.0020.0002][.2E5A.0020.0002] # <THAI CHARACTER SARA E, THAI CHARACTER LO CHULA> +0E41 0E2C ; [.2E4B.0020.0002][.2E5B.0020.0002] # <THAI CHARACTER SARA AE, THAI CHARACTER LO CHULA> +0E42 0E2C ; [.2E4B.0020.0002][.2E5C.0020.0002] # <THAI CHARACTER SARA O, THAI CHARACTER LO CHULA> +0E43 0E2C ; [.2E4B.0020.0002][.2E5D.0020.0002] # <THAI CHARACTER SARA AI MAIMUAN, THAI CHARACTER LO CHULA> +0E44 0E2C ; [.2E4B.0020.0002][.2E5E.0020.0002] # <THAI CHARACTER SARA AI MAIMALAI, THAI CHARACTER LO CHULA> +0E2D ; [.2E4C.0020.0002] # THAI CHARACTER O ANG +0E40 0E2D ; [.2E4C.0020.0002][.2E5A.0020.0002] # <THAI CHARACTER SARA E, THAI CHARACTER O ANG> +0E41 0E2D ; [.2E4C.0020.0002][.2E5B.0020.0002] # <THAI CHARACTER SARA AE, THAI CHARACTER O ANG> +0E42 0E2D ; [.2E4C.0020.0002][.2E5C.0020.0002] # <THAI CHARACTER SARA O, THAI CHARACTER O ANG> +0E43 0E2D ; [.2E4C.0020.0002][.2E5D.0020.0002] # <THAI CHARACTER SARA AI MAIMUAN, THAI CHARACTER O ANG> +0E44 0E2D ; [.2E4C.0020.0002][.2E5E.0020.0002] # <THAI CHARACTER SARA AI MAIMALAI, THAI CHARACTER O ANG> +0E2E ; [.2E4D.0020.0002] # THAI CHARACTER HO NOKHUK +0E40 0E2E ; [.2E4D.0020.0002][.2E5A.0020.0002] # <THAI CHARACTER SARA E, THAI CHARACTER HO NOKHUK> +0E41 0E2E ; [.2E4D.0020.0002][.2E5B.0020.0002] # <THAI CHARACTER SARA AE, THAI CHARACTER HO NOKHUK> +0E42 0E2E ; [.2E4D.0020.0002][.2E5C.0020.0002] # <THAI CHARACTER SARA O, THAI CHARACTER HO NOKHUK> +0E43 0E2E ; [.2E4D.0020.0002][.2E5D.0020.0002] # <THAI CHARACTER SARA AI MAIMUAN, THAI CHARACTER HO NOKHUK> +0E44 0E2E ; [.2E4D.0020.0002][.2E5E.0020.0002] # <THAI CHARACTER SARA AI MAIMALAI, THAI CHARACTER HO NOKHUK> +0E2F ; [.2E4E.0020.0002] # THAI CHARACTER PAIYANNOI +0E30 ; [.2E4F.0020.0002] # THAI CHARACTER SARA A +0E31 ; [.2E50.0020.0002] # THAI CHARACTER MAI HAN-AKAT +0E32 ; [.2E51.0020.0002] # THAI CHARACTER SARA AA +0E33 ; [.2E52.0020.0002] # THAI CHARACTER SARA AM +0E4D 0E32 ; [.2E52.0020.0002] # THAI CHARACTER SARA AM +0E34 ; [.2E53.0020.0002] # THAI CHARACTER SARA I +0E35 ; [.2E54.0020.0002] # THAI CHARACTER SARA II +0E36 ; [.2E55.0020.0002] # THAI CHARACTER SARA UE +0E37 ; [.2E56.0020.0002] # THAI CHARACTER SARA UEE +0E38 ; [.2E57.0020.0002] # THAI CHARACTER SARA U +0E39 ; [.2E58.0020.0002] # THAI CHARACTER SARA UU +0E3A ; [.2E59.0020.0002] # THAI CHARACTER PHINTHU +0E40 ; [.2E5A.0020.0002] # THAI CHARACTER SARA E +0E41 ; [.2E5B.0020.0002] # THAI CHARACTER SARA AE +0E42 ; [.2E5C.0020.0002] # THAI CHARACTER SARA O +0E43 ; [.2E5D.0020.0002] # THAI CHARACTER SARA AI MAIMUAN +0E44 ; [.2E5E.0020.0002] # THAI CHARACTER SARA AI MAIMALAI +0E45 ; [.2E5F.0020.0002] # THAI CHARACTER LAKKHANGYAO +0EDE ; [.2E60.0020.0002] # LAO LETTER KHMU GO +0EC0 0EDE ; [.2E60.0020.0002][.2E8B.0020.0002] # <LAO VOWEL SIGN E, LAO LETTER KHMU GO> +0EC1 0EDE ; [.2E60.0020.0002][.2E8C.0020.0002] # <LAO VOWEL SIGN EI, LAO LETTER KHMU GO> +0EC2 0EDE ; [.2E60.0020.0002][.2E8D.0020.0002] # <LAO VOWEL SIGN O, LAO LETTER KHMU GO> +0EC3 0EDE ; [.2E60.0020.0002][.2E8E.0020.0002] # <LAO VOWEL SIGN AY, LAO LETTER KHMU GO> +0EC4 0EDE ; [.2E60.0020.0002][.2E8F.0020.0002] # <LAO VOWEL SIGN AI, LAO LETTER KHMU GO> +0E81 ; [.2E61.0020.0002] # LAO LETTER KO +0EC0 0E81 ; [.2E61.0020.0002][.2E8B.0020.0002] # <LAO VOWEL SIGN E, LAO LETTER KO> +0EC1 0E81 ; [.2E61.0020.0002][.2E8C.0020.0002] # <LAO VOWEL SIGN EI, LAO LETTER KO> +0EC2 0E81 ; [.2E61.0020.0002][.2E8D.0020.0002] # <LAO VOWEL SIGN O, LAO LETTER KO> +0EC3 0E81 ; [.2E61.0020.0002][.2E8E.0020.0002] # <LAO VOWEL SIGN AY, LAO LETTER KO> +0EC4 0E81 ; [.2E61.0020.0002][.2E8F.0020.0002] # <LAO VOWEL SIGN AI, LAO LETTER KO> +0E82 ; [.2E62.0020.0002] # LAO LETTER KHO SUNG +0EC0 0E82 ; [.2E62.0020.0002][.2E8B.0020.0002] # <LAO VOWEL SIGN E, LAO LETTER KHO SUNG> +0EC1 0E82 ; [.2E62.0020.0002][.2E8C.0020.0002] # <LAO VOWEL SIGN EI, LAO LETTER KHO SUNG> +0EC2 0E82 ; [.2E62.0020.0002][.2E8D.0020.0002] # <LAO VOWEL SIGN O, LAO LETTER KHO SUNG> +0EC3 0E82 ; [.2E62.0020.0002][.2E8E.0020.0002] # <LAO VOWEL SIGN AY, LAO LETTER KHO SUNG> +0EC4 0E82 ; [.2E62.0020.0002][.2E8F.0020.0002] # <LAO VOWEL SIGN AI, LAO LETTER KHO SUNG> +0E84 ; [.2E63.0020.0002] # LAO LETTER KHO TAM +0EC0 0E84 ; [.2E63.0020.0002][.2E8B.0020.0002] # <LAO VOWEL SIGN E, LAO LETTER KHO TAM> +0EC1 0E84 ; [.2E63.0020.0002][.2E8C.0020.0002] # <LAO VOWEL SIGN EI, LAO LETTER KHO TAM> +0EC2 0E84 ; [.2E63.0020.0002][.2E8D.0020.0002] # <LAO VOWEL SIGN O, LAO LETTER KHO TAM> +0EC3 0E84 ; [.2E63.0020.0002][.2E8E.0020.0002] # <LAO VOWEL SIGN AY, LAO LETTER KHO TAM> +0EC4 0E84 ; [.2E63.0020.0002][.2E8F.0020.0002] # <LAO VOWEL SIGN AI, LAO LETTER KHO TAM> +0E87 ; [.2E64.0020.0002] # LAO LETTER NGO +0EC0 0E87 ; [.2E64.0020.0002][.2E8B.0020.0002] # <LAO VOWEL SIGN E, LAO LETTER NGO> +0EC1 0E87 ; [.2E64.0020.0002][.2E8C.0020.0002] # <LAO VOWEL SIGN EI, LAO LETTER NGO> +0EC2 0E87 ; [.2E64.0020.0002][.2E8D.0020.0002] # <LAO VOWEL SIGN O, LAO LETTER NGO> +0EC3 0E87 ; [.2E64.0020.0002][.2E8E.0020.0002] # <LAO VOWEL SIGN AY, LAO LETTER NGO> +0EC4 0E87 ; [.2E64.0020.0002][.2E8F.0020.0002] # <LAO VOWEL SIGN AI, LAO LETTER NGO> +0E88 ; [.2E65.0020.0002] # LAO LETTER CO +0EC0 0E88 ; [.2E65.0020.0002][.2E8B.0020.0002] # <LAO VOWEL SIGN E, LAO LETTER CO> +0EC1 0E88 ; [.2E65.0020.0002][.2E8C.0020.0002] # <LAO VOWEL SIGN EI, LAO LETTER CO> +0EC2 0E88 ; [.2E65.0020.0002][.2E8D.0020.0002] # <LAO VOWEL SIGN O, LAO LETTER CO> +0EC3 0E88 ; [.2E65.0020.0002][.2E8E.0020.0002] # <LAO VOWEL SIGN AY, LAO LETTER CO> +0EC4 0E88 ; [.2E65.0020.0002][.2E8F.0020.0002] # <LAO VOWEL SIGN AI, LAO LETTER CO> +0EAA ; [.2E66.0020.0002] # LAO LETTER SO SUNG +0EC0 0EAA ; [.2E66.0020.0002][.2E8B.0020.0002] # <LAO VOWEL SIGN E, LAO LETTER SO SUNG> +0EC1 0EAA ; [.2E66.0020.0002][.2E8C.0020.0002] # <LAO VOWEL SIGN EI, LAO LETTER SO SUNG> +0EC2 0EAA ; [.2E66.0020.0002][.2E8D.0020.0002] # <LAO VOWEL SIGN O, LAO LETTER SO SUNG> +0EC3 0EAA ; [.2E66.0020.0002][.2E8E.0020.0002] # <LAO VOWEL SIGN AY, LAO LETTER SO SUNG> +0EC4 0EAA ; [.2E66.0020.0002][.2E8F.0020.0002] # <LAO VOWEL SIGN AI, LAO LETTER SO SUNG> +0E8A ; [.2E67.0020.0002] # LAO LETTER SO TAM +0EC0 0E8A ; [.2E67.0020.0002][.2E8B.0020.0002] # <LAO VOWEL SIGN E, LAO LETTER SO TAM> +0EC1 0E8A ; [.2E67.0020.0002][.2E8C.0020.0002] # <LAO VOWEL SIGN EI, LAO LETTER SO TAM> +0EC2 0E8A ; [.2E67.0020.0002][.2E8D.0020.0002] # <LAO VOWEL SIGN O, LAO LETTER SO TAM> +0EC3 0E8A ; [.2E67.0020.0002][.2E8E.0020.0002] # <LAO VOWEL SIGN AY, LAO LETTER SO TAM> +0EC4 0E8A ; [.2E67.0020.0002][.2E8F.0020.0002] # <LAO VOWEL SIGN AI, LAO LETTER SO TAM> +0EDF ; [.2E68.0020.0002] # LAO LETTER KHMU NYO +0EC0 0EDF ; [.2E68.0020.0002][.2E8B.0020.0002] # <LAO VOWEL SIGN E, LAO LETTER KHMU NYO> +0EC1 0EDF ; [.2E68.0020.0002][.2E8C.0020.0002] # <LAO VOWEL SIGN EI, LAO LETTER KHMU NYO> +0EC2 0EDF ; [.2E68.0020.0002][.2E8D.0020.0002] # <LAO VOWEL SIGN O, LAO LETTER KHMU NYO> +0EC3 0EDF ; [.2E68.0020.0002][.2E8E.0020.0002] # <LAO VOWEL SIGN AY, LAO LETTER KHMU NYO> +0EC4 0EDF ; [.2E68.0020.0002][.2E8F.0020.0002] # <LAO VOWEL SIGN AI, LAO LETTER KHMU NYO> +0E8D ; [.2E69.0020.0002] # LAO LETTER NYO +0EC0 0E8D ; [.2E69.0020.0002][.2E8B.0020.0002] # <LAO VOWEL SIGN E, LAO LETTER NYO> +0EC1 0E8D ; [.2E69.0020.0002][.2E8C.0020.0002] # <LAO VOWEL SIGN EI, LAO LETTER NYO> +0EC2 0E8D ; [.2E69.0020.0002][.2E8D.0020.0002] # <LAO VOWEL SIGN O, LAO LETTER NYO> +0EC3 0E8D ; [.2E69.0020.0002][.2E8E.0020.0002] # <LAO VOWEL SIGN AY, LAO LETTER NYO> +0EC4 0E8D ; [.2E69.0020.0002][.2E8F.0020.0002] # <LAO VOWEL SIGN AI, LAO LETTER NYO> +0E94 ; [.2E6A.0020.0002] # LAO LETTER DO +0EC0 0E94 ; [.2E6A.0020.0002][.2E8B.0020.0002] # <LAO VOWEL SIGN E, LAO LETTER DO> +0EC1 0E94 ; [.2E6A.0020.0002][.2E8C.0020.0002] # <LAO VOWEL SIGN EI, LAO LETTER DO> +0EC2 0E94 ; [.2E6A.0020.0002][.2E8D.0020.0002] # <LAO VOWEL SIGN O, LAO LETTER DO> +0EC3 0E94 ; [.2E6A.0020.0002][.2E8E.0020.0002] # <LAO VOWEL SIGN AY, LAO LETTER DO> +0EC4 0E94 ; [.2E6A.0020.0002][.2E8F.0020.0002] # <LAO VOWEL SIGN AI, LAO LETTER DO> +0E95 ; [.2E6B.0020.0002] # LAO LETTER TO +0EC0 0E95 ; [.2E6B.0020.0002][.2E8B.0020.0002] # <LAO VOWEL SIGN E, LAO LETTER TO> +0EC1 0E95 ; [.2E6B.0020.0002][.2E8C.0020.0002] # <LAO VOWEL SIGN EI, LAO LETTER TO> +0EC2 0E95 ; [.2E6B.0020.0002][.2E8D.0020.0002] # <LAO VOWEL SIGN O, LAO LETTER TO> +0EC3 0E95 ; [.2E6B.0020.0002][.2E8E.0020.0002] # <LAO VOWEL SIGN AY, LAO LETTER TO> +0EC4 0E95 ; [.2E6B.0020.0002][.2E8F.0020.0002] # <LAO VOWEL SIGN AI, LAO LETTER TO> +0E96 ; [.2E6C.0020.0002] # LAO LETTER THO SUNG +0EC0 0E96 ; [.2E6C.0020.0002][.2E8B.0020.0002] # <LAO VOWEL SIGN E, LAO LETTER THO SUNG> +0EC1 0E96 ; [.2E6C.0020.0002][.2E8C.0020.0002] # <LAO VOWEL SIGN EI, LAO LETTER THO SUNG> +0EC2 0E96 ; [.2E6C.0020.0002][.2E8D.0020.0002] # <LAO VOWEL SIGN O, LAO LETTER THO SUNG> +0EC3 0E96 ; [.2E6C.0020.0002][.2E8E.0020.0002] # <LAO VOWEL SIGN AY, LAO LETTER THO SUNG> +0EC4 0E96 ; [.2E6C.0020.0002][.2E8F.0020.0002] # <LAO VOWEL SIGN AI, LAO LETTER THO SUNG> +0E97 ; [.2E6D.0020.0002] # LAO LETTER THO TAM +0EC0 0E97 ; [.2E6D.0020.0002][.2E8B.0020.0002] # <LAO VOWEL SIGN E, LAO LETTER THO TAM> +0EC1 0E97 ; [.2E6D.0020.0002][.2E8C.0020.0002] # <LAO VOWEL SIGN EI, LAO LETTER THO TAM> +0EC2 0E97 ; [.2E6D.0020.0002][.2E8D.0020.0002] # <LAO VOWEL SIGN O, LAO LETTER THO TAM> +0EC3 0E97 ; [.2E6D.0020.0002][.2E8E.0020.0002] # <LAO VOWEL SIGN AY, LAO LETTER THO TAM> +0EC4 0E97 ; [.2E6D.0020.0002][.2E8F.0020.0002] # <LAO VOWEL SIGN AI, LAO LETTER THO TAM> +0E99 ; [.2E6E.0020.0002] # LAO LETTER NO +0EC0 0E99 ; [.2E6E.0020.0002][.2E8B.0020.0002] # <LAO VOWEL SIGN E, LAO LETTER NO> +0EC1 0E99 ; [.2E6E.0020.0002][.2E8C.0020.0002] # <LAO VOWEL SIGN EI, LAO LETTER NO> +0EC2 0E99 ; [.2E6E.0020.0002][.2E8D.0020.0002] # <LAO VOWEL SIGN O, LAO LETTER NO> +0EC3 0E99 ; [.2E6E.0020.0002][.2E8E.0020.0002] # <LAO VOWEL SIGN AY, LAO LETTER NO> +0EC4 0E99 ; [.2E6E.0020.0002][.2E8F.0020.0002] # <LAO VOWEL SIGN AI, LAO LETTER NO> +0E9A ; [.2E6F.0020.0002] # LAO LETTER BO +0EC0 0E9A ; [.2E6F.0020.0002][.2E8B.0020.0002] # <LAO VOWEL SIGN E, LAO LETTER BO> +0EC1 0E9A ; [.2E6F.0020.0002][.2E8C.0020.0002] # <LAO VOWEL SIGN EI, LAO LETTER BO> +0EC2 0E9A ; [.2E6F.0020.0002][.2E8D.0020.0002] # <LAO VOWEL SIGN O, LAO LETTER BO> +0EC3 0E9A ; [.2E6F.0020.0002][.2E8E.0020.0002] # <LAO VOWEL SIGN AY, LAO LETTER BO> +0EC4 0E9A ; [.2E6F.0020.0002][.2E8F.0020.0002] # <LAO VOWEL SIGN AI, LAO LETTER BO> +0E9B ; [.2E70.0020.0002] # LAO LETTER PO +0EC0 0E9B ; [.2E70.0020.0002][.2E8B.0020.0002] # <LAO VOWEL SIGN E, LAO LETTER PO> +0EC1 0E9B ; [.2E70.0020.0002][.2E8C.0020.0002] # <LAO VOWEL SIGN EI, LAO LETTER PO> +0EC2 0E9B ; [.2E70.0020.0002][.2E8D.0020.0002] # <LAO VOWEL SIGN O, LAO LETTER PO> +0EC3 0E9B ; [.2E70.0020.0002][.2E8E.0020.0002] # <LAO VOWEL SIGN AY, LAO LETTER PO> +0EC4 0E9B ; [.2E70.0020.0002][.2E8F.0020.0002] # <LAO VOWEL SIGN AI, LAO LETTER PO> +0E9C ; [.2E71.0020.0002] # LAO LETTER PHO SUNG +0EC0 0E9C ; [.2E71.0020.0002][.2E8B.0020.0002] # <LAO VOWEL SIGN E, LAO LETTER PHO SUNG> +0EC1 0E9C ; [.2E71.0020.0002][.2E8C.0020.0002] # <LAO VOWEL SIGN EI, LAO LETTER PHO SUNG> +0EC2 0E9C ; [.2E71.0020.0002][.2E8D.0020.0002] # <LAO VOWEL SIGN O, LAO LETTER PHO SUNG> +0EC3 0E9C ; [.2E71.0020.0002][.2E8E.0020.0002] # <LAO VOWEL SIGN AY, LAO LETTER PHO SUNG> +0EC4 0E9C ; [.2E71.0020.0002][.2E8F.0020.0002] # <LAO VOWEL SIGN AI, LAO LETTER PHO SUNG> +0E9D ; [.2E72.0020.0002] # LAO LETTER FO TAM +0EC0 0E9D ; [.2E72.0020.0002][.2E8B.0020.0002] # <LAO VOWEL SIGN E, LAO LETTER FO TAM> +0EC1 0E9D ; [.2E72.0020.0002][.2E8C.0020.0002] # <LAO VOWEL SIGN EI, LAO LETTER FO TAM> +0EC2 0E9D ; [.2E72.0020.0002][.2E8D.0020.0002] # <LAO VOWEL SIGN O, LAO LETTER FO TAM> +0EC3 0E9D ; [.2E72.0020.0002][.2E8E.0020.0002] # <LAO VOWEL SIGN AY, LAO LETTER FO TAM> +0EC4 0E9D ; [.2E72.0020.0002][.2E8F.0020.0002] # <LAO VOWEL SIGN AI, LAO LETTER FO TAM> +0E9E ; [.2E73.0020.0002] # LAO LETTER PHO TAM +0EC0 0E9E ; [.2E73.0020.0002][.2E8B.0020.0002] # <LAO VOWEL SIGN E, LAO LETTER PHO TAM> +0EC1 0E9E ; [.2E73.0020.0002][.2E8C.0020.0002] # <LAO VOWEL SIGN EI, LAO LETTER PHO TAM> +0EC2 0E9E ; [.2E73.0020.0002][.2E8D.0020.0002] # <LAO VOWEL SIGN O, LAO LETTER PHO TAM> +0EC3 0E9E ; [.2E73.0020.0002][.2E8E.0020.0002] # <LAO VOWEL SIGN AY, LAO LETTER PHO TAM> +0EC4 0E9E ; [.2E73.0020.0002][.2E8F.0020.0002] # <LAO VOWEL SIGN AI, LAO LETTER PHO TAM> +0E9F ; [.2E74.0020.0002] # LAO LETTER FO SUNG +0EC0 0E9F ; [.2E74.0020.0002][.2E8B.0020.0002] # <LAO VOWEL SIGN E, LAO LETTER FO SUNG> +0EC1 0E9F ; [.2E74.0020.0002][.2E8C.0020.0002] # <LAO VOWEL SIGN EI, LAO LETTER FO SUNG> +0EC2 0E9F ; [.2E74.0020.0002][.2E8D.0020.0002] # <LAO VOWEL SIGN O, LAO LETTER FO SUNG> +0EC3 0E9F ; [.2E74.0020.0002][.2E8E.0020.0002] # <LAO VOWEL SIGN AY, LAO LETTER FO SUNG> +0EC4 0E9F ; [.2E74.0020.0002][.2E8F.0020.0002] # <LAO VOWEL SIGN AI, LAO LETTER FO SUNG> +0EA1 ; [.2E75.0020.0002] # LAO LETTER MO +0EC0 0EA1 ; [.2E75.0020.0002][.2E8B.0020.0002] # <LAO VOWEL SIGN E, LAO LETTER MO> +0EC1 0EA1 ; [.2E75.0020.0002][.2E8C.0020.0002] # <LAO VOWEL SIGN EI, LAO LETTER MO> +0EC2 0EA1 ; [.2E75.0020.0002][.2E8D.0020.0002] # <LAO VOWEL SIGN O, LAO LETTER MO> +0EC3 0EA1 ; [.2E75.0020.0002][.2E8E.0020.0002] # <LAO VOWEL SIGN AY, LAO LETTER MO> +0EC4 0EA1 ; [.2E75.0020.0002][.2E8F.0020.0002] # <LAO VOWEL SIGN AI, LAO LETTER MO> +0EA2 ; [.2E76.0020.0002] # LAO LETTER YO +0EC0 0EA2 ; [.2E76.0020.0002][.2E8B.0020.0002] # <LAO VOWEL SIGN E, LAO LETTER YO> +0EC1 0EA2 ; [.2E76.0020.0002][.2E8C.0020.0002] # <LAO VOWEL SIGN EI, LAO LETTER YO> +0EC2 0EA2 ; [.2E76.0020.0002][.2E8D.0020.0002] # <LAO VOWEL SIGN O, LAO LETTER YO> +0EC3 0EA2 ; [.2E76.0020.0002][.2E8E.0020.0002] # <LAO VOWEL SIGN AY, LAO LETTER YO> +0EC4 0EA2 ; [.2E76.0020.0002][.2E8F.0020.0002] # <LAO VOWEL SIGN AI, LAO LETTER YO> +0EA3 ; [.2E77.0020.0002] # LAO LETTER LO LING +0EC0 0EA3 ; [.2E77.0020.0002][.2E8B.0020.0002] # <LAO VOWEL SIGN E, LAO LETTER LO LING> +0EC1 0EA3 ; [.2E77.0020.0002][.2E8C.0020.0002] # <LAO VOWEL SIGN EI, LAO LETTER LO LING> +0EC2 0EA3 ; [.2E77.0020.0002][.2E8D.0020.0002] # <LAO VOWEL SIGN O, LAO LETTER LO LING> +0EC3 0EA3 ; [.2E77.0020.0002][.2E8E.0020.0002] # <LAO VOWEL SIGN AY, LAO LETTER LO LING> +0EC4 0EA3 ; [.2E77.0020.0002][.2E8F.0020.0002] # <LAO VOWEL SIGN AI, LAO LETTER LO LING> +0EA5 ; [.2E78.0020.0002] # LAO LETTER LO LOOT +0EC0 0EA5 ; [.2E78.0020.0002][.2E8B.0020.0002] # <LAO VOWEL SIGN E, LAO LETTER LO LOOT> +0EC1 0EA5 ; [.2E78.0020.0002][.2E8C.0020.0002] # <LAO VOWEL SIGN EI, LAO LETTER LO LOOT> +0EC2 0EA5 ; [.2E78.0020.0002][.2E8D.0020.0002] # <LAO VOWEL SIGN O, LAO LETTER LO LOOT> +0EC3 0EA5 ; [.2E78.0020.0002][.2E8E.0020.0002] # <LAO VOWEL SIGN AY, LAO LETTER LO LOOT> +0EC4 0EA5 ; [.2E78.0020.0002][.2E8F.0020.0002] # <LAO VOWEL SIGN AI, LAO LETTER LO LOOT> +0EA7 ; [.2E79.0020.0002] # LAO LETTER WO +0EC0 0EA7 ; [.2E79.0020.0002][.2E8B.0020.0002] # <LAO VOWEL SIGN E, LAO LETTER WO> +0EC1 0EA7 ; [.2E79.0020.0002][.2E8C.0020.0002] # <LAO VOWEL SIGN EI, LAO LETTER WO> +0EC2 0EA7 ; [.2E79.0020.0002][.2E8D.0020.0002] # <LAO VOWEL SIGN O, LAO LETTER WO> +0EC3 0EA7 ; [.2E79.0020.0002][.2E8E.0020.0002] # <LAO VOWEL SIGN AY, LAO LETTER WO> +0EC4 0EA7 ; [.2E79.0020.0002][.2E8F.0020.0002] # <LAO VOWEL SIGN AI, LAO LETTER WO> +0EAB ; [.2E7A.0020.0002] # LAO LETTER HO SUNG +0EDC ; [.2E7A.0020.0004][.2E6E.0020.0004] # LAO HO NO +0EC0 0EDC ; [.2E7A.0020.0004][.2E6E.0020.0004][.2E8B.0020.0002] # <LAO VOWEL SIGN E, LAO HO NO> +0EC1 0EDC ; [.2E7A.0020.0004][.2E6E.0020.0004][.2E8C.0020.0002] # <LAO VOWEL SIGN EI, LAO HO NO> +0EC2 0EDC ; [.2E7A.0020.0004][.2E6E.0020.0004][.2E8D.0020.0002] # <LAO VOWEL SIGN O, LAO HO NO> +0EC3 0EDC ; [.2E7A.0020.0004][.2E6E.0020.0004][.2E8E.0020.0002] # <LAO VOWEL SIGN AY, LAO HO NO> +0EC4 0EDC ; [.2E7A.0020.0004][.2E6E.0020.0004][.2E8F.0020.0002] # <LAO VOWEL SIGN AI, LAO HO NO> +0EDD ; [.2E7A.0020.0004][.2E75.0020.0004] # LAO HO MO +0EC0 0EDD ; [.2E7A.0020.0004][.2E75.0020.0004][.2E8B.0020.0002] # <LAO VOWEL SIGN E, LAO HO MO> +0EC1 0EDD ; [.2E7A.0020.0004][.2E75.0020.0004][.2E8C.0020.0002] # <LAO VOWEL SIGN EI, LAO HO MO> +0EC2 0EDD ; [.2E7A.0020.0004][.2E75.0020.0004][.2E8D.0020.0002] # <LAO VOWEL SIGN O, LAO HO MO> +0EC3 0EDD ; [.2E7A.0020.0004][.2E75.0020.0004][.2E8E.0020.0002] # <LAO VOWEL SIGN AY, LAO HO MO> +0EC4 0EDD ; [.2E7A.0020.0004][.2E75.0020.0004][.2E8F.0020.0002] # <LAO VOWEL SIGN AI, LAO HO MO> +0EC0 0EAB ; [.2E7A.0020.0002][.2E8B.0020.0002] # <LAO VOWEL SIGN E, LAO LETTER HO SUNG> +0EC1 0EAB ; [.2E7A.0020.0002][.2E8C.0020.0002] # <LAO VOWEL SIGN EI, LAO LETTER HO SUNG> +0EC2 0EAB ; [.2E7A.0020.0002][.2E8D.0020.0002] # <LAO VOWEL SIGN O, LAO LETTER HO SUNG> +0EC3 0EAB ; [.2E7A.0020.0002][.2E8E.0020.0002] # <LAO VOWEL SIGN AY, LAO LETTER HO SUNG> +0EC4 0EAB ; [.2E7A.0020.0002][.2E8F.0020.0002] # <LAO VOWEL SIGN AI, LAO LETTER HO SUNG> +0EAD ; [.2E7B.0020.0002] # LAO LETTER O +0EC0 0EAD ; [.2E7B.0020.0002][.2E8B.0020.0002] # <LAO VOWEL SIGN E, LAO LETTER O> +0EC1 0EAD ; [.2E7B.0020.0002][.2E8C.0020.0002] # <LAO VOWEL SIGN EI, LAO LETTER O> +0EC2 0EAD ; [.2E7B.0020.0002][.2E8D.0020.0002] # <LAO VOWEL SIGN O, LAO LETTER O> +0EC3 0EAD ; [.2E7B.0020.0002][.2E8E.0020.0002] # <LAO VOWEL SIGN AY, LAO LETTER O> +0EC4 0EAD ; [.2E7B.0020.0002][.2E8F.0020.0002] # <LAO VOWEL SIGN AI, LAO LETTER O> +0EAE ; [.2E7C.0020.0002] # LAO LETTER HO TAM +0EC0 0EAE ; [.2E7C.0020.0002][.2E8B.0020.0002] # <LAO VOWEL SIGN E, LAO LETTER HO TAM> +0EC1 0EAE ; [.2E7C.0020.0002][.2E8C.0020.0002] # <LAO VOWEL SIGN EI, LAO LETTER HO TAM> +0EC2 0EAE ; [.2E7C.0020.0002][.2E8D.0020.0002] # <LAO VOWEL SIGN O, LAO LETTER HO TAM> +0EC3 0EAE ; [.2E7C.0020.0002][.2E8E.0020.0002] # <LAO VOWEL SIGN AY, LAO LETTER HO TAM> +0EC4 0EAE ; [.2E7C.0020.0002][.2E8F.0020.0002] # <LAO VOWEL SIGN AI, LAO LETTER HO TAM> +0EAF ; [.2E7D.0020.0002] # LAO ELLIPSIS +0EB0 ; [.2E7E.0020.0002] # LAO VOWEL SIGN A +0EB1 ; [.2E7F.0020.0002] # LAO VOWEL SIGN MAI KAN +0EB2 ; [.2E80.0020.0002] # LAO VOWEL SIGN AA +0EB3 ; [.2E81.0020.0002] # LAO VOWEL SIGN AM +0ECD 0EB2 ; [.2E81.0020.0002] # LAO VOWEL SIGN AM +0EB4 ; [.2E82.0020.0002] # LAO VOWEL SIGN I +0EB5 ; [.2E83.0020.0002] # LAO VOWEL SIGN II +0EB6 ; [.2E84.0020.0002] # LAO VOWEL SIGN Y +0EB7 ; [.2E85.0020.0002] # LAO VOWEL SIGN YY +0EB8 ; [.2E86.0020.0002] # LAO VOWEL SIGN U +0EB9 ; [.2E87.0020.0002] # LAO VOWEL SIGN UU +0EBB ; [.2E88.0020.0002] # LAO VOWEL SIGN MAI KON +0EBC ; [.2E89.0020.0002] # LAO SEMIVOWEL SIGN LO +0EBD ; [.2E8A.0020.0002] # LAO SEMIVOWEL SIGN NYO +0EC0 ; [.2E8B.0020.0002] # LAO VOWEL SIGN E +0EC1 ; [.2E8C.0020.0002] # LAO VOWEL SIGN EI +0EC2 ; [.2E8D.0020.0002] # LAO VOWEL SIGN O +0EC3 ; [.2E8E.0020.0002] # LAO VOWEL SIGN AY +0EC4 ; [.2E8F.0020.0002] # LAO VOWEL SIGN AI +AA80 ; [.2E90.0020.0002] # TAI VIET LETTER LOW KO +AAB5 AA80 ; [.2E90.0020.0002][.2EC5.0020.0002] # <TAI VIET VOWEL E, TAI VIET LETTER LOW KO> +AAB6 AA80 ; [.2E90.0020.0002][.2EC6.0020.0002] # <TAI VIET VOWEL O, TAI VIET LETTER LOW KO> +AAB9 AA80 ; [.2E90.0020.0002][.2EC9.0020.0002] # <TAI VIET VOWEL UEA, TAI VIET LETTER LOW KO> +AABB AA80 ; [.2E90.0020.0002][.2ECB.0020.0002] # <TAI VIET VOWEL AUE, TAI VIET LETTER LOW KO> +AABC AA80 ; [.2E90.0020.0002][.2ECC.0020.0002] # <TAI VIET VOWEL AY, TAI VIET LETTER LOW KO> +AA81 ; [.2E91.0020.0002] # TAI VIET LETTER HIGH KO +AAB5 AA81 ; [.2E91.0020.0002][.2EC5.0020.0002] # <TAI VIET VOWEL E, TAI VIET LETTER HIGH KO> +AAB6 AA81 ; [.2E91.0020.0002][.2EC6.0020.0002] # <TAI VIET VOWEL O, TAI VIET LETTER HIGH KO> +AAB9 AA81 ; [.2E91.0020.0002][.2EC9.0020.0002] # <TAI VIET VOWEL UEA, TAI VIET LETTER HIGH KO> +AABB AA81 ; [.2E91.0020.0002][.2ECB.0020.0002] # <TAI VIET VOWEL AUE, TAI VIET LETTER HIGH KO> +AABC AA81 ; [.2E91.0020.0002][.2ECC.0020.0002] # <TAI VIET VOWEL AY, TAI VIET LETTER HIGH KO> +AA82 ; [.2E92.0020.0002] # TAI VIET LETTER LOW KHO +AAB5 AA82 ; [.2E92.0020.0002][.2EC5.0020.0002] # <TAI VIET VOWEL E, TAI VIET LETTER LOW KHO> +AAB6 AA82 ; [.2E92.0020.0002][.2EC6.0020.0002] # <TAI VIET VOWEL O, TAI VIET LETTER LOW KHO> +AAB9 AA82 ; [.2E92.0020.0002][.2EC9.0020.0002] # <TAI VIET VOWEL UEA, TAI VIET LETTER LOW KHO> +AABB AA82 ; [.2E92.0020.0002][.2ECB.0020.0002] # <TAI VIET VOWEL AUE, TAI VIET LETTER LOW KHO> +AABC AA82 ; [.2E92.0020.0002][.2ECC.0020.0002] # <TAI VIET VOWEL AY, TAI VIET LETTER LOW KHO> +AA83 ; [.2E93.0020.0002] # TAI VIET LETTER HIGH KHO +AAB5 AA83 ; [.2E93.0020.0002][.2EC5.0020.0002] # <TAI VIET VOWEL E, TAI VIET LETTER HIGH KHO> +AAB6 AA83 ; [.2E93.0020.0002][.2EC6.0020.0002] # <TAI VIET VOWEL O, TAI VIET LETTER HIGH KHO> +AAB9 AA83 ; [.2E93.0020.0002][.2EC9.0020.0002] # <TAI VIET VOWEL UEA, TAI VIET LETTER HIGH KHO> +AABB AA83 ; [.2E93.0020.0002][.2ECB.0020.0002] # <TAI VIET VOWEL AUE, TAI VIET LETTER HIGH KHO> +AABC AA83 ; [.2E93.0020.0002][.2ECC.0020.0002] # <TAI VIET VOWEL AY, TAI VIET LETTER HIGH KHO> +AA84 ; [.2E94.0020.0002] # TAI VIET LETTER LOW KHHO +AAB5 AA84 ; [.2E94.0020.0002][.2EC5.0020.0002] # <TAI VIET VOWEL E, TAI VIET LETTER LOW KHHO> +AAB6 AA84 ; [.2E94.0020.0002][.2EC6.0020.0002] # <TAI VIET VOWEL O, TAI VIET LETTER LOW KHHO> +AAB9 AA84 ; [.2E94.0020.0002][.2EC9.0020.0002] # <TAI VIET VOWEL UEA, TAI VIET LETTER LOW KHHO> +AABB AA84 ; [.2E94.0020.0002][.2ECB.0020.0002] # <TAI VIET VOWEL AUE, TAI VIET LETTER LOW KHHO> +AABC AA84 ; [.2E94.0020.0002][.2ECC.0020.0002] # <TAI VIET VOWEL AY, TAI VIET LETTER LOW KHHO> +AA85 ; [.2E95.0020.0002] # TAI VIET LETTER HIGH KHHO +AAB5 AA85 ; [.2E95.0020.0002][.2EC5.0020.0002] # <TAI VIET VOWEL E, TAI VIET LETTER HIGH KHHO> +AAB6 AA85 ; [.2E95.0020.0002][.2EC6.0020.0002] # <TAI VIET VOWEL O, TAI VIET LETTER HIGH KHHO> +AAB9 AA85 ; [.2E95.0020.0002][.2EC9.0020.0002] # <TAI VIET VOWEL UEA, TAI VIET LETTER HIGH KHHO> +AABB AA85 ; [.2E95.0020.0002][.2ECB.0020.0002] # <TAI VIET VOWEL AUE, TAI VIET LETTER HIGH KHHO> +AABC AA85 ; [.2E95.0020.0002][.2ECC.0020.0002] # <TAI VIET VOWEL AY, TAI VIET LETTER HIGH KHHO> +AA86 ; [.2E96.0020.0002] # TAI VIET LETTER LOW GO +AAB5 AA86 ; [.2E96.0020.0002][.2EC5.0020.0002] # <TAI VIET VOWEL E, TAI VIET LETTER LOW GO> +AAB6 AA86 ; [.2E96.0020.0002][.2EC6.0020.0002] # <TAI VIET VOWEL O, TAI VIET LETTER LOW GO> +AAB9 AA86 ; [.2E96.0020.0002][.2EC9.0020.0002] # <TAI VIET VOWEL UEA, TAI VIET LETTER LOW GO> +AABB AA86 ; [.2E96.0020.0002][.2ECB.0020.0002] # <TAI VIET VOWEL AUE, TAI VIET LETTER LOW GO> +AABC AA86 ; [.2E96.0020.0002][.2ECC.0020.0002] # <TAI VIET VOWEL AY, TAI VIET LETTER LOW GO> +AA87 ; [.2E97.0020.0002] # TAI VIET LETTER HIGH GO +AAB5 AA87 ; [.2E97.0020.0002][.2EC5.0020.0002] # <TAI VIET VOWEL E, TAI VIET LETTER HIGH GO> +AAB6 AA87 ; [.2E97.0020.0002][.2EC6.0020.0002] # <TAI VIET VOWEL O, TAI VIET LETTER HIGH GO> +AAB9 AA87 ; [.2E97.0020.0002][.2EC9.0020.0002] # <TAI VIET VOWEL UEA, TAI VIET LETTER HIGH GO> +AABB AA87 ; [.2E97.0020.0002][.2ECB.0020.0002] # <TAI VIET VOWEL AUE, TAI VIET LETTER HIGH GO> +AABC AA87 ; [.2E97.0020.0002][.2ECC.0020.0002] # <TAI VIET VOWEL AY, TAI VIET LETTER HIGH GO> +AA88 ; [.2E98.0020.0002] # TAI VIET LETTER LOW NGO +AAB5 AA88 ; [.2E98.0020.0002][.2EC5.0020.0002] # <TAI VIET VOWEL E, TAI VIET LETTER LOW NGO> +AAB6 AA88 ; [.2E98.0020.0002][.2EC6.0020.0002] # <TAI VIET VOWEL O, TAI VIET LETTER LOW NGO> +AAB9 AA88 ; [.2E98.0020.0002][.2EC9.0020.0002] # <TAI VIET VOWEL UEA, TAI VIET LETTER LOW NGO> +AABB AA88 ; [.2E98.0020.0002][.2ECB.0020.0002] # <TAI VIET VOWEL AUE, TAI VIET LETTER LOW NGO> +AABC AA88 ; [.2E98.0020.0002][.2ECC.0020.0002] # <TAI VIET VOWEL AY, TAI VIET LETTER LOW NGO> +AA89 ; [.2E99.0020.0002] # TAI VIET LETTER HIGH NGO +AAB5 AA89 ; [.2E99.0020.0002][.2EC5.0020.0002] # <TAI VIET VOWEL E, TAI VIET LETTER HIGH NGO> +AAB6 AA89 ; [.2E99.0020.0002][.2EC6.0020.0002] # <TAI VIET VOWEL O, TAI VIET LETTER HIGH NGO> +AAB9 AA89 ; [.2E99.0020.0002][.2EC9.0020.0002] # <TAI VIET VOWEL UEA, TAI VIET LETTER HIGH NGO> +AABB AA89 ; [.2E99.0020.0002][.2ECB.0020.0002] # <TAI VIET VOWEL AUE, TAI VIET LETTER HIGH NGO> +AABC AA89 ; [.2E99.0020.0002][.2ECC.0020.0002] # <TAI VIET VOWEL AY, TAI VIET LETTER HIGH NGO> +AA8A ; [.2E9A.0020.0002] # TAI VIET LETTER LOW CO +AAB5 AA8A ; [.2E9A.0020.0002][.2EC5.0020.0002] # <TAI VIET VOWEL E, TAI VIET LETTER LOW CO> +AAB6 AA8A ; [.2E9A.0020.0002][.2EC6.0020.0002] # <TAI VIET VOWEL O, TAI VIET LETTER LOW CO> +AAB9 AA8A ; [.2E9A.0020.0002][.2EC9.0020.0002] # <TAI VIET VOWEL UEA, TAI VIET LETTER LOW CO> +AABB AA8A ; [.2E9A.0020.0002][.2ECB.0020.0002] # <TAI VIET VOWEL AUE, TAI VIET LETTER LOW CO> +AABC AA8A ; [.2E9A.0020.0002][.2ECC.0020.0002] # <TAI VIET VOWEL AY, TAI VIET LETTER LOW CO> +AA8B ; [.2E9B.0020.0002] # TAI VIET LETTER HIGH CO +AAB5 AA8B ; [.2E9B.0020.0002][.2EC5.0020.0002] # <TAI VIET VOWEL E, TAI VIET LETTER HIGH CO> +AAB6 AA8B ; [.2E9B.0020.0002][.2EC6.0020.0002] # <TAI VIET VOWEL O, TAI VIET LETTER HIGH CO> +AAB9 AA8B ; [.2E9B.0020.0002][.2EC9.0020.0002] # <TAI VIET VOWEL UEA, TAI VIET LETTER HIGH CO> +AABB AA8B ; [.2E9B.0020.0002][.2ECB.0020.0002] # <TAI VIET VOWEL AUE, TAI VIET LETTER HIGH CO> +AABC AA8B ; [.2E9B.0020.0002][.2ECC.0020.0002] # <TAI VIET VOWEL AY, TAI VIET LETTER HIGH CO> +AA8C ; [.2E9C.0020.0002] # TAI VIET LETTER LOW CHO +AAB5 AA8C ; [.2E9C.0020.0002][.2EC5.0020.0002] # <TAI VIET VOWEL E, TAI VIET LETTER LOW CHO> +AAB6 AA8C ; [.2E9C.0020.0002][.2EC6.0020.0002] # <TAI VIET VOWEL O, TAI VIET LETTER LOW CHO> +AAB9 AA8C ; [.2E9C.0020.0002][.2EC9.0020.0002] # <TAI VIET VOWEL UEA, TAI VIET LETTER LOW CHO> +AABB AA8C ; [.2E9C.0020.0002][.2ECB.0020.0002] # <TAI VIET VOWEL AUE, TAI VIET LETTER LOW CHO> +AABC AA8C ; [.2E9C.0020.0002][.2ECC.0020.0002] # <TAI VIET VOWEL AY, TAI VIET LETTER LOW CHO> +AA8D ; [.2E9D.0020.0002] # TAI VIET LETTER HIGH CHO +AAB5 AA8D ; [.2E9D.0020.0002][.2EC5.0020.0002] # <TAI VIET VOWEL E, TAI VIET LETTER HIGH CHO> +AAB6 AA8D ; [.2E9D.0020.0002][.2EC6.0020.0002] # <TAI VIET VOWEL O, TAI VIET LETTER HIGH CHO> +AAB9 AA8D ; [.2E9D.0020.0002][.2EC9.0020.0002] # <TAI VIET VOWEL UEA, TAI VIET LETTER HIGH CHO> +AABB AA8D ; [.2E9D.0020.0002][.2ECB.0020.0002] # <TAI VIET VOWEL AUE, TAI VIET LETTER HIGH CHO> +AABC AA8D ; [.2E9D.0020.0002][.2ECC.0020.0002] # <TAI VIET VOWEL AY, TAI VIET LETTER HIGH CHO> +AA8E ; [.2E9E.0020.0002] # TAI VIET LETTER LOW SO +AAB5 AA8E ; [.2E9E.0020.0002][.2EC5.0020.0002] # <TAI VIET VOWEL E, TAI VIET LETTER LOW SO> +AAB6 AA8E ; [.2E9E.0020.0002][.2EC6.0020.0002] # <TAI VIET VOWEL O, TAI VIET LETTER LOW SO> +AAB9 AA8E ; [.2E9E.0020.0002][.2EC9.0020.0002] # <TAI VIET VOWEL UEA, TAI VIET LETTER LOW SO> +AABB AA8E ; [.2E9E.0020.0002][.2ECB.0020.0002] # <TAI VIET VOWEL AUE, TAI VIET LETTER LOW SO> +AABC AA8E ; [.2E9E.0020.0002][.2ECC.0020.0002] # <TAI VIET VOWEL AY, TAI VIET LETTER LOW SO> +AA8F ; [.2E9F.0020.0002] # TAI VIET LETTER HIGH SO +AAB5 AA8F ; [.2E9F.0020.0002][.2EC5.0020.0002] # <TAI VIET VOWEL E, TAI VIET LETTER HIGH SO> +AAB6 AA8F ; [.2E9F.0020.0002][.2EC6.0020.0002] # <TAI VIET VOWEL O, TAI VIET LETTER HIGH SO> +AAB9 AA8F ; [.2E9F.0020.0002][.2EC9.0020.0002] # <TAI VIET VOWEL UEA, TAI VIET LETTER HIGH SO> +AABB AA8F ; [.2E9F.0020.0002][.2ECB.0020.0002] # <TAI VIET VOWEL AUE, TAI VIET LETTER HIGH SO> +AABC AA8F ; [.2E9F.0020.0002][.2ECC.0020.0002] # <TAI VIET VOWEL AY, TAI VIET LETTER HIGH SO> +AA90 ; [.2EA0.0020.0002] # TAI VIET LETTER LOW NYO +AAB5 AA90 ; [.2EA0.0020.0002][.2EC5.0020.0002] # <TAI VIET VOWEL E, TAI VIET LETTER LOW NYO> +AAB6 AA90 ; [.2EA0.0020.0002][.2EC6.0020.0002] # <TAI VIET VOWEL O, TAI VIET LETTER LOW NYO> +AAB9 AA90 ; [.2EA0.0020.0002][.2EC9.0020.0002] # <TAI VIET VOWEL UEA, TAI VIET LETTER LOW NYO> +AABB AA90 ; [.2EA0.0020.0002][.2ECB.0020.0002] # <TAI VIET VOWEL AUE, TAI VIET LETTER LOW NYO> +AABC AA90 ; [.2EA0.0020.0002][.2ECC.0020.0002] # <TAI VIET VOWEL AY, TAI VIET LETTER LOW NYO> +AA91 ; [.2EA1.0020.0002] # TAI VIET LETTER HIGH NYO +AAB5 AA91 ; [.2EA1.0020.0002][.2EC5.0020.0002] # <TAI VIET VOWEL E, TAI VIET LETTER HIGH NYO> +AAB6 AA91 ; [.2EA1.0020.0002][.2EC6.0020.0002] # <TAI VIET VOWEL O, TAI VIET LETTER HIGH NYO> +AAB9 AA91 ; [.2EA1.0020.0002][.2EC9.0020.0002] # <TAI VIET VOWEL UEA, TAI VIET LETTER HIGH NYO> +AABB AA91 ; [.2EA1.0020.0002][.2ECB.0020.0002] # <TAI VIET VOWEL AUE, TAI VIET LETTER HIGH NYO> +AABC AA91 ; [.2EA1.0020.0002][.2ECC.0020.0002] # <TAI VIET VOWEL AY, TAI VIET LETTER HIGH NYO> +AA92 ; [.2EA2.0020.0002] # TAI VIET LETTER LOW DO +AAB5 AA92 ; [.2EA2.0020.0002][.2EC5.0020.0002] # <TAI VIET VOWEL E, TAI VIET LETTER LOW DO> +AAB6 AA92 ; [.2EA2.0020.0002][.2EC6.0020.0002] # <TAI VIET VOWEL O, TAI VIET LETTER LOW DO> +AAB9 AA92 ; [.2EA2.0020.0002][.2EC9.0020.0002] # <TAI VIET VOWEL UEA, TAI VIET LETTER LOW DO> +AABB AA92 ; [.2EA2.0020.0002][.2ECB.0020.0002] # <TAI VIET VOWEL AUE, TAI VIET LETTER LOW DO> +AABC AA92 ; [.2EA2.0020.0002][.2ECC.0020.0002] # <TAI VIET VOWEL AY, TAI VIET LETTER LOW DO> +AA93 ; [.2EA3.0020.0002] # TAI VIET LETTER HIGH DO +AAB5 AA93 ; [.2EA3.0020.0002][.2EC5.0020.0002] # <TAI VIET VOWEL E, TAI VIET LETTER HIGH DO> +AAB6 AA93 ; [.2EA3.0020.0002][.2EC6.0020.0002] # <TAI VIET VOWEL O, TAI VIET LETTER HIGH DO> +AAB9 AA93 ; [.2EA3.0020.0002][.2EC9.0020.0002] # <TAI VIET VOWEL UEA, TAI VIET LETTER HIGH DO> +AABB AA93 ; [.2EA3.0020.0002][.2ECB.0020.0002] # <TAI VIET VOWEL AUE, TAI VIET LETTER HIGH DO> +AABC AA93 ; [.2EA3.0020.0002][.2ECC.0020.0002] # <TAI VIET VOWEL AY, TAI VIET LETTER HIGH DO> +AA94 ; [.2EA4.0020.0002] # TAI VIET LETTER LOW TO +AAB5 AA94 ; [.2EA4.0020.0002][.2EC5.0020.0002] # <TAI VIET VOWEL E, TAI VIET LETTER LOW TO> +AAB6 AA94 ; [.2EA4.0020.0002][.2EC6.0020.0002] # <TAI VIET VOWEL O, TAI VIET LETTER LOW TO> +AAB9 AA94 ; [.2EA4.0020.0002][.2EC9.0020.0002] # <TAI VIET VOWEL UEA, TAI VIET LETTER LOW TO> +AABB AA94 ; [.2EA4.0020.0002][.2ECB.0020.0002] # <TAI VIET VOWEL AUE, TAI VIET LETTER LOW TO> +AABC AA94 ; [.2EA4.0020.0002][.2ECC.0020.0002] # <TAI VIET VOWEL AY, TAI VIET LETTER LOW TO> +AA95 ; [.2EA5.0020.0002] # TAI VIET LETTER HIGH TO +AAB5 AA95 ; [.2EA5.0020.0002][.2EC5.0020.0002] # <TAI VIET VOWEL E, TAI VIET LETTER HIGH TO> +AAB6 AA95 ; [.2EA5.0020.0002][.2EC6.0020.0002] # <TAI VIET VOWEL O, TAI VIET LETTER HIGH TO> +AAB9 AA95 ; [.2EA5.0020.0002][.2EC9.0020.0002] # <TAI VIET VOWEL UEA, TAI VIET LETTER HIGH TO> +AABB AA95 ; [.2EA5.0020.0002][.2ECB.0020.0002] # <TAI VIET VOWEL AUE, TAI VIET LETTER HIGH TO> +AABC AA95 ; [.2EA5.0020.0002][.2ECC.0020.0002] # <TAI VIET VOWEL AY, TAI VIET LETTER HIGH TO> +AA96 ; [.2EA6.0020.0002] # TAI VIET LETTER LOW THO +AAB5 AA96 ; [.2EA6.0020.0002][.2EC5.0020.0002] # <TAI VIET VOWEL E, TAI VIET LETTER LOW THO> +AAB6 AA96 ; [.2EA6.0020.0002][.2EC6.0020.0002] # <TAI VIET VOWEL O, TAI VIET LETTER LOW THO> +AAB9 AA96 ; [.2EA6.0020.0002][.2EC9.0020.0002] # <TAI VIET VOWEL UEA, TAI VIET LETTER LOW THO> +AABB AA96 ; [.2EA6.0020.0002][.2ECB.0020.0002] # <TAI VIET VOWEL AUE, TAI VIET LETTER LOW THO> +AABC AA96 ; [.2EA6.0020.0002][.2ECC.0020.0002] # <TAI VIET VOWEL AY, TAI VIET LETTER LOW THO> +AA97 ; [.2EA7.0020.0002] # TAI VIET LETTER HIGH THO +AAB5 AA97 ; [.2EA7.0020.0002][.2EC5.0020.0002] # <TAI VIET VOWEL E, TAI VIET LETTER HIGH THO> +AAB6 AA97 ; [.2EA7.0020.0002][.2EC6.0020.0002] # <TAI VIET VOWEL O, TAI VIET LETTER HIGH THO> +AAB9 AA97 ; [.2EA7.0020.0002][.2EC9.0020.0002] # <TAI VIET VOWEL UEA, TAI VIET LETTER HIGH THO> +AABB AA97 ; [.2EA7.0020.0002][.2ECB.0020.0002] # <TAI VIET VOWEL AUE, TAI VIET LETTER HIGH THO> +AABC AA97 ; [.2EA7.0020.0002][.2ECC.0020.0002] # <TAI VIET VOWEL AY, TAI VIET LETTER HIGH THO> +AA98 ; [.2EA8.0020.0002] # TAI VIET LETTER LOW NO +AAB5 AA98 ; [.2EA8.0020.0002][.2EC5.0020.0002] # <TAI VIET VOWEL E, TAI VIET LETTER LOW NO> +AAB6 AA98 ; [.2EA8.0020.0002][.2EC6.0020.0002] # <TAI VIET VOWEL O, TAI VIET LETTER LOW NO> +AAB9 AA98 ; [.2EA8.0020.0002][.2EC9.0020.0002] # <TAI VIET VOWEL UEA, TAI VIET LETTER LOW NO> +AABB AA98 ; [.2EA8.0020.0002][.2ECB.0020.0002] # <TAI VIET VOWEL AUE, TAI VIET LETTER LOW NO> +AABC AA98 ; [.2EA8.0020.0002][.2ECC.0020.0002] # <TAI VIET VOWEL AY, TAI VIET LETTER LOW NO> +AA99 ; [.2EA9.0020.0002] # TAI VIET LETTER HIGH NO +AAB5 AA99 ; [.2EA9.0020.0002][.2EC5.0020.0002] # <TAI VIET VOWEL E, TAI VIET LETTER HIGH NO> +AAB6 AA99 ; [.2EA9.0020.0002][.2EC6.0020.0002] # <TAI VIET VOWEL O, TAI VIET LETTER HIGH NO> +AAB9 AA99 ; [.2EA9.0020.0002][.2EC9.0020.0002] # <TAI VIET VOWEL UEA, TAI VIET LETTER HIGH NO> +AABB AA99 ; [.2EA9.0020.0002][.2ECB.0020.0002] # <TAI VIET VOWEL AUE, TAI VIET LETTER HIGH NO> +AABC AA99 ; [.2EA9.0020.0002][.2ECC.0020.0002] # <TAI VIET VOWEL AY, TAI VIET LETTER HIGH NO> +AA9A ; [.2EAA.0020.0002] # TAI VIET LETTER LOW BO +AAB5 AA9A ; [.2EAA.0020.0002][.2EC5.0020.0002] # <TAI VIET VOWEL E, TAI VIET LETTER LOW BO> +AAB6 AA9A ; [.2EAA.0020.0002][.2EC6.0020.0002] # <TAI VIET VOWEL O, TAI VIET LETTER LOW BO> +AAB9 AA9A ; [.2EAA.0020.0002][.2EC9.0020.0002] # <TAI VIET VOWEL UEA, TAI VIET LETTER LOW BO> +AABB AA9A ; [.2EAA.0020.0002][.2ECB.0020.0002] # <TAI VIET VOWEL AUE, TAI VIET LETTER LOW BO> +AABC AA9A ; [.2EAA.0020.0002][.2ECC.0020.0002] # <TAI VIET VOWEL AY, TAI VIET LETTER LOW BO> +AA9B ; [.2EAB.0020.0002] # TAI VIET LETTER HIGH BO +AAB5 AA9B ; [.2EAB.0020.0002][.2EC5.0020.0002] # <TAI VIET VOWEL E, TAI VIET LETTER HIGH BO> +AAB6 AA9B ; [.2EAB.0020.0002][.2EC6.0020.0002] # <TAI VIET VOWEL O, TAI VIET LETTER HIGH BO> +AAB9 AA9B ; [.2EAB.0020.0002][.2EC9.0020.0002] # <TAI VIET VOWEL UEA, TAI VIET LETTER HIGH BO> +AABB AA9B ; [.2EAB.0020.0002][.2ECB.0020.0002] # <TAI VIET VOWEL AUE, TAI VIET LETTER HIGH BO> +AABC AA9B ; [.2EAB.0020.0002][.2ECC.0020.0002] # <TAI VIET VOWEL AY, TAI VIET LETTER HIGH BO> +AA9C ; [.2EAC.0020.0002] # TAI VIET LETTER LOW PO +AAB5 AA9C ; [.2EAC.0020.0002][.2EC5.0020.0002] # <TAI VIET VOWEL E, TAI VIET LETTER LOW PO> +AAB6 AA9C ; [.2EAC.0020.0002][.2EC6.0020.0002] # <TAI VIET VOWEL O, TAI VIET LETTER LOW PO> +AAB9 AA9C ; [.2EAC.0020.0002][.2EC9.0020.0002] # <TAI VIET VOWEL UEA, TAI VIET LETTER LOW PO> +AABB AA9C ; [.2EAC.0020.0002][.2ECB.0020.0002] # <TAI VIET VOWEL AUE, TAI VIET LETTER LOW PO> +AABC AA9C ; [.2EAC.0020.0002][.2ECC.0020.0002] # <TAI VIET VOWEL AY, TAI VIET LETTER LOW PO> +AA9D ; [.2EAD.0020.0002] # TAI VIET LETTER HIGH PO +AAB5 AA9D ; [.2EAD.0020.0002][.2EC5.0020.0002] # <TAI VIET VOWEL E, TAI VIET LETTER HIGH PO> +AAB6 AA9D ; [.2EAD.0020.0002][.2EC6.0020.0002] # <TAI VIET VOWEL O, TAI VIET LETTER HIGH PO> +AAB9 AA9D ; [.2EAD.0020.0002][.2EC9.0020.0002] # <TAI VIET VOWEL UEA, TAI VIET LETTER HIGH PO> +AABB AA9D ; [.2EAD.0020.0002][.2ECB.0020.0002] # <TAI VIET VOWEL AUE, TAI VIET LETTER HIGH PO> +AABC AA9D ; [.2EAD.0020.0002][.2ECC.0020.0002] # <TAI VIET VOWEL AY, TAI VIET LETTER HIGH PO> +AA9E ; [.2EAE.0020.0002] # TAI VIET LETTER LOW PHO +AAB5 AA9E ; [.2EAE.0020.0002][.2EC5.0020.0002] # <TAI VIET VOWEL E, TAI VIET LETTER LOW PHO> +AAB6 AA9E ; [.2EAE.0020.0002][.2EC6.0020.0002] # <TAI VIET VOWEL O, TAI VIET LETTER LOW PHO> +AAB9 AA9E ; [.2EAE.0020.0002][.2EC9.0020.0002] # <TAI VIET VOWEL UEA, TAI VIET LETTER LOW PHO> +AABB AA9E ; [.2EAE.0020.0002][.2ECB.0020.0002] # <TAI VIET VOWEL AUE, TAI VIET LETTER LOW PHO> +AABC AA9E ; [.2EAE.0020.0002][.2ECC.0020.0002] # <TAI VIET VOWEL AY, TAI VIET LETTER LOW PHO> +AA9F ; [.2EAF.0020.0002] # TAI VIET LETTER HIGH PHO +AAB5 AA9F ; [.2EAF.0020.0002][.2EC5.0020.0002] # <TAI VIET VOWEL E, TAI VIET LETTER HIGH PHO> +AAB6 AA9F ; [.2EAF.0020.0002][.2EC6.0020.0002] # <TAI VIET VOWEL O, TAI VIET LETTER HIGH PHO> +AAB9 AA9F ; [.2EAF.0020.0002][.2EC9.0020.0002] # <TAI VIET VOWEL UEA, TAI VIET LETTER HIGH PHO> +AABB AA9F ; [.2EAF.0020.0002][.2ECB.0020.0002] # <TAI VIET VOWEL AUE, TAI VIET LETTER HIGH PHO> +AABC AA9F ; [.2EAF.0020.0002][.2ECC.0020.0002] # <TAI VIET VOWEL AY, TAI VIET LETTER HIGH PHO> +AAA0 ; [.2EB0.0020.0002] # TAI VIET LETTER LOW FO +AAB5 AAA0 ; [.2EB0.0020.0002][.2EC5.0020.0002] # <TAI VIET VOWEL E, TAI VIET LETTER LOW FO> +AAB6 AAA0 ; [.2EB0.0020.0002][.2EC6.0020.0002] # <TAI VIET VOWEL O, TAI VIET LETTER LOW FO> +AAB9 AAA0 ; [.2EB0.0020.0002][.2EC9.0020.0002] # <TAI VIET VOWEL UEA, TAI VIET LETTER LOW FO> +AABB AAA0 ; [.2EB0.0020.0002][.2ECB.0020.0002] # <TAI VIET VOWEL AUE, TAI VIET LETTER LOW FO> +AABC AAA0 ; [.2EB0.0020.0002][.2ECC.0020.0002] # <TAI VIET VOWEL AY, TAI VIET LETTER LOW FO> +AAA1 ; [.2EB1.0020.0002] # TAI VIET LETTER HIGH FO +AAB5 AAA1 ; [.2EB1.0020.0002][.2EC5.0020.0002] # <TAI VIET VOWEL E, TAI VIET LETTER HIGH FO> +AAB6 AAA1 ; [.2EB1.0020.0002][.2EC6.0020.0002] # <TAI VIET VOWEL O, TAI VIET LETTER HIGH FO> +AAB9 AAA1 ; [.2EB1.0020.0002][.2EC9.0020.0002] # <TAI VIET VOWEL UEA, TAI VIET LETTER HIGH FO> +AABB AAA1 ; [.2EB1.0020.0002][.2ECB.0020.0002] # <TAI VIET VOWEL AUE, TAI VIET LETTER HIGH FO> +AABC AAA1 ; [.2EB1.0020.0002][.2ECC.0020.0002] # <TAI VIET VOWEL AY, TAI VIET LETTER HIGH FO> +AAA2 ; [.2EB2.0020.0002] # TAI VIET LETTER LOW MO +AAB5 AAA2 ; [.2EB2.0020.0002][.2EC5.0020.0002] # <TAI VIET VOWEL E, TAI VIET LETTER LOW MO> +AAB6 AAA2 ; [.2EB2.0020.0002][.2EC6.0020.0002] # <TAI VIET VOWEL O, TAI VIET LETTER LOW MO> +AAB9 AAA2 ; [.2EB2.0020.0002][.2EC9.0020.0002] # <TAI VIET VOWEL UEA, TAI VIET LETTER LOW MO> +AABB AAA2 ; [.2EB2.0020.0002][.2ECB.0020.0002] # <TAI VIET VOWEL AUE, TAI VIET LETTER LOW MO> +AABC AAA2 ; [.2EB2.0020.0002][.2ECC.0020.0002] # <TAI VIET VOWEL AY, TAI VIET LETTER LOW MO> +AAA3 ; [.2EB3.0020.0002] # TAI VIET LETTER HIGH MO +AAB5 AAA3 ; [.2EB3.0020.0002][.2EC5.0020.0002] # <TAI VIET VOWEL E, TAI VIET LETTER HIGH MO> +AAB6 AAA3 ; [.2EB3.0020.0002][.2EC6.0020.0002] # <TAI VIET VOWEL O, TAI VIET LETTER HIGH MO> +AAB9 AAA3 ; [.2EB3.0020.0002][.2EC9.0020.0002] # <TAI VIET VOWEL UEA, TAI VIET LETTER HIGH MO> +AABB AAA3 ; [.2EB3.0020.0002][.2ECB.0020.0002] # <TAI VIET VOWEL AUE, TAI VIET LETTER HIGH MO> +AABC AAA3 ; [.2EB3.0020.0002][.2ECC.0020.0002] # <TAI VIET VOWEL AY, TAI VIET LETTER HIGH MO> +AAA4 ; [.2EB4.0020.0002] # TAI VIET LETTER LOW YO +AAB5 AAA4 ; [.2EB4.0020.0002][.2EC5.0020.0002] # <TAI VIET VOWEL E, TAI VIET LETTER LOW YO> +AAB6 AAA4 ; [.2EB4.0020.0002][.2EC6.0020.0002] # <TAI VIET VOWEL O, TAI VIET LETTER LOW YO> +AAB9 AAA4 ; [.2EB4.0020.0002][.2EC9.0020.0002] # <TAI VIET VOWEL UEA, TAI VIET LETTER LOW YO> +AABB AAA4 ; [.2EB4.0020.0002][.2ECB.0020.0002] # <TAI VIET VOWEL AUE, TAI VIET LETTER LOW YO> +AABC AAA4 ; [.2EB4.0020.0002][.2ECC.0020.0002] # <TAI VIET VOWEL AY, TAI VIET LETTER LOW YO> +AAA5 ; [.2EB5.0020.0002] # TAI VIET LETTER HIGH YO +AAB5 AAA5 ; [.2EB5.0020.0002][.2EC5.0020.0002] # <TAI VIET VOWEL E, TAI VIET LETTER HIGH YO> +AAB6 AAA5 ; [.2EB5.0020.0002][.2EC6.0020.0002] # <TAI VIET VOWEL O, TAI VIET LETTER HIGH YO> +AAB9 AAA5 ; [.2EB5.0020.0002][.2EC9.0020.0002] # <TAI VIET VOWEL UEA, TAI VIET LETTER HIGH YO> +AABB AAA5 ; [.2EB5.0020.0002][.2ECB.0020.0002] # <TAI VIET VOWEL AUE, TAI VIET LETTER HIGH YO> +AABC AAA5 ; [.2EB5.0020.0002][.2ECC.0020.0002] # <TAI VIET VOWEL AY, TAI VIET LETTER HIGH YO> +AAA6 ; [.2EB6.0020.0002] # TAI VIET LETTER LOW RO +AAB5 AAA6 ; [.2EB6.0020.0002][.2EC5.0020.0002] # <TAI VIET VOWEL E, TAI VIET LETTER LOW RO> +AAB6 AAA6 ; [.2EB6.0020.0002][.2EC6.0020.0002] # <TAI VIET VOWEL O, TAI VIET LETTER LOW RO> +AAB9 AAA6 ; [.2EB6.0020.0002][.2EC9.0020.0002] # <TAI VIET VOWEL UEA, TAI VIET LETTER LOW RO> +AABB AAA6 ; [.2EB6.0020.0002][.2ECB.0020.0002] # <TAI VIET VOWEL AUE, TAI VIET LETTER LOW RO> +AABC AAA6 ; [.2EB6.0020.0002][.2ECC.0020.0002] # <TAI VIET VOWEL AY, TAI VIET LETTER LOW RO> +AAA7 ; [.2EB7.0020.0002] # TAI VIET LETTER HIGH RO +AAB5 AAA7 ; [.2EB7.0020.0002][.2EC5.0020.0002] # <TAI VIET VOWEL E, TAI VIET LETTER HIGH RO> +AAB6 AAA7 ; [.2EB7.0020.0002][.2EC6.0020.0002] # <TAI VIET VOWEL O, TAI VIET LETTER HIGH RO> +AAB9 AAA7 ; [.2EB7.0020.0002][.2EC9.0020.0002] # <TAI VIET VOWEL UEA, TAI VIET LETTER HIGH RO> +AABB AAA7 ; [.2EB7.0020.0002][.2ECB.0020.0002] # <TAI VIET VOWEL AUE, TAI VIET LETTER HIGH RO> +AABC AAA7 ; [.2EB7.0020.0002][.2ECC.0020.0002] # <TAI VIET VOWEL AY, TAI VIET LETTER HIGH RO> +AAA8 ; [.2EB8.0020.0002] # TAI VIET LETTER LOW LO +AAB5 AAA8 ; [.2EB8.0020.0002][.2EC5.0020.0002] # <TAI VIET VOWEL E, TAI VIET LETTER LOW LO> +AAB6 AAA8 ; [.2EB8.0020.0002][.2EC6.0020.0002] # <TAI VIET VOWEL O, TAI VIET LETTER LOW LO> +AAB9 AAA8 ; [.2EB8.0020.0002][.2EC9.0020.0002] # <TAI VIET VOWEL UEA, TAI VIET LETTER LOW LO> +AABB AAA8 ; [.2EB8.0020.0002][.2ECB.0020.0002] # <TAI VIET VOWEL AUE, TAI VIET LETTER LOW LO> +AABC AAA8 ; [.2EB8.0020.0002][.2ECC.0020.0002] # <TAI VIET VOWEL AY, TAI VIET LETTER LOW LO> +AAA9 ; [.2EB9.0020.0002] # TAI VIET LETTER HIGH LO +AAB5 AAA9 ; [.2EB9.0020.0002][.2EC5.0020.0002] # <TAI VIET VOWEL E, TAI VIET LETTER HIGH LO> +AAB6 AAA9 ; [.2EB9.0020.0002][.2EC6.0020.0002] # <TAI VIET VOWEL O, TAI VIET LETTER HIGH LO> +AAB9 AAA9 ; [.2EB9.0020.0002][.2EC9.0020.0002] # <TAI VIET VOWEL UEA, TAI VIET LETTER HIGH LO> +AABB AAA9 ; [.2EB9.0020.0002][.2ECB.0020.0002] # <TAI VIET VOWEL AUE, TAI VIET LETTER HIGH LO> +AABC AAA9 ; [.2EB9.0020.0002][.2ECC.0020.0002] # <TAI VIET VOWEL AY, TAI VIET LETTER HIGH LO> +AAAA ; [.2EBA.0020.0002] # TAI VIET LETTER LOW VO +AAB5 AAAA ; [.2EBA.0020.0002][.2EC5.0020.0002] # <TAI VIET VOWEL E, TAI VIET LETTER LOW VO> +AAB6 AAAA ; [.2EBA.0020.0002][.2EC6.0020.0002] # <TAI VIET VOWEL O, TAI VIET LETTER LOW VO> +AAB9 AAAA ; [.2EBA.0020.0002][.2EC9.0020.0002] # <TAI VIET VOWEL UEA, TAI VIET LETTER LOW VO> +AABB AAAA ; [.2EBA.0020.0002][.2ECB.0020.0002] # <TAI VIET VOWEL AUE, TAI VIET LETTER LOW VO> +AABC AAAA ; [.2EBA.0020.0002][.2ECC.0020.0002] # <TAI VIET VOWEL AY, TAI VIET LETTER LOW VO> +AAAB ; [.2EBB.0020.0002] # TAI VIET LETTER HIGH VO +AAB5 AAAB ; [.2EBB.0020.0002][.2EC5.0020.0002] # <TAI VIET VOWEL E, TAI VIET LETTER HIGH VO> +AAB6 AAAB ; [.2EBB.0020.0002][.2EC6.0020.0002] # <TAI VIET VOWEL O, TAI VIET LETTER HIGH VO> +AAB9 AAAB ; [.2EBB.0020.0002][.2EC9.0020.0002] # <TAI VIET VOWEL UEA, TAI VIET LETTER HIGH VO> +AABB AAAB ; [.2EBB.0020.0002][.2ECB.0020.0002] # <TAI VIET VOWEL AUE, TAI VIET LETTER HIGH VO> +AABC AAAB ; [.2EBB.0020.0002][.2ECC.0020.0002] # <TAI VIET VOWEL AY, TAI VIET LETTER HIGH VO> +AAAC ; [.2EBC.0020.0002] # TAI VIET LETTER LOW HO +AAB5 AAAC ; [.2EBC.0020.0002][.2EC5.0020.0002] # <TAI VIET VOWEL E, TAI VIET LETTER LOW HO> +AAB6 AAAC ; [.2EBC.0020.0002][.2EC6.0020.0002] # <TAI VIET VOWEL O, TAI VIET LETTER LOW HO> +AAB9 AAAC ; [.2EBC.0020.0002][.2EC9.0020.0002] # <TAI VIET VOWEL UEA, TAI VIET LETTER LOW HO> +AABB AAAC ; [.2EBC.0020.0002][.2ECB.0020.0002] # <TAI VIET VOWEL AUE, TAI VIET LETTER LOW HO> +AABC AAAC ; [.2EBC.0020.0002][.2ECC.0020.0002] # <TAI VIET VOWEL AY, TAI VIET LETTER LOW HO> +AAAD ; [.2EBD.0020.0002] # TAI VIET LETTER HIGH HO +AAB5 AAAD ; [.2EBD.0020.0002][.2EC5.0020.0002] # <TAI VIET VOWEL E, TAI VIET LETTER HIGH HO> +AAB6 AAAD ; [.2EBD.0020.0002][.2EC6.0020.0002] # <TAI VIET VOWEL O, TAI VIET LETTER HIGH HO> +AAB9 AAAD ; [.2EBD.0020.0002][.2EC9.0020.0002] # <TAI VIET VOWEL UEA, TAI VIET LETTER HIGH HO> +AABB AAAD ; [.2EBD.0020.0002][.2ECB.0020.0002] # <TAI VIET VOWEL AUE, TAI VIET LETTER HIGH HO> +AABC AAAD ; [.2EBD.0020.0002][.2ECC.0020.0002] # <TAI VIET VOWEL AY, TAI VIET LETTER HIGH HO> +AAAE ; [.2EBE.0020.0002] # TAI VIET LETTER LOW O +AAB5 AAAE ; [.2EBE.0020.0002][.2EC5.0020.0002] # <TAI VIET VOWEL E, TAI VIET LETTER LOW O> +AAB6 AAAE ; [.2EBE.0020.0002][.2EC6.0020.0002] # <TAI VIET VOWEL O, TAI VIET LETTER LOW O> +AAB9 AAAE ; [.2EBE.0020.0002][.2EC9.0020.0002] # <TAI VIET VOWEL UEA, TAI VIET LETTER LOW O> +AABB AAAE ; [.2EBE.0020.0002][.2ECB.0020.0002] # <TAI VIET VOWEL AUE, TAI VIET LETTER LOW O> +AABC AAAE ; [.2EBE.0020.0002][.2ECC.0020.0002] # <TAI VIET VOWEL AY, TAI VIET LETTER LOW O> +AAAF ; [.2EBF.0020.0002] # TAI VIET LETTER HIGH O +AAB5 AAAF ; [.2EBF.0020.0002][.2EC5.0020.0002] # <TAI VIET VOWEL E, TAI VIET LETTER HIGH O> +AAB6 AAAF ; [.2EBF.0020.0002][.2EC6.0020.0002] # <TAI VIET VOWEL O, TAI VIET LETTER HIGH O> +AAB9 AAAF ; [.2EBF.0020.0002][.2EC9.0020.0002] # <TAI VIET VOWEL UEA, TAI VIET LETTER HIGH O> +AABB AAAF ; [.2EBF.0020.0002][.2ECB.0020.0002] # <TAI VIET VOWEL AUE, TAI VIET LETTER HIGH O> +AABC AAAF ; [.2EBF.0020.0002][.2ECC.0020.0002] # <TAI VIET VOWEL AY, TAI VIET LETTER HIGH O> +AAB0 ; [.2EC0.0020.0002] # TAI VIET MAI KANG +AAB1 ; [.2EC1.0020.0002] # TAI VIET VOWEL AA +AAB2 ; [.2EC2.0020.0002] # TAI VIET VOWEL I +AAB3 ; [.2EC3.0020.0002] # TAI VIET VOWEL UE +AAB4 ; [.2EC4.0020.0002] # TAI VIET VOWEL U +AAB5 ; [.2EC5.0020.0002] # TAI VIET VOWEL E +AAB6 ; [.2EC6.0020.0002] # TAI VIET VOWEL O +AAB7 ; [.2EC7.0020.0002] # TAI VIET MAI KHIT +AAB8 ; [.2EC8.0020.0002] # TAI VIET VOWEL IA +AAB9 ; [.2EC9.0020.0002] # TAI VIET VOWEL UEA +AABA ; [.2ECA.0020.0002] # TAI VIET VOWEL UA +AABB ; [.2ECB.0020.0002] # TAI VIET VOWEL AUE +AABC ; [.2ECC.0020.0002] # TAI VIET VOWEL AY +AABD ; [.2ECD.0020.0002] # TAI VIET VOWEL AN +AABE ; [.2ECE.0020.0002] # TAI VIET VOWEL AM +AAC0 ; [.2ECF.0020.0002] # TAI VIET TONE MAI NUENG +AAC2 ; [.2ED0.0020.0002] # TAI VIET TONE MAI SONG +AADB ; [.2ED1.0020.0002] # TAI VIET SYMBOL KON +AADC ; [.2ED2.0020.0002] # TAI VIET SYMBOL NUENG +0F40 ; [.2ED3.0020.0002] # TIBETAN LETTER KA +0F69 ; [.2ED3.0020.0002][.2F14.0020.0002] # TIBETAN LETTER KSSA +0F90 ; [.2ED4.0020.0002] # TIBETAN SUBJOINED LETTER KA +0FB9 ; [.2ED4.0020.0002][.2F14.0020.0002] # TIBETAN SUBJOINED LETTER KSSA +0F6B ; [.2ED5.0020.0002] # TIBETAN LETTER KKA +0F41 ; [.2ED6.0020.0002] # TIBETAN LETTER KHA +0F91 ; [.2ED7.0020.0002] # TIBETAN SUBJOINED LETTER KHA +0F42 ; [.2ED8.0020.0002] # TIBETAN LETTER GA +0F43 ; [.2ED8.0020.0002][.2F18.0020.0002] # TIBETAN LETTER GHA +0F92 ; [.2ED9.0020.0002] # TIBETAN SUBJOINED LETTER GA +0F93 ; [.2ED9.0020.0002][.2F18.0020.0002] # TIBETAN SUBJOINED LETTER GHA +0F44 ; [.2EDA.0020.0002] # TIBETAN LETTER NGA +0F94 ; [.2EDB.0020.0002] # TIBETAN SUBJOINED LETTER NGA +0F45 ; [.2EDC.0020.0002] # TIBETAN LETTER CA +0F95 ; [.2EDD.0020.0002] # TIBETAN SUBJOINED LETTER CA +0F46 ; [.2EDE.0020.0002] # TIBETAN LETTER CHA +0F96 ; [.2EDF.0020.0002] # TIBETAN SUBJOINED LETTER CHA +0F47 ; [.2EE0.0020.0002] # TIBETAN LETTER JA +0F97 ; [.2EE1.0020.0002] # TIBETAN SUBJOINED LETTER JA +0F49 ; [.2EE2.0020.0002] # TIBETAN LETTER NYA +0F99 ; [.2EE3.0020.0002] # TIBETAN SUBJOINED LETTER NYA +0F4A ; [.2EE4.0020.0002] # TIBETAN LETTER TTA +0F9A ; [.2EE5.0020.0002] # TIBETAN SUBJOINED LETTER TTA +0F4B ; [.2EE6.0020.0002] # TIBETAN LETTER TTHA +0F9B ; [.2EE7.0020.0002] # TIBETAN SUBJOINED LETTER TTHA +0F4C ; [.2EE8.0020.0002] # TIBETAN LETTER DDA +0F4D ; [.2EE8.0020.0002][.2F18.0020.0002] # TIBETAN LETTER DDHA +0F9C ; [.2EE9.0020.0002] # TIBETAN SUBJOINED LETTER DDA +0F9D ; [.2EE9.0020.0002][.2F18.0020.0002] # TIBETAN SUBJOINED LETTER DDHA +0F4E ; [.2EEA.0020.0002] # TIBETAN LETTER NNA +0F9E ; [.2EEB.0020.0002] # TIBETAN SUBJOINED LETTER NNA +0F4F ; [.2EEC.0020.0002] # TIBETAN LETTER TA +0F9F ; [.2EED.0020.0002] # TIBETAN SUBJOINED LETTER TA +0F50 ; [.2EEE.0020.0002] # TIBETAN LETTER THA +0FA0 ; [.2EEF.0020.0002] # TIBETAN SUBJOINED LETTER THA +0F51 ; [.2EF0.0020.0002] # TIBETAN LETTER DA +0F52 ; [.2EF0.0020.0002][.2F18.0020.0002] # TIBETAN LETTER DHA +0FA1 ; [.2EF1.0020.0002] # TIBETAN SUBJOINED LETTER DA +0FA2 ; [.2EF1.0020.0002][.2F18.0020.0002] # TIBETAN SUBJOINED LETTER DHA +0F53 ; [.2EF2.0020.0002] # TIBETAN LETTER NA +0FA3 ; [.2EF3.0020.0002] # TIBETAN SUBJOINED LETTER NA +0F54 ; [.2EF4.0020.0002] # TIBETAN LETTER PA +0FA4 ; [.2EF5.0020.0002] # TIBETAN SUBJOINED LETTER PA +0F55 ; [.2EF6.0020.0002] # TIBETAN LETTER PHA +0FA5 ; [.2EF7.0020.0002] # TIBETAN SUBJOINED LETTER PHA +0F56 ; [.2EF8.0020.0002] # TIBETAN LETTER BA +0F57 ; [.2EF8.0020.0002][.2F18.0020.0002] # TIBETAN LETTER BHA +0FA6 ; [.2EF9.0020.0002] # TIBETAN SUBJOINED LETTER BA +0FA7 ; [.2EF9.0020.0002][.2F18.0020.0002] # TIBETAN SUBJOINED LETTER BHA +0F58 ; [.2EFA.0020.0002] # TIBETAN LETTER MA +0FA8 ; [.2EFB.0020.0002] # TIBETAN SUBJOINED LETTER MA +0F59 ; [.2EFC.0020.0002] # TIBETAN LETTER TSA +0FA9 ; [.2EFD.0020.0002] # TIBETAN SUBJOINED LETTER TSA +0F5A ; [.2EFE.0020.0002] # TIBETAN LETTER TSHA +0FAA ; [.2EFF.0020.0002] # TIBETAN SUBJOINED LETTER TSHA +0F5B ; [.2F00.0020.0002] # TIBETAN LETTER DZA +0F5C ; [.2F00.0020.0002][.2F18.0020.0002] # TIBETAN LETTER DZHA +0FAB ; [.2F01.0020.0002] # TIBETAN SUBJOINED LETTER DZA +0FAC ; [.2F01.0020.0002][.2F18.0020.0002] # TIBETAN SUBJOINED LETTER DZHA +0F5D ; [.2F02.0020.0002] # TIBETAN LETTER WA +0FAD ; [.2F03.0020.0002] # TIBETAN SUBJOINED LETTER WA +0FBA ; [.2F03.0020.0004][.0000.0112.0004] # TIBETAN SUBJOINED LETTER FIXED-FORM WA +0F5E ; [.2F04.0020.0002] # TIBETAN LETTER ZHA +0FAE ; [.2F05.0020.0002] # TIBETAN SUBJOINED LETTER ZHA +0F5F ; [.2F06.0020.0002] # TIBETAN LETTER ZA +0FAF ; [.2F07.0020.0002] # TIBETAN SUBJOINED LETTER ZA +0F60 ; [.2F08.0020.0002] # TIBETAN LETTER -A +0FB0 ; [.2F09.0020.0002] # TIBETAN SUBJOINED LETTER -A +0F61 ; [.2F0A.0020.0002] # TIBETAN LETTER YA +0FB1 ; [.2F0B.0020.0002] # TIBETAN SUBJOINED LETTER YA +0FBB ; [.2F0B.0020.0004][.0000.0112.0004] # TIBETAN SUBJOINED LETTER FIXED-FORM YA +0F62 ; [.2F0C.0020.0002] # TIBETAN LETTER RA +0F6A ; [.2F0C.0020.0004][.0000.0112.0004] # TIBETAN LETTER FIXED-FORM RA +0FB2 ; [.2F0D.0020.0002] # TIBETAN SUBJOINED LETTER RA +0FBC ; [.2F0D.0020.0004][.0000.0112.0004] # TIBETAN SUBJOINED LETTER FIXED-FORM RA +0F6C ; [.2F0E.0020.0002] # TIBETAN LETTER RRA +0F63 ; [.2F0F.0020.0002] # TIBETAN LETTER LA +0FB3 ; [.2F10.0020.0002] # TIBETAN SUBJOINED LETTER LA +0F64 ; [.2F11.0020.0002] # TIBETAN LETTER SHA +0FB4 ; [.2F12.0020.0002] # TIBETAN SUBJOINED LETTER SHA +0F65 ; [.2F13.0020.0002] # TIBETAN LETTER SSA +0FB5 ; [.2F14.0020.0002] # TIBETAN SUBJOINED LETTER SSA +0F66 ; [.2F15.0020.0002] # TIBETAN LETTER SA +0FB6 ; [.2F16.0020.0002] # TIBETAN SUBJOINED LETTER SA +0F67 ; [.2F17.0020.0002] # TIBETAN LETTER HA +0FB7 ; [.2F18.0020.0002] # TIBETAN SUBJOINED LETTER HA +0F68 ; [.2F19.0020.0002] # TIBETAN LETTER A +0F00 ; [.2F19.0020.0004][.2F30.0020.0004][.0000.00C4.0004] # TIBETAN SYLLABLE OM +0FB8 ; [.2F1A.0020.0002] # TIBETAN SUBJOINED LETTER A +0F88 ; [.2F1B.0020.0002] # TIBETAN SIGN LCE TSA CAN +0F8D ; [.2F1C.0020.0002] # TIBETAN SUBJOINED SIGN LCE TSA CAN +0F89 ; [.2F1D.0020.0002] # TIBETAN SIGN MCHU CAN +0F8E ; [.2F1E.0020.0002] # TIBETAN SUBJOINED SIGN MCHU CAN +0F8C ; [.2F1F.0020.0002] # TIBETAN SIGN INVERTED MCHU CAN +0F8F ; [.2F20.0020.0002] # TIBETAN SUBJOINED SIGN INVERTED MCHU CAN +0F8A ; [.2F21.0020.0002] # TIBETAN SIGN GRU CAN RGYINGS +0F8B ; [.2F22.0020.0002] # TIBETAN SIGN GRU MED RGYINGS +0F71 ; [.2F23.0020.0002] # TIBETAN VOWEL SIGN AA +0F72 ; [.2F24.0020.0002] # TIBETAN VOWEL SIGN I +0F73 ; [.2F25.0020.0002] # TIBETAN VOWEL SIGN II +0F71 0F72 ; [.2F25.0020.0002] # TIBETAN VOWEL SIGN II +0F80 ; [.2F26.0020.0002] # TIBETAN VOWEL SIGN REVERSED I +0F81 ; [.2F27.0020.0002] # TIBETAN VOWEL SIGN REVERSED II +0F71 0F80 ; [.2F27.0020.0002] # TIBETAN VOWEL SIGN REVERSED II +0F74 ; [.2F28.0020.0002] # TIBETAN VOWEL SIGN U +0F75 ; [.2F29.0020.0002] # TIBETAN VOWEL SIGN UU +0F71 0F74 ; [.2F29.0020.0002] # TIBETAN VOWEL SIGN UU +0F76 ; [.2F2A.0020.0002] # TIBETAN VOWEL SIGN VOCALIC R +0FB2 0F80 ; [.2F2A.0020.0002] # TIBETAN VOWEL SIGN VOCALIC R +0F77 ; [.2F2B.0020.0002] # TIBETAN VOWEL SIGN VOCALIC RR +0FB2 0F71 0F80 ; [.2F2B.0020.0002] # TIBETAN VOWEL SIGN VOCALIC RR +0FB2 0F81 ; [.2F2B.0020.0002] # TIBETAN VOWEL SIGN VOCALIC RR +0F78 ; [.2F2C.0020.0002] # TIBETAN VOWEL SIGN VOCALIC L +0FB3 0F80 ; [.2F2C.0020.0002] # TIBETAN VOWEL SIGN VOCALIC L +0F79 ; [.2F2D.0020.0002] # TIBETAN VOWEL SIGN VOCALIC LL +0FB3 0F71 0F80 ; [.2F2D.0020.0002] # TIBETAN VOWEL SIGN VOCALIC LL +0FB3 0F81 ; [.2F2D.0020.0002] # TIBETAN VOWEL SIGN VOCALIC LL +0F7A ; [.2F2E.0020.0002] # TIBETAN VOWEL SIGN E +0F7B ; [.2F2F.0020.0002] # TIBETAN VOWEL SIGN EE +0F7C ; [.2F30.0020.0002] # TIBETAN VOWEL SIGN O +0F7D ; [.2F31.0020.0002] # TIBETAN VOWEL SIGN OO +0F84 ; [.2F32.0020.0002] # TIBETAN MARK HALANTA +11A0B ; [.2F33.0020.0002] # ZANABAZAR SQUARE LETTER KA +11A32 ; [.2F34.0020.0002] # ZANABAZAR SQUARE LETTER KSSA +11A0C ; [.2F35.0020.0002] # ZANABAZAR SQUARE LETTER KHA +11A0D ; [.2F36.0020.0002] # ZANABAZAR SQUARE LETTER GA +11A0E ; [.2F37.0020.0002] # ZANABAZAR SQUARE LETTER GHA +11A0F ; [.2F38.0020.0002] # ZANABAZAR SQUARE LETTER NGA +11A10 ; [.2F39.0020.0002] # ZANABAZAR SQUARE LETTER CA +11A11 ; [.2F3A.0020.0002] # ZANABAZAR SQUARE LETTER CHA +11A12 ; [.2F3B.0020.0002] # ZANABAZAR SQUARE LETTER JA +11A13 ; [.2F3C.0020.0002] # ZANABAZAR SQUARE LETTER NYA +11A14 ; [.2F3D.0020.0002] # ZANABAZAR SQUARE LETTER TTA +11A15 ; [.2F3E.0020.0002] # ZANABAZAR SQUARE LETTER TTHA +11A16 ; [.2F3F.0020.0002] # ZANABAZAR SQUARE LETTER DDA +11A17 ; [.2F40.0020.0002] # ZANABAZAR SQUARE LETTER DDHA +11A18 ; [.2F41.0020.0002] # ZANABAZAR SQUARE LETTER NNA +11A19 ; [.2F42.0020.0002] # ZANABAZAR SQUARE LETTER TA +11A1A ; [.2F43.0020.0002] # ZANABAZAR SQUARE LETTER THA +11A1B ; [.2F44.0020.0002] # ZANABAZAR SQUARE LETTER DA +11A1C ; [.2F45.0020.0002] # ZANABAZAR SQUARE LETTER DHA +11A1D ; [.2F46.0020.0002] # ZANABAZAR SQUARE LETTER NA +11A1E ; [.2F47.0020.0002] # ZANABAZAR SQUARE LETTER PA +11A1F ; [.2F48.0020.0002] # ZANABAZAR SQUARE LETTER PHA +11A20 ; [.2F49.0020.0002] # ZANABAZAR SQUARE LETTER BA +11A21 ; [.2F4A.0020.0002] # ZANABAZAR SQUARE LETTER BHA +11A22 ; [.2F4B.0020.0002] # ZANABAZAR SQUARE LETTER MA +11A23 ; [.2F4C.0020.0002] # ZANABAZAR SQUARE LETTER TSA +11A24 ; [.2F4D.0020.0002] # ZANABAZAR SQUARE LETTER TSHA +11A25 ; [.2F4E.0020.0002] # ZANABAZAR SQUARE LETTER DZA +11A26 ; [.2F4F.0020.0002] # ZANABAZAR SQUARE LETTER DZHA +11A27 ; [.2F50.0020.0002] # ZANABAZAR SQUARE LETTER ZHA +11A28 ; [.2F51.0020.0002] # ZANABAZAR SQUARE LETTER ZA +11A29 ; [.2F52.0020.0002] # ZANABAZAR SQUARE LETTER -A +11A2A ; [.2F53.0020.0002] # ZANABAZAR SQUARE LETTER YA +11A3B ; [.2F53.0020.0019] # ZANABAZAR SQUARE CLUSTER-FINAL LETTER YA +11A2B ; [.2F54.0020.0002] # ZANABAZAR SQUARE LETTER RA +11A3A ; [.2F54.0020.0017] # ZANABAZAR SQUARE CLUSTER-INITIAL LETTER RA +11A3C ; [.2F54.0020.0019] # ZANABAZAR SQUARE CLUSTER-FINAL LETTER RA +11A2C ; [.2F55.0020.0002] # ZANABAZAR SQUARE LETTER LA +11A3D ; [.2F55.0020.0019] # ZANABAZAR SQUARE CLUSTER-FINAL LETTER LA +11A2D ; [.2F56.0020.0002] # ZANABAZAR SQUARE LETTER VA +11A3E ; [.2F56.0020.0019] # ZANABAZAR SQUARE CLUSTER-FINAL LETTER VA +11A2E ; [.2F57.0020.0002] # ZANABAZAR SQUARE LETTER SHA +11A2F ; [.2F58.0020.0002] # ZANABAZAR SQUARE LETTER SSA +11A30 ; [.2F59.0020.0002] # ZANABAZAR SQUARE LETTER SA +11A31 ; [.2F5A.0020.0002] # ZANABAZAR SQUARE LETTER HA +11A00 ; [.2F5B.0020.0002] # ZANABAZAR SQUARE LETTER A +11A01 ; [.2F5C.0020.0002] # ZANABAZAR SQUARE VOWEL SIGN I +11A02 ; [.2F5D.0020.0002] # ZANABAZAR SQUARE VOWEL SIGN UE +11A03 ; [.2F5E.0020.0002] # ZANABAZAR SQUARE VOWEL SIGN U +11A04 ; [.2F5F.0020.0002] # ZANABAZAR SQUARE VOWEL SIGN E +11A05 ; [.2F60.0020.0002] # ZANABAZAR SQUARE VOWEL SIGN OE +11A06 ; [.2F61.0020.0002] # ZANABAZAR SQUARE VOWEL SIGN O +11A07 ; [.2F62.0020.0002] # ZANABAZAR SQUARE VOWEL SIGN AI +11A08 ; [.2F63.0020.0002] # ZANABAZAR SQUARE VOWEL SIGN AU +11A09 ; [.2F64.0020.0002] # ZANABAZAR SQUARE VOWEL SIGN REVERSED I +11A0A ; [.2F65.0020.0002] # ZANABAZAR SQUARE VOWEL LENGTH MARK +11A34 ; [.2F66.0020.0002] # ZANABAZAR SQUARE SIGN VIRAMA +11A47 ; [.2F67.0020.0002] # ZANABAZAR SQUARE SUBJOINER +11A50 ; [.2F68.0020.0002] # SOYOMBO LETTER A +11A51 ; [.2F69.0020.0002] # SOYOMBO VOWEL SIGN I +11A52 ; [.2F6A.0020.0002] # SOYOMBO VOWEL SIGN UE +11A53 ; [.2F6B.0020.0002] # SOYOMBO VOWEL SIGN U +11A59 ; [.2F6C.0020.0002] # SOYOMBO VOWEL SIGN VOCALIC R +11A5A ; [.2F6D.0020.0002] # SOYOMBO VOWEL SIGN VOCALIC L +11A54 ; [.2F6E.0020.0002] # SOYOMBO VOWEL SIGN E +11A56 ; [.2F6F.0020.0002] # SOYOMBO VOWEL SIGN OE +11A55 ; [.2F70.0020.0002] # SOYOMBO VOWEL SIGN O +11A57 ; [.2F71.0020.0002] # SOYOMBO VOWEL SIGN AI +11A58 ; [.2F72.0020.0002] # SOYOMBO VOWEL SIGN AU +11A5B ; [.2F73.0020.0002] # SOYOMBO VOWEL LENGTH MARK +11A5C ; [.2F74.0020.0002] # SOYOMBO LETTER KA +11A8A ; [.2F74.0020.0019] # SOYOMBO FINAL CONSONANT SIGN G +11A83 ; [.2F75.0020.0002] # SOYOMBO LETTER KSSA +11A5D ; [.2F76.0020.0002] # SOYOMBO LETTER KHA +11A8B ; [.2F76.0020.0019] # SOYOMBO FINAL CONSONANT SIGN K +11A5E ; [.2F77.0020.0002] # SOYOMBO LETTER GA +11A5F ; [.2F78.0020.0002] # SOYOMBO LETTER GHA +11A60 ; [.2F79.0020.0002] # SOYOMBO LETTER NGA +11A8C ; [.2F79.0020.0019] # SOYOMBO FINAL CONSONANT SIGN NG +11A61 ; [.2F7A.0020.0002] # SOYOMBO LETTER CA +11A62 ; [.2F7B.0020.0002] # SOYOMBO LETTER CHA +11A63 ; [.2F7C.0020.0002] # SOYOMBO LETTER JA +11A64 ; [.2F7D.0020.0002] # SOYOMBO LETTER JHA +11A65 ; [.2F7E.0020.0002] # SOYOMBO LETTER NYA +11A66 ; [.2F7F.0020.0002] # SOYOMBO LETTER TTA +11A67 ; [.2F80.0020.0002] # SOYOMBO LETTER TTHA +11A68 ; [.2F81.0020.0002] # SOYOMBO LETTER DDA +11A69 ; [.2F82.0020.0002] # SOYOMBO LETTER DDHA +11A6A ; [.2F83.0020.0002] # SOYOMBO LETTER NNA +11A6B ; [.2F84.0020.0002] # SOYOMBO LETTER TA +11A8D ; [.2F84.0020.0019] # SOYOMBO FINAL CONSONANT SIGN D +11A6C ; [.2F85.0020.0002] # SOYOMBO LETTER THA +11A6D ; [.2F86.0020.0002] # SOYOMBO LETTER DA +11A6E ; [.2F87.0020.0002] # SOYOMBO LETTER DHA +11A6F ; [.2F88.0020.0002] # SOYOMBO LETTER NA +11A8E ; [.2F88.0020.0019] # SOYOMBO FINAL CONSONANT SIGN N +11A70 ; [.2F89.0020.0002] # SOYOMBO LETTER PA +11A8F ; [.2F89.0020.0019] # SOYOMBO FINAL CONSONANT SIGN B +11A71 ; [.2F8A.0020.0002] # SOYOMBO LETTER PHA +11A72 ; [.2F8B.0020.0002] # SOYOMBO LETTER BA +11A73 ; [.2F8C.0020.0002] # SOYOMBO LETTER BHA +11A74 ; [.2F8D.0020.0002] # SOYOMBO LETTER MA +11A90 ; [.2F8D.0020.0019] # SOYOMBO FINAL CONSONANT SIGN M +11A75 ; [.2F8E.0020.0002] # SOYOMBO LETTER TSA +11A76 ; [.2F8F.0020.0002] # SOYOMBO LETTER TSHA +11A77 ; [.2F90.0020.0002] # SOYOMBO LETTER DZA +11A78 ; [.2F91.0020.0002] # SOYOMBO LETTER ZHA +11A79 ; [.2F92.0020.0002] # SOYOMBO LETTER ZA +11A7A ; [.2F93.0020.0002] # SOYOMBO LETTER -A +11A95 ; [.2F93.0020.0019] # SOYOMBO FINAL CONSONANT SIGN -A +11A7B ; [.2F94.0020.0002] # SOYOMBO LETTER YA +11A7C ; [.2F95.0020.0002] # SOYOMBO LETTER RA +11A86 ; [.2F95.0020.0017] # SOYOMBO CLUSTER-INITIAL LETTER RA +11A91 ; [.2F95.0020.0019] # SOYOMBO FINAL CONSONANT SIGN R +11A7D ; [.2F96.0020.0002] # SOYOMBO LETTER LA +11A87 ; [.2F96.0020.0017] # SOYOMBO CLUSTER-INITIAL LETTER LA +11A92 ; [.2F96.0020.0019] # SOYOMBO FINAL CONSONANT SIGN L +11A7E ; [.2F97.0020.0002] # SOYOMBO LETTER VA +11A7F ; [.2F98.0020.0002] # SOYOMBO LETTER SHA +11A88 ; [.2F98.0020.0017] # SOYOMBO CLUSTER-INITIAL LETTER SHA +11A93 ; [.2F98.0020.0019] # SOYOMBO FINAL CONSONANT SIGN SH +11A80 ; [.2F99.0020.0002] # SOYOMBO LETTER SSA +11A81 ; [.2F9A.0020.0002] # SOYOMBO LETTER SA +11A89 ; [.2F9A.0020.0017] # SOYOMBO CLUSTER-INITIAL LETTER SA +11A94 ; [.2F9A.0020.0019] # SOYOMBO FINAL CONSONANT SIGN S +11A82 ; [.2F9B.0020.0002] # SOYOMBO LETTER HA +11A99 ; [.2F9C.0020.0002] # SOYOMBO SUBJOINER +11C72 ; [.2F9D.0020.0002] # MARCHEN LETTER KA +11C92 ; [.2F9E.0020.0002] # MARCHEN SUBJOINED LETTER KA +11C73 ; [.2F9F.0020.0002] # MARCHEN LETTER KHA +11C93 ; [.2FA0.0020.0002] # MARCHEN SUBJOINED LETTER KHA +11C74 ; [.2FA1.0020.0002] # MARCHEN LETTER GA +11C94 ; [.2FA2.0020.0002] # MARCHEN SUBJOINED LETTER GA +11C75 ; [.2FA3.0020.0002] # MARCHEN LETTER NGA +11C95 ; [.2FA4.0020.0002] # MARCHEN SUBJOINED LETTER NGA +11C76 ; [.2FA5.0020.0002] # MARCHEN LETTER CA +11C96 ; [.2FA6.0020.0002] # MARCHEN SUBJOINED LETTER CA +11C77 ; [.2FA7.0020.0002] # MARCHEN LETTER CHA +11C97 ; [.2FA8.0020.0002] # MARCHEN SUBJOINED LETTER CHA +11C78 ; [.2FA9.0020.0002] # MARCHEN LETTER JA +11C98 ; [.2FAA.0020.0002] # MARCHEN SUBJOINED LETTER JA +11C79 ; [.2FAB.0020.0002] # MARCHEN LETTER NYA +11C99 ; [.2FAC.0020.0002] # MARCHEN SUBJOINED LETTER NYA +11C7A ; [.2FAD.0020.0002] # MARCHEN LETTER TA +11C9A ; [.2FAE.0020.0002] # MARCHEN SUBJOINED LETTER TA +11C7B ; [.2FAF.0020.0002] # MARCHEN LETTER THA +11C9B ; [.2FB0.0020.0002] # MARCHEN SUBJOINED LETTER THA +11C7C ; [.2FB1.0020.0002] # MARCHEN LETTER DA +11C9C ; [.2FB2.0020.0002] # MARCHEN SUBJOINED LETTER DA +11C7D ; [.2FB3.0020.0002] # MARCHEN LETTER NA +11C9D ; [.2FB4.0020.0002] # MARCHEN SUBJOINED LETTER NA +11C7E ; [.2FB5.0020.0002] # MARCHEN LETTER PA +11C9E ; [.2FB6.0020.0002] # MARCHEN SUBJOINED LETTER PA +11C7F ; [.2FB7.0020.0002] # MARCHEN LETTER PHA +11C9F ; [.2FB8.0020.0002] # MARCHEN SUBJOINED LETTER PHA +11C80 ; [.2FB9.0020.0002] # MARCHEN LETTER BA +11CA0 ; [.2FBA.0020.0002] # MARCHEN SUBJOINED LETTER BA +11C81 ; [.2FBB.0020.0002] # MARCHEN LETTER MA +11CA1 ; [.2FBC.0020.0002] # MARCHEN SUBJOINED LETTER MA +11C82 ; [.2FBD.0020.0002] # MARCHEN LETTER TSA +11CA2 ; [.2FBE.0020.0002] # MARCHEN SUBJOINED LETTER TSA +11C83 ; [.2FBF.0020.0002] # MARCHEN LETTER TSHA +11CA3 ; [.2FC0.0020.0002] # MARCHEN SUBJOINED LETTER TSHA +11C84 ; [.2FC1.0020.0002] # MARCHEN LETTER DZA +11CA4 ; [.2FC2.0020.0002] # MARCHEN SUBJOINED LETTER DZA +11C85 ; [.2FC3.0020.0002] # MARCHEN LETTER WA +11CA5 ; [.2FC4.0020.0002] # MARCHEN SUBJOINED LETTER WA +11C86 ; [.2FC5.0020.0002] # MARCHEN LETTER ZHA +11CA6 ; [.2FC6.0020.0002] # MARCHEN SUBJOINED LETTER ZHA +11C87 ; [.2FC7.0020.0002] # MARCHEN LETTER ZA +11CA7 ; [.2FC8.0020.0002] # MARCHEN SUBJOINED LETTER ZA +11C88 ; [.2FC9.0020.0002] # MARCHEN LETTER -A +11C89 ; [.2FCA.0020.0002] # MARCHEN LETTER YA +11CA9 ; [.2FCB.0020.0002] # MARCHEN SUBJOINED LETTER YA +11C8A ; [.2FCC.0020.0002] # MARCHEN LETTER RA +11CAA ; [.2FCD.0020.0002] # MARCHEN SUBJOINED LETTER RA +11C8B ; [.2FCE.0020.0002] # MARCHEN LETTER LA +11CAB ; [.2FCF.0020.0002] # MARCHEN SUBJOINED LETTER LA +11C8C ; [.2FD0.0020.0002] # MARCHEN LETTER SHA +11CAC ; [.2FD1.0020.0002] # MARCHEN SUBJOINED LETTER SHA +11C8D ; [.2FD2.0020.0002] # MARCHEN LETTER SA +11CAD ; [.2FD3.0020.0002] # MARCHEN SUBJOINED LETTER SA +11C8E ; [.2FD4.0020.0002] # MARCHEN LETTER HA +11CAE ; [.2FD5.0020.0002] # MARCHEN SUBJOINED LETTER HA +11C8F ; [.2FD6.0020.0002] # MARCHEN LETTER A +11CAF ; [.2FD7.0020.0002] # MARCHEN SUBJOINED LETTER A +11CB0 ; [.2FD8.0020.0002] # MARCHEN VOWEL SIGN AA +11CB1 ; [.2FD9.0020.0002] # MARCHEN VOWEL SIGN I +11CB2 ; [.2FDA.0020.0002] # MARCHEN VOWEL SIGN U +11CB3 ; [.2FDB.0020.0002] # MARCHEN VOWEL SIGN E +11CB4 ; [.2FDC.0020.0002] # MARCHEN VOWEL SIGN O +1C00 ; [.2FDD.0020.0002] # LEPCHA LETTER KA +1C01 ; [.2FDE.0020.0002] # LEPCHA LETTER KLA +1C02 ; [.2FDF.0020.0002] # LEPCHA LETTER KHA +1C03 ; [.2FE0.0020.0002] # LEPCHA LETTER GA +1C04 ; [.2FE1.0020.0002] # LEPCHA LETTER GLA +1C05 ; [.2FE2.0020.0002] # LEPCHA LETTER NGA +1C06 ; [.2FE3.0020.0002] # LEPCHA LETTER CA +1C07 ; [.2FE4.0020.0002] # LEPCHA LETTER CHA +1C08 ; [.2FE5.0020.0002] # LEPCHA LETTER JA +1C09 ; [.2FE6.0020.0002] # LEPCHA LETTER NYA +1C4D ; [.2FE7.0020.0002] # LEPCHA LETTER TTA +1C4E ; [.2FE8.0020.0002] # LEPCHA LETTER TTHA +1C4F ; [.2FE9.0020.0002] # LEPCHA LETTER DDA +1C0A ; [.2FEA.0020.0002] # LEPCHA LETTER TA +1C0B ; [.2FEB.0020.0002] # LEPCHA LETTER THA +1C0C ; [.2FEC.0020.0002] # LEPCHA LETTER DA +1C0D ; [.2FED.0020.0002] # LEPCHA LETTER NA +1C0E ; [.2FEE.0020.0002] # LEPCHA LETTER PA +1C0F ; [.2FEF.0020.0002] # LEPCHA LETTER PLA +1C10 ; [.2FF0.0020.0002] # LEPCHA LETTER PHA +1C11 ; [.2FF1.0020.0002] # LEPCHA LETTER FA +1C12 ; [.2FF2.0020.0002] # LEPCHA LETTER FLA +1C13 ; [.2FF3.0020.0002] # LEPCHA LETTER BA +1C14 ; [.2FF4.0020.0002] # LEPCHA LETTER BLA +1C15 ; [.2FF5.0020.0002] # LEPCHA LETTER MA +1C16 ; [.2FF6.0020.0002] # LEPCHA LETTER MLA +1C17 ; [.2FF7.0020.0002] # LEPCHA LETTER TSA +1C18 ; [.2FF8.0020.0002] # LEPCHA LETTER TSHA +1C19 ; [.2FF9.0020.0002] # LEPCHA LETTER DZA +1C1A ; [.2FFA.0020.0002] # LEPCHA LETTER YA +1C24 ; [.2FFB.0020.0002] # LEPCHA SUBJOINED LETTER YA +1C1B ; [.2FFC.0020.0002] # LEPCHA LETTER RA +1C25 ; [.2FFD.0020.0002] # LEPCHA SUBJOINED LETTER RA +1C1C ; [.2FFE.0020.0002] # LEPCHA LETTER LA +1C1D ; [.2FFF.0020.0002] # LEPCHA LETTER HA +1C1E ; [.3000.0020.0002] # LEPCHA LETTER HLA +1C1F ; [.3001.0020.0002] # LEPCHA LETTER VA +1C20 ; [.3002.0020.0002] # LEPCHA LETTER SA +1C21 ; [.3003.0020.0002] # LEPCHA LETTER SHA +1C22 ; [.3004.0020.0002] # LEPCHA LETTER WA +1C23 ; [.3005.0020.0002] # LEPCHA LETTER A +1C36 ; [.3006.0020.0002] # LEPCHA SIGN RAN +1C26 ; [.3007.0020.0002] # LEPCHA VOWEL SIGN AA +1C27 ; [.3008.0020.0002] # LEPCHA VOWEL SIGN I +1C28 ; [.3009.0020.0002] # LEPCHA VOWEL SIGN O +1C29 ; [.300A.0020.0002] # LEPCHA VOWEL SIGN OO +1C2A ; [.300B.0020.0002] # LEPCHA VOWEL SIGN U +1C2B ; [.300C.0020.0002] # LEPCHA VOWEL SIGN UU +1C2C ; [.300D.0020.0002] # LEPCHA VOWEL SIGN E +1C2D ; [.300E.0020.0002] # LEPCHA CONSONANT SIGN K +1C2E ; [.300F.0020.0002] # LEPCHA CONSONANT SIGN M +1C2F ; [.3010.0020.0002] # LEPCHA CONSONANT SIGN L +1C30 ; [.3011.0020.0002] # LEPCHA CONSONANT SIGN N +1C31 ; [.3012.0020.0002] # LEPCHA CONSONANT SIGN P +1C32 ; [.3013.0020.0002] # LEPCHA CONSONANT SIGN R +1C33 ; [.3014.0020.0002] # LEPCHA CONSONANT SIGN T +1C34 ; [.3015.0020.0002] # LEPCHA CONSONANT SIGN NYIN-DO +1C35 ; [.3016.0020.0002] # LEPCHA CONSONANT SIGN KANG +A840 ; [.3017.0020.0002] # PHAGS-PA LETTER KA +A841 ; [.3018.0020.0002] # PHAGS-PA LETTER KHA +A842 ; [.3019.0020.0002] # PHAGS-PA LETTER GA +A843 ; [.301A.0020.0002] # PHAGS-PA LETTER NGA +A844 ; [.301B.0020.0002] # PHAGS-PA LETTER CA +A845 ; [.301C.0020.0002] # PHAGS-PA LETTER CHA +A846 ; [.301D.0020.0002] # PHAGS-PA LETTER JA +A847 ; [.301E.0020.0002] # PHAGS-PA LETTER NYA +A869 ; [.301F.0020.0002] # PHAGS-PA LETTER TTA +A86A ; [.3020.0020.0002] # PHAGS-PA LETTER TTHA +A86B ; [.3021.0020.0002] # PHAGS-PA LETTER DDA +A86C ; [.3022.0020.0002] # PHAGS-PA LETTER NNA +A848 ; [.3023.0020.0002] # PHAGS-PA LETTER TA +A849 ; [.3024.0020.0002] # PHAGS-PA LETTER THA +A84A ; [.3025.0020.0002] # PHAGS-PA LETTER DA +A84B ; [.3026.0020.0002] # PHAGS-PA LETTER NA +A84C ; [.3027.0020.0002] # PHAGS-PA LETTER PA +A84D ; [.3028.0020.0002] # PHAGS-PA LETTER PHA +A84E ; [.3029.0020.0002] # PHAGS-PA LETTER BA +A84F ; [.302A.0020.0002] # PHAGS-PA LETTER MA +A850 ; [.302B.0020.0002] # PHAGS-PA LETTER TSA +A851 ; [.302C.0020.0002] # PHAGS-PA LETTER TSHA +A852 ; [.302D.0020.0002] # PHAGS-PA LETTER DZA +A853 ; [.302E.0020.0002] # PHAGS-PA LETTER WA +A867 ; [.302F.0020.0002] # PHAGS-PA SUBJOINED LETTER WA +A854 ; [.3030.0020.0002] # PHAGS-PA LETTER ZHA +A855 ; [.3031.0020.0002] # PHAGS-PA LETTER ZA +A856 ; [.3032.0020.0002] # PHAGS-PA LETTER SMALL A +A857 ; [.3033.0020.0002] # PHAGS-PA LETTER YA +A868 ; [.3034.0020.0002] # PHAGS-PA SUBJOINED LETTER YA +A86D ; [.3035.0020.0002] # PHAGS-PA LETTER ALTERNATE YA +A858 ; [.3036.0020.0002] # PHAGS-PA LETTER RA +A871 ; [.3037.0020.0002] # PHAGS-PA SUBJOINED LETTER RA +A872 ; [.3038.0020.0002] # PHAGS-PA SUPERFIXED LETTER RA +A859 ; [.3039.0020.0002] # PHAGS-PA LETTER LA +A85A ; [.303A.0020.0002] # PHAGS-PA LETTER SHA +A86E ; [.303B.0020.0002] # PHAGS-PA LETTER VOICELESS SHA +A85B ; [.303C.0020.0002] # PHAGS-PA LETTER SA +A85C ; [.303D.0020.0002] # PHAGS-PA LETTER HA +A86F ; [.303E.0020.0002] # PHAGS-PA LETTER VOICED HA +A870 ; [.303F.0020.0002] # PHAGS-PA LETTER ASPIRATED FA +A85D ; [.3040.0020.0002] # PHAGS-PA LETTER A +A862 ; [.3041.0020.0002] # PHAGS-PA LETTER QA +A863 ; [.3042.0020.0002] # PHAGS-PA LETTER XA +A864 ; [.3043.0020.0002] # PHAGS-PA LETTER FA +A865 ; [.3044.0020.0002] # PHAGS-PA LETTER GGA +A85E ; [.3045.0020.0002] # PHAGS-PA LETTER I +A85F ; [.3046.0020.0002] # PHAGS-PA LETTER U +A860 ; [.3047.0020.0002] # PHAGS-PA LETTER E +A861 ; [.3048.0020.0002] # PHAGS-PA LETTER O +A866 ; [.3049.0020.0002] # PHAGS-PA LETTER EE +A873 ; [.304A.0020.0002] # PHAGS-PA LETTER CANDRABINDU +1900 ; [.304B.0020.0002] # LIMBU VOWEL-CARRIER LETTER +1901 ; [.304C.0020.0002] # LIMBU LETTER KA +1902 ; [.304D.0020.0002] # LIMBU LETTER KHA +1903 ; [.304E.0020.0002] # LIMBU LETTER GA +1904 ; [.304F.0020.0002] # LIMBU LETTER GHA +1905 ; [.3050.0020.0002] # LIMBU LETTER NGA +1906 ; [.3051.0020.0002] # LIMBU LETTER CA +1907 ; [.3052.0020.0002] # LIMBU LETTER CHA +1908 ; [.3053.0020.0002] # LIMBU LETTER JA +191D ; [.3053.0020.0004][.3071.0020.0004] # LIMBU LETTER GYAN +1909 ; [.3054.0020.0002] # LIMBU LETTER JHA +190A ; [.3055.0020.0002] # LIMBU LETTER YAN +190B ; [.3056.0020.0002] # LIMBU LETTER TA +191E ; [.3056.0020.0004][.3072.0020.0004] # LIMBU LETTER TRA +190C ; [.3057.0020.0002] # LIMBU LETTER THA +190D ; [.3058.0020.0002] # LIMBU LETTER DA +190E ; [.3059.0020.0002] # LIMBU LETTER DHA +190F ; [.305A.0020.0002] # LIMBU LETTER NA +1910 ; [.305B.0020.0002] # LIMBU LETTER PA +1911 ; [.305C.0020.0002] # LIMBU LETTER PHA +1912 ; [.305D.0020.0002] # LIMBU LETTER BA +1913 ; [.305E.0020.0002] # LIMBU LETTER BHA +1914 ; [.305F.0020.0002] # LIMBU LETTER MA +1915 ; [.3060.0020.0002] # LIMBU LETTER YA +1916 ; [.3061.0020.0002] # LIMBU LETTER RA +1917 ; [.3062.0020.0002] # LIMBU LETTER LA +1918 ; [.3063.0020.0002] # LIMBU LETTER WA +1919 ; [.3064.0020.0002] # LIMBU LETTER SHA +191A ; [.3065.0020.0002] # LIMBU LETTER SSA +191B ; [.3066.0020.0002] # LIMBU LETTER SA +191C ; [.3067.0020.0002] # LIMBU LETTER HA +1920 ; [.3068.0020.0002] # LIMBU VOWEL SIGN A +1921 ; [.3069.0020.0002] # LIMBU VOWEL SIGN I +1922 ; [.306A.0020.0002] # LIMBU VOWEL SIGN U +1923 ; [.306B.0020.0002] # LIMBU VOWEL SIGN EE +1924 ; [.306C.0020.0002] # LIMBU VOWEL SIGN AI +1925 ; [.306D.0020.0002] # LIMBU VOWEL SIGN OO +1926 ; [.306E.0020.0002] # LIMBU VOWEL SIGN AU +1927 ; [.306F.0020.0002] # LIMBU VOWEL SIGN E +1928 ; [.3070.0020.0002] # LIMBU VOWEL SIGN O +1929 ; [.3071.0020.0002] # LIMBU SUBJOINED LETTER YA +192A ; [.3072.0020.0002] # LIMBU SUBJOINED LETTER RA +192B ; [.3073.0020.0002] # LIMBU SUBJOINED LETTER WA +1930 ; [.3074.0020.0002] # LIMBU SMALL LETTER KA +1931 ; [.3075.0020.0002] # LIMBU SMALL LETTER NGA +1932 ; [.3076.0020.0002] # LIMBU SMALL LETTER ANUSVARA +1933 ; [.3077.0020.0002] # LIMBU SMALL LETTER TA +1934 ; [.3078.0020.0002] # LIMBU SMALL LETTER NA +1935 ; [.3079.0020.0002] # LIMBU SMALL LETTER PA +1936 ; [.307A.0020.0002] # LIMBU SMALL LETTER MA +1937 ; [.307B.0020.0002] # LIMBU SMALL LETTER RA +1938 ; [.307C.0020.0002] # LIMBU SMALL LETTER LA +1700 ; [.307D.0020.0002] # TAGALOG LETTER A +1701 ; [.307E.0020.0002] # TAGALOG LETTER I +1702 ; [.307F.0020.0002] # TAGALOG LETTER U +1703 ; [.3080.0020.0002] # TAGALOG LETTER KA +1704 ; [.3081.0020.0002] # TAGALOG LETTER GA +1705 ; [.3082.0020.0002] # TAGALOG LETTER NGA +1706 ; [.3083.0020.0002] # TAGALOG LETTER TA +1707 ; [.3084.0020.0002] # TAGALOG LETTER DA +1708 ; [.3085.0020.0002] # TAGALOG LETTER NA +1709 ; [.3086.0020.0002] # TAGALOG LETTER PA +170A ; [.3087.0020.0002] # TAGALOG LETTER BA +170B ; [.3088.0020.0002] # TAGALOG LETTER MA +170C ; [.3089.0020.0002] # TAGALOG LETTER YA +170E ; [.308A.0020.0002] # TAGALOG LETTER LA +170F ; [.308B.0020.0002] # TAGALOG LETTER WA +1710 ; [.308C.0020.0002] # TAGALOG LETTER SA +1711 ; [.308D.0020.0002] # TAGALOG LETTER HA +1712 ; [.308E.0020.0002] # TAGALOG VOWEL SIGN I +1713 ; [.308F.0020.0002] # TAGALOG VOWEL SIGN U +1714 ; [.3090.0020.0002] # TAGALOG SIGN VIRAMA +1720 ; [.3091.0020.0002] # HANUNOO LETTER A +1721 ; [.3092.0020.0002] # HANUNOO LETTER I +1722 ; [.3093.0020.0002] # HANUNOO LETTER U +1723 ; [.3094.0020.0002] # HANUNOO LETTER KA +1724 ; [.3095.0020.0002] # HANUNOO LETTER GA +1725 ; [.3096.0020.0002] # HANUNOO LETTER NGA +1726 ; [.3097.0020.0002] # HANUNOO LETTER TA +1727 ; [.3098.0020.0002] # HANUNOO LETTER DA +1728 ; [.3099.0020.0002] # HANUNOO LETTER NA +1729 ; [.309A.0020.0002] # HANUNOO LETTER PA +172A ; [.309B.0020.0002] # HANUNOO LETTER BA +172B ; [.309C.0020.0002] # HANUNOO LETTER MA +172C ; [.309D.0020.0002] # HANUNOO LETTER YA +172D ; [.309E.0020.0002] # HANUNOO LETTER RA +172E ; [.309F.0020.0002] # HANUNOO LETTER LA +172F ; [.30A0.0020.0002] # HANUNOO LETTER WA +1730 ; [.30A1.0020.0002] # HANUNOO LETTER SA +1731 ; [.30A2.0020.0002] # HANUNOO LETTER HA +1732 ; [.30A3.0020.0002] # HANUNOO VOWEL SIGN I +1733 ; [.30A4.0020.0002] # HANUNOO VOWEL SIGN U +1734 ; [.30A5.0020.0002] # HANUNOO SIGN PAMUDPOD +1740 ; [.30A6.0020.0002] # BUHID LETTER A +1741 ; [.30A7.0020.0002] # BUHID LETTER I +1742 ; [.30A8.0020.0002] # BUHID LETTER U +1743 ; [.30A9.0020.0002] # BUHID LETTER KA +1744 ; [.30AA.0020.0002] # BUHID LETTER GA +1745 ; [.30AB.0020.0002] # BUHID LETTER NGA +1746 ; [.30AC.0020.0002] # BUHID LETTER TA +1747 ; [.30AD.0020.0002] # BUHID LETTER DA +1748 ; [.30AE.0020.0002] # BUHID LETTER NA +1749 ; [.30AF.0020.0002] # BUHID LETTER PA +174A ; [.30B0.0020.0002] # BUHID LETTER BA +174B ; [.30B1.0020.0002] # BUHID LETTER MA +174C ; [.30B2.0020.0002] # BUHID LETTER YA +174D ; [.30B3.0020.0002] # BUHID LETTER RA +174E ; [.30B4.0020.0002] # BUHID LETTER LA +174F ; [.30B5.0020.0002] # BUHID LETTER WA +1750 ; [.30B6.0020.0002] # BUHID LETTER SA +1751 ; [.30B7.0020.0002] # BUHID LETTER HA +1752 ; [.30B8.0020.0002] # BUHID VOWEL SIGN I +1753 ; [.30B9.0020.0002] # BUHID VOWEL SIGN U +1760 ; [.30BA.0020.0002] # TAGBANWA LETTER A +1761 ; [.30BB.0020.0002] # TAGBANWA LETTER I +1762 ; [.30BC.0020.0002] # TAGBANWA LETTER U +1763 ; [.30BD.0020.0002] # TAGBANWA LETTER KA +1764 ; [.30BE.0020.0002] # TAGBANWA LETTER GA +1765 ; [.30BF.0020.0002] # TAGBANWA LETTER NGA +1766 ; [.30C0.0020.0002] # TAGBANWA LETTER TA +1767 ; [.30C1.0020.0002] # TAGBANWA LETTER DA +1768 ; [.30C2.0020.0002] # TAGBANWA LETTER NA +1769 ; [.30C3.0020.0002] # TAGBANWA LETTER PA +176A ; [.30C4.0020.0002] # TAGBANWA LETTER BA +176B ; [.30C5.0020.0002] # TAGBANWA LETTER MA +176C ; [.30C6.0020.0002] # TAGBANWA LETTER YA +176E ; [.30C7.0020.0002] # TAGBANWA LETTER LA +176F ; [.30C8.0020.0002] # TAGBANWA LETTER WA +1770 ; [.30C9.0020.0002] # TAGBANWA LETTER SA +1772 ; [.30CA.0020.0002] # TAGBANWA VOWEL SIGN I +1773 ; [.30CB.0020.0002] # TAGBANWA VOWEL SIGN U +1A00 ; [.30CC.0020.0002] # BUGINESE LETTER KA +1A01 ; [.30CD.0020.0002] # BUGINESE LETTER GA +1A02 ; [.30CE.0020.0002] # BUGINESE LETTER NGA +1A03 ; [.30CF.0020.0002] # BUGINESE LETTER NGKA +1A04 ; [.30D0.0020.0002] # BUGINESE LETTER PA +1A05 ; [.30D1.0020.0002] # BUGINESE LETTER BA +1A06 ; [.30D2.0020.0002] # BUGINESE LETTER MA +1A07 ; [.30D3.0020.0002] # BUGINESE LETTER MPA +1A08 ; [.30D4.0020.0002] # BUGINESE LETTER TA +1A09 ; [.30D5.0020.0002] # BUGINESE LETTER DA +1A0A ; [.30D6.0020.0002] # BUGINESE LETTER NA +1A0B ; [.30D7.0020.0002] # BUGINESE LETTER NRA +1A0C ; [.30D8.0020.0002] # BUGINESE LETTER CA +1A0D ; [.30D9.0020.0002] # BUGINESE LETTER JA +1A0E ; [.30DA.0020.0002] # BUGINESE LETTER NYA +1A0F ; [.30DB.0020.0002] # BUGINESE LETTER NYCA +1A10 ; [.30DC.0020.0002] # BUGINESE LETTER YA +1A11 ; [.30DD.0020.0002] # BUGINESE LETTER RA +1A12 ; [.30DE.0020.0002] # BUGINESE LETTER LA +1A13 ; [.30DF.0020.0002] # BUGINESE LETTER VA +1A14 ; [.30E0.0020.0002] # BUGINESE LETTER SA +1A15 ; [.30E1.0020.0002] # BUGINESE LETTER A +1A16 ; [.30E2.0020.0002] # BUGINESE LETTER HA +1A17 ; [.30E3.0020.0002] # BUGINESE VOWEL SIGN I +1A18 ; [.30E4.0020.0002] # BUGINESE VOWEL SIGN U +1A19 ; [.30E5.0020.0002] # BUGINESE VOWEL SIGN E +1A1A ; [.30E6.0020.0002] # BUGINESE VOWEL SIGN O +1A1B ; [.30E7.0020.0002] # BUGINESE VOWEL SIGN AE +1BC0 ; [.30E8.0020.0002] # BATAK LETTER A +1BC1 ; [.30E8.0020.0004] # BATAK LETTER SIMALUNGUN A +1BC2 ; [.30E9.0020.0002] # BATAK LETTER HA +1BC3 ; [.30E9.0020.0004] # BATAK LETTER SIMALUNGUN HA +1BC4 ; [.30E9.0020.0004] # BATAK LETTER MANDAILING HA +1BC5 ; [.30EA.0020.0002] # BATAK LETTER BA +1BC6 ; [.30EA.0020.0004] # BATAK LETTER KARO BA +1BC7 ; [.30EB.0020.0002] # BATAK LETTER PA +1BC8 ; [.30EB.0020.0004] # BATAK LETTER SIMALUNGUN PA +1BC9 ; [.30EC.0020.0002] # BATAK LETTER NA +1BCA ; [.30EC.0020.0004] # BATAK LETTER MANDAILING NA +1BCB ; [.30ED.0020.0002] # BATAK LETTER WA +1BCC ; [.30ED.0020.0004] # BATAK LETTER SIMALUNGUN WA +1BCD ; [.30ED.0020.0004] # BATAK LETTER PAKPAK WA +1BCE ; [.30EE.0020.0002] # BATAK LETTER GA +1BCF ; [.30EE.0020.0004] # BATAK LETTER SIMALUNGUN GA +1BD0 ; [.30EF.0020.0002] # BATAK LETTER JA +1BD1 ; [.30F0.0020.0002] # BATAK LETTER DA +1BD2 ; [.30F1.0020.0002] # BATAK LETTER RA +1BD3 ; [.30F1.0020.0004] # BATAK LETTER SIMALUNGUN RA +1BD4 ; [.30F2.0020.0002] # BATAK LETTER MA +1BD5 ; [.30F2.0020.0004] # BATAK LETTER SIMALUNGUN MA +1BD6 ; [.30F3.0020.0002] # BATAK LETTER SOUTHERN TA +1BD7 ; [.30F3.0020.0004] # BATAK LETTER NORTHERN TA +1BD8 ; [.30F4.0020.0002] # BATAK LETTER SA +1BD9 ; [.30F4.0020.0004] # BATAK LETTER SIMALUNGUN SA +1BDA ; [.30F4.0020.0004] # BATAK LETTER MANDAILING SA +1BDB ; [.30F5.0020.0002] # BATAK LETTER YA +1BDC ; [.30F5.0020.0004] # BATAK LETTER SIMALUNGUN YA +1BDD ; [.30F6.0020.0002] # BATAK LETTER NGA +1BDE ; [.30F7.0020.0002] # BATAK LETTER LA +1BDF ; [.30F7.0020.0004] # BATAK LETTER SIMALUNGUN LA +1BE0 ; [.30F8.0020.0002] # BATAK LETTER NYA +1BE1 ; [.30F9.0020.0002] # BATAK LETTER CA +1BE2 ; [.30FA.0020.0002] # BATAK LETTER NDA +1BE3 ; [.30FB.0020.0002] # BATAK LETTER MBA +1BE4 ; [.30FC.0020.0002] # BATAK LETTER I +1BE5 ; [.30FD.0020.0002] # BATAK LETTER U +1BE7 ; [.30FE.0020.0002] # BATAK VOWEL SIGN E +1BE8 ; [.30FE.0020.0004] # BATAK VOWEL SIGN PAKPAK E +1BE9 ; [.30FF.0020.0002] # BATAK VOWEL SIGN EE +1BEA ; [.3100.0020.0002] # BATAK VOWEL SIGN I +1BEB ; [.3100.0020.0004] # BATAK VOWEL SIGN KARO I +1BEC ; [.3101.0020.0002] # BATAK VOWEL SIGN O +1BED ; [.3101.0020.0004] # BATAK VOWEL SIGN KARO O +1BEE ; [.3102.0020.0002] # BATAK VOWEL SIGN U +1BEF ; [.3102.0020.0004] # BATAK VOWEL SIGN U FOR SIMALUNGUN SA +1BF0 ; [.3103.0020.0002] # BATAK CONSONANT SIGN NG +1BF1 ; [.3104.0020.0002] # BATAK CONSONANT SIGN H +1BF2 ; [.3105.0020.0002] # BATAK PANGOLAT +1BF3 ; [.3106.0020.0002] # BATAK PANONGONAN +A930 ; [.3107.0020.0002] # REJANG LETTER KA +A931 ; [.3108.0020.0002] # REJANG LETTER GA +A932 ; [.3109.0020.0002] # REJANG LETTER NGA +A933 ; [.310A.0020.0002] # REJANG LETTER TA +A934 ; [.310B.0020.0002] # REJANG LETTER DA +A935 ; [.310C.0020.0002] # REJANG LETTER NA +A936 ; [.310D.0020.0002] # REJANG LETTER PA +A937 ; [.310E.0020.0002] # REJANG LETTER BA +A938 ; [.310F.0020.0002] # REJANG LETTER MA +A939 ; [.3110.0020.0002] # REJANG LETTER CA +A93A ; [.3111.0020.0002] # REJANG LETTER JA +A93B ; [.3112.0020.0002] # REJANG LETTER NYA +A93C ; [.3113.0020.0002] # REJANG LETTER SA +A93D ; [.3114.0020.0002] # REJANG LETTER RA +A93E ; [.3115.0020.0002] # REJANG LETTER LA +A93F ; [.3116.0020.0002] # REJANG LETTER YA +A940 ; [.3117.0020.0002] # REJANG LETTER WA +A941 ; [.3118.0020.0002] # REJANG LETTER HA +A942 ; [.3119.0020.0002] # REJANG LETTER MBA +A943 ; [.311A.0020.0002] # REJANG LETTER NGGA +A944 ; [.311B.0020.0002] # REJANG LETTER NDA +A945 ; [.311C.0020.0002] # REJANG LETTER NYJA +A946 ; [.311D.0020.0002] # REJANG LETTER A +A947 ; [.311E.0020.0002] # REJANG VOWEL SIGN I +A948 ; [.311F.0020.0002] # REJANG VOWEL SIGN U +A949 ; [.3120.0020.0002] # REJANG VOWEL SIGN E +A94A ; [.3121.0020.0002] # REJANG VOWEL SIGN AI +A94B ; [.3122.0020.0002] # REJANG VOWEL SIGN O +A94C ; [.3123.0020.0002] # REJANG VOWEL SIGN AU +A94D ; [.3124.0020.0002] # REJANG VOWEL SIGN EU +A94E ; [.3125.0020.0002] # REJANG VOWEL SIGN EA +A94F ; [.3126.0020.0002] # REJANG CONSONANT SIGN NG +A950 ; [.3127.0020.0002] # REJANG CONSONANT SIGN N +A951 ; [.3128.0020.0002] # REJANG CONSONANT SIGN R +A952 ; [.3129.0020.0002] # REJANG CONSONANT SIGN H +A953 ; [.312A.0020.0002] # REJANG VIRAMA +A90A ; [.312B.0020.0002] # KAYAH LI LETTER KA +A90B ; [.312C.0020.0002] # KAYAH LI LETTER KHA +A90C ; [.312D.0020.0002] # KAYAH LI LETTER GA +A90D ; [.312E.0020.0002] # KAYAH LI LETTER NGA +A90E ; [.312F.0020.0002] # KAYAH LI LETTER SA +A90F ; [.3130.0020.0002] # KAYAH LI LETTER SHA +A910 ; [.3131.0020.0002] # KAYAH LI LETTER ZA +A911 ; [.3132.0020.0002] # KAYAH LI LETTER NYA +A912 ; [.3133.0020.0002] # KAYAH LI LETTER TA +A913 ; [.3134.0020.0002] # KAYAH LI LETTER HTA +A914 ; [.3135.0020.0002] # KAYAH LI LETTER NA +A915 ; [.3136.0020.0002] # KAYAH LI LETTER PA +A916 ; [.3137.0020.0002] # KAYAH LI LETTER PHA +A917 ; [.3138.0020.0002] # KAYAH LI LETTER MA +A918 ; [.3139.0020.0002] # KAYAH LI LETTER DA +A919 ; [.313A.0020.0002] # KAYAH LI LETTER BA +A91A ; [.313B.0020.0002] # KAYAH LI LETTER RA +A91B ; [.313C.0020.0002] # KAYAH LI LETTER YA +A91C ; [.313D.0020.0002] # KAYAH LI LETTER LA +A91D ; [.313E.0020.0002] # KAYAH LI LETTER WA +A91E ; [.313F.0020.0002] # KAYAH LI LETTER THA +A91F ; [.3140.0020.0002] # KAYAH LI LETTER HA +A920 ; [.3141.0020.0002] # KAYAH LI LETTER VA +A921 ; [.3142.0020.0002] # KAYAH LI LETTER CA +A922 ; [.3143.0020.0002] # KAYAH LI LETTER A +A923 ; [.3144.0020.0002] # KAYAH LI LETTER OE +A924 ; [.3145.0020.0002] # KAYAH LI LETTER I +A925 ; [.3146.0020.0002] # KAYAH LI LETTER OO +A926 ; [.3147.0020.0002] # KAYAH LI VOWEL UE +A927 ; [.3148.0020.0002] # KAYAH LI VOWEL E +A928 ; [.3149.0020.0002] # KAYAH LI VOWEL U +A929 ; [.314A.0020.0002] # KAYAH LI VOWEL EE +A92A ; [.314B.0020.0002] # KAYAH LI VOWEL O +1000 ; [.314C.0020.0002] # MYANMAR LETTER KA +1075 ; [.314D.0020.0002] # MYANMAR LETTER SHAN KA +1001 ; [.314E.0020.0002] # MYANMAR LETTER KHA +1076 ; [.314F.0020.0002] # MYANMAR LETTER SHAN KHA +1002 ; [.3150.0020.0002] # MYANMAR LETTER GA +1077 ; [.3151.0020.0002] # MYANMAR LETTER SHAN GA +AA60 ; [.3152.0020.0002] # MYANMAR LETTER KHAMTI GA +A9E9 ; [.3153.0020.0002] # MYANMAR LETTER TAI LAING GA +1003 ; [.3154.0020.0002] # MYANMAR LETTER GHA +A9E0 ; [.3155.0020.0002] # MYANMAR LETTER SHAN GHA +A9EA ; [.3156.0020.0002] # MYANMAR LETTER TAI LAING GHA +1004 ; [.3157.0020.0002] # MYANMAR LETTER NGA +105A ; [.3158.0020.0002] # MYANMAR LETTER MON NGA +1005 ; [.3159.0020.0002] # MYANMAR LETTER CA +1078 ; [.315A.0020.0002] # MYANMAR LETTER SHAN CA +AA61 ; [.315B.0020.0002] # MYANMAR LETTER KHAMTI CA +1006 ; [.315C.0020.0002] # MYANMAR LETTER CHA +A9E1 ; [.315D.0020.0002] # MYANMAR LETTER SHAN CHA +AA62 ; [.315E.0020.0002] # MYANMAR LETTER KHAMTI CHA +AA7E ; [.315F.0020.0002] # MYANMAR LETTER SHWE PALAUNG CHA +1007 ; [.3160.0020.0002] # MYANMAR LETTER JA +AA63 ; [.3161.0020.0002] # MYANMAR LETTER KHAMTI JA +A9EB ; [.3162.0020.0002] # MYANMAR LETTER TAI LAING JA +1079 ; [.3163.0020.0002] # MYANMAR LETTER SHAN ZA +AA72 ; [.3164.0020.0002] # MYANMAR LETTER KHAMTI ZA +1008 ; [.3165.0020.0002] # MYANMAR LETTER JHA +105B ; [.3166.0020.0002] # MYANMAR LETTER MON JHA +A9E2 ; [.3167.0020.0002] # MYANMAR LETTER SHAN JHA +AA64 ; [.3168.0020.0002] # MYANMAR LETTER KHAMTI JHA +A9EC ; [.3169.0020.0002] # MYANMAR LETTER TAI LAING JHA +1061 ; [.316A.0020.0002] # MYANMAR LETTER SGAW KAREN SHA +AA7F ; [.316B.0020.0002] # MYANMAR LETTER SHWE PALAUNG SHA +1009 ; [.316C.0020.0002] # MYANMAR LETTER NYA +107A ; [.316D.0020.0002] # MYANMAR LETTER SHAN NYA +AA65 ; [.316E.0020.0002] # MYANMAR LETTER KHAMTI NYA +A9E7 ; [.316F.0020.0002] # MYANMAR LETTER TAI LAING NYA +100A ; [.3170.0020.0002] # MYANMAR LETTER NNYA +100B ; [.3171.0020.0002] # MYANMAR LETTER TTA +AA66 ; [.3172.0020.0002] # MYANMAR LETTER KHAMTI TTA +100C ; [.3173.0020.0002] # MYANMAR LETTER TTHA +AA67 ; [.3174.0020.0002] # MYANMAR LETTER KHAMTI TTHA +100D ; [.3175.0020.0002] # MYANMAR LETTER DDA +AA68 ; [.3176.0020.0002] # MYANMAR LETTER KHAMTI DDA +A9ED ; [.3177.0020.0002] # MYANMAR LETTER TAI LAING DDA +100E ; [.3178.0020.0002] # MYANMAR LETTER DDHA +AA69 ; [.3179.0020.0002] # MYANMAR LETTER KHAMTI DDHA +A9EE ; [.317A.0020.0002] # MYANMAR LETTER TAI LAING DDHA +100F ; [.317B.0020.0002] # MYANMAR LETTER NNA +106E ; [.317C.0020.0002] # MYANMAR LETTER EASTERN PWO KAREN NNA +A9E3 ; [.317D.0020.0002] # MYANMAR LETTER SHAN NNA +A9EF ; [.317E.0020.0002] # MYANMAR LETTER TAI LAING NNA +1010 ; [.317F.0020.0002] # MYANMAR LETTER TA +1011 ; [.3180.0020.0002] # MYANMAR LETTER THA +1012 ; [.3181.0020.0002] # MYANMAR LETTER DA +107B ; [.3182.0020.0002] # MYANMAR LETTER SHAN DA +A9FB ; [.3183.0020.0002] # MYANMAR LETTER TAI LAING DA +1013 ; [.3184.0020.0002] # MYANMAR LETTER DHA +AA6A ; [.3185.0020.0002] # MYANMAR LETTER KHAMTI DHA +A9FC ; [.3186.0020.0002] # MYANMAR LETTER TAI LAING DHA +1014 ; [.3187.0020.0002] # MYANMAR LETTER NA +107C ; [.3188.0020.0002] # MYANMAR LETTER SHAN NA +AA6B ; [.3189.0020.0002] # MYANMAR LETTER KHAMTI NA +105E ; [.318A.0020.0002] # MYANMAR CONSONANT SIGN MON MEDIAL NA +1015 ; [.318B.0020.0002] # MYANMAR LETTER PA +1016 ; [.318C.0020.0002] # MYANMAR LETTER PHA +107D ; [.318D.0020.0002] # MYANMAR LETTER SHAN PHA +107E ; [.318E.0020.0002] # MYANMAR LETTER SHAN FA +AA6F ; [.318F.0020.0002] # MYANMAR LETTER KHAMTI FA +108E ; [.3190.0020.0002] # MYANMAR LETTER RUMAI PALAUNG FA +A9E8 ; [.3191.0020.0002] # MYANMAR LETTER TAI LAING FA +1017 ; [.3192.0020.0002] # MYANMAR LETTER BA +107F ; [.3193.0020.0002] # MYANMAR LETTER SHAN BA +A9FD ; [.3194.0020.0002] # MYANMAR LETTER TAI LAING BA +1018 ; [.3195.0020.0002] # MYANMAR LETTER BHA +A9E4 ; [.3196.0020.0002] # MYANMAR LETTER SHAN BHA +A9FE ; [.3197.0020.0002] # MYANMAR LETTER TAI LAING BHA +1019 ; [.3198.0020.0002] # MYANMAR LETTER MA +105F ; [.3199.0020.0002] # MYANMAR CONSONANT SIGN MON MEDIAL MA +101A ; [.319A.0020.0002] # MYANMAR LETTER YA +103B ; [.319B.0020.0002] # MYANMAR CONSONANT SIGN MEDIAL YA +101B ; [.319C.0020.0002] # MYANMAR LETTER RA +AA73 ; [.319D.0020.0002] # MYANMAR LETTER KHAMTI RA +AA7A ; [.319E.0020.0002] # MYANMAR LETTER AITON RA +103C ; [.319F.0020.0002] # MYANMAR CONSONANT SIGN MEDIAL RA +101C ; [.31A0.0020.0002] # MYANMAR LETTER LA +1060 ; [.31A1.0020.0002] # MYANMAR CONSONANT SIGN MON MEDIAL LA +101D ; [.31A2.0020.0002] # MYANMAR LETTER WA +103D ; [.31A3.0020.0002] # MYANMAR CONSONANT SIGN MEDIAL WA +1082 ; [.31A4.0020.0002] # MYANMAR CONSONANT SIGN SHAN MEDIAL WA +1080 ; [.31A5.0020.0002] # MYANMAR LETTER SHAN THA +1050 ; [.31A6.0020.0002] # MYANMAR LETTER SHA +1051 ; [.31A7.0020.0002] # MYANMAR LETTER SSA +1065 ; [.31A8.0020.0002] # MYANMAR LETTER WESTERN PWO KAREN THA +101E ; [.31A9.0020.0002] # MYANMAR LETTER SA +103F ; [.31A9.0020.0004][.31E2.0020.0004][.31A9.0020.0004] # MYANMAR LETTER GREAT SA +AA6C ; [.31AA.0020.0002] # MYANMAR LETTER KHAMTI SA +101F ; [.31AB.0020.0002] # MYANMAR LETTER HA +1081 ; [.31AC.0020.0002] # MYANMAR LETTER SHAN HA +AA6D ; [.31AD.0020.0002] # MYANMAR LETTER KHAMTI HA +103E ; [.31AE.0020.0002] # MYANMAR CONSONANT SIGN MEDIAL HA +AA6E ; [.31AF.0020.0002] # MYANMAR LETTER KHAMTI HHA +AA71 ; [.31B0.0020.0002] # MYANMAR LETTER KHAMTI XA +1020 ; [.31B1.0020.0002] # MYANMAR LETTER LLA +A9FA ; [.31B2.0020.0002] # MYANMAR LETTER TAI LAING LLA +105C ; [.31B3.0020.0002] # MYANMAR LETTER MON BBA +105D ; [.31B4.0020.0002] # MYANMAR LETTER MON BBE +106F ; [.31B5.0020.0002] # MYANMAR LETTER EASTERN PWO KAREN YWA +1070 ; [.31B6.0020.0002] # MYANMAR LETTER EASTERN PWO KAREN GHWA +1066 ; [.31B7.0020.0002] # MYANMAR LETTER WESTERN PWO KAREN PWA +1021 ; [.31B8.0020.0002] # MYANMAR LETTER A +1022 ; [.31B9.0020.0002] # MYANMAR LETTER SHAN A +1023 ; [.31BA.0020.0002] # MYANMAR LETTER I +1024 ; [.31BB.0020.0002] # MYANMAR LETTER II +1025 ; [.31BC.0020.0002] # MYANMAR LETTER U +1026 ; [.31BD.0020.0002] # MYANMAR LETTER UU +1025 102E ; [.31BD.0020.0002] # MYANMAR LETTER UU +1052 ; [.31BE.0020.0002] # MYANMAR LETTER VOCALIC R +1053 ; [.31BF.0020.0002] # MYANMAR LETTER VOCALIC RR +1054 ; [.31C0.0020.0002] # MYANMAR LETTER VOCALIC L +1055 ; [.31C1.0020.0002] # MYANMAR LETTER VOCALIC LL +1027 ; [.31C2.0020.0002] # MYANMAR LETTER E +1028 ; [.31C3.0020.0002] # MYANMAR LETTER MON E +1029 ; [.31C4.0020.0002] # MYANMAR LETTER O +102A ; [.31C5.0020.0002] # MYANMAR LETTER AU +102C ; [.31C6.0020.0002] # MYANMAR VOWEL SIGN AA +102B ; [.31C6.0020.0004] # MYANMAR VOWEL SIGN TALL AA +1083 ; [.31C7.0020.0002] # MYANMAR VOWEL SIGN SHAN AA +1072 ; [.31C8.0020.0002] # MYANMAR VOWEL SIGN KAYAH OE +109C ; [.31C9.0020.0002] # MYANMAR VOWEL SIGN AITON A +102D ; [.31CA.0020.0002] # MYANMAR VOWEL SIGN I +1071 ; [.31CB.0020.0002] # MYANMAR VOWEL SIGN GEBA KAREN I +102E ; [.31CC.0020.0002] # MYANMAR VOWEL SIGN II +1033 ; [.31CD.0020.0002] # MYANMAR VOWEL SIGN MON II +102F ; [.31CE.0020.0002] # MYANMAR VOWEL SIGN U +1073 ; [.31CF.0020.0002] # MYANMAR VOWEL SIGN KAYAH U +1074 ; [.31D0.0020.0002] # MYANMAR VOWEL SIGN KAYAH EE +1030 ; [.31D1.0020.0002] # MYANMAR VOWEL SIGN UU +1056 ; [.31D2.0020.0002] # MYANMAR VOWEL SIGN VOCALIC R +1057 ; [.31D3.0020.0002] # MYANMAR VOWEL SIGN VOCALIC RR +1058 ; [.31D4.0020.0002] # MYANMAR VOWEL SIGN VOCALIC L +1059 ; [.31D5.0020.0002] # MYANMAR VOWEL SIGN VOCALIC LL +1031 ; [.31D6.0020.0002] # MYANMAR VOWEL SIGN E +1084 ; [.31D7.0020.0002] # MYANMAR VOWEL SIGN SHAN E +1035 ; [.31D8.0020.0002] # MYANMAR VOWEL SIGN E ABOVE +1085 ; [.31D9.0020.0002] # MYANMAR VOWEL SIGN SHAN E ABOVE +1032 ; [.31DA.0020.0002] # MYANMAR VOWEL SIGN AI +109D ; [.31DB.0020.0002] # MYANMAR VOWEL SIGN AITON AI +1034 ; [.31DC.0020.0002] # MYANMAR VOWEL SIGN MON O +1062 ; [.31DD.0020.0002] # MYANMAR VOWEL SIGN SGAW KAREN EU +1067 ; [.31DE.0020.0002] # MYANMAR VOWEL SIGN WESTERN PWO KAREN EU +1068 ; [.31DF.0020.0002] # MYANMAR VOWEL SIGN WESTERN PWO KAREN UE +A9E5 ; [.31E0.0020.0002] # MYANMAR SIGN SHAN SAW +1086 ; [.31E1.0020.0002] # MYANMAR VOWEL SIGN SHAN FINAL Y +1039 ; [.31E2.0020.0002] # MYANMAR SIGN VIRAMA +103A ; [.31E3.0020.0002] # MYANMAR SIGN ASAT +1063 ; [.31E4.0020.0002] # MYANMAR TONE MARK SGAW KAREN HATHI +1064 ; [.31E5.0020.0002] # MYANMAR TONE MARK SGAW KAREN KE PHO +1069 ; [.31E6.0020.0002] # MYANMAR SIGN WESTERN PWO KAREN TONE-1 +106A ; [.31E7.0020.0002] # MYANMAR SIGN WESTERN PWO KAREN TONE-2 +106B ; [.31E8.0020.0002] # MYANMAR SIGN WESTERN PWO KAREN TONE-3 +106C ; [.31E9.0020.0002] # MYANMAR SIGN WESTERN PWO KAREN TONE-4 +106D ; [.31EA.0020.0002] # MYANMAR SIGN WESTERN PWO KAREN TONE-5 +1087 ; [.31EB.0020.0002] # MYANMAR SIGN SHAN TONE-2 +108B ; [.31EC.0020.0002] # MYANMAR SIGN SHAN COUNCIL TONE-2 +1088 ; [.31ED.0020.0002] # MYANMAR SIGN SHAN TONE-3 +108C ; [.31EE.0020.0002] # MYANMAR SIGN SHAN COUNCIL TONE-3 +108D ; [.31EF.0020.0002] # MYANMAR SIGN SHAN COUNCIL EMPHATIC TONE +1089 ; [.31F0.0020.0002] # MYANMAR SIGN SHAN TONE-5 +108A ; [.31F1.0020.0002] # MYANMAR SIGN SHAN TONE-6 +108F ; [.31F2.0020.0002] # MYANMAR SIGN RUMAI PALAUNG TONE-5 +109A ; [.31F3.0020.0002] # MYANMAR SIGN KHAMTI TONE-1 +109B ; [.31F4.0020.0002] # MYANMAR SIGN KHAMTI TONE-3 +AA7B ; [.31F5.0020.0002] # MYANMAR SIGN PAO KAREN TONE +AA7C ; [.31F6.0020.0002] # MYANMAR SIGN TAI LAING TONE-2 +AA7D ; [.31F7.0020.0002] # MYANMAR SIGN TAI LAING TONE-5 +AA74 ; [.31F8.0020.0002] # MYANMAR LOGOGRAM KHAMTI OAY +AA75 ; [.31F9.0020.0002] # MYANMAR LOGOGRAM KHAMTI QN +AA76 ; [.31FA.0020.0002] # MYANMAR LOGOGRAM KHAMTI HM +11103 ; [.31FB.0020.0002] # CHAKMA LETTER AA +11104 ; [.31FC.0020.0002] # CHAKMA LETTER I +11105 ; [.31FD.0020.0002] # CHAKMA LETTER U +11106 ; [.31FE.0020.0002] # CHAKMA LETTER E +11107 ; [.31FF.0020.0002] # CHAKMA LETTER KAA +11108 ; [.3200.0020.0002] # CHAKMA LETTER KHAA +11109 ; [.3201.0020.0002] # CHAKMA LETTER GAA +1110A ; [.3202.0020.0002] # CHAKMA LETTER GHAA +1110B ; [.3203.0020.0002] # CHAKMA LETTER NGAA +1110C ; [.3204.0020.0002] # CHAKMA LETTER CAA +1110D ; [.3205.0020.0002] # CHAKMA LETTER CHAA +1110E ; [.3206.0020.0002] # CHAKMA LETTER JAA +1110F ; [.3207.0020.0002] # CHAKMA LETTER JHAA +11110 ; [.3208.0020.0002] # CHAKMA LETTER NYAA +11111 ; [.3209.0020.0002] # CHAKMA LETTER TTAA +11112 ; [.320A.0020.0002] # CHAKMA LETTER TTHAA +11113 ; [.320B.0020.0002] # CHAKMA LETTER DDAA +11114 ; [.320C.0020.0002] # CHAKMA LETTER DDHAA +11115 ; [.320D.0020.0002] # CHAKMA LETTER NNAA +11116 ; [.320E.0020.0002] # CHAKMA LETTER TAA +11117 ; [.320F.0020.0002] # CHAKMA LETTER THAA +11118 ; [.3210.0020.0002] # CHAKMA LETTER DAA +11119 ; [.3211.0020.0002] # CHAKMA LETTER DHAA +1111A ; [.3212.0020.0002] # CHAKMA LETTER NAA +1111B ; [.3213.0020.0002] # CHAKMA LETTER PAA +1111C ; [.3214.0020.0002] # CHAKMA LETTER PHAA +1111D ; [.3215.0020.0002] # CHAKMA LETTER BAA +1111E ; [.3216.0020.0002] # CHAKMA LETTER BHAA +1111F ; [.3217.0020.0002] # CHAKMA LETTER MAA +11120 ; [.3218.0020.0002] # CHAKMA LETTER YYAA +11121 ; [.3219.0020.0002] # CHAKMA LETTER YAA +11122 ; [.321A.0020.0002] # CHAKMA LETTER RAA +11123 ; [.321B.0020.0002] # CHAKMA LETTER LAA +11124 ; [.321C.0020.0002] # CHAKMA LETTER WAA +11125 ; [.321D.0020.0002] # CHAKMA LETTER SAA +11126 ; [.321E.0020.0002] # CHAKMA LETTER HAA +11127 ; [.321F.0020.0002] # CHAKMA VOWEL SIGN A +11128 ; [.3220.0020.0002] # CHAKMA VOWEL SIGN I +11129 ; [.3221.0020.0002] # CHAKMA VOWEL SIGN II +1112A ; [.3222.0020.0002] # CHAKMA VOWEL SIGN U +1112B ; [.3223.0020.0002] # CHAKMA VOWEL SIGN UU +1112C ; [.3224.0020.0002] # CHAKMA VOWEL SIGN E +1112D ; [.3225.0020.0002] # CHAKMA VOWEL SIGN AI +1112E ; [.3226.0020.0002] # CHAKMA VOWEL SIGN O +11131 11127 ; [.3226.0020.0002] # CHAKMA VOWEL SIGN O +1112F ; [.3227.0020.0002] # CHAKMA VOWEL SIGN AU +11132 11127 ; [.3227.0020.0002] # CHAKMA VOWEL SIGN AU +11130 ; [.3228.0020.0002] # CHAKMA VOWEL SIGN OI +11131 ; [.3229.0020.0002] # CHAKMA O MARK +11132 ; [.322A.0020.0002] # CHAKMA AU MARK +11133 ; [.322B.0020.0002] # CHAKMA VIRAMA +11134 ; [.322C.0020.0002] # CHAKMA MAAYYAA +1780 ; [.322D.0020.0002] # KHMER LETTER KA +1781 ; [.322E.0020.0002] # KHMER LETTER KHA +1782 ; [.322F.0020.0002] # KHMER LETTER KO +1783 ; [.3230.0020.0002] # KHMER LETTER KHO +1784 ; [.3231.0020.0002] # KHMER LETTER NGO +1785 ; [.3232.0020.0002] # KHMER LETTER CA +1786 ; [.3233.0020.0002] # KHMER LETTER CHA +1787 ; [.3234.0020.0002] # KHMER LETTER CO +1788 ; [.3235.0020.0002] # KHMER LETTER CHO +1789 ; [.3236.0020.0002] # KHMER LETTER NYO +178A ; [.3237.0020.0002] # KHMER LETTER DA +178B ; [.3238.0020.0002] # KHMER LETTER TTHA +178C ; [.3239.0020.0002] # KHMER LETTER DO +178D ; [.323A.0020.0002] # KHMER LETTER TTHO +178E ; [.323B.0020.0002] # KHMER LETTER NNO +178F ; [.323C.0020.0002] # KHMER LETTER TA +1790 ; [.323D.0020.0002] # KHMER LETTER THA +1791 ; [.323E.0020.0002] # KHMER LETTER TO +1792 ; [.323F.0020.0002] # KHMER LETTER THO +1793 ; [.3240.0020.0002] # KHMER LETTER NO +1794 ; [.3241.0020.0002] # KHMER LETTER BA +1795 ; [.3242.0020.0002] # KHMER LETTER PHA +1796 ; [.3243.0020.0002] # KHMER LETTER PO +1797 ; [.3244.0020.0002] # KHMER LETTER PHO +1798 ; [.3245.0020.0002] # KHMER LETTER MO +1799 ; [.3246.0020.0002] # KHMER LETTER YO +179A ; [.3247.0020.0002] # KHMER LETTER RO +179B ; [.3248.0020.0002] # KHMER LETTER LO +179C ; [.3249.0020.0002] # KHMER LETTER VO +179D ; [.324A.0020.0002] # KHMER LETTER SHA +179E ; [.324B.0020.0002] # KHMER LETTER SSO +179F ; [.324C.0020.0002] # KHMER LETTER SA +17A0 ; [.324D.0020.0002] # KHMER LETTER HA +17A1 ; [.324E.0020.0002] # KHMER LETTER LA +17A2 ; [.324F.0020.0002] # KHMER LETTER QA +17DC ; [.3250.0020.0002] # KHMER SIGN AVAKRAHASANYA +17A3 ; [.3251.0020.0002] # KHMER INDEPENDENT VOWEL QAQ +17A4 ; [.3252.0020.0002] # KHMER INDEPENDENT VOWEL QAA +17A5 ; [.3253.0020.0002] # KHMER INDEPENDENT VOWEL QI +17A6 ; [.3254.0020.0002] # KHMER INDEPENDENT VOWEL QII +17A7 ; [.3255.0020.0002] # KHMER INDEPENDENT VOWEL QU +17A8 ; [.3256.0020.0002] # KHMER INDEPENDENT VOWEL QUK +17A9 ; [.3257.0020.0002] # KHMER INDEPENDENT VOWEL QUU +17AA ; [.3258.0020.0002] # KHMER INDEPENDENT VOWEL QUUV +17AB ; [.3259.0020.0002] # KHMER INDEPENDENT VOWEL RY +17AC ; [.325A.0020.0002] # KHMER INDEPENDENT VOWEL RYY +17AD ; [.325B.0020.0002] # KHMER INDEPENDENT VOWEL LY +17AE ; [.325C.0020.0002] # KHMER INDEPENDENT VOWEL LYY +17AF ; [.325D.0020.0002] # KHMER INDEPENDENT VOWEL QE +17B0 ; [.325E.0020.0002] # KHMER INDEPENDENT VOWEL QAI +17B1 ; [.325F.0020.0002] # KHMER INDEPENDENT VOWEL QOO TYPE ONE +17B2 ; [.3260.0020.0002] # KHMER INDEPENDENT VOWEL QOO TYPE TWO +17B3 ; [.3261.0020.0002] # KHMER INDEPENDENT VOWEL QAU +17B6 ; [.3262.0020.0002] # KHMER VOWEL SIGN AA +17B7 ; [.3263.0020.0002] # KHMER VOWEL SIGN I +17B8 ; [.3264.0020.0002] # KHMER VOWEL SIGN II +17B9 ; [.3265.0020.0002] # KHMER VOWEL SIGN Y +17BA ; [.3266.0020.0002] # KHMER VOWEL SIGN YY +17BB ; [.3267.0020.0002] # KHMER VOWEL SIGN U +17BC ; [.3268.0020.0002] # KHMER VOWEL SIGN UU +17BD ; [.3269.0020.0002] # KHMER VOWEL SIGN UA +17BE ; [.326A.0020.0002] # KHMER VOWEL SIGN OE +17BF ; [.326B.0020.0002] # KHMER VOWEL SIGN YA +17C0 ; [.326C.0020.0002] # KHMER VOWEL SIGN IE +17C1 ; [.326D.0020.0002] # KHMER VOWEL SIGN E +17C2 ; [.326E.0020.0002] # KHMER VOWEL SIGN AE +17C3 ; [.326F.0020.0002] # KHMER VOWEL SIGN AI +17C4 ; [.3270.0020.0002] # KHMER VOWEL SIGN OO +17C5 ; [.3271.0020.0002] # KHMER VOWEL SIGN AU +17D2 ; [.3272.0020.0002] # KHMER SIGN COENG +1950 ; [.3273.0020.0002] # TAI LE LETTER KA +1951 ; [.3274.0020.0002] # TAI LE LETTER XA +1952 ; [.3275.0020.0002] # TAI LE LETTER NGA +1953 ; [.3276.0020.0002] # TAI LE LETTER TSA +1954 ; [.3277.0020.0002] # TAI LE LETTER SA +1955 ; [.3278.0020.0002] # TAI LE LETTER YA +1956 ; [.3279.0020.0002] # TAI LE LETTER TA +1957 ; [.327A.0020.0002] # TAI LE LETTER THA +1958 ; [.327B.0020.0002] # TAI LE LETTER LA +1959 ; [.327C.0020.0002] # TAI LE LETTER PA +195A ; [.327D.0020.0002] # TAI LE LETTER PHA +195B ; [.327E.0020.0002] # TAI LE LETTER MA +195C ; [.327F.0020.0002] # TAI LE LETTER FA +195D ; [.3280.0020.0002] # TAI LE LETTER VA +195E ; [.3281.0020.0002] # TAI LE LETTER HA +195F ; [.3282.0020.0002] # TAI LE LETTER QA +1960 ; [.3283.0020.0002] # TAI LE LETTER KHA +1961 ; [.3284.0020.0002] # TAI LE LETTER TSHA +1962 ; [.3285.0020.0002] # TAI LE LETTER NA +1963 ; [.3286.0020.0002] # TAI LE LETTER A +1964 ; [.3287.0020.0002] # TAI LE LETTER I +1965 ; [.3288.0020.0002] # TAI LE LETTER EE +1966 ; [.3289.0020.0002] # TAI LE LETTER EH +1967 ; [.328A.0020.0002] # TAI LE LETTER U +1968 ; [.328B.0020.0002] # TAI LE LETTER OO +1969 ; [.328C.0020.0002] # TAI LE LETTER O +196A ; [.328D.0020.0002] # TAI LE LETTER UE +196B ; [.328E.0020.0002] # TAI LE LETTER E +196C ; [.328F.0020.0002] # TAI LE LETTER AUE +196D ; [.3290.0020.0002] # TAI LE LETTER AI +1970 ; [.3291.0020.0002] # TAI LE LETTER TONE-2 +1971 ; [.3292.0020.0002] # TAI LE LETTER TONE-3 +1972 ; [.3293.0020.0002] # TAI LE LETTER TONE-4 +1973 ; [.3294.0020.0002] # TAI LE LETTER TONE-5 +1974 ; [.3295.0020.0002] # TAI LE LETTER TONE-6 +1980 ; [.3296.0020.0002] # NEW TAI LUE LETTER HIGH QA +19B5 1980 ; [.3296.0020.0002][.32C7.0020.0002] # <NEW TAI LUE VOWEL SIGN E, NEW TAI LUE LETTER HIGH QA> +19B6 1980 ; [.3296.0020.0002][.32C8.0020.0002] # <NEW TAI LUE VOWEL SIGN AE, NEW TAI LUE LETTER HIGH QA> +19B7 1980 ; [.3296.0020.0002][.32C9.0020.0002] # <NEW TAI LUE VOWEL SIGN O, NEW TAI LUE LETTER HIGH QA> +19BA 1980 ; [.3296.0020.0002][.32CC.0020.0002] # <NEW TAI LUE VOWEL SIGN AY, NEW TAI LUE LETTER HIGH QA> +1981 ; [.3297.0020.0002] # NEW TAI LUE LETTER LOW QA +19B5 1981 ; [.3297.0020.0002][.32C7.0020.0002] # <NEW TAI LUE VOWEL SIGN E, NEW TAI LUE LETTER LOW QA> +19B6 1981 ; [.3297.0020.0002][.32C8.0020.0002] # <NEW TAI LUE VOWEL SIGN AE, NEW TAI LUE LETTER LOW QA> +19B7 1981 ; [.3297.0020.0002][.32C9.0020.0002] # <NEW TAI LUE VOWEL SIGN O, NEW TAI LUE LETTER LOW QA> +19BA 1981 ; [.3297.0020.0002][.32CC.0020.0002] # <NEW TAI LUE VOWEL SIGN AY, NEW TAI LUE LETTER LOW QA> +1982 ; [.3298.0020.0002] # NEW TAI LUE LETTER HIGH KA +19B5 1982 ; [.3298.0020.0002][.32C7.0020.0002] # <NEW TAI LUE VOWEL SIGN E, NEW TAI LUE LETTER HIGH KA> +19B6 1982 ; [.3298.0020.0002][.32C8.0020.0002] # <NEW TAI LUE VOWEL SIGN AE, NEW TAI LUE LETTER HIGH KA> +19B7 1982 ; [.3298.0020.0002][.32C9.0020.0002] # <NEW TAI LUE VOWEL SIGN O, NEW TAI LUE LETTER HIGH KA> +19BA 1982 ; [.3298.0020.0002][.32CC.0020.0002] # <NEW TAI LUE VOWEL SIGN AY, NEW TAI LUE LETTER HIGH KA> +1983 ; [.3299.0020.0002] # NEW TAI LUE LETTER HIGH XA +19B5 1983 ; [.3299.0020.0002][.32C7.0020.0002] # <NEW TAI LUE VOWEL SIGN E, NEW TAI LUE LETTER HIGH XA> +19B6 1983 ; [.3299.0020.0002][.32C8.0020.0002] # <NEW TAI LUE VOWEL SIGN AE, NEW TAI LUE LETTER HIGH XA> +19B7 1983 ; [.3299.0020.0002][.32C9.0020.0002] # <NEW TAI LUE VOWEL SIGN O, NEW TAI LUE LETTER HIGH XA> +19BA 1983 ; [.3299.0020.0002][.32CC.0020.0002] # <NEW TAI LUE VOWEL SIGN AY, NEW TAI LUE LETTER HIGH XA> +1984 ; [.329A.0020.0002] # NEW TAI LUE LETTER HIGH NGA +19B5 1984 ; [.329A.0020.0002][.32C7.0020.0002] # <NEW TAI LUE VOWEL SIGN E, NEW TAI LUE LETTER HIGH NGA> +19B6 1984 ; [.329A.0020.0002][.32C8.0020.0002] # <NEW TAI LUE VOWEL SIGN AE, NEW TAI LUE LETTER HIGH NGA> +19B7 1984 ; [.329A.0020.0002][.32C9.0020.0002] # <NEW TAI LUE VOWEL SIGN O, NEW TAI LUE LETTER HIGH NGA> +19BA 1984 ; [.329A.0020.0002][.32CC.0020.0002] # <NEW TAI LUE VOWEL SIGN AY, NEW TAI LUE LETTER HIGH NGA> +1985 ; [.329B.0020.0002] # NEW TAI LUE LETTER LOW KA +19B5 1985 ; [.329B.0020.0002][.32C7.0020.0002] # <NEW TAI LUE VOWEL SIGN E, NEW TAI LUE LETTER LOW KA> +19B6 1985 ; [.329B.0020.0002][.32C8.0020.0002] # <NEW TAI LUE VOWEL SIGN AE, NEW TAI LUE LETTER LOW KA> +19B7 1985 ; [.329B.0020.0002][.32C9.0020.0002] # <NEW TAI LUE VOWEL SIGN O, NEW TAI LUE LETTER LOW KA> +19BA 1985 ; [.329B.0020.0002][.32CC.0020.0002] # <NEW TAI LUE VOWEL SIGN AY, NEW TAI LUE LETTER LOW KA> +1986 ; [.329C.0020.0002] # NEW TAI LUE LETTER LOW XA +19B5 1986 ; [.329C.0020.0002][.32C7.0020.0002] # <NEW TAI LUE VOWEL SIGN E, NEW TAI LUE LETTER LOW XA> +19B6 1986 ; [.329C.0020.0002][.32C8.0020.0002] # <NEW TAI LUE VOWEL SIGN AE, NEW TAI LUE LETTER LOW XA> +19B7 1986 ; [.329C.0020.0002][.32C9.0020.0002] # <NEW TAI LUE VOWEL SIGN O, NEW TAI LUE LETTER LOW XA> +19BA 1986 ; [.329C.0020.0002][.32CC.0020.0002] # <NEW TAI LUE VOWEL SIGN AY, NEW TAI LUE LETTER LOW XA> +1987 ; [.329D.0020.0002] # NEW TAI LUE LETTER LOW NGA +19B5 1987 ; [.329D.0020.0002][.32C7.0020.0002] # <NEW TAI LUE VOWEL SIGN E, NEW TAI LUE LETTER LOW NGA> +19B6 1987 ; [.329D.0020.0002][.32C8.0020.0002] # <NEW TAI LUE VOWEL SIGN AE, NEW TAI LUE LETTER LOW NGA> +19B7 1987 ; [.329D.0020.0002][.32C9.0020.0002] # <NEW TAI LUE VOWEL SIGN O, NEW TAI LUE LETTER LOW NGA> +19BA 1987 ; [.329D.0020.0002][.32CC.0020.0002] # <NEW TAI LUE VOWEL SIGN AY, NEW TAI LUE LETTER LOW NGA> +1988 ; [.329E.0020.0002] # NEW TAI LUE LETTER HIGH TSA +19B5 1988 ; [.329E.0020.0002][.32C7.0020.0002] # <NEW TAI LUE VOWEL SIGN E, NEW TAI LUE LETTER HIGH TSA> +19B6 1988 ; [.329E.0020.0002][.32C8.0020.0002] # <NEW TAI LUE VOWEL SIGN AE, NEW TAI LUE LETTER HIGH TSA> +19B7 1988 ; [.329E.0020.0002][.32C9.0020.0002] # <NEW TAI LUE VOWEL SIGN O, NEW TAI LUE LETTER HIGH TSA> +19BA 1988 ; [.329E.0020.0002][.32CC.0020.0002] # <NEW TAI LUE VOWEL SIGN AY, NEW TAI LUE LETTER HIGH TSA> +1989 ; [.329F.0020.0002] # NEW TAI LUE LETTER HIGH SA +19B5 1989 ; [.329F.0020.0002][.32C7.0020.0002] # <NEW TAI LUE VOWEL SIGN E, NEW TAI LUE LETTER HIGH SA> +19B6 1989 ; [.329F.0020.0002][.32C8.0020.0002] # <NEW TAI LUE VOWEL SIGN AE, NEW TAI LUE LETTER HIGH SA> +19B7 1989 ; [.329F.0020.0002][.32C9.0020.0002] # <NEW TAI LUE VOWEL SIGN O, NEW TAI LUE LETTER HIGH SA> +19BA 1989 ; [.329F.0020.0002][.32CC.0020.0002] # <NEW TAI LUE VOWEL SIGN AY, NEW TAI LUE LETTER HIGH SA> +198A ; [.32A0.0020.0002] # NEW TAI LUE LETTER HIGH YA +19B5 198A ; [.32A0.0020.0002][.32C7.0020.0002] # <NEW TAI LUE VOWEL SIGN E, NEW TAI LUE LETTER HIGH YA> +19B6 198A ; [.32A0.0020.0002][.32C8.0020.0002] # <NEW TAI LUE VOWEL SIGN AE, NEW TAI LUE LETTER HIGH YA> +19B7 198A ; [.32A0.0020.0002][.32C9.0020.0002] # <NEW TAI LUE VOWEL SIGN O, NEW TAI LUE LETTER HIGH YA> +19BA 198A ; [.32A0.0020.0002][.32CC.0020.0002] # <NEW TAI LUE VOWEL SIGN AY, NEW TAI LUE LETTER HIGH YA> +198B ; [.32A1.0020.0002] # NEW TAI LUE LETTER LOW TSA +19B5 198B ; [.32A1.0020.0002][.32C7.0020.0002] # <NEW TAI LUE VOWEL SIGN E, NEW TAI LUE LETTER LOW TSA> +19B6 198B ; [.32A1.0020.0002][.32C8.0020.0002] # <NEW TAI LUE VOWEL SIGN AE, NEW TAI LUE LETTER LOW TSA> +19B7 198B ; [.32A1.0020.0002][.32C9.0020.0002] # <NEW TAI LUE VOWEL SIGN O, NEW TAI LUE LETTER LOW TSA> +19BA 198B ; [.32A1.0020.0002][.32CC.0020.0002] # <NEW TAI LUE VOWEL SIGN AY, NEW TAI LUE LETTER LOW TSA> +198C ; [.32A2.0020.0002] # NEW TAI LUE LETTER LOW SA +19B5 198C ; [.32A2.0020.0002][.32C7.0020.0002] # <NEW TAI LUE VOWEL SIGN E, NEW TAI LUE LETTER LOW SA> +19B6 198C ; [.32A2.0020.0002][.32C8.0020.0002] # <NEW TAI LUE VOWEL SIGN AE, NEW TAI LUE LETTER LOW SA> +19B7 198C ; [.32A2.0020.0002][.32C9.0020.0002] # <NEW TAI LUE VOWEL SIGN O, NEW TAI LUE LETTER LOW SA> +19BA 198C ; [.32A2.0020.0002][.32CC.0020.0002] # <NEW TAI LUE VOWEL SIGN AY, NEW TAI LUE LETTER LOW SA> +198D ; [.32A3.0020.0002] # NEW TAI LUE LETTER LOW YA +19B5 198D ; [.32A3.0020.0002][.32C7.0020.0002] # <NEW TAI LUE VOWEL SIGN E, NEW TAI LUE LETTER LOW YA> +19B6 198D ; [.32A3.0020.0002][.32C8.0020.0002] # <NEW TAI LUE VOWEL SIGN AE, NEW TAI LUE LETTER LOW YA> +19B7 198D ; [.32A3.0020.0002][.32C9.0020.0002] # <NEW TAI LUE VOWEL SIGN O, NEW TAI LUE LETTER LOW YA> +19BA 198D ; [.32A3.0020.0002][.32CC.0020.0002] # <NEW TAI LUE VOWEL SIGN AY, NEW TAI LUE LETTER LOW YA> +198E ; [.32A4.0020.0002] # NEW TAI LUE LETTER HIGH TA +19B5 198E ; [.32A4.0020.0002][.32C7.0020.0002] # <NEW TAI LUE VOWEL SIGN E, NEW TAI LUE LETTER HIGH TA> +19B6 198E ; [.32A4.0020.0002][.32C8.0020.0002] # <NEW TAI LUE VOWEL SIGN AE, NEW TAI LUE LETTER HIGH TA> +19B7 198E ; [.32A4.0020.0002][.32C9.0020.0002] # <NEW TAI LUE VOWEL SIGN O, NEW TAI LUE LETTER HIGH TA> +19BA 198E ; [.32A4.0020.0002][.32CC.0020.0002] # <NEW TAI LUE VOWEL SIGN AY, NEW TAI LUE LETTER HIGH TA> +198F ; [.32A5.0020.0002] # NEW TAI LUE LETTER HIGH THA +19B5 198F ; [.32A5.0020.0002][.32C7.0020.0002] # <NEW TAI LUE VOWEL SIGN E, NEW TAI LUE LETTER HIGH THA> +19B6 198F ; [.32A5.0020.0002][.32C8.0020.0002] # <NEW TAI LUE VOWEL SIGN AE, NEW TAI LUE LETTER HIGH THA> +19B7 198F ; [.32A5.0020.0002][.32C9.0020.0002] # <NEW TAI LUE VOWEL SIGN O, NEW TAI LUE LETTER HIGH THA> +19BA 198F ; [.32A5.0020.0002][.32CC.0020.0002] # <NEW TAI LUE VOWEL SIGN AY, NEW TAI LUE LETTER HIGH THA> +1990 ; [.32A6.0020.0002] # NEW TAI LUE LETTER HIGH NA +19B5 1990 ; [.32A6.0020.0002][.32C7.0020.0002] # <NEW TAI LUE VOWEL SIGN E, NEW TAI LUE LETTER HIGH NA> +19B6 1990 ; [.32A6.0020.0002][.32C8.0020.0002] # <NEW TAI LUE VOWEL SIGN AE, NEW TAI LUE LETTER HIGH NA> +19B7 1990 ; [.32A6.0020.0002][.32C9.0020.0002] # <NEW TAI LUE VOWEL SIGN O, NEW TAI LUE LETTER HIGH NA> +19BA 1990 ; [.32A6.0020.0002][.32CC.0020.0002] # <NEW TAI LUE VOWEL SIGN AY, NEW TAI LUE LETTER HIGH NA> +1991 ; [.32A7.0020.0002] # NEW TAI LUE LETTER LOW TA +19B5 1991 ; [.32A7.0020.0002][.32C7.0020.0002] # <NEW TAI LUE VOWEL SIGN E, NEW TAI LUE LETTER LOW TA> +19B6 1991 ; [.32A7.0020.0002][.32C8.0020.0002] # <NEW TAI LUE VOWEL SIGN AE, NEW TAI LUE LETTER LOW TA> +19B7 1991 ; [.32A7.0020.0002][.32C9.0020.0002] # <NEW TAI LUE VOWEL SIGN O, NEW TAI LUE LETTER LOW TA> +19BA 1991 ; [.32A7.0020.0002][.32CC.0020.0002] # <NEW TAI LUE VOWEL SIGN AY, NEW TAI LUE LETTER LOW TA> +1992 ; [.32A8.0020.0002] # NEW TAI LUE LETTER LOW THA +19B5 1992 ; [.32A8.0020.0002][.32C7.0020.0002] # <NEW TAI LUE VOWEL SIGN E, NEW TAI LUE LETTER LOW THA> +19B6 1992 ; [.32A8.0020.0002][.32C8.0020.0002] # <NEW TAI LUE VOWEL SIGN AE, NEW TAI LUE LETTER LOW THA> +19B7 1992 ; [.32A8.0020.0002][.32C9.0020.0002] # <NEW TAI LUE VOWEL SIGN O, NEW TAI LUE LETTER LOW THA> +19BA 1992 ; [.32A8.0020.0002][.32CC.0020.0002] # <NEW TAI LUE VOWEL SIGN AY, NEW TAI LUE LETTER LOW THA> +1993 ; [.32A9.0020.0002] # NEW TAI LUE LETTER LOW NA +19B5 1993 ; [.32A9.0020.0002][.32C7.0020.0002] # <NEW TAI LUE VOWEL SIGN E, NEW TAI LUE LETTER LOW NA> +19B6 1993 ; [.32A9.0020.0002][.32C8.0020.0002] # <NEW TAI LUE VOWEL SIGN AE, NEW TAI LUE LETTER LOW NA> +19B7 1993 ; [.32A9.0020.0002][.32C9.0020.0002] # <NEW TAI LUE VOWEL SIGN O, NEW TAI LUE LETTER LOW NA> +19BA 1993 ; [.32A9.0020.0002][.32CC.0020.0002] # <NEW TAI LUE VOWEL SIGN AY, NEW TAI LUE LETTER LOW NA> +1994 ; [.32AA.0020.0002] # NEW TAI LUE LETTER HIGH PA +19B5 1994 ; [.32AA.0020.0002][.32C7.0020.0002] # <NEW TAI LUE VOWEL SIGN E, NEW TAI LUE LETTER HIGH PA> +19B6 1994 ; [.32AA.0020.0002][.32C8.0020.0002] # <NEW TAI LUE VOWEL SIGN AE, NEW TAI LUE LETTER HIGH PA> +19B7 1994 ; [.32AA.0020.0002][.32C9.0020.0002] # <NEW TAI LUE VOWEL SIGN O, NEW TAI LUE LETTER HIGH PA> +19BA 1994 ; [.32AA.0020.0002][.32CC.0020.0002] # <NEW TAI LUE VOWEL SIGN AY, NEW TAI LUE LETTER HIGH PA> +1995 ; [.32AB.0020.0002] # NEW TAI LUE LETTER HIGH PHA +19B5 1995 ; [.32AB.0020.0002][.32C7.0020.0002] # <NEW TAI LUE VOWEL SIGN E, NEW TAI LUE LETTER HIGH PHA> +19B6 1995 ; [.32AB.0020.0002][.32C8.0020.0002] # <NEW TAI LUE VOWEL SIGN AE, NEW TAI LUE LETTER HIGH PHA> +19B7 1995 ; [.32AB.0020.0002][.32C9.0020.0002] # <NEW TAI LUE VOWEL SIGN O, NEW TAI LUE LETTER HIGH PHA> +19BA 1995 ; [.32AB.0020.0002][.32CC.0020.0002] # <NEW TAI LUE VOWEL SIGN AY, NEW TAI LUE LETTER HIGH PHA> +1996 ; [.32AC.0020.0002] # NEW TAI LUE LETTER HIGH MA +19B5 1996 ; [.32AC.0020.0002][.32C7.0020.0002] # <NEW TAI LUE VOWEL SIGN E, NEW TAI LUE LETTER HIGH MA> +19B6 1996 ; [.32AC.0020.0002][.32C8.0020.0002] # <NEW TAI LUE VOWEL SIGN AE, NEW TAI LUE LETTER HIGH MA> +19B7 1996 ; [.32AC.0020.0002][.32C9.0020.0002] # <NEW TAI LUE VOWEL SIGN O, NEW TAI LUE LETTER HIGH MA> +19BA 1996 ; [.32AC.0020.0002][.32CC.0020.0002] # <NEW TAI LUE VOWEL SIGN AY, NEW TAI LUE LETTER HIGH MA> +1997 ; [.32AD.0020.0002] # NEW TAI LUE LETTER LOW PA +19B5 1997 ; [.32AD.0020.0002][.32C7.0020.0002] # <NEW TAI LUE VOWEL SIGN E, NEW TAI LUE LETTER LOW PA> +19B6 1997 ; [.32AD.0020.0002][.32C8.0020.0002] # <NEW TAI LUE VOWEL SIGN AE, NEW TAI LUE LETTER LOW PA> +19B7 1997 ; [.32AD.0020.0002][.32C9.0020.0002] # <NEW TAI LUE VOWEL SIGN O, NEW TAI LUE LETTER LOW PA> +19BA 1997 ; [.32AD.0020.0002][.32CC.0020.0002] # <NEW TAI LUE VOWEL SIGN AY, NEW TAI LUE LETTER LOW PA> +1998 ; [.32AE.0020.0002] # NEW TAI LUE LETTER LOW PHA +19B5 1998 ; [.32AE.0020.0002][.32C7.0020.0002] # <NEW TAI LUE VOWEL SIGN E, NEW TAI LUE LETTER LOW PHA> +19B6 1998 ; [.32AE.0020.0002][.32C8.0020.0002] # <NEW TAI LUE VOWEL SIGN AE, NEW TAI LUE LETTER LOW PHA> +19B7 1998 ; [.32AE.0020.0002][.32C9.0020.0002] # <NEW TAI LUE VOWEL SIGN O, NEW TAI LUE LETTER LOW PHA> +19BA 1998 ; [.32AE.0020.0002][.32CC.0020.0002] # <NEW TAI LUE VOWEL SIGN AY, NEW TAI LUE LETTER LOW PHA> +1999 ; [.32AF.0020.0002] # NEW TAI LUE LETTER LOW MA +19B5 1999 ; [.32AF.0020.0002][.32C7.0020.0002] # <NEW TAI LUE VOWEL SIGN E, NEW TAI LUE LETTER LOW MA> +19B6 1999 ; [.32AF.0020.0002][.32C8.0020.0002] # <NEW TAI LUE VOWEL SIGN AE, NEW TAI LUE LETTER LOW MA> +19B7 1999 ; [.32AF.0020.0002][.32C9.0020.0002] # <NEW TAI LUE VOWEL SIGN O, NEW TAI LUE LETTER LOW MA> +19BA 1999 ; [.32AF.0020.0002][.32CC.0020.0002] # <NEW TAI LUE VOWEL SIGN AY, NEW TAI LUE LETTER LOW MA> +199A ; [.32B0.0020.0002] # NEW TAI LUE LETTER HIGH FA +19B5 199A ; [.32B0.0020.0002][.32C7.0020.0002] # <NEW TAI LUE VOWEL SIGN E, NEW TAI LUE LETTER HIGH FA> +19B6 199A ; [.32B0.0020.0002][.32C8.0020.0002] # <NEW TAI LUE VOWEL SIGN AE, NEW TAI LUE LETTER HIGH FA> +19B7 199A ; [.32B0.0020.0002][.32C9.0020.0002] # <NEW TAI LUE VOWEL SIGN O, NEW TAI LUE LETTER HIGH FA> +19BA 199A ; [.32B0.0020.0002][.32CC.0020.0002] # <NEW TAI LUE VOWEL SIGN AY, NEW TAI LUE LETTER HIGH FA> +199B ; [.32B1.0020.0002] # NEW TAI LUE LETTER HIGH VA +19B5 199B ; [.32B1.0020.0002][.32C7.0020.0002] # <NEW TAI LUE VOWEL SIGN E, NEW TAI LUE LETTER HIGH VA> +19B6 199B ; [.32B1.0020.0002][.32C8.0020.0002] # <NEW TAI LUE VOWEL SIGN AE, NEW TAI LUE LETTER HIGH VA> +19B7 199B ; [.32B1.0020.0002][.32C9.0020.0002] # <NEW TAI LUE VOWEL SIGN O, NEW TAI LUE LETTER HIGH VA> +19BA 199B ; [.32B1.0020.0002][.32CC.0020.0002] # <NEW TAI LUE VOWEL SIGN AY, NEW TAI LUE LETTER HIGH VA> +199C ; [.32B2.0020.0002] # NEW TAI LUE LETTER HIGH LA +19B5 199C ; [.32B2.0020.0002][.32C7.0020.0002] # <NEW TAI LUE VOWEL SIGN E, NEW TAI LUE LETTER HIGH LA> +19B6 199C ; [.32B2.0020.0002][.32C8.0020.0002] # <NEW TAI LUE VOWEL SIGN AE, NEW TAI LUE LETTER HIGH LA> +19DE ; [.32B2.0020.0004][.32C8.0020.0004] # NEW TAI LUE SIGN LAE +19DF ; [.32B2.0020.0004][.32C8.0020.0004][.32D3.0020.0004] # NEW TAI LUE SIGN LAEV +19B7 199C ; [.32B2.0020.0002][.32C9.0020.0002] # <NEW TAI LUE VOWEL SIGN O, NEW TAI LUE LETTER HIGH LA> +19BA 199C ; [.32B2.0020.0002][.32CC.0020.0002] # <NEW TAI LUE VOWEL SIGN AY, NEW TAI LUE LETTER HIGH LA> +199D ; [.32B3.0020.0002] # NEW TAI LUE LETTER LOW FA +19B5 199D ; [.32B3.0020.0002][.32C7.0020.0002] # <NEW TAI LUE VOWEL SIGN E, NEW TAI LUE LETTER LOW FA> +19B6 199D ; [.32B3.0020.0002][.32C8.0020.0002] # <NEW TAI LUE VOWEL SIGN AE, NEW TAI LUE LETTER LOW FA> +19B7 199D ; [.32B3.0020.0002][.32C9.0020.0002] # <NEW TAI LUE VOWEL SIGN O, NEW TAI LUE LETTER LOW FA> +19BA 199D ; [.32B3.0020.0002][.32CC.0020.0002] # <NEW TAI LUE VOWEL SIGN AY, NEW TAI LUE LETTER LOW FA> +199E ; [.32B4.0020.0002] # NEW TAI LUE LETTER LOW VA +19B5 199E ; [.32B4.0020.0002][.32C7.0020.0002] # <NEW TAI LUE VOWEL SIGN E, NEW TAI LUE LETTER LOW VA> +19B6 199E ; [.32B4.0020.0002][.32C8.0020.0002] # <NEW TAI LUE VOWEL SIGN AE, NEW TAI LUE LETTER LOW VA> +19B7 199E ; [.32B4.0020.0002][.32C9.0020.0002] # <NEW TAI LUE VOWEL SIGN O, NEW TAI LUE LETTER LOW VA> +19BA 199E ; [.32B4.0020.0002][.32CC.0020.0002] # <NEW TAI LUE VOWEL SIGN AY, NEW TAI LUE LETTER LOW VA> +199F ; [.32B5.0020.0002] # NEW TAI LUE LETTER LOW LA +19B5 199F ; [.32B5.0020.0002][.32C7.0020.0002] # <NEW TAI LUE VOWEL SIGN E, NEW TAI LUE LETTER LOW LA> +19B6 199F ; [.32B5.0020.0002][.32C8.0020.0002] # <NEW TAI LUE VOWEL SIGN AE, NEW TAI LUE LETTER LOW LA> +19B7 199F ; [.32B5.0020.0002][.32C9.0020.0002] # <NEW TAI LUE VOWEL SIGN O, NEW TAI LUE LETTER LOW LA> +19BA 199F ; [.32B5.0020.0002][.32CC.0020.0002] # <NEW TAI LUE VOWEL SIGN AY, NEW TAI LUE LETTER LOW LA> +19A0 ; [.32B6.0020.0002] # NEW TAI LUE LETTER HIGH HA +19B5 19A0 ; [.32B6.0020.0002][.32C7.0020.0002] # <NEW TAI LUE VOWEL SIGN E, NEW TAI LUE LETTER HIGH HA> +19B6 19A0 ; [.32B6.0020.0002][.32C8.0020.0002] # <NEW TAI LUE VOWEL SIGN AE, NEW TAI LUE LETTER HIGH HA> +19B7 19A0 ; [.32B6.0020.0002][.32C9.0020.0002] # <NEW TAI LUE VOWEL SIGN O, NEW TAI LUE LETTER HIGH HA> +19BA 19A0 ; [.32B6.0020.0002][.32CC.0020.0002] # <NEW TAI LUE VOWEL SIGN AY, NEW TAI LUE LETTER HIGH HA> +19A1 ; [.32B7.0020.0002] # NEW TAI LUE LETTER HIGH DA +19B5 19A1 ; [.32B7.0020.0002][.32C7.0020.0002] # <NEW TAI LUE VOWEL SIGN E, NEW TAI LUE LETTER HIGH DA> +19B6 19A1 ; [.32B7.0020.0002][.32C8.0020.0002] # <NEW TAI LUE VOWEL SIGN AE, NEW TAI LUE LETTER HIGH DA> +19B7 19A1 ; [.32B7.0020.0002][.32C9.0020.0002] # <NEW TAI LUE VOWEL SIGN O, NEW TAI LUE LETTER HIGH DA> +19BA 19A1 ; [.32B7.0020.0002][.32CC.0020.0002] # <NEW TAI LUE VOWEL SIGN AY, NEW TAI LUE LETTER HIGH DA> +19A2 ; [.32B8.0020.0002] # NEW TAI LUE LETTER HIGH BA +19B5 19A2 ; [.32B8.0020.0002][.32C7.0020.0002] # <NEW TAI LUE VOWEL SIGN E, NEW TAI LUE LETTER HIGH BA> +19B6 19A2 ; [.32B8.0020.0002][.32C8.0020.0002] # <NEW TAI LUE VOWEL SIGN AE, NEW TAI LUE LETTER HIGH BA> +19B7 19A2 ; [.32B8.0020.0002][.32C9.0020.0002] # <NEW TAI LUE VOWEL SIGN O, NEW TAI LUE LETTER HIGH BA> +19BA 19A2 ; [.32B8.0020.0002][.32CC.0020.0002] # <NEW TAI LUE VOWEL SIGN AY, NEW TAI LUE LETTER HIGH BA> +19A3 ; [.32B9.0020.0002] # NEW TAI LUE LETTER LOW HA +19B5 19A3 ; [.32B9.0020.0002][.32C7.0020.0002] # <NEW TAI LUE VOWEL SIGN E, NEW TAI LUE LETTER LOW HA> +19B6 19A3 ; [.32B9.0020.0002][.32C8.0020.0002] # <NEW TAI LUE VOWEL SIGN AE, NEW TAI LUE LETTER LOW HA> +19B7 19A3 ; [.32B9.0020.0002][.32C9.0020.0002] # <NEW TAI LUE VOWEL SIGN O, NEW TAI LUE LETTER LOW HA> +19BA 19A3 ; [.32B9.0020.0002][.32CC.0020.0002] # <NEW TAI LUE VOWEL SIGN AY, NEW TAI LUE LETTER LOW HA> +19A4 ; [.32BA.0020.0002] # NEW TAI LUE LETTER LOW DA +19B5 19A4 ; [.32BA.0020.0002][.32C7.0020.0002] # <NEW TAI LUE VOWEL SIGN E, NEW TAI LUE LETTER LOW DA> +19B6 19A4 ; [.32BA.0020.0002][.32C8.0020.0002] # <NEW TAI LUE VOWEL SIGN AE, NEW TAI LUE LETTER LOW DA> +19B7 19A4 ; [.32BA.0020.0002][.32C9.0020.0002] # <NEW TAI LUE VOWEL SIGN O, NEW TAI LUE LETTER LOW DA> +19BA 19A4 ; [.32BA.0020.0002][.32CC.0020.0002] # <NEW TAI LUE VOWEL SIGN AY, NEW TAI LUE LETTER LOW DA> +19A5 ; [.32BB.0020.0002] # NEW TAI LUE LETTER LOW BA +19B5 19A5 ; [.32BB.0020.0002][.32C7.0020.0002] # <NEW TAI LUE VOWEL SIGN E, NEW TAI LUE LETTER LOW BA> +19B6 19A5 ; [.32BB.0020.0002][.32C8.0020.0002] # <NEW TAI LUE VOWEL SIGN AE, NEW TAI LUE LETTER LOW BA> +19B7 19A5 ; [.32BB.0020.0002][.32C9.0020.0002] # <NEW TAI LUE VOWEL SIGN O, NEW TAI LUE LETTER LOW BA> +19BA 19A5 ; [.32BB.0020.0002][.32CC.0020.0002] # <NEW TAI LUE VOWEL SIGN AY, NEW TAI LUE LETTER LOW BA> +19A6 ; [.32BC.0020.0002] # NEW TAI LUE LETTER HIGH KVA +19B5 19A6 ; [.32BC.0020.0002][.32C7.0020.0002] # <NEW TAI LUE VOWEL SIGN E, NEW TAI LUE LETTER HIGH KVA> +19B6 19A6 ; [.32BC.0020.0002][.32C8.0020.0002] # <NEW TAI LUE VOWEL SIGN AE, NEW TAI LUE LETTER HIGH KVA> +19B7 19A6 ; [.32BC.0020.0002][.32C9.0020.0002] # <NEW TAI LUE VOWEL SIGN O, NEW TAI LUE LETTER HIGH KVA> +19BA 19A6 ; [.32BC.0020.0002][.32CC.0020.0002] # <NEW TAI LUE VOWEL SIGN AY, NEW TAI LUE LETTER HIGH KVA> +19A7 ; [.32BD.0020.0002] # NEW TAI LUE LETTER HIGH XVA +19B5 19A7 ; [.32BD.0020.0002][.32C7.0020.0002] # <NEW TAI LUE VOWEL SIGN E, NEW TAI LUE LETTER HIGH XVA> +19B6 19A7 ; [.32BD.0020.0002][.32C8.0020.0002] # <NEW TAI LUE VOWEL SIGN AE, NEW TAI LUE LETTER HIGH XVA> +19B7 19A7 ; [.32BD.0020.0002][.32C9.0020.0002] # <NEW TAI LUE VOWEL SIGN O, NEW TAI LUE LETTER HIGH XVA> +19BA 19A7 ; [.32BD.0020.0002][.32CC.0020.0002] # <NEW TAI LUE VOWEL SIGN AY, NEW TAI LUE LETTER HIGH XVA> +19A8 ; [.32BE.0020.0002] # NEW TAI LUE LETTER LOW KVA +19B5 19A8 ; [.32BE.0020.0002][.32C7.0020.0002] # <NEW TAI LUE VOWEL SIGN E, NEW TAI LUE LETTER LOW KVA> +19B6 19A8 ; [.32BE.0020.0002][.32C8.0020.0002] # <NEW TAI LUE VOWEL SIGN AE, NEW TAI LUE LETTER LOW KVA> +19B7 19A8 ; [.32BE.0020.0002][.32C9.0020.0002] # <NEW TAI LUE VOWEL SIGN O, NEW TAI LUE LETTER LOW KVA> +19BA 19A8 ; [.32BE.0020.0002][.32CC.0020.0002] # <NEW TAI LUE VOWEL SIGN AY, NEW TAI LUE LETTER LOW KVA> +19A9 ; [.32BF.0020.0002] # NEW TAI LUE LETTER LOW XVA +19B5 19A9 ; [.32BF.0020.0002][.32C7.0020.0002] # <NEW TAI LUE VOWEL SIGN E, NEW TAI LUE LETTER LOW XVA> +19B6 19A9 ; [.32BF.0020.0002][.32C8.0020.0002] # <NEW TAI LUE VOWEL SIGN AE, NEW TAI LUE LETTER LOW XVA> +19B7 19A9 ; [.32BF.0020.0002][.32C9.0020.0002] # <NEW TAI LUE VOWEL SIGN O, NEW TAI LUE LETTER LOW XVA> +19BA 19A9 ; [.32BF.0020.0002][.32CC.0020.0002] # <NEW TAI LUE VOWEL SIGN AY, NEW TAI LUE LETTER LOW XVA> +19AA ; [.32C0.0020.0002] # NEW TAI LUE LETTER HIGH SUA +19B5 19AA ; [.32C0.0020.0002][.32C7.0020.0002] # <NEW TAI LUE VOWEL SIGN E, NEW TAI LUE LETTER HIGH SUA> +19B6 19AA ; [.32C0.0020.0002][.32C8.0020.0002] # <NEW TAI LUE VOWEL SIGN AE, NEW TAI LUE LETTER HIGH SUA> +19B7 19AA ; [.32C0.0020.0002][.32C9.0020.0002] # <NEW TAI LUE VOWEL SIGN O, NEW TAI LUE LETTER HIGH SUA> +19BA 19AA ; [.32C0.0020.0002][.32CC.0020.0002] # <NEW TAI LUE VOWEL SIGN AY, NEW TAI LUE LETTER HIGH SUA> +19AB ; [.32C1.0020.0002] # NEW TAI LUE LETTER LOW SUA +19B5 19AB ; [.32C1.0020.0002][.32C7.0020.0002] # <NEW TAI LUE VOWEL SIGN E, NEW TAI LUE LETTER LOW SUA> +19B6 19AB ; [.32C1.0020.0002][.32C8.0020.0002] # <NEW TAI LUE VOWEL SIGN AE, NEW TAI LUE LETTER LOW SUA> +19B7 19AB ; [.32C1.0020.0002][.32C9.0020.0002] # <NEW TAI LUE VOWEL SIGN O, NEW TAI LUE LETTER LOW SUA> +19BA 19AB ; [.32C1.0020.0002][.32CC.0020.0002] # <NEW TAI LUE VOWEL SIGN AY, NEW TAI LUE LETTER LOW SUA> +19B0 ; [.32C2.0020.0002] # NEW TAI LUE VOWEL SIGN VOWEL SHORTENER +19B1 ; [.32C3.0020.0002] # NEW TAI LUE VOWEL SIGN AA +19B2 ; [.32C4.0020.0002] # NEW TAI LUE VOWEL SIGN II +19B3 ; [.32C5.0020.0002] # NEW TAI LUE VOWEL SIGN U +19B4 ; [.32C6.0020.0002] # NEW TAI LUE VOWEL SIGN UU +19B5 ; [.32C7.0020.0002] # NEW TAI LUE VOWEL SIGN E +19B6 ; [.32C8.0020.0002] # NEW TAI LUE VOWEL SIGN AE +19B7 ; [.32C9.0020.0002] # NEW TAI LUE VOWEL SIGN O +19B8 ; [.32CA.0020.0002] # NEW TAI LUE VOWEL SIGN OA +19B9 ; [.32CB.0020.0002] # NEW TAI LUE VOWEL SIGN UE +19BA ; [.32CC.0020.0002] # NEW TAI LUE VOWEL SIGN AY +19BB ; [.32CD.0020.0002] # NEW TAI LUE VOWEL SIGN AAY +19BC ; [.32CE.0020.0002] # NEW TAI LUE VOWEL SIGN UY +19BD ; [.32CF.0020.0002] # NEW TAI LUE VOWEL SIGN OY +19BE ; [.32D0.0020.0002] # NEW TAI LUE VOWEL SIGN OAY +19BF ; [.32D1.0020.0002] # NEW TAI LUE VOWEL SIGN UEY +19C0 ; [.32D2.0020.0002] # NEW TAI LUE VOWEL SIGN IY +19C1 ; [.32D3.0020.0002] # NEW TAI LUE LETTER FINAL V +19C2 ; [.32D4.0020.0002] # NEW TAI LUE LETTER FINAL NG +19C3 ; [.32D5.0020.0002] # NEW TAI LUE LETTER FINAL N +19C4 ; [.32D6.0020.0002] # NEW TAI LUE LETTER FINAL M +19C5 ; [.32D7.0020.0002] # NEW TAI LUE LETTER FINAL K +19C6 ; [.32D8.0020.0002] # NEW TAI LUE LETTER FINAL D +19C7 ; [.32D9.0020.0002] # NEW TAI LUE LETTER FINAL B +19C8 ; [.32DA.0020.0002] # NEW TAI LUE TONE MARK-1 +19C9 ; [.32DB.0020.0002] # NEW TAI LUE TONE MARK-2 +1A20 ; [.32DC.0020.0002] # TAI THAM LETTER HIGH KA +1A21 ; [.32DD.0020.0002] # TAI THAM LETTER HIGH KHA +1A22 ; [.32DE.0020.0002] # TAI THAM LETTER HIGH KXA +1A23 ; [.32DF.0020.0002] # TAI THAM LETTER LOW KA +1A24 ; [.32E0.0020.0002] # TAI THAM LETTER LOW KXA +1A25 ; [.32E1.0020.0002] # TAI THAM LETTER LOW KHA +1A26 ; [.32E2.0020.0002] # TAI THAM LETTER NGA +1A58 ; [.32E2.0020.0004] # TAI THAM SIGN MAI KANG LAI +1A59 ; [.32E2.0020.0004] # TAI THAM CONSONANT SIGN FINAL NGA +1A27 ; [.32E3.0020.0002] # TAI THAM LETTER HIGH CA +1A28 ; [.32E4.0020.0002] # TAI THAM LETTER HIGH CHA +1A29 ; [.32E5.0020.0002] # TAI THAM LETTER LOW CA +1A2A ; [.32E6.0020.0002] # TAI THAM LETTER LOW SA +1A2B ; [.32E7.0020.0002] # TAI THAM LETTER LOW CHA +1A2C ; [.32E8.0020.0002] # TAI THAM LETTER NYA +1A2D ; [.32E9.0020.0002] # TAI THAM LETTER RATA +1A2E ; [.32EA.0020.0002] # TAI THAM LETTER HIGH RATHA +1A2F ; [.32EB.0020.0002] # TAI THAM LETTER DA +1A30 ; [.32EC.0020.0002] # TAI THAM LETTER LOW RATHA +1A31 ; [.32ED.0020.0002] # TAI THAM LETTER RANA +1A32 ; [.32EE.0020.0002] # TAI THAM LETTER HIGH TA +1A33 ; [.32EF.0020.0002] # TAI THAM LETTER HIGH THA +1A34 ; [.32F0.0020.0002] # TAI THAM LETTER LOW TA +1A35 ; [.32F1.0020.0002] # TAI THAM LETTER LOW THA +1A36 ; [.32F2.0020.0002] # TAI THAM LETTER NA +1A37 ; [.32F3.0020.0002] # TAI THAM LETTER BA +1A38 ; [.32F4.0020.0002] # TAI THAM LETTER HIGH PA +1A39 ; [.32F5.0020.0002] # TAI THAM LETTER HIGH PHA +1A3A ; [.32F6.0020.0002] # TAI THAM LETTER HIGH FA +1A3B ; [.32F7.0020.0002] # TAI THAM LETTER LOW PA +1A5A ; [.32F7.0020.0004] # TAI THAM CONSONANT SIGN LOW PA +1A5B ; [.32F7.0020.0004] # TAI THAM CONSONANT SIGN HIGH RATHA OR LOW PA +1A3C ; [.32F8.0020.0002] # TAI THAM LETTER LOW FA +1A3D ; [.32F9.0020.0002] # TAI THAM LETTER LOW PHA +1A3E ; [.32FA.0020.0002] # TAI THAM LETTER MA +1A3F ; [.32FB.0020.0002] # TAI THAM LETTER LOW YA +1A40 ; [.32FC.0020.0002] # TAI THAM LETTER HIGH YA +1A41 ; [.32FD.0020.0002] # TAI THAM LETTER RA +1A42 ; [.32FE.0020.0002] # TAI THAM LETTER RUE +1A43 ; [.32FF.0020.0002] # TAI THAM LETTER LA +1A44 ; [.3300.0020.0002] # TAI THAM LETTER LUE +1A45 ; [.3301.0020.0002] # TAI THAM LETTER WA +1A46 ; [.3302.0020.0002] # TAI THAM LETTER HIGH SHA +1A54 ; [.3302.0020.0004][.3328.0020.0004][.3302.0020.0004] # TAI THAM LETTER GREAT SA +1A47 ; [.3303.0020.0002] # TAI THAM LETTER HIGH SSA +1A48 ; [.3304.0020.0002] # TAI THAM LETTER HIGH SA +1A49 ; [.3305.0020.0002] # TAI THAM LETTER HIGH HA +1A4A ; [.3306.0020.0002] # TAI THAM LETTER LLA +1A4B ; [.3307.0020.0002] # TAI THAM LETTER A +1A4C ; [.3308.0020.0002] # TAI THAM LETTER LOW HA +1A53 ; [.3309.0020.0002] # TAI THAM LETTER LAE +1A6B ; [.330A.0020.0002] # TAI THAM VOWEL SIGN O +1A55 ; [.330B.0020.0002] # TAI THAM CONSONANT SIGN MEDIAL RA +1A56 ; [.330C.0020.0002] # TAI THAM CONSONANT SIGN MEDIAL LA +1A57 ; [.330D.0020.0002] # TAI THAM CONSONANT SIGN LA TANG LAI +1A5C ; [.330E.0020.0002] # TAI THAM CONSONANT SIGN MA +1A5D ; [.330F.0020.0002] # TAI THAM CONSONANT SIGN BA +1A5E ; [.3310.0020.0002] # TAI THAM CONSONANT SIGN SA +1A4D ; [.3311.0020.0002] # TAI THAM LETTER I +1A4E ; [.3312.0020.0002] # TAI THAM LETTER II +1A4F ; [.3313.0020.0002] # TAI THAM LETTER U +1A50 ; [.3314.0020.0002] # TAI THAM LETTER UU +1A51 ; [.3315.0020.0002] # TAI THAM LETTER EE +1A52 ; [.3316.0020.0002] # TAI THAM LETTER OO +1A61 ; [.3317.0020.0002] # TAI THAM VOWEL SIGN A +1A6C ; [.3318.0020.0002] # TAI THAM VOWEL SIGN OA BELOW +1A62 ; [.3319.0020.0002] # TAI THAM VOWEL SIGN MAI SAT +1A63 ; [.331A.0020.0002] # TAI THAM VOWEL SIGN AA +1A64 ; [.331A.0020.0004] # TAI THAM VOWEL SIGN TALL AA +1A65 ; [.331B.0020.0002] # TAI THAM VOWEL SIGN I +1A66 ; [.331C.0020.0002] # TAI THAM VOWEL SIGN II +1A67 ; [.331D.0020.0002] # TAI THAM VOWEL SIGN UE +1A68 ; [.331E.0020.0002] # TAI THAM VOWEL SIGN UUE +1A69 ; [.331F.0020.0002] # TAI THAM VOWEL SIGN U +1A6A ; [.3320.0020.0002] # TAI THAM VOWEL SIGN UU +1A6E ; [.3321.0020.0002] # TAI THAM VOWEL SIGN E +1A6F ; [.3322.0020.0002] # TAI THAM VOWEL SIGN AE +1A73 ; [.3323.0020.0002] # TAI THAM VOWEL SIGN OA ABOVE +1A70 ; [.3324.0020.0002] # TAI THAM VOWEL SIGN OO +1A71 ; [.3325.0020.0002] # TAI THAM VOWEL SIGN AI +1A72 ; [.3326.0020.0002] # TAI THAM VOWEL SIGN THAM AI +1A6D ; [.3327.0020.0002] # TAI THAM VOWEL SIGN OY +1A60 ; [.3328.0020.0002] # TAI THAM SIGN SAKOT +AA00 ; [.3329.0020.0002] # CHAM LETTER A +AA01 ; [.332A.0020.0002] # CHAM LETTER I +AA02 ; [.332B.0020.0002] # CHAM LETTER U +AA03 ; [.332C.0020.0002] # CHAM LETTER E +AA04 ; [.332D.0020.0002] # CHAM LETTER AI +AA05 ; [.332E.0020.0002] # CHAM LETTER O +AA06 ; [.332F.0020.0002] # CHAM LETTER KA +AA07 ; [.3330.0020.0002] # CHAM LETTER KHA +AA08 ; [.3331.0020.0002] # CHAM LETTER GA +AA09 ; [.3332.0020.0002] # CHAM LETTER GHA +AA0A ; [.3333.0020.0002] # CHAM LETTER NGUE +AA0B ; [.3334.0020.0002] # CHAM LETTER NGA +AA0C ; [.3335.0020.0002] # CHAM LETTER CHA +AA0D ; [.3336.0020.0002] # CHAM LETTER CHHA +AA0E ; [.3337.0020.0002] # CHAM LETTER JA +AA0F ; [.3338.0020.0002] # CHAM LETTER JHA +AA10 ; [.3339.0020.0002] # CHAM LETTER NHUE +AA11 ; [.333A.0020.0002] # CHAM LETTER NHA +AA12 ; [.333B.0020.0002] # CHAM LETTER NHJA +AA13 ; [.333C.0020.0002] # CHAM LETTER TA +AA14 ; [.333D.0020.0002] # CHAM LETTER THA +AA15 ; [.333E.0020.0002] # CHAM LETTER DA +AA16 ; [.333F.0020.0002] # CHAM LETTER DHA +AA17 ; [.3340.0020.0002] # CHAM LETTER NUE +AA18 ; [.3341.0020.0002] # CHAM LETTER NA +AA19 ; [.3342.0020.0002] # CHAM LETTER DDA +AA1A ; [.3343.0020.0002] # CHAM LETTER PA +AA1B ; [.3344.0020.0002] # CHAM LETTER PPA +AA1C ; [.3345.0020.0002] # CHAM LETTER PHA +AA1D ; [.3346.0020.0002] # CHAM LETTER BA +AA1E ; [.3347.0020.0002] # CHAM LETTER BHA +AA1F ; [.3348.0020.0002] # CHAM LETTER MUE +AA20 ; [.3349.0020.0002] # CHAM LETTER MA +AA21 ; [.334A.0020.0002] # CHAM LETTER BBA +AA22 ; [.334B.0020.0002] # CHAM LETTER YA +AA23 ; [.334C.0020.0002] # CHAM LETTER RA +AA24 ; [.334D.0020.0002] # CHAM LETTER LA +AA25 ; [.334E.0020.0002] # CHAM LETTER VA +AA26 ; [.334F.0020.0002] # CHAM LETTER SSA +AA27 ; [.3350.0020.0002] # CHAM LETTER SA +AA28 ; [.3351.0020.0002] # CHAM LETTER HA +AA33 ; [.3352.0020.0002] # CHAM CONSONANT SIGN YA +AA34 ; [.3353.0020.0002] # CHAM CONSONANT SIGN RA +AA35 ; [.3354.0020.0002] # CHAM CONSONANT SIGN LA +AA36 ; [.3355.0020.0002] # CHAM CONSONANT SIGN WA +AA29 ; [.3356.0020.0002] # CHAM VOWEL SIGN AA +AA2A ; [.3357.0020.0002] # CHAM VOWEL SIGN I +AA2B ; [.3358.0020.0002] # CHAM VOWEL SIGN II +AA2C ; [.3359.0020.0002] # CHAM VOWEL SIGN EI +AA2D ; [.335A.0020.0002] # CHAM VOWEL SIGN U +AA2E ; [.335B.0020.0002] # CHAM VOWEL SIGN OE +AA2F ; [.335C.0020.0002] # CHAM VOWEL SIGN O +AA30 ; [.335D.0020.0002] # CHAM VOWEL SIGN AI +AA31 ; [.335E.0020.0002] # CHAM VOWEL SIGN AU +AA32 ; [.335F.0020.0002] # CHAM VOWEL SIGN UE +AA40 ; [.3360.0020.0002] # CHAM LETTER FINAL K +AA41 ; [.3361.0020.0002] # CHAM LETTER FINAL G +AA42 ; [.3362.0020.0002] # CHAM LETTER FINAL NG +AA43 ; [.3363.0020.0002] # CHAM CONSONANT SIGN FINAL NG +AA44 ; [.3364.0020.0002] # CHAM LETTER FINAL CH +AA45 ; [.3365.0020.0002] # CHAM LETTER FINAL T +AA46 ; [.3366.0020.0002] # CHAM LETTER FINAL N +AA47 ; [.3367.0020.0002] # CHAM LETTER FINAL P +AA48 ; [.3368.0020.0002] # CHAM LETTER FINAL Y +AA49 ; [.3369.0020.0002] # CHAM LETTER FINAL R +AA4A ; [.336A.0020.0002] # CHAM LETTER FINAL L +AA4B ; [.336B.0020.0002] # CHAM LETTER FINAL SS +AA4C ; [.336C.0020.0002] # CHAM CONSONANT SIGN FINAL M +AA4D ; [.336D.0020.0002] # CHAM CONSONANT SIGN FINAL H +1B05 ; [.336E.0020.0002] # BALINESE LETTER AKARA +1B06 ; [.336F.0020.0002] # BALINESE LETTER AKARA TEDUNG +1B05 1B35 ; [.336F.0020.0002] # BALINESE LETTER AKARA TEDUNG +1B07 ; [.3370.0020.0002] # BALINESE LETTER IKARA +1B08 ; [.3371.0020.0002] # BALINESE LETTER IKARA TEDUNG +1B07 1B35 ; [.3371.0020.0002] # BALINESE LETTER IKARA TEDUNG +1B09 ; [.3372.0020.0002] # BALINESE LETTER UKARA +1B0A ; [.3373.0020.0002] # BALINESE LETTER UKARA TEDUNG +1B09 1B35 ; [.3373.0020.0002] # BALINESE LETTER UKARA TEDUNG +1B0B ; [.3374.0020.0002] # BALINESE LETTER RA REPA +1B0C ; [.3375.0020.0002] # BALINESE LETTER RA REPA TEDUNG +1B0B 1B35 ; [.3375.0020.0002] # BALINESE LETTER RA REPA TEDUNG +1B0D ; [.3376.0020.0002] # BALINESE LETTER LA LENGA +1B0E ; [.3377.0020.0002] # BALINESE LETTER LA LENGA TEDUNG +1B0D 1B35 ; [.3377.0020.0002] # BALINESE LETTER LA LENGA TEDUNG +1B0F ; [.3378.0020.0002] # BALINESE LETTER EKARA +1B10 ; [.3379.0020.0002] # BALINESE LETTER AIKARA +1B11 ; [.337A.0020.0002] # BALINESE LETTER OKARA +1B12 ; [.337B.0020.0002] # BALINESE LETTER OKARA TEDUNG +1B11 1B35 ; [.337B.0020.0002] # BALINESE LETTER OKARA TEDUNG +1B13 ; [.337C.0020.0002] # BALINESE LETTER KA +1B45 ; [.337D.0020.0002] # BALINESE LETTER KAF SASAK +1B46 ; [.337E.0020.0002] # BALINESE LETTER KHOT SASAK +1B14 ; [.337F.0020.0002] # BALINESE LETTER KA MAHAPRANA +1B15 ; [.3380.0020.0002] # BALINESE LETTER GA +1B16 ; [.3381.0020.0002] # BALINESE LETTER GA GORA +1B17 ; [.3382.0020.0002] # BALINESE LETTER NGA +1B18 ; [.3383.0020.0002] # BALINESE LETTER CA +1B19 ; [.3384.0020.0002] # BALINESE LETTER CA LACA +1B1A ; [.3385.0020.0002] # BALINESE LETTER JA +1B1B ; [.3386.0020.0002] # BALINESE LETTER JA JERA +1B1C ; [.3387.0020.0002] # BALINESE LETTER NYA +1B1D ; [.3388.0020.0002] # BALINESE LETTER TA LATIK +1B1E ; [.3389.0020.0002] # BALINESE LETTER TA MURDA MAHAPRANA +1B1F ; [.338A.0020.0002] # BALINESE LETTER DA MURDA ALPAPRANA +1B20 ; [.338B.0020.0002] # BALINESE LETTER DA MURDA MAHAPRANA +1B21 ; [.338C.0020.0002] # BALINESE LETTER NA RAMBAT +1B22 ; [.338D.0020.0002] # BALINESE LETTER TA +1B47 ; [.338E.0020.0002] # BALINESE LETTER TZIR SASAK +1B23 ; [.338F.0020.0002] # BALINESE LETTER TA TAWA +1B24 ; [.3390.0020.0002] # BALINESE LETTER DA +1B25 ; [.3391.0020.0002] # BALINESE LETTER DA MADU +1B26 ; [.3392.0020.0002] # BALINESE LETTER NA +1B27 ; [.3393.0020.0002] # BALINESE LETTER PA +1B48 ; [.3394.0020.0002] # BALINESE LETTER EF SASAK +1B28 ; [.3395.0020.0002] # BALINESE LETTER PA KAPAL +1B29 ; [.3396.0020.0002] # BALINESE LETTER BA +1B2A ; [.3397.0020.0002] # BALINESE LETTER BA KEMBANG +1B2B ; [.3398.0020.0002] # BALINESE LETTER MA +1B2C ; [.3399.0020.0002] # BALINESE LETTER YA +1B2D ; [.339A.0020.0002] # BALINESE LETTER RA +1B2E ; [.339B.0020.0002] # BALINESE LETTER LA +1B2F ; [.339C.0020.0002] # BALINESE LETTER WA +1B49 ; [.339D.0020.0002] # BALINESE LETTER VE SASAK +1B30 ; [.339E.0020.0002] # BALINESE LETTER SA SAGA +1B31 ; [.339F.0020.0002] # BALINESE LETTER SA SAPA +1B32 ; [.33A0.0020.0002] # BALINESE LETTER SA +1B4A ; [.33A1.0020.0002] # BALINESE LETTER ZAL SASAK +1B4B ; [.33A2.0020.0002] # BALINESE LETTER ASYURA SASAK +1B33 ; [.33A3.0020.0002] # BALINESE LETTER HA +1B35 ; [.33A4.0020.0002] # BALINESE VOWEL SIGN TEDUNG +1B36 ; [.33A5.0020.0002] # BALINESE VOWEL SIGN ULU +1B37 ; [.33A6.0020.0002] # BALINESE VOWEL SIGN ULU SARI +1B38 ; [.33A7.0020.0002] # BALINESE VOWEL SIGN SUKU +1B39 ; [.33A8.0020.0002] # BALINESE VOWEL SIGN SUKU ILUT +1B3A ; [.33A9.0020.0002] # BALINESE VOWEL SIGN RA REPA +1B3B ; [.33AA.0020.0002] # BALINESE VOWEL SIGN RA REPA TEDUNG +1B3A 1B35 ; [.33AA.0020.0002] # BALINESE VOWEL SIGN RA REPA TEDUNG +1B3C ; [.33AB.0020.0002] # BALINESE VOWEL SIGN LA LENGA +1B3D ; [.33AC.0020.0002] # BALINESE VOWEL SIGN LA LENGA TEDUNG +1B3C 1B35 ; [.33AC.0020.0002] # BALINESE VOWEL SIGN LA LENGA TEDUNG +1B3E ; [.33AD.0020.0002] # BALINESE VOWEL SIGN TALING +1B3F ; [.33AE.0020.0002] # BALINESE VOWEL SIGN TALING REPA +1B40 ; [.33AF.0020.0002] # BALINESE VOWEL SIGN TALING TEDUNG +1B3E 1B35 ; [.33AF.0020.0002] # BALINESE VOWEL SIGN TALING TEDUNG +1B41 ; [.33B0.0020.0002] # BALINESE VOWEL SIGN TALING REPA TEDUNG +1B3F 1B35 ; [.33B0.0020.0002] # BALINESE VOWEL SIGN TALING REPA TEDUNG +1B42 ; [.33B1.0020.0002] # BALINESE VOWEL SIGN PEPET +1B43 ; [.33B2.0020.0002] # BALINESE VOWEL SIGN PEPET TEDUNG +1B42 1B35 ; [.33B2.0020.0002] # BALINESE VOWEL SIGN PEPET TEDUNG +1B44 ; [.33B3.0020.0002] # BALINESE ADEG ADEG +A984 ; [.33B4.0020.0002] # JAVANESE LETTER A +A985 ; [.33B5.0020.0002] # JAVANESE LETTER I KAWI +A986 ; [.33B6.0020.0002] # JAVANESE LETTER I +A987 ; [.33B7.0020.0002] # JAVANESE LETTER II +A988 ; [.33B8.0020.0002] # JAVANESE LETTER U +A989 ; [.33B9.0020.0002] # JAVANESE LETTER PA CEREK +A98A ; [.33BA.0020.0002] # JAVANESE LETTER NGA LELET +A98B ; [.33BB.0020.0002] # JAVANESE LETTER NGA LELET RASWADI +A98C ; [.33BC.0020.0002] # JAVANESE LETTER E +A98D ; [.33BD.0020.0002] # JAVANESE LETTER AI +A98E ; [.33BE.0020.0002] # JAVANESE LETTER O +A98F ; [.33BF.0020.0002] # JAVANESE LETTER KA +A990 ; [.33C0.0020.0002] # JAVANESE LETTER KA SASAK +A991 ; [.33C1.0020.0002] # JAVANESE LETTER KA MURDA +A992 ; [.33C2.0020.0002] # JAVANESE LETTER GA +A993 ; [.33C3.0020.0002] # JAVANESE LETTER GA MURDA +A994 ; [.33C4.0020.0002] # JAVANESE LETTER NGA +A995 ; [.33C5.0020.0002] # JAVANESE LETTER CA +A996 ; [.33C6.0020.0002] # JAVANESE LETTER CA MURDA +A997 ; [.33C7.0020.0002] # JAVANESE LETTER JA +A998 ; [.33C8.0020.0002] # JAVANESE LETTER NYA MURDA +A999 ; [.33C9.0020.0002] # JAVANESE LETTER JA MAHAPRANA +A99A ; [.33CA.0020.0002] # JAVANESE LETTER NYA +A99B ; [.33CB.0020.0002] # JAVANESE LETTER TTA +A99C ; [.33CC.0020.0002] # JAVANESE LETTER TTA MAHAPRANA +A99D ; [.33CD.0020.0002] # JAVANESE LETTER DDA +A99E ; [.33CE.0020.0002] # JAVANESE LETTER DDA MAHAPRANA +A99F ; [.33CF.0020.0002] # JAVANESE LETTER NA MURDA +A9A0 ; [.33D0.0020.0002] # JAVANESE LETTER TA +A9A1 ; [.33D1.0020.0002] # JAVANESE LETTER TA MURDA +A9A2 ; [.33D2.0020.0002] # JAVANESE LETTER DA +A9A3 ; [.33D3.0020.0002] # JAVANESE LETTER DA MAHAPRANA +A9A4 ; [.33D4.0020.0002] # JAVANESE LETTER NA +A9A5 ; [.33D5.0020.0002] # JAVANESE LETTER PA +A9A6 ; [.33D6.0020.0002] # JAVANESE LETTER PA MURDA +A9A7 ; [.33D7.0020.0002] # JAVANESE LETTER BA +A9A8 ; [.33D8.0020.0002] # JAVANESE LETTER BA MURDA +A9A9 ; [.33D9.0020.0002] # JAVANESE LETTER MA +A9AA ; [.33DA.0020.0002] # JAVANESE LETTER YA +A9BE ; [.33DB.0020.0002] # JAVANESE CONSONANT SIGN PENGKAL +A9AB ; [.33DC.0020.0002] # JAVANESE LETTER RA +A9AC ; [.33DC.0020.0004] # JAVANESE LETTER RA AGUNG +A9BF ; [.33DD.0020.0002] # JAVANESE CONSONANT SIGN CAKRA +A9AD ; [.33DE.0020.0002] # JAVANESE LETTER LA +A9AE ; [.33DF.0020.0002] # JAVANESE LETTER WA +A9AF ; [.33E0.0020.0002] # JAVANESE LETTER SA MURDA +A9B0 ; [.33E1.0020.0002] # JAVANESE LETTER SA MAHAPRANA +A9B1 ; [.33E2.0020.0002] # JAVANESE LETTER SA +A9B2 ; [.33E3.0020.0002] # JAVANESE LETTER HA +A9B4 ; [.33E4.0020.0002] # JAVANESE VOWEL SIGN TARUNG +A9BC ; [.33E5.0020.0002] # JAVANESE VOWEL SIGN PEPET +A9B6 ; [.33E6.0020.0002] # JAVANESE VOWEL SIGN WULU +A9B7 ; [.33E7.0020.0002] # JAVANESE VOWEL SIGN WULU MELIK +A9B8 ; [.33E8.0020.0002] # JAVANESE VOWEL SIGN SUKU +A9B9 ; [.33E9.0020.0002] # JAVANESE VOWEL SIGN SUKU MENDUT +A9BD ; [.33EA.0020.0002] # JAVANESE CONSONANT SIGN KERET +A9BA ; [.33EB.0020.0002] # JAVANESE VOWEL SIGN TALING +A9BB ; [.33EC.0020.0002] # JAVANESE VOWEL SIGN DIRGA MURE +A9B5 ; [.33ED.0020.0002] # JAVANESE VOWEL SIGN TOLONG +A9C0 ; [.33EE.0020.0002] # JAVANESE PANGKON +1880 ; [.33EF.0020.0002] # MONGOLIAN LETTER ALI GALI ANUSVARA ONE +1881 ; [.33F0.0020.0002] # MONGOLIAN LETTER ALI GALI VISARGA ONE +1882 ; [.33F1.0020.0002] # MONGOLIAN LETTER ALI GALI DAMARU +1883 ; [.33F2.0020.0002] # MONGOLIAN LETTER ALI GALI UBADAMA +1884 ; [.33F3.0020.0002] # MONGOLIAN LETTER ALI GALI INVERTED UBADAMA +1885 ; [.33F4.0020.0002] # MONGOLIAN LETTER ALI GALI BALUDA +1886 ; [.33F5.0020.0002] # MONGOLIAN LETTER ALI GALI THREE BALUDA +1843 ; [.33F6.0020.0002] # MONGOLIAN LETTER TODO LONG VOWEL SIGN +1820 ; [.33F7.0020.0002] # MONGOLIAN LETTER A +1887 ; [.33F8.0020.0002] # MONGOLIAN LETTER ALI GALI A +1821 ; [.33F9.0020.0002] # MONGOLIAN LETTER E +1844 ; [.33FA.0020.0002] # MONGOLIAN LETTER TODO E +185D ; [.33FB.0020.0002] # MONGOLIAN LETTER SIBE E +1822 ; [.33FC.0020.0002] # MONGOLIAN LETTER I +1845 ; [.33FD.0020.0002] # MONGOLIAN LETTER TODO I +185E ; [.33FE.0020.0002] # MONGOLIAN LETTER SIBE I +1873 ; [.33FF.0020.0002] # MONGOLIAN LETTER MANCHU I +1888 ; [.3400.0020.0002] # MONGOLIAN LETTER ALI GALI I +185F ; [.3401.0020.0002] # MONGOLIAN LETTER SIBE IY +1823 ; [.3402.0020.0002] # MONGOLIAN LETTER O +1846 ; [.3403.0020.0002] # MONGOLIAN LETTER TODO O +1824 ; [.3404.0020.0002] # MONGOLIAN LETTER U +1847 ; [.3405.0020.0002] # MONGOLIAN LETTER TODO U +1861 ; [.3406.0020.0002] # MONGOLIAN LETTER SIBE U +1825 ; [.3407.0020.0002] # MONGOLIAN LETTER OE +1848 ; [.3408.0020.0002] # MONGOLIAN LETTER TODO OE +1826 ; [.3409.0020.0002] # MONGOLIAN LETTER UE +1849 ; [.340A.0020.0002] # MONGOLIAN LETTER TODO UE +1860 ; [.340B.0020.0002] # MONGOLIAN LETTER SIBE UE +1827 ; [.340C.0020.0002] # MONGOLIAN LETTER EE +1828 ; [.340D.0020.0002] # MONGOLIAN LETTER NA +1829 ; [.340E.0020.0002] # MONGOLIAN LETTER ANG +184A ; [.340F.0020.0002] # MONGOLIAN LETTER TODO ANG +1862 ; [.3410.0020.0002] # MONGOLIAN LETTER SIBE ANG +188A ; [.3411.0020.0002] # MONGOLIAN LETTER ALI GALI NGA +189B ; [.3412.0020.0002] # MONGOLIAN LETTER MANCHU ALI GALI NGA +182A ; [.3413.0020.0002] # MONGOLIAN LETTER BA +184B ; [.3414.0020.0002] # MONGOLIAN LETTER TODO BA +182B ; [.3415.0020.0002] # MONGOLIAN LETTER PA +184C ; [.3416.0020.0002] # MONGOLIAN LETTER TODO PA +1866 ; [.3417.0020.0002] # MONGOLIAN LETTER SIBE PA +182C ; [.3418.0020.0002] # MONGOLIAN LETTER QA +184D ; [.3419.0020.0002] # MONGOLIAN LETTER TODO QA +182D ; [.341A.0020.0002] # MONGOLIAN LETTER GA +184E ; [.341B.0020.0002] # MONGOLIAN LETTER TODO GA +1864 ; [.341C.0020.0002] # MONGOLIAN LETTER SIBE GA +189A ; [.341D.0020.0002] # MONGOLIAN LETTER MANCHU ALI GALI GHA +1865 ; [.341E.0020.0002] # MONGOLIAN LETTER SIBE HA +182E ; [.341F.0020.0002] # MONGOLIAN LETTER MA +184F ; [.3420.0020.0002] # MONGOLIAN LETTER TODO MA +182F ; [.3421.0020.0002] # MONGOLIAN LETTER LA +1830 ; [.3422.0020.0002] # MONGOLIAN LETTER SA +1831 ; [.3423.0020.0002] # MONGOLIAN LETTER SHA +1867 ; [.3424.0020.0002] # MONGOLIAN LETTER SIBE SHA +189C ; [.3425.0020.0002] # MONGOLIAN LETTER MANCHU ALI GALI CA +189D ; [.3426.0020.0002] # MONGOLIAN LETTER MANCHU ALI GALI JHA +18A2 ; [.3427.0020.0002] # MONGOLIAN LETTER MANCHU ALI GALI SSA +18A4 ; [.3428.0020.0002] # MONGOLIAN LETTER MANCHU ALI GALI ZHA +18A5 ; [.3429.0020.0002] # MONGOLIAN LETTER MANCHU ALI GALI ZA +1832 ; [.342A.0020.0002] # MONGOLIAN LETTER TA +1850 ; [.342B.0020.0002] # MONGOLIAN LETTER TODO TA +1868 ; [.342C.0020.0002] # MONGOLIAN LETTER SIBE TA +1833 ; [.342D.0020.0002] # MONGOLIAN LETTER DA +1851 ; [.342E.0020.0002] # MONGOLIAN LETTER TODO DA +1869 ; [.342F.0020.0002] # MONGOLIAN LETTER SIBE DA +1834 ; [.3430.0020.0002] # MONGOLIAN LETTER CHA +1852 ; [.3431.0020.0002] # MONGOLIAN LETTER TODO CHA +1871 ; [.3432.0020.0002] # MONGOLIAN LETTER SIBE CHA +185C ; [.3433.0020.0002] # MONGOLIAN LETTER TODO DZA +188B ; [.3434.0020.0002] # MONGOLIAN LETTER ALI GALI CA +1835 ; [.3435.0020.0002] # MONGOLIAN LETTER JA +1853 ; [.3436.0020.0002] # MONGOLIAN LETTER TODO JA +186A ; [.3437.0020.0002] # MONGOLIAN LETTER SIBE JA +1877 ; [.3438.0020.0002] # MONGOLIAN LETTER MANCHU ZHA +1836 ; [.3439.0020.0002] # MONGOLIAN LETTER YA +1855 ; [.343A.0020.0002] # MONGOLIAN LETTER TODO YA +1872 ; [.343B.0020.0002] # MONGOLIAN LETTER SIBE ZHA +1837 ; [.343C.0020.0002] # MONGOLIAN LETTER RA +1875 ; [.343D.0020.0002] # MONGOLIAN LETTER MANCHU RA +1838 ; [.343E.0020.0002] # MONGOLIAN LETTER WA +1856 ; [.343F.0020.0002] # MONGOLIAN LETTER TODO WA +1839 ; [.3440.0020.0002] # MONGOLIAN LETTER FA +186B ; [.3441.0020.0002] # MONGOLIAN LETTER SIBE FA +1876 ; [.3442.0020.0002] # MONGOLIAN LETTER MANCHU FA +183A ; [.3443.0020.0002] # MONGOLIAN LETTER KA +1857 ; [.3444.0020.0002] # MONGOLIAN LETTER TODO KA +1863 ; [.3445.0020.0002] # MONGOLIAN LETTER SIBE KA +1874 ; [.3446.0020.0002] # MONGOLIAN LETTER MANCHU KA +1889 ; [.3447.0020.0002] # MONGOLIAN LETTER ALI GALI KA +183B ; [.3448.0020.0002] # MONGOLIAN LETTER KHA +183C ; [.3449.0020.0002] # MONGOLIAN LETTER TSA +1854 ; [.344A.0020.0002] # MONGOLIAN LETTER TODO TSA +186E ; [.344B.0020.0002] # MONGOLIAN LETTER SIBE TSA +183D ; [.344C.0020.0002] # MONGOLIAN LETTER ZA +186F ; [.344D.0020.0002] # MONGOLIAN LETTER SIBE ZA +1858 ; [.344E.0020.0002] # MONGOLIAN LETTER TODO GAA +186C ; [.344F.0020.0002] # MONGOLIAN LETTER SIBE GAA +183E ; [.3450.0020.0002] # MONGOLIAN LETTER HAA +1859 ; [.3451.0020.0002] # MONGOLIAN LETTER TODO HAA +186D ; [.3452.0020.0002] # MONGOLIAN LETTER SIBE HAA +183F ; [.3453.0020.0002] # MONGOLIAN LETTER ZRA +1840 ; [.3454.0020.0002] # MONGOLIAN LETTER LHA +1841 ; [.3455.0020.0002] # MONGOLIAN LETTER ZHI +1842 ; [.3456.0020.0002] # MONGOLIAN LETTER CHI +185A ; [.3457.0020.0002] # MONGOLIAN LETTER TODO JIA +185B ; [.3458.0020.0002] # MONGOLIAN LETTER TODO NIA +1870 ; [.3459.0020.0002] # MONGOLIAN LETTER SIBE RAA +188C ; [.345A.0020.0002] # MONGOLIAN LETTER ALI GALI TTA +189E ; [.345B.0020.0002] # MONGOLIAN LETTER MANCHU ALI GALI TTA +188D ; [.345C.0020.0002] # MONGOLIAN LETTER ALI GALI TTHA +188E ; [.345D.0020.0002] # MONGOLIAN LETTER ALI GALI DDA +189F ; [.345E.0020.0002] # MONGOLIAN LETTER MANCHU ALI GALI DDHA +188F ; [.345F.0020.0002] # MONGOLIAN LETTER ALI GALI NNA +1890 ; [.3460.0020.0002] # MONGOLIAN LETTER ALI GALI TA +1898 ; [.3461.0020.0002] # MONGOLIAN LETTER TODO ALI GALI TA +18A0 ; [.3462.0020.0002] # MONGOLIAN LETTER MANCHU ALI GALI TA +1891 ; [.3463.0020.0002] # MONGOLIAN LETTER ALI GALI DA +18A1 ; [.3464.0020.0002] # MONGOLIAN LETTER MANCHU ALI GALI DHA +1892 ; [.3465.0020.0002] # MONGOLIAN LETTER ALI GALI PA +1893 ; [.3466.0020.0002] # MONGOLIAN LETTER ALI GALI PHA +18A8 ; [.3467.0020.0002] # MONGOLIAN LETTER MANCHU ALI GALI BHA +1894 ; [.3468.0020.0002] # MONGOLIAN LETTER ALI GALI SSA +18A3 ; [.3469.0020.0002] # MONGOLIAN LETTER MANCHU ALI GALI CYA +1895 ; [.346A.0020.0002] # MONGOLIAN LETTER ALI GALI ZHA +1899 ; [.346B.0020.0002] # MONGOLIAN LETTER TODO ALI GALI ZHA +1896 ; [.346C.0020.0002] # MONGOLIAN LETTER ALI GALI ZA +1897 ; [.346D.0020.0002] # MONGOLIAN LETTER ALI GALI AH +18A6 ; [.346E.0020.0002] # MONGOLIAN LETTER ALI GALI HALF U +18A7 ; [.346F.0020.0002] # MONGOLIAN LETTER ALI GALI HALF YA +18AA ; [.3470.0020.0002] # MONGOLIAN LETTER MANCHU ALI GALI LHA +18A9 ; [.3471.0020.0002] # MONGOLIAN LETTER ALI GALI DAGALGA +1C5A ; [.3472.0020.0002] # OL CHIKI LETTER LA +1C5B ; [.3473.0020.0002] # OL CHIKI LETTER AT +1C5C ; [.3474.0020.0002] # OL CHIKI LETTER AG +1C5D ; [.3475.0020.0002] # OL CHIKI LETTER ANG +1C5E ; [.3476.0020.0002] # OL CHIKI LETTER AL +1C5F ; [.3477.0020.0002] # OL CHIKI LETTER LAA +1C60 ; [.3478.0020.0002] # OL CHIKI LETTER AAK +1C61 ; [.3479.0020.0002] # OL CHIKI LETTER AAJ +1C62 ; [.347A.0020.0002] # OL CHIKI LETTER AAM +1C63 ; [.347B.0020.0002] # OL CHIKI LETTER AAW +1C64 ; [.347C.0020.0002] # OL CHIKI LETTER LI +1C65 ; [.347D.0020.0002] # OL CHIKI LETTER IS +1C66 ; [.347E.0020.0002] # OL CHIKI LETTER IH +1C67 ; [.347F.0020.0002] # OL CHIKI LETTER INY +1C68 ; [.3480.0020.0002] # OL CHIKI LETTER IR +1C69 ; [.3481.0020.0002] # OL CHIKI LETTER LU +1C6A ; [.3482.0020.0002] # OL CHIKI LETTER UC +1C6B ; [.3483.0020.0002] # OL CHIKI LETTER UD +1C6C ; [.3484.0020.0002] # OL CHIKI LETTER UNN +1C6D ; [.3485.0020.0002] # OL CHIKI LETTER UY +1C6E ; [.3486.0020.0002] # OL CHIKI LETTER LE +1C6F ; [.3487.0020.0002] # OL CHIKI LETTER EP +1C70 ; [.3488.0020.0002] # OL CHIKI LETTER EDD +1C71 ; [.3489.0020.0002] # OL CHIKI LETTER EN +1C72 ; [.348A.0020.0002] # OL CHIKI LETTER ERR +1C73 ; [.348B.0020.0002] # OL CHIKI LETTER LO +1C74 ; [.348C.0020.0002] # OL CHIKI LETTER OTT +1C75 ; [.348D.0020.0002] # OL CHIKI LETTER OB +1C76 ; [.348E.0020.0002] # OL CHIKI LETTER OV +1C77 ; [.348F.0020.0002] # OL CHIKI LETTER OH +1C78 ; [.3490.0020.0002] # OL CHIKI MU TTUDDAG +1C79 ; [.3491.0020.0002] # OL CHIKI GAAHLAA TTUDDAAG +1C7A ; [.3492.0020.0002] # OL CHIKI MU-GAAHLAA TTUDDAAG +1C7B ; [.3493.0020.0002] # OL CHIKI RELAA +1C7C ; [.3494.0020.0002] # OL CHIKI PHAARKAA +1C7D ; [.3495.0020.0002] # OL CHIKI AHAD +AB70 ; [.3496.0020.0002] # CHEROKEE SMALL LETTER A +13A0 ; [.3496.0020.0008] # CHEROKEE LETTER A +AB71 ; [.3497.0020.0002] # CHEROKEE SMALL LETTER E +13A1 ; [.3497.0020.0008] # CHEROKEE LETTER E +AB72 ; [.3498.0020.0002] # CHEROKEE SMALL LETTER I +13A2 ; [.3498.0020.0008] # CHEROKEE LETTER I +AB73 ; [.3499.0020.0002] # CHEROKEE SMALL LETTER O +13A3 ; [.3499.0020.0008] # CHEROKEE LETTER O +AB74 ; [.349A.0020.0002] # CHEROKEE SMALL LETTER U +13A4 ; [.349A.0020.0008] # CHEROKEE LETTER U +AB75 ; [.349B.0020.0002] # CHEROKEE SMALL LETTER V +13A5 ; [.349B.0020.0008] # CHEROKEE LETTER V +AB76 ; [.349C.0020.0002] # CHEROKEE SMALL LETTER GA +13A6 ; [.349C.0020.0008] # CHEROKEE LETTER GA +AB77 ; [.349D.0020.0002] # CHEROKEE SMALL LETTER KA +13A7 ; [.349D.0020.0008] # CHEROKEE LETTER KA +AB78 ; [.349E.0020.0002] # CHEROKEE SMALL LETTER GE +13A8 ; [.349E.0020.0008] # CHEROKEE LETTER GE +AB79 ; [.349F.0020.0002] # CHEROKEE SMALL LETTER GI +13A9 ; [.349F.0020.0008] # CHEROKEE LETTER GI +AB7A ; [.34A0.0020.0002] # CHEROKEE SMALL LETTER GO +13AA ; [.34A0.0020.0008] # CHEROKEE LETTER GO +AB7B ; [.34A1.0020.0002] # CHEROKEE SMALL LETTER GU +13AB ; [.34A1.0020.0008] # CHEROKEE LETTER GU +AB7C ; [.34A2.0020.0002] # CHEROKEE SMALL LETTER GV +13AC ; [.34A2.0020.0008] # CHEROKEE LETTER GV +AB7D ; [.34A3.0020.0002] # CHEROKEE SMALL LETTER HA +13AD ; [.34A3.0020.0008] # CHEROKEE LETTER HA +AB7E ; [.34A4.0020.0002] # CHEROKEE SMALL LETTER HE +13AE ; [.34A4.0020.0008] # CHEROKEE LETTER HE +AB7F ; [.34A5.0020.0002] # CHEROKEE SMALL LETTER HI +13AF ; [.34A5.0020.0008] # CHEROKEE LETTER HI +AB80 ; [.34A6.0020.0002] # CHEROKEE SMALL LETTER HO +13B0 ; [.34A6.0020.0008] # CHEROKEE LETTER HO +AB81 ; [.34A7.0020.0002] # CHEROKEE SMALL LETTER HU +13B1 ; [.34A7.0020.0008] # CHEROKEE LETTER HU +AB82 ; [.34A8.0020.0002] # CHEROKEE SMALL LETTER HV +13B2 ; [.34A8.0020.0008] # CHEROKEE LETTER HV +AB83 ; [.34A9.0020.0002] # CHEROKEE SMALL LETTER LA +13B3 ; [.34A9.0020.0008] # CHEROKEE LETTER LA +AB84 ; [.34AA.0020.0002] # CHEROKEE SMALL LETTER LE +13B4 ; [.34AA.0020.0008] # CHEROKEE LETTER LE +AB85 ; [.34AB.0020.0002] # CHEROKEE SMALL LETTER LI +13B5 ; [.34AB.0020.0008] # CHEROKEE LETTER LI +AB86 ; [.34AC.0020.0002] # CHEROKEE SMALL LETTER LO +13B6 ; [.34AC.0020.0008] # CHEROKEE LETTER LO +AB87 ; [.34AD.0020.0002] # CHEROKEE SMALL LETTER LU +13B7 ; [.34AD.0020.0008] # CHEROKEE LETTER LU +AB88 ; [.34AE.0020.0002] # CHEROKEE SMALL LETTER LV +13B8 ; [.34AE.0020.0008] # CHEROKEE LETTER LV +AB89 ; [.34AF.0020.0002] # CHEROKEE SMALL LETTER MA +13B9 ; [.34AF.0020.0008] # CHEROKEE LETTER MA +AB8A ; [.34B0.0020.0002] # CHEROKEE SMALL LETTER ME +13BA ; [.34B0.0020.0008] # CHEROKEE LETTER ME +AB8B ; [.34B1.0020.0002] # CHEROKEE SMALL LETTER MI +13BB ; [.34B1.0020.0008] # CHEROKEE LETTER MI +AB8C ; [.34B2.0020.0002] # CHEROKEE SMALL LETTER MO +13BC ; [.34B2.0020.0008] # CHEROKEE LETTER MO +AB8D ; [.34B3.0020.0002] # CHEROKEE SMALL LETTER MU +13BD ; [.34B3.0020.0008] # CHEROKEE LETTER MU +AB8E ; [.34B4.0020.0002] # CHEROKEE SMALL LETTER NA +13BE ; [.34B4.0020.0008] # CHEROKEE LETTER NA +AB8F ; [.34B5.0020.0002] # CHEROKEE SMALL LETTER HNA +13BF ; [.34B5.0020.0008] # CHEROKEE LETTER HNA +AB90 ; [.34B6.0020.0002] # CHEROKEE SMALL LETTER NAH +13C0 ; [.34B6.0020.0008] # CHEROKEE LETTER NAH +AB91 ; [.34B7.0020.0002] # CHEROKEE SMALL LETTER NE +13C1 ; [.34B7.0020.0008] # CHEROKEE LETTER NE +AB92 ; [.34B8.0020.0002] # CHEROKEE SMALL LETTER NI +13C2 ; [.34B8.0020.0008] # CHEROKEE LETTER NI +AB93 ; [.34B9.0020.0002] # CHEROKEE SMALL LETTER NO +13C3 ; [.34B9.0020.0008] # CHEROKEE LETTER NO +AB94 ; [.34BA.0020.0002] # CHEROKEE SMALL LETTER NU +13C4 ; [.34BA.0020.0008] # CHEROKEE LETTER NU +AB95 ; [.34BB.0020.0002] # CHEROKEE SMALL LETTER NV +13C5 ; [.34BB.0020.0008] # CHEROKEE LETTER NV +AB96 ; [.34BC.0020.0002] # CHEROKEE SMALL LETTER QUA +13C6 ; [.34BC.0020.0008] # CHEROKEE LETTER QUA +AB97 ; [.34BD.0020.0002] # CHEROKEE SMALL LETTER QUE +13C7 ; [.34BD.0020.0008] # CHEROKEE LETTER QUE +AB98 ; [.34BE.0020.0002] # CHEROKEE SMALL LETTER QUI +13C8 ; [.34BE.0020.0008] # CHEROKEE LETTER QUI +AB99 ; [.34BF.0020.0002] # CHEROKEE SMALL LETTER QUO +13C9 ; [.34BF.0020.0008] # CHEROKEE LETTER QUO +AB9A ; [.34C0.0020.0002] # CHEROKEE SMALL LETTER QUU +13CA ; [.34C0.0020.0008] # CHEROKEE LETTER QUU +AB9B ; [.34C1.0020.0002] # CHEROKEE SMALL LETTER QUV +13CB ; [.34C1.0020.0008] # CHEROKEE LETTER QUV +AB9C ; [.34C2.0020.0002] # CHEROKEE SMALL LETTER SA +13CC ; [.34C2.0020.0008] # CHEROKEE LETTER SA +AB9D ; [.34C3.0020.0002] # CHEROKEE SMALL LETTER S +13CD ; [.34C3.0020.0008] # CHEROKEE LETTER S +AB9E ; [.34C4.0020.0002] # CHEROKEE SMALL LETTER SE +13CE ; [.34C4.0020.0008] # CHEROKEE LETTER SE +AB9F ; [.34C5.0020.0002] # CHEROKEE SMALL LETTER SI +13CF ; [.34C5.0020.0008] # CHEROKEE LETTER SI +ABA0 ; [.34C6.0020.0002] # CHEROKEE SMALL LETTER SO +13D0 ; [.34C6.0020.0008] # CHEROKEE LETTER SO +ABA1 ; [.34C7.0020.0002] # CHEROKEE SMALL LETTER SU +13D1 ; [.34C7.0020.0008] # CHEROKEE LETTER SU +ABA2 ; [.34C8.0020.0002] # CHEROKEE SMALL LETTER SV +13D2 ; [.34C8.0020.0008] # CHEROKEE LETTER SV +ABA3 ; [.34C9.0020.0002] # CHEROKEE SMALL LETTER DA +13D3 ; [.34C9.0020.0008] # CHEROKEE LETTER DA +ABA4 ; [.34CA.0020.0002] # CHEROKEE SMALL LETTER TA +13D4 ; [.34CA.0020.0008] # CHEROKEE LETTER TA +ABA5 ; [.34CB.0020.0002] # CHEROKEE SMALL LETTER DE +13D5 ; [.34CB.0020.0008] # CHEROKEE LETTER DE +ABA6 ; [.34CC.0020.0002] # CHEROKEE SMALL LETTER TE +13D6 ; [.34CC.0020.0008] # CHEROKEE LETTER TE +ABA7 ; [.34CD.0020.0002] # CHEROKEE SMALL LETTER DI +13D7 ; [.34CD.0020.0008] # CHEROKEE LETTER DI +ABA8 ; [.34CE.0020.0002] # CHEROKEE SMALL LETTER TI +13D8 ; [.34CE.0020.0008] # CHEROKEE LETTER TI +ABA9 ; [.34CF.0020.0002] # CHEROKEE SMALL LETTER DO +13D9 ; [.34CF.0020.0008] # CHEROKEE LETTER DO +ABAA ; [.34D0.0020.0002] # CHEROKEE SMALL LETTER DU +13DA ; [.34D0.0020.0008] # CHEROKEE LETTER DU +ABAB ; [.34D1.0020.0002] # CHEROKEE SMALL LETTER DV +13DB ; [.34D1.0020.0008] # CHEROKEE LETTER DV +ABAC ; [.34D2.0020.0002] # CHEROKEE SMALL LETTER DLA +13DC ; [.34D2.0020.0008] # CHEROKEE LETTER DLA +ABAD ; [.34D3.0020.0002] # CHEROKEE SMALL LETTER TLA +13DD ; [.34D3.0020.0008] # CHEROKEE LETTER TLA +ABAE ; [.34D4.0020.0002] # CHEROKEE SMALL LETTER TLE +13DE ; [.34D4.0020.0008] # CHEROKEE LETTER TLE +ABAF ; [.34D5.0020.0002] # CHEROKEE SMALL LETTER TLI +13DF ; [.34D5.0020.0008] # CHEROKEE LETTER TLI +ABB0 ; [.34D6.0020.0002] # CHEROKEE SMALL LETTER TLO +13E0 ; [.34D6.0020.0008] # CHEROKEE LETTER TLO +ABB1 ; [.34D7.0020.0002] # CHEROKEE SMALL LETTER TLU +13E1 ; [.34D7.0020.0008] # CHEROKEE LETTER TLU +ABB2 ; [.34D8.0020.0002] # CHEROKEE SMALL LETTER TLV +13E2 ; [.34D8.0020.0008] # CHEROKEE LETTER TLV +ABB3 ; [.34D9.0020.0002] # CHEROKEE SMALL LETTER TSA +13E3 ; [.34D9.0020.0008] # CHEROKEE LETTER TSA +ABB4 ; [.34DA.0020.0002] # CHEROKEE SMALL LETTER TSE +13E4 ; [.34DA.0020.0008] # CHEROKEE LETTER TSE +ABB5 ; [.34DB.0020.0002] # CHEROKEE SMALL LETTER TSI +13E5 ; [.34DB.0020.0008] # CHEROKEE LETTER TSI +ABB6 ; [.34DC.0020.0002] # CHEROKEE SMALL LETTER TSO +13E6 ; [.34DC.0020.0008] # CHEROKEE LETTER TSO +ABB7 ; [.34DD.0020.0002] # CHEROKEE SMALL LETTER TSU +13E7 ; [.34DD.0020.0008] # CHEROKEE LETTER TSU +ABB8 ; [.34DE.0020.0002] # CHEROKEE SMALL LETTER TSV +13E8 ; [.34DE.0020.0008] # CHEROKEE LETTER TSV +ABB9 ; [.34DF.0020.0002] # CHEROKEE SMALL LETTER WA +13E9 ; [.34DF.0020.0008] # CHEROKEE LETTER WA +ABBA ; [.34E0.0020.0002] # CHEROKEE SMALL LETTER WE +13EA ; [.34E0.0020.0008] # CHEROKEE LETTER WE +ABBB ; [.34E1.0020.0002] # CHEROKEE SMALL LETTER WI +13EB ; [.34E1.0020.0008] # CHEROKEE LETTER WI +ABBC ; [.34E2.0020.0002] # CHEROKEE SMALL LETTER WO +13EC ; [.34E2.0020.0008] # CHEROKEE LETTER WO +ABBD ; [.34E3.0020.0002] # CHEROKEE SMALL LETTER WU +13ED ; [.34E3.0020.0008] # CHEROKEE LETTER WU +ABBE ; [.34E4.0020.0002] # CHEROKEE SMALL LETTER WV +13EE ; [.34E4.0020.0008] # CHEROKEE LETTER WV +ABBF ; [.34E5.0020.0002] # CHEROKEE SMALL LETTER YA +13EF ; [.34E5.0020.0008] # CHEROKEE LETTER YA +13F8 ; [.34E6.0020.0002] # CHEROKEE SMALL LETTER YE +13F0 ; [.34E6.0020.0008] # CHEROKEE LETTER YE +13F9 ; [.34E7.0020.0002] # CHEROKEE SMALL LETTER YI +13F1 ; [.34E7.0020.0008] # CHEROKEE LETTER YI +13FA ; [.34E8.0020.0002] # CHEROKEE SMALL LETTER YO +13F2 ; [.34E8.0020.0008] # CHEROKEE LETTER YO +13FB ; [.34E9.0020.0002] # CHEROKEE SMALL LETTER YU +13F3 ; [.34E9.0020.0008] # CHEROKEE LETTER YU +13FC ; [.34EA.0020.0002] # CHEROKEE SMALL LETTER YV +13F4 ; [.34EA.0020.0008] # CHEROKEE LETTER YV +13FD ; [.34EB.0020.0002] # CHEROKEE SMALL LETTER MV +13F5 ; [.34EB.0020.0008] # CHEROKEE LETTER MV +104D8 ; [.34EC.0020.0002] # OSAGE SMALL LETTER A +104B0 ; [.34EC.0020.0008] # OSAGE CAPITAL LETTER A +104D9 ; [.34ED.0020.0002] # OSAGE SMALL LETTER AI +104B1 ; [.34ED.0020.0008] # OSAGE CAPITAL LETTER AI +104DA ; [.34EE.0020.0002] # OSAGE SMALL LETTER AIN +104B2 ; [.34EE.0020.0008] # OSAGE CAPITAL LETTER AIN +104DB ; [.34EF.0020.0002] # OSAGE SMALL LETTER AH +104B3 ; [.34EF.0020.0008] # OSAGE CAPITAL LETTER AH +104DC ; [.34F0.0020.0002] # OSAGE SMALL LETTER BRA +104B4 ; [.34F0.0020.0008] # OSAGE CAPITAL LETTER BRA +104DD ; [.34F1.0020.0002] # OSAGE SMALL LETTER CHA +104B5 ; [.34F1.0020.0008] # OSAGE CAPITAL LETTER CHA +104DE ; [.34F2.0020.0002] # OSAGE SMALL LETTER EHCHA +104B6 ; [.34F2.0020.0008] # OSAGE CAPITAL LETTER EHCHA +104DF ; [.34F3.0020.0002] # OSAGE SMALL LETTER E +104B7 ; [.34F3.0020.0008] # OSAGE CAPITAL LETTER E +104E0 ; [.34F4.0020.0002] # OSAGE SMALL LETTER EIN +104B8 ; [.34F4.0020.0008] # OSAGE CAPITAL LETTER EIN +104E1 ; [.34F5.0020.0002] # OSAGE SMALL LETTER HA +104B9 ; [.34F5.0020.0008] # OSAGE CAPITAL LETTER HA +104E2 ; [.34F6.0020.0002] # OSAGE SMALL LETTER HYA +104BA ; [.34F6.0020.0008] # OSAGE CAPITAL LETTER HYA +104E3 ; [.34F7.0020.0002] # OSAGE SMALL LETTER I +104BB ; [.34F7.0020.0008] # OSAGE CAPITAL LETTER I +104E4 ; [.34F8.0020.0002] # OSAGE SMALL LETTER KA +104BC ; [.34F8.0020.0008] # OSAGE CAPITAL LETTER KA +104E5 ; [.34F9.0020.0002] # OSAGE SMALL LETTER EHKA +104BD ; [.34F9.0020.0008] # OSAGE CAPITAL LETTER EHKA +104E6 ; [.34FA.0020.0002] # OSAGE SMALL LETTER KYA +104BE ; [.34FA.0020.0008] # OSAGE CAPITAL LETTER KYA +104E7 ; [.34FB.0020.0002] # OSAGE SMALL LETTER LA +104BF ; [.34FB.0020.0008] # OSAGE CAPITAL LETTER LA +104E8 ; [.34FC.0020.0002] # OSAGE SMALL LETTER MA +104C0 ; [.34FC.0020.0008] # OSAGE CAPITAL LETTER MA +104E9 ; [.34FD.0020.0002] # OSAGE SMALL LETTER NA +104C1 ; [.34FD.0020.0008] # OSAGE CAPITAL LETTER NA +104EA ; [.34FE.0020.0002] # OSAGE SMALL LETTER O +104C2 ; [.34FE.0020.0008] # OSAGE CAPITAL LETTER O +104EB ; [.34FF.0020.0002] # OSAGE SMALL LETTER OIN +104C3 ; [.34FF.0020.0008] # OSAGE CAPITAL LETTER OIN +104EC ; [.3500.0020.0002] # OSAGE SMALL LETTER PA +104C4 ; [.3500.0020.0008] # OSAGE CAPITAL LETTER PA +104ED ; [.3501.0020.0002] # OSAGE SMALL LETTER EHPA +104C5 ; [.3501.0020.0008] # OSAGE CAPITAL LETTER EHPA +104EE ; [.3502.0020.0002] # OSAGE SMALL LETTER SA +104C6 ; [.3502.0020.0008] # OSAGE CAPITAL LETTER SA +104EF ; [.3503.0020.0002] # OSAGE SMALL LETTER SHA +104C7 ; [.3503.0020.0008] # OSAGE CAPITAL LETTER SHA +104F0 ; [.3504.0020.0002] # OSAGE SMALL LETTER TA +104C8 ; [.3504.0020.0008] # OSAGE CAPITAL LETTER TA +104F1 ; [.3505.0020.0002] # OSAGE SMALL LETTER EHTA +104C9 ; [.3505.0020.0008] # OSAGE CAPITAL LETTER EHTA +104F2 ; [.3506.0020.0002] # OSAGE SMALL LETTER TSA +104CA ; [.3506.0020.0008] # OSAGE CAPITAL LETTER TSA +104F3 ; [.3507.0020.0002] # OSAGE SMALL LETTER EHTSA +104CB ; [.3507.0020.0008] # OSAGE CAPITAL LETTER EHTSA +104F4 ; [.3508.0020.0002] # OSAGE SMALL LETTER TSHA +104CC ; [.3508.0020.0008] # OSAGE CAPITAL LETTER TSHA +104F5 ; [.3509.0020.0002] # OSAGE SMALL LETTER DHA +104CD ; [.3509.0020.0008] # OSAGE CAPITAL LETTER DHA +104F6 ; [.350A.0020.0002] # OSAGE SMALL LETTER U +104CE ; [.350A.0020.0008] # OSAGE CAPITAL LETTER U +104F7 ; [.350B.0020.0002] # OSAGE SMALL LETTER WA +104CF ; [.350B.0020.0008] # OSAGE CAPITAL LETTER WA +104F8 ; [.350C.0020.0002] # OSAGE SMALL LETTER KHA +104D0 ; [.350C.0020.0008] # OSAGE CAPITAL LETTER KHA +104F9 ; [.350D.0020.0002] # OSAGE SMALL LETTER GHA +104D1 ; [.350D.0020.0008] # OSAGE CAPITAL LETTER GHA +104FA ; [.350E.0020.0002] # OSAGE SMALL LETTER ZA +104D2 ; [.350E.0020.0008] # OSAGE CAPITAL LETTER ZA +104FB ; [.350F.0020.0002] # OSAGE SMALL LETTER ZHA +104D3 ; [.350F.0020.0008] # OSAGE CAPITAL LETTER ZHA +1401 ; [.3510.0020.0002] # CANADIAN SYLLABICS E +1402 ; [.3511.0020.0002] # CANADIAN SYLLABICS AAI +1403 ; [.3512.0020.0002] # CANADIAN SYLLABICS I +1404 ; [.3513.0020.0002] # CANADIAN SYLLABICS II +1405 ; [.3514.0020.0002] # CANADIAN SYLLABICS O +1406 ; [.3515.0020.0002] # CANADIAN SYLLABICS OO +1407 ; [.3516.0020.0002] # CANADIAN SYLLABICS Y-CREE OO +1408 ; [.3517.0020.0002] # CANADIAN SYLLABICS CARRIER EE +1409 ; [.3518.0020.0002] # CANADIAN SYLLABICS CARRIER I +140A ; [.3519.0020.0002] # CANADIAN SYLLABICS A +140B ; [.351A.0020.0002] # CANADIAN SYLLABICS AA +140C ; [.351B.0020.0002] # CANADIAN SYLLABICS WE +140D ; [.351C.0020.0002] # CANADIAN SYLLABICS WEST-CREE WE +140E ; [.351D.0020.0002] # CANADIAN SYLLABICS WI +140F ; [.351E.0020.0002] # CANADIAN SYLLABICS WEST-CREE WI +1410 ; [.351F.0020.0002] # CANADIAN SYLLABICS WII +1411 ; [.3520.0020.0002] # CANADIAN SYLLABICS WEST-CREE WII +1412 ; [.3521.0020.0002] # CANADIAN SYLLABICS WO +1413 ; [.3522.0020.0002] # CANADIAN SYLLABICS WEST-CREE WO +1414 ; [.3523.0020.0002] # CANADIAN SYLLABICS WOO +1415 ; [.3524.0020.0002] # CANADIAN SYLLABICS WEST-CREE WOO +1416 ; [.3525.0020.0002] # CANADIAN SYLLABICS NASKAPI WOO +1417 ; [.3526.0020.0002] # CANADIAN SYLLABICS WA +1418 ; [.3527.0020.0002] # CANADIAN SYLLABICS WEST-CREE WA +1419 ; [.3528.0020.0002] # CANADIAN SYLLABICS WAA +141A ; [.3529.0020.0002] # CANADIAN SYLLABICS WEST-CREE WAA +141B ; [.352A.0020.0002] # CANADIAN SYLLABICS NASKAPI WAA +141C ; [.352B.0020.0002] # CANADIAN SYLLABICS AI +141D ; [.352C.0020.0002] # CANADIAN SYLLABICS Y-CREE W +141E ; [.352D.0020.0002] # CANADIAN SYLLABICS GLOTTAL STOP +141F ; [.352E.0020.0002] # CANADIAN SYLLABICS FINAL ACUTE +1420 ; [.352F.0020.0002] # CANADIAN SYLLABICS FINAL GRAVE +1421 ; [.3530.0020.0002] # CANADIAN SYLLABICS FINAL BOTTOM HALF RING +1422 ; [.3531.0020.0002] # CANADIAN SYLLABICS FINAL TOP HALF RING +1423 ; [.3532.0020.0002] # CANADIAN SYLLABICS FINAL RIGHT HALF RING +1424 ; [.3533.0020.0002] # CANADIAN SYLLABICS FINAL RING +1425 ; [.3534.0020.0002] # CANADIAN SYLLABICS FINAL DOUBLE ACUTE +1426 ; [.3535.0020.0002] # CANADIAN SYLLABICS FINAL DOUBLE SHORT VERTICAL STROKES +1427 ; [.3536.0020.0002] # CANADIAN SYLLABICS FINAL MIDDLE DOT +1428 ; [.3537.0020.0002] # CANADIAN SYLLABICS FINAL SHORT HORIZONTAL STROKE +1429 ; [.3538.0020.0002] # CANADIAN SYLLABICS FINAL PLUS +142A ; [.3539.0020.0002] # CANADIAN SYLLABICS FINAL DOWN TACK +142B ; [.353A.0020.0002] # CANADIAN SYLLABICS EN +142C ; [.353B.0020.0002] # CANADIAN SYLLABICS IN +142D ; [.353C.0020.0002] # CANADIAN SYLLABICS ON +142E ; [.353D.0020.0002] # CANADIAN SYLLABICS AN +142F ; [.353E.0020.0002] # CANADIAN SYLLABICS PE +1430 ; [.353F.0020.0002] # CANADIAN SYLLABICS PAAI +1431 ; [.3540.0020.0002] # CANADIAN SYLLABICS PI +1432 ; [.3541.0020.0002] # CANADIAN SYLLABICS PII +1433 ; [.3542.0020.0002] # CANADIAN SYLLABICS PO +1434 ; [.3543.0020.0002] # CANADIAN SYLLABICS POO +1435 ; [.3544.0020.0002] # CANADIAN SYLLABICS Y-CREE POO +1436 ; [.3545.0020.0002] # CANADIAN SYLLABICS CARRIER HEE +1437 ; [.3546.0020.0002] # CANADIAN SYLLABICS CARRIER HI +1438 ; [.3547.0020.0002] # CANADIAN SYLLABICS PA +1439 ; [.3548.0020.0002] # CANADIAN SYLLABICS PAA +143A ; [.3549.0020.0002] # CANADIAN SYLLABICS PWE +143B ; [.354A.0020.0002] # CANADIAN SYLLABICS WEST-CREE PWE +143C ; [.354B.0020.0002] # CANADIAN SYLLABICS PWI +143D ; [.354C.0020.0002] # CANADIAN SYLLABICS WEST-CREE PWI +143E ; [.354D.0020.0002] # CANADIAN SYLLABICS PWII +143F ; [.354E.0020.0002] # CANADIAN SYLLABICS WEST-CREE PWII +1440 ; [.354F.0020.0002] # CANADIAN SYLLABICS PWO +1441 ; [.3550.0020.0002] # CANADIAN SYLLABICS WEST-CREE PWO +1442 ; [.3551.0020.0002] # CANADIAN SYLLABICS PWOO +1443 ; [.3552.0020.0002] # CANADIAN SYLLABICS WEST-CREE PWOO +1444 ; [.3553.0020.0002] # CANADIAN SYLLABICS PWA +1445 ; [.3554.0020.0002] # CANADIAN SYLLABICS WEST-CREE PWA +1446 ; [.3555.0020.0002] # CANADIAN SYLLABICS PWAA +1447 ; [.3556.0020.0002] # CANADIAN SYLLABICS WEST-CREE PWAA +1448 ; [.3557.0020.0002] # CANADIAN SYLLABICS Y-CREE PWAA +1449 ; [.3558.0020.0002] # CANADIAN SYLLABICS P +144A ; [.3559.0020.0002] # CANADIAN SYLLABICS WEST-CREE P +144B ; [.355A.0020.0002] # CANADIAN SYLLABICS CARRIER H +144C ; [.355B.0020.0002] # CANADIAN SYLLABICS TE +144D ; [.355C.0020.0002] # CANADIAN SYLLABICS TAAI +144E ; [.355D.0020.0002] # CANADIAN SYLLABICS TI +144F ; [.355E.0020.0002] # CANADIAN SYLLABICS TII +1450 ; [.355F.0020.0002] # CANADIAN SYLLABICS TO +1451 ; [.3560.0020.0002] # CANADIAN SYLLABICS TOO +1452 ; [.3561.0020.0002] # CANADIAN SYLLABICS Y-CREE TOO +1453 ; [.3562.0020.0002] # CANADIAN SYLLABICS CARRIER DEE +1454 ; [.3563.0020.0002] # CANADIAN SYLLABICS CARRIER DI +1455 ; [.3564.0020.0002] # CANADIAN SYLLABICS TA +1456 ; [.3565.0020.0002] # CANADIAN SYLLABICS TAA +1457 ; [.3566.0020.0002] # CANADIAN SYLLABICS TWE +1458 ; [.3567.0020.0002] # CANADIAN SYLLABICS WEST-CREE TWE +1459 ; [.3568.0020.0002] # CANADIAN SYLLABICS TWI +145A ; [.3569.0020.0002] # CANADIAN SYLLABICS WEST-CREE TWI +145B ; [.356A.0020.0002] # CANADIAN SYLLABICS TWII +145C ; [.356B.0020.0002] # CANADIAN SYLLABICS WEST-CREE TWII +145D ; [.356C.0020.0002] # CANADIAN SYLLABICS TWO +145E ; [.356D.0020.0002] # CANADIAN SYLLABICS WEST-CREE TWO +145F ; [.356E.0020.0002] # CANADIAN SYLLABICS TWOO +1460 ; [.356F.0020.0002] # CANADIAN SYLLABICS WEST-CREE TWOO +1461 ; [.3570.0020.0002] # CANADIAN SYLLABICS TWA +1462 ; [.3571.0020.0002] # CANADIAN SYLLABICS WEST-CREE TWA +1463 ; [.3572.0020.0002] # CANADIAN SYLLABICS TWAA +1464 ; [.3573.0020.0002] # CANADIAN SYLLABICS WEST-CREE TWAA +1465 ; [.3574.0020.0002] # CANADIAN SYLLABICS NASKAPI TWAA +1466 ; [.3575.0020.0002] # CANADIAN SYLLABICS T +1467 ; [.3576.0020.0002] # CANADIAN SYLLABICS TTE +1468 ; [.3577.0020.0002] # CANADIAN SYLLABICS TTI +1469 ; [.3578.0020.0002] # CANADIAN SYLLABICS TTO +146A ; [.3579.0020.0002] # CANADIAN SYLLABICS TTA +146B ; [.357A.0020.0002] # CANADIAN SYLLABICS KE +146C ; [.357B.0020.0002] # CANADIAN SYLLABICS KAAI +146D ; [.357C.0020.0002] # CANADIAN SYLLABICS KI +146E ; [.357D.0020.0002] # CANADIAN SYLLABICS KII +146F ; [.357E.0020.0002] # CANADIAN SYLLABICS KO +1470 ; [.357F.0020.0002] # CANADIAN SYLLABICS KOO +1471 ; [.3580.0020.0002] # CANADIAN SYLLABICS Y-CREE KOO +1472 ; [.3581.0020.0002] # CANADIAN SYLLABICS KA +1473 ; [.3582.0020.0002] # CANADIAN SYLLABICS KAA +1474 ; [.3583.0020.0002] # CANADIAN SYLLABICS KWE +1475 ; [.3584.0020.0002] # CANADIAN SYLLABICS WEST-CREE KWE +1476 ; [.3585.0020.0002] # CANADIAN SYLLABICS KWI +1477 ; [.3586.0020.0002] # CANADIAN SYLLABICS WEST-CREE KWI +1478 ; [.3587.0020.0002] # CANADIAN SYLLABICS KWII +1479 ; [.3588.0020.0002] # CANADIAN SYLLABICS WEST-CREE KWII +147A ; [.3589.0020.0002] # CANADIAN SYLLABICS KWO +147B ; [.358A.0020.0002] # CANADIAN SYLLABICS WEST-CREE KWO +147C ; [.358B.0020.0002] # CANADIAN SYLLABICS KWOO +147D ; [.358C.0020.0002] # CANADIAN SYLLABICS WEST-CREE KWOO +147E ; [.358D.0020.0002] # CANADIAN SYLLABICS KWA +147F ; [.358E.0020.0002] # CANADIAN SYLLABICS WEST-CREE KWA +1480 ; [.358F.0020.0002] # CANADIAN SYLLABICS KWAA +1481 ; [.3590.0020.0002] # CANADIAN SYLLABICS WEST-CREE KWAA +1482 ; [.3591.0020.0002] # CANADIAN SYLLABICS NASKAPI KWAA +1483 ; [.3592.0020.0002] # CANADIAN SYLLABICS K +1484 ; [.3593.0020.0002] # CANADIAN SYLLABICS KW +1485 ; [.3594.0020.0002] # CANADIAN SYLLABICS SOUTH-SLAVEY KEH +1486 ; [.3595.0020.0002] # CANADIAN SYLLABICS SOUTH-SLAVEY KIH +1487 ; [.3596.0020.0002] # CANADIAN SYLLABICS SOUTH-SLAVEY KOH +1488 ; [.3597.0020.0002] # CANADIAN SYLLABICS SOUTH-SLAVEY KAH +1489 ; [.3598.0020.0002] # CANADIAN SYLLABICS CE +148A ; [.3599.0020.0002] # CANADIAN SYLLABICS CAAI +148B ; [.359A.0020.0002] # CANADIAN SYLLABICS CI +148C ; [.359B.0020.0002] # CANADIAN SYLLABICS CII +148D ; [.359C.0020.0002] # CANADIAN SYLLABICS CO +148E ; [.359D.0020.0002] # CANADIAN SYLLABICS COO +148F ; [.359E.0020.0002] # CANADIAN SYLLABICS Y-CREE COO +1490 ; [.359F.0020.0002] # CANADIAN SYLLABICS CA +1491 ; [.35A0.0020.0002] # CANADIAN SYLLABICS CAA +1492 ; [.35A1.0020.0002] # CANADIAN SYLLABICS CWE +1493 ; [.35A2.0020.0002] # CANADIAN SYLLABICS WEST-CREE CWE +1494 ; [.35A3.0020.0002] # CANADIAN SYLLABICS CWI +1495 ; [.35A4.0020.0002] # CANADIAN SYLLABICS WEST-CREE CWI +1496 ; [.35A5.0020.0002] # CANADIAN SYLLABICS CWII +1497 ; [.35A6.0020.0002] # CANADIAN SYLLABICS WEST-CREE CWII +1498 ; [.35A7.0020.0002] # CANADIAN SYLLABICS CWO +1499 ; [.35A8.0020.0002] # CANADIAN SYLLABICS WEST-CREE CWO +149A ; [.35A9.0020.0002] # CANADIAN SYLLABICS CWOO +149B ; [.35AA.0020.0002] # CANADIAN SYLLABICS WEST-CREE CWOO +149C ; [.35AB.0020.0002] # CANADIAN SYLLABICS CWA +149D ; [.35AC.0020.0002] # CANADIAN SYLLABICS WEST-CREE CWA +149E ; [.35AD.0020.0002] # CANADIAN SYLLABICS CWAA +149F ; [.35AE.0020.0002] # CANADIAN SYLLABICS WEST-CREE CWAA +14A0 ; [.35AF.0020.0002] # CANADIAN SYLLABICS NASKAPI CWAA +14A1 ; [.35B0.0020.0002] # CANADIAN SYLLABICS C +14A2 ; [.35B1.0020.0002] # CANADIAN SYLLABICS SAYISI TH +14A3 ; [.35B2.0020.0002] # CANADIAN SYLLABICS ME +14A4 ; [.35B3.0020.0002] # CANADIAN SYLLABICS MAAI +14A5 ; [.35B4.0020.0002] # CANADIAN SYLLABICS MI +14A6 ; [.35B5.0020.0002] # CANADIAN SYLLABICS MII +14A7 ; [.35B6.0020.0002] # CANADIAN SYLLABICS MO +14A8 ; [.35B7.0020.0002] # CANADIAN SYLLABICS MOO +14A9 ; [.35B8.0020.0002] # CANADIAN SYLLABICS Y-CREE MOO +14AA ; [.35B9.0020.0002] # CANADIAN SYLLABICS MA +14AB ; [.35BA.0020.0002] # CANADIAN SYLLABICS MAA +14AC ; [.35BB.0020.0002] # CANADIAN SYLLABICS MWE +14AD ; [.35BC.0020.0002] # CANADIAN SYLLABICS WEST-CREE MWE +14AE ; [.35BD.0020.0002] # CANADIAN SYLLABICS MWI +14AF ; [.35BE.0020.0002] # CANADIAN SYLLABICS WEST-CREE MWI +14B0 ; [.35BF.0020.0002] # CANADIAN SYLLABICS MWII +14B1 ; [.35C0.0020.0002] # CANADIAN SYLLABICS WEST-CREE MWII +14B2 ; [.35C1.0020.0002] # CANADIAN SYLLABICS MWO +14B3 ; [.35C2.0020.0002] # CANADIAN SYLLABICS WEST-CREE MWO +14B4 ; [.35C3.0020.0002] # CANADIAN SYLLABICS MWOO +14B5 ; [.35C4.0020.0002] # CANADIAN SYLLABICS WEST-CREE MWOO +14B6 ; [.35C5.0020.0002] # CANADIAN SYLLABICS MWA +14B7 ; [.35C6.0020.0002] # CANADIAN SYLLABICS WEST-CREE MWA +14B8 ; [.35C7.0020.0002] # CANADIAN SYLLABICS MWAA +14B9 ; [.35C8.0020.0002] # CANADIAN SYLLABICS WEST-CREE MWAA +14BA ; [.35C9.0020.0002] # CANADIAN SYLLABICS NASKAPI MWAA +14BB ; [.35CA.0020.0002] # CANADIAN SYLLABICS M +14BC ; [.35CB.0020.0002] # CANADIAN SYLLABICS WEST-CREE M +14BD ; [.35CC.0020.0002] # CANADIAN SYLLABICS MH +14BE ; [.35CD.0020.0002] # CANADIAN SYLLABICS ATHAPASCAN M +14BF ; [.35CE.0020.0002] # CANADIAN SYLLABICS SAYISI M +14C0 ; [.35CF.0020.0002] # CANADIAN SYLLABICS NE +14C1 ; [.35D0.0020.0002] # CANADIAN SYLLABICS NAAI +14C2 ; [.35D1.0020.0002] # CANADIAN SYLLABICS NI +14C3 ; [.35D2.0020.0002] # CANADIAN SYLLABICS NII +14C4 ; [.35D3.0020.0002] # CANADIAN SYLLABICS NO +14C5 ; [.35D4.0020.0002] # CANADIAN SYLLABICS NOO +14C6 ; [.35D5.0020.0002] # CANADIAN SYLLABICS Y-CREE NOO +14C7 ; [.35D6.0020.0002] # CANADIAN SYLLABICS NA +14C8 ; [.35D7.0020.0002] # CANADIAN SYLLABICS NAA +14C9 ; [.35D8.0020.0002] # CANADIAN SYLLABICS NWE +14CA ; [.35D9.0020.0002] # CANADIAN SYLLABICS WEST-CREE NWE +14CB ; [.35DA.0020.0002] # CANADIAN SYLLABICS NWA +14CC ; [.35DB.0020.0002] # CANADIAN SYLLABICS WEST-CREE NWA +14CD ; [.35DC.0020.0002] # CANADIAN SYLLABICS NWAA +14CE ; [.35DD.0020.0002] # CANADIAN SYLLABICS WEST-CREE NWAA +14CF ; [.35DE.0020.0002] # CANADIAN SYLLABICS NASKAPI NWAA +14D0 ; [.35DF.0020.0002] # CANADIAN SYLLABICS N +14D1 ; [.35E0.0020.0002] # CANADIAN SYLLABICS CARRIER NG +14D2 ; [.35E1.0020.0002] # CANADIAN SYLLABICS NH +14D3 ; [.35E2.0020.0002] # CANADIAN SYLLABICS LE +14D4 ; [.35E3.0020.0002] # CANADIAN SYLLABICS LAAI +14D5 ; [.35E4.0020.0002] # CANADIAN SYLLABICS LI +14D6 ; [.35E5.0020.0002] # CANADIAN SYLLABICS LII +14D7 ; [.35E6.0020.0002] # CANADIAN SYLLABICS LO +14D8 ; [.35E7.0020.0002] # CANADIAN SYLLABICS LOO +14D9 ; [.35E8.0020.0002] # CANADIAN SYLLABICS Y-CREE LOO +14DA ; [.35E9.0020.0002] # CANADIAN SYLLABICS LA +14DB ; [.35EA.0020.0002] # CANADIAN SYLLABICS LAA +14DC ; [.35EB.0020.0002] # CANADIAN SYLLABICS LWE +14DD ; [.35EC.0020.0002] # CANADIAN SYLLABICS WEST-CREE LWE +14DE ; [.35ED.0020.0002] # CANADIAN SYLLABICS LWI +14DF ; [.35EE.0020.0002] # CANADIAN SYLLABICS WEST-CREE LWI +14E0 ; [.35EF.0020.0002] # CANADIAN SYLLABICS LWII +14E1 ; [.35F0.0020.0002] # CANADIAN SYLLABICS WEST-CREE LWII +14E2 ; [.35F1.0020.0002] # CANADIAN SYLLABICS LWO +14E3 ; [.35F2.0020.0002] # CANADIAN SYLLABICS WEST-CREE LWO +14E4 ; [.35F3.0020.0002] # CANADIAN SYLLABICS LWOO +14E5 ; [.35F4.0020.0002] # CANADIAN SYLLABICS WEST-CREE LWOO +14E6 ; [.35F5.0020.0002] # CANADIAN SYLLABICS LWA +14E7 ; [.35F6.0020.0002] # CANADIAN SYLLABICS WEST-CREE LWA +14E8 ; [.35F7.0020.0002] # CANADIAN SYLLABICS LWAA +14E9 ; [.35F8.0020.0002] # CANADIAN SYLLABICS WEST-CREE LWAA +14EA ; [.35F9.0020.0002] # CANADIAN SYLLABICS L +14EB ; [.35FA.0020.0002] # CANADIAN SYLLABICS WEST-CREE L +14EC ; [.35FB.0020.0002] # CANADIAN SYLLABICS MEDIAL L +14ED ; [.35FC.0020.0002] # CANADIAN SYLLABICS SE +14EE ; [.35FD.0020.0002] # CANADIAN SYLLABICS SAAI +14EF ; [.35FE.0020.0002] # CANADIAN SYLLABICS SI +14F0 ; [.35FF.0020.0002] # CANADIAN SYLLABICS SII +14F1 ; [.3600.0020.0002] # CANADIAN SYLLABICS SO +14F2 ; [.3601.0020.0002] # CANADIAN SYLLABICS SOO +14F3 ; [.3602.0020.0002] # CANADIAN SYLLABICS Y-CREE SOO +14F4 ; [.3603.0020.0002] # CANADIAN SYLLABICS SA +14F5 ; [.3604.0020.0002] # CANADIAN SYLLABICS SAA +14F6 ; [.3605.0020.0002] # CANADIAN SYLLABICS SWE +14F7 ; [.3606.0020.0002] # CANADIAN SYLLABICS WEST-CREE SWE +14F8 ; [.3607.0020.0002] # CANADIAN SYLLABICS SWI +14F9 ; [.3608.0020.0002] # CANADIAN SYLLABICS WEST-CREE SWI +14FA ; [.3609.0020.0002] # CANADIAN SYLLABICS SWII +14FB ; [.360A.0020.0002] # CANADIAN SYLLABICS WEST-CREE SWII +14FC ; [.360B.0020.0002] # CANADIAN SYLLABICS SWO +14FD ; [.360C.0020.0002] # CANADIAN SYLLABICS WEST-CREE SWO +14FE ; [.360D.0020.0002] # CANADIAN SYLLABICS SWOO +14FF ; [.360E.0020.0002] # CANADIAN SYLLABICS WEST-CREE SWOO +1500 ; [.360F.0020.0002] # CANADIAN SYLLABICS SWA +1501 ; [.3610.0020.0002] # CANADIAN SYLLABICS WEST-CREE SWA +1502 ; [.3611.0020.0002] # CANADIAN SYLLABICS SWAA +1503 ; [.3612.0020.0002] # CANADIAN SYLLABICS WEST-CREE SWAA +1504 ; [.3613.0020.0002] # CANADIAN SYLLABICS NASKAPI SWAA +1505 ; [.3614.0020.0002] # CANADIAN SYLLABICS S +1506 ; [.3615.0020.0002] # CANADIAN SYLLABICS ATHAPASCAN S +1507 ; [.3616.0020.0002] # CANADIAN SYLLABICS SW +1508 ; [.3617.0020.0002] # CANADIAN SYLLABICS BLACKFOOT S +1509 ; [.3618.0020.0002] # CANADIAN SYLLABICS MOOSE-CREE SK +150A ; [.3619.0020.0002] # CANADIAN SYLLABICS NASKAPI SKW +150B ; [.361A.0020.0002] # CANADIAN SYLLABICS NASKAPI S-W +150C ; [.361B.0020.0002] # CANADIAN SYLLABICS NASKAPI SPWA +150D ; [.361C.0020.0002] # CANADIAN SYLLABICS NASKAPI STWA +150E ; [.361D.0020.0002] # CANADIAN SYLLABICS NASKAPI SKWA +150F ; [.361E.0020.0002] # CANADIAN SYLLABICS NASKAPI SCWA +1510 ; [.361F.0020.0002] # CANADIAN SYLLABICS SHE +1511 ; [.3620.0020.0002] # CANADIAN SYLLABICS SHI +1512 ; [.3621.0020.0002] # CANADIAN SYLLABICS SHII +1513 ; [.3622.0020.0002] # CANADIAN SYLLABICS SHO +1514 ; [.3623.0020.0002] # CANADIAN SYLLABICS SHOO +1515 ; [.3624.0020.0002] # CANADIAN SYLLABICS SHA +1516 ; [.3625.0020.0002] # CANADIAN SYLLABICS SHAA +1517 ; [.3626.0020.0002] # CANADIAN SYLLABICS SHWE +1518 ; [.3627.0020.0002] # CANADIAN SYLLABICS WEST-CREE SHWE +1519 ; [.3628.0020.0002] # CANADIAN SYLLABICS SHWI +151A ; [.3629.0020.0002] # CANADIAN SYLLABICS WEST-CREE SHWI +151B ; [.362A.0020.0002] # CANADIAN SYLLABICS SHWII +151C ; [.362B.0020.0002] # CANADIAN SYLLABICS WEST-CREE SHWII +151D ; [.362C.0020.0002] # CANADIAN SYLLABICS SHWO +151E ; [.362D.0020.0002] # CANADIAN SYLLABICS WEST-CREE SHWO +151F ; [.362E.0020.0002] # CANADIAN SYLLABICS SHWOO +1520 ; [.362F.0020.0002] # CANADIAN SYLLABICS WEST-CREE SHWOO +1521 ; [.3630.0020.0002] # CANADIAN SYLLABICS SHWA +1522 ; [.3631.0020.0002] # CANADIAN SYLLABICS WEST-CREE SHWA +1523 ; [.3632.0020.0002] # CANADIAN SYLLABICS SHWAA +1524 ; [.3633.0020.0002] # CANADIAN SYLLABICS WEST-CREE SHWAA +1525 ; [.3634.0020.0002] # CANADIAN SYLLABICS SH +1526 ; [.3635.0020.0002] # CANADIAN SYLLABICS YE +1527 ; [.3636.0020.0002] # CANADIAN SYLLABICS YAAI +1528 ; [.3637.0020.0002] # CANADIAN SYLLABICS YI +1529 ; [.3638.0020.0002] # CANADIAN SYLLABICS YII +152A ; [.3639.0020.0002] # CANADIAN SYLLABICS YO +152B ; [.363A.0020.0002] # CANADIAN SYLLABICS YOO +152C ; [.363B.0020.0002] # CANADIAN SYLLABICS Y-CREE YOO +152D ; [.363C.0020.0002] # CANADIAN SYLLABICS YA +152E ; [.363D.0020.0002] # CANADIAN SYLLABICS YAA +152F ; [.363E.0020.0002] # CANADIAN SYLLABICS YWE +1530 ; [.363F.0020.0002] # CANADIAN SYLLABICS WEST-CREE YWE +1531 ; [.3640.0020.0002] # CANADIAN SYLLABICS YWI +1532 ; [.3641.0020.0002] # CANADIAN SYLLABICS WEST-CREE YWI +1533 ; [.3642.0020.0002] # CANADIAN SYLLABICS YWII +1534 ; [.3643.0020.0002] # CANADIAN SYLLABICS WEST-CREE YWII +1535 ; [.3644.0020.0002] # CANADIAN SYLLABICS YWO +1536 ; [.3645.0020.0002] # CANADIAN SYLLABICS WEST-CREE YWO +1537 ; [.3646.0020.0002] # CANADIAN SYLLABICS YWOO +1538 ; [.3647.0020.0002] # CANADIAN SYLLABICS WEST-CREE YWOO +1539 ; [.3648.0020.0002] # CANADIAN SYLLABICS YWA +153A ; [.3649.0020.0002] # CANADIAN SYLLABICS WEST-CREE YWA +153B ; [.364A.0020.0002] # CANADIAN SYLLABICS YWAA +153C ; [.364B.0020.0002] # CANADIAN SYLLABICS WEST-CREE YWAA +153D ; [.364C.0020.0002] # CANADIAN SYLLABICS NASKAPI YWAA +153E ; [.364D.0020.0002] # CANADIAN SYLLABICS Y +153F ; [.364E.0020.0002] # CANADIAN SYLLABICS BIBLE-CREE Y +1540 ; [.364F.0020.0002] # CANADIAN SYLLABICS WEST-CREE Y +1541 ; [.3650.0020.0002] # CANADIAN SYLLABICS SAYISI YI +1542 ; [.3651.0020.0002] # CANADIAN SYLLABICS RE +1543 ; [.3652.0020.0002] # CANADIAN SYLLABICS R-CREE RE +1544 ; [.3653.0020.0002] # CANADIAN SYLLABICS WEST-CREE LE +1545 ; [.3654.0020.0002] # CANADIAN SYLLABICS RAAI +1546 ; [.3655.0020.0002] # CANADIAN SYLLABICS RI +1547 ; [.3656.0020.0002] # CANADIAN SYLLABICS RII +1548 ; [.3657.0020.0002] # CANADIAN SYLLABICS RO +1549 ; [.3658.0020.0002] # CANADIAN SYLLABICS ROO +154A ; [.3659.0020.0002] # CANADIAN SYLLABICS WEST-CREE LO +154B ; [.365A.0020.0002] # CANADIAN SYLLABICS RA +154C ; [.365B.0020.0002] # CANADIAN SYLLABICS RAA +154D ; [.365C.0020.0002] # CANADIAN SYLLABICS WEST-CREE LA +154E ; [.365D.0020.0002] # CANADIAN SYLLABICS RWAA +154F ; [.365E.0020.0002] # CANADIAN SYLLABICS WEST-CREE RWAA +1550 ; [.365F.0020.0002] # CANADIAN SYLLABICS R +1551 ; [.3660.0020.0002] # CANADIAN SYLLABICS WEST-CREE R +1552 ; [.3661.0020.0002] # CANADIAN SYLLABICS MEDIAL R +1553 ; [.3662.0020.0002] # CANADIAN SYLLABICS FE +1554 ; [.3663.0020.0002] # CANADIAN SYLLABICS FAAI +1555 ; [.3664.0020.0002] # CANADIAN SYLLABICS FI +1556 ; [.3665.0020.0002] # CANADIAN SYLLABICS FII +1557 ; [.3666.0020.0002] # CANADIAN SYLLABICS FO +1558 ; [.3667.0020.0002] # CANADIAN SYLLABICS FOO +1559 ; [.3668.0020.0002] # CANADIAN SYLLABICS FA +155A ; [.3669.0020.0002] # CANADIAN SYLLABICS FAA +155B ; [.366A.0020.0002] # CANADIAN SYLLABICS FWAA +155C ; [.366B.0020.0002] # CANADIAN SYLLABICS WEST-CREE FWAA +155D ; [.366C.0020.0002] # CANADIAN SYLLABICS F +155E ; [.366D.0020.0002] # CANADIAN SYLLABICS THE +155F ; [.366E.0020.0002] # CANADIAN SYLLABICS N-CREE THE +1560 ; [.366F.0020.0002] # CANADIAN SYLLABICS THI +1561 ; [.3670.0020.0002] # CANADIAN SYLLABICS N-CREE THI +1562 ; [.3671.0020.0002] # CANADIAN SYLLABICS THII +1563 ; [.3672.0020.0002] # CANADIAN SYLLABICS N-CREE THII +1564 ; [.3673.0020.0002] # CANADIAN SYLLABICS THO +1565 ; [.3674.0020.0002] # CANADIAN SYLLABICS THOO +1566 ; [.3675.0020.0002] # CANADIAN SYLLABICS THA +1567 ; [.3676.0020.0002] # CANADIAN SYLLABICS THAA +1568 ; [.3677.0020.0002] # CANADIAN SYLLABICS THWAA +1569 ; [.3678.0020.0002] # CANADIAN SYLLABICS WEST-CREE THWAA +156A ; [.3679.0020.0002] # CANADIAN SYLLABICS TH +156B ; [.367A.0020.0002] # CANADIAN SYLLABICS TTHE +156C ; [.367B.0020.0002] # CANADIAN SYLLABICS TTHI +156D ; [.367C.0020.0002] # CANADIAN SYLLABICS TTHO +156E ; [.367D.0020.0002] # CANADIAN SYLLABICS TTHA +156F ; [.367E.0020.0002] # CANADIAN SYLLABICS TTH +1570 ; [.367F.0020.0002] # CANADIAN SYLLABICS TYE +1571 ; [.3680.0020.0002] # CANADIAN SYLLABICS TYI +1572 ; [.3681.0020.0002] # CANADIAN SYLLABICS TYO +1573 ; [.3682.0020.0002] # CANADIAN SYLLABICS TYA +1574 ; [.3683.0020.0002] # CANADIAN SYLLABICS NUNAVIK HE +1575 ; [.3684.0020.0002] # CANADIAN SYLLABICS NUNAVIK HI +1576 ; [.3685.0020.0002] # CANADIAN SYLLABICS NUNAVIK HII +1577 ; [.3686.0020.0002] # CANADIAN SYLLABICS NUNAVIK HO +1578 ; [.3687.0020.0002] # CANADIAN SYLLABICS NUNAVIK HOO +1579 ; [.3688.0020.0002] # CANADIAN SYLLABICS NUNAVIK HA +157A ; [.3689.0020.0002] # CANADIAN SYLLABICS NUNAVIK HAA +157B ; [.368A.0020.0002] # CANADIAN SYLLABICS NUNAVIK H +157D ; [.368B.0020.0002] # CANADIAN SYLLABICS HK +166F ; [.368C.0020.0002] # CANADIAN SYLLABICS QAI +157E ; [.368D.0020.0002] # CANADIAN SYLLABICS QAAI +157F ; [.368E.0020.0002] # CANADIAN SYLLABICS QI +1580 ; [.368F.0020.0002] # CANADIAN SYLLABICS QII +1581 ; [.3690.0020.0002] # CANADIAN SYLLABICS QO +1582 ; [.3691.0020.0002] # CANADIAN SYLLABICS QOO +1583 ; [.3692.0020.0002] # CANADIAN SYLLABICS QA +1584 ; [.3693.0020.0002] # CANADIAN SYLLABICS QAA +1585 ; [.3694.0020.0002] # CANADIAN SYLLABICS Q +1586 ; [.3695.0020.0002] # CANADIAN SYLLABICS TLHE +1587 ; [.3696.0020.0002] # CANADIAN SYLLABICS TLHI +1588 ; [.3697.0020.0002] # CANADIAN SYLLABICS TLHO +1589 ; [.3698.0020.0002] # CANADIAN SYLLABICS TLHA +158A ; [.3699.0020.0002] # CANADIAN SYLLABICS WEST-CREE RE +158B ; [.369A.0020.0002] # CANADIAN SYLLABICS WEST-CREE RI +158C ; [.369B.0020.0002] # CANADIAN SYLLABICS WEST-CREE RO +158D ; [.369C.0020.0002] # CANADIAN SYLLABICS WEST-CREE RA +1670 ; [.369D.0020.0002] # CANADIAN SYLLABICS NGAI +158E ; [.369E.0020.0002] # CANADIAN SYLLABICS NGAAI +158F ; [.369F.0020.0002] # CANADIAN SYLLABICS NGI +1590 ; [.36A0.0020.0002] # CANADIAN SYLLABICS NGII +1591 ; [.36A1.0020.0002] # CANADIAN SYLLABICS NGO +1592 ; [.36A2.0020.0002] # CANADIAN SYLLABICS NGOO +1593 ; [.36A3.0020.0002] # CANADIAN SYLLABICS NGA +1594 ; [.36A4.0020.0002] # CANADIAN SYLLABICS NGAA +1595 ; [.36A5.0020.0002] # CANADIAN SYLLABICS NG +1671 ; [.36A6.0020.0002] # CANADIAN SYLLABICS NNGI +1672 ; [.36A7.0020.0002] # CANADIAN SYLLABICS NNGII +1673 ; [.36A8.0020.0002] # CANADIAN SYLLABICS NNGO +1674 ; [.36A9.0020.0002] # CANADIAN SYLLABICS NNGOO +1675 ; [.36AA.0020.0002] # CANADIAN SYLLABICS NNGA +1676 ; [.36AB.0020.0002] # CANADIAN SYLLABICS NNGAA +1596 ; [.36AC.0020.0002] # CANADIAN SYLLABICS NNG +1597 ; [.36AD.0020.0002] # CANADIAN SYLLABICS SAYISI SHE +1598 ; [.36AE.0020.0002] # CANADIAN SYLLABICS SAYISI SHI +1599 ; [.36AF.0020.0002] # CANADIAN SYLLABICS SAYISI SHO +159A ; [.36B0.0020.0002] # CANADIAN SYLLABICS SAYISI SHA +159B ; [.36B1.0020.0002] # CANADIAN SYLLABICS WOODS-CREE THE +159C ; [.36B2.0020.0002] # CANADIAN SYLLABICS WOODS-CREE THI +159D ; [.36B3.0020.0002] # CANADIAN SYLLABICS WOODS-CREE THO +159E ; [.36B4.0020.0002] # CANADIAN SYLLABICS WOODS-CREE THA +159F ; [.36B5.0020.0002] # CANADIAN SYLLABICS WOODS-CREE TH +15A0 ; [.36B6.0020.0002] # CANADIAN SYLLABICS LHI +15A1 ; [.36B7.0020.0002] # CANADIAN SYLLABICS LHII +15A2 ; [.36B8.0020.0002] # CANADIAN SYLLABICS LHO +15A3 ; [.36B9.0020.0002] # CANADIAN SYLLABICS LHOO +15A4 ; [.36BA.0020.0002] # CANADIAN SYLLABICS LHA +15A5 ; [.36BB.0020.0002] # CANADIAN SYLLABICS LHAA +15A6 ; [.36BC.0020.0002] # CANADIAN SYLLABICS LH +157C ; [.36BD.0020.0002] # CANADIAN SYLLABICS NUNAVUT H +15A7 ; [.36BE.0020.0002] # CANADIAN SYLLABICS TH-CREE THE +15A8 ; [.36BF.0020.0002] # CANADIAN SYLLABICS TH-CREE THI +15A9 ; [.36C0.0020.0002] # CANADIAN SYLLABICS TH-CREE THII +15AA ; [.36C1.0020.0002] # CANADIAN SYLLABICS TH-CREE THO +15AB ; [.36C2.0020.0002] # CANADIAN SYLLABICS TH-CREE THOO +15AC ; [.36C3.0020.0002] # CANADIAN SYLLABICS TH-CREE THA +15AD ; [.36C4.0020.0002] # CANADIAN SYLLABICS TH-CREE THAA +15AE ; [.36C5.0020.0002] # CANADIAN SYLLABICS TH-CREE TH +15AF ; [.36C6.0020.0002] # CANADIAN SYLLABICS AIVILIK B +15B0 ; [.36C7.0020.0002] # CANADIAN SYLLABICS BLACKFOOT E +15B1 ; [.36C8.0020.0002] # CANADIAN SYLLABICS BLACKFOOT I +15B2 ; [.36C9.0020.0002] # CANADIAN SYLLABICS BLACKFOOT O +15B3 ; [.36CA.0020.0002] # CANADIAN SYLLABICS BLACKFOOT A +15B4 ; [.36CB.0020.0002] # CANADIAN SYLLABICS BLACKFOOT WE +15B5 ; [.36CC.0020.0002] # CANADIAN SYLLABICS BLACKFOOT WI +15B6 ; [.36CD.0020.0002] # CANADIAN SYLLABICS BLACKFOOT WO +15B7 ; [.36CE.0020.0002] # CANADIAN SYLLABICS BLACKFOOT WA +15B8 ; [.36CF.0020.0002] # CANADIAN SYLLABICS BLACKFOOT NE +15B9 ; [.36D0.0020.0002] # CANADIAN SYLLABICS BLACKFOOT NI +15BA ; [.36D1.0020.0002] # CANADIAN SYLLABICS BLACKFOOT NO +15BB ; [.36D2.0020.0002] # CANADIAN SYLLABICS BLACKFOOT NA +15BC ; [.36D3.0020.0002] # CANADIAN SYLLABICS BLACKFOOT KE +15BD ; [.36D4.0020.0002] # CANADIAN SYLLABICS BLACKFOOT KI +15BE ; [.36D5.0020.0002] # CANADIAN SYLLABICS BLACKFOOT KO +15BF ; [.36D6.0020.0002] # CANADIAN SYLLABICS BLACKFOOT KA +15C0 ; [.36D7.0020.0002] # CANADIAN SYLLABICS SAYISI HE +15C1 ; [.36D8.0020.0002] # CANADIAN SYLLABICS SAYISI HI +15C2 ; [.36D9.0020.0002] # CANADIAN SYLLABICS SAYISI HO +15C3 ; [.36DA.0020.0002] # CANADIAN SYLLABICS SAYISI HA +15C4 ; [.36DB.0020.0002] # CANADIAN SYLLABICS CARRIER GHU +15C5 ; [.36DC.0020.0002] # CANADIAN SYLLABICS CARRIER GHO +15C6 ; [.36DD.0020.0002] # CANADIAN SYLLABICS CARRIER GHE +15C7 ; [.36DE.0020.0002] # CANADIAN SYLLABICS CARRIER GHEE +15C8 ; [.36DF.0020.0002] # CANADIAN SYLLABICS CARRIER GHI +15C9 ; [.36E0.0020.0002] # CANADIAN SYLLABICS CARRIER GHA +15CA ; [.36E1.0020.0002] # CANADIAN SYLLABICS CARRIER RU +15CB ; [.36E2.0020.0002] # CANADIAN SYLLABICS CARRIER RO +15CC ; [.36E3.0020.0002] # CANADIAN SYLLABICS CARRIER RE +15CD ; [.36E4.0020.0002] # CANADIAN SYLLABICS CARRIER REE +15CE ; [.36E5.0020.0002] # CANADIAN SYLLABICS CARRIER RI +15CF ; [.36E6.0020.0002] # CANADIAN SYLLABICS CARRIER RA +15D0 ; [.36E7.0020.0002] # CANADIAN SYLLABICS CARRIER WU +15D1 ; [.36E8.0020.0002] # CANADIAN SYLLABICS CARRIER WO +15D2 ; [.36E9.0020.0002] # CANADIAN SYLLABICS CARRIER WE +15D3 ; [.36EA.0020.0002] # CANADIAN SYLLABICS CARRIER WEE +15D4 ; [.36EB.0020.0002] # CANADIAN SYLLABICS CARRIER WI +15D5 ; [.36EC.0020.0002] # CANADIAN SYLLABICS CARRIER WA +15D6 ; [.36ED.0020.0002] # CANADIAN SYLLABICS CARRIER HWU +15D7 ; [.36EE.0020.0002] # CANADIAN SYLLABICS CARRIER HWO +15D8 ; [.36EF.0020.0002] # CANADIAN SYLLABICS CARRIER HWE +15D9 ; [.36F0.0020.0002] # CANADIAN SYLLABICS CARRIER HWEE +15DA ; [.36F1.0020.0002] # CANADIAN SYLLABICS CARRIER HWI +15DB ; [.36F2.0020.0002] # CANADIAN SYLLABICS CARRIER HWA +15DC ; [.36F3.0020.0002] # CANADIAN SYLLABICS CARRIER THU +15DD ; [.36F4.0020.0002] # CANADIAN SYLLABICS CARRIER THO +15DE ; [.36F5.0020.0002] # CANADIAN SYLLABICS CARRIER THE +15DF ; [.36F6.0020.0002] # CANADIAN SYLLABICS CARRIER THEE +15E0 ; [.36F7.0020.0002] # CANADIAN SYLLABICS CARRIER THI +15E1 ; [.36F8.0020.0002] # CANADIAN SYLLABICS CARRIER THA +15E2 ; [.36F9.0020.0002] # CANADIAN SYLLABICS CARRIER TTU +15E3 ; [.36FA.0020.0002] # CANADIAN SYLLABICS CARRIER TTO +15E4 ; [.36FB.0020.0002] # CANADIAN SYLLABICS CARRIER TTE +15E5 ; [.36FC.0020.0002] # CANADIAN SYLLABICS CARRIER TTEE +15E6 ; [.36FD.0020.0002] # CANADIAN SYLLABICS CARRIER TTI +15E7 ; [.36FE.0020.0002] # CANADIAN SYLLABICS CARRIER TTA +15E8 ; [.36FF.0020.0002] # CANADIAN SYLLABICS CARRIER PU +15E9 ; [.3700.0020.0002] # CANADIAN SYLLABICS CARRIER PO +15EA ; [.3701.0020.0002] # CANADIAN SYLLABICS CARRIER PE +15EB ; [.3702.0020.0002] # CANADIAN SYLLABICS CARRIER PEE +15EC ; [.3703.0020.0002] # CANADIAN SYLLABICS CARRIER PI +15ED ; [.3704.0020.0002] # CANADIAN SYLLABICS CARRIER PA +15EE ; [.3705.0020.0002] # CANADIAN SYLLABICS CARRIER P +15EF ; [.3706.0020.0002] # CANADIAN SYLLABICS CARRIER GU +15F0 ; [.3707.0020.0002] # CANADIAN SYLLABICS CARRIER GO +15F1 ; [.3708.0020.0002] # CANADIAN SYLLABICS CARRIER GE +15F2 ; [.3709.0020.0002] # CANADIAN SYLLABICS CARRIER GEE +15F3 ; [.370A.0020.0002] # CANADIAN SYLLABICS CARRIER GI +15F4 ; [.370B.0020.0002] # CANADIAN SYLLABICS CARRIER GA +15F5 ; [.370C.0020.0002] # CANADIAN SYLLABICS CARRIER KHU +15F6 ; [.370D.0020.0002] # CANADIAN SYLLABICS CARRIER KHO +15F7 ; [.370E.0020.0002] # CANADIAN SYLLABICS CARRIER KHE +15F8 ; [.370F.0020.0002] # CANADIAN SYLLABICS CARRIER KHEE +15F9 ; [.3710.0020.0002] # CANADIAN SYLLABICS CARRIER KHI +15FA ; [.3711.0020.0002] # CANADIAN SYLLABICS CARRIER KHA +15FB ; [.3712.0020.0002] # CANADIAN SYLLABICS CARRIER KKU +15FC ; [.3713.0020.0002] # CANADIAN SYLLABICS CARRIER KKO +15FD ; [.3714.0020.0002] # CANADIAN SYLLABICS CARRIER KKE +15FE ; [.3715.0020.0002] # CANADIAN SYLLABICS CARRIER KKEE +15FF ; [.3716.0020.0002] # CANADIAN SYLLABICS CARRIER KKI +1600 ; [.3717.0020.0002] # CANADIAN SYLLABICS CARRIER KKA +1601 ; [.3718.0020.0002] # CANADIAN SYLLABICS CARRIER KK +1602 ; [.3719.0020.0002] # CANADIAN SYLLABICS CARRIER NU +1603 ; [.371A.0020.0002] # CANADIAN SYLLABICS CARRIER NO +1604 ; [.371B.0020.0002] # CANADIAN SYLLABICS CARRIER NE +1605 ; [.371C.0020.0002] # CANADIAN SYLLABICS CARRIER NEE +1606 ; [.371D.0020.0002] # CANADIAN SYLLABICS CARRIER NI +1607 ; [.371E.0020.0002] # CANADIAN SYLLABICS CARRIER NA +1608 ; [.371F.0020.0002] # CANADIAN SYLLABICS CARRIER MU +1609 ; [.3720.0020.0002] # CANADIAN SYLLABICS CARRIER MO +160A ; [.3721.0020.0002] # CANADIAN SYLLABICS CARRIER ME +160B ; [.3722.0020.0002] # CANADIAN SYLLABICS CARRIER MEE +160C ; [.3723.0020.0002] # CANADIAN SYLLABICS CARRIER MI +160D ; [.3724.0020.0002] # CANADIAN SYLLABICS CARRIER MA +160E ; [.3725.0020.0002] # CANADIAN SYLLABICS CARRIER YU +160F ; [.3726.0020.0002] # CANADIAN SYLLABICS CARRIER YO +1610 ; [.3727.0020.0002] # CANADIAN SYLLABICS CARRIER YE +1611 ; [.3728.0020.0002] # CANADIAN SYLLABICS CARRIER YEE +1612 ; [.3729.0020.0002] # CANADIAN SYLLABICS CARRIER YI +1613 ; [.372A.0020.0002] # CANADIAN SYLLABICS CARRIER YA +1614 ; [.372B.0020.0002] # CANADIAN SYLLABICS CARRIER JU +1615 ; [.372C.0020.0002] # CANADIAN SYLLABICS SAYISI JU +1616 ; [.372D.0020.0002] # CANADIAN SYLLABICS CARRIER JO +1617 ; [.372E.0020.0002] # CANADIAN SYLLABICS CARRIER JE +1618 ; [.372F.0020.0002] # CANADIAN SYLLABICS CARRIER JEE +1619 ; [.3730.0020.0002] # CANADIAN SYLLABICS CARRIER JI +161A ; [.3731.0020.0002] # CANADIAN SYLLABICS SAYISI JI +161B ; [.3732.0020.0002] # CANADIAN SYLLABICS CARRIER JA +161C ; [.3733.0020.0002] # CANADIAN SYLLABICS CARRIER JJU +161D ; [.3734.0020.0002] # CANADIAN SYLLABICS CARRIER JJO +161E ; [.3735.0020.0002] # CANADIAN SYLLABICS CARRIER JJE +161F ; [.3736.0020.0002] # CANADIAN SYLLABICS CARRIER JJEE +1620 ; [.3737.0020.0002] # CANADIAN SYLLABICS CARRIER JJI +1621 ; [.3738.0020.0002] # CANADIAN SYLLABICS CARRIER JJA +1622 ; [.3739.0020.0002] # CANADIAN SYLLABICS CARRIER LU +1623 ; [.373A.0020.0002] # CANADIAN SYLLABICS CARRIER LO +1624 ; [.373B.0020.0002] # CANADIAN SYLLABICS CARRIER LE +1625 ; [.373C.0020.0002] # CANADIAN SYLLABICS CARRIER LEE +1626 ; [.373D.0020.0002] # CANADIAN SYLLABICS CARRIER LI +1627 ; [.373E.0020.0002] # CANADIAN SYLLABICS CARRIER LA +1628 ; [.373F.0020.0002] # CANADIAN SYLLABICS CARRIER DLU +1629 ; [.3740.0020.0002] # CANADIAN SYLLABICS CARRIER DLO +162A ; [.3741.0020.0002] # CANADIAN SYLLABICS CARRIER DLE +162B ; [.3742.0020.0002] # CANADIAN SYLLABICS CARRIER DLEE +162C ; [.3743.0020.0002] # CANADIAN SYLLABICS CARRIER DLI +162D ; [.3744.0020.0002] # CANADIAN SYLLABICS CARRIER DLA +162E ; [.3745.0020.0002] # CANADIAN SYLLABICS CARRIER LHU +162F ; [.3746.0020.0002] # CANADIAN SYLLABICS CARRIER LHO +1630 ; [.3747.0020.0002] # CANADIAN SYLLABICS CARRIER LHE +1631 ; [.3748.0020.0002] # CANADIAN SYLLABICS CARRIER LHEE +1632 ; [.3749.0020.0002] # CANADIAN SYLLABICS CARRIER LHI +1633 ; [.374A.0020.0002] # CANADIAN SYLLABICS CARRIER LHA +1634 ; [.374B.0020.0002] # CANADIAN SYLLABICS CARRIER TLHU +1635 ; [.374C.0020.0002] # CANADIAN SYLLABICS CARRIER TLHO +1636 ; [.374D.0020.0002] # CANADIAN SYLLABICS CARRIER TLHE +1637 ; [.374E.0020.0002] # CANADIAN SYLLABICS CARRIER TLHEE +1638 ; [.374F.0020.0002] # CANADIAN SYLLABICS CARRIER TLHI +1639 ; [.3750.0020.0002] # CANADIAN SYLLABICS CARRIER TLHA +163A ; [.3751.0020.0002] # CANADIAN SYLLABICS CARRIER TLU +163B ; [.3752.0020.0002] # CANADIAN SYLLABICS CARRIER TLO +163C ; [.3753.0020.0002] # CANADIAN SYLLABICS CARRIER TLE +163D ; [.3754.0020.0002] # CANADIAN SYLLABICS CARRIER TLEE +163E ; [.3755.0020.0002] # CANADIAN SYLLABICS CARRIER TLI +163F ; [.3756.0020.0002] # CANADIAN SYLLABICS CARRIER TLA +1640 ; [.3757.0020.0002] # CANADIAN SYLLABICS CARRIER ZU +1641 ; [.3758.0020.0002] # CANADIAN SYLLABICS CARRIER ZO +1642 ; [.3759.0020.0002] # CANADIAN SYLLABICS CARRIER ZE +1643 ; [.375A.0020.0002] # CANADIAN SYLLABICS CARRIER ZEE +1644 ; [.375B.0020.0002] # CANADIAN SYLLABICS CARRIER ZI +1645 ; [.375C.0020.0002] # CANADIAN SYLLABICS CARRIER ZA +1646 ; [.375D.0020.0002] # CANADIAN SYLLABICS CARRIER Z +1647 ; [.375E.0020.0002] # CANADIAN SYLLABICS CARRIER INITIAL Z +1648 ; [.375F.0020.0002] # CANADIAN SYLLABICS CARRIER DZU +1649 ; [.3760.0020.0002] # CANADIAN SYLLABICS CARRIER DZO +164A ; [.3761.0020.0002] # CANADIAN SYLLABICS CARRIER DZE +164B ; [.3762.0020.0002] # CANADIAN SYLLABICS CARRIER DZEE +164C ; [.3763.0020.0002] # CANADIAN SYLLABICS CARRIER DZI +164D ; [.3764.0020.0002] # CANADIAN SYLLABICS CARRIER DZA +164E ; [.3765.0020.0002] # CANADIAN SYLLABICS CARRIER SU +164F ; [.3766.0020.0002] # CANADIAN SYLLABICS CARRIER SO +1650 ; [.3767.0020.0002] # CANADIAN SYLLABICS CARRIER SE +1651 ; [.3768.0020.0002] # CANADIAN SYLLABICS CARRIER SEE +1652 ; [.3769.0020.0002] # CANADIAN SYLLABICS CARRIER SI +1653 ; [.376A.0020.0002] # CANADIAN SYLLABICS CARRIER SA +1654 ; [.376B.0020.0002] # CANADIAN SYLLABICS CARRIER SHU +1655 ; [.376C.0020.0002] # CANADIAN SYLLABICS CARRIER SHO +1656 ; [.376D.0020.0002] # CANADIAN SYLLABICS CARRIER SHE +1657 ; [.376E.0020.0002] # CANADIAN SYLLABICS CARRIER SHEE +1658 ; [.376F.0020.0002] # CANADIAN SYLLABICS CARRIER SHI +1659 ; [.3770.0020.0002] # CANADIAN SYLLABICS CARRIER SHA +165A ; [.3771.0020.0002] # CANADIAN SYLLABICS CARRIER SH +165B ; [.3772.0020.0002] # CANADIAN SYLLABICS CARRIER TSU +165C ; [.3773.0020.0002] # CANADIAN SYLLABICS CARRIER TSO +165D ; [.3774.0020.0002] # CANADIAN SYLLABICS CARRIER TSE +165E ; [.3775.0020.0002] # CANADIAN SYLLABICS CARRIER TSEE +165F ; [.3776.0020.0002] # CANADIAN SYLLABICS CARRIER TSI +1660 ; [.3777.0020.0002] # CANADIAN SYLLABICS CARRIER TSA +1661 ; [.3778.0020.0002] # CANADIAN SYLLABICS CARRIER CHU +1662 ; [.3779.0020.0002] # CANADIAN SYLLABICS CARRIER CHO +1663 ; [.377A.0020.0002] # CANADIAN SYLLABICS CARRIER CHE +1664 ; [.377B.0020.0002] # CANADIAN SYLLABICS CARRIER CHEE +1665 ; [.377C.0020.0002] # CANADIAN SYLLABICS CARRIER CHI +1666 ; [.377D.0020.0002] # CANADIAN SYLLABICS CARRIER CHA +1667 ; [.377E.0020.0002] # CANADIAN SYLLABICS CARRIER TTSU +1668 ; [.377F.0020.0002] # CANADIAN SYLLABICS CARRIER TTSO +1669 ; [.3780.0020.0002] # CANADIAN SYLLABICS CARRIER TTSE +166A ; [.3781.0020.0002] # CANADIAN SYLLABICS CARRIER TTSEE +166B ; [.3782.0020.0002] # CANADIAN SYLLABICS CARRIER TTSI +166C ; [.3783.0020.0002] # CANADIAN SYLLABICS CARRIER TTSA +1677 ; [.3784.0020.0002] # CANADIAN SYLLABICS WOODS-CREE THWEE +1678 ; [.3785.0020.0002] # CANADIAN SYLLABICS WOODS-CREE THWI +1679 ; [.3786.0020.0002] # CANADIAN SYLLABICS WOODS-CREE THWII +167A ; [.3787.0020.0002] # CANADIAN SYLLABICS WOODS-CREE THWO +167B ; [.3788.0020.0002] # CANADIAN SYLLABICS WOODS-CREE THWOO +167C ; [.3789.0020.0002] # CANADIAN SYLLABICS WOODS-CREE THWA +167D ; [.378A.0020.0002] # CANADIAN SYLLABICS WOODS-CREE THWAA +167E ; [.378B.0020.0002] # CANADIAN SYLLABICS WOODS-CREE FINAL TH +167F ; [.378C.0020.0002] # CANADIAN SYLLABICS BLACKFOOT W +18B0 ; [.378D.0020.0002] # CANADIAN SYLLABICS OY +18B1 ; [.378E.0020.0002] # CANADIAN SYLLABICS AY +18B2 ; [.378F.0020.0002] # CANADIAN SYLLABICS AAY +18B3 ; [.3790.0020.0002] # CANADIAN SYLLABICS WAY +18B4 ; [.3791.0020.0002] # CANADIAN SYLLABICS POY +18B5 ; [.3792.0020.0002] # CANADIAN SYLLABICS PAY +18B6 ; [.3793.0020.0002] # CANADIAN SYLLABICS PWOY +18B7 ; [.3794.0020.0002] # CANADIAN SYLLABICS TAY +18B8 ; [.3795.0020.0002] # CANADIAN SYLLABICS KAY +18B9 ; [.3796.0020.0002] # CANADIAN SYLLABICS KWAY +18BA ; [.3797.0020.0002] # CANADIAN SYLLABICS MAY +18BB ; [.3798.0020.0002] # CANADIAN SYLLABICS NOY +18BC ; [.3799.0020.0002] # CANADIAN SYLLABICS NAY +18BD ; [.379A.0020.0002] # CANADIAN SYLLABICS LAY +18BE ; [.379B.0020.0002] # CANADIAN SYLLABICS SOY +18BF ; [.379C.0020.0002] # CANADIAN SYLLABICS SAY +18C0 ; [.379D.0020.0002] # CANADIAN SYLLABICS SHOY +18C1 ; [.379E.0020.0002] # CANADIAN SYLLABICS SHAY +18C2 ; [.379F.0020.0002] # CANADIAN SYLLABICS SHWOY +18C3 ; [.37A0.0020.0002] # CANADIAN SYLLABICS YOY +18C4 ; [.37A1.0020.0002] # CANADIAN SYLLABICS YAY +18C5 ; [.37A2.0020.0002] # CANADIAN SYLLABICS RAY +18C6 ; [.37A3.0020.0002] # CANADIAN SYLLABICS NWI +18C7 ; [.37A4.0020.0002] # CANADIAN SYLLABICS OJIBWAY NWI +18C8 ; [.37A5.0020.0002] # CANADIAN SYLLABICS NWII +18C9 ; [.37A6.0020.0002] # CANADIAN SYLLABICS OJIBWAY NWII +18CA ; [.37A7.0020.0002] # CANADIAN SYLLABICS NWO +18CB ; [.37A8.0020.0002] # CANADIAN SYLLABICS OJIBWAY NWO +18CC ; [.37A9.0020.0002] # CANADIAN SYLLABICS NWOO +18CD ; [.37AA.0020.0002] # CANADIAN SYLLABICS OJIBWAY NWOO +18CE ; [.37AB.0020.0002] # CANADIAN SYLLABICS RWEE +18CF ; [.37AC.0020.0002] # CANADIAN SYLLABICS RWI +18D0 ; [.37AD.0020.0002] # CANADIAN SYLLABICS RWII +18D1 ; [.37AE.0020.0002] # CANADIAN SYLLABICS RWO +18D2 ; [.37AF.0020.0002] # CANADIAN SYLLABICS RWOO +18D3 ; [.37B0.0020.0002] # CANADIAN SYLLABICS RWA +18D4 ; [.37B1.0020.0002] # CANADIAN SYLLABICS OJIBWAY P +18D5 ; [.37B2.0020.0002] # CANADIAN SYLLABICS OJIBWAY T +18D6 ; [.37B3.0020.0002] # CANADIAN SYLLABICS OJIBWAY K +18D7 ; [.37B4.0020.0002] # CANADIAN SYLLABICS OJIBWAY C +18D8 ; [.37B5.0020.0002] # CANADIAN SYLLABICS OJIBWAY M +18D9 ; [.37B6.0020.0002] # CANADIAN SYLLABICS OJIBWAY N +18DA ; [.37B7.0020.0002] # CANADIAN SYLLABICS OJIBWAY S +18DB ; [.37B8.0020.0002] # CANADIAN SYLLABICS OJIBWAY SH +18DC ; [.37B9.0020.0002] # CANADIAN SYLLABICS EASTERN W +18DD ; [.37BA.0020.0002] # CANADIAN SYLLABICS WESTERN W +18DE ; [.37BB.0020.0002] # CANADIAN SYLLABICS FINAL SMALL RING +18DF ; [.37BC.0020.0002] # CANADIAN SYLLABICS FINAL RAISED DOT +18E0 ; [.37BD.0020.0002] # CANADIAN SYLLABICS R-CREE RWE +18E1 ; [.37BE.0020.0002] # CANADIAN SYLLABICS WEST-CREE LOO +18E2 ; [.37BF.0020.0002] # CANADIAN SYLLABICS WEST-CREE LAA +18E3 ; [.37C0.0020.0002] # CANADIAN SYLLABICS THWE +18E4 ; [.37C1.0020.0002] # CANADIAN SYLLABICS THWA +18E5 ; [.37C2.0020.0002] # CANADIAN SYLLABICS TTHWE +18E6 ; [.37C3.0020.0002] # CANADIAN SYLLABICS TTHOO +18E7 ; [.37C4.0020.0002] # CANADIAN SYLLABICS TTHAA +18E8 ; [.37C5.0020.0002] # CANADIAN SYLLABICS TLHWE +18E9 ; [.37C6.0020.0002] # CANADIAN SYLLABICS TLHOO +18EA ; [.37C7.0020.0002] # CANADIAN SYLLABICS SAYISI SHWE +18EB ; [.37C8.0020.0002] # CANADIAN SYLLABICS SAYISI SHOO +18EC ; [.37C9.0020.0002] # CANADIAN SYLLABICS SAYISI HOO +18ED ; [.37CA.0020.0002] # CANADIAN SYLLABICS CARRIER GWU +18EE ; [.37CB.0020.0002] # CANADIAN SYLLABICS CARRIER DENE GEE +18EF ; [.37CC.0020.0002] # CANADIAN SYLLABICS CARRIER GAA +18F0 ; [.37CD.0020.0002] # CANADIAN SYLLABICS CARRIER GWA +18F1 ; [.37CE.0020.0002] # CANADIAN SYLLABICS SAYISI JUU +18F2 ; [.37CF.0020.0002] # CANADIAN SYLLABICS CARRIER JWA +18F3 ; [.37D0.0020.0002] # CANADIAN SYLLABICS BEAVER DENE L +18F4 ; [.37D1.0020.0002] # CANADIAN SYLLABICS BEAVER DENE R +18F5 ; [.37D2.0020.0002] # CANADIAN SYLLABICS CARRIER DENTAL S +1681 ; [.37D3.0020.0002] # OGHAM LETTER BEITH +1682 ; [.37D4.0020.0002] # OGHAM LETTER LUIS +1683 ; [.37D5.0020.0002] # OGHAM LETTER FEARN +1684 ; [.37D6.0020.0002] # OGHAM LETTER SAIL +1685 ; [.37D7.0020.0002] # OGHAM LETTER NION +1686 ; [.37D8.0020.0002] # OGHAM LETTER UATH +1687 ; [.37D9.0020.0002] # OGHAM LETTER DAIR +1688 ; [.37DA.0020.0002] # OGHAM LETTER TINNE +1689 ; [.37DB.0020.0002] # OGHAM LETTER COLL +168A ; [.37DC.0020.0002] # OGHAM LETTER CEIRT +168B ; [.37DD.0020.0002] # OGHAM LETTER MUIN +168C ; [.37DE.0020.0002] # OGHAM LETTER GORT +168D ; [.37DF.0020.0002] # OGHAM LETTER NGEADAL +168E ; [.37E0.0020.0002] # OGHAM LETTER STRAIF +168F ; [.37E1.0020.0002] # OGHAM LETTER RUIS +1690 ; [.37E2.0020.0002] # OGHAM LETTER AILM +1691 ; [.37E3.0020.0002] # OGHAM LETTER ONN +1692 ; [.37E4.0020.0002] # OGHAM LETTER UR +1693 ; [.37E5.0020.0002] # OGHAM LETTER EADHADH +1694 ; [.37E6.0020.0002] # OGHAM LETTER IODHADH +1695 ; [.37E7.0020.0002] # OGHAM LETTER EABHADH +1696 ; [.37E8.0020.0002] # OGHAM LETTER OR +1697 ; [.37E9.0020.0002] # OGHAM LETTER UILLEANN +1698 ; [.37EA.0020.0002] # OGHAM LETTER IFIN +1699 ; [.37EB.0020.0002] # OGHAM LETTER EAMHANCHOLL +169A ; [.37EC.0020.0002] # OGHAM LETTER PEITH +16A0 ; [.37ED.0020.0002] # RUNIC LETTER FEHU FEOH FE F +16A1 ; [.37ED.0020.0004][.0000.0111.0004] # RUNIC LETTER V +16A2 ; [.37EE.0020.0002] # RUNIC LETTER URUZ UR U +16A4 ; [.37EE.0020.0004][.0000.0111.0004] # RUNIC LETTER Y +16A5 ; [.37EE.0020.0004][.0000.0112.0004] # RUNIC LETTER W +16A6 ; [.37EF.0020.0002] # RUNIC LETTER THURISAZ THURS THORN +16A7 ; [.37EF.0020.0004][.0000.0111.0004] # RUNIC LETTER ETH +16F0 ; [.37EF.0020.0004][.37EF.0020.0004] # RUNIC BELGTHOR SYMBOL +16A8 ; [.37F0.0020.0002] # RUNIC LETTER ANSUZ A +16A9 ; [.37F0.0020.0004][.0000.0111.0004] # RUNIC LETTER OS O +16AC ; [.37F0.0020.0004][.0000.0112.0004] # RUNIC LETTER LONG-BRANCH-OSS O +16AD ; [.37F0.0020.0004][.0000.0113.0004] # RUNIC LETTER SHORT-TWIG-OSS O +16AE ; [.37F0.0020.0004][.0000.0114.0004] # RUNIC LETTER O +16F4 ; [.37F1.0020.0002] # RUNIC LETTER FRANKS CASKET OS +16AF ; [.37F2.0020.0002] # RUNIC LETTER OE +16B0 ; [.37F3.0020.0002] # RUNIC LETTER ON +16B1 ; [.37F4.0020.0002] # RUNIC LETTER RAIDO RAD REID R +16B2 ; [.37F5.0020.0002] # RUNIC LETTER KAUNA +16B3 ; [.37F5.0020.0004][.0000.0111.0004] # RUNIC LETTER CEN +16B4 ; [.37F5.0020.0004][.0000.0112.0004] # RUNIC LETTER KAUN K +16B5 ; [.37F5.0020.0004][.0000.0113.0004] # RUNIC LETTER G +16B6 ; [.37F5.0020.0004][.0000.0114.0004] # RUNIC LETTER ENG +16F1 ; [.37F6.0020.0002] # RUNIC LETTER K +16B7 ; [.37F7.0020.0002] # RUNIC LETTER GEBO GYFU G +16B9 ; [.37F8.0020.0002] # RUNIC LETTER WUNJO WYNN W +16E9 ; [.37F8.0020.0004][.0000.0111.0004] # RUNIC LETTER Q +16BA ; [.37F9.0020.0002] # RUNIC LETTER HAGLAZ H +16BB ; [.37F9.0020.0004][.0000.0111.0004] # RUNIC LETTER HAEGL H +16BC ; [.37F9.0020.0004][.0000.0112.0004] # RUNIC LETTER LONG-BRANCH-HAGALL H +16BD ; [.37F9.0020.0004][.0000.0113.0004] # RUNIC LETTER SHORT-TWIG-HAGALL H +16BE ; [.37FA.0020.0002] # RUNIC LETTER NAUDIZ NYD NAUD N +16BF ; [.37FA.0020.0004][.0000.0111.0004] # RUNIC LETTER SHORT-TWIG-NAUD N +16C0 ; [.37FA.0020.0004][.0000.0112.0004] # RUNIC LETTER DOTTED-N +16C1 ; [.37FB.0020.0002] # RUNIC LETTER ISAZ IS ISS I +16C2 ; [.37FB.0020.0004][.0000.0111.0004] # RUNIC LETTER E +16F5 ; [.37FC.0020.0002] # RUNIC LETTER FRANKS CASKET IS +16C3 ; [.37FD.0020.0002] # RUNIC LETTER JERAN J +16C4 ; [.37FD.0020.0004][.0000.0111.0004] # RUNIC LETTER GER +16C5 ; [.37FE.0020.0002] # RUNIC LETTER LONG-BRANCH-AR AE +16C6 ; [.37FE.0020.0004][.0000.0111.0004] # RUNIC LETTER SHORT-TWIG-AR A +16EE ; [.37FE.0020.0004][.3809.0020.0004] # RUNIC ARLAUG SYMBOL +16C7 ; [.37FF.0020.0002] # RUNIC LETTER IWAZ EOH +16C8 ; [.3800.0020.0002] # RUNIC LETTER PERTHO PEORTH P +16D5 ; [.3800.0020.0004][.0000.0111.0004] # RUNIC LETTER OPEN-P +16C9 ; [.3801.0020.0002] # RUNIC LETTER ALGIZ EOLHX +16CA ; [.3802.0020.0002] # RUNIC LETTER SOWILO S +16CB ; [.3802.0020.0004][.0000.0111.0004] # RUNIC LETTER SIGEL LONG-BRANCH-SOL S +16EA ; [.3802.0020.0004][.0000.0112.0004] # RUNIC LETTER X +16CC ; [.3802.0020.0004][.0000.0113.0004] # RUNIC LETTER SHORT-TWIG-SOL S +16CD ; [.3802.0020.0004][.0000.0114.0004] # RUNIC LETTER C +16CE ; [.3802.0020.0004][.0000.0115.0004] # RUNIC LETTER Z +16F2 ; [.3803.0020.0002] # RUNIC LETTER SH +16CF ; [.3804.0020.0002] # RUNIC LETTER TIWAZ TIR TYR T +16D0 ; [.3804.0020.0004][.0000.0111.0004] # RUNIC LETTER SHORT-TWIG-TYR T +16D1 ; [.3804.0020.0004][.0000.0112.0004] # RUNIC LETTER D +16D2 ; [.3805.0020.0002] # RUNIC LETTER BERKANAN BEORC BJARKAN B +16D3 ; [.3805.0020.0004][.0000.0111.0004] # RUNIC LETTER SHORT-TWIG-BJARKAN B +16D4 ; [.3805.0020.0004][.0000.0112.0004] # RUNIC LETTER DOTTED-P +16D6 ; [.3806.0020.0002] # RUNIC LETTER EHWAZ EH E +16F6 ; [.3807.0020.0002] # RUNIC LETTER FRANKS CASKET EH +16D7 ; [.3808.0020.0002] # RUNIC LETTER MANNAZ MAN M +16D8 ; [.3808.0020.0004][.0000.0111.0004] # RUNIC LETTER LONG-BRANCH-MADR M +16D9 ; [.3808.0020.0004][.0000.0112.0004] # RUNIC LETTER SHORT-TWIG-MADR M +16EF ; [.3808.0020.0004][.0000.0111.0004][.3808.0020.0004][.0000.0111.0004] # RUNIC TVIMADUR SYMBOL +16DA ; [.3809.0020.0002] # RUNIC LETTER LAUKAZ LAGU LOGR L +16DB ; [.3809.0020.0004][.0000.0111.0004] # RUNIC LETTER DOTTED-L +16DC ; [.380A.0020.0002] # RUNIC LETTER INGWAZ +16DD ; [.380A.0020.0004][.0000.0111.0004] # RUNIC LETTER ING +16DE ; [.380B.0020.0002] # RUNIC LETTER DAGAZ DAEG D +16DF ; [.380C.0020.0002] # RUNIC LETTER OTHALAN ETHEL O +16F3 ; [.380D.0020.0002] # RUNIC LETTER OO +16AA ; [.380E.0020.0002] # RUNIC LETTER AC A +16F7 ; [.380F.0020.0002] # RUNIC LETTER FRANKS CASKET AC +16AB ; [.3810.0020.0002] # RUNIC LETTER AESC +16F8 ; [.3811.0020.0002] # RUNIC LETTER FRANKS CASKET AESC +16A3 ; [.3812.0020.0002] # RUNIC LETTER YR +16E0 ; [.3813.0020.0002] # RUNIC LETTER EAR +16E3 ; [.3814.0020.0002] # RUNIC LETTER CALC +16B8 ; [.3815.0020.0002] # RUNIC LETTER GAR +16E4 ; [.3816.0020.0002] # RUNIC LETTER CEALC +16E1 ; [.3817.0020.0002] # RUNIC LETTER IOR +16E2 ; [.3818.0020.0002] # RUNIC LETTER CWEORTH +16E5 ; [.3819.0020.0002] # RUNIC LETTER STAN +16E6 ; [.381A.0020.0002] # RUNIC LETTER LONG-BRANCH-YR +16E7 ; [.381A.0020.0004][.0000.0111.0004] # RUNIC LETTER SHORT-TWIG-YR +16E8 ; [.381A.0020.0004][.0000.0112.0004] # RUNIC LETTER ICELANDIC-YR +10CC0 ; [.381B.0020.0002] # OLD HUNGARIAN SMALL LETTER A +10C80 ; [.381B.0020.0008] # OLD HUNGARIAN CAPITAL LETTER A +10CC1 ; [.381B.0020.0004][.0000.0111.0004] # OLD HUNGARIAN SMALL LETTER AA +10C81 ; [.381B.0020.000A][.0000.0111.0004] # OLD HUNGARIAN CAPITAL LETTER AA +10CC2 ; [.381C.0020.0002] # OLD HUNGARIAN SMALL LETTER EB +10C82 ; [.381C.0020.0008] # OLD HUNGARIAN CAPITAL LETTER EB +10CC3 ; [.381D.0020.0002] # OLD HUNGARIAN SMALL LETTER AMB +10C83 ; [.381D.0020.0008] # OLD HUNGARIAN CAPITAL LETTER AMB +10CC4 ; [.381E.0020.0002] # OLD HUNGARIAN SMALL LETTER EC +10C84 ; [.381E.0020.0008] # OLD HUNGARIAN CAPITAL LETTER EC +10CC5 ; [.381F.0020.0002] # OLD HUNGARIAN SMALL LETTER ENC +10C85 ; [.381F.0020.0008] # OLD HUNGARIAN CAPITAL LETTER ENC +10CC6 ; [.3820.0020.0002] # OLD HUNGARIAN SMALL LETTER ECS +10C86 ; [.3820.0020.0008] # OLD HUNGARIAN CAPITAL LETTER ECS +10CC7 ; [.3821.0020.0002] # OLD HUNGARIAN SMALL LETTER ED +10C87 ; [.3821.0020.0008] # OLD HUNGARIAN CAPITAL LETTER ED +10CC8 ; [.3822.0020.0002] # OLD HUNGARIAN SMALL LETTER AND +10C88 ; [.3822.0020.0008] # OLD HUNGARIAN CAPITAL LETTER AND +10CC9 ; [.3823.0020.0002] # OLD HUNGARIAN SMALL LETTER E +10C89 ; [.3823.0020.0008] # OLD HUNGARIAN CAPITAL LETTER E +10CCA ; [.3823.0020.0004][.0000.0111.0004] # OLD HUNGARIAN SMALL LETTER CLOSE E +10C8A ; [.3823.0020.000A][.0000.0111.0004] # OLD HUNGARIAN CAPITAL LETTER CLOSE E +10CCB ; [.3823.0020.0004][.0000.0112.0004] # OLD HUNGARIAN SMALL LETTER EE +10C8B ; [.3823.0020.000A][.0000.0112.0004] # OLD HUNGARIAN CAPITAL LETTER EE +10CCC ; [.3824.0020.0002] # OLD HUNGARIAN SMALL LETTER EF +10C8C ; [.3824.0020.0008] # OLD HUNGARIAN CAPITAL LETTER EF +10CCD ; [.3825.0020.0002] # OLD HUNGARIAN SMALL LETTER EG +10C8D ; [.3825.0020.0008] # OLD HUNGARIAN CAPITAL LETTER EG +10CCE ; [.3826.0020.0002] # OLD HUNGARIAN SMALL LETTER EGY +10C8E ; [.3826.0020.0008] # OLD HUNGARIAN CAPITAL LETTER EGY +10CCF ; [.3827.0020.0002] # OLD HUNGARIAN SMALL LETTER EH +10C8F ; [.3827.0020.0008] # OLD HUNGARIAN CAPITAL LETTER EH +10CD0 ; [.3828.0020.0002] # OLD HUNGARIAN SMALL LETTER I +10C90 ; [.3828.0020.0008] # OLD HUNGARIAN CAPITAL LETTER I +10CD1 ; [.3828.0020.0004][.0000.0111.0004] # OLD HUNGARIAN SMALL LETTER II +10C91 ; [.3828.0020.000A][.0000.0111.0004] # OLD HUNGARIAN CAPITAL LETTER II +10CD2 ; [.3829.0020.0002] # OLD HUNGARIAN SMALL LETTER EJ +10C92 ; [.3829.0020.0008] # OLD HUNGARIAN CAPITAL LETTER EJ +10CD3 ; [.382A.0020.0002] # OLD HUNGARIAN SMALL LETTER EK +10C93 ; [.382A.0020.0008] # OLD HUNGARIAN CAPITAL LETTER EK +10CD4 ; [.382B.0020.0002] # OLD HUNGARIAN SMALL LETTER AK +10C94 ; [.382B.0020.0008] # OLD HUNGARIAN CAPITAL LETTER AK +10CD5 ; [.382C.0020.0002] # OLD HUNGARIAN SMALL LETTER UNK +10C95 ; [.382C.0020.0008] # OLD HUNGARIAN CAPITAL LETTER UNK +10CD6 ; [.382D.0020.0002] # OLD HUNGARIAN SMALL LETTER EL +10C96 ; [.382D.0020.0008] # OLD HUNGARIAN CAPITAL LETTER EL +10CD7 ; [.382E.0020.0002] # OLD HUNGARIAN SMALL LETTER ELY +10C97 ; [.382E.0020.0008] # OLD HUNGARIAN CAPITAL LETTER ELY +10CD8 ; [.382F.0020.0002] # OLD HUNGARIAN SMALL LETTER EM +10C98 ; [.382F.0020.0008] # OLD HUNGARIAN CAPITAL LETTER EM +10CD9 ; [.3830.0020.0002] # OLD HUNGARIAN SMALL LETTER EN +10C99 ; [.3830.0020.0008] # OLD HUNGARIAN CAPITAL LETTER EN +10CDA ; [.3831.0020.0002] # OLD HUNGARIAN SMALL LETTER ENY +10C9A ; [.3831.0020.0008] # OLD HUNGARIAN CAPITAL LETTER ENY +10CDB ; [.3832.0020.0002] # OLD HUNGARIAN SMALL LETTER O +10C9B ; [.3832.0020.0008] # OLD HUNGARIAN CAPITAL LETTER O +10CDC ; [.3832.0020.0004][.0000.0111.0004] # OLD HUNGARIAN SMALL LETTER OO +10C9C ; [.3832.0020.000A][.0000.0111.0004] # OLD HUNGARIAN CAPITAL LETTER OO +10CDD ; [.3833.0020.0002] # OLD HUNGARIAN SMALL LETTER NIKOLSBURG OE +10C9D ; [.3833.0020.0008] # OLD HUNGARIAN CAPITAL LETTER NIKOLSBURG OE +10CDE ; [.3833.0020.0004][.0000.0111.0004] # OLD HUNGARIAN SMALL LETTER RUDIMENTA OE +10C9E ; [.3833.0020.000A][.0000.0111.0004] # OLD HUNGARIAN CAPITAL LETTER RUDIMENTA OE +10CDF ; [.3833.0020.0004][.0000.0112.0004] # OLD HUNGARIAN SMALL LETTER OEE +10C9F ; [.3833.0020.000A][.0000.0112.0004] # OLD HUNGARIAN CAPITAL LETTER OEE +10CE0 ; [.3834.0020.0002] # OLD HUNGARIAN SMALL LETTER EP +10CA0 ; [.3834.0020.0008] # OLD HUNGARIAN CAPITAL LETTER EP +10CE1 ; [.3835.0020.0002] # OLD HUNGARIAN SMALL LETTER EMP +10CA1 ; [.3835.0020.0008] # OLD HUNGARIAN CAPITAL LETTER EMP +10CE2 ; [.3836.0020.0002] # OLD HUNGARIAN SMALL LETTER ER +10CA2 ; [.3836.0020.0008] # OLD HUNGARIAN CAPITAL LETTER ER +10CE3 ; [.3836.0020.0004][.0000.0111.0004] # OLD HUNGARIAN SMALL LETTER SHORT ER +10CA3 ; [.3836.0020.000A][.0000.0111.0004] # OLD HUNGARIAN CAPITAL LETTER SHORT ER +10CE4 ; [.3837.0020.0002] # OLD HUNGARIAN SMALL LETTER ES +10CA4 ; [.3837.0020.0008] # OLD HUNGARIAN CAPITAL LETTER ES +10CE5 ; [.3838.0020.0002] # OLD HUNGARIAN SMALL LETTER ESZ +10CA5 ; [.3838.0020.0008] # OLD HUNGARIAN CAPITAL LETTER ESZ +10CE6 ; [.3839.0020.0002] # OLD HUNGARIAN SMALL LETTER ET +10CA6 ; [.3839.0020.0008] # OLD HUNGARIAN CAPITAL LETTER ET +10CE7 ; [.383A.0020.0002] # OLD HUNGARIAN SMALL LETTER ENT +10CA7 ; [.383A.0020.0008] # OLD HUNGARIAN CAPITAL LETTER ENT +10CE8 ; [.383B.0020.0002] # OLD HUNGARIAN SMALL LETTER ETY +10CA8 ; [.383B.0020.0008] # OLD HUNGARIAN CAPITAL LETTER ETY +10CE9 ; [.383C.0020.0002] # OLD HUNGARIAN SMALL LETTER ECH +10CA9 ; [.383C.0020.0008] # OLD HUNGARIAN CAPITAL LETTER ECH +10CEA ; [.383D.0020.0002] # OLD HUNGARIAN SMALL LETTER U +10CAA ; [.383D.0020.0008] # OLD HUNGARIAN CAPITAL LETTER U +10CEB ; [.383D.0020.0004][.0000.0111.0004] # OLD HUNGARIAN SMALL LETTER UU +10CAB ; [.383D.0020.000A][.0000.0111.0004] # OLD HUNGARIAN CAPITAL LETTER UU +10CEC ; [.383E.0020.0002] # OLD HUNGARIAN SMALL LETTER NIKOLSBURG UE +10CAC ; [.383E.0020.0008] # OLD HUNGARIAN CAPITAL LETTER NIKOLSBURG UE +10CED ; [.383E.0020.0004][.0000.0111.0004] # OLD HUNGARIAN SMALL LETTER RUDIMENTA UE +10CAD ; [.383E.0020.000A][.0000.0111.0004] # OLD HUNGARIAN CAPITAL LETTER RUDIMENTA UE +10CEE ; [.383F.0020.0002] # OLD HUNGARIAN SMALL LETTER EV +10CAE ; [.383F.0020.0008] # OLD HUNGARIAN CAPITAL LETTER EV +10CEF ; [.3840.0020.0002] # OLD HUNGARIAN SMALL LETTER EZ +10CAF ; [.3840.0020.0008] # OLD HUNGARIAN CAPITAL LETTER EZ +10CF0 ; [.3841.0020.0002] # OLD HUNGARIAN SMALL LETTER EZS +10CB0 ; [.3841.0020.0008] # OLD HUNGARIAN CAPITAL LETTER EZS +10CF1 ; [.3842.0020.0002] # OLD HUNGARIAN SMALL LETTER ENT-SHAPED SIGN +10CB1 ; [.3842.0020.0008] # OLD HUNGARIAN CAPITAL LETTER ENT-SHAPED SIGN +10CF2 ; [.3843.0020.0002] # OLD HUNGARIAN SMALL LETTER US +10CB2 ; [.3843.0020.0008] # OLD HUNGARIAN CAPITAL LETTER US +10C00 ; [.3844.0020.0002] # OLD TURKIC LETTER ORKHON A +10C01 ; [.3844.0020.0004][.0000.0111.0004] # OLD TURKIC LETTER YENISEI A +10C02 ; [.3845.0020.0002] # OLD TURKIC LETTER YENISEI AE +10C03 ; [.3846.0020.0002] # OLD TURKIC LETTER ORKHON I +10C04 ; [.3846.0020.0004][.0000.0111.0004] # OLD TURKIC LETTER YENISEI I +10C05 ; [.3847.0020.0002] # OLD TURKIC LETTER YENISEI E +10C06 ; [.3848.0020.0002] # OLD TURKIC LETTER ORKHON O +10C07 ; [.3849.0020.0002] # OLD TURKIC LETTER ORKHON OE +10C08 ; [.3849.0020.0004][.0000.0111.0004] # OLD TURKIC LETTER YENISEI OE +10C09 ; [.384A.0020.0002] # OLD TURKIC LETTER ORKHON AB +10C0A ; [.384A.0020.0004][.0000.0111.0004] # OLD TURKIC LETTER YENISEI AB +10C0B ; [.384B.0020.0002] # OLD TURKIC LETTER ORKHON AEB +10C0C ; [.384B.0020.0004][.0000.0111.0004] # OLD TURKIC LETTER YENISEI AEB +10C0D ; [.384C.0020.0002] # OLD TURKIC LETTER ORKHON AG +10C0E ; [.384C.0020.0004][.0000.0111.0004] # OLD TURKIC LETTER YENISEI AG +10C0F ; [.384D.0020.0002] # OLD TURKIC LETTER ORKHON AEG +10C10 ; [.384D.0020.0004][.0000.0111.0004] # OLD TURKIC LETTER YENISEI AEG +10C11 ; [.384E.0020.0002] # OLD TURKIC LETTER ORKHON AD +10C12 ; [.384E.0020.0004][.0000.0111.0004] # OLD TURKIC LETTER YENISEI AD +10C13 ; [.384F.0020.0002] # OLD TURKIC LETTER ORKHON AED +10C14 ; [.3850.0020.0002] # OLD TURKIC LETTER ORKHON EZ +10C15 ; [.3850.0020.0004][.0000.0111.0004] # OLD TURKIC LETTER YENISEI EZ +10C16 ; [.3851.0020.0002] # OLD TURKIC LETTER ORKHON AY +10C17 ; [.3851.0020.0004][.0000.0111.0004] # OLD TURKIC LETTER YENISEI AY +10C18 ; [.3852.0020.0002] # OLD TURKIC LETTER ORKHON AEY +10C19 ; [.3852.0020.0004][.0000.0111.0004] # OLD TURKIC LETTER YENISEI AEY +10C1A ; [.3853.0020.0002] # OLD TURKIC LETTER ORKHON AEK +10C1B ; [.3853.0020.0004][.0000.0111.0004] # OLD TURKIC LETTER YENISEI AEK +10C1C ; [.3854.0020.0002] # OLD TURKIC LETTER ORKHON OEK +10C1D ; [.3854.0020.0004][.0000.0111.0004] # OLD TURKIC LETTER YENISEI OEK +10C1E ; [.3855.0020.0002] # OLD TURKIC LETTER ORKHON AL +10C1F ; [.3855.0020.0004][.0000.0111.0004] # OLD TURKIC LETTER YENISEI AL +10C20 ; [.3856.0020.0002] # OLD TURKIC LETTER ORKHON AEL +10C21 ; [.3857.0020.0002] # OLD TURKIC LETTER ORKHON ELT +10C22 ; [.3858.0020.0002] # OLD TURKIC LETTER ORKHON EM +10C23 ; [.3859.0020.0002] # OLD TURKIC LETTER ORKHON AN +10C24 ; [.385A.0020.0002] # OLD TURKIC LETTER ORKHON AEN +10C25 ; [.385A.0020.0004][.0000.0111.0004] # OLD TURKIC LETTER YENISEI AEN +10C26 ; [.385B.0020.0002] # OLD TURKIC LETTER ORKHON ENT +10C27 ; [.385B.0020.0004][.0000.0111.0004] # OLD TURKIC LETTER YENISEI ENT +10C28 ; [.385C.0020.0002] # OLD TURKIC LETTER ORKHON ENC +10C29 ; [.385C.0020.0004][.0000.0111.0004] # OLD TURKIC LETTER YENISEI ENC +10C2A ; [.385D.0020.0002] # OLD TURKIC LETTER ORKHON ENY +10C2B ; [.385D.0020.0004][.0000.0111.0004] # OLD TURKIC LETTER YENISEI ENY +10C2C ; [.385E.0020.0002] # OLD TURKIC LETTER YENISEI ANG +10C2D ; [.385F.0020.0002] # OLD TURKIC LETTER ORKHON ENG +10C2E ; [.385F.0020.0004][.0000.0111.0004] # OLD TURKIC LETTER YENISEI AENG +10C2F ; [.3860.0020.0002] # OLD TURKIC LETTER ORKHON EP +10C30 ; [.3861.0020.0002] # OLD TURKIC LETTER ORKHON OP +10C31 ; [.3862.0020.0002] # OLD TURKIC LETTER ORKHON IC +10C32 ; [.3863.0020.0002] # OLD TURKIC LETTER ORKHON EC +10C33 ; [.3863.0020.0004][.0000.0111.0004] # OLD TURKIC LETTER YENISEI EC +10C34 ; [.3864.0020.0002] # OLD TURKIC LETTER ORKHON AQ +10C35 ; [.3864.0020.0004][.0000.0111.0004] # OLD TURKIC LETTER YENISEI AQ +10C36 ; [.3865.0020.0002] # OLD TURKIC LETTER ORKHON IQ +10C37 ; [.3865.0020.0004][.0000.0111.0004] # OLD TURKIC LETTER YENISEI IQ +10C38 ; [.3866.0020.0002] # OLD TURKIC LETTER ORKHON OQ +10C39 ; [.3866.0020.0004][.0000.0111.0004] # OLD TURKIC LETTER YENISEI OQ +10C3A ; [.3867.0020.0002] # OLD TURKIC LETTER ORKHON AR +10C3B ; [.3867.0020.0004][.0000.0111.0004] # OLD TURKIC LETTER YENISEI AR +10C3C ; [.3868.0020.0002] # OLD TURKIC LETTER ORKHON AER +10C3D ; [.3869.0020.0002] # OLD TURKIC LETTER ORKHON AS +10C3E ; [.386A.0020.0002] # OLD TURKIC LETTER ORKHON AES +10C3F ; [.386B.0020.0002] # OLD TURKIC LETTER ORKHON ASH +10C40 ; [.386B.0020.0004][.0000.0111.0004] # OLD TURKIC LETTER YENISEI ASH +10C41 ; [.386C.0020.0002] # OLD TURKIC LETTER ORKHON ESH +10C42 ; [.386C.0020.0004][.0000.0111.0004] # OLD TURKIC LETTER YENISEI ESH +10C43 ; [.386D.0020.0002] # OLD TURKIC LETTER ORKHON AT +10C44 ; [.386D.0020.0004][.0000.0111.0004] # OLD TURKIC LETTER YENISEI AT +10C45 ; [.386E.0020.0002] # OLD TURKIC LETTER ORKHON AET +10C46 ; [.386E.0020.0004][.0000.0111.0004] # OLD TURKIC LETTER YENISEI AET +10C47 ; [.386F.0020.0002] # OLD TURKIC LETTER ORKHON OT +10C48 ; [.3870.0020.0002] # OLD TURKIC LETTER ORKHON BASH +A500 ; [.3871.0020.0002] # VAI SYLLABLE EE +A501 ; [.3872.0020.0002] # VAI SYLLABLE EEN +A502 ; [.3873.0020.0002] # VAI SYLLABLE HEE +A503 ; [.3874.0020.0002] # VAI SYLLABLE WEE +A504 ; [.3875.0020.0002] # VAI SYLLABLE WEEN +A505 ; [.3876.0020.0002] # VAI SYLLABLE PEE +A506 ; [.3877.0020.0002] # VAI SYLLABLE BHEE +A507 ; [.3878.0020.0002] # VAI SYLLABLE BEE +A508 ; [.3879.0020.0002] # VAI SYLLABLE MBEE +A509 ; [.387A.0020.0002] # VAI SYLLABLE KPEE +A50A ; [.387B.0020.0002] # VAI SYLLABLE MGBEE +A50B ; [.387C.0020.0002] # VAI SYLLABLE GBEE +A50C ; [.387D.0020.0002] # VAI SYLLABLE FEE +A613 ; [.387D.0020.0004][.397C.0020.0004] # VAI SYMBOL FEENG +A50D ; [.387E.0020.0002] # VAI SYLLABLE VEE +A50E ; [.387F.0020.0002] # VAI SYLLABLE TEE +A50F ; [.3880.0020.0002] # VAI SYLLABLE THEE +A510 ; [.3881.0020.0002] # VAI SYLLABLE DHEE +A511 ; [.3882.0020.0002] # VAI SYLLABLE DHHEE +A512 ; [.3883.0020.0002] # VAI SYLLABLE LEE +A513 ; [.3884.0020.0002] # VAI SYLLABLE REE +A514 ; [.3885.0020.0002] # VAI SYLLABLE DEE +A515 ; [.3886.0020.0002] # VAI SYLLABLE NDEE +A516 ; [.3887.0020.0002] # VAI SYLLABLE SEE +A517 ; [.3888.0020.0002] # VAI SYLLABLE SHEE +A518 ; [.3889.0020.0002] # VAI SYLLABLE ZEE +A519 ; [.388A.0020.0002] # VAI SYLLABLE ZHEE +A51A ; [.388B.0020.0002] # VAI SYLLABLE CEE +A51B ; [.388C.0020.0002] # VAI SYLLABLE JEE +A51C ; [.388D.0020.0002] # VAI SYLLABLE NJEE +A51D ; [.388E.0020.0002] # VAI SYLLABLE YEE +A51E ; [.388F.0020.0002] # VAI SYLLABLE KEE +A614 ; [.388F.0020.0004][.397C.0020.0004] # VAI SYMBOL KEENG +A51F ; [.3890.0020.0002] # VAI SYLLABLE NGGEE +A520 ; [.3891.0020.0002] # VAI SYLLABLE GEE +A521 ; [.3892.0020.0002] # VAI SYLLABLE MEE +A522 ; [.3893.0020.0002] # VAI SYLLABLE NEE +A523 ; [.3894.0020.0002] # VAI SYLLABLE NYEE +A524 ; [.3895.0020.0002] # VAI SYLLABLE I +A525 ; [.3896.0020.0002] # VAI SYLLABLE IN +A526 ; [.3897.0020.0002] # VAI SYLLABLE HI +A527 ; [.3898.0020.0002] # VAI SYLLABLE HIN +A528 ; [.3899.0020.0002] # VAI SYLLABLE WI +A529 ; [.389A.0020.0002] # VAI SYLLABLE WIN +A52A ; [.389B.0020.0002] # VAI SYLLABLE PI +A52B ; [.389C.0020.0002] # VAI SYLLABLE BHI +A52C ; [.389D.0020.0002] # VAI SYLLABLE BI +A52D ; [.389E.0020.0002] # VAI SYLLABLE MBI +A52E ; [.389F.0020.0002] # VAI SYLLABLE KPI +A52F ; [.38A0.0020.0002] # VAI SYLLABLE MGBI +A530 ; [.38A1.0020.0002] # VAI SYLLABLE GBI +A531 ; [.38A2.0020.0002] # VAI SYLLABLE FI +A532 ; [.38A3.0020.0002] # VAI SYLLABLE VI +A533 ; [.38A4.0020.0002] # VAI SYLLABLE TI +A615 ; [.38A4.0020.0004][.397C.0020.0004] # VAI SYMBOL TING +A534 ; [.38A5.0020.0002] # VAI SYLLABLE THI +A535 ; [.38A6.0020.0002] # VAI SYLLABLE DHI +A536 ; [.38A7.0020.0002] # VAI SYLLABLE DHHI +A537 ; [.38A8.0020.0002] # VAI SYLLABLE LI +A538 ; [.38A9.0020.0002] # VAI SYLLABLE RI +A539 ; [.38AA.0020.0002] # VAI SYLLABLE DI +A53A ; [.38AB.0020.0002] # VAI SYLLABLE NDI +A53B ; [.38AC.0020.0002] # VAI SYLLABLE SI +A53C ; [.38AD.0020.0002] # VAI SYLLABLE SHI +A53D ; [.38AE.0020.0002] # VAI SYLLABLE ZI +A53E ; [.38AF.0020.0002] # VAI SYLLABLE ZHI +A53F ; [.38B0.0020.0002] # VAI SYLLABLE CI +A540 ; [.38B1.0020.0002] # VAI SYLLABLE JI +A541 ; [.38B2.0020.0002] # VAI SYLLABLE NJI +A542 ; [.38B3.0020.0002] # VAI SYLLABLE YI +A543 ; [.38B4.0020.0002] # VAI SYLLABLE KI +A544 ; [.38B5.0020.0002] # VAI SYLLABLE NGGI +A545 ; [.38B6.0020.0002] # VAI SYLLABLE GI +A546 ; [.38B7.0020.0002] # VAI SYLLABLE MI +A547 ; [.38B8.0020.0002] # VAI SYLLABLE NI +A616 ; [.38B8.0020.0004][.397D.0020.0004] # VAI SYMBOL NII +A548 ; [.38B9.0020.0002] # VAI SYLLABLE NYI +A549 ; [.38BA.0020.0002] # VAI SYLLABLE A +A54A ; [.38BB.0020.0002] # VAI SYLLABLE AN +A54B ; [.38BC.0020.0002] # VAI SYLLABLE NGAN +A54C ; [.38BD.0020.0002] # VAI SYLLABLE HA +A54D ; [.38BE.0020.0002] # VAI SYLLABLE HAN +A54E ; [.38BF.0020.0002] # VAI SYLLABLE WA +A54F ; [.38C0.0020.0002] # VAI SYLLABLE WAN +A550 ; [.38C1.0020.0002] # VAI SYLLABLE PA +A551 ; [.38C2.0020.0002] # VAI SYLLABLE BHA +A552 ; [.38C3.0020.0002] # VAI SYLLABLE BA +A617 ; [.38C3.0020.0004][.397C.0020.0004] # VAI SYMBOL BANG +A553 ; [.38C4.0020.0002] # VAI SYLLABLE MBA +A554 ; [.38C5.0020.0002] # VAI SYLLABLE KPA +A555 ; [.38C6.0020.0002] # VAI SYLLABLE KPAN +A556 ; [.38C7.0020.0002] # VAI SYLLABLE MGBA +A557 ; [.38C8.0020.0002] # VAI SYLLABLE GBA +A558 ; [.38C9.0020.0002] # VAI SYLLABLE FA +A610 ; [.38C9.0020.0004] # VAI SYLLABLE NDOLE FA +A618 ; [.38C9.0020.0004][.397D.0020.0004] # VAI SYMBOL FAA +A559 ; [.38CA.0020.0002] # VAI SYLLABLE VA +A55A ; [.38CB.0020.0002] # VAI SYLLABLE TA +A619 ; [.38CB.0020.0004][.397D.0020.0004] # VAI SYMBOL TAA +A55B ; [.38CC.0020.0002] # VAI SYLLABLE THA +A55C ; [.38CD.0020.0002] # VAI SYLLABLE DHA +A55D ; [.38CE.0020.0002] # VAI SYLLABLE DHHA +A55E ; [.38CF.0020.0002] # VAI SYLLABLE LA +A55F ; [.38D0.0020.0002] # VAI SYLLABLE RA +A560 ; [.38D1.0020.0002] # VAI SYLLABLE DA +A61A ; [.38D1.0020.0004][.397C.0020.0004] # VAI SYMBOL DANG +A561 ; [.38D2.0020.0002] # VAI SYLLABLE NDA +A562 ; [.38D3.0020.0002] # VAI SYLLABLE SA +A563 ; [.38D4.0020.0002] # VAI SYLLABLE SHA +A564 ; [.38D5.0020.0002] # VAI SYLLABLE ZA +A565 ; [.38D6.0020.0002] # VAI SYLLABLE ZHA +A566 ; [.38D7.0020.0002] # VAI SYLLABLE CA +A567 ; [.38D8.0020.0002] # VAI SYLLABLE JA +A568 ; [.38D9.0020.0002] # VAI SYLLABLE NJA +A569 ; [.38DA.0020.0002] # VAI SYLLABLE YA +A56A ; [.38DB.0020.0002] # VAI SYLLABLE KA +A611 ; [.38DB.0020.0004] # VAI SYLLABLE NDOLE KA +A56B ; [.38DC.0020.0002] # VAI SYLLABLE KAN +A56C ; [.38DD.0020.0002] # VAI SYLLABLE NGGA +A56D ; [.38DE.0020.0002] # VAI SYLLABLE GA +A56E ; [.38DF.0020.0002] # VAI SYLLABLE MA +A62A ; [.38DF.0020.0004] # VAI SYLLABLE NDOLE MA +A56F ; [.38E0.0020.0002] # VAI SYLLABLE NA +A570 ; [.38E1.0020.0002] # VAI SYLLABLE NYA +A571 ; [.38E2.0020.0002] # VAI SYLLABLE OO +A572 ; [.38E3.0020.0002] # VAI SYLLABLE OON +A573 ; [.38E4.0020.0002] # VAI SYLLABLE HOO +A574 ; [.38E5.0020.0002] # VAI SYLLABLE WOO +A575 ; [.38E6.0020.0002] # VAI SYLLABLE WOON +A576 ; [.38E7.0020.0002] # VAI SYLLABLE POO +A577 ; [.38E8.0020.0002] # VAI SYLLABLE BHOO +A578 ; [.38E9.0020.0002] # VAI SYLLABLE BOO +A579 ; [.38EA.0020.0002] # VAI SYLLABLE MBOO +A57A ; [.38EB.0020.0002] # VAI SYLLABLE KPOO +A57B ; [.38EC.0020.0002] # VAI SYLLABLE MGBOO +A57C ; [.38ED.0020.0002] # VAI SYLLABLE GBOO +A57D ; [.38EE.0020.0002] # VAI SYLLABLE FOO +A57E ; [.38EF.0020.0002] # VAI SYLLABLE VOO +A57F ; [.38F0.0020.0002] # VAI SYLLABLE TOO +A580 ; [.38F1.0020.0002] # VAI SYLLABLE THOO +A581 ; [.38F2.0020.0002] # VAI SYLLABLE DHOO +A582 ; [.38F3.0020.0002] # VAI SYLLABLE DHHOO +A583 ; [.38F4.0020.0002] # VAI SYLLABLE LOO +A584 ; [.38F5.0020.0002] # VAI SYLLABLE ROO +A585 ; [.38F6.0020.0002] # VAI SYLLABLE DOO +A61B ; [.38F6.0020.0004][.397C.0020.0004] # VAI SYMBOL DOONG +A586 ; [.38F7.0020.0002] # VAI SYLLABLE NDOO +A587 ; [.38F8.0020.0002] # VAI SYLLABLE SOO +A612 ; [.38F8.0020.0004] # VAI SYLLABLE NDOLE SOO +A588 ; [.38F9.0020.0002] # VAI SYLLABLE SHOO +A589 ; [.38FA.0020.0002] # VAI SYLLABLE ZOO +A58A ; [.38FB.0020.0002] # VAI SYLLABLE ZHOO +A58B ; [.38FC.0020.0002] # VAI SYLLABLE COO +A58C ; [.38FD.0020.0002] # VAI SYLLABLE JOO +A58D ; [.38FE.0020.0002] # VAI SYLLABLE NJOO +A58E ; [.38FF.0020.0002] # VAI SYLLABLE YOO +A58F ; [.3900.0020.0002] # VAI SYLLABLE KOO +A590 ; [.3901.0020.0002] # VAI SYLLABLE NGGOO +A591 ; [.3902.0020.0002] # VAI SYLLABLE GOO +A592 ; [.3903.0020.0002] # VAI SYLLABLE MOO +A593 ; [.3904.0020.0002] # VAI SYLLABLE NOO +A594 ; [.3905.0020.0002] # VAI SYLLABLE NYOO +A595 ; [.3906.0020.0002] # VAI SYLLABLE U +A596 ; [.3907.0020.0002] # VAI SYLLABLE UN +A597 ; [.3908.0020.0002] # VAI SYLLABLE HU +A598 ; [.3909.0020.0002] # VAI SYLLABLE HUN +A599 ; [.390A.0020.0002] # VAI SYLLABLE WU +A59A ; [.390B.0020.0002] # VAI SYLLABLE WUN +A59B ; [.390C.0020.0002] # VAI SYLLABLE PU +A59C ; [.390D.0020.0002] # VAI SYLLABLE BHU +A59D ; [.390E.0020.0002] # VAI SYLLABLE BU +A59E ; [.390F.0020.0002] # VAI SYLLABLE MBU +A59F ; [.3910.0020.0002] # VAI SYLLABLE KPU +A5A0 ; [.3911.0020.0002] # VAI SYLLABLE MGBU +A5A1 ; [.3912.0020.0002] # VAI SYLLABLE GBU +A5A2 ; [.3913.0020.0002] # VAI SYLLABLE FU +A5A3 ; [.3914.0020.0002] # VAI SYLLABLE VU +A5A4 ; [.3915.0020.0002] # VAI SYLLABLE TU +A5A5 ; [.3916.0020.0002] # VAI SYLLABLE THU +A5A6 ; [.3917.0020.0002] # VAI SYLLABLE DHU +A5A7 ; [.3918.0020.0002] # VAI SYLLABLE DHHU +A5A8 ; [.3919.0020.0002] # VAI SYLLABLE LU +A5A9 ; [.391A.0020.0002] # VAI SYLLABLE RU +A5AA ; [.391B.0020.0002] # VAI SYLLABLE DU +A5AB ; [.391C.0020.0002] # VAI SYLLABLE NDU +A5AC ; [.391D.0020.0002] # VAI SYLLABLE SU +A5AD ; [.391E.0020.0002] # VAI SYLLABLE SHU +A5AE ; [.391F.0020.0002] # VAI SYLLABLE ZU +A5AF ; [.3920.0020.0002] # VAI SYLLABLE ZHU +A5B0 ; [.3921.0020.0002] # VAI SYLLABLE CU +A5B1 ; [.3922.0020.0002] # VAI SYLLABLE JU +A5B2 ; [.3923.0020.0002] # VAI SYLLABLE NJU +A5B3 ; [.3924.0020.0002] # VAI SYLLABLE YU +A5B4 ; [.3925.0020.0002] # VAI SYLLABLE KU +A61C ; [.3925.0020.0004][.397C.0020.0004] # VAI SYMBOL KUNG +A5B5 ; [.3926.0020.0002] # VAI SYLLABLE NGGU +A5B6 ; [.3927.0020.0002] # VAI SYLLABLE GU +A5B7 ; [.3928.0020.0002] # VAI SYLLABLE MU +A5B8 ; [.3929.0020.0002] # VAI SYLLABLE NU +A5B9 ; [.392A.0020.0002] # VAI SYLLABLE NYU +A5BA ; [.392B.0020.0002] # VAI SYLLABLE O +A5BB ; [.392C.0020.0002] # VAI SYLLABLE ON +A5BC ; [.392D.0020.0002] # VAI SYLLABLE NGON +A5BD ; [.392E.0020.0002] # VAI SYLLABLE HO +A5BE ; [.392F.0020.0002] # VAI SYLLABLE HON +A5BF ; [.3930.0020.0002] # VAI SYLLABLE WO +A5C0 ; [.3931.0020.0002] # VAI SYLLABLE WON +A5C1 ; [.3932.0020.0002] # VAI SYLLABLE PO +A5C2 ; [.3933.0020.0002] # VAI SYLLABLE BHO +A5C3 ; [.3934.0020.0002] # VAI SYLLABLE BO +A5C4 ; [.3935.0020.0002] # VAI SYLLABLE MBO +A5C5 ; [.3936.0020.0002] # VAI SYLLABLE KPO +A5C6 ; [.3937.0020.0002] # VAI SYLLABLE MGBO +A5C7 ; [.3938.0020.0002] # VAI SYLLABLE GBO +A5C8 ; [.3939.0020.0002] # VAI SYLLABLE GBON +A5C9 ; [.393A.0020.0002] # VAI SYLLABLE FO +A5CA ; [.393B.0020.0002] # VAI SYLLABLE VO +A5CB ; [.393C.0020.0002] # VAI SYLLABLE TO +A61D ; [.393C.0020.0004][.397C.0020.0004] # VAI SYMBOL TONG +A5CC ; [.393D.0020.0002] # VAI SYLLABLE THO +A5CD ; [.393E.0020.0002] # VAI SYLLABLE DHO +A5CE ; [.393F.0020.0002] # VAI SYLLABLE DHHO +A5CF ; [.3940.0020.0002] # VAI SYLLABLE LO +A5D0 ; [.3941.0020.0002] # VAI SYLLABLE RO +A5D1 ; [.3942.0020.0002] # VAI SYLLABLE DO +A62B ; [.3942.0020.0004] # VAI SYLLABLE NDOLE DO +A61E ; [.3942.0020.0004][.397D.0020.0004] # VAI SYMBOL DO-O +A5D2 ; [.3943.0020.0002] # VAI SYLLABLE NDO +A5D3 ; [.3944.0020.0002] # VAI SYLLABLE SO +A5D4 ; [.3945.0020.0002] # VAI SYLLABLE SHO +A5D5 ; [.3946.0020.0002] # VAI SYLLABLE ZO +A5D6 ; [.3947.0020.0002] # VAI SYLLABLE ZHO +A5D7 ; [.3948.0020.0002] # VAI SYLLABLE CO +A5D8 ; [.3949.0020.0002] # VAI SYLLABLE JO +A61F ; [.3949.0020.0004][.397C.0020.0004] # VAI SYMBOL JONG +A5D9 ; [.394A.0020.0002] # VAI SYLLABLE NJO +A5DA ; [.394B.0020.0002] # VAI SYLLABLE YO +A5DB ; [.394C.0020.0002] # VAI SYLLABLE KO +A5DC ; [.394D.0020.0002] # VAI SYLLABLE NGGO +A5DD ; [.394E.0020.0002] # VAI SYLLABLE GO +A5DE ; [.394F.0020.0002] # VAI SYLLABLE MO +A5DF ; [.3950.0020.0002] # VAI SYLLABLE NO +A5E0 ; [.3951.0020.0002] # VAI SYLLABLE NYO +A5E1 ; [.3952.0020.0002] # VAI SYLLABLE E +A5E2 ; [.3953.0020.0002] # VAI SYLLABLE EN +A5E3 ; [.3954.0020.0002] # VAI SYLLABLE NGEN +A5E4 ; [.3955.0020.0002] # VAI SYLLABLE HE +A5E5 ; [.3956.0020.0002] # VAI SYLLABLE HEN +A5E6 ; [.3957.0020.0002] # VAI SYLLABLE WE +A5E7 ; [.3958.0020.0002] # VAI SYLLABLE WEN +A5E8 ; [.3959.0020.0002] # VAI SYLLABLE PE +A5E9 ; [.395A.0020.0002] # VAI SYLLABLE BHE +A5EA ; [.395B.0020.0002] # VAI SYLLABLE BE +A5EB ; [.395C.0020.0002] # VAI SYLLABLE MBE +A5EC ; [.395D.0020.0002] # VAI SYLLABLE KPE +A5ED ; [.395E.0020.0002] # VAI SYLLABLE KPEN +A5EE ; [.395F.0020.0002] # VAI SYLLABLE MGBE +A5EF ; [.3960.0020.0002] # VAI SYLLABLE GBE +A5F0 ; [.3961.0020.0002] # VAI SYLLABLE GBEN +A5F1 ; [.3962.0020.0002] # VAI SYLLABLE FE +A5F2 ; [.3963.0020.0002] # VAI SYLLABLE VE +A5F3 ; [.3964.0020.0002] # VAI SYLLABLE TE +A5F4 ; [.3965.0020.0002] # VAI SYLLABLE THE +A5F5 ; [.3966.0020.0002] # VAI SYLLABLE DHE +A5F6 ; [.3967.0020.0002] # VAI SYLLABLE DHHE +A5F7 ; [.3968.0020.0002] # VAI SYLLABLE LE +A5F8 ; [.3969.0020.0002] # VAI SYLLABLE RE +A5F9 ; [.396A.0020.0002] # VAI SYLLABLE DE +A5FA ; [.396B.0020.0002] # VAI SYLLABLE NDE +A5FB ; [.396C.0020.0002] # VAI SYLLABLE SE +A5FC ; [.396D.0020.0002] # VAI SYLLABLE SHE +A5FD ; [.396E.0020.0002] # VAI SYLLABLE ZE +A5FE ; [.396F.0020.0002] # VAI SYLLABLE ZHE +A5FF ; [.3970.0020.0002] # VAI SYLLABLE CE +A600 ; [.3971.0020.0002] # VAI SYLLABLE JE +A601 ; [.3972.0020.0002] # VAI SYLLABLE NJE +A602 ; [.3973.0020.0002] # VAI SYLLABLE YE +A603 ; [.3974.0020.0002] # VAI SYLLABLE KE +A604 ; [.3975.0020.0002] # VAI SYLLABLE NGGE +A605 ; [.3976.0020.0002] # VAI SYLLABLE NGGEN +A606 ; [.3977.0020.0002] # VAI SYLLABLE GE +A607 ; [.3978.0020.0002] # VAI SYLLABLE GEN +A608 ; [.3979.0020.0002] # VAI SYLLABLE ME +A609 ; [.397A.0020.0002] # VAI SYLLABLE NE +A60A ; [.397B.0020.0002] # VAI SYLLABLE NYE +A60B ; [.397C.0020.0002] # VAI SYLLABLE NG +A60C ; [.397D.0020.0002] # VAI SYLLABLE LENGTHENER +A6A0 ; [.397E.0020.0002] # BAMUM LETTER A +A6A1 ; [.397F.0020.0002] # BAMUM LETTER KA +A6A2 ; [.3980.0020.0002] # BAMUM LETTER U +A6A3 ; [.3981.0020.0002] # BAMUM LETTER KU +A6A4 ; [.3982.0020.0002] # BAMUM LETTER EE +A6A5 ; [.3983.0020.0002] # BAMUM LETTER REE +A6A6 ; [.3984.0020.0002] # BAMUM LETTER TAE +A6A7 ; [.3985.0020.0002] # BAMUM LETTER O +A6A8 ; [.3986.0020.0002] # BAMUM LETTER NYI +A6A9 ; [.3987.0020.0002] # BAMUM LETTER I +A6AA ; [.3988.0020.0002] # BAMUM LETTER LA +A6AB ; [.3989.0020.0002] # BAMUM LETTER PA +A6AC ; [.398A.0020.0002] # BAMUM LETTER RII +A6AD ; [.398B.0020.0002] # BAMUM LETTER RIEE +A6AE ; [.398C.0020.0002] # BAMUM LETTER LEEEE +A6AF ; [.398D.0020.0002] # BAMUM LETTER MEEEE +A6B0 ; [.398E.0020.0002] # BAMUM LETTER TAA +A6B1 ; [.398F.0020.0002] # BAMUM LETTER NDAA +A6B2 ; [.3990.0020.0002] # BAMUM LETTER NJAEM +A6B3 ; [.3991.0020.0002] # BAMUM LETTER M +A6B4 ; [.3992.0020.0002] # BAMUM LETTER SUU +A6B5 ; [.3993.0020.0002] # BAMUM LETTER MU +A6B6 ; [.3994.0020.0002] # BAMUM LETTER SHII +A6B7 ; [.3995.0020.0002] # BAMUM LETTER SI +A6B8 ; [.3996.0020.0002] # BAMUM LETTER SHEUX +A6B9 ; [.3997.0020.0002] # BAMUM LETTER SEUX +A6BA ; [.3998.0020.0002] # BAMUM LETTER KYEE +A6BB ; [.3999.0020.0002] # BAMUM LETTER KET +A6BC ; [.399A.0020.0002] # BAMUM LETTER NUAE +A6BD ; [.399B.0020.0002] # BAMUM LETTER NU +A6BE ; [.399C.0020.0002] # BAMUM LETTER NJUAE +A6BF ; [.399D.0020.0002] # BAMUM LETTER YOQ +A6C0 ; [.399E.0020.0002] # BAMUM LETTER SHU +A6C1 ; [.399F.0020.0002] # BAMUM LETTER YUQ +A6C2 ; [.39A0.0020.0002] # BAMUM LETTER YA +A6C3 ; [.39A1.0020.0002] # BAMUM LETTER NSHA +A6C4 ; [.39A2.0020.0002] # BAMUM LETTER KEUX +A6C5 ; [.39A3.0020.0002] # BAMUM LETTER PEUX +A6C6 ; [.39A4.0020.0002] # BAMUM LETTER NJEE +A6C7 ; [.39A5.0020.0002] # BAMUM LETTER NTEE +A6C8 ; [.39A6.0020.0002] # BAMUM LETTER PUE +A6C9 ; [.39A7.0020.0002] # BAMUM LETTER WUE +A6CA ; [.39A8.0020.0002] # BAMUM LETTER PEE +A6CB ; [.39A9.0020.0002] # BAMUM LETTER FEE +A6CC ; [.39AA.0020.0002] # BAMUM LETTER RU +A6CD ; [.39AB.0020.0002] # BAMUM LETTER LU +A6CE ; [.39AC.0020.0002] # BAMUM LETTER MI +A6CF ; [.39AD.0020.0002] # BAMUM LETTER NI +A6D0 ; [.39AE.0020.0002] # BAMUM LETTER REUX +A6D1 ; [.39AF.0020.0002] # BAMUM LETTER RAE +A6D2 ; [.39B0.0020.0002] # BAMUM LETTER KEN +A6D3 ; [.39B1.0020.0002] # BAMUM LETTER NGKWAEN +A6D4 ; [.39B2.0020.0002] # BAMUM LETTER NGGA +A6D5 ; [.39B3.0020.0002] # BAMUM LETTER NGA +A6D6 ; [.39B4.0020.0002] # BAMUM LETTER SHO +A6D7 ; [.39B5.0020.0002] # BAMUM LETTER PUAE +A6D8 ; [.39B6.0020.0002] # BAMUM LETTER FU +A6D9 ; [.39B7.0020.0002] # BAMUM LETTER FOM +A6DA ; [.39B8.0020.0002] # BAMUM LETTER WA +A6DB ; [.39B9.0020.0002] # BAMUM LETTER NA +A6DC ; [.39BA.0020.0002] # BAMUM LETTER LI +A6DD ; [.39BB.0020.0002] # BAMUM LETTER PI +A6DE ; [.39BC.0020.0002] # BAMUM LETTER LOQ +A6DF ; [.39BD.0020.0002] # BAMUM LETTER KO +A6E0 ; [.39BE.0020.0002] # BAMUM LETTER MBEN +A6E1 ; [.39BF.0020.0002] # BAMUM LETTER REN +A6E2 ; [.39C0.0020.0002] # BAMUM LETTER MEN +A6E3 ; [.39C1.0020.0002] # BAMUM LETTER MA +A6E4 ; [.39C2.0020.0002] # BAMUM LETTER TI +A6E5 ; [.39C3.0020.0002] # BAMUM LETTER KI +A6E6 ; [.39C4.0020.0002] # BAMUM LETTER MO +A6E7 ; [.39C5.0020.0002] # BAMUM LETTER MBAA +A6E8 ; [.39C6.0020.0002] # BAMUM LETTER TET +A6E9 ; [.39C7.0020.0002] # BAMUM LETTER KPA +A6EA ; [.39C8.0020.0002] # BAMUM LETTER TEN +A6EB ; [.39C9.0020.0002] # BAMUM LETTER NTUU +A6EC ; [.39CA.0020.0002] # BAMUM LETTER SAMBA +A6ED ; [.39CB.0020.0002] # BAMUM LETTER FAAMAE +A6EE ; [.39CC.0020.0002] # BAMUM LETTER KOVUU +A6EF ; [.39CD.0020.0002] # BAMUM LETTER KOGHOM +16800 ; [.39CE.0020.0002] # BAMUM LETTER PHASE-A NGKUE MFON +16801 ; [.39CF.0020.0002] # BAMUM LETTER PHASE-A GBIEE FON +16802 ; [.39D0.0020.0002] # BAMUM LETTER PHASE-A PON MFON PIPAEMGBIEE +16803 ; [.39D1.0020.0002] # BAMUM LETTER PHASE-A PON MFON PIPAEMBA +16804 ; [.39D2.0020.0002] # BAMUM LETTER PHASE-A NAA MFON +16805 ; [.39D3.0020.0002] # BAMUM LETTER PHASE-A SHUENSHUET +16806 ; [.39D4.0020.0002] # BAMUM LETTER PHASE-A TITA MFON +16807 ; [.39D5.0020.0002] # BAMUM LETTER PHASE-A NZA MFON +16808 ; [.39D6.0020.0002] # BAMUM LETTER PHASE-A SHINDA PA NJI +16809 ; [.39D7.0020.0002] # BAMUM LETTER PHASE-A PON PA NJI PIPAEMGBIEE +1680A ; [.39D8.0020.0002] # BAMUM LETTER PHASE-A PON PA NJI PIPAEMBA +1680B ; [.39D9.0020.0002] # BAMUM LETTER PHASE-A MAEMBGBIEE +1680C ; [.39DA.0020.0002] # BAMUM LETTER PHASE-A TU MAEMBA +1680D ; [.39DB.0020.0002] # BAMUM LETTER PHASE-A NGANGU +1680E ; [.39DC.0020.0002] # BAMUM LETTER PHASE-A MAEMVEUX +1680F ; [.39DD.0020.0002] # BAMUM LETTER PHASE-A MANSUAE +16810 ; [.39DE.0020.0002] # BAMUM LETTER PHASE-A MVEUAENGAM +16811 ; [.39DF.0020.0002] # BAMUM LETTER PHASE-A SEUNYAM +16812 ; [.39E0.0020.0002] # BAMUM LETTER PHASE-A NTOQPEN +16813 ; [.39E1.0020.0002] # BAMUM LETTER PHASE-A KEUKEUTNDA +16814 ; [.39E2.0020.0002] # BAMUM LETTER PHASE-A NKINDI +16815 ; [.39E3.0020.0002] # BAMUM LETTER PHASE-A SUU +16816 ; [.39E4.0020.0002] # BAMUM LETTER PHASE-A NGKUENZEUM +16817 ; [.39E5.0020.0002] # BAMUM LETTER PHASE-A LAPAQ +16818 ; [.39E6.0020.0002] # BAMUM LETTER PHASE-A LET KUT +16819 ; [.39E7.0020.0002] # BAMUM LETTER PHASE-A NTAP MFAA +1681A ; [.39E8.0020.0002] # BAMUM LETTER PHASE-A MAEKEUP +1681B ; [.39E9.0020.0002] # BAMUM LETTER PHASE-A PASHAE +1681C ; [.39EA.0020.0002] # BAMUM LETTER PHASE-A GHEUAERAE +1681D ; [.39EB.0020.0002] # BAMUM LETTER PHASE-A PAMSHAE +1681E ; [.39EC.0020.0002] # BAMUM LETTER PHASE-A MON NGGEUAET +1681F ; [.39ED.0020.0002] # BAMUM LETTER PHASE-A NZUN MEUT +16820 ; [.39EE.0020.0002] # BAMUM LETTER PHASE-A U YUQ NAE +16821 ; [.39EF.0020.0002] # BAMUM LETTER PHASE-A GHEUAEGHEUAE +16822 ; [.39F0.0020.0002] # BAMUM LETTER PHASE-A NTAP NTAA +16823 ; [.39F1.0020.0002] # BAMUM LETTER PHASE-A SISA +16824 ; [.39F2.0020.0002] # BAMUM LETTER PHASE-A MGBASA +16825 ; [.39F3.0020.0002] # BAMUM LETTER PHASE-A MEUNJOMNDEUQ +16826 ; [.39F4.0020.0002] # BAMUM LETTER PHASE-A MOOMPUQ +16827 ; [.39F5.0020.0002] # BAMUM LETTER PHASE-A KAFA +16828 ; [.39F6.0020.0002] # BAMUM LETTER PHASE-A PA LEERAEWA +16829 ; [.39F7.0020.0002] # BAMUM LETTER PHASE-A NDA LEERAEWA +1682A ; [.39F8.0020.0002] # BAMUM LETTER PHASE-A PET +1682B ; [.39F9.0020.0002] # BAMUM LETTER PHASE-A MAEMKPEN +1682C ; [.39FA.0020.0002] # BAMUM LETTER PHASE-A NIKA +1682D ; [.39FB.0020.0002] # BAMUM LETTER PHASE-A PUP +1682E ; [.39FC.0020.0002] # BAMUM LETTER PHASE-A TUAEP +1682F ; [.39FD.0020.0002] # BAMUM LETTER PHASE-A LUAEP +16830 ; [.39FE.0020.0002] # BAMUM LETTER PHASE-A SONJAM +16831 ; [.39FF.0020.0002] # BAMUM LETTER PHASE-A TEUTEUWEN +16832 ; [.3A00.0020.0002] # BAMUM LETTER PHASE-A MAENYI +16833 ; [.3A01.0020.0002] # BAMUM LETTER PHASE-A KET +16834 ; [.3A02.0020.0002] # BAMUM LETTER PHASE-A NDAANGGEUAET +16835 ; [.3A03.0020.0002] # BAMUM LETTER PHASE-A KUOQ +16836 ; [.3A04.0020.0002] # BAMUM LETTER PHASE-A MOOMEUT +16837 ; [.3A05.0020.0002] # BAMUM LETTER PHASE-A SHUM +16838 ; [.3A06.0020.0002] # BAMUM LETTER PHASE-A LOMMAE +16839 ; [.3A07.0020.0002] # BAMUM LETTER PHASE-A FIRI +1683A ; [.3A08.0020.0002] # BAMUM LETTER PHASE-A ROM +1683B ; [.3A09.0020.0002] # BAMUM LETTER PHASE-A KPOQ +1683C ; [.3A0A.0020.0002] # BAMUM LETTER PHASE-A SOQ +1683D ; [.3A0B.0020.0002] # BAMUM LETTER PHASE-A MAP PIEET +1683E ; [.3A0C.0020.0002] # BAMUM LETTER PHASE-A SHIRAE +1683F ; [.3A0D.0020.0002] # BAMUM LETTER PHASE-A NTAP +16840 ; [.3A0E.0020.0002] # BAMUM LETTER PHASE-A SHOQ NSHUT YUM +16841 ; [.3A0F.0020.0002] # BAMUM LETTER PHASE-A NYIT MONGKEUAEQ +16842 ; [.3A10.0020.0002] # BAMUM LETTER PHASE-A PAARAE +16843 ; [.3A11.0020.0002] # BAMUM LETTER PHASE-A NKAARAE +16844 ; [.3A12.0020.0002] # BAMUM LETTER PHASE-A UNKNOWN +16845 ; [.3A13.0020.0002] # BAMUM LETTER PHASE-A NGGEN +16846 ; [.3A14.0020.0002] # BAMUM LETTER PHASE-A MAESI +16847 ; [.3A15.0020.0002] # BAMUM LETTER PHASE-A NJAM +16848 ; [.3A16.0020.0002] # BAMUM LETTER PHASE-A MBANYI +16849 ; [.3A17.0020.0002] # BAMUM LETTER PHASE-A NYET +1684A ; [.3A18.0020.0002] # BAMUM LETTER PHASE-A TEUAEN +1684B ; [.3A19.0020.0002] # BAMUM LETTER PHASE-A SOT +1684C ; [.3A1A.0020.0002] # BAMUM LETTER PHASE-A PAAM +1684D ; [.3A1B.0020.0002] # BAMUM LETTER PHASE-A NSHIEE +1684E ; [.3A1C.0020.0002] # BAMUM LETTER PHASE-A MAEM +1684F ; [.3A1D.0020.0002] # BAMUM LETTER PHASE-A NYI +16850 ; [.3A1E.0020.0002] # BAMUM LETTER PHASE-A KAQ +16851 ; [.3A1F.0020.0002] # BAMUM LETTER PHASE-A NSHA +16852 ; [.3A20.0020.0002] # BAMUM LETTER PHASE-A VEE +16853 ; [.3A21.0020.0002] # BAMUM LETTER PHASE-A LU +16854 ; [.3A22.0020.0002] # BAMUM LETTER PHASE-A NEN +16855 ; [.3A23.0020.0002] # BAMUM LETTER PHASE-A NAQ +16856 ; [.3A24.0020.0002] # BAMUM LETTER PHASE-A MBAQ +16857 ; [.3A25.0020.0002] # BAMUM LETTER PHASE-B NSHUET +16858 ; [.3A26.0020.0002] # BAMUM LETTER PHASE-B TU MAEMGBIEE +16859 ; [.3A27.0020.0002] # BAMUM LETTER PHASE-B SIEE +1685A ; [.3A28.0020.0002] # BAMUM LETTER PHASE-B SET TU +1685B ; [.3A29.0020.0002] # BAMUM LETTER PHASE-B LOM NTEUM +1685C ; [.3A2A.0020.0002] # BAMUM LETTER PHASE-B MBA MAELEE +1685D ; [.3A2B.0020.0002] # BAMUM LETTER PHASE-B KIEEM +1685E ; [.3A2C.0020.0002] # BAMUM LETTER PHASE-B YEURAE +1685F ; [.3A2D.0020.0002] # BAMUM LETTER PHASE-B MBAARAE +16860 ; [.3A2E.0020.0002] # BAMUM LETTER PHASE-B KAM +16861 ; [.3A2F.0020.0002] # BAMUM LETTER PHASE-B PEESHI +16862 ; [.3A30.0020.0002] # BAMUM LETTER PHASE-B YAFU LEERAEWA +16863 ; [.3A31.0020.0002] # BAMUM LETTER PHASE-B LAM NSHUT NYAM +16864 ; [.3A32.0020.0002] # BAMUM LETTER PHASE-B NTIEE SHEUOQ +16865 ; [.3A33.0020.0002] # BAMUM LETTER PHASE-B NDU NJAA +16866 ; [.3A34.0020.0002] # BAMUM LETTER PHASE-B GHEUGHEUAEM +16867 ; [.3A35.0020.0002] # BAMUM LETTER PHASE-B PIT +16868 ; [.3A36.0020.0002] # BAMUM LETTER PHASE-B TU NSIEE +16869 ; [.3A37.0020.0002] # BAMUM LETTER PHASE-B SHET NJAQ +1686A ; [.3A38.0020.0002] # BAMUM LETTER PHASE-B SHEUAEQTU +1686B ; [.3A39.0020.0002] # BAMUM LETTER PHASE-B MFON TEUAEQ +1686C ; [.3A3A.0020.0002] # BAMUM LETTER PHASE-B MBIT MBAAKET +1686D ; [.3A3B.0020.0002] # BAMUM LETTER PHASE-B NYI NTEUM +1686E ; [.3A3C.0020.0002] # BAMUM LETTER PHASE-B KEUPUQ +1686F ; [.3A3D.0020.0002] # BAMUM LETTER PHASE-B GHEUGHEN +16870 ; [.3A3E.0020.0002] # BAMUM LETTER PHASE-B KEUYEUX +16871 ; [.3A3F.0020.0002] # BAMUM LETTER PHASE-B LAANAE +16872 ; [.3A40.0020.0002] # BAMUM LETTER PHASE-B PARUM +16873 ; [.3A41.0020.0002] # BAMUM LETTER PHASE-B VEUM +16874 ; [.3A42.0020.0002] # BAMUM LETTER PHASE-B NGKINDI MVOP +16875 ; [.3A43.0020.0002] # BAMUM LETTER PHASE-B NGGEU MBU +16876 ; [.3A44.0020.0002] # BAMUM LETTER PHASE-B WUAET +16877 ; [.3A45.0020.0002] # BAMUM LETTER PHASE-B SAKEUAE +16878 ; [.3A46.0020.0002] # BAMUM LETTER PHASE-B TAAM +16879 ; [.3A47.0020.0002] # BAMUM LETTER PHASE-B MEUQ +1687A ; [.3A48.0020.0002] # BAMUM LETTER PHASE-B NGGUOQ +1687B ; [.3A49.0020.0002] # BAMUM LETTER PHASE-B NGGUOQ LARGE +1687C ; [.3A4A.0020.0002] # BAMUM LETTER PHASE-B MFIYAQ +1687D ; [.3A4B.0020.0002] # BAMUM LETTER PHASE-B SUE +1687E ; [.3A4C.0020.0002] # BAMUM LETTER PHASE-B MBEURI +1687F ; [.3A4D.0020.0002] # BAMUM LETTER PHASE-B MONTIEEN +16880 ; [.3A4E.0020.0002] # BAMUM LETTER PHASE-B NYAEMAE +16881 ; [.3A4F.0020.0002] # BAMUM LETTER PHASE-B PUNGAAM +16882 ; [.3A50.0020.0002] # BAMUM LETTER PHASE-B MEUT NGGEET +16883 ; [.3A51.0020.0002] # BAMUM LETTER PHASE-B FEUX +16884 ; [.3A52.0020.0002] # BAMUM LETTER PHASE-B MBUOQ +16885 ; [.3A53.0020.0002] # BAMUM LETTER PHASE-B FEE +16886 ; [.3A54.0020.0002] # BAMUM LETTER PHASE-B KEUAEM +16887 ; [.3A55.0020.0002] # BAMUM LETTER PHASE-B MA NJEUAENA +16888 ; [.3A56.0020.0002] # BAMUM LETTER PHASE-B MA NJUQA +16889 ; [.3A57.0020.0002] # BAMUM LETTER PHASE-B LET +1688A ; [.3A58.0020.0002] # BAMUM LETTER PHASE-B NGGAAM +1688B ; [.3A59.0020.0002] # BAMUM LETTER PHASE-B NSEN +1688C ; [.3A5A.0020.0002] # BAMUM LETTER PHASE-B MA +1688D ; [.3A5B.0020.0002] # BAMUM LETTER PHASE-B KIQ +1688E ; [.3A5C.0020.0002] # BAMUM LETTER PHASE-B NGOM +1688F ; [.3A5D.0020.0002] # BAMUM LETTER PHASE-C NGKUE MAEMBA +16890 ; [.3A5E.0020.0002] # BAMUM LETTER PHASE-C NZA +16891 ; [.3A5F.0020.0002] # BAMUM LETTER PHASE-C YUM +16892 ; [.3A60.0020.0002] # BAMUM LETTER PHASE-C WANGKUOQ +16893 ; [.3A61.0020.0002] # BAMUM LETTER PHASE-C NGGEN +16894 ; [.3A62.0020.0002] # BAMUM LETTER PHASE-C NDEUAEREE +16895 ; [.3A63.0020.0002] # BAMUM LETTER PHASE-C NGKAQ +16896 ; [.3A64.0020.0002] # BAMUM LETTER PHASE-C GHARAE +16897 ; [.3A65.0020.0002] # BAMUM LETTER PHASE-C MBEEKEET +16898 ; [.3A66.0020.0002] # BAMUM LETTER PHASE-C GBAYI +16899 ; [.3A67.0020.0002] # BAMUM LETTER PHASE-C NYIR MKPARAQ MEUN +1689A ; [.3A68.0020.0002] # BAMUM LETTER PHASE-C NTU MBIT +1689B ; [.3A69.0020.0002] # BAMUM LETTER PHASE-C MBEUM +1689C ; [.3A6A.0020.0002] # BAMUM LETTER PHASE-C PIRIEEN +1689D ; [.3A6B.0020.0002] # BAMUM LETTER PHASE-C NDOMBU +1689E ; [.3A6C.0020.0002] # BAMUM LETTER PHASE-C MBAA CABBAGE-TREE +1689F ; [.3A6D.0020.0002] # BAMUM LETTER PHASE-C KEUSHEUAEP +168A0 ; [.3A6E.0020.0002] # BAMUM LETTER PHASE-C GHAP +168A1 ; [.3A6F.0020.0002] # BAMUM LETTER PHASE-C KEUKAQ +168A2 ; [.3A70.0020.0002] # BAMUM LETTER PHASE-C YU MUOMAE +168A3 ; [.3A71.0020.0002] # BAMUM LETTER PHASE-C NZEUM +168A4 ; [.3A72.0020.0002] # BAMUM LETTER PHASE-C MBUE +168A5 ; [.3A73.0020.0002] # BAMUM LETTER PHASE-C NSEUAEN +168A6 ; [.3A74.0020.0002] # BAMUM LETTER PHASE-C MBIT +168A7 ; [.3A75.0020.0002] # BAMUM LETTER PHASE-C YEUQ +168A8 ; [.3A76.0020.0002] # BAMUM LETTER PHASE-C KPARAQ +168A9 ; [.3A77.0020.0002] # BAMUM LETTER PHASE-C KAA +168AA ; [.3A78.0020.0002] # BAMUM LETTER PHASE-C SEUX +168AB ; [.3A79.0020.0002] # BAMUM LETTER PHASE-C NDIDA +168AC ; [.3A7A.0020.0002] # BAMUM LETTER PHASE-C TAASHAE +168AD ; [.3A7B.0020.0002] # BAMUM LETTER PHASE-C NJUEQ +168AE ; [.3A7C.0020.0002] # BAMUM LETTER PHASE-C TITA YUE +168AF ; [.3A7D.0020.0002] # BAMUM LETTER PHASE-C SUAET +168B0 ; [.3A7E.0020.0002] # BAMUM LETTER PHASE-C NGGUAEN NYAM +168B1 ; [.3A7F.0020.0002] # BAMUM LETTER PHASE-C VEUX +168B2 ; [.3A80.0020.0002] # BAMUM LETTER PHASE-C NANSANAQ +168B3 ; [.3A81.0020.0002] # BAMUM LETTER PHASE-C MA KEUAERI +168B4 ; [.3A82.0020.0002] # BAMUM LETTER PHASE-C NTAA +168B5 ; [.3A83.0020.0002] # BAMUM LETTER PHASE-C NGGUON +168B6 ; [.3A84.0020.0002] # BAMUM LETTER PHASE-C LAP +168B7 ; [.3A85.0020.0002] # BAMUM LETTER PHASE-C MBIRIEEN +168B8 ; [.3A86.0020.0002] # BAMUM LETTER PHASE-C MGBASAQ +168B9 ; [.3A87.0020.0002] # BAMUM LETTER PHASE-C NTEUNGBA +168BA ; [.3A88.0020.0002] # BAMUM LETTER PHASE-C TEUTEUX +168BB ; [.3A89.0020.0002] # BAMUM LETTER PHASE-C NGGUM +168BC ; [.3A8A.0020.0002] # BAMUM LETTER PHASE-C FUE +168BD ; [.3A8B.0020.0002] # BAMUM LETTER PHASE-C NDEUT +168BE ; [.3A8C.0020.0002] # BAMUM LETTER PHASE-C NSA +168BF ; [.3A8D.0020.0002] # BAMUM LETTER PHASE-C NSHAQ +168C0 ; [.3A8E.0020.0002] # BAMUM LETTER PHASE-C BUNG +168C1 ; [.3A8F.0020.0002] # BAMUM LETTER PHASE-C VEUAEPEN +168C2 ; [.3A90.0020.0002] # BAMUM LETTER PHASE-C MBERAE +168C3 ; [.3A91.0020.0002] # BAMUM LETTER PHASE-C RU +168C4 ; [.3A92.0020.0002] # BAMUM LETTER PHASE-C NJAEM +168C5 ; [.3A93.0020.0002] # BAMUM LETTER PHASE-C LAM +168C6 ; [.3A94.0020.0002] # BAMUM LETTER PHASE-C TITUAEP +168C7 ; [.3A95.0020.0002] # BAMUM LETTER PHASE-C NSUOT NGOM +168C8 ; [.3A96.0020.0002] # BAMUM LETTER PHASE-C NJEEEE +168C9 ; [.3A97.0020.0002] # BAMUM LETTER PHASE-C KET +168CA ; [.3A98.0020.0002] # BAMUM LETTER PHASE-C NGGU +168CB ; [.3A99.0020.0002] # BAMUM LETTER PHASE-C MAESI +168CC ; [.3A9A.0020.0002] # BAMUM LETTER PHASE-C MBUAEM +168CD ; [.3A9B.0020.0002] # BAMUM LETTER PHASE-C LU +168CE ; [.3A9C.0020.0002] # BAMUM LETTER PHASE-C KUT +168CF ; [.3A9D.0020.0002] # BAMUM LETTER PHASE-C NJAM +168D0 ; [.3A9E.0020.0002] # BAMUM LETTER PHASE-C NGOM +168D1 ; [.3A9F.0020.0002] # BAMUM LETTER PHASE-C WUP +168D2 ; [.3AA0.0020.0002] # BAMUM LETTER PHASE-C NGGUEET +168D3 ; [.3AA1.0020.0002] # BAMUM LETTER PHASE-C NSOM +168D4 ; [.3AA2.0020.0002] # BAMUM LETTER PHASE-C NTEN +168D5 ; [.3AA3.0020.0002] # BAMUM LETTER PHASE-C KUOP NKAARAE +168D6 ; [.3AA4.0020.0002] # BAMUM LETTER PHASE-C NSUN +168D7 ; [.3AA5.0020.0002] # BAMUM LETTER PHASE-C NDAM +168D8 ; [.3AA6.0020.0002] # BAMUM LETTER PHASE-C MA NSIEE +168D9 ; [.3AA7.0020.0002] # BAMUM LETTER PHASE-C YAA +168DA ; [.3AA8.0020.0002] # BAMUM LETTER PHASE-C NDAP +168DB ; [.3AA9.0020.0002] # BAMUM LETTER PHASE-C SHUEQ +168DC ; [.3AAA.0020.0002] # BAMUM LETTER PHASE-C SETFON +168DD ; [.3AAB.0020.0002] # BAMUM LETTER PHASE-C MBI +168DE ; [.3AAC.0020.0002] # BAMUM LETTER PHASE-C MAEMBA +168DF ; [.3AAD.0020.0002] # BAMUM LETTER PHASE-C MBANYI +168E0 ; [.3AAE.0020.0002] # BAMUM LETTER PHASE-C KEUSEUX +168E1 ; [.3AAF.0020.0002] # BAMUM LETTER PHASE-C MBEUX +168E2 ; [.3AB0.0020.0002] # BAMUM LETTER PHASE-C KEUM +168E3 ; [.3AB1.0020.0002] # BAMUM LETTER PHASE-C MBAA PICKET +168E4 ; [.3AB2.0020.0002] # BAMUM LETTER PHASE-C YUWOQ +168E5 ; [.3AB3.0020.0002] # BAMUM LETTER PHASE-C NJEUX +168E6 ; [.3AB4.0020.0002] # BAMUM LETTER PHASE-C MIEE +168E7 ; [.3AB5.0020.0002] # BAMUM LETTER PHASE-C MUAE +168E8 ; [.3AB6.0020.0002] # BAMUM LETTER PHASE-C SHIQ +168E9 ; [.3AB7.0020.0002] # BAMUM LETTER PHASE-C KEN LAW +168EA ; [.3AB8.0020.0002] # BAMUM LETTER PHASE-C KEN FATIGUE +168EB ; [.3AB9.0020.0002] # BAMUM LETTER PHASE-C NGAQ +168EC ; [.3ABA.0020.0002] # BAMUM LETTER PHASE-C NAQ +168ED ; [.3ABB.0020.0002] # BAMUM LETTER PHASE-C LIQ +168EE ; [.3ABC.0020.0002] # BAMUM LETTER PHASE-C PIN +168EF ; [.3ABD.0020.0002] # BAMUM LETTER PHASE-C PEN +168F0 ; [.3ABE.0020.0002] # BAMUM LETTER PHASE-C TET +168F1 ; [.3ABF.0020.0002] # BAMUM LETTER PHASE-D MBUO +168F2 ; [.3AC0.0020.0002] # BAMUM LETTER PHASE-D WAP +168F3 ; [.3AC1.0020.0002] # BAMUM LETTER PHASE-D NJI +168F4 ; [.3AC2.0020.0002] # BAMUM LETTER PHASE-D MFON +168F5 ; [.3AC3.0020.0002] # BAMUM LETTER PHASE-D NJIEE +168F6 ; [.3AC4.0020.0002] # BAMUM LETTER PHASE-D LIEE +168F7 ; [.3AC5.0020.0002] # BAMUM LETTER PHASE-D NJEUT +168F8 ; [.3AC6.0020.0002] # BAMUM LETTER PHASE-D NSHEE +168F9 ; [.3AC7.0020.0002] # BAMUM LETTER PHASE-D NGGAAMAE +168FA ; [.3AC8.0020.0002] # BAMUM LETTER PHASE-D NYAM +168FB ; [.3AC9.0020.0002] # BAMUM LETTER PHASE-D WUAEN +168FC ; [.3ACA.0020.0002] # BAMUM LETTER PHASE-D NGKUN +168FD ; [.3ACB.0020.0002] # BAMUM LETTER PHASE-D SHEE +168FE ; [.3ACC.0020.0002] # BAMUM LETTER PHASE-D NGKAP +168FF ; [.3ACD.0020.0002] # BAMUM LETTER PHASE-D KEUAETMEUN +16900 ; [.3ACE.0020.0002] # BAMUM LETTER PHASE-D TEUT +16901 ; [.3ACF.0020.0002] # BAMUM LETTER PHASE-D SHEUAE +16902 ; [.3AD0.0020.0002] # BAMUM LETTER PHASE-D NJAP +16903 ; [.3AD1.0020.0002] # BAMUM LETTER PHASE-D SUE +16904 ; [.3AD2.0020.0002] # BAMUM LETTER PHASE-D KET +16905 ; [.3AD3.0020.0002] # BAMUM LETTER PHASE-D YAEMMAE +16906 ; [.3AD4.0020.0002] # BAMUM LETTER PHASE-D KUOM +16907 ; [.3AD5.0020.0002] # BAMUM LETTER PHASE-D SAP +16908 ; [.3AD6.0020.0002] # BAMUM LETTER PHASE-D MFEUT +16909 ; [.3AD7.0020.0002] # BAMUM LETTER PHASE-D NDEUX +1690A ; [.3AD8.0020.0002] # BAMUM LETTER PHASE-D MALEERI +1690B ; [.3AD9.0020.0002] # BAMUM LETTER PHASE-D MEUT +1690C ; [.3ADA.0020.0002] # BAMUM LETTER PHASE-D SEUAEQ +1690D ; [.3ADB.0020.0002] # BAMUM LETTER PHASE-D YEN +1690E ; [.3ADC.0020.0002] # BAMUM LETTER PHASE-D NJEUAEM +1690F ; [.3ADD.0020.0002] # BAMUM LETTER PHASE-D KEUOT MBUAE +16910 ; [.3ADE.0020.0002] # BAMUM LETTER PHASE-D NGKEURI +16911 ; [.3ADF.0020.0002] # BAMUM LETTER PHASE-D TU +16912 ; [.3AE0.0020.0002] # BAMUM LETTER PHASE-D GHAA +16913 ; [.3AE1.0020.0002] # BAMUM LETTER PHASE-D NGKYEE +16914 ; [.3AE2.0020.0002] # BAMUM LETTER PHASE-D FEUFEUAET +16915 ; [.3AE3.0020.0002] # BAMUM LETTER PHASE-D NDEE +16916 ; [.3AE4.0020.0002] # BAMUM LETTER PHASE-D MGBOFUM +16917 ; [.3AE5.0020.0002] # BAMUM LETTER PHASE-D LEUAEP +16918 ; [.3AE6.0020.0002] # BAMUM LETTER PHASE-D NDON +16919 ; [.3AE7.0020.0002] # BAMUM LETTER PHASE-D MONI +1691A ; [.3AE8.0020.0002] # BAMUM LETTER PHASE-D MGBEUN +1691B ; [.3AE9.0020.0002] # BAMUM LETTER PHASE-D PUUT +1691C ; [.3AEA.0020.0002] # BAMUM LETTER PHASE-D MGBIEE +1691D ; [.3AEB.0020.0002] # BAMUM LETTER PHASE-D MFO +1691E ; [.3AEC.0020.0002] # BAMUM LETTER PHASE-D LUM +1691F ; [.3AED.0020.0002] # BAMUM LETTER PHASE-D NSIEEP +16920 ; [.3AEE.0020.0002] # BAMUM LETTER PHASE-D MBAA +16921 ; [.3AEF.0020.0002] # BAMUM LETTER PHASE-D KWAET +16922 ; [.3AF0.0020.0002] # BAMUM LETTER PHASE-D NYET +16923 ; [.3AF1.0020.0002] # BAMUM LETTER PHASE-D TEUAEN +16924 ; [.3AF2.0020.0002] # BAMUM LETTER PHASE-D SOT +16925 ; [.3AF3.0020.0002] # BAMUM LETTER PHASE-D YUWOQ +16926 ; [.3AF4.0020.0002] # BAMUM LETTER PHASE-D KEUM +16927 ; [.3AF5.0020.0002] # BAMUM LETTER PHASE-D RAEM +16928 ; [.3AF6.0020.0002] # BAMUM LETTER PHASE-D TEEEE +16929 ; [.3AF7.0020.0002] # BAMUM LETTER PHASE-D NGKEUAEQ +1692A ; [.3AF8.0020.0002] # BAMUM LETTER PHASE-D MFEUAE +1692B ; [.3AF9.0020.0002] # BAMUM LETTER PHASE-D NSIEET +1692C ; [.3AFA.0020.0002] # BAMUM LETTER PHASE-D KEUP +1692D ; [.3AFB.0020.0002] # BAMUM LETTER PHASE-D PIP +1692E ; [.3AFC.0020.0002] # BAMUM LETTER PHASE-D PEUTAE +1692F ; [.3AFD.0020.0002] # BAMUM LETTER PHASE-D NYUE +16930 ; [.3AFE.0020.0002] # BAMUM LETTER PHASE-D LET +16931 ; [.3AFF.0020.0002] # BAMUM LETTER PHASE-D NGGAAM +16932 ; [.3B00.0020.0002] # BAMUM LETTER PHASE-D MFIEE +16933 ; [.3B01.0020.0002] # BAMUM LETTER PHASE-D NGGWAEN +16934 ; [.3B02.0020.0002] # BAMUM LETTER PHASE-D YUOM +16935 ; [.3B03.0020.0002] # BAMUM LETTER PHASE-D PAP +16936 ; [.3B04.0020.0002] # BAMUM LETTER PHASE-D YUOP +16937 ; [.3B05.0020.0002] # BAMUM LETTER PHASE-D NDAM +16938 ; [.3B06.0020.0002] # BAMUM LETTER PHASE-D NTEUM +16939 ; [.3B07.0020.0002] # BAMUM LETTER PHASE-D SUAE +1693A ; [.3B08.0020.0002] # BAMUM LETTER PHASE-D KUN +1693B ; [.3B09.0020.0002] # BAMUM LETTER PHASE-D NGGEUX +1693C ; [.3B0A.0020.0002] # BAMUM LETTER PHASE-D NGKIEE +1693D ; [.3B0B.0020.0002] # BAMUM LETTER PHASE-D TUOT +1693E ; [.3B0C.0020.0002] # BAMUM LETTER PHASE-D MEUN +1693F ; [.3B0D.0020.0002] # BAMUM LETTER PHASE-D KUQ +16940 ; [.3B0E.0020.0002] # BAMUM LETTER PHASE-D NSUM +16941 ; [.3B0F.0020.0002] # BAMUM LETTER PHASE-D TEUN +16942 ; [.3B10.0020.0002] # BAMUM LETTER PHASE-D MAENJET +16943 ; [.3B11.0020.0002] # BAMUM LETTER PHASE-D NGGAP +16944 ; [.3B12.0020.0002] # BAMUM LETTER PHASE-D LEUM +16945 ; [.3B13.0020.0002] # BAMUM LETTER PHASE-D NGGUOM +16946 ; [.3B14.0020.0002] # BAMUM LETTER PHASE-D NSHUT +16947 ; [.3B15.0020.0002] # BAMUM LETTER PHASE-D NJUEQ +16948 ; [.3B16.0020.0002] # BAMUM LETTER PHASE-D GHEUAE +16949 ; [.3B17.0020.0002] # BAMUM LETTER PHASE-D KU +1694A ; [.3B18.0020.0002] # BAMUM LETTER PHASE-D REN OLD +1694B ; [.3B19.0020.0002] # BAMUM LETTER PHASE-D TAE +1694C ; [.3B1A.0020.0002] # BAMUM LETTER PHASE-D TOQ +1694D ; [.3B1B.0020.0002] # BAMUM LETTER PHASE-D NYI +1694E ; [.3B1C.0020.0002] # BAMUM LETTER PHASE-D RII +1694F ; [.3B1D.0020.0002] # BAMUM LETTER PHASE-D LEEEE +16950 ; [.3B1E.0020.0002] # BAMUM LETTER PHASE-D MEEEE +16951 ; [.3B1F.0020.0002] # BAMUM LETTER PHASE-D M +16952 ; [.3B20.0020.0002] # BAMUM LETTER PHASE-D SUU +16953 ; [.3B21.0020.0002] # BAMUM LETTER PHASE-D MU +16954 ; [.3B22.0020.0002] # BAMUM LETTER PHASE-D SHII +16955 ; [.3B23.0020.0002] # BAMUM LETTER PHASE-D SHEUX +16956 ; [.3B24.0020.0002] # BAMUM LETTER PHASE-D KYEE +16957 ; [.3B25.0020.0002] # BAMUM LETTER PHASE-D NU +16958 ; [.3B26.0020.0002] # BAMUM LETTER PHASE-D SHU +16959 ; [.3B27.0020.0002] # BAMUM LETTER PHASE-D NTEE +1695A ; [.3B28.0020.0002] # BAMUM LETTER PHASE-D PEE +1695B ; [.3B29.0020.0002] # BAMUM LETTER PHASE-D NI +1695C ; [.3B2A.0020.0002] # BAMUM LETTER PHASE-D SHOQ +1695D ; [.3B2B.0020.0002] # BAMUM LETTER PHASE-D PUQ +1695E ; [.3B2C.0020.0002] # BAMUM LETTER PHASE-D MVOP +1695F ; [.3B2D.0020.0002] # BAMUM LETTER PHASE-D LOQ +16960 ; [.3B2E.0020.0002] # BAMUM LETTER PHASE-D REN MUCH +16961 ; [.3B2F.0020.0002] # BAMUM LETTER PHASE-D TI +16962 ; [.3B30.0020.0002] # BAMUM LETTER PHASE-D NTUU +16963 ; [.3B31.0020.0002] # BAMUM LETTER PHASE-D MBAA SEVEN +16964 ; [.3B32.0020.0002] # BAMUM LETTER PHASE-D SAQ +16965 ; [.3B33.0020.0002] # BAMUM LETTER PHASE-D FAA +16966 ; [.3B34.0020.0002] # BAMUM LETTER PHASE-E NDAP +16967 ; [.3B35.0020.0002] # BAMUM LETTER PHASE-E TOON +16968 ; [.3B36.0020.0002] # BAMUM LETTER PHASE-E MBEUM +16969 ; [.3B37.0020.0002] # BAMUM LETTER PHASE-E LAP +1696A ; [.3B38.0020.0002] # BAMUM LETTER PHASE-E VOM +1696B ; [.3B39.0020.0002] # BAMUM LETTER PHASE-E LOON +1696C ; [.3B3A.0020.0002] # BAMUM LETTER PHASE-E PAA +1696D ; [.3B3B.0020.0002] # BAMUM LETTER PHASE-E SOM +1696E ; [.3B3C.0020.0002] # BAMUM LETTER PHASE-E RAQ +1696F ; [.3B3D.0020.0002] # BAMUM LETTER PHASE-E NSHUOP +16970 ; [.3B3E.0020.0002] # BAMUM LETTER PHASE-E NDUN +16971 ; [.3B3F.0020.0002] # BAMUM LETTER PHASE-E PUAE +16972 ; [.3B40.0020.0002] # BAMUM LETTER PHASE-E TAM +16973 ; [.3B41.0020.0002] # BAMUM LETTER PHASE-E NGKA +16974 ; [.3B42.0020.0002] # BAMUM LETTER PHASE-E KPEUX +16975 ; [.3B43.0020.0002] # BAMUM LETTER PHASE-E WUO +16976 ; [.3B44.0020.0002] # BAMUM LETTER PHASE-E SEE +16977 ; [.3B45.0020.0002] # BAMUM LETTER PHASE-E NGGEUAET +16978 ; [.3B46.0020.0002] # BAMUM LETTER PHASE-E PAAM +16979 ; [.3B47.0020.0002] # BAMUM LETTER PHASE-E TOO +1697A ; [.3B48.0020.0002] # BAMUM LETTER PHASE-E KUOP +1697B ; [.3B49.0020.0002] # BAMUM LETTER PHASE-E LOM +1697C ; [.3B4A.0020.0002] # BAMUM LETTER PHASE-E NSHIEE +1697D ; [.3B4B.0020.0002] # BAMUM LETTER PHASE-E NGOP +1697E ; [.3B4C.0020.0002] # BAMUM LETTER PHASE-E MAEM +1697F ; [.3B4D.0020.0002] # BAMUM LETTER PHASE-E NGKEUX +16980 ; [.3B4E.0020.0002] # BAMUM LETTER PHASE-E NGOQ +16981 ; [.3B4F.0020.0002] # BAMUM LETTER PHASE-E NSHUE +16982 ; [.3B50.0020.0002] # BAMUM LETTER PHASE-E RIMGBA +16983 ; [.3B51.0020.0002] # BAMUM LETTER PHASE-E NJEUX +16984 ; [.3B52.0020.0002] # BAMUM LETTER PHASE-E PEEM +16985 ; [.3B53.0020.0002] # BAMUM LETTER PHASE-E SAA +16986 ; [.3B54.0020.0002] # BAMUM LETTER PHASE-E NGGURAE +16987 ; [.3B55.0020.0002] # BAMUM LETTER PHASE-E MGBA +16988 ; [.3B56.0020.0002] # BAMUM LETTER PHASE-E GHEUX +16989 ; [.3B57.0020.0002] # BAMUM LETTER PHASE-E NGKEUAEM +1698A ; [.3B58.0020.0002] # BAMUM LETTER PHASE-E NJAEMLI +1698B ; [.3B59.0020.0002] # BAMUM LETTER PHASE-E MAP +1698C ; [.3B5A.0020.0002] # BAMUM LETTER PHASE-E LOOT +1698D ; [.3B5B.0020.0002] # BAMUM LETTER PHASE-E NGGEEEE +1698E ; [.3B5C.0020.0002] # BAMUM LETTER PHASE-E NDIQ +1698F ; [.3B5D.0020.0002] # BAMUM LETTER PHASE-E TAEN NTEUM +16990 ; [.3B5E.0020.0002] # BAMUM LETTER PHASE-E SET +16991 ; [.3B5F.0020.0002] # BAMUM LETTER PHASE-E PUM +16992 ; [.3B60.0020.0002] # BAMUM LETTER PHASE-E NDAA SOFTNESS +16993 ; [.3B61.0020.0002] # BAMUM LETTER PHASE-E NGGUAESHAE NYAM +16994 ; [.3B62.0020.0002] # BAMUM LETTER PHASE-E YIEE +16995 ; [.3B63.0020.0002] # BAMUM LETTER PHASE-E GHEUN +16996 ; [.3B64.0020.0002] # BAMUM LETTER PHASE-E TUAE +16997 ; [.3B65.0020.0002] # BAMUM LETTER PHASE-E YEUAE +16998 ; [.3B66.0020.0002] # BAMUM LETTER PHASE-E PO +16999 ; [.3B67.0020.0002] # BAMUM LETTER PHASE-E TUMAE +1699A ; [.3B68.0020.0002] # BAMUM LETTER PHASE-E KEUAE +1699B ; [.3B69.0020.0002] # BAMUM LETTER PHASE-E SUAEN +1699C ; [.3B6A.0020.0002] # BAMUM LETTER PHASE-E TEUAEQ +1699D ; [.3B6B.0020.0002] # BAMUM LETTER PHASE-E VEUAE +1699E ; [.3B6C.0020.0002] # BAMUM LETTER PHASE-E WEUX +1699F ; [.3B6D.0020.0002] # BAMUM LETTER PHASE-E LAAM +169A0 ; [.3B6E.0020.0002] # BAMUM LETTER PHASE-E PU +169A1 ; [.3B6F.0020.0002] # BAMUM LETTER PHASE-E TAAQ +169A2 ; [.3B70.0020.0002] # BAMUM LETTER PHASE-E GHAAMAE +169A3 ; [.3B71.0020.0002] # BAMUM LETTER PHASE-E NGEUREUT +169A4 ; [.3B72.0020.0002] # BAMUM LETTER PHASE-E SHEUAEQ +169A5 ; [.3B73.0020.0002] # BAMUM LETTER PHASE-E MGBEN +169A6 ; [.3B74.0020.0002] # BAMUM LETTER PHASE-E MBEE +169A7 ; [.3B75.0020.0002] # BAMUM LETTER PHASE-E NZAQ +169A8 ; [.3B76.0020.0002] # BAMUM LETTER PHASE-E NKOM +169A9 ; [.3B77.0020.0002] # BAMUM LETTER PHASE-E GBET +169AA ; [.3B78.0020.0002] # BAMUM LETTER PHASE-E TUM +169AB ; [.3B79.0020.0002] # BAMUM LETTER PHASE-E KUET +169AC ; [.3B7A.0020.0002] # BAMUM LETTER PHASE-E YAP +169AD ; [.3B7B.0020.0002] # BAMUM LETTER PHASE-E NYI CLEAVER +169AE ; [.3B7C.0020.0002] # BAMUM LETTER PHASE-E YIT +169AF ; [.3B7D.0020.0002] # BAMUM LETTER PHASE-E MFEUQ +169B0 ; [.3B7E.0020.0002] # BAMUM LETTER PHASE-E NDIAQ +169B1 ; [.3B7F.0020.0002] # BAMUM LETTER PHASE-E PIEEQ +169B2 ; [.3B80.0020.0002] # BAMUM LETTER PHASE-E YUEQ +169B3 ; [.3B81.0020.0002] # BAMUM LETTER PHASE-E LEUAEM +169B4 ; [.3B82.0020.0002] # BAMUM LETTER PHASE-E FUE +169B5 ; [.3B83.0020.0002] # BAMUM LETTER PHASE-E GBEUX +169B6 ; [.3B84.0020.0002] # BAMUM LETTER PHASE-E NGKUP +169B7 ; [.3B85.0020.0002] # BAMUM LETTER PHASE-E KET +169B8 ; [.3B86.0020.0002] # BAMUM LETTER PHASE-E MAE +169B9 ; [.3B87.0020.0002] # BAMUM LETTER PHASE-E NGKAAMI +169BA ; [.3B88.0020.0002] # BAMUM LETTER PHASE-E GHET +169BB ; [.3B89.0020.0002] # BAMUM LETTER PHASE-E FA +169BC ; [.3B8A.0020.0002] # BAMUM LETTER PHASE-E NTUM +169BD ; [.3B8B.0020.0002] # BAMUM LETTER PHASE-E PEUT +169BE ; [.3B8C.0020.0002] # BAMUM LETTER PHASE-E YEUM +169BF ; [.3B8D.0020.0002] # BAMUM LETTER PHASE-E NGGEUAE +169C0 ; [.3B8E.0020.0002] # BAMUM LETTER PHASE-E NYI BETWEEN +169C1 ; [.3B8F.0020.0002] # BAMUM LETTER PHASE-E NZUQ +169C2 ; [.3B90.0020.0002] # BAMUM LETTER PHASE-E POON +169C3 ; [.3B91.0020.0002] # BAMUM LETTER PHASE-E MIEE +169C4 ; [.3B92.0020.0002] # BAMUM LETTER PHASE-E FUET +169C5 ; [.3B93.0020.0002] # BAMUM LETTER PHASE-E NAE +169C6 ; [.3B94.0020.0002] # BAMUM LETTER PHASE-E MUAE +169C7 ; [.3B95.0020.0002] # BAMUM LETTER PHASE-E GHEUAE +169C8 ; [.3B96.0020.0002] # BAMUM LETTER PHASE-E FU I +169C9 ; [.3B97.0020.0002] # BAMUM LETTER PHASE-E MVI +169CA ; [.3B98.0020.0002] # BAMUM LETTER PHASE-E PUAQ +169CB ; [.3B99.0020.0002] # BAMUM LETTER PHASE-E NGKUM +169CC ; [.3B9A.0020.0002] # BAMUM LETTER PHASE-E KUT +169CD ; [.3B9B.0020.0002] # BAMUM LETTER PHASE-E PIET +169CE ; [.3B9C.0020.0002] # BAMUM LETTER PHASE-E NTAP +169CF ; [.3B9D.0020.0002] # BAMUM LETTER PHASE-E YEUAET +169D0 ; [.3B9E.0020.0002] # BAMUM LETTER PHASE-E NGGUP +169D1 ; [.3B9F.0020.0002] # BAMUM LETTER PHASE-E PA PEOPLE +169D2 ; [.3BA0.0020.0002] # BAMUM LETTER PHASE-E FU CALL +169D3 ; [.3BA1.0020.0002] # BAMUM LETTER PHASE-E FOM +169D4 ; [.3BA2.0020.0002] # BAMUM LETTER PHASE-E NJEE +169D5 ; [.3BA3.0020.0002] # BAMUM LETTER PHASE-E A +169D6 ; [.3BA4.0020.0002] # BAMUM LETTER PHASE-E TOQ +169D7 ; [.3BA5.0020.0002] # BAMUM LETTER PHASE-E O +169D8 ; [.3BA6.0020.0002] # BAMUM LETTER PHASE-E I +169D9 ; [.3BA7.0020.0002] # BAMUM LETTER PHASE-E LAQ +169DA ; [.3BA8.0020.0002] # BAMUM LETTER PHASE-E PA PLURAL +169DB ; [.3BA9.0020.0002] # BAMUM LETTER PHASE-E TAA +169DC ; [.3BAA.0020.0002] # BAMUM LETTER PHASE-E TAQ +169DD ; [.3BAB.0020.0002] # BAMUM LETTER PHASE-E NDAA MY HOUSE +169DE ; [.3BAC.0020.0002] # BAMUM LETTER PHASE-E SHIQ +169DF ; [.3BAD.0020.0002] # BAMUM LETTER PHASE-E YEUX +169E0 ; [.3BAE.0020.0002] # BAMUM LETTER PHASE-E NGUAE +169E1 ; [.3BAF.0020.0002] # BAMUM LETTER PHASE-E YUAEN +169E2 ; [.3BB0.0020.0002] # BAMUM LETTER PHASE-E YOQ SWIMMING +169E3 ; [.3BB1.0020.0002] # BAMUM LETTER PHASE-E YOQ COVER +169E4 ; [.3BB2.0020.0002] # BAMUM LETTER PHASE-E YUQ +169E5 ; [.3BB3.0020.0002] # BAMUM LETTER PHASE-E YUN +169E6 ; [.3BB4.0020.0002] # BAMUM LETTER PHASE-E KEUX +169E7 ; [.3BB5.0020.0002] # BAMUM LETTER PHASE-E PEUX +169E8 ; [.3BB6.0020.0002] # BAMUM LETTER PHASE-E NJEE EPOCH +169E9 ; [.3BB7.0020.0002] # BAMUM LETTER PHASE-E PUE +169EA ; [.3BB8.0020.0002] # BAMUM LETTER PHASE-E WUE +169EB ; [.3BB9.0020.0002] # BAMUM LETTER PHASE-E FEE +169EC ; [.3BBA.0020.0002] # BAMUM LETTER PHASE-E VEE +169ED ; [.3BBB.0020.0002] # BAMUM LETTER PHASE-E LU +169EE ; [.3BBC.0020.0002] # BAMUM LETTER PHASE-E MI +169EF ; [.3BBD.0020.0002] # BAMUM LETTER PHASE-E REUX +169F0 ; [.3BBE.0020.0002] # BAMUM LETTER PHASE-E RAE +169F1 ; [.3BBF.0020.0002] # BAMUM LETTER PHASE-E NGUAET +169F2 ; [.3BC0.0020.0002] # BAMUM LETTER PHASE-E NGA +169F3 ; [.3BC1.0020.0002] # BAMUM LETTER PHASE-E SHO +169F4 ; [.3BC2.0020.0002] # BAMUM LETTER PHASE-E SHOQ +169F5 ; [.3BC3.0020.0002] # BAMUM LETTER PHASE-E FU REMEDY +169F6 ; [.3BC4.0020.0002] # BAMUM LETTER PHASE-E NA +169F7 ; [.3BC5.0020.0002] # BAMUM LETTER PHASE-E PI +169F8 ; [.3BC6.0020.0002] # BAMUM LETTER PHASE-E LOQ +169F9 ; [.3BC7.0020.0002] # BAMUM LETTER PHASE-E KO +169FA ; [.3BC8.0020.0002] # BAMUM LETTER PHASE-E MEN +169FB ; [.3BC9.0020.0002] # BAMUM LETTER PHASE-E MA +169FC ; [.3BCA.0020.0002] # BAMUM LETTER PHASE-E MAQ +169FD ; [.3BCB.0020.0002] # BAMUM LETTER PHASE-E TEU +169FE ; [.3BCC.0020.0002] # BAMUM LETTER PHASE-E KI +169FF ; [.3BCD.0020.0002] # BAMUM LETTER PHASE-E MON +16A00 ; [.3BCE.0020.0002] # BAMUM LETTER PHASE-E TEN +16A01 ; [.3BCF.0020.0002] # BAMUM LETTER PHASE-E FAQ +16A02 ; [.3BD0.0020.0002] # BAMUM LETTER PHASE-E GHOM +16A03 ; [.3BD1.0020.0002] # BAMUM LETTER PHASE-F KA +16A04 ; [.3BD2.0020.0002] # BAMUM LETTER PHASE-F U +16A05 ; [.3BD3.0020.0002] # BAMUM LETTER PHASE-F KU +16A06 ; [.3BD4.0020.0002] # BAMUM LETTER PHASE-F EE +16A07 ; [.3BD5.0020.0002] # BAMUM LETTER PHASE-F REE +16A08 ; [.3BD6.0020.0002] # BAMUM LETTER PHASE-F TAE +16A09 ; [.3BD7.0020.0002] # BAMUM LETTER PHASE-F NYI +16A0A ; [.3BD8.0020.0002] # BAMUM LETTER PHASE-F LA +16A0B ; [.3BD9.0020.0002] # BAMUM LETTER PHASE-F RII +16A0C ; [.3BDA.0020.0002] # BAMUM LETTER PHASE-F RIEE +16A0D ; [.3BDB.0020.0002] # BAMUM LETTER PHASE-F MEEEE +16A0E ; [.3BDC.0020.0002] # BAMUM LETTER PHASE-F TAA +16A0F ; [.3BDD.0020.0002] # BAMUM LETTER PHASE-F NDAA +16A10 ; [.3BDE.0020.0002] # BAMUM LETTER PHASE-F NJAEM +16A11 ; [.3BDF.0020.0002] # BAMUM LETTER PHASE-F M +16A12 ; [.3BE0.0020.0002] # BAMUM LETTER PHASE-F SUU +16A13 ; [.3BE1.0020.0002] # BAMUM LETTER PHASE-F SHII +16A14 ; [.3BE2.0020.0002] # BAMUM LETTER PHASE-F SI +16A15 ; [.3BE3.0020.0002] # BAMUM LETTER PHASE-F SEUX +16A16 ; [.3BE4.0020.0002] # BAMUM LETTER PHASE-F KYEE +16A17 ; [.3BE5.0020.0002] # BAMUM LETTER PHASE-F KET +16A18 ; [.3BE6.0020.0002] # BAMUM LETTER PHASE-F NUAE +16A19 ; [.3BE7.0020.0002] # BAMUM LETTER PHASE-F NU +16A1A ; [.3BE8.0020.0002] # BAMUM LETTER PHASE-F NJUAE +16A1B ; [.3BE9.0020.0002] # BAMUM LETTER PHASE-F YOQ +16A1C ; [.3BEA.0020.0002] # BAMUM LETTER PHASE-F SHU +16A1D ; [.3BEB.0020.0002] # BAMUM LETTER PHASE-F YA +16A1E ; [.3BEC.0020.0002] # BAMUM LETTER PHASE-F NSHA +16A1F ; [.3BED.0020.0002] # BAMUM LETTER PHASE-F PEUX +16A20 ; [.3BEE.0020.0002] # BAMUM LETTER PHASE-F NTEE +16A21 ; [.3BEF.0020.0002] # BAMUM LETTER PHASE-F WUE +16A22 ; [.3BF0.0020.0002] # BAMUM LETTER PHASE-F PEE +16A23 ; [.3BF1.0020.0002] # BAMUM LETTER PHASE-F RU +16A24 ; [.3BF2.0020.0002] # BAMUM LETTER PHASE-F NI +16A25 ; [.3BF3.0020.0002] # BAMUM LETTER PHASE-F REUX +16A26 ; [.3BF4.0020.0002] # BAMUM LETTER PHASE-F KEN +16A27 ; [.3BF5.0020.0002] # BAMUM LETTER PHASE-F NGKWAEN +16A28 ; [.3BF6.0020.0002] # BAMUM LETTER PHASE-F NGGA +16A29 ; [.3BF7.0020.0002] # BAMUM LETTER PHASE-F SHO +16A2A ; [.3BF8.0020.0002] # BAMUM LETTER PHASE-F PUAE +16A2B ; [.3BF9.0020.0002] # BAMUM LETTER PHASE-F FOM +16A2C ; [.3BFA.0020.0002] # BAMUM LETTER PHASE-F WA +16A2D ; [.3BFB.0020.0002] # BAMUM LETTER PHASE-F LI +16A2E ; [.3BFC.0020.0002] # BAMUM LETTER PHASE-F LOQ +16A2F ; [.3BFD.0020.0002] # BAMUM LETTER PHASE-F KO +16A30 ; [.3BFE.0020.0002] # BAMUM LETTER PHASE-F MBEN +16A31 ; [.3BFF.0020.0002] # BAMUM LETTER PHASE-F REN +16A32 ; [.3C00.0020.0002] # BAMUM LETTER PHASE-F MA +16A33 ; [.3C01.0020.0002] # BAMUM LETTER PHASE-F MO +16A34 ; [.3C02.0020.0002] # BAMUM LETTER PHASE-F MBAA +16A35 ; [.3C03.0020.0002] # BAMUM LETTER PHASE-F TET +16A36 ; [.3C04.0020.0002] # BAMUM LETTER PHASE-F KPA +16A37 ; [.3C05.0020.0002] # BAMUM LETTER PHASE-F SAMBA +16A38 ; [.3C06.0020.0002] # BAMUM LETTER PHASE-F VUEQ +16AD0 ; [.3C07.0020.0002] # BASSA VAH LETTER ENNI +16AD1 ; [.3C08.0020.0002] # BASSA VAH LETTER KA +16AD2 ; [.3C09.0020.0002] # BASSA VAH LETTER SE +16AD3 ; [.3C0A.0020.0002] # BASSA VAH LETTER FA +16AD4 ; [.3C0B.0020.0002] # BASSA VAH LETTER MBE +16AD5 ; [.3C0C.0020.0002] # BASSA VAH LETTER YIE +16AD6 ; [.3C0D.0020.0002] # BASSA VAH LETTER GAH +16AD7 ; [.3C0E.0020.0002] # BASSA VAH LETTER DHII +16AD8 ; [.3C0F.0020.0002] # BASSA VAH LETTER KPAH +16AD9 ; [.3C10.0020.0002] # BASSA VAH LETTER JO +16ADA ; [.3C11.0020.0002] # BASSA VAH LETTER HWAH +16ADB ; [.3C12.0020.0002] # BASSA VAH LETTER WA +16ADC ; [.3C13.0020.0002] # BASSA VAH LETTER ZO +16ADD ; [.3C14.0020.0002] # BASSA VAH LETTER GBU +16ADE ; [.3C15.0020.0002] # BASSA VAH LETTER DO +16ADF ; [.3C16.0020.0002] # BASSA VAH LETTER CE +16AE0 ; [.3C17.0020.0002] # BASSA VAH LETTER UWU +16AE1 ; [.3C18.0020.0002] # BASSA VAH LETTER TO +16AE2 ; [.3C19.0020.0002] # BASSA VAH LETTER BA +16AE3 ; [.3C1A.0020.0002] # BASSA VAH LETTER VU +16AE4 ; [.3C1B.0020.0002] # BASSA VAH LETTER YEIN +16AE5 ; [.3C1C.0020.0002] # BASSA VAH LETTER PA +16AE6 ; [.3C1D.0020.0002] # BASSA VAH LETTER WADDA +16AE7 ; [.3C1E.0020.0002] # BASSA VAH LETTER A +16AE8 ; [.3C1F.0020.0002] # BASSA VAH LETTER O +16AE9 ; [.3C20.0020.0002] # BASSA VAH LETTER OO +16AEA ; [.3C21.0020.0002] # BASSA VAH LETTER U +16AEB ; [.3C22.0020.0002] # BASSA VAH LETTER EE +16AEC ; [.3C23.0020.0002] # BASSA VAH LETTER E +16AED ; [.3C24.0020.0002] # BASSA VAH LETTER I +1E800 ; [.3C25.0020.0002] # MENDE KIKAKUI SYLLABLE M001 KI +1E801 ; [.3C26.0020.0002] # MENDE KIKAKUI SYLLABLE M002 KA +1E802 ; [.3C27.0020.0002] # MENDE KIKAKUI SYLLABLE M003 KU +1E803 ; [.3C28.0020.0002] # MENDE KIKAKUI SYLLABLE M065 KEE +1E804 ; [.3C29.0020.0002] # MENDE KIKAKUI SYLLABLE M095 KE +1E805 ; [.3C2A.0020.0002] # MENDE KIKAKUI SYLLABLE M076 KOO +1E806 ; [.3C2B.0020.0002] # MENDE KIKAKUI SYLLABLE M048 KO +1E807 ; [.3C2C.0020.0002] # MENDE KIKAKUI SYLLABLE M179 KUA +1E808 ; [.3C2D.0020.0002] # MENDE KIKAKUI SYLLABLE M004 WI +1E809 ; [.3C2E.0020.0002] # MENDE KIKAKUI SYLLABLE M005 WA +1E80A ; [.3C2F.0020.0002] # MENDE KIKAKUI SYLLABLE M006 WU +1E80B ; [.3C30.0020.0002] # MENDE KIKAKUI SYLLABLE M126 WEE +1E80C ; [.3C31.0020.0002] # MENDE KIKAKUI SYLLABLE M118 WE +1E80D ; [.3C32.0020.0002] # MENDE KIKAKUI SYLLABLE M114 WOO +1E80E ; [.3C33.0020.0002] # MENDE KIKAKUI SYLLABLE M045 WO +1E80F ; [.3C34.0020.0002] # MENDE KIKAKUI SYLLABLE M194 WUI +1E810 ; [.3C35.0020.0002] # MENDE KIKAKUI SYLLABLE M143 WEI +1E811 ; [.3C36.0020.0002] # MENDE KIKAKUI SYLLABLE M061 WVI +1E812 ; [.3C37.0020.0002] # MENDE KIKAKUI SYLLABLE M049 WVA +1E813 ; [.3C38.0020.0002] # MENDE KIKAKUI SYLLABLE M139 WVE +1E814 ; [.3C39.0020.0002] # MENDE KIKAKUI SYLLABLE M007 MIN +1E815 ; [.3C3A.0020.0002] # MENDE KIKAKUI SYLLABLE M008 MAN +1E816 ; [.3C3B.0020.0002] # MENDE KIKAKUI SYLLABLE M009 MUN +1E817 ; [.3C3C.0020.0002] # MENDE KIKAKUI SYLLABLE M059 MEN +1E818 ; [.3C3D.0020.0002] # MENDE KIKAKUI SYLLABLE M094 MON +1E819 ; [.3C3E.0020.0002] # MENDE KIKAKUI SYLLABLE M154 MUAN +1E81A ; [.3C3F.0020.0002] # MENDE KIKAKUI SYLLABLE M189 MUEN +1E81B ; [.3C40.0020.0002] # MENDE KIKAKUI SYLLABLE M010 BI +1E81C ; [.3C41.0020.0002] # MENDE KIKAKUI SYLLABLE M011 BA +1E81D ; [.3C42.0020.0002] # MENDE KIKAKUI SYLLABLE M012 BU +1E81E ; [.3C43.0020.0002] # MENDE KIKAKUI SYLLABLE M150 BEE +1E81F ; [.3C44.0020.0002] # MENDE KIKAKUI SYLLABLE M097 BE +1E820 ; [.3C45.0020.0002] # MENDE KIKAKUI SYLLABLE M103 BOO +1E821 ; [.3C46.0020.0002] # MENDE KIKAKUI SYLLABLE M138 BO +1E822 ; [.3C47.0020.0002] # MENDE KIKAKUI SYLLABLE M013 I +1E823 ; [.3C48.0020.0002] # MENDE KIKAKUI SYLLABLE M014 A +1E824 ; [.3C49.0020.0002] # MENDE KIKAKUI SYLLABLE M015 U +1E825 ; [.3C4A.0020.0002] # MENDE KIKAKUI SYLLABLE M163 EE +1E826 ; [.3C4B.0020.0002] # MENDE KIKAKUI SYLLABLE M100 E +1E827 ; [.3C4C.0020.0002] # MENDE KIKAKUI SYLLABLE M165 OO +1E828 ; [.3C4D.0020.0002] # MENDE KIKAKUI SYLLABLE M147 O +1E829 ; [.3C4E.0020.0002] # MENDE KIKAKUI SYLLABLE M137 EI +1E82A ; [.3C4F.0020.0002] # MENDE KIKAKUI SYLLABLE M131 IN +1E82B ; [.3C50.0020.0002] # MENDE KIKAKUI SYLLABLE M135 IN +1E82C ; [.3C51.0020.0002] # MENDE KIKAKUI SYLLABLE M195 AN +1E82D ; [.3C52.0020.0002] # MENDE KIKAKUI SYLLABLE M178 EN +1E82E ; [.3C53.0020.0002] # MENDE KIKAKUI SYLLABLE M019 SI +1E82F ; [.3C54.0020.0002] # MENDE KIKAKUI SYLLABLE M020 SA +1E830 ; [.3C55.0020.0002] # MENDE KIKAKUI SYLLABLE M021 SU +1E831 ; [.3C56.0020.0002] # MENDE KIKAKUI SYLLABLE M162 SEE +1E832 ; [.3C57.0020.0002] # MENDE KIKAKUI SYLLABLE M116 SE +1E833 ; [.3C58.0020.0002] # MENDE KIKAKUI SYLLABLE M136 SOO +1E834 ; [.3C59.0020.0002] # MENDE KIKAKUI SYLLABLE M079 SO +1E835 ; [.3C5A.0020.0002] # MENDE KIKAKUI SYLLABLE M196 SIA +1E836 ; [.3C5B.0020.0002] # MENDE KIKAKUI SYLLABLE M025 LI +1E837 ; [.3C5C.0020.0002] # MENDE KIKAKUI SYLLABLE M026 LA +1E838 ; [.3C5D.0020.0002] # MENDE KIKAKUI SYLLABLE M027 LU +1E839 ; [.3C5E.0020.0002] # MENDE KIKAKUI SYLLABLE M084 LEE +1E83A ; [.3C5F.0020.0002] # MENDE KIKAKUI SYLLABLE M073 LE +1E83B ; [.3C60.0020.0002] # MENDE KIKAKUI SYLLABLE M054 LOO +1E83C ; [.3C61.0020.0002] # MENDE KIKAKUI SYLLABLE M153 LO +1E83D ; [.3C62.0020.0002] # MENDE KIKAKUI SYLLABLE M110 LONG LE +1E83E ; [.3C63.0020.0002] # MENDE KIKAKUI SYLLABLE M016 DI +1E83F ; [.3C64.0020.0002] # MENDE KIKAKUI SYLLABLE M017 DA +1E840 ; [.3C65.0020.0002] # MENDE KIKAKUI SYLLABLE M018 DU +1E841 ; [.3C66.0020.0002] # MENDE KIKAKUI SYLLABLE M089 DEE +1E842 ; [.3C67.0020.0002] # MENDE KIKAKUI SYLLABLE M180 DOO +1E843 ; [.3C68.0020.0002] # MENDE KIKAKUI SYLLABLE M181 DO +1E844 ; [.3C69.0020.0002] # MENDE KIKAKUI SYLLABLE M022 TI +1E845 ; [.3C6A.0020.0002] # MENDE KIKAKUI SYLLABLE M023 TA +1E846 ; [.3C6B.0020.0002] # MENDE KIKAKUI SYLLABLE M024 TU +1E847 ; [.3C6C.0020.0002] # MENDE KIKAKUI SYLLABLE M091 TEE +1E848 ; [.3C6D.0020.0002] # MENDE KIKAKUI SYLLABLE M055 TE +1E849 ; [.3C6E.0020.0002] # MENDE KIKAKUI SYLLABLE M104 TOO +1E84A ; [.3C6F.0020.0002] # MENDE KIKAKUI SYLLABLE M069 TO +1E84B ; [.3C70.0020.0002] # MENDE KIKAKUI SYLLABLE M028 JI +1E84C ; [.3C71.0020.0002] # MENDE KIKAKUI SYLLABLE M029 JA +1E84D ; [.3C72.0020.0002] # MENDE KIKAKUI SYLLABLE M030 JU +1E84E ; [.3C73.0020.0002] # MENDE KIKAKUI SYLLABLE M157 JEE +1E84F ; [.3C74.0020.0002] # MENDE KIKAKUI SYLLABLE M113 JE +1E850 ; [.3C75.0020.0002] # MENDE KIKAKUI SYLLABLE M160 JOO +1E851 ; [.3C76.0020.0002] # MENDE KIKAKUI SYLLABLE M063 JO +1E852 ; [.3C77.0020.0002] # MENDE KIKAKUI SYLLABLE M175 LONG JO +1E853 ; [.3C78.0020.0002] # MENDE KIKAKUI SYLLABLE M031 YI +1E854 ; [.3C79.0020.0002] # MENDE KIKAKUI SYLLABLE M032 YA +1E855 ; [.3C7A.0020.0002] # MENDE KIKAKUI SYLLABLE M033 YU +1E856 ; [.3C7B.0020.0002] # MENDE KIKAKUI SYLLABLE M109 YEE +1E857 ; [.3C7C.0020.0002] # MENDE KIKAKUI SYLLABLE M080 YE +1E858 ; [.3C7D.0020.0002] # MENDE KIKAKUI SYLLABLE M141 YOO +1E859 ; [.3C7E.0020.0002] # MENDE KIKAKUI SYLLABLE M121 YO +1E85A ; [.3C7F.0020.0002] # MENDE KIKAKUI SYLLABLE M034 FI +1E85B ; [.3C80.0020.0002] # MENDE KIKAKUI SYLLABLE M035 FA +1E85C ; [.3C81.0020.0002] # MENDE KIKAKUI SYLLABLE M036 FU +1E85D ; [.3C82.0020.0002] # MENDE KIKAKUI SYLLABLE M078 FEE +1E85E ; [.3C83.0020.0002] # MENDE KIKAKUI SYLLABLE M075 FE +1E85F ; [.3C84.0020.0002] # MENDE KIKAKUI SYLLABLE M133 FOO +1E860 ; [.3C85.0020.0002] # MENDE KIKAKUI SYLLABLE M088 FO +1E861 ; [.3C86.0020.0002] # MENDE KIKAKUI SYLLABLE M197 FUA +1E862 ; [.3C87.0020.0002] # MENDE KIKAKUI SYLLABLE M101 FAN +1E863 ; [.3C88.0020.0002] # MENDE KIKAKUI SYLLABLE M037 NIN +1E864 ; [.3C89.0020.0002] # MENDE KIKAKUI SYLLABLE M038 NAN +1E865 ; [.3C8A.0020.0002] # MENDE KIKAKUI SYLLABLE M039 NUN +1E866 ; [.3C8B.0020.0002] # MENDE KIKAKUI SYLLABLE M117 NEN +1E867 ; [.3C8C.0020.0002] # MENDE KIKAKUI SYLLABLE M169 NON +1E868 ; [.3C8D.0020.0002] # MENDE KIKAKUI SYLLABLE M176 HI +1E869 ; [.3C8E.0020.0002] # MENDE KIKAKUI SYLLABLE M041 HA +1E86A ; [.3C8F.0020.0002] # MENDE KIKAKUI SYLLABLE M186 HU +1E86B ; [.3C90.0020.0002] # MENDE KIKAKUI SYLLABLE M040 HEE +1E86C ; [.3C91.0020.0002] # MENDE KIKAKUI SYLLABLE M096 HE +1E86D ; [.3C92.0020.0002] # MENDE KIKAKUI SYLLABLE M042 HOO +1E86E ; [.3C93.0020.0002] # MENDE KIKAKUI SYLLABLE M140 HO +1E86F ; [.3C94.0020.0002] # MENDE KIKAKUI SYLLABLE M083 HEEI +1E870 ; [.3C95.0020.0002] # MENDE KIKAKUI SYLLABLE M128 HOOU +1E871 ; [.3C96.0020.0002] # MENDE KIKAKUI SYLLABLE M053 HIN +1E872 ; [.3C97.0020.0002] # MENDE KIKAKUI SYLLABLE M130 HAN +1E873 ; [.3C98.0020.0002] # MENDE KIKAKUI SYLLABLE M087 HUN +1E874 ; [.3C99.0020.0002] # MENDE KIKAKUI SYLLABLE M052 HEN +1E875 ; [.3C9A.0020.0002] # MENDE KIKAKUI SYLLABLE M193 HON +1E876 ; [.3C9B.0020.0002] # MENDE KIKAKUI SYLLABLE M046 HUAN +1E877 ; [.3C9C.0020.0002] # MENDE KIKAKUI SYLLABLE M090 NGGI +1E878 ; [.3C9D.0020.0002] # MENDE KIKAKUI SYLLABLE M043 NGGA +1E879 ; [.3C9E.0020.0002] # MENDE KIKAKUI SYLLABLE M082 NGGU +1E87A ; [.3C9F.0020.0002] # MENDE KIKAKUI SYLLABLE M115 NGGEE +1E87B ; [.3CA0.0020.0002] # MENDE KIKAKUI SYLLABLE M146 NGGE +1E87C ; [.3CA1.0020.0002] # MENDE KIKAKUI SYLLABLE M156 NGGOO +1E87D ; [.3CA2.0020.0002] # MENDE KIKAKUI SYLLABLE M120 NGGO +1E87E ; [.3CA3.0020.0002] # MENDE KIKAKUI SYLLABLE M159 NGGAA +1E87F ; [.3CA4.0020.0002] # MENDE KIKAKUI SYLLABLE M127 NGGUA +1E880 ; [.3CA5.0020.0002] # MENDE KIKAKUI SYLLABLE M086 LONG NGGE +1E881 ; [.3CA6.0020.0002] # MENDE KIKAKUI SYLLABLE M106 LONG NGGOO +1E882 ; [.3CA7.0020.0002] # MENDE KIKAKUI SYLLABLE M183 LONG NGGO +1E883 ; [.3CA8.0020.0002] # MENDE KIKAKUI SYLLABLE M155 GI +1E884 ; [.3CA9.0020.0002] # MENDE KIKAKUI SYLLABLE M111 GA +1E885 ; [.3CAA.0020.0002] # MENDE KIKAKUI SYLLABLE M168 GU +1E886 ; [.3CAB.0020.0002] # MENDE KIKAKUI SYLLABLE M190 GEE +1E887 ; [.3CAC.0020.0002] # MENDE KIKAKUI SYLLABLE M166 GUEI +1E888 ; [.3CAD.0020.0002] # MENDE KIKAKUI SYLLABLE M167 GUAN +1E889 ; [.3CAE.0020.0002] # MENDE KIKAKUI SYLLABLE M184 NGEN +1E88A ; [.3CAF.0020.0002] # MENDE KIKAKUI SYLLABLE M057 NGON +1E88B ; [.3CB0.0020.0002] # MENDE KIKAKUI SYLLABLE M177 NGUAN +1E88C ; [.3CB1.0020.0002] # MENDE KIKAKUI SYLLABLE M068 PI +1E88D ; [.3CB2.0020.0002] # MENDE KIKAKUI SYLLABLE M099 PA +1E88E ; [.3CB3.0020.0002] # MENDE KIKAKUI SYLLABLE M050 PU +1E88F ; [.3CB4.0020.0002] # MENDE KIKAKUI SYLLABLE M081 PEE +1E890 ; [.3CB5.0020.0002] # MENDE KIKAKUI SYLLABLE M051 PE +1E891 ; [.3CB6.0020.0002] # MENDE KIKAKUI SYLLABLE M102 POO +1E892 ; [.3CB7.0020.0002] # MENDE KIKAKUI SYLLABLE M066 PO +1E893 ; [.3CB8.0020.0002] # MENDE KIKAKUI SYLLABLE M145 MBI +1E894 ; [.3CB9.0020.0002] # MENDE KIKAKUI SYLLABLE M062 MBA +1E895 ; [.3CBA.0020.0002] # MENDE KIKAKUI SYLLABLE M122 MBU +1E896 ; [.3CBB.0020.0002] # MENDE KIKAKUI SYLLABLE M047 MBEE +1E897 ; [.3CBC.0020.0002] # MENDE KIKAKUI SYLLABLE M188 MBEE +1E898 ; [.3CBD.0020.0002] # MENDE KIKAKUI SYLLABLE M072 MBE +1E899 ; [.3CBE.0020.0002] # MENDE KIKAKUI SYLLABLE M172 MBOO +1E89A ; [.3CBF.0020.0002] # MENDE KIKAKUI SYLLABLE M174 MBO +1E89B ; [.3CC0.0020.0002] # MENDE KIKAKUI SYLLABLE M187 MBUU +1E89C ; [.3CC1.0020.0002] # MENDE KIKAKUI SYLLABLE M161 LONG MBE +1E89D ; [.3CC2.0020.0002] # MENDE KIKAKUI SYLLABLE M105 LONG MBOO +1E89E ; [.3CC3.0020.0002] # MENDE KIKAKUI SYLLABLE M142 LONG MBO +1E89F ; [.3CC4.0020.0002] # MENDE KIKAKUI SYLLABLE M132 KPI +1E8A0 ; [.3CC5.0020.0002] # MENDE KIKAKUI SYLLABLE M092 KPA +1E8A1 ; [.3CC6.0020.0002] # MENDE KIKAKUI SYLLABLE M074 KPU +1E8A2 ; [.3CC7.0020.0002] # MENDE KIKAKUI SYLLABLE M044 KPEE +1E8A3 ; [.3CC8.0020.0002] # MENDE KIKAKUI SYLLABLE M108 KPE +1E8A4 ; [.3CC9.0020.0002] # MENDE KIKAKUI SYLLABLE M112 KPOO +1E8A5 ; [.3CCA.0020.0002] # MENDE KIKAKUI SYLLABLE M158 KPO +1E8A6 ; [.3CCB.0020.0002] # MENDE KIKAKUI SYLLABLE M124 GBI +1E8A7 ; [.3CCC.0020.0002] # MENDE KIKAKUI SYLLABLE M056 GBA +1E8A8 ; [.3CCD.0020.0002] # MENDE KIKAKUI SYLLABLE M148 GBU +1E8A9 ; [.3CCE.0020.0002] # MENDE KIKAKUI SYLLABLE M093 GBEE +1E8AA ; [.3CCF.0020.0002] # MENDE KIKAKUI SYLLABLE M107 GBE +1E8AB ; [.3CD0.0020.0002] # MENDE KIKAKUI SYLLABLE M071 GBOO +1E8AC ; [.3CD1.0020.0002] # MENDE KIKAKUI SYLLABLE M070 GBO +1E8AD ; [.3CD2.0020.0002] # MENDE KIKAKUI SYLLABLE M171 RA +1E8AE ; [.3CD3.0020.0002] # MENDE KIKAKUI SYLLABLE M123 NDI +1E8AF ; [.3CD4.0020.0002] # MENDE KIKAKUI SYLLABLE M129 NDA +1E8B0 ; [.3CD5.0020.0002] # MENDE KIKAKUI SYLLABLE M125 NDU +1E8B1 ; [.3CD6.0020.0002] # MENDE KIKAKUI SYLLABLE M191 NDEE +1E8B2 ; [.3CD7.0020.0002] # MENDE KIKAKUI SYLLABLE M119 NDE +1E8B3 ; [.3CD8.0020.0002] # MENDE KIKAKUI SYLLABLE M067 NDOO +1E8B4 ; [.3CD9.0020.0002] # MENDE KIKAKUI SYLLABLE M064 NDO +1E8B5 ; [.3CDA.0020.0002] # MENDE KIKAKUI SYLLABLE M152 NJA +1E8B6 ; [.3CDB.0020.0002] # MENDE KIKAKUI SYLLABLE M192 NJU +1E8B7 ; [.3CDC.0020.0002] # MENDE KIKAKUI SYLLABLE M149 NJEE +1E8B8 ; [.3CDD.0020.0002] # MENDE KIKAKUI SYLLABLE M134 NJOO +1E8B9 ; [.3CDE.0020.0002] # MENDE KIKAKUI SYLLABLE M182 VI +1E8BA ; [.3CDF.0020.0002] # MENDE KIKAKUI SYLLABLE M185 VA +1E8BB ; [.3CE0.0020.0002] # MENDE KIKAKUI SYLLABLE M151 VU +1E8BC ; [.3CE1.0020.0002] # MENDE KIKAKUI SYLLABLE M173 VEE +1E8BD ; [.3CE2.0020.0002] # MENDE KIKAKUI SYLLABLE M085 VE +1E8BE ; [.3CE3.0020.0002] # MENDE KIKAKUI SYLLABLE M144 VOO +1E8BF ; [.3CE4.0020.0002] # MENDE KIKAKUI SYLLABLE M077 VO +1E8C0 ; [.3CE5.0020.0002] # MENDE KIKAKUI SYLLABLE M164 NYIN +1E8C1 ; [.3CE6.0020.0002] # MENDE KIKAKUI SYLLABLE M058 NYAN +1E8C2 ; [.3CE7.0020.0002] # MENDE KIKAKUI SYLLABLE M170 NYUN +1E8C3 ; [.3CE8.0020.0002] # MENDE KIKAKUI SYLLABLE M098 NYEN +1E8C4 ; [.3CE9.0020.0002] # MENDE KIKAKUI SYLLABLE M060 NYON +1E922 ; [.3CEA.0020.0002] # ADLAM SMALL LETTER ALIF +1E900 ; [.3CEA.0020.0008] # ADLAM CAPITAL LETTER ALIF +1E923 ; [.3CEB.0020.0002] # ADLAM SMALL LETTER DAALI +1E901 ; [.3CEB.0020.0008] # ADLAM CAPITAL LETTER DAALI +1E924 ; [.3CEC.0020.0002] # ADLAM SMALL LETTER LAAM +1E902 ; [.3CEC.0020.0008] # ADLAM CAPITAL LETTER LAAM +1E925 ; [.3CED.0020.0002] # ADLAM SMALL LETTER MIIM +1E903 ; [.3CED.0020.0008] # ADLAM CAPITAL LETTER MIIM +1E926 ; [.3CEE.0020.0002] # ADLAM SMALL LETTER BA +1E904 ; [.3CEE.0020.0008] # ADLAM CAPITAL LETTER BA +1E927 ; [.3CEF.0020.0002] # ADLAM SMALL LETTER SINNYIIYHE +1E905 ; [.3CEF.0020.0008] # ADLAM CAPITAL LETTER SINNYIIYHE +1E928 ; [.3CF0.0020.0002] # ADLAM SMALL LETTER PE +1E906 ; [.3CF0.0020.0008] # ADLAM CAPITAL LETTER PE +1E929 ; [.3CF1.0020.0002] # ADLAM SMALL LETTER BHE +1E907 ; [.3CF1.0020.0008] # ADLAM CAPITAL LETTER BHE +1E92A ; [.3CF2.0020.0002] # ADLAM SMALL LETTER RA +1E908 ; [.3CF2.0020.0008] # ADLAM CAPITAL LETTER RA +1E92B ; [.3CF3.0020.0002] # ADLAM SMALL LETTER E +1E909 ; [.3CF3.0020.0008] # ADLAM CAPITAL LETTER E +1E92C ; [.3CF4.0020.0002] # ADLAM SMALL LETTER FA +1E90A ; [.3CF4.0020.0008] # ADLAM CAPITAL LETTER FA +1E92D ; [.3CF5.0020.0002] # ADLAM SMALL LETTER I +1E90B ; [.3CF5.0020.0008] # ADLAM CAPITAL LETTER I +1E92E ; [.3CF6.0020.0002] # ADLAM SMALL LETTER O +1E90C ; [.3CF6.0020.0008] # ADLAM CAPITAL LETTER O +1E92F ; [.3CF7.0020.0002] # ADLAM SMALL LETTER DHA +1E90D ; [.3CF7.0020.0008] # ADLAM CAPITAL LETTER DHA +1E930 ; [.3CF8.0020.0002] # ADLAM SMALL LETTER YHE +1E90E ; [.3CF8.0020.0008] # ADLAM CAPITAL LETTER YHE +1E931 ; [.3CF9.0020.0002] # ADLAM SMALL LETTER WAW +1E90F ; [.3CF9.0020.0008] # ADLAM CAPITAL LETTER WAW +1E932 ; [.3CFA.0020.0002] # ADLAM SMALL LETTER NUN +1E910 ; [.3CFA.0020.0008] # ADLAM CAPITAL LETTER NUN +1E933 ; [.3CFB.0020.0002] # ADLAM SMALL LETTER KAF +1E911 ; [.3CFB.0020.0008] # ADLAM CAPITAL LETTER KAF +1E934 ; [.3CFC.0020.0002] # ADLAM SMALL LETTER YA +1E912 ; [.3CFC.0020.0008] # ADLAM CAPITAL LETTER YA +1E935 ; [.3CFD.0020.0002] # ADLAM SMALL LETTER U +1E913 ; [.3CFD.0020.0008] # ADLAM CAPITAL LETTER U +1E936 ; [.3CFE.0020.0002] # ADLAM SMALL LETTER JIIM +1E914 ; [.3CFE.0020.0008] # ADLAM CAPITAL LETTER JIIM +1E937 ; [.3CFF.0020.0002] # ADLAM SMALL LETTER CHI +1E915 ; [.3CFF.0020.0008] # ADLAM CAPITAL LETTER CHI +1E938 ; [.3D00.0020.0002] # ADLAM SMALL LETTER HA +1E916 ; [.3D00.0020.0008] # ADLAM CAPITAL LETTER HA +1E939 ; [.3D01.0020.0002] # ADLAM SMALL LETTER QAAF +1E917 ; [.3D01.0020.0008] # ADLAM CAPITAL LETTER QAAF +1E93A ; [.3D02.0020.0002] # ADLAM SMALL LETTER GA +1E918 ; [.3D02.0020.0008] # ADLAM CAPITAL LETTER GA +1E93B ; [.3D03.0020.0002] # ADLAM SMALL LETTER NYA +1E919 ; [.3D03.0020.0008] # ADLAM CAPITAL LETTER NYA +1E93C ; [.3D04.0020.0002] # ADLAM SMALL LETTER TU +1E91A ; [.3D04.0020.0008] # ADLAM CAPITAL LETTER TU +1E93D ; [.3D05.0020.0002] # ADLAM SMALL LETTER NHA +1E91B ; [.3D05.0020.0008] # ADLAM CAPITAL LETTER NHA +1E93E ; [.3D06.0020.0002] # ADLAM SMALL LETTER VA +1E91C ; [.3D06.0020.0008] # ADLAM CAPITAL LETTER VA +1E93F ; [.3D07.0020.0002] # ADLAM SMALL LETTER KHA +1E91D ; [.3D07.0020.0008] # ADLAM CAPITAL LETTER KHA +1E940 ; [.3D08.0020.0002] # ADLAM SMALL LETTER GBE +1E91E ; [.3D08.0020.0008] # ADLAM CAPITAL LETTER GBE +1E941 ; [.3D09.0020.0002] # ADLAM SMALL LETTER ZAL +1E91F ; [.3D09.0020.0008] # ADLAM CAPITAL LETTER ZAL +1E942 ; [.3D0A.0020.0002] # ADLAM SMALL LETTER KPO +1E920 ; [.3D0A.0020.0008] # ADLAM CAPITAL LETTER KPO +1E943 ; [.3D0B.0020.0002] # ADLAM SMALL LETTER SHA +1E921 ; [.3D0B.0020.0008] # ADLAM CAPITAL LETTER SHA +1100 ; [.3D0C.0020.0002] # HANGUL CHOSEONG KIYEOK +3131 ; [.3D0C.0020.0004] # HANGUL LETTER KIYEOK +3200 ; [*0318.0020.0004][.3D0C.0020.0004][*0319.0020.0004] # PARENTHESIZED HANGUL KIYEOK +3260 ; [.3D0C.0020.0006] # CIRCLED HANGUL KIYEOK +FFA1 ; [.3D0C.0020.0012] # HALFWIDTH HANGUL LETTER KIYEOK +320E ; [*0318.0020.0004][.3D0C.0020.0004][.3D8A.0020.0004][*0319.0020.0004] # PARENTHESIZED HANGUL KIYEOK A +326E ; [.3D0C.0020.0006][.3D8A.0020.0006] # CIRCLED HANGUL KIYEOK A +1101 ; [.3D0D.0020.0002] # HANGUL CHOSEONG SSANGKIYEOK +3132 ; [.3D0D.0020.0004] # HANGUL LETTER SSANGKIYEOK +FFA2 ; [.3D0D.0020.0012] # HALFWIDTH HANGUL LETTER SSANGKIYEOK +1102 ; [.3D0E.0020.0002] # HANGUL CHOSEONG NIEUN +3134 ; [.3D0E.0020.0004] # HANGUL LETTER NIEUN +3201 ; [*0318.0020.0004][.3D0E.0020.0004][*0319.0020.0004] # PARENTHESIZED HANGUL NIEUN +3261 ; [.3D0E.0020.0006] # CIRCLED HANGUL NIEUN +FFA4 ; [.3D0E.0020.0012] # HALFWIDTH HANGUL LETTER NIEUN +320F ; [*0318.0020.0004][.3D0E.0020.0004][.3D8A.0020.0004][*0319.0020.0004] # PARENTHESIZED HANGUL NIEUN A +326F ; [.3D0E.0020.0006][.3D8A.0020.0006] # CIRCLED HANGUL NIEUN A +1103 ; [.3D0F.0020.0002] # HANGUL CHOSEONG TIKEUT +3137 ; [.3D0F.0020.0004] # HANGUL LETTER TIKEUT +3202 ; [*0318.0020.0004][.3D0F.0020.0004][*0319.0020.0004] # PARENTHESIZED HANGUL TIKEUT +3262 ; [.3D0F.0020.0006] # CIRCLED HANGUL TIKEUT +FFA7 ; [.3D0F.0020.0012] # HALFWIDTH HANGUL LETTER TIKEUT +3210 ; [*0318.0020.0004][.3D0F.0020.0004][.3D8A.0020.0004][*0319.0020.0004] # PARENTHESIZED HANGUL TIKEUT A +3270 ; [.3D0F.0020.0006][.3D8A.0020.0006] # CIRCLED HANGUL TIKEUT A +1104 ; [.3D10.0020.0002] # HANGUL CHOSEONG SSANGTIKEUT +3138 ; [.3D10.0020.0004] # HANGUL LETTER SSANGTIKEUT +FFA8 ; [.3D10.0020.0012] # HALFWIDTH HANGUL LETTER SSANGTIKEUT +1105 ; [.3D11.0020.0002] # HANGUL CHOSEONG RIEUL +3139 ; [.3D11.0020.0004] # HANGUL LETTER RIEUL +3203 ; [*0318.0020.0004][.3D11.0020.0004][*0319.0020.0004] # PARENTHESIZED HANGUL RIEUL +3263 ; [.3D11.0020.0006] # CIRCLED HANGUL RIEUL +FFA9 ; [.3D11.0020.0012] # HALFWIDTH HANGUL LETTER RIEUL +3211 ; [*0318.0020.0004][.3D11.0020.0004][.3D8A.0020.0004][*0319.0020.0004] # PARENTHESIZED HANGUL RIEUL A +3271 ; [.3D11.0020.0006][.3D8A.0020.0006] # CIRCLED HANGUL RIEUL A +1106 ; [.3D12.0020.0002] # HANGUL CHOSEONG MIEUM +3141 ; [.3D12.0020.0004] # HANGUL LETTER MIEUM +3204 ; [*0318.0020.0004][.3D12.0020.0004][*0319.0020.0004] # PARENTHESIZED HANGUL MIEUM +3264 ; [.3D12.0020.0006] # CIRCLED HANGUL MIEUM +FFB1 ; [.3D12.0020.0012] # HALFWIDTH HANGUL LETTER MIEUM +3212 ; [*0318.0020.0004][.3D12.0020.0004][.3D8A.0020.0004][*0319.0020.0004] # PARENTHESIZED HANGUL MIEUM A +3272 ; [.3D12.0020.0006][.3D8A.0020.0006] # CIRCLED HANGUL MIEUM A +1107 ; [.3D13.0020.0002] # HANGUL CHOSEONG PIEUP +3142 ; [.3D13.0020.0004] # HANGUL LETTER PIEUP +3205 ; [*0318.0020.0004][.3D13.0020.0004][*0319.0020.0004] # PARENTHESIZED HANGUL PIEUP +3265 ; [.3D13.0020.0006] # CIRCLED HANGUL PIEUP +FFB2 ; [.3D13.0020.0012] # HALFWIDTH HANGUL LETTER PIEUP +3213 ; [*0318.0020.0004][.3D13.0020.0004][.3D8A.0020.0004][*0319.0020.0004] # PARENTHESIZED HANGUL PIEUP A +3273 ; [.3D13.0020.0006][.3D8A.0020.0006] # CIRCLED HANGUL PIEUP A +1108 ; [.3D14.0020.0002] # HANGUL CHOSEONG SSANGPIEUP +3143 ; [.3D14.0020.0004] # HANGUL LETTER SSANGPIEUP +FFB3 ; [.3D14.0020.0012] # HALFWIDTH HANGUL LETTER SSANGPIEUP +1109 ; [.3D15.0020.0002] # HANGUL CHOSEONG SIOS +3145 ; [.3D15.0020.0004] # HANGUL LETTER SIOS +3206 ; [*0318.0020.0004][.3D15.0020.0004][*0319.0020.0004] # PARENTHESIZED HANGUL SIOS +3266 ; [.3D15.0020.0006] # CIRCLED HANGUL SIOS +FFB5 ; [.3D15.0020.0012] # HALFWIDTH HANGUL LETTER SIOS +3214 ; [*0318.0020.0004][.3D15.0020.0004][.3D8A.0020.0004][*0319.0020.0004] # PARENTHESIZED HANGUL SIOS A +3274 ; [.3D15.0020.0006][.3D8A.0020.0006] # CIRCLED HANGUL SIOS A +110A ; [.3D16.0020.0002] # HANGUL CHOSEONG SSANGSIOS +3146 ; [.3D16.0020.0004] # HANGUL LETTER SSANGSIOS +FFB6 ; [.3D16.0020.0012] # HALFWIDTH HANGUL LETTER SSANGSIOS +110B ; [.3D17.0020.0002] # HANGUL CHOSEONG IEUNG +3147 ; [.3D17.0020.0004] # HANGUL LETTER IEUNG +3207 ; [*0318.0020.0004][.3D17.0020.0004][*0319.0020.0004] # PARENTHESIZED HANGUL IEUNG +3267 ; [.3D17.0020.0006] # CIRCLED HANGUL IEUNG +FFB7 ; [.3D17.0020.0012] # HALFWIDTH HANGUL LETTER IEUNG +3215 ; [*0318.0020.0004][.3D17.0020.0004][.3D8A.0020.0004][*0319.0020.0004] # PARENTHESIZED HANGUL IEUNG A +3275 ; [.3D17.0020.0006][.3D8A.0020.0006] # CIRCLED HANGUL IEUNG A +321D ; [*0318.0020.0004][.3D17.0020.0004][.3D92.0020.0004][.3D18.0020.0004][.3D8E.0020.0004][.3DEB.0020.0004][*0319.0020.0004] # PARENTHESIZED KOREAN CHARACTER OJEON +321E ; [*0318.0020.0004][.3D17.0020.0004][.3D92.0020.0004][.3D1E.0020.0004][.3D97.0020.0004][*0319.0020.0004] # PARENTHESIZED KOREAN CHARACTER O HU +327E ; [.3D17.0020.0006][.3D97.0020.0006] # CIRCLED HANGUL IEUNG U +110C ; [.3D18.0020.0002] # HANGUL CHOSEONG CIEUC +3148 ; [.3D18.0020.0004] # HANGUL LETTER CIEUC +3208 ; [*0318.0020.0004][.3D18.0020.0004][*0319.0020.0004] # PARENTHESIZED HANGUL CIEUC +3268 ; [.3D18.0020.0006] # CIRCLED HANGUL CIEUC +FFB8 ; [.3D18.0020.0012] # HALFWIDTH HANGUL LETTER CIEUC +3216 ; [*0318.0020.0004][.3D18.0020.0004][.3D8A.0020.0004][*0319.0020.0004] # PARENTHESIZED HANGUL CIEUC A +3276 ; [.3D18.0020.0006][.3D8A.0020.0006] # CIRCLED HANGUL CIEUC A +321C ; [*0318.0020.0004][.3D18.0020.0004][.3D97.0020.0004][*0319.0020.0004] # PARENTHESIZED HANGUL CIEUC U +327D ; [.3D18.0020.0006][.3D97.0020.0006][.3D17.0020.0006][.3D9D.0020.0006] # CIRCLED KOREAN CHARACTER JUEUI +110D ; [.3D19.0020.0002] # HANGUL CHOSEONG SSANGCIEUC +3149 ; [.3D19.0020.0004] # HANGUL LETTER SSANGCIEUC +FFB9 ; [.3D19.0020.0012] # HALFWIDTH HANGUL LETTER SSANGCIEUC +110E ; [.3D1A.0020.0002] # HANGUL CHOSEONG CHIEUCH +314A ; [.3D1A.0020.0004] # HANGUL LETTER CHIEUCH +3209 ; [*0318.0020.0004][.3D1A.0020.0004][*0319.0020.0004] # PARENTHESIZED HANGUL CHIEUCH +3269 ; [.3D1A.0020.0006] # CIRCLED HANGUL CHIEUCH +FFBA ; [.3D1A.0020.0012] # HALFWIDTH HANGUL LETTER CHIEUCH +3217 ; [*0318.0020.0004][.3D1A.0020.0004][.3D8A.0020.0004][*0319.0020.0004] # PARENTHESIZED HANGUL CHIEUCH A +3277 ; [.3D1A.0020.0006][.3D8A.0020.0006] # CIRCLED HANGUL CHIEUCH A +327C ; [.3D1A.0020.0006][.3D8A.0020.0006][.3DF7.0020.0006][.3D0C.0020.0006][.3D92.0020.0006] # CIRCLED KOREAN CHARACTER CHAMKO +110F ; [.3D1B.0020.0002] # HANGUL CHOSEONG KHIEUKH +314B ; [.3D1B.0020.0004] # HANGUL LETTER KHIEUKH +320A ; [*0318.0020.0004][.3D1B.0020.0004][*0319.0020.0004] # PARENTHESIZED HANGUL KHIEUKH +326A ; [.3D1B.0020.0006] # CIRCLED HANGUL KHIEUKH +FFBB ; [.3D1B.0020.0012] # HALFWIDTH HANGUL LETTER KHIEUKH +3218 ; [*0318.0020.0004][.3D1B.0020.0004][.3D8A.0020.0004][*0319.0020.0004] # PARENTHESIZED HANGUL KHIEUKH A +3278 ; [.3D1B.0020.0006][.3D8A.0020.0006] # CIRCLED HANGUL KHIEUKH A +1110 ; [.3D1C.0020.0002] # HANGUL CHOSEONG THIEUTH +314C ; [.3D1C.0020.0004] # HANGUL LETTER THIEUTH +320B ; [*0318.0020.0004][.3D1C.0020.0004][*0319.0020.0004] # PARENTHESIZED HANGUL THIEUTH +326B ; [.3D1C.0020.0006] # CIRCLED HANGUL THIEUTH +FFBC ; [.3D1C.0020.0012] # HALFWIDTH HANGUL LETTER THIEUTH +3219 ; [*0318.0020.0004][.3D1C.0020.0004][.3D8A.0020.0004][*0319.0020.0004] # PARENTHESIZED HANGUL THIEUTH A +3279 ; [.3D1C.0020.0006][.3D8A.0020.0006] # CIRCLED HANGUL THIEUTH A +1111 ; [.3D1D.0020.0002] # HANGUL CHOSEONG PHIEUPH +314D ; [.3D1D.0020.0004] # HANGUL LETTER PHIEUPH +320C ; [*0318.0020.0004][.3D1D.0020.0004][*0319.0020.0004] # PARENTHESIZED HANGUL PHIEUPH +326C ; [.3D1D.0020.0006] # CIRCLED HANGUL PHIEUPH +FFBD ; [.3D1D.0020.0012] # HALFWIDTH HANGUL LETTER PHIEUPH +321A ; [*0318.0020.0004][.3D1D.0020.0004][.3D8A.0020.0004][*0319.0020.0004] # PARENTHESIZED HANGUL PHIEUPH A +327A ; [.3D1D.0020.0006][.3D8A.0020.0006] # CIRCLED HANGUL PHIEUPH A +1112 ; [.3D1E.0020.0002] # HANGUL CHOSEONG HIEUH +314E ; [.3D1E.0020.0004] # HANGUL LETTER HIEUH +320D ; [*0318.0020.0004][.3D1E.0020.0004][*0319.0020.0004] # PARENTHESIZED HANGUL HIEUH +326D ; [.3D1E.0020.0006] # CIRCLED HANGUL HIEUH +FFBE ; [.3D1E.0020.0012] # HALFWIDTH HANGUL LETTER HIEUH +321B ; [*0318.0020.0004][.3D1E.0020.0004][.3D8A.0020.0004][*0319.0020.0004] # PARENTHESIZED HANGUL HIEUH A +327B ; [.3D1E.0020.0006][.3D8A.0020.0006] # CIRCLED HANGUL HIEUH A +1113 ; [.3D1F.0020.0002] # HANGUL CHOSEONG NIEUN-KIYEOK +1114 ; [.3D20.0020.0002] # HANGUL CHOSEONG SSANGNIEUN +3165 ; [.3D20.0020.0004] # HANGUL LETTER SSANGNIEUN +1115 ; [.3D21.0020.0002] # HANGUL CHOSEONG NIEUN-TIKEUT +3166 ; [.3D21.0020.0004] # HANGUL LETTER NIEUN-TIKEUT +1116 ; [.3D22.0020.0002] # HANGUL CHOSEONG NIEUN-PIEUP +1117 ; [.3D23.0020.0002] # HANGUL CHOSEONG TIKEUT-KIYEOK +1118 ; [.3D24.0020.0002] # HANGUL CHOSEONG RIEUL-NIEUN +1119 ; [.3D25.0020.0002] # HANGUL CHOSEONG SSANGRIEUL +111A ; [.3D26.0020.0002] # HANGUL CHOSEONG RIEUL-HIEUH +3140 ; [.3D26.0020.0004] # HANGUL LETTER RIEUL-HIEUH +FFB0 ; [.3D26.0020.0012] # HALFWIDTH HANGUL LETTER RIEUL-HIEUH +111B ; [.3D27.0020.0002] # HANGUL CHOSEONG KAPYEOUNRIEUL +111C ; [.3D28.0020.0002] # HANGUL CHOSEONG MIEUM-PIEUP +316E ; [.3D28.0020.0004] # HANGUL LETTER MIEUM-PIEUP +111D ; [.3D29.0020.0002] # HANGUL CHOSEONG KAPYEOUNMIEUM +3171 ; [.3D29.0020.0004] # HANGUL LETTER KAPYEOUNMIEUM +111E ; [.3D2A.0020.0002] # HANGUL CHOSEONG PIEUP-KIYEOK +3172 ; [.3D2A.0020.0004] # HANGUL LETTER PIEUP-KIYEOK +111F ; [.3D2B.0020.0002] # HANGUL CHOSEONG PIEUP-NIEUN +1120 ; [.3D2C.0020.0002] # HANGUL CHOSEONG PIEUP-TIKEUT +3173 ; [.3D2C.0020.0004] # HANGUL LETTER PIEUP-TIKEUT +1121 ; [.3D2D.0020.0002] # HANGUL CHOSEONG PIEUP-SIOS +3144 ; [.3D2D.0020.0004] # HANGUL LETTER PIEUP-SIOS +FFB4 ; [.3D2D.0020.0012] # HALFWIDTH HANGUL LETTER PIEUP-SIOS +1122 ; [.3D2E.0020.0002] # HANGUL CHOSEONG PIEUP-SIOS-KIYEOK +3174 ; [.3D2E.0020.0004] # HANGUL LETTER PIEUP-SIOS-KIYEOK +1123 ; [.3D2F.0020.0002] # HANGUL CHOSEONG PIEUP-SIOS-TIKEUT +3175 ; [.3D2F.0020.0004] # HANGUL LETTER PIEUP-SIOS-TIKEUT +1124 ; [.3D30.0020.0002] # HANGUL CHOSEONG PIEUP-SIOS-PIEUP +1125 ; [.3D31.0020.0002] # HANGUL CHOSEONG PIEUP-SSANGSIOS +1126 ; [.3D32.0020.0002] # HANGUL CHOSEONG PIEUP-SIOS-CIEUC +1127 ; [.3D33.0020.0002] # HANGUL CHOSEONG PIEUP-CIEUC +3176 ; [.3D33.0020.0004] # HANGUL LETTER PIEUP-CIEUC +1128 ; [.3D34.0020.0002] # HANGUL CHOSEONG PIEUP-CHIEUCH +1129 ; [.3D35.0020.0002] # HANGUL CHOSEONG PIEUP-THIEUTH +3177 ; [.3D35.0020.0004] # HANGUL LETTER PIEUP-THIEUTH +112A ; [.3D36.0020.0002] # HANGUL CHOSEONG PIEUP-PHIEUPH +112B ; [.3D37.0020.0002] # HANGUL CHOSEONG KAPYEOUNPIEUP +3178 ; [.3D37.0020.0004] # HANGUL LETTER KAPYEOUNPIEUP +112C ; [.3D38.0020.0002] # HANGUL CHOSEONG KAPYEOUNSSANGPIEUP +3179 ; [.3D38.0020.0004] # HANGUL LETTER KAPYEOUNSSANGPIEUP +112D ; [.3D39.0020.0002] # HANGUL CHOSEONG SIOS-KIYEOK +317A ; [.3D39.0020.0004] # HANGUL LETTER SIOS-KIYEOK +112E ; [.3D3A.0020.0002] # HANGUL CHOSEONG SIOS-NIEUN +317B ; [.3D3A.0020.0004] # HANGUL LETTER SIOS-NIEUN +112F ; [.3D3B.0020.0002] # HANGUL CHOSEONG SIOS-TIKEUT +317C ; [.3D3B.0020.0004] # HANGUL LETTER SIOS-TIKEUT +1130 ; [.3D3C.0020.0002] # HANGUL CHOSEONG SIOS-RIEUL +1131 ; [.3D3D.0020.0002] # HANGUL CHOSEONG SIOS-MIEUM +1132 ; [.3D3E.0020.0002] # HANGUL CHOSEONG SIOS-PIEUP +317D ; [.3D3E.0020.0004] # HANGUL LETTER SIOS-PIEUP +1133 ; [.3D3F.0020.0002] # HANGUL CHOSEONG SIOS-PIEUP-KIYEOK +1134 ; [.3D40.0020.0002] # HANGUL CHOSEONG SIOS-SSANGSIOS +1135 ; [.3D41.0020.0002] # HANGUL CHOSEONG SIOS-IEUNG +1136 ; [.3D42.0020.0002] # HANGUL CHOSEONG SIOS-CIEUC +317E ; [.3D42.0020.0004] # HANGUL LETTER SIOS-CIEUC +1137 ; [.3D43.0020.0002] # HANGUL CHOSEONG SIOS-CHIEUCH +1138 ; [.3D44.0020.0002] # HANGUL CHOSEONG SIOS-KHIEUKH +1139 ; [.3D45.0020.0002] # HANGUL CHOSEONG SIOS-THIEUTH +113A ; [.3D46.0020.0002] # HANGUL CHOSEONG SIOS-PHIEUPH +113B ; [.3D47.0020.0002] # HANGUL CHOSEONG SIOS-HIEUH +113C ; [.3D48.0020.0002] # HANGUL CHOSEONG CHITUEUMSIOS +113D ; [.3D49.0020.0002] # HANGUL CHOSEONG CHITUEUMSSANGSIOS +113E ; [.3D4A.0020.0002] # HANGUL CHOSEONG CEONGCHIEUMSIOS +113F ; [.3D4B.0020.0002] # HANGUL CHOSEONG CEONGCHIEUMSSANGSIOS +1140 ; [.3D4C.0020.0002] # HANGUL CHOSEONG PANSIOS +317F ; [.3D4C.0020.0004] # HANGUL LETTER PANSIOS +1141 ; [.3D4D.0020.0002] # HANGUL CHOSEONG IEUNG-KIYEOK +1142 ; [.3D4E.0020.0002] # HANGUL CHOSEONG IEUNG-TIKEUT +1143 ; [.3D4F.0020.0002] # HANGUL CHOSEONG IEUNG-MIEUM +1144 ; [.3D50.0020.0002] # HANGUL CHOSEONG IEUNG-PIEUP +1145 ; [.3D51.0020.0002] # HANGUL CHOSEONG IEUNG-SIOS +1146 ; [.3D52.0020.0002] # HANGUL CHOSEONG IEUNG-PANSIOS +1147 ; [.3D53.0020.0002] # HANGUL CHOSEONG SSANGIEUNG +3180 ; [.3D53.0020.0004] # HANGUL LETTER SSANGIEUNG +1148 ; [.3D54.0020.0002] # HANGUL CHOSEONG IEUNG-CIEUC +1149 ; [.3D55.0020.0002] # HANGUL CHOSEONG IEUNG-CHIEUCH +114A ; [.3D56.0020.0002] # HANGUL CHOSEONG IEUNG-THIEUTH +114B ; [.3D57.0020.0002] # HANGUL CHOSEONG IEUNG-PHIEUPH +114C ; [.3D58.0020.0002] # HANGUL CHOSEONG YESIEUNG +3181 ; [.3D58.0020.0004] # HANGUL LETTER YESIEUNG +114D ; [.3D59.0020.0002] # HANGUL CHOSEONG CIEUC-IEUNG +114E ; [.3D5A.0020.0002] # HANGUL CHOSEONG CHITUEUMCIEUC +114F ; [.3D5B.0020.0002] # HANGUL CHOSEONG CHITUEUMSSANGCIEUC +1150 ; [.3D5C.0020.0002] # HANGUL CHOSEONG CEONGCHIEUMCIEUC +1151 ; [.3D5D.0020.0002] # HANGUL CHOSEONG CEONGCHIEUMSSANGCIEUC +1152 ; [.3D5E.0020.0002] # HANGUL CHOSEONG CHIEUCH-KHIEUKH +1153 ; [.3D5F.0020.0002] # HANGUL CHOSEONG CHIEUCH-HIEUH +1154 ; [.3D60.0020.0002] # HANGUL CHOSEONG CHITUEUMCHIEUCH +1155 ; [.3D61.0020.0002] # HANGUL CHOSEONG CEONGCHIEUMCHIEUCH +1156 ; [.3D62.0020.0002] # HANGUL CHOSEONG PHIEUPH-PIEUP +1157 ; [.3D63.0020.0002] # HANGUL CHOSEONG KAPYEOUNPHIEUPH +3184 ; [.3D63.0020.0004] # HANGUL LETTER KAPYEOUNPHIEUPH +1158 ; [.3D64.0020.0002] # HANGUL CHOSEONG SSANGHIEUH +3185 ; [.3D64.0020.0004] # HANGUL LETTER SSANGHIEUH +1159 ; [.3D65.0020.0002] # HANGUL CHOSEONG YEORINHIEUH +3186 ; [.3D65.0020.0004] # HANGUL LETTER YEORINHIEUH +115A ; [.3D66.0020.0002] # HANGUL CHOSEONG KIYEOK-TIKEUT +115B ; [.3D67.0020.0002] # HANGUL CHOSEONG NIEUN-SIOS +115C ; [.3D68.0020.0002] # HANGUL CHOSEONG NIEUN-CIEUC +115D ; [.3D69.0020.0002] # HANGUL CHOSEONG NIEUN-HIEUH +115E ; [.3D6A.0020.0002] # HANGUL CHOSEONG TIKEUT-RIEUL +A960 ; [.3D6B.0020.0002] # HANGUL CHOSEONG TIKEUT-MIEUM +A961 ; [.3D6C.0020.0002] # HANGUL CHOSEONG TIKEUT-PIEUP +A962 ; [.3D6D.0020.0002] # HANGUL CHOSEONG TIKEUT-SIOS +A963 ; [.3D6E.0020.0002] # HANGUL CHOSEONG TIKEUT-CIEUC +A964 ; [.3D6F.0020.0002] # HANGUL CHOSEONG RIEUL-KIYEOK +A965 ; [.3D70.0020.0002] # HANGUL CHOSEONG RIEUL-SSANGKIYEOK +A966 ; [.3D71.0020.0002] # HANGUL CHOSEONG RIEUL-TIKEUT +A967 ; [.3D72.0020.0002] # HANGUL CHOSEONG RIEUL-SSANGTIKEUT +A968 ; [.3D73.0020.0002] # HANGUL CHOSEONG RIEUL-MIEUM +A969 ; [.3D74.0020.0002] # HANGUL CHOSEONG RIEUL-PIEUP +A96A ; [.3D75.0020.0002] # HANGUL CHOSEONG RIEUL-SSANGPIEUP +A96B ; [.3D76.0020.0002] # HANGUL CHOSEONG RIEUL-KAPYEOUNPIEUP +A96C ; [.3D77.0020.0002] # HANGUL CHOSEONG RIEUL-SIOS +A96D ; [.3D78.0020.0002] # HANGUL CHOSEONG RIEUL-CIEUC +A96E ; [.3D79.0020.0002] # HANGUL CHOSEONG RIEUL-KHIEUKH +A96F ; [.3D7A.0020.0002] # HANGUL CHOSEONG MIEUM-KIYEOK +A970 ; [.3D7B.0020.0002] # HANGUL CHOSEONG MIEUM-TIKEUT +A971 ; [.3D7C.0020.0002] # HANGUL CHOSEONG MIEUM-SIOS +A972 ; [.3D7D.0020.0002] # HANGUL CHOSEONG PIEUP-SIOS-THIEUTH +A973 ; [.3D7E.0020.0002] # HANGUL CHOSEONG PIEUP-KHIEUKH +A974 ; [.3D7F.0020.0002] # HANGUL CHOSEONG PIEUP-HIEUH +A975 ; [.3D80.0020.0002] # HANGUL CHOSEONG SSANGSIOS-PIEUP +A976 ; [.3D81.0020.0002] # HANGUL CHOSEONG IEUNG-RIEUL +A977 ; [.3D82.0020.0002] # HANGUL CHOSEONG IEUNG-HIEUH +A978 ; [.3D83.0020.0002] # HANGUL CHOSEONG SSANGCIEUC-HIEUH +A979 ; [.3D84.0020.0002] # HANGUL CHOSEONG SSANGTHIEUTH +A97A ; [.3D85.0020.0002] # HANGUL CHOSEONG PHIEUPH-HIEUH +A97B ; [.3D86.0020.0002] # HANGUL CHOSEONG HIEUH-SIOS +A97C ; [.3D87.0020.0002] # HANGUL CHOSEONG SSANGYEORINHIEUH +115F ; [.3D88.0020.0002] # HANGUL CHOSEONG FILLER +1160 ; [.3D89.0020.0002] # HANGUL JUNGSEONG FILLER +3164 ; [.3D89.0020.0004] # HANGUL FILLER +FFA0 ; [.3D89.0020.0012] # HALFWIDTH HANGUL FILLER +1161 ; [.3D8A.0020.0002] # HANGUL JUNGSEONG A +314F ; [.3D8A.0020.0004] # HANGUL LETTER A +FFC2 ; [.3D8A.0020.0012] # HALFWIDTH HANGUL LETTER A +1162 ; [.3D8B.0020.0002] # HANGUL JUNGSEONG AE +3150 ; [.3D8B.0020.0004] # HANGUL LETTER AE +FFC3 ; [.3D8B.0020.0012] # HALFWIDTH HANGUL LETTER AE +1163 ; [.3D8C.0020.0002] # HANGUL JUNGSEONG YA +3151 ; [.3D8C.0020.0004] # HANGUL LETTER YA +FFC4 ; [.3D8C.0020.0012] # HALFWIDTH HANGUL LETTER YA +1164 ; [.3D8D.0020.0002] # HANGUL JUNGSEONG YAE +3152 ; [.3D8D.0020.0004] # HANGUL LETTER YAE +FFC5 ; [.3D8D.0020.0012] # HALFWIDTH HANGUL LETTER YAE +1165 ; [.3D8E.0020.0002] # HANGUL JUNGSEONG EO +3153 ; [.3D8E.0020.0004] # HANGUL LETTER EO +FFC6 ; [.3D8E.0020.0012] # HALFWIDTH HANGUL LETTER EO +1166 ; [.3D8F.0020.0002] # HANGUL JUNGSEONG E +3154 ; [.3D8F.0020.0004] # HANGUL LETTER E +FFC7 ; [.3D8F.0020.0012] # HALFWIDTH HANGUL LETTER E +1167 ; [.3D90.0020.0002] # HANGUL JUNGSEONG YEO +3155 ; [.3D90.0020.0004] # HANGUL LETTER YEO +FFCA ; [.3D90.0020.0012] # HALFWIDTH HANGUL LETTER YEO +1168 ; [.3D91.0020.0002] # HANGUL JUNGSEONG YE +3156 ; [.3D91.0020.0004] # HANGUL LETTER YE +FFCB ; [.3D91.0020.0012] # HALFWIDTH HANGUL LETTER YE +1169 ; [.3D92.0020.0002] # HANGUL JUNGSEONG O +3157 ; [.3D92.0020.0004] # HANGUL LETTER O +FFCC ; [.3D92.0020.0012] # HALFWIDTH HANGUL LETTER O +116A ; [.3D93.0020.0002] # HANGUL JUNGSEONG WA +3158 ; [.3D93.0020.0004] # HANGUL LETTER WA +FFCD ; [.3D93.0020.0012] # HALFWIDTH HANGUL LETTER WA +116B ; [.3D94.0020.0002] # HANGUL JUNGSEONG WAE +3159 ; [.3D94.0020.0004] # HANGUL LETTER WAE +FFCE ; [.3D94.0020.0012] # HALFWIDTH HANGUL LETTER WAE +116C ; [.3D95.0020.0002] # HANGUL JUNGSEONG OE +315A ; [.3D95.0020.0004] # HANGUL LETTER OE +FFCF ; [.3D95.0020.0012] # HALFWIDTH HANGUL LETTER OE +116D ; [.3D96.0020.0002] # HANGUL JUNGSEONG YO +315B ; [.3D96.0020.0004] # HANGUL LETTER YO +FFD2 ; [.3D96.0020.0012] # HALFWIDTH HANGUL LETTER YO +116E ; [.3D97.0020.0002] # HANGUL JUNGSEONG U +315C ; [.3D97.0020.0004] # HANGUL LETTER U +FFD3 ; [.3D97.0020.0012] # HALFWIDTH HANGUL LETTER U +116F ; [.3D98.0020.0002] # HANGUL JUNGSEONG WEO +315D ; [.3D98.0020.0004] # HANGUL LETTER WEO +FFD4 ; [.3D98.0020.0012] # HALFWIDTH HANGUL LETTER WEO +1170 ; [.3D99.0020.0002] # HANGUL JUNGSEONG WE +315E ; [.3D99.0020.0004] # HANGUL LETTER WE +FFD5 ; [.3D99.0020.0012] # HALFWIDTH HANGUL LETTER WE +1171 ; [.3D9A.0020.0002] # HANGUL JUNGSEONG WI +315F ; [.3D9A.0020.0004] # HANGUL LETTER WI +FFD6 ; [.3D9A.0020.0012] # HALFWIDTH HANGUL LETTER WI +1172 ; [.3D9B.0020.0002] # HANGUL JUNGSEONG YU +3160 ; [.3D9B.0020.0004] # HANGUL LETTER YU +FFD7 ; [.3D9B.0020.0012] # HALFWIDTH HANGUL LETTER YU +1173 ; [.3D9C.0020.0002] # HANGUL JUNGSEONG EU +3161 ; [.3D9C.0020.0004] # HANGUL LETTER EU +FFDA ; [.3D9C.0020.0012] # HALFWIDTH HANGUL LETTER EU +1174 ; [.3D9D.0020.0002] # HANGUL JUNGSEONG YI +3162 ; [.3D9D.0020.0004] # HANGUL LETTER YI +FFDB ; [.3D9D.0020.0012] # HALFWIDTH HANGUL LETTER YI +1175 ; [.3D9E.0020.0002] # HANGUL JUNGSEONG I +3163 ; [.3D9E.0020.0004] # HANGUL LETTER I +FFDC ; [.3D9E.0020.0012] # HALFWIDTH HANGUL LETTER I +1176 ; [.3D9F.0020.0002] # HANGUL JUNGSEONG A-O +1177 ; [.3DA0.0020.0002] # HANGUL JUNGSEONG A-U +1178 ; [.3DA1.0020.0002] # HANGUL JUNGSEONG YA-O +1179 ; [.3DA2.0020.0002] # HANGUL JUNGSEONG YA-YO +117A ; [.3DA3.0020.0002] # HANGUL JUNGSEONG EO-O +117B ; [.3DA4.0020.0002] # HANGUL JUNGSEONG EO-U +117C ; [.3DA5.0020.0002] # HANGUL JUNGSEONG EO-EU +117D ; [.3DA6.0020.0002] # HANGUL JUNGSEONG YEO-O +117E ; [.3DA7.0020.0002] # HANGUL JUNGSEONG YEO-U +117F ; [.3DA8.0020.0002] # HANGUL JUNGSEONG O-EO +1180 ; [.3DA9.0020.0002] # HANGUL JUNGSEONG O-E +1181 ; [.3DAA.0020.0002] # HANGUL JUNGSEONG O-YE +1182 ; [.3DAB.0020.0002] # HANGUL JUNGSEONG O-O +1183 ; [.3DAC.0020.0002] # HANGUL JUNGSEONG O-U +1184 ; [.3DAD.0020.0002] # HANGUL JUNGSEONG YO-YA +3187 ; [.3DAD.0020.0004] # HANGUL LETTER YO-YA +1185 ; [.3DAE.0020.0002] # HANGUL JUNGSEONG YO-YAE +3188 ; [.3DAE.0020.0004] # HANGUL LETTER YO-YAE +1186 ; [.3DAF.0020.0002] # HANGUL JUNGSEONG YO-YEO +1187 ; [.3DB0.0020.0002] # HANGUL JUNGSEONG YO-O +1188 ; [.3DB1.0020.0002] # HANGUL JUNGSEONG YO-I +3189 ; [.3DB1.0020.0004] # HANGUL LETTER YO-I +1189 ; [.3DB2.0020.0002] # HANGUL JUNGSEONG U-A +118A ; [.3DB3.0020.0002] # HANGUL JUNGSEONG U-AE +118B ; [.3DB4.0020.0002] # HANGUL JUNGSEONG U-EO-EU +118C ; [.3DB5.0020.0002] # HANGUL JUNGSEONG U-YE +118D ; [.3DB6.0020.0002] # HANGUL JUNGSEONG U-U +118E ; [.3DB7.0020.0002] # HANGUL JUNGSEONG YU-A +118F ; [.3DB8.0020.0002] # HANGUL JUNGSEONG YU-EO +1190 ; [.3DB9.0020.0002] # HANGUL JUNGSEONG YU-E +1191 ; [.3DBA.0020.0002] # HANGUL JUNGSEONG YU-YEO +318A ; [.3DBA.0020.0004] # HANGUL LETTER YU-YEO +1192 ; [.3DBB.0020.0002] # HANGUL JUNGSEONG YU-YE +318B ; [.3DBB.0020.0004] # HANGUL LETTER YU-YE +1193 ; [.3DBC.0020.0002] # HANGUL JUNGSEONG YU-U +1194 ; [.3DBD.0020.0002] # HANGUL JUNGSEONG YU-I +318C ; [.3DBD.0020.0004] # HANGUL LETTER YU-I +1195 ; [.3DBE.0020.0002] # HANGUL JUNGSEONG EU-U +1196 ; [.3DBF.0020.0002] # HANGUL JUNGSEONG EU-EU +1197 ; [.3DC0.0020.0002] # HANGUL JUNGSEONG YI-U +1198 ; [.3DC1.0020.0002] # HANGUL JUNGSEONG I-A +1199 ; [.3DC2.0020.0002] # HANGUL JUNGSEONG I-YA +119A ; [.3DC3.0020.0002] # HANGUL JUNGSEONG I-O +119B ; [.3DC4.0020.0002] # HANGUL JUNGSEONG I-U +119C ; [.3DC5.0020.0002] # HANGUL JUNGSEONG I-EU +119D ; [.3DC6.0020.0002] # HANGUL JUNGSEONG I-ARAEA +119E ; [.3DC7.0020.0002] # HANGUL JUNGSEONG ARAEA +318D ; [.3DC7.0020.0004] # HANGUL LETTER ARAEA +119F ; [.3DC8.0020.0002] # HANGUL JUNGSEONG ARAEA-EO +11A0 ; [.3DC9.0020.0002] # HANGUL JUNGSEONG ARAEA-U +11A1 ; [.3DCA.0020.0002] # HANGUL JUNGSEONG ARAEA-I +318E ; [.3DCA.0020.0004] # HANGUL LETTER ARAEAE +11A2 ; [.3DCB.0020.0002] # HANGUL JUNGSEONG SSANGARAEA +11A3 ; [.3DCC.0020.0002] # HANGUL JUNGSEONG A-EU +11A4 ; [.3DCD.0020.0002] # HANGUL JUNGSEONG YA-U +11A5 ; [.3DCE.0020.0002] # HANGUL JUNGSEONG YEO-YA +11A6 ; [.3DCF.0020.0002] # HANGUL JUNGSEONG O-YA +11A7 ; [.3DD0.0020.0002] # HANGUL JUNGSEONG O-YAE +D7B0 ; [.3DD1.0020.0002] # HANGUL JUNGSEONG O-YEO +D7B1 ; [.3DD2.0020.0002] # HANGUL JUNGSEONG O-O-I +D7B2 ; [.3DD3.0020.0002] # HANGUL JUNGSEONG YO-A +D7B3 ; [.3DD4.0020.0002] # HANGUL JUNGSEONG YO-AE +D7B4 ; [.3DD5.0020.0002] # HANGUL JUNGSEONG YO-EO +D7B5 ; [.3DD6.0020.0002] # HANGUL JUNGSEONG U-YEO +D7B6 ; [.3DD7.0020.0002] # HANGUL JUNGSEONG U-I-I +D7B7 ; [.3DD8.0020.0002] # HANGUL JUNGSEONG YU-AE +D7B8 ; [.3DD9.0020.0002] # HANGUL JUNGSEONG YU-O +D7B9 ; [.3DDA.0020.0002] # HANGUL JUNGSEONG EU-A +D7BA ; [.3DDB.0020.0002] # HANGUL JUNGSEONG EU-EO +D7BB ; [.3DDC.0020.0002] # HANGUL JUNGSEONG EU-E +D7BC ; [.3DDD.0020.0002] # HANGUL JUNGSEONG EU-O +D7BD ; [.3DDE.0020.0002] # HANGUL JUNGSEONG I-YA-O +D7BE ; [.3DDF.0020.0002] # HANGUL JUNGSEONG I-YAE +D7BF ; [.3DE0.0020.0002] # HANGUL JUNGSEONG I-YEO +D7C0 ; [.3DE1.0020.0002] # HANGUL JUNGSEONG I-YE +D7C1 ; [.3DE2.0020.0002] # HANGUL JUNGSEONG I-O-I +D7C2 ; [.3DE3.0020.0002] # HANGUL JUNGSEONG I-YO +D7C3 ; [.3DE4.0020.0002] # HANGUL JUNGSEONG I-YU +D7C4 ; [.3DE5.0020.0002] # HANGUL JUNGSEONG I-I +D7C5 ; [.3DE6.0020.0002] # HANGUL JUNGSEONG ARAEA-A +D7C6 ; [.3DE7.0020.0002] # HANGUL JUNGSEONG ARAEA-E +11A8 ; [.3DE8.0020.0002] # HANGUL JONGSEONG KIYEOK +11A9 ; [.3DE9.0020.0002] # HANGUL JONGSEONG SSANGKIYEOK +11AA ; [.3DEA.0020.0002] # HANGUL JONGSEONG KIYEOK-SIOS +3133 ; [.3DEA.0020.0004] # HANGUL LETTER KIYEOK-SIOS +FFA3 ; [.3DEA.0020.0012] # HALFWIDTH HANGUL LETTER KIYEOK-SIOS +11AB ; [.3DEB.0020.0002] # HANGUL JONGSEONG NIEUN +11AC ; [.3DEC.0020.0002] # HANGUL JONGSEONG NIEUN-CIEUC +3135 ; [.3DEC.0020.0004] # HANGUL LETTER NIEUN-CIEUC +FFA5 ; [.3DEC.0020.0012] # HALFWIDTH HANGUL LETTER NIEUN-CIEUC +11AD ; [.3DED.0020.0002] # HANGUL JONGSEONG NIEUN-HIEUH +3136 ; [.3DED.0020.0004] # HANGUL LETTER NIEUN-HIEUH +FFA6 ; [.3DED.0020.0012] # HALFWIDTH HANGUL LETTER NIEUN-HIEUH +11AE ; [.3DEE.0020.0002] # HANGUL JONGSEONG TIKEUT +11AF ; [.3DEF.0020.0002] # HANGUL JONGSEONG RIEUL +11B0 ; [.3DF0.0020.0002] # HANGUL JONGSEONG RIEUL-KIYEOK +313A ; [.3DF0.0020.0004] # HANGUL LETTER RIEUL-KIYEOK +FFAA ; [.3DF0.0020.0012] # HALFWIDTH HANGUL LETTER RIEUL-KIYEOK +11B1 ; [.3DF1.0020.0002] # HANGUL JONGSEONG RIEUL-MIEUM +313B ; [.3DF1.0020.0004] # HANGUL LETTER RIEUL-MIEUM +FFAB ; [.3DF1.0020.0012] # HALFWIDTH HANGUL LETTER RIEUL-MIEUM +11B2 ; [.3DF2.0020.0002] # HANGUL JONGSEONG RIEUL-PIEUP +313C ; [.3DF2.0020.0004] # HANGUL LETTER RIEUL-PIEUP +FFAC ; [.3DF2.0020.0012] # HALFWIDTH HANGUL LETTER RIEUL-PIEUP +11B3 ; [.3DF3.0020.0002] # HANGUL JONGSEONG RIEUL-SIOS +313D ; [.3DF3.0020.0004] # HANGUL LETTER RIEUL-SIOS +FFAD ; [.3DF3.0020.0012] # HALFWIDTH HANGUL LETTER RIEUL-SIOS +11B4 ; [.3DF4.0020.0002] # HANGUL JONGSEONG RIEUL-THIEUTH +313E ; [.3DF4.0020.0004] # HANGUL LETTER RIEUL-THIEUTH +FFAE ; [.3DF4.0020.0012] # HALFWIDTH HANGUL LETTER RIEUL-THIEUTH +11B5 ; [.3DF5.0020.0002] # HANGUL JONGSEONG RIEUL-PHIEUPH +313F ; [.3DF5.0020.0004] # HANGUL LETTER RIEUL-PHIEUPH +FFAF ; [.3DF5.0020.0012] # HALFWIDTH HANGUL LETTER RIEUL-PHIEUPH +11B6 ; [.3DF6.0020.0002] # HANGUL JONGSEONG RIEUL-HIEUH +11B7 ; [.3DF7.0020.0002] # HANGUL JONGSEONG MIEUM +11B8 ; [.3DF8.0020.0002] # HANGUL JONGSEONG PIEUP +11B9 ; [.3DF9.0020.0002] # HANGUL JONGSEONG PIEUP-SIOS +11BA ; [.3DFA.0020.0002] # HANGUL JONGSEONG SIOS +11BB ; [.3DFB.0020.0002] # HANGUL JONGSEONG SSANGSIOS +11BC ; [.3DFC.0020.0002] # HANGUL JONGSEONG IEUNG +11BD ; [.3DFD.0020.0002] # HANGUL JONGSEONG CIEUC +11BE ; [.3DFE.0020.0002] # HANGUL JONGSEONG CHIEUCH +11BF ; [.3DFF.0020.0002] # HANGUL JONGSEONG KHIEUKH +11C0 ; [.3E00.0020.0002] # HANGUL JONGSEONG THIEUTH +11C1 ; [.3E01.0020.0002] # HANGUL JONGSEONG PHIEUPH +11C2 ; [.3E02.0020.0002] # HANGUL JONGSEONG HIEUH +11C3 ; [.3E03.0020.0002] # HANGUL JONGSEONG KIYEOK-RIEUL +11C4 ; [.3E04.0020.0002] # HANGUL JONGSEONG KIYEOK-SIOS-KIYEOK +11C5 ; [.3E05.0020.0002] # HANGUL JONGSEONG NIEUN-KIYEOK +11C6 ; [.3E06.0020.0002] # HANGUL JONGSEONG NIEUN-TIKEUT +11C7 ; [.3E07.0020.0002] # HANGUL JONGSEONG NIEUN-SIOS +3167 ; [.3E07.0020.0004] # HANGUL LETTER NIEUN-SIOS +11C8 ; [.3E08.0020.0002] # HANGUL JONGSEONG NIEUN-PANSIOS +3168 ; [.3E08.0020.0004] # HANGUL LETTER NIEUN-PANSIOS +11C9 ; [.3E09.0020.0002] # HANGUL JONGSEONG NIEUN-THIEUTH +11CA ; [.3E0A.0020.0002] # HANGUL JONGSEONG TIKEUT-KIYEOK +11CB ; [.3E0B.0020.0002] # HANGUL JONGSEONG TIKEUT-RIEUL +11CC ; [.3E0C.0020.0002] # HANGUL JONGSEONG RIEUL-KIYEOK-SIOS +3169 ; [.3E0C.0020.0004] # HANGUL LETTER RIEUL-KIYEOK-SIOS +11CD ; [.3E0D.0020.0002] # HANGUL JONGSEONG RIEUL-NIEUN +11CE ; [.3E0E.0020.0002] # HANGUL JONGSEONG RIEUL-TIKEUT +316A ; [.3E0E.0020.0004] # HANGUL LETTER RIEUL-TIKEUT +11CF ; [.3E0F.0020.0002] # HANGUL JONGSEONG RIEUL-TIKEUT-HIEUH +11D0 ; [.3E10.0020.0002] # HANGUL JONGSEONG SSANGRIEUL +11D1 ; [.3E11.0020.0002] # HANGUL JONGSEONG RIEUL-MIEUM-KIYEOK +11D2 ; [.3E12.0020.0002] # HANGUL JONGSEONG RIEUL-MIEUM-SIOS +11D3 ; [.3E13.0020.0002] # HANGUL JONGSEONG RIEUL-PIEUP-SIOS +316B ; [.3E13.0020.0004] # HANGUL LETTER RIEUL-PIEUP-SIOS +11D4 ; [.3E14.0020.0002] # HANGUL JONGSEONG RIEUL-PIEUP-HIEUH +11D5 ; [.3E15.0020.0002] # HANGUL JONGSEONG RIEUL-KAPYEOUNPIEUP +11D6 ; [.3E16.0020.0002] # HANGUL JONGSEONG RIEUL-SSANGSIOS +11D7 ; [.3E17.0020.0002] # HANGUL JONGSEONG RIEUL-PANSIOS +316C ; [.3E17.0020.0004] # HANGUL LETTER RIEUL-PANSIOS +11D8 ; [.3E18.0020.0002] # HANGUL JONGSEONG RIEUL-KHIEUKH +11D9 ; [.3E19.0020.0002] # HANGUL JONGSEONG RIEUL-YEORINHIEUH +316D ; [.3E19.0020.0004] # HANGUL LETTER RIEUL-YEORINHIEUH +11DA ; [.3E1A.0020.0002] # HANGUL JONGSEONG MIEUM-KIYEOK +11DB ; [.3E1B.0020.0002] # HANGUL JONGSEONG MIEUM-RIEUL +11DC ; [.3E1C.0020.0002] # HANGUL JONGSEONG MIEUM-PIEUP +11DD ; [.3E1D.0020.0002] # HANGUL JONGSEONG MIEUM-SIOS +316F ; [.3E1D.0020.0004] # HANGUL LETTER MIEUM-SIOS +11DE ; [.3E1E.0020.0002] # HANGUL JONGSEONG MIEUM-SSANGSIOS +11DF ; [.3E1F.0020.0002] # HANGUL JONGSEONG MIEUM-PANSIOS +3170 ; [.3E1F.0020.0004] # HANGUL LETTER MIEUM-PANSIOS +11E0 ; [.3E20.0020.0002] # HANGUL JONGSEONG MIEUM-CHIEUCH +11E1 ; [.3E21.0020.0002] # HANGUL JONGSEONG MIEUM-HIEUH +11E2 ; [.3E22.0020.0002] # HANGUL JONGSEONG KAPYEOUNMIEUM +11E3 ; [.3E23.0020.0002] # HANGUL JONGSEONG PIEUP-RIEUL +11E4 ; [.3E24.0020.0002] # HANGUL JONGSEONG PIEUP-PHIEUPH +11E5 ; [.3E25.0020.0002] # HANGUL JONGSEONG PIEUP-HIEUH +11E6 ; [.3E26.0020.0002] # HANGUL JONGSEONG KAPYEOUNPIEUP +11E7 ; [.3E27.0020.0002] # HANGUL JONGSEONG SIOS-KIYEOK +11E8 ; [.3E28.0020.0002] # HANGUL JONGSEONG SIOS-TIKEUT +11E9 ; [.3E29.0020.0002] # HANGUL JONGSEONG SIOS-RIEUL +11EA ; [.3E2A.0020.0002] # HANGUL JONGSEONG SIOS-PIEUP +11EB ; [.3E2B.0020.0002] # HANGUL JONGSEONG PANSIOS +11EC ; [.3E2C.0020.0002] # HANGUL JONGSEONG IEUNG-KIYEOK +11ED ; [.3E2D.0020.0002] # HANGUL JONGSEONG IEUNG-SSANGKIYEOK +11EE ; [.3E2E.0020.0002] # HANGUL JONGSEONG SSANGIEUNG +11EF ; [.3E2F.0020.0002] # HANGUL JONGSEONG IEUNG-KHIEUKH +11F0 ; [.3E30.0020.0002] # HANGUL JONGSEONG YESIEUNG +11F1 ; [.3E31.0020.0002] # HANGUL JONGSEONG YESIEUNG-SIOS +3182 ; [.3E31.0020.0004] # HANGUL LETTER YESIEUNG-SIOS +11F2 ; [.3E32.0020.0002] # HANGUL JONGSEONG YESIEUNG-PANSIOS +3183 ; [.3E32.0020.0004] # HANGUL LETTER YESIEUNG-PANSIOS +11F3 ; [.3E33.0020.0002] # HANGUL JONGSEONG PHIEUPH-PIEUP +11F4 ; [.3E34.0020.0002] # HANGUL JONGSEONG KAPYEOUNPHIEUPH +11F5 ; [.3E35.0020.0002] # HANGUL JONGSEONG HIEUH-NIEUN +11F6 ; [.3E36.0020.0002] # HANGUL JONGSEONG HIEUH-RIEUL +11F7 ; [.3E37.0020.0002] # HANGUL JONGSEONG HIEUH-MIEUM +11F8 ; [.3E38.0020.0002] # HANGUL JONGSEONG HIEUH-PIEUP +11F9 ; [.3E39.0020.0002] # HANGUL JONGSEONG YEORINHIEUH +11FA ; [.3E3A.0020.0002] # HANGUL JONGSEONG KIYEOK-NIEUN +11FB ; [.3E3B.0020.0002] # HANGUL JONGSEONG KIYEOK-PIEUP +11FC ; [.3E3C.0020.0002] # HANGUL JONGSEONG KIYEOK-CHIEUCH +11FD ; [.3E3D.0020.0002] # HANGUL JONGSEONG KIYEOK-KHIEUKH +11FE ; [.3E3E.0020.0002] # HANGUL JONGSEONG KIYEOK-HIEUH +11FF ; [.3E3F.0020.0002] # HANGUL JONGSEONG SSANGNIEUN +D7CB ; [.3E40.0020.0002] # HANGUL JONGSEONG NIEUN-RIEUL +D7CC ; [.3E41.0020.0002] # HANGUL JONGSEONG NIEUN-CHIEUCH +D7CD ; [.3E42.0020.0002] # HANGUL JONGSEONG SSANGTIKEUT +D7CE ; [.3E43.0020.0002] # HANGUL JONGSEONG SSANGTIKEUT-PIEUP +D7CF ; [.3E44.0020.0002] # HANGUL JONGSEONG TIKEUT-PIEUP +D7D0 ; [.3E45.0020.0002] # HANGUL JONGSEONG TIKEUT-SIOS +D7D1 ; [.3E46.0020.0002] # HANGUL JONGSEONG TIKEUT-SIOS-KIYEOK +D7D2 ; [.3E47.0020.0002] # HANGUL JONGSEONG TIKEUT-CIEUC +D7D3 ; [.3E48.0020.0002] # HANGUL JONGSEONG TIKEUT-CHIEUCH +D7D4 ; [.3E49.0020.0002] # HANGUL JONGSEONG TIKEUT-THIEUTH +D7D5 ; [.3E4A.0020.0002] # HANGUL JONGSEONG RIEUL-SSANGKIYEOK +D7D6 ; [.3E4B.0020.0002] # HANGUL JONGSEONG RIEUL-KIYEOK-HIEUH +D7D7 ; [.3E4C.0020.0002] # HANGUL JONGSEONG SSANGRIEUL-KHIEUKH +D7D8 ; [.3E4D.0020.0002] # HANGUL JONGSEONG RIEUL-MIEUM-HIEUH +D7D9 ; [.3E4E.0020.0002] # HANGUL JONGSEONG RIEUL-PIEUP-TIKEUT +D7DA ; [.3E4F.0020.0002] # HANGUL JONGSEONG RIEUL-PIEUP-PHIEUPH +D7DB ; [.3E50.0020.0002] # HANGUL JONGSEONG RIEUL-YESIEUNG +D7DC ; [.3E51.0020.0002] # HANGUL JONGSEONG RIEUL-YEORINHIEUH-HIEUH +D7DD ; [.3E52.0020.0002] # HANGUL JONGSEONG KAPYEOUNRIEUL +D7DE ; [.3E53.0020.0002] # HANGUL JONGSEONG MIEUM-NIEUN +D7DF ; [.3E54.0020.0002] # HANGUL JONGSEONG MIEUM-SSANGNIEUN +D7E0 ; [.3E55.0020.0002] # HANGUL JONGSEONG SSANGMIEUM +D7E1 ; [.3E56.0020.0002] # HANGUL JONGSEONG MIEUM-PIEUP-SIOS +D7E2 ; [.3E57.0020.0002] # HANGUL JONGSEONG MIEUM-CIEUC +D7E3 ; [.3E58.0020.0002] # HANGUL JONGSEONG PIEUP-TIKEUT +D7E4 ; [.3E59.0020.0002] # HANGUL JONGSEONG PIEUP-RIEUL-PHIEUPH +D7E5 ; [.3E5A.0020.0002] # HANGUL JONGSEONG PIEUP-MIEUM +D7E6 ; [.3E5B.0020.0002] # HANGUL JONGSEONG SSANGPIEUP +D7E7 ; [.3E5C.0020.0002] # HANGUL JONGSEONG PIEUP-SIOS-TIKEUT +D7E8 ; [.3E5D.0020.0002] # HANGUL JONGSEONG PIEUP-CIEUC +D7E9 ; [.3E5E.0020.0002] # HANGUL JONGSEONG PIEUP-CHIEUCH +D7EA ; [.3E5F.0020.0002] # HANGUL JONGSEONG SIOS-MIEUM +D7EB ; [.3E60.0020.0002] # HANGUL JONGSEONG SIOS-KAPYEOUNPIEUP +D7EC ; [.3E61.0020.0002] # HANGUL JONGSEONG SSANGSIOS-KIYEOK +D7ED ; [.3E62.0020.0002] # HANGUL JONGSEONG SSANGSIOS-TIKEUT +D7EE ; [.3E63.0020.0002] # HANGUL JONGSEONG SIOS-PANSIOS +D7EF ; [.3E64.0020.0002] # HANGUL JONGSEONG SIOS-CIEUC +D7F0 ; [.3E65.0020.0002] # HANGUL JONGSEONG SIOS-CHIEUCH +D7F1 ; [.3E66.0020.0002] # HANGUL JONGSEONG SIOS-THIEUTH +D7F2 ; [.3E67.0020.0002] # HANGUL JONGSEONG SIOS-HIEUH +D7F3 ; [.3E68.0020.0002] # HANGUL JONGSEONG PANSIOS-PIEUP +D7F4 ; [.3E69.0020.0002] # HANGUL JONGSEONG PANSIOS-KAPYEOUNPIEUP +D7F5 ; [.3E6A.0020.0002] # HANGUL JONGSEONG YESIEUNG-MIEUM +D7F6 ; [.3E6B.0020.0002] # HANGUL JONGSEONG YESIEUNG-HIEUH +D7F7 ; [.3E6C.0020.0002] # HANGUL JONGSEONG CIEUC-PIEUP +D7F8 ; [.3E6D.0020.0002] # HANGUL JONGSEONG CIEUC-SSANGPIEUP +D7F9 ; [.3E6E.0020.0002] # HANGUL JONGSEONG SSANGCIEUC +D7FA ; [.3E6F.0020.0002] # HANGUL JONGSEONG PHIEUPH-SIOS +D7FB ; [.3E70.0020.0002] # HANGUL JONGSEONG PHIEUPH-THIEUTH +3041 ; [.3E71.0020.000D] # HIRAGANA LETTER SMALL A +3042 ; [.3E71.0020.000E] # HIRAGANA LETTER A +30A1 ; [.3E71.0020.000F] # KATAKANA LETTER SMALL A +FF67 ; [.3E71.0020.0010] # HALFWIDTH KATAKANA LETTER SMALL A +30A2 ; [.3E71.0020.0011] # KATAKANA LETTER A +FF71 ; [.3E71.0020.0012] # HALFWIDTH KATAKANA LETTER A +32D0 ; [.3E71.0020.0013] # CIRCLED KATAKANA A +3303 ; [.3E71.0020.001C][.1C73.0020.001C][.3E9A.0020.001C] # SQUARE AARU +3300 ; [.3E71.0020.001C][.3E8B.0020.001C][.0000.0038.001C][.1C73.0020.001C][.3E85.0020.001C] # SQUARE APAATO +3301 ; [.3E71.0020.001C][.3E9A.0020.001C][.3E8D.0020.001C][.3E71.0020.001C] # SQUARE ARUHUA +3302 ; [.3E71.0020.001C][.3EA1.0020.001C][.3E8E.0020.001C][.0000.0038.001C][.3E71.0020.001C] # SQUARE ANPEA +3043 ; [.3E72.0020.000D] # HIRAGANA LETTER SMALL I +3044 ; [.3E72.0020.000E] # HIRAGANA LETTER I +30A3 ; [.3E72.0020.000F] # KATAKANA LETTER SMALL I +FF68 ; [.3E72.0020.0010] # HALFWIDTH KATAKANA LETTER SMALL I +30A4 ; [.3E72.0020.0011] # KATAKANA LETTER I +FF72 ; [.3E72.0020.0012] # HALFWIDTH KATAKANA LETTER I +32D1 ; [.3E72.0020.0013] # CIRCLED KATAKANA I +3304 ; [.3E72.0020.001C][.3E87.0020.001C][.3EA1.0020.001C][.3E79.0020.001C][.0000.0037.001C] # SQUARE ININGU +3305 ; [.3E72.0020.001C][.3EA1.0020.001C][.3E82.0020.001C] # SQUARE INTI +3045 ; [.3E73.0020.000D] # HIRAGANA LETTER SMALL U +3046 ; [.3E73.0020.000E] # HIRAGANA LETTER U +30A5 ; [.3E73.0020.000F] # KATAKANA LETTER SMALL U +FF69 ; [.3E73.0020.0010] # HALFWIDTH KATAKANA LETTER SMALL U +30A6 ; [.3E73.0020.0011] # KATAKANA LETTER U +FF73 ; [.3E73.0020.0012] # HALFWIDTH KATAKANA LETTER U +32D2 ; [.3E73.0020.0013] # CIRCLED KATAKANA U +3094 ; [.3E73.0020.000E][.0000.0037.0002] # HIRAGANA LETTER VU +30F4 ; [.3E73.0020.0011][.0000.0037.0002] # KATAKANA LETTER VU +3306 ; [.3E73.0020.001C][.3E76.0020.001C][.3EA1.0020.001C] # SQUARE UON +1B000 ; [.3E74.0020.0011] # KATAKANA LETTER ARCHAIC E +3047 ; [.3E75.0020.000D] # HIRAGANA LETTER SMALL E +3048 ; [.3E75.0020.000E] # HIRAGANA LETTER E +30A7 ; [.3E75.0020.000F] # KATAKANA LETTER SMALL E +FF6A ; [.3E75.0020.0010] # HALFWIDTH KATAKANA LETTER SMALL E +30A8 ; [.3E75.0020.0011] # KATAKANA LETTER E +FF74 ; [.3E75.0020.0012] # HALFWIDTH KATAKANA LETTER E +32D3 ; [.3E75.0020.0013] # CIRCLED KATAKANA E +3308 ; [.3E75.0020.001C][.1C73.0020.001C][.3E77.0020.001C][.1C73.0020.001C] # SQUARE EEKAA +3307 ; [.3E75.0020.001C][.3E7E.0020.001C][.3E79.0020.001C][.1C73.0020.001C][.3E85.0020.001C][.0000.0037.001C] # SQUARE ESUKUUDO +3049 ; [.3E76.0020.000D] # HIRAGANA LETTER SMALL O +304A ; [.3E76.0020.000E] # HIRAGANA LETTER O +30A9 ; [.3E76.0020.000F] # KATAKANA LETTER SMALL O +FF6B ; [.3E76.0020.0010] # HALFWIDTH KATAKANA LETTER SMALL O +30AA ; [.3E76.0020.0011] # KATAKANA LETTER O +FF75 ; [.3E76.0020.0012] # HALFWIDTH KATAKANA LETTER O +32D4 ; [.3E76.0020.0013] # CIRCLED KATAKANA O +330A ; [.3E76.0020.001C][.1C73.0020.001C][.3E92.0020.001C] # SQUARE OOMU +3309 ; [.3E76.0020.001C][.3EA1.0020.001C][.3E7E.0020.001C] # SQUARE ONSU +3095 ; [.3E77.0020.000D] # HIRAGANA LETTER SMALL KA +304B ; [.3E77.0020.000E] # HIRAGANA LETTER KA +30F5 ; [.3E77.0020.000F] # KATAKANA LETTER SMALL KA +30AB ; [.3E77.0020.0011] # KATAKANA LETTER KA +FF76 ; [.3E77.0020.0012] # HALFWIDTH KATAKANA LETTER KA +32D5 ; [.3E77.0020.0013] # CIRCLED KATAKANA KA +304C ; [.3E77.0020.000E][.0000.0037.0002] # HIRAGANA LETTER GA +30AC ; [.3E77.0020.0011][.0000.0037.0002] # KATAKANA LETTER GA +330B ; [.3E77.0020.001C][.3E72.0020.001C][.3E99.0020.001C] # SQUARE KAIRI +330C ; [.3E77.0020.001C][.3E98.0020.001C][.3E83.0020.001C][.3E85.0020.001C] # SQUARE KARATTO +330D ; [.3E77.0020.001C][.3E9C.0020.001C][.3E99.0020.001C][.1C73.0020.001C] # SQUARE KARORII +330E ; [.3E77.0020.001C][.0000.0037.001C][.3E9C.0020.001C][.3EA1.0020.001C] # SQUARE GARON +330F ; [.3E77.0020.001C][.0000.0037.001C][.3EA1.0020.001C][.3E90.0020.001C] # SQUARE GANMA +304D ; [.3E78.0020.000E] # HIRAGANA LETTER KI +30AD ; [.3E78.0020.0011] # KATAKANA LETTER KI +FF77 ; [.3E78.0020.0012] # HALFWIDTH KATAKANA LETTER KI +32D6 ; [.3E78.0020.0013] # CIRCLED KATAKANA KI +304E ; [.3E78.0020.000E][.0000.0037.0002] # HIRAGANA LETTER GI +30AE ; [.3E78.0020.0011][.0000.0037.0002] # KATAKANA LETTER GI +3310 ; [.3E78.0020.001C][.0000.0037.001C][.3E77.0020.001C][.0000.0037.001C] # SQUARE GIGA +3311 ; [.3E78.0020.001C][.0000.0037.001C][.3E87.0020.001C][.1C73.0020.001C] # SQUARE GINII +3312 ; [.3E78.0020.001C][.3E96.0020.001C][.3E99.0020.001C][.1C73.0020.001C] # SQUARE KYURII +3313 ; [.3E78.0020.001C][.0000.0037.001C][.3E9A.0020.001C][.3E81.0020.001C][.0000.0037.001C][.1C73.0020.001C] # SQUARE GIRUDAA +3314 ; [.3E78.0020.001C][.3E9C.0020.001C] # SQUARE KIRO +3315 ; [.3E78.0020.001C][.3E9C.0020.001C][.3E79.0020.001C][.0000.0037.001C][.3E98.0020.001C][.3E92.0020.001C] # SQUARE KIROGURAMU +3316 ; [.3E78.0020.001C][.3E9C.0020.001C][.3E93.0020.001C][.1C73.0020.001C][.3E85.0020.001C][.3E9A.0020.001C] # SQUARE KIROMEETORU +3317 ; [.3E78.0020.001C][.3E9C.0020.001C][.3E9D.0020.001C][.3E83.0020.001C][.3E85.0020.001C] # SQUARE KIROWATTO +304F ; [.3E79.0020.000E] # HIRAGANA LETTER KU +31F0 ; [.3E79.0020.000F] # KATAKANA LETTER SMALL KU +30AF ; [.3E79.0020.0011] # KATAKANA LETTER KU +FF78 ; [.3E79.0020.0012] # HALFWIDTH KATAKANA LETTER KU +32D7 ; [.3E79.0020.0013] # CIRCLED KATAKANA KU +3050 ; [.3E79.0020.000E][.0000.0037.0002] # HIRAGANA LETTER GU +30B0 ; [.3E79.0020.0011][.0000.0037.0002] # KATAKANA LETTER GU +3318 ; [.3E79.0020.001C][.0000.0037.001C][.3E98.0020.001C][.3E92.0020.001C] # SQUARE GURAMU +3319 ; [.3E79.0020.001C][.0000.0037.001C][.3E98.0020.001C][.3E92.0020.001C][.3E85.0020.001C][.3EA1.0020.001C] # SQUARE GURAMUTON +331A ; [.3E79.0020.001C][.3E9A.0020.001C][.3E7F.0020.001C][.0000.0037.001C][.3E72.0020.001C][.3E9C.0020.001C] # SQUARE KURUZEIRO +331B ; [.3E79.0020.001C][.3E9C.0020.001C][.1C73.0020.001C][.3E89.0020.001C] # SQUARE KUROONE +3096 ; [.3E7A.0020.000D] # HIRAGANA LETTER SMALL KE +3051 ; [.3E7A.0020.000E] # HIRAGANA LETTER KE +30F6 ; [.3E7A.0020.000F] # KATAKANA LETTER SMALL KE +30B1 ; [.3E7A.0020.0011] # KATAKANA LETTER KE +FF79 ; [.3E7A.0020.0012] # HALFWIDTH KATAKANA LETTER KE +32D8 ; [.3E7A.0020.0013] # CIRCLED KATAKANA KE +3052 ; [.3E7A.0020.000E][.0000.0037.0002] # HIRAGANA LETTER GE +30B2 ; [.3E7A.0020.0011][.0000.0037.0002] # KATAKANA LETTER GE +331C ; [.3E7A.0020.001C][.1C73.0020.001C][.3E7E.0020.001C] # SQUARE KEESU +3053 ; [.3E7B.0020.000E] # HIRAGANA LETTER KO +30B3 ; [.3E7B.0020.0011] # KATAKANA LETTER KO +FF7A ; [.3E7B.0020.0012] # HALFWIDTH KATAKANA LETTER KO +32D9 ; [.3E7B.0020.0013] # CIRCLED KATAKANA KO +3054 ; [.3E7B.0020.000E][.0000.0037.0002] # HIRAGANA LETTER GO +30B4 ; [.3E7B.0020.0011][.0000.0037.0002] # KATAKANA LETTER GO +331E ; [.3E7B.0020.001C][.1C73.0020.001C][.3E8F.0020.001C][.0000.0038.001C] # SQUARE KOOPO +1F201 ; [.3E7B.0020.001C][.3E7B.0020.001C] # SQUARED KATAKANA KOKO +30FF ; [.3E7B.0020.0016][.3E85.0020.0016] # KATAKANA DIGRAPH KOTO +331D ; [.3E7B.0020.001C][.3E9A.0020.001C][.3E86.0020.001C] # SQUARE KORUNA +3055 ; [.3E7C.0020.000E] # HIRAGANA LETTER SA +30B5 ; [.3E7C.0020.0011] # KATAKANA LETTER SA +FF7B ; [.3E7C.0020.0012] # HALFWIDTH KATAKANA LETTER SA +32DA ; [.3E7C.0020.0013] # CIRCLED KATAKANA SA +1F202 ; [.3E7C.0020.001C] # SQUARED KATAKANA SA +3056 ; [.3E7C.0020.000E][.0000.0037.0002] # HIRAGANA LETTER ZA +30B6 ; [.3E7C.0020.0011][.0000.0037.0002] # KATAKANA LETTER ZA +331F ; [.3E7C.0020.001C][.3E72.0020.001C][.3E79.0020.001C][.3E9A.0020.001C] # SQUARE SAIKURU +3320 ; [.3E7C.0020.001C][.3EA1.0020.001C][.3E82.0020.001C][.1C73.0020.001C][.3E92.0020.001C] # SQUARE SANTIIMU +3057 ; [.3E7D.0020.000E] # HIRAGANA LETTER SI +31F1 ; [.3E7D.0020.000F] # KATAKANA LETTER SMALL SI +30B7 ; [.3E7D.0020.0011] # KATAKANA LETTER SI +FF7C ; [.3E7D.0020.0012] # HALFWIDTH KATAKANA LETTER SI +32DB ; [.3E7D.0020.0013] # CIRCLED KATAKANA SI +3058 ; [.3E7D.0020.000E][.0000.0037.0002] # HIRAGANA LETTER ZI +30B8 ; [.3E7D.0020.0011][.0000.0037.0002] # KATAKANA LETTER ZI +3006 ; [.3E7D.0020.0004][.3E93.0020.0004] # IDEOGRAPHIC CLOSING MARK +3321 ; [.3E7D.0020.001C][.3E99.0020.001C][.3EA1.0020.001C][.3E79.0020.001C][.0000.0037.001C] # SQUARE SIRINGU +3059 ; [.3E7E.0020.000E] # HIRAGANA LETTER SU +31F2 ; [.3E7E.0020.000F] # KATAKANA LETTER SMALL SU +30B9 ; [.3E7E.0020.0011] # KATAKANA LETTER SU +FF7D ; [.3E7E.0020.0012] # HALFWIDTH KATAKANA LETTER SU +32DC ; [.3E7E.0020.0013] # CIRCLED KATAKANA SU +305A ; [.3E7E.0020.000E][.0000.0037.0002] # HIRAGANA LETTER ZU +30BA ; [.3E7E.0020.0011][.0000.0037.0002] # KATAKANA LETTER ZU +305B ; [.3E7F.0020.000E] # HIRAGANA LETTER SE +30BB ; [.3E7F.0020.0011] # KATAKANA LETTER SE +FF7E ; [.3E7F.0020.0012] # HALFWIDTH KATAKANA LETTER SE +32DD ; [.3E7F.0020.0013] # CIRCLED KATAKANA SE +305C ; [.3E7F.0020.000E][.0000.0037.0002] # HIRAGANA LETTER ZE +30BC ; [.3E7F.0020.0011][.0000.0037.0002] # KATAKANA LETTER ZE +3322 ; [.3E7F.0020.001C][.3EA1.0020.001C][.3E82.0020.001C] # SQUARE SENTI +3323 ; [.3E7F.0020.001C][.3EA1.0020.001C][.3E85.0020.001C] # SQUARE SENTO +305D ; [.3E80.0020.000E] # HIRAGANA LETTER SO +30BD ; [.3E80.0020.0011] # KATAKANA LETTER SO +FF7F ; [.3E80.0020.0012] # HALFWIDTH KATAKANA LETTER SO +32DE ; [.3E80.0020.0013] # CIRCLED KATAKANA SO +305E ; [.3E80.0020.000E][.0000.0037.0002] # HIRAGANA LETTER ZO +30BE ; [.3E80.0020.0011][.0000.0037.0002] # KATAKANA LETTER ZO +305F ; [.3E81.0020.000E] # HIRAGANA LETTER TA +30BF ; [.3E81.0020.0011] # KATAKANA LETTER TA +FF80 ; [.3E81.0020.0012] # HALFWIDTH KATAKANA LETTER TA +32DF ; [.3E81.0020.0013] # CIRCLED KATAKANA TA +3060 ; [.3E81.0020.000E][.0000.0037.0002] # HIRAGANA LETTER DA +30C0 ; [.3E81.0020.0011][.0000.0037.0002] # KATAKANA LETTER DA +3324 ; [.3E81.0020.001C][.0000.0037.001C][.1C73.0020.001C][.3E7E.0020.001C] # SQUARE DAASU +3061 ; [.3E82.0020.000E] # HIRAGANA LETTER TI +30C1 ; [.3E82.0020.0011] # KATAKANA LETTER TI +FF81 ; [.3E82.0020.0012] # HALFWIDTH KATAKANA LETTER TI +32E0 ; [.3E82.0020.0013] # CIRCLED KATAKANA TI +3062 ; [.3E82.0020.000E][.0000.0037.0002] # HIRAGANA LETTER DI +30C2 ; [.3E82.0020.0011][.0000.0037.0002] # KATAKANA LETTER DI +3063 ; [.3E83.0020.000D] # HIRAGANA LETTER SMALL TU +3064 ; [.3E83.0020.000E] # HIRAGANA LETTER TU +30C3 ; [.3E83.0020.000F] # KATAKANA LETTER SMALL TU +FF6F ; [.3E83.0020.0010] # HALFWIDTH KATAKANA LETTER SMALL TU +30C4 ; [.3E83.0020.0011] # KATAKANA LETTER TU +FF82 ; [.3E83.0020.0012] # HALFWIDTH KATAKANA LETTER TU +32E1 ; [.3E83.0020.0013] # CIRCLED KATAKANA TU +3065 ; [.3E83.0020.000E][.0000.0037.0002] # HIRAGANA LETTER DU +30C5 ; [.3E83.0020.0011][.0000.0037.0002] # KATAKANA LETTER DU +3066 ; [.3E84.0020.000E] # HIRAGANA LETTER TE +30C6 ; [.3E84.0020.0011] # KATAKANA LETTER TE +FF83 ; [.3E84.0020.0012] # HALFWIDTH KATAKANA LETTER TE +32E2 ; [.3E84.0020.0013] # CIRCLED KATAKANA TE +3067 ; [.3E84.0020.000E][.0000.0037.0002] # HIRAGANA LETTER DE +30C7 ; [.3E84.0020.0011][.0000.0037.0002] # KATAKANA LETTER DE +1F213 ; [.3E84.0020.001C][.0000.0037.001C] # SQUARED KATAKANA DE +3325 ; [.3E84.0020.001C][.0000.0037.001C][.3E7D.0020.001C] # SQUARE DESI +3068 ; [.3E85.0020.000E] # HIRAGANA LETTER TO +31F3 ; [.3E85.0020.000F] # KATAKANA LETTER SMALL TO +30C8 ; [.3E85.0020.0011] # KATAKANA LETTER TO +FF84 ; [.3E85.0020.0012] # HALFWIDTH KATAKANA LETTER TO +32E3 ; [.3E85.0020.0013] # CIRCLED KATAKANA TO +3069 ; [.3E85.0020.000E][.0000.0037.0002] # HIRAGANA LETTER DO +30C9 ; [.3E85.0020.0011][.0000.0037.0002] # KATAKANA LETTER DO +3326 ; [.3E85.0020.001C][.0000.0037.001C][.3E9A.0020.001C] # SQUARE DORU +3327 ; [.3E85.0020.001C][.3EA1.0020.001C] # SQUARE TON +306A ; [.3E86.0020.000E] # HIRAGANA LETTER NA +30CA ; [.3E86.0020.0011] # KATAKANA LETTER NA +FF85 ; [.3E86.0020.0012] # HALFWIDTH KATAKANA LETTER NA +32E4 ; [.3E86.0020.0013] # CIRCLED KATAKANA NA +3328 ; [.3E86.0020.001C][.3E8A.0020.001C] # SQUARE NANO +306B ; [.3E87.0020.000E] # HIRAGANA LETTER NI +30CB ; [.3E87.0020.0011] # KATAKANA LETTER NI +FF86 ; [.3E87.0020.0012] # HALFWIDTH KATAKANA LETTER NI +32E5 ; [.3E87.0020.0013] # CIRCLED KATAKANA NI +306C ; [.3E88.0020.000E] # HIRAGANA LETTER NU +31F4 ; [.3E88.0020.000F] # KATAKANA LETTER SMALL NU +30CC ; [.3E88.0020.0011] # KATAKANA LETTER NU +FF87 ; [.3E88.0020.0012] # HALFWIDTH KATAKANA LETTER NU +32E6 ; [.3E88.0020.0013] # CIRCLED KATAKANA NU +306D ; [.3E89.0020.000E] # HIRAGANA LETTER NE +30CD ; [.3E89.0020.0011] # KATAKANA LETTER NE +FF88 ; [.3E89.0020.0012] # HALFWIDTH KATAKANA LETTER NE +32E7 ; [.3E89.0020.0013] # CIRCLED KATAKANA NE +306E ; [.3E8A.0020.000E] # HIRAGANA LETTER NO +30CE ; [.3E8A.0020.0011] # KATAKANA LETTER NO +FF89 ; [.3E8A.0020.0012] # HALFWIDTH KATAKANA LETTER NO +32E8 ; [.3E8A.0020.0013] # CIRCLED KATAKANA NO +3329 ; [.3E8A.0020.001C][.3E83.0020.001C][.3E85.0020.001C] # SQUARE NOTTO +306F ; [.3E8B.0020.000E] # HIRAGANA LETTER HA +31F5 ; [.3E8B.0020.000F] # KATAKANA LETTER SMALL HA +30CF ; [.3E8B.0020.0011] # KATAKANA LETTER HA +FF8A ; [.3E8B.0020.0012] # HALFWIDTH KATAKANA LETTER HA +32E9 ; [.3E8B.0020.0013] # CIRCLED KATAKANA HA +3070 ; [.3E8B.0020.000E][.0000.0037.0002] # HIRAGANA LETTER BA +30D0 ; [.3E8B.0020.0011][.0000.0037.0002] # KATAKANA LETTER BA +3071 ; [.3E8B.0020.000E][.0000.0038.0002] # HIRAGANA LETTER PA +30D1 ; [.3E8B.0020.0011][.0000.0038.0002] # KATAKANA LETTER PA +332B ; [.3E8B.0020.001C][.0000.0038.001C][.1C73.0020.001C][.3E7F.0020.001C][.3EA1.0020.001C][.3E85.0020.001C] # SQUARE PAASENTO +332C ; [.3E8B.0020.001C][.0000.0038.001C][.1C73.0020.001C][.3E83.0020.001C] # SQUARE PAATU +332D ; [.3E8B.0020.001C][.0000.0037.001C][.1C73.0020.001C][.3E9B.0020.001C][.3E9A.0020.001C] # SQUARE BAARERU +332A ; [.3E8B.0020.001C][.3E72.0020.001C][.3E83.0020.001C] # SQUARE HAITU +3072 ; [.3E8C.0020.000E] # HIRAGANA LETTER HI +31F6 ; [.3E8C.0020.000F] # KATAKANA LETTER SMALL HI +30D2 ; [.3E8C.0020.0011] # KATAKANA LETTER HI +FF8B ; [.3E8C.0020.0012] # HALFWIDTH KATAKANA LETTER HI +32EA ; [.3E8C.0020.0013] # CIRCLED KATAKANA HI +3073 ; [.3E8C.0020.000E][.0000.0037.0002] # HIRAGANA LETTER BI +30D3 ; [.3E8C.0020.0011][.0000.0037.0002] # KATAKANA LETTER BI +3074 ; [.3E8C.0020.000E][.0000.0038.0002] # HIRAGANA LETTER PI +30D4 ; [.3E8C.0020.0011][.0000.0038.0002] # KATAKANA LETTER PI +332E ; [.3E8C.0020.001C][.0000.0038.001C][.3E71.0020.001C][.3E7E.0020.001C][.3E85.0020.001C][.3E9A.0020.001C] # SQUARE PIASUTORU +332F ; [.3E8C.0020.001C][.0000.0038.001C][.3E79.0020.001C][.3E9A.0020.001C] # SQUARE PIKURU +3330 ; [.3E8C.0020.001C][.0000.0038.001C][.3E7B.0020.001C] # SQUARE PIKO +3331 ; [.3E8C.0020.001C][.0000.0037.001C][.3E9A.0020.001C] # SQUARE BIRU +3075 ; [.3E8D.0020.000E] # HIRAGANA LETTER HU +31F7 ; [.3E8D.0020.000F] # KATAKANA LETTER SMALL HU +30D5 ; [.3E8D.0020.0011] # KATAKANA LETTER HU +FF8C ; [.3E8D.0020.0012] # HALFWIDTH KATAKANA LETTER HU +32EB ; [.3E8D.0020.0013] # CIRCLED KATAKANA HU +3076 ; [.3E8D.0020.000E][.0000.0037.0002] # HIRAGANA LETTER BU +30D6 ; [.3E8D.0020.0011][.0000.0037.0002] # KATAKANA LETTER BU +3077 ; [.3E8D.0020.000E][.0000.0038.0002] # HIRAGANA LETTER PU +30D7 ; [.3E8D.0020.0011][.0000.0038.0002] # KATAKANA LETTER PU +3332 ; [.3E8D.0020.001C][.3E71.0020.001C][.3E98.0020.001C][.3E83.0020.001C][.3E85.0020.001C][.0000.0037.001C] # SQUARE HUARADDO +3333 ; [.3E8D.0020.001C][.3E72.0020.001C][.1C73.0020.001C][.3E85.0020.001C] # SQUARE HUIITO +3334 ; [.3E8D.0020.001C][.0000.0037.001C][.3E83.0020.001C][.3E7D.0020.001C][.3E75.0020.001C][.3E9A.0020.001C] # SQUARE BUSSYERU +3335 ; [.3E8D.0020.001C][.3E98.0020.001C][.3EA1.0020.001C] # SQUARE HURAN +3078 ; [.3E8E.0020.000E] # HIRAGANA LETTER HE +31F8 ; [.3E8E.0020.000F] # KATAKANA LETTER SMALL HE +30D8 ; [.3E8E.0020.0011] # KATAKANA LETTER HE +FF8D ; [.3E8E.0020.0012] # HALFWIDTH KATAKANA LETTER HE +32EC ; [.3E8E.0020.0013] # CIRCLED KATAKANA HE +3079 ; [.3E8E.0020.000E][.0000.0037.0002] # HIRAGANA LETTER BE +30D9 ; [.3E8E.0020.0011][.0000.0037.0002] # KATAKANA LETTER BE +307A ; [.3E8E.0020.000E][.0000.0038.0002] # HIRAGANA LETTER PE +30DA ; [.3E8E.0020.0011][.0000.0038.0002] # KATAKANA LETTER PE +333B ; [.3E8E.0020.001C][.0000.0038.001C][.1C73.0020.001C][.3E7D.0020.001C][.0000.0037.001C] # SQUARE PEEZI +333C ; [.3E8E.0020.001C][.0000.0037.001C][.1C73.0020.001C][.3E81.0020.001C] # SQUARE BEETA +3336 ; [.3E8E.0020.001C][.3E79.0020.001C][.3E81.0020.001C][.1C73.0020.001C][.3E9A.0020.001C] # SQUARE HEKUTAARU +3337 ; [.3E8E.0020.001C][.0000.0038.001C][.3E80.0020.001C] # SQUARE PESO +3338 ; [.3E8E.0020.001C][.0000.0038.001C][.3E87.0020.001C][.3E8C.0020.001C] # SQUARE PENIHI +3339 ; [.3E8E.0020.001C][.3E9A.0020.001C][.3E83.0020.001C] # SQUARE HERUTU +333A ; [.3E8E.0020.001C][.0000.0038.001C][.3EA1.0020.001C][.3E7E.0020.001C] # SQUARE PENSU +307B ; [.3E8F.0020.000E] # HIRAGANA LETTER HO +31F9 ; [.3E8F.0020.000F] # KATAKANA LETTER SMALL HO +30DB ; [.3E8F.0020.0011] # KATAKANA LETTER HO +FF8E ; [.3E8F.0020.0012] # HALFWIDTH KATAKANA LETTER HO +32ED ; [.3E8F.0020.0013] # CIRCLED KATAKANA HO +307C ; [.3E8F.0020.000E][.0000.0037.0002] # HIRAGANA LETTER BO +30DC ; [.3E8F.0020.0011][.0000.0037.0002] # KATAKANA LETTER BO +307D ; [.3E8F.0020.000E][.0000.0038.0002] # HIRAGANA LETTER PO +30DD ; [.3E8F.0020.0011][.0000.0038.0002] # KATAKANA LETTER PO +3341 ; [.3E8F.0020.001C][.1C73.0020.001C][.3E9A.0020.001C] # SQUARE HOORU +3342 ; [.3E8F.0020.001C][.1C73.0020.001C][.3EA1.0020.001C] # SQUARE HOON +333D ; [.3E8F.0020.001C][.0000.0038.001C][.3E72.0020.001C][.3EA1.0020.001C][.3E85.0020.001C] # SQUARE POINTO +1F200 ; [.3E8F.0020.001C][.3E77.0020.001C] # SQUARE HIRAGANA HOKA +333E ; [.3E8F.0020.001C][.0000.0037.001C][.3E9A.0020.001C][.3E85.0020.001C] # SQUARE BORUTO +333F ; [.3E8F.0020.001C][.3EA1.0020.001C] # SQUARE HON +3340 ; [.3E8F.0020.001C][.0000.0038.001C][.3EA1.0020.001C][.3E85.0020.001C][.0000.0037.001C] # SQUARE PONDO +307E ; [.3E90.0020.000E] # HIRAGANA LETTER MA +30DE ; [.3E90.0020.0011] # KATAKANA LETTER MA +FF8F ; [.3E90.0020.0012] # HALFWIDTH KATAKANA LETTER MA +32EE ; [.3E90.0020.0013] # CIRCLED KATAKANA MA +3343 ; [.3E90.0020.001C][.3E72.0020.001C][.3E79.0020.001C][.3E9C.0020.001C] # SQUARE MAIKURO +3344 ; [.3E90.0020.001C][.3E72.0020.001C][.3E9A.0020.001C] # SQUARE MAIRU +303C ; [.3E90.0020.0004][.3E7E.0020.0004] # MASU MARK +3345 ; [.3E90.0020.001C][.3E83.0020.001C][.3E8B.0020.001C] # SQUARE MAHHA +3346 ; [.3E90.0020.001C][.3E9A.0020.001C][.3E79.0020.001C] # SQUARE MARUKU +3347 ; [.3E90.0020.001C][.3EA1.0020.001C][.3E7D.0020.001C][.3E97.0020.001C][.3EA1.0020.001C] # SQUARE MANSYON +307F ; [.3E91.0020.000E] # HIRAGANA LETTER MI +30DF ; [.3E91.0020.0011] # KATAKANA LETTER MI +FF90 ; [.3E91.0020.0012] # HALFWIDTH KATAKANA LETTER MI +32EF ; [.3E91.0020.0013] # CIRCLED KATAKANA MI +3348 ; [.3E91.0020.001C][.3E79.0020.001C][.3E9C.0020.001C][.3EA1.0020.001C] # SQUARE MIKURON +3349 ; [.3E91.0020.001C][.3E99.0020.001C] # SQUARE MIRI +334A ; [.3E91.0020.001C][.3E99.0020.001C][.3E8B.0020.001C][.0000.0037.001C][.1C73.0020.001C][.3E9A.0020.001C] # SQUARE MIRIBAARU +3080 ; [.3E92.0020.000E] # HIRAGANA LETTER MU +31FA ; [.3E92.0020.000F] # KATAKANA LETTER SMALL MU +30E0 ; [.3E92.0020.0011] # KATAKANA LETTER MU +FF91 ; [.3E92.0020.0012] # HALFWIDTH KATAKANA LETTER MU +32F0 ; [.3E92.0020.0013] # CIRCLED KATAKANA MU +3081 ; [.3E93.0020.000E] # HIRAGANA LETTER ME +30E1 ; [.3E93.0020.0011] # KATAKANA LETTER ME +FF92 ; [.3E93.0020.0012] # HALFWIDTH KATAKANA LETTER ME +32F1 ; [.3E93.0020.0013] # CIRCLED KATAKANA ME +334D ; [.3E93.0020.001C][.1C73.0020.001C][.3E85.0020.001C][.3E9A.0020.001C] # SQUARE MEETORU +334B ; [.3E93.0020.001C][.3E77.0020.001C][.0000.0037.001C] # SQUARE MEGA +334C ; [.3E93.0020.001C][.3E77.0020.001C][.0000.0037.001C][.3E85.0020.001C][.3EA1.0020.001C] # SQUARE MEGATON +3082 ; [.3E94.0020.000E] # HIRAGANA LETTER MO +30E2 ; [.3E94.0020.0011] # KATAKANA LETTER MO +FF93 ; [.3E94.0020.0012] # HALFWIDTH KATAKANA LETTER MO +32F2 ; [.3E94.0020.0013] # CIRCLED KATAKANA MO +3083 ; [.3E95.0020.000D] # HIRAGANA LETTER SMALL YA +3084 ; [.3E95.0020.000E] # HIRAGANA LETTER YA +30E3 ; [.3E95.0020.000F] # KATAKANA LETTER SMALL YA +FF6C ; [.3E95.0020.0010] # HALFWIDTH KATAKANA LETTER SMALL YA +30E4 ; [.3E95.0020.0011] # KATAKANA LETTER YA +FF94 ; [.3E95.0020.0012] # HALFWIDTH KATAKANA LETTER YA +32F3 ; [.3E95.0020.0013] # CIRCLED KATAKANA YA +334E ; [.3E95.0020.001C][.1C73.0020.001C][.3E85.0020.001C][.0000.0037.001C] # SQUARE YAADO +334F ; [.3E95.0020.001C][.1C73.0020.001C][.3E9A.0020.001C] # SQUARE YAARU +3085 ; [.3E96.0020.000D] # HIRAGANA LETTER SMALL YU +3086 ; [.3E96.0020.000E] # HIRAGANA LETTER YU +30E5 ; [.3E96.0020.000F] # KATAKANA LETTER SMALL YU +FF6D ; [.3E96.0020.0010] # HALFWIDTH KATAKANA LETTER SMALL YU +30E6 ; [.3E96.0020.0011] # KATAKANA LETTER YU +FF95 ; [.3E96.0020.0012] # HALFWIDTH KATAKANA LETTER YU +32F4 ; [.3E96.0020.0013] # CIRCLED KATAKANA YU +3350 ; [.3E96.0020.001C][.3E71.0020.001C][.3EA1.0020.001C] # SQUARE YUAN +3087 ; [.3E97.0020.000D] # HIRAGANA LETTER SMALL YO +3088 ; [.3E97.0020.000E] # HIRAGANA LETTER YO +30E7 ; [.3E97.0020.000F] # KATAKANA LETTER SMALL YO +FF6E ; [.3E97.0020.0010] # HALFWIDTH KATAKANA LETTER SMALL YO +30E8 ; [.3E97.0020.0011] # KATAKANA LETTER YO +FF96 ; [.3E97.0020.0012] # HALFWIDTH KATAKANA LETTER YO +32F5 ; [.3E97.0020.0013] # CIRCLED KATAKANA YO +309F ; [.3E97.0020.0016][.3E99.0020.0016] # HIRAGANA DIGRAPH YORI +3089 ; [.3E98.0020.000E] # HIRAGANA LETTER RA +31FB ; [.3E98.0020.000F] # KATAKANA LETTER SMALL RA +30E9 ; [.3E98.0020.0011] # KATAKANA LETTER RA +FF97 ; [.3E98.0020.0012] # HALFWIDTH KATAKANA LETTER RA +32F6 ; [.3E98.0020.0013] # CIRCLED KATAKANA RA +308A ; [.3E99.0020.000E] # HIRAGANA LETTER RI +31FC ; [.3E99.0020.000F] # KATAKANA LETTER SMALL RI +30EA ; [.3E99.0020.0011] # KATAKANA LETTER RI +FF98 ; [.3E99.0020.0012] # HALFWIDTH KATAKANA LETTER RI +32F7 ; [.3E99.0020.0013] # CIRCLED KATAKANA RI +3351 ; [.3E99.0020.001C][.3E83.0020.001C][.3E85.0020.001C][.3E9A.0020.001C] # SQUARE RITTORU +3352 ; [.3E99.0020.001C][.3E98.0020.001C] # SQUARE RIRA +308B ; [.3E9A.0020.000E] # HIRAGANA LETTER RU +31FD ; [.3E9A.0020.000F] # KATAKANA LETTER SMALL RU +30EB ; [.3E9A.0020.0011] # KATAKANA LETTER RU +FF99 ; [.3E9A.0020.0012] # HALFWIDTH KATAKANA LETTER RU +32F8 ; [.3E9A.0020.0013] # CIRCLED KATAKANA RU +3354 ; [.3E9A.0020.001C][.1C73.0020.001C][.3E8D.0020.001C][.0000.0037.001C][.3E9A.0020.001C] # SQUARE RUUBURU +3353 ; [.3E9A.0020.001C][.3E8C.0020.001C][.0000.0038.001C][.1C73.0020.001C] # SQUARE RUPII +308C ; [.3E9B.0020.000E] # HIRAGANA LETTER RE +31FE ; [.3E9B.0020.000F] # KATAKANA LETTER SMALL RE +30EC ; [.3E9B.0020.0011] # KATAKANA LETTER RE +FF9A ; [.3E9B.0020.0012] # HALFWIDTH KATAKANA LETTER RE +32F9 ; [.3E9B.0020.0013] # CIRCLED KATAKANA RE +3355 ; [.3E9B.0020.001C][.3E92.0020.001C] # SQUARE REMU +3356 ; [.3E9B.0020.001C][.3EA1.0020.001C][.3E85.0020.001C][.3E7A.0020.001C][.0000.0037.001C][.3EA1.0020.001C] # SQUARE RENTOGEN +308D ; [.3E9C.0020.000E] # HIRAGANA LETTER RO +31FF ; [.3E9C.0020.000F] # KATAKANA LETTER SMALL RO +30ED ; [.3E9C.0020.0011] # KATAKANA LETTER RO +FF9B ; [.3E9C.0020.0012] # HALFWIDTH KATAKANA LETTER RO +32FA ; [.3E9C.0020.0013] # CIRCLED KATAKANA RO +308E ; [.3E9D.0020.000D] # HIRAGANA LETTER SMALL WA +308F ; [.3E9D.0020.000E] # HIRAGANA LETTER WA +30EE ; [.3E9D.0020.000F] # KATAKANA LETTER SMALL WA +30EF ; [.3E9D.0020.0011] # KATAKANA LETTER WA +FF9C ; [.3E9D.0020.0012] # HALFWIDTH KATAKANA LETTER WA +32FB ; [.3E9D.0020.0013] # CIRCLED KATAKANA WA +30F7 ; [.3E9D.0020.0011][.0000.0037.0002] # KATAKANA LETTER VA +3357 ; [.3E9D.0020.001C][.3E83.0020.001C][.3E85.0020.001C] # SQUARE WATTO +3090 ; [.3E9E.0020.000E] # HIRAGANA LETTER WI +30F0 ; [.3E9E.0020.0011] # KATAKANA LETTER WI +32FC ; [.3E9E.0020.0013] # CIRCLED KATAKANA WI +30F8 ; [.3E9E.0020.0011][.0000.0037.0002] # KATAKANA LETTER VI +3091 ; [.3E9F.0020.000E] # HIRAGANA LETTER WE +30F1 ; [.3E9F.0020.0011] # KATAKANA LETTER WE +32FD ; [.3E9F.0020.0013] # CIRCLED KATAKANA WE +30F9 ; [.3E9F.0020.0011][.0000.0037.0002] # KATAKANA LETTER VE +3092 ; [.3EA0.0020.000E] # HIRAGANA LETTER WO +30F2 ; [.3EA0.0020.0011] # KATAKANA LETTER WO +FF66 ; [.3EA0.0020.0012] # HALFWIDTH KATAKANA LETTER WO +32FE ; [.3EA0.0020.0013] # CIRCLED KATAKANA WO +30FA ; [.3EA0.0020.0011][.0000.0037.0002] # KATAKANA LETTER VO +3093 ; [.3EA1.0020.000E] # HIRAGANA LETTER N +30F3 ; [.3EA1.0020.0011] # KATAKANA LETTER N +FF9D ; [.3EA1.0020.0012] # HALFWIDTH KATAKANA LETTER N +1B002 ; [.3EA2.0020.0002] # HENTAIGANA LETTER A-1 +1B003 ; [.3EA3.0020.0002] # HENTAIGANA LETTER A-2 +1B004 ; [.3EA4.0020.0002] # HENTAIGANA LETTER A-3 +1B005 ; [.3EA5.0020.0002] # HENTAIGANA LETTER A-WO +1B006 ; [.3EA6.0020.0002] # HENTAIGANA LETTER I-1 +1B007 ; [.3EA7.0020.0002] # HENTAIGANA LETTER I-2 +1B008 ; [.3EA8.0020.0002] # HENTAIGANA LETTER I-3 +1B009 ; [.3EA9.0020.0002] # HENTAIGANA LETTER I-4 +1B00A ; [.3EAA.0020.0002] # HENTAIGANA LETTER U-1 +1B00B ; [.3EAB.0020.0002] # HENTAIGANA LETTER U-2 +1B00C ; [.3EAC.0020.0002] # HENTAIGANA LETTER U-3 +1B00D ; [.3EAD.0020.0002] # HENTAIGANA LETTER U-4 +1B00E ; [.3EAE.0020.0002] # HENTAIGANA LETTER U-5 +1B001 ; [.3EAF.0020.0002] # HIRAGANA LETTER ARCHAIC YE +1B00F ; [.3EB0.0020.0002] # HENTAIGANA LETTER E-2 +1B010 ; [.3EB1.0020.0002] # HENTAIGANA LETTER E-3 +1B011 ; [.3EB2.0020.0002] # HENTAIGANA LETTER E-4 +1B012 ; [.3EB3.0020.0002] # HENTAIGANA LETTER E-5 +1B013 ; [.3EB4.0020.0002] # HENTAIGANA LETTER E-6 +1B014 ; [.3EB5.0020.0002] # HENTAIGANA LETTER O-1 +1B015 ; [.3EB6.0020.0002] # HENTAIGANA LETTER O-2 +1B016 ; [.3EB7.0020.0002] # HENTAIGANA LETTER O-3 +1B017 ; [.3EB8.0020.0002] # HENTAIGANA LETTER KA-1 +1B018 ; [.3EB9.0020.0002] # HENTAIGANA LETTER KA-2 +1B019 ; [.3EBA.0020.0002] # HENTAIGANA LETTER KA-3 +1B01A ; [.3EBB.0020.0002] # HENTAIGANA LETTER KA-4 +1B01B ; [.3EBC.0020.0002] # HENTAIGANA LETTER KA-5 +1B01C ; [.3EBD.0020.0002] # HENTAIGANA LETTER KA-6 +1B01D ; [.3EBE.0020.0002] # HENTAIGANA LETTER KA-7 +1B01E ; [.3EBF.0020.0002] # HENTAIGANA LETTER KA-8 +1B01F ; [.3EC0.0020.0002] # HENTAIGANA LETTER KA-9 +1B020 ; [.3EC1.0020.0002] # HENTAIGANA LETTER KA-10 +1B021 ; [.3EC2.0020.0002] # HENTAIGANA LETTER KA-11 +1B022 ; [.3EC3.0020.0002] # HENTAIGANA LETTER KA-KE +1B023 ; [.3EC4.0020.0002] # HENTAIGANA LETTER KI-1 +1B024 ; [.3EC5.0020.0002] # HENTAIGANA LETTER KI-2 +1B025 ; [.3EC6.0020.0002] # HENTAIGANA LETTER KI-3 +1B026 ; [.3EC7.0020.0002] # HENTAIGANA LETTER KI-4 +1B027 ; [.3EC8.0020.0002] # HENTAIGANA LETTER KI-5 +1B028 ; [.3EC9.0020.0002] # HENTAIGANA LETTER KI-6 +1B029 ; [.3ECA.0020.0002] # HENTAIGANA LETTER KI-7 +1B02A ; [.3ECB.0020.0002] # HENTAIGANA LETTER KI-8 +1B02B ; [.3ECC.0020.0002] # HENTAIGANA LETTER KU-1 +1B02C ; [.3ECD.0020.0002] # HENTAIGANA LETTER KU-2 +1B02D ; [.3ECE.0020.0002] # HENTAIGANA LETTER KU-3 +1B02E ; [.3ECF.0020.0002] # HENTAIGANA LETTER KU-4 +1B02F ; [.3ED0.0020.0002] # HENTAIGANA LETTER KU-5 +1B030 ; [.3ED1.0020.0002] # HENTAIGANA LETTER KU-6 +1B031 ; [.3ED2.0020.0002] # HENTAIGANA LETTER KU-7 +1B032 ; [.3ED3.0020.0002] # HENTAIGANA LETTER KE-1 +1B033 ; [.3ED4.0020.0002] # HENTAIGANA LETTER KE-2 +1B034 ; [.3ED5.0020.0002] # HENTAIGANA LETTER KE-3 +1B035 ; [.3ED6.0020.0002] # HENTAIGANA LETTER KE-4 +1B036 ; [.3ED7.0020.0002] # HENTAIGANA LETTER KE-5 +1B037 ; [.3ED8.0020.0002] # HENTAIGANA LETTER KE-6 +1B038 ; [.3ED9.0020.0002] # HENTAIGANA LETTER KO-1 +1B039 ; [.3EDA.0020.0002] # HENTAIGANA LETTER KO-2 +1B03A ; [.3EDB.0020.0002] # HENTAIGANA LETTER KO-3 +1B03B ; [.3EDC.0020.0002] # HENTAIGANA LETTER KO-KI +1B03C ; [.3EDD.0020.0002] # HENTAIGANA LETTER SA-1 +1B03D ; [.3EDE.0020.0002] # HENTAIGANA LETTER SA-2 +1B03E ; [.3EDF.0020.0002] # HENTAIGANA LETTER SA-3 +1B03F ; [.3EE0.0020.0002] # HENTAIGANA LETTER SA-4 +1B040 ; [.3EE1.0020.0002] # HENTAIGANA LETTER SA-5 +1B041 ; [.3EE2.0020.0002] # HENTAIGANA LETTER SA-6 +1B042 ; [.3EE3.0020.0002] # HENTAIGANA LETTER SA-7 +1B043 ; [.3EE4.0020.0002] # HENTAIGANA LETTER SA-8 +1B044 ; [.3EE5.0020.0002] # HENTAIGANA LETTER SI-1 +1B045 ; [.3EE6.0020.0002] # HENTAIGANA LETTER SI-2 +1B046 ; [.3EE7.0020.0002] # HENTAIGANA LETTER SI-3 +1B047 ; [.3EE8.0020.0002] # HENTAIGANA LETTER SI-4 +1B048 ; [.3EE9.0020.0002] # HENTAIGANA LETTER SI-5 +1B049 ; [.3EEA.0020.0002] # HENTAIGANA LETTER SI-6 +1B04A ; [.3EEB.0020.0002] # HENTAIGANA LETTER SU-1 +1B04B ; [.3EEC.0020.0002] # HENTAIGANA LETTER SU-2 +1B04C ; [.3EED.0020.0002] # HENTAIGANA LETTER SU-3 +1B04D ; [.3EEE.0020.0002] # HENTAIGANA LETTER SU-4 +1B04E ; [.3EEF.0020.0002] # HENTAIGANA LETTER SU-5 +1B04F ; [.3EF0.0020.0002] # HENTAIGANA LETTER SU-6 +1B050 ; [.3EF1.0020.0002] # HENTAIGANA LETTER SU-7 +1B051 ; [.3EF2.0020.0002] # HENTAIGANA LETTER SU-8 +1B052 ; [.3EF3.0020.0002] # HENTAIGANA LETTER SE-1 +1B053 ; [.3EF4.0020.0002] # HENTAIGANA LETTER SE-2 +1B054 ; [.3EF5.0020.0002] # HENTAIGANA LETTER SE-3 +1B055 ; [.3EF6.0020.0002] # HENTAIGANA LETTER SE-4 +1B056 ; [.3EF7.0020.0002] # HENTAIGANA LETTER SE-5 +1B057 ; [.3EF8.0020.0002] # HENTAIGANA LETTER SO-1 +1B058 ; [.3EF9.0020.0002] # HENTAIGANA LETTER SO-2 +1B059 ; [.3EFA.0020.0002] # HENTAIGANA LETTER SO-3 +1B05A ; [.3EFB.0020.0002] # HENTAIGANA LETTER SO-4 +1B05B ; [.3EFC.0020.0002] # HENTAIGANA LETTER SO-5 +1B05C ; [.3EFD.0020.0002] # HENTAIGANA LETTER SO-6 +1B05D ; [.3EFE.0020.0002] # HENTAIGANA LETTER SO-7 +1B05E ; [.3EFF.0020.0002] # HENTAIGANA LETTER TA-1 +1B05F ; [.3F00.0020.0002] # HENTAIGANA LETTER TA-2 +1B060 ; [.3F01.0020.0002] # HENTAIGANA LETTER TA-3 +1B061 ; [.3F02.0020.0002] # HENTAIGANA LETTER TA-4 +1B062 ; [.3F03.0020.0002] # HENTAIGANA LETTER TI-1 +1B063 ; [.3F04.0020.0002] # HENTAIGANA LETTER TI-2 +1B064 ; [.3F05.0020.0002] # HENTAIGANA LETTER TI-3 +1B065 ; [.3F06.0020.0002] # HENTAIGANA LETTER TI-4 +1B066 ; [.3F07.0020.0002] # HENTAIGANA LETTER TI-5 +1B067 ; [.3F08.0020.0002] # HENTAIGANA LETTER TI-6 +1B068 ; [.3F09.0020.0002] # HENTAIGANA LETTER TI-7 +1B069 ; [.3F0A.0020.0002] # HENTAIGANA LETTER TU-1 +1B06A ; [.3F0B.0020.0002] # HENTAIGANA LETTER TU-2 +1B06B ; [.3F0C.0020.0002] # HENTAIGANA LETTER TU-3 +1B06C ; [.3F0D.0020.0002] # HENTAIGANA LETTER TU-4 +1B06D ; [.3F0E.0020.0002] # HENTAIGANA LETTER TU-TO +1B06E ; [.3F0F.0020.0002] # HENTAIGANA LETTER TE-1 +1B06F ; [.3F10.0020.0002] # HENTAIGANA LETTER TE-2 +1B070 ; [.3F11.0020.0002] # HENTAIGANA LETTER TE-3 +1B071 ; [.3F12.0020.0002] # HENTAIGANA LETTER TE-4 +1B072 ; [.3F13.0020.0002] # HENTAIGANA LETTER TE-5 +1B073 ; [.3F14.0020.0002] # HENTAIGANA LETTER TE-6 +1B074 ; [.3F15.0020.0002] # HENTAIGANA LETTER TE-7 +1B075 ; [.3F16.0020.0002] # HENTAIGANA LETTER TE-8 +1B076 ; [.3F17.0020.0002] # HENTAIGANA LETTER TE-9 +1B077 ; [.3F18.0020.0002] # HENTAIGANA LETTER TO-1 +1B078 ; [.3F19.0020.0002] # HENTAIGANA LETTER TO-2 +1B079 ; [.3F1A.0020.0002] # HENTAIGANA LETTER TO-3 +1B07A ; [.3F1B.0020.0002] # HENTAIGANA LETTER TO-4 +1B07B ; [.3F1C.0020.0002] # HENTAIGANA LETTER TO-5 +1B07C ; [.3F1D.0020.0002] # HENTAIGANA LETTER TO-6 +1B07D ; [.3F1E.0020.0002] # HENTAIGANA LETTER TO-RA +1B07E ; [.3F1F.0020.0002] # HENTAIGANA LETTER NA-1 +1B07F ; [.3F20.0020.0002] # HENTAIGANA LETTER NA-2 +1B080 ; [.3F21.0020.0002] # HENTAIGANA LETTER NA-3 +1B081 ; [.3F22.0020.0002] # HENTAIGANA LETTER NA-4 +1B082 ; [.3F23.0020.0002] # HENTAIGANA LETTER NA-5 +1B083 ; [.3F24.0020.0002] # HENTAIGANA LETTER NA-6 +1B084 ; [.3F25.0020.0002] # HENTAIGANA LETTER NA-7 +1B085 ; [.3F26.0020.0002] # HENTAIGANA LETTER NA-8 +1B086 ; [.3F27.0020.0002] # HENTAIGANA LETTER NA-9 +1B087 ; [.3F28.0020.0002] # HENTAIGANA LETTER NI-1 +1B088 ; [.3F29.0020.0002] # HENTAIGANA LETTER NI-2 +1B089 ; [.3F2A.0020.0002] # HENTAIGANA LETTER NI-3 +1B08A ; [.3F2B.0020.0002] # HENTAIGANA LETTER NI-4 +1B08B ; [.3F2C.0020.0002] # HENTAIGANA LETTER NI-5 +1B08C ; [.3F2D.0020.0002] # HENTAIGANA LETTER NI-6 +1B08D ; [.3F2E.0020.0002] # HENTAIGANA LETTER NI-7 +1B08E ; [.3F2F.0020.0002] # HENTAIGANA LETTER NI-TE +1B08F ; [.3F30.0020.0002] # HENTAIGANA LETTER NU-1 +1B090 ; [.3F31.0020.0002] # HENTAIGANA LETTER NU-2 +1B091 ; [.3F32.0020.0002] # HENTAIGANA LETTER NU-3 +1B092 ; [.3F33.0020.0002] # HENTAIGANA LETTER NE-1 +1B093 ; [.3F34.0020.0002] # HENTAIGANA LETTER NE-2 +1B094 ; [.3F35.0020.0002] # HENTAIGANA LETTER NE-3 +1B095 ; [.3F36.0020.0002] # HENTAIGANA LETTER NE-4 +1B096 ; [.3F37.0020.0002] # HENTAIGANA LETTER NE-5 +1B097 ; [.3F38.0020.0002] # HENTAIGANA LETTER NE-6 +1B098 ; [.3F39.0020.0002] # HENTAIGANA LETTER NE-KO +1B099 ; [.3F3A.0020.0002] # HENTAIGANA LETTER NO-1 +1B09A ; [.3F3B.0020.0002] # HENTAIGANA LETTER NO-2 +1B09B ; [.3F3C.0020.0002] # HENTAIGANA LETTER NO-3 +1B09C ; [.3F3D.0020.0002] # HENTAIGANA LETTER NO-4 +1B09D ; [.3F3E.0020.0002] # HENTAIGANA LETTER NO-5 +1B09E ; [.3F3F.0020.0002] # HENTAIGANA LETTER HA-1 +1B09F ; [.3F40.0020.0002] # HENTAIGANA LETTER HA-2 +1B0A0 ; [.3F41.0020.0002] # HENTAIGANA LETTER HA-3 +1B0A1 ; [.3F42.0020.0002] # HENTAIGANA LETTER HA-4 +1B0A2 ; [.3F43.0020.0002] # HENTAIGANA LETTER HA-5 +1B0A3 ; [.3F44.0020.0002] # HENTAIGANA LETTER HA-6 +1B0A4 ; [.3F45.0020.0002] # HENTAIGANA LETTER HA-7 +1B0A5 ; [.3F46.0020.0002] # HENTAIGANA LETTER HA-8 +1B0A6 ; [.3F47.0020.0002] # HENTAIGANA LETTER HA-9 +1B0A7 ; [.3F48.0020.0002] # HENTAIGANA LETTER HA-10 +1B0A8 ; [.3F49.0020.0002] # HENTAIGANA LETTER HA-11 +1B0A9 ; [.3F4A.0020.0002] # HENTAIGANA LETTER HI-1 +1B0AA ; [.3F4B.0020.0002] # HENTAIGANA LETTER HI-2 +1B0AB ; [.3F4C.0020.0002] # HENTAIGANA LETTER HI-3 +1B0AC ; [.3F4D.0020.0002] # HENTAIGANA LETTER HI-4 +1B0AD ; [.3F4E.0020.0002] # HENTAIGANA LETTER HI-5 +1B0AE ; [.3F4F.0020.0002] # HENTAIGANA LETTER HI-6 +1B0AF ; [.3F50.0020.0002] # HENTAIGANA LETTER HI-7 +1B0B0 ; [.3F51.0020.0002] # HENTAIGANA LETTER HU-1 +1B0B1 ; [.3F52.0020.0002] # HENTAIGANA LETTER HU-2 +1B0B2 ; [.3F53.0020.0002] # HENTAIGANA LETTER HU-3 +1B0B3 ; [.3F54.0020.0002] # HENTAIGANA LETTER HE-1 +1B0B4 ; [.3F55.0020.0002] # HENTAIGANA LETTER HE-2 +1B0B5 ; [.3F56.0020.0002] # HENTAIGANA LETTER HE-3 +1B0B6 ; [.3F57.0020.0002] # HENTAIGANA LETTER HE-4 +1B0B7 ; [.3F58.0020.0002] # HENTAIGANA LETTER HE-5 +1B0B8 ; [.3F59.0020.0002] # HENTAIGANA LETTER HE-6 +1B0B9 ; [.3F5A.0020.0002] # HENTAIGANA LETTER HE-7 +1B0BA ; [.3F5B.0020.0002] # HENTAIGANA LETTER HO-1 +1B0BB ; [.3F5C.0020.0002] # HENTAIGANA LETTER HO-2 +1B0BC ; [.3F5D.0020.0002] # HENTAIGANA LETTER HO-3 +1B0BD ; [.3F5E.0020.0002] # HENTAIGANA LETTER HO-4 +1B0BE ; [.3F5F.0020.0002] # HENTAIGANA LETTER HO-5 +1B0BF ; [.3F60.0020.0002] # HENTAIGANA LETTER HO-6 +1B0C0 ; [.3F61.0020.0002] # HENTAIGANA LETTER HO-7 +1B0C1 ; [.3F62.0020.0002] # HENTAIGANA LETTER HO-8 +1B0C2 ; [.3F63.0020.0002] # HENTAIGANA LETTER MA-1 +1B0C3 ; [.3F64.0020.0002] # HENTAIGANA LETTER MA-2 +1B0C4 ; [.3F65.0020.0002] # HENTAIGANA LETTER MA-3 +1B0C5 ; [.3F66.0020.0002] # HENTAIGANA LETTER MA-4 +1B0C6 ; [.3F67.0020.0002] # HENTAIGANA LETTER MA-5 +1B0C7 ; [.3F68.0020.0002] # HENTAIGANA LETTER MA-6 +1B0C8 ; [.3F69.0020.0002] # HENTAIGANA LETTER MA-7 +1B0C9 ; [.3F6A.0020.0002] # HENTAIGANA LETTER MI-1 +1B0CA ; [.3F6B.0020.0002] # HENTAIGANA LETTER MI-2 +1B0CB ; [.3F6C.0020.0002] # HENTAIGANA LETTER MI-3 +1B0CC ; [.3F6D.0020.0002] # HENTAIGANA LETTER MI-4 +1B0CD ; [.3F6E.0020.0002] # HENTAIGANA LETTER MI-5 +1B0CE ; [.3F6F.0020.0002] # HENTAIGANA LETTER MI-6 +1B0CF ; [.3F70.0020.0002] # HENTAIGANA LETTER MI-7 +1B0D0 ; [.3F71.0020.0002] # HENTAIGANA LETTER MU-1 +1B0D1 ; [.3F72.0020.0002] # HENTAIGANA LETTER MU-2 +1B0D2 ; [.3F73.0020.0002] # HENTAIGANA LETTER MU-3 +1B0D3 ; [.3F74.0020.0002] # HENTAIGANA LETTER MU-4 +1B0D4 ; [.3F75.0020.0002] # HENTAIGANA LETTER ME-1 +1B0D5 ; [.3F76.0020.0002] # HENTAIGANA LETTER ME-2 +1B0D6 ; [.3F77.0020.0002] # HENTAIGANA LETTER ME-MA +1B0D7 ; [.3F78.0020.0002] # HENTAIGANA LETTER MO-1 +1B0D8 ; [.3F79.0020.0002] # HENTAIGANA LETTER MO-2 +1B0D9 ; [.3F7A.0020.0002] # HENTAIGANA LETTER MO-3 +1B0DA ; [.3F7B.0020.0002] # HENTAIGANA LETTER MO-4 +1B0DB ; [.3F7C.0020.0002] # HENTAIGANA LETTER MO-5 +1B0DC ; [.3F7D.0020.0002] # HENTAIGANA LETTER MO-6 +1B0DD ; [.3F7E.0020.0002] # HENTAIGANA LETTER YA-1 +1B0DE ; [.3F7F.0020.0002] # HENTAIGANA LETTER YA-2 +1B0DF ; [.3F80.0020.0002] # HENTAIGANA LETTER YA-3 +1B0E0 ; [.3F81.0020.0002] # HENTAIGANA LETTER YA-4 +1B0E1 ; [.3F82.0020.0002] # HENTAIGANA LETTER YA-5 +1B0E2 ; [.3F83.0020.0002] # HENTAIGANA LETTER YA-YO +1B0E3 ; [.3F84.0020.0002] # HENTAIGANA LETTER YU-1 +1B0E4 ; [.3F85.0020.0002] # HENTAIGANA LETTER YU-2 +1B0E5 ; [.3F86.0020.0002] # HENTAIGANA LETTER YU-3 +1B0E6 ; [.3F87.0020.0002] # HENTAIGANA LETTER YU-4 +1B0E7 ; [.3F88.0020.0002] # HENTAIGANA LETTER YO-1 +1B0E8 ; [.3F89.0020.0002] # HENTAIGANA LETTER YO-2 +1B0E9 ; [.3F8A.0020.0002] # HENTAIGANA LETTER YO-3 +1B0EA ; [.3F8B.0020.0002] # HENTAIGANA LETTER YO-4 +1B0EB ; [.3F8C.0020.0002] # HENTAIGANA LETTER YO-5 +1B0EC ; [.3F8D.0020.0002] # HENTAIGANA LETTER YO-6 +1B0ED ; [.3F8E.0020.0002] # HENTAIGANA LETTER RA-1 +1B0EE ; [.3F8F.0020.0002] # HENTAIGANA LETTER RA-2 +1B0EF ; [.3F90.0020.0002] # HENTAIGANA LETTER RA-3 +1B0F0 ; [.3F91.0020.0002] # HENTAIGANA LETTER RA-4 +1B0F1 ; [.3F92.0020.0002] # HENTAIGANA LETTER RI-1 +1B0F2 ; [.3F93.0020.0002] # HENTAIGANA LETTER RI-2 +1B0F3 ; [.3F94.0020.0002] # HENTAIGANA LETTER RI-3 +1B0F4 ; [.3F95.0020.0002] # HENTAIGANA LETTER RI-4 +1B0F5 ; [.3F96.0020.0002] # HENTAIGANA LETTER RI-5 +1B0F6 ; [.3F97.0020.0002] # HENTAIGANA LETTER RI-6 +1B0F7 ; [.3F98.0020.0002] # HENTAIGANA LETTER RI-7 +1B0F8 ; [.3F99.0020.0002] # HENTAIGANA LETTER RU-1 +1B0F9 ; [.3F9A.0020.0002] # HENTAIGANA LETTER RU-2 +1B0FA ; [.3F9B.0020.0002] # HENTAIGANA LETTER RU-3 +1B0FB ; [.3F9C.0020.0002] # HENTAIGANA LETTER RU-4 +1B0FC ; [.3F9D.0020.0002] # HENTAIGANA LETTER RU-5 +1B0FD ; [.3F9E.0020.0002] # HENTAIGANA LETTER RU-6 +1B0FE ; [.3F9F.0020.0002] # HENTAIGANA LETTER RE-1 +1B0FF ; [.3FA0.0020.0002] # HENTAIGANA LETTER RE-2 +1B100 ; [.3FA1.0020.0002] # HENTAIGANA LETTER RE-3 +1B101 ; [.3FA2.0020.0002] # HENTAIGANA LETTER RE-4 +1B102 ; [.3FA3.0020.0002] # HENTAIGANA LETTER RO-1 +1B103 ; [.3FA4.0020.0002] # HENTAIGANA LETTER RO-2 +1B104 ; [.3FA5.0020.0002] # HENTAIGANA LETTER RO-3 +1B105 ; [.3FA6.0020.0002] # HENTAIGANA LETTER RO-4 +1B106 ; [.3FA7.0020.0002] # HENTAIGANA LETTER RO-5 +1B107 ; [.3FA8.0020.0002] # HENTAIGANA LETTER RO-6 +1B108 ; [.3FA9.0020.0002] # HENTAIGANA LETTER WA-1 +1B109 ; [.3FAA.0020.0002] # HENTAIGANA LETTER WA-2 +1B10A ; [.3FAB.0020.0002] # HENTAIGANA LETTER WA-3 +1B10B ; [.3FAC.0020.0002] # HENTAIGANA LETTER WA-4 +1B10C ; [.3FAD.0020.0002] # HENTAIGANA LETTER WA-5 +1B10D ; [.3FAE.0020.0002] # HENTAIGANA LETTER WI-1 +1B10E ; [.3FAF.0020.0002] # HENTAIGANA LETTER WI-2 +1B10F ; [.3FB0.0020.0002] # HENTAIGANA LETTER WI-3 +1B110 ; [.3FB1.0020.0002] # HENTAIGANA LETTER WI-4 +1B111 ; [.3FB2.0020.0002] # HENTAIGANA LETTER WI-5 +1B112 ; [.3FB3.0020.0002] # HENTAIGANA LETTER WE-1 +1B113 ; [.3FB4.0020.0002] # HENTAIGANA LETTER WE-2 +1B114 ; [.3FB5.0020.0002] # HENTAIGANA LETTER WE-3 +1B115 ; [.3FB6.0020.0002] # HENTAIGANA LETTER WE-4 +1B116 ; [.3FB7.0020.0002] # HENTAIGANA LETTER WO-1 +1B117 ; [.3FB8.0020.0002] # HENTAIGANA LETTER WO-2 +1B118 ; [.3FB9.0020.0002] # HENTAIGANA LETTER WO-3 +1B119 ; [.3FBA.0020.0002] # HENTAIGANA LETTER WO-4 +1B11A ; [.3FBB.0020.0002] # HENTAIGANA LETTER WO-5 +1B11B ; [.3FBC.0020.0002] # HENTAIGANA LETTER WO-6 +1B11C ; [.3FBD.0020.0002] # HENTAIGANA LETTER WO-7 +1B11D ; [.3FBE.0020.0002] # HENTAIGANA LETTER N-MU-MO-1 +1B11E ; [.3FBF.0020.0002] # HENTAIGANA LETTER N-MU-MO-2 +3105 ; [.3FC0.0020.0002] # BOPOMOFO LETTER B +31A0 ; [.3FC0.0020.0004][.0000.0112.0004] # BOPOMOFO LETTER BU +3106 ; [.3FC1.0020.0002] # BOPOMOFO LETTER P +31B4 ; [.3FC1.0020.0019] # BOPOMOFO FINAL LETTER P +3107 ; [.3FC2.0020.0002] # BOPOMOFO LETTER M +3108 ; [.3FC3.0020.0002] # BOPOMOFO LETTER F +312A ; [.3FC4.0020.0002] # BOPOMOFO LETTER V +3109 ; [.3FC5.0020.0002] # BOPOMOFO LETTER D +310A ; [.3FC6.0020.0002] # BOPOMOFO LETTER T +31B5 ; [.3FC6.0020.0019] # BOPOMOFO FINAL LETTER T +310B ; [.3FC7.0020.0002] # BOPOMOFO LETTER N +310C ; [.3FC8.0020.0002] # BOPOMOFO LETTER L +310D ; [.3FC9.0020.0002] # BOPOMOFO LETTER G +31A3 ; [.3FC9.0020.0004][.0000.0112.0004] # BOPOMOFO LETTER GU +310E ; [.3FCA.0020.0002] # BOPOMOFO LETTER K +31B6 ; [.3FCA.0020.0019] # BOPOMOFO FINAL LETTER K +312B ; [.3FCB.0020.0002] # BOPOMOFO LETTER NG +31AD ; [.3FCC.0020.0002] # BOPOMOFO LETTER NGG +310F ; [.3FCD.0020.0002] # BOPOMOFO LETTER H +31B7 ; [.3FCD.0020.0019] # BOPOMOFO FINAL LETTER H +3110 ; [.3FCE.0020.0002] # BOPOMOFO LETTER J +31A2 ; [.3FCE.0020.0004][.0000.0112.0004] # BOPOMOFO LETTER JI +3111 ; [.3FCF.0020.0002] # BOPOMOFO LETTER Q +3112 ; [.3FD0.0020.0002] # BOPOMOFO LETTER X +312C ; [.3FD1.0020.0002] # BOPOMOFO LETTER GN +3113 ; [.3FD2.0020.0002] # BOPOMOFO LETTER ZH +3114 ; [.3FD3.0020.0002] # BOPOMOFO LETTER CH +3115 ; [.3FD4.0020.0002] # BOPOMOFO LETTER SH +3116 ; [.3FD5.0020.0002] # BOPOMOFO LETTER R +3117 ; [.3FD6.0020.0002] # BOPOMOFO LETTER Z +31A1 ; [.3FD6.0020.0004][.0000.0112.0004] # BOPOMOFO LETTER ZI +3118 ; [.3FD7.0020.0002] # BOPOMOFO LETTER C +3119 ; [.3FD8.0020.0002] # BOPOMOFO LETTER S +31B8 ; [.3FD9.0020.0002] # BOPOMOFO LETTER GH +31B9 ; [.3FDA.0020.0002] # BOPOMOFO LETTER LH +31BA ; [.3FDB.0020.0002] # BOPOMOFO LETTER ZY +311A ; [.3FDC.0020.0002] # BOPOMOFO LETTER A +31A9 ; [.3FDC.0020.0004][.0000.0112.0004] # BOPOMOFO LETTER ANN +311B ; [.3FDD.0020.0002] # BOPOMOFO LETTER O +31A7 ; [.3FDD.0020.0004][.0000.0112.0004] # BOPOMOFO LETTER ONN +31A6 ; [.3FDE.0020.0002] # BOPOMOFO LETTER OO +311C ; [.3FDF.0020.0002] # BOPOMOFO LETTER E +312E ; [.3FDF.0020.0004] # BOPOMOFO LETTER O WITH DOT ABOVE +311D ; [.3FE0.0020.0002] # BOPOMOFO LETTER EH +31A4 ; [.3FE1.0020.0002] # BOPOMOFO LETTER EE +31A5 ; [.3FE1.0020.0004][.0000.0112.0004] # BOPOMOFO LETTER ENN +311E ; [.3FE2.0020.0002] # BOPOMOFO LETTER AI +31AE ; [.3FE2.0020.0004][.0000.0112.0004] # BOPOMOFO LETTER AINN +311F ; [.3FE3.0020.0002] # BOPOMOFO LETTER EI +3120 ; [.3FE4.0020.0002] # BOPOMOFO LETTER AU +31AF ; [.3FE4.0020.0004][.0000.0112.0004] # BOPOMOFO LETTER AUNN +3121 ; [.3FE5.0020.0002] # BOPOMOFO LETTER OU +3122 ; [.3FE6.0020.0002] # BOPOMOFO LETTER AN +3123 ; [.3FE7.0020.0002] # BOPOMOFO LETTER EN +3124 ; [.3FE8.0020.0002] # BOPOMOFO LETTER ANG +31B2 ; [.3FE9.0020.0002] # BOPOMOFO LETTER ONG +3125 ; [.3FEA.0020.0002] # BOPOMOFO LETTER ENG +31B0 ; [.3FEB.0020.0002] # BOPOMOFO LETTER AM +31B1 ; [.3FEC.0020.0002] # BOPOMOFO LETTER OM +31AC ; [.3FED.0020.0002] # BOPOMOFO LETTER IM +3126 ; [.3FEE.0020.0002] # BOPOMOFO LETTER ER +3127 ; [.3FEF.0020.0002] # BOPOMOFO LETTER I +31AA ; [.3FEF.0020.0004][.0000.0112.0004] # BOPOMOFO LETTER INN +31B3 ; [.3FEF.0020.0016][.0000.0112.0016] # BOPOMOFO LETTER INNN +3128 ; [.3FF0.0020.0002] # BOPOMOFO LETTER U +31AB ; [.3FF0.0020.0004][.0000.0112.0004] # BOPOMOFO LETTER UNN +31A8 ; [.3FF0.0020.0004][.0000.0113.0004] # BOPOMOFO LETTER IR +3129 ; [.3FF1.0020.0002] # BOPOMOFO LETTER IU +312D ; [.3FF2.0020.0002] # BOPOMOFO LETTER IH +A000 ; [.3FF3.0020.0002] # YI SYLLABLE IT +A001 ; [.3FF4.0020.0002] # YI SYLLABLE IX +A002 ; [.3FF5.0020.0002] # YI SYLLABLE I +A003 ; [.3FF6.0020.0002] # YI SYLLABLE IP +A004 ; [.3FF7.0020.0002] # YI SYLLABLE IET +A005 ; [.3FF8.0020.0002] # YI SYLLABLE IEX +A006 ; [.3FF9.0020.0002] # YI SYLLABLE IE +A007 ; [.3FFA.0020.0002] # YI SYLLABLE IEP +A008 ; [.3FFB.0020.0002] # YI SYLLABLE AT +A009 ; [.3FFC.0020.0002] # YI SYLLABLE AX +A00A ; [.3FFD.0020.0002] # YI SYLLABLE A +A00B ; [.3FFE.0020.0002] # YI SYLLABLE AP +A00C ; [.3FFF.0020.0002] # YI SYLLABLE UOX +A00D ; [.4000.0020.0002] # YI SYLLABLE UO +A00E ; [.4001.0020.0002] # YI SYLLABLE UOP +A00F ; [.4002.0020.0002] # YI SYLLABLE OT +A010 ; [.4003.0020.0002] # YI SYLLABLE OX +A011 ; [.4004.0020.0002] # YI SYLLABLE O +A012 ; [.4005.0020.0002] # YI SYLLABLE OP +A013 ; [.4006.0020.0002] # YI SYLLABLE EX +A014 ; [.4007.0020.0002] # YI SYLLABLE E +A015 ; [.4008.0020.0002] # YI SYLLABLE WU +A016 ; [.4009.0020.0002] # YI SYLLABLE BIT +A017 ; [.400A.0020.0002] # YI SYLLABLE BIX +A018 ; [.400B.0020.0002] # YI SYLLABLE BI +A019 ; [.400C.0020.0002] # YI SYLLABLE BIP +A01A ; [.400D.0020.0002] # YI SYLLABLE BIET +A01B ; [.400E.0020.0002] # YI SYLLABLE BIEX +A01C ; [.400F.0020.0002] # YI SYLLABLE BIE +A01D ; [.4010.0020.0002] # YI SYLLABLE BIEP +A01E ; [.4011.0020.0002] # YI SYLLABLE BAT +A01F ; [.4012.0020.0002] # YI SYLLABLE BAX +A020 ; [.4013.0020.0002] # YI SYLLABLE BA +A021 ; [.4014.0020.0002] # YI SYLLABLE BAP +A022 ; [.4015.0020.0002] # YI SYLLABLE BUOX +A023 ; [.4016.0020.0002] # YI SYLLABLE BUO +A024 ; [.4017.0020.0002] # YI SYLLABLE BUOP +A025 ; [.4018.0020.0002] # YI SYLLABLE BOT +A026 ; [.4019.0020.0002] # YI SYLLABLE BOX +A027 ; [.401A.0020.0002] # YI SYLLABLE BO +A028 ; [.401B.0020.0002] # YI SYLLABLE BOP +A029 ; [.401C.0020.0002] # YI SYLLABLE BEX +A02A ; [.401D.0020.0002] # YI SYLLABLE BE +A02B ; [.401E.0020.0002] # YI SYLLABLE BEP +A02C ; [.401F.0020.0002] # YI SYLLABLE BUT +A02D ; [.4020.0020.0002] # YI SYLLABLE BUX +A02E ; [.4021.0020.0002] # YI SYLLABLE BU +A02F ; [.4022.0020.0002] # YI SYLLABLE BUP +A030 ; [.4023.0020.0002] # YI SYLLABLE BURX +A031 ; [.4024.0020.0002] # YI SYLLABLE BUR +A032 ; [.4025.0020.0002] # YI SYLLABLE BYT +A033 ; [.4026.0020.0002] # YI SYLLABLE BYX +A034 ; [.4027.0020.0002] # YI SYLLABLE BY +A035 ; [.4028.0020.0002] # YI SYLLABLE BYP +A036 ; [.4029.0020.0002] # YI SYLLABLE BYRX +A037 ; [.402A.0020.0002] # YI SYLLABLE BYR +A038 ; [.402B.0020.0002] # YI SYLLABLE PIT +A039 ; [.402C.0020.0002] # YI SYLLABLE PIX +A03A ; [.402D.0020.0002] # YI SYLLABLE PI +A03B ; [.402E.0020.0002] # YI SYLLABLE PIP +A03C ; [.402F.0020.0002] # YI SYLLABLE PIEX +A03D ; [.4030.0020.0002] # YI SYLLABLE PIE +A03E ; [.4031.0020.0002] # YI SYLLABLE PIEP +A03F ; [.4032.0020.0002] # YI SYLLABLE PAT +A040 ; [.4033.0020.0002] # YI SYLLABLE PAX +A041 ; [.4034.0020.0002] # YI SYLLABLE PA +A042 ; [.4035.0020.0002] # YI SYLLABLE PAP +A043 ; [.4036.0020.0002] # YI SYLLABLE PUOX +A044 ; [.4037.0020.0002] # YI SYLLABLE PUO +A045 ; [.4038.0020.0002] # YI SYLLABLE PUOP +A046 ; [.4039.0020.0002] # YI SYLLABLE POT +A047 ; [.403A.0020.0002] # YI SYLLABLE POX +A048 ; [.403B.0020.0002] # YI SYLLABLE PO +A049 ; [.403C.0020.0002] # YI SYLLABLE POP +A04A ; [.403D.0020.0002] # YI SYLLABLE PUT +A04B ; [.403E.0020.0002] # YI SYLLABLE PUX +A04C ; [.403F.0020.0002] # YI SYLLABLE PU +A04D ; [.4040.0020.0002] # YI SYLLABLE PUP +A04E ; [.4041.0020.0002] # YI SYLLABLE PURX +A04F ; [.4042.0020.0002] # YI SYLLABLE PUR +A050 ; [.4043.0020.0002] # YI SYLLABLE PYT +A051 ; [.4044.0020.0002] # YI SYLLABLE PYX +A052 ; [.4045.0020.0002] # YI SYLLABLE PY +A053 ; [.4046.0020.0002] # YI SYLLABLE PYP +A054 ; [.4047.0020.0002] # YI SYLLABLE PYRX +A055 ; [.4048.0020.0002] # YI SYLLABLE PYR +A056 ; [.4049.0020.0002] # YI SYLLABLE BBIT +A057 ; [.404A.0020.0002] # YI SYLLABLE BBIX +A058 ; [.404B.0020.0002] # YI SYLLABLE BBI +A059 ; [.404C.0020.0002] # YI SYLLABLE BBIP +A05A ; [.404D.0020.0002] # YI SYLLABLE BBIET +A05B ; [.404E.0020.0002] # YI SYLLABLE BBIEX +A05C ; [.404F.0020.0002] # YI SYLLABLE BBIE +A05D ; [.4050.0020.0002] # YI SYLLABLE BBIEP +A05E ; [.4051.0020.0002] # YI SYLLABLE BBAT +A05F ; [.4052.0020.0002] # YI SYLLABLE BBAX +A060 ; [.4053.0020.0002] # YI SYLLABLE BBA +A061 ; [.4054.0020.0002] # YI SYLLABLE BBAP +A062 ; [.4055.0020.0002] # YI SYLLABLE BBUOX +A063 ; [.4056.0020.0002] # YI SYLLABLE BBUO +A064 ; [.4057.0020.0002] # YI SYLLABLE BBUOP +A065 ; [.4058.0020.0002] # YI SYLLABLE BBOT +A066 ; [.4059.0020.0002] # YI SYLLABLE BBOX +A067 ; [.405A.0020.0002] # YI SYLLABLE BBO +A068 ; [.405B.0020.0002] # YI SYLLABLE BBOP +A069 ; [.405C.0020.0002] # YI SYLLABLE BBEX +A06A ; [.405D.0020.0002] # YI SYLLABLE BBE +A06B ; [.405E.0020.0002] # YI SYLLABLE BBEP +A06C ; [.405F.0020.0002] # YI SYLLABLE BBUT +A06D ; [.4060.0020.0002] # YI SYLLABLE BBUX +A06E ; [.4061.0020.0002] # YI SYLLABLE BBU +A06F ; [.4062.0020.0002] # YI SYLLABLE BBUP +A070 ; [.4063.0020.0002] # YI SYLLABLE BBURX +A071 ; [.4064.0020.0002] # YI SYLLABLE BBUR +A072 ; [.4065.0020.0002] # YI SYLLABLE BBYT +A073 ; [.4066.0020.0002] # YI SYLLABLE BBYX +A074 ; [.4067.0020.0002] # YI SYLLABLE BBY +A075 ; [.4068.0020.0002] # YI SYLLABLE BBYP +A076 ; [.4069.0020.0002] # YI SYLLABLE NBIT +A077 ; [.406A.0020.0002] # YI SYLLABLE NBIX +A078 ; [.406B.0020.0002] # YI SYLLABLE NBI +A079 ; [.406C.0020.0002] # YI SYLLABLE NBIP +A07A ; [.406D.0020.0002] # YI SYLLABLE NBIEX +A07B ; [.406E.0020.0002] # YI SYLLABLE NBIE +A07C ; [.406F.0020.0002] # YI SYLLABLE NBIEP +A07D ; [.4070.0020.0002] # YI SYLLABLE NBAT +A07E ; [.4071.0020.0002] # YI SYLLABLE NBAX +A07F ; [.4072.0020.0002] # YI SYLLABLE NBA +A080 ; [.4073.0020.0002] # YI SYLLABLE NBAP +A081 ; [.4074.0020.0002] # YI SYLLABLE NBOT +A082 ; [.4075.0020.0002] # YI SYLLABLE NBOX +A083 ; [.4076.0020.0002] # YI SYLLABLE NBO +A084 ; [.4077.0020.0002] # YI SYLLABLE NBOP +A085 ; [.4078.0020.0002] # YI SYLLABLE NBUT +A086 ; [.4079.0020.0002] # YI SYLLABLE NBUX +A087 ; [.407A.0020.0002] # YI SYLLABLE NBU +A088 ; [.407B.0020.0002] # YI SYLLABLE NBUP +A089 ; [.407C.0020.0002] # YI SYLLABLE NBURX +A08A ; [.407D.0020.0002] # YI SYLLABLE NBUR +A08B ; [.407E.0020.0002] # YI SYLLABLE NBYT +A08C ; [.407F.0020.0002] # YI SYLLABLE NBYX +A08D ; [.4080.0020.0002] # YI SYLLABLE NBY +A08E ; [.4081.0020.0002] # YI SYLLABLE NBYP +A08F ; [.4082.0020.0002] # YI SYLLABLE NBYRX +A090 ; [.4083.0020.0002] # YI SYLLABLE NBYR +A091 ; [.4084.0020.0002] # YI SYLLABLE HMIT +A092 ; [.4085.0020.0002] # YI SYLLABLE HMIX +A093 ; [.4086.0020.0002] # YI SYLLABLE HMI +A094 ; [.4087.0020.0002] # YI SYLLABLE HMIP +A095 ; [.4088.0020.0002] # YI SYLLABLE HMIEX +A096 ; [.4089.0020.0002] # YI SYLLABLE HMIE +A097 ; [.408A.0020.0002] # YI SYLLABLE HMIEP +A098 ; [.408B.0020.0002] # YI SYLLABLE HMAT +A099 ; [.408C.0020.0002] # YI SYLLABLE HMAX +A09A ; [.408D.0020.0002] # YI SYLLABLE HMA +A09B ; [.408E.0020.0002] # YI SYLLABLE HMAP +A09C ; [.408F.0020.0002] # YI SYLLABLE HMUOX +A09D ; [.4090.0020.0002] # YI SYLLABLE HMUO +A09E ; [.4091.0020.0002] # YI SYLLABLE HMUOP +A09F ; [.4092.0020.0002] # YI SYLLABLE HMOT +A0A0 ; [.4093.0020.0002] # YI SYLLABLE HMOX +A0A1 ; [.4094.0020.0002] # YI SYLLABLE HMO +A0A2 ; [.4095.0020.0002] # YI SYLLABLE HMOP +A0A3 ; [.4096.0020.0002] # YI SYLLABLE HMUT +A0A4 ; [.4097.0020.0002] # YI SYLLABLE HMUX +A0A5 ; [.4098.0020.0002] # YI SYLLABLE HMU +A0A6 ; [.4099.0020.0002] # YI SYLLABLE HMUP +A0A7 ; [.409A.0020.0002] # YI SYLLABLE HMURX +A0A8 ; [.409B.0020.0002] # YI SYLLABLE HMUR +A0A9 ; [.409C.0020.0002] # YI SYLLABLE HMYX +A0AA ; [.409D.0020.0002] # YI SYLLABLE HMY +A0AB ; [.409E.0020.0002] # YI SYLLABLE HMYP +A0AC ; [.409F.0020.0002] # YI SYLLABLE HMYRX +A0AD ; [.40A0.0020.0002] # YI SYLLABLE HMYR +A0AE ; [.40A1.0020.0002] # YI SYLLABLE MIT +A0AF ; [.40A2.0020.0002] # YI SYLLABLE MIX +A0B0 ; [.40A3.0020.0002] # YI SYLLABLE MI +A0B1 ; [.40A4.0020.0002] # YI SYLLABLE MIP +A0B2 ; [.40A5.0020.0002] # YI SYLLABLE MIEX +A0B3 ; [.40A6.0020.0002] # YI SYLLABLE MIE +A0B4 ; [.40A7.0020.0002] # YI SYLLABLE MIEP +A0B5 ; [.40A8.0020.0002] # YI SYLLABLE MAT +A0B6 ; [.40A9.0020.0002] # YI SYLLABLE MAX +A0B7 ; [.40AA.0020.0002] # YI SYLLABLE MA +A0B8 ; [.40AB.0020.0002] # YI SYLLABLE MAP +A0B9 ; [.40AC.0020.0002] # YI SYLLABLE MUOT +A0BA ; [.40AD.0020.0002] # YI SYLLABLE MUOX +A0BB ; [.40AE.0020.0002] # YI SYLLABLE MUO +A0BC ; [.40AF.0020.0002] # YI SYLLABLE MUOP +A0BD ; [.40B0.0020.0002] # YI SYLLABLE MOT +A0BE ; [.40B1.0020.0002] # YI SYLLABLE MOX +A0BF ; [.40B2.0020.0002] # YI SYLLABLE MO +A0C0 ; [.40B3.0020.0002] # YI SYLLABLE MOP +A0C1 ; [.40B4.0020.0002] # YI SYLLABLE MEX +A0C2 ; [.40B5.0020.0002] # YI SYLLABLE ME +A0C3 ; [.40B6.0020.0002] # YI SYLLABLE MUT +A0C4 ; [.40B7.0020.0002] # YI SYLLABLE MUX +A0C5 ; [.40B8.0020.0002] # YI SYLLABLE MU +A0C6 ; [.40B9.0020.0002] # YI SYLLABLE MUP +A0C7 ; [.40BA.0020.0002] # YI SYLLABLE MURX +A0C8 ; [.40BB.0020.0002] # YI SYLLABLE MUR +A0C9 ; [.40BC.0020.0002] # YI SYLLABLE MYT +A0CA ; [.40BD.0020.0002] # YI SYLLABLE MYX +A0CB ; [.40BE.0020.0002] # YI SYLLABLE MY +A0CC ; [.40BF.0020.0002] # YI SYLLABLE MYP +A0CD ; [.40C0.0020.0002] # YI SYLLABLE FIT +A0CE ; [.40C1.0020.0002] # YI SYLLABLE FIX +A0CF ; [.40C2.0020.0002] # YI SYLLABLE FI +A0D0 ; [.40C3.0020.0002] # YI SYLLABLE FIP +A0D1 ; [.40C4.0020.0002] # YI SYLLABLE FAT +A0D2 ; [.40C5.0020.0002] # YI SYLLABLE FAX +A0D3 ; [.40C6.0020.0002] # YI SYLLABLE FA +A0D4 ; [.40C7.0020.0002] # YI SYLLABLE FAP +A0D5 ; [.40C8.0020.0002] # YI SYLLABLE FOX +A0D6 ; [.40C9.0020.0002] # YI SYLLABLE FO +A0D7 ; [.40CA.0020.0002] # YI SYLLABLE FOP +A0D8 ; [.40CB.0020.0002] # YI SYLLABLE FUT +A0D9 ; [.40CC.0020.0002] # YI SYLLABLE FUX +A0DA ; [.40CD.0020.0002] # YI SYLLABLE FU +A0DB ; [.40CE.0020.0002] # YI SYLLABLE FUP +A0DC ; [.40CF.0020.0002] # YI SYLLABLE FURX +A0DD ; [.40D0.0020.0002] # YI SYLLABLE FUR +A0DE ; [.40D1.0020.0002] # YI SYLLABLE FYT +A0DF ; [.40D2.0020.0002] # YI SYLLABLE FYX +A0E0 ; [.40D3.0020.0002] # YI SYLLABLE FY +A0E1 ; [.40D4.0020.0002] # YI SYLLABLE FYP +A0E2 ; [.40D5.0020.0002] # YI SYLLABLE VIT +A0E3 ; [.40D6.0020.0002] # YI SYLLABLE VIX +A0E4 ; [.40D7.0020.0002] # YI SYLLABLE VI +A0E5 ; [.40D8.0020.0002] # YI SYLLABLE VIP +A0E6 ; [.40D9.0020.0002] # YI SYLLABLE VIET +A0E7 ; [.40DA.0020.0002] # YI SYLLABLE VIEX +A0E8 ; [.40DB.0020.0002] # YI SYLLABLE VIE +A0E9 ; [.40DC.0020.0002] # YI SYLLABLE VIEP +A0EA ; [.40DD.0020.0002] # YI SYLLABLE VAT +A0EB ; [.40DE.0020.0002] # YI SYLLABLE VAX +A0EC ; [.40DF.0020.0002] # YI SYLLABLE VA +A0ED ; [.40E0.0020.0002] # YI SYLLABLE VAP +A0EE ; [.40E1.0020.0002] # YI SYLLABLE VOT +A0EF ; [.40E2.0020.0002] # YI SYLLABLE VOX +A0F0 ; [.40E3.0020.0002] # YI SYLLABLE VO +A0F1 ; [.40E4.0020.0002] # YI SYLLABLE VOP +A0F2 ; [.40E5.0020.0002] # YI SYLLABLE VEX +A0F3 ; [.40E6.0020.0002] # YI SYLLABLE VEP +A0F4 ; [.40E7.0020.0002] # YI SYLLABLE VUT +A0F5 ; [.40E8.0020.0002] # YI SYLLABLE VUX +A0F6 ; [.40E9.0020.0002] # YI SYLLABLE VU +A0F7 ; [.40EA.0020.0002] # YI SYLLABLE VUP +A0F8 ; [.40EB.0020.0002] # YI SYLLABLE VURX +A0F9 ; [.40EC.0020.0002] # YI SYLLABLE VUR +A0FA ; [.40ED.0020.0002] # YI SYLLABLE VYT +A0FB ; [.40EE.0020.0002] # YI SYLLABLE VYX +A0FC ; [.40EF.0020.0002] # YI SYLLABLE VY +A0FD ; [.40F0.0020.0002] # YI SYLLABLE VYP +A0FE ; [.40F1.0020.0002] # YI SYLLABLE VYRX +A0FF ; [.40F2.0020.0002] # YI SYLLABLE VYR +A100 ; [.40F3.0020.0002] # YI SYLLABLE DIT +A101 ; [.40F4.0020.0002] # YI SYLLABLE DIX +A102 ; [.40F5.0020.0002] # YI SYLLABLE DI +A103 ; [.40F6.0020.0002] # YI SYLLABLE DIP +A104 ; [.40F7.0020.0002] # YI SYLLABLE DIEX +A105 ; [.40F8.0020.0002] # YI SYLLABLE DIE +A106 ; [.40F9.0020.0002] # YI SYLLABLE DIEP +A107 ; [.40FA.0020.0002] # YI SYLLABLE DAT +A108 ; [.40FB.0020.0002] # YI SYLLABLE DAX +A109 ; [.40FC.0020.0002] # YI SYLLABLE DA +A10A ; [.40FD.0020.0002] # YI SYLLABLE DAP +A10B ; [.40FE.0020.0002] # YI SYLLABLE DUOX +A10C ; [.40FF.0020.0002] # YI SYLLABLE DUO +A10D ; [.4100.0020.0002] # YI SYLLABLE DOT +A10E ; [.4101.0020.0002] # YI SYLLABLE DOX +A10F ; [.4102.0020.0002] # YI SYLLABLE DO +A110 ; [.4103.0020.0002] # YI SYLLABLE DOP +A111 ; [.4104.0020.0002] # YI SYLLABLE DEX +A112 ; [.4105.0020.0002] # YI SYLLABLE DE +A113 ; [.4106.0020.0002] # YI SYLLABLE DEP +A114 ; [.4107.0020.0002] # YI SYLLABLE DUT +A115 ; [.4108.0020.0002] # YI SYLLABLE DUX +A116 ; [.4109.0020.0002] # YI SYLLABLE DU +A117 ; [.410A.0020.0002] # YI SYLLABLE DUP +A118 ; [.410B.0020.0002] # YI SYLLABLE DURX +A119 ; [.410C.0020.0002] # YI SYLLABLE DUR +A11A ; [.410D.0020.0002] # YI SYLLABLE TIT +A11B ; [.410E.0020.0002] # YI SYLLABLE TIX +A11C ; [.410F.0020.0002] # YI SYLLABLE TI +A11D ; [.4110.0020.0002] # YI SYLLABLE TIP +A11E ; [.4111.0020.0002] # YI SYLLABLE TIEX +A11F ; [.4112.0020.0002] # YI SYLLABLE TIE +A120 ; [.4113.0020.0002] # YI SYLLABLE TIEP +A121 ; [.4114.0020.0002] # YI SYLLABLE TAT +A122 ; [.4115.0020.0002] # YI SYLLABLE TAX +A123 ; [.4116.0020.0002] # YI SYLLABLE TA +A124 ; [.4117.0020.0002] # YI SYLLABLE TAP +A125 ; [.4118.0020.0002] # YI SYLLABLE TUOT +A126 ; [.4119.0020.0002] # YI SYLLABLE TUOX +A127 ; [.411A.0020.0002] # YI SYLLABLE TUO +A128 ; [.411B.0020.0002] # YI SYLLABLE TUOP +A129 ; [.411C.0020.0002] # YI SYLLABLE TOT +A12A ; [.411D.0020.0002] # YI SYLLABLE TOX +A12B ; [.411E.0020.0002] # YI SYLLABLE TO +A12C ; [.411F.0020.0002] # YI SYLLABLE TOP +A12D ; [.4120.0020.0002] # YI SYLLABLE TEX +A12E ; [.4121.0020.0002] # YI SYLLABLE TE +A12F ; [.4122.0020.0002] # YI SYLLABLE TEP +A130 ; [.4123.0020.0002] # YI SYLLABLE TUT +A131 ; [.4124.0020.0002] # YI SYLLABLE TUX +A132 ; [.4125.0020.0002] # YI SYLLABLE TU +A133 ; [.4126.0020.0002] # YI SYLLABLE TUP +A134 ; [.4127.0020.0002] # YI SYLLABLE TURX +A135 ; [.4128.0020.0002] # YI SYLLABLE TUR +A136 ; [.4129.0020.0002] # YI SYLLABLE DDIT +A137 ; [.412A.0020.0002] # YI SYLLABLE DDIX +A138 ; [.412B.0020.0002] # YI SYLLABLE DDI +A139 ; [.412C.0020.0002] # YI SYLLABLE DDIP +A13A ; [.412D.0020.0002] # YI SYLLABLE DDIEX +A13B ; [.412E.0020.0002] # YI SYLLABLE DDIE +A13C ; [.412F.0020.0002] # YI SYLLABLE DDIEP +A13D ; [.4130.0020.0002] # YI SYLLABLE DDAT +A13E ; [.4131.0020.0002] # YI SYLLABLE DDAX +A13F ; [.4132.0020.0002] # YI SYLLABLE DDA +A140 ; [.4133.0020.0002] # YI SYLLABLE DDAP +A141 ; [.4134.0020.0002] # YI SYLLABLE DDUOX +A142 ; [.4135.0020.0002] # YI SYLLABLE DDUO +A143 ; [.4136.0020.0002] # YI SYLLABLE DDUOP +A144 ; [.4137.0020.0002] # YI SYLLABLE DDOT +A145 ; [.4138.0020.0002] # YI SYLLABLE DDOX +A146 ; [.4139.0020.0002] # YI SYLLABLE DDO +A147 ; [.413A.0020.0002] # YI SYLLABLE DDOP +A148 ; [.413B.0020.0002] # YI SYLLABLE DDEX +A149 ; [.413C.0020.0002] # YI SYLLABLE DDE +A14A ; [.413D.0020.0002] # YI SYLLABLE DDEP +A14B ; [.413E.0020.0002] # YI SYLLABLE DDUT +A14C ; [.413F.0020.0002] # YI SYLLABLE DDUX +A14D ; [.4140.0020.0002] # YI SYLLABLE DDU +A14E ; [.4141.0020.0002] # YI SYLLABLE DDUP +A14F ; [.4142.0020.0002] # YI SYLLABLE DDURX +A150 ; [.4143.0020.0002] # YI SYLLABLE DDUR +A151 ; [.4144.0020.0002] # YI SYLLABLE NDIT +A152 ; [.4145.0020.0002] # YI SYLLABLE NDIX +A153 ; [.4146.0020.0002] # YI SYLLABLE NDI +A154 ; [.4147.0020.0002] # YI SYLLABLE NDIP +A155 ; [.4148.0020.0002] # YI SYLLABLE NDIEX +A156 ; [.4149.0020.0002] # YI SYLLABLE NDIE +A157 ; [.414A.0020.0002] # YI SYLLABLE NDAT +A158 ; [.414B.0020.0002] # YI SYLLABLE NDAX +A159 ; [.414C.0020.0002] # YI SYLLABLE NDA +A15A ; [.414D.0020.0002] # YI SYLLABLE NDAP +A15B ; [.414E.0020.0002] # YI SYLLABLE NDOT +A15C ; [.414F.0020.0002] # YI SYLLABLE NDOX +A15D ; [.4150.0020.0002] # YI SYLLABLE NDO +A15E ; [.4151.0020.0002] # YI SYLLABLE NDOP +A15F ; [.4152.0020.0002] # YI SYLLABLE NDEX +A160 ; [.4153.0020.0002] # YI SYLLABLE NDE +A161 ; [.4154.0020.0002] # YI SYLLABLE NDEP +A162 ; [.4155.0020.0002] # YI SYLLABLE NDUT +A163 ; [.4156.0020.0002] # YI SYLLABLE NDUX +A164 ; [.4157.0020.0002] # YI SYLLABLE NDU +A165 ; [.4158.0020.0002] # YI SYLLABLE NDUP +A166 ; [.4159.0020.0002] # YI SYLLABLE NDURX +A167 ; [.415A.0020.0002] # YI SYLLABLE NDUR +A168 ; [.415B.0020.0002] # YI SYLLABLE HNIT +A169 ; [.415C.0020.0002] # YI SYLLABLE HNIX +A16A ; [.415D.0020.0002] # YI SYLLABLE HNI +A16B ; [.415E.0020.0002] # YI SYLLABLE HNIP +A16C ; [.415F.0020.0002] # YI SYLLABLE HNIET +A16D ; [.4160.0020.0002] # YI SYLLABLE HNIEX +A16E ; [.4161.0020.0002] # YI SYLLABLE HNIE +A16F ; [.4162.0020.0002] # YI SYLLABLE HNIEP +A170 ; [.4163.0020.0002] # YI SYLLABLE HNAT +A171 ; [.4164.0020.0002] # YI SYLLABLE HNAX +A172 ; [.4165.0020.0002] # YI SYLLABLE HNA +A173 ; [.4166.0020.0002] # YI SYLLABLE HNAP +A174 ; [.4167.0020.0002] # YI SYLLABLE HNUOX +A175 ; [.4168.0020.0002] # YI SYLLABLE HNUO +A176 ; [.4169.0020.0002] # YI SYLLABLE HNOT +A177 ; [.416A.0020.0002] # YI SYLLABLE HNOX +A178 ; [.416B.0020.0002] # YI SYLLABLE HNOP +A179 ; [.416C.0020.0002] # YI SYLLABLE HNEX +A17A ; [.416D.0020.0002] # YI SYLLABLE HNE +A17B ; [.416E.0020.0002] # YI SYLLABLE HNEP +A17C ; [.416F.0020.0002] # YI SYLLABLE HNUT +A17D ; [.4170.0020.0002] # YI SYLLABLE NIT +A17E ; [.4171.0020.0002] # YI SYLLABLE NIX +A17F ; [.4172.0020.0002] # YI SYLLABLE NI +A180 ; [.4173.0020.0002] # YI SYLLABLE NIP +A181 ; [.4174.0020.0002] # YI SYLLABLE NIEX +A182 ; [.4175.0020.0002] # YI SYLLABLE NIE +A183 ; [.4176.0020.0002] # YI SYLLABLE NIEP +A184 ; [.4177.0020.0002] # YI SYLLABLE NAX +A185 ; [.4178.0020.0002] # YI SYLLABLE NA +A186 ; [.4179.0020.0002] # YI SYLLABLE NAP +A187 ; [.417A.0020.0002] # YI SYLLABLE NUOX +A188 ; [.417B.0020.0002] # YI SYLLABLE NUO +A189 ; [.417C.0020.0002] # YI SYLLABLE NUOP +A18A ; [.417D.0020.0002] # YI SYLLABLE NOT +A18B ; [.417E.0020.0002] # YI SYLLABLE NOX +A18C ; [.417F.0020.0002] # YI SYLLABLE NO +A18D ; [.4180.0020.0002] # YI SYLLABLE NOP +A18E ; [.4181.0020.0002] # YI SYLLABLE NEX +A18F ; [.4182.0020.0002] # YI SYLLABLE NE +A190 ; [.4183.0020.0002] # YI SYLLABLE NEP +A191 ; [.4184.0020.0002] # YI SYLLABLE NUT +A192 ; [.4185.0020.0002] # YI SYLLABLE NUX +A193 ; [.4186.0020.0002] # YI SYLLABLE NU +A194 ; [.4187.0020.0002] # YI SYLLABLE NUP +A195 ; [.4188.0020.0002] # YI SYLLABLE NURX +A196 ; [.4189.0020.0002] # YI SYLLABLE NUR +A197 ; [.418A.0020.0002] # YI SYLLABLE HLIT +A198 ; [.418B.0020.0002] # YI SYLLABLE HLIX +A199 ; [.418C.0020.0002] # YI SYLLABLE HLI +A19A ; [.418D.0020.0002] # YI SYLLABLE HLIP +A19B ; [.418E.0020.0002] # YI SYLLABLE HLIEX +A19C ; [.418F.0020.0002] # YI SYLLABLE HLIE +A19D ; [.4190.0020.0002] # YI SYLLABLE HLIEP +A19E ; [.4191.0020.0002] # YI SYLLABLE HLAT +A19F ; [.4192.0020.0002] # YI SYLLABLE HLAX +A1A0 ; [.4193.0020.0002] # YI SYLLABLE HLA +A1A1 ; [.4194.0020.0002] # YI SYLLABLE HLAP +A1A2 ; [.4195.0020.0002] # YI SYLLABLE HLUOX +A1A3 ; [.4196.0020.0002] # YI SYLLABLE HLUO +A1A4 ; [.4197.0020.0002] # YI SYLLABLE HLUOP +A1A5 ; [.4198.0020.0002] # YI SYLLABLE HLOX +A1A6 ; [.4199.0020.0002] # YI SYLLABLE HLO +A1A7 ; [.419A.0020.0002] # YI SYLLABLE HLOP +A1A8 ; [.419B.0020.0002] # YI SYLLABLE HLEX +A1A9 ; [.419C.0020.0002] # YI SYLLABLE HLE +A1AA ; [.419D.0020.0002] # YI SYLLABLE HLEP +A1AB ; [.419E.0020.0002] # YI SYLLABLE HLUT +A1AC ; [.419F.0020.0002] # YI SYLLABLE HLUX +A1AD ; [.41A0.0020.0002] # YI SYLLABLE HLU +A1AE ; [.41A1.0020.0002] # YI SYLLABLE HLUP +A1AF ; [.41A2.0020.0002] # YI SYLLABLE HLURX +A1B0 ; [.41A3.0020.0002] # YI SYLLABLE HLUR +A1B1 ; [.41A4.0020.0002] # YI SYLLABLE HLYT +A1B2 ; [.41A5.0020.0002] # YI SYLLABLE HLYX +A1B3 ; [.41A6.0020.0002] # YI SYLLABLE HLY +A1B4 ; [.41A7.0020.0002] # YI SYLLABLE HLYP +A1B5 ; [.41A8.0020.0002] # YI SYLLABLE HLYRX +A1B6 ; [.41A9.0020.0002] # YI SYLLABLE HLYR +A1B7 ; [.41AA.0020.0002] # YI SYLLABLE LIT +A1B8 ; [.41AB.0020.0002] # YI SYLLABLE LIX +A1B9 ; [.41AC.0020.0002] # YI SYLLABLE LI +A1BA ; [.41AD.0020.0002] # YI SYLLABLE LIP +A1BB ; [.41AE.0020.0002] # YI SYLLABLE LIET +A1BC ; [.41AF.0020.0002] # YI SYLLABLE LIEX +A1BD ; [.41B0.0020.0002] # YI SYLLABLE LIE +A1BE ; [.41B1.0020.0002] # YI SYLLABLE LIEP +A1BF ; [.41B2.0020.0002] # YI SYLLABLE LAT +A1C0 ; [.41B3.0020.0002] # YI SYLLABLE LAX +A1C1 ; [.41B4.0020.0002] # YI SYLLABLE LA +A1C2 ; [.41B5.0020.0002] # YI SYLLABLE LAP +A1C3 ; [.41B6.0020.0002] # YI SYLLABLE LUOT +A1C4 ; [.41B7.0020.0002] # YI SYLLABLE LUOX +A1C5 ; [.41B8.0020.0002] # YI SYLLABLE LUO +A1C6 ; [.41B9.0020.0002] # YI SYLLABLE LUOP +A1C7 ; [.41BA.0020.0002] # YI SYLLABLE LOT +A1C8 ; [.41BB.0020.0002] # YI SYLLABLE LOX +A1C9 ; [.41BC.0020.0002] # YI SYLLABLE LO +A1CA ; [.41BD.0020.0002] # YI SYLLABLE LOP +A1CB ; [.41BE.0020.0002] # YI SYLLABLE LEX +A1CC ; [.41BF.0020.0002] # YI SYLLABLE LE +A1CD ; [.41C0.0020.0002] # YI SYLLABLE LEP +A1CE ; [.41C1.0020.0002] # YI SYLLABLE LUT +A1CF ; [.41C2.0020.0002] # YI SYLLABLE LUX +A1D0 ; [.41C3.0020.0002] # YI SYLLABLE LU +A1D1 ; [.41C4.0020.0002] # YI SYLLABLE LUP +A1D2 ; [.41C5.0020.0002] # YI SYLLABLE LURX +A1D3 ; [.41C6.0020.0002] # YI SYLLABLE LUR +A1D4 ; [.41C7.0020.0002] # YI SYLLABLE LYT +A1D5 ; [.41C8.0020.0002] # YI SYLLABLE LYX +A1D6 ; [.41C9.0020.0002] # YI SYLLABLE LY +A1D7 ; [.41CA.0020.0002] # YI SYLLABLE LYP +A1D8 ; [.41CB.0020.0002] # YI SYLLABLE LYRX +A1D9 ; [.41CC.0020.0002] # YI SYLLABLE LYR +A1DA ; [.41CD.0020.0002] # YI SYLLABLE GIT +A1DB ; [.41CE.0020.0002] # YI SYLLABLE GIX +A1DC ; [.41CF.0020.0002] # YI SYLLABLE GI +A1DD ; [.41D0.0020.0002] # YI SYLLABLE GIP +A1DE ; [.41D1.0020.0002] # YI SYLLABLE GIET +A1DF ; [.41D2.0020.0002] # YI SYLLABLE GIEX +A1E0 ; [.41D3.0020.0002] # YI SYLLABLE GIE +A1E1 ; [.41D4.0020.0002] # YI SYLLABLE GIEP +A1E2 ; [.41D5.0020.0002] # YI SYLLABLE GAT +A1E3 ; [.41D6.0020.0002] # YI SYLLABLE GAX +A1E4 ; [.41D7.0020.0002] # YI SYLLABLE GA +A1E5 ; [.41D8.0020.0002] # YI SYLLABLE GAP +A1E6 ; [.41D9.0020.0002] # YI SYLLABLE GUOT +A1E7 ; [.41DA.0020.0002] # YI SYLLABLE GUOX +A1E8 ; [.41DB.0020.0002] # YI SYLLABLE GUO +A1E9 ; [.41DC.0020.0002] # YI SYLLABLE GUOP +A1EA ; [.41DD.0020.0002] # YI SYLLABLE GOT +A1EB ; [.41DE.0020.0002] # YI SYLLABLE GOX +A1EC ; [.41DF.0020.0002] # YI SYLLABLE GO +A1ED ; [.41E0.0020.0002] # YI SYLLABLE GOP +A1EE ; [.41E1.0020.0002] # YI SYLLABLE GET +A1EF ; [.41E2.0020.0002] # YI SYLLABLE GEX +A1F0 ; [.41E3.0020.0002] # YI SYLLABLE GE +A1F1 ; [.41E4.0020.0002] # YI SYLLABLE GEP +A1F2 ; [.41E5.0020.0002] # YI SYLLABLE GUT +A1F3 ; [.41E6.0020.0002] # YI SYLLABLE GUX +A1F4 ; [.41E7.0020.0002] # YI SYLLABLE GU +A1F5 ; [.41E8.0020.0002] # YI SYLLABLE GUP +A1F6 ; [.41E9.0020.0002] # YI SYLLABLE GURX +A1F7 ; [.41EA.0020.0002] # YI SYLLABLE GUR +A1F8 ; [.41EB.0020.0002] # YI SYLLABLE KIT +A1F9 ; [.41EC.0020.0002] # YI SYLLABLE KIX +A1FA ; [.41ED.0020.0002] # YI SYLLABLE KI +A1FB ; [.41EE.0020.0002] # YI SYLLABLE KIP +A1FC ; [.41EF.0020.0002] # YI SYLLABLE KIEX +A1FD ; [.41F0.0020.0002] # YI SYLLABLE KIE +A1FE ; [.41F1.0020.0002] # YI SYLLABLE KIEP +A1FF ; [.41F2.0020.0002] # YI SYLLABLE KAT +A200 ; [.41F3.0020.0002] # YI SYLLABLE KAX +A201 ; [.41F4.0020.0002] # YI SYLLABLE KA +A202 ; [.41F5.0020.0002] # YI SYLLABLE KAP +A203 ; [.41F6.0020.0002] # YI SYLLABLE KUOX +A204 ; [.41F7.0020.0002] # YI SYLLABLE KUO +A205 ; [.41F8.0020.0002] # YI SYLLABLE KUOP +A206 ; [.41F9.0020.0002] # YI SYLLABLE KOT +A207 ; [.41FA.0020.0002] # YI SYLLABLE KOX +A208 ; [.41FB.0020.0002] # YI SYLLABLE KO +A209 ; [.41FC.0020.0002] # YI SYLLABLE KOP +A20A ; [.41FD.0020.0002] # YI SYLLABLE KET +A20B ; [.41FE.0020.0002] # YI SYLLABLE KEX +A20C ; [.41FF.0020.0002] # YI SYLLABLE KE +A20D ; [.4200.0020.0002] # YI SYLLABLE KEP +A20E ; [.4201.0020.0002] # YI SYLLABLE KUT +A20F ; [.4202.0020.0002] # YI SYLLABLE KUX +A210 ; [.4203.0020.0002] # YI SYLLABLE KU +A211 ; [.4204.0020.0002] # YI SYLLABLE KUP +A212 ; [.4205.0020.0002] # YI SYLLABLE KURX +A213 ; [.4206.0020.0002] # YI SYLLABLE KUR +A214 ; [.4207.0020.0002] # YI SYLLABLE GGIT +A215 ; [.4208.0020.0002] # YI SYLLABLE GGIX +A216 ; [.4209.0020.0002] # YI SYLLABLE GGI +A217 ; [.420A.0020.0002] # YI SYLLABLE GGIEX +A218 ; [.420B.0020.0002] # YI SYLLABLE GGIE +A219 ; [.420C.0020.0002] # YI SYLLABLE GGIEP +A21A ; [.420D.0020.0002] # YI SYLLABLE GGAT +A21B ; [.420E.0020.0002] # YI SYLLABLE GGAX +A21C ; [.420F.0020.0002] # YI SYLLABLE GGA +A21D ; [.4210.0020.0002] # YI SYLLABLE GGAP +A21E ; [.4211.0020.0002] # YI SYLLABLE GGUOT +A21F ; [.4212.0020.0002] # YI SYLLABLE GGUOX +A220 ; [.4213.0020.0002] # YI SYLLABLE GGUO +A221 ; [.4214.0020.0002] # YI SYLLABLE GGUOP +A222 ; [.4215.0020.0002] # YI SYLLABLE GGOT +A223 ; [.4216.0020.0002] # YI SYLLABLE GGOX +A224 ; [.4217.0020.0002] # YI SYLLABLE GGO +A225 ; [.4218.0020.0002] # YI SYLLABLE GGOP +A226 ; [.4219.0020.0002] # YI SYLLABLE GGET +A227 ; [.421A.0020.0002] # YI SYLLABLE GGEX +A228 ; [.421B.0020.0002] # YI SYLLABLE GGE +A229 ; [.421C.0020.0002] # YI SYLLABLE GGEP +A22A ; [.421D.0020.0002] # YI SYLLABLE GGUT +A22B ; [.421E.0020.0002] # YI SYLLABLE GGUX +A22C ; [.421F.0020.0002] # YI SYLLABLE GGU +A22D ; [.4220.0020.0002] # YI SYLLABLE GGUP +A22E ; [.4221.0020.0002] # YI SYLLABLE GGURX +A22F ; [.4222.0020.0002] # YI SYLLABLE GGUR +A230 ; [.4223.0020.0002] # YI SYLLABLE MGIEX +A231 ; [.4224.0020.0002] # YI SYLLABLE MGIE +A232 ; [.4225.0020.0002] # YI SYLLABLE MGAT +A233 ; [.4226.0020.0002] # YI SYLLABLE MGAX +A234 ; [.4227.0020.0002] # YI SYLLABLE MGA +A235 ; [.4228.0020.0002] # YI SYLLABLE MGAP +A236 ; [.4229.0020.0002] # YI SYLLABLE MGUOX +A237 ; [.422A.0020.0002] # YI SYLLABLE MGUO +A238 ; [.422B.0020.0002] # YI SYLLABLE MGUOP +A239 ; [.422C.0020.0002] # YI SYLLABLE MGOT +A23A ; [.422D.0020.0002] # YI SYLLABLE MGOX +A23B ; [.422E.0020.0002] # YI SYLLABLE MGO +A23C ; [.422F.0020.0002] # YI SYLLABLE MGOP +A23D ; [.4230.0020.0002] # YI SYLLABLE MGEX +A23E ; [.4231.0020.0002] # YI SYLLABLE MGE +A23F ; [.4232.0020.0002] # YI SYLLABLE MGEP +A240 ; [.4233.0020.0002] # YI SYLLABLE MGUT +A241 ; [.4234.0020.0002] # YI SYLLABLE MGUX +A242 ; [.4235.0020.0002] # YI SYLLABLE MGU +A243 ; [.4236.0020.0002] # YI SYLLABLE MGUP +A244 ; [.4237.0020.0002] # YI SYLLABLE MGURX +A245 ; [.4238.0020.0002] # YI SYLLABLE MGUR +A246 ; [.4239.0020.0002] # YI SYLLABLE HXIT +A247 ; [.423A.0020.0002] # YI SYLLABLE HXIX +A248 ; [.423B.0020.0002] # YI SYLLABLE HXI +A249 ; [.423C.0020.0002] # YI SYLLABLE HXIP +A24A ; [.423D.0020.0002] # YI SYLLABLE HXIET +A24B ; [.423E.0020.0002] # YI SYLLABLE HXIEX +A24C ; [.423F.0020.0002] # YI SYLLABLE HXIE +A24D ; [.4240.0020.0002] # YI SYLLABLE HXIEP +A24E ; [.4241.0020.0002] # YI SYLLABLE HXAT +A24F ; [.4242.0020.0002] # YI SYLLABLE HXAX +A250 ; [.4243.0020.0002] # YI SYLLABLE HXA +A251 ; [.4244.0020.0002] # YI SYLLABLE HXAP +A252 ; [.4245.0020.0002] # YI SYLLABLE HXUOT +A253 ; [.4246.0020.0002] # YI SYLLABLE HXUOX +A254 ; [.4247.0020.0002] # YI SYLLABLE HXUO +A255 ; [.4248.0020.0002] # YI SYLLABLE HXUOP +A256 ; [.4249.0020.0002] # YI SYLLABLE HXOT +A257 ; [.424A.0020.0002] # YI SYLLABLE HXOX +A258 ; [.424B.0020.0002] # YI SYLLABLE HXO +A259 ; [.424C.0020.0002] # YI SYLLABLE HXOP +A25A ; [.424D.0020.0002] # YI SYLLABLE HXEX +A25B ; [.424E.0020.0002] # YI SYLLABLE HXE +A25C ; [.424F.0020.0002] # YI SYLLABLE HXEP +A25D ; [.4250.0020.0002] # YI SYLLABLE NGIEX +A25E ; [.4251.0020.0002] # YI SYLLABLE NGIE +A25F ; [.4252.0020.0002] # YI SYLLABLE NGIEP +A260 ; [.4253.0020.0002] # YI SYLLABLE NGAT +A261 ; [.4254.0020.0002] # YI SYLLABLE NGAX +A262 ; [.4255.0020.0002] # YI SYLLABLE NGA +A263 ; [.4256.0020.0002] # YI SYLLABLE NGAP +A264 ; [.4257.0020.0002] # YI SYLLABLE NGUOT +A265 ; [.4258.0020.0002] # YI SYLLABLE NGUOX +A266 ; [.4259.0020.0002] # YI SYLLABLE NGUO +A267 ; [.425A.0020.0002] # YI SYLLABLE NGOT +A268 ; [.425B.0020.0002] # YI SYLLABLE NGOX +A269 ; [.425C.0020.0002] # YI SYLLABLE NGO +A26A ; [.425D.0020.0002] # YI SYLLABLE NGOP +A26B ; [.425E.0020.0002] # YI SYLLABLE NGEX +A26C ; [.425F.0020.0002] # YI SYLLABLE NGE +A26D ; [.4260.0020.0002] # YI SYLLABLE NGEP +A26E ; [.4261.0020.0002] # YI SYLLABLE HIT +A26F ; [.4262.0020.0002] # YI SYLLABLE HIEX +A270 ; [.4263.0020.0002] # YI SYLLABLE HIE +A271 ; [.4264.0020.0002] # YI SYLLABLE HAT +A272 ; [.4265.0020.0002] # YI SYLLABLE HAX +A273 ; [.4266.0020.0002] # YI SYLLABLE HA +A274 ; [.4267.0020.0002] # YI SYLLABLE HAP +A275 ; [.4268.0020.0002] # YI SYLLABLE HUOT +A276 ; [.4269.0020.0002] # YI SYLLABLE HUOX +A277 ; [.426A.0020.0002] # YI SYLLABLE HUO +A278 ; [.426B.0020.0002] # YI SYLLABLE HUOP +A279 ; [.426C.0020.0002] # YI SYLLABLE HOT +A27A ; [.426D.0020.0002] # YI SYLLABLE HOX +A27B ; [.426E.0020.0002] # YI SYLLABLE HO +A27C ; [.426F.0020.0002] # YI SYLLABLE HOP +A27D ; [.4270.0020.0002] # YI SYLLABLE HEX +A27E ; [.4271.0020.0002] # YI SYLLABLE HE +A27F ; [.4272.0020.0002] # YI SYLLABLE HEP +A280 ; [.4273.0020.0002] # YI SYLLABLE WAT +A281 ; [.4274.0020.0002] # YI SYLLABLE WAX +A282 ; [.4275.0020.0002] # YI SYLLABLE WA +A283 ; [.4276.0020.0002] # YI SYLLABLE WAP +A284 ; [.4277.0020.0002] # YI SYLLABLE WUOX +A285 ; [.4278.0020.0002] # YI SYLLABLE WUO +A286 ; [.4279.0020.0002] # YI SYLLABLE WUOP +A287 ; [.427A.0020.0002] # YI SYLLABLE WOX +A288 ; [.427B.0020.0002] # YI SYLLABLE WO +A289 ; [.427C.0020.0002] # YI SYLLABLE WOP +A28A ; [.427D.0020.0002] # YI SYLLABLE WEX +A28B ; [.427E.0020.0002] # YI SYLLABLE WE +A28C ; [.427F.0020.0002] # YI SYLLABLE WEP +A28D ; [.4280.0020.0002] # YI SYLLABLE ZIT +A28E ; [.4281.0020.0002] # YI SYLLABLE ZIX +A28F ; [.4282.0020.0002] # YI SYLLABLE ZI +A290 ; [.4283.0020.0002] # YI SYLLABLE ZIP +A291 ; [.4284.0020.0002] # YI SYLLABLE ZIEX +A292 ; [.4285.0020.0002] # YI SYLLABLE ZIE +A293 ; [.4286.0020.0002] # YI SYLLABLE ZIEP +A294 ; [.4287.0020.0002] # YI SYLLABLE ZAT +A295 ; [.4288.0020.0002] # YI SYLLABLE ZAX +A296 ; [.4289.0020.0002] # YI SYLLABLE ZA +A297 ; [.428A.0020.0002] # YI SYLLABLE ZAP +A298 ; [.428B.0020.0002] # YI SYLLABLE ZUOX +A299 ; [.428C.0020.0002] # YI SYLLABLE ZUO +A29A ; [.428D.0020.0002] # YI SYLLABLE ZUOP +A29B ; [.428E.0020.0002] # YI SYLLABLE ZOT +A29C ; [.428F.0020.0002] # YI SYLLABLE ZOX +A29D ; [.4290.0020.0002] # YI SYLLABLE ZO +A29E ; [.4291.0020.0002] # YI SYLLABLE ZOP +A29F ; [.4292.0020.0002] # YI SYLLABLE ZEX +A2A0 ; [.4293.0020.0002] # YI SYLLABLE ZE +A2A1 ; [.4294.0020.0002] # YI SYLLABLE ZEP +A2A2 ; [.4295.0020.0002] # YI SYLLABLE ZUT +A2A3 ; [.4296.0020.0002] # YI SYLLABLE ZUX +A2A4 ; [.4297.0020.0002] # YI SYLLABLE ZU +A2A5 ; [.4298.0020.0002] # YI SYLLABLE ZUP +A2A6 ; [.4299.0020.0002] # YI SYLLABLE ZURX +A2A7 ; [.429A.0020.0002] # YI SYLLABLE ZUR +A2A8 ; [.429B.0020.0002] # YI SYLLABLE ZYT +A2A9 ; [.429C.0020.0002] # YI SYLLABLE ZYX +A2AA ; [.429D.0020.0002] # YI SYLLABLE ZY +A2AB ; [.429E.0020.0002] # YI SYLLABLE ZYP +A2AC ; [.429F.0020.0002] # YI SYLLABLE ZYRX +A2AD ; [.42A0.0020.0002] # YI SYLLABLE ZYR +A2AE ; [.42A1.0020.0002] # YI SYLLABLE CIT +A2AF ; [.42A2.0020.0002] # YI SYLLABLE CIX +A2B0 ; [.42A3.0020.0002] # YI SYLLABLE CI +A2B1 ; [.42A4.0020.0002] # YI SYLLABLE CIP +A2B2 ; [.42A5.0020.0002] # YI SYLLABLE CIET +A2B3 ; [.42A6.0020.0002] # YI SYLLABLE CIEX +A2B4 ; [.42A7.0020.0002] # YI SYLLABLE CIE +A2B5 ; [.42A8.0020.0002] # YI SYLLABLE CIEP +A2B6 ; [.42A9.0020.0002] # YI SYLLABLE CAT +A2B7 ; [.42AA.0020.0002] # YI SYLLABLE CAX +A2B8 ; [.42AB.0020.0002] # YI SYLLABLE CA +A2B9 ; [.42AC.0020.0002] # YI SYLLABLE CAP +A2BA ; [.42AD.0020.0002] # YI SYLLABLE CUOX +A2BB ; [.42AE.0020.0002] # YI SYLLABLE CUO +A2BC ; [.42AF.0020.0002] # YI SYLLABLE CUOP +A2BD ; [.42B0.0020.0002] # YI SYLLABLE COT +A2BE ; [.42B1.0020.0002] # YI SYLLABLE COX +A2BF ; [.42B2.0020.0002] # YI SYLLABLE CO +A2C0 ; [.42B3.0020.0002] # YI SYLLABLE COP +A2C1 ; [.42B4.0020.0002] # YI SYLLABLE CEX +A2C2 ; [.42B5.0020.0002] # YI SYLLABLE CE +A2C3 ; [.42B6.0020.0002] # YI SYLLABLE CEP +A2C4 ; [.42B7.0020.0002] # YI SYLLABLE CUT +A2C5 ; [.42B8.0020.0002] # YI SYLLABLE CUX +A2C6 ; [.42B9.0020.0002] # YI SYLLABLE CU +A2C7 ; [.42BA.0020.0002] # YI SYLLABLE CUP +A2C8 ; [.42BB.0020.0002] # YI SYLLABLE CURX +A2C9 ; [.42BC.0020.0002] # YI SYLLABLE CUR +A2CA ; [.42BD.0020.0002] # YI SYLLABLE CYT +A2CB ; [.42BE.0020.0002] # YI SYLLABLE CYX +A2CC ; [.42BF.0020.0002] # YI SYLLABLE CY +A2CD ; [.42C0.0020.0002] # YI SYLLABLE CYP +A2CE ; [.42C1.0020.0002] # YI SYLLABLE CYRX +A2CF ; [.42C2.0020.0002] # YI SYLLABLE CYR +A2D0 ; [.42C3.0020.0002] # YI SYLLABLE ZZIT +A2D1 ; [.42C4.0020.0002] # YI SYLLABLE ZZIX +A2D2 ; [.42C5.0020.0002] # YI SYLLABLE ZZI +A2D3 ; [.42C6.0020.0002] # YI SYLLABLE ZZIP +A2D4 ; [.42C7.0020.0002] # YI SYLLABLE ZZIET +A2D5 ; [.42C8.0020.0002] # YI SYLLABLE ZZIEX +A2D6 ; [.42C9.0020.0002] # YI SYLLABLE ZZIE +A2D7 ; [.42CA.0020.0002] # YI SYLLABLE ZZIEP +A2D8 ; [.42CB.0020.0002] # YI SYLLABLE ZZAT +A2D9 ; [.42CC.0020.0002] # YI SYLLABLE ZZAX +A2DA ; [.42CD.0020.0002] # YI SYLLABLE ZZA +A2DB ; [.42CE.0020.0002] # YI SYLLABLE ZZAP +A2DC ; [.42CF.0020.0002] # YI SYLLABLE ZZOX +A2DD ; [.42D0.0020.0002] # YI SYLLABLE ZZO +A2DE ; [.42D1.0020.0002] # YI SYLLABLE ZZOP +A2DF ; [.42D2.0020.0002] # YI SYLLABLE ZZEX +A2E0 ; [.42D3.0020.0002] # YI SYLLABLE ZZE +A2E1 ; [.42D4.0020.0002] # YI SYLLABLE ZZEP +A2E2 ; [.42D5.0020.0002] # YI SYLLABLE ZZUX +A2E3 ; [.42D6.0020.0002] # YI SYLLABLE ZZU +A2E4 ; [.42D7.0020.0002] # YI SYLLABLE ZZUP +A2E5 ; [.42D8.0020.0002] # YI SYLLABLE ZZURX +A2E6 ; [.42D9.0020.0002] # YI SYLLABLE ZZUR +A2E7 ; [.42DA.0020.0002] # YI SYLLABLE ZZYT +A2E8 ; [.42DB.0020.0002] # YI SYLLABLE ZZYX +A2E9 ; [.42DC.0020.0002] # YI SYLLABLE ZZY +A2EA ; [.42DD.0020.0002] # YI SYLLABLE ZZYP +A2EB ; [.42DE.0020.0002] # YI SYLLABLE ZZYRX +A2EC ; [.42DF.0020.0002] # YI SYLLABLE ZZYR +A2ED ; [.42E0.0020.0002] # YI SYLLABLE NZIT +A2EE ; [.42E1.0020.0002] # YI SYLLABLE NZIX +A2EF ; [.42E2.0020.0002] # YI SYLLABLE NZI +A2F0 ; [.42E3.0020.0002] # YI SYLLABLE NZIP +A2F1 ; [.42E4.0020.0002] # YI SYLLABLE NZIEX +A2F2 ; [.42E5.0020.0002] # YI SYLLABLE NZIE +A2F3 ; [.42E6.0020.0002] # YI SYLLABLE NZIEP +A2F4 ; [.42E7.0020.0002] # YI SYLLABLE NZAT +A2F5 ; [.42E8.0020.0002] # YI SYLLABLE NZAX +A2F6 ; [.42E9.0020.0002] # YI SYLLABLE NZA +A2F7 ; [.42EA.0020.0002] # YI SYLLABLE NZAP +A2F8 ; [.42EB.0020.0002] # YI SYLLABLE NZUOX +A2F9 ; [.42EC.0020.0002] # YI SYLLABLE NZUO +A2FA ; [.42ED.0020.0002] # YI SYLLABLE NZOX +A2FB ; [.42EE.0020.0002] # YI SYLLABLE NZOP +A2FC ; [.42EF.0020.0002] # YI SYLLABLE NZEX +A2FD ; [.42F0.0020.0002] # YI SYLLABLE NZE +A2FE ; [.42F1.0020.0002] # YI SYLLABLE NZUX +A2FF ; [.42F2.0020.0002] # YI SYLLABLE NZU +A300 ; [.42F3.0020.0002] # YI SYLLABLE NZUP +A301 ; [.42F4.0020.0002] # YI SYLLABLE NZURX +A302 ; [.42F5.0020.0002] # YI SYLLABLE NZUR +A303 ; [.42F6.0020.0002] # YI SYLLABLE NZYT +A304 ; [.42F7.0020.0002] # YI SYLLABLE NZYX +A305 ; [.42F8.0020.0002] # YI SYLLABLE NZY +A306 ; [.42F9.0020.0002] # YI SYLLABLE NZYP +A307 ; [.42FA.0020.0002] # YI SYLLABLE NZYRX +A308 ; [.42FB.0020.0002] # YI SYLLABLE NZYR +A309 ; [.42FC.0020.0002] # YI SYLLABLE SIT +A30A ; [.42FD.0020.0002] # YI SYLLABLE SIX +A30B ; [.42FE.0020.0002] # YI SYLLABLE SI +A30C ; [.42FF.0020.0002] # YI SYLLABLE SIP +A30D ; [.4300.0020.0002] # YI SYLLABLE SIEX +A30E ; [.4301.0020.0002] # YI SYLLABLE SIE +A30F ; [.4302.0020.0002] # YI SYLLABLE SIEP +A310 ; [.4303.0020.0002] # YI SYLLABLE SAT +A311 ; [.4304.0020.0002] # YI SYLLABLE SAX +A312 ; [.4305.0020.0002] # YI SYLLABLE SA +A313 ; [.4306.0020.0002] # YI SYLLABLE SAP +A314 ; [.4307.0020.0002] # YI SYLLABLE SUOX +A315 ; [.4308.0020.0002] # YI SYLLABLE SUO +A316 ; [.4309.0020.0002] # YI SYLLABLE SUOP +A317 ; [.430A.0020.0002] # YI SYLLABLE SOT +A318 ; [.430B.0020.0002] # YI SYLLABLE SOX +A319 ; [.430C.0020.0002] # YI SYLLABLE SO +A31A ; [.430D.0020.0002] # YI SYLLABLE SOP +A31B ; [.430E.0020.0002] # YI SYLLABLE SEX +A31C ; [.430F.0020.0002] # YI SYLLABLE SE +A31D ; [.4310.0020.0002] # YI SYLLABLE SEP +A31E ; [.4311.0020.0002] # YI SYLLABLE SUT +A31F ; [.4312.0020.0002] # YI SYLLABLE SUX +A320 ; [.4313.0020.0002] # YI SYLLABLE SU +A321 ; [.4314.0020.0002] # YI SYLLABLE SUP +A322 ; [.4315.0020.0002] # YI SYLLABLE SURX +A323 ; [.4316.0020.0002] # YI SYLLABLE SUR +A324 ; [.4317.0020.0002] # YI SYLLABLE SYT +A325 ; [.4318.0020.0002] # YI SYLLABLE SYX +A326 ; [.4319.0020.0002] # YI SYLLABLE SY +A327 ; [.431A.0020.0002] # YI SYLLABLE SYP +A328 ; [.431B.0020.0002] # YI SYLLABLE SYRX +A329 ; [.431C.0020.0002] # YI SYLLABLE SYR +A32A ; [.431D.0020.0002] # YI SYLLABLE SSIT +A32B ; [.431E.0020.0002] # YI SYLLABLE SSIX +A32C ; [.431F.0020.0002] # YI SYLLABLE SSI +A32D ; [.4320.0020.0002] # YI SYLLABLE SSIP +A32E ; [.4321.0020.0002] # YI SYLLABLE SSIEX +A32F ; [.4322.0020.0002] # YI SYLLABLE SSIE +A330 ; [.4323.0020.0002] # YI SYLLABLE SSIEP +A331 ; [.4324.0020.0002] # YI SYLLABLE SSAT +A332 ; [.4325.0020.0002] # YI SYLLABLE SSAX +A333 ; [.4326.0020.0002] # YI SYLLABLE SSA +A334 ; [.4327.0020.0002] # YI SYLLABLE SSAP +A335 ; [.4328.0020.0002] # YI SYLLABLE SSOT +A336 ; [.4329.0020.0002] # YI SYLLABLE SSOX +A337 ; [.432A.0020.0002] # YI SYLLABLE SSO +A338 ; [.432B.0020.0002] # YI SYLLABLE SSOP +A339 ; [.432C.0020.0002] # YI SYLLABLE SSEX +A33A ; [.432D.0020.0002] # YI SYLLABLE SSE +A33B ; [.432E.0020.0002] # YI SYLLABLE SSEP +A33C ; [.432F.0020.0002] # YI SYLLABLE SSUT +A33D ; [.4330.0020.0002] # YI SYLLABLE SSUX +A33E ; [.4331.0020.0002] # YI SYLLABLE SSU +A33F ; [.4332.0020.0002] # YI SYLLABLE SSUP +A340 ; [.4333.0020.0002] # YI SYLLABLE SSYT +A341 ; [.4334.0020.0002] # YI SYLLABLE SSYX +A342 ; [.4335.0020.0002] # YI SYLLABLE SSY +A343 ; [.4336.0020.0002] # YI SYLLABLE SSYP +A344 ; [.4337.0020.0002] # YI SYLLABLE SSYRX +A345 ; [.4338.0020.0002] # YI SYLLABLE SSYR +A346 ; [.4339.0020.0002] # YI SYLLABLE ZHAT +A347 ; [.433A.0020.0002] # YI SYLLABLE ZHAX +A348 ; [.433B.0020.0002] # YI SYLLABLE ZHA +A349 ; [.433C.0020.0002] # YI SYLLABLE ZHAP +A34A ; [.433D.0020.0002] # YI SYLLABLE ZHUOX +A34B ; [.433E.0020.0002] # YI SYLLABLE ZHUO +A34C ; [.433F.0020.0002] # YI SYLLABLE ZHUOP +A34D ; [.4340.0020.0002] # YI SYLLABLE ZHOT +A34E ; [.4341.0020.0002] # YI SYLLABLE ZHOX +A34F ; [.4342.0020.0002] # YI SYLLABLE ZHO +A350 ; [.4343.0020.0002] # YI SYLLABLE ZHOP +A351 ; [.4344.0020.0002] # YI SYLLABLE ZHET +A352 ; [.4345.0020.0002] # YI SYLLABLE ZHEX +A353 ; [.4346.0020.0002] # YI SYLLABLE ZHE +A354 ; [.4347.0020.0002] # YI SYLLABLE ZHEP +A355 ; [.4348.0020.0002] # YI SYLLABLE ZHUT +A356 ; [.4349.0020.0002] # YI SYLLABLE ZHUX +A357 ; [.434A.0020.0002] # YI SYLLABLE ZHU +A358 ; [.434B.0020.0002] # YI SYLLABLE ZHUP +A359 ; [.434C.0020.0002] # YI SYLLABLE ZHURX +A35A ; [.434D.0020.0002] # YI SYLLABLE ZHUR +A35B ; [.434E.0020.0002] # YI SYLLABLE ZHYT +A35C ; [.434F.0020.0002] # YI SYLLABLE ZHYX +A35D ; [.4350.0020.0002] # YI SYLLABLE ZHY +A35E ; [.4351.0020.0002] # YI SYLLABLE ZHYP +A35F ; [.4352.0020.0002] # YI SYLLABLE ZHYRX +A360 ; [.4353.0020.0002] # YI SYLLABLE ZHYR +A361 ; [.4354.0020.0002] # YI SYLLABLE CHAT +A362 ; [.4355.0020.0002] # YI SYLLABLE CHAX +A363 ; [.4356.0020.0002] # YI SYLLABLE CHA +A364 ; [.4357.0020.0002] # YI SYLLABLE CHAP +A365 ; [.4358.0020.0002] # YI SYLLABLE CHUOT +A366 ; [.4359.0020.0002] # YI SYLLABLE CHUOX +A367 ; [.435A.0020.0002] # YI SYLLABLE CHUO +A368 ; [.435B.0020.0002] # YI SYLLABLE CHUOP +A369 ; [.435C.0020.0002] # YI SYLLABLE CHOT +A36A ; [.435D.0020.0002] # YI SYLLABLE CHOX +A36B ; [.435E.0020.0002] # YI SYLLABLE CHO +A36C ; [.435F.0020.0002] # YI SYLLABLE CHOP +A36D ; [.4360.0020.0002] # YI SYLLABLE CHET +A36E ; [.4361.0020.0002] # YI SYLLABLE CHEX +A36F ; [.4362.0020.0002] # YI SYLLABLE CHE +A370 ; [.4363.0020.0002] # YI SYLLABLE CHEP +A371 ; [.4364.0020.0002] # YI SYLLABLE CHUX +A372 ; [.4365.0020.0002] # YI SYLLABLE CHU +A373 ; [.4366.0020.0002] # YI SYLLABLE CHUP +A374 ; [.4367.0020.0002] # YI SYLLABLE CHURX +A375 ; [.4368.0020.0002] # YI SYLLABLE CHUR +A376 ; [.4369.0020.0002] # YI SYLLABLE CHYT +A377 ; [.436A.0020.0002] # YI SYLLABLE CHYX +A378 ; [.436B.0020.0002] # YI SYLLABLE CHY +A379 ; [.436C.0020.0002] # YI SYLLABLE CHYP +A37A ; [.436D.0020.0002] # YI SYLLABLE CHYRX +A37B ; [.436E.0020.0002] # YI SYLLABLE CHYR +A37C ; [.436F.0020.0002] # YI SYLLABLE RRAX +A37D ; [.4370.0020.0002] # YI SYLLABLE RRA +A37E ; [.4371.0020.0002] # YI SYLLABLE RRUOX +A37F ; [.4372.0020.0002] # YI SYLLABLE RRUO +A380 ; [.4373.0020.0002] # YI SYLLABLE RROT +A381 ; [.4374.0020.0002] # YI SYLLABLE RROX +A382 ; [.4375.0020.0002] # YI SYLLABLE RRO +A383 ; [.4376.0020.0002] # YI SYLLABLE RROP +A384 ; [.4377.0020.0002] # YI SYLLABLE RRET +A385 ; [.4378.0020.0002] # YI SYLLABLE RREX +A386 ; [.4379.0020.0002] # YI SYLLABLE RRE +A387 ; [.437A.0020.0002] # YI SYLLABLE RREP +A388 ; [.437B.0020.0002] # YI SYLLABLE RRUT +A389 ; [.437C.0020.0002] # YI SYLLABLE RRUX +A38A ; [.437D.0020.0002] # YI SYLLABLE RRU +A38B ; [.437E.0020.0002] # YI SYLLABLE RRUP +A38C ; [.437F.0020.0002] # YI SYLLABLE RRURX +A38D ; [.4380.0020.0002] # YI SYLLABLE RRUR +A38E ; [.4381.0020.0002] # YI SYLLABLE RRYT +A38F ; [.4382.0020.0002] # YI SYLLABLE RRYX +A390 ; [.4383.0020.0002] # YI SYLLABLE RRY +A391 ; [.4384.0020.0002] # YI SYLLABLE RRYP +A392 ; [.4385.0020.0002] # YI SYLLABLE RRYRX +A393 ; [.4386.0020.0002] # YI SYLLABLE RRYR +A394 ; [.4387.0020.0002] # YI SYLLABLE NRAT +A395 ; [.4388.0020.0002] # YI SYLLABLE NRAX +A396 ; [.4389.0020.0002] # YI SYLLABLE NRA +A397 ; [.438A.0020.0002] # YI SYLLABLE NRAP +A398 ; [.438B.0020.0002] # YI SYLLABLE NROX +A399 ; [.438C.0020.0002] # YI SYLLABLE NRO +A39A ; [.438D.0020.0002] # YI SYLLABLE NROP +A39B ; [.438E.0020.0002] # YI SYLLABLE NRET +A39C ; [.438F.0020.0002] # YI SYLLABLE NREX +A39D ; [.4390.0020.0002] # YI SYLLABLE NRE +A39E ; [.4391.0020.0002] # YI SYLLABLE NREP +A39F ; [.4392.0020.0002] # YI SYLLABLE NRUT +A3A0 ; [.4393.0020.0002] # YI SYLLABLE NRUX +A3A1 ; [.4394.0020.0002] # YI SYLLABLE NRU +A3A2 ; [.4395.0020.0002] # YI SYLLABLE NRUP +A3A3 ; [.4396.0020.0002] # YI SYLLABLE NRURX +A3A4 ; [.4397.0020.0002] # YI SYLLABLE NRUR +A3A5 ; [.4398.0020.0002] # YI SYLLABLE NRYT +A3A6 ; [.4399.0020.0002] # YI SYLLABLE NRYX +A3A7 ; [.439A.0020.0002] # YI SYLLABLE NRY +A3A8 ; [.439B.0020.0002] # YI SYLLABLE NRYP +A3A9 ; [.439C.0020.0002] # YI SYLLABLE NRYRX +A3AA ; [.439D.0020.0002] # YI SYLLABLE NRYR +A3AB ; [.439E.0020.0002] # YI SYLLABLE SHAT +A3AC ; [.439F.0020.0002] # YI SYLLABLE SHAX +A3AD ; [.43A0.0020.0002] # YI SYLLABLE SHA +A3AE ; [.43A1.0020.0002] # YI SYLLABLE SHAP +A3AF ; [.43A2.0020.0002] # YI SYLLABLE SHUOX +A3B0 ; [.43A3.0020.0002] # YI SYLLABLE SHUO +A3B1 ; [.43A4.0020.0002] # YI SYLLABLE SHUOP +A3B2 ; [.43A5.0020.0002] # YI SYLLABLE SHOT +A3B3 ; [.43A6.0020.0002] # YI SYLLABLE SHOX +A3B4 ; [.43A7.0020.0002] # YI SYLLABLE SHO +A3B5 ; [.43A8.0020.0002] # YI SYLLABLE SHOP +A3B6 ; [.43A9.0020.0002] # YI SYLLABLE SHET +A3B7 ; [.43AA.0020.0002] # YI SYLLABLE SHEX +A3B8 ; [.43AB.0020.0002] # YI SYLLABLE SHE +A3B9 ; [.43AC.0020.0002] # YI SYLLABLE SHEP +A3BA ; [.43AD.0020.0002] # YI SYLLABLE SHUT +A3BB ; [.43AE.0020.0002] # YI SYLLABLE SHUX +A3BC ; [.43AF.0020.0002] # YI SYLLABLE SHU +A3BD ; [.43B0.0020.0002] # YI SYLLABLE SHUP +A3BE ; [.43B1.0020.0002] # YI SYLLABLE SHURX +A3BF ; [.43B2.0020.0002] # YI SYLLABLE SHUR +A3C0 ; [.43B3.0020.0002] # YI SYLLABLE SHYT +A3C1 ; [.43B4.0020.0002] # YI SYLLABLE SHYX +A3C2 ; [.43B5.0020.0002] # YI SYLLABLE SHY +A3C3 ; [.43B6.0020.0002] # YI SYLLABLE SHYP +A3C4 ; [.43B7.0020.0002] # YI SYLLABLE SHYRX +A3C5 ; [.43B8.0020.0002] # YI SYLLABLE SHYR +A3C6 ; [.43B9.0020.0002] # YI SYLLABLE RAT +A3C7 ; [.43BA.0020.0002] # YI SYLLABLE RAX +A3C8 ; [.43BB.0020.0002] # YI SYLLABLE RA +A3C9 ; [.43BC.0020.0002] # YI SYLLABLE RAP +A3CA ; [.43BD.0020.0002] # YI SYLLABLE RUOX +A3CB ; [.43BE.0020.0002] # YI SYLLABLE RUO +A3CC ; [.43BF.0020.0002] # YI SYLLABLE RUOP +A3CD ; [.43C0.0020.0002] # YI SYLLABLE ROT +A3CE ; [.43C1.0020.0002] # YI SYLLABLE ROX +A3CF ; [.43C2.0020.0002] # YI SYLLABLE RO +A3D0 ; [.43C3.0020.0002] # YI SYLLABLE ROP +A3D1 ; [.43C4.0020.0002] # YI SYLLABLE REX +A3D2 ; [.43C5.0020.0002] # YI SYLLABLE RE +A3D3 ; [.43C6.0020.0002] # YI SYLLABLE REP +A3D4 ; [.43C7.0020.0002] # YI SYLLABLE RUT +A3D5 ; [.43C8.0020.0002] # YI SYLLABLE RUX +A3D6 ; [.43C9.0020.0002] # YI SYLLABLE RU +A3D7 ; [.43CA.0020.0002] # YI SYLLABLE RUP +A3D8 ; [.43CB.0020.0002] # YI SYLLABLE RURX +A3D9 ; [.43CC.0020.0002] # YI SYLLABLE RUR +A3DA ; [.43CD.0020.0002] # YI SYLLABLE RYT +A3DB ; [.43CE.0020.0002] # YI SYLLABLE RYX +A3DC ; [.43CF.0020.0002] # YI SYLLABLE RY +A3DD ; [.43D0.0020.0002] # YI SYLLABLE RYP +A3DE ; [.43D1.0020.0002] # YI SYLLABLE RYRX +A3DF ; [.43D2.0020.0002] # YI SYLLABLE RYR +A3E0 ; [.43D3.0020.0002] # YI SYLLABLE JIT +A3E1 ; [.43D4.0020.0002] # YI SYLLABLE JIX +A3E2 ; [.43D5.0020.0002] # YI SYLLABLE JI +A3E3 ; [.43D6.0020.0002] # YI SYLLABLE JIP +A3E4 ; [.43D7.0020.0002] # YI SYLLABLE JIET +A3E5 ; [.43D8.0020.0002] # YI SYLLABLE JIEX +A3E6 ; [.43D9.0020.0002] # YI SYLLABLE JIE +A3E7 ; [.43DA.0020.0002] # YI SYLLABLE JIEP +A3E8 ; [.43DB.0020.0002] # YI SYLLABLE JUOT +A3E9 ; [.43DC.0020.0002] # YI SYLLABLE JUOX +A3EA ; [.43DD.0020.0002] # YI SYLLABLE JUO +A3EB ; [.43DE.0020.0002] # YI SYLLABLE JUOP +A3EC ; [.43DF.0020.0002] # YI SYLLABLE JOT +A3ED ; [.43E0.0020.0002] # YI SYLLABLE JOX +A3EE ; [.43E1.0020.0002] # YI SYLLABLE JO +A3EF ; [.43E2.0020.0002] # YI SYLLABLE JOP +A3F0 ; [.43E3.0020.0002] # YI SYLLABLE JUT +A3F1 ; [.43E4.0020.0002] # YI SYLLABLE JUX +A3F2 ; [.43E5.0020.0002] # YI SYLLABLE JU +A3F3 ; [.43E6.0020.0002] # YI SYLLABLE JUP +A3F4 ; [.43E7.0020.0002] # YI SYLLABLE JURX +A3F5 ; [.43E8.0020.0002] # YI SYLLABLE JUR +A3F6 ; [.43E9.0020.0002] # YI SYLLABLE JYT +A3F7 ; [.43EA.0020.0002] # YI SYLLABLE JYX +A3F8 ; [.43EB.0020.0002] # YI SYLLABLE JY +A3F9 ; [.43EC.0020.0002] # YI SYLLABLE JYP +A3FA ; [.43ED.0020.0002] # YI SYLLABLE JYRX +A3FB ; [.43EE.0020.0002] # YI SYLLABLE JYR +A3FC ; [.43EF.0020.0002] # YI SYLLABLE QIT +A3FD ; [.43F0.0020.0002] # YI SYLLABLE QIX +A3FE ; [.43F1.0020.0002] # YI SYLLABLE QI +A3FF ; [.43F2.0020.0002] # YI SYLLABLE QIP +A400 ; [.43F3.0020.0002] # YI SYLLABLE QIET +A401 ; [.43F4.0020.0002] # YI SYLLABLE QIEX +A402 ; [.43F5.0020.0002] # YI SYLLABLE QIE +A403 ; [.43F6.0020.0002] # YI SYLLABLE QIEP +A404 ; [.43F7.0020.0002] # YI SYLLABLE QUOT +A405 ; [.43F8.0020.0002] # YI SYLLABLE QUOX +A406 ; [.43F9.0020.0002] # YI SYLLABLE QUO +A407 ; [.43FA.0020.0002] # YI SYLLABLE QUOP +A408 ; [.43FB.0020.0002] # YI SYLLABLE QOT +A409 ; [.43FC.0020.0002] # YI SYLLABLE QOX +A40A ; [.43FD.0020.0002] # YI SYLLABLE QO +A40B ; [.43FE.0020.0002] # YI SYLLABLE QOP +A40C ; [.43FF.0020.0002] # YI SYLLABLE QUT +A40D ; [.4400.0020.0002] # YI SYLLABLE QUX +A40E ; [.4401.0020.0002] # YI SYLLABLE QU +A40F ; [.4402.0020.0002] # YI SYLLABLE QUP +A410 ; [.4403.0020.0002] # YI SYLLABLE QURX +A411 ; [.4404.0020.0002] # YI SYLLABLE QUR +A412 ; [.4405.0020.0002] # YI SYLLABLE QYT +A413 ; [.4406.0020.0002] # YI SYLLABLE QYX +A414 ; [.4407.0020.0002] # YI SYLLABLE QY +A415 ; [.4408.0020.0002] # YI SYLLABLE QYP +A416 ; [.4409.0020.0002] # YI SYLLABLE QYRX +A417 ; [.440A.0020.0002] # YI SYLLABLE QYR +A418 ; [.440B.0020.0002] # YI SYLLABLE JJIT +A419 ; [.440C.0020.0002] # YI SYLLABLE JJIX +A41A ; [.440D.0020.0002] # YI SYLLABLE JJI +A41B ; [.440E.0020.0002] # YI SYLLABLE JJIP +A41C ; [.440F.0020.0002] # YI SYLLABLE JJIET +A41D ; [.4410.0020.0002] # YI SYLLABLE JJIEX +A41E ; [.4411.0020.0002] # YI SYLLABLE JJIE +A41F ; [.4412.0020.0002] # YI SYLLABLE JJIEP +A420 ; [.4413.0020.0002] # YI SYLLABLE JJUOX +A421 ; [.4414.0020.0002] # YI SYLLABLE JJUO +A422 ; [.4415.0020.0002] # YI SYLLABLE JJUOP +A423 ; [.4416.0020.0002] # YI SYLLABLE JJOT +A424 ; [.4417.0020.0002] # YI SYLLABLE JJOX +A425 ; [.4418.0020.0002] # YI SYLLABLE JJO +A426 ; [.4419.0020.0002] # YI SYLLABLE JJOP +A427 ; [.441A.0020.0002] # YI SYLLABLE JJUT +A428 ; [.441B.0020.0002] # YI SYLLABLE JJUX +A429 ; [.441C.0020.0002] # YI SYLLABLE JJU +A42A ; [.441D.0020.0002] # YI SYLLABLE JJUP +A42B ; [.441E.0020.0002] # YI SYLLABLE JJURX +A42C ; [.441F.0020.0002] # YI SYLLABLE JJUR +A42D ; [.4420.0020.0002] # YI SYLLABLE JJYT +A42E ; [.4421.0020.0002] # YI SYLLABLE JJYX +A42F ; [.4422.0020.0002] # YI SYLLABLE JJY +A430 ; [.4423.0020.0002] # YI SYLLABLE JJYP +A431 ; [.4424.0020.0002] # YI SYLLABLE NJIT +A432 ; [.4425.0020.0002] # YI SYLLABLE NJIX +A433 ; [.4426.0020.0002] # YI SYLLABLE NJI +A434 ; [.4427.0020.0002] # YI SYLLABLE NJIP +A435 ; [.4428.0020.0002] # YI SYLLABLE NJIET +A436 ; [.4429.0020.0002] # YI SYLLABLE NJIEX +A437 ; [.442A.0020.0002] # YI SYLLABLE NJIE +A438 ; [.442B.0020.0002] # YI SYLLABLE NJIEP +A439 ; [.442C.0020.0002] # YI SYLLABLE NJUOX +A43A ; [.442D.0020.0002] # YI SYLLABLE NJUO +A43B ; [.442E.0020.0002] # YI SYLLABLE NJOT +A43C ; [.442F.0020.0002] # YI SYLLABLE NJOX +A43D ; [.4430.0020.0002] # YI SYLLABLE NJO +A43E ; [.4431.0020.0002] # YI SYLLABLE NJOP +A43F ; [.4432.0020.0002] # YI SYLLABLE NJUX +A440 ; [.4433.0020.0002] # YI SYLLABLE NJU +A441 ; [.4434.0020.0002] # YI SYLLABLE NJUP +A442 ; [.4435.0020.0002] # YI SYLLABLE NJURX +A443 ; [.4436.0020.0002] # YI SYLLABLE NJUR +A444 ; [.4437.0020.0002] # YI SYLLABLE NJYT +A445 ; [.4438.0020.0002] # YI SYLLABLE NJYX +A446 ; [.4439.0020.0002] # YI SYLLABLE NJY +A447 ; [.443A.0020.0002] # YI SYLLABLE NJYP +A448 ; [.443B.0020.0002] # YI SYLLABLE NJYRX +A449 ; [.443C.0020.0002] # YI SYLLABLE NJYR +A44A ; [.443D.0020.0002] # YI SYLLABLE NYIT +A44B ; [.443E.0020.0002] # YI SYLLABLE NYIX +A44C ; [.443F.0020.0002] # YI SYLLABLE NYI +A44D ; [.4440.0020.0002] # YI SYLLABLE NYIP +A44E ; [.4441.0020.0002] # YI SYLLABLE NYIET +A44F ; [.4442.0020.0002] # YI SYLLABLE NYIEX +A450 ; [.4443.0020.0002] # YI SYLLABLE NYIE +A451 ; [.4444.0020.0002] # YI SYLLABLE NYIEP +A452 ; [.4445.0020.0002] # YI SYLLABLE NYUOX +A453 ; [.4446.0020.0002] # YI SYLLABLE NYUO +A454 ; [.4447.0020.0002] # YI SYLLABLE NYUOP +A455 ; [.4448.0020.0002] # YI SYLLABLE NYOT +A456 ; [.4449.0020.0002] # YI SYLLABLE NYOX +A457 ; [.444A.0020.0002] # YI SYLLABLE NYO +A458 ; [.444B.0020.0002] # YI SYLLABLE NYOP +A459 ; [.444C.0020.0002] # YI SYLLABLE NYUT +A45A ; [.444D.0020.0002] # YI SYLLABLE NYUX +A45B ; [.444E.0020.0002] # YI SYLLABLE NYU +A45C ; [.444F.0020.0002] # YI SYLLABLE NYUP +A45D ; [.4450.0020.0002] # YI SYLLABLE XIT +A45E ; [.4451.0020.0002] # YI SYLLABLE XIX +A45F ; [.4452.0020.0002] # YI SYLLABLE XI +A460 ; [.4453.0020.0002] # YI SYLLABLE XIP +A461 ; [.4454.0020.0002] # YI SYLLABLE XIET +A462 ; [.4455.0020.0002] # YI SYLLABLE XIEX +A463 ; [.4456.0020.0002] # YI SYLLABLE XIE +A464 ; [.4457.0020.0002] # YI SYLLABLE XIEP +A465 ; [.4458.0020.0002] # YI SYLLABLE XUOX +A466 ; [.4459.0020.0002] # YI SYLLABLE XUO +A467 ; [.445A.0020.0002] # YI SYLLABLE XOT +A468 ; [.445B.0020.0002] # YI SYLLABLE XOX +A469 ; [.445C.0020.0002] # YI SYLLABLE XO +A46A ; [.445D.0020.0002] # YI SYLLABLE XOP +A46B ; [.445E.0020.0002] # YI SYLLABLE XYT +A46C ; [.445F.0020.0002] # YI SYLLABLE XYX +A46D ; [.4460.0020.0002] # YI SYLLABLE XY +A46E ; [.4461.0020.0002] # YI SYLLABLE XYP +A46F ; [.4462.0020.0002] # YI SYLLABLE XYRX +A470 ; [.4463.0020.0002] # YI SYLLABLE XYR +A471 ; [.4464.0020.0002] # YI SYLLABLE YIT +A472 ; [.4465.0020.0002] # YI SYLLABLE YIX +A473 ; [.4466.0020.0002] # YI SYLLABLE YI +A474 ; [.4467.0020.0002] # YI SYLLABLE YIP +A475 ; [.4468.0020.0002] # YI SYLLABLE YIET +A476 ; [.4469.0020.0002] # YI SYLLABLE YIEX +A477 ; [.446A.0020.0002] # YI SYLLABLE YIE +A478 ; [.446B.0020.0002] # YI SYLLABLE YIEP +A479 ; [.446C.0020.0002] # YI SYLLABLE YUOT +A47A ; [.446D.0020.0002] # YI SYLLABLE YUOX +A47B ; [.446E.0020.0002] # YI SYLLABLE YUO +A47C ; [.446F.0020.0002] # YI SYLLABLE YUOP +A47D ; [.4470.0020.0002] # YI SYLLABLE YOT +A47E ; [.4471.0020.0002] # YI SYLLABLE YOX +A47F ; [.4472.0020.0002] # YI SYLLABLE YO +A480 ; [.4473.0020.0002] # YI SYLLABLE YOP +A481 ; [.4474.0020.0002] # YI SYLLABLE YUT +A482 ; [.4475.0020.0002] # YI SYLLABLE YUX +A483 ; [.4476.0020.0002] # YI SYLLABLE YU +A484 ; [.4477.0020.0002] # YI SYLLABLE YUP +A485 ; [.4478.0020.0002] # YI SYLLABLE YURX +A486 ; [.4479.0020.0002] # YI SYLLABLE YUR +A487 ; [.447A.0020.0002] # YI SYLLABLE YYT +A488 ; [.447B.0020.0002] # YI SYLLABLE YYX +A489 ; [.447C.0020.0002] # YI SYLLABLE YY +A48A ; [.447D.0020.0002] # YI SYLLABLE YYP +A48B ; [.447E.0020.0002] # YI SYLLABLE YYRX +A48C ; [.447F.0020.0002] # YI SYLLABLE YYR +A4F8 ; [.4480.0020.0002] # LISU LETTER TONE MYA TI +A4F9 ; [.4481.0020.0002] # LISU LETTER TONE NA PO +A4FA ; [.4482.0020.0002] # LISU LETTER TONE MYA CYA +A4FB ; [.4483.0020.0002] # LISU LETTER TONE MYA BO +A4FD ; [.4484.0020.0002] # LISU LETTER TONE MYA JEU +A4FC ; [.4485.0020.0002] # LISU LETTER TONE MYA NA +A4D0 ; [.4486.0020.0002] # LISU LETTER BA +A4D1 ; [.4487.0020.0002] # LISU LETTER PA +A4D2 ; [.4488.0020.0002] # LISU LETTER PHA +A4D3 ; [.4489.0020.0002] # LISU LETTER DA +A4D4 ; [.448A.0020.0002] # LISU LETTER TA +A4D5 ; [.448B.0020.0002] # LISU LETTER THA +A4D6 ; [.448C.0020.0002] # LISU LETTER GA +A4D7 ; [.448D.0020.0002] # LISU LETTER KA +A4D8 ; [.448E.0020.0002] # LISU LETTER KHA +A4D9 ; [.448F.0020.0002] # LISU LETTER JA +A4DA ; [.4490.0020.0002] # LISU LETTER CA +A4DB ; [.4491.0020.0002] # LISU LETTER CHA +A4DC ; [.4492.0020.0002] # LISU LETTER DZA +A4DD ; [.4493.0020.0002] # LISU LETTER TSA +A4DE ; [.4494.0020.0002] # LISU LETTER TSHA +A4DF ; [.4495.0020.0002] # LISU LETTER MA +A4E0 ; [.4496.0020.0002] # LISU LETTER NA +A4E1 ; [.4497.0020.0002] # LISU LETTER LA +A4E2 ; [.4498.0020.0002] # LISU LETTER SA +A4E3 ; [.4499.0020.0002] # LISU LETTER ZHA +A4E4 ; [.449A.0020.0002] # LISU LETTER ZA +A4E5 ; [.449B.0020.0002] # LISU LETTER NGA +A4E6 ; [.449C.0020.0002] # LISU LETTER HA +A4E7 ; [.449D.0020.0002] # LISU LETTER XA +A4E8 ; [.449E.0020.0002] # LISU LETTER HHA +A4E9 ; [.449F.0020.0002] # LISU LETTER FA +A4EB ; [.44A0.0020.0002] # LISU LETTER SHA +A4ED ; [.44A1.0020.0002] # LISU LETTER GHA +A4EA ; [.44A2.0020.0002] # LISU LETTER WA +A4EC ; [.44A3.0020.0002] # LISU LETTER YA +A4EE ; [.44A4.0020.0002] # LISU LETTER A +A4EF ; [.44A5.0020.0002] # LISU LETTER AE +A4F0 ; [.44A6.0020.0002] # LISU LETTER E +A4F1 ; [.44A7.0020.0002] # LISU LETTER EU +A4F2 ; [.44A8.0020.0002] # LISU LETTER I +A4F3 ; [.44A9.0020.0002] # LISU LETTER O +A4F4 ; [.44AA.0020.0002] # LISU LETTER U +A4F5 ; [.44AB.0020.0002] # LISU LETTER UE +A4F6 ; [.44AC.0020.0002] # LISU LETTER UH +A4F7 ; [.44AD.0020.0002] # LISU LETTER OE +16F00 ; [.44AE.0020.0002] # MIAO LETTER PA +16F01 ; [.44AF.0020.0002] # MIAO LETTER BA +16F02 ; [.44B0.0020.0002] # MIAO LETTER YI PA +16F03 ; [.44B1.0020.0002] # MIAO LETTER PLA +16F04 ; [.44B2.0020.0002] # MIAO LETTER MA +16F06 ; [.44B2.0020.0004] # MIAO LETTER ARCHAIC MA +16F05 ; [.44B3.0020.0002] # MIAO LETTER MHA +16F07 ; [.44B4.0020.0002] # MIAO LETTER FA +16F08 ; [.44B5.0020.0002] # MIAO LETTER VA +16F09 ; [.44B6.0020.0002] # MIAO LETTER VFA +16F0A ; [.44B7.0020.0002] # MIAO LETTER TA +16F0B ; [.44B8.0020.0002] # MIAO LETTER DA +16F0C ; [.44B9.0020.0002] # MIAO LETTER YI TTA +16F0D ; [.44BA.0020.0002] # MIAO LETTER YI TA +16F0E ; [.44BB.0020.0002] # MIAO LETTER TTA +16F0F ; [.44BC.0020.0002] # MIAO LETTER DDA +16F10 ; [.44BD.0020.0002] # MIAO LETTER NA +16F13 ; [.44BD.0020.0004] # MIAO LETTER ARCHAIC NA +16F11 ; [.44BE.0020.0002] # MIAO LETTER NHA +16F12 ; [.44BF.0020.0002] # MIAO LETTER YI NNA +16F14 ; [.44C0.0020.0002] # MIAO LETTER NNA +16F15 ; [.44C1.0020.0002] # MIAO LETTER NNHA +16F16 ; [.44C2.0020.0002] # MIAO LETTER LA +16F17 ; [.44C3.0020.0002] # MIAO LETTER LYA +16F18 ; [.44C4.0020.0002] # MIAO LETTER LHA +16F19 ; [.44C5.0020.0002] # MIAO LETTER LHYA +16F1A ; [.44C6.0020.0002] # MIAO LETTER TLHA +16F1B ; [.44C7.0020.0002] # MIAO LETTER DLHA +16F1C ; [.44C8.0020.0002] # MIAO LETTER TLHYA +16F1D ; [.44C9.0020.0002] # MIAO LETTER DLHYA +16F1E ; [.44CA.0020.0002] # MIAO LETTER KA +16F1F ; [.44CB.0020.0002] # MIAO LETTER GA +16F20 ; [.44CC.0020.0002] # MIAO LETTER YI KA +16F21 ; [.44CD.0020.0002] # MIAO LETTER QA +16F22 ; [.44CE.0020.0002] # MIAO LETTER QGA +16F23 ; [.44CF.0020.0002] # MIAO LETTER NGA +16F25 ; [.44CF.0020.0004] # MIAO LETTER ARCHAIC NGA +16F24 ; [.44D0.0020.0002] # MIAO LETTER NGHA +16F26 ; [.44D1.0020.0002] # MIAO LETTER HA +16F27 ; [.44D2.0020.0002] # MIAO LETTER XA +16F28 ; [.44D3.0020.0002] # MIAO LETTER GHA +16F29 ; [.44D4.0020.0002] # MIAO LETTER GHHA +16F2A ; [.44D5.0020.0002] # MIAO LETTER TSSA +16F2B ; [.44D6.0020.0002] # MIAO LETTER DZZA +16F2C ; [.44D7.0020.0002] # MIAO LETTER NYA +16F2D ; [.44D8.0020.0002] # MIAO LETTER NYHA +16F2E ; [.44D9.0020.0002] # MIAO LETTER TSHA +16F2F ; [.44DA.0020.0002] # MIAO LETTER DZHA +16F30 ; [.44DB.0020.0002] # MIAO LETTER YI TSHA +16F31 ; [.44DC.0020.0002] # MIAO LETTER YI DZHA +16F32 ; [.44DD.0020.0002] # MIAO LETTER REFORMED TSHA +16F33 ; [.44DE.0020.0002] # MIAO LETTER SHA +16F34 ; [.44DF.0020.0002] # MIAO LETTER SSA +16F35 ; [.44E0.0020.0002] # MIAO LETTER ZHA +16F36 ; [.44E1.0020.0002] # MIAO LETTER ZSHA +16F37 ; [.44E2.0020.0002] # MIAO LETTER TSA +16F38 ; [.44E3.0020.0002] # MIAO LETTER DZA +16F39 ; [.44E4.0020.0002] # MIAO LETTER YI TSA +16F3A ; [.44E5.0020.0002] # MIAO LETTER SA +16F3B ; [.44E6.0020.0002] # MIAO LETTER ZA +16F3C ; [.44E7.0020.0002] # MIAO LETTER ZSA +16F3D ; [.44E8.0020.0002] # MIAO LETTER ZZA +16F3F ; [.44E8.0020.0004] # MIAO LETTER ARCHAIC ZZA +16F3E ; [.44E9.0020.0002] # MIAO LETTER ZZSA +16F40 ; [.44EA.0020.0002] # MIAO LETTER ZZYA +16F41 ; [.44EB.0020.0002] # MIAO LETTER ZZSYA +16F42 ; [.44EC.0020.0002] # MIAO LETTER WA +16F43 ; [.44ED.0020.0002] # MIAO LETTER AH +16F44 ; [.44EE.0020.0002] # MIAO LETTER HHA +16F50 ; [.44EF.0020.0002] # MIAO LETTER NASALIZATION +16F51 ; [.44F0.0020.0002] # MIAO SIGN ASPIRATION +16F52 ; [.44F1.0020.0002] # MIAO SIGN REFORMED VOICING +16F53 ; [.44F2.0020.0002] # MIAO SIGN REFORMED ASPIRATION +16F54 ; [.44F3.0020.0002] # MIAO VOWEL SIGN A +16F55 ; [.44F4.0020.0002] # MIAO VOWEL SIGN AA +16F56 ; [.44F5.0020.0002] # MIAO VOWEL SIGN AHH +16F57 ; [.44F6.0020.0002] # MIAO VOWEL SIGN AN +16F58 ; [.44F7.0020.0002] # MIAO VOWEL SIGN ANG +16F59 ; [.44F8.0020.0002] # MIAO VOWEL SIGN O +16F5A ; [.44F9.0020.0002] # MIAO VOWEL SIGN OO +16F5B ; [.44FA.0020.0002] # MIAO VOWEL SIGN WO +16F5C ; [.44FB.0020.0002] # MIAO VOWEL SIGN W +16F5D ; [.44FC.0020.0002] # MIAO VOWEL SIGN E +16F5E ; [.44FD.0020.0002] # MIAO VOWEL SIGN EN +16F5F ; [.44FE.0020.0002] # MIAO VOWEL SIGN ENG +16F60 ; [.44FF.0020.0002] # MIAO VOWEL SIGN OEY +16F61 ; [.4500.0020.0002] # MIAO VOWEL SIGN I +16F62 ; [.4501.0020.0002] # MIAO VOWEL SIGN IA +16F63 ; [.4502.0020.0002] # MIAO VOWEL SIGN IAN +16F64 ; [.4503.0020.0002] # MIAO VOWEL SIGN IANG +16F65 ; [.4504.0020.0002] # MIAO VOWEL SIGN IO +16F66 ; [.4505.0020.0002] # MIAO VOWEL SIGN IE +16F67 ; [.4506.0020.0002] # MIAO VOWEL SIGN II +16F68 ; [.4507.0020.0002] # MIAO VOWEL SIGN IU +16F69 ; [.4508.0020.0002] # MIAO VOWEL SIGN ING +16F6A ; [.4509.0020.0002] # MIAO VOWEL SIGN U +16F6B ; [.450A.0020.0002] # MIAO VOWEL SIGN UA +16F6C ; [.450B.0020.0002] # MIAO VOWEL SIGN UAN +16F6D ; [.450C.0020.0002] # MIAO VOWEL SIGN UANG +16F6E ; [.450D.0020.0002] # MIAO VOWEL SIGN UU +16F6F ; [.450E.0020.0002] # MIAO VOWEL SIGN UEI +16F70 ; [.450F.0020.0002] # MIAO VOWEL SIGN UNG +16F71 ; [.4510.0020.0002] # MIAO VOWEL SIGN Y +16F72 ; [.4511.0020.0002] # MIAO VOWEL SIGN YI +16F73 ; [.4512.0020.0002] # MIAO VOWEL SIGN AE +16F74 ; [.4513.0020.0002] # MIAO VOWEL SIGN AEE +16F75 ; [.4514.0020.0002] # MIAO VOWEL SIGN ERR +16F76 ; [.4515.0020.0002] # MIAO VOWEL SIGN ROUNDED ERR +16F77 ; [.4516.0020.0002] # MIAO VOWEL SIGN ER +16F78 ; [.4517.0020.0002] # MIAO VOWEL SIGN ROUNDED ER +16F79 ; [.4518.0020.0002] # MIAO VOWEL SIGN AI +16F7A ; [.4519.0020.0002] # MIAO VOWEL SIGN EI +16F7B ; [.451A.0020.0002] # MIAO VOWEL SIGN AU +16F7C ; [.451B.0020.0002] # MIAO VOWEL SIGN OU +16F7D ; [.451C.0020.0002] # MIAO VOWEL SIGN N +16F7E ; [.451D.0020.0002] # MIAO VOWEL SIGN NG +16F8F ; [.451E.0020.0002] # MIAO TONE RIGHT +16F90 ; [.451F.0020.0002] # MIAO TONE TOP RIGHT +16F91 ; [.4520.0020.0002] # MIAO TONE ABOVE +16F92 ; [.4521.0020.0002] # MIAO TONE BELOW +16F93 ; [.4522.0020.0002] # MIAO LETTER TONE-2 +16F94 ; [.4523.0020.0002] # MIAO LETTER TONE-3 +16F95 ; [.4524.0020.0002] # MIAO LETTER TONE-4 +16F96 ; [.4525.0020.0002] # MIAO LETTER TONE-5 +16F97 ; [.4526.0020.0002] # MIAO LETTER TONE-6 +16F98 ; [.4527.0020.0002] # MIAO LETTER TONE-7 +16F99 ; [.4528.0020.0002] # MIAO LETTER TONE-8 +16F9A ; [.4529.0020.0002] # MIAO LETTER REFORMED TONE-1 +16F9B ; [.452A.0020.0002] # MIAO LETTER REFORMED TONE-2 +16F9C ; [.452B.0020.0002] # MIAO LETTER REFORMED TONE-4 +16F9D ; [.452C.0020.0002] # MIAO LETTER REFORMED TONE-5 +16F9E ; [.452D.0020.0002] # MIAO LETTER REFORMED TONE-6 +16F9F ; [.452E.0020.0002] # MIAO LETTER REFORMED TONE-8 +118FF ; [.452F.0020.0002] # WARANG CITI OM +118C0 ; [.4530.0020.0002] # WARANG CITI SMALL LETTER NGAA +118A0 ; [.4530.0020.0008] # WARANG CITI CAPITAL LETTER NGAA +118C1 ; [.4531.0020.0002] # WARANG CITI SMALL LETTER A +118A1 ; [.4531.0020.0008] # WARANG CITI CAPITAL LETTER A +118C2 ; [.4532.0020.0002] # WARANG CITI SMALL LETTER WI +118A2 ; [.4532.0020.0008] # WARANG CITI CAPITAL LETTER WI +118C3 ; [.4533.0020.0002] # WARANG CITI SMALL LETTER YU +118A3 ; [.4533.0020.0008] # WARANG CITI CAPITAL LETTER YU +118C4 ; [.4534.0020.0002] # WARANG CITI SMALL LETTER YA +118A4 ; [.4534.0020.0008] # WARANG CITI CAPITAL LETTER YA +118C5 ; [.4535.0020.0002] # WARANG CITI SMALL LETTER YO +118A5 ; [.4535.0020.0008] # WARANG CITI CAPITAL LETTER YO +118C6 ; [.4536.0020.0002] # WARANG CITI SMALL LETTER II +118A6 ; [.4536.0020.0008] # WARANG CITI CAPITAL LETTER II +118C7 ; [.4537.0020.0002] # WARANG CITI SMALL LETTER UU +118A7 ; [.4537.0020.0008] # WARANG CITI CAPITAL LETTER UU +118C8 ; [.4538.0020.0002] # WARANG CITI SMALL LETTER E +118A8 ; [.4538.0020.0008] # WARANG CITI CAPITAL LETTER E +118C9 ; [.4539.0020.0002] # WARANG CITI SMALL LETTER O +118A9 ; [.4539.0020.0008] # WARANG CITI CAPITAL LETTER O +118CA ; [.453A.0020.0002] # WARANG CITI SMALL LETTER ANG +118AA ; [.453A.0020.0008] # WARANG CITI CAPITAL LETTER ANG +118CB ; [.453B.0020.0002] # WARANG CITI SMALL LETTER GA +118AB ; [.453B.0020.0008] # WARANG CITI CAPITAL LETTER GA +118CC ; [.453C.0020.0002] # WARANG CITI SMALL LETTER KO +118AC ; [.453C.0020.0008] # WARANG CITI CAPITAL LETTER KO +118CD ; [.453D.0020.0002] # WARANG CITI SMALL LETTER ENY +118AD ; [.453D.0020.0008] # WARANG CITI CAPITAL LETTER ENY +118CE ; [.453E.0020.0002] # WARANG CITI SMALL LETTER YUJ +118AE ; [.453E.0020.0008] # WARANG CITI CAPITAL LETTER YUJ +118CF ; [.453F.0020.0002] # WARANG CITI SMALL LETTER UC +118AF ; [.453F.0020.0008] # WARANG CITI CAPITAL LETTER UC +118D0 ; [.4540.0020.0002] # WARANG CITI SMALL LETTER ENN +118B0 ; [.4540.0020.0008] # WARANG CITI CAPITAL LETTER ENN +118D1 ; [.4541.0020.0002] # WARANG CITI SMALL LETTER ODD +118B1 ; [.4541.0020.0008] # WARANG CITI CAPITAL LETTER ODD +118D2 ; [.4542.0020.0002] # WARANG CITI SMALL LETTER TTE +118B2 ; [.4542.0020.0008] # WARANG CITI CAPITAL LETTER TTE +118D3 ; [.4543.0020.0002] # WARANG CITI SMALL LETTER NUNG +118B3 ; [.4543.0020.0008] # WARANG CITI CAPITAL LETTER NUNG +118D4 ; [.4544.0020.0002] # WARANG CITI SMALL LETTER DA +118B4 ; [.4544.0020.0008] # WARANG CITI CAPITAL LETTER DA +118D5 ; [.4545.0020.0002] # WARANG CITI SMALL LETTER AT +118B5 ; [.4545.0020.0008] # WARANG CITI CAPITAL LETTER AT +118D6 ; [.4546.0020.0002] # WARANG CITI SMALL LETTER AM +118B6 ; [.4546.0020.0008] # WARANG CITI CAPITAL LETTER AM +118D7 ; [.4547.0020.0002] # WARANG CITI SMALL LETTER BU +118B7 ; [.4547.0020.0008] # WARANG CITI CAPITAL LETTER BU +118D8 ; [.4548.0020.0002] # WARANG CITI SMALL LETTER PU +118B8 ; [.4548.0020.0008] # WARANG CITI CAPITAL LETTER PU +118D9 ; [.4549.0020.0002] # WARANG CITI SMALL LETTER HIYO +118B9 ; [.4549.0020.0008] # WARANG CITI CAPITAL LETTER HIYO +118DA ; [.454A.0020.0002] # WARANG CITI SMALL LETTER HOLO +118BA ; [.454A.0020.0008] # WARANG CITI CAPITAL LETTER HOLO +118DB ; [.454B.0020.0002] # WARANG CITI SMALL LETTER HORR +118BB ; [.454B.0020.0008] # WARANG CITI CAPITAL LETTER HORR +118DC ; [.454C.0020.0002] # WARANG CITI SMALL LETTER HAR +118BC ; [.454C.0020.0008] # WARANG CITI CAPITAL LETTER HAR +118DD ; [.454D.0020.0002] # WARANG CITI SMALL LETTER SSUU +118BD ; [.454D.0020.0008] # WARANG CITI CAPITAL LETTER SSUU +118DE ; [.454E.0020.0002] # WARANG CITI SMALL LETTER SII +118BE ; [.454E.0020.0008] # WARANG CITI CAPITAL LETTER SII +118DF ; [.454F.0020.0002] # WARANG CITI SMALL LETTER VIYO +118BF ; [.454F.0020.0008] # WARANG CITI CAPITAL LETTER VIYO +11AD5 ; [.4550.0020.0002] # PAU CIN HAU LETTER A +11AD6 ; [.4551.0020.0002] # PAU CIN HAU LETTER E +11AD7 ; [.4552.0020.0002] # PAU CIN HAU LETTER I +11AD8 ; [.4553.0020.0002] # PAU CIN HAU LETTER O +11AD9 ; [.4554.0020.0002] # PAU CIN HAU LETTER U +11ADA ; [.4555.0020.0002] # PAU CIN HAU LETTER UA +11ADB ; [.4556.0020.0002] # PAU CIN HAU LETTER IA +11AC0 ; [.4557.0020.0002] # PAU CIN HAU LETTER PA +11AC1 ; [.4558.0020.0002] # PAU CIN HAU LETTER KA +11AC2 ; [.4559.0020.0002] # PAU CIN HAU LETTER LA +11AC3 ; [.455A.0020.0002] # PAU CIN HAU LETTER MA +11AC4 ; [.455B.0020.0002] # PAU CIN HAU LETTER DA +11AC5 ; [.455C.0020.0002] # PAU CIN HAU LETTER ZA +11AC6 ; [.455D.0020.0002] # PAU CIN HAU LETTER VA +11AC7 ; [.455E.0020.0002] # PAU CIN HAU LETTER NGA +11AC8 ; [.455F.0020.0002] # PAU CIN HAU LETTER HA +11AC9 ; [.4560.0020.0002] # PAU CIN HAU LETTER GA +11ACA ; [.4561.0020.0002] # PAU CIN HAU LETTER KHA +11ACB ; [.4562.0020.0002] # PAU CIN HAU LETTER SA +11ACC ; [.4563.0020.0002] # PAU CIN HAU LETTER BA +11ACD ; [.4564.0020.0002] # PAU CIN HAU LETTER CA +11ACE ; [.4565.0020.0002] # PAU CIN HAU LETTER TA +11ACF ; [.4566.0020.0002] # PAU CIN HAU LETTER THA +11AD0 ; [.4567.0020.0002] # PAU CIN HAU LETTER NA +11AD1 ; [.4568.0020.0002] # PAU CIN HAU LETTER PHA +11AD2 ; [.4569.0020.0002] # PAU CIN HAU LETTER RA +11AD3 ; [.456A.0020.0002] # PAU CIN HAU LETTER FA +11AD4 ; [.456B.0020.0002] # PAU CIN HAU LETTER CHA +11ADC ; [.456C.0020.0002] # PAU CIN HAU LETTER FINAL P +11ADD ; [.456D.0020.0002] # PAU CIN HAU LETTER FINAL K +11ADF ; [.456E.0020.0002] # PAU CIN HAU LETTER FINAL M +11AE0 ; [.456F.0020.0002] # PAU CIN HAU LETTER FINAL N +11AE1 ; [.4570.0020.0002] # PAU CIN HAU LETTER FINAL L +11AE2 ; [.4571.0020.0002] # PAU CIN HAU LETTER FINAL W +11AE3 ; [.4572.0020.0002] # PAU CIN HAU LETTER FINAL NG +11ADE ; [.4573.0020.0002] # PAU CIN HAU LETTER FINAL T +11AE4 ; [.4574.0020.0002] # PAU CIN HAU LETTER FINAL Y +11AEF ; [.4575.0020.0002] # PAU CIN HAU MID-LEVEL TONE +11AF2 ; [.4576.0020.0002] # PAU CIN HAU MID-LEVEL TONE FINAL +11AF1 ; [.4577.0020.0002] # PAU CIN HAU MID-LEVEL TONE LONG FINAL +11AE6 ; [.4578.0020.0002] # PAU CIN HAU RISING TONE +11AE9 ; [.4579.0020.0002] # PAU CIN HAU RISING TONE FINAL +11AE5 ; [.457A.0020.0002] # PAU CIN HAU RISING TONE LONG +11AE8 ; [.457B.0020.0002] # PAU CIN HAU RISING TONE LONG FINAL +11AF4 ; [.457C.0020.0002] # PAU CIN HAU LOW-FALLING TONE +11AF7 ; [.457D.0020.0002] # PAU CIN HAU LOW-FALLING TONE FINAL +11AF3 ; [.457E.0020.0002] # PAU CIN HAU LOW-FALLING TONE LONG +11AF6 ; [.457F.0020.0002] # PAU CIN HAU LOW-FALLING TONE LONG FINAL +11AEC ; [.4580.0020.0002] # PAU CIN HAU SANDHI TONE +11AEE ; [.4581.0020.0002] # PAU CIN HAU SANDHI TONE FINAL +11AEB ; [.4582.0020.0002] # PAU CIN HAU SANDHI TONE LONG +11AED ; [.4583.0020.0002] # PAU CIN HAU SANDHI TONE LONG FINAL +11AF5 ; [.4584.0020.0002] # PAU CIN HAU GLOTTAL STOP +11AF8 ; [.4585.0020.0002] # PAU CIN HAU GLOTTAL STOP FINAL +11AE7 ; [.4586.0020.0002] # PAU CIN HAU SANDHI GLOTTAL STOP +11AEA ; [.4587.0020.0002] # PAU CIN HAU SANDHI GLOTTAL STOP FINAL +11AF0 ; [.4588.0020.0002] # PAU CIN HAU GLOTTAL STOP VARIANT +16B00 ; [.4589.0020.0002] # PAHAWH HMONG VOWEL KEEB +16B01 ; [.458A.0020.0002] # PAHAWH HMONG VOWEL KEEV +16B02 ; [.458B.0020.0002] # PAHAWH HMONG VOWEL KIB +16B03 ; [.458C.0020.0002] # PAHAWH HMONG VOWEL KIV +16B04 ; [.458D.0020.0002] # PAHAWH HMONG VOWEL KAUB +16B05 ; [.458E.0020.0002] # PAHAWH HMONG VOWEL KAUV +16B06 ; [.458F.0020.0002] # PAHAWH HMONG VOWEL KUB +16B07 ; [.4590.0020.0002] # PAHAWH HMONG VOWEL KUV +16B08 ; [.4591.0020.0002] # PAHAWH HMONG VOWEL KEB +16B09 ; [.4592.0020.0002] # PAHAWH HMONG VOWEL KEV +16B0A ; [.4593.0020.0002] # PAHAWH HMONG VOWEL KAIB +16B0B ; [.4594.0020.0002] # PAHAWH HMONG VOWEL KAIV +16B0C ; [.4595.0020.0002] # PAHAWH HMONG VOWEL KOOB +16B0D ; [.4596.0020.0002] # PAHAWH HMONG VOWEL KOOV +16B0E ; [.4597.0020.0002] # PAHAWH HMONG VOWEL KAWB +16B0F ; [.4598.0020.0002] # PAHAWH HMONG VOWEL KAWV +16B10 ; [.4599.0020.0002] # PAHAWH HMONG VOWEL KUAB +16B11 ; [.459A.0020.0002] # PAHAWH HMONG VOWEL KUAV +16B12 ; [.459B.0020.0002] # PAHAWH HMONG VOWEL KOB +16B13 ; [.459C.0020.0002] # PAHAWH HMONG VOWEL KOV +16B14 ; [.459D.0020.0002] # PAHAWH HMONG VOWEL KIAB +16B15 ; [.459E.0020.0002] # PAHAWH HMONG VOWEL KIAV +16B16 ; [.459F.0020.0002] # PAHAWH HMONG VOWEL KAB +16B17 ; [.45A0.0020.0002] # PAHAWH HMONG VOWEL KAV +16B18 ; [.45A1.0020.0002] # PAHAWH HMONG VOWEL KWB +16B19 ; [.45A2.0020.0002] # PAHAWH HMONG VOWEL KWV +16B1A ; [.45A3.0020.0002] # PAHAWH HMONG VOWEL KAAB +16B1B ; [.45A4.0020.0002] # PAHAWH HMONG VOWEL KAAV +16B1C ; [.45A5.0020.0002] # PAHAWH HMONG CONSONANT VAU +16B1D ; [.45A6.0020.0002] # PAHAWH HMONG CONSONANT NTSAU +16B1E ; [.45A7.0020.0002] # PAHAWH HMONG CONSONANT LAU +16B1F ; [.45A8.0020.0002] # PAHAWH HMONG CONSONANT HAU +16B20 ; [.45A9.0020.0002] # PAHAWH HMONG CONSONANT NLAU +16B21 ; [.45AA.0020.0002] # PAHAWH HMONG CONSONANT RAU +16B22 ; [.45AB.0020.0002] # PAHAWH HMONG CONSONANT NKAU +16B23 ; [.45AC.0020.0002] # PAHAWH HMONG CONSONANT QHAU +16B24 ; [.45AD.0020.0002] # PAHAWH HMONG CONSONANT YAU +16B25 ; [.45AE.0020.0002] # PAHAWH HMONG CONSONANT HLAU +16B26 ; [.45AF.0020.0002] # PAHAWH HMONG CONSONANT MAU +16B27 ; [.45B0.0020.0002] # PAHAWH HMONG CONSONANT CHAU +16B28 ; [.45B1.0020.0002] # PAHAWH HMONG CONSONANT NCHAU +16B29 ; [.45B2.0020.0002] # PAHAWH HMONG CONSONANT HNAU +16B2A ; [.45B3.0020.0002] # PAHAWH HMONG CONSONANT PLHAU +16B2B ; [.45B4.0020.0002] # PAHAWH HMONG CONSONANT NTHAU +16B2C ; [.45B5.0020.0002] # PAHAWH HMONG CONSONANT NAU +16B2D ; [.45B6.0020.0002] # PAHAWH HMONG CONSONANT AU +16B2E ; [.45B7.0020.0002] # PAHAWH HMONG CONSONANT XAU +16B2F ; [.45B8.0020.0002] # PAHAWH HMONG CONSONANT CAU +16B40 ; [.45B9.0020.0002] # PAHAWH HMONG SIGN VOS SEEV +16B41 ; [.45BA.0020.0002] # PAHAWH HMONG SIGN MEEJ SUAB +16B63 ; [.45BB.0020.0002] # PAHAWH HMONG SIGN VOS LUB +16B64 ; [.45BC.0020.0002] # PAHAWH HMONG SIGN XYOO +16B65 ; [.45BD.0020.0002] # PAHAWH HMONG SIGN HLI +16B66 ; [.45BE.0020.0002] # PAHAWH HMONG SIGN THIRD-STAGE HLI +16B67 ; [.45BF.0020.0002] # PAHAWH HMONG SIGN ZWJ THAJ +16B68 ; [.45C0.0020.0002] # PAHAWH HMONG SIGN HNUB +16B69 ; [.45C1.0020.0002] # PAHAWH HMONG SIGN NQIG +16B6A ; [.45C2.0020.0002] # PAHAWH HMONG SIGN XIAB +16B6B ; [.45C3.0020.0002] # PAHAWH HMONG SIGN NTUJ +16B6C ; [.45C4.0020.0002] # PAHAWH HMONG SIGN AV +16B6D ; [.45C5.0020.0002] # PAHAWH HMONG SIGN TXHEEJ CEEV +16B6E ; [.45C6.0020.0002] # PAHAWH HMONG SIGN MEEJ TSEEB +16B6F ; [.45C7.0020.0002] # PAHAWH HMONG SIGN TAU +16B70 ; [.45C8.0020.0002] # PAHAWH HMONG SIGN LOS +16B71 ; [.45C9.0020.0002] # PAHAWH HMONG SIGN MUS +16B72 ; [.45CA.0020.0002] # PAHAWH HMONG SIGN CIM HAIS LUS NTOG NTOG +16B73 ; [.45CB.0020.0002] # PAHAWH HMONG SIGN CIM CUAM TSHOOJ +16B74 ; [.45CC.0020.0002] # PAHAWH HMONG SIGN CIM TXWV +16B75 ; [.45CD.0020.0002] # PAHAWH HMONG SIGN CIM TXWV CHWV +16B76 ; [.45CE.0020.0002] # PAHAWH HMONG SIGN CIM PUB DAWB +16B77 ; [.45CF.0020.0002] # PAHAWH HMONG SIGN CIM NRES TOS +16B7D ; [.45D0.0020.0002] # PAHAWH HMONG CLAN SIGN TSHEEJ +16B7E ; [.45D1.0020.0002] # PAHAWH HMONG CLAN SIGN YEEG +16B7F ; [.45D2.0020.0002] # PAHAWH HMONG CLAN SIGN LIS +16B80 ; [.45D3.0020.0002] # PAHAWH HMONG CLAN SIGN LAUJ +16B81 ; [.45D4.0020.0002] # PAHAWH HMONG CLAN SIGN XYOOJ +16B82 ; [.45D5.0020.0002] # PAHAWH HMONG CLAN SIGN KOO +16B83 ; [.45D6.0020.0002] # PAHAWH HMONG CLAN SIGN HAWJ +16B84 ; [.45D7.0020.0002] # PAHAWH HMONG CLAN SIGN MUAS +16B85 ; [.45D8.0020.0002] # PAHAWH HMONG CLAN SIGN THOJ +16B86 ; [.45D9.0020.0002] # PAHAWH HMONG CLAN SIGN TSAB +16B87 ; [.45DA.0020.0002] # PAHAWH HMONG CLAN SIGN PHAB +16B88 ; [.45DB.0020.0002] # PAHAWH HMONG CLAN SIGN KHAB +16B89 ; [.45DC.0020.0002] # PAHAWH HMONG CLAN SIGN HAM +16B8A ; [.45DD.0020.0002] # PAHAWH HMONG CLAN SIGN VAJ +16B8B ; [.45DE.0020.0002] # PAHAWH HMONG CLAN SIGN FAJ +16B8C ; [.45DF.0020.0002] # PAHAWH HMONG CLAN SIGN YAJ +16B8D ; [.45E0.0020.0002] # PAHAWH HMONG CLAN SIGN TSWB +16B8E ; [.45E1.0020.0002] # PAHAWH HMONG CLAN SIGN KWM +16B8F ; [.45E2.0020.0002] # PAHAWH HMONG CLAN SIGN VWJ +10280 ; [.45E3.0020.0002] # LYCIAN LETTER A +10281 ; [.45E4.0020.0002] # LYCIAN LETTER E +10282 ; [.45E5.0020.0002] # LYCIAN LETTER B +10283 ; [.45E6.0020.0002] # LYCIAN LETTER BH +10284 ; [.45E7.0020.0002] # LYCIAN LETTER G +10285 ; [.45E8.0020.0002] # LYCIAN LETTER D +10286 ; [.45E9.0020.0002] # LYCIAN LETTER I +10287 ; [.45EA.0020.0002] # LYCIAN LETTER W +10288 ; [.45EB.0020.0002] # LYCIAN LETTER Z +10289 ; [.45EC.0020.0002] # LYCIAN LETTER TH +1028A ; [.45ED.0020.0002] # LYCIAN LETTER J +1028B ; [.45EE.0020.0002] # LYCIAN LETTER K +1028C ; [.45EF.0020.0002] # LYCIAN LETTER Q +1028D ; [.45F0.0020.0002] # LYCIAN LETTER L +1028E ; [.45F1.0020.0002] # LYCIAN LETTER M +1028F ; [.45F2.0020.0002] # LYCIAN LETTER N +10290 ; [.45F3.0020.0002] # LYCIAN LETTER MM +10291 ; [.45F4.0020.0002] # LYCIAN LETTER NN +10292 ; [.45F5.0020.0002] # LYCIAN LETTER U +10293 ; [.45F6.0020.0002] # LYCIAN LETTER P +10294 ; [.45F7.0020.0002] # LYCIAN LETTER KK +10295 ; [.45F8.0020.0002] # LYCIAN LETTER R +10296 ; [.45F9.0020.0002] # LYCIAN LETTER S +10297 ; [.45FA.0020.0002] # LYCIAN LETTER T +10298 ; [.45FB.0020.0002] # LYCIAN LETTER TT +10299 ; [.45FC.0020.0002] # LYCIAN LETTER AN +1029A ; [.45FD.0020.0002] # LYCIAN LETTER EN +1029B ; [.45FE.0020.0002] # LYCIAN LETTER H +1029C ; [.45FF.0020.0002] # LYCIAN LETTER X +102A0 ; [.4600.0020.0002] # CARIAN LETTER A +102A1 ; [.4601.0020.0002] # CARIAN LETTER P2 +102A2 ; [.4602.0020.0002] # CARIAN LETTER D +102A3 ; [.4603.0020.0002] # CARIAN LETTER L +102A4 ; [.4604.0020.0002] # CARIAN LETTER UUU +102A5 ; [.4605.0020.0002] # CARIAN LETTER R +102A6 ; [.4606.0020.0002] # CARIAN LETTER LD +102A7 ; [.4607.0020.0002] # CARIAN LETTER A2 +102A8 ; [.4608.0020.0002] # CARIAN LETTER Q +102A9 ; [.4609.0020.0002] # CARIAN LETTER B +102AA ; [.460A.0020.0002] # CARIAN LETTER M +102AB ; [.460B.0020.0002] # CARIAN LETTER O +102AC ; [.460C.0020.0002] # CARIAN LETTER D2 +102AD ; [.460D.0020.0002] # CARIAN LETTER T +102AE ; [.460E.0020.0002] # CARIAN LETTER SH +102AF ; [.460F.0020.0002] # CARIAN LETTER SH2 +102B0 ; [.4610.0020.0002] # CARIAN LETTER S +102B1 ; [.4611.0020.0002] # CARIAN LETTER C-18 +102B2 ; [.4612.0020.0002] # CARIAN LETTER U +102B3 ; [.4613.0020.0002] # CARIAN LETTER NN +102B4 ; [.4614.0020.0002] # CARIAN LETTER X +102B5 ; [.4615.0020.0002] # CARIAN LETTER N +102B6 ; [.4616.0020.0002] # CARIAN LETTER TT2 +102B7 ; [.4617.0020.0002] # CARIAN LETTER P +102B8 ; [.4618.0020.0002] # CARIAN LETTER SS +102B9 ; [.4619.0020.0002] # CARIAN LETTER I +102BA ; [.461A.0020.0002] # CARIAN LETTER E +102BB ; [.461B.0020.0002] # CARIAN LETTER UUUU +102BC ; [.461C.0020.0002] # CARIAN LETTER K +102BD ; [.461D.0020.0002] # CARIAN LETTER K2 +102BE ; [.461E.0020.0002] # CARIAN LETTER ND +102BF ; [.461F.0020.0002] # CARIAN LETTER UU +102C0 ; [.4620.0020.0002] # CARIAN LETTER G +102C1 ; [.4621.0020.0002] # CARIAN LETTER G2 +102C2 ; [.4622.0020.0002] # CARIAN LETTER ST +102C3 ; [.4623.0020.0002] # CARIAN LETTER ST2 +102C4 ; [.4624.0020.0002] # CARIAN LETTER NG +102C5 ; [.4625.0020.0002] # CARIAN LETTER II +102C6 ; [.4626.0020.0002] # CARIAN LETTER C-39 +102C7 ; [.4627.0020.0002] # CARIAN LETTER TT +102C8 ; [.4628.0020.0002] # CARIAN LETTER UUU2 +102C9 ; [.4629.0020.0002] # CARIAN LETTER RR +102CA ; [.462A.0020.0002] # CARIAN LETTER MB +102CB ; [.462B.0020.0002] # CARIAN LETTER MB2 +102CC ; [.462C.0020.0002] # CARIAN LETTER MB3 +102CD ; [.462D.0020.0002] # CARIAN LETTER MB4 +102CE ; [.462E.0020.0002] # CARIAN LETTER LD2 +102CF ; [.462F.0020.0002] # CARIAN LETTER E2 +102D0 ; [.4630.0020.0002] # CARIAN LETTER UUU3 +10920 ; [.4631.0020.0002] # LYDIAN LETTER A +10921 ; [.4632.0020.0002] # LYDIAN LETTER B +10922 ; [.4633.0020.0002] # LYDIAN LETTER G +10923 ; [.4634.0020.0002] # LYDIAN LETTER D +10924 ; [.4635.0020.0002] # LYDIAN LETTER E +10925 ; [.4636.0020.0002] # LYDIAN LETTER V +10926 ; [.4637.0020.0002] # LYDIAN LETTER I +10927 ; [.4638.0020.0002] # LYDIAN LETTER Y +10928 ; [.4639.0020.0002] # LYDIAN LETTER K +10929 ; [.463A.0020.0002] # LYDIAN LETTER L +1092A ; [.463B.0020.0002] # LYDIAN LETTER M +1092B ; [.463C.0020.0002] # LYDIAN LETTER N +1092C ; [.463D.0020.0002] # LYDIAN LETTER O +1092D ; [.463E.0020.0002] # LYDIAN LETTER R +1092E ; [.463F.0020.0002] # LYDIAN LETTER SS +1092F ; [.4640.0020.0002] # LYDIAN LETTER T +10930 ; [.4641.0020.0002] # LYDIAN LETTER U +10931 ; [.4642.0020.0002] # LYDIAN LETTER F +10932 ; [.4643.0020.0002] # LYDIAN LETTER Q +10933 ; [.4644.0020.0002] # LYDIAN LETTER S +10934 ; [.4645.0020.0002] # LYDIAN LETTER TT +10935 ; [.4646.0020.0002] # LYDIAN LETTER AN +10936 ; [.4647.0020.0002] # LYDIAN LETTER EN +10937 ; [.4648.0020.0002] # LYDIAN LETTER LY +10938 ; [.4649.0020.0002] # LYDIAN LETTER NN +10939 ; [.464A.0020.0002] # LYDIAN LETTER C +10300 ; [.464B.0020.0002] # OLD ITALIC LETTER A +10301 ; [.464C.0020.0002] # OLD ITALIC LETTER BE +10302 ; [.464D.0020.0002] # OLD ITALIC LETTER KE +10303 ; [.464E.0020.0002] # OLD ITALIC LETTER DE +10304 ; [.464F.0020.0002] # OLD ITALIC LETTER E +10305 ; [.4650.0020.0002] # OLD ITALIC LETTER VE +10306 ; [.4651.0020.0002] # OLD ITALIC LETTER ZE +10307 ; [.4652.0020.0002] # OLD ITALIC LETTER HE +10308 ; [.4653.0020.0002] # OLD ITALIC LETTER THE +10309 ; [.4654.0020.0002] # OLD ITALIC LETTER I +1030A ; [.4655.0020.0002] # OLD ITALIC LETTER KA +1030B ; [.4656.0020.0002] # OLD ITALIC LETTER EL +1030C ; [.4657.0020.0002] # OLD ITALIC LETTER EM +1030D ; [.4658.0020.0002] # OLD ITALIC LETTER EN +1030E ; [.4659.0020.0002] # OLD ITALIC LETTER ESH +1031F ; [.465A.0020.0002] # OLD ITALIC LETTER ESS +1030F ; [.465B.0020.0002] # OLD ITALIC LETTER O +10310 ; [.465C.0020.0002] # OLD ITALIC LETTER PE +10311 ; [.465D.0020.0002] # OLD ITALIC LETTER SHE +10312 ; [.465E.0020.0002] # OLD ITALIC LETTER KU +10313 ; [.465F.0020.0002] # OLD ITALIC LETTER ER +10314 ; [.4660.0020.0002] # OLD ITALIC LETTER ES +10315 ; [.4661.0020.0002] # OLD ITALIC LETTER TE +10316 ; [.4662.0020.0002] # OLD ITALIC LETTER U +10317 ; [.4663.0020.0002] # OLD ITALIC LETTER EKS +10318 ; [.4664.0020.0002] # OLD ITALIC LETTER PHE +10319 ; [.4665.0020.0002] # OLD ITALIC LETTER KHE +1031A ; [.4666.0020.0002] # OLD ITALIC LETTER EF +1031B ; [.4667.0020.0002] # OLD ITALIC LETTER ERS +1031C ; [.4668.0020.0002] # OLD ITALIC LETTER CHE +1031D ; [.4669.0020.0002] # OLD ITALIC LETTER II +1031E ; [.466A.0020.0002] # OLD ITALIC LETTER UU +1032D ; [.466B.0020.0002] # OLD ITALIC LETTER YE +1032E ; [.466C.0020.0002] # OLD ITALIC LETTER NORTHERN TSE +1032F ; [.466D.0020.0002] # OLD ITALIC LETTER SOUTHERN TSE +10330 ; [.466E.0020.0002] # GOTHIC LETTER AHSA +10331 ; [.466F.0020.0002] # GOTHIC LETTER BAIRKAN +10332 ; [.4670.0020.0002] # GOTHIC LETTER GIBA +10333 ; [.4671.0020.0002] # GOTHIC LETTER DAGS +10334 ; [.4672.0020.0002] # GOTHIC LETTER AIHVUS +10335 ; [.4673.0020.0002] # GOTHIC LETTER QAIRTHRA +10336 ; [.4674.0020.0002] # GOTHIC LETTER IUJA +10337 ; [.4675.0020.0002] # GOTHIC LETTER HAGL +10338 ; [.4676.0020.0002] # GOTHIC LETTER THIUTH +10339 ; [.4677.0020.0002] # GOTHIC LETTER EIS +1033A ; [.4678.0020.0002] # GOTHIC LETTER KUSMA +1033B ; [.4679.0020.0002] # GOTHIC LETTER LAGUS +1033C ; [.467A.0020.0002] # GOTHIC LETTER MANNA +1033D ; [.467B.0020.0002] # GOTHIC LETTER NAUTHS +1033E ; [.467C.0020.0002] # GOTHIC LETTER JER +1033F ; [.467D.0020.0002] # GOTHIC LETTER URUS +10340 ; [.467E.0020.0002] # GOTHIC LETTER PAIRTHRA +10341 ; [.467F.0020.0002] # GOTHIC LETTER NINETY +10342 ; [.4680.0020.0002] # GOTHIC LETTER RAIDA +10343 ; [.4681.0020.0002] # GOTHIC LETTER SAUIL +10344 ; [.4682.0020.0002] # GOTHIC LETTER TEIWS +10345 ; [.4683.0020.0002] # GOTHIC LETTER WINJA +10346 ; [.4684.0020.0002] # GOTHIC LETTER FAIHU +10347 ; [.4685.0020.0002] # GOTHIC LETTER IGGWS +10348 ; [.4686.0020.0002] # GOTHIC LETTER HWAIR +10349 ; [.4687.0020.0002] # GOTHIC LETTER OTHAL +1034A ; [.4688.0020.0002] # GOTHIC LETTER NINE HUNDRED +10428 ; [.4689.0020.0002] # DESERET SMALL LETTER LONG I +10400 ; [.4689.0020.0008] # DESERET CAPITAL LETTER LONG I +10429 ; [.468A.0020.0002] # DESERET SMALL LETTER LONG E +10401 ; [.468A.0020.0008] # DESERET CAPITAL LETTER LONG E +1042A ; [.468B.0020.0002] # DESERET SMALL LETTER LONG A +10402 ; [.468B.0020.0008] # DESERET CAPITAL LETTER LONG A +1042B ; [.468C.0020.0002] # DESERET SMALL LETTER LONG AH +10403 ; [.468C.0020.0008] # DESERET CAPITAL LETTER LONG AH +1042C ; [.468D.0020.0002] # DESERET SMALL LETTER LONG O +10404 ; [.468D.0020.0008] # DESERET CAPITAL LETTER LONG O +1042D ; [.468E.0020.0002] # DESERET SMALL LETTER LONG OO +10405 ; [.468E.0020.0008] # DESERET CAPITAL LETTER LONG OO +1042E ; [.468F.0020.0002] # DESERET SMALL LETTER SHORT I +10406 ; [.468F.0020.0008] # DESERET CAPITAL LETTER SHORT I +1042F ; [.4690.0020.0002] # DESERET SMALL LETTER SHORT E +10407 ; [.4690.0020.0008] # DESERET CAPITAL LETTER SHORT E +10430 ; [.4691.0020.0002] # DESERET SMALL LETTER SHORT A +10408 ; [.4691.0020.0008] # DESERET CAPITAL LETTER SHORT A +10431 ; [.4692.0020.0002] # DESERET SMALL LETTER SHORT AH +10409 ; [.4692.0020.0008] # DESERET CAPITAL LETTER SHORT AH +10432 ; [.4693.0020.0002] # DESERET SMALL LETTER SHORT O +1040A ; [.4693.0020.0008] # DESERET CAPITAL LETTER SHORT O +10433 ; [.4694.0020.0002] # DESERET SMALL LETTER SHORT OO +1040B ; [.4694.0020.0008] # DESERET CAPITAL LETTER SHORT OO +10434 ; [.4695.0020.0002] # DESERET SMALL LETTER AY +1040C ; [.4695.0020.0008] # DESERET CAPITAL LETTER AY +10435 ; [.4696.0020.0002] # DESERET SMALL LETTER OW +1040D ; [.4696.0020.0008] # DESERET CAPITAL LETTER OW +10436 ; [.4697.0020.0002] # DESERET SMALL LETTER WU +1040E ; [.4697.0020.0008] # DESERET CAPITAL LETTER WU +10437 ; [.4698.0020.0002] # DESERET SMALL LETTER YEE +1040F ; [.4698.0020.0008] # DESERET CAPITAL LETTER YEE +10438 ; [.4699.0020.0002] # DESERET SMALL LETTER H +10410 ; [.4699.0020.0008] # DESERET CAPITAL LETTER H +10439 ; [.469A.0020.0002] # DESERET SMALL LETTER PEE +10411 ; [.469A.0020.0008] # DESERET CAPITAL LETTER PEE +1043A ; [.469B.0020.0002] # DESERET SMALL LETTER BEE +10412 ; [.469B.0020.0008] # DESERET CAPITAL LETTER BEE +1043B ; [.469C.0020.0002] # DESERET SMALL LETTER TEE +10413 ; [.469C.0020.0008] # DESERET CAPITAL LETTER TEE +1043C ; [.469D.0020.0002] # DESERET SMALL LETTER DEE +10414 ; [.469D.0020.0008] # DESERET CAPITAL LETTER DEE +1043D ; [.469E.0020.0002] # DESERET SMALL LETTER CHEE +10415 ; [.469E.0020.0008] # DESERET CAPITAL LETTER CHEE +1043E ; [.469F.0020.0002] # DESERET SMALL LETTER JEE +10416 ; [.469F.0020.0008] # DESERET CAPITAL LETTER JEE +1043F ; [.46A0.0020.0002] # DESERET SMALL LETTER KAY +10417 ; [.46A0.0020.0008] # DESERET CAPITAL LETTER KAY +10440 ; [.46A1.0020.0002] # DESERET SMALL LETTER GAY +10418 ; [.46A1.0020.0008] # DESERET CAPITAL LETTER GAY +10441 ; [.46A2.0020.0002] # DESERET SMALL LETTER EF +10419 ; [.46A2.0020.0008] # DESERET CAPITAL LETTER EF +10442 ; [.46A3.0020.0002] # DESERET SMALL LETTER VEE +1041A ; [.46A3.0020.0008] # DESERET CAPITAL LETTER VEE +10443 ; [.46A4.0020.0002] # DESERET SMALL LETTER ETH +1041B ; [.46A4.0020.0008] # DESERET CAPITAL LETTER ETH +10444 ; [.46A5.0020.0002] # DESERET SMALL LETTER THEE +1041C ; [.46A5.0020.0008] # DESERET CAPITAL LETTER THEE +10445 ; [.46A6.0020.0002] # DESERET SMALL LETTER ES +1041D ; [.46A6.0020.0008] # DESERET CAPITAL LETTER ES +10446 ; [.46A7.0020.0002] # DESERET SMALL LETTER ZEE +1041E ; [.46A7.0020.0008] # DESERET CAPITAL LETTER ZEE +10447 ; [.46A8.0020.0002] # DESERET SMALL LETTER ESH +1041F ; [.46A8.0020.0008] # DESERET CAPITAL LETTER ESH +10448 ; [.46A9.0020.0002] # DESERET SMALL LETTER ZHEE +10420 ; [.46A9.0020.0008] # DESERET CAPITAL LETTER ZHEE +10449 ; [.46AA.0020.0002] # DESERET SMALL LETTER ER +10421 ; [.46AA.0020.0008] # DESERET CAPITAL LETTER ER +1044A ; [.46AB.0020.0002] # DESERET SMALL LETTER EL +10422 ; [.46AB.0020.0008] # DESERET CAPITAL LETTER EL +1044B ; [.46AC.0020.0002] # DESERET SMALL LETTER EM +10423 ; [.46AC.0020.0008] # DESERET CAPITAL LETTER EM +1044C ; [.46AD.0020.0002] # DESERET SMALL LETTER EN +10424 ; [.46AD.0020.0008] # DESERET CAPITAL LETTER EN +1044D ; [.46AE.0020.0002] # DESERET SMALL LETTER ENG +10425 ; [.46AE.0020.0008] # DESERET CAPITAL LETTER ENG +1044E ; [.46AF.0020.0002] # DESERET SMALL LETTER OI +10426 ; [.46AF.0020.0008] # DESERET CAPITAL LETTER OI +1044F ; [.46B0.0020.0002] # DESERET SMALL LETTER EW +10427 ; [.46B0.0020.0008] # DESERET CAPITAL LETTER EW +10450 ; [.46B1.0020.0002] # SHAVIAN LETTER PEEP +10451 ; [.46B2.0020.0002] # SHAVIAN LETTER TOT +10452 ; [.46B3.0020.0002] # SHAVIAN LETTER KICK +10453 ; [.46B4.0020.0002] # SHAVIAN LETTER FEE +10454 ; [.46B5.0020.0002] # SHAVIAN LETTER THIGH +10455 ; [.46B6.0020.0002] # SHAVIAN LETTER SO +10456 ; [.46B7.0020.0002] # SHAVIAN LETTER SURE +10457 ; [.46B8.0020.0002] # SHAVIAN LETTER CHURCH +10458 ; [.46B9.0020.0002] # SHAVIAN LETTER YEA +10459 ; [.46BA.0020.0002] # SHAVIAN LETTER HUNG +1045A ; [.46BB.0020.0002] # SHAVIAN LETTER BIB +1045B ; [.46BC.0020.0002] # SHAVIAN LETTER DEAD +1045C ; [.46BD.0020.0002] # SHAVIAN LETTER GAG +1045D ; [.46BE.0020.0002] # SHAVIAN LETTER VOW +1045E ; [.46BF.0020.0002] # SHAVIAN LETTER THEY +1045F ; [.46C0.0020.0002] # SHAVIAN LETTER ZOO +10460 ; [.46C1.0020.0002] # SHAVIAN LETTER MEASURE +10461 ; [.46C2.0020.0002] # SHAVIAN LETTER JUDGE +10462 ; [.46C3.0020.0002] # SHAVIAN LETTER WOE +10463 ; [.46C4.0020.0002] # SHAVIAN LETTER HA-HA +10464 ; [.46C5.0020.0002] # SHAVIAN LETTER LOLL +10465 ; [.46C6.0020.0002] # SHAVIAN LETTER MIME +10466 ; [.46C7.0020.0002] # SHAVIAN LETTER IF +10467 ; [.46C8.0020.0002] # SHAVIAN LETTER EGG +10468 ; [.46C9.0020.0002] # SHAVIAN LETTER ASH +10469 ; [.46CA.0020.0002] # SHAVIAN LETTER ADO +1046A ; [.46CB.0020.0002] # SHAVIAN LETTER ON +1046B ; [.46CC.0020.0002] # SHAVIAN LETTER WOOL +1046C ; [.46CD.0020.0002] # SHAVIAN LETTER OUT +1046D ; [.46CE.0020.0002] # SHAVIAN LETTER AH +1046E ; [.46CF.0020.0002] # SHAVIAN LETTER ROAR +1046F ; [.46D0.0020.0002] # SHAVIAN LETTER NUN +10470 ; [.46D1.0020.0002] # SHAVIAN LETTER EAT +10471 ; [.46D2.0020.0002] # SHAVIAN LETTER AGE +10472 ; [.46D3.0020.0002] # SHAVIAN LETTER ICE +10473 ; [.46D4.0020.0002] # SHAVIAN LETTER UP +10474 ; [.46D5.0020.0002] # SHAVIAN LETTER OAK +10475 ; [.46D6.0020.0002] # SHAVIAN LETTER OOZE +10476 ; [.46D7.0020.0002] # SHAVIAN LETTER OIL +10477 ; [.46D8.0020.0002] # SHAVIAN LETTER AWE +10478 ; [.46D9.0020.0002] # SHAVIAN LETTER ARE +10479 ; [.46DA.0020.0002] # SHAVIAN LETTER OR +1047A ; [.46DB.0020.0002] # SHAVIAN LETTER AIR +1047B ; [.46DC.0020.0002] # SHAVIAN LETTER ERR +1047C ; [.46DD.0020.0002] # SHAVIAN LETTER ARRAY +1047D ; [.46DE.0020.0002] # SHAVIAN LETTER EAR +1047E ; [.46DF.0020.0002] # SHAVIAN LETTER IAN +1047F ; [.46E0.0020.0002] # SHAVIAN LETTER YEW +1BC00 ; [.46E1.0020.0002] # DUPLOYAN LETTER H +1BC01 ; [.46E2.0020.0002] # DUPLOYAN LETTER X +1BC02 ; [.46E3.0020.0002] # DUPLOYAN LETTER P +1BC03 ; [.46E4.0020.0002] # DUPLOYAN LETTER T +1BC04 ; [.46E5.0020.0002] # DUPLOYAN LETTER F +1BC05 ; [.46E6.0020.0002] # DUPLOYAN LETTER K +1BC06 ; [.46E7.0020.0002] # DUPLOYAN LETTER L +1BC07 ; [.46E8.0020.0002] # DUPLOYAN LETTER B +1BC08 ; [.46E9.0020.0002] # DUPLOYAN LETTER D +1BC09 ; [.46EA.0020.0002] # DUPLOYAN LETTER V +1BC0A ; [.46EB.0020.0002] # DUPLOYAN LETTER G +1BC0B ; [.46EC.0020.0002] # DUPLOYAN LETTER R +1BC0C ; [.46ED.0020.0002] # DUPLOYAN LETTER P N +1BC0D ; [.46EE.0020.0002] # DUPLOYAN LETTER D S +1BC0E ; [.46EF.0020.0002] # DUPLOYAN LETTER F N +1BC0F ; [.46F0.0020.0002] # DUPLOYAN LETTER K M +1BC10 ; [.46F1.0020.0002] # DUPLOYAN LETTER R S +1BC11 ; [.46F2.0020.0002] # DUPLOYAN LETTER TH +1BC12 ; [.46F3.0020.0002] # DUPLOYAN LETTER SLOAN DH +1BC13 ; [.46F4.0020.0002] # DUPLOYAN LETTER DH +1BC14 ; [.46F5.0020.0002] # DUPLOYAN LETTER KK +1BC15 ; [.46F6.0020.0002] # DUPLOYAN LETTER SLOAN J +1BC16 ; [.46F7.0020.0002] # DUPLOYAN LETTER HL +1BC17 ; [.46F8.0020.0002] # DUPLOYAN LETTER LH +1BC18 ; [.46F9.0020.0002] # DUPLOYAN LETTER RH +1BC19 ; [.46FA.0020.0002] # DUPLOYAN LETTER M +1BC1A ; [.46FB.0020.0002] # DUPLOYAN LETTER N +1BC1B ; [.46FC.0020.0002] # DUPLOYAN LETTER J +1BC1C ; [.46FD.0020.0002] # DUPLOYAN LETTER S +1BC1D ; [.46FE.0020.0002] # DUPLOYAN LETTER M N +1BC1E ; [.46FF.0020.0002] # DUPLOYAN LETTER N M +1BC1F ; [.4700.0020.0002] # DUPLOYAN LETTER J M +1BC20 ; [.4701.0020.0002] # DUPLOYAN LETTER S J +1BC21 ; [.4702.0020.0002] # DUPLOYAN LETTER M WITH DOT +1BC22 ; [.4703.0020.0002] # DUPLOYAN LETTER N WITH DOT +1BC23 ; [.4704.0020.0002] # DUPLOYAN LETTER J WITH DOT +1BC24 ; [.4705.0020.0002] # DUPLOYAN LETTER J WITH DOTS INSIDE AND ABOVE +1BC25 ; [.4706.0020.0002] # DUPLOYAN LETTER S WITH DOT +1BC26 ; [.4707.0020.0002] # DUPLOYAN LETTER S WITH DOT BELOW +1BC27 ; [.4708.0020.0002] # DUPLOYAN LETTER M S +1BC28 ; [.4709.0020.0002] # DUPLOYAN LETTER N S +1BC29 ; [.470A.0020.0002] # DUPLOYAN LETTER J S +1BC2A ; [.470B.0020.0002] # DUPLOYAN LETTER S S +1BC2B ; [.470C.0020.0002] # DUPLOYAN LETTER M N S +1BC2C ; [.470D.0020.0002] # DUPLOYAN LETTER N M S +1BC2D ; [.470E.0020.0002] # DUPLOYAN LETTER J M S +1BC2E ; [.470F.0020.0002] # DUPLOYAN LETTER S J S +1BC2F ; [.4710.0020.0002] # DUPLOYAN LETTER J S WITH DOT +1BC30 ; [.4711.0020.0002] # DUPLOYAN LETTER J N +1BC31 ; [.4712.0020.0002] # DUPLOYAN LETTER J N S +1BC32 ; [.4713.0020.0002] # DUPLOYAN LETTER S T +1BC33 ; [.4714.0020.0002] # DUPLOYAN LETTER S T R +1BC34 ; [.4715.0020.0002] # DUPLOYAN LETTER S P +1BC35 ; [.4716.0020.0002] # DUPLOYAN LETTER S P R +1BC36 ; [.4717.0020.0002] # DUPLOYAN LETTER T S +1BC37 ; [.4718.0020.0002] # DUPLOYAN LETTER T R S +1BC38 ; [.4719.0020.0002] # DUPLOYAN LETTER W +1BC39 ; [.471A.0020.0002] # DUPLOYAN LETTER WH +1BC3A ; [.471B.0020.0002] # DUPLOYAN LETTER W R +1BC3B ; [.471C.0020.0002] # DUPLOYAN LETTER S N +1BC3C ; [.471D.0020.0002] # DUPLOYAN LETTER S M +1BC3D ; [.471E.0020.0002] # DUPLOYAN LETTER K R S +1BC3E ; [.471F.0020.0002] # DUPLOYAN LETTER G R S +1BC3F ; [.4720.0020.0002] # DUPLOYAN LETTER S K +1BC40 ; [.4721.0020.0002] # DUPLOYAN LETTER S K R +1BC41 ; [.4722.0020.0002] # DUPLOYAN LETTER A +1BC42 ; [.4723.0020.0002] # DUPLOYAN LETTER SLOAN OW +1BC43 ; [.4724.0020.0002] # DUPLOYAN LETTER OA +1BC44 ; [.4725.0020.0002] # DUPLOYAN LETTER O +1BC45 ; [.4726.0020.0002] # DUPLOYAN LETTER AOU +1BC46 ; [.4727.0020.0002] # DUPLOYAN LETTER I +1BC47 ; [.4728.0020.0002] # DUPLOYAN LETTER E +1BC48 ; [.4729.0020.0002] # DUPLOYAN LETTER IE +1BC49 ; [.472A.0020.0002] # DUPLOYAN LETTER SHORT I +1BC4A ; [.472B.0020.0002] # DUPLOYAN LETTER UI +1BC4B ; [.472C.0020.0002] # DUPLOYAN LETTER EE +1BC4C ; [.472D.0020.0002] # DUPLOYAN LETTER SLOAN EH +1BC4D ; [.472E.0020.0002] # DUPLOYAN LETTER ROMANIAN I +1BC4E ; [.472F.0020.0002] # DUPLOYAN LETTER SLOAN EE +1BC4F ; [.4730.0020.0002] # DUPLOYAN LETTER LONG I +1BC50 ; [.4731.0020.0002] # DUPLOYAN LETTER YE +1BC51 ; [.4732.0020.0002] # DUPLOYAN LETTER U +1BC52 ; [.4733.0020.0002] # DUPLOYAN LETTER EU +1BC53 ; [.4734.0020.0002] # DUPLOYAN LETTER XW +1BC54 ; [.4735.0020.0002] # DUPLOYAN LETTER U N +1BC55 ; [.4736.0020.0002] # DUPLOYAN LETTER LONG U +1BC56 ; [.4737.0020.0002] # DUPLOYAN LETTER ROMANIAN U +1BC57 ; [.4738.0020.0002] # DUPLOYAN LETTER UH +1BC58 ; [.4739.0020.0002] # DUPLOYAN LETTER SLOAN U +1BC59 ; [.473A.0020.0002] # DUPLOYAN LETTER OOH +1BC5A ; [.473B.0020.0002] # DUPLOYAN LETTER OW +1BC5B ; [.473C.0020.0002] # DUPLOYAN LETTER OU +1BC5C ; [.473D.0020.0002] # DUPLOYAN LETTER WA +1BC5D ; [.473E.0020.0002] # DUPLOYAN LETTER WO +1BC5E ; [.473F.0020.0002] # DUPLOYAN LETTER WI +1BC5F ; [.4740.0020.0002] # DUPLOYAN LETTER WEI +1BC60 ; [.4741.0020.0002] # DUPLOYAN LETTER WOW +1BC61 ; [.4742.0020.0002] # DUPLOYAN LETTER NASAL U +1BC62 ; [.4743.0020.0002] # DUPLOYAN LETTER NASAL O +1BC63 ; [.4744.0020.0002] # DUPLOYAN LETTER NASAL I +1BC64 ; [.4745.0020.0002] # DUPLOYAN LETTER NASAL A +1BC65 ; [.4746.0020.0002] # DUPLOYAN LETTER PERNIN AN +1BC66 ; [.4747.0020.0002] # DUPLOYAN LETTER PERNIN AM +1BC67 ; [.4748.0020.0002] # DUPLOYAN LETTER SLOAN EN +1BC68 ; [.4749.0020.0002] # DUPLOYAN LETTER SLOAN AN +1BC69 ; [.474A.0020.0002] # DUPLOYAN LETTER SLOAN ON +1BC6A ; [.474B.0020.0002] # DUPLOYAN LETTER VOCALIC M +1BC70 ; [.474C.0020.0002] # DUPLOYAN AFFIX LEFT HORIZONTAL SECANT +1BC71 ; [.474D.0020.0002] # DUPLOYAN AFFIX MID HORIZONTAL SECANT +1BC72 ; [.474E.0020.0002] # DUPLOYAN AFFIX RIGHT HORIZONTAL SECANT +1BC73 ; [.474F.0020.0002] # DUPLOYAN AFFIX LOW VERTICAL SECANT +1BC74 ; [.4750.0020.0002] # DUPLOYAN AFFIX MID VERTICAL SECANT +1BC75 ; [.4751.0020.0002] # DUPLOYAN AFFIX HIGH VERTICAL SECANT +1BC76 ; [.4752.0020.0002] # DUPLOYAN AFFIX ATTACHED SECANT +1BC77 ; [.4753.0020.0002] # DUPLOYAN AFFIX ATTACHED LEFT-TO-RIGHT SECANT +1BC78 ; [.4754.0020.0002] # DUPLOYAN AFFIX ATTACHED TANGENT +1BC79 ; [.4755.0020.0002] # DUPLOYAN AFFIX ATTACHED TAIL +1BC7A ; [.4756.0020.0002] # DUPLOYAN AFFIX ATTACHED E HOOK +1BC7B ; [.4757.0020.0002] # DUPLOYAN AFFIX ATTACHED I HOOK +1BC7C ; [.4758.0020.0002] # DUPLOYAN AFFIX ATTACHED TANGENT HOOK +1BC80 ; [.4759.0020.0002] # DUPLOYAN AFFIX HIGH ACUTE +1BC81 ; [.475A.0020.0002] # DUPLOYAN AFFIX HIGH TIGHT ACUTE +1BC82 ; [.475B.0020.0002] # DUPLOYAN AFFIX HIGH GRAVE +1BC83 ; [.475C.0020.0002] # DUPLOYAN AFFIX HIGH LONG GRAVE +1BC84 ; [.475D.0020.0002] # DUPLOYAN AFFIX HIGH DOT +1BC85 ; [.475E.0020.0002] # DUPLOYAN AFFIX HIGH CIRCLE +1BC86 ; [.475F.0020.0002] # DUPLOYAN AFFIX HIGH LINE +1BC87 ; [.4760.0020.0002] # DUPLOYAN AFFIX HIGH WAVE +1BC88 ; [.4761.0020.0002] # DUPLOYAN AFFIX HIGH VERTICAL +1BC90 ; [.4762.0020.0002] # DUPLOYAN AFFIX LOW ACUTE +1BC91 ; [.4763.0020.0002] # DUPLOYAN AFFIX LOW TIGHT ACUTE +1BC92 ; [.4764.0020.0002] # DUPLOYAN AFFIX LOW GRAVE +1BC93 ; [.4765.0020.0002] # DUPLOYAN AFFIX LOW LONG GRAVE +1BC94 ; [.4766.0020.0002] # DUPLOYAN AFFIX LOW DOT +1BC95 ; [.4767.0020.0002] # DUPLOYAN AFFIX LOW CIRCLE +1BC96 ; [.4768.0020.0002] # DUPLOYAN AFFIX LOW LINE +1BC97 ; [.4769.0020.0002] # DUPLOYAN AFFIX LOW WAVE +1BC98 ; [.476A.0020.0002] # DUPLOYAN AFFIX LOW VERTICAL +1BC99 ; [.476B.0020.0002] # DUPLOYAN AFFIX LOW ARROW +10480 ; [.476C.0020.0002] # OSMANYA LETTER ALEF +10481 ; [.476D.0020.0002] # OSMANYA LETTER BA +10482 ; [.476E.0020.0002] # OSMANYA LETTER TA +10483 ; [.476F.0020.0002] # OSMANYA LETTER JA +10484 ; [.4770.0020.0002] # OSMANYA LETTER XA +10485 ; [.4771.0020.0002] # OSMANYA LETTER KHA +10486 ; [.4772.0020.0002] # OSMANYA LETTER DEEL +10487 ; [.4773.0020.0002] # OSMANYA LETTER RA +10488 ; [.4774.0020.0002] # OSMANYA LETTER SA +10489 ; [.4775.0020.0002] # OSMANYA LETTER SHIIN +1048A ; [.4776.0020.0002] # OSMANYA LETTER DHA +1048B ; [.4777.0020.0002] # OSMANYA LETTER CAYN +1048C ; [.4778.0020.0002] # OSMANYA LETTER GA +1048D ; [.4779.0020.0002] # OSMANYA LETTER FA +1048E ; [.477A.0020.0002] # OSMANYA LETTER QAAF +1048F ; [.477B.0020.0002] # OSMANYA LETTER KAAF +10490 ; [.477C.0020.0002] # OSMANYA LETTER LAAN +10491 ; [.477D.0020.0002] # OSMANYA LETTER MIIN +10492 ; [.477E.0020.0002] # OSMANYA LETTER NUUN +10493 ; [.477F.0020.0002] # OSMANYA LETTER WAW +10494 ; [.4780.0020.0002] # OSMANYA LETTER HA +10495 ; [.4781.0020.0002] # OSMANYA LETTER YA +10496 ; [.4782.0020.0002] # OSMANYA LETTER A +10497 ; [.4783.0020.0002] # OSMANYA LETTER E +10498 ; [.4784.0020.0002] # OSMANYA LETTER I +10499 ; [.4785.0020.0002] # OSMANYA LETTER O +1049A ; [.4786.0020.0002] # OSMANYA LETTER U +1049B ; [.4787.0020.0002] # OSMANYA LETTER AA +1049C ; [.4788.0020.0002] # OSMANYA LETTER EE +1049D ; [.4789.0020.0002] # OSMANYA LETTER OO +10500 ; [.478A.0020.0002] # ELBASAN LETTER A +10501 ; [.478B.0020.0002] # ELBASAN LETTER BE +10502 ; [.478C.0020.0002] # ELBASAN LETTER CE +10503 ; [.478D.0020.0002] # ELBASAN LETTER CHE +10504 ; [.478E.0020.0002] # ELBASAN LETTER DE +10505 ; [.478F.0020.0002] # ELBASAN LETTER NDE +10506 ; [.4790.0020.0002] # ELBASAN LETTER DHE +10507 ; [.4791.0020.0002] # ELBASAN LETTER EI +10508 ; [.4792.0020.0002] # ELBASAN LETTER E +10509 ; [.4793.0020.0002] # ELBASAN LETTER FE +1050A ; [.4794.0020.0002] # ELBASAN LETTER GE +1050B ; [.4795.0020.0002] # ELBASAN LETTER GJE +1050C ; [.4796.0020.0002] # ELBASAN LETTER HE +1050D ; [.4797.0020.0002] # ELBASAN LETTER I +1050E ; [.4798.0020.0002] # ELBASAN LETTER JE +1050F ; [.4799.0020.0002] # ELBASAN LETTER KE +10510 ; [.479A.0020.0002] # ELBASAN LETTER LE +10511 ; [.479B.0020.0002] # ELBASAN LETTER LLE +10512 ; [.479C.0020.0002] # ELBASAN LETTER ME +10513 ; [.479D.0020.0002] # ELBASAN LETTER NE +10514 ; [.479E.0020.0002] # ELBASAN LETTER NA +10515 ; [.479F.0020.0002] # ELBASAN LETTER NJE +10516 ; [.47A0.0020.0002] # ELBASAN LETTER O +10517 ; [.47A1.0020.0002] # ELBASAN LETTER PE +10518 ; [.47A2.0020.0002] # ELBASAN LETTER QE +10519 ; [.47A3.0020.0002] # ELBASAN LETTER RE +1051A ; [.47A4.0020.0002] # ELBASAN LETTER RRE +1051B ; [.47A5.0020.0002] # ELBASAN LETTER SE +1051C ; [.47A6.0020.0002] # ELBASAN LETTER SHE +1051D ; [.47A7.0020.0002] # ELBASAN LETTER TE +1051E ; [.47A8.0020.0002] # ELBASAN LETTER THE +1051F ; [.47A9.0020.0002] # ELBASAN LETTER U +10520 ; [.47AA.0020.0002] # ELBASAN LETTER VE +10521 ; [.47AB.0020.0002] # ELBASAN LETTER XE +10522 ; [.47AC.0020.0002] # ELBASAN LETTER Y +10523 ; [.47AD.0020.0002] # ELBASAN LETTER ZE +10524 ; [.47AE.0020.0002] # ELBASAN LETTER ZHE +10525 ; [.47AF.0020.0002] # ELBASAN LETTER GHE +10526 ; [.47B0.0020.0002] # ELBASAN LETTER GHAMMA +10527 ; [.47B1.0020.0002] # ELBASAN LETTER KHE +10530 ; [.47B2.0020.0002] # CAUCASIAN ALBANIAN LETTER ALT +10531 ; [.47B3.0020.0002] # CAUCASIAN ALBANIAN LETTER BET +10532 ; [.47B4.0020.0002] # CAUCASIAN ALBANIAN LETTER GIM +10533 ; [.47B5.0020.0002] # CAUCASIAN ALBANIAN LETTER DAT +10534 ; [.47B6.0020.0002] # CAUCASIAN ALBANIAN LETTER EB +10535 ; [.47B7.0020.0002] # CAUCASIAN ALBANIAN LETTER ZARL +10536 ; [.47B8.0020.0002] # CAUCASIAN ALBANIAN LETTER EYN +10537 ; [.47B9.0020.0002] # CAUCASIAN ALBANIAN LETTER ZHIL +10538 ; [.47BA.0020.0002] # CAUCASIAN ALBANIAN LETTER TAS +10539 ; [.47BB.0020.0002] # CAUCASIAN ALBANIAN LETTER CHA +1053A ; [.47BC.0020.0002] # CAUCASIAN ALBANIAN LETTER YOWD +1053B ; [.47BD.0020.0002] # CAUCASIAN ALBANIAN LETTER ZHA +1053C ; [.47BE.0020.0002] # CAUCASIAN ALBANIAN LETTER IRB +1053D ; [.47BF.0020.0002] # CAUCASIAN ALBANIAN LETTER SHA +1053E ; [.47C0.0020.0002] # CAUCASIAN ALBANIAN LETTER LAN +1053F ; [.47C1.0020.0002] # CAUCASIAN ALBANIAN LETTER INYA +10540 ; [.47C2.0020.0002] # CAUCASIAN ALBANIAN LETTER XEYN +10541 ; [.47C3.0020.0002] # CAUCASIAN ALBANIAN LETTER DYAN +10542 ; [.47C4.0020.0002] # CAUCASIAN ALBANIAN LETTER CAR +10543 ; [.47C5.0020.0002] # CAUCASIAN ALBANIAN LETTER JHOX +10544 ; [.47C6.0020.0002] # CAUCASIAN ALBANIAN LETTER KAR +10545 ; [.47C7.0020.0002] # CAUCASIAN ALBANIAN LETTER LYIT +10546 ; [.47C8.0020.0002] # CAUCASIAN ALBANIAN LETTER HEYT +10547 ; [.47C9.0020.0002] # CAUCASIAN ALBANIAN LETTER QAY +10548 ; [.47CA.0020.0002] # CAUCASIAN ALBANIAN LETTER AOR +10549 ; [.47CB.0020.0002] # CAUCASIAN ALBANIAN LETTER CHOY +1054A ; [.47CC.0020.0002] # CAUCASIAN ALBANIAN LETTER CHI +1054B ; [.47CD.0020.0002] # CAUCASIAN ALBANIAN LETTER CYAY +1054C ; [.47CE.0020.0002] # CAUCASIAN ALBANIAN LETTER MAQ +1054D ; [.47CF.0020.0002] # CAUCASIAN ALBANIAN LETTER QAR +1054E ; [.47D0.0020.0002] # CAUCASIAN ALBANIAN LETTER NOWC +1054F ; [.47D1.0020.0002] # CAUCASIAN ALBANIAN LETTER DZYAY +10550 ; [.47D2.0020.0002] # CAUCASIAN ALBANIAN LETTER SHAK +10551 ; [.47D3.0020.0002] # CAUCASIAN ALBANIAN LETTER JAYN +10552 ; [.47D4.0020.0002] # CAUCASIAN ALBANIAN LETTER ON +10553 ; [.47D5.0020.0002] # CAUCASIAN ALBANIAN LETTER TYAY +10554 ; [.47D6.0020.0002] # CAUCASIAN ALBANIAN LETTER FAM +10555 ; [.47D7.0020.0002] # CAUCASIAN ALBANIAN LETTER DZAY +10556 ; [.47D8.0020.0002] # CAUCASIAN ALBANIAN LETTER CHAT +10557 ; [.47D9.0020.0002] # CAUCASIAN ALBANIAN LETTER PEN +10558 ; [.47DA.0020.0002] # CAUCASIAN ALBANIAN LETTER GHEYS +10559 ; [.47DB.0020.0002] # CAUCASIAN ALBANIAN LETTER RAT +1055A ; [.47DC.0020.0002] # CAUCASIAN ALBANIAN LETTER SEYK +1055B ; [.47DD.0020.0002] # CAUCASIAN ALBANIAN LETTER VEYZ +1055C ; [.47DE.0020.0002] # CAUCASIAN ALBANIAN LETTER TIWR +1055D ; [.47DF.0020.0002] # CAUCASIAN ALBANIAN LETTER SHOY +1055E ; [.47E0.0020.0002] # CAUCASIAN ALBANIAN LETTER IWN +1055F ; [.47E1.0020.0002] # CAUCASIAN ALBANIAN LETTER CYAW +10560 ; [.47E2.0020.0002] # CAUCASIAN ALBANIAN LETTER CAYN +10561 ; [.47E3.0020.0002] # CAUCASIAN ALBANIAN LETTER YAYD +10562 ; [.47E4.0020.0002] # CAUCASIAN ALBANIAN LETTER PIWR +10563 ; [.47E5.0020.0002] # CAUCASIAN ALBANIAN LETTER KIW +110D0 ; [.47E6.0020.0002] # SORA SOMPENG LETTER SAH +110D1 ; [.47E7.0020.0002] # SORA SOMPENG LETTER TAH +110D2 ; [.47E8.0020.0002] # SORA SOMPENG LETTER BAH +110D3 ; [.47E9.0020.0002] # SORA SOMPENG LETTER CAH +110D4 ; [.47EA.0020.0002] # SORA SOMPENG LETTER DAH +110D5 ; [.47EB.0020.0002] # SORA SOMPENG LETTER GAH +110D6 ; [.47EC.0020.0002] # SORA SOMPENG LETTER MAH +110D7 ; [.47ED.0020.0002] # SORA SOMPENG LETTER NGAH +110D8 ; [.47EE.0020.0002] # SORA SOMPENG LETTER LAH +110D9 ; [.47EF.0020.0002] # SORA SOMPENG LETTER NAH +110DA ; [.47F0.0020.0002] # SORA SOMPENG LETTER VAH +110DB ; [.47F1.0020.0002] # SORA SOMPENG LETTER PAH +110DC ; [.47F2.0020.0002] # SORA SOMPENG LETTER YAH +110DD ; [.47F3.0020.0002] # SORA SOMPENG LETTER RAH +110DE ; [.47F4.0020.0002] # SORA SOMPENG LETTER HAH +110DF ; [.47F5.0020.0002] # SORA SOMPENG LETTER KAH +110E0 ; [.47F6.0020.0002] # SORA SOMPENG LETTER JAH +110E1 ; [.47F7.0020.0002] # SORA SOMPENG LETTER NYAH +110E2 ; [.47F8.0020.0002] # SORA SOMPENG LETTER AH +110E3 ; [.47F9.0020.0002] # SORA SOMPENG LETTER EEH +110E4 ; [.47FA.0020.0002] # SORA SOMPENG LETTER IH +110E5 ; [.47FB.0020.0002] # SORA SOMPENG LETTER UH +110E6 ; [.47FC.0020.0002] # SORA SOMPENG LETTER OH +110E7 ; [.47FD.0020.0002] # SORA SOMPENG LETTER EH +110E8 ; [.47FE.0020.0002] # SORA SOMPENG LETTER MAE +16A40 ; [.47FF.0020.0002] # MRO LETTER TA +16A41 ; [.4800.0020.0002] # MRO LETTER NGI +16A42 ; [.4801.0020.0002] # MRO LETTER YO +16A43 ; [.4802.0020.0002] # MRO LETTER MIM +16A44 ; [.4803.0020.0002] # MRO LETTER BA +16A45 ; [.4804.0020.0002] # MRO LETTER DA +16A46 ; [.4805.0020.0002] # MRO LETTER A +16A47 ; [.4806.0020.0002] # MRO LETTER PHI +16A48 ; [.4807.0020.0002] # MRO LETTER KHAI +16A49 ; [.4808.0020.0002] # MRO LETTER HAO +16A4A ; [.4809.0020.0002] # MRO LETTER DAI +16A4B ; [.480A.0020.0002] # MRO LETTER CHU +16A4C ; [.480B.0020.0002] # MRO LETTER KEAAE +16A4D ; [.480C.0020.0002] # MRO LETTER OL +16A4E ; [.480D.0020.0002] # MRO LETTER MAEM +16A4F ; [.480E.0020.0002] # MRO LETTER NIN +16A50 ; [.480F.0020.0002] # MRO LETTER PA +16A51 ; [.4810.0020.0002] # MRO LETTER OO +16A52 ; [.4811.0020.0002] # MRO LETTER O +16A53 ; [.4812.0020.0002] # MRO LETTER RO +16A54 ; [.4813.0020.0002] # MRO LETTER SHI +16A55 ; [.4814.0020.0002] # MRO LETTER THEA +16A56 ; [.4815.0020.0002] # MRO LETTER EA +16A57 ; [.4816.0020.0002] # MRO LETTER WA +16A58 ; [.4817.0020.0002] # MRO LETTER E +16A59 ; [.4818.0020.0002] # MRO LETTER KO +16A5A ; [.4819.0020.0002] # MRO LETTER LAN +16A5B ; [.481A.0020.0002] # MRO LETTER LA +16A5C ; [.481B.0020.0002] # MRO LETTER HAI +16A5D ; [.481C.0020.0002] # MRO LETTER RI +16A5E ; [.481D.0020.0002] # MRO LETTER TEK +10000 ; [.481E.0020.0002] # LINEAR B SYLLABLE B008 A +10001 ; [.481F.0020.0002] # LINEAR B SYLLABLE B038 E +10002 ; [.4820.0020.0002] # LINEAR B SYLLABLE B028 I +10003 ; [.4821.0020.0002] # LINEAR B SYLLABLE B061 O +10004 ; [.4822.0020.0002] # LINEAR B SYLLABLE B010 U +10005 ; [.4823.0020.0002] # LINEAR B SYLLABLE B001 DA +10006 ; [.4824.0020.0002] # LINEAR B SYLLABLE B045 DE +10007 ; [.4825.0020.0002] # LINEAR B SYLLABLE B007 DI +10008 ; [.4826.0020.0002] # LINEAR B SYLLABLE B014 DO +10009 ; [.4827.0020.0002] # LINEAR B SYLLABLE B051 DU +1000A ; [.4828.0020.0002] # LINEAR B SYLLABLE B057 JA +1000B ; [.4829.0020.0002] # LINEAR B SYLLABLE B046 JE +1000D ; [.482A.0020.0002] # LINEAR B SYLLABLE B036 JO +1000E ; [.482B.0020.0002] # LINEAR B SYLLABLE B065 JU +1000F ; [.482C.0020.0002] # LINEAR B SYLLABLE B077 KA +10010 ; [.482D.0020.0002] # LINEAR B SYLLABLE B044 KE +10011 ; [.482E.0020.0002] # LINEAR B SYLLABLE B067 KI +10012 ; [.482F.0020.0002] # LINEAR B SYLLABLE B070 KO +10013 ; [.4830.0020.0002] # LINEAR B SYLLABLE B081 KU +10014 ; [.4831.0020.0002] # LINEAR B SYLLABLE B080 MA +10015 ; [.4832.0020.0002] # LINEAR B SYLLABLE B013 ME +10016 ; [.4833.0020.0002] # LINEAR B SYLLABLE B073 MI +10017 ; [.4834.0020.0002] # LINEAR B SYLLABLE B015 MO +10018 ; [.4835.0020.0002] # LINEAR B SYLLABLE B023 MU +10019 ; [.4836.0020.0002] # LINEAR B SYLLABLE B006 NA +1001A ; [.4837.0020.0002] # LINEAR B SYLLABLE B024 NE +1001B ; [.4838.0020.0002] # LINEAR B SYLLABLE B030 NI +1001C ; [.4839.0020.0002] # LINEAR B SYLLABLE B052 NO +1001D ; [.483A.0020.0002] # LINEAR B SYLLABLE B055 NU +1001E ; [.483B.0020.0002] # LINEAR B SYLLABLE B003 PA +1001F ; [.483C.0020.0002] # LINEAR B SYLLABLE B072 PE +10020 ; [.483D.0020.0002] # LINEAR B SYLLABLE B039 PI +10021 ; [.483E.0020.0002] # LINEAR B SYLLABLE B011 PO +10022 ; [.483F.0020.0002] # LINEAR B SYLLABLE B050 PU +10023 ; [.4840.0020.0002] # LINEAR B SYLLABLE B016 QA +10024 ; [.4841.0020.0002] # LINEAR B SYLLABLE B078 QE +10025 ; [.4842.0020.0002] # LINEAR B SYLLABLE B021 QI +10026 ; [.4843.0020.0002] # LINEAR B SYLLABLE B032 QO +10028 ; [.4844.0020.0002] # LINEAR B SYLLABLE B060 RA +10029 ; [.4845.0020.0002] # LINEAR B SYLLABLE B027 RE +1002A ; [.4846.0020.0002] # LINEAR B SYLLABLE B053 RI +1002B ; [.4847.0020.0002] # LINEAR B SYLLABLE B002 RO +1002C ; [.4848.0020.0002] # LINEAR B SYLLABLE B026 RU +1002D ; [.4849.0020.0002] # LINEAR B SYLLABLE B031 SA +1002E ; [.484A.0020.0002] # LINEAR B SYLLABLE B009 SE +1002F ; [.484B.0020.0002] # LINEAR B SYLLABLE B041 SI +10030 ; [.484C.0020.0002] # LINEAR B SYLLABLE B012 SO +10031 ; [.484D.0020.0002] # LINEAR B SYLLABLE B058 SU +10032 ; [.484E.0020.0002] # LINEAR B SYLLABLE B059 TA +10033 ; [.484F.0020.0002] # LINEAR B SYLLABLE B004 TE +10034 ; [.4850.0020.0002] # LINEAR B SYLLABLE B037 TI +10035 ; [.4851.0020.0002] # LINEAR B SYLLABLE B005 TO +10036 ; [.4852.0020.0002] # LINEAR B SYLLABLE B069 TU +10037 ; [.4853.0020.0002] # LINEAR B SYLLABLE B054 WA +10038 ; [.4854.0020.0002] # LINEAR B SYLLABLE B075 WE +10039 ; [.4855.0020.0002] # LINEAR B SYLLABLE B040 WI +1003A ; [.4856.0020.0002] # LINEAR B SYLLABLE B042 WO +1003C ; [.4857.0020.0002] # LINEAR B SYLLABLE B017 ZA +1003D ; [.4858.0020.0002] # LINEAR B SYLLABLE B074 ZE +1003F ; [.4859.0020.0002] # LINEAR B SYLLABLE B020 ZO +10040 ; [.485A.0020.0002] # LINEAR B SYLLABLE B025 A2 +10041 ; [.485B.0020.0002] # LINEAR B SYLLABLE B043 A3 +10042 ; [.485C.0020.0002] # LINEAR B SYLLABLE B085 AU +10043 ; [.485D.0020.0002] # LINEAR B SYLLABLE B071 DWE +10044 ; [.485E.0020.0002] # LINEAR B SYLLABLE B090 DWO +10045 ; [.485F.0020.0002] # LINEAR B SYLLABLE B048 NWA +10046 ; [.4860.0020.0002] # LINEAR B SYLLABLE B029 PU2 +10047 ; [.4861.0020.0002] # LINEAR B SYLLABLE B062 PTE +10048 ; [.4862.0020.0002] # LINEAR B SYLLABLE B076 RA2 +10049 ; [.4863.0020.0002] # LINEAR B SYLLABLE B033 RA3 +1004A ; [.4864.0020.0002] # LINEAR B SYLLABLE B068 RO2 +1004B ; [.4865.0020.0002] # LINEAR B SYLLABLE B066 TA2 +1004C ; [.4866.0020.0002] # LINEAR B SYLLABLE B087 TWE +1004D ; [.4867.0020.0002] # LINEAR B SYLLABLE B091 TWO +10050 ; [.4868.0020.0002] # LINEAR B SYMBOL B018 +10051 ; [.4869.0020.0002] # LINEAR B SYMBOL B019 +10052 ; [.486A.0020.0002] # LINEAR B SYMBOL B022 +10053 ; [.486B.0020.0002] # LINEAR B SYMBOL B034 +10054 ; [.486C.0020.0002] # LINEAR B SYMBOL B047 +10055 ; [.486D.0020.0002] # LINEAR B SYMBOL B049 +10056 ; [.486E.0020.0002] # LINEAR B SYMBOL B056 +10057 ; [.486F.0020.0002] # LINEAR B SYMBOL B063 +10058 ; [.4870.0020.0002] # LINEAR B SYMBOL B064 +10059 ; [.4871.0020.0002] # LINEAR B SYMBOL B079 +1005A ; [.4872.0020.0002] # LINEAR B SYMBOL B082 +1005B ; [.4873.0020.0002] # LINEAR B SYMBOL B083 +1005C ; [.4874.0020.0002] # LINEAR B SYMBOL B086 +1005D ; [.4875.0020.0002] # LINEAR B SYMBOL B089 +10080 ; [.4876.0020.0002] # LINEAR B IDEOGRAM B100 MAN +10081 ; [.4877.0020.0002] # LINEAR B IDEOGRAM B102 WOMAN +10082 ; [.4878.0020.0002] # LINEAR B IDEOGRAM B104 DEER +10083 ; [.4879.0020.0002] # LINEAR B IDEOGRAM B105 EQUID +10084 ; [.487A.0020.0002] # LINEAR B IDEOGRAM B105F MARE +10085 ; [.487B.0020.0002] # LINEAR B IDEOGRAM B105M STALLION +10086 ; [.487C.0020.0002] # LINEAR B IDEOGRAM B106F EWE +10087 ; [.487D.0020.0002] # LINEAR B IDEOGRAM B106M RAM +10088 ; [.487E.0020.0002] # LINEAR B IDEOGRAM B107F SHE-GOAT +10089 ; [.487F.0020.0002] # LINEAR B IDEOGRAM B107M HE-GOAT +1008A ; [.4880.0020.0002] # LINEAR B IDEOGRAM B108F SOW +1008B ; [.4881.0020.0002] # LINEAR B IDEOGRAM B108M BOAR +1008C ; [.4882.0020.0002] # LINEAR B IDEOGRAM B109F COW +1008D ; [.4883.0020.0002] # LINEAR B IDEOGRAM B109M BULL +1008E ; [.4884.0020.0002] # LINEAR B IDEOGRAM B120 WHEAT +1008F ; [.4885.0020.0002] # LINEAR B IDEOGRAM B121 BARLEY +10090 ; [.4886.0020.0002] # LINEAR B IDEOGRAM B122 OLIVE +10091 ; [.4887.0020.0002] # LINEAR B IDEOGRAM B123 SPICE +10092 ; [.4888.0020.0002] # LINEAR B IDEOGRAM B125 CYPERUS +10093 ; [.4889.0020.0002] # LINEAR B MONOGRAM B127 KAPO +10094 ; [.488A.0020.0002] # LINEAR B MONOGRAM B128 KANAKO +10095 ; [.488B.0020.0002] # LINEAR B IDEOGRAM B130 OIL +10096 ; [.488C.0020.0002] # LINEAR B IDEOGRAM B131 WINE +10097 ; [.488D.0020.0002] # LINEAR B IDEOGRAM B132 +10098 ; [.488E.0020.0002] # LINEAR B MONOGRAM B133 AREPA +10099 ; [.488F.0020.0002] # LINEAR B MONOGRAM B135 MERI +1009A ; [.4890.0020.0002] # LINEAR B IDEOGRAM B140 BRONZE +1009B ; [.4891.0020.0002] # LINEAR B IDEOGRAM B141 GOLD +1009C ; [.4892.0020.0002] # LINEAR B IDEOGRAM B142 +1009D ; [.4893.0020.0002] # LINEAR B IDEOGRAM B145 WOOL +1009E ; [.4894.0020.0002] # LINEAR B IDEOGRAM B146 +1009F ; [.4895.0020.0002] # LINEAR B IDEOGRAM B150 +100A0 ; [.4896.0020.0002] # LINEAR B IDEOGRAM B151 HORN +100A1 ; [.4897.0020.0002] # LINEAR B IDEOGRAM B152 +100A2 ; [.4898.0020.0002] # LINEAR B IDEOGRAM B153 +100A3 ; [.4899.0020.0002] # LINEAR B IDEOGRAM B154 +100A4 ; [.489A.0020.0002] # LINEAR B MONOGRAM B156 TURO2 +100A5 ; [.489B.0020.0002] # LINEAR B IDEOGRAM B157 +100A6 ; [.489C.0020.0002] # LINEAR B IDEOGRAM B158 +100A7 ; [.489D.0020.0002] # LINEAR B IDEOGRAM B159 CLOTH +100A8 ; [.489E.0020.0002] # LINEAR B IDEOGRAM B160 +100A9 ; [.489F.0020.0002] # LINEAR B IDEOGRAM B161 +100AA ; [.48A0.0020.0002] # LINEAR B IDEOGRAM B162 GARMENT +100AB ; [.48A1.0020.0002] # LINEAR B IDEOGRAM B163 ARMOUR +100AC ; [.48A2.0020.0002] # LINEAR B IDEOGRAM B164 +100AD ; [.48A3.0020.0002] # LINEAR B IDEOGRAM B165 +100AE ; [.48A4.0020.0002] # LINEAR B IDEOGRAM B166 +100AF ; [.48A5.0020.0002] # LINEAR B IDEOGRAM B167 +100B0 ; [.48A6.0020.0002] # LINEAR B IDEOGRAM B168 +100B1 ; [.48A7.0020.0002] # LINEAR B IDEOGRAM B169 +100B2 ; [.48A8.0020.0002] # LINEAR B IDEOGRAM B170 +100B3 ; [.48A9.0020.0002] # LINEAR B IDEOGRAM B171 +100B4 ; [.48AA.0020.0002] # LINEAR B IDEOGRAM B172 +100B5 ; [.48AB.0020.0002] # LINEAR B IDEOGRAM B173 MONTH +100B6 ; [.48AC.0020.0002] # LINEAR B IDEOGRAM B174 +100B7 ; [.48AD.0020.0002] # LINEAR B IDEOGRAM B176 TREE +100B8 ; [.48AE.0020.0002] # LINEAR B IDEOGRAM B177 +100B9 ; [.48AF.0020.0002] # LINEAR B IDEOGRAM B178 +100BA ; [.48B0.0020.0002] # LINEAR B IDEOGRAM B179 +100BB ; [.48B1.0020.0002] # LINEAR B IDEOGRAM B180 +100BC ; [.48B2.0020.0002] # LINEAR B IDEOGRAM B181 +100BD ; [.48B3.0020.0002] # LINEAR B IDEOGRAM B182 +100BE ; [.48B4.0020.0002] # LINEAR B IDEOGRAM B183 +100BF ; [.48B5.0020.0002] # LINEAR B IDEOGRAM B184 +100C0 ; [.48B6.0020.0002] # LINEAR B IDEOGRAM B185 +100C1 ; [.48B7.0020.0002] # LINEAR B IDEOGRAM B189 +100C2 ; [.48B8.0020.0002] # LINEAR B IDEOGRAM B190 +100C3 ; [.48B9.0020.0002] # LINEAR B IDEOGRAM B191 HELMET +100C4 ; [.48BA.0020.0002] # LINEAR B IDEOGRAM B220 FOOTSTOOL +100C5 ; [.48BB.0020.0002] # LINEAR B IDEOGRAM B225 BATHTUB +100C6 ; [.48BC.0020.0002] # LINEAR B IDEOGRAM B230 SPEAR +100C7 ; [.48BD.0020.0002] # LINEAR B IDEOGRAM B231 ARROW +100C8 ; [.48BE.0020.0002] # LINEAR B IDEOGRAM B232 +100C9 ; [.48BF.0020.0002] # LINEAR B IDEOGRAM B233 SWORD +100CA ; [.48C0.0020.0002] # LINEAR B IDEOGRAM B234 +100CB ; [.48C1.0020.0002] # LINEAR B IDEOGRAM B236 +100CC ; [.48C2.0020.0002] # LINEAR B IDEOGRAM B240 WHEELED CHARIOT +100CD ; [.48C3.0020.0002] # LINEAR B IDEOGRAM B241 CHARIOT +100CE ; [.48C4.0020.0002] # LINEAR B IDEOGRAM B242 CHARIOT FRAME +100CF ; [.48C5.0020.0002] # LINEAR B IDEOGRAM B243 WHEEL +100D0 ; [.48C6.0020.0002] # LINEAR B IDEOGRAM B245 +100D1 ; [.48C7.0020.0002] # LINEAR B IDEOGRAM B246 +100D2 ; [.48C8.0020.0002] # LINEAR B MONOGRAM B247 DIPTE +100D3 ; [.48C9.0020.0002] # LINEAR B IDEOGRAM B248 +100D4 ; [.48CA.0020.0002] # LINEAR B IDEOGRAM B249 +100D5 ; [.48CB.0020.0002] # LINEAR B IDEOGRAM B251 +100D6 ; [.48CC.0020.0002] # LINEAR B IDEOGRAM B252 +100D7 ; [.48CD.0020.0002] # LINEAR B IDEOGRAM B253 +100D8 ; [.48CE.0020.0002] # LINEAR B IDEOGRAM B254 DART +100D9 ; [.48CF.0020.0002] # LINEAR B IDEOGRAM B255 +100DA ; [.48D0.0020.0002] # LINEAR B IDEOGRAM B256 +100DB ; [.48D1.0020.0002] # LINEAR B IDEOGRAM B257 +100DC ; [.48D2.0020.0002] # LINEAR B IDEOGRAM B258 +100DD ; [.48D3.0020.0002] # LINEAR B IDEOGRAM B259 +100DE ; [.48D4.0020.0002] # LINEAR B IDEOGRAM VESSEL B155 +100DF ; [.48D5.0020.0002] # LINEAR B IDEOGRAM VESSEL B200 +100E0 ; [.48D6.0020.0002] # LINEAR B IDEOGRAM VESSEL B201 +100E1 ; [.48D7.0020.0002] # LINEAR B IDEOGRAM VESSEL B202 +100E2 ; [.48D8.0020.0002] # LINEAR B IDEOGRAM VESSEL B203 +100E3 ; [.48D9.0020.0002] # LINEAR B IDEOGRAM VESSEL B204 +100E4 ; [.48DA.0020.0002] # LINEAR B IDEOGRAM VESSEL B205 +100E5 ; [.48DB.0020.0002] # LINEAR B IDEOGRAM VESSEL B206 +100E6 ; [.48DC.0020.0002] # LINEAR B IDEOGRAM VESSEL B207 +100E7 ; [.48DD.0020.0002] # LINEAR B IDEOGRAM VESSEL B208 +100E8 ; [.48DE.0020.0002] # LINEAR B IDEOGRAM VESSEL B209 +100E9 ; [.48DF.0020.0002] # LINEAR B IDEOGRAM VESSEL B210 +100EA ; [.48E0.0020.0002] # LINEAR B IDEOGRAM VESSEL B211 +100EB ; [.48E1.0020.0002] # LINEAR B IDEOGRAM VESSEL B212 +100EC ; [.48E2.0020.0002] # LINEAR B IDEOGRAM VESSEL B213 +100ED ; [.48E3.0020.0002] # LINEAR B IDEOGRAM VESSEL B214 +100EE ; [.48E4.0020.0002] # LINEAR B IDEOGRAM VESSEL B215 +100EF ; [.48E5.0020.0002] # LINEAR B IDEOGRAM VESSEL B216 +100F0 ; [.48E6.0020.0002] # LINEAR B IDEOGRAM VESSEL B217 +100F1 ; [.48E7.0020.0002] # LINEAR B IDEOGRAM VESSEL B218 +100F2 ; [.48E8.0020.0002] # LINEAR B IDEOGRAM VESSEL B219 +100F3 ; [.48E9.0020.0002] # LINEAR B IDEOGRAM VESSEL B221 +100F4 ; [.48EA.0020.0002] # LINEAR B IDEOGRAM VESSEL B222 +100F5 ; [.48EB.0020.0002] # LINEAR B IDEOGRAM VESSEL B226 +100F6 ; [.48EC.0020.0002] # LINEAR B IDEOGRAM VESSEL B227 +100F7 ; [.48ED.0020.0002] # LINEAR B IDEOGRAM VESSEL B228 +100F8 ; [.48EE.0020.0002] # LINEAR B IDEOGRAM VESSEL B229 +100F9 ; [.48EF.0020.0002] # LINEAR B IDEOGRAM VESSEL B250 +100FA ; [.48F0.0020.0002] # LINEAR B IDEOGRAM VESSEL B305 +10600 ; [.48F1.0020.0002] # LINEAR A SIGN AB001 +10601 ; [.48F2.0020.0002] # LINEAR A SIGN AB002 +10602 ; [.48F3.0020.0002] # LINEAR A SIGN AB003 +10603 ; [.48F4.0020.0002] # LINEAR A SIGN AB004 +10604 ; [.48F5.0020.0002] # LINEAR A SIGN AB005 +10605 ; [.48F6.0020.0002] # LINEAR A SIGN AB006 +10606 ; [.48F7.0020.0002] # LINEAR A SIGN AB007 +10607 ; [.48F8.0020.0002] # LINEAR A SIGN AB008 +10608 ; [.48F9.0020.0002] # LINEAR A SIGN AB009 +10609 ; [.48FA.0020.0002] # LINEAR A SIGN AB010 +1060A ; [.48FB.0020.0002] # LINEAR A SIGN AB011 +1060B ; [.48FC.0020.0002] # LINEAR A SIGN AB013 +1060C ; [.48FD.0020.0002] # LINEAR A SIGN AB016 +1060D ; [.48FE.0020.0002] # LINEAR A SIGN AB017 +1060E ; [.48FF.0020.0002] # LINEAR A SIGN AB020 +1060F ; [.4900.0020.0002] # LINEAR A SIGN AB021 +10610 ; [.4901.0020.0002] # LINEAR A SIGN AB021F +10611 ; [.4902.0020.0002] # LINEAR A SIGN AB021M +10612 ; [.4903.0020.0002] # LINEAR A SIGN AB022 +10613 ; [.4904.0020.0002] # LINEAR A SIGN AB022F +10614 ; [.4905.0020.0002] # LINEAR A SIGN AB022M +10615 ; [.4906.0020.0002] # LINEAR A SIGN AB023 +10616 ; [.4907.0020.0002] # LINEAR A SIGN AB023M +10617 ; [.4908.0020.0002] # LINEAR A SIGN AB024 +10618 ; [.4909.0020.0002] # LINEAR A SIGN AB026 +10619 ; [.490A.0020.0002] # LINEAR A SIGN AB027 +1061A ; [.490B.0020.0002] # LINEAR A SIGN AB028 +1061B ; [.490C.0020.0002] # LINEAR A SIGN A028B +1061C ; [.490D.0020.0002] # LINEAR A SIGN AB029 +1061D ; [.490E.0020.0002] # LINEAR A SIGN AB030 +1061E ; [.490F.0020.0002] # LINEAR A SIGN AB031 +1061F ; [.4910.0020.0002] # LINEAR A SIGN AB034 +10620 ; [.4911.0020.0002] # LINEAR A SIGN AB037 +10621 ; [.4912.0020.0002] # LINEAR A SIGN AB038 +10622 ; [.4913.0020.0002] # LINEAR A SIGN AB039 +10623 ; [.4914.0020.0002] # LINEAR A SIGN AB040 +10624 ; [.4915.0020.0002] # LINEAR A SIGN AB041 +10625 ; [.4916.0020.0002] # LINEAR A SIGN AB044 +10626 ; [.4917.0020.0002] # LINEAR A SIGN AB045 +10627 ; [.4918.0020.0002] # LINEAR A SIGN AB046 +10628 ; [.4919.0020.0002] # LINEAR A SIGN AB047 +10629 ; [.491A.0020.0002] # LINEAR A SIGN AB048 +1062A ; [.491B.0020.0002] # LINEAR A SIGN AB049 +1062B ; [.491C.0020.0002] # LINEAR A SIGN AB050 +1062C ; [.491D.0020.0002] # LINEAR A SIGN AB051 +1062D ; [.491E.0020.0002] # LINEAR A SIGN AB053 +1062E ; [.491F.0020.0002] # LINEAR A SIGN AB054 +1062F ; [.4920.0020.0002] # LINEAR A SIGN AB055 +10630 ; [.4921.0020.0002] # LINEAR A SIGN AB056 +10631 ; [.4922.0020.0002] # LINEAR A SIGN AB057 +10632 ; [.4923.0020.0002] # LINEAR A SIGN AB058 +10633 ; [.4924.0020.0002] # LINEAR A SIGN AB059 +10634 ; [.4925.0020.0002] # LINEAR A SIGN AB060 +10635 ; [.4926.0020.0002] # LINEAR A SIGN AB061 +10636 ; [.4927.0020.0002] # LINEAR A SIGN AB065 +10637 ; [.4928.0020.0002] # LINEAR A SIGN AB066 +10638 ; [.4929.0020.0002] # LINEAR A SIGN AB067 +10639 ; [.492A.0020.0002] # LINEAR A SIGN AB069 +1063A ; [.492B.0020.0002] # LINEAR A SIGN AB070 +1063B ; [.492C.0020.0002] # LINEAR A SIGN AB073 +1063C ; [.492D.0020.0002] # LINEAR A SIGN AB074 +1063D ; [.492E.0020.0002] # LINEAR A SIGN AB076 +1063E ; [.492F.0020.0002] # LINEAR A SIGN AB077 +1063F ; [.4930.0020.0002] # LINEAR A SIGN AB078 +10640 ; [.4931.0020.0002] # LINEAR A SIGN AB079 +10641 ; [.4932.0020.0002] # LINEAR A SIGN AB080 +10642 ; [.4933.0020.0002] # LINEAR A SIGN AB081 +10643 ; [.4934.0020.0002] # LINEAR A SIGN AB082 +10644 ; [.4935.0020.0002] # LINEAR A SIGN AB085 +10645 ; [.4936.0020.0002] # LINEAR A SIGN AB086 +10646 ; [.4937.0020.0002] # LINEAR A SIGN AB087 +10647 ; [.4938.0020.0002] # LINEAR A SIGN A100-102 +10648 ; [.4939.0020.0002] # LINEAR A SIGN AB118 +10649 ; [.493A.0020.0002] # LINEAR A SIGN AB120 +1064A ; [.493B.0020.0002] # LINEAR A SIGN A120B +1064B ; [.493C.0020.0002] # LINEAR A SIGN AB122 +1064C ; [.493D.0020.0002] # LINEAR A SIGN AB123 +1064D ; [.493E.0020.0002] # LINEAR A SIGN AB131A +1064E ; [.493F.0020.0002] # LINEAR A SIGN AB131B +1064F ; [.4940.0020.0002] # LINEAR A SIGN A131C +10650 ; [.4941.0020.0002] # LINEAR A SIGN AB164 +10651 ; [.4942.0020.0002] # LINEAR A SIGN AB171 +10652 ; [.4943.0020.0002] # LINEAR A SIGN AB180 +10653 ; [.4944.0020.0002] # LINEAR A SIGN AB188 +10654 ; [.4945.0020.0002] # LINEAR A SIGN AB191 +10655 ; [.4946.0020.0002] # LINEAR A SIGN A301 +10656 ; [.4947.0020.0002] # LINEAR A SIGN A302 +10657 ; [.4948.0020.0002] # LINEAR A SIGN A303 +10658 ; [.4949.0020.0002] # LINEAR A SIGN A304 +10659 ; [.494A.0020.0002] # LINEAR A SIGN A305 +1065A ; [.494B.0020.0002] # LINEAR A SIGN A306 +1065B ; [.494C.0020.0002] # LINEAR A SIGN A307 +1065C ; [.494D.0020.0002] # LINEAR A SIGN A308 +1065D ; [.494E.0020.0002] # LINEAR A SIGN A309A +1065E ; [.494F.0020.0002] # LINEAR A SIGN A309B +1065F ; [.4950.0020.0002] # LINEAR A SIGN A309C +10660 ; [.4951.0020.0002] # LINEAR A SIGN A310 +10661 ; [.4952.0020.0002] # LINEAR A SIGN A311 +10662 ; [.4953.0020.0002] # LINEAR A SIGN A312 +10663 ; [.4954.0020.0002] # LINEAR A SIGN A313A +10664 ; [.4955.0020.0002] # LINEAR A SIGN A313B +10665 ; [.4956.0020.0002] # LINEAR A SIGN A313C +10666 ; [.4957.0020.0002] # LINEAR A SIGN A314 +10667 ; [.4958.0020.0002] # LINEAR A SIGN A315 +10668 ; [.4959.0020.0002] # LINEAR A SIGN A316 +10669 ; [.495A.0020.0002] # LINEAR A SIGN A317 +1066A ; [.495B.0020.0002] # LINEAR A SIGN A318 +1066B ; [.495C.0020.0002] # LINEAR A SIGN A319 +1066C ; [.495D.0020.0002] # LINEAR A SIGN A320 +1066D ; [.495E.0020.0002] # LINEAR A SIGN A321 +1066E ; [.495F.0020.0002] # LINEAR A SIGN A322 +1066F ; [.4960.0020.0002] # LINEAR A SIGN A323 +10670 ; [.4961.0020.0002] # LINEAR A SIGN A324 +10671 ; [.4962.0020.0002] # LINEAR A SIGN A325 +10672 ; [.4963.0020.0002] # LINEAR A SIGN A326 +10673 ; [.4964.0020.0002] # LINEAR A SIGN A327 +10674 ; [.4965.0020.0002] # LINEAR A SIGN A328 +10675 ; [.4966.0020.0002] # LINEAR A SIGN A329 +10676 ; [.4967.0020.0002] # LINEAR A SIGN A330 +10677 ; [.4968.0020.0002] # LINEAR A SIGN A331 +10678 ; [.4969.0020.0002] # LINEAR A SIGN A332 +10679 ; [.496A.0020.0002] # LINEAR A SIGN A333 +1067A ; [.496B.0020.0002] # LINEAR A SIGN A334 +1067B ; [.496C.0020.0002] # LINEAR A SIGN A335 +1067C ; [.496D.0020.0002] # LINEAR A SIGN A336 +1067D ; [.496E.0020.0002] # LINEAR A SIGN A337 +1067E ; [.496F.0020.0002] # LINEAR A SIGN A338 +1067F ; [.4970.0020.0002] # LINEAR A SIGN A339 +10680 ; [.4971.0020.0002] # LINEAR A SIGN A340 +10681 ; [.4972.0020.0002] # LINEAR A SIGN A341 +10682 ; [.4973.0020.0002] # LINEAR A SIGN A342 +10683 ; [.4974.0020.0002] # LINEAR A SIGN A343 +10684 ; [.4975.0020.0002] # LINEAR A SIGN A344 +10685 ; [.4976.0020.0002] # LINEAR A SIGN A345 +10686 ; [.4977.0020.0002] # LINEAR A SIGN A346 +10687 ; [.4978.0020.0002] # LINEAR A SIGN A347 +10688 ; [.4979.0020.0002] # LINEAR A SIGN A348 +10689 ; [.497A.0020.0002] # LINEAR A SIGN A349 +1068A ; [.497B.0020.0002] # LINEAR A SIGN A350 +1068B ; [.497C.0020.0002] # LINEAR A SIGN A351 +1068C ; [.497D.0020.0002] # LINEAR A SIGN A352 +1068D ; [.497E.0020.0002] # LINEAR A SIGN A353 +1068E ; [.497F.0020.0002] # LINEAR A SIGN A354 +1068F ; [.4980.0020.0002] # LINEAR A SIGN A355 +10690 ; [.4981.0020.0002] # LINEAR A SIGN A356 +10691 ; [.4982.0020.0002] # LINEAR A SIGN A357 +10692 ; [.4983.0020.0002] # LINEAR A SIGN A358 +10693 ; [.4984.0020.0002] # LINEAR A SIGN A359 +10694 ; [.4985.0020.0002] # LINEAR A SIGN A360 +10695 ; [.4986.0020.0002] # LINEAR A SIGN A361 +10696 ; [.4987.0020.0002] # LINEAR A SIGN A362 +10697 ; [.4988.0020.0002] # LINEAR A SIGN A363 +10698 ; [.4989.0020.0002] # LINEAR A SIGN A364 +10699 ; [.498A.0020.0002] # LINEAR A SIGN A365 +1069A ; [.498B.0020.0002] # LINEAR A SIGN A366 +1069B ; [.498C.0020.0002] # LINEAR A SIGN A367 +1069C ; [.498D.0020.0002] # LINEAR A SIGN A368 +1069D ; [.498E.0020.0002] # LINEAR A SIGN A369 +1069E ; [.498F.0020.0002] # LINEAR A SIGN A370 +1069F ; [.4990.0020.0002] # LINEAR A SIGN A371 +106A0 ; [.4991.0020.0002] # LINEAR A SIGN A400-VAS +106A1 ; [.4992.0020.0002] # LINEAR A SIGN A401-VAS +106A2 ; [.4993.0020.0002] # LINEAR A SIGN A402-VAS +106A3 ; [.4994.0020.0002] # LINEAR A SIGN A403-VAS +106A4 ; [.4995.0020.0002] # LINEAR A SIGN A404-VAS +106A5 ; [.4996.0020.0002] # LINEAR A SIGN A405-VAS +106A6 ; [.4997.0020.0002] # LINEAR A SIGN A406-VAS +106A7 ; [.4998.0020.0002] # LINEAR A SIGN A407-VAS +106A8 ; [.4999.0020.0002] # LINEAR A SIGN A408-VAS +106A9 ; [.499A.0020.0002] # LINEAR A SIGN A409-VAS +106AA ; [.499B.0020.0002] # LINEAR A SIGN A410-VAS +106AB ; [.499C.0020.0002] # LINEAR A SIGN A411-VAS +106AC ; [.499D.0020.0002] # LINEAR A SIGN A412-VAS +106AD ; [.499E.0020.0002] # LINEAR A SIGN A413-VAS +106AE ; [.499F.0020.0002] # LINEAR A SIGN A414-VAS +106AF ; [.49A0.0020.0002] # LINEAR A SIGN A415-VAS +106B0 ; [.49A1.0020.0002] # LINEAR A SIGN A416-VAS +106B1 ; [.49A2.0020.0002] # LINEAR A SIGN A417-VAS +106B2 ; [.49A3.0020.0002] # LINEAR A SIGN A418-VAS +106B3 ; [.49A4.0020.0002] # LINEAR A SIGN A501 +106B4 ; [.49A5.0020.0002] # LINEAR A SIGN A502 +106B5 ; [.49A6.0020.0002] # LINEAR A SIGN A503 +106B6 ; [.49A7.0020.0002] # LINEAR A SIGN A504 +106B7 ; [.49A8.0020.0002] # LINEAR A SIGN A505 +106B8 ; [.49A9.0020.0002] # LINEAR A SIGN A506 +106B9 ; [.49AA.0020.0002] # LINEAR A SIGN A508 +106BA ; [.49AB.0020.0002] # LINEAR A SIGN A509 +106BB ; [.49AC.0020.0002] # LINEAR A SIGN A510 +106BC ; [.49AD.0020.0002] # LINEAR A SIGN A511 +106BD ; [.49AE.0020.0002] # LINEAR A SIGN A512 +106BE ; [.49AF.0020.0002] # LINEAR A SIGN A513 +106BF ; [.49B0.0020.0002] # LINEAR A SIGN A515 +106C0 ; [.49B1.0020.0002] # LINEAR A SIGN A516 +106C1 ; [.49B2.0020.0002] # LINEAR A SIGN A520 +106C2 ; [.49B3.0020.0002] # LINEAR A SIGN A521 +106C3 ; [.49B4.0020.0002] # LINEAR A SIGN A523 +106C4 ; [.49B5.0020.0002] # LINEAR A SIGN A524 +106C5 ; [.49B6.0020.0002] # LINEAR A SIGN A525 +106C6 ; [.49B7.0020.0002] # LINEAR A SIGN A526 +106C7 ; [.49B8.0020.0002] # LINEAR A SIGN A527 +106C8 ; [.49B9.0020.0002] # LINEAR A SIGN A528 +106C9 ; [.49BA.0020.0002] # LINEAR A SIGN A529 +106CA ; [.49BB.0020.0002] # LINEAR A SIGN A530 +106CB ; [.49BC.0020.0002] # LINEAR A SIGN A531 +106CC ; [.49BD.0020.0002] # LINEAR A SIGN A532 +106CD ; [.49BE.0020.0002] # LINEAR A SIGN A534 +106CE ; [.49BF.0020.0002] # LINEAR A SIGN A535 +106CF ; [.49C0.0020.0002] # LINEAR A SIGN A536 +106D0 ; [.49C1.0020.0002] # LINEAR A SIGN A537 +106D1 ; [.49C2.0020.0002] # LINEAR A SIGN A538 +106D2 ; [.49C3.0020.0002] # LINEAR A SIGN A539 +106D3 ; [.49C4.0020.0002] # LINEAR A SIGN A540 +106D4 ; [.49C5.0020.0002] # LINEAR A SIGN A541 +106D5 ; [.49C6.0020.0002] # LINEAR A SIGN A542 +106D6 ; [.49C7.0020.0002] # LINEAR A SIGN A545 +106D7 ; [.49C8.0020.0002] # LINEAR A SIGN A547 +106D8 ; [.49C9.0020.0002] # LINEAR A SIGN A548 +106D9 ; [.49CA.0020.0002] # LINEAR A SIGN A549 +106DA ; [.49CB.0020.0002] # LINEAR A SIGN A550 +106DB ; [.49CC.0020.0002] # LINEAR A SIGN A551 +106DC ; [.49CD.0020.0002] # LINEAR A SIGN A552 +106DD ; [.49CE.0020.0002] # LINEAR A SIGN A553 +106DE ; [.49CF.0020.0002] # LINEAR A SIGN A554 +106DF ; [.49D0.0020.0002] # LINEAR A SIGN A555 +106E0 ; [.49D1.0020.0002] # LINEAR A SIGN A556 +106E1 ; [.49D2.0020.0002] # LINEAR A SIGN A557 +106E2 ; [.49D3.0020.0002] # LINEAR A SIGN A559 +106E3 ; [.49D4.0020.0002] # LINEAR A SIGN A563 +106E4 ; [.49D5.0020.0002] # LINEAR A SIGN A564 +106E5 ; [.49D6.0020.0002] # LINEAR A SIGN A565 +106E6 ; [.49D7.0020.0002] # LINEAR A SIGN A566 +106E7 ; [.49D8.0020.0002] # LINEAR A SIGN A568 +106E8 ; [.49D9.0020.0002] # LINEAR A SIGN A569 +106E9 ; [.49DA.0020.0002] # LINEAR A SIGN A570 +106EA ; [.49DB.0020.0002] # LINEAR A SIGN A571 +106EB ; [.49DC.0020.0002] # LINEAR A SIGN A572 +106EC ; [.49DD.0020.0002] # LINEAR A SIGN A573 +106ED ; [.49DE.0020.0002] # LINEAR A SIGN A574 +106EE ; [.49DF.0020.0002] # LINEAR A SIGN A575 +106EF ; [.49E0.0020.0002] # LINEAR A SIGN A576 +106F0 ; [.49E1.0020.0002] # LINEAR A SIGN A577 +106F1 ; [.49E2.0020.0002] # LINEAR A SIGN A578 +106F2 ; [.49E3.0020.0002] # LINEAR A SIGN A579 +106F3 ; [.49E4.0020.0002] # LINEAR A SIGN A580 +106F4 ; [.49E5.0020.0002] # LINEAR A SIGN A581 +106F5 ; [.49E6.0020.0002] # LINEAR A SIGN A582 +106F6 ; [.49E7.0020.0002] # LINEAR A SIGN A583 +106F7 ; [.49E8.0020.0002] # LINEAR A SIGN A584 +106F8 ; [.49E9.0020.0002] # LINEAR A SIGN A585 +106F9 ; [.49EA.0020.0002] # LINEAR A SIGN A586 +106FA ; [.49EB.0020.0002] # LINEAR A SIGN A587 +106FB ; [.49EC.0020.0002] # LINEAR A SIGN A588 +106FC ; [.49ED.0020.0002] # LINEAR A SIGN A589 +106FD ; [.49EE.0020.0002] # LINEAR A SIGN A591 +106FE ; [.49EF.0020.0002] # LINEAR A SIGN A592 +106FF ; [.49F0.0020.0002] # LINEAR A SIGN A594 +10700 ; [.49F1.0020.0002] # LINEAR A SIGN A595 +10701 ; [.49F2.0020.0002] # LINEAR A SIGN A596 +10702 ; [.49F3.0020.0002] # LINEAR A SIGN A598 +10703 ; [.49F4.0020.0002] # LINEAR A SIGN A600 +10704 ; [.49F5.0020.0002] # LINEAR A SIGN A601 +10705 ; [.49F6.0020.0002] # LINEAR A SIGN A602 +10706 ; [.49F7.0020.0002] # LINEAR A SIGN A603 +10707 ; [.49F8.0020.0002] # LINEAR A SIGN A604 +10708 ; [.49F9.0020.0002] # LINEAR A SIGN A606 +10709 ; [.49FA.0020.0002] # LINEAR A SIGN A608 +1070A ; [.49FB.0020.0002] # LINEAR A SIGN A609 +1070B ; [.49FC.0020.0002] # LINEAR A SIGN A610 +1070C ; [.49FD.0020.0002] # LINEAR A SIGN A611 +1070D ; [.49FE.0020.0002] # LINEAR A SIGN A612 +1070E ; [.49FF.0020.0002] # LINEAR A SIGN A613 +1070F ; [.4A00.0020.0002] # LINEAR A SIGN A614 +10710 ; [.4A01.0020.0002] # LINEAR A SIGN A615 +10711 ; [.4A02.0020.0002] # LINEAR A SIGN A616 +10712 ; [.4A03.0020.0002] # LINEAR A SIGN A617 +10713 ; [.4A04.0020.0002] # LINEAR A SIGN A618 +10714 ; [.4A05.0020.0002] # LINEAR A SIGN A619 +10715 ; [.4A06.0020.0002] # LINEAR A SIGN A620 +10716 ; [.4A07.0020.0002] # LINEAR A SIGN A621 +10717 ; [.4A08.0020.0002] # LINEAR A SIGN A622 +10718 ; [.4A09.0020.0002] # LINEAR A SIGN A623 +10719 ; [.4A0A.0020.0002] # LINEAR A SIGN A624 +1071A ; [.4A0B.0020.0002] # LINEAR A SIGN A626 +1071B ; [.4A0C.0020.0002] # LINEAR A SIGN A627 +1071C ; [.4A0D.0020.0002] # LINEAR A SIGN A628 +1071D ; [.4A0E.0020.0002] # LINEAR A SIGN A629 +1071E ; [.4A0F.0020.0002] # LINEAR A SIGN A634 +1071F ; [.4A10.0020.0002] # LINEAR A SIGN A637 +10720 ; [.4A11.0020.0002] # LINEAR A SIGN A638 +10721 ; [.4A12.0020.0002] # LINEAR A SIGN A640 +10722 ; [.4A13.0020.0002] # LINEAR A SIGN A642 +10723 ; [.4A14.0020.0002] # LINEAR A SIGN A643 +10724 ; [.4A15.0020.0002] # LINEAR A SIGN A644 +10725 ; [.4A16.0020.0002] # LINEAR A SIGN A645 +10726 ; [.4A17.0020.0002] # LINEAR A SIGN A646 +10727 ; [.4A18.0020.0002] # LINEAR A SIGN A648 +10728 ; [.4A19.0020.0002] # LINEAR A SIGN A649 +10729 ; [.4A1A.0020.0002] # LINEAR A SIGN A651 +1072A ; [.4A1B.0020.0002] # LINEAR A SIGN A652 +1072B ; [.4A1C.0020.0002] # LINEAR A SIGN A653 +1072C ; [.4A1D.0020.0002] # LINEAR A SIGN A654 +1072D ; [.4A1E.0020.0002] # LINEAR A SIGN A655 +1072E ; [.4A1F.0020.0002] # LINEAR A SIGN A656 +1072F ; [.4A20.0020.0002] # LINEAR A SIGN A657 +10730 ; [.4A21.0020.0002] # LINEAR A SIGN A658 +10731 ; [.4A22.0020.0002] # LINEAR A SIGN A659 +10732 ; [.4A23.0020.0002] # LINEAR A SIGN A660 +10733 ; [.4A24.0020.0002] # LINEAR A SIGN A661 +10734 ; [.4A25.0020.0002] # LINEAR A SIGN A662 +10735 ; [.4A26.0020.0002] # LINEAR A SIGN A663 +10736 ; [.4A27.0020.0002] # LINEAR A SIGN A664 +10740 ; [.4A28.0020.0002] # LINEAR A SIGN A701 A +10741 ; [.4A29.0020.0002] # LINEAR A SIGN A702 B +10742 ; [.4A2A.0020.0002] # LINEAR A SIGN A703 D +10743 ; [.4A2B.0020.0002] # LINEAR A SIGN A704 E +10744 ; [.4A2C.0020.0002] # LINEAR A SIGN A705 F +10745 ; [.4A2D.0020.0002] # LINEAR A SIGN A706 H +10746 ; [.4A2E.0020.0002] # LINEAR A SIGN A707 J +10747 ; [.4A2F.0020.0002] # LINEAR A SIGN A708 K +10748 ; [.4A30.0020.0002] # LINEAR A SIGN A709 L +10749 ; [.4A31.0020.0002] # LINEAR A SIGN A709-2 L2 +1074A ; [.4A32.0020.0002] # LINEAR A SIGN A709-3 L3 +1074B ; [.4A33.0020.0002] # LINEAR A SIGN A709-4 L4 +1074C ; [.4A34.0020.0002] # LINEAR A SIGN A709-6 L6 +1074D ; [.4A35.0020.0002] # LINEAR A SIGN A710 W +1074E ; [.4A36.0020.0002] # LINEAR A SIGN A711 X +1074F ; [.4A37.0020.0002] # LINEAR A SIGN A712 Y +10750 ; [.4A38.0020.0002] # LINEAR A SIGN A713 OMEGA +10751 ; [.4A39.0020.0002] # LINEAR A SIGN A714 ABB +10752 ; [.4A3A.0020.0002] # LINEAR A SIGN A715 BB +10753 ; [.4A3B.0020.0002] # LINEAR A SIGN A717 DD +10754 ; [.4A3C.0020.0002] # LINEAR A SIGN A726 EYYY +10755 ; [.4A3D.0020.0002] # LINEAR A SIGN A732 JE +10760 ; [.4A3E.0020.0002] # LINEAR A SIGN A800 +10761 ; [.4A3F.0020.0002] # LINEAR A SIGN A801 +10762 ; [.4A40.0020.0002] # LINEAR A SIGN A802 +10763 ; [.4A41.0020.0002] # LINEAR A SIGN A803 +10764 ; [.4A42.0020.0002] # LINEAR A SIGN A804 +10765 ; [.4A43.0020.0002] # LINEAR A SIGN A805 +10766 ; [.4A44.0020.0002] # LINEAR A SIGN A806 +10767 ; [.4A45.0020.0002] # LINEAR A SIGN A807 +10800 ; [.4A46.0020.0002] # CYPRIOT SYLLABLE A +10801 ; [.4A47.0020.0002] # CYPRIOT SYLLABLE E +10802 ; [.4A48.0020.0002] # CYPRIOT SYLLABLE I +10803 ; [.4A49.0020.0002] # CYPRIOT SYLLABLE O +10804 ; [.4A4A.0020.0002] # CYPRIOT SYLLABLE U +10805 ; [.4A4B.0020.0002] # CYPRIOT SYLLABLE JA +10808 ; [.4A4C.0020.0002] # CYPRIOT SYLLABLE JO +1080A ; [.4A4D.0020.0002] # CYPRIOT SYLLABLE KA +1080B ; [.4A4E.0020.0002] # CYPRIOT SYLLABLE KE +1080C ; [.4A4F.0020.0002] # CYPRIOT SYLLABLE KI +1080D ; [.4A50.0020.0002] # CYPRIOT SYLLABLE KO +1080E ; [.4A51.0020.0002] # CYPRIOT SYLLABLE KU +1080F ; [.4A52.0020.0002] # CYPRIOT SYLLABLE LA +10810 ; [.4A53.0020.0002] # CYPRIOT SYLLABLE LE +10811 ; [.4A54.0020.0002] # CYPRIOT SYLLABLE LI +10812 ; [.4A55.0020.0002] # CYPRIOT SYLLABLE LO +10813 ; [.4A56.0020.0002] # CYPRIOT SYLLABLE LU +10814 ; [.4A57.0020.0002] # CYPRIOT SYLLABLE MA +10815 ; [.4A58.0020.0002] # CYPRIOT SYLLABLE ME +10816 ; [.4A59.0020.0002] # CYPRIOT SYLLABLE MI +10817 ; [.4A5A.0020.0002] # CYPRIOT SYLLABLE MO +10818 ; [.4A5B.0020.0002] # CYPRIOT SYLLABLE MU +10819 ; [.4A5C.0020.0002] # CYPRIOT SYLLABLE NA +1081A ; [.4A5D.0020.0002] # CYPRIOT SYLLABLE NE +1081B ; [.4A5E.0020.0002] # CYPRIOT SYLLABLE NI +1081C ; [.4A5F.0020.0002] # CYPRIOT SYLLABLE NO +1081D ; [.4A60.0020.0002] # CYPRIOT SYLLABLE NU +1081E ; [.4A61.0020.0002] # CYPRIOT SYLLABLE PA +1081F ; [.4A62.0020.0002] # CYPRIOT SYLLABLE PE +10820 ; [.4A63.0020.0002] # CYPRIOT SYLLABLE PI +10821 ; [.4A64.0020.0002] # CYPRIOT SYLLABLE PO +10822 ; [.4A65.0020.0002] # CYPRIOT SYLLABLE PU +10823 ; [.4A66.0020.0002] # CYPRIOT SYLLABLE RA +10824 ; [.4A67.0020.0002] # CYPRIOT SYLLABLE RE +10825 ; [.4A68.0020.0002] # CYPRIOT SYLLABLE RI +10826 ; [.4A69.0020.0002] # CYPRIOT SYLLABLE RO +10827 ; [.4A6A.0020.0002] # CYPRIOT SYLLABLE RU +10828 ; [.4A6B.0020.0002] # CYPRIOT SYLLABLE SA +10829 ; [.4A6C.0020.0002] # CYPRIOT SYLLABLE SE +1082A ; [.4A6D.0020.0002] # CYPRIOT SYLLABLE SI +1082B ; [.4A6E.0020.0002] # CYPRIOT SYLLABLE SO +1082C ; [.4A6F.0020.0002] # CYPRIOT SYLLABLE SU +1082D ; [.4A70.0020.0002] # CYPRIOT SYLLABLE TA +1082E ; [.4A71.0020.0002] # CYPRIOT SYLLABLE TE +1082F ; [.4A72.0020.0002] # CYPRIOT SYLLABLE TI +10830 ; [.4A73.0020.0002] # CYPRIOT SYLLABLE TO +10831 ; [.4A74.0020.0002] # CYPRIOT SYLLABLE TU +10832 ; [.4A75.0020.0002] # CYPRIOT SYLLABLE WA +10833 ; [.4A76.0020.0002] # CYPRIOT SYLLABLE WE +10834 ; [.4A77.0020.0002] # CYPRIOT SYLLABLE WI +10835 ; [.4A78.0020.0002] # CYPRIOT SYLLABLE WO +10837 ; [.4A79.0020.0002] # CYPRIOT SYLLABLE XA +10838 ; [.4A7A.0020.0002] # CYPRIOT SYLLABLE XE +1083C ; [.4A7B.0020.0002] # CYPRIOT SYLLABLE ZA +1083F ; [.4A7C.0020.0002] # CYPRIOT SYLLABLE ZO +10A60 ; [.4A7D.0020.0002] # OLD SOUTH ARABIAN LETTER HE +10A61 ; [.4A7E.0020.0002] # OLD SOUTH ARABIAN LETTER LAMEDH +10A62 ; [.4A7F.0020.0002] # OLD SOUTH ARABIAN LETTER HETH +10A63 ; [.4A80.0020.0002] # OLD SOUTH ARABIAN LETTER MEM +10A64 ; [.4A81.0020.0002] # OLD SOUTH ARABIAN LETTER QOPH +10A65 ; [.4A82.0020.0002] # OLD SOUTH ARABIAN LETTER WAW +10A66 ; [.4A83.0020.0002] # OLD SOUTH ARABIAN LETTER SHIN +10A67 ; [.4A84.0020.0002] # OLD SOUTH ARABIAN LETTER RESH +10A68 ; [.4A85.0020.0002] # OLD SOUTH ARABIAN LETTER BETH +10A69 ; [.4A86.0020.0002] # OLD SOUTH ARABIAN LETTER TAW +10A6A ; [.4A87.0020.0002] # OLD SOUTH ARABIAN LETTER SAT +10A6B ; [.4A88.0020.0002] # OLD SOUTH ARABIAN LETTER KAPH +10A6C ; [.4A89.0020.0002] # OLD SOUTH ARABIAN LETTER NUN +10A6D ; [.4A8A.0020.0002] # OLD SOUTH ARABIAN LETTER KHETH +10A6E ; [.4A8B.0020.0002] # OLD SOUTH ARABIAN LETTER SADHE +10A6F ; [.4A8C.0020.0002] # OLD SOUTH ARABIAN LETTER SAMEKH +10A70 ; [.4A8D.0020.0002] # OLD SOUTH ARABIAN LETTER FE +10A71 ; [.4A8E.0020.0002] # OLD SOUTH ARABIAN LETTER ALEF +10A72 ; [.4A8F.0020.0002] # OLD SOUTH ARABIAN LETTER AYN +10A73 ; [.4A90.0020.0002] # OLD SOUTH ARABIAN LETTER DHADHE +10A74 ; [.4A91.0020.0002] # OLD SOUTH ARABIAN LETTER GIMEL +10A75 ; [.4A92.0020.0002] # OLD SOUTH ARABIAN LETTER DALETH +10A76 ; [.4A93.0020.0002] # OLD SOUTH ARABIAN LETTER GHAYN +10A77 ; [.4A94.0020.0002] # OLD SOUTH ARABIAN LETTER TETH +10A78 ; [.4A95.0020.0002] # OLD SOUTH ARABIAN LETTER ZAYN +10A79 ; [.4A96.0020.0002] # OLD SOUTH ARABIAN LETTER DHALETH +10A7A ; [.4A97.0020.0002] # OLD SOUTH ARABIAN LETTER YODH +10A7B ; [.4A98.0020.0002] # OLD SOUTH ARABIAN LETTER THAW +10A7C ; [.4A99.0020.0002] # OLD SOUTH ARABIAN LETTER THETH +10A80 ; [.4A9A.0020.0002] # OLD NORTH ARABIAN LETTER HEH +10A81 ; [.4A9B.0020.0002] # OLD NORTH ARABIAN LETTER LAM +10A82 ; [.4A9C.0020.0002] # OLD NORTH ARABIAN LETTER HAH +10A83 ; [.4A9D.0020.0002] # OLD NORTH ARABIAN LETTER MEEM +10A84 ; [.4A9E.0020.0002] # OLD NORTH ARABIAN LETTER QAF +10A85 ; [.4A9F.0020.0002] # OLD NORTH ARABIAN LETTER WAW +10A86 ; [.4AA0.0020.0002] # OLD NORTH ARABIAN LETTER ES-2 +10A87 ; [.4AA1.0020.0002] # OLD NORTH ARABIAN LETTER REH +10A88 ; [.4AA2.0020.0002] # OLD NORTH ARABIAN LETTER BEH +10A89 ; [.4AA3.0020.0002] # OLD NORTH ARABIAN LETTER TEH +10A8A ; [.4AA4.0020.0002] # OLD NORTH ARABIAN LETTER ES-1 +10A8B ; [.4AA5.0020.0002] # OLD NORTH ARABIAN LETTER KAF +10A8C ; [.4AA6.0020.0002] # OLD NORTH ARABIAN LETTER NOON +10A8D ; [.4AA7.0020.0002] # OLD NORTH ARABIAN LETTER KHAH +10A8E ; [.4AA8.0020.0002] # OLD NORTH ARABIAN LETTER SAD +10A8F ; [.4AA9.0020.0002] # OLD NORTH ARABIAN LETTER ES-3 +10A90 ; [.4AAA.0020.0002] # OLD NORTH ARABIAN LETTER FEH +10A91 ; [.4AAB.0020.0002] # OLD NORTH ARABIAN LETTER ALEF +10A92 ; [.4AAC.0020.0002] # OLD NORTH ARABIAN LETTER AIN +10A93 ; [.4AAD.0020.0002] # OLD NORTH ARABIAN LETTER DAD +10A94 ; [.4AAE.0020.0002] # OLD NORTH ARABIAN LETTER GEEM +10A95 ; [.4AAF.0020.0002] # OLD NORTH ARABIAN LETTER DAL +10A96 ; [.4AB0.0020.0002] # OLD NORTH ARABIAN LETTER GHAIN +10A97 ; [.4AB1.0020.0002] # OLD NORTH ARABIAN LETTER TAH +10A98 ; [.4AB2.0020.0002] # OLD NORTH ARABIAN LETTER ZAIN +10A99 ; [.4AB3.0020.0002] # OLD NORTH ARABIAN LETTER THAL +10A9A ; [.4AB4.0020.0002] # OLD NORTH ARABIAN LETTER YEH +10A9B ; [.4AB5.0020.0002] # OLD NORTH ARABIAN LETTER THEH +10A9C ; [.4AB6.0020.0002] # OLD NORTH ARABIAN LETTER ZAH +10B00 ; [.4AB7.0020.0002] # AVESTAN LETTER A +10B01 ; [.4AB8.0020.0002] # AVESTAN LETTER AA +10B02 ; [.4AB9.0020.0002] # AVESTAN LETTER AO +10B03 ; [.4ABA.0020.0002] # AVESTAN LETTER AAO +10B04 ; [.4ABB.0020.0002] # AVESTAN LETTER AN +10B05 ; [.4ABC.0020.0002] # AVESTAN LETTER AAN +10B06 ; [.4ABD.0020.0002] # AVESTAN LETTER AE +10B07 ; [.4ABE.0020.0002] # AVESTAN LETTER AEE +10B08 ; [.4ABF.0020.0002] # AVESTAN LETTER E +10B09 ; [.4AC0.0020.0002] # AVESTAN LETTER EE +10B0A ; [.4AC1.0020.0002] # AVESTAN LETTER O +10B0B ; [.4AC2.0020.0002] # AVESTAN LETTER OO +10B0C ; [.4AC3.0020.0002] # AVESTAN LETTER I +10B0D ; [.4AC4.0020.0002] # AVESTAN LETTER II +10B0E ; [.4AC5.0020.0002] # AVESTAN LETTER U +10B0F ; [.4AC6.0020.0002] # AVESTAN LETTER UU +10B10 ; [.4AC7.0020.0002] # AVESTAN LETTER KE +10B11 ; [.4AC8.0020.0002] # AVESTAN LETTER XE +10B12 ; [.4AC9.0020.0002] # AVESTAN LETTER XYE +10B13 ; [.4ACA.0020.0002] # AVESTAN LETTER XVE +10B14 ; [.4ACB.0020.0002] # AVESTAN LETTER GE +10B15 ; [.4ACC.0020.0002] # AVESTAN LETTER GGE +10B16 ; [.4ACD.0020.0002] # AVESTAN LETTER GHE +10B17 ; [.4ACE.0020.0002] # AVESTAN LETTER CE +10B18 ; [.4ACF.0020.0002] # AVESTAN LETTER JE +10B19 ; [.4AD0.0020.0002] # AVESTAN LETTER TE +10B1A ; [.4AD1.0020.0002] # AVESTAN LETTER THE +10B1B ; [.4AD2.0020.0002] # AVESTAN LETTER DE +10B1C ; [.4AD3.0020.0002] # AVESTAN LETTER DHE +10B1D ; [.4AD4.0020.0002] # AVESTAN LETTER TTE +10B1E ; [.4AD5.0020.0002] # AVESTAN LETTER PE +10B1F ; [.4AD6.0020.0002] # AVESTAN LETTER FE +10B20 ; [.4AD7.0020.0002] # AVESTAN LETTER BE +10B21 ; [.4AD8.0020.0002] # AVESTAN LETTER BHE +10B22 ; [.4AD9.0020.0002] # AVESTAN LETTER NGE +10B23 ; [.4ADA.0020.0002] # AVESTAN LETTER NGYE +10B24 ; [.4ADB.0020.0002] # AVESTAN LETTER NGVE +10B25 ; [.4ADC.0020.0002] # AVESTAN LETTER NE +10B26 ; [.4ADD.0020.0002] # AVESTAN LETTER NYE +10B27 ; [.4ADE.0020.0002] # AVESTAN LETTER NNE +10B28 ; [.4ADF.0020.0002] # AVESTAN LETTER ME +10B29 ; [.4AE0.0020.0002] # AVESTAN LETTER HME +10B2A ; [.4AE1.0020.0002] # AVESTAN LETTER YYE +10B2B ; [.4AE2.0020.0002] # AVESTAN LETTER YE +10B2C ; [.4AE3.0020.0002] # AVESTAN LETTER VE +10B2D ; [.4AE4.0020.0002] # AVESTAN LETTER RE +10B2E ; [.4AE4.0020.0004][.0000.0111.0004] # AVESTAN LETTER LE +10B2F ; [.4AE5.0020.0002] # AVESTAN LETTER SE +10B30 ; [.4AE6.0020.0002] # AVESTAN LETTER ZE +10B31 ; [.4AE7.0020.0002] # AVESTAN LETTER SHE +10B32 ; [.4AE8.0020.0002] # AVESTAN LETTER ZHE +10B33 ; [.4AE9.0020.0002] # AVESTAN LETTER SHYE +10B34 ; [.4AEA.0020.0002] # AVESTAN LETTER SSHE +10B35 ; [.4AEB.0020.0002] # AVESTAN LETTER HE +10860 ; [.4AEC.0020.0002] # PALMYRENE LETTER ALEPH +10861 ; [.4AED.0020.0002] # PALMYRENE LETTER BETH +10862 ; [.4AEE.0020.0002] # PALMYRENE LETTER GIMEL +10863 ; [.4AEF.0020.0002] # PALMYRENE LETTER DALETH +10864 ; [.4AF0.0020.0002] # PALMYRENE LETTER HE +10865 ; [.4AF1.0020.0002] # PALMYRENE LETTER WAW +10866 ; [.4AF2.0020.0002] # PALMYRENE LETTER ZAYIN +10867 ; [.4AF3.0020.0002] # PALMYRENE LETTER HETH +10868 ; [.4AF4.0020.0002] # PALMYRENE LETTER TETH +10869 ; [.4AF5.0020.0002] # PALMYRENE LETTER YODH +1086A ; [.4AF6.0020.0002] # PALMYRENE LETTER KAPH +1086B ; [.4AF7.0020.0002] # PALMYRENE LETTER LAMEDH +1086C ; [.4AF8.0020.0002] # PALMYRENE LETTER MEM +1086E ; [.4AF9.0020.0002] # PALMYRENE LETTER NUN +1086D ; [.4AF9.0020.0019] # PALMYRENE LETTER FINAL NUN +1086F ; [.4AFA.0020.0002] # PALMYRENE LETTER SAMEKH +10870 ; [.4AFB.0020.0002] # PALMYRENE LETTER AYIN +10871 ; [.4AFC.0020.0002] # PALMYRENE LETTER PE +10872 ; [.4AFD.0020.0002] # PALMYRENE LETTER SADHE +10873 ; [.4AFE.0020.0002] # PALMYRENE LETTER QOPH +10874 ; [.4AFF.0020.0002] # PALMYRENE LETTER RESH +10875 ; [.4B00.0020.0002] # PALMYRENE LETTER SHIN +10876 ; [.4B01.0020.0002] # PALMYRENE LETTER TAW +10881 ; [.4B02.0020.0002] # NABATAEAN LETTER ALEPH +10880 ; [.4B02.0020.0019] # NABATAEAN LETTER FINAL ALEPH +10883 ; [.4B03.0020.0002] # NABATAEAN LETTER BETH +10882 ; [.4B03.0020.0019] # NABATAEAN LETTER FINAL BETH +10884 ; [.4B04.0020.0002] # NABATAEAN LETTER GIMEL +10885 ; [.4B05.0020.0002] # NABATAEAN LETTER DALETH +10887 ; [.4B06.0020.0002] # NABATAEAN LETTER HE +10886 ; [.4B06.0020.0019] # NABATAEAN LETTER FINAL HE +10888 ; [.4B07.0020.0002] # NABATAEAN LETTER WAW +10889 ; [.4B08.0020.0002] # NABATAEAN LETTER ZAYIN +1088A ; [.4B09.0020.0002] # NABATAEAN LETTER HETH +1088B ; [.4B0A.0020.0002] # NABATAEAN LETTER TETH +1088D ; [.4B0B.0020.0002] # NABATAEAN LETTER YODH +1088C ; [.4B0B.0020.0019] # NABATAEAN LETTER FINAL YODH +1088F ; [.4B0C.0020.0002] # NABATAEAN LETTER KAPH +1088E ; [.4B0C.0020.0019] # NABATAEAN LETTER FINAL KAPH +10891 ; [.4B0D.0020.0002] # NABATAEAN LETTER LAMEDH +10890 ; [.4B0D.0020.0019] # NABATAEAN LETTER FINAL LAMEDH +10893 ; [.4B0E.0020.0002] # NABATAEAN LETTER MEM +10892 ; [.4B0E.0020.0019] # NABATAEAN LETTER FINAL MEM +10895 ; [.4B0F.0020.0002] # NABATAEAN LETTER NUN +10894 ; [.4B0F.0020.0019] # NABATAEAN LETTER FINAL NUN +10896 ; [.4B10.0020.0002] # NABATAEAN LETTER SAMEKH +10897 ; [.4B11.0020.0002] # NABATAEAN LETTER AYIN +10898 ; [.4B12.0020.0002] # NABATAEAN LETTER PE +10899 ; [.4B13.0020.0002] # NABATAEAN LETTER SADHE +1089A ; [.4B14.0020.0002] # NABATAEAN LETTER QOPH +1089B ; [.4B15.0020.0002] # NABATAEAN LETTER RESH +1089D ; [.4B16.0020.0002] # NABATAEAN LETTER SHIN +1089C ; [.4B16.0020.0019] # NABATAEAN LETTER FINAL SHIN +1089E ; [.4B17.0020.0002] # NABATAEAN LETTER TAW +108E0 ; [.4B18.0020.0002] # HATRAN LETTER ALEPH +108E1 ; [.4B19.0020.0002] # HATRAN LETTER BETH +108E2 ; [.4B1A.0020.0002] # HATRAN LETTER GIMEL +108E3 ; [.4B1B.0020.0002] # HATRAN LETTER DALETH-RESH +108E4 ; [.4B1C.0020.0002] # HATRAN LETTER HE +108E5 ; [.4B1D.0020.0002] # HATRAN LETTER WAW +108E6 ; [.4B1E.0020.0002] # HATRAN LETTER ZAYN +108E7 ; [.4B1F.0020.0002] # HATRAN LETTER HETH +108E8 ; [.4B20.0020.0002] # HATRAN LETTER TETH +108E9 ; [.4B21.0020.0002] # HATRAN LETTER YODH +108EA ; [.4B22.0020.0002] # HATRAN LETTER KAPH +108EB ; [.4B23.0020.0002] # HATRAN LETTER LAMEDH +108EC ; [.4B24.0020.0002] # HATRAN LETTER MEM +108ED ; [.4B25.0020.0002] # HATRAN LETTER NUN +108EE ; [.4B26.0020.0002] # HATRAN LETTER SAMEKH +108EF ; [.4B27.0020.0002] # HATRAN LETTER AYN +108F0 ; [.4B28.0020.0002] # HATRAN LETTER PE +108F1 ; [.4B29.0020.0002] # HATRAN LETTER SADHE +108F2 ; [.4B2A.0020.0002] # HATRAN LETTER QOPH +108F4 ; [.4B2B.0020.0002] # HATRAN LETTER SHIN +108F5 ; [.4B2C.0020.0002] # HATRAN LETTER TAW +10840 ; [.4B2D.0020.0002] # IMPERIAL ARAMAIC LETTER ALEPH +10841 ; [.4B2E.0020.0002] # IMPERIAL ARAMAIC LETTER BETH +10842 ; [.4B2F.0020.0002] # IMPERIAL ARAMAIC LETTER GIMEL +10843 ; [.4B30.0020.0002] # IMPERIAL ARAMAIC LETTER DALETH +10844 ; [.4B31.0020.0002] # IMPERIAL ARAMAIC LETTER HE +10845 ; [.4B32.0020.0002] # IMPERIAL ARAMAIC LETTER WAW +10846 ; [.4B33.0020.0002] # IMPERIAL ARAMAIC LETTER ZAYIN +10847 ; [.4B34.0020.0002] # IMPERIAL ARAMAIC LETTER HETH +10848 ; [.4B35.0020.0002] # IMPERIAL ARAMAIC LETTER TETH +10849 ; [.4B36.0020.0002] # IMPERIAL ARAMAIC LETTER YODH +1084A ; [.4B37.0020.0002] # IMPERIAL ARAMAIC LETTER KAPH +1084B ; [.4B38.0020.0002] # IMPERIAL ARAMAIC LETTER LAMEDH +1084C ; [.4B39.0020.0002] # IMPERIAL ARAMAIC LETTER MEM +1084D ; [.4B3A.0020.0002] # IMPERIAL ARAMAIC LETTER NUN +1084E ; [.4B3B.0020.0002] # IMPERIAL ARAMAIC LETTER SAMEKH +1084F ; [.4B3C.0020.0002] # IMPERIAL ARAMAIC LETTER AYIN +10850 ; [.4B3D.0020.0002] # IMPERIAL ARAMAIC LETTER PE +10851 ; [.4B3E.0020.0002] # IMPERIAL ARAMAIC LETTER SADHE +10852 ; [.4B3F.0020.0002] # IMPERIAL ARAMAIC LETTER QOPH +10853 ; [.4B40.0020.0002] # IMPERIAL ARAMAIC LETTER RESH +10854 ; [.4B41.0020.0002] # IMPERIAL ARAMAIC LETTER SHIN +10855 ; [.4B42.0020.0002] # IMPERIAL ARAMAIC LETTER TAW +10B40 ; [.4B43.0020.0002] # INSCRIPTIONAL PARTHIAN LETTER ALEPH +10B41 ; [.4B44.0020.0002] # INSCRIPTIONAL PARTHIAN LETTER BETH +10B42 ; [.4B45.0020.0002] # INSCRIPTIONAL PARTHIAN LETTER GIMEL +10B43 ; [.4B46.0020.0002] # INSCRIPTIONAL PARTHIAN LETTER DALETH +10B44 ; [.4B47.0020.0002] # INSCRIPTIONAL PARTHIAN LETTER HE +10B45 ; [.4B48.0020.0002] # INSCRIPTIONAL PARTHIAN LETTER WAW +10B46 ; [.4B49.0020.0002] # INSCRIPTIONAL PARTHIAN LETTER ZAYIN +10B47 ; [.4B4A.0020.0002] # INSCRIPTIONAL PARTHIAN LETTER HETH +10B48 ; [.4B4B.0020.0002] # INSCRIPTIONAL PARTHIAN LETTER TETH +10B49 ; [.4B4C.0020.0002] # INSCRIPTIONAL PARTHIAN LETTER YODH +10B4A ; [.4B4D.0020.0002] # INSCRIPTIONAL PARTHIAN LETTER KAPH +10B4B ; [.4B4E.0020.0002] # INSCRIPTIONAL PARTHIAN LETTER LAMEDH +10B4C ; [.4B4F.0020.0002] # INSCRIPTIONAL PARTHIAN LETTER MEM +10B4D ; [.4B50.0020.0002] # INSCRIPTIONAL PARTHIAN LETTER NUN +10B4E ; [.4B51.0020.0002] # INSCRIPTIONAL PARTHIAN LETTER SAMEKH +10B4F ; [.4B52.0020.0002] # INSCRIPTIONAL PARTHIAN LETTER AYIN +10B50 ; [.4B53.0020.0002] # INSCRIPTIONAL PARTHIAN LETTER PE +10B51 ; [.4B54.0020.0002] # INSCRIPTIONAL PARTHIAN LETTER SADHE +10B52 ; [.4B55.0020.0002] # INSCRIPTIONAL PARTHIAN LETTER QOPH +10B53 ; [.4B56.0020.0002] # INSCRIPTIONAL PARTHIAN LETTER RESH +10B54 ; [.4B57.0020.0002] # INSCRIPTIONAL PARTHIAN LETTER SHIN +10B55 ; [.4B58.0020.0002] # INSCRIPTIONAL PARTHIAN LETTER TAW +10B60 ; [.4B59.0020.0002] # INSCRIPTIONAL PAHLAVI LETTER ALEPH +10B61 ; [.4B5A.0020.0002] # INSCRIPTIONAL PAHLAVI LETTER BETH +10B62 ; [.4B5B.0020.0002] # INSCRIPTIONAL PAHLAVI LETTER GIMEL +10B63 ; [.4B5C.0020.0002] # INSCRIPTIONAL PAHLAVI LETTER DALETH +10B64 ; [.4B5D.0020.0002] # INSCRIPTIONAL PAHLAVI LETTER HE +10B65 ; [.4B5E.0020.0002] # INSCRIPTIONAL PAHLAVI LETTER WAW-AYIN-RESH +10B66 ; [.4B5F.0020.0002] # INSCRIPTIONAL PAHLAVI LETTER ZAYIN +10B67 ; [.4B60.0020.0002] # INSCRIPTIONAL PAHLAVI LETTER HETH +10B68 ; [.4B61.0020.0002] # INSCRIPTIONAL PAHLAVI LETTER TETH +10B69 ; [.4B62.0020.0002] # INSCRIPTIONAL PAHLAVI LETTER YODH +10B6A ; [.4B63.0020.0002] # INSCRIPTIONAL PAHLAVI LETTER KAPH +10B6B ; [.4B64.0020.0002] # INSCRIPTIONAL PAHLAVI LETTER LAMEDH +10B6C ; [.4B65.0020.0002] # INSCRIPTIONAL PAHLAVI LETTER MEM-QOPH +10B6D ; [.4B66.0020.0002] # INSCRIPTIONAL PAHLAVI LETTER NUN +10B6E ; [.4B67.0020.0002] # INSCRIPTIONAL PAHLAVI LETTER SAMEKH +10B6F ; [.4B68.0020.0002] # INSCRIPTIONAL PAHLAVI LETTER PE +10B70 ; [.4B69.0020.0002] # INSCRIPTIONAL PAHLAVI LETTER SADHE +10B71 ; [.4B6A.0020.0002] # INSCRIPTIONAL PAHLAVI LETTER SHIN +10B72 ; [.4B6B.0020.0002] # INSCRIPTIONAL PAHLAVI LETTER TAW +10B80 ; [.4B6C.0020.0002] # PSALTER PAHLAVI LETTER ALEPH +10B81 ; [.4B6D.0020.0002] # PSALTER PAHLAVI LETTER BETH +10B82 ; [.4B6E.0020.0002] # PSALTER PAHLAVI LETTER GIMEL +10B83 ; [.4B6F.0020.0002] # PSALTER PAHLAVI LETTER DALETH +10B84 ; [.4B70.0020.0002] # PSALTER PAHLAVI LETTER HE +10B85 ; [.4B71.0020.0002] # PSALTER PAHLAVI LETTER WAW-AYIN-RESH +10B86 ; [.4B72.0020.0002] # PSALTER PAHLAVI LETTER ZAYIN +10B87 ; [.4B73.0020.0002] # PSALTER PAHLAVI LETTER HETH +10B88 ; [.4B74.0020.0002] # PSALTER PAHLAVI LETTER YODH +10B89 ; [.4B75.0020.0002] # PSALTER PAHLAVI LETTER KAPH +10B8A ; [.4B76.0020.0002] # PSALTER PAHLAVI LETTER LAMEDH +10B8B ; [.4B77.0020.0002] # PSALTER PAHLAVI LETTER MEM-QOPH +10B8C ; [.4B78.0020.0002] # PSALTER PAHLAVI LETTER NUN +10B8D ; [.4B79.0020.0002] # PSALTER PAHLAVI LETTER SAMEKH +10B8E ; [.4B7A.0020.0002] # PSALTER PAHLAVI LETTER PE +10B8F ; [.4B7B.0020.0002] # PSALTER PAHLAVI LETTER SADHE +10B90 ; [.4B7C.0020.0002] # PSALTER PAHLAVI LETTER SHIN +10B91 ; [.4B7D.0020.0002] # PSALTER PAHLAVI LETTER TAW +10AC0 ; [.4B7E.0020.0002] # MANICHAEAN LETTER ALEPH +10AC1 ; [.4B7F.0020.0002] # MANICHAEAN LETTER BETH +10AC2 ; [.4B80.0020.0002] # MANICHAEAN LETTER BHETH +10AC3 ; [.4B81.0020.0002] # MANICHAEAN LETTER GIMEL +10AC4 ; [.4B82.0020.0002] # MANICHAEAN LETTER GHIMEL +10AC5 ; [.4B83.0020.0002] # MANICHAEAN LETTER DALETH +10AC6 ; [.4B84.0020.0002] # MANICHAEAN LETTER HE +10AC7 ; [.4B85.0020.0002] # MANICHAEAN LETTER WAW +10AC8 ; [.4B85.0020.0004][.0000.0112.0004] # MANICHAEAN SIGN UD +10AC9 ; [.4B86.0020.0002] # MANICHAEAN LETTER ZAYIN +10ACA ; [.4B87.0020.0002] # MANICHAEAN LETTER ZHAYIN +10ACB ; [.4B88.0020.0002] # MANICHAEAN LETTER JAYIN +10ACC ; [.4B89.0020.0002] # MANICHAEAN LETTER JHAYIN +10ACD ; [.4B8A.0020.0002] # MANICHAEAN LETTER HETH +10ACE ; [.4B8B.0020.0002] # MANICHAEAN LETTER TETH +10ACF ; [.4B8C.0020.0002] # MANICHAEAN LETTER YODH +10AD0 ; [.4B8D.0020.0002] # MANICHAEAN LETTER KAPH +10AD1 ; [.4B8E.0020.0002] # MANICHAEAN LETTER XAPH +10AD2 ; [.4B8F.0020.0002] # MANICHAEAN LETTER KHAPH +10AD3 ; [.4B90.0020.0002] # MANICHAEAN LETTER LAMEDH +10AD4 ; [.4B91.0020.0002] # MANICHAEAN LETTER DHAMEDH +10AD5 ; [.4B92.0020.0002] # MANICHAEAN LETTER THAMEDH +10AD6 ; [.4B93.0020.0002] # MANICHAEAN LETTER MEM +10AD7 ; [.4B94.0020.0002] # MANICHAEAN LETTER NUN +10AD8 ; [.4B95.0020.0002] # MANICHAEAN LETTER SAMEKH +10AD9 ; [.4B96.0020.0002] # MANICHAEAN LETTER AYIN +10ADA ; [.4B97.0020.0002] # MANICHAEAN LETTER AAYIN +10ADB ; [.4B98.0020.0002] # MANICHAEAN LETTER PE +10ADC ; [.4B99.0020.0002] # MANICHAEAN LETTER FE +10ADD ; [.4B9A.0020.0002] # MANICHAEAN LETTER SADHE +10ADE ; [.4B9B.0020.0002] # MANICHAEAN LETTER QOPH +10ADF ; [.4B9C.0020.0002] # MANICHAEAN LETTER XOPH +10AE0 ; [.4B9D.0020.0002] # MANICHAEAN LETTER QHOPH +10AE1 ; [.4B9E.0020.0002] # MANICHAEAN LETTER RESH +10AE2 ; [.4B9F.0020.0002] # MANICHAEAN LETTER SHIN +10AE3 ; [.4BA0.0020.0002] # MANICHAEAN LETTER SSHIN +10AE4 ; [.4BA1.0020.0002] # MANICHAEAN LETTER TAW +10380 ; [.4BA2.0020.0002] # UGARITIC LETTER ALPA +10381 ; [.4BA3.0020.0002] # UGARITIC LETTER BETA +10382 ; [.4BA4.0020.0002] # UGARITIC LETTER GAMLA +10383 ; [.4BA5.0020.0002] # UGARITIC LETTER KHA +10384 ; [.4BA6.0020.0002] # UGARITIC LETTER DELTA +10385 ; [.4BA7.0020.0002] # UGARITIC LETTER HO +10386 ; [.4BA8.0020.0002] # UGARITIC LETTER WO +10387 ; [.4BA9.0020.0002] # UGARITIC LETTER ZETA +10388 ; [.4BAA.0020.0002] # UGARITIC LETTER HOTA +10389 ; [.4BAB.0020.0002] # UGARITIC LETTER TET +1038A ; [.4BAC.0020.0002] # UGARITIC LETTER YOD +1038B ; [.4BAD.0020.0002] # UGARITIC LETTER KAF +1038C ; [.4BAE.0020.0002] # UGARITIC LETTER SHIN +1038D ; [.4BAF.0020.0002] # UGARITIC LETTER LAMDA +1038E ; [.4BB0.0020.0002] # UGARITIC LETTER MEM +1038F ; [.4BB1.0020.0002] # UGARITIC LETTER DHAL +10390 ; [.4BB2.0020.0002] # UGARITIC LETTER NUN +10391 ; [.4BB3.0020.0002] # UGARITIC LETTER ZU +10392 ; [.4BB4.0020.0002] # UGARITIC LETTER SAMKA +10393 ; [.4BB5.0020.0002] # UGARITIC LETTER AIN +10394 ; [.4BB6.0020.0002] # UGARITIC LETTER PU +10395 ; [.4BB7.0020.0002] # UGARITIC LETTER SADE +10396 ; [.4BB8.0020.0002] # UGARITIC LETTER QOPA +10397 ; [.4BB9.0020.0002] # UGARITIC LETTER RASHA +10398 ; [.4BBA.0020.0002] # UGARITIC LETTER THANNA +10399 ; [.4BBB.0020.0002] # UGARITIC LETTER GHAIN +1039A ; [.4BBC.0020.0002] # UGARITIC LETTER TO +1039B ; [.4BBD.0020.0002] # UGARITIC LETTER I +1039C ; [.4BBE.0020.0002] # UGARITIC LETTER U +1039D ; [.4BBF.0020.0002] # UGARITIC LETTER SSU +103A0 ; [.4BC0.0020.0002] # OLD PERSIAN SIGN A +103A1 ; [.4BC1.0020.0002] # OLD PERSIAN SIGN I +103A2 ; [.4BC2.0020.0002] # OLD PERSIAN SIGN U +103A3 ; [.4BC3.0020.0002] # OLD PERSIAN SIGN KA +103A4 ; [.4BC4.0020.0002] # OLD PERSIAN SIGN KU +103A5 ; [.4BC5.0020.0002] # OLD PERSIAN SIGN GA +103A6 ; [.4BC6.0020.0002] # OLD PERSIAN SIGN GU +103A7 ; [.4BC7.0020.0002] # OLD PERSIAN SIGN XA +103A8 ; [.4BC8.0020.0002] # OLD PERSIAN SIGN CA +103A9 ; [.4BC9.0020.0002] # OLD PERSIAN SIGN JA +103AA ; [.4BCA.0020.0002] # OLD PERSIAN SIGN JI +103AB ; [.4BCB.0020.0002] # OLD PERSIAN SIGN TA +103AC ; [.4BCC.0020.0002] # OLD PERSIAN SIGN TU +103AD ; [.4BCD.0020.0002] # OLD PERSIAN SIGN DA +103AE ; [.4BCE.0020.0002] # OLD PERSIAN SIGN DI +103AF ; [.4BCF.0020.0002] # OLD PERSIAN SIGN DU +103B0 ; [.4BD0.0020.0002] # OLD PERSIAN SIGN THA +103B1 ; [.4BD1.0020.0002] # OLD PERSIAN SIGN PA +103B2 ; [.4BD2.0020.0002] # OLD PERSIAN SIGN BA +103B3 ; [.4BD3.0020.0002] # OLD PERSIAN SIGN FA +103B4 ; [.4BD4.0020.0002] # OLD PERSIAN SIGN NA +103B5 ; [.4BD5.0020.0002] # OLD PERSIAN SIGN NU +103B6 ; [.4BD6.0020.0002] # OLD PERSIAN SIGN MA +103B7 ; [.4BD7.0020.0002] # OLD PERSIAN SIGN MI +103B8 ; [.4BD8.0020.0002] # OLD PERSIAN SIGN MU +103B9 ; [.4BD9.0020.0002] # OLD PERSIAN SIGN YA +103BA ; [.4BDA.0020.0002] # OLD PERSIAN SIGN VA +103BB ; [.4BDB.0020.0002] # OLD PERSIAN SIGN VI +103BC ; [.4BDC.0020.0002] # OLD PERSIAN SIGN RA +103BD ; [.4BDD.0020.0002] # OLD PERSIAN SIGN RU +103BE ; [.4BDE.0020.0002] # OLD PERSIAN SIGN LA +103BF ; [.4BDF.0020.0002] # OLD PERSIAN SIGN SA +103C0 ; [.4BE0.0020.0002] # OLD PERSIAN SIGN ZA +103C1 ; [.4BE1.0020.0002] # OLD PERSIAN SIGN SHA +103C2 ; [.4BE2.0020.0002] # OLD PERSIAN SIGN SSA +103C3 ; [.4BE3.0020.0002] # OLD PERSIAN SIGN HA +103C8 ; [.4BE4.0020.0002] # OLD PERSIAN SIGN AURAMAZDAA +103C9 ; [.4BE5.0020.0002] # OLD PERSIAN SIGN AURAMAZDAA-2 +103CA ; [.4BE6.0020.0002] # OLD PERSIAN SIGN AURAMAZDAAHA +103CB ; [.4BE7.0020.0002] # OLD PERSIAN SIGN XSHAAYATHIYA +103CC ; [.4BE8.0020.0002] # OLD PERSIAN SIGN DAHYAAUSH +103CD ; [.4BE9.0020.0002] # OLD PERSIAN SIGN DAHYAAUSH-2 +103CE ; [.4BEA.0020.0002] # OLD PERSIAN SIGN BAGA +103CF ; [.4BEB.0020.0002] # OLD PERSIAN SIGN BUUMISH +12000 ; [.4BEC.0020.0002] # CUNEIFORM SIGN A +12001 ; [.4BED.0020.0002] # CUNEIFORM SIGN A TIMES A +12002 ; [.4BEE.0020.0002] # CUNEIFORM SIGN A TIMES BAD +12003 ; [.4BEF.0020.0002] # CUNEIFORM SIGN A TIMES GAN2 TENU +12004 ; [.4BF0.0020.0002] # CUNEIFORM SIGN A TIMES HA +12005 ; [.4BF1.0020.0002] # CUNEIFORM SIGN A TIMES IGI +12006 ; [.4BF2.0020.0002] # CUNEIFORM SIGN A TIMES LAGAR GUNU +12007 ; [.4BF3.0020.0002] # CUNEIFORM SIGN A TIMES MUSH +12008 ; [.4BF4.0020.0002] # CUNEIFORM SIGN A TIMES SAG +12009 ; [.4BF5.0020.0002] # CUNEIFORM SIGN A2 +1200A ; [.4BF6.0020.0002] # CUNEIFORM SIGN AB +1200B ; [.4BF7.0020.0002] # CUNEIFORM SIGN AB TIMES ASH2 +1200C ; [.4BF8.0020.0002] # CUNEIFORM SIGN AB TIMES DUN3 GUNU +1200D ; [.4BF9.0020.0002] # CUNEIFORM SIGN AB TIMES GAL +1200E ; [.4BFA.0020.0002] # CUNEIFORM SIGN AB TIMES GAN2 TENU +1200F ; [.4BFB.0020.0002] # CUNEIFORM SIGN AB TIMES HA +12010 ; [.4BFC.0020.0002] # CUNEIFORM SIGN AB TIMES IGI GUNU +12011 ; [.4BFD.0020.0002] # CUNEIFORM SIGN AB TIMES IMIN +12012 ; [.4BFE.0020.0002] # CUNEIFORM SIGN AB TIMES LAGAB +12013 ; [.4BFF.0020.0002] # CUNEIFORM SIGN AB TIMES SHESH +12014 ; [.4C00.0020.0002] # CUNEIFORM SIGN AB TIMES U PLUS U PLUS U +12015 ; [.4C01.0020.0002] # CUNEIFORM SIGN AB GUNU +12016 ; [.4C02.0020.0002] # CUNEIFORM SIGN AB2 +12017 ; [.4C03.0020.0002] # CUNEIFORM SIGN AB2 TIMES BALAG +12018 ; [.4C04.0020.0002] # CUNEIFORM SIGN AB2 TIMES GAN2 TENU +12019 ; [.4C05.0020.0002] # CUNEIFORM SIGN AB2 TIMES ME PLUS EN +1201A ; [.4C06.0020.0002] # CUNEIFORM SIGN AB2 TIMES SHA3 +1201B ; [.4C07.0020.0002] # CUNEIFORM SIGN AB2 TIMES TAK4 +1201C ; [.4C08.0020.0002] # CUNEIFORM SIGN AD +1201D ; [.4C09.0020.0002] # CUNEIFORM SIGN AK +1201E ; [.4C0A.0020.0002] # CUNEIFORM SIGN AK TIMES ERIN2 +1201F ; [.4C0B.0020.0002] # CUNEIFORM SIGN AK TIMES SHITA PLUS GISH +12020 ; [.4C0C.0020.0002] # CUNEIFORM SIGN AL +12021 ; [.4C0D.0020.0002] # CUNEIFORM SIGN AL TIMES AL +12022 ; [.4C0E.0020.0002] # CUNEIFORM SIGN AL TIMES DIM2 +12023 ; [.4C0F.0020.0002] # CUNEIFORM SIGN AL TIMES GISH +12024 ; [.4C10.0020.0002] # CUNEIFORM SIGN AL TIMES HA +12025 ; [.4C11.0020.0002] # CUNEIFORM SIGN AL TIMES KAD3 +12026 ; [.4C12.0020.0002] # CUNEIFORM SIGN AL TIMES KI +12027 ; [.4C13.0020.0002] # CUNEIFORM SIGN AL TIMES SHE +12028 ; [.4C14.0020.0002] # CUNEIFORM SIGN AL TIMES USH +12029 ; [.4C15.0020.0002] # CUNEIFORM SIGN ALAN +1202A ; [.4C16.0020.0002] # CUNEIFORM SIGN ALEPH +1202B ; [.4C17.0020.0002] # CUNEIFORM SIGN AMAR +1202C ; [.4C18.0020.0002] # CUNEIFORM SIGN AMAR TIMES SHE +1202D ; [.4C19.0020.0002] # CUNEIFORM SIGN AN +1202E ; [.4C1A.0020.0002] # CUNEIFORM SIGN AN OVER AN +1202F ; [.4C1B.0020.0002] # CUNEIFORM SIGN AN THREE TIMES +12030 ; [.4C1C.0020.0002] # CUNEIFORM SIGN AN PLUS NAGA OPPOSING AN PLUS NAGA +12031 ; [.4C1D.0020.0002] # CUNEIFORM SIGN AN PLUS NAGA SQUARED +12032 ; [.4C1E.0020.0002] # CUNEIFORM SIGN ANSHE +12033 ; [.4C1F.0020.0002] # CUNEIFORM SIGN APIN +12034 ; [.4C20.0020.0002] # CUNEIFORM SIGN ARAD +12035 ; [.4C21.0020.0002] # CUNEIFORM SIGN ARAD TIMES KUR +12036 ; [.4C22.0020.0002] # CUNEIFORM SIGN ARKAB +12037 ; [.4C23.0020.0002] # CUNEIFORM SIGN ASAL2 +12038 ; [.4C24.0020.0002] # CUNEIFORM SIGN ASH +12039 ; [.4C25.0020.0002] # CUNEIFORM SIGN ASH ZIDA TENU +1203A ; [.4C26.0020.0002] # CUNEIFORM SIGN ASH KABA TENU +1203B ; [.4C27.0020.0002] # CUNEIFORM SIGN ASH OVER ASH TUG2 OVER TUG2 TUG2 OVER TUG2 PAP +1203C ; [.4C28.0020.0002] # CUNEIFORM SIGN ASH OVER ASH OVER ASH +1203D ; [.4C29.0020.0002] # CUNEIFORM SIGN ASH OVER ASH OVER ASH CROSSING ASH OVER ASH OVER ASH +1203E ; [.4C2A.0020.0002] # CUNEIFORM SIGN ASH2 +1203F ; [.4C2B.0020.0002] # CUNEIFORM SIGN ASHGAB +12040 ; [.4C2C.0020.0002] # CUNEIFORM SIGN BA +12041 ; [.4C2D.0020.0002] # CUNEIFORM SIGN BAD +12042 ; [.4C2E.0020.0002] # CUNEIFORM SIGN BAG3 +12043 ; [.4C2F.0020.0002] # CUNEIFORM SIGN BAHAR2 +12044 ; [.4C30.0020.0002] # CUNEIFORM SIGN BAL +12045 ; [.4C31.0020.0002] # CUNEIFORM SIGN BAL OVER BAL +12046 ; [.4C32.0020.0002] # CUNEIFORM SIGN BALAG +12047 ; [.4C33.0020.0002] # CUNEIFORM SIGN BAR +12048 ; [.4C34.0020.0002] # CUNEIFORM SIGN BARA2 +12049 ; [.4C35.0020.0002] # CUNEIFORM SIGN BI +1204A ; [.4C36.0020.0002] # CUNEIFORM SIGN BI TIMES A +1204B ; [.4C37.0020.0002] # CUNEIFORM SIGN BI TIMES GAR +1204C ; [.4C38.0020.0002] # CUNEIFORM SIGN BI TIMES IGI GUNU +1204D ; [.4C39.0020.0002] # CUNEIFORM SIGN BU +1204E ; [.4C3A.0020.0002] # CUNEIFORM SIGN BU OVER BU AB +1204F ; [.4C3B.0020.0002] # CUNEIFORM SIGN BU OVER BU UN +12050 ; [.4C3C.0020.0002] # CUNEIFORM SIGN BU CROSSING BU +12051 ; [.4C3D.0020.0002] # CUNEIFORM SIGN BULUG +12052 ; [.4C3E.0020.0002] # CUNEIFORM SIGN BULUG OVER BULUG +12053 ; [.4C3F.0020.0002] # CUNEIFORM SIGN BUR +12054 ; [.4C40.0020.0002] # CUNEIFORM SIGN BUR2 +12055 ; [.4C41.0020.0002] # CUNEIFORM SIGN DA +12056 ; [.4C42.0020.0002] # CUNEIFORM SIGN DAG +12057 ; [.4C43.0020.0002] # CUNEIFORM SIGN DAG KISIM5 TIMES A PLUS MASH +12058 ; [.4C44.0020.0002] # CUNEIFORM SIGN DAG KISIM5 TIMES AMAR +12059 ; [.4C45.0020.0002] # CUNEIFORM SIGN DAG KISIM5 TIMES BALAG +1205A ; [.4C46.0020.0002] # CUNEIFORM SIGN DAG KISIM5 TIMES BI +1205B ; [.4C47.0020.0002] # CUNEIFORM SIGN DAG KISIM5 TIMES GA +1205C ; [.4C48.0020.0002] # CUNEIFORM SIGN DAG KISIM5 TIMES GA PLUS MASH +1205D ; [.4C49.0020.0002] # CUNEIFORM SIGN DAG KISIM5 TIMES GI +1205E ; [.4C4A.0020.0002] # CUNEIFORM SIGN DAG KISIM5 TIMES GIR2 +1205F ; [.4C4B.0020.0002] # CUNEIFORM SIGN DAG KISIM5 TIMES GUD +12060 ; [.4C4C.0020.0002] # CUNEIFORM SIGN DAG KISIM5 TIMES HA +12061 ; [.4C4D.0020.0002] # CUNEIFORM SIGN DAG KISIM5 TIMES IR +12062 ; [.4C4E.0020.0002] # CUNEIFORM SIGN DAG KISIM5 TIMES IR PLUS LU +12063 ; [.4C4F.0020.0002] # CUNEIFORM SIGN DAG KISIM5 TIMES KAK +12064 ; [.4C50.0020.0002] # CUNEIFORM SIGN DAG KISIM5 TIMES LA +12065 ; [.4C51.0020.0002] # CUNEIFORM SIGN DAG KISIM5 TIMES LU +12066 ; [.4C52.0020.0002] # CUNEIFORM SIGN DAG KISIM5 TIMES LU PLUS MASH2 +12067 ; [.4C53.0020.0002] # CUNEIFORM SIGN DAG KISIM5 TIMES LUM +12068 ; [.4C54.0020.0002] # CUNEIFORM SIGN DAG KISIM5 TIMES NE +12069 ; [.4C55.0020.0002] # CUNEIFORM SIGN DAG KISIM5 TIMES PAP PLUS PAP +1206A ; [.4C56.0020.0002] # CUNEIFORM SIGN DAG KISIM5 TIMES SI +1206B ; [.4C57.0020.0002] # CUNEIFORM SIGN DAG KISIM5 TIMES TAK4 +1206C ; [.4C58.0020.0002] # CUNEIFORM SIGN DAG KISIM5 TIMES U2 PLUS GIR2 +1206D ; [.4C59.0020.0002] # CUNEIFORM SIGN DAG KISIM5 TIMES USH +1206E ; [.4C5A.0020.0002] # CUNEIFORM SIGN DAM +1206F ; [.4C5B.0020.0002] # CUNEIFORM SIGN DAR +12070 ; [.4C5C.0020.0002] # CUNEIFORM SIGN DARA3 +12071 ; [.4C5D.0020.0002] # CUNEIFORM SIGN DARA4 +12072 ; [.4C5E.0020.0002] # CUNEIFORM SIGN DI +12073 ; [.4C5F.0020.0002] # CUNEIFORM SIGN DIB +12074 ; [.4C60.0020.0002] # CUNEIFORM SIGN DIM +12075 ; [.4C61.0020.0002] # CUNEIFORM SIGN DIM TIMES SHE +12076 ; [.4C62.0020.0002] # CUNEIFORM SIGN DIM2 +12077 ; [.4C63.0020.0002] # CUNEIFORM SIGN DIN +12078 ; [.4C64.0020.0002] # CUNEIFORM SIGN DIN KASKAL U GUNU DISH +12079 ; [.4C65.0020.0002] # CUNEIFORM SIGN DISH +1207A ; [.4C66.0020.0002] # CUNEIFORM SIGN DU +1207B ; [.4C67.0020.0002] # CUNEIFORM SIGN DU OVER DU +1207C ; [.4C68.0020.0002] # CUNEIFORM SIGN DU GUNU +1207D ; [.4C69.0020.0002] # CUNEIFORM SIGN DU SHESHIG +1207E ; [.4C6A.0020.0002] # CUNEIFORM SIGN DUB +1207F ; [.4C6B.0020.0002] # CUNEIFORM SIGN DUB TIMES ESH2 +12080 ; [.4C6C.0020.0002] # CUNEIFORM SIGN DUB2 +12081 ; [.4C6D.0020.0002] # CUNEIFORM SIGN DUG +12082 ; [.4C6E.0020.0002] # CUNEIFORM SIGN DUGUD +12083 ; [.4C6F.0020.0002] # CUNEIFORM SIGN DUH +12084 ; [.4C70.0020.0002] # CUNEIFORM SIGN DUN +12085 ; [.4C71.0020.0002] # CUNEIFORM SIGN DUN3 +12086 ; [.4C72.0020.0002] # CUNEIFORM SIGN DUN3 GUNU +12087 ; [.4C73.0020.0002] # CUNEIFORM SIGN DUN3 GUNU GUNU +12088 ; [.4C74.0020.0002] # CUNEIFORM SIGN DUN4 +12089 ; [.4C75.0020.0002] # CUNEIFORM SIGN DUR2 +1208A ; [.4C76.0020.0002] # CUNEIFORM SIGN E +1208B ; [.4C77.0020.0002] # CUNEIFORM SIGN E TIMES PAP +1208C ; [.4C78.0020.0002] # CUNEIFORM SIGN E OVER E NUN OVER NUN +1208D ; [.4C79.0020.0002] # CUNEIFORM SIGN E2 +1208E ; [.4C7A.0020.0002] # CUNEIFORM SIGN E2 TIMES A PLUS HA PLUS DA +1208F ; [.4C7B.0020.0002] # CUNEIFORM SIGN E2 TIMES GAR +12090 ; [.4C7C.0020.0002] # CUNEIFORM SIGN E2 TIMES MI +12091 ; [.4C7D.0020.0002] # CUNEIFORM SIGN E2 TIMES SAL +12092 ; [.4C7E.0020.0002] # CUNEIFORM SIGN E2 TIMES SHE +12093 ; [.4C7F.0020.0002] # CUNEIFORM SIGN E2 TIMES U +12094 ; [.4C80.0020.0002] # CUNEIFORM SIGN EDIN +12095 ; [.4C81.0020.0002] # CUNEIFORM SIGN EGIR +12096 ; [.4C82.0020.0002] # CUNEIFORM SIGN EL +12097 ; [.4C83.0020.0002] # CUNEIFORM SIGN EN +12098 ; [.4C84.0020.0002] # CUNEIFORM SIGN EN TIMES GAN2 +12099 ; [.4C85.0020.0002] # CUNEIFORM SIGN EN TIMES GAN2 TENU +1209A ; [.4C86.0020.0002] # CUNEIFORM SIGN EN TIMES ME +1209B ; [.4C87.0020.0002] # CUNEIFORM SIGN EN CROSSING EN +1209C ; [.4C88.0020.0002] # CUNEIFORM SIGN EN OPPOSING EN +1209D ; [.4C89.0020.0002] # CUNEIFORM SIGN EN SQUARED +1209E ; [.4C8A.0020.0002] # CUNEIFORM SIGN EREN +1209F ; [.4C8B.0020.0002] # CUNEIFORM SIGN ERIN2 +120A0 ; [.4C8C.0020.0002] # CUNEIFORM SIGN ESH2 +120A1 ; [.4C8D.0020.0002] # CUNEIFORM SIGN EZEN +120A2 ; [.4C8E.0020.0002] # CUNEIFORM SIGN EZEN TIMES A +120A3 ; [.4C8F.0020.0002] # CUNEIFORM SIGN EZEN TIMES A PLUS LAL +120A4 ; [.4C90.0020.0002] # CUNEIFORM SIGN EZEN TIMES A PLUS LAL TIMES LAL +120A5 ; [.4C91.0020.0002] # CUNEIFORM SIGN EZEN TIMES AN +120A6 ; [.4C92.0020.0002] # CUNEIFORM SIGN EZEN TIMES BAD +120A7 ; [.4C93.0020.0002] # CUNEIFORM SIGN EZEN TIMES DUN3 GUNU +120A8 ; [.4C94.0020.0002] # CUNEIFORM SIGN EZEN TIMES DUN3 GUNU GUNU +120A9 ; [.4C95.0020.0002] # CUNEIFORM SIGN EZEN TIMES HA +120AA ; [.4C96.0020.0002] # CUNEIFORM SIGN EZEN TIMES HA GUNU +120AB ; [.4C97.0020.0002] # CUNEIFORM SIGN EZEN TIMES IGI GUNU +120AC ; [.4C98.0020.0002] # CUNEIFORM SIGN EZEN TIMES KASKAL +120AD ; [.4C99.0020.0002] # CUNEIFORM SIGN EZEN TIMES KASKAL SQUARED +120AE ; [.4C9A.0020.0002] # CUNEIFORM SIGN EZEN TIMES KU3 +120AF ; [.4C9B.0020.0002] # CUNEIFORM SIGN EZEN TIMES LA +120B0 ; [.4C9C.0020.0002] # CUNEIFORM SIGN EZEN TIMES LAL TIMES LAL +120B1 ; [.4C9D.0020.0002] # CUNEIFORM SIGN EZEN TIMES LI +120B2 ; [.4C9E.0020.0002] # CUNEIFORM SIGN EZEN TIMES LU +120B3 ; [.4C9F.0020.0002] # CUNEIFORM SIGN EZEN TIMES U2 +120B4 ; [.4CA0.0020.0002] # CUNEIFORM SIGN EZEN TIMES UD +120B5 ; [.4CA1.0020.0002] # CUNEIFORM SIGN GA +120B6 ; [.4CA2.0020.0002] # CUNEIFORM SIGN GA GUNU +120B7 ; [.4CA3.0020.0002] # CUNEIFORM SIGN GA2 +120B8 ; [.4CA4.0020.0002] # CUNEIFORM SIGN GA2 TIMES A PLUS DA PLUS HA +120B9 ; [.4CA5.0020.0002] # CUNEIFORM SIGN GA2 TIMES A PLUS HA +120BA ; [.4CA6.0020.0002] # CUNEIFORM SIGN GA2 TIMES A PLUS IGI +120BB ; [.4CA7.0020.0002] # CUNEIFORM SIGN GA2 TIMES AB2 TENU PLUS TAB +120BC ; [.4CA8.0020.0002] # CUNEIFORM SIGN GA2 TIMES AN +120BD ; [.4CA9.0020.0002] # CUNEIFORM SIGN GA2 TIMES ASH +120BE ; [.4CAA.0020.0002] # CUNEIFORM SIGN GA2 TIMES ASH2 PLUS GAL +120BF ; [.4CAB.0020.0002] # CUNEIFORM SIGN GA2 TIMES BAD +120C0 ; [.4CAC.0020.0002] # CUNEIFORM SIGN GA2 TIMES BAR PLUS RA +120C1 ; [.4CAD.0020.0002] # CUNEIFORM SIGN GA2 TIMES BUR +120C2 ; [.4CAE.0020.0002] # CUNEIFORM SIGN GA2 TIMES BUR PLUS RA +120C3 ; [.4CAF.0020.0002] # CUNEIFORM SIGN GA2 TIMES DA +120C4 ; [.4CB0.0020.0002] # CUNEIFORM SIGN GA2 TIMES DI +120C5 ; [.4CB1.0020.0002] # CUNEIFORM SIGN GA2 TIMES DIM TIMES SHE +120C6 ; [.4CB2.0020.0002] # CUNEIFORM SIGN GA2 TIMES DUB +120C7 ; [.4CB3.0020.0002] # CUNEIFORM SIGN GA2 TIMES EL +120C8 ; [.4CB4.0020.0002] # CUNEIFORM SIGN GA2 TIMES EL PLUS LA +120C9 ; [.4CB5.0020.0002] # CUNEIFORM SIGN GA2 TIMES EN +120CA ; [.4CB6.0020.0002] # CUNEIFORM SIGN GA2 TIMES EN TIMES GAN2 TENU +120CB ; [.4CB7.0020.0002] # CUNEIFORM SIGN GA2 TIMES GAN2 TENU +120CC ; [.4CB8.0020.0002] # CUNEIFORM SIGN GA2 TIMES GAR +120CD ; [.4CB9.0020.0002] # CUNEIFORM SIGN GA2 TIMES GI +120CE ; [.4CBA.0020.0002] # CUNEIFORM SIGN GA2 TIMES GI4 +120CF ; [.4CBB.0020.0002] # CUNEIFORM SIGN GA2 TIMES GI4 PLUS A +120D0 ; [.4CBC.0020.0002] # CUNEIFORM SIGN GA2 TIMES GIR2 PLUS SU +120D1 ; [.4CBD.0020.0002] # CUNEIFORM SIGN GA2 TIMES HA PLUS LU PLUS ESH2 +120D2 ; [.4CBE.0020.0002] # CUNEIFORM SIGN GA2 TIMES HAL +120D3 ; [.4CBF.0020.0002] # CUNEIFORM SIGN GA2 TIMES HAL PLUS LA +120D4 ; [.4CC0.0020.0002] # CUNEIFORM SIGN GA2 TIMES HI PLUS LI +120D5 ; [.4CC1.0020.0002] # CUNEIFORM SIGN GA2 TIMES HUB2 +120D6 ; [.4CC2.0020.0002] # CUNEIFORM SIGN GA2 TIMES IGI GUNU +120D7 ; [.4CC3.0020.0002] # CUNEIFORM SIGN GA2 TIMES ISH PLUS HU PLUS ASH +120D8 ; [.4CC4.0020.0002] # CUNEIFORM SIGN GA2 TIMES KAK +120D9 ; [.4CC5.0020.0002] # CUNEIFORM SIGN GA2 TIMES KASKAL +120DA ; [.4CC6.0020.0002] # CUNEIFORM SIGN GA2 TIMES KID +120DB ; [.4CC7.0020.0002] # CUNEIFORM SIGN GA2 TIMES KID PLUS LAL +120DC ; [.4CC8.0020.0002] # CUNEIFORM SIGN GA2 TIMES KU3 PLUS AN +120DD ; [.4CC9.0020.0002] # CUNEIFORM SIGN GA2 TIMES LA +120DE ; [.4CCA.0020.0002] # CUNEIFORM SIGN GA2 TIMES ME PLUS EN +120DF ; [.4CCB.0020.0002] # CUNEIFORM SIGN GA2 TIMES MI +120E0 ; [.4CCC.0020.0002] # CUNEIFORM SIGN GA2 TIMES NUN +120E1 ; [.4CCD.0020.0002] # CUNEIFORM SIGN GA2 TIMES NUN OVER NUN +120E2 ; [.4CCE.0020.0002] # CUNEIFORM SIGN GA2 TIMES PA +120E3 ; [.4CCF.0020.0002] # CUNEIFORM SIGN GA2 TIMES SAL +120E4 ; [.4CD0.0020.0002] # CUNEIFORM SIGN GA2 TIMES SAR +120E5 ; [.4CD1.0020.0002] # CUNEIFORM SIGN GA2 TIMES SHE +120E6 ; [.4CD2.0020.0002] # CUNEIFORM SIGN GA2 TIMES SHE PLUS TUR +120E7 ; [.4CD3.0020.0002] # CUNEIFORM SIGN GA2 TIMES SHID +120E8 ; [.4CD4.0020.0002] # CUNEIFORM SIGN GA2 TIMES SUM +120E9 ; [.4CD5.0020.0002] # CUNEIFORM SIGN GA2 TIMES TAK4 +120EA ; [.4CD6.0020.0002] # CUNEIFORM SIGN GA2 TIMES U +120EB ; [.4CD7.0020.0002] # CUNEIFORM SIGN GA2 TIMES UD +120EC ; [.4CD8.0020.0002] # CUNEIFORM SIGN GA2 TIMES UD PLUS DU +120ED ; [.4CD9.0020.0002] # CUNEIFORM SIGN GA2 OVER GA2 +120EE ; [.4CDA.0020.0002] # CUNEIFORM SIGN GABA +120EF ; [.4CDB.0020.0002] # CUNEIFORM SIGN GABA CROSSING GABA +120F0 ; [.4CDC.0020.0002] # CUNEIFORM SIGN GAD +120F1 ; [.4CDD.0020.0002] # CUNEIFORM SIGN GAD OVER GAD GAR OVER GAR +120F2 ; [.4CDE.0020.0002] # CUNEIFORM SIGN GAL +120F3 ; [.4CDF.0020.0002] # CUNEIFORM SIGN GAL GAD OVER GAD GAR OVER GAR +120F4 ; [.4CE0.0020.0002] # CUNEIFORM SIGN GALAM +120F5 ; [.4CE1.0020.0002] # CUNEIFORM SIGN GAM +120F6 ; [.4CE2.0020.0002] # CUNEIFORM SIGN GAN +120F7 ; [.4CE3.0020.0002] # CUNEIFORM SIGN GAN2 +120F8 ; [.4CE4.0020.0002] # CUNEIFORM SIGN GAN2 TENU +120F9 ; [.4CE5.0020.0002] # CUNEIFORM SIGN GAN2 OVER GAN2 +120FA ; [.4CE6.0020.0002] # CUNEIFORM SIGN GAN2 CROSSING GAN2 +120FB ; [.4CE7.0020.0002] # CUNEIFORM SIGN GAR +120FC ; [.4CE8.0020.0002] # CUNEIFORM SIGN GAR3 +120FD ; [.4CE9.0020.0002] # CUNEIFORM SIGN GASHAN +120FE ; [.4CEA.0020.0002] # CUNEIFORM SIGN GESHTIN +120FF ; [.4CEB.0020.0002] # CUNEIFORM SIGN GESHTIN TIMES KUR +12100 ; [.4CEC.0020.0002] # CUNEIFORM SIGN GI +12101 ; [.4CED.0020.0002] # CUNEIFORM SIGN GI TIMES E +12102 ; [.4CEE.0020.0002] # CUNEIFORM SIGN GI TIMES U +12103 ; [.4CEF.0020.0002] # CUNEIFORM SIGN GI CROSSING GI +12104 ; [.4CF0.0020.0002] # CUNEIFORM SIGN GI4 +12105 ; [.4CF1.0020.0002] # CUNEIFORM SIGN GI4 OVER GI4 +12106 ; [.4CF2.0020.0002] # CUNEIFORM SIGN GI4 CROSSING GI4 +12107 ; [.4CF3.0020.0002] # CUNEIFORM SIGN GIDIM +12108 ; [.4CF4.0020.0002] # CUNEIFORM SIGN GIR2 +12109 ; [.4CF5.0020.0002] # CUNEIFORM SIGN GIR2 GUNU +1210A ; [.4CF6.0020.0002] # CUNEIFORM SIGN GIR3 +1210B ; [.4CF7.0020.0002] # CUNEIFORM SIGN GIR3 TIMES A PLUS IGI +1210C ; [.4CF8.0020.0002] # CUNEIFORM SIGN GIR3 TIMES GAN2 TENU +1210D ; [.4CF9.0020.0002] # CUNEIFORM SIGN GIR3 TIMES IGI +1210E ; [.4CFA.0020.0002] # CUNEIFORM SIGN GIR3 TIMES LU PLUS IGI +1210F ; [.4CFB.0020.0002] # CUNEIFORM SIGN GIR3 TIMES PA +12110 ; [.4CFC.0020.0002] # CUNEIFORM SIGN GISAL +12111 ; [.4CFD.0020.0002] # CUNEIFORM SIGN GISH +12112 ; [.4CFE.0020.0002] # CUNEIFORM SIGN GISH CROSSING GISH +12113 ; [.4CFF.0020.0002] # CUNEIFORM SIGN GISH TIMES BAD +12114 ; [.4D00.0020.0002] # CUNEIFORM SIGN GISH TIMES TAK4 +12115 ; [.4D01.0020.0002] # CUNEIFORM SIGN GISH TENU +12116 ; [.4D02.0020.0002] # CUNEIFORM SIGN GU +12117 ; [.4D03.0020.0002] # CUNEIFORM SIGN GU CROSSING GU +12118 ; [.4D04.0020.0002] # CUNEIFORM SIGN GU2 +12119 ; [.4D05.0020.0002] # CUNEIFORM SIGN GU2 TIMES KAK +1211A ; [.4D06.0020.0002] # CUNEIFORM SIGN GU2 TIMES KAK TIMES IGI GUNU +1211B ; [.4D07.0020.0002] # CUNEIFORM SIGN GU2 TIMES NUN +1211C ; [.4D08.0020.0002] # CUNEIFORM SIGN GU2 TIMES SAL PLUS TUG2 +1211D ; [.4D09.0020.0002] # CUNEIFORM SIGN GU2 GUNU +1211E ; [.4D0A.0020.0002] # CUNEIFORM SIGN GUD +1211F ; [.4D0B.0020.0002] # CUNEIFORM SIGN GUD TIMES A PLUS KUR +12120 ; [.4D0C.0020.0002] # CUNEIFORM SIGN GUD TIMES KUR +12121 ; [.4D0D.0020.0002] # CUNEIFORM SIGN GUD OVER GUD LUGAL +12122 ; [.4D0E.0020.0002] # CUNEIFORM SIGN GUL +12123 ; [.4D0F.0020.0002] # CUNEIFORM SIGN GUM +12124 ; [.4D10.0020.0002] # CUNEIFORM SIGN GUM TIMES SHE +12125 ; [.4D11.0020.0002] # CUNEIFORM SIGN GUR +12126 ; [.4D12.0020.0002] # CUNEIFORM SIGN GUR7 +12127 ; [.4D13.0020.0002] # CUNEIFORM SIGN GURUN +12128 ; [.4D14.0020.0002] # CUNEIFORM SIGN GURUSH +12129 ; [.4D15.0020.0002] # CUNEIFORM SIGN HA +1212A ; [.4D16.0020.0002] # CUNEIFORM SIGN HA TENU +1212B ; [.4D17.0020.0002] # CUNEIFORM SIGN HA GUNU +1212C ; [.4D18.0020.0002] # CUNEIFORM SIGN HAL +1212D ; [.4D19.0020.0002] # CUNEIFORM SIGN HI +1212E ; [.4D1A.0020.0002] # CUNEIFORM SIGN HI TIMES ASH +1212F ; [.4D1B.0020.0002] # CUNEIFORM SIGN HI TIMES ASH2 +12130 ; [.4D1C.0020.0002] # CUNEIFORM SIGN HI TIMES BAD +12131 ; [.4D1D.0020.0002] # CUNEIFORM SIGN HI TIMES DISH +12132 ; [.4D1E.0020.0002] # CUNEIFORM SIGN HI TIMES GAD +12133 ; [.4D1F.0020.0002] # CUNEIFORM SIGN HI TIMES KIN +12134 ; [.4D20.0020.0002] # CUNEIFORM SIGN HI TIMES NUN +12135 ; [.4D21.0020.0002] # CUNEIFORM SIGN HI TIMES SHE +12136 ; [.4D22.0020.0002] # CUNEIFORM SIGN HI TIMES U +12137 ; [.4D23.0020.0002] # CUNEIFORM SIGN HU +12138 ; [.4D24.0020.0002] # CUNEIFORM SIGN HUB2 +12139 ; [.4D25.0020.0002] # CUNEIFORM SIGN HUB2 TIMES AN +1213A ; [.4D26.0020.0002] # CUNEIFORM SIGN HUB2 TIMES HAL +1213B ; [.4D27.0020.0002] # CUNEIFORM SIGN HUB2 TIMES KASKAL +1213C ; [.4D28.0020.0002] # CUNEIFORM SIGN HUB2 TIMES LISH +1213D ; [.4D29.0020.0002] # CUNEIFORM SIGN HUB2 TIMES UD +1213E ; [.4D2A.0020.0002] # CUNEIFORM SIGN HUL2 +1213F ; [.4D2B.0020.0002] # CUNEIFORM SIGN I +12140 ; [.4D2C.0020.0002] # CUNEIFORM SIGN I A +12141 ; [.4D2D.0020.0002] # CUNEIFORM SIGN IB +12142 ; [.4D2E.0020.0002] # CUNEIFORM SIGN IDIM +12143 ; [.4D2F.0020.0002] # CUNEIFORM SIGN IDIM OVER IDIM BUR +12144 ; [.4D30.0020.0002] # CUNEIFORM SIGN IDIM OVER IDIM SQUARED +12145 ; [.4D31.0020.0002] # CUNEIFORM SIGN IG +12146 ; [.4D32.0020.0002] # CUNEIFORM SIGN IGI +12147 ; [.4D33.0020.0002] # CUNEIFORM SIGN IGI DIB +12148 ; [.4D34.0020.0002] # CUNEIFORM SIGN IGI RI +12149 ; [.4D35.0020.0002] # CUNEIFORM SIGN IGI OVER IGI SHIR OVER SHIR UD OVER UD +1214A ; [.4D36.0020.0002] # CUNEIFORM SIGN IGI GUNU +1214B ; [.4D37.0020.0002] # CUNEIFORM SIGN IL +1214C ; [.4D38.0020.0002] # CUNEIFORM SIGN IL TIMES GAN2 TENU +1214D ; [.4D39.0020.0002] # CUNEIFORM SIGN IL2 +1214E ; [.4D3A.0020.0002] # CUNEIFORM SIGN IM +1214F ; [.4D3B.0020.0002] # CUNEIFORM SIGN IM TIMES TAK4 +12150 ; [.4D3C.0020.0002] # CUNEIFORM SIGN IM CROSSING IM +12151 ; [.4D3D.0020.0002] # CUNEIFORM SIGN IM OPPOSING IM +12152 ; [.4D3E.0020.0002] # CUNEIFORM SIGN IM SQUARED +12153 ; [.4D3F.0020.0002] # CUNEIFORM SIGN IMIN +12154 ; [.4D40.0020.0002] # CUNEIFORM SIGN IN +12155 ; [.4D41.0020.0002] # CUNEIFORM SIGN IR +12156 ; [.4D42.0020.0002] # CUNEIFORM SIGN ISH +12157 ; [.4D43.0020.0002] # CUNEIFORM SIGN KA +12158 ; [.4D44.0020.0002] # CUNEIFORM SIGN KA TIMES A +12159 ; [.4D45.0020.0002] # CUNEIFORM SIGN KA TIMES AD +1215A ; [.4D46.0020.0002] # CUNEIFORM SIGN KA TIMES AD PLUS KU3 +1215B ; [.4D47.0020.0002] # CUNEIFORM SIGN KA TIMES ASH2 +1215C ; [.4D48.0020.0002] # CUNEIFORM SIGN KA TIMES BAD +1215D ; [.4D49.0020.0002] # CUNEIFORM SIGN KA TIMES BALAG +1215E ; [.4D4A.0020.0002] # CUNEIFORM SIGN KA TIMES BAR +1215F ; [.4D4B.0020.0002] # CUNEIFORM SIGN KA TIMES BI +12160 ; [.4D4C.0020.0002] # CUNEIFORM SIGN KA TIMES ERIN2 +12161 ; [.4D4D.0020.0002] # CUNEIFORM SIGN KA TIMES ESH2 +12162 ; [.4D4E.0020.0002] # CUNEIFORM SIGN KA TIMES GA +12163 ; [.4D4F.0020.0002] # CUNEIFORM SIGN KA TIMES GAL +12164 ; [.4D50.0020.0002] # CUNEIFORM SIGN KA TIMES GAN2 TENU +12165 ; [.4D51.0020.0002] # CUNEIFORM SIGN KA TIMES GAR +12166 ; [.4D52.0020.0002] # CUNEIFORM SIGN KA TIMES GAR PLUS SHA3 PLUS A +12167 ; [.4D53.0020.0002] # CUNEIFORM SIGN KA TIMES GI +12168 ; [.4D54.0020.0002] # CUNEIFORM SIGN KA TIMES GIR2 +12169 ; [.4D55.0020.0002] # CUNEIFORM SIGN KA TIMES GISH PLUS SAR +1216A ; [.4D56.0020.0002] # CUNEIFORM SIGN KA TIMES GISH CROSSING GISH +1216B ; [.4D57.0020.0002] # CUNEIFORM SIGN KA TIMES GU +1216C ; [.4D58.0020.0002] # CUNEIFORM SIGN KA TIMES GUR7 +1216D ; [.4D59.0020.0002] # CUNEIFORM SIGN KA TIMES IGI +1216E ; [.4D5A.0020.0002] # CUNEIFORM SIGN KA TIMES IM +1216F ; [.4D5B.0020.0002] # CUNEIFORM SIGN KA TIMES KAK +12170 ; [.4D5C.0020.0002] # CUNEIFORM SIGN KA TIMES KI +12171 ; [.4D5D.0020.0002] # CUNEIFORM SIGN KA TIMES KID +12172 ; [.4D5E.0020.0002] # CUNEIFORM SIGN KA TIMES LI +12173 ; [.4D5F.0020.0002] # CUNEIFORM SIGN KA TIMES LU +12174 ; [.4D60.0020.0002] # CUNEIFORM SIGN KA TIMES ME +12175 ; [.4D61.0020.0002] # CUNEIFORM SIGN KA TIMES ME PLUS DU +12176 ; [.4D62.0020.0002] # CUNEIFORM SIGN KA TIMES ME PLUS GI +12177 ; [.4D63.0020.0002] # CUNEIFORM SIGN KA TIMES ME PLUS TE +12178 ; [.4D64.0020.0002] # CUNEIFORM SIGN KA TIMES MI +12179 ; [.4D65.0020.0002] # CUNEIFORM SIGN KA TIMES MI PLUS NUNUZ +1217A ; [.4D66.0020.0002] # CUNEIFORM SIGN KA TIMES NE +1217B ; [.4D67.0020.0002] # CUNEIFORM SIGN KA TIMES NUN +1217C ; [.4D68.0020.0002] # CUNEIFORM SIGN KA TIMES PI +1217D ; [.4D69.0020.0002] # CUNEIFORM SIGN KA TIMES RU +1217E ; [.4D6A.0020.0002] # CUNEIFORM SIGN KA TIMES SA +1217F ; [.4D6B.0020.0002] # CUNEIFORM SIGN KA TIMES SAR +12180 ; [.4D6C.0020.0002] # CUNEIFORM SIGN KA TIMES SHA +12181 ; [.4D6D.0020.0002] # CUNEIFORM SIGN KA TIMES SHE +12182 ; [.4D6E.0020.0002] # CUNEIFORM SIGN KA TIMES SHID +12183 ; [.4D6F.0020.0002] # CUNEIFORM SIGN KA TIMES SHU +12184 ; [.4D70.0020.0002] # CUNEIFORM SIGN KA TIMES SIG +12185 ; [.4D71.0020.0002] # CUNEIFORM SIGN KA TIMES SUHUR +12186 ; [.4D72.0020.0002] # CUNEIFORM SIGN KA TIMES TAR +12187 ; [.4D73.0020.0002] # CUNEIFORM SIGN KA TIMES U +12188 ; [.4D74.0020.0002] # CUNEIFORM SIGN KA TIMES U2 +12189 ; [.4D75.0020.0002] # CUNEIFORM SIGN KA TIMES UD +1218A ; [.4D76.0020.0002] # CUNEIFORM SIGN KA TIMES UMUM TIMES PA +1218B ; [.4D77.0020.0002] # CUNEIFORM SIGN KA TIMES USH +1218C ; [.4D78.0020.0002] # CUNEIFORM SIGN KA TIMES ZI +1218D ; [.4D79.0020.0002] # CUNEIFORM SIGN KA2 +1218E ; [.4D7A.0020.0002] # CUNEIFORM SIGN KA2 CROSSING KA2 +1218F ; [.4D7B.0020.0002] # CUNEIFORM SIGN KAB +12190 ; [.4D7C.0020.0002] # CUNEIFORM SIGN KAD2 +12191 ; [.4D7D.0020.0002] # CUNEIFORM SIGN KAD3 +12192 ; [.4D7E.0020.0002] # CUNEIFORM SIGN KAD4 +12193 ; [.4D7F.0020.0002] # CUNEIFORM SIGN KAD5 +12194 ; [.4D80.0020.0002] # CUNEIFORM SIGN KAD5 OVER KAD5 +12195 ; [.4D81.0020.0002] # CUNEIFORM SIGN KAK +12196 ; [.4D82.0020.0002] # CUNEIFORM SIGN KAK TIMES IGI GUNU +12197 ; [.4D83.0020.0002] # CUNEIFORM SIGN KAL +12198 ; [.4D84.0020.0002] # CUNEIFORM SIGN KAL TIMES BAD +12199 ; [.4D85.0020.0002] # CUNEIFORM SIGN KAL CROSSING KAL +1219A ; [.4D86.0020.0002] # CUNEIFORM SIGN KAM2 +1219B ; [.4D87.0020.0002] # CUNEIFORM SIGN KAM4 +1219C ; [.4D88.0020.0002] # CUNEIFORM SIGN KASKAL +1219D ; [.4D89.0020.0002] # CUNEIFORM SIGN KASKAL LAGAB TIMES U OVER LAGAB TIMES U +1219E ; [.4D8A.0020.0002] # CUNEIFORM SIGN KASKAL OVER KASKAL LAGAB TIMES U OVER LAGAB TIMES U +1219F ; [.4D8B.0020.0002] # CUNEIFORM SIGN KESH2 +121A0 ; [.4D8C.0020.0002] # CUNEIFORM SIGN KI +121A1 ; [.4D8D.0020.0002] # CUNEIFORM SIGN KI TIMES BAD +121A2 ; [.4D8E.0020.0002] # CUNEIFORM SIGN KI TIMES U +121A3 ; [.4D8F.0020.0002] # CUNEIFORM SIGN KI TIMES UD +121A4 ; [.4D90.0020.0002] # CUNEIFORM SIGN KID +121A5 ; [.4D91.0020.0002] # CUNEIFORM SIGN KIN +121A6 ; [.4D92.0020.0002] # CUNEIFORM SIGN KISAL +121A7 ; [.4D93.0020.0002] # CUNEIFORM SIGN KISH +121A8 ; [.4D94.0020.0002] # CUNEIFORM SIGN KISIM5 +121A9 ; [.4D95.0020.0002] # CUNEIFORM SIGN KISIM5 OVER KISIM5 +121AA ; [.4D96.0020.0002] # CUNEIFORM SIGN KU +121AB ; [.4D97.0020.0002] # CUNEIFORM SIGN KU OVER HI TIMES ASH2 KU OVER HI TIMES ASH2 +121AC ; [.4D98.0020.0002] # CUNEIFORM SIGN KU3 +121AD ; [.4D99.0020.0002] # CUNEIFORM SIGN KU4 +121AE ; [.4D9A.0020.0002] # CUNEIFORM SIGN KU4 VARIANT FORM +121AF ; [.4D9B.0020.0002] # CUNEIFORM SIGN KU7 +121B0 ; [.4D9C.0020.0002] # CUNEIFORM SIGN KUL +121B1 ; [.4D9D.0020.0002] # CUNEIFORM SIGN KUL GUNU +121B2 ; [.4D9E.0020.0002] # CUNEIFORM SIGN KUN +121B3 ; [.4D9F.0020.0002] # CUNEIFORM SIGN KUR +121B4 ; [.4DA0.0020.0002] # CUNEIFORM SIGN KUR OPPOSING KUR +121B5 ; [.4DA1.0020.0002] # CUNEIFORM SIGN KUSHU2 +121B6 ; [.4DA2.0020.0002] # CUNEIFORM SIGN KWU318 +121B7 ; [.4DA3.0020.0002] # CUNEIFORM SIGN LA +121B8 ; [.4DA4.0020.0002] # CUNEIFORM SIGN LAGAB +121B9 ; [.4DA5.0020.0002] # CUNEIFORM SIGN LAGAB TIMES A +121BA ; [.4DA6.0020.0002] # CUNEIFORM SIGN LAGAB TIMES A PLUS DA PLUS HA +121BB ; [.4DA7.0020.0002] # CUNEIFORM SIGN LAGAB TIMES A PLUS GAR +121BC ; [.4DA8.0020.0002] # CUNEIFORM SIGN LAGAB TIMES A PLUS LAL +121BD ; [.4DA9.0020.0002] # CUNEIFORM SIGN LAGAB TIMES AL +121BE ; [.4DAA.0020.0002] # CUNEIFORM SIGN LAGAB TIMES AN +121BF ; [.4DAB.0020.0002] # CUNEIFORM SIGN LAGAB TIMES ASH ZIDA TENU +121C0 ; [.4DAC.0020.0002] # CUNEIFORM SIGN LAGAB TIMES BAD +121C1 ; [.4DAD.0020.0002] # CUNEIFORM SIGN LAGAB TIMES BI +121C2 ; [.4DAE.0020.0002] # CUNEIFORM SIGN LAGAB TIMES DAR +121C3 ; [.4DAF.0020.0002] # CUNEIFORM SIGN LAGAB TIMES EN +121C4 ; [.4DB0.0020.0002] # CUNEIFORM SIGN LAGAB TIMES GA +121C5 ; [.4DB1.0020.0002] # CUNEIFORM SIGN LAGAB TIMES GAR +121C6 ; [.4DB2.0020.0002] # CUNEIFORM SIGN LAGAB TIMES GUD +121C7 ; [.4DB3.0020.0002] # CUNEIFORM SIGN LAGAB TIMES GUD PLUS GUD +121C8 ; [.4DB4.0020.0002] # CUNEIFORM SIGN LAGAB TIMES HA +121C9 ; [.4DB5.0020.0002] # CUNEIFORM SIGN LAGAB TIMES HAL +121CA ; [.4DB6.0020.0002] # CUNEIFORM SIGN LAGAB TIMES HI TIMES NUN +121CB ; [.4DB7.0020.0002] # CUNEIFORM SIGN LAGAB TIMES IGI GUNU +121CC ; [.4DB8.0020.0002] # CUNEIFORM SIGN LAGAB TIMES IM +121CD ; [.4DB9.0020.0002] # CUNEIFORM SIGN LAGAB TIMES IM PLUS HA +121CE ; [.4DBA.0020.0002] # CUNEIFORM SIGN LAGAB TIMES IM PLUS LU +121CF ; [.4DBB.0020.0002] # CUNEIFORM SIGN LAGAB TIMES KI +121D0 ; [.4DBC.0020.0002] # CUNEIFORM SIGN LAGAB TIMES KIN +121D1 ; [.4DBD.0020.0002] # CUNEIFORM SIGN LAGAB TIMES KU3 +121D2 ; [.4DBE.0020.0002] # CUNEIFORM SIGN LAGAB TIMES KUL +121D3 ; [.4DBF.0020.0002] # CUNEIFORM SIGN LAGAB TIMES KUL PLUS HI PLUS A +121D4 ; [.4DC0.0020.0002] # CUNEIFORM SIGN LAGAB TIMES LAGAB +121D5 ; [.4DC1.0020.0002] # CUNEIFORM SIGN LAGAB TIMES LISH +121D6 ; [.4DC2.0020.0002] # CUNEIFORM SIGN LAGAB TIMES LU +121D7 ; [.4DC3.0020.0002] # CUNEIFORM SIGN LAGAB TIMES LUL +121D8 ; [.4DC4.0020.0002] # CUNEIFORM SIGN LAGAB TIMES ME +121D9 ; [.4DC5.0020.0002] # CUNEIFORM SIGN LAGAB TIMES ME PLUS EN +121DA ; [.4DC6.0020.0002] # CUNEIFORM SIGN LAGAB TIMES MUSH +121DB ; [.4DC7.0020.0002] # CUNEIFORM SIGN LAGAB TIMES NE +121DC ; [.4DC8.0020.0002] # CUNEIFORM SIGN LAGAB TIMES SHE PLUS SUM +121DD ; [.4DC9.0020.0002] # CUNEIFORM SIGN LAGAB TIMES SHITA PLUS GISH PLUS ERIN2 +121DE ; [.4DCA.0020.0002] # CUNEIFORM SIGN LAGAB TIMES SHITA PLUS GISH TENU +121DF ; [.4DCB.0020.0002] # CUNEIFORM SIGN LAGAB TIMES SHU2 +121E0 ; [.4DCC.0020.0002] # CUNEIFORM SIGN LAGAB TIMES SHU2 PLUS SHU2 +121E1 ; [.4DCD.0020.0002] # CUNEIFORM SIGN LAGAB TIMES SUM +121E2 ; [.4DCE.0020.0002] # CUNEIFORM SIGN LAGAB TIMES TAG +121E3 ; [.4DCF.0020.0002] # CUNEIFORM SIGN LAGAB TIMES TAK4 +121E4 ; [.4DD0.0020.0002] # CUNEIFORM SIGN LAGAB TIMES TE PLUS A PLUS SU PLUS NA +121E5 ; [.4DD1.0020.0002] # CUNEIFORM SIGN LAGAB TIMES U +121E6 ; [.4DD2.0020.0002] # CUNEIFORM SIGN LAGAB TIMES U PLUS A +121E7 ; [.4DD3.0020.0002] # CUNEIFORM SIGN LAGAB TIMES U PLUS U PLUS U +121E8 ; [.4DD4.0020.0002] # CUNEIFORM SIGN LAGAB TIMES U2 PLUS ASH +121E9 ; [.4DD5.0020.0002] # CUNEIFORM SIGN LAGAB TIMES UD +121EA ; [.4DD6.0020.0002] # CUNEIFORM SIGN LAGAB TIMES USH +121EB ; [.4DD7.0020.0002] # CUNEIFORM SIGN LAGAB SQUARED +121EC ; [.4DD8.0020.0002] # CUNEIFORM SIGN LAGAR +121ED ; [.4DD9.0020.0002] # CUNEIFORM SIGN LAGAR TIMES SHE +121EE ; [.4DDA.0020.0002] # CUNEIFORM SIGN LAGAR TIMES SHE PLUS SUM +121EF ; [.4DDB.0020.0002] # CUNEIFORM SIGN LAGAR GUNU +121F0 ; [.4DDC.0020.0002] # CUNEIFORM SIGN LAGAR GUNU OVER LAGAR GUNU SHE +121F1 ; [.4DDD.0020.0002] # CUNEIFORM SIGN LAHSHU +121F2 ; [.4DDE.0020.0002] # CUNEIFORM SIGN LAL +121F3 ; [.4DDF.0020.0002] # CUNEIFORM SIGN LAL TIMES LAL +121F4 ; [.4DE0.0020.0002] # CUNEIFORM SIGN LAM +121F5 ; [.4DE1.0020.0002] # CUNEIFORM SIGN LAM TIMES KUR +121F6 ; [.4DE2.0020.0002] # CUNEIFORM SIGN LAM TIMES KUR PLUS RU +121F7 ; [.4DE3.0020.0002] # CUNEIFORM SIGN LI +121F8 ; [.4DE4.0020.0002] # CUNEIFORM SIGN LIL +121F9 ; [.4DE5.0020.0002] # CUNEIFORM SIGN LIMMU2 +121FA ; [.4DE6.0020.0002] # CUNEIFORM SIGN LISH +121FB ; [.4DE7.0020.0002] # CUNEIFORM SIGN LU +121FC ; [.4DE8.0020.0002] # CUNEIFORM SIGN LU TIMES BAD +121FD ; [.4DE9.0020.0002] # CUNEIFORM SIGN LU2 +121FE ; [.4DEA.0020.0002] # CUNEIFORM SIGN LU2 TIMES AL +121FF ; [.4DEB.0020.0002] # CUNEIFORM SIGN LU2 TIMES BAD +12200 ; [.4DEC.0020.0002] # CUNEIFORM SIGN LU2 TIMES ESH2 +12201 ; [.4DED.0020.0002] # CUNEIFORM SIGN LU2 TIMES ESH2 TENU +12202 ; [.4DEE.0020.0002] # CUNEIFORM SIGN LU2 TIMES GAN2 TENU +12203 ; [.4DEF.0020.0002] # CUNEIFORM SIGN LU2 TIMES HI TIMES BAD +12204 ; [.4DF0.0020.0002] # CUNEIFORM SIGN LU2 TIMES IM +12205 ; [.4DF1.0020.0002] # CUNEIFORM SIGN LU2 TIMES KAD2 +12206 ; [.4DF2.0020.0002] # CUNEIFORM SIGN LU2 TIMES KAD3 +12207 ; [.4DF3.0020.0002] # CUNEIFORM SIGN LU2 TIMES KAD3 PLUS ASH +12208 ; [.4DF4.0020.0002] # CUNEIFORM SIGN LU2 TIMES KI +12209 ; [.4DF5.0020.0002] # CUNEIFORM SIGN LU2 TIMES LA PLUS ASH +1220A ; [.4DF6.0020.0002] # CUNEIFORM SIGN LU2 TIMES LAGAB +1220B ; [.4DF7.0020.0002] # CUNEIFORM SIGN LU2 TIMES ME PLUS EN +1220C ; [.4DF8.0020.0002] # CUNEIFORM SIGN LU2 TIMES NE +1220D ; [.4DF9.0020.0002] # CUNEIFORM SIGN LU2 TIMES NU +1220E ; [.4DFA.0020.0002] # CUNEIFORM SIGN LU2 TIMES SI PLUS ASH +1220F ; [.4DFB.0020.0002] # CUNEIFORM SIGN LU2 TIMES SIK2 PLUS BU +12210 ; [.4DFC.0020.0002] # CUNEIFORM SIGN LU2 TIMES TUG2 +12211 ; [.4DFD.0020.0002] # CUNEIFORM SIGN LU2 TENU +12212 ; [.4DFE.0020.0002] # CUNEIFORM SIGN LU2 CROSSING LU2 +12213 ; [.4DFF.0020.0002] # CUNEIFORM SIGN LU2 OPPOSING LU2 +12214 ; [.4E00.0020.0002] # CUNEIFORM SIGN LU2 SQUARED +12215 ; [.4E01.0020.0002] # CUNEIFORM SIGN LU2 SHESHIG +12216 ; [.4E02.0020.0002] # CUNEIFORM SIGN LU3 +12217 ; [.4E03.0020.0002] # CUNEIFORM SIGN LUGAL +12218 ; [.4E04.0020.0002] # CUNEIFORM SIGN LUGAL OVER LUGAL +12219 ; [.4E05.0020.0002] # CUNEIFORM SIGN LUGAL OPPOSING LUGAL +1221A ; [.4E06.0020.0002] # CUNEIFORM SIGN LUGAL SHESHIG +1221B ; [.4E07.0020.0002] # CUNEIFORM SIGN LUH +1221C ; [.4E08.0020.0002] # CUNEIFORM SIGN LUL +1221D ; [.4E09.0020.0002] # CUNEIFORM SIGN LUM +1221E ; [.4E0A.0020.0002] # CUNEIFORM SIGN LUM OVER LUM +1221F ; [.4E0B.0020.0002] # CUNEIFORM SIGN LUM OVER LUM GAR OVER GAR +12220 ; [.4E0C.0020.0002] # CUNEIFORM SIGN MA +12221 ; [.4E0D.0020.0002] # CUNEIFORM SIGN MA TIMES TAK4 +12222 ; [.4E0E.0020.0002] # CUNEIFORM SIGN MA GUNU +12223 ; [.4E0F.0020.0002] # CUNEIFORM SIGN MA2 +12224 ; [.4E10.0020.0002] # CUNEIFORM SIGN MAH +12225 ; [.4E11.0020.0002] # CUNEIFORM SIGN MAR +12226 ; [.4E12.0020.0002] # CUNEIFORM SIGN MASH +12227 ; [.4E13.0020.0002] # CUNEIFORM SIGN MASH2 +12228 ; [.4E14.0020.0002] # CUNEIFORM SIGN ME +12229 ; [.4E15.0020.0002] # CUNEIFORM SIGN MES +1222A ; [.4E16.0020.0002] # CUNEIFORM SIGN MI +1222B ; [.4E17.0020.0002] # CUNEIFORM SIGN MIN +1222C ; [.4E18.0020.0002] # CUNEIFORM SIGN MU +1222D ; [.4E19.0020.0002] # CUNEIFORM SIGN MU OVER MU +1222E ; [.4E1A.0020.0002] # CUNEIFORM SIGN MUG +1222F ; [.4E1B.0020.0002] # CUNEIFORM SIGN MUG GUNU +12230 ; [.4E1C.0020.0002] # CUNEIFORM SIGN MUNSUB +12231 ; [.4E1D.0020.0002] # CUNEIFORM SIGN MURGU2 +12232 ; [.4E1E.0020.0002] # CUNEIFORM SIGN MUSH +12233 ; [.4E1F.0020.0002] # CUNEIFORM SIGN MUSH TIMES A +12234 ; [.4E20.0020.0002] # CUNEIFORM SIGN MUSH TIMES KUR +12235 ; [.4E21.0020.0002] # CUNEIFORM SIGN MUSH TIMES ZA +12236 ; [.4E22.0020.0002] # CUNEIFORM SIGN MUSH OVER MUSH +12237 ; [.4E23.0020.0002] # CUNEIFORM SIGN MUSH OVER MUSH TIMES A PLUS NA +12238 ; [.4E24.0020.0002] # CUNEIFORM SIGN MUSH CROSSING MUSH +12239 ; [.4E25.0020.0002] # CUNEIFORM SIGN MUSH3 +1223A ; [.4E26.0020.0002] # CUNEIFORM SIGN MUSH3 TIMES A +1223B ; [.4E27.0020.0002] # CUNEIFORM SIGN MUSH3 TIMES A PLUS DI +1223C ; [.4E28.0020.0002] # CUNEIFORM SIGN MUSH3 TIMES DI +1223D ; [.4E29.0020.0002] # CUNEIFORM SIGN MUSH3 GUNU +1223E ; [.4E2A.0020.0002] # CUNEIFORM SIGN NA +1223F ; [.4E2B.0020.0002] # CUNEIFORM SIGN NA2 +12240 ; [.4E2C.0020.0002] # CUNEIFORM SIGN NAGA +12241 ; [.4E2D.0020.0002] # CUNEIFORM SIGN NAGA INVERTED +12242 ; [.4E2E.0020.0002] # CUNEIFORM SIGN NAGA TIMES SHU TENU +12243 ; [.4E2F.0020.0002] # CUNEIFORM SIGN NAGA OPPOSING NAGA +12244 ; [.4E30.0020.0002] # CUNEIFORM SIGN NAGAR +12245 ; [.4E31.0020.0002] # CUNEIFORM SIGN NAM NUTILLU +12246 ; [.4E32.0020.0002] # CUNEIFORM SIGN NAM +12247 ; [.4E33.0020.0002] # CUNEIFORM SIGN NAM2 +12248 ; [.4E34.0020.0002] # CUNEIFORM SIGN NE +12249 ; [.4E35.0020.0002] # CUNEIFORM SIGN NE TIMES A +1224A ; [.4E36.0020.0002] # CUNEIFORM SIGN NE TIMES UD +1224B ; [.4E37.0020.0002] # CUNEIFORM SIGN NE SHESHIG +1224C ; [.4E38.0020.0002] # CUNEIFORM SIGN NI +1224D ; [.4E39.0020.0002] # CUNEIFORM SIGN NI TIMES E +1224E ; [.4E3A.0020.0002] # CUNEIFORM SIGN NI2 +1224F ; [.4E3B.0020.0002] # CUNEIFORM SIGN NIM +12250 ; [.4E3C.0020.0002] # CUNEIFORM SIGN NIM TIMES GAN2 TENU +12251 ; [.4E3D.0020.0002] # CUNEIFORM SIGN NIM TIMES GAR PLUS GAN2 TENU +12252 ; [.4E3E.0020.0002] # CUNEIFORM SIGN NINDA2 +12253 ; [.4E3F.0020.0002] # CUNEIFORM SIGN NINDA2 TIMES AN +12254 ; [.4E40.0020.0002] # CUNEIFORM SIGN NINDA2 TIMES ASH +12255 ; [.4E41.0020.0002] # CUNEIFORM SIGN NINDA2 TIMES ASH PLUS ASH +12256 ; [.4E42.0020.0002] # CUNEIFORM SIGN NINDA2 TIMES GUD +12257 ; [.4E43.0020.0002] # CUNEIFORM SIGN NINDA2 TIMES ME PLUS GAN2 TENU +12258 ; [.4E44.0020.0002] # CUNEIFORM SIGN NINDA2 TIMES NE +12259 ; [.4E45.0020.0002] # CUNEIFORM SIGN NINDA2 TIMES NUN +1225A ; [.4E46.0020.0002] # CUNEIFORM SIGN NINDA2 TIMES SHE +1225B ; [.4E47.0020.0002] # CUNEIFORM SIGN NINDA2 TIMES SHE PLUS A AN +1225C ; [.4E48.0020.0002] # CUNEIFORM SIGN NINDA2 TIMES SHE PLUS ASH +1225D ; [.4E49.0020.0002] # CUNEIFORM SIGN NINDA2 TIMES SHE PLUS ASH PLUS ASH +1225E ; [.4E4A.0020.0002] # CUNEIFORM SIGN NINDA2 TIMES U2 PLUS ASH +1225F ; [.4E4B.0020.0002] # CUNEIFORM SIGN NINDA2 TIMES USH +12260 ; [.4E4C.0020.0002] # CUNEIFORM SIGN NISAG +12261 ; [.4E4D.0020.0002] # CUNEIFORM SIGN NU +12262 ; [.4E4E.0020.0002] # CUNEIFORM SIGN NU11 +122D4 ; [.4E4F.0020.0002] # CUNEIFORM SIGN SHIR TENU +122D5 ; [.4E50.0020.0002] # CUNEIFORM SIGN SHIR OVER SHIR BUR OVER BUR +12263 ; [.4E51.0020.0002] # CUNEIFORM SIGN NUN +12264 ; [.4E52.0020.0002] # CUNEIFORM SIGN NUN LAGAR TIMES GAR +12265 ; [.4E53.0020.0002] # CUNEIFORM SIGN NUN LAGAR TIMES MASH +12266 ; [.4E54.0020.0002] # CUNEIFORM SIGN NUN LAGAR TIMES SAL +12267 ; [.4E55.0020.0002] # CUNEIFORM SIGN NUN LAGAR TIMES SAL OVER NUN LAGAR TIMES SAL +12268 ; [.4E56.0020.0002] # CUNEIFORM SIGN NUN LAGAR TIMES USH +12269 ; [.4E57.0020.0002] # CUNEIFORM SIGN NUN TENU +1226A ; [.4E58.0020.0002] # CUNEIFORM SIGN NUN OVER NUN +1226B ; [.4E59.0020.0002] # CUNEIFORM SIGN NUN CROSSING NUN +1226C ; [.4E5A.0020.0002] # CUNEIFORM SIGN NUN CROSSING NUN LAGAR OVER LAGAR +1226D ; [.4E5B.0020.0002] # CUNEIFORM SIGN NUNUZ +1226E ; [.4E5C.0020.0002] # CUNEIFORM SIGN NUNUZ AB2 TIMES ASHGAB +1226F ; [.4E5D.0020.0002] # CUNEIFORM SIGN NUNUZ AB2 TIMES BI +12270 ; [.4E5E.0020.0002] # CUNEIFORM SIGN NUNUZ AB2 TIMES DUG +12271 ; [.4E5F.0020.0002] # CUNEIFORM SIGN NUNUZ AB2 TIMES GUD +12272 ; [.4E60.0020.0002] # CUNEIFORM SIGN NUNUZ AB2 TIMES IGI GUNU +12273 ; [.4E61.0020.0002] # CUNEIFORM SIGN NUNUZ AB2 TIMES KAD3 +12274 ; [.4E62.0020.0002] # CUNEIFORM SIGN NUNUZ AB2 TIMES LA +12275 ; [.4E63.0020.0002] # CUNEIFORM SIGN NUNUZ AB2 TIMES NE +12276 ; [.4E64.0020.0002] # CUNEIFORM SIGN NUNUZ AB2 TIMES SILA3 +12277 ; [.4E65.0020.0002] # CUNEIFORM SIGN NUNUZ AB2 TIMES U2 +12278 ; [.4E66.0020.0002] # CUNEIFORM SIGN NUNUZ KISIM5 TIMES BI +12279 ; [.4E67.0020.0002] # CUNEIFORM SIGN NUNUZ KISIM5 TIMES BI U +1227A ; [.4E68.0020.0002] # CUNEIFORM SIGN PA +1227B ; [.4E69.0020.0002] # CUNEIFORM SIGN PAD +1227C ; [.4E6A.0020.0002] # CUNEIFORM SIGN PAN +1227D ; [.4E6B.0020.0002] # CUNEIFORM SIGN PAP +1227E ; [.4E6C.0020.0002] # CUNEIFORM SIGN PESH2 +1227F ; [.4E6D.0020.0002] # CUNEIFORM SIGN PI +12280 ; [.4E6E.0020.0002] # CUNEIFORM SIGN PI TIMES A +12281 ; [.4E6F.0020.0002] # CUNEIFORM SIGN PI TIMES AB +12282 ; [.4E70.0020.0002] # CUNEIFORM SIGN PI TIMES BI +12283 ; [.4E71.0020.0002] # CUNEIFORM SIGN PI TIMES BU +12284 ; [.4E72.0020.0002] # CUNEIFORM SIGN PI TIMES E +12285 ; [.4E73.0020.0002] # CUNEIFORM SIGN PI TIMES I +12286 ; [.4E74.0020.0002] # CUNEIFORM SIGN PI TIMES IB +12287 ; [.4E75.0020.0002] # CUNEIFORM SIGN PI TIMES U +12288 ; [.4E76.0020.0002] # CUNEIFORM SIGN PI TIMES U2 +12289 ; [.4E77.0020.0002] # CUNEIFORM SIGN PI CROSSING PI +1228A ; [.4E78.0020.0002] # CUNEIFORM SIGN PIRIG +1228B ; [.4E79.0020.0002] # CUNEIFORM SIGN PIRIG TIMES KAL +1228C ; [.4E7A.0020.0002] # CUNEIFORM SIGN PIRIG TIMES UD +1228D ; [.4E7B.0020.0002] # CUNEIFORM SIGN PIRIG TIMES ZA +1228E ; [.4E7C.0020.0002] # CUNEIFORM SIGN PIRIG OPPOSING PIRIG +1228F ; [.4E7D.0020.0002] # CUNEIFORM SIGN RA +12290 ; [.4E7E.0020.0002] # CUNEIFORM SIGN RAB +12291 ; [.4E7F.0020.0002] # CUNEIFORM SIGN RI +12292 ; [.4E80.0020.0002] # CUNEIFORM SIGN RU +12293 ; [.4E81.0020.0002] # CUNEIFORM SIGN SA +12294 ; [.4E82.0020.0002] # CUNEIFORM SIGN SAG NUTILLU +12295 ; [.4E83.0020.0002] # CUNEIFORM SIGN SAG +12296 ; [.4E84.0020.0002] # CUNEIFORM SIGN SAG TIMES A +12297 ; [.4E85.0020.0002] # CUNEIFORM SIGN SAG TIMES DU +12298 ; [.4E86.0020.0002] # CUNEIFORM SIGN SAG TIMES DUB +12299 ; [.4E87.0020.0002] # CUNEIFORM SIGN SAG TIMES HA +1229A ; [.4E88.0020.0002] # CUNEIFORM SIGN SAG TIMES KAK +1229B ; [.4E89.0020.0002] # CUNEIFORM SIGN SAG TIMES KUR +1229C ; [.4E8A.0020.0002] # CUNEIFORM SIGN SAG TIMES LUM +1229D ; [.4E8B.0020.0002] # CUNEIFORM SIGN SAG TIMES MI +1229E ; [.4E8C.0020.0002] # CUNEIFORM SIGN SAG TIMES NUN +1229F ; [.4E8D.0020.0002] # CUNEIFORM SIGN SAG TIMES SAL +122A0 ; [.4E8E.0020.0002] # CUNEIFORM SIGN SAG TIMES SHID +122A1 ; [.4E8F.0020.0002] # CUNEIFORM SIGN SAG TIMES TAB +122A2 ; [.4E90.0020.0002] # CUNEIFORM SIGN SAG TIMES U2 +122A3 ; [.4E91.0020.0002] # CUNEIFORM SIGN SAG TIMES UB +122A4 ; [.4E92.0020.0002] # CUNEIFORM SIGN SAG TIMES UM +122A5 ; [.4E93.0020.0002] # CUNEIFORM SIGN SAG TIMES UR +122A6 ; [.4E94.0020.0002] # CUNEIFORM SIGN SAG TIMES USH +122A7 ; [.4E95.0020.0002] # CUNEIFORM SIGN SAG OVER SAG +122A8 ; [.4E96.0020.0002] # CUNEIFORM SIGN SAG GUNU +122A9 ; [.4E97.0020.0002] # CUNEIFORM SIGN SAL +122AA ; [.4E98.0020.0002] # CUNEIFORM SIGN SAL LAGAB TIMES ASH2 +122AB ; [.4E99.0020.0002] # CUNEIFORM SIGN SANGA2 +122AC ; [.4E9A.0020.0002] # CUNEIFORM SIGN SAR +122AD ; [.4E9B.0020.0002] # CUNEIFORM SIGN SHA +122AE ; [.4E9C.0020.0002] # CUNEIFORM SIGN SHA3 +122AF ; [.4E9D.0020.0002] # CUNEIFORM SIGN SHA3 TIMES A +122B0 ; [.4E9E.0020.0002] # CUNEIFORM SIGN SHA3 TIMES BAD +122B1 ; [.4E9F.0020.0002] # CUNEIFORM SIGN SHA3 TIMES GISH +122B2 ; [.4EA0.0020.0002] # CUNEIFORM SIGN SHA3 TIMES NE +122B3 ; [.4EA1.0020.0002] # CUNEIFORM SIGN SHA3 TIMES SHU2 +122B4 ; [.4EA2.0020.0002] # CUNEIFORM SIGN SHA3 TIMES TUR +122B5 ; [.4EA3.0020.0002] # CUNEIFORM SIGN SHA3 TIMES U +122B6 ; [.4EA4.0020.0002] # CUNEIFORM SIGN SHA3 TIMES U PLUS A +122B7 ; [.4EA5.0020.0002] # CUNEIFORM SIGN SHA6 +122B8 ; [.4EA6.0020.0002] # CUNEIFORM SIGN SHAB6 +122B9 ; [.4EA7.0020.0002] # CUNEIFORM SIGN SHAR2 +122BA ; [.4EA8.0020.0002] # CUNEIFORM SIGN SHE +122BB ; [.4EA9.0020.0002] # CUNEIFORM SIGN SHE HU +122BC ; [.4EAA.0020.0002] # CUNEIFORM SIGN SHE OVER SHE GAD OVER GAD GAR OVER GAR +122BD ; [.4EAB.0020.0002] # CUNEIFORM SIGN SHE OVER SHE TAB OVER TAB GAR OVER GAR +122BE ; [.4EAC.0020.0002] # CUNEIFORM SIGN SHEG9 +122BF ; [.4EAD.0020.0002] # CUNEIFORM SIGN SHEN +122C0 ; [.4EAE.0020.0002] # CUNEIFORM SIGN SHESH +122C1 ; [.4EAF.0020.0002] # CUNEIFORM SIGN SHESH2 +122C2 ; [.4EB0.0020.0002] # CUNEIFORM SIGN SHESHLAM +122C3 ; [.4EB1.0020.0002] # CUNEIFORM SIGN SHID +122C4 ; [.4EB2.0020.0002] # CUNEIFORM SIGN SHID TIMES A +122C5 ; [.4EB3.0020.0002] # CUNEIFORM SIGN SHID TIMES IM +122C6 ; [.4EB4.0020.0002] # CUNEIFORM SIGN SHIM +122C7 ; [.4EB5.0020.0002] # CUNEIFORM SIGN SHIM TIMES A +122C8 ; [.4EB6.0020.0002] # CUNEIFORM SIGN SHIM TIMES BAL +122C9 ; [.4EB7.0020.0002] # CUNEIFORM SIGN SHIM TIMES BULUG +122CA ; [.4EB8.0020.0002] # CUNEIFORM SIGN SHIM TIMES DIN +122CB ; [.4EB9.0020.0002] # CUNEIFORM SIGN SHIM TIMES GAR +122CC ; [.4EBA.0020.0002] # CUNEIFORM SIGN SHIM TIMES IGI +122CD ; [.4EBB.0020.0002] # CUNEIFORM SIGN SHIM TIMES IGI GUNU +122CE ; [.4EBC.0020.0002] # CUNEIFORM SIGN SHIM TIMES KUSHU2 +122CF ; [.4EBD.0020.0002] # CUNEIFORM SIGN SHIM TIMES LUL +122D0 ; [.4EBE.0020.0002] # CUNEIFORM SIGN SHIM TIMES MUG +122D1 ; [.4EBF.0020.0002] # CUNEIFORM SIGN SHIM TIMES SAL +122D2 ; [.4EC0.0020.0002] # CUNEIFORM SIGN SHINIG +122D3 ; [.4EC1.0020.0002] # CUNEIFORM SIGN SHIR +122D6 ; [.4EC2.0020.0002] # CUNEIFORM SIGN SHITA +122D7 ; [.4EC3.0020.0002] # CUNEIFORM SIGN SHU +122D8 ; [.4EC4.0020.0002] # CUNEIFORM SIGN SHU OVER INVERTED SHU +122D9 ; [.4EC5.0020.0002] # CUNEIFORM SIGN SHU2 +122DA ; [.4EC6.0020.0002] # CUNEIFORM SIGN SHUBUR +122DB ; [.4EC7.0020.0002] # CUNEIFORM SIGN SI +122DC ; [.4EC8.0020.0002] # CUNEIFORM SIGN SI GUNU +122DD ; [.4EC9.0020.0002] # CUNEIFORM SIGN SIG +122DE ; [.4ECA.0020.0002] # CUNEIFORM SIGN SIG4 +122DF ; [.4ECB.0020.0002] # CUNEIFORM SIGN SIG4 OVER SIG4 SHU2 +122E0 ; [.4ECC.0020.0002] # CUNEIFORM SIGN SIK2 +122E1 ; [.4ECD.0020.0002] # CUNEIFORM SIGN SILA3 +122E2 ; [.4ECE.0020.0002] # CUNEIFORM SIGN SU +122E3 ; [.4ECF.0020.0002] # CUNEIFORM SIGN SU OVER SU +122E4 ; [.4ED0.0020.0002] # CUNEIFORM SIGN SUD +122E5 ; [.4ED1.0020.0002] # CUNEIFORM SIGN SUD2 +122E6 ; [.4ED2.0020.0002] # CUNEIFORM SIGN SUHUR +122E7 ; [.4ED3.0020.0002] # CUNEIFORM SIGN SUM +122E8 ; [.4ED4.0020.0002] # CUNEIFORM SIGN SUMASH +122E9 ; [.4ED5.0020.0002] # CUNEIFORM SIGN SUR +122EA ; [.4ED6.0020.0002] # CUNEIFORM SIGN SUR9 +122EB ; [.4ED7.0020.0002] # CUNEIFORM SIGN TA +122EC ; [.4ED8.0020.0002] # CUNEIFORM SIGN TA ASTERISK +122ED ; [.4ED9.0020.0002] # CUNEIFORM SIGN TA TIMES HI +122EE ; [.4EDA.0020.0002] # CUNEIFORM SIGN TA TIMES MI +122EF ; [.4EDB.0020.0002] # CUNEIFORM SIGN TA GUNU +122F0 ; [.4EDC.0020.0002] # CUNEIFORM SIGN TAB +122F1 ; [.4EDD.0020.0002] # CUNEIFORM SIGN TAB OVER TAB NI OVER NI DISH OVER DISH +122F2 ; [.4EDE.0020.0002] # CUNEIFORM SIGN TAB SQUARED +122F3 ; [.4EDF.0020.0002] # CUNEIFORM SIGN TAG +122F4 ; [.4EE0.0020.0002] # CUNEIFORM SIGN TAG TIMES BI +122F5 ; [.4EE1.0020.0002] # CUNEIFORM SIGN TAG TIMES GUD +122F6 ; [.4EE2.0020.0002] # CUNEIFORM SIGN TAG TIMES SHE +122F7 ; [.4EE3.0020.0002] # CUNEIFORM SIGN TAG TIMES SHU +122F8 ; [.4EE4.0020.0002] # CUNEIFORM SIGN TAG TIMES TUG2 +122F9 ; [.4EE5.0020.0002] # CUNEIFORM SIGN TAG TIMES UD +122FA ; [.4EE6.0020.0002] # CUNEIFORM SIGN TAK4 +122FB ; [.4EE7.0020.0002] # CUNEIFORM SIGN TAR +122FC ; [.4EE8.0020.0002] # CUNEIFORM SIGN TE +122FD ; [.4EE9.0020.0002] # CUNEIFORM SIGN TE GUNU +122FE ; [.4EEA.0020.0002] # CUNEIFORM SIGN TI +122FF ; [.4EEB.0020.0002] # CUNEIFORM SIGN TI TENU +12300 ; [.4EEC.0020.0002] # CUNEIFORM SIGN TIL +12301 ; [.4EED.0020.0002] # CUNEIFORM SIGN TIR +12302 ; [.4EEE.0020.0002] # CUNEIFORM SIGN TIR TIMES TAK4 +12303 ; [.4EEF.0020.0002] # CUNEIFORM SIGN TIR OVER TIR +12304 ; [.4EF0.0020.0002] # CUNEIFORM SIGN TIR OVER TIR GAD OVER GAD GAR OVER GAR +12305 ; [.4EF1.0020.0002] # CUNEIFORM SIGN TU +12306 ; [.4EF2.0020.0002] # CUNEIFORM SIGN TUG2 +12307 ; [.4EF3.0020.0002] # CUNEIFORM SIGN TUK +12308 ; [.4EF4.0020.0002] # CUNEIFORM SIGN TUM +12309 ; [.4EF5.0020.0002] # CUNEIFORM SIGN TUR +1230A ; [.4EF6.0020.0002] # CUNEIFORM SIGN TUR OVER TUR ZA OVER ZA +1230B ; [.4EF7.0020.0002] # CUNEIFORM SIGN U +1230C ; [.4EF8.0020.0002] # CUNEIFORM SIGN U GUD +1230D ; [.4EF9.0020.0002] # CUNEIFORM SIGN U U U +1230E ; [.4EFA.0020.0002] # CUNEIFORM SIGN U OVER U PA OVER PA GAR OVER GAR +1230F ; [.4EFB.0020.0002] # CUNEIFORM SIGN U OVER U SUR OVER SUR +12310 ; [.4EFC.0020.0002] # CUNEIFORM SIGN U OVER U U REVERSED OVER U REVERSED +12311 ; [.4EFD.0020.0002] # CUNEIFORM SIGN U2 +12312 ; [.4EFE.0020.0002] # CUNEIFORM SIGN UB +12313 ; [.4EFF.0020.0002] # CUNEIFORM SIGN UD +12314 ; [.4F00.0020.0002] # CUNEIFORM SIGN UD KUSHU2 +12315 ; [.4F01.0020.0002] # CUNEIFORM SIGN UD TIMES BAD +12316 ; [.4F02.0020.0002] # CUNEIFORM SIGN UD TIMES MI +12317 ; [.4F03.0020.0002] # CUNEIFORM SIGN UD TIMES U PLUS U PLUS U +12318 ; [.4F04.0020.0002] # CUNEIFORM SIGN UD TIMES U PLUS U PLUS U GUNU +12319 ; [.4F05.0020.0002] # CUNEIFORM SIGN UD GUNU +1231A ; [.4F06.0020.0002] # CUNEIFORM SIGN UD SHESHIG +1231B ; [.4F07.0020.0002] # CUNEIFORM SIGN UD SHESHIG TIMES BAD +1231C ; [.4F08.0020.0002] # CUNEIFORM SIGN UDUG +1231D ; [.4F09.0020.0002] # CUNEIFORM SIGN UM +1231E ; [.4F0A.0020.0002] # CUNEIFORM SIGN UM TIMES LAGAB +1231F ; [.4F0B.0020.0002] # CUNEIFORM SIGN UM TIMES ME PLUS DA +12320 ; [.4F0C.0020.0002] # CUNEIFORM SIGN UM TIMES SHA3 +12321 ; [.4F0D.0020.0002] # CUNEIFORM SIGN UM TIMES U +12322 ; [.4F0E.0020.0002] # CUNEIFORM SIGN UMBIN +12323 ; [.4F0F.0020.0002] # CUNEIFORM SIGN UMUM +12324 ; [.4F10.0020.0002] # CUNEIFORM SIGN UMUM TIMES KASKAL +12325 ; [.4F11.0020.0002] # CUNEIFORM SIGN UMUM TIMES PA +12326 ; [.4F12.0020.0002] # CUNEIFORM SIGN UN +12327 ; [.4F13.0020.0002] # CUNEIFORM SIGN UN GUNU +12328 ; [.4F14.0020.0002] # CUNEIFORM SIGN UR +12329 ; [.4F15.0020.0002] # CUNEIFORM SIGN UR CROSSING UR +1232A ; [.4F16.0020.0002] # CUNEIFORM SIGN UR SHESHIG +1232B ; [.4F17.0020.0002] # CUNEIFORM SIGN UR2 +1232C ; [.4F18.0020.0002] # CUNEIFORM SIGN UR2 TIMES A PLUS HA +1232D ; [.4F19.0020.0002] # CUNEIFORM SIGN UR2 TIMES A PLUS NA +1232E ; [.4F1A.0020.0002] # CUNEIFORM SIGN UR2 TIMES AL +1232F ; [.4F1B.0020.0002] # CUNEIFORM SIGN UR2 TIMES HA +12330 ; [.4F1C.0020.0002] # CUNEIFORM SIGN UR2 TIMES NUN +12331 ; [.4F1D.0020.0002] # CUNEIFORM SIGN UR2 TIMES U2 +12332 ; [.4F1E.0020.0002] # CUNEIFORM SIGN UR2 TIMES U2 PLUS ASH +12333 ; [.4F1F.0020.0002] # CUNEIFORM SIGN UR2 TIMES U2 PLUS BI +12334 ; [.4F20.0020.0002] # CUNEIFORM SIGN UR4 +12335 ; [.4F21.0020.0002] # CUNEIFORM SIGN URI +12336 ; [.4F22.0020.0002] # CUNEIFORM SIGN URI3 +12337 ; [.4F23.0020.0002] # CUNEIFORM SIGN URU +12338 ; [.4F24.0020.0002] # CUNEIFORM SIGN URU TIMES A +12339 ; [.4F25.0020.0002] # CUNEIFORM SIGN URU TIMES ASHGAB +1233A ; [.4F26.0020.0002] # CUNEIFORM SIGN URU TIMES BAR +1233B ; [.4F27.0020.0002] # CUNEIFORM SIGN URU TIMES DUN +1233C ; [.4F28.0020.0002] # CUNEIFORM SIGN URU TIMES GA +1233D ; [.4F29.0020.0002] # CUNEIFORM SIGN URU TIMES GAL +1233E ; [.4F2A.0020.0002] # CUNEIFORM SIGN URU TIMES GAN2 TENU +1233F ; [.4F2B.0020.0002] # CUNEIFORM SIGN URU TIMES GAR +12340 ; [.4F2C.0020.0002] # CUNEIFORM SIGN URU TIMES GU +12341 ; [.4F2D.0020.0002] # CUNEIFORM SIGN URU TIMES HA +12342 ; [.4F2E.0020.0002] # CUNEIFORM SIGN URU TIMES IGI +12343 ; [.4F2F.0020.0002] # CUNEIFORM SIGN URU TIMES IM +12344 ; [.4F30.0020.0002] # CUNEIFORM SIGN URU TIMES ISH +12345 ; [.4F31.0020.0002] # CUNEIFORM SIGN URU TIMES KI +12346 ; [.4F32.0020.0002] # CUNEIFORM SIGN URU TIMES LUM +12347 ; [.4F33.0020.0002] # CUNEIFORM SIGN URU TIMES MIN +12348 ; [.4F34.0020.0002] # CUNEIFORM SIGN URU TIMES PA +12349 ; [.4F35.0020.0002] # CUNEIFORM SIGN URU TIMES SHE +1234A ; [.4F36.0020.0002] # CUNEIFORM SIGN URU TIMES SIG4 +1234B ; [.4F37.0020.0002] # CUNEIFORM SIGN URU TIMES TU +1234C ; [.4F38.0020.0002] # CUNEIFORM SIGN URU TIMES U PLUS GUD +1234D ; [.4F39.0020.0002] # CUNEIFORM SIGN URU TIMES UD +1234E ; [.4F3A.0020.0002] # CUNEIFORM SIGN URU TIMES URUDA +1234F ; [.4F3B.0020.0002] # CUNEIFORM SIGN URUDA +12350 ; [.4F3C.0020.0002] # CUNEIFORM SIGN URUDA TIMES U +12351 ; [.4F3D.0020.0002] # CUNEIFORM SIGN USH +12352 ; [.4F3E.0020.0002] # CUNEIFORM SIGN USH TIMES A +12353 ; [.4F3F.0020.0002] # CUNEIFORM SIGN USH TIMES KU +12354 ; [.4F40.0020.0002] # CUNEIFORM SIGN USH TIMES KUR +12355 ; [.4F41.0020.0002] # CUNEIFORM SIGN USH TIMES TAK4 +12356 ; [.4F42.0020.0002] # CUNEIFORM SIGN USHX +12357 ; [.4F43.0020.0002] # CUNEIFORM SIGN USH2 +12358 ; [.4F44.0020.0002] # CUNEIFORM SIGN USHUMX +12359 ; [.4F45.0020.0002] # CUNEIFORM SIGN UTUKI +1235A ; [.4F46.0020.0002] # CUNEIFORM SIGN UZ3 +1235B ; [.4F47.0020.0002] # CUNEIFORM SIGN UZ3 TIMES KASKAL +1235C ; [.4F48.0020.0002] # CUNEIFORM SIGN UZU +1235D ; [.4F49.0020.0002] # CUNEIFORM SIGN ZA +1235E ; [.4F4A.0020.0002] # CUNEIFORM SIGN ZA TENU +1235F ; [.4F4B.0020.0002] # CUNEIFORM SIGN ZA SQUARED TIMES KUR +12360 ; [.4F4C.0020.0002] # CUNEIFORM SIGN ZAG +12361 ; [.4F4D.0020.0002] # CUNEIFORM SIGN ZAMX +12362 ; [.4F4E.0020.0002] # CUNEIFORM SIGN ZE2 +12363 ; [.4F4F.0020.0002] # CUNEIFORM SIGN ZI +12364 ; [.4F50.0020.0002] # CUNEIFORM SIGN ZI OVER ZI +12365 ; [.4F51.0020.0002] # CUNEIFORM SIGN ZI3 +12366 ; [.4F52.0020.0002] # CUNEIFORM SIGN ZIB +12367 ; [.4F53.0020.0002] # CUNEIFORM SIGN ZIB KABA TENU +12368 ; [.4F54.0020.0002] # CUNEIFORM SIGN ZIG +12369 ; [.4F55.0020.0002] # CUNEIFORM SIGN ZIZ2 +1236A ; [.4F56.0020.0002] # CUNEIFORM SIGN ZU +1236B ; [.4F57.0020.0002] # CUNEIFORM SIGN ZU5 +1236C ; [.4F58.0020.0002] # CUNEIFORM SIGN ZU5 TIMES A +1236D ; [.4F59.0020.0002] # CUNEIFORM SIGN ZUBUR +1236E ; [.4F5A.0020.0002] # CUNEIFORM SIGN ZUM +1236F ; [.4F5B.0020.0002] # CUNEIFORM SIGN KAP ELAMITE +12370 ; [.4F5C.0020.0002] # CUNEIFORM SIGN AB TIMES NUN +12371 ; [.4F5D.0020.0002] # CUNEIFORM SIGN AB2 TIMES A +12372 ; [.4F5E.0020.0002] # CUNEIFORM SIGN AMAR TIMES KUG +12373 ; [.4F5F.0020.0002] # CUNEIFORM SIGN DAG KISIM5 TIMES U2 PLUS MASH +12374 ; [.4F60.0020.0002] # CUNEIFORM SIGN DAG3 +12375 ; [.4F61.0020.0002] # CUNEIFORM SIGN DISH PLUS SHU +12376 ; [.4F62.0020.0002] # CUNEIFORM SIGN DUB TIMES SHE +12377 ; [.4F63.0020.0002] # CUNEIFORM SIGN EZEN TIMES GUD +12378 ; [.4F64.0020.0002] # CUNEIFORM SIGN EZEN TIMES SHE +12379 ; [.4F65.0020.0002] # CUNEIFORM SIGN GA2 TIMES AN PLUS KAK PLUS A +1237A ; [.4F66.0020.0002] # CUNEIFORM SIGN GA2 TIMES ASH2 +1237B ; [.4F67.0020.0002] # CUNEIFORM SIGN GE22 +1237C ; [.4F68.0020.0002] # CUNEIFORM SIGN GIG +1237D ; [.4F69.0020.0002] # CUNEIFORM SIGN HUSH +1237E ; [.4F6A.0020.0002] # CUNEIFORM SIGN KA TIMES ANSHE +1237F ; [.4F6B.0020.0002] # CUNEIFORM SIGN KA TIMES ASH3 +12380 ; [.4F6C.0020.0002] # CUNEIFORM SIGN KA TIMES GISH +12381 ; [.4F6D.0020.0002] # CUNEIFORM SIGN KA TIMES GUD +12382 ; [.4F6E.0020.0002] # CUNEIFORM SIGN KA TIMES HI TIMES ASH2 +12383 ; [.4F6F.0020.0002] # CUNEIFORM SIGN KA TIMES LUM +12384 ; [.4F70.0020.0002] # CUNEIFORM SIGN KA TIMES PA +12385 ; [.4F71.0020.0002] # CUNEIFORM SIGN KA TIMES SHUL +12386 ; [.4F72.0020.0002] # CUNEIFORM SIGN KA TIMES TU +12387 ; [.4F73.0020.0002] # CUNEIFORM SIGN KA TIMES UR2 +12388 ; [.4F74.0020.0002] # CUNEIFORM SIGN LAGAB TIMES GI +12389 ; [.4F75.0020.0002] # CUNEIFORM SIGN LU2 SHESHIG TIMES BAD +1238A ; [.4F76.0020.0002] # CUNEIFORM SIGN LU2 TIMES ESH2 PLUS LAL +1238B ; [.4F77.0020.0002] # CUNEIFORM SIGN LU2 TIMES SHU +1238C ; [.4F78.0020.0002] # CUNEIFORM SIGN MESH +1238D ; [.4F79.0020.0002] # CUNEIFORM SIGN MUSH3 TIMES ZA +1238E ; [.4F7A.0020.0002] # CUNEIFORM SIGN NA4 +1238F ; [.4F7B.0020.0002] # CUNEIFORM SIGN NIN +12390 ; [.4F7C.0020.0002] # CUNEIFORM SIGN NIN9 +12391 ; [.4F7D.0020.0002] # CUNEIFORM SIGN NINDA2 TIMES BAL +12392 ; [.4F7E.0020.0002] # CUNEIFORM SIGN NINDA2 TIMES GI +12393 ; [.4F7F.0020.0002] # CUNEIFORM SIGN NU11 ROTATED NINETY DEGREES +12394 ; [.4F80.0020.0002] # CUNEIFORM SIGN PESH2 ASTERISK +12395 ; [.4F81.0020.0002] # CUNEIFORM SIGN PIR2 +12396 ; [.4F82.0020.0002] # CUNEIFORM SIGN SAG TIMES IGI GUNU +12397 ; [.4F83.0020.0002] # CUNEIFORM SIGN TI2 +12398 ; [.4F84.0020.0002] # CUNEIFORM SIGN UM TIMES ME +12399 ; [.4F85.0020.0002] # CUNEIFORM SIGN U U +12480 ; [.4F86.0020.0002] # CUNEIFORM SIGN AB TIMES NUN TENU +12481 ; [.4F87.0020.0002] # CUNEIFORM SIGN AB TIMES SHU2 +12482 ; [.4F88.0020.0002] # CUNEIFORM SIGN AD TIMES ESH2 +12483 ; [.4F89.0020.0002] # CUNEIFORM SIGN BAD TIMES DISH TENU +12484 ; [.4F8A.0020.0002] # CUNEIFORM SIGN BAHAR2 TIMES AB2 +12485 ; [.4F8B.0020.0002] # CUNEIFORM SIGN BAHAR2 TIMES NI +12486 ; [.4F8C.0020.0002] # CUNEIFORM SIGN BAHAR2 TIMES ZA +12487 ; [.4F8D.0020.0002] # CUNEIFORM SIGN BU OVER BU TIMES NA2 +12488 ; [.4F8E.0020.0002] # CUNEIFORM SIGN DA TIMES TAK4 +12489 ; [.4F8F.0020.0002] # CUNEIFORM SIGN DAG TIMES KUR +1248A ; [.4F90.0020.0002] # CUNEIFORM SIGN DIM TIMES IGI +1248B ; [.4F91.0020.0002] # CUNEIFORM SIGN DIM TIMES U U U +1248C ; [.4F92.0020.0002] # CUNEIFORM SIGN DIM2 TIMES UD +1248D ; [.4F93.0020.0002] # CUNEIFORM SIGN DUG TIMES ANSHE +1248E ; [.4F94.0020.0002] # CUNEIFORM SIGN DUG TIMES ASH +1248F ; [.4F95.0020.0002] # CUNEIFORM SIGN DUG TIMES ASH AT LEFT +12490 ; [.4F96.0020.0002] # CUNEIFORM SIGN DUG TIMES DIN +12491 ; [.4F97.0020.0002] # CUNEIFORM SIGN DUG TIMES DUN +12492 ; [.4F98.0020.0002] # CUNEIFORM SIGN DUG TIMES ERIN2 +12493 ; [.4F99.0020.0002] # CUNEIFORM SIGN DUG TIMES GA +12494 ; [.4F9A.0020.0002] # CUNEIFORM SIGN DUG TIMES GI +12495 ; [.4F9B.0020.0002] # CUNEIFORM SIGN DUG TIMES GIR2 GUNU +12496 ; [.4F9C.0020.0002] # CUNEIFORM SIGN DUG TIMES GISH +12497 ; [.4F9D.0020.0002] # CUNEIFORM SIGN DUG TIMES HA +12498 ; [.4F9E.0020.0002] # CUNEIFORM SIGN DUG TIMES HI +12499 ; [.4F9F.0020.0002] # CUNEIFORM SIGN DUG TIMES IGI GUNU +1249A ; [.4FA0.0020.0002] # CUNEIFORM SIGN DUG TIMES KASKAL +1249B ; [.4FA1.0020.0002] # CUNEIFORM SIGN DUG TIMES KUR +1249C ; [.4FA2.0020.0002] # CUNEIFORM SIGN DUG TIMES KUSHU2 +1249D ; [.4FA3.0020.0002] # CUNEIFORM SIGN DUG TIMES KUSHU2 PLUS KASKAL +1249E ; [.4FA4.0020.0002] # CUNEIFORM SIGN DUG TIMES LAK-020 +1249F ; [.4FA5.0020.0002] # CUNEIFORM SIGN DUG TIMES LAM +124A0 ; [.4FA6.0020.0002] # CUNEIFORM SIGN DUG TIMES LAM TIMES KUR +124A1 ; [.4FA7.0020.0002] # CUNEIFORM SIGN DUG TIMES LUH PLUS GISH +124A2 ; [.4FA8.0020.0002] # CUNEIFORM SIGN DUG TIMES MASH +124A3 ; [.4FA9.0020.0002] # CUNEIFORM SIGN DUG TIMES MES +124A4 ; [.4FAA.0020.0002] # CUNEIFORM SIGN DUG TIMES MI +124A5 ; [.4FAB.0020.0002] # CUNEIFORM SIGN DUG TIMES NI +124A6 ; [.4FAC.0020.0002] # CUNEIFORM SIGN DUG TIMES PI +124A7 ; [.4FAD.0020.0002] # CUNEIFORM SIGN DUG TIMES SHE +124A8 ; [.4FAE.0020.0002] # CUNEIFORM SIGN DUG TIMES SI GUNU +124A9 ; [.4FAF.0020.0002] # CUNEIFORM SIGN E2 TIMES KUR +124AA ; [.4FB0.0020.0002] # CUNEIFORM SIGN E2 TIMES PAP +124AB ; [.4FB1.0020.0002] # CUNEIFORM SIGN ERIN2 X +124AC ; [.4FB2.0020.0002] # CUNEIFORM SIGN ESH2 CROSSING ESH2 +124AD ; [.4FB3.0020.0002] # CUNEIFORM SIGN EZEN SHESHIG TIMES ASH +124AE ; [.4FB4.0020.0002] # CUNEIFORM SIGN EZEN SHESHIG TIMES HI +124AF ; [.4FB5.0020.0002] # CUNEIFORM SIGN EZEN SHESHIG TIMES IGI GUNU +124B0 ; [.4FB6.0020.0002] # CUNEIFORM SIGN EZEN SHESHIG TIMES LA +124B1 ; [.4FB7.0020.0002] # CUNEIFORM SIGN EZEN SHESHIG TIMES LAL +124B2 ; [.4FB8.0020.0002] # CUNEIFORM SIGN EZEN SHESHIG TIMES ME +124B3 ; [.4FB9.0020.0002] # CUNEIFORM SIGN EZEN SHESHIG TIMES MES +124B4 ; [.4FBA.0020.0002] # CUNEIFORM SIGN EZEN SHESHIG TIMES SU +124B5 ; [.4FBB.0020.0002] # CUNEIFORM SIGN EZEN TIMES SU +124B6 ; [.4FBC.0020.0002] # CUNEIFORM SIGN GA2 TIMES BAHAR2 +124B7 ; [.4FBD.0020.0002] # CUNEIFORM SIGN GA2 TIMES DIM GUNU +124B8 ; [.4FBE.0020.0002] # CUNEIFORM SIGN GA2 TIMES DUG TIMES IGI GUNU +124B9 ; [.4FBF.0020.0002] # CUNEIFORM SIGN GA2 TIMES DUG TIMES KASKAL +124BA ; [.4FC0.0020.0002] # CUNEIFORM SIGN GA2 TIMES EREN +124BB ; [.4FC1.0020.0002] # CUNEIFORM SIGN GA2 TIMES GA +124BC ; [.4FC2.0020.0002] # CUNEIFORM SIGN GA2 TIMES GAR PLUS DI +124BD ; [.4FC3.0020.0002] # CUNEIFORM SIGN GA2 TIMES GAR PLUS NE +124BE ; [.4FC4.0020.0002] # CUNEIFORM SIGN GA2 TIMES HA PLUS A +124BF ; [.4FC5.0020.0002] # CUNEIFORM SIGN GA2 TIMES KUSHU2 PLUS KASKAL +124C0 ; [.4FC6.0020.0002] # CUNEIFORM SIGN GA2 TIMES LAM +124C1 ; [.4FC7.0020.0002] # CUNEIFORM SIGN GA2 TIMES LAM TIMES KUR +124C2 ; [.4FC8.0020.0002] # CUNEIFORM SIGN GA2 TIMES LUH +124C3 ; [.4FC9.0020.0002] # CUNEIFORM SIGN GA2 TIMES MUSH +124C4 ; [.4FCA.0020.0002] # CUNEIFORM SIGN GA2 TIMES NE +124C5 ; [.4FCB.0020.0002] # CUNEIFORM SIGN GA2 TIMES NE PLUS E2 +124C6 ; [.4FCC.0020.0002] # CUNEIFORM SIGN GA2 TIMES NE PLUS GI +124C7 ; [.4FCD.0020.0002] # CUNEIFORM SIGN GA2 TIMES SHIM +124C8 ; [.4FCE.0020.0002] # CUNEIFORM SIGN GA2 TIMES ZIZ2 +124C9 ; [.4FCF.0020.0002] # CUNEIFORM SIGN GABA ROTATED NINETY DEGREES +124CA ; [.4FD0.0020.0002] # CUNEIFORM SIGN GESHTIN TIMES U +124CB ; [.4FD1.0020.0002] # CUNEIFORM SIGN GISH TIMES GISH CROSSING GISH +124CC ; [.4FD2.0020.0002] # CUNEIFORM SIGN GU2 TIMES IGI GUNU +124CD ; [.4FD3.0020.0002] # CUNEIFORM SIGN GUD PLUS GISH TIMES TAK4 +124CE ; [.4FD4.0020.0002] # CUNEIFORM SIGN HA TENU GUNU +124CF ; [.4FD5.0020.0002] # CUNEIFORM SIGN HI TIMES ASH OVER HI TIMES ASH +124D0 ; [.4FD6.0020.0002] # CUNEIFORM SIGN KA TIMES BU +124D1 ; [.4FD7.0020.0002] # CUNEIFORM SIGN KA TIMES KA +124D2 ; [.4FD8.0020.0002] # CUNEIFORM SIGN KA TIMES U U U +124D3 ; [.4FD9.0020.0002] # CUNEIFORM SIGN KA TIMES UR +124D4 ; [.4FDA.0020.0002] # CUNEIFORM SIGN LAGAB TIMES ZU OVER ZU +124D5 ; [.4FDB.0020.0002] # CUNEIFORM SIGN LAK-003 +124D6 ; [.4FDC.0020.0002] # CUNEIFORM SIGN LAK-021 +124D7 ; [.4FDD.0020.0002] # CUNEIFORM SIGN LAK-025 +124D8 ; [.4FDE.0020.0002] # CUNEIFORM SIGN LAK-030 +124D9 ; [.4FDF.0020.0002] # CUNEIFORM SIGN LAK-050 +124DA ; [.4FE0.0020.0002] # CUNEIFORM SIGN LAK-051 +124DB ; [.4FE1.0020.0002] # CUNEIFORM SIGN LAK-062 +124DC ; [.4FE2.0020.0002] # CUNEIFORM SIGN LAK-079 OVER LAK-079 GUNU +124DD ; [.4FE3.0020.0002] # CUNEIFORM SIGN LAK-080 +124DE ; [.4FE4.0020.0002] # CUNEIFORM SIGN LAK-081 OVER LAK-081 +124DF ; [.4FE5.0020.0002] # CUNEIFORM SIGN LAK-092 +124E0 ; [.4FE6.0020.0002] # CUNEIFORM SIGN LAK-130 +124E1 ; [.4FE7.0020.0002] # CUNEIFORM SIGN LAK-142 +124E2 ; [.4FE8.0020.0002] # CUNEIFORM SIGN LAK-210 +124E3 ; [.4FE9.0020.0002] # CUNEIFORM SIGN LAK-219 +124E4 ; [.4FEA.0020.0002] # CUNEIFORM SIGN LAK-220 +124E5 ; [.4FEB.0020.0002] # CUNEIFORM SIGN LAK-225 +124E6 ; [.4FEC.0020.0002] # CUNEIFORM SIGN LAK-228 +124E7 ; [.4FED.0020.0002] # CUNEIFORM SIGN LAK-238 +124E8 ; [.4FEE.0020.0002] # CUNEIFORM SIGN LAK-265 +124E9 ; [.4FEF.0020.0002] # CUNEIFORM SIGN LAK-266 +124EA ; [.4FF0.0020.0002] # CUNEIFORM SIGN LAK-343 +124EB ; [.4FF1.0020.0002] # CUNEIFORM SIGN LAK-347 +124EC ; [.4FF2.0020.0002] # CUNEIFORM SIGN LAK-348 +124ED ; [.4FF3.0020.0002] # CUNEIFORM SIGN LAK-383 +124EE ; [.4FF4.0020.0002] # CUNEIFORM SIGN LAK-384 +124EF ; [.4FF5.0020.0002] # CUNEIFORM SIGN LAK-390 +124F0 ; [.4FF6.0020.0002] # CUNEIFORM SIGN LAK-441 +124F1 ; [.4FF7.0020.0002] # CUNEIFORM SIGN LAK-449 +124F2 ; [.4FF8.0020.0002] # CUNEIFORM SIGN LAK-449 TIMES GU +124F3 ; [.4FF9.0020.0002] # CUNEIFORM SIGN LAK-449 TIMES IGI +124F4 ; [.4FFA.0020.0002] # CUNEIFORM SIGN LAK-449 TIMES PAP PLUS LU3 +124F5 ; [.4FFB.0020.0002] # CUNEIFORM SIGN LAK-449 TIMES PAP PLUS PAP PLUS LU3 +124F6 ; [.4FFC.0020.0002] # CUNEIFORM SIGN LAK-449 TIMES U2 PLUS BA +124F7 ; [.4FFD.0020.0002] # CUNEIFORM SIGN LAK-450 +124F8 ; [.4FFE.0020.0002] # CUNEIFORM SIGN LAK-457 +124F9 ; [.4FFF.0020.0002] # CUNEIFORM SIGN LAK-470 +124FA ; [.5000.0020.0002] # CUNEIFORM SIGN LAK-483 +124FB ; [.5001.0020.0002] # CUNEIFORM SIGN LAK-490 +124FC ; [.5002.0020.0002] # CUNEIFORM SIGN LAK-492 +124FD ; [.5003.0020.0002] # CUNEIFORM SIGN LAK-493 +124FE ; [.5004.0020.0002] # CUNEIFORM SIGN LAK-495 +124FF ; [.5005.0020.0002] # CUNEIFORM SIGN LAK-550 +12500 ; [.5006.0020.0002] # CUNEIFORM SIGN LAK-608 +12501 ; [.5007.0020.0002] # CUNEIFORM SIGN LAK-617 +12502 ; [.5008.0020.0002] # CUNEIFORM SIGN LAK-617 TIMES ASH +12503 ; [.5009.0020.0002] # CUNEIFORM SIGN LAK-617 TIMES BAD +12504 ; [.500A.0020.0002] # CUNEIFORM SIGN LAK-617 TIMES DUN3 GUNU GUNU +12505 ; [.500B.0020.0002] # CUNEIFORM SIGN LAK-617 TIMES KU3 +12506 ; [.500C.0020.0002] # CUNEIFORM SIGN LAK-617 TIMES LA +12507 ; [.500D.0020.0002] # CUNEIFORM SIGN LAK-617 TIMES TAR +12508 ; [.500E.0020.0002] # CUNEIFORM SIGN LAK-617 TIMES TE +12509 ; [.500F.0020.0002] # CUNEIFORM SIGN LAK-617 TIMES U2 +1250A ; [.5010.0020.0002] # CUNEIFORM SIGN LAK-617 TIMES UD +1250B ; [.5011.0020.0002] # CUNEIFORM SIGN LAK-617 TIMES URUDA +1250C ; [.5012.0020.0002] # CUNEIFORM SIGN LAK-636 +1250D ; [.5013.0020.0002] # CUNEIFORM SIGN LAK-648 +1250E ; [.5014.0020.0002] # CUNEIFORM SIGN LAK-648 TIMES DUB +1250F ; [.5015.0020.0002] # CUNEIFORM SIGN LAK-648 TIMES GA +12510 ; [.5016.0020.0002] # CUNEIFORM SIGN LAK-648 TIMES IGI +12511 ; [.5017.0020.0002] # CUNEIFORM SIGN LAK-648 TIMES IGI GUNU +12512 ; [.5018.0020.0002] # CUNEIFORM SIGN LAK-648 TIMES NI +12513 ; [.5019.0020.0002] # CUNEIFORM SIGN LAK-648 TIMES PAP PLUS PAP PLUS LU3 +12514 ; [.501A.0020.0002] # CUNEIFORM SIGN LAK-648 TIMES SHESH PLUS KI +12515 ; [.501B.0020.0002] # CUNEIFORM SIGN LAK-648 TIMES UD +12516 ; [.501C.0020.0002] # CUNEIFORM SIGN LAK-648 TIMES URUDA +12517 ; [.501D.0020.0002] # CUNEIFORM SIGN LAK-724 +12518 ; [.501E.0020.0002] # CUNEIFORM SIGN LAK-749 +12519 ; [.501F.0020.0002] # CUNEIFORM SIGN LU2 GUNU TIMES ASH +1251A ; [.5020.0020.0002] # CUNEIFORM SIGN LU2 TIMES DISH +1251B ; [.5021.0020.0002] # CUNEIFORM SIGN LU2 TIMES HAL +1251C ; [.5022.0020.0002] # CUNEIFORM SIGN LU2 TIMES PAP +1251D ; [.5023.0020.0002] # CUNEIFORM SIGN LU2 TIMES PAP PLUS PAP PLUS LU3 +1251E ; [.5024.0020.0002] # CUNEIFORM SIGN LU2 TIMES TAK4 +1251F ; [.5025.0020.0002] # CUNEIFORM SIGN MI PLUS ZA7 +12520 ; [.5026.0020.0002] # CUNEIFORM SIGN MUSH OVER MUSH TIMES GA +12521 ; [.5027.0020.0002] # CUNEIFORM SIGN MUSH OVER MUSH TIMES KAK +12522 ; [.5028.0020.0002] # CUNEIFORM SIGN NINDA2 TIMES DIM GUNU +12523 ; [.5029.0020.0002] # CUNEIFORM SIGN NINDA2 TIMES GISH +12524 ; [.502A.0020.0002] # CUNEIFORM SIGN NINDA2 TIMES GUL +12525 ; [.502B.0020.0002] # CUNEIFORM SIGN NINDA2 TIMES HI +12526 ; [.502C.0020.0002] # CUNEIFORM SIGN NINDA2 TIMES KESH2 +12527 ; [.502D.0020.0002] # CUNEIFORM SIGN NINDA2 TIMES LAK-050 +12528 ; [.502E.0020.0002] # CUNEIFORM SIGN NINDA2 TIMES MASH +12529 ; [.502F.0020.0002] # CUNEIFORM SIGN NINDA2 TIMES PAP PLUS PAP +1252A ; [.5030.0020.0002] # CUNEIFORM SIGN NINDA2 TIMES U +1252B ; [.5031.0020.0002] # CUNEIFORM SIGN NINDA2 TIMES U PLUS U +1252C ; [.5032.0020.0002] # CUNEIFORM SIGN NINDA2 TIMES URUDA +1252D ; [.5033.0020.0002] # CUNEIFORM SIGN SAG GUNU TIMES HA +1252E ; [.5034.0020.0002] # CUNEIFORM SIGN SAG TIMES EN +1252F ; [.5035.0020.0002] # CUNEIFORM SIGN SAG TIMES SHE AT LEFT +12530 ; [.5036.0020.0002] # CUNEIFORM SIGN SAG TIMES TAK4 +12531 ; [.5037.0020.0002] # CUNEIFORM SIGN SHA6 TENU +12532 ; [.5038.0020.0002] # CUNEIFORM SIGN SHE OVER SHE +12533 ; [.5039.0020.0002] # CUNEIFORM SIGN SHE PLUS HUB2 +12534 ; [.503A.0020.0002] # CUNEIFORM SIGN SHE PLUS NAM2 +12535 ; [.503B.0020.0002] # CUNEIFORM SIGN SHE PLUS SAR +12536 ; [.503C.0020.0002] # CUNEIFORM SIGN SHU2 PLUS DUG TIMES NI +12537 ; [.503D.0020.0002] # CUNEIFORM SIGN SHU2 PLUS E2 TIMES AN +12538 ; [.503E.0020.0002] # CUNEIFORM SIGN SI TIMES TAK4 +12539 ; [.503F.0020.0002] # CUNEIFORM SIGN TAK4 PLUS SAG +1253A ; [.5040.0020.0002] # CUNEIFORM SIGN TUM TIMES GAN2 TENU +1253B ; [.5041.0020.0002] # CUNEIFORM SIGN TUM TIMES THREE DISH +1253C ; [.5042.0020.0002] # CUNEIFORM SIGN UR2 INVERTED +1253D ; [.5043.0020.0002] # CUNEIFORM SIGN UR2 TIMES UD +1253E ; [.5044.0020.0002] # CUNEIFORM SIGN URU TIMES DARA3 +1253F ; [.5045.0020.0002] # CUNEIFORM SIGN URU TIMES LAK-668 +12540 ; [.5046.0020.0002] # CUNEIFORM SIGN URU TIMES LU3 +12541 ; [.5047.0020.0002] # CUNEIFORM SIGN ZA7 +12542 ; [.5048.0020.0002] # CUNEIFORM SIGN ZU OVER ZU PLUS SAR +12543 ; [.5049.0020.0002] # CUNEIFORM SIGN ZU5 TIMES THREE DISH TENU +13000 ; [.504A.0020.0002] # EGYPTIAN HIEROGLYPH A001 +13001 ; [.504B.0020.0002] # EGYPTIAN HIEROGLYPH A002 +13002 ; [.504C.0020.0002] # EGYPTIAN HIEROGLYPH A003 +13003 ; [.504D.0020.0002] # EGYPTIAN HIEROGLYPH A004 +13004 ; [.504E.0020.0002] # EGYPTIAN HIEROGLYPH A005 +13005 ; [.504F.0020.0002] # EGYPTIAN HIEROGLYPH A005A +13006 ; [.5050.0020.0002] # EGYPTIAN HIEROGLYPH A006 +13007 ; [.5051.0020.0002] # EGYPTIAN HIEROGLYPH A006A +13008 ; [.5052.0020.0002] # EGYPTIAN HIEROGLYPH A006B +13009 ; [.5053.0020.0002] # EGYPTIAN HIEROGLYPH A007 +1300A ; [.5054.0020.0002] # EGYPTIAN HIEROGLYPH A008 +1300B ; [.5055.0020.0002] # EGYPTIAN HIEROGLYPH A009 +1300C ; [.5056.0020.0002] # EGYPTIAN HIEROGLYPH A010 +1300D ; [.5057.0020.0002] # EGYPTIAN HIEROGLYPH A011 +1300E ; [.5058.0020.0002] # EGYPTIAN HIEROGLYPH A012 +1300F ; [.5059.0020.0002] # EGYPTIAN HIEROGLYPH A013 +13010 ; [.505A.0020.0002] # EGYPTIAN HIEROGLYPH A014 +13011 ; [.505B.0020.0002] # EGYPTIAN HIEROGLYPH A014A +13012 ; [.505C.0020.0002] # EGYPTIAN HIEROGLYPH A015 +13013 ; [.505D.0020.0002] # EGYPTIAN HIEROGLYPH A016 +13014 ; [.505E.0020.0002] # EGYPTIAN HIEROGLYPH A017 +13015 ; [.505F.0020.0002] # EGYPTIAN HIEROGLYPH A017A +13016 ; [.5060.0020.0002] # EGYPTIAN HIEROGLYPH A018 +13017 ; [.5061.0020.0002] # EGYPTIAN HIEROGLYPH A019 +13018 ; [.5062.0020.0002] # EGYPTIAN HIEROGLYPH A020 +13019 ; [.5063.0020.0002] # EGYPTIAN HIEROGLYPH A021 +1301A ; [.5064.0020.0002] # EGYPTIAN HIEROGLYPH A022 +1301B ; [.5065.0020.0002] # EGYPTIAN HIEROGLYPH A023 +1301C ; [.5066.0020.0002] # EGYPTIAN HIEROGLYPH A024 +1301D ; [.5067.0020.0002] # EGYPTIAN HIEROGLYPH A025 +1301E ; [.5068.0020.0002] # EGYPTIAN HIEROGLYPH A026 +1301F ; [.5069.0020.0002] # EGYPTIAN HIEROGLYPH A027 +13020 ; [.506A.0020.0002] # EGYPTIAN HIEROGLYPH A028 +13021 ; [.506B.0020.0002] # EGYPTIAN HIEROGLYPH A029 +13022 ; [.506C.0020.0002] # EGYPTIAN HIEROGLYPH A030 +13023 ; [.506D.0020.0002] # EGYPTIAN HIEROGLYPH A031 +13024 ; [.506E.0020.0002] # EGYPTIAN HIEROGLYPH A032 +13025 ; [.506F.0020.0002] # EGYPTIAN HIEROGLYPH A032A +13026 ; [.5070.0020.0002] # EGYPTIAN HIEROGLYPH A033 +13027 ; [.5071.0020.0002] # EGYPTIAN HIEROGLYPH A034 +13028 ; [.5072.0020.0002] # EGYPTIAN HIEROGLYPH A035 +13029 ; [.5073.0020.0002] # EGYPTIAN HIEROGLYPH A036 +1302A ; [.5074.0020.0002] # EGYPTIAN HIEROGLYPH A037 +1302B ; [.5075.0020.0002] # EGYPTIAN HIEROGLYPH A038 +1302C ; [.5076.0020.0002] # EGYPTIAN HIEROGLYPH A039 +1302D ; [.5077.0020.0002] # EGYPTIAN HIEROGLYPH A040 +1302E ; [.5078.0020.0002] # EGYPTIAN HIEROGLYPH A040A +1302F ; [.5079.0020.0002] # EGYPTIAN HIEROGLYPH A041 +13030 ; [.507A.0020.0002] # EGYPTIAN HIEROGLYPH A042 +13031 ; [.507B.0020.0002] # EGYPTIAN HIEROGLYPH A042A +13032 ; [.507C.0020.0002] # EGYPTIAN HIEROGLYPH A043 +13033 ; [.507D.0020.0002] # EGYPTIAN HIEROGLYPH A043A +13034 ; [.507E.0020.0002] # EGYPTIAN HIEROGLYPH A044 +13035 ; [.507F.0020.0002] # EGYPTIAN HIEROGLYPH A045 +13036 ; [.5080.0020.0002] # EGYPTIAN HIEROGLYPH A045A +13037 ; [.5081.0020.0002] # EGYPTIAN HIEROGLYPH A046 +13038 ; [.5082.0020.0002] # EGYPTIAN HIEROGLYPH A047 +13039 ; [.5083.0020.0002] # EGYPTIAN HIEROGLYPH A048 +1303A ; [.5084.0020.0002] # EGYPTIAN HIEROGLYPH A049 +1303B ; [.5085.0020.0002] # EGYPTIAN HIEROGLYPH A050 +1303C ; [.5086.0020.0002] # EGYPTIAN HIEROGLYPH A051 +1303D ; [.5087.0020.0002] # EGYPTIAN HIEROGLYPH A052 +1303E ; [.5088.0020.0002] # EGYPTIAN HIEROGLYPH A053 +1303F ; [.5089.0020.0002] # EGYPTIAN HIEROGLYPH A054 +13040 ; [.508A.0020.0002] # EGYPTIAN HIEROGLYPH A055 +13041 ; [.508B.0020.0002] # EGYPTIAN HIEROGLYPH A056 +13042 ; [.508C.0020.0002] # EGYPTIAN HIEROGLYPH A057 +13043 ; [.508D.0020.0002] # EGYPTIAN HIEROGLYPH A058 +13044 ; [.508E.0020.0002] # EGYPTIAN HIEROGLYPH A059 +13045 ; [.508F.0020.0002] # EGYPTIAN HIEROGLYPH A060 +13046 ; [.5090.0020.0002] # EGYPTIAN HIEROGLYPH A061 +13047 ; [.5091.0020.0002] # EGYPTIAN HIEROGLYPH A062 +13048 ; [.5092.0020.0002] # EGYPTIAN HIEROGLYPH A063 +13049 ; [.5093.0020.0002] # EGYPTIAN HIEROGLYPH A064 +1304A ; [.5094.0020.0002] # EGYPTIAN HIEROGLYPH A065 +1304B ; [.5095.0020.0002] # EGYPTIAN HIEROGLYPH A066 +1304C ; [.5096.0020.0002] # EGYPTIAN HIEROGLYPH A067 +1304D ; [.5097.0020.0002] # EGYPTIAN HIEROGLYPH A068 +1304E ; [.5098.0020.0002] # EGYPTIAN HIEROGLYPH A069 +1304F ; [.5099.0020.0002] # EGYPTIAN HIEROGLYPH A070 +13050 ; [.509A.0020.0002] # EGYPTIAN HIEROGLYPH B001 +13051 ; [.509B.0020.0002] # EGYPTIAN HIEROGLYPH B002 +13052 ; [.509C.0020.0002] # EGYPTIAN HIEROGLYPH B003 +13053 ; [.509D.0020.0002] # EGYPTIAN HIEROGLYPH B004 +13054 ; [.509E.0020.0002] # EGYPTIAN HIEROGLYPH B005 +13055 ; [.509F.0020.0002] # EGYPTIAN HIEROGLYPH B005A +13056 ; [.50A0.0020.0002] # EGYPTIAN HIEROGLYPH B006 +13057 ; [.50A1.0020.0002] # EGYPTIAN HIEROGLYPH B007 +13058 ; [.50A2.0020.0002] # EGYPTIAN HIEROGLYPH B008 +13059 ; [.50A3.0020.0002] # EGYPTIAN HIEROGLYPH B009 +1305A ; [.50A4.0020.0002] # EGYPTIAN HIEROGLYPH C001 +1305B ; [.50A5.0020.0002] # EGYPTIAN HIEROGLYPH C002 +1305C ; [.50A6.0020.0002] # EGYPTIAN HIEROGLYPH C002A +1305D ; [.50A7.0020.0002] # EGYPTIAN HIEROGLYPH C002B +1305E ; [.50A8.0020.0002] # EGYPTIAN HIEROGLYPH C002C +1305F ; [.50A9.0020.0002] # EGYPTIAN HIEROGLYPH C003 +13060 ; [.50AA.0020.0002] # EGYPTIAN HIEROGLYPH C004 +13061 ; [.50AB.0020.0002] # EGYPTIAN HIEROGLYPH C005 +13062 ; [.50AC.0020.0002] # EGYPTIAN HIEROGLYPH C006 +13063 ; [.50AD.0020.0002] # EGYPTIAN HIEROGLYPH C007 +13064 ; [.50AE.0020.0002] # EGYPTIAN HIEROGLYPH C008 +13065 ; [.50AF.0020.0002] # EGYPTIAN HIEROGLYPH C009 +13066 ; [.50B0.0020.0002] # EGYPTIAN HIEROGLYPH C010 +13067 ; [.50B1.0020.0002] # EGYPTIAN HIEROGLYPH C010A +13068 ; [.50B2.0020.0002] # EGYPTIAN HIEROGLYPH C011 +13069 ; [.50B3.0020.0002] # EGYPTIAN HIEROGLYPH C012 +1306A ; [.50B4.0020.0002] # EGYPTIAN HIEROGLYPH C013 +1306B ; [.50B5.0020.0002] # EGYPTIAN HIEROGLYPH C014 +1306C ; [.50B6.0020.0002] # EGYPTIAN HIEROGLYPH C015 +1306D ; [.50B7.0020.0002] # EGYPTIAN HIEROGLYPH C016 +1306E ; [.50B8.0020.0002] # EGYPTIAN HIEROGLYPH C017 +1306F ; [.50B9.0020.0002] # EGYPTIAN HIEROGLYPH C018 +13070 ; [.50BA.0020.0002] # EGYPTIAN HIEROGLYPH C019 +13071 ; [.50BB.0020.0002] # EGYPTIAN HIEROGLYPH C020 +13072 ; [.50BC.0020.0002] # EGYPTIAN HIEROGLYPH C021 +13073 ; [.50BD.0020.0002] # EGYPTIAN HIEROGLYPH C022 +13074 ; [.50BE.0020.0002] # EGYPTIAN HIEROGLYPH C023 +13075 ; [.50BF.0020.0002] # EGYPTIAN HIEROGLYPH C024 +13076 ; [.50C0.0020.0002] # EGYPTIAN HIEROGLYPH D001 +13077 ; [.50C1.0020.0002] # EGYPTIAN HIEROGLYPH D002 +13078 ; [.50C2.0020.0002] # EGYPTIAN HIEROGLYPH D003 +13079 ; [.50C3.0020.0002] # EGYPTIAN HIEROGLYPH D004 +1307A ; [.50C4.0020.0002] # EGYPTIAN HIEROGLYPH D005 +1307B ; [.50C5.0020.0002] # EGYPTIAN HIEROGLYPH D006 +1307C ; [.50C6.0020.0002] # EGYPTIAN HIEROGLYPH D007 +1307D ; [.50C7.0020.0002] # EGYPTIAN HIEROGLYPH D008 +1307E ; [.50C8.0020.0002] # EGYPTIAN HIEROGLYPH D008A +1307F ; [.50C9.0020.0002] # EGYPTIAN HIEROGLYPH D009 +13080 ; [.50CA.0020.0002] # EGYPTIAN HIEROGLYPH D010 +13081 ; [.50CB.0020.0002] # EGYPTIAN HIEROGLYPH D011 +13082 ; [.50CC.0020.0002] # EGYPTIAN HIEROGLYPH D012 +13083 ; [.50CD.0020.0002] # EGYPTIAN HIEROGLYPH D013 +13084 ; [.50CE.0020.0002] # EGYPTIAN HIEROGLYPH D014 +13085 ; [.50CF.0020.0002] # EGYPTIAN HIEROGLYPH D015 +13086 ; [.50D0.0020.0002] # EGYPTIAN HIEROGLYPH D016 +13087 ; [.50D1.0020.0002] # EGYPTIAN HIEROGLYPH D017 +13088 ; [.50D2.0020.0002] # EGYPTIAN HIEROGLYPH D018 +13089 ; [.50D3.0020.0002] # EGYPTIAN HIEROGLYPH D019 +1308A ; [.50D4.0020.0002] # EGYPTIAN HIEROGLYPH D020 +1308B ; [.50D5.0020.0002] # EGYPTIAN HIEROGLYPH D021 +1308C ; [.50D6.0020.0002] # EGYPTIAN HIEROGLYPH D022 +1308D ; [.50D7.0020.0002] # EGYPTIAN HIEROGLYPH D023 +1308E ; [.50D8.0020.0002] # EGYPTIAN HIEROGLYPH D024 +1308F ; [.50D9.0020.0002] # EGYPTIAN HIEROGLYPH D025 +13090 ; [.50DA.0020.0002] # EGYPTIAN HIEROGLYPH D026 +13091 ; [.50DB.0020.0002] # EGYPTIAN HIEROGLYPH D027 +13092 ; [.50DC.0020.0002] # EGYPTIAN HIEROGLYPH D027A +13093 ; [.50DD.0020.0002] # EGYPTIAN HIEROGLYPH D028 +13094 ; [.50DE.0020.0002] # EGYPTIAN HIEROGLYPH D029 +13095 ; [.50DF.0020.0002] # EGYPTIAN HIEROGLYPH D030 +13096 ; [.50E0.0020.0002] # EGYPTIAN HIEROGLYPH D031 +13097 ; [.50E1.0020.0002] # EGYPTIAN HIEROGLYPH D031A +13098 ; [.50E2.0020.0002] # EGYPTIAN HIEROGLYPH D032 +13099 ; [.50E3.0020.0002] # EGYPTIAN HIEROGLYPH D033 +1309A ; [.50E4.0020.0002] # EGYPTIAN HIEROGLYPH D034 +1309B ; [.50E5.0020.0002] # EGYPTIAN HIEROGLYPH D034A +1309C ; [.50E6.0020.0002] # EGYPTIAN HIEROGLYPH D035 +1309D ; [.50E7.0020.0002] # EGYPTIAN HIEROGLYPH D036 +1309E ; [.50E8.0020.0002] # EGYPTIAN HIEROGLYPH D037 +1309F ; [.50E9.0020.0002] # EGYPTIAN HIEROGLYPH D038 +130A0 ; [.50EA.0020.0002] # EGYPTIAN HIEROGLYPH D039 +130A1 ; [.50EB.0020.0002] # EGYPTIAN HIEROGLYPH D040 +130A2 ; [.50EC.0020.0002] # EGYPTIAN HIEROGLYPH D041 +130A3 ; [.50ED.0020.0002] # EGYPTIAN HIEROGLYPH D042 +130A4 ; [.50EE.0020.0002] # EGYPTIAN HIEROGLYPH D043 +130A5 ; [.50EF.0020.0002] # EGYPTIAN HIEROGLYPH D044 +130A6 ; [.50F0.0020.0002] # EGYPTIAN HIEROGLYPH D045 +130A7 ; [.50F1.0020.0002] # EGYPTIAN HIEROGLYPH D046 +130A8 ; [.50F2.0020.0002] # EGYPTIAN HIEROGLYPH D046A +130A9 ; [.50F3.0020.0002] # EGYPTIAN HIEROGLYPH D047 +130AA ; [.50F4.0020.0002] # EGYPTIAN HIEROGLYPH D048 +130AB ; [.50F5.0020.0002] # EGYPTIAN HIEROGLYPH D048A +130AC ; [.50F6.0020.0002] # EGYPTIAN HIEROGLYPH D049 +130AD ; [.50F7.0020.0002] # EGYPTIAN HIEROGLYPH D050 +130AE ; [.50F8.0020.0002] # EGYPTIAN HIEROGLYPH D050A +130AF ; [.50F9.0020.0002] # EGYPTIAN HIEROGLYPH D050B +130B0 ; [.50FA.0020.0002] # EGYPTIAN HIEROGLYPH D050C +130B1 ; [.50FB.0020.0002] # EGYPTIAN HIEROGLYPH D050D +130B2 ; [.50FC.0020.0002] # EGYPTIAN HIEROGLYPH D050E +130B3 ; [.50FD.0020.0002] # EGYPTIAN HIEROGLYPH D050F +130B4 ; [.50FE.0020.0002] # EGYPTIAN HIEROGLYPH D050G +130B5 ; [.50FF.0020.0002] # EGYPTIAN HIEROGLYPH D050H +130B6 ; [.5100.0020.0002] # EGYPTIAN HIEROGLYPH D050I +130B7 ; [.5101.0020.0002] # EGYPTIAN HIEROGLYPH D051 +130B8 ; [.5102.0020.0002] # EGYPTIAN HIEROGLYPH D052 +130B9 ; [.5103.0020.0002] # EGYPTIAN HIEROGLYPH D052A +130BA ; [.5104.0020.0002] # EGYPTIAN HIEROGLYPH D053 +130BB ; [.5105.0020.0002] # EGYPTIAN HIEROGLYPH D054 +130BC ; [.5106.0020.0002] # EGYPTIAN HIEROGLYPH D054A +130BD ; [.5107.0020.0002] # EGYPTIAN HIEROGLYPH D055 +130BE ; [.5108.0020.0002] # EGYPTIAN HIEROGLYPH D056 +130BF ; [.5109.0020.0002] # EGYPTIAN HIEROGLYPH D057 +130C0 ; [.510A.0020.0002] # EGYPTIAN HIEROGLYPH D058 +130C1 ; [.510B.0020.0002] # EGYPTIAN HIEROGLYPH D059 +130C2 ; [.510C.0020.0002] # EGYPTIAN HIEROGLYPH D060 +130C3 ; [.510D.0020.0002] # EGYPTIAN HIEROGLYPH D061 +130C4 ; [.510E.0020.0002] # EGYPTIAN HIEROGLYPH D062 +130C5 ; [.510F.0020.0002] # EGYPTIAN HIEROGLYPH D063 +130C6 ; [.5110.0020.0002] # EGYPTIAN HIEROGLYPH D064 +130C7 ; [.5111.0020.0002] # EGYPTIAN HIEROGLYPH D065 +130C8 ; [.5112.0020.0002] # EGYPTIAN HIEROGLYPH D066 +130C9 ; [.5113.0020.0002] # EGYPTIAN HIEROGLYPH D067 +130CA ; [.5114.0020.0002] # EGYPTIAN HIEROGLYPH D067A +130CB ; [.5115.0020.0002] # EGYPTIAN HIEROGLYPH D067B +130CC ; [.5116.0020.0002] # EGYPTIAN HIEROGLYPH D067C +130CD ; [.5117.0020.0002] # EGYPTIAN HIEROGLYPH D067D +130CE ; [.5118.0020.0002] # EGYPTIAN HIEROGLYPH D067E +130CF ; [.5119.0020.0002] # EGYPTIAN HIEROGLYPH D067F +130D0 ; [.511A.0020.0002] # EGYPTIAN HIEROGLYPH D067G +130D1 ; [.511B.0020.0002] # EGYPTIAN HIEROGLYPH D067H +130D2 ; [.511C.0020.0002] # EGYPTIAN HIEROGLYPH E001 +130D3 ; [.511D.0020.0002] # EGYPTIAN HIEROGLYPH E002 +130D4 ; [.511E.0020.0002] # EGYPTIAN HIEROGLYPH E003 +130D5 ; [.511F.0020.0002] # EGYPTIAN HIEROGLYPH E004 +130D6 ; [.5120.0020.0002] # EGYPTIAN HIEROGLYPH E005 +130D7 ; [.5121.0020.0002] # EGYPTIAN HIEROGLYPH E006 +130D8 ; [.5122.0020.0002] # EGYPTIAN HIEROGLYPH E007 +130D9 ; [.5123.0020.0002] # EGYPTIAN HIEROGLYPH E008 +130DA ; [.5124.0020.0002] # EGYPTIAN HIEROGLYPH E008A +130DB ; [.5125.0020.0002] # EGYPTIAN HIEROGLYPH E009 +130DC ; [.5126.0020.0002] # EGYPTIAN HIEROGLYPH E009A +130DD ; [.5127.0020.0002] # EGYPTIAN HIEROGLYPH E010 +130DE ; [.5128.0020.0002] # EGYPTIAN HIEROGLYPH E011 +130DF ; [.5129.0020.0002] # EGYPTIAN HIEROGLYPH E012 +130E0 ; [.512A.0020.0002] # EGYPTIAN HIEROGLYPH E013 +130E1 ; [.512B.0020.0002] # EGYPTIAN HIEROGLYPH E014 +130E2 ; [.512C.0020.0002] # EGYPTIAN HIEROGLYPH E015 +130E3 ; [.512D.0020.0002] # EGYPTIAN HIEROGLYPH E016 +130E4 ; [.512E.0020.0002] # EGYPTIAN HIEROGLYPH E016A +130E5 ; [.512F.0020.0002] # EGYPTIAN HIEROGLYPH E017 +130E6 ; [.5130.0020.0002] # EGYPTIAN HIEROGLYPH E017A +130E7 ; [.5131.0020.0002] # EGYPTIAN HIEROGLYPH E018 +130E8 ; [.5132.0020.0002] # EGYPTIAN HIEROGLYPH E019 +130E9 ; [.5133.0020.0002] # EGYPTIAN HIEROGLYPH E020 +130EA ; [.5134.0020.0002] # EGYPTIAN HIEROGLYPH E020A +130EB ; [.5135.0020.0002] # EGYPTIAN HIEROGLYPH E021 +130EC ; [.5136.0020.0002] # EGYPTIAN HIEROGLYPH E022 +130ED ; [.5137.0020.0002] # EGYPTIAN HIEROGLYPH E023 +130EE ; [.5138.0020.0002] # EGYPTIAN HIEROGLYPH E024 +130EF ; [.5139.0020.0002] # EGYPTIAN HIEROGLYPH E025 +130F0 ; [.513A.0020.0002] # EGYPTIAN HIEROGLYPH E026 +130F1 ; [.513B.0020.0002] # EGYPTIAN HIEROGLYPH E027 +130F2 ; [.513C.0020.0002] # EGYPTIAN HIEROGLYPH E028 +130F3 ; [.513D.0020.0002] # EGYPTIAN HIEROGLYPH E028A +130F4 ; [.513E.0020.0002] # EGYPTIAN HIEROGLYPH E029 +130F5 ; [.513F.0020.0002] # EGYPTIAN HIEROGLYPH E030 +130F6 ; [.5140.0020.0002] # EGYPTIAN HIEROGLYPH E031 +130F7 ; [.5141.0020.0002] # EGYPTIAN HIEROGLYPH E032 +130F8 ; [.5142.0020.0002] # EGYPTIAN HIEROGLYPH E033 +130F9 ; [.5143.0020.0002] # EGYPTIAN HIEROGLYPH E034 +130FA ; [.5144.0020.0002] # EGYPTIAN HIEROGLYPH E034A +130FB ; [.5145.0020.0002] # EGYPTIAN HIEROGLYPH E036 +130FC ; [.5146.0020.0002] # EGYPTIAN HIEROGLYPH E037 +130FD ; [.5147.0020.0002] # EGYPTIAN HIEROGLYPH E038 +130FE ; [.5148.0020.0002] # EGYPTIAN HIEROGLYPH F001 +130FF ; [.5149.0020.0002] # EGYPTIAN HIEROGLYPH F001A +13100 ; [.514A.0020.0002] # EGYPTIAN HIEROGLYPH F002 +13101 ; [.514B.0020.0002] # EGYPTIAN HIEROGLYPH F003 +13102 ; [.514C.0020.0002] # EGYPTIAN HIEROGLYPH F004 +13103 ; [.514D.0020.0002] # EGYPTIAN HIEROGLYPH F005 +13104 ; [.514E.0020.0002] # EGYPTIAN HIEROGLYPH F006 +13105 ; [.514F.0020.0002] # EGYPTIAN HIEROGLYPH F007 +13106 ; [.5150.0020.0002] # EGYPTIAN HIEROGLYPH F008 +13107 ; [.5151.0020.0002] # EGYPTIAN HIEROGLYPH F009 +13108 ; [.5152.0020.0002] # EGYPTIAN HIEROGLYPH F010 +13109 ; [.5153.0020.0002] # EGYPTIAN HIEROGLYPH F011 +1310A ; [.5154.0020.0002] # EGYPTIAN HIEROGLYPH F012 +1310B ; [.5155.0020.0002] # EGYPTIAN HIEROGLYPH F013 +1310C ; [.5156.0020.0002] # EGYPTIAN HIEROGLYPH F013A +1310D ; [.5157.0020.0002] # EGYPTIAN HIEROGLYPH F014 +1310E ; [.5158.0020.0002] # EGYPTIAN HIEROGLYPH F015 +1310F ; [.5159.0020.0002] # EGYPTIAN HIEROGLYPH F016 +13110 ; [.515A.0020.0002] # EGYPTIAN HIEROGLYPH F017 +13111 ; [.515B.0020.0002] # EGYPTIAN HIEROGLYPH F018 +13112 ; [.515C.0020.0002] # EGYPTIAN HIEROGLYPH F019 +13113 ; [.515D.0020.0002] # EGYPTIAN HIEROGLYPH F020 +13114 ; [.515E.0020.0002] # EGYPTIAN HIEROGLYPH F021 +13115 ; [.515F.0020.0002] # EGYPTIAN HIEROGLYPH F021A +13116 ; [.5160.0020.0002] # EGYPTIAN HIEROGLYPH F022 +13117 ; [.5161.0020.0002] # EGYPTIAN HIEROGLYPH F023 +13118 ; [.5162.0020.0002] # EGYPTIAN HIEROGLYPH F024 +13119 ; [.5163.0020.0002] # EGYPTIAN HIEROGLYPH F025 +1311A ; [.5164.0020.0002] # EGYPTIAN HIEROGLYPH F026 +1311B ; [.5165.0020.0002] # EGYPTIAN HIEROGLYPH F027 +1311C ; [.5166.0020.0002] # EGYPTIAN HIEROGLYPH F028 +1311D ; [.5167.0020.0002] # EGYPTIAN HIEROGLYPH F029 +1311E ; [.5168.0020.0002] # EGYPTIAN HIEROGLYPH F030 +1311F ; [.5169.0020.0002] # EGYPTIAN HIEROGLYPH F031 +13120 ; [.516A.0020.0002] # EGYPTIAN HIEROGLYPH F031A +13121 ; [.516B.0020.0002] # EGYPTIAN HIEROGLYPH F032 +13122 ; [.516C.0020.0002] # EGYPTIAN HIEROGLYPH F033 +13123 ; [.516D.0020.0002] # EGYPTIAN HIEROGLYPH F034 +13124 ; [.516E.0020.0002] # EGYPTIAN HIEROGLYPH F035 +13125 ; [.516F.0020.0002] # EGYPTIAN HIEROGLYPH F036 +13126 ; [.5170.0020.0002] # EGYPTIAN HIEROGLYPH F037 +13127 ; [.5171.0020.0002] # EGYPTIAN HIEROGLYPH F037A +13128 ; [.5172.0020.0002] # EGYPTIAN HIEROGLYPH F038 +13129 ; [.5173.0020.0002] # EGYPTIAN HIEROGLYPH F038A +1312A ; [.5174.0020.0002] # EGYPTIAN HIEROGLYPH F039 +1312B ; [.5175.0020.0002] # EGYPTIAN HIEROGLYPH F040 +1312C ; [.5176.0020.0002] # EGYPTIAN HIEROGLYPH F041 +1312D ; [.5177.0020.0002] # EGYPTIAN HIEROGLYPH F042 +1312E ; [.5178.0020.0002] # EGYPTIAN HIEROGLYPH F043 +1312F ; [.5179.0020.0002] # EGYPTIAN HIEROGLYPH F044 +13130 ; [.517A.0020.0002] # EGYPTIAN HIEROGLYPH F045 +13131 ; [.517B.0020.0002] # EGYPTIAN HIEROGLYPH F045A +13132 ; [.517C.0020.0002] # EGYPTIAN HIEROGLYPH F046 +13133 ; [.517D.0020.0002] # EGYPTIAN HIEROGLYPH F046A +13134 ; [.517E.0020.0002] # EGYPTIAN HIEROGLYPH F047 +13135 ; [.517F.0020.0002] # EGYPTIAN HIEROGLYPH F047A +13136 ; [.5180.0020.0002] # EGYPTIAN HIEROGLYPH F048 +13137 ; [.5181.0020.0002] # EGYPTIAN HIEROGLYPH F049 +13138 ; [.5182.0020.0002] # EGYPTIAN HIEROGLYPH F050 +13139 ; [.5183.0020.0002] # EGYPTIAN HIEROGLYPH F051 +1313A ; [.5184.0020.0002] # EGYPTIAN HIEROGLYPH F051A +1313B ; [.5185.0020.0002] # EGYPTIAN HIEROGLYPH F051B +1313C ; [.5186.0020.0002] # EGYPTIAN HIEROGLYPH F051C +1313D ; [.5187.0020.0002] # EGYPTIAN HIEROGLYPH F052 +1313E ; [.5188.0020.0002] # EGYPTIAN HIEROGLYPH F053 +1313F ; [.5189.0020.0002] # EGYPTIAN HIEROGLYPH G001 +13140 ; [.518A.0020.0002] # EGYPTIAN HIEROGLYPH G002 +13141 ; [.518B.0020.0002] # EGYPTIAN HIEROGLYPH G003 +13142 ; [.518C.0020.0002] # EGYPTIAN HIEROGLYPH G004 +13143 ; [.518D.0020.0002] # EGYPTIAN HIEROGLYPH G005 +13144 ; [.518E.0020.0002] # EGYPTIAN HIEROGLYPH G006 +13145 ; [.518F.0020.0002] # EGYPTIAN HIEROGLYPH G006A +13146 ; [.5190.0020.0002] # EGYPTIAN HIEROGLYPH G007 +13147 ; [.5191.0020.0002] # EGYPTIAN HIEROGLYPH G007A +13148 ; [.5192.0020.0002] # EGYPTIAN HIEROGLYPH G007B +13149 ; [.5193.0020.0002] # EGYPTIAN HIEROGLYPH G008 +1314A ; [.5194.0020.0002] # EGYPTIAN HIEROGLYPH G009 +1314B ; [.5195.0020.0002] # EGYPTIAN HIEROGLYPH G010 +1314C ; [.5196.0020.0002] # EGYPTIAN HIEROGLYPH G011 +1314D ; [.5197.0020.0002] # EGYPTIAN HIEROGLYPH G011A +1314E ; [.5198.0020.0002] # EGYPTIAN HIEROGLYPH G012 +1314F ; [.5199.0020.0002] # EGYPTIAN HIEROGLYPH G013 +13150 ; [.519A.0020.0002] # EGYPTIAN HIEROGLYPH G014 +13151 ; [.519B.0020.0002] # EGYPTIAN HIEROGLYPH G015 +13152 ; [.519C.0020.0002] # EGYPTIAN HIEROGLYPH G016 +13153 ; [.519D.0020.0002] # EGYPTIAN HIEROGLYPH G017 +13154 ; [.519E.0020.0002] # EGYPTIAN HIEROGLYPH G018 +13155 ; [.519F.0020.0002] # EGYPTIAN HIEROGLYPH G019 +13156 ; [.51A0.0020.0002] # EGYPTIAN HIEROGLYPH G020 +13157 ; [.51A1.0020.0002] # EGYPTIAN HIEROGLYPH G020A +13158 ; [.51A2.0020.0002] # EGYPTIAN HIEROGLYPH G021 +13159 ; [.51A3.0020.0002] # EGYPTIAN HIEROGLYPH G022 +1315A ; [.51A4.0020.0002] # EGYPTIAN HIEROGLYPH G023 +1315B ; [.51A5.0020.0002] # EGYPTIAN HIEROGLYPH G024 +1315C ; [.51A6.0020.0002] # EGYPTIAN HIEROGLYPH G025 +1315D ; [.51A7.0020.0002] # EGYPTIAN HIEROGLYPH G026 +1315E ; [.51A8.0020.0002] # EGYPTIAN HIEROGLYPH G026A +1315F ; [.51A9.0020.0002] # EGYPTIAN HIEROGLYPH G027 +13160 ; [.51AA.0020.0002] # EGYPTIAN HIEROGLYPH G028 +13161 ; [.51AB.0020.0002] # EGYPTIAN HIEROGLYPH G029 +13162 ; [.51AC.0020.0002] # EGYPTIAN HIEROGLYPH G030 +13163 ; [.51AD.0020.0002] # EGYPTIAN HIEROGLYPH G031 +13164 ; [.51AE.0020.0002] # EGYPTIAN HIEROGLYPH G032 +13165 ; [.51AF.0020.0002] # EGYPTIAN HIEROGLYPH G033 +13166 ; [.51B0.0020.0002] # EGYPTIAN HIEROGLYPH G034 +13167 ; [.51B1.0020.0002] # EGYPTIAN HIEROGLYPH G035 +13168 ; [.51B2.0020.0002] # EGYPTIAN HIEROGLYPH G036 +13169 ; [.51B3.0020.0002] # EGYPTIAN HIEROGLYPH G036A +1316A ; [.51B4.0020.0002] # EGYPTIAN HIEROGLYPH G037 +1316B ; [.51B5.0020.0002] # EGYPTIAN HIEROGLYPH G037A +1316C ; [.51B6.0020.0002] # EGYPTIAN HIEROGLYPH G038 +1316D ; [.51B7.0020.0002] # EGYPTIAN HIEROGLYPH G039 +1316E ; [.51B8.0020.0002] # EGYPTIAN HIEROGLYPH G040 +1316F ; [.51B9.0020.0002] # EGYPTIAN HIEROGLYPH G041 +13170 ; [.51BA.0020.0002] # EGYPTIAN HIEROGLYPH G042 +13171 ; [.51BB.0020.0002] # EGYPTIAN HIEROGLYPH G043 +13172 ; [.51BC.0020.0002] # EGYPTIAN HIEROGLYPH G043A +13173 ; [.51BD.0020.0002] # EGYPTIAN HIEROGLYPH G044 +13174 ; [.51BE.0020.0002] # EGYPTIAN HIEROGLYPH G045 +13175 ; [.51BF.0020.0002] # EGYPTIAN HIEROGLYPH G045A +13176 ; [.51C0.0020.0002] # EGYPTIAN HIEROGLYPH G046 +13177 ; [.51C1.0020.0002] # EGYPTIAN HIEROGLYPH G047 +13178 ; [.51C2.0020.0002] # EGYPTIAN HIEROGLYPH G048 +13179 ; [.51C3.0020.0002] # EGYPTIAN HIEROGLYPH G049 +1317A ; [.51C4.0020.0002] # EGYPTIAN HIEROGLYPH G050 +1317B ; [.51C5.0020.0002] # EGYPTIAN HIEROGLYPH G051 +1317C ; [.51C6.0020.0002] # EGYPTIAN HIEROGLYPH G052 +1317D ; [.51C7.0020.0002] # EGYPTIAN HIEROGLYPH G053 +1317E ; [.51C8.0020.0002] # EGYPTIAN HIEROGLYPH G054 +1317F ; [.51C9.0020.0002] # EGYPTIAN HIEROGLYPH H001 +13180 ; [.51CA.0020.0002] # EGYPTIAN HIEROGLYPH H002 +13181 ; [.51CB.0020.0002] # EGYPTIAN HIEROGLYPH H003 +13182 ; [.51CC.0020.0002] # EGYPTIAN HIEROGLYPH H004 +13183 ; [.51CD.0020.0002] # EGYPTIAN HIEROGLYPH H005 +13184 ; [.51CE.0020.0002] # EGYPTIAN HIEROGLYPH H006 +13185 ; [.51CF.0020.0002] # EGYPTIAN HIEROGLYPH H006A +13186 ; [.51D0.0020.0002] # EGYPTIAN HIEROGLYPH H007 +13187 ; [.51D1.0020.0002] # EGYPTIAN HIEROGLYPH H008 +13188 ; [.51D2.0020.0002] # EGYPTIAN HIEROGLYPH I001 +13189 ; [.51D3.0020.0002] # EGYPTIAN HIEROGLYPH I002 +1318A ; [.51D4.0020.0002] # EGYPTIAN HIEROGLYPH I003 +1318B ; [.51D5.0020.0002] # EGYPTIAN HIEROGLYPH I004 +1318C ; [.51D6.0020.0002] # EGYPTIAN HIEROGLYPH I005 +1318D ; [.51D7.0020.0002] # EGYPTIAN HIEROGLYPH I005A +1318E ; [.51D8.0020.0002] # EGYPTIAN HIEROGLYPH I006 +1318F ; [.51D9.0020.0002] # EGYPTIAN HIEROGLYPH I007 +13190 ; [.51DA.0020.0002] # EGYPTIAN HIEROGLYPH I008 +13191 ; [.51DB.0020.0002] # EGYPTIAN HIEROGLYPH I009 +13192 ; [.51DC.0020.0002] # EGYPTIAN HIEROGLYPH I009A +13193 ; [.51DD.0020.0002] # EGYPTIAN HIEROGLYPH I010 +13194 ; [.51DE.0020.0002] # EGYPTIAN HIEROGLYPH I010A +13195 ; [.51DF.0020.0002] # EGYPTIAN HIEROGLYPH I011 +13196 ; [.51E0.0020.0002] # EGYPTIAN HIEROGLYPH I011A +13197 ; [.51E1.0020.0002] # EGYPTIAN HIEROGLYPH I012 +13198 ; [.51E2.0020.0002] # EGYPTIAN HIEROGLYPH I013 +13199 ; [.51E3.0020.0002] # EGYPTIAN HIEROGLYPH I014 +1319A ; [.51E4.0020.0002] # EGYPTIAN HIEROGLYPH I015 +1319B ; [.51E5.0020.0002] # EGYPTIAN HIEROGLYPH K001 +1319C ; [.51E6.0020.0002] # EGYPTIAN HIEROGLYPH K002 +1319D ; [.51E7.0020.0002] # EGYPTIAN HIEROGLYPH K003 +1319E ; [.51E8.0020.0002] # EGYPTIAN HIEROGLYPH K004 +1319F ; [.51E9.0020.0002] # EGYPTIAN HIEROGLYPH K005 +131A0 ; [.51EA.0020.0002] # EGYPTIAN HIEROGLYPH K006 +131A1 ; [.51EB.0020.0002] # EGYPTIAN HIEROGLYPH K007 +131A2 ; [.51EC.0020.0002] # EGYPTIAN HIEROGLYPH K008 +131A3 ; [.51ED.0020.0002] # EGYPTIAN HIEROGLYPH L001 +131A4 ; [.51EE.0020.0002] # EGYPTIAN HIEROGLYPH L002 +131A5 ; [.51EF.0020.0002] # EGYPTIAN HIEROGLYPH L002A +131A6 ; [.51F0.0020.0002] # EGYPTIAN HIEROGLYPH L003 +131A7 ; [.51F1.0020.0002] # EGYPTIAN HIEROGLYPH L004 +131A8 ; [.51F2.0020.0002] # EGYPTIAN HIEROGLYPH L005 +131A9 ; [.51F3.0020.0002] # EGYPTIAN HIEROGLYPH L006 +131AA ; [.51F4.0020.0002] # EGYPTIAN HIEROGLYPH L006A +131AB ; [.51F5.0020.0002] # EGYPTIAN HIEROGLYPH L007 +131AC ; [.51F6.0020.0002] # EGYPTIAN HIEROGLYPH L008 +131AD ; [.51F7.0020.0002] # EGYPTIAN HIEROGLYPH M001 +131AE ; [.51F8.0020.0002] # EGYPTIAN HIEROGLYPH M001A +131AF ; [.51F9.0020.0002] # EGYPTIAN HIEROGLYPH M001B +131B0 ; [.51FA.0020.0002] # EGYPTIAN HIEROGLYPH M002 +131B1 ; [.51FB.0020.0002] # EGYPTIAN HIEROGLYPH M003 +131B2 ; [.51FC.0020.0002] # EGYPTIAN HIEROGLYPH M003A +131B3 ; [.51FD.0020.0002] # EGYPTIAN HIEROGLYPH M004 +131B4 ; [.51FE.0020.0002] # EGYPTIAN HIEROGLYPH M005 +131B5 ; [.51FF.0020.0002] # EGYPTIAN HIEROGLYPH M006 +131B6 ; [.5200.0020.0002] # EGYPTIAN HIEROGLYPH M007 +131B7 ; [.5201.0020.0002] # EGYPTIAN HIEROGLYPH M008 +131B8 ; [.5202.0020.0002] # EGYPTIAN HIEROGLYPH M009 +131B9 ; [.5203.0020.0002] # EGYPTIAN HIEROGLYPH M010 +131BA ; [.5204.0020.0002] # EGYPTIAN HIEROGLYPH M010A +131BB ; [.5205.0020.0002] # EGYPTIAN HIEROGLYPH M011 +131BC ; [.5206.0020.0002] # EGYPTIAN HIEROGLYPH M012 +131BD ; [.5207.0020.0002] # EGYPTIAN HIEROGLYPH M012A +131BE ; [.5208.0020.0002] # EGYPTIAN HIEROGLYPH M012B +131BF ; [.5209.0020.0002] # EGYPTIAN HIEROGLYPH M012C +131C0 ; [.520A.0020.0002] # EGYPTIAN HIEROGLYPH M012D +131C1 ; [.520B.0020.0002] # EGYPTIAN HIEROGLYPH M012E +131C2 ; [.520C.0020.0002] # EGYPTIAN HIEROGLYPH M012F +131C3 ; [.520D.0020.0002] # EGYPTIAN HIEROGLYPH M012G +131C4 ; [.520E.0020.0002] # EGYPTIAN HIEROGLYPH M012H +131C5 ; [.520F.0020.0002] # EGYPTIAN HIEROGLYPH M013 +131C6 ; [.5210.0020.0002] # EGYPTIAN HIEROGLYPH M014 +131C7 ; [.5211.0020.0002] # EGYPTIAN HIEROGLYPH M015 +131C8 ; [.5212.0020.0002] # EGYPTIAN HIEROGLYPH M015A +131C9 ; [.5213.0020.0002] # EGYPTIAN HIEROGLYPH M016 +131CA ; [.5214.0020.0002] # EGYPTIAN HIEROGLYPH M016A +131CB ; [.5215.0020.0002] # EGYPTIAN HIEROGLYPH M017 +131CC ; [.5216.0020.0002] # EGYPTIAN HIEROGLYPH M017A +131CD ; [.5217.0020.0002] # EGYPTIAN HIEROGLYPH M018 +131CE ; [.5218.0020.0002] # EGYPTIAN HIEROGLYPH M019 +131CF ; [.5219.0020.0002] # EGYPTIAN HIEROGLYPH M020 +131D0 ; [.521A.0020.0002] # EGYPTIAN HIEROGLYPH M021 +131D1 ; [.521B.0020.0002] # EGYPTIAN HIEROGLYPH M022 +131D2 ; [.521C.0020.0002] # EGYPTIAN HIEROGLYPH M022A +131D3 ; [.521D.0020.0002] # EGYPTIAN HIEROGLYPH M023 +131D4 ; [.521E.0020.0002] # EGYPTIAN HIEROGLYPH M024 +131D5 ; [.521F.0020.0002] # EGYPTIAN HIEROGLYPH M024A +131D6 ; [.5220.0020.0002] # EGYPTIAN HIEROGLYPH M025 +131D7 ; [.5221.0020.0002] # EGYPTIAN HIEROGLYPH M026 +131D8 ; [.5222.0020.0002] # EGYPTIAN HIEROGLYPH M027 +131D9 ; [.5223.0020.0002] # EGYPTIAN HIEROGLYPH M028 +131DA ; [.5224.0020.0002] # EGYPTIAN HIEROGLYPH M028A +131DB ; [.5225.0020.0002] # EGYPTIAN HIEROGLYPH M029 +131DC ; [.5226.0020.0002] # EGYPTIAN HIEROGLYPH M030 +131DD ; [.5227.0020.0002] # EGYPTIAN HIEROGLYPH M031 +131DE ; [.5228.0020.0002] # EGYPTIAN HIEROGLYPH M031A +131DF ; [.5229.0020.0002] # EGYPTIAN HIEROGLYPH M032 +131E0 ; [.522A.0020.0002] # EGYPTIAN HIEROGLYPH M033 +131E1 ; [.522B.0020.0002] # EGYPTIAN HIEROGLYPH M033A +131E2 ; [.522C.0020.0002] # EGYPTIAN HIEROGLYPH M033B +131E3 ; [.522D.0020.0002] # EGYPTIAN HIEROGLYPH M034 +131E4 ; [.522E.0020.0002] # EGYPTIAN HIEROGLYPH M035 +131E5 ; [.522F.0020.0002] # EGYPTIAN HIEROGLYPH M036 +131E6 ; [.5230.0020.0002] # EGYPTIAN HIEROGLYPH M037 +131E7 ; [.5231.0020.0002] # EGYPTIAN HIEROGLYPH M038 +131E8 ; [.5232.0020.0002] # EGYPTIAN HIEROGLYPH M039 +131E9 ; [.5233.0020.0002] # EGYPTIAN HIEROGLYPH M040 +131EA ; [.5234.0020.0002] # EGYPTIAN HIEROGLYPH M040A +131EB ; [.5235.0020.0002] # EGYPTIAN HIEROGLYPH M041 +131EC ; [.5236.0020.0002] # EGYPTIAN HIEROGLYPH M042 +131ED ; [.5237.0020.0002] # EGYPTIAN HIEROGLYPH M043 +131EE ; [.5238.0020.0002] # EGYPTIAN HIEROGLYPH M044 +131EF ; [.5239.0020.0002] # EGYPTIAN HIEROGLYPH N001 +131F0 ; [.523A.0020.0002] # EGYPTIAN HIEROGLYPH N002 +131F1 ; [.523B.0020.0002] # EGYPTIAN HIEROGLYPH N003 +131F2 ; [.523C.0020.0002] # EGYPTIAN HIEROGLYPH N004 +131F3 ; [.523D.0020.0002] # EGYPTIAN HIEROGLYPH N005 +131F4 ; [.523E.0020.0002] # EGYPTIAN HIEROGLYPH N006 +131F5 ; [.523F.0020.0002] # EGYPTIAN HIEROGLYPH N007 +131F6 ; [.5240.0020.0002] # EGYPTIAN HIEROGLYPH N008 +131F7 ; [.5241.0020.0002] # EGYPTIAN HIEROGLYPH N009 +131F8 ; [.5242.0020.0002] # EGYPTIAN HIEROGLYPH N010 +131F9 ; [.5243.0020.0002] # EGYPTIAN HIEROGLYPH N011 +131FA ; [.5244.0020.0002] # EGYPTIAN HIEROGLYPH N012 +131FB ; [.5245.0020.0002] # EGYPTIAN HIEROGLYPH N013 +131FC ; [.5246.0020.0002] # EGYPTIAN HIEROGLYPH N014 +131FD ; [.5247.0020.0002] # EGYPTIAN HIEROGLYPH N015 +131FE ; [.5248.0020.0002] # EGYPTIAN HIEROGLYPH N016 +131FF ; [.5249.0020.0002] # EGYPTIAN HIEROGLYPH N017 +13200 ; [.524A.0020.0002] # EGYPTIAN HIEROGLYPH N018 +13201 ; [.524B.0020.0002] # EGYPTIAN HIEROGLYPH N018A +13202 ; [.524C.0020.0002] # EGYPTIAN HIEROGLYPH N018B +13203 ; [.524D.0020.0002] # EGYPTIAN HIEROGLYPH N019 +13204 ; [.524E.0020.0002] # EGYPTIAN HIEROGLYPH N020 +13205 ; [.524F.0020.0002] # EGYPTIAN HIEROGLYPH N021 +13206 ; [.5250.0020.0002] # EGYPTIAN HIEROGLYPH N022 +13207 ; [.5251.0020.0002] # EGYPTIAN HIEROGLYPH N023 +13208 ; [.5252.0020.0002] # EGYPTIAN HIEROGLYPH N024 +13209 ; [.5253.0020.0002] # EGYPTIAN HIEROGLYPH N025 +1320A ; [.5254.0020.0002] # EGYPTIAN HIEROGLYPH N025A +1320B ; [.5255.0020.0002] # EGYPTIAN HIEROGLYPH N026 +1320C ; [.5256.0020.0002] # EGYPTIAN HIEROGLYPH N027 +1320D ; [.5257.0020.0002] # EGYPTIAN HIEROGLYPH N028 +1320E ; [.5258.0020.0002] # EGYPTIAN HIEROGLYPH N029 +1320F ; [.5259.0020.0002] # EGYPTIAN HIEROGLYPH N030 +13210 ; [.525A.0020.0002] # EGYPTIAN HIEROGLYPH N031 +13211 ; [.525B.0020.0002] # EGYPTIAN HIEROGLYPH N032 +13212 ; [.525C.0020.0002] # EGYPTIAN HIEROGLYPH N033 +13213 ; [.525D.0020.0002] # EGYPTIAN HIEROGLYPH N033A +13214 ; [.525E.0020.0002] # EGYPTIAN HIEROGLYPH N034 +13215 ; [.525F.0020.0002] # EGYPTIAN HIEROGLYPH N034A +13216 ; [.5260.0020.0002] # EGYPTIAN HIEROGLYPH N035 +13217 ; [.5261.0020.0002] # EGYPTIAN HIEROGLYPH N035A +13218 ; [.5262.0020.0002] # EGYPTIAN HIEROGLYPH N036 +13219 ; [.5263.0020.0002] # EGYPTIAN HIEROGLYPH N037 +1321A ; [.5264.0020.0002] # EGYPTIAN HIEROGLYPH N037A +1321B ; [.5265.0020.0002] # EGYPTIAN HIEROGLYPH N038 +1321C ; [.5266.0020.0002] # EGYPTIAN HIEROGLYPH N039 +1321D ; [.5267.0020.0002] # EGYPTIAN HIEROGLYPH N040 +1321E ; [.5268.0020.0002] # EGYPTIAN HIEROGLYPH N041 +1321F ; [.5269.0020.0002] # EGYPTIAN HIEROGLYPH N042 +13220 ; [.526A.0020.0002] # EGYPTIAN HIEROGLYPH NL001 +13221 ; [.526B.0020.0002] # EGYPTIAN HIEROGLYPH NL002 +13222 ; [.526C.0020.0002] # EGYPTIAN HIEROGLYPH NL003 +13223 ; [.526D.0020.0002] # EGYPTIAN HIEROGLYPH NL004 +13224 ; [.526E.0020.0002] # EGYPTIAN HIEROGLYPH NL005 +13225 ; [.526F.0020.0002] # EGYPTIAN HIEROGLYPH NL005A +13226 ; [.5270.0020.0002] # EGYPTIAN HIEROGLYPH NL006 +13227 ; [.5271.0020.0002] # EGYPTIAN HIEROGLYPH NL007 +13228 ; [.5272.0020.0002] # EGYPTIAN HIEROGLYPH NL008 +13229 ; [.5273.0020.0002] # EGYPTIAN HIEROGLYPH NL009 +1322A ; [.5274.0020.0002] # EGYPTIAN HIEROGLYPH NL010 +1322B ; [.5275.0020.0002] # EGYPTIAN HIEROGLYPH NL011 +1322C ; [.5276.0020.0002] # EGYPTIAN HIEROGLYPH NL012 +1322D ; [.5277.0020.0002] # EGYPTIAN HIEROGLYPH NL013 +1322E ; [.5278.0020.0002] # EGYPTIAN HIEROGLYPH NL014 +1322F ; [.5279.0020.0002] # EGYPTIAN HIEROGLYPH NL015 +13230 ; [.527A.0020.0002] # EGYPTIAN HIEROGLYPH NL016 +13231 ; [.527B.0020.0002] # EGYPTIAN HIEROGLYPH NL017 +13232 ; [.527C.0020.0002] # EGYPTIAN HIEROGLYPH NL017A +13233 ; [.527D.0020.0002] # EGYPTIAN HIEROGLYPH NL018 +13234 ; [.527E.0020.0002] # EGYPTIAN HIEROGLYPH NL019 +13235 ; [.527F.0020.0002] # EGYPTIAN HIEROGLYPH NL020 +13236 ; [.5280.0020.0002] # EGYPTIAN HIEROGLYPH NU001 +13237 ; [.5281.0020.0002] # EGYPTIAN HIEROGLYPH NU002 +13238 ; [.5282.0020.0002] # EGYPTIAN HIEROGLYPH NU003 +13239 ; [.5283.0020.0002] # EGYPTIAN HIEROGLYPH NU004 +1323A ; [.5284.0020.0002] # EGYPTIAN HIEROGLYPH NU005 +1323B ; [.5285.0020.0002] # EGYPTIAN HIEROGLYPH NU006 +1323C ; [.5286.0020.0002] # EGYPTIAN HIEROGLYPH NU007 +1323D ; [.5287.0020.0002] # EGYPTIAN HIEROGLYPH NU008 +1323E ; [.5288.0020.0002] # EGYPTIAN HIEROGLYPH NU009 +1323F ; [.5289.0020.0002] # EGYPTIAN HIEROGLYPH NU010 +13240 ; [.528A.0020.0002] # EGYPTIAN HIEROGLYPH NU010A +13241 ; [.528B.0020.0002] # EGYPTIAN HIEROGLYPH NU011 +13242 ; [.528C.0020.0002] # EGYPTIAN HIEROGLYPH NU011A +13243 ; [.528D.0020.0002] # EGYPTIAN HIEROGLYPH NU012 +13244 ; [.528E.0020.0002] # EGYPTIAN HIEROGLYPH NU013 +13245 ; [.528F.0020.0002] # EGYPTIAN HIEROGLYPH NU014 +13246 ; [.5290.0020.0002] # EGYPTIAN HIEROGLYPH NU015 +13247 ; [.5291.0020.0002] # EGYPTIAN HIEROGLYPH NU016 +13248 ; [.5292.0020.0002] # EGYPTIAN HIEROGLYPH NU017 +13249 ; [.5293.0020.0002] # EGYPTIAN HIEROGLYPH NU018 +1324A ; [.5294.0020.0002] # EGYPTIAN HIEROGLYPH NU018A +1324B ; [.5295.0020.0002] # EGYPTIAN HIEROGLYPH NU019 +1324C ; [.5296.0020.0002] # EGYPTIAN HIEROGLYPH NU020 +1324D ; [.5297.0020.0002] # EGYPTIAN HIEROGLYPH NU021 +1324E ; [.5298.0020.0002] # EGYPTIAN HIEROGLYPH NU022 +1324F ; [.5299.0020.0002] # EGYPTIAN HIEROGLYPH NU022A +13250 ; [.529A.0020.0002] # EGYPTIAN HIEROGLYPH O001 +13251 ; [.529B.0020.0002] # EGYPTIAN HIEROGLYPH O001A +13252 ; [.529C.0020.0002] # EGYPTIAN HIEROGLYPH O002 +13253 ; [.529D.0020.0002] # EGYPTIAN HIEROGLYPH O003 +13254 ; [.529E.0020.0002] # EGYPTIAN HIEROGLYPH O004 +13255 ; [.529F.0020.0002] # EGYPTIAN HIEROGLYPH O005 +13256 ; [.52A0.0020.0002] # EGYPTIAN HIEROGLYPH O005A +13257 ; [.52A1.0020.0002] # EGYPTIAN HIEROGLYPH O006 +13258 ; [.52A2.0020.0002] # EGYPTIAN HIEROGLYPH O006A +13259 ; [.52A3.0020.0002] # EGYPTIAN HIEROGLYPH O006B +1325A ; [.52A4.0020.0002] # EGYPTIAN HIEROGLYPH O006C +1325B ; [.52A5.0020.0002] # EGYPTIAN HIEROGLYPH O006D +1325C ; [.52A6.0020.0002] # EGYPTIAN HIEROGLYPH O006E +1325D ; [.52A7.0020.0002] # EGYPTIAN HIEROGLYPH O006F +1325E ; [.52A8.0020.0002] # EGYPTIAN HIEROGLYPH O007 +1325F ; [.52A9.0020.0002] # EGYPTIAN HIEROGLYPH O008 +13260 ; [.52AA.0020.0002] # EGYPTIAN HIEROGLYPH O009 +13261 ; [.52AB.0020.0002] # EGYPTIAN HIEROGLYPH O010 +13262 ; [.52AC.0020.0002] # EGYPTIAN HIEROGLYPH O010A +13263 ; [.52AD.0020.0002] # EGYPTIAN HIEROGLYPH O010B +13264 ; [.52AE.0020.0002] # EGYPTIAN HIEROGLYPH O010C +13265 ; [.52AF.0020.0002] # EGYPTIAN HIEROGLYPH O011 +13266 ; [.52B0.0020.0002] # EGYPTIAN HIEROGLYPH O012 +13267 ; [.52B1.0020.0002] # EGYPTIAN HIEROGLYPH O013 +13268 ; [.52B2.0020.0002] # EGYPTIAN HIEROGLYPH O014 +13269 ; [.52B3.0020.0002] # EGYPTIAN HIEROGLYPH O015 +1326A ; [.52B4.0020.0002] # EGYPTIAN HIEROGLYPH O016 +1326B ; [.52B5.0020.0002] # EGYPTIAN HIEROGLYPH O017 +1326C ; [.52B6.0020.0002] # EGYPTIAN HIEROGLYPH O018 +1326D ; [.52B7.0020.0002] # EGYPTIAN HIEROGLYPH O019 +1326E ; [.52B8.0020.0002] # EGYPTIAN HIEROGLYPH O019A +1326F ; [.52B9.0020.0002] # EGYPTIAN HIEROGLYPH O020 +13270 ; [.52BA.0020.0002] # EGYPTIAN HIEROGLYPH O020A +13271 ; [.52BB.0020.0002] # EGYPTIAN HIEROGLYPH O021 +13272 ; [.52BC.0020.0002] # EGYPTIAN HIEROGLYPH O022 +13273 ; [.52BD.0020.0002] # EGYPTIAN HIEROGLYPH O023 +13274 ; [.52BE.0020.0002] # EGYPTIAN HIEROGLYPH O024 +13275 ; [.52BF.0020.0002] # EGYPTIAN HIEROGLYPH O024A +13276 ; [.52C0.0020.0002] # EGYPTIAN HIEROGLYPH O025 +13277 ; [.52C1.0020.0002] # EGYPTIAN HIEROGLYPH O025A +13278 ; [.52C2.0020.0002] # EGYPTIAN HIEROGLYPH O026 +13279 ; [.52C3.0020.0002] # EGYPTIAN HIEROGLYPH O027 +1327A ; [.52C4.0020.0002] # EGYPTIAN HIEROGLYPH O028 +1327B ; [.52C5.0020.0002] # EGYPTIAN HIEROGLYPH O029 +1327C ; [.52C6.0020.0002] # EGYPTIAN HIEROGLYPH O029A +1327D ; [.52C7.0020.0002] # EGYPTIAN HIEROGLYPH O030 +1327E ; [.52C8.0020.0002] # EGYPTIAN HIEROGLYPH O030A +1327F ; [.52C9.0020.0002] # EGYPTIAN HIEROGLYPH O031 +13280 ; [.52CA.0020.0002] # EGYPTIAN HIEROGLYPH O032 +13281 ; [.52CB.0020.0002] # EGYPTIAN HIEROGLYPH O033 +13282 ; [.52CC.0020.0002] # EGYPTIAN HIEROGLYPH O033A +13283 ; [.52CD.0020.0002] # EGYPTIAN HIEROGLYPH O034 +13284 ; [.52CE.0020.0002] # EGYPTIAN HIEROGLYPH O035 +13285 ; [.52CF.0020.0002] # EGYPTIAN HIEROGLYPH O036 +13286 ; [.52D0.0020.0002] # EGYPTIAN HIEROGLYPH O036A +13287 ; [.52D1.0020.0002] # EGYPTIAN HIEROGLYPH O036B +13288 ; [.52D2.0020.0002] # EGYPTIAN HIEROGLYPH O036C +13289 ; [.52D3.0020.0002] # EGYPTIAN HIEROGLYPH O036D +1328A ; [.52D4.0020.0002] # EGYPTIAN HIEROGLYPH O037 +1328B ; [.52D5.0020.0002] # EGYPTIAN HIEROGLYPH O038 +1328C ; [.52D6.0020.0002] # EGYPTIAN HIEROGLYPH O039 +1328D ; [.52D7.0020.0002] # EGYPTIAN HIEROGLYPH O040 +1328E ; [.52D8.0020.0002] # EGYPTIAN HIEROGLYPH O041 +1328F ; [.52D9.0020.0002] # EGYPTIAN HIEROGLYPH O042 +13290 ; [.52DA.0020.0002] # EGYPTIAN HIEROGLYPH O043 +13291 ; [.52DB.0020.0002] # EGYPTIAN HIEROGLYPH O044 +13292 ; [.52DC.0020.0002] # EGYPTIAN HIEROGLYPH O045 +13293 ; [.52DD.0020.0002] # EGYPTIAN HIEROGLYPH O046 +13294 ; [.52DE.0020.0002] # EGYPTIAN HIEROGLYPH O047 +13295 ; [.52DF.0020.0002] # EGYPTIAN HIEROGLYPH O048 +13296 ; [.52E0.0020.0002] # EGYPTIAN HIEROGLYPH O049 +13297 ; [.52E1.0020.0002] # EGYPTIAN HIEROGLYPH O050 +13298 ; [.52E2.0020.0002] # EGYPTIAN HIEROGLYPH O050A +13299 ; [.52E3.0020.0002] # EGYPTIAN HIEROGLYPH O050B +1329A ; [.52E4.0020.0002] # EGYPTIAN HIEROGLYPH O051 +1329B ; [.52E5.0020.0002] # EGYPTIAN HIEROGLYPH P001 +1329C ; [.52E6.0020.0002] # EGYPTIAN HIEROGLYPH P001A +1329D ; [.52E7.0020.0002] # EGYPTIAN HIEROGLYPH P002 +1329E ; [.52E8.0020.0002] # EGYPTIAN HIEROGLYPH P003 +1329F ; [.52E9.0020.0002] # EGYPTIAN HIEROGLYPH P003A +132A0 ; [.52EA.0020.0002] # EGYPTIAN HIEROGLYPH P004 +132A1 ; [.52EB.0020.0002] # EGYPTIAN HIEROGLYPH P005 +132A2 ; [.52EC.0020.0002] # EGYPTIAN HIEROGLYPH P006 +132A3 ; [.52ED.0020.0002] # EGYPTIAN HIEROGLYPH P007 +132A4 ; [.52EE.0020.0002] # EGYPTIAN HIEROGLYPH P008 +132A5 ; [.52EF.0020.0002] # EGYPTIAN HIEROGLYPH P009 +132A6 ; [.52F0.0020.0002] # EGYPTIAN HIEROGLYPH P010 +132A7 ; [.52F1.0020.0002] # EGYPTIAN HIEROGLYPH P011 +132A8 ; [.52F2.0020.0002] # EGYPTIAN HIEROGLYPH Q001 +132A9 ; [.52F3.0020.0002] # EGYPTIAN HIEROGLYPH Q002 +132AA ; [.52F4.0020.0002] # EGYPTIAN HIEROGLYPH Q003 +132AB ; [.52F5.0020.0002] # EGYPTIAN HIEROGLYPH Q004 +132AC ; [.52F6.0020.0002] # EGYPTIAN HIEROGLYPH Q005 +132AD ; [.52F7.0020.0002] # EGYPTIAN HIEROGLYPH Q006 +132AE ; [.52F8.0020.0002] # EGYPTIAN HIEROGLYPH Q007 +132AF ; [.52F9.0020.0002] # EGYPTIAN HIEROGLYPH R001 +132B0 ; [.52FA.0020.0002] # EGYPTIAN HIEROGLYPH R002 +132B1 ; [.52FB.0020.0002] # EGYPTIAN HIEROGLYPH R002A +132B2 ; [.52FC.0020.0002] # EGYPTIAN HIEROGLYPH R003 +132B3 ; [.52FD.0020.0002] # EGYPTIAN HIEROGLYPH R003A +132B4 ; [.52FE.0020.0002] # EGYPTIAN HIEROGLYPH R003B +132B5 ; [.52FF.0020.0002] # EGYPTIAN HIEROGLYPH R004 +132B6 ; [.5300.0020.0002] # EGYPTIAN HIEROGLYPH R005 +132B7 ; [.5301.0020.0002] # EGYPTIAN HIEROGLYPH R006 +132B8 ; [.5302.0020.0002] # EGYPTIAN HIEROGLYPH R007 +132B9 ; [.5303.0020.0002] # EGYPTIAN HIEROGLYPH R008 +132BA ; [.5304.0020.0002] # EGYPTIAN HIEROGLYPH R009 +132BB ; [.5305.0020.0002] # EGYPTIAN HIEROGLYPH R010 +132BC ; [.5306.0020.0002] # EGYPTIAN HIEROGLYPH R010A +132BD ; [.5307.0020.0002] # EGYPTIAN HIEROGLYPH R011 +132BE ; [.5308.0020.0002] # EGYPTIAN HIEROGLYPH R012 +132BF ; [.5309.0020.0002] # EGYPTIAN HIEROGLYPH R013 +132C0 ; [.530A.0020.0002] # EGYPTIAN HIEROGLYPH R014 +132C1 ; [.530B.0020.0002] # EGYPTIAN HIEROGLYPH R015 +132C2 ; [.530C.0020.0002] # EGYPTIAN HIEROGLYPH R016 +132C3 ; [.530D.0020.0002] # EGYPTIAN HIEROGLYPH R016A +132C4 ; [.530E.0020.0002] # EGYPTIAN HIEROGLYPH R017 +132C5 ; [.530F.0020.0002] # EGYPTIAN HIEROGLYPH R018 +132C6 ; [.5310.0020.0002] # EGYPTIAN HIEROGLYPH R019 +132C7 ; [.5311.0020.0002] # EGYPTIAN HIEROGLYPH R020 +132C8 ; [.5312.0020.0002] # EGYPTIAN HIEROGLYPH R021 +132C9 ; [.5313.0020.0002] # EGYPTIAN HIEROGLYPH R022 +132CA ; [.5314.0020.0002] # EGYPTIAN HIEROGLYPH R023 +132CB ; [.5315.0020.0002] # EGYPTIAN HIEROGLYPH R024 +132CC ; [.5316.0020.0002] # EGYPTIAN HIEROGLYPH R025 +132CD ; [.5317.0020.0002] # EGYPTIAN HIEROGLYPH R026 +132CE ; [.5318.0020.0002] # EGYPTIAN HIEROGLYPH R027 +132CF ; [.5319.0020.0002] # EGYPTIAN HIEROGLYPH R028 +132D0 ; [.531A.0020.0002] # EGYPTIAN HIEROGLYPH R029 +132D1 ; [.531B.0020.0002] # EGYPTIAN HIEROGLYPH S001 +132D2 ; [.531C.0020.0002] # EGYPTIAN HIEROGLYPH S002 +132D3 ; [.531D.0020.0002] # EGYPTIAN HIEROGLYPH S002A +132D4 ; [.531E.0020.0002] # EGYPTIAN HIEROGLYPH S003 +132D5 ; [.531F.0020.0002] # EGYPTIAN HIEROGLYPH S004 +132D6 ; [.5320.0020.0002] # EGYPTIAN HIEROGLYPH S005 +132D7 ; [.5321.0020.0002] # EGYPTIAN HIEROGLYPH S006 +132D8 ; [.5322.0020.0002] # EGYPTIAN HIEROGLYPH S006A +132D9 ; [.5323.0020.0002] # EGYPTIAN HIEROGLYPH S007 +132DA ; [.5324.0020.0002] # EGYPTIAN HIEROGLYPH S008 +132DB ; [.5325.0020.0002] # EGYPTIAN HIEROGLYPH S009 +132DC ; [.5326.0020.0002] # EGYPTIAN HIEROGLYPH S010 +132DD ; [.5327.0020.0002] # EGYPTIAN HIEROGLYPH S011 +132DE ; [.5328.0020.0002] # EGYPTIAN HIEROGLYPH S012 +132DF ; [.5329.0020.0002] # EGYPTIAN HIEROGLYPH S013 +132E0 ; [.532A.0020.0002] # EGYPTIAN HIEROGLYPH S014 +132E1 ; [.532B.0020.0002] # EGYPTIAN HIEROGLYPH S014A +132E2 ; [.532C.0020.0002] # EGYPTIAN HIEROGLYPH S014B +132E3 ; [.532D.0020.0002] # EGYPTIAN HIEROGLYPH S015 +132E4 ; [.532E.0020.0002] # EGYPTIAN HIEROGLYPH S016 +132E5 ; [.532F.0020.0002] # EGYPTIAN HIEROGLYPH S017 +132E6 ; [.5330.0020.0002] # EGYPTIAN HIEROGLYPH S017A +132E7 ; [.5331.0020.0002] # EGYPTIAN HIEROGLYPH S018 +132E8 ; [.5332.0020.0002] # EGYPTIAN HIEROGLYPH S019 +132E9 ; [.5333.0020.0002] # EGYPTIAN HIEROGLYPH S020 +132EA ; [.5334.0020.0002] # EGYPTIAN HIEROGLYPH S021 +132EB ; [.5335.0020.0002] # EGYPTIAN HIEROGLYPH S022 +132EC ; [.5336.0020.0002] # EGYPTIAN HIEROGLYPH S023 +132ED ; [.5337.0020.0002] # EGYPTIAN HIEROGLYPH S024 +132EE ; [.5338.0020.0002] # EGYPTIAN HIEROGLYPH S025 +132EF ; [.5339.0020.0002] # EGYPTIAN HIEROGLYPH S026 +132F0 ; [.533A.0020.0002] # EGYPTIAN HIEROGLYPH S026A +132F1 ; [.533B.0020.0002] # EGYPTIAN HIEROGLYPH S026B +132F2 ; [.533C.0020.0002] # EGYPTIAN HIEROGLYPH S027 +132F3 ; [.533D.0020.0002] # EGYPTIAN HIEROGLYPH S028 +132F4 ; [.533E.0020.0002] # EGYPTIAN HIEROGLYPH S029 +132F5 ; [.533F.0020.0002] # EGYPTIAN HIEROGLYPH S030 +132F6 ; [.5340.0020.0002] # EGYPTIAN HIEROGLYPH S031 +132F7 ; [.5341.0020.0002] # EGYPTIAN HIEROGLYPH S032 +132F8 ; [.5342.0020.0002] # EGYPTIAN HIEROGLYPH S033 +132F9 ; [.5343.0020.0002] # EGYPTIAN HIEROGLYPH S034 +132FA ; [.5344.0020.0002] # EGYPTIAN HIEROGLYPH S035 +132FB ; [.5345.0020.0002] # EGYPTIAN HIEROGLYPH S035A +132FC ; [.5346.0020.0002] # EGYPTIAN HIEROGLYPH S036 +132FD ; [.5347.0020.0002] # EGYPTIAN HIEROGLYPH S037 +132FE ; [.5348.0020.0002] # EGYPTIAN HIEROGLYPH S038 +132FF ; [.5349.0020.0002] # EGYPTIAN HIEROGLYPH S039 +13300 ; [.534A.0020.0002] # EGYPTIAN HIEROGLYPH S040 +13301 ; [.534B.0020.0002] # EGYPTIAN HIEROGLYPH S041 +13302 ; [.534C.0020.0002] # EGYPTIAN HIEROGLYPH S042 +13303 ; [.534D.0020.0002] # EGYPTIAN HIEROGLYPH S043 +13304 ; [.534E.0020.0002] # EGYPTIAN HIEROGLYPH S044 +13305 ; [.534F.0020.0002] # EGYPTIAN HIEROGLYPH S045 +13306 ; [.5350.0020.0002] # EGYPTIAN HIEROGLYPH S046 +13307 ; [.5351.0020.0002] # EGYPTIAN HIEROGLYPH T001 +13308 ; [.5352.0020.0002] # EGYPTIAN HIEROGLYPH T002 +13309 ; [.5353.0020.0002] # EGYPTIAN HIEROGLYPH T003 +1330A ; [.5354.0020.0002] # EGYPTIAN HIEROGLYPH T003A +1330B ; [.5355.0020.0002] # EGYPTIAN HIEROGLYPH T004 +1330C ; [.5356.0020.0002] # EGYPTIAN HIEROGLYPH T005 +1330D ; [.5357.0020.0002] # EGYPTIAN HIEROGLYPH T006 +1330E ; [.5358.0020.0002] # EGYPTIAN HIEROGLYPH T007 +1330F ; [.5359.0020.0002] # EGYPTIAN HIEROGLYPH T007A +13310 ; [.535A.0020.0002] # EGYPTIAN HIEROGLYPH T008 +13311 ; [.535B.0020.0002] # EGYPTIAN HIEROGLYPH T008A +13312 ; [.535C.0020.0002] # EGYPTIAN HIEROGLYPH T009 +13313 ; [.535D.0020.0002] # EGYPTIAN HIEROGLYPH T009A +13314 ; [.535E.0020.0002] # EGYPTIAN HIEROGLYPH T010 +13315 ; [.535F.0020.0002] # EGYPTIAN HIEROGLYPH T011 +13316 ; [.5360.0020.0002] # EGYPTIAN HIEROGLYPH T011A +13317 ; [.5361.0020.0002] # EGYPTIAN HIEROGLYPH T012 +13318 ; [.5362.0020.0002] # EGYPTIAN HIEROGLYPH T013 +13319 ; [.5363.0020.0002] # EGYPTIAN HIEROGLYPH T014 +1331A ; [.5364.0020.0002] # EGYPTIAN HIEROGLYPH T015 +1331B ; [.5365.0020.0002] # EGYPTIAN HIEROGLYPH T016 +1331C ; [.5366.0020.0002] # EGYPTIAN HIEROGLYPH T016A +1331D ; [.5367.0020.0002] # EGYPTIAN HIEROGLYPH T017 +1331E ; [.5368.0020.0002] # EGYPTIAN HIEROGLYPH T018 +1331F ; [.5369.0020.0002] # EGYPTIAN HIEROGLYPH T019 +13320 ; [.536A.0020.0002] # EGYPTIAN HIEROGLYPH T020 +13321 ; [.536B.0020.0002] # EGYPTIAN HIEROGLYPH T021 +13322 ; [.536C.0020.0002] # EGYPTIAN HIEROGLYPH T022 +13323 ; [.536D.0020.0002] # EGYPTIAN HIEROGLYPH T023 +13324 ; [.536E.0020.0002] # EGYPTIAN HIEROGLYPH T024 +13325 ; [.536F.0020.0002] # EGYPTIAN HIEROGLYPH T025 +13326 ; [.5370.0020.0002] # EGYPTIAN HIEROGLYPH T026 +13327 ; [.5371.0020.0002] # EGYPTIAN HIEROGLYPH T027 +13328 ; [.5372.0020.0002] # EGYPTIAN HIEROGLYPH T028 +13329 ; [.5373.0020.0002] # EGYPTIAN HIEROGLYPH T029 +1332A ; [.5374.0020.0002] # EGYPTIAN HIEROGLYPH T030 +1332B ; [.5375.0020.0002] # EGYPTIAN HIEROGLYPH T031 +1332C ; [.5376.0020.0002] # EGYPTIAN HIEROGLYPH T032 +1332D ; [.5377.0020.0002] # EGYPTIAN HIEROGLYPH T032A +1332E ; [.5378.0020.0002] # EGYPTIAN HIEROGLYPH T033 +1332F ; [.5379.0020.0002] # EGYPTIAN HIEROGLYPH T033A +13330 ; [.537A.0020.0002] # EGYPTIAN HIEROGLYPH T034 +13331 ; [.537B.0020.0002] # EGYPTIAN HIEROGLYPH T035 +13332 ; [.537C.0020.0002] # EGYPTIAN HIEROGLYPH T036 +13333 ; [.537D.0020.0002] # EGYPTIAN HIEROGLYPH U001 +13334 ; [.537E.0020.0002] # EGYPTIAN HIEROGLYPH U002 +13335 ; [.537F.0020.0002] # EGYPTIAN HIEROGLYPH U003 +13336 ; [.5380.0020.0002] # EGYPTIAN HIEROGLYPH U004 +13337 ; [.5381.0020.0002] # EGYPTIAN HIEROGLYPH U005 +13338 ; [.5382.0020.0002] # EGYPTIAN HIEROGLYPH U006 +13339 ; [.5383.0020.0002] # EGYPTIAN HIEROGLYPH U006A +1333A ; [.5384.0020.0002] # EGYPTIAN HIEROGLYPH U006B +1333B ; [.5385.0020.0002] # EGYPTIAN HIEROGLYPH U007 +1333C ; [.5386.0020.0002] # EGYPTIAN HIEROGLYPH U008 +1333D ; [.5387.0020.0002] # EGYPTIAN HIEROGLYPH U009 +1333E ; [.5388.0020.0002] # EGYPTIAN HIEROGLYPH U010 +1333F ; [.5389.0020.0002] # EGYPTIAN HIEROGLYPH U011 +13340 ; [.538A.0020.0002] # EGYPTIAN HIEROGLYPH U012 +13341 ; [.538B.0020.0002] # EGYPTIAN HIEROGLYPH U013 +13342 ; [.538C.0020.0002] # EGYPTIAN HIEROGLYPH U014 +13343 ; [.538D.0020.0002] # EGYPTIAN HIEROGLYPH U015 +13344 ; [.538E.0020.0002] # EGYPTIAN HIEROGLYPH U016 +13345 ; [.538F.0020.0002] # EGYPTIAN HIEROGLYPH U017 +13346 ; [.5390.0020.0002] # EGYPTIAN HIEROGLYPH U018 +13347 ; [.5391.0020.0002] # EGYPTIAN HIEROGLYPH U019 +13348 ; [.5392.0020.0002] # EGYPTIAN HIEROGLYPH U020 +13349 ; [.5393.0020.0002] # EGYPTIAN HIEROGLYPH U021 +1334A ; [.5394.0020.0002] # EGYPTIAN HIEROGLYPH U022 +1334B ; [.5395.0020.0002] # EGYPTIAN HIEROGLYPH U023 +1334C ; [.5396.0020.0002] # EGYPTIAN HIEROGLYPH U023A +1334D ; [.5397.0020.0002] # EGYPTIAN HIEROGLYPH U024 +1334E ; [.5398.0020.0002] # EGYPTIAN HIEROGLYPH U025 +1334F ; [.5399.0020.0002] # EGYPTIAN HIEROGLYPH U026 +13350 ; [.539A.0020.0002] # EGYPTIAN HIEROGLYPH U027 +13351 ; [.539B.0020.0002] # EGYPTIAN HIEROGLYPH U028 +13352 ; [.539C.0020.0002] # EGYPTIAN HIEROGLYPH U029 +13353 ; [.539D.0020.0002] # EGYPTIAN HIEROGLYPH U029A +13354 ; [.539E.0020.0002] # EGYPTIAN HIEROGLYPH U030 +13355 ; [.539F.0020.0002] # EGYPTIAN HIEROGLYPH U031 +13356 ; [.53A0.0020.0002] # EGYPTIAN HIEROGLYPH U032 +13357 ; [.53A1.0020.0002] # EGYPTIAN HIEROGLYPH U032A +13358 ; [.53A2.0020.0002] # EGYPTIAN HIEROGLYPH U033 +13359 ; [.53A3.0020.0002] # EGYPTIAN HIEROGLYPH U034 +1335A ; [.53A4.0020.0002] # EGYPTIAN HIEROGLYPH U035 +1335B ; [.53A5.0020.0002] # EGYPTIAN HIEROGLYPH U036 +1335C ; [.53A6.0020.0002] # EGYPTIAN HIEROGLYPH U037 +1335D ; [.53A7.0020.0002] # EGYPTIAN HIEROGLYPH U038 +1335E ; [.53A8.0020.0002] # EGYPTIAN HIEROGLYPH U039 +1335F ; [.53A9.0020.0002] # EGYPTIAN HIEROGLYPH U040 +13360 ; [.53AA.0020.0002] # EGYPTIAN HIEROGLYPH U041 +13361 ; [.53AB.0020.0002] # EGYPTIAN HIEROGLYPH U042 +13362 ; [.53AC.0020.0002] # EGYPTIAN HIEROGLYPH V001 +13363 ; [.53AD.0020.0002] # EGYPTIAN HIEROGLYPH V001A +13364 ; [.53AE.0020.0002] # EGYPTIAN HIEROGLYPH V001B +13365 ; [.53AF.0020.0002] # EGYPTIAN HIEROGLYPH V001C +13366 ; [.53B0.0020.0002] # EGYPTIAN HIEROGLYPH V001D +13367 ; [.53B1.0020.0002] # EGYPTIAN HIEROGLYPH V001E +13368 ; [.53B2.0020.0002] # EGYPTIAN HIEROGLYPH V001F +13369 ; [.53B3.0020.0002] # EGYPTIAN HIEROGLYPH V001G +1336A ; [.53B4.0020.0002] # EGYPTIAN HIEROGLYPH V001H +1336B ; [.53B5.0020.0002] # EGYPTIAN HIEROGLYPH V001I +1336C ; [.53B6.0020.0002] # EGYPTIAN HIEROGLYPH V002 +1336D ; [.53B7.0020.0002] # EGYPTIAN HIEROGLYPH V002A +1336E ; [.53B8.0020.0002] # EGYPTIAN HIEROGLYPH V003 +1336F ; [.53B9.0020.0002] # EGYPTIAN HIEROGLYPH V004 +13370 ; [.53BA.0020.0002] # EGYPTIAN HIEROGLYPH V005 +13371 ; [.53BB.0020.0002] # EGYPTIAN HIEROGLYPH V006 +13372 ; [.53BC.0020.0002] # EGYPTIAN HIEROGLYPH V007 +13373 ; [.53BD.0020.0002] # EGYPTIAN HIEROGLYPH V007A +13374 ; [.53BE.0020.0002] # EGYPTIAN HIEROGLYPH V007B +13375 ; [.53BF.0020.0002] # EGYPTIAN HIEROGLYPH V008 +13376 ; [.53C0.0020.0002] # EGYPTIAN HIEROGLYPH V009 +13377 ; [.53C1.0020.0002] # EGYPTIAN HIEROGLYPH V010 +13378 ; [.53C2.0020.0002] # EGYPTIAN HIEROGLYPH V011 +13379 ; [.53C3.0020.0002] # EGYPTIAN HIEROGLYPH V011A +1337A ; [.53C4.0020.0002] # EGYPTIAN HIEROGLYPH V011B +1337B ; [.53C5.0020.0002] # EGYPTIAN HIEROGLYPH V011C +1337C ; [.53C6.0020.0002] # EGYPTIAN HIEROGLYPH V012 +1337D ; [.53C7.0020.0002] # EGYPTIAN HIEROGLYPH V012A +1337E ; [.53C8.0020.0002] # EGYPTIAN HIEROGLYPH V012B +1337F ; [.53C9.0020.0002] # EGYPTIAN HIEROGLYPH V013 +13380 ; [.53CA.0020.0002] # EGYPTIAN HIEROGLYPH V014 +13381 ; [.53CB.0020.0002] # EGYPTIAN HIEROGLYPH V015 +13382 ; [.53CC.0020.0002] # EGYPTIAN HIEROGLYPH V016 +13383 ; [.53CD.0020.0002] # EGYPTIAN HIEROGLYPH V017 +13384 ; [.53CE.0020.0002] # EGYPTIAN HIEROGLYPH V018 +13385 ; [.53CF.0020.0002] # EGYPTIAN HIEROGLYPH V019 +13386 ; [.53D0.0020.0002] # EGYPTIAN HIEROGLYPH V020 +13387 ; [.53D1.0020.0002] # EGYPTIAN HIEROGLYPH V020A +13388 ; [.53D2.0020.0002] # EGYPTIAN HIEROGLYPH V020B +13389 ; [.53D3.0020.0002] # EGYPTIAN HIEROGLYPH V020C +1338A ; [.53D4.0020.0002] # EGYPTIAN HIEROGLYPH V020D +1338B ; [.53D5.0020.0002] # EGYPTIAN HIEROGLYPH V020E +1338C ; [.53D6.0020.0002] # EGYPTIAN HIEROGLYPH V020F +1338D ; [.53D7.0020.0002] # EGYPTIAN HIEROGLYPH V020G +1338E ; [.53D8.0020.0002] # EGYPTIAN HIEROGLYPH V020H +1338F ; [.53D9.0020.0002] # EGYPTIAN HIEROGLYPH V020I +13390 ; [.53DA.0020.0002] # EGYPTIAN HIEROGLYPH V020J +13391 ; [.53DB.0020.0002] # EGYPTIAN HIEROGLYPH V020K +13392 ; [.53DC.0020.0002] # EGYPTIAN HIEROGLYPH V020L +13393 ; [.53DD.0020.0002] # EGYPTIAN HIEROGLYPH V021 +13394 ; [.53DE.0020.0002] # EGYPTIAN HIEROGLYPH V022 +13395 ; [.53DF.0020.0002] # EGYPTIAN HIEROGLYPH V023 +13396 ; [.53E0.0020.0002] # EGYPTIAN HIEROGLYPH V023A +13397 ; [.53E1.0020.0002] # EGYPTIAN HIEROGLYPH V024 +13398 ; [.53E2.0020.0002] # EGYPTIAN HIEROGLYPH V025 +13399 ; [.53E3.0020.0002] # EGYPTIAN HIEROGLYPH V026 +1339A ; [.53E4.0020.0002] # EGYPTIAN HIEROGLYPH V027 +1339B ; [.53E5.0020.0002] # EGYPTIAN HIEROGLYPH V028 +1339C ; [.53E6.0020.0002] # EGYPTIAN HIEROGLYPH V028A +1339D ; [.53E7.0020.0002] # EGYPTIAN HIEROGLYPH V029 +1339E ; [.53E8.0020.0002] # EGYPTIAN HIEROGLYPH V029A +1339F ; [.53E9.0020.0002] # EGYPTIAN HIEROGLYPH V030 +133A0 ; [.53EA.0020.0002] # EGYPTIAN HIEROGLYPH V030A +133A1 ; [.53EB.0020.0002] # EGYPTIAN HIEROGLYPH V031 +133A2 ; [.53EC.0020.0002] # EGYPTIAN HIEROGLYPH V031A +133A3 ; [.53ED.0020.0002] # EGYPTIAN HIEROGLYPH V032 +133A4 ; [.53EE.0020.0002] # EGYPTIAN HIEROGLYPH V033 +133A5 ; [.53EF.0020.0002] # EGYPTIAN HIEROGLYPH V033A +133A6 ; [.53F0.0020.0002] # EGYPTIAN HIEROGLYPH V034 +133A7 ; [.53F1.0020.0002] # EGYPTIAN HIEROGLYPH V035 +133A8 ; [.53F2.0020.0002] # EGYPTIAN HIEROGLYPH V036 +133A9 ; [.53F3.0020.0002] # EGYPTIAN HIEROGLYPH V037 +133AA ; [.53F4.0020.0002] # EGYPTIAN HIEROGLYPH V037A +133AB ; [.53F5.0020.0002] # EGYPTIAN HIEROGLYPH V038 +133AC ; [.53F6.0020.0002] # EGYPTIAN HIEROGLYPH V039 +133AD ; [.53F7.0020.0002] # EGYPTIAN HIEROGLYPH V040 +133AE ; [.53F8.0020.0002] # EGYPTIAN HIEROGLYPH V040A +133AF ; [.53F9.0020.0002] # EGYPTIAN HIEROGLYPH W001 +133B0 ; [.53FA.0020.0002] # EGYPTIAN HIEROGLYPH W002 +133B1 ; [.53FB.0020.0002] # EGYPTIAN HIEROGLYPH W003 +133B2 ; [.53FC.0020.0002] # EGYPTIAN HIEROGLYPH W003A +133B3 ; [.53FD.0020.0002] # EGYPTIAN HIEROGLYPH W004 +133B4 ; [.53FE.0020.0002] # EGYPTIAN HIEROGLYPH W005 +133B5 ; [.53FF.0020.0002] # EGYPTIAN HIEROGLYPH W006 +133B6 ; [.5400.0020.0002] # EGYPTIAN HIEROGLYPH W007 +133B7 ; [.5401.0020.0002] # EGYPTIAN HIEROGLYPH W008 +133B8 ; [.5402.0020.0002] # EGYPTIAN HIEROGLYPH W009 +133B9 ; [.5403.0020.0002] # EGYPTIAN HIEROGLYPH W009A +133BA ; [.5404.0020.0002] # EGYPTIAN HIEROGLYPH W010 +133BB ; [.5405.0020.0002] # EGYPTIAN HIEROGLYPH W010A +133BC ; [.5406.0020.0002] # EGYPTIAN HIEROGLYPH W011 +133BD ; [.5407.0020.0002] # EGYPTIAN HIEROGLYPH W012 +133BE ; [.5408.0020.0002] # EGYPTIAN HIEROGLYPH W013 +133BF ; [.5409.0020.0002] # EGYPTIAN HIEROGLYPH W014 +133C0 ; [.540A.0020.0002] # EGYPTIAN HIEROGLYPH W014A +133C1 ; [.540B.0020.0002] # EGYPTIAN HIEROGLYPH W015 +133C2 ; [.540C.0020.0002] # EGYPTIAN HIEROGLYPH W016 +133C3 ; [.540D.0020.0002] # EGYPTIAN HIEROGLYPH W017 +133C4 ; [.540E.0020.0002] # EGYPTIAN HIEROGLYPH W017A +133C5 ; [.540F.0020.0002] # EGYPTIAN HIEROGLYPH W018 +133C6 ; [.5410.0020.0002] # EGYPTIAN HIEROGLYPH W018A +133C7 ; [.5411.0020.0002] # EGYPTIAN HIEROGLYPH W019 +133C8 ; [.5412.0020.0002] # EGYPTIAN HIEROGLYPH W020 +133C9 ; [.5413.0020.0002] # EGYPTIAN HIEROGLYPH W021 +133CA ; [.5414.0020.0002] # EGYPTIAN HIEROGLYPH W022 +133CB ; [.5415.0020.0002] # EGYPTIAN HIEROGLYPH W023 +133CC ; [.5416.0020.0002] # EGYPTIAN HIEROGLYPH W024 +133CD ; [.5417.0020.0002] # EGYPTIAN HIEROGLYPH W024A +133CE ; [.5418.0020.0002] # EGYPTIAN HIEROGLYPH W025 +133CF ; [.5419.0020.0002] # EGYPTIAN HIEROGLYPH X001 +133D0 ; [.541A.0020.0002] # EGYPTIAN HIEROGLYPH X002 +133D1 ; [.541B.0020.0002] # EGYPTIAN HIEROGLYPH X003 +133D2 ; [.541C.0020.0002] # EGYPTIAN HIEROGLYPH X004 +133D3 ; [.541D.0020.0002] # EGYPTIAN HIEROGLYPH X004A +133D4 ; [.541E.0020.0002] # EGYPTIAN HIEROGLYPH X004B +133D5 ; [.541F.0020.0002] # EGYPTIAN HIEROGLYPH X005 +133D6 ; [.5420.0020.0002] # EGYPTIAN HIEROGLYPH X006 +133D7 ; [.5421.0020.0002] # EGYPTIAN HIEROGLYPH X006A +133D8 ; [.5422.0020.0002] # EGYPTIAN HIEROGLYPH X007 +133D9 ; [.5423.0020.0002] # EGYPTIAN HIEROGLYPH X008 +133DA ; [.5424.0020.0002] # EGYPTIAN HIEROGLYPH X008A +133DB ; [.5425.0020.0002] # EGYPTIAN HIEROGLYPH Y001 +133DC ; [.5426.0020.0002] # EGYPTIAN HIEROGLYPH Y001A +133DD ; [.5427.0020.0002] # EGYPTIAN HIEROGLYPH Y002 +133DE ; [.5428.0020.0002] # EGYPTIAN HIEROGLYPH Y003 +133DF ; [.5429.0020.0002] # EGYPTIAN HIEROGLYPH Y004 +133E0 ; [.542A.0020.0002] # EGYPTIAN HIEROGLYPH Y005 +133E1 ; [.542B.0020.0002] # EGYPTIAN HIEROGLYPH Y006 +133E2 ; [.542C.0020.0002] # EGYPTIAN HIEROGLYPH Y007 +133E3 ; [.542D.0020.0002] # EGYPTIAN HIEROGLYPH Y008 +133E4 ; [.542E.0020.0002] # EGYPTIAN HIEROGLYPH Z001 +133E5 ; [.542F.0020.0002] # EGYPTIAN HIEROGLYPH Z002 +133E6 ; [.5430.0020.0002] # EGYPTIAN HIEROGLYPH Z002A +133E7 ; [.5431.0020.0002] # EGYPTIAN HIEROGLYPH Z002B +133E8 ; [.5432.0020.0002] # EGYPTIAN HIEROGLYPH Z002C +133E9 ; [.5433.0020.0002] # EGYPTIAN HIEROGLYPH Z002D +133EA ; [.5434.0020.0002] # EGYPTIAN HIEROGLYPH Z003 +133EB ; [.5435.0020.0002] # EGYPTIAN HIEROGLYPH Z003A +133EC ; [.5436.0020.0002] # EGYPTIAN HIEROGLYPH Z003B +133ED ; [.5437.0020.0002] # EGYPTIAN HIEROGLYPH Z004 +133EE ; [.5438.0020.0002] # EGYPTIAN HIEROGLYPH Z004A +133EF ; [.5439.0020.0002] # EGYPTIAN HIEROGLYPH Z005 +133F0 ; [.543A.0020.0002] # EGYPTIAN HIEROGLYPH Z005A +133F1 ; [.543B.0020.0002] # EGYPTIAN HIEROGLYPH Z006 +133F2 ; [.543C.0020.0002] # EGYPTIAN HIEROGLYPH Z007 +133F3 ; [.543D.0020.0002] # EGYPTIAN HIEROGLYPH Z008 +133F4 ; [.543E.0020.0002] # EGYPTIAN HIEROGLYPH Z009 +133F5 ; [.543F.0020.0002] # EGYPTIAN HIEROGLYPH Z010 +133F6 ; [.5440.0020.0002] # EGYPTIAN HIEROGLYPH Z011 +133F7 ; [.5441.0020.0002] # EGYPTIAN HIEROGLYPH Z012 +133F8 ; [.5442.0020.0002] # EGYPTIAN HIEROGLYPH Z013 +133F9 ; [.5443.0020.0002] # EGYPTIAN HIEROGLYPH Z014 +133FA ; [.5444.0020.0002] # EGYPTIAN HIEROGLYPH Z015 +133FB ; [.5445.0020.0002] # EGYPTIAN HIEROGLYPH Z015A +133FC ; [.5446.0020.0002] # EGYPTIAN HIEROGLYPH Z015B +133FD ; [.5447.0020.0002] # EGYPTIAN HIEROGLYPH Z015C +133FE ; [.5448.0020.0002] # EGYPTIAN HIEROGLYPH Z015D +133FF ; [.5449.0020.0002] # EGYPTIAN HIEROGLYPH Z015E +13400 ; [.544A.0020.0002] # EGYPTIAN HIEROGLYPH Z015F +13401 ; [.544B.0020.0002] # EGYPTIAN HIEROGLYPH Z015G +13402 ; [.544C.0020.0002] # EGYPTIAN HIEROGLYPH Z015H +13403 ; [.544D.0020.0002] # EGYPTIAN HIEROGLYPH Z015I +13404 ; [.544E.0020.0002] # EGYPTIAN HIEROGLYPH Z016 +13405 ; [.544F.0020.0002] # EGYPTIAN HIEROGLYPH Z016A +13406 ; [.5450.0020.0002] # EGYPTIAN HIEROGLYPH Z016B +13407 ; [.5451.0020.0002] # EGYPTIAN HIEROGLYPH Z016C +13408 ; [.5452.0020.0002] # EGYPTIAN HIEROGLYPH Z016D +13409 ; [.5453.0020.0002] # EGYPTIAN HIEROGLYPH Z016E +1340A ; [.5454.0020.0002] # EGYPTIAN HIEROGLYPH Z016F +1340B ; [.5455.0020.0002] # EGYPTIAN HIEROGLYPH Z016G +1340C ; [.5456.0020.0002] # EGYPTIAN HIEROGLYPH Z016H +1340D ; [.5457.0020.0002] # EGYPTIAN HIEROGLYPH AA001 +1340E ; [.5458.0020.0002] # EGYPTIAN HIEROGLYPH AA002 +1340F ; [.5459.0020.0002] # EGYPTIAN HIEROGLYPH AA003 +13410 ; [.545A.0020.0002] # EGYPTIAN HIEROGLYPH AA004 +13411 ; [.545B.0020.0002] # EGYPTIAN HIEROGLYPH AA005 +13412 ; [.545C.0020.0002] # EGYPTIAN HIEROGLYPH AA006 +13413 ; [.545D.0020.0002] # EGYPTIAN HIEROGLYPH AA007 +13414 ; [.545E.0020.0002] # EGYPTIAN HIEROGLYPH AA007A +13415 ; [.545F.0020.0002] # EGYPTIAN HIEROGLYPH AA007B +13416 ; [.5460.0020.0002] # EGYPTIAN HIEROGLYPH AA008 +13417 ; [.5461.0020.0002] # EGYPTIAN HIEROGLYPH AA009 +13418 ; [.5462.0020.0002] # EGYPTIAN HIEROGLYPH AA010 +13419 ; [.5463.0020.0002] # EGYPTIAN HIEROGLYPH AA011 +1341A ; [.5464.0020.0002] # EGYPTIAN HIEROGLYPH AA012 +1341B ; [.5465.0020.0002] # EGYPTIAN HIEROGLYPH AA013 +1341C ; [.5466.0020.0002] # EGYPTIAN HIEROGLYPH AA014 +1341D ; [.5467.0020.0002] # EGYPTIAN HIEROGLYPH AA015 +1341E ; [.5468.0020.0002] # EGYPTIAN HIEROGLYPH AA016 +1341F ; [.5469.0020.0002] # EGYPTIAN HIEROGLYPH AA017 +13420 ; [.546A.0020.0002] # EGYPTIAN HIEROGLYPH AA018 +13421 ; [.546B.0020.0002] # EGYPTIAN HIEROGLYPH AA019 +13422 ; [.546C.0020.0002] # EGYPTIAN HIEROGLYPH AA020 +13423 ; [.546D.0020.0002] # EGYPTIAN HIEROGLYPH AA021 +13424 ; [.546E.0020.0002] # EGYPTIAN HIEROGLYPH AA022 +13425 ; [.546F.0020.0002] # EGYPTIAN HIEROGLYPH AA023 +13426 ; [.5470.0020.0002] # EGYPTIAN HIEROGLYPH AA024 +13427 ; [.5471.0020.0002] # EGYPTIAN HIEROGLYPH AA025 +13428 ; [.5472.0020.0002] # EGYPTIAN HIEROGLYPH AA026 +13429 ; [.5473.0020.0002] # EGYPTIAN HIEROGLYPH AA027 +1342A ; [.5474.0020.0002] # EGYPTIAN HIEROGLYPH AA028 +1342B ; [.5475.0020.0002] # EGYPTIAN HIEROGLYPH AA029 +1342C ; [.5476.0020.0002] # EGYPTIAN HIEROGLYPH AA030 +1342D ; [.5477.0020.0002] # EGYPTIAN HIEROGLYPH AA031 +1342E ; [.5478.0020.0002] # EGYPTIAN HIEROGLYPH AA032 +109A0 ; [.5479.0020.0002] # MEROITIC CURSIVE LETTER A +10980 ; [.5479.0020.0004][.0000.0111.0004] # MEROITIC HIEROGLYPHIC LETTER A +109A1 ; [.547A.0020.0002] # MEROITIC CURSIVE LETTER E +10981 ; [.547A.0020.0004][.0000.0111.0004] # MEROITIC HIEROGLYPHIC LETTER E +109A2 ; [.547B.0020.0002] # MEROITIC CURSIVE LETTER I +10982 ; [.547B.0020.0004][.0000.0111.0004] # MEROITIC HIEROGLYPHIC LETTER I +109A3 ; [.547C.0020.0002] # MEROITIC CURSIVE LETTER O +10983 ; [.547C.0020.0004][.0000.0111.0004] # MEROITIC HIEROGLYPHIC LETTER O +109A4 ; [.547D.0020.0002] # MEROITIC CURSIVE LETTER YA +10984 ; [.547D.0020.0004][.0000.0111.0004] # MEROITIC HIEROGLYPHIC LETTER YA +109A5 ; [.547E.0020.0002] # MEROITIC CURSIVE LETTER WA +10985 ; [.547E.0020.0004][.0000.0111.0004] # MEROITIC HIEROGLYPHIC LETTER WA +109A6 ; [.547F.0020.0002] # MEROITIC CURSIVE LETTER BA +10986 ; [.547F.0020.0004][.0000.0111.0004] # MEROITIC HIEROGLYPHIC LETTER BA +10987 ; [.547F.0020.0004][.0000.0112.0004] # MEROITIC HIEROGLYPHIC LETTER BA-2 +109A7 ; [.5480.0020.0002] # MEROITIC CURSIVE LETTER PA +10988 ; [.5480.0020.0004][.0000.0111.0004] # MEROITIC HIEROGLYPHIC LETTER PA +109A8 ; [.5481.0020.0002] # MEROITIC CURSIVE LETTER MA +10989 ; [.5481.0020.0004][.0000.0111.0004] # MEROITIC HIEROGLYPHIC LETTER MA +109A9 ; [.5482.0020.0002] # MEROITIC CURSIVE LETTER NA +1098A ; [.5482.0020.0004][.0000.0111.0004] # MEROITIC HIEROGLYPHIC LETTER NA +1098B ; [.5482.0020.0004][.0000.0112.0004] # MEROITIC HIEROGLYPHIC LETTER NA-2 +109AA ; [.5483.0020.0002] # MEROITIC CURSIVE LETTER NE +1098C ; [.5483.0020.0004][.0000.0111.0004] # MEROITIC HIEROGLYPHIC LETTER NE +1098D ; [.5483.0020.0004][.0000.0112.0004] # MEROITIC HIEROGLYPHIC LETTER NE-2 +109AB ; [.5484.0020.0002] # MEROITIC CURSIVE LETTER RA +1098E ; [.5484.0020.0004][.0000.0111.0004] # MEROITIC HIEROGLYPHIC LETTER RA +1098F ; [.5484.0020.0004][.0000.0112.0004] # MEROITIC HIEROGLYPHIC LETTER RA-2 +109AC ; [.5485.0020.0002] # MEROITIC CURSIVE LETTER LA +10990 ; [.5485.0020.0004][.0000.0111.0004] # MEROITIC HIEROGLYPHIC LETTER LA +109AD ; [.5486.0020.0002] # MEROITIC CURSIVE LETTER KHA +10991 ; [.5486.0020.0004][.0000.0111.0004] # MEROITIC HIEROGLYPHIC LETTER KHA +109AE ; [.5487.0020.0002] # MEROITIC CURSIVE LETTER HHA +10992 ; [.5487.0020.0004][.0000.0111.0004] # MEROITIC HIEROGLYPHIC LETTER HHA +109AF ; [.5488.0020.0002] # MEROITIC CURSIVE LETTER SA +109B0 ; [.5488.0020.0004][.0000.0111.0004] # MEROITIC CURSIVE LETTER ARCHAIC SA +10993 ; [.5488.0020.0004][.0000.0112.0004] # MEROITIC HIEROGLYPHIC LETTER SA +10994 ; [.5488.0020.0004][.0000.0113.0004] # MEROITIC HIEROGLYPHIC LETTER SA-2 +109B1 ; [.5489.0020.0002] # MEROITIC CURSIVE LETTER SE +10995 ; [.5489.0020.0004][.0000.0111.0004] # MEROITIC HIEROGLYPHIC LETTER SE +109B2 ; [.548A.0020.0002] # MEROITIC CURSIVE LETTER KA +10996 ; [.548A.0020.0004][.0000.0111.0004] # MEROITIC HIEROGLYPHIC LETTER KA +109B3 ; [.548B.0020.0002] # MEROITIC CURSIVE LETTER QA +10997 ; [.548B.0020.0004][.0000.0111.0004] # MEROITIC HIEROGLYPHIC LETTER QA +109B4 ; [.548C.0020.0002] # MEROITIC CURSIVE LETTER TA +10998 ; [.548C.0020.0004][.0000.0111.0004] # MEROITIC HIEROGLYPHIC LETTER TA +10999 ; [.548C.0020.0004][.0000.0112.0004] # MEROITIC HIEROGLYPHIC LETTER TA-2 +109B5 ; [.548D.0020.0002] # MEROITIC CURSIVE LETTER TE +1099A ; [.548D.0020.0004][.0000.0111.0004] # MEROITIC HIEROGLYPHIC LETTER TE +1099B ; [.548D.0020.0004][.0000.0112.0004] # MEROITIC HIEROGLYPHIC LETTER TE-2 +109B6 ; [.548E.0020.0002] # MEROITIC CURSIVE LETTER TO +1099C ; [.548E.0020.0004][.0000.0111.0004] # MEROITIC HIEROGLYPHIC LETTER TO +109B7 ; [.548F.0020.0002] # MEROITIC CURSIVE LETTER DA +1099D ; [.548F.0020.0004][.0000.0111.0004] # MEROITIC HIEROGLYPHIC LETTER DA +109BE ; [.5490.0020.0002] # MEROITIC CURSIVE LOGOGRAM RMT +109BF ; [.5491.0020.0002] # MEROITIC CURSIVE LOGOGRAM IMN +1099E ; [.5492.0020.0002] # MEROITIC HIEROGLYPHIC SYMBOL VIDJ +1099F ; [.5493.0020.0002] # MEROITIC HIEROGLYPHIC SYMBOL VIDJ-2 +14400 ; [.5494.0020.0002] # ANATOLIAN HIEROGLYPH A001 +14401 ; [.5495.0020.0002] # ANATOLIAN HIEROGLYPH A002 +14402 ; [.5496.0020.0002] # ANATOLIAN HIEROGLYPH A003 +14403 ; [.5497.0020.0002] # ANATOLIAN HIEROGLYPH A004 +14404 ; [.5498.0020.0002] # ANATOLIAN HIEROGLYPH A005 +14405 ; [.5499.0020.0002] # ANATOLIAN HIEROGLYPH A006 +14406 ; [.549A.0020.0002] # ANATOLIAN HIEROGLYPH A007 +14407 ; [.549B.0020.0002] # ANATOLIAN HIEROGLYPH A008 +14408 ; [.549C.0020.0002] # ANATOLIAN HIEROGLYPH A009 +14409 ; [.549D.0020.0002] # ANATOLIAN HIEROGLYPH A010 +1440A ; [.549E.0020.0002] # ANATOLIAN HIEROGLYPH A010A +1440B ; [.549F.0020.0002] # ANATOLIAN HIEROGLYPH A011 +1440C ; [.54A0.0020.0002] # ANATOLIAN HIEROGLYPH A012 +1440D ; [.54A1.0020.0002] # ANATOLIAN HIEROGLYPH A013 +1440E ; [.54A2.0020.0002] # ANATOLIAN HIEROGLYPH A014 +1440F ; [.54A3.0020.0002] # ANATOLIAN HIEROGLYPH A015 +14410 ; [.54A4.0020.0002] # ANATOLIAN HIEROGLYPH A016 +14411 ; [.54A5.0020.0002] # ANATOLIAN HIEROGLYPH A017 +14412 ; [.54A6.0020.0002] # ANATOLIAN HIEROGLYPH A018 +14413 ; [.54A7.0020.0002] # ANATOLIAN HIEROGLYPH A019 +14414 ; [.54A8.0020.0002] # ANATOLIAN HIEROGLYPH A020 +14415 ; [.54A9.0020.0002] # ANATOLIAN HIEROGLYPH A021 +14416 ; [.54AA.0020.0002] # ANATOLIAN HIEROGLYPH A022 +14417 ; [.54AB.0020.0002] # ANATOLIAN HIEROGLYPH A023 +14418 ; [.54AC.0020.0002] # ANATOLIAN HIEROGLYPH A024 +14419 ; [.54AD.0020.0002] # ANATOLIAN HIEROGLYPH A025 +1441A ; [.54AE.0020.0002] # ANATOLIAN HIEROGLYPH A026 +1441B ; [.54AF.0020.0002] # ANATOLIAN HIEROGLYPH A026A +1441C ; [.54B0.0020.0002] # ANATOLIAN HIEROGLYPH A027 +1441D ; [.54B1.0020.0002] # ANATOLIAN HIEROGLYPH A028 +1441E ; [.54B2.0020.0002] # ANATOLIAN HIEROGLYPH A029 +1441F ; [.54B3.0020.0002] # ANATOLIAN HIEROGLYPH A030 +14420 ; [.54B4.0020.0002] # ANATOLIAN HIEROGLYPH A031 +14421 ; [.54B5.0020.0002] # ANATOLIAN HIEROGLYPH A032 +14422 ; [.54B6.0020.0002] # ANATOLIAN HIEROGLYPH A033 +14423 ; [.54B7.0020.0002] # ANATOLIAN HIEROGLYPH A034 +14424 ; [.54B8.0020.0002] # ANATOLIAN HIEROGLYPH A035 +14425 ; [.54B9.0020.0002] # ANATOLIAN HIEROGLYPH A036 +14426 ; [.54BA.0020.0002] # ANATOLIAN HIEROGLYPH A037 +14427 ; [.54BB.0020.0002] # ANATOLIAN HIEROGLYPH A038 +14428 ; [.54BC.0020.0002] # ANATOLIAN HIEROGLYPH A039 +14429 ; [.54BD.0020.0002] # ANATOLIAN HIEROGLYPH A039A +1442A ; [.54BE.0020.0002] # ANATOLIAN HIEROGLYPH A040 +1442B ; [.54BF.0020.0002] # ANATOLIAN HIEROGLYPH A041 +1442C ; [.54C0.0020.0002] # ANATOLIAN HIEROGLYPH A041A +1442D ; [.54C1.0020.0002] # ANATOLIAN HIEROGLYPH A042 +1442E ; [.54C2.0020.0002] # ANATOLIAN HIEROGLYPH A043 +1442F ; [.54C3.0020.0002] # ANATOLIAN HIEROGLYPH A044 +14430 ; [.54C4.0020.0002] # ANATOLIAN HIEROGLYPH A045 +14431 ; [.54C5.0020.0002] # ANATOLIAN HIEROGLYPH A045A +14432 ; [.54C6.0020.0002] # ANATOLIAN HIEROGLYPH A046 +14433 ; [.54C7.0020.0002] # ANATOLIAN HIEROGLYPH A046A +14434 ; [.54C8.0020.0002] # ANATOLIAN HIEROGLYPH A046B +14435 ; [.54C9.0020.0002] # ANATOLIAN HIEROGLYPH A047 +14436 ; [.54CA.0020.0002] # ANATOLIAN HIEROGLYPH A048 +14437 ; [.54CB.0020.0002] # ANATOLIAN HIEROGLYPH A049 +14438 ; [.54CC.0020.0002] # ANATOLIAN HIEROGLYPH A050 +14439 ; [.54CD.0020.0002] # ANATOLIAN HIEROGLYPH A051 +1443A ; [.54CE.0020.0002] # ANATOLIAN HIEROGLYPH A052 +1443B ; [.54CF.0020.0002] # ANATOLIAN HIEROGLYPH A053 +1443C ; [.54D0.0020.0002] # ANATOLIAN HIEROGLYPH A054 +1443D ; [.54D1.0020.0002] # ANATOLIAN HIEROGLYPH A055 +1443E ; [.54D2.0020.0002] # ANATOLIAN HIEROGLYPH A056 +1443F ; [.54D3.0020.0002] # ANATOLIAN HIEROGLYPH A057 +14440 ; [.54D4.0020.0002] # ANATOLIAN HIEROGLYPH A058 +14441 ; [.54D5.0020.0002] # ANATOLIAN HIEROGLYPH A059 +14442 ; [.54D6.0020.0002] # ANATOLIAN HIEROGLYPH A060 +14443 ; [.54D7.0020.0002] # ANATOLIAN HIEROGLYPH A061 +14444 ; [.54D8.0020.0002] # ANATOLIAN HIEROGLYPH A062 +14445 ; [.54D9.0020.0002] # ANATOLIAN HIEROGLYPH A063 +14446 ; [.54DA.0020.0002] # ANATOLIAN HIEROGLYPH A064 +14447 ; [.54DB.0020.0002] # ANATOLIAN HIEROGLYPH A065 +14448 ; [.54DC.0020.0002] # ANATOLIAN HIEROGLYPH A066 +14449 ; [.54DD.0020.0002] # ANATOLIAN HIEROGLYPH A066A +1444A ; [.54DE.0020.0002] # ANATOLIAN HIEROGLYPH A066B +1444B ; [.54DF.0020.0002] # ANATOLIAN HIEROGLYPH A066C +1444C ; [.54E0.0020.0002] # ANATOLIAN HIEROGLYPH A067 +1444D ; [.54E1.0020.0002] # ANATOLIAN HIEROGLYPH A068 +1444E ; [.54E2.0020.0002] # ANATOLIAN HIEROGLYPH A069 +1444F ; [.54E3.0020.0002] # ANATOLIAN HIEROGLYPH A070 +14450 ; [.54E4.0020.0002] # ANATOLIAN HIEROGLYPH A071 +14451 ; [.54E5.0020.0002] # ANATOLIAN HIEROGLYPH A072 +14452 ; [.54E6.0020.0002] # ANATOLIAN HIEROGLYPH A073 +14453 ; [.54E7.0020.0002] # ANATOLIAN HIEROGLYPH A074 +14454 ; [.54E8.0020.0002] # ANATOLIAN HIEROGLYPH A075 +14455 ; [.54E9.0020.0002] # ANATOLIAN HIEROGLYPH A076 +14456 ; [.54EA.0020.0002] # ANATOLIAN HIEROGLYPH A077 +14457 ; [.54EB.0020.0002] # ANATOLIAN HIEROGLYPH A078 +14458 ; [.54EC.0020.0002] # ANATOLIAN HIEROGLYPH A079 +14459 ; [.54ED.0020.0002] # ANATOLIAN HIEROGLYPH A080 +1445A ; [.54EE.0020.0002] # ANATOLIAN HIEROGLYPH A081 +1445B ; [.54EF.0020.0002] # ANATOLIAN HIEROGLYPH A082 +1445C ; [.54F0.0020.0002] # ANATOLIAN HIEROGLYPH A083 +1445D ; [.54F1.0020.0002] # ANATOLIAN HIEROGLYPH A084 +1445E ; [.54F2.0020.0002] # ANATOLIAN HIEROGLYPH A085 +1445F ; [.54F3.0020.0002] # ANATOLIAN HIEROGLYPH A086 +14460 ; [.54F4.0020.0002] # ANATOLIAN HIEROGLYPH A087 +14461 ; [.54F5.0020.0002] # ANATOLIAN HIEROGLYPH A088 +14462 ; [.54F6.0020.0002] # ANATOLIAN HIEROGLYPH A089 +14463 ; [.54F7.0020.0002] # ANATOLIAN HIEROGLYPH A090 +14464 ; [.54F8.0020.0002] # ANATOLIAN HIEROGLYPH A091 +14465 ; [.54F9.0020.0002] # ANATOLIAN HIEROGLYPH A092 +14466 ; [.54FA.0020.0002] # ANATOLIAN HIEROGLYPH A093 +14467 ; [.54FB.0020.0002] # ANATOLIAN HIEROGLYPH A094 +14468 ; [.54FC.0020.0002] # ANATOLIAN HIEROGLYPH A095 +14469 ; [.54FD.0020.0002] # ANATOLIAN HIEROGLYPH A096 +1446A ; [.54FE.0020.0002] # ANATOLIAN HIEROGLYPH A097 +1446B ; [.54FF.0020.0002] # ANATOLIAN HIEROGLYPH A097A +1446C ; [.5500.0020.0002] # ANATOLIAN HIEROGLYPH A098 +1446D ; [.5501.0020.0002] # ANATOLIAN HIEROGLYPH A098A +1446E ; [.5502.0020.0002] # ANATOLIAN HIEROGLYPH A099 +1446F ; [.5503.0020.0002] # ANATOLIAN HIEROGLYPH A100 +14470 ; [.5504.0020.0002] # ANATOLIAN HIEROGLYPH A100A +14471 ; [.5505.0020.0002] # ANATOLIAN HIEROGLYPH A101 +14472 ; [.5506.0020.0002] # ANATOLIAN HIEROGLYPH A101A +14473 ; [.5507.0020.0002] # ANATOLIAN HIEROGLYPH A102 +14474 ; [.5508.0020.0002] # ANATOLIAN HIEROGLYPH A102A +14475 ; [.5509.0020.0002] # ANATOLIAN HIEROGLYPH A103 +14476 ; [.550A.0020.0002] # ANATOLIAN HIEROGLYPH A104 +14477 ; [.550B.0020.0002] # ANATOLIAN HIEROGLYPH A104A +14478 ; [.550C.0020.0002] # ANATOLIAN HIEROGLYPH A104B +14479 ; [.550D.0020.0002] # ANATOLIAN HIEROGLYPH A104C +1447A ; [.550E.0020.0002] # ANATOLIAN HIEROGLYPH A105 +1447B ; [.550F.0020.0002] # ANATOLIAN HIEROGLYPH A105A +1447C ; [.5510.0020.0002] # ANATOLIAN HIEROGLYPH A105B +1447D ; [.5511.0020.0002] # ANATOLIAN HIEROGLYPH A106 +1447E ; [.5512.0020.0002] # ANATOLIAN HIEROGLYPH A107 +1447F ; [.5513.0020.0002] # ANATOLIAN HIEROGLYPH A107A +14480 ; [.5514.0020.0002] # ANATOLIAN HIEROGLYPH A107B +14481 ; [.5515.0020.0002] # ANATOLIAN HIEROGLYPH A107C +14482 ; [.5516.0020.0002] # ANATOLIAN HIEROGLYPH A108 +14483 ; [.5517.0020.0002] # ANATOLIAN HIEROGLYPH A109 +14484 ; [.5518.0020.0002] # ANATOLIAN HIEROGLYPH A110 +14485 ; [.5519.0020.0002] # ANATOLIAN HIEROGLYPH A110A +14486 ; [.551A.0020.0002] # ANATOLIAN HIEROGLYPH A110B +14487 ; [.551B.0020.0002] # ANATOLIAN HIEROGLYPH A111 +14488 ; [.551C.0020.0002] # ANATOLIAN HIEROGLYPH A112 +14489 ; [.551D.0020.0002] # ANATOLIAN HIEROGLYPH A113 +1448A ; [.551E.0020.0002] # ANATOLIAN HIEROGLYPH A114 +1448B ; [.551F.0020.0002] # ANATOLIAN HIEROGLYPH A115 +1448C ; [.5520.0020.0002] # ANATOLIAN HIEROGLYPH A115A +1448D ; [.5521.0020.0002] # ANATOLIAN HIEROGLYPH A116 +1448E ; [.5522.0020.0002] # ANATOLIAN HIEROGLYPH A117 +1448F ; [.5523.0020.0002] # ANATOLIAN HIEROGLYPH A118 +14490 ; [.5524.0020.0002] # ANATOLIAN HIEROGLYPH A119 +14491 ; [.5525.0020.0002] # ANATOLIAN HIEROGLYPH A120 +14492 ; [.5526.0020.0002] # ANATOLIAN HIEROGLYPH A121 +14493 ; [.5527.0020.0002] # ANATOLIAN HIEROGLYPH A122 +14494 ; [.5528.0020.0002] # ANATOLIAN HIEROGLYPH A123 +14495 ; [.5529.0020.0002] # ANATOLIAN HIEROGLYPH A124 +14496 ; [.552A.0020.0002] # ANATOLIAN HIEROGLYPH A125 +14497 ; [.552B.0020.0002] # ANATOLIAN HIEROGLYPH A125A +14498 ; [.552C.0020.0002] # ANATOLIAN HIEROGLYPH A126 +14499 ; [.552D.0020.0002] # ANATOLIAN HIEROGLYPH A127 +1449A ; [.552E.0020.0002] # ANATOLIAN HIEROGLYPH A128 +1449B ; [.552F.0020.0002] # ANATOLIAN HIEROGLYPH A129 +1449C ; [.5530.0020.0002] # ANATOLIAN HIEROGLYPH A130 +1449D ; [.5531.0020.0002] # ANATOLIAN HIEROGLYPH A131 +1449E ; [.5532.0020.0002] # ANATOLIAN HIEROGLYPH A132 +1449F ; [.5533.0020.0002] # ANATOLIAN HIEROGLYPH A133 +144A0 ; [.5534.0020.0002] # ANATOLIAN HIEROGLYPH A134 +144A1 ; [.5535.0020.0002] # ANATOLIAN HIEROGLYPH A135 +144A2 ; [.5536.0020.0002] # ANATOLIAN HIEROGLYPH A135A +144A3 ; [.5537.0020.0002] # ANATOLIAN HIEROGLYPH A136 +144A4 ; [.5538.0020.0002] # ANATOLIAN HIEROGLYPH A137 +144A5 ; [.5539.0020.0002] # ANATOLIAN HIEROGLYPH A138 +144A6 ; [.553A.0020.0002] # ANATOLIAN HIEROGLYPH A139 +144A7 ; [.553B.0020.0002] # ANATOLIAN HIEROGLYPH A140 +144A8 ; [.553C.0020.0002] # ANATOLIAN HIEROGLYPH A141 +144A9 ; [.553D.0020.0002] # ANATOLIAN HIEROGLYPH A142 +144AA ; [.553E.0020.0002] # ANATOLIAN HIEROGLYPH A143 +144AB ; [.553F.0020.0002] # ANATOLIAN HIEROGLYPH A144 +144AC ; [.5540.0020.0002] # ANATOLIAN HIEROGLYPH A145 +144AD ; [.5541.0020.0002] # ANATOLIAN HIEROGLYPH A146 +144AE ; [.5542.0020.0002] # ANATOLIAN HIEROGLYPH A147 +144AF ; [.5543.0020.0002] # ANATOLIAN HIEROGLYPH A148 +144B0 ; [.5544.0020.0002] # ANATOLIAN HIEROGLYPH A149 +144B1 ; [.5545.0020.0002] # ANATOLIAN HIEROGLYPH A150 +144B2 ; [.5546.0020.0002] # ANATOLIAN HIEROGLYPH A151 +144B3 ; [.5547.0020.0002] # ANATOLIAN HIEROGLYPH A152 +144B4 ; [.5548.0020.0002] # ANATOLIAN HIEROGLYPH A153 +144B5 ; [.5549.0020.0002] # ANATOLIAN HIEROGLYPH A154 +144B6 ; [.554A.0020.0002] # ANATOLIAN HIEROGLYPH A155 +144B7 ; [.554B.0020.0002] # ANATOLIAN HIEROGLYPH A156 +144B8 ; [.554C.0020.0002] # ANATOLIAN HIEROGLYPH A157 +144B9 ; [.554D.0020.0002] # ANATOLIAN HIEROGLYPH A158 +144BA ; [.554E.0020.0002] # ANATOLIAN HIEROGLYPH A159 +144BB ; [.554F.0020.0002] # ANATOLIAN HIEROGLYPH A160 +144BC ; [.5550.0020.0002] # ANATOLIAN HIEROGLYPH A161 +144BD ; [.5551.0020.0002] # ANATOLIAN HIEROGLYPH A162 +144BE ; [.5552.0020.0002] # ANATOLIAN HIEROGLYPH A163 +144BF ; [.5553.0020.0002] # ANATOLIAN HIEROGLYPH A164 +144C0 ; [.5554.0020.0002] # ANATOLIAN HIEROGLYPH A165 +144C1 ; [.5555.0020.0002] # ANATOLIAN HIEROGLYPH A166 +144C2 ; [.5556.0020.0002] # ANATOLIAN HIEROGLYPH A167 +144C3 ; [.5557.0020.0002] # ANATOLIAN HIEROGLYPH A168 +144C4 ; [.5558.0020.0002] # ANATOLIAN HIEROGLYPH A169 +144C5 ; [.5559.0020.0002] # ANATOLIAN HIEROGLYPH A170 +144C6 ; [.555A.0020.0002] # ANATOLIAN HIEROGLYPH A171 +144C7 ; [.555B.0020.0002] # ANATOLIAN HIEROGLYPH A172 +144C8 ; [.555C.0020.0002] # ANATOLIAN HIEROGLYPH A173 +144C9 ; [.555D.0020.0002] # ANATOLIAN HIEROGLYPH A174 +144CA ; [.555E.0020.0002] # ANATOLIAN HIEROGLYPH A175 +144CB ; [.555F.0020.0002] # ANATOLIAN HIEROGLYPH A176 +144CC ; [.5560.0020.0002] # ANATOLIAN HIEROGLYPH A177 +144CD ; [.5561.0020.0002] # ANATOLIAN HIEROGLYPH A178 +144CE ; [.5562.0020.0002] # ANATOLIAN HIEROGLYPH A179 +144CF ; [.5563.0020.0002] # ANATOLIAN HIEROGLYPH A180 +144D0 ; [.5564.0020.0002] # ANATOLIAN HIEROGLYPH A181 +144D1 ; [.5565.0020.0002] # ANATOLIAN HIEROGLYPH A182 +144D2 ; [.5566.0020.0002] # ANATOLIAN HIEROGLYPH A183 +144D3 ; [.5567.0020.0002] # ANATOLIAN HIEROGLYPH A184 +144D4 ; [.5568.0020.0002] # ANATOLIAN HIEROGLYPH A185 +144D5 ; [.5569.0020.0002] # ANATOLIAN HIEROGLYPH A186 +144D6 ; [.556A.0020.0002] # ANATOLIAN HIEROGLYPH A187 +144D7 ; [.556B.0020.0002] # ANATOLIAN HIEROGLYPH A188 +144D8 ; [.556C.0020.0002] # ANATOLIAN HIEROGLYPH A189 +144D9 ; [.556D.0020.0002] # ANATOLIAN HIEROGLYPH A190 +144DA ; [.556E.0020.0002] # ANATOLIAN HIEROGLYPH A191 +144DB ; [.556F.0020.0002] # ANATOLIAN HIEROGLYPH A192 +144DC ; [.5570.0020.0002] # ANATOLIAN HIEROGLYPH A193 +144DD ; [.5571.0020.0002] # ANATOLIAN HIEROGLYPH A194 +144DE ; [.5572.0020.0002] # ANATOLIAN HIEROGLYPH A195 +144DF ; [.5573.0020.0002] # ANATOLIAN HIEROGLYPH A196 +144E0 ; [.5574.0020.0002] # ANATOLIAN HIEROGLYPH A197 +144E1 ; [.5575.0020.0002] # ANATOLIAN HIEROGLYPH A198 +144E2 ; [.5576.0020.0002] # ANATOLIAN HIEROGLYPH A199 +144E3 ; [.5577.0020.0002] # ANATOLIAN HIEROGLYPH A200 +144E4 ; [.5578.0020.0002] # ANATOLIAN HIEROGLYPH A201 +144E5 ; [.5579.0020.0002] # ANATOLIAN HIEROGLYPH A202 +144E6 ; [.557A.0020.0002] # ANATOLIAN HIEROGLYPH A202A +144E7 ; [.557B.0020.0002] # ANATOLIAN HIEROGLYPH A202B +144E8 ; [.557C.0020.0002] # ANATOLIAN HIEROGLYPH A203 +144E9 ; [.557D.0020.0002] # ANATOLIAN HIEROGLYPH A204 +144EA ; [.557E.0020.0002] # ANATOLIAN HIEROGLYPH A205 +144EB ; [.557F.0020.0002] # ANATOLIAN HIEROGLYPH A206 +144EC ; [.5580.0020.0002] # ANATOLIAN HIEROGLYPH A207 +144ED ; [.5581.0020.0002] # ANATOLIAN HIEROGLYPH A207A +144EE ; [.5582.0020.0002] # ANATOLIAN HIEROGLYPH A208 +144EF ; [.5583.0020.0002] # ANATOLIAN HIEROGLYPH A209 +144F0 ; [.5584.0020.0002] # ANATOLIAN HIEROGLYPH A209A +144F1 ; [.5585.0020.0002] # ANATOLIAN HIEROGLYPH A210 +144F2 ; [.5586.0020.0002] # ANATOLIAN HIEROGLYPH A211 +144F3 ; [.5587.0020.0002] # ANATOLIAN HIEROGLYPH A212 +144F4 ; [.5588.0020.0002] # ANATOLIAN HIEROGLYPH A213 +144F5 ; [.5589.0020.0002] # ANATOLIAN HIEROGLYPH A214 +144F6 ; [.558A.0020.0002] # ANATOLIAN HIEROGLYPH A215 +144F7 ; [.558B.0020.0002] # ANATOLIAN HIEROGLYPH A215A +144F8 ; [.558C.0020.0002] # ANATOLIAN HIEROGLYPH A216 +144F9 ; [.558D.0020.0002] # ANATOLIAN HIEROGLYPH A216A +144FA ; [.558E.0020.0002] # ANATOLIAN HIEROGLYPH A217 +144FB ; [.558F.0020.0002] # ANATOLIAN HIEROGLYPH A218 +144FC ; [.5590.0020.0002] # ANATOLIAN HIEROGLYPH A219 +144FD ; [.5591.0020.0002] # ANATOLIAN HIEROGLYPH A220 +144FE ; [.5592.0020.0002] # ANATOLIAN HIEROGLYPH A221 +144FF ; [.5593.0020.0002] # ANATOLIAN HIEROGLYPH A222 +14500 ; [.5594.0020.0002] # ANATOLIAN HIEROGLYPH A223 +14501 ; [.5595.0020.0002] # ANATOLIAN HIEROGLYPH A224 +14502 ; [.5596.0020.0002] # ANATOLIAN HIEROGLYPH A225 +14503 ; [.5597.0020.0002] # ANATOLIAN HIEROGLYPH A226 +14504 ; [.5598.0020.0002] # ANATOLIAN HIEROGLYPH A227 +14505 ; [.5599.0020.0002] # ANATOLIAN HIEROGLYPH A227A +14506 ; [.559A.0020.0002] # ANATOLIAN HIEROGLYPH A228 +14507 ; [.559B.0020.0002] # ANATOLIAN HIEROGLYPH A229 +14508 ; [.559C.0020.0002] # ANATOLIAN HIEROGLYPH A230 +14509 ; [.559D.0020.0002] # ANATOLIAN HIEROGLYPH A231 +1450A ; [.559E.0020.0002] # ANATOLIAN HIEROGLYPH A232 +1450B ; [.559F.0020.0002] # ANATOLIAN HIEROGLYPH A233 +1450C ; [.55A0.0020.0002] # ANATOLIAN HIEROGLYPH A234 +1450D ; [.55A1.0020.0002] # ANATOLIAN HIEROGLYPH A235 +1450E ; [.55A2.0020.0002] # ANATOLIAN HIEROGLYPH A236 +1450F ; [.55A3.0020.0002] # ANATOLIAN HIEROGLYPH A237 +14510 ; [.55A4.0020.0002] # ANATOLIAN HIEROGLYPH A238 +14511 ; [.55A5.0020.0002] # ANATOLIAN HIEROGLYPH A239 +14512 ; [.55A6.0020.0002] # ANATOLIAN HIEROGLYPH A240 +14513 ; [.55A7.0020.0002] # ANATOLIAN HIEROGLYPH A241 +14514 ; [.55A8.0020.0002] # ANATOLIAN HIEROGLYPH A242 +14515 ; [.55A9.0020.0002] # ANATOLIAN HIEROGLYPH A243 +14516 ; [.55AA.0020.0002] # ANATOLIAN HIEROGLYPH A244 +14517 ; [.55AB.0020.0002] # ANATOLIAN HIEROGLYPH A245 +14518 ; [.55AC.0020.0002] # ANATOLIAN HIEROGLYPH A246 +14519 ; [.55AD.0020.0002] # ANATOLIAN HIEROGLYPH A247 +1451A ; [.55AE.0020.0002] # ANATOLIAN HIEROGLYPH A248 +1451B ; [.55AF.0020.0002] # ANATOLIAN HIEROGLYPH A249 +1451C ; [.55B0.0020.0002] # ANATOLIAN HIEROGLYPH A250 +1451D ; [.55B1.0020.0002] # ANATOLIAN HIEROGLYPH A251 +1451E ; [.55B2.0020.0002] # ANATOLIAN HIEROGLYPH A252 +1451F ; [.55B3.0020.0002] # ANATOLIAN HIEROGLYPH A253 +14520 ; [.55B4.0020.0002] # ANATOLIAN HIEROGLYPH A254 +14521 ; [.55B5.0020.0002] # ANATOLIAN HIEROGLYPH A255 +14522 ; [.55B6.0020.0002] # ANATOLIAN HIEROGLYPH A256 +14523 ; [.55B7.0020.0002] # ANATOLIAN HIEROGLYPH A257 +14524 ; [.55B8.0020.0002] # ANATOLIAN HIEROGLYPH A258 +14525 ; [.55B9.0020.0002] # ANATOLIAN HIEROGLYPH A259 +14526 ; [.55BA.0020.0002] # ANATOLIAN HIEROGLYPH A260 +14527 ; [.55BB.0020.0002] # ANATOLIAN HIEROGLYPH A261 +14528 ; [.55BC.0020.0002] # ANATOLIAN HIEROGLYPH A262 +14529 ; [.55BD.0020.0002] # ANATOLIAN HIEROGLYPH A263 +1452A ; [.55BE.0020.0002] # ANATOLIAN HIEROGLYPH A264 +1452B ; [.55BF.0020.0002] # ANATOLIAN HIEROGLYPH A265 +1452C ; [.55C0.0020.0002] # ANATOLIAN HIEROGLYPH A266 +1452D ; [.55C1.0020.0002] # ANATOLIAN HIEROGLYPH A267 +1452E ; [.55C2.0020.0002] # ANATOLIAN HIEROGLYPH A267A +1452F ; [.55C3.0020.0002] # ANATOLIAN HIEROGLYPH A268 +14530 ; [.55C4.0020.0002] # ANATOLIAN HIEROGLYPH A269 +14531 ; [.55C5.0020.0002] # ANATOLIAN HIEROGLYPH A270 +14532 ; [.55C6.0020.0002] # ANATOLIAN HIEROGLYPH A271 +14533 ; [.55C7.0020.0002] # ANATOLIAN HIEROGLYPH A272 +14534 ; [.55C8.0020.0002] # ANATOLIAN HIEROGLYPH A273 +14535 ; [.55C9.0020.0002] # ANATOLIAN HIEROGLYPH A274 +14536 ; [.55CA.0020.0002] # ANATOLIAN HIEROGLYPH A275 +14537 ; [.55CB.0020.0002] # ANATOLIAN HIEROGLYPH A276 +14538 ; [.55CC.0020.0002] # ANATOLIAN HIEROGLYPH A277 +14539 ; [.55CD.0020.0002] # ANATOLIAN HIEROGLYPH A278 +1453A ; [.55CE.0020.0002] # ANATOLIAN HIEROGLYPH A279 +1453B ; [.55CF.0020.0002] # ANATOLIAN HIEROGLYPH A280 +1453C ; [.55D0.0020.0002] # ANATOLIAN HIEROGLYPH A281 +1453D ; [.55D1.0020.0002] # ANATOLIAN HIEROGLYPH A282 +1453E ; [.55D2.0020.0002] # ANATOLIAN HIEROGLYPH A283 +1453F ; [.55D3.0020.0002] # ANATOLIAN HIEROGLYPH A284 +14540 ; [.55D4.0020.0002] # ANATOLIAN HIEROGLYPH A285 +14541 ; [.55D5.0020.0002] # ANATOLIAN HIEROGLYPH A286 +14542 ; [.55D6.0020.0002] # ANATOLIAN HIEROGLYPH A287 +14543 ; [.55D7.0020.0002] # ANATOLIAN HIEROGLYPH A288 +14544 ; [.55D8.0020.0002] # ANATOLIAN HIEROGLYPH A289 +14545 ; [.55D9.0020.0002] # ANATOLIAN HIEROGLYPH A289A +14546 ; [.55DA.0020.0002] # ANATOLIAN HIEROGLYPH A290 +14547 ; [.55DB.0020.0002] # ANATOLIAN HIEROGLYPH A291 +14548 ; [.55DC.0020.0002] # ANATOLIAN HIEROGLYPH A292 +14549 ; [.55DD.0020.0002] # ANATOLIAN HIEROGLYPH A293 +1454A ; [.55DE.0020.0002] # ANATOLIAN HIEROGLYPH A294 +1454B ; [.55DF.0020.0002] # ANATOLIAN HIEROGLYPH A294A +1454C ; [.55E0.0020.0002] # ANATOLIAN HIEROGLYPH A295 +1454D ; [.55E1.0020.0002] # ANATOLIAN HIEROGLYPH A296 +1454E ; [.55E2.0020.0002] # ANATOLIAN HIEROGLYPH A297 +1454F ; [.55E3.0020.0002] # ANATOLIAN HIEROGLYPH A298 +14550 ; [.55E4.0020.0002] # ANATOLIAN HIEROGLYPH A299 +14551 ; [.55E5.0020.0002] # ANATOLIAN HIEROGLYPH A299A +14552 ; [.55E6.0020.0002] # ANATOLIAN HIEROGLYPH A300 +14553 ; [.55E7.0020.0002] # ANATOLIAN HIEROGLYPH A301 +14554 ; [.55E8.0020.0002] # ANATOLIAN HIEROGLYPH A302 +14555 ; [.55E9.0020.0002] # ANATOLIAN HIEROGLYPH A303 +14556 ; [.55EA.0020.0002] # ANATOLIAN HIEROGLYPH A304 +14557 ; [.55EB.0020.0002] # ANATOLIAN HIEROGLYPH A305 +14558 ; [.55EC.0020.0002] # ANATOLIAN HIEROGLYPH A306 +14559 ; [.55ED.0020.0002] # ANATOLIAN HIEROGLYPH A307 +1455A ; [.55EE.0020.0002] # ANATOLIAN HIEROGLYPH A308 +1455B ; [.55EF.0020.0002] # ANATOLIAN HIEROGLYPH A309 +1455C ; [.55F0.0020.0002] # ANATOLIAN HIEROGLYPH A309A +1455D ; [.55F1.0020.0002] # ANATOLIAN HIEROGLYPH A310 +1455E ; [.55F2.0020.0002] # ANATOLIAN HIEROGLYPH A311 +1455F ; [.55F3.0020.0002] # ANATOLIAN HIEROGLYPH A312 +14560 ; [.55F4.0020.0002] # ANATOLIAN HIEROGLYPH A313 +14561 ; [.55F5.0020.0002] # ANATOLIAN HIEROGLYPH A314 +14562 ; [.55F6.0020.0002] # ANATOLIAN HIEROGLYPH A315 +14563 ; [.55F7.0020.0002] # ANATOLIAN HIEROGLYPH A316 +14564 ; [.55F8.0020.0002] # ANATOLIAN HIEROGLYPH A317 +14565 ; [.55F9.0020.0002] # ANATOLIAN HIEROGLYPH A318 +14566 ; [.55FA.0020.0002] # ANATOLIAN HIEROGLYPH A319 +14567 ; [.55FB.0020.0002] # ANATOLIAN HIEROGLYPH A320 +14568 ; [.55FC.0020.0002] # ANATOLIAN HIEROGLYPH A321 +14569 ; [.55FD.0020.0002] # ANATOLIAN HIEROGLYPH A322 +1456A ; [.55FE.0020.0002] # ANATOLIAN HIEROGLYPH A323 +1456B ; [.55FF.0020.0002] # ANATOLIAN HIEROGLYPH A324 +1456C ; [.5600.0020.0002] # ANATOLIAN HIEROGLYPH A325 +1456D ; [.5601.0020.0002] # ANATOLIAN HIEROGLYPH A326 +1456E ; [.5602.0020.0002] # ANATOLIAN HIEROGLYPH A327 +1456F ; [.5603.0020.0002] # ANATOLIAN HIEROGLYPH A328 +14570 ; [.5604.0020.0002] # ANATOLIAN HIEROGLYPH A329 +14571 ; [.5605.0020.0002] # ANATOLIAN HIEROGLYPH A329A +14572 ; [.5606.0020.0002] # ANATOLIAN HIEROGLYPH A330 +14573 ; [.5607.0020.0002] # ANATOLIAN HIEROGLYPH A331 +14574 ; [.5608.0020.0002] # ANATOLIAN HIEROGLYPH A332A +14575 ; [.5609.0020.0002] # ANATOLIAN HIEROGLYPH A332B +14576 ; [.560A.0020.0002] # ANATOLIAN HIEROGLYPH A332C +14577 ; [.560B.0020.0002] # ANATOLIAN HIEROGLYPH A333 +14578 ; [.560C.0020.0002] # ANATOLIAN HIEROGLYPH A334 +14579 ; [.560D.0020.0002] # ANATOLIAN HIEROGLYPH A335 +1457A ; [.560E.0020.0002] # ANATOLIAN HIEROGLYPH A336 +1457B ; [.560F.0020.0002] # ANATOLIAN HIEROGLYPH A336A +1457C ; [.5610.0020.0002] # ANATOLIAN HIEROGLYPH A336B +1457D ; [.5611.0020.0002] # ANATOLIAN HIEROGLYPH A336C +1457E ; [.5612.0020.0002] # ANATOLIAN HIEROGLYPH A337 +1457F ; [.5613.0020.0002] # ANATOLIAN HIEROGLYPH A338 +14580 ; [.5614.0020.0002] # ANATOLIAN HIEROGLYPH A339 +14581 ; [.5615.0020.0002] # ANATOLIAN HIEROGLYPH A340 +14582 ; [.5616.0020.0002] # ANATOLIAN HIEROGLYPH A341 +14583 ; [.5617.0020.0002] # ANATOLIAN HIEROGLYPH A342 +14584 ; [.5618.0020.0002] # ANATOLIAN HIEROGLYPH A343 +14585 ; [.5619.0020.0002] # ANATOLIAN HIEROGLYPH A344 +14586 ; [.561A.0020.0002] # ANATOLIAN HIEROGLYPH A345 +14587 ; [.561B.0020.0002] # ANATOLIAN HIEROGLYPH A346 +14588 ; [.561C.0020.0002] # ANATOLIAN HIEROGLYPH A347 +14589 ; [.561D.0020.0002] # ANATOLIAN HIEROGLYPH A348 +1458A ; [.561E.0020.0002] # ANATOLIAN HIEROGLYPH A349 +1458B ; [.561F.0020.0002] # ANATOLIAN HIEROGLYPH A350 +1458C ; [.5620.0020.0002] # ANATOLIAN HIEROGLYPH A351 +1458D ; [.5621.0020.0002] # ANATOLIAN HIEROGLYPH A352 +1458E ; [.5622.0020.0002] # ANATOLIAN HIEROGLYPH A353 +1458F ; [.5623.0020.0002] # ANATOLIAN HIEROGLYPH A354 +14590 ; [.5624.0020.0002] # ANATOLIAN HIEROGLYPH A355 +14591 ; [.5625.0020.0002] # ANATOLIAN HIEROGLYPH A356 +14592 ; [.5626.0020.0002] # ANATOLIAN HIEROGLYPH A357 +14593 ; [.5627.0020.0002] # ANATOLIAN HIEROGLYPH A358 +14594 ; [.5628.0020.0002] # ANATOLIAN HIEROGLYPH A359 +14595 ; [.5629.0020.0002] # ANATOLIAN HIEROGLYPH A359A +14596 ; [.562A.0020.0002] # ANATOLIAN HIEROGLYPH A360 +14597 ; [.562B.0020.0002] # ANATOLIAN HIEROGLYPH A361 +14598 ; [.562C.0020.0002] # ANATOLIAN HIEROGLYPH A362 +14599 ; [.562D.0020.0002] # ANATOLIAN HIEROGLYPH A363 +1459A ; [.562E.0020.0002] # ANATOLIAN HIEROGLYPH A364 +1459B ; [.562F.0020.0002] # ANATOLIAN HIEROGLYPH A364A +1459C ; [.5630.0020.0002] # ANATOLIAN HIEROGLYPH A365 +1459D ; [.5631.0020.0002] # ANATOLIAN HIEROGLYPH A366 +1459E ; [.5632.0020.0002] # ANATOLIAN HIEROGLYPH A367 +1459F ; [.5633.0020.0002] # ANATOLIAN HIEROGLYPH A368 +145A0 ; [.5634.0020.0002] # ANATOLIAN HIEROGLYPH A368A +145A1 ; [.5635.0020.0002] # ANATOLIAN HIEROGLYPH A369 +145A2 ; [.5636.0020.0002] # ANATOLIAN HIEROGLYPH A370 +145A3 ; [.5637.0020.0002] # ANATOLIAN HIEROGLYPH A371 +145A4 ; [.5638.0020.0002] # ANATOLIAN HIEROGLYPH A371A +145A5 ; [.5639.0020.0002] # ANATOLIAN HIEROGLYPH A372 +145A6 ; [.563A.0020.0002] # ANATOLIAN HIEROGLYPH A373 +145A7 ; [.563B.0020.0002] # ANATOLIAN HIEROGLYPH A374 +145A8 ; [.563C.0020.0002] # ANATOLIAN HIEROGLYPH A375 +145A9 ; [.563D.0020.0002] # ANATOLIAN HIEROGLYPH A376 +145AA ; [.563E.0020.0002] # ANATOLIAN HIEROGLYPH A377 +145AB ; [.563F.0020.0002] # ANATOLIAN HIEROGLYPH A378 +145AC ; [.5640.0020.0002] # ANATOLIAN HIEROGLYPH A379 +145AD ; [.5641.0020.0002] # ANATOLIAN HIEROGLYPH A380 +145AE ; [.5642.0020.0002] # ANATOLIAN HIEROGLYPH A381 +145AF ; [.5643.0020.0002] # ANATOLIAN HIEROGLYPH A381A +145B0 ; [.5644.0020.0002] # ANATOLIAN HIEROGLYPH A382 +145B1 ; [.5645.0020.0002] # ANATOLIAN HIEROGLYPH A383 RA OR RI +145B2 ; [.5646.0020.0002] # ANATOLIAN HIEROGLYPH A383A +145B3 ; [.5647.0020.0002] # ANATOLIAN HIEROGLYPH A384 +145B4 ; [.5648.0020.0002] # ANATOLIAN HIEROGLYPH A385 +145B5 ; [.5649.0020.0002] # ANATOLIAN HIEROGLYPH A386 +145B6 ; [.564A.0020.0002] # ANATOLIAN HIEROGLYPH A386A +145B7 ; [.564B.0020.0002] # ANATOLIAN HIEROGLYPH A387 +145B8 ; [.564C.0020.0002] # ANATOLIAN HIEROGLYPH A388 +145B9 ; [.564D.0020.0002] # ANATOLIAN HIEROGLYPH A389 +145BA ; [.564E.0020.0002] # ANATOLIAN HIEROGLYPH A390 +145BB ; [.564F.0020.0002] # ANATOLIAN HIEROGLYPH A391 +145BC ; [.5650.0020.0002] # ANATOLIAN HIEROGLYPH A392 +145BD ; [.5651.0020.0002] # ANATOLIAN HIEROGLYPH A393 EIGHT +145BE ; [.5652.0020.0002] # ANATOLIAN HIEROGLYPH A394 +145BF ; [.5653.0020.0002] # ANATOLIAN HIEROGLYPH A395 +145C0 ; [.5654.0020.0002] # ANATOLIAN HIEROGLYPH A396 +145C1 ; [.5655.0020.0002] # ANATOLIAN HIEROGLYPH A397 +145C2 ; [.5656.0020.0002] # ANATOLIAN HIEROGLYPH A398 +145C3 ; [.5657.0020.0002] # ANATOLIAN HIEROGLYPH A399 +145C4 ; [.5658.0020.0002] # ANATOLIAN HIEROGLYPH A400 +145C5 ; [.5659.0020.0002] # ANATOLIAN HIEROGLYPH A401 +145C6 ; [.565A.0020.0002] # ANATOLIAN HIEROGLYPH A402 +145C7 ; [.565B.0020.0002] # ANATOLIAN HIEROGLYPH A403 +145C8 ; [.565C.0020.0002] # ANATOLIAN HIEROGLYPH A404 +145C9 ; [.565D.0020.0002] # ANATOLIAN HIEROGLYPH A405 +145CA ; [.565E.0020.0002] # ANATOLIAN HIEROGLYPH A406 +145CB ; [.565F.0020.0002] # ANATOLIAN HIEROGLYPH A407 +145CC ; [.5660.0020.0002] # ANATOLIAN HIEROGLYPH A408 +145CD ; [.5661.0020.0002] # ANATOLIAN HIEROGLYPH A409 +145CE ; [.5662.0020.0002] # ANATOLIAN HIEROGLYPH A410 BEGIN LOGOGRAM MARK +145CF ; [.5663.0020.0002] # ANATOLIAN HIEROGLYPH A410A END LOGOGRAM MARK +145D0 ; [.5664.0020.0002] # ANATOLIAN HIEROGLYPH A411 +145D1 ; [.5665.0020.0002] # ANATOLIAN HIEROGLYPH A412 +145D2 ; [.5666.0020.0002] # ANATOLIAN HIEROGLYPH A413 +145D3 ; [.5667.0020.0002] # ANATOLIAN HIEROGLYPH A414 +145D4 ; [.5668.0020.0002] # ANATOLIAN HIEROGLYPH A415 +145D5 ; [.5669.0020.0002] # ANATOLIAN HIEROGLYPH A416 +145D6 ; [.566A.0020.0002] # ANATOLIAN HIEROGLYPH A417 +145D7 ; [.566B.0020.0002] # ANATOLIAN HIEROGLYPH A418 +145D8 ; [.566C.0020.0002] # ANATOLIAN HIEROGLYPH A419 +145D9 ; [.566D.0020.0002] # ANATOLIAN HIEROGLYPH A420 +145DA ; [.566E.0020.0002] # ANATOLIAN HIEROGLYPH A421 +145DB ; [.566F.0020.0002] # ANATOLIAN HIEROGLYPH A422 +145DC ; [.5670.0020.0002] # ANATOLIAN HIEROGLYPH A423 +145DD ; [.5671.0020.0002] # ANATOLIAN HIEROGLYPH A424 +145DE ; [.5672.0020.0002] # ANATOLIAN HIEROGLYPH A425 +145DF ; [.5673.0020.0002] # ANATOLIAN HIEROGLYPH A426 +145E0 ; [.5674.0020.0002] # ANATOLIAN HIEROGLYPH A427 +145E1 ; [.5675.0020.0002] # ANATOLIAN HIEROGLYPH A428 +145E2 ; [.5676.0020.0002] # ANATOLIAN HIEROGLYPH A429 +145E3 ; [.5677.0020.0002] # ANATOLIAN HIEROGLYPH A430 +145E4 ; [.5678.0020.0002] # ANATOLIAN HIEROGLYPH A431 +145E5 ; [.5679.0020.0002] # ANATOLIAN HIEROGLYPH A432 +145E6 ; [.567A.0020.0002] # ANATOLIAN HIEROGLYPH A433 +145E7 ; [.567B.0020.0002] # ANATOLIAN HIEROGLYPH A434 +145E8 ; [.567C.0020.0002] # ANATOLIAN HIEROGLYPH A435 +145E9 ; [.567D.0020.0002] # ANATOLIAN HIEROGLYPH A436 +145EA ; [.567E.0020.0002] # ANATOLIAN HIEROGLYPH A437 +145EB ; [.567F.0020.0002] # ANATOLIAN HIEROGLYPH A438 +145EC ; [.5680.0020.0002] # ANATOLIAN HIEROGLYPH A439 +145ED ; [.5681.0020.0002] # ANATOLIAN HIEROGLYPH A440 +145EE ; [.5682.0020.0002] # ANATOLIAN HIEROGLYPH A441 +145EF ; [.5683.0020.0002] # ANATOLIAN HIEROGLYPH A442 +145F0 ; [.5684.0020.0002] # ANATOLIAN HIEROGLYPH A443 +145F1 ; [.5685.0020.0002] # ANATOLIAN HIEROGLYPH A444 +145F2 ; [.5686.0020.0002] # ANATOLIAN HIEROGLYPH A445 +145F3 ; [.5687.0020.0002] # ANATOLIAN HIEROGLYPH A446 +145F4 ; [.5688.0020.0002] # ANATOLIAN HIEROGLYPH A447 +145F5 ; [.5689.0020.0002] # ANATOLIAN HIEROGLYPH A448 +145F6 ; [.568A.0020.0002] # ANATOLIAN HIEROGLYPH A449 +145F7 ; [.568B.0020.0002] # ANATOLIAN HIEROGLYPH A450 +145F8 ; [.568C.0020.0002] # ANATOLIAN HIEROGLYPH A450A +145F9 ; [.568D.0020.0002] # ANATOLIAN HIEROGLYPH A451 +145FA ; [.568E.0020.0002] # ANATOLIAN HIEROGLYPH A452 +145FB ; [.568F.0020.0002] # ANATOLIAN HIEROGLYPH A453 +145FC ; [.5690.0020.0002] # ANATOLIAN HIEROGLYPH A454 +145FD ; [.5691.0020.0002] # ANATOLIAN HIEROGLYPH A455 +145FE ; [.5692.0020.0002] # ANATOLIAN HIEROGLYPH A456 +145FF ; [.5693.0020.0002] # ANATOLIAN HIEROGLYPH A457 +14600 ; [.5694.0020.0002] # ANATOLIAN HIEROGLYPH A457A +14601 ; [.5695.0020.0002] # ANATOLIAN HIEROGLYPH A458 +14602 ; [.5696.0020.0002] # ANATOLIAN HIEROGLYPH A459 +14603 ; [.5697.0020.0002] # ANATOLIAN HIEROGLYPH A460 +14604 ; [.5698.0020.0002] # ANATOLIAN HIEROGLYPH A461 +14605 ; [.5699.0020.0002] # ANATOLIAN HIEROGLYPH A462 +14606 ; [.569A.0020.0002] # ANATOLIAN HIEROGLYPH A463 +14607 ; [.569B.0020.0002] # ANATOLIAN HIEROGLYPH A464 +14608 ; [.569C.0020.0002] # ANATOLIAN HIEROGLYPH A465 +14609 ; [.569D.0020.0002] # ANATOLIAN HIEROGLYPH A466 +1460A ; [.569E.0020.0002] # ANATOLIAN HIEROGLYPH A467 +1460B ; [.569F.0020.0002] # ANATOLIAN HIEROGLYPH A468 +1460C ; [.56A0.0020.0002] # ANATOLIAN HIEROGLYPH A469 +1460D ; [.56A1.0020.0002] # ANATOLIAN HIEROGLYPH A470 +1460E ; [.56A2.0020.0002] # ANATOLIAN HIEROGLYPH A471 +1460F ; [.56A3.0020.0002] # ANATOLIAN HIEROGLYPH A472 +14610 ; [.56A4.0020.0002] # ANATOLIAN HIEROGLYPH A473 +14611 ; [.56A5.0020.0002] # ANATOLIAN HIEROGLYPH A474 +14612 ; [.56A6.0020.0002] # ANATOLIAN HIEROGLYPH A475 +14613 ; [.56A7.0020.0002] # ANATOLIAN HIEROGLYPH A476 +14614 ; [.56A8.0020.0002] # ANATOLIAN HIEROGLYPH A477 +14615 ; [.56A9.0020.0002] # ANATOLIAN HIEROGLYPH A478 +14616 ; [.56AA.0020.0002] # ANATOLIAN HIEROGLYPH A479 +14617 ; [.56AB.0020.0002] # ANATOLIAN HIEROGLYPH A480 +14618 ; [.56AC.0020.0002] # ANATOLIAN HIEROGLYPH A481 +14619 ; [.56AD.0020.0002] # ANATOLIAN HIEROGLYPH A482 +1461A ; [.56AE.0020.0002] # ANATOLIAN HIEROGLYPH A483 +1461B ; [.56AF.0020.0002] # ANATOLIAN HIEROGLYPH A484 +1461C ; [.56B0.0020.0002] # ANATOLIAN HIEROGLYPH A485 +1461D ; [.56B1.0020.0002] # ANATOLIAN HIEROGLYPH A486 +1461E ; [.56B2.0020.0002] # ANATOLIAN HIEROGLYPH A487 +1461F ; [.56B3.0020.0002] # ANATOLIAN HIEROGLYPH A488 +14620 ; [.56B4.0020.0002] # ANATOLIAN HIEROGLYPH A489 +14621 ; [.56B5.0020.0002] # ANATOLIAN HIEROGLYPH A490 +14622 ; [.56B6.0020.0002] # ANATOLIAN HIEROGLYPH A491 +14623 ; [.56B7.0020.0002] # ANATOLIAN HIEROGLYPH A492 +14624 ; [.56B8.0020.0002] # ANATOLIAN HIEROGLYPH A493 +14625 ; [.56B9.0020.0002] # ANATOLIAN HIEROGLYPH A494 +14626 ; [.56BA.0020.0002] # ANATOLIAN HIEROGLYPH A495 +14627 ; [.56BB.0020.0002] # ANATOLIAN HIEROGLYPH A496 +14628 ; [.56BC.0020.0002] # ANATOLIAN HIEROGLYPH A497 +14629 ; [.56BD.0020.0002] # ANATOLIAN HIEROGLYPH A501 +1462A ; [.56BE.0020.0002] # ANATOLIAN HIEROGLYPH A502 +1462B ; [.56BF.0020.0002] # ANATOLIAN HIEROGLYPH A503 +1462C ; [.56C0.0020.0002] # ANATOLIAN HIEROGLYPH A504 +1462D ; [.56C1.0020.0002] # ANATOLIAN HIEROGLYPH A505 +1462E ; [.56C2.0020.0002] # ANATOLIAN HIEROGLYPH A506 +1462F ; [.56C3.0020.0002] # ANATOLIAN HIEROGLYPH A507 +14630 ; [.56C4.0020.0002] # ANATOLIAN HIEROGLYPH A508 +14631 ; [.56C5.0020.0002] # ANATOLIAN HIEROGLYPH A509 +14632 ; [.56C6.0020.0002] # ANATOLIAN HIEROGLYPH A510 +14633 ; [.56C7.0020.0002] # ANATOLIAN HIEROGLYPH A511 +14634 ; [.56C8.0020.0002] # ANATOLIAN HIEROGLYPH A512 +14635 ; [.56C9.0020.0002] # ANATOLIAN HIEROGLYPH A513 +14636 ; [.56CA.0020.0002] # ANATOLIAN HIEROGLYPH A514 +14637 ; [.56CB.0020.0002] # ANATOLIAN HIEROGLYPH A515 +14638 ; [.56CC.0020.0002] # ANATOLIAN HIEROGLYPH A516 +14639 ; [.56CD.0020.0002] # ANATOLIAN HIEROGLYPH A517 +1463A ; [.56CE.0020.0002] # ANATOLIAN HIEROGLYPH A518 +1463B ; [.56CF.0020.0002] # ANATOLIAN HIEROGLYPH A519 +1463C ; [.56D0.0020.0002] # ANATOLIAN HIEROGLYPH A520 +1463D ; [.56D1.0020.0002] # ANATOLIAN HIEROGLYPH A521 +1463E ; [.56D2.0020.0002] # ANATOLIAN HIEROGLYPH A522 +1463F ; [.56D3.0020.0002] # ANATOLIAN HIEROGLYPH A523 +14640 ; [.56D4.0020.0002] # ANATOLIAN HIEROGLYPH A524 +14641 ; [.56D5.0020.0002] # ANATOLIAN HIEROGLYPH A525 +14642 ; [.56D6.0020.0002] # ANATOLIAN HIEROGLYPH A526 +14643 ; [.56D7.0020.0002] # ANATOLIAN HIEROGLYPH A527 +14644 ; [.56D8.0020.0002] # ANATOLIAN HIEROGLYPH A528 +14645 ; [.56D9.0020.0002] # ANATOLIAN HIEROGLYPH A529 +14646 ; [.56DA.0020.0002] # ANATOLIAN HIEROGLYPH A530 +2F00 ; [.FB40.0020.0004][.CE00.0000.0000] # KANGXI RADICAL ONE +3220 ; [*0318.0020.0004][.FB40.0020.0004][.CE00.0000.0000][*0319.0020.0004] # PARENTHESIZED IDEOGRAPH ONE +3280 ; [.FB40.0020.0006][.CE00.0000.0000] # CIRCLED IDEOGRAPH ONE +3192 ; [.FB40.0020.0014][.CE00.0000.0000] # IDEOGRAPHIC ANNOTATION ONE MARK +1F229 ; [.FB40.0020.001C][.CE00.0000.0000] # SQUARED CJK UNIFIED IDEOGRAPH-4E00 +319C ; [.FB40.0020.0014][.CE01.0000.0000] # IDEOGRAPHIC ANNOTATION FOURTH MARK +3226 ; [*0318.0020.0004][.FB40.0020.0004][.CE03.0000.0000][*0319.0020.0004] # PARENTHESIZED IDEOGRAPH SEVEN +3286 ; [.FB40.0020.0006][.CE03.0000.0000] # CIRCLED IDEOGRAPH SEVEN +3222 ; [*0318.0020.0004][.FB40.0020.0004][.CE09.0000.0000][*0319.0020.0004] # PARENTHESIZED IDEOGRAPH THREE +1F241 ; [*037A.0020.0004][.FB40.0020.0004][.CE09.0000.0000][*037B.0020.0004] # TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-4E09 +3282 ; [.FB40.0020.0006][.CE09.0000.0000] # CIRCLED IDEOGRAPH THREE +3194 ; [.FB40.0020.0014][.CE09.0000.0000] # IDEOGRAPHIC ANNOTATION THREE MARK +1F22A ; [.FB40.0020.001C][.CE09.0000.0000] # SQUARED CJK UNIFIED IDEOGRAPH-4E09 +32A4 ; [.FB40.0020.0006][.CE0A.0000.0000] # CIRCLED IDEOGRAPH HIGH +3196 ; [.FB40.0020.0014][.CE0A.0000.0000] # IDEOGRAPHIC ANNOTATION TOP MARK +32A6 ; [.FB40.0020.0006][.CE0B.0000.0000] # CIRCLED IDEOGRAPH LOW +3198 ; [.FB40.0020.0014][.CE0B.0000.0000] # IDEOGRAPHIC ANNOTATION BOTTOM MARK +F967 ; [.FB40.0020.0002][.CE0D.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F967 +319B ; [.FB40.0020.0014][.CE19.0000.0000] # IDEOGRAPHIC ANNOTATION THIRD MARK +FA70 ; [.FB40.0020.0002][.CE26.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA70 +2F01 ; [.FB40.0020.0004][.CE28.0000.0000] # KANGXI RADICAL LINE +2EA6 ; [.FB40.0020.0004][.CE2C.0000.0000] # CJK RADICAL SIMPLIFIED HALF TREE TRUNK +32A5 ; [.FB40.0020.0006][.CE2D.0000.0000] # CIRCLED IDEOGRAPH CENTRE +3197 ; [.FB40.0020.0014][.CE2D.0000.0000] # IDEOGRAPHIC ANNOTATION MIDDLE MARK +1F22D ; [.FB40.0020.001C][.CE2D.0000.0000] # SQUARED CJK UNIFIED IDEOGRAPH-4E2D +F905 ; [.FB40.0020.0002][.CE32.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F905 +2F02 ; [.FB40.0020.0004][.CE36.0000.0000] # KANGXI RADICAL DOT +2E80 ; [.FB40.0020.0004][.CE36.0000.0000][.0000.0111.0004] # CJK RADICAL REPEAT +2F801 ; [.FB40.0020.0002][.CE38.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F801 +F95E ; [.FB40.0020.0002][.CE39.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F95E +2F800 ; [.FB40.0020.0002][.CE3D.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F800 +2F03 ; [.FB40.0020.0004][.CE3F.0000.0000] # KANGXI RADICAL SLASH +2F802 ; [.FB40.0020.0002][.CE41.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F802 +2F04 ; [.FB40.0020.0004][.CE59.0000.0000] # KANGXI RADICAL SECOND +319A ; [.FB40.0020.0014][.CE59.0000.0000] # IDEOGRAPHIC ANNOTATION SECOND MARK +2E84 ; [.FB40.0020.0004][.CE59.0000.0000][.0000.0111.0004] # CJK RADICAL SECOND THREE +2E83 ; [.FB40.0020.0004][.CE5A.0000.0000] # CJK RADICAL SECOND TWO +2E82 ; [.FB40.0020.0004][.CE5B.0000.0000] # CJK RADICAL SECOND ONE +3228 ; [*0318.0020.0004][.FB40.0020.0004][.CE5D.0000.0000][*0319.0020.0004] # PARENTHESIZED IDEOGRAPH NINE +3288 ; [.FB40.0020.0006][.CE5D.0000.0000] # CIRCLED IDEOGRAPH NINE +F91B ; [.FB40.0020.0002][.CE82.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F91B +2F05 ; [.FB40.0020.0004][.CE85.0000.0000] # KANGXI RADICAL HOOK +F9BA ; [.FB40.0020.0002][.CE86.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F9BA +2F06 ; [.FB40.0020.0004][.CE8C.0000.0000] # KANGXI RADICAL TWO +3221 ; [*0318.0020.0004][.FB40.0020.0004][.CE8C.0000.0000][*0319.0020.0004] # PARENTHESIZED IDEOGRAPH TWO +1F242 ; [*037A.0020.0004][.FB40.0020.0004][.CE8C.0000.0000][*037B.0020.0004] # TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-4E8C +3281 ; [.FB40.0020.0006][.CE8C.0000.0000] # CIRCLED IDEOGRAPH TWO +3193 ; [.FB40.0020.0014][.CE8C.0000.0000] # IDEOGRAPHIC ANNOTATION TWO MARK +1F214 ; [.FB40.0020.001C][.CE8C.0000.0000] # SQUARED CJK UNIFIED IDEOGRAPH-4E8C +3224 ; [*0318.0020.0004][.FB40.0020.0004][.CE94.0000.0000][*0319.0020.0004] # PARENTHESIZED IDEOGRAPH FIVE +3284 ; [.FB40.0020.0006][.CE94.0000.0000] # CIRCLED IDEOGRAPH FIVE +2F07 ; [.FB40.0020.0004][.CEA0.0000.0000] # KANGXI RADICAL LID +1F218 ; [.FB40.0020.001C][.CEA4.0000.0000] # SQUARED CJK UNIFIED IDEOGRAPH-4EA4 +F977 ; [.FB40.0020.0002][.CEAE.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F977 +2F08 ; [.FB40.0020.0004][.CEBA.0000.0000] # KANGXI RADICAL MAN +319F ; [.FB40.0020.0014][.CEBA.0000.0000] # IDEOGRAPHIC ANNOTATION MAN MARK +2E85 ; [.FB40.0020.0004][.CEBB.0000.0000] # CJK RADICAL PERSON +F9FD ; [.FB40.0020.0002][.CEC0.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F9FD +2F819 ; [.FB40.0020.0002][.CECC.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F819 +3239 ; [*0318.0020.0004][.FB40.0020.0004][.CEE3.0000.0000][*0319.0020.0004] # PARENTHESIZED IDEOGRAPH REPRESENT +F9A8 ; [.FB40.0020.0002][.CEE4.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F9A8 +323D ; [*0318.0020.0004][.FB40.0020.0004][.CF01.0000.0000][*0319.0020.0004] # PARENTHESIZED IDEOGRAPH ENTERPRISE +32AD ; [.FB40.0020.0006][.CF01.0000.0000] # CIRCLED IDEOGRAPH ENTERPRISE +3241 ; [*0318.0020.0004][.FB40.0020.0004][.CF11.0000.0000][*0319.0020.0004] # PARENTHESIZED IDEOGRAPH REST +32A1 ; [.FB40.0020.0006][.CF11.0000.0000] # CIRCLED IDEOGRAPH REST +2F804 ; [.FB40.0020.0002][.CF60.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F804 +FA73 ; [.FB40.0020.0002][.CF80.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA73 +F92D ; [.FB40.0020.0002][.CF86.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F92D +F9B5 ; [.FB40.0020.0002][.CF8B.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F9B5 +FA30 ; [.FB40.0020.0002][.CFAE.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA30 +2F805 ; [.FB40.0020.0002][.CFAE.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F805 +2F806 ; [.FB40.0020.0002][.CFBB.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F806 +F965 ; [.FB40.0020.0002][.CFBF.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F965 +2F807 ; [.FB40.0020.0002][.D002.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F807 +F9D4 ; [.FB40.0020.0002][.D02B.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F9D4 +2F808 ; [.FB40.0020.0002][.D07A.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F808 +2F809 ; [.FB40.0020.0002][.D099.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F809 +2F80B ; [.FB40.0020.0002][.D0CF.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F80B +F9BB ; [.FB40.0020.0002][.D0DA.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F9BB +FA31 ; [.FB40.0020.0002][.D0E7.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA31 +2F80A ; [.FB40.0020.0002][.D0E7.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F80A +329D ; [.FB40.0020.0006][.D12A.0000.0000] # CIRCLED IDEOGRAPH EXCELLENT +2F09 ; [.FB40.0020.0004][.D13F.0000.0000] # KANGXI RADICAL LEGS +FA0C ; [.FB40.0020.0002][.D140.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA0C +FA74 ; [.FB40.0020.0002][.D145.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA74 +FA32 ; [.FB40.0020.0002][.D14D.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA32 +2F80E ; [.FB40.0020.0002][.D14D.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F80E +2F80F ; [.FB40.0020.0002][.D154.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F80F +2F810 ; [.FB40.0020.0002][.D164.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F810 +2F0A ; [.FB40.0020.0004][.D165.0000.0000] # KANGXI RADICAL ENTER +2F814 ; [.FB40.0020.0002][.D167.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F814 +FA72 ; [.FB40.0020.0002][.D168.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA72 +F978 ; [.FB40.0020.0002][.D169.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F978 +2F0B ; [.FB40.0020.0004][.D16B.0000.0000] # KANGXI RADICAL EIGHT +3227 ; [*0318.0020.0004][.FB40.0020.0004][.D16B.0000.0000][*0319.0020.0004] # PARENTHESIZED IDEOGRAPH EIGHT +3287 ; [.FB40.0020.0006][.D16B.0000.0000] # CIRCLED IDEOGRAPH EIGHT +F9D1 ; [.FB40.0020.0002][.D16D.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F9D1 +3225 ; [*0318.0020.0004][.FB40.0020.0004][.D16D.0000.0000][*0319.0020.0004] # PARENTHESIZED IDEOGRAPH SIX +3285 ; [.FB40.0020.0006][.D16D.0000.0000] # CIRCLED IDEOGRAPH SIX +2F811 ; [.FB40.0020.0002][.D177.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F811 +FA75 ; [.FB40.0020.0002][.D180.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA75 +2F0C ; [.FB40.0020.0004][.D182.0000.0000] # KANGXI RADICAL DOWN BOX +2E86 ; [.FB40.0020.0004][.D182.0000.0000][.0000.0111.0004] # CJK RADICAL BOX +2F815 ; [.FB40.0020.0002][.D18D.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F815 +1F21E ; [.FB40.0020.001C][.D18D.0000.0000] # SQUARED CJK UNIFIED IDEOGRAPH-518D +2F8D2 ; [.FB40.0020.0002][.D192.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F8D2 +2F8D3 ; [.FB40.0020.0002][.D195.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F8D3 +2F0D ; [.FB40.0020.0004][.D196.0000.0000] # KANGXI RADICAL COVER +2F817 ; [.FB40.0020.0002][.D197.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F817 +32A2 ; [.FB40.0020.0006][.D199.0000.0000] # CIRCLED IDEOGRAPH COPY +2F818 ; [.FB40.0020.0002][.D1A4.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F818 +2F0E ; [.FB40.0020.0004][.D1AB.0000.0000] # KANGXI RADICAL ICE +2F81A ; [.FB40.0020.0002][.D1AC.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F81A +FA71 ; [.FB40.0020.0002][.D1B5.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA71 +2F81B ; [.FB40.0020.0002][.D1B5.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F81B +F92E ; [.FB40.0020.0002][.D1B7.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F92E +F979 ; [.FB40.0020.0002][.D1C9.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F979 +F955 ; [.FB40.0020.0002][.D1CC.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F955 +F954 ; [.FB40.0020.0002][.D1DC.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F954 +FA15 ; [.FB40.0020.0002][.D1DE.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA15 +2F0F ; [.FB40.0020.0004][.D1E0.0000.0000] # KANGXI RADICAL TABLE +2E87 ; [.FB40.0020.0004][.D1E0.0000.0000][.0000.0111.0004] # CJK RADICAL TABLE +2F81D ; [.FB40.0020.0002][.D1F5.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F81D +2F10 ; [.FB40.0020.0004][.D1F5.0000.0000] # KANGXI RADICAL OPEN BOX +2F11 ; [.FB40.0020.0004][.D200.0000.0000] # KANGXI RADICAL KNIFE +2E88 ; [.FB40.0020.0004][.D200.0000.0000][.0000.0111.0004] # CJK RADICAL KNIFE ONE +2E89 ; [.FB40.0020.0004][.D202.0000.0000] # CJK RADICAL KNIFE TWO +2F81E ; [.FB40.0020.0002][.D203.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F81E +FA00 ; [.FB40.0020.0002][.D207.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA00 +2F850 ; [.FB40.0020.0002][.D207.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F850 +F99C ; [.FB40.0020.0002][.D217.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F99C +1F220 ; [.FB40.0020.001C][.D21D.0000.0000] # SQUARED CJK UNIFIED IDEOGRAPH-521D +F9DD ; [.FB40.0020.0002][.D229.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F9DD +F9FF ; [.FB40.0020.0002][.D23A.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F9FF +2F820 ; [.FB40.0020.0002][.D23B.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F820 +2F821 ; [.FB40.0020.0002][.D246.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F821 +1F21C ; [.FB40.0020.001C][.D24D.0000.0000] # SQUARED CJK UNIFIED IDEOGRAPH-524D +2F822 ; [.FB40.0020.0002][.D272.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F822 +1F239 ; [.FB40.0020.001C][.D272.0000.0000] # SQUARED CJK UNIFIED IDEOGRAPH-5272 +2F823 ; [.FB40.0020.0002][.D277.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F823 +F9C7 ; [.FB40.0020.0002][.D289.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F9C7 +F98A ; [.FB40.0020.0002][.D29B.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F98A +2F12 ; [.FB40.0020.0004][.D29B.0000.0000] # KANGXI RADICAL POWER +F99D ; [.FB40.0020.0002][.D2A3.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F99D +2F992 ; [.FB40.0020.0002][.D2B3.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F992 +3238 ; [*0318.0020.0004][.FB40.0020.0004][.D2B4.0000.0000][*0319.0020.0004] # PARENTHESIZED IDEOGRAPH LABOR +3298 ; [.FB40.0020.0006][.D2B4.0000.0000] # CIRCLED IDEOGRAPH LABOR +FA76 ; [.FB40.0020.0002][.D2C7.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA76 +2F825 ; [.FB40.0020.0002][.D2C7.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F825 +FA33 ; [.FB40.0020.0002][.D2C9.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA33 +2F826 ; [.FB40.0020.0002][.D2C9.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F826 +F952 ; [.FB40.0020.0002][.D2D2.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F952 +1F247 ; [*037A.0020.0004][.FB40.0020.0004][.D2DD.0000.0000][*037B.0020.0004] # TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-52DD +F92F ; [.FB40.0020.0002][.D2DE.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F92F +FA34 ; [.FB40.0020.0002][.D2E4.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA34 +2F827 ; [.FB40.0020.0002][.D2E4.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F827 +F97F ; [.FB40.0020.0002][.D2F5.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F97F +2F13 ; [.FB40.0020.0004][.D2F9.0000.0000] # KANGXI RADICAL WRAP +FA77 ; [.FB40.0020.0002][.D2FA.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA77 +2F828 ; [.FB40.0020.0002][.D2FA.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F828 +2F829 ; [.FB40.0020.0002][.D305.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F829 +2F82A ; [.FB40.0020.0002][.D306.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F82A +2F14 ; [.FB40.0020.0004][.D315.0000.0000] # KANGXI RADICAL SPOON +F963 ; [.FB40.0020.0002][.D317.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F963 +2F82B ; [.FB40.0020.0002][.D317.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F82B +2F15 ; [.FB40.0020.0004][.D31A.0000.0000] # KANGXI RADICAL RIGHT OPEN BOX +2F16 ; [.FB40.0020.0004][.D338.0000.0000] # KANGXI RADICAL HIDING ENCLOSURE +32A9 ; [.FB40.0020.0006][.D33B.0000.0000] # CIRCLED IDEOGRAPH MEDICINE +F9EB ; [.FB40.0020.0002][.D33F.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F9EB +2F17 ; [.FB40.0020.0004][.D341.0000.0000] # KANGXI RADICAL TEN +3038 ; [.FB40.0020.0004][.D341.0000.0000] # HANGZHOU NUMERAL TEN +3229 ; [*0318.0020.0004][.FB40.0020.0004][.D341.0000.0000][*0319.0020.0004] # PARENTHESIZED IDEOGRAPH TEN +3289 ; [.FB40.0020.0006][.D341.0000.0000] # CIRCLED IDEOGRAPH TEN +3039 ; [.FB40.0020.0004][.D344.0000.0000] # HANGZHOU NUMERAL TWENTY +303A ; [.FB40.0020.0004][.D345.0000.0000] # HANGZHOU NUMERAL THIRTY +2F82C ; [.FB40.0020.0002][.D349.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F82C +FA35 ; [.FB40.0020.0002][.D351.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA35 +2F82D ; [.FB40.0020.0002][.D351.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F82D +323F ; [*0318.0020.0004][.FB40.0020.0004][.D354.0000.0000][*0319.0020.0004] # PARENTHESIZED IDEOGRAPH ALLIANCE +32AF ; [.FB40.0020.0006][.D354.0000.0000] # CIRCLED IDEOGRAPH ALLIANCE +2F82E ; [.FB40.0020.0002][.D35A.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F82E +2F18 ; [.FB40.0020.0004][.D35C.0000.0000] # KANGXI RADICAL DIVINATION +2E8A ; [.FB40.0020.0004][.D35C.0000.0000][.0000.0111.0004] # CJK RADICAL DIVINATION +2F19 ; [.FB40.0020.0004][.D369.0000.0000] # KANGXI RADICAL SEAL +2E8B ; [.FB40.0020.0004][.D369.0000.0000][.0000.0111.0004] # CJK RADICAL SEAL +329E ; [.FB40.0020.0006][.D370.0000.0000] # CIRCLED IDEOGRAPH PRINT +2F82F ; [.FB40.0020.0002][.D373.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F82F +F91C ; [.FB40.0020.0002][.D375.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F91C +2F830 ; [.FB40.0020.0002][.D37D.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F830 +2F831 ; [.FB40.0020.0002][.D37F.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F831 +2F832 ; [.FB40.0020.0002][.D37F.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F832 +2F833 ; [.FB40.0020.0002][.D37F.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F833 +2F1A ; [.FB40.0020.0004][.D382.0000.0000] # KANGXI RADICAL CLIFF +2E81 ; [.FB40.0020.0004][.D382.0000.0000][.0000.0111.0004] # CJK RADICAL CLIFF +2F1B ; [.FB40.0020.0004][.D3B6.0000.0000] # KANGXI RADICAL PRIVATE +F96B ; [.FB40.0020.0002][.D3C3.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F96B +2F1C ; [.FB40.0020.0004][.D3C8.0000.0000] # KANGXI RADICAL AGAIN +2F836 ; [.FB40.0020.0002][.D3CA.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F836 +1F212 ; [.FB40.0020.001C][.D3CC.0000.0000] # SQUARED CJK UNIFIED IDEOGRAPH-53CC +2F837 ; [.FB40.0020.0002][.D3DF.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F837 +2F1D ; [.FB40.0020.0004][.D3E3.0000.0000] # KANGXI RADICAL MOUTH +F906 ; [.FB40.0020.0002][.D3E5.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F906 +2F839 ; [.FB40.0020.0002][.D3EB.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F839 +1F251 ; [.FB40.0020.0006][.D3EF.0000.0000] # CIRCLED IDEOGRAPH ACCEPT +2F83A ; [.FB40.0020.0002][.D3F1.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F83A +32A8 ; [.FB40.0020.0006][.D3F3.0000.0000] # CIRCLED IDEOGRAPH RIGHT +1F22E ; [.FB40.0020.001C][.D3F3.0000.0000] # SQUARED CJK UNIFIED IDEOGRAPH-53F3 +2F83B ; [.FB40.0020.0002][.D406.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F83B +1F234 ; [.FB40.0020.001C][.D408.0000.0000] # SQUARED CJK UNIFIED IDEOGRAPH-5408 +3234 ; [*0318.0020.0004][.FB40.0020.0004][.D40D.0000.0000][*0319.0020.0004] # PARENTHESIZED IDEOGRAPH NAME +3294 ; [.FB40.0020.0006][.D40D.0000.0000] # CIRCLED IDEOGRAPH NAME +F9DE ; [.FB40.0020.0002][.D40F.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F9DE +F9ED ; [.FB40.0020.0002][.D41D.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F9ED +2F83D ; [.FB40.0020.0002][.D438.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F83D +1F225 ; [.FB40.0020.001C][.D439.0000.0000] # SQUARED CJK UNIFIED IDEOGRAPH-5439 +F980 ; [.FB40.0020.0002][.D442.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F980 +2F83E ; [.FB40.0020.0002][.D448.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F83E +2F83F ; [.FB40.0020.0002][.D468.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F83F +323A ; [*0318.0020.0004][.FB40.0020.0004][.D47C.0000.0000][*0319.0020.0004] # PARENTHESIZED IDEOGRAPH CALL +2F83C ; [.FB40.0020.0002][.D49E.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F83C +2F840 ; [.FB40.0020.0002][.D4A2.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F840 +F99E ; [.FB40.0020.0002][.D4BD.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F99E +2F841 ; [.FB40.0020.0002][.D4F6.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F841 +2F842 ; [.FB40.0020.0002][.D510.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F842 +3244 ; [.FB40.0020.0006][.D54F.0000.0000] # CIRCLED IDEOGRAPH QUESTION +2F843 ; [.FB40.0020.0002][.D553.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F843 +FA79 ; [.FB40.0020.0002][.D555.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA79 +2F844 ; [.FB40.0020.0002][.D563.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F844 +2F845 ; [.FB40.0020.0002][.D584.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F845 +2F846 ; [.FB40.0020.0002][.D584.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F846 +F90B ; [.FB40.0020.0002][.D587.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F90B +FA7A ; [.FB40.0020.0002][.D599.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA7A +2F847 ; [.FB40.0020.0002][.D599.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F847 +FA36 ; [.FB40.0020.0002][.D59D.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA36 +FA78 ; [.FB40.0020.0002][.D59D.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA78 +2F848 ; [.FB40.0020.0002][.D5AB.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F848 +2F849 ; [.FB40.0020.0002][.D5B3.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F849 +1F23A ; [.FB40.0020.001C][.D5B6.0000.0000] # SQUARED CJK UNIFIED IDEOGRAPH-55B6 +FA0D ; [.FB40.0020.0002][.D5C0.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA0D +2F84A ; [.FB40.0020.0002][.D5C2.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F84A +FA7B ; [.FB40.0020.0002][.D5E2.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA7B +FA37 ; [.FB40.0020.0002][.D606.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA37 +2F84C ; [.FB40.0020.0002][.D606.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F84C +2F84E ; [.FB40.0020.0002][.D651.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F84E +FA38 ; [.FB40.0020.0002][.D668.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA38 +2F84F ; [.FB40.0020.0002][.D674.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F84F +2F1E ; [.FB40.0020.0004][.D6D7.0000.0000] # KANGXI RADICAL ENCLOSURE +3223 ; [*0318.0020.0004][.FB40.0020.0004][.D6DB.0000.0000][*0319.0020.0004] # PARENTHESIZED IDEOGRAPH FOUR +3283 ; [.FB40.0020.0006][.D6DB.0000.0000] # CIRCLED IDEOGRAPH FOUR +3195 ; [.FB40.0020.0014][.D6DB.0000.0000] # IDEOGRAPHIC ANNOTATION FOUR MARK +F9A9 ; [.FB40.0020.0002][.D6F9.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F9A9 +2F84B ; [.FB40.0020.0002][.D716.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F84B +2F84D ; [.FB40.0020.0002][.D717.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F84D +2F1F ; [.FB40.0020.0004][.D71F.0000.0000] # KANGXI RADICAL EARTH +322F ; [*0318.0020.0004][.FB40.0020.0004][.D71F.0000.0000][*0319.0020.0004] # PARENTHESIZED IDEOGRAPH EARTH +328F ; [.FB40.0020.0006][.D71F.0000.0000] # CIRCLED IDEOGRAPH EARTH +319E ; [.FB40.0020.0014][.D730.0000.0000] # IDEOGRAPHIC ANNOTATION EARTH MARK +2F855 ; [.FB40.0020.0002][.D78B.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F855 +2F852 ; [.FB40.0020.0002][.D7CE.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F852 +2F853 ; [.FB40.0020.0002][.D7F4.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F853 +2F854 ; [.FB40.0020.0002][.D80D.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F854 +2F857 ; [.FB40.0020.0002][.D831.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F857 +2F856 ; [.FB40.0020.0002][.D832.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F856 +FA39 ; [.FB40.0020.0002][.D840.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA39 +FA10 ; [.FB40.0020.0002][.D85A.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA10 +FA7C ; [.FB40.0020.0002][.D85A.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA7C +F96C ; [.FB40.0020.0002][.D85E.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F96C +FA3A ; [.FB40.0020.0002][.D8A8.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA3A +2F858 ; [.FB40.0020.0002][.D8AC.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F858 +FA7D ; [.FB40.0020.0002][.D8B3.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA7D +F94A ; [.FB40.0020.0002][.D8D8.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F94A +F942 ; [.FB40.0020.0002][.D8DF.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F942 +2F20 ; [.FB40.0020.0004][.D8EB.0000.0000] # KANGXI RADICAL SCHOLAR +2F851 ; [.FB40.0020.0002][.D8EE.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F851 +1F224 ; [.FB40.0020.001C][.D8F0.0000.0000] # SQUARED CJK UNIFIED IDEOGRAPH-58F0 +2F85A ; [.FB40.0020.0002][.D8F2.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F85A +2F85B ; [.FB40.0020.0002][.D8F7.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F85B +2F21 ; [.FB40.0020.0004][.D902.0000.0000] # KANGXI RADICAL GO +2F85C ; [.FB40.0020.0002][.D906.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F85C +2F22 ; [.FB40.0020.0004][.D90A.0000.0000] # KANGXI RADICAL GO SLOWLY +2F23 ; [.FB40.0020.0004][.D915.0000.0000] # KANGXI RADICAL EVENING +2F85D ; [.FB40.0020.0002][.D91A.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F85D +1F215 ; [.FB40.0020.001C][.D91A.0000.0000] # SQUARED CJK UNIFIED IDEOGRAPH-591A +32B0 ; [.FB40.0020.0006][.D91C.0000.0000] # CIRCLED IDEOGRAPH NIGHT +2F85E ; [.FB40.0020.0002][.D922.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F85E +2F24 ; [.FB40.0020.0004][.D927.0000.0000] # KANGXI RADICAL BIG +337D ; [.FB40.0020.001C][.D927.0000.0000][.FB40.0020.001C][.EB63.0000.0000] # SQUARE ERA NAME TAISYOU +319D ; [.FB40.0020.0014][.D929.0000.0000] # IDEOGRAPHIC ANNOTATION HEAVEN MARK +1F217 ; [.FB40.0020.001C][.D929.0000.0000] # SQUARED CJK UNIFIED IDEOGRAPH-5929 +FA7E ; [.FB40.0020.0002][.D944.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA7E +F90C ; [.FB40.0020.0002][.D948.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F90C +F909 ; [.FB40.0020.0002][.D951.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F909 +FA7F ; [.FB40.0020.0002][.D954.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA7F +2F85F ; [.FB40.0020.0002][.D962.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F85F +F981 ; [.FB40.0020.0002][.D973.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F981 +2F25 ; [.FB40.0020.0004][.D973.0000.0000] # KANGXI RADICAL WOMAN +329B ; [.FB40.0020.0006][.D973.0000.0000] # CIRCLED IDEOGRAPH FEMALE +2F865 ; [.FB40.0020.0002][.D9D8.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F865 +2F862 ; [.FB40.0020.0002][.D9EC.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F862 +2F863 ; [.FB40.0020.0002][.DA1B.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F863 +2F864 ; [.FB40.0020.0002][.DA27.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F864 +FA80 ; [.FB40.0020.0002][.DA62.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA80 +2F866 ; [.FB40.0020.0002][.DA66.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F866 +2F986 ; [.FB40.0020.0002][.DAB5.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F986 +2F869 ; [.FB40.0020.0002][.DB08.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F869 +FA81 ; [.FB40.0020.0002][.DB28.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA81 +2F86A ; [.FB40.0020.0002][.DB3E.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F86A +2F86B ; [.FB40.0020.0002][.DB3E.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F86B +2F26 ; [.FB40.0020.0004][.DB50.0000.0000] # KANGXI RADICAL CHILD +1F211 ; [.FB40.0020.001C][.DB57.0000.0000] # SQUARED CJK UNIFIED IDEOGRAPH-5B57 +323B ; [*0318.0020.0004][.FB40.0020.0004][.DB66.0000.0000][*0319.0020.0004] # PARENTHESIZED IDEOGRAPH STUDY +32AB ; [.FB40.0020.0006][.DB66.0000.0000] # CIRCLED IDEOGRAPH STUDY +2F27 ; [.FB40.0020.0004][.DB80.0000.0000] # KANGXI RADICAL ROOF +FA04 ; [.FB40.0020.0002][.DB85.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA04 +1F243 ; [*037A.0020.0004][.FB40.0020.0004][.DB89.0000.0000][*037B.0020.0004] # TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-5B89 +32AA ; [.FB40.0020.0006][.DB97.0000.0000] # CIRCLED IDEOGRAPH RELIGION +2F86D ; [.FB40.0020.0002][.DBC3.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F86D +2F86E ; [.FB40.0020.0002][.DBD8.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F86E +F95F ; [.FB40.0020.0002][.DBE7.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F95F +F9AA ; [.FB40.0020.0002][.DBE7.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F9AA +2F86F ; [.FB40.0020.0002][.DBE7.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F86F +F9BC ; [.FB40.0020.0002][.DBEE.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F9BC +2F870 ; [.FB40.0020.0002][.DBF3.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F870 +2F28 ; [.FB40.0020.0004][.DBF8.0000.0000] # KANGXI RADICAL INCH +2F872 ; [.FB40.0020.0002][.DBFF.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F872 +2F873 ; [.FB40.0020.0002][.DC06.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F873 +2F29 ; [.FB40.0020.0004][.DC0F.0000.0000] # KANGXI RADICAL SMALL +2E8C ; [.FB40.0020.0004][.DC0F.0000.0000][.0000.0111.0004] # CJK RADICAL SMALL ONE +2E8D ; [.FB40.0020.0004][.DC0F.0000.0000][.0000.0112.0004] # CJK RADICAL SMALL TWO +2F875 ; [.FB40.0020.0002][.DC22.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F875 +2E90 ; [.FB40.0020.0004][.DC22.0000.0000] # CJK RADICAL LAME THREE +2F2A ; [.FB40.0020.0004][.DC22.0000.0000] # KANGXI RADICAL LAME +2E8E ; [.FB40.0020.0004][.DC22.0000.0000][.0000.0111.0004] # CJK RADICAL LAME ONE +2E8F ; [.FB40.0020.0004][.DC23.0000.0000] # CJK RADICAL LAME TWO +2E91 ; [.FB40.0020.0004][.DC23.0000.0000][.0000.0111.0004] # CJK RADICAL LAME FOUR +2F2B ; [.FB40.0020.0004][.DC38.0000.0000] # KANGXI RADICAL CORPSE +F9BD ; [.FB40.0020.0002][.DC3F.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F9BD +2F877 ; [.FB40.0020.0002][.DC60.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F877 +F94B ; [.FB40.0020.0002][.DC62.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F94B +FA3B ; [.FB40.0020.0002][.DC64.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA3B +F9DF ; [.FB40.0020.0002][.DC65.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F9DF +FA3C ; [.FB40.0020.0002][.DC6E.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA3C +2F878 ; [.FB40.0020.0002][.DC6E.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F878 +2F2C ; [.FB40.0020.0004][.DC6E.0000.0000] # KANGXI RADICAL SPROUT +2F2D ; [.FB40.0020.0004][.DC71.0000.0000] # KANGXI RADICAL MOUNTAIN +2F87A ; [.FB40.0020.0002][.DC8D.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F87A +2F879 ; [.FB40.0020.0002][.DCC0.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F879 +F9D5 ; [.FB40.0020.0002][.DD19.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F9D5 +2F87C ; [.FB40.0020.0002][.DD43.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F87C +F921 ; [.FB40.0020.0002][.DD50.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F921 +2F87F ; [.FB40.0020.0002][.DD6B.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F87F +2F87E ; [.FB40.0020.0002][.DD6E.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F87E +2F880 ; [.FB40.0020.0002][.DD7C.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F880 +2F9F4 ; [.FB40.0020.0002][.DDB2.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F9F4 +F9AB ; [.FB40.0020.0002][.DDBA.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F9AB +2F2E ; [.FB40.0020.0004][.DDDB.0000.0000] # KANGXI RADICAL RIVER +2F881 ; [.FB40.0020.0002][.DDE1.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F881 +2F882 ; [.FB40.0020.0002][.DDE2.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F882 +2F2F ; [.FB40.0020.0004][.DDE5.0000.0000] # KANGXI RADICAL WORK +32A7 ; [.FB40.0020.0006][.DDE6.0000.0000] # CIRCLED IDEOGRAPH LEFT +1F22C ; [.FB40.0020.001C][.DDE6.0000.0000] # SQUARED CJK UNIFIED IDEOGRAPH-5DE6 +2F30 ; [.FB40.0020.0004][.DDF1.0000.0000] # KANGXI RADICAL ONESELF +2E92 ; [.FB40.0020.0004][.DDF3.0000.0000] # CJK RADICAL SNAKE +2F884 ; [.FB40.0020.0002][.DDFD.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F884 +2F31 ; [.FB40.0020.0004][.DDFE.0000.0000] # KANGXI RADICAL TURBAN +2F885 ; [.FB40.0020.0002][.DE28.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F885 +2F886 ; [.FB40.0020.0002][.DE3D.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F886 +2F887 ; [.FB40.0020.0002][.DE69.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F887 +2F32 ; [.FB40.0020.0004][.DE72.0000.0000] # KANGXI RADICAL DRY +337B ; [.FB40.0020.001C][.DE73.0000.0000][.FB40.0020.001C][.E210.0000.0000] # SQUARE ERA NAME HEISEI +F98E ; [.FB40.0020.0002][.DE74.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F98E +2E93 ; [.FB40.0020.0004][.DE7A.0000.0000] # CJK RADICAL THREAD +2F33 ; [.FB40.0020.0004][.DE7A.0000.0000] # KANGXI RADICAL SHORT THREAD +3245 ; [.FB40.0020.0006][.DE7C.0000.0000] # CIRCLED IDEOGRAPH KINDERGARTEN +2F34 ; [.FB40.0020.0004][.DE7F.0000.0000] # KANGXI RADICAL DOTTED CLIFF +FA01 ; [.FB40.0020.0002][.DEA6.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA01 +2F88B ; [.FB40.0020.0002][.DEB0.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F88B +2F88C ; [.FB40.0020.0002][.DEB3.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F88C +2F88D ; [.FB40.0020.0002][.DEB6.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F88D +F9A2 ; [.FB40.0020.0002][.DEC9.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F9A2 +F928 ; [.FB40.0020.0002][.DECA.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F928 +2F88E ; [.FB40.0020.0002][.DECA.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F88E +FA82 ; [.FB40.0020.0002][.DED2.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA82 +FA0B ; [.FB40.0020.0002][.DED3.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA0B +FA83 ; [.FB40.0020.0002][.DED9.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA83 +F982 ; [.FB40.0020.0002][.DEEC.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F982 +2F35 ; [.FB40.0020.0004][.DEF4.0000.0000] # KANGXI RADICAL LONG STRIDE +2F890 ; [.FB40.0020.0002][.DEFE.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F890 +2F36 ; [.FB40.0020.0004][.DEFE.0000.0000] # KANGXI RADICAL TWO HANDS +F943 ; [.FB40.0020.0002][.DF04.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F943 +2F37 ; [.FB40.0020.0004][.DF0B.0000.0000] # KANGXI RADICAL SHOOT +2F38 ; [.FB40.0020.0004][.DF13.0000.0000] # KANGXI RADICAL BOW +2F894 ; [.FB40.0020.0002][.DF22.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F894 +2F895 ; [.FB40.0020.0002][.DF22.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F895 +2F39 ; [.FB40.0020.0004][.DF50.0000.0000] # KANGXI RADICAL SNOUT +2E95 ; [.FB40.0020.0004][.DF50.0000.0000][.0000.0111.0004] # CJK RADICAL SNOUT TWO +2E94 ; [.FB40.0020.0004][.DF51.0000.0000] # CJK RADICAL SNOUT ONE +2F874 ; [.FB40.0020.0002][.DF53.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F874 +2F3A ; [.FB40.0020.0004][.DF61.0000.0000] # KANGXI RADICAL BRISTLE +2F899 ; [.FB40.0020.0002][.DF62.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F899 +FA84 ; [.FB40.0020.0002][.DF69.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA84 +2F89A ; [.FB40.0020.0002][.DF6B.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F89A +2F3B ; [.FB40.0020.0004][.DF73.0000.0000] # KANGXI RADICAL STEP +F9D8 ; [.FB40.0020.0002][.DF8B.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F9D8 +1F21D ; [.FB40.0020.001C][.DF8C.0000.0000] # SQUARED CJK UNIFIED IDEOGRAPH-5F8C +1F250 ; [.FB40.0020.0006][.DF97.0000.0000] # CIRCLED IDEOGRAPH ADVANTAGE +2F89C ; [.FB40.0020.0002][.DF9A.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F89C +F966 ; [.FB40.0020.0002][.DFA9.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F966 +FA85 ; [.FB40.0020.0002][.DFAD.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA85 +2F3C ; [.FB40.0020.0004][.DFC3.0000.0000] # KANGXI RADICAL HEART +2E97 ; [.FB40.0020.0004][.DFC3.0000.0000][.0000.0111.0004] # CJK RADICAL HEART TWO +2E96 ; [.FB40.0020.0004][.DFC4.0000.0000] # CJK RADICAL HEART ONE +2F89D ; [.FB40.0020.0002][.DFCD.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F89D +2F89E ; [.FB40.0020.0002][.DFD7.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F89E +F9A3 ; [.FB40.0020.0002][.DFF5.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F9A3 +2F89F ; [.FB40.0020.0002][.DFF9.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F89F +F960 ; [.FB40.0020.0002][.E012.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F960 +F9AC ; [.FB40.0020.0002][.E01C.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F9AC +FA6B ; [.FB40.0020.0002][.E075.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA6B +2F8A0 ; [.FB40.0020.0002][.E081.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F8A0 +FA3D ; [.FB40.0020.0002][.E094.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA3D +2F8A3 ; [.FB40.0020.0002][.E094.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F8A3 +2F8A5 ; [.FB40.0020.0002][.E0C7.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F8A5 +FA86 ; [.FB40.0020.0002][.E0D8.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA86 +F9B9 ; [.FB40.0020.0002][.E0E1.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F9B9 +FA88 ; [.FB40.0020.0002][.E108.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA88 +F9D9 ; [.FB40.0020.0002][.E144.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F9D9 +2F8A6 ; [.FB40.0020.0002][.E148.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F8A6 +2F8A7 ; [.FB40.0020.0002][.E14C.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F8A7 +2F8A9 ; [.FB40.0020.0002][.E14C.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F8A9 +FA87 ; [.FB40.0020.0002][.E14E.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA87 +2F8A8 ; [.FB40.0020.0002][.E14E.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F8A8 +FA8A ; [.FB40.0020.0002][.E160.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA8A +FA3E ; [.FB40.0020.0002][.E168.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA3E +2F8AA ; [.FB40.0020.0002][.E17A.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F8AA +FA3F ; [.FB40.0020.0002][.E18E.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA3F +FA89 ; [.FB40.0020.0002][.E18E.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA89 +2F8AB ; [.FB40.0020.0002][.E18E.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F8AB +F98F ; [.FB40.0020.0002][.E190.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F98F +2F8AD ; [.FB40.0020.0002][.E1A4.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F8AD +2F8AE ; [.FB40.0020.0002][.E1AF.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F8AE +2F8AC ; [.FB40.0020.0002][.E1B2.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F8AC +2F8AF ; [.FB40.0020.0002][.E1DE.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F8AF +FA40 ; [.FB40.0020.0002][.E1F2.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA40 +FA8B ; [.FB40.0020.0002][.E1F2.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA8B +2F8B0 ; [.FB40.0020.0002][.E1F2.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F8B0 +F90D ; [.FB40.0020.0002][.E1F6.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F90D +2F8B1 ; [.FB40.0020.0002][.E1F6.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F8B1 +F990 ; [.FB40.0020.0002][.E200.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F990 +2F3D ; [.FB40.0020.0004][.E208.0000.0000] # KANGXI RADICAL HALBERD +2F8B2 ; [.FB40.0020.0002][.E210.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F8B2 +2F8B3 ; [.FB40.0020.0002][.E21B.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F8B3 +F9D2 ; [.FB40.0020.0002][.E22E.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F9D2 +FA8C ; [.FB40.0020.0002][.E234.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA8C +2F3E ; [.FB40.0020.0004][.E236.0000.0000] # KANGXI RADICAL DOOR +2F3F ; [.FB40.0020.0004][.E24B.0000.0000] # KANGXI RADICAL HAND +1F210 ; [.FB40.0020.001C][.E24B.0000.0000] # SQUARED CJK UNIFIED IDEOGRAPH-624B +2E98 ; [.FB40.0020.0004][.E24C.0000.0000] # CJK RADICAL HAND +1F245 ; [*037A.0020.0004][.FB40.0020.0004][.E253.0000.0000][*037B.0020.0004] # TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-6253 +1F231 ; [.FB40.0020.001C][.E253.0000.0000] # SQUARED CJK UNIFIED IDEOGRAPH-6253 +2F8B4 ; [.FB40.0020.0002][.E25D.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F8B4 +1F227 ; [.FB40.0020.001C][.E295.0000.0000] # SQUARED CJK UNIFIED IDEOGRAPH-6295 +2F8B5 ; [.FB40.0020.0002][.E2B1.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F8B5 +F925 ; [.FB40.0020.0002][.E2C9.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F925 +F95B ; [.FB40.0020.0002][.E2CF.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F95B +FA02 ; [.FB40.0020.0002][.E2D3.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA02 +2F8B6 ; [.FB40.0020.0002][.E2D4.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F8B6 +2F8BA ; [.FB40.0020.0002][.E2FC.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F8BA +F973 ; [.FB40.0020.0002][.E2FE.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F973 +1F22F ; [.FB40.0020.001C][.E307.0000.0000] # SQUARED CJK UNIFIED IDEOGRAPH-6307 +2F8B9 ; [.FB40.0020.0002][.E33D.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F8B9 +2F8B7 ; [.FB40.0020.0002][.E350.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F8B7 +1F228 ; [.FB40.0020.001C][.E355.0000.0000] # SQUARED CJK UNIFIED IDEOGRAPH-6355 +2F8BB ; [.FB40.0020.0002][.E368.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F8BB +F9A4 ; [.FB40.0020.0002][.E37B.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F9A4 +2F8BC ; [.FB40.0020.0002][.E383.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F8BC +F975 ; [.FB40.0020.0002][.E3A0.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F975 +2F8C1 ; [.FB40.0020.0002][.E3A9.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F8C1 +FA8D ; [.FB40.0020.0002][.E3C4.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA8D +2F8C0 ; [.FB40.0020.0002][.E3C5.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F8C0 +2F8BD ; [.FB40.0020.0002][.E3E4.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F8BD +FA8E ; [.FB40.0020.0002][.E41C.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA8E +2F8BF ; [.FB40.0020.0002][.E422.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F8BF +FA8F ; [.FB40.0020.0002][.E452.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA8F +2F8C3 ; [.FB40.0020.0002][.E469.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F8C3 +2F8C6 ; [.FB40.0020.0002][.E477.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F8C6 +2F8C4 ; [.FB40.0020.0002][.E47E.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F8C4 +F991 ; [.FB40.0020.0002][.E49A.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F991 +2F8C5 ; [.FB40.0020.0002][.E49D.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F8C5 +F930 ; [.FB40.0020.0002][.E4C4.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F930 +2F40 ; [.FB40.0020.0004][.E52F.0000.0000] # KANGXI RADICAL BRANCH +2F41 ; [.FB40.0020.0004][.E534.0000.0000] # KANGXI RADICAL RAP +2E99 ; [.FB40.0020.0004][.E535.0000.0000] # CJK RADICAL RAP +FA41 ; [.FB40.0020.0002][.E54F.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA41 +2F8C8 ; [.FB40.0020.0002][.E54F.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F8C8 +FA90 ; [.FB40.0020.0002][.E556.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA90 +1F248 ; [*037A.0020.0004][.FB40.0020.0004][.E557.0000.0000][*037B.0020.0004] # TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-6557 +2F8C9 ; [.FB40.0020.0002][.E56C.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F8C9 +F969 ; [.FB40.0020.0002][.E578.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F969 +2F42 ; [.FB40.0020.0004][.E587.0000.0000] # KANGXI RADICAL SCRIPT +3246 ; [.FB40.0020.0006][.E587.0000.0000] # CIRCLED IDEOGRAPH SCHOOL +2F43 ; [.FB40.0020.0004][.E597.0000.0000] # KANGXI RADICAL DIPPER +F9BE ; [.FB40.0020.0002][.E599.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F9BE +1F21B ; [.FB40.0020.001C][.E599.0000.0000] # SQUARED CJK UNIFIED IDEOGRAPH-6599 +2F44 ; [.FB40.0020.0004][.E5A4.0000.0000] # KANGXI RADICAL AXE +1F21F ; [.FB40.0020.001C][.E5B0.0000.0000] # SQUARED CJK UNIFIED IDEOGRAPH-65B0 +2F45 ; [.FB40.0020.0004][.E5B9.0000.0000] # KANGXI RADICAL SQUARE +F983 ; [.FB40.0020.0002][.E5C5.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F983 +2F46 ; [.FB40.0020.0004][.E5E0.0000.0000] # KANGXI RADICAL NOT +2E9B ; [.FB40.0020.0004][.E5E1.0000.0000] # CJK RADICAL CHOKE +FA42 ; [.FB40.0020.0002][.E5E2.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA42 +2F8CB ; [.FB40.0020.0002][.E5E3.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F8CB +2F47 ; [.FB40.0020.0004][.E5E5.0000.0000] # KANGXI RADICAL SUN +3230 ; [*0318.0020.0004][.FB40.0020.0004][.E5E5.0000.0000][*0319.0020.0004] # PARENTHESIZED IDEOGRAPH SUN +3290 ; [.FB40.0020.0006][.E5E5.0000.0000] # CIRCLED IDEOGRAPH SUN +2E9C ; [.FB40.0020.0004][.E5E5.0000.0000][.0000.0111.0004] # CJK RADICAL SUN +337E ; [.FB40.0020.001C][.E60E.0000.0000][.FB40.0020.001C][.ECBB.0000.0000] # SQUARE ERA NAME MEIZI +F9E0 ; [.FB40.0020.0002][.E613.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F9E0 +1F219 ; [.FB40.0020.001C][.E620.0000.0000] # SQUARED CJK UNIFIED IDEOGRAPH-6620 +337C ; [.FB40.0020.001C][.E62D.0000.0000][.FB40.0020.001C][.D48C.0000.0000] # SQUARE ERA NAME SYOUWA +2F8CD ; [.FB40.0020.0002][.E649.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F8CD +FA12 ; [.FB40.0020.0002][.E674.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA12 +FA91 ; [.FB40.0020.0002][.E674.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA91 +F9C5 ; [.FB40.0020.0002][.E688.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F9C5 +FA43 ; [.FB40.0020.0002][.E691.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA43 +2F8CF ; [.FB40.0020.0002][.E691.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F8CF +2F8D5 ; [.FB40.0020.0002][.E69C.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F8D5 +FA06 ; [.FB40.0020.0002][.E6B4.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA06 +F98B ; [.FB40.0020.0002][.E6C6.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F98B +2F48 ; [.FB40.0020.0004][.E6F0.0000.0000] # KANGXI RADICAL SAY +F901 ; [.FB40.0020.0002][.E6F4.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F901 +2F8CC ; [.FB40.0020.0002][.E6F8.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F8CC +2F8D4 ; [.FB40.0020.0002][.E700.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F8D4 +2F49 ; [.FB40.0020.0004][.E708.0000.0000] # KANGXI RADICAL MOON +322A ; [*0318.0020.0004][.FB40.0020.0004][.E708.0000.0000][*0319.0020.0004] # PARENTHESIZED IDEOGRAPH MOON +328A ; [.FB40.0020.0006][.E708.0000.0000] # CIRCLED IDEOGRAPH MOON +1F237 ; [.FB40.0020.001C][.E708.0000.0000] # SQUARED CJK UNIFIED IDEOGRAPH-6708 +2E9D ; [.FB40.0020.0004][.E708.0000.0000][.0000.0111.0004] # CJK RADICAL MOON +3232 ; [*0318.0020.0004][.FB40.0020.0004][.E709.0000.0000][*0319.0020.0004] # PARENTHESIZED IDEOGRAPH HAVE +3292 ; [.FB40.0020.0006][.E709.0000.0000] # CIRCLED IDEOGRAPH HAVE +1F236 ; [.FB40.0020.001C][.E709.0000.0000] # SQUARED CJK UNIFIED IDEOGRAPH-6709 +F929 ; [.FB40.0020.0002][.E717.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F929 +FA92 ; [.FB40.0020.0002][.E717.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA92 +2F8D8 ; [.FB40.0020.0002][.E717.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F8D8 +FA93 ; [.FB40.0020.0002][.E71B.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA93 +2F8D9 ; [.FB40.0020.0002][.E71B.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F8D9 +2F8DA ; [.FB40.0020.0002][.E721.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F8DA +2F4A ; [.FB40.0020.0004][.E728.0000.0000] # KANGXI RADICAL TREE +322D ; [*0318.0020.0004][.FB40.0020.0004][.E728.0000.0000][*0319.0020.0004] # PARENTHESIZED IDEOGRAPH WOOD +328D ; [.FB40.0020.0006][.E728.0000.0000] # CIRCLED IDEOGRAPH WOOD +1F240 ; [*037A.0020.0004][.FB40.0020.0004][.E72C.0000.0000][*037B.0020.0004] # TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-672C +F9E1 ; [.FB40.0020.0002][.E74E.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F9E1 +2F8DC ; [.FB40.0020.0002][.E753.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F8DC +FA94 ; [.FB40.0020.0002][.E756.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA94 +2F8DB ; [.FB40.0020.0002][.E75E.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F8DB +F9C8 ; [.FB40.0020.0002][.E77B.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F9C8 +2F8E0 ; [.FB40.0020.0002][.E785.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F8E0 +F9F4 ; [.FB40.0020.0002][.E797.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F9F4 +F9C9 ; [.FB40.0020.0002][.E7F3.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F9C9 +2F8DF ; [.FB40.0020.0002][.E7FA.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F8DF +F9DA ; [.FB40.0020.0002][.E817.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F9DA +2F8E5 ; [.FB40.0020.0002][.E81F.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F8E5 +3231 ; [*0318.0020.0004][.FB40.0020.0004][.E82A.0000.0000][*0319.0020.0004] # PARENTHESIZED IDEOGRAPH STOCK +3291 ; [.FB40.0020.0006][.E82A.0000.0000] # CIRCLED IDEOGRAPH STOCK +337F ; [.FB40.0020.001C][.E82A.0000.0000][.FB40.0020.001C][.DF0F.0000.0000][.FB40.0020.001C][.CF1A.0000.0000][.FB40.0020.001C][.F93E.0000.0000] # SQUARE CORPORATION +2F8E1 ; [.FB40.0020.0002][.E852.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F8E1 +F97A ; [.FB40.0020.0002][.E881.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F97A +FA44 ; [.FB40.0020.0002][.E885.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA44 +2F8E2 ; [.FB40.0020.0002][.E885.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F8E2 +2F8E4 ; [.FB40.0020.0002][.E88E.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F8E4 +F9E2 ; [.FB40.0020.0002][.E8A8.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F9E2 +2F8E6 ; [.FB40.0020.0002][.E914.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F8E6 +2F8E8 ; [.FB40.0020.0002][.E942.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F8E8 +2F8E9 ; [.FB40.0020.0002][.E9A3.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F8E9 +2F8EA ; [.FB40.0020.0002][.E9EA.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F8EA +F914 ; [.FB40.0020.0002][.EA02.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F914 +F95C ; [.FB40.0020.0002][.EA02.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F95C +F9BF ; [.FB40.0020.0002][.EA02.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F9BF +F94C ; [.FB40.0020.0002][.EA13.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F94C +2F8EB ; [.FB40.0020.0002][.EAA8.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F8EB +F931 ; [.FB40.0020.0002][.EAD3.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F931 +2F8ED ; [.FB40.0020.0002][.EADB.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F8ED +F91D ; [.FB40.0020.0002][.EB04.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F91D +2F4B ; [.FB40.0020.0004][.EB20.0000.0000] # KANGXI RADICAL LACK +2F8EF ; [.FB40.0020.0002][.EB21.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F8EF +2F8F1 ; [.FB40.0020.0002][.EB54.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F8F1 +2F4C ; [.FB40.0020.0004][.EB62.0000.0000] # KANGXI RADICAL STOP +32A3 ; [.FB40.0020.0006][.EB63.0000.0000] # CIRCLED IDEOGRAPH CORRECT +2F8F3 ; [.FB40.0020.0002][.EB72.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F8F3 +F98C ; [.FB40.0020.0002][.EB77.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F98C +FA95 ; [.FB40.0020.0002][.EB79.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA95 +2F4D ; [.FB40.0020.0004][.EB79.0000.0000] # KANGXI RADICAL DEATH +2E9E ; [.FB40.0020.0004][.EB7A.0000.0000][.0000.0111.0004] # CJK RADICAL DEATH +2F8F4 ; [.FB40.0020.0002][.EB9F.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F8F4 +F9A5 ; [.FB40.0020.0002][.EBAE.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F9A5 +2F4E ; [.FB40.0020.0004][.EBB3.0000.0000] # KANGXI RADICAL WEAPON +F970 ; [.FB40.0020.0002][.EBBA.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F970 +FA96 ; [.FB40.0020.0002][.EBBA.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA96 +2F8F5 ; [.FB40.0020.0002][.EBBA.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F8F5 +2F8F6 ; [.FB40.0020.0002][.EBBB.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F8F6 +2F4F ; [.FB40.0020.0004][.EBCB.0000.0000] # KANGXI RADICAL DO NOT +2E9F ; [.FB40.0020.0004][.EBCD.0000.0000] # CJK RADICAL MOTHER +2F50 ; [.FB40.0020.0004][.EBD4.0000.0000] # KANGXI RADICAL COMPARE +2F51 ; [.FB40.0020.0004][.EBDB.0000.0000] # KANGXI RADICAL FUR +2F52 ; [.FB40.0020.0004][.EC0F.0000.0000] # KANGXI RADICAL CLAN +2EA0 ; [.FB40.0020.0004][.EC11.0000.0000] # CJK RADICAL CIVILIAN +2F53 ; [.FB40.0020.0004][.EC14.0000.0000] # KANGXI RADICAL STEAM +2F54 ; [.FB40.0020.0004][.EC34.0000.0000] # KANGXI RADICAL WATER +322C ; [*0318.0020.0004][.FB40.0020.0004][.EC34.0000.0000][*0319.0020.0004] # PARENTHESIZED IDEOGRAPH WATER +328C ; [.FB40.0020.0006][.EC34.0000.0000] # CIRCLED IDEOGRAPH WATER +2EA1 ; [.FB40.0020.0004][.EC35.0000.0000] # CJK RADICAL WATER ONE +2EA2 ; [.FB40.0020.0004][.EC3A.0000.0000] # CJK RADICAL WATER TWO +2F8FA ; [.FB40.0020.0002][.EC4E.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F8FA +2F8FE ; [.FB40.0020.0002][.EC67.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F8FE +F972 ; [.FB40.0020.0002][.EC88.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F972 +2F8FC ; [.FB40.0020.0002][.ECBF.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F8FC +F968 ; [.FB40.0020.0002][.ECCC.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F968 +2F8FD ; [.FB40.0020.0002][.ECCD.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F8FD +F9E3 ; [.FB40.0020.0002][.ECE5.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F9E3 +329F ; [.FB40.0020.0006][.ECE8.0000.0000] # CIRCLED IDEOGRAPH ATTENTION +2F8FF ; [.FB40.0020.0002][.ED16.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F8FF +F915 ; [.FB40.0020.0002][.ED1B.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F915 +FA05 ; [.FB40.0020.0002][.ED1E.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA05 +2F907 ; [.FB40.0020.0002][.ED34.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F907 +2F900 ; [.FB40.0020.0002][.ED3E.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F900 +F9CA ; [.FB40.0020.0002][.ED41.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F9CA +FA97 ; [.FB40.0020.0002][.ED41.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA97 +2F902 ; [.FB40.0020.0002][.ED41.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F902 +2F903 ; [.FB40.0020.0002][.ED69.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F903 +F92A ; [.FB40.0020.0002][.ED6A.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F92A +FA45 ; [.FB40.0020.0002][.ED77.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA45 +2F901 ; [.FB40.0020.0002][.ED77.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F901 +2F904 ; [.FB40.0020.0002][.ED78.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F904 +2F905 ; [.FB40.0020.0002][.ED85.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F905 +F9F5 ; [.FB40.0020.0002][.EDCB.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F9F5 +F94D ; [.FB40.0020.0002][.EDDA.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F94D +F9D6 ; [.FB40.0020.0002][.EDEA.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F9D6 +2F90E ; [.FB40.0020.0002][.EDF9.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F90E +FA46 ; [.FB40.0020.0002][.EE1A.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA46 +2F908 ; [.FB40.0020.0002][.EE2F.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F908 +2F909 ; [.FB40.0020.0002][.EE6E.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F909 +1F235 ; [.FB40.0020.001C][.EE80.0000.0000] # SQUARED CJK UNIFIED IDEOGRAPH-6E80 +F9CB ; [.FB40.0020.0002][.EE9C.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F9CB +F9EC ; [.FB40.0020.0002][.EEBA.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F9EC +2F90C ; [.FB40.0020.0002][.EEC7.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F90C +FA99 ; [.FB40.0020.0002][.EECB.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA99 +2F90B ; [.FB40.0020.0002][.EECB.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F90B +F904 ; [.FB40.0020.0002][.EED1.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F904 +FA98 ; [.FB40.0020.0002][.EEDB.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA98 +F94E ; [.FB40.0020.0002][.EF0F.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F94E +1F226 ; [.FB40.0020.001C][.EF14.0000.0000] # SQUARED CJK UNIFIED IDEOGRAPH-6F14 +FA47 ; [.FB40.0020.0002][.EF22.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA47 +FA9A ; [.FB40.0020.0002][.EF22.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA9A +F992 ; [.FB40.0020.0002][.EF23.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F992 +2F90F ; [.FB40.0020.0002][.EF6E.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F90F +2F912 ; [.FB40.0020.0002][.EFC6.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F912 +F922 ; [.FB40.0020.0002][.EFEB.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F922 +F984 ; [.FB40.0020.0002][.EFFE.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F984 +2F915 ; [.FB40.0020.0002][.F01B.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F915 +FA9B ; [.FB40.0020.0002][.F01E.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA9B +2F914 ; [.FB40.0020.0002][.F01E.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F914 +2F913 ; [.FB40.0020.0002][.F039.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F913 +2F917 ; [.FB40.0020.0002][.F04A.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F917 +2F55 ; [.FB40.0020.0004][.F06B.0000.0000] # KANGXI RADICAL FIRE +322B ; [*0318.0020.0004][.FB40.0020.0004][.F06B.0000.0000][*0319.0020.0004] # PARENTHESIZED IDEOGRAPH FIRE +328B ; [.FB40.0020.0006][.F06B.0000.0000] # CIRCLED IDEOGRAPH FIRE +2EA3 ; [.FB40.0020.0004][.F06C.0000.0000] # CJK RADICAL FIRE +2F835 ; [.FB40.0020.0002][.F070.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F835 +2F919 ; [.FB40.0020.0002][.F077.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F919 +2F918 ; [.FB40.0020.0002][.F07D.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F918 +F9FB ; [.FB40.0020.0002][.F099.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F9FB +2F91A ; [.FB40.0020.0002][.F0AD.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F91A +1F244 ; [*037A.0020.0004][.FB40.0020.0004][.F0B9.0000.0000][*037B.0020.0004] # TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-70B9 +F99F ; [.FB40.0020.0002][.F0C8.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F99F +F916 ; [.FB40.0020.0002][.F0D9.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F916 +1F21A ; [.FB40.0020.001C][.F121.0000.0000] # SQUARED CJK UNIFIED IDEOGRAPH-7121 +2F91C ; [.FB40.0020.0002][.F145.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F91C +F993 ; [.FB40.0020.0002][.F149.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F993 +FA48 ; [.FB40.0020.0002][.F16E.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA48 +FA9C ; [.FB40.0020.0002][.F16E.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA9C +2F91E ; [.FB40.0020.0002][.F19C.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F91E +F9C0 ; [.FB40.0020.0002][.F1CE.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F9C0 +F9EE ; [.FB40.0020.0002][.F1D0.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F9EE +F932 ; [.FB40.0020.0002][.F210.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F932 +F91E ; [.FB40.0020.0002][.F21B.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F91E +2F920 ; [.FB40.0020.0002][.F228.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F920 +2F56 ; [.FB40.0020.0004][.F22A.0000.0000] # KANGXI RADICAL CLAW +FA49 ; [.FB40.0020.0002][.F22B.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA49 +2EA4 ; [.FB40.0020.0004][.F22B.0000.0000] # CJK RADICAL PAW ONE +2EA5 ; [.FB40.0020.0004][.F22B.0000.0000][.0000.0111.0004] # CJK RADICAL PAW TWO +FA9E ; [.FB40.0020.0002][.F235.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA9E +2F921 ; [.FB40.0020.0002][.F235.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F921 +2F57 ; [.FB40.0020.0004][.F236.0000.0000] # KANGXI RADICAL FATHER +2F58 ; [.FB40.0020.0004][.F23B.0000.0000] # KANGXI RADICAL DOUBLE X +2F59 ; [.FB40.0020.0004][.F23F.0000.0000] # KANGXI RADICAL HALF TREE TRUNK +2F5A ; [.FB40.0020.0004][.F247.0000.0000] # KANGXI RADICAL SLICE +2F922 ; [.FB40.0020.0002][.F250.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F922 +2F5B ; [.FB40.0020.0004][.F259.0000.0000] # KANGXI RADICAL FANG +2F5C ; [.FB40.0020.0004][.F25B.0000.0000] # KANGXI RADICAL COW +2EA7 ; [.FB40.0020.0004][.F25B.0000.0000][.0000.0111.0004] # CJK RADICAL COW +F946 ; [.FB40.0020.0002][.F262.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F946 +3235 ; [*0318.0020.0004][.FB40.0020.0004][.F279.0000.0000][*0319.0020.0004] # PARENTHESIZED IDEOGRAPH SPECIAL +3295 ; [.FB40.0020.0006][.F279.0000.0000] # CIRCLED IDEOGRAPH SPECIAL +2F924 ; [.FB40.0020.0002][.F280.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F924 +2F925 ; [.FB40.0020.0002][.F295.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F925 +2F5D ; [.FB40.0020.0004][.F2AC.0000.0000] # KANGXI RADICAL DOG +2EA8 ; [.FB40.0020.0004][.F2AD.0000.0000] # CJK RADICAL DOG +FA9F ; [.FB40.0020.0002][.F2AF.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA9F +F9FA ; [.FB40.0020.0002][.F2C0.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F9FA +F92B ; [.FB40.0020.0002][.F2FC.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F92B +FA16 ; [.FB40.0020.0002][.F32A.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA16 +FAA0 ; [.FB40.0020.0002][.F32A.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FAA0 +F9A7 ; [.FB40.0020.0002][.F375.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F9A7 +2F928 ; [.FB40.0020.0002][.F37A.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F928 +2F5E ; [.FB40.0020.0004][.F384.0000.0000] # KANGXI RADICAL PROFOUND +F961 ; [.FB40.0020.0002][.F387.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F961 +F9DB ; [.FB40.0020.0002][.F387.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F9DB +2F5F ; [.FB40.0020.0004][.F389.0000.0000] # KANGXI RADICAL JADE +2F929 ; [.FB40.0020.0002][.F38B.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F929 +2EA9 ; [.FB40.0020.0004][.F38B.0000.0000][.0000.0111.0004] # CJK RADICAL JADE +2F92B ; [.FB40.0020.0002][.F3A5.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F92B +F9AD ; [.FB40.0020.0002][.F3B2.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F9AD +F917 ; [.FB40.0020.0002][.F3DE.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F917 +F9E4 ; [.FB40.0020.0002][.F406.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F9E4 +F9CC ; [.FB40.0020.0002][.F409.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F9CC +FA4A ; [.FB40.0020.0002][.F422.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA4A +2F92E ; [.FB40.0020.0002][.F447.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F92E +2F92F ; [.FB40.0020.0002][.F45C.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F92F +F9AE ; [.FB40.0020.0002][.F469.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F9AE +FAA1 ; [.FB40.0020.0002][.F471.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FAA1 +2F930 ; [.FB40.0020.0002][.F471.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F930 +2F931 ; [.FB40.0020.0002][.F485.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F931 +F994 ; [.FB40.0020.0002][.F489.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F994 +F9EF ; [.FB40.0020.0002][.F498.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F9EF +2F932 ; [.FB40.0020.0002][.F4CA.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F932 +2F60 ; [.FB40.0020.0004][.F4DC.0000.0000] # KANGXI RADICAL MELON +2F61 ; [.FB40.0020.0004][.F4E6.0000.0000] # KANGXI RADICAL TILE +FAA2 ; [.FB40.0020.0002][.F506.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FAA2 +2F62 ; [.FB40.0020.0004][.F518.0000.0000] # KANGXI RADICAL SWEET +2F63 ; [.FB40.0020.0004][.F51F.0000.0000] # KANGXI RADICAL LIFE +1F222 ; [.FB40.0020.001C][.F51F.0000.0000] # SQUARED CJK UNIFIED IDEOGRAPH-751F +2F934 ; [.FB40.0020.0002][.F524.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F934 +2F64 ; [.FB40.0020.0004][.F528.0000.0000] # KANGXI RADICAL USE +2F65 ; [.FB40.0020.0004][.F530.0000.0000] # KANGXI RADICAL FIELD +3199 ; [.FB40.0020.0014][.F532.0000.0000] # IDEOGRAPHIC ANNOTATION FIRST MARK +1F238 ; [.FB40.0020.001C][.F533.0000.0000] # SQUARED CJK UNIFIED IDEOGRAPH-7533 +329A ; [.FB40.0020.0006][.F537.0000.0000] # CIRCLED IDEOGRAPH MALE +FAA3 ; [.FB40.0020.0002][.F53B.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FAA3 +2F936 ; [.FB40.0020.0002][.F53E.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F936 +F9CD ; [.FB40.0020.0002][.F559.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F9CD +F976 ; [.FB40.0020.0002][.F565.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F976 +F962 ; [.FB40.0020.0002][.F570.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F962 +2F938 ; [.FB40.0020.0002][.F570.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F938 +2F66 ; [.FB40.0020.0004][.F58B.0000.0000] # KANGXI RADICAL BOLT OF CLOTH +2EAA ; [.FB40.0020.0004][.F58B.0000.0000][.0000.0111.0004] # CJK RADICAL BOLT OF CLOTH +2F67 ; [.FB40.0020.0004][.F592.0000.0000] # KANGXI RADICAL SICKNESS +F9E5 ; [.FB40.0020.0002][.F5E2.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F9E5 +2F93A ; [.FB40.0020.0002][.F610.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F93A +FAA4 ; [.FB40.0020.0002][.F61D.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FAA4 +FAA5 ; [.FB40.0020.0002][.F61F.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FAA5 +F9C1 ; [.FB40.0020.0002][.F642.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F9C1 +F90E ; [.FB40.0020.0002][.F669.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F90E +2F68 ; [.FB40.0020.0004][.F676.0000.0000] # KANGXI RADICAL DOTTED TENT +2F69 ; [.FB40.0020.0004][.F67D.0000.0000] # KANGXI RADICAL WHITE +2F6A ; [.FB40.0020.0004][.F6AE.0000.0000] # KANGXI RADICAL SKIN +2F6B ; [.FB40.0020.0004][.F6BF.0000.0000] # KANGXI RADICAL DISH +FA17 ; [.FB40.0020.0002][.F6CA.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA17 +FAA6 ; [.FB40.0020.0002][.F6CA.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FAA6 +1F246 ; [*037A.0020.0004][.FB40.0020.0004][.F6D7.0000.0000][*037B.0020.0004] # TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-76D7 +FAA7 ; [.FB40.0020.0002][.F6DB.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FAA7 +323C ; [*0318.0020.0004][.FB40.0020.0004][.F6E3.0000.0000][*0319.0020.0004] # PARENTHESIZED IDEOGRAPH SUPERVISE +32AC ; [.FB40.0020.0006][.F6E3.0000.0000] # CIRCLED IDEOGRAPH SUPERVISE +F933 ; [.FB40.0020.0002][.F6E7.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F933 +2F6C ; [.FB40.0020.0004][.F6EE.0000.0000] # KANGXI RADICAL EYE +2EAB ; [.FB40.0020.0004][.F6EE.0000.0000][.0000.0111.0004] # CJK RADICAL EYE +FAA8 ; [.FB40.0020.0002][.F6F4.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FAA8 +2F940 ; [.FB40.0020.0002][.F6F4.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F940 +F96D ; [.FB40.0020.0002][.F701.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F96D +2F945 ; [.FB40.0020.0002][.F71E.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F945 +2F946 ; [.FB40.0020.0002][.F71F.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F946 +2F947 ; [.FB40.0020.0002][.F71F.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F947 +FAAA ; [.FB40.0020.0002][.F740.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FAAA +FAA9 ; [.FB40.0020.0002][.F74A.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FAA9 +2F948 ; [.FB40.0020.0002][.F74A.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F948 +2F94A ; [.FB40.0020.0002][.F78B.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F94A +FA9D ; [.FB40.0020.0002][.F7A7.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA9D +2F6D ; [.FB40.0020.0004][.F7DB.0000.0000] # KANGXI RADICAL SPEAR +2F6E ; [.FB40.0020.0004][.F7E2.0000.0000] # KANGXI RADICAL ARROW +2F6F ; [.FB40.0020.0004][.F7F3.0000.0000] # KANGXI RADICAL STONE +2F94E ; [.FB40.0020.0002][.F84E.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F94E +F9CE ; [.FB40.0020.0002][.F86B.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F9CE +F93B ; [.FB40.0020.0002][.F88C.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F93B +2F94F ; [.FB40.0020.0002][.F88C.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F94F +FA4B ; [.FB40.0020.0002][.F891.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA4B +F947 ; [.FB40.0020.0002][.F8CA.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F947 +FAAB ; [.FB40.0020.0002][.F8CC.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FAAB +2F950 ; [.FB40.0020.0002][.F8CC.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F950 +F964 ; [.FB40.0020.0002][.F8FB.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F964 +F985 ; [.FB40.0020.0002][.F92A.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F985 +2F70 ; [.FB40.0020.0004][.F93A.0000.0000] # KANGXI RADICAL SPIRIT +2EAC ; [.FB40.0020.0004][.F93A.0000.0000][.0000.0111.0004] # CJK RADICAL SPIRIT ONE +2EAD ; [.FB40.0020.0004][.F93B.0000.0000] # CJK RADICAL SPIRIT TWO +FA18 ; [.FB40.0020.0002][.F93C.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA18 +FA4C ; [.FB40.0020.0002][.F93E.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA4C +3233 ; [*0318.0020.0004][.FB40.0020.0004][.F93E.0000.0000][*0319.0020.0004] # PARENTHESIZED IDEOGRAPH SOCIETY +3293 ; [.FB40.0020.0006][.F93E.0000.0000] # CIRCLED IDEOGRAPH SOCIETY +FA4E ; [.FB40.0020.0002][.F948.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA4E +FA4D ; [.FB40.0020.0002][.F949.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA4D +FA4F ; [.FB40.0020.0002][.F950.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA4F +FA50 ; [.FB40.0020.0002][.F956.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA50 +2F953 ; [.FB40.0020.0002][.F956.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F953 +FA51 ; [.FB40.0020.0002][.F95D.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA51 +3237 ; [*0318.0020.0004][.FB40.0020.0004][.F95D.0000.0000][*0319.0020.0004] # PARENTHESIZED IDEOGRAPH CONGRATULATION +3297 ; [.FB40.0020.0006][.F95D.0000.0000] # CIRCLED IDEOGRAPH CONGRATULATION +FA19 ; [.FB40.0020.0002][.F95E.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA19 +FA1A ; [.FB40.0020.0002][.F965.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA1A +3240 ; [*0318.0020.0004][.FB40.0020.0004][.F96D.0000.0000][*0319.0020.0004] # PARENTHESIZED IDEOGRAPH FESTIVAL +F93C ; [.FB40.0020.0002][.F97F.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F93C +1F232 ; [.FB40.0020.001C][.F981.0000.0000] # SQUARED CJK UNIFIED IDEOGRAPH-7981 +FA52 ; [.FB40.0020.0002][.F98D.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA52 +FA53 ; [.FB40.0020.0002][.F98E.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA53 +FA1B ; [.FB40.0020.0002][.F98F.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA1B +2F956 ; [.FB40.0020.0002][.F98F.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F956 +F9B6 ; [.FB40.0020.0002][.F9AE.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F9B6 +2F71 ; [.FB40.0020.0004][.F9B8.0000.0000] # KANGXI RADICAL TRACK +2F72 ; [.FB40.0020.0004][.F9BE.0000.0000] # KANGXI RADICAL GRAIN +F995 ; [.FB40.0020.0002][.F9CA.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F995 +3299 ; [.FB40.0020.0006][.F9D8.0000.0000] # CIRCLED IDEOGRAPH SECRET +2F957 ; [.FB40.0020.0002][.F9EB.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F957 +F956 ; [.FB40.0020.0002][.FA1C.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F956 +FA54 ; [.FB40.0020.0002][.FA40.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA54 +2F959 ; [.FB40.0020.0002][.FA40.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F959 +2F95A ; [.FB40.0020.0002][.FA4A.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F95A +2F95B ; [.FB40.0020.0002][.FA4F.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F95B +2F73 ; [.FB40.0020.0004][.FA74.0000.0000] # KANGXI RADICAL CAVE +1F233 ; [.FB40.0020.001C][.FA7A.0000.0000] # SQUARED CJK UNIFIED IDEOGRAPH-7A7A +FA55 ; [.FB40.0020.0002][.FA81.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA55 +FAAC ; [.FB40.0020.0002][.FAB1.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FAAC +F9F7 ; [.FB40.0020.0002][.FACB.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F9F7 +2F74 ; [.FB40.0020.0004][.FACB.0000.0000] # KANGXI RADICAL STAND +2F95F ; [.FB40.0020.0002][.FAEE.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F95F +2F75 ; [.FB40.0020.0004][.FAF9.0000.0000] # KANGXI RADICAL BAMBOO +2EAE ; [.FB40.0020.0004][.FAF9.0000.0000][.0000.0111.0004] # CJK RADICAL BAMBOO +F9F8 ; [.FB40.0020.0002][.FB20.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F9F8 +3247 ; [.FB40.0020.0006][.FB8F.0000.0000] # CIRCLED IDEOGRAPH KOTO +FA56 ; [.FB40.0020.0002][.FBC0.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA56 +FAAD ; [.FB40.0020.0002][.FBC0.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FAAD +2F962 ; [.FB40.0020.0002][.FBC6.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F962 +2F963 ; [.FB40.0020.0002][.FBC9.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F963 +F9A6 ; [.FB40.0020.0002][.FC3E.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F9A6 +F944 ; [.FB40.0020.0002][.FC60.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F944 +2F76 ; [.FB40.0020.0004][.FC73.0000.0000] # KANGXI RADICAL RICE +FAAE ; [.FB40.0020.0002][.FC7B.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FAAE +F9F9 ; [.FB40.0020.0002][.FC92.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F9F9 +FA1D ; [.FB40.0020.0002][.FCBE.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA1D +2F966 ; [.FB40.0020.0002][.FCD2.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F966 +FA03 ; [.FB40.0020.0002][.FCD6.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA03 +2F969 ; [.FB40.0020.0002][.FCE3.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F969 +F97B ; [.FB40.0020.0002][.FCE7.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F97B +2F968 ; [.FB40.0020.0002][.FCE8.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F968 +2F77 ; [.FB40.0020.0004][.FCF8.0000.0000] # KANGXI RADICAL SILK +2EAF ; [.FB40.0020.0004][.FCF9.0000.0000] # CJK RADICAL SILK +2F96A ; [.FB40.0020.0002][.FD00.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F96A +F9CF ; [.FB40.0020.0002][.FD10.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F9CF +F96A ; [.FB40.0020.0002][.FD22.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F96A +F94F ; [.FB40.0020.0002][.FD2F.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F94F +1F221 ; [.FB40.0020.001C][.FD42.0000.0000] # SQUARED CJK UNIFIED IDEOGRAPH-7D42 +FAAF ; [.FB40.0020.0002][.FD5B.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FAAF +2F96C ; [.FB40.0020.0002][.FD63.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F96C +F93D ; [.FB40.0020.0002][.FDA0.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F93D +F957 ; [.FB40.0020.0002][.FDBE.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F957 +2F96E ; [.FB40.0020.0002][.FDC7.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F96E +F996 ; [.FB40.0020.0002][.FDF4.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F996 +FA57 ; [.FB40.0020.0002][.FDF4.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA57 +FAB0 ; [.FB40.0020.0002][.FDF4.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FAB0 +2F96F ; [.FB40.0020.0002][.FE02.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F96F +FA58 ; [.FB40.0020.0002][.FE09.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA58 +F950 ; [.FB40.0020.0002][.FE37.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F950 +FA59 ; [.FB40.0020.0002][.FE41.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA59 +2F970 ; [.FB40.0020.0002][.FE45.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F970 +2EB0 ; [.FB40.0020.0004][.FE9F.0000.0000] # CJK RADICAL C-SIMPLIFIED SILK +2F78 ; [.FB40.0020.0004][.FF36.0000.0000] # KANGXI RADICAL JAR +FAB1 ; [.FB40.0020.0002][.FF3E.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FAB1 +2F79 ; [.FB40.0020.0004][.FF51.0000.0000] # KANGXI RADICAL NET +2EB2 ; [.FB40.0020.0004][.FF52.0000.0000] # CJK RADICAL NET TWO +2EB5 ; [.FB40.0020.0004][.FF52.0000.0000][.0000.0111.0004] # CJK RADICAL MESH +2EB1 ; [.FB40.0020.0004][.FF53.0000.0000] # CJK RADICAL NET ONE +2EB3 ; [.FB40.0020.0004][.FF53.0000.0000][.0000.0111.0004] # CJK RADICAL NET THREE +2EB4 ; [.FB40.0020.0004][.FF53.0000.0000][.0000.0112.0004] # CJK RADICAL NET FOUR +FA5A ; [.FB40.0020.0002][.FF72.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA5A +F9E6 ; [.FB40.0020.0002][.FF79.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F9E6 +2F976 ; [.FB40.0020.0002][.FF7A.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F976 +F90F ; [.FB40.0020.0002][.FF85.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F90F +2F7A ; [.FB40.0020.0004][.FF8A.0000.0000] # KANGXI RADICAL SHEEP +2EB6 ; [.FB40.0020.0004][.FF8A.0000.0000][.0000.0111.0004] # CJK RADICAL SHEEP +2EB7 ; [.FB40.0020.0004][.FF8A.0000.0000][.0000.0112.0004] # CJK RADICAL RAM +2EB8 ; [.FB40.0020.0004][.FF8B.0000.0000] # CJK RADICAL EWE +2F978 ; [.FB40.0020.0002][.FF95.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F978 +F9AF ; [.FB40.0020.0002][.FF9A.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F9AF +FA1E ; [.FB40.0020.0002][.FFBD.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA1E +2F7B ; [.FB40.0020.0004][.FFBD.0000.0000] # KANGXI RADICAL FEATHER +2F979 ; [.FB40.0020.0002][.FFFA.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F979 +F934 ; [.FB41.0020.0002][.8001.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F934 +2F7C ; [.FB41.0020.0004][.8001.0000.0000] # KANGXI RADICAL OLD +2EB9 ; [.FB41.0020.0004][.8002.0000.0000] # CJK RADICAL OLD +FA5B ; [.FB41.0020.0002][.8005.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA5B +FAB2 ; [.FB41.0020.0002][.8005.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FAB2 +2F97A ; [.FB41.0020.0002][.8005.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F97A +2F7D ; [.FB41.0020.0004][.800C.0000.0000] # KANGXI RADICAL AND +2F7E ; [.FB41.0020.0004][.8012.0000.0000] # KANGXI RADICAL PLOW +2F7F ; [.FB41.0020.0004][.8033.0000.0000] # KANGXI RADICAL EAR +F9B0 ; [.FB41.0020.0002][.8046.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F9B0 +2F97D ; [.FB41.0020.0002][.8060.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F97D +F997 ; [.FB41.0020.0002][.806F.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F997 +2F97F ; [.FB41.0020.0002][.8070.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F97F +F945 ; [.FB41.0020.0002][.807E.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F945 +2F80 ; [.FB41.0020.0004][.807F.0000.0000] # KANGXI RADICAL BRUSH +2EBB ; [.FB41.0020.0004][.807F.0000.0000][.0000.0111.0004] # CJK RADICAL BRUSH TWO +2EBA ; [.FB41.0020.0004][.8080.0000.0000] # CJK RADICAL BRUSH ONE +2F81 ; [.FB41.0020.0004][.8089.0000.0000] # KANGXI RADICAL MEAT +2EBC ; [.FB41.0020.0004][.8089.0000.0000][.0000.0111.0004] # CJK RADICAL MEAT +F953 ; [.FB41.0020.0002][.808B.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F953 +2F8D6 ; [.FB41.0020.0002][.80AD.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F8D6 +2F982 ; [.FB41.0020.0002][.80B2.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F982 +2F983 ; [.FB41.0020.0002][.8103.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F983 +2F985 ; [.FB41.0020.0002][.813E.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F985 +F926 ; [.FB41.0020.0002][.81D8.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F926 +2F82 ; [.FB41.0020.0004][.81E3.0000.0000] # KANGXI RADICAL MINISTER +F9F6 ; [.FB41.0020.0002][.81E8.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F9F6 +2F83 ; [.FB41.0020.0004][.81EA.0000.0000] # KANGXI RADICAL SELF +3242 ; [*0318.0020.0004][.FB41.0020.0004][.81EA.0000.0000][*0319.0020.0004] # PARENTHESIZED IDEOGRAPH SELF +FA5C ; [.FB41.0020.0002][.81ED.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA5C +2F84 ; [.FB41.0020.0004][.81F3.0000.0000] # KANGXI RADICAL ARRIVE +3243 ; [*0318.0020.0004][.FB41.0020.0004][.81F3.0000.0000][*0319.0020.0004] # PARENTHESIZED IDEOGRAPH REACH +2F85 ; [.FB41.0020.0004][.81FC.0000.0000] # KANGXI RADICAL MORTAR +2EBD ; [.FB41.0020.0004][.81FC.0000.0000][.0000.0111.0004] # CJK RADICAL MORTAR +2F893 ; [.FB41.0020.0002][.8201.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F893 +2F98B ; [.FB41.0020.0002][.8201.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F98B +2F98C ; [.FB41.0020.0002][.8204.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F98C +2F86 ; [.FB41.0020.0004][.820C.0000.0000] # KANGXI RADICAL TONGUE +FA6D ; [.FB41.0020.0002][.8218.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA6D +2F87 ; [.FB41.0020.0004][.821B.0000.0000] # KANGXI RADICAL OPPOSE +2F88 ; [.FB41.0020.0004][.821F.0000.0000] # KANGXI RADICAL BOAT +2F89 ; [.FB41.0020.0004][.826E.0000.0000] # KANGXI RADICAL STOPPING +F97C ; [.FB41.0020.0002][.826F.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F97C +2F8A ; [.FB41.0020.0004][.8272.0000.0000] # KANGXI RADICAL COLOR +2F8B ; [.FB41.0020.0004][.8278.0000.0000] # KANGXI RADICAL GRASS +FA5D ; [.FB41.0020.0002][.8279.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA5D +FA5E ; [.FB41.0020.0002][.8279.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA5E +2EBE ; [.FB41.0020.0004][.8279.0000.0000] # CJK RADICAL GRASS ONE +2EBF ; [.FB41.0020.0004][.8279.0000.0000][.0000.0111.0004] # CJK RADICAL GRASS TWO +2EC0 ; [.FB41.0020.0004][.8279.0000.0000][.0000.0112.0004] # CJK RADICAL GRASS THREE +2F990 ; [.FB41.0020.0002][.828B.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F990 +2F98F ; [.FB41.0020.0002][.8291.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F98F +2F991 ; [.FB41.0020.0002][.829D.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F991 +2F993 ; [.FB41.0020.0002][.82B1.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F993 +2F994 ; [.FB41.0020.0002][.82B3.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F994 +2F995 ; [.FB41.0020.0002][.82BD.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F995 +F974 ; [.FB41.0020.0002][.82E5.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F974 +2F998 ; [.FB41.0020.0002][.82E5.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F998 +2F996 ; [.FB41.0020.0002][.82E6.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F996 +2F999 ; [.FB41.0020.0002][.831D.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F999 +2F99C ; [.FB41.0020.0002][.8323.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F99C +F9FE ; [.FB41.0020.0002][.8336.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F9FE +FAB3 ; [.FB41.0020.0002][.8352.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FAB3 +2F9A0 ; [.FB41.0020.0002][.8353.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F9A0 +2F99A ; [.FB41.0020.0002][.8363.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F99A +2F99B ; [.FB41.0020.0002][.83AD.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F99B +2F99D ; [.FB41.0020.0002][.83BD.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F99D +F93E ; [.FB41.0020.0002][.83C9.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F93E +2F9A1 ; [.FB41.0020.0002][.83CA.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F9A1 +2F9A2 ; [.FB41.0020.0002][.83CC.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F9A2 +2F9A3 ; [.FB41.0020.0002][.83DC.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F9A3 +2F99E ; [.FB41.0020.0002][.83E7.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F99E +FAB4 ; [.FB41.0020.0002][.83EF.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FAB4 +F958 ; [.FB41.0020.0002][.83F1.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F958 +F918 ; [.FB41.0020.0002][.843D.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F918 +F96E ; [.FB41.0020.0002][.8449.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F96E +FA5F ; [.FB41.0020.0002][.8457.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA5F +2F99F ; [.FB41.0020.0002][.8457.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F99F +F999 ; [.FB41.0020.0002][.84EE.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F999 +2F9A8 ; [.FB41.0020.0002][.84F1.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F9A8 +2F9A9 ; [.FB41.0020.0002][.84F3.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F9A9 +F9C2 ; [.FB41.0020.0002][.84FC.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F9C2 +2F9AA ; [.FB41.0020.0002][.8516.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F9AA +2F9AC ; [.FB41.0020.0002][.8564.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F9AC +F923 ; [.FB41.0020.0002][.85CD.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F923 +F9F0 ; [.FB41.0020.0002][.85FA.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F9F0 +F935 ; [.FB41.0020.0002][.8606.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F935 +FA20 ; [.FB41.0020.0002][.8612.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA20 +F91F ; [.FB41.0020.0002][.862D.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F91F +F910 ; [.FB41.0020.0002][.863F.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F910 +2F8C ; [.FB41.0020.0004][.864D.0000.0000] # KANGXI RADICAL TIGER +2EC1 ; [.FB41.0020.0004][.864E.0000.0000] # CJK RADICAL TIGER +2F9B3 ; [.FB41.0020.0002][.8650.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F9B3 +F936 ; [.FB41.0020.0002][.865C.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F936 +2F9B4 ; [.FB41.0020.0002][.865C.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F9B4 +2F9B5 ; [.FB41.0020.0002][.8667.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F9B5 +2F9B6 ; [.FB41.0020.0002][.8669.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F9B6 +2F8D ; [.FB41.0020.0004][.866B.0000.0000] # KANGXI RADICAL INSECT +2F9B8 ; [.FB41.0020.0002][.8688.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F9B8 +2F9B7 ; [.FB41.0020.0002][.86A9.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F9B7 +2F9BA ; [.FB41.0020.0002][.86E2.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F9BA +2F9B9 ; [.FB41.0020.0002][.870E.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F9B9 +2F9BC ; [.FB41.0020.0002][.8728.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F9BC +2F9BD ; [.FB41.0020.0002][.876B.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F9BD +FAB5 ; [.FB41.0020.0002][.8779.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FAB5 +2F9BB ; [.FB41.0020.0002][.8779.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F9BB +2F9BE ; [.FB41.0020.0002][.8786.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F9BE +F911 ; [.FB41.0020.0002][.87BA.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F911 +2F9C0 ; [.FB41.0020.0002][.87E1.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F9C0 +2F9C1 ; [.FB41.0020.0002][.8801.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F9C1 +F927 ; [.FB41.0020.0002][.881F.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F927 +2F8E ; [.FB41.0020.0004][.8840.0000.0000] # KANGXI RADICAL BLOOD +FA08 ; [.FB41.0020.0002][.884C.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA08 +2F8F ; [.FB41.0020.0004][.884C.0000.0000] # KANGXI RADICAL WALK ENCLOSURE +2F9C3 ; [.FB41.0020.0002][.8860.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F9C3 +2F9C4 ; [.FB41.0020.0002][.8863.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F9C4 +2F90 ; [.FB41.0020.0004][.8863.0000.0000] # KANGXI RADICAL CLOTHES +2EC2 ; [.FB41.0020.0004][.8864.0000.0000] # CJK RADICAL CLOTHES +F9A0 ; [.FB41.0020.0002][.88C2.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F9A0 +F9E7 ; [.FB41.0020.0002][.88CF.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F9E7 +2F9C6 ; [.FB41.0020.0002][.88D7.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F9C6 +2F9C7 ; [.FB41.0020.0002][.88DE.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F9C7 +F9E8 ; [.FB41.0020.0002][.88E1.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F9E8 +F912 ; [.FB41.0020.0002][.88F8.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F912 +2F9C9 ; [.FB41.0020.0002][.88FA.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F9C9 +FA60 ; [.FB41.0020.0002][.8910.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA60 +FAB6 ; [.FB41.0020.0002][.8941.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FAB6 +F924 ; [.FB41.0020.0002][.8964.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F924 +2F91 ; [.FB41.0020.0004][.897E.0000.0000] # KANGXI RADICAL WEST +2EC4 ; [.FB41.0020.0004][.897F.0000.0000] # CJK RADICAL WEST TWO +2EC3 ; [.FB41.0020.0004][.8980.0000.0000] # CJK RADICAL WEST ONE +FAB7 ; [.FB41.0020.0002][.8986.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FAB7 +FA0A ; [.FB41.0020.0002][.898B.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA0A +2F92 ; [.FB41.0020.0004][.898B.0000.0000] # KANGXI RADICAL SEE +FA61 ; [.FB41.0020.0002][.8996.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA61 +FAB8 ; [.FB41.0020.0002][.8996.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FAB8 +2EC5 ; [.FB41.0020.0004][.89C1.0000.0000] # CJK RADICAL C-SIMPLIFIED SEE +2EC6 ; [.FB41.0020.0004][.89D2.0000.0000] # CJK RADICAL SIMPLIFIED HORN +2F93 ; [.FB41.0020.0004][.89D2.0000.0000] # KANGXI RADICAL HORN +2EC7 ; [.FB41.0020.0004][.89D2.0000.0000][.0000.0111.0004] # CJK RADICAL HORN +1F216 ; [.FB41.0020.001C][.89E3.0000.0000] # SQUARED CJK UNIFIED IDEOGRAPH-89E3 +2F94 ; [.FB41.0020.0004][.8A00.0000.0000] # KANGXI RADICAL SPEECH +2F9CF ; [.FB41.0020.0002][.8AA0.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F9CF +F96F ; [.FB41.0020.0002][.8AAA.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F96F +F9A1 ; [.FB41.0020.0002][.8AAA.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F9A1 +FAB9 ; [.FB41.0020.0002][.8ABF.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FAB9 +FABB ; [.FB41.0020.0002][.8ACB.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FABB +F97D ; [.FB41.0020.0002][.8AD2.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F97D +F941 ; [.FB41.0020.0002][.8AD6.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F941 +FABE ; [.FB41.0020.0002][.8AED.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FABE +2F9D0 ; [.FB41.0020.0002][.8AED.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F9D0 +FA22 ; [.FB41.0020.0002][.8AF8.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA22 +FABA ; [.FB41.0020.0002][.8AF8.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FABA +F95D ; [.FB41.0020.0002][.8AFE.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F95D +FABD ; [.FB41.0020.0002][.8AFE.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FABD +FA62 ; [.FB41.0020.0002][.8B01.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA62 +FABC ; [.FB41.0020.0002][.8B01.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FABC +FA63 ; [.FB41.0020.0002][.8B39.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA63 +FABF ; [.FB41.0020.0002][.8B39.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FABF +F9FC ; [.FB41.0020.0002][.8B58.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F9FC +F95A ; [.FB41.0020.0002][.8B80.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F95A +FAC0 ; [.FB41.0020.0002][.8B8A.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FAC0 +2F9D1 ; [.FB41.0020.0002][.8B8A.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F9D1 +2EC8 ; [.FB41.0020.0004][.8BA0.0000.0000] # CJK RADICAL C-SIMPLIFIED SPEECH +2F95 ; [.FB41.0020.0004][.8C37.0000.0000] # KANGXI RADICAL VALLEY +2F96 ; [.FB41.0020.0004][.8C46.0000.0000] # KANGXI RADICAL BEAN +F900 ; [.FB41.0020.0002][.8C48.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F900 +2F9D2 ; [.FB41.0020.0002][.8C55.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F9D2 +2F97 ; [.FB41.0020.0004][.8C55.0000.0000] # KANGXI RADICAL PIG +2F98 ; [.FB41.0020.0004][.8C78.0000.0000] # KANGXI RADICAL BADGER +2F99 ; [.FB41.0020.0004][.8C9D.0000.0000] # KANGXI RADICAL SHELL +3236 ; [*0318.0020.0004][.FB41.0020.0004][.8CA1.0000.0000][*0319.0020.0004] # PARENTHESIZED IDEOGRAPH FINANCIAL +3296 ; [.FB41.0020.0006][.8CA1.0000.0000] # CIRCLED IDEOGRAPH FINANCIAL +1F223 ; [.FB41.0020.001C][.8CA9.0000.0000] # SQUARED CJK UNIFIED IDEOGRAPH-8CA9 +2F9D4 ; [.FB41.0020.0002][.8CAB.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F9D4 +2F9D5 ; [.FB41.0020.0002][.8CC1.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F9D5 +F948 ; [.FB41.0020.0002][.8CC2.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F948 +323E ; [*0318.0020.0004][.FB41.0020.0004][.8CC7.0000.0000][*0319.0020.0004] # PARENTHESIZED IDEOGRAPH RESOURCE +32AE ; [.FB41.0020.0006][.8CC7.0000.0000] # CIRCLED IDEOGRAPH RESOURCE +F903 ; [.FB41.0020.0002][.8CC8.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F903 +FA64 ; [.FB41.0020.0002][.8CD3.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA64 +FA65 ; [.FB41.0020.0002][.8D08.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA65 +FAC1 ; [.FB41.0020.0002][.8D08.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FAC1 +2F9D6 ; [.FB41.0020.0002][.8D1B.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F9D6 +2EC9 ; [.FB41.0020.0004][.8D1D.0000.0000] # CJK RADICAL C-SIMPLIFIED SHELL +2F9A ; [.FB41.0020.0004][.8D64.0000.0000] # KANGXI RADICAL RED +2F9B ; [.FB41.0020.0004][.8D70.0000.0000] # KANGXI RADICAL RUN +1F230 ; [.FB41.0020.001C][.8D70.0000.0000] # SQUARED CJK UNIFIED IDEOGRAPH-8D70 +2F9D7 ; [.FB41.0020.0002][.8D77.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F9D7 +2F9C ; [.FB41.0020.0004][.8DB3.0000.0000] # KANGXI RADICAL FOOT +2ECA ; [.FB41.0020.0004][.8DB3.0000.0000][.0000.0111.0004] # CJK RADICAL FOOT +2F9DB ; [.FB41.0020.0002][.8DBC.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F9DB +2F9DA ; [.FB41.0020.0002][.8DCB.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F9DA +F937 ; [.FB41.0020.0002][.8DEF.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F937 +2F9DC ; [.FB41.0020.0002][.8DF0.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F9DC +2F9D ; [.FB41.0020.0004][.8EAB.0000.0000] # KANGXI RADICAL BODY +F902 ; [.FB41.0020.0002][.8ECA.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F902 +2F9E ; [.FB41.0020.0004][.8ECA.0000.0000] # KANGXI RADICAL CART +2F9DE ; [.FB41.0020.0002][.8ED4.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F9DE +F998 ; [.FB41.0020.0002][.8F26.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F998 +F9D7 ; [.FB41.0020.0002][.8F2A.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F9D7 +FAC2 ; [.FB41.0020.0002][.8F38.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FAC2 +2F9DF ; [.FB41.0020.0002][.8F38.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F9DF +FA07 ; [.FB41.0020.0002][.8F3B.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA07 +F98D ; [.FB41.0020.0002][.8F62.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F98D +2ECB ; [.FB41.0020.0004][.8F66.0000.0000] # CJK RADICAL C-SIMPLIFIED CART +2F9F ; [.FB41.0020.0004][.8F9B.0000.0000] # KANGXI RADICAL BITTER +2F98D ; [.FB41.0020.0002][.8F9E.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F98D +F971 ; [.FB41.0020.0002][.8FB0.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F971 +2FA0 ; [.FB41.0020.0004][.8FB0.0000.0000] # KANGXI RADICAL MORNING +2FA1 ; [.FB41.0020.0004][.8FB5.0000.0000] # KANGXI RADICAL WALK +FA66 ; [.FB41.0020.0002][.8FB6.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA66 +2ECC ; [.FB41.0020.0004][.8FB6.0000.0000] # CJK RADICAL SIMPLIFIED WALK +2ECD ; [.FB41.0020.0004][.8FB6.0000.0000][.0000.0111.0004] # CJK RADICAL WALK ONE +2ECE ; [.FB41.0020.0004][.8FB6.0000.0000][.0000.0112.0004] # CJK RADICAL WALK TWO +F99A ; [.FB41.0020.0002][.9023.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F99A +FA25 ; [.FB41.0020.0002][.9038.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA25 +FA67 ; [.FB41.0020.0002][.9038.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA67 +1F22B ; [.FB41.0020.001C][.904A.0000.0000] # SQUARED CJK UNIFIED IDEOGRAPH-904A +329C ; [.FB41.0020.0006][.9069.0000.0000] # CIRCLED IDEOGRAPH SUITABLE +FAC3 ; [.FB41.0020.0002][.9072.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FAC3 +F9C3 ; [.FB41.0020.0002][.907C.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F9C3 +F913 ; [.FB41.0020.0002][.908F.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F913 +2FA2 ; [.FB41.0020.0004][.9091.0000.0000] # KANGXI RADICAL CITY +2ECF ; [.FB41.0020.0004][.9091.0000.0000][.0000.0111.0004] # CJK RADICAL CITY +2F9E2 ; [.FB41.0020.0002][.9094.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F9E2 +F92C ; [.FB41.0020.0002][.90CE.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F92C +FA2E ; [.FB41.0020.0002][.90DE.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA2E +2F9E3 ; [.FB41.0020.0002][.90F1.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F9E3 +FA26 ; [.FB41.0020.0002][.90FD.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA26 +2F9E4 ; [.FB41.0020.0002][.9111.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F9E4 +2F9E6 ; [.FB41.0020.0002][.911B.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F9E6 +2FA3 ; [.FB41.0020.0004][.9149.0000.0000] # KANGXI RADICAL WINE +1F23B ; [.FB41.0020.001C][.914D.0000.0000] # SQUARED CJK UNIFIED IDEOGRAPH-914D +F919 ; [.FB41.0020.0002][.916A.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F919 +FAC4 ; [.FB41.0020.0002][.9199.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FAC4 +F9B7 ; [.FB41.0020.0002][.91B4.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F9B7 +2FA4 ; [.FB41.0020.0004][.91C6.0000.0000] # KANGXI RADICAL DISTINGUISH +F9E9 ; [.FB41.0020.0002][.91CC.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F9E9 +2FA5 ; [.FB41.0020.0004][.91CC.0000.0000] # KANGXI RADICAL VILLAGE +F97E ; [.FB41.0020.0002][.91CF.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F97E +F90A ; [.FB41.0020.0002][.91D1.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F90A +2FA6 ; [.FB41.0020.0004][.91D1.0000.0000] # KANGXI RADICAL GOLD +322E ; [*0318.0020.0004][.FB41.0020.0004][.91D1.0000.0000][*0319.0020.0004] # PARENTHESIZED IDEOGRAPH METAL +328E ; [.FB41.0020.0006][.91D1.0000.0000] # CIRCLED IDEOGRAPH METAL +F9B1 ; [.FB41.0020.0002][.9234.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F9B1 +2F9E7 ; [.FB41.0020.0002][.9238.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F9E7 +FAC5 ; [.FB41.0020.0002][.9276.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FAC5 +2F9EA ; [.FB41.0020.0002][.927C.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F9EA +2F9E8 ; [.FB41.0020.0002][.92D7.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F9E8 +2F9E9 ; [.FB41.0020.0002][.92D8.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F9E9 +F93F ; [.FB41.0020.0002][.9304.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F93F +F99B ; [.FB41.0020.0002][.934A.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F99B +2F9EB ; [.FB41.0020.0002][.93F9.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F9EB +2F9EC ; [.FB41.0020.0002][.9415.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F9EC +2ED0 ; [.FB41.0020.0004][.9485.0000.0000] # CJK RADICAL C-SIMPLIFIED GOLD +2ED1 ; [.FB41.0020.0004][.9577.0000.0000] # CJK RADICAL LONG ONE +2FA7 ; [.FB41.0020.0004][.9577.0000.0000] # KANGXI RADICAL LONG +2ED2 ; [.FB41.0020.0004][.9578.0000.0000] # CJK RADICAL LONG TWO +2ED3 ; [.FB41.0020.0004][.957F.0000.0000] # CJK RADICAL C-SIMPLIFIED LONG +2FA8 ; [.FB41.0020.0004][.9580.0000.0000] # KANGXI RADICAL GATE +2F9EE ; [.FB41.0020.0002][.958B.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F9EE +F986 ; [.FB41.0020.0002][.95AD.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F986 +2F9F0 ; [.FB41.0020.0002][.95B7.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F9F0 +2ED4 ; [.FB41.0020.0004][.95E8.0000.0000] # CJK RADICAL C-SIMPLIFIED GATE +2FA9 ; [.FB41.0020.0004][.961C.0000.0000] # KANGXI RADICAL MOUND +2ED5 ; [.FB41.0020.0004][.961C.0000.0000][.0000.0111.0004] # CJK RADICAL MOUND ONE +2ED6 ; [.FB41.0020.0004][.961D.0000.0000] # CJK RADICAL MOUND TWO +F9C6 ; [.FB41.0020.0002][.962E.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F9C6 +F951 ; [.FB41.0020.0002][.964B.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F951 +FA09 ; [.FB41.0020.0002][.964D.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA09 +F959 ; [.FB41.0020.0002][.9675.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F959 +F9D3 ; [.FB41.0020.0002][.9678.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F9D3 +FAC6 ; [.FB41.0020.0002][.967C.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FAC6 +F9DC ; [.FB41.0020.0002][.9686.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F9DC +F9F1 ; [.FB41.0020.0002][.96A3.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F9F1 +2FAA ; [.FB41.0020.0004][.96B6.0000.0000] # KANGXI RADICAL SLAVE +FA2F ; [.FB41.0020.0002][.96B7.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA2F +F9B8 ; [.FB41.0020.0002][.96B8.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F9B8 +2FAB ; [.FB41.0020.0004][.96B9.0000.0000] # KANGXI RADICAL SHORT TAILED BIRD +2F9F3 ; [.FB41.0020.0002][.96C3.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F9F3 +F9EA ; [.FB41.0020.0002][.96E2.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F9EA +FA68 ; [.FB41.0020.0002][.96E3.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA68 +FAC7 ; [.FB41.0020.0002][.96E3.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FAC7 +2FAC ; [.FB41.0020.0004][.96E8.0000.0000] # KANGXI RADICAL RAIN +2ED7 ; [.FB41.0020.0004][.96E8.0000.0000][.0000.0111.0004] # CJK RADICAL RAIN +F9B2 ; [.FB41.0020.0002][.96F6.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F9B2 +F949 ; [.FB41.0020.0002][.96F7.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F949 +2F9F5 ; [.FB41.0020.0002][.9723.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F9F5 +F938 ; [.FB41.0020.0002][.9732.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F938 +F9B3 ; [.FB41.0020.0002][.9748.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F9B3 +2FAD ; [.FB41.0020.0004][.9751.0000.0000] # KANGXI RADICAL BLUE +2ED8 ; [.FB41.0020.0004][.9752.0000.0000] # CJK RADICAL BLUE +FA1C ; [.FB41.0020.0002][.9756.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA1C +FAC8 ; [.FB41.0020.0002][.9756.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FAC8 +2FAE ; [.FB41.0020.0004][.975E.0000.0000] # KANGXI RADICAL WRONG +2FAF ; [.FB41.0020.0004][.9762.0000.0000] # KANGXI RADICAL FACE +2FB0 ; [.FB41.0020.0004][.9769.0000.0000] # KANGXI RADICAL LEATHER +2FB1 ; [.FB41.0020.0004][.97CB.0000.0000] # KANGXI RADICAL TANNED LEATHER +FAC9 ; [.FB41.0020.0002][.97DB.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FAC9 +2F9FA ; [.FB41.0020.0002][.97E0.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F9FA +2ED9 ; [.FB41.0020.0004][.97E6.0000.0000] # CJK RADICAL C-SIMPLIFIED TANNED LEATHER +2FB2 ; [.FB41.0020.0004][.97ED.0000.0000] # KANGXI RADICAL LEEK +2FB3 ; [.FB41.0020.0004][.97F3.0000.0000] # KANGXI RADICAL SOUND +FA69 ; [.FB41.0020.0002][.97FF.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA69 +FACA ; [.FB41.0020.0002][.97FF.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FACA +2FB4 ; [.FB41.0020.0004][.9801.0000.0000] # KANGXI RADICAL LEAF +32A0 ; [.FB41.0020.0006][.9805.0000.0000] # CIRCLED IDEOGRAPH ITEM +FACB ; [.FB41.0020.0002][.980B.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FACB +2F9FE ; [.FB41.0020.0002][.980B.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F9FE +2F9FF ; [.FB41.0020.0002][.980B.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F9FF +F9B4 ; [.FB41.0020.0002][.9818.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F9B4 +2FA00 ; [.FB41.0020.0002][.9829.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2FA00 +FA6A ; [.FB41.0020.0002][.983B.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA6A +FACC ; [.FB41.0020.0002][.983B.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FACC +F9D0 ; [.FB41.0020.0002][.985E.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F9D0 +2EDA ; [.FB41.0020.0004][.9875.0000.0000] # CJK RADICAL C-SIMPLIFIED LEAF +2FB5 ; [.FB41.0020.0004][.98A8.0000.0000] # KANGXI RADICAL WIND +2EDB ; [.FB41.0020.0004][.98CE.0000.0000] # CJK RADICAL C-SIMPLIFIED WIND +2FB6 ; [.FB41.0020.0004][.98DB.0000.0000] # KANGXI RADICAL FLY +2EDC ; [.FB41.0020.0004][.98DE.0000.0000] # CJK RADICAL C-SIMPLIFIED FLY +2EDD ; [.FB41.0020.0004][.98DF.0000.0000] # CJK RADICAL EAT ONE +2FB7 ; [.FB41.0020.0004][.98DF.0000.0000] # KANGXI RADICAL EAT +2EDF ; [.FB41.0020.0004][.98E0.0000.0000] # CJK RADICAL EAT THREE +2EDE ; [.FB41.0020.0004][.98E0.0000.0000][.0000.0111.0004] # CJK RADICAL EAT TWO +2FA02 ; [.FB41.0020.0002][.98E2.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2FA02 +FA2A ; [.FB41.0020.0002][.98EF.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA2A +FA2B ; [.FB41.0020.0002][.98FC.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA2B +FA2C ; [.FB41.0020.0002][.9928.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA2C +2FA04 ; [.FB41.0020.0002][.9929.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2FA04 +2EE0 ; [.FB41.0020.0004][.9963.0000.0000] # CJK RADICAL C-SIMPLIFIED EAT +2FB8 ; [.FB41.0020.0004][.9996.0000.0000] # KANGXI RADICAL HEAD +2EE1 ; [.FB41.0020.0004][.9996.0000.0000][.0000.0111.0004] # CJK RADICAL HEAD +2FB9 ; [.FB41.0020.0004][.9999.0000.0000] # KANGXI RADICAL FRAGRANT +2FA05 ; [.FB41.0020.0002][.99A7.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2FA05 +2FBA ; [.FB41.0020.0004][.99AC.0000.0000] # KANGXI RADICAL HORSE +2FA06 ; [.FB41.0020.0002][.99C2.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2FA06 +F91A ; [.FB41.0020.0002][.99F1.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F91A +2FA07 ; [.FB41.0020.0002][.99FE.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2FA07 +F987 ; [.FB41.0020.0002][.9A6A.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F987 +2EE2 ; [.FB41.0020.0004][.9A6C.0000.0000] # CJK RADICAL C-SIMPLIFIED HORSE +2FBB ; [.FB41.0020.0004][.9AA8.0000.0000] # KANGXI RADICAL BONE +2EE3 ; [.FB41.0020.0004][.9AA8.0000.0000][.0000.0111.0004] # CJK RADICAL BONE +2FBC ; [.FB41.0020.0004][.9AD8.0000.0000] # KANGXI RADICAL TALL +2FBD ; [.FB41.0020.0004][.9ADF.0000.0000] # KANGXI RADICAL HAIR +FACD ; [.FB41.0020.0002][.9B12.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FACD +2FA0A ; [.FB41.0020.0002][.9B12.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2FA0A +2FBE ; [.FB41.0020.0004][.9B25.0000.0000] # KANGXI RADICAL FIGHT +2FBF ; [.FB41.0020.0004][.9B2F.0000.0000] # KANGXI RADICAL SACRIFICIAL WINE +2FC0 ; [.FB41.0020.0004][.9B32.0000.0000] # KANGXI RADICAL CAULDRON +2FC1 ; [.FB41.0020.0004][.9B3C.0000.0000] # KANGXI RADICAL GHOST +2EE4 ; [.FB41.0020.0004][.9B3C.0000.0000][.0000.0111.0004] # CJK RADICAL GHOST +2FC2 ; [.FB41.0020.0004][.9B5A.0000.0000] # KANGXI RADICAL FISH +F939 ; [.FB41.0020.0002][.9B6F.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F939 +2FA0B ; [.FB41.0020.0002][.9C40.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2FA0B +F9F2 ; [.FB41.0020.0002][.9C57.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F9F2 +2EE5 ; [.FB41.0020.0004][.9C7C.0000.0000] # CJK RADICAL C-SIMPLIFIED FISH +2FC3 ; [.FB41.0020.0004][.9CE5.0000.0000] # KANGXI RADICAL BIRD +2FA0C ; [.FB41.0020.0002][.9CFD.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2FA0C +2FA0F ; [.FB41.0020.0002][.9D67.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2FA0F +FA2D ; [.FB41.0020.0002][.9DB4.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA2D +F93A ; [.FB41.0020.0002][.9DFA.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F93A +F920 ; [.FB41.0020.0002][.9E1E.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F920 +2EE6 ; [.FB41.0020.0004][.9E1F.0000.0000] # CJK RADICAL C-SIMPLIFIED BIRD +2FC4 ; [.FB41.0020.0004][.9E75.0000.0000] # KANGXI RADICAL SALT +2EE7 ; [.FB41.0020.0004][.9E75.0000.0000][.0000.0111.0004] # CJK RADICAL C-SIMPLIFIED SALT +F940 ; [.FB41.0020.0002][.9E7F.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F940 +2FC5 ; [.FB41.0020.0004][.9E7F.0000.0000] # KANGXI RADICAL DEER +F988 ; [.FB41.0020.0002][.9E97.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F988 +F9F3 ; [.FB41.0020.0002][.9E9F.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F9F3 +2FC6 ; [.FB41.0020.0004][.9EA5.0000.0000] # KANGXI RADICAL WHEAT +2EE8 ; [.FB41.0020.0004][.9EA6.0000.0000] # CJK RADICAL SIMPLIFIED WHEAT +2FA15 ; [.FB41.0020.0002][.9EBB.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2FA15 +2FC7 ; [.FB41.0020.0004][.9EBB.0000.0000] # KANGXI RADICAL HEMP +2FC8 ; [.FB41.0020.0004][.9EC3.0000.0000] # KANGXI RADICAL YELLOW +2EE9 ; [.FB41.0020.0004][.9EC4.0000.0000] # CJK RADICAL SIMPLIFIED YELLOW +2FC9 ; [.FB41.0020.0004][.9ECD.0000.0000] # KANGXI RADICAL MILLET +F989 ; [.FB41.0020.0002][.9ECE.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F989 +2FCA ; [.FB41.0020.0004][.9ED1.0000.0000] # KANGXI RADICAL BLACK +2FA17 ; [.FB41.0020.0002][.9EF9.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2FA17 +2FCB ; [.FB41.0020.0004][.9EF9.0000.0000] # KANGXI RADICAL EMBROIDERY +2FCC ; [.FB41.0020.0004][.9EFD.0000.0000] # KANGXI RADICAL FROG +2FA18 ; [.FB41.0020.0002][.9EFE.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2FA18 +2EEA ; [.FB41.0020.0004][.9EFE.0000.0000] # CJK RADICAL C-SIMPLIFIED FROG +2FA19 ; [.FB41.0020.0002][.9F05.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2FA19 +2FCD ; [.FB41.0020.0004][.9F0E.0000.0000] # KANGXI RADICAL TRIPOD +2FA1A ; [.FB41.0020.0002][.9F0F.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2FA1A +2FCE ; [.FB41.0020.0004][.9F13.0000.0000] # KANGXI RADICAL DRUM +2FA1B ; [.FB41.0020.0002][.9F16.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2FA1B +2FCF ; [.FB41.0020.0004][.9F20.0000.0000] # KANGXI RADICAL RAT +2FA1C ; [.FB41.0020.0002][.9F3B.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2FA1C +2FD0 ; [.FB41.0020.0004][.9F3B.0000.0000] # KANGXI RADICAL NOSE +FAD8 ; [.FB41.0020.0002][.9F43.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FAD8 +2FD1 ; [.FB41.0020.0004][.9F4A.0000.0000] # KANGXI RADICAL EVEN +2EEB ; [.FB41.0020.0004][.9F4A.0000.0000][.0000.0111.0004] # CJK RADICAL J-SIMPLIFIED EVEN +2EEC ; [.FB41.0020.0004][.9F50.0000.0000] # CJK RADICAL C-SIMPLIFIED EVEN +2FD2 ; [.FB41.0020.0004][.9F52.0000.0000] # KANGXI RADICAL TOOTH +2EED ; [.FB41.0020.0004][.9F52.0000.0000][.0000.0111.0004] # CJK RADICAL J-SIMPLIFIED TOOTH +2EEE ; [.FB41.0020.0004][.9F7F.0000.0000] # CJK RADICAL C-SIMPLIFIED TOOTH +F9C4 ; [.FB41.0020.0002][.9F8D.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F9C4 +2FD3 ; [.FB41.0020.0004][.9F8D.0000.0000] # KANGXI RADICAL DRAGON +2EEF ; [.FB41.0020.0004][.9F8D.0000.0000][.0000.0111.0004] # CJK RADICAL J-SIMPLIFIED DRAGON +FAD9 ; [.FB41.0020.0002][.9F8E.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FAD9 +2EF0 ; [.FB41.0020.0004][.9F99.0000.0000] # CJK RADICAL C-SIMPLIFIED DRAGON +F907 ; [.FB41.0020.0002][.9F9C.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F907 +F908 ; [.FB41.0020.0002][.9F9C.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-F908 +FACE ; [.FB41.0020.0002][.9F9C.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FACE +2FD4 ; [.FB41.0020.0004][.9F9C.0000.0000] # KANGXI RADICAL TURTLE +2EF1 ; [.FB41.0020.0004][.9F9C.0000.0000][.0000.0111.0004] # CJK RADICAL TURTLE +2EF2 ; [.FB41.0020.0004][.9F9C.0000.0000][.0000.0112.0004] # CJK RADICAL J-SIMPLIFIED TURTLE +2EF3 ; [.FB41.0020.0004][.9F9F.0000.0000] # CJK RADICAL C-SIMPLIFIED TURTLE +2FD5 ; [.FB41.0020.0004][.9FA0.0000.0000] # KANGXI RADICAL FLUTE +FA0E ; [.FB41.0020.0002][.FA0E.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA0E +FA0F ; [.FB41.0020.0002][.FA0F.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA0F +FA11 ; [.FB41.0020.0002][.FA11.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA11 +FA13 ; [.FB41.0020.0002][.FA13.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA13 +FA14 ; [.FB41.0020.0002][.FA14.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA14 +FA1F ; [.FB41.0020.0002][.FA1F.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA1F +FA21 ; [.FB41.0020.0002][.FA21.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA21 +FA23 ; [.FB41.0020.0002][.FA23.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA23 +FA24 ; [.FB41.0020.0002][.FA24.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA24 +FA27 ; [.FB41.0020.0002][.FA27.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA27 +FA28 ; [.FB41.0020.0002][.FA28.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA28 +FA29 ; [.FB41.0020.0002][.FA29.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA29 +2F80C ; [.FB80.0020.0002][.B49E.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F80C +2F813 ; [.FB80.0020.0002][.B4B9.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F813 +2F9CA ; [.FB80.0020.0002][.B4BB.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F9CA +2F81F ; [.FB80.0020.0002][.B4DF.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F81F +2F824 ; [.FB80.0020.0002][.B515.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F824 +2F867 ; [.FB80.0020.0002][.B6EE.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F867 +2F868 ; [.FB80.0020.0002][.B6FC.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F868 +2F876 ; [.FB80.0020.0002][.B781.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F876 +2F883 ; [.FB80.0020.0002][.B82F.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F883 +2F888 ; [.FB80.0020.0002][.B862.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F888 +2F88A ; [.FB80.0020.0002][.B87C.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F88A +2F896 ; [.FB80.0020.0002][.B8C7.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F896 +2F89B ; [.FB80.0020.0002][.B8E3.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F89B +2F8A2 ; [.FB80.0020.0002][.B91C.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F8A2 +2F8A1 ; [.FB80.0020.0002][.B93A.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F8A1 +2F8C2 ; [.FB80.0020.0002][.BA2E.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F8C2 +2F8C7 ; [.FB80.0020.0002][.BA6C.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F8C7 +2F8D1 ; [.FB80.0020.0002][.BAE4.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F8D1 +2F8D0 ; [.FB80.0020.0002][.BB08.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F8D0 +2F8CE ; [.FB80.0020.0002][.BB19.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F8CE +2F8DE ; [.FB80.0020.0002][.BB49.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F8DE +FAD2 ; [.FB80.0020.0002][.BB9D.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FAD2 +2F8E7 ; [.FB80.0020.0002][.BB9D.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F8E7 +2F8EE ; [.FB80.0020.0002][.BC18.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F8EE +2F8F2 ; [.FB80.0020.0002][.BC4E.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F8F2 +2F90A ; [.FB80.0020.0002][.BD33.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F90A +2F916 ; [.FB80.0020.0002][.BD96.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F916 +2F92A ; [.FB80.0020.0002][.BEAC.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F92A +2F92C ; [.FB80.0020.0002][.BEB8.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F92C +2F92D ; [.FB80.0020.0002][.BEB8.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F92D +2F933 ; [.FB80.0020.0002][.BF1B.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F933 +2F93E ; [.FB80.0020.0002][.BFFC.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F93E +2F93F ; [.FB80.0020.0002][.C008.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F93F +FAD3 ; [.FB80.0020.0002][.C018.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FAD3 +FAD4 ; [.FB80.0020.0002][.C039.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FAD4 +2F949 ; [.FB80.0020.0002][.C039.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F949 +2F94B ; [.FB80.0020.0002][.C046.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F94B +2F94C ; [.FB80.0020.0002][.C096.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F94C +2F951 ; [.FB80.0020.0002][.C0E3.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F951 +2F958 ; [.FB80.0020.0002][.C12F.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F958 +2F960 ; [.FB80.0020.0002][.C202.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F960 +2F964 ; [.FB80.0020.0002][.C227.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F964 +2F967 ; [.FB80.0020.0002][.C2A0.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F967 +2F96D ; [.FB80.0020.0002][.C301.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F96D +2F971 ; [.FB80.0020.0002][.C334.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F971 +2F974 ; [.FB80.0020.0002][.C359.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F974 +2F981 ; [.FB80.0020.0002][.C3D5.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F981 +2F8D7 ; [.FB80.0020.0002][.C3D9.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F8D7 +2F984 ; [.FB80.0020.0002][.C40B.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F984 +2F98E ; [.FB80.0020.0002][.C46B.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F98E +2F9A7 ; [.FB80.0020.0002][.C52B.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F9A7 +2F9AE ; [.FB80.0020.0002][.C55D.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F9AE +2F9AF ; [.FB80.0020.0002][.C561.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F9AF +2F9B2 ; [.FB80.0020.0002][.C56B.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F9B2 +2F9BF ; [.FB80.0020.0002][.C5D7.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F9BF +2F9C2 ; [.FB80.0020.0002][.C5F9.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F9C2 +2F9C8 ; [.FB80.0020.0002][.C635.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F9C8 +2F9CD ; [.FB80.0020.0002][.C6BE.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F9CD +2F9CE ; [.FB80.0020.0002][.C6C7.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F9CE +2F9EF ; [.FB80.0020.0002][.C995.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F9EF +2F9F2 ; [.FB80.0020.0002][.C9E6.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F9F2 +2F9F8 ; [.FB80.0020.0002][.CA6E.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F9F8 +2F9F9 ; [.FB80.0020.0002][.CA76.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F9F9 +2F9FC ; [.FB80.0020.0002][.CAB2.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F9FC +2FA03 ; [.FB80.0020.0002][.CB33.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2FA03 +2FA08 ; [.FB80.0020.0002][.CBCE.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2FA08 +2FA0D ; [.FB80.0020.0002][.CCCE.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2FA0D +2FA0E ; [.FB80.0020.0002][.CCED.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2FA0E +2FA11 ; [.FB80.0020.0002][.CCF8.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2FA11 +2FA16 ; [.FB80.0020.0002][.CD56.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2FA16 +2F803 ; [.FB84.0020.0002][.8122.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F803 +2F812 ; [.FB84.0020.0002][.851C.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F812 +2F91B ; [.FB84.0020.0002][.8525.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F91B +2F816 ; [.FB84.0020.0002][.854B.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F816 +2F80D ; [.FB84.0020.0002][.863A.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F80D +2F9D9 ; [.FB84.0020.0002][.8804.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F9D9 +2F9DD ; [.FB84.0020.0002][.88DE.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F9DD +2F834 ; [.FB84.0020.0002][.8A2C.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F834 +2F838 ; [.FB84.0020.0002][.8B63.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F838 +2F859 ; [.FB84.0020.0002][.94E4.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F859 +2F860 ; [.FB84.0020.0002][.96A8.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F860 +2F861 ; [.FB84.0020.0002][.96EA.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F861 +2F86C ; [.FB84.0020.0002][.99C8.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F86C +2F871 ; [.FB84.0020.0002][.9B18.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F871 +2F8F8 ; [.FB84.0020.0002][.9D0B.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F8F8 +2F87B ; [.FB84.0020.0002][.9DE4.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F87B +2F87D ; [.FB84.0020.0002][.9DE6.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F87D +2F889 ; [.FB84.0020.0002][.A183.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F889 +2F939 ; [.FB84.0020.0002][.A19F.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F939 +2F891 ; [.FB84.0020.0002][.A331.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F891 +2F892 ; [.FB84.0020.0002][.A331.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F892 +2F8A4 ; [.FB84.0020.0002][.A6D4.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F8A4 +FAD0 ; [.FB84.0020.0002][.A844.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FAD0 +FACF ; [.FB84.0020.0002][.A84A.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FACF +2F8B8 ; [.FB84.0020.0002][.AB0C.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F8B8 +2F8BE ; [.FB84.0020.0002][.ABF1.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F8BE +2F8CA ; [.FB84.0020.0002][.B00A.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F8CA +2F897 ; [.FB84.0020.0002][.B2B8.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F897 +2F980 ; [.FB84.0020.0002][.B35F.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F980 +2F989 ; [.FB84.0020.0002][.B393.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F989 +2F98A ; [.FB84.0020.0002][.B39C.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F98A +2F8DD ; [.FB84.0020.0002][.B3C3.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F8DD +FAD1 ; [.FB84.0020.0002][.B3D5.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FAD1 +2F8E3 ; [.FB84.0020.0002][.B46D.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F8E3 +2F8EC ; [.FB84.0020.0002][.B6A3.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F8EC +2F8F0 ; [.FB84.0020.0002][.B8A7.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F8F0 +2F8F7 ; [.FB84.0020.0002][.BA8D.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F8F7 +2F8F9 ; [.FB84.0020.0002][.BAFA.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F8F9 +2F8FB ; [.FB84.0020.0002][.BCBC.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F8FB +2F906 ; [.FB84.0020.0002][.BD1E.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F906 +2F90D ; [.FB84.0020.0002][.BED1.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F90D +2F910 ; [.FB84.0020.0002][.BF5E.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F910 +2F911 ; [.FB84.0020.0002][.BF8E.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F911 +2F91D ; [.FB84.0020.0002][.C263.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F91D +FA6C ; [.FB84.0020.0002][.C2EE.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FA6C +2F91F ; [.FB84.0020.0002][.C3AB.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F91F +2F923 ; [.FB84.0020.0002][.C608.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F923 +2F926 ; [.FB84.0020.0002][.C735.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F926 +2F927 ; [.FB84.0020.0002][.C814.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F927 +2F935 ; [.FB84.0020.0002][.CC36.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F935 +2F937 ; [.FB84.0020.0002][.CC92.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F937 +2F93B ; [.FB84.0020.0002][.CFA1.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F93B +2F93C ; [.FB84.0020.0002][.CFB8.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F93C +2F93D ; [.FB84.0020.0002][.D044.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F93D +2F942 ; [.FB84.0020.0002][.D0F2.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F942 +2F941 ; [.FB84.0020.0002][.D0F3.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F941 +2F943 ; [.FB84.0020.0002][.D119.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F943 +2F944 ; [.FB84.0020.0002][.D133.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F944 +FAD5 ; [.FB84.0020.0002][.D249.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FAD5 +2F94D ; [.FB84.0020.0002][.D41D.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F94D +2F952 ; [.FB84.0020.0002][.D626.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F952 +2F954 ; [.FB84.0020.0002][.D69A.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F954 +2F955 ; [.FB84.0020.0002][.D6C5.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F955 +2F95C ; [.FB84.0020.0002][.D97C.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F95C +2F95D ; [.FB84.0020.0002][.DAA7.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F95D +2F95E ; [.FB84.0020.0002][.DAA7.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F95E +2F961 ; [.FB84.0020.0002][.DBAB.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F961 +2F965 ; [.FB84.0020.0002][.DC80.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F965 +FAD6 ; [.FB84.0020.0002][.DCD0.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FAD6 +2F96B ; [.FB84.0020.0002][.DF86.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F96B +2F898 ; [.FB84.0020.0002][.E1DA.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F898 +2F972 ; [.FB84.0020.0002][.E228.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F972 +2F973 ; [.FB84.0020.0002][.E247.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F973 +2F975 ; [.FB84.0020.0002][.E2D9.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F975 +2F977 ; [.FB84.0020.0002][.E33E.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F977 +2F97B ; [.FB84.0020.0002][.E4DA.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F97B +2F97C ; [.FB84.0020.0002][.E523.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F97C +2F97E ; [.FB84.0020.0002][.E5A8.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F97E +2F987 ; [.FB84.0020.0002][.E7A7.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F987 +2F988 ; [.FB84.0020.0002][.E7B5.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F988 +2F997 ; [.FB84.0020.0002][.EB3C.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F997 +2F9A4 ; [.FB84.0020.0002][.EC36.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F9A4 +2F9A6 ; [.FB84.0020.0002][.ECD5.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F9A6 +2F9A5 ; [.FB84.0020.0002][.ED6B.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F9A5 +2F9AD ; [.FB84.0020.0002][.EF2C.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F9AD +2F9B0 ; [.FB84.0020.0002][.EFB1.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F9B0 +2F9B1 ; [.FB84.0020.0002][.F0D2.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F9B1 +2F9AB ; [.FB84.0020.0002][.F3CA.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F9AB +2F9C5 ; [.FB84.0020.0002][.F667.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F9C5 +2F9CB ; [.FB84.0020.0002][.F8AE.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F9CB +2F9CC ; [.FB84.0020.0002][.F966.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F9CC +2F9D3 ; [.FB84.0020.0002][.FCA8.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F9D3 +FAD7 ; [.FB84.0020.0002][.FED3.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-FAD7 +2F9D8 ; [.FB84.0020.0002][.FF2F.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F9D8 +2F9E0 ; [.FB85.0020.0002][.85D2.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F9E0 +2F9E1 ; [.FB85.0020.0002][.85ED.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F9E1 +2F9E5 ; [.FB85.0020.0002][.872E.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F9E5 +2F9ED ; [.FB85.0020.0002][.8BFA.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F9ED +2F9F1 ; [.FB85.0020.0002][.8D77.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F9F1 +2F9F6 ; [.FB85.0020.0002][.9145.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F9F6 +2F81C ; [.FB85.0020.0002][.91DF.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F81C +2F9F7 ; [.FB85.0020.0002][.921A.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F9F7 +2F9FB ; [.FB85.0020.0002][.940A.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F9FB +2F9FD ; [.FB85.0020.0002][.9496.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F9FD +2FA01 ; [.FB85.0020.0002][.95B6.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2FA01 +2FA09 ; [.FB85.0020.0002][.9B30.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2FA09 +2FA10 ; [.FB85.0020.0002][.A0CE.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2FA10 +2FA12 ; [.FB85.0020.0002][.A105.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2FA12 +2FA13 ; [.FB85.0020.0002][.A20E.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2FA13 +2FA14 ; [.FB85.0020.0002][.A291.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2FA14 +2F88F ; [.FB85.0020.0002][.A392.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2F88F +2FA1D ; [.FB85.0020.0002][.A600.0000.0000] # CJK COMPATIBILITY IDEOGRAPH-2FA1D +FFFD ; [.FFFD.0020.0002] # REPLACEMENT CHARACTER + +# EOF diff --git a/tools-for-build/avx2.c b/tools-for-build/avx2.c new file mode 100644 index 0000000000..b16956fb23 --- /dev/null +++ b/tools-for-build/avx2.c @@ -0,0 +1,4 @@ +int main () { + __builtin_cpu_init(); + return __builtin_cpu_supports("avx2") != 0; +} diff --git a/tools-for-build/canonicalize-whitespace.lisp b/tools-for-build/canonicalize-whitespace.lisp index b65b1745a3..d13fa64c03 100644 --- a/tools-for-build/canonicalize-whitespace.lisp +++ b/tools-for-build/canonicalize-whitespace.lisp @@ -66,9 +66,11 @@ (cond (change-p (delete-file file) - (rename-file temporary file)) + (rename-file temporary file) + t) ((probe-file temporary) - (delete-file temporary)))))) + (delete-file temporary) + nil))))) ;;; Timestamp functions @@ -80,11 +82,14 @@ 0)) (defun write-stamp-file () - (with-open-file (stream *stamp-file* - :direction :output - :if-exists :supersede) - (declare (ignorable stream)) - (values))) + ;; We want the stamp file to have the current time for its write + ;; date. Conforming variation in OPEN's IF-EXISTS semantics across + ;; existing XC hosts means it's simplest to unconditionally ensure a + ;; new file. + (when (probe-file *stamp-file*) + (delete-file *stamp-file*)) + (close (open *stamp-file* :direction :output :if-exists :error + :if-does-not-exist :create))) ;;; Repository-level functions @@ -93,23 +98,51 @@ (defvar *exceptions* '("compile-file-pos-utf16be")) (defun canonicalize-whitespace/directory - (&optional (directory *default-pathname-defaults*)) - (let ((stamp-date (read-stamp-file))) + (&optional (directory *default-pathname-defaults*) (report t)) + (let ((stamp-date (read-stamp-file)) (n-files 0) (n-newer 0) (n-changed 0)) (labels ((older-than-stamp (file) (< (file-write-date file) stamp-date)) (exception-p (file) (member (pathname-name file) *exceptions* :test #'string=)) (skip-p (file) - (or (older-than-stamp file) (exception-p file)))) + (incf n-files) + (or (older-than-stamp file) (exception-p file))) + (directory* (pattern) + ;; We might be in a build tree made out of symlinks, so + ;; we should list our files without resolving + ;; symlinks. (This is implementation-dependent, but + ;; many implementations on Unix can do it. The list of + ;; implementations covered below might be larger than + ;; the set that can build SBCL.) + (apply #-clisp #'directory + #+clisp #'(lambda (pathname &rest keys) + (mapcar #'first + (apply #'directory pathname keys))) + pattern + #+abcl '(:resolve-symlinks nil) + #+allegro '(:follow-symbolic-links nil) + #+ccl '(:follow-links nil) + #+clisp '(:full t) + #+cmu '(:truenamep nil) + #+ecl '(:resolve-symlinks nil) + #+lispworks '(:link-transparency nil) + #+sbcl '(:resolve-symlinks nil) + #-(or abcl allegro ccl clisp cmu ecl lispworks sbcl) + #.(error "Don't know how to list files without ~ + resolving symlinks.")))) (dolist (type *source-types*) (let* ((pattern (merge-pathnames (make-pathname :type type :name :wild :directory '(:relative :wild-inferiors)) directory)) - (files (remove-if #'skip-p (directory pattern)))) - (mapc #'canonicalize-whitespace/file files)))) + (files (remove-if #'skip-p (directory* pattern)))) + (incf n-newer (length files)) + (incf n-changed (count-if #'canonicalize-whitespace/file files))))) + (when report + (format t "~&// Rewrote ~D of ~D new files out of ~D total." + n-changed n-newer n-files)) (write-stamp-file))) ) ; end PROGN diff --git a/tools-for-build/corefile.lisp b/tools-for-build/corefile.lisp index 50b4cf2e51..a55e163647 100644 --- a/tools-for-build/corefile.lisp +++ b/tools-for-build/corefile.lisp @@ -1,7 +1,4 @@ - -;;; This package name does not persist after the build is complete, -;;; so it does not have an "!" in it. -;;; It it needed by genesis and SB-EDITCORE +;;; This is needed by genesis and SB-EDITCORE (defpackage "SB-COREFILE" (:use "CL") (:export #:core-magic @@ -9,15 +6,18 @@ #:directory-core-entry-type-code #:initial-fun-core-entry-type-code #:page-table-core-entry-type-code - #:linkage-table-core-entry-type-code + #:alien-linkage-table-core-entry-type-code #:end-core-entry-type-code #:max-core-space-id ;; #:read-only-core-space-id #:static-core-space-id + #:static-code-core-space-id #:dynamic-core-space-id #:immobile-fixedobj-core-space-id - #:immobile-varyobj-core-space-id + #:immobile-text-core-space-id + #:alien-linkage-table-core-space-id + #:thread-struct-core-space-id #:deflated-core-space-id-flag)) (in-package "SB-COREFILE") @@ -44,12 +44,17 @@ (defconstant directory-core-entry-type-code 3861) (defconstant initial-fun-core-entry-type-code 3863) (defconstant page-table-core-entry-type-code 3880) -(defconstant linkage-table-core-entry-type-code 3881) +(defconstant alien-linkage-table-core-entry-type-code 3881) (defconstant end-core-entry-type-code 3840) (defconstant dynamic-core-space-id 1) (defconstant static-core-space-id 2) (defconstant read-only-core-space-id 3) (defconstant immobile-fixedobj-core-space-id 4) -(defconstant immobile-varyobj-core-space-id 5) +(defconstant immobile-text-core-space-id 5) +(defconstant static-code-core-space-id 4) (defconstant deflated-core-space-id-flag 8) +;;; These space-IDs are not present in a core file, but +;;; we need unique values for supplying to os_alloc_gc_space +(defconstant alien-linkage-table-core-space-id 101) +(defconstant thread-struct-core-space-id 102) diff --git a/tools-for-build/create-linkage-table-prelink-info-override.lisp b/tools-for-build/create-linkage-table-prelink-info-override.lisp new file mode 100644 index 0000000000..2e563af27f --- /dev/null +++ b/tools-for-build/create-linkage-table-prelink-info-override.lisp @@ -0,0 +1,43 @@ +(in-package :cl-user) + +(defun foreign-symbols-to-c (output-pathname sorted-symbols) + (with-open-file (output output-pathname + :direction :output + :if-exists :supersede) + ;; Needed for uintptr_t. We use the raw uintptr_t as we don't want to have + ;; to include any SBCL headers just to get at lispobj. + (format output "#include <stdint.h>~%~%") + + ;; Write out the extern definitions. Everything is a void function (even + ;; variables) because compilers don't like void variables. Remove + ;; lisp_linkage_values as we need to write to it, so we should use the + ;; actual type. + (format output "extern void ~{~A()~^, ~};~%~%" + (remove "lisp_linkage_values" + (mapcar #'first + (remove t sorted-symbols :key #'third)) + :test #'equal)) + + (format output "uintptr_t lisp_linkage_values[] = {~%") + + (format output " ~D,~%" (length sorted-symbols)) + (dolist (symbol sorted-symbols) + (destructuring-bind (name datap undefinedp) symbol + (when datap + ;; This is data, put -1 in to indicate that. + (format output " (uintptr_t)-1,~%")) + (if undefinedp + (format output " (uintptr_t)0,~%") + (format output " (uintptr_t)&~A,~%" name)))) + (format output "};~%"))) + +(defun main (&optional (args (cdr sb-ext:*posix-argv*))) + (foreign-symbols-to-c (second args) + (with-open-file (s (first args)) + (read s)))) + +(eval-when (:execute) + (let ((args (cdr sb-ext:*posix-argv*))) + (when args + (let ((*print-pretty* nil)) + (main args))))) diff --git a/tools-for-build/dump-linkage-info.lisp b/tools-for-build/dump-linkage-info.lisp new file mode 100644 index 0000000000..c71fef609f --- /dev/null +++ b/tools-for-build/dump-linkage-info.lisp @@ -0,0 +1,26 @@ +(defpackage #:sb-dump-linkage-info + (:use #:cl) + (:export #:*libdl-symbols* + #:dump-to-file)) + +(in-package #:sb-dump-linkage-info) + +(defparameter *libdl-symbols* '("dladdr" "dlclose" "dlerror" "dlopen" "dlsym")) + +(defun dump-to-file (pn &key (make-undefined nil)) + (let ((ht (car sb-sys:*linkage-info*)) + (undefined-entries (cdr sb-sys:*linkage-info*)) + out) + (loop + :for key :being :the :hash-keys :in ht :using (hash-value idx) + :for datap := (listp key) + :for name := (if datap (first key) key) + :for undefinedp := (not (null (or (member key undefined-entries :test #'equal) + (member name make-undefined :test #'equal)))) + :do (push (cons idx (list name datap undefinedp)) out)) + (ensure-directories-exist pn) + (with-open-file (s pn :direction :output :if-exists :supersede) + (let ((*print-pretty* nil)) + (prin1 (mapcar #'cdr (sort out #'< :key #'car)) s)) + (terpri s))) + pn) diff --git a/tools-for-build/editcore.lisp b/tools-for-build/editcore.lisp index b38c240b0a..d46e9828a8 100644 --- a/tools-for-build/editcore.lisp +++ b/tools-for-build/editcore.lisp @@ -32,7 +32,7 @@ #:map-segment-instructions #:inst-name #:dstate-next-addr #:dstate-cur-offs) (:import-from "SB-X86-64-ASM" #:near-jump-displacement - #:near-cond-jump-displacement #:mov #:call + #:near-cond-jump-displacement #:mov #:call #:jmp #:get-gpr #:reg-name) (:import-from "SB-IMPL" #:package-hashtable #:package-%name #:package-hashtable-cells @@ -78,7 +78,7 @@ (find id (cdr spaces) :key #'space-id)) (defun compute-nil-object (spaces) (let ((space (get-space static-core-space-id spaces))) - (%make-lisp-obj (logior (space-addr space) #x17)))) + (%make-lisp-obj (logior (space-addr space) #x117)))) ; SUPER KLUDGE ;;; Given OBJ which is tagged pointer into the target core, translate it into ;;; the range at which the core is now mapped during execution of this tool, @@ -103,6 +103,8 @@ (:constructor %make-core)) (spaces) (nil-object) + ;; mapping from small integer ID to package + (pkg-id->package) ;; mapping from string naming a package to list of symbol names (strings) ;; that are external in the package. (packages (make-hash-table :test 'equal)) @@ -130,7 +132,7 @@ (defglobal *editcore-ppd* ;; copy no entries for macros/special-operators (flet, etc) - (let ((ppd (sb-pretty::make-pprint-dispatch-table nil nil nil))) + (let ((ppd (sb-pretty::make-pprint-dispatch-table #() nil nil))) (set-pprint-dispatch 'string ;; Write strings without string quotes (lambda (stream string) (write-string string stream)) @@ -244,11 +246,12 @@ (let ((p (position #\/ x :from-end t))) (if p (subseq x (1+ p)) x))) ((symbolp x) - (let ((name (translate (symbol-name x) spaces))) - (when (eq (symbol-package x) core-nil) ; uninterned + (let ((package-id (sb-impl::symbol-package-id x)) + (name (translate (symbol-name x) spaces))) + (when (eq package-id 0) ; uninterned (return-from recurse (string-downcase name))) (let* ((package (truly-the package - (translate (symbol-package x) spaces))) + (aref (core-pkg-id->package core) package-id))) (package-name (translate (package-%name package) spaces))) ;; The name-cleaning code wants to compare against symbols ;; in CL, PCL, and KEYWORD, so use real symbols for those. @@ -330,6 +333,8 @@ ;; but no more so than everything else in this file) (let ((locs (sb-c::compiled-debug-fun-encoded-locs (truly-the sb-c::compiled-debug-fun compiled-debug-fun)))) + (when (consp locs) + (setq locs (cdr (translate locs spaces)))) (sb-c::compiled-debug-fun-offset (sb-c::make-compiled-debug-fun :name nil @@ -393,8 +398,10 @@ (pairs (cons (descriptorize (svref cells i)) (descriptorize (svref cells (1+ i)))))))))) +(defmacro package-id (name) (sb-impl::package-id (find-package name))) + ;;; Return either the physical or logical address of the specified symbol. -(defun find-target-symbol (package-name symbol-name spaces +(defun find-target-symbol (package-id symbol-name spaces &optional (address-mode :physical)) (dolist (id `(,immobile-fixedobj-core-space-id ,static-core-space-id)) (let* ((space (get-space id spaces)) @@ -403,16 +410,11 @@ (physaddr start)) (loop (when (>= physaddr end) (return)) - (multiple-value-bind (obj tag size) - (reconstitute-object (ash physaddr (- n-fixnum-tag-bits))) - (when (and (= tag symbol-widetag) + (let* ((obj (reconstitute-object (ash physaddr (- n-fixnum-tag-bits)))) + (size (primitive-object-size obj))) + (when (and (symbolp obj) (string= symbol-name (translate (symbol-name obj) spaces)) - (%instancep (symbol-package obj)) - (string= package-name - (translate - (package-%name - (truly-the package (translate (symbol-package obj) spaces))) - spaces))) + (= (sb-impl::symbol-package-id obj) package-id)) (return-from find-target-symbol (%make-lisp-obj (logior (ecase address-mode @@ -420,14 +422,14 @@ (:logical (+ (space-addr space) (- physaddr start)))) other-pointer-lowtag)))) (incf physaddr size))))) - (bug "Can't find symbol ~A::~A" package-name symbol-name)) + (bug "Can't find symbol ~A::~A" package-id symbol-name)) (defparameter label-prefix (if (member :darwin *features*) "_" "")) (defun labelize (x) (concatenate 'string label-prefix x)) -(defun compute-linkage-symbols (spaces entry-size) +(defun compute-linkage-symbols (spaces) (let* ((linkage-info (symbol-global-value - (find-target-symbol "SB-SYS" "*LINKAGE-INFO*" + (find-target-symbol (package-id "SB-SYS") "*LINKAGE-INFO*" spaces :physical))) (hashtable (car (translate linkage-info spaces))) (pairs (target-hash-table-alist hashtable spaces)) @@ -447,20 +449,18 @@ (defconstant inst-jmp (find-inst #b11101001 (get-inst-space))) (defconstant inst-jmpz (find-inst #x840f (get-inst-space))) (defconstant inst-pop (find-inst #x5d (get-inst-space))) +(defconstant inst-mov (find-inst #x8B (get-inst-space))) +(defconstant inst-lea (find-inst #x8D (get-inst-space))) (defun make-core (spaces code-bounds fixedobj-bounds &optional enable-pie) (let* ((linkage-bounds - (make-bounds - (symbol-global-value - (find-target-symbol "SB-VM" "LINKAGE-TABLE-SPACE-START" spaces :physical)) - (symbol-global-value - (find-target-symbol "SB-VM" "LINKAGE-TABLE-SPACE-END" spaces :physical)))) + (let ((text (space-addr (get-space immobile-text-core-space-id spaces)))) + (make-bounds (- text sb-vm:alien-linkage-table-space-size) text))) (linkage-entry-size (symbol-global-value - (find-target-symbol "SB-VM" "LINKAGE-TABLE-ENTRY-SIZE" + (find-target-symbol (package-id "SB-VM") "ALIEN-LINKAGE-TABLE-ENTRY-SIZE" spaces :physical))) - (linkage-symbols (compute-linkage-symbols spaces linkage-entry-size)) - (inst-space (get-inst-space)) + (linkage-symbols (compute-linkage-symbols spaces)) (nil-object (compute-nil-object spaces)) (ambiguous-symbols (make-hash-table :test 'equal)) (core @@ -473,11 +473,13 @@ :linkage-bounds linkage-bounds :linkage-entry-size linkage-entry-size :linkage-symbols linkage-symbols - :linkage-symbol-usedp (make-array (length linkage-symbols) :element-type 'bit) + :linkage-symbol-usedp (make-array (length linkage-symbols) :element-type 'bit + :initial-element 0) :enable-pie enable-pie))) (let ((package-table (symbol-global-value - (find-target-symbol "SB-KERNEL" "*PACKAGE-NAMES*" spaces :physical))) + (find-target-symbol (package-id "SB-KERNEL") "*PACKAGE-NAMES*" spaces :physical))) + (package-alist) (symbols (make-hash-table :test 'equal))) (dovector (x (translate (%instance-ref (translate package-table spaces) 0) spaces)) (when (%instancep x) ; package @@ -487,8 +489,14 @@ (pushnew (get-lisp-obj-address sym) (gethash str symbols))) table core))) (let ((package (truly-the package (translate x spaces)))) + (push (cons (sb-impl::package-id package) package) package-alist) (scan (package-external-symbols package)) (scan (package-internal-symbols package)))))) + (let ((package-by-id (make-array (1+ (reduce #'max package-alist :key #'car)) + :initial-element nil))) + (loop for (id . package) in package-alist + do (setf (aref package-by-id id) package)) + (setf (core-pkg-id->package core) package-by-id)) (dohash ((string symbols) symbols) (when (cdr symbols) (setf (gethash string ambiguous-symbols) t)))) @@ -577,7 +585,7 @@ (- operand (bounds-low (core-code-bounds core)))))) (push (list* (dstate-cur-offs dstate) 5 "mov" text) list))) ((and (eq (inst-name inst) 'mov) ; match "mov qword ptr [R+disp8], imm32" - (eql (sap-ref-8 sap (1- offs)) #x48) + (member (sap-ref-8 sap (1- offs)) '(#x48 #x49)) ; REX.w and maybe REX.b (eql (sap-ref-8 sap offs) #xC7) ;; modRegRm = #b01 #b000 #b___ (eql (logand (sap-ref-8 sap (1+ offs)) #o370) #o100)) @@ -587,17 +595,22 @@ (signed-sap-ref-8 sap (+ offs 2)) (reg-name (get-gpr :qword reg))))) (push (list* (1- (dstate-cur-offs dstate)) 8 "mov" text) list))) - ((and (eq (inst-name inst) 'call) ; match "call qword ptr [addr]" - (eql (ldb (byte 24 0) (sap-ref-32 sap offs)) - #x2514FF)) ; ModRM+SIB encodes disp32, no base, no index - ;; This form of call instruction is employed for asm routines when - ;; compile-to-memory-space is :AUTO. If the code were to be loaded - ;; into dynamic space, the offset to the called routine isn't - ;; a (signed-byte 32), so we need the indirection. - (push (list* (dstate-cur-offs dstate) 7 "call*" operand) list)) + ((let ((bytes (ldb (byte 24 0) (sap-ref-32 sap offs)))) + (or (and (eq (inst-name inst) 'call) ; match "{call,jmp} qword ptr [addr]" + (eql bytes #x2514FF)) ; ModRM+SIB encodes disp32, no base, no index + (and (eq (inst-name inst) 'jmp) + (eql bytes #x2524FF)))) + (let ((new-opcode (ecase (sap-ref-8 sap (1+ offs)) + (#x14 "call *") + (#x24 "jmp *")))) + ;; This instruction form is employed for asm routines when + ;; compile-to-memory-space is :AUTO. If the code were to be loaded + ;; into dynamic space, the offset to the called routine isn't + ;; a (signed-byte 32), so we need the indirection. + (push (list* (dstate-cur-offs dstate) 7 new-opcode operand) list))) (t (bug "Can't reverse-engineer fixup: ~s ~x" - (inst-name inst) (sap-ref-32 sap offs)))))) + (inst-name inst) (sap-ref-64 sap offs)))))) (pop (core-fixup-addrs core)) (setq next-fixup-addr (or (car (core-fixup-addrs core)) most-positive-word))) ((or (eq inst inst-jmp) (eq inst inst-call)) @@ -616,6 +629,23 @@ (when (in-bounds-p target-addr (core-linkage-bounds core)) (push (list* (dstate-cur-offs dstate) 6 "je" target-addr) list)))) + ((and (or (and (eq inst inst-mov) + (eql (sap-ref-8 sap (dstate-cur-offs dstate)) #x8B)) + (eq inst inst-lea)) + (let ((modrm (sap-ref-8 sap (1+ (dstate-cur-offs dstate))))) + (= (logand modrm #b11000111) #b00000101)) ; RIP-relative mode + (in-bounds-p (+ (signed-sap-ref-32 sap (+ (dstate-cur-offs dstate) 2)) + (dstate-next-addr dstate)) + (core-linkage-bounds core))) + (let* ((abs-addr (+ (signed-sap-ref-32 sap (+ (dstate-cur-offs dstate) 2)) + (dstate-next-addr dstate))) + (reg (logior (ldb (byte 3 3) (sap-ref-8 sap (1+ (dstate-cur-offs dstate)))) + (if (logtest (sb-disassem::dstate-inst-properties dstate) + #b0100) ; REX.r + 8 0))) + (op (if (eq inst inst-lea) "lea" "mov-gotpcrel")) + (args (list abs-addr (reg-name (get-gpr :qword reg))))) + (push (list* (1- (dstate-cur-offs dstate)) 7 op args) list))) ((and (eq inst inst-pop) (eq (logand dchunk #xFF) #x5D)) (push (list* (dstate-cur-offs dstate) 1 "pop" "%rbp") list)))) seg @@ -725,6 +755,20 @@ (format stream " ~A ~:[0x~X~;~a~:[~;@PLT~]~]~%" opcode (stringp operand) operand (core-enable-pie core))) + ((string= opcode "mov-gotpcrel") + (let* ((entry-index + (/ (- (car operand) (bounds-low (core-linkage-bounds core))) + (core-linkage-entry-size core))) + (c-symbol (car (aref (core-linkage-symbols core) entry-index)))) + (setf (bit (core-linkage-symbol-usedp core) entry-index) 1) + (format stream " mov ~A@GOTPCREL(%rip), %~(~A~)~%" c-symbol (cadr operand)))) + ((string= opcode "lea") ; lea becomes "mov" with gotpcrel as src, which becomes lea + (let* ((entry-index + (/ (- (car operand) (bounds-low (core-linkage-bounds core))) + (core-linkage-entry-size core))) + (c-symbol (aref (core-linkage-symbols core) entry-index))) + (setf (bit (core-linkage-symbol-usedp core) entry-index) 1) + (format stream " mov ~A@GOTPCREL(%rip), %~(~A~)~%" c-symbol (cadr operand)))) ((string= opcode "pop") (format stream " ~A ~A~%" opcode operand) (cond ((string= operand "8(%rbp)") @@ -737,11 +781,12 @@ ;; the so-called "operand" is the entire instruction (write-string operand stream) (terpri stream)) - ((string= opcode "call*") + ((or (string= opcode "call *") (string= opcode "jmp *")) ;; Indirect call - since the code is in immobile space, ;; we could render this as a 2-byte NOP followed by a direct ;; call. For simplicity I'm leaving it exactly as it was. - (format stream " call *(CS+0x~x)~%" + (format stream " ~A(CS+0x~x)~%" + opcode ; contains a "*" as needed for the syntax (- operand (bounds-low (core-code-bounds core))))) (t)) (bug "Random annotated opcode ~S" opcode)) @@ -832,7 +877,7 @@ (total-nwords (cdr (pop ranges)))) (cond ((> jump-table-size 1) (format output "# jump table~%") - (format output ".quad ~d" jump-table-size) + (format output ".quad ~d" (sap-ref-word text-sap 0)) (dotimes (i (1- jump-table-size)) (format output ",\"~a\"+0x~x" base-symbol @@ -882,7 +927,7 @@ collect (sap-ref-8 text-sap i))) (when additional-relative-fixups (binding* ((existing-fixups (sb-vm::%code-fixups code)) - ((absolute relative) + ((absolute relative immediate) (sb-c::unpack-code-fixup-locs (if (fixnump existing-fixups) existing-fixups @@ -897,9 +942,8 @@ sb-vm:word-shift)))) additional-relative-fixups) #'<))) - (sb-c::pack-code-fixup-locs - absolute - (merge 'list relative new-sorted #'<)))))) + (sb-c:pack-code-fixup-locs + absolute (merge 'list relative new-sorted #'<) immediate))))) (defconstant +gf-name-slot+ 5) @@ -934,11 +978,11 @@ (member :darwin *features*) label-prefix label-prefix label-prefix label-prefix)) -;;; Convert immobile varyobj space to an assembly file in OUTPUT. +;;; Convert immobile text space to an assembly file in OUTPUT. (defun write-assembler-text (spaces output &optional enable-pie (emit-cfi t) - &aux (code-bounds (space-bounds immobile-varyobj-core-space-id spaces)) + &aux (code-bounds (space-bounds immobile-text-core-space-id spaces)) (fixedobj-bounds (space-bounds immobile-fixedobj-core-space-id spaces)) (core (make-core spaces code-bounds fixedobj-bounds enable-pie)) (code-addr (bounds-low code-bounds)) @@ -946,9 +990,6 @@ (pp-state (cons (make-hash-table :test 'equal) nil)) (prev-namestring "") (n-linker-relocs 0) - (seen-fdefns nil) - (seen-trampolines nil) - (seen-gfs nil) (temp-output (make-string-output-stream :element-type 'base-char)) end-loc) (labels ((dumpwords (sap count stream &optional (exceptions #()) logical-addr) @@ -1006,15 +1047,20 @@ (end (car (translate (cdr val) spaces)))) (list* (translate (symbol-name name) spaces) start end)) (target-hash-table-alist - (car (translate (%code-debug-info code-component) spaces)) + ;; Can't use %CODE-DEBUG-INFO on a foreign core because + ;; it would dereference the cons not at its current physically mapped + ;; address, but at its logical address. %%CODE-DEBUG-INFO is ok though. + (car (translate (sb-vm::%%code-debug-info code-component) spaces)) spaces)) #'< :key #'cadr))) - ;; Possibly a padding word + ;; Possibly unboxed words and/or padding (let ((here (ash jump-table-count sb-vm:word-shift)) (first-entry-point (cadar name->addr))) (when (> first-entry-point here) - (assert (= first-entry-point (+ here 8))) - (format output " .quad 0~%"))) + (format output " .quad ~{0x~x~^,~}~%" + (loop for offs = here then (+ offs 8) + while (< offs first-entry-point) + collect (sap-ref-word (code-instructions code-component) offs))))) ;; Loop over the embedded routines (let ((list name->addr) (obj-size (code-object-size code-component))) @@ -1049,13 +1095,6 @@ (objsize (code-object-size code))) (incf total-code-size objsize) (cond - ((< (code-header-words code) 3) ; filler object - (let ((sap (int-sap (- (get-lisp-obj-address code) other-pointer-lowtag)))) - (format output " .quad 0x~x, 0x~x~% .fill 0x~x~%# ~x:~%" - (sap-ref-word sap 0) - (sap-ref-word sap n-word-bytes) - (- objsize (* 2 n-word-bytes)) - (+ code-addr objsize)))) ((%instancep (%code-debug-info code)) ; assume it's a COMPILED-DEBUG-INFO (aver (plusp (code-n-entries code))) (let* ((source @@ -1103,68 +1142,17 @@ (dumpwords (int-sap code-physaddr) (code-header-words code) output header-exceptions code-addr) (write-string (get-output-stream-string temp-output) output)))) - ((functionp (%code-debug-info code)) - (unless seen-trampolines - (setq seen-trampolines t) - (format output "lisp_trampolines:~%")) - (let* ((sap (int-sap (translate-ptr code-addr spaces))) - (tramp-fun (sap-ref-word sap (ash 2 word-shift)))) - (aver (not (in-bounds-p tramp-fun code-bounds))) - (format output " .quad ~{0x~x~^,~}~%" - (loop for i from 0 by n-word-bytes repeat 6 - collect (sap-ref-word sap i))))) (t (error "Strange code component: ~S" code))) (incf code-addr objsize))) - (#.fdefn-widetag - (unless seen-fdefns - (format output "~%# FDEFNs~%") - (setq seen-fdefns t)) - (let* ((ptr (translate-ptr code-addr spaces)) - (fdefn (%make-lisp-obj (logior ptr other-pointer-lowtag))) - (name (fun-name-from-core (fdefn-name fdefn) core)) - (c-name (c-name name core pp-state "F"))) - (format output "~a: # ~x~% .size ~0@*~a, 32~%" - (c-symbol-quote c-name) - (logior code-addr other-pointer-lowtag)) - (flet ((relativize (slot &aux (x (sap-ref-word (int-sap ptr) (ash slot word-shift)))) - (if (in-bounds-p x code-bounds) - (format nil "CS+0x~x" (- x (bounds-low code-bounds))) - (format nil "0x~x" x)))) - (format output " .quad 0x~x, 0x~x, ~a, ~a~%" - (sap-ref-word (int-sap ptr) 0) - (sap-ref-word (int-sap ptr) 8) - (relativize fdefn-fun-slot) - (relativize fdefn-raw-addr-slot))) - (incf code-addr (* 4 n-word-bytes)))) - (#.funcallable-instance-widetag - (unless seen-gfs - (setq seen-gfs t) - (when seen-trampolines - (format output " .size lisp_trampolines, .-lisp_trampolines~%"))) - (let* ((sap (int-sap (translate-ptr code-addr spaces))) - (fin-fun (sap-ref-word sap (ash 2 word-shift))) - (code-space-p (in-bounds-p fin-fun code-bounds)) - (slots (translate (sap-ref-lispobj sap (ash 3 word-shift)) spaces)) - (name (and (> (length (the simple-vector slots)) +gf-name-slot+) - (svref slots +gf-name-slot+))) - (c-name - (c-name - (if (or (not name) - (eql (get-lisp-obj-address name) unbound-marker-widetag)) - "unnamed" - (fun-name-from-core name core)) - core pp-state "G"))) - (format output "~a:~% .size ~0@*~a, 48~%" (c-symbol-quote c-name)) - (format output " .quad 0x~x, .+24, ~:[~;CS+~]0x~x~{, 0x~x~}~%" - (sap-ref-word sap 0) - code-space-p - (if code-space-p (- fin-fun (bounds-low code-bounds)) fin-fun) - (loop for i from (ash 3 word-shift) by n-word-bytes repeat 3 - collect (sap-ref-word sap i)))) - (incf code-addr (* 6 n-word-bytes)))))) - - ;; coreparse uses the 'lisp_jit_code' symbol to set varyobj_free_pointer + (#.filler-widetag + (let* ((word (sap-ref-word (int-sap (translate-ptr code-addr spaces)) 0)) + (nwords (ash word -32)) + (nbytes (* nwords sb-vm:n-word-bytes))) + (format output " .quad 0x~x~% .fill ~d~%" word (- nbytes n-word-bytes)) + (incf code-addr nbytes)))))) + + ;; coreparse uses the 'lisp_jit_code' symbol to set text_space_highwatermark ;; The intent is that compilation to memory can use this reserved area ;; (if space remains) so that profilers can associate a C symbol with the ;; program counter range. It's better than nothing. @@ -1245,7 +1233,7 @@ (addend (signed 64)))) (defun make-elf64-sym (name info) - (let ((a (make-array 24 :element-type '(unsigned-byte 8)))) + (let ((a (make-array 24 :element-type '(unsigned-byte 8) :initial-element 0))) (with-pinned-objects (a) (setf (sap-ref-32 (vector-sap a) 0) name (sap-ref-8 (vector-sap a) 4) info)) @@ -1348,7 +1336,7 @@ `("lisp.rel" ,+sht-progbits+ 0 0 0 8 8) `(".relalisp.core" ,+sht-rela+ 0 2 1 8 ,reloc-entry-size))) ; symbol table -- ^ ^ -- for which section - (:note ".note.GNU-stack" ,+sht-null+ 0 0 0 1 0))) + (:note ".note.GNU-stack" ,+sht-progbits+ 0 0 0 1 0))) (string-table (string-table (append '("lisp_code_start") (map 'list #'second sections)))) (strings (cdr string-table)) @@ -1444,7 +1432,7 @@ ;;; that need to be applied on startup of a position-independent executable. ;;; (defun collect-relocations (spaces fixups pie &key (verbose nil) (print nil)) - (let* ((code-bounds (space-bounds immobile-varyobj-core-space-id spaces)) + (let* ((code-bounds (space-bounds immobile-text-core-space-id spaces)) (code-start (bounds-low code-bounds)) (n-abs 0) (n-rel 0) @@ -1492,7 +1480,7 @@ (id (space-id space)) (npages (ceiling nwords (/ +backend-page-bytes+ n-word-bytes)))) (when (and (<= page0 page (+ page0 (1- npages))) - (/= id immobile-varyobj-core-space-id)) + (/= id immobile-text-core-space-id)) (return (+ (space-addr space) (* (- page page0) +backend-page-bytes+) (logand core-offs (1- +backend-page-bytes+)))))))) @@ -1519,19 +1507,18 @@ (return-from scan-obj)) (case widetag (#.instance-widetag - (let* ((layout (truly-the layout - (translate (%instance-layout obj) spaces))) - (bitmap (layout-bitmap layout)) - (translated - (if (fixnump bitmap) bitmap (translate bitmap spaces)))) - (do-instance-tagged-slot (i obj :bitmap translated) - (scanptr vaddr obj (1+ i)))) + (let ((type (truly-the layout (translate (%instance-layout obj) spaces)))) + (do-layout-bitmap (i taggedp type (%instance-length obj)) + (when taggedp + (scanptr vaddr obj (1+ i))))) (return-from scan-obj)) (#.simple-vector-widetag (let ((len (length (the simple-vector obj)))) - (when (eql (logand (get-header-data obj) #xFF) vector-addr-hashing-subtype) + (when (logtest (get-header-data obj) vector-addr-hashing-flag) (do ((i 2 (+ i 2)) (needs-rehash)) - ((= i len) + ;; Refer to the figure at the top of src/code/hash-table.lisp. + ;; LEN is an odd number. + ((>= i (1- len)) (when needs-rehash (setf (svref obj 1) 1))) ;; A weak or EQ-based hash table any of whose keys is a function @@ -1556,14 +1543,15 @@ (+ core-offs n-word-bytes) word))) (when (eq widetag funcallable-instance-widetag) - (let ((layout (truly-the layout (translate (%fun-layout obj) spaces)))) - (unless (fixnump (layout-bitmap layout)) - (error "Can't process bignum bitmap")) - (let ((bitmap (layout-bitmap layout))) - (unless (eql bitmap -1) + (let* ((layout (truly-the sb-vm:layout (translate (%fun-layout obj) spaces))) + (bitmap (%raw-instance-ref/signed-word + layout (sb-kernel::type-dd-length sb-vm:layout)))) + (unless (= (sb-kernel:bitmap-nwords layout) 1) + (error "Strange funcallable-instance bitmap")) + (unless (eql bitmap sb-kernel:+layout-all-tagged+) ;; tagged slots precede untagged slots, ;; so integer-length is the count of tagged slots. - (setq nwords (1+ (integer-length bitmap)))))))) + (setq nwords (1+ (integer-length bitmap))))))) ;; mixed boxed/unboxed objects (#.code-header-widetag (aver (not pie)) @@ -1585,7 +1573,7 @@ (return-from scan-obj))) (scanptrs vaddr obj 1 (1- nwords)))) (dolist (space (cdr spaces)) - (unless (= (space-id space) immobile-varyobj-core-space-id) + (unless (= (space-id space) immobile-text-core-space-id) (let* ((logical-addr (space-addr space)) (size (space-size space)) (physical-addr (space-physaddr space spaces)) @@ -1661,16 +1649,16 @@ (alien-funcall (extern-alien "load_core_bytes" (function system-area-pointer - int int unsigned unsigned)) + int int unsigned unsigned int)) (sb-sys:fd-stream-fd ,stream) - ;; Skip the core header - (+ ,start +backend-page-bytes+) + (+ ,start +backend-page-bytes+) ; Skip the core header 0 ; place it anywhere - (* ,npages +backend-page-bytes+))) + (* ,npages +backend-page-bytes+) ; len + 0)) ,@body) (when ,sap-var (alien-funcall - (extern-alien "os_invalidate" + (extern-alien "os_deallocate" (function void system-area-pointer unsigned)) ,sap-var (* ,npages +backend-page-bytes+))))))) @@ -1684,9 +1672,7 @@ (defun split-core (input-pathname asm-pathname &key enable-pie (verbose nil) - &aux (split-core-pathname - (merge-pathnames (make-pathname :type "core") asm-pathname)) - (elf-core-pathname + &aux (elf-core-pathname (merge-pathnames (make-pathname :name (concatenate 'string (pathname-name asm-pathname) "-core") :type "o") @@ -1701,15 +1687,16 @@ (fixedobj-range) ; = (START . SIZE-IN-BYTES) (relocs (make-array 100000 :adjustable t :fill-pointer 1))) + (declare (ignorable fixedobj-range)) ;; Remove old files (ignore-errors (delete-file asm-pathname)) - (ignore-errors (delete-file split-core-pathname)) (ignore-errors (delete-file elf-core-pathname)) ;; Ensure that all files can be opened (with-open-file (input input-pathname :element-type '(unsigned-byte 8)) (with-open-file (asm-file asm-pathname :direction :output :if-exists :supersede) - (with-open-file (split-core split-core-pathname :direction :output - :element-type '(unsigned-byte 8) :if-exists :supersede) + ;;(with-open-file (split-core split-core-pathname :direction :output + ;; :element-type '(unsigned-byte 8) :if-exists :supersede) + (let ((split-core nil)) (setq core-offset (read-core-header input core-header verbose)) (do-core-header-entry ((id len ptr) core-header) (case id @@ -1726,8 +1713,8 @@ (when verbose (format t "id=~d page=~5x + ~5x addr=~10x words=~8x~:[~; (drop)~]~%" id data-page npages addr nwords - (= id immobile-varyobj-core-space-id))) - (cond ((= id immobile-varyobj-core-space-id) + (= id immobile-text-core-space-id))) + (cond ((= id immobile-text-core-space-id) (setq code-start-fixup-ofs (+ index 3)) ;; Keep this entry but delete the page count. We need to know ;; where the space was supposed to be mapped and at what size. @@ -1744,14 +1731,15 @@ ;; adjust this entry's start page in the new core (decf data-page page-adjust))))) (#.page-table-core-entry-type-code - (aver (= len 3)) - (symbol-macrolet ((nbytes (%vector-raw-bits core-header (1+ ptr))) - (data-page (%vector-raw-bits core-header (+ ptr 2)))) + (aver (= len 4)) + (symbol-macrolet ((n-ptes (%vector-raw-bits core-header (+ ptr 1))) + (nbytes (%vector-raw-bits core-header (+ ptr 2))) + (data-page (%vector-raw-bits core-header (+ ptr 3)))) (aver (= data-page original-total-npages)) (aver (= (ceiling (space-nwords (find dynamic-core-space-id spaces :key #'space-id)) - (/ +backend-page-bytes+ n-word-bytes)) - (%vector-raw-bits core-header ptr))) ; number of PTEs + (/ sb-vm:gencgc-page-bytes n-word-bytes)) + n-ptes)) (when verbose (format t "PTE: page=~5x~40tbytes=~8x~%" data-page nbytes)) (push (cons data-page nbytes) copy-actions) @@ -1760,7 +1748,8 @@ :element-type '(unsigned-byte 8))) (filepos)) ;; Write the new core file - (write-sequence core-header split-core) + (when split-core + (write-sequence core-header split-core)) (dolist (action (reverse copy-actions)) ; nondestructive ;; page index convention assumes absence of core header. ;; i.e. data page 0 is the file page immediately following the core header @@ -1769,8 +1758,11 @@ (when verbose (format t "File offset ~10x: ~10x bytes~%" offset nbytes)) (setq filepos (+ core-offset offset)) - (file-position input filepos) - (copy-bytes input split-core nbytes buffer))) + (cond (split-core + (file-position input filepos) + (copy-bytes input split-core nbytes buffer)) + (t + (file-position input (+ filepos nbytes)))))) ;; Trailer (runtime options and magic number) (let ((nbytes (read-sequence buffer input))) ;; expect trailing magic number @@ -1783,20 +1775,22 @@ (format t "Trailer words:(~{~X~^ ~})~%" (loop for i below (floor nbytes n-word-bytes) collect (%vector-raw-bits buffer i)))) - (write-sequence buffer split-core :end nbytes) - (finish-output split-core)) + (when split-core + (write-sequence buffer split-core :end nbytes) + (finish-output split-core))) ;; Sanity test - (aver (= (+ core-offset - (* page-adjust +backend-page-bytes+) - (file-length split-core)) - (file-length input))) + (when split-core + (aver (= (+ core-offset + (* page-adjust +backend-page-bytes+) + (file-length split-core)) + (file-length input)))) ;; Seek back to the PTE pages so they can be copied to the '.o' file (file-position input filepos))) ;; Map the original core file to memory (with-mapped-core (sap core-offset original-total-npages input) (let* ((data-spaces - (delete immobile-varyobj-core-space-id (reverse spaces) + (delete immobile-text-core-space-id (reverse spaces) :key #'space-id)) (map (cons sap (sort (copy-list spaces) #'> :key #'space-addr))) (pte-nbytes (cdar copy-actions))) @@ -1819,6 +1813,12 @@ (if enable-pie +code-space-nominal-address+ 0)) (write-sequence core-header output) ; Copy prepared header (force-output output) + ;; os_link_runtime() doesn't need to process the "required" symbols now + (let* ((sym (find-target-symbol (package-id "SB-VM") + "+REQUIRED-FOREIGN-SYMBOLS+" map :physical)) + (vector (translate (symbol-global-value sym) map))) + (fill vector 0) + (setf (%array-fill-pointer vector) 0)) ;; Change SB-C::*COMPILE-FILE-TO-MEMORY-SPACE* to :DYNAMIC ;; and SB-C::*COMPILE-TO-MEMORY-SPACE* to :AUTO ;; in case the resulting executable needs to compile anything. @@ -1827,8 +1827,8 @@ ("*COMPILE-TO-MEMORY-SPACE*" . "DYNAMIC"))) (destructuring-bind (symbol . value) item (%set-symbol-global-value - (find-target-symbol "SB-C" symbol map) - (find-target-symbol "KEYWORD" value map :logical)))) + (find-target-symbol (package-id "SB-C") symbol map) + (find-target-symbol (package-id "KEYWORD") value map :logical)))) ;; (dolist (space data-spaces) ; Copy pages from memory (let ((start (space-physaddr space map)) @@ -1840,8 +1840,7 @@ (format t "Copying ~d bytes (#x~x) from ptes = ~d PTEs~%" pte-nbytes pte-nbytes (floor pte-nbytes 10))) (copy-bytes input output pte-nbytes)) ; Copy PTEs from input - (let ((core (write-assembler-text map asm-file enable-pie)) - (emit-all-c-symbols t)) + (let ((core (write-assembler-text map asm-file enable-pie))) (format asm-file " .section .rodata~% .p2align 4~%lisp_fixups:~%") ;; Sort the hash-table in emit order. (dolist (x (sort (%hash-table-alist (core-new-fixups core)) #'< :key #'cdr)) @@ -1851,13 +1850,11 @@ "~% .section .rodata~%")) (format asm-file " .globl ~A~%~:*~A: .quad ~d # ct~%" - (labelize "lisp_linkage_values") + (labelize "alien_linkage_values") (length (core-linkage-symbols core))) ;; -1 (not a plausible function address) signifies that word ;; following it is a data, not text, reference. (loop for s across (core-linkage-symbols core) - for bit across (core-linkage-symbol-usedp core) - when (or emit-all-c-symbols (eql bit 0)) do (format asm-file " .quad ~:[~;-1, ~]~a~%" (consp s) (if (consp s) (car s) s)))))) @@ -1887,9 +1884,9 @@ (when (plusp nwords) (push (make-space id addr data-page 0 nwords) spaces)))) (#.page-table-core-entry-type-code - (aver (= len 3)) - (symbol-macrolet ((nbytes (%vector-raw-bits core-header (1+ ptr))) - (data-page (%vector-raw-bits core-header (+ ptr 2)))) + (aver (= len 4)) + (symbol-macrolet ((nbytes (%vector-raw-bits core-header (+ ptr 2))) + (data-page (%vector-raw-bits core-header (+ ptr 3)))) (aver (= data-page total-npages)) (setq core-size (+ (* total-npages +backend-page-bytes+) nbytes)))))) (incf core-size +backend-page-bytes+) ; add in core header page @@ -1897,7 +1894,7 @@ (with-mapped-core (sap core-offset total-npages input) (let* ((spaces (cons sap (sort (copy-list spaces) #'> :key #'space-addr))) (core (make-core spaces - (space-bounds immobile-varyobj-core-space-id spaces) + (space-bounds immobile-text-core-space-id spaces) (space-bounds immobile-fixedobj-core-space-id spaces))) (c-symbols (map 'list (lambda (x) (if (consp x) (car x) x)) (core-linkage-symbols core))) @@ -1905,7 +1902,7 @@ (:sym ".symtab" ,+sht-symtab+ 0 1 1 8 ,sym-entry-size) ;; section with the strings -- ^ ^ -- 1+ highest local symbol (:core "lisp.core" ,+sht-progbits+ 0 0 0 ,core-align 0) - (:note ".note.GNU-stack" ,+sht-null+ 0 0 0 1 0))) + (:note ".note.GNU-stack" ,+sht-progbits+ 0 0 0 1 0))) (string-table (string-table (append (map 'list #'second sections) c-symbols))) (packed-strings (cdr string-table)) diff --git a/tools-for-build/grovel-features.sh b/tools-for-build/grovel-features.sh index baf6778037..73925d9ddd 100644 --- a/tools-for-build/grovel-features.sh +++ b/tools-for-build/grovel-features.sh @@ -6,25 +6,32 @@ cd ./tools-for-build > /dev/null # Assumes the presence of $1-test.c, which when built and # run should return with 104 if the feature is present. +# We presumes that the build machine matches the target machine +# in terms of a whether each feature presence test should pass. featurep() { bin="$1-test" + featurename=${2:-$1} rm -f $bin $GNUMAKE $bin -I ../src/runtime > /dev/null 2>&1 && echo "input" | ./$bin> /dev/null 2>&1 if [ "$?" -eq 104 ] then - printf " :$1" + printf " :$featurename" fi rm -f $bin } -# KLUDGE: ppc/darwin dlopen is special cased in make-config.sh, as -# we fake it with a shim. +# Adding a nonexistent link library to Config.*-win32 will fail, +# so we pass -lSynchronization to the featurep test specifically +# and not in the general make rule. +# It will get added in by Config.*-win32 only if LISP_FEATURE_SB_FUTEX. +if [ "$sbcl_os" = win32 ] ; then + LOADLIBES=-lSynchronization featurep os-provides-wakebyaddr sb-futex +fi + featurep os-provides-dlopen featurep os-provides-dladdr -featurep os-provides-putwc - featurep os-provides-blksize-t featurep os-provides-suseconds-t @@ -33,6 +40,8 @@ featurep os-provides-getprotoby-r featurep os-provides-poll +featurep os-provides-close-range-wrapper + if [ "$sbcl_arch" = arm ] ; then featurep arm-softfp fi diff --git a/tools-for-build/grovel-headers-win32.h b/tools-for-build/grovel-headers-win32.inc similarity index 97% rename from tools-for-build/grovel-headers-win32.h rename to tools-for-build/grovel-headers-win32.inc index 6f9a08fdcf..dcff8e12f7 100644 --- a/tools-for-build/grovel-headers-win32.h +++ b/tools-for-build/grovel-headers-win32.inc @@ -77,6 +77,7 @@ defconstant("+exception-flt-overflow+", EXCEPTION_FLT_OVERFLOW); defconstant("+exception-flt-stack-check+", EXCEPTION_FLT_STACK_CHECK); defconstant("+exception-flt-underflow+", EXCEPTION_FLT_UNDERFLOW); + defconstant("+exception-heap-corruption+", STATUS_HEAP_CORRUPTION); defconstant("+exception-illegal-instruction+", EXCEPTION_ILLEGAL_INSTRUCTION); defconstant("+exception-in-page-error+", EXCEPTION_IN_PAGE_ERROR); defconstant("+exception-int-divide-by-zero+", EXCEPTION_INT_DIVIDE_BY_ZERO); @@ -222,4 +223,9 @@ defconstant("fd-setsize", 1024); printf("\n"); + defconstant("sizeof-sigset_t", sizeof (sigset_t)); + defconstant("sig_block", SIG_BLOCK); + defconstant("sig_unblock", SIG_UNBLOCK); + defconstant("sig_setmask", SIG_SETMASK); + } diff --git a/tools-for-build/grovel-headers.c b/tools-for-build/grovel-headers.c index e97bf4484a..1fc1fa002a 100644 --- a/tools-for-build/grovel-headers.c +++ b/tools-for-build/grovel-headers.c @@ -29,6 +29,7 @@ #define boolean rpcndr_boolean #define WIN32_LEAN_AND_MEAN #include <windows.h> + #include <ntstatus.h> #include <shlobj.h> #include <wincrypt.h> #include <winsock2.h> @@ -39,13 +40,10 @@ #include <sys/times.h> #include <sys/wait.h> #include <sys/ioctl.h> -#ifdef LISP_FEATURE_ANDROID +#if defined __HAIKU__ || defined __DragonFly__ || defined LISP_FEATURE_ANDROID #include <termios.h> #else -# ifndef LISP_FEATURE_HAIKU -# include <sys/termios.h> -# endif - #include <langinfo.h> + #include <sys/termios.h> #endif #include <sys/time.h> #include <dlfcn.h> @@ -58,17 +56,18 @@ #include <errno.h> #include <time.h> -#ifdef LISP_FEATURE_HPUX -#include <sys/bsdtty.h> /* for TIOCGPGRP */ -#endif - #ifdef LISP_FEATURE_BSD #include <sys/param.h> #include <sys/sysctl.h> #endif -#if defined(LISP_FEATURE_WIN32) && defined(LISP_FEATURE_SB_THREAD) - #include "pthreads_win32.h" +#ifdef LISP_FEATURE_SB_THREAD +# ifdef LISP_FEATURE_WIN32 +# include "pthreads_win32.h" +# elif defined LISP_FEATURE_OS_THREAD_STACK +# include <limits.h> // PTHREAD_STACK_MIN is possibly in here +# include <pthread.h> // instead of in here +# endif #endif #include "wrap.h" @@ -88,11 +87,14 @@ (((bar.cname=-1)<0) ? "signed" : "unsigned"), \ (8LU * (sizeof bar.cname))) -void -defconstant(char* lisp_name, unsigned long unix_number) -{ - printf("(defconstant %s %lu) ; #x%lx\n", - lisp_name, unix_number, unix_number); +#define DEFCONSTANT(lispname,cname) \ + if (cname<0) defconstant_neg(lispname, cname); else defconstant(lispname,cname) + +void defconstant(char* lisp_name, unsigned long unix_number) { + printf("(defconstant %s %lu) ; #x%lx\n", lisp_name, unix_number, unix_number); +} +void defconstant_neg(char* lisp_name, long unix_number) { + printf("(defconstant %s %ld)\n", lisp_name, unix_number); } #ifdef __HAIKU__ @@ -147,7 +149,7 @@ main(int argc, char __attribute__((unused)) *argv[]) \n\ "); #ifdef _WIN32 - #include "grovel-headers-win32.h" + #include "grovel-headers-win32.inc" #else printf("(in-package \"SB-ALIEN\")\n\n"); @@ -157,7 +159,12 @@ main(int argc, char __attribute__((unused)) *argv[]) defconstant ("rtld-now", RTLD_NOW); defconstant ("rtld-global", RTLD_GLOBAL); - printf("(in-package \"SB-UNIX\")\n\n"); + printf("\n(in-package \"SB-UNIX\")\n\n"); + +#if defined LISP_FEATURE_OS_THREAD_STACK + defconstant("pthread-min-stack", PTHREAD_STACK_MIN); + printf("\n"); +#endif printf(";;; select()\n"); defconstant("fd-setsize", FD_SETSIZE); @@ -170,10 +177,6 @@ main(int argc, char __attribute__((unused)) *argv[]) defconstant("pollnval", POLLNVAL); defconstant("pollerr", POLLERR); DEFTYPE("nfds-t", nfds_t); -#ifndef LISP_FEATURE_ANDROID - printf(";;; langinfo\n"); - defconstant("codeset", CODESET); -#endif printf(";;; types, types, types\n"); DEFTYPE("clock-t", clock_t); DEFTYPE("dev-t", dev_t); @@ -269,6 +272,10 @@ main(int argc, char __attribute__((unused)) *argv[]) printf("\n"); printf(";;; signals\n"); + defconstant("sizeof-sigset_t", sizeof (sigset_t)); + defconstant("sig_block", SIG_BLOCK); + defconstant("sig_unblock", SIG_UNBLOCK); + defconstant("sig_setmask", SIG_SETMASK); defsignal("sigalrm", SIGALRM); defsignal("sigbus", SIGBUS); defsignal("sigchld", SIGCHLD); @@ -337,6 +344,29 @@ main(int argc, char __attribute__((unused)) *argv[]) #endif // !WIN32 printf("\n"); +#ifdef LISP_FEATURE_UNIX + DEFCONSTANT("clock-realtime", CLOCK_REALTIME); + DEFCONSTANT("clock-monotonic", CLOCK_MONOTONIC); + DEFCONSTANT("clock-process-cputime-id", CLOCK_PROCESS_CPUTIME_ID); +#endif +#ifdef LISP_FEATURE_LINUX +#ifdef CLOCK_REALTIME_ALARM + defconstant("clock-realtime-alarm", CLOCK_REALTIME_ALARM); +#endif + defconstant("clock-realtime-coarse", CLOCK_REALTIME_COARSE); +#ifdef CLOCK_TAI + defconstant("clock-tai", CLOCK_TAI); // International Atomic Time. +#endif + defconstant("clock-monotonic-coarse", CLOCK_MONOTONIC_COARSE); + defconstant("clock-monotonic-raw", CLOCK_MONOTONIC_RAW); +#ifdef CLOCK_BOOTTIME + defconstant("clock-boottime", CLOCK_BOOTTIME); +#endif +#ifdef CLOCK_BOOTTIME_ALARM + defconstant("clock-boottime-alarn", CLOCK_BOOTTIME_ALARM); +#endif + DEFCONSTANT("clock-thread-cputime-id", CLOCK_THREAD_CPUTIME_ID); +#endif printf(";;; structures\n"); DEFSTRUCT(timeval, struct timeval, DEFSLOT(tv-sec, tv_sec); diff --git a/tools-for-build/ldso-stubs.lisp b/tools-for-build/ldso-stubs.lisp deleted file mode 100644 index 0cc0562e69..0000000000 --- a/tools-for-build/ldso-stubs.lisp +++ /dev/null @@ -1,222 +0,0 @@ -;;;; Generate stubs for C-linkage library functions which we need to refer to -;;;; from Lisp. -;;;; -;;;; These stubs exist for the benefit of Lisp code that needs to refer -;;;; to foreign symbols when dlsym() is not available (i.e. when dumping -;;;; cold-sbcl.core, when we may be running in a host that's not SBCL, -;;;; or on platforms that don't have it at all). If the runtime is -;;;; dynamically linked, library functions won't be linked into it, so -;;;; the map file won't show them. So, we need a bunch of stubs that -;;;; nm(1) _can_ see. -;;;; -;;;; This software is part of the SBCL system. See the README file for -;;;; more information. -;;;; -;;;; This software is derived from the CMU CL system, which was -;;;; written at Carnegie Mellon University and released into the -;;;; public domain. The software is in the public domain and is -;;;; provided with absolutely no warranty. See the COPYING and CREDITS -;;;; files for more information. - -;;; This is an attempt to follow DB's hint of sbcl-devel -;;; 2001-09-18. -- CSR -;;; -(defun ldso-stubify (index fct stream) - (declare (ignorable index)) - #+hppa - (let ((stub (format nil "ldso_stub__~a" fct))) - (apply #'format stream (list -" .export ~A -~A: - .proc - .callinfo - b,n ~a - .procend - .import ~a,code~%" stub stub fct fct))) - - #-hppa - (format stream "LDSO_STUBIFY(~A)~%" fct)) - -(defvar *preludes* (list " -/* This is an automatically generated file, please do not hand-edit it. - * See the program tools-for-build/ldso-stubs.lisp. */ - -#ifndef __ASSEMBLER__ -#define __ASSEMBLER__ -#endif -#include \"sbcl.h\"" - -#+(and linux alpha) " -#define LDSO_STUBIFY(fct) \\ -.globl ldso_stub__ ## fct ; \\ - .type ldso_stub__ ## fct,@function ; \\ -ldso_stub__ ## fct: ; \\ - jmp fct ; \\ -.L ## fct ## e1: ; \\ - .size ldso_stub__ ## fct,.L ## fct ## e1-ldso_stub__ ## fct ;" - -#+hppa " - .level 2.0 - .text" - -)) - -;;; Most of the #+- in here is just noise, but so is this whole file. -;;; So I don't really care to go through with a comb and remove the fluff. -(defvar *stubs* (append - '("_exit" - "accept" - "access" - "acos" - "acosh" - "asin" - "asinh" - "atanh" - "bind" - "chmod" - "chown" - "close" - "closedir" - "connect" - "cosh" - "creat" - "dup" - "dup2" - "execve" - "exit" - "fchmod" - "fchown" - "fcntl" - "fork" - "free" - "fstat" - #+inode64 "fstat$INODE64" - "fsync" - "ftruncate" - "getcwd" - "getdtablesize" - "getegid" - "getenv" - "getgid" - "gethostbyaddr" - "gethostbyname" - "gethostname" - "getitimer" - "getpeername" - "getpgrp" - "getpid" - "getppid" - "getrusage" - "getsockname" - "gettimeofday" - "getuid" - "hypot" - "ioctl" - "isatty" - "kill" - "killpg" - "link" - "listen" - "log1p" - "lseek" - "lstat" - #+inode64 "lstat$INODE64" - "malloc" - #+(or x86 x86-64) "memcmp" - "memmove" - "mkdir" - "nanosleep" - "open" - "opendir" - "pipe" - "poll" - "pow" - "read" - "readdir" - "readlink" - "realpath" - "recv" - "rename" - "rmdir" - "select" - "send" - "setitimer" - "setpgrp" - "setsid" - "sinh" - "socket" - "stat" - #+inode64 "stat$INODE64" - "strerror" - "strlen" - "symlink" - "sync" - "tanh" - "truncate" - "ttyname" - #-hpux "tzname" - "unlink" - "utimes" - "waitpid" - "write") - ;; These aren't needed on the X86 because they're microcoded into the - ;; FPU, so the Lisp VOPs can implement them directly without having to - ;; call C code. - ;; - ;; Note: There might be some other functions in this category as well. - ;; E.g. I notice tanh() and acos() in the list above.. -- WHN 2001-06-07 - #-x86 - '("sin" - "cos" - "tan" - "atan" - "atan2" - "exp" - "log" - "log10" - "sqrt") - #+alpha - '("ieee_get_fp_control" - "ieee_set_fp_control") - ;; FIXME: After 1.0 this should be made - ;; #-linkage-table, as we only need these stubs if - ;; we don't have linkage-table. Done this way now to - ;; cut down on the number of ports affected. - #-(or win32 darwin freebsd netbsd openbsd) - '("ptsname" - #-android "grantpt" - "unlockpt") - #+(or openbsd freebsd dragonfly) - '("openpty") - '("dlclose" - "dlerror" - "dlopen" - "dlsym") - #+bsd - '("sysctl") - #+darwin - '("sysctlbyname") - #+os-provides-dladdr - '("dladdr") - #-android - '("nl_langinfo" - "getpagesize" - "cfgetispeed" - "cfgetospeed" - "cfsetispeed" - "cfsetospeed" - "tcdrain" - "tcflow" - "tcflush" - "tcgetattr" - "tcsendbreak" - "tcsetattr"))) - -(with-open-file (f "src/runtime/ldso-stubs.S" :direction :output :if-exists :supersede) - (assert (= (length *preludes*) 2)) - (dolist (pre *preludes*) - (write-line pre f)) - (let ((i -1)) - (dolist (stub *stubs*) - (check-type stub string) - (ldso-stubify (incf i) stub f)))) diff --git a/tools-for-build/more-ucd-consts.lisp-expr b/tools-for-build/more-ucd-consts.lisp-expr index b1a2b57bad..eb889eeac6 100644 --- a/tools-for-build/more-ucd-consts.lisp-expr +++ b/tools-for-build/more-ucd-consts.lisp-expr @@ -36,9 +36,10 @@ "Psalter_Pahlavi" "Grantha" "Mro" "Siddham" "Khojki" "Nabataean" "Tirhuta" "Khudawadi" "Old_North_Arabian" "Warang_Citi" "Linear_A" "Old_Permic" "Ahom" "Anatolian_Hieroglyphs" "Hatran" "Multani" "Old_Hungarian" - "SignWriting")) + "SignWriting" "Adlam" "Bhaiksuki" "Marchen" "Newa" "Osage" "Tangut" + "Masaram_Gondi" "Nushu" "Soyombo" "Zanabazar_Square")) (*line-break-classes* - ("XX" "AI" "AL" "B2" "BA" "BB" "BK" "CB" "CJ" "CL" "CM" "CP" "CR" "EX" "GL" - "HL" "HY" "ID" "IN" "IS" "LF" "NL" "NS" "NU" "OP" "PO" "PR" "QU" "RI" "SA" - "SG" "SP" "SY" "WJ" "ZW"))) + ("XX" "AI" "AL" "B2" "BA" "BB" "BK" "CB" "CJ" "CL" "CM" "CP" "CR" "EB" "EM" + "EX" "GL" "HL" "HY" "ID" "IN" "IS" "LF" "NL" "NS" "NU" "OP" "PO" "PR" "QU" + "RI" "SA" "SG" "SP" "SY" "WJ" "ZW" "ZWJ"))) diff --git a/tools-for-build/os-provides-close-range-wrapper-test.c b/tools-for-build/os-provides-close-range-wrapper-test.c new file mode 100644 index 0000000000..7743c92e01 --- /dev/null +++ b/tools-for-build/os-provides-close-range-wrapper-test.c @@ -0,0 +1,14 @@ +/* We're really only interested in if this builds. If it does, the OS provides + * close_range as a libc wrapper for the close_range syscall. If it doesn't + * build, we fall back to syscall(2) if __NR_close_range is defined. + */ + +/* glibc won't give us close_range without this */ +#define _GNU_SOURCE +#include <unistd.h> + +int main () +{ + close_range(3, ~0U, 0); + return 104; +} diff --git a/tools-for-build/os-provides-putwc-test.c b/tools-for-build/os-provides-putwc-test.c deleted file mode 100644 index 676f135865..0000000000 --- a/tools-for-build/os-provides-putwc-test.c +++ /dev/null @@ -1,11 +0,0 @@ -/* test to build and run so that we know if we have putwc */ - -#include <stdio.h> -#include <wchar.h> - -int main () -{ - wchar_t a = 'a'; - putwc(a, stdout); - return 104; -} diff --git a/tools-for-build/os-provides-wakebyaddr-test.c b/tools-for-build/os-provides-wakebyaddr-test.c new file mode 100644 index 0000000000..7b3da046d8 --- /dev/null +++ b/tools-for-build/os-provides-wakebyaddr-test.c @@ -0,0 +1,50 @@ +#include <windows.h> + +int mutex_word = 0; +int expect = 9; + +DWORD waiter(void* arg) { + mutex_word = expect = 2; + return WaitOnAddress(&mutex_word, &expect, 4, 100); // .1 sec max +} +DWORD waker(void* arg) { + mutex_word = 0; + WakeByAddressSingle(&mutex_word); + return 0; +} + +int main() +{ + // Verify that WaitOnAddress returns right away if the mutex word has the wrong value. + int result = WaitOnAddress(&mutex_word, &expect, 4, 500); // max = .5 sec + if (!result) return 0; // what? shouldn't be an error to mismatch + + // Try really waiting + mutex_word = 9; + result = WaitOnAddress(&mutex_word, &expect, 4, 20); // wait 20 millisec + // expect a timeout + if (!(result == 0 && GetLastError()==ERROR_TIMEOUT)) return 0; + + // Simulate a lisp mutex being woken + HANDLE hWaiter, hWaker; + hWaiter = CreateThread(NULL, 0, + waiter, 0, /* function and argument */ + 0, /* flags */ + 0); /* id */ + + hWaker = CreateThread(NULL, 0, + waker, 0, /* function and argument */ + CREATE_SUSPENDED, /* flags */ + 0); /* id */ + + for (;;) { + // wait for the waiter to place itself into a wait state on the mutex + if (mutex_word == 2) break; + Sleep(10); // 10 millisec + } + // Give them some time to rendezvous + ResumeThread(hWaker); + WaitForSingleObject(hWaiter, 200); // .2 sec max + if (mutex_word == 0) return 104; + return 1; +} diff --git a/tools-for-build/sparc-funcdef.sh b/tools-for-build/sparc-funcdef.sh deleted file mode 100644 index 80350bc863..0000000000 --- a/tools-for-build/sparc-funcdef.sh +++ /dev/null @@ -1,25 +0,0 @@ -cd ./tools-for-build - -TMP=sparc-funcdef.S - -SUN_FUNCDEF="#define FUNCDEF(x) .type x, #function" -GNU_FUNCDEF="#define FUNCDEF(x) .type x,@function" - -echo $SUN_FUNCDEF > $TMP -# cribbed from ldso_stubs, just "some code" -echo " -.globl ldso_stub__printf ; - FUNCDEF(ldso_stub__printf) ; -ldso_stub__printf: ; - sethi %hi(printf),%g1 ; - jmpl %g1+%lo(printf),%g0 ; - nop /* delay slot*/ ; -.Lprintfe1: ; - .size ldso_stub__printf,.Lprintfe1-ldso_stub__printf ;" >> $TMP - -if $GNUMAKE sparc-funcdef.o > /dev/null 2>&1 ; then - echo $SUN_FUNCDEF -else - echo $GNU_FUNCDEF -fi -rm -f $TMP diff --git a/tools-for-build/ucd.lisp b/tools-for-build/ucd.lisp index e4b08a26ee..f656b38a16 100644 --- a/tools-for-build/ucd.lisp +++ b/tools-for-build/ucd.lisp @@ -18,6 +18,72 @@ (setf (gethash (format nil "tools-for-build/~A.txt" ,name) *ucd-inputs*) 'used) ,@body)) +(defmacro with-input-utf8-file + ((s name &key (eszets 0) (registereds 1) (copyrights 1)) &body body) + ;; KLUDGE: Unicode data files in general have registered and + ;; copyright marks (non-ASCII characters) in the header; + ;; additionally, CaseFolding.txt as distributed by Unicode contains + ;; a non-ASCII character, an eszet, within a comment to act as an + ;; example. We can't in general assume that our host lisp will let + ;; us read those, and we can't portably write that we don't care + ;; about the text content of anything on a line after a hash because + ;; text decoding happens at a lower level. So here we rewrite data + ;; files to exclude the UTF-8 sequences corresponding to those + ;; characters (and error if we see any other UTF-8 sequence). + (let ((in (gensym "IN")) + (out (gensym "OUT"))) + `(let ((filename (format nil "~A.txt" ,name))) + (with-open-file (,in (make-pathname :name ,name :type "txt" + :defaults *unicode-character-database*) + :element-type '(unsigned-byte 8)) + (setf (gethash (format nil "tools-for-build/~A.txt" ,name) *ucd-inputs*) 'used) + (with-open-file (,out (make-pathname :name ,name :type "txt" + :defaults *output-directory*) + :element-type '(unsigned-byte 8) + :direction :output + :if-exists :supersede + :if-does-not-exist :create) + (setf (gethash (format nil "output/~A.txt" ,name) *ucd-outputs*) 'made) + (do ((inbyte (read-byte ,in nil nil) (read-byte ,in nil nil)) + (eszet (map '(vector (unsigned-byte 8)) 'char-code "<eszet>")) + (eszet-count 0) + (copyright (map '(vector (unsigned-byte 8)) 'char-code "<copyright>")) + (copyright-count 0) + (registered (map '(vector (unsigned-byte 8)) 'char-code "<registered>")) + (registered-count 0)) + ((null inbyte) + (unless (= eszet-count ,eszets) + (error "Unexpected number of eszets in ~A: ~D (expected ~D)" + filename eszet-count ,eszets)) + (unless (= copyright-count ,copyrights) + (error "Unexpected number of copyright symbols in ~A: ~D (expected ~D)" + filename copyright-count ,copyrights)) + (unless (= registered-count ,registereds) + (error "Unexpected number of registered symbols in ~A: ~D (expected ~D)" + filename registered-count ,registereds))) + (cond + ((= inbyte #xc3) + (let ((second (read-byte ,in nil nil))) + (cond + ((null second) + (error "No continuation after #xc3 in ~A" filename)) + ((= second #x9f) (incf eszet-count) (write-sequence eszet ,out)) + (t (error "Unexpected continuation after #xc3 in ~A: #x~X" + filename second))))) + ((= inbyte #xc2) + (let ((second (read-byte ,in nil nil))) + (cond + ((null second) + (error "No continuation after #xc2 in ~A" filename)) + ((= second #xa9) (incf copyright-count) (write-sequence copyright ,out)) + ((= second #xae) (incf registered-count) (write-sequence registered ,out))))) + ((>= inbyte #x7f) + (error "Unexpected octet in ~A: #x~X" filename inbyte)) + (t (write-byte inbyte ,out)))))) + (with-open-file (,s (make-pathname :name ,name :type "txt" + :defaults *output-directory*)) + ,@body)))) + (defmacro with-output-dat-file ((s name) &body body) `(with-open-file (,s (make-pathname :name ,name :type "dat" :defaults *output-directory*) @@ -83,6 +149,10 @@ do (setf (gethash string hash) index)) hash)) +(defun index-or-lose (key table kind) + (or (gethash key table) + (error "unknown ~A: ~S" kind key))) + (defun clear-flag (bit integer) (logandc2 integer (ash 1 bit))) @@ -98,7 +168,7 @@ :adjustable t)) ; 10000 is not a significant number (defparameter *decomposition-corrections* - (with-input-txt-file (s "NormalizationCorrections") + (with-input-utf8-file (s "NormalizationCorrections") (loop with result = nil for line = (read-line s nil nil) while line do (when (position #\; line) @@ -113,7 +183,7 @@ (defparameter *compositions* (make-hash-table :test #'equal)) (defparameter *composition-exclusions* - (with-input-txt-file (s "CompositionExclusions") + (with-input-utf8-file (s "CompositionExclusions") (loop with result = nil for line = (read-line s nil nil) while line when (and (> (length line) 0) (char/= (char line 0) #\#)) @@ -125,7 +195,7 @@ (defparameter *different-casefolds* nil) (defparameter *case-mapping* - (with-input-txt-file (s "SpecialCasing") + (with-input-utf8-file (s "SpecialCasing") (loop with hash = (make-hash-table) for line = (read-line s nil nil) while line unless (or (not (position #\# line)) (= 0 (position #\# line))) @@ -161,7 +231,7 @@ Length should be adjusted when the standard changes.") (defparameter *line-break-classes* (init-indices '*line-break-classes*)) (defparameter *east-asian-width-table* - (with-input-txt-file (s "EastAsianWidth") + (with-input-utf8-file (s "EastAsianWidth") (loop with hash = (make-hash-table) for line = (read-line s nil nil) while line unless (or (not (position #\# line)) (= 0 (position #\# line))) @@ -169,14 +239,14 @@ Length should be adjusted when the standard changes.") (split-string (string-right-trim " " (subseq line 0 (position #\# line))) #\;) (let ((range (parse-codepoint-range codepoints)) - (index (gethash value *east-asian-widths*))) + (index (index-or-lose value *east-asian-widths* "East Asian width"))) (loop for i from (car range) to (cadr range) do (setf (gethash i hash) index)))) finally (return hash))) "Table of East Asian Widths. Used in the creation of misc entries.") (defparameter *script-table* - (with-input-txt-file (s "Scripts") + (with-input-utf8-file (s "Scripts") (loop with hash = (make-hash-table) for line = (read-line s nil nil) while line unless (or (not (position #\# line)) (= 0 (position #\# line))) @@ -184,30 +254,34 @@ Length should be adjusted when the standard changes.") (split-string (string-right-trim " " (subseq line 0 (position #\# line))) #\;) (let ((range (parse-codepoint-range codepoints)) - (index (gethash (subseq value 1) *scripts*))) + (index (index-or-lose (subseq value 1) *scripts* "script"))) (loop for i from (car range) to (cadr range) do (setf (gethash i hash) index)))) finally (return hash))) "Table of scripts. Used in the creation of misc entries.") (defparameter *line-break-class-table* - (with-input-txt-file (s "LineBreak") + (with-input-utf8-file (s "LineBreak") (loop with hash = (make-hash-table) for line = (read-line s nil nil) while line unless (or (not (position #\# line)) (= 0 (position #\# line))) do (destructuring-bind (codepoints value) (split-string (string-right-trim " " (subseq line 0 (position #\# line))) #\;) - (let ((range (parse-codepoint-range codepoints)) - ;; Hangul syllables temporarily go to "Unkwown" - (index (gethash value *line-break-classes* 0))) + (let* ((range (parse-codepoint-range codepoints)) + ;; Hangul syllables are marked as "Unknown", and programmatically + ;; handled in SB-UNICODE:LINE-BREAK-CLASS + (value + (or (and (member value '("JL" "JV" "JT" "H2" "H3") :test 'string=) "XX") + value)) + (index (index-or-lose value *line-break-classes* "line break"))) (loop for i from (car range) to (cadr range) do (setf (gethash i hash) index)))) finally (return hash))) "Table of line break classes. Used in the creation of misc entries.") (defparameter *age-table* - (with-input-txt-file (s "DerivedAge") + (with-input-utf8-file (s "DerivedAge") (loop with hash = (make-hash-table) for line = (read-line s nil nil) while line unless (or (not (position #\# line)) (= 0 (position #\# line))) @@ -260,12 +334,12 @@ Length should be adjusted when the standard changes.") (when (ordered-ranges-member code-point vector) (gethash class *bidi-classes*)))) (cond - ((in - #(#x0600 #x07BF #x08A0 #x08FF #xFB50 #xFDCF #xFDF0 #xFDFF #xFE70 #xFEFF - #x1EE00 #x1EEFF) "AL")) - ((in - #(#x0590 #x05FF #x07C0 #x089F #xFB1D #xFB4F #x10800 #x10FFF #x1E800 #x1EDFF - #x1EF00 #x1EFFF) "R")) + ((in #(#x0600 #x07BF #x0860 #x086F #x08A0 #x08FF + #xFB50 #xFDCF #xFDF0 #xFDFF #xFE70 #xFEFF + #x1EE00 #x1EEFF) "AL")) + ((in #(#x0590 #x05FF #x07C0 #x085F #x0870 #x089F + #xFB1D #xFB4F #x10800 #x10FFF #x1E800 #x1EDFF + #x1EF00 #x1EFFF) "R")) ((in #(#x20A0 #x20CF) "ET")) ;; BN is non-characters and default-ignorable. ;; Default-ignorable will be dealt with elsewhere @@ -373,7 +447,7 @@ Length should be adjusted when the standard changes.") (ncount (* vcount tcount)) (table (make-hash-table))) (declare (ignore lcount)) - (with-input-txt-file (*standard-input* "Jamo") + (with-input-utf8-file (*standard-input* "Jamo") (loop for line = (read-line nil nil) while line if (position #\; line) @@ -419,12 +493,9 @@ Length should be adjusted when the standard changes.") (progn (setf *block-first* code-point) nil) - (let* ((gc-index (or (gethash general-category *general-categories*) - (error "unknown general category ~A" - general-category))) - (bidi-index (or (gethash bidi-class *bidi-classes*) - (error "unknown bidirectional class ~A" - bidi-class))) + (let* ((gc-index + (index-or-lose general-category *general-categories* "general category")) + (bidi-index (index-or-lose bidi-class *bidi-classes* "bidirectional class")) (ccc (parse-integer canonical-combining-class)) (digit-index (if (string= "" digit) 128 ; non-digits have high bit (let ((%digit (parse-integer digit))) @@ -560,61 +631,18 @@ Length should be adjusted when the standard changes.") (setf (ucd-misc (gethash code-point *ucd-entries*)) new-misc)))))) (defun fixup-casefolding () - ;; KLUDGE: CaseFolding.txt as distributed by Unicode contains a - ;; non-ASCII character, an eszet, within a comment to act as an - ;; example. We can't in general assume that our host lisp will let - ;; us read that, and we can't portably write that we don't care - ;; about the text content of anything on a line after a hash because - ;; text decoding happens at a lower level. So here we rewrite the - ;; CaseFolding.txt file to exclude the UTF-8 sequence corresponding - ;; to the eszet character. - (with-open-file (in (make-pathname :name "CaseFolding" :type "txt" - :defaults *unicode-character-database*) - :element-type '(unsigned-byte 8)) - (setf (gethash "tools-for-build/CaseFolding.txt" *ucd-inputs*) 'used) - (with-open-file (out (make-pathname :name "CaseFolding" :type "txt" - :defaults *output-directory*) - :direction :output - :if-exists :supersede - :if-does-not-exist :create - :element-type '(unsigned-byte 8)) - (setf (gethash "output/CaseFolding.txt" *ucd-outputs*) 'made) - ;; KLUDGE: it's inefficient, though simple, to do the I/O - ;; byte-by-bite. - (do ((inbyte (read-byte in nil nil) (read-byte in nil nil)) - (eszet (map '(vector (unsigned-byte 8)) 'char-code "<eszet>")) - (eszet-count 0) - (filename "CaseFolding.txt")) - ((null inbyte) - (unless (= eszet-count 1) - (error "Unexpected number of eszets in ~A: ~D" - filename eszet-count))) - (cond - ((= inbyte #xc3) - (let ((second (read-byte in nil nil))) - (cond - ((null second) - (error "No continuation after #xc3 in ~A" filename)) - ((= second #x9f) (incf eszet-count) (write-sequence eszet out)) - (t (error "Unexpected continuation after #xc3 in ~A: #x~X" - filename second))))) - ((>= inbyte #x7f) - (error "Unexpected octet in ~A: #x~X" filename inbyte)) - (t (write-byte inbyte out)))))) - (with-open-file (s (make-pathname :name "CaseFolding" :type "txt" - :defaults *output-directory*)) - (setf (gethash "tools-for-build/CaseFolding.txt" *ucd-inputs*) 'used) + (with-input-utf8-file (s "CaseFolding" :eszets 1) (loop for line = (read-line s nil nil) - while line - unless (or (not (position #\; line)) (equal (position #\# line) 0)) - do (destructuring-bind (original type mapping comment) - (split-string line #\;) - (declare (ignore comment)) - (let ((cp (parse-integer original :radix 16)) - (fold (parse-codepoints mapping :singleton-list nil))) - (unless (or (string= type " S") (string= type " T")) - (when (not (equal (cdr (gethash cp *case-mapping*)) fold)) - (push (cons cp fold) *different-casefolds*)))))))) + while line + unless (or (not (position #\; line)) (equal (position #\# line) 0)) + do (destructuring-bind (original type mapping comment) + (split-string line #\;) + (declare (ignore comment)) + (let ((cp (parse-integer original :radix 16)) + (fold (parse-codepoints mapping :singleton-list nil))) + (unless (or (string= type " S") (string= type " T")) + (when (not (equal (cdr (gethash cp *case-mapping*)) fold)) + (push (cons cp fold) *different-casefolds*)))))))) (defun fixup-ages () (let ((age (sort @@ -670,7 +698,7 @@ Length should be adjusted when the standard changes.") (push result **proplist-properties**)))) (defun slurp-proplist () - (with-input-txt-file (s "PropList") + (with-input-utf8-file (s "PropList") (parse-property s) ;; Initial comments (parse-property s :white-space) (parse-property s :bidi-control) @@ -700,12 +728,14 @@ Length should be adjusted when the standard changes.") (parse-property s :logical-order-exception) (parse-property s :other-id-start) (parse-property s :other-id-continue) - (parse-property s :sterm) + (parse-property s :sentence-terminal) (parse-property s :variation-selector) (parse-property s :pattern-white-space) - (parse-property s :pattern-syntax)) + (parse-property s :pattern-syntax) + (parse-property s :prepended-concatenation-mark) + (parse-property s :regional-indicator)) - (with-input-txt-file (s "DerivedNormalizationProps") + (with-input-utf8-file (s "DerivedNormalizationProps") (parse-property s) ;; Initial comments (parse-property s) ;; FC_NFKC_Closure (parse-property s) ;; FC_NFKC_Closure @@ -737,10 +767,11 @@ Length should be adjusted when the standard changes.") (defun parse-collation-line (line) (destructuring-bind (%code-points %keys) (split-string line #\;) (let* ((code-points (parse-codepoints %code-points)) + (%keys (subseq %keys 0 (search " #" %keys))) (keys - (remove - "" - (split-string (remove #\[ (remove #\Space %keys)) #\]) :test #'string=)) + (remove + "" + (split-string (remove #\[ (remove #\Space %keys)) #\]) :test #'string=)) (ret (loop for key in keys for variable-p = (position #\* key) @@ -755,15 +786,6 @@ Length should be adjusted when the standard changes.") (bitpack-collation-key primary secondary tertiary))))) (values code-points ret)))) -(defparameter *collation-table* - (with-input-txt-file (stream "allkeys") - (loop with hash = (make-hash-table :test #'equal) - for line = (read-line stream nil nil) while line - unless (eql 0 (position #\# line)) - do (multiple-value-bind (codepoints keys) (parse-collation-line line) - (setf (gethash codepoints hash) keys)) - finally (return hash)))) - ;;; Other properties (defparameter *confusables* @@ -787,7 +809,7 @@ Length should be adjusted when the standard changes.") "List of confusable codepoint sets") (defparameter *bidi-mirroring-glyphs* - (with-input-txt-file (s "BidiMirroring") + (with-input-utf8-file (s "BidiMirroring") (loop for line = (read-line s nil nil) while line when (and (plusp (length line)) (char/= (char line 0) #\#)) @@ -799,7 +821,7 @@ Length should be adjusted when the standard changes.") (defparameter *blocks* (let (ranges names) - (with-input-txt-file (stream "Blocks") + (with-input-utf8-file (stream "Blocks") (loop (let ((line (read-line stream nil nil))) (cond ((not line) (return)) @@ -821,13 +843,6 @@ Used to look up block data.") (write-byte (ldb (byte 8 8) code-point) stream) (write-byte (ldb (byte 8 0) code-point) stream)) -(defun write-4-byte (value stream) - (declare (type (unsigned-byte 32) value)) - (write-byte (ldb (byte 8 24) value) stream) - (write-byte (ldb (byte 8 16) value) stream) - (write-byte (ldb (byte 8 8) value) stream) - (write-byte (ldb (byte 8 0) value) stream)) - (defun output-misc-data () (with-output-dat-file (stream "ucdmisc") (loop for (gc-index bidi-index ccc digit decomposition-info flags @@ -895,14 +910,14 @@ Used to look up block data.") (print (length *decompositions*)))) (defun output-composition-data () - (with-output-dat-file (stream "comp") + (with-output-lisp-expr-file (stream "comp") (let (comp) (maphash (lambda (k v) (push (cons k v) comp)) *compositions*) - (setq comp (sort comp #'< :key #'cdr)) - (loop for (k . v) in comp - do (write-codepoint (car k) stream) - (write-codepoint (cdr k) stream) - (write-codepoint v stream))))) + (format stream "#(~%") + (loop for (k . v) in (sort comp #'< :key #'cdr) + do (format stream "(~D . ~D) ; #x~X + #x~X~%" + (logior (ash (car k) 21) (cdr k)) v (car k) (cdr k))) + (format stream ")~%")))) (defun output-case-data () (let (casing-pages points-with-case) @@ -934,37 +949,32 @@ Used to look up block data.") (print casing-pages stream)))) (defun output-collation-data () - (with-output-dat-file (stream "collation") - (flet ((length-tag (list1 list2) - ;; takes two lists of UB32 (with the caveat that list1[0] - ;; needs its high 8 bits free (codepoints always have - ;; that) and do - (let* ((l1 (length list1)) (l2 (length list2)) - (tag (dpb l1 (byte 4 28) (dpb l2 (byte 5 23) (car list1))))) - (assert (<= l1 3)) - (write-4-byte tag stream) - (map nil #'(lambda (l) (write-4-byte l stream)) (append (cdr list1) list2))))) - (let (coll) - (maphash (lambda (k v) (push (cons k v) coll)) *collation-table*) - (labels ((sorter (o1 o2) - (cond - ((null o1) t) - ((null o2) nil) - (t (or (< (car o1) (car o2)) - (and (= (car o1) (car o2)) - (sorter (cdr o1) (cdr o2)))))))) - (setq coll (sort coll #'sorter :key #'car))) - (loop for (k . v) in coll - do (length-tag k v))))) + (with-output-lisp-expr-file (output "collation") + (format output ";;;; This is 'allkeys.txt' converted to Lisp syntax~%") + (format output ";;;; Assume *READ-BASE* is 16.~%#(~%") + (with-input-txt-file (input "allkeys") + (loop for line = (read-line input nil nil) while line + unless (or (string= line "") + (eql 0 (position #\@ line)) (eql 0 (position #\# line))) + do + (multiple-value-bind (codepoints keys) (parse-collation-line line) + (format output "(~x . ~x)~%" + ;; Pack up to 3 codepoints, rightmost in the highest bits + (destructuring-bind (first &optional second third) codepoints + (cond (third (logior (ash third 42) (ash second 21) first)) + (second (logior (ash second 21) first)) + (t first))) + ;; Pack the blob of "keys" using 32 bits each + (let ((sum 0)) + ;; reversal here is magic. Don't worry about getting it wrong- + ;; unicode-collation.pure checks that. + (dolist (part (reverse keys) sum) + (setq sum (logior (ash sum 32) part)))))))) + (format output ")~%")) (with-output-lisp-expr-file (*standard-output* "other-collation-info") (write-string ";;; The highest primary variable collation index") (terpri) - (prin1 *maximum-variable-key*) (terpri)) - (with-output-lisp-expr-file (*standard-output* "n-collation-entries") - (write-string ";;; The number of entries in the collation table") - (terpri) - (prin1 (hash-table-count *collation-table*)) - (terpri))) + (prin1 *maximum-variable-key*) (terpri))) (defun output (&optional (*output-directory* *output-directory*)) (output-misc-data) @@ -994,12 +1004,9 @@ Used to look up block data.") (setf *unicode-1-names* nil)) (with-output-lisp-expr-file (*standard-output* "numerics") - (let ((result (make-array (* (length *different-numerics*) 2)))) - (loop for (code . value) in (sort *different-numerics* #'< :key #'car) - for i by 2 - do (setf (aref result i) code - (aref result (1+ i)) (read-from-string value))) - (prin1 result))) + (prin1 (mapcar (lambda (x) (cons (car x) (read-from-string (cdr x)))) + ;; Print it low to high. It was collected with PUSH + (reverse *different-numerics*)))) (with-output-lisp-expr-file (*standard-output* "titlecases") (prin1 *different-titlecases*)) (with-output-lisp-expr-file (*standard-output* "foldcases") diff --git a/tools-for-build/wxs.lisp b/tools-for-build/wxs.lisp index 904a0b17b0..af2a5840a0 100644 --- a/tools-for-build/wxs.lisp +++ b/tools-for-build/wxs.lisp @@ -59,11 +59,10 @@ "Turns something like 0.pre7.14.flaky4.13 (see version.lisp-expr) into an acceptable form for WIX (up to four dot-separated numbers)." (with-output-to-string (output) - (loop repeat 4 - with position = 0 + (loop with position = 0 for separator = "" then "." - for next-digit = (position-if #'digit-char-p horrible-thing - :start position) + for next-digit = (position-if #'digit-char-p horrible-thing :start position) + repeat 4 while next-digit do (multiple-value-bind (number end) (parse-integer horrible-thing :start next-digit :junk-allowed t) diff --git a/verify-header-parsing.sh b/verify-header-parsing.sh new file mode 100755 index 0000000000..d367731b3f --- /dev/null +++ b/verify-header-parsing.sh @@ -0,0 +1,10 @@ +#!/bin/sh + +# This script is not part of the build, but running it tells you +# whether each genesis headers can be included without fussing +# around with all sorts of other headers. +for i in src/runtime/genesis/*.h +do + echo '#include "'$i'"' > tmp.c + cc -Isrc/runtime -c tmp.c +done